From f2116fd6a883076f081ef446ac76e50c71c04a01 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 23 Nov 2025 14:12:59 +0000 Subject: [PATCH 001/372] start v1.4 --- include/pal/pal_config.h | 7 +- include/pal/pal_graphics.h | 51 +++++++ pal.lua | 34 ++++- pal_config.lua | 9 +- src/graphics/pal_graphics_linux.c | 235 ++++++++++++++++++++++++++++++ src/pal_core.c | 4 +- tests/graphics_test.c | 25 ++++ tests/tests.h | 3 + tests/tests.lua | 6 + tests/tests_main.c | 38 ++--- 10 files changed, 386 insertions(+), 26 deletions(-) create mode 100644 include/pal/pal_graphics.h create mode 100644 src/graphics/pal_graphics_linux.c create mode 100644 tests/graphics_test.c diff --git a/include/pal/pal_config.h b/include/pal/pal_config.h index 65d5ee9e..1bb59aa7 100644 --- a/include/pal/pal_config.h +++ b/include/pal/pal_config.h @@ -2,7 +2,8 @@ // Auto Generated Config Header From pal_config.lua // Must not be edited manually -#define PAL_HAS_SYSTEM 1 -#define PAL_HAS_THREAD 1 +#define PAL_HAS_SYSTEM 0 +#define PAL_HAS_THREAD 0 #define PAL_HAS_VIDEO 1 -#define PAL_HAS_OPENGL 1 +#define PAL_HAS_OPENGL 0 +#define PAL_HAS_GRAPHICS 1 diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h new file mode 100644 index 00000000..a46f4fd1 --- /dev/null +++ b/include/pal/pal_graphics.h @@ -0,0 +1,51 @@ + +/** + +Copyright (C) 2025 Nicholas Agbo + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + + */ + +/** + * @defgroup pal_graphics Graphics + * Graphics PAL functionality such as GPUs, GPUDevices, swapchains and more. + * + * @{ + */ + +#ifndef _PAL_GRAPHICS_H +#define _PAL_GRAPHICS_H + +#include "pal_core.h" + +typedef struct PalGPUAdapter PalGPUAdapter; +typedef struct PalGPUDevice PalGPUDevice; + +typedef struct { + PalResult PAL_CALL (*enumerateAdapters)( + Int32* count, + PalGPUAdapter** outAdapters); +} PalGPUBackend; + +PAL_API PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator); + +PAL_API void PAL_CALL palShutdownGraphics(); + +/** @} */ // end of pal_graphics group + +#endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/pal.lua b/pal.lua index ecf46819..f0a04297 100644 --- a/pal.lua +++ b/pal.lua @@ -29,6 +29,12 @@ function writeConfig(path) else file:write("#define PAL_HAS_OPENGL 0\n") end + + if (PAL_BUILD_GRAPHICS) then + file:write("#define PAL_HAS_GRAPHICS 1\n") + else + file:write("#define PAL_HAS_GRAPHICS 0\n") + end file:close() end @@ -107,7 +113,7 @@ project "PAL" defines { "PAL_HAS_WAYLAND=0" } end - -- -- check for X11 support. This is cross compiler + -- check for X11 support. This is cross compiler local XPaths = { "/usr/include/X11/Xlib.h", "/usr/include/x86_64-linux-gnu/X11/Xlib.h" @@ -141,4 +147,30 @@ project "PAL" filter {} end + if (PAL_BUILD_GRAPHICS) then + filter {"system:windows", "configurations:*"} + -- files { "src/graphics/pal_graphics_win32.c" } + + filter {"system:linux", "configurations:*"} + files { "src/graphics/pal_graphics_linux.c" } + + -- check for vulkan support. This is cross compiler + vulkan_sdk = os.getenv("VULKAN_SDK") + if (vulkan_sdk) then + -- add to include path if compiler does not see it + includedirs { + path.join(vulkan_sdk, "include") + } + + libdirs { + path.join(vulkan_sdk, "Lib") + } + + defines { "PAL_HAS_VULKAN=1" } + else + defines { "PAL_HAS_VULKAN=0" } + end + filter {} + end + writeConfig("include/pal/pal_config.h") \ No newline at end of file diff --git a/pal_config.lua b/pal_config.lua index a912de31..14259d5a 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -6,13 +6,16 @@ PAL_BUILD_STATIC = false PAL_BUILD_TESTS = true -- build system module -PAL_BUILD_SYSTEM = true +PAL_BUILD_SYSTEM = false -- build thread module -PAL_BUILD_THREAD = true +PAL_BUILD_THREAD = false -- build video module PAL_BUILD_VIDEO = true -- build opengl module -PAL_BUILD_OPENGL = true \ No newline at end of file +PAL_BUILD_OPENGL = false + +-- build graphics module +PAL_BUILD_GRAPHICS = true \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c new file mode 100644 index 00000000..d48c2066 --- /dev/null +++ b/src/graphics/pal_graphics_linux.c @@ -0,0 +1,235 @@ + +/** + +Copyright (C) 2025 Nicholas Agbo + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + + */ + +// ================================================== +// Includes +// ================================================== + +#include "pal/pal_graphics.h" + +#if PAL_HAS_VULKAN +#include +#include +#include +#endif // PAL_HAS_VULKAN + +// ================================================== +// Typedefs, enums and structs +// ================================================== + +#define PAL_MAX_BACKENDS 8 // should be fine for now + +#if PAL_HAS_VULKAN +// VKAPI_PTR expands to nothing on linux + +typedef VkResult (*vkCreateInstanceFn)( + const VkInstanceCreateInfo*, + const VkAllocationCallbacks*, + VkInstance*); + +typedef void (*vkDestroyInstanceFn)( + VkInstance, + const VkAllocationCallbacks*); + +typedef VkResult (*vkEnumeratePhysicalDevicesFn)( + VkInstance, + uint32_t*, + VkPhysicalDevice*); + +#endif // PAL_HAS_VULKAN + +typedef struct { + bool initialized; + Int32 backendCount; + const PalAllocator* allocator; + void* instance; + void* handle; + + void* destroyInstance; + void* createInstance; + void* enumeratePhysicalDevices; + + const PalGPUBackend* backends[PAL_MAX_BACKENDS]; +} VkGPU; + +static VkGPU s_VkGPU = {0}; + +// ================================================== +// Internal API +// ================================================== + +#if PAL_HAS_VULKAN + +// we dont want to fill this everytime we want to use +static VkAllocationCallbacks s_VkAllocator = {0}; + +void* vkAlloc( + void* pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope) +{ + return palAllocate(s_VkGPU.allocator, size, alignment); +} + +void vkFree( + void* pUserData, + void* ptr) +{ + palFree(s_VkGPU.allocator, ptr); +} + +void* vkRealloc( + void* pUserData, + void* pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope) +{ + // Note: This is a hack which could cost performance but + // realloc is not really called that much so it should be fine + // this is because we dont know the old size + void* block = realloc(pOriginal, size); + if (block) { + void* memory = palAllocate(s_VkGPU.allocator, size, alignment); + if (!memory) { + free(block); + return nullptr; + } + + memcpy(memory, block, size); + return memory; + } + return nullptr; +} + +PalResult vkInitGraphics() +{ + // load vulkan + s_VkGPU.handle = dlopen("libvulkan.so", RTLD_LAZY); + if (!s_VkGPU.handle) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + s_VkGPU.createInstance = dlsym(s_VkGPU.handle, "vkCreateInstance"); + s_VkGPU.destroyInstance = dlsym(s_VkGPU.handle, "vkDestroyInstance"); + + s_VkGPU.enumeratePhysicalDevices = dlsym( + s_VkGPU.handle, + "vkEnumeratePhysicalDevices"); + + // create a dummy instance + VkApplicationInfo appInfo = {0}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.apiVersion = VK_API_VERSION_1_0; // for wider support + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.pEngineName = "Engine"; + appInfo.pApplicationName = "App"; + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + + VkInstanceCreateInfo instanceCreateInfo = {0}; + instanceCreateInfo.pApplicationInfo = &appInfo; + instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + + // vk allocator + s_VkAllocator.pfnAllocation = vkAlloc; + s_VkAllocator.pfnFree = vkFree; + s_VkAllocator.pfnReallocation = vkRealloc; + + VkInstance instance = nullptr; + vkCreateInstanceFn vkCreateInstancePtr = s_VkGPU.createInstance; + VkResult result = vkCreateInstancePtr( + &instanceCreateInfo, + &s_VkAllocator, + &instance); + + if (result != VK_SUCCESS) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + s_VkGPU.instance = instance; + return PAL_RESULT_SUCCESS; +} + +void vkShutdownGraphics() +{ + if (s_VkGPU.instance) { + vkDestroyInstanceFn vkDestroyInstancePtr = s_VkGPU.destroyInstance; + vkDestroyInstancePtr(s_VkGPU.instance, &s_VkAllocator); + } +} + +PalResult vkEnumerateAdapters( + Int32* count, + PalGPUAdapter** outAdapters) +{ + palLog(nullptr, "Vulkan GPU"); + return PAL_RESULT_SUCCESS; +} + +static PalGPUBackend s_VkBackend = { + .enumerateAdapters = vkEnumerateAdapters +}; + +#endif // PAL_HAS_VULKAN + +// ================================================== +// Public API +// ================================================== + +PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator) +{ + if (s_VkGPU.initialized) { + return PAL_RESULT_SUCCESS; + } + + if (allocator && (!allocator->allocate || !allocator->free)) { + return PAL_RESULT_INVALID_ALLOCATOR; + } + + s_VkGPU.allocator = allocator; +#if PAL_HAS_VULKAN + PalResult ret = vkInitGraphics(); + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + s_VkGPU.backends[s_VkGPU.backendCount++] = &s_VkBackend; +#endif // PAL_HAS_VULKAN + + s_VkGPU.initialized = true; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palShutdownGraphics() +{ + if (!s_VkGPU.initialized) { + return; + } + +#if PAL_HAS_VULKAN + vkShutdownGraphics(); +#endif // PAL_HAS_VULKAN + + memset(&s_VkGPU, 0, sizeof(VkGPU)); + s_VkGPU.initialized = false; // just in case +} \ No newline at end of file diff --git a/src/pal_core.c b/src/pal_core.c index f9b5de85..7166b751 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -68,9 +68,9 @@ freely, subject to the following restrictions: #define PAL_DEFAULT_ALIGNMENT 16 #define PAL_VERSION_MAJOR 1 -#define PAL_VERSION_MINOR 3 +#define PAL_VERSION_MINOR 4 #define PAL_VERSION_BUILD 0 -#define PAL_VERSION_STRING "1.3.0" +#define PAL_VERSION_STRING "1.4.0" #define PAL_LOG_MSG_SIZE 4096 #ifdef _WIN32 diff --git a/tests/graphics_test.c b/tests/graphics_test.c new file mode 100644 index 00000000..b62676e9 --- /dev/null +++ b/tests/graphics_test.c @@ -0,0 +1,25 @@ + +#include "pal/pal_graphics.h" +#include "tests.h" + +bool graphicsTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Graphics Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + // initialize the video system + PalResult result = palInitGraphics(nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // shutdown the graphics system + palShutdownGraphics(); + + return true; +} \ No newline at end of file diff --git a/tests/tests.h b/tests/tests.h index 65eb69c8..a29d820f 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -53,4 +53,7 @@ bool openglMultiContextTest(); // opengl, video and thread bool multiThreadOpenGlTest(); +// graphics +bool graphicsTest(); + #endif // _TESTS_H \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index 1c196956..f30d5af9 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -63,5 +63,11 @@ project "tests" } end + if (PAL_BUILD_GRAPHICS) then + files { + "graphics_test.c" + } + end + includedirs { "%{wks.location}/include" } links { "PAL" } \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index a551b677..a3db1bbd 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -9,10 +9,10 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - registerTest("Logger Test", loggerTest); - registerTest("Time Test", timeTest); - registerTest("User Event Test", userEventTest); - registerTest("Event Test", eventTest); + // registerTest("Logger Test", loggerTest); + // registerTest("Time Test", timeTest); + // registerTest("User Event Test", userEventTest); + // registerTest("Event Test", eventTest); #if PAL_HAS_SYSTEM registerTest("System Test", systemTest); @@ -26,19 +26,19 @@ int main(int argc, char** argv) #endif // PAL_HAS_THREAD #if PAL_HAS_VIDEO - registerTest("Video Test", videoTest); - registerTest("Monitor Test", monitorTest); - registerTest("Monitor Mode Test", monitorModeTest); - registerTest("Window Test", windowTest); - registerTest("Icon Test", iconTest); - registerTest("Cursor Test", cursorTest); - registerTest("Input Window Test", inputWindowTest); - registerTest("System Cursor Test", systemCursorTest); - registerTest("Attach Window Test", attachWindowTest); - registerTest("Character Event Test", charEventTest); - registerTest("Native Integration Test", nativeIntegrationTest); - registerTest("Native Instance Test", nativeInstanceTest); - registerTest("Custom Decoration Test", customDecorationTest); + // registerTest("Video Test", videoTest); + // registerTest("Monitor Test", monitorTest); + // registerTest("Monitor Mode Test", monitorModeTest); + // registerTest("Window Test", windowTest); + // registerTest("Icon Test", iconTest); + // registerTest("Cursor Test", cursorTest); + // registerTest("Input Window Test", inputWindowTest); + // registerTest("System Cursor Test", systemCursorTest); + // registerTest("Attach Window Test", attachWindowTest); + // registerTest("Character Event Test", charEventTest); + // registerTest("Native Integration Test", nativeIntegrationTest); + // registerTest("Native Instance Test", nativeInstanceTest); + // registerTest("Custom Decoration Test", customDecorationTest); #endif // PAL_HAS_VIDEO // This test can run without video system so long as your have a valid @@ -54,6 +54,10 @@ int main(int argc, char** argv) registerTest("Multi Thread OpenGL Test", multiThreadOpenGlTest); #endif // +#if PAL_HAS_GRAPHICS + registerTest("Graphics Test", graphicsTest); +#endif // + runTests(); return 0; } \ No newline at end of file From 0748377cdcd5a113f9d11491454aeaac5a6ae337 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 23 Nov 2025 19:07:45 +0000 Subject: [PATCH 002/372] add gpu adapter linux --- include/pal/pal_core.h | 4 +- include/pal/pal_graphics.h | 43 ++++- src/graphics/pal_graphics_linux.c | 290 +++++++++++++++++++++++++++++- src/pal_core.c | 7 + tests/graphics_test.c | 107 +++++++++++ 5 files changed, 442 insertions(+), 9 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index a21c117a..eb73c718 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -245,7 +245,9 @@ typedef enum { PAL_RESULT_INVALID_GL_VERSION, PAL_RESULT_INVALID_GL_PROFILE, PAL_RESULT_INVALID_GL_CONTEXT, - PAL_RESULT_INVALID_FBCONFIG_BACKEND + PAL_RESULT_INVALID_FBCONFIG_BACKEND, + PAL_RESULT_GRAPHICS_NOT_INITIALIZED, + PAL_RESULT_INVALID_GPU_ADAPTER } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index a46f4fd1..0a166944 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -33,19 +33,58 @@ freely, subject to the following restrictions: #include "pal_core.h" +#define PAL_GPU_NAME_SIZE 128 +#define PAL_GPU_VERSION_SIZE 16 + typedef struct PalGPUAdapter PalGPUAdapter; typedef struct PalGPUDevice PalGPUDevice; +typedef enum { + PAL_GPU_TYPE_UNKNOWN, + PAL_GPU_TYPE_DISCRETE, + PAL_GPU_TYPE_INTEGRATED, + PAL_GPU_TYPE_VIRTUAL, + PAL_GPU_TYPE_CPU +} PalGPUType; + +typedef enum { + PAL_GPU_API_VULKAN, + PAL_GPU_API_D3D12, + PAL_GPU_API_METAL, + PAL_GPU_API_CUSTOM +} PalGPUApiType; + +typedef struct { + bool debugLayerSupported; + PalGPUType type; + PalGPUApiType apiType; + Uint32 version; + Uint64 totalMemory; + char versionString[PAL_GPU_VERSION_SIZE]; + char name[PAL_GPU_NAME_SIZE]; +} PalGPUAdapterInfo; + typedef struct { - PalResult PAL_CALL (*enumerateAdapters)( + PalResult PAL_CALL (*enumerateGPUAdapters)( Int32* count, PalGPUAdapter** outAdapters); + + PalResult PAL_CALL (*getGPUAdapterInfo)( + PalGPUAdapter* adapter, + PalGPUAdapterInfo* info); } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator); - PAL_API void PAL_CALL palShutdownGraphics(); +PAL_API PalResult PAL_CALL palEnumerateGPUAdapters( + Int32* count, + PalGPUAdapter** outAdapters); + +PAL_API PalResult PAL_CALL palGetGPUAdapterInfo( + PalGPUAdapter* adapter, + PalGPUAdapterInfo* info); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index d48c2066..ba987ad9 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -31,13 +31,16 @@ freely, subject to the following restrictions: #include #include #include +#include +#include #endif // PAL_HAS_VULKAN // ================================================== // Typedefs, enums and structs // ================================================== -#define PAL_MAX_BACKENDS 8 // should be fine for now +#define MAX_BACKENDS 8 // should be fine for now +#define MAX_ADAPTERS 32 // should be enough #if PAL_HAS_VULKAN // VKAPI_PTR expands to nothing on linux @@ -56,11 +59,37 @@ typedef VkResult (*vkEnumeratePhysicalDevicesFn)( uint32_t*, VkPhysicalDevice*); +typedef void (*vkGetPhysicalDevicePropertiesFn)( + VkPhysicalDevice, + VkPhysicalDeviceProperties*); + +typedef void (*vkGetPhysicalDeviceMemoryPropertiesFn)( + VkPhysicalDevice, + VkPhysicalDeviceMemoryProperties*); + +typedef VkResult (*vkEnumerateInstanceLayerPropertiesFn)( + uint32_t*, + VkLayerProperties*); + #endif // PAL_HAS_VULKAN +typedef struct { + bool used; + const PalGPUBackend* backend; + PalGPUAdapter* adapter; +} AdapterData; + +typedef struct { + const PalGPUBackend* base; + Uint16 startIndex; + Uint16 count; +} AttachGPUBackend; + typedef struct { bool initialized; + bool hasDebug; Int32 backendCount; + Int32 totalAdapterCount; const PalAllocator* allocator; void* instance; void* handle; @@ -68,8 +97,12 @@ typedef struct { void* destroyInstance; void* createInstance; void* enumeratePhysicalDevices; + void* getPhysicalDeviceProperties; + void* getPhysicalDeviceMemoryProperties; + void* enumerateInstanceLayerProperties; - const PalGPUBackend* backends[PAL_MAX_BACKENDS]; + AdapterData adapterData[MAX_ADAPTERS]; + AttachGPUBackend backends[MAX_BACKENDS]; } VkGPU; static VkGPU s_VkGPU = {0}; @@ -78,8 +111,28 @@ static VkGPU s_VkGPU = {0}; // Internal API // ================================================== -#if PAL_HAS_VULKAN +static AdapterData* getFreeAdapterData() +{ + for (int i = 0; i < MAX_ADAPTERS; ++i) { + if (!s_VkGPU.adapterData[i].used) { + s_VkGPU.adapterData[i].used = true; + return &s_VkGPU.adapterData[i]; + } + } +} +static AdapterData* findAdapterData(PalGPUAdapter* adapter) +{ + for (int i = 0; i < MAX_ADAPTERS; ++i) { + if (s_VkGPU.adapterData[i].used && + s_VkGPU.adapterData[i].adapter == adapter) { + return &s_VkGPU.adapterData[i]; + } + } + return nullptr; +} + +#if PAL_HAS_VULKAN // we dont want to fill this everytime we want to use static VkAllocationCallbacks s_VkAllocator = {0}; @@ -138,6 +191,18 @@ PalResult vkInitGraphics() s_VkGPU.handle, "vkEnumeratePhysicalDevices"); + s_VkGPU.getPhysicalDeviceProperties = dlsym( + s_VkGPU.handle, + "vkGetPhysicalDeviceProperties"); + + s_VkGPU.getPhysicalDeviceMemoryProperties = dlsym( + s_VkGPU.handle, + "vkGetPhysicalDeviceMemoryProperties"); + + s_VkGPU.enumerateInstanceLayerProperties = dlsym( + s_VkGPU.handle, + "vkEnumerateInstanceLayerProperties"); + // create a dummy instance VkApplicationInfo appInfo = {0}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -167,6 +232,34 @@ PalResult vkInitGraphics() return PAL_RESULT_PLATFORM_FAILURE; } + Uint32 count = 0; + vkEnumerateInstanceLayerPropertiesFn enumerateProperties; + enumerateProperties = s_VkGPU.enumerateInstanceLayerProperties; + + VkResult ret = enumerateProperties(&count, nullptr); + if (ret != VK_SUCCESS) { + s_VkGPU.hasDebug = false; + } + + VkLayerProperties* props = nullptr; + props = palAllocate( + s_VkGPU.allocator, + sizeof(VkLayerProperties) * count, + 0); + + if (!props) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + enumerateProperties(&count, props); + for (int i = 0; i < count; i++) { + if (strcmp(props[i].layerName, "VK_LAYER_KHRONOS_validation") == 0) { + s_VkGPU.hasDebug = true; + break; + } + } + + palFree(s_VkGPU.allocator, props); s_VkGPU.instance = instance; return PAL_RESULT_SUCCESS; } @@ -176,6 +269,7 @@ void vkShutdownGraphics() if (s_VkGPU.instance) { vkDestroyInstanceFn vkDestroyInstancePtr = s_VkGPU.destroyInstance; vkDestroyInstancePtr(s_VkGPU.instance, &s_VkAllocator); + dlclose(s_VkGPU.handle); } } @@ -183,12 +277,118 @@ PalResult vkEnumerateAdapters( Int32* count, PalGPUAdapter** outAdapters) { - palLog(nullptr, "Vulkan GPU"); + int _count = 0; + int maxCount = outAdapters ? *count : 0; + + vkEnumeratePhysicalDevicesFn enumerate = s_VkGPU.enumeratePhysicalDevices; + VkResult result = enumerate(s_VkGPU.instance, &_count, nullptr); + if (result != VK_SUCCESS) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + if (outAdapters) { + VkPhysicalDevice* devices = nullptr; + devices = palAllocate( + s_VkGPU.allocator, + sizeof(VkPhysicalDevice) * _count, + 0); + + if (!devices) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + result = enumerate(s_VkGPU.instance, &_count, devices); + if (result != VK_SUCCESS) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + // write to user array + for (int i = 0; i < _count && i < *count; i++) { + outAdapters[i] = (PalGPUAdapter*)devices[i]; + } + + palFree(s_VkGPU.allocator, devices); + } + + if (!outAdapters) { + *count = _count; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL vkGetAdapterInfo( + PalGPUAdapter* adapter, + PalGPUAdapterInfo* info) +{ + VkPhysicalDeviceProperties props; + VkPhysicalDeviceMemoryProperties memProps; + vkGetPhysicalDevicePropertiesFn getProperties; + vkGetPhysicalDeviceMemoryPropertiesFn getMemoryProperties; + + getProperties = s_VkGPU.getPhysicalDeviceProperties; + getMemoryProperties = s_VkGPU.getPhysicalDeviceMemoryProperties; + getProperties((VkPhysicalDevice)adapter, &props); + getMemoryProperties((VkPhysicalDevice)adapter, &memProps); + + strcpy(info->name, props.deviceName); + info->version = props.apiVersion; + info->debugLayerSupported = s_VkGPU.hasDebug; + + // get total memory + Uint64 memory = 0; + for (int i = 0; i < memProps.memoryHeapCount; i++) { + if (memProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { + memory += memProps.memoryHeaps[i].size; + } + } + + info->totalMemory = memory; + info->apiType = PAL_GPU_API_VULKAN; + + // get device type + switch (props.deviceType) { + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { + info->type = PAL_GPU_TYPE_INTEGRATED; + break; + } + + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { + info->type = PAL_GPU_TYPE_DISCRETE; + break; + } + + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { + info->type = PAL_GPU_TYPE_VIRTUAL; + break; + } + + case VK_PHYSICAL_DEVICE_TYPE_CPU: { + info->type = PAL_GPU_TYPE_CPU; + break; + } + + default: { + info->type = PAL_GPU_TYPE_UNKNOWN; + break; + } + } + + // version string + snprintf( + info->versionString, + PAL_GPU_VERSION_SIZE, + "%d.%d.%d", + VK_VERSION_MAJOR(info->version), + VK_VERSION_MINOR(info->version), + VK_VERSION_PATCH(info->version)); + return PAL_RESULT_SUCCESS; } static PalGPUBackend s_VkBackend = { - .enumerateAdapters = vkEnumerateAdapters + .enumerateGPUAdapters = vkEnumerateAdapters, + .getGPUAdapterInfo = vkGetAdapterInfo }; #endif // PAL_HAS_VULKAN @@ -213,7 +413,9 @@ PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator) if (ret != PAL_RESULT_SUCCESS) { return ret; } - s_VkGPU.backends[s_VkGPU.backendCount++] = &s_VkBackend; + + AttachGPUBackend* backend = &s_VkGPU.backends[s_VkGPU.backendCount++]; + backend->base = &s_VkBackend; #endif // PAL_HAS_VULKAN s_VkGPU.initialized = true; @@ -232,4 +434,80 @@ void PAL_CALL palShutdownGraphics() memset(&s_VkGPU, 0, sizeof(VkGPU)); s_VkGPU.initialized = false; // just in case +} + +PalResult PAL_CALL palEnumerateGPUAdapters( + Int32* count, + PalGPUAdapter** outAdapters) +{ + // enumerate all adapters for both custom and PAL backends + if (!s_VkGPU.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!count) { + return PAL_RESULT_NULL_POINTER; + } + + if (*count == 0 && outAdapters) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + + PalResult result; + int totalCount = 0; + int index = 0; + + int _count = outAdapters ? *count : 0; + for (int i = 0; i < s_VkGPU.backendCount; i++) { + AttachGPUBackend* backend = &s_VkGPU.backends[i]; + if (outAdapters) { + // offset into the array so all backends write at the correct index + PalGPUAdapter** adapters = &outAdapters[backend->startIndex]; + result = backend->base->enumerateGPUAdapters(&_count, adapters); + + for (int i = 0; i < backend->count; i++) { + AdapterData* data = getFreeAdapterData(); + data->adapter = adapters[i]; + data->backend = backend->base; + } + + } else { + result = backend->base->enumerateGPUAdapters(&_count, nullptr); + backend->startIndex = totalCount; + backend->count = _count; + totalCount += _count; + _count = 0; + } + + // break if a backend fails + if (result != PAL_RESULT_SUCCESS) { + return result; + } + } + + if (!outAdapters) { + *count = totalCount; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetGPUAdapterInfo( + PalGPUAdapter* adapter, + PalGPUAdapterInfo* info) +{ + if (!s_VkGPU.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!adapter || !info) { + return PAL_RESULT_NULL_POINTER; + } + + AdapterData* data = findAdapterData(adapter); + if (data) { + return data->backend->getGPUAdapterInfo(adapter, info); + } + + return PAL_RESULT_INVALID_GPU_ADAPTER; } \ No newline at end of file diff --git a/src/pal_core.c b/src/pal_core.c index 7166b751..82a303d7 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -379,6 +379,13 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_FBCONFIG_BACKEND: return "Invalid FBConfg backend"; + + // graphics + case PAL_RESULT_GRAPHICS_NOT_INITIALIZED: + return "Graphics system not initialized"; + + case PAL_RESULT_INVALID_GPU_ADAPTER: + return "Invalid GPU adapter"; } return "Unknown"; } diff --git a/tests/graphics_test.c b/tests/graphics_test.c index b62676e9..f0059747 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -18,8 +18,115 @@ bool graphicsTest() return false; } + // enumerate all available GPUs from internal and custom backends + Int32 count = 0; + result = palEnumerateGPUAdapters(&count, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + return false; + } + + if (count == 0) { + palLog(nullptr, "No Adapters found"); + return false; + } + palLog(nullptr, "Adapter (GPUs) Count: %d", count); + + // allocate an array of adapters or use a fixed array + // Example: PalGPUAdapter* adapters[12]; + PalGPUAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalGPUAdapter*) * count, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateGPUAdapters(&count, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + return false; + } + + // get information about all the adapters + PalGPUAdapterInfo info; + for (Int32 i = 0; i < count; i++) { + PalGPUAdapter* adapter = adapters[i]; + result = palGetGPUAdapterInfo(adapter, &info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + palFree(nullptr, adapters); + return false; + } + + Uint32 memoryGb = info.totalMemory / (1024.0 * 1024.0 * 1024.0); + palLog(nullptr, "GPU Name: %s", info.name); + palLog(nullptr, " Total Memory %dGB", memoryGb); + palLog(nullptr, " API Version: %s", info.versionString); + + const char* typeString; + switch (info.type) { + case PAL_GPU_TYPE_INTEGRATED: { + typeString = "Integrated"; + break; + } + + case PAL_GPU_TYPE_VIRTUAL: { + typeString = "Virtual"; + break; + } + + case PAL_GPU_TYPE_DISCRETE: { + typeString = "Discrete"; + break; + } + + case PAL_GPU_TYPE_CPU: { + typeString = "CPU"; + break; + } + } + palLog(nullptr, " Type: %s", typeString); + + const char* apiTypeString; + switch (info.apiType) { + case PAL_GPU_API_D3D12: { + apiTypeString = "D3D12"; + break; + } + + case PAL_GPU_API_VULKAN: { + apiTypeString = "Vulkan"; + break; + } + + case PAL_GPU_API_METAL: { + apiTypeString = "Metal"; + break; + } + + case PAL_GPU_API_CUSTOM: { + apiTypeString = "Custom"; + break; + } + } + palLog(nullptr, " API Type: %s", apiTypeString); + + const char* boolToString; + if (info.debugLayerSupported) { + boolToString = "True"; + } else { + boolToString = "False"; + } + palLog(nullptr, " Debug Layer: %s", boolToString); + } + // shutdown the graphics system palShutdownGraphics(); + + palFree(nullptr, adapters); return true; } \ No newline at end of file From be0abe004d0c844e038579b97d5a3c89b9b02988 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 24 Nov 2025 11:22:12 +0000 Subject: [PATCH 003/372] add custom backend test --- CHANGELOG.md | 21 +++ include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 12 +- src/graphics/pal_graphics_linux.c | 26 ++- src/pal_core.c | 3 + tests/custom_graphics_backend_test.c | 259 +++++++++++++++++++++++++++ tests/graphics_test.c | 26 ++- tests/tests.c | 2 +- tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 3 +- 11 files changed, 349 insertions(+), 10 deletions(-) create mode 100644 tests/custom_graphics_backend_test.c diff --git a/CHANGELOG.md b/CHANGELOG.md index a8c99abd..be93045c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,3 +121,24 @@ void* retval; palJoinThread(thread, &retval); ``` +## [1.3.0] - 2025-00-00 + +### Features + +- **Core:** Added **PAL_RESULT_GRAPHICS_NOT_INITIALIZED** to `PalResult` enum to indicate that a graphics function was called whiles the graphics system has not been initialized. + +- **Core:** Added **PAL_RESULT_INVALID_GPU_ADAPTER** to `PalResult` enum to indiate an invalid `PalGPUAdapter` handle error. + +- **Core:** Added **PAL_RESULT_INVALID_GPU_BACKEND** to `PalResult` enum to indiate an invalid `PalGPUBackend` handle error. + +- **Graphics:** Added **Graphics System To PAL**. This system allows users to use modern graphics APIs (eg. Vulkan, D3D12, and Metal). Systems which do not support this APIs are not left out, the graphics system also has an API to allow users set custom backends to the graphics system and use its API as though its part of the internal ones. see **custom_graphics_backend_test.c**. + +### Tests + +- Added grapics test example: demonstrating **Enumerating GPU Adapters And Selecting The Best One For Your Needs**. see **graphics_test.c**. + +- Added custom graphics backend example: demonstrating **Adding Custom Graphics Backends to PAL**. +see **custom_graphics_backend_test.c**. + +### Notes +- **No ABI changes** - existing code remains compatible. \ No newline at end of file diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index eb73c718..5a36192a 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -247,7 +247,8 @@ typedef enum { PAL_RESULT_INVALID_GL_CONTEXT, PAL_RESULT_INVALID_FBCONFIG_BACKEND, PAL_RESULT_GRAPHICS_NOT_INITIALIZED, - PAL_RESULT_INVALID_GPU_ADAPTER + PAL_RESULT_INVALID_GPU_ADAPTER, + PAL_RESULT_INVALID_GPU_BACKEND } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 0a166944..1de807c4 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -51,7 +51,13 @@ typedef enum { PAL_GPU_API_VULKAN, PAL_GPU_API_D3D12, PAL_GPU_API_METAL, - PAL_GPU_API_CUSTOM + + // for custom backends + PAL_GPU_API_OPENGL, + PAL_GPU_API_GLES, + PAL_GPU_API_D3D11, + PAL_GPU_API_D3D9, + PAL_GPU_API_PPM, } PalGPUApiType; typedef struct { @@ -59,7 +65,7 @@ typedef struct { PalGPUType type; PalGPUApiType apiType; Uint32 version; - Uint64 totalMemory; + Uint64 totalMemory; // in bytes char versionString[PAL_GPU_VERSION_SIZE]; char name[PAL_GPU_NAME_SIZE]; } PalGPUAdapterInfo; @@ -85,6 +91,8 @@ PAL_API PalResult PAL_CALL palGetGPUAdapterInfo( PalGPUAdapter* adapter, PalGPUAdapterInfo* info); +PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index ba987ad9..13c1f069 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -39,7 +39,7 @@ freely, subject to the following restrictions: // Typedefs, enums and structs // ================================================== -#define MAX_BACKENDS 8 // should be fine for now +#define MAX_BACKENDS 16 // should be fine for now #define MAX_ADAPTERS 32 // should be enough #if PAL_HAS_VULKAN @@ -416,6 +416,8 @@ PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator) AttachGPUBackend* backend = &s_VkGPU.backends[s_VkGPU.backendCount++]; backend->base = &s_VkBackend; + backend->count = 0; + backend->startIndex = 0; #endif // PAL_HAS_VULKAN s_VkGPU.initialized = true; @@ -510,4 +512,26 @@ PalResult PAL_CALL palGetGPUAdapterInfo( } return PAL_RESULT_INVALID_GPU_ADAPTER; +} + +PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) +{ + if (s_VkGPU.initialized) { + return PAL_RESULT_INVALID_GPU_BACKEND; + } + + // check if all the function pointers are set + // clang-format off + if (!backend->enumerateGPUAdapters || + !backend->getGPUAdapterInfo) { + return PAL_RESULT_INVALID_GPU_BACKEND; + } + // clang-format on + + AttachGPUBackend* attached = &s_VkGPU.backends[s_VkGPU.backendCount++]; + attached->base = backend; + attached->startIndex = 0; + attached->count = 0; + + return PAL_RESULT_SUCCESS; } \ No newline at end of file diff --git a/src/pal_core.c b/src/pal_core.c index 82a303d7..8e97229c 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -386,6 +386,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_GPU_ADAPTER: return "Invalid GPU adapter"; + + case PAL_RESULT_INVALID_GPU_BACKEND: + return "Invalid GPU backend"; } return "Unknown"; } diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c new file mode 100644 index 00000000..e98aad0d --- /dev/null +++ b/tests/custom_graphics_backend_test.c @@ -0,0 +1,259 @@ + +#include "pal/pal_graphics.h" +#include "tests.h" + +// a simple custom backend +// for simplicity we are not going to add that much functionality +// to it + +typedef struct { + PalGPUAdapterInfo adapterInfo; + // add more fields if needed +} CustomGPUAdapter; + +typedef struct { + // we just have only two adapters for simplicity + CustomGPUAdapter adapters[2]; +} CustomGPUBackend; + +static CustomGPUBackend s_CustomGPU; + +// setup our state which we will use +// PAL does not need this call so we set it up +// before adding the backend to PAL +// you might need a shutdown function for the backend after PAL has shutdown +// if there is cleanup to do +static void initCustomBackend() { + CustomGPUAdapter* adapter = &s_CustomGPU.adapters[0]; + adapter->adapterInfo.apiType = PAL_GPU_API_D3D9; + adapter->adapterInfo.debugLayerSupported = true; + adapter->adapterInfo.type = PAL_GPU_TYPE_INTEGRATED; + adapter->adapterInfo.version = 9; // combine into a single value + + // PAL needs it in bytes + Uint64 byte = 1024 * 1024 * 1024; + adapter->adapterInfo.totalMemory = byte * 4; // 4 GB + + strcpy(adapter->adapterInfo.versionString, "10_1"); + strcpy(adapter->adapterInfo.name, "Intel Arc A580"); + + // second adapter + adapter = &s_CustomGPU.adapters[1]; + adapter->adapterInfo.apiType = PAL_GPU_API_OPENGL; + adapter->adapterInfo.debugLayerSupported = true; + adapter->adapterInfo.type = PAL_GPU_TYPE_DISCRETE; + adapter->adapterInfo.version = 4; // combine into a single value + + // PAL needs it in bytes + adapter->adapterInfo.totalMemory = byte * 6; // 6 GB + + strcpy(adapter->adapterInfo.versionString, "4.4"); + strcpy(adapter->adapterInfo.name, "AMD Radeon RX 7700 XT"); +} + +static PalResult PAL_CALL customEnumerateGPUAdapters( + Int32* count, + PalGPUAdapter** outAdapters) +{ + if (outAdapters) { + for (int i = 0; i < 2 && i < *count; i++) { + PalGPUAdapter* adapter = (PalGPUAdapter*)&s_CustomGPU.adapters[i]; + outAdapters[i] = adapter; + } + + } else { + *count = 2; + } + + return PAL_RESULT_SUCCESS; +} + +static PalResult PAL_CALL customGetGPUAdapterInfo( + PalGPUAdapter* adapter, + PalGPUAdapterInfo* info) +{ + for (int i = 0; i < 2; i++) { + PalGPUAdapter* custom = (PalGPUAdapter*)&s_CustomGPU.adapters[i]; + if (custom == adapter) { + // make a copy + PalGPUAdapterInfo* gpuInfo = &s_CustomGPU.adapters[i].adapterInfo; + info->apiType = gpuInfo->apiType; + info->debugLayerSupported = gpuInfo->debugLayerSupported; + info->totalMemory = gpuInfo->totalMemory; + info->type = gpuInfo->type; + info->version = gpuInfo->version; + + strcpy(info->name, gpuInfo->name); + strcpy(info->versionString, gpuInfo->versionString); + + return PAL_RESULT_SUCCESS; + } + } +} + +static PalGPUBackend s_CustomBackend = { + .enumerateGPUAdapters = customEnumerateGPUAdapters, + .getGPUAdapterInfo = customGetGPUAdapterInfo +}; + +bool customGraphicsBackendTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Custom Graphics Backend Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + // do any initializtion before adding the backen to PAL + initCustomBackend(); + + // add the backend to the graphics system + PalResult result = palAddGPUBackend(&s_CustomBackend); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to add backend: %s", error); + return false; + } + + // initialize the video system + result = palInitGraphics(nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available GPUs from internal and custom backends + Int32 count = 0; + result = palEnumerateGPUAdapters(&count, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + return false; + } + + if (count == 0) { + palLog(nullptr, "No Adapters found"); + return false; + } + palLog(nullptr, "Adapter (GPUs) Count: %d", count); + + // allocate an array of adapters or use a fixed array + // Example: PalGPUAdapter* adapters[12]; + PalGPUAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalGPUAdapter*) * count, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateGPUAdapters(&count, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + return false; + } + + // get information about all the adapters + PalGPUAdapterInfo info; + for (Int32 i = 0; i < count; i++) { + PalGPUAdapter* adapter = adapters[i]; + result = palGetGPUAdapterInfo(adapter, &info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + palFree(nullptr, adapters); + return false; + } + + Uint32 memoryGb = info.totalMemory / (1024.0 * 1024.0 * 1024.0); + palLog(nullptr, "GPU Name: %s", info.name); + palLog(nullptr, " Total Memory %dGB", memoryGb); + palLog(nullptr, " API Version: %s", info.versionString); + + const char* typeString; + switch (info.type) { + case PAL_GPU_TYPE_INTEGRATED: { + typeString = "Integrated"; + break; + } + + case PAL_GPU_TYPE_VIRTUAL: { + typeString = "Virtual"; + break; + } + + case PAL_GPU_TYPE_DISCRETE: { + typeString = "Discrete"; + break; + } + + case PAL_GPU_TYPE_CPU: { + typeString = "CPU"; + break; + } + } + palLog(nullptr, " Type: %s", typeString); + + const char* apiTypeString; + switch (info.apiType) { + case PAL_GPU_API_D3D12: { + apiTypeString = "D3D12"; + break; + } + + case PAL_GPU_API_VULKAN: { + apiTypeString = "Vulkan"; + break; + } + + case PAL_GPU_API_METAL: { + apiTypeString = "Metal"; + break; + } + + case PAL_GPU_API_OPENGL: { + apiTypeString = "OpenGL"; + break; + } + + case PAL_GPU_API_GLES: { + apiTypeString = "GLes"; + break; + } + + case PAL_GPU_API_D3D11: { + apiTypeString = "D3D11"; + break; + } + + case PAL_GPU_API_D3D9: { + apiTypeString = "D3D9"; + break; + } + + case PAL_GPU_API_PPM: { + apiTypeString = "PPM"; + break; + } + } + palLog(nullptr, " API Type: %s", apiTypeString); + + const char* boolToString; + if (info.debugLayerSupported) { + boolToString = "True"; + } else { + boolToString = "False"; + } + + palLog(nullptr, " Debug Layer: %s", boolToString); + palLog(nullptr, ""); + } + + // shutdown the graphics system + palShutdownGraphics(); + + palFree(nullptr, adapters); + + return true; +} \ No newline at end of file diff --git a/tests/graphics_test.c b/tests/graphics_test.c index f0059747..f9c211bb 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -61,7 +61,7 @@ bool graphicsTest() return false; } - Uint32 memoryGb = info.totalMemory / (1024.0 * 1024.0 * 1024.0); + Uint32 memoryGb = info.totalMemory / (1024 * 1024 * 1024); palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Total Memory %dGB", memoryGb); palLog(nullptr, " API Version: %s", info.versionString); @@ -107,8 +107,28 @@ bool graphicsTest() break; } - case PAL_GPU_API_CUSTOM: { - apiTypeString = "Custom"; + case PAL_GPU_API_OPENGL: { + apiTypeString = "OpenGL"; + break; + } + + case PAL_GPU_API_GLES: { + apiTypeString = "GLes"; + break; + } + + case PAL_GPU_API_D3D11: { + apiTypeString = "D3D11"; + break; + } + + case PAL_GPU_API_D3D9: { + apiTypeString = "D3D9"; + break; + } + + case PAL_GPU_API_PPM: { + apiTypeString = "PPM"; break; } } diff --git a/tests/tests.c b/tests/tests.c index 0b470049..4546118c 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -1,7 +1,7 @@ #include "tests.h" -#define MAX_TESTS 32 // will change +#define MAX_TESTS 64 // will change typedef struct { TestFn func; diff --git a/tests/tests.h b/tests/tests.h index a29d820f..2bb498ea 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -55,5 +55,6 @@ bool multiThreadOpenGlTest(); // graphics bool graphicsTest(); +bool customGraphicsBackendTest(); #endif // _TESTS_H \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index f30d5af9..04f39207 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -65,7 +65,8 @@ project "tests" if (PAL_BUILD_GRAPHICS) then files { - "graphics_test.c" + "graphics_test.c", + "custom_graphics_backend_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index a3db1bbd..500ca43a 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,7 +55,8 @@ int main(int argc, char** argv) #endif // #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + // registerTest("Graphics Test", graphicsTest); + registerTest("Custom Graphics Backend Test", customGraphicsBackendTest); #endif // runTests(); From d8a08b70fb88b8d42558c3e90be952af751fdc16 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 24 Nov 2025 14:41:57 +0000 Subject: [PATCH 004/372] update readme --- README.md | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 6438f822..713b5074 100644 --- a/README.md +++ b/README.md @@ -5,19 +5,18 @@ ## Overview -PAL is a lightweight, low-level, cross-platform abstraction layer in **C**, designed to be **explicit** and as close to the **OS** as possible — similar in philosophy to Vulkan. It gives you precise control without hidden behavior, making it ideal for developers who want performance and predictability. +PAL is a lightweight, low-level, cross-platform abstraction layer in **C**, designed to be explicit and as close to the OS as possible similar in philosophy to Vulkan. PAL makes it possible to safely mix native API with its API in a very straight forward way. This is one of the main reasons why PAL exists. -PAL is transparent. All queries — window size, position, monitor info, and more — reflect the current platform state. Using PAL is like working directly with the OS: it applies no hidden logic, makes no assumptions, and leaves behavior fully in your control. +PAL is transparent. All queries like window size, position, monitor info reflect the current platform state. Using PAL is like working directly with the OS. PAL applies no hidden logic, makes no assumptions, and leaves behavior fully in your control. -The goal is very simple, write low-level cross-platform code without having per platform files -all over the place. Example: `renderer_vulkan`, `renderer_d3d12`, `window_win32`, etc. -PAL makes it possible to safely mix native API with its API in a very straight forward way. This is one of the main reasons why PAL exists. +The goal of PAL is very simple. Write low-level cross-platform code without having per platform files +all over the place. (eg. `renderer_vulkan`, `renderer_d3d12`, `window_win32`, etc). -This approach gives you total control: you handle events, manage resources, and cache state explicitly. PAL provides the building blocks; how you use them — whether for simple applications or advanced frameworks — is entirely up to you. +This approach gives you total control. You handle events, manage resources, and cache state explicitly. PAL provides the building blocks, how you use them, whether for simple applications or advanced frameworks is entirely up to you. -Example – Get Window Size +Get Window Size ```c -// Direct query from the platform — not cached by PAL +// Direct query from the platform, not cached by PAL palGetWindowSize(window, &w, &h); ``` > Note: palGetWindowSize queries the OS directly. If your application needs continuous updates (e.g., window moves or resizes frequently), it is more efficient to listen to PAL events rather than repeatedly querying the OS. This ensures your app stays performant. @@ -29,11 +28,11 @@ palGetWindowSize(window, &w, &h); While libraries like SDL or GLFW focus on simplifying development through high-level abstractions. **PAL is different:** -- ✅ **Explicit**: You decide how memory, events, and handles are managed. -- ✅ **Low Overhead**: PAL is close to raw OS calls, ensuring performance. -- ✅ **Modular**: Pick only the subsystems you need (video, event, threading, OpenGL, etc.). -- ✅ **Extendable**: Plug in your own backends (event queue, allocator, etc.). -- ✅ **Transparent**: Exposes raw OS handles when you need them. +- **Explicit**: You decide how memory, events, and handles are managed. +- **Low Overhead**: PAL is close to raw OS calls, ensuring performance. +- **Modular**: Pick only the subsystems you need (video, event, threading, OpenGL, etc.). +- **Extendable**: Plug in your own backends (event queue, allocator, GPUbackend, etc.). +- **Transparent**: Exposes raw OS handles when you need them. --- @@ -69,7 +68,7 @@ int main() { } ``` -➡️ Build and run this, and you’ll get a cross-platform window managed entirely by PAL. +Build and run this, and you’ll get a cross-platform window managed entirely by PAL. For more detailed examples, see the [tests folder](./tests) tests folder, which contains full usage scenarios and validation cases. @@ -117,7 +116,7 @@ For more detailed examples, see the [tests folder](./tests) tests folder, which ## Build -PAL is written in **C99** and uses **Premake** as its build system. Configure modules via [pal_config.lua](./pal_config.lua). +PAL is written in **C99** and uses Premake as its build system. Configure modules via [pal_config.lua](./pal_config.lua). See [pal_config.h](./include/pal/pal_config.h) to see the reflection of modules that will be built. **Windows** @@ -145,9 +144,9 @@ Enable tests in `pal_config.lua` by setting `PAL_BUILD_TESTS = true`. - `pal_event` - event queue, event callback - `pal_thread` - threads, synchronization - `pal_opengl` - framebuffer configs, context +- `pal_graphics` - Vulkan, D3D12, Metal, Custom ### Planned Modules -- `pal_graphics` - Vulkan, D3D12, Metal, Custom - `pal_network` - `pal_audio` - `pal_hid` @@ -170,7 +169,9 @@ The generated HTML docs will be available in `docs/html/`. ## Contributing -Contributions are welcome! Please open an issue or pull request. +Contributions are welcome! Please open an issue or pull request. +See [CONTRIBUTING.md](./.github/CONTRIBUTING.md) for how and what to contribute. +Thanks for contributing to PAL. --- From b8aa5a19beac949104b18995d7de1cdd8c5472d5 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 24 Nov 2025 18:09:24 +0000 Subject: [PATCH 005/372] add more gpu adapter info --- include/pal/pal_graphics.h | 72 ++++++---- src/graphics/pal_graphics_linux.c | 200 ++++++++++++++++++++++++++- tests/custom_graphics_backend_test.c | 49 +++++++ 3 files changed, 293 insertions(+), 28 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 1de807c4..5ee5fabb 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -40,39 +40,54 @@ typedef struct PalGPUAdapter PalGPUAdapter; typedef struct PalGPUDevice PalGPUDevice; typedef enum { - PAL_GPU_TYPE_UNKNOWN, - PAL_GPU_TYPE_DISCRETE, - PAL_GPU_TYPE_INTEGRATED, - PAL_GPU_TYPE_VIRTUAL, - PAL_GPU_TYPE_CPU + PAL_GPU_TYPE_UNKNOWN, + PAL_GPU_TYPE_DISCRETE, + PAL_GPU_TYPE_INTEGRATED, + PAL_GPU_TYPE_VIRTUAL, + PAL_GPU_TYPE_CPU } PalGPUType; typedef enum { - PAL_GPU_API_VULKAN, - PAL_GPU_API_D3D12, - PAL_GPU_API_METAL, - - // for custom backends - PAL_GPU_API_OPENGL, - PAL_GPU_API_GLES, - PAL_GPU_API_D3D11, - PAL_GPU_API_D3D9, - PAL_GPU_API_PPM, + PAL_GPU_API_VULKAN, + PAL_GPU_API_D3D12, + PAL_GPU_API_METAL, + + // for custom backends + PAL_GPU_API_OPENGL, + PAL_GPU_API_GLES, + PAL_GPU_API_D3D11, + PAL_GPU_API_D3D9, + PAL_GPU_API_PPM, } PalGPUApiType; +typedef enum { + PAL_GPU_COMMAND_GRAPHICS = PAL_BIT64(0), + PAL_GPU_COMMAND_COMPUTE = PAL_BIT64(1), + PAL_GPU_COMMAND_TRANSFER = PAL_BIT64(2) +} PalGPUCommands; + +typedef enum { + PAL_GPU_FEATURE_RAY_TRACING = PAL_BIT64(0), + PAL_GPU_FEATURE_MESH_SHADER = PAL_BIT64(1), + PAL_GPU_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(2), + PAL_GPU_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(3) +} PalGPUFeatures; + typedef struct { - bool debugLayerSupported; - PalGPUType type; - PalGPUApiType apiType; - Uint32 version; - Uint64 totalMemory; // in bytes - char versionString[PAL_GPU_VERSION_SIZE]; - char name[PAL_GPU_NAME_SIZE]; + bool debugLayerSupported; + PalGPUType type; + PalGPUApiType apiType; + Uint32 version; + Uint64 totalMemory; // in bytes + PalGPUCommands commands; + PalGPUFeatures features; + char versionString[PAL_GPU_VERSION_SIZE]; + char name[PAL_GPU_NAME_SIZE]; } PalGPUAdapterInfo; typedef struct { PalResult PAL_CALL (*enumerateGPUAdapters)( - Int32* count, + Int32* count, PalGPUAdapter** outAdapters); PalResult PAL_CALL (*getGPUAdapterInfo)( @@ -84,8 +99,8 @@ PAL_API PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator); PAL_API void PAL_CALL palShutdownGraphics(); PAL_API PalResult PAL_CALL palEnumerateGPUAdapters( - Int32* count, - PalGPUAdapter** outAdapters); + Int32* count, + PalGPUAdapter** outAdapters); PAL_API PalResult PAL_CALL palGetGPUAdapterInfo( PalGPUAdapter* adapter, @@ -93,6 +108,13 @@ PAL_API PalResult PAL_CALL palGetGPUAdapterInfo( PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); +PAL_API PalResult PAL_CALL palCreateGPUDevice( + bool debug, + PalGPUAdapter* adapter, + PalGPUDevice** outDevice); + +PAL_API void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 13c1f069..8e8ef2cd 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -71,6 +71,21 @@ typedef VkResult (*vkEnumerateInstanceLayerPropertiesFn)( uint32_t*, VkLayerProperties*); +typedef void (*vkGetPhysicalDeviceQueueFamilyPropertiesFn)( + VkPhysicalDevice, + uint32_t*, + VkQueueFamilyProperties*); + +typedef VkResult (*vkEnumerateDeviceExtensionPropertiesFn)( + VkPhysicalDevice, + const char*, + uint32_t*, + VkExtensionProperties*); + +typedef void (*vkGetPhysicalDeviceFeatures2Fn)( + VkPhysicalDevice, + VkPhysicalDeviceFeatures2*); + #endif // PAL_HAS_VULKAN typedef struct { @@ -100,6 +115,9 @@ typedef struct { void* getPhysicalDeviceProperties; void* getPhysicalDeviceMemoryProperties; void* enumerateInstanceLayerProperties; + void* getPhysicalDeviceQueueFamilyProperties; + void* enumerateDeviceExtensionProperties; + void* getPhysicalDeviceFeatures2; AdapterData adapterData[MAX_ADAPTERS]; AttachGPUBackend backends[MAX_BACKENDS]; @@ -203,6 +221,18 @@ PalResult vkInitGraphics() s_VkGPU.handle, "vkEnumerateInstanceLayerProperties"); + s_VkGPU.getPhysicalDeviceQueueFamilyProperties = dlsym( + s_VkGPU.handle, + "vkGetPhysicalDeviceQueueFamilyProperties"); + + s_VkGPU.enumerateDeviceExtensionProperties = dlsym( + s_VkGPU.handle, + "vkEnumerateDeviceExtensionProperties"); + + s_VkGPU.getPhysicalDeviceFeatures2 = dlsym( + s_VkGPU.handle, + "vkGetPhysicalDeviceFeatures2"); + // create a dummy instance VkApplicationInfo appInfo = {0}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; @@ -321,15 +351,23 @@ PalResult PAL_CALL vkGetAdapterInfo( PalGPUAdapter* adapter, PalGPUAdapterInfo* info) { + VkPhysicalDevice vkPhysicalDevice = (VkPhysicalDevice)adapter; VkPhysicalDeviceProperties props; VkPhysicalDeviceMemoryProperties memProps; vkGetPhysicalDevicePropertiesFn getProperties; vkGetPhysicalDeviceMemoryPropertiesFn getMemoryProperties; + vkGetPhysicalDeviceQueueFamilyPropertiesFn getQueueProperties; + vkEnumerateDeviceExtensionPropertiesFn getExtensionProperties; + vkGetPhysicalDeviceFeatures2Fn getFeatures2; getProperties = s_VkGPU.getPhysicalDeviceProperties; getMemoryProperties = s_VkGPU.getPhysicalDeviceMemoryProperties; - getProperties((VkPhysicalDevice)adapter, &props); - getMemoryProperties((VkPhysicalDevice)adapter, &memProps); + getQueueProperties = s_VkGPU.getPhysicalDeviceQueueFamilyProperties; + getExtensionProperties = s_VkGPU.enumerateDeviceExtensionProperties; + getFeatures2 = s_VkGPU.getPhysicalDeviceFeatures2; + + getProperties(vkPhysicalDevice, &props); + getMemoryProperties(vkPhysicalDevice, &memProps); strcpy(info->name, props.deviceName); info->version = props.apiVersion; @@ -382,7 +420,142 @@ PalResult PAL_CALL vkGetAdapterInfo( VK_VERSION_MAJOR(info->version), VK_VERSION_MINOR(info->version), VK_VERSION_PATCH(info->version)); - + + // get supported queue commands + Uint32 count; + getQueueProperties( + vkPhysicalDevice, + &count, + nullptr); + + // not that huge, we allocate on the stack rather (16 for safety) + VkQueueFamilyProperties queueProps[16]; + getQueueProperties( + vkPhysicalDevice, + &count, + queueProps); + + info->commands = 0; + for (int i = 0; i < count; i++) { + if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { + info->commands |= PAL_GPU_COMMAND_COMPUTE; + } + + if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + info->commands |= PAL_GPU_COMMAND_GRAPHICS; + } + + if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { + info->commands |= PAL_GPU_COMMAND_TRANSFER; + } + } + + // get supported extensions + Uint32 extensionCount = 0; + VkResult ret = getExtensionProperties( + vkPhysicalDevice, + nullptr, + &extensionCount, + nullptr); + + if (ret != VK_SUCCESS) { + // we just return without any modern features + return PAL_RESULT_SUCCESS; + } + + VkExtensionProperties* extensionProps = nullptr; + extensionProps = palAllocate( + s_VkGPU.allocator, + sizeof(VkExtensionProperties) * extensionCount, + 0); + + if (!extensionProps) { + return PAL_RESULT_SUCCESS; + } + + getExtensionProperties( + vkPhysicalDevice, + nullptr, + &extensionCount, + extensionProps); + + bool rayTracingFound = false; + bool accelerateFound = false; + info->features = 0; + + // clang-format off + for (int i = 0; i < extensionCount; i++) { + VkExtensionProperties* props = &extensionProps[i]; + if (strcmp(props->extensionName, "VK_KHR_ray_tracing_pipeline") == 0) { + rayTracingFound = true; + + } else if (strcmp(props->extensionName, "VK_KHR_acceleration_structur") == 0) { + accelerateFound = true; + + } else if (strcmp(props->extensionName, "VK_EXT_mesh_shader") == 0) { + // mesh shader + VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; + mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &mesh; + getFeatures2(vkPhysicalDevice, &features); + + if (mesh.meshShader && mesh.taskShader) { + info->features |= PAL_GPU_FEATURE_MESH_SHADER; + } + + } else if (strcmp(props->extensionName, "VK_KHR_fragment_shading_rate") == 0) { + // variable rate shading + VkPhysicalDeviceFragmentShadingRateFeaturesKHR frag = {0}; + frag.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &frag; + getFeatures2(vkPhysicalDevice, &features); + + if (frag.pipelineFragmentShadingRate) { + info->features |= PAL_GPU_FEATURE_VARIABLE_RATE_SHADING; + } + + } else if (strcmp(props->extensionName, "VK_EXT_descriptor_indexing") == 0) { + // descriptor indexing + VkPhysicalDeviceDescriptorIndexingFeatures desc = {0}; + desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &desc; + getFeatures2(vkPhysicalDevice, &features); + + if (desc.shaderSampledImageArrayNonUniformIndexing) { + info->features |= PAL_GPU_FEATURE_DESCRIPTOR_INDEXING; + } + } + } + + if (accelerateFound && rayTracingFound) { + // ray tracing + VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; + VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; + ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; + acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + + ray.pNext = &acc; + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &ray; + getFeatures2(vkPhysicalDevice, &features); + + if (ray.rayTracingPipeline && acc.accelerationStructure) { + info->features |= PAL_GPU_FEATURE_RAY_TRACING; + } + } + // clang-format on + + palFree(s_VkGPU.allocator, extensionProps); return PAL_RESULT_SUCCESS; } @@ -438,6 +611,10 @@ void PAL_CALL palShutdownGraphics() s_VkGPU.initialized = false; // just in case } +// ================================================== +// GPUAdapter +// ================================================== + PalResult PAL_CALL palEnumerateGPUAdapters( Int32* count, PalGPUAdapter** outAdapters) @@ -534,4 +711,21 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) attached->count = 0; return PAL_RESULT_SUCCESS; +} + +// ================================================== +// GPUDevice +// ================================================== + +PalResult PAL_CALL palCreateGPUDevice( + bool debug, + PalGPUAdapter* adapter, + PalGPUDevice** outDevice) +{ + +} + +void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device) +{ + } \ No newline at end of file diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index e98aad0d..d19911fc 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -25,6 +25,9 @@ static CustomGPUBackend s_CustomGPU; // if there is cleanup to do static void initCustomBackend() { CustomGPUAdapter* adapter = &s_CustomGPU.adapters[0]; + adapter->adapterInfo.features = 0; + adapter->adapterInfo.commands = 0; + adapter->adapterInfo.apiType = PAL_GPU_API_D3D9; adapter->adapterInfo.debugLayerSupported = true; adapter->adapterInfo.type = PAL_GPU_TYPE_INTEGRATED; @@ -37,8 +40,14 @@ static void initCustomBackend() { strcpy(adapter->adapterInfo.versionString, "10_1"); strcpy(adapter->adapterInfo.name, "Intel Arc A580"); + adapter->adapterInfo.commands |= PAL_GPU_COMMAND_GRAPHICS; + adapter->adapterInfo.features |= PAL_GPU_FEATURE_RAY_TRACING; + // second adapter adapter = &s_CustomGPU.adapters[1]; + adapter->adapterInfo.features = 0; + adapter->adapterInfo.commands = 0; + adapter->adapterInfo.apiType = PAL_GPU_API_OPENGL; adapter->adapterInfo.debugLayerSupported = true; adapter->adapterInfo.type = PAL_GPU_TYPE_DISCRETE; @@ -49,6 +58,11 @@ static void initCustomBackend() { strcpy(adapter->adapterInfo.versionString, "4.4"); strcpy(adapter->adapterInfo.name, "AMD Radeon RX 7700 XT"); + + adapter->adapterInfo.commands |= PAL_GPU_COMMAND_GRAPHICS; + adapter->adapterInfo.commands |= PAL_GPU_COMMAND_COMPUTE; + adapter->adapterInfo.features |= PAL_GPU_FEATURE_RAY_TRACING; + adapter->adapterInfo.features |= PAL_GPU_FEATURE_MESH_SHADER; } static PalResult PAL_CALL customEnumerateGPUAdapters( @@ -82,6 +96,8 @@ static PalResult PAL_CALL customGetGPUAdapterInfo( info->totalMemory = gpuInfo->totalMemory; info->type = gpuInfo->type; info->version = gpuInfo->version; + info->features = gpuInfo->features; + info->commands = gpuInfo->commands; strcpy(info->name, gpuInfo->name); strcpy(info->versionString, gpuInfo->versionString); @@ -247,6 +263,39 @@ bool customGraphicsBackendTest() } palLog(nullptr, " Debug Layer: %s", boolToString); + + // commands + palLog(nullptr, " Supported Commands:"); + if (info.commands & PAL_GPU_COMMAND_COMPUTE) { + palLog(nullptr, " Compute"); + } + + if (info.commands & PAL_GPU_COMMAND_GRAPHICS) { + palLog(nullptr, " Graphics"); + } + + if (info.commands & PAL_GPU_COMMAND_TRANSFER) { + palLog(nullptr, " Transfer"); + } + + // features + palLog(nullptr, " Supported Features:"); + if (info.features & PAL_GPU_FEATURE_RAY_TRACING) { + palLog(nullptr, " Ray tracing"); + } + + if (info.features & PAL_GPU_FEATURE_MESH_SHADER) { + palLog(nullptr, " Mesh shading"); + } + + if (info.features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { + palLog(nullptr, " Descriptor indexing"); + } + + if (info.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { + palLog(nullptr, " Variable Rate Shading"); + } + palLog(nullptr, ""); } From c796a92e8171798924c330bb5a02b37963f05969 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 24 Nov 2025 20:52:30 +0000 Subject: [PATCH 006/372] add shader formats: gpu adapter info --- include/pal/pal_graphics.h | 11 ++++- src/graphics/pal_graphics_linux.c | 10 +++-- tests/custom_graphics_backend_test.c | 35 ++++++++++++++-- tests/graphics_test.c | 63 +++++++++++++++++++++++++++- tests/tests_main.c | 2 +- 5 files changed, 110 insertions(+), 11 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 5ee5fabb..c25f76bd 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -66,6 +66,15 @@ typedef enum { PAL_GPU_COMMAND_TRANSFER = PAL_BIT64(2) } PalGPUCommands; +typedef enum { + PAL_GPU_SHADER_FORMAT_SPIRV = PAL_BIT(0), + PAL_GPU_SHADER_FORMAT_DXIL = PAL_BIT(1), + PAL_GPU_SHADER_FORMAT_DXBC = PAL_BIT(2), + PAL_GPU_SHADER_FORMAT_GLSL = PAL_BIT(3), + PAL_GPU_SHADER_FORMAT_MSL = PAL_BIT(4), + PAL_GPU_SHADER_FORMAT_PPM = PAL_BIT(5) +} PalGPUShaderFormat; + typedef enum { PAL_GPU_FEATURE_RAY_TRACING = PAL_BIT64(0), PAL_GPU_FEATURE_MESH_SHADER = PAL_BIT64(1), @@ -77,7 +86,7 @@ typedef struct { bool debugLayerSupported; PalGPUType type; PalGPUApiType apiType; - Uint32 version; + PalGPUShaderFormat shaderFormat; Uint64 totalMemory; // in bytes PalGPUCommands commands; PalGPUFeatures features; diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 8e8ef2cd..f8901d30 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -370,7 +370,6 @@ PalResult PAL_CALL vkGetAdapterInfo( getMemoryProperties(vkPhysicalDevice, &memProps); strcpy(info->name, props.deviceName); - info->version = props.apiVersion; info->debugLayerSupported = s_VkGPU.hasDebug; // get total memory @@ -412,14 +411,17 @@ PalResult PAL_CALL vkGetAdapterInfo( } } + // shader format + info->shaderFormat = PAL_GPU_SHADER_FORMAT_SPIRV; + // version string snprintf( info->versionString, PAL_GPU_VERSION_SIZE, "%d.%d.%d", - VK_VERSION_MAJOR(info->version), - VK_VERSION_MINOR(info->version), - VK_VERSION_PATCH(info->version)); + VK_VERSION_MAJOR(props.apiVersion), + VK_VERSION_MINOR(props.apiVersion), + VK_VERSION_PATCH(props.apiVersion)); // get supported queue commands Uint32 count; diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index d19911fc..ddb9496f 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -31,7 +31,6 @@ static void initCustomBackend() { adapter->adapterInfo.apiType = PAL_GPU_API_D3D9; adapter->adapterInfo.debugLayerSupported = true; adapter->adapterInfo.type = PAL_GPU_TYPE_INTEGRATED; - adapter->adapterInfo.version = 9; // combine into a single value // PAL needs it in bytes Uint64 byte = 1024 * 1024 * 1024; @@ -42,6 +41,7 @@ static void initCustomBackend() { adapter->adapterInfo.commands |= PAL_GPU_COMMAND_GRAPHICS; adapter->adapterInfo.features |= PAL_GPU_FEATURE_RAY_TRACING; + adapter->adapterInfo.shaderFormat = PAL_GPU_SHADER_FORMAT_DXBC; // second adapter adapter = &s_CustomGPU.adapters[1]; @@ -51,7 +51,6 @@ static void initCustomBackend() { adapter->adapterInfo.apiType = PAL_GPU_API_OPENGL; adapter->adapterInfo.debugLayerSupported = true; adapter->adapterInfo.type = PAL_GPU_TYPE_DISCRETE; - adapter->adapterInfo.version = 4; // combine into a single value // PAL needs it in bytes adapter->adapterInfo.totalMemory = byte * 6; // 6 GB @@ -63,6 +62,8 @@ static void initCustomBackend() { adapter->adapterInfo.commands |= PAL_GPU_COMMAND_COMPUTE; adapter->adapterInfo.features |= PAL_GPU_FEATURE_RAY_TRACING; adapter->adapterInfo.features |= PAL_GPU_FEATURE_MESH_SHADER; + adapter->adapterInfo.shaderFormat |= PAL_GPU_SHADER_FORMAT_SPIRV; + adapter->adapterInfo.shaderFormat |= PAL_GPU_SHADER_FORMAT_GLSL; } static PalResult PAL_CALL customEnumerateGPUAdapters( @@ -95,9 +96,9 @@ static PalResult PAL_CALL customGetGPUAdapterInfo( info->debugLayerSupported = gpuInfo->debugLayerSupported; info->totalMemory = gpuInfo->totalMemory; info->type = gpuInfo->type; - info->version = gpuInfo->version; info->features = gpuInfo->features; info->commands = gpuInfo->commands; + info->shaderFormat = gpuInfo->shaderFormat; strcpy(info->name, gpuInfo->name); strcpy(info->versionString, gpuInfo->versionString); @@ -293,7 +294,33 @@ bool customGraphicsBackendTest() } if (info.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { - palLog(nullptr, " Variable Rate Shading"); + palLog(nullptr, " Variable Rate Shading"); + } + + // shader formats + palLog(nullptr, " Supported Shader Formats:"); + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_SPIRV) { + palLog(nullptr, " SPIRV"); + } + + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_DXIL) { + palLog(nullptr, " DXIL"); + } + + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_DXBC) { + palLog(nullptr, " DXBC"); + } + + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_GLSL) { + palLog(nullptr, " GLSL"); + } + + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_MSL) { + palLog(nullptr, " MSL"); + } + + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_PPM) { + palLog(nullptr, " PPM"); } palLog(nullptr, ""); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index f9c211bb..fbb57ba7 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -61,7 +61,7 @@ bool graphicsTest() return false; } - Uint32 memoryGb = info.totalMemory / (1024 * 1024 * 1024); + Uint32 memoryGb = info.totalMemory / (1024.0 * 1024.0 * 1024.0); palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Total Memory %dGB", memoryGb); palLog(nullptr, " API Version: %s", info.versionString); @@ -140,7 +140,68 @@ bool graphicsTest() } else { boolToString = "False"; } + palLog(nullptr, " Debug Layer: %s", boolToString); + + // commands + palLog(nullptr, " Supported Commands:"); + if (info.commands & PAL_GPU_COMMAND_COMPUTE) { + palLog(nullptr, " Compute"); + } + + if (info.commands & PAL_GPU_COMMAND_GRAPHICS) { + palLog(nullptr, " Graphics"); + } + + if (info.commands & PAL_GPU_COMMAND_TRANSFER) { + palLog(nullptr, " Transfer"); + } + + // features + palLog(nullptr, " Supported Features:"); + if (info.features & PAL_GPU_FEATURE_RAY_TRACING) { + palLog(nullptr, " Ray tracing"); + } + + if (info.features & PAL_GPU_FEATURE_MESH_SHADER) { + palLog(nullptr, " Mesh shading"); + } + + if (info.features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { + palLog(nullptr, " Descriptor indexing"); + } + + if (info.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { + palLog(nullptr, " Variable Rate Shading"); + } + + // shader formats + palLog(nullptr, " Supported Shader Formats:"); + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_SPIRV) { + palLog(nullptr, " SPIRV"); + } + + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_DXIL) { + palLog(nullptr, " DXIL"); + } + + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_DXBC) { + palLog(nullptr, " DXBC"); + } + + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_GLSL) { + palLog(nullptr, " GLSL"); + } + + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_MSL) { + palLog(nullptr, " MSL"); + } + + if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_PPM) { + palLog(nullptr, " PPM"); + } + + palLog(nullptr, ""); } // shutdown the graphics system diff --git a/tests/tests_main.c b/tests/tests_main.c index 500ca43a..df50672e 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,7 +57,7 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest("Graphics Test", graphicsTest); registerTest("Custom Graphics Backend Test", customGraphicsBackendTest); -#endif // +#endif // PAL_HAS_GRAPHICS runTests(); return 0; From f9ad0526d1e3025b74ccbc5d3e2d9ba9d3faf30d Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 26 Nov 2025 10:37:27 +0000 Subject: [PATCH 007/372] create gpudevice custom backend --- include/pal/pal_graphics.h | 15 +++++- src/graphics/pal_graphics_linux.c | 74 ++++++++++++++++++++++++++-- tests/custom_graphics_backend_test.c | 66 ++++++++++++++++++++++++- 3 files changed, 148 insertions(+), 7 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index c25f76bd..4aa52e6a 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -94,6 +94,12 @@ typedef struct { char name[PAL_GPU_NAME_SIZE]; } PalGPUAdapterInfo; +typedef struct { + bool debug; + PalGPUCommands commands; + PalGPUAdapter* adapter; +} PalGPUDeviceCreateInfo; + typedef struct { PalResult PAL_CALL (*enumerateGPUAdapters)( Int32* count, @@ -102,6 +108,12 @@ typedef struct { PalResult PAL_CALL (*getGPUAdapterInfo)( PalGPUAdapter* adapter, PalGPUAdapterInfo* info); + + PalResult PAL_CALL (*createGPUDevice)( + const PalGPUDeviceCreateInfo* info, + PalGPUDevice** outDevice); + + void PAL_CALL (*destroyGPUDevice)(PalGPUDevice* device); } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator); @@ -118,8 +130,7 @@ PAL_API PalResult PAL_CALL palGetGPUAdapterInfo( PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); PAL_API PalResult PAL_CALL palCreateGPUDevice( - bool debug, - PalGPUAdapter* adapter, + const PalGPUDeviceCreateInfo* info, PalGPUDevice** outDevice); PAL_API void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device); diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index f8901d30..2eb4a87d 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -41,6 +41,7 @@ freely, subject to the following restrictions: #define MAX_BACKENDS 16 // should be fine for now #define MAX_ADAPTERS 32 // should be enough +#define MAX_DEVICE 16 // should be enough #if PAL_HAS_VULKAN // VKAPI_PTR expands to nothing on linux @@ -94,6 +95,12 @@ typedef struct { PalGPUAdapter* adapter; } AdapterData; +typedef struct { + bool used; + PalGPUDevice* device; + AdapterData* adapterData; +} DeviceData; + typedef struct { const PalGPUBackend* base; Uint16 startIndex; @@ -120,6 +127,7 @@ typedef struct { void* getPhysicalDeviceFeatures2; AdapterData adapterData[MAX_ADAPTERS]; + DeviceData deviceData[MAX_DEVICE]; AttachGPUBackend backends[MAX_BACKENDS]; } VkGPU; @@ -150,6 +158,27 @@ static AdapterData* findAdapterData(PalGPUAdapter* adapter) return nullptr; } +static DeviceData* getFreeDeviceData() +{ + for (int i = 0; i < MAX_DEVICE; ++i) { + if (!s_VkGPU.deviceData[i].used) { + s_VkGPU.deviceData[i].used = true; + return &s_VkGPU.deviceData[i]; + } + } +} + +static DeviceData* findDeviceData(PalGPUDevice* device) +{ + for (int i = 0; i < MAX_DEVICE; ++i) { + if (s_VkGPU.deviceData[i].used && + s_VkGPU.deviceData[i].device == device) { + return &s_VkGPU.deviceData[i]; + } + } + return nullptr; +} + #if PAL_HAS_VULKAN // we dont want to fill this everytime we want to use static VkAllocationCallbacks s_VkAllocator = {0}; @@ -702,7 +731,9 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) // check if all the function pointers are set // clang-format off if (!backend->enumerateGPUAdapters || - !backend->getGPUAdapterInfo) { + !backend->getGPUAdapterInfo || + !backend->createGPUDevice || + !backend->destroyGPUDevice) { return PAL_RESULT_INVALID_GPU_BACKEND; } // clang-format on @@ -720,14 +751,49 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) // ================================================== PalResult PAL_CALL palCreateGPUDevice( - bool debug, - PalGPUAdapter* adapter, + const PalGPUDeviceCreateInfo* info, PalGPUDevice** outDevice) { + if (!s_VkGPU.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + if (!info || !outDevice) { + return PAL_RESULT_NULL_POINTER; + } + + // check if the adapter is from PAL (custom or internal backend) + AdapterData* adapterData = findAdapterData(info->adapter); + if (!adapterData) { + return PAL_RESULT_INVALID_GPU_ADAPTER; + } + + PalGPUDevice* device = nullptr; + PalResult ret = adapterData->backend->createGPUDevice(info, &device); + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + // create a slot for the created device + DeviceData* deviceData = getFreeDeviceData(); + if (!deviceData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + deviceData->adapterData = adapterData; + deviceData->device = device; + + *outDevice = device; + return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device) { - + if (s_VkGPU.initialized && device) { + DeviceData* data = findDeviceData(device); + if (data) { + data->adapterData->backend->destroyGPUDevice(device); + } + data->used = false; + } } \ No newline at end of file diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index ddb9496f..8d157441 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -11,6 +11,11 @@ typedef struct { // add more fields if needed } CustomGPUAdapter; +typedef struct { + CustomGPUAdapter* adapter; + // add more fields if needed +} CustomGPUDevice; + typedef struct { // we just have only two adapters for simplicity CustomGPUAdapter adapters[2]; @@ -108,9 +113,48 @@ static PalResult PAL_CALL customGetGPUAdapterInfo( } } +PalResult PAL_CALL customCreateGPUDevice( + const PalGPUDeviceCreateInfo* info, + PalGPUDevice** outDevice) +{ + // very simple GPU device. Just an allocation + // no need for checks eithe, PAL does that already for you + // use any allocator you want but its best to use the same allocator + // passed to the graphics system + + CustomGPUDevice* device = nullptr; + device = palAllocate(nullptr, sizeof(CustomGPUDevice), 0); + if (!device) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // if your backend has more than one adapter + // check and create the device with that adapter + for (int i = 0; i < 2; i++) { + PalGPUAdapter* custom = (PalGPUAdapter*)&s_CustomGPU.adapters[i]; + if (info->adapter == custom) { + device->adapter = &s_CustomGPU.adapters[i]; + // additional info for the adapter + break; + } + } + + *outDevice = (PalGPUDevice*)device; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL customDestroyGPUDevice(PalGPUDevice* device) +{ + // get your device + CustomGPUDevice* customDevice = (CustomGPUDevice*)device; + palFree(nullptr, device); +} + static PalGPUBackend s_CustomBackend = { .enumerateGPUAdapters = customEnumerateGPUAdapters, - .getGPUAdapterInfo = customGetGPUAdapterInfo + .getGPUAdapterInfo = customGetGPUAdapterInfo, + .createGPUDevice = customCreateGPUDevice, + .destroyGPUDevice = customDestroyGPUDevice }; bool customGraphicsBackendTest() @@ -173,6 +217,8 @@ bool customGraphicsBackendTest() // get information about all the adapters PalGPUAdapterInfo info; + PalGPUAdapter* d3d9Adapter = nullptr; + for (Int32 i = 0; i < count; i++) { PalGPUAdapter* adapter = adapters[i]; result = palGetGPUAdapterInfo(adapter, &info); @@ -246,6 +292,7 @@ bool customGraphicsBackendTest() case PAL_GPU_API_D3D9: { apiTypeString = "D3D9"; + d3d9Adapter = adapter; break; } @@ -326,6 +373,23 @@ bool customGraphicsBackendTest() palLog(nullptr, ""); } + // create a device with a custom aapter (D3D9) + PalGPUDevice* device = nullptr; + PalGPUDeviceCreateInfo createInfo = {0}; + createInfo.adapter = d3d9Adapter; + createInfo.commands = PAL_GPU_COMMAND_GRAPHICS; // only graphics + createInfo.debug = false; // no debug layer + + result = palCreateGPUDevice(&createInfo, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + palFree(nullptr, adapters); + return false; + } + + palDestroyGPUDevice(device); + // shutdown the graphics system palShutdownGraphics(); From 65f1ea12feb6d9f8c61e0d9f4965d95e7b540a97 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 26 Nov 2025 12:52:26 +0000 Subject: [PATCH 008/372] more feature flags --- include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 39 ++++--- src/graphics/pal_graphics_linux.c | 163 +++++++++++++++++++++++---- src/pal_core.c | 3 + tests/custom_graphics_backend_test.c | 56 ++++----- tests/graphics_test.c | 22 ++-- 6 files changed, 210 insertions(+), 76 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 5a36192a..2fac1088 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -248,7 +248,8 @@ typedef enum { PAL_RESULT_INVALID_FBCONFIG_BACKEND, PAL_RESULT_GRAPHICS_NOT_INITIALIZED, PAL_RESULT_INVALID_GPU_ADAPTER, - PAL_RESULT_INVALID_GPU_BACKEND + PAL_RESULT_INVALID_GPU_BACKEND, + PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 4aa52e6a..bb7d4aa9 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -61,10 +61,10 @@ typedef enum { } PalGPUApiType; typedef enum { - PAL_GPU_COMMAND_GRAPHICS = PAL_BIT64(0), - PAL_GPU_COMMAND_COMPUTE = PAL_BIT64(1), - PAL_GPU_COMMAND_TRANSFER = PAL_BIT64(2) -} PalGPUCommands; + PAL_GPU_COMMAND_QUEUE_GRAPHICS = PAL_BIT64(0), + PAL_GPU_COMMAND_QUEUE_COMPUTE = PAL_BIT64(1), + PAL_GPU_COMMAND_QUEUE_TRANSFER = PAL_BIT64(2) +} PalGPUCommandQueues; typedef enum { PAL_GPU_SHADER_FORMAT_SPIRV = PAL_BIT(0), @@ -73,22 +73,33 @@ typedef enum { PAL_GPU_SHADER_FORMAT_GLSL = PAL_BIT(3), PAL_GPU_SHADER_FORMAT_MSL = PAL_BIT(4), PAL_GPU_SHADER_FORMAT_PPM = PAL_BIT(5) -} PalGPUShaderFormat; +} PalGPUShaderFormats; typedef enum { - PAL_GPU_FEATURE_RAY_TRACING = PAL_BIT64(0), - PAL_GPU_FEATURE_MESH_SHADER = PAL_BIT64(1), - PAL_GPU_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(2), - PAL_GPU_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(3) + PAL_GPU_FEATURE_SAMPLER_ANISOTROPY = PAL_BIT64(0), + PAL_GPU_FEATURE_SAMPLE_RATE_SHADING = PAL_BIT64(1), + PAL_GPU_FEATURE_MULTI_VIEWPORT = PAL_BIT64(2), + PAL_GPU_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(3), + PAL_GPU_FEATURE_TESSELLATION_SHADER = PAL_BIT64(4), + PAL_GPU_FEATURE_GEOMETRY_SHADER = PAL_BIT64(5), + PAL_GPU_FEATURE_SHADER_FLOAT16 = PAL_BIT64(6), + PAL_GPU_FEATURE_SHADER_FLOAT64 = PAL_BIT64(7), + PAL_GPU_FEATURE_SHADER_INT16 = PAL_BIT64(8), + PAL_GPU_FEATURE_SHADER_INT64 = PAL_BIT64(9), + PAL_GPU_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(10), + PAL_GPU_FEATURE_RAY_TRACING = PAL_BIT64(11), + PAL_GPU_FEATURE_MESH_SHADER = PAL_BIT64(12), + PAL_GPU_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(13), + PAL_GPU_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14) } PalGPUFeatures; typedef struct { bool debugLayerSupported; PalGPUType type; PalGPUApiType apiType; - PalGPUShaderFormat shaderFormat; + PalGPUShaderFormats shaderFormats; Uint64 totalMemory; // in bytes - PalGPUCommands commands; + PalGPUCommandQueues commandQueues; PalGPUFeatures features; char versionString[PAL_GPU_VERSION_SIZE]; char name[PAL_GPU_NAME_SIZE]; @@ -96,8 +107,7 @@ typedef struct { typedef struct { bool debug; - PalGPUCommands commands; - PalGPUAdapter* adapter; + PalGPUCommandQueues commandQueues; } PalGPUDeviceCreateInfo; typedef struct { @@ -110,6 +120,7 @@ typedef struct { PalGPUAdapterInfo* info); PalResult PAL_CALL (*createGPUDevice)( + PalGPUAdapter* adapter, const PalGPUDeviceCreateInfo* info, PalGPUDevice** outDevice); @@ -117,6 +128,7 @@ typedef struct { } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator); + PAL_API void PAL_CALL palShutdownGraphics(); PAL_API PalResult PAL_CALL palEnumerateGPUAdapters( @@ -130,6 +142,7 @@ PAL_API PalResult PAL_CALL palGetGPUAdapterInfo( PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); PAL_API PalResult PAL_CALL palCreateGPUDevice( + PalGPUAdapter* adapter, const PalGPUDeviceCreateInfo* info, PalGPUDevice** outDevice); diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 2eb4a87d..000ad631 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -380,7 +380,7 @@ PalResult PAL_CALL vkGetAdapterInfo( PalGPUAdapter* adapter, PalGPUAdapterInfo* info) { - VkPhysicalDevice vkPhysicalDevice = (VkPhysicalDevice)adapter; + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; VkPhysicalDeviceProperties props; VkPhysicalDeviceMemoryProperties memProps; vkGetPhysicalDevicePropertiesFn getProperties; @@ -395,8 +395,8 @@ PalResult PAL_CALL vkGetAdapterInfo( getExtensionProperties = s_VkGPU.enumerateDeviceExtensionProperties; getFeatures2 = s_VkGPU.getPhysicalDeviceFeatures2; - getProperties(vkPhysicalDevice, &props); - getMemoryProperties(vkPhysicalDevice, &memProps); + getProperties(physicalDevice, &props); + getMemoryProperties(physicalDevice, &memProps); strcpy(info->name, props.deviceName); info->debugLayerSupported = s_VkGPU.hasDebug; @@ -441,7 +441,7 @@ PalResult PAL_CALL vkGetAdapterInfo( } // shader format - info->shaderFormat = PAL_GPU_SHADER_FORMAT_SPIRV; + info->shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; // version string snprintf( @@ -455,36 +455,36 @@ PalResult PAL_CALL vkGetAdapterInfo( // get supported queue commands Uint32 count; getQueueProperties( - vkPhysicalDevice, + physicalDevice, &count, nullptr); - // not that huge, we allocate on the stack rather (16 for safety) - VkQueueFamilyProperties queueProps[16]; + // not that huge, we allocate on the stack rather (8 for safety) + VkQueueFamilyProperties queueProps[8]; getQueueProperties( - vkPhysicalDevice, + physicalDevice, &count, queueProps); - info->commands = 0; + info->commandQueues = 0; for (int i = 0; i < count; i++) { if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { - info->commands |= PAL_GPU_COMMAND_COMPUTE; + info->commandQueues |= PAL_GPU_COMMAND_QUEUE_COMPUTE; } if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - info->commands |= PAL_GPU_COMMAND_GRAPHICS; + info->commandQueues |= PAL_GPU_COMMAND_QUEUE_GRAPHICS; } if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { - info->commands |= PAL_GPU_COMMAND_TRANSFER; + info->commandQueues |= PAL_GPU_COMMAND_QUEUE_TRANSFER; } } // get supported extensions Uint32 extensionCount = 0; VkResult ret = getExtensionProperties( - vkPhysicalDevice, + physicalDevice, nullptr, &extensionCount, nullptr); @@ -505,7 +505,7 @@ PalResult PAL_CALL vkGetAdapterInfo( } getExtensionProperties( - vkPhysicalDevice, + physicalDevice, nullptr, &extensionCount, extensionProps); @@ -531,7 +531,7 @@ PalResult PAL_CALL vkGetAdapterInfo( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &mesh; - getFeatures2(vkPhysicalDevice, &features); + getFeatures2(physicalDevice, &features); if (mesh.meshShader && mesh.taskShader) { info->features |= PAL_GPU_FEATURE_MESH_SHADER; @@ -545,7 +545,7 @@ PalResult PAL_CALL vkGetAdapterInfo( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &frag; - getFeatures2(vkPhysicalDevice, &features); + getFeatures2(physicalDevice, &features); if (frag.pipelineFragmentShadingRate) { info->features |= PAL_GPU_FEATURE_VARIABLE_RATE_SHADING; @@ -559,7 +559,7 @@ PalResult PAL_CALL vkGetAdapterInfo( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &desc; - getFeatures2(vkPhysicalDevice, &features); + getFeatures2(physicalDevice, &features); if (desc.shaderSampledImageArrayNonUniformIndexing) { info->features |= PAL_GPU_FEATURE_DESCRIPTOR_INDEXING; @@ -578,7 +578,7 @@ PalResult PAL_CALL vkGetAdapterInfo( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &ray; - getFeatures2(vkPhysicalDevice, &features); + getFeatures2(physicalDevice, &features); if (ray.rayTracingPipeline && acc.accelerationStructure) { info->features |= PAL_GPU_FEATURE_RAY_TRACING; @@ -590,6 +590,127 @@ PalResult PAL_CALL vkGetAdapterInfo( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL vkCreateGPUDevice( + PalGPUAdapter* adapter, + const PalGPUDeviceCreateInfo* info, + PalGPUDevice** outDevice) +{ + VkDevice device = nullptr; + VkPhysicalDevice physicalDevice = (PalGPUAdapter*)adapter; + + // check if the requested queue is supported ny the Adapter and select it + vkGetPhysicalDeviceQueueFamilyPropertiesFn getQueueProperties; + getQueueProperties = s_VkGPU.getPhysicalDeviceQueueFamilyProperties; + Uint32 count; + getQueueProperties( + physicalDevice, + &count, + nullptr); + + // not that huge, we allocate on the stack rather (8 for safety) + VkQueueFamilyProperties queueProps[8]; + getQueueProperties( + physicalDevice, + &count, + queueProps); + + // find the index of all the supported queue families + Int32 computeFamily, graphicsFamily, transferFamily = -1; + for (int i = 0; i < count; i++) { + if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { + if (computeFamily == -1) { + computeFamily = i; + } + } + + if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + if (graphicsFamily == -1) { + graphicsFamily = i; + } + } + + if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { + if (transferFamily == -1) { + transferFamily = i; + } + } + } + + // build queue families + Int32 queueFamilies[3]; // compute, graphics, transfer + Int32 queueFamilyCount = 0; + if (info->commandQueues & PAL_GPU_COMMAND_QUEUE_COMPUTE) { + if (computeFamily == -1) { + // not supported + return PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED; + } + queueFamilies[queueFamilyCount++] = computeFamily; + } + + if (info->commandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { + if (graphicsFamily == -1) { + // not supported + return PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED; + } + + if (graphicsFamily != computeFamily) { + // different families, add a new family entry + queueFamilies[queueFamilyCount++] = graphicsFamily; + } + } + + if (info->commandQueues & PAL_GPU_COMMAND_QUEUE_TRANSFER) { + if (transferFamily == -1) { + // not supported + return PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED; + } + + if (transferFamily != computeFamily && + transferFamily != graphicsFamily) { + // different families, add a new family entry + queueFamilies[queueFamilyCount++] = transferFamily; + } + } + + float priority = 1.0f; + VkDeviceQueueCreateInfo queueCreateInfos[3]; + for (int i = 0; i < queueFamilyCount; i++) { + queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfos[i].pNext = nullptr; + queueCreateInfos[i].pQueuePriorities = &priority; + queueCreateInfos[i].queueFamilyIndex = queueFamilies[i]; + queueCreateInfos[i].queueCount = 1; + queueCreateInfos[i].flags = 0; + } + + VkDeviceCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.pEnabledFeatures = 0; + createInfo.enabledExtensionCount = 0; + createInfo.ppEnabledExtensionNames = nullptr; + createInfo.pQueueCreateInfos = queueCreateInfos; + createInfo.queueCreateInfoCount = queueFamilyCount; + createInfo.pNext = nullptr; + + // VkResult result = vkCreateDevice( + // physicalDevice, + // &createInfo, + // &s_VkAllocator, + // &device); + + // if (result != VK_SUCCESS) { + + // } + + outDevice = (PalGPUDevice*)device; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL vkDestroyGPUDevice(PalGPUDevice* device) +{ + // vkDestroyDevice((VkDevice)device, &s_VkAllocator); +} + static PalGPUBackend s_VkBackend = { .enumerateGPUAdapters = vkEnumerateAdapters, .getGPUAdapterInfo = vkGetAdapterInfo @@ -751,6 +872,7 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) // ================================================== PalResult PAL_CALL palCreateGPUDevice( + PalGPUAdapter* adapter, const PalGPUDeviceCreateInfo* info, PalGPUDevice** outDevice) { @@ -763,13 +885,14 @@ PalResult PAL_CALL palCreateGPUDevice( } // check if the adapter is from PAL (custom or internal backend) - AdapterData* adapterData = findAdapterData(info->adapter); + AdapterData* adapterData = findAdapterData(adapter); if (!adapterData) { return PAL_RESULT_INVALID_GPU_ADAPTER; } PalGPUDevice* device = nullptr; - PalResult ret = adapterData->backend->createGPUDevice(info, &device); + PalResult ret; + ret = adapterData->backend->createGPUDevice(adapter, info, &device); if (ret != PAL_RESULT_SUCCESS) { return ret; } diff --git a/src/pal_core.c b/src/pal_core.c index 8e97229c..3b2fcc62 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -389,6 +389,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_GPU_BACKEND: return "Invalid GPU backend"; + + case PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED: + return "GPU command queue not supported"; } return "Unknown"; } diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index 8d157441..8e6ac8be 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -30,9 +30,6 @@ static CustomGPUBackend s_CustomGPU; // if there is cleanup to do static void initCustomBackend() { CustomGPUAdapter* adapter = &s_CustomGPU.adapters[0]; - adapter->adapterInfo.features = 0; - adapter->adapterInfo.commands = 0; - adapter->adapterInfo.apiType = PAL_GPU_API_D3D9; adapter->adapterInfo.debugLayerSupported = true; adapter->adapterInfo.type = PAL_GPU_TYPE_INTEGRATED; @@ -44,15 +41,12 @@ static void initCustomBackend() { strcpy(adapter->adapterInfo.versionString, "10_1"); strcpy(adapter->adapterInfo.name, "Intel Arc A580"); - adapter->adapterInfo.commands |= PAL_GPU_COMMAND_GRAPHICS; - adapter->adapterInfo.features |= PAL_GPU_FEATURE_RAY_TRACING; - adapter->adapterInfo.shaderFormat = PAL_GPU_SHADER_FORMAT_DXBC; + adapter->adapterInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; + adapter->adapterInfo.features = PAL_GPU_FEATURE_RAY_TRACING; + adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_DXBC; // second adapter adapter = &s_CustomGPU.adapters[1]; - adapter->adapterInfo.features = 0; - adapter->adapterInfo.commands = 0; - adapter->adapterInfo.apiType = PAL_GPU_API_OPENGL; adapter->adapterInfo.debugLayerSupported = true; adapter->adapterInfo.type = PAL_GPU_TYPE_DISCRETE; @@ -63,12 +57,12 @@ static void initCustomBackend() { strcpy(adapter->adapterInfo.versionString, "4.4"); strcpy(adapter->adapterInfo.name, "AMD Radeon RX 7700 XT"); - adapter->adapterInfo.commands |= PAL_GPU_COMMAND_GRAPHICS; - adapter->adapterInfo.commands |= PAL_GPU_COMMAND_COMPUTE; - adapter->adapterInfo.features |= PAL_GPU_FEATURE_RAY_TRACING; + adapter->adapterInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; + adapter->adapterInfo.commandQueues |= PAL_GPU_COMMAND_QUEUE_COMPUTE; + adapter->adapterInfo.features = PAL_GPU_FEATURE_RAY_TRACING; adapter->adapterInfo.features |= PAL_GPU_FEATURE_MESH_SHADER; - adapter->adapterInfo.shaderFormat |= PAL_GPU_SHADER_FORMAT_SPIRV; - adapter->adapterInfo.shaderFormat |= PAL_GPU_SHADER_FORMAT_GLSL; + adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; + adapter->adapterInfo.shaderFormats |= PAL_GPU_SHADER_FORMAT_GLSL; } static PalResult PAL_CALL customEnumerateGPUAdapters( @@ -102,8 +96,8 @@ static PalResult PAL_CALL customGetGPUAdapterInfo( info->totalMemory = gpuInfo->totalMemory; info->type = gpuInfo->type; info->features = gpuInfo->features; - info->commands = gpuInfo->commands; - info->shaderFormat = gpuInfo->shaderFormat; + info->commandQueues = gpuInfo->commandQueues; + info->shaderFormats = gpuInfo->shaderFormats; strcpy(info->name, gpuInfo->name); strcpy(info->versionString, gpuInfo->versionString); @@ -114,6 +108,7 @@ static PalResult PAL_CALL customGetGPUAdapterInfo( } PalResult PAL_CALL customCreateGPUDevice( + PalGPUAdapter* adapter, const PalGPUDeviceCreateInfo* info, PalGPUDevice** outDevice) { @@ -132,7 +127,7 @@ PalResult PAL_CALL customCreateGPUDevice( // check and create the device with that adapter for (int i = 0; i < 2; i++) { PalGPUAdapter* custom = (PalGPUAdapter*)&s_CustomGPU.adapters[i]; - if (info->adapter == custom) { + if (adapter == custom) { device->adapter = &s_CustomGPU.adapters[i]; // additional info for the adapter break; @@ -312,17 +307,17 @@ bool customGraphicsBackendTest() palLog(nullptr, " Debug Layer: %s", boolToString); - // commands - palLog(nullptr, " Supported Commands:"); - if (info.commands & PAL_GPU_COMMAND_COMPUTE) { + // command queues + palLog(nullptr, " Supported Command Queues:"); + if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_COMPUTE) { palLog(nullptr, " Compute"); } - if (info.commands & PAL_GPU_COMMAND_GRAPHICS) { + if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { palLog(nullptr, " Graphics"); } - if (info.commands & PAL_GPU_COMMAND_TRANSFER) { + if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_TRANSFER) { palLog(nullptr, " Transfer"); } @@ -346,27 +341,27 @@ bool customGraphicsBackendTest() // shader formats palLog(nullptr, " Supported Shader Formats:"); - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_SPIRV) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_SPIRV) { palLog(nullptr, " SPIRV"); } - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_DXIL) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_DXIL) { palLog(nullptr, " DXIL"); } - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_DXBC) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_DXBC) { palLog(nullptr, " DXBC"); } - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_GLSL) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_GLSL) { palLog(nullptr, " GLSL"); } - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_MSL) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_MSL) { palLog(nullptr, " MSL"); } - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_PPM) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_PPM) { palLog(nullptr, " PPM"); } @@ -376,11 +371,10 @@ bool customGraphicsBackendTest() // create a device with a custom aapter (D3D9) PalGPUDevice* device = nullptr; PalGPUDeviceCreateInfo createInfo = {0}; - createInfo.adapter = d3d9Adapter; - createInfo.commands = PAL_GPU_COMMAND_GRAPHICS; // only graphics + createInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; // only graphics createInfo.debug = false; // no debug layer - result = palCreateGPUDevice(&createInfo, &device); + result = palCreateGPUDevice(d3d9Adapter, &createInfo, &device); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index fbb57ba7..48f2efea 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -143,17 +143,17 @@ bool graphicsTest() palLog(nullptr, " Debug Layer: %s", boolToString); - // commands - palLog(nullptr, " Supported Commands:"); - if (info.commands & PAL_GPU_COMMAND_COMPUTE) { + // command queue + palLog(nullptr, " Supported Command Queues:"); + if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_COMPUTE) { palLog(nullptr, " Compute"); } - if (info.commands & PAL_GPU_COMMAND_GRAPHICS) { + if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { palLog(nullptr, " Graphics"); } - if (info.commands & PAL_GPU_COMMAND_TRANSFER) { + if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_TRANSFER) { palLog(nullptr, " Transfer"); } @@ -177,27 +177,27 @@ bool graphicsTest() // shader formats palLog(nullptr, " Supported Shader Formats:"); - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_SPIRV) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_SPIRV) { palLog(nullptr, " SPIRV"); } - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_DXIL) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_DXIL) { palLog(nullptr, " DXIL"); } - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_DXBC) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_DXBC) { palLog(nullptr, " DXBC"); } - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_GLSL) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_GLSL) { palLog(nullptr, " GLSL"); } - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_MSL) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_MSL) { palLog(nullptr, " MSL"); } - if (info.shaderFormat & PAL_GPU_SHADER_FORMAT_PPM) { + if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_PPM) { palLog(nullptr, " PPM"); } From e2d769f1da455e7bb6032610ede0446969e030c6 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 26 Nov 2025 15:21:09 +0000 Subject: [PATCH 009/372] more gpudevice features --- include/pal/pal_graphics.h | 13 +- src/graphics/pal_graphics_linux.c | 284 +++++++++++++++++++++++---- tests/custom_graphics_backend_test.c | 57 +++++- tests/graphics_test.c | 55 +++++- 4 files changed, 364 insertions(+), 45 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index bb7d4aa9..5fe4771e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -36,6 +36,11 @@ freely, subject to the following restrictions: #define PAL_GPU_NAME_SIZE 128 #define PAL_GPU_VERSION_SIZE 16 +#define PAL_VERSION_DEFAULT 0x0667 +#define PAL_MAKE_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFFFF)) +#define PAL_VERSION_MAJOR(version) ((version) >> 16) +#define PAL_VERSION_MINOR(version) ((version) & 0xFFFF) + typedef struct PalGPUAdapter PalGPUAdapter; typedef struct PalGPUDevice PalGPUDevice; @@ -90,7 +95,8 @@ typedef enum { PAL_GPU_FEATURE_RAY_TRACING = PAL_BIT64(11), PAL_GPU_FEATURE_MESH_SHADER = PAL_BIT64(12), PAL_GPU_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(13), - PAL_GPU_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14) + PAL_GPU_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), + PAL_GPU_FEATURE_SWAPCHAIN = PAL_BIT64(15) } PalGPUFeatures; typedef struct { @@ -127,7 +133,10 @@ typedef struct { void PAL_CALL (*destroyGPUDevice)(PalGPUDevice* device); } PalGPUBackend; -PAL_API PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator); +PAL_API PalResult PAL_CALL palInitGraphics( + bool enableDebug, + Int32 versionHint, + const PalAllocator* allocator); PAL_API void PAL_CALL palShutdownGraphics(); diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 000ad631..b188a0ab 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -46,6 +46,13 @@ freely, subject to the following restrictions: #if PAL_HAS_VULKAN // VKAPI_PTR expands to nothing on linux +typedef VkResult (*vkEnumerateInstanceVersionFn)(uint32_t*); + +typedef VkResult (*vkEnumerateInstanceExtensionPropertiesFn)( + const char*, + uint32_t*, + VkExtensionProperties*); + typedef VkResult (*vkCreateInstanceFn)( const VkInstanceCreateInfo*, const VkAllocationCallbacks*, @@ -83,6 +90,10 @@ typedef VkResult (*vkEnumerateDeviceExtensionPropertiesFn)( uint32_t*, VkExtensionProperties*); +typedef void (*vkGetPhysicalDeviceFeaturesFn)( + VkPhysicalDevice, + VkPhysicalDeviceFeatures*); + typedef void (*vkGetPhysicalDeviceFeatures2Fn)( VkPhysicalDevice, VkPhysicalDeviceFeatures2*); @@ -116,6 +127,8 @@ typedef struct { void* instance; void* handle; + void* enumerateInstanceVersion; + void* enumerateInstanceExtensionProperties; void* destroyInstance; void* createInstance; void* enumeratePhysicalDevices; @@ -124,6 +137,7 @@ typedef struct { void* enumerateInstanceLayerProperties; void* getPhysicalDeviceQueueFamilyProperties; void* enumerateDeviceExtensionProperties; + void* getPhysicalDeviceFeatures; void* getPhysicalDeviceFeatures2; AdapterData adapterData[MAX_ADAPTERS]; @@ -223,7 +237,9 @@ void* vkRealloc( return nullptr; } -PalResult vkInitGraphics() +PalResult vkInitGraphics( + bool enableDebug, + Int32 versionHint) { // load vulkan s_VkGPU.handle = dlopen("libvulkan.so", RTLD_LAZY); @@ -231,6 +247,14 @@ PalResult vkInitGraphics() return PAL_RESULT_PLATFORM_FAILURE; } + s_VkGPU.enumerateInstanceVersion = dlsym( + s_VkGPU.handle, + "vkEnumerateInstanceVersion"); + + s_VkGPU.enumerateInstanceExtensionProperties = dlsym( + s_VkGPU.handle, + "vkEnumerateInstanceExtensionProperties"); + s_VkGPU.createInstance = dlsym(s_VkGPU.handle, "vkCreateInstance"); s_VkGPU.destroyInstance = dlsym(s_VkGPU.handle, "vkDestroyInstance"); @@ -258,14 +282,146 @@ PalResult vkInitGraphics() s_VkGPU.handle, "vkEnumerateDeviceExtensionProperties"); + s_VkGPU.getPhysicalDeviceFeatures = dlsym( + s_VkGPU.handle, + "vkGetPhysicalDeviceFeatures"); + s_VkGPU.getPhysicalDeviceFeatures2 = dlsym( s_VkGPU.handle, "vkGetPhysicalDeviceFeatures2"); - // create a dummy instance + // get version + Uint32 version = 0; + if (versionHint == PAL_VERSION_DEFAULT) { + vkEnumerateInstanceVersionFn getInstanceVersion; + getInstanceVersion = s_VkGPU.enumerateInstanceVersion; + if (getInstanceVersion) { + getInstanceVersion(&version); + } else { + version = VK_API_VERSION_1_0; + } + + } else { + Uint16 major = PAL_VERSION_MAJOR(versionHint); + Uint16 minor = PAL_VERSION_MINOR(versionHint); + version = VK_MAKE_VERSION(major, minor, 0); + } + + // layers + Uint32 layerCount = 0; + vkEnumerateInstanceLayerPropertiesFn enumerateProperties; + enumerateProperties = s_VkGPU.enumerateInstanceLayerProperties; + VkResult ret = enumerateProperties(&layerCount, nullptr); + if (ret != VK_SUCCESS) { + s_VkGPU.hasDebug = false; + } + + VkLayerProperties* props = nullptr; + props = palAllocate( + s_VkGPU.allocator, + sizeof(VkLayerProperties) * layerCount, + 0); + + if (!props) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + enumerateProperties(&layerCount, props); + bool hasValidationLayer = false; + for (int i = 0; i < layerCount; i++) { + if (strcmp(props[i].layerName, "VK_LAYER_KHRONOS_validation") == 0) { + hasValidationLayer = true; + break; + } + } + + palFree(s_VkGPU.allocator, props); + + // extensions + const char* extensions[8]; + vkEnumerateInstanceExtensionPropertiesFn getExtensionProperties; + getExtensionProperties = s_VkGPU.enumerateInstanceExtensionProperties; + + // get supported extensions + Uint32 extCount = 0; + ret = getExtensionProperties( + nullptr, + &extCount, + nullptr); + + if (ret != VK_SUCCESS) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + VkExtensionProperties* extensionProps = nullptr; + extensionProps = palAllocate( + s_VkGPU.allocator, + sizeof(VkExtensionProperties) * extCount, + 0); + + if (!extensionProps) { + return PAL_RESULT_SUCCESS; + } + + getExtensionProperties( + nullptr, + &extCount, + extensionProps); + + bool hasXlib = false; + bool hasXcb = false; + bool hasWayland = false; + bool hasSurface = false; + bool hasExtDebug = false; + + for (int i = 0; i < extCount; i++) { + VkExtensionProperties* prop = &extensionProps[i]; + if (strcmp(prop->extensionName, "VK_KHR_xlib_surface") == 0) { + hasXlib = true; + + } else if (strcmp(prop->extensionName, "VK_KHR_xcb_surface") == 0) { + hasXcb = true; + + } else if (strcmp(prop->extensionName, "VK_KHR_wayland_surface") == 0) { + hasWayland = true; + + } else if (strcmp(prop->extensionName, "VK_KHR_surface") == 0) { + hasSurface = true; + + } else if (strcmp(prop->extensionName, "VK_EXT_debug_utils") == 0) { + hasExtDebug = true; + } + } + + palFree(s_VkGPU.allocator, extensionProps); + + int extensionCount = 0; + if (hasSurface) { + extensions[extensionCount++] = "VK_KHR_surface"; + if (hasWayland) { + extensions[extensionCount++] = "VK_KHR_wayland_surface"; + } + + if (hasXlib) { + extensions[extensionCount++] = "VK_KHR_xlib_surface"; + } + + if (hasXcb) { + extensions[extensionCount++] = "VK_KHR_xcb_surface"; + } + } + + const char* layers[2]; + layerCount = 0; + if (hasValidationLayer && hasExtDebug) { + s_VkGPU.hasDebug = true; + extensions[extensionCount++] = "VK_EXT_debug_utils"; + layers[layerCount++] = "VK_LAYER_KHRONOS_validation"; + } + VkApplicationInfo appInfo = {0}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.apiVersion = VK_API_VERSION_1_0; // for wider support + appInfo.apiVersion = version; appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.pEngineName = "Engine"; appInfo.pApplicationName = "App"; @@ -274,6 +430,11 @@ PalResult vkInitGraphics() VkInstanceCreateInfo instanceCreateInfo = {0}; instanceCreateInfo.pApplicationInfo = &appInfo; instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instanceCreateInfo.enabledExtensionCount = extensionCount; + instanceCreateInfo.enabledLayerCount = layerCount; + + instanceCreateInfo.ppEnabledExtensionNames = extensions; + instanceCreateInfo.ppEnabledLayerNames = layers; // vk allocator s_VkAllocator.pfnAllocation = vkAlloc; @@ -291,34 +452,6 @@ PalResult vkInitGraphics() return PAL_RESULT_PLATFORM_FAILURE; } - Uint32 count = 0; - vkEnumerateInstanceLayerPropertiesFn enumerateProperties; - enumerateProperties = s_VkGPU.enumerateInstanceLayerProperties; - - VkResult ret = enumerateProperties(&count, nullptr); - if (ret != VK_SUCCESS) { - s_VkGPU.hasDebug = false; - } - - VkLayerProperties* props = nullptr; - props = palAllocate( - s_VkGPU.allocator, - sizeof(VkLayerProperties) * count, - 0); - - if (!props) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - enumerateProperties(&count, props); - for (int i = 0; i < count; i++) { - if (strcmp(props[i].layerName, "VK_LAYER_KHRONOS_validation") == 0) { - s_VkGPU.hasDebug = true; - break; - } - } - - palFree(s_VkGPU.allocator, props); s_VkGPU.instance = instance; return PAL_RESULT_SUCCESS; } @@ -387,12 +520,14 @@ PalResult PAL_CALL vkGetAdapterInfo( vkGetPhysicalDeviceMemoryPropertiesFn getMemoryProperties; vkGetPhysicalDeviceQueueFamilyPropertiesFn getQueueProperties; vkEnumerateDeviceExtensionPropertiesFn getExtensionProperties; + vkGetPhysicalDeviceFeaturesFn getFeatures; vkGetPhysicalDeviceFeatures2Fn getFeatures2; getProperties = s_VkGPU.getPhysicalDeviceProperties; getMemoryProperties = s_VkGPU.getPhysicalDeviceMemoryProperties; getQueueProperties = s_VkGPU.getPhysicalDeviceQueueFamilyProperties; getExtensionProperties = s_VkGPU.enumerateDeviceExtensionProperties; + getFeatures = s_VkGPU.getPhysicalDeviceFeatures; getFeatures2 = s_VkGPU.getPhysicalDeviceFeatures2; getProperties(physicalDevice, &props); @@ -564,6 +699,42 @@ PalResult PAL_CALL vkGetAdapterInfo( if (desc.shaderSampledImageArrayNonUniformIndexing) { info->features |= PAL_GPU_FEATURE_DESCRIPTOR_INDEXING; } + + } else if (strcmp(props->extensionName, "VK_KHR_swapchain") == 0) { + // swapchain + info->features |= PAL_GPU_FEATURE_SWAPCHAIN; + + } else if (strcmp(props->extensionName, "VK_KHR_dynamic_rendering") == 0) { + // dynamic rendering + info->features |= PAL_GPU_FEATURE_DYNAMIC_RENDERING; + + } else if (strcmp(props->extensionName, "VK_KHR_shader_float16_int8") == 0) { + // shader float16 + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; + shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &shader16; + getFeatures2(physicalDevice, &features); + + if (shader16.shaderFloat16) { + info->features |= PAL_GPU_FEATURE_SHADER_FLOAT16; + } + + } else if (strcmp(props->extensionName, "VK_KHR_timeline_semaphore") == 0) { + // timeline semaphore + VkPhysicalDeviceTimelineSemaphoreFeatures timeline = {0}; + timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &timeline; + getFeatures2(physicalDevice, &features); + + if (timeline.timelineSemaphore) { + info->features |= PAL_GPU_FEATURE_TIMELINE_SEMAPHORE; + } } } @@ -586,6 +757,43 @@ PalResult PAL_CALL vkGetAdapterInfo( } // clang-format on + getFeatures = s_VkGPU.getPhysicalDeviceFeatures2; + VkPhysicalDeviceFeatures features; + getFeatures(physicalDevice, &features); + + // check for additional features + if (features.geometryShader) { + info->features |= PAL_GPU_FEATURE_GEOMETRY_SHADER; + } + + if (features.multiViewport) { + info->features |= PAL_GPU_FEATURE_MULTI_VIEWPORT; + } + + if (features.samplerAnisotropy) { + info->features |= PAL_GPU_FEATURE_SAMPLER_ANISOTROPY; + } + + if (features.sampleRateShading) { + info->features |= PAL_GPU_FEATURE_SAMPLE_RATE_SHADING; + } + + if (features.shaderFloat64) { + info->features |= PAL_GPU_FEATURE_SHADER_FLOAT64; + } + + if (features.shaderInt64) { + info->features |= PAL_GPU_FEATURE_SHADER_INT64; + } + + if (features.shaderInt16) { + info->features |= PAL_GPU_FEATURE_SHADER_INT16; + } + + if (features.tessellationShader) { + info->features |= PAL_GPU_FEATURE_TESSELLATION_SHADER; + } + palFree(s_VkGPU.allocator, extensionProps); return PAL_RESULT_SUCCESS; } @@ -596,7 +804,7 @@ PalResult PAL_CALL vkCreateGPUDevice( PalGPUDevice** outDevice) { VkDevice device = nullptr; - VkPhysicalDevice physicalDevice = (PalGPUAdapter*)adapter; + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; // check if the requested queue is supported ny the Adapter and select it vkGetPhysicalDeviceQueueFamilyPropertiesFn getQueueProperties; @@ -702,7 +910,7 @@ PalResult PAL_CALL vkCreateGPUDevice( // } - outDevice = (PalGPUDevice*)device; + *outDevice = (PalGPUDevice*)device; return PAL_RESULT_SUCCESS; } @@ -722,7 +930,10 @@ static PalGPUBackend s_VkBackend = { // Public API // ================================================== -PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator) +PalResult PAL_CALL palInitGraphics( + bool enableDebug, + Int32 versionHint, + const PalAllocator* allocator) { if (s_VkGPU.initialized) { return PAL_RESULT_SUCCESS; @@ -734,7 +945,10 @@ PalResult PAL_CALL palInitGraphics(const PalAllocator* allocator) s_VkGPU.allocator = allocator; #if PAL_HAS_VULKAN - PalResult ret = vkInitGraphics(); + PalResult ret = vkInitGraphics( + enableDebug, + versionHint); + if (ret != PAL_RESULT_SUCCESS) { return ret; } diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index 8e6ac8be..e44cca66 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -43,6 +43,7 @@ static void initCustomBackend() { adapter->adapterInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; adapter->adapterInfo.features = PAL_GPU_FEATURE_RAY_TRACING; + adapter->adapterInfo.features |= PAL_GPU_FEATURE_SWAPCHAIN; adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_DXBC; // second adapter @@ -61,6 +62,7 @@ static void initCustomBackend() { adapter->adapterInfo.commandQueues |= PAL_GPU_COMMAND_QUEUE_COMPUTE; adapter->adapterInfo.features = PAL_GPU_FEATURE_RAY_TRACING; adapter->adapterInfo.features |= PAL_GPU_FEATURE_MESH_SHADER; + adapter->adapterInfo.features |= PAL_GPU_FEATURE_SWAPCHAIN; adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; adapter->adapterInfo.shaderFormats |= PAL_GPU_SHADER_FORMAT_GLSL; } @@ -172,7 +174,7 @@ bool customGraphicsBackendTest() } // initialize the video system - result = palInitGraphics(nullptr); + result = palInitGraphics(true, PAL_VERSION_DEFAULT, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -323,20 +325,67 @@ bool customGraphicsBackendTest() // features palLog(nullptr, " Supported Features:"); + if (info.features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { + palLog(nullptr, " Sampler Anisotropy"); + } + + if (info.features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { + palLog(nullptr, " Sample rate shading"); + } + + if (info.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { + palLog(nullptr, " Multi viewport"); + } + + if (info.features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { + palLog(nullptr, " Timeline Semaphore"); + } + + if (info.features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { + palLog(nullptr, " Tesselation Shader"); + } + + if (info.features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { + palLog(nullptr, " Geometry shader"); + } + + if (info.features & PAL_GPU_FEATURE_SHADER_FLOAT16) { + palLog(nullptr, " Shader float16"); + } + + if (info.features & PAL_GPU_FEATURE_SHADER_FLOAT64) { + palLog(nullptr, " Shader float64"); + } + + if (info.features & PAL_GPU_FEATURE_SHADER_INT16) { + palLog(nullptr, " Shader int16"); + } + if (info.features & PAL_GPU_FEATURE_SHADER_INT64) { + palLog(nullptr, " Shader int64"); + } + + if (info.features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { + palLog(nullptr, " Dynamic rendering"); + } + if (info.features & PAL_GPU_FEATURE_RAY_TRACING) { palLog(nullptr, " Ray tracing"); } if (info.features & PAL_GPU_FEATURE_MESH_SHADER) { - palLog(nullptr, " Mesh shading"); + palLog(nullptr, " Mesh shader"); + } + + if (info.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { + palLog(nullptr, " Variable rate rendering"); } if (info.features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { palLog(nullptr, " Descriptor indexing"); } - if (info.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { - palLog(nullptr, " Variable Rate Shading"); + if (info.features & PAL_GPU_FEATURE_SWAPCHAIN) { + palLog(nullptr, " Swapchain"); } // shader formats diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 48f2efea..3882264c 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -11,7 +11,7 @@ bool graphicsTest() palLog(nullptr, ""); // initialize the video system - PalResult result = palInitGraphics(nullptr); + PalResult result = palInitGraphics(true, PAL_VERSION_DEFAULT, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -159,20 +159,67 @@ bool graphicsTest() // features palLog(nullptr, " Supported Features:"); + if (info.features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { + palLog(nullptr, " Sampler Anisotropy"); + } + + if (info.features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { + palLog(nullptr, " Sample rate shading"); + } + + if (info.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { + palLog(nullptr, " Multi viewport"); + } + + if (info.features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { + palLog(nullptr, " Timeline Semaphore"); + } + + if (info.features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { + palLog(nullptr, " Tesselation Shader"); + } + + if (info.features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { + palLog(nullptr, " Geometry shader"); + } + + if (info.features & PAL_GPU_FEATURE_SHADER_FLOAT16) { + palLog(nullptr, " Shader float16"); + } + + if (info.features & PAL_GPU_FEATURE_SHADER_FLOAT64) { + palLog(nullptr, " Shader float64"); + } + + if (info.features & PAL_GPU_FEATURE_SHADER_INT16) { + palLog(nullptr, " Shader int16"); + } + if (info.features & PAL_GPU_FEATURE_SHADER_INT64) { + palLog(nullptr, " Shader int64"); + } + + if (info.features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { + palLog(nullptr, " Dynamic rendering"); + } + if (info.features & PAL_GPU_FEATURE_RAY_TRACING) { palLog(nullptr, " Ray tracing"); } if (info.features & PAL_GPU_FEATURE_MESH_SHADER) { - palLog(nullptr, " Mesh shading"); + palLog(nullptr, " Mesh shader"); + } + + if (info.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { + palLog(nullptr, " Variable rate rendering"); } if (info.features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { palLog(nullptr, " Descriptor indexing"); } - if (info.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { - palLog(nullptr, " Variable Rate Shading"); + if (info.features & PAL_GPU_FEATURE_SWAPCHAIN) { + palLog(nullptr, " Swapchain"); } // shader formats From 0cf7f034e84601b99bbe0412e624a2dfb3724633 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 27 Nov 2025 09:49:22 +0000 Subject: [PATCH 010/372] dynamic vulkan instance version --- include/pal/pal_graphics.h | 10 +-- src/graphics/pal_graphics_linux.c | 104 +++++++++++++++++------- tests/custom_graphics_backend_test.c | 9 ++- tests/gpu_device_test.c | 114 +++++++++++++++++++++++++++ tests/graphics_test.c | 4 +- tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 3 +- 8 files changed, 205 insertions(+), 43 deletions(-) create mode 100644 tests/gpu_device_test.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 5fe4771e..43d44b56 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -36,11 +36,6 @@ freely, subject to the following restrictions: #define PAL_GPU_NAME_SIZE 128 #define PAL_GPU_VERSION_SIZE 16 -#define PAL_VERSION_DEFAULT 0x0667 -#define PAL_MAKE_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFFFF)) -#define PAL_VERSION_MAJOR(version) ((version) >> 16) -#define PAL_VERSION_MINOR(version) ((version) & 0xFFFF) - typedef struct PalGPUAdapter PalGPUAdapter; typedef struct PalGPUDevice PalGPUDevice; @@ -112,8 +107,8 @@ typedef struct { } PalGPUAdapterInfo; typedef struct { - bool debug; PalGPUCommandQueues commandQueues; + PalGPUFeatures features; } PalGPUDeviceCreateInfo; typedef struct { @@ -134,8 +129,7 @@ typedef struct { } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics( - bool enableDebug, - Int32 versionHint, + bool enableDebugLayer, const PalAllocator* allocator); PAL_API void PAL_CALL palShutdownGraphics(); diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index b188a0ab..75106621 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -98,6 +98,10 @@ typedef void (*vkGetPhysicalDeviceFeatures2Fn)( VkPhysicalDevice, VkPhysicalDeviceFeatures2*); +typedef void (*vkGetPhysicalDeviceFeatures2KHRFn)( + VkPhysicalDevice, + VkPhysicalDeviceFeatures2*); + #endif // PAL_HAS_VULKAN typedef struct { @@ -121,6 +125,7 @@ typedef struct { typedef struct { bool initialized; bool hasDebug; + bool versionFallback; Int32 backendCount; Int32 totalAdapterCount; const PalAllocator* allocator; @@ -139,6 +144,7 @@ typedef struct { void* enumerateDeviceExtensionProperties; void* getPhysicalDeviceFeatures; void* getPhysicalDeviceFeatures2; + void* getPhysicalDeviceFeatures2KHR; AdapterData adapterData[MAX_ADAPTERS]; DeviceData deviceData[MAX_DEVICE]; @@ -237,9 +243,7 @@ void* vkRealloc( return nullptr; } -PalResult vkInitGraphics( - bool enableDebug, - Int32 versionHint) +PalResult vkInitGraphics(bool enableDebugLayer) { // load vulkan s_VkGPU.handle = dlopen("libvulkan.so", RTLD_LAZY); @@ -291,20 +295,15 @@ PalResult vkInitGraphics( "vkGetPhysicalDeviceFeatures2"); // get version + bool versionFallback = false; Uint32 version = 0; - if (versionHint == PAL_VERSION_DEFAULT) { - vkEnumerateInstanceVersionFn getInstanceVersion; - getInstanceVersion = s_VkGPU.enumerateInstanceVersion; - if (getInstanceVersion) { - getInstanceVersion(&version); - } else { - version = VK_API_VERSION_1_0; + vkEnumerateInstanceVersionFn getInstanceVersion; + getInstanceVersion = s_VkGPU.enumerateInstanceVersion; + if (getInstanceVersion) { + getInstanceVersion(&version); + if (version <= VK_API_VERSION_1_0) { + versionFallback = true; } - - } else { - Uint16 major = PAL_VERSION_MAJOR(versionHint); - Uint16 minor = PAL_VERSION_MINOR(versionHint); - version = VK_MAKE_VERSION(major, minor, 0); } // layers @@ -419,6 +418,11 @@ PalResult vkInitGraphics( layers[layerCount++] = "VK_LAYER_KHRONOS_validation"; } + if (versionFallback) { + const char* name = "VK_KHR_get_physical_device_properties2"; + extensions[extensionCount++] = name; + } + VkApplicationInfo appInfo = {0}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.apiVersion = version; @@ -452,6 +456,17 @@ PalResult vkInitGraphics( return PAL_RESULT_PLATFORM_FAILURE; } + // load get physical device properties2 proc if we are on version 1.0 + s_VkGPU.getPhysicalDeviceFeatures2KHR = dlsym( + s_VkGPU.handle, + "vkGetPhysicalDeviceFeatures2KHR"); + + if (s_VkGPU.getPhysicalDeviceFeatures2KHR) { + s_VkGPU.versionFallback = true; + } else { + s_VkGPU.versionFallback = false; + } + s_VkGPU.instance = instance; return PAL_RESULT_SUCCESS; } @@ -522,6 +537,7 @@ PalResult PAL_CALL vkGetAdapterInfo( vkEnumerateDeviceExtensionPropertiesFn getExtensionProperties; vkGetPhysicalDeviceFeaturesFn getFeatures; vkGetPhysicalDeviceFeatures2Fn getFeatures2; + vkGetPhysicalDeviceFeatures2KHRFn getFeatures2KHR; getProperties = s_VkGPU.getPhysicalDeviceProperties; getMemoryProperties = s_VkGPU.getPhysicalDeviceMemoryProperties; @@ -529,6 +545,7 @@ PalResult PAL_CALL vkGetAdapterInfo( getExtensionProperties = s_VkGPU.enumerateDeviceExtensionProperties; getFeatures = s_VkGPU.getPhysicalDeviceFeatures; getFeatures2 = s_VkGPU.getPhysicalDeviceFeatures2; + getFeatures2KHR = s_VkGPU.getPhysicalDeviceFeatures2KHR; getProperties(physicalDevice, &props); getMemoryProperties(physicalDevice, &memProps); @@ -626,6 +643,7 @@ PalResult PAL_CALL vkGetAdapterInfo( if (ret != VK_SUCCESS) { // we just return without any modern features + // this is rare return PAL_RESULT_SUCCESS; } @@ -666,7 +684,13 @@ PalResult PAL_CALL vkGetAdapterInfo( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &mesh; - getFeatures2(physicalDevice, &features); + + if (getFeatures2KHR) { + getFeatures2KHR(physicalDevice, &features); + + } else { + getFeatures2(physicalDevice, &features); + } if (mesh.meshShader && mesh.taskShader) { info->features |= PAL_GPU_FEATURE_MESH_SHADER; @@ -680,7 +704,13 @@ PalResult PAL_CALL vkGetAdapterInfo( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &frag; - getFeatures2(physicalDevice, &features); + + if (getFeatures2KHR) { + getFeatures2KHR(physicalDevice, &features); + + } else { + getFeatures2(physicalDevice, &features); + } if (frag.pipelineFragmentShadingRate) { info->features |= PAL_GPU_FEATURE_VARIABLE_RATE_SHADING; @@ -694,7 +724,13 @@ PalResult PAL_CALL vkGetAdapterInfo( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &desc; - getFeatures2(physicalDevice, &features); + + if (getFeatures2KHR) { + getFeatures2KHR(physicalDevice, &features); + + } else { + getFeatures2(physicalDevice, &features); + } if (desc.shaderSampledImageArrayNonUniformIndexing) { info->features |= PAL_GPU_FEATURE_DESCRIPTOR_INDEXING; @@ -716,7 +752,13 @@ PalResult PAL_CALL vkGetAdapterInfo( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &shader16; - getFeatures2(physicalDevice, &features); + + if (getFeatures2KHR) { + getFeatures2KHR(physicalDevice, &features); + + } else { + getFeatures2(physicalDevice, &features); + } if (shader16.shaderFloat16) { info->features |= PAL_GPU_FEATURE_SHADER_FLOAT16; @@ -730,7 +772,13 @@ PalResult PAL_CALL vkGetAdapterInfo( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &timeline; - getFeatures2(physicalDevice, &features); + + if (getFeatures2KHR) { + getFeatures2KHR(physicalDevice, &features); + + } else { + getFeatures2(physicalDevice, &features); + } if (timeline.timelineSemaphore) { info->features |= PAL_GPU_FEATURE_TIMELINE_SEMAPHORE; @@ -749,7 +797,13 @@ PalResult PAL_CALL vkGetAdapterInfo( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &ray; - getFeatures2(physicalDevice, &features); + + if (getFeatures2KHR) { + getFeatures2KHR(physicalDevice, &features); + + } else { + getFeatures2(physicalDevice, &features); + } if (ray.rayTracingPipeline && acc.accelerationStructure) { info->features |= PAL_GPU_FEATURE_RAY_TRACING; @@ -931,8 +985,7 @@ static PalGPUBackend s_VkBackend = { // ================================================== PalResult PAL_CALL palInitGraphics( - bool enableDebug, - Int32 versionHint, + bool enableDebugLayer, const PalAllocator* allocator) { if (s_VkGPU.initialized) { @@ -945,10 +998,7 @@ PalResult PAL_CALL palInitGraphics( s_VkGPU.allocator = allocator; #if PAL_HAS_VULKAN - PalResult ret = vkInitGraphics( - enableDebug, - versionHint); - + PalResult ret = vkInitGraphics(enableDebugLayer); if (ret != PAL_RESULT_SUCCESS) { return ret; } diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index e44cca66..8096887a 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -173,8 +173,8 @@ bool customGraphicsBackendTest() return false; } - // initialize the video system - result = palInitGraphics(true, PAL_VERSION_DEFAULT, nullptr); + // initialize the graphics system + result = palInitGraphics(true, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -417,11 +417,12 @@ bool customGraphicsBackendTest() palLog(nullptr, ""); } - // create a device with a custom aapter (D3D9) + // create a device with a custom adapter (D3D9) PalGPUDevice* device = nullptr; PalGPUDeviceCreateInfo createInfo = {0}; createInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; // only graphics - createInfo.debug = false; // no debug layer + createInfo.features = PAL_GPU_FEATURE_SHADER_FLOAT64; + createInfo.features |= PAL_GPU_FEATURE_SWAPCHAIN; result = palCreateGPUDevice(d3d9Adapter, &createInfo, &device); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/gpu_device_test.c b/tests/gpu_device_test.c new file mode 100644 index 00000000..a091851a --- /dev/null +++ b/tests/gpu_device_test.c @@ -0,0 +1,114 @@ + +#include "pal/pal_graphics.h" +#include "tests.h" + +bool gpuDeviceTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "GPU Device Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + // initialize the graphics system + PalResult result = palInitGraphics(true, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available GPUs from internal and custom backends + Int32 count = 0; + result = palEnumerateGPUAdapters(&count, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + return false; + } + + if (count == 0) { + palLog(nullptr, "No Adapters found"); + return false; + } + palLog(nullptr, "Adapter (GPUs) Count: %d", count); + + // allocate an array of adapters or use a fixed array + // Example: PalGPUAdapter* adapters[12]; + PalGPUAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalGPUAdapter*) * count, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateGPUAdapters(&count, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + return false; + } + + // get information about all the adapters + PalGPUAdapterInfo info; + PalGPUAdapter* vulkanAdapter = nullptr; + PalGPUCommandQueues vulkanCommandQueues; + PalGPUFeatures vulkanFeatures; + + for (Int32 i = 0; i < count; i++) { + PalGPUAdapter* adapter = adapters[i]; + result = palGetGPUAdapterInfo(adapter, &info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (info.apiType == PAL_GPU_API_VULKAN) { + vulkanAdapter = adapter; + vulkanCommandQueues = info.commandQueues; + vulkanFeatures = info.features; + break; + } + } + + palFree(nullptr, adapters); + if (!vulkanAdapter) { + palLog(nullptr, "Failed to find a vulkan adapter"); + return false; + } + + // create a device with the vulkan adapter + PalGPUDevice* device = nullptr; + PalGPUDeviceCreateInfo deviceCreateInfo = {0}; + + // almost supported on all platforms + if (vulkanCommandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { + deviceCreateInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; + } + + // enable swapchain and maybe multi viewport if supported + if (vulkanFeatures & PAL_GPU_FEATURE_SWAPCHAIN) { + deviceCreateInfo.features = PAL_GPU_FEATURE_SWAPCHAIN; + } + + if (vulkanFeatures & PAL_GPU_FEATURE_MULTI_VIEWPORT) { + deviceCreateInfo.features = PAL_GPU_FEATURE_MULTI_VIEWPORT; + } + + result = palCreateGPUDevice(vulkanAdapter, &deviceCreateInfo, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // destroy the device + palDestroyGPUDevice(device); + + // shutdown the graphics system + palShutdownGraphics(); + + return true; +} \ No newline at end of file diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 3882264c..6cc8ccf5 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -10,8 +10,8 @@ bool graphicsTest() palLog(nullptr, "==========================================="); palLog(nullptr, ""); - // initialize the video system - PalResult result = palInitGraphics(true, PAL_VERSION_DEFAULT, nullptr); + // initialize the graphics system + PalResult result = palInitGraphics(true, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/tests.h b/tests/tests.h index 2bb498ea..2a3159ca 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -56,5 +56,6 @@ bool multiThreadOpenGlTest(); // graphics bool graphicsTest(); bool customGraphicsBackendTest(); +bool gpuDeviceTest(); #endif // _TESTS_H \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index 04f39207..543c312d 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -66,7 +66,8 @@ project "tests" if (PAL_BUILD_GRAPHICS) then files { "graphics_test.c", - "custom_graphics_backend_test.c" + "custom_graphics_backend_test.c", + "gpu_device_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index df50672e..1412780d 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -56,7 +56,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest("Graphics Test", graphicsTest); - registerTest("Custom Graphics Backend Test", customGraphicsBackendTest); + // registerTest("Custom Graphics Backend Test", customGraphicsBackendTest); + registerTest("GPU Device Test", gpuDeviceTest); #endif // PAL_HAS_GRAPHICS runTests(); From 6cf596dbe4e2cb7b2277df221c867f25bfaa7f00 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 27 Nov 2025 10:37:58 +0000 Subject: [PATCH 011/372] code refractor graphics_linux --- src/graphics/pal_graphics_linux.c | 405 +++++++++++++++--------------- tests/tests_main.c | 4 +- 2 files changed, 202 insertions(+), 207 deletions(-) diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 75106621..8e0c2a77 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -102,6 +102,44 @@ typedef void (*vkGetPhysicalDeviceFeatures2KHRFn)( VkPhysicalDevice, VkPhysicalDeviceFeatures2*); +typedef VkResult (*vkCreateDeviceFn)( + VkPhysicalDevice, + const VkDeviceCreateInfo*, + const VkAllocationCallbacks*, + VkDevice*); + +typedef void (*vkDestroyDeviceFn)( + VkDevice, + const VkAllocationCallbacks*); + +typedef struct { + bool hasDebug; + bool versionFallback; + void* handle; + VkInstance instance; + + vkEnumerateInstanceVersionFn enumerateInstanceVersion; + vkEnumerateInstanceExtensionPropertiesFn enumerateInstanceExtensionProperties; + vkDestroyInstanceFn destroyInstance; + vkCreateInstanceFn createInstance; + vkEnumeratePhysicalDevicesFn enumeratePhysicalDevices; + vkGetPhysicalDevicePropertiesFn getPhysicalDeviceProperties; + vkGetPhysicalDeviceMemoryPropertiesFn getPhysicalDeviceMemoryProperties; + vkEnumerateInstanceLayerPropertiesFn enumerateInstanceLayerProperties; + vkGetPhysicalDeviceQueueFamilyPropertiesFn getPhysicalDeviceQueueFamilyProperties; + vkEnumerateDeviceExtensionPropertiesFn enumerateDeviceExtensionProperties; + vkGetPhysicalDeviceFeaturesFn getPhysicalDeviceFeatures; + vkGetPhysicalDeviceFeatures2Fn getPhysicalDeviceFeatures2; + vkGetPhysicalDeviceFeatures2KHRFn getPhysicalDeviceFeatures2KHR; + + vkCreateDeviceFn createDevice; + vkDestroyDeviceFn destroyDevice; + + VkAllocationCallbacks allocator; +} Vulkan; + +static Vulkan s_Vk = {0}; + #endif // PAL_HAS_VULKAN typedef struct { @@ -120,38 +158,19 @@ typedef struct { const PalGPUBackend* base; Uint16 startIndex; Uint16 count; -} AttachGPUBackend; +} AttachBackend; typedef struct { bool initialized; - bool hasDebug; - bool versionFallback; Int32 backendCount; Int32 totalAdapterCount; const PalAllocator* allocator; - void* instance; - void* handle; - - void* enumerateInstanceVersion; - void* enumerateInstanceExtensionProperties; - void* destroyInstance; - void* createInstance; - void* enumeratePhysicalDevices; - void* getPhysicalDeviceProperties; - void* getPhysicalDeviceMemoryProperties; - void* enumerateInstanceLayerProperties; - void* getPhysicalDeviceQueueFamilyProperties; - void* enumerateDeviceExtensionProperties; - void* getPhysicalDeviceFeatures; - void* getPhysicalDeviceFeatures2; - void* getPhysicalDeviceFeatures2KHR; - AdapterData adapterData[MAX_ADAPTERS]; DeviceData deviceData[MAX_DEVICE]; - AttachGPUBackend backends[MAX_BACKENDS]; -} VkGPU; + AttachBackend backends[MAX_BACKENDS]; +} GraphicsLinux; -static VkGPU s_VkGPU = {0}; +static GraphicsLinux s_Graphics = {0}; // ================================================== // Internal API @@ -160,9 +179,9 @@ static VkGPU s_VkGPU = {0}; static AdapterData* getFreeAdapterData() { for (int i = 0; i < MAX_ADAPTERS; ++i) { - if (!s_VkGPU.adapterData[i].used) { - s_VkGPU.adapterData[i].used = true; - return &s_VkGPU.adapterData[i]; + if (!s_Graphics.adapterData[i].used) { + s_Graphics.adapterData[i].used = true; + return &s_Graphics.adapterData[i]; } } } @@ -170,9 +189,9 @@ static AdapterData* getFreeAdapterData() static AdapterData* findAdapterData(PalGPUAdapter* adapter) { for (int i = 0; i < MAX_ADAPTERS; ++i) { - if (s_VkGPU.adapterData[i].used && - s_VkGPU.adapterData[i].adapter == adapter) { - return &s_VkGPU.adapterData[i]; + if (s_Graphics.adapterData[i].used && + s_Graphics.adapterData[i].adapter == adapter) { + return &s_Graphics.adapterData[i]; } } return nullptr; @@ -181,9 +200,9 @@ static AdapterData* findAdapterData(PalGPUAdapter* adapter) static DeviceData* getFreeDeviceData() { for (int i = 0; i < MAX_DEVICE; ++i) { - if (!s_VkGPU.deviceData[i].used) { - s_VkGPU.deviceData[i].used = true; - return &s_VkGPU.deviceData[i]; + if (!s_Graphics.deviceData[i].used) { + s_Graphics.deviceData[i].used = true; + return &s_Graphics.deviceData[i]; } } } @@ -191,17 +210,15 @@ static DeviceData* getFreeDeviceData() static DeviceData* findDeviceData(PalGPUDevice* device) { for (int i = 0; i < MAX_DEVICE; ++i) { - if (s_VkGPU.deviceData[i].used && - s_VkGPU.deviceData[i].device == device) { - return &s_VkGPU.deviceData[i]; + if (s_Graphics.deviceData[i].used && + s_Graphics.deviceData[i].device == device) { + return &s_Graphics.deviceData[i]; } } return nullptr; } #if PAL_HAS_VULKAN -// we dont want to fill this everytime we want to use -static VkAllocationCallbacks s_VkAllocator = {0}; void* vkAlloc( void* pUserData, @@ -209,14 +226,14 @@ void* vkAlloc( size_t alignment, VkSystemAllocationScope allocationScope) { - return palAllocate(s_VkGPU.allocator, size, alignment); + return palAllocate(s_Graphics.allocator, size, alignment); } void vkFree( void* pUserData, void* ptr) { - palFree(s_VkGPU.allocator, ptr); + palFree(s_Graphics.allocator, ptr); } void* vkRealloc( @@ -231,13 +248,14 @@ void* vkRealloc( // this is because we dont know the old size void* block = realloc(pOriginal, size); if (block) { - void* memory = palAllocate(s_VkGPU.allocator, size, alignment); + void* memory = palAllocate(s_Graphics.allocator, size, alignment); if (!memory) { free(block); return nullptr; } memcpy(memory, block, size); + free(block); return memory; } return nullptr; @@ -246,61 +264,67 @@ void* vkRealloc( PalResult vkInitGraphics(bool enableDebugLayer) { // load vulkan - s_VkGPU.handle = dlopen("libvulkan.so", RTLD_LAZY); - if (!s_VkGPU.handle) { + s_Vk.handle = dlopen("libvulkan.so", RTLD_LAZY); + if (!s_Vk.handle) { return PAL_RESULT_PLATFORM_FAILURE; } - s_VkGPU.enumerateInstanceVersion = dlsym( - s_VkGPU.handle, + // clang-format off + s_Vk.enumerateInstanceVersion = (vkEnumerateInstanceVersionFn)dlsym( + s_Vk.handle, "vkEnumerateInstanceVersion"); - s_VkGPU.enumerateInstanceExtensionProperties = dlsym( - s_VkGPU.handle, + s_Vk.enumerateInstanceExtensionProperties = (vkEnumerateInstanceExtensionPropertiesFn)dlsym( + s_Vk.handle, "vkEnumerateInstanceExtensionProperties"); - s_VkGPU.createInstance = dlsym(s_VkGPU.handle, "vkCreateInstance"); - s_VkGPU.destroyInstance = dlsym(s_VkGPU.handle, "vkDestroyInstance"); + s_Vk.createInstance = (vkCreateInstanceFn)dlsym( + s_Vk.handle, + "vkCreateInstance"); + + s_Vk.destroyInstance = (vkDestroyInstanceFn)dlsym( + s_Vk.handle, + "vkDestroyInstance"); - s_VkGPU.enumeratePhysicalDevices = dlsym( - s_VkGPU.handle, + s_Vk.enumeratePhysicalDevices = (vkEnumeratePhysicalDevicesFn)dlsym( + s_Vk.handle, "vkEnumeratePhysicalDevices"); - s_VkGPU.getPhysicalDeviceProperties = dlsym( - s_VkGPU.handle, + s_Vk.getPhysicalDeviceProperties = (vkGetPhysicalDevicePropertiesFn)dlsym( + s_Vk.handle, "vkGetPhysicalDeviceProperties"); - s_VkGPU.getPhysicalDeviceMemoryProperties = dlsym( - s_VkGPU.handle, + s_Vk.getPhysicalDeviceMemoryProperties = (vkGetPhysicalDeviceMemoryPropertiesFn)dlsym( + s_Vk.handle, "vkGetPhysicalDeviceMemoryProperties"); - s_VkGPU.enumerateInstanceLayerProperties = dlsym( - s_VkGPU.handle, + s_Vk.enumerateInstanceLayerProperties = (vkEnumerateInstanceLayerPropertiesFn)dlsym( + s_Vk.handle, "vkEnumerateInstanceLayerProperties"); - s_VkGPU.getPhysicalDeviceQueueFamilyProperties = dlsym( - s_VkGPU.handle, + s_Vk.getPhysicalDeviceQueueFamilyProperties = (vkGetPhysicalDeviceQueueFamilyPropertiesFn)dlsym( + s_Vk.handle, "vkGetPhysicalDeviceQueueFamilyProperties"); - s_VkGPU.enumerateDeviceExtensionProperties = dlsym( - s_VkGPU.handle, + s_Vk.enumerateDeviceExtensionProperties = (vkEnumerateDeviceExtensionPropertiesFn)dlsym( + s_Vk.handle, "vkEnumerateDeviceExtensionProperties"); - s_VkGPU.getPhysicalDeviceFeatures = dlsym( - s_VkGPU.handle, + s_Vk.getPhysicalDeviceFeatures = (vkGetPhysicalDeviceFeaturesFn)dlsym( + s_Vk.handle, "vkGetPhysicalDeviceFeatures"); - s_VkGPU.getPhysicalDeviceFeatures2 = dlsym( - s_VkGPU.handle, + s_Vk.getPhysicalDeviceFeatures2 = (vkGetPhysicalDeviceFeatures2Fn)dlsym( + s_Vk.handle, "vkGetPhysicalDeviceFeatures2"); + // clang-format on + // get version bool versionFallback = false; Uint32 version = 0; - vkEnumerateInstanceVersionFn getInstanceVersion; - getInstanceVersion = s_VkGPU.enumerateInstanceVersion; - if (getInstanceVersion) { - getInstanceVersion(&version); + if (s_Vk.enumerateInstanceVersion) { + s_Vk.enumerateInstanceVersion(&version); if (version <= VK_API_VERSION_1_0) { versionFallback = true; } @@ -308,16 +332,14 @@ PalResult vkInitGraphics(bool enableDebugLayer) // layers Uint32 layerCount = 0; - vkEnumerateInstanceLayerPropertiesFn enumerateProperties; - enumerateProperties = s_VkGPU.enumerateInstanceLayerProperties; - VkResult ret = enumerateProperties(&layerCount, nullptr); + VkResult ret = s_Vk.enumerateInstanceLayerProperties(&layerCount, nullptr); if (ret != VK_SUCCESS) { - s_VkGPU.hasDebug = false; + s_Vk.hasDebug = false; } VkLayerProperties* props = nullptr; props = palAllocate( - s_VkGPU.allocator, + s_Graphics.allocator, sizeof(VkLayerProperties) * layerCount, 0); @@ -325,7 +347,7 @@ PalResult vkInitGraphics(bool enableDebugLayer) return PAL_RESULT_OUT_OF_MEMORY; } - enumerateProperties(&layerCount, props); + s_Vk.enumerateInstanceLayerProperties(&layerCount, props); bool hasValidationLayer = false; for (int i = 0; i < layerCount; i++) { if (strcmp(props[i].layerName, "VK_LAYER_KHRONOS_validation") == 0) { @@ -334,18 +356,14 @@ PalResult vkInitGraphics(bool enableDebugLayer) } } - palFree(s_VkGPU.allocator, props); + palFree(s_Graphics.allocator, props); // extensions - const char* extensions[8]; - vkEnumerateInstanceExtensionPropertiesFn getExtensionProperties; - getExtensionProperties = s_VkGPU.enumerateInstanceExtensionProperties; - - // get supported extensions Uint32 extCount = 0; - ret = getExtensionProperties( + const char* extensions[8]; + ret = s_Vk.enumerateInstanceExtensionProperties( nullptr, - &extCount, + &extCount, nullptr); if (ret != VK_SUCCESS) { @@ -354,7 +372,7 @@ PalResult vkInitGraphics(bool enableDebugLayer) VkExtensionProperties* extensionProps = nullptr; extensionProps = palAllocate( - s_VkGPU.allocator, + s_Graphics.allocator, sizeof(VkExtensionProperties) * extCount, 0); @@ -362,7 +380,7 @@ PalResult vkInitGraphics(bool enableDebugLayer) return PAL_RESULT_SUCCESS; } - getExtensionProperties( + s_Vk.enumerateInstanceExtensionProperties( nullptr, &extCount, extensionProps); @@ -392,7 +410,7 @@ PalResult vkInitGraphics(bool enableDebugLayer) } } - palFree(s_VkGPU.allocator, extensionProps); + palFree(s_Graphics.allocator, extensionProps); int extensionCount = 0; if (hasSurface) { @@ -413,7 +431,7 @@ PalResult vkInitGraphics(bool enableDebugLayer) const char* layers[2]; layerCount = 0; if (hasValidationLayer && hasExtDebug) { - s_VkGPU.hasDebug = true; + s_Vk.hasDebug = true; extensions[extensionCount++] = "VK_EXT_debug_utils"; layers[layerCount++] = "VK_LAYER_KHRONOS_validation"; } @@ -441,42 +459,45 @@ PalResult vkInitGraphics(bool enableDebugLayer) instanceCreateInfo.ppEnabledLayerNames = layers; // vk allocator - s_VkAllocator.pfnAllocation = vkAlloc; - s_VkAllocator.pfnFree = vkFree; - s_VkAllocator.pfnReallocation = vkRealloc; + s_Vk.allocator.pfnAllocation = vkAlloc; + s_Vk.allocator.pfnFree = vkFree; + s_Vk.allocator.pfnReallocation = vkRealloc; VkInstance instance = nullptr; - vkCreateInstanceFn vkCreateInstancePtr = s_VkGPU.createInstance; - VkResult result = vkCreateInstancePtr( + VkResult result = s_Vk.createInstance( &instanceCreateInfo, - &s_VkAllocator, + &s_Vk.allocator, &instance); if (result != VK_SUCCESS) { return PAL_RESULT_PLATFORM_FAILURE; } - // load get physical device properties2 proc if we are on version 1.0 - s_VkGPU.getPhysicalDeviceFeatures2KHR = dlsym( - s_VkGPU.handle, - "vkGetPhysicalDeviceFeatures2KHR"); - - if (s_VkGPU.getPhysicalDeviceFeatures2KHR) { - s_VkGPU.versionFallback = true; - } else { - s_VkGPU.versionFallback = false; + if (versionFallback) { + // load get physical device properties2 proc if we are on version 1.0 + // clang-format off + s_Vk.getPhysicalDeviceFeatures2KHR = (vkGetPhysicalDeviceFeatures2KHRFn)dlsym( + s_Vk.handle, + "vkGetPhysicalDeviceFeatures2KHR"); + // clang-format on + + if (s_Vk.getPhysicalDeviceFeatures2KHR) { + s_Vk.versionFallback = true; + } else { + s_Vk.versionFallback = false; + } } - s_VkGPU.instance = instance; + s_Vk.instance = instance; return PAL_RESULT_SUCCESS; } void vkShutdownGraphics() { - if (s_VkGPU.instance) { - vkDestroyInstanceFn vkDestroyInstancePtr = s_VkGPU.destroyInstance; - vkDestroyInstancePtr(s_VkGPU.instance, &s_VkAllocator); - dlclose(s_VkGPU.handle); + if (s_Vk.instance) { + s_Vk.destroyInstance(s_Vk.instance, &s_Vk.allocator); + dlclose(s_Vk.handle); + memset(&s_Vk, 0, sizeof(s_Vk)); } } @@ -486,41 +507,34 @@ PalResult vkEnumerateAdapters( { int _count = 0; int maxCount = outAdapters ? *count : 0; + VkResult result; - vkEnumeratePhysicalDevicesFn enumerate = s_VkGPU.enumeratePhysicalDevices; - VkResult result = enumerate(s_VkGPU.instance, &_count, nullptr); + result = s_Vk.enumeratePhysicalDevices(s_Vk.instance, &_count, nullptr); if (result != VK_SUCCESS) { return PAL_RESULT_PLATFORM_FAILURE; } - if (outAdapters) { - VkPhysicalDevice* devices = nullptr; - devices = palAllocate( - s_VkGPU.allocator, - sizeof(VkPhysicalDevice) * _count, - 0); - - if (!devices) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - result = enumerate(s_VkGPU.instance, &_count, devices); - if (result != VK_SUCCESS) { - return PAL_RESULT_PLATFORM_FAILURE; - } + if (!outAdapters) { + *count = _count; + return PAL_RESULT_SUCCESS; + } - // write to user array - for (int i = 0; i < _count && i < *count; i++) { - outAdapters[i] = (PalGPUAdapter*)devices[i]; - } + VkPhysicalDevice* devices = nullptr; + devices = palAllocate( + s_Graphics.allocator, + sizeof(VkPhysicalDevice) * _count, + 0); - palFree(s_VkGPU.allocator, devices); + if (!devices) { + return PAL_RESULT_OUT_OF_MEMORY; } - if (!outAdapters) { - *count = _count; + s_Vk.enumeratePhysicalDevices(s_Vk.instance, &_count, devices); + for (int i = 0; i < _count && i < *count; i++) { + outAdapters[i] = (PalGPUAdapter*)devices[i]; } + palFree(s_Graphics.allocator, devices); return PAL_RESULT_SUCCESS; } @@ -528,30 +542,15 @@ PalResult PAL_CALL vkGetAdapterInfo( PalGPUAdapter* adapter, PalGPUAdapterInfo* info) { + VkResult ret; VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; VkPhysicalDeviceProperties props; VkPhysicalDeviceMemoryProperties memProps; - vkGetPhysicalDevicePropertiesFn getProperties; - vkGetPhysicalDeviceMemoryPropertiesFn getMemoryProperties; - vkGetPhysicalDeviceQueueFamilyPropertiesFn getQueueProperties; - vkEnumerateDeviceExtensionPropertiesFn getExtensionProperties; - vkGetPhysicalDeviceFeaturesFn getFeatures; - vkGetPhysicalDeviceFeatures2Fn getFeatures2; - vkGetPhysicalDeviceFeatures2KHRFn getFeatures2KHR; - - getProperties = s_VkGPU.getPhysicalDeviceProperties; - getMemoryProperties = s_VkGPU.getPhysicalDeviceMemoryProperties; - getQueueProperties = s_VkGPU.getPhysicalDeviceQueueFamilyProperties; - getExtensionProperties = s_VkGPU.enumerateDeviceExtensionProperties; - getFeatures = s_VkGPU.getPhysicalDeviceFeatures; - getFeatures2 = s_VkGPU.getPhysicalDeviceFeatures2; - getFeatures2KHR = s_VkGPU.getPhysicalDeviceFeatures2KHR; - - getProperties(physicalDevice, &props); - getMemoryProperties(physicalDevice, &memProps); + s_Vk.getPhysicalDeviceProperties(physicalDevice, &props); + s_Vk.getPhysicalDeviceMemoryProperties(physicalDevice, &memProps); strcpy(info->name, props.deviceName); - info->debugLayerSupported = s_VkGPU.hasDebug; + info->debugLayerSupported = s_Vk.hasDebug; // get total memory Uint64 memory = 0; @@ -606,14 +605,14 @@ PalResult PAL_CALL vkGetAdapterInfo( // get supported queue commands Uint32 count; - getQueueProperties( - physicalDevice, + s_Vk.getPhysicalDeviceQueueFamilyProperties( + physicalDevice, &count, nullptr); // not that huge, we allocate on the stack rather (8 for safety) VkQueueFamilyProperties queueProps[8]; - getQueueProperties( + s_Vk.getPhysicalDeviceQueueFamilyProperties( physicalDevice, &count, queueProps); @@ -635,21 +634,20 @@ PalResult PAL_CALL vkGetAdapterInfo( // get supported extensions Uint32 extensionCount = 0; - VkResult ret = getExtensionProperties( - physicalDevice, + ret = s_Vk.enumerateDeviceExtensionProperties( + physicalDevice, nullptr, &extensionCount, nullptr); if (ret != VK_SUCCESS) { - // we just return without any modern features - // this is rare + // we just return without any modern features which is rare return PAL_RESULT_SUCCESS; } VkExtensionProperties* extensionProps = nullptr; extensionProps = palAllocate( - s_VkGPU.allocator, + s_Graphics.allocator, sizeof(VkExtensionProperties) * extensionCount, 0); @@ -657,7 +655,7 @@ PalResult PAL_CALL vkGetAdapterInfo( return PAL_RESULT_SUCCESS; } - getExtensionProperties( + s_Vk.enumerateDeviceExtensionProperties( physicalDevice, nullptr, &extensionCount, @@ -685,11 +683,11 @@ PalResult PAL_CALL vkGetAdapterInfo( features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &mesh; - if (getFeatures2KHR) { - getFeatures2KHR(physicalDevice, &features); + if (s_Vk.getPhysicalDeviceFeatures2KHR) { + s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); } else { - getFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); } if (mesh.meshShader && mesh.taskShader) { @@ -705,11 +703,11 @@ PalResult PAL_CALL vkGetAdapterInfo( features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &frag; - if (getFeatures2KHR) { - getFeatures2KHR(physicalDevice, &features); + if (s_Vk.getPhysicalDeviceFeatures2KHR) { + s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); } else { - getFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); } if (frag.pipelineFragmentShadingRate) { @@ -725,11 +723,11 @@ PalResult PAL_CALL vkGetAdapterInfo( features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &desc; - if (getFeatures2KHR) { - getFeatures2KHR(physicalDevice, &features); + if (s_Vk.getPhysicalDeviceFeatures2KHR) { + s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); } else { - getFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); } if (desc.shaderSampledImageArrayNonUniformIndexing) { @@ -753,11 +751,11 @@ PalResult PAL_CALL vkGetAdapterInfo( features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &shader16; - if (getFeatures2KHR) { - getFeatures2KHR(physicalDevice, &features); + if (s_Vk.getPhysicalDeviceFeatures2KHR) { + s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); } else { - getFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); } if (shader16.shaderFloat16) { @@ -773,11 +771,11 @@ PalResult PAL_CALL vkGetAdapterInfo( features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &timeline; - if (getFeatures2KHR) { - getFeatures2KHR(physicalDevice, &features); + if (s_Vk.getPhysicalDeviceFeatures2KHR) { + s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); } else { - getFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); } if (timeline.timelineSemaphore) { @@ -798,11 +796,11 @@ PalResult PAL_CALL vkGetAdapterInfo( features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &ray; - if (getFeatures2KHR) { - getFeatures2KHR(physicalDevice, &features); + if (s_Vk.getPhysicalDeviceFeatures2KHR) { + s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); } else { - getFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); } if (ray.rayTracingPipeline && acc.accelerationStructure) { @@ -810,10 +808,8 @@ PalResult PAL_CALL vkGetAdapterInfo( } } // clang-format on - - getFeatures = s_VkGPU.getPhysicalDeviceFeatures2; VkPhysicalDeviceFeatures features; - getFeatures(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures(physicalDevice, &features); // check for additional features if (features.geometryShader) { @@ -848,7 +844,7 @@ PalResult PAL_CALL vkGetAdapterInfo( info->features |= PAL_GPU_FEATURE_TESSELLATION_SHADER; } - palFree(s_VkGPU.allocator, extensionProps); + palFree(s_Graphics.allocator, extensionProps); return PAL_RESULT_SUCCESS; } @@ -857,21 +853,20 @@ PalResult PAL_CALL vkCreateGPUDevice( const PalGPUDeviceCreateInfo* info, PalGPUDevice** outDevice) { + VkResult ret; VkDevice device = nullptr; VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; - // check if the requested queue is supported ny the Adapter and select it - vkGetPhysicalDeviceQueueFamilyPropertiesFn getQueueProperties; - getQueueProperties = s_VkGPU.getPhysicalDeviceQueueFamilyProperties; + // check if the requested queue is supported by the adapter and select it Uint32 count; - getQueueProperties( + s_Vk.getPhysicalDeviceQueueFamilyProperties( physicalDevice, &count, nullptr); // not that huge, we allocate on the stack rather (8 for safety) VkQueueFamilyProperties queueProps[8]; - getQueueProperties( + s_Vk.getPhysicalDeviceQueueFamilyProperties( physicalDevice, &count, queueProps); @@ -954,13 +949,13 @@ PalResult PAL_CALL vkCreateGPUDevice( createInfo.queueCreateInfoCount = queueFamilyCount; createInfo.pNext = nullptr; - // VkResult result = vkCreateDevice( + // ret = s_Vk.createDevice( // physicalDevice, // &createInfo, - // &s_VkAllocator, + // &s_Vk.allocator, // &device); - // if (result != VK_SUCCESS) { + // if (ret != VK_SUCCESS) { // } @@ -970,7 +965,7 @@ PalResult PAL_CALL vkCreateGPUDevice( void PAL_CALL vkDestroyGPUDevice(PalGPUDevice* device) { - // vkDestroyDevice((VkDevice)device, &s_VkAllocator); + s_Vk.destroyDevice((VkDevice)device, &s_Vk.allocator); } static PalGPUBackend s_VkBackend = { @@ -988,7 +983,7 @@ PalResult PAL_CALL palInitGraphics( bool enableDebugLayer, const PalAllocator* allocator) { - if (s_VkGPU.initialized) { + if (s_Graphics.initialized) { return PAL_RESULT_SUCCESS; } @@ -996,26 +991,26 @@ PalResult PAL_CALL palInitGraphics( return PAL_RESULT_INVALID_ALLOCATOR; } - s_VkGPU.allocator = allocator; + s_Graphics.allocator = allocator; #if PAL_HAS_VULKAN PalResult ret = vkInitGraphics(enableDebugLayer); if (ret != PAL_RESULT_SUCCESS) { return ret; } - AttachGPUBackend* backend = &s_VkGPU.backends[s_VkGPU.backendCount++]; + AttachBackend* backend = &s_Graphics.backends[s_Graphics.backendCount++]; backend->base = &s_VkBackend; backend->count = 0; backend->startIndex = 0; #endif // PAL_HAS_VULKAN - s_VkGPU.initialized = true; + s_Graphics.initialized = true; return PAL_RESULT_SUCCESS; } void PAL_CALL palShutdownGraphics() { - if (!s_VkGPU.initialized) { + if (!s_Graphics.initialized) { return; } @@ -1023,8 +1018,8 @@ void PAL_CALL palShutdownGraphics() vkShutdownGraphics(); #endif // PAL_HAS_VULKAN - memset(&s_VkGPU, 0, sizeof(VkGPU)); - s_VkGPU.initialized = false; // just in case + memset(&s_Graphics, 0, sizeof(s_Graphics)); + s_Graphics.initialized = false; } // ================================================== @@ -1036,7 +1031,7 @@ PalResult PAL_CALL palEnumerateGPUAdapters( PalGPUAdapter** outAdapters) { // enumerate all adapters for both custom and PAL backends - if (!s_VkGPU.initialized) { + if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } @@ -1053,8 +1048,8 @@ PalResult PAL_CALL palEnumerateGPUAdapters( int index = 0; int _count = outAdapters ? *count : 0; - for (int i = 0; i < s_VkGPU.backendCount; i++) { - AttachGPUBackend* backend = &s_VkGPU.backends[i]; + for (int i = 0; i < s_Graphics.backendCount; i++) { + AttachBackend* backend = &s_Graphics.backends[i]; if (outAdapters) { // offset into the array so all backends write at the correct index PalGPUAdapter** adapters = &outAdapters[backend->startIndex]; @@ -1091,7 +1086,7 @@ PalResult PAL_CALL palGetGPUAdapterInfo( PalGPUAdapter* adapter, PalGPUAdapterInfo* info) { - if (!s_VkGPU.initialized) { + if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } @@ -1109,7 +1104,7 @@ PalResult PAL_CALL palGetGPUAdapterInfo( PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) { - if (s_VkGPU.initialized) { + if (s_Graphics.initialized) { return PAL_RESULT_INVALID_GPU_BACKEND; } @@ -1123,7 +1118,7 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) } // clang-format on - AttachGPUBackend* attached = &s_VkGPU.backends[s_VkGPU.backendCount++]; + AttachBackend* attached = &s_Graphics.backends[s_Graphics.backendCount++]; attached->base = backend; attached->startIndex = 0; attached->count = 0; @@ -1140,7 +1135,7 @@ PalResult PAL_CALL palCreateGPUDevice( const PalGPUDeviceCreateInfo* info, PalGPUDevice** outDevice) { - if (!s_VkGPU.initialized) { + if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } @@ -1176,11 +1171,11 @@ PalResult PAL_CALL palCreateGPUDevice( void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device) { - if (s_VkGPU.initialized && device) { + if (s_Graphics.initialized && device) { DeviceData* data = findDeviceData(device); if (data) { data->adapterData->backend->destroyGPUDevice(device); + data->used = false; } - data->used = false; } } \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index 1412780d..5b8cb639 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,9 +55,9 @@ int main(int argc, char** argv) #endif // #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); + registerTest("Graphics Test", graphicsTest); // registerTest("Custom Graphics Backend Test", customGraphicsBackendTest); - registerTest("GPU Device Test", gpuDeviceTest); + // registerTest("GPU Device Test", gpuDeviceTest); #endif // PAL_HAS_GRAPHICS runTests(); From 1d478322bb8070c7e98a05c1d80d491dfb4a990d Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 27 Nov 2025 13:29:45 +0000 Subject: [PATCH 012/372] gpu device create and destroy --- include/pal/pal_core.h | 4 +- include/pal/pal_graphics.h | 15 + src/graphics/pal_graphics_linux.c | 391 +++++++++++++++++++++++---- src/pal_core.c | 6 + tests/custom_graphics_backend_test.c | 21 +- tests/gpu_device_test.c | 37 ++- tests/graphics_test.c | 4 +- tests/tests_main.c | 4 +- 8 files changed, 414 insertions(+), 68 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 2fac1088..d12c01b1 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -249,7 +249,9 @@ typedef enum { PAL_RESULT_GRAPHICS_NOT_INITIALIZED, PAL_RESULT_INVALID_GPU_ADAPTER, PAL_RESULT_INVALID_GPU_BACKEND, - PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED + PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED, + PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED, + PAL_RESULT_INVALID_GRAPHICS_DRIVER, } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 43d44b56..118f1cc7 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -94,6 +94,13 @@ typedef enum { PAL_GPU_FEATURE_SWAPCHAIN = PAL_BIT64(15) } PalGPUFeatures; +typedef struct { + PalGPUType type; + PalGPUApiType apiType; + char versionString[PAL_GPU_VERSION_SIZE]; + char name[PAL_GPU_NAME_SIZE]; +} PalGPUAdapterSubInfo; + typedef struct { bool debugLayerSupported; PalGPUType type; @@ -116,6 +123,10 @@ typedef struct { Int32* count, PalGPUAdapter** outAdapters); + PalResult PAL_CALL (*getGPUAdapterSubInfo)( + PalGPUAdapter* adapter, + PalGPUAdapterSubInfo* info); + PalResult PAL_CALL (*getGPUAdapterInfo)( PalGPUAdapter* adapter, PalGPUAdapterInfo* info); @@ -142,6 +153,10 @@ PAL_API PalResult PAL_CALL palGetGPUAdapterInfo( PalGPUAdapter* adapter, PalGPUAdapterInfo* info); +PAL_API PalResult PAL_CALL palGetGPUAdapterSubInfo( + PalGPUAdapter* adapter, + PalGPUAdapterSubInfo* info); + PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); PAL_API PalResult PAL_CALL palCreateGPUDevice( diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 8e0c2a77..0224e45c 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -220,6 +220,42 @@ static DeviceData* findDeviceData(PalGPUDevice* device) #if PAL_HAS_VULKAN +static PalResult vkResultToPal(VkResult result) +{ + switch (result) { + case VK_ERROR_FEATURE_NOT_PRESENT: + case VK_ERROR_EXTENSION_NOT_PRESENT: { + return PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED; + } + + case VK_ERROR_OUT_OF_HOST_MEMORY: + case VK_ERROR_TOO_MANY_OBJECTS: + case VK_ERROR_OUT_OF_DEVICE_MEMORY: { + return PAL_RESULT_OUT_OF_MEMORY; + } + + case VK_ERROR_INITIALIZATION_FAILED: + case VK_ERROR_DEVICE_LOST: { + return PAL_RESULT_PLATFORM_FAILURE; + } + + case VK_ERROR_INCOMPATIBLE_DRIVER: + return PAL_RESULT_INVALID_GRAPHICS_DRIVER; + + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: + case VK_ERROR_SURFACE_LOST_KHR: { + return PAL_RESULT_INVALID_WINDOW; + } + + case VK_TIMEOUT: + return PAL_RESULT_TIMEOUT; + + default: + return PAL_RESULT_PLATFORM_FAILURE; + } + return PAL_RESULT_PLATFORM_FAILURE; +} + void* vkAlloc( void* pUserData, size_t size, @@ -318,6 +354,14 @@ PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.handle, "vkGetPhysicalDeviceFeatures2"); + s_Vk.createDevice = (vkCreateDeviceFn)dlsym( + s_Vk.handle, + "vkCreateDevice"); + + s_Vk.destroyDevice = (vkDestroyDeviceFn)dlsym( + s_Vk.handle, + "vkDestroyDevice"); + // clang-format on // get version @@ -330,33 +374,40 @@ PalResult vkInitGraphics(bool enableDebugLayer) } } - // layers + VkResult ret; Uint32 layerCount = 0; - VkResult ret = s_Vk.enumerateInstanceLayerProperties(&layerCount, nullptr); - if (ret != VK_SUCCESS) { - s_Vk.hasDebug = false; - } + bool hasValidationLayer = false; + if (enableDebugLayer) { + // layers + ret = s_Vk.enumerateInstanceLayerProperties( + &layerCount, + nullptr); + + if (ret != VK_SUCCESS) { + s_Vk.hasDebug = false; + } - VkLayerProperties* props = nullptr; - props = palAllocate( - s_Graphics.allocator, - sizeof(VkLayerProperties) * layerCount, - 0); + VkLayerProperties* props = nullptr; + props = palAllocate( + s_Graphics.allocator, + sizeof(VkLayerProperties) * layerCount, + 0); - if (!props) { - return PAL_RESULT_OUT_OF_MEMORY; - } + if (!props) { + return PAL_RESULT_OUT_OF_MEMORY; + } - s_Vk.enumerateInstanceLayerProperties(&layerCount, props); - bool hasValidationLayer = false; - for (int i = 0; i < layerCount; i++) { - if (strcmp(props[i].layerName, "VK_LAYER_KHRONOS_validation") == 0) { - hasValidationLayer = true; - break; + s_Vk.enumerateInstanceLayerProperties(&layerCount, props); + for (int i = 0; i < layerCount; i++) { + const char* name = props[i].layerName; + if (strcmp(name, "VK_LAYER_KHRONOS_validation") == 0) { + hasValidationLayer = true; + break; + } } - } - palFree(s_Graphics.allocator, props); + palFree(s_Graphics.allocator, props); + } // extensions Uint32 extCount = 0; @@ -470,7 +521,7 @@ PalResult vkInitGraphics(bool enableDebugLayer) &instance); if (result != VK_SUCCESS) { - return PAL_RESULT_PLATFORM_FAILURE; + return vkResultToPal(result); } if (versionFallback) { @@ -671,7 +722,7 @@ PalResult PAL_CALL vkGetAdapterInfo( if (strcmp(props->extensionName, "VK_KHR_ray_tracing_pipeline") == 0) { rayTracingFound = true; - } else if (strcmp(props->extensionName, "VK_KHR_acceleration_structur") == 0) { + } else if (strcmp(props->extensionName, "VK_KHR_acceleration_structure") == 0) { accelerateFound = true; } else if (strcmp(props->extensionName, "VK_EXT_mesh_shader") == 0) { @@ -848,6 +899,57 @@ PalResult PAL_CALL vkGetAdapterInfo( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL vkGetAdapterSubInfo( + PalGPUAdapter* adapter, + PalGPUAdapterSubInfo* info) +{ + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; + VkPhysicalDeviceProperties props; + + s_Vk.getPhysicalDeviceProperties(physicalDevice, &props); + strcpy(info->name, props.deviceName); + info->apiType = PAL_GPU_API_VULKAN; + + // get device type + switch (props.deviceType) { + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { + info->type = PAL_GPU_TYPE_INTEGRATED; + break; + } + + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { + info->type = PAL_GPU_TYPE_DISCRETE; + break; + } + + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { + info->type = PAL_GPU_TYPE_VIRTUAL; + break; + } + + case VK_PHYSICAL_DEVICE_TYPE_CPU: { + info->type = PAL_GPU_TYPE_CPU; + break; + } + + default: { + info->type = PAL_GPU_TYPE_UNKNOWN; + break; + } + } + + // version string + snprintf( + info->versionString, + PAL_GPU_VERSION_SIZE, + "%d.%d.%d", + VK_VERSION_MAJOR(props.apiVersion), + VK_VERSION_MINOR(props.apiVersion), + VK_VERSION_PATCH(props.apiVersion)); + + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL vkCreateGPUDevice( PalGPUAdapter* adapter, const PalGPUDeviceCreateInfo* info, @@ -872,7 +974,10 @@ PalResult PAL_CALL vkCreateGPUDevice( queueProps); // find the index of all the supported queue families - Int32 computeFamily, graphicsFamily, transferFamily = -1; + Int32 computeFamily = -1; + Int32 graphicsFamily = -1; + Int32 transferFamily = -1; + for (int i = 0; i < count; i++) { if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { if (computeFamily == -1) { @@ -894,11 +999,10 @@ PalResult PAL_CALL vkCreateGPUDevice( } // build queue families - Int32 queueFamilies[3]; // compute, graphics, transfer + Int32 queueFamilies[3] = {0}; // compute, graphics, transfer Int32 queueFamilyCount = 0; if (info->commandQueues & PAL_GPU_COMMAND_QUEUE_COMPUTE) { if (computeFamily == -1) { - // not supported return PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED; } queueFamilies[queueFamilyCount++] = computeFamily; @@ -906,26 +1010,32 @@ PalResult PAL_CALL vkCreateGPUDevice( if (info->commandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { if (graphicsFamily == -1) { - // not supported return PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED; } - if (graphicsFamily != computeFamily) { - // different families, add a new family entry + if (queueFamilyCount == 0) { queueFamilies[queueFamilyCount++] = graphicsFamily; - } + + } else { + if (graphicsFamily != computeFamily) { + queueFamilies[queueFamilyCount++] = graphicsFamily; + } + } } if (info->commandQueues & PAL_GPU_COMMAND_QUEUE_TRANSFER) { if (transferFamily == -1) { - // not supported return PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED; } - if (transferFamily != computeFamily && - transferFamily != graphicsFamily) { - // different families, add a new family entry - queueFamilies[queueFamilyCount++] = transferFamily; + if (queueFamilyCount == 0) { + queueFamilies[queueFamilyCount++] = graphicsFamily; + + } else { + if (transferFamily != computeFamily && + transferFamily != graphicsFamily) { + queueFamilies[queueFamilyCount++] = transferFamily; + } } } @@ -940,24 +1050,186 @@ PalResult PAL_CALL vkCreateGPUDevice( queueCreateInfos[i].flags = 0; } + // build features and extensions capabilities + VkPhysicalDeviceFeatures features = {0}; + if (info->features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { + features.samplerAnisotropy = true; + } + + if (info->features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { + features.sampleRateShading = true; + } + + if (info->features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { + features.multiViewport = true; + } + + if (info->features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { + features.tessellationShader = true; + } + + if (info->features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { + features.geometryShader = true; + } + + if (info->features & PAL_GPU_FEATURE_SHADER_INT16) { + features.shaderInt16 = true; + } + + if (info->features & PAL_GPU_FEATURE_SHADER_INT64) { + features.shaderInt64 = true; + } + + if (info->features & PAL_GPU_FEATURE_SHADER_FLOAT64) { + features.shaderFloat64 = true; + } + + // extensions and features2 + int extCount = 0; + const char* extensions[12]; + + // clang-format off + + const void* start = nullptr; + VkPhysicalDeviceTimelineSemaphoreFeatures timeline = {0}; + timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; + + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; + shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; + + VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; + mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; + + VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; + VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; + ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; + acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + + VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs = {0}; + vrs.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; + + VkPhysicalDeviceDescriptorIndexingFeatures descIndex = {0}; + descIndex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + + // clang-format on + + if (info->features & PAL_GPU_FEATURE_SWAPCHAIN) { + extensions[extCount++] = "VK_KHR_swapchain"; + } + + if (info->features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { + extensions[extCount++] = "VK_KHR_dynamic_rendering"; + } + + if (info->features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { + extensions[extCount++] = "VK_KHR_timeline_semaphore"; + timeline.timelineSemaphore = true; + start = &timeline; + } + + if (info->features & PAL_GPU_FEATURE_SHADER_FLOAT16) { + extensions[extCount++] = "VK_KHR_shader_float16_int8"; + shader16.shaderFloat16 = true; + + if (timeline.timelineSemaphore) { + timeline.pNext = &shader16; + } + start = &shader16; + } + + if (info->features & PAL_GPU_FEATURE_RAY_TRACING) { + extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; + extensions[extCount++] = "VK_KHR_acceleration_structure"; + ray.rayTracingPipeline = true; + acc.accelerationStructure = true; + + if (shader16.shaderFloat16) { + shader16.pNext = &ray; + + } else if (timeline.timelineSemaphore) { + // no shader16, check timeline + timeline.pNext = &ray; + } + ray.pNext = &acc; + start = &ray; + } + + if (info->features & PAL_GPU_FEATURE_MESH_SHADER) { + extensions[extCount++] = "VK_EXT_mesh_shader"; + mesh.meshShader = true; + mesh.taskShader = true; + + if (acc.accelerationStructure) { + acc.pNext = &mesh; + + } else if (shader16.shaderFloat16) { + shader16.pNext = &mesh; + + } else if (timeline.timelineSemaphore) { + timeline.pNext = &mesh; + } + start = &mesh; + } + + if (info->features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { + extensions[extCount++] = "VK_KHR_fragment_shading_rate"; + vrs.pipelineFragmentShadingRate = true; + + if (mesh.meshShader) { + mesh.pNext = &vrs; + + } else if (acc.accelerationStructure) { + acc.pNext = &vrs; + + } else if (shader16.shaderFloat16) { + shader16.pNext = &vrs; + + } else if (timeline.timelineSemaphore) { + timeline.pNext = &vrs; + } + start = &vrs; + } + + if (info->features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { + extensions[extCount++] = "VK_EXT_descriptor_indexing"; + descIndex.shaderSampledImageArrayNonUniformIndexing = true; + + if (vrs.pipelineFragmentShadingRate) { + vrs.pNext = &descIndex; + + } else if (mesh.meshShader) { + mesh.pNext = &descIndex; + + } else if (acc.accelerationStructure) { + acc.pNext = &descIndex; + + } else if (shader16.shaderFloat16) { + shader16.pNext = &descIndex; + + } else if (timeline.timelineSemaphore) { + timeline.pNext = &descIndex; + } + start = &descIndex; + } + VkDeviceCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - createInfo.pEnabledFeatures = 0; - createInfo.enabledExtensionCount = 0; - createInfo.ppEnabledExtensionNames = nullptr; + createInfo.pEnabledFeatures = &features; + createInfo.enabledExtensionCount = extCount; + createInfo.ppEnabledExtensionNames = extensions; createInfo.pQueueCreateInfos = queueCreateInfos; createInfo.queueCreateInfoCount = queueFamilyCount; - createInfo.pNext = nullptr; - - // ret = s_Vk.createDevice( - // physicalDevice, - // &createInfo, - // &s_Vk.allocator, - // &device); + createInfo.pNext = start; - // if (ret != VK_SUCCESS) { + ret = s_Vk.createDevice( + physicalDevice, + &createInfo, + &s_Vk.allocator, + &device); - // } + if (ret != VK_SUCCESS) { + return vkResultToPal(ret); + } *outDevice = (PalGPUDevice*)device; return PAL_RESULT_SUCCESS; @@ -970,7 +1242,10 @@ void PAL_CALL vkDestroyGPUDevice(PalGPUDevice* device) static PalGPUBackend s_VkBackend = { .enumerateGPUAdapters = vkEnumerateAdapters, - .getGPUAdapterInfo = vkGetAdapterInfo + .getGPUAdapterInfo = vkGetAdapterInfo, + .getGPUAdapterSubInfo = vkGetAdapterSubInfo, + .createGPUDevice = vkCreateGPUDevice, + .destroyGPUDevice = vkDestroyGPUDevice }; #endif // PAL_HAS_VULKAN @@ -1102,6 +1377,26 @@ PalResult PAL_CALL palGetGPUAdapterInfo( return PAL_RESULT_INVALID_GPU_ADAPTER; } +PalResult PAL_CALL palGetGPUAdapterSubInfo( + PalGPUAdapter* adapter, + PalGPUAdapterSubInfo* info) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!adapter || !info) { + return PAL_RESULT_NULL_POINTER; + } + + AdapterData* data = findAdapterData(adapter); + if (data) { + return data->backend->getGPUAdapterSubInfo(adapter, info); + } + + return PAL_RESULT_INVALID_GPU_ADAPTER; +} + PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) { if (s_Graphics.initialized) { diff --git a/src/pal_core.c b/src/pal_core.c index 3b2fcc62..075ea1df 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -392,6 +392,12 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED: return "GPU command queue not supported"; + + case PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED: + return "Unsupported gpu feature"; + + case PAL_RESULT_INVALID_GRAPHICS_DRIVER: + return "Incompatible graphics driver"; } return "Unknown"; } diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index 8096887a..70292752 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -109,6 +109,25 @@ static PalResult PAL_CALL customGetGPUAdapterInfo( } } +static PalResult PAL_CALL customGetGPUAdapterSubInfo( + PalGPUAdapter* adapter, + PalGPUAdapterSubInfo* info) +{ + for (int i = 0; i < 2; i++) { + PalGPUAdapter* custom = (PalGPUAdapter*)&s_CustomGPU.adapters[i]; + if (custom == adapter) { + // make a copy + PalGPUAdapterInfo* gpuInfo = &s_CustomGPU.adapters[i].adapterInfo; + info->apiType = gpuInfo->apiType; + info->type = gpuInfo->type; + strcpy(info->name, gpuInfo->name); + strcpy(info->versionString, gpuInfo->versionString); + + return PAL_RESULT_SUCCESS; + } + } +} + PalResult PAL_CALL customCreateGPUDevice( PalGPUAdapter* adapter, const PalGPUDeviceCreateInfo* info, @@ -174,7 +193,7 @@ bool customGraphicsBackendTest() } // initialize the graphics system - result = palInitGraphics(true, nullptr); + result = palInitGraphics(false, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/gpu_device_test.c b/tests/gpu_device_test.c index a091851a..35f3d050 100644 --- a/tests/gpu_device_test.c +++ b/tests/gpu_device_test.c @@ -11,7 +11,7 @@ bool gpuDeviceTest() palLog(nullptr, ""); // initialize the graphics system - PalResult result = palInitGraphics(true, nullptr); + PalResult result = palInitGraphics(false, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -49,26 +49,23 @@ bool gpuDeviceTest() return false; } - // get information about all the adapters - PalGPUAdapterInfo info; + // filter the adapters for Vulkan PalGPUAdapter* vulkanAdapter = nullptr; - PalGPUCommandQueues vulkanCommandQueues; - PalGPUFeatures vulkanFeatures; + PalGPUAdapterSubInfo subInfo = {0}; for (Int32 i = 0; i < count; i++) { PalGPUAdapter* adapter = adapters[i]; - result = palGetGPUAdapterInfo(adapter, &info); + result = palGetGPUAdapterSubInfo(adapter, &subInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + palLog(nullptr, "Failed to get adapter sub info: %s", error); palFree(nullptr, adapters); return false; } - if (info.apiType == PAL_GPU_API_VULKAN) { + // check if its Vulkan + if (subInfo.apiType == PAL_GPU_API_VULKAN) { vulkanAdapter = adapter; - vulkanCommandQueues = info.commandQueues; - vulkanFeatures = info.features; break; } } @@ -79,22 +76,34 @@ bool gpuDeviceTest() return false; } + // get information about the adapter + // this time, we want all the information including + // supported features and the rest + PalGPUAdapterInfo info = {0}; + result = palGetGPUAdapterInfo(vulkanAdapter, &info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + palFree(nullptr, adapters); + return false; + } + // create a device with the vulkan adapter PalGPUDevice* device = nullptr; PalGPUDeviceCreateInfo deviceCreateInfo = {0}; // almost supported on all platforms - if (vulkanCommandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { + if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { deviceCreateInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; } // enable swapchain and maybe multi viewport if supported - if (vulkanFeatures & PAL_GPU_FEATURE_SWAPCHAIN) { + if (info.features & PAL_GPU_FEATURE_SWAPCHAIN) { deviceCreateInfo.features = PAL_GPU_FEATURE_SWAPCHAIN; } - if (vulkanFeatures & PAL_GPU_FEATURE_MULTI_VIEWPORT) { - deviceCreateInfo.features = PAL_GPU_FEATURE_MULTI_VIEWPORT; + if (info.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { + deviceCreateInfo.features |= PAL_GPU_FEATURE_MULTI_VIEWPORT; } result = palCreateGPUDevice(vulkanAdapter, &deviceCreateInfo, &device); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 6cc8ccf5..bcea1846 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -10,8 +10,8 @@ bool graphicsTest() palLog(nullptr, "==========================================="); palLog(nullptr, ""); - // initialize the graphics system - PalResult result = palInitGraphics(true, nullptr); + // initialize the graphics system + PalResult result = palInitGraphics(false, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/tests_main.c b/tests/tests_main.c index 5b8cb639..1412780d 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,9 +55,9 @@ int main(int argc, char** argv) #endif // #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + // registerTest("Graphics Test", graphicsTest); // registerTest("Custom Graphics Backend Test", customGraphicsBackendTest); - // registerTest("GPU Device Test", gpuDeviceTest); + registerTest("GPU Device Test", gpuDeviceTest); #endif // PAL_HAS_GRAPHICS runTests(); From d4d6145e85d3d2f98e20d099ff34ef0ffcbbf0d5 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 27 Nov 2025 18:04:54 +0000 Subject: [PATCH 013/372] command queues vulkan --- include/pal/pal_graphics.h | 16 +- src/graphics/pal_graphics_linux.c | 212 +++++++++++++-------------- tests/custom_graphics_backend_test.c | 26 +++- tests/gpu_device_test.c | 13 +- tests/graphics_test.c | 7 + 5 files changed, 146 insertions(+), 128 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 118f1cc7..c3068be8 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -101,6 +101,12 @@ typedef struct { char name[PAL_GPU_NAME_SIZE]; } PalGPUAdapterSubInfo; +typedef struct { + Uint32 maxComputeQueues; + Uint32 maxGraphicsQueues; + Uint32 maxTransferQueues; +} PalGPUCommandQueuesInfo; + typedef struct { bool debugLayerSupported; PalGPUType type; @@ -109,15 +115,11 @@ typedef struct { Uint64 totalMemory; // in bytes PalGPUCommandQueues commandQueues; PalGPUFeatures features; + PalGPUCommandQueuesInfo commandQueuesInfo; char versionString[PAL_GPU_VERSION_SIZE]; char name[PAL_GPU_NAME_SIZE]; } PalGPUAdapterInfo; -typedef struct { - PalGPUCommandQueues commandQueues; - PalGPUFeatures features; -} PalGPUDeviceCreateInfo; - typedef struct { PalResult PAL_CALL (*enumerateGPUAdapters)( Int32* count, @@ -133,7 +135,7 @@ typedef struct { PalResult PAL_CALL (*createGPUDevice)( PalGPUAdapter* adapter, - const PalGPUDeviceCreateInfo* info, + PalGPUFeatures features, PalGPUDevice** outDevice); void PAL_CALL (*destroyGPUDevice)(PalGPUDevice* device); @@ -161,7 +163,7 @@ PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); PAL_API PalResult PAL_CALL palCreateGPUDevice( PalGPUAdapter* adapter, - const PalGPUDeviceCreateInfo* info, + PalGPUFeatures features, PalGPUDevice** outDevice); PAL_API void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device); diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 0224e45c..2fe63f51 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -42,6 +42,8 @@ freely, subject to the following restrictions: #define MAX_BACKENDS 16 // should be fine for now #define MAX_ADAPTERS 32 // should be enough #define MAX_DEVICE 16 // should be enough +#define MAX_QUEUE_FAMILIES 8 +#define MAX_PHYSICAL_QUEUES 16 #if PAL_HAS_VULKAN // VKAPI_PTR expands to nothing on linux @@ -112,6 +114,12 @@ typedef void (*vkDestroyDeviceFn)( VkDevice, const VkAllocationCallbacks*); +typedef void (*vkGetDeviceQueueFn)( + VkDevice, + uint32_t, + uint32_t, + VkQueue*); + typedef struct { bool hasDebug; bool versionFallback; @@ -134,10 +142,28 @@ typedef struct { vkCreateDeviceFn createDevice; vkDestroyDeviceFn destroyDevice; + vkGetDeviceQueueFn getDeviceQueue; VkAllocationCallbacks allocator; } Vulkan; +typedef struct { + Int32 count; + Int32 index; + VkQueueFlags flags; +} QueueFamilyData; + +typedef struct { + VkQueue handle; + VkQueueFlags usage; +} PhysicalQueue; + +typedef struct { + Int32 queueCount; + VkDevice handle; + PhysicalQueue queues[MAX_PHYSICAL_QUEUES]; +} VkGPUDevice; + static Vulkan s_Vk = {0}; #endif // PAL_HAS_VULKAN @@ -361,6 +387,10 @@ PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.destroyDevice = (vkDestroyDeviceFn)dlsym( s_Vk.handle, "vkDestroyDevice"); + + s_Vk.getDeviceQueue = (vkGetDeviceQueueFn)dlsym( + s_Vk.handle, + "vkGetDeviceQueue"); // clang-format on @@ -661,25 +691,32 @@ PalResult PAL_CALL vkGetAdapterInfo( &count, nullptr); - // not that huge, we allocate on the stack rather (8 for safety) - VkQueueFamilyProperties queueProps[8]; + VkQueueFamilyProperties queueProps[MAX_QUEUE_FAMILIES]; s_Vk.getPhysicalDeviceQueueFamilyProperties( physicalDevice, &count, queueProps); + PalGPUCommandQueuesInfo* queueInfo = &info->commandQueuesInfo; + queueInfo->maxComputeQueues = 0; + queueInfo->maxGraphicsQueues = 0; + queueInfo->maxTransferQueues = 0; info->commandQueues = 0; + for (int i = 0; i < count; i++) { if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { info->commandQueues |= PAL_GPU_COMMAND_QUEUE_COMPUTE; + queueInfo->maxComputeQueues += queueProps->queueCount; } if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { info->commandQueues |= PAL_GPU_COMMAND_QUEUE_GRAPHICS; + queueInfo->maxGraphicsQueues += queueProps->queueCount; } if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { info->commandQueues |= PAL_GPU_COMMAND_QUEUE_TRANSFER; + queueInfo->maxTransferQueues += queueProps->queueCount; } } @@ -952,141 +989,83 @@ PalResult PAL_CALL vkGetAdapterSubInfo( PalResult PAL_CALL vkCreateGPUDevice( PalGPUAdapter* adapter, - const PalGPUDeviceCreateInfo* info, + PalGPUFeatures features, PalGPUDevice** outDevice) { - VkResult ret; + VkResult ret = VK_SUCCESS; VkDevice device = nullptr; VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; - // check if the requested queue is supported by the adapter and select it - Uint32 count; + Uint32 count = 0; s_Vk.getPhysicalDeviceQueueFamilyProperties( physicalDevice, &count, nullptr); - // not that huge, we allocate on the stack rather (8 for safety) - VkQueueFamilyProperties queueProps[8]; + VkQueueFamilyProperties queueProps[MAX_QUEUE_FAMILIES]; s_Vk.getPhysicalDeviceQueueFamilyProperties( physicalDevice, &count, queueProps); - // find the index of all the supported queue families - Int32 computeFamily = -1; - Int32 graphicsFamily = -1; - Int32 transferFamily = -1; - - for (int i = 0; i < count; i++) { - if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { - if (computeFamily == -1) { - computeFamily = i; - } - } - - if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - if (graphicsFamily == -1) { - graphicsFamily = i; - } - } - - if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { - if (transferFamily == -1) { - transferFamily = i; - } - } - } - - // build queue families - Int32 queueFamilies[3] = {0}; // compute, graphics, transfer Int32 queueFamilyCount = 0; - if (info->commandQueues & PAL_GPU_COMMAND_QUEUE_COMPUTE) { - if (computeFamily == -1) { - return PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED; - } - queueFamilies[queueFamilyCount++] = computeFamily; - } - - if (info->commandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { - if (graphicsFamily == -1) { - return PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED; - } - - if (queueFamilyCount == 0) { - queueFamilies[queueFamilyCount++] = graphicsFamily; - - } else { - if (graphicsFamily != computeFamily) { - queueFamilies[queueFamilyCount++] = graphicsFamily; - } - } - } - - if (info->commandQueues & PAL_GPU_COMMAND_QUEUE_TRANSFER) { - if (transferFamily == -1) { - return PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED; - } - - if (queueFamilyCount == 0) { - queueFamilies[queueFamilyCount++] = graphicsFamily; - - } else { - if (transferFamily != computeFamily && - transferFamily != graphicsFamily) { - queueFamilies[queueFamilyCount++] = transferFamily; - } - } + QueueFamilyData queueFamilyData[MAX_QUEUE_FAMILIES]; + for (int i = 0; i < count; i++) { + VkQueueFamilyProperties* prop = &queueProps[i]; + QueueFamilyData* data = &queueFamilyData[queueFamilyCount++]; + data->count = prop->queueCount; + data->flags = prop->queueFlags; + data->index = i; } float priority = 1.0f; - VkDeviceQueueCreateInfo queueCreateInfos[3]; + VkDeviceQueueCreateInfo queueCreateInfos[MAX_QUEUE_FAMILIES]; for (int i = 0; i < queueFamilyCount; i++) { queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfos[i].pNext = nullptr; queueCreateInfos[i].pQueuePriorities = &priority; - queueCreateInfos[i].queueFamilyIndex = queueFamilies[i]; - queueCreateInfos[i].queueCount = 1; + queueCreateInfos[i].queueFamilyIndex = queueFamilyData[i].index; + queueCreateInfos[i].queueCount = queueFamilyData[i].count; queueCreateInfos[i].flags = 0; } // build features and extensions capabilities - VkPhysicalDeviceFeatures features = {0}; - if (info->features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { - features.samplerAnisotropy = true; + VkPhysicalDeviceFeatures coreFeatures = {0}; + if (features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { + coreFeatures.samplerAnisotropy = true; } - if (info->features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { - features.sampleRateShading = true; + if (features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { + coreFeatures.sampleRateShading = true; } - if (info->features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { - features.multiViewport = true; + if (features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { + coreFeatures.multiViewport = true; } - if (info->features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { - features.tessellationShader = true; + if (features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { + coreFeatures.tessellationShader = true; } - if (info->features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { - features.geometryShader = true; + if (features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { + coreFeatures.geometryShader = true; } - if (info->features & PAL_GPU_FEATURE_SHADER_INT16) { - features.shaderInt16 = true; + if (features & PAL_GPU_FEATURE_SHADER_INT16) { + coreFeatures.shaderInt16 = true; } - if (info->features & PAL_GPU_FEATURE_SHADER_INT64) { - features.shaderInt64 = true; + if (features & PAL_GPU_FEATURE_SHADER_INT64) { + coreFeatures.shaderInt64 = true; } - if (info->features & PAL_GPU_FEATURE_SHADER_FLOAT64) { - features.shaderFloat64 = true; + if (features & PAL_GPU_FEATURE_SHADER_FLOAT64) { + coreFeatures.shaderFloat64 = true; } // extensions and features2 int extCount = 0; - const char* extensions[12]; + const char* extensions[16] = {0}; // clang-format off @@ -1113,21 +1092,21 @@ PalResult PAL_CALL vkCreateGPUDevice( // clang-format on - if (info->features & PAL_GPU_FEATURE_SWAPCHAIN) { + if (features & PAL_GPU_FEATURE_SWAPCHAIN) { extensions[extCount++] = "VK_KHR_swapchain"; } - if (info->features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { + if (features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { extensions[extCount++] = "VK_KHR_dynamic_rendering"; } - if (info->features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { + if (features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { extensions[extCount++] = "VK_KHR_timeline_semaphore"; timeline.timelineSemaphore = true; start = &timeline; } - if (info->features & PAL_GPU_FEATURE_SHADER_FLOAT16) { + if (features & PAL_GPU_FEATURE_SHADER_FLOAT16) { extensions[extCount++] = "VK_KHR_shader_float16_int8"; shader16.shaderFloat16 = true; @@ -1137,7 +1116,7 @@ PalResult PAL_CALL vkCreateGPUDevice( start = &shader16; } - if (info->features & PAL_GPU_FEATURE_RAY_TRACING) { + if (features & PAL_GPU_FEATURE_RAY_TRACING) { extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; extensions[extCount++] = "VK_KHR_acceleration_structure"; ray.rayTracingPipeline = true; @@ -1154,7 +1133,7 @@ PalResult PAL_CALL vkCreateGPUDevice( start = &ray; } - if (info->features & PAL_GPU_FEATURE_MESH_SHADER) { + if (features & PAL_GPU_FEATURE_MESH_SHADER) { extensions[extCount++] = "VK_EXT_mesh_shader"; mesh.meshShader = true; mesh.taskShader = true; @@ -1171,7 +1150,7 @@ PalResult PAL_CALL vkCreateGPUDevice( start = &mesh; } - if (info->features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { + if (features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { extensions[extCount++] = "VK_KHR_fragment_shading_rate"; vrs.pipelineFragmentShadingRate = true; @@ -1190,7 +1169,7 @@ PalResult PAL_CALL vkCreateGPUDevice( start = &vrs; } - if (info->features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { + if (features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { extensions[extCount++] = "VK_EXT_descriptor_indexing"; descIndex.shaderSampledImageArrayNonUniformIndexing = true; @@ -1214,7 +1193,7 @@ PalResult PAL_CALL vkCreateGPUDevice( VkDeviceCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - createInfo.pEnabledFeatures = &features; + createInfo.pEnabledFeatures = &coreFeatures; createInfo.enabledExtensionCount = extCount; createInfo.ppEnabledExtensionNames = extensions; createInfo.pQueueCreateInfos = queueCreateInfos; @@ -1231,13 +1210,34 @@ PalResult PAL_CALL vkCreateGPUDevice( return vkResultToPal(ret); } - *outDevice = (PalGPUDevice*)device; + VkGPUDevice* gpuDevice = nullptr; + gpuDevice = palAllocate(s_Graphics.allocator, sizeof(VkGPUDevice), 0); + if (!gpuDevice) { + s_Vk.destroyDevice(device, &s_Vk.allocator); + return PAL_RESULT_OUT_OF_MEMORY; + } + memset(gpuDevice, 0, sizeof(VkGPUDevice)); + + // get queues + gpuDevice->handle = device; + for (int i = 0; i < queueFamilyCount; i++) { + QueueFamilyData* data = &queueFamilyData[i]; + for (int j = 0; j < data->count; j++) { + PhysicalQueue* queue = &gpuDevice->queues[gpuDevice->queueCount++]; + s_Vk.getDeviceQueue(device, data->index, 0, &queue->handle); + queue->usage = data->flags; + } + } + + *outDevice = (PalGPUDevice*)gpuDevice; return PAL_RESULT_SUCCESS; } void PAL_CALL vkDestroyGPUDevice(PalGPUDevice* device) { - s_Vk.destroyDevice((VkDevice)device, &s_Vk.allocator); + VkGPUDevice* gpuDevice = (VkGPUDevice*)device; + s_Vk.destroyDevice(gpuDevice->handle, &s_Vk.allocator); + palFree(s_Graphics.allocator, gpuDevice); } static PalGPUBackend s_VkBackend = { @@ -1427,14 +1427,14 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) PalResult PAL_CALL palCreateGPUDevice( PalGPUAdapter* adapter, - const PalGPUDeviceCreateInfo* info, + PalGPUFeatures features, PalGPUDevice** outDevice) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!info || !outDevice) { + if (!outDevice) { return PAL_RESULT_NULL_POINTER; } @@ -1446,7 +1446,7 @@ PalResult PAL_CALL palCreateGPUDevice( PalGPUDevice* device = nullptr; PalResult ret; - ret = adapterData->backend->createGPUDevice(adapter, info, &device); + ret = adapterData->backend->createGPUDevice(adapter, features, &device); if (ret != PAL_RESULT_SUCCESS) { return ret; } diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index 70292752..4e7c791a 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -46,6 +46,10 @@ static void initCustomBackend() { adapter->adapterInfo.features |= PAL_GPU_FEATURE_SWAPCHAIN; adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_DXBC; + adapter->adapterInfo.commandQueuesInfo.maxComputeQueues = 1; + adapter->adapterInfo.commandQueuesInfo.maxGraphicsQueues = 1; + adapter->adapterInfo.commandQueuesInfo.maxTransferQueues = 2; + // second adapter adapter = &s_CustomGPU.adapters[1]; adapter->adapterInfo.apiType = PAL_GPU_API_OPENGL; @@ -65,6 +69,10 @@ static void initCustomBackend() { adapter->adapterInfo.features |= PAL_GPU_FEATURE_SWAPCHAIN; adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; adapter->adapterInfo.shaderFormats |= PAL_GPU_SHADER_FORMAT_GLSL; + + adapter->adapterInfo.commandQueuesInfo.maxComputeQueues = 1; + adapter->adapterInfo.commandQueuesInfo.maxGraphicsQueues = 4; + adapter->adapterInfo.commandQueuesInfo.maxTransferQueues = 4; } static PalResult PAL_CALL customEnumerateGPUAdapters( @@ -100,6 +108,7 @@ static PalResult PAL_CALL customGetGPUAdapterInfo( info->features = gpuInfo->features; info->commandQueues = gpuInfo->commandQueues; info->shaderFormats = gpuInfo->shaderFormats; + info->commandQueuesInfo = gpuInfo->commandQueuesInfo; strcpy(info->name, gpuInfo->name); strcpy(info->versionString, gpuInfo->versionString); @@ -130,7 +139,7 @@ static PalResult PAL_CALL customGetGPUAdapterSubInfo( PalResult PAL_CALL customCreateGPUDevice( PalGPUAdapter* adapter, - const PalGPUDeviceCreateInfo* info, + PalGPUFeatures features, PalGPUDevice** outDevice) { // very simple GPU device. Just an allocation @@ -329,6 +338,13 @@ bool customGraphicsBackendTest() palLog(nullptr, " Debug Layer: %s", boolToString); // command queues + Int32 maxComputeQueues = info.commandQueuesInfo.maxComputeQueues; + Int32 maxGraphicsQueues = info.commandQueuesInfo.maxGraphicsQueues; + Int32 maxTransferQueues = info.commandQueuesInfo.maxTransferQueues; + palLog(nullptr, " Max compute command queues: %d", maxComputeQueues); + palLog(nullptr, " Max graphics command queues: %d", maxGraphicsQueues); + palLog(nullptr, " Max transfer command queues: %d", maxTransferQueues); + palLog(nullptr, " Supported Command Queues:"); if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_COMPUTE) { palLog(nullptr, " Compute"); @@ -438,12 +454,10 @@ bool customGraphicsBackendTest() // create a device with a custom adapter (D3D9) PalGPUDevice* device = nullptr; - PalGPUDeviceCreateInfo createInfo = {0}; - createInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; // only graphics - createInfo.features = PAL_GPU_FEATURE_SHADER_FLOAT64; - createInfo.features |= PAL_GPU_FEATURE_SWAPCHAIN; + PalGPUFeatures features = PAL_GPU_FEATURE_SHADER_FLOAT64; + features |= PAL_GPU_FEATURE_SWAPCHAIN; - result = palCreateGPUDevice(d3d9Adapter, &createInfo, &device); + result = palCreateGPUDevice(d3d9Adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); diff --git a/tests/gpu_device_test.c b/tests/gpu_device_test.c index 35f3d050..6a8357aa 100644 --- a/tests/gpu_device_test.c +++ b/tests/gpu_device_test.c @@ -90,23 +90,18 @@ bool gpuDeviceTest() // create a device with the vulkan adapter PalGPUDevice* device = nullptr; - PalGPUDeviceCreateInfo deviceCreateInfo = {0}; - - // almost supported on all platforms - if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { - deviceCreateInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; - } + PalGPUFeatures features = 0; // enable swapchain and maybe multi viewport if supported if (info.features & PAL_GPU_FEATURE_SWAPCHAIN) { - deviceCreateInfo.features = PAL_GPU_FEATURE_SWAPCHAIN; + features = PAL_GPU_FEATURE_SWAPCHAIN; } if (info.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { - deviceCreateInfo.features |= PAL_GPU_FEATURE_MULTI_VIEWPORT; + features |= PAL_GPU_FEATURE_MULTI_VIEWPORT; } - result = palCreateGPUDevice(vulkanAdapter, &deviceCreateInfo, &device); + result = palCreateGPUDevice(vulkanAdapter, features, &device); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index bcea1846..e60528f7 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -144,6 +144,13 @@ bool graphicsTest() palLog(nullptr, " Debug Layer: %s", boolToString); // command queue + Int32 maxComputeQueues = info.commandQueuesInfo.maxComputeQueues; + Int32 maxGraphicsQueues = info.commandQueuesInfo.maxGraphicsQueues; + Int32 maxTransferQueues = info.commandQueuesInfo.maxTransferQueues; + palLog(nullptr, " Max compute command queues: %d", maxComputeQueues); + palLog(nullptr, " Max graphics command queues: %d", maxGraphicsQueues); + palLog(nullptr, " Max transfer command queues: %d", maxTransferQueues); + palLog(nullptr, " Supported Command Queues:"); if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_COMPUTE) { palLog(nullptr, " Compute"); From ed527efa21a7b3bffc2d4b86490ad4596a6f56f5 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 28 Nov 2025 10:55:56 +0000 Subject: [PATCH 014/372] rename gpu api type enums --- include/pal/pal_graphics.h | 25 +++++++++---------- src/graphics/pal_graphics_linux.c | 8 ++---- tests/custom_graphics_backend_test.c | 37 ++++++++-------------------- tests/gpu_device_test.c | 2 +- tests/graphics_test.c | 29 ++++++---------------- 5 files changed, 33 insertions(+), 68 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index c3068be8..06490eb2 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -48,23 +48,23 @@ typedef enum { } PalGPUType; typedef enum { - PAL_GPU_API_VULKAN, - PAL_GPU_API_D3D12, - PAL_GPU_API_METAL, + PAL_GPU_API_TYPE_VULKAN, + PAL_GPU_API_TYPE_D3D12, + PAL_GPU_API_TYPE_METAL, // for custom backends - PAL_GPU_API_OPENGL, - PAL_GPU_API_GLES, - PAL_GPU_API_D3D11, - PAL_GPU_API_D3D9, - PAL_GPU_API_PPM, + PAL_GPU_API_TYPE_OPENGL, + PAL_GPU_API_TYPE_GLES, + PAL_GPU_API_TYPE_D3D11, + PAL_GPU_API_TYPE_D3D9, + PAL_GPU_API_TYPE_PPM, } PalGPUApiType; typedef enum { - PAL_GPU_COMMAND_QUEUE_GRAPHICS = PAL_BIT64(0), - PAL_GPU_COMMAND_QUEUE_COMPUTE = PAL_BIT64(1), - PAL_GPU_COMMAND_QUEUE_TRANSFER = PAL_BIT64(2) -} PalGPUCommandQueues; + PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS, + PAL_GPU_COMMAND_QUEUE_TYPE_COMPUTE, + PAL_GPU_COMMAND_QUEUE_TYPE_TRANSFER +} PalGPUCommandQueueType; typedef enum { PAL_GPU_SHADER_FORMAT_SPIRV = PAL_BIT(0), @@ -113,7 +113,6 @@ typedef struct { PalGPUApiType apiType; PalGPUShaderFormats shaderFormats; Uint64 totalMemory; // in bytes - PalGPUCommandQueues commandQueues; PalGPUFeatures features; PalGPUCommandQueuesInfo commandQueuesInfo; char versionString[PAL_GPU_VERSION_SIZE]; diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 2fe63f51..7358f9df 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -642,7 +642,7 @@ PalResult PAL_CALL vkGetAdapterInfo( } info->totalMemory = memory; - info->apiType = PAL_GPU_API_VULKAN; + info->apiType = PAL_GPU_API_TYPE_VULKAN; // get device type switch (props.deviceType) { @@ -701,21 +701,17 @@ PalResult PAL_CALL vkGetAdapterInfo( queueInfo->maxComputeQueues = 0; queueInfo->maxGraphicsQueues = 0; queueInfo->maxTransferQueues = 0; - info->commandQueues = 0; for (int i = 0; i < count; i++) { if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { - info->commandQueues |= PAL_GPU_COMMAND_QUEUE_COMPUTE; queueInfo->maxComputeQueues += queueProps->queueCount; } if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - info->commandQueues |= PAL_GPU_COMMAND_QUEUE_GRAPHICS; queueInfo->maxGraphicsQueues += queueProps->queueCount; } if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { - info->commandQueues |= PAL_GPU_COMMAND_QUEUE_TRANSFER; queueInfo->maxTransferQueues += queueProps->queueCount; } } @@ -945,7 +941,7 @@ PalResult PAL_CALL vkGetAdapterSubInfo( s_Vk.getPhysicalDeviceProperties(physicalDevice, &props); strcpy(info->name, props.deviceName); - info->apiType = PAL_GPU_API_VULKAN; + info->apiType = PAL_GPU_API_TYPE_VULKAN; // get device type switch (props.deviceType) { diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index 4e7c791a..18c6c3fd 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -30,7 +30,7 @@ static CustomGPUBackend s_CustomGPU; // if there is cleanup to do static void initCustomBackend() { CustomGPUAdapter* adapter = &s_CustomGPU.adapters[0]; - adapter->adapterInfo.apiType = PAL_GPU_API_D3D9; + adapter->adapterInfo.apiType = PAL_GPU_API_TYPE_D3D9; adapter->adapterInfo.debugLayerSupported = true; adapter->adapterInfo.type = PAL_GPU_TYPE_INTEGRATED; @@ -41,7 +41,6 @@ static void initCustomBackend() { strcpy(adapter->adapterInfo.versionString, "10_1"); strcpy(adapter->adapterInfo.name, "Intel Arc A580"); - adapter->adapterInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; adapter->adapterInfo.features = PAL_GPU_FEATURE_RAY_TRACING; adapter->adapterInfo.features |= PAL_GPU_FEATURE_SWAPCHAIN; adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_DXBC; @@ -52,7 +51,7 @@ static void initCustomBackend() { // second adapter adapter = &s_CustomGPU.adapters[1]; - adapter->adapterInfo.apiType = PAL_GPU_API_OPENGL; + adapter->adapterInfo.apiType = PAL_GPU_API_TYPE_OPENGL; adapter->adapterInfo.debugLayerSupported = true; adapter->adapterInfo.type = PAL_GPU_TYPE_DISCRETE; @@ -62,8 +61,6 @@ static void initCustomBackend() { strcpy(adapter->adapterInfo.versionString, "4.4"); strcpy(adapter->adapterInfo.name, "AMD Radeon RX 7700 XT"); - adapter->adapterInfo.commandQueues = PAL_GPU_COMMAND_QUEUE_GRAPHICS; - adapter->adapterInfo.commandQueues |= PAL_GPU_COMMAND_QUEUE_COMPUTE; adapter->adapterInfo.features = PAL_GPU_FEATURE_RAY_TRACING; adapter->adapterInfo.features |= PAL_GPU_FEATURE_MESH_SHADER; adapter->adapterInfo.features |= PAL_GPU_FEATURE_SWAPCHAIN; @@ -106,7 +103,6 @@ static PalResult PAL_CALL customGetGPUAdapterInfo( info->totalMemory = gpuInfo->totalMemory; info->type = gpuInfo->type; info->features = gpuInfo->features; - info->commandQueues = gpuInfo->commandQueues; info->shaderFormats = gpuInfo->shaderFormats; info->commandQueuesInfo = gpuInfo->commandQueuesInfo; @@ -285,43 +281,43 @@ bool customGraphicsBackendTest() const char* apiTypeString; switch (info.apiType) { - case PAL_GPU_API_D3D12: { + case PAL_GPU_API_TYPE_D3D12: { apiTypeString = "D3D12"; break; } - case PAL_GPU_API_VULKAN: { + case PAL_GPU_API_TYPE_VULKAN: { apiTypeString = "Vulkan"; break; } - case PAL_GPU_API_METAL: { + case PAL_GPU_API_TYPE_METAL: { apiTypeString = "Metal"; break; } - case PAL_GPU_API_OPENGL: { + case PAL_GPU_API_TYPE_OPENGL: { apiTypeString = "OpenGL"; break; } - case PAL_GPU_API_GLES: { + case PAL_GPU_API_TYPE_GLES: { apiTypeString = "GLes"; break; } - case PAL_GPU_API_D3D11: { + case PAL_GPU_API_TYPE_D3D11: { apiTypeString = "D3D11"; break; } - case PAL_GPU_API_D3D9: { + case PAL_GPU_API_TYPE_D3D9: { apiTypeString = "D3D9"; d3d9Adapter = adapter; break; } - case PAL_GPU_API_PPM: { + case PAL_GPU_API_TYPE_PPM: { apiTypeString = "PPM"; break; } @@ -345,19 +341,6 @@ bool customGraphicsBackendTest() palLog(nullptr, " Max graphics command queues: %d", maxGraphicsQueues); palLog(nullptr, " Max transfer command queues: %d", maxTransferQueues); - palLog(nullptr, " Supported Command Queues:"); - if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_COMPUTE) { - palLog(nullptr, " Compute"); - } - - if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { - palLog(nullptr, " Graphics"); - } - - if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_TRANSFER) { - palLog(nullptr, " Transfer"); - } - // features palLog(nullptr, " Supported Features:"); if (info.features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { diff --git a/tests/gpu_device_test.c b/tests/gpu_device_test.c index 6a8357aa..183b832c 100644 --- a/tests/gpu_device_test.c +++ b/tests/gpu_device_test.c @@ -64,7 +64,7 @@ bool gpuDeviceTest() } // check if its Vulkan - if (subInfo.apiType == PAL_GPU_API_VULKAN) { + if (subInfo.apiType == PAL_GPU_API_TYPE_VULKAN) { vulkanAdapter = adapter; break; } diff --git a/tests/graphics_test.c b/tests/graphics_test.c index e60528f7..5f64b4f3 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -92,42 +92,42 @@ bool graphicsTest() const char* apiTypeString; switch (info.apiType) { - case PAL_GPU_API_D3D12: { + case PAL_GPU_API_TYPE_D3D12: { apiTypeString = "D3D12"; break; } - case PAL_GPU_API_VULKAN: { + case PAL_GPU_API_TYPE_VULKAN: { apiTypeString = "Vulkan"; break; } - case PAL_GPU_API_METAL: { + case PAL_GPU_API_TYPE_METAL: { apiTypeString = "Metal"; break; } - case PAL_GPU_API_OPENGL: { + case PAL_GPU_API_TYPE_OPENGL: { apiTypeString = "OpenGL"; break; } - case PAL_GPU_API_GLES: { + case PAL_GPU_API_TYPE_GLES: { apiTypeString = "GLes"; break; } - case PAL_GPU_API_D3D11: { + case PAL_GPU_API_TYPE_D3D11: { apiTypeString = "D3D11"; break; } - case PAL_GPU_API_D3D9: { + case PAL_GPU_API_TYPE_D3D9: { apiTypeString = "D3D9"; break; } - case PAL_GPU_API_PPM: { + case PAL_GPU_API_TYPE_PPM: { apiTypeString = "PPM"; break; } @@ -150,19 +150,6 @@ bool graphicsTest() palLog(nullptr, " Max compute command queues: %d", maxComputeQueues); palLog(nullptr, " Max graphics command queues: %d", maxGraphicsQueues); palLog(nullptr, " Max transfer command queues: %d", maxTransferQueues); - - palLog(nullptr, " Supported Command Queues:"); - if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_COMPUTE) { - palLog(nullptr, " Compute"); - } - - if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_GRAPHICS) { - palLog(nullptr, " Graphics"); - } - - if (info.commandQueues & PAL_GPU_COMMAND_QUEUE_TRANSFER) { - palLog(nullptr, " Transfer"); - } // features palLog(nullptr, " Supported Features:"); From a70206f37bddb4423467cabd0c9da835ee8b0e29 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 28 Nov 2025 13:03:40 +0000 Subject: [PATCH 015/372] add command queues vulkan --- include/pal/pal_core.h | 2 + include/pal/pal_graphics.h | 20 ++- src/graphics/pal_graphics_linux.c | 218 ++++++++++++++++++++++++--- src/pal_core.c | 6 + tests/custom_graphics_backend_test.c | 8 +- tests/gpu_device_test.c | 24 +++ tests/graphics_test.c | 4 +- 7 files changed, 252 insertions(+), 30 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index d12c01b1..8800f627 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -252,6 +252,8 @@ typedef enum { PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED, PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED, PAL_RESULT_INVALID_GRAPHICS_DRIVER, + PAL_RESULT_INVALID_GPU_DEVICE, + PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 06490eb2..bcbf7946 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -38,6 +38,7 @@ freely, subject to the following restrictions: typedef struct PalGPUAdapter PalGPUAdapter; typedef struct PalGPUDevice PalGPUDevice; +typedef struct PalGPUCommandQueue PalGPUCommandQueue; typedef enum { PAL_GPU_TYPE_UNKNOWN, @@ -63,7 +64,7 @@ typedef enum { typedef enum { PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS, PAL_GPU_COMMAND_QUEUE_TYPE_COMPUTE, - PAL_GPU_COMMAND_QUEUE_TYPE_TRANSFER + PAL_GPU_COMMAND_QUEUE_TYPE_COPY } PalGPUCommandQueueType; typedef enum { @@ -104,7 +105,7 @@ typedef struct { typedef struct { Uint32 maxComputeQueues; Uint32 maxGraphicsQueues; - Uint32 maxTransferQueues; + Uint32 maxCopyQueues; } PalGPUCommandQueuesInfo; typedef struct { @@ -138,6 +139,14 @@ typedef struct { PalGPUDevice** outDevice); void PAL_CALL (*destroyGPUDevice)(PalGPUDevice* device); + + PalResult PAL_CALL (*createGPUCommandQueue)( + PalGPUDevice* device, + PalGPUCommandQueueType type, + PalGPUCommandQueue** outQueue); + + void PAL_CALL (*destroyGPUCommandQueue)(PalGPUCommandQueue* queue); + } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics( @@ -167,6 +176,13 @@ PAL_API PalResult PAL_CALL palCreateGPUDevice( PAL_API void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device); +PAL_API PalResult PAL_CALL palCreateGPUCommandQueue( + PalGPUDevice* device, + PalGPUCommandQueueType type, + PalGPUCommandQueue** outQueue); + +PAL_API void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 7358f9df..5c420780 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -39,11 +39,13 @@ freely, subject to the following restrictions: // Typedefs, enums and structs // ================================================== +// TODO: make all these dynamic #define MAX_BACKENDS 16 // should be fine for now #define MAX_ADAPTERS 32 // should be enough #define MAX_DEVICE 16 // should be enough #define MAX_QUEUE_FAMILIES 8 #define MAX_PHYSICAL_QUEUES 16 +#define MAX_COMMAND_QUEUES 32 #if PAL_HAS_VULKAN // VKAPI_PTR expands to nothing on linux @@ -155,9 +157,15 @@ typedef struct { typedef struct { VkQueue handle; - VkQueueFlags usage; + VkQueueFlags usages; + VkQueueFlags usedUsages; } PhysicalQueue; +typedef struct { + VkQueueFlags usage; + PhysicalQueue* phyQueue; +} VkCommandQueue; + typedef struct { Int32 queueCount; VkDevice handle; @@ -177,9 +185,16 @@ typedef struct { typedef struct { bool used; PalGPUDevice* device; - AdapterData* adapterData; + const PalGPUBackend* backend; } DeviceData; +typedef struct { + bool used; + PalGPUDevice* device; + PalGPUCommandQueue* queue; + const PalGPUBackend* backend; +} CommandQueueData; + typedef struct { const PalGPUBackend* base; Uint16 startIndex; @@ -193,6 +208,7 @@ typedef struct { const PalAllocator* allocator; AdapterData adapterData[MAX_ADAPTERS]; DeviceData deviceData[MAX_DEVICE]; + CommandQueueData commandQueueData[MAX_COMMAND_QUEUES]; AttachBackend backends[MAX_BACKENDS]; } GraphicsLinux; @@ -210,6 +226,7 @@ static AdapterData* getFreeAdapterData() return &s_Graphics.adapterData[i]; } } + return nullptr; } static AdapterData* findAdapterData(PalGPUAdapter* adapter) @@ -231,6 +248,7 @@ static DeviceData* getFreeDeviceData() return &s_Graphics.deviceData[i]; } } + return nullptr; } static DeviceData* findDeviceData(PalGPUDevice* device) @@ -244,6 +262,28 @@ static DeviceData* findDeviceData(PalGPUDevice* device) return nullptr; } +static CommandQueueData* getFreeCommandQueueData() +{ + for (int i = 0; i < MAX_COMMAND_QUEUES; ++i) { + if (!s_Graphics.commandQueueData[i].used) { + s_Graphics.commandQueueData[i].used = true; + return &s_Graphics.commandQueueData[i]; + } + } + return nullptr; +} + +static CommandQueueData* findCommandQueueData(PalGPUCommandQueue* queue) +{ + for (int i = 0; i < MAX_COMMAND_QUEUES; ++i) { + if (s_Graphics.commandQueueData[i].used && + s_Graphics.commandQueueData[i].queue == queue) { + return &s_Graphics.commandQueueData[i]; + } + } + return nullptr; +} + #if PAL_HAS_VULKAN static PalResult vkResultToPal(VkResult result) @@ -282,7 +322,7 @@ static PalResult vkResultToPal(VkResult result) return PAL_RESULT_PLATFORM_FAILURE; } -void* vkAlloc( +static void* vkAlloc( void* pUserData, size_t size, size_t alignment, @@ -291,14 +331,14 @@ void* vkAlloc( return palAllocate(s_Graphics.allocator, size, alignment); } -void vkFree( +static void vkFree( void* pUserData, void* ptr) { palFree(s_Graphics.allocator, ptr); } -void* vkRealloc( +static void* vkRealloc( void* pUserData, void* pOriginal, size_t size, @@ -323,7 +363,7 @@ void* vkRealloc( return nullptr; } -PalResult vkInitGraphics(bool enableDebugLayer) +static PalResult vkInitGraphics(bool enableDebugLayer) { // load vulkan s_Vk.handle = dlopen("libvulkan.so", RTLD_LAZY); @@ -573,7 +613,7 @@ PalResult vkInitGraphics(bool enableDebugLayer) return PAL_RESULT_SUCCESS; } -void vkShutdownGraphics() +static void vkShutdownGraphics() { if (s_Vk.instance) { s_Vk.destroyInstance(s_Vk.instance, &s_Vk.allocator); @@ -582,7 +622,7 @@ void vkShutdownGraphics() } } -PalResult vkEnumerateAdapters( +static PalResult vkEnumerateAdapters( Int32* count, PalGPUAdapter** outAdapters) { @@ -619,7 +659,7 @@ PalResult vkEnumerateAdapters( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL vkGetAdapterInfo( +static PalResult PAL_CALL vkGetAdapterInfo( PalGPUAdapter* adapter, PalGPUAdapterInfo* info) { @@ -700,7 +740,7 @@ PalResult PAL_CALL vkGetAdapterInfo( PalGPUCommandQueuesInfo* queueInfo = &info->commandQueuesInfo; queueInfo->maxComputeQueues = 0; queueInfo->maxGraphicsQueues = 0; - queueInfo->maxTransferQueues = 0; + queueInfo->maxCopyQueues = 0; for (int i = 0; i < count; i++) { if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { @@ -712,7 +752,7 @@ PalResult PAL_CALL vkGetAdapterInfo( } if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { - queueInfo->maxTransferQueues += queueProps->queueCount; + queueInfo->maxCopyQueues += queueProps->queueCount; } } @@ -932,7 +972,7 @@ PalResult PAL_CALL vkGetAdapterInfo( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL vkGetAdapterSubInfo( +static PalResult PAL_CALL vkGetAdapterSubInfo( PalGPUAdapter* adapter, PalGPUAdapterSubInfo* info) { @@ -983,7 +1023,7 @@ PalResult PAL_CALL vkGetAdapterSubInfo( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL vkCreateGPUDevice( +static PalResult PAL_CALL vkCreateGPUDevice( PalGPUAdapter* adapter, PalGPUFeatures features, PalGPUDevice** outDevice) @@ -1221,7 +1261,8 @@ PalResult PAL_CALL vkCreateGPUDevice( for (int j = 0; j < data->count; j++) { PhysicalQueue* queue = &gpuDevice->queues[gpuDevice->queueCount++]; s_Vk.getDeviceQueue(device, data->index, 0, &queue->handle); - queue->usage = data->flags; + queue->usages = data->flags; + queue->usedUsages = 0; } } @@ -1229,19 +1270,96 @@ PalResult PAL_CALL vkCreateGPUDevice( return PAL_RESULT_SUCCESS; } -void PAL_CALL vkDestroyGPUDevice(PalGPUDevice* device) +static void PAL_CALL vkDestroyGPUDevice(PalGPUDevice* device) { VkGPUDevice* gpuDevice = (VkGPUDevice*)device; s_Vk.destroyDevice(gpuDevice->handle, &s_Vk.allocator); palFree(s_Graphics.allocator, gpuDevice); } +static PalResult PAL_CALL vkCreateGPUCommandQueue( + PalGPUDevice* device, + PalGPUCommandQueueType type, + PalGPUCommandQueue** outQueue) +{ + VkCommandQueue* commandQueue = nullptr; + VkQueueFlags queueFlag = 0; + + VkGPUDevice* gpuDevice = (VkGPUDevice*)device; + if (!gpuDevice->handle) { + return PAL_RESULT_INVALID_GPU_DEVICE; + } + + if (gpuDevice->queueCount == 0) { + return PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE; + } + + switch (type) { + case PAL_GPU_COMMAND_QUEUE_TYPE_COMPUTE: { + queueFlag = VK_QUEUE_COMPUTE_BIT; + break; + } + + case PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS: { + queueFlag = VK_QUEUE_GRAPHICS_BIT; + break; + } + + case PAL_GPU_COMMAND_QUEUE_TYPE_COPY: { + queueFlag = VK_QUEUE_TRANSFER_BIT; + break; + } + } + + PhysicalQueue* physicalQueue = nullptr; + for (int i = 0; i < gpuDevice->queueCount; i++) { + PhysicalQueue* phyQueue = &gpuDevice->queues[i]; + // check if the physical queue supports the requested operation + // and if its not already used + if (phyQueue->usages & queueFlag && + phyQueue->usedUsages != queueFlag) { + phyQueue->usedUsages |= queueFlag; + physicalQueue = phyQueue; + break; + } + } + + if (physicalQueue) { + commandQueue = palAllocate( + s_Graphics.allocator, + sizeof(VkCommandQueue), + 0); + + if (!commandQueue) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + commandQueue->phyQueue = physicalQueue; + commandQueue->usage = queueFlag; + + *outQueue = (PalGPUCommandQueue*)commandQueue; + return PAL_RESULT_SUCCESS; + } + + return PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE; +} + +static void PAL_CALL vkDestroyGPUCommandQueue(PalGPUCommandQueue* queue) +{ + VkCommandQueue* commandQueue = (VkCommandQueue*)queue; + PhysicalQueue* phyQueue = commandQueue->phyQueue; + phyQueue->usedUsages &= ~commandQueue->usage; + palFree(s_Graphics.allocator, commandQueue); +} + static PalGPUBackend s_VkBackend = { .enumerateGPUAdapters = vkEnumerateAdapters, .getGPUAdapterInfo = vkGetAdapterInfo, .getGPUAdapterSubInfo = vkGetAdapterSubInfo, .createGPUDevice = vkCreateGPUDevice, - .destroyGPUDevice = vkDestroyGPUDevice + .destroyGPUDevice = vkDestroyGPUDevice, + .createGPUCommandQueue = vkCreateGPUCommandQueue, + .destroyGPUCommandQueue = vkDestroyGPUCommandQueue }; #endif // PAL_HAS_VULKAN @@ -1401,10 +1519,12 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) // check if all the function pointers are set // clang-format off - if (!backend->enumerateGPUAdapters || - !backend->getGPUAdapterInfo || - !backend->createGPUDevice || - !backend->destroyGPUDevice) { + if (!backend->enumerateGPUAdapters || + !backend->getGPUAdapterInfo || + !backend->createGPUDevice || + !backend->destroyGPUDevice || + !backend->createGPUCommandQueue || + !backend->destroyGPUCommandQueue) { return PAL_RESULT_INVALID_GPU_BACKEND; } // clang-format on @@ -1453,7 +1573,7 @@ PalResult PAL_CALL palCreateGPUDevice( return PAL_RESULT_OUT_OF_MEMORY; } - deviceData->adapterData = adapterData; + deviceData->backend = adapterData->backend; deviceData->device = device; *outDevice = device; @@ -1465,7 +1585,61 @@ void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device) if (s_Graphics.initialized && device) { DeviceData* data = findDeviceData(device); if (data) { - data->adapterData->backend->destroyGPUDevice(device); + data->backend->destroyGPUDevice(device); + data->used = false; + } + } +} + +PalResult PAL_CALL palCreateGPUCommandQueue( + PalGPUDevice* device, + PalGPUCommandQueueType type, + PalGPUCommandQueue** outQueue) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !outQueue) { + return PAL_RESULT_NULL_POINTER; + } + + DeviceData* data = findDeviceData(device); + if (!data) { + return PAL_RESULT_INVALID_GPU_DEVICE; + } + + PalGPUCommandQueue* queue = nullptr; + PalResult ret; + ret = data->backend->createGPUCommandQueue( + device, + type, + &queue); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + // create a slot for the created device + CommandQueueData* queueData = getFreeCommandQueueData(); + if (!queueData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + queueData->backend = data->backend; + queueData->queue = queue; + queueData->device = device; + + *outQueue = queue; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue) +{ + if (s_Graphics.initialized && queue) { + CommandQueueData* data = findCommandQueueData(queue); + if (data) { + data->backend->destroyGPUCommandQueue(queue); data->used = false; } } diff --git a/src/pal_core.c b/src/pal_core.c index 075ea1df..95f91af9 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -398,6 +398,12 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_GRAPHICS_DRIVER: return "Incompatible graphics driver"; + + case PAL_RESULT_INVALID_GPU_DEVICE: + return "Invalid GPU device"; + + case PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE: + return "Out of GPU command queues"; } return "Unknown"; } diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index 18c6c3fd..77d88095 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -47,7 +47,7 @@ static void initCustomBackend() { adapter->adapterInfo.commandQueuesInfo.maxComputeQueues = 1; adapter->adapterInfo.commandQueuesInfo.maxGraphicsQueues = 1; - adapter->adapterInfo.commandQueuesInfo.maxTransferQueues = 2; + adapter->adapterInfo.commandQueuesInfo.maxCopyQueues = 2; // second adapter adapter = &s_CustomGPU.adapters[1]; @@ -69,7 +69,7 @@ static void initCustomBackend() { adapter->adapterInfo.commandQueuesInfo.maxComputeQueues = 1; adapter->adapterInfo.commandQueuesInfo.maxGraphicsQueues = 4; - adapter->adapterInfo.commandQueuesInfo.maxTransferQueues = 4; + adapter->adapterInfo.commandQueuesInfo.maxCopyQueues = 4; } static PalResult PAL_CALL customEnumerateGPUAdapters( @@ -336,10 +336,10 @@ bool customGraphicsBackendTest() // command queues Int32 maxComputeQueues = info.commandQueuesInfo.maxComputeQueues; Int32 maxGraphicsQueues = info.commandQueuesInfo.maxGraphicsQueues; - Int32 maxTransferQueues = info.commandQueuesInfo.maxTransferQueues; + Int32 maxCopyQueues = info.commandQueuesInfo.maxCopyQueues; palLog(nullptr, " Max compute command queues: %d", maxComputeQueues); palLog(nullptr, " Max graphics command queues: %d", maxGraphicsQueues); - palLog(nullptr, " Max transfer command queues: %d", maxTransferQueues); + palLog(nullptr, " Max transfer command queues: %d", maxCopyQueues); // features palLog(nullptr, " Supported Features:"); diff --git a/tests/gpu_device_test.c b/tests/gpu_device_test.c index 183b832c..336eaedb 100644 --- a/tests/gpu_device_test.c +++ b/tests/gpu_device_test.c @@ -108,6 +108,30 @@ bool gpuDeviceTest() return false; } + // check if we support a graphics command queue + if (!info.commandQueuesInfo.maxGraphicsQueues) { + palLog( + nullptr, + "This Adapter (GPU) does not have any grapics command queues"); + return false; + } + + // create a graphics command queue + PalGPUCommandQueue* graphicsQueue = nullptr; + result = palCreateGPUCommandQueue( + device, + PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS, + &graphicsQueue); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create grapics command queue: %s", error); + return false; + } + + // destroy the command queue + palDestroyGPUCommandQueue(graphicsQueue); + // destroy the device palDestroyGPUDevice(device); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 5f64b4f3..ec553394 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -146,10 +146,10 @@ bool graphicsTest() // command queue Int32 maxComputeQueues = info.commandQueuesInfo.maxComputeQueues; Int32 maxGraphicsQueues = info.commandQueuesInfo.maxGraphicsQueues; - Int32 maxTransferQueues = info.commandQueuesInfo.maxTransferQueues; + Int32 maxCopyQueues = info.commandQueuesInfo.maxCopyQueues; palLog(nullptr, " Max compute command queues: %d", maxComputeQueues); palLog(nullptr, " Max graphics command queues: %d", maxGraphicsQueues); - palLog(nullptr, " Max transfer command queues: %d", maxTransferQueues); + palLog(nullptr, " Max copy command queues: %d", maxCopyQueues); // features palLog(nullptr, " Supported Features:"); From 6fa40e9c98787980e6fcc13e5a811077d09d41e3 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 28 Nov 2025 18:40:41 +0000 Subject: [PATCH 016/372] remove and trim API --- include/pal/pal_graphics.h | 32 ++--- src/graphics/pal_graphics_linux.c | 142 +++++++------------- tests/custom_graphics_backend_test.c | 187 +++++++-------------------- tests/gpu_device_test.c | 26 ++-- tests/graphics_test.c | 51 +++++--- tests/tests_main.c | 4 +- 6 files changed, 154 insertions(+), 288 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index bcbf7946..d95dc79b 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -39,6 +39,7 @@ freely, subject to the following restrictions: typedef struct PalGPUAdapter PalGPUAdapter; typedef struct PalGPUDevice PalGPUDevice; typedef struct PalGPUCommandQueue PalGPUCommandQueue; +typedef struct PalSwapchain PalSwapchain; typedef enum { PAL_GPU_TYPE_UNKNOWN, @@ -98,41 +99,33 @@ typedef enum { typedef struct { PalGPUType type; PalGPUApiType apiType; + PalGPUShaderFormats shaderFormats; + Uint64 totalMemory; // in bytes char versionString[PAL_GPU_VERSION_SIZE]; char name[PAL_GPU_NAME_SIZE]; -} PalGPUAdapterSubInfo; +} PalGPUAdapterInfo; typedef struct { + bool debugLayerSupported; Uint32 maxComputeQueues; Uint32 maxGraphicsQueues; Uint32 maxCopyQueues; -} PalGPUCommandQueuesInfo; - -typedef struct { - bool debugLayerSupported; - PalGPUType type; - PalGPUApiType apiType; - PalGPUShaderFormats shaderFormats; - Uint64 totalMemory; // in bytes PalGPUFeatures features; - PalGPUCommandQueuesInfo commandQueuesInfo; - char versionString[PAL_GPU_VERSION_SIZE]; - char name[PAL_GPU_NAME_SIZE]; -} PalGPUAdapterInfo; +} PalGPUAdapterCapabilities; typedef struct { PalResult PAL_CALL (*enumerateGPUAdapters)( Int32* count, PalGPUAdapter** outAdapters); - PalResult PAL_CALL (*getGPUAdapterSubInfo)( - PalGPUAdapter* adapter, - PalGPUAdapterSubInfo* info); - PalResult PAL_CALL (*getGPUAdapterInfo)( PalGPUAdapter* adapter, PalGPUAdapterInfo* info); + PalResult PAL_CALL (*getGPUAdapterCapabilities)( + PalGPUAdapter* adapter, + PalGPUAdapterCapabilities* caps); + PalResult PAL_CALL (*createGPUDevice)( PalGPUAdapter* adapter, PalGPUFeatures features, @@ -146,7 +139,6 @@ typedef struct { PalGPUCommandQueue** outQueue); void PAL_CALL (*destroyGPUCommandQueue)(PalGPUCommandQueue* queue); - } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics( @@ -163,9 +155,9 @@ PAL_API PalResult PAL_CALL palGetGPUAdapterInfo( PalGPUAdapter* adapter, PalGPUAdapterInfo* info); -PAL_API PalResult PAL_CALL palGetGPUAdapterSubInfo( +PAL_API PalResult PAL_CALL palGetGPUAdapterCapabilities( PalGPUAdapter* adapter, - PalGPUAdapterSubInfo* info); + PalGPUAdapterCapabilities* caps); PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 5c420780..f35a7931 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -663,27 +663,24 @@ static PalResult PAL_CALL vkGetAdapterInfo( PalGPUAdapter* adapter, PalGPUAdapterInfo* info) { - VkResult ret; VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; - VkPhysicalDeviceProperties props; - VkPhysicalDeviceMemoryProperties memProps; + VkPhysicalDeviceProperties props = {0}; + VkPhysicalDeviceMemoryProperties memProps = {0}; - s_Vk.getPhysicalDeviceProperties(physicalDevice, &props); s_Vk.getPhysicalDeviceMemoryProperties(physicalDevice, &memProps); + s_Vk.getPhysicalDeviceProperties(physicalDevice, &props); + + info->apiType = PAL_GPU_API_TYPE_VULKAN; + info->shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; strcpy(info->name, props.deviceName); - info->debugLayerSupported = s_Vk.hasDebug; - // get total memory - Uint64 memory = 0; + info->totalMemory = 0; for (int i = 0; i < memProps.memoryHeapCount; i++) { if (memProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { - memory += memProps.memoryHeaps[i].size; + info->totalMemory = memProps.memoryHeaps[i].size; } } - info->totalMemory = memory; - info->apiType = PAL_GPU_API_TYPE_VULKAN; - // get device type switch (props.deviceType) { case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { @@ -712,9 +709,6 @@ static PalResult PAL_CALL vkGetAdapterInfo( } } - // shader format - info->shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; - // version string snprintf( info->versionString, @@ -724,6 +718,17 @@ static PalResult PAL_CALL vkGetAdapterInfo( VK_VERSION_MINOR(props.apiVersion), VK_VERSION_PATCH(props.apiVersion)); + return PAL_RESULT_SUCCESS; +} + +static PalResult PAL_CALL vkGetAdapterCapabilities( + PalGPUAdapter* adapter, + PalGPUAdapterCapabilities* caps) +{ + VkResult ret = VK_SUCCESS; + VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; + caps->debugLayerSupported = s_Vk.hasDebug; + // get supported queue commands Uint32 count; s_Vk.getPhysicalDeviceQueueFamilyProperties( @@ -737,22 +742,21 @@ static PalResult PAL_CALL vkGetAdapterInfo( &count, queueProps); - PalGPUCommandQueuesInfo* queueInfo = &info->commandQueuesInfo; - queueInfo->maxComputeQueues = 0; - queueInfo->maxGraphicsQueues = 0; - queueInfo->maxCopyQueues = 0; + caps->maxComputeQueues = 0; + caps->maxGraphicsQueues = 0; + caps->maxCopyQueues = 0; for (int i = 0; i < count; i++) { if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { - queueInfo->maxComputeQueues += queueProps->queueCount; + caps->maxComputeQueues += queueProps->queueCount; } if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - queueInfo->maxGraphicsQueues += queueProps->queueCount; + caps->maxGraphicsQueues += queueProps->queueCount; } if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { - queueInfo->maxCopyQueues += queueProps->queueCount; + caps->maxCopyQueues += queueProps->queueCount; } } @@ -787,7 +791,7 @@ static PalResult PAL_CALL vkGetAdapterInfo( bool rayTracingFound = false; bool accelerateFound = false; - info->features = 0; + caps->features = 0; // clang-format off for (int i = 0; i < extensionCount; i++) { @@ -815,7 +819,7 @@ static PalResult PAL_CALL vkGetAdapterInfo( } if (mesh.meshShader && mesh.taskShader) { - info->features |= PAL_GPU_FEATURE_MESH_SHADER; + caps->features |= PAL_GPU_FEATURE_MESH_SHADER; } } else if (strcmp(props->extensionName, "VK_KHR_fragment_shading_rate") == 0) { @@ -835,7 +839,7 @@ static PalResult PAL_CALL vkGetAdapterInfo( } if (frag.pipelineFragmentShadingRate) { - info->features |= PAL_GPU_FEATURE_VARIABLE_RATE_SHADING; + caps->features |= PAL_GPU_FEATURE_VARIABLE_RATE_SHADING; } } else if (strcmp(props->extensionName, "VK_EXT_descriptor_indexing") == 0) { @@ -855,16 +859,16 @@ static PalResult PAL_CALL vkGetAdapterInfo( } if (desc.shaderSampledImageArrayNonUniformIndexing) { - info->features |= PAL_GPU_FEATURE_DESCRIPTOR_INDEXING; + caps->features |= PAL_GPU_FEATURE_DESCRIPTOR_INDEXING; } } else if (strcmp(props->extensionName, "VK_KHR_swapchain") == 0) { // swapchain - info->features |= PAL_GPU_FEATURE_SWAPCHAIN; + caps->features |= PAL_GPU_FEATURE_SWAPCHAIN; } else if (strcmp(props->extensionName, "VK_KHR_dynamic_rendering") == 0) { // dynamic rendering - info->features |= PAL_GPU_FEATURE_DYNAMIC_RENDERING; + caps->features |= PAL_GPU_FEATURE_DYNAMIC_RENDERING; } else if (strcmp(props->extensionName, "VK_KHR_shader_float16_int8") == 0) { // shader float16 @@ -883,7 +887,7 @@ static PalResult PAL_CALL vkGetAdapterInfo( } if (shader16.shaderFloat16) { - info->features |= PAL_GPU_FEATURE_SHADER_FLOAT16; + caps->features |= PAL_GPU_FEATURE_SHADER_FLOAT16; } } else if (strcmp(props->extensionName, "VK_KHR_timeline_semaphore") == 0) { @@ -903,7 +907,7 @@ static PalResult PAL_CALL vkGetAdapterInfo( } if (timeline.timelineSemaphore) { - info->features |= PAL_GPU_FEATURE_TIMELINE_SEMAPHORE; + caps->features |= PAL_GPU_FEATURE_TIMELINE_SEMAPHORE; } } } @@ -928,7 +932,7 @@ static PalResult PAL_CALL vkGetAdapterInfo( } if (ray.rayTracingPipeline && acc.accelerationStructure) { - info->features |= PAL_GPU_FEATURE_RAY_TRACING; + caps->features |= PAL_GPU_FEATURE_RAY_TRACING; } } // clang-format on @@ -937,92 +941,41 @@ static PalResult PAL_CALL vkGetAdapterInfo( // check for additional features if (features.geometryShader) { - info->features |= PAL_GPU_FEATURE_GEOMETRY_SHADER; + caps->features |= PAL_GPU_FEATURE_GEOMETRY_SHADER; } if (features.multiViewport) { - info->features |= PAL_GPU_FEATURE_MULTI_VIEWPORT; + caps->features |= PAL_GPU_FEATURE_MULTI_VIEWPORT; } if (features.samplerAnisotropy) { - info->features |= PAL_GPU_FEATURE_SAMPLER_ANISOTROPY; + caps->features |= PAL_GPU_FEATURE_SAMPLER_ANISOTROPY; } if (features.sampleRateShading) { - info->features |= PAL_GPU_FEATURE_SAMPLE_RATE_SHADING; + caps->features |= PAL_GPU_FEATURE_SAMPLE_RATE_SHADING; } if (features.shaderFloat64) { - info->features |= PAL_GPU_FEATURE_SHADER_FLOAT64; + caps->features |= PAL_GPU_FEATURE_SHADER_FLOAT64; } if (features.shaderInt64) { - info->features |= PAL_GPU_FEATURE_SHADER_INT64; + caps->features |= PAL_GPU_FEATURE_SHADER_INT64; } if (features.shaderInt16) { - info->features |= PAL_GPU_FEATURE_SHADER_INT16; + caps->features |= PAL_GPU_FEATURE_SHADER_INT16; } if (features.tessellationShader) { - info->features |= PAL_GPU_FEATURE_TESSELLATION_SHADER; + caps->features |= PAL_GPU_FEATURE_TESSELLATION_SHADER; } palFree(s_Graphics.allocator, extensionProps); return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL vkGetAdapterSubInfo( - PalGPUAdapter* adapter, - PalGPUAdapterSubInfo* info) -{ - VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; - VkPhysicalDeviceProperties props; - - s_Vk.getPhysicalDeviceProperties(physicalDevice, &props); - strcpy(info->name, props.deviceName); - info->apiType = PAL_GPU_API_TYPE_VULKAN; - - // get device type - switch (props.deviceType) { - case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { - info->type = PAL_GPU_TYPE_INTEGRATED; - break; - } - - case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { - info->type = PAL_GPU_TYPE_DISCRETE; - break; - } - - case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { - info->type = PAL_GPU_TYPE_VIRTUAL; - break; - } - - case VK_PHYSICAL_DEVICE_TYPE_CPU: { - info->type = PAL_GPU_TYPE_CPU; - break; - } - - default: { - info->type = PAL_GPU_TYPE_UNKNOWN; - break; - } - } - - // version string - snprintf( - info->versionString, - PAL_GPU_VERSION_SIZE, - "%d.%d.%d", - VK_VERSION_MAJOR(props.apiVersion), - VK_VERSION_MINOR(props.apiVersion), - VK_VERSION_PATCH(props.apiVersion)); - - return PAL_RESULT_SUCCESS; -} - static PalResult PAL_CALL vkCreateGPUDevice( PalGPUAdapter* adapter, PalGPUFeatures features, @@ -1355,7 +1308,7 @@ static void PAL_CALL vkDestroyGPUCommandQueue(PalGPUCommandQueue* queue) static PalGPUBackend s_VkBackend = { .enumerateGPUAdapters = vkEnumerateAdapters, .getGPUAdapterInfo = vkGetAdapterInfo, - .getGPUAdapterSubInfo = vkGetAdapterSubInfo, + .getGPUAdapterCapabilities = vkGetAdapterCapabilities, .createGPUDevice = vkCreateGPUDevice, .destroyGPUDevice = vkDestroyGPUDevice, .createGPUCommandQueue = vkCreateGPUCommandQueue, @@ -1491,21 +1444,21 @@ PalResult PAL_CALL palGetGPUAdapterInfo( return PAL_RESULT_INVALID_GPU_ADAPTER; } -PalResult PAL_CALL palGetGPUAdapterSubInfo( +PalResult PAL_CALL palGetGPUAdapterCapabilities( PalGPUAdapter* adapter, - PalGPUAdapterSubInfo* info) + PalGPUAdapterCapabilities* caps) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!adapter || !info) { + if (!adapter || !caps) { return PAL_RESULT_NULL_POINTER; } AdapterData* data = findAdapterData(adapter); if (data) { - return data->backend->getGPUAdapterSubInfo(adapter, info); + return data->backend->getGPUAdapterCapabilities(adapter, caps); } return PAL_RESULT_INVALID_GPU_ADAPTER; @@ -1521,6 +1474,7 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) // clang-format off if (!backend->enumerateGPUAdapters || !backend->getGPUAdapterInfo || + !backend->getGPUAdapterCapabilities || !backend->createGPUDevice || !backend->destroyGPUDevice || !backend->createGPUCommandQueue || diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c index 77d88095..5898faf8 100644 --- a/tests/custom_graphics_backend_test.c +++ b/tests/custom_graphics_backend_test.c @@ -5,9 +5,9 @@ // a simple custom backend // for simplicity we are not going to add that much functionality // to it - typedef struct { PalGPUAdapterInfo adapterInfo; + PalGPUAdapterCapabilities caps; // add more fields if needed } CustomGPUAdapter; @@ -16,6 +16,12 @@ typedef struct { // add more fields if needed } CustomGPUDevice; +typedef struct { + CustomGPUDevice* device; + PalGPUCommandQueueType type; + // add more fields if needed +} CustomGPUCommandQueue; + typedef struct { // we just have only two adapters for simplicity CustomGPUAdapter adapters[2]; @@ -29,47 +35,41 @@ static CustomGPUBackend s_CustomGPU; // you might need a shutdown function for the backend after PAL has shutdown // if there is cleanup to do static void initCustomBackend() { + // PAL needs the memory it in bytes + Uint64 byte = 1024 * 1024 * 1024; + CustomGPUAdapter* adapter = &s_CustomGPU.adapters[0]; adapter->adapterInfo.apiType = PAL_GPU_API_TYPE_D3D9; - adapter->adapterInfo.debugLayerSupported = true; adapter->adapterInfo.type = PAL_GPU_TYPE_INTEGRATED; - - // PAL needs it in bytes - Uint64 byte = 1024 * 1024 * 1024; + adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_DXBC; adapter->adapterInfo.totalMemory = byte * 4; // 4 GB - strcpy(adapter->adapterInfo.versionString, "10_1"); strcpy(adapter->adapterInfo.name, "Intel Arc A580"); - adapter->adapterInfo.features = PAL_GPU_FEATURE_RAY_TRACING; - adapter->adapterInfo.features |= PAL_GPU_FEATURE_SWAPCHAIN; - adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_DXBC; - - adapter->adapterInfo.commandQueuesInfo.maxComputeQueues = 1; - adapter->adapterInfo.commandQueuesInfo.maxGraphicsQueues = 1; - adapter->adapterInfo.commandQueuesInfo.maxCopyQueues = 2; + adapter->caps.debugLayerSupported = true; + adapter->caps.features = PAL_GPU_FEATURE_RAY_TRACING; + adapter->caps.features |= PAL_GPU_FEATURE_SWAPCHAIN; + adapter->caps.maxComputeQueues = 1; + adapter->caps.maxGraphicsQueues = 1; + adapter->caps.maxCopyQueues = 2; // second adapter adapter = &s_CustomGPU.adapters[1]; adapter->adapterInfo.apiType = PAL_GPU_API_TYPE_OPENGL; - adapter->adapterInfo.debugLayerSupported = true; adapter->adapterInfo.type = PAL_GPU_TYPE_DISCRETE; - - // PAL needs it in bytes + adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; + adapter->adapterInfo.shaderFormats |= PAL_GPU_SHADER_FORMAT_GLSL; adapter->adapterInfo.totalMemory = byte * 6; // 6 GB - strcpy(adapter->adapterInfo.versionString, "4.4"); strcpy(adapter->adapterInfo.name, "AMD Radeon RX 7700 XT"); - adapter->adapterInfo.features = PAL_GPU_FEATURE_RAY_TRACING; - adapter->adapterInfo.features |= PAL_GPU_FEATURE_MESH_SHADER; - adapter->adapterInfo.features |= PAL_GPU_FEATURE_SWAPCHAIN; - adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; - adapter->adapterInfo.shaderFormats |= PAL_GPU_SHADER_FORMAT_GLSL; - - adapter->adapterInfo.commandQueuesInfo.maxComputeQueues = 1; - adapter->adapterInfo.commandQueuesInfo.maxGraphicsQueues = 4; - adapter->adapterInfo.commandQueuesInfo.maxCopyQueues = 4; + adapter->caps.debugLayerSupported = true; + adapter->caps.features = PAL_GPU_FEATURE_RAY_TRACING; + adapter->caps.features |= PAL_GPU_FEATURE_SWAPCHAIN; + adapter->caps.features |= PAL_GPU_FEATURE_MESH_SHADER; + adapter->caps.maxComputeQueues = 1; + adapter->caps.maxGraphicsQueues = 4; + adapter->caps.maxCopyQueues = 4; } static PalResult PAL_CALL customEnumerateGPUAdapters( @@ -99,38 +99,33 @@ static PalResult PAL_CALL customGetGPUAdapterInfo( // make a copy PalGPUAdapterInfo* gpuInfo = &s_CustomGPU.adapters[i].adapterInfo; info->apiType = gpuInfo->apiType; - info->debugLayerSupported = gpuInfo->debugLayerSupported; info->totalMemory = gpuInfo->totalMemory; info->type = gpuInfo->type; - info->features = gpuInfo->features; info->shaderFormats = gpuInfo->shaderFormats; - info->commandQueuesInfo = gpuInfo->commandQueuesInfo; strcpy(info->name, gpuInfo->name); strcpy(info->versionString, gpuInfo->versionString); - return PAL_RESULT_SUCCESS; } } + + return PAL_RESULT_INVALID_GPU_ADAPTER; } -static PalResult PAL_CALL customGetGPUAdapterSubInfo( +static PalResult PAL_CALL customGetGPUAdapterCapabilities( PalGPUAdapter* adapter, - PalGPUAdapterSubInfo* info) + PalGPUAdapterCapabilities* caps) { for (int i = 0; i < 2; i++) { PalGPUAdapter* custom = (PalGPUAdapter*)&s_CustomGPU.adapters[i]; if (custom == adapter) { // make a copy - PalGPUAdapterInfo* gpuInfo = &s_CustomGPU.adapters[i].adapterInfo; - info->apiType = gpuInfo->apiType; - info->type = gpuInfo->type; - strcpy(info->name, gpuInfo->name); - strcpy(info->versionString, gpuInfo->versionString); - + *caps = s_CustomGPU.adapters[i].caps; return PAL_RESULT_SUCCESS; } } + + return PAL_RESULT_INVALID_GPU_ADAPTER; } PalResult PAL_CALL customCreateGPUDevice( @@ -166,16 +161,31 @@ PalResult PAL_CALL customCreateGPUDevice( void PAL_CALL customDestroyGPUDevice(PalGPUDevice* device) { - // get your device CustomGPUDevice* customDevice = (CustomGPUDevice*)device; palFree(nullptr, device); } +static PalResult PAL_CALL customCreateGPUCommandQueue( + PalGPUDevice* device, + PalGPUCommandQueueType type, + PalGPUCommandQueue** outQueue) +{ + // implement +} + +void PAL_CALL customDestroyGPUCommandQueue(PalGPUCommandQueue* queue) +{ + // implement +} + static PalGPUBackend s_CustomBackend = { .enumerateGPUAdapters = customEnumerateGPUAdapters, .getGPUAdapterInfo = customGetGPUAdapterInfo, + .getGPUAdapterCapabilities = customGetGPUAdapterCapabilities, .createGPUDevice = customCreateGPUDevice, - .destroyGPUDevice = customDestroyGPUDevice + .destroyGPUDevice = customDestroyGPUDevice, + .createGPUCommandQueue = customCreateGPUCommandQueue, + .destroyGPUCommandQueue = customDestroyGPUCommandQueue }; bool customGraphicsBackendTest() @@ -324,88 +334,6 @@ bool customGraphicsBackendTest() } palLog(nullptr, " API Type: %s", apiTypeString); - const char* boolToString; - if (info.debugLayerSupported) { - boolToString = "True"; - } else { - boolToString = "False"; - } - - palLog(nullptr, " Debug Layer: %s", boolToString); - - // command queues - Int32 maxComputeQueues = info.commandQueuesInfo.maxComputeQueues; - Int32 maxGraphicsQueues = info.commandQueuesInfo.maxGraphicsQueues; - Int32 maxCopyQueues = info.commandQueuesInfo.maxCopyQueues; - palLog(nullptr, " Max compute command queues: %d", maxComputeQueues); - palLog(nullptr, " Max graphics command queues: %d", maxGraphicsQueues); - palLog(nullptr, " Max transfer command queues: %d", maxCopyQueues); - - // features - palLog(nullptr, " Supported Features:"); - if (info.features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { - palLog(nullptr, " Sampler Anisotropy"); - } - - if (info.features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { - palLog(nullptr, " Sample rate shading"); - } - - if (info.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { - palLog(nullptr, " Multi viewport"); - } - - if (info.features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { - palLog(nullptr, " Timeline Semaphore"); - } - - if (info.features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { - palLog(nullptr, " Tesselation Shader"); - } - - if (info.features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { - palLog(nullptr, " Geometry shader"); - } - - if (info.features & PAL_GPU_FEATURE_SHADER_FLOAT16) { - palLog(nullptr, " Shader float16"); - } - - if (info.features & PAL_GPU_FEATURE_SHADER_FLOAT64) { - palLog(nullptr, " Shader float64"); - } - - if (info.features & PAL_GPU_FEATURE_SHADER_INT16) { - palLog(nullptr, " Shader int16"); - } - if (info.features & PAL_GPU_FEATURE_SHADER_INT64) { - palLog(nullptr, " Shader int64"); - } - - if (info.features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { - palLog(nullptr, " Dynamic rendering"); - } - - if (info.features & PAL_GPU_FEATURE_RAY_TRACING) { - palLog(nullptr, " Ray tracing"); - } - - if (info.features & PAL_GPU_FEATURE_MESH_SHADER) { - palLog(nullptr, " Mesh shader"); - } - - if (info.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { - palLog(nullptr, " Variable rate rendering"); - } - - if (info.features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { - palLog(nullptr, " Descriptor indexing"); - } - - if (info.features & PAL_GPU_FEATURE_SWAPCHAIN) { - palLog(nullptr, " Swapchain"); - } - // shader formats palLog(nullptr, " Supported Shader Formats:"); if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_SPIRV) { @@ -435,21 +363,6 @@ bool customGraphicsBackendTest() palLog(nullptr, ""); } - // create a device with a custom adapter (D3D9) - PalGPUDevice* device = nullptr; - PalGPUFeatures features = PAL_GPU_FEATURE_SHADER_FLOAT64; - features |= PAL_GPU_FEATURE_SWAPCHAIN; - - result = palCreateGPUDevice(d3d9Adapter, features, &device); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); - palFree(nullptr, adapters); - return false; - } - - palDestroyGPUDevice(device); - // shutdown the graphics system palShutdownGraphics(); diff --git a/tests/gpu_device_test.c b/tests/gpu_device_test.c index 336eaedb..be617127 100644 --- a/tests/gpu_device_test.c +++ b/tests/gpu_device_test.c @@ -51,20 +51,20 @@ bool gpuDeviceTest() // filter the adapters for Vulkan PalGPUAdapter* vulkanAdapter = nullptr; - PalGPUAdapterSubInfo subInfo = {0}; + PalGPUAdapterInfo info = {0}; for (Int32 i = 0; i < count; i++) { PalGPUAdapter* adapter = adapters[i]; - result = palGetGPUAdapterSubInfo(adapter, &subInfo); + result = palGetGPUAdapterInfo(adapter, &info); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter sub info: %s", error); + palLog(nullptr, "Failed to get adapter info: %s", error); palFree(nullptr, adapters); return false; } // check if its Vulkan - if (subInfo.apiType == PAL_GPU_API_TYPE_VULKAN) { + if (info.apiType == PAL_GPU_API_TYPE_VULKAN) { vulkanAdapter = adapter; break; } @@ -76,11 +76,9 @@ bool gpuDeviceTest() return false; } - // get information about the adapter - // this time, we want all the information including - // supported features and the rest - PalGPUAdapterInfo info = {0}; - result = palGetGPUAdapterInfo(vulkanAdapter, &info); + // get capabilities about the adapter + PalGPUAdapterCapabilities caps = {0}; + result = palGetGPUAdapterCapabilities(vulkanAdapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); @@ -93,11 +91,11 @@ bool gpuDeviceTest() PalGPUFeatures features = 0; // enable swapchain and maybe multi viewport if supported - if (info.features & PAL_GPU_FEATURE_SWAPCHAIN) { + if (caps.features & PAL_GPU_FEATURE_SWAPCHAIN) { features = PAL_GPU_FEATURE_SWAPCHAIN; } - if (info.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { + if (caps.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { features |= PAL_GPU_FEATURE_MULTI_VIEWPORT; } @@ -109,10 +107,10 @@ bool gpuDeviceTest() } // check if we support a graphics command queue - if (!info.commandQueuesInfo.maxGraphicsQueues) { + if (!caps.maxGraphicsQueues) { palLog( nullptr, - "This Adapter (GPU) does not have any grapics command queues"); + "This Adapter (GPU) does not have any graphics command queues"); return false; } @@ -125,7 +123,7 @@ bool gpuDeviceTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create grapics command queue: %s", error); + palLog(nullptr, "Failed to create graphics command queue: %s", error); return false; } diff --git a/tests/graphics_test.c b/tests/graphics_test.c index ec553394..96095924 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -51,6 +51,7 @@ bool graphicsTest() // get information about all the adapters PalGPUAdapterInfo info; + PalGPUAdapterCapabilities caps; for (Int32 i = 0; i < count; i++) { PalGPUAdapter* adapter = adapters[i]; result = palGetGPUAdapterInfo(adapter, &info); @@ -61,6 +62,14 @@ bool graphicsTest() return false; } + result = palGetGPUAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + Uint32 memoryGb = info.totalMemory / (1024.0 * 1024.0 * 1024.0); palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Total Memory %dGB", memoryGb); @@ -135,7 +144,7 @@ bool graphicsTest() palLog(nullptr, " API Type: %s", apiTypeString); const char* boolToString; - if (info.debugLayerSupported) { + if (caps.debugLayerSupported) { boolToString = "True"; } else { boolToString = "False"; @@ -143,76 +152,76 @@ bool graphicsTest() palLog(nullptr, " Debug Layer: %s", boolToString); - // command queue - Int32 maxComputeQueues = info.commandQueuesInfo.maxComputeQueues; - Int32 maxGraphicsQueues = info.commandQueuesInfo.maxGraphicsQueues; - Int32 maxCopyQueues = info.commandQueuesInfo.maxCopyQueues; + // command queues + Int32 maxComputeQueues = caps.maxComputeQueues; + Int32 maxGraphicsQueues = caps.maxGraphicsQueues; + Int32 maxCopyQueues = caps.maxCopyQueues; palLog(nullptr, " Max compute command queues: %d", maxComputeQueues); palLog(nullptr, " Max graphics command queues: %d", maxGraphicsQueues); palLog(nullptr, " Max copy command queues: %d", maxCopyQueues); // features palLog(nullptr, " Supported Features:"); - if (info.features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { + if (caps.features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { palLog(nullptr, " Sampler Anisotropy"); } - if (info.features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { + if (caps.features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { palLog(nullptr, " Sample rate shading"); } - if (info.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { + if (caps.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { palLog(nullptr, " Multi viewport"); } - if (info.features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { + if (caps.features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { palLog(nullptr, " Timeline Semaphore"); } - if (info.features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { + if (caps.features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { palLog(nullptr, " Tesselation Shader"); } - if (info.features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { + if (caps.features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { palLog(nullptr, " Geometry shader"); } - if (info.features & PAL_GPU_FEATURE_SHADER_FLOAT16) { + if (caps.features & PAL_GPU_FEATURE_SHADER_FLOAT16) { palLog(nullptr, " Shader float16"); } - if (info.features & PAL_GPU_FEATURE_SHADER_FLOAT64) { + if (caps.features & PAL_GPU_FEATURE_SHADER_FLOAT64) { palLog(nullptr, " Shader float64"); } - if (info.features & PAL_GPU_FEATURE_SHADER_INT16) { + if (caps.features & PAL_GPU_FEATURE_SHADER_INT16) { palLog(nullptr, " Shader int16"); } - if (info.features & PAL_GPU_FEATURE_SHADER_INT64) { + if (caps.features & PAL_GPU_FEATURE_SHADER_INT64) { palLog(nullptr, " Shader int64"); } - if (info.features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { + if (caps.features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { palLog(nullptr, " Dynamic rendering"); } - if (info.features & PAL_GPU_FEATURE_RAY_TRACING) { + if (caps.features & PAL_GPU_FEATURE_RAY_TRACING) { palLog(nullptr, " Ray tracing"); } - if (info.features & PAL_GPU_FEATURE_MESH_SHADER) { + if (caps.features & PAL_GPU_FEATURE_MESH_SHADER) { palLog(nullptr, " Mesh shader"); } - if (info.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { + if (caps.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { palLog(nullptr, " Variable rate rendering"); } - if (info.features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { + if (caps.features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { palLog(nullptr, " Descriptor indexing"); } - if (info.features & PAL_GPU_FEATURE_SWAPCHAIN) { + if (caps.features & PAL_GPU_FEATURE_SWAPCHAIN) { palLog(nullptr, " Swapchain"); } diff --git a/tests/tests_main.c b/tests/tests_main.c index 1412780d..b5b4d7ac 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,9 +55,9 @@ int main(int argc, char** argv) #endif // #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); + registerTest("Graphics Test", graphicsTest); // registerTest("Custom Graphics Backend Test", customGraphicsBackendTest); - registerTest("GPU Device Test", gpuDeviceTest); + //registerTest("GPU Device Test", gpuDeviceTest); #endif // PAL_HAS_GRAPHICS runTests(); From 078458e6789bf8b988fe106fbaab9e79c72060da Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 29 Nov 2025 16:21:26 +0000 Subject: [PATCH 017/372] start swapchain --- include/pal/pal_core.h | 4 +- include/pal/pal_graphics.h | 94 +++++- src/graphics/pal_graphics_linux.c | 508 +++++++++++++++++++++++++++--- src/pal_core.c | 6 + tests/gpu_device_test.c | 39 +-- tests/swapchain_test.c | 292 +++++++++++++++++ tests/tests.h | 3 + tests/tests.lua | 6 + tests/tests_main.c | 10 +- 9 files changed, 887 insertions(+), 75 deletions(-) create mode 100644 tests/swapchain_test.c diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 8800f627..fcbc25e3 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -253,7 +253,9 @@ typedef enum { PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED, PAL_RESULT_INVALID_GRAPHICS_DRIVER, PAL_RESULT_INVALID_GPU_DEVICE, - PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE + PAL_RESULT_INVALID_GPU_COMMAND_QUEUE, + PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE, + PAL_RESULT_INVALID_GPU_WINDOW } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d95dc79b..83f69500 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -35,6 +35,7 @@ freely, subject to the following restrictions: #define PAL_GPU_NAME_SIZE 128 #define PAL_GPU_VERSION_SIZE 16 +#define PAL_INFINITE (2147483647) typedef struct PalGPUAdapter PalGPUAdapter; typedef struct PalGPUDevice PalGPUDevice; @@ -59,7 +60,7 @@ typedef enum { PAL_GPU_API_TYPE_GLES, PAL_GPU_API_TYPE_D3D11, PAL_GPU_API_TYPE_D3D9, - PAL_GPU_API_TYPE_PPM, + PAL_GPU_API_TYPE_PPM } PalGPUApiType; typedef enum { @@ -68,6 +69,44 @@ typedef enum { PAL_GPU_COMMAND_QUEUE_TYPE_COPY } PalGPUCommandQueueType; +typedef enum { + PAL_PRESENT_MODE_FIFO = PAL_BIT(0), + PAL_PRESENT_MODE_IMMEDIATE = PAL_BIT(1), + PAL_PRESENT_MODE_MAILBOX = PAL_BIT(2) +} PalPresentModes; + +typedef enum { + PAL_COMPOSITE_ALPHA_OPAQUE = PAL_BIT(0), + PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED = PAL_BIT(1), + PAL_COMPOSITE_ALPHA_POST_MULTIPLIED = PAL_BIT(2) +} PalCompositeAplhas; + +typedef enum { + PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB = PAL_BIT64(0), + PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB = PAL_BIT64(1), + PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB = PAL_BIT64(2), + PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10 = PAL_BIT64(3) +} PalSwapchainFormats; + +typedef enum { + PAL_SWAPCHAIN_SHARING_MODE_EXCLUSIVE = PAL_BIT(0), + PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT = PAL_BIT(1) +} PalSwapchainSharingModes; + +typedef enum { + PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE = PAL_BIT(0), + PAL_SWAPCHAIN_TRANSFORM_PORTRAIT = PAL_BIT(1), + PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED = PAL_BIT(2), + PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED = PAL_BIT(3) +} PalSwapchainTransforms; + +typedef enum { + PAL_SWAPCHAIN_USAGE_COLOR_ATTACHEMENT = PAL_BIT(0), + PAL_SWAPCHAIN_USAGE_TRANSFER_SRC = PAL_BIT(1), + PAL_SWAPCHAIN_USAGE_TRANSFER_DST = PAL_BIT(2), + PAL_SWAPCHAIN_USAGE_SAMPLED = PAL_BIT(3), +} PalSwapchainUsages; + typedef enum { PAL_GPU_SHADER_FORMAT_SPIRV = PAL_BIT(0), PAL_GPU_SHADER_FORMAT_DXIL = PAL_BIT(1), @@ -113,6 +152,41 @@ typedef struct { PalGPUFeatures features; } PalGPUAdapterCapabilities; +typedef struct { + Uint32 minBufferCount; + Uint32 maxBufferCount; + Uint32 minWidth; + Uint32 minHeight; + Uint32 maxWidth; + Uint32 maxHeight; + Uint32 maxBufferArrayLayers; + PalSwapchainFormats formats; + PalSwapchainUsages usages; + PalPresentModes presentModes; + PalCompositeAplhas compositeAlphas; + PalSwapchainSharingModes sharingModes; + PalSwapchainTransforms transforms; +} PalSwapchainCapabilities; + +typedef struct { + bool clipped; + Uint32 width; + Uint32 height; + Uint32 imageCount; + Uint32 imageArrayLayerCount; + PalPresentModes presentMode; + PalSwapchainUsages usages; + PalCompositeAplhas compositeAlpha; + PalSwapchainFormats format; + PalSwapchainSharingModes sharingMode; + PalSwapchainTransforms transform; +} PalSwapchainCreateInfo; + +typedef struct { + void* display; + void* window; +} PalGPUWindow; + typedef struct { PalResult PAL_CALL (*enumerateGPUAdapters)( Int32* count, @@ -139,6 +213,15 @@ typedef struct { PalGPUCommandQueue** outQueue); void PAL_CALL (*destroyGPUCommandQueue)(PalGPUCommandQueue* queue); + + bool PAL_CALL (*canCommandQueuePresent)( + PalGPUCommandQueue* queue, + PalGPUWindow* window); + + PalResult PAL_CALL (*getSwapchainCapabilities)( + PalGPUAdapter* adapter, + PalGPUWindow* window, + PalSwapchainCapabilities* caps); } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics( @@ -175,6 +258,15 @@ PAL_API PalResult PAL_CALL palCreateGPUCommandQueue( PAL_API void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue); +PAL_API bool PAL_CALL palCanCommandQueuePresent( + PalGPUCommandQueue* queue, + PalGPUWindow* window); + +PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( + PalGPUAdapter* adapter, + PalGPUWindow* window, + PalSwapchainCapabilities* caps); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index f35a7931..9333499e 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -39,17 +39,71 @@ freely, subject to the following restrictions: // Typedefs, enums and structs // ================================================== -// TODO: make all these dynamic -#define MAX_BACKENDS 16 // should be fine for now -#define MAX_ADAPTERS 32 // should be enough -#define MAX_DEVICE 16 // should be enough +// FIXME: make all these dynamic if need be +// but for now its fine +#define MAX_BACKENDS 16 +#define MAX_ADAPTERS 32 +#define MAX_DEVICE 16 #define MAX_QUEUE_FAMILIES 8 #define MAX_PHYSICAL_QUEUES 16 #define MAX_COMMAND_QUEUES 32 +#define MAX_FORMATS 32 +#define MAX_PRESENT_MODES 16 #if PAL_HAS_VULKAN // VKAPI_PTR expands to nothing on linux +// HACK: Needed to determine display type +struct wl_display; +typedef int (*wl_display_get_fd_fn)(struct wl_display*); + +// wayland +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; +typedef struct VkWaylandSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display* display; + struct wl_surface* surface; +} VkWaylandSurfaceCreateInfoKHR; + +typedef VkResult (*vkCreateWaylandSurfaceKHRFn)( + VkInstance, + const VkWaylandSurfaceCreateInfoKHR*, + const VkAllocationCallbacks*, + VkSurfaceKHR*); + +typedef VkBool32 (*vkGetPhysicalDeviceWaylandPresentationSupportKHRFn)( + VkPhysicalDevice, + uint32_t, + struct wl_display*); + +// Xlib +typedef struct _XDisplay Display; +typedef unsigned long Window; +typedef unsigned long VisualID; +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; + +typedef struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + +typedef VkResult (*vkCreateXlibSurfaceKHRFn)( + VkInstance, + const VkXlibSurfaceCreateInfoKHR*, + const VkAllocationCallbacks*, + VkSurfaceKHR*); + +typedef VkBool32 (*vkGetPhysicalDeviceXlibPresentationSupportKHRFn)( + VkPhysicalDevice, + uint32_t, + Display*, + VisualID); + typedef VkResult (*vkEnumerateInstanceVersionFn)(uint32_t*); typedef VkResult (*vkEnumerateInstanceExtensionPropertiesFn)( @@ -122,12 +176,46 @@ typedef void (*vkGetDeviceQueueFn)( uint32_t, VkQueue*); +typedef void (*vkDestroySurfaceKHRFn)( + VkInstance, + VkSurfaceKHR, + const VkAllocationCallbacks*); + +typedef PFN_vkVoidFunction (*vkGetInstanceProcAddrFn)( + VkInstance, + const char*); + +typedef PFN_vkVoidFunction (*vkGetDeviceProcAddrFn)( + VkDevice, + const char*); + +typedef VkResult (*vkGetPhysicalDeviceSurfaceCapabilitiesKHRFn)( + VkPhysicalDevice, + VkSurfaceKHR, + VkSurfaceCapabilitiesKHR*); + +typedef VkResult (*vkGetPhysicalDeviceSurfaceFormatsKHRFn)( + VkPhysicalDevice, + VkSurfaceKHR, + uint32_t*, + VkSurfaceFormatKHR*); + +typedef VkResult (*vkGetPhysicalDeviceSurfacePresentModesKHRFn)( + VkPhysicalDevice, + VkSurfaceKHR, + uint32_t*, + VkPresentModeKHR*); + typedef struct { bool hasDebug; bool versionFallback; void* handle; VkInstance instance; - + + // HACK: for display testing + void* libWayland; + wl_display_get_fd_fn getDisplayFd; + vkEnumerateInstanceVersionFn enumerateInstanceVersion; vkEnumerateInstanceExtensionPropertiesFn enumerateInstanceExtensionProperties; vkDestroyInstanceFn destroyInstance; @@ -141,10 +229,21 @@ typedef struct { vkGetPhysicalDeviceFeaturesFn getPhysicalDeviceFeatures; vkGetPhysicalDeviceFeatures2Fn getPhysicalDeviceFeatures2; vkGetPhysicalDeviceFeatures2KHRFn getPhysicalDeviceFeatures2KHR; - + vkGetInstanceProcAddrFn getInstanceProcAddr; + vkCreateDeviceFn createDevice; vkDestroyDeviceFn destroyDevice; vkGetDeviceQueueFn getDeviceQueue; + vkGetDeviceProcAddrFn getDeviceProcAddr; + + vkCreateWaylandSurfaceKHRFn createWaylandSurface; + vkGetPhysicalDeviceWaylandPresentationSupportKHRFn checkWaylandPresentSupport; + vkCreateXlibSurfaceKHRFn createXlibSurface; + vkGetPhysicalDeviceXlibPresentationSupportKHRFn checkXlibPresentSupport; + vkDestroySurfaceKHRFn destroySurface; + vkGetPhysicalDeviceSurfaceCapabilitiesKHRFn getSurfaceCapabilities; + vkGetPhysicalDeviceSurfaceFormatsKHRFn getSurfaceFormats; + vkGetPhysicalDeviceSurfacePresentModesKHRFn getSurfacePresentModes; VkAllocationCallbacks allocator; } Vulkan; @@ -156,6 +255,8 @@ typedef struct { } QueueFamilyData; typedef struct { + Int32 familyIndex; + VkPhysicalDevice phyDevice; VkQueue handle; VkQueueFlags usages; VkQueueFlags usedUsages; @@ -168,6 +269,7 @@ typedef struct { typedef struct { Int32 queueCount; + VkPhysicalDevice phyDevice; VkDevice handle; PhysicalQueue queues[MAX_PHYSICAL_QUEUES]; } VkGPUDevice; @@ -184,6 +286,7 @@ typedef struct { typedef struct { bool used; + PalGPUAdapter* adapter; PalGPUDevice* device; const PalGPUBackend* backend; } DeviceData; @@ -286,6 +389,51 @@ static CommandQueueData* findCommandQueueData(PalGPUCommandQueue* queue) #if PAL_HAS_VULKAN +static bool vkOnWayland(struct wl_display* display) +{ + if (!s_Vk.libWayland) { + return false; + } + + int fd = s_Vk.getDisplayFd(display); + if (fd <= 0 || fd > 1024) { // fds are usaually 0-30 but this is fine + return false; + } + return true; +} + +static bool vkCreateSurface(PalGPUWindow* window, VkSurfaceKHR* outSurface) +{ + if (vkOnWayland(window->display)) { + if (!s_Vk.createWaylandSurface) { + return false; + } + + VkSurfaceKHR surface = nullptr; + VkWaylandSurfaceCreateInfoKHR createInfo = {0}; + createInfo.display = window->display; + createInfo.pNext = nullptr; + createInfo.flags = 0; + createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + createInfo.surface = window->window; + + VkResult result = s_Vk.createWaylandSurface( + s_Vk.instance, + &createInfo, + &s_Vk.allocator, + &surface); + + if (result != VK_SUCCESS) { + return false; + } + *outSurface = surface; + + } else { + // TODO: create surface for xlib + } + return true; +} + static PalResult vkResultToPal(VkResult result) { switch (result) { @@ -365,6 +513,14 @@ static void* vkRealloc( static PalResult vkInitGraphics(bool enableDebugLayer) { + s_Vk.libWayland = nullptr; + s_Vk.libWayland = dlopen("libwayland-client.so.0", RTLD_LAZY); + if (s_Vk.libWayland) { + s_Vk.getDisplayFd = (wl_display_get_fd_fn)dlsym( + s_Vk.libWayland, + "wl_display_get_fd"); + } + // load vulkan s_Vk.handle = dlopen("libvulkan.so", RTLD_LAZY); if (!s_Vk.handle) { @@ -420,6 +576,10 @@ static PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.handle, "vkGetPhysicalDeviceFeatures2"); + s_Vk.getInstanceProcAddr = (vkGetInstanceProcAddrFn)dlsym( + s_Vk.handle, + "vkGetInstanceProcAddr"); + s_Vk.createDevice = (vkCreateDeviceFn)dlsym( s_Vk.handle, "vkCreateDevice"); @@ -431,6 +591,10 @@ static PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.getDeviceQueue = (vkGetDeviceQueueFn)dlsym( s_Vk.handle, "vkGetDeviceQueue"); + + s_Vk.getDeviceProcAddr = (vkGetDeviceProcAddrFn)dlsym( + s_Vk.handle, + "vkGetDeviceProcAddr"); // clang-format on @@ -507,7 +671,6 @@ static PalResult vkInitGraphics(bool enableDebugLayer) extensionProps); bool hasXlib = false; - bool hasXcb = false; bool hasWayland = false; bool hasSurface = false; bool hasExtDebug = false; @@ -517,9 +680,6 @@ static PalResult vkInitGraphics(bool enableDebugLayer) if (strcmp(prop->extensionName, "VK_KHR_xlib_surface") == 0) { hasXlib = true; - } else if (strcmp(prop->extensionName, "VK_KHR_xcb_surface") == 0) { - hasXcb = true; - } else if (strcmp(prop->extensionName, "VK_KHR_wayland_surface") == 0) { hasWayland = true; @@ -543,10 +703,6 @@ static PalResult vkInitGraphics(bool enableDebugLayer) if (hasXlib) { extensions[extensionCount++] = "VK_KHR_xlib_surface"; } - - if (hasXcb) { - extensions[extensionCount++] = "VK_KHR_xcb_surface"; - } } const char* layers[2]; @@ -594,13 +750,13 @@ static PalResult vkInitGraphics(bool enableDebugLayer) return vkResultToPal(result); } + // clang-format off if (versionFallback) { // load get physical device properties2 proc if we are on version 1.0 - // clang-format off - s_Vk.getPhysicalDeviceFeatures2KHR = (vkGetPhysicalDeviceFeatures2KHRFn)dlsym( - s_Vk.handle, - "vkGetPhysicalDeviceFeatures2KHR"); - // clang-format on + s_Vk.getPhysicalDeviceFeatures2KHR = + (vkGetPhysicalDeviceFeatures2KHRFn)s_Vk.getInstanceProcAddr( + s_Vk.handle, + "vkGetPhysicalDeviceFeatures2KHR"); if (s_Vk.getPhysicalDeviceFeatures2KHR) { s_Vk.versionFallback = true; @@ -609,6 +765,52 @@ static PalResult vkInitGraphics(bool enableDebugLayer) } } + // load surface creation function pointers + s_Vk.createWaylandSurface = nullptr; + s_Vk.createXlibSurface = nullptr; + + if (hasWayland) { + s_Vk.createWaylandSurface = (vkCreateWaylandSurfaceKHRFn)s_Vk.getInstanceProcAddr( + instance, + "vkCreateWaylandSurfaceKHR"); + + s_Vk.checkWaylandPresentSupport = + (vkGetPhysicalDeviceWaylandPresentationSupportKHRFn)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); + } + + if (hasXlib) { + s_Vk.createXlibSurface = (vkCreateXlibSurfaceKHRFn)s_Vk.getInstanceProcAddr( + instance, + "vkCreateXlibSurfaceKHR"); + + s_Vk.checkXlibPresentSupport = + (vkGetPhysicalDeviceXlibPresentationSupportKHRFn)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceXlibPresentationSupportKHR"); + } + + // remaining function procs + s_Vk.destroySurface = (vkDestroySurfaceKHRFn)s_Vk.getInstanceProcAddr( + instance, + "vkDestroySurfaceKHR"); + + s_Vk.getSurfaceCapabilities = + (vkGetPhysicalDeviceSurfaceCapabilitiesKHRFn)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); + + s_Vk.getSurfacePresentModes = + (vkGetPhysicalDeviceSurfacePresentModesKHRFn)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceSurfacePresentModesKHR"); + + s_Vk.getSurfaceFormats = (vkGetPhysicalDeviceSurfaceFormatsKHRFn)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceSurfaceFormatsKHR"); + // clang-format on + s_Vk.instance = instance; return PAL_RESULT_SUCCESS; } @@ -618,6 +820,9 @@ static void vkShutdownGraphics() if (s_Vk.instance) { s_Vk.destroyInstance(s_Vk.instance, &s_Vk.allocator); dlclose(s_Vk.handle); + if (s_Vk.libWayland) { + dlclose(s_Vk.libWayland); + } memset(&s_Vk, 0, sizeof(s_Vk)); } } @@ -663,12 +868,12 @@ static PalResult PAL_CALL vkGetAdapterInfo( PalGPUAdapter* adapter, PalGPUAdapterInfo* info) { - VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; VkPhysicalDeviceProperties props = {0}; VkPhysicalDeviceMemoryProperties memProps = {0}; - s_Vk.getPhysicalDeviceMemoryProperties(physicalDevice, &memProps); - s_Vk.getPhysicalDeviceProperties(physicalDevice, &props); + s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); + s_Vk.getPhysicalDeviceProperties(phyDevice, &props); info->apiType = PAL_GPU_API_TYPE_VULKAN; info->shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; @@ -726,19 +931,19 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( PalGPUAdapterCapabilities* caps) { VkResult ret = VK_SUCCESS; - VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; caps->debugLayerSupported = s_Vk.hasDebug; // get supported queue commands Uint32 count; s_Vk.getPhysicalDeviceQueueFamilyProperties( - physicalDevice, + phyDevice, &count, nullptr); VkQueueFamilyProperties queueProps[MAX_QUEUE_FAMILIES]; s_Vk.getPhysicalDeviceQueueFamilyProperties( - physicalDevice, + phyDevice, &count, queueProps); @@ -763,7 +968,7 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( // get supported extensions Uint32 extensionCount = 0; ret = s_Vk.enumerateDeviceExtensionProperties( - physicalDevice, + phyDevice, nullptr, &extensionCount, nullptr); @@ -784,7 +989,7 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( } s_Vk.enumerateDeviceExtensionProperties( - physicalDevice, + phyDevice, nullptr, &extensionCount, extensionProps); @@ -812,10 +1017,10 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( features.pNext = &mesh; if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); } else { - s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); } if (mesh.meshShader && mesh.taskShader) { @@ -832,10 +1037,10 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( features.pNext = &frag; if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); } else { - s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); } if (frag.pipelineFragmentShadingRate) { @@ -852,10 +1057,10 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( features.pNext = &desc; if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); } else { - s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); } if (desc.shaderSampledImageArrayNonUniformIndexing) { @@ -880,10 +1085,10 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( features.pNext = &shader16; if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); } else { - s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); } if (shader16.shaderFloat16) { @@ -900,10 +1105,10 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( features.pNext = &timeline; if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); } else { - s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); } if (timeline.timelineSemaphore) { @@ -925,10 +1130,10 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( features.pNext = &ray; if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); } else { - s_Vk.getPhysicalDeviceFeatures2(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); } if (ray.rayTracingPipeline && acc.accelerationStructure) { @@ -937,7 +1142,7 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( } // clang-format on VkPhysicalDeviceFeatures features; - s_Vk.getPhysicalDeviceFeatures(physicalDevice, &features); + s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); // check for additional features if (features.geometryShader) { @@ -983,17 +1188,17 @@ static PalResult PAL_CALL vkCreateGPUDevice( { VkResult ret = VK_SUCCESS; VkDevice device = nullptr; - VkPhysicalDevice physicalDevice = (VkPhysicalDevice)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; Uint32 count = 0; s_Vk.getPhysicalDeviceQueueFamilyProperties( - physicalDevice, + phyDevice, &count, nullptr); VkQueueFamilyProperties queueProps[MAX_QUEUE_FAMILIES]; s_Vk.getPhysicalDeviceQueueFamilyProperties( - physicalDevice, + phyDevice, &count, queueProps); @@ -1190,7 +1395,7 @@ static PalResult PAL_CALL vkCreateGPUDevice( createInfo.pNext = start; ret = s_Vk.createDevice( - physicalDevice, + phyDevice, &createInfo, &s_Vk.allocator, &device); @@ -1208,17 +1413,21 @@ static PalResult PAL_CALL vkCreateGPUDevice( memset(gpuDevice, 0, sizeof(VkGPUDevice)); // get queues - gpuDevice->handle = device; for (int i = 0; i < queueFamilyCount; i++) { QueueFamilyData* data = &queueFamilyData[i]; for (int j = 0; j < data->count; j++) { PhysicalQueue* queue = &gpuDevice->queues[gpuDevice->queueCount++]; - s_Vk.getDeviceQueue(device, data->index, 0, &queue->handle); + s_Vk.getDeviceQueue(device, data->index, j, &queue->handle); queue->usages = data->flags; queue->usedUsages = 0; + queue->familyIndex = data->index; + queue->phyDevice = phyDevice; } } + gpuDevice->handle = device; + gpuDevice->phyDevice = phyDevice; + *outDevice = (PalGPUDevice*)gpuDevice; return PAL_RESULT_SUCCESS; } @@ -1305,6 +1514,162 @@ static void PAL_CALL vkDestroyGPUCommandQueue(PalGPUCommandQueue* queue) palFree(s_Graphics.allocator, commandQueue); } +bool PAL_CALL vkCanCommandQueuePresent( + PalGPUCommandQueue* queue, + PalGPUWindow* window) +{ + bool onWayland = vkOnWayland(window->display); + VkCommandQueue* commandQueue = (VkCommandQueue*)queue; + PhysicalQueue* phyQueue = commandQueue->phyQueue; + + if (!s_Vk.checkWaylandPresentSupport( + phyQueue->phyDevice, + phyQueue->familyIndex, window->display)) { + return false; + } else { + // TODO: check presentation for xlib + } + + return true; +} + +static PalResult PAL_CALL vkQuerySwapchainCapabilities( + PalGPUAdapter* adapter, + PalGPUWindow* window, + PalSwapchainCapabilities* caps) +{ + VkSurfaceKHR surface = nullptr; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + + bool ret = vkCreateSurface(window, &surface); + if (!ret) { + return PAL_RESULT_INVALID_GPU_WINDOW; + } + + VkSurfaceCapabilitiesKHR surfaceCaps; + s_Vk.getSurfaceCapabilities(phyDevice, surface, &surfaceCaps); + caps->minWidth = surfaceCaps.minImageExtent.width; + caps->minHeight = surfaceCaps.minImageExtent.height; + caps->maxWidth = surfaceCaps.maxImageExtent.width; + caps->maxHeight = surfaceCaps.maxImageExtent.height; + + caps->maxBufferCount = surfaceCaps.maxImageCount; + caps->minBufferCount = surfaceCaps.minImageCount; + caps->maxBufferArrayLayers = surfaceCaps.maxImageArrayLayers; + + if (caps->maxBufferCount == 0) { + caps->maxBufferCount = PAL_INFINITE; + } + + // get supported transforms + VkSurfaceTransformFlagsKHR trans = surfaceCaps.supportedTransforms; + if (trans & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { + caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE; + } + + if (trans & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { + caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_PORTRAIT; + } + + if (trans & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) { + caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED; + } + + if (trans & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { + caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED; + } + + // get supported composite alphas + VkCompositeAlphaFlagsKHR alpha = surfaceCaps.supportedCompositeAlpha; + caps->compositeAlphas = PAL_COMPOSITE_ALPHA_OPAQUE; + if (alpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { + caps->compositeAlphas |= PAL_COMPOSITE_ALPHA_POST_MULTIPLIED; + } + + if (alpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { + caps->compositeAlphas |= PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED; + } + + // get supported composite alphas + VkImageUsageFlags usage = surfaceCaps.supportedUsageFlags; + caps->usages = 0; + if (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { + caps->usages |= PAL_SWAPCHAIN_USAGE_COLOR_ATTACHEMENT; + } + + if (usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { + caps->usages |= PAL_SWAPCHAIN_USAGE_TRANSFER_DST; + } + + if (usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { + caps->usages |= PAL_SWAPCHAIN_USAGE_TRANSFER_SRC; + } + + if (usage & VK_IMAGE_USAGE_SAMPLED_BIT) { + caps->usages |= PAL_SWAPCHAIN_USAGE_SAMPLED; + } + + // sharing modes + caps->sharingModes = PAL_SWAPCHAIN_SHARING_MODE_EXCLUSIVE; + caps->sharingModes |= PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT; + + // present modes + caps->presentModes = PAL_PRESENT_MODE_FIFO; + Int32 count = 0; + VkPresentModeKHR modes[MAX_PRESENT_MODES] = {0}; + s_Vk.getSurfacePresentModes(phyDevice, surface, &count, nullptr); + + if (count) { + s_Vk.getSurfacePresentModes(phyDevice, surface, &count, modes); + for (int i = 0; i < count; i++) { + if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { + caps->presentModes |= PAL_PRESENT_MODE_IMMEDIATE; + } + + if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { + caps->presentModes |= PAL_PRESENT_MODE_MAILBOX; + } + } + } + + // get format and colorspace + count = 0; + VkSurfaceFormatKHR formats[MAX_FORMATS] = {0}; + s_Vk.getSurfaceFormats(phyDevice, surface, &count, nullptr); + + s_Vk.getSurfaceFormats(phyDevice, surface, &count, formats); + for (int i = 0; i < count; i++) { + VkSurfaceFormatKHR* fmt = &formats[i]; + if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + caps->formats |= PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; + } + + } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + caps->formats |= PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB; + } + + } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + caps->formats |= PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + } + + } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { + caps->formats |= PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10; + } + } + } + + s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); + return PAL_RESULT_SUCCESS; +} + static PalGPUBackend s_VkBackend = { .enumerateGPUAdapters = vkEnumerateAdapters, .getGPUAdapterInfo = vkGetAdapterInfo, @@ -1312,7 +1677,9 @@ static PalGPUBackend s_VkBackend = { .createGPUDevice = vkCreateGPUDevice, .destroyGPUDevice = vkDestroyGPUDevice, .createGPUCommandQueue = vkCreateGPUCommandQueue, - .destroyGPUCommandQueue = vkDestroyGPUCommandQueue + .destroyGPUCommandQueue = vkDestroyGPUCommandQueue, + .canCommandQueuePresent = vkCanCommandQueuePresent, + .getSwapchainCapabilities = vkQuerySwapchainCapabilities }; #endif // PAL_HAS_VULKAN @@ -1478,7 +1845,9 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) !backend->createGPUDevice || !backend->destroyGPUDevice || !backend->createGPUCommandQueue || - !backend->destroyGPUCommandQueue) { + !backend->destroyGPUCommandQueue || + !backend->canCommandQueuePresent || + !backend->getSwapchainCapabilities) { return PAL_RESULT_INVALID_GPU_BACKEND; } // clang-format on @@ -1529,6 +1898,7 @@ PalResult PAL_CALL palCreateGPUDevice( deviceData->backend = adapterData->backend; deviceData->device = device; + deviceData->adapter = adapter; *outDevice = device; return PAL_RESULT_SUCCESS; @@ -1597,4 +1967,46 @@ void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue) data->used = false; } } +} + +bool PAL_CALL palCanCommandQueuePresent( + PalGPUCommandQueue* queue, + PalGPUWindow* window) +{ + if (s_Graphics.initialized && queue) { + CommandQueueData* data = findCommandQueueData(queue); + if (data) { + return data->backend->canCommandQueuePresent(queue, window); + } + return false; + } + return false; +} + +// ================================================== +// Swapchain +// ================================================== + +PalResult PAL_CALL palQuerySwapchainCapabilities( + PalGPUAdapter* adapter, + PalGPUWindow* window, + PalSwapchainCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!adapter || !window || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + AdapterData* adapterData = findAdapterData(adapter); + if (!adapterData) { + return PAL_RESULT_INVALID_GPU_ADAPTER; + } + + return adapterData->backend->getSwapchainCapabilities( + adapter, + window, + caps); } \ No newline at end of file diff --git a/src/pal_core.c b/src/pal_core.c index 95f91af9..ce8dfe58 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -402,8 +402,14 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_GPU_DEVICE: return "Invalid GPU device"; + case PAL_RESULT_INVALID_GPU_COMMAND_QUEUE: + return "Invalid GPU command queue"; + case PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE: return "Out of GPU command queues"; + + case PAL_RESULT_INVALID_GPU_WINDOW: + return "Invalid GPU window"; } return "Unknown"; } diff --git a/tests/gpu_device_test.c b/tests/gpu_device_test.c index be617127..48121809 100644 --- a/tests/gpu_device_test.c +++ b/tests/gpu_device_test.c @@ -82,19 +82,26 @@ bool gpuDeviceTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - palFree(nullptr, adapters); return false; } - // create a device with the vulkan adapter - PalGPUDevice* device = nullptr; - PalGPUFeatures features = 0; + // check if we support a graphics command queue + const char* msg = "This Adapter (GPU) does not have any graphics queues"; + if (!(caps.features & PAL_GPU_FEATURE_SWAPCHAIN)) { + palLog(nullptr, msg); + return false; + } - // enable swapchain and maybe multi viewport if supported - if (caps.features & PAL_GPU_FEATURE_SWAPCHAIN) { - features = PAL_GPU_FEATURE_SWAPCHAIN; + if (!caps.maxGraphicsQueues) { + palLog(nullptr, msg); + return false; } + // create a device with the vulkan adapter + PalGPUDevice* device = nullptr; + PalGPUFeatures features = PAL_GPU_FEATURE_SWAPCHAIN; + + // enable multi viewport if supported if (caps.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { features |= PAL_GPU_FEATURE_MULTI_VIEWPORT; } @@ -106,24 +113,12 @@ bool gpuDeviceTest() return false; } - // check if we support a graphics command queue - if (!caps.maxGraphicsQueues) { - palLog( - nullptr, - "This Adapter (GPU) does not have any graphics command queues"); - return false; - } - - // create a graphics command queue + PalGPUCommandQueueType queueType = PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS; PalGPUCommandQueue* graphicsQueue = nullptr; - result = palCreateGPUCommandQueue( - device, - PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS, - &graphicsQueue); - + result = palCreateGPUCommandQueue(device, queueType, &graphicsQueue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create graphics command queue: %s", error); + palLog(nullptr, "Failed to create command queue: %s", error); return false; } diff --git a/tests/swapchain_test.c b/tests/swapchain_test.c new file mode 100644 index 00000000..1d0c2790 --- /dev/null +++ b/tests/swapchain_test.c @@ -0,0 +1,292 @@ + + +#include "pal/pal_graphics.h" +#include "pal/pal_video.h" +#include "tests.h" + +bool swapchainTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Swapchain Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + // we need a window. We use PAL video system to create the window + PalResult result = palInitVideo(nullptr, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize video: %s", error); + return false; + } + + PalWindow* window = nullptr; + PalWindowCreateInfo windowCreateInfo = {0}; + windowCreateInfo.height = 480; + windowCreateInfo.width = 640; + windowCreateInfo.show = true; + + // check if we support decorated windows (title bar, close etc) + PalVideoFeatures64 features = palGetVideoFeaturesEx(); + if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + // if we dont support, we need to create a borderless window + // and create the decorations ourselves + windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&windowCreateInfo, &window); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create window: %s", error); + return false; + } + + // initialize the graphics system + result = palInitGraphics(false, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available GPUs from internal and custom backends + Int32 count = 0; + result = palEnumerateGPUAdapters(&count, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + return false; + } + + if (count == 0) { + palLog(nullptr, "No Adapters found"); + return false; + } + palLog(nullptr, "Adapter (GPUs) Count: %d", count); + + // allocate an array of adapters or use a fixed array + // Example: PalGPUAdapter* adapters[12]; + PalGPUAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalGPUAdapter*) * count, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateGPUAdapters(&count, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + return false; + } + + // filter the adapters for Vulkan + PalGPUAdapter* vulkanAdapter = nullptr; + PalGPUAdapterInfo info = {0}; + + for (Int32 i = 0; i < count; i++) { + PalGPUAdapter* adapter = adapters[i]; + result = palGetGPUAdapterInfo(adapter, &info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + palFree(nullptr, adapters); + return false; + } + + // check if its Vulkan + if (info.apiType == PAL_GPU_API_TYPE_VULKAN) { + vulkanAdapter = adapter; + break; + } + } + + palFree(nullptr, adapters); + if (!vulkanAdapter) { + palLog(nullptr, "Failed to find a vulkan adapter"); + return false; + } + + // get capabilities about the vulkan adapter and check if we support + // graphics command queues + PalGPUAdapterCapabilities caps = {0}; + result = palGetGPUAdapterCapabilities(vulkanAdapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // check if we support a graphics command queue + const char* msg = "This Adapter (GPU) does not have any graphics queues"; + if (!(caps.features & PAL_GPU_FEATURE_SWAPCHAIN)) { + palLog(nullptr, msg); + return false; + } + + if (!caps.maxGraphicsQueues) { + palLog(nullptr, msg); + return false; + } + + // create a device and a graphics command queue with the vulkan adapter + PalGPUDevice* device = nullptr; + PalGPUFeatures GPUfeatures = PAL_GPU_FEATURE_SWAPCHAIN; + + result = palCreateGPUDevice(vulkanAdapter, GPUfeatures, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a graphics command queue + PalGPUCommandQueueType queueType = PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS; + PalGPUCommandQueue* graphicsQueue = nullptr; + result = palCreateGPUCommandQueue(device, queueType, &graphicsQueue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command queue: %s", error); + return false; + } + + // create and retrive the native window handles + PalGPUWindow gpuWindow = {0}; + PalWindowHandleInfo windowHandleInfo = {}; + windowHandleInfo = palGetWindowHandleInfo(window); + gpuWindow.display = windowHandleInfo.nativeDisplay; + gpuWindow.window = windowHandleInfo.nativeWindow; + + // check if the command queue supports presentation to your window + bool canPresent = palCanCommandQueuePresent(graphicsQueue, &gpuWindow); + if (!canPresent) { + palLog(nullptr, "Command queue cannot present to provided window"); + // cleanup + return false; + } + + // query swapchain capabilities of the adapter and the window + PalSwapchainCapabilities swapchainCaps = {0}; + result = palQuerySwapchainCapabilities( + vulkanAdapter, + &gpuWindow, + &swapchainCaps); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to query swapchain capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + // log swapchain capabilities + Uint32 bufferLayers = swapchainCaps.maxBufferArrayLayers; + palLog(nullptr, "Swapchain capabilities:"); + palLog(nullptr, " Min buffer count: %d", swapchainCaps.minBufferCount); + palLog(nullptr, " Max buffer count: %d", swapchainCaps.maxBufferCount); + palLog(nullptr, " Max buffer array layers: %d", bufferLayers); + + palLog(nullptr, " Min width: %d", swapchainCaps.minWidth); + palLog(nullptr, " Min height: %d", swapchainCaps.minHeight); + palLog(nullptr, " Max width: %d", swapchainCaps.maxWidth); + palLog(nullptr, " Max height: %d", swapchainCaps.maxHeight); + + palLog(nullptr, " Supported formats:"); + if (swapchainCaps.formats & PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB) { + palLog(nullptr, " BGRA8 SRGB SRGB"); + } + + if (swapchainCaps.formats & PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB) { + palLog(nullptr, " BGRA8 UNORM SRGB"); + } + + if (swapchainCaps.formats & PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10) { + palLog(nullptr, " RGBA16 FLOAT HDR10"); + } + + if (swapchainCaps.formats & PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB) { + palLog(nullptr, " RGBA8 UNORM SRGB"); + } + + palLog(nullptr, " Supported present modes:"); + if (swapchainCaps.presentModes & PAL_PRESENT_MODE_FIFO) { + palLog(nullptr, " FIFO"); + } + + if (swapchainCaps.presentModes & PAL_PRESENT_MODE_IMMEDIATE) { + palLog(nullptr, " Immediate"); + } + + if (swapchainCaps.presentModes & PAL_PRESENT_MODE_MAILBOX) { + palLog(nullptr, " Mailbox"); + } + + palLog(nullptr, " Supported transforms:"); + if (swapchainCaps.transforms & PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE) { + palLog(nullptr, " Landscape"); + } + + if (swapchainCaps.transforms & PAL_SWAPCHAIN_TRANSFORM_PORTRAIT) { + palLog(nullptr, " Portrait"); + } + + if (swapchainCaps.transforms & PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED) { + palLog(nullptr, " Portrait flipped"); + } + + if (swapchainCaps.transforms & PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED) { + palLog(nullptr, " Landscape flipped"); + } + + palLog(nullptr, " Supported sharing modes:"); + if (swapchainCaps.sharingModes & PAL_SWAPCHAIN_SHARING_MODE_EXCLUSIVE) { + palLog(nullptr, " Exclusive"); + } + + if (swapchainCaps.sharingModes & PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT) { + palLog(nullptr, " Concurrent"); + } + + palLog(nullptr, " Supported composite alphas:"); + if (swapchainCaps.compositeAlphas & PAL_COMPOSITE_ALPHA_OPAQUE) { + palLog(nullptr, " Opaque"); + } + + if (swapchainCaps.compositeAlphas & PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED) { + palLog(nullptr, " Pre Multiplied"); + } + + if (swapchainCaps.compositeAlphas & PAL_COMPOSITE_ALPHA_POST_MULTIPLIED) { + palLog(nullptr, " Post Multiplied"); + } + + palLog(nullptr, " Supported usages:"); + if (swapchainCaps.usages & PAL_SWAPCHAIN_USAGE_SAMPLED) { + palLog(nullptr, " Sampled"); + } + + if (swapchainCaps.usages & PAL_SWAPCHAIN_USAGE_TRANSFER_DST) { + palLog(nullptr, " Transfer Dst"); + } + + if (swapchainCaps.usages & PAL_SWAPCHAIN_USAGE_TRANSFER_SRC) { + palLog(nullptr, " Transfer src"); + } + + if (swapchainCaps.usages & PAL_SWAPCHAIN_USAGE_COLOR_ATTACHEMENT) { + palLog(nullptr, " Color attachment"); + } + + // destroy command queue and gpu device + palDestroyGPUCommandQueue(graphicsQueue); + palDestroyGPUDevice(device); + + // destroy window and shutdown video system + palDestroyWindow(window); + palShutdownVideo(); + + // shutdown the graphics system + palShutdownGraphics(); + + return true; +} \ No newline at end of file diff --git a/tests/tests.h b/tests/tests.h index 2a3159ca..f4163d67 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -58,4 +58,7 @@ bool graphicsTest(); bool customGraphicsBackendTest(); bool gpuDeviceTest(); +// graphics and video +bool swapchainTest(); + #endif // _TESTS_H \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index 543c312d..709c2074 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -71,5 +71,11 @@ project "tests" } end + if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then + files { + "swapchain_test.c" + } + end + includedirs { "%{wks.location}/include" } links { "PAL" } \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index b5b4d7ac..78a381b1 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -52,14 +52,18 @@ int main(int argc, char** argv) #if PAL_HAS_OPENGL && PAL_HAS_VIDEO && PAL_HAS_THREAD registerTest("Multi Thread OpenGL Test", multiThreadOpenGlTest); -#endif // +#endif #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + // registerTest("Graphics Test", graphicsTest); // registerTest("Custom Graphics Backend Test", customGraphicsBackendTest); - //registerTest("GPU Device Test", gpuDeviceTest); + // registerTest("GPU Device Test", gpuDeviceTest); #endif // PAL_HAS_GRAPHICS +#if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO + registerTest("Swapchain Test", swapchainTest); +#endif + runTests(); return 0; } \ No newline at end of file From 61cd7a24b0d427d171201250dcadc5f3f7d3f0ee Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 30 Nov 2025 15:18:40 +0000 Subject: [PATCH 018/372] add swapchain creation and deletion --- include/pal/pal_graphics.h | 24 +- src/graphics/pal_graphics_linux.c | 648 +++++++++++++++++++++--------- tests/swapchain_test.c | 46 +++ 3 files changed, 521 insertions(+), 197 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 83f69500..3d15f8be 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -172,14 +172,16 @@ typedef struct { bool clipped; Uint32 width; Uint32 height; - Uint32 imageCount; - Uint32 imageArrayLayerCount; + Uint32 bufferCount; + Uint32 bufferArrayLayerCount; + Uint32 concurrentQueueCount; PalPresentModes presentMode; - PalSwapchainUsages usages; + PalSwapchainUsages usage; PalCompositeAplhas compositeAlpha; PalSwapchainFormats format; PalSwapchainSharingModes sharingMode; PalSwapchainTransforms transform; + PalGPUCommandQueue** concurrentQueue; } PalSwapchainCreateInfo; typedef struct { @@ -222,6 +224,14 @@ typedef struct { PalGPUAdapter* adapter, PalGPUWindow* window, PalSwapchainCapabilities* caps); + + PalResult PAL_CALL (*createSwapchain)( + PalGPUCommandQueue* queue, + PalGPUWindow* window, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + + void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics( @@ -267,6 +277,14 @@ PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( PalGPUWindow* window, PalSwapchainCapabilities* caps); +PAL_API PalResult PAL_CALL palCreateSwapchain( + PalGPUCommandQueue* queue, + PalGPUWindow* window, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + +PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 9333499e..f255a2d0 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -39,16 +39,7 @@ freely, subject to the following restrictions: // Typedefs, enums and structs // ================================================== -// FIXME: make all these dynamic if need be -// but for now its fine -#define MAX_BACKENDS 16 -#define MAX_ADAPTERS 32 -#define MAX_DEVICE 16 -#define MAX_QUEUE_FAMILIES 8 -#define MAX_PHYSICAL_QUEUES 16 -#define MAX_COMMAND_QUEUES 32 -#define MAX_FORMATS 32 -#define MAX_PRESENT_MODES 16 +#define MAX_BACKENDS 32 #if PAL_HAS_VULKAN // VKAPI_PTR expands to nothing on linux @@ -206,6 +197,35 @@ typedef VkResult (*vkGetPhysicalDeviceSurfacePresentModesKHRFn)( uint32_t*, VkPresentModeKHR*); +typedef VkResult (*vkCreateSwapchainKHRFn)( + VkDevice, + const VkSwapchainCreateInfoKHR*, + const VkAllocationCallbacks*, + VkSwapchainKHR*); + +typedef void (*vkDestroySwapchainKHRFn)( + VkDevice, + VkSwapchainKHR, + const VkAllocationCallbacks*); + +typedef VkResult (*vkGetSwapchainImagesKHRFn)( + VkDevice, + VkSwapchainKHR, + uint32_t*, + VkImage*); + +typedef VkResult (*vkAcquireNextImageKHRFn)( + VkDevice, + VkSwapchainKHR, + uint64_t, + VkSemaphore, + VkFence, + uint32_t*); + +typedef VkResult (*vkQueuePresentKHRFn)( + VkQueue, + const VkPresentInfoKHR*); + typedef struct { bool hasDebug; bool versionFallback; @@ -262,17 +282,29 @@ typedef struct { VkQueueFlags usedUsages; } PhysicalQueue; +typedef struct { + Int32 queueCount; + VkPhysicalDevice phyDevice; + VkDevice handle; + PhysicalQueue* phyQueues; + vkCreateSwapchainKHRFn createSwapchain; + vkDestroySwapchainKHRFn destroySwapchain; + vkGetSwapchainImagesKHRFn getSwapchainImages; + vkAcquireNextImageKHRFn acquireNextImage; + vkQueuePresentKHRFn queuePresent; +} Device; + typedef struct { VkQueueFlags usage; + Device* device; PhysicalQueue* phyQueue; -} VkCommandQueue; +} CommandQueue; typedef struct { - Int32 queueCount; - VkPhysicalDevice phyDevice; - VkDevice handle; - PhysicalQueue queues[MAX_PHYSICAL_QUEUES]; -} VkGPUDevice; + Device* device; + VkSurfaceKHR surface; + VkSwapchainKHR handle; +} Swapchain; static Vulkan s_Vk = {0}; @@ -280,39 +312,23 @@ static Vulkan s_Vk = {0}; typedef struct { bool used; + void* handle; const PalGPUBackend* backend; - PalGPUAdapter* adapter; -} AdapterData; - -typedef struct { - bool used; - PalGPUAdapter* adapter; - PalGPUDevice* device; - const PalGPUBackend* backend; -} DeviceData; - -typedef struct { - bool used; - PalGPUDevice* device; - PalGPUCommandQueue* queue; - const PalGPUBackend* backend; -} CommandQueueData; +} HandleData; typedef struct { + Int32 count; + Int32 startIndex; const PalGPUBackend* base; - Uint16 startIndex; - Uint16 count; -} AttachBackend; +} BackendData; typedef struct { bool initialized; Int32 backendCount; - Int32 totalAdapterCount; + Int32 maxHandleData; const PalAllocator* allocator; - AdapterData adapterData[MAX_ADAPTERS]; - DeviceData deviceData[MAX_DEVICE]; - CommandQueueData commandQueueData[MAX_COMMAND_QUEUES]; - AttachBackend backends[MAX_BACKENDS]; + HandleData* handleData; + BackendData backends[MAX_BACKENDS]; } GraphicsLinux; static GraphicsLinux s_Graphics = {0}; @@ -321,67 +337,43 @@ static GraphicsLinux s_Graphics = {0}; // Internal API // ================================================== -static AdapterData* getFreeAdapterData() +// FIXME: might be replaced with hashmap for performance +static HandleData* getFreeHandleData() { - for (int i = 0; i < MAX_ADAPTERS; ++i) { - if (!s_Graphics.adapterData[i].used) { - s_Graphics.adapterData[i].used = true; - return &s_Graphics.adapterData[i]; + for (int i = 0; i < s_Graphics.maxHandleData; ++i) { + if (!s_Graphics.handleData[i].used) { + s_Graphics.handleData[i].used = true; + return &s_Graphics.handleData[i]; } } - return nullptr; -} -static AdapterData* findAdapterData(PalGPUAdapter* adapter) -{ - for (int i = 0; i < MAX_ADAPTERS; ++i) { - if (s_Graphics.adapterData[i].used && - s_Graphics.adapterData[i].adapter == adapter) { - return &s_Graphics.adapterData[i]; - } - } - return nullptr; -} + // resize the data array + HandleData* data = nullptr; + int count = s_Graphics.maxHandleData * 2; // double the size + int freeIndex = s_Graphics.maxHandleData + 1; + data = palAllocate(s_Graphics.allocator, sizeof(HandleData) * count, 0); + if (data) { + memcpy( + data, + s_Graphics.handleData, + s_Graphics.maxHandleData * sizeof(HandleData)); -static DeviceData* getFreeDeviceData() -{ - for (int i = 0; i < MAX_DEVICE; ++i) { - if (!s_Graphics.deviceData[i].used) { - s_Graphics.deviceData[i].used = true; - return &s_Graphics.deviceData[i]; - } - } - return nullptr; -} + palFree(s_Graphics.allocator, s_Graphics.handleData); + s_Graphics.handleData = data; + s_Graphics.maxHandleData = count; -static DeviceData* findDeviceData(PalGPUDevice* device) -{ - for (int i = 0; i < MAX_DEVICE; ++i) { - if (s_Graphics.deviceData[i].used && - s_Graphics.deviceData[i].device == device) { - return &s_Graphics.deviceData[i]; - } + s_Graphics.handleData[freeIndex].used = true; + return &s_Graphics.handleData[freeIndex]; } return nullptr; } -static CommandQueueData* getFreeCommandQueueData() -{ - for (int i = 0; i < MAX_COMMAND_QUEUES; ++i) { - if (!s_Graphics.commandQueueData[i].used) { - s_Graphics.commandQueueData[i].used = true; - return &s_Graphics.commandQueueData[i]; - } - } - return nullptr; -} - -static CommandQueueData* findCommandQueueData(PalGPUCommandQueue* queue) +static HandleData* findHandleData(void* handle) { - for (int i = 0; i < MAX_COMMAND_QUEUES; ++i) { - if (s_Graphics.commandQueueData[i].used && - s_Graphics.commandQueueData[i].queue == queue) { - return &s_Graphics.commandQueueData[i]; + for (int i = 0; i < s_Graphics.maxHandleData; ++i) { + if (s_Graphics.handleData[i].used && + s_Graphics.handleData[i].handle == handle) { + return &s_Graphics.handleData[i]; } } return nullptr; @@ -595,7 +587,6 @@ static PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.getDeviceProcAddr = (vkGetDeviceProcAddrFn)dlsym( s_Vk.handle, "vkGetDeviceProcAddr"); - // clang-format on // get version @@ -817,14 +808,12 @@ static PalResult vkInitGraphics(bool enableDebugLayer) static void vkShutdownGraphics() { - if (s_Vk.instance) { - s_Vk.destroyInstance(s_Vk.instance, &s_Vk.allocator); - dlclose(s_Vk.handle); - if (s_Vk.libWayland) { - dlclose(s_Vk.libWayland); - } - memset(&s_Vk, 0, sizeof(s_Vk)); + s_Vk.destroyInstance(s_Vk.instance, &s_Vk.allocator); + dlclose(s_Vk.handle); + if (s_Vk.libWayland) { + dlclose(s_Vk.libWayland); } + memset(&s_Vk, 0, sizeof(s_Vk)); } static PalResult vkEnumerateAdapters( @@ -941,7 +930,12 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( &count, nullptr); - VkQueueFamilyProperties queueProps[MAX_QUEUE_FAMILIES]; + VkQueueFamilyProperties* queueProps = nullptr; + queueProps = palAllocate( + s_Graphics.allocator, + sizeof(VkQueueFamilyProperties) * count, + 0); + s_Vk.getPhysicalDeviceQueueFamilyProperties( phyDevice, &count, @@ -965,6 +959,8 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( } } + palFree(s_Graphics.allocator, queueProps); + // get supported extensions Uint32 extensionCount = 0; ret = s_Vk.enumerateDeviceExtensionProperties( @@ -1185,41 +1181,58 @@ static PalResult PAL_CALL vkCreateGPUDevice( PalGPUAdapter* adapter, PalGPUFeatures features, PalGPUDevice** outDevice) -{ +{ + float priority = 1.0f; + Uint32 count = 0; VkResult ret = VK_SUCCESS; - VkDevice device = nullptr; + Device* device = nullptr; VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; - Uint32 count = 0; + VkQueueFamilyProperties* queueProps = nullptr; + VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; s_Vk.getPhysicalDeviceQueueFamilyProperties( phyDevice, &count, nullptr); - VkQueueFamilyProperties queueProps[MAX_QUEUE_FAMILIES]; + queueProps = palAllocate( + s_Graphics.allocator, + sizeof(VkQueueFamilyProperties) * count, + 0); + + queueCreateInfos = palAllocate( + s_Graphics.allocator, + sizeof(VkDeviceQueueCreateInfo) * count, + 0); + + device = palAllocate(s_Graphics.allocator, sizeof(Device), 0); + if (!queueProps || !queueCreateInfos || !device) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + device->queueCount = count; + device->phyDevice = phyDevice; + + device->phyQueues = palAllocate( + s_Graphics.allocator, + sizeof(PhysicalQueue) * count, + 0); + + if (!device->phyQueues) { + return PAL_RESULT_OUT_OF_MEMORY; + } + s_Vk.getPhysicalDeviceQueueFamilyProperties( phyDevice, &count, queueProps); - - Int32 queueFamilyCount = 0; - QueueFamilyData queueFamilyData[MAX_QUEUE_FAMILIES]; + for (int i = 0; i < count; i++) { - VkQueueFamilyProperties* prop = &queueProps[i]; - QueueFamilyData* data = &queueFamilyData[queueFamilyCount++]; - data->count = prop->queueCount; - data->flags = prop->queueFlags; - data->index = i; - } - - float priority = 1.0f; - VkDeviceQueueCreateInfo queueCreateInfos[MAX_QUEUE_FAMILIES]; - for (int i = 0; i < queueFamilyCount; i++) { queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfos[i].pNext = nullptr; queueCreateInfos[i].pQueuePriorities = &priority; - queueCreateInfos[i].queueFamilyIndex = queueFamilyData[i].index; - queueCreateInfos[i].queueCount = queueFamilyData[i].count; + queueCreateInfos[i].queueFamilyIndex = i; + queueCreateInfos[i].queueCount = queueProps[i].queueCount; queueCreateInfos[i].flags = 0; } @@ -1391,51 +1404,69 @@ static PalResult PAL_CALL vkCreateGPUDevice( createInfo.enabledExtensionCount = extCount; createInfo.ppEnabledExtensionNames = extensions; createInfo.pQueueCreateInfos = queueCreateInfos; - createInfo.queueCreateInfoCount = queueFamilyCount; + createInfo.queueCreateInfoCount = count; createInfo.pNext = start; ret = s_Vk.createDevice( phyDevice, &createInfo, &s_Vk.allocator, - &device); + &device->handle); if (ret != VK_SUCCESS) { + palFree(s_Graphics.allocator, queueProps); + palFree(s_Graphics.allocator, queueCreateInfos); + palFree(s_Graphics.allocator, device->phyQueues); + palFree(s_Graphics.allocator, device); return vkResultToPal(ret); } - VkGPUDevice* gpuDevice = nullptr; - gpuDevice = palAllocate(s_Graphics.allocator, sizeof(VkGPUDevice), 0); - if (!gpuDevice) { - s_Vk.destroyDevice(device, &s_Vk.allocator); - return PAL_RESULT_OUT_OF_MEMORY; - } - memset(gpuDevice, 0, sizeof(VkGPUDevice)); - // get queues - for (int i = 0; i < queueFamilyCount; i++) { - QueueFamilyData* data = &queueFamilyData[i]; - for (int j = 0; j < data->count; j++) { - PhysicalQueue* queue = &gpuDevice->queues[gpuDevice->queueCount++]; - s_Vk.getDeviceQueue(device, data->index, j, &queue->handle); - queue->usages = data->flags; + for (int i = 0; i < count; i++) { + VkQueueFamilyProperties* data = &queueProps[i]; + for (int j = 0; j < data->queueCount; j++) { + PhysicalQueue* queue = &device->phyQueues[i]; + s_Vk.getDeviceQueue(device->handle, i, j, &queue->handle); + queue->usages = data->queueFlags; queue->usedUsages = 0; - queue->familyIndex = data->index; + queue->familyIndex = i; queue->phyDevice = phyDevice; } } - gpuDevice->handle = device; - gpuDevice->phyDevice = phyDevice; + // load procs + device->acquireNextImage = (vkAcquireNextImageKHRFn)s_Vk.getDeviceProcAddr( + device->handle, + "vkAcquireNextImageKHR"); + + device->createSwapchain = (vkCreateSwapchainKHRFn)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateSwapchainKHR"); + + device->destroySwapchain = (vkDestroySwapchainKHRFn)s_Vk.getDeviceProcAddr( + device->handle, + "vkDestroySwapchainKHR"); + + device->getSwapchainImages = (vkGetSwapchainImagesKHRFn)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetSwapchainImagesKHR"); - *outDevice = (PalGPUDevice*)gpuDevice; + device->queuePresent = (vkQueuePresentKHRFn)s_Vk.getDeviceProcAddr( + device->handle, + "vkQueuePresentKHR"); + + palFree(s_Graphics.allocator, queueProps); + palFree(s_Graphics.allocator, queueCreateInfos); + + *outDevice = (PalGPUDevice*)device; return PAL_RESULT_SUCCESS; } static void PAL_CALL vkDestroyGPUDevice(PalGPUDevice* device) { - VkGPUDevice* gpuDevice = (VkGPUDevice*)device; + Device* gpuDevice = (Device*)device; s_Vk.destroyDevice(gpuDevice->handle, &s_Vk.allocator); + palFree(s_Graphics.allocator, gpuDevice->phyQueues); palFree(s_Graphics.allocator, gpuDevice); } @@ -1444,10 +1475,9 @@ static PalResult PAL_CALL vkCreateGPUCommandQueue( PalGPUCommandQueueType type, PalGPUCommandQueue** outQueue) { - VkCommandQueue* commandQueue = nullptr; VkQueueFlags queueFlag = 0; - - VkGPUDevice* gpuDevice = (VkGPUDevice*)device; + Device* gpuDevice = (Device*)device; + CommandQueue* commandQueue = nullptr; if (!gpuDevice->handle) { return PAL_RESULT_INVALID_GPU_DEVICE; } @@ -1473,31 +1503,32 @@ static PalResult PAL_CALL vkCreateGPUCommandQueue( } } - PhysicalQueue* physicalQueue = nullptr; + PhysicalQueue* phyQueue = nullptr; for (int i = 0; i < gpuDevice->queueCount; i++) { - PhysicalQueue* phyQueue = &gpuDevice->queues[i]; + PhysicalQueue* queue = &gpuDevice->phyQueues[i]; // check if the physical queue supports the requested operation // and if its not already used - if (phyQueue->usages & queueFlag && - phyQueue->usedUsages != queueFlag) { - phyQueue->usedUsages |= queueFlag; - physicalQueue = phyQueue; + if (queue->usages & queueFlag && + queue->usedUsages != queueFlag) { + queue->usedUsages |= queueFlag; + phyQueue = queue; break; } } - if (physicalQueue) { + if (phyQueue) { commandQueue = palAllocate( s_Graphics.allocator, - sizeof(VkCommandQueue), + sizeof(CommandQueue), 0); if (!commandQueue) { return PAL_RESULT_OUT_OF_MEMORY; } - commandQueue->phyQueue = physicalQueue; + commandQueue->phyQueue = phyQueue; commandQueue->usage = queueFlag; + commandQueue->device = gpuDevice; *outQueue = (PalGPUCommandQueue*)commandQueue; return PAL_RESULT_SUCCESS; @@ -1508,18 +1539,18 @@ static PalResult PAL_CALL vkCreateGPUCommandQueue( static void PAL_CALL vkDestroyGPUCommandQueue(PalGPUCommandQueue* queue) { - VkCommandQueue* commandQueue = (VkCommandQueue*)queue; + CommandQueue* commandQueue = (CommandQueue*)queue; PhysicalQueue* phyQueue = commandQueue->phyQueue; phyQueue->usedUsages &= ~commandQueue->usage; palFree(s_Graphics.allocator, commandQueue); } -bool PAL_CALL vkCanCommandQueuePresent( +static bool PAL_CALL vkCanCommandQueuePresent( PalGPUCommandQueue* queue, PalGPUWindow* window) { bool onWayland = vkOnWayland(window->display); - VkCommandQueue* commandQueue = (VkCommandQueue*)queue; + CommandQueue* commandQueue = (CommandQueue*)queue; PhysicalQueue* phyQueue = commandQueue->phyQueue; if (!s_Vk.checkWaylandPresentSupport( @@ -1538,14 +1569,39 @@ static PalResult PAL_CALL vkQuerySwapchainCapabilities( PalGPUWindow* window, PalSwapchainCapabilities* caps) { + Int32 formatCount = 0; + Int32 modeCount = 0; VkSurfaceKHR surface = nullptr; VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + VkPresentModeKHR* modes = nullptr; + VkSurfaceFormatKHR* formats = nullptr; bool ret = vkCreateSurface(window, &surface); if (!ret) { return PAL_RESULT_INVALID_GPU_WINDOW; } + s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, nullptr); + s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, nullptr); + + modes = palAllocate( + s_Graphics.allocator, + sizeof(VkPresentModeKHR) * modeCount, + 0); + + formats = palAllocate( + s_Graphics.allocator, + sizeof(VkSurfaceFormatKHR) * formatCount, + 0); + + if (!modes || !formats) { + s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); + return PAL_RESULT_OUT_OF_MEMORY; + } + + s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, modes); + s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, formats); + VkSurfaceCapabilitiesKHR surfaceCaps; s_Vk.getSurfaceCapabilities(phyDevice, surface, &surfaceCaps); caps->minWidth = surfaceCaps.minImageExtent.width; @@ -1615,30 +1671,18 @@ static PalResult PAL_CALL vkQuerySwapchainCapabilities( // present modes caps->presentModes = PAL_PRESENT_MODE_FIFO; - Int32 count = 0; - VkPresentModeKHR modes[MAX_PRESENT_MODES] = {0}; - s_Vk.getSurfacePresentModes(phyDevice, surface, &count, nullptr); - - if (count) { - s_Vk.getSurfacePresentModes(phyDevice, surface, &count, modes); - for (int i = 0; i < count; i++) { - if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { - caps->presentModes |= PAL_PRESENT_MODE_IMMEDIATE; - } + for (int i = 0; i < modeCount; i++) { + if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { + caps->presentModes |= PAL_PRESENT_MODE_IMMEDIATE; + } - if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { - caps->presentModes |= PAL_PRESENT_MODE_MAILBOX; - } + if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { + caps->presentModes |= PAL_PRESENT_MODE_MAILBOX; } } // get format and colorspace - count = 0; - VkSurfaceFormatKHR formats[MAX_FORMATS] = {0}; - s_Vk.getSurfaceFormats(phyDevice, surface, &count, nullptr); - - s_Vk.getSurfaceFormats(phyDevice, surface, &count, formats); - for (int i = 0; i < count; i++) { + for (int i = 0; i < formatCount; i++) { VkSurfaceFormatKHR* fmt = &formats[i]; if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { // find its supported colorspace @@ -1666,10 +1710,164 @@ static PalResult PAL_CALL vkQuerySwapchainCapabilities( } } + palFree(s_Graphics.allocator, formats); + palFree(s_Graphics.allocator, modes); s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); + + return PAL_RESULT_SUCCESS; +} + +static PalResult PAL_CALL vkCreateSwapchain( + PalGPUCommandQueue* queue, + PalGPUWindow* window, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain) +{ + Swapchain* swapchain = nullptr; + CommandQueue* commandQueue = (CommandQueue*)queue; + PhysicalQueue* phyQueue = commandQueue->phyQueue; + + // check if we enabled swapchain feature + if (!commandQueue->device->createSwapchain) { + return PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED; + } + + swapchain = palAllocate(s_Graphics.allocator, sizeof(Swapchain), 0); + if (!swapchain) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + swapchain->device = commandQueue->device; + bool ret = vkCreateSurface(window, &swapchain->surface); + if (!ret) { + return PAL_RESULT_INVALID_GPU_WINDOW; + } + + VkSwapchainCreateInfoKHR createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = swapchain->surface; + createInfo.imageArrayLayers = info->bufferArrayLayerCount; + createInfo.imageExtent.width = info->width; + createInfo.imageExtent.height = info->height; + createInfo.minImageCount = info->bufferCount; + if (info->clipped) { + createInfo.clipped = VK_TRUE; + } + + // sharing mode + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + if (info->sharingMode == PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT) { + createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + // set up concurrrent queue families + Uint32 count = 0; + Uint32 familyQueus[32]; // should be more than enough + familyQueus[count++] = phyQueue->familyIndex; + + for (int i = 0; i < info->concurrentQueueCount; i++) { + CommandQueue* tmp = (CommandQueue*)info->concurrentQueue[i]; + if (tmp->phyQueue != phyQueue) { + // different queue families. Add index + familyQueus[count++] = tmp->phyQueue->familyIndex; + } + } + + createInfo.queueFamilyIndexCount = count; + createInfo.pQueueFamilyIndices = familyQueus; + } + + // present modes + createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; + if (info->presentMode == PAL_PRESENT_MODE_IMMEDIATE) { + createInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + + } else if (info->presentMode == PAL_PRESENT_MODE_MAILBOX) { + createInfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR; + } + + // usage + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + if (info->usage == PAL_SWAPCHAIN_USAGE_TRANSFER_SRC) { + createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + + } else if (info->usage == PAL_SWAPCHAIN_USAGE_TRANSFER_DST) { + createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + } else if (info->usage == PAL_SWAPCHAIN_USAGE_SAMPLED) { + createInfo.imageUsage = VK_IMAGE_USAGE_SAMPLED_BIT; + } + + // composite alpha + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_POST_MULTIPLIED) { + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; + + } else if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED) { + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; + } + + // transform + createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + if (info->transform == PAL_SWAPCHAIN_TRANSFORM_PORTRAIT) { + createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; + + } else if (info->transform == PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED) { + createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; + + } else if (info->transform == PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED) { + createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; + } + + // format and colorspace + createInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; + createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + + if (info->format == PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB) { + createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; + createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + + } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB) { + createInfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; + createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + + } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10) { + createInfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; + createInfo.imageColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; + } + + // create swapchain + VkResult result = swapchain->device->createSwapchain( + swapchain->device->handle, + &createInfo, + &s_Vk.allocator, + &swapchain->handle); + + if (result != VK_SUCCESS) { + s_Vk.destroySurface( + s_Vk.instance, + swapchain->surface, + &s_Vk.allocator); + + palFree(s_Graphics.allocator, swapchain); + return vkResultToPal(result); + } + + *outSwapchain = (PalSwapchain*)swapchain; return PAL_RESULT_SUCCESS; } +static void PAL_CALL vkDestroySwapchain(PalSwapchain* swapchain) +{ + Swapchain* _swapchain = (Swapchain*)swapchain; + _swapchain->device->destroySwapchain( + _swapchain->device->handle, + _swapchain->handle, + &s_Vk.allocator + ); + + s_Vk.destroySurface(s_Vk.instance, _swapchain->surface, &s_Vk.allocator); + palFree(s_Graphics.allocator, _swapchain); +} + static PalGPUBackend s_VkBackend = { .enumerateGPUAdapters = vkEnumerateAdapters, .getGPUAdapterInfo = vkGetAdapterInfo, @@ -1679,7 +1877,9 @@ static PalGPUBackend s_VkBackend = { .createGPUCommandQueue = vkCreateGPUCommandQueue, .destroyGPUCommandQueue = vkDestroyGPUCommandQueue, .canCommandQueuePresent = vkCanCommandQueuePresent, - .getSwapchainCapabilities = vkQuerySwapchainCapabilities + .getSwapchainCapabilities = vkQuerySwapchainCapabilities, + .createSwapchain = vkCreateSwapchain, + .destroySwapchain = vkDestroySwapchain }; #endif // PAL_HAS_VULKAN @@ -1701,13 +1901,23 @@ PalResult PAL_CALL palInitGraphics( } s_Graphics.allocator = allocator; + s_Graphics.maxHandleData = 16; + s_Graphics.handleData = palAllocate( + s_Graphics.allocator, + sizeof(HandleData) * s_Graphics.maxHandleData, + 0); + + if (!s_Graphics.handleData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + #if PAL_HAS_VULKAN PalResult ret = vkInitGraphics(enableDebugLayer); if (ret != PAL_RESULT_SUCCESS) { return ret; } - AttachBackend* backend = &s_Graphics.backends[s_Graphics.backendCount++]; + BackendData* backend = &s_Graphics.backends[s_Graphics.backendCount++]; backend->base = &s_VkBackend; backend->count = 0; backend->startIndex = 0; @@ -1727,6 +1937,7 @@ void PAL_CALL palShutdownGraphics() vkShutdownGraphics(); #endif // PAL_HAS_VULKAN + palFree(s_Graphics.allocator, s_Graphics.handleData); memset(&s_Graphics, 0, sizeof(s_Graphics)); s_Graphics.initialized = false; } @@ -1758,16 +1969,16 @@ PalResult PAL_CALL palEnumerateGPUAdapters( int _count = outAdapters ? *count : 0; for (int i = 0; i < s_Graphics.backendCount; i++) { - AttachBackend* backend = &s_Graphics.backends[i]; + BackendData* backend = &s_Graphics.backends[i]; if (outAdapters) { // offset into the array so all backends write at the correct index PalGPUAdapter** adapters = &outAdapters[backend->startIndex]; result = backend->base->enumerateGPUAdapters(&_count, adapters); for (int i = 0; i < backend->count; i++) { - AdapterData* data = getFreeAdapterData(); - data->adapter = adapters[i]; + HandleData* data = getFreeHandleData(); data->backend = backend->base; + data->handle = adapters[i]; } } else { @@ -1803,7 +2014,7 @@ PalResult PAL_CALL palGetGPUAdapterInfo( return PAL_RESULT_NULL_POINTER; } - AdapterData* data = findAdapterData(adapter); + HandleData* data = findHandleData(adapter); if (data) { return data->backend->getGPUAdapterInfo(adapter, info); } @@ -1823,7 +2034,7 @@ PalResult PAL_CALL palGetGPUAdapterCapabilities( return PAL_RESULT_NULL_POINTER; } - AdapterData* data = findAdapterData(adapter); + HandleData* data = findHandleData(adapter); if (data) { return data->backend->getGPUAdapterCapabilities(adapter, caps); } @@ -1847,12 +2058,14 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) !backend->createGPUCommandQueue || !backend->destroyGPUCommandQueue || !backend->canCommandQueuePresent || + !backend->createSwapchain || + !backend->destroySwapchain || !backend->getSwapchainCapabilities) { return PAL_RESULT_INVALID_GPU_BACKEND; } // clang-format on - AttachBackend* attached = &s_Graphics.backends[s_Graphics.backendCount++]; + BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; attached->base = backend; attached->startIndex = 0; attached->count = 0; @@ -1878,7 +2091,7 @@ PalResult PAL_CALL palCreateGPUDevice( } // check if the adapter is from PAL (custom or internal backend) - AdapterData* adapterData = findAdapterData(adapter); + HandleData* adapterData = findHandleData(adapter); if (!adapterData) { return PAL_RESULT_INVALID_GPU_ADAPTER; } @@ -1891,14 +2104,13 @@ PalResult PAL_CALL palCreateGPUDevice( } // create a slot for the created device - DeviceData* deviceData = getFreeDeviceData(); + HandleData* deviceData = getFreeHandleData(); if (!deviceData) { return PAL_RESULT_OUT_OF_MEMORY; } deviceData->backend = adapterData->backend; - deviceData->device = device; - deviceData->adapter = adapter; + deviceData->handle = device; *outDevice = device; return PAL_RESULT_SUCCESS; @@ -1907,7 +2119,7 @@ PalResult PAL_CALL palCreateGPUDevice( void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device) { if (s_Graphics.initialized && device) { - DeviceData* data = findDeviceData(device); + HandleData* data = findHandleData(device); if (data) { data->backend->destroyGPUDevice(device); data->used = false; @@ -1928,7 +2140,7 @@ PalResult PAL_CALL palCreateGPUCommandQueue( return PAL_RESULT_NULL_POINTER; } - DeviceData* data = findDeviceData(device); + HandleData* data = findHandleData(device); if (!data) { return PAL_RESULT_INVALID_GPU_DEVICE; } @@ -1944,15 +2156,14 @@ PalResult PAL_CALL palCreateGPUCommandQueue( return ret; } - // create a slot for the created device - CommandQueueData* queueData = getFreeCommandQueueData(); + // create a slot for the created command queue + HandleData* queueData = getFreeHandleData(); if (!queueData) { return PAL_RESULT_OUT_OF_MEMORY; } queueData->backend = data->backend; - queueData->queue = queue; - queueData->device = device; + queueData->handle = queue; *outQueue = queue; return PAL_RESULT_SUCCESS; @@ -1961,7 +2172,7 @@ PalResult PAL_CALL palCreateGPUCommandQueue( void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue) { if (s_Graphics.initialized && queue) { - CommandQueueData* data = findCommandQueueData(queue); + HandleData* data = findHandleData(queue); if (data) { data->backend->destroyGPUCommandQueue(queue); data->used = false; @@ -1974,7 +2185,7 @@ bool PAL_CALL palCanCommandQueuePresent( PalGPUWindow* window) { if (s_Graphics.initialized && queue) { - CommandQueueData* data = findCommandQueueData(queue); + HandleData* data = findHandleData(queue); if (data) { return data->backend->canCommandQueuePresent(queue, window); } @@ -2000,7 +2211,7 @@ PalResult PAL_CALL palQuerySwapchainCapabilities( return PAL_RESULT_NULL_POINTER; } - AdapterData* adapterData = findAdapterData(adapter); + HandleData* adapterData = findHandleData(adapter); if (!adapterData) { return PAL_RESULT_INVALID_GPU_ADAPTER; } @@ -2009,4 +2220,53 @@ PalResult PAL_CALL palQuerySwapchainCapabilities( adapter, window, caps); +} + +PalResult PAL_CALL palCreateSwapchain( + PalGPUCommandQueue* queue, + PalGPUWindow* window, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!queue || !window || !info || !outSwapchain) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* queueData = findHandleData(queue); + if (!queueData) { + return PAL_RESULT_INVALID_GPU_COMMAND_QUEUE; + } + + PalResult ret; + PalSwapchain* swapchain = nullptr; + ret = queueData->backend->createSwapchain(queue, window, info, &swapchain); + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + // create a slot for the created swapchain + HandleData* swapchainData = getFreeHandleData(); + if (!swapchainData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + swapchainData->backend = queueData->backend; + swapchainData->handle = swapchain; + + *outSwapchain = swapchain; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) +{ + if (s_Graphics.initialized && swapchain) { + HandleData* data = findHandleData(swapchain); + if (data) { + data->backend->destroySwapchain(swapchain); + data->used = false; + } + } } \ No newline at end of file diff --git a/tests/swapchain_test.c b/tests/swapchain_test.c index 1d0c2790..47bf51ed 100644 --- a/tests/swapchain_test.c +++ b/tests/swapchain_test.c @@ -277,6 +277,52 @@ bool swapchainTest() palLog(nullptr, " Color attachment"); } + // create a swapchain + PalSwapchain* swapchain = nullptr; + PalSwapchainCreateInfo swapchainCreateInfo = {0}; + swapchainCreateInfo.bufferArrayLayerCount = 1; // works on all systems + + // check max count to choose buffers but for this example + //we just set it to the minimal supported + swapchainCreateInfo.bufferCount = swapchainCaps.minBufferCount; + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + + // set size + swapchainCreateInfo.width = 640; + swapchainCreateInfo.height = 480; + if (640 > swapchainCaps.maxWidth) { + // we set it to the minimal to mak it work across systems + swapchainCreateInfo.width = swapchainCaps.minWidth; + } + + if (480 > swapchainCaps.maxHeight) { + // we set it to the minimal to mak it work across systems + swapchainCreateInfo.height = swapchainCaps.minHeight; + } + + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + swapchainCreateInfo.transform = PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE; + swapchainCreateInfo.usage = PAL_SWAPCHAIN_USAGE_COLOR_ATTACHEMENT; + swapchainCreateInfo.sharingMode = PAL_SWAPCHAIN_SHARING_MODE_EXCLUSIVE; + + result = palCreateSwapchain( + graphicsQueue, + &gpuWindow, + &swapchainCreateInfo, + &swapchain); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create swapchain: %s", error); + palFree(nullptr, adapters); + return false; + } + + // destroy the swapchain + palDestroySwapchain(swapchain); + // destroy command queue and gpu device palDestroyGPUCommandQueue(graphicsQueue); palDestroyGPUDevice(device); From 2e37a66e0ffd6164e0fc8798e8e150cb87833688 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 30 Nov 2025 23:06:59 +0000 Subject: [PATCH 019/372] add gpu buffer and render target view --- include/pal/pal_core.h | 4 +- include/pal/pal_graphics.h | 26 ++++ src/graphics/pal_graphics_linux.c | 220 ++++++++++++++++++++++++++++-- src/pal_core.c | 6 + tests/swapchain_test.c | 28 +++- 5 files changed, 272 insertions(+), 12 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index fcbc25e3..766dcd31 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -255,7 +255,9 @@ typedef enum { PAL_RESULT_INVALID_GPU_DEVICE, PAL_RESULT_INVALID_GPU_COMMAND_QUEUE, PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE, - PAL_RESULT_INVALID_GPU_WINDOW + PAL_RESULT_INVALID_GPU_WINDOW, + PAL_RESULT_INVALID_SWAPCHAIN, + PAL_RESULT_INVALID_GPU_BUFFER, } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 3d15f8be..ddf71815 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -41,6 +41,8 @@ typedef struct PalGPUAdapter PalGPUAdapter; typedef struct PalGPUDevice PalGPUDevice; typedef struct PalGPUCommandQueue PalGPUCommandQueue; typedef struct PalSwapchain PalSwapchain; +typedef struct PalGPUBuffer PalGPUBuffer; +typedef struct PalRenderTargetView PalRenderTargetView; typedef enum { PAL_GPU_TYPE_UNKNOWN, @@ -232,6 +234,18 @@ typedef struct { PalSwapchain** outSwapchain); void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); + + PalResult PAL_CALL (*getSwapchainBuffers)( + PalSwapchain* swapchain, + Int32* count, + PalGPUBuffer** outBuffers); + + PalResult PAL_CALL (*createRenderTargetView)( + PalSwapchain* swapchain, + PalGPUBuffer* buffer, + PalRenderTargetView** outRtv); + + void PAL_CALL (*destroyRenderTargetView)(PalRenderTargetView* rtv); } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics( @@ -285,6 +299,18 @@ PAL_API PalResult PAL_CALL palCreateSwapchain( PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); +PAL_API PalResult PAL_CALL palGetSwapchainBuffers( + PalSwapchain* swapchain, + Int32* count, + PalGPUBuffer** outBuffers); + +PAL_API PalResult PAL_CALL palCreateRenderTargetView( + PalSwapchain* swapchain, + PalGPUBuffer* buffer, + PalRenderTargetView** outRtv); + +PAL_API void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index f255a2d0..8b55300d 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -226,6 +226,17 @@ typedef VkResult (*vkQueuePresentKHRFn)( VkQueue, const VkPresentInfoKHR*); +typedef VkResult (*vkCreateImageViewFn)( + VkDevice, + const VkImageViewCreateInfo*, + const VkAllocationCallbacks*, + VkImageView*); + +typedef void (*vkDestroyImageViewFn)( + VkDevice, + VkImageView, + const VkAllocationCallbacks*); + typedef struct { bool hasDebug; bool versionFallback; @@ -250,6 +261,8 @@ typedef struct { vkGetPhysicalDeviceFeatures2Fn getPhysicalDeviceFeatures2; vkGetPhysicalDeviceFeatures2KHRFn getPhysicalDeviceFeatures2KHR; vkGetInstanceProcAddrFn getInstanceProcAddr; + vkCreateImageViewFn createImageView; + vkDestroyImageViewFn destroyImageView; vkCreateDeviceFn createDevice; vkDestroyDeviceFn destroyDevice; @@ -268,12 +281,6 @@ typedef struct { VkAllocationCallbacks allocator; } Vulkan; -typedef struct { - Int32 count; - Int32 index; - VkQueueFlags flags; -} QueueFamilyData; - typedef struct { Int32 familyIndex; VkPhysicalDevice phyDevice; @@ -301,11 +308,17 @@ typedef struct { } CommandQueue; typedef struct { + VkFormat format; Device* device; VkSurfaceKHR surface; VkSwapchainKHR handle; } Swapchain; +typedef struct { + Device* device; + VkImageView handle; +} RenderTargetView; + static Vulkan s_Vk = {0}; #endif // PAL_HAS_VULKAN @@ -572,6 +585,14 @@ static PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.handle, "vkGetInstanceProcAddr"); + s_Vk.createImageView = (vkCreateImageViewFn)dlsym( + s_Vk.handle, + "vkCreateImageView"); + + s_Vk.destroyImageView = (vkDestroyImageViewFn)dlsym( + s_Vk.handle, + "vkDestroyImageView"); + s_Vk.createDevice = (vkCreateDeviceFn)dlsym( s_Vk.handle, "vkCreateDevice"); @@ -1820,18 +1841,22 @@ static PalResult PAL_CALL vkCreateSwapchain( // format and colorspace createInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + swapchain->format = VK_FORMAT_B8G8R8A8_UNORM; if (info->format == PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB) { createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + swapchain->format = VK_FORMAT_B8G8R8A8_SRGB; } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB) { createInfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + swapchain->format = VK_FORMAT_R8G8B8A8_UNORM; } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10) { createInfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; createInfo.imageColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; + swapchain->format = VK_FORMAT_R16G16B16A16_SFLOAT; } // create swapchain @@ -1868,6 +1893,96 @@ static void PAL_CALL vkDestroySwapchain(PalSwapchain* swapchain) palFree(s_Graphics.allocator, _swapchain); } +PalResult PAL_CALL vkGetSwapchainBuffers( + PalSwapchain* swapchain, + Int32* count, + PalGPUBuffer** outBuffers) +{ + VkResult result = VK_SUCCESS; + Uint32 _count = 0; + VkImage* images = nullptr; + Swapchain* _swapchain = (Swapchain*)swapchain; + + result = _swapchain->device->getSwapchainImages( + _swapchain->device->handle, + _swapchain->handle, + &_count, + nullptr); + + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + if (!outBuffers) { + *count = _count; + return PAL_RESULT_SUCCESS; + } + + images = palAllocate(s_Graphics.allocator, sizeof(VkImage) * _count, 0); + if (!images) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + _swapchain->device->getSwapchainImages( + _swapchain->device->handle, + _swapchain->handle, + &_count, + images); + + for (int i = 0; i < _count && i < *count; i++) { + outBuffers[i] = (PalGPUBuffer*)images[i]; + } + + palFree(s_Graphics.allocator, images); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL vkCreateRenderTargetView( + PalSwapchain* swapchain, + PalGPUBuffer* buffer, + PalRenderTargetView** outRtv) +{ + VkResult result = VK_SUCCESS; + RenderTargetView* rtv = nullptr; + Swapchain* _swapchain = (Swapchain*)swapchain; + + rtv = palAllocate(s_Graphics.allocator, sizeof(RenderTargetView), 0); + if (!rtv) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkImageViewCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.format = _swapchain->format; + createInfo.image = (VkImage)buffer; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.layerCount = 1; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + result = s_Vk.createImageView( + _swapchain->device->handle, + &createInfo, + &s_Vk.allocator, + &rtv->handle); + + if (result != VK_SUCCESS) { + palFree(s_Graphics.allocator, rtv); + return vkResultToPal(result); + } + + rtv->device = _swapchain->device; + *outRtv = (PalRenderTargetView*)rtv; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL vkDestroyRenderTargetView(PalRenderTargetView* rtv) +{ + RenderTargetView* _rtv = (RenderTargetView*)rtv; + s_Vk.destroyImageView(_rtv->device->handle, _rtv->handle, &s_Vk.allocator); + palFree(s_Graphics.allocator, _rtv); +} + static PalGPUBackend s_VkBackend = { .enumerateGPUAdapters = vkEnumerateAdapters, .getGPUAdapterInfo = vkGetAdapterInfo, @@ -1879,7 +1994,10 @@ static PalGPUBackend s_VkBackend = { .canCommandQueuePresent = vkCanCommandQueuePresent, .getSwapchainCapabilities = vkQuerySwapchainCapabilities, .createSwapchain = vkCreateSwapchain, - .destroySwapchain = vkDestroySwapchain + .destroySwapchain = vkDestroySwapchain, + .getSwapchainBuffers = vkGetSwapchainBuffers, + .createRenderTargetView = vkCreateRenderTargetView, + .destroyRenderTargetView = vkDestroyRenderTargetView }; #endif // PAL_HAS_VULKAN @@ -1901,7 +2019,7 @@ PalResult PAL_CALL palInitGraphics( } s_Graphics.allocator = allocator; - s_Graphics.maxHandleData = 16; + s_Graphics.maxHandleData = 32; s_Graphics.handleData = palAllocate( s_Graphics.allocator, sizeof(HandleData) * s_Graphics.maxHandleData, @@ -2060,7 +2178,10 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) !backend->canCommandQueuePresent || !backend->createSwapchain || !backend->destroySwapchain || - !backend->getSwapchainCapabilities) { + !backend->getSwapchainCapabilities || + !backend->getSwapchainBuffers || + !backend->createRenderTargetView || + !backend->destroyRenderTargetView) { return PAL_RESULT_INVALID_GPU_BACKEND; } // clang-format on @@ -2269,4 +2390,85 @@ void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) data->used = false; } } +} + +PalResult PAL_CALL palGetSwapchainBuffers( + PalSwapchain* swapchain, + Int32* count, + PalGPUBuffer** outBuffers) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!swapchain || !count) { + return PAL_RESULT_NULL_POINTER; + } + + if (*count == 0 && outBuffers) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + + HandleData* swapchainData = findHandleData(swapchain); + if (!swapchainData) { + return PAL_RESULT_INVALID_SWAPCHAIN; + } + + return swapchainData->backend->getSwapchainBuffers( + swapchain, + count, + outBuffers); +} + +PalResult PAL_CALL palCreateRenderTargetView( + PalSwapchain* swapchain, + PalGPUBuffer* buffer, + PalRenderTargetView** outRtv) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!swapchain || !buffer || !outRtv) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* swapchainData = findHandleData(swapchain); + if (!swapchainData) { + return PAL_RESULT_INVALID_SWAPCHAIN; + } + + PalResult ret; + PalRenderTargetView* rtv = nullptr; + ret = swapchainData->backend->createRenderTargetView( + swapchain, + buffer, + &rtv); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + // create a slot for the created render target view + HandleData* rtvData = getFreeHandleData(); + if (!rtvData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + rtvData->backend = swapchainData->backend; + rtvData->handle = rtv; + + *outRtv = rtv; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv) +{ + if (s_Graphics.initialized && rtv) { + HandleData* data = findHandleData(rtv); + if (data) { + data->backend->destroyRenderTargetView(rtv); + data->used = false; + } + } } \ No newline at end of file diff --git a/src/pal_core.c b/src/pal_core.c index ce8dfe58..7abe00c5 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -410,6 +410,12 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_GPU_WINDOW: return "Invalid GPU window"; + + case PAL_RESULT_INVALID_SWAPCHAIN: + return "Invalid swapchain"; + + case PAL_RESULT_INVALID_GPU_BUFFER: + return "Invalid GPU buffer"; } return "Unknown"; } diff --git a/tests/swapchain_test.c b/tests/swapchain_test.c index 47bf51ed..4216b77c 100644 --- a/tests/swapchain_test.c +++ b/tests/swapchain_test.c @@ -175,7 +175,6 @@ bool swapchainTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to query swapchain capabilities: %s", error); - palFree(nullptr, adapters); return false; } @@ -316,10 +315,35 @@ bool swapchainTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); - palFree(nullptr, adapters); return false; } + // get the number of buffers the swapchain has + // this should match the buffers used to create the swapchain + // for simplicity, you can only create two render target and use + // them for rendering without creating one for each seperate buffer + Int32 bufferCount = 1; // we need only one buffer + PalGPUBuffer* buffers[1]; + result = palGetSwapchainBuffers(swapchain, &bufferCount, buffers); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get swapchain buffers: %s", error); + return false; + } + + // since we wont render in this example, we just create one rtv + PalRenderTargetView* rtv = nullptr; + result = palCreateRenderTargetView(swapchain, buffers[0], &rtv); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create render target view: %s", error); + palFree(nullptr, buffers); + return false; + } + + // destroy the render target view + palDestroyRenderTargetView(rtv); + // destroy the swapchain palDestroySwapchain(swapchain); From 1c1a9878a3a36f726c52c66d52c3f234ac0ec0d5 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 1 Dec 2025 01:34:20 +0000 Subject: [PATCH 020/372] make swapchain buffer query simple --- include/pal/pal_core.h | 2 +- include/pal/pal_graphics.h | 15 +--- src/graphics/pal_graphics_linux.c | 123 ++++++++++++++---------------- src/pal_core.c | 4 +- tests/swapchain_test.c | 17 +---- 5 files changed, 68 insertions(+), 93 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 766dcd31..b509f966 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -257,7 +257,7 @@ typedef enum { PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE, PAL_RESULT_INVALID_GPU_WINDOW, PAL_RESULT_INVALID_SWAPCHAIN, - PAL_RESULT_INVALID_GPU_BUFFER, + PAL_RESULT_INVALID_SWAPCHAIN_BUFFER_INDEX, } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index ddf71815..d97e3453 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -41,7 +41,6 @@ typedef struct PalGPUAdapter PalGPUAdapter; typedef struct PalGPUDevice PalGPUDevice; typedef struct PalGPUCommandQueue PalGPUCommandQueue; typedef struct PalSwapchain PalSwapchain; -typedef struct PalGPUBuffer PalGPUBuffer; typedef struct PalRenderTargetView PalRenderTargetView; typedef enum { @@ -235,14 +234,11 @@ typedef struct { void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); - PalResult PAL_CALL (*getSwapchainBuffers)( - PalSwapchain* swapchain, - Int32* count, - PalGPUBuffer** outBuffers); + Uint32 PAL_CALL (*getSwapchainBufferCount)(PalSwapchain* swapchain); PalResult PAL_CALL (*createRenderTargetView)( PalSwapchain* swapchain, - PalGPUBuffer* buffer, + Uint32 bufferIndex, PalRenderTargetView** outRtv); void PAL_CALL (*destroyRenderTargetView)(PalRenderTargetView* rtv); @@ -299,14 +295,11 @@ PAL_API PalResult PAL_CALL palCreateSwapchain( PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); -PAL_API PalResult PAL_CALL palGetSwapchainBuffers( - PalSwapchain* swapchain, - Int32* count, - PalGPUBuffer** outBuffers); +PAL_API Uint32 PAL_CALL palGetSwapchainBufferCount(PalSwapchain* swapchain); PAL_API PalResult PAL_CALL palCreateRenderTargetView( PalSwapchain* swapchain, - PalGPUBuffer* buffer, + Uint32 bufferIndex, PalRenderTargetView** outRtv); PAL_API void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv); diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 8b55300d..827c34a3 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -308,10 +308,12 @@ typedef struct { } CommandQueue; typedef struct { + Int32 bufferCount; VkFormat format; Device* device; VkSurfaceKHR surface; VkSwapchainKHR handle; + VkImage* buffers; } Swapchain; typedef struct { @@ -1876,6 +1878,42 @@ static PalResult PAL_CALL vkCreateSwapchain( return vkResultToPal(result); } + // get all images of the created swapchain + Int32 count = 0; + result = swapchain->device->getSwapchainImages( + swapchain->device->handle, + swapchain->handle, + &count, + nullptr); + + swapchain->buffers = palAllocate( + s_Graphics.allocator, + sizeof(VkImage) * count, + 0); + + if (!swapchain->buffers) { + swapchain->device->destroySwapchain( + swapchain->device->handle, + swapchain->handle, + &s_Vk.allocator + ); + + s_Vk.destroySurface( + s_Vk.instance, + swapchain->surface, + &s_Vk.allocator); + + palFree(s_Graphics.allocator, swapchain); + return PAL_RESULT_OUT_OF_MEMORY; + } + + swapchain->bufferCount = count; + swapchain->device->getSwapchainImages( + swapchain->device->handle, + swapchain->handle, + &count, + swapchain->buffers); + *outSwapchain = (PalSwapchain*)swapchain; return PAL_RESULT_SUCCESS; } @@ -1890,62 +1928,29 @@ static void PAL_CALL vkDestroySwapchain(PalSwapchain* swapchain) ); s_Vk.destroySurface(s_Vk.instance, _swapchain->surface, &s_Vk.allocator); + palFree(s_Graphics.allocator, _swapchain->buffers); palFree(s_Graphics.allocator, _swapchain); } -PalResult PAL_CALL vkGetSwapchainBuffers( - PalSwapchain* swapchain, - Int32* count, - PalGPUBuffer** outBuffers) +Uint32 PAL_CALL vkGetSwapchainBufferCount(PalSwapchain* swapchain) { - VkResult result = VK_SUCCESS; - Uint32 _count = 0; - VkImage* images = nullptr; Swapchain* _swapchain = (Swapchain*)swapchain; - - result = _swapchain->device->getSwapchainImages( - _swapchain->device->handle, - _swapchain->handle, - &_count, - nullptr); - - if (result != VK_SUCCESS) { - return vkResultToPal(result); - } - - if (!outBuffers) { - *count = _count; - return PAL_RESULT_SUCCESS; - } - - images = palAllocate(s_Graphics.allocator, sizeof(VkImage) * _count, 0); - if (!images) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - _swapchain->device->getSwapchainImages( - _swapchain->device->handle, - _swapchain->handle, - &_count, - images); - - for (int i = 0; i < _count && i < *count; i++) { - outBuffers[i] = (PalGPUBuffer*)images[i]; - } - - palFree(s_Graphics.allocator, images); - return PAL_RESULT_SUCCESS; + return _swapchain->bufferCount; } PalResult PAL_CALL vkCreateRenderTargetView( PalSwapchain* swapchain, - PalGPUBuffer* buffer, + Uint32 bufferIndex, PalRenderTargetView** outRtv) { VkResult result = VK_SUCCESS; RenderTargetView* rtv = nullptr; Swapchain* _swapchain = (Swapchain*)swapchain; + if (bufferIndex < 0 && bufferIndex >= _swapchain->bufferCount) { + return PAL_RESULT_INVALID_SWAPCHAIN_BUFFER_INDEX; + } + VkImage buffer = _swapchain->buffers[bufferIndex]; rtv = palAllocate(s_Graphics.allocator, sizeof(RenderTargetView), 0); if (!rtv) { return PAL_RESULT_OUT_OF_MEMORY; @@ -1954,7 +1959,7 @@ PalResult PAL_CALL vkCreateRenderTargetView( VkImageViewCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.format = _swapchain->format; - createInfo.image = (VkImage)buffer; + createInfo.image = buffer; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.layerCount = 1; @@ -1995,7 +2000,7 @@ static PalGPUBackend s_VkBackend = { .getSwapchainCapabilities = vkQuerySwapchainCapabilities, .createSwapchain = vkCreateSwapchain, .destroySwapchain = vkDestroySwapchain, - .getSwapchainBuffers = vkGetSwapchainBuffers, + .getSwapchainBufferCount = vkGetSwapchainBufferCount, .createRenderTargetView = vkCreateRenderTargetView, .destroyRenderTargetView = vkDestroyRenderTargetView }; @@ -2179,7 +2184,7 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) !backend->createSwapchain || !backend->destroySwapchain || !backend->getSwapchainCapabilities || - !backend->getSwapchainBuffers || + !backend->getSwapchainBufferCount || !backend->createRenderTargetView || !backend->destroyRenderTargetView) { return PAL_RESULT_INVALID_GPU_BACKEND; @@ -2392,44 +2397,30 @@ void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) } } -PalResult PAL_CALL palGetSwapchainBuffers( - PalSwapchain* swapchain, - Int32* count, - PalGPUBuffer** outBuffers) +Uint32 PAL_CALL palGetSwapchainBufferCount(PalSwapchain* swapchain) { - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!swapchain || !count) { - return PAL_RESULT_NULL_POINTER; - } - - if (*count == 0 && outBuffers) { - return PAL_RESULT_INSUFFICIENT_BUFFER; + if (!s_Graphics.initialized || !swapchain) { + return 0; } HandleData* swapchainData = findHandleData(swapchain); if (!swapchainData) { - return PAL_RESULT_INVALID_SWAPCHAIN; + return 0; } - return swapchainData->backend->getSwapchainBuffers( - swapchain, - count, - outBuffers); + return swapchainData->backend->getSwapchainBufferCount(swapchain); } PalResult PAL_CALL palCreateRenderTargetView( PalSwapchain* swapchain, - PalGPUBuffer* buffer, + Uint32 bufferIndex, PalRenderTargetView** outRtv) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!swapchain || !buffer || !outRtv) { + if (!swapchain || !outRtv) { return PAL_RESULT_NULL_POINTER; } @@ -2442,7 +2433,7 @@ PalResult PAL_CALL palCreateRenderTargetView( PalRenderTargetView* rtv = nullptr; ret = swapchainData->backend->createRenderTargetView( swapchain, - buffer, + bufferIndex, &rtv); if (ret != PAL_RESULT_SUCCESS) { diff --git a/src/pal_core.c b/src/pal_core.c index 7abe00c5..19e18c9f 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -414,8 +414,8 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_SWAPCHAIN: return "Invalid swapchain"; - case PAL_RESULT_INVALID_GPU_BUFFER: - return "Invalid GPU buffer"; + case PAL_RESULT_INVALID_SWAPCHAIN_BUFFER_INDEX: + return "Invalid swapchain buffer index"; } return "Unknown"; } diff --git a/tests/swapchain_test.c b/tests/swapchain_test.c index 4216b77c..1033bbb1 100644 --- a/tests/swapchain_test.c +++ b/tests/swapchain_test.c @@ -320,24 +320,15 @@ bool swapchainTest() // get the number of buffers the swapchain has // this should match the buffers used to create the swapchain - // for simplicity, you can only create two render target and use - // them for rendering without creating one for each seperate buffer - Int32 bufferCount = 1; // we need only one buffer - PalGPUBuffer* buffers[1]; - result = palGetSwapchainBuffers(swapchain, &bufferCount, buffers); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get swapchain buffers: %s", error); - return false; - } + Uint32 swapchainBufferCount = palGetSwapchainBufferCount(swapchain); + palLog(nullptr, "Swapchain buffer count: %d", swapchainBufferCount); - // since we wont render in this example, we just create one rtv + // create a render target view for the first swapchain buffer PalRenderTargetView* rtv = nullptr; - result = palCreateRenderTargetView(swapchain, buffers[0], &rtv); + result = palCreateRenderTargetView(swapchain, 0, &rtv); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create render target view: %s", error); - palFree(nullptr, buffers); return false; } From 2347d6d26271d4f3230fb25b1731c44514d3178b Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 1 Dec 2025 11:14:48 +0000 Subject: [PATCH 021/372] add render pass capabilities query --- include/pal/pal_graphics.h | 39 ++++- src/graphics/pal_graphics_linux.c | 273 +++++++++++++++++++++++++++--- tests/graphics_test.c | 4 + tests/swapchain_test.c | 18 ++ 4 files changed, 307 insertions(+), 27 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d97e3453..99f22aaf 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -42,6 +42,7 @@ typedef struct PalGPUDevice PalGPUDevice; typedef struct PalGPUCommandQueue PalGPUCommandQueue; typedef struct PalSwapchain PalSwapchain; typedef struct PalRenderTargetView PalRenderTargetView; +typedef struct PalRenderPass PalRenderPass; typedef enum { PAL_GPU_TYPE_UNKNOWN, @@ -55,8 +56,6 @@ typedef enum { PAL_GPU_API_TYPE_VULKAN, PAL_GPU_API_TYPE_D3D12, PAL_GPU_API_TYPE_METAL, - - // for custom backends PAL_GPU_API_TYPE_OPENGL, PAL_GPU_API_TYPE_GLES, PAL_GPU_API_TYPE_D3D11, @@ -133,7 +132,8 @@ typedef enum { PAL_GPU_FEATURE_MESH_SHADER = PAL_BIT64(12), PAL_GPU_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(13), PAL_GPU_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), - PAL_GPU_FEATURE_SWAPCHAIN = PAL_BIT64(15) + PAL_GPU_FEATURE_SWAPCHAIN = PAL_BIT64(15), + PAL_GPU_FEATURE_MULTI_VIEW = PAL_BIT64(16) } PalGPUFeatures; typedef struct { @@ -185,6 +185,15 @@ typedef struct { PalGPUCommandQueue** concurrentQueue; } PalSwapchainCreateInfo; +typedef struct { + Uint32 maxMultiViews; + Uint32 maxColorAttachments; +} PalRenderPassCapabilities; + +typedef struct { + bool clipped; +} PalRenderPassCreateInfo; + typedef struct { void* display; void* window; @@ -221,7 +230,7 @@ typedef struct { PalGPUCommandQueue* queue, PalGPUWindow* window); - PalResult PAL_CALL (*getSwapchainCapabilities)( + PalResult PAL_CALL (*querySwapchainCapabilities)( PalGPUAdapter* adapter, PalGPUWindow* window, PalSwapchainCapabilities* caps); @@ -242,6 +251,17 @@ typedef struct { PalRenderTargetView** outRtv); void PAL_CALL (*destroyRenderTargetView)(PalRenderTargetView* rtv); + + PalResult PAL_CALL (*queryRenderPassCapabilities)( + PalSwapchain* swapchain, + PalRenderPassCapabilities* caps); + + PalResult PAL_CALL (*createRenderPass)( + PalSwapchain* swapchain, + PalRenderPassCreateInfo* info, + PalRenderPass** outRenderPass); + + void PAL_CALL (*destroyRenderPass)(PalRenderPass* renderPass); } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics( @@ -304,6 +324,17 @@ PAL_API PalResult PAL_CALL palCreateRenderTargetView( PAL_API void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv); +PAL_API PalResult PAL_CALL palQueryRenderPassCapabilities( + PalSwapchain* swapchain, + PalRenderPassCapabilities* caps); + +PAL_API PalResult PAL_CALL palCreateRenderPass( + PalSwapchain* swapchain, + PalRenderPassCreateInfo* info, + PalRenderPass** outRenderPass); + +PAL_API void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 827c34a3..74b9aeeb 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -237,6 +237,10 @@ typedef void (*vkDestroyImageViewFn)( VkImageView, const VkAllocationCallbacks*); +typedef void (*vkGetPhysicalDeviceProperties2Fn)( + VkPhysicalDevice, + VkPhysicalDeviceProperties2*); + typedef struct { bool hasDebug; bool versionFallback; @@ -263,6 +267,7 @@ typedef struct { vkGetInstanceProcAddrFn getInstanceProcAddr; vkCreateImageViewFn createImageView; vkDestroyImageViewFn destroyImageView; + vkGetPhysicalDeviceProperties2Fn getPhysicalDeviceProperties2; vkCreateDeviceFn createDevice; vkDestroyDeviceFn destroyDevice; @@ -290,7 +295,11 @@ typedef struct { } PhysicalQueue; typedef struct { + bool dynamicRendering; + bool multiView; + bool swapchain; Int32 queueCount; + Int32 multiViewCount; VkPhysicalDevice phyDevice; VkDevice handle; PhysicalQueue* phyQueues; @@ -321,6 +330,11 @@ typedef struct { VkImageView handle; } RenderTargetView; +typedef struct { + Device* device; + VkRenderPass handle; +} RenderPass; + static Vulkan s_Vk = {0}; #endif // PAL_HAS_VULKAN @@ -595,6 +609,10 @@ static PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.handle, "vkDestroyImageView"); + s_Vk.getPhysicalDeviceProperties2 = (vkGetPhysicalDeviceProperties2Fn)dlsym( + s_Vk.handle, + "vkGetPhysicalDeviceProperties2"); + s_Vk.createDevice = (vkCreateDeviceFn)dlsym( s_Vk.handle, "vkCreateDevice"); @@ -1133,6 +1151,26 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( if (timeline.timelineSemaphore) { caps->features |= PAL_GPU_FEATURE_TIMELINE_SEMAPHORE; } + + } else if (strcmp(props->extensionName, "VK_KHR_multiview") == 0) { + // multi view + VkPhysicalDeviceMultiviewFeaturesKHR view = {0}; + view.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &view; + + if (s_Vk.getPhysicalDeviceFeatures2KHR) { + s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); + + } else { + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + } + + if (view.multiview) { + caps->features |= PAL_GPU_FEATURE_MULTI_VIEW; + } } } @@ -1235,6 +1273,10 @@ static PalResult PAL_CALL vkCreateGPUDevice( device->queueCount = count; device->phyDevice = phyDevice; + device->swapchain = false; + device->multiView = false; + device->dynamicRendering = false; + device->multiViewCount = 1; device->phyQueues = palAllocate( s_Graphics.allocator, @@ -1320,14 +1362,19 @@ static PalResult PAL_CALL vkCreateGPUDevice( VkPhysicalDeviceDescriptorIndexingFeatures descIndex = {0}; descIndex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + VkPhysicalDeviceMultiviewFeatures multiView = {0}; + multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; + // clang-format on if (features & PAL_GPU_FEATURE_SWAPCHAIN) { extensions[extCount++] = "VK_KHR_swapchain"; + device->swapchain = true; } if (features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { extensions[extCount++] = "VK_KHR_dynamic_rendering"; + device->dynamicRendering = true; } if (features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { @@ -1421,6 +1468,41 @@ static PalResult PAL_CALL vkCreateGPUDevice( start = &descIndex; } + if (features & PAL_GPU_FEATURE_MULTI_VIEW) { + extensions[extCount++] = "VK_KHR_multiview"; + multiView.multiview = true; + device->multiView = true; + + VkPhysicalDeviceMultiviewPropertiesKHR p = {0}; + p.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; + + VkPhysicalDeviceProperties2 props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + props.pNext = &p; + s_Vk.getPhysicalDeviceProperties2(phyDevice, &props); + device->multiViewCount = p.maxMultiviewViewCount; + + if (descIndex.shaderSampledImageArrayNonUniformIndexing) { + descIndex.pNext = &multiView; + + } else if (vrs.pipelineFragmentShadingRate) { + vrs.pNext = &multiView; + + } else if (mesh.meshShader) { + mesh.pNext = &multiView; + + } else if (acc.accelerationStructure) { + acc.pNext = &multiView; + + } else if (shader16.shaderFloat16) { + shader16.pNext = &multiView; + + } else if (timeline.timelineSemaphore) { + timeline.pNext = &multiView; + } + start = &multiView; + } + VkDeviceCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pEnabledFeatures = &coreFeatures; @@ -1751,7 +1833,7 @@ static PalResult PAL_CALL vkCreateSwapchain( PhysicalQueue* phyQueue = commandQueue->phyQueue; // check if we enabled swapchain feature - if (!commandQueue->device->createSwapchain) { + if (!commandQueue->device->swapchain) { return PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED; } @@ -1932,13 +2014,13 @@ static void PAL_CALL vkDestroySwapchain(PalSwapchain* swapchain) palFree(s_Graphics.allocator, _swapchain); } -Uint32 PAL_CALL vkGetSwapchainBufferCount(PalSwapchain* swapchain) +static Uint32 PAL_CALL vkGetSwapchainBufferCount(PalSwapchain* swapchain) { Swapchain* _swapchain = (Swapchain*)swapchain; return _swapchain->bufferCount; } -PalResult PAL_CALL vkCreateRenderTargetView( +static PalResult PAL_CALL vkCreateRenderTargetView( PalSwapchain* swapchain, Uint32 bufferIndex, PalRenderTargetView** outRtv) @@ -1981,28 +2063,83 @@ PalResult PAL_CALL vkCreateRenderTargetView( return PAL_RESULT_SUCCESS; } -void PAL_CALL vkDestroyRenderTargetView(PalRenderTargetView* rtv) +static void PAL_CALL vkDestroyRenderTargetView(PalRenderTargetView* rtv) { RenderTargetView* _rtv = (RenderTargetView*)rtv; s_Vk.destroyImageView(_rtv->device->handle, _rtv->handle, &s_Vk.allocator); palFree(s_Graphics.allocator, _rtv); } +static PalResult PAL_CALL vkQueryRenderPassCapabilities( + PalSwapchain* swapchain, + PalRenderPassCapabilities* caps) +{ + Swapchain* _swapchain = (Swapchain*)swapchain; + Device* device = (Device*)_swapchain->device; + + VkPhysicalDeviceProperties props = {0}; + s_Vk.getPhysicalDeviceProperties(device->phyDevice, &props); + caps->maxColorAttachments = props.limits.maxColorAttachments; + caps->maxMultiViews = device->multiViewCount; + + return PAL_RESULT_SUCCESS; +} + +static PalResult PAL_CALL vkCreateRenderPass_( + PalSwapchain* swapchain, + PalRenderPassCreateInfo* info, + PalRenderPass** outRenderPass) +{ + VkResult result = VK_SUCCESS; + RenderPass* renderPass = nullptr; + Swapchain* _swapchain = (Swapchain*)swapchain; + + renderPass = palAllocate(s_Graphics.allocator, sizeof(RenderPass), 0); + if (!renderPass) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkRenderPassCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + + *outRenderPass = (PalRenderPass*)renderPass; + return PAL_RESULT_SUCCESS; +} + +static void PAL_CALL vkDestroyRenderPass_(PalRenderPass* renderPass) +{ + +} + static PalGPUBackend s_VkBackend = { + // adapter .enumerateGPUAdapters = vkEnumerateAdapters, .getGPUAdapterInfo = vkGetAdapterInfo, .getGPUAdapterCapabilities = vkGetAdapterCapabilities, + + // device .createGPUDevice = vkCreateGPUDevice, .destroyGPUDevice = vkDestroyGPUDevice, + + // command queue .createGPUCommandQueue = vkCreateGPUCommandQueue, .destroyGPUCommandQueue = vkDestroyGPUCommandQueue, .canCommandQueuePresent = vkCanCommandQueuePresent, - .getSwapchainCapabilities = vkQuerySwapchainCapabilities, + + // swapchain + .querySwapchainCapabilities = vkQuerySwapchainCapabilities, .createSwapchain = vkCreateSwapchain, .destroySwapchain = vkDestroySwapchain, .getSwapchainBufferCount = vkGetSwapchainBufferCount, + + // render target view .createRenderTargetView = vkCreateRenderTargetView, - .destroyRenderTargetView = vkDestroyRenderTargetView + .destroyRenderTargetView = vkDestroyRenderTargetView, + + // render pass + .queryRenderPassCapabilities = vkQueryRenderPassCapabilities, + .createRenderPass = vkCreateRenderPass_, + .destroyRenderPass = vkDestroyRenderPass_ }; #endif // PAL_HAS_VULKAN @@ -2066,7 +2203,7 @@ void PAL_CALL palShutdownGraphics() } // ================================================== -// GPUAdapter +// GPU Adapter // ================================================== PalResult PAL_CALL palEnumerateGPUAdapters( @@ -2173,20 +2310,23 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) // check if all the function pointers are set // clang-format off - if (!backend->enumerateGPUAdapters || - !backend->getGPUAdapterInfo || - !backend->getGPUAdapterCapabilities || - !backend->createGPUDevice || - !backend->destroyGPUDevice || - !backend->createGPUCommandQueue || - !backend->destroyGPUCommandQueue || - !backend->canCommandQueuePresent || - !backend->createSwapchain || - !backend->destroySwapchain || - !backend->getSwapchainCapabilities || - !backend->getSwapchainBufferCount || - !backend->createRenderTargetView || - !backend->destroyRenderTargetView) { + if (!backend->enumerateGPUAdapters || + !backend->getGPUAdapterInfo || + !backend->getGPUAdapterCapabilities || + !backend->createGPUDevice || + !backend->destroyGPUDevice || + !backend->createGPUCommandQueue || + !backend->destroyGPUCommandQueue || + !backend->canCommandQueuePresent || + !backend->createSwapchain || + !backend->destroySwapchain || + !backend->querySwapchainCapabilities || + !backend->getSwapchainBufferCount || + !backend->createRenderTargetView || + !backend->destroyRenderTargetView || + !backend->queryRenderPassCapabilities || + !backend->createRenderPass || + !backend->destroyRenderPass) { return PAL_RESULT_INVALID_GPU_BACKEND; } // clang-format on @@ -2200,7 +2340,7 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) } // ================================================== -// GPUDevice +// GPU Device // ================================================== PalResult PAL_CALL palCreateGPUDevice( @@ -2253,6 +2393,10 @@ void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device) } } +// ================================================== +// GPU Command Queue +// ================================================== + PalResult PAL_CALL palCreateGPUCommandQueue( PalGPUDevice* device, PalGPUCommandQueueType type, @@ -2342,7 +2486,7 @@ PalResult PAL_CALL palQuerySwapchainCapabilities( return PAL_RESULT_INVALID_GPU_ADAPTER; } - return adapterData->backend->getSwapchainCapabilities( + return adapterData->backend->querySwapchainCapabilities( adapter, window, caps); @@ -2411,6 +2555,10 @@ Uint32 PAL_CALL palGetSwapchainBufferCount(PalSwapchain* swapchain) return swapchainData->backend->getSwapchainBufferCount(swapchain); } +// ================================================== +// Render Target View +// ================================================== + PalResult PAL_CALL palCreateRenderTargetView( PalSwapchain* swapchain, Uint32 bufferIndex, @@ -2462,4 +2610,83 @@ void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv) data->used = false; } } +} + +// ================================================== +// Render Pass +// ================================================== + +PalResult PAL_CALL palQueryRenderPassCapabilities( + PalSwapchain* swapchain, + PalRenderPassCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!swapchain || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* swapchainData = findHandleData(swapchain); + if (!swapchainData) { + return PAL_RESULT_INVALID_SWAPCHAIN; + } + + return swapchainData->backend->queryRenderPassCapabilities( + swapchain, + caps); +} + +PalResult PAL_CALL palCreateRenderPass( + PalSwapchain* swapchain, + PalRenderPassCreateInfo* info, + PalRenderPass** outRenderPass) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!swapchain || !info || !outRenderPass) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* swapchainData = findHandleData(swapchain); + if (!swapchainData) { + return PAL_RESULT_INVALID_SWAPCHAIN; + } + + PalResult ret; + PalRenderPass* renderPass = nullptr; + ret = swapchainData->backend->createRenderPass( + swapchain, + info, + &renderPass); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + // create a slot for the created render pass + HandleData* renderPassData = getFreeHandleData(); + if (!renderPassData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + renderPassData->backend = swapchainData->backend; + renderPassData->handle = renderPass; + + *outRenderPass = renderPass; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) +{ + if (s_Graphics.initialized && renderPass) { + HandleData* data = findHandleData(renderPass); + if (data) { + data->backend->destroyRenderPass(renderPass); + data->used = false; + } + } } \ No newline at end of file diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 96095924..0034beb0 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -225,6 +225,10 @@ bool graphicsTest() palLog(nullptr, " Swapchain"); } + if (caps.features & PAL_GPU_FEATURE_MULTI_VIEW) { + palLog(nullptr, " Multiview"); + } + // shader formats palLog(nullptr, " Supported Shader Formats:"); if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_SPIRV) { diff --git a/tests/swapchain_test.c b/tests/swapchain_test.c index 1033bbb1..9490da37 100644 --- a/tests/swapchain_test.c +++ b/tests/swapchain_test.c @@ -332,6 +332,24 @@ bool swapchainTest() return false; } + // query render pass capabilities of the swapchain + PalRenderPassCapabilities renderPassCaps = {0}; + result = palQueryRenderPassCapabilities( + swapchain, + &renderPassCaps); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to query render pass capabilities: %s", error); + return false; + } + + // log render pass capabilities + Uint32 maxColorAttachments = renderPassCaps.maxColorAttachments; + palLog(nullptr, "Render pass capabilities:"); + palLog(nullptr, " Max color attachments: %d", maxColorAttachments); + palLog(nullptr, " Max multi views: %d", renderPassCaps.maxMultiViews); + // destroy the render target view palDestroyRenderTargetView(rtv); From 666cde3913e108db1fcf1c97bc95d0d170fbe06c Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 1 Dec 2025 18:11:05 +0000 Subject: [PATCH 022/372] add new adapter api --- include/pal/pal_graphics.h | 538 +++-- src/graphics/pal_graphics_linux.c | 2983 +++++++++++++------------- tests/custom_graphics_backend_test.c | 372 ---- tests/graphics_test.c | 149 +- tests/tests.lua | 5 +- tests/tests_main.c | 5 +- 6 files changed, 1977 insertions(+), 2075 deletions(-) delete mode 100644 tests/custom_graphics_backend_test.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 99f22aaf..b94a5e9d 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -23,7 +23,7 @@ freely, subject to the following restrictions: /** * @defgroup pal_graphics Graphics - * Graphics PAL functionality such as GPUs, GPUDevices, swapchains and more. + * Graphics PAL functionality such as Adapters, Device, Swapchains and more. * * @{ */ @@ -33,88 +33,167 @@ freely, subject to the following restrictions: #include "pal_core.h" -#define PAL_GPU_NAME_SIZE 128 -#define PAL_GPU_VERSION_SIZE 16 +#define PAL_ADAPTER_NAME_SIZE 128 +#define PAL_ADAPTER_VERSION_SIZE 16 #define PAL_INFINITE (2147483647) -typedef struct PalGPUAdapter PalGPUAdapter; -typedef struct PalGPUDevice PalGPUDevice; -typedef struct PalGPUCommandQueue PalGPUCommandQueue; +typedef struct PalAdapter PalAdapter; +typedef struct PalDevice PalDevice; +typedef struct PalQueue PalQueue; typedef struct PalSwapchain PalSwapchain; -typedef struct PalRenderTargetView PalRenderTargetView; +typedef struct PalImage PalImage; +typedef struct PalImageView PalImageView; typedef struct PalRenderPass PalRenderPass; typedef enum { - PAL_GPU_TYPE_UNKNOWN, - PAL_GPU_TYPE_DISCRETE, - PAL_GPU_TYPE_INTEGRATED, - PAL_GPU_TYPE_VIRTUAL, - PAL_GPU_TYPE_CPU -} PalGPUType; + PAL_ADAPTER_TYPE_UNKNOWN, + PAL_ADAPTER_TYPE_DISCRETE, + PAL_ADAPTER_TYPE_INTEGRATED, + PAL_ADAPTER_TYPE_VIRTUAL, + PAL_ADAPTER_TYPE_CPU +} PalAdapterType; typedef enum { - PAL_GPU_API_TYPE_VULKAN, - PAL_GPU_API_TYPE_D3D12, - PAL_GPU_API_TYPE_METAL, - PAL_GPU_API_TYPE_OPENGL, - PAL_GPU_API_TYPE_GLES, - PAL_GPU_API_TYPE_D3D11, - PAL_GPU_API_TYPE_D3D9, - PAL_GPU_API_TYPE_PPM -} PalGPUApiType; + PAL_ADAPTER_API_TYPE_VULKAN, + PAL_ADAPTER_API_TYPE_D3D12, + PAL_ADAPTER_API_TYPE_METAL, + PAL_ADAPTER_API_TYPE_OPENGL, + PAL_ADAPTER_API_TYPE_GLES, + PAL_ADAPTER_API_TYPE_D3D11, + PAL_ADAPTER_API_TYPE_D3D9, + PAL_ADAPTER_API_TYPE_PPM +} PalAdapterApiType; typedef enum { - PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS, - PAL_GPU_COMMAND_QUEUE_TYPE_COMPUTE, - PAL_GPU_COMMAND_QUEUE_TYPE_COPY -} PalGPUCommandQueueType; + PAL_QUEUE_TYPE_GRAPHICS, + PAL_QUEUE_TYPE_COMPUTE, + PAL_QUEUE_TYPE_COPY +} PalQueueType; typedef enum { - PAL_PRESENT_MODE_FIFO = PAL_BIT(0), - PAL_PRESENT_MODE_IMMEDIATE = PAL_BIT(1), - PAL_PRESENT_MODE_MAILBOX = PAL_BIT(2) -} PalPresentModes; + PAL_PRESENT_MODE_FIFO, + PAL_PRESENT_MODE_IMMEDIATE, + PAL_PRESENT_MODE_MAILBOX +} PalPresentMode; typedef enum { - PAL_COMPOSITE_ALPHA_OPAQUE = PAL_BIT(0), - PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED = PAL_BIT(1), - PAL_COMPOSITE_ALPHA_POST_MULTIPLIED = PAL_BIT(2) -} PalCompositeAplhas; + PAL_COMPOSITE_ALPHA_OPAQUE, + PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED, + PAL_COMPOSITE_ALPHA_POST_MULTIPLIED +} PalCompositeAplha; typedef enum { - PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB = PAL_BIT64(0), - PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB = PAL_BIT64(1), - PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB = PAL_BIT64(2), - PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10 = PAL_BIT64(3) -} PalSwapchainFormats; + PAL_FORMAT_R8_UNORM, + PAL_FORMAT_R8_SNORM, + PAL_FORMAT_R8_UINT, + PAL_FORMAT_R8_SINT, + PAL_FORMAT_R8_SRGB, + PAL_FORMAT_R16_UNORM, + PAL_FORMAT_R16_SNORM, + PAL_FORMAT_R16_UINT, + PAL_FORMAT_R16_SINT, + PAL_FORMAT_R16_SFLOAT, + PAL_FORMAT_R32_UINT, + PAL_FORMAT_R32_SINT, + PAL_FORMAT_R32_SFLOAT, + PAL_FORMAT_R64_UINT, + PAL_FORMAT_R64_SINT, + PAL_FORMAT_R64_SFLOAT, + PAL_FORMAT_R8G8_UNORM, + PAL_FORMAT_R8G8_SNORM, + PAL_FORMAT_R8G8_UINT, + PAL_FORMAT_R8G8_SINT, + PAL_FORMAT_R8G8_SRGB, + PAL_FORMAT_R16G16_UNORM, + PAL_FORMAT_R16G16_SNORM, + PAL_FORMAT_R16G16_UINT, + PAL_FORMAT_R16G16_SINT, + PAL_FORMAT_R16G16_SFLOAT, + PAL_FORMAT_R32G32_UINT, + PAL_FORMAT_R32G32_SINT, + PAL_FORMAT_R32G32_SFLOAT, + PAL_FORMAT_R64G64_UINT, + PAL_FORMAT_R64G64_SINT, + PAL_FORMAT_R64G64_SFLOAT, + PAL_FORMAT_R8G8B8_UNORM, + PAL_FORMAT_R8G8B8_SNORM, + PAL_FORMAT_R8G8B8_UINT, + PAL_FORMAT_R8G8B8_SINT, + PAL_FORMAT_R8G8B8_SRGB, + PAL_FORMAT_R16G16B16_UNORM, + PAL_FORMAT_R16G16B16_SNORM, + PAL_FORMAT_R16G16B16_UINT, + PAL_FORMAT_R16G16B16_SINT, + PAL_FORMAT_R16G16B16_SFLOAT, + PAL_FORMAT_R32G32B32_UINT, + PAL_FORMAT_R32G32B32_SINT, + PAL_FORMAT_R32G32B32_SFLOAT, + PAL_FORMAT_R64G64B64_UINT, + PAL_FORMAT_R64G64B64_SINT, + PAL_FORMAT_R64G64B64_SFLOAT, + PAL_FORMAT_B8G8R8_UNORM, + PAL_FORMAT_B8G8R8_SNORM, + PAL_FORMAT_B8G8R8_UINT, + PAL_FORMAT_B8G8R8_SINT, + PAL_FORMAT_B8G8R8_SRGB, + PAL_FORMAT_R8G8B8A8_UNORM, + PAL_FORMAT_R8G8B8A8_SNORM, + PAL_FORMAT_R8G8B8A8_UINT, + PAL_FORMAT_R8G8B8A8_SINT, + PAL_FORMAT_R8G8B8A8_SRGB, + PAL_FORMAT_R16G16B16A16_UNORM, + PAL_FORMAT_R16G16B16A16_SNORM, + PAL_FORMAT_R16G16B16A16_UINT, + PAL_FORMAT_R16G16B16A16_SINT, + PAL_FORMAT_R16G16B16A16_SFLOAT, + PAL_FORMAT_R32G32B32A32_UINT, + PAL_FORMAT_R32G32B32A32_SINT, + PAL_FORMAT_R32G32B32A32_SFLOAT, + PAL_FORMAT_R64G64B64A64_UINT, + PAL_FORMAT_R64G64B64A64_SINT, + PAL_FORMAT_R64G64B64A64_SFLOAT, + PAL_FORMAT_B8G8RA88_UNORM, + PAL_FORMAT_B8G8R8A8_SNORM, + PAL_FORMAT_B8G8R8A8_UINT, + PAL_FORMAT_B8G8R8A8_SINT, + PAL_FORMAT_B8G8R8A8_SRGB, + PAL_FORMAT_S8_UINT, + PAL_FORMAT_D16_UNORM, + PAL_FORMAT_D32_SFLOAT, + PAL_FORMAT_D32_SFLOAT_S8_UINT, + PAL_FORMAT_D16_UNORM_S8_UINT, + PAL_FORMAT_D24_UNORM_S8_UINT, +} PalFormat; typedef enum { - PAL_SWAPCHAIN_SHARING_MODE_EXCLUSIVE = PAL_BIT(0), - PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT = PAL_BIT(1) -} PalSwapchainSharingModes; + PAL_IMAGE_USAGE_COLOR_ATTACHEMENT = PAL_BIT(0), + PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT = PAL_BIT(1), + PAL_IMAGE_USAGE_TRANSFER_SRC = PAL_BIT(2), + PAL_IMAGE_USAGE_TRANSFER_DST = PAL_BIT(3), + PAL_IMAGE_USAGE_STORAGE = PAL_BIT(4), + PAL_IMAGE_USAGE_SAMPLED = PAL_BIT(5) +} PalImageUsages; typedef enum { - PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE = PAL_BIT(0), - PAL_SWAPCHAIN_TRANSFORM_PORTRAIT = PAL_BIT(1), - PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED = PAL_BIT(2), - PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED = PAL_BIT(3) -} PalSwapchainTransforms; + PAL_SHARING_MODE_EXCLUSIVE, + PAL_SHARING_MODE_CONCURRENT +} PalSharingMode; typedef enum { - PAL_SWAPCHAIN_USAGE_COLOR_ATTACHEMENT = PAL_BIT(0), - PAL_SWAPCHAIN_USAGE_TRANSFER_SRC = PAL_BIT(1), - PAL_SWAPCHAIN_USAGE_TRANSFER_DST = PAL_BIT(2), - PAL_SWAPCHAIN_USAGE_SAMPLED = PAL_BIT(3), -} PalSwapchainUsages; + PAL_TRANSFORM_LANDSCAPE, + PAL_TRANSFORM_PORTRAIT, + PAL_TRANSFORM_LANDSCAPE_FLIPPED, + PAL_TRANSFORM_PORTRAIT_FLIPPED +} PalTransform; typedef enum { - PAL_GPU_SHADER_FORMAT_SPIRV = PAL_BIT(0), - PAL_GPU_SHADER_FORMAT_DXIL = PAL_BIT(1), - PAL_GPU_SHADER_FORMAT_DXBC = PAL_BIT(2), - PAL_GPU_SHADER_FORMAT_GLSL = PAL_BIT(3), - PAL_GPU_SHADER_FORMAT_MSL = PAL_BIT(4), - PAL_GPU_SHADER_FORMAT_PPM = PAL_BIT(5) -} PalGPUShaderFormats; + PAL_SHADER_FORMAT_SPIRV = PAL_BIT(0), + PAL_SHADER_FORMAT_DXIL = PAL_BIT(1), + PAL_SHADER_FORMAT_DXBC = PAL_BIT(2), + PAL_SHADER_FORMAT_GLSL = PAL_BIT(3), + PAL_SHADER_FORMAT_MSL = PAL_BIT(4), + PAL_SHADER_FORMAT_PPM = PAL_BIT(5) +} PalShaderFormats; typedef enum { PAL_GPU_FEATURE_SAMPLER_ANISOTROPY = PAL_BIT64(0), @@ -136,132 +215,183 @@ typedef enum { PAL_GPU_FEATURE_MULTI_VIEW = PAL_BIT64(16) } PalGPUFeatures; +typedef enum { + PAL_LOAD_OP_LOAD, + PAL_LOAD_OP_CLEAR, + PAL_LOAD_OP_DONT_CARE, +} PalLoadOp; + +typedef enum { + PAL_STORE_OP_STORE, + PAL_STORE_OP_DONT_CARE +} PalStoreOp; + typedef struct { - PalGPUType type; - PalGPUApiType apiType; - PalGPUShaderFormats shaderFormats; - Uint64 totalMemory; // in bytes - char versionString[PAL_GPU_VERSION_SIZE]; - char name[PAL_GPU_NAME_SIZE]; -} PalGPUAdapterInfo; + Uint32 vendorId; + Uint32 deviceId; + PalAdapterType type; + PalAdapterApiType apiType; + PalShaderFormats shaderFormats; + Uint64 vram; + Uint64 sharedMemory; + Uint64 version; + char versionString[PAL_ADAPTER_VERSION_SIZE]; + char name[PAL_ADAPTER_NAME_SIZE]; +} PalAdapterInfo; typedef struct { bool debugLayerSupported; Uint32 maxComputeQueues; Uint32 maxGraphicsQueues; Uint32 maxCopyQueues; - PalGPUFeatures features; -} PalGPUAdapterCapabilities; - -typedef struct { - Uint32 minBufferCount; - Uint32 maxBufferCount; - Uint32 minWidth; - Uint32 minHeight; - Uint32 maxWidth; - Uint32 maxHeight; - Uint32 maxBufferArrayLayers; - PalSwapchainFormats formats; - PalSwapchainUsages usages; - PalPresentModes presentModes; - PalCompositeAplhas compositeAlphas; - PalSwapchainSharingModes sharingModes; - PalSwapchainTransforms transforms; -} PalSwapchainCapabilities; - -typedef struct { - bool clipped; - Uint32 width; - Uint32 height; - Uint32 bufferCount; - Uint32 bufferArrayLayerCount; - Uint32 concurrentQueueCount; - PalPresentModes presentMode; - PalSwapchainUsages usage; - PalCompositeAplhas compositeAlpha; - PalSwapchainFormats format; - PalSwapchainSharingModes sharingMode; - PalSwapchainTransforms transform; - PalGPUCommandQueue** concurrentQueue; -} PalSwapchainCreateInfo; - -typedef struct { - Uint32 maxMultiViews; + Uint32 maxImageWidth; + Uint32 maxImageHeight; + Uint32 maxImageDepth; + Uint32 maxImageArrayLayers; + Uint32 maxImageMipLevels; + Uint32 maxColorSamples; + Uint32 maxDepthSamples; Uint32 maxColorAttachments; -} PalRenderPassCapabilities; - -typedef struct { - bool clipped; -} PalRenderPassCreateInfo; - -typedef struct { - void* display; - void* window; -} PalGPUWindow; + Uint32 maxMultiViews; + Uint32 maxViewports; + Uint32 maxSamplers; + Uint32 maxUniformBufferSize; + Uint32 maxStorageBufferSize; + Uint32 maxPushConstantSize; + PalGPUFeatures features; +} PalAdapterCapabilities; + +// typedef struct { +// Uint32 minBufferCount; +// Uint32 maxBufferCount; +// Uint32 minWidth; +// Uint32 minHeight; +// Uint32 maxWidth; +// Uint32 maxHeight; +// Uint32 maxBufferArrayLayers; +// PalSwapchainFormats formats; +// PalSwapchainUsages usages; +// PalPresentModes presentModes; +// PalCompositeAplhas compositeAlphas; +// PalSwapchainSharingModes sharingModes; +// PalSwapchainTransforms transforms; +// } PalSwapchainCapabilities; + +// typedef struct { +// bool clipped; +// Uint32 width; +// Uint32 height; +// Uint32 bufferCount; +// Uint32 bufferArrayLayerCount; +// Uint32 concurrentQueueCount; +// PalPresentModes presentMode; +// PalSwapchainUsages usage; +// PalCompositeAplhas compositeAlpha; +// PalSwapchainFormats format; +// PalSwapchainSharingModes sharingMode; +// PalSwapchainTransforms transform; +// PalGPUCommandQueue** concurrentQueue; +// } PalSwapchainCreateInfo; + +// typedef struct { +// Uint32 maxMultiViews; +// Uint32 maxColorAttachments; +// } PalRenderPassCapabilities; + +// typedef struct { +// Uint32 mipLevel; +// Uint32 baseLayer; +// Uint32 layerCount; +// PalRenderTargetView* renderTargetView; +// } PalRenderPassResolveInfo; + +// typedef struct { +// Uint32 mipLevel; +// Uint32 baseLayer; +// Uint32 layerCount; +// PalRenderPassLoadOp loadOp; +// PalRenderPassStoreOp storeOp; +// float depth; +// float stencil; +// PalRenderPassResolveInfo* resolve; +// float color[4]; +// } PalRenderPassAttachmentInfo; + +// typedef struct { +// Uint32 attachmentCount; +// Uint32 multiViewCount; +// PalRenderTargetView* renderTargetView; +// PalRenderPassAttachmentInfo* attachments; +// } PalRenderPassCreateInfo; + +// typedef struct { +// void* display; +// void* window; +// } PalGPUWindow; typedef struct { - PalResult PAL_CALL (*enumerateGPUAdapters)( + PalResult PAL_CALL (*enumerateAdapters)( Int32* count, - PalGPUAdapter** outAdapters); + PalAdapter** outAdapters); - PalResult PAL_CALL (*getGPUAdapterInfo)( - PalGPUAdapter* adapter, - PalGPUAdapterInfo* info); + PalResult PAL_CALL (*getAdapterInfo)( + PalAdapter* adapter, + PalAdapterInfo* info); - PalResult PAL_CALL (*getGPUAdapterCapabilities)( - PalGPUAdapter* adapter, - PalGPUAdapterCapabilities* caps); + PalResult PAL_CALL (*getAdapterCapabilities)( + PalAdapter* adapter, + PalAdapterCapabilities* caps); - PalResult PAL_CALL (*createGPUDevice)( - PalGPUAdapter* adapter, - PalGPUFeatures features, - PalGPUDevice** outDevice); + // PalResult PAL_CALL (*createGPUDevice)( + // PalGPUAdapter* adapter, + // PalGPUFeatures features, + // PalGPUDevice** outDevice); - void PAL_CALL (*destroyGPUDevice)(PalGPUDevice* device); + // void PAL_CALL (*destroyGPUDevice)(PalGPUDevice* device); - PalResult PAL_CALL (*createGPUCommandQueue)( - PalGPUDevice* device, - PalGPUCommandQueueType type, - PalGPUCommandQueue** outQueue); + // PalResult PAL_CALL (*createGPUCommandQueue)( + // PalGPUDevice* device, + // PalGPUCommandQueueType type, + // PalGPUCommandQueue** outQueue); - void PAL_CALL (*destroyGPUCommandQueue)(PalGPUCommandQueue* queue); + // void PAL_CALL (*destroyGPUCommandQueue)(PalGPUCommandQueue* queue); - bool PAL_CALL (*canCommandQueuePresent)( - PalGPUCommandQueue* queue, - PalGPUWindow* window); + // bool PAL_CALL (*canCommandQueuePresent)( + // PalGPUCommandQueue* queue, + // PalGPUWindow* window); - PalResult PAL_CALL (*querySwapchainCapabilities)( - PalGPUAdapter* adapter, - PalGPUWindow* window, - PalSwapchainCapabilities* caps); + // PalResult PAL_CALL (*querySwapchainCapabilities)( + // PalGPUAdapter* adapter, + // PalGPUWindow* window, + // PalSwapchainCapabilities* caps); - PalResult PAL_CALL (*createSwapchain)( - PalGPUCommandQueue* queue, - PalGPUWindow* window, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain); + // PalResult PAL_CALL (*createSwapchain)( + // PalGPUCommandQueue* queue, + // PalGPUWindow* window, + // const PalSwapchainCreateInfo* info, + // PalSwapchain** outSwapchain); - void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); + // void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); - Uint32 PAL_CALL (*getSwapchainBufferCount)(PalSwapchain* swapchain); + // Uint32 PAL_CALL (*getSwapchainBufferCount)(PalSwapchain* swapchain); - PalResult PAL_CALL (*createRenderTargetView)( - PalSwapchain* swapchain, - Uint32 bufferIndex, - PalRenderTargetView** outRtv); + // PalResult PAL_CALL (*createRenderTargetView)( + // PalSwapchain* swapchain, + // Uint32 bufferIndex, + // PalRenderTargetView** outRtv); - void PAL_CALL (*destroyRenderTargetView)(PalRenderTargetView* rtv); + // void PAL_CALL (*destroyRenderTargetView)(PalRenderTargetView* rtv); - PalResult PAL_CALL (*queryRenderPassCapabilities)( - PalSwapchain* swapchain, - PalRenderPassCapabilities* caps); + // PalResult PAL_CALL (*queryRenderPassCapabilities)( + // PalSwapchain* swapchain, + // PalRenderPassCapabilities* caps); - PalResult PAL_CALL (*createRenderPass)( - PalSwapchain* swapchain, - PalRenderPassCreateInfo* info, - PalRenderPass** outRenderPass); + // PalResult PAL_CALL (*createRenderPass)( + // PalSwapchain* swapchain, + // PalRenderPassCreateInfo* info, + // PalRenderPass** outRenderPass); - void PAL_CALL (*destroyRenderPass)(PalRenderPass* renderPass); + // void PAL_CALL (*destroyRenderPass)(PalRenderPass* renderPass); } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics( @@ -270,70 +400,70 @@ PAL_API PalResult PAL_CALL palInitGraphics( PAL_API void PAL_CALL palShutdownGraphics(); -PAL_API PalResult PAL_CALL palEnumerateGPUAdapters( +PAL_API PalResult PAL_CALL palEnumerateAdapters( Int32* count, - PalGPUAdapter** outAdapters); + PalAdapter** outAdapters); -PAL_API PalResult PAL_CALL palGetGPUAdapterInfo( - PalGPUAdapter* adapter, - PalGPUAdapterInfo* info); +PAL_API PalResult PAL_CALL palGetAdapterInfo( + PalAdapter* adapter, + PalAdapterInfo* info); -PAL_API PalResult PAL_CALL palGetGPUAdapterCapabilities( - PalGPUAdapter* adapter, - PalGPUAdapterCapabilities* caps); +PAL_API PalResult PAL_CALL palGetAdapterCapabilities( + PalAdapter* adapter, + PalAdapterCapabilities* caps); -PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); +// PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); -PAL_API PalResult PAL_CALL palCreateGPUDevice( - PalGPUAdapter* adapter, - PalGPUFeatures features, - PalGPUDevice** outDevice); +// PAL_API PalResult PAL_CALL palCreateGPUDevice( +// PalGPUAdapter* adapter, +// PalGPUFeatures features, +// PalGPUDevice** outDevice); -PAL_API void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device); +// PAL_API void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device); -PAL_API PalResult PAL_CALL palCreateGPUCommandQueue( - PalGPUDevice* device, - PalGPUCommandQueueType type, - PalGPUCommandQueue** outQueue); +// PAL_API PalResult PAL_CALL palCreateGPUCommandQueue( +// PalGPUDevice* device, +// PalGPUCommandQueueType type, +// PalGPUCommandQueue** outQueue); -PAL_API void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue); +// PAL_API void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue); -PAL_API bool PAL_CALL palCanCommandQueuePresent( - PalGPUCommandQueue* queue, - PalGPUWindow* window); +// PAL_API bool PAL_CALL palCanCommandQueuePresent( +// PalGPUCommandQueue* queue, +// PalGPUWindow* window); -PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( - PalGPUAdapter* adapter, - PalGPUWindow* window, - PalSwapchainCapabilities* caps); +// PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( +// PalGPUAdapter* adapter, +// PalGPUWindow* window, +// PalSwapchainCapabilities* caps); -PAL_API PalResult PAL_CALL palCreateSwapchain( - PalGPUCommandQueue* queue, - PalGPUWindow* window, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain); +// PAL_API PalResult PAL_CALL palCreateSwapchain( +// PalGPUCommandQueue* queue, +// PalGPUWindow* window, +// const PalSwapchainCreateInfo* info, +// PalSwapchain** outSwapchain); -PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); +// PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); -PAL_API Uint32 PAL_CALL palGetSwapchainBufferCount(PalSwapchain* swapchain); +// PAL_API Uint32 PAL_CALL palGetSwapchainBufferCount(PalSwapchain* swapchain); -PAL_API PalResult PAL_CALL palCreateRenderTargetView( - PalSwapchain* swapchain, - Uint32 bufferIndex, - PalRenderTargetView** outRtv); +// PAL_API PalResult PAL_CALL palCreateRenderTargetView( +// PalSwapchain* swapchain, +// Uint32 bufferIndex, +// PalRenderTargetView** outRtv); -PAL_API void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv); +// PAL_API void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv); -PAL_API PalResult PAL_CALL palQueryRenderPassCapabilities( - PalSwapchain* swapchain, - PalRenderPassCapabilities* caps); +// PAL_API PalResult PAL_CALL palQueryRenderPassCapabilities( +// PalSwapchain* swapchain, +// PalRenderPassCapabilities* caps); -PAL_API PalResult PAL_CALL palCreateRenderPass( - PalSwapchain* swapchain, - PalRenderPassCreateInfo* info, - PalRenderPass** outRenderPass); +// PAL_API PalResult PAL_CALL palCreateRenderPass( +// PalSwapchain* swapchain, +// PalRenderPassCreateInfo* info, +// PalRenderPass** outRenderPass); -PAL_API void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass); +// PAL_API void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass); /** @} */ // end of pal_graphics group diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 74b9aeeb..c204afdd 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -326,13 +326,16 @@ typedef struct { } Swapchain; typedef struct { + VkFormat format; Device* device; VkImageView handle; } RenderTargetView; typedef struct { Device* device; + VkFramebuffer framebuffer; VkRenderPass handle; + //PalRenderPassCreateInfo info; } RenderPass; static Vulkan s_Vk = {0}; @@ -410,50 +413,50 @@ static HandleData* findHandleData(void* handle) #if PAL_HAS_VULKAN -static bool vkOnWayland(struct wl_display* display) -{ - if (!s_Vk.libWayland) { - return false; - } - - int fd = s_Vk.getDisplayFd(display); - if (fd <= 0 || fd > 1024) { // fds are usaually 0-30 but this is fine - return false; - } - return true; -} - -static bool vkCreateSurface(PalGPUWindow* window, VkSurfaceKHR* outSurface) -{ - if (vkOnWayland(window->display)) { - if (!s_Vk.createWaylandSurface) { - return false; - } - - VkSurfaceKHR surface = nullptr; - VkWaylandSurfaceCreateInfoKHR createInfo = {0}; - createInfo.display = window->display; - createInfo.pNext = nullptr; - createInfo.flags = 0; - createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; - createInfo.surface = window->window; - - VkResult result = s_Vk.createWaylandSurface( - s_Vk.instance, - &createInfo, - &s_Vk.allocator, - &surface); - - if (result != VK_SUCCESS) { - return false; - } - *outSurface = surface; - - } else { - // TODO: create surface for xlib - } - return true; -} +// static bool vkOnWayland(struct wl_display* display) +// { +// if (!s_Vk.libWayland) { +// return false; +// } + +// int fd = s_Vk.getDisplayFd(display); +// if (fd <= 0 || fd > 1024) { // fds are usaually 0-30 but this is fine +// return false; +// } +// return true; +// } + +// static bool vkCreateSurface(PalGPUWindow* window, VkSurfaceKHR* outSurface) +// { +// if (vkOnWayland(window->display)) { +// if (!s_Vk.createWaylandSurface) { +// return false; +// } + +// VkSurfaceKHR surface = nullptr; +// VkWaylandSurfaceCreateInfoKHR createInfo = {0}; +// createInfo.display = window->display; +// createInfo.pNext = nullptr; +// createInfo.flags = 0; +// createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; +// createInfo.surface = window->window; + +// VkResult result = s_Vk.createWaylandSurface( +// s_Vk.instance, +// &createInfo, +// &s_Vk.allocator, +// &surface); + +// if (result != VK_SUCCESS) { +// return false; +// } +// *outSurface = surface; + +// } else { +// // TODO: create surface for xlib +// } +// return true; +// } static PalResult vkResultToPal(VkResult result) { @@ -859,7 +862,7 @@ static void vkShutdownGraphics() static PalResult vkEnumerateAdapters( Int32* count, - PalGPUAdapter** outAdapters) + PalAdapter** outAdapters) { int _count = 0; int maxCount = outAdapters ? *count : 0; @@ -887,7 +890,7 @@ static PalResult vkEnumerateAdapters( s_Vk.enumeratePhysicalDevices(s_Vk.instance, &_count, devices); for (int i = 0; i < _count && i < *count; i++) { - outAdapters[i] = (PalGPUAdapter*)devices[i]; + outAdapters[i] = (PalAdapter*)devices[i]; } palFree(s_Graphics.allocator, devices); @@ -895,8 +898,8 @@ static PalResult vkEnumerateAdapters( } static PalResult PAL_CALL vkGetAdapterInfo( - PalGPUAdapter* adapter, - PalGPUAdapterInfo* info) + PalAdapter* adapter, + PalAdapterInfo* info) { VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; VkPhysicalDeviceProperties props = {0}; @@ -905,41 +908,47 @@ static PalResult PAL_CALL vkGetAdapterInfo( s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); s_Vk.getPhysicalDeviceProperties(phyDevice, &props); - info->apiType = PAL_GPU_API_TYPE_VULKAN; - info->shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; + info->apiType = PAL_ADAPTER_API_TYPE_VULKAN; + info->shaderFormats = PAL_SHADER_FORMAT_SPIRV; + info->version = props.driverVersion; + info->deviceId = props.deviceID; + info->vendorId = props.vendorID; strcpy(info->name, props.deviceName); - info->totalMemory = 0; + info->vram = 0; + info->sharedMemory = 0; for (int i = 0; i < memProps.memoryHeapCount; i++) { if (memProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { - info->totalMemory = memProps.memoryHeaps[i].size; + info->vram += memProps.memoryHeaps[i].size; + } else { + info->sharedMemory += memProps.memoryHeaps[i].size; } } // get device type switch (props.deviceType) { case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { - info->type = PAL_GPU_TYPE_INTEGRATED; + info->type = PAL_ADAPTER_TYPE_INTEGRATED; break; } case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { - info->type = PAL_GPU_TYPE_DISCRETE; + info->type = PAL_ADAPTER_TYPE_DISCRETE; break; } case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { - info->type = PAL_GPU_TYPE_VIRTUAL; + info->type = PAL_ADAPTER_TYPE_VIRTUAL; break; } case VK_PHYSICAL_DEVICE_TYPE_CPU: { - info->type = PAL_GPU_TYPE_CPU; + info->type = PAL_ADAPTER_TYPE_CPU; break; } default: { - info->type = PAL_GPU_TYPE_UNKNOWN; + info->type = PAL_ADAPTER_TYPE_UNKNOWN; break; } } @@ -947,7 +956,7 @@ static PalResult PAL_CALL vkGetAdapterInfo( // version string snprintf( info->versionString, - PAL_GPU_VERSION_SIZE, + PAL_ADAPTER_VERSION_SIZE, "%d.%d.%d", VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion), @@ -957,12 +966,55 @@ static PalResult PAL_CALL vkGetAdapterInfo( } static PalResult PAL_CALL vkGetAdapterCapabilities( - PalGPUAdapter* adapter, - PalGPUAdapterCapabilities* caps) + PalAdapter* adapter, + PalAdapterCapabilities* caps) { VkResult ret = VK_SUCCESS; VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + VkPhysicalDeviceProperties props = {0}; + VkPhysicalDeviceMultiviewPropertiesKHR vProps = {0}; + VkPhysicalDeviceProperties2 properties2 = {0}; + vProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; + + s_Vk.getPhysicalDeviceProperties(phyDevice, &props); + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + properties2.pNext = &vProps; + s_Vk.getPhysicalDeviceProperties2(phyDevice, &properties2); + caps->debugLayerSupported = s_Vk.hasDebug; + caps->maxColorAttachments = props.limits.maxColorAttachments; + caps->maxImageWidth = props.limits.maxImageDimension2D; + caps->maxImageHeight = props.limits.maxImageDimension2D; + caps->maxImageDepth = props.limits.maxImageDimension3D; + caps->maxImageArrayLayers = props.limits.maxImageArrayLayers; + caps->maxColorSamples = props.limits.framebufferColorSampleCounts; + caps->maxDepthSamples = props.limits.framebufferDepthSampleCounts; + + caps->maxViewports = props.limits.maxViewports; + caps->maxSamplers = props.limits.maxSamplerAllocationCount; + caps->maxUniformBufferSize = props.limits.maxUniformBufferRange; + caps->maxStorageBufferSize = props.limits.maxStorageBufferRange; + caps->maxPushConstantSize = props.limits.maxPushConstantsSize; + + caps->maxMultiViews = vProps.maxMultiviewViewCount; + if (caps->maxMultiViews == 0) { + caps->maxMultiViews = 1; + } + + // vulkan does not give this but we calculate from the max width and width + Uint32 a = caps->maxImageWidth; + Uint32 b = caps->maxImageHeight; + Uint32 c = caps->maxImageDepth; + + Uint32 tmp = a > b ? a : b; + Uint32 size = tmp > c ? tmp : c; + Uint32 levels = 0; + while (size > 0) { + // divide by two + size = size / 2; + levels++; + } + caps->maxImageMipLevels = levels; // get supported queue commands Uint32 count; @@ -1238,1455 +1290,1522 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL vkCreateGPUDevice( - PalGPUAdapter* adapter, - PalGPUFeatures features, - PalGPUDevice** outDevice) -{ - float priority = 1.0f; - Uint32 count = 0; - VkResult ret = VK_SUCCESS; - Device* device = nullptr; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; - - VkQueueFamilyProperties* queueProps = nullptr; - VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; - s_Vk.getPhysicalDeviceQueueFamilyProperties( - phyDevice, - &count, - nullptr); - - queueProps = palAllocate( - s_Graphics.allocator, - sizeof(VkQueueFamilyProperties) * count, - 0); - - queueCreateInfos = palAllocate( - s_Graphics.allocator, - sizeof(VkDeviceQueueCreateInfo) * count, - 0); - - device = palAllocate(s_Graphics.allocator, sizeof(Device), 0); - if (!queueProps || !queueCreateInfos || !device) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - device->queueCount = count; - device->phyDevice = phyDevice; - device->swapchain = false; - device->multiView = false; - device->dynamicRendering = false; - device->multiViewCount = 1; +// static PalResult PAL_CALL vkCreateGPUDevice( +// PalGPUAdapter* adapter, +// PalGPUFeatures features, +// PalGPUDevice** outDevice) +// { +// float priority = 1.0f; +// Uint32 count = 0; +// VkResult ret = VK_SUCCESS; +// Device* device = nullptr; +// VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + +// VkQueueFamilyProperties* queueProps = nullptr; +// VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; +// s_Vk.getPhysicalDeviceQueueFamilyProperties( +// phyDevice, +// &count, +// nullptr); + +// queueProps = palAllocate( +// s_Graphics.allocator, +// sizeof(VkQueueFamilyProperties) * count, +// 0); + +// queueCreateInfos = palAllocate( +// s_Graphics.allocator, +// sizeof(VkDeviceQueueCreateInfo) * count, +// 0); + +// device = palAllocate(s_Graphics.allocator, sizeof(Device), 0); +// if (!queueProps || !queueCreateInfos || !device) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// device->queueCount = count; +// device->phyDevice = phyDevice; +// device->swapchain = false; +// device->multiView = false; +// device->dynamicRendering = false; +// device->multiViewCount = 1; - device->phyQueues = palAllocate( - s_Graphics.allocator, - sizeof(PhysicalQueue) * count, - 0); +// device->phyQueues = palAllocate( +// s_Graphics.allocator, +// sizeof(PhysicalQueue) * count, +// 0); - if (!device->phyQueues) { - return PAL_RESULT_OUT_OF_MEMORY; - } +// if (!device->phyQueues) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// s_Vk.getPhysicalDeviceQueueFamilyProperties( +// phyDevice, +// &count, +// queueProps); + +// for (int i = 0; i < count; i++) { +// queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; +// queueCreateInfos[i].pNext = nullptr; +// queueCreateInfos[i].pQueuePriorities = &priority; +// queueCreateInfos[i].queueFamilyIndex = i; +// queueCreateInfos[i].queueCount = queueProps[i].queueCount; +// queueCreateInfos[i].flags = 0; +// } + +// // build features and extensions capabilities +// VkPhysicalDeviceFeatures coreFeatures = {0}; +// if (features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { +// coreFeatures.samplerAnisotropy = true; +// } + +// if (features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { +// coreFeatures.sampleRateShading = true; +// } + +// if (features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { +// coreFeatures.multiViewport = true; +// } + +// if (features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { +// coreFeatures.tessellationShader = true; +// } + +// if (features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { +// coreFeatures.geometryShader = true; +// } + +// if (features & PAL_GPU_FEATURE_SHADER_INT16) { +// coreFeatures.shaderInt16 = true; +// } + +// if (features & PAL_GPU_FEATURE_SHADER_INT64) { +// coreFeatures.shaderInt64 = true; +// } + +// if (features & PAL_GPU_FEATURE_SHADER_FLOAT64) { +// coreFeatures.shaderFloat64 = true; +// } + +// // extensions and features2 +// int extCount = 0; +// const char* extensions[16] = {0}; + +// // clang-format off + +// const void* start = nullptr; +// VkPhysicalDeviceTimelineSemaphoreFeatures timeline = {0}; +// timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; + +// VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; +// shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; + +// VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; +// mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; + +// VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; +// VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; +// ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; +// acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + +// VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs = {0}; +// vrs.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; + +// VkPhysicalDeviceDescriptorIndexingFeatures descIndex = {0}; +// descIndex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + +// VkPhysicalDeviceMultiviewFeatures multiView = {0}; +// multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; + +// // clang-format on + +// if (features & PAL_GPU_FEATURE_SWAPCHAIN) { +// extensions[extCount++] = "VK_KHR_swapchain"; +// device->swapchain = true; +// } + +// if (features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { +// extensions[extCount++] = "VK_KHR_dynamic_rendering"; +// device->dynamicRendering = true; +// } + +// if (features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { +// extensions[extCount++] = "VK_KHR_timeline_semaphore"; +// timeline.timelineSemaphore = true; +// start = &timeline; +// } + +// if (features & PAL_GPU_FEATURE_SHADER_FLOAT16) { +// extensions[extCount++] = "VK_KHR_shader_float16_int8"; +// shader16.shaderFloat16 = true; + +// if (timeline.timelineSemaphore) { +// timeline.pNext = &shader16; +// } +// start = &shader16; +// } + +// if (features & PAL_GPU_FEATURE_RAY_TRACING) { +// extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; +// extensions[extCount++] = "VK_KHR_acceleration_structure"; +// ray.rayTracingPipeline = true; +// acc.accelerationStructure = true; + +// if (shader16.shaderFloat16) { +// shader16.pNext = &ray; - s_Vk.getPhysicalDeviceQueueFamilyProperties( - phyDevice, - &count, - queueProps); +// } else if (timeline.timelineSemaphore) { +// // no shader16, check timeline +// timeline.pNext = &ray; +// } +// ray.pNext = &acc; +// start = &ray; +// } + +// if (features & PAL_GPU_FEATURE_MESH_SHADER) { +// extensions[extCount++] = "VK_EXT_mesh_shader"; +// mesh.meshShader = true; +// mesh.taskShader = true; + +// if (acc.accelerationStructure) { +// acc.pNext = &mesh; + +// } else if (shader16.shaderFloat16) { +// shader16.pNext = &mesh; + +// } else if (timeline.timelineSemaphore) { +// timeline.pNext = &mesh; +// } +// start = &mesh; +// } + +// if (features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { +// extensions[extCount++] = "VK_KHR_fragment_shading_rate"; +// vrs.pipelineFragmentShadingRate = true; + +// if (mesh.meshShader) { +// mesh.pNext = &vrs; + +// } else if (acc.accelerationStructure) { +// acc.pNext = &vrs; + +// } else if (shader16.shaderFloat16) { +// shader16.pNext = &vrs; + +// } else if (timeline.timelineSemaphore) { +// timeline.pNext = &vrs; +// } +// start = &vrs; +// } + +// if (features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { +// extensions[extCount++] = "VK_EXT_descriptor_indexing"; +// descIndex.shaderSampledImageArrayNonUniformIndexing = true; + +// if (vrs.pipelineFragmentShadingRate) { +// vrs.pNext = &descIndex; + +// } else if (mesh.meshShader) { +// mesh.pNext = &descIndex; + +// } else if (acc.accelerationStructure) { +// acc.pNext = &descIndex; + +// } else if (shader16.shaderFloat16) { +// shader16.pNext = &descIndex; + +// } else if (timeline.timelineSemaphore) { +// timeline.pNext = &descIndex; +// } +// start = &descIndex; +// } + +// if (features & PAL_GPU_FEATURE_MULTI_VIEW) { +// extensions[extCount++] = "VK_KHR_multiview"; +// multiView.multiview = true; +// device->multiView = true; + +// VkPhysicalDeviceMultiviewPropertiesKHR p = {0}; +// p.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; + +// VkPhysicalDeviceProperties2 props = {0}; +// props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; +// props.pNext = &p; +// s_Vk.getPhysicalDeviceProperties2(phyDevice, &props); +// device->multiViewCount = p.maxMultiviewViewCount; + +// if (descIndex.shaderSampledImageArrayNonUniformIndexing) { +// descIndex.pNext = &multiView; + +// } else if (vrs.pipelineFragmentShadingRate) { +// vrs.pNext = &multiView; + +// } else if (mesh.meshShader) { +// mesh.pNext = &multiView; + +// } else if (acc.accelerationStructure) { +// acc.pNext = &multiView; + +// } else if (shader16.shaderFloat16) { +// shader16.pNext = &multiView; + +// } else if (timeline.timelineSemaphore) { +// timeline.pNext = &multiView; +// } +// start = &multiView; +// } + +// VkDeviceCreateInfo createInfo = {0}; +// createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; +// createInfo.pEnabledFeatures = &coreFeatures; +// createInfo.enabledExtensionCount = extCount; +// createInfo.ppEnabledExtensionNames = extensions; +// createInfo.pQueueCreateInfos = queueCreateInfos; +// createInfo.queueCreateInfoCount = count; +// createInfo.pNext = start; + +// ret = s_Vk.createDevice( +// phyDevice, +// &createInfo, +// &s_Vk.allocator, +// &device->handle); + +// if (ret != VK_SUCCESS) { +// palFree(s_Graphics.allocator, queueProps); +// palFree(s_Graphics.allocator, queueCreateInfos); +// palFree(s_Graphics.allocator, device->phyQueues); +// palFree(s_Graphics.allocator, device); +// return vkResultToPal(ret); +// } + +// // get queues +// for (int i = 0; i < count; i++) { +// VkQueueFamilyProperties* data = &queueProps[i]; +// for (int j = 0; j < data->queueCount; j++) { +// PhysicalQueue* queue = &device->phyQueues[i]; +// s_Vk.getDeviceQueue(device->handle, i, j, &queue->handle); +// queue->usages = data->queueFlags; +// queue->usedUsages = 0; +// queue->familyIndex = i; +// queue->phyDevice = phyDevice; +// } +// } + +// // load procs +// device->acquireNextImage = (vkAcquireNextImageKHRFn)s_Vk.getDeviceProcAddr( +// device->handle, +// "vkAcquireNextImageKHR"); + +// device->createSwapchain = (vkCreateSwapchainKHRFn)s_Vk.getDeviceProcAddr( +// device->handle, +// "vkCreateSwapchainKHR"); + +// device->destroySwapchain = (vkDestroySwapchainKHRFn)s_Vk.getDeviceProcAddr( +// device->handle, +// "vkDestroySwapchainKHR"); + +// device->getSwapchainImages = (vkGetSwapchainImagesKHRFn)s_Vk.getDeviceProcAddr( +// device->handle, +// "vkGetSwapchainImagesKHR"); + +// device->queuePresent = (vkQueuePresentKHRFn)s_Vk.getDeviceProcAddr( +// device->handle, +// "vkQueuePresentKHR"); + +// palFree(s_Graphics.allocator, queueProps); +// palFree(s_Graphics.allocator, queueCreateInfos); + +// *outDevice = (PalGPUDevice*)device; +// return PAL_RESULT_SUCCESS; +// } + +// static void PAL_CALL vkDestroyGPUDevice(PalGPUDevice* device) +// { +// Device* gpuDevice = (Device*)device; +// s_Vk.destroyDevice(gpuDevice->handle, &s_Vk.allocator); +// palFree(s_Graphics.allocator, gpuDevice->phyQueues); +// palFree(s_Graphics.allocator, gpuDevice); +// } + +// static PalResult PAL_CALL vkCreateGPUCommandQueue( +// PalGPUDevice* device, +// PalGPUCommandQueueType type, +// PalGPUCommandQueue** outQueue) +// { +// VkQueueFlags queueFlag = 0; +// Device* gpuDevice = (Device*)device; +// CommandQueue* commandQueue = nullptr; +// if (!gpuDevice->handle) { +// return PAL_RESULT_INVALID_GPU_DEVICE; +// } + +// if (gpuDevice->queueCount == 0) { +// return PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE; +// } + +// switch (type) { +// case PAL_GPU_COMMAND_QUEUE_TYPE_COMPUTE: { +// queueFlag = VK_QUEUE_COMPUTE_BIT; +// break; +// } + +// case PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS: { +// queueFlag = VK_QUEUE_GRAPHICS_BIT; +// break; +// } + +// case PAL_GPU_COMMAND_QUEUE_TYPE_COPY: { +// queueFlag = VK_QUEUE_TRANSFER_BIT; +// break; +// } +// } + +// PhysicalQueue* phyQueue = nullptr; +// for (int i = 0; i < gpuDevice->queueCount; i++) { +// PhysicalQueue* queue = &gpuDevice->phyQueues[i]; +// // check if the physical queue supports the requested operation +// // and if its not already used +// if (queue->usages & queueFlag && +// queue->usedUsages != queueFlag) { +// queue->usedUsages |= queueFlag; +// phyQueue = queue; +// break; +// } +// } + +// if (phyQueue) { +// commandQueue = palAllocate( +// s_Graphics.allocator, +// sizeof(CommandQueue), +// 0); - for (int i = 0; i < count; i++) { - queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfos[i].pNext = nullptr; - queueCreateInfos[i].pQueuePriorities = &priority; - queueCreateInfos[i].queueFamilyIndex = i; - queueCreateInfos[i].queueCount = queueProps[i].queueCount; - queueCreateInfos[i].flags = 0; - } +// if (!commandQueue) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// commandQueue->phyQueue = phyQueue; +// commandQueue->usage = queueFlag; +// commandQueue->device = gpuDevice; + +// *outQueue = (PalGPUCommandQueue*)commandQueue; +// return PAL_RESULT_SUCCESS; +// } + +// return PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE; +// } + +// static void PAL_CALL vkDestroyGPUCommandQueue(PalGPUCommandQueue* queue) +// { +// CommandQueue* commandQueue = (CommandQueue*)queue; +// PhysicalQueue* phyQueue = commandQueue->phyQueue; +// phyQueue->usedUsages &= ~commandQueue->usage; +// palFree(s_Graphics.allocator, commandQueue); +// } + +// static bool PAL_CALL vkCanCommandQueuePresent( +// PalGPUCommandQueue* queue, +// PalGPUWindow* window) +// { +// bool onWayland = vkOnWayland(window->display); +// CommandQueue* commandQueue = (CommandQueue*)queue; +// PhysicalQueue* phyQueue = commandQueue->phyQueue; + +// if (!s_Vk.checkWaylandPresentSupport( +// phyQueue->phyDevice, +// phyQueue->familyIndex, window->display)) { +// return false; +// } else { +// // TODO: check presentation for xlib +// } + +// return true; +// } + +// static PalResult PAL_CALL vkQuerySwapchainCapabilities( +// PalGPUAdapter* adapter, +// PalGPUWindow* window, +// PalSwapchainCapabilities* caps) +// { +// Int32 formatCount = 0; +// Int32 modeCount = 0; +// VkSurfaceKHR surface = nullptr; +// VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; +// VkPresentModeKHR* modes = nullptr; +// VkSurfaceFormatKHR* formats = nullptr; + +// bool ret = vkCreateSurface(window, &surface); +// if (!ret) { +// return PAL_RESULT_INVALID_GPU_WINDOW; +// } + +// s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, nullptr); +// s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, nullptr); + +// modes = palAllocate( +// s_Graphics.allocator, +// sizeof(VkPresentModeKHR) * modeCount, +// 0); + +// formats = palAllocate( +// s_Graphics.allocator, +// sizeof(VkSurfaceFormatKHR) * formatCount, +// 0); + +// if (!modes || !formats) { +// s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, modes); +// s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, formats); + +// VkSurfaceCapabilitiesKHR surfaceCaps; +// s_Vk.getSurfaceCapabilities(phyDevice, surface, &surfaceCaps); +// caps->minWidth = surfaceCaps.minImageExtent.width; +// caps->minHeight = surfaceCaps.minImageExtent.height; +// caps->maxWidth = surfaceCaps.maxImageExtent.width; +// caps->maxHeight = surfaceCaps.maxImageExtent.height; + +// caps->maxBufferCount = surfaceCaps.maxImageCount; +// caps->minBufferCount = surfaceCaps.minImageCount; +// caps->maxBufferArrayLayers = surfaceCaps.maxImageArrayLayers; + +// if (caps->maxBufferCount == 0) { +// caps->maxBufferCount = PAL_INFINITE; +// } + +// // get supported transforms +// VkSurfaceTransformFlagsKHR trans = surfaceCaps.supportedTransforms; +// if (trans & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { +// caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE; +// } + +// if (trans & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { +// caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_PORTRAIT; +// } + +// if (trans & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) { +// caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED; +// } + +// if (trans & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { +// caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED; +// } + +// // get supported composite alphas +// VkCompositeAlphaFlagsKHR alpha = surfaceCaps.supportedCompositeAlpha; +// caps->compositeAlphas = PAL_COMPOSITE_ALPHA_OPAQUE; +// if (alpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { +// caps->compositeAlphas |= PAL_COMPOSITE_ALPHA_POST_MULTIPLIED; +// } + +// if (alpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { +// caps->compositeAlphas |= PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED; +// } + +// // get supported composite alphas +// VkImageUsageFlags usage = surfaceCaps.supportedUsageFlags; +// caps->usages = 0; +// if (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { +// caps->usages |= PAL_SWAPCHAIN_USAGE_COLOR_ATTACHEMENT; +// } + +// if (usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { +// caps->usages |= PAL_SWAPCHAIN_USAGE_TRANSFER_DST; +// } + +// if (usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { +// caps->usages |= PAL_SWAPCHAIN_USAGE_TRANSFER_SRC; +// } + +// if (usage & VK_IMAGE_USAGE_SAMPLED_BIT) { +// caps->usages |= PAL_SWAPCHAIN_USAGE_SAMPLED; +// } + +// // sharing modes +// caps->sharingModes = PAL_SWAPCHAIN_SHARING_MODE_EXCLUSIVE; +// caps->sharingModes |= PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT; + +// // present modes +// caps->presentModes = PAL_PRESENT_MODE_FIFO; +// for (int i = 0; i < modeCount; i++) { +// if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { +// caps->presentModes |= PAL_PRESENT_MODE_IMMEDIATE; +// } + +// if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { +// caps->presentModes |= PAL_PRESENT_MODE_MAILBOX; +// } +// } + +// // get format and colorspace +// for (int i = 0; i < formatCount; i++) { +// VkSurfaceFormatKHR* fmt = &formats[i]; +// if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { +// // find its supported colorspace +// if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { +// caps->formats |= PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; +// } + +// } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { +// // find its supported colorspace +// if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { +// caps->formats |= PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB; +// } + +// } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { +// // find its supported colorspace +// if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { +// caps->formats |= PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; +// } + +// } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { +// // find its supported colorspace +// if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { +// caps->formats |= PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10; +// } +// } +// } + +// palFree(s_Graphics.allocator, formats); +// palFree(s_Graphics.allocator, modes); +// s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); + +// return PAL_RESULT_SUCCESS; +// } + +// static PalResult PAL_CALL vkCreateSwapchain( +// PalGPUCommandQueue* queue, +// PalGPUWindow* window, +// const PalSwapchainCreateInfo* info, +// PalSwapchain** outSwapchain) +// { +// Swapchain* swapchain = nullptr; +// CommandQueue* commandQueue = (CommandQueue*)queue; +// PhysicalQueue* phyQueue = commandQueue->phyQueue; + +// // check if we enabled swapchain feature +// if (!commandQueue->device->swapchain) { +// return PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED; +// } + +// swapchain = palAllocate(s_Graphics.allocator, sizeof(Swapchain), 0); +// if (!swapchain) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// swapchain->device = commandQueue->device; +// bool ret = vkCreateSurface(window, &swapchain->surface); +// if (!ret) { +// return PAL_RESULT_INVALID_GPU_WINDOW; +// } + +// VkSwapchainCreateInfoKHR createInfo = {0}; +// createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; +// createInfo.surface = swapchain->surface; +// createInfo.imageArrayLayers = info->bufferArrayLayerCount; +// createInfo.imageExtent.width = info->width; +// createInfo.imageExtent.height = info->height; +// createInfo.minImageCount = info->bufferCount; +// if (info->clipped) { +// createInfo.clipped = VK_TRUE; +// } + +// // sharing mode +// createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; +// if (info->sharingMode == PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT) { +// createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; +// // set up concurrrent queue families +// Uint32 count = 0; +// Uint32 familyQueus[32]; // should be more than enough +// familyQueus[count++] = phyQueue->familyIndex; + +// for (int i = 0; i < info->concurrentQueueCount; i++) { +// CommandQueue* tmp = (CommandQueue*)info->concurrentQueue[i]; +// if (tmp->phyQueue != phyQueue) { +// // different queue families. Add index +// familyQueus[count++] = tmp->phyQueue->familyIndex; +// } +// } + +// createInfo.queueFamilyIndexCount = count; +// createInfo.pQueueFamilyIndices = familyQueus; +// } + +// // present modes +// createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; +// if (info->presentMode == PAL_PRESENT_MODE_IMMEDIATE) { +// createInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + +// } else if (info->presentMode == PAL_PRESENT_MODE_MAILBOX) { +// createInfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR; +// } + +// // usage +// createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; +// if (info->usage == PAL_SWAPCHAIN_USAGE_TRANSFER_SRC) { +// createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + +// } else if (info->usage == PAL_SWAPCHAIN_USAGE_TRANSFER_DST) { +// createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + +// } else if (info->usage == PAL_SWAPCHAIN_USAGE_SAMPLED) { +// createInfo.imageUsage = VK_IMAGE_USAGE_SAMPLED_BIT; +// } + +// // composite alpha +// createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; +// if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_POST_MULTIPLIED) { +// createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; + +// } else if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED) { +// createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; +// } + +// // transform +// createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; +// if (info->transform == PAL_SWAPCHAIN_TRANSFORM_PORTRAIT) { +// createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; + +// } else if (info->transform == PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED) { +// createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; + +// } else if (info->transform == PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED) { +// createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; +// } + +// // format and colorspace +// createInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; +// createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; +// swapchain->format = VK_FORMAT_B8G8R8A8_UNORM; + +// if (info->format == PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB) { +// createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; +// createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; +// swapchain->format = VK_FORMAT_B8G8R8A8_SRGB; + +// } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB) { +// createInfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; +// createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; +// swapchain->format = VK_FORMAT_R8G8B8A8_UNORM; + +// } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10) { +// createInfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; +// createInfo.imageColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; +// swapchain->format = VK_FORMAT_R16G16B16A16_SFLOAT; +// } + +// // create swapchain +// VkResult result = swapchain->device->createSwapchain( +// swapchain->device->handle, +// &createInfo, +// &s_Vk.allocator, +// &swapchain->handle); + +// if (result != VK_SUCCESS) { +// s_Vk.destroySurface( +// s_Vk.instance, +// swapchain->surface, +// &s_Vk.allocator); + +// palFree(s_Graphics.allocator, swapchain); +// return vkResultToPal(result); +// } + +// // get all images of the created swapchain +// Int32 count = 0; +// result = swapchain->device->getSwapchainImages( +// swapchain->device->handle, +// swapchain->handle, +// &count, +// nullptr); + +// swapchain->buffers = palAllocate( +// s_Graphics.allocator, +// sizeof(VkImage) * count, +// 0); + +// if (!swapchain->buffers) { +// swapchain->device->destroySwapchain( +// swapchain->device->handle, +// swapchain->handle, +// &s_Vk.allocator +// ); + +// s_Vk.destroySurface( +// s_Vk.instance, +// swapchain->surface, +// &s_Vk.allocator); + +// palFree(s_Graphics.allocator, swapchain); +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// swapchain->bufferCount = count; +// swapchain->device->getSwapchainImages( +// swapchain->device->handle, +// swapchain->handle, +// &count, +// swapchain->buffers); + +// *outSwapchain = (PalSwapchain*)swapchain; +// return PAL_RESULT_SUCCESS; +// } + +// static void PAL_CALL vkDestroySwapchain(PalSwapchain* swapchain) +// { +// Swapchain* _swapchain = (Swapchain*)swapchain; +// _swapchain->device->destroySwapchain( +// _swapchain->device->handle, +// _swapchain->handle, +// &s_Vk.allocator +// ); + +// s_Vk.destroySurface(s_Vk.instance, _swapchain->surface, &s_Vk.allocator); +// palFree(s_Graphics.allocator, _swapchain->buffers); +// palFree(s_Graphics.allocator, _swapchain); +// } + +// static Uint32 PAL_CALL vkGetSwapchainBufferCount(PalSwapchain* swapchain) +// { +// Swapchain* _swapchain = (Swapchain*)swapchain; +// return _swapchain->bufferCount; +// } + +// static PalResult PAL_CALL vkCreateRenderTargetView( +// PalSwapchain* swapchain, +// Uint32 bufferIndex, +// PalRenderTargetView** outRtv) +// { +// VkResult result = VK_SUCCESS; +// RenderTargetView* rtv = nullptr; +// Swapchain* _swapchain = (Swapchain*)swapchain; +// if (bufferIndex < 0 && bufferIndex >= _swapchain->bufferCount) { +// return PAL_RESULT_INVALID_SWAPCHAIN_BUFFER_INDEX; +// } + +// VkImage buffer = _swapchain->buffers[bufferIndex]; +// rtv = palAllocate(s_Graphics.allocator, sizeof(RenderTargetView), 0); +// if (!rtv) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// VkImageViewCreateInfo createInfo = {0}; +// createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; +// createInfo.format = _swapchain->format; +// createInfo.image = buffer; +// createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; +// createInfo.subresourceRange.levelCount = 1; +// createInfo.subresourceRange.layerCount = 1; +// createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + +// result = s_Vk.createImageView( +// _swapchain->device->handle, +// &createInfo, +// &s_Vk.allocator, +// &rtv->handle); + +// if (result != VK_SUCCESS) { +// palFree(s_Graphics.allocator, rtv); +// return vkResultToPal(result); +// } + +// rtv->format = _swapchain->format; +// rtv->device = _swapchain->device; + +// *outRtv = (PalRenderTargetView*)rtv; +// return PAL_RESULT_SUCCESS; +// } + +// static void PAL_CALL vkDestroyRenderTargetView(PalRenderTargetView* rtv) +// { +// RenderTargetView* _rtv = (RenderTargetView*)rtv; +// s_Vk.destroyImageView(_rtv->device->handle, _rtv->handle, &s_Vk.allocator); +// palFree(s_Graphics.allocator, _rtv); +// } + +// static PalResult PAL_CALL vkQueryRenderPassCapabilities( +// PalSwapchain* swapchain, +// PalRenderPassCapabilities* caps) +// { +// Swapchain* _swapchain = (Swapchain*)swapchain; +// Device* device = (Device*)_swapchain->device; + +// VkPhysicalDeviceProperties props = {0}; +// s_Vk.getPhysicalDeviceProperties(device->phyDevice, &props); +// caps->maxColorAttachments = props.limits.maxColorAttachments; +// caps->maxMultiViews = device->multiViewCount; + +// return PAL_RESULT_SUCCESS; +// } + +// static PalResult PAL_CALL vkCreateRenderPass_( +// PalSwapchain* swapchain, +// PalRenderPassCreateInfo* info, +// PalRenderPass** outRenderPass) +// { +// VkResult result = VK_SUCCESS; +// RenderPass* renderPass = nullptr; +// Swapchain* _swapchain = (Swapchain*)swapchain; + +// renderPass = palAllocate(s_Graphics.allocator, sizeof(RenderPass), 0); +// if (!renderPass) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } - // build features and extensions capabilities - VkPhysicalDeviceFeatures coreFeatures = {0}; - if (features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { - coreFeatures.samplerAnisotropy = true; - } +// renderPass->device = _swapchain->device; +// if (_swapchain->device->dynamicRendering) { +// // we support dynamic rendering, just store the information +// renderPass->info = *info; +// renderPass->handle = nullptr; +// renderPass->framebuffer = nullptr; - if (features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { - coreFeatures.sampleRateShading = true; - } +// } else { +// // dynamic rendering not supported +// VkAttachmentDescription* attachmentDescs = nullptr; +// attachmentDescs = palAllocate( +// s_Graphics.allocator, +// sizeof(VkAttachmentDescription) * info->attachmentCount, +// 0); - if (features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { - coreFeatures.multiViewport = true; - } +// if (!attachmentDescs) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } - if (features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { - coreFeatures.tessellationShader = true; - } +// RenderTargetView* rtv = nullptr; +// for (int i = 0; i < info->attachmentCount; i++) { +// rtv = (RenderTargetView*)info->renderTargetView; +// PalRenderPassAttachmentInfo* aInfo = &info->attachments[i]; +// VkAttachmentDescription* aDesc = &attachmentDescs[i]; - if (features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { - coreFeatures.geometryShader = true; - } +// aDesc->format = rtv->format; +// aDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; +// aDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - if (features & PAL_GPU_FEATURE_SHADER_INT16) { - coreFeatures.shaderInt16 = true; - } +// // load op +// if (aInfo->loadOp == PAL_RENDER_PASS_LOAD_OP_CLEAR) { +// aDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - if (features & PAL_GPU_FEATURE_SHADER_INT64) { - coreFeatures.shaderInt64 = true; - } +// } else if (aInfo->loadOp == PAL_RENDER_PASS_LOAD_OP_LOAD) { +// aDesc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - if (features & PAL_GPU_FEATURE_SHADER_FLOAT64) { - coreFeatures.shaderFloat64 = true; - } +// } else if (aInfo->loadOp == PAL_RENDER_PASS_LOAD_OP_DONT_CARE) { +// aDesc->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; +// } - // extensions and features2 - int extCount = 0; - const char* extensions[16] = {0}; +// // store op +// if (aInfo->storeOp == PAL_RENDER_PASS_STORE_OP_STORE) { +// aDesc->storeOp = VK_ATTACHMENT_STORE_OP_STORE; - // clang-format off +// } else if (aInfo->storeOp == PAL_RENDER_PASS_STORE_OP_DONT_CARE) { +// aDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; +// } +// } - const void* start = nullptr; - VkPhysicalDeviceTimelineSemaphoreFeatures timeline = {0}; - timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; - VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; - shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; +// attachmentDesc. - VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; - mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; - VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; - VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; - ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs = {0}; - vrs.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; - VkPhysicalDeviceDescriptorIndexingFeatures descIndex = {0}; - descIndex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; - VkPhysicalDeviceMultiviewFeatures multiView = {0}; - multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; +// VkRenderPassCreateInfo createInfo = {0}; +// createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; +// } - // clang-format on +// *outRenderPass = (PalRenderPass*)renderPass; +// return PAL_RESULT_SUCCESS; +// } - if (features & PAL_GPU_FEATURE_SWAPCHAIN) { - extensions[extCount++] = "VK_KHR_swapchain"; - device->swapchain = true; - } +// static void PAL_CALL vkDestroyRenderPass_(PalRenderPass* renderPass) +// { - if (features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { - extensions[extCount++] = "VK_KHR_dynamic_rendering"; - device->dynamicRendering = true; - } +// } - if (features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { - extensions[extCount++] = "VK_KHR_timeline_semaphore"; - timeline.timelineSemaphore = true; - start = &timeline; - } +static PalGPUBackend s_VkBackend = { + // adapter + .enumerateAdapters = vkEnumerateAdapters, + .getAdapterInfo = vkGetAdapterInfo, + .getAdapterCapabilities = vkGetAdapterCapabilities, - if (features & PAL_GPU_FEATURE_SHADER_FLOAT16) { - extensions[extCount++] = "VK_KHR_shader_float16_int8"; - shader16.shaderFloat16 = true; + // device + // .createGPUDevice = vkCreateGPUDevice, + // .destroyGPUDevice = vkDestroyGPUDevice, + + // // command queue + // .createGPUCommandQueue = vkCreateGPUCommandQueue, + // .destroyGPUCommandQueue = vkDestroyGPUCommandQueue, + // .canCommandQueuePresent = vkCanCommandQueuePresent, + + // // swapchain + // .querySwapchainCapabilities = vkQuerySwapchainCapabilities, + // .createSwapchain = vkCreateSwapchain, + // .destroySwapchain = vkDestroySwapchain, + // .getSwapchainBufferCount = vkGetSwapchainBufferCount, + + // // render target view + // .createRenderTargetView = vkCreateRenderTargetView, + // .destroyRenderTargetView = vkDestroyRenderTargetView, + + // // render pass + // .queryRenderPassCapabilities = vkQueryRenderPassCapabilities, + // .createRenderPass = vkCreateRenderPass_, + // .destroyRenderPass = vkDestroyRenderPass_ +}; - if (timeline.timelineSemaphore) { - timeline.pNext = &shader16; - } - start = &shader16; - } +#endif // PAL_HAS_VULKAN - if (features & PAL_GPU_FEATURE_RAY_TRACING) { - extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; - extensions[extCount++] = "VK_KHR_acceleration_structure"; - ray.rayTracingPipeline = true; - acc.accelerationStructure = true; - - if (shader16.shaderFloat16) { - shader16.pNext = &ray; +// ================================================== +// Public API +// ================================================== - } else if (timeline.timelineSemaphore) { - // no shader16, check timeline - timeline.pNext = &ray; - } - ray.pNext = &acc; - start = &ray; +PalResult PAL_CALL palInitGraphics( + bool enableDebugLayer, + const PalAllocator* allocator) +{ + if (s_Graphics.initialized) { + return PAL_RESULT_SUCCESS; } - if (features & PAL_GPU_FEATURE_MESH_SHADER) { - extensions[extCount++] = "VK_EXT_mesh_shader"; - mesh.meshShader = true; - mesh.taskShader = true; - - if (acc.accelerationStructure) { - acc.pNext = &mesh; - - } else if (shader16.shaderFloat16) { - shader16.pNext = &mesh; - - } else if (timeline.timelineSemaphore) { - timeline.pNext = &mesh; - } - start = &mesh; + if (allocator && (!allocator->allocate || !allocator->free)) { + return PAL_RESULT_INVALID_ALLOCATOR; } - if (features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { - extensions[extCount++] = "VK_KHR_fragment_shading_rate"; - vrs.pipelineFragmentShadingRate = true; - - if (mesh.meshShader) { - mesh.pNext = &vrs; - - } else if (acc.accelerationStructure) { - acc.pNext = &vrs; - - } else if (shader16.shaderFloat16) { - shader16.pNext = &vrs; + s_Graphics.allocator = allocator; + s_Graphics.maxHandleData = 32; + s_Graphics.handleData = palAllocate( + s_Graphics.allocator, + sizeof(HandleData) * s_Graphics.maxHandleData, + 0); - } else if (timeline.timelineSemaphore) { - timeline.pNext = &vrs; - } - start = &vrs; + if (!s_Graphics.handleData) { + return PAL_RESULT_OUT_OF_MEMORY; } - if (features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { - extensions[extCount++] = "VK_EXT_descriptor_indexing"; - descIndex.shaderSampledImageArrayNonUniformIndexing = true; - - if (vrs.pipelineFragmentShadingRate) { - vrs.pNext = &descIndex; - - } else if (mesh.meshShader) { - mesh.pNext = &descIndex; - - } else if (acc.accelerationStructure) { - acc.pNext = &descIndex; - - } else if (shader16.shaderFloat16) { - shader16.pNext = &descIndex; - - } else if (timeline.timelineSemaphore) { - timeline.pNext = &descIndex; - } - start = &descIndex; +#if PAL_HAS_VULKAN + PalResult ret = vkInitGraphics(enableDebugLayer); + if (ret != PAL_RESULT_SUCCESS) { + return ret; } - if (features & PAL_GPU_FEATURE_MULTI_VIEW) { - extensions[extCount++] = "VK_KHR_multiview"; - multiView.multiview = true; - device->multiView = true; - - VkPhysicalDeviceMultiviewPropertiesKHR p = {0}; - p.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; - - VkPhysicalDeviceProperties2 props = {0}; - props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - props.pNext = &p; - s_Vk.getPhysicalDeviceProperties2(phyDevice, &props); - device->multiViewCount = p.maxMultiviewViewCount; + BackendData* backend = &s_Graphics.backends[s_Graphics.backendCount++]; + backend->base = &s_VkBackend; + backend->count = 0; + backend->startIndex = 0; +#endif // PAL_HAS_VULKAN - if (descIndex.shaderSampledImageArrayNonUniformIndexing) { - descIndex.pNext = &multiView; + s_Graphics.initialized = true; + return PAL_RESULT_SUCCESS; +} - } else if (vrs.pipelineFragmentShadingRate) { - vrs.pNext = &multiView; +void PAL_CALL palShutdownGraphics() +{ + if (!s_Graphics.initialized) { + return; + } - } else if (mesh.meshShader) { - mesh.pNext = &multiView; +#if PAL_HAS_VULKAN + vkShutdownGraphics(); +#endif // PAL_HAS_VULKAN - } else if (acc.accelerationStructure) { - acc.pNext = &multiView; + palFree(s_Graphics.allocator, s_Graphics.handleData); + memset(&s_Graphics, 0, sizeof(s_Graphics)); + s_Graphics.initialized = false; +} - } else if (shader16.shaderFloat16) { - shader16.pNext = &multiView; +// ================================================== +// GPU Adapter +// ================================================== - } else if (timeline.timelineSemaphore) { - timeline.pNext = &multiView; - } - start = &multiView; +PalResult PAL_CALL palEnumerateAdapters( + Int32* count, + PalAdapter** outAdapters) +{ + // enumerate all adapters for both custom and PAL backends + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - VkDeviceCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - createInfo.pEnabledFeatures = &coreFeatures; - createInfo.enabledExtensionCount = extCount; - createInfo.ppEnabledExtensionNames = extensions; - createInfo.pQueueCreateInfos = queueCreateInfos; - createInfo.queueCreateInfoCount = count; - createInfo.pNext = start; - - ret = s_Vk.createDevice( - phyDevice, - &createInfo, - &s_Vk.allocator, - &device->handle); - - if (ret != VK_SUCCESS) { - palFree(s_Graphics.allocator, queueProps); - palFree(s_Graphics.allocator, queueCreateInfos); - palFree(s_Graphics.allocator, device->phyQueues); - palFree(s_Graphics.allocator, device); - return vkResultToPal(ret); + if (!count) { + return PAL_RESULT_NULL_POINTER; } - // get queues - for (int i = 0; i < count; i++) { - VkQueueFamilyProperties* data = &queueProps[i]; - for (int j = 0; j < data->queueCount; j++) { - PhysicalQueue* queue = &device->phyQueues[i]; - s_Vk.getDeviceQueue(device->handle, i, j, &queue->handle); - queue->usages = data->queueFlags; - queue->usedUsages = 0; - queue->familyIndex = i; - queue->phyDevice = phyDevice; - } + if (*count == 0 && outAdapters) { + return PAL_RESULT_INSUFFICIENT_BUFFER; } - // load procs - device->acquireNextImage = (vkAcquireNextImageKHRFn)s_Vk.getDeviceProcAddr( - device->handle, - "vkAcquireNextImageKHR"); - - device->createSwapchain = (vkCreateSwapchainKHRFn)s_Vk.getDeviceProcAddr( - device->handle, - "vkCreateSwapchainKHR"); + PalResult result; + int totalCount = 0; + int index = 0; - device->destroySwapchain = (vkDestroySwapchainKHRFn)s_Vk.getDeviceProcAddr( - device->handle, - "vkDestroySwapchainKHR"); + int _count = outAdapters ? *count : 0; + for (int i = 0; i < s_Graphics.backendCount; i++) { + BackendData* backend = &s_Graphics.backends[i]; + if (outAdapters) { + // offset into the array so all backends write at the correct index + PalAdapter** adapters = &outAdapters[backend->startIndex]; + result = backend->base->enumerateAdapters(&_count, adapters); - device->getSwapchainImages = (vkGetSwapchainImagesKHRFn)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetSwapchainImagesKHR"); + for (int i = 0; i < backend->count; i++) { + HandleData* data = getFreeHandleData(); + data->backend = backend->base; + data->handle = adapters[i]; + } - device->queuePresent = (vkQueuePresentKHRFn)s_Vk.getDeviceProcAddr( - device->handle, - "vkQueuePresentKHR"); + } else { + result = backend->base->enumerateAdapters(&_count, nullptr); + backend->startIndex = totalCount; + backend->count = _count; + totalCount += _count; + _count = 0; + } + + // break if a backend fails + if (result != PAL_RESULT_SUCCESS) { + return result; + } + } - palFree(s_Graphics.allocator, queueProps); - palFree(s_Graphics.allocator, queueCreateInfos); + if (!outAdapters) { + *count = totalCount; + } - *outDevice = (PalGPUDevice*)device; return PAL_RESULT_SUCCESS; } -static void PAL_CALL vkDestroyGPUDevice(PalGPUDevice* device) -{ - Device* gpuDevice = (Device*)device; - s_Vk.destroyDevice(gpuDevice->handle, &s_Vk.allocator); - palFree(s_Graphics.allocator, gpuDevice->phyQueues); - palFree(s_Graphics.allocator, gpuDevice); -} - -static PalResult PAL_CALL vkCreateGPUCommandQueue( - PalGPUDevice* device, - PalGPUCommandQueueType type, - PalGPUCommandQueue** outQueue) +PalResult PAL_CALL palGetAdapterInfo( + PalAdapter* adapter, + PalAdapterInfo* info) { - VkQueueFlags queueFlag = 0; - Device* gpuDevice = (Device*)device; - CommandQueue* commandQueue = nullptr; - if (!gpuDevice->handle) { - return PAL_RESULT_INVALID_GPU_DEVICE; - } - - if (gpuDevice->queueCount == 0) { - return PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE; - } - - switch (type) { - case PAL_GPU_COMMAND_QUEUE_TYPE_COMPUTE: { - queueFlag = VK_QUEUE_COMPUTE_BIT; - break; - } - - case PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS: { - queueFlag = VK_QUEUE_GRAPHICS_BIT; - break; - } - - case PAL_GPU_COMMAND_QUEUE_TYPE_COPY: { - queueFlag = VK_QUEUE_TRANSFER_BIT; - break; - } + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - PhysicalQueue* phyQueue = nullptr; - for (int i = 0; i < gpuDevice->queueCount; i++) { - PhysicalQueue* queue = &gpuDevice->phyQueues[i]; - // check if the physical queue supports the requested operation - // and if its not already used - if (queue->usages & queueFlag && - queue->usedUsages != queueFlag) { - queue->usedUsages |= queueFlag; - phyQueue = queue; - break; - } + if (!adapter || !info) { + return PAL_RESULT_NULL_POINTER; } - if (phyQueue) { - commandQueue = palAllocate( - s_Graphics.allocator, - sizeof(CommandQueue), - 0); - - if (!commandQueue) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - commandQueue->phyQueue = phyQueue; - commandQueue->usage = queueFlag; - commandQueue->device = gpuDevice; - - *outQueue = (PalGPUCommandQueue*)commandQueue; - return PAL_RESULT_SUCCESS; + HandleData* data = findHandleData(adapter); + if (data) { + return data->backend->getAdapterInfo(adapter, info); } - return PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE; + return PAL_RESULT_INVALID_GPU_ADAPTER; } -static void PAL_CALL vkDestroyGPUCommandQueue(PalGPUCommandQueue* queue) +PalResult PAL_CALL palGetAdapterCapabilities( + PalAdapter* adapter, + PalAdapterCapabilities* caps) { - CommandQueue* commandQueue = (CommandQueue*)queue; - PhysicalQueue* phyQueue = commandQueue->phyQueue; - phyQueue->usedUsages &= ~commandQueue->usage; - palFree(s_Graphics.allocator, commandQueue); -} + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } -static bool PAL_CALL vkCanCommandQueuePresent( - PalGPUCommandQueue* queue, - PalGPUWindow* window) -{ - bool onWayland = vkOnWayland(window->display); - CommandQueue* commandQueue = (CommandQueue*)queue; - PhysicalQueue* phyQueue = commandQueue->phyQueue; - - if (!s_Vk.checkWaylandPresentSupport( - phyQueue->phyDevice, - phyQueue->familyIndex, window->display)) { - return false; - } else { - // TODO: check presentation for xlib + if (!adapter || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = findHandleData(adapter); + if (data) { + return data->backend->getAdapterCapabilities(adapter, caps); } - return true; + return PAL_RESULT_INVALID_GPU_ADAPTER; } -static PalResult PAL_CALL vkQuerySwapchainCapabilities( - PalGPUAdapter* adapter, - PalGPUWindow* window, - PalSwapchainCapabilities* caps) +PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) { - Int32 formatCount = 0; - Int32 modeCount = 0; - VkSurfaceKHR surface = nullptr; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; - VkPresentModeKHR* modes = nullptr; - VkSurfaceFormatKHR* formats = nullptr; - - bool ret = vkCreateSurface(window, &surface); - if (!ret) { - return PAL_RESULT_INVALID_GPU_WINDOW; + if (s_Graphics.initialized) { + return PAL_RESULT_INVALID_GPU_BACKEND; } - s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, nullptr); - s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, nullptr); - - modes = palAllocate( - s_Graphics.allocator, - sizeof(VkPresentModeKHR) * modeCount, - 0); - - formats = palAllocate( - s_Graphics.allocator, - sizeof(VkSurfaceFormatKHR) * formatCount, - 0); + // // check if all the function pointers are set + // // clang-format off + // if (!backend->enumerateGPUAdapters || + // !backend->getGPUAdapterInfo || + // !backend->getGPUAdapterCapabilities || + // !backend->createGPUDevice || + // !backend->destroyGPUDevice || + // !backend->createGPUCommandQueue || + // !backend->destroyGPUCommandQueue || + // !backend->canCommandQueuePresent || + // !backend->createSwapchain || + // !backend->destroySwapchain || + // !backend->querySwapchainCapabilities || + // !backend->getSwapchainBufferCount || + // !backend->createRenderTargetView || + // !backend->destroyRenderTargetView || + // !backend->queryRenderPassCapabilities || + // !backend->createRenderPass || + // !backend->destroyRenderPass) { + // return PAL_RESULT_INVALID_GPU_BACKEND; + // } + // // clang-format on - if (!modes || !formats) { - s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); - return PAL_RESULT_OUT_OF_MEMORY; - } + BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; + attached->base = backend; + attached->startIndex = 0; + attached->count = 0; - s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, modes); - s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, formats); + return PAL_RESULT_SUCCESS; +} - VkSurfaceCapabilitiesKHR surfaceCaps; - s_Vk.getSurfaceCapabilities(phyDevice, surface, &surfaceCaps); - caps->minWidth = surfaceCaps.minImageExtent.width; - caps->minHeight = surfaceCaps.minImageExtent.height; - caps->maxWidth = surfaceCaps.maxImageExtent.width; - caps->maxHeight = surfaceCaps.maxImageExtent.height; +// ================================================== +// GPU Device +// ================================================== - caps->maxBufferCount = surfaceCaps.maxImageCount; - caps->minBufferCount = surfaceCaps.minImageCount; - caps->maxBufferArrayLayers = surfaceCaps.maxImageArrayLayers; - - if (caps->maxBufferCount == 0) { - caps->maxBufferCount = PAL_INFINITE; - } - - // get supported transforms - VkSurfaceTransformFlagsKHR trans = surfaceCaps.supportedTransforms; - if (trans & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { - caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE; - } - - if (trans & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { - caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_PORTRAIT; - } - - if (trans & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) { - caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED; - } - - if (trans & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { - caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED; - } - - // get supported composite alphas - VkCompositeAlphaFlagsKHR alpha = surfaceCaps.supportedCompositeAlpha; - caps->compositeAlphas = PAL_COMPOSITE_ALPHA_OPAQUE; - if (alpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { - caps->compositeAlphas |= PAL_COMPOSITE_ALPHA_POST_MULTIPLIED; - } - - if (alpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { - caps->compositeAlphas |= PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED; - } - - // get supported composite alphas - VkImageUsageFlags usage = surfaceCaps.supportedUsageFlags; - caps->usages = 0; - if (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { - caps->usages |= PAL_SWAPCHAIN_USAGE_COLOR_ATTACHEMENT; - } - - if (usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { - caps->usages |= PAL_SWAPCHAIN_USAGE_TRANSFER_DST; - } - - if (usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { - caps->usages |= PAL_SWAPCHAIN_USAGE_TRANSFER_SRC; - } - - if (usage & VK_IMAGE_USAGE_SAMPLED_BIT) { - caps->usages |= PAL_SWAPCHAIN_USAGE_SAMPLED; - } - - // sharing modes - caps->sharingModes = PAL_SWAPCHAIN_SHARING_MODE_EXCLUSIVE; - caps->sharingModes |= PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT; - - // present modes - caps->presentModes = PAL_PRESENT_MODE_FIFO; - for (int i = 0; i < modeCount; i++) { - if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { - caps->presentModes |= PAL_PRESENT_MODE_IMMEDIATE; - } - - if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { - caps->presentModes |= PAL_PRESENT_MODE_MAILBOX; - } - } - - // get format and colorspace - for (int i = 0; i < formatCount; i++) { - VkSurfaceFormatKHR* fmt = &formats[i]; - if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { - // find its supported colorspace - if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats |= PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; - } - - } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { - // find its supported colorspace - if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats |= PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB; - } - - } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { - // find its supported colorspace - if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats |= PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - } - - } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { - // find its supported colorspace - if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { - caps->formats |= PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10; - } - } - } - - palFree(s_Graphics.allocator, formats); - palFree(s_Graphics.allocator, modes); - s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); - - return PAL_RESULT_SUCCESS; -} - -static PalResult PAL_CALL vkCreateSwapchain( - PalGPUCommandQueue* queue, - PalGPUWindow* window, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain) -{ - Swapchain* swapchain = nullptr; - CommandQueue* commandQueue = (CommandQueue*)queue; - PhysicalQueue* phyQueue = commandQueue->phyQueue; - - // check if we enabled swapchain feature - if (!commandQueue->device->swapchain) { - return PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED; - } - - swapchain = palAllocate(s_Graphics.allocator, sizeof(Swapchain), 0); - if (!swapchain) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - swapchain->device = commandQueue->device; - bool ret = vkCreateSurface(window, &swapchain->surface); - if (!ret) { - return PAL_RESULT_INVALID_GPU_WINDOW; - } - - VkSwapchainCreateInfoKHR createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.surface = swapchain->surface; - createInfo.imageArrayLayers = info->bufferArrayLayerCount; - createInfo.imageExtent.width = info->width; - createInfo.imageExtent.height = info->height; - createInfo.minImageCount = info->bufferCount; - if (info->clipped) { - createInfo.clipped = VK_TRUE; - } - - // sharing mode - createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (info->sharingMode == PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT) { - createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - // set up concurrrent queue families - Uint32 count = 0; - Uint32 familyQueus[32]; // should be more than enough - familyQueus[count++] = phyQueue->familyIndex; - - for (int i = 0; i < info->concurrentQueueCount; i++) { - CommandQueue* tmp = (CommandQueue*)info->concurrentQueue[i]; - if (tmp->phyQueue != phyQueue) { - // different queue families. Add index - familyQueus[count++] = tmp->phyQueue->familyIndex; - } - } - - createInfo.queueFamilyIndexCount = count; - createInfo.pQueueFamilyIndices = familyQueus; - } - - // present modes - createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; - if (info->presentMode == PAL_PRESENT_MODE_IMMEDIATE) { - createInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; - - } else if (info->presentMode == PAL_PRESENT_MODE_MAILBOX) { - createInfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR; - } - - // usage - createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - if (info->usage == PAL_SWAPCHAIN_USAGE_TRANSFER_SRC) { - createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - - } else if (info->usage == PAL_SWAPCHAIN_USAGE_TRANSFER_DST) { - createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; - - } else if (info->usage == PAL_SWAPCHAIN_USAGE_SAMPLED) { - createInfo.imageUsage = VK_IMAGE_USAGE_SAMPLED_BIT; - } - - // composite alpha - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_POST_MULTIPLIED) { - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; - - } else if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED) { - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; - } - - // transform - createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - if (info->transform == PAL_SWAPCHAIN_TRANSFORM_PORTRAIT) { - createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; - - } else if (info->transform == PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED) { - createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; - - } else if (info->transform == PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED) { - createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; - } - - // format and colorspace - createInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; - createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - swapchain->format = VK_FORMAT_B8G8R8A8_UNORM; - - if (info->format == PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB) { - createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; - createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - swapchain->format = VK_FORMAT_B8G8R8A8_SRGB; - - } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB) { - createInfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; - createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - swapchain->format = VK_FORMAT_R8G8B8A8_UNORM; - - } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10) { - createInfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; - createInfo.imageColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; - swapchain->format = VK_FORMAT_R16G16B16A16_SFLOAT; - } - - // create swapchain - VkResult result = swapchain->device->createSwapchain( - swapchain->device->handle, - &createInfo, - &s_Vk.allocator, - &swapchain->handle); - - if (result != VK_SUCCESS) { - s_Vk.destroySurface( - s_Vk.instance, - swapchain->surface, - &s_Vk.allocator); - - palFree(s_Graphics.allocator, swapchain); - return vkResultToPal(result); - } - - // get all images of the created swapchain - Int32 count = 0; - result = swapchain->device->getSwapchainImages( - swapchain->device->handle, - swapchain->handle, - &count, - nullptr); - - swapchain->buffers = palAllocate( - s_Graphics.allocator, - sizeof(VkImage) * count, - 0); - - if (!swapchain->buffers) { - swapchain->device->destroySwapchain( - swapchain->device->handle, - swapchain->handle, - &s_Vk.allocator - ); - - s_Vk.destroySurface( - s_Vk.instance, - swapchain->surface, - &s_Vk.allocator); - - palFree(s_Graphics.allocator, swapchain); - return PAL_RESULT_OUT_OF_MEMORY; - } - - swapchain->bufferCount = count; - swapchain->device->getSwapchainImages( - swapchain->device->handle, - swapchain->handle, - &count, - swapchain->buffers); - - *outSwapchain = (PalSwapchain*)swapchain; - return PAL_RESULT_SUCCESS; -} - -static void PAL_CALL vkDestroySwapchain(PalSwapchain* swapchain) -{ - Swapchain* _swapchain = (Swapchain*)swapchain; - _swapchain->device->destroySwapchain( - _swapchain->device->handle, - _swapchain->handle, - &s_Vk.allocator - ); - - s_Vk.destroySurface(s_Vk.instance, _swapchain->surface, &s_Vk.allocator); - palFree(s_Graphics.allocator, _swapchain->buffers); - palFree(s_Graphics.allocator, _swapchain); -} - -static Uint32 PAL_CALL vkGetSwapchainBufferCount(PalSwapchain* swapchain) -{ - Swapchain* _swapchain = (Swapchain*)swapchain; - return _swapchain->bufferCount; -} - -static PalResult PAL_CALL vkCreateRenderTargetView( - PalSwapchain* swapchain, - Uint32 bufferIndex, - PalRenderTargetView** outRtv) -{ - VkResult result = VK_SUCCESS; - RenderTargetView* rtv = nullptr; - Swapchain* _swapchain = (Swapchain*)swapchain; - if (bufferIndex < 0 && bufferIndex >= _swapchain->bufferCount) { - return PAL_RESULT_INVALID_SWAPCHAIN_BUFFER_INDEX; - } - - VkImage buffer = _swapchain->buffers[bufferIndex]; - rtv = palAllocate(s_Graphics.allocator, sizeof(RenderTargetView), 0); - if (!rtv) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkImageViewCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.format = _swapchain->format; - createInfo.image = buffer; - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.layerCount = 1; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - result = s_Vk.createImageView( - _swapchain->device->handle, - &createInfo, - &s_Vk.allocator, - &rtv->handle); - - if (result != VK_SUCCESS) { - palFree(s_Graphics.allocator, rtv); - return vkResultToPal(result); - } - - rtv->device = _swapchain->device; - *outRtv = (PalRenderTargetView*)rtv; - return PAL_RESULT_SUCCESS; -} - -static void PAL_CALL vkDestroyRenderTargetView(PalRenderTargetView* rtv) -{ - RenderTargetView* _rtv = (RenderTargetView*)rtv; - s_Vk.destroyImageView(_rtv->device->handle, _rtv->handle, &s_Vk.allocator); - palFree(s_Graphics.allocator, _rtv); -} - -static PalResult PAL_CALL vkQueryRenderPassCapabilities( - PalSwapchain* swapchain, - PalRenderPassCapabilities* caps) -{ - Swapchain* _swapchain = (Swapchain*)swapchain; - Device* device = (Device*)_swapchain->device; - - VkPhysicalDeviceProperties props = {0}; - s_Vk.getPhysicalDeviceProperties(device->phyDevice, &props); - caps->maxColorAttachments = props.limits.maxColorAttachments; - caps->maxMultiViews = device->multiViewCount; - - return PAL_RESULT_SUCCESS; -} - -static PalResult PAL_CALL vkCreateRenderPass_( - PalSwapchain* swapchain, - PalRenderPassCreateInfo* info, - PalRenderPass** outRenderPass) -{ - VkResult result = VK_SUCCESS; - RenderPass* renderPass = nullptr; - Swapchain* _swapchain = (Swapchain*)swapchain; - - renderPass = palAllocate(s_Graphics.allocator, sizeof(RenderPass), 0); - if (!renderPass) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkRenderPassCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - - *outRenderPass = (PalRenderPass*)renderPass; - return PAL_RESULT_SUCCESS; -} - -static void PAL_CALL vkDestroyRenderPass_(PalRenderPass* renderPass) -{ - -} - -static PalGPUBackend s_VkBackend = { - // adapter - .enumerateGPUAdapters = vkEnumerateAdapters, - .getGPUAdapterInfo = vkGetAdapterInfo, - .getGPUAdapterCapabilities = vkGetAdapterCapabilities, - - // device - .createGPUDevice = vkCreateGPUDevice, - .destroyGPUDevice = vkDestroyGPUDevice, - - // command queue - .createGPUCommandQueue = vkCreateGPUCommandQueue, - .destroyGPUCommandQueue = vkDestroyGPUCommandQueue, - .canCommandQueuePresent = vkCanCommandQueuePresent, - - // swapchain - .querySwapchainCapabilities = vkQuerySwapchainCapabilities, - .createSwapchain = vkCreateSwapchain, - .destroySwapchain = vkDestroySwapchain, - .getSwapchainBufferCount = vkGetSwapchainBufferCount, - - // render target view - .createRenderTargetView = vkCreateRenderTargetView, - .destroyRenderTargetView = vkDestroyRenderTargetView, - - // render pass - .queryRenderPassCapabilities = vkQueryRenderPassCapabilities, - .createRenderPass = vkCreateRenderPass_, - .destroyRenderPass = vkDestroyRenderPass_ -}; - -#endif // PAL_HAS_VULKAN - -// ================================================== -// Public API -// ================================================== - -PalResult PAL_CALL palInitGraphics( - bool enableDebugLayer, - const PalAllocator* allocator) -{ - if (s_Graphics.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - - s_Graphics.allocator = allocator; - s_Graphics.maxHandleData = 32; - s_Graphics.handleData = palAllocate( - s_Graphics.allocator, - sizeof(HandleData) * s_Graphics.maxHandleData, - 0); - - if (!s_Graphics.handleData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - -#if PAL_HAS_VULKAN - PalResult ret = vkInitGraphics(enableDebugLayer); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - BackendData* backend = &s_Graphics.backends[s_Graphics.backendCount++]; - backend->base = &s_VkBackend; - backend->count = 0; - backend->startIndex = 0; -#endif // PAL_HAS_VULKAN - - s_Graphics.initialized = true; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palShutdownGraphics() -{ - if (!s_Graphics.initialized) { - return; - } - -#if PAL_HAS_VULKAN - vkShutdownGraphics(); -#endif // PAL_HAS_VULKAN - - palFree(s_Graphics.allocator, s_Graphics.handleData); - memset(&s_Graphics, 0, sizeof(s_Graphics)); - s_Graphics.initialized = false; -} - -// ================================================== -// GPU Adapter -// ================================================== - -PalResult PAL_CALL palEnumerateGPUAdapters( - Int32* count, - PalGPUAdapter** outAdapters) -{ - // enumerate all adapters for both custom and PAL backends - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!count) { - return PAL_RESULT_NULL_POINTER; - } - - if (*count == 0 && outAdapters) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - PalResult result; - int totalCount = 0; - int index = 0; - - int _count = outAdapters ? *count : 0; - for (int i = 0; i < s_Graphics.backendCount; i++) { - BackendData* backend = &s_Graphics.backends[i]; - if (outAdapters) { - // offset into the array so all backends write at the correct index - PalGPUAdapter** adapters = &outAdapters[backend->startIndex]; - result = backend->base->enumerateGPUAdapters(&_count, adapters); - - for (int i = 0; i < backend->count; i++) { - HandleData* data = getFreeHandleData(); - data->backend = backend->base; - data->handle = adapters[i]; - } - - } else { - result = backend->base->enumerateGPUAdapters(&_count, nullptr); - backend->startIndex = totalCount; - backend->count = _count; - totalCount += _count; - _count = 0; - } - - // break if a backend fails - if (result != PAL_RESULT_SUCCESS) { - return result; - } - } - - if (!outAdapters) { - *count = totalCount; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetGPUAdapterInfo( - PalGPUAdapter* adapter, - PalGPUAdapterInfo* info) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!adapter || !info) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = findHandleData(adapter); - if (data) { - return data->backend->getGPUAdapterInfo(adapter, info); - } - - return PAL_RESULT_INVALID_GPU_ADAPTER; -} - -PalResult PAL_CALL palGetGPUAdapterCapabilities( - PalGPUAdapter* adapter, - PalGPUAdapterCapabilities* caps) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!adapter || !caps) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = findHandleData(adapter); - if (data) { - return data->backend->getGPUAdapterCapabilities(adapter, caps); - } - - return PAL_RESULT_INVALID_GPU_ADAPTER; -} - -PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) -{ - if (s_Graphics.initialized) { - return PAL_RESULT_INVALID_GPU_BACKEND; - } - - // check if all the function pointers are set - // clang-format off - if (!backend->enumerateGPUAdapters || - !backend->getGPUAdapterInfo || - !backend->getGPUAdapterCapabilities || - !backend->createGPUDevice || - !backend->destroyGPUDevice || - !backend->createGPUCommandQueue || - !backend->destroyGPUCommandQueue || - !backend->canCommandQueuePresent || - !backend->createSwapchain || - !backend->destroySwapchain || - !backend->querySwapchainCapabilities || - !backend->getSwapchainBufferCount || - !backend->createRenderTargetView || - !backend->destroyRenderTargetView || - !backend->queryRenderPassCapabilities || - !backend->createRenderPass || - !backend->destroyRenderPass) { - return PAL_RESULT_INVALID_GPU_BACKEND; - } - // clang-format on - - BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; - attached->base = backend; - attached->startIndex = 0; - attached->count = 0; - - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// GPU Device -// ================================================== - -PalResult PAL_CALL palCreateGPUDevice( - PalGPUAdapter* adapter, - PalGPUFeatures features, - PalGPUDevice** outDevice) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!outDevice) { - return PAL_RESULT_NULL_POINTER; - } - - // check if the adapter is from PAL (custom or internal backend) - HandleData* adapterData = findHandleData(adapter); - if (!adapterData) { - return PAL_RESULT_INVALID_GPU_ADAPTER; - } - - PalGPUDevice* device = nullptr; - PalResult ret; - ret = adapterData->backend->createGPUDevice(adapter, features, &device); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // create a slot for the created device - HandleData* deviceData = getFreeHandleData(); - if (!deviceData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - deviceData->backend = adapterData->backend; - deviceData->handle = device; - - *outDevice = device; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device) -{ - if (s_Graphics.initialized && device) { - HandleData* data = findHandleData(device); - if (data) { - data->backend->destroyGPUDevice(device); - data->used = false; - } - } -} - -// ================================================== -// GPU Command Queue -// ================================================== - -PalResult PAL_CALL palCreateGPUCommandQueue( - PalGPUDevice* device, - PalGPUCommandQueueType type, - PalGPUCommandQueue** outQueue) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device || !outQueue) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = findHandleData(device); - if (!data) { - return PAL_RESULT_INVALID_GPU_DEVICE; - } - - PalGPUCommandQueue* queue = nullptr; - PalResult ret; - ret = data->backend->createGPUCommandQueue( - device, - type, - &queue); - - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // create a slot for the created command queue - HandleData* queueData = getFreeHandleData(); - if (!queueData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - queueData->backend = data->backend; - queueData->handle = queue; - - *outQueue = queue; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue) -{ - if (s_Graphics.initialized && queue) { - HandleData* data = findHandleData(queue); - if (data) { - data->backend->destroyGPUCommandQueue(queue); - data->used = false; - } - } -} - -bool PAL_CALL palCanCommandQueuePresent( - PalGPUCommandQueue* queue, - PalGPUWindow* window) -{ - if (s_Graphics.initialized && queue) { - HandleData* data = findHandleData(queue); - if (data) { - return data->backend->canCommandQueuePresent(queue, window); - } - return false; - } - return false; -} - -// ================================================== -// Swapchain -// ================================================== - -PalResult PAL_CALL palQuerySwapchainCapabilities( - PalGPUAdapter* adapter, - PalGPUWindow* window, - PalSwapchainCapabilities* caps) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!adapter || !window || !caps) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* adapterData = findHandleData(adapter); - if (!adapterData) { - return PAL_RESULT_INVALID_GPU_ADAPTER; - } - - return adapterData->backend->querySwapchainCapabilities( - adapter, - window, - caps); -} - -PalResult PAL_CALL palCreateSwapchain( - PalGPUCommandQueue* queue, - PalGPUWindow* window, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!queue || !window || !info || !outSwapchain) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* queueData = findHandleData(queue); - if (!queueData) { - return PAL_RESULT_INVALID_GPU_COMMAND_QUEUE; - } - - PalResult ret; - PalSwapchain* swapchain = nullptr; - ret = queueData->backend->createSwapchain(queue, window, info, &swapchain); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // create a slot for the created swapchain - HandleData* swapchainData = getFreeHandleData(); - if (!swapchainData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - swapchainData->backend = queueData->backend; - swapchainData->handle = swapchain; - - *outSwapchain = swapchain; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) -{ - if (s_Graphics.initialized && swapchain) { - HandleData* data = findHandleData(swapchain); - if (data) { - data->backend->destroySwapchain(swapchain); - data->used = false; - } - } -} - -Uint32 PAL_CALL palGetSwapchainBufferCount(PalSwapchain* swapchain) -{ - if (!s_Graphics.initialized || !swapchain) { - return 0; - } - - HandleData* swapchainData = findHandleData(swapchain); - if (!swapchainData) { - return 0; - } - - return swapchainData->backend->getSwapchainBufferCount(swapchain); -} - -// ================================================== -// Render Target View -// ================================================== - -PalResult PAL_CALL palCreateRenderTargetView( - PalSwapchain* swapchain, - Uint32 bufferIndex, - PalRenderTargetView** outRtv) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!swapchain || !outRtv) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* swapchainData = findHandleData(swapchain); - if (!swapchainData) { - return PAL_RESULT_INVALID_SWAPCHAIN; - } - - PalResult ret; - PalRenderTargetView* rtv = nullptr; - ret = swapchainData->backend->createRenderTargetView( - swapchain, - bufferIndex, - &rtv); - - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // create a slot for the created render target view - HandleData* rtvData = getFreeHandleData(); - if (!rtvData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - rtvData->backend = swapchainData->backend; - rtvData->handle = rtv; - - *outRtv = rtv; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv) -{ - if (s_Graphics.initialized && rtv) { - HandleData* data = findHandleData(rtv); - if (data) { - data->backend->destroyRenderTargetView(rtv); - data->used = false; - } - } -} - -// ================================================== -// Render Pass -// ================================================== - -PalResult PAL_CALL palQueryRenderPassCapabilities( - PalSwapchain* swapchain, - PalRenderPassCapabilities* caps) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!swapchain || !caps) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* swapchainData = findHandleData(swapchain); - if (!swapchainData) { - return PAL_RESULT_INVALID_SWAPCHAIN; - } - - return swapchainData->backend->queryRenderPassCapabilities( - swapchain, - caps); -} - -PalResult PAL_CALL palCreateRenderPass( - PalSwapchain* swapchain, - PalRenderPassCreateInfo* info, - PalRenderPass** outRenderPass) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!swapchain || !info || !outRenderPass) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* swapchainData = findHandleData(swapchain); - if (!swapchainData) { - return PAL_RESULT_INVALID_SWAPCHAIN; - } - - PalResult ret; - PalRenderPass* renderPass = nullptr; - ret = swapchainData->backend->createRenderPass( - swapchain, - info, - &renderPass); - - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // create a slot for the created render pass - HandleData* renderPassData = getFreeHandleData(); - if (!renderPassData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - renderPassData->backend = swapchainData->backend; - renderPassData->handle = renderPass; - - *outRenderPass = renderPass; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) -{ - if (s_Graphics.initialized && renderPass) { - HandleData* data = findHandleData(renderPass); - if (data) { - data->backend->destroyRenderPass(renderPass); - data->used = false; - } - } -} \ No newline at end of file +// PalResult PAL_CALL palCreateGPUDevice( +// PalGPUAdapter* adapter, +// PalGPUFeatures features, +// PalGPUDevice** outDevice) +// { +// if (!s_Graphics.initialized) { +// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; +// } + +// if (!outDevice) { +// return PAL_RESULT_NULL_POINTER; +// } + +// // check if the adapter is from PAL (custom or internal backend) +// HandleData* adapterData = findHandleData(adapter); +// if (!adapterData) { +// return PAL_RESULT_INVALID_GPU_ADAPTER; +// } + +// PalGPUDevice* device = nullptr; +// PalResult ret; +// ret = adapterData->backend->createGPUDevice(adapter, features, &device); +// if (ret != PAL_RESULT_SUCCESS) { +// return ret; +// } + +// // create a slot for the created device +// HandleData* deviceData = getFreeHandleData(); +// if (!deviceData) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// deviceData->backend = adapterData->backend; +// deviceData->handle = device; + +// *outDevice = device; +// return PAL_RESULT_SUCCESS; +// } + +// void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device) +// { +// if (s_Graphics.initialized && device) { +// HandleData* data = findHandleData(device); +// if (data) { +// data->backend->destroyGPUDevice(device); +// data->used = false; +// } +// } +// } + +// // ================================================== +// // GPU Command Queue +// // ================================================== + +// PalResult PAL_CALL palCreateGPUCommandQueue( +// PalGPUDevice* device, +// PalGPUCommandQueueType type, +// PalGPUCommandQueue** outQueue) +// { +// if (!s_Graphics.initialized) { +// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; +// } + +// if (!device || !outQueue) { +// return PAL_RESULT_NULL_POINTER; +// } + +// HandleData* data = findHandleData(device); +// if (!data) { +// return PAL_RESULT_INVALID_GPU_DEVICE; +// } + +// PalGPUCommandQueue* queue = nullptr; +// PalResult ret; +// ret = data->backend->createGPUCommandQueue( +// device, +// type, +// &queue); + +// if (ret != PAL_RESULT_SUCCESS) { +// return ret; +// } + +// // create a slot for the created command queue +// HandleData* queueData = getFreeHandleData(); +// if (!queueData) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// queueData->backend = data->backend; +// queueData->handle = queue; + +// *outQueue = queue; +// return PAL_RESULT_SUCCESS; +// } + +// void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue) +// { +// if (s_Graphics.initialized && queue) { +// HandleData* data = findHandleData(queue); +// if (data) { +// data->backend->destroyGPUCommandQueue(queue); +// data->used = false; +// } +// } +// } + +// bool PAL_CALL palCanCommandQueuePresent( +// PalGPUCommandQueue* queue, +// PalGPUWindow* window) +// { +// if (s_Graphics.initialized && queue) { +// HandleData* data = findHandleData(queue); +// if (data) { +// return data->backend->canCommandQueuePresent(queue, window); +// } +// return false; +// } +// return false; +// } + +// // ================================================== +// // Swapchain +// // ================================================== + +// PalResult PAL_CALL palQuerySwapchainCapabilities( +// PalGPUAdapter* adapter, +// PalGPUWindow* window, +// PalSwapchainCapabilities* caps) +// { +// if (!s_Graphics.initialized) { +// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; +// } + +// if (!adapter || !window || !caps) { +// return PAL_RESULT_NULL_POINTER; +// } + +// HandleData* adapterData = findHandleData(adapter); +// if (!adapterData) { +// return PAL_RESULT_INVALID_GPU_ADAPTER; +// } + +// return adapterData->backend->querySwapchainCapabilities( +// adapter, +// window, +// caps); +// } + +// PalResult PAL_CALL palCreateSwapchain( +// PalGPUCommandQueue* queue, +// PalGPUWindow* window, +// const PalSwapchainCreateInfo* info, +// PalSwapchain** outSwapchain) +// { +// if (!s_Graphics.initialized) { +// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; +// } + +// if (!queue || !window || !info || !outSwapchain) { +// return PAL_RESULT_NULL_POINTER; +// } + +// HandleData* queueData = findHandleData(queue); +// if (!queueData) { +// return PAL_RESULT_INVALID_GPU_COMMAND_QUEUE; +// } + +// PalResult ret; +// PalSwapchain* swapchain = nullptr; +// ret = queueData->backend->createSwapchain(queue, window, info, &swapchain); +// if (ret != PAL_RESULT_SUCCESS) { +// return ret; +// } + +// // create a slot for the created swapchain +// HandleData* swapchainData = getFreeHandleData(); +// if (!swapchainData) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } +// swapchainData->backend = queueData->backend; +// swapchainData->handle = swapchain; + +// *outSwapchain = swapchain; +// return PAL_RESULT_SUCCESS; +// } + +// void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) +// { +// if (s_Graphics.initialized && swapchain) { +// HandleData* data = findHandleData(swapchain); +// if (data) { +// data->backend->destroySwapchain(swapchain); +// data->used = false; +// } +// } +// } + +// Uint32 PAL_CALL palGetSwapchainBufferCount(PalSwapchain* swapchain) +// { +// if (!s_Graphics.initialized || !swapchain) { +// return 0; +// } + +// HandleData* swapchainData = findHandleData(swapchain); +// if (!swapchainData) { +// return 0; +// } + +// return swapchainData->backend->getSwapchainBufferCount(swapchain); +// } + +// // ================================================== +// // Render Target View +// // ================================================== + +// PalResult PAL_CALL palCreateRenderTargetView( +// PalSwapchain* swapchain, +// Uint32 bufferIndex, +// PalRenderTargetView** outRtv) +// { +// if (!s_Graphics.initialized) { +// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; +// } + +// if (!swapchain || !outRtv) { +// return PAL_RESULT_NULL_POINTER; +// } + +// HandleData* swapchainData = findHandleData(swapchain); +// if (!swapchainData) { +// return PAL_RESULT_INVALID_SWAPCHAIN; +// } + +// PalResult ret; +// PalRenderTargetView* rtv = nullptr; +// ret = swapchainData->backend->createRenderTargetView( +// swapchain, +// bufferIndex, +// &rtv); + +// if (ret != PAL_RESULT_SUCCESS) { +// return ret; +// } + +// // create a slot for the created render target view +// HandleData* rtvData = getFreeHandleData(); +// if (!rtvData) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// rtvData->backend = swapchainData->backend; +// rtvData->handle = rtv; + +// *outRtv = rtv; +// return PAL_RESULT_SUCCESS; +// } + +// void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv) +// { +// if (s_Graphics.initialized && rtv) { +// HandleData* data = findHandleData(rtv); +// if (data) { +// data->backend->destroyRenderTargetView(rtv); +// data->used = false; +// } +// } +// } + +// // ================================================== +// // Render Pass +// // ================================================== + +// PalResult PAL_CALL palQueryRenderPassCapabilities( +// PalSwapchain* swapchain, +// PalRenderPassCapabilities* caps) +// { +// if (!s_Graphics.initialized) { +// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; +// } + +// if (!swapchain || !caps) { +// return PAL_RESULT_NULL_POINTER; +// } + +// HandleData* swapchainData = findHandleData(swapchain); +// if (!swapchainData) { +// return PAL_RESULT_INVALID_SWAPCHAIN; +// } + +// return swapchainData->backend->queryRenderPassCapabilities( +// swapchain, +// caps); +// } + +// PalResult PAL_CALL palCreateRenderPass( +// PalSwapchain* swapchain, +// PalRenderPassCreateInfo* info, +// PalRenderPass** outRenderPass) +// { +// if (!s_Graphics.initialized) { +// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; +// } + +// if (!swapchain || !info || !outRenderPass) { +// return PAL_RESULT_NULL_POINTER; +// } + +// if (!info->attachments) { +// return PAL_RESULT_NULL_POINTER; +// } + +// if (info->attachmentCount == 0 && info->attachments) { +// return PAL_RESULT_INSUFFICIENT_BUFFER; +// } + +// HandleData* swapchainData = findHandleData(swapchain); +// if (!swapchainData) { +// return PAL_RESULT_INVALID_SWAPCHAIN; +// } + +// PalResult ret; +// PalRenderPass* renderPass = nullptr; +// ret = swapchainData->backend->createRenderPass( +// swapchain, +// info, +// &renderPass); + +// if (ret != PAL_RESULT_SUCCESS) { +// return ret; +// } + +// // create a slot for the created render pass +// HandleData* renderPassData = getFreeHandleData(); +// if (!renderPassData) { +// return PAL_RESULT_OUT_OF_MEMORY; +// } + +// renderPassData->backend = swapchainData->backend; +// renderPassData->handle = renderPass; + +// *outRenderPass = renderPass; +// return PAL_RESULT_SUCCESS; +// } + +// void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) +// { +// if (s_Graphics.initialized && renderPass) { +// HandleData* data = findHandleData(renderPass); +// if (data) { +// data->backend->destroyRenderPass(renderPass); +// data->used = false; +// } +// } +// } \ No newline at end of file diff --git a/tests/custom_graphics_backend_test.c b/tests/custom_graphics_backend_test.c deleted file mode 100644 index 5898faf8..00000000 --- a/tests/custom_graphics_backend_test.c +++ /dev/null @@ -1,372 +0,0 @@ - -#include "pal/pal_graphics.h" -#include "tests.h" - -// a simple custom backend -// for simplicity we are not going to add that much functionality -// to it -typedef struct { - PalGPUAdapterInfo adapterInfo; - PalGPUAdapterCapabilities caps; - // add more fields if needed -} CustomGPUAdapter; - -typedef struct { - CustomGPUAdapter* adapter; - // add more fields if needed -} CustomGPUDevice; - -typedef struct { - CustomGPUDevice* device; - PalGPUCommandQueueType type; - // add more fields if needed -} CustomGPUCommandQueue; - -typedef struct { - // we just have only two adapters for simplicity - CustomGPUAdapter adapters[2]; -} CustomGPUBackend; - -static CustomGPUBackend s_CustomGPU; - -// setup our state which we will use -// PAL does not need this call so we set it up -// before adding the backend to PAL -// you might need a shutdown function for the backend after PAL has shutdown -// if there is cleanup to do -static void initCustomBackend() { - // PAL needs the memory it in bytes - Uint64 byte = 1024 * 1024 * 1024; - - CustomGPUAdapter* adapter = &s_CustomGPU.adapters[0]; - adapter->adapterInfo.apiType = PAL_GPU_API_TYPE_D3D9; - adapter->adapterInfo.type = PAL_GPU_TYPE_INTEGRATED; - adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_DXBC; - adapter->adapterInfo.totalMemory = byte * 4; // 4 GB - strcpy(adapter->adapterInfo.versionString, "10_1"); - strcpy(adapter->adapterInfo.name, "Intel Arc A580"); - - adapter->caps.debugLayerSupported = true; - adapter->caps.features = PAL_GPU_FEATURE_RAY_TRACING; - adapter->caps.features |= PAL_GPU_FEATURE_SWAPCHAIN; - adapter->caps.maxComputeQueues = 1; - adapter->caps.maxGraphicsQueues = 1; - adapter->caps.maxCopyQueues = 2; - - // second adapter - adapter = &s_CustomGPU.adapters[1]; - adapter->adapterInfo.apiType = PAL_GPU_API_TYPE_OPENGL; - adapter->adapterInfo.type = PAL_GPU_TYPE_DISCRETE; - adapter->adapterInfo.shaderFormats = PAL_GPU_SHADER_FORMAT_SPIRV; - adapter->adapterInfo.shaderFormats |= PAL_GPU_SHADER_FORMAT_GLSL; - adapter->adapterInfo.totalMemory = byte * 6; // 6 GB - strcpy(adapter->adapterInfo.versionString, "4.4"); - strcpy(adapter->adapterInfo.name, "AMD Radeon RX 7700 XT"); - - adapter->caps.debugLayerSupported = true; - adapter->caps.features = PAL_GPU_FEATURE_RAY_TRACING; - adapter->caps.features |= PAL_GPU_FEATURE_SWAPCHAIN; - adapter->caps.features |= PAL_GPU_FEATURE_MESH_SHADER; - adapter->caps.maxComputeQueues = 1; - adapter->caps.maxGraphicsQueues = 4; - adapter->caps.maxCopyQueues = 4; -} - -static PalResult PAL_CALL customEnumerateGPUAdapters( - Int32* count, - PalGPUAdapter** outAdapters) -{ - if (outAdapters) { - for (int i = 0; i < 2 && i < *count; i++) { - PalGPUAdapter* adapter = (PalGPUAdapter*)&s_CustomGPU.adapters[i]; - outAdapters[i] = adapter; - } - - } else { - *count = 2; - } - - return PAL_RESULT_SUCCESS; -} - -static PalResult PAL_CALL customGetGPUAdapterInfo( - PalGPUAdapter* adapter, - PalGPUAdapterInfo* info) -{ - for (int i = 0; i < 2; i++) { - PalGPUAdapter* custom = (PalGPUAdapter*)&s_CustomGPU.adapters[i]; - if (custom == adapter) { - // make a copy - PalGPUAdapterInfo* gpuInfo = &s_CustomGPU.adapters[i].adapterInfo; - info->apiType = gpuInfo->apiType; - info->totalMemory = gpuInfo->totalMemory; - info->type = gpuInfo->type; - info->shaderFormats = gpuInfo->shaderFormats; - - strcpy(info->name, gpuInfo->name); - strcpy(info->versionString, gpuInfo->versionString); - return PAL_RESULT_SUCCESS; - } - } - - return PAL_RESULT_INVALID_GPU_ADAPTER; -} - -static PalResult PAL_CALL customGetGPUAdapterCapabilities( - PalGPUAdapter* adapter, - PalGPUAdapterCapabilities* caps) -{ - for (int i = 0; i < 2; i++) { - PalGPUAdapter* custom = (PalGPUAdapter*)&s_CustomGPU.adapters[i]; - if (custom == adapter) { - // make a copy - *caps = s_CustomGPU.adapters[i].caps; - return PAL_RESULT_SUCCESS; - } - } - - return PAL_RESULT_INVALID_GPU_ADAPTER; -} - -PalResult PAL_CALL customCreateGPUDevice( - PalGPUAdapter* adapter, - PalGPUFeatures features, - PalGPUDevice** outDevice) -{ - // very simple GPU device. Just an allocation - // no need for checks eithe, PAL does that already for you - // use any allocator you want but its best to use the same allocator - // passed to the graphics system - - CustomGPUDevice* device = nullptr; - device = palAllocate(nullptr, sizeof(CustomGPUDevice), 0); - if (!device) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // if your backend has more than one adapter - // check and create the device with that adapter - for (int i = 0; i < 2; i++) { - PalGPUAdapter* custom = (PalGPUAdapter*)&s_CustomGPU.adapters[i]; - if (adapter == custom) { - device->adapter = &s_CustomGPU.adapters[i]; - // additional info for the adapter - break; - } - } - - *outDevice = (PalGPUDevice*)device; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL customDestroyGPUDevice(PalGPUDevice* device) -{ - CustomGPUDevice* customDevice = (CustomGPUDevice*)device; - palFree(nullptr, device); -} - -static PalResult PAL_CALL customCreateGPUCommandQueue( - PalGPUDevice* device, - PalGPUCommandQueueType type, - PalGPUCommandQueue** outQueue) -{ - // implement -} - -void PAL_CALL customDestroyGPUCommandQueue(PalGPUCommandQueue* queue) -{ - // implement -} - -static PalGPUBackend s_CustomBackend = { - .enumerateGPUAdapters = customEnumerateGPUAdapters, - .getGPUAdapterInfo = customGetGPUAdapterInfo, - .getGPUAdapterCapabilities = customGetGPUAdapterCapabilities, - .createGPUDevice = customCreateGPUDevice, - .destroyGPUDevice = customDestroyGPUDevice, - .createGPUCommandQueue = customCreateGPUCommandQueue, - .destroyGPUCommandQueue = customDestroyGPUCommandQueue -}; - -bool customGraphicsBackendTest() -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Custom Graphics Backend Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - // do any initializtion before adding the backen to PAL - initCustomBackend(); - - // add the backend to the graphics system - PalResult result = palAddGPUBackend(&s_CustomBackend); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to add backend: %s", error); - return false; - } - - // initialize the graphics system - result = palInitGraphics(false, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; - } - - // enumerate all available GPUs from internal and custom backends - Int32 count = 0; - result = palEnumerateGPUAdapters(&count, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); - return false; - } - - if (count == 0) { - palLog(nullptr, "No Adapters found"); - return false; - } - palLog(nullptr, "Adapter (GPUs) Count: %d", count); - - // allocate an array of adapters or use a fixed array - // Example: PalGPUAdapter* adapters[12]; - PalGPUAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalGPUAdapter*) * count, 0); - if (!adapters) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - result = palEnumerateGPUAdapters(&count, adapters); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); - return false; - } - - // get information about all the adapters - PalGPUAdapterInfo info; - PalGPUAdapter* d3d9Adapter = nullptr; - - for (Int32 i = 0; i < count; i++) { - PalGPUAdapter* adapter = adapters[i]; - result = palGetGPUAdapterInfo(adapter, &info); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - palFree(nullptr, adapters); - return false; - } - - Uint32 memoryGb = info.totalMemory / (1024.0 * 1024.0 * 1024.0); - palLog(nullptr, "GPU Name: %s", info.name); - palLog(nullptr, " Total Memory %dGB", memoryGb); - palLog(nullptr, " API Version: %s", info.versionString); - - const char* typeString; - switch (info.type) { - case PAL_GPU_TYPE_INTEGRATED: { - typeString = "Integrated"; - break; - } - - case PAL_GPU_TYPE_VIRTUAL: { - typeString = "Virtual"; - break; - } - - case PAL_GPU_TYPE_DISCRETE: { - typeString = "Discrete"; - break; - } - - case PAL_GPU_TYPE_CPU: { - typeString = "CPU"; - break; - } - } - palLog(nullptr, " Type: %s", typeString); - - const char* apiTypeString; - switch (info.apiType) { - case PAL_GPU_API_TYPE_D3D12: { - apiTypeString = "D3D12"; - break; - } - - case PAL_GPU_API_TYPE_VULKAN: { - apiTypeString = "Vulkan"; - break; - } - - case PAL_GPU_API_TYPE_METAL: { - apiTypeString = "Metal"; - break; - } - - case PAL_GPU_API_TYPE_OPENGL: { - apiTypeString = "OpenGL"; - break; - } - - case PAL_GPU_API_TYPE_GLES: { - apiTypeString = "GLes"; - break; - } - - case PAL_GPU_API_TYPE_D3D11: { - apiTypeString = "D3D11"; - break; - } - - case PAL_GPU_API_TYPE_D3D9: { - apiTypeString = "D3D9"; - d3d9Adapter = adapter; - break; - } - - case PAL_GPU_API_TYPE_PPM: { - apiTypeString = "PPM"; - break; - } - } - palLog(nullptr, " API Type: %s", apiTypeString); - - // shader formats - palLog(nullptr, " Supported Shader Formats:"); - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_SPIRV) { - palLog(nullptr, " SPIRV"); - } - - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_DXIL) { - palLog(nullptr, " DXIL"); - } - - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_DXBC) { - palLog(nullptr, " DXBC"); - } - - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_GLSL) { - palLog(nullptr, " GLSL"); - } - - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_MSL) { - palLog(nullptr, " MSL"); - } - - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_PPM) { - palLog(nullptr, " PPM"); - } - - palLog(nullptr, ""); - } - - // shutdown the graphics system - palShutdownGraphics(); - - palFree(nullptr, adapters); - - return true; -} \ No newline at end of file diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 0034beb0..86cf0cee 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -18,43 +18,43 @@ bool graphicsTest() return false; } - // enumerate all available GPUs from internal and custom backends + // enumerate all available adapters Int32 count = 0; - result = palEnumerateGPUAdapters(&count, nullptr); + result = palEnumerateAdapters(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + palLog(nullptr, "Failed to get query adapters: %s", error); return false; } if (count == 0) { - palLog(nullptr, "No Adapters found"); + palLog(nullptr, "No adapters found"); return false; } - palLog(nullptr, "Adapter (GPUs) Count: %d", count); + palLog(nullptr, "Adapter count: %d", count); // allocate an array of adapters or use a fixed array - // Example: PalGPUAdapter* adapters[12]; - PalGPUAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalGPUAdapter*) * count, 0); + // Example: PalAdapter* adapters[12]; + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); return false; } - result = palEnumerateGPUAdapters(&count, adapters); + result = palEnumerateAdapters(&count, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + palLog(nullptr, "Failed to get query adapters: %s", error); return false; } // get information about all the adapters - PalGPUAdapterInfo info; - PalGPUAdapterCapabilities caps; + PalAdapterInfo info; + PalAdapterCapabilities caps; for (Int32 i = 0; i < count; i++) { - PalGPUAdapter* adapter = adapters[i]; - result = palGetGPUAdapterInfo(adapter, &info); + PalAdapter* adapter = adapters[i]; + result = palGetAdapterInfo(adapter, &info); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); @@ -62,7 +62,7 @@ bool graphicsTest() return false; } - result = palGetGPUAdapterCapabilities(adapter, &caps); + result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); @@ -70,29 +70,34 @@ bool graphicsTest() return false; } - Uint32 memoryGb = info.totalMemory / (1024.0 * 1024.0 * 1024.0); + Uint32 vramGb = info.vram / (1024.0 * 1024.0 * 1024.0); + Uint32 sharedMemGb = info.sharedMemory / (1024.0 * 1024.0 * 1024.0); + palLog(nullptr, "GPU Name: %s", info.name); - palLog(nullptr, " Total Memory %dGB", memoryGb); + palLog(nullptr, " Vendor Id: %d", info.vendorId); + palLog(nullptr, " Device Id: %d", info.deviceId); + palLog(nullptr, " Vram %dGB", vramGb); + palLog(nullptr, " Shared Memory %dGB", sharedMemGb); palLog(nullptr, " API Version: %s", info.versionString); const char* typeString; switch (info.type) { - case PAL_GPU_TYPE_INTEGRATED: { + case PAL_ADAPTER_TYPE_INTEGRATED: { typeString = "Integrated"; break; } - case PAL_GPU_TYPE_VIRTUAL: { + case PAL_ADAPTER_TYPE_VIRTUAL: { typeString = "Virtual"; break; } - case PAL_GPU_TYPE_DISCRETE: { + case PAL_ADAPTER_TYPE_DISCRETE: { typeString = "Discrete"; break; } - case PAL_GPU_TYPE_CPU: { + case PAL_ADAPTER_TYPE_CPU: { typeString = "CPU"; break; } @@ -101,48 +106,74 @@ bool graphicsTest() const char* apiTypeString; switch (info.apiType) { - case PAL_GPU_API_TYPE_D3D12: { + case PAL_ADAPTER_API_TYPE_D3D12: { apiTypeString = "D3D12"; break; } - case PAL_GPU_API_TYPE_VULKAN: { + case PAL_ADAPTER_API_TYPE_VULKAN: { apiTypeString = "Vulkan"; break; } - case PAL_GPU_API_TYPE_METAL: { + case PAL_ADAPTER_API_TYPE_METAL: { apiTypeString = "Metal"; break; } - case PAL_GPU_API_TYPE_OPENGL: { + case PAL_ADAPTER_API_TYPE_OPENGL: { apiTypeString = "OpenGL"; break; } - case PAL_GPU_API_TYPE_GLES: { + case PAL_ADAPTER_API_TYPE_GLES: { apiTypeString = "GLes"; break; } - case PAL_GPU_API_TYPE_D3D11: { + case PAL_ADAPTER_API_TYPE_D3D11: { apiTypeString = "D3D11"; break; } - case PAL_GPU_API_TYPE_D3D9: { + case PAL_ADAPTER_API_TYPE_D3D9: { apiTypeString = "D3D9"; break; } - case PAL_GPU_API_TYPE_PPM: { + case PAL_ADAPTER_API_TYPE_PPM: { apiTypeString = "PPM"; break; } } palLog(nullptr, " API Type: %s", apiTypeString); + // shader formats + palLog(nullptr, " Supported Shader Formats:"); + if (info.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + palLog(nullptr, " SPIRV"); + } + + if (info.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + palLog(nullptr, " DXIL"); + } + + if (info.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + palLog(nullptr, " DXBC"); + } + + if (info.shaderFormats & PAL_SHADER_FORMAT_GLSL) { + palLog(nullptr, " GLSL"); + } + + if (info.shaderFormats & PAL_SHADER_FORMAT_MSL) { + palLog(nullptr, " MSL"); + } + + if (info.shaderFormats & PAL_SHADER_FORMAT_PPM) { + palLog(nullptr, " PPM"); + } + const char* boolToString; if (caps.debugLayerSupported) { boolToString = "True"; @@ -152,13 +183,33 @@ bool graphicsTest() palLog(nullptr, " Debug Layer: %s", boolToString); - // command queues - Int32 maxComputeQueues = caps.maxComputeQueues; - Int32 maxGraphicsQueues = caps.maxGraphicsQueues; - Int32 maxCopyQueues = caps.maxCopyQueues; - palLog(nullptr, " Max compute command queues: %d", maxComputeQueues); - palLog(nullptr, " Max graphics command queues: %d", maxGraphicsQueues); - palLog(nullptr, " Max copy command queues: %d", maxCopyQueues); + // clang-format off + + Uint32 uniformBufferSize = caps.maxUniformBufferSize / 1024; + Uint32 storageBufferSize = caps.maxStorageBufferSize / 1024; + Uint32 pushConstantSize = caps.maxStorageBufferSize / 1024; + + palLog(nullptr, " Max compute queues: %d", caps.maxComputeQueues); + palLog(nullptr, " Max graphics queues: %d", caps.maxGraphicsQueues); + palLog(nullptr, " Max copy queues: %d", caps.maxCopyQueues); + + palLog(nullptr, " Max image width: %d", caps.maxImageWidth); + palLog(nullptr, " Max image height: %d", caps.maxImageHeight); + palLog(nullptr, " Max image depth: %d", caps.maxImageDepth); + palLog(nullptr, " Max image array layers: %d", caps.maxImageArrayLayers); + palLog(nullptr, " Max image mip levels: %d", caps.maxImageMipLevels); + + palLog(nullptr, " Max color samples: %d", caps.maxColorSamples); + palLog(nullptr, " Max depth samples: %d", caps.maxDepthSamples); + palLog(nullptr, " Max color attachment: %d", caps.maxColorAttachments); + palLog(nullptr, " Max multi views: %d", caps.maxMultiViews); + palLog(nullptr, " Max viewports: %d", caps.maxViewports); + palLog(nullptr, " Max samplers: %d", caps.maxSamplers); + palLog(nullptr, " Max uniform buffer size: %dKB", uniformBufferSize); + palLog(nullptr, " Max storage buffer size: %dKB", storageBufferSize); + palLog(nullptr, " Max push constant size: %dKB", pushConstantSize); + + // clang-format on // features palLog(nullptr, " Supported Features:"); @@ -229,31 +280,7 @@ bool graphicsTest() palLog(nullptr, " Multiview"); } - // shader formats - palLog(nullptr, " Supported Shader Formats:"); - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_SPIRV) { - palLog(nullptr, " SPIRV"); - } - - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_DXIL) { - palLog(nullptr, " DXIL"); - } - - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_DXBC) { - palLog(nullptr, " DXBC"); - } - - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_GLSL) { - palLog(nullptr, " GLSL"); - } - - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_MSL) { - palLog(nullptr, " MSL"); - } - - if (info.shaderFormats & PAL_GPU_SHADER_FORMAT_PPM) { - palLog(nullptr, " PPM"); - } + palLog(nullptr, ""); } diff --git a/tests/tests.lua b/tests/tests.lua index 709c2074..19acee7f 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -66,14 +66,13 @@ project "tests" if (PAL_BUILD_GRAPHICS) then files { "graphics_test.c", - "custom_graphics_backend_test.c", - "gpu_device_test.c" + --"gpu_device_test.c" } end if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { - "swapchain_test.c" + --"swapchain_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 78a381b1..427e472c 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,13 +55,12 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); - // registerTest("Custom Graphics Backend Test", customGraphicsBackendTest); + registerTest("Graphics Test", graphicsTest); // registerTest("GPU Device Test", gpuDeviceTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest("Swapchain Test", swapchainTest); + // registerTest("Swapchain Test", swapchainTest); #endif runTests(); From 2063a7f87627df60a3c4cc161bb5f5d8969c18e4 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 1 Dec 2025 20:47:13 +0000 Subject: [PATCH 023/372] add new graphics device api --- include/pal/pal_core.h | 19 +- include/pal/pal_graphics.h | 60 +- src/graphics/pal_graphics_linux.c | 687 ++++++++++----------- src/pal_core.c | 35 +- tests/{gpu_device_test.c => device_test.c} | 74 +-- tests/graphics_test.c | 36 +- tests/tests.h | 2 +- tests/tests.lua | 2 +- tests/tests_main.c | 4 +- 9 files changed, 436 insertions(+), 483 deletions(-) rename tests/{gpu_device_test.c => device_test.c} (51%) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index b509f966..703c7db3 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -247,17 +247,16 @@ typedef enum { PAL_RESULT_INVALID_GL_CONTEXT, PAL_RESULT_INVALID_FBCONFIG_BACKEND, PAL_RESULT_GRAPHICS_NOT_INITIALIZED, - PAL_RESULT_INVALID_GPU_ADAPTER, - PAL_RESULT_INVALID_GPU_BACKEND, - PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED, - PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED, + PAL_RESULT_INVALID_ADAPTER, + PAL_RESULT_INVALID_GRAPHICS_BACKEND, + PAL_RESULT_QUEUE_NOT_SUPPORTED, + PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED, PAL_RESULT_INVALID_GRAPHICS_DRIVER, - PAL_RESULT_INVALID_GPU_DEVICE, - PAL_RESULT_INVALID_GPU_COMMAND_QUEUE, - PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE, - PAL_RESULT_INVALID_GPU_WINDOW, - PAL_RESULT_INVALID_SWAPCHAIN, - PAL_RESULT_INVALID_SWAPCHAIN_BUFFER_INDEX, + PAL_RESULT_INVALID_GRAPHICS_DEVICE, + PAL_RESULT_INVALID_QUEUE, + PAL_RESULT_OUT_OF_QUEUE, + PAL_RESULT_INVALID_GRAPHICS_WINDOW, + PAL_RESULT_INVALID_SWAPCHAIN } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index b94a5e9d..da9b92b0 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -196,24 +196,24 @@ typedef enum { } PalShaderFormats; typedef enum { - PAL_GPU_FEATURE_SAMPLER_ANISOTROPY = PAL_BIT64(0), - PAL_GPU_FEATURE_SAMPLE_RATE_SHADING = PAL_BIT64(1), - PAL_GPU_FEATURE_MULTI_VIEWPORT = PAL_BIT64(2), - PAL_GPU_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(3), - PAL_GPU_FEATURE_TESSELLATION_SHADER = PAL_BIT64(4), - PAL_GPU_FEATURE_GEOMETRY_SHADER = PAL_BIT64(5), - PAL_GPU_FEATURE_SHADER_FLOAT16 = PAL_BIT64(6), - PAL_GPU_FEATURE_SHADER_FLOAT64 = PAL_BIT64(7), - PAL_GPU_FEATURE_SHADER_INT16 = PAL_BIT64(8), - PAL_GPU_FEATURE_SHADER_INT64 = PAL_BIT64(9), - PAL_GPU_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(10), - PAL_GPU_FEATURE_RAY_TRACING = PAL_BIT64(11), - PAL_GPU_FEATURE_MESH_SHADER = PAL_BIT64(12), - PAL_GPU_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(13), - PAL_GPU_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), - PAL_GPU_FEATURE_SWAPCHAIN = PAL_BIT64(15), - PAL_GPU_FEATURE_MULTI_VIEW = PAL_BIT64(16) -} PalGPUFeatures; + PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY = PAL_BIT64(0), + PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING = PAL_BIT64(1), + PAL_ADAPTER_FEATURE_MULTI_VIEWPORT = PAL_BIT64(2), + PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(3), + PAL_ADAPTER_FEATURE_TESSELLATION_SHADER = PAL_BIT64(4), + PAL_ADAPTER_FEATURE_GEOMETRY_SHADER = PAL_BIT64(5), + PAL_ADAPTER_FEATURE_SHADER_FLOAT16 = PAL_BIT64(6), + PAL_ADAPTER_FEATURE_SHADER_FLOAT64 = PAL_BIT64(7), + PAL_ADAPTER_FEATURE_SHADER_INT16 = PAL_BIT64(8), + PAL_ADAPTER_FEATURE_SHADER_INT64 = PAL_BIT64(9), + PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(10), + PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(11), + PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(12), + PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(13), + PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), + PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(15), + PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16) +} PalAdapterFeatures; typedef enum { PAL_LOAD_OP_LOAD, @@ -258,7 +258,7 @@ typedef struct { Uint32 maxUniformBufferSize; Uint32 maxStorageBufferSize; Uint32 maxPushConstantSize; - PalGPUFeatures features; + PalAdapterFeatures features; } PalAdapterCapabilities; // typedef struct { @@ -342,12 +342,12 @@ typedef struct { PalAdapter* adapter, PalAdapterCapabilities* caps); - // PalResult PAL_CALL (*createGPUDevice)( - // PalGPUAdapter* adapter, - // PalGPUFeatures features, - // PalGPUDevice** outDevice); + PalResult PAL_CALL (*createDevice)( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); - // void PAL_CALL (*destroyGPUDevice)(PalGPUDevice* device); + void PAL_CALL (*destroyDevice)(PalDevice* device); // PalResult PAL_CALL (*createGPUCommandQueue)( // PalGPUDevice* device, @@ -412,14 +412,14 @@ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps); -// PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); +PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); -// PAL_API PalResult PAL_CALL palCreateGPUDevice( -// PalGPUAdapter* adapter, -// PalGPUFeatures features, -// PalGPUDevice** outDevice); +PAL_API PalResult PAL_CALL palCreateDevice( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); -// PAL_API void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device); +PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); // PAL_API PalResult PAL_CALL palCreateGPUCommandQueue( // PalGPUDevice* device, diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index c204afdd..2164658f 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -296,10 +296,7 @@ typedef struct { typedef struct { bool dynamicRendering; - bool multiView; - bool swapchain; Int32 queueCount; - Int32 multiViewCount; VkPhysicalDevice phyDevice; VkDevice handle; PhysicalQueue* phyQueues; @@ -463,7 +460,7 @@ static PalResult vkResultToPal(VkResult result) switch (result) { case VK_ERROR_FEATURE_NOT_PRESENT: case VK_ERROR_EXTENSION_NOT_PRESENT: { - return PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED; + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } case VK_ERROR_OUT_OF_HOST_MEMORY: @@ -860,7 +857,7 @@ static void vkShutdownGraphics() memset(&s_Vk, 0, sizeof(s_Vk)); } -static PalResult vkEnumerateAdapters( +static PalResult _vkEnumerateAdapters( Int32* count, PalAdapter** outAdapters) { @@ -897,7 +894,7 @@ static PalResult vkEnumerateAdapters( return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL vkGetAdapterInfo( +static PalResult PAL_CALL _vkGetAdapterInfo( PalAdapter* adapter, PalAdapterInfo* info) { @@ -965,7 +962,7 @@ static PalResult PAL_CALL vkGetAdapterInfo( return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL vkGetAdapterCapabilities( +static PalResult PAL_CALL _vkGetAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps) { @@ -1113,7 +1110,7 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( } if (mesh.meshShader && mesh.taskShader) { - caps->features |= PAL_GPU_FEATURE_MESH_SHADER; + caps->features |= PAL_ADAPTER_FEATURE_MESH_SHADER; } } else if (strcmp(props->extensionName, "VK_KHR_fragment_shading_rate") == 0) { @@ -1133,7 +1130,7 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( } if (frag.pipelineFragmentShadingRate) { - caps->features |= PAL_GPU_FEATURE_VARIABLE_RATE_SHADING; + caps->features |= PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING; } } else if (strcmp(props->extensionName, "VK_EXT_descriptor_indexing") == 0) { @@ -1153,16 +1150,16 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( } if (desc.shaderSampledImageArrayNonUniformIndexing) { - caps->features |= PAL_GPU_FEATURE_DESCRIPTOR_INDEXING; + caps->features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } } else if (strcmp(props->extensionName, "VK_KHR_swapchain") == 0) { // swapchain - caps->features |= PAL_GPU_FEATURE_SWAPCHAIN; + caps->features |= PAL_ADAPTER_FEATURE_SWAPCHAIN; } else if (strcmp(props->extensionName, "VK_KHR_dynamic_rendering") == 0) { // dynamic rendering - caps->features |= PAL_GPU_FEATURE_DYNAMIC_RENDERING; + caps->features |= PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING; } else if (strcmp(props->extensionName, "VK_KHR_shader_float16_int8") == 0) { // shader float16 @@ -1181,7 +1178,7 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( } if (shader16.shaderFloat16) { - caps->features |= PAL_GPU_FEATURE_SHADER_FLOAT16; + caps->features |= PAL_ADAPTER_FEATURE_SHADER_FLOAT16; } } else if (strcmp(props->extensionName, "VK_KHR_timeline_semaphore") == 0) { @@ -1201,7 +1198,7 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( } if (timeline.timelineSemaphore) { - caps->features |= PAL_GPU_FEATURE_TIMELINE_SEMAPHORE; + caps->features |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; } } else if (strcmp(props->extensionName, "VK_KHR_multiview") == 0) { @@ -1221,7 +1218,7 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( } if (view.multiview) { - caps->features |= PAL_GPU_FEATURE_MULTI_VIEW; + caps->features |= PAL_ADAPTER_FEATURE_MULTI_VIEW; } } } @@ -1246,7 +1243,7 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( } if (ray.rayTracingPipeline && acc.accelerationStructure) { - caps->features |= PAL_GPU_FEATURE_RAY_TRACING; + caps->features |= PAL_ADAPTER_FEATURE_RAY_TRACING; } } // clang-format on @@ -1255,377 +1252,363 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( // check for additional features if (features.geometryShader) { - caps->features |= PAL_GPU_FEATURE_GEOMETRY_SHADER; + caps->features |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; } if (features.multiViewport) { - caps->features |= PAL_GPU_FEATURE_MULTI_VIEWPORT; + caps->features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; } if (features.samplerAnisotropy) { - caps->features |= PAL_GPU_FEATURE_SAMPLER_ANISOTROPY; + caps->features |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; } if (features.sampleRateShading) { - caps->features |= PAL_GPU_FEATURE_SAMPLE_RATE_SHADING; + caps->features |= PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING; } if (features.shaderFloat64) { - caps->features |= PAL_GPU_FEATURE_SHADER_FLOAT64; + caps->features |= PAL_ADAPTER_FEATURE_SHADER_FLOAT64; } if (features.shaderInt64) { - caps->features |= PAL_GPU_FEATURE_SHADER_INT64; + caps->features |= PAL_ADAPTER_FEATURE_SHADER_INT64; } if (features.shaderInt16) { - caps->features |= PAL_GPU_FEATURE_SHADER_INT16; + caps->features |= PAL_ADAPTER_FEATURE_SHADER_INT16; } if (features.tessellationShader) { - caps->features |= PAL_GPU_FEATURE_TESSELLATION_SHADER; + caps->features |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; } palFree(s_Graphics.allocator, extensionProps); return PAL_RESULT_SUCCESS; } -// static PalResult PAL_CALL vkCreateGPUDevice( -// PalGPUAdapter* adapter, -// PalGPUFeatures features, -// PalGPUDevice** outDevice) -// { -// float priority = 1.0f; -// Uint32 count = 0; -// VkResult ret = VK_SUCCESS; -// Device* device = nullptr; -// VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; +static PalResult PAL_CALL _vkCreateDevice( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice) +{ + float priority = 1.0f; + Uint32 count = 0; + VkResult ret = VK_SUCCESS; + Device* device = nullptr; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; -// VkQueueFamilyProperties* queueProps = nullptr; -// VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; -// s_Vk.getPhysicalDeviceQueueFamilyProperties( -// phyDevice, -// &count, -// nullptr); + VkQueueFamilyProperties* queueProps = nullptr; + VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; + s_Vk.getPhysicalDeviceQueueFamilyProperties( + phyDevice, + &count, + nullptr); -// queueProps = palAllocate( -// s_Graphics.allocator, -// sizeof(VkQueueFamilyProperties) * count, -// 0); + queueProps = palAllocate( + s_Graphics.allocator, + sizeof(VkQueueFamilyProperties) * count, + 0); -// queueCreateInfos = palAllocate( -// s_Graphics.allocator, -// sizeof(VkDeviceQueueCreateInfo) * count, -// 0); + queueCreateInfos = palAllocate( + s_Graphics.allocator, + sizeof(VkDeviceQueueCreateInfo) * count, + 0); -// device = palAllocate(s_Graphics.allocator, sizeof(Device), 0); -// if (!queueProps || !queueCreateInfos || !device) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } + device = palAllocate(s_Graphics.allocator, sizeof(Device), 0); + if (!queueProps || !queueCreateInfos || !device) { + return PAL_RESULT_OUT_OF_MEMORY; + } -// device->queueCount = count; -// device->phyDevice = phyDevice; -// device->swapchain = false; -// device->multiView = false; -// device->dynamicRendering = false; -// device->multiViewCount = 1; + device->queueCount = count; + device->phyDevice = phyDevice; + device->dynamicRendering = false; -// device->phyQueues = palAllocate( -// s_Graphics.allocator, -// sizeof(PhysicalQueue) * count, -// 0); + device->phyQueues = palAllocate( + s_Graphics.allocator, + sizeof(PhysicalQueue) * count, + 0); -// if (!device->phyQueues) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } + if (!device->phyQueues) { + return PAL_RESULT_OUT_OF_MEMORY; + } -// s_Vk.getPhysicalDeviceQueueFamilyProperties( -// phyDevice, -// &count, -// queueProps); + s_Vk.getPhysicalDeviceQueueFamilyProperties( + phyDevice, + &count, + queueProps); -// for (int i = 0; i < count; i++) { -// queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; -// queueCreateInfos[i].pNext = nullptr; -// queueCreateInfos[i].pQueuePriorities = &priority; -// queueCreateInfos[i].queueFamilyIndex = i; -// queueCreateInfos[i].queueCount = queueProps[i].queueCount; -// queueCreateInfos[i].flags = 0; -// } + for (int i = 0; i < count; i++) { + queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfos[i].pNext = nullptr; + queueCreateInfos[i].pQueuePriorities = &priority; + queueCreateInfos[i].queueFamilyIndex = i; + queueCreateInfos[i].queueCount = queueProps[i].queueCount; + queueCreateInfos[i].flags = 0; + } -// // build features and extensions capabilities -// VkPhysicalDeviceFeatures coreFeatures = {0}; -// if (features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { -// coreFeatures.samplerAnisotropy = true; -// } + // build features and extensions capabilities + VkPhysicalDeviceFeatures coreFeatures = {0}; + if (features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { + coreFeatures.samplerAnisotropy = true; + } -// if (features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { -// coreFeatures.sampleRateShading = true; -// } + if (features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { + coreFeatures.sampleRateShading = true; + } -// if (features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { -// coreFeatures.multiViewport = true; -// } + if (features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { + coreFeatures.multiViewport = true; + } -// if (features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { -// coreFeatures.tessellationShader = true; -// } + if (features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { + coreFeatures.tessellationShader = true; + } -// if (features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { -// coreFeatures.geometryShader = true; -// } + if (features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { + coreFeatures.geometryShader = true; + } -// if (features & PAL_GPU_FEATURE_SHADER_INT16) { -// coreFeatures.shaderInt16 = true; -// } + if (features & PAL_ADAPTER_FEATURE_SHADER_INT16) { + coreFeatures.shaderInt16 = true; + } -// if (features & PAL_GPU_FEATURE_SHADER_INT64) { -// coreFeatures.shaderInt64 = true; -// } + if (features & PAL_ADAPTER_FEATURE_SHADER_INT64) { + coreFeatures.shaderInt64 = true; + } -// if (features & PAL_GPU_FEATURE_SHADER_FLOAT64) { -// coreFeatures.shaderFloat64 = true; -// } + if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT64) { + coreFeatures.shaderFloat64 = true; + } -// // extensions and features2 -// int extCount = 0; -// const char* extensions[16] = {0}; + // extensions and features2 + int extCount = 0; + const char* extensions[16] = {0}; -// // clang-format off + // clang-format off -// const void* start = nullptr; -// VkPhysicalDeviceTimelineSemaphoreFeatures timeline = {0}; -// timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; + const void* start = nullptr; + VkPhysicalDeviceTimelineSemaphoreFeatures timeline = {0}; + timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; -// VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; -// shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; + shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; -// VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; -// mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; + VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; + mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; -// VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; -// VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; -// ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; -// acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; + VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; + ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; + acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; -// VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs = {0}; -// vrs.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; + VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs = {0}; + vrs.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; -// VkPhysicalDeviceDescriptorIndexingFeatures descIndex = {0}; -// descIndex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + VkPhysicalDeviceDescriptorIndexingFeatures descIndex = {0}; + descIndex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; -// VkPhysicalDeviceMultiviewFeatures multiView = {0}; -// multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; + VkPhysicalDeviceMultiviewFeatures multiView = {0}; + multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; -// // clang-format on + // clang-format on -// if (features & PAL_GPU_FEATURE_SWAPCHAIN) { -// extensions[extCount++] = "VK_KHR_swapchain"; -// device->swapchain = true; -// } + if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { + extensions[extCount++] = "VK_KHR_swapchain"; + } -// if (features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { -// extensions[extCount++] = "VK_KHR_dynamic_rendering"; -// device->dynamicRendering = true; -// } + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { + extensions[extCount++] = "VK_KHR_dynamic_rendering"; + device->dynamicRendering = true; + } -// if (features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { -// extensions[extCount++] = "VK_KHR_timeline_semaphore"; -// timeline.timelineSemaphore = true; -// start = &timeline; -// } + if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + extensions[extCount++] = "VK_KHR_timeline_semaphore"; + timeline.timelineSemaphore = true; + start = &timeline; + } -// if (features & PAL_GPU_FEATURE_SHADER_FLOAT16) { -// extensions[extCount++] = "VK_KHR_shader_float16_int8"; -// shader16.shaderFloat16 = true; + if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { + extensions[extCount++] = "VK_KHR_shader_float16_int8"; + shader16.shaderFloat16 = true; -// if (timeline.timelineSemaphore) { -// timeline.pNext = &shader16; -// } -// start = &shader16; -// } + if (timeline.timelineSemaphore) { + timeline.pNext = &shader16; + } + start = &shader16; + } -// if (features & PAL_GPU_FEATURE_RAY_TRACING) { -// extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; -// extensions[extCount++] = "VK_KHR_acceleration_structure"; -// ray.rayTracingPipeline = true; -// acc.accelerationStructure = true; + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; + extensions[extCount++] = "VK_KHR_acceleration_structure"; + ray.rayTracingPipeline = true; + acc.accelerationStructure = true; -// if (shader16.shaderFloat16) { -// shader16.pNext = &ray; + if (shader16.shaderFloat16) { + shader16.pNext = &ray; -// } else if (timeline.timelineSemaphore) { -// // no shader16, check timeline -// timeline.pNext = &ray; -// } -// ray.pNext = &acc; -// start = &ray; -// } + } else if (timeline.timelineSemaphore) { + // no shader16, check timeline + timeline.pNext = &ray; + } + ray.pNext = &acc; + start = &ray; + } -// if (features & PAL_GPU_FEATURE_MESH_SHADER) { -// extensions[extCount++] = "VK_EXT_mesh_shader"; -// mesh.meshShader = true; -// mesh.taskShader = true; + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + extensions[extCount++] = "VK_EXT_mesh_shader"; + mesh.meshShader = true; + mesh.taskShader = true; -// if (acc.accelerationStructure) { -// acc.pNext = &mesh; + if (acc.accelerationStructure) { + acc.pNext = &mesh; -// } else if (shader16.shaderFloat16) { -// shader16.pNext = &mesh; + } else if (shader16.shaderFloat16) { + shader16.pNext = &mesh; -// } else if (timeline.timelineSemaphore) { -// timeline.pNext = &mesh; -// } -// start = &mesh; -// } + } else if (timeline.timelineSemaphore) { + timeline.pNext = &mesh; + } + start = &mesh; + } -// if (features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { -// extensions[extCount++] = "VK_KHR_fragment_shading_rate"; -// vrs.pipelineFragmentShadingRate = true; + if (features & PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING) { + extensions[extCount++] = "VK_KHR_fragment_shading_rate"; + vrs.pipelineFragmentShadingRate = true; -// if (mesh.meshShader) { -// mesh.pNext = &vrs; + if (mesh.meshShader) { + mesh.pNext = &vrs; -// } else if (acc.accelerationStructure) { -// acc.pNext = &vrs; + } else if (acc.accelerationStructure) { + acc.pNext = &vrs; -// } else if (shader16.shaderFloat16) { -// shader16.pNext = &vrs; + } else if (shader16.shaderFloat16) { + shader16.pNext = &vrs; -// } else if (timeline.timelineSemaphore) { -// timeline.pNext = &vrs; -// } -// start = &vrs; -// } + } else if (timeline.timelineSemaphore) { + timeline.pNext = &vrs; + } + start = &vrs; + } -// if (features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { -// extensions[extCount++] = "VK_EXT_descriptor_indexing"; -// descIndex.shaderSampledImageArrayNonUniformIndexing = true; + if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + extensions[extCount++] = "VK_EXT_descriptor_indexing"; + descIndex.shaderSampledImageArrayNonUniformIndexing = true; -// if (vrs.pipelineFragmentShadingRate) { -// vrs.pNext = &descIndex; + if (vrs.pipelineFragmentShadingRate) { + vrs.pNext = &descIndex; -// } else if (mesh.meshShader) { -// mesh.pNext = &descIndex; + } else if (mesh.meshShader) { + mesh.pNext = &descIndex; -// } else if (acc.accelerationStructure) { -// acc.pNext = &descIndex; + } else if (acc.accelerationStructure) { + acc.pNext = &descIndex; -// } else if (shader16.shaderFloat16) { -// shader16.pNext = &descIndex; + } else if (shader16.shaderFloat16) { + shader16.pNext = &descIndex; -// } else if (timeline.timelineSemaphore) { -// timeline.pNext = &descIndex; -// } -// start = &descIndex; -// } + } else if (timeline.timelineSemaphore) { + timeline.pNext = &descIndex; + } + start = &descIndex; + } -// if (features & PAL_GPU_FEATURE_MULTI_VIEW) { -// extensions[extCount++] = "VK_KHR_multiview"; -// multiView.multiview = true; -// device->multiView = true; + if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { + extensions[extCount++] = "VK_KHR_multiview"; + multiView.multiview = true; -// VkPhysicalDeviceMultiviewPropertiesKHR p = {0}; -// p.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; + if (descIndex.shaderSampledImageArrayNonUniformIndexing) { + descIndex.pNext = &multiView; -// VkPhysicalDeviceProperties2 props = {0}; -// props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; -// props.pNext = &p; -// s_Vk.getPhysicalDeviceProperties2(phyDevice, &props); -// device->multiViewCount = p.maxMultiviewViewCount; + } else if (vrs.pipelineFragmentShadingRate) { + vrs.pNext = &multiView; -// if (descIndex.shaderSampledImageArrayNonUniformIndexing) { -// descIndex.pNext = &multiView; + } else if (mesh.meshShader) { + mesh.pNext = &multiView; -// } else if (vrs.pipelineFragmentShadingRate) { -// vrs.pNext = &multiView; + } else if (acc.accelerationStructure) { + acc.pNext = &multiView; -// } else if (mesh.meshShader) { -// mesh.pNext = &multiView; + } else if (shader16.shaderFloat16) { + shader16.pNext = &multiView; -// } else if (acc.accelerationStructure) { -// acc.pNext = &multiView; + } else if (timeline.timelineSemaphore) { + timeline.pNext = &multiView; + } + start = &multiView; + } -// } else if (shader16.shaderFloat16) { -// shader16.pNext = &multiView; + VkDeviceCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.pEnabledFeatures = &coreFeatures; + createInfo.enabledExtensionCount = extCount; + createInfo.ppEnabledExtensionNames = extensions; + createInfo.pQueueCreateInfos = queueCreateInfos; + createInfo.queueCreateInfoCount = count; + createInfo.pNext = start; -// } else if (timeline.timelineSemaphore) { -// timeline.pNext = &multiView; -// } -// start = &multiView; -// } + ret = s_Vk.createDevice( + phyDevice, + &createInfo, + &s_Vk.allocator, + &device->handle); -// VkDeviceCreateInfo createInfo = {0}; -// createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; -// createInfo.pEnabledFeatures = &coreFeatures; -// createInfo.enabledExtensionCount = extCount; -// createInfo.ppEnabledExtensionNames = extensions; -// createInfo.pQueueCreateInfos = queueCreateInfos; -// createInfo.queueCreateInfoCount = count; -// createInfo.pNext = start; + if (ret != VK_SUCCESS) { + palFree(s_Graphics.allocator, queueProps); + palFree(s_Graphics.allocator, queueCreateInfos); + palFree(s_Graphics.allocator, device->phyQueues); + palFree(s_Graphics.allocator, device); + return vkResultToPal(ret); + } -// ret = s_Vk.createDevice( -// phyDevice, -// &createInfo, -// &s_Vk.allocator, -// &device->handle); - -// if (ret != VK_SUCCESS) { -// palFree(s_Graphics.allocator, queueProps); -// palFree(s_Graphics.allocator, queueCreateInfos); -// palFree(s_Graphics.allocator, device->phyQueues); -// palFree(s_Graphics.allocator, device); -// return vkResultToPal(ret); -// } - -// // get queues -// for (int i = 0; i < count; i++) { -// VkQueueFamilyProperties* data = &queueProps[i]; -// for (int j = 0; j < data->queueCount; j++) { -// PhysicalQueue* queue = &device->phyQueues[i]; -// s_Vk.getDeviceQueue(device->handle, i, j, &queue->handle); -// queue->usages = data->queueFlags; -// queue->usedUsages = 0; -// queue->familyIndex = i; -// queue->phyDevice = phyDevice; -// } -// } - -// // load procs -// device->acquireNextImage = (vkAcquireNextImageKHRFn)s_Vk.getDeviceProcAddr( -// device->handle, -// "vkAcquireNextImageKHR"); - -// device->createSwapchain = (vkCreateSwapchainKHRFn)s_Vk.getDeviceProcAddr( -// device->handle, -// "vkCreateSwapchainKHR"); - -// device->destroySwapchain = (vkDestroySwapchainKHRFn)s_Vk.getDeviceProcAddr( -// device->handle, -// "vkDestroySwapchainKHR"); - -// device->getSwapchainImages = (vkGetSwapchainImagesKHRFn)s_Vk.getDeviceProcAddr( -// device->handle, -// "vkGetSwapchainImagesKHR"); - -// device->queuePresent = (vkQueuePresentKHRFn)s_Vk.getDeviceProcAddr( -// device->handle, -// "vkQueuePresentKHR"); - -// palFree(s_Graphics.allocator, queueProps); -// palFree(s_Graphics.allocator, queueCreateInfos); - -// *outDevice = (PalGPUDevice*)device; -// return PAL_RESULT_SUCCESS; -// } + // get queues + for (int i = 0; i < count; i++) { + VkQueueFamilyProperties* data = &queueProps[i]; + for (int j = 0; j < data->queueCount; j++) { + PhysicalQueue* queue = &device->phyQueues[i]; + s_Vk.getDeviceQueue(device->handle, i, j, &queue->handle); + queue->usages = data->queueFlags; + queue->usedUsages = 0; + queue->familyIndex = i; + queue->phyDevice = phyDevice; + } + } -// static void PAL_CALL vkDestroyGPUDevice(PalGPUDevice* device) -// { -// Device* gpuDevice = (Device*)device; -// s_Vk.destroyDevice(gpuDevice->handle, &s_Vk.allocator); -// palFree(s_Graphics.allocator, gpuDevice->phyQueues); -// palFree(s_Graphics.allocator, gpuDevice); -// } + // load procs + device->acquireNextImage = (vkAcquireNextImageKHRFn)s_Vk.getDeviceProcAddr( + device->handle, + "vkAcquireNextImageKHR"); + + device->createSwapchain = (vkCreateSwapchainKHRFn)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateSwapchainKHR"); + + device->destroySwapchain = (vkDestroySwapchainKHRFn)s_Vk.getDeviceProcAddr( + device->handle, + "vkDestroySwapchainKHR"); + + device->getSwapchainImages = (vkGetSwapchainImagesKHRFn)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetSwapchainImagesKHR"); + + device->queuePresent = (vkQueuePresentKHRFn)s_Vk.getDeviceProcAddr( + device->handle, + "vkQueuePresentKHR"); + + palFree(s_Graphics.allocator, queueProps); + palFree(s_Graphics.allocator, queueCreateInfos); + + *outDevice = (PalDevice*)device; + return PAL_RESULT_SUCCESS; +} + +static void PAL_CALL _vkDestroyDevice(PalDevice* device) +{ + Device* _device = (Device*)device; + s_Vk.destroyDevice(_device->handle, &s_Vk.allocator); + palFree(s_Graphics.allocator, _device->phyQueues); + palFree(s_Graphics.allocator, _device); +} // static PalResult PAL_CALL vkCreateGPUCommandQueue( // PalGPUDevice* device, @@ -1886,7 +1869,7 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( // // check if we enabled swapchain feature // if (!commandQueue->device->swapchain) { -// return PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED; +// return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; // } // swapchain = palAllocate(s_Graphics.allocator, sizeof(Swapchain), 0); @@ -2224,13 +2207,13 @@ static PalResult PAL_CALL vkGetAdapterCapabilities( static PalGPUBackend s_VkBackend = { // adapter - .enumerateAdapters = vkEnumerateAdapters, - .getAdapterInfo = vkGetAdapterInfo, - .getAdapterCapabilities = vkGetAdapterCapabilities, + .enumerateAdapters = _vkEnumerateAdapters, + .getAdapterInfo = _vkGetAdapterInfo, + .getAdapterCapabilities = _vkGetAdapterCapabilities, // device - // .createGPUDevice = vkCreateGPUDevice, - // .destroyGPUDevice = vkDestroyGPUDevice, + .createDevice = _vkCreateDevice, + .destroyDevice = _vkDestroyDevice, // // command queue // .createGPUCommandQueue = vkCreateGPUCommandQueue, @@ -2314,7 +2297,7 @@ void PAL_CALL palShutdownGraphics() } // ================================================== -// GPU Adapter +// Adapter // ================================================== PalResult PAL_CALL palEnumerateAdapters( @@ -2390,7 +2373,7 @@ PalResult PAL_CALL palGetAdapterInfo( return data->backend->getAdapterInfo(adapter, info); } - return PAL_RESULT_INVALID_GPU_ADAPTER; + return PAL_RESULT_INVALID_ADAPTER; } PalResult PAL_CALL palGetAdapterCapabilities( @@ -2410,13 +2393,13 @@ PalResult PAL_CALL palGetAdapterCapabilities( return data->backend->getAdapterCapabilities(adapter, caps); } - return PAL_RESULT_INVALID_GPU_ADAPTER; + return PAL_RESULT_INVALID_ADAPTER; } PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) { if (s_Graphics.initialized) { - return PAL_RESULT_INVALID_GPU_BACKEND; + return PAL_RESULT_INVALID_GRAPHICS_BACKEND; } // // check if all the function pointers are set @@ -2451,58 +2434,58 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) } // ================================================== -// GPU Device +// Device // ================================================== -// PalResult PAL_CALL palCreateGPUDevice( -// PalGPUAdapter* adapter, -// PalGPUFeatures features, -// PalGPUDevice** outDevice) -// { -// if (!s_Graphics.initialized) { -// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; -// } +PalResult PAL_CALL palCreateDevice( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } -// if (!outDevice) { -// return PAL_RESULT_NULL_POINTER; -// } + if (!outDevice) { + return PAL_RESULT_NULL_POINTER; + } -// // check if the adapter is from PAL (custom or internal backend) -// HandleData* adapterData = findHandleData(adapter); -// if (!adapterData) { -// return PAL_RESULT_INVALID_GPU_ADAPTER; -// } + // check if the adapter is from PAL (custom or internal backend) + HandleData* adapterData = findHandleData(adapter); + if (!adapterData) { + return PAL_RESULT_INVALID_ADAPTER; + } -// PalGPUDevice* device = nullptr; -// PalResult ret; -// ret = adapterData->backend->createGPUDevice(adapter, features, &device); -// if (ret != PAL_RESULT_SUCCESS) { -// return ret; -// } + PalDevice* device = nullptr; + PalResult ret; + ret = adapterData->backend->createDevice(adapter, features, &device); + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } -// // create a slot for the created device -// HandleData* deviceData = getFreeHandleData(); -// if (!deviceData) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } + // create a slot for the created device + HandleData* deviceData = getFreeHandleData(); + if (!deviceData) { + return PAL_RESULT_OUT_OF_MEMORY; + } -// deviceData->backend = adapterData->backend; -// deviceData->handle = device; + deviceData->backend = adapterData->backend; + deviceData->handle = device; -// *outDevice = device; -// return PAL_RESULT_SUCCESS; -// } + *outDevice = device; + return PAL_RESULT_SUCCESS; +} -// void PAL_CALL palDestroyGPUDevice(PalGPUDevice* device) -// { -// if (s_Graphics.initialized && device) { -// HandleData* data = findHandleData(device); -// if (data) { -// data->backend->destroyGPUDevice(device); -// data->used = false; -// } -// } -// } +void PAL_CALL palDestroyDevice(PalDevice* device) +{ + if (s_Graphics.initialized && device) { + HandleData* data = findHandleData(device); + if (data) { + data->backend->destroyDevice(device); + data->used = false; + } + } +} // // ================================================== // // GPU Command Queue @@ -2594,7 +2577,7 @@ PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) // HandleData* adapterData = findHandleData(adapter); // if (!adapterData) { -// return PAL_RESULT_INVALID_GPU_ADAPTER; +// return PAL_RESULT_INVALID_ADAPTER; // } // return adapterData->backend->querySwapchainCapabilities( diff --git a/src/pal_core.c b/src/pal_core.c index 19e18c9f..828bf4f8 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -384,38 +384,35 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_GRAPHICS_NOT_INITIALIZED: return "Graphics system not initialized"; - case PAL_RESULT_INVALID_GPU_ADAPTER: - return "Invalid GPU adapter"; + case PAL_RESULT_INVALID_ADAPTER: + return "Invalid adapter"; - case PAL_RESULT_INVALID_GPU_BACKEND: - return "Invalid GPU backend"; + case PAL_RESULT_INVALID_GRAPHICS_BACKEND: + return "Invalid graphics backend"; - case PAL_RESULT_GPU_COMMAND_QUEUE_NOT_SUPPORTED: - return "GPU command queue not supported"; + case PAL_RESULT_QUEUE_NOT_SUPPORTED: + return "Queue not supported"; - case PAL_RESULT_GPU_FEATURE_NOT_SUPPORTED: - return "Unsupported gpu feature"; + case PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED: + return "Unsupported adapter feature"; case PAL_RESULT_INVALID_GRAPHICS_DRIVER: return "Incompatible graphics driver"; - case PAL_RESULT_INVALID_GPU_DEVICE: - return "Invalid GPU device"; + case PAL_RESULT_INVALID_GRAPHICS_DEVICE: + return "Invalid graphics device"; - case PAL_RESULT_INVALID_GPU_COMMAND_QUEUE: - return "Invalid GPU command queue"; + case PAL_RESULT_INVALID_QUEUE: + return "Invalid queue"; - case PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE: - return "Out of GPU command queues"; + case PAL_RESULT_OUT_OF_QUEUE: + return "Out of queues"; - case PAL_RESULT_INVALID_GPU_WINDOW: - return "Invalid GPU window"; + case PAL_RESULT_INVALID_GRAPHICS_WINDOW: + return "Invalid graphics window"; case PAL_RESULT_INVALID_SWAPCHAIN: return "Invalid swapchain"; - - case PAL_RESULT_INVALID_SWAPCHAIN_BUFFER_INDEX: - return "Invalid swapchain buffer index"; } return "Unknown"; } diff --git a/tests/gpu_device_test.c b/tests/device_test.c similarity index 51% rename from tests/gpu_device_test.c rename to tests/device_test.c index 48121809..fd0530c7 100644 --- a/tests/gpu_device_test.c +++ b/tests/device_test.c @@ -2,11 +2,11 @@ #include "pal/pal_graphics.h" #include "tests.h" -bool gpuDeviceTest() +bool deviceTest() { palLog(nullptr, ""); palLog(nullptr, "==========================================="); - palLog(nullptr, "GPU Device Test"); + palLog(nullptr, "Device Test"); palLog(nullptr, "==========================================="); palLog(nullptr, ""); @@ -18,44 +18,44 @@ bool gpuDeviceTest() return false; } - // enumerate all available GPUs from internal and custom backends + // enumerate all available adapters Int32 count = 0; - result = palEnumerateGPUAdapters(&count, nullptr); + result = palEnumerateAdapters(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + palLog(nullptr, "Failed to get query adapters: %s", error); return false; } if (count == 0) { - palLog(nullptr, "No Adapters found"); + palLog(nullptr, "No adapters found"); return false; } - palLog(nullptr, "Adapter (GPUs) Count: %d", count); + palLog(nullptr, "Adapter count: %d", count); // allocate an array of adapters or use a fixed array - // Example: PalGPUAdapter* adapters[12]; - PalGPUAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalGPUAdapter*) * count, 0); + // Example: PalAdapter* adapters[12]; + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); return false; } - result = palEnumerateGPUAdapters(&count, adapters); + result = palEnumerateAdapters(&count, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + palLog(nullptr, "Failed to get query adapters: %s", error); return false; } // filter the adapters for Vulkan - PalGPUAdapter* vulkanAdapter = nullptr; - PalGPUAdapterInfo info = {0}; + PalAdapter* vulkanAdapter = nullptr; + PalAdapterInfo info = {0}; for (Int32 i = 0; i < count; i++) { - PalGPUAdapter* adapter = adapters[i]; - result = palGetGPUAdapterInfo(adapter, &info); + PalAdapter* adapter = adapters[i]; + result = palGetAdapterInfo(adapter, &info); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); @@ -64,7 +64,7 @@ bool gpuDeviceTest() } // check if its Vulkan - if (info.apiType == PAL_GPU_API_TYPE_VULKAN) { + if (info.apiType == PAL_ADAPTER_API_TYPE_VULKAN) { vulkanAdapter = adapter; break; } @@ -77,56 +77,32 @@ bool gpuDeviceTest() } // get capabilities about the adapter - PalGPUAdapterCapabilities caps = {0}; - result = palGetGPUAdapterCapabilities(vulkanAdapter, &caps); + PalAdapterCapabilities caps = {0}; + result = palGetAdapterCapabilities(vulkanAdapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); return false; } - // check if we support a graphics command queue - const char* msg = "This Adapter (GPU) does not have any graphics queues"; - if (!(caps.features & PAL_GPU_FEATURE_SWAPCHAIN)) { - palLog(nullptr, msg); - return false; - } - - if (!caps.maxGraphicsQueues) { - palLog(nullptr, msg); - return false; - } - // create a device with the vulkan adapter - PalGPUDevice* device = nullptr; - PalGPUFeatures features = PAL_GPU_FEATURE_SWAPCHAIN; + PalDevice* device = nullptr; + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; // enable multi viewport if supported - if (caps.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { - features |= PAL_GPU_FEATURE_MULTI_VIEWPORT; + if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { + features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; } - result = palCreateGPUDevice(vulkanAdapter, features, &device); + result = palCreateDevice(vulkanAdapter, features, &device); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); return false; } - PalGPUCommandQueueType queueType = PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS; - PalGPUCommandQueue* graphicsQueue = nullptr; - result = palCreateGPUCommandQueue(device, queueType, &graphicsQueue); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command queue: %s", error); - return false; - } - - // destroy the command queue - palDestroyGPUCommandQueue(graphicsQueue); - // destroy the device - palDestroyGPUDevice(device); + palDestroyDevice(device); // shutdown the graphics system palShutdownGraphics(); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 86cf0cee..d7a7cfd1 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -213,75 +213,73 @@ bool graphicsTest() // features palLog(nullptr, " Supported Features:"); - if (caps.features & PAL_GPU_FEATURE_SAMPLER_ANISOTROPY) { + if (caps.features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { palLog(nullptr, " Sampler Anisotropy"); } - if (caps.features & PAL_GPU_FEATURE_SAMPLE_RATE_SHADING) { + if (caps.features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { palLog(nullptr, " Sample rate shading"); } - if (caps.features & PAL_GPU_FEATURE_MULTI_VIEWPORT) { + if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { palLog(nullptr, " Multi viewport"); } - if (caps.features & PAL_GPU_FEATURE_TIMELINE_SEMAPHORE) { + if (caps.features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { palLog(nullptr, " Timeline Semaphore"); } - if (caps.features & PAL_GPU_FEATURE_TESSELLATION_SHADER) { + if (caps.features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { palLog(nullptr, " Tesselation Shader"); } - if (caps.features & PAL_GPU_FEATURE_GEOMETRY_SHADER) { + if (caps.features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { palLog(nullptr, " Geometry shader"); } - if (caps.features & PAL_GPU_FEATURE_SHADER_FLOAT16) { + if (caps.features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { palLog(nullptr, " Shader float16"); } - if (caps.features & PAL_GPU_FEATURE_SHADER_FLOAT64) { + if (caps.features & PAL_ADAPTER_FEATURE_SHADER_FLOAT64) { palLog(nullptr, " Shader float64"); } - if (caps.features & PAL_GPU_FEATURE_SHADER_INT16) { + if (caps.features & PAL_ADAPTER_FEATURE_SHADER_INT16) { palLog(nullptr, " Shader int16"); } - if (caps.features & PAL_GPU_FEATURE_SHADER_INT64) { + if (caps.features & PAL_ADAPTER_FEATURE_SHADER_INT64) { palLog(nullptr, " Shader int64"); } - if (caps.features & PAL_GPU_FEATURE_DYNAMIC_RENDERING) { + if (caps.features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { palLog(nullptr, " Dynamic rendering"); } - if (caps.features & PAL_GPU_FEATURE_RAY_TRACING) { + if (caps.features & PAL_ADAPTER_FEATURE_RAY_TRACING) { palLog(nullptr, " Ray tracing"); } - if (caps.features & PAL_GPU_FEATURE_MESH_SHADER) { + if (caps.features & PAL_ADAPTER_FEATURE_MESH_SHADER) { palLog(nullptr, " Mesh shader"); } - if (caps.features & PAL_GPU_FEATURE_VARIABLE_RATE_SHADING) { + if (caps.features & PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING) { palLog(nullptr, " Variable rate rendering"); } - if (caps.features & PAL_GPU_FEATURE_DESCRIPTOR_INDEXING) { + if (caps.features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { palLog(nullptr, " Descriptor indexing"); } - if (caps.features & PAL_GPU_FEATURE_SWAPCHAIN) { + if (caps.features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { palLog(nullptr, " Swapchain"); } - if (caps.features & PAL_GPU_FEATURE_MULTI_VIEW) { + if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { palLog(nullptr, " Multiview"); } - - palLog(nullptr, ""); } diff --git a/tests/tests.h b/tests/tests.h index f4163d67..b4985f16 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -56,7 +56,7 @@ bool multiThreadOpenGlTest(); // graphics bool graphicsTest(); bool customGraphicsBackendTest(); -bool gpuDeviceTest(); +bool deviceTest(); // graphics and video bool swapchainTest(); diff --git a/tests/tests.lua b/tests/tests.lua index 19acee7f..da1b298b 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -66,7 +66,7 @@ project "tests" if (PAL_BUILD_GRAPHICS) then files { "graphics_test.c", - --"gpu_device_test.c" + "device_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 427e472c..63e6ed62 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,8 +55,8 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); - // registerTest("GPU Device Test", gpuDeviceTest); + // registerTest("Graphics Test", graphicsTest); + registerTest("Device Test", deviceTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From e3ff96f2c80ffcf45c0b8586ebeb10d202587af9 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 1 Dec 2025 21:30:20 +0000 Subject: [PATCH 024/372] add new queue api --- include/pal/pal_graphics.h | 40 ++-- src/graphics/pal_graphics_linux.c | 318 +++++++++++++++--------------- tests/queue_test.c | 128 ++++++++++++ tests/tests.h | 2 +- tests/tests.lua | 1 + tests/tests_main.c | 4 +- 6 files changed, 311 insertions(+), 182 deletions(-) create mode 100644 tests/queue_test.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index da9b92b0..e513bca7 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -324,10 +324,10 @@ typedef struct { // PalRenderPassAttachmentInfo* attachments; // } PalRenderPassCreateInfo; -// typedef struct { -// void* display; -// void* window; -// } PalGPUWindow; +typedef struct { + void* display; + void* window; +} PalGraphicsWindow; typedef struct { PalResult PAL_CALL (*enumerateAdapters)( @@ -349,16 +349,16 @@ typedef struct { void PAL_CALL (*destroyDevice)(PalDevice* device); - // PalResult PAL_CALL (*createGPUCommandQueue)( - // PalGPUDevice* device, - // PalGPUCommandQueueType type, - // PalGPUCommandQueue** outQueue); + PalResult PAL_CALL (*createQueue)( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); - // void PAL_CALL (*destroyGPUCommandQueue)(PalGPUCommandQueue* queue); + void PAL_CALL (*destroyQueue)(PalQueue* queue); - // bool PAL_CALL (*canCommandQueuePresent)( - // PalGPUCommandQueue* queue, - // PalGPUWindow* window); + bool PAL_CALL (*canQueuePresent)( + PalQueue* queue, + PalGraphicsWindow* window); // PalResult PAL_CALL (*querySwapchainCapabilities)( // PalGPUAdapter* adapter, @@ -421,16 +421,16 @@ PAL_API PalResult PAL_CALL palCreateDevice( PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); -// PAL_API PalResult PAL_CALL palCreateGPUCommandQueue( -// PalGPUDevice* device, -// PalGPUCommandQueueType type, -// PalGPUCommandQueue** outQueue); +PAL_API PalResult PAL_CALL palCreateQueue( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); -// PAL_API void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue); +PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); -// PAL_API bool PAL_CALL palCanCommandQueuePresent( -// PalGPUCommandQueue* queue, -// PalGPUWindow* window); +PAL_API bool PAL_CALL palCanQueuePresent( + PalQueue* queue, + PalGraphicsWindow* window); // PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( // PalGPUAdapter* adapter, diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 2164658f..f2cab492 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -311,7 +311,7 @@ typedef struct { VkQueueFlags usage; Device* device; PhysicalQueue* phyQueue; -} CommandQueue; +} Queue; typedef struct { Int32 bufferCount; @@ -326,7 +326,7 @@ typedef struct { VkFormat format; Device* device; VkImageView handle; -} RenderTargetView; +} ImageView; typedef struct { Device* device; @@ -410,18 +410,18 @@ static HandleData* findHandleData(void* handle) #if PAL_HAS_VULKAN -// static bool vkOnWayland(struct wl_display* display) -// { -// if (!s_Vk.libWayland) { -// return false; -// } +static bool vkOnWayland(struct wl_display* display) +{ + if (!s_Vk.libWayland) { + return false; + } -// int fd = s_Vk.getDisplayFd(display); -// if (fd <= 0 || fd > 1024) { // fds are usaually 0-30 but this is fine -// return false; -// } -// return true; -// } + int fd = s_Vk.getDisplayFd(display); + if (fd <= 0 || fd > 1024) { // fds are usaually 0-30 but this is fine + return false; + } + return true; +} // static bool vkCreateSurface(PalGPUWindow* window, VkSurfaceKHR* outSurface) // { @@ -1610,99 +1610,99 @@ static void PAL_CALL _vkDestroyDevice(PalDevice* device) palFree(s_Graphics.allocator, _device); } -// static PalResult PAL_CALL vkCreateGPUCommandQueue( -// PalGPUDevice* device, -// PalGPUCommandQueueType type, -// PalGPUCommandQueue** outQueue) -// { -// VkQueueFlags queueFlag = 0; -// Device* gpuDevice = (Device*)device; -// CommandQueue* commandQueue = nullptr; -// if (!gpuDevice->handle) { -// return PAL_RESULT_INVALID_GPU_DEVICE; -// } +static PalResult PAL_CALL _vkCreateQueue( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue) +{ + VkQueueFlags queueFlag = 0; + Device* _device = (Device*)device; + Queue* queue = nullptr; + if (!_device->handle) { + return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + } -// if (gpuDevice->queueCount == 0) { -// return PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE; -// } + if (_device->queueCount == 0) { + return PAL_RESULT_OUT_OF_QUEUE; + } -// switch (type) { -// case PAL_GPU_COMMAND_QUEUE_TYPE_COMPUTE: { -// queueFlag = VK_QUEUE_COMPUTE_BIT; -// break; -// } + switch (type) { + case PAL_QUEUE_TYPE_COMPUTE: { + queueFlag = VK_QUEUE_COMPUTE_BIT; + break; + } -// case PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS: { -// queueFlag = VK_QUEUE_GRAPHICS_BIT; -// break; -// } + case PAL_QUEUE_TYPE_GRAPHICS: { + queueFlag = VK_QUEUE_GRAPHICS_BIT; + break; + } -// case PAL_GPU_COMMAND_QUEUE_TYPE_COPY: { -// queueFlag = VK_QUEUE_TRANSFER_BIT; -// break; -// } -// } + case PAL_QUEUE_TYPE_COPY: { + queueFlag = VK_QUEUE_TRANSFER_BIT; + break; + } + } -// PhysicalQueue* phyQueue = nullptr; -// for (int i = 0; i < gpuDevice->queueCount; i++) { -// PhysicalQueue* queue = &gpuDevice->phyQueues[i]; -// // check if the physical queue supports the requested operation -// // and if its not already used -// if (queue->usages & queueFlag && -// queue->usedUsages != queueFlag) { -// queue->usedUsages |= queueFlag; -// phyQueue = queue; -// break; -// } -// } + PhysicalQueue* phyQueue = nullptr; + for (int i = 0; i < _device->queueCount; i++) { + PhysicalQueue* queue = &_device->phyQueues[i]; + // check if the physical queue supports the requested operation + // and if its not already used + if (queue->usages & queueFlag && + queue->usedUsages != queueFlag) { + queue->usedUsages |= queueFlag; + phyQueue = queue; + break; + } + } -// if (phyQueue) { -// commandQueue = palAllocate( -// s_Graphics.allocator, -// sizeof(CommandQueue), -// 0); + if (phyQueue) { + queue = palAllocate( + s_Graphics.allocator, + sizeof(Queue), + 0); -// if (!commandQueue) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } + if (!queue) { + return PAL_RESULT_OUT_OF_MEMORY; + } -// commandQueue->phyQueue = phyQueue; -// commandQueue->usage = queueFlag; -// commandQueue->device = gpuDevice; + queue->phyQueue = phyQueue; + queue->usage = queueFlag; + queue->device = _device; -// *outQueue = (PalGPUCommandQueue*)commandQueue; -// return PAL_RESULT_SUCCESS; -// } + *outQueue = (PalQueue*)queue; + return PAL_RESULT_SUCCESS; + } -// return PAL_RESULT_OUT_OF_GPU_COMMAND_QUEUE; -// } + return PAL_RESULT_OUT_OF_QUEUE; +} -// static void PAL_CALL vkDestroyGPUCommandQueue(PalGPUCommandQueue* queue) -// { -// CommandQueue* commandQueue = (CommandQueue*)queue; -// PhysicalQueue* phyQueue = commandQueue->phyQueue; -// phyQueue->usedUsages &= ~commandQueue->usage; -// palFree(s_Graphics.allocator, commandQueue); -// } +static void PAL_CALL _vkDestroyQueue(PalQueue* queue) +{ + Queue* _queue = (Queue*)queue; + PhysicalQueue* phyQueue = _queue->phyQueue; + phyQueue->usedUsages &= ~_queue->usage; + palFree(s_Graphics.allocator, _queue); +} -// static bool PAL_CALL vkCanCommandQueuePresent( -// PalGPUCommandQueue* queue, -// PalGPUWindow* window) -// { -// bool onWayland = vkOnWayland(window->display); -// CommandQueue* commandQueue = (CommandQueue*)queue; -// PhysicalQueue* phyQueue = commandQueue->phyQueue; +static bool PAL_CALL _vkCanQueuePresent( + PalQueue* queue, + PalGraphicsWindow* window) +{ + bool onWayland = vkOnWayland(window->display); + Queue* _queue = (Queue*)queue; + PhysicalQueue* phyQueue = _queue->phyQueue; -// if (!s_Vk.checkWaylandPresentSupport( -// phyQueue->phyDevice, -// phyQueue->familyIndex, window->display)) { -// return false; -// } else { -// // TODO: check presentation for xlib -// } + if (!s_Vk.checkWaylandPresentSupport( + phyQueue->phyDevice, + phyQueue->familyIndex, window->display)) { + return false; + } else { + // TODO: check presentation for xlib + } -// return true; -// } + return true; +} // static PalResult PAL_CALL vkQuerySwapchainCapabilities( // PalGPUAdapter* adapter, @@ -2215,10 +2215,10 @@ static PalGPUBackend s_VkBackend = { .createDevice = _vkCreateDevice, .destroyDevice = _vkDestroyDevice, - // // command queue - // .createGPUCommandQueue = vkCreateGPUCommandQueue, - // .destroyGPUCommandQueue = vkDestroyGPUCommandQueue, - // .canCommandQueuePresent = vkCanCommandQueuePresent, + // queue + .createQueue = _vkCreateQueue, + .destroyQueue = _vkDestroyQueue, + .canQueuePresent = _vkCanQueuePresent, // // swapchain // .querySwapchainCapabilities = vkQuerySwapchainCapabilities, @@ -2487,80 +2487,80 @@ void PAL_CALL palDestroyDevice(PalDevice* device) } } -// // ================================================== -// // GPU Command Queue -// // ================================================== +// ================================================== +// Queue +// ================================================== -// PalResult PAL_CALL palCreateGPUCommandQueue( -// PalGPUDevice* device, -// PalGPUCommandQueueType type, -// PalGPUCommandQueue** outQueue) -// { -// if (!s_Graphics.initialized) { -// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; -// } +PalResult PAL_CALL palCreateQueue( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } -// if (!device || !outQueue) { -// return PAL_RESULT_NULL_POINTER; -// } + if (!device || !outQueue) { + return PAL_RESULT_NULL_POINTER; + } -// HandleData* data = findHandleData(device); -// if (!data) { -// return PAL_RESULT_INVALID_GPU_DEVICE; -// } + HandleData* data = findHandleData(device); + if (!data) { + return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + } -// PalGPUCommandQueue* queue = nullptr; -// PalResult ret; -// ret = data->backend->createGPUCommandQueue( -// device, -// type, -// &queue); + PalQueue* queue = nullptr; + PalResult ret; + ret = data->backend->createQueue( + device, + type, + &queue); -// if (ret != PAL_RESULT_SUCCESS) { -// return ret; -// } + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } -// // create a slot for the created command queue -// HandleData* queueData = getFreeHandleData(); -// if (!queueData) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } + // create a slot for the created queue + HandleData* queueData = getFreeHandleData(); + if (!queueData) { + return PAL_RESULT_OUT_OF_MEMORY; + } -// queueData->backend = data->backend; -// queueData->handle = queue; + queueData->backend = data->backend; + queueData->handle = queue; -// *outQueue = queue; -// return PAL_RESULT_SUCCESS; -// } + *outQueue = queue; + return PAL_RESULT_SUCCESS; +} -// void PAL_CALL palDestroyGPUCommandQueue(PalGPUCommandQueue* queue) -// { -// if (s_Graphics.initialized && queue) { -// HandleData* data = findHandleData(queue); -// if (data) { -// data->backend->destroyGPUCommandQueue(queue); -// data->used = false; -// } -// } -// } +void PAL_CALL palDestroyQueue(PalQueue* queue) +{ + if (s_Graphics.initialized && queue) { + HandleData* data = findHandleData(queue); + if (data) { + data->backend->destroyQueue(queue); + data->used = false; + } + } +} -// bool PAL_CALL palCanCommandQueuePresent( -// PalGPUCommandQueue* queue, -// PalGPUWindow* window) -// { -// if (s_Graphics.initialized && queue) { -// HandleData* data = findHandleData(queue); -// if (data) { -// return data->backend->canCommandQueuePresent(queue, window); -// } -// return false; -// } -// return false; -// } +bool PAL_CALL palCanQueuePresent( + PalQueue* queue, + PalGraphicsWindow* window) +{ + if (s_Graphics.initialized && queue) { + HandleData* data = findHandleData(queue); + if (data) { + return data->backend->canQueuePresent(queue, window); + } + return false; + } + return false; +} -// // ================================================== -// // Swapchain -// // ================================================== +// ================================================== +// Swapchain +// ================================================== // PalResult PAL_CALL palQuerySwapchainCapabilities( // PalGPUAdapter* adapter, diff --git a/tests/queue_test.c b/tests/queue_test.c new file mode 100644 index 00000000..2e2162ba --- /dev/null +++ b/tests/queue_test.c @@ -0,0 +1,128 @@ + +#include "pal/pal_graphics.h" +#include "tests.h" + +bool queueTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Queue Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + // initialize the graphics system + PalResult result = palInitGraphics(false, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 count = 0; + result = palEnumerateAdapters(&count, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (count == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", count); + + // allocate an array of adapters or use a fixed array + // Example: PalAdapter* adapters[12]; + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&count, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + // filter the adapters for Vulkan + PalAdapter* vulkanAdapter = nullptr; + PalAdapterInfo info = {0}; + + for (Int32 i = 0; i < count; i++) { + PalAdapter* adapter = adapters[i]; + result = palGetAdapterInfo(adapter, &info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + palFree(nullptr, adapters); + return false; + } + + // check if its Vulkan + if (info.apiType == PAL_ADAPTER_API_TYPE_VULKAN) { + vulkanAdapter = adapter; + break; + } + } + + palFree(nullptr, adapters); + if (!vulkanAdapter) { + palLog(nullptr, "Failed to find a vulkan adapter"); + return false; + } + + // get capabilities about the adapter + PalAdapterCapabilities caps = {0}; + result = palGetAdapterCapabilities(vulkanAdapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + if (caps.maxGraphicsQueues == 0) { + palLog(nullptr, "adapter does not support graphics queues"); + return false; + } + + // create a device with the vulkan adapter + PalDevice* device = nullptr; + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + + // enable multi viewport if supported + if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { + features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; + } + + result = palCreateDevice(vulkanAdapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a graphics queue + PalQueue* gfxQueue = nullptr; + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &gfxQueue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + // destroy the graphics queue + palDestroyQueue(gfxQueue); + + // destroy the device + palDestroyDevice(device); + + // shutdown the graphics system + palShutdownGraphics(); + + return true; +} \ No newline at end of file diff --git a/tests/tests.h b/tests/tests.h index b4985f16..4d7822f6 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -59,6 +59,6 @@ bool customGraphicsBackendTest(); bool deviceTest(); // graphics and video -bool swapchainTest(); +bool queueTest(); #endif // _TESTS_H \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index da1b298b..867c76fd 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -72,6 +72,7 @@ project "tests" if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { + "queue_test.c" --"swapchain_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 63e6ed62..adaf1f99 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -56,11 +56,11 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest("Graphics Test", graphicsTest); - registerTest("Device Test", deviceTest); + // registerTest("Device Test", deviceTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest("Swapchain Test", swapchainTest); + registerTest("Queue Test", queueTest); #endif runTests(); From 5523439160b18768f5312af4193713b8951b473f Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 2 Dec 2025 06:02:53 +0000 Subject: [PATCH 025/372] add sample counts --- include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 61 ++- src/graphics/pal_graphics_linux.c | 853 ++++++++++++++++++++---------- src/pal_core.c | 3 + tests/queue_test.c | 46 ++ tests/tests_main.c | 4 +- 6 files changed, 690 insertions(+), 280 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 703c7db3..4baa818d 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -256,7 +256,8 @@ typedef enum { PAL_RESULT_INVALID_QUEUE, PAL_RESULT_OUT_OF_QUEUE, PAL_RESULT_INVALID_GRAPHICS_WINDOW, - PAL_RESULT_INVALID_SWAPCHAIN + PAL_RESULT_INVALID_SWAPCHAIN, + PAL_RESULT_INVALID_GRAPHICS_IMAGE } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index e513bca7..f1f13ef4 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -152,7 +152,7 @@ typedef enum { PAL_FORMAT_R64G64B64A64_UINT, PAL_FORMAT_R64G64B64A64_SINT, PAL_FORMAT_R64G64B64A64_SFLOAT, - PAL_FORMAT_B8G8RA88_UNORM, + PAL_FORMAT_B8G8R8A8_UNORM, PAL_FORMAT_B8G8R8A8_SNORM, PAL_FORMAT_B8G8R8A8_UINT, PAL_FORMAT_B8G8R8A8_SINT, @@ -162,7 +162,7 @@ typedef enum { PAL_FORMAT_D32_SFLOAT, PAL_FORMAT_D32_SFLOAT_S8_UINT, PAL_FORMAT_D16_UNORM_S8_UINT, - PAL_FORMAT_D24_UNORM_S8_UINT, + PAL_FORMAT_D24_UNORM_S8_UINT } PalFormat; typedef enum { @@ -174,11 +174,6 @@ typedef enum { PAL_IMAGE_USAGE_SAMPLED = PAL_BIT(5) } PalImageUsages; -typedef enum { - PAL_SHARING_MODE_EXCLUSIVE, - PAL_SHARING_MODE_CONCURRENT -} PalSharingMode; - typedef enum { PAL_TRANSFORM_LANDSCAPE, PAL_TRANSFORM_PORTRAIT, @@ -226,6 +221,12 @@ typedef enum { PAL_STORE_OP_DONT_CARE } PalStoreOp; +typedef enum { + PAL_MEMORY_TYPE_GPU_ONLY, + PAL_MEMORY_CPU_UPLOAD, + PAL_MEMORY_CPU_READBACK +} PalMemoryType; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -324,6 +325,30 @@ typedef struct { // PalRenderPassAttachmentInfo* attachments; // } PalRenderPassCreateInfo; +typedef struct { + Uint32 width; + Uint32 height; + Uint32 depth; + Uint32 mipLevels; + Uint32 arrayLayers; + Uint32 samples; + PalFormat format; + PalImageUsages usages; + PalMemoryType memoryType; +} PalImageInfo; + +typedef struct { + Uint32 width; + Uint32 height; + Uint32 depth; + Uint32 mipLevels; + Uint32 arrayLayers; + Uint32 samples; + PalFormat format; + PalImageUsages usages; + PalMemoryType memoryType; +} PalImageCreateInfo; + typedef struct { void* display; void* window; @@ -360,6 +385,17 @@ typedef struct { PalQueue* queue, PalGraphicsWindow* window); + PalResult PAL_CALL (*createImage)( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + + void PAL_CALL (*destroyImage)(PalImage* image); + + PalResult PAL_CALL (*getImageInfo)( + PalImage* image, + PalImageInfo* info); + // PalResult PAL_CALL (*querySwapchainCapabilities)( // PalGPUAdapter* adapter, // PalGPUWindow* window, @@ -432,6 +468,17 @@ PAL_API bool PAL_CALL palCanQueuePresent( PalQueue* queue, PalGraphicsWindow* window); +PAL_API PalResult PAL_CALL palCreateImage( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + +PAL_API void PAL_CALL palDestroyImage(PalImage* image); + +PAL_API PalResult PAL_CALL palGetImageInfo( + PalImage* image, + PalImageInfo* info); + // PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( // PalGPUAdapter* adapter, // PalGPUWindow* window, diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index f2cab492..03d5535b 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -33,6 +33,18 @@ freely, subject to the following restrictions: #include #include #include + +// HACK: Needed to determine display type +struct wl_display; +struct wl_surface; +typedef struct _XDisplay Display; +typedef unsigned long Window; +typedef unsigned long VisualID; +typedef int (*wl_display_get_fd_fn)(struct wl_display*); + +#include +#include + #endif // PAL_HAS_VULKAN // ================================================== @@ -42,204 +54,6 @@ freely, subject to the following restrictions: #define MAX_BACKENDS 32 #if PAL_HAS_VULKAN -// VKAPI_PTR expands to nothing on linux - -// HACK: Needed to determine display type -struct wl_display; -typedef int (*wl_display_get_fd_fn)(struct wl_display*); - -// wayland -typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; -typedef struct VkWaylandSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkWaylandSurfaceCreateFlagsKHR flags; - struct wl_display* display; - struct wl_surface* surface; -} VkWaylandSurfaceCreateInfoKHR; - -typedef VkResult (*vkCreateWaylandSurfaceKHRFn)( - VkInstance, - const VkWaylandSurfaceCreateInfoKHR*, - const VkAllocationCallbacks*, - VkSurfaceKHR*); - -typedef VkBool32 (*vkGetPhysicalDeviceWaylandPresentationSupportKHRFn)( - VkPhysicalDevice, - uint32_t, - struct wl_display*); - -// Xlib -typedef struct _XDisplay Display; -typedef unsigned long Window; -typedef unsigned long VisualID; -typedef VkFlags VkXlibSurfaceCreateFlagsKHR; - -typedef struct VkXlibSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkXlibSurfaceCreateFlagsKHR flags; - Display* dpy; - Window window; -} VkXlibSurfaceCreateInfoKHR; - -typedef VkResult (*vkCreateXlibSurfaceKHRFn)( - VkInstance, - const VkXlibSurfaceCreateInfoKHR*, - const VkAllocationCallbacks*, - VkSurfaceKHR*); - -typedef VkBool32 (*vkGetPhysicalDeviceXlibPresentationSupportKHRFn)( - VkPhysicalDevice, - uint32_t, - Display*, - VisualID); - -typedef VkResult (*vkEnumerateInstanceVersionFn)(uint32_t*); - -typedef VkResult (*vkEnumerateInstanceExtensionPropertiesFn)( - const char*, - uint32_t*, - VkExtensionProperties*); - -typedef VkResult (*vkCreateInstanceFn)( - const VkInstanceCreateInfo*, - const VkAllocationCallbacks*, - VkInstance*); - -typedef void (*vkDestroyInstanceFn)( - VkInstance, - const VkAllocationCallbacks*); - -typedef VkResult (*vkEnumeratePhysicalDevicesFn)( - VkInstance, - uint32_t*, - VkPhysicalDevice*); - -typedef void (*vkGetPhysicalDevicePropertiesFn)( - VkPhysicalDevice, - VkPhysicalDeviceProperties*); - -typedef void (*vkGetPhysicalDeviceMemoryPropertiesFn)( - VkPhysicalDevice, - VkPhysicalDeviceMemoryProperties*); - -typedef VkResult (*vkEnumerateInstanceLayerPropertiesFn)( - uint32_t*, - VkLayerProperties*); - -typedef void (*vkGetPhysicalDeviceQueueFamilyPropertiesFn)( - VkPhysicalDevice, - uint32_t*, - VkQueueFamilyProperties*); - -typedef VkResult (*vkEnumerateDeviceExtensionPropertiesFn)( - VkPhysicalDevice, - const char*, - uint32_t*, - VkExtensionProperties*); - -typedef void (*vkGetPhysicalDeviceFeaturesFn)( - VkPhysicalDevice, - VkPhysicalDeviceFeatures*); - -typedef void (*vkGetPhysicalDeviceFeatures2Fn)( - VkPhysicalDevice, - VkPhysicalDeviceFeatures2*); - -typedef void (*vkGetPhysicalDeviceFeatures2KHRFn)( - VkPhysicalDevice, - VkPhysicalDeviceFeatures2*); - -typedef VkResult (*vkCreateDeviceFn)( - VkPhysicalDevice, - const VkDeviceCreateInfo*, - const VkAllocationCallbacks*, - VkDevice*); - -typedef void (*vkDestroyDeviceFn)( - VkDevice, - const VkAllocationCallbacks*); - -typedef void (*vkGetDeviceQueueFn)( - VkDevice, - uint32_t, - uint32_t, - VkQueue*); - -typedef void (*vkDestroySurfaceKHRFn)( - VkInstance, - VkSurfaceKHR, - const VkAllocationCallbacks*); - -typedef PFN_vkVoidFunction (*vkGetInstanceProcAddrFn)( - VkInstance, - const char*); - -typedef PFN_vkVoidFunction (*vkGetDeviceProcAddrFn)( - VkDevice, - const char*); - -typedef VkResult (*vkGetPhysicalDeviceSurfaceCapabilitiesKHRFn)( - VkPhysicalDevice, - VkSurfaceKHR, - VkSurfaceCapabilitiesKHR*); - -typedef VkResult (*vkGetPhysicalDeviceSurfaceFormatsKHRFn)( - VkPhysicalDevice, - VkSurfaceKHR, - uint32_t*, - VkSurfaceFormatKHR*); - -typedef VkResult (*vkGetPhysicalDeviceSurfacePresentModesKHRFn)( - VkPhysicalDevice, - VkSurfaceKHR, - uint32_t*, - VkPresentModeKHR*); - -typedef VkResult (*vkCreateSwapchainKHRFn)( - VkDevice, - const VkSwapchainCreateInfoKHR*, - const VkAllocationCallbacks*, - VkSwapchainKHR*); - -typedef void (*vkDestroySwapchainKHRFn)( - VkDevice, - VkSwapchainKHR, - const VkAllocationCallbacks*); - -typedef VkResult (*vkGetSwapchainImagesKHRFn)( - VkDevice, - VkSwapchainKHR, - uint32_t*, - VkImage*); - -typedef VkResult (*vkAcquireNextImageKHRFn)( - VkDevice, - VkSwapchainKHR, - uint64_t, - VkSemaphore, - VkFence, - uint32_t*); - -typedef VkResult (*vkQueuePresentKHRFn)( - VkQueue, - const VkPresentInfoKHR*); - -typedef VkResult (*vkCreateImageViewFn)( - VkDevice, - const VkImageViewCreateInfo*, - const VkAllocationCallbacks*, - VkImageView*); - -typedef void (*vkDestroyImageViewFn)( - VkDevice, - VkImageView, - const VkAllocationCallbacks*); - -typedef void (*vkGetPhysicalDeviceProperties2Fn)( - VkPhysicalDevice, - VkPhysicalDeviceProperties2*); typedef struct { bool hasDebug; @@ -251,37 +65,40 @@ typedef struct { void* libWayland; wl_display_get_fd_fn getDisplayFd; - vkEnumerateInstanceVersionFn enumerateInstanceVersion; - vkEnumerateInstanceExtensionPropertiesFn enumerateInstanceExtensionProperties; - vkDestroyInstanceFn destroyInstance; - vkCreateInstanceFn createInstance; - vkEnumeratePhysicalDevicesFn enumeratePhysicalDevices; - vkGetPhysicalDevicePropertiesFn getPhysicalDeviceProperties; - vkGetPhysicalDeviceMemoryPropertiesFn getPhysicalDeviceMemoryProperties; - vkEnumerateInstanceLayerPropertiesFn enumerateInstanceLayerProperties; - vkGetPhysicalDeviceQueueFamilyPropertiesFn getPhysicalDeviceQueueFamilyProperties; - vkEnumerateDeviceExtensionPropertiesFn enumerateDeviceExtensionProperties; - vkGetPhysicalDeviceFeaturesFn getPhysicalDeviceFeatures; - vkGetPhysicalDeviceFeatures2Fn getPhysicalDeviceFeatures2; - vkGetPhysicalDeviceFeatures2KHRFn getPhysicalDeviceFeatures2KHR; - vkGetInstanceProcAddrFn getInstanceProcAddr; - vkCreateImageViewFn createImageView; - vkDestroyImageViewFn destroyImageView; - vkGetPhysicalDeviceProperties2Fn getPhysicalDeviceProperties2; + PFN_vkEnumerateInstanceVersion enumerateInstanceVersion; + PFN_vkEnumerateInstanceExtensionProperties enumerateInstanceExtensionProperties; + PFN_vkDestroyInstance destroyInstance; + PFN_vkCreateInstance createInstance; + PFN_vkEnumeratePhysicalDevices enumeratePhysicalDevices; + PFN_vkGetPhysicalDeviceProperties getPhysicalDeviceProperties; + PFN_vkGetPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties; + PFN_vkEnumerateInstanceLayerProperties enumerateInstanceLayerProperties; + PFN_vkGetPhysicalDeviceQueueFamilyProperties getPhysicalDeviceQueueFamilyProperties; + PFN_vkEnumerateDeviceExtensionProperties enumerateDeviceExtensionProperties; + PFN_vkGetPhysicalDeviceFeatures getPhysicalDeviceFeatures; + PFN_vkGetPhysicalDeviceFeatures2 getPhysicalDeviceFeatures2; + PFN_vkGetPhysicalDeviceFeatures2KHR getPhysicalDeviceFeatures2KHR; + PFN_vkGetInstanceProcAddr getInstanceProcAddr; + PFN_vkCreateImageView createImageView; + PFN_vkDestroyImageView destroyImageView; + PFN_vkGetPhysicalDeviceProperties2 getPhysicalDeviceProperties2; - vkCreateDeviceFn createDevice; - vkDestroyDeviceFn destroyDevice; - vkGetDeviceQueueFn getDeviceQueue; - vkGetDeviceProcAddrFn getDeviceProcAddr; - - vkCreateWaylandSurfaceKHRFn createWaylandSurface; - vkGetPhysicalDeviceWaylandPresentationSupportKHRFn checkWaylandPresentSupport; - vkCreateXlibSurfaceKHRFn createXlibSurface; - vkGetPhysicalDeviceXlibPresentationSupportKHRFn checkXlibPresentSupport; - vkDestroySurfaceKHRFn destroySurface; - vkGetPhysicalDeviceSurfaceCapabilitiesKHRFn getSurfaceCapabilities; - vkGetPhysicalDeviceSurfaceFormatsKHRFn getSurfaceFormats; - vkGetPhysicalDeviceSurfacePresentModesKHRFn getSurfacePresentModes; + PFN_vkCreateDevice createDevice; + PFN_vkDestroyDevice destroyDevice; + PFN_vkGetDeviceQueue getDeviceQueue; + PFN_vkGetDeviceProcAddr getDeviceProcAddr; + PFN_vkCreateImage createImage; + PFN_vkDestroyImage destroyImage; + + PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; + PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; + PFN_vkCreateXlibSurfaceKHR createXlibSurface; + PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR checkXlibPresentSupport; + + PFN_vkDestroySurfaceKHR destroySurface; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR getSurfaceCapabilities; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR getSurfaceFormats; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR getSurfacePresentModes; VkAllocationCallbacks allocator; } Vulkan; @@ -300,11 +117,11 @@ typedef struct { VkPhysicalDevice phyDevice; VkDevice handle; PhysicalQueue* phyQueues; - vkCreateSwapchainKHRFn createSwapchain; - vkDestroySwapchainKHRFn destroySwapchain; - vkGetSwapchainImagesKHRFn getSwapchainImages; - vkAcquireNextImageKHRFn acquireNextImage; - vkQueuePresentKHRFn queuePresent; + PFN_vkCreateSwapchainKHR createSwapchain; + PFN_vkDestroySwapchainKHR destroySwapchain; + PFN_vkGetSwapchainImagesKHR getSwapchainImages; + PFN_vkAcquireNextImageKHR acquireNextImage; + PFN_vkQueuePresentKHR queuePresent; } Device; typedef struct { @@ -313,6 +130,12 @@ typedef struct { PhysicalQueue* phyQueue; } Queue; +typedef struct { + Device* device; + VkImage handle; + PalImageInfo info; +} Image; + typedef struct { Int32 bufferCount; VkFormat format; @@ -491,6 +314,332 @@ static PalResult vkResultToPal(VkResult result) return PAL_RESULT_PLATFORM_FAILURE; } +static VkImageUsageFlags palUsageToVk(PalImageUsages usages) +{ + VkImageUsageFlags flags = 0; + if (usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { + flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + + if (usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { + flags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + + if (usages & PAL_IMAGE_USAGE_TRANSFER_SRC) { + flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } + + if (usages & PAL_IMAGE_USAGE_TRANSFER_DST) { + flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + + if (usages & PAL_IMAGE_USAGE_STORAGE) { + flags |= VK_IMAGE_USAGE_STORAGE_BIT; + } + + if (usages & PAL_IMAGE_USAGE_SAMPLED) { + flags |= VK_IMAGE_USAGE_SAMPLED_BIT; + } + + return flags; +} + +static VkFormat palFormatToVk(PalFormat format) +{ + switch (format) { + case PAL_FORMAT_R8_UNORM: + return VK_FORMAT_R8_UNORM; + + case PAL_FORMAT_R8_SNORM: + return VK_FORMAT_R8_SNORM; + + case PAL_FORMAT_R8_UINT: + return VK_FORMAT_R8_UINT; + + case PAL_FORMAT_R8_SINT: + return VK_FORMAT_R8_SINT; + + case PAL_FORMAT_R8_SRGB: + return VK_FORMAT_R8_SRGB; + + case PAL_FORMAT_R16_UNORM: + return VK_FORMAT_R16_UNORM; + + case PAL_FORMAT_R16_SNORM: + return VK_FORMAT_R16_SNORM; + + case PAL_FORMAT_R16_UINT: + return VK_FORMAT_R16_UINT; + + case PAL_FORMAT_R16_SINT: + return VK_FORMAT_R16_SINT; + + case PAL_FORMAT_R16_SFLOAT: + return VK_FORMAT_R16_SFLOAT; + + case PAL_FORMAT_R32_UINT: + return VK_FORMAT_R32_UINT; + + case PAL_FORMAT_R32_SINT: + return VK_FORMAT_R32_SINT; + + case PAL_FORMAT_R32_SFLOAT: + return VK_FORMAT_R32_SFLOAT; + + case PAL_FORMAT_R64_UINT: + return VK_FORMAT_R64_UINT; + + case PAL_FORMAT_R64_SINT: + return VK_FORMAT_R64_SINT; + + case PAL_FORMAT_R64_SFLOAT: + return VK_FORMAT_R64_SFLOAT; + + case PAL_FORMAT_R8G8_UNORM: + return VK_FORMAT_R8G8_UNORM; + + case PAL_FORMAT_R8G8_SNORM: + return VK_FORMAT_R8G8_SNORM; + + case PAL_FORMAT_R8G8_UINT: + return VK_FORMAT_R8G8_UINT; + + case PAL_FORMAT_R8G8_SINT: + return VK_FORMAT_R8G8_SINT; + + case PAL_FORMAT_R8G8_SRGB: + return VK_FORMAT_R8G8_SRGB; + + case PAL_FORMAT_R16G16_UNORM: + return VK_FORMAT_R16G16_UNORM; + + case PAL_FORMAT_R16G16_SNORM: + return VK_FORMAT_R16G16_SNORM; + + case PAL_FORMAT_R16G16_UINT: + return VK_FORMAT_R16G16_UINT; + + case PAL_FORMAT_R16G16_SINT: + return VK_FORMAT_R16G16_SINT; + + case PAL_FORMAT_R16G16_SFLOAT: + return VK_FORMAT_R16G16_SFLOAT; + + case PAL_FORMAT_R32G32_UINT: + return VK_FORMAT_R32G32_UINT; + + case PAL_FORMAT_R32G32_SINT: + return VK_FORMAT_R32G32_SINT; + + case PAL_FORMAT_R32G32_SFLOAT: + return VK_FORMAT_R32G32_SFLOAT; + + case PAL_FORMAT_R64G64_UINT: + return VK_FORMAT_R64G64_UINT; + + case PAL_FORMAT_R64G64_SINT: + return VK_FORMAT_R64G64_SINT; + + case PAL_FORMAT_R64G64_SFLOAT: + return VK_FORMAT_R64G64_SFLOAT; + + case PAL_FORMAT_R8G8B8_UNORM: + return VK_FORMAT_R8G8B8_UNORM; + + case PAL_FORMAT_R8G8B8_SNORM: + return VK_FORMAT_R8G8B8_SNORM; + + case PAL_FORMAT_R8G8B8_UINT: + return VK_FORMAT_R8G8B8_UINT; + + case PAL_FORMAT_R8G8B8_SINT: + return VK_FORMAT_R8G8B8_SINT; + + case PAL_FORMAT_R8G8B8_SRGB: + return VK_FORMAT_R8G8B8_SRGB; + + case PAL_FORMAT_R16G16B16_UNORM: + return VK_FORMAT_R16G16B16_UNORM; + + case PAL_FORMAT_R16G16B16_SNORM: + return VK_FORMAT_R16G16B16_SNORM; + + case PAL_FORMAT_R16G16B16_UINT: + return VK_FORMAT_R16G16B16_UINT; + + case PAL_FORMAT_R16G16B16_SINT: + return VK_FORMAT_R16G16B16_SINT; + + case PAL_FORMAT_R16G16B16_SFLOAT: + return VK_FORMAT_R16G16B16_SFLOAT; + + case PAL_FORMAT_R32G32B32_UINT: + return VK_FORMAT_R32G32B32_UINT; + + case PAL_FORMAT_R32G32B32_SINT: + return VK_FORMAT_R32G32B32_SINT; + + case PAL_FORMAT_R32G32B32_SFLOAT: + return VK_FORMAT_R32G32B32_SFLOAT; + + case PAL_FORMAT_R64G64B64_UINT: + return VK_FORMAT_R64G64B64_UINT; + + case PAL_FORMAT_R64G64B64_SINT: + return VK_FORMAT_R64G64B64_SINT; + + case PAL_FORMAT_R64G64B64_SFLOAT: + return VK_FORMAT_R64G64B64_SFLOAT; + + case PAL_FORMAT_B8G8R8_UNORM: + return VK_FORMAT_B8G8R8_UNORM; + + case PAL_FORMAT_B8G8R8_SNORM: + return VK_FORMAT_B8G8R8_SNORM; + + case PAL_FORMAT_B8G8R8_UINT: + return VK_FORMAT_B8G8R8_UINT; + + case PAL_FORMAT_B8G8R8_SINT: + return VK_FORMAT_B8G8R8_SINT; + + case PAL_FORMAT_B8G8R8_SRGB: + return VK_FORMAT_B8G8R8_SRGB; + + case PAL_FORMAT_R8G8B8A8_UNORM: + return VK_FORMAT_R8G8B8A8_UNORM; + + case PAL_FORMAT_R8G8B8A8_SNORM: + return VK_FORMAT_R8G8B8A8_SNORM; + + case PAL_FORMAT_R8G8B8A8_UINT: + return VK_FORMAT_R8G8B8A8_UINT; + + case PAL_FORMAT_R8G8B8A8_SINT: + return VK_FORMAT_R8G8B8A8_SINT; + + case PAL_FORMAT_R8G8B8A8_SRGB: + return VK_FORMAT_R8G8B8A8_SRGB; + + case PAL_FORMAT_R16G16B16A16_UNORM: + return VK_FORMAT_R16G16B16A16_UNORM; + + case PAL_FORMAT_R16G16B16A16_SNORM: + return VK_FORMAT_R16G16B16A16_SNORM; + + case PAL_FORMAT_R16G16B16A16_UINT: + return VK_FORMAT_R16G16B16A16_UINT; + + case PAL_FORMAT_R16G16B16A16_SINT: + return VK_FORMAT_R16G16B16A16_SINT; + + case PAL_FORMAT_R16G16B16A16_SFLOAT: + return VK_FORMAT_R16G16B16A16_SFLOAT; + + case PAL_FORMAT_R32G32B32A32_UINT: + return VK_FORMAT_R32G32B32A32_UINT; + + case PAL_FORMAT_R32G32B32A32_SINT: + return VK_FORMAT_R32G32B32A32_SINT; + + case PAL_FORMAT_R32G32B32A32_SFLOAT: + return VK_FORMAT_R32G32B32A32_SFLOAT; + + case PAL_FORMAT_R64G64B64A64_UINT: + return VK_FORMAT_R64G64B64A64_UINT; + + case PAL_FORMAT_R64G64B64A64_SINT: + return VK_FORMAT_R64G64B64A64_SINT; + + case PAL_FORMAT_R64G64B64A64_SFLOAT: + return VK_FORMAT_R64G64B64A64_SFLOAT; + + case PAL_FORMAT_B8G8R8A8_UNORM: + return VK_FORMAT_B8G8R8A8_UNORM; + + case PAL_FORMAT_B8G8R8A8_SNORM: + return VK_FORMAT_B8G8R8A8_SNORM; + + case PAL_FORMAT_B8G8R8A8_UINT: + return VK_FORMAT_B8G8R8A8_UINT; + + case PAL_FORMAT_B8G8R8A8_SINT: + return VK_FORMAT_B8G8R8A8_SINT; + + case PAL_FORMAT_B8G8R8A8_SRGB: + return VK_FORMAT_B8G8R8A8_SRGB; + + case PAL_FORMAT_S8_UINT: + return VK_FORMAT_S8_UINT; + + case PAL_FORMAT_D16_UNORM: + return VK_FORMAT_D16_UNORM; + + case PAL_FORMAT_D32_SFLOAT: + return VK_FORMAT_D32_SFLOAT; + + case PAL_FORMAT_D32_SFLOAT_S8_UINT: + return VK_FORMAT_D32_SFLOAT_S8_UINT; + + case PAL_FORMAT_D16_UNORM_S8_UINT: + return VK_FORMAT_D16_UNORM_S8_UINT; + + case PAL_FORMAT_D24_UNORM_S8_UINT: + return VK_FORMAT_D24_UNORM_S8_UINT; + } + + return VK_FORMAT_UNDEFINED; +} + +static VkSampleCountFlags samplesToVk(Uint32 samples) +{ + switch (samples) { + case 2: + return VK_SAMPLE_COUNT_2_BIT; + + case 4: + return VK_SAMPLE_COUNT_4_BIT; + + case 8: + return VK_SAMPLE_COUNT_8_BIT; + + case 16: + return VK_SAMPLE_COUNT_16_BIT; + + case 32: + return VK_SAMPLE_COUNT_32_BIT; + + case 64: + return VK_SAMPLE_COUNT_64_BIT; + } + + return VK_SAMPLE_COUNT_1_BIT; +} + +static Uint32 vkSamplesToSamples(VkSampleCountFlags samples) +{ + if (samples & VK_SAMPLE_COUNT_2_BIT) { + return 2; + + } else if (samples & VK_SAMPLE_COUNT_4_BIT) { + return 4; + + } else if (samples & VK_SAMPLE_COUNT_8_BIT) { + return 8; + + } else if (samples & VK_SAMPLE_COUNT_16_BIT) { + return 16; + + } else if (samples & VK_SAMPLE_COUNT_32_BIT) { + return 32; + + } else if (samples & VK_SAMPLE_COUNT_64_BIT) { + return 64; + } + + return 1; +} + static void* vkAlloc( void* pUserData, size_t size, @@ -549,83 +698,83 @@ static PalResult vkInitGraphics(bool enableDebugLayer) } // clang-format off - s_Vk.enumerateInstanceVersion = (vkEnumerateInstanceVersionFn)dlsym( + s_Vk.enumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)dlsym( s_Vk.handle, "vkEnumerateInstanceVersion"); - s_Vk.enumerateInstanceExtensionProperties = (vkEnumerateInstanceExtensionPropertiesFn)dlsym( + s_Vk.enumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)dlsym( s_Vk.handle, "vkEnumerateInstanceExtensionProperties"); - s_Vk.createInstance = (vkCreateInstanceFn)dlsym( + s_Vk.createInstance = (PFN_vkCreateInstance)dlsym( s_Vk.handle, "vkCreateInstance"); - s_Vk.destroyInstance = (vkDestroyInstanceFn)dlsym( + s_Vk.destroyInstance = (PFN_vkDestroyInstance)dlsym( s_Vk.handle, "vkDestroyInstance"); - s_Vk.enumeratePhysicalDevices = (vkEnumeratePhysicalDevicesFn)dlsym( + s_Vk.enumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)dlsym( s_Vk.handle, "vkEnumeratePhysicalDevices"); - s_Vk.getPhysicalDeviceProperties = (vkGetPhysicalDevicePropertiesFn)dlsym( + s_Vk.getPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)dlsym( s_Vk.handle, "vkGetPhysicalDeviceProperties"); - s_Vk.getPhysicalDeviceMemoryProperties = (vkGetPhysicalDeviceMemoryPropertiesFn)dlsym( + s_Vk.getPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)dlsym( s_Vk.handle, "vkGetPhysicalDeviceMemoryProperties"); - s_Vk.enumerateInstanceLayerProperties = (vkEnumerateInstanceLayerPropertiesFn)dlsym( + s_Vk.enumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)dlsym( s_Vk.handle, "vkEnumerateInstanceLayerProperties"); - s_Vk.getPhysicalDeviceQueueFamilyProperties = (vkGetPhysicalDeviceQueueFamilyPropertiesFn)dlsym( + s_Vk.getPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)dlsym( s_Vk.handle, "vkGetPhysicalDeviceQueueFamilyProperties"); - s_Vk.enumerateDeviceExtensionProperties = (vkEnumerateDeviceExtensionPropertiesFn)dlsym( + s_Vk.enumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)dlsym( s_Vk.handle, "vkEnumerateDeviceExtensionProperties"); - s_Vk.getPhysicalDeviceFeatures = (vkGetPhysicalDeviceFeaturesFn)dlsym( + s_Vk.getPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)dlsym( s_Vk.handle, "vkGetPhysicalDeviceFeatures"); - s_Vk.getPhysicalDeviceFeatures2 = (vkGetPhysicalDeviceFeatures2Fn)dlsym( + s_Vk.getPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)dlsym( s_Vk.handle, "vkGetPhysicalDeviceFeatures2"); - s_Vk.getInstanceProcAddr = (vkGetInstanceProcAddrFn)dlsym( + s_Vk.getInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym( s_Vk.handle, "vkGetInstanceProcAddr"); - s_Vk.createImageView = (vkCreateImageViewFn)dlsym( + s_Vk.createImageView = (PFN_vkCreateImageView)dlsym( s_Vk.handle, "vkCreateImageView"); - s_Vk.destroyImageView = (vkDestroyImageViewFn)dlsym( + s_Vk.destroyImageView = (PFN_vkDestroyImageView)dlsym( s_Vk.handle, "vkDestroyImageView"); - s_Vk.getPhysicalDeviceProperties2 = (vkGetPhysicalDeviceProperties2Fn)dlsym( + s_Vk.getPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)dlsym( s_Vk.handle, "vkGetPhysicalDeviceProperties2"); - s_Vk.createDevice = (vkCreateDeviceFn)dlsym( + s_Vk.createDevice = (PFN_vkCreateDevice)dlsym( s_Vk.handle, "vkCreateDevice"); - s_Vk.destroyDevice = (vkDestroyDeviceFn)dlsym( + s_Vk.destroyDevice = (PFN_vkDestroyDevice)dlsym( s_Vk.handle, "vkDestroyDevice"); - s_Vk.getDeviceQueue = (vkGetDeviceQueueFn)dlsym( + s_Vk.getDeviceQueue = (PFN_vkGetDeviceQueue)dlsym( s_Vk.handle, "vkGetDeviceQueue"); - s_Vk.getDeviceProcAddr = (vkGetDeviceProcAddrFn)dlsym( + s_Vk.getDeviceProcAddr = (PFN_vkGetDeviceProcAddr)dlsym( s_Vk.handle, "vkGetDeviceProcAddr"); // clang-format on @@ -786,7 +935,7 @@ static PalResult vkInitGraphics(bool enableDebugLayer) if (versionFallback) { // load get physical device properties2 proc if we are on version 1.0 s_Vk.getPhysicalDeviceFeatures2KHR = - (vkGetPhysicalDeviceFeatures2KHRFn)s_Vk.getInstanceProcAddr( + (PFN_vkGetPhysicalDeviceFeatures2KHR)s_Vk.getInstanceProcAddr( s_Vk.handle, "vkGetPhysicalDeviceFeatures2KHR"); @@ -802,43 +951,43 @@ static PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.createXlibSurface = nullptr; if (hasWayland) { - s_Vk.createWaylandSurface = (vkCreateWaylandSurfaceKHRFn)s_Vk.getInstanceProcAddr( + s_Vk.createWaylandSurface = (PFN_vkCreateWaylandSurfaceKHR)s_Vk.getInstanceProcAddr( instance, "vkCreateWaylandSurfaceKHR"); s_Vk.checkWaylandPresentSupport = - (vkGetPhysicalDeviceWaylandPresentationSupportKHRFn)s_Vk.getInstanceProcAddr( + (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)s_Vk.getInstanceProcAddr( instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); } if (hasXlib) { - s_Vk.createXlibSurface = (vkCreateXlibSurfaceKHRFn)s_Vk.getInstanceProcAddr( + s_Vk.createXlibSurface = (PFN_vkCreateXlibSurfaceKHR)s_Vk.getInstanceProcAddr( instance, "vkCreateXlibSurfaceKHR"); s_Vk.checkXlibPresentSupport = - (vkGetPhysicalDeviceXlibPresentationSupportKHRFn)s_Vk.getInstanceProcAddr( + (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)s_Vk.getInstanceProcAddr( instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); } // remaining function procs - s_Vk.destroySurface = (vkDestroySurfaceKHRFn)s_Vk.getInstanceProcAddr( + s_Vk.destroySurface = (PFN_vkDestroySurfaceKHR)s_Vk.getInstanceProcAddr( instance, "vkDestroySurfaceKHR"); s_Vk.getSurfaceCapabilities = - (vkGetPhysicalDeviceSurfaceCapabilitiesKHRFn)s_Vk.getInstanceProcAddr( + (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)s_Vk.getInstanceProcAddr( instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); s_Vk.getSurfacePresentModes = - (vkGetPhysicalDeviceSurfacePresentModesKHRFn)s_Vk.getInstanceProcAddr( + (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)s_Vk.getInstanceProcAddr( instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"); - s_Vk.getSurfaceFormats = (vkGetPhysicalDeviceSurfaceFormatsKHRFn)s_Vk.getInstanceProcAddr( + s_Vk.getSurfaceFormats = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)s_Vk.getInstanceProcAddr( instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"); // clang-format on @@ -984,8 +1133,11 @@ static PalResult PAL_CALL _vkGetAdapterCapabilities( caps->maxImageHeight = props.limits.maxImageDimension2D; caps->maxImageDepth = props.limits.maxImageDimension3D; caps->maxImageArrayLayers = props.limits.maxImageArrayLayers; - caps->maxColorSamples = props.limits.framebufferColorSampleCounts; - caps->maxDepthSamples = props.limits.framebufferDepthSampleCounts; + + Uint32 tmp = vkSamplesToSamples(props.limits.framebufferColorSampleCounts); + caps->maxColorSamples = tmp; + tmp = vkSamplesToSamples(props.limits.framebufferDepthSampleCounts); + caps->maxDepthSamples = tmp; caps->maxViewports = props.limits.maxViewports; caps->maxSamplers = props.limits.maxSamplerAllocationCount; @@ -1003,7 +1155,7 @@ static PalResult PAL_CALL _vkGetAdapterCapabilities( Uint32 b = caps->maxImageHeight; Uint32 c = caps->maxImageDepth; - Uint32 tmp = a > b ? a : b; + tmp = a > b ? a : b; Uint32 size = tmp > c ? tmp : c; Uint32 levels = 0; while (size > 0) { @@ -1575,23 +1727,23 @@ static PalResult PAL_CALL _vkCreateDevice( } // load procs - device->acquireNextImage = (vkAcquireNextImageKHRFn)s_Vk.getDeviceProcAddr( + device->acquireNextImage = (PFN_vkAcquireNextImageKHR)s_Vk.getDeviceProcAddr( device->handle, "vkAcquireNextImageKHR"); - device->createSwapchain = (vkCreateSwapchainKHRFn)s_Vk.getDeviceProcAddr( + device->createSwapchain = (PFN_vkCreateSwapchainKHR)s_Vk.getDeviceProcAddr( device->handle, "vkCreateSwapchainKHR"); - device->destroySwapchain = (vkDestroySwapchainKHRFn)s_Vk.getDeviceProcAddr( + device->destroySwapchain = (PFN_vkDestroySwapchainKHR)s_Vk.getDeviceProcAddr( device->handle, "vkDestroySwapchainKHR"); - device->getSwapchainImages = (vkGetSwapchainImagesKHRFn)s_Vk.getDeviceProcAddr( + device->getSwapchainImages = (PFN_vkGetSwapchainImagesKHR)s_Vk.getDeviceProcAddr( device->handle, "vkGetSwapchainImagesKHR"); - device->queuePresent = (vkQueuePresentKHRFn)s_Vk.getDeviceProcAddr( + device->queuePresent = (PFN_vkQueuePresentKHR)s_Vk.getDeviceProcAddr( device->handle, "vkQueuePresentKHR"); @@ -1704,6 +1856,89 @@ static bool PAL_CALL _vkCanQueuePresent( return true; } +static PalResult PAL_CALL _vkCreateImage( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage) +{ + VkResult result; + Image* image = nullptr; + Device* _device = (Device*)device; + if (!_device->handle) { + return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + } + + image = palAllocate(s_Graphics.allocator, sizeof(Image), 0); + if (!image) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkImageCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + createInfo.arrayLayers = info->arrayLayers; + createInfo.extent.width = info->width; + createInfo.extent.height = info->height; + createInfo.extent.depth = info->depth; + createInfo.mipLevels = info->mipLevels; + + createInfo.format = palFormatToVk(info->format); + createInfo.samples = samplesToVk(info->samples); + createInfo.usage = palUsageToVk(info->usages); + + // image type + if (info->depth > 1) { + createInfo.imageType = VK_IMAGE_TYPE_3D; + + } else if (info->height > 1) { + createInfo.imageType = VK_IMAGE_TYPE_2D; + + } else { + createInfo.imageType = VK_IMAGE_TYPE_1D; + } + + result = s_Vk.createImage( + _device->handle, + &createInfo, + &s_Vk.allocator, + &image->handle); + + if (result != VK_SUCCESS) { + palFree(s_Graphics.allocator, image); + return vkResultToPal(result); + } + + image->info.arrayLayers = info->arrayLayers; + image->info.depth = info->depth; + image->info.format = info->format; + image->info.height = info->height; + image->info.memoryType = info->memoryType; + image->info.mipLevels = info->mipLevels; + image->info.samples = info->samples; + image->info.usages = info->usages; + image->info.width = info->width; + + *outImage = (PalImage*)image; + return PAL_RESULT_SUCCESS; +} + +static void PAL_CALL _vkDestroyImage(PalImage* image) +{ + Image* _image = (Image*)image; + s_Vk.destroyImage(_image->device->handle, _image->handle, &s_Vk.allocator); + palFree(s_Graphics.allocator, _image); +} + +PalResult PAL_CALL _vkGetImageInfo( + PalImage* image, + PalImageInfo* info) +{ + Image* _image = (Image*)image; + *info = _image->info; +} + // static PalResult PAL_CALL vkQuerySwapchainCapabilities( // PalGPUAdapter* adapter, // PalGPUWindow* window, @@ -2220,6 +2455,11 @@ static PalGPUBackend s_VkBackend = { .destroyQueue = _vkDestroyQueue, .canQueuePresent = _vkCanQueuePresent, + // image + .createImage = _vkCreateImage, + .destroyImage = _vkDestroyImage, + .getImageInfo = _vkGetImageInfo + // // swapchain // .querySwapchainCapabilities = vkQuerySwapchainCapabilities, // .createSwapchain = vkCreateSwapchain, @@ -2558,6 +2798,79 @@ bool PAL_CALL palCanQueuePresent( return false; } +PalResult PAL_CALL palCreateImage( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !outImage) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = findHandleData(device); + if (!data) { + return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + } + + PalImage* image = nullptr; + PalResult ret; + ret = data->backend->createImage( + device, + info, + &image); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + // create a slot for the created image + HandleData* imageData = getFreeHandleData(); + if (!imageData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + imageData->backend = data->backend; + imageData->handle = image; + + *outImage = image; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyImage(PalImage* image) +{ + if (s_Graphics.initialized && image) { + HandleData* data = findHandleData(image); + if (data) { + data->backend->destroyImage(image); + data->used = false; + } + } +} + +PalResult PAL_CALL palGetImageInfo( + PalImage* image, + PalImageInfo* info) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!image || !info) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = findHandleData(image); + if (!data) { + return PAL_RESULT_INVALID_GRAPHICS_IMAGE; + } + + return data->backend->getImageInfo(image, info); +} + // ================================================== // Swapchain // ================================================== diff --git a/src/pal_core.c b/src/pal_core.c index 828bf4f8..84aba60f 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -413,6 +413,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_SWAPCHAIN: return "Invalid swapchain"; + + case PAL_RESULT_INVALID_GRAPHICS_IMAGE: + return "Invalid graphics image"; } return "Unknown"; } diff --git a/tests/queue_test.c b/tests/queue_test.c index 2e2162ba..9743279f 100644 --- a/tests/queue_test.c +++ b/tests/queue_test.c @@ -1,5 +1,6 @@ #include "pal/pal_graphics.h" +#include "pal/pal_video.h" #include "tests.h" bool queueTest() @@ -115,6 +116,51 @@ bool queueTest() return false; } + // check if the graphics queue we created is presentable + // to the provided window. we need a window + result = palInitVideo(nullptr, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize video: %s", error); + return false; + } + + PalWindow* window = nullptr; + PalWindowCreateInfo createInfo = {0}; + createInfo.height = 480; + createInfo.width = 640; + createInfo.show = true; + + // check if we support decorated windows (title bar, close etc) + PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); + if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + // if we dont support, we need to create a borderless window + // and create the decorations ourselves + createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&createInfo, &window); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create window: %s", error); + return false; + } + + PalGraphicsWindow gWindow = {0}; + PalWindowHandleInfo winInfo = palGetWindowHandleInfo(window); + gWindow.display = winInfo.nativeDisplay; + gWindow.window = winInfo.nativeWindow; + + bool canPresent = palCanQueuePresent(gfxQueue, &gWindow); + const char* boolString = "True"; + if (!canPresent) { + boolString = "False"; + } + palLog(nullptr, "Graphics queue presentable: %s", boolString); + + palDestroyWindow(window); + palShutdownVideo(); + // destroy the graphics queue palDestroyQueue(gfxQueue); diff --git a/tests/tests_main.c b/tests/tests_main.c index adaf1f99..5f07de0a 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,12 +55,12 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); + registerTest("Graphics Test", graphicsTest); // registerTest("Device Test", deviceTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest("Queue Test", queueTest); + // registerTest("Queue Test", queueTest); #endif runTests(); From 67b5b0aca70b7e5b3501b687fbe32f5a97bd087e Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 2 Dec 2025 11:18:46 +0000 Subject: [PATCH 026/372] add extra image api --- include/pal/pal_graphics.h | 51 +++- src/graphics/pal_graphics_linux.c | 422 +++++++++++++++++++++++++++++- tests/device_test.c | 2 +- tests/image_test.c | 147 +++++++++++ tests/queue_test.c | 2 +- tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 3 +- 8 files changed, 613 insertions(+), 18 deletions(-) create mode 100644 tests/image_test.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index f1f13ef4..d5f30baf 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -83,6 +83,8 @@ typedef enum { } PalCompositeAplha; typedef enum { + PAL_FORMAT_UNDEFINED, + PAL_FORMAT_R8_UNORM, PAL_FORMAT_R8_SNORM, PAL_FORMAT_R8_UINT, @@ -162,10 +164,14 @@ typedef enum { PAL_FORMAT_D32_SFLOAT, PAL_FORMAT_D32_SFLOAT_S8_UINT, PAL_FORMAT_D16_UNORM_S8_UINT, - PAL_FORMAT_D24_UNORM_S8_UINT + PAL_FORMAT_D24_UNORM_S8_UINT, + + PAL_FORMAT_MAX } PalFormat; typedef enum { + PAL_IMAGE_USAGE_UNDEFINED = 0, + PAL_IMAGE_USAGE_COLOR_ATTACHEMENT = PAL_BIT(0), PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT = PAL_BIT(1), PAL_IMAGE_USAGE_TRANSFER_SRC = PAL_BIT(2), @@ -325,6 +331,11 @@ typedef struct { // PalRenderPassAttachmentInfo* attachments; // } PalRenderPassCreateInfo; +typedef struct { + PalFormat format; + PalImageUsages usages; +} PalFormatInfo; + typedef struct { Uint32 width; Uint32 height; @@ -332,9 +343,8 @@ typedef struct { Uint32 mipLevels; Uint32 arrayLayers; Uint32 samples; - PalFormat format; - PalImageUsages usages; PalMemoryType memoryType; + PalFormatInfo format; } PalImageInfo; typedef struct { @@ -344,15 +354,14 @@ typedef struct { Uint32 mipLevels; Uint32 arrayLayers; Uint32 samples; - PalFormat format; - PalImageUsages usages; PalMemoryType memoryType; + PalFormatInfo format; } PalImageCreateInfo; typedef struct { void* display; void* window; -} PalGraphicsWindow; +} PalGfxWindow; typedef struct { PalResult PAL_CALL (*enumerateAdapters)( @@ -383,7 +392,7 @@ typedef struct { bool PAL_CALL (*canQueuePresent)( PalQueue* queue, - PalGraphicsWindow* window); + PalGfxWindow* window); PalResult PAL_CALL (*createImage)( PalDevice* device, @@ -396,6 +405,19 @@ typedef struct { PalImage* image, PalImageInfo* info); + PalResult PAL_CALL (*enumerateFormats)( + PalAdapter* adapter, + Int32* count, + PalFormatInfo* outFormats); + + bool PAL_CALL (*isFormatSupported)( + PalAdapter* adapter, + PalFormat format); + + PalImageUsages PAL_CALL (*queryFormatUsages)( + PalAdapter* adapter, + PalFormat format); + // PalResult PAL_CALL (*querySwapchainCapabilities)( // PalGPUAdapter* adapter, // PalGPUWindow* window, @@ -466,7 +488,7 @@ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); PAL_API bool PAL_CALL palCanQueuePresent( PalQueue* queue, - PalGraphicsWindow* window); + PalGfxWindow* window); PAL_API PalResult PAL_CALL palCreateImage( PalDevice* device, @@ -479,6 +501,19 @@ PAL_API PalResult PAL_CALL palGetImageInfo( PalImage* image, PalImageInfo* info); +PAL_API PalResult PAL_CALL palEnumerateFormats( + PalAdapter* adapter, + Int32* count, + PalFormatInfo* outFormats); + +PAL_API bool PAL_CALL palIsFormatSupported( + PalAdapter* adapter, + PalFormat format); + +PAL_API PalImageUsages PAL_CALL palQueryFormatUsages( + PalAdapter* adapter, + PalFormat format); + // PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( // PalGPUAdapter* adapter, // PalGPUWindow* window, diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 03d5535b..28d99975 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -82,6 +82,7 @@ typedef struct { PFN_vkCreateImageView createImageView; PFN_vkDestroyImageView destroyImageView; PFN_vkGetPhysicalDeviceProperties2 getPhysicalDeviceProperties2; + PFN_vkGetPhysicalDeviceFormatProperties getPhysicalDeviceFormatProperties; PFN_vkCreateDevice createDevice; PFN_vkDestroyDevice destroyDevice; @@ -640,6 +641,283 @@ static Uint32 vkSamplesToSamples(VkSampleCountFlags samples) return 1; } +static PalFormat vkFormatToPal(VkFormat format) +{ + switch (format) { + case VK_FORMAT_R8_UNORM: + return PAL_FORMAT_R8_UNORM; + + case VK_FORMAT_R8_SNORM: + return PAL_FORMAT_R8_SNORM; + + case VK_FORMAT_R8_UINT: + return PAL_FORMAT_R8_UINT; + + case VK_FORMAT_R8_SINT: + return PAL_FORMAT_R8_SINT; + + case VK_FORMAT_R8_SRGB: + return PAL_FORMAT_R8_SRGB; + + case VK_FORMAT_R16_UNORM: + return PAL_FORMAT_R16_UNORM; + + case VK_FORMAT_R16_SNORM: + return PAL_FORMAT_R16_SNORM; + + case VK_FORMAT_R16_UINT: + return PAL_FORMAT_R16_UINT; + + case VK_FORMAT_R16_SINT: + return PAL_FORMAT_R16_SINT; + + case VK_FORMAT_R16_SFLOAT: + return PAL_FORMAT_R16_SFLOAT; + + case VK_FORMAT_R32_UINT: + return PAL_FORMAT_R32_UINT; + + case VK_FORMAT_R32_SINT: + return PAL_FORMAT_R32_SINT; + + case VK_FORMAT_R32_SFLOAT: + return PAL_FORMAT_R32_SFLOAT; + + case VK_FORMAT_R64_UINT: + return PAL_FORMAT_R64_UINT; + + case VK_FORMAT_R64_SINT: + return PAL_FORMAT_R64_SINT; + + case VK_FORMAT_R64_SFLOAT: + return PAL_FORMAT_R64_SFLOAT; + + case VK_FORMAT_R8G8_UNORM: + return PAL_FORMAT_R8G8_UNORM; + + case VK_FORMAT_R8G8_SNORM: + return PAL_FORMAT_R8G8_SNORM; + + case VK_FORMAT_R8G8_UINT: + return PAL_FORMAT_R8G8_UINT; + + case VK_FORMAT_R8G8_SINT: + return PAL_FORMAT_R8G8_SINT; + + case VK_FORMAT_R8G8_SRGB: + return PAL_FORMAT_R8G8_SRGB; + + case VK_FORMAT_R16G16_UNORM: + return PAL_FORMAT_R16G16_UNORM; + + case VK_FORMAT_R16G16_SNORM: + return PAL_FORMAT_R16G16_SNORM; + + case VK_FORMAT_R16G16_UINT: + return PAL_FORMAT_R16G16_UINT; + + case VK_FORMAT_R16G16_SINT: + return PAL_FORMAT_R16G16_SINT; + + case VK_FORMAT_R16G16_SFLOAT: + return PAL_FORMAT_R16G16_SFLOAT; + + case VK_FORMAT_R32G32_UINT: + return PAL_FORMAT_R32G32_UINT; + + case VK_FORMAT_R32G32_SINT: + return PAL_FORMAT_R32G32_SINT; + + case VK_FORMAT_R32G32_SFLOAT: + return PAL_FORMAT_R32G32_SFLOAT; + + case VK_FORMAT_R64G64_UINT: + return PAL_FORMAT_R64G64_UINT; + + case VK_FORMAT_R64G64_SINT: + return PAL_FORMAT_R64G64_SINT; + + case VK_FORMAT_R64G64_SFLOAT: + return PAL_FORMAT_R64G64_SFLOAT; + + case VK_FORMAT_R8G8B8_UNORM: + return PAL_FORMAT_R8G8B8_UNORM; + + case VK_FORMAT_R8G8B8_SNORM: + return PAL_FORMAT_R8G8B8_SNORM; + + case VK_FORMAT_R8G8B8_UINT: + return PAL_FORMAT_R8G8B8_UINT; + + case VK_FORMAT_R8G8B8_SINT: + return PAL_FORMAT_R8G8B8_SINT; + + case VK_FORMAT_R8G8B8_SRGB: + return PAL_FORMAT_R8G8B8_SRGB; + + case VK_FORMAT_R16G16B16_UNORM: + return PAL_FORMAT_R16G16B16_UNORM; + + case VK_FORMAT_R16G16B16_SNORM: + return PAL_FORMAT_R16G16B16_SNORM; + + case VK_FORMAT_R16G16B16_UINT: + return PAL_FORMAT_R16G16B16_UINT; + + case VK_FORMAT_R16G16B16_SINT: + return PAL_FORMAT_R16G16B16_SINT; + + case VK_FORMAT_R16G16B16_SFLOAT: + return PAL_FORMAT_R16G16B16_SFLOAT; + + case VK_FORMAT_R32G32B32_UINT: + return PAL_FORMAT_R32G32B32_UINT; + + case VK_FORMAT_R32G32B32_SINT: + return PAL_FORMAT_R32G32B32_SINT; + + case VK_FORMAT_R32G32B32_SFLOAT: + return PAL_FORMAT_R32G32B32_SFLOAT; + + case VK_FORMAT_R64G64B64_UINT: + return PAL_FORMAT_R64G64B64_UINT; + + case VK_FORMAT_R64G64B64_SINT: + return PAL_FORMAT_R64G64B64_SINT; + + case VK_FORMAT_R64G64B64_SFLOAT: + return PAL_FORMAT_R64G64B64_SFLOAT; + + case VK_FORMAT_B8G8R8_UNORM: + return PAL_FORMAT_B8G8R8_UNORM; + + case VK_FORMAT_B8G8R8_SNORM: + return PAL_FORMAT_B8G8R8_SNORM; + + case VK_FORMAT_B8G8R8_UINT: + return PAL_FORMAT_B8G8R8_UINT; + + case VK_FORMAT_B8G8R8_SINT: + return PAL_FORMAT_B8G8R8_SINT; + + case VK_FORMAT_B8G8R8_SRGB: + return PAL_FORMAT_B8G8R8_SRGB; + + case VK_FORMAT_R8G8B8A8_UNORM: + return PAL_FORMAT_R8G8B8A8_UNORM; + + case VK_FORMAT_R8G8B8A8_SNORM: + return PAL_FORMAT_R8G8B8A8_SNORM; + + case VK_FORMAT_R8G8B8A8_UINT: + return PAL_FORMAT_R8G8B8A8_UINT; + + case VK_FORMAT_R8G8B8A8_SINT: + return PAL_FORMAT_R8G8B8A8_SINT; + + case VK_FORMAT_R8G8B8A8_SRGB: + return PAL_FORMAT_R8G8B8A8_SRGB; + + case VK_FORMAT_R16G16B16A16_UNORM: + return PAL_FORMAT_R16G16B16A16_UNORM; + + case VK_FORMAT_R16G16B16A16_SNORM: + return PAL_FORMAT_R16G16B16A16_SNORM; + + case VK_FORMAT_R16G16B16A16_UINT: + return PAL_FORMAT_R16G16B16A16_UINT; + + case VK_FORMAT_R16G16B16A16_SINT: + return PAL_FORMAT_R16G16B16A16_SINT; + + case VK_FORMAT_R16G16B16A16_SFLOAT: + return PAL_FORMAT_R16G16B16A16_SFLOAT; + + case VK_FORMAT_R32G32B32A32_UINT: + return PAL_FORMAT_R32G32B32A32_UINT; + + case VK_FORMAT_R32G32B32A32_SINT: + return PAL_FORMAT_R32G32B32A32_SINT; + + case VK_FORMAT_R32G32B32A32_SFLOAT: + return PAL_FORMAT_R32G32B32A32_SFLOAT; + + case VK_FORMAT_R64G64B64A64_UINT: + return PAL_FORMAT_R64G64B64A64_UINT; + + case VK_FORMAT_R64G64B64A64_SINT: + return PAL_FORMAT_R64G64B64A64_SINT; + + case VK_FORMAT_R64G64B64A64_SFLOAT: + return PAL_FORMAT_R64G64B64A64_SFLOAT; + + case VK_FORMAT_B8G8R8A8_UNORM: + return PAL_FORMAT_B8G8R8A8_UNORM; + + case VK_FORMAT_B8G8R8A8_SNORM: + return PAL_FORMAT_B8G8R8A8_SNORM; + + case VK_FORMAT_B8G8R8A8_UINT: + return PAL_FORMAT_B8G8R8A8_UINT; + + case VK_FORMAT_B8G8R8A8_SINT: + return PAL_FORMAT_B8G8R8A8_SINT; + + case VK_FORMAT_B8G8R8A8_SRGB: + return PAL_FORMAT_B8G8R8A8_SRGB; + + case VK_FORMAT_S8_UINT: + return PAL_FORMAT_S8_UINT; + + case VK_FORMAT_D16_UNORM: + return PAL_FORMAT_D16_UNORM; + + case VK_FORMAT_D32_SFLOAT: + return PAL_FORMAT_D32_SFLOAT; + + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return PAL_FORMAT_D32_SFLOAT_S8_UINT; + + case VK_FORMAT_D16_UNORM_S8_UINT: + return PAL_FORMAT_D16_UNORM_S8_UINT; + + case VK_FORMAT_D24_UNORM_S8_UINT: + return PAL_FORMAT_D24_UNORM_S8_UINT; + } + + return PAL_FORMAT_UNDEFINED; +} + +static PalImageUsages vkFeatureToPalUsage(VkFormatFeatureFlags flags) +{ + PalImageUsages usages = 0; + if (flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { + usages |= PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; + } + + if (flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { + usages |= PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT; + } + + if (flags & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) { + usages |= PAL_IMAGE_USAGE_TRANSFER_SRC; + } + + if (flags & VK_FORMAT_FEATURE_TRANSFER_DST_BIT) { + usages |= PAL_IMAGE_USAGE_TRANSFER_DST; + } + + if (flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) { + usages |= VK_IMAGE_USAGE_STORAGE_BIT; + } + + if (flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { + usages |= PAL_IMAGE_USAGE_SAMPLED; + } + + return usages; +} + static void* vkAlloc( void* pUserData, size_t size, @@ -762,6 +1040,10 @@ static PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.handle, "vkGetPhysicalDeviceProperties2"); + s_Vk.getPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)dlsym( + s_Vk.handle, + "vkGetPhysicalDeviceFormatProperties"); + s_Vk.createDevice = (PFN_vkCreateDevice)dlsym( s_Vk.handle, "vkCreateDevice"); @@ -1839,7 +2121,7 @@ static void PAL_CALL _vkDestroyQueue(PalQueue* queue) static bool PAL_CALL _vkCanQueuePresent( PalQueue* queue, - PalGraphicsWindow* window) + PalGfxWindow* window) { bool onWayland = vkOnWayland(window->display); Queue* _queue = (Queue*)queue; @@ -1884,9 +2166,9 @@ static PalResult PAL_CALL _vkCreateImage( createInfo.extent.depth = info->depth; createInfo.mipLevels = info->mipLevels; - createInfo.format = palFormatToVk(info->format); + createInfo.format = palFormatToVk(info->format.format); createInfo.samples = samplesToVk(info->samples); - createInfo.usage = palUsageToVk(info->usages); + createInfo.usage = palUsageToVk(info->format.usages); // image type if (info->depth > 1) { @@ -1910,6 +2192,8 @@ static PalResult PAL_CALL _vkCreateImage( return vkResultToPal(result); } + // TODO: memory allocation + image->info.arrayLayers = info->arrayLayers; image->info.depth = info->depth; image->info.format = info->format; @@ -1917,7 +2201,6 @@ static PalResult PAL_CALL _vkCreateImage( image->info.memoryType = info->memoryType; image->info.mipLevels = info->mipLevels; image->info.samples = info->samples; - image->info.usages = info->usages; image->info.width = info->width; *outImage = (PalImage*)image; @@ -1939,6 +2222,73 @@ PalResult PAL_CALL _vkGetImageInfo( *info = _image->info; } +PalResult PAL_CALL _vkEnumerateFormats( + PalAdapter* adapter, + Int32* count, + PalFormatInfo* outFormats) +{ + Int32 fmtCount = 0; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + VkFormatProperties props = {0}; + + for (int i = 0; i < PAL_FORMAT_MAX; i++) { + VkFormat fmt = palFormatToVk((PalFormat)i); + s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); + if (props.optimalTilingFeatures != 0) { + // format supported + if (outFormats) { + if (fmtCount < *count) { + PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; + fmtInfo->format = (PalFormat)i; + fmtInfo->usages = + vkFeatureToPalUsage(props.optimalTilingFeatures); + } + + } else { + fmtCount++; + } + } + } + + if (!outFormats) { + *count = fmtCount; + } + + return PAL_RESULT_SUCCESS; +} + +bool PAL_CALL _vkIsFormatSupported( + PalAdapter* adapter, + PalFormat format) +{ + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + VkFormatProperties props = {0}; + + VkFormat fmt = palFormatToVk(format); + s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); + if (props.optimalTilingFeatures != 0) { + return true; + } + + return false; +} + +PalImageUsages PAL_CALL _vkQueryFormatUsages( + PalAdapter* adapter, + PalFormat format) +{ + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + VkFormatProperties props = {0}; + + VkFormat fmt = palFormatToVk(format); + s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); + if (props.optimalTilingFeatures != 0) { + return vkFeatureToPalUsage(props.optimalTilingFeatures); + } + + return PAL_IMAGE_USAGE_UNDEFINED; +} + // static PalResult PAL_CALL vkQuerySwapchainCapabilities( // PalGPUAdapter* adapter, // PalGPUWindow* window, @@ -2458,7 +2808,10 @@ static PalGPUBackend s_VkBackend = { // image .createImage = _vkCreateImage, .destroyImage = _vkDestroyImage, - .getImageInfo = _vkGetImageInfo + .getImageInfo = _vkGetImageInfo, + .enumerateFormats = _vkEnumerateFormats, + .isFormatSupported = _vkIsFormatSupported, + .queryFormatUsages = _vkQueryFormatUsages // // swapchain // .querySwapchainCapabilities = vkQuerySwapchainCapabilities, @@ -2786,7 +3139,7 @@ void PAL_CALL palDestroyQueue(PalQueue* queue) bool PAL_CALL palCanQueuePresent( PalQueue* queue, - PalGraphicsWindow* window) + PalGfxWindow* window) { if (s_Graphics.initialized && queue) { HandleData* data = findHandleData(queue); @@ -2871,6 +3224,63 @@ PalResult PAL_CALL palGetImageInfo( return data->backend->getImageInfo(image, info); } +PalResult PAL_CALL palEnumerateFormats( + PalAdapter* adapter, + Int32* count, + PalFormatInfo* outFormats) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!adapter || !count) { + return PAL_RESULT_NULL_POINTER; + } + + if (*count == 0 && outFormats) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + + HandleData* adapterData = findHandleData(adapter); + if (!adapterData) { + return PAL_RESULT_INVALID_ADAPTER; + } + + return adapterData->backend->enumerateFormats(adapter, count, outFormats); +} + +bool PAL_CALL palIsFormatSupported( + PalAdapter* adapter, + PalFormat format) +{ + if (!s_Graphics.initialized || !adapter) { + return false; + } + + HandleData* adapterData = findHandleData(adapter); + if (!adapterData) { + return false; + } + + return adapterData->backend->isFormatSupported(adapter, format); +} + +PalImageUsages PAL_CALL palQueryFormatUsages( + PalAdapter* adapter, + PalFormat format) +{ + if (!s_Graphics.initialized || !adapter) { + return PAL_IMAGE_USAGE_UNDEFINED; + } + + HandleData* adapterData = findHandleData(adapter); + if (!adapterData) { + return PAL_IMAGE_USAGE_UNDEFINED; + } + + return adapterData->backend->queryFormatUsages(adapter, format); +} + // ================================================== // Swapchain // ================================================== diff --git a/tests/device_test.c b/tests/device_test.c index fd0530c7..c5413a90 100644 --- a/tests/device_test.c +++ b/tests/device_test.c @@ -81,7 +81,7 @@ bool deviceTest() result = palGetAdapterCapabilities(vulkanAdapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); return false; } diff --git a/tests/image_test.c b/tests/image_test.c new file mode 100644 index 00000000..1c6b5e98 --- /dev/null +++ b/tests/image_test.c @@ -0,0 +1,147 @@ + +#include "pal/pal_graphics.h" +#include "tests.h" + +bool imageTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Image Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + // initialize the graphics system + PalResult result = palInitGraphics(false, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 count = 0; + result = palEnumerateAdapters(&count, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (count == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", count); + + // allocate an array of adapters or use a fixed array + // Example: PalAdapter* adapters[12]; + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&count, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + // filter the adapters for Vulkan + PalAdapter* vulkanAdapter = nullptr; + PalAdapterInfo info = {0}; + + for (Int32 i = 0; i < count; i++) { + PalAdapter* adapter = adapters[i]; + result = palGetAdapterInfo(adapter, &info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + palFree(nullptr, adapters); + return false; + } + + // check if its Vulkan + if (info.apiType == PAL_ADAPTER_API_TYPE_VULKAN) { + vulkanAdapter = adapter; + break; + } + } + + palFree(nullptr, adapters); + if (!vulkanAdapter) { + palLog(nullptr, "Failed to find a vulkan adapter"); + return false; + } + + // get capabilities about the adapter + PalAdapterCapabilities caps = {0}; + result = palGetAdapterCapabilities(vulkanAdapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + return false; + } + + // create a device with the vulkan adapter + PalDevice* device = nullptr; + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + result = palCreateDevice(vulkanAdapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a simple 2d image allocated on the gpu + // we can either enumerate all the supported formats andd choose one + // or we can choose our preffered format and check for support + + // use palEnumerateFormats() to get all supported formats + // and their image usages + + PalFormat format = PAL_FORMAT_R8G8B8A8_UNORM; + PalImageUsages usage = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; + if (!palIsFormatSupported(vulkanAdapter, format)) { + palLog(nullptr, "The preffered format is not supported"); + return false; + } + + if(!(usage & palQueryFormatUsages(vulkanAdapter, format))) { + palLog(nullptr, + "The preffered format does not support color attachement"); + return false; + } + + PalImage* image = nullptr; + PalImageCreateInfo imageCreateInfo = {0}; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.depth = 1; + imageCreateInfo.format.format = format; + imageCreateInfo.format.usages = usage; + imageCreateInfo.height = 240; + imageCreateInfo.memoryType = PAL_MEMORY_TYPE_GPU_ONLY; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.samples = 1; // very simple + imageCreateInfo.width = 320; + + result = palCreateImage(device, &imageCreateInfo, &image); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image: %s", error); + return false; + } + + // destroy image + palDestroyImage(image); + + // destroy the device + palDestroyDevice(device); + + // shutdown the graphics system + palShutdownGraphics(); + + return true; +} \ No newline at end of file diff --git a/tests/queue_test.c b/tests/queue_test.c index 9743279f..3bdab786 100644 --- a/tests/queue_test.c +++ b/tests/queue_test.c @@ -146,7 +146,7 @@ bool queueTest() return false; } - PalGraphicsWindow gWindow = {0}; + PalGfxWindow gWindow = {0}; PalWindowHandleInfo winInfo = palGetWindowHandleInfo(window); gWindow.display = winInfo.nativeDisplay; gWindow.window = winInfo.nativeWindow; diff --git a/tests/tests.h b/tests/tests.h index 4d7822f6..060357e9 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -57,6 +57,7 @@ bool multiThreadOpenGlTest(); bool graphicsTest(); bool customGraphicsBackendTest(); bool deviceTest(); +bool imageTest(); // graphics and video bool queueTest(); diff --git a/tests/tests.lua b/tests/tests.lua index 867c76fd..26d0bb05 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -66,7 +66,8 @@ project "tests" if (PAL_BUILD_GRAPHICS) then files { "graphics_test.c", - "device_test.c" + "device_test.c", + "image_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 5f07de0a..183e4a73 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,8 +55,9 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + // registerTest("Graphics Test", graphicsTest); // registerTest("Device Test", deviceTest); + registerTest("Image Test", imageTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From 231e9fe78bdb4d77536dcb136f9696e5c487e849 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 2 Dec 2025 17:57:29 +0000 Subject: [PATCH 027/372] add image memory bind --- include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 57 ++++++- src/graphics/pal_graphics_linux.c | 263 +++++++++++++++++++++++++++++- src/pal_core.c | 3 + tests/image_test.c | 44 ++++- 5 files changed, 356 insertions(+), 14 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 4baa818d..b8f82fb5 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -257,7 +257,8 @@ typedef enum { PAL_RESULT_OUT_OF_QUEUE, PAL_RESULT_INVALID_GRAPHICS_WINDOW, PAL_RESULT_INVALID_SWAPCHAIN, - PAL_RESULT_INVALID_GRAPHICS_IMAGE + PAL_RESULT_INVALID_GRAPHICS_IMAGE, + PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d5f30baf..58d72862 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -36,9 +36,11 @@ freely, subject to the following restrictions: #define PAL_ADAPTER_NAME_SIZE 128 #define PAL_ADAPTER_VERSION_SIZE 16 #define PAL_INFINITE (2147483647) +#define PAL_DEFAULT_MEMORY_OFFSET 0 typedef struct PalAdapter PalAdapter; typedef struct PalDevice PalDevice; +typedef struct PalMemory PalMemory; typedef struct PalQueue PalQueue; typedef struct PalSwapchain PalSwapchain; typedef struct PalImage PalImage; @@ -229,8 +231,9 @@ typedef enum { typedef enum { PAL_MEMORY_TYPE_GPU_ONLY, - PAL_MEMORY_CPU_UPLOAD, - PAL_MEMORY_CPU_READBACK + PAL_MEMORY_TYPE_CPU_UPLOAD, + PAL_MEMORY_TYPE_CPU_READBACK, + PAL_MEMORY_TYPE_MAX } PalMemoryType; typedef struct { @@ -343,10 +346,15 @@ typedef struct { Uint32 mipLevels; Uint32 arrayLayers; Uint32 samples; - PalMemoryType memoryType; PalFormatInfo format; } PalImageInfo; +typedef struct { + bool memoryTypeAllowed[PAL_MEMORY_TYPE_MAX]; + Uint64 size; + Uint32 alignment; +} PalMemoryRequirements; + typedef struct { Uint32 width; Uint32 height; @@ -354,7 +362,6 @@ typedef struct { Uint32 mipLevels; Uint32 arrayLayers; Uint32 samples; - PalMemoryType memoryType; PalFormatInfo format; } PalImageCreateInfo; @@ -418,6 +425,27 @@ typedef struct { PalAdapter* adapter, PalFormat format); + PalResult PAL_CALL (*getImageMemoryRequirements)( + PalDevice* device, + PalImage* image, + PalMemoryRequirements* requirments); + + PalResult PAL_CALL (*allocate)( + PalDevice* device, + PalMemoryType type, + Uint64 size, + PalMemory** outMemory); + + void PAL_CALL (*free)( + PalDevice* device, + PalMemory* memory); + + PalResult PAL_CALL (*bindImageMemory)( + PalDevice* device, + PalImage* image, + PalMemory* memory, + Uint64 offset); + // PalResult PAL_CALL (*querySwapchainCapabilities)( // PalGPUAdapter* adapter, // PalGPUWindow* window, @@ -514,6 +542,27 @@ PAL_API PalImageUsages PAL_CALL palQueryFormatUsages( PalAdapter* adapter, PalFormat format); +PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( + PalDevice* device, + PalImage* image, + PalMemoryRequirements* requirements); + +PAL_API PalResult PAL_CALL palGfxAllocate( + PalDevice* device, + PalMemoryType type, + Uint64 size, + PalMemory** outMemory); + +PAL_API void PAL_CALL palGfxFree( + PalDevice* device, + PalMemory* memory); + +PAL_API PalResult PAL_CALL palBindImageMemory( + PalDevice* device, + PalImage* image, + PalMemory* memory, + Uint64 offset); + // PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( // PalGPUAdapter* adapter, // PalGPUWindow* window, diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 28d99975..304e0f86 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -83,6 +83,10 @@ typedef struct { PFN_vkDestroyImageView destroyImageView; PFN_vkGetPhysicalDeviceProperties2 getPhysicalDeviceProperties2; PFN_vkGetPhysicalDeviceFormatProperties getPhysicalDeviceFormatProperties; + PFN_vkGetImageMemoryRequirements getImageMemoryRequirements; + PFN_vkAllocateMemory allocateMemory; + PFN_vkFreeMemory freeMemory; + PFN_vkBindImageMemory bindImageMemory; PFN_vkCreateDevice createDevice; PFN_vkDestroyDevice destroyDevice; @@ -123,6 +127,7 @@ typedef struct { PFN_vkGetSwapchainImagesKHR getSwapchainImages; PFN_vkAcquireNextImageKHR acquireNextImage; PFN_vkQueuePresentKHR queuePresent; + Int32 memoryTypeIndex[PAL_MEMORY_TYPE_MAX]; } Device; typedef struct { @@ -132,6 +137,7 @@ typedef struct { } Queue; typedef struct { + bool ownsMemory; Device* device; VkImage handle; PalImageInfo info; @@ -1028,6 +1034,14 @@ static PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.handle, "vkGetInstanceProcAddr"); + s_Vk.createImage = (PFN_vkCreateImage)dlsym( + s_Vk.handle, + "vkCreateImage"); + + s_Vk.destroyImage = (PFN_vkDestroyImage)dlsym( + s_Vk.handle, + "vkDestroyImage"); + s_Vk.createImageView = (PFN_vkCreateImageView)dlsym( s_Vk.handle, "vkCreateImageView"); @@ -1059,6 +1073,23 @@ static PalResult vkInitGraphics(bool enableDebugLayer) s_Vk.getDeviceProcAddr = (PFN_vkGetDeviceProcAddr)dlsym( s_Vk.handle, "vkGetDeviceProcAddr"); + + s_Vk.getImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)dlsym( + s_Vk.handle, + "vkGetImageMemoryRequirements"); + + s_Vk.allocateMemory = (PFN_vkAllocateMemory)dlsym( + s_Vk.handle, + "vkAllocateMemory"); + + s_Vk.freeMemory = (PFN_vkFreeMemory)dlsym( + s_Vk.handle, + "vkFreeMemory"); + + s_Vk.bindImageMemory = (PFN_vkBindImageMemory)dlsym( + s_Vk.handle, + "vkBindImageMemory"); + // clang-format on // get version @@ -2008,6 +2039,30 @@ static PalResult PAL_CALL _vkCreateDevice( } } + // cache memory type indices + VkPhysicalDeviceMemoryProperties memProps = {0}; + s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); + device->memoryTypeIndex[PAL_MEMORY_TYPE_GPU_ONLY] = -1; + device->memoryTypeIndex[PAL_MEMORY_TYPE_GPU_ONLY] = -1; + device->memoryTypeIndex[PAL_MEMORY_TYPE_GPU_ONLY] = -1; + + for (int i = 0; i < memProps.memoryTypeCount; i++) { + VkMemoryPropertyFlags prop = memProps.memoryTypes[i].propertyFlags; + if (prop & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + device->memoryTypeIndex[PAL_MEMORY_TYPE_GPU_ONLY] = i; + } + + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { + device->memoryTypeIndex[PAL_MEMORY_TYPE_CPU_UPLOAD] = i; + } + + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + device->memoryTypeIndex[PAL_MEMORY_TYPE_CPU_READBACK] = i; + } + } + // load procs device->acquireNextImage = (PFN_vkAcquireNextImageKHR)s_Vk.getDeviceProcAddr( device->handle, @@ -2192,13 +2247,11 @@ static PalResult PAL_CALL _vkCreateImage( return vkResultToPal(result); } - // TODO: memory allocation - + image->device = _device; image->info.arrayLayers = info->arrayLayers; image->info.depth = info->depth; image->info.format = info->format; image->info.height = info->height; - image->info.memoryType = info->memoryType; image->info.mipLevels = info->mipLevels; image->info.samples = info->samples; image->info.width = info->width; @@ -2214,7 +2267,7 @@ static void PAL_CALL _vkDestroyImage(PalImage* image) palFree(s_Graphics.allocator, _image); } -PalResult PAL_CALL _vkGetImageInfo( +static PalResult PAL_CALL _vkGetImageInfo( PalImage* image, PalImageInfo* info) { @@ -2222,7 +2275,7 @@ PalResult PAL_CALL _vkGetImageInfo( *info = _image->info; } -PalResult PAL_CALL _vkEnumerateFormats( +static PalResult PAL_CALL _vkEnumerateFormats( PalAdapter* adapter, Int32* count, PalFormatInfo* outFormats) @@ -2257,7 +2310,7 @@ PalResult PAL_CALL _vkEnumerateFormats( return PAL_RESULT_SUCCESS; } -bool PAL_CALL _vkIsFormatSupported( +static bool PAL_CALL _vkIsFormatSupported( PalAdapter* adapter, PalFormat format) { @@ -2273,7 +2326,7 @@ bool PAL_CALL _vkIsFormatSupported( return false; } -PalImageUsages PAL_CALL _vkQueryFormatUsages( +static PalImageUsages PAL_CALL _vkQueryFormatUsages( PalAdapter* adapter, PalFormat format) { @@ -2289,6 +2342,106 @@ PalImageUsages PAL_CALL _vkQueryFormatUsages( return PAL_IMAGE_USAGE_UNDEFINED; } +static PalResult PAL_CALL _vkGetImageMemoryRequirements( + PalDevice* device, + PalImage* image, + PalMemoryRequirements* requirments) +{ + Device* _device = (Device*)device; + Image* _image = (Image*)image; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)_device->phyDevice; + + VkPhysicalDeviceMemoryProperties memProps = {0}; + s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); + + VkMemoryRequirements memReq = {0}; + s_Vk.getImageMemoryRequirements(_device->handle, _image->handle, &memReq); + requirments->alignment = (Uint64)memReq.alignment; + requirments->size = (Uint64)memReq.size; + + requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_GPU_ONLY] = false; + requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; + requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_CPU_READBACK] = false; + + for (int i = 0; i < memProps.memoryTypeCount; i++) { + if (!(memReq.memoryTypeBits & (1 << i))) { + // memory type not supported + continue; + } + + bool t = true; + VkMemoryPropertyFlags prop = memProps.memoryTypes[i].propertyFlags; + if (prop & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_GPU_ONLY] = t; + } + + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { + requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_CPU_UPLOAD] = t; + } + + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_CPU_READBACK] = t; + } + } + + return PAL_RESULT_SUCCESS; +} + +static PalResult PAL_CALL _vkAllocate( + PalDevice* device, + PalMemoryType type, + Uint64 size, + PalMemory** outMemory) +{ + Device* _device = (Device*)device; + VkMemoryAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = (VkDeviceSize)size; + allocateInfo.memoryTypeIndex = _device->memoryTypeIndex[type]; + + if (allocateInfo.memoryTypeIndex == -1) { + // not supported + return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; + } + + VkDeviceMemory memory = nullptr; + VkResult result = s_Vk.allocateMemory( + _device->handle, + &allocateInfo, + &s_Vk.allocator, + &memory); + + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + *outMemory = (PalMemory*)memory; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL _vkFree( + PalDevice* device, + PalMemory* memory) +{ + Device* _device = (Device*)device; + VkDeviceMemory mem = (VkDeviceMemory)memory; + s_Vk.freeMemory(_device->handle, mem, &s_Vk.allocator); +} + +PalResult PAL_CALL _vkBindImageMemory( + PalDevice* device, + PalImage* image, + PalMemory* memory, + Uint64 offset) +{ + Device* _device = (Device*)device; + Image* _image = (Image*)image; + VkDeviceMemory mem = (VkDeviceMemory)memory; + s_Vk.bindImageMemory(_device->handle, _image->handle, mem, offset); +} + // static PalResult PAL_CALL vkQuerySwapchainCapabilities( // PalGPUAdapter* adapter, // PalGPUWindow* window, @@ -2811,7 +2964,13 @@ static PalGPUBackend s_VkBackend = { .getImageInfo = _vkGetImageInfo, .enumerateFormats = _vkEnumerateFormats, .isFormatSupported = _vkIsFormatSupported, - .queryFormatUsages = _vkQueryFormatUsages + .queryFormatUsages = _vkQueryFormatUsages, + .getImageMemoryRequirements = _vkGetImageMemoryRequirements, + + // memory + .allocate = _vkAllocate, + .free = _vkFree, + .bindImageMemory = _vkBindImageMemory // // swapchain // .querySwapchainCapabilities = vkQuerySwapchainCapabilities, @@ -3281,6 +3440,94 @@ PalImageUsages PAL_CALL palQueryFormatUsages( return adapterData->backend->queryFormatUsages(adapter, format); } +PalResult PAL_CALL palGetImageMemoryRequirements( + PalDevice* device, + PalImage* image, + PalMemoryRequirements* requirements) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !image) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* deviceData = findHandleData(device); + if (!deviceData) { + return PAL_RESULT_INVALID_GRAPHICS_BACKEND; + } + + return deviceData->backend->getImageMemoryRequirements( + device, + image, + requirements); +} + +// ================================================== +// Memory +// ================================================== + +PalResult PAL_CALL palGfxAllocate( + PalDevice* device, + PalMemoryType type, + Uint64 size, + PalMemory** outMemory) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!outMemory || !device) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* deviceData = findHandleData(device); + if (!deviceData) { + return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + } + + return deviceData->backend->allocate(device, type, size, outMemory); +} + +void PAL_CALL palGfxFree( + PalDevice* device, + PalMemory* memory) +{ + if (s_Graphics.initialized && device && memory) { + HandleData* data = findHandleData(device); + if (data) { + data->backend->free(device, memory); + } + } +} + +PalResult PAL_CALL palBindImageMemory( + PalDevice* device, + PalImage* image, + PalMemory* memory, + Uint64 offset) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !image || !memory) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* deviceData = findHandleData(device); + if (!deviceData) { + return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + } + + return deviceData->backend->bindImageMemory( + device, + image, + memory, + offset); +} + // ================================================== // Swapchain // ================================================== diff --git a/src/pal_core.c b/src/pal_core.c index 84aba60f..880bcfd9 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -416,6 +416,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_GRAPHICS_IMAGE: return "Invalid graphics image"; + + case PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED: + return "memory type not supported"; } return "Unknown"; } diff --git a/tests/image_test.c b/tests/image_test.c index 1c6b5e98..2cdda1c3 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -122,7 +122,6 @@ bool imageTest() imageCreateInfo.format.format = format; imageCreateInfo.format.usages = usage; imageCreateInfo.height = 240; - imageCreateInfo.memoryType = PAL_MEMORY_TYPE_GPU_ONLY; imageCreateInfo.mipLevels = 1; imageCreateInfo.samples = 1; // very simple imageCreateInfo.width = 320; @@ -134,9 +133,52 @@ bool imageTest() return false; } + // bind memory to the create image + PalMemoryRequirements imageMemReq; + result = palGetImageMemoryRequirements(device, image, &imageMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image memory requirements: %s", error); + return false; + } + + // allocate memory for the image + if (!imageMemReq.memoryTypeAllowed[PAL_MEMORY_TYPE_GPU_ONLY]) { + palLog(nullptr, "Cannot allocate gpu only memory"); + } + + PalMemory* imageMemory = nullptr; + result = palGfxAllocate( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + imageMemReq.size, + &imageMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for image: %s", error); + return false; + } + + // bind the memory to the image + result = palBindImageMemory( + device, + image, + imageMemory, + PAL_DEFAULT_MEMORY_OFFSET); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind image memory: %s", error); + return false; + } + // destroy image palDestroyImage(image); + // free the image memory + palGfxFree(device, imageMemory); + // destroy the device palDestroyDevice(device); From 36676d33a0d7706dc43a05d87a170a77eb06e7ef Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 3 Dec 2025 10:07:25 +0000 Subject: [PATCH 028/372] fix image create info field bug and add image types --- include/pal/pal_graphics.h | 28 +++++++--- src/graphics/pal_graphics_linux.c | 88 ++++++++++++++++++++++--------- tests/image_test.c | 11 ++-- 3 files changed, 93 insertions(+), 34 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 58d72862..3d3c1f8f 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -236,6 +236,22 @@ typedef enum { PAL_MEMORY_TYPE_MAX } PalMemoryType; +typedef enum { + PAL_IMAGE_TYPE_1D, + PAL_IMAGE_TYPE_2D, + PAL_IMAGE_TYPE_3D +} PalImageType; + +typedef enum { + PAL_IMAGE_VIEW_TYPE_1D, + PAL_IMAGE_VIEW_TYPE_1D_ARRAY, + PAL_IMAGE_VIEW_TYPE_2D, + PAL_IMAGE_VIEW_TYPE_2D_ARRAY, + PAL_IMAGE_VIEW_TYPE_3D, + PAL_IMAGE_VIEW_TYPE_CUBE, + PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY, +} PalImageViewType; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -342,10 +358,10 @@ typedef struct { typedef struct { Uint32 width; Uint32 height; - Uint32 depth; + Uint32 depthOrArraySize; Uint32 mipLevels; - Uint32 arrayLayers; Uint32 samples; + PalImageViewType type; PalFormatInfo format; } PalImageInfo; @@ -358,10 +374,10 @@ typedef struct { typedef struct { Uint32 width; Uint32 height; - Uint32 depth; + Uint32 depthOrArraySize; Uint32 mipLevels; - Uint32 arrayLayers; Uint32 samples; + PalImageViewType type; PalFormatInfo format; } PalImageCreateInfo; @@ -547,13 +563,13 @@ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( PalImage* image, PalMemoryRequirements* requirements); -PAL_API PalResult PAL_CALL palGfxAllocate( +PAL_API PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, Uint64 size, PalMemory** outMemory); -PAL_API void PAL_CALL palGfxFree( +PAL_API void PAL_CALL palFreeMemory( PalDevice* device, PalMemory* memory); diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 304e0f86..b33428b3 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -143,6 +143,12 @@ typedef struct { PalImageInfo info; } Image; +typedef struct { + VkFormat format; + Device* device; + VkImageView handle; +} ImageView; + typedef struct { Int32 bufferCount; VkFormat format; @@ -152,12 +158,6 @@ typedef struct { VkImage* buffers; } Swapchain; -typedef struct { - VkFormat format; - Device* device; - VkImageView handle; -} ImageView; - typedef struct { Device* device; VkFramebuffer framebuffer; @@ -924,6 +924,50 @@ static PalImageUsages vkFeatureToPalUsage(VkFormatFeatureFlags flags) return usages; } +static VkImageType palImageTypeToVk(PalImageType type) +{ + switch (type) { + case PAL_IMAGE_TYPE_1D: + return VK_IMAGE_TYPE_1D; + + case PAL_IMAGE_TYPE_2D: + return VK_IMAGE_TYPE_2D; + + case PAL_IMAGE_TYPE_3D: + return VK_IMAGE_TYPE_3D; + } + + return VK_IMAGE_TYPE_2D; +} + +static VkImageViewType palImageViewTypeToVk(PalImageViewType type) +{ + switch (type) { + case PAL_IMAGE_VIEW_TYPE_1D: + return VK_IMAGE_VIEW_TYPE_1D; + + case PAL_IMAGE_VIEW_TYPE_1D_ARRAY: + return VK_IMAGE_VIEW_TYPE_1D_ARRAY; + + case PAL_IMAGE_VIEW_TYPE_2D: + return VK_IMAGE_VIEW_TYPE_2D; + + case PAL_IMAGE_VIEW_TYPE_2D_ARRAY: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + + case PAL_IMAGE_VIEW_TYPE_3D: + return VK_IMAGE_VIEW_TYPE_3D; + + case PAL_IMAGE_VIEW_TYPE_CUBE: + return VK_IMAGE_VIEW_TYPE_CUBE; + + case PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY: + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + } + + return VK_IMAGE_VIEW_TYPE_2D; +} + static void* vkAlloc( void* pUserData, size_t size, @@ -2215,25 +2259,21 @@ static PalResult PAL_CALL _vkCreateImage( createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - createInfo.arrayLayers = info->arrayLayers; createInfo.extent.width = info->width; createInfo.extent.height = info->height; - createInfo.extent.depth = info->depth; createInfo.mipLevels = info->mipLevels; createInfo.format = palFormatToVk(info->format.format); createInfo.samples = samplesToVk(info->samples); createInfo.usage = palUsageToVk(info->format.usages); - // image type - if (info->depth > 1) { - createInfo.imageType = VK_IMAGE_TYPE_3D; + createInfo.arrayLayers = info->depthOrArraySize; + createInfo.extent.depth = 1; + createInfo.imageType = palImageTypeToVk(info->type); - } else if (info->height > 1) { - createInfo.imageType = VK_IMAGE_TYPE_2D; - - } else { - createInfo.imageType = VK_IMAGE_TYPE_1D; + if (info->type == PAL_IMAGE_TYPE_3D) { + createInfo.arrayLayers = 1; + createInfo.extent.depth = info->depthOrArraySize; } result = s_Vk.createImage( @@ -2248,8 +2288,8 @@ static PalResult PAL_CALL _vkCreateImage( } image->device = _device; - image->info.arrayLayers = info->arrayLayers; - image->info.depth = info->depth; + image->info.depthOrArraySize = info->depthOrArraySize; + image->info.type = info->type; image->info.format = info->format; image->info.height = info->height; image->info.mipLevels = info->mipLevels; @@ -2389,7 +2429,7 @@ static PalResult PAL_CALL _vkGetImageMemoryRequirements( return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL _vkAllocate( +static PalResult PAL_CALL _vkAllocateMemory( PalDevice* device, PalMemoryType type, Uint64 size, @@ -2421,7 +2461,7 @@ static PalResult PAL_CALL _vkAllocate( return PAL_RESULT_SUCCESS; } -void PAL_CALL _vkFree( +void PAL_CALL _vkFreeMemory( PalDevice* device, PalMemory* memory) { @@ -2968,8 +3008,8 @@ static PalGPUBackend s_VkBackend = { .getImageMemoryRequirements = _vkGetImageMemoryRequirements, // memory - .allocate = _vkAllocate, - .free = _vkFree, + .allocate = _vkAllocateMemory, + .free = _vkFreeMemory, .bindImageMemory = _vkBindImageMemory // // swapchain @@ -3468,7 +3508,7 @@ PalResult PAL_CALL palGetImageMemoryRequirements( // Memory // ================================================== -PalResult PAL_CALL palGfxAllocate( +PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, Uint64 size, @@ -3490,7 +3530,7 @@ PalResult PAL_CALL palGfxAllocate( return deviceData->backend->allocate(device, type, size, outMemory); } -void PAL_CALL palGfxFree( +void PAL_CALL palFreeMemory( PalDevice* device, PalMemory* memory) { diff --git a/tests/image_test.c b/tests/image_test.c index 2cdda1c3..7ac9a3a6 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -117,8 +117,6 @@ bool imageTest() PalImage* image = nullptr; PalImageCreateInfo imageCreateInfo = {0}; - imageCreateInfo.arrayLayers = 1; - imageCreateInfo.depth = 1; imageCreateInfo.format.format = format; imageCreateInfo.format.usages = usage; imageCreateInfo.height = 240; @@ -126,6 +124,11 @@ bool imageTest() imageCreateInfo.samples = 1; // very simple imageCreateInfo.width = 320; + // if the image type is 1D or 2D + // PalImageCreateInfo::depthOrArraySize is used for the array size + imageCreateInfo.type == PAL_IMAGE_TYPE_2D; + imageCreateInfo.depthOrArraySize = 1; + result = palCreateImage(device, &imageCreateInfo, &image); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -148,7 +151,7 @@ bool imageTest() } PalMemory* imageMemory = nullptr; - result = palGfxAllocate( + result = palAllocateMemory( device, PAL_MEMORY_TYPE_GPU_ONLY, imageMemReq.size, @@ -177,7 +180,7 @@ bool imageTest() palDestroyImage(image); // free the image memory - palGfxFree(device, imageMemory); + palFreeMemory(device, imageMemory); // destroy the device palDestroyDevice(device); From 084798ec98d657a0090f5fb9d73b5ef396bfcec8 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 3 Dec 2025 10:16:01 +0000 Subject: [PATCH 029/372] fix queue presentation check bug --- src/graphics/pal_graphics_linux.c | 9 +++++++-- tests/tests_main.c | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index b33428b3..f0cf5a70 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -2222,10 +2222,15 @@ static bool PAL_CALL _vkCanQueuePresent( PalQueue* queue, PalGfxWindow* window) { - bool onWayland = vkOnWayland(window->display); + // check if the queue is a graphics queue before we check its family + // index for presentation support. Queue* _queue = (Queue*)queue; - PhysicalQueue* phyQueue = _queue->phyQueue; + if (_queue->usage != VK_QUEUE_GRAPHICS_BIT) { + return false; + } + bool onWayland = vkOnWayland(window->display); + PhysicalQueue* phyQueue = _queue->phyQueue; if (!s_Vk.checkWaylandPresentSupport( phyQueue->phyDevice, phyQueue->familyIndex, window->display)) { diff --git a/tests/tests_main.c b/tests/tests_main.c index 183e4a73..2278f0d5 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,11 +57,11 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest("Graphics Test", graphicsTest); // registerTest("Device Test", deviceTest); - registerTest("Image Test", imageTest); + // registerTest("Image Test", imageTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest("Queue Test", queueTest); + registerTest("Queue Test", queueTest); #endif runTests(); From 8de97a5fd7831d9c339f4c80ff7e06af598f7470 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 3 Dec 2025 13:48:46 +0000 Subject: [PATCH 030/372] add image view api --- include/pal/pal_graphics.h | 47 ++++++- src/graphics/pal_graphics_linux.c | 204 +++++++++++++++++++++++++++++- tests/graphics_test.c | 6 +- tests/image_test.c | 30 +++++ tests/tests_main.c | 4 +- 5 files changed, 281 insertions(+), 10 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 3d3c1f8f..cc0cc4d9 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -183,6 +183,14 @@ typedef enum { } PalImageUsages; typedef enum { + PAL_IMAGE_VIEW_USAGE_UNDEFINED = 0, + PAL_IMAGE_VIEW_USAGE_COLOR = PAL_BIT(0), + PAL_IMAGE_VIEW_USAGE_DEPTH = PAL_BIT(1), + PAL_IMAGE_VIEW_USAGE_STENCIL = PAL_BIT(2) +} PalImageViewUsages; + +typedef enum { + PAL_TRANSFORM_IDENTITY, PAL_TRANSFORM_LANDSCAPE, PAL_TRANSFORM_PORTRAIT, PAL_TRANSFORM_LANDSCAPE_FLIPPED, @@ -215,7 +223,8 @@ typedef enum { PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(13), PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(15), - PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16) + PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16), + PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(17) } PalAdapterFeatures; typedef enum { @@ -266,7 +275,7 @@ typedef struct { } PalAdapterInfo; typedef struct { - bool debugLayerSupported; + bool debugLayer; Uint32 maxComputeQueues; Uint32 maxGraphicsQueues; Uint32 maxCopyQueues; @@ -353,6 +362,7 @@ typedef struct { typedef struct { PalFormat format; PalImageUsages usages; + PalImageViewUsages viewUsages; } PalFormatInfo; typedef struct { @@ -381,6 +391,15 @@ typedef struct { PalFormatInfo format; } PalImageCreateInfo; +typedef struct { + Uint32 startMipLevel; + Uint32 mipLevelCount; + Uint32 startArrayLayer; + Uint32 layerArrayCount; + PalImageViewType type; + PalImageUsages usages; +} PalImageViewCreateInfo; + typedef struct { void* display; void* window; @@ -441,6 +460,10 @@ typedef struct { PalAdapter* adapter, PalFormat format); + PalImageViewUsages PAL_CALL (*queryFormatViewUsages)( + PalAdapter* adapter, + PalFormat format); + PalResult PAL_CALL (*getImageMemoryRequirements)( PalDevice* device, PalImage* image, @@ -462,6 +485,14 @@ typedef struct { PalMemory* memory, Uint64 offset); + PalResult PAL_CALL (*createImageView)( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + + void PAL_CALL (*destroyImageView)(PalImageView* imageView); + // PalResult PAL_CALL (*querySwapchainCapabilities)( // PalGPUAdapter* adapter, // PalGPUWindow* window, @@ -558,6 +589,10 @@ PAL_API PalImageUsages PAL_CALL palQueryFormatUsages( PalAdapter* adapter, PalFormat format); +PAL_API PalImageViewUsages PAL_CALL palQueryFormatViewUsages( + PalAdapter* adapter, + PalFormat format); + PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( PalDevice* device, PalImage* image, @@ -579,6 +614,14 @@ PAL_API PalResult PAL_CALL palBindImageMemory( PalMemory* memory, Uint64 offset); +PAL_API PalResult PAL_CALL palCreateImageView( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + +PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); + // PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( // PalGPUAdapter* adapter, // PalGPUWindow* window, diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index f0cf5a70..1957b77f 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -137,15 +137,16 @@ typedef struct { } Queue; typedef struct { - bool ownsMemory; + bool belongsToSwapchain; Device* device; VkImage handle; PalImageInfo info; } Image; typedef struct { - VkFormat format; + VkImageViewType type; Device* device; + Image* image; VkImageView handle; } ImageView; @@ -1484,7 +1485,7 @@ static PalResult PAL_CALL _vkGetAdapterCapabilities( properties2.pNext = &vProps; s_Vk.getPhysicalDeviceProperties2(phyDevice, &properties2); - caps->debugLayerSupported = s_Vk.hasDebug; + caps->debugLayer = s_Vk.hasDebug; caps->maxColorAttachments = props.limits.maxColorAttachments; caps->maxImageWidth = props.limits.maxImageDimension2D; caps->maxImageHeight = props.limits.maxImageDimension2D; @@ -1792,6 +1793,9 @@ static PalResult PAL_CALL _vkGetAdapterCapabilities( caps->features |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; } + // this features are supported on vulkan + caps->features |= PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW; + palFree(s_Graphics.allocator, extensionProps); return PAL_RESULT_SUCCESS; } @@ -2292,6 +2296,7 @@ static PalResult PAL_CALL _vkCreateImage( return vkResultToPal(result); } + image->belongsToSwapchain = false; image->device = _device; image->info.depthOrArraySize = info->depthOrArraySize; image->info.type = info->type; @@ -2308,6 +2313,10 @@ static PalResult PAL_CALL _vkCreateImage( static void PAL_CALL _vkDestroyImage(PalImage* image) { Image* _image = (Image*)image; + if (_image->belongsToSwapchain) { + return; + } + s_Vk.destroyImage(_image->device->handle, _image->handle, &s_Vk.allocator); palFree(s_Graphics.allocator, _image); } @@ -2387,6 +2396,44 @@ static PalImageUsages PAL_CALL _vkQueryFormatUsages( return PAL_IMAGE_USAGE_UNDEFINED; } +PalImageViewUsages PAL_CALL _vkQueryFormatViewUsages( + PalAdapter* adapter, + PalFormat format) +{ + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + VkFormatProperties props = {0}; + + VkFormat fmt = palFormatToVk(format); + s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); + if (props.optimalTilingFeatures != 0) { + // format supported. check if we have any depth or stencil component + // Note: this is a hack + PalImageViewUsages usages = 0; + if (format == PAL_FORMAT_S8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } + + if (format == PAL_FORMAT_D16_UNORM || format == PAL_FORMAT_D32_SFLOAT) { + usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + } + + if (format == PAL_FORMAT_D32_SFLOAT_S8_UINT || + format == PAL_FORMAT_D16_UNORM_S8_UINT || + format == PAL_FORMAT_D24_UNORM_S8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } + + if (usages == 0) { + usages = PAL_IMAGE_VIEW_USAGE_COLOR; + } + + return usages; + } + + return PAL_IMAGE_VIEW_USAGE_UNDEFINED; +} + static PalResult PAL_CALL _vkGetImageMemoryRequirements( PalDevice* device, PalImage* image, @@ -2487,6 +2534,77 @@ PalResult PAL_CALL _vkBindImageMemory( s_Vk.bindImageMemory(_device->handle, _image->handle, mem, offset); } +PalResult PAL_CALL _vkCreateImageView( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView) +{ + VkResult result = VK_SUCCESS; + ImageView* imageView = nullptr; + Device* _device = (Device*)device; + Image* _image = (Image*)image; + + imageView = palAllocate(s_Graphics.allocator, sizeof(ImageView), 0); + if (!imageView) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkImageViewCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.format = _image->info.format.format; + createInfo.image = _image->handle; + + createInfo.subresourceRange.baseArrayLayer = info->startArrayLayer; + createInfo.subresourceRange.baseMipLevel = info->startMipLevel; + createInfo.subresourceRange.levelCount = info->mipLevelCount; + createInfo.subresourceRange.layerCount = info->layerArrayCount; + createInfo.viewType = palImageViewTypeToVk(info->type); + + VkImageAspectFlags aspectFlags = 0; + if (info->usages & PAL_IMAGE_VIEW_USAGE_DEPTH) { + aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; + } + + if (info->usages & PAL_IMAGE_VIEW_USAGE_STENCIL) { + aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; + } + + if (info->usages & PAL_IMAGE_VIEW_USAGE_COLOR) { + aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT; + } + + createInfo.subresourceRange .aspectMask = aspectFlags; + result = s_Vk.createImageView( + _device->handle, + &createInfo, + &s_Vk.allocator, + &imageView->handle); + + if (result != VK_SUCCESS) { + palFree(s_Graphics.allocator, imageView); + return vkResultToPal(result); + } + + imageView->device = _device; + imageView->image = _image; + imageView->type = createInfo.viewType; + + *outImageView = (PalImageView*)imageView; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL _vkDestroyImageView(PalImageView* imageView) +{ + ImageView* _imageView = (ImageView*)imageView; + s_Vk.destroyImageView( + _imageView->device->handle, + _imageView->handle, + &s_Vk.allocator); + + palFree(s_Graphics.allocator, _imageView); +} + // static PalResult PAL_CALL vkQuerySwapchainCapabilities( // PalGPUAdapter* adapter, // PalGPUWindow* window, @@ -3010,12 +3128,17 @@ static PalGPUBackend s_VkBackend = { .enumerateFormats = _vkEnumerateFormats, .isFormatSupported = _vkIsFormatSupported, .queryFormatUsages = _vkQueryFormatUsages, + .queryFormatViewUsages = _vkQueryFormatViewUsages, .getImageMemoryRequirements = _vkGetImageMemoryRequirements, // memory .allocate = _vkAllocateMemory, .free = _vkFreeMemory, - .bindImageMemory = _vkBindImageMemory + .bindImageMemory = _vkBindImageMemory, + + // image view + .createImageView = _vkCreateImageView, + .destroyImageView = _vkDestroyImageView // // swapchain // .querySwapchainCapabilities = vkQuerySwapchainCapabilities, @@ -3364,7 +3487,7 @@ PalResult PAL_CALL palCreateImage( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device || !outImage) { + if (!device ||!info || !outImage) { return PAL_RESULT_NULL_POINTER; } @@ -3485,6 +3608,22 @@ PalImageUsages PAL_CALL palQueryFormatUsages( return adapterData->backend->queryFormatUsages(adapter, format); } +PalImageViewUsages PAL_CALL palQueryFormatViewUsages( + PalAdapter* adapter, + PalFormat format) +{ + if (!s_Graphics.initialized || !adapter) { + return PAL_IMAGE_VIEW_USAGE_UNDEFINED; + } + + HandleData* adapterData = findHandleData(adapter); + if (!adapterData) { + return PAL_IMAGE_VIEW_USAGE_UNDEFINED; + } + + return adapterData->backend->queryFormatViewUsages(adapter, format); +} + PalResult PAL_CALL palGetImageMemoryRequirements( PalDevice* device, PalImage* image, @@ -3573,6 +3712,61 @@ PalResult PAL_CALL palBindImageMemory( offset); } +PalResult PAL_CALL palCreateImageView( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device ||!image || !info || !outImageView) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = findHandleData(device); + if (!data) { + return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + } + + PalImageView* imageView = nullptr; + PalResult ret; + ret = data->backend->createImageView( + device, + image, + info, + &imageView); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + // create a slot for the created image view + HandleData* imageViewData = getFreeHandleData(); + if (!imageViewData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + imageViewData->backend = data->backend; + imageViewData->handle = imageView; + + *outImageView = imageView; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyImageView(PalImageView* imageView) +{ + if (s_Graphics.initialized && imageView) { + HandleData* data = findHandleData(imageView); + if (data) { + data->backend->destroyImageView(imageView); + data->used = false; + } + } +} + // ================================================== // Swapchain // ================================================== diff --git a/tests/graphics_test.c b/tests/graphics_test.c index d7a7cfd1..3d4a553e 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -175,7 +175,7 @@ bool graphicsTest() } const char* boolToString; - if (caps.debugLayerSupported) { + if (caps.debugLayer) { boolToString = "True"; } else { boolToString = "False"; @@ -279,6 +279,10 @@ bool graphicsTest() if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { palLog(nullptr, " Multiview"); } + + if (caps.features & PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW) { + palLog(nullptr, " Cube array image view type"); + } palLog(nullptr, ""); } diff --git a/tests/image_test.c b/tests/image_test.c index 7ac9a3a6..aec55902 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -163,6 +163,36 @@ bool imageTest() return false; } + PalImageViewUsages viewUsage = PAL_IMAGE_VIEW_USAGE_COLOR; + if(!(viewUsage & palQueryFormatViewUsages(vulkanAdapter, format))) { + palLog(nullptr, + "The preffered format does not support color image view"); + return false; + } + + // create an image view from the image + PalImageView* imageView = nullptr; + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.startMipLevel = 0; // start from the first + imageViewCreateInfo.startArrayLayer = 0; // start from the first + imageViewCreateInfo.layerArrayCount = imageCreateInfo.depthOrArraySize; + imageViewCreateInfo.mipLevelCount = imageCreateInfo.mipLevels; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + + result = palCreateImageView( + device, + image, + &imageViewCreateInfo, + &imageView); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + + palDestroyImageView(imageView); + // bind the memory to the image result = palBindImageMemory( device, diff --git a/tests/tests_main.c b/tests/tests_main.c index 2278f0d5..183e4a73 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,11 +57,11 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest("Graphics Test", graphicsTest); // registerTest("Device Test", deviceTest); - // registerTest("Image Test", imageTest); + registerTest("Image Test", imageTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest("Queue Test", queueTest); + // registerTest("Queue Test", queueTest); #endif runTests(); From 4e87066316f13d6b4e4fadf7ef00694bcd0706b3 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 3 Dec 2025 16:57:03 +0000 Subject: [PATCH 031/372] rewrite swapchain api --- include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 149 +++-- src/graphics/pal_graphics_linux.c | 947 ++++++++++++++---------------- src/pal_core.c | 3 + tests/image_test.c | 4 +- tests/queue_test.c | 8 +- tests/swapchain_test.c | 340 +++++------ tests/tests.h | 1 + tests/tests.lua | 4 +- tests/tests_main.c | 3 +- 10 files changed, 673 insertions(+), 789 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index b8f82fb5..a5712ff0 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -258,7 +258,8 @@ typedef enum { PAL_RESULT_INVALID_GRAPHICS_WINDOW, PAL_RESULT_INVALID_SWAPCHAIN, PAL_RESULT_INVALID_GRAPHICS_IMAGE, - PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED + PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED, + PAL_RESULT_INVALID_GRAPHICS_OPERATION } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index cc0cc4d9..c8519e69 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -75,13 +75,17 @@ typedef enum { typedef enum { PAL_PRESENT_MODE_FIFO, PAL_PRESENT_MODE_IMMEDIATE, - PAL_PRESENT_MODE_MAILBOX + PAL_PRESENT_MODE_MAILBOX, + + PAL_PRESENT_MODE_MAX } PalPresentMode; typedef enum { PAL_COMPOSITE_ALPHA_OPAQUE, PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED, - PAL_COMPOSITE_ALPHA_POST_MULTIPLIED + PAL_COMPOSITE_ALPHA_POST_MULTIPLIED, + + PAL_COMPOSITE_ALPHA_MAX } PalCompositeAplha; typedef enum { @@ -189,14 +193,6 @@ typedef enum { PAL_IMAGE_VIEW_USAGE_STENCIL = PAL_BIT(2) } PalImageViewUsages; -typedef enum { - PAL_TRANSFORM_IDENTITY, - PAL_TRANSFORM_LANDSCAPE, - PAL_TRANSFORM_PORTRAIT, - PAL_TRANSFORM_LANDSCAPE_FLIPPED, - PAL_TRANSFORM_PORTRAIT_FLIPPED -} PalTransform; - typedef enum { PAL_SHADER_FORMAT_SPIRV = PAL_BIT(0), PAL_SHADER_FORMAT_DXIL = PAL_BIT(1), @@ -261,6 +257,15 @@ typedef enum { PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY, } PalImageViewType; +typedef enum { + PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB, + PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB, + PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB, + PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10, + + PAL_SWAPCHAIN_FORMAT_MAX // more pars will be added +} PalSwapchainFormat; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -296,37 +301,18 @@ typedef struct { PalAdapterFeatures features; } PalAdapterCapabilities; -// typedef struct { -// Uint32 minBufferCount; -// Uint32 maxBufferCount; -// Uint32 minWidth; -// Uint32 minHeight; -// Uint32 maxWidth; -// Uint32 maxHeight; -// Uint32 maxBufferArrayLayers; -// PalSwapchainFormats formats; -// PalSwapchainUsages usages; -// PalPresentModes presentModes; -// PalCompositeAplhas compositeAlphas; -// PalSwapchainSharingModes sharingModes; -// PalSwapchainTransforms transforms; -// } PalSwapchainCapabilities; - -// typedef struct { -// bool clipped; -// Uint32 width; -// Uint32 height; -// Uint32 bufferCount; -// Uint32 bufferArrayLayerCount; -// Uint32 concurrentQueueCount; -// PalPresentModes presentMode; -// PalSwapchainUsages usage; -// PalCompositeAplhas compositeAlpha; -// PalSwapchainFormats format; -// PalSwapchainSharingModes sharingMode; -// PalSwapchainTransforms transform; -// PalGPUCommandQueue** concurrentQueue; -// } PalSwapchainCreateInfo; +typedef struct { + bool presentModessAllowed[PAL_PRESENT_MODE_MAX]; + bool compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_MAX]; + bool swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_MAX]; + Uint32 minImageCount; + Uint32 maxImageCount; + Uint32 minImageWidth; + Uint32 minImageHeight; + Uint32 maxImageWidth; + Uint32 maxImageHeight; + Uint32 maxImageArrayLayers; +} PalSwapchainCapabilities; // typedef struct { // Uint32 maxMultiViews; @@ -369,9 +355,9 @@ typedef struct { Uint32 width; Uint32 height; Uint32 depthOrArraySize; - Uint32 mipLevels; + Uint32 mipLevelCount; Uint32 samples; - PalImageViewType type; + PalImageType type; PalFormatInfo format; } PalImageInfo; @@ -385,7 +371,7 @@ typedef struct { Uint32 width; Uint32 height; Uint32 depthOrArraySize; - Uint32 mipLevels; + Uint32 mipLevelCount; Uint32 samples; PalImageViewType type; PalFormatInfo format; @@ -400,6 +386,17 @@ typedef struct { PalImageUsages usages; } PalImageViewCreateInfo; +typedef struct { + bool clipped; + Uint32 width; + Uint32 height; + Uint32 imageCount; + Uint32 imageArrayLayerCount; + PalPresentMode presentMode; + PalCompositeAplha compositeAlpha; + PalSwapchainFormat format; +} PalSwapchainCreateInfo; + typedef struct { void* display; void* window; @@ -493,27 +490,25 @@ typedef struct { void PAL_CALL (*destroyImageView)(PalImageView* imageView); - // PalResult PAL_CALL (*querySwapchainCapabilities)( - // PalGPUAdapter* adapter, - // PalGPUWindow* window, - // PalSwapchainCapabilities* caps); - - // PalResult PAL_CALL (*createSwapchain)( - // PalGPUCommandQueue* queue, - // PalGPUWindow* window, - // const PalSwapchainCreateInfo* info, - // PalSwapchain** outSwapchain); + PalResult PAL_CALL (*querySwapchainCapabilities)( + PalAdapter* adapter, + PalGfxWindow* window, + PalSwapchainCapabilities* caps); - // void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); + PalResult PAL_CALL (*createSwapchain)( + PalDevice* device, + PalQueue* queue, + PalGfxWindow* window, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); - // Uint32 PAL_CALL (*getSwapchainBufferCount)(PalSwapchain* swapchain); + void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); - // PalResult PAL_CALL (*createRenderTargetView)( - // PalSwapchain* swapchain, - // Uint32 bufferIndex, - // PalRenderTargetView** outRtv); + Uint32 PAL_CALL (*getSwapchainImageCount)(PalSwapchain* swapchain); - // void PAL_CALL (*destroyRenderTargetView)(PalRenderTargetView* rtv); + PalImage* PAL_CALL (*getSwapchainImage)( + PalSwapchain* swapchain, + Int32 index); // PalResult PAL_CALL (*queryRenderPassCapabilities)( // PalSwapchain* swapchain, @@ -622,27 +617,25 @@ PAL_API PalResult PAL_CALL palCreateImageView( PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); -// PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( -// PalGPUAdapter* adapter, -// PalGPUWindow* window, -// PalSwapchainCapabilities* caps); - -// PAL_API PalResult PAL_CALL palCreateSwapchain( -// PalGPUCommandQueue* queue, -// PalGPUWindow* window, -// const PalSwapchainCreateInfo* info, -// PalSwapchain** outSwapchain); +PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( + PalAdapter* adapter, + PalGfxWindow* window, + PalSwapchainCapabilities* caps); -// PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); +PAL_API PalResult PAL_CALL palCreateSwapchain( + PalDevice* device, + PalQueue* queue, + PalGfxWindow* window, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); -// PAL_API Uint32 PAL_CALL palGetSwapchainBufferCount(PalSwapchain* swapchain); +PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); -// PAL_API PalResult PAL_CALL palCreateRenderTargetView( -// PalSwapchain* swapchain, -// Uint32 bufferIndex, -// PalRenderTargetView** outRtv); +PAL_API Uint32 PAL_CALL palGetSwapchainImageCount(PalSwapchain* swapchain); -// PAL_API void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv); +PAL_API PalImage* PAL_CALL palGetSwapchainImage( + PalSwapchain* swapchain, + Int32 index); // PAL_API PalResult PAL_CALL palQueryRenderPassCapabilities( // PalSwapchain* swapchain, diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index 1957b77f..e5ae307b 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -151,12 +151,11 @@ typedef struct { } ImageView; typedef struct { - Int32 bufferCount; - VkFormat format; + Uint32 imageCount; Device* device; VkSurfaceKHR surface; VkSwapchainKHR handle; - VkImage* buffers; + Image* images; } Swapchain; typedef struct { @@ -254,37 +253,37 @@ static bool vkOnWayland(struct wl_display* display) return true; } -// static bool vkCreateSurface(PalGPUWindow* window, VkSurfaceKHR* outSurface) -// { -// if (vkOnWayland(window->display)) { -// if (!s_Vk.createWaylandSurface) { -// return false; -// } +static bool vkCreateSurface(PalGfxWindow* window, VkSurfaceKHR* outSurface) +{ + if (vkOnWayland(window->display)) { + if (!s_Vk.createWaylandSurface) { + return false; + } -// VkSurfaceKHR surface = nullptr; -// VkWaylandSurfaceCreateInfoKHR createInfo = {0}; -// createInfo.display = window->display; -// createInfo.pNext = nullptr; -// createInfo.flags = 0; -// createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; -// createInfo.surface = window->window; - -// VkResult result = s_Vk.createWaylandSurface( -// s_Vk.instance, -// &createInfo, -// &s_Vk.allocator, -// &surface); - -// if (result != VK_SUCCESS) { -// return false; -// } -// *outSurface = surface; + VkSurfaceKHR surface = nullptr; + VkWaylandSurfaceCreateInfoKHR createInfo = {0}; + createInfo.display = window->display; + createInfo.pNext = nullptr; + createInfo.flags = 0; + createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + createInfo.surface = window->window; + + VkResult result = s_Vk.createWaylandSurface( + s_Vk.instance, + &createInfo, + &s_Vk.allocator, + &surface); + + if (result != VK_SUCCESS) { + return false; + } + *outSurface = surface; -// } else { -// // TODO: create surface for xlib -// } -// return true; -// } + } else { + // TODO: create surface for xlib + } + return true; +} static PalResult vkResultToPal(VkResult result) { @@ -2112,6 +2111,7 @@ static PalResult PAL_CALL _vkCreateDevice( } // load procs + device->createSwapchain = nullptr; device->acquireNextImage = (PFN_vkAcquireNextImageKHR)s_Vk.getDeviceProcAddr( device->handle, "vkAcquireNextImageKHR"); @@ -2270,7 +2270,7 @@ static PalResult PAL_CALL _vkCreateImage( createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; createInfo.extent.width = info->width; createInfo.extent.height = info->height; - createInfo.mipLevels = info->mipLevels; + createInfo.mipLevels = info->mipLevelCount; createInfo.format = palFormatToVk(info->format.format); createInfo.samples = samplesToVk(info->samples); @@ -2302,7 +2302,7 @@ static PalResult PAL_CALL _vkCreateImage( image->info.type = info->type; image->info.format = info->format; image->info.height = info->height; - image->info.mipLevels = info->mipLevels; + image->info.mipLevelCount = info->mipLevelCount; image->info.samples = info->samples; image->info.width = info->width; @@ -2327,6 +2327,7 @@ static PalResult PAL_CALL _vkGetImageInfo( { Image* _image = (Image*)image; *info = _image->info; + return PAL_RESULT_SUCCESS; } static PalResult PAL_CALL _vkEnumerateFormats( @@ -2396,7 +2397,7 @@ static PalImageUsages PAL_CALL _vkQueryFormatUsages( return PAL_IMAGE_USAGE_UNDEFINED; } -PalImageViewUsages PAL_CALL _vkQueryFormatViewUsages( +static PalImageViewUsages PAL_CALL _vkQueryFormatViewUsages( PalAdapter* adapter, PalFormat format) { @@ -2522,19 +2523,23 @@ void PAL_CALL _vkFreeMemory( s_Vk.freeMemory(_device->handle, mem, &s_Vk.allocator); } -PalResult PAL_CALL _vkBindImageMemory( +static PalResult PAL_CALL _vkBindImageMemory( PalDevice* device, PalImage* image, PalMemory* memory, Uint64 offset) { - Device* _device = (Device*)device; Image* _image = (Image*)image; + if (_image->belongsToSwapchain) { + return PAL_RESULT_INVALID_GRAPHICS_OPERATION; + } + + Device* _device = (Device*)device; VkDeviceMemory mem = (VkDeviceMemory)memory; s_Vk.bindImageMemory(_device->handle, _image->handle, mem, offset); } -PalResult PAL_CALL _vkCreateImageView( +static PalResult PAL_CALL _vkCreateImageView( PalDevice* device, PalImage* image, const PalImageViewCreateInfo* info, @@ -2594,7 +2599,7 @@ PalResult PAL_CALL _vkCreateImageView( return PAL_RESULT_SUCCESS; } -void PAL_CALL _vkDestroyImageView(PalImageView* imageView) +static void PAL_CALL _vkDestroyImageView(PalImageView* imageView) { ImageView* _imageView = (ImageView*)imageView; s_Vk.destroyImageView( @@ -2605,408 +2610,333 @@ void PAL_CALL _vkDestroyImageView(PalImageView* imageView) palFree(s_Graphics.allocator, _imageView); } -// static PalResult PAL_CALL vkQuerySwapchainCapabilities( -// PalGPUAdapter* adapter, -// PalGPUWindow* window, -// PalSwapchainCapabilities* caps) -// { -// Int32 formatCount = 0; -// Int32 modeCount = 0; -// VkSurfaceKHR surface = nullptr; -// VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; -// VkPresentModeKHR* modes = nullptr; -// VkSurfaceFormatKHR* formats = nullptr; - -// bool ret = vkCreateSurface(window, &surface); -// if (!ret) { -// return PAL_RESULT_INVALID_GPU_WINDOW; -// } +static PalResult PAL_CALL _vkQuerySwapchainCapabilities( + PalAdapter* adapter, + PalGfxWindow* window, + PalSwapchainCapabilities* caps) +{ + Int32 formatCount = 0; + Int32 modeCount = 0; + VkSurfaceKHR surface = nullptr; + VkSurfaceFormatKHR* formats = nullptr; + VkPresentModeKHR* modes = nullptr; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; -// s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, nullptr); -// s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, nullptr); + bool ret = vkCreateSurface(window, &surface); + if (!ret) { + return PAL_RESULT_INVALID_GRAPHICS_WINDOW; + } -// modes = palAllocate( -// s_Graphics.allocator, -// sizeof(VkPresentModeKHR) * modeCount, -// 0); + s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, nullptr); + s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, nullptr); -// formats = palAllocate( -// s_Graphics.allocator, -// sizeof(VkSurfaceFormatKHR) * formatCount, -// 0); + modes = palAllocate( + s_Graphics.allocator, + sizeof(VkPresentModeKHR) * modeCount, + 0); -// if (!modes || !formats) { -// s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); -// return PAL_RESULT_OUT_OF_MEMORY; -// } + formats = palAllocate( + s_Graphics.allocator, + sizeof(VkSurfaceFormatKHR) * formatCount, + 0); -// s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, modes); -// s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, formats); + if (!modes || !formats) { + s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); + return PAL_RESULT_OUT_OF_MEMORY; + } -// VkSurfaceCapabilitiesKHR surfaceCaps; -// s_Vk.getSurfaceCapabilities(phyDevice, surface, &surfaceCaps); -// caps->minWidth = surfaceCaps.minImageExtent.width; -// caps->minHeight = surfaceCaps.minImageExtent.height; -// caps->maxWidth = surfaceCaps.maxImageExtent.width; -// caps->maxHeight = surfaceCaps.maxImageExtent.height; + s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, modes); + s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, formats); -// caps->maxBufferCount = surfaceCaps.maxImageCount; -// caps->minBufferCount = surfaceCaps.minImageCount; -// caps->maxBufferArrayLayers = surfaceCaps.maxImageArrayLayers; + VkSurfaceCapabilitiesKHR surfaceCaps; + s_Vk.getSurfaceCapabilities(phyDevice, surface, &surfaceCaps); + caps->minImageWidth = surfaceCaps.minImageExtent.width; + caps->minImageHeight = surfaceCaps.minImageExtent.height; + caps->maxImageWidth = surfaceCaps.maxImageExtent.width; + caps->maxImageHeight = surfaceCaps.maxImageExtent.height; -// if (caps->maxBufferCount == 0) { -// caps->maxBufferCount = PAL_INFINITE; -// } + caps->maxImageCount = surfaceCaps.maxImageCount; + caps->minImageCount = surfaceCaps.minImageCount; + caps->maxImageArrayLayers = surfaceCaps.maxImageArrayLayers; -// // get supported transforms -// VkSurfaceTransformFlagsKHR trans = surfaceCaps.supportedTransforms; -// if (trans & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { -// caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE; -// } + if (caps->maxImageCount == 0) { + caps->maxImageCount = PAL_INFINITE; + } -// if (trans & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { -// caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_PORTRAIT; -// } + // get supported composite alphas + VkCompositeAlphaFlagsKHR alpha = surfaceCaps.supportedCompositeAlpha; + caps->compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_OPAQUE] = true; + caps->compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = false; + caps->compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = false; + bool t = true; -// if (trans & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) { -// caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED; -// } + if (alpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { + caps->compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = t; + } -// if (trans & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { -// caps->transforms |= PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED; -// } + if (alpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { + caps->compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = t; + } -// // get supported composite alphas -// VkCompositeAlphaFlagsKHR alpha = surfaceCaps.supportedCompositeAlpha; -// caps->compositeAlphas = PAL_COMPOSITE_ALPHA_OPAQUE; -// if (alpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { -// caps->compositeAlphas |= PAL_COMPOSITE_ALPHA_POST_MULTIPLIED; -// } + // present modes + caps->presentModessAllowed[PAL_PRESENT_MODE_FIFO] = true; + caps->presentModessAllowed[PAL_PRESENT_MODE_MAILBOX] = false; + caps->presentModessAllowed[PAL_PRESENT_MODE_IMMEDIATE] = false; -// if (alpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { -// caps->compositeAlphas |= PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED; -// } + for (int i = 0; i < modeCount; i++) { + if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { + caps->presentModessAllowed[PAL_PRESENT_MODE_IMMEDIATE] = true; + } -// // get supported composite alphas -// VkImageUsageFlags usage = surfaceCaps.supportedUsageFlags; -// caps->usages = 0; -// if (usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { -// caps->usages |= PAL_SWAPCHAIN_USAGE_COLOR_ATTACHEMENT; -// } + if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { + caps->presentModessAllowed[PAL_PRESENT_MODE_MAILBOX] = true; + } + } -// if (usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { -// caps->usages |= PAL_SWAPCHAIN_USAGE_TRANSFER_DST; -// } + // clang-format off -// if (usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { -// caps->usages |= PAL_SWAPCHAIN_USAGE_TRANSFER_SRC; -// } + // get format and colorspace + caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = false; + caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB] = false; + caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB] = false; + caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB] = false; + + for (int i = 0; i < formatCount; i++) { + VkSurfaceFormatKHR* fmt = &formats[i]; + if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB] = true; + } -// if (usage & VK_IMAGE_USAGE_SAMPLED_BIT) { -// caps->usages |= PAL_SWAPCHAIN_USAGE_SAMPLED; -// } + } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB] = true; + } -// // sharing modes -// caps->sharingModes = PAL_SWAPCHAIN_SHARING_MODE_EXCLUSIVE; -// caps->sharingModes |= PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT; + } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB] = true; + } -// // present modes -// caps->presentModes = PAL_PRESENT_MODE_FIFO; -// for (int i = 0; i < modeCount; i++) { -// if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { -// caps->presentModes |= PAL_PRESENT_MODE_IMMEDIATE; -// } + } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { + caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = true; + } + } + } -// if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { -// caps->presentModes |= PAL_PRESENT_MODE_MAILBOX; -// } -// } + // clang-format on -// // get format and colorspace -// for (int i = 0; i < formatCount; i++) { -// VkSurfaceFormatKHR* fmt = &formats[i]; -// if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { -// // find its supported colorspace -// if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { -// caps->formats |= PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; -// } + palFree(s_Graphics.allocator, formats); + palFree(s_Graphics.allocator, modes); + s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); -// } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { -// // find its supported colorspace -// if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { -// caps->formats |= PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB; -// } + return PAL_RESULT_SUCCESS; +} -// } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { -// // find its supported colorspace -// if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { -// caps->formats |= PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; -// } +static PalResult PAL_CALL _vkCreateSwapchain( + PalDevice* device, + PalQueue* queue, + PalGfxWindow* window, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain) +{ + PalFormat imageFormat = 0; + Swapchain* swapchain = nullptr; + VkImage* images = nullptr; -// } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { -// // find its supported colorspace -// if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { -// caps->formats |= PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10; -// } -// } -// } + Queue* _queue = (Queue*)queue; + Device* _device = (Device*)device; + PhysicalQueue* phyQueue = _queue->phyQueue; -// palFree(s_Graphics.allocator, formats); -// palFree(s_Graphics.allocator, modes); -// s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); + // check if we enabled swapchain feature + if (!_device->createSwapchain) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } -// return PAL_RESULT_SUCCESS; -// } + // check if the queue is a graphics queue before we check its family + // index for presentation support. + if (_queue->usage != VK_QUEUE_GRAPHICS_BIT) { + PAL_RESULT_INVALID_QUEUE; + } -// static PalResult PAL_CALL vkCreateSwapchain( -// PalGPUCommandQueue* queue, -// PalGPUWindow* window, -// const PalSwapchainCreateInfo* info, -// PalSwapchain** outSwapchain) -// { -// Swapchain* swapchain = nullptr; -// CommandQueue* commandQueue = (CommandQueue*)queue; -// PhysicalQueue* phyQueue = commandQueue->phyQueue; + swapchain = palAllocate(s_Graphics.allocator, sizeof(Swapchain), 0); + if (!swapchain) { + return PAL_RESULT_OUT_OF_MEMORY; + } -// // check if we enabled swapchain feature -// if (!commandQueue->device->swapchain) { -// return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; -// } + bool ret = vkCreateSurface(window, &swapchain->surface); + if (!ret) { + return PAL_RESULT_INVALID_GRAPHICS_WINDOW; + } -// swapchain = palAllocate(s_Graphics.allocator, sizeof(Swapchain), 0); -// if (!swapchain) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } + VkSwapchainCreateInfoKHR createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = swapchain->surface; + createInfo.imageArrayLayers = info->imageArrayLayerCount; + createInfo.imageExtent.width = info->width; + createInfo.imageExtent.height = info->height; + createInfo.minImageCount = info->imageCount; + createInfo.clipped = (VkBool32)info->clipped; + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; -// swapchain->device = commandQueue->device; -// bool ret = vkCreateSurface(window, &swapchain->surface); -// if (!ret) { -// return PAL_RESULT_INVALID_GPU_WINDOW; -// } + // present modes + createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; + if (info->presentMode == PAL_PRESENT_MODE_IMMEDIATE) { + createInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; -// VkSwapchainCreateInfoKHR createInfo = {0}; -// createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; -// createInfo.surface = swapchain->surface; -// createInfo.imageArrayLayers = info->bufferArrayLayerCount; -// createInfo.imageExtent.width = info->width; -// createInfo.imageExtent.height = info->height; -// createInfo.minImageCount = info->bufferCount; -// if (info->clipped) { -// createInfo.clipped = VK_TRUE; -// } + } else if (info->presentMode == PAL_PRESENT_MODE_MAILBOX) { + createInfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR; + } -// // sharing mode -// createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; -// if (info->sharingMode == PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT) { -// createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; -// // set up concurrrent queue families -// Uint32 count = 0; -// Uint32 familyQueus[32]; // should be more than enough -// familyQueus[count++] = phyQueue->familyIndex; - -// for (int i = 0; i < info->concurrentQueueCount; i++) { -// CommandQueue* tmp = (CommandQueue*)info->concurrentQueue[i]; -// if (tmp->phyQueue != phyQueue) { -// // different queue families. Add index -// familyQueus[count++] = tmp->phyQueue->familyIndex; -// } -// } + // composite alpha + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_POST_MULTIPLIED) { + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; -// createInfo.queueFamilyIndexCount = count; -// createInfo.pQueueFamilyIndices = familyQueus; -// } + } else if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED) { + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; + } -// // present modes -// createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; -// if (info->presentMode == PAL_PRESENT_MODE_IMMEDIATE) { -// createInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + // format and colorspace + createInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; + createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + imageFormat = PAL_FORMAT_B8G8R8A8_UNORM; -// } else if (info->presentMode == PAL_PRESENT_MODE_MAILBOX) { -// createInfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR; -// } + if (info->format == PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB) { + createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; + createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + imageFormat = PAL_FORMAT_B8G8R8A8_SRGB; -// // usage -// createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; -// if (info->usage == PAL_SWAPCHAIN_USAGE_TRANSFER_SRC) { -// createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB) { + createInfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; + createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + imageFormat = PAL_FORMAT_R8G8B8A8_UNORM; -// } else if (info->usage == PAL_SWAPCHAIN_USAGE_TRANSFER_DST) { -// createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10) { + createInfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; + createInfo.imageColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; + imageFormat = PAL_FORMAT_R16G16B16A16_SFLOAT; + } -// } else if (info->usage == PAL_SWAPCHAIN_USAGE_SAMPLED) { -// createInfo.imageUsage = VK_IMAGE_USAGE_SAMPLED_BIT; -// } + // create swapchain + VkResult result = _device->createSwapchain( + _device->handle, + &createInfo, + &s_Vk.allocator, + &swapchain->handle); -// // composite alpha -// createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; -// if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_POST_MULTIPLIED) { -// createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; + if (result != VK_SUCCESS) { + s_Vk.destroySurface( + s_Vk.instance, + swapchain->surface, + &s_Vk.allocator); -// } else if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED) { -// createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; -// } + palFree(s_Graphics.allocator, swapchain); + return vkResultToPal(result); + } -// // transform -// createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; -// if (info->transform == PAL_SWAPCHAIN_TRANSFORM_PORTRAIT) { -// createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; + // get and cache all images + Int32 count = 0; + result = _device->getSwapchainImages( + _device->handle, + swapchain->handle, + &count, + nullptr); -// } else if (info->transform == PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED) { -// createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; + swapchain->images = palAllocate( + s_Graphics.allocator, + sizeof(Image) * count, + 0); -// } else if (info->transform == PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED) { -// createInfo.preTransform = VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; -// } + images = palAllocate( + s_Graphics.allocator, + sizeof(VkImage) * count, + 0); -// // format and colorspace -// createInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; -// createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; -// swapchain->format = VK_FORMAT_B8G8R8A8_UNORM; - -// if (info->format == PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB) { -// createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; -// createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; -// swapchain->format = VK_FORMAT_B8G8R8A8_SRGB; - -// } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB) { -// createInfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; -// createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; -// swapchain->format = VK_FORMAT_R8G8B8A8_UNORM; - -// } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10) { -// createInfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; -// createInfo.imageColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; -// swapchain->format = VK_FORMAT_R16G16B16A16_SFLOAT; -// } + if (!swapchain->images || !images) { + _device->destroySwapchain( + _device->handle, + swapchain->handle, + &s_Vk.allocator + ); -// // create swapchain -// VkResult result = swapchain->device->createSwapchain( -// swapchain->device->handle, -// &createInfo, -// &s_Vk.allocator, -// &swapchain->handle); - -// if (result != VK_SUCCESS) { -// s_Vk.destroySurface( -// s_Vk.instance, -// swapchain->surface, -// &s_Vk.allocator); - -// palFree(s_Graphics.allocator, swapchain); -// return vkResultToPal(result); -// } + s_Vk.destroySurface( + s_Vk.instance, + swapchain->surface, + &s_Vk.allocator); -// // get all images of the created swapchain -// Int32 count = 0; -// result = swapchain->device->getSwapchainImages( -// swapchain->device->handle, -// swapchain->handle, -// &count, -// nullptr); - -// swapchain->buffers = palAllocate( -// s_Graphics.allocator, -// sizeof(VkImage) * count, -// 0); - -// if (!swapchain->buffers) { -// swapchain->device->destroySwapchain( -// swapchain->device->handle, -// swapchain->handle, -// &s_Vk.allocator -// ); - -// s_Vk.destroySurface( -// s_Vk.instance, -// swapchain->surface, -// &s_Vk.allocator); - -// palFree(s_Graphics.allocator, swapchain); -// return PAL_RESULT_OUT_OF_MEMORY; -// } - -// swapchain->bufferCount = count; -// swapchain->device->getSwapchainImages( -// swapchain->device->handle, -// swapchain->handle, -// &count, -// swapchain->buffers); + palFree(s_Graphics.allocator, swapchain); + return PAL_RESULT_OUT_OF_MEMORY; + } -// *outSwapchain = (PalSwapchain*)swapchain; -// return PAL_RESULT_SUCCESS; -// } - -// static void PAL_CALL vkDestroySwapchain(PalSwapchain* swapchain) -// { -// Swapchain* _swapchain = (Swapchain*)swapchain; -// _swapchain->device->destroySwapchain( -// _swapchain->device->handle, -// _swapchain->handle, -// &s_Vk.allocator -// ); - -// s_Vk.destroySurface(s_Vk.instance, _swapchain->surface, &s_Vk.allocator); -// palFree(s_Graphics.allocator, _swapchain->buffers); -// palFree(s_Graphics.allocator, _swapchain); -// } - -// static Uint32 PAL_CALL vkGetSwapchainBufferCount(PalSwapchain* swapchain) -// { -// Swapchain* _swapchain = (Swapchain*)swapchain; -// return _swapchain->bufferCount; -// } + _device->getSwapchainImages( + _device->handle, + swapchain->handle, + &count, + images); -// static PalResult PAL_CALL vkCreateRenderTargetView( -// PalSwapchain* swapchain, -// Uint32 bufferIndex, -// PalRenderTargetView** outRtv) -// { -// VkResult result = VK_SUCCESS; -// RenderTargetView* rtv = nullptr; -// Swapchain* _swapchain = (Swapchain*)swapchain; -// if (bufferIndex < 0 && bufferIndex >= _swapchain->bufferCount) { -// return PAL_RESULT_INVALID_SWAPCHAIN_BUFFER_INDEX; -// } + // fill all images with the creatio info + for (int i = 0; i < count; i++) { + Image* image = &swapchain->images[i]; + image->belongsToSwapchain = true; + image->device = _device; + image->handle = images[i]; + + image->info.depthOrArraySize = createInfo.imageArrayLayers; + image->info.format.format = imageFormat; + image->info.format.viewUsages = PAL_IMAGE_VIEW_USAGE_COLOR; + image->info.height = createInfo.imageExtent.height; + image->info.width = createInfo.imageExtent.width; + image->info.mipLevelCount = 1; + image->info.samples = 1; // swapchain images are not multisampled + image->info.type = PAL_IMAGE_TYPE_2D; + } + + swapchain->device = _device; + swapchain->imageCount = count; -// VkImage buffer = _swapchain->buffers[bufferIndex]; -// rtv = palAllocate(s_Graphics.allocator, sizeof(RenderTargetView), 0); -// if (!rtv) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } + *outSwapchain = (PalSwapchain*)swapchain; + return PAL_RESULT_SUCCESS; +} -// VkImageViewCreateInfo createInfo = {0}; -// createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; -// createInfo.format = _swapchain->format; -// createInfo.image = buffer; -// createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; -// createInfo.subresourceRange.levelCount = 1; -// createInfo.subresourceRange.layerCount = 1; -// createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - -// result = s_Vk.createImageView( -// _swapchain->device->handle, -// &createInfo, -// &s_Vk.allocator, -// &rtv->handle); - -// if (result != VK_SUCCESS) { -// palFree(s_Graphics.allocator, rtv); -// return vkResultToPal(result); -// } +static void PAL_CALL vkDestroySwapchain(PalSwapchain* swapchain) +{ + Swapchain* _swapchain = (Swapchain*)swapchain; + _swapchain->device->destroySwapchain( + _swapchain->device->handle, + _swapchain->handle, + &s_Vk.allocator + ); + + s_Vk.destroySurface(s_Vk.instance, _swapchain->surface, &s_Vk.allocator); + palFree(s_Graphics.allocator, _swapchain->images); + palFree(s_Graphics.allocator, _swapchain); +} -// rtv->format = _swapchain->format; -// rtv->device = _swapchain->device; +static Uint32 PAL_CALL _vkGetSwapchainImageCount(PalSwapchain* swapchain) +{ + Swapchain* _swapchain = (Swapchain*)swapchain; + return _swapchain->imageCount; +} -// *outRtv = (PalRenderTargetView*)rtv; -// return PAL_RESULT_SUCCESS; -// } +static PalImage* PAL_CALL _vkGetSwapchainImage( + PalSwapchain* swapchain, + Int32 index) +{ + Swapchain* _swapchain = (Swapchain*)swapchain; + if (index > _swapchain->imageCount) { + return nullptr; + } -// static void PAL_CALL vkDestroyRenderTargetView(PalRenderTargetView* rtv) -// { -// RenderTargetView* _rtv = (RenderTargetView*)rtv; -// s_Vk.destroyImageView(_rtv->device->handle, _rtv->handle, &s_Vk.allocator); -// palFree(s_Graphics.allocator, _rtv); -// } + return (PalImage*)&_swapchain->images[index]; +} // static PalResult PAL_CALL vkQueryRenderPassCapabilities( // PalSwapchain* swapchain, @@ -3138,13 +3068,14 @@ static PalGPUBackend s_VkBackend = { // image view .createImageView = _vkCreateImageView, - .destroyImageView = _vkDestroyImageView + .destroyImageView = _vkDestroyImageView, - // // swapchain - // .querySwapchainCapabilities = vkQuerySwapchainCapabilities, - // .createSwapchain = vkCreateSwapchain, - // .destroySwapchain = vkDestroySwapchain, - // .getSwapchainBufferCount = vkGetSwapchainBufferCount, + // swapchain + .querySwapchainCapabilities = _vkQuerySwapchainCapabilities, + .createSwapchain = _vkCreateSwapchain, + .destroySwapchain = vkDestroySwapchain, + .getSwapchainImageCount = _vkGetSwapchainImageCount, + .getSwapchainImage = _vkGetSwapchainImage, // // render target view // .createRenderTargetView = vkCreateRenderTargetView, @@ -3771,149 +3702,131 @@ void PAL_CALL palDestroyImageView(PalImageView* imageView) // Swapchain // ================================================== -// PalResult PAL_CALL palQuerySwapchainCapabilities( -// PalGPUAdapter* adapter, -// PalGPUWindow* window, -// PalSwapchainCapabilities* caps) -// { -// if (!s_Graphics.initialized) { -// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; -// } - -// if (!adapter || !window || !caps) { -// return PAL_RESULT_NULL_POINTER; -// } - -// HandleData* adapterData = findHandleData(adapter); -// if (!adapterData) { -// return PAL_RESULT_INVALID_ADAPTER; -// } - -// return adapterData->backend->querySwapchainCapabilities( -// adapter, -// window, -// caps); -// } - -// PalResult PAL_CALL palCreateSwapchain( -// PalGPUCommandQueue* queue, -// PalGPUWindow* window, -// const PalSwapchainCreateInfo* info, -// PalSwapchain** outSwapchain) -// { -// if (!s_Graphics.initialized) { -// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; -// } +PalResult PAL_CALL palQuerySwapchainCapabilities( + PalAdapter* adapter, + PalGfxWindow* window, + PalSwapchainCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } -// if (!queue || !window || !info || !outSwapchain) { -// return PAL_RESULT_NULL_POINTER; -// } + if (!adapter || !window || !caps) { + return PAL_RESULT_NULL_POINTER; + } -// HandleData* queueData = findHandleData(queue); -// if (!queueData) { -// return PAL_RESULT_INVALID_GPU_COMMAND_QUEUE; -// } + HandleData* adapterData = findHandleData(adapter); + if (!adapterData) { + return PAL_RESULT_INVALID_ADAPTER; + } -// PalResult ret; -// PalSwapchain* swapchain = nullptr; -// ret = queueData->backend->createSwapchain(queue, window, info, &swapchain); -// if (ret != PAL_RESULT_SUCCESS) { -// return ret; -// } + return adapterData->backend->querySwapchainCapabilities( + adapter, + window, + caps); +} -// // create a slot for the created swapchain -// HandleData* swapchainData = getFreeHandleData(); -// if (!swapchainData) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } -// swapchainData->backend = queueData->backend; -// swapchainData->handle = swapchain; +PalResult PAL_CALL palCreateSwapchain( + PalDevice* device, + PalQueue* queue, + PalGfxWindow* window, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } -// *outSwapchain = swapchain; -// return PAL_RESULT_SUCCESS; -// } + if (!device || !queue || !window || !info || !outSwapchain) { + return PAL_RESULT_NULL_POINTER; + } -// void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) -// { -// if (s_Graphics.initialized && swapchain) { -// HandleData* data = findHandleData(swapchain); -// if (data) { -// data->backend->destroySwapchain(swapchain); -// data->used = false; -// } -// } -// } + HandleData* deviceData = findHandleData(device); + if (!deviceData) { + return PAL_RESULT_INVALID_QUEUE; + } -// Uint32 PAL_CALL palGetSwapchainBufferCount(PalSwapchain* swapchain) -// { -// if (!s_Graphics.initialized || !swapchain) { -// return 0; -// } + PalResult ret; + PalSwapchain* swapchain = nullptr; + ret = deviceData->backend->createSwapchain( + device, + queue, + window, + info, + &swapchain); -// HandleData* swapchainData = findHandleData(swapchain); -// if (!swapchainData) { -// return 0; -// } + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } -// return swapchainData->backend->getSwapchainBufferCount(swapchain); -// } + // create a slot for the created swapchain + HandleData* swapchainData = getFreeHandleData(); + if (!swapchainData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + swapchainData->backend = deviceData->backend; + swapchainData->handle = swapchain; -// // ================================================== -// // Render Target View -// // ================================================== + *outSwapchain = swapchain; + return PAL_RESULT_SUCCESS; +} -// PalResult PAL_CALL palCreateRenderTargetView( -// PalSwapchain* swapchain, -// Uint32 bufferIndex, -// PalRenderTargetView** outRtv) -// { -// if (!s_Graphics.initialized) { -// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; -// } +void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) +{ + if (s_Graphics.initialized && swapchain) { + HandleData* data = findHandleData(swapchain); + if (data) { + data->backend->destroySwapchain(swapchain); + data->used = false; + } + } +} -// if (!swapchain || !outRtv) { -// return PAL_RESULT_NULL_POINTER; -// } +Uint32 PAL_CALL palGetSwapchainImageCount(PalSwapchain* swapchain) +{ + if (!s_Graphics.initialized || !swapchain) { + return 0; + } -// HandleData* swapchainData = findHandleData(swapchain); -// if (!swapchainData) { -// return PAL_RESULT_INVALID_SWAPCHAIN; -// } + HandleData* swapchainData = findHandleData(swapchain); + if (!swapchainData) { + return 0; + } -// PalResult ret; -// PalRenderTargetView* rtv = nullptr; -// ret = swapchainData->backend->createRenderTargetView( -// swapchain, -// bufferIndex, -// &rtv); + return swapchainData->backend->getSwapchainImageCount(swapchain); +} -// if (ret != PAL_RESULT_SUCCESS) { -// return ret; -// } +PalImage* PAL_CALL palGetSwapchainImage( + PalSwapchain* swapchain, + Int32 index) +{ + if (!s_Graphics.initialized || !swapchain || index < 0) { + return nullptr; + } -// // create a slot for the created render target view -// HandleData* rtvData = getFreeHandleData(); -// if (!rtvData) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } + HandleData* swapchainData = findHandleData(swapchain); + if (!swapchainData) { + return nullptr; + } -// rtvData->backend = swapchainData->backend; -// rtvData->handle = rtv; + PalImage* image = swapchainData->backend->getSwapchainImage( + swapchain, + index); -// *outRtv = rtv; -// return PAL_RESULT_SUCCESS; -// } + // check if the user has already requested for the image + HandleData* imageData = findHandleData(image); + if (!imageData) { + // create a new slot + imageData = getFreeHandleData(); + if (!imageData) { + return nullptr; + } + } -// void PAL_CALL palDestroyRenderTargetView(PalRenderTargetView* rtv) -// { -// if (s_Graphics.initialized && rtv) { -// HandleData* data = findHandleData(rtv); -// if (data) { -// data->backend->destroyRenderTargetView(rtv); -// data->used = false; -// } -// } -// } + imageData->backend = swapchainData->backend; + imageData->handle = image; + return image; +} // // ================================================== // // Render Pass diff --git a/src/pal_core.c b/src/pal_core.c index 880bcfd9..81563705 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -419,6 +419,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED: return "memory type not supported"; + + case PAL_RESULT_INVALID_GRAPHICS_OPERATION: + return "Invalid graphics operation"; } return "Unknown"; } diff --git a/tests/image_test.c b/tests/image_test.c index aec55902..a549471d 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -120,7 +120,7 @@ bool imageTest() imageCreateInfo.format.format = format; imageCreateInfo.format.usages = usage; imageCreateInfo.height = 240; - imageCreateInfo.mipLevels = 1; + imageCreateInfo.mipLevelCount = 1; imageCreateInfo.samples = 1; // very simple imageCreateInfo.width = 320; @@ -176,7 +176,7 @@ bool imageTest() imageViewCreateInfo.startMipLevel = 0; // start from the first imageViewCreateInfo.startArrayLayer = 0; // start from the first imageViewCreateInfo.layerArrayCount = imageCreateInfo.depthOrArraySize; - imageViewCreateInfo.mipLevelCount = imageCreateInfo.mipLevels; + imageViewCreateInfo.mipLevelCount = imageCreateInfo.mipLevelCount; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; result = palCreateImageView( diff --git a/tests/queue_test.c b/tests/queue_test.c index 3bdab786..47f7ba45 100644 --- a/tests/queue_test.c +++ b/tests/queue_test.c @@ -146,12 +146,12 @@ bool queueTest() return false; } - PalGfxWindow gWindow = {0}; + PalGfxWindow gfxWindow = {0}; PalWindowHandleInfo winInfo = palGetWindowHandleInfo(window); - gWindow.display = winInfo.nativeDisplay; - gWindow.window = winInfo.nativeWindow; + gfxWindow.display = winInfo.nativeDisplay; + gfxWindow.window = winInfo.nativeWindow; - bool canPresent = palCanQueuePresent(gfxQueue, &gWindow); + bool canPresent = palCanQueuePresent(gfxQueue, &gfxWindow); const char* boolString = "True"; if (!canPresent) { boolString = "False"; diff --git a/tests/swapchain_test.c b/tests/swapchain_test.c index 9490da37..40f073a0 100644 --- a/tests/swapchain_test.c +++ b/tests/swapchain_test.c @@ -1,5 +1,4 @@ - #include "pal/pal_graphics.h" #include "pal/pal_video.h" #include "tests.h" @@ -12,81 +11,52 @@ bool swapchainTest() palLog(nullptr, "==========================================="); palLog(nullptr, ""); - // we need a window. We use PAL video system to create the window - PalResult result = palInitVideo(nullptr, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; - } - - PalWindow* window = nullptr; - PalWindowCreateInfo windowCreateInfo = {0}; - windowCreateInfo.height = 480; - windowCreateInfo.width = 640; - windowCreateInfo.show = true; - - // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { - // if we dont support, we need to create a borderless window - // and create the decorations ourselves - windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; - } - - result = palCreateWindow(&windowCreateInfo, &window); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; - } - // initialize the graphics system - result = palInitGraphics(false, nullptr); + PalResult result = palInitGraphics(false, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); return false; } - // enumerate all available GPUs from internal and custom backends + // enumerate all available adapters Int32 count = 0; - result = palEnumerateGPUAdapters(&count, nullptr); + result = palEnumerateAdapters(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + palLog(nullptr, "Failed to get query adapters: %s", error); return false; } if (count == 0) { - palLog(nullptr, "No Adapters found"); + palLog(nullptr, "No adapters found"); return false; } - palLog(nullptr, "Adapter (GPUs) Count: %d", count); + palLog(nullptr, "Adapter count: %d", count); // allocate an array of adapters or use a fixed array - // Example: PalGPUAdapter* adapters[12]; - PalGPUAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalGPUAdapter*) * count, 0); + // Example: PalAdapter* adapters[12]; + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); return false; } - result = palEnumerateGPUAdapters(&count, adapters); + result = palEnumerateAdapters(&count, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query Adapters (GPUs): %s", error); + palLog(nullptr, "Failed to get query adapters: %s", error); return false; } // filter the adapters for Vulkan - PalGPUAdapter* vulkanAdapter = nullptr; - PalGPUAdapterInfo info = {0}; + PalAdapter* vulkanAdapter = nullptr; + PalAdapterInfo info = {0}; for (Int32 i = 0; i < count; i++) { - PalGPUAdapter* adapter = adapters[i]; - result = palGetGPUAdapterInfo(adapter, &info); + PalAdapter* adapter = adapters[i]; + result = palGetAdapterInfo(adapter, &info); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); @@ -95,7 +65,7 @@ bool swapchainTest() } // check if its Vulkan - if (info.apiType == PAL_GPU_API_TYPE_VULKAN) { + if (info.apiType == PAL_ADAPTER_API_TYPE_VULKAN) { vulkanAdapter = adapter; break; } @@ -107,61 +77,82 @@ bool swapchainTest() return false; } - // get capabilities about the vulkan adapter and check if we support - // graphics command queues - PalGPUAdapterCapabilities caps = {0}; - result = palGetGPUAdapterCapabilities(vulkanAdapter, &caps); + // get capabilities about the adapter + PalAdapterCapabilities caps = {0}; + result = palGetAdapterCapabilities(vulkanAdapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); return false; } - // check if we support a graphics command queue - const char* msg = "This Adapter (GPU) does not have any graphics queues"; - if (!(caps.features & PAL_GPU_FEATURE_SWAPCHAIN)) { - palLog(nullptr, msg); + if (caps.maxGraphicsQueues == 0) { + palLog(nullptr, "adapter does not support graphics queues"); return false; } - if (!caps.maxGraphicsQueues) { - palLog(nullptr, msg); + // create a device with the vulkan adapter + PalDevice* device = nullptr; + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + + // enable multi viewport if supported + if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { + features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; + } + + result = palCreateDevice(vulkanAdapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); return false; } - // create a device and a graphics command queue with the vulkan adapter - PalGPUDevice* device = nullptr; - PalGPUFeatures GPUfeatures = PAL_GPU_FEATURE_SWAPCHAIN; + // create a graphics queue + PalQueue* gfxQueue = nullptr; + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &gfxQueue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } - result = palCreateGPUDevice(vulkanAdapter, GPUfeatures, &device); + /// we need a window. We use PAL video system to create the window + result = palInitVideo(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + palLog(nullptr, "Failed to initialize video: %s", error); return false; } - // create a graphics command queue - PalGPUCommandQueueType queueType = PAL_GPU_COMMAND_QUEUE_TYPE_GRAPHICS; - PalGPUCommandQueue* graphicsQueue = nullptr; - result = palCreateGPUCommandQueue(device, queueType, &graphicsQueue); + PalWindow* window = nullptr; + PalWindowCreateInfo createInfo = {0}; + createInfo.height = 480; + createInfo.width = 640; + createInfo.show = true; + + // check if we support decorated windows (title bar, close etc) + PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); + if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + // if we dont support, we need to create a borderless window + // and create the decorations ourselves + createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command queue: %s", error); + palLog(nullptr, "Failed to create window: %s", error); return false; } - // create and retrive the native window handles - PalGPUWindow gpuWindow = {0}; - PalWindowHandleInfo windowHandleInfo = {}; - windowHandleInfo = palGetWindowHandleInfo(window); - gpuWindow.display = windowHandleInfo.nativeDisplay; - gpuWindow.window = windowHandleInfo.nativeWindow; + PalGfxWindow gfxWindow = {0}; + PalWindowHandleInfo winInfo = palGetWindowHandleInfo(window); + gfxWindow.display = winInfo.nativeDisplay; + gfxWindow.window = winInfo.nativeWindow; - // check if the command queue supports presentation to your window - bool canPresent = palCanCommandQueuePresent(graphicsQueue, &gpuWindow); + bool canPresent = palCanQueuePresent(gfxQueue, &gfxWindow); if (!canPresent) { - palLog(nullptr, "Command queue cannot present to provided window"); - // cleanup + palLog(nullptr, "Queue could not present to window"); return false; } @@ -169,7 +160,7 @@ bool swapchainTest() PalSwapchainCapabilities swapchainCaps = {0}; result = palQuerySwapchainCapabilities( vulkanAdapter, - &gpuWindow, + &gfxWindow, &swapchainCaps); if (result != PAL_RESULT_SUCCESS) { @@ -179,136 +170,103 @@ bool swapchainTest() } // log swapchain capabilities - Uint32 bufferLayers = swapchainCaps.maxBufferArrayLayers; + Uint32 imageArrayLayers = swapchainCaps.maxImageArrayLayers; palLog(nullptr, "Swapchain capabilities:"); - palLog(nullptr, " Min buffer count: %d", swapchainCaps.minBufferCount); - palLog(nullptr, " Max buffer count: %d", swapchainCaps.maxBufferCount); - palLog(nullptr, " Max buffer array layers: %d", bufferLayers); + palLog(nullptr, " Min image count: %d", swapchainCaps.minImageCount); + palLog(nullptr, " Max image count: %d", swapchainCaps.maxImageCount); + palLog(nullptr, " Max image array layers: %d", imageArrayLayers); - palLog(nullptr, " Min width: %d", swapchainCaps.minWidth); - palLog(nullptr, " Min height: %d", swapchainCaps.minHeight); - palLog(nullptr, " Max width: %d", swapchainCaps.maxWidth); - palLog(nullptr, " Max height: %d", swapchainCaps.maxHeight); + palLog(nullptr, " Min image width: %d", swapchainCaps.minImageWidth); + palLog(nullptr, " Min image height: %d", swapchainCaps.minImageHeight); + palLog(nullptr, " Max image width: %d", swapchainCaps.maxImageWidth); + palLog(nullptr, " Max image height: %d", swapchainCaps.maxImageHeight); + + Uint32 bgraSrgbSrgb = PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB; + Uint32 bgraUnormSrgb = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; + Uint32 rgbaFloatHdr = PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10; + Uint32 rgbaUnormSrgb = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; palLog(nullptr, " Supported formats:"); - if (swapchainCaps.formats & PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB) { + if (swapchainCaps.swapchainFormatsAllowed[bgraSrgbSrgb]) { palLog(nullptr, " BGRA8 SRGB SRGB"); } - if (swapchainCaps.formats & PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB) { + if (swapchainCaps.swapchainFormatsAllowed[bgraUnormSrgb]) { palLog(nullptr, " BGRA8 UNORM SRGB"); } - if (swapchainCaps.formats & PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10) { + if (swapchainCaps.swapchainFormatsAllowed[rgbaFloatHdr]) { palLog(nullptr, " RGBA16 FLOAT HDR10"); } - if (swapchainCaps.formats & PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB) { + if (swapchainCaps.swapchainFormatsAllowed[rgbaUnormSrgb]) { palLog(nullptr, " RGBA8 UNORM SRGB"); } + Uint32 fifo = PAL_PRESENT_MODE_FIFO; + Uint32 immediate = PAL_PRESENT_MODE_IMMEDIATE; + Uint32 mailbox = PAL_PRESENT_MODE_MAILBOX; + palLog(nullptr, " Supported present modes:"); - if (swapchainCaps.presentModes & PAL_PRESENT_MODE_FIFO) { + if (swapchainCaps.presentModessAllowed[fifo]) { palLog(nullptr, " FIFO"); } - if (swapchainCaps.presentModes & PAL_PRESENT_MODE_IMMEDIATE) { + if (swapchainCaps.presentModessAllowed[immediate]) { palLog(nullptr, " Immediate"); } - if (swapchainCaps.presentModes & PAL_PRESENT_MODE_MAILBOX) { + if (swapchainCaps.presentModessAllowed[mailbox]) { palLog(nullptr, " Mailbox"); } - palLog(nullptr, " Supported transforms:"); - if (swapchainCaps.transforms & PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE) { - palLog(nullptr, " Landscape"); - } - - if (swapchainCaps.transforms & PAL_SWAPCHAIN_TRANSFORM_PORTRAIT) { - palLog(nullptr, " Portrait"); - } - - if (swapchainCaps.transforms & PAL_SWAPCHAIN_TRANSFORM_PORTRAIT_FLIPPED) { - palLog(nullptr, " Portrait flipped"); - } - - if (swapchainCaps.transforms & PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE_FLIPPED) { - palLog(nullptr, " Landscape flipped"); - } - - palLog(nullptr, " Supported sharing modes:"); - if (swapchainCaps.sharingModes & PAL_SWAPCHAIN_SHARING_MODE_EXCLUSIVE) { - palLog(nullptr, " Exclusive"); - } - - if (swapchainCaps.sharingModes & PAL_SWAPCHAIN_SHARING_MODE_CONCURRENT) { - palLog(nullptr, " Concurrent"); - } + Uint32 opaque = PAL_COMPOSITE_ALPHA_OPAQUE; + Uint32 postMultiplied = PAL_COMPOSITE_ALPHA_POST_MULTIPLIED; + Uint32 preMultiplied = PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED; palLog(nullptr, " Supported composite alphas:"); - if (swapchainCaps.compositeAlphas & PAL_COMPOSITE_ALPHA_OPAQUE) { + if (swapchainCaps.compositeAlphasAllowed[opaque]) { palLog(nullptr, " Opaque"); } - if (swapchainCaps.compositeAlphas & PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED) { + if (swapchainCaps.compositeAlphasAllowed[preMultiplied]) { palLog(nullptr, " Pre Multiplied"); } - if (swapchainCaps.compositeAlphas & PAL_COMPOSITE_ALPHA_POST_MULTIPLIED) { + if (swapchainCaps.compositeAlphasAllowed[postMultiplied]) { palLog(nullptr, " Post Multiplied"); } - palLog(nullptr, " Supported usages:"); - if (swapchainCaps.usages & PAL_SWAPCHAIN_USAGE_SAMPLED) { - palLog(nullptr, " Sampled"); - } - - if (swapchainCaps.usages & PAL_SWAPCHAIN_USAGE_TRANSFER_DST) { - palLog(nullptr, " Transfer Dst"); - } - - if (swapchainCaps.usages & PAL_SWAPCHAIN_USAGE_TRANSFER_SRC) { - palLog(nullptr, " Transfer src"); - } - - if (swapchainCaps.usages & PAL_SWAPCHAIN_USAGE_COLOR_ATTACHEMENT) { - palLog(nullptr, " Color attachment"); - } - - // create a swapchain + // create swapchain PalSwapchain* swapchain = nullptr; PalSwapchainCreateInfo swapchainCreateInfo = {0}; - swapchainCreateInfo.bufferArrayLayerCount = 1; // works on all systems - - // check max count to choose buffers but for this example - //we just set it to the minimal supported - swapchainCreateInfo.bufferCount = swapchainCaps.minBufferCount; swapchainCreateInfo.clipped = true; - swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + swapchainCreateInfo.compositeAlpha = opaque; + swapchainCreateInfo.format = rgbaUnormSrgb; + swapchainCreateInfo.imageArrayLayerCount = 1; // 2 VR + + // check the number and increment it but not passed + // PalSwapchainCapabilities::maxImageCount + swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; + swapchainCreateInfo.presentMode = fifo; // set size swapchainCreateInfo.width = 640; swapchainCreateInfo.height = 480; - if (640 > swapchainCaps.maxWidth) { + if (640 > swapchainCaps.maxImageWidth) { // we set it to the minimal to mak it work across systems - swapchainCreateInfo.width = swapchainCaps.minWidth; + swapchainCreateInfo.width = swapchainCaps.minImageWidth; } - if (480 > swapchainCaps.maxHeight) { + if (480 > swapchainCaps.maxImageHeight) { // we set it to the minimal to mak it work across systems - swapchainCreateInfo.height = swapchainCaps.minHeight; + swapchainCreateInfo.height = swapchainCaps.minImageHeight; } - swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - swapchainCreateInfo.transform = PAL_SWAPCHAIN_TRANSFORM_LANDSCAPE; - swapchainCreateInfo.usage = PAL_SWAPCHAIN_USAGE_COLOR_ATTACHEMENT; - swapchainCreateInfo.sharingMode = PAL_SWAPCHAIN_SHARING_MODE_EXCLUSIVE; - result = palCreateSwapchain( - graphicsQueue, - &gpuWindow, + device, + gfxQueue, + &gfxWindow, &swapchainCreateInfo, &swapchain); @@ -318,54 +276,68 @@ bool swapchainTest() return false; } - // get the number of buffers the swapchain has - // this should match the buffers used to create the swapchain - Uint32 swapchainBufferCount = palGetSwapchainBufferCount(swapchain); - palLog(nullptr, "Swapchain buffer count: %d", swapchainBufferCount); + // if you need to get all images and create image views for them + // use palGetSwapchainImage() to get the image count. + // but this is the same number as the requested images + // when creating the swapchain - // create a render target view for the first swapchain buffer - PalRenderTargetView* rtv = nullptr; - result = palCreateRenderTargetView(swapchain, 0, &rtv); + // we only get the first image and use it for our needs + PalImage* swapchainImage = palGetSwapchainImage(swapchain, 0); + if (!swapchainImage) { + palLog(nullptr, "Failed to get swapchain image"); + return false; + } + + // create an image view for the image + // swapchain images do not need memory to be bound to them + PalImageView* imageView = nullptr; + PalImageViewCreateInfo imageViewCreateInfo = {0}; + PalImageInfo imageInfo = {0}; + + // get the swapchain info and use it to create the image view + result = palGetImageInfo(swapchainImage, &imageInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create render target view: %s", error); + palLog(nullptr, "Failed to get image info: %s", error); return false; } - // query render pass capabilities of the swapchain - PalRenderPassCapabilities renderPassCaps = {0}; - result = palQueryRenderPassCapabilities( - swapchain, - &renderPassCaps); + imageViewCreateInfo.layerArrayCount = imageInfo.depthOrArraySize; + imageViewCreateInfo.mipLevelCount = imageInfo.mipLevelCount; + imageViewCreateInfo.startArrayLayer = 0; // always 0 for swapchain + imageViewCreateInfo.startMipLevel = 0; // always 0 for swapchain + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; // only 2D + imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; + + result = palCreateImageView( + device, + swapchainImage, + &imageViewCreateInfo, + &imageView); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query render pass capabilities: %s", error); + palLog(nullptr, "Failed to create image view: %s", error); return false; } - // log render pass capabilities - Uint32 maxColorAttachments = renderPassCaps.maxColorAttachments; - palLog(nullptr, "Render pass capabilities:"); - palLog(nullptr, " Max color attachments: %d", maxColorAttachments); - palLog(nullptr, " Max multi views: %d", renderPassCaps.maxMultiViews); - - // destroy the render target view - palDestroyRenderTargetView(rtv); + // destroy the image view + palDestroyImageView(imageView); // destroy the swapchain palDestroySwapchain(swapchain); - // destroy command queue and gpu device - palDestroyGPUCommandQueue(graphicsQueue); - palDestroyGPUDevice(device); - - // destroy window and shutdown video system palDestroyWindow(window); palShutdownVideo(); + // destroy the graphics queue + palDestroyQueue(gfxQueue); + + // destroy the device + palDestroyDevice(device); + // shutdown the graphics system palShutdownGraphics(); return true; -} \ No newline at end of file +} diff --git a/tests/tests.h b/tests/tests.h index 060357e9..b842a06e 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -61,5 +61,6 @@ bool imageTest(); // graphics and video bool queueTest(); +bool swapchainTest(); #endif // _TESTS_H \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index 26d0bb05..ae39a869 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -73,8 +73,8 @@ project "tests" if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { - "queue_test.c" - --"swapchain_test.c" + "queue_test.c", + "swapchain_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 183e4a73..37f3a1b6 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,11 +57,12 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest("Graphics Test", graphicsTest); // registerTest("Device Test", deviceTest); - registerTest("Image Test", imageTest); + // registerTest("Image Test", imageTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest("Queue Test", queueTest); + registerTest("Swapchain Test", swapchainTest); #endif runTests(); From eb1c7966c3ce46af6a714401d8156cdacf00bcff Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 4 Dec 2025 16:59:40 +0000 Subject: [PATCH 032/372] simplify graphics api --- include/pal/pal_graphics.h | 99 ++----- src/graphics/pal_graphics_linux.c | 416 +++++++++++------------------- tests/graphics_test.c | 4 - tests/image_test.c | 19 +- tests/swapchain_test.c | 39 +-- tests/tests_main.c | 8 +- 6 files changed, 203 insertions(+), 382 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index c8519e69..c02527f1 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -45,7 +45,6 @@ typedef struct PalQueue PalQueue; typedef struct PalSwapchain PalSwapchain; typedef struct PalImage PalImage; typedef struct PalImageView PalImageView; -typedef struct PalRenderPass PalRenderPass; typedef enum { PAL_ADAPTER_TYPE_UNKNOWN, @@ -213,14 +212,13 @@ typedef enum { PAL_ADAPTER_FEATURE_SHADER_FLOAT64 = PAL_BIT64(7), PAL_ADAPTER_FEATURE_SHADER_INT16 = PAL_BIT64(8), PAL_ADAPTER_FEATURE_SHADER_INT64 = PAL_BIT64(9), - PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(10), - PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(11), - PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(12), - PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(13), - PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), - PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(15), - PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16), - PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(17) + PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(10), + PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(11), + PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(12), + PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(13), + PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(14), + PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(15), + PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(16) } PalAdapterFeatures; typedef enum { @@ -302,9 +300,9 @@ typedef struct { } PalAdapterCapabilities; typedef struct { - bool presentModessAllowed[PAL_PRESENT_MODE_MAX]; - bool compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_MAX]; - bool swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_MAX]; + bool presentModes[PAL_PRESENT_MODE_MAX]; + bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; + bool formats[PAL_SWAPCHAIN_FORMAT_MAX]; Uint32 minImageCount; Uint32 maxImageCount; Uint32 minImageWidth; @@ -314,43 +312,20 @@ typedef struct { Uint32 maxImageArrayLayers; } PalSwapchainCapabilities; -// typedef struct { -// Uint32 maxMultiViews; -// Uint32 maxColorAttachments; -// } PalRenderPassCapabilities; - -// typedef struct { -// Uint32 mipLevel; -// Uint32 baseLayer; -// Uint32 layerCount; -// PalRenderTargetView* renderTargetView; -// } PalRenderPassResolveInfo; - -// typedef struct { -// Uint32 mipLevel; -// Uint32 baseLayer; -// Uint32 layerCount; -// PalRenderPassLoadOp loadOp; -// PalRenderPassStoreOp storeOp; -// float depth; -// float stencil; -// PalRenderPassResolveInfo* resolve; -// float color[4]; -// } PalRenderPassAttachmentInfo; - -// typedef struct { -// Uint32 attachmentCount; -// Uint32 multiViewCount; -// PalRenderTargetView* renderTargetView; -// PalRenderPassAttachmentInfo* attachments; -// } PalRenderPassCreateInfo; - typedef struct { PalFormat format; PalImageUsages usages; PalImageViewUsages viewUsages; } PalFormatInfo; +typedef struct { + Uint32 multiViewCount; + PalLoadOp loadOp; + PalStoreOp storeOp; + PalImageView* target; + PalImageView* resolveTarget; +} PalAttachmentDesc; + typedef struct { Uint32 width; Uint32 height; @@ -358,11 +333,12 @@ typedef struct { Uint32 mipLevelCount; Uint32 samples; PalImageType type; - PalFormatInfo format; + PalFormat format; + PalImageUsages usages; } PalImageInfo; typedef struct { - bool memoryTypeAllowed[PAL_MEMORY_TYPE_MAX]; + bool memoryTypes[PAL_MEMORY_TYPE_MAX]; Uint64 size; Uint32 alignment; } PalMemoryRequirements; @@ -373,8 +349,9 @@ typedef struct { Uint32 depthOrArraySize; Uint32 mipLevelCount; Uint32 samples; - PalImageViewType type; - PalFormatInfo format; + PalImageType type; + PalFormat format; + PalImageUsages usages; } PalImageCreateInfo; typedef struct { @@ -383,7 +360,7 @@ typedef struct { Uint32 startArrayLayer; Uint32 layerArrayCount; PalImageViewType type; - PalImageUsages usages; + PalImageViewUsages usages; } PalImageViewCreateInfo; typedef struct { @@ -509,17 +486,6 @@ typedef struct { PalImage* PAL_CALL (*getSwapchainImage)( PalSwapchain* swapchain, Int32 index); - - // PalResult PAL_CALL (*queryRenderPassCapabilities)( - // PalSwapchain* swapchain, - // PalRenderPassCapabilities* caps); - - // PalResult PAL_CALL (*createRenderPass)( - // PalSwapchain* swapchain, - // PalRenderPassCreateInfo* info, - // PalRenderPass** outRenderPass); - - // void PAL_CALL (*destroyRenderPass)(PalRenderPass* renderPass); } PalGPUBackend; PAL_API PalResult PAL_CALL palInitGraphics( @@ -580,11 +546,11 @@ PAL_API bool PAL_CALL palIsFormatSupported( PalAdapter* adapter, PalFormat format); -PAL_API PalImageUsages PAL_CALL palQueryFormatUsages( +PAL_API PalImageUsages PAL_CALL palQueryFormatImageUsages( PalAdapter* adapter, PalFormat format); -PAL_API PalImageViewUsages PAL_CALL palQueryFormatViewUsages( +PAL_API PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( PalAdapter* adapter, PalFormat format); @@ -637,17 +603,6 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, Int32 index); -// PAL_API PalResult PAL_CALL palQueryRenderPassCapabilities( -// PalSwapchain* swapchain, -// PalRenderPassCapabilities* caps); - -// PAL_API PalResult PAL_CALL palCreateRenderPass( -// PalSwapchain* swapchain, -// PalRenderPassCreateInfo* info, -// PalRenderPass** outRenderPass); - -// PAL_API void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass); - /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index e5ae307b..ddacc338 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -57,7 +57,7 @@ typedef int (*wl_display_get_fd_fn)(struct wl_display*); typedef struct { bool hasDebug; - bool versionFallback; + bool hasDynamicRendering; void* handle; VkInstance instance; @@ -117,7 +117,6 @@ typedef struct { } PhysicalQueue; typedef struct { - bool dynamicRendering; Int32 queueCount; VkPhysicalDevice phyDevice; VkDevice handle; @@ -145,6 +144,7 @@ typedef struct { typedef struct { VkImageViewType type; + PalImageViewUsages usages; Device* device; Image* image; VkImageView handle; @@ -158,13 +158,6 @@ typedef struct { Image* images; } Swapchain; -typedef struct { - Device* device; - VkFramebuffer framebuffer; - VkRenderPass handle; - //PalRenderPassCreateInfo info; -} RenderPass; - static Vulkan s_Vk = {0}; #endif // PAL_HAS_VULKAN @@ -253,7 +246,9 @@ static bool vkOnWayland(struct wl_display* display) return true; } -static bool vkCreateSurface(PalGfxWindow* window, VkSurfaceKHR* outSurface) +static bool vkCreateSurface( + PalGfxWindow* window, + VkSurfaceKHR* outSurface) { if (vkOnWayland(window->display)) { if (!s_Vk.createWaylandSurface) { @@ -1138,12 +1133,17 @@ static PalResult vkInitGraphics(bool enableDebugLayer) // get version bool versionFallback = false; + s_Vk.hasDynamicRendering = false; Uint32 version = 0; if (s_Vk.enumerateInstanceVersion) { s_Vk.enumerateInstanceVersion(&version); if (version <= VK_API_VERSION_1_0) { versionFallback = true; } + + if (version >= VK_API_VERSION_1_3) { + s_Vk.hasDynamicRendering = true; + } } VkResult ret; @@ -1290,17 +1290,12 @@ static PalResult vkInitGraphics(bool enableDebugLayer) // clang-format off if (versionFallback) { + s_Vk.getPhysicalDeviceFeatures2KHR = nullptr; // load get physical device properties2 proc if we are on version 1.0 s_Vk.getPhysicalDeviceFeatures2KHR = (PFN_vkGetPhysicalDeviceFeatures2KHR)s_Vk.getInstanceProcAddr( s_Vk.handle, "vkGetPhysicalDeviceFeatures2KHR"); - - if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.versionFallback = true; - } else { - s_Vk.versionFallback = false; - } } // load surface creation function pointers @@ -1368,6 +1363,7 @@ static PalResult _vkEnumerateAdapters( PalAdapter** outAdapters) { int _count = 0; + int deviceCount = 0; int maxCount = outAdapters ? *count : 0; VkResult result; @@ -1376,15 +1372,10 @@ static PalResult _vkEnumerateAdapters( return PAL_RESULT_PLATFORM_FAILURE; } - if (!outAdapters) { - *count = _count; - return PAL_RESULT_SUCCESS; - } - + // PAL only supports supports dynamic rendering VkPhysicalDevice* devices = nullptr; - devices = palAllocate( - s_Graphics.allocator, - sizeof(VkPhysicalDevice) * _count, + devices = palAllocate(s_Graphics.allocator, + sizeof(VkPhysicalDevice) * _count, 0); if (!devices) { @@ -1392,8 +1383,78 @@ static PalResult _vkEnumerateAdapters( } s_Vk.enumeratePhysicalDevices(s_Vk.instance, &_count, devices); - for (int i = 0; i < _count && i < *count; i++) { - outAdapters[i] = (PalAdapter*)devices[i]; + for (int i = 0; i < _count; i++) { + // check if the gpu supports dynamic rendering + if (s_Vk.hasDynamicRendering) { + if (outAdapters) { + if (deviceCount < *count) { + PalAdapter* adapter = (PalAdapter*)devices[i]; + outAdapters[deviceCount++] = adapter; + } + + } else { + deviceCount++; + } + + } else { + // check extension + Uint32 extCount = 0; + VkExtensionProperties* exts = nullptr; + VkResult ret; + ret = s_Vk.enumerateDeviceExtensionProperties( + devices[i], + nullptr, + &extCount, + nullptr); + + if (ret != VK_SUCCESS) { + // skip + continue; + } + + exts = palAllocate( + s_Graphics.allocator, + sizeof(VkExtensionProperties) * extCount, + 0); + + if (!exts) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + s_Vk.enumerateDeviceExtensionProperties( + devices[i], + nullptr, + &extCount, + exts); + + bool found = false; + for (int j = 0; j < extCount; j++) { + const char* name = exts[j].extensionName; + if (strcmp(name, "VK_KHR_dynamic_rendering") == 0) { + found = true; + } + } + + palFree(s_Graphics.allocator, exts); + if (!found) { + // skip + continue; + } + + if (outAdapters) { + if (deviceCount < *count) { + PalAdapter* adapter = (PalAdapter*)devices[i]; + outAdapters[deviceCount++] = adapter; + } + + } else { + deviceCount++; + } + } + } + + if (!outAdapters) { + *count = deviceCount; } palFree(s_Graphics.allocator, devices); @@ -1666,10 +1727,6 @@ static PalResult PAL_CALL _vkGetAdapterCapabilities( // swapchain caps->features |= PAL_ADAPTER_FEATURE_SWAPCHAIN; - } else if (strcmp(props->extensionName, "VK_KHR_dynamic_rendering") == 0) { - // dynamic rendering - caps->features |= PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING; - } else if (strcmp(props->extensionName, "VK_KHR_shader_float16_int8") == 0) { // shader float16 VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; @@ -1834,7 +1891,6 @@ static PalResult PAL_CALL _vkCreateDevice( device->queueCount = count; device->phyDevice = phyDevice; - device->dynamicRendering = false; device->phyQueues = palAllocate( s_Graphics.allocator, @@ -1925,15 +1981,11 @@ static PalResult PAL_CALL _vkCreateDevice( // clang-format on + extensions[extCount++] = "VK_KHR_dynamic_rendering"; if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { extensions[extCount++] = "VK_KHR_swapchain"; } - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { - extensions[extCount++] = "VK_KHR_dynamic_rendering"; - device->dynamicRendering = true; - } - if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { extensions[extCount++] = "VK_KHR_timeline_semaphore"; timeline.timelineSemaphore = true; @@ -2272,9 +2324,9 @@ static PalResult PAL_CALL _vkCreateImage( createInfo.extent.height = info->height; createInfo.mipLevels = info->mipLevelCount; - createInfo.format = palFormatToVk(info->format.format); + createInfo.format = palFormatToVk(info->format); createInfo.samples = samplesToVk(info->samples); - createInfo.usage = palUsageToVk(info->format.usages); + createInfo.usage = palUsageToVk(info->usages); createInfo.arrayLayers = info->depthOrArraySize; createInfo.extent.depth = 1; @@ -2301,6 +2353,7 @@ static PalResult PAL_CALL _vkCreateImage( image->info.depthOrArraySize = info->depthOrArraySize; image->info.type = info->type; image->info.format = info->format; + image->info.usages = info->usages; image->info.height = info->height; image->info.mipLevelCount = info->mipLevelCount; image->info.samples = info->samples; @@ -2350,6 +2403,28 @@ static PalResult PAL_CALL _vkEnumerateFormats( fmtInfo->format = (PalFormat)i; fmtInfo->usages = vkFeatureToPalUsage(props.optimalTilingFeatures); + + PalImageViewUsages usages = 0; + if (i == PAL_FORMAT_S8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } + + if (i == PAL_FORMAT_D16_UNORM || i == PAL_FORMAT_D32_SFLOAT) { + usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + } + + if (i == PAL_FORMAT_D32_SFLOAT_S8_UINT || + i == PAL_FORMAT_D16_UNORM_S8_UINT || + i == PAL_FORMAT_D24_UNORM_S8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } + + if (usages == 0) { + usages = PAL_IMAGE_VIEW_USAGE_COLOR; + } + + fmtInfo->viewUsages = usages; } } else { @@ -2381,7 +2456,7 @@ static bool PAL_CALL _vkIsFormatSupported( return false; } -static PalImageUsages PAL_CALL _vkQueryFormatUsages( +static PalImageUsages PAL_CALL _vkQueryFormatImageUsages( PalAdapter* adapter, PalFormat format) { @@ -2397,7 +2472,7 @@ static PalImageUsages PAL_CALL _vkQueryFormatUsages( return PAL_IMAGE_USAGE_UNDEFINED; } -static PalImageViewUsages PAL_CALL _vkQueryFormatViewUsages( +static PalImageViewUsages PAL_CALL _vkQueryFormatImageViewUsages( PalAdapter* adapter, PalFormat format) { @@ -2452,9 +2527,9 @@ static PalResult PAL_CALL _vkGetImageMemoryRequirements( requirments->alignment = (Uint64)memReq.alignment; requirments->size = (Uint64)memReq.size; - requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_GPU_ONLY] = false; - requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; - requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_CPU_READBACK] = false; + requirments->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; + requirments->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; + requirments->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = false; for (int i = 0; i < memProps.memoryTypeCount; i++) { if (!(memReq.memoryTypeBits & (1 << i))) { @@ -2462,20 +2537,19 @@ static PalResult PAL_CALL _vkGetImageMemoryRequirements( continue; } - bool t = true; VkMemoryPropertyFlags prop = memProps.memoryTypes[i].propertyFlags; if (prop & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { - requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_GPU_ONLY] = t; + requirments->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; } if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { - requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_CPU_UPLOAD] = t; + requirments->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; } if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { - requirments->memoryTypeAllowed[PAL_MEMORY_TYPE_CPU_READBACK] = t; + requirments->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; } } @@ -2557,7 +2631,7 @@ static PalResult PAL_CALL _vkCreateImageView( VkImageViewCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.format = _image->info.format.format; + createInfo.format = palFormatToVk(_image->info.format); createInfo.image = _image->handle; createInfo.subresourceRange.baseArrayLayer = info->startArrayLayer; @@ -2594,6 +2668,7 @@ static PalResult PAL_CALL _vkCreateImageView( imageView->device = _device; imageView->image = _image; imageView->type = createInfo.viewType; + imageView->usages = info->usages; *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; @@ -2665,66 +2740,65 @@ static PalResult PAL_CALL _vkQuerySwapchainCapabilities( // get supported composite alphas VkCompositeAlphaFlagsKHR alpha = surfaceCaps.supportedCompositeAlpha; - caps->compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_OPAQUE] = true; - caps->compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = false; - caps->compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = false; - bool t = true; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = true; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = false; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = false; if (alpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { - caps->compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = t; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = true; } if (alpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { - caps->compositeAlphasAllowed[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = t; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = true; } // present modes - caps->presentModessAllowed[PAL_PRESENT_MODE_FIFO] = true; - caps->presentModessAllowed[PAL_PRESENT_MODE_MAILBOX] = false; - caps->presentModessAllowed[PAL_PRESENT_MODE_IMMEDIATE] = false; + caps->presentModes[PAL_PRESENT_MODE_FIFO] = true; + caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = false; + caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = false; for (int i = 0; i < modeCount; i++) { if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { - caps->presentModessAllowed[PAL_PRESENT_MODE_IMMEDIATE] = true; + caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = true; } if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { - caps->presentModessAllowed[PAL_PRESENT_MODE_MAILBOX] = true; + caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = true; } } // clang-format off // get format and colorspace - caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = false; - caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB] = false; - caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB] = false; - caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB] = false; + caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = false; + caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB] = false; + caps->formats[PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB] = false; + caps->formats[PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB] = false; for (int i = 0; i < formatCount; i++) { VkSurfaceFormatKHR* fmt = &formats[i]; if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB] = true; + caps->formats[PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB] = true; } } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB] = true; + caps->formats[PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB] = true; } } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB] = true; + caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB] = true; } } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { - caps->swapchainFormatsAllowed[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = true; + caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = true; } } } @@ -2890,8 +2964,8 @@ static PalResult PAL_CALL _vkCreateSwapchain( image->handle = images[i]; image->info.depthOrArraySize = createInfo.imageArrayLayers; - image->info.format.format = imageFormat; - image->info.format.viewUsages = PAL_IMAGE_VIEW_USAGE_COLOR; + image->info.format = imageFormat; + image->info.usages = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; image->info.height = createInfo.imageExtent.height; image->info.width = createInfo.imageExtent.width; image->info.mipLevelCount = 1; @@ -2938,104 +3012,6 @@ static PalImage* PAL_CALL _vkGetSwapchainImage( return (PalImage*)&_swapchain->images[index]; } -// static PalResult PAL_CALL vkQueryRenderPassCapabilities( -// PalSwapchain* swapchain, -// PalRenderPassCapabilities* caps) -// { -// Swapchain* _swapchain = (Swapchain*)swapchain; -// Device* device = (Device*)_swapchain->device; - -// VkPhysicalDeviceProperties props = {0}; -// s_Vk.getPhysicalDeviceProperties(device->phyDevice, &props); -// caps->maxColorAttachments = props.limits.maxColorAttachments; -// caps->maxMultiViews = device->multiViewCount; - -// return PAL_RESULT_SUCCESS; -// } - -// static PalResult PAL_CALL vkCreateRenderPass_( -// PalSwapchain* swapchain, -// PalRenderPassCreateInfo* info, -// PalRenderPass** outRenderPass) -// { -// VkResult result = VK_SUCCESS; -// RenderPass* renderPass = nullptr; -// Swapchain* _swapchain = (Swapchain*)swapchain; - -// renderPass = palAllocate(s_Graphics.allocator, sizeof(RenderPass), 0); -// if (!renderPass) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } - -// renderPass->device = _swapchain->device; -// if (_swapchain->device->dynamicRendering) { -// // we support dynamic rendering, just store the information -// renderPass->info = *info; -// renderPass->handle = nullptr; -// renderPass->framebuffer = nullptr; - -// } else { -// // dynamic rendering not supported -// VkAttachmentDescription* attachmentDescs = nullptr; -// attachmentDescs = palAllocate( -// s_Graphics.allocator, -// sizeof(VkAttachmentDescription) * info->attachmentCount, -// 0); - -// if (!attachmentDescs) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } - -// RenderTargetView* rtv = nullptr; -// for (int i = 0; i < info->attachmentCount; i++) { -// rtv = (RenderTargetView*)info->renderTargetView; -// PalRenderPassAttachmentInfo* aInfo = &info->attachments[i]; -// VkAttachmentDescription* aDesc = &attachmentDescs[i]; - -// aDesc->format = rtv->format; -// aDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; -// aDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - -// // load op -// if (aInfo->loadOp == PAL_RENDER_PASS_LOAD_OP_CLEAR) { -// aDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - -// } else if (aInfo->loadOp == PAL_RENDER_PASS_LOAD_OP_LOAD) { -// aDesc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - -// } else if (aInfo->loadOp == PAL_RENDER_PASS_LOAD_OP_DONT_CARE) { -// aDesc->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; -// } - -// // store op -// if (aInfo->storeOp == PAL_RENDER_PASS_STORE_OP_STORE) { -// aDesc->storeOp = VK_ATTACHMENT_STORE_OP_STORE; - -// } else if (aInfo->storeOp == PAL_RENDER_PASS_STORE_OP_DONT_CARE) { -// aDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; -// } -// } - - -// attachmentDesc. - - - - - -// VkRenderPassCreateInfo createInfo = {0}; -// createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; -// } - -// *outRenderPass = (PalRenderPass*)renderPass; -// return PAL_RESULT_SUCCESS; -// } - -// static void PAL_CALL vkDestroyRenderPass_(PalRenderPass* renderPass) -// { - -// } - static PalGPUBackend s_VkBackend = { // adapter .enumerateAdapters = _vkEnumerateAdapters, @@ -3057,8 +3033,8 @@ static PalGPUBackend s_VkBackend = { .getImageInfo = _vkGetImageInfo, .enumerateFormats = _vkEnumerateFormats, .isFormatSupported = _vkIsFormatSupported, - .queryFormatUsages = _vkQueryFormatUsages, - .queryFormatViewUsages = _vkQueryFormatViewUsages, + .queryFormatUsages = _vkQueryFormatImageUsages, + .queryFormatViewUsages = _vkQueryFormatImageViewUsages, .getImageMemoryRequirements = _vkGetImageMemoryRequirements, // memory @@ -3076,15 +3052,6 @@ static PalGPUBackend s_VkBackend = { .destroySwapchain = vkDestroySwapchain, .getSwapchainImageCount = _vkGetSwapchainImageCount, .getSwapchainImage = _vkGetSwapchainImage, - - // // render target view - // .createRenderTargetView = vkCreateRenderTargetView, - // .destroyRenderTargetView = vkDestroyRenderTargetView, - - // // render pass - // .queryRenderPassCapabilities = vkQueryRenderPassCapabilities, - // .createRenderPass = vkCreateRenderPass_, - // .destroyRenderPass = vkDestroyRenderPass_ }; #endif // PAL_HAS_VULKAN @@ -3523,7 +3490,7 @@ bool PAL_CALL palIsFormatSupported( return adapterData->backend->isFormatSupported(adapter, format); } -PalImageUsages PAL_CALL palQueryFormatUsages( +PalImageUsages PAL_CALL palQueryFormatImageUsages( PalAdapter* adapter, PalFormat format) { @@ -3539,7 +3506,7 @@ PalImageUsages PAL_CALL palQueryFormatUsages( return adapterData->backend->queryFormatUsages(adapter, format); } -PalImageViewUsages PAL_CALL palQueryFormatViewUsages( +PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( PalAdapter* adapter, PalFormat format) { @@ -3826,91 +3793,4 @@ PalImage* PAL_CALL palGetSwapchainImage( imageData->backend = swapchainData->backend; imageData->handle = image; return image; -} - -// // ================================================== -// // Render Pass -// // ================================================== - -// PalResult PAL_CALL palQueryRenderPassCapabilities( -// PalSwapchain* swapchain, -// PalRenderPassCapabilities* caps) -// { -// if (!s_Graphics.initialized) { -// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; -// } - -// if (!swapchain || !caps) { -// return PAL_RESULT_NULL_POINTER; -// } - -// HandleData* swapchainData = findHandleData(swapchain); -// if (!swapchainData) { -// return PAL_RESULT_INVALID_SWAPCHAIN; -// } - -// return swapchainData->backend->queryRenderPassCapabilities( -// swapchain, -// caps); -// } - -// PalResult PAL_CALL palCreateRenderPass( -// PalSwapchain* swapchain, -// PalRenderPassCreateInfo* info, -// PalRenderPass** outRenderPass) -// { -// if (!s_Graphics.initialized) { -// return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; -// } - -// if (!swapchain || !info || !outRenderPass) { -// return PAL_RESULT_NULL_POINTER; -// } - -// if (!info->attachments) { -// return PAL_RESULT_NULL_POINTER; -// } - -// if (info->attachmentCount == 0 && info->attachments) { -// return PAL_RESULT_INSUFFICIENT_BUFFER; -// } - -// HandleData* swapchainData = findHandleData(swapchain); -// if (!swapchainData) { -// return PAL_RESULT_INVALID_SWAPCHAIN; -// } - -// PalResult ret; -// PalRenderPass* renderPass = nullptr; -// ret = swapchainData->backend->createRenderPass( -// swapchain, -// info, -// &renderPass); - -// if (ret != PAL_RESULT_SUCCESS) { -// return ret; -// } - -// // create a slot for the created render pass -// HandleData* renderPassData = getFreeHandleData(); -// if (!renderPassData) { -// return PAL_RESULT_OUT_OF_MEMORY; -// } - -// renderPassData->backend = swapchainData->backend; -// renderPassData->handle = renderPass; - -// *outRenderPass = renderPass; -// return PAL_RESULT_SUCCESS; -// } - -// void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) -// { -// if (s_Graphics.initialized && renderPass) { -// HandleData* data = findHandleData(renderPass); -// if (data) { -// data->backend->destroyRenderPass(renderPass); -// data->used = false; -// } -// } -// } \ No newline at end of file +} \ No newline at end of file diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 3d4a553e..7c79b606 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -252,10 +252,6 @@ bool graphicsTest() palLog(nullptr, " Shader int64"); } - if (caps.features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { - palLog(nullptr, " Dynamic rendering"); - } - if (caps.features & PAL_ADAPTER_FEATURE_RAY_TRACING) { palLog(nullptr, " Ray tracing"); } diff --git a/tests/image_test.c b/tests/image_test.c index a549471d..7b664452 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -109,7 +109,7 @@ bool imageTest() return false; } - if(!(usage & palQueryFormatUsages(vulkanAdapter, format))) { + if(!(usage & palQueryFormatImageUsages(vulkanAdapter, format))) { palLog(nullptr, "The preffered format does not support color attachement"); return false; @@ -117,8 +117,8 @@ bool imageTest() PalImage* image = nullptr; PalImageCreateInfo imageCreateInfo = {0}; - imageCreateInfo.format.format = format; - imageCreateInfo.format.usages = usage; + imageCreateInfo.format = format; + imageCreateInfo.usages = usage; imageCreateInfo.height = 240; imageCreateInfo.mipLevelCount = 1; imageCreateInfo.samples = 1; // very simple @@ -126,7 +126,7 @@ bool imageTest() // if the image type is 1D or 2D // PalImageCreateInfo::depthOrArraySize is used for the array size - imageCreateInfo.type == PAL_IMAGE_TYPE_2D; + imageCreateInfo.type = PAL_IMAGE_TYPE_2D; imageCreateInfo.depthOrArraySize = 1; result = palCreateImage(device, &imageCreateInfo, &image); @@ -146,7 +146,7 @@ bool imageTest() } // allocate memory for the image - if (!imageMemReq.memoryTypeAllowed[PAL_MEMORY_TYPE_GPU_ONLY]) { + if (!imageMemReq.memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY]) { palLog(nullptr, "Cannot allocate gpu only memory"); } @@ -164,7 +164,7 @@ bool imageTest() } PalImageViewUsages viewUsage = PAL_IMAGE_VIEW_USAGE_COLOR; - if(!(viewUsage & palQueryFormatViewUsages(vulkanAdapter, format))) { + if(!(viewUsage & palQueryFormatImageViewUsages(vulkanAdapter, format))) { palLog(nullptr, "The preffered format does not support color image view"); return false; @@ -178,6 +178,7 @@ bool imageTest() imageViewCreateInfo.layerArrayCount = imageCreateInfo.depthOrArraySize; imageViewCreateInfo.mipLevelCount = imageCreateInfo.mipLevelCount; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.usages = viewUsage; result = palCreateImageView( device, @@ -191,8 +192,6 @@ bool imageTest() return false; } - palDestroyImageView(imageView); - // bind the memory to the image result = palBindImageMemory( device, @@ -206,6 +205,10 @@ bool imageTest() return false; } + + // destroy image view + palDestroyImageView(imageView); + // destroy image palDestroyImage(image); diff --git a/tests/swapchain_test.c b/tests/swapchain_test.c index 40f073a0..6dc0c603 100644 --- a/tests/swapchain_test.c +++ b/tests/swapchain_test.c @@ -181,59 +181,46 @@ bool swapchainTest() palLog(nullptr, " Max image width: %d", swapchainCaps.maxImageWidth); palLog(nullptr, " Max image height: %d", swapchainCaps.maxImageHeight); - Uint32 bgraSrgbSrgb = PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB; - Uint32 bgraUnormSrgb = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; - Uint32 rgbaFloatHdr = PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10; - Uint32 rgbaUnormSrgb = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - palLog(nullptr, " Supported formats:"); - if (swapchainCaps.swapchainFormatsAllowed[bgraSrgbSrgb]) { + if (swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB]) { palLog(nullptr, " BGRA8 SRGB SRGB"); } - if (swapchainCaps.swapchainFormatsAllowed[bgraUnormSrgb]) { + if (swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB]) { palLog(nullptr, " BGRA8 UNORM SRGB"); } - if (swapchainCaps.swapchainFormatsAllowed[rgbaFloatHdr]) { + if (swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10]) { palLog(nullptr, " RGBA16 FLOAT HDR10"); } - if (swapchainCaps.swapchainFormatsAllowed[rgbaUnormSrgb]) { + if (swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { palLog(nullptr, " RGBA8 UNORM SRGB"); } - Uint32 fifo = PAL_PRESENT_MODE_FIFO; - Uint32 immediate = PAL_PRESENT_MODE_IMMEDIATE; - Uint32 mailbox = PAL_PRESENT_MODE_MAILBOX; - palLog(nullptr, " Supported present modes:"); - if (swapchainCaps.presentModessAllowed[fifo]) { + if (swapchainCaps.presentModes[PAL_PRESENT_MODE_FIFO]) { palLog(nullptr, " FIFO"); } - if (swapchainCaps.presentModessAllowed[immediate]) { + if (swapchainCaps.presentModes[PAL_PRESENT_MODE_IMMEDIATE]) { palLog(nullptr, " Immediate"); } - if (swapchainCaps.presentModessAllowed[mailbox]) { + if (swapchainCaps.presentModes[PAL_PRESENT_MODE_MAILBOX]) { palLog(nullptr, " Mailbox"); } - Uint32 opaque = PAL_COMPOSITE_ALPHA_OPAQUE; - Uint32 postMultiplied = PAL_COMPOSITE_ALPHA_POST_MULTIPLIED; - Uint32 preMultiplied = PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED; - palLog(nullptr, " Supported composite alphas:"); - if (swapchainCaps.compositeAlphasAllowed[opaque]) { + if (swapchainCaps.compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE]) { palLog(nullptr, " Opaque"); } - if (swapchainCaps.compositeAlphasAllowed[preMultiplied]) { + if (swapchainCaps.compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED]) { palLog(nullptr, " Pre Multiplied"); } - if (swapchainCaps.compositeAlphasAllowed[postMultiplied]) { + if (swapchainCaps.compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED]) { palLog(nullptr, " Post Multiplied"); } @@ -241,14 +228,14 @@ bool swapchainTest() PalSwapchain* swapchain = nullptr; PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = true; - swapchainCreateInfo.compositeAlpha = opaque; - swapchainCreateInfo.format = rgbaUnormSrgb; + swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; swapchainCreateInfo.imageArrayLayerCount = 1; // 2 VR // check the number and increment it but not passed // PalSwapchainCapabilities::maxImageCount swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; - swapchainCreateInfo.presentMode = fifo; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; // set size swapchainCreateInfo.width = 640; diff --git a/tests/tests_main.c b/tests/tests_main.c index 37f3a1b6..236feefc 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,13 +55,13 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); - // registerTest("Device Test", deviceTest); - // registerTest("Image Test", imageTest); + registerTest("Graphics Test", graphicsTest); + registerTest("Device Test", deviceTest); + registerTest("Image Test", imageTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest("Queue Test", queueTest); + registerTest("Queue Test", queueTest); registerTest("Swapchain Test", swapchainTest); #endif From d9df1658e7e7ab5e80b5afc664d042f11d503e4c Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 4 Dec 2025 17:44:14 +0000 Subject: [PATCH 033/372] rewrite graphics api --- include/pal/pal_core.h | 10 ++-- include/pal/pal_graphics.h | 16 ++--- src/graphics/pal_graphics_linux.c | 97 +++++++++++++++++-------------- src/pal_core.c | 20 +++---- 4 files changed, 72 insertions(+), 71 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index a5712ff0..f89a597b 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -248,18 +248,18 @@ typedef enum { PAL_RESULT_INVALID_FBCONFIG_BACKEND, PAL_RESULT_GRAPHICS_NOT_INITIALIZED, PAL_RESULT_INVALID_ADAPTER, - PAL_RESULT_INVALID_GRAPHICS_BACKEND, + PAL_RESULT_INVALID_BACKEND, PAL_RESULT_QUEUE_NOT_SUPPORTED, PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED, - PAL_RESULT_INVALID_GRAPHICS_DRIVER, - PAL_RESULT_INVALID_GRAPHICS_DEVICE, + PAL_RESULT_INVALID_DRIVER, + PAL_RESULT_INVALID_DEVICE, PAL_RESULT_INVALID_QUEUE, PAL_RESULT_OUT_OF_QUEUE, PAL_RESULT_INVALID_GRAPHICS_WINDOW, PAL_RESULT_INVALID_SWAPCHAIN, - PAL_RESULT_INVALID_GRAPHICS_IMAGE, + PAL_RESULT_INVALID_IMAGE, PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED, - PAL_RESULT_INVALID_GRAPHICS_OPERATION + PAL_RESULT_INVALID_OPERATION } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index c02527f1..6d9b85da 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -318,14 +318,6 @@ typedef struct { PalImageViewUsages viewUsages; } PalFormatInfo; -typedef struct { - Uint32 multiViewCount; - PalLoadOp loadOp; - PalStoreOp storeOp; - PalImageView* target; - PalImageView* resolveTarget; -} PalAttachmentDesc; - typedef struct { Uint32 width; Uint32 height; @@ -430,11 +422,11 @@ typedef struct { PalAdapter* adapter, PalFormat format); - PalImageUsages PAL_CALL (*queryFormatUsages)( + PalImageUsages PAL_CALL (*queryFormatImageUsages)( PalAdapter* adapter, PalFormat format); - PalImageViewUsages PAL_CALL (*queryFormatViewUsages)( + PalImageViewUsages PAL_CALL (*queryFormatImageViewUsages)( PalAdapter* adapter, PalFormat format); @@ -486,7 +478,7 @@ typedef struct { PalImage* PAL_CALL (*getSwapchainImage)( PalSwapchain* swapchain, Int32 index); -} PalGPUBackend; +} PalGfxBackend; PAL_API PalResult PAL_CALL palInitGraphics( bool enableDebugLayer, @@ -506,7 +498,7 @@ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps); -PAL_API PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend); +PAL_API PalResult PAL_CALL palAddGfxBackend(const PalGfxBackend* backend); PAL_API PalResult PAL_CALL palCreateDevice( PalAdapter* adapter, diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_graphics_linux.c index ddacc338..a8262387 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_graphics_linux.c @@ -165,13 +165,13 @@ static Vulkan s_Vk = {0}; typedef struct { bool used; void* handle; - const PalGPUBackend* backend; + const PalGfxBackend* backend; } HandleData; typedef struct { Int32 count; Int32 startIndex; - const PalGPUBackend* base; + const PalGfxBackend* base; } BackendData; typedef struct { @@ -300,7 +300,7 @@ static PalResult vkResultToPal(VkResult result) } case VK_ERROR_INCOMPATIBLE_DRIVER: - return PAL_RESULT_INVALID_GRAPHICS_DRIVER; + return PAL_RESULT_INVALID_DRIVER; case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: case VK_ERROR_SURFACE_LOST_KHR: { @@ -2208,7 +2208,7 @@ static PalResult PAL_CALL _vkCreateQueue( Device* _device = (Device*)device; Queue* queue = nullptr; if (!_device->handle) { - return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + return PAL_RESULT_INVALID_DEVICE; } if (_device->queueCount == 0) { @@ -2307,7 +2307,7 @@ static PalResult PAL_CALL _vkCreateImage( Image* image = nullptr; Device* _device = (Device*)device; if (!_device->handle) { - return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + return PAL_RESULT_INVALID_DEVICE; } image = palAllocate(s_Graphics.allocator, sizeof(Image), 0); @@ -2605,7 +2605,7 @@ static PalResult PAL_CALL _vkBindImageMemory( { Image* _image = (Image*)image; if (_image->belongsToSwapchain) { - return PAL_RESULT_INVALID_GRAPHICS_OPERATION; + return PAL_RESULT_INVALID_OPERATION; } Device* _device = (Device*)device; @@ -3012,7 +3012,7 @@ static PalImage* PAL_CALL _vkGetSwapchainImage( return (PalImage*)&_swapchain->images[index]; } -static PalGPUBackend s_VkBackend = { +static PalGfxBackend s_VkBackend = { // adapter .enumerateAdapters = _vkEnumerateAdapters, .getAdapterInfo = _vkGetAdapterInfo, @@ -3033,8 +3033,8 @@ static PalGPUBackend s_VkBackend = { .getImageInfo = _vkGetImageInfo, .enumerateFormats = _vkEnumerateFormats, .isFormatSupported = _vkIsFormatSupported, - .queryFormatUsages = _vkQueryFormatImageUsages, - .queryFormatViewUsages = _vkQueryFormatImageViewUsages, + .queryFormatImageUsages = _vkQueryFormatImageUsages, + .queryFormatImageViewUsages = _vkQueryFormatImageViewUsages, .getImageMemoryRequirements = _vkGetImageMemoryRequirements, // memory @@ -3214,34 +3214,43 @@ PalResult PAL_CALL palGetAdapterCapabilities( return PAL_RESULT_INVALID_ADAPTER; } -PalResult PAL_CALL palAddGPUBackend(const PalGPUBackend* backend) +PalResult PAL_CALL palAddGfxBackend(const PalGfxBackend* backend) { if (s_Graphics.initialized) { - return PAL_RESULT_INVALID_GRAPHICS_BACKEND; - } - - // // check if all the function pointers are set - // // clang-format off - // if (!backend->enumerateGPUAdapters || - // !backend->getGPUAdapterInfo || - // !backend->getGPUAdapterCapabilities || - // !backend->createGPUDevice || - // !backend->destroyGPUDevice || - // !backend->createGPUCommandQueue || - // !backend->destroyGPUCommandQueue || - // !backend->canCommandQueuePresent || - // !backend->createSwapchain || - // !backend->destroySwapchain || - // !backend->querySwapchainCapabilities || - // !backend->getSwapchainBufferCount || - // !backend->createRenderTargetView || - // !backend->destroyRenderTargetView || - // !backend->queryRenderPassCapabilities || - // !backend->createRenderPass || - // !backend->destroyRenderPass) { - // return PAL_RESULT_INVALID_GPU_BACKEND; - // } - // // clang-format on + return PAL_RESULT_INVALID_BACKEND; + } + + // check if all the function pointers are set + // clang-format off + if (!backend->enumerateAdapters || + !backend->getAdapterInfo || + !backend->getAdapterCapabilities || + !backend->createDevice || + !backend->destroyDevice || + !backend->createQueue || + !backend->destroyQueue || + !backend->canQueuePresent || + !backend->createImage || + !backend->destroyImage || + !backend->getImageInfo || + !backend->enumerateFormats || + !backend->isFormatSupported || + !backend->queryFormatImageUsages || + !backend->queryFormatImageViewUsages || + !backend->getImageMemoryRequirements || + !backend->allocate || + !backend->free || + !backend->bindImageMemory || + !backend->createImageView || + !backend->destroyImageView || + !backend->querySwapchainCapabilities || + !backend->createSwapchain || + !backend->destroySwapchain || + !backend->getSwapchainImageCount || + !backend->getSwapchainImage) { + return PAL_RESULT_INVALID_BACKEND; + } + // clang-format on BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; attached->base = backend; @@ -3324,7 +3333,7 @@ PalResult PAL_CALL palCreateQueue( HandleData* data = findHandleData(device); if (!data) { - return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + return PAL_RESULT_INVALID_DEVICE; } PalQueue* queue = nullptr; @@ -3391,7 +3400,7 @@ PalResult PAL_CALL palCreateImage( HandleData* data = findHandleData(device); if (!data) { - return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + return PAL_RESULT_INVALID_DEVICE; } PalImage* image = nullptr; @@ -3443,7 +3452,7 @@ PalResult PAL_CALL palGetImageInfo( HandleData* data = findHandleData(image); if (!data) { - return PAL_RESULT_INVALID_GRAPHICS_IMAGE; + return PAL_RESULT_INVALID_IMAGE; } return data->backend->getImageInfo(image, info); @@ -3503,7 +3512,7 @@ PalImageUsages PAL_CALL palQueryFormatImageUsages( return PAL_IMAGE_USAGE_UNDEFINED; } - return adapterData->backend->queryFormatUsages(adapter, format); + return adapterData->backend->queryFormatImageUsages(adapter, format); } PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( @@ -3519,7 +3528,7 @@ PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( return PAL_IMAGE_VIEW_USAGE_UNDEFINED; } - return adapterData->backend->queryFormatViewUsages(adapter, format); + return adapterData->backend->queryFormatImageViewUsages(adapter, format); } PalResult PAL_CALL palGetImageMemoryRequirements( @@ -3537,7 +3546,7 @@ PalResult PAL_CALL palGetImageMemoryRequirements( HandleData* deviceData = findHandleData(device); if (!deviceData) { - return PAL_RESULT_INVALID_GRAPHICS_BACKEND; + return PAL_RESULT_INVALID_BACKEND; } return deviceData->backend->getImageMemoryRequirements( @@ -3566,7 +3575,7 @@ PalResult PAL_CALL palAllocateMemory( HandleData* deviceData = findHandleData(device); if (!deviceData) { - return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + return PAL_RESULT_INVALID_DEVICE; } return deviceData->backend->allocate(device, type, size, outMemory); @@ -3600,7 +3609,7 @@ PalResult PAL_CALL palBindImageMemory( HandleData* deviceData = findHandleData(device); if (!deviceData) { - return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + return PAL_RESULT_INVALID_DEVICE; } return deviceData->backend->bindImageMemory( @@ -3626,7 +3635,7 @@ PalResult PAL_CALL palCreateImageView( HandleData* data = findHandleData(device); if (!data) { - return PAL_RESULT_INVALID_GRAPHICS_DEVICE; + return PAL_RESULT_INVALID_DEVICE; } PalImageView* imageView = nullptr; diff --git a/src/pal_core.c b/src/pal_core.c index 81563705..3a080de2 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -387,8 +387,8 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_ADAPTER: return "Invalid adapter"; - case PAL_RESULT_INVALID_GRAPHICS_BACKEND: - return "Invalid graphics backend"; + case PAL_RESULT_INVALID_BACKEND: + return "Invalid backend"; case PAL_RESULT_QUEUE_NOT_SUPPORTED: return "Queue not supported"; @@ -396,11 +396,11 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED: return "Unsupported adapter feature"; - case PAL_RESULT_INVALID_GRAPHICS_DRIVER: - return "Incompatible graphics driver"; + case PAL_RESULT_INVALID_DRIVER: + return "Incompatible driver"; - case PAL_RESULT_INVALID_GRAPHICS_DEVICE: - return "Invalid graphics device"; + case PAL_RESULT_INVALID_DEVICE: + return "Invalid device"; case PAL_RESULT_INVALID_QUEUE: return "Invalid queue"; @@ -414,14 +414,14 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_SWAPCHAIN: return "Invalid swapchain"; - case PAL_RESULT_INVALID_GRAPHICS_IMAGE: - return "Invalid graphics image"; + case PAL_RESULT_INVALID_IMAGE: + return "Invalid image"; case PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED: return "memory type not supported"; - case PAL_RESULT_INVALID_GRAPHICS_OPERATION: - return "Invalid graphics operation"; + case PAL_RESULT_INVALID_OPERATION: + return "Invalid operation"; } return "Unknown"; } From e247159f6120867c4e601effd1488552532d9b51 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 5 Dec 2025 14:56:03 +0000 Subject: [PATCH 034/372] make graphics system platform independent --- include/pal/pal_graphics.h | 88 +- pal.lua | 41 +- src/graphics/pal_graphics.c | 1100 +++++++++++ .../{pal_graphics_linux.c => pal_vulkan.c} | 1630 ++++------------- src/video/pal_video_linux.c | 4 + 5 files changed, 1552 insertions(+), 1311 deletions(-) create mode 100644 src/graphics/pal_graphics.c rename src/graphics/{pal_graphics_linux.c => pal_vulkan.c} (71%) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 6d9b85da..5b531357 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -391,6 +391,16 @@ typedef struct { void PAL_CALL (*destroyDevice)(PalDevice* device); + PalResult PAL_CALL (*allocateMemory)( + PalDevice* device, + PalMemoryType type, + Uint64 size, + PalMemory** outMemory); + + void PAL_CALL (*freeMemory)( + PalDevice* device, + PalMemory* memory); + PalResult PAL_CALL (*createQueue)( PalDevice* device, PalQueueType type, @@ -402,17 +412,6 @@ typedef struct { PalQueue* queue, PalGfxWindow* window); - PalResult PAL_CALL (*createImage)( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage); - - void PAL_CALL (*destroyImage)(PalImage* image); - - PalResult PAL_CALL (*getImageInfo)( - PalImage* image, - PalImageInfo* info); - PalResult PAL_CALL (*enumerateFormats)( PalAdapter* adapter, Int32* count, @@ -430,20 +429,21 @@ typedef struct { PalAdapter* adapter, PalFormat format); - PalResult PAL_CALL (*getImageMemoryRequirements)( + PalResult PAL_CALL (*createImage)( PalDevice* device, - PalImage* image, - PalMemoryRequirements* requirments); + const PalImageCreateInfo* info, + PalImage** outImage); - PalResult PAL_CALL (*allocate)( - PalDevice* device, - PalMemoryType type, - Uint64 size, - PalMemory** outMemory); + void PAL_CALL (*destroyImage)(PalImage* image); - void PAL_CALL (*free)( + PalResult PAL_CALL (*getImageInfo)( + PalImage* image, + PalImageInfo* info); + + PalResult PAL_CALL (*getImageMemoryRequirements)( PalDevice* device, - PalMemory* memory); + PalImage* image, + PalMemoryRequirements* requirments); PalResult PAL_CALL (*bindImageMemory)( PalDevice* device, @@ -480,6 +480,8 @@ typedef struct { Int32 index); } PalGfxBackend; +PAL_API PalResult PAL_CALL palAddGfxBackend(const PalGfxBackend* backend); + PAL_API PalResult PAL_CALL palInitGraphics( bool enableDebugLayer, const PalAllocator* allocator); @@ -498,8 +500,6 @@ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps); -PAL_API PalResult PAL_CALL palAddGfxBackend(const PalGfxBackend* backend); - PAL_API PalResult PAL_CALL palCreateDevice( PalAdapter* adapter, PalAdapterFeatures features, @@ -507,6 +507,16 @@ PAL_API PalResult PAL_CALL palCreateDevice( PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); +PAL_API PalResult PAL_CALL palAllocateMemory( + PalDevice* device, + PalMemoryType type, + Uint64 size, + PalMemory** outMemory); + +PAL_API void PAL_CALL palFreeMemory( + PalDevice* device, + PalMemory* memory); + PAL_API PalResult PAL_CALL palCreateQueue( PalDevice* device, PalQueueType type, @@ -518,17 +528,6 @@ PAL_API bool PAL_CALL palCanQueuePresent( PalQueue* queue, PalGfxWindow* window); -PAL_API PalResult PAL_CALL palCreateImage( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage); - -PAL_API void PAL_CALL palDestroyImage(PalImage* image); - -PAL_API PalResult PAL_CALL palGetImageInfo( - PalImage* image, - PalImageInfo* info); - PAL_API PalResult PAL_CALL palEnumerateFormats( PalAdapter* adapter, Int32* count, @@ -546,20 +545,21 @@ PAL_API PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( PalAdapter* adapter, PalFormat format); -PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( +PAL_API PalResult PAL_CALL palCreateImage( PalDevice* device, - PalImage* image, - PalMemoryRequirements* requirements); + const PalImageCreateInfo* info, + PalImage** outImage); -PAL_API PalResult PAL_CALL palAllocateMemory( - PalDevice* device, - PalMemoryType type, - Uint64 size, - PalMemory** outMemory); +PAL_API void PAL_CALL palDestroyImage(PalImage* image); -PAL_API void PAL_CALL palFreeMemory( +PAL_API PalResult PAL_CALL palGetImageInfo( + PalImage* image, + PalImageInfo* info); + +PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( PalDevice* device, - PalMemory* memory); + PalImage* image, + PalMemoryRequirements* requirements); PAL_API PalResult PAL_CALL palBindImageMemory( PalDevice* device, diff --git a/pal.lua b/pal.lua index f0a04297..8464567d 100644 --- a/pal.lua +++ b/pal.lua @@ -148,27 +148,34 @@ project "PAL" end if (PAL_BUILD_GRAPHICS) then - filter {"system:windows", "configurations:*"} - -- files { "src/graphics/pal_graphics_win32.c" } + -- check for vulkan support. This is cross compiler + vulkan_sdk = os.getenv("VULKAN_SDK") + hasVulkan = false + if (vulkan_sdk) then + hasVulkan = true + -- add to include path if compiler does not see it + includedirs { + path.join(vulkan_sdk, "include") + } - filter {"system:linux", "configurations:*"} - files { "src/graphics/pal_graphics_linux.c" } + libdirs { + path.join(vulkan_sdk, "Lib") + } - -- check for vulkan support. This is cross compiler - vulkan_sdk = os.getenv("VULKAN_SDK") - if (vulkan_sdk) then - -- add to include path if compiler does not see it - includedirs { - path.join(vulkan_sdk, "include") - } + defines { "PAL_HAS_VULKAN=1" } + else + defines { "PAL_HAS_VULKAN=0" } + end - libdirs { - path.join(vulkan_sdk, "Lib") - } + -- base graphics file + files { "src/graphics/pal_graphics.c" } - defines { "PAL_HAS_VULKAN=1" } - else - defines { "PAL_HAS_VULKAN=0" } + filter {"system:windows", "configurations:*"} + -- files { "src/graphics/pal_graphics_win32.c" } + + filter {"system:linux", "configurations:*"} + if (hasVulkan) then + files { "src/graphics/pal_vulkan.c" } end filter {} end diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c new file mode 100644 index 00000000..b502880f --- /dev/null +++ b/src/graphics/pal_graphics.c @@ -0,0 +1,1100 @@ + +/** + +Copyright (C) 2025 Nicholas Agbo + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + + */ + +// ================================================== +// Includes +// ================================================== + +#include "pal/pal_graphics.h" + +// ================================================== +// Typedefs, enums and structs +// ================================================== + +#define MAX_BACKENDS 32 +#define TO_PAL_HANDLE(type, value) ((type*)(UintPtr)(value)) +#define FROM_PAL_HANDLE(handle) ((Uint64)(UintPtr)(handle)) + +typedef struct { + bool used; + void* handle; + const PalGfxBackend* backend; +} HandleData; + +typedef struct { + Int32 count; + Int32 startIndex; + const PalGfxBackend* base; +} BackendData; + +typedef struct { + bool initialized; + Int32 backendCount; + Int32 maxHandleData; + const PalAllocator* allocator; + HandleData* handleData; + BackendData backends[MAX_BACKENDS]; +} GraphicsLinux; + +static GraphicsLinux s_Graphics = {0}; + +// ================================================== +// Internal API +// ================================================== + +static HandleData* getFreeHandleData(Uint64* outIndex) +{ + for (int i = 0; i < s_Graphics.maxHandleData; ++i) { + if (!s_Graphics.handleData[i].used) { + s_Graphics.handleData[i].used = true; + *outIndex = i + 1; + return &s_Graphics.handleData[i]; + } + } + + // resize the data array + HandleData* data = nullptr; + + + Uint32 newSize = s_Graphics.maxHandleData * 2; // double the size + int freeIndex = s_Graphics.maxHandleData + 1; + data = palAllocate(s_Graphics.allocator, sizeof(HandleData) * newSize, 0); + if (data) { + memset(data, 0, sizeof(HandleData) * newSize); + for (int i = 0; i < s_Graphics.maxHandleData; i++) { + // copy (shallow) old array into the new one + data[i] = s_Graphics.handleData[i]; + } + + palFree(s_Graphics.allocator, s_Graphics.handleData); + s_Graphics.handleData = data; + s_Graphics.maxHandleData = newSize; + + s_Graphics.handleData[freeIndex].used = true; + *outIndex = freeIndex; + return &s_Graphics.handleData[freeIndex]; + } + return nullptr; +} + +static HandleData* findHandleData(Uint64 index) +{ + if (index < 1 || index > s_Graphics.maxHandleData) { + return nullptr; + } + return &s_Graphics.handleData[index - 1]; +} + +// ================================================== +// Vulkan API +// ================================================== + +#if PAL_HAS_VULKAN + +PalResult PAL_CALL initGraphicsVk( + bool enableDebugLayer, + const PalAllocator* allocator); + +PalResult PAL_CALL shutdownGraphicsVk(); + +PalResult PAL_CALL enumerateVkAdapters( + Int32* count, + PalAdapter** outAdapters); + +PalResult PAL_CALL getVkAdapterInfo( + PalAdapter* adapter, + PalAdapterInfo* info); + +PalResult PAL_CALL getVkAdapterCapabilities( + PalAdapter* adapter, + PalAdapterCapabilities* caps); + +PalResult PAL_CALL createVkDevice( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); + +void PAL_CALL destroyVkDevice(PalDevice* device); + +PalResult PAL_CALL allocateVkMemory( + PalDevice* device, + PalMemoryType type, + Uint64 size, + PalMemory** outMemory); + +void PAL_CALL freeVkMemory( + PalDevice* device, + PalMemory* memory); + +PalResult PAL_CALL createVkQueue( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); + +void PAL_CALL destroyVkQueue(PalQueue* queue); + +bool PAL_CALL canVkQueuePresent( + PalQueue* queue, + PalGfxWindow* window); + +PalResult PAL_CALL enumerateVkFormats( + PalAdapter* adapter, + Int32* count, + PalFormatInfo* outFormats); + +bool PAL_CALL isVkFormatSupported( + PalAdapter* adapter, + PalFormat format); + +PalImageUsages PAL_CALL queryVkFormatImageUsages( + PalAdapter* adapter, + PalFormat format); + +PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( + PalAdapter* adapter, + PalFormat format); + +PalResult PAL_CALL createVkImage( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + +void PAL_CALL destroyVkImage(PalImage* image); + +PalResult PAL_CALL getVkImageInfo( + PalImage* image, + PalImageInfo* info); + +PalResult PAL_CALL getVkImageMemoryRequirements( + PalDevice* device, + PalImage* image, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL bindVkImageMemory( + PalDevice* device, + PalImage* image, + PalMemory* memory, + Uint64 offset); + +PalResult PAL_CALL createVkImageView( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + +void PAL_CALL destroyVkImageView(PalImageView* imageView); + +PalResult PAL_CALL queryVkSwapchainCapabilities( + PalAdapter* adapter, + PalGfxWindow* window, + PalSwapchainCapabilities* caps); + +PalResult PAL_CALL createVkSwapchain( + PalDevice* device, + PalQueue* queue, + PalGfxWindow* window, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + +void PAL_CALL destroyVkSwapchain(PalSwapchain* swapchain); + +Uint32 PAL_CALL getVkSwapchainImageCount(PalSwapchain* swapchain); + +PalImage* PAL_CALL getVkSwapchainImage( + PalSwapchain* swapchain, + Int32 index); + +static PalGfxBackend s_VkBackend = { + .enumerateAdapters = enumerateVkAdapters, + .getAdapterInfo = getVkAdapterInfo, + .getAdapterCapabilities = getVkAdapterCapabilities, + .createDevice = createVkDevice, + .destroyDevice = destroyVkDevice, + .allocateMemory = allocateVkMemory, + .freeMemory = freeVkMemory, + .createQueue = createVkQueue, + .destroyQueue = destroyVkQueue, + .canQueuePresent = canVkQueuePresent, + .enumerateFormats = enumerateVkFormats, + .isFormatSupported = isVkFormatSupported, + .queryFormatImageUsages = queryVkFormatImageUsages, + .queryFormatImageViewUsages = queryVkFormatImageViewUsages, + .createImage = createVkImage, + .destroyImage = destroyVkImage, + .getImageInfo = getVkImageInfo, + .getImageMemoryRequirements = getVkImageMemoryRequirements, + .bindImageMemory = bindVkImageMemory, + .createImageView = createVkImageView, + .destroyImageView = destroyVkImageView, + .querySwapchainCapabilities = queryVkSwapchainCapabilities, + .createSwapchain = createVkSwapchain, + .destroySwapchain = destroyVkSwapchain, + .getSwapchainImageCount = getVkSwapchainImageCount, + .getSwapchainImage = getVkSwapchainImage +}; + +#endif // PAL_HAS_VULKAN + +// ================================================== +// D3D12 API +// ================================================== + +// ================================================== +// Metal API +// ================================================== + +// ================================================== +// Public API +// ================================================== + +PalResult PAL_CALL palAddGfxBackend(const PalGfxBackend* backend) +{ + if (s_Graphics.initialized) { + return PAL_RESULT_INVALID_BACKEND; + } + +#ifdef _WIN32 + // we reserve two slots for vulkan and d3d12 + if (s_Graphics.backendCount == MAX_BACKENDS - 2) { + return PAL_RESULT_INVALID_BACKEND; + } +#else + // we reserve one slot for vulkan or metal depending on platform + if (s_Graphics.backendCount == MAX_BACKENDS - 1) { + return PAL_RESULT_INVALID_BACKEND; + } +#endif // _WIN32 + + // check if all the function pointers are set + // clang-format off + if (!backend->enumerateAdapters || + !backend->getAdapterInfo || + !backend->getAdapterCapabilities || + !backend->createDevice || + !backend->destroyDevice || + !backend->createQueue || + !backend->destroyQueue || + !backend->canQueuePresent || + !backend->createImage || + !backend->destroyImage || + !backend->getImageInfo || + !backend->enumerateFormats || + !backend->isFormatSupported || + !backend->queryFormatImageUsages || + !backend->queryFormatImageViewUsages || + !backend->getImageMemoryRequirements || + !backend->allocateMemory || + !backend->freeMemory || + !backend->bindImageMemory || + !backend->createImageView || + !backend->destroyImageView || + !backend->querySwapchainCapabilities || + !backend->createSwapchain || + !backend->destroySwapchain || + !backend->getSwapchainImageCount || + !backend->getSwapchainImage) { + return PAL_RESULT_INVALID_BACKEND; + } + // clang-format on + + BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; + attached->base = backend; + attached->startIndex = 0; + attached->count = 0; + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palInitGraphics( + bool enableDebugLayer, + const PalAllocator* allocator) +{ + if (s_Graphics.initialized) { + return PAL_RESULT_SUCCESS; + } + + if (allocator && (!allocator->allocate || !allocator->free)) { + return PAL_RESULT_INVALID_ALLOCATOR; + } + + s_Graphics.maxHandleData = 32; + s_Graphics.handleData = palAllocate( + s_Graphics.allocator, + sizeof(HandleData) * s_Graphics.maxHandleData, + 0); + + if (!s_Graphics.handleData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + +#ifdef _WIN32 + // vulkan and d3d12 +#elif defined(__linux__) + // vulkan +#if PAL_HAS_VULKAN + initGraphicsVk(enableDebugLayer, allocator); + BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; + attached->base = &s_VkBackend; + attached->startIndex = 0; + attached->count = 0; +#endif // PAL_HAS_VULKAN +#else + // metal or andriod +#endif // _WIN32 + + s_Graphics.allocator = allocator; + s_Graphics.initialized = true; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palShutdownGraphics() +{ + if (!s_Graphics.initialized) { + return; + } + +#ifdef _WIN32 +// vulkan and d3d12 +#elif defined(__linux__) + // vulkan + shutdownGraphicsVk(); +#else + // metal or andriod +#endif // _WIN32 + + palFree(s_Graphics.allocator, s_Graphics.handleData); + memset(&s_Graphics, 0, sizeof(s_Graphics)); + s_Graphics.initialized = false; +} + +// ================================================== +// Adapter +// ================================================== + +PalResult PAL_CALL palEnumerateAdapters( + Int32* count, + PalAdapter** outAdapters) +{ + // enumerate all adapters for both custom and PAL backends + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!count) { + return PAL_RESULT_NULL_POINTER; + } + + if (*count == 0 && outAdapters) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + + PalResult result; + int totalCount = 0; + int index = 0; + int _count = outAdapters ? *count : 0; + + for (int i = 0; i < s_Graphics.backendCount; i++) { + BackendData* backend = &s_Graphics.backends[i]; + if (outAdapters) { + // offset into the array so all backends write at the correct index + PalAdapter** adapters = &outAdapters[backend->startIndex]; + result = backend->base->enumerateAdapters(&_count, adapters); + + for (int i = 0; i < backend->count; i++) { + Uint64 adapterIndex = 0; + HandleData* data = getFreeHandleData(&adapterIndex); + data->backend = backend->base; + data->handle = adapters[i]; + + // reset the adapter handle into our index generated handle + PalAdapter* tmp = TO_PAL_HANDLE(PalAdapter, adapterIndex); + adapters[i] = tmp; + } + + } else { + result = backend->base->enumerateAdapters(&_count, nullptr); + backend->startIndex = totalCount; + backend->count = _count; + totalCount += _count; + _count = 0; + } + + // break if a backend fails + if (result != PAL_RESULT_SUCCESS) { + return result; + } + } + + if (!outAdapters) { + *count = totalCount; + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetAdapterInfo( + PalAdapter* adapter, + PalAdapterInfo* info) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!adapter || !info) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(adapter); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_ADAPTER; + } + return data->backend->getAdapterInfo(data->handle, info); +} + +PalResult PAL_CALL palGetAdapterCapabilities( + PalAdapter* adapter, + PalAdapterCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!adapter || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(adapter); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_ADAPTER; + } + return data->backend->getAdapterCapabilities(data->handle, caps); +} + +// ================================================== +// Device +// ================================================== + +PalResult PAL_CALL palCreateDevice( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!outDevice) { + return PAL_RESULT_NULL_POINTER; + } + + // check if the adapter is from PAL (custom or internal backend) + Uint64 index = FROM_PAL_HANDLE(adapter); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_ADAPTER; + } + + // create a slot for the created device + Uint64 deviceIndex = 0; + HandleData* deviceData = getFreeHandleData(&deviceIndex); + if (!deviceData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalDevice* device = nullptr; + PalResult ret; + ret = data->backend->createDevice(data->handle, features, &device); + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + deviceData->backend = data->backend; + deviceData->handle = device; + + *outDevice = TO_PAL_HANDLE(PalDevice, deviceIndex); + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyDevice(PalDevice* device) +{ + if (s_Graphics.initialized && device) { + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + if (data) { + data->backend->destroyDevice(data->handle); + data->used = false; + } + } +} + +PalResult PAL_CALL palAllocateMemory( + PalDevice* device, + PalMemoryType type, + Uint64 size, + PalMemory** outMemory) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!outMemory || !device) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* deviceData = findHandleData(index); + if (!deviceData) { + return PAL_RESULT_INVALID_DEVICE; + } + return deviceData->backend->allocateMemory( + deviceData->handle, + type, + size, + outMemory); +} + +void PAL_CALL palFreeMemory( + PalDevice* device, + PalMemory* memory) +{ + if (s_Graphics.initialized && device && memory) { + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + if (data) { + data->backend->freeMemory(data->handle, memory); + } + } +} + +// ================================================== +// Queue +// ================================================== + +PalResult PAL_CALL palCreateQueue( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !outQueue) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + // create a slot for the created queue + Uint64 queueIndex = 0; + HandleData* queueData = getFreeHandleData(&queueIndex); + if (!queueData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalQueue* queue = nullptr; + PalResult ret; + ret = data->backend->createQueue( + data->handle, + type, + &queue); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + queueData->backend = data->backend; + queueData->handle = queue; + + *outQueue = TO_PAL_HANDLE(PalQueue, queueIndex); + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyQueue(PalQueue* queue) +{ + if (s_Graphics.initialized && queue) { + Uint64 index = FROM_PAL_HANDLE(queue); + HandleData* data = findHandleData(index); + if (data) { + data->backend->destroyQueue(data->handle); + data->used = false; + } + } +} + +bool PAL_CALL palCanQueuePresent( + PalQueue* queue, + PalGfxWindow* window) +{ + if (s_Graphics.initialized && queue) { + Uint64 index = FROM_PAL_HANDLE(queue); + HandleData* data = findHandleData(index); + if (!data) { + return false; + } + return data->backend->canQueuePresent(data->handle, window); + } + return false; +} + +// ================================================== +// Format And Usages +// ================================================== + +PalResult PAL_CALL palEnumerateFormats( + PalAdapter* adapter, + Int32* count, + PalFormatInfo* outFormats) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!adapter || !count) { + return PAL_RESULT_NULL_POINTER; + } + + if (*count == 0 && outFormats) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + + Uint64 index = FROM_PAL_HANDLE(adapter); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_ADAPTER; + } + return data->backend->enumerateFormats(data->handle, count, outFormats); +} + +bool PAL_CALL palIsFormatSupported( + PalAdapter* adapter, + PalFormat format) +{ + if (!s_Graphics.initialized || !adapter) { + return false; + } + + Uint64 index = FROM_PAL_HANDLE(adapter); + HandleData* data = findHandleData(index); + if (!data) { + return false; + } + return data->backend->isFormatSupported(data->handle, format); +} + +PalImageUsages PAL_CALL palQueryFormatImageUsages( + PalAdapter* adapter, + PalFormat format) +{ + if (!s_Graphics.initialized || !adapter) { + return PAL_IMAGE_USAGE_UNDEFINED; + } + + Uint64 index = FROM_PAL_HANDLE(adapter); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_IMAGE_USAGE_UNDEFINED; + } + return data->backend->queryFormatImageUsages(data->handle, format); +} + +PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( + PalAdapter* adapter, + PalFormat format) +{ + if (!s_Graphics.initialized || !adapter) { + return PAL_IMAGE_VIEW_USAGE_UNDEFINED; + } + + Uint64 index = FROM_PAL_HANDLE(adapter); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_IMAGE_VIEW_USAGE_UNDEFINED; + } + return data->backend->queryFormatImageViewUsages(data->handle, format); +} + +// ================================================== +// Image +// ================================================== + +PalResult PAL_CALL palCreateImage( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device ||!info || !outImage) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + // create a slot for the created image + Uint64 imageIndex = 0; + HandleData* imageData = getFreeHandleData(&imageIndex); + if (!imageData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalImage* image = nullptr; + PalResult ret; + ret = data->backend->createImage( + data->handle, + info, + &image); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + imageData->backend = data->backend; + imageData->handle = image; + + *outImage = TO_PAL_HANDLE(PalImage, imageIndex); + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyImage(PalImage* image) +{ + if (s_Graphics.initialized && image) { + Uint64 index = FROM_PAL_HANDLE(image); + HandleData* data = findHandleData(index); + if (data) { + data->backend->destroyImage(data->handle); + data->used = false; + } + } +} + +PalResult PAL_CALL palGetImageInfo( + PalImage* image, + PalImageInfo* info) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!image || !info) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(image); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_IMAGE; + } + return data->backend->getImageInfo(data->handle, info); +} + +PalResult PAL_CALL palGetImageMemoryRequirements( + PalDevice* device, + PalImage* image, + PalMemoryRequirements* requirements) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !image) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + + index = FROM_PAL_HANDLE(image); + HandleData* imageData = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + if (!imageData) { + return PAL_RESULT_INVALID_IMAGE; + } + + return data->backend->getImageMemoryRequirements( + data->handle, + imageData->handle, + requirements); +} + +PalResult PAL_CALL palBindImageMemory( + PalDevice* device, + PalImage* image, + PalMemory* memory, + Uint64 offset) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !image || !memory) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + + index = FROM_PAL_HANDLE(image); + HandleData* imageData = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + if (!imageData) { + return PAL_RESULT_INVALID_IMAGE; + } + + return data->backend->bindImageMemory( + data->handle, + imageData->handle, + memory, + offset); +} + +// ================================================== +// Image View +// ================================================== + +PalResult PAL_CALL palCreateImageView( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device ||!image || !info || !outImageView) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + + index = FROM_PAL_HANDLE(image); + HandleData* imageData = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + if (!imageData) { + return PAL_RESULT_INVALID_IMAGE; + } + + // create a slot for the created image view + Uint64 imageViewIndex = 0; + HandleData* imageViewData = getFreeHandleData(&imageViewIndex); + if (!imageViewData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalImageView* imageView = nullptr; + PalResult ret; + ret = data->backend->createImageView( + data->handle, + imageData->handle, + info, + &imageView); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + imageViewData->backend = data->backend; + imageViewData->handle = imageView; + + *outImageView = TO_PAL_HANDLE(PalImageView, imageViewIndex); + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyImageView(PalImageView* imageView) +{ + if (s_Graphics.initialized && imageView) { + Uint64 index = FROM_PAL_HANDLE(imageView); + HandleData* data = findHandleData(index); + if (data) { + data->backend->destroyImageView(data->handle); + data->used = false; + } + } +} + +// ================================================== +// Swapchain +// ================================================== + +PalResult PAL_CALL palQuerySwapchainCapabilities( + PalAdapter* adapter, + PalGfxWindow* window, + PalSwapchainCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!adapter || !window || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(adapter); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_ADAPTER; + } + + return data->backend->querySwapchainCapabilities( + data->handle, + window, + caps); +} + +PalResult PAL_CALL palCreateSwapchain( + PalDevice* device, + PalQueue* queue, + PalGfxWindow* window, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !queue || !window || !info || !outSwapchain) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + + index = FROM_PAL_HANDLE(queue); + HandleData* queueData = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + if (!queueData) { + return PAL_RESULT_INVALID_QUEUE; + } + + // create a slot for the created swapchain + Uint64 swapchainIndex = 0; + HandleData* swapchainData = getFreeHandleData(&swapchainIndex); + if (!swapchainData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalResult ret; + PalSwapchain* swapchain = nullptr; + ret = data->backend->createSwapchain( + data->handle, + queueData->handle, + window, + info, + &swapchain); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + swapchainData->backend = data->backend; + swapchainData->handle = swapchain; + + *outSwapchain = TO_PAL_HANDLE(PalSwapchain, swapchainIndex); + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) +{ + if (s_Graphics.initialized && swapchain) { + Uint64 index = FROM_PAL_HANDLE(swapchain); + HandleData* data = findHandleData(index); + if (data) { + data->backend->destroySwapchain(data->handle); + data->used = false; + } + } +} + +Uint32 PAL_CALL palGetSwapchainImageCount(PalSwapchain* swapchain) +{ + if (!s_Graphics.initialized || !swapchain) { + return 0; + } + + Uint64 index = FROM_PAL_HANDLE(swapchain); + HandleData* data = findHandleData(index); + if (!data) { + return 0; + } + return data->backend->getSwapchainImageCount(data->handle); +} + +PalImage* PAL_CALL palGetSwapchainImage( + PalSwapchain* swapchain, + Int32 index) +{ + if (!s_Graphics.initialized || !swapchain || index < 0) { + return nullptr; + } + + Uint64 swapchainIndex = FROM_PAL_HANDLE(swapchain); + HandleData* data = findHandleData(swapchainIndex); + if (!data) { + return nullptr; + } + + PalImage* image = data->backend->getSwapchainImage( + data->handle, + index); + + // check if the user has already requested for the image + Uint64 imageIndex = FROM_PAL_HANDLE(image); + HandleData* imageData = findHandleData(imageIndex); + if (!imageData) { + // create a new slot + imageData = getFreeHandleData(&imageIndex); + if (!imageData) { + return nullptr; + } + } + + imageData->backend = data->backend; + imageData->handle = image; + + return TO_PAL_HANDLE(PalImage, imageIndex); +} \ No newline at end of file diff --git a/src/graphics/pal_graphics_linux.c b/src/graphics/pal_vulkan.c similarity index 71% rename from src/graphics/pal_graphics_linux.c rename to src/graphics/pal_vulkan.c index a8262387..8e7a4259 100644 --- a/src/graphics/pal_graphics_linux.c +++ b/src/graphics/pal_vulkan.c @@ -34,7 +34,11 @@ freely, subject to the following restrictions: #include #include -// HACK: Needed to determine display type +// HACK: Needed to determine display type if on linux +#ifdef _WIN32 +#define VK_LIB_NAME "" + +#elif defined(__linux__) struct wl_display; struct wl_surface; typedef struct _XDisplay Display; @@ -44,26 +48,33 @@ typedef int (*wl_display_get_fd_fn)(struct wl_display*); #include #include +#define VK_LIB_NAME "libvulkan.so" + +#else +// Android +#define VK_LIB_NAME "" -#endif // PAL_HAS_VULKAN +#endif // _WIN32 // ================================================== // Typedefs, enums and structs // ================================================== -#define MAX_BACKENDS 32 - -#if PAL_HAS_VULKAN +#define VK_WIN32_PLATFORM 1 +#define VK_XLIB_PLATFORM 2 +#define VK_WAYLAND_PLATFORM 3 typedef struct { bool hasDebug; bool hasDynamicRendering; void* handle; VkInstance instance; - + +#ifdef __linux__ // HACK: for display testing void* libWayland; wl_display_get_fd_fn getDisplayFd; +#endif // __linux__ PFN_vkEnumerateInstanceVersion enumerateInstanceVersion; PFN_vkEnumerateInstanceExtensionProperties enumerateInstanceExtensionProperties; @@ -105,7 +116,8 @@ typedef struct { PFN_vkGetPhysicalDeviceSurfaceFormatsKHR getSurfaceFormats; PFN_vkGetPhysicalDeviceSurfacePresentModesKHR getSurfacePresentModes; - VkAllocationCallbacks allocator; + VkAllocationCallbacks vkAllocator; + const PalAllocator* allocator; } Vulkan; typedef struct { @@ -116,7 +128,7 @@ typedef struct { VkQueueFlags usedUsages; } PhysicalQueue; -typedef struct { +struct PalDevice { Int32 queueCount; VkPhysicalDevice phyDevice; VkDevice handle; @@ -127,130 +139,69 @@ typedef struct { PFN_vkAcquireNextImageKHR acquireNextImage; PFN_vkQueuePresentKHR queuePresent; Int32 memoryTypeIndex[PAL_MEMORY_TYPE_MAX]; -} Device; +}; -typedef struct { +struct PalQueue { VkQueueFlags usage; - Device* device; + PalDevice* device; PhysicalQueue* phyQueue; -} Queue; +}; -typedef struct { +struct PalImage { bool belongsToSwapchain; - Device* device; + PalDevice* device; VkImage handle; PalImageInfo info; -} Image; +}; -typedef struct { +struct PalImageView { VkImageViewType type; PalImageViewUsages usages; - Device* device; - Image* image; + PalDevice* device; + PalImage* image; VkImageView handle; -} ImageView; +}; -typedef struct { +struct PalSwapchain { Uint32 imageCount; - Device* device; + PalDevice* device; VkSurfaceKHR surface; VkSwapchainKHR handle; - Image* images; -} Swapchain; + PalImage* images; +}; static Vulkan s_Vk = {0}; -#endif // PAL_HAS_VULKAN - -typedef struct { - bool used; - void* handle; - const PalGfxBackend* backend; -} HandleData; - -typedef struct { - Int32 count; - Int32 startIndex; - const PalGfxBackend* base; -} BackendData; - -typedef struct { - bool initialized; - Int32 backendCount; - Int32 maxHandleData; - const PalAllocator* allocator; - HandleData* handleData; - BackendData backends[MAX_BACKENDS]; -} GraphicsLinux; - -static GraphicsLinux s_Graphics = {0}; - // ================================================== -// Internal API +// API // ================================================== -// FIXME: might be replaced with hashmap for performance -static HandleData* getFreeHandleData() -{ - for (int i = 0; i < s_Graphics.maxHandleData; ++i) { - if (!s_Graphics.handleData[i].used) { - s_Graphics.handleData[i].used = true; - return &s_Graphics.handleData[i]; - } - } - - // resize the data array - HandleData* data = nullptr; - int count = s_Graphics.maxHandleData * 2; // double the size - int freeIndex = s_Graphics.maxHandleData + 1; - data = palAllocate(s_Graphics.allocator, sizeof(HandleData) * count, 0); - if (data) { - memcpy( - data, - s_Graphics.handleData, - s_Graphics.maxHandleData * sizeof(HandleData)); - - palFree(s_Graphics.allocator, s_Graphics.handleData); - s_Graphics.handleData = data; - s_Graphics.maxHandleData = count; - - s_Graphics.handleData[freeIndex].used = true; - return &s_Graphics.handleData[freeIndex]; - } - return nullptr; -} - -static HandleData* findHandleData(void* handle) -{ - for (int i = 0; i < s_Graphics.maxHandleData; ++i) { - if (s_Graphics.handleData[i].used && - s_Graphics.handleData[i].handle == handle) { - return &s_Graphics.handleData[i]; - } - } - return nullptr; -} - -#if PAL_HAS_VULKAN - -static bool vkOnWayland(struct wl_display* display) +static Uint32 checkPlatform(struct wl_display* display) { +#ifdef _WIN32 +#elif defined(__linux__) if (!s_Vk.libWayland) { - return false; + return VK_XLIB_PLATFORM; } int fd = s_Vk.getDisplayFd(display); if (fd <= 0 || fd > 1024) { // fds are usaually 0-30 but this is fine - return false; + return VK_XLIB_PLATFORM; } - return true; + return VK_WAYLAND_PLATFORM; +#else + // Android +#endif // _WIN32 } -static bool vkCreateSurface( +static bool createSurface( PalGfxWindow* window, VkSurfaceKHR* outSurface) { - if (vkOnWayland(window->display)) { + Uint32 platform = checkPlatform(window->display); + if (platform == VK_WIN32_PLATFORM) { + + } else if (platform == VK_WAYLAND_PLATFORM) { if (!s_Vk.createWaylandSurface) { return false; } @@ -266,18 +217,19 @@ static bool vkCreateSurface( VkResult result = s_Vk.createWaylandSurface( s_Vk.instance, &createInfo, - &s_Vk.allocator, + &s_Vk.vkAllocator, &surface); if (result != VK_SUCCESS) { return false; } - *outSurface = surface; - } else { - // TODO: create surface for xlib + *outSurface = surface; + return true; + + } else if (platform == VK_XLIB_PLATFORM) { + } - return true; } static PalResult vkResultToPal(VkResult result) @@ -969,14 +921,14 @@ static void* vkAlloc( size_t alignment, VkSystemAllocationScope allocationScope) { - return palAllocate(s_Graphics.allocator, size, alignment); + return palAllocate(s_Vk.allocator, size, alignment); } static void vkFree( void* pUserData, void* ptr) { - palFree(s_Graphics.allocator, ptr); + palFree(s_Vk.allocator, ptr); } static void* vkRealloc( @@ -991,7 +943,7 @@ static void* vkRealloc( // this is because we dont know the old size void* block = realloc(pOriginal, size); if (block) { - void* memory = palAllocate(s_Graphics.allocator, size, alignment); + void* memory = palAllocate(s_Vk.allocator, size, alignment); if (!memory) { free(block); return nullptr; @@ -1004,7 +956,9 @@ static void* vkRealloc( return nullptr; } -static PalResult vkInitGraphics(bool enableDebugLayer) +PalResult PAL_CALL initGraphicsVk( + bool enableDebugLayer, + const PalAllocator* allocator) { s_Vk.libWayland = nullptr; s_Vk.libWayland = dlopen("libwayland-client.so.0", RTLD_LAZY); @@ -1015,7 +969,7 @@ static PalResult vkInitGraphics(bool enableDebugLayer) } // load vulkan - s_Vk.handle = dlopen("libvulkan.so", RTLD_LAZY); + s_Vk.handle = dlopen(VK_LIB_NAME, RTLD_LAZY); if (!s_Vk.handle) { return PAL_RESULT_PLATFORM_FAILURE; } @@ -1161,7 +1115,7 @@ static PalResult vkInitGraphics(bool enableDebugLayer) VkLayerProperties* props = nullptr; props = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(VkLayerProperties) * layerCount, 0); @@ -1178,7 +1132,7 @@ static PalResult vkInitGraphics(bool enableDebugLayer) } } - palFree(s_Graphics.allocator, props); + palFree(s_Vk.allocator, props); } // extensions @@ -1195,7 +1149,7 @@ static PalResult vkInitGraphics(bool enableDebugLayer) VkExtensionProperties* extensionProps = nullptr; extensionProps = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(VkExtensionProperties) * extCount, 0); @@ -1229,7 +1183,7 @@ static PalResult vkInitGraphics(bool enableDebugLayer) } } - palFree(s_Graphics.allocator, extensionProps); + palFree(s_Vk.allocator, extensionProps); int extensionCount = 0; if (hasSurface) { @@ -1274,14 +1228,14 @@ static PalResult vkInitGraphics(bool enableDebugLayer) instanceCreateInfo.ppEnabledLayerNames = layers; // vk allocator - s_Vk.allocator.pfnAllocation = vkAlloc; - s_Vk.allocator.pfnFree = vkFree; - s_Vk.allocator.pfnReallocation = vkRealloc; + s_Vk.vkAllocator.pfnAllocation = vkAlloc; + s_Vk.vkAllocator.pfnFree = vkFree; + s_Vk.vkAllocator.pfnReallocation = vkRealloc; VkInstance instance = nullptr; VkResult result = s_Vk.createInstance( &instanceCreateInfo, - &s_Vk.allocator, + &s_Vk.vkAllocator, &instance); if (result != VK_SUCCESS) { @@ -1348,9 +1302,9 @@ static PalResult vkInitGraphics(bool enableDebugLayer) return PAL_RESULT_SUCCESS; } -static void vkShutdownGraphics() +PalResult PAL_CALL shutdownGraphicsVk() { - s_Vk.destroyInstance(s_Vk.instance, &s_Vk.allocator); + s_Vk.destroyInstance(s_Vk.instance, &s_Vk.vkAllocator); dlclose(s_Vk.handle); if (s_Vk.libWayland) { dlclose(s_Vk.libWayland); @@ -1358,8 +1312,8 @@ static void vkShutdownGraphics() memset(&s_Vk, 0, sizeof(s_Vk)); } -static PalResult _vkEnumerateAdapters( - Int32* count, +PalResult PAL_CALL enumerateVkAdapters( + Int32* count, PalAdapter** outAdapters) { int _count = 0; @@ -1374,7 +1328,7 @@ static PalResult _vkEnumerateAdapters( // PAL only supports supports dynamic rendering VkPhysicalDevice* devices = nullptr; - devices = palAllocate(s_Graphics.allocator, + devices = palAllocate(s_Vk.allocator, sizeof(VkPhysicalDevice) * _count, 0); @@ -1413,7 +1367,7 @@ static PalResult _vkEnumerateAdapters( } exts = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(VkExtensionProperties) * extCount, 0); @@ -1435,7 +1389,7 @@ static PalResult _vkEnumerateAdapters( } } - palFree(s_Graphics.allocator, exts); + palFree(s_Vk.allocator, exts); if (!found) { // skip continue; @@ -1457,11 +1411,11 @@ static PalResult _vkEnumerateAdapters( *count = deviceCount; } - palFree(s_Graphics.allocator, devices); + palFree(s_Vk.allocator, devices); return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL _vkGetAdapterInfo( +PalResult PAL_CALL getVkAdapterInfo( PalAdapter* adapter, PalAdapterInfo* info) { @@ -1529,7 +1483,7 @@ static PalResult PAL_CALL _vkGetAdapterInfo( return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL _vkGetAdapterCapabilities( +PalResult PAL_CALL getVkAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps) { @@ -1592,7 +1546,7 @@ static PalResult PAL_CALL _vkGetAdapterCapabilities( VkQueueFamilyProperties* queueProps = nullptr; queueProps = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(VkQueueFamilyProperties) * count, 0); @@ -1619,7 +1573,7 @@ static PalResult PAL_CALL _vkGetAdapterCapabilities( } } - palFree(s_Graphics.allocator, queueProps); + palFree(s_Vk.allocator, queueProps); // get supported extensions Uint32 extensionCount = 0; @@ -1636,7 +1590,7 @@ static PalResult PAL_CALL _vkGetAdapterCapabilities( VkExtensionProperties* extensionProps = nullptr; extensionProps = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(VkExtensionProperties) * extensionCount, 0); @@ -1852,19 +1806,19 @@ static PalResult PAL_CALL _vkGetAdapterCapabilities( // this features are supported on vulkan caps->features |= PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW; - palFree(s_Graphics.allocator, extensionProps); + palFree(s_Vk.allocator, extensionProps); return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL _vkCreateDevice( +PalResult PAL_CALL createVkDevice( PalAdapter* adapter, PalAdapterFeatures features, PalDevice** outDevice) -{ +{ float priority = 1.0f; Uint32 count = 0; VkResult ret = VK_SUCCESS; - Device* device = nullptr; + PalDevice* device = nullptr; VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; VkQueueFamilyProperties* queueProps = nullptr; @@ -1875,16 +1829,16 @@ static PalResult PAL_CALL _vkCreateDevice( nullptr); queueProps = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(VkQueueFamilyProperties) * count, 0); queueCreateInfos = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(VkDeviceQueueCreateInfo) * count, 0); - device = palAllocate(s_Graphics.allocator, sizeof(Device), 0); + device = palAllocate(s_Vk.allocator, sizeof(PalDevice), 0); if (!queueProps || !queueCreateInfos || !device) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -1893,7 +1847,7 @@ static PalResult PAL_CALL _vkCreateDevice( device->phyDevice = phyDevice; device->phyQueues = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(PhysicalQueue) * count, 0); @@ -2114,14 +2068,14 @@ static PalResult PAL_CALL _vkCreateDevice( ret = s_Vk.createDevice( phyDevice, &createInfo, - &s_Vk.allocator, + &s_Vk.vkAllocator, &device->handle); if (ret != VK_SUCCESS) { - palFree(s_Graphics.allocator, queueProps); - palFree(s_Graphics.allocator, queueCreateInfos); - palFree(s_Graphics.allocator, device->phyQueues); - palFree(s_Graphics.allocator, device); + palFree(s_Vk.allocator, queueProps); + palFree(s_Vk.allocator, queueCreateInfos); + palFree(s_Vk.allocator, device->phyQueues); + palFree(s_Vk.allocator, device); return vkResultToPal(ret); } @@ -2184,34 +2138,71 @@ static PalResult PAL_CALL _vkCreateDevice( device->handle, "vkQueuePresentKHR"); - palFree(s_Graphics.allocator, queueProps); - palFree(s_Graphics.allocator, queueCreateInfos); + palFree(s_Vk.allocator, queueProps); + palFree(s_Vk.allocator, queueCreateInfos); + + *outDevice = device; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkDevice(PalDevice* device) +{ + s_Vk.destroyDevice(device->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, device->phyQueues); + palFree(s_Vk.allocator, device); +} + +PalResult PAL_CALL allocateVkMemory( + PalDevice* device, + PalMemoryType type, + Uint64 size, + PalMemory** outMemory) +{ + VkMemoryAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = (VkDeviceSize)size; + allocateInfo.memoryTypeIndex = device->memoryTypeIndex[type]; + + if (allocateInfo.memoryTypeIndex == -1) { + // not supported + return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; + } + + VkDeviceMemory memory = nullptr; + VkResult result = s_Vk.allocateMemory( + device->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &memory); + + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } - *outDevice = (PalDevice*)device; + *outMemory = (PalMemory*)memory; return PAL_RESULT_SUCCESS; } -static void PAL_CALL _vkDestroyDevice(PalDevice* device) +void PAL_CALL freeVkMemory( + PalDevice* device, + PalMemory* memory) { - Device* _device = (Device*)device; - s_Vk.destroyDevice(_device->handle, &s_Vk.allocator); - palFree(s_Graphics.allocator, _device->phyQueues); - palFree(s_Graphics.allocator, _device); + VkDeviceMemory mem = (VkDeviceMemory)memory; + s_Vk.freeMemory(device->handle, mem, &s_Vk.vkAllocator); } -static PalResult PAL_CALL _vkCreateQueue( +PalResult PAL_CALL createVkQueue( PalDevice* device, PalQueueType type, PalQueue** outQueue) { VkQueueFlags queueFlag = 0; - Device* _device = (Device*)device; - Queue* queue = nullptr; - if (!_device->handle) { + PalQueue* queue = nullptr; + if (!device->handle) { return PAL_RESULT_INVALID_DEVICE; } - if (_device->queueCount == 0) { + if (device->queueCount == 0) { return PAL_RESULT_OUT_OF_QUEUE; } @@ -2233,157 +2224,70 @@ static PalResult PAL_CALL _vkCreateQueue( } PhysicalQueue* phyQueue = nullptr; - for (int i = 0; i < _device->queueCount; i++) { - PhysicalQueue* queue = &_device->phyQueues[i]; + for (int i = 0; i < device->queueCount; i++) { + PhysicalQueue* pq = &device->phyQueues[i]; // check if the physical queue supports the requested operation // and if its not already used - if (queue->usages & queueFlag && - queue->usedUsages != queueFlag) { - queue->usedUsages |= queueFlag; - phyQueue = queue; + if (pq->usages & queueFlag && + pq->usedUsages != queueFlag) { + pq->usedUsages |= queueFlag; + phyQueue = pq; break; } } - if (phyQueue) { - queue = palAllocate( - s_Graphics.allocator, - sizeof(Queue), - 0); - - if (!queue) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - queue->phyQueue = phyQueue; - queue->usage = queueFlag; - queue->device = _device; + if (!phyQueue) { + return PAL_RESULT_OUT_OF_QUEUE; + } - *outQueue = (PalQueue*)queue; - return PAL_RESULT_SUCCESS; + queue = palAllocate(s_Vk.allocator, sizeof(PalQueue), 0); + if (!queue) { + return PAL_RESULT_OUT_OF_MEMORY; } - return PAL_RESULT_OUT_OF_QUEUE; + queue->phyQueue = phyQueue; + queue->usage = queueFlag; + queue->device = device; + + *outQueue = queue; + return PAL_RESULT_SUCCESS; } -static void PAL_CALL _vkDestroyQueue(PalQueue* queue) +void PAL_CALL destroyVkQueue(PalQueue* queue) { - Queue* _queue = (Queue*)queue; - PhysicalQueue* phyQueue = _queue->phyQueue; - phyQueue->usedUsages &= ~_queue->usage; - palFree(s_Graphics.allocator, _queue); + PhysicalQueue* phyQueue = queue->phyQueue; + phyQueue->usedUsages &= ~queue->usage; + palFree(s_Vk.allocator, queue); } -static bool PAL_CALL _vkCanQueuePresent( +bool PAL_CALL canVkQueuePresent( PalQueue* queue, PalGfxWindow* window) { // check if the queue is a graphics queue before we check its family // index for presentation support. - Queue* _queue = (Queue*)queue; - if (_queue->usage != VK_QUEUE_GRAPHICS_BIT) { - return false; - } - - bool onWayland = vkOnWayland(window->display); - PhysicalQueue* phyQueue = _queue->phyQueue; - if (!s_Vk.checkWaylandPresentSupport( - phyQueue->phyDevice, - phyQueue->familyIndex, window->display)) { + if (queue->usage != VK_QUEUE_GRAPHICS_BIT) { return false; - } else { - // TODO: check presentation for xlib - } - - return true; -} - -static PalResult PAL_CALL _vkCreateImage( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage) -{ - VkResult result; - Image* image = nullptr; - Device* _device = (Device*)device; - if (!_device->handle) { - return PAL_RESULT_INVALID_DEVICE; - } - - image = palAllocate(s_Graphics.allocator, sizeof(Image), 0); - if (!image) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkImageCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - createInfo.extent.width = info->width; - createInfo.extent.height = info->height; - createInfo.mipLevels = info->mipLevelCount; - - createInfo.format = palFormatToVk(info->format); - createInfo.samples = samplesToVk(info->samples); - createInfo.usage = palUsageToVk(info->usages); - - createInfo.arrayLayers = info->depthOrArraySize; - createInfo.extent.depth = 1; - createInfo.imageType = palImageTypeToVk(info->type); - - if (info->type == PAL_IMAGE_TYPE_3D) { - createInfo.arrayLayers = 1; - createInfo.extent.depth = info->depthOrArraySize; - } - - result = s_Vk.createImage( - _device->handle, - &createInfo, - &s_Vk.allocator, - &image->handle); - - if (result != VK_SUCCESS) { - palFree(s_Graphics.allocator, image); - return vkResultToPal(result); } - image->belongsToSwapchain = false; - image->device = _device; - image->info.depthOrArraySize = info->depthOrArraySize; - image->info.type = info->type; - image->info.format = info->format; - image->info.usages = info->usages; - image->info.height = info->height; - image->info.mipLevelCount = info->mipLevelCount; - image->info.samples = info->samples; - image->info.width = info->width; + Uint32 platform = checkPlatform(window->display); + PhysicalQueue* phyQueue = queue->phyQueue; + if (platform == VK_WIN32_PLATFORM) { - *outImage = (PalImage*)image; - return PAL_RESULT_SUCCESS; -} + } else if (platform == VK_WAYLAND_PLATFORM) { + if (s_Vk.checkWaylandPresentSupport( + phyQueue->phyDevice, + phyQueue->familyIndex, window->display)) { + return true; + } -static void PAL_CALL _vkDestroyImage(PalImage* image) -{ - Image* _image = (Image*)image; - if (_image->belongsToSwapchain) { - return; + } else if (platform == VK_XLIB_PLATFORM) { + } - - s_Vk.destroyImage(_image->device->handle, _image->handle, &s_Vk.allocator); - palFree(s_Graphics.allocator, _image); -} - -static PalResult PAL_CALL _vkGetImageInfo( - PalImage* image, - PalImageInfo* info) -{ - Image* _image = (Image*)image; - *info = _image->info; - return PAL_RESULT_SUCCESS; + return false; } -static PalResult PAL_CALL _vkEnumerateFormats( +PalResult PAL_CALL enumerateVkFormats( PalAdapter* adapter, Int32* count, PalFormatInfo* outFormats) @@ -2432,15 +2336,13 @@ static PalResult PAL_CALL _vkEnumerateFormats( } } } - if (!outFormats) { *count = fmtCount; } - return PAL_RESULT_SUCCESS; } -static bool PAL_CALL _vkIsFormatSupported( +bool PAL_CALL isVkFormatSupported( PalAdapter* adapter, PalFormat format) { @@ -2452,11 +2354,10 @@ static bool PAL_CALL _vkIsFormatSupported( if (props.optimalTilingFeatures != 0) { return true; } - return false; } -static PalImageUsages PAL_CALL _vkQueryFormatImageUsages( +PalImageUsages PAL_CALL queryVkFormatImageUsages( PalAdapter* adapter, PalFormat format) { @@ -2465,14 +2366,13 @@ static PalImageUsages PAL_CALL _vkQueryFormatImageUsages( VkFormat fmt = palFormatToVk(format); s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); - if (props.optimalTilingFeatures != 0) { - return vkFeatureToPalUsage(props.optimalTilingFeatures); + if (props.optimalTilingFeatures == 0) { + return PAL_IMAGE_USAGE_UNDEFINED; } - - return PAL_IMAGE_USAGE_UNDEFINED; + return vkFeatureToPalUsage(props.optimalTilingFeatures); } -static PalImageViewUsages PAL_CALL _vkQueryFormatImageViewUsages( +PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( PalAdapter* adapter, PalFormat format) { @@ -2481,158 +2381,187 @@ static PalImageViewUsages PAL_CALL _vkQueryFormatImageViewUsages( VkFormat fmt = palFormatToVk(format); s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); - if (props.optimalTilingFeatures != 0) { - // format supported. check if we have any depth or stencil component - // Note: this is a hack - PalImageViewUsages usages = 0; - if (format == PAL_FORMAT_S8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - } - - if (format == PAL_FORMAT_D16_UNORM || format == PAL_FORMAT_D32_SFLOAT) { - usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - } + if (props.optimalTilingFeatures == 0) { + return PAL_IMAGE_VIEW_USAGE_UNDEFINED; + } - if (format == PAL_FORMAT_D32_SFLOAT_S8_UINT || - format == PAL_FORMAT_D16_UNORM_S8_UINT || - format == PAL_FORMAT_D24_UNORM_S8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - } - - if (usages == 0) { - usages = PAL_IMAGE_VIEW_USAGE_COLOR; - } + // format supported. check if we have any depth or stencil component + // Note: this is a hack + PalImageViewUsages usages = 0; + if (format == PAL_FORMAT_S8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } - return usages; + if (format == PAL_FORMAT_D16_UNORM || format == PAL_FORMAT_D32_SFLOAT) { + usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; } - return PAL_IMAGE_VIEW_USAGE_UNDEFINED; + if (format == PAL_FORMAT_D32_SFLOAT_S8_UINT || + format == PAL_FORMAT_D16_UNORM_S8_UINT || + format == PAL_FORMAT_D24_UNORM_S8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } + + if (usages == 0) { + usages = PAL_IMAGE_VIEW_USAGE_COLOR; + } + return usages; } -static PalResult PAL_CALL _vkGetImageMemoryRequirements( +PalResult PAL_CALL createVkImage( PalDevice* device, - PalImage* image, - PalMemoryRequirements* requirments) + const PalImageCreateInfo* info, + PalImage** outImage) { - Device* _device = (Device*)device; - Image* _image = (Image*)image; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)_device->phyDevice; + VkResult result; + PalImage* image = nullptr; + if (!device->handle) { + return PAL_RESULT_INVALID_DEVICE; + } - VkPhysicalDeviceMemoryProperties memProps = {0}; - s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); + image = palAllocate(s_Vk.allocator, sizeof(PalImage), 0); + if (!image) { + return PAL_RESULT_OUT_OF_MEMORY; + } - VkMemoryRequirements memReq = {0}; - s_Vk.getImageMemoryRequirements(_device->handle, _image->handle, &memReq); - requirments->alignment = (Uint64)memReq.alignment; - requirments->size = (Uint64)memReq.size; + VkImageCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + createInfo.extent.width = info->width; + createInfo.extent.height = info->height; + createInfo.mipLevels = info->mipLevelCount; - requirments->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; - requirments->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; - requirments->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = false; + createInfo.format = palFormatToVk(info->format); + createInfo.samples = samplesToVk(info->samples); + createInfo.usage = palUsageToVk(info->usages); - for (int i = 0; i < memProps.memoryTypeCount; i++) { - if (!(memReq.memoryTypeBits & (1 << i))) { - // memory type not supported - continue; - } + createInfo.arrayLayers = info->depthOrArraySize; + createInfo.extent.depth = 1; + createInfo.imageType = palImageTypeToVk(info->type); - VkMemoryPropertyFlags prop = memProps.memoryTypes[i].propertyFlags; - if (prop & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { - requirments->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; - } + if (info->type == PAL_IMAGE_TYPE_3D) { + createInfo.arrayLayers = 1; + createInfo.extent.depth = info->depthOrArraySize; + } - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { - requirments->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; - } + result = s_Vk.createImage( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &image->handle); - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { - requirments->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; - } + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, image); + return vkResultToPal(result); } + image->belongsToSwapchain = false; + image->device = device; + image->info.depthOrArraySize = info->depthOrArraySize; + image->info.type = info->type; + image->info.format = info->format; + image->info.usages = info->usages; + image->info.height = info->height; + image->info.mipLevelCount = info->mipLevelCount; + image->info.samples = info->samples; + image->info.width = info->width; + + *outImage = image; return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL _vkAllocateMemory( - PalDevice* device, - PalMemoryType type, - Uint64 size, - PalMemory** outMemory) +void PAL_CALL destroyVkImage(PalImage* image) { - Device* _device = (Device*)device; - VkMemoryAllocateInfo allocateInfo = {0}; - allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.allocationSize = (VkDeviceSize)size; - allocateInfo.memoryTypeIndex = _device->memoryTypeIndex[type]; - - if (allocateInfo.memoryTypeIndex == -1) { - // not supported - return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; - } - - VkDeviceMemory memory = nullptr; - VkResult result = s_Vk.allocateMemory( - _device->handle, - &allocateInfo, - &s_Vk.allocator, - &memory); - - if (result != VK_SUCCESS) { - return vkResultToPal(result); + if (image->belongsToSwapchain) { + return; } + s_Vk.destroyImage(image->device->handle, image->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, image); +} - *outMemory = (PalMemory*)memory; +PalResult PAL_CALL getVkImageInfo( + PalImage* image, + PalImageInfo* info) +{ + *info = image->info; return PAL_RESULT_SUCCESS; } -void PAL_CALL _vkFreeMemory( +PalResult PAL_CALL getVkImageMemoryRequirements( PalDevice* device, - PalMemory* memory) + PalImage* image, + PalMemoryRequirements* requirements) { - Device* _device = (Device*)device; - VkDeviceMemory mem = (VkDeviceMemory)memory; - s_Vk.freeMemory(_device->handle, mem, &s_Vk.allocator); + VkPhysicalDevice phyDevice = (VkPhysicalDevice)device->phyDevice; + VkPhysicalDeviceMemoryProperties memProps = {0}; + s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); + + VkMemoryRequirements memReq = {0}; + s_Vk.getImageMemoryRequirements(device->handle, image->handle, &memReq); + requirements->alignment = (Uint64)memReq.alignment; + requirements->size = (Uint64)memReq.size; + + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = false; + + for (int i = 0; i < memProps.memoryTypeCount; i++) { + if (!(memReq.memoryTypeBits & (1 << i))) { + // memory type not supported + continue; + } + + VkMemoryPropertyFlags prop = memProps.memoryTypes[i].propertyFlags; + if (prop & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; + } + + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; + } + + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; + } + } + return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL _vkBindImageMemory( +PalResult PAL_CALL bindVkImageMemory( PalDevice* device, PalImage* image, PalMemory* memory, Uint64 offset) { - Image* _image = (Image*)image; - if (_image->belongsToSwapchain) { + if (image->belongsToSwapchain) { return PAL_RESULT_INVALID_OPERATION; } - - Device* _device = (Device*)device; VkDeviceMemory mem = (VkDeviceMemory)memory; - s_Vk.bindImageMemory(_device->handle, _image->handle, mem, offset); + s_Vk.bindImageMemory(device->handle, image->handle, mem, offset); } -static PalResult PAL_CALL _vkCreateImageView( +PalResult PAL_CALL createVkImageView( PalDevice* device, PalImage* image, const PalImageViewCreateInfo* info, PalImageView** outImageView) { VkResult result = VK_SUCCESS; - ImageView* imageView = nullptr; - Device* _device = (Device*)device; - Image* _image = (Image*)image; - - imageView = palAllocate(s_Graphics.allocator, sizeof(ImageView), 0); + PalImageView* imageView = nullptr; + imageView = palAllocate(s_Vk.allocator, sizeof(PalImageView), 0); if (!imageView) { return PAL_RESULT_OUT_OF_MEMORY; } VkImageViewCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.format = palFormatToVk(_image->info.format); - createInfo.image = _image->handle; + createInfo.format = palFormatToVk(image->info.format); + createInfo.image = image->handle; createInfo.subresourceRange.baseArrayLayer = info->startArrayLayer; createInfo.subresourceRange.baseMipLevel = info->startMipLevel; @@ -2655,37 +2584,36 @@ static PalResult PAL_CALL _vkCreateImageView( createInfo.subresourceRange .aspectMask = aspectFlags; result = s_Vk.createImageView( - _device->handle, + device->handle, &createInfo, - &s_Vk.allocator, + &s_Vk.vkAllocator, &imageView->handle); if (result != VK_SUCCESS) { - palFree(s_Graphics.allocator, imageView); + palFree(s_Vk.allocator, imageView); return vkResultToPal(result); } - imageView->device = _device; - imageView->image = _image; + imageView->device = device; + imageView->image = image; imageView->type = createInfo.viewType; imageView->usages = info->usages; - *outImageView = (PalImageView*)imageView; + *outImageView = imageView; return PAL_RESULT_SUCCESS; } -static void PAL_CALL _vkDestroyImageView(PalImageView* imageView) +void PAL_CALL destroyVkImageView(PalImageView* imageView) { - ImageView* _imageView = (ImageView*)imageView; s_Vk.destroyImageView( - _imageView->device->handle, - _imageView->handle, - &s_Vk.allocator); + imageView->device->handle, + imageView->handle, + &s_Vk.vkAllocator); - palFree(s_Graphics.allocator, _imageView); + palFree(s_Vk.allocator, imageView); } -static PalResult PAL_CALL _vkQuerySwapchainCapabilities( +PalResult PAL_CALL queryVkSwapchainCapabilities( PalAdapter* adapter, PalGfxWindow* window, PalSwapchainCapabilities* caps) @@ -2697,7 +2625,7 @@ static PalResult PAL_CALL _vkQuerySwapchainCapabilities( VkPresentModeKHR* modes = nullptr; VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; - bool ret = vkCreateSurface(window, &surface); + bool ret = createSurface(window, &surface); if (!ret) { return PAL_RESULT_INVALID_GRAPHICS_WINDOW; } @@ -2706,17 +2634,17 @@ static PalResult PAL_CALL _vkQuerySwapchainCapabilities( s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, nullptr); modes = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(VkPresentModeKHR) * modeCount, 0); formats = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(VkSurfaceFormatKHR) * formatCount, 0); if (!modes || !formats) { - s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); + s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.vkAllocator); return PAL_RESULT_OUT_OF_MEMORY; } @@ -2805,14 +2733,13 @@ static PalResult PAL_CALL _vkQuerySwapchainCapabilities( // clang-format on - palFree(s_Graphics.allocator, formats); - palFree(s_Graphics.allocator, modes); - s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocator); - + palFree(s_Vk.allocator, formats); + palFree(s_Vk.allocator, modes); + s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.vkAllocator); return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL _vkCreateSwapchain( +PalResult PAL_CALL createVkSwapchain( PalDevice* device, PalQueue* queue, PalGfxWindow* window, @@ -2820,30 +2747,27 @@ static PalResult PAL_CALL _vkCreateSwapchain( PalSwapchain** outSwapchain) { PalFormat imageFormat = 0; - Swapchain* swapchain = nullptr; + PalSwapchain* swapchain = nullptr; VkImage* images = nullptr; - - Queue* _queue = (Queue*)queue; - Device* _device = (Device*)device; - PhysicalQueue* phyQueue = _queue->phyQueue; + PhysicalQueue* phyQueue = queue->phyQueue; // check if we enabled swapchain feature - if (!_device->createSwapchain) { + if (!device->createSwapchain) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } // check if the queue is a graphics queue before we check its family // index for presentation support. - if (_queue->usage != VK_QUEUE_GRAPHICS_BIT) { + if (queue->usage != VK_QUEUE_GRAPHICS_BIT) { PAL_RESULT_INVALID_QUEUE; } - swapchain = palAllocate(s_Graphics.allocator, sizeof(Swapchain), 0); + swapchain = palAllocate(s_Vk.allocator, sizeof(PalSwapchain), 0); if (!swapchain) { return PAL_RESULT_OUT_OF_MEMORY; } - bool ret = vkCreateSurface(window, &swapchain->surface); + bool ret = createSurface(window, &swapchain->surface); if (!ret) { return PAL_RESULT_INVALID_GRAPHICS_WINDOW; } @@ -2900,67 +2824,67 @@ static PalResult PAL_CALL _vkCreateSwapchain( } // create swapchain - VkResult result = _device->createSwapchain( - _device->handle, + VkResult result = device->createSwapchain( + device->handle, &createInfo, - &s_Vk.allocator, + &s_Vk.vkAllocator, &swapchain->handle); if (result != VK_SUCCESS) { s_Vk.destroySurface( s_Vk.instance, swapchain->surface, - &s_Vk.allocator); + &s_Vk.vkAllocator); - palFree(s_Graphics.allocator, swapchain); + palFree(s_Vk.allocator, swapchain); return vkResultToPal(result); } // get and cache all images Int32 count = 0; - result = _device->getSwapchainImages( - _device->handle, + result = device->getSwapchainImages( + device->handle, swapchain->handle, &count, nullptr); swapchain->images = palAllocate( - s_Graphics.allocator, - sizeof(Image) * count, + s_Vk.allocator, + sizeof(PalImage) * count, 0); images = palAllocate( - s_Graphics.allocator, + s_Vk.allocator, sizeof(VkImage) * count, 0); if (!swapchain->images || !images) { - _device->destroySwapchain( - _device->handle, + device->destroySwapchain( + device->handle, swapchain->handle, - &s_Vk.allocator + &s_Vk.vkAllocator ); s_Vk.destroySurface( s_Vk.instance, swapchain->surface, - &s_Vk.allocator); + &s_Vk.vkAllocator); - palFree(s_Graphics.allocator, swapchain); + palFree(s_Vk.allocator, swapchain); return PAL_RESULT_OUT_OF_MEMORY; } - _device->getSwapchainImages( - _device->handle, + device->getSwapchainImages( + device->handle, swapchain->handle, &count, images); // fill all images with the creatio info for (int i = 0; i < count; i++) { - Image* image = &swapchain->images[i]; + PalImage* image = &swapchain->images[i]; image->belongsToSwapchain = true; - image->device = _device; + image->device = device; image->handle = images[i]; image->info.depthOrArraySize = createInfo.imageArrayLayers; @@ -2973,833 +2897,39 @@ static PalResult PAL_CALL _vkCreateSwapchain( image->info.type = PAL_IMAGE_TYPE_2D; } - swapchain->device = _device; + swapchain->device = device; swapchain->imageCount = count; - *outSwapchain = (PalSwapchain*)swapchain; + *outSwapchain = swapchain; return PAL_RESULT_SUCCESS; } -static void PAL_CALL vkDestroySwapchain(PalSwapchain* swapchain) +void PAL_CALL destroyVkSwapchain(PalSwapchain* swapchain) { - Swapchain* _swapchain = (Swapchain*)swapchain; - _swapchain->device->destroySwapchain( - _swapchain->device->handle, - _swapchain->handle, - &s_Vk.allocator + swapchain->device->destroySwapchain( + swapchain->device->handle, + swapchain->handle, + &s_Vk.vkAllocator ); - s_Vk.destroySurface(s_Vk.instance, _swapchain->surface, &s_Vk.allocator); - palFree(s_Graphics.allocator, _swapchain->images); - palFree(s_Graphics.allocator, _swapchain); + s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, swapchain->images); + palFree(s_Vk.allocator, swapchain); } -static Uint32 PAL_CALL _vkGetSwapchainImageCount(PalSwapchain* swapchain) +Uint32 PAL_CALL getVkSwapchainImageCount(PalSwapchain* swapchain) { - Swapchain* _swapchain = (Swapchain*)swapchain; - return _swapchain->imageCount; + return swapchain->imageCount; } -static PalImage* PAL_CALL _vkGetSwapchainImage( +PalImage* PAL_CALL getVkSwapchainImage( PalSwapchain* swapchain, Int32 index) { - Swapchain* _swapchain = (Swapchain*)swapchain; - if (index > _swapchain->imageCount) { + if (index > swapchain->imageCount) { return nullptr; } - - return (PalImage*)&_swapchain->images[index]; -} - -static PalGfxBackend s_VkBackend = { - // adapter - .enumerateAdapters = _vkEnumerateAdapters, - .getAdapterInfo = _vkGetAdapterInfo, - .getAdapterCapabilities = _vkGetAdapterCapabilities, - - // device - .createDevice = _vkCreateDevice, - .destroyDevice = _vkDestroyDevice, - - // queue - .createQueue = _vkCreateQueue, - .destroyQueue = _vkDestroyQueue, - .canQueuePresent = _vkCanQueuePresent, - - // image - .createImage = _vkCreateImage, - .destroyImage = _vkDestroyImage, - .getImageInfo = _vkGetImageInfo, - .enumerateFormats = _vkEnumerateFormats, - .isFormatSupported = _vkIsFormatSupported, - .queryFormatImageUsages = _vkQueryFormatImageUsages, - .queryFormatImageViewUsages = _vkQueryFormatImageViewUsages, - .getImageMemoryRequirements = _vkGetImageMemoryRequirements, - - // memory - .allocate = _vkAllocateMemory, - .free = _vkFreeMemory, - .bindImageMemory = _vkBindImageMemory, - - // image view - .createImageView = _vkCreateImageView, - .destroyImageView = _vkDestroyImageView, - - // swapchain - .querySwapchainCapabilities = _vkQuerySwapchainCapabilities, - .createSwapchain = _vkCreateSwapchain, - .destroySwapchain = vkDestroySwapchain, - .getSwapchainImageCount = _vkGetSwapchainImageCount, - .getSwapchainImage = _vkGetSwapchainImage, -}; - -#endif // PAL_HAS_VULKAN - -// ================================================== -// Public API -// ================================================== - -PalResult PAL_CALL palInitGraphics( - bool enableDebugLayer, - const PalAllocator* allocator) -{ - if (s_Graphics.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - - s_Graphics.allocator = allocator; - s_Graphics.maxHandleData = 32; - s_Graphics.handleData = palAllocate( - s_Graphics.allocator, - sizeof(HandleData) * s_Graphics.maxHandleData, - 0); - - if (!s_Graphics.handleData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - -#if PAL_HAS_VULKAN - PalResult ret = vkInitGraphics(enableDebugLayer); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - BackendData* backend = &s_Graphics.backends[s_Graphics.backendCount++]; - backend->base = &s_VkBackend; - backend->count = 0; - backend->startIndex = 0; -#endif // PAL_HAS_VULKAN - - s_Graphics.initialized = true; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palShutdownGraphics() -{ - if (!s_Graphics.initialized) { - return; - } - -#if PAL_HAS_VULKAN - vkShutdownGraphics(); -#endif // PAL_HAS_VULKAN - - palFree(s_Graphics.allocator, s_Graphics.handleData); - memset(&s_Graphics, 0, sizeof(s_Graphics)); - s_Graphics.initialized = false; -} - -// ================================================== -// Adapter -// ================================================== - -PalResult PAL_CALL palEnumerateAdapters( - Int32* count, - PalAdapter** outAdapters) -{ - // enumerate all adapters for both custom and PAL backends - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!count) { - return PAL_RESULT_NULL_POINTER; - } - - if (*count == 0 && outAdapters) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - PalResult result; - int totalCount = 0; - int index = 0; - - int _count = outAdapters ? *count : 0; - for (int i = 0; i < s_Graphics.backendCount; i++) { - BackendData* backend = &s_Graphics.backends[i]; - if (outAdapters) { - // offset into the array so all backends write at the correct index - PalAdapter** adapters = &outAdapters[backend->startIndex]; - result = backend->base->enumerateAdapters(&_count, adapters); - - for (int i = 0; i < backend->count; i++) { - HandleData* data = getFreeHandleData(); - data->backend = backend->base; - data->handle = adapters[i]; - } - - } else { - result = backend->base->enumerateAdapters(&_count, nullptr); - backend->startIndex = totalCount; - backend->count = _count; - totalCount += _count; - _count = 0; - } - - // break if a backend fails - if (result != PAL_RESULT_SUCCESS) { - return result; - } - } - - if (!outAdapters) { - *count = totalCount; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetAdapterInfo( - PalAdapter* adapter, - PalAdapterInfo* info) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!adapter || !info) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = findHandleData(adapter); - if (data) { - return data->backend->getAdapterInfo(adapter, info); - } - - return PAL_RESULT_INVALID_ADAPTER; -} - -PalResult PAL_CALL palGetAdapterCapabilities( - PalAdapter* adapter, - PalAdapterCapabilities* caps) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!adapter || !caps) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = findHandleData(adapter); - if (data) { - return data->backend->getAdapterCapabilities(adapter, caps); - } - - return PAL_RESULT_INVALID_ADAPTER; -} - -PalResult PAL_CALL palAddGfxBackend(const PalGfxBackend* backend) -{ - if (s_Graphics.initialized) { - return PAL_RESULT_INVALID_BACKEND; - } - - // check if all the function pointers are set - // clang-format off - if (!backend->enumerateAdapters || - !backend->getAdapterInfo || - !backend->getAdapterCapabilities || - !backend->createDevice || - !backend->destroyDevice || - !backend->createQueue || - !backend->destroyQueue || - !backend->canQueuePresent || - !backend->createImage || - !backend->destroyImage || - !backend->getImageInfo || - !backend->enumerateFormats || - !backend->isFormatSupported || - !backend->queryFormatImageUsages || - !backend->queryFormatImageViewUsages || - !backend->getImageMemoryRequirements || - !backend->allocate || - !backend->free || - !backend->bindImageMemory || - !backend->createImageView || - !backend->destroyImageView || - !backend->querySwapchainCapabilities || - !backend->createSwapchain || - !backend->destroySwapchain || - !backend->getSwapchainImageCount || - !backend->getSwapchainImage) { - return PAL_RESULT_INVALID_BACKEND; - } - // clang-format on - - BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; - attached->base = backend; - attached->startIndex = 0; - attached->count = 0; - - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Device -// ================================================== - -PalResult PAL_CALL palCreateDevice( - PalAdapter* adapter, - PalAdapterFeatures features, - PalDevice** outDevice) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!outDevice) { - return PAL_RESULT_NULL_POINTER; - } - - // check if the adapter is from PAL (custom or internal backend) - HandleData* adapterData = findHandleData(adapter); - if (!adapterData) { - return PAL_RESULT_INVALID_ADAPTER; - } - - PalDevice* device = nullptr; - PalResult ret; - ret = adapterData->backend->createDevice(adapter, features, &device); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // create a slot for the created device - HandleData* deviceData = getFreeHandleData(); - if (!deviceData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - deviceData->backend = adapterData->backend; - deviceData->handle = device; - - *outDevice = device; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyDevice(PalDevice* device) -{ - if (s_Graphics.initialized && device) { - HandleData* data = findHandleData(device); - if (data) { - data->backend->destroyDevice(device); - data->used = false; - } - } -} - -// ================================================== -// Queue -// ================================================== - -PalResult PAL_CALL palCreateQueue( - PalDevice* device, - PalQueueType type, - PalQueue** outQueue) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device || !outQueue) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = findHandleData(device); - if (!data) { - return PAL_RESULT_INVALID_DEVICE; - } - - PalQueue* queue = nullptr; - PalResult ret; - ret = data->backend->createQueue( - device, - type, - &queue); - - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // create a slot for the created queue - HandleData* queueData = getFreeHandleData(); - if (!queueData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - queueData->backend = data->backend; - queueData->handle = queue; - - *outQueue = queue; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyQueue(PalQueue* queue) -{ - if (s_Graphics.initialized && queue) { - HandleData* data = findHandleData(queue); - if (data) { - data->backend->destroyQueue(queue); - data->used = false; - } - } -} - -bool PAL_CALL palCanQueuePresent( - PalQueue* queue, - PalGfxWindow* window) -{ - if (s_Graphics.initialized && queue) { - HandleData* data = findHandleData(queue); - if (data) { - return data->backend->canQueuePresent(queue, window); - } - return false; - } - return false; -} - -PalResult PAL_CALL palCreateImage( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device ||!info || !outImage) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = findHandleData(device); - if (!data) { - return PAL_RESULT_INVALID_DEVICE; - } - - PalImage* image = nullptr; - PalResult ret; - ret = data->backend->createImage( - device, - info, - &image); - - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // create a slot for the created image - HandleData* imageData = getFreeHandleData(); - if (!imageData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - imageData->backend = data->backend; - imageData->handle = image; - - *outImage = image; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyImage(PalImage* image) -{ - if (s_Graphics.initialized && image) { - HandleData* data = findHandleData(image); - if (data) { - data->backend->destroyImage(image); - data->used = false; - } - } -} - -PalResult PAL_CALL palGetImageInfo( - PalImage* image, - PalImageInfo* info) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!image || !info) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = findHandleData(image); - if (!data) { - return PAL_RESULT_INVALID_IMAGE; - } - - return data->backend->getImageInfo(image, info); -} - -PalResult PAL_CALL palEnumerateFormats( - PalAdapter* adapter, - Int32* count, - PalFormatInfo* outFormats) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!adapter || !count) { - return PAL_RESULT_NULL_POINTER; - } - - if (*count == 0 && outFormats) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - HandleData* adapterData = findHandleData(adapter); - if (!adapterData) { - return PAL_RESULT_INVALID_ADAPTER; - } - - return adapterData->backend->enumerateFormats(adapter, count, outFormats); -} - -bool PAL_CALL palIsFormatSupported( - PalAdapter* adapter, - PalFormat format) -{ - if (!s_Graphics.initialized || !adapter) { - return false; - } - - HandleData* adapterData = findHandleData(adapter); - if (!adapterData) { - return false; - } - - return adapterData->backend->isFormatSupported(adapter, format); -} - -PalImageUsages PAL_CALL palQueryFormatImageUsages( - PalAdapter* adapter, - PalFormat format) -{ - if (!s_Graphics.initialized || !adapter) { - return PAL_IMAGE_USAGE_UNDEFINED; - } - - HandleData* adapterData = findHandleData(adapter); - if (!adapterData) { - return PAL_IMAGE_USAGE_UNDEFINED; - } - - return adapterData->backend->queryFormatImageUsages(adapter, format); -} - -PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( - PalAdapter* adapter, - PalFormat format) -{ - if (!s_Graphics.initialized || !adapter) { - return PAL_IMAGE_VIEW_USAGE_UNDEFINED; - } - - HandleData* adapterData = findHandleData(adapter); - if (!adapterData) { - return PAL_IMAGE_VIEW_USAGE_UNDEFINED; - } - - return adapterData->backend->queryFormatImageViewUsages(adapter, format); -} - -PalResult PAL_CALL palGetImageMemoryRequirements( - PalDevice* device, - PalImage* image, - PalMemoryRequirements* requirements) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device || !image) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* deviceData = findHandleData(device); - if (!deviceData) { - return PAL_RESULT_INVALID_BACKEND; - } - - return deviceData->backend->getImageMemoryRequirements( - device, - image, - requirements); -} - -// ================================================== -// Memory -// ================================================== - -PalResult PAL_CALL palAllocateMemory( - PalDevice* device, - PalMemoryType type, - Uint64 size, - PalMemory** outMemory) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!outMemory || !device) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* deviceData = findHandleData(device); - if (!deviceData) { - return PAL_RESULT_INVALID_DEVICE; - } - - return deviceData->backend->allocate(device, type, size, outMemory); -} - -void PAL_CALL palFreeMemory( - PalDevice* device, - PalMemory* memory) -{ - if (s_Graphics.initialized && device && memory) { - HandleData* data = findHandleData(device); - if (data) { - data->backend->free(device, memory); - } - } -} - -PalResult PAL_CALL palBindImageMemory( - PalDevice* device, - PalImage* image, - PalMemory* memory, - Uint64 offset) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device || !image || !memory) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* deviceData = findHandleData(device); - if (!deviceData) { - return PAL_RESULT_INVALID_DEVICE; - } - - return deviceData->backend->bindImageMemory( - device, - image, - memory, - offset); -} - -PalResult PAL_CALL palCreateImageView( - PalDevice* device, - PalImage* image, - const PalImageViewCreateInfo* info, - PalImageView** outImageView) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device ||!image || !info || !outImageView) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = findHandleData(device); - if (!data) { - return PAL_RESULT_INVALID_DEVICE; - } - - PalImageView* imageView = nullptr; - PalResult ret; - ret = data->backend->createImageView( - device, - image, - info, - &imageView); - - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // create a slot for the created image view - HandleData* imageViewData = getFreeHandleData(); - if (!imageViewData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - imageViewData->backend = data->backend; - imageViewData->handle = imageView; - - *outImageView = imageView; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyImageView(PalImageView* imageView) -{ - if (s_Graphics.initialized && imageView) { - HandleData* data = findHandleData(imageView); - if (data) { - data->backend->destroyImageView(imageView); - data->used = false; - } - } -} - -// ================================================== -// Swapchain -// ================================================== - -PalResult PAL_CALL palQuerySwapchainCapabilities( - PalAdapter* adapter, - PalGfxWindow* window, - PalSwapchainCapabilities* caps) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!adapter || !window || !caps) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* adapterData = findHandleData(adapter); - if (!adapterData) { - return PAL_RESULT_INVALID_ADAPTER; - } - - return adapterData->backend->querySwapchainCapabilities( - adapter, - window, - caps); + return (PalImage*)&swapchain->images[index]; } -PalResult PAL_CALL palCreateSwapchain( - PalDevice* device, - PalQueue* queue, - PalGfxWindow* window, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device || !queue || !window || !info || !outSwapchain) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* deviceData = findHandleData(device); - if (!deviceData) { - return PAL_RESULT_INVALID_QUEUE; - } - - PalResult ret; - PalSwapchain* swapchain = nullptr; - ret = deviceData->backend->createSwapchain( - device, - queue, - window, - info, - &swapchain); - - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // create a slot for the created swapchain - HandleData* swapchainData = getFreeHandleData(); - if (!swapchainData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - swapchainData->backend = deviceData->backend; - swapchainData->handle = swapchain; - - *outSwapchain = swapchain; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) -{ - if (s_Graphics.initialized && swapchain) { - HandleData* data = findHandleData(swapchain); - if (data) { - data->backend->destroySwapchain(swapchain); - data->used = false; - } - } -} - -Uint32 PAL_CALL palGetSwapchainImageCount(PalSwapchain* swapchain) -{ - if (!s_Graphics.initialized || !swapchain) { - return 0; - } - - HandleData* swapchainData = findHandleData(swapchain); - if (!swapchainData) { - return 0; - } - - return swapchainData->backend->getSwapchainImageCount(swapchain); -} - -PalImage* PAL_CALL palGetSwapchainImage( - PalSwapchain* swapchain, - Int32 index) -{ - if (!s_Graphics.initialized || !swapchain || index < 0) { - return nullptr; - } - - HandleData* swapchainData = findHandleData(swapchain); - if (!swapchainData) { - return nullptr; - } - - PalImage* image = swapchainData->backend->getSwapchainImage( - swapchain, - index); - - // check if the user has already requested for the image - HandleData* imageData = findHandleData(image); - if (!imageData) { - // create a new slot - imageData = getFreeHandleData(); - if (!imageData) { - return nullptr; - } - } - - imageData->backend = swapchainData->backend; - imageData->handle = image; - return image; -} \ No newline at end of file +#endif // PAL_HAS_VULKAN \ No newline at end of file diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index ffe25d33..51c87387 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -2797,6 +2797,7 @@ static int compareModes( } } +// FIXME: manual copy static WindowData* getFreeWindowData() { for (int i = 0; i < s_Video.maxWindowData; ++i) { @@ -2829,6 +2830,7 @@ static WindowData* getFreeWindowData() return nullptr; } +// FIXME: make it performant static WindowData* findWindowData(PalWindow* window) { for (int i = 0; i < s_Video.maxWindowData; ++i) { @@ -2848,6 +2850,7 @@ static void resetMonitorData() s_Video.maxMonitorData * sizeof(MonitorData)); } +// FIXME: manual copy static MonitorData* getFreeMonitorData() { for (int i = 0; i < s_Video.maxMonitorData; ++i) { @@ -2879,6 +2882,7 @@ static MonitorData* getFreeMonitorData() return nullptr; } +// FIXME: make it performant static MonitorData* findMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Video.maxMonitorData; ++i) { From 1b288ac02db8b1936ab8da55019b4ca5ca11111f Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 5 Dec 2025 16:49:26 +0000 Subject: [PATCH 035/372] add shader api --- include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 58 +++++++++++++++---- src/graphics/pal_graphics.c | 112 +++++++++++++++++++++++++++++++----- src/graphics/pal_vulkan.c | 95 ++++++++++++++++++++++++++++-- src/pal_core.c | 3 + src/video/pal_video_linux.c | 4 -- tests/graphics_test.c | 4 ++ 7 files changed, 244 insertions(+), 35 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index f89a597b..20ce1434 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -259,7 +259,8 @@ typedef enum { PAL_RESULT_INVALID_SWAPCHAIN, PAL_RESULT_INVALID_IMAGE, PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED, - PAL_RESULT_INVALID_OPERATION + PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_INVALID_SHADER_TYPE } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 5b531357..5c099300 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -45,6 +45,7 @@ typedef struct PalQueue PalQueue; typedef struct PalSwapchain PalSwapchain; typedef struct PalImage PalImage; typedef struct PalImageView PalImageView; +typedef struct PalShader PalShader; typedef enum { PAL_ADAPTER_TYPE_UNKNOWN, @@ -208,17 +209,18 @@ typedef enum { PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(3), PAL_ADAPTER_FEATURE_TESSELLATION_SHADER = PAL_BIT64(4), PAL_ADAPTER_FEATURE_GEOMETRY_SHADER = PAL_BIT64(5), - PAL_ADAPTER_FEATURE_SHADER_FLOAT16 = PAL_BIT64(6), - PAL_ADAPTER_FEATURE_SHADER_FLOAT64 = PAL_BIT64(7), - PAL_ADAPTER_FEATURE_SHADER_INT16 = PAL_BIT64(8), - PAL_ADAPTER_FEATURE_SHADER_INT64 = PAL_BIT64(9), - PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(10), - PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(11), - PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(12), - PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(13), - PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(14), - PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(15), - PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(16) + PAL_ADAPTER_FEATURE_COMPUTE_SHADER = PAL_BIT64(6), + PAL_ADAPTER_FEATURE_SHADER_FLOAT16 = PAL_BIT64(7), + PAL_ADAPTER_FEATURE_SHADER_FLOAT64 = PAL_BIT64(8), + PAL_ADAPTER_FEATURE_SHADER_INT16 = PAL_BIT64(9), + PAL_ADAPTER_FEATURE_SHADER_INT64 = PAL_BIT64(10), + PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(11), + PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(12), + PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(13), + PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), + PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(15), + PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16), + PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(17) } PalAdapterFeatures; typedef enum { @@ -264,6 +266,16 @@ typedef enum { PAL_SWAPCHAIN_FORMAT_MAX // more pars will be added } PalSwapchainFormat; +typedef enum { + PAL_SHADER_TYPE_UNDEFINED, + PAL_SHADER_TYPE_VERTEX, + PAL_SHADER_TYPE_PIXEL, + PAL_SHADER_TYPE_COMPUTE, + PAL_SHADER_TYPE_GEOMETRY, + PAL_SHADER_TYPE_TESSELLATION_CONTROL, + PAL_SHADER_TYPE_TESSELLATION_EVALUATION +} PalShaderType; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -366,6 +378,12 @@ typedef struct { PalSwapchainFormat format; } PalSwapchainCreateInfo; +typedef struct { + PalShaderType type; + const void* bytecode; + Uint64 bytecodeSize; +} PalShaderCreateInfo; + typedef struct { void* display; void* window; @@ -478,6 +496,15 @@ typedef struct { PalImage* PAL_CALL (*getSwapchainImage)( PalSwapchain* swapchain, Int32 index); + + PalResult PAL_CALL (*createShader)( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + + void PAL_CALL (*destroyShader)(PalShader* shader); + + PalShaderType PAL_CALL (*getShaderType)(PalShader* shader); } PalGfxBackend; PAL_API PalResult PAL_CALL palAddGfxBackend(const PalGfxBackend* backend); @@ -595,6 +622,15 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, Int32 index); +PAL_API PalResult PAL_CALL palCreateShader( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + +PAL_API void PAL_CALL palDestroyShader(PalShader* shader); + +PAL_API PalShaderType PAL_CALL palGetShaderType(PalShader* shader); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index b502880f..950baea8 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -224,6 +224,15 @@ PalImage* PAL_CALL getVkSwapchainImage( PalSwapchain* swapchain, Int32 index); +PalResult PAL_CALL createVkShader( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + +void PAL_CALL destroyVkShader(PalShader* shader); + +PalShaderType PAL_CALL getVkShaderType(PalShader* shader); + static PalGfxBackend s_VkBackend = { .enumerateAdapters = enumerateVkAdapters, .getAdapterInfo = getVkAdapterInfo, @@ -250,7 +259,10 @@ static PalGfxBackend s_VkBackend = { .createSwapchain = createVkSwapchain, .destroySwapchain = destroyVkSwapchain, .getSwapchainImageCount = getVkSwapchainImageCount, - .getSwapchainImage = getVkSwapchainImage + .getSwapchainImage = getVkSwapchainImage, + .createShader = createVkShader, + .destroyShader = destroyVkShader, + .getShaderType = getVkShaderType }; #endif // PAL_HAS_VULKAN @@ -515,7 +527,7 @@ PalResult PAL_CALL palCreateDevice( return PAL_RESULT_INVALID_ADAPTER; } - // create a slot for the created device + // create a slot for the device Uint64 deviceIndex = 0; HandleData* deviceData = getFreeHandleData(&deviceIndex); if (!deviceData) { @@ -610,7 +622,7 @@ PalResult PAL_CALL palCreateQueue( return PAL_RESULT_INVALID_DEVICE; } - // create a slot for the created queue + // create a slot for the queue Uint64 queueIndex = 0; HandleData* queueData = getFreeHandleData(&queueIndex); if (!queueData) { @@ -762,7 +774,7 @@ PalResult PAL_CALL palCreateImage( return PAL_RESULT_INVALID_DEVICE; } - // create a slot for the created image + // create a slot for the image Uint64 imageIndex = 0; HandleData* imageData = getFreeHandleData(&imageIndex); if (!imageData) { @@ -916,7 +928,7 @@ PalResult PAL_CALL palCreateImageView( return PAL_RESULT_INVALID_IMAGE; } - // create a slot for the created image view + // create a slot for the image view Uint64 imageViewIndex = 0; HandleData* imageViewData = getFreeHandleData(&imageViewIndex); if (!imageViewData) { @@ -1011,7 +1023,7 @@ PalResult PAL_CALL palCreateSwapchain( return PAL_RESULT_INVALID_QUEUE; } - // create a slot for the created swapchain + // create a slot for the swapchain Uint64 swapchainIndex = 0; HandleData* swapchainData = getFreeHandleData(&swapchainIndex); if (!swapchainData) { @@ -1052,16 +1064,14 @@ void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) Uint32 PAL_CALL palGetSwapchainImageCount(PalSwapchain* swapchain) { - if (!s_Graphics.initialized || !swapchain) { - return 0; - } - - Uint64 index = FROM_PAL_HANDLE(swapchain); - HandleData* data = findHandleData(index); - if (!data) { - return 0; + if (s_Graphics.initialized && swapchain) { + Uint64 index = FROM_PAL_HANDLE(swapchain); + HandleData* data = findHandleData(index); + if (data) { + return data->backend->getSwapchainImageCount(data->handle); + } } - return data->backend->getSwapchainImageCount(data->handle); + return 0; } PalImage* PAL_CALL palGetSwapchainImage( @@ -1097,4 +1107,76 @@ PalImage* PAL_CALL palGetSwapchainImage( imageData->handle = image; return TO_PAL_HANDLE(PalImage, imageIndex); +} + +PalResult PAL_CALL palCreateShader( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outShader) { + return PAL_RESULT_NULL_POINTER; + } + + if (info->type == PAL_SHADER_TYPE_UNDEFINED) { + return PAL_RESULT_INVALID_SHADER_TYPE; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + // create a slot for the shader + Uint64 shaderIndex = 0; + HandleData* shaderData = getFreeHandleData(&shaderIndex); + if (!shaderData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalShader* shader = nullptr; + PalResult ret; + ret = data->backend->createShader( + data->handle, + info, + &shader); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + shaderData->backend = data->backend; + shaderData->handle = shader; + + *outShader = TO_PAL_HANDLE(PalShader, shader); + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyShader(PalShader* shader) +{ + if (s_Graphics.initialized && shader) { + Uint64 index = FROM_PAL_HANDLE(shader); + HandleData* data = findHandleData(index); + if (data) { + data->backend->destroyShader(data->handle); + data->used = false; + } + } +} + +PalShaderType PAL_CALL palGetShaderType(PalShader* shader) +{ + if (s_Graphics.initialized && shader) { + Uint64 index = FROM_PAL_HANDLE(shader); + HandleData* data = findHandleData(index); + if (data) { + return data->backend->getShaderType(data->handle); + } + } + return PAL_SHADER_TYPE_UNDEFINED; } \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 8e7a4259..acf1584e 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -105,6 +105,8 @@ typedef struct { PFN_vkGetDeviceProcAddr getDeviceProcAddr; PFN_vkCreateImage createImage; PFN_vkDestroyImage destroyImage; + PFN_vkCreateShaderModule createShader; + PFN_vkDestroyShaderModule destroyShader; PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; @@ -170,6 +172,13 @@ struct PalSwapchain { PalImage* images; }; +struct PalShader { + PalShaderType type; + PalDevice* device; + VkShaderModule handle; + VkPipelineShaderStageCreateInfo info; +}; + static Vulkan s_Vk = {0}; // ================================================== @@ -1043,6 +1052,14 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroyImageView"); + s_Vk.createShader = (PFN_vkCreateShaderModule)dlsym( + s_Vk.handle, + "vkCreateShaderModule"); + + s_Vk.destroyShader = (PFN_vkDestroyShaderModule)dlsym( + s_Vk.handle, + "vkDestroyShaderModule"); + s_Vk.getPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)dlsym( s_Vk.handle, "vkGetPhysicalDeviceProperties2"); @@ -1771,10 +1788,6 @@ PalResult PAL_CALL getVkAdapterCapabilities( s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); // check for additional features - if (features.geometryShader) { - caps->features |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; - } - if (features.multiViewport) { caps->features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; } @@ -1799,12 +1812,17 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->features |= PAL_ADAPTER_FEATURE_SHADER_INT16; } + if (features.geometryShader) { + caps->features |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; + } + if (features.tessellationShader) { caps->features |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; } // this features are supported on vulkan caps->features |= PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW; + caps->features |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; palFree(s_Vk.allocator, extensionProps); return PAL_RESULT_SUCCESS; @@ -2932,4 +2950,73 @@ PalImage* PAL_CALL getVkSwapchainImage( return (PalImage*)&swapchain->images[index]; } +PalResult PAL_CALL createVkShader( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader) +{ + VkResult result; + PalShader* shader = nullptr; + shader = palAllocate(s_Vk.allocator, sizeof(PalShader), 0); + if (!shader) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkShaderModuleCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = info->bytecodeSize; + createInfo.pCode = (const Uint32*)info->bytecode; + + result = s_Vk.createShader( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &shader->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, shader); + vkResultToPal(result); + } + + shader->device = device; + shader->type = info->type; + shader->info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shader->info.module = shader->handle; + shader->info.pName = "main"; + + if (info->type == PAL_SHADER_TYPE_VERTEX) { + shader->info.stage = VK_SHADER_STAGE_VERTEX_BIT; + + } else if (info->type == PAL_SHADER_TYPE_PIXEL) { + shader->info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + + } else if (info->type == PAL_SHADER_TYPE_COMPUTE) { + shader->info.stage = VK_SHADER_STAGE_COMPUTE_BIT; + + } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_CONTROL) { + shader->info.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + + } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_EVALUATION) { + shader->info.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + } + + *outShader = shader; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkShader(PalShader* shader) +{ + s_Vk.destroyShader( + shader->device->handle, + shader->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, shader); +} + +PalShaderType PAL_CALL getVkShaderType(PalShader* shader) +{ + return shader->type; +} + #endif // PAL_HAS_VULKAN \ No newline at end of file diff --git a/src/pal_core.c b/src/pal_core.c index 3a080de2..5cf13807 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -422,6 +422,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_OPERATION: return "Invalid operation"; + + case PAL_RESULT_INVALID_SHADER_TYPE: + return "Invalid shader type"; } return "Unknown"; } diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index 51c87387..ffe25d33 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -2797,7 +2797,6 @@ static int compareModes( } } -// FIXME: manual copy static WindowData* getFreeWindowData() { for (int i = 0; i < s_Video.maxWindowData; ++i) { @@ -2830,7 +2829,6 @@ static WindowData* getFreeWindowData() return nullptr; } -// FIXME: make it performant static WindowData* findWindowData(PalWindow* window) { for (int i = 0; i < s_Video.maxWindowData; ++i) { @@ -2850,7 +2848,6 @@ static void resetMonitorData() s_Video.maxMonitorData * sizeof(MonitorData)); } -// FIXME: manual copy static MonitorData* getFreeMonitorData() { for (int i = 0; i < s_Video.maxMonitorData; ++i) { @@ -2882,7 +2879,6 @@ static MonitorData* getFreeMonitorData() return nullptr; } -// FIXME: make it performant static MonitorData* findMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Video.maxMonitorData; ++i) { diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 7c79b606..c3c00d67 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -237,6 +237,10 @@ bool graphicsTest() palLog(nullptr, " Geometry shader"); } + if (caps.features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { + palLog(nullptr, " Compute shader"); + } + if (caps.features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { palLog(nullptr, " Shader float16"); } From 95658d3740757e4dc7a20d601b8745e56821f5e5 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 6 Dec 2025 16:19:13 +0000 Subject: [PATCH 036/372] remove dynamic rendering requirement --- include/pal/pal_graphics.h | 3 +- src/graphics/pal_vulkan.c | 166 +++++++++++++++---------------------- tests/graphics_test.c | 4 + tests/tests_main.c | 8 +- 4 files changed, 75 insertions(+), 106 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 5c099300..1ef7cd34 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -220,7 +220,8 @@ typedef enum { PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(15), PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16), - PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(17) + PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(17), + PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(18) } PalAdapterFeatures; typedef enum { diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index acf1584e..571ec4ac 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -66,7 +66,6 @@ typedef int (*wl_display_get_fd_fn)(struct wl_display*); typedef struct { bool hasDebug; - bool hasDynamicRendering; void* handle; VkInstance instance; @@ -131,6 +130,7 @@ typedef struct { } PhysicalQueue; struct PalDevice { + PalAdapterFeatures features; Int32 queueCount; VkPhysicalDevice phyDevice; VkDevice handle; @@ -1104,17 +1104,12 @@ PalResult PAL_CALL initGraphicsVk( // get version bool versionFallback = false; - s_Vk.hasDynamicRendering = false; Uint32 version = 0; if (s_Vk.enumerateInstanceVersion) { s_Vk.enumerateInstanceVersion(&version); if (version <= VK_API_VERSION_1_0) { versionFallback = true; } - - if (version >= VK_API_VERSION_1_3) { - s_Vk.hasDynamicRendering = true; - } } VkResult ret; @@ -1333,99 +1328,36 @@ PalResult PAL_CALL enumerateVkAdapters( Int32* count, PalAdapter** outAdapters) { - int _count = 0; int deviceCount = 0; int maxCount = outAdapters ? *count : 0; VkResult result; - result = s_Vk.enumeratePhysicalDevices(s_Vk.instance, &_count, nullptr); + result = s_Vk.enumeratePhysicalDevices( + s_Vk.instance, + &deviceCount, + nullptr); + if (result != VK_SUCCESS) { return PAL_RESULT_PLATFORM_FAILURE; } - // PAL only supports supports dynamic rendering + if (!outAdapters) { + *count = deviceCount; + return PAL_RESULT_SUCCESS; + } + VkPhysicalDevice* devices = nullptr; devices = palAllocate(s_Vk.allocator, - sizeof(VkPhysicalDevice) * _count, + sizeof(VkPhysicalDevice) * deviceCount, 0); if (!devices) { return PAL_RESULT_OUT_OF_MEMORY; } - s_Vk.enumeratePhysicalDevices(s_Vk.instance, &_count, devices); - for (int i = 0; i < _count; i++) { - // check if the gpu supports dynamic rendering - if (s_Vk.hasDynamicRendering) { - if (outAdapters) { - if (deviceCount < *count) { - PalAdapter* adapter = (PalAdapter*)devices[i]; - outAdapters[deviceCount++] = adapter; - } - - } else { - deviceCount++; - } - - } else { - // check extension - Uint32 extCount = 0; - VkExtensionProperties* exts = nullptr; - VkResult ret; - ret = s_Vk.enumerateDeviceExtensionProperties( - devices[i], - nullptr, - &extCount, - nullptr); - - if (ret != VK_SUCCESS) { - // skip - continue; - } - - exts = palAllocate( - s_Vk.allocator, - sizeof(VkExtensionProperties) * extCount, - 0); - - if (!exts) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_Vk.enumerateDeviceExtensionProperties( - devices[i], - nullptr, - &extCount, - exts); - - bool found = false; - for (int j = 0; j < extCount; j++) { - const char* name = exts[j].extensionName; - if (strcmp(name, "VK_KHR_dynamic_rendering") == 0) { - found = true; - } - } - - palFree(s_Vk.allocator, exts); - if (!found) { - // skip - continue; - } - - if (outAdapters) { - if (deviceCount < *count) { - PalAdapter* adapter = (PalAdapter*)devices[i]; - outAdapters[deviceCount++] = adapter; - } - - } else { - deviceCount++; - } - } - } - - if (!outAdapters) { - *count = deviceCount; + s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, devices); + for (int i = 0; i < *count && i < deviceCount; i++) { + outAdapters[i] = (PalAdapter*)devices[i]; } palFree(s_Vk.allocator, devices); @@ -1623,8 +1555,17 @@ PalResult PAL_CALL getVkAdapterCapabilities( bool rayTracingFound = false; bool accelerateFound = false; + bool dynamicRendering = false; caps->features = 0; + Uint32 version = 0; + if (s_Vk.enumerateInstanceVersion) { + s_Vk.enumerateInstanceVersion(&version); + if (version >= VK_API_VERSION_1_3) { + dynamicRendering = true; + } + } + // clang-format off for (int i = 0; i < extensionCount; i++) { VkExtensionProperties* props = &extensionProps[i]; @@ -1634,6 +1575,9 @@ PalResult PAL_CALL getVkAdapterCapabilities( } else if (strcmp(props->extensionName, "VK_KHR_acceleration_structure") == 0) { accelerateFound = true; + } else if (strcmp(props->extensionName, "VK_KHR_dynamic_rendering") == 0) { + dynamicRendering = true; + } else if (strcmp(props->extensionName, "VK_EXT_mesh_shader") == 0) { // mesh shader VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; @@ -1820,6 +1764,10 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->features |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; } + if (dynamicRendering) { + caps->features |= PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING; + } + // this features are supported on vulkan caps->features |= PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW; caps->features |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; @@ -1953,11 +1901,14 @@ PalResult PAL_CALL createVkDevice( // clang-format on - extensions[extCount++] = "VK_KHR_dynamic_rendering"; if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { extensions[extCount++] = "VK_KHR_swapchain"; } + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { + extensions[extCount++] = "VK_KHR_dynamic_rendering"; + } + if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { extensions[extCount++] = "VK_KHR_timeline_semaphore"; timeline.timelineSemaphore = true; @@ -2156,6 +2107,7 @@ PalResult PAL_CALL createVkDevice( device->handle, "vkQueuePresentKHR"); + device->features = features; palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); @@ -2770,7 +2722,7 @@ PalResult PAL_CALL createVkSwapchain( PhysicalQueue* phyQueue = queue->phyQueue; // check if we enabled swapchain feature - if (!device->createSwapchain) { + if (!device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -2957,6 +2909,33 @@ PalResult PAL_CALL createVkShader( { VkResult result; PalShader* shader = nullptr; + VkShaderStageFlags stage = 0; + + if (info->type == PAL_SHADER_TYPE_VERTEX) { + stage = VK_SHADER_STAGE_VERTEX_BIT; + + } else if (info->type == PAL_SHADER_TYPE_PIXEL) { + stage = VK_SHADER_STAGE_FRAGMENT_BIT; + + } else if (info->type == PAL_SHADER_TYPE_COMPUTE) { + if (device->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + stage = VK_SHADER_STAGE_COMPUTE_BIT; + + } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_CONTROL) { + if (device->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + + } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_EVALUATION) { + if (device->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + } + shader = palAllocate(s_Vk.allocator, sizeof(PalShader), 0); if (!shader) { return PAL_RESULT_OUT_OF_MEMORY; @@ -2983,22 +2962,7 @@ PalResult PAL_CALL createVkShader( shader->info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader->info.module = shader->handle; shader->info.pName = "main"; - - if (info->type == PAL_SHADER_TYPE_VERTEX) { - shader->info.stage = VK_SHADER_STAGE_VERTEX_BIT; - - } else if (info->type == PAL_SHADER_TYPE_PIXEL) { - shader->info.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - - } else if (info->type == PAL_SHADER_TYPE_COMPUTE) { - shader->info.stage = VK_SHADER_STAGE_COMPUTE_BIT; - - } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_CONTROL) { - shader->info.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - - } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_EVALUATION) { - shader->info.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - } + shader->info.stage = stage; *outShader = shader; return PAL_RESULT_SUCCESS; diff --git a/tests/graphics_test.c b/tests/graphics_test.c index c3c00d67..dd8b31d4 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -283,6 +283,10 @@ bool graphicsTest() if (caps.features & PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW) { palLog(nullptr, " Cube array image view type"); } + + if (caps.features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { + palLog(nullptr, " Dynamic rendering"); + } palLog(nullptr, ""); } diff --git a/tests/tests_main.c b/tests/tests_main.c index 236feefc..67ef58da 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -56,13 +56,13 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS registerTest("Graphics Test", graphicsTest); - registerTest("Device Test", deviceTest); - registerTest("Image Test", imageTest); + // registerTest("Device Test", deviceTest); + // registerTest("Image Test", imageTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest("Queue Test", queueTest); - registerTest("Swapchain Test", swapchainTest); + // registerTest("Queue Test", queueTest); + // registerTest("Swapchain Test", swapchainTest); #endif runTests(); From b3749fc8b69da2a3f6716c8f1b17c86ad5e39c6d Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 7 Dec 2025 14:44:17 +0000 Subject: [PATCH 037/372] add renderpass api --- include/pal/pal_graphics.h | 35 +++++ src/graphics/pal_graphics.c | 106 +++++++++++++++- src/graphics/pal_vulkan.c | 194 ++++++++++++++++++++++++++++ tests/renderpass_test.c | 247 ++++++++++++++++++++++++++++++++++++ tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 3 +- 7 files changed, 585 insertions(+), 4 deletions(-) create mode 100644 tests/renderpass_test.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 1ef7cd34..2cf5519c 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -46,6 +46,7 @@ typedef struct PalSwapchain PalSwapchain; typedef struct PalImage PalImage; typedef struct PalImageView PalImageView; typedef struct PalShader PalShader; +typedef struct PalRenderPass PalRenderPass; typedef enum { PAL_ADAPTER_TYPE_UNKNOWN, @@ -277,6 +278,11 @@ typedef enum { PAL_SHADER_TYPE_TESSELLATION_EVALUATION } PalShaderType; +typedef enum { + PAL_ATTACHMENT_TYPE_COLOR, + PAL_ATTACHMENT_TYPE_DEPTH +} PalAttachmentType; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -342,6 +348,14 @@ typedef struct { PalImageUsages usages; } PalImageInfo; +typedef struct { + PalAttachmentType type; + PalLoadOp loadOp; + PalStoreOp storeOp; + PalImageView* target; + PalImageView* resolveTarget; +} PalAttachmentDesc; + typedef struct { bool memoryTypes[PAL_MEMORY_TYPE_MAX]; Uint64 size; @@ -385,6 +399,13 @@ typedef struct { Uint64 bytecodeSize; } PalShaderCreateInfo; +typedef struct { + Uint32 width; + Uint32 height; + Uint32 attachmentCount; + PalAttachmentDesc* attachments; +} PalRenderPassCreateInfo; + typedef struct { void* display; void* window; @@ -506,6 +527,13 @@ typedef struct { void PAL_CALL (*destroyShader)(PalShader* shader); PalShaderType PAL_CALL (*getShaderType)(PalShader* shader); + + PalResult PAL_CALL (*createRenderPass)( + PalDevice* device, + const PalRenderPassCreateInfo* info, + PalRenderPass** outRenderPass); + + void PAL_CALL (*destroyRenderPass)(PalRenderPass* renderPass); } PalGfxBackend; PAL_API PalResult PAL_CALL palAddGfxBackend(const PalGfxBackend* backend); @@ -632,6 +660,13 @@ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); PAL_API PalShaderType PAL_CALL palGetShaderType(PalShader* shader); +PAL_API PalResult PAL_CALL palCreateRenderPass( + PalDevice* device, + const PalRenderPassCreateInfo* info, + PalRenderPass** outRenderPass); + +PAL_API void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 950baea8..9f01b6de 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -233,6 +233,13 @@ void PAL_CALL destroyVkShader(PalShader* shader); PalShaderType PAL_CALL getVkShaderType(PalShader* shader); +PalResult PAL_CALL createVkRenderPass( + PalDevice* device, + const PalRenderPassCreateInfo* info, + PalRenderPass** outRenderPass); + +void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass); + static PalGfxBackend s_VkBackend = { .enumerateAdapters = enumerateVkAdapters, .getAdapterInfo = getVkAdapterInfo, @@ -262,7 +269,9 @@ static PalGfxBackend s_VkBackend = { .getSwapchainImage = getVkSwapchainImage, .createShader = createVkShader, .destroyShader = destroyVkShader, - .getShaderType = getVkShaderType + .getShaderType = getVkShaderType, + .createRenderPass = createVkRenderPass, + .destroyRenderPass = destroyVkRenderPass }; #endif // PAL_HAS_VULKAN @@ -1109,6 +1118,10 @@ PalImage* PAL_CALL palGetSwapchainImage( return TO_PAL_HANDLE(PalImage, imageIndex); } +// ================================================== +// Shader +// ================================================== + PalResult PAL_CALL palCreateShader( PalDevice* device, const PalShaderCreateInfo* info, @@ -1153,7 +1166,7 @@ PalResult PAL_CALL palCreateShader( shaderData->backend = data->backend; shaderData->handle = shader; - *outShader = TO_PAL_HANDLE(PalShader, shader); + *outShader = TO_PAL_HANDLE(PalShader, shaderIndex); return PAL_RESULT_SUCCESS; } @@ -1179,4 +1192,93 @@ PalShaderType PAL_CALL palGetShaderType(PalShader* shader) } } return PAL_SHADER_TYPE_UNDEFINED; +} + +// ================================================== +// Render Pass +// ================================================== + +PalResult PAL_CALL palCreateRenderPass( + PalDevice* device, + const PalRenderPassCreateInfo* info, + PalRenderPass** outRenderPass) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outRenderPass) { + return PAL_RESULT_NULL_POINTER; + } + + if (info->attachmentCount == 0 && info->attachments) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + PalAttachmentDesc attachments[16]; // should be fine + PalRenderPassCreateInfo createInfo = {0}; + createInfo.attachmentCount = info->attachmentCount; + createInfo.attachments = attachments; + + for (int i = 0; i < info->attachmentCount; i++) { + if (!info->attachments[i].target) { + return PAL_RESULT_NULL_POINTER; + } + + index = FROM_PAL_HANDLE(info->attachments[i].target); + HandleData* tmp = findHandleData(index); + attachments[i].target = tmp->handle; + attachments[i].loadOp = info->attachments[i].loadOp; + attachments[i].storeOp = info->attachments[i].storeOp; + attachments[i].type = info->attachments[i].type; + attachments[i].resolveTarget = nullptr; + + if (info->attachments[i].resolveTarget) { + index = FROM_PAL_HANDLE(info->attachments[i].target); + tmp = findHandleData(index); + attachments[i].resolveTarget = tmp->handle; + } + } + + // create a slot for the renderpass + Uint64 renderPassIndex = 0; + HandleData* renderPassData = getFreeHandleData(&renderPassIndex); + if (!renderPassData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalRenderPass* renderpass = nullptr; + PalResult ret; + ret = data->backend->createRenderPass( + data->handle, + &createInfo, + &renderpass); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + renderPassData->backend = data->backend; + renderPassData->handle = renderpass; + + *outRenderPass = TO_PAL_HANDLE(PalRenderPass, renderPassIndex); + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) +{ + if (s_Graphics.initialized && renderPass) { + Uint64 index = FROM_PAL_HANDLE(renderPass); + HandleData* data = findHandleData(index); + if (data) { + data->backend->destroyRenderPass(data->handle); + data->used = false; + } + } } \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 571ec4ac..e685bf3d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -63,6 +63,7 @@ typedef int (*wl_display_get_fd_fn)(struct wl_display*); #define VK_WIN32_PLATFORM 1 #define VK_XLIB_PLATFORM 2 #define VK_WAYLAND_PLATFORM 3 +#define MAX_ATTACHMENTS 16 // //TODO: should be fine but maybe 32 to be safe typedef struct { bool hasDebug; @@ -106,6 +107,10 @@ typedef struct { PFN_vkDestroyImage destroyImage; PFN_vkCreateShaderModule createShader; PFN_vkDestroyShaderModule destroyShader; + PFN_vkCreateRenderPass createRenderPass; + PFN_vkDestroyRenderPass destroyRenderPass; + PFN_vkCreateFramebuffer createFramebuffer; + PFN_vkDestroyFramebuffer destroyFramebuffer; PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; @@ -179,6 +184,19 @@ struct PalShader { VkPipelineShaderStageCreateInfo info; }; +struct PalRenderPass { + bool hasDepth; + Uint32 attachmentCount; + PalDevice* device; + VkRenderPass handle; + VkFramebuffer framebuffer; + VkAttachmentReference depthRef; + VkAttachmentDescription attachments[MAX_ATTACHMENTS]; + VkAttachmentReference colorRefs[MAX_ATTACHMENTS]; + VkAttachmentReference resolveRefs[MAX_ATTACHMENTS]; + VkImageView views[MAX_ATTACHMENTS]; +}; + static Vulkan s_Vk = {0}; // ================================================== @@ -1060,6 +1078,22 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroyShaderModule"); + s_Vk.createRenderPass = (PFN_vkCreateRenderPass)dlsym( + s_Vk.handle, + "vkCreateRenderPass"); + + s_Vk.destroyRenderPass = (PFN_vkDestroyRenderPass)dlsym( + s_Vk.handle, + "vkDestroyRenderPass"); + + s_Vk.createFramebuffer = (PFN_vkCreateFramebuffer)dlsym( + s_Vk.handle, + "vkCreateFramebuffer"); + + s_Vk.destroyFramebuffer = (PFN_vkDestroyFramebuffer)dlsym( + s_Vk.handle, + "vkDestroyFramebuffer"); + s_Vk.getPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)dlsym( s_Vk.handle, "vkGetPhysicalDeviceProperties2"); @@ -2521,6 +2555,13 @@ PalResult PAL_CALL createVkImageView( const PalImageViewCreateInfo* info, PalImageView** outImageView) { + // mimic the actual requested features at device creation + if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { + if (!(device->features & PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + VkResult result = VK_SUCCESS; PalImageView* imageView = nullptr; imageView = palAllocate(s_Vk.allocator, sizeof(PalImageView), 0); @@ -2983,4 +3024,157 @@ PalShaderType PAL_CALL getVkShaderType(PalShader* shader) return shader->type; } +PalResult PAL_CALL createVkRenderPass( + PalDevice* device, + const PalRenderPassCreateInfo* info, + PalRenderPass** outRenderPass) +{ + VkResult result; + PalRenderPass* renderpass = nullptr; + renderpass = palAllocate(s_Vk.allocator, sizeof(PalRenderPass), 0); + if (!renderpass) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + renderpass->hasDepth = false; + Uint32 colorRefCount = 0; + Uint32 layers = 0; + for (int i = 0; i < info->attachmentCount; i++) { + PalAttachmentDesc* desc = &info->attachments[i]; + VkAttachmentDescription* rDesc = &renderpass->attachments[i]; + + rDesc->format = palFormatToVk(desc->target->image->info.format); + rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + rDesc->samples = vkSamplesToSamples(desc->target->image->info.samples); + rDesc->flags = 0; + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + + layers = desc->target->image->info.depthOrArraySize; + if (desc->resolveTarget) { + // on legacy rendering, this should make but PAL supports both + // so we use the highest on legacy rendering + layers = desc->resolveTarget->image->info.depthOrArraySize; + } + + // load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + // store op + if (desc->storeOp == PAL_STORE_OP_STORE) { + rDesc->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + + } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { + rDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + + // add the image views from the attachments into a seperate array + renderpass->views[i] = desc->target->handle; + + if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { + VkAttachmentReference* ref = &renderpass->colorRefs[colorRefCount]; + rDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + ref->attachment = i; + ref->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + colorRefCount++; + if (desc->target->image->belongsToSwapchain) { + rDesc->finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + } + + } else { + rDesc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + rDesc->stencilLoadOp = rDesc->loadOp; + rDesc->stencilStoreOp = rDesc->storeOp; + VkAttachmentReference* ref = &renderpass->depthRef; + ref->attachment = i; + ref->layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + renderpass->hasDepth = true; + } + } + + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING)) { + // subpass + VkSubpassDescription subpassDesc = {0}; + subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDesc.colorAttachmentCount = colorRefCount; + subpassDesc.pColorAttachments = renderpass->colorRefs; + if (renderpass->hasDepth) { + subpassDesc.pDepthStencilAttachment = &renderpass->depthRef; + } + + // render pass + VkRenderPassCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + createInfo.attachmentCount = info->attachmentCount; + createInfo.pAttachments = renderpass->attachments; + createInfo.subpassCount = 1; + createInfo.pSubpasses = &subpassDesc; + + result = s_Vk.createRenderPass( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &renderpass->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, renderpass); + vkResultToPal(result); + } + + // create framebuffer + VkFramebufferCreateInfo fbCreateInfo = {0}; + fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fbCreateInfo.attachmentCount = info->attachmentCount; + fbCreateInfo.pAttachments = renderpass->views; + fbCreateInfo.height = info->height; + fbCreateInfo.width = info->width; + fbCreateInfo.layers = layers; + + result = s_Vk.createFramebuffer( + device->handle, + &fbCreateInfo, + &s_Vk.vkAllocator, + &renderpass->framebuffer); + + if (result != VK_SUCCESS) { + s_Vk.destroyRenderPass( + device->handle, + renderpass->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, renderpass); + // legacy rendering needs all image views to have + // the same layers/width/height + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + + renderpass->device = device; + *outRenderPass = renderpass; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass) +{ + s_Vk.destroyFramebuffer( + renderPass->device->handle, + renderPass->framebuffer, + &s_Vk.vkAllocator); + + s_Vk.destroyRenderPass( + renderPass->device->handle, + renderPass->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, renderPass); +} + #endif // PAL_HAS_VULKAN \ No newline at end of file diff --git a/tests/renderpass_test.c b/tests/renderpass_test.c new file mode 100644 index 00000000..23d6abf8 --- /dev/null +++ b/tests/renderpass_test.c @@ -0,0 +1,247 @@ + +#include "pal/pal_graphics.h" +#include "tests.h" + +bool renderPassTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Render Pass Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + // initialize the graphics system + PalResult result = palInitGraphics(false, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 count = 0; + result = palEnumerateAdapters(&count, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (count == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", count); + + // allocate an array of adapters or use a fixed array + // Example: PalAdapter* adapters[12]; + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&count, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + // filter the adapters for Vulkan + PalAdapter* vulkanAdapter = nullptr; + PalAdapterInfo info = {0}; + + for (Int32 i = 0; i < count; i++) { + PalAdapter* adapter = adapters[i]; + result = palGetAdapterInfo(adapter, &info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + palFree(nullptr, adapters); + return false; + } + + // check if its Vulkan + if (info.apiType == PAL_ADAPTER_API_TYPE_VULKAN) { + vulkanAdapter = adapter; + break; + } + } + + palFree(nullptr, adapters); + if (!vulkanAdapter) { + palLog(nullptr, "Failed to find a vulkan adapter"); + return false; + } + + // get capabilities about the adapter + PalAdapterCapabilities caps = {0}; + result = palGetAdapterCapabilities(vulkanAdapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + return false; + } + + // create a device with the vulkan adapter + PalDevice* device = nullptr; + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + result = palCreateDevice(vulkanAdapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a simple 2d image allocated on the gpu + // we can either enumerate all the supported formats andd choose one + // or we can choose our preffered format and check for support + + // use palEnumerateFormats() to get all supported formats + // and their image usages + + PalFormat format = PAL_FORMAT_R8G8B8A8_UNORM; + PalImageUsages usage = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; + if (!palIsFormatSupported(vulkanAdapter, format)) { + palLog(nullptr, "The preffered format is not supported"); + return false; + } + + if(!(usage & palQueryFormatImageUsages(vulkanAdapter, format))) { + palLog(nullptr, + "The preffered format does not support color attachement"); + return false; + } + + PalImage* image = nullptr; + PalImageCreateInfo imageCreateInfo = {0}; + imageCreateInfo.format = format; + imageCreateInfo.usages = usage; + imageCreateInfo.height = 240; + imageCreateInfo.mipLevelCount = 1; + imageCreateInfo.samples = 1; // very simple + imageCreateInfo.width = 320; + + // if the image type is 1D or 2D + // PalImageCreateInfo::depthOrArraySize is used for the array size + imageCreateInfo.type = PAL_IMAGE_TYPE_2D; + imageCreateInfo.depthOrArraySize = 1; + + result = palCreateImage(device, &imageCreateInfo, &image); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image: %s", error); + return false; + } + + // bind memory to the create image + PalMemoryRequirements imageMemReq; + result = palGetImageMemoryRequirements(device, image, &imageMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image memory requirements: %s", error); + return false; + } + + // allocate memory for the image + if (!imageMemReq.memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY]) { + palLog(nullptr, "Cannot allocate gpu only memory"); + } + + PalMemory* imageMemory = nullptr; + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + imageMemReq.size, + &imageMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for image: %s", error); + return false; + } + + PalImageViewUsages viewUsage = PAL_IMAGE_VIEW_USAGE_COLOR; + if(!(viewUsage & palQueryFormatImageViewUsages(vulkanAdapter, format))) { + palLog(nullptr, + "The preffered format does not support color image view"); + return false; + } + + // create an image view from the image + PalImageView* imageView = nullptr; + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.startMipLevel = 0; // start from the first + imageViewCreateInfo.startArrayLayer = 0; // start from the first + imageViewCreateInfo.layerArrayCount = imageCreateInfo.depthOrArraySize; + imageViewCreateInfo.mipLevelCount = imageCreateInfo.mipLevelCount; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.usages = viewUsage; + + result = palCreateImageView( + device, + image, + &imageViewCreateInfo, + &imageView); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + + // bind the memory to the image + result = palBindImageMemory( + device, + image, + imageMemory, + PAL_DEFAULT_MEMORY_OFFSET); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind image memory: %s", error); + return false; + } + + // create renderpass + PalRenderPass* renderPass = nullptr; + PalRenderPassCreateInfo renderpassCreateInfo = {0}; + + // color attachment + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.type = PAL_ATTACHMENT_TYPE_COLOR; + colorAttachment.target = imageView; + + renderpassCreateInfo.attachmentCount = 1; + renderpassCreateInfo.attachments = &colorAttachment; + result = palCreateRenderPass(device, &renderpassCreateInfo, &renderPass); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create renderpass: %s", error); + return false; + } + + // destroy renderpass + palDestroyRenderPass(renderPass); + + // destroy image view + palDestroyImageView(imageView); + + // destroy image + palDestroyImage(image); + + // free the image memory + palFreeMemory(device, imageMemory); + + // destroy the device + palDestroyDevice(device); + + // shutdown the graphics system + palShutdownGraphics(); + + return true; +} \ No newline at end of file diff --git a/tests/tests.h b/tests/tests.h index b842a06e..191850d1 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -58,6 +58,7 @@ bool graphicsTest(); bool customGraphicsBackendTest(); bool deviceTest(); bool imageTest(); +bool renderPassTest(); // graphics and video bool queueTest(); diff --git a/tests/tests.lua b/tests/tests.lua index ae39a869..aacdacef 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -67,7 +67,8 @@ project "tests" files { "graphics_test.c", "device_test.c", - "image_test.c" + "image_test.c", + "renderpass_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 67ef58da..4613ee2f 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,9 +55,10 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + // registerTest("Graphics Test", graphicsTest); // registerTest("Device Test", deviceTest); // registerTest("Image Test", imageTest); + registerTest("Render Pass Test", renderPassTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From 5b2159bf0b98956bc44fe3650ce4c4a51dc9aafd Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Dec 2025 12:52:07 +0000 Subject: [PATCH 038/372] remove API check tests --- include/pal/pal_graphics.h | 22 +-- src/graphics/pal_graphics.c | 20 +-- src/graphics/pal_vulkan.c | 53 +++++- tests/image_test.c | 225 ------------------------ tests/queue_test.c | 174 ------------------- tests/renderpass_test.c | 247 --------------------------- tests/swapchain_test.c | 330 ------------------------------------ 7 files changed, 69 insertions(+), 1002 deletions(-) delete mode 100644 tests/image_test.c delete mode 100644 tests/queue_test.c delete mode 100644 tests/renderpass_test.c delete mode 100644 tests/swapchain_test.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 2cf5519c..2ddd3bfd 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -43,6 +43,7 @@ typedef struct PalDevice PalDevice; typedef struct PalMemory PalMemory; typedef struct PalQueue PalQueue; typedef struct PalSwapchain PalSwapchain; + typedef struct PalImage PalImage; typedef struct PalImageView PalImageView; typedef struct PalShader PalShader; @@ -265,7 +266,7 @@ typedef enum { PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB, PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10, - PAL_SWAPCHAIN_FORMAT_MAX // more pars will be added + PAL_SWAPCHAIN_FORMAT_MAX } PalSwapchainFormat; typedef enum { @@ -409,7 +410,7 @@ typedef struct { typedef struct { void* display; void* window; -} PalGfxWindow; +} PalGraphicsWindow; typedef struct { PalResult PAL_CALL (*enumerateAdapters)( @@ -450,7 +451,7 @@ typedef struct { bool PAL_CALL (*canQueuePresent)( PalQueue* queue, - PalGfxWindow* window); + PalGraphicsWindow* window); PalResult PAL_CALL (*enumerateFormats)( PalAdapter* adapter, @@ -501,13 +502,13 @@ typedef struct { PalResult PAL_CALL (*querySwapchainCapabilities)( PalAdapter* adapter, - PalGfxWindow* window, + PalGraphicsWindow* window, PalSwapchainCapabilities* caps); PalResult PAL_CALL (*createSwapchain)( PalDevice* device, PalQueue* queue, - PalGfxWindow* window, + PalGraphicsWindow* window, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain); @@ -534,9 +535,10 @@ typedef struct { PalRenderPass** outRenderPass); void PAL_CALL (*destroyRenderPass)(PalRenderPass* renderPass); -} PalGfxBackend; +} PalGraphicsBackend; -PAL_API PalResult PAL_CALL palAddGfxBackend(const PalGfxBackend* backend); +PAL_API PalResult PAL_CALL palAddGraphicsBackend( + const PalGraphicsBackend* backend); PAL_API PalResult PAL_CALL palInitGraphics( bool enableDebugLayer, @@ -582,7 +584,7 @@ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); PAL_API bool PAL_CALL palCanQueuePresent( PalQueue* queue, - PalGfxWindow* window); + PalGraphicsWindow* window); PAL_API PalResult PAL_CALL palEnumerateFormats( PalAdapter* adapter, @@ -633,13 +635,13 @@ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( PalAdapter* adapter, - PalGfxWindow* window, + PalGraphicsWindow* window, PalSwapchainCapabilities* caps); PAL_API PalResult PAL_CALL palCreateSwapchain( PalDevice* device, PalQueue* queue, - PalGfxWindow* window, + PalGraphicsWindow* window, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 9f01b6de..38dc9874 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -38,13 +38,13 @@ freely, subject to the following restrictions: typedef struct { bool used; void* handle; - const PalGfxBackend* backend; + const PalGraphicsBackend* backend; } HandleData; typedef struct { Int32 count; Int32 startIndex; - const PalGfxBackend* base; + const PalGraphicsBackend* base; } BackendData; typedef struct { @@ -155,7 +155,7 @@ void PAL_CALL destroyVkQueue(PalQueue* queue); bool PAL_CALL canVkQueuePresent( PalQueue* queue, - PalGfxWindow* window); + PalGraphicsWindow* window); PalResult PAL_CALL enumerateVkFormats( PalAdapter* adapter, @@ -206,13 +206,13 @@ void PAL_CALL destroyVkImageView(PalImageView* imageView); PalResult PAL_CALL queryVkSwapchainCapabilities( PalAdapter* adapter, - PalGfxWindow* window, + PalGraphicsWindow* window, PalSwapchainCapabilities* caps); PalResult PAL_CALL createVkSwapchain( PalDevice* device, PalQueue* queue, - PalGfxWindow* window, + PalGraphicsWindow* window, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain); @@ -240,7 +240,7 @@ PalResult PAL_CALL createVkRenderPass( void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass); -static PalGfxBackend s_VkBackend = { +static PalGraphicsBackend s_VkBackend = { .enumerateAdapters = enumerateVkAdapters, .getAdapterInfo = getVkAdapterInfo, .getAdapterCapabilities = getVkAdapterCapabilities, @@ -288,7 +288,7 @@ static PalGfxBackend s_VkBackend = { // Public API // ================================================== -PalResult PAL_CALL palAddGfxBackend(const PalGfxBackend* backend) +PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) { if (s_Graphics.initialized) { return PAL_RESULT_INVALID_BACKEND; @@ -670,7 +670,7 @@ void PAL_CALL palDestroyQueue(PalQueue* queue) bool PAL_CALL palCanQueuePresent( PalQueue* queue, - PalGfxWindow* window) + PalGraphicsWindow* window) { if (s_Graphics.initialized && queue) { Uint64 index = FROM_PAL_HANDLE(queue); @@ -981,7 +981,7 @@ void PAL_CALL palDestroyImageView(PalImageView* imageView) PalResult PAL_CALL palQuerySwapchainCapabilities( PalAdapter* adapter, - PalGfxWindow* window, + PalGraphicsWindow* window, PalSwapchainCapabilities* caps) { if (!s_Graphics.initialized) { @@ -1007,7 +1007,7 @@ PalResult PAL_CALL palQuerySwapchainCapabilities( PalResult PAL_CALL palCreateSwapchain( PalDevice* device, PalQueue* queue, - PalGfxWindow* window, + PalGraphicsWindow* window, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain) { diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e685bf3d..9956ae1c 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -48,6 +48,7 @@ typedef int (*wl_display_get_fd_fn)(struct wl_display*); #include #include + #define VK_LIB_NAME "libvulkan.so" #else @@ -63,7 +64,7 @@ typedef int (*wl_display_get_fd_fn)(struct wl_display*); #define VK_WIN32_PLATFORM 1 #define VK_XLIB_PLATFORM 2 #define VK_WAYLAND_PLATFORM 3 -#define MAX_ATTACHMENTS 16 // //TODO: should be fine but maybe 32 to be safe +#define MAX_ATTACHMENTS 32 typedef struct { bool hasDebug; @@ -200,7 +201,7 @@ struct PalRenderPass { static Vulkan s_Vk = {0}; // ================================================== -// API +// Helper Functions // ================================================== static Uint32 checkPlatform(struct wl_display* display) @@ -222,7 +223,7 @@ static Uint32 checkPlatform(struct wl_display* display) } static bool createSurface( - PalGfxWindow* window, + PalGraphicsWindow* window, VkSurfaceKHR* outSurface) { Uint32 platform = checkPlatform(window->display); @@ -983,6 +984,10 @@ static void* vkRealloc( return nullptr; } +// ================================================== +// Adapter +// ================================================== + PalResult PAL_CALL initGraphicsVk( bool enableDebugLayer, const PalAllocator* allocator) @@ -1810,6 +1815,10 @@ PalResult PAL_CALL getVkAdapterCapabilities( return PAL_RESULT_SUCCESS; } +// ================================================== +// Device +// ================================================== + PalResult PAL_CALL createVkDevice( PalAdapter* adapter, PalAdapterFeatures features, @@ -2156,6 +2165,10 @@ void PAL_CALL destroyVkDevice(PalDevice* device) palFree(s_Vk.allocator, device); } +// ================================================== +// Memory +// ================================================== + PalResult PAL_CALL allocateVkMemory( PalDevice* device, PalMemoryType type, @@ -2195,6 +2208,10 @@ void PAL_CALL freeVkMemory( s_Vk.freeMemory(device->handle, mem, &s_Vk.vkAllocator); } +// ================================================== +// Queue +// ================================================== + PalResult PAL_CALL createVkQueue( PalDevice* device, PalQueueType type, @@ -2266,7 +2283,7 @@ void PAL_CALL destroyVkQueue(PalQueue* queue) bool PAL_CALL canVkQueuePresent( PalQueue* queue, - PalGfxWindow* window) + PalGraphicsWindow* window) { // check if the queue is a graphics queue before we check its family // index for presentation support. @@ -2291,6 +2308,10 @@ bool PAL_CALL canVkQueuePresent( return false; } +// ================================================== +// Formats +// ================================================== + PalResult PAL_CALL enumerateVkFormats( PalAdapter* adapter, Int32* count, @@ -2413,6 +2434,10 @@ PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( return usages; } +// ================================================== +// Image +// ================================================== + PalResult PAL_CALL createVkImage( PalDevice* device, const PalImageCreateInfo* info, @@ -2549,6 +2574,10 @@ PalResult PAL_CALL bindVkImageMemory( s_Vk.bindImageMemory(device->handle, image->handle, mem, offset); } +// ================================================== +// Image View +// ================================================== + PalResult PAL_CALL createVkImageView( PalDevice* device, PalImage* image, @@ -2624,9 +2653,13 @@ void PAL_CALL destroyVkImageView(PalImageView* imageView) palFree(s_Vk.allocator, imageView); } +// ================================================== +// Swapchain +// ================================================== + PalResult PAL_CALL queryVkSwapchainCapabilities( PalAdapter* adapter, - PalGfxWindow* window, + PalGraphicsWindow* window, PalSwapchainCapabilities* caps) { Int32 formatCount = 0; @@ -2753,7 +2786,7 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( PalResult PAL_CALL createVkSwapchain( PalDevice* device, PalQueue* queue, - PalGfxWindow* window, + PalGraphicsWindow* window, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain) { @@ -2943,6 +2976,10 @@ PalImage* PAL_CALL getVkSwapchainImage( return (PalImage*)&swapchain->images[index]; } +// ================================================== +// Shader +// ================================================== + PalResult PAL_CALL createVkShader( PalDevice* device, const PalShaderCreateInfo* info, @@ -3024,6 +3061,10 @@ PalShaderType PAL_CALL getVkShaderType(PalShader* shader) return shader->type; } +// ================================================== +// Render Pass +// ================================================== + PalResult PAL_CALL createVkRenderPass( PalDevice* device, const PalRenderPassCreateInfo* info, diff --git a/tests/image_test.c b/tests/image_test.c deleted file mode 100644 index 7b664452..00000000 --- a/tests/image_test.c +++ /dev/null @@ -1,225 +0,0 @@ - -#include "pal/pal_graphics.h" -#include "tests.h" - -bool imageTest() -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Image Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - // initialize the graphics system - PalResult result = palInitGraphics(false, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; - } - - // enumerate all available adapters - Int32 count = 0; - result = palEnumerateAdapters(&count, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - if (count == 0) { - palLog(nullptr, "No adapters found"); - return false; - } - palLog(nullptr, "Adapter count: %d", count); - - // allocate an array of adapters or use a fixed array - // Example: PalAdapter* adapters[12]; - PalAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); - if (!adapters) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - result = palEnumerateAdapters(&count, adapters); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - // filter the adapters for Vulkan - PalAdapter* vulkanAdapter = nullptr; - PalAdapterInfo info = {0}; - - for (Int32 i = 0; i < count; i++) { - PalAdapter* adapter = adapters[i]; - result = palGetAdapterInfo(adapter, &info); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - palFree(nullptr, adapters); - return false; - } - - // check if its Vulkan - if (info.apiType == PAL_ADAPTER_API_TYPE_VULKAN) { - vulkanAdapter = adapter; - break; - } - } - - palFree(nullptr, adapters); - if (!vulkanAdapter) { - palLog(nullptr, "Failed to find a vulkan adapter"); - return false; - } - - // get capabilities about the adapter - PalAdapterCapabilities caps = {0}; - result = palGetAdapterCapabilities(vulkanAdapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); - return false; - } - - // create a device with the vulkan adapter - PalDevice* device = nullptr; - PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; - result = palCreateDevice(vulkanAdapter, features, &device); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); - return false; - } - - // create a simple 2d image allocated on the gpu - // we can either enumerate all the supported formats andd choose one - // or we can choose our preffered format and check for support - - // use palEnumerateFormats() to get all supported formats - // and their image usages - - PalFormat format = PAL_FORMAT_R8G8B8A8_UNORM; - PalImageUsages usage = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; - if (!palIsFormatSupported(vulkanAdapter, format)) { - palLog(nullptr, "The preffered format is not supported"); - return false; - } - - if(!(usage & palQueryFormatImageUsages(vulkanAdapter, format))) { - palLog(nullptr, - "The preffered format does not support color attachement"); - return false; - } - - PalImage* image = nullptr; - PalImageCreateInfo imageCreateInfo = {0}; - imageCreateInfo.format = format; - imageCreateInfo.usages = usage; - imageCreateInfo.height = 240; - imageCreateInfo.mipLevelCount = 1; - imageCreateInfo.samples = 1; // very simple - imageCreateInfo.width = 320; - - // if the image type is 1D or 2D - // PalImageCreateInfo::depthOrArraySize is used for the array size - imageCreateInfo.type = PAL_IMAGE_TYPE_2D; - imageCreateInfo.depthOrArraySize = 1; - - result = palCreateImage(device, &imageCreateInfo, &image); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image: %s", error); - return false; - } - - // bind memory to the create image - PalMemoryRequirements imageMemReq; - result = palGetImageMemoryRequirements(device, image, &imageMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image memory requirements: %s", error); - return false; - } - - // allocate memory for the image - if (!imageMemReq.memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY]) { - palLog(nullptr, "Cannot allocate gpu only memory"); - } - - PalMemory* imageMemory = nullptr; - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - imageMemReq.size, - &imageMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for image: %s", error); - return false; - } - - PalImageViewUsages viewUsage = PAL_IMAGE_VIEW_USAGE_COLOR; - if(!(viewUsage & palQueryFormatImageViewUsages(vulkanAdapter, format))) { - palLog(nullptr, - "The preffered format does not support color image view"); - return false; - } - - // create an image view from the image - PalImageView* imageView = nullptr; - PalImageViewCreateInfo imageViewCreateInfo = {0}; - imageViewCreateInfo.startMipLevel = 0; // start from the first - imageViewCreateInfo.startArrayLayer = 0; // start from the first - imageViewCreateInfo.layerArrayCount = imageCreateInfo.depthOrArraySize; - imageViewCreateInfo.mipLevelCount = imageCreateInfo.mipLevelCount; - imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.usages = viewUsage; - - result = palCreateImageView( - device, - image, - &imageViewCreateInfo, - &imageView); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); - return false; - } - - // bind the memory to the image - result = palBindImageMemory( - device, - image, - imageMemory, - PAL_DEFAULT_MEMORY_OFFSET); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind image memory: %s", error); - return false; - } - - - // destroy image view - palDestroyImageView(imageView); - - // destroy image - palDestroyImage(image); - - // free the image memory - palFreeMemory(device, imageMemory); - - // destroy the device - palDestroyDevice(device); - - // shutdown the graphics system - palShutdownGraphics(); - - return true; -} \ No newline at end of file diff --git a/tests/queue_test.c b/tests/queue_test.c deleted file mode 100644 index 47f7ba45..00000000 --- a/tests/queue_test.c +++ /dev/null @@ -1,174 +0,0 @@ - -#include "pal/pal_graphics.h" -#include "pal/pal_video.h" -#include "tests.h" - -bool queueTest() -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Queue Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - // initialize the graphics system - PalResult result = palInitGraphics(false, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; - } - - // enumerate all available adapters - Int32 count = 0; - result = palEnumerateAdapters(&count, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - if (count == 0) { - palLog(nullptr, "No adapters found"); - return false; - } - palLog(nullptr, "Adapter count: %d", count); - - // allocate an array of adapters or use a fixed array - // Example: PalAdapter* adapters[12]; - PalAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); - if (!adapters) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - result = palEnumerateAdapters(&count, adapters); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - // filter the adapters for Vulkan - PalAdapter* vulkanAdapter = nullptr; - PalAdapterInfo info = {0}; - - for (Int32 i = 0; i < count; i++) { - PalAdapter* adapter = adapters[i]; - result = palGetAdapterInfo(adapter, &info); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - palFree(nullptr, adapters); - return false; - } - - // check if its Vulkan - if (info.apiType == PAL_ADAPTER_API_TYPE_VULKAN) { - vulkanAdapter = adapter; - break; - } - } - - palFree(nullptr, adapters); - if (!vulkanAdapter) { - palLog(nullptr, "Failed to find a vulkan adapter"); - return false; - } - - // get capabilities about the adapter - PalAdapterCapabilities caps = {0}; - result = palGetAdapterCapabilities(vulkanAdapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } - - if (caps.maxGraphicsQueues == 0) { - palLog(nullptr, "adapter does not support graphics queues"); - return false; - } - - // create a device with the vulkan adapter - PalDevice* device = nullptr; - PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; - - // enable multi viewport if supported - if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { - features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; - } - - result = palCreateDevice(vulkanAdapter, features, &device); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); - return false; - } - - // create a graphics queue - PalQueue* gfxQueue = nullptr; - result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &gfxQueue); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); - return false; - } - - // check if the graphics queue we created is presentable - // to the provided window. we need a window - result = palInitVideo(nullptr, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; - } - - PalWindow* window = nullptr; - PalWindowCreateInfo createInfo = {0}; - createInfo.height = 480; - createInfo.width = 640; - createInfo.show = true; - - // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); - if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { - // if we dont support, we need to create a borderless window - // and create the decorations ourselves - createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; - } - - result = palCreateWindow(&createInfo, &window); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; - } - - PalGfxWindow gfxWindow = {0}; - PalWindowHandleInfo winInfo = palGetWindowHandleInfo(window); - gfxWindow.display = winInfo.nativeDisplay; - gfxWindow.window = winInfo.nativeWindow; - - bool canPresent = palCanQueuePresent(gfxQueue, &gfxWindow); - const char* boolString = "True"; - if (!canPresent) { - boolString = "False"; - } - palLog(nullptr, "Graphics queue presentable: %s", boolString); - - palDestroyWindow(window); - palShutdownVideo(); - - // destroy the graphics queue - palDestroyQueue(gfxQueue); - - // destroy the device - palDestroyDevice(device); - - // shutdown the graphics system - palShutdownGraphics(); - - return true; -} \ No newline at end of file diff --git a/tests/renderpass_test.c b/tests/renderpass_test.c deleted file mode 100644 index 23d6abf8..00000000 --- a/tests/renderpass_test.c +++ /dev/null @@ -1,247 +0,0 @@ - -#include "pal/pal_graphics.h" -#include "tests.h" - -bool renderPassTest() -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Render Pass Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - // initialize the graphics system - PalResult result = palInitGraphics(false, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; - } - - // enumerate all available adapters - Int32 count = 0; - result = palEnumerateAdapters(&count, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - if (count == 0) { - palLog(nullptr, "No adapters found"); - return false; - } - palLog(nullptr, "Adapter count: %d", count); - - // allocate an array of adapters or use a fixed array - // Example: PalAdapter* adapters[12]; - PalAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); - if (!adapters) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - result = palEnumerateAdapters(&count, adapters); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - // filter the adapters for Vulkan - PalAdapter* vulkanAdapter = nullptr; - PalAdapterInfo info = {0}; - - for (Int32 i = 0; i < count; i++) { - PalAdapter* adapter = adapters[i]; - result = palGetAdapterInfo(adapter, &info); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - palFree(nullptr, adapters); - return false; - } - - // check if its Vulkan - if (info.apiType == PAL_ADAPTER_API_TYPE_VULKAN) { - vulkanAdapter = adapter; - break; - } - } - - palFree(nullptr, adapters); - if (!vulkanAdapter) { - palLog(nullptr, "Failed to find a vulkan adapter"); - return false; - } - - // get capabilities about the adapter - PalAdapterCapabilities caps = {0}; - result = palGetAdapterCapabilities(vulkanAdapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); - return false; - } - - // create a device with the vulkan adapter - PalDevice* device = nullptr; - PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; - result = palCreateDevice(vulkanAdapter, features, &device); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); - return false; - } - - // create a simple 2d image allocated on the gpu - // we can either enumerate all the supported formats andd choose one - // or we can choose our preffered format and check for support - - // use palEnumerateFormats() to get all supported formats - // and their image usages - - PalFormat format = PAL_FORMAT_R8G8B8A8_UNORM; - PalImageUsages usage = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; - if (!palIsFormatSupported(vulkanAdapter, format)) { - palLog(nullptr, "The preffered format is not supported"); - return false; - } - - if(!(usage & palQueryFormatImageUsages(vulkanAdapter, format))) { - palLog(nullptr, - "The preffered format does not support color attachement"); - return false; - } - - PalImage* image = nullptr; - PalImageCreateInfo imageCreateInfo = {0}; - imageCreateInfo.format = format; - imageCreateInfo.usages = usage; - imageCreateInfo.height = 240; - imageCreateInfo.mipLevelCount = 1; - imageCreateInfo.samples = 1; // very simple - imageCreateInfo.width = 320; - - // if the image type is 1D or 2D - // PalImageCreateInfo::depthOrArraySize is used for the array size - imageCreateInfo.type = PAL_IMAGE_TYPE_2D; - imageCreateInfo.depthOrArraySize = 1; - - result = palCreateImage(device, &imageCreateInfo, &image); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image: %s", error); - return false; - } - - // bind memory to the create image - PalMemoryRequirements imageMemReq; - result = palGetImageMemoryRequirements(device, image, &imageMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image memory requirements: %s", error); - return false; - } - - // allocate memory for the image - if (!imageMemReq.memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY]) { - palLog(nullptr, "Cannot allocate gpu only memory"); - } - - PalMemory* imageMemory = nullptr; - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - imageMemReq.size, - &imageMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for image: %s", error); - return false; - } - - PalImageViewUsages viewUsage = PAL_IMAGE_VIEW_USAGE_COLOR; - if(!(viewUsage & palQueryFormatImageViewUsages(vulkanAdapter, format))) { - palLog(nullptr, - "The preffered format does not support color image view"); - return false; - } - - // create an image view from the image - PalImageView* imageView = nullptr; - PalImageViewCreateInfo imageViewCreateInfo = {0}; - imageViewCreateInfo.startMipLevel = 0; // start from the first - imageViewCreateInfo.startArrayLayer = 0; // start from the first - imageViewCreateInfo.layerArrayCount = imageCreateInfo.depthOrArraySize; - imageViewCreateInfo.mipLevelCount = imageCreateInfo.mipLevelCount; - imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.usages = viewUsage; - - result = palCreateImageView( - device, - image, - &imageViewCreateInfo, - &imageView); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); - return false; - } - - // bind the memory to the image - result = palBindImageMemory( - device, - image, - imageMemory, - PAL_DEFAULT_MEMORY_OFFSET); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind image memory: %s", error); - return false; - } - - // create renderpass - PalRenderPass* renderPass = nullptr; - PalRenderPassCreateInfo renderpassCreateInfo = {0}; - - // color attachment - PalAttachmentDesc colorAttachment = {0}; - colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; - colorAttachment.storeOp = PAL_STORE_OP_STORE; - colorAttachment.type = PAL_ATTACHMENT_TYPE_COLOR; - colorAttachment.target = imageView; - - renderpassCreateInfo.attachmentCount = 1; - renderpassCreateInfo.attachments = &colorAttachment; - result = palCreateRenderPass(device, &renderpassCreateInfo, &renderPass); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create renderpass: %s", error); - return false; - } - - // destroy renderpass - palDestroyRenderPass(renderPass); - - // destroy image view - palDestroyImageView(imageView); - - // destroy image - palDestroyImage(image); - - // free the image memory - palFreeMemory(device, imageMemory); - - // destroy the device - palDestroyDevice(device); - - // shutdown the graphics system - palShutdownGraphics(); - - return true; -} \ No newline at end of file diff --git a/tests/swapchain_test.c b/tests/swapchain_test.c deleted file mode 100644 index 6dc0c603..00000000 --- a/tests/swapchain_test.c +++ /dev/null @@ -1,330 +0,0 @@ - -#include "pal/pal_graphics.h" -#include "pal/pal_video.h" -#include "tests.h" - -bool swapchainTest() -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Swapchain Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - // initialize the graphics system - PalResult result = palInitGraphics(false, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; - } - - // enumerate all available adapters - Int32 count = 0; - result = palEnumerateAdapters(&count, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - if (count == 0) { - palLog(nullptr, "No adapters found"); - return false; - } - palLog(nullptr, "Adapter count: %d", count); - - // allocate an array of adapters or use a fixed array - // Example: PalAdapter* adapters[12]; - PalAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); - if (!adapters) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - result = palEnumerateAdapters(&count, adapters); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - // filter the adapters for Vulkan - PalAdapter* vulkanAdapter = nullptr; - PalAdapterInfo info = {0}; - - for (Int32 i = 0; i < count; i++) { - PalAdapter* adapter = adapters[i]; - result = palGetAdapterInfo(adapter, &info); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - palFree(nullptr, adapters); - return false; - } - - // check if its Vulkan - if (info.apiType == PAL_ADAPTER_API_TYPE_VULKAN) { - vulkanAdapter = adapter; - break; - } - } - - palFree(nullptr, adapters); - if (!vulkanAdapter) { - palLog(nullptr, "Failed to find a vulkan adapter"); - return false; - } - - // get capabilities about the adapter - PalAdapterCapabilities caps = {0}; - result = palGetAdapterCapabilities(vulkanAdapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } - - if (caps.maxGraphicsQueues == 0) { - palLog(nullptr, "adapter does not support graphics queues"); - return false; - } - - // create a device with the vulkan adapter - PalDevice* device = nullptr; - PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; - - // enable multi viewport if supported - if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { - features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; - } - - result = palCreateDevice(vulkanAdapter, features, &device); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); - return false; - } - - // create a graphics queue - PalQueue* gfxQueue = nullptr; - result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &gfxQueue); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); - return false; - } - - /// we need a window. We use PAL video system to create the window - result = palInitVideo(nullptr, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; - } - - PalWindow* window = nullptr; - PalWindowCreateInfo createInfo = {0}; - createInfo.height = 480; - createInfo.width = 640; - createInfo.show = true; - - // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); - if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { - // if we dont support, we need to create a borderless window - // and create the decorations ourselves - createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; - } - - result = palCreateWindow(&createInfo, &window); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; - } - - PalGfxWindow gfxWindow = {0}; - PalWindowHandleInfo winInfo = palGetWindowHandleInfo(window); - gfxWindow.display = winInfo.nativeDisplay; - gfxWindow.window = winInfo.nativeWindow; - - bool canPresent = palCanQueuePresent(gfxQueue, &gfxWindow); - if (!canPresent) { - palLog(nullptr, "Queue could not present to window"); - return false; - } - - // query swapchain capabilities of the adapter and the window - PalSwapchainCapabilities swapchainCaps = {0}; - result = palQuerySwapchainCapabilities( - vulkanAdapter, - &gfxWindow, - &swapchainCaps); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query swapchain capabilities: %s", error); - return false; - } - - // log swapchain capabilities - Uint32 imageArrayLayers = swapchainCaps.maxImageArrayLayers; - palLog(nullptr, "Swapchain capabilities:"); - palLog(nullptr, " Min image count: %d", swapchainCaps.minImageCount); - palLog(nullptr, " Max image count: %d", swapchainCaps.maxImageCount); - palLog(nullptr, " Max image array layers: %d", imageArrayLayers); - - palLog(nullptr, " Min image width: %d", swapchainCaps.minImageWidth); - palLog(nullptr, " Min image height: %d", swapchainCaps.minImageHeight); - palLog(nullptr, " Max image width: %d", swapchainCaps.maxImageWidth); - palLog(nullptr, " Max image height: %d", swapchainCaps.maxImageHeight); - - palLog(nullptr, " Supported formats:"); - if (swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB]) { - palLog(nullptr, " BGRA8 SRGB SRGB"); - } - - if (swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB]) { - palLog(nullptr, " BGRA8 UNORM SRGB"); - } - - if (swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10]) { - palLog(nullptr, " RGBA16 FLOAT HDR10"); - } - - if (swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { - palLog(nullptr, " RGBA8 UNORM SRGB"); - } - - palLog(nullptr, " Supported present modes:"); - if (swapchainCaps.presentModes[PAL_PRESENT_MODE_FIFO]) { - palLog(nullptr, " FIFO"); - } - - if (swapchainCaps.presentModes[PAL_PRESENT_MODE_IMMEDIATE]) { - palLog(nullptr, " Immediate"); - } - - if (swapchainCaps.presentModes[PAL_PRESENT_MODE_MAILBOX]) { - palLog(nullptr, " Mailbox"); - } - - palLog(nullptr, " Supported composite alphas:"); - if (swapchainCaps.compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE]) { - palLog(nullptr, " Opaque"); - } - - if (swapchainCaps.compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED]) { - palLog(nullptr, " Pre Multiplied"); - } - - if (swapchainCaps.compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED]) { - palLog(nullptr, " Post Multiplied"); - } - - // create swapchain - PalSwapchain* swapchain = nullptr; - PalSwapchainCreateInfo swapchainCreateInfo = {0}; - swapchainCreateInfo.clipped = true; - swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - swapchainCreateInfo.imageArrayLayerCount = 1; // 2 VR - - // check the number and increment it but not passed - // PalSwapchainCapabilities::maxImageCount - swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; - swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - - // set size - swapchainCreateInfo.width = 640; - swapchainCreateInfo.height = 480; - if (640 > swapchainCaps.maxImageWidth) { - // we set it to the minimal to mak it work across systems - swapchainCreateInfo.width = swapchainCaps.minImageWidth; - } - - if (480 > swapchainCaps.maxImageHeight) { - // we set it to the minimal to mak it work across systems - swapchainCreateInfo.height = swapchainCaps.minImageHeight; - } - - result = palCreateSwapchain( - device, - gfxQueue, - &gfxWindow, - &swapchainCreateInfo, - &swapchain); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create swapchain: %s", error); - return false; - } - - // if you need to get all images and create image views for them - // use palGetSwapchainImage() to get the image count. - // but this is the same number as the requested images - // when creating the swapchain - - // we only get the first image and use it for our needs - PalImage* swapchainImage = palGetSwapchainImage(swapchain, 0); - if (!swapchainImage) { - palLog(nullptr, "Failed to get swapchain image"); - return false; - } - - // create an image view for the image - // swapchain images do not need memory to be bound to them - PalImageView* imageView = nullptr; - PalImageViewCreateInfo imageViewCreateInfo = {0}; - PalImageInfo imageInfo = {0}; - - // get the swapchain info and use it to create the image view - result = palGetImageInfo(swapchainImage, &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); - return false; - } - - imageViewCreateInfo.layerArrayCount = imageInfo.depthOrArraySize; - imageViewCreateInfo.mipLevelCount = imageInfo.mipLevelCount; - imageViewCreateInfo.startArrayLayer = 0; // always 0 for swapchain - imageViewCreateInfo.startMipLevel = 0; // always 0 for swapchain - imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; // only 2D - imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; - - result = palCreateImageView( - device, - swapchainImage, - &imageViewCreateInfo, - &imageView); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); - return false; - } - - // destroy the image view - palDestroyImageView(imageView); - - // destroy the swapchain - palDestroySwapchain(swapchain); - - palDestroyWindow(window); - palShutdownVideo(); - - // destroy the graphics queue - palDestroyQueue(gfxQueue); - - // destroy the device - palDestroyDevice(device); - - // shutdown the graphics system - palShutdownGraphics(); - - return true; -} From 9636467672152a2dadb13eb681f52a9b8aec453f Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Dec 2025 13:39:46 +0000 Subject: [PATCH 039/372] add command pool API --- include/pal/pal_graphics.h | 26 ++++++++++++- src/graphics/pal_graphics.c | 75 ++++++++++++++++++++++++++++++++++++- src/graphics/pal_vulkan.c | 73 ++++++++++++++++++++++++++++++++++++ tests/graphics_test.c | 8 ++++ tests/tests.lua | 12 +----- tests/tests_main.c | 10 +---- 6 files changed, 180 insertions(+), 24 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 2ddd3bfd..63770693 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -48,6 +48,7 @@ typedef struct PalImage PalImage; typedef struct PalImageView PalImageView; typedef struct PalShader PalShader; typedef struct PalRenderPass PalRenderPass; +typedef struct PalCommandPool PalCommandPool; typedef enum { PAL_ADAPTER_TYPE_UNKNOWN, @@ -179,7 +180,6 @@ typedef enum { typedef enum { PAL_IMAGE_USAGE_UNDEFINED = 0, - PAL_IMAGE_USAGE_COLOR_ATTACHEMENT = PAL_BIT(0), PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT = PAL_BIT(1), PAL_IMAGE_USAGE_TRANSFER_SRC = PAL_BIT(2), @@ -223,7 +223,9 @@ typedef enum { PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(15), PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16), PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(17), - PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(18) + PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(18), + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(19), + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(20) } PalAdapterFeatures; typedef enum { @@ -407,6 +409,12 @@ typedef struct { PalAttachmentDesc* attachments; } PalRenderPassCreateInfo; +typedef struct { + bool transient; + bool resettable; + PalQueue* queue; +} PalCommandPoolCreateInfo; + typedef struct { void* display; void* window; @@ -535,6 +543,13 @@ typedef struct { PalRenderPass** outRenderPass); void PAL_CALL (*destroyRenderPass)(PalRenderPass* renderPass); + + PalResult PAL_CALL (*createCommandPool)( + PalDevice* device, + const PalCommandPoolCreateInfo* info, + PalCommandPool** outPool); + + void PAL_CALL (*destroyCommandPool)(PalCommandPool* pool); } PalGraphicsBackend; PAL_API PalResult PAL_CALL palAddGraphicsBackend( @@ -669,6 +684,13 @@ PAL_API PalResult PAL_CALL palCreateRenderPass( PAL_API void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass); +PAL_API PalResult PAL_CALL palCreateCommandPool( + PalDevice* device, + const PalCommandPoolCreateInfo* info, + PalCommandPool** outPool); + +PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 38dc9874..7eae121c 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -240,6 +240,13 @@ PalResult PAL_CALL createVkRenderPass( void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass); +PalResult PAL_CALL createVkCommandPool( + PalDevice* device, + const PalCommandPoolCreateInfo* info, + PalCommandPool** outPool); + +void PAL_CALL destroyVkCommandPool(PalCommandPool* pool); + static PalGraphicsBackend s_VkBackend = { .enumerateAdapters = enumerateVkAdapters, .getAdapterInfo = getVkAdapterInfo, @@ -271,7 +278,9 @@ static PalGraphicsBackend s_VkBackend = { .destroyShader = destroyVkShader, .getShaderType = getVkShaderType, .createRenderPass = createVkRenderPass, - .destroyRenderPass = destroyVkRenderPass + .destroyRenderPass = destroyVkRenderPass, + .createCommandPool = createVkCommandPool, + .destroyCommandPool = destroyVkCommandPool }; #endif // PAL_HAS_VULKAN @@ -333,7 +342,9 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->createSwapchain || !backend->destroySwapchain || !backend->getSwapchainImageCount || - !backend->getSwapchainImage) { + !backend->getSwapchainImage || + !backend->createCommandPool || + !backend->destroyCommandPool) { return PAL_RESULT_INVALID_BACKEND; } // clang-format on @@ -1281,4 +1292,64 @@ void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) data->used = false; } } +} + +// ================================================== +// Command Pool And Buffer +// ================================================== + +PalResult PAL_CALL palCreateCommandPool( + PalDevice* device, + const PalCommandPoolCreateInfo* info, + PalCommandPool** outPool) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outPool) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + // create a slot for the command pool + Uint64 poolIndex = 0; + HandleData* poolData = getFreeHandleData(&poolIndex); + if (!poolData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalCommandPool* pool = nullptr; + PalResult ret; + ret = data->backend->createCommandPool( + data->handle, + info, + &pool); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + poolData->backend = data->backend; + poolData->handle = pool; + + *outPool = TO_PAL_HANDLE(PalCommandPool, poolIndex); + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) +{ + if (s_Graphics.initialized && pool) { + Uint64 index = FROM_PAL_HANDLE(pool); + HandleData* data = findHandleData(index); + if (data) { + data->backend->destroyCommandPool(data->handle); + data->used = false; + } + } } \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 9956ae1c..86699d5b 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -113,6 +113,9 @@ typedef struct { PFN_vkCreateFramebuffer createFramebuffer; PFN_vkDestroyFramebuffer destroyFramebuffer; + PFN_vkCreateCommandPool createCommandPool; + PFN_vkDestroyCommandPool destroyCommandPool; + PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; PFN_vkCreateXlibSurfaceKHR createXlibSurface; @@ -198,6 +201,11 @@ struct PalRenderPass { VkImageView views[MAX_ATTACHMENTS]; }; +struct PalCommandPool { + PalDevice* device; + VkCommandPool handle; +}; + static Vulkan s_Vk = {0}; // ================================================== @@ -1139,6 +1147,14 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkBindImageMemory"); + s_Vk.createCommandPool = (PFN_vkCreateCommandPool)dlsym( + s_Vk.handle, + "vkCreateCommandPool"); + + s_Vk.destroyCommandPool = (PFN_vkDestroyCommandPool)dlsym( + s_Vk.handle, + "vkDestroyCommandPool"); + // clang-format on // get version @@ -1810,6 +1826,8 @@ PalResult PAL_CALL getVkAdapterCapabilities( // this features are supported on vulkan caps->features |= PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW; caps->features |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; + caps->features |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE; + caps->features |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT; palFree(s_Vk.allocator, extensionProps); return PAL_RESULT_SUCCESS; @@ -3218,4 +3236,59 @@ void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass) palFree(s_Vk.allocator, renderPass); } +// ================================================== +// Command Pool And Buffer +// ================================================== + +PalResult PAL_CALL createVkCommandPool( + PalDevice* device, + const PalCommandPoolCreateInfo* info, + PalCommandPool** outPool) +{ + VkResult result; + PalCommandPool* pool = nullptr; + PhysicalQueue* phyQueue = info->queue->phyQueue; + + pool = palAllocate(s_Vk.allocator, sizeof(PalCommandPool), 0); + if (!pool) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkCommandPoolCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + createInfo.queueFamilyIndex = phyQueue->familyIndex; + + if (info->resettable) { + createInfo.flags |= VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + } + + if (info->transient) { + createInfo.flags |= VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; + } + + result = s_Vk.createCommandPool( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &pool->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pool); + vkResultToPal(result); + } + + *outPool = pool; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkCommandPool(PalCommandPool* pool) +{ + s_Vk.destroyCommandPool( + pool->device->handle, + pool->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, pool); +} + #endif // PAL_HAS_VULKAN \ No newline at end of file diff --git a/tests/graphics_test.c b/tests/graphics_test.c index dd8b31d4..14ef86d4 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -287,6 +287,14 @@ bool graphicsTest() if (caps.features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { palLog(nullptr, " Dynamic rendering"); } + + if (caps.features & PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE) { + palLog(nullptr, " Resettable command pool"); + } + + if (caps.features & PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT) { + palLog(nullptr, " Transient command pool"); + } palLog(nullptr, ""); } diff --git a/tests/tests.lua b/tests/tests.lua index aacdacef..f30d5af9 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -65,17 +65,7 @@ project "tests" if (PAL_BUILD_GRAPHICS) then files { - "graphics_test.c", - "device_test.c", - "image_test.c", - "renderpass_test.c" - } - end - - if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then - files { - "queue_test.c", - "swapchain_test.c" + "graphics_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 4613ee2f..3153418f 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,17 +55,9 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); - // registerTest("Device Test", deviceTest); - // registerTest("Image Test", imageTest); - registerTest("Render Pass Test", renderPassTest); + registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS -#if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest("Queue Test", queueTest); - // registerTest("Swapchain Test", swapchainTest); -#endif - runTests(); return 0; } \ No newline at end of file From 7ff91ec46ca639bc51a712fe06bbd38313c18253 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Dec 2025 16:45:08 +0000 Subject: [PATCH 040/372] add fence API --- include/pal/pal_core.h | 5 +- include/pal/pal_graphics.h | 76 +++++++- src/graphics/pal_graphics.c | 353 +++++++++++++++++++++++++++++++++++- src/graphics/pal_vulkan.c | 217 +++++++++++++++++++++- src/pal_core.c | 9 + tests/graphics_test.c | 8 + 6 files changed, 654 insertions(+), 14 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 20ce1434..d851c23f 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -260,7 +260,10 @@ typedef enum { PAL_RESULT_INVALID_IMAGE, PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED, PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_INVALID_SHADER_TYPE + PAL_RESULT_INVALID_SHADER_TYPE, + PAL_RESULT_INVALID_COMMAND_POOL, + PAL_RESULT_INVALID_COMMAND_BUFFER, + PAL_RESULT_INVALID_FENCE } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 63770693..96b50ad7 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -35,7 +35,6 @@ freely, subject to the following restrictions: #define PAL_ADAPTER_NAME_SIZE 128 #define PAL_ADAPTER_VERSION_SIZE 16 -#define PAL_INFINITE (2147483647) #define PAL_DEFAULT_MEMORY_OFFSET 0 typedef struct PalAdapter PalAdapter; @@ -48,7 +47,10 @@ typedef struct PalImage PalImage; typedef struct PalImageView PalImageView; typedef struct PalShader PalShader; typedef struct PalRenderPass PalRenderPass; + +typedef struct PalFence PalFence; typedef struct PalCommandPool PalCommandPool; +typedef struct PalCommandBuffer PalCommandBuffer; typedef enum { PAL_ADAPTER_TYPE_UNKNOWN, @@ -225,7 +227,9 @@ typedef enum { PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(17), PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(18), PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(19), - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(20) + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(20), + PAL_ADAPTER_FEATURE_RESET_FENCE = PAL_BIT64(21), + PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(22) } PalAdapterFeatures; typedef enum { @@ -544,12 +548,45 @@ typedef struct { void PAL_CALL (*destroyRenderPass)(PalRenderPass* renderPass); + PalResult PAL_CALL (*createFence)( + PalDevice* device, + PalFence** outFence); + + void PAL_CALL (*destroyFence)(PalFence* fence); + + PalResult PAL_CALL (*waitFenceTimeout)( + PalFence* fence, + Uint64 nanoseconds); + + bool PAL_CALL (*isFenceSignaled)(PalFence* fence); + PalResult PAL_CALL (*createCommandPool)( PalDevice* device, const PalCommandPoolCreateInfo* info, PalCommandPool** outPool); void PAL_CALL (*destroyCommandPool)(PalCommandPool* pool); + + PalResult PAL_CALL (*createCommandBuffer)( + PalDevice* device, + PalCommandPool* pool, + bool primary, + PalCommandBuffer** outCmdBuffer); + + void PAL_CALL (*destroyCommandBuffer)(PalCommandBuffer* cmdBuffer); + + PalResult PAL_CALL (*cmdBegin)(PalCommandBuffer* cmdBuffer); + + PalResult PAL_CALL (*cmdEnd)(PalCommandBuffer* cmdBuffer); + + PalResult PAL_CALL (*cmdExecuteCommandBuffer)( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + + PalResult PAL_CALL (*queueSubmit)( + PalQueue* queue, + PalCommandBuffer* primaryCmdBuffer, + PalFence* fence); } PalGraphicsBackend; PAL_API PalResult PAL_CALL palAddGraphicsBackend( @@ -691,6 +728,41 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); +PAL_API PalResult PAL_CALL palCreateFence( + PalDevice* device, + PalFence** outFence); + +PAL_API void PAL_CALL palDestroyFence(PalFence* fence); + +PAL_API PalResult PAL_CALL palWaitFence(PalFence* fence); + +PAL_API PalResult PAL_CALL palWaitFenceTimeout( + PalFence* fence, + Uint64 nanoseconds); + +PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); + +PAL_API PalResult PAL_CALL palCreateCommandBuffer( + PalDevice* device, + PalCommandPool* pool, + bool primary, + PalCommandBuffer** outCmdbuffer); + +PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); + +PAL_API PalResult PAL_CALL palCmdBegin(PalCommandBuffer* cmdBuffer); + +PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); + +PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + +PAL_API PalResult PAL_CALL palQueueSubmit( + PalQueue* queue, + PalCommandBuffer* primaryCmdBuffer, + PalFence* fence); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 7eae121c..2d61137c 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -240,6 +240,18 @@ PalResult PAL_CALL createVkRenderPass( void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass); +PalResult PAL_CALL createVkFence( + PalDevice* device, + PalFence** outFence); + +void PAL_CALL destroyVkFence(PalFence* fence); + +PalResult PAL_CALL waitVkFenceTimeout( + PalFence* fence, + Uint64 nanoseconds); + +bool PAL_CALL isVkFenceSignaled(PalFence* fence); + PalResult PAL_CALL createVkCommandPool( PalDevice* device, const PalCommandPoolCreateInfo* info, @@ -247,6 +259,27 @@ PalResult PAL_CALL createVkCommandPool( void PAL_CALL destroyVkCommandPool(PalCommandPool* pool); +PalResult PAL_CALL createVkCommandBuffer( + PalDevice* device, + PalCommandPool* pool, + bool primary, + PalCommandBuffer** outBuffer); + +void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); + +PalResult PAL_CALL cmdBeginVk(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdExecuteCommandBufferVk( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + +PalResult PAL_CALL queueSubmitVk( + PalQueue* queue, + PalCommandBuffer* primaryCmdBuffer, + PalFence* fence); + static PalGraphicsBackend s_VkBackend = { .enumerateAdapters = enumerateVkAdapters, .getAdapterInfo = getVkAdapterInfo, @@ -279,8 +312,18 @@ static PalGraphicsBackend s_VkBackend = { .getShaderType = getVkShaderType, .createRenderPass = createVkRenderPass, .destroyRenderPass = destroyVkRenderPass, + .createFence = createVkFence, + .destroyFence = destroyVkFence, + .waitFenceTimeout = waitVkFenceTimeout, + .isFenceSignaled = isVkFenceSignaled, .createCommandPool = createVkCommandPool, - .destroyCommandPool = destroyVkCommandPool + .destroyCommandPool = destroyVkCommandPool, + .createCommandBuffer = createVkCommandBuffer, + .destroyCommandBuffer = destroyVkCommandBuffer, + .cmdBegin = cmdBeginVk, + .cmdEnd = cmdEndVk, + .cmdExecuteCommandBuffer = cmdExecuteCommandBufferVk, + .queueSubmit = queueSubmitVk }; #endif // PAL_HAS_VULKAN @@ -322,19 +365,19 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->getAdapterCapabilities || !backend->createDevice || !backend->destroyDevice || + !backend->allocateMemory || + !backend->freeMemory || !backend->createQueue || !backend->destroyQueue || !backend->canQueuePresent || - !backend->createImage || - !backend->destroyImage || - !backend->getImageInfo || !backend->enumerateFormats || !backend->isFormatSupported || !backend->queryFormatImageUsages || !backend->queryFormatImageViewUsages || + !backend->createImage || + !backend->destroyImage || + !backend->getImageInfo || !backend->getImageMemoryRequirements || - !backend->allocateMemory || - !backend->freeMemory || !backend->bindImageMemory || !backend->createImageView || !backend->destroyImageView || @@ -343,10 +386,35 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroySwapchain || !backend->getSwapchainImageCount || !backend->getSwapchainImage || + !backend->createShader || + !backend->destroyShader || + !backend->getShaderType || + !backend->createRenderPass || + !backend->destroyRenderPass || + !backend->createFence || + !backend->destroyFence || + !backend->waitFenceTimeout || + !backend->isFenceSignaled || !backend->createCommandPool || - !backend->destroyCommandPool) { + !backend->destroyCommandPool || + !backend->createCommandBuffer || + !backend->destroyCommandBuffer || + !backend->cmdBegin || + !backend->cmdEnd || + !backend->cmdExecuteCommandBuffer || + !backend->queueSubmit) { return PAL_RESULT_INVALID_BACKEND; } + // palCreateFence + // palDestroyFence + // palWaitFence + // palIsFenceSignaled + // palCreateCommandBuffer + // palDestroyCommandBuffer + // palCmdBegin + // palCmdEnd + // palCmdExecuteCommandBuffer + // palQueueSubmit // clang-format on BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; @@ -1294,6 +1362,113 @@ void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) } } +// ================================================== +// Fences +// ================================================== + +PalResult PAL_CALL palCreateFence( + PalDevice* device, + PalFence** outFence) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !outFence) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + // create a slot for the fence + Uint64 fenceIndex = 0; + HandleData* fenceData = getFreeHandleData(&fenceIndex); + if (!fenceData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalFence* fence = nullptr; + PalResult ret; + ret = data->backend->createFence(data->handle, &fence); + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + fenceData->backend = data->backend; + fenceData->handle = fence; + + *outFence = TO_PAL_HANDLE(PalFence, fenceIndex); + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyFence(PalFence* fence) +{ + if (s_Graphics.initialized && fence) { + Uint64 index = FROM_PAL_HANDLE(fence); + HandleData* data = findHandleData(index); + if (data) { + data->backend->destroyFence(data->handle); + data->used = false; + } + } +} + +PalResult PAL_CALL palWaitFence(PalFence* fence) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!fence) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(fence); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_FENCE; + } + + return data->backend->waitFenceTimeout(data->handle, UINT64_MAX); +} + +PalResult PAL_CALL palWaitFenceTimeout( + PalFence* fence, + Uint64 nanoseconds) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!fence) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(fence); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_FENCE; + } + + return data->backend->waitFenceTimeout(data->handle, nanoseconds); +} + +bool PAL_CALL palIsFenceSignaled(PalFence* fence) +{ + if (s_Graphics.initialized && fence) { + Uint64 index = FROM_PAL_HANDLE(fence); + HandleData* data = findHandleData(index); + if (data) { + return data->backend->isFenceSignaled(data->handle); + } + } + return false; +} + // ================================================== // Command Pool And Buffer // ================================================== @@ -1352,4 +1527,168 @@ void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) data->used = false; } } +} + +PalResult PAL_CALL palCreateCommandBuffer( + PalDevice* device, + PalCommandPool* pool, + bool primary, + PalCommandBuffer** outCmdBuffer) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !pool || !outCmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(device); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_DEVICE; + } + + index = FROM_PAL_HANDLE(pool); + HandleData* poolData = findHandleData(index); + if (!poolData) { + return PAL_RESULT_INVALID_COMMAND_POOL; + } + + // create a slot for the command buffer + Uint64 cmdBufferIndex = 0; + HandleData* cmdBufferData = getFreeHandleData(&cmdBufferIndex); + if (!cmdBufferData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalCommandBuffer* cmdBuffer = nullptr; + PalResult ret; + ret = data->backend->createCommandBuffer( + data->handle, + poolData->handle, + primary, + &cmdBuffer); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + cmdBufferData->backend = data->backend; + cmdBufferData->handle = cmdBuffer; + + *outCmdBuffer = TO_PAL_HANDLE(PalCommandBuffer, cmdBufferIndex); + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) +{ + if (s_Graphics.initialized && cmdBuffer) { + Uint64 index = FROM_PAL_HANDLE(cmdBuffer); + HandleData* data = findHandleData(index); + if (data) { + data->backend->destroyCommandBuffer(data->handle); + data->used = false; + } + } +} + +PalResult PAL_CALL palCmdBegin(PalCommandBuffer* cmdBuffer) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(cmdBuffer); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + return data->backend->cmdBegin(data->handle); +} + +PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(cmdBuffer); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + return data->backend->cmdEnd(data->handle); +} + +PalResult PAL_CALL palCmdExecuteCommandBuffer( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!primaryCmdBuffer || !secondaryCmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(primaryCmdBuffer); + HandleData* data = findHandleData(index); + index = FROM_PAL_HANDLE(secondaryCmdBuffer); + HandleData* secondaryCmdBufferData = findHandleData(index); + if (!data || !secondaryCmdBufferData) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + return data->backend->cmdExecuteCommandBuffer( + data->handle, + secondaryCmdBufferData->handle); +} + +PalResult PAL_CALL palQueueSubmit( + PalQueue* queue, + PalCommandBuffer* primaryCmdBuffer, + PalFence* fence) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!queue || !primaryCmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(queue); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_QUEUE; + } + + index = FROM_PAL_HANDLE(primaryCmdBuffer); + HandleData* cmdBufferData = findHandleData(index); + if (!cmdBufferData) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + HandleData* fenceData = nullptr; + if (fence) { + index = FROM_PAL_HANDLE(fence); + fenceData = findHandleData(index); + } + + return data->backend->queueSubmit( + data->handle, + cmdBufferData->handle, + fence); } \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 86699d5b..17f8040d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -115,6 +115,17 @@ typedef struct { PFN_vkCreateCommandPool createCommandPool; PFN_vkDestroyCommandPool destroyCommandPool; + PFN_vkAllocateCommandBuffers createCommandBuffer; + PFN_vkFreeCommandBuffers destroyCommandBuffer; + PFN_vkCreateFence createFence; + PFN_vkDestroyFence destroyFence; + PFN_vkResetFences resetFence; + PFN_vkWaitForFences waitFence; + PFN_vkGetFenceStatus isFenceSignaled; + PFN_vkBeginCommandBuffer cmdBegin; + PFN_vkEndCommandBuffer cmdEnd; + PFN_vkCmdExecuteCommands cmdExecuteCommandBuffer; + PFN_vkQueueSubmit queueSubmit; PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; @@ -206,6 +217,17 @@ struct PalCommandPool { VkCommandPool handle; }; +struct PalCommandBuffer { + PalDevice* device; + VkCommandPool pool; + VkCommandBuffer handle; +}; + +struct PalFence { + PalDevice* device; + VkFence handle; +}; + static Vulkan s_Vk = {0}; // ================================================== @@ -1155,6 +1177,50 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroyCommandPool"); + s_Vk.createCommandBuffer = (PFN_vkAllocateCommandBuffers)dlsym( + s_Vk.handle, + "vkAllocateCommandBuffers"); + + s_Vk.destroyCommandBuffer = (PFN_vkFreeCommandBuffers)dlsym( + s_Vk.handle, + "vkFreeCommandBuffers"); + + s_Vk.createFence = (PFN_vkCreateFence)dlsym( + s_Vk.handle, + "vkCreateFence"); + + s_Vk.destroyFence = (PFN_vkDestroyFence)dlsym( + s_Vk.handle, + "vkDestroyFence"); + + s_Vk.resetFence = (PFN_vkResetFences)dlsym( + s_Vk.handle, + "vkResetFences"); + + s_Vk.waitFence = (PFN_vkWaitForFences)dlsym( + s_Vk.handle, + "vkWaitForFences"); + + s_Vk.isFenceSignaled = (PFN_vkGetFenceStatus)dlsym( + s_Vk.handle, + "vkGetFenceStatus"); + + s_Vk.cmdBegin = (PFN_vkBeginCommandBuffer)dlsym( + s_Vk.handle, + "vkBeginCommandBuffer"); + + s_Vk.cmdEnd = (PFN_vkEndCommandBuffer)dlsym( + s_Vk.handle, + "vkEndCommandBuffer"); + + s_Vk.cmdExecuteCommandBuffer = (PFN_vkCmdExecuteCommands)dlsym( + s_Vk.handle, + "vkCmdExecuteCommands"); + + s_Vk.queueSubmit = (PFN_vkQueueSubmit)dlsym( + s_Vk.handle, + "vkQueueSubmit"); + // clang-format on // get version @@ -1828,6 +1894,8 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->features |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; caps->features |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE; caps->features |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT; + caps->features |= PAL_ADAPTER_FEATURE_RESET_FENCE; + caps->features |= PAL_ADAPTER_FEATURE_TIMEOUT_FENCE; palFree(s_Vk.allocator, extensionProps); return PAL_RESULT_SUCCESS; @@ -2725,7 +2793,7 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( caps->maxImageArrayLayers = surfaceCaps.maxImageArrayLayers; if (caps->maxImageCount == 0) { - caps->maxImageCount = PAL_INFINITE; + caps->maxImageCount = INT32_MAX; } // get supported composite alphas @@ -3050,7 +3118,7 @@ PalResult PAL_CALL createVkShader( if (result != VK_SUCCESS) { palFree(s_Vk.allocator, shader); - vkResultToPal(result); + return vkResultToPal(result); } shader->device = device; @@ -3185,7 +3253,7 @@ PalResult PAL_CALL createVkRenderPass( if (result != VK_SUCCESS) { palFree(s_Vk.allocator, renderpass); - vkResultToPal(result); + return vkResultToPal(result); } // create framebuffer @@ -3236,6 +3304,72 @@ void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass) palFree(s_Vk.allocator, renderPass); } +// ================================================== +// Fences +// ================================================== + +PalResult PAL_CALL createVkFence( + PalDevice* device, + PalFence** outFence) +{ + VkResult result; + PalFence* fence = nullptr; + fence = palAllocate(s_Vk.allocator, sizeof(PalFence), 0); + if (!fence) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkFenceCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + result = s_Vk.createFence( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &fence->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, fence); + vkResultToPal(result); + } + + fence->device = device; + *outFence = fence; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkFence(PalFence* fence) +{ + s_Vk.destroyFence(fence->device->handle, fence->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, fence); +} + +PalResult PAL_CALL waitVkFenceTimeout( + PalFence* fence, + Uint64 nanoseconds) +{ + VkResult result = s_Vk.waitFence( + fence->device->handle, + 1, + &fence->handle, + true, + nanoseconds); + + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + return PAL_RESULT_SUCCESS; +} + +bool PAL_CALL isVkFenceSignaled(PalFence* fence) +{ + VkResult ret = s_Vk.isFenceSignaled(fence->device->handle, fence->handle); + if (ret == VK_SUCCESS) { + return true; + } else { + return false; + } +} + // ================================================== // Command Pool And Buffer // ================================================== @@ -3274,9 +3408,10 @@ PalResult PAL_CALL createVkCommandPool( if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pool); - vkResultToPal(result); + return vkResultToPal(result); } + pool->device = device; *outPool = pool; return PAL_RESULT_SUCCESS; } @@ -3291,4 +3426,78 @@ void PAL_CALL destroyVkCommandPool(PalCommandPool* pool) palFree(s_Vk.allocator, pool); } +PalResult PAL_CALL createVkCommandBuffer( + PalDevice* device, + PalCommandPool* pool, + bool primary, + PalCommandBuffer** outCmdBuffer) +{ + VkResult result; + PalCommandBuffer* cmdBuffer = nullptr; + cmdBuffer = palAllocate(s_Vk.allocator, sizeof(PalCommandBuffer), 0); + if (!cmdBuffer) { + PAL_RESULT_OUT_OF_MEMORY; + } + + VkCommandBufferAllocateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + createInfo.commandBufferCount = 1; + createInfo.commandPool = pool->handle; + createInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + if (!primary) { + createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + } + + result = s_Vk.createCommandBuffer( + device->handle, + &createInfo, + &cmdBuffer->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, cmdBuffer); + return vkResultToPal(result); + } + + cmdBuffer->device = device; + cmdBuffer->pool = pool->handle; + *outCmdBuffer = cmdBuffer; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) +{ + s_Vk.destroyCommandBuffer( + cmdBuffer->device->handle, + cmdBuffer->pool, + 1, + &cmdBuffer->handle); + + palFree(s_Vk.allocator, cmdBuffer); +} + +PalResult PAL_CALL cmdBeginVk(PalCommandBuffer* cmdBuffer) +{ + +} + +PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer) +{ + +} + +PalResult PAL_CALL cmdExecuteCommandBufferVk( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer) +{ + +} + +PalResult PAL_CALL queueSubmitVk( + PalQueue* queue, + PalCommandBuffer* primaryCmdBuffer, + PalFence* fence) +{ + +} + #endif // PAL_HAS_VULKAN \ No newline at end of file diff --git a/src/pal_core.c b/src/pal_core.c index 5cf13807..ab10eb65 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -425,6 +425,15 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_SHADER_TYPE: return "Invalid shader type"; + + case PAL_RESULT_INVALID_COMMAND_POOL: + return "Invalid command pool"; + + case PAL_RESULT_INVALID_COMMAND_BUFFER: + return "Invalid command buffer"; + + case PAL_RESULT_INVALID_FENCE: + return "Invalid fence"; } return "Unknown"; } diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 14ef86d4..f3c9ecb3 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -295,6 +295,14 @@ bool graphicsTest() if (caps.features & PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT) { palLog(nullptr, " Transient command pool"); } + + if (caps.features & PAL_ADAPTER_FEATURE_RESET_FENCE) { + palLog(nullptr, " Resetting fence"); + } + + if (caps.features & PAL_ADAPTER_FEATURE_TIMEOUT_FENCE) { + palLog(nullptr, " Timeout fence"); + } palLog(nullptr, ""); } From d9abb741383da573b6d9513ffd1f4b7567275a0c Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Dec 2025 17:28:06 +0000 Subject: [PATCH 041/372] add command buffer API --- include/pal/pal_graphics.h | 13 +++---- src/graphics/pal_graphics.c | 58 +++++++++++++++---------------- src/graphics/pal_vulkan.c | 68 +++++++++++++++++++++++++++++++++++-- tests/graphics_test.c | 4 +++ 4 files changed, 104 insertions(+), 39 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 96b50ad7..1d107d3f 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -229,7 +229,8 @@ typedef enum { PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(19), PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(20), PAL_ADAPTER_FEATURE_RESET_FENCE = PAL_BIT64(21), - PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(22) + PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(22), + PAL_ADAPTER_FEATURE_MULTI_QUEUE_SUBMIT = PAL_BIT64(23) } PalAdapterFeatures; typedef enum { @@ -585,7 +586,8 @@ typedef struct { PalResult PAL_CALL (*queueSubmit)( PalQueue* queue, - PalCommandBuffer* primaryCmdBuffer, + Uint32 cmdBufferCount, + PalCommandBuffer** cmdBuffers, PalFence* fence); } PalGraphicsBackend; @@ -734,9 +736,7 @@ PAL_API PalResult PAL_CALL palCreateFence( PAL_API void PAL_CALL palDestroyFence(PalFence* fence); -PAL_API PalResult PAL_CALL palWaitFence(PalFence* fence); - -PAL_API PalResult PAL_CALL palWaitFenceTimeout( +PAL_API PalResult PAL_CALL palWaitFence( PalFence* fence, Uint64 nanoseconds); @@ -760,7 +760,8 @@ PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( PAL_API PalResult PAL_CALL palQueueSubmit( PalQueue* queue, - PalCommandBuffer* primaryCmdBuffer, + Uint32 cmdBufferCount, + PalCommandBuffer** cmdBuffers, PalFence* fence); /** @} */ // end of pal_graphics group diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 2d61137c..3939d745 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -277,7 +277,8 @@ PalResult PAL_CALL cmdExecuteCommandBufferVk( PalResult PAL_CALL queueSubmitVk( PalQueue* queue, - PalCommandBuffer* primaryCmdBuffer, + Uint32 cmdBufferCount, + PalCommandBuffer** cmdBuffers, PalFence* fence); static PalGraphicsBackend s_VkBackend = { @@ -1417,26 +1418,7 @@ void PAL_CALL palDestroyFence(PalFence* fence) } } -PalResult PAL_CALL palWaitFence(PalFence* fence) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!fence) { - return PAL_RESULT_NULL_POINTER; - } - - Uint64 index = FROM_PAL_HANDLE(fence); - HandleData* data = findHandleData(index); - if (!data) { - return PAL_RESULT_INVALID_FENCE; - } - - return data->backend->waitFenceTimeout(data->handle, UINT64_MAX); -} - -PalResult PAL_CALL palWaitFenceTimeout( +PalResult PAL_CALL palWaitFence( PalFence* fence, Uint64 nanoseconds) { @@ -1658,37 +1640,51 @@ PalResult PAL_CALL palCmdExecuteCommandBuffer( PalResult PAL_CALL palQueueSubmit( PalQueue* queue, - PalCommandBuffer* primaryCmdBuffer, + Uint32 cmdBufferCount, + PalCommandBuffer** cmdBuffers, PalFence* fence) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!queue || !primaryCmdBuffer) { + if (!queue || !cmdBuffers) { return PAL_RESULT_NULL_POINTER; } + if (cmdBufferCount == 0) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + Uint64 index = FROM_PAL_HANDLE(queue); HandleData* data = findHandleData(index); if (!data) { return PAL_RESULT_INVALID_QUEUE; } - index = FROM_PAL_HANDLE(primaryCmdBuffer); - HandleData* cmdBufferData = findHandleData(index); - if (!cmdBufferData) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - HandleData* fenceData = nullptr; + void* fenceHandle = nullptr; if (fence) { index = FROM_PAL_HANDLE(fence); fenceData = findHandleData(index); + fenceHandle = fenceData->handle; + } + + // 16 should be more than enough + PalCommandBuffer* cmdHandles[16]; + for (int i = 0; i < cmdBufferCount; i++) { + // get the cmd buffer handles + index = FROM_PAL_HANDLE(cmdBuffers[i]); + HandleData* cmdBufferData = findHandleData(index); + if (!cmdBufferData) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + cmdHandles[i] = cmdBufferData->handle; } return data->backend->queueSubmit( data->handle, - cmdBufferData->handle, - fence); + cmdBufferCount, + cmdHandles, + fenceHandle); } \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 17f8040d..131d6670 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -218,6 +218,7 @@ struct PalCommandPool { }; struct PalCommandBuffer { + bool primary; PalDevice* device; VkCommandPool pool; VkCommandBuffer handle; @@ -1896,6 +1897,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->features |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT; caps->features |= PAL_ADAPTER_FEATURE_RESET_FENCE; caps->features |= PAL_ADAPTER_FEATURE_TIMEOUT_FENCE; + caps->features |= PAL_ADAPTER_FEATURE_MULTI_QUEUE_SUBMIT; palFree(s_Vk.allocator, extensionProps); return PAL_RESULT_SUCCESS; @@ -3458,6 +3460,12 @@ PalResult PAL_CALL createVkCommandBuffer( return vkResultToPal(result); } + if (primary) { + cmdBuffer->primary = true; + } else { + cmdBuffer->primary = false; + } + cmdBuffer->device = device; cmdBuffer->pool = pool->handle; *outCmdBuffer = cmdBuffer; @@ -3477,27 +3485,83 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL cmdBeginVk(PalCommandBuffer* cmdBuffer) { + VkCommandBufferBeginInfo beginInfo = {0}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + VkResult result = s_Vk.cmdBegin(cmdBuffer->handle, &beginInfo); + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer) { - + VkResult result = s_Vk.cmdEnd(cmdBuffer->handle); + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdExecuteCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { + // check if both are primary cmd buffers + if (primaryCmdBuffer->primary && secondaryCmdBuffer->primary) { + return PAL_RESULT_INVALID_OPERATION; + } + + if (!primaryCmdBuffer->primary && !secondaryCmdBuffer->primary) { + return PAL_RESULT_INVALID_OPERATION; + } + + if (!primaryCmdBuffer->primary) { + return PAL_RESULT_INVALID_OPERATION; + } + s_Vk.cmdExecuteCommandBuffer( + primaryCmdBuffer->handle, + 1, + &secondaryCmdBuffer->handle); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL queueSubmitVk( PalQueue* queue, - PalCommandBuffer* primaryCmdBuffer, + Uint32 cmdBufferCount, + PalCommandBuffer** cmdBuffers, PalFence* fence) { + VkResult result; + VkFence fenceHandle = nullptr; + VkCommandBuffer cmdHandles[16]; // 16 should be more than enough + for (int i = 0; i < cmdBufferCount; i++) { + cmdHandles[i] = cmdBuffers[i]->handle; + } + + VkSubmitInfo submitInfo = {0}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = cmdBufferCount; + submitInfo.pCommandBuffers = cmdHandles; + if (fence) { + fenceHandle = fence->handle; + } + + result = s_Vk.queueSubmit( + queue->phyQueue->handle, + 1, + &submitInfo, + fenceHandle); + + if (result != VK_SUCCESS) { + vkResultToPal(result); + } + + return PAL_RESULT_SUCCESS; } #endif // PAL_HAS_VULKAN \ No newline at end of file diff --git a/tests/graphics_test.c b/tests/graphics_test.c index f3c9ecb3..5999b9bd 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -303,6 +303,10 @@ bool graphicsTest() if (caps.features & PAL_ADAPTER_FEATURE_TIMEOUT_FENCE) { palLog(nullptr, " Timeout fence"); } + + if (caps.features & PAL_ADAPTER_FEATURE_MULTI_QUEUE_SUBMIT) { + palLog(nullptr, " Multi queue submit"); + } palLog(nullptr, ""); } From e8b6878cb8b2a7405a364dea0ef6698ed4599ef7 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 12 Dec 2025 15:49:16 +0000 Subject: [PATCH 042/372] add renderpass commands --- include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 67 ++++++++--- src/graphics/pal_graphics.c | 222 ++++++++++++++++++++++++++++++------ src/graphics/pal_vulkan.c | 145 +++++++++++++++++++++-- src/pal_core.c | 3 + 5 files changed, 377 insertions(+), 63 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index d851c23f..62e2ea5f 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -263,7 +263,8 @@ typedef enum { PAL_RESULT_INVALID_SHADER_TYPE, PAL_RESULT_INVALID_COMMAND_POOL, PAL_RESULT_INVALID_COMMAND_BUFFER, - PAL_RESULT_INVALID_FENCE + PAL_RESULT_INVALID_FENCE, + PAL_RESULT_INVALID_RENDER_PASS } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 1d107d3f..c19f20d0 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -288,7 +288,8 @@ typedef enum { typedef enum { PAL_ATTACHMENT_TYPE_COLOR, - PAL_ATTACHMENT_TYPE_DEPTH + PAL_ATTACHMENT_TYPE_DEPTH, + PAL_ATTACHMENT_TYPE_STENCIL } PalAttachmentType; typedef struct { @@ -370,6 +371,12 @@ typedef struct { Uint32 alignment; } PalMemoryRequirements; +typedef struct { + float color[4]; + float depth; + Uint32 stencil; +} PalClearValue; + typedef struct { Uint32 width; Uint32 height; @@ -533,6 +540,15 @@ typedef struct { PalSwapchain* swapchain, Int32 index); + PalImage* PAL_CALL (*getNextSwapchainImage)( + PalSwapchain* swapchain, + PalFence* fence, + Uint64 timeout); + + PalResult PAL_CALL (*presentSwapchain)( + PalSwapchain* swapchain, + PalImage* image); + PalResult PAL_CALL (*createShader)( PalDevice* device, const PalShaderCreateInfo* info, @@ -557,7 +573,7 @@ typedef struct { PalResult PAL_CALL (*waitFenceTimeout)( PalFence* fence, - Uint64 nanoseconds); + Uint64 timeout); bool PAL_CALL (*isFenceSignaled)(PalFence* fence); @@ -576,17 +592,25 @@ typedef struct { void PAL_CALL (*destroyCommandBuffer)(PalCommandBuffer* cmdBuffer); - PalResult PAL_CALL (*cmdBegin)(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL (*beginRendering)(PalCommandBuffer* cmdBuffer); - PalResult PAL_CALL (*cmdEnd)(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL (*endRendering)(PalCommandBuffer* cmdBuffer); - PalResult PAL_CALL (*cmdExecuteCommandBuffer)( + PalResult PAL_CALL (*executeCommandBuffer)( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); - PalResult PAL_CALL (*queueSubmit)( + PalResult PAL_CALL (*beginRenderPass)( + PalCommandBuffer* cmdBuffer, + PalRenderPass* renderPass, + Int32 clearValuecount, + PalClearValue* clearValues); + + PalResult PAL_CALL (*endRenderPass)(PalCommandBuffer* cmdBuffer); + + PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, - Uint32 cmdBufferCount, + Int32 cmdBufferCount, PalCommandBuffer** cmdBuffers, PalFence* fence); } PalGraphicsBackend; @@ -707,6 +731,15 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, Int32 index); +PAL_API PalImage* PAL_CALL palGetNextSwapchainImage( + PalSwapchain* swapchain, + PalFence* fence, + Uint64 timeout); + +PAL_API PalResult PAL_CALL palPresentSwapchain( + PalSwapchain* swapchain, + PalImage* image); + PAL_API PalResult PAL_CALL palCreateShader( PalDevice* device, const PalShaderCreateInfo* info, @@ -738,7 +771,7 @@ PAL_API void PAL_CALL palDestroyFence(PalFence* fence); PAL_API PalResult PAL_CALL palWaitFence( PalFence* fence, - Uint64 nanoseconds); + Uint64 timeout); PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); @@ -750,17 +783,25 @@ PAL_API PalResult PAL_CALL palCreateCommandBuffer( PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); -PAL_API PalResult PAL_CALL palCmdBegin(PalCommandBuffer* cmdBuffer); +PAL_API PalResult PAL_CALL palBeginRendering(PalCommandBuffer* cmdBuffer); -PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); +PAL_API PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer); -PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( +PAL_API PalResult PAL_CALL palExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); -PAL_API PalResult PAL_CALL palQueueSubmit( +PAL_API PalResult PAL_CALL palBeginRenderPass( + PalCommandBuffer* cmdBuffer, + PalRenderPass* renderPass, + Int32 clearValueCount, + PalClearValue* clearValues); + +PAL_API PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer); + +PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, - Uint32 cmdBufferCount, + Int32 cmdBufferCount, PalCommandBuffer** cmdBuffers, PalFence* fence); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 3939d745..de522a47 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -224,6 +224,15 @@ PalImage* PAL_CALL getVkSwapchainImage( PalSwapchain* swapchain, Int32 index); +PalImage* PAL_CALL getVkNextSwapchainImage( + PalSwapchain* swapchain, + PalFence* fence, + Uint64 timeout); + +PalResult PAL_CALL presentVkSwapchain( + PalSwapchain* swapchain, + PalImage* image); + PalResult PAL_CALL createVkShader( PalDevice* device, const PalShaderCreateInfo* info, @@ -246,9 +255,9 @@ PalResult PAL_CALL createVkFence( void PAL_CALL destroyVkFence(PalFence* fence); -PalResult PAL_CALL waitVkFenceTimeout( +PalResult PAL_CALL waitVkFence( PalFence* fence, - Uint64 nanoseconds); + Uint64 timeout); bool PAL_CALL isVkFenceSignaled(PalFence* fence); @@ -267,17 +276,25 @@ PalResult PAL_CALL createVkCommandBuffer( void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); -PalResult PAL_CALL cmdBeginVk(PalCommandBuffer* cmdBuffer); +PalResult PAL_CALL beginRenderingVk(PalCommandBuffer* cmdBuffer); -PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer); +PalResult PAL_CALL endRenderingVk(PalCommandBuffer* cmdBuffer); -PalResult PAL_CALL cmdExecuteCommandBufferVk( +PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); -PalResult PAL_CALL queueSubmitVk( +PalResult PAL_CALL beginRenderPassVk( + PalCommandBuffer* cmdBuffer, + PalRenderPass* renderPass, + Int32 clearValueCount, + PalClearValue* clearValues); + +PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, - Uint32 cmdBufferCount, + Int32 cmdBufferCount, PalCommandBuffer** cmdBuffers, PalFence* fence); @@ -308,6 +325,8 @@ static PalGraphicsBackend s_VkBackend = { .destroySwapchain = destroyVkSwapchain, .getSwapchainImageCount = getVkSwapchainImageCount, .getSwapchainImage = getVkSwapchainImage, + .getNextSwapchainImage = getVkNextSwapchainImage, + .presentSwapchain = presentVkSwapchain, .createShader = createVkShader, .destroyShader = destroyVkShader, .getShaderType = getVkShaderType, @@ -315,16 +334,18 @@ static PalGraphicsBackend s_VkBackend = { .destroyRenderPass = destroyVkRenderPass, .createFence = createVkFence, .destroyFence = destroyVkFence, - .waitFenceTimeout = waitVkFenceTimeout, + .waitFenceTimeout = waitVkFence, .isFenceSignaled = isVkFenceSignaled, .createCommandPool = createVkCommandPool, .destroyCommandPool = destroyVkCommandPool, .createCommandBuffer = createVkCommandBuffer, .destroyCommandBuffer = destroyVkCommandBuffer, - .cmdBegin = cmdBeginVk, - .cmdEnd = cmdEndVk, - .cmdExecuteCommandBuffer = cmdExecuteCommandBufferVk, - .queueSubmit = queueSubmitVk + .beginRendering = beginRenderingVk, + .endRendering = endRenderingVk, + .executeCommandBuffer = executeCommandBufferVk, + .beginRenderPass = beginRenderPassVk, + .endRenderPass = endRenderPassVk, + .submitCommandBuffer = submitVkCommandBuffer }; #endif // PAL_HAS_VULKAN @@ -387,6 +408,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroySwapchain || !backend->getSwapchainImageCount || !backend->getSwapchainImage || + !backend->getNextSwapchainImage || + !backend->presentSwapchain || !backend->createShader || !backend->destroyShader || !backend->getShaderType || @@ -400,22 +423,15 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroyCommandPool || !backend->createCommandBuffer || !backend->destroyCommandBuffer || - !backend->cmdBegin || - !backend->cmdEnd || - !backend->cmdExecuteCommandBuffer || - !backend->queueSubmit) { + !backend->beginRendering || + !backend->endRendering || + !backend->beginRenderPass || + !backend->endRenderPass || + !backend->endRendering || + !backend->executeCommandBuffer || + !backend->submitCommandBuffer) { return PAL_RESULT_INVALID_BACKEND; } - // palCreateFence - // palDestroyFence - // palWaitFence - // palIsFenceSignaled - // palCreateCommandBuffer - // palDestroyCommandBuffer - // palCmdBegin - // palCmdEnd - // palCmdExecuteCommandBuffer - // palQueueSubmit // clang-format on BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; @@ -1198,6 +1214,80 @@ PalImage* PAL_CALL palGetSwapchainImage( return TO_PAL_HANDLE(PalImage, imageIndex); } +PalImage* PAL_CALL palGetNextSwapchainImage( + PalSwapchain* swapchain, + PalFence* fence, + Uint64 timeout) +{ + if (!s_Graphics.initialized || !swapchain) { + return nullptr; + } + + Uint64 index = FROM_PAL_HANDLE(swapchain); + HandleData* data = findHandleData(index); + if (!data) { + return nullptr; + } + + void* FenceHandle = nullptr; + if (fence) { + index = FROM_PAL_HANDLE(fence); + HandleData* tmp = findHandleData(index); + if (!tmp) { + return nullptr; + } + FenceHandle = tmp->handle; + } + + PalImage* image = data->backend->getNextSwapchainImage( + data->handle, + FenceHandle, + timeout); + + // check if the image has been requested already + Uint64 imageIndex = FROM_PAL_HANDLE(image); + HandleData* imageData = findHandleData(imageIndex); + if (!imageData) { + // create a new slot + imageData = getFreeHandleData(&imageIndex); + if (!imageData) { + return nullptr; + } + } + + imageData->backend = data->backend; + imageData->handle = image; + + return TO_PAL_HANDLE(PalImage, imageIndex); +} + +PalResult PAL_CALL palPresentSwapchain( + PalSwapchain* swapchain, + PalImage* image) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!swapchain || !image) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(swapchain); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_SWAPCHAIN; + } + + index = FROM_PAL_HANDLE(image); + HandleData* imageData = findHandleData(index); + if (!imageData) { + return PAL_RESULT_INVALID_IMAGE; + } + + return data->backend->presentSwapchain(data->handle, imageData->handle); +} + // ================================================== // Shader // ================================================== @@ -1364,7 +1454,7 @@ void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) } // ================================================== -// Fences +// Fence // ================================================== PalResult PAL_CALL palCreateFence( @@ -1420,7 +1510,7 @@ void PAL_CALL palDestroyFence(PalFence* fence) PalResult PAL_CALL palWaitFence( PalFence* fence, - Uint64 nanoseconds) + Uint64 timeout) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1436,7 +1526,7 @@ PalResult PAL_CALL palWaitFence( return PAL_RESULT_INVALID_FENCE; } - return data->backend->waitFenceTimeout(data->handle, nanoseconds); + return data->backend->waitFenceTimeout(data->handle, timeout); } bool PAL_CALL palIsFenceSignaled(PalFence* fence) @@ -1575,7 +1665,7 @@ void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) } } -PalResult PAL_CALL palCmdBegin(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL palBeginRendering(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1591,10 +1681,10 @@ PalResult PAL_CALL palCmdBegin(PalCommandBuffer* cmdBuffer) return PAL_RESULT_INVALID_COMMAND_BUFFER; } - return data->backend->cmdBegin(data->handle); + return data->backend->beginRendering(data->handle); } -PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1610,10 +1700,10 @@ PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer) return PAL_RESULT_INVALID_COMMAND_BUFFER; } - return data->backend->cmdEnd(data->handle); + return data->backend->endRendering(data->handle); } -PalResult PAL_CALL palCmdExecuteCommandBuffer( +PalResult PAL_CALL palExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { @@ -1633,14 +1723,70 @@ PalResult PAL_CALL palCmdExecuteCommandBuffer( return PAL_RESULT_INVALID_COMMAND_BUFFER; } - return data->backend->cmdExecuteCommandBuffer( + return data->backend->executeCommandBuffer( data->handle, secondaryCmdBufferData->handle); } -PalResult PAL_CALL palQueueSubmit( +PalResult PAL_CALL palBeginRenderPass( + PalCommandBuffer* cmdBuffer, + PalRenderPass* renderPass, + Int32 clearValueCount, + PalClearValue* clearValues) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !renderPass) { + return PAL_RESULT_NULL_POINTER; + } + + if (clearValueCount == 0 && clearValues) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + + Uint64 index = FROM_PAL_HANDLE(cmdBuffer); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + index = FROM_PAL_HANDLE(renderPass); + HandleData* renderPassData = findHandleData(index); + if (!renderPassData) { + return PAL_RESULT_INVALID_RENDER_PASS; + } + + return data->backend->beginRenderPass( + data->handle, + renderPassData->handle, + clearValueCount, + clearValues); +} + +PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + Uint64 index = FROM_PAL_HANDLE(cmdBuffer); + HandleData* data = findHandleData(index); + if (!data) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + return data->backend->endRenderPass(data->handle); +} + +PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, - Uint32 cmdBufferCount, + Int32 cmdBufferCount, PalCommandBuffer** cmdBuffers, PalFence* fence) { @@ -1682,7 +1828,7 @@ PalResult PAL_CALL palQueueSubmit( cmdHandles[i] = cmdBufferData->handle; } - return data->backend->queueSubmit( + return data->backend->submitCommandBuffer( data->handle, cmdBufferCount, cmdHandles, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 131d6670..3aaa6332 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -126,6 +126,8 @@ typedef struct { PFN_vkEndCommandBuffer cmdEnd; PFN_vkCmdExecuteCommands cmdExecuteCommandBuffer; PFN_vkQueueSubmit queueSubmit; + PFN_vkCmdBeginRenderPass cmdBeginRenderPass; + PFN_vkCmdEndRenderPass cmdEndRenderPass; PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; @@ -171,6 +173,7 @@ struct PalQueue { struct PalImage { bool belongsToSwapchain; + Int32 index; PalDevice* device; VkImage handle; PalImageInfo info; @@ -187,6 +190,7 @@ struct PalImageView { struct PalSwapchain { Uint32 imageCount; PalDevice* device; + PalQueue* queue; VkSurfaceKHR surface; VkSwapchainKHR handle; PalImage* images; @@ -202,6 +206,8 @@ struct PalShader { struct PalRenderPass { bool hasDepth; Uint32 attachmentCount; + Uint32 width; + Uint32 height; PalDevice* device; VkRenderPass handle; VkFramebuffer framebuffer; @@ -1218,6 +1224,14 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCmdExecuteCommands"); + s_Vk.cmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)dlsym( + s_Vk.handle, + "vkCmdBeginRenderPass"); + + s_Vk.cmdEndRenderPass = (PFN_vkCmdEndRenderPass)dlsym( + s_Vk.handle, + "vkCmdEndRenderPass"); + s_Vk.queueSubmit = (PFN_vkQueueSubmit)dlsym( s_Vk.handle, "vkQueueSubmit"); @@ -3018,6 +3032,7 @@ PalResult PAL_CALL createVkSwapchain( image->belongsToSwapchain = true; image->device = device; image->handle = images[i]; + image->index = -1; image->info.depthOrArraySize = createInfo.imageArrayLayers; image->info.format = imageFormat; @@ -3030,6 +3045,7 @@ PalResult PAL_CALL createVkSwapchain( } swapchain->device = device; + swapchain->queue = queue; swapchain->imageCount = count; *outSwapchain = swapchain; @@ -3061,7 +3077,60 @@ PalImage* PAL_CALL getVkSwapchainImage( if (index > swapchain->imageCount) { return nullptr; } - return (PalImage*)&swapchain->images[index]; + return &swapchain->images[index]; +} + +PalImage* PAL_CALL getVkNextSwapchainImage( + PalSwapchain* swapchain, + PalFence* fence, + Uint64 timeout) +{ + Uint32 index = 0; + VkResult result; + result = swapchain->device->acquireNextImage( + swapchain->device->handle, + swapchain->handle, + timeout, + VK_NULL_HANDLE, + fence->handle, + &index); + + if (result != VK_SUCCESS) { + return nullptr; + } + + PalImage* image = &swapchain->images[index]; + image->index = index; + return image; +} + +PalResult PAL_CALL presentVkSwapchain( + PalSwapchain* swapchain, + PalImage* image) +{ + if (image->index == -1) { + // image was not the next image + // this prevents UB + return PAL_RESULT_INVALID_IMAGE; + } + + VkResult result; + VkPresentInfoKHR presentInfo = {0}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &swapchain->handle; + presentInfo.pImageIndices = &image->index; + + result = swapchain->device->queuePresent( + swapchain->queue->phyQueue->handle, + &presentInfo); + + if (result != VK_SUCCESS) { + vkResultToPal(result); + } + + image->index = -1; + return PAL_RESULT_SUCCESS; } // ================================================== @@ -3286,7 +3355,9 @@ PalResult PAL_CALL createVkRenderPass( } } - renderpass->device = device; + renderpass->device = device; + renderpass->width = info->width; + renderpass->height = info->height; *outRenderPass = renderpass; return PAL_RESULT_SUCCESS; } @@ -3307,7 +3378,7 @@ void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass) } // ================================================== -// Fences +// Fence // ================================================== PalResult PAL_CALL createVkFence( @@ -3345,16 +3416,16 @@ void PAL_CALL destroyVkFence(PalFence* fence) palFree(s_Vk.allocator, fence); } -PalResult PAL_CALL waitVkFenceTimeout( +PalResult PAL_CALL waitVkFence( PalFence* fence, - Uint64 nanoseconds) + Uint64 timeout) { VkResult result = s_Vk.waitFence( fence->device->handle, 1, &fence->handle, true, - nanoseconds); + timeout); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -3483,7 +3554,7 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) palFree(s_Vk.allocator, cmdBuffer); } -PalResult PAL_CALL cmdBeginVk(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL beginRenderingVk(PalCommandBuffer* cmdBuffer) { VkCommandBufferBeginInfo beginInfo = {0}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -3495,7 +3566,7 @@ PalResult PAL_CALL cmdBeginVk(PalCommandBuffer* cmdBuffer) return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL endRenderingVk(PalCommandBuffer* cmdBuffer) { VkResult result = s_Vk.cmdEnd(cmdBuffer->handle); if (result != VK_SUCCESS) { @@ -3504,7 +3575,7 @@ PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer) return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdExecuteCommandBufferVk( +PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { @@ -3529,9 +3600,61 @@ PalResult PAL_CALL cmdExecuteCommandBufferVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queueSubmitVk( +PalResult PAL_CALL beginRenderPassVk( + PalCommandBuffer* cmdBuffer, + PalRenderPass* renderPass, + Int32 clearValueCount, + PalClearValue* clearValues) +{ + if (clearValueCount != renderPass->attachmentCount) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + + VkRenderPassBeginInfo beginInfo = {0}; + beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + VkClearValue tmp[MAX_ATTACHMENTS]; + + for (int i = 0; i < clearValueCount; i++) { + VkAttachmentDescription* desc = &renderPass->attachments[i]; + PalClearValue* clearValue = &clearValues[i]; + if (desc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { + // color attachment + tmp[i].color.float32[0] = clearValue->color[0]; + tmp[i].color.float32[1] = clearValue->color[1]; + tmp[i].color.float32[2] = clearValue->color[2]; + tmp[i].color.float32[3] = clearValue->color[3]; + + } else { + // depth/stencil attachment + tmp[i].depthStencil.depth = clearValue->depth; + tmp[i].depthStencil.stencil = clearValue->stencil; + } + } + + beginInfo.clearValueCount = clearValueCount; + beginInfo.pClearValues = tmp; + beginInfo.framebuffer = renderPass->framebuffer; + beginInfo.renderPass = renderPass->handle; + beginInfo.renderArea.extent.width = renderPass->width; + beginInfo.renderArea.extent.height = renderPass->height; + + s_Vk.cmdBeginRenderPass( + cmdBuffer->handle, + &beginInfo, + VK_SUBPASS_CONTENTS_INLINE); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer) +{ + s_Vk.cmdEndRenderPass(cmdBuffer->handle); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, - Uint32 cmdBufferCount, + Int32 cmdBufferCount, PalCommandBuffer** cmdBuffers, PalFence* fence) { diff --git a/src/pal_core.c b/src/pal_core.c index ab10eb65..00476168 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -434,6 +434,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_FENCE: return "Invalid fence"; + + case PAL_RESULT_INVALID_RENDER_PASS: + return "Invalid render pass"; } return "Unknown"; } From 0ba655bb784cb03bac550612b0320a5025a140d2 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Dec 2025 13:39:54 +0000 Subject: [PATCH 043/372] add graphics clear color test --- include/pal/pal_core.h | 1 + include/pal/pal_graphics.h | 6 - src/graphics/pal_graphics.c | 595 ++++++++++++++++-------------------- src/graphics/pal_vulkan.c | 82 ++--- src/pal_core.c | 3 + src/video/pal_video_linux.c | 5 + tests/clear_color_test.c | 445 +++++++++++++++++++++++++++ tests/tests.h | 7 +- tests/tests.lua | 6 + tests/tests_main.c | 6 +- 10 files changed, 780 insertions(+), 376 deletions(-) create mode 100644 tests/clear_color_test.c diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 62e2ea5f..e8caf477 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -258,6 +258,7 @@ typedef enum { PAL_RESULT_INVALID_GRAPHICS_WINDOW, PAL_RESULT_INVALID_SWAPCHAIN, PAL_RESULT_INVALID_IMAGE, + PAL_RESULT_INVALID_IMAGE_VIEW, PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED, PAL_RESULT_INVALID_OPERATION, PAL_RESULT_INVALID_SHADER_TYPE, diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index c19f20d0..f7dd6aef 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -502,12 +502,10 @@ typedef struct { PalImageInfo* info); PalResult PAL_CALL (*getImageMemoryRequirements)( - PalDevice* device, PalImage* image, PalMemoryRequirements* requirments); PalResult PAL_CALL (*bindImageMemory)( - PalDevice* device, PalImage* image, PalMemory* memory, Uint64 offset); @@ -534,8 +532,6 @@ typedef struct { void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); - Uint32 PAL_CALL (*getSwapchainImageCount)(PalSwapchain* swapchain); - PalImage* PAL_CALL (*getSwapchainImage)( PalSwapchain* swapchain, Int32 index); @@ -693,12 +689,10 @@ PAL_API PalResult PAL_CALL palGetImageInfo( PalImageInfo* info); PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( - PalDevice* device, PalImage* image, PalMemoryRequirements* requirements); PAL_API PalResult PAL_CALL palBindImageMemory( - PalDevice* device, PalImage* image, PalMemory* memory, Uint64 offset); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index de522a47..c3529029 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -32,12 +32,13 @@ freely, subject to the following restrictions: // ================================================== #define MAX_BACKENDS 32 -#define TO_PAL_HANDLE(type, value) ((type*)(UintPtr)(value)) -#define FROM_PAL_HANDLE(handle) ((Uint64)(UintPtr)(handle)) typedef struct { bool used; + bool shouldFree; + Uint32 data2; void* handle; + void* data; const PalGraphicsBackend* backend; } HandleData; @@ -62,47 +63,35 @@ static GraphicsLinux s_Graphics = {0}; // Internal API // ================================================== -static HandleData* getFreeHandleData(Uint64* outIndex) +static HandleData* getFreeHandleData() { for (int i = 0; i < s_Graphics.maxHandleData; ++i) { if (!s_Graphics.handleData[i].used) { s_Graphics.handleData[i].used = true; - *outIndex = i + 1; + s_Graphics.handleData[i].shouldFree = false; return &s_Graphics.handleData[i]; } } - // resize the data array + // It will be rare to have more than 128 handles at the same time HandleData* data = nullptr; - - - Uint32 newSize = s_Graphics.maxHandleData * 2; // double the size - int freeIndex = s_Graphics.maxHandleData + 1; - data = palAllocate(s_Graphics.allocator, sizeof(HandleData) * newSize, 0); - if (data) { - memset(data, 0, sizeof(HandleData) * newSize); - for (int i = 0; i < s_Graphics.maxHandleData; i++) { - // copy (shallow) old array into the new one - data[i] = s_Graphics.handleData[i]; - } - - palFree(s_Graphics.allocator, s_Graphics.handleData); - s_Graphics.handleData = data; - s_Graphics.maxHandleData = newSize; - - s_Graphics.handleData[freeIndex].used = true; - *outIndex = freeIndex; - return &s_Graphics.handleData[freeIndex]; + data = palAllocate(s_Graphics.allocator, sizeof(HandleData), 0); + if (!data) { + return nullptr; } - return nullptr; + + data->used = true; + data->shouldFree = true; + return data; } -static HandleData* findHandleData(Uint64 index) +static void freeHandleData(HandleData* data) { - if (index < 1 || index > s_Graphics.maxHandleData) { - return nullptr; + if (data->shouldFree) { + palFree(s_Graphics.allocator, data); + } else { + data->used = false; } - return &s_Graphics.handleData[index - 1]; } // ================================================== @@ -186,12 +175,10 @@ PalResult PAL_CALL getVkImageInfo( PalImageInfo* info); PalResult PAL_CALL getVkImageMemoryRequirements( - PalDevice* device, PalImage* image, PalMemoryRequirements* requirements); PalResult PAL_CALL bindVkImageMemory( - PalDevice* device, PalImage* image, PalMemory* memory, Uint64 offset); @@ -218,8 +205,6 @@ PalResult PAL_CALL createVkSwapchain( void PAL_CALL destroyVkSwapchain(PalSwapchain* swapchain); -Uint32 PAL_CALL getVkSwapchainImageCount(PalSwapchain* swapchain); - PalImage* PAL_CALL getVkSwapchainImage( PalSwapchain* swapchain, Int32 index); @@ -323,7 +308,6 @@ static PalGraphicsBackend s_VkBackend = { .querySwapchainCapabilities = queryVkSwapchainCapabilities, .createSwapchain = createVkSwapchain, .destroySwapchain = destroyVkSwapchain, - .getSwapchainImageCount = getVkSwapchainImageCount, .getSwapchainImage = getVkSwapchainImage, .getNextSwapchainImage = getVkNextSwapchainImage, .presentSwapchain = presentVkSwapchain, @@ -406,7 +390,6 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->querySwapchainCapabilities || !backend->createSwapchain || !backend->destroySwapchain || - !backend->getSwapchainImageCount || !backend->getSwapchainImage || !backend->getNextSwapchainImage || !backend->presentSwapchain || @@ -454,7 +437,7 @@ PalResult PAL_CALL palInitGraphics( return PAL_RESULT_INVALID_ALLOCATOR; } - s_Graphics.maxHandleData = 32; + s_Graphics.maxHandleData = 128; s_Graphics.handleData = palAllocate( s_Graphics.allocator, sizeof(HandleData) * s_Graphics.maxHandleData, @@ -538,14 +521,12 @@ PalResult PAL_CALL palEnumerateAdapters( result = backend->base->enumerateAdapters(&_count, adapters); for (int i = 0; i < backend->count; i++) { - Uint64 adapterIndex = 0; - HandleData* data = getFreeHandleData(&adapterIndex); + HandleData* data = getFreeHandleData(); data->backend = backend->base; data->handle = adapters[i]; - // reset the adapter handle into our index generated handle - PalAdapter* tmp = TO_PAL_HANDLE(PalAdapter, adapterIndex); - adapters[i] = tmp; + // set the adapter handle into our index generated handle + adapters[i] = (PalAdapter*)data; } } else { @@ -580,11 +561,11 @@ PalResult PAL_CALL palGetAdapterInfo( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(adapter); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)adapter; + if (!data->used) { return PAL_RESULT_INVALID_ADAPTER; } + return data->backend->getAdapterInfo(data->handle, info); } @@ -600,11 +581,11 @@ PalResult PAL_CALL palGetAdapterCapabilities( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(adapter); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)adapter; + if (!data->used) { return PAL_RESULT_INVALID_ADAPTER; } + return data->backend->getAdapterCapabilities(data->handle, caps); } @@ -625,42 +606,42 @@ PalResult PAL_CALL palCreateDevice( return PAL_RESULT_NULL_POINTER; } - // check if the adapter is from PAL (custom or internal backend) - Uint64 index = FROM_PAL_HANDLE(adapter); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* adapterData = (HandleData*)adapter; + if (!adapterData->used) { return PAL_RESULT_INVALID_ADAPTER; } // create a slot for the device - Uint64 deviceIndex = 0; - HandleData* deviceData = getFreeHandleData(&deviceIndex); + HandleData* deviceData = getFreeHandleData(); if (!deviceData) { return PAL_RESULT_OUT_OF_MEMORY; } PalDevice* device = nullptr; PalResult ret; - ret = data->backend->createDevice(data->handle, features, &device); + ret = adapterData->backend->createDevice( + adapterData->handle, + features, + &device); + if (ret != PAL_RESULT_SUCCESS) { return ret; } - deviceData->backend = data->backend; + deviceData->backend = adapterData->backend; deviceData->handle = device; - *outDevice = TO_PAL_HANDLE(PalDevice, deviceIndex); + *outDevice = (PalDevice*)deviceData; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyDevice(PalDevice* device) { if (s_Graphics.initialized && device) { - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)device; + if (data->used) { data->backend->destroyDevice(data->handle); - data->used = false; + freeHandleData(data); } } } @@ -679,13 +660,13 @@ PalResult PAL_CALL palAllocateMemory( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* deviceData = findHandleData(index); - if (!deviceData) { + HandleData* data = (HandleData*)device; + if (!data->used) { return PAL_RESULT_INVALID_DEVICE; } - return deviceData->backend->allocateMemory( - deviceData->handle, + + return data->backend->allocateMemory( + data->handle, type, size, outMemory); @@ -696,10 +677,10 @@ void PAL_CALL palFreeMemory( PalMemory* memory) { if (s_Graphics.initialized && device && memory) { - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)device; + if (data->used) { data->backend->freeMemory(data->handle, memory); + freeHandleData(data); } } } @@ -721,23 +702,21 @@ PalResult PAL_CALL palCreateQueue( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* deviceData = (HandleData*)device; + if (!deviceData->used) { return PAL_RESULT_INVALID_DEVICE; } // create a slot for the queue - Uint64 queueIndex = 0; - HandleData* queueData = getFreeHandleData(&queueIndex); + HandleData* queueData = getFreeHandleData(); if (!queueData) { return PAL_RESULT_OUT_OF_MEMORY; } PalQueue* queue = nullptr; PalResult ret; - ret = data->backend->createQueue( - data->handle, + ret = deviceData->backend->createQueue( + deviceData->handle, type, &queue); @@ -745,21 +724,20 @@ PalResult PAL_CALL palCreateQueue( return ret; } - queueData->backend = data->backend; + queueData->backend = deviceData->backend; queueData->handle = queue; - *outQueue = TO_PAL_HANDLE(PalQueue, queueIndex); + *outQueue = (PalQueue*)queueData; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyQueue(PalQueue* queue) { if (s_Graphics.initialized && queue) { - Uint64 index = FROM_PAL_HANDLE(queue); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)queue; + if (data->used) { data->backend->destroyQueue(data->handle); - data->used = false; + freeHandleData(data); } } } @@ -769,12 +747,10 @@ bool PAL_CALL palCanQueuePresent( PalGraphicsWindow* window) { if (s_Graphics.initialized && queue) { - Uint64 index = FROM_PAL_HANDLE(queue); - HandleData* data = findHandleData(index); - if (!data) { - return false; + HandleData* data = (HandleData*)queue; + if (data->used) { + return data->backend->canQueuePresent(data->handle, window); } - return data->backend->canQueuePresent(data->handle, window); } return false; } @@ -800,11 +776,11 @@ PalResult PAL_CALL palEnumerateFormats( return PAL_RESULT_INSUFFICIENT_BUFFER; } - Uint64 index = FROM_PAL_HANDLE(adapter); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)adapter; + if (!data->used) { return PAL_RESULT_INVALID_ADAPTER; } + return data->backend->enumerateFormats(data->handle, count, outFormats); } @@ -816,11 +792,11 @@ bool PAL_CALL palIsFormatSupported( return false; } - Uint64 index = FROM_PAL_HANDLE(adapter); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)adapter; + if (!data->used) { return false; } + return data->backend->isFormatSupported(data->handle, format); } @@ -832,11 +808,11 @@ PalImageUsages PAL_CALL palQueryFormatImageUsages( return PAL_IMAGE_USAGE_UNDEFINED; } - Uint64 index = FROM_PAL_HANDLE(adapter); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)adapter; + if (!data->used) { return PAL_IMAGE_USAGE_UNDEFINED; } + return data->backend->queryFormatImageUsages(data->handle, format); } @@ -848,11 +824,11 @@ PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( return PAL_IMAGE_VIEW_USAGE_UNDEFINED; } - Uint64 index = FROM_PAL_HANDLE(adapter); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)adapter; + if (!data->used) { return PAL_IMAGE_VIEW_USAGE_UNDEFINED; } + return data->backend->queryFormatImageViewUsages(data->handle, format); } @@ -873,15 +849,13 @@ PalResult PAL_CALL palCreateImage( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)device; + if (!data->used) { return PAL_RESULT_INVALID_DEVICE; } // create a slot for the image - Uint64 imageIndex = 0; - HandleData* imageData = getFreeHandleData(&imageIndex); + HandleData* imageData = getFreeHandleData(); if (!imageData) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -900,18 +874,17 @@ PalResult PAL_CALL palCreateImage( imageData->backend = data->backend; imageData->handle = image; - *outImage = TO_PAL_HANDLE(PalImage, imageIndex); + *outImage = (PalImage*)imageData; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyImage(PalImage* image) { if (s_Graphics.initialized && image) { - Uint64 index = FROM_PAL_HANDLE(image); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)image; + if (data->used) { data->backend->destroyImage(data->handle); - data->used = false; + freeHandleData(data); } } } @@ -928,16 +901,15 @@ PalResult PAL_CALL palGetImageInfo( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(image); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)image; + if (!data->used) { return PAL_RESULT_INVALID_IMAGE; } + return data->backend->getImageInfo(data->handle, info); } PalResult PAL_CALL palGetImageMemoryRequirements( - PalDevice* device, PalImage* image, PalMemoryRequirements* requirements) { @@ -945,31 +917,25 @@ PalResult PAL_CALL palGetImageMemoryRequirements( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device || !image) { + if (!image) { return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - - index = FROM_PAL_HANDLE(image); - HandleData* imageData = findHandleData(index); + HandleData* data = (HandleData*)image; if (!data) { - return PAL_RESULT_INVALID_DEVICE; + return PAL_RESULT_INVALID_IMAGE; } - if (!imageData) { + if (!data->used) { return PAL_RESULT_INVALID_IMAGE; } return data->backend->getImageMemoryRequirements( data->handle, - imageData->handle, requirements); } PalResult PAL_CALL palBindImageMemory( - PalDevice* device, PalImage* image, PalMemory* memory, Uint64 offset) @@ -978,26 +944,17 @@ PalResult PAL_CALL palBindImageMemory( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device || !image || !memory) { + if (!image || !memory) { return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - - index = FROM_PAL_HANDLE(image); - HandleData* imageData = findHandleData(index); + HandleData* data = (HandleData*)image; if (!data) { - return PAL_RESULT_INVALID_DEVICE; - } - - if (!imageData) { return PAL_RESULT_INVALID_IMAGE; } return data->backend->bindImageMemory( data->handle, - imageData->handle, memory, offset); } @@ -1020,30 +977,26 @@ PalResult PAL_CALL palCreateImageView( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - - index = FROM_PAL_HANDLE(image); - HandleData* imageData = findHandleData(index); - if (!data) { + HandleData* deviceData = (HandleData*)device; + HandleData* imageData = (HandleData*)image; + if (!deviceData->used) { return PAL_RESULT_INVALID_DEVICE; } - if (!imageData) { + if (!imageData->used) { return PAL_RESULT_INVALID_IMAGE; } - // create a slot for the image view - Uint64 imageViewIndex = 0; - HandleData* imageViewData = getFreeHandleData(&imageViewIndex); + // create a slot for the image views + HandleData* imageViewData = getFreeHandleData(); if (!imageViewData) { return PAL_RESULT_OUT_OF_MEMORY; } PalImageView* imageView = nullptr; PalResult ret; - ret = data->backend->createImageView( - data->handle, + ret = deviceData->backend->createImageView( + deviceData->handle, imageData->handle, info, &imageView); @@ -1052,21 +1005,20 @@ PalResult PAL_CALL palCreateImageView( return ret; } - imageViewData->backend = data->backend; + imageViewData->backend = deviceData->backend; imageViewData->handle = imageView; - *outImageView = TO_PAL_HANDLE(PalImageView, imageViewIndex); + *outImageView = (PalImageView*)imageViewData; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyImageView(PalImageView* imageView) { if (s_Graphics.initialized && imageView) { - Uint64 index = FROM_PAL_HANDLE(imageView); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)imageView; + if (data->used) { data->backend->destroyImageView(data->handle); - data->used = false; + freeHandleData(data); } } } @@ -1088,9 +1040,8 @@ PalResult PAL_CALL palQuerySwapchainCapabilities( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(adapter); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)adapter; + if (!data->used) { return PAL_RESULT_INVALID_ADAPTER; } @@ -1115,30 +1066,36 @@ PalResult PAL_CALL palCreateSwapchain( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); + HandleData* imagesData = nullptr; + imagesData = palAllocate( + s_Graphics.allocator, + sizeof(HandleData) * info->imageCount, + 0); - index = FROM_PAL_HANDLE(queue); - HandleData* queueData = findHandleData(index); - if (!data) { + if (!imagesData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + HandleData* deviceData = (HandleData*)device; + HandleData* queueData = (HandleData*)queue; + if (!deviceData->used) { return PAL_RESULT_INVALID_DEVICE; } - if (!queueData) { + if (!queueData->used) { return PAL_RESULT_INVALID_QUEUE; } // create a slot for the swapchain - Uint64 swapchainIndex = 0; - HandleData* swapchainData = getFreeHandleData(&swapchainIndex); + HandleData* swapchainData = getFreeHandleData(); if (!swapchainData) { return PAL_RESULT_OUT_OF_MEMORY; } PalResult ret; PalSwapchain* swapchain = nullptr; - ret = data->backend->createSwapchain( - data->handle, + ret = deviceData->backend->createSwapchain( + deviceData->handle, queueData->handle, window, info, @@ -1147,22 +1104,36 @@ PalResult PAL_CALL palCreateSwapchain( if (ret != PAL_RESULT_SUCCESS) { return ret; } + + // cache the swapchain images so we dont create new handles + // for them anytime they are queried + for (int i = 0; i < info->imageCount; i++) { + PalImage* image = deviceData->backend->getSwapchainImage(swapchain, i); + HandleData* tmp = &imagesData[i]; + tmp->backend = swapchainData->backend; + tmp->handle = image; + tmp->used = true; + tmp->shouldFree = false; // we free all at once + tmp->data = nullptr; + } - swapchainData->backend = data->backend; + swapchainData->backend = deviceData->backend; swapchainData->handle = swapchain; + swapchainData->data = (void*)imagesData; + swapchainData->data2 = info->imageCount; - *outSwapchain = TO_PAL_HANDLE(PalSwapchain, swapchainIndex); + *outSwapchain = (PalSwapchain*)swapchainData; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) { if (s_Graphics.initialized && swapchain) { - Uint64 index = FROM_PAL_HANDLE(swapchain); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)swapchain; + if (data->used) { data->backend->destroySwapchain(data->handle); - data->used = false; + palFree(s_Graphics.allocator, data->data); + freeHandleData(data); } } } @@ -1170,11 +1141,8 @@ void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) Uint32 PAL_CALL palGetSwapchainImageCount(PalSwapchain* swapchain) { if (s_Graphics.initialized && swapchain) { - Uint64 index = FROM_PAL_HANDLE(swapchain); - HandleData* data = findHandleData(index); - if (data) { - return data->backend->getSwapchainImageCount(data->handle); - } + HandleData* data = (HandleData*)swapchain; + return data->data2; } return 0; } @@ -1187,31 +1155,17 @@ PalImage* PAL_CALL palGetSwapchainImage( return nullptr; } - Uint64 swapchainIndex = FROM_PAL_HANDLE(swapchain); - HandleData* data = findHandleData(swapchainIndex); - if (!data) { + HandleData* data = (HandleData*)swapchain; + if (!data->used) { return nullptr; } - PalImage* image = data->backend->getSwapchainImage( - data->handle, - index); - - // check if the user has already requested for the image - Uint64 imageIndex = FROM_PAL_HANDLE(image); - HandleData* imageData = findHandleData(imageIndex); - if (!imageData) { - // create a new slot - imageData = getFreeHandleData(&imageIndex); - if (!imageData) { - return nullptr; - } + if (index > data->data2) { + return nullptr; } - imageData->backend = data->backend; - imageData->handle = image; - - return TO_PAL_HANDLE(PalImage, imageIndex); + HandleData* imagesData = data->data; + return (PalImage*)&imagesData[index]; } PalImage* PAL_CALL palGetNextSwapchainImage( @@ -1223,42 +1177,38 @@ PalImage* PAL_CALL palGetNextSwapchainImage( return nullptr; } - Uint64 index = FROM_PAL_HANDLE(swapchain); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)swapchain; + if (!data->used) { return nullptr; } void* FenceHandle = nullptr; if (fence) { - index = FROM_PAL_HANDLE(fence); - HandleData* tmp = findHandleData(index); - if (!tmp) { + HandleData* tmp = (HandleData*)fence; + if (!tmp->used) { return nullptr; } FenceHandle = tmp->handle; } - PalImage* image = data->backend->getNextSwapchainImage( + PalImage* tmp = data->backend->getNextSwapchainImage( data->handle, FenceHandle, timeout); - // check if the image has been requested already - Uint64 imageIndex = FROM_PAL_HANDLE(image); - HandleData* imageData = findHandleData(imageIndex); - if (!imageData) { - // create a new slot - imageData = getFreeHandleData(&imageIndex); - if (!imageData) { - return nullptr; + // loop through all our cache images and get the handle data + // associated with the image + HandleData* imagesData = data->data; + HandleData* imageData = nullptr; + for (int i = 0; i < data->data2; i++) { + if (imagesData[i].handle == tmp) { + // found our handle info + imageData = &imagesData[i]; + break; } } - imageData->backend = data->backend; - imageData->handle = image; - - return TO_PAL_HANDLE(PalImage, imageIndex); + return (PalImage*)imageData; } PalResult PAL_CALL palPresentSwapchain( @@ -1273,19 +1223,19 @@ PalResult PAL_CALL palPresentSwapchain( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(swapchain); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* swapchainData = (HandleData*)swapchain; + if (!swapchainData->used) { return PAL_RESULT_INVALID_SWAPCHAIN; } - index = FROM_PAL_HANDLE(image); - HandleData* imageData = findHandleData(index); - if (!imageData) { + HandleData* imageData = (HandleData*)image; + if (!imageData->used) { return PAL_RESULT_INVALID_IMAGE; } - return data->backend->presentSwapchain(data->handle, imageData->handle); + return swapchainData->backend->presentSwapchain( + swapchainData->handle, + imageData->handle); } // ================================================== @@ -1309,15 +1259,13 @@ PalResult PAL_CALL palCreateShader( return PAL_RESULT_INVALID_SHADER_TYPE; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)device; + if (!data->used) { return PAL_RESULT_INVALID_DEVICE; } // create a slot for the shader - Uint64 shaderIndex = 0; - HandleData* shaderData = getFreeHandleData(&shaderIndex); + HandleData* shaderData = getFreeHandleData(); if (!shaderData) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -1336,18 +1284,17 @@ PalResult PAL_CALL palCreateShader( shaderData->backend = data->backend; shaderData->handle = shader; - *outShader = TO_PAL_HANDLE(PalShader, shaderIndex); + *outShader = (PalShader*)shaderData; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyShader(PalShader* shader) { if (s_Graphics.initialized && shader) { - Uint64 index = FROM_PAL_HANDLE(shader); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)shader; + if (data->used) { data->backend->destroyShader(data->handle); - data->used = false; + freeHandleData(data); } } } @@ -1355,9 +1302,8 @@ void PAL_CALL palDestroyShader(PalShader* shader) PalShaderType PAL_CALL palGetShaderType(PalShader* shader) { if (s_Graphics.initialized && shader) { - Uint64 index = FROM_PAL_HANDLE(shader); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)shader; + if (data->used) { return data->backend->getShaderType(data->handle); } } @@ -1385,9 +1331,8 @@ PalResult PAL_CALL palCreateRenderPass( return PAL_RESULT_INSUFFICIENT_BUFFER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)device; + if (!data->used) { return PAL_RESULT_INVALID_DEVICE; } @@ -1395,14 +1340,19 @@ PalResult PAL_CALL palCreateRenderPass( PalRenderPassCreateInfo createInfo = {0}; createInfo.attachmentCount = info->attachmentCount; createInfo.attachments = attachments; + createInfo.width = info->width; + createInfo.height = info->height; for (int i = 0; i < info->attachmentCount; i++) { if (!info->attachments[i].target) { return PAL_RESULT_NULL_POINTER; } - index = FROM_PAL_HANDLE(info->attachments[i].target); - HandleData* tmp = findHandleData(index); + HandleData* tmp = (HandleData*)info->attachments[i].target; + if (!tmp->used) { + return PAL_RESULT_INVALID_IMAGE_VIEW; + } + attachments[i].target = tmp->handle; attachments[i].loadOp = info->attachments[i].loadOp; attachments[i].storeOp = info->attachments[i].storeOp; @@ -1410,15 +1360,16 @@ PalResult PAL_CALL palCreateRenderPass( attachments[i].resolveTarget = nullptr; if (info->attachments[i].resolveTarget) { - index = FROM_PAL_HANDLE(info->attachments[i].target); - tmp = findHandleData(index); + tmp = (HandleData*)info->attachments[i].resolveTarget; + if (!tmp->used) { + return PAL_RESULT_INVALID_IMAGE_VIEW; + } attachments[i].resolveTarget = tmp->handle; } } // create a slot for the renderpass - Uint64 renderPassIndex = 0; - HandleData* renderPassData = getFreeHandleData(&renderPassIndex); + HandleData* renderPassData = getFreeHandleData(); if (!renderPassData) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -1437,18 +1388,17 @@ PalResult PAL_CALL palCreateRenderPass( renderPassData->backend = data->backend; renderPassData->handle = renderpass; - *outRenderPass = TO_PAL_HANDLE(PalRenderPass, renderPassIndex); + *outRenderPass = (PalRenderPass*)renderPassData; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) { if (s_Graphics.initialized && renderPass) { - Uint64 index = FROM_PAL_HANDLE(renderPass); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)renderPass; + if (data->used) { data->backend->destroyRenderPass(data->handle); - data->used = false; + freeHandleData(data); } } } @@ -1469,15 +1419,13 @@ PalResult PAL_CALL palCreateFence( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)device; + if (!data->used) { return PAL_RESULT_INVALID_DEVICE; } // create a slot for the fence - Uint64 fenceIndex = 0; - HandleData* fenceData = getFreeHandleData(&fenceIndex); + HandleData* fenceData = getFreeHandleData(); if (!fenceData) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -1492,18 +1440,17 @@ PalResult PAL_CALL palCreateFence( fenceData->backend = data->backend; fenceData->handle = fence; - *outFence = TO_PAL_HANDLE(PalFence, fenceIndex); + *outFence = (PalFence*)fenceData; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyFence(PalFence* fence) { if (s_Graphics.initialized && fence) { - Uint64 index = FROM_PAL_HANDLE(fence); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)fence; + if (data->used) { data->backend->destroyFence(data->handle); - data->used = false; + freeHandleData(data); } } } @@ -1520,9 +1467,8 @@ PalResult PAL_CALL palWaitFence( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(fence); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)fence; + if (!data->used) { return PAL_RESULT_INVALID_FENCE; } @@ -1532,9 +1478,8 @@ PalResult PAL_CALL palWaitFence( bool PAL_CALL palIsFenceSignaled(PalFence* fence) { if (s_Graphics.initialized && fence) { - Uint64 index = FROM_PAL_HANDLE(fence); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)fence; + if (data->used) { return data->backend->isFenceSignaled(data->handle); } } @@ -1558,45 +1503,56 @@ PalResult PAL_CALL palCreateCommandPool( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - if (!data) { + if (!info->queue) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* deviceData = (HandleData*)device; + if (!deviceData->used) { return PAL_RESULT_INVALID_DEVICE; } + HandleData* queueData = (HandleData*)info->queue; + if (!queueData->used) { + return PAL_RESULT_INVALID_QUEUE; + } + + PalCommandPoolCreateInfo createInfo = {0}; + createInfo.queue = queueData->handle; + createInfo.resettable = info->resettable; + createInfo.transient = info->transient; + // create a slot for the command pool - Uint64 poolIndex = 0; - HandleData* poolData = getFreeHandleData(&poolIndex); + HandleData* poolData = getFreeHandleData(); if (!poolData) { return PAL_RESULT_OUT_OF_MEMORY; } PalCommandPool* pool = nullptr; PalResult ret; - ret = data->backend->createCommandPool( - data->handle, - info, + ret = deviceData->backend->createCommandPool( + deviceData->handle, + &createInfo, &pool); if (ret != PAL_RESULT_SUCCESS) { return ret; } - poolData->backend = data->backend; + poolData->backend = deviceData->backend; poolData->handle = pool; - *outPool = TO_PAL_HANDLE(PalCommandPool, poolIndex); + *outPool = (PalCommandPool*)poolData; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) { if (s_Graphics.initialized && pool) { - Uint64 index = FROM_PAL_HANDLE(pool); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)pool; + if (data->used) { data->backend->destroyCommandPool(data->handle); - data->used = false; + freeHandleData(data); } } } @@ -1615,21 +1571,18 @@ PalResult PAL_CALL palCreateCommandBuffer( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(device); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)device; + if (!data->used) { return PAL_RESULT_INVALID_DEVICE; } - index = FROM_PAL_HANDLE(pool); - HandleData* poolData = findHandleData(index); - if (!poolData) { + HandleData* poolData = (HandleData*)pool; + if (!poolData->used) { return PAL_RESULT_INVALID_COMMAND_POOL; } // create a slot for the command buffer - Uint64 cmdBufferIndex = 0; - HandleData* cmdBufferData = getFreeHandleData(&cmdBufferIndex); + HandleData* cmdBufferData = getFreeHandleData(); if (!cmdBufferData) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -1649,18 +1602,17 @@ PalResult PAL_CALL palCreateCommandBuffer( cmdBufferData->backend = data->backend; cmdBufferData->handle = cmdBuffer; - *outCmdBuffer = TO_PAL_HANDLE(PalCommandBuffer, cmdBufferIndex); + *outCmdBuffer = (PalCommandBuffer*)cmdBufferData; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) { if (s_Graphics.initialized && cmdBuffer) { - Uint64 index = FROM_PAL_HANDLE(cmdBuffer); - HandleData* data = findHandleData(index); - if (data) { + HandleData* data = (HandleData*)cmdBuffer; + if (data->used) { data->backend->destroyCommandBuffer(data->handle); - data->used = false; + freeHandleData(data); } } } @@ -1675,9 +1627,8 @@ PalResult PAL_CALL palBeginRendering(PalCommandBuffer* cmdBuffer) return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(cmdBuffer); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)cmdBuffer; + if (!data->used) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } @@ -1694,9 +1645,8 @@ PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer) return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(cmdBuffer); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)cmdBuffer; + if (!data->used) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } @@ -1715,16 +1665,14 @@ PalResult PAL_CALL palExecuteCommandBuffer( return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(primaryCmdBuffer); - HandleData* data = findHandleData(index); - index = FROM_PAL_HANDLE(secondaryCmdBuffer); - HandleData* secondaryCmdBufferData = findHandleData(index); - if (!data || !secondaryCmdBufferData) { + HandleData* primaryCmdBufferData = (HandleData*)primaryCmdBuffer; + HandleData* secondaryCmdBufferData = (HandleData*)secondaryCmdBuffer; + if (!primaryCmdBufferData->used || secondaryCmdBufferData->used) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } - return data->backend->executeCommandBuffer( - data->handle, + return primaryCmdBufferData->backend->executeCommandBuffer( + primaryCmdBufferData->handle, secondaryCmdBufferData->handle); } @@ -1746,20 +1694,18 @@ PalResult PAL_CALL palBeginRenderPass( return PAL_RESULT_INSUFFICIENT_BUFFER; } - Uint64 index = FROM_PAL_HANDLE(cmdBuffer); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* cmdBufferData = (HandleData*)cmdBuffer; + if (!cmdBufferData->used) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } - index = FROM_PAL_HANDLE(renderPass); - HandleData* renderPassData = findHandleData(index); - if (!renderPassData) { + HandleData* renderPassData = (HandleData*)renderPass; + if (!renderPassData->used) { return PAL_RESULT_INVALID_RENDER_PASS; } - return data->backend->beginRenderPass( - data->handle, + return cmdBufferData->backend->beginRenderPass( + cmdBufferData->handle, renderPassData->handle, clearValueCount, clearValues); @@ -1775,9 +1721,8 @@ PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer) return PAL_RESULT_NULL_POINTER; } - Uint64 index = FROM_PAL_HANDLE(cmdBuffer); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)cmdBuffer; + if (!data->used) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } @@ -1802,30 +1747,28 @@ PalResult PAL_CALL palSubmitCommandBuffer( return PAL_RESULT_INSUFFICIENT_BUFFER; } - Uint64 index = FROM_PAL_HANDLE(queue); - HandleData* data = findHandleData(index); - if (!data) { + HandleData* data = (HandleData*)queue; + if (!data->used) { return PAL_RESULT_INVALID_QUEUE; } - HandleData* fenceData = nullptr; void* fenceHandle = nullptr; if (fence) { - index = FROM_PAL_HANDLE(fence); - fenceData = findHandleData(index); - fenceHandle = fenceData->handle; + HandleData* tmp = (HandleData*)fence; + if (tmp->used) { + fenceHandle = tmp->handle; + } } // 16 should be more than enough PalCommandBuffer* cmdHandles[16]; for (int i = 0; i < cmdBufferCount; i++) { // get the cmd buffer handles - index = FROM_PAL_HANDLE(cmdBuffers[i]); - HandleData* cmdBufferData = findHandleData(index); - if (!cmdBufferData) { + HandleData* tmp = (HandleData*)cmdBuffers[i]; + if (!tmp->used) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } - cmdHandles[i] = cmdBufferData->handle; + cmdHandles[i] = tmp->handle; } return data->backend->submitCommandBuffer( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 3aaa6332..27fd1f24 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -154,6 +154,9 @@ typedef struct { struct PalDevice { PalAdapterFeatures features; Int32 queueCount; + Int32 gpuOnlyMemoryIndex; + Int32 cpuUploadMemoryIndex; + Int32 cpuReadbackMemoryIndex; VkPhysicalDevice phyDevice; VkDevice handle; PhysicalQueue* phyQueues; @@ -162,7 +165,6 @@ struct PalDevice { PFN_vkGetSwapchainImagesKHR getSwapchainImages; PFN_vkAcquireNextImageKHR acquireNextImage; PFN_vkQueuePresentKHR queuePresent; - Int32 memoryTypeIndex[PAL_MEMORY_TYPE_MAX]; }; struct PalQueue { @@ -211,11 +213,6 @@ struct PalRenderPass { PalDevice* device; VkRenderPass handle; VkFramebuffer framebuffer; - VkAttachmentReference depthRef; - VkAttachmentDescription attachments[MAX_ATTACHMENTS]; - VkAttachmentReference colorRefs[MAX_ATTACHMENTS]; - VkAttachmentReference resolveRefs[MAX_ATTACHMENTS]; - VkImageView views[MAX_ATTACHMENTS]; }; struct PalCommandPool { @@ -2209,24 +2206,20 @@ PalResult PAL_CALL createVkDevice( // cache memory type indices VkPhysicalDeviceMemoryProperties memProps = {0}; s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); - device->memoryTypeIndex[PAL_MEMORY_TYPE_GPU_ONLY] = -1; - device->memoryTypeIndex[PAL_MEMORY_TYPE_GPU_ONLY] = -1; - device->memoryTypeIndex[PAL_MEMORY_TYPE_GPU_ONLY] = -1; - for (int i = 0; i < memProps.memoryTypeCount; i++) { VkMemoryPropertyFlags prop = memProps.memoryTypes[i].propertyFlags; if (prop & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { - device->memoryTypeIndex[PAL_MEMORY_TYPE_GPU_ONLY] = i; + device->gpuOnlyMemoryIndex = i; } if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { - device->memoryTypeIndex[PAL_MEMORY_TYPE_CPU_UPLOAD] = i; + device->cpuUploadMemoryIndex = i; } if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { - device->memoryTypeIndex[PAL_MEMORY_TYPE_CPU_READBACK] = i; + device->cpuReadbackMemoryIndex = i; } } @@ -2280,7 +2273,15 @@ PalResult PAL_CALL allocateVkMemory( VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = (VkDeviceSize)size; - allocateInfo.memoryTypeIndex = device->memoryTypeIndex[type]; + if (type == PAL_MEMORY_TYPE_GPU_ONLY) { + allocateInfo.memoryTypeIndex = device->gpuOnlyMemoryIndex; + + } else if (type == PAL_MEMORY_TYPE_CPU_UPLOAD) { + allocateInfo.memoryTypeIndex = device->cpuUploadMemoryIndex; + + } else if (type == PAL_MEMORY_TYPE_CPU_READBACK) { + allocateInfo.memoryTypeIndex = device->cpuReadbackMemoryIndex; + } if (allocateInfo.memoryTypeIndex == -1) { // not supported @@ -2622,10 +2623,10 @@ PalResult PAL_CALL getVkImageInfo( } PalResult PAL_CALL getVkImageMemoryRequirements( - PalDevice* device, PalImage* image, PalMemoryRequirements* requirements) { + PalDevice* device = image->device; VkPhysicalDevice phyDevice = (VkPhysicalDevice)device->phyDevice; VkPhysicalDeviceMemoryProperties memProps = {0}; s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); @@ -2664,7 +2665,6 @@ PalResult PAL_CALL getVkImageMemoryRequirements( } PalResult PAL_CALL bindVkImageMemory( - PalDevice* device, PalImage* image, PalMemory* memory, Uint64 offset) @@ -2672,8 +2672,9 @@ PalResult PAL_CALL bindVkImageMemory( if (image->belongsToSwapchain) { return PAL_RESULT_INVALID_OPERATION; } + VkDeviceMemory mem = (VkDeviceMemory)memory; - s_Vk.bindImageMemory(device->handle, image->handle, mem, offset); + s_Vk.bindImageMemory(image->device->handle, image->handle, mem, offset); } // ================================================== @@ -3065,11 +3066,6 @@ void PAL_CALL destroyVkSwapchain(PalSwapchain* swapchain) palFree(s_Vk.allocator, swapchain); } -Uint32 PAL_CALL getVkSwapchainImageCount(PalSwapchain* swapchain) -{ - return swapchain->imageCount; -} - PalImage* PAL_CALL getVkSwapchainImage( PalSwapchain* swapchain, Int32 index) @@ -3085,14 +3081,19 @@ PalImage* PAL_CALL getVkNextSwapchainImage( PalFence* fence, Uint64 timeout) { - Uint32 index = 0; VkResult result; + Uint32 index = 0; + VkFence fenceHandle = nullptr; + if (fence) { + fenceHandle = fence->handle; + } + result = swapchain->device->acquireNextImage( - swapchain->device->handle, + swapchain->device->handle, swapchain->handle, timeout, VK_NULL_HANDLE, - fence->handle, + fenceHandle, &index); if (result != VK_SUCCESS) { @@ -3234,12 +3235,18 @@ PalResult PAL_CALL createVkRenderPass( return PAL_RESULT_OUT_OF_MEMORY; } + VkAttachmentReference depthRef; + VkAttachmentDescription attachments[MAX_ATTACHMENTS]; + VkAttachmentReference colorRefs[MAX_ATTACHMENTS]; + VkAttachmentReference resolveRefs[MAX_ATTACHMENTS]; + VkImageView views[MAX_ATTACHMENTS]; + renderpass->hasDepth = false; Uint32 colorRefCount = 0; Uint32 layers = 0; for (int i = 0; i < info->attachmentCount; i++) { PalAttachmentDesc* desc = &info->attachments[i]; - VkAttachmentDescription* rDesc = &renderpass->attachments[i]; + VkAttachmentDescription* rDesc = &attachments[i]; rDesc->format = palFormatToVk(desc->target->image->info.format); rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -3275,10 +3282,10 @@ PalResult PAL_CALL createVkRenderPass( } // add the image views from the attachments into a seperate array - renderpass->views[i] = desc->target->handle; + views[i] = desc->target->handle; if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { - VkAttachmentReference* ref = &renderpass->colorRefs[colorRefCount]; + VkAttachmentReference* ref = &colorRefs[colorRefCount]; rDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; ref->attachment = i; ref->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; @@ -3291,9 +3298,8 @@ PalResult PAL_CALL createVkRenderPass( rDesc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; rDesc->stencilLoadOp = rDesc->loadOp; rDesc->stencilStoreOp = rDesc->storeOp; - VkAttachmentReference* ref = &renderpass->depthRef; - ref->attachment = i; - ref->layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + depthRef.attachment = i; + depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; renderpass->hasDepth = true; } } @@ -3303,16 +3309,16 @@ PalResult PAL_CALL createVkRenderPass( VkSubpassDescription subpassDesc = {0}; subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpassDesc.colorAttachmentCount = colorRefCount; - subpassDesc.pColorAttachments = renderpass->colorRefs; + subpassDesc.pColorAttachments = colorRefs; if (renderpass->hasDepth) { - subpassDesc.pDepthStencilAttachment = &renderpass->depthRef; + subpassDesc.pDepthStencilAttachment = &depthRef; } // render pass VkRenderPassCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; createInfo.attachmentCount = info->attachmentCount; - createInfo.pAttachments = renderpass->attachments; + createInfo.pAttachments = attachments; createInfo.subpassCount = 1; createInfo.pSubpasses = &subpassDesc; @@ -3331,10 +3337,11 @@ PalResult PAL_CALL createVkRenderPass( VkFramebufferCreateInfo fbCreateInfo = {0}; fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; fbCreateInfo.attachmentCount = info->attachmentCount; - fbCreateInfo.pAttachments = renderpass->views; + fbCreateInfo.pAttachments = views; fbCreateInfo.height = info->height; fbCreateInfo.width = info->width; fbCreateInfo.layers = layers; + fbCreateInfo.renderPass = renderpass->handle; result = s_Vk.createFramebuffer( device->handle, @@ -3358,6 +3365,8 @@ PalResult PAL_CALL createVkRenderPass( renderpass->device = device; renderpass->width = info->width; renderpass->height = info->height; + renderpass->attachmentCount = info->attachmentCount; + *outRenderPass = renderpass; return PAL_RESULT_SUCCESS; } @@ -3615,9 +3624,8 @@ PalResult PAL_CALL beginRenderPassVk( VkClearValue tmp[MAX_ATTACHMENTS]; for (int i = 0; i < clearValueCount; i++) { - VkAttachmentDescription* desc = &renderPass->attachments[i]; PalClearValue* clearValue = &clearValues[i]; - if (desc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { + if (clearValue->depth == 0 && clearValue->stencil == 0) { // color attachment tmp[i].color.float32[0] = clearValue->color[0]; tmp[i].color.float32[1] = clearValue->color[1]; diff --git a/src/pal_core.c b/src/pal_core.c index 00476168..018e8cab 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -417,6 +417,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_IMAGE: return "Invalid image"; + case PAL_RESULT_INVALID_IMAGE_VIEW: + return "Invalid image view"; + case PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED: return "memory type not supported"; diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index ffe25d33..7bbe41b3 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -2797,6 +2797,7 @@ static int compareModes( } } +// TODO: rewrite this static WindowData* getFreeWindowData() { for (int i = 0; i < s_Video.maxWindowData; ++i) { @@ -2829,6 +2830,7 @@ static WindowData* getFreeWindowData() return nullptr; } +// TODO: remove this static WindowData* findWindowData(PalWindow* window) { for (int i = 0; i < s_Video.maxWindowData; ++i) { @@ -2848,6 +2850,7 @@ static void resetMonitorData() s_Video.maxMonitorData * sizeof(MonitorData)); } +// TODO: rewrite this static MonitorData* getFreeMonitorData() { for (int i = 0; i < s_Video.maxMonitorData; ++i) { @@ -2879,6 +2882,7 @@ static MonitorData* getFreeMonitorData() return nullptr; } +// TODO: remove this static MonitorData* findMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Video.maxMonitorData; ++i) { @@ -2890,6 +2894,7 @@ static MonitorData* findMonitorData(PalMonitor* monitor) return nullptr; } +// TODO: remove this static void freeMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Video.maxMonitorData; ++i) { diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c new file mode 100644 index 00000000..c77e9197 --- /dev/null +++ b/tests/clear_color_test.c @@ -0,0 +1,445 @@ + +#include "pal/pal_graphics.h" +#include "pal/pal_video.h" +#include "tests.h" + +bool clearColorTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Clear Color Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + PalResult result; + PalWindow* window = nullptr; + PalEventDriver* eventDriver = nullptr; + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + PalCommandBuffer** cmdBuffers = nullptr; + PalRenderPass** renderPasses = nullptr; + + // create an event driver + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create event driver: %s", error); + return false; + } + + // we only need window close and keydown(escape) for borderless window + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_WINDOW_CLOSE, + PAL_DISPATCH_POLL); + + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_KEYDOWN, + PAL_DISPATCH_POLL); + + // initialize the video system + // you can use any library you want + result = palInitVideo(nullptr, eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize video: %s", error); + return false; + } + + // create a window + PalWindowCreateInfo windowCreateInfo = {0}; + windowCreateInfo.height = 480; + windowCreateInfo.width = 640; + windowCreateInfo.show = true; + windowCreateInfo.title = "Clear Color Window"; + + // check if we support decorated windows (title bar, close etc) + PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); + if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + // if we dont support, we need to create a borderless window + // and create the decorations ourselves + windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&windowCreateInfo, &window); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create window: %s", error); + return false; + } + + // initialize the graphics system + result = palInitGraphics(false, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 count = 0; + result = palEnumerateAdapters(&count, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (count == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", count); + + // allocate an array of adapters or use a fixed array + // Example: PalAdapter* adapters[12]; + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&count, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + // get information about all the adapters and find the adapter that + // has graphics queue + PalAdapterCapabilities caps; + for (Int32 i = 0; i < count; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (caps.maxGraphicsQueues == 0) { + continue; + } else { + break; + } + } + + palFree(nullptr, adapters); + + // create a device + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + result = palCreateDevice(adapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a graphics command queue + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + // check if the queue can present on our window + PalWindowHandleInfo handleInfo; + PalGraphicsWindow gfxWindow; + handleInfo = palGetWindowHandleInfo(window); + gfxWindow.window = handleInfo.nativeWindow; + gfxWindow.display = handleInfo.nativeDisplay; + + if (!palCanQueuePresent(queue, &gfxWindow)) { + palLog(nullptr, "Queue cannot present to window"); + return false; + } + + // create a swapchain with the graphics queue + PalSwapchainCapabilities swapchainCaps = {0}; + result = palQuerySwapchainCapabilities( + adapter, + &gfxWindow, + &swapchainCaps); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to query swapchain capabilities: %s", error); + return false; + } + + PalSwapchainCreateInfo swapchainCreateInfo = {0}; + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + swapchainCreateInfo.height = windowCreateInfo.height; + swapchainCreateInfo.width = windowCreateInfo.width; + swapchainCreateInfo.imageArrayLayerCount = 1; + + // rare but possible on andriod + if (windowCreateInfo.width > swapchainCaps.maxImageWidth) { + swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; + } + + if (windowCreateInfo.height > swapchainCaps.maxImageHeight) { + swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; + } + + // check if the minimal image count is not good for you + // and increase it nut not pass the max count + swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + + result = palCreateSwapchain( + device, + queue, + &gfxWindow, + &swapchainCreateInfo, + &swapchain); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create swapchain: %s", error); + return false; + } + + // create a command pool for the command buffers + PalCommandPoolCreateInfo cmdPoolCreateInfo = {0}; + cmdPoolCreateInfo.queue = queue; + result = palCreateCommandPool(device, &cmdPoolCreateInfo, &cmdPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + // get all swapchain images and create command buffers and image views + // for them. This is much faster than resetting and recording per frames + Uint32 imageCount = swapchainCreateInfo.imageCount; + imageViews = palAllocate( + nullptr, + sizeof(PalImageView*) * imageCount, + 0); + + renderPasses = palAllocate( + nullptr, + sizeof(PalRenderPass*) * imageCount, + 0); + + cmdBuffers = palAllocate( + nullptr, + sizeof(PalCommandBuffer*) * imageCount, + 0); + + if (!imageViews || !renderPasses || !cmdBuffers) { + palLog(nullptr, "Failed to allocate memory"); + palFree(nullptr, imageViews); + palFree(nullptr, cmdBuffers); + palFree(nullptr, renderPasses); + return false; + } + + for (int i = 0; i < imageCount; i++) { + // get swapchain image + PalImage* image = palGetSwapchainImage(swapchain, i); + if (!image) { + palLog(nullptr, "Failed to get swapchain image"); + } + + // create image view + // swapchain images are 2D and they only supports 2D + // and 2D array view types + PalImageView* imageView = nullptr; + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.layerArrayCount = 1; + imageViewCreateInfo.mipLevelCount = 1; + imageViewCreateInfo.startArrayLayer = 0; + imageViewCreateInfo.startMipLevel = 0; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; + + result = palCreateImageView( + device, + image, + &imageViewCreateInfo, + &imageView); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + + // create a render pass with the image view as a color attahcment + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.type = PAL_ATTACHMENT_TYPE_COLOR; + colorAttachment.target = imageView; + + PalRenderPassCreateInfo renderPasscreateInfo = {0}; + renderPasscreateInfo.attachmentCount = 1; + renderPasscreateInfo.attachments = &colorAttachment; + + // render area + renderPasscreateInfo.width = swapchainCreateInfo.width; + renderPasscreateInfo.height = swapchainCreateInfo.height; + + PalRenderPass* renderPass = nullptr; + result = palCreateRenderPass( + device, + &renderPasscreateInfo, + &renderPass); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create render pass: %s", error); + return false; + } + + // create a command buffer for the image view + PalCommandBuffer* cmdBuffer = nullptr; + result = palCreateCommandBuffer(device, cmdPool, true, &cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command buffer: %s", error); + return false; + } + + // record commands + PalClearValue clearValue = {0}; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; + + result = palBeginRendering(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin rendering: %s", error); + return false; + } + + result = palBeginRenderPass(cmdBuffer, renderPass, 1, &clearValue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin render pass: %s", error); + return false; + } + + result = palEndRenderPass(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end render pass: %s", error); + return false; + } + + result = palEndRendering(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end rendering: %s", error); + return false; + } + + // cache everything so we can reference and destroy later + renderPasses[i] = renderPass; + cmdBuffers[i] = cmdBuffer; + imageViews[i] = imageView; + } + + // main loop + bool running = true; + while (running) { + // update the video system to push video events + palUpdateVideo(); + + PalEvent event; + while (palPollEvent(eventDriver, &event)) { + switch (event.type) { + case PAL_EVENT_WINDOW_CLOSE: { + running = false; + break; + } + + case PAL_EVENT_KEYDOWN: { + PalKeycode keycode = 0; + palUnpackUint32(event.data, &keycode, nullptr); + if (keycode == PAL_KEYCODE_ESCAPE) { + running = false; + } + break; + } + } + } + + // get the next image that we can render too + PalImage* image = nullptr; + image = palGetNextSwapchainImage(swapchain, nullptr, UINT64_MAX); + + // find the command buffer associated with the image + // this is fast, the swapchain caches all it images internally + PalCommandBuffer* cmdBuffer = nullptr; + for (int i = 0; i < imageCount; i++) { + if (image == palGetSwapchainImage(swapchain, i)) { + cmdBuffer = cmdBuffers[i]; + break; + } + } + + // submit to the queue and present + result = palSubmitCommandBuffer(queue, 1, &cmdBuffer, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + result = palPresentSwapchain(swapchain, image); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to present swapchain: %s", error); + return false; + } + } + + // since we dont use a fence or sempahore, there is no way to know + // if the GPU is done presenting and we can now destroy the swapchain + // so we just wait for a while + // and we dont want to use thread system for this + Int32 counter = 0; + for (int i = 0; i < 30000; i++) { + counter++; + } + + // cleanup + for (int i = 0; i < imageCount; i++) { + palDestroyRenderPass(renderPasses[i]); + palDestroyCommandBuffer(cmdBuffers[i]); + palDestroyImageView(imageViews[i]); + } + + palDestroyCommandPool(cmdPool); + palDestroySwapchain(swapchain); + palDestroyQueue(queue); + palDestroyDevice(device); + + palDestroyWindow(window); + palShutdownVideo(); + + palShutdownGraphics(); + + palFree(nullptr, imageViews); + palFree(nullptr, cmdBuffers); + palFree(nullptr, renderPasses); + + return true; +} \ No newline at end of file diff --git a/tests/tests.h b/tests/tests.h index 191850d1..a43c7bf8 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -55,13 +55,8 @@ bool multiThreadOpenGlTest(); // graphics bool graphicsTest(); -bool customGraphicsBackendTest(); -bool deviceTest(); -bool imageTest(); -bool renderPassTest(); // graphics and video -bool queueTest(); -bool swapchainTest(); +bool clearColorTest(); #endif // _TESTS_H \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index f30d5af9..b10266ed 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -69,5 +69,11 @@ project "tests" } end + if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then + files { + "clear_color_test.c" + } + end + includedirs { "%{wks.location}/include" } links { "PAL" } \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index 3153418f..17c21405 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,9 +55,13 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + // registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS +#if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO + registerTest("Clear Color Test", clearColorTest); +#endif // + runTests(); return 0; } \ No newline at end of file From 5502d2e5ec5ea5ec6605a190fdda9d0ed9781671 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Dec 2025 14:13:53 +0000 Subject: [PATCH 044/372] add reset fence API --- include/pal/pal_graphics.h | 48 +++++++++++++++++++++---------------- src/graphics/pal_graphics.c | 22 +++++++++++++++++ src/graphics/pal_vulkan.c | 15 ++++++++++++ tests/graphics_test.c | 4 ++++ 4 files changed, 68 insertions(+), 21 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index f7dd6aef..3db0d129 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -49,6 +49,7 @@ typedef struct PalShader PalShader; typedef struct PalRenderPass PalRenderPass; typedef struct PalFence PalFence; +typedef struct PalSemaphore PalSemaphore; typedef struct PalCommandPool PalCommandPool; typedef struct PalCommandBuffer PalCommandBuffer; @@ -210,27 +211,28 @@ typedef enum { PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY = PAL_BIT64(0), PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING = PAL_BIT64(1), PAL_ADAPTER_FEATURE_MULTI_VIEWPORT = PAL_BIT64(2), - PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(3), - PAL_ADAPTER_FEATURE_TESSELLATION_SHADER = PAL_BIT64(4), - PAL_ADAPTER_FEATURE_GEOMETRY_SHADER = PAL_BIT64(5), - PAL_ADAPTER_FEATURE_COMPUTE_SHADER = PAL_BIT64(6), - PAL_ADAPTER_FEATURE_SHADER_FLOAT16 = PAL_BIT64(7), - PAL_ADAPTER_FEATURE_SHADER_FLOAT64 = PAL_BIT64(8), - PAL_ADAPTER_FEATURE_SHADER_INT16 = PAL_BIT64(9), - PAL_ADAPTER_FEATURE_SHADER_INT64 = PAL_BIT64(10), - PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(11), - PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(12), - PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(13), - PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), - PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(15), - PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16), - PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(17), - PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(18), - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(19), - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(20), - PAL_ADAPTER_FEATURE_RESET_FENCE = PAL_BIT64(21), - PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(22), - PAL_ADAPTER_FEATURE_MULTI_QUEUE_SUBMIT = PAL_BIT64(23) + PAL_ADAPTER_FEATURE_SEMAPHORE = PAL_BIT64(3), + PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(4), + PAL_ADAPTER_FEATURE_TESSELLATION_SHADER = PAL_BIT64(5), + PAL_ADAPTER_FEATURE_GEOMETRY_SHADER = PAL_BIT64(6), + PAL_ADAPTER_FEATURE_COMPUTE_SHADER = PAL_BIT64(7), + PAL_ADAPTER_FEATURE_SHADER_FLOAT16 = PAL_BIT64(8), + PAL_ADAPTER_FEATURE_SHADER_FLOAT64 = PAL_BIT64(9), + PAL_ADAPTER_FEATURE_SHADER_INT16 = PAL_BIT64(10), + PAL_ADAPTER_FEATURE_SHADER_INT64 = PAL_BIT64(11), + PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(12), + PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(13), + PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(14), + PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(15), + PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(16), + PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(17), + PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(18), + PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(19), + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(20), + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(21), + PAL_ADAPTER_FEATURE_RESET_FENCE = PAL_BIT64(22), + PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(23), + PAL_ADAPTER_FEATURE_MULTI_QUEUE_SUBMIT = PAL_BIT64(24) } PalAdapterFeatures; typedef enum { @@ -571,6 +573,8 @@ typedef struct { PalFence* fence, Uint64 timeout); + PalResult PAL_CALL (*resetFence)(PalFence* fence); + bool PAL_CALL (*isFenceSignaled)(PalFence* fence); PalResult PAL_CALL (*createCommandPool)( @@ -767,6 +771,8 @@ PAL_API PalResult PAL_CALL palWaitFence( PalFence* fence, Uint64 timeout); +PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); + PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); PAL_API PalResult PAL_CALL palCreateCommandBuffer( diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index c3529029..2d71a13c 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -244,6 +244,8 @@ PalResult PAL_CALL waitVkFence( PalFence* fence, Uint64 timeout); +PalResult PAL_CALL resetVkFence(PalFence* fence); + bool PAL_CALL isVkFenceSignaled(PalFence* fence); PalResult PAL_CALL createVkCommandPool( @@ -319,6 +321,7 @@ static PalGraphicsBackend s_VkBackend = { .createFence = createVkFence, .destroyFence = destroyVkFence, .waitFenceTimeout = waitVkFence, + .resetFence = resetVkFence, .isFenceSignaled = isVkFenceSignaled, .createCommandPool = createVkCommandPool, .destroyCommandPool = destroyVkCommandPool, @@ -401,6 +404,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->createFence || !backend->destroyFence || !backend->waitFenceTimeout || + !backend->resetFence || !backend->isFenceSignaled || !backend->createCommandPool || !backend->destroyCommandPool || @@ -1475,6 +1479,24 @@ PalResult PAL_CALL palWaitFence( return data->backend->waitFenceTimeout(data->handle, timeout); } +PalResult PAL_CALL palResetFence(PalFence* fence) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!fence) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)fence; + if (!data->used) { + return PAL_RESULT_INVALID_FENCE; + } + + return data->backend->resetFence(data->handle); +} + bool PAL_CALL palIsFenceSignaled(PalFence* fence) { if (s_Graphics.initialized && fence) { diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 27fd1f24..e2985c40 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1909,6 +1909,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->features |= PAL_ADAPTER_FEATURE_RESET_FENCE; caps->features |= PAL_ADAPTER_FEATURE_TIMEOUT_FENCE; caps->features |= PAL_ADAPTER_FEATURE_MULTI_QUEUE_SUBMIT; + caps->features |= PAL_ADAPTER_FEATURE_SEMAPHORE; palFree(s_Vk.allocator, extensionProps); return PAL_RESULT_SUCCESS; @@ -3442,6 +3443,20 @@ PalResult PAL_CALL waitVkFence( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL resetVkFence(PalFence* fence) +{ + if (!(fence->device->features & PAL_ADAPTER_FEATURE_RESET_FENCE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkResult ret = s_Vk.resetFence(fence->device->handle, 1, &fence->handle); + if (ret != VK_SUCCESS) { + vkResultToPal(ret); + } + + return PAL_RESULT_SUCCESS; +} + bool PAL_CALL isVkFenceSignaled(PalFence* fence) { VkResult ret = s_Vk.isFenceSignaled(fence->device->handle, fence->handle); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 5999b9bd..ac6283f8 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -225,6 +225,10 @@ bool graphicsTest() palLog(nullptr, " Multi viewport"); } + if (caps.features & PAL_ADAPTER_FEATURE_SEMAPHORE) { + palLog(nullptr, " Semaphore"); + } + if (caps.features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { palLog(nullptr, " Timeline Semaphore"); } From ff04ebb91fa3903291ca924c6c93bd86374383f2 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Dec 2025 16:20:33 +0000 Subject: [PATCH 045/372] add semaphore API --- include/pal/pal_core.h | 1 + include/pal/pal_graphics.h | 77 +++++++++-- src/graphics/pal_graphics.c | 247 ++++++++++++++++++++++++++++++------ src/graphics/pal_vulkan.c | 211 ++++++++++++++++++++++++++---- src/pal_core.c | 3 + tests/clear_color_test.c | 14 +- tests/graphics_test.c | 4 - 7 files changed, 471 insertions(+), 86 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index e8caf477..11f3f5aa 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -265,6 +265,7 @@ typedef enum { PAL_RESULT_INVALID_COMMAND_POOL, PAL_RESULT_INVALID_COMMAND_BUFFER, PAL_RESULT_INVALID_FENCE, + PAL_RESULT_INVALID_SEMAPHORE, PAL_RESULT_INVALID_RENDER_PASS } PalResult; diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 3db0d129..903c223c 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -231,8 +231,7 @@ typedef enum { PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(20), PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(21), PAL_ADAPTER_FEATURE_RESET_FENCE = PAL_BIT64(22), - PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(23), - PAL_ADAPTER_FEATURE_MULTI_QUEUE_SUBMIT = PAL_BIT64(24) + PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(23) } PalAdapterFeatures; typedef enum { @@ -379,6 +378,28 @@ typedef struct { Uint32 stencil; } PalClearValue; +typedef struct { + Uint64 waitValue; + Uint64 signalValue; + PalCommandBuffer* cmdBuffer; + PalSemaphore* waitSemaphore; + PalSemaphore* signalSemaphore; + PalFence* fence; +} PalSubmitInfo; + +typedef struct { + Uint64 timeout; + Uint64 signalValue; + PalSemaphore* signalSemaphore; + PalFence* fence; +} PalNextImageInfo; + +typedef struct { + Uint64 waitValue; + PalImage* image; + PalSemaphore* waitSemaphore; +} PalPresentInfo; + typedef struct { Uint32 width; Uint32 height; @@ -540,12 +561,11 @@ typedef struct { PalImage* PAL_CALL (*getNextSwapchainImage)( PalSwapchain* swapchain, - PalFence* fence, - Uint64 timeout); + PalNextImageInfo* info); PalResult PAL_CALL (*presentSwapchain)( PalSwapchain* swapchain, - PalImage* image); + PalPresentInfo* info); PalResult PAL_CALL (*createShader)( PalDevice* device, @@ -577,6 +597,23 @@ typedef struct { bool PAL_CALL (*isFenceSignaled)(PalFence* fence); + PalResult PAL_CALL (*createSemaphore)( + PalDevice* device, + PalSemaphore** outSemaphore); + + void PAL_CALL (*destroySemaphore)(PalSemaphore* semaphore); + + PalResult PAL_CALL (*waitSemaphore)( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value, + Uint64 timeout); + + PalResult PAL_CALL (*signalSemaphore)( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value); + PalResult PAL_CALL (*createCommandPool)( PalDevice* device, const PalCommandPoolCreateInfo* info, @@ -610,9 +647,7 @@ typedef struct { PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, - Int32 cmdBufferCount, - PalCommandBuffer** cmdBuffers, - PalFence* fence); + PalSubmitInfo* info); } PalGraphicsBackend; PAL_API PalResult PAL_CALL palAddGraphicsBackend( @@ -731,12 +766,11 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PAL_API PalImage* PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, - PalFence* fence, - Uint64 timeout); + PalNextImageInfo* info); PAL_API PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, - PalImage* image); + PalPresentInfo* info); PAL_API PalResult PAL_CALL palCreateShader( PalDevice* device, @@ -775,6 +809,23 @@ PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); +PAL_API PalResult PAL_CALL palCreateSemaphore( + PalDevice* device, + PalSemaphore** outSemaphore); + +PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); + +PAL_API PalResult PAL_CALL palWaitSemaphore( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value, + Uint64 timeout); + +PAL_API PalResult PAL_CALL palSignalSemaphore( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value); + PAL_API PalResult PAL_CALL palCreateCommandBuffer( PalDevice* device, PalCommandPool* pool, @@ -801,9 +852,7 @@ PAL_API PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer); PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, - Int32 cmdBufferCount, - PalCommandBuffer** cmdBuffers, - PalFence* fence); + PalSubmitInfo* info); /** @} */ // end of pal_graphics group diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 2d71a13c..560f9968 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -211,12 +211,11 @@ PalImage* PAL_CALL getVkSwapchainImage( PalImage* PAL_CALL getVkNextSwapchainImage( PalSwapchain* swapchain, - PalFence* fence, - Uint64 timeout); + PalNextImageInfo* info); PalResult PAL_CALL presentVkSwapchain( PalSwapchain* swapchain, - PalImage* image); + PalPresentInfo* info); PalResult PAL_CALL createVkShader( PalDevice* device, @@ -248,6 +247,23 @@ PalResult PAL_CALL resetVkFence(PalFence* fence); bool PAL_CALL isVkFenceSignaled(PalFence* fence); +PalResult PAL_CALL createVkSemaphore( + PalDevice* device, + PalSemaphore** outSemaphore); + +void PAL_CALL destroyVkSemaphore(PalSemaphore* semaphore); + +PalResult PAL_CALL waitVkSemaphore( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value, + Uint64 timeout); + +PalResult PAL_CALL signalVkSemaphore( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value); + PalResult PAL_CALL createVkCommandPool( PalDevice* device, const PalCommandPoolCreateInfo* info, @@ -281,9 +297,7 @@ PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer); PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, - Int32 cmdBufferCount, - PalCommandBuffer** cmdBuffers, - PalFence* fence); + PalSubmitInfo* info); static PalGraphicsBackend s_VkBackend = { .enumerateAdapters = enumerateVkAdapters, @@ -323,6 +337,10 @@ static PalGraphicsBackend s_VkBackend = { .waitFenceTimeout = waitVkFence, .resetFence = resetVkFence, .isFenceSignaled = isVkFenceSignaled, + .createSemaphore = createVkSemaphore, + .destroySemaphore = destroyVkSemaphore, + .waitSemaphore = waitVkSemaphore, + .signalSemaphore = signalVkSemaphore, .createCommandPool = createVkCommandPool, .destroyCommandPool = destroyVkCommandPool, .createCommandBuffer = createVkCommandBuffer, @@ -406,6 +424,10 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->waitFenceTimeout || !backend->resetFence || !backend->isFenceSignaled || + !backend->createSemaphore || + !backend->destroySemaphore || + !backend->waitSemaphore || + !backend->signalSemaphore || !backend->createCommandPool || !backend->destroyCommandPool || !backend->createCommandBuffer || @@ -1174,10 +1196,9 @@ PalImage* PAL_CALL palGetSwapchainImage( PalImage* PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, - PalFence* fence, - Uint64 timeout) + PalNextImageInfo* info) { - if (!s_Graphics.initialized || !swapchain) { + if (!s_Graphics.initialized || !swapchain || !info) { return nullptr; } @@ -1187,18 +1208,32 @@ PalImage* PAL_CALL palGetNextSwapchainImage( } void* FenceHandle = nullptr; - if (fence) { - HandleData* tmp = (HandleData*)fence; + void* signalSemaphoreHandle = nullptr; + if (info->fence) { + HandleData* tmp = (HandleData*)info->signalSemaphore; if (!tmp->used) { return nullptr; } FenceHandle = tmp->handle; } + if (info->signalSemaphore) { + HandleData* tmp = (HandleData*)info->signalSemaphore; + if (!tmp->used) { + return nullptr; + } + signalSemaphoreHandle = tmp->handle; + } + + PalNextImageInfo nextInfo; + nextInfo.fence = FenceHandle; + nextInfo.signalSemaphore = signalSemaphoreHandle; + nextInfo.signalValue = info->signalValue; + nextInfo.timeout = info->timeout; + PalImage* tmp = data->backend->getNextSwapchainImage( data->handle, - FenceHandle, - timeout); + &nextInfo); // loop through all our cache images and get the handle data // associated with the image @@ -1217,13 +1252,13 @@ PalImage* PAL_CALL palGetNextSwapchainImage( PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, - PalImage* image) + PalPresentInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!swapchain || !image) { + if (!swapchain || !info) { return PAL_RESULT_NULL_POINTER; } @@ -1232,14 +1267,28 @@ PalResult PAL_CALL palPresentSwapchain( return PAL_RESULT_INVALID_SWAPCHAIN; } - HandleData* imageData = (HandleData*)image; + HandleData* imageData = (HandleData*)info->image; if (!imageData->used) { return PAL_RESULT_INVALID_IMAGE; } + void* waitSemaphoreHandle = nullptr; + if (info->waitSemaphore) { + HandleData* tmp = (HandleData*)info->waitSemaphore; + if (!tmp->used) { + return PAL_RESULT_INVALID_SEMAPHORE; + } + waitSemaphoreHandle = tmp->handle; + } + + PalPresentInfo presentInfo; + presentInfo.image = imageData->handle; + presentInfo.waitValue = info->waitValue; + presentInfo.waitSemaphore = waitSemaphoreHandle; + return swapchainData->backend->presentSwapchain( swapchainData->handle, - imageData->handle); + &presentInfo); } // ================================================== @@ -1508,6 +1557,118 @@ bool PAL_CALL palIsFenceSignaled(PalFence* fence) return false; } +// ================================================== +// Semaphore +// ================================================== + +PalResult PAL_CALL palCreateSemaphore( + PalDevice* device, + PalSemaphore** outSemaphore) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !outSemaphore) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)device; + if (!data->used) { + return PAL_RESULT_INVALID_DEVICE; + } + + // create a slot for the semaphore + HandleData* semaphoreData = getFreeHandleData(); + if (!semaphoreData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalSemaphore* semaphore = nullptr; + PalResult ret; + ret = data->backend->createSemaphore(data->handle, &semaphore); + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + semaphoreData->backend = data->backend; + semaphoreData->handle = semaphore; + + *outSemaphore = (PalSemaphore*)semaphoreData; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore) +{ + if (s_Graphics.initialized && semaphore) { + HandleData* data = (HandleData*)semaphore; + if (data->used) { + data->backend->destroySemaphore(data->handle); + freeHandleData(data); + } + } +} + +PalResult PAL_CALL palWaitSemaphore( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value, + Uint64 timeout) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!semaphore || !queue) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* semaphoreData = (HandleData*)semaphore; + if (!semaphoreData->used) { + return PAL_RESULT_INVALID_SEMAPHORE; + } + + HandleData* queueData = (HandleData*)queue; + if (!queueData->used) { + return PAL_RESULT_INVALID_QUEUE; + } + + return semaphoreData->backend->waitSemaphore( + semaphoreData->handle, + queueData->handle, + value, + timeout); +} + +PalResult PAL_CALL palSignalSemaphore( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!semaphore || !queue) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* semaphoreData = (HandleData*)semaphore; + if (!semaphoreData->used) { + return PAL_RESULT_INVALID_SEMAPHORE; + } + + HandleData* queueData = (HandleData*)queue; + if (!queueData->used) { + return PAL_RESULT_INVALID_QUEUE; + } + + return semaphoreData->backend->signalSemaphore( + semaphoreData->handle, + queueData->handle, + value); +} + // ================================================== // Command Pool And Buffer // ================================================== @@ -1753,49 +1914,59 @@ PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, - Int32 cmdBufferCount, - PalCommandBuffer** cmdBuffers, - PalFence* fence) + PalSubmitInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!queue || !cmdBuffers) { + if (!queue || !info) { return PAL_RESULT_NULL_POINTER; } - if (cmdBufferCount == 0) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - HandleData* data = (HandleData*)queue; if (!data->used) { return PAL_RESULT_INVALID_QUEUE; } + HandleData* cmdBufferData = (HandleData*)info->cmdBuffer; + if (!cmdBufferData->used) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + void* fenceHandle = nullptr; - if (fence) { - HandleData* tmp = (HandleData*)fence; + void* waitSemaphoreHandle = nullptr; + void* signalSemaphoreHandle = nullptr; + if (info->fence) { + HandleData* tmp = (HandleData*)info->fence; if (tmp->used) { fenceHandle = tmp->handle; } } - // 16 should be more than enough - PalCommandBuffer* cmdHandles[16]; - for (int i = 0; i < cmdBufferCount; i++) { - // get the cmd buffer handles - HandleData* tmp = (HandleData*)cmdBuffers[i]; - if (!tmp->used) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; + if (info->waitSemaphore) { + HandleData* tmp = (HandleData*)info->waitSemaphore; + if (tmp->used) { + waitSemaphoreHandle = tmp->handle; + } + } + + if (info->signalSemaphore) { + HandleData* tmp = (HandleData*)info->signalSemaphore; + if (tmp->used) { + signalSemaphoreHandle = tmp->handle; } - cmdHandles[i] = tmp->handle; } + PalSubmitInfo submitInfo; + submitInfo.cmdBuffer = cmdBufferData->handle; + submitInfo.fence = fenceHandle; + submitInfo.signalSemaphore = signalSemaphoreHandle; + submitInfo.waitSemaphore = waitSemaphoreHandle; + submitInfo.signalValue = info->signalValue; + submitInfo.waitValue = info->waitValue; + return data->backend->submitCommandBuffer( data->handle, - cmdBufferCount, - cmdHandles, - fenceHandle); + &submitInfo); } \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e2985c40..047decaf 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -122,6 +122,12 @@ typedef struct { PFN_vkResetFences resetFence; PFN_vkWaitForFences waitFence; PFN_vkGetFenceStatus isFenceSignaled; + PFN_vkCreateSemaphore createSemaphore; + PFN_vkDestroySemaphore destroySemaphore; + PFN_vkWaitSemaphores waitSemaphores; + PFN_vkSignalSemaphore signalSemaphore; + PFN_vkGetSemaphoreCounterValue getSemaphoreValue; + PFN_vkBeginCommandBuffer cmdBegin; PFN_vkEndCommandBuffer cmdEnd; PFN_vkCmdExecuteCommands cmdExecuteCommandBuffer; @@ -232,6 +238,12 @@ struct PalFence { VkFence handle; }; +struct PalSemaphore { + bool isTimeline; + PalDevice* device; + VkSemaphore handle; +}; + static Vulkan s_Vk = {0}; // ================================================== @@ -1209,6 +1221,26 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkGetFenceStatus"); + s_Vk.createSemaphore = (PFN_vkCreateSemaphore)dlsym( + s_Vk.handle, + "vkCreateSemaphore"); + + s_Vk.destroySemaphore = (PFN_vkDestroySemaphore)dlsym( + s_Vk.handle, + "vkDestroySemaphore"); + + s_Vk.waitSemaphores = (PFN_vkWaitSemaphores)dlsym( + s_Vk.handle, + "vkWaitSemaphores"); + + s_Vk.signalSemaphore = (PFN_vkSignalSemaphore)dlsym( + s_Vk.handle, + "vkSignalSemaphore"); + + s_Vk.getSemaphoreValue = (PFN_vkGetSemaphoreCounterValue)dlsym( + s_Vk.handle, + "vkGetSemaphoreCounterValue"); + s_Vk.cmdBegin = (PFN_vkBeginCommandBuffer)dlsym( s_Vk.handle, "vkBeginCommandBuffer"); @@ -1908,7 +1940,6 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->features |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT; caps->features |= PAL_ADAPTER_FEATURE_RESET_FENCE; caps->features |= PAL_ADAPTER_FEATURE_TIMEOUT_FENCE; - caps->features |= PAL_ADAPTER_FEATURE_MULTI_QUEUE_SUBMIT; caps->features |= PAL_ADAPTER_FEATURE_SEMAPHORE; palFree(s_Vk.allocator, extensionProps); @@ -3079,21 +3110,26 @@ PalImage* PAL_CALL getVkSwapchainImage( PalImage* PAL_CALL getVkNextSwapchainImage( PalSwapchain* swapchain, - PalFence* fence, - Uint64 timeout) + PalNextImageInfo* info) { VkResult result; Uint32 index = 0; VkFence fenceHandle = nullptr; - if (fence) { - fenceHandle = fence->handle; + VkSemaphore semaphoreHandle = nullptr; + + if (info->fence) { + fenceHandle = info->fence->handle; + } + + if (info->signalSemaphore) { + semaphoreHandle = info->signalSemaphore->handle; } result = swapchain->device->acquireNextImage( swapchain->device->handle, swapchain->handle, - timeout, - VK_NULL_HANDLE, + info->timeout, + semaphoreHandle, fenceHandle, &index); @@ -3108,30 +3144,39 @@ PalImage* PAL_CALL getVkNextSwapchainImage( PalResult PAL_CALL presentVkSwapchain( PalSwapchain* swapchain, - PalImage* image) + PalPresentInfo* info) { - if (image->index == -1) { + if (info->image->index == -1) { // image was not the next image // this prevents UB return PAL_RESULT_INVALID_IMAGE; } + Int32 semaphoreCount = 0; + VkSemaphore semaphoreHandle = nullptr; + if (info->waitSemaphore) { + semaphoreHandle = info->waitSemaphore->handle; + semaphoreCount = 1; + } + VkResult result; VkPresentInfoKHR presentInfo = {0}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = &swapchain->handle; - presentInfo.pImageIndices = &image->index; + presentInfo.pImageIndices = &info->image->index; + presentInfo.pWaitSemaphores = &semaphoreHandle; + presentInfo.waitSemaphoreCount = semaphoreCount; result = swapchain->device->queuePresent( swapchain->queue->phyQueue->handle, &presentInfo); if (result != VK_SUCCESS) { - vkResultToPal(result); + return vkResultToPal(result); } - image->index = -1; + info->image->index = -1; return PAL_RESULT_SUCCESS; } @@ -3412,7 +3457,7 @@ PalResult PAL_CALL createVkFence( if (result != VK_SUCCESS) { palFree(s_Vk.allocator, fence); - vkResultToPal(result); + return vkResultToPal(result); } fence->device = device; @@ -3451,7 +3496,7 @@ PalResult PAL_CALL resetVkFence(PalFence* fence) VkResult ret = s_Vk.resetFence(fence->device->handle, 1, &fence->handle); if (ret != VK_SUCCESS) { - vkResultToPal(ret); + return vkResultToPal(ret); } return PAL_RESULT_SUCCESS; @@ -3467,6 +3512,106 @@ bool PAL_CALL isVkFenceSignaled(PalFence* fence) } } +// ================================================== +// Semaphore +// ================================================== + +PalResult PAL_CALL createVkSemaphore( + PalDevice* device, + PalSemaphore** outSemaphore) +{ + VkResult result; + PalSemaphore* semaphore = nullptr; + semaphore = palAllocate(s_Vk.allocator, sizeof(PalSemaphore), 0); + if (!semaphore) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkSemaphoreTypeCreateInfo timelineCreateInfo = {0}; + timelineCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; + timelineCreateInfo.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + + VkSemaphoreCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + const void* next = nullptr; + semaphore->isTimeline = false; + if (device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + next = &timelineCreateInfo; + semaphore->isTimeline = true; + } + + createInfo.pNext = next; + result = s_Vk.createSemaphore( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &semaphore->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, semaphore); + return vkResultToPal(result); + } + + semaphore->device = device; + *outSemaphore = semaphore; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkSemaphore(PalSemaphore* semaphore) +{ + s_Vk.destroySemaphore( + semaphore->device->handle, + semaphore->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, semaphore); +} + +PalResult PAL_CALL waitVkSemaphore( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value, + Uint64 timeout) +{ + VkResult result; + VkSemaphoreWaitInfo waitInfo = {0}; + waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; + waitInfo.semaphoreCount = 1; + waitInfo.pSemaphores = &semaphore->handle; + waitInfo.pValues = &value; + + result = s_Vk.waitSemaphores( + semaphore->device->handle, + &waitInfo, + timeout); + + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL signalVkSemaphore( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value) +{ + VkResult result; + VkSemaphoreSignalInfo signalInfo = {0}; + signalInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; + signalInfo.semaphore = semaphore->handle; + signalInfo.value = value; + + result = s_Vk.signalSemaphore(semaphore->device->handle, &signalInfo); + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + return PAL_RESULT_SUCCESS; +} + // ================================================== // Command Pool And Buffer // ================================================== @@ -3677,26 +3822,38 @@ PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, - Int32 cmdBufferCount, - PalCommandBuffer** cmdBuffers, - PalFence* fence) + PalSubmitInfo* info) { VkResult result; + Int32 waitSemaphoreCount = 0; + Int32 signalSemaphoreCount = 0; VkFence fenceHandle = nullptr; - VkCommandBuffer cmdHandles[16]; // 16 should be more than enough - for (int i = 0; i < cmdBufferCount; i++) { - cmdHandles[i] = cmdBuffers[i]->handle; + VkSemaphore waitSemaphoreHandle = nullptr; + VkSemaphore signalSemaphoreHandle = nullptr; + + if (info->waitSemaphore) { + waitSemaphoreHandle = info->waitSemaphore->handle; + waitSemaphoreCount = 1; } - VkSubmitInfo submitInfo = {0}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = cmdBufferCount; - submitInfo.pCommandBuffers = cmdHandles; + if (info->signalSemaphore) { + signalSemaphoreHandle = info->signalSemaphore->handle; + signalSemaphoreCount = 1; + } - if (fence) { - fenceHandle = fence->handle; + if (info->fence) { + fenceHandle = info->fence->handle; } + VkSubmitInfo submitInfo = {0}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &info->cmdBuffer->handle; + submitInfo.pSignalSemaphores = &signalSemaphoreHandle; + submitInfo.pWaitSemaphores = &waitSemaphoreHandle; + submitInfo.waitSemaphoreCount = waitSemaphoreCount; + submitInfo.waitSemaphoreCount = signalSemaphoreCount; + result = s_Vk.queueSubmit( queue->phyQueue->handle, 1, @@ -3704,7 +3861,7 @@ PalResult PAL_CALL submitVkCommandBuffer( fenceHandle); if (result != VK_SUCCESS) { - vkResultToPal(result); + return vkResultToPal(result); } return PAL_RESULT_SUCCESS; diff --git a/src/pal_core.c b/src/pal_core.c index 018e8cab..95c5768d 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -438,6 +438,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_FENCE: return "Invalid fence"; + case PAL_RESULT_INVALID_SEMAPHORE: + return "Invalid semaphore"; + case PAL_RESULT_INVALID_RENDER_PASS: return "Invalid render pass"; } diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index c77e9197..2193cd16 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -383,7 +383,9 @@ bool clearColorTest() // get the next image that we can render too PalImage* image = nullptr; - image = palGetNextSwapchainImage(swapchain, nullptr, UINT64_MAX); + PalNextImageInfo nextImageInfo = {0}; + nextImageInfo.timeout = UINT64_MAX; + image = palGetNextSwapchainImage(swapchain, &nextImageInfo); // find the command buffer associated with the image // this is fast, the swapchain caches all it images internally @@ -396,14 +398,20 @@ bool clearColorTest() } // submit to the queue and present - result = palSubmitCommandBuffer(queue, 1, &cmdBuffer, nullptr); + PalSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffer; + + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); return false; } - result = palPresentSwapchain(swapchain, image); + PalPresentInfo presentInfo = {0}; + presentInfo.image = image; + + result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to present swapchain: %s", error); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index ac6283f8..d9554684 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -307,10 +307,6 @@ bool graphicsTest() if (caps.features & PAL_ADAPTER_FEATURE_TIMEOUT_FENCE) { palLog(nullptr, " Timeout fence"); } - - if (caps.features & PAL_ADAPTER_FEATURE_MULTI_QUEUE_SUBMIT) { - palLog(nullptr, " Multi queue submit"); - } palLog(nullptr, ""); } From 5f3f5cc3a2844efaa781fe75e8dbaaf54c73dd5d Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Dec 2025 16:34:39 +0000 Subject: [PATCH 046/372] add initial entries to CHANGELOG.md --- CHANGELOG.md | 41 ++++++++++++++++++++++++++----------- src/video/pal_video_linux.c | 5 ----- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be93045c..4384b307 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,24 +121,41 @@ void* retval; palJoinThread(thread, &retval); ``` -## [1.3.0] - 2025-00-00 +## [1.4.0] - 2025-00-00 ### Features -- **Core:** Added **PAL_RESULT_GRAPHICS_NOT_INITIALIZED** to `PalResult` enum to indicate that a graphics function was called whiles the graphics system has not been initialized. - -- **Core:** Added **PAL_RESULT_INVALID_GPU_ADAPTER** to `PalResult` enum to indiate an invalid `PalGPUAdapter` handle error. - -- **Core:** Added **PAL_RESULT_INVALID_GPU_BACKEND** to `PalResult` enum to indiate an invalid `PalGPUBackend` handle error. - -- **Graphics:** Added **Graphics System To PAL**. This system allows users to use modern graphics APIs (eg. Vulkan, D3D12, and Metal). Systems which do not support this APIs are not left out, the graphics system also has an API to allow users set custom backends to the graphics system and use its API as though its part of the internal ones. see **custom_graphics_backend_test.c**. +- **Core:** Added **PAL_RESULT_GRAPHICS_NOT_INITIALIZED** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_ADAPTER** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_BACKEND** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_QUEUE_NOT_SUPPORTED** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_DRIVER** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_DEVICE** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_QUEUE** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_OUT_OF_QUEUE** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_GRAPHICS_WINDOW** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_SWAPCHAIN** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_IMAGE** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_IMAGE_VIEW** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_OPERATION** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_SHADER_TYPE** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_COMMAND_POOL** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_COMMAND_BUFFER** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_FENCE** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_SEMAPHORE** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_RENDER_PASS** to `PalResult` enum. + +- **Graphics:** Added **Graphics System To PAL**. ### Tests -- Added grapics test example: demonstrating **Enumerating GPU Adapters And Selecting The Best One For Your Needs**. see **graphics_test.c**. +- Added grapics example: see **graphics_test.c** -- Added custom graphics backend example: demonstrating **Adding Custom Graphics Backends to PAL**. -see **custom_graphics_backend_test.c**. +- Added clear color example: see **clear_color_test.c** ### Notes -- **No ABI changes** - existing code remains compatible. \ No newline at end of file +- No API or ABI changes - existing code remains compatible. +- Safe upgrade from **v1.3.0** - just rebuild your project after updating. +- The graphics system supports both legacy and dynamic rendering on vulkan. \ No newline at end of file diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index 7bbe41b3..ffe25d33 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -2797,7 +2797,6 @@ static int compareModes( } } -// TODO: rewrite this static WindowData* getFreeWindowData() { for (int i = 0; i < s_Video.maxWindowData; ++i) { @@ -2830,7 +2829,6 @@ static WindowData* getFreeWindowData() return nullptr; } -// TODO: remove this static WindowData* findWindowData(PalWindow* window) { for (int i = 0; i < s_Video.maxWindowData; ++i) { @@ -2850,7 +2848,6 @@ static void resetMonitorData() s_Video.maxMonitorData * sizeof(MonitorData)); } -// TODO: rewrite this static MonitorData* getFreeMonitorData() { for (int i = 0; i < s_Video.maxMonitorData; ++i) { @@ -2882,7 +2879,6 @@ static MonitorData* getFreeMonitorData() return nullptr; } -// TODO: remove this static MonitorData* findMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Video.maxMonitorData; ++i) { @@ -2894,7 +2890,6 @@ static MonitorData* findMonitorData(PalMonitor* monitor) return nullptr; } -// TODO: remove this static void freeMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Video.maxMonitorData; ++i) { From ea6614727343705c028830d9551d64d0ccfe2dd6 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 16 Dec 2025 10:31:41 +0000 Subject: [PATCH 047/372] change sample count into an enum --- include/pal/pal_graphics.h | 19 +++++++++--- src/graphics/pal_vulkan.c | 62 ++++++++++++++++++++------------------ tests/graphics_test.c | 36 ++++++++++++++++++++-- tests/tests_main.c | 4 +-- 4 files changed, 83 insertions(+), 38 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 903c223c..0a070d34 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -293,6 +293,16 @@ typedef enum { PAL_ATTACHMENT_TYPE_STENCIL } PalAttachmentType; +typedef enum { + PAL_SAMPLE_COUNT_1, + PAL_SAMPLE_COUNT_2, + PAL_SAMPLE_COUNT_4, + PAL_SAMPLE_COUNT_8, + PAL_SAMPLE_COUNT_16, + PAL_SAMPLE_COUNT_32, + PAL_SAMPLE_COUNT_64 +} PalSampleCount; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -304,6 +314,7 @@ typedef struct { Uint64 version; char versionString[PAL_ADAPTER_VERSION_SIZE]; char name[PAL_ADAPTER_NAME_SIZE]; + char backendName[PAL_ADAPTER_NAME_SIZE]; } PalAdapterInfo; typedef struct { @@ -316,8 +327,8 @@ typedef struct { Uint32 maxImageDepth; Uint32 maxImageArrayLayers; Uint32 maxImageMipLevels; - Uint32 maxColorSamples; - Uint32 maxDepthSamples; + PalSampleCount maxColorSampleCount; + PalSampleCount maxDepthSampleCount; Uint32 maxColorAttachments; Uint32 maxMultiViews; Uint32 maxViewports; @@ -352,7 +363,7 @@ typedef struct { Uint32 height; Uint32 depthOrArraySize; Uint32 mipLevelCount; - Uint32 samples; + PalSampleCount sampleCount; PalImageType type; PalFormat format; PalImageUsages usages; @@ -405,7 +416,7 @@ typedef struct { Uint32 height; Uint32 depthOrArraySize; Uint32 mipLevelCount; - Uint32 samples; + PalSampleCount sampleCount; PalImageType type; PalFormat format; PalImageUsages usages; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 047decaf..75bf8fa5 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -619,53 +619,53 @@ static VkFormat palFormatToVk(PalFormat format) return VK_FORMAT_UNDEFINED; } -static VkSampleCountFlags samplesToVk(Uint32 samples) +static VkSampleCountFlags samplesToVk(PalSampleCount count) { - switch (samples) { - case 2: + switch (count) { + case PAL_SAMPLE_COUNT_2: return VK_SAMPLE_COUNT_2_BIT; - case 4: + case PAL_SAMPLE_COUNT_4: return VK_SAMPLE_COUNT_4_BIT; - case 8: + case PAL_SAMPLE_COUNT_8: return VK_SAMPLE_COUNT_8_BIT; - case 16: + case PAL_SAMPLE_COUNT_16: return VK_SAMPLE_COUNT_16_BIT; - case 32: + case PAL_SAMPLE_COUNT_32: return VK_SAMPLE_COUNT_32_BIT; - case 64: + case PAL_SAMPLE_COUNT_64: return VK_SAMPLE_COUNT_64_BIT; } return VK_SAMPLE_COUNT_1_BIT; } -static Uint32 vkSamplesToSamples(VkSampleCountFlags samples) +static PalSampleCount vkSamplesToSamples(VkSampleCountFlags count) { - if (samples & VK_SAMPLE_COUNT_2_BIT) { - return 2; + if (count & VK_SAMPLE_COUNT_2_BIT) { + return PAL_SAMPLE_COUNT_2; - } else if (samples & VK_SAMPLE_COUNT_4_BIT) { - return 4; + } else if (count & VK_SAMPLE_COUNT_4_BIT) { + return PAL_SAMPLE_COUNT_4; - } else if (samples & VK_SAMPLE_COUNT_8_BIT) { - return 8; + } else if (count & VK_SAMPLE_COUNT_8_BIT) { + return PAL_SAMPLE_COUNT_8; - } else if (samples & VK_SAMPLE_COUNT_16_BIT) { - return 16; + } else if (count & VK_SAMPLE_COUNT_16_BIT) { + return PAL_SAMPLE_COUNT_16; - } else if (samples & VK_SAMPLE_COUNT_32_BIT) { - return 32; + } else if (count & VK_SAMPLE_COUNT_32_BIT) { + return PAL_SAMPLE_COUNT_32; - } else if (samples & VK_SAMPLE_COUNT_64_BIT) { - return 64; + } else if (count & VK_SAMPLE_COUNT_64_BIT) { + return PAL_SAMPLE_COUNT_64; } - return 1; + return PAL_SAMPLE_COUNT_1; } static PalFormat vkFormatToPal(VkFormat format) @@ -1546,6 +1546,7 @@ PalResult PAL_CALL getVkAdapterInfo( info->deviceId = props.deviceID; info->vendorId = props.vendorID; strcpy(info->name, props.deviceName); + strcpy(info->backendName, "PAL"); info->vram = 0; info->sharedMemory = 0; @@ -1619,11 +1620,12 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->maxImageHeight = props.limits.maxImageDimension2D; caps->maxImageDepth = props.limits.maxImageDimension3D; caps->maxImageArrayLayers = props.limits.maxImageArrayLayers; - - Uint32 tmp = vkSamplesToSamples(props.limits.framebufferColorSampleCounts); - caps->maxColorSamples = tmp; + + PalSampleCount tmp = PAL_SAMPLE_COUNT_1; + tmp = vkSamplesToSamples(props.limits.framebufferColorSampleCounts); + caps->maxColorSampleCount = tmp; tmp = vkSamplesToSamples(props.limits.framebufferDepthSampleCounts); - caps->maxDepthSamples = tmp; + caps->maxDepthSampleCount = tmp; caps->maxViewports = props.limits.maxViewports; caps->maxSamplers = props.limits.maxSamplerAllocationCount; @@ -2599,7 +2601,7 @@ PalResult PAL_CALL createVkImage( createInfo.mipLevels = info->mipLevelCount; createInfo.format = palFormatToVk(info->format); - createInfo.samples = samplesToVk(info->samples); + createInfo.samples = samplesToVk(info->sampleCount); createInfo.usage = palUsageToVk(info->usages); createInfo.arrayLayers = info->depthOrArraySize; @@ -2630,7 +2632,7 @@ PalResult PAL_CALL createVkImage( image->info.usages = info->usages; image->info.height = info->height; image->info.mipLevelCount = info->mipLevelCount; - image->info.samples = info->samples; + image->info.sampleCount = info->sampleCount; image->info.width = info->width; *outImage = image; @@ -3073,7 +3075,7 @@ PalResult PAL_CALL createVkSwapchain( image->info.height = createInfo.imageExtent.height; image->info.width = createInfo.imageExtent.width; image->info.mipLevelCount = 1; - image->info.samples = 1; // swapchain images are not multisampled + image->info.sampleCount = PAL_SAMPLE_COUNT_1; // swapchain images are not multisampled image->info.type = PAL_IMAGE_TYPE_2D; } @@ -3296,7 +3298,7 @@ PalResult PAL_CALL createVkRenderPass( rDesc->format = palFormatToVk(desc->target->image->info.format); rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rDesc->samples = vkSamplesToSamples(desc->target->image->info.samples); + rDesc->samples = vkSamplesToSamples(desc->target->image->info.sampleCount); rDesc->flags = 0; rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; diff --git a/tests/graphics_test.c b/tests/graphics_test.c index d9554684..7e5efadf 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -2,6 +2,34 @@ #include "pal/pal_graphics.h" #include "tests.h" +static Uint32 getSampleCount(PalSampleCount sampleCount) +{ + switch (sampleCount) { + case PAL_SAMPLE_COUNT_1: + return 1; + + case PAL_SAMPLE_COUNT_2: + return 2; + + case PAL_SAMPLE_COUNT_4: + return 4; + + case PAL_SAMPLE_COUNT_8: + return 8; + + case PAL_SAMPLE_COUNT_16: + return 16; + + case PAL_SAMPLE_COUNT_32: + return 32; + + case PAL_SAMPLE_COUNT_64: + return 64; + } + + return 1; +} + bool graphicsTest() { palLog(nullptr, ""); @@ -74,6 +102,7 @@ bool graphicsTest() Uint32 sharedMemGb = info.sharedMemory / (1024.0 * 1024.0 * 1024.0); palLog(nullptr, "GPU Name: %s", info.name); + palLog(nullptr, " Backend Name: %s", info.backendName); palLog(nullptr, " Vendor Id: %d", info.vendorId); palLog(nullptr, " Device Id: %d", info.deviceId); palLog(nullptr, " Vram %dGB", vramGb); @@ -185,6 +214,9 @@ bool graphicsTest() // clang-format off + Uint32 colorSampleCount = getSampleCount(caps.maxColorSampleCount); + Uint32 depthSampleCount = getSampleCount(caps.maxDepthSampleCount); + Uint32 uniformBufferSize = caps.maxUniformBufferSize / 1024; Uint32 storageBufferSize = caps.maxStorageBufferSize / 1024; Uint32 pushConstantSize = caps.maxStorageBufferSize / 1024; @@ -199,8 +231,8 @@ bool graphicsTest() palLog(nullptr, " Max image array layers: %d", caps.maxImageArrayLayers); palLog(nullptr, " Max image mip levels: %d", caps.maxImageMipLevels); - palLog(nullptr, " Max color samples: %d", caps.maxColorSamples); - palLog(nullptr, " Max depth samples: %d", caps.maxDepthSamples); + palLog(nullptr, " Max color samples: %d", colorSampleCount); + palLog(nullptr, " Max depth samples: %d", depthSampleCount); palLog(nullptr, " Max color attachment: %d", caps.maxColorAttachments); palLog(nullptr, " Max multi views: %d", caps.maxMultiViews); palLog(nullptr, " Max viewports: %d", caps.maxViewports); diff --git a/tests/tests_main.c b/tests/tests_main.c index 17c21405..5bf06fe6 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,11 +55,11 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); + registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest("Clear Color Test", clearColorTest); + // registerTest("Clear Color Test", clearColorTest); #endif // runTests(); From 55a08368fabe2b00290a41145fe6c6fc5d67a300 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 16 Dec 2025 14:20:09 +0000 Subject: [PATCH 048/372] start graphics pipeline API --- include/pal/pal_graphics.h | 202 ++++++++++++++++++++++++++++++++++++- src/graphics/pal_vulkan.c | 4 + tests/graphics_test.c | 4 + tests/tests_main.c | 2 +- 4 files changed, 207 insertions(+), 5 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 0a070d34..8828ad62 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -231,7 +231,8 @@ typedef enum { PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(20), PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(21), PAL_ADAPTER_FEATURE_RESET_FENCE = PAL_BIT64(22), - PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(23) + PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(23), + PAL_ADAPTER_FEATURE_LINE_POLYGON_MODE = PAL_BIT64(24) } PalAdapterFeatures; typedef enum { @@ -303,6 +304,127 @@ typedef enum { PAL_SAMPLE_COUNT_64 } PalSampleCount; +typedef enum { + PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + PAL_PRIMITIVE_TOPOLOGY_LINE_LIST, + PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP, + PAL_PRIMITIVE_TOPOLOGY_POINT_LIST +} PalPrimitiveTopology; + +typedef enum { + PAL_CULL_MODE_NONE, + PAL_CULL_MODE_FRONT, + PAL_CULL_MODE_BACK +} PalCullMode; + +typedef enum { + PAL_FRONT_FACE_CLOCKWISE, + PAL_FRONT_FACE_COUNTER_CLOCKWISE +} PalFrontFace; + +typedef enum { + PAL_POLYGON_MODE_FILL, + PAL_POLYGON_MODE_LINE +} PalPolygonMode; + +typedef enum { + PAL_VERTEX_TYPE_UNDEFINED, + + PAL_VERTEX_TYPE_INT32, + PAL_VERTEX_TYPE_INT32_2, + PAL_VERTEX_TYPE_INT32_3, + PAL_VERTEX_TYPE_INT32_4, + + PAL_VERTEX_TYPE_UINT32, + PAL_VERTEX_TYPE_UINT32_2, + PAL_VERTEX_TYPE_UINT32_3, + PAL_VERTEX_TYPE_UINT32_4, + + PAL_VERTEX_TYPE_INT8_2, + PAL_VERTEX_TYPE_INT8_4, + PAL_VERTEX_TYPE_UINT8_2, + PAL_VERTEX_TYPE_UINT8_4, + + PAL_VERTEX_TYPE_INT8_2NORM, + PAL_VERTEX_TYPE_INT8_4NORM, + PAL_VERTEX_TYPE_UINT8_2NORM, + PAL_VERTEX_TYPE_UINT8_4NORM, + + PAL_VERTEX_TYPE_INT16_2, + PAL_VERTEX_TYPE_INT16_4, + PAL_VERTEX_TYPE_UINT16_2, + PAL_VERTEX_TYPE_UINT16_4, + + PAL_VERTEX_TYPE_INT16_2NORM, + PAL_VERTEX_TYPE_INT16_4NORM, + PAL_VERTEX_TYPE_UINT16_2NORM, + PAL_VERTEX_TYPE_UINT16_4NORM, + + PAL_VERTEX_TYPE_FLOAT, + PAL_VERTEX_TYPE_FLOAT2, + PAL_VERTEX_TYPE_FLOAT3, + PAL_VERTEX_TYPE_FLOAT4, + + PAL_VERTEX_TYPE_HALF_FLOAT16_2, + PAL_VERTEX_TYPE_HALF_FLOAT16_4 +} PalVertexType; + +typedef enum { + PAL_COMPARE_OP_NEVER, + PAL_COMPARE_OP_LESS, + PAL_COMPARE_OP_EQUAL, + PAL_COMPARE_OP_LESS_EQUAL, + PAL_COMPARE_OP_GREATER, + PAL_COMPARE_OP_NOT_EQUAL, + PAL_COMPARE_OP_GREATER_EQUAL, + PAL_COMPARE_OP_ALWAYS +} PalCompareOp; + +typedef enum { + PAL_STENCIL_OP_KEEP, + PAL_STENCIL_OP_ZERO, + PAL_STENCIL_OP_REPLACE, + PAL_STENCIL_OP_INCREMENT_AND_CLAMP, + PAL_STENCIL_OP_DECREMENT_AND_CLAMP, + PAL_STENCIL_OP_INVERT, + PAL_STENCIL_OP_INCREMENT_AND_WRAP, + PAL_STENCIL_OP_DECREMENT_AND_WRAP +} PalStencilOp; + +typedef enum { + PAL_BLEND_OP_ADD, + PAL_BLEND_OP_SUBTRACT, + PAL_BLEND_OP_REVERSE_SUBTRACT, + PAL_BLEND_OP_MIN, + PAL_BLEND_OP_MAX +} PalBlendOp; + +typedef enum { + PAL_BLEND_FACTOR_ZERO, + PAL_BLEND_FACTOR_ONE, + PAL_BLEND_FACTOR_SRC_COLOR, + PAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, + PAL_BLEND_FACTOR_DST_COLOR, + PAL_BLEND_FACTOR_ONE_MINUX_DST_COLOR, + PAL_BLEND_FACTOR_SRC_ALPHA, + PAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + PAL_BLEND_FACTOR_DST_ALPHA, + PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, + PAL_BLEND_FACTOR_CONSTANT_COLOR, + PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, + PAL_BLEND_FACTOR_CONSTANT_ALPHA, + PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA +} PalBlendFactor; + +typedef enum { + PAL_COLOR_MASK_NONE = 0, + PAL_COLOR_MASK_RED = PAL_BIT(0), + PAL_COLOR_MASK_GREEN = PAL_BIT(1), + PAL_COLOR_MASK_BLUE = PAL_BIT(2), + PAL_COLOR_MASK_ALPHA = PAL_BIT(3), +} PalColorMask; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -352,6 +474,11 @@ typedef struct { Uint32 maxImageArrayLayers; } PalSwapchainCapabilities; +typedef struct { + void* display; + void* window; +} PalGraphicsWindow; + typedef struct { PalFormat format; PalImageUsages usages; @@ -411,6 +538,61 @@ typedef struct { PalSemaphore* waitSemaphore; } PalPresentInfo; +typedef struct { + PalVertexType type; + Uint32 location; +} PalVertexAttribute; + +typedef struct { + bool perInstance; + Uint32 binding; + Uint32 vertexCount; + PalVertexAttribute* vertices; +} PalVertexLayout; + +typedef struct { + bool enableDepthClamp; + bool enableDepthBias; + PalPolygonMode polygonMode; + PalCullMode cullMode; + PalFrontFace frontFace; +} PalRasterizerState; + +typedef struct { + bool enableSampleShading; + bool enableAlphaToCoverage; + PalSampleCount sampleCount; + Uint32 sampleMask; + float minSampleShading; +} PalMultisampleState; + +typedef struct { + PalStencilOp failOp; + PalStencilOp passOp; + PalStencilOp depthFailOp; + PalCompareOp compareOp; +} PalStencilOpState; + +typedef struct { + bool enableDepthTest; + bool enableDepthWrite; + bool enableStencilTest; + PalCompareOp compareOp; + PalStencilOpState frontStencilOpState; + PalStencilOpState backStencilOpState; +} PalDepthStencilState; + +typedef struct { + bool enableBlend; + PalColorMask colorWriteMask; + PalBlendFactor srcColorBlendFactor; + PalBlendFactor dstColorBlendFactor; + PalBlendOp colorBlendOp; + PalBlendFactor srcAlphaBlendFactor; + PalBlendFactor dstAlphaBlendFactor; + PalBlendOp alphaBlendOp; +} PalColorBlendAttachmentState; + typedef struct { Uint32 width; Uint32 height; @@ -462,9 +644,21 @@ typedef struct { } PalCommandPoolCreateInfo; typedef struct { - void* display; - void* window; -} PalGraphicsWindow; + PalPrimitiveTopology topology; + Uint32 vertexLayoutCount; + Uint32 colorBlendAttachmentStateCount; + PalShader* vertexShader; + PalShader* pixelShader; + PalShader* geometryShader; + PalShader* meshShader; + PalShader* tessellationEvaluationShader; + PalShader* tessellationControlShader; + PalVertexLayout* vertexLayouts; + PalColorBlendAttachmentState* colorBlendAttachmentStates; + PalRasterizerState rasterizerState; + PalMultisampleState multisampleState; + PalDepthStencilState depthStencilState; +} PalGraphicsPipelineCreateInfo; typedef struct { PalResult PAL_CALL (*enumerateAdapters)( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 75bf8fa5..bb7b77a1 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1935,6 +1935,10 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->features |= PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING; } + if (features.fillModeNonSolid) { + caps->features |= PAL_ADAPTER_FEATURE_LINE_POLYGON_MODE; + } + // this features are supported on vulkan caps->features |= PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW; caps->features |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 7e5efadf..60a50c23 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -339,6 +339,10 @@ bool graphicsTest() if (caps.features & PAL_ADAPTER_FEATURE_TIMEOUT_FENCE) { palLog(nullptr, " Timeout fence"); } + + if (caps.features & PAL_ADAPTER_FEATURE_LINE_POLYGON_MODE) { + palLog(nullptr, " Line Polygon Mode"); + } palLog(nullptr, ""); } diff --git a/tests/tests_main.c b/tests/tests_main.c index 5bf06fe6..4660bd2f 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,7 +55,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + // registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From bcd317926011684481b53e617915aa6b8da22129 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 16 Dec 2025 15:08:57 +0000 Subject: [PATCH 049/372] add graphics pipeline backend layer --- include/pal/pal_graphics.h | 25 +++++-- src/graphics/pal_graphics.c | 140 +++++++++++++++++++++++++++++++++++- src/graphics/pal_vulkan.c | 19 ++++- 3 files changed, 176 insertions(+), 8 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 8828ad62..238f3213 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -52,6 +52,7 @@ typedef struct PalFence PalFence; typedef struct PalSemaphore PalSemaphore; typedef struct PalCommandPool PalCommandPool; typedef struct PalCommandBuffer PalCommandBuffer; +typedef struct PalPipeline PalPipeline; typedef enum { PAL_ADAPTER_TYPE_UNKNOWN, @@ -281,7 +282,7 @@ typedef enum { typedef enum { PAL_SHADER_TYPE_UNDEFINED, PAL_SHADER_TYPE_VERTEX, - PAL_SHADER_TYPE_PIXEL, + PAL_SHADER_TYPE_FRAGMENT, PAL_SHADER_TYPE_COMPUTE, PAL_SHADER_TYPE_GEOMETRY, PAL_SHADER_TYPE_TESSELLATION_CONTROL, @@ -591,7 +592,7 @@ typedef struct { PalBlendFactor srcAlphaBlendFactor; PalBlendFactor dstAlphaBlendFactor; PalBlendOp alphaBlendOp; -} PalColorBlendAttachmentState; +} PalBlendAttachment; typedef struct { Uint32 width; @@ -646,15 +647,15 @@ typedef struct { typedef struct { PalPrimitiveTopology topology; Uint32 vertexLayoutCount; - Uint32 colorBlendAttachmentStateCount; + Uint32 blendAttachmentCount; PalShader* vertexShader; - PalShader* pixelShader; + PalShader* fragmentShader; PalShader* geometryShader; PalShader* meshShader; PalShader* tessellationEvaluationShader; PalShader* tessellationControlShader; PalVertexLayout* vertexLayouts; - PalColorBlendAttachmentState* colorBlendAttachmentStates; + PalBlendAttachment* blendAttachments; PalRasterizerState rasterizerState; PalMultisampleState multisampleState; PalDepthStencilState depthStencilState; @@ -853,6 +854,13 @@ typedef struct { PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, PalSubmitInfo* info); + + PalResult PAL_CALL (*createGraphicsPipeline)( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + + void PAL_CALL (*destroyPipeline)(PalPipeline* pipeline); } PalGraphicsBackend; PAL_API PalResult PAL_CALL palAddGraphicsBackend( @@ -1059,6 +1067,13 @@ PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalSubmitInfo* info); +PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + +PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 560f9968..90c44b2b 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -299,6 +299,13 @@ PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalSubmitInfo* info); +PalResult PAL_CALL createVkGraphicsPipeline( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + +void PAL_CALL destroyVkPipeline(PalPipeline* pipeline); + static PalGraphicsBackend s_VkBackend = { .enumerateAdapters = enumerateVkAdapters, .getAdapterInfo = getVkAdapterInfo, @@ -350,7 +357,9 @@ static PalGraphicsBackend s_VkBackend = { .executeCommandBuffer = executeCommandBufferVk, .beginRenderPass = beginRenderPassVk, .endRenderPass = endRenderPassVk, - .submitCommandBuffer = submitVkCommandBuffer + .submitCommandBuffer = submitVkCommandBuffer, + .createGraphicsPipeline = createVkGraphicsPipeline, + .destroyPipeline = destroyVkPipeline }; #endif // PAL_HAS_VULKAN @@ -437,7 +446,9 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->beginRenderPass || !backend->endRenderPass || !backend->endRendering || - !backend->executeCommandBuffer || + !backend->createGraphicsPipeline || + !backend->destroyPipeline || + !backend->submitCommandBuffer || !backend->submitCommandBuffer) { return PAL_RESULT_INVALID_BACKEND; } @@ -1969,4 +1980,129 @@ PalResult PAL_CALL palSubmitCommandBuffer( return data->backend->submitCommandBuffer( data->handle, &submitInfo); +} + +// ================================================== +// Pipeline +// ================================================== + +PalResult PAL_CALL palCreateGraphicsPipeline( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outPipeline) { + return PAL_RESULT_NULL_POINTER; + } + + if (!info->fragmentShader) { + return PAL_RESULT_NULL_POINTER; + } + + if (!info->meshShader && !info->vertexShader) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* deviceData = (HandleData*)device; + if (!deviceData->used) { + return PAL_RESULT_INVALID_DEVICE; + } + + // shaders + void* vShaderHandle = nullptr; + void* fShaderHandle = nullptr; + void* gShaderHandle = nullptr; + void* mShaderHandle = nullptr; + void* tessEShaderHandle = nullptr; + void* tessCShaderHandle = nullptr; + + // create a slot for the pipeline + HandleData* pipelineData = getFreeHandleData(); + if (!pipelineData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + HandleData* tmp = nullptr; + // vertex shader path + if (info->vertexShader) { + tmp = (HandleData*)info->vertexShader; + if (tmp->used) { + vShaderHandle = tmp->handle; + } + + // fragment shader + tmp = (HandleData*)info->fragmentShader; + if (tmp->used) { + fShaderHandle = tmp->handle; + } + + // tessellation control shader + tmp = (HandleData*)info->tessellationControlShader; + if (tmp->used) { + tessCShaderHandle = tmp->handle; + } + + // tessellation evaluation shader + tmp = (HandleData*)info->tessellationEvaluationShader; + if (tmp->used) { + tessEShaderHandle = tmp->handle; + } + + // geometry shader + tmp = (HandleData*)info->geometryShader; + if (tmp->used) { + gShaderHandle = tmp->handle; + } + } + + PalGraphicsPipelineCreateInfo createInfo; + createInfo.fragmentShader = fShaderHandle; + createInfo.geometryShader = gShaderHandle; + createInfo.meshShader = mShaderHandle; + createInfo.tessellationControlShader = tessCShaderHandle; + createInfo.tessellationEvaluationShader = tessEShaderHandle; + createInfo.vertexShader = vShaderHandle; + + createInfo.topology = info->topology; + createInfo.blendAttachmentCount = info->blendAttachmentCount; + createInfo.blendAttachments = info->blendAttachments; + + createInfo.depthStencilState = info->depthStencilState; + createInfo.multisampleState = info->multisampleState; + createInfo.rasterizerState = info->rasterizerState; + + createInfo.vertexLayoutCount = info->vertexLayoutCount; + createInfo.vertexLayouts = info->vertexLayouts; + + PalResult ret; + PalPipeline* pipeline = nullptr; + ret = deviceData->backend->createGraphicsPipeline( + deviceData->handle, + &createInfo, + &pipeline); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + pipelineData->backend = deviceData->backend; + pipelineData->handle = pipeline; + + *outPipeline = (PalPipeline*)pipelineData; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) +{ + if (s_Graphics.initialized && pipeline) { + HandleData* data = (HandleData*)pipeline; + if (data->used) { + data->backend->destroyPipeline(data->handle); + freeHandleData(data); + } + } } \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index bb7b77a1..4488189b 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3202,7 +3202,7 @@ PalResult PAL_CALL createVkShader( if (info->type == PAL_SHADER_TYPE_VERTEX) { stage = VK_SHADER_STAGE_VERTEX_BIT; - } else if (info->type == PAL_SHADER_TYPE_PIXEL) { + } else if (info->type == PAL_SHADER_TYPE_FRAGMENT) { stage = VK_SHADER_STAGE_FRAGMENT_BIT; } else if (info->type == PAL_SHADER_TYPE_COMPUTE) { @@ -3873,4 +3873,21 @@ PalResult PAL_CALL submitVkCommandBuffer( return PAL_RESULT_SUCCESS; } +// ================================================== +// Pipeline +// ================================================== + +PalResult PAL_CALL createVkGraphicsPipeline( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + +} + +void PAL_CALL destroyVkPipeline(PalPipeline* pipeline) +{ + +} + #endif // PAL_HAS_VULKAN \ No newline at end of file From ce994d69d0976bbb5e3952726225bfff1573d6bd Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 16 Dec 2025 16:42:04 +0000 Subject: [PATCH 050/372] add tags to graphics objects --- include/pal/pal_graphics.h | 15 +- src/graphics/pal_graphics.c | 323 +++++++++++++++++++++++++----------- src/graphics/pal_vulkan.c | 27 ++- tests/tests_main.c | 4 +- 4 files changed, 266 insertions(+), 103 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 238f3213..89893bac 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -285,6 +285,7 @@ typedef enum { PAL_SHADER_TYPE_FRAGMENT, PAL_SHADER_TYPE_COMPUTE, PAL_SHADER_TYPE_GEOMETRY, + PAL_SHADER_TYPE_MESH, PAL_SHADER_TYPE_TESSELLATION_CONTROL, PAL_SHADER_TYPE_TESSELLATION_EVALUATION } PalShaderType; @@ -780,8 +781,6 @@ typedef struct { void PAL_CALL (*destroyShader)(PalShader* shader); - PalShaderType PAL_CALL (*getShaderType)(PalShader* shader); - PalResult PAL_CALL (*createRenderPass)( PalDevice* device, const PalRenderPassCreateInfo* info, @@ -820,6 +819,10 @@ typedef struct { PalQueue* queue, Uint64 value); + PalResult PAL_CALL (*getSemaphoreValue)( + PalSemaphore* semaphore, + Uint64* value); + PalResult PAL_CALL (*createCommandPool)( PalDevice* device, const PalCommandPoolCreateInfo* info, @@ -1039,6 +1042,12 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( PalQueue* queue, Uint64 value); +PAL_API PalResult PAL_CALL palGetSemaphoreValue( + PalSemaphore* semaphore, + Uint64* value); + +PAL_API bool PAL_CALL palIsTimelineSemaphore(PalSemaphore* semaphore); + PAL_API PalResult PAL_CALL palCreateCommandBuffer( PalDevice* device, PalCommandPool* pool, @@ -1074,6 +1083,8 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); +PAL_API bool PAL_CALL palIsGraphicsPipeline(PalPipeline* pipeline); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 90c44b2b..859f6066 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -32,10 +32,33 @@ freely, subject to the following restrictions: // ================================================== #define MAX_BACKENDS 32 +#define BINARY_SEMAPHORE 4 +#define TIMELINE_SEMAPHORE 5 +#define GRAPHICS_PIPELINE 6 +#define COMPUTE_PIPELINE 7 +#define SWAPCHAIN_IMAGE 12 + +typedef enum { + HANDLE_TYPE_NONE, + HANDLE_TYPE_ADAPTER, + HANDLE_TYPE_DEVICE, + HANDLE_TYPE_IMAGE, + HANDLE_TYPE_IMAGE_VIEW, + HANDLE_TYPE_SWAPCHAIN, + HANDLE_TYPE_RENDER_PASS, + HANDLE_TYPE_COMMAND_POOL, + HANDLE_TYPE_COMMAND_BUFFER, + HANDLE_TYPE_QUEUE, + HANDLE_TYPE_FENCE, + HANDLE_TYPE_SEMAPHORE, + HANDLE_TYPE_PIPELINE, + HANDLE_TYPE_SHADER +} HandleType; typedef struct { bool used; bool shouldFree; + HandleType type; Uint32 data2; void* handle; void* data; @@ -69,6 +92,7 @@ static HandleData* getFreeHandleData() if (!s_Graphics.handleData[i].used) { s_Graphics.handleData[i].used = true; s_Graphics.handleData[i].shouldFree = false; + s_Graphics.handleData[i].type = HANDLE_TYPE_NONE; return &s_Graphics.handleData[i]; } } @@ -82,6 +106,7 @@ static HandleData* getFreeHandleData() data->used = true; data->shouldFree = true; + data->type = HANDLE_TYPE_NONE; return data; } @@ -92,6 +117,7 @@ static void freeHandleData(HandleData* data) } else { data->used = false; } + data->type = HANDLE_TYPE_NONE; } // ================================================== @@ -224,8 +250,6 @@ PalResult PAL_CALL createVkShader( void PAL_CALL destroyVkShader(PalShader* shader); -PalShaderType PAL_CALL getVkShaderType(PalShader* shader); - PalResult PAL_CALL createVkRenderPass( PalDevice* device, const PalRenderPassCreateInfo* info, @@ -264,6 +288,10 @@ PalResult PAL_CALL signalVkSemaphore( PalQueue* queue, Uint64 value); +PalResult PAL_CALL getVkSemaphoreValue( + PalSemaphore* semaphore, + Uint64* value); + PalResult PAL_CALL createVkCommandPool( PalDevice* device, const PalCommandPoolCreateInfo* info, @@ -336,7 +364,6 @@ static PalGraphicsBackend s_VkBackend = { .presentSwapchain = presentVkSwapchain, .createShader = createVkShader, .destroyShader = destroyVkShader, - .getShaderType = getVkShaderType, .createRenderPass = createVkRenderPass, .destroyRenderPass = destroyVkRenderPass, .createFence = createVkFence, @@ -348,6 +375,7 @@ static PalGraphicsBackend s_VkBackend = { .destroySemaphore = destroyVkSemaphore, .waitSemaphore = waitVkSemaphore, .signalSemaphore = signalVkSemaphore, + .getSemaphoreValue = getVkSemaphoreValue, .createCommandPool = createVkCommandPool, .destroyCommandPool = destroyVkCommandPool, .createCommandBuffer = createVkCommandBuffer, @@ -425,7 +453,6 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->presentSwapchain || !backend->createShader || !backend->destroyShader || - !backend->getShaderType || !backend->createRenderPass || !backend->destroyRenderPass || !backend->createFence || @@ -437,6 +464,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroySemaphore || !backend->waitSemaphore || !backend->signalSemaphore || + !backend->getSemaphoreValue || !backend->createCommandPool || !backend->destroyCommandPool || !backend->createCommandBuffer || @@ -561,6 +589,7 @@ PalResult PAL_CALL palEnumerateAdapters( HandleData* data = getFreeHandleData(); data->backend = backend->base; data->handle = adapters[i]; + data->type = HANDLE_TYPE_ADAPTER; // set the adapter handle into our index generated handle adapters[i] = (PalAdapter*)data; @@ -599,7 +628,7 @@ PalResult PAL_CALL palGetAdapterInfo( } HandleData* data = (HandleData*)adapter; - if (!data->used) { + if (data->type != HANDLE_TYPE_ADAPTER) { return PAL_RESULT_INVALID_ADAPTER; } @@ -619,7 +648,7 @@ PalResult PAL_CALL palGetAdapterCapabilities( } HandleData* data = (HandleData*)adapter; - if (!data->used) { + if (data->type != HANDLE_TYPE_ADAPTER) { return PAL_RESULT_INVALID_ADAPTER; } @@ -644,7 +673,7 @@ PalResult PAL_CALL palCreateDevice( } HandleData* adapterData = (HandleData*)adapter; - if (!adapterData->used) { + if (adapterData->type != HANDLE_TYPE_ADAPTER) { return PAL_RESULT_INVALID_ADAPTER; } @@ -667,6 +696,8 @@ PalResult PAL_CALL palCreateDevice( deviceData->backend = adapterData->backend; deviceData->handle = device; + deviceData->type = HANDLE_TYPE_DEVICE; + deviceData->data2 = features; *outDevice = (PalDevice*)deviceData; return PAL_RESULT_SUCCESS; @@ -676,7 +707,7 @@ void PAL_CALL palDestroyDevice(PalDevice* device) { if (s_Graphics.initialized && device) { HandleData* data = (HandleData*)device; - if (data->used) { + if (data->type == HANDLE_TYPE_DEVICE) { data->backend->destroyDevice(data->handle); freeHandleData(data); } @@ -698,7 +729,7 @@ PalResult PAL_CALL palAllocateMemory( } HandleData* data = (HandleData*)device; - if (!data->used) { + if (data->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } @@ -715,7 +746,7 @@ void PAL_CALL palFreeMemory( { if (s_Graphics.initialized && device && memory) { HandleData* data = (HandleData*)device; - if (data->used) { + if (data->type == HANDLE_TYPE_DEVICE) { data->backend->freeMemory(data->handle, memory); freeHandleData(data); } @@ -740,7 +771,7 @@ PalResult PAL_CALL palCreateQueue( } HandleData* deviceData = (HandleData*)device; - if (!deviceData->used) { + if (deviceData->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } @@ -763,6 +794,7 @@ PalResult PAL_CALL palCreateQueue( queueData->backend = deviceData->backend; queueData->handle = queue; + queueData->type = HANDLE_TYPE_QUEUE; *outQueue = (PalQueue*)queueData; return PAL_RESULT_SUCCESS; @@ -772,7 +804,7 @@ void PAL_CALL palDestroyQueue(PalQueue* queue) { if (s_Graphics.initialized && queue) { HandleData* data = (HandleData*)queue; - if (data->used) { + if (data->type == HANDLE_TYPE_QUEUE) { data->backend->destroyQueue(data->handle); freeHandleData(data); } @@ -785,7 +817,7 @@ bool PAL_CALL palCanQueuePresent( { if (s_Graphics.initialized && queue) { HandleData* data = (HandleData*)queue; - if (data->used) { + if (data->type == HANDLE_TYPE_QUEUE) { return data->backend->canQueuePresent(data->handle, window); } } @@ -814,7 +846,7 @@ PalResult PAL_CALL palEnumerateFormats( } HandleData* data = (HandleData*)adapter; - if (!data->used) { + if (data->type != HANDLE_TYPE_ADAPTER) { return PAL_RESULT_INVALID_ADAPTER; } @@ -830,7 +862,7 @@ bool PAL_CALL palIsFormatSupported( } HandleData* data = (HandleData*)adapter; - if (!data->used) { + if (data->type != HANDLE_TYPE_ADAPTER) { return false; } @@ -846,7 +878,7 @@ PalImageUsages PAL_CALL palQueryFormatImageUsages( } HandleData* data = (HandleData*)adapter; - if (!data->used) { + if (data->type != HANDLE_TYPE_ADAPTER) { return PAL_IMAGE_USAGE_UNDEFINED; } @@ -862,7 +894,7 @@ PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( } HandleData* data = (HandleData*)adapter; - if (!data->used) { + if (data->type == HANDLE_TYPE_ADAPTER) { return PAL_IMAGE_VIEW_USAGE_UNDEFINED; } @@ -887,7 +919,7 @@ PalResult PAL_CALL palCreateImage( } HandleData* data = (HandleData*)device; - if (!data->used) { + if (data->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } @@ -910,6 +942,8 @@ PalResult PAL_CALL palCreateImage( imageData->backend = data->backend; imageData->handle = image; + imageData->type = HANDLE_TYPE_IMAGE; + imageData->data2 = 0; *outImage = (PalImage*)imageData; return PAL_RESULT_SUCCESS; @@ -919,9 +953,11 @@ void PAL_CALL palDestroyImage(PalImage* image) { if (s_Graphics.initialized && image) { HandleData* data = (HandleData*)image; - if (data->used) { - data->backend->destroyImage(data->handle); - freeHandleData(data); + if (data->type == HANDLE_TYPE_IMAGE) { + if (data->data2 == SWAPCHAIN_IMAGE) { + data->backend->destroyImage(data->handle); + freeHandleData(data); + } } } } @@ -939,7 +975,7 @@ PalResult PAL_CALL palGetImageInfo( } HandleData* data = (HandleData*)image; - if (!data->used) { + if (data->type != HANDLE_TYPE_IMAGE) { return PAL_RESULT_INVALID_IMAGE; } @@ -959,11 +995,11 @@ PalResult PAL_CALL palGetImageMemoryRequirements( } HandleData* data = (HandleData*)image; - if (!data) { + if (data->type != HANDLE_TYPE_IMAGE) { return PAL_RESULT_INVALID_IMAGE; } - if (!data->used) { + if (data->data2 == SWAPCHAIN_IMAGE) { return PAL_RESULT_INVALID_IMAGE; } @@ -986,7 +1022,11 @@ PalResult PAL_CALL palBindImageMemory( } HandleData* data = (HandleData*)image; - if (!data) { + if (data->type != HANDLE_TYPE_IMAGE) { + return PAL_RESULT_INVALID_IMAGE; + } + + if (data->data2 == SWAPCHAIN_IMAGE) { return PAL_RESULT_INVALID_IMAGE; } @@ -1016,15 +1056,15 @@ PalResult PAL_CALL palCreateImageView( HandleData* deviceData = (HandleData*)device; HandleData* imageData = (HandleData*)image; - if (!deviceData->used) { + if (deviceData->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } - if (!imageData->used) { + if (imageData->type != HANDLE_TYPE_IMAGE) { return PAL_RESULT_INVALID_IMAGE; } - // create a slot for the image views + // create a slot for the image view HandleData* imageViewData = getFreeHandleData(); if (!imageViewData) { return PAL_RESULT_OUT_OF_MEMORY; @@ -1044,6 +1084,7 @@ PalResult PAL_CALL palCreateImageView( imageViewData->backend = deviceData->backend; imageViewData->handle = imageView; + imageViewData->type = HANDLE_TYPE_IMAGE_VIEW; *outImageView = (PalImageView*)imageViewData; return PAL_RESULT_SUCCESS; @@ -1053,7 +1094,7 @@ void PAL_CALL palDestroyImageView(PalImageView* imageView) { if (s_Graphics.initialized && imageView) { HandleData* data = (HandleData*)imageView; - if (data->used) { + if (data->type == HANDLE_TYPE_IMAGE_VIEW) { data->backend->destroyImageView(data->handle); freeHandleData(data); } @@ -1078,7 +1119,7 @@ PalResult PAL_CALL palQuerySwapchainCapabilities( } HandleData* data = (HandleData*)adapter; - if (!data->used) { + if (data->type != HANDLE_TYPE_ADAPTER) { return PAL_RESULT_INVALID_ADAPTER; } @@ -1115,11 +1156,11 @@ PalResult PAL_CALL palCreateSwapchain( HandleData* deviceData = (HandleData*)device; HandleData* queueData = (HandleData*)queue; - if (!deviceData->used) { + if (deviceData->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } - if (!queueData->used) { + if (queueData->type != HANDLE_TYPE_QUEUE) { return PAL_RESULT_INVALID_QUEUE; } @@ -1152,12 +1193,15 @@ PalResult PAL_CALL palCreateSwapchain( tmp->used = true; tmp->shouldFree = false; // we free all at once tmp->data = nullptr; + tmp->type = HANDLE_TYPE_IMAGE; + tmp->data2 = SWAPCHAIN_IMAGE; } swapchainData->backend = deviceData->backend; swapchainData->handle = swapchain; swapchainData->data = (void*)imagesData; swapchainData->data2 = info->imageCount; + swapchainData->type = HANDLE_TYPE_SWAPCHAIN; *outSwapchain = (PalSwapchain*)swapchainData; return PAL_RESULT_SUCCESS; @@ -1167,7 +1211,7 @@ void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) { if (s_Graphics.initialized && swapchain) { HandleData* data = (HandleData*)swapchain; - if (data->used) { + if (data->type == HANDLE_TYPE_SWAPCHAIN) { data->backend->destroySwapchain(data->handle); palFree(s_Graphics.allocator, data->data); freeHandleData(data); @@ -1179,7 +1223,9 @@ Uint32 PAL_CALL palGetSwapchainImageCount(PalSwapchain* swapchain) { if (s_Graphics.initialized && swapchain) { HandleData* data = (HandleData*)swapchain; - return data->data2; + if (data->type == HANDLE_TYPE_SWAPCHAIN) { + return data->data2; + } } return 0; } @@ -1193,7 +1239,7 @@ PalImage* PAL_CALL palGetSwapchainImage( } HandleData* data = (HandleData*)swapchain; - if (!data->used) { + if (data->type != HANDLE_TYPE_SWAPCHAIN) { return nullptr; } @@ -1214,23 +1260,24 @@ PalImage* PAL_CALL palGetNextSwapchainImage( } HandleData* data = (HandleData*)swapchain; - if (!data->used) { + if (data->type != HANDLE_TYPE_SWAPCHAIN) { return nullptr; } void* FenceHandle = nullptr; void* signalSemaphoreHandle = nullptr; + HandleData* tmp = (HandleData*)info->signalSemaphore; if (info->fence) { - HandleData* tmp = (HandleData*)info->signalSemaphore; - if (!tmp->used) { + tmp = (HandleData*)info->signalSemaphore; + if (tmp->type != HANDLE_TYPE_FENCE) { return nullptr; } FenceHandle = tmp->handle; } if (info->signalSemaphore) { - HandleData* tmp = (HandleData*)info->signalSemaphore; - if (!tmp->used) { + tmp = (HandleData*)info->signalSemaphore; + if (tmp->type != HANDLE_TYPE_SEMAPHORE) { return nullptr; } signalSemaphoreHandle = tmp->handle; @@ -1242,7 +1289,7 @@ PalImage* PAL_CALL palGetNextSwapchainImage( nextInfo.signalValue = info->signalValue; nextInfo.timeout = info->timeout; - PalImage* tmp = data->backend->getNextSwapchainImage( + PalImage* tmpImage = data->backend->getNextSwapchainImage( data->handle, &nextInfo); @@ -1251,7 +1298,7 @@ PalImage* PAL_CALL palGetNextSwapchainImage( HandleData* imagesData = data->data; HandleData* imageData = nullptr; for (int i = 0; i < data->data2; i++) { - if (imagesData[i].handle == tmp) { + if (imagesData[i].handle == tmpImage) { // found our handle info imageData = &imagesData[i]; break; @@ -1274,19 +1321,23 @@ PalResult PAL_CALL palPresentSwapchain( } HandleData* swapchainData = (HandleData*)swapchain; - if (!swapchainData->used) { + if (swapchainData->type != HANDLE_TYPE_SWAPCHAIN) { return PAL_RESULT_INVALID_SWAPCHAIN; } HandleData* imageData = (HandleData*)info->image; - if (!imageData->used) { + if (imageData->type != HANDLE_TYPE_IMAGE) { + return PAL_RESULT_INVALID_IMAGE; + } + + if (imageData->data2 != SWAPCHAIN_IMAGE) { return PAL_RESULT_INVALID_IMAGE; } void* waitSemaphoreHandle = nullptr; if (info->waitSemaphore) { HandleData* tmp = (HandleData*)info->waitSemaphore; - if (!tmp->used) { + if (tmp->type != HANDLE_TYPE_SEMAPHORE) { return PAL_RESULT_INVALID_SEMAPHORE; } waitSemaphoreHandle = tmp->handle; @@ -1324,7 +1375,7 @@ PalResult PAL_CALL palCreateShader( } HandleData* data = (HandleData*)device; - if (!data->used) { + if (data->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } @@ -1347,6 +1398,8 @@ PalResult PAL_CALL palCreateShader( shaderData->backend = data->backend; shaderData->handle = shader; + shaderData->type = HANDLE_TYPE_SHADER; + shaderData->data2 = (Uint32)info->type; *outShader = (PalShader*)shaderData; return PAL_RESULT_SUCCESS; @@ -1356,7 +1409,7 @@ void PAL_CALL palDestroyShader(PalShader* shader) { if (s_Graphics.initialized && shader) { HandleData* data = (HandleData*)shader; - if (data->used) { + if (data->type == HANDLE_TYPE_SHADER) { data->backend->destroyShader(data->handle); freeHandleData(data); } @@ -1367,8 +1420,8 @@ PalShaderType PAL_CALL palGetShaderType(PalShader* shader) { if (s_Graphics.initialized && shader) { HandleData* data = (HandleData*)shader; - if (data->used) { - return data->backend->getShaderType(data->handle); + if (data->type == HANDLE_TYPE_SHADER) { + return (PalShaderType)data->data2; } } return PAL_SHADER_TYPE_UNDEFINED; @@ -1396,7 +1449,7 @@ PalResult PAL_CALL palCreateRenderPass( } HandleData* data = (HandleData*)device; - if (!data->used) { + if (data->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } @@ -1407,13 +1460,14 @@ PalResult PAL_CALL palCreateRenderPass( createInfo.width = info->width; createInfo.height = info->height; + HandleData* tmp = nullptr; for (int i = 0; i < info->attachmentCount; i++) { if (!info->attachments[i].target) { return PAL_RESULT_NULL_POINTER; } - HandleData* tmp = (HandleData*)info->attachments[i].target; - if (!tmp->used) { + tmp = (HandleData*)info->attachments[i].target; + if (tmp->type != HANDLE_TYPE_IMAGE_VIEW) { return PAL_RESULT_INVALID_IMAGE_VIEW; } @@ -1425,7 +1479,7 @@ PalResult PAL_CALL palCreateRenderPass( if (info->attachments[i].resolveTarget) { tmp = (HandleData*)info->attachments[i].resolveTarget; - if (!tmp->used) { + if (tmp->type != HANDLE_TYPE_IMAGE_VIEW) { return PAL_RESULT_INVALID_IMAGE_VIEW; } attachments[i].resolveTarget = tmp->handle; @@ -1451,6 +1505,7 @@ PalResult PAL_CALL palCreateRenderPass( renderPassData->backend = data->backend; renderPassData->handle = renderpass; + renderPassData->type = HANDLE_TYPE_RENDER_PASS; *outRenderPass = (PalRenderPass*)renderPassData; return PAL_RESULT_SUCCESS; @@ -1460,7 +1515,7 @@ void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) { if (s_Graphics.initialized && renderPass) { HandleData* data = (HandleData*)renderPass; - if (data->used) { + if (data->type == HANDLE_TYPE_RENDER_PASS) { data->backend->destroyRenderPass(data->handle); freeHandleData(data); } @@ -1484,7 +1539,7 @@ PalResult PAL_CALL palCreateFence( } HandleData* data = (HandleData*)device; - if (!data->used) { + if (data->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } @@ -1503,6 +1558,7 @@ PalResult PAL_CALL palCreateFence( fenceData->backend = data->backend; fenceData->handle = fence; + fenceData->type = HANDLE_TYPE_FENCE; *outFence = (PalFence*)fenceData; return PAL_RESULT_SUCCESS; @@ -1512,7 +1568,7 @@ void PAL_CALL palDestroyFence(PalFence* fence) { if (s_Graphics.initialized && fence) { HandleData* data = (HandleData*)fence; - if (data->used) { + if (data->type == HANDLE_TYPE_FENCE) { data->backend->destroyFence(data->handle); freeHandleData(data); } @@ -1532,7 +1588,7 @@ PalResult PAL_CALL palWaitFence( } HandleData* data = (HandleData*)fence; - if (!data->used) { + if (data->type != HANDLE_TYPE_FENCE) { return PAL_RESULT_INVALID_FENCE; } @@ -1550,7 +1606,7 @@ PalResult PAL_CALL palResetFence(PalFence* fence) } HandleData* data = (HandleData*)fence; - if (!data->used) { + if (data->type != HANDLE_TYPE_FENCE) { return PAL_RESULT_INVALID_FENCE; } @@ -1561,7 +1617,7 @@ bool PAL_CALL palIsFenceSignaled(PalFence* fence) { if (s_Graphics.initialized && fence) { HandleData* data = (HandleData*)fence; - if (data->used) { + if (data->type == HANDLE_TYPE_FENCE) { return data->backend->isFenceSignaled(data->handle); } } @@ -1585,7 +1641,7 @@ PalResult PAL_CALL palCreateSemaphore( } HandleData* data = (HandleData*)device; - if (!data->used) { + if (data->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } @@ -1604,6 +1660,12 @@ PalResult PAL_CALL palCreateSemaphore( semaphoreData->backend = data->backend; semaphoreData->handle = semaphore; + semaphoreData->type = HANDLE_TYPE_SEMAPHORE; + + semaphoreData->data2 = BINARY_SEMAPHORE; + if (data->data2 & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + semaphoreData->data2 = TIMELINE_SEMAPHORE; + } *outSemaphore = (PalSemaphore*)semaphoreData; return PAL_RESULT_SUCCESS; @@ -1613,7 +1675,7 @@ void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore) { if (s_Graphics.initialized && semaphore) { HandleData* data = (HandleData*)semaphore; - if (data->used) { + if (data->type != HANDLE_TYPE_SEMAPHORE) { data->backend->destroySemaphore(data->handle); freeHandleData(data); } @@ -1635,12 +1697,12 @@ PalResult PAL_CALL palWaitSemaphore( } HandleData* semaphoreData = (HandleData*)semaphore; - if (!semaphoreData->used) { + if (semaphoreData->type != HANDLE_TYPE_SEMAPHORE) { return PAL_RESULT_INVALID_SEMAPHORE; } HandleData* queueData = (HandleData*)queue; - if (!queueData->used) { + if (queueData->type != HANDLE_TYPE_QUEUE) { return PAL_RESULT_INVALID_QUEUE; } @@ -1665,12 +1727,12 @@ PalResult PAL_CALL palSignalSemaphore( } HandleData* semaphoreData = (HandleData*)semaphore; - if (!semaphoreData->used) { + if (semaphoreData->type != HANDLE_TYPE_SEMAPHORE) { return PAL_RESULT_INVALID_SEMAPHORE; } HandleData* queueData = (HandleData*)queue; - if (!queueData->used) { + if (queueData->type != HANDLE_TYPE_QUEUE) { return PAL_RESULT_INVALID_QUEUE; } @@ -1680,6 +1742,45 @@ PalResult PAL_CALL palSignalSemaphore( value); } +PalResult PAL_CALL palGetSemaphoreValue( + PalSemaphore* semaphore, + Uint64* value) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!semaphore || !value) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)semaphore; + if (data->type != HANDLE_TYPE_SEMAPHORE) { + return PAL_RESULT_INVALID_SEMAPHORE; + } + + if (data->data2 == BINARY_SEMAPHORE) { + return PAL_RESULT_INVALID_SEMAPHORE; + } + + return data->backend->getSemaphoreValue( + data->handle, + value); +} + +bool PAL_CALL palIsTimelineSemaphore(PalSemaphore* semaphore) +{ + if (s_Graphics.initialized && semaphore) { + HandleData* data = (HandleData*)semaphore; + if (data->type == HANDLE_TYPE_SEMAPHORE) { + if (data->data2 == TIMELINE_SEMAPHORE) { + return true; + } + } + } + return false; +} + // ================================================== // Command Pool And Buffer // ================================================== @@ -1702,12 +1803,12 @@ PalResult PAL_CALL palCreateCommandPool( } HandleData* deviceData = (HandleData*)device; - if (!deviceData->used) { + if (deviceData->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } HandleData* queueData = (HandleData*)info->queue; - if (!queueData->used) { + if (queueData->type != HANDLE_TYPE_QUEUE) { return PAL_RESULT_INVALID_QUEUE; } @@ -1735,6 +1836,7 @@ PalResult PAL_CALL palCreateCommandPool( poolData->backend = deviceData->backend; poolData->handle = pool; + poolData->type = HANDLE_TYPE_COMMAND_POOL; *outPool = (PalCommandPool*)poolData; return PAL_RESULT_SUCCESS; @@ -1744,7 +1846,7 @@ void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) { if (s_Graphics.initialized && pool) { HandleData* data = (HandleData*)pool; - if (data->used) { + if (data->type == HANDLE_TYPE_COMMAND_POOL) { data->backend->destroyCommandPool(data->handle); freeHandleData(data); } @@ -1766,12 +1868,12 @@ PalResult PAL_CALL palCreateCommandBuffer( } HandleData* data = (HandleData*)device; - if (!data->used) { + if (data->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } HandleData* poolData = (HandleData*)pool; - if (!poolData->used) { + if (poolData->type != HANDLE_TYPE_COMMAND_POOL) { return PAL_RESULT_INVALID_COMMAND_POOL; } @@ -1795,6 +1897,7 @@ PalResult PAL_CALL palCreateCommandBuffer( cmdBufferData->backend = data->backend; cmdBufferData->handle = cmdBuffer; + cmdBufferData->type = HANDLE_TYPE_COMMAND_BUFFER; *outCmdBuffer = (PalCommandBuffer*)cmdBufferData; return PAL_RESULT_SUCCESS; @@ -1804,7 +1907,7 @@ void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) { if (s_Graphics.initialized && cmdBuffer) { HandleData* data = (HandleData*)cmdBuffer; - if (data->used) { + if (data->type == HANDLE_TYPE_COMMAND_BUFFER) { data->backend->destroyCommandBuffer(data->handle); freeHandleData(data); } @@ -1822,7 +1925,7 @@ PalResult PAL_CALL palBeginRendering(PalCommandBuffer* cmdBuffer) } HandleData* data = (HandleData*)cmdBuffer; - if (!data->used) { + if (data->type != HANDLE_TYPE_COMMAND_BUFFER) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } @@ -1840,7 +1943,7 @@ PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer) } HandleData* data = (HandleData*)cmdBuffer; - if (!data->used) { + if (data->type != HANDLE_TYPE_COMMAND_BUFFER) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } @@ -1861,7 +1964,11 @@ PalResult PAL_CALL palExecuteCommandBuffer( HandleData* primaryCmdBufferData = (HandleData*)primaryCmdBuffer; HandleData* secondaryCmdBufferData = (HandleData*)secondaryCmdBuffer; - if (!primaryCmdBufferData->used || secondaryCmdBufferData->used) { + if (primaryCmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + if (secondaryCmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } @@ -1889,12 +1996,12 @@ PalResult PAL_CALL palBeginRenderPass( } HandleData* cmdBufferData = (HandleData*)cmdBuffer; - if (!cmdBufferData->used) { + if (cmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } HandleData* renderPassData = (HandleData*)renderPass; - if (!renderPassData->used) { + if (renderPassData->type != HANDLE_TYPE_RENDER_PASS) { return PAL_RESULT_INVALID_RENDER_PASS; } @@ -1916,7 +2023,7 @@ PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer) } HandleData* data = (HandleData*)cmdBuffer; - if (!data->used) { + if (data->type != HANDLE_TYPE_COMMAND_BUFFER) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } @@ -1936,12 +2043,12 @@ PalResult PAL_CALL palSubmitCommandBuffer( } HandleData* data = (HandleData*)queue; - if (!data->used) { + if (data->type != HANDLE_TYPE_QUEUE) { return PAL_RESULT_INVALID_QUEUE; } HandleData* cmdBufferData = (HandleData*)info->cmdBuffer; - if (!cmdBufferData->used) { + if (cmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } @@ -1950,21 +2057,21 @@ PalResult PAL_CALL palSubmitCommandBuffer( void* signalSemaphoreHandle = nullptr; if (info->fence) { HandleData* tmp = (HandleData*)info->fence; - if (tmp->used) { + if (tmp->type == HANDLE_TYPE_FENCE) { fenceHandle = tmp->handle; } } if (info->waitSemaphore) { HandleData* tmp = (HandleData*)info->waitSemaphore; - if (tmp->used) { + if (tmp->type == HANDLE_TYPE_SEMAPHORE) { waitSemaphoreHandle = tmp->handle; } } if (info->signalSemaphore) { HandleData* tmp = (HandleData*)info->signalSemaphore; - if (tmp->used) { + if (tmp->type == HANDLE_TYPE_SEMAPHORE) { signalSemaphoreHandle = tmp->handle; } } @@ -2008,7 +2115,7 @@ PalResult PAL_CALL palCreateGraphicsPipeline( } HandleData* deviceData = (HandleData*)device; - if (!deviceData->used) { + if (deviceData->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } @@ -2030,33 +2137,46 @@ PalResult PAL_CALL palCreateGraphicsPipeline( // vertex shader path if (info->vertexShader) { tmp = (HandleData*)info->vertexShader; - if (tmp->used) { + if (tmp->type == HANDLE_TYPE_SHADER && + tmp->data2 == PAL_SHADER_TYPE_VERTEX) { vShaderHandle = tmp->handle; } - // fragment shader - tmp = (HandleData*)info->fragmentShader; - if (tmp->used) { - fShaderHandle = tmp->handle; - } - // tessellation control shader tmp = (HandleData*)info->tessellationControlShader; - if (tmp->used) { + if (tmp->type == HANDLE_TYPE_SHADER && + tmp->data2 == PAL_SHADER_TYPE_TESSELLATION_CONTROL) { tessCShaderHandle = tmp->handle; } // tessellation evaluation shader tmp = (HandleData*)info->tessellationEvaluationShader; - if (tmp->used) { + if (tmp->type == HANDLE_TYPE_SHADER && + tmp->data2 == PAL_SHADER_TYPE_TESSELLATION_EVALUATION) { tessEShaderHandle = tmp->handle; } // geometry shader tmp = (HandleData*)info->geometryShader; - if (tmp->used) { + if (tmp->type == HANDLE_TYPE_SHADER && + tmp->data2 == PAL_SHADER_TYPE_GEOMETRY) { gShaderHandle = tmp->handle; } + + } else { + // mesh shader + tmp = (HandleData*)info->meshShader; + if (tmp->type == HANDLE_TYPE_SHADER && + tmp->data2 == PAL_SHADER_TYPE_MESH) { + mShaderHandle = tmp->handle; + } + } + + // fragment shader + tmp = (HandleData*)info->fragmentShader; + if (tmp->type == HANDLE_TYPE_SHADER && + tmp->data2 == PAL_SHADER_TYPE_FRAGMENT) { + fShaderHandle = tmp->handle; } PalGraphicsPipelineCreateInfo createInfo; @@ -2091,6 +2211,8 @@ PalResult PAL_CALL palCreateGraphicsPipeline( pipelineData->backend = deviceData->backend; pipelineData->handle = pipeline; + pipelineData->type = HANDLE_TYPE_PIPELINE; + pipelineData->data2 = GRAPHICS_PIPELINE; *outPipeline = (PalPipeline*)pipelineData; return PAL_RESULT_SUCCESS; @@ -2100,9 +2222,22 @@ void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) { if (s_Graphics.initialized && pipeline) { HandleData* data = (HandleData*)pipeline; - if (data->used) { + if (data->type == HANDLE_TYPE_PIPELINE) { data->backend->destroyPipeline(data->handle); freeHandleData(data); } } +} + +bool PAL_CALL palIsGraphicsPipeline(PalPipeline* pipeline) +{ + if (s_Graphics.initialized && pipeline) { + HandleData* data = (HandleData*)pipeline; + if (data->type == HANDLE_TYPE_PIPELINE) { + if (data->data2 == GRAPHICS_PIPELINE) { + return true; + } + } + } + return false; } \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 4488189b..30b08a06 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3222,6 +3222,12 @@ PalResult PAL_CALL createVkShader( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + + } else if (info->type == PAL_SHADER_TYPE_MESH) { + if (device->features & PAL_SHADER_TYPE_MESH) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + stage = VK_SHADER_STAGE_MESH_BIT_EXT; } shader = palAllocate(s_Vk.allocator, sizeof(PalShader), 0); @@ -3266,11 +3272,6 @@ void PAL_CALL destroyVkShader(PalShader* shader) palFree(s_Vk.allocator, shader); } -PalShaderType PAL_CALL getVkShaderType(PalShader* shader) -{ - return shader->type; -} - // ================================================== // Render Pass // ================================================== @@ -3618,6 +3619,22 @@ PalResult PAL_CALL signalVkSemaphore( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL getVkSemaphoreValue( + PalSemaphore* semaphore, + Uint64* value) +{ + VkResult result = s_Vk.getSemaphoreValue( + semaphore->device->handle, + semaphore->handle, + value); + + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + return PAL_RESULT_SUCCESS; +} + // ================================================== // Command Pool And Buffer // ================================================== diff --git a/tests/tests_main.c b/tests/tests_main.c index 4660bd2f..b8d7f6ac 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,11 +55,11 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); + registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest("Clear Color Test", clearColorTest); + registerTest("Clear Color Test", clearColorTest); #endif // runTests(); From f5f25d2aba0d1ca1d3c2d00dcd182fd024c291c3 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 19 Dec 2025 11:36:13 +0000 Subject: [PATCH 051/372] seperate adapter features from adapter capabilities --- include/pal/pal_graphics.h | 12 +- src/graphics/pal_graphics.c | 22 +++ src/graphics/pal_vulkan.c | 301 +++++++++++++++++++----------------- tests/graphics_test.c | 132 ++++------------ 4 files changed, 216 insertions(+), 251 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 89893bac..04455103 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -223,7 +223,7 @@ typedef enum { PAL_ADAPTER_FEATURE_SHADER_INT64 = PAL_BIT64(11), PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(12), PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(13), - PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING = PAL_BIT64(14), + PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE = PAL_BIT64(14), PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(15), PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(16), PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(17), @@ -233,7 +233,7 @@ typedef enum { PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(21), PAL_ADAPTER_FEATURE_RESET_FENCE = PAL_BIT64(22), PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(23), - PAL_ADAPTER_FEATURE_LINE_POLYGON_MODE = PAL_BIT64(24) + PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE = PAL_BIT64(24) } PalAdapterFeatures; typedef enum { @@ -460,7 +460,9 @@ typedef struct { Uint32 maxUniformBufferSize; Uint32 maxStorageBufferSize; Uint32 maxPushConstantSize; - PalAdapterFeatures features; + Uint32 maxComputeWorkGroupInvocations; + Uint32 maxComputeWorkGroupCount[3]; + Uint32 maxComputeWorkGroupSize[3]; } PalAdapterCapabilities; typedef struct { @@ -675,6 +677,8 @@ typedef struct { PalAdapter* adapter, PalAdapterCapabilities* caps); + PalAdapterFeatures PAL_CALL (*getAdapterFeatures)(PalAdapter* adapter); + PalResult PAL_CALL (*createDevice)( PalAdapter* adapter, PalAdapterFeatures features, @@ -887,6 +891,8 @@ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps); +PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); + PAL_API PalResult PAL_CALL palCreateDevice( PalAdapter* adapter, PalAdapterFeatures features, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 859f6066..74d9f21e 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -144,6 +144,8 @@ PalResult PAL_CALL getVkAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps); +PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter); + PalResult PAL_CALL createVkDevice( PalAdapter* adapter, PalAdapterFeatures features, @@ -338,6 +340,7 @@ static PalGraphicsBackend s_VkBackend = { .enumerateAdapters = enumerateVkAdapters, .getAdapterInfo = getVkAdapterInfo, .getAdapterCapabilities = getVkAdapterCapabilities, + .getAdapterFeatures = getVkAdapterFeatures, .createDevice = createVkDevice, .destroyDevice = destroyVkDevice, .allocateMemory = allocateVkMemory, @@ -427,6 +430,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) if (!backend->enumerateAdapters || !backend->getAdapterInfo || !backend->getAdapterCapabilities || + !backend->getAdapterFeatures || !backend->createDevice || !backend->destroyDevice || !backend->allocateMemory || @@ -655,6 +659,24 @@ PalResult PAL_CALL palGetAdapterCapabilities( return data->backend->getAdapterCapabilities(data->handle, caps); } +PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) +{ + if (!s_Graphics.initialized) { + return 0; + } + + if (!adapter) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)adapter; + if (data->type != HANDLE_TYPE_ADAPTER) { + return PAL_RESULT_INVALID_ADAPTER; + } + + return data->backend->getAdapterFeatures(data->handle); +} + // ================================================== // Device // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 30b08a06..37c840d0 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1605,13 +1605,14 @@ PalResult PAL_CALL getVkAdapterCapabilities( VkResult ret = VK_SUCCESS; VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; VkPhysicalDeviceProperties props = {0}; - VkPhysicalDeviceMultiviewPropertiesKHR vProps = {0}; + VkPhysicalDeviceMultiviewPropertiesKHR multiViewProps = {0}; VkPhysicalDeviceProperties2 properties2 = {0}; - vProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; + multiViewProps.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; s_Vk.getPhysicalDeviceProperties(phyDevice, &props); properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - properties2.pNext = &vProps; + properties2.pNext = &multiViewProps; s_Vk.getPhysicalDeviceProperties2(phyDevice, &properties2); caps->debugLayer = s_Vk.hasDebug; @@ -1633,7 +1634,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->maxStorageBufferSize = props.limits.maxStorageBufferRange; caps->maxPushConstantSize = props.limits.maxPushConstantsSize; - caps->maxMultiViews = vProps.maxMultiviewViewCount; + caps->maxMultiViews = multiViewProps.maxMultiviewViewCount; if (caps->maxMultiViews == 0) { caps->maxMultiViews = 1; } @@ -1690,9 +1691,19 @@ PalResult PAL_CALL getVkAdapterCapabilities( } palFree(s_Vk.allocator, queueProps); + return PAL_RESULT_SUCCESS; +} - // get supported extensions +PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) +{ + VkResult ret; + PalAdapterFeatures adapterFeatures = 0; Uint32 extensionCount = 0; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + VkPhysicalDeviceProperties props = {0}; + + // get supported extensions + s_Vk.getPhysicalDeviceProperties(phyDevice, &props); ret = s_Vk.enumerateDeviceExtensionProperties( phyDevice, nullptr, @@ -1701,7 +1712,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( if (ret != VK_SUCCESS) { // we just return without any modern features which is rare - return PAL_RESULT_SUCCESS; + return 0; } VkExtensionProperties* extensionProps = nullptr; @@ -1711,7 +1722,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( 0); if (!extensionProps) { - return PAL_RESULT_SUCCESS; + return 0; } s_Vk.enumerateDeviceExtensionProperties( @@ -1720,20 +1731,19 @@ PalResult PAL_CALL getVkAdapterCapabilities( &extensionCount, extensionProps); + // check extensions bool rayTracingFound = false; bool accelerateFound = false; bool dynamicRendering = false; - caps->features = 0; - - Uint32 version = 0; - if (s_Vk.enumerateInstanceVersion) { - s_Vk.enumerateInstanceVersion(&version); - if (version >= VK_API_VERSION_1_3) { - dynamicRendering = true; - } - } + bool meshShader = false; + bool fragmentRateShading = false; + bool timelineSemaphore = false; + bool descriptorIndexing = false; + bool shaderFloat16 = false; + bool multiiView = false; // clang-format off + // check if the extensions are present for (int i = 0; i < extensionCount; i++) { VkExtensionProperties* props = &extensionProps[i]; if (strcmp(props->extensionName, "VK_KHR_ray_tracing_pipeline") == 0) { @@ -1746,207 +1756,208 @@ PalResult PAL_CALL getVkAdapterCapabilities( dynamicRendering = true; } else if (strcmp(props->extensionName, "VK_EXT_mesh_shader") == 0) { - // mesh shader - VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; - mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &mesh; - - if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); - - } else { - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - } - - if (mesh.meshShader && mesh.taskShader) { - caps->features |= PAL_ADAPTER_FEATURE_MESH_SHADER; - } + meshShader = true; } else if (strcmp(props->extensionName, "VK_KHR_fragment_shading_rate") == 0) { - // variable rate shading - VkPhysicalDeviceFragmentShadingRateFeaturesKHR frag = {0}; - frag.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &frag; + fragmentRateShading = true; - if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); + } else if (strcmp(props->extensionName, "VK_EXT_descriptor_indexing") == 0) { + descriptorIndexing = true; + + } else if (strcmp(props->extensionName, "VK_KHR_swapchain") == 0) { + adapterFeatures |= PAL_ADAPTER_FEATURE_SWAPCHAIN; - } else { - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - } + } else if (strcmp(props->extensionName, "VK_KHR_shader_float16_int8") == 0) { + shaderFloat16 = true; - if (frag.pipelineFragmentShadingRate) { - caps->features |= PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING; - } + } else if (strcmp(props->extensionName, "VK_KHR_timeline_semaphore") == 0) { + timelineSemaphore = true; - } else if (strcmp(props->extensionName, "VK_EXT_descriptor_indexing") == 0) { - // descriptor indexing - VkPhysicalDeviceDescriptorIndexingFeatures desc = {0}; - desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + } else if (strcmp(props->extensionName, "VK_KHR_multiview") == 0) { + multiiView = true; + } + } - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &desc; + // features that require core and extension support + // ray tracing is part of core 1.3 + if (props.apiVersion >= VK_API_VERSION_1_3 || + (rayTracingFound && accelerateFound)) { - if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); + VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; + VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; - } else { - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - } + ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; + acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - if (desc.shaderSampledImageArrayNonUniformIndexing) { - caps->features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - } + ray.pNext = &acc; + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &ray; - } else if (strcmp(props->extensionName, "VK_KHR_swapchain") == 0) { - // swapchain - caps->features |= PAL_ADAPTER_FEATURE_SWAPCHAIN; + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (ray.rayTracingPipeline && acc.accelerationStructure) { + adapterFeatures |= PAL_ADAPTER_FEATURE_RAY_TRACING; + } + } - } else if (strcmp(props->extensionName, "VK_KHR_shader_float16_int8") == 0) { - // shader float16 - VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; - shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; + // dynamic rendering is part of core 1.3 + if (props.apiVersion >= VK_API_VERSION_1_3 || dynamicRendering) { + VkPhysicalDeviceDynamicRenderingFeaturesKHR dyn; + dyn.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &shader16; + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &dyn; - if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (dyn.dynamicRendering) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING; + } + } - } else { - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - } + // mesh shader is part of core 1.3 + if (props.apiVersion >= VK_API_VERSION_1_3 || meshShader) { + VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; + mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; - if (shader16.shaderFloat16) { - caps->features |= PAL_ADAPTER_FEATURE_SHADER_FLOAT16; - } + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &mesh; - } else if (strcmp(props->extensionName, "VK_KHR_timeline_semaphore") == 0) { - // timeline semaphore - VkPhysicalDeviceTimelineSemaphoreFeatures timeline = {0}; - timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (mesh.meshShader && mesh.taskShader) { + adapterFeatures |= PAL_ADAPTER_FEATURE_MESH_SHADER; + } + } - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &timeline; + // fragment shading rate is part of core 1.3 + if (props.apiVersion >= VK_API_VERSION_1_3 || fragmentRateShading) { + VkPhysicalDeviceFragmentShadingRateFeaturesKHR frag = {0}; + frag.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; - if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &frag; - } else { - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - } + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (frag.pipelineFragmentShadingRate) { + adapterFeatures |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE; + } + } - if (timeline.timelineSemaphore) { - caps->features |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; - } + // descriptor indexing is part of core 1.2 + if (props.apiVersion >= VK_API_VERSION_1_2 || descriptorIndexing) { + VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; + desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; - } else if (strcmp(props->extensionName, "VK_KHR_multiview") == 0) { - // multi view - VkPhysicalDeviceMultiviewFeaturesKHR view = {0}; - view.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR; + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &desc; - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &view; + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (desc.shaderSampledImageArrayNonUniformIndexing) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + } + } - if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); + // timeline semaphore is part of core 1.2 + if (props.apiVersion >= VK_API_VERSION_1_2 || timelineSemaphore) { + VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline = {0}; + timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; - } else { - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - } + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &timeline; - if (view.multiview) { - caps->features |= PAL_ADAPTER_FEATURE_MULTI_VIEW; - } + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (timeline.timelineSemaphore) { + adapterFeatures |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; } } - if (accelerateFound && rayTracingFound) { - // ray tracing - VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; - VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; - ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + // shader float 16 is part of core 1.2 + if (props.apiVersion >= VK_API_VERSION_1_2 || shaderFloat16) { + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; + shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; - ray.pNext = &acc; VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &ray; - - if (s_Vk.getPhysicalDeviceFeatures2KHR) { - s_Vk.getPhysicalDeviceFeatures2KHR(phyDevice, &features); + features.pNext = &shader16; - } else { - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (shader16.shaderFloat16) { + adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_FLOAT16; } + } - if (ray.rayTracingPipeline && acc.accelerationStructure) { - caps->features |= PAL_ADAPTER_FEATURE_RAY_TRACING; + // multi view is part of core 1.1 + if (props.apiVersion >= VK_API_VERSION_1_1 || multiiView) { + VkPhysicalDeviceMultiviewFeaturesKHR multiView = {0}; + multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &multiView; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (multiView.multiview) { + adapterFeatures |= PAL_ADAPTER_FEATURE_MULTI_VIEW; } } + // clang-format on VkPhysicalDeviceFeatures features; s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); // check for additional features if (features.multiViewport) { - caps->features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; + adapterFeatures |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; } if (features.samplerAnisotropy) { - caps->features |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; + adapterFeatures |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; } if (features.sampleRateShading) { - caps->features |= PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING; + adapterFeatures |= PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING; } if (features.shaderFloat64) { - caps->features |= PAL_ADAPTER_FEATURE_SHADER_FLOAT64; + adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_FLOAT64; } if (features.shaderInt64) { - caps->features |= PAL_ADAPTER_FEATURE_SHADER_INT64; + adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_INT64; } if (features.shaderInt16) { - caps->features |= PAL_ADAPTER_FEATURE_SHADER_INT16; + adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_INT16; } if (features.geometryShader) { - caps->features |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; + adapterFeatures |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; } if (features.tessellationShader) { - caps->features |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; + adapterFeatures |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; } if (dynamicRendering) { - caps->features |= PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING; } if (features.fillModeNonSolid) { - caps->features |= PAL_ADAPTER_FEATURE_LINE_POLYGON_MODE; + adapterFeatures |= PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE; } // this features are supported on vulkan - caps->features |= PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW; - caps->features |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; - caps->features |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE; - caps->features |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT; - caps->features |= PAL_ADAPTER_FEATURE_RESET_FENCE; - caps->features |= PAL_ADAPTER_FEATURE_TIMEOUT_FENCE; - caps->features |= PAL_ADAPTER_FEATURE_SEMAPHORE; + adapterFeatures |= PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW; + adapterFeatures |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; + adapterFeatures |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE; + adapterFeatures |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT; + adapterFeatures |= PAL_ADAPTER_FEATURE_RESET_FENCE; + adapterFeatures |= PAL_ADAPTER_FEATURE_TIMEOUT_FENCE; + adapterFeatures |= PAL_ADAPTER_FEATURE_SEMAPHORE; palFree(s_Vk.allocator, extensionProps); return PAL_RESULT_SUCCESS; @@ -2139,7 +2150,7 @@ PalResult PAL_CALL createVkDevice( start = &mesh; } - if (features & PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING) { + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { extensions[extCount++] = "VK_KHR_fragment_shading_rate"; vrs.pipelineFragmentShadingRate = true; diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 60a50c23..8a9e1a81 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -2,34 +2,6 @@ #include "pal/pal_graphics.h" #include "tests.h" -static Uint32 getSampleCount(PalSampleCount sampleCount) -{ - switch (sampleCount) { - case PAL_SAMPLE_COUNT_1: - return 1; - - case PAL_SAMPLE_COUNT_2: - return 2; - - case PAL_SAMPLE_COUNT_4: - return 4; - - case PAL_SAMPLE_COUNT_8: - return 8; - - case PAL_SAMPLE_COUNT_16: - return 16; - - case PAL_SAMPLE_COUNT_32: - return 32; - - case PAL_SAMPLE_COUNT_64: - return 64; - } - - return 1; -} - bool graphicsTest() { palLog(nullptr, ""); @@ -79,7 +51,7 @@ bool graphicsTest() // get information about all the adapters PalAdapterInfo info; - PalAdapterCapabilities caps; + PalAdapterFeatures features = 0; for (Int32 i = 0; i < count; i++) { PalAdapter* adapter = adapters[i]; result = palGetAdapterInfo(adapter, &info); @@ -90,13 +62,7 @@ bool graphicsTest() return false; } - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); - palFree(nullptr, adapters); - return false; - } + result = palGetAdapterFeatures(adapter); Uint32 vramGb = info.vram / (1024.0 * 1024.0 * 1024.0); Uint32 sharedMemGb = info.sharedMemory / (1024.0 * 1024.0 * 1024.0); @@ -203,145 +169,105 @@ bool graphicsTest() palLog(nullptr, " PPM"); } - const char* boolToString; - if (caps.debugLayer) { - boolToString = "True"; - } else { - boolToString = "False"; - } - - palLog(nullptr, " Debug Layer: %s", boolToString); - - // clang-format off - - Uint32 colorSampleCount = getSampleCount(caps.maxColorSampleCount); - Uint32 depthSampleCount = getSampleCount(caps.maxDepthSampleCount); - - Uint32 uniformBufferSize = caps.maxUniformBufferSize / 1024; - Uint32 storageBufferSize = caps.maxStorageBufferSize / 1024; - Uint32 pushConstantSize = caps.maxStorageBufferSize / 1024; - - palLog(nullptr, " Max compute queues: %d", caps.maxComputeQueues); - palLog(nullptr, " Max graphics queues: %d", caps.maxGraphicsQueues); - palLog(nullptr, " Max copy queues: %d", caps.maxCopyQueues); - - palLog(nullptr, " Max image width: %d", caps.maxImageWidth); - palLog(nullptr, " Max image height: %d", caps.maxImageHeight); - palLog(nullptr, " Max image depth: %d", caps.maxImageDepth); - palLog(nullptr, " Max image array layers: %d", caps.maxImageArrayLayers); - palLog(nullptr, " Max image mip levels: %d", caps.maxImageMipLevels); - - palLog(nullptr, " Max color samples: %d", colorSampleCount); - palLog(nullptr, " Max depth samples: %d", depthSampleCount); - palLog(nullptr, " Max color attachment: %d", caps.maxColorAttachments); - palLog(nullptr, " Max multi views: %d", caps.maxMultiViews); - palLog(nullptr, " Max viewports: %d", caps.maxViewports); - palLog(nullptr, " Max samplers: %d", caps.maxSamplers); - palLog(nullptr, " Max uniform buffer size: %dKB", uniformBufferSize); - palLog(nullptr, " Max storage buffer size: %dKB", storageBufferSize); - palLog(nullptr, " Max push constant size: %dKB", pushConstantSize); - - // clang-format on - // features palLog(nullptr, " Supported Features:"); - if (caps.features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { + if (features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { palLog(nullptr, " Sampler Anisotropy"); } - if (caps.features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { + if (features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { palLog(nullptr, " Sample rate shading"); } - if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { + if (features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { palLog(nullptr, " Multi viewport"); } - if (caps.features & PAL_ADAPTER_FEATURE_SEMAPHORE) { + if (features & PAL_ADAPTER_FEATURE_SEMAPHORE) { palLog(nullptr, " Semaphore"); } - if (caps.features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { palLog(nullptr, " Timeline Semaphore"); } - if (caps.features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { + if (features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { palLog(nullptr, " Tesselation Shader"); } - if (caps.features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { + if (features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { palLog(nullptr, " Geometry shader"); } - if (caps.features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { + if (features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { palLog(nullptr, " Compute shader"); } - if (caps.features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { + if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { palLog(nullptr, " Shader float16"); } - if (caps.features & PAL_ADAPTER_FEATURE_SHADER_FLOAT64) { + if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT64) { palLog(nullptr, " Shader float64"); } - if (caps.features & PAL_ADAPTER_FEATURE_SHADER_INT16) { + if (features & PAL_ADAPTER_FEATURE_SHADER_INT16) { palLog(nullptr, " Shader int16"); } - if (caps.features & PAL_ADAPTER_FEATURE_SHADER_INT64) { + if (features & PAL_ADAPTER_FEATURE_SHADER_INT64) { palLog(nullptr, " Shader int64"); } - if (caps.features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { palLog(nullptr, " Ray tracing"); } - if (caps.features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { palLog(nullptr, " Mesh shader"); } - if (caps.features & PAL_ADAPTER_FEATURE_VARIABLE_RATE_SHADING) { - palLog(nullptr, " Variable rate rendering"); + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { + palLog(nullptr, " Fragment rendering rate"); } - if (caps.features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { palLog(nullptr, " Descriptor indexing"); } - if (caps.features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { + if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { palLog(nullptr, " Swapchain"); } - if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { + if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { palLog(nullptr, " Multiview"); } - if (caps.features & PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW) { + if (features & PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW) { palLog(nullptr, " Cube array image view type"); } - if (caps.features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { palLog(nullptr, " Dynamic rendering"); } - if (caps.features & PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE) { + if (features & PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE) { palLog(nullptr, " Resettable command pool"); } - if (caps.features & PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT) { + if (features & PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT) { palLog(nullptr, " Transient command pool"); } - if (caps.features & PAL_ADAPTER_FEATURE_RESET_FENCE) { + if (features & PAL_ADAPTER_FEATURE_RESET_FENCE) { palLog(nullptr, " Resetting fence"); } - if (caps.features & PAL_ADAPTER_FEATURE_TIMEOUT_FENCE) { + if (features & PAL_ADAPTER_FEATURE_TIMEOUT_FENCE) { palLog(nullptr, " Timeout fence"); } - if (caps.features & PAL_ADAPTER_FEATURE_LINE_POLYGON_MODE) { - palLog(nullptr, " Line Polygon Mode"); + if (features & PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE) { + palLog(nullptr, " Polygon mode line"); } palLog(nullptr, ""); From cf7eb8e4ed1412900340c6f7e272226a4004ae02 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 19 Dec 2025 12:42:07 +0000 Subject: [PATCH 052/372] remove pal begin and end rendering function --- CHANGELOG.md | 3 +- include/pal/pal_graphics.h | 27 ++-- src/graphics/pal_graphics.c | 49 +------ src/graphics/pal_vulkan.c | 247 +++++++++++++++++------------------- tests/clear_color_test.c | 14 -- tests/graphics_test.c | 44 +++++-- tests/tests_main.c | 2 +- 7 files changed, 167 insertions(+), 219 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4384b307..94aa7032 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -157,5 +157,4 @@ palJoinThread(thread, &retval); ### Notes - No API or ABI changes - existing code remains compatible. -- Safe upgrade from **v1.3.0** - just rebuild your project after updating. -- The graphics system supports both legacy and dynamic rendering on vulkan. \ No newline at end of file +- Safe upgrade from **v1.3.0** - just rebuild your project after updating. \ No newline at end of file diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 04455103..17bcfbaa 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -227,13 +227,18 @@ typedef enum { PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(15), PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(16), PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(17), - PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW = PAL_BIT64(18), - PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING = PAL_BIT64(19), - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(20), - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(21), - PAL_ADAPTER_FEATURE_RESET_FENCE = PAL_BIT64(22), - PAL_ADAPTER_FEATURE_TIMEOUT_FENCE = PAL_BIT64(23), - PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE = PAL_BIT64(24) + PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY = PAL_BIT64(18), + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(19), + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(20), + PAL_ADAPTER_FEATURE_FENCE_RESET = PAL_BIT64(21), + PAL_ADAPTER_FEATURE_FENCE_TIMEOUT = PAL_BIT64(22), + PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE = PAL_BIT64(23), + PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE = PAL_BIT64(24), + PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE = PAL_BIT64(25), + PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY = PAL_BIT64(26), + PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE = PAL_BIT64(27), + PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(28), + PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(29) } PalAdapterFeatures; typedef enum { @@ -842,10 +847,6 @@ typedef struct { void PAL_CALL (*destroyCommandBuffer)(PalCommandBuffer* cmdBuffer); - PalResult PAL_CALL (*beginRendering)(PalCommandBuffer* cmdBuffer); - - PalResult PAL_CALL (*endRendering)(PalCommandBuffer* cmdBuffer); - PalResult PAL_CALL (*executeCommandBuffer)( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -1062,10 +1063,6 @@ PAL_API PalResult PAL_CALL palCreateCommandBuffer( PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); -PAL_API PalResult PAL_CALL palBeginRendering(PalCommandBuffer* cmdBuffer); - -PAL_API PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer); - PAL_API PalResult PAL_CALL palExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 74d9f21e..a816d7bc 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -309,10 +309,6 @@ PalResult PAL_CALL createVkCommandBuffer( void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); -PalResult PAL_CALL beginRenderingVk(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL endRenderingVk(PalCommandBuffer* cmdBuffer); - PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -383,8 +379,6 @@ static PalGraphicsBackend s_VkBackend = { .destroyCommandPool = destroyVkCommandPool, .createCommandBuffer = createVkCommandBuffer, .destroyCommandBuffer = destroyVkCommandBuffer, - .beginRendering = beginRenderingVk, - .endRendering = endRenderingVk, .executeCommandBuffer = executeCommandBufferVk, .beginRenderPass = beginRenderPassVk, .endRenderPass = endRenderPassVk, @@ -473,11 +467,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroyCommandPool || !backend->createCommandBuffer || !backend->destroyCommandBuffer || - !backend->beginRendering || - !backend->endRendering || !backend->beginRenderPass || !backend->endRenderPass || - !backend->endRendering || !backend->createGraphicsPipeline || !backend->destroyPipeline || !backend->submitCommandBuffer || @@ -666,12 +657,12 @@ PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) } if (!adapter) { - return PAL_RESULT_NULL_POINTER; + return 0; } HandleData* data = (HandleData*)adapter; if (data->type != HANDLE_TYPE_ADAPTER) { - return PAL_RESULT_INVALID_ADAPTER; + return 0; } return data->backend->getAdapterFeatures(data->handle); @@ -1936,42 +1927,6 @@ void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) } } -PalResult PAL_CALL palBeginRendering(PalCommandBuffer* cmdBuffer) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = (HandleData*)cmdBuffer; - if (data->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - return data->backend->beginRendering(data->handle); -} - -PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = (HandleData*)cmdBuffer; - if (data->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - return data->backend->endRendering(data->handle); -} - PalResult PAL_CALL palExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 37c840d0..06f00d26 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -89,7 +89,6 @@ typedef struct { PFN_vkEnumerateDeviceExtensionProperties enumerateDeviceExtensionProperties; PFN_vkGetPhysicalDeviceFeatures getPhysicalDeviceFeatures; PFN_vkGetPhysicalDeviceFeatures2 getPhysicalDeviceFeatures2; - PFN_vkGetPhysicalDeviceFeatures2KHR getPhysicalDeviceFeatures2KHR; PFN_vkGetInstanceProcAddr getInstanceProcAddr; PFN_vkCreateImageView createImageView; PFN_vkDestroyImageView destroyImageView; @@ -1421,9 +1420,8 @@ PalResult PAL_CALL initGraphicsVk( // clang-format off if (versionFallback) { - s_Vk.getPhysicalDeviceFeatures2KHR = nullptr; // load get physical device properties2 proc if we are on version 1.0 - s_Vk.getPhysicalDeviceFeatures2KHR = + s_Vk.getPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2KHR)s_Vk.getInstanceProcAddr( s_Vk.handle, "vkGetPhysicalDeviceFeatures2KHR"); @@ -1734,7 +1732,6 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) // check extensions bool rayTracingFound = false; bool accelerateFound = false; - bool dynamicRendering = false; bool meshShader = false; bool fragmentRateShading = false; bool timelineSemaphore = false; @@ -1752,9 +1749,6 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } else if (strcmp(props->extensionName, "VK_KHR_acceleration_structure") == 0) { accelerateFound = true; - } else if (strcmp(props->extensionName, "VK_KHR_dynamic_rendering") == 0) { - dynamicRendering = true; - } else if (strcmp(props->extensionName, "VK_EXT_mesh_shader") == 0) { meshShader = true; @@ -1775,6 +1769,16 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } else if (strcmp(props->extensionName, "VK_KHR_multiview") == 0) { multiiView = true; + + } else if (strcmp(props->extensionName, "VK_EXT_extended_dynamic_state") == 0) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY; + + } else if (strcmp(props->extensionName, "VK_EXT_extended_dynamic_state2") == 0) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP; } } @@ -1800,21 +1804,6 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } } - // dynamic rendering is part of core 1.3 - if (props.apiVersion >= VK_API_VERSION_1_3 || dynamicRendering) { - VkPhysicalDeviceDynamicRenderingFeaturesKHR dyn; - dyn.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &dyn; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (dyn.dynamicRendering) { - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING; - } - } - // mesh shader is part of core 1.3 if (props.apiVersion >= VK_API_VERSION_1_3 || meshShader) { VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; @@ -1942,25 +1931,21 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; } - if (dynamicRendering) { - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING; - } - if (features.fillModeNonSolid) { adapterFeatures |= PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE; } // this features are supported on vulkan - adapterFeatures |= PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW; + adapterFeatures |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; adapterFeatures |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; adapterFeatures |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE; adapterFeatures |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT; - adapterFeatures |= PAL_ADAPTER_FEATURE_RESET_FENCE; - adapterFeatures |= PAL_ADAPTER_FEATURE_TIMEOUT_FENCE; + adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; + adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_TIMEOUT; adapterFeatures |= PAL_ADAPTER_FEATURE_SEMAPHORE; palFree(s_Vk.allocator, extensionProps); - return PAL_RESULT_SUCCESS; + return adapterFeatures; } // ================================================== @@ -1976,8 +1961,11 @@ PalResult PAL_CALL createVkDevice( Uint32 count = 0; VkResult ret = VK_SUCCESS; PalDevice* device = nullptr; + VkPhysicalDeviceProperties props = {0}; VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + s_Vk.getPhysicalDeviceProperties(phyDevice, &props); + VkQueueFamilyProperties* queueProps = nullptr; VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; s_Vk.getPhysicalDeviceQueueFamilyProperties( @@ -2096,20 +2084,21 @@ PalResult PAL_CALL createVkDevice( extensions[extCount++] = "VK_KHR_swapchain"; } - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { - extensions[extCount++] = "VK_KHR_dynamic_rendering"; - } - if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - extensions[extCount++] = "VK_KHR_timeline_semaphore"; + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_timeline_semaphore"; + } + timeline.timelineSemaphore = true; start = &timeline; } if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { - extensions[extCount++] = "VK_KHR_shader_float16_int8"; - shader16.shaderFloat16 = true; + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_shader_float16_int8"; + } + shader16.shaderFloat16 = true; if (timeline.timelineSemaphore) { timeline.pNext = &shader16; } @@ -2117,11 +2106,13 @@ PalResult PAL_CALL createVkDevice( } if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; - extensions[extCount++] = "VK_KHR_acceleration_structure"; + if (props.apiVersion < VK_API_VERSION_1_3) { + extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; + extensions[extCount++] = "VK_KHR_acceleration_structure"; + } + ray.rayTracingPipeline = true; acc.accelerationStructure = true; - if (shader16.shaderFloat16) { shader16.pNext = &ray; @@ -2134,10 +2125,12 @@ PalResult PAL_CALL createVkDevice( } if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { - extensions[extCount++] = "VK_EXT_mesh_shader"; + if (props.apiVersion < VK_API_VERSION_1_3) { + extensions[extCount++] = "VK_EXT_mesh_shader"; + } + mesh.meshShader = true; mesh.taskShader = true; - if (acc.accelerationStructure) { acc.pNext = &mesh; @@ -2151,9 +2144,11 @@ PalResult PAL_CALL createVkDevice( } if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { - extensions[extCount++] = "VK_KHR_fragment_shading_rate"; - vrs.pipelineFragmentShadingRate = true; + if (props.apiVersion < VK_API_VERSION_1_3) { + extensions[extCount++] = "VK_KHR_fragment_shading_rate"; + } + vrs.pipelineFragmentShadingRate = true; if (mesh.meshShader) { mesh.pNext = &vrs; @@ -2170,9 +2165,11 @@ PalResult PAL_CALL createVkDevice( } if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - extensions[extCount++] = "VK_EXT_descriptor_indexing"; - descIndex.shaderSampledImageArrayNonUniformIndexing = true; + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_EXT_descriptor_indexing"; + } + descIndex.shaderSampledImageArrayNonUniformIndexing = true; if (vrs.pipelineFragmentShadingRate) { vrs.pNext = &descIndex; @@ -2192,9 +2189,11 @@ PalResult PAL_CALL createVkDevice( } if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { - extensions[extCount++] = "VK_KHR_multiview"; - multiView.multiview = true; + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_multiview"; + } + multiView.multiview = true; if (descIndex.shaderSampledImageArrayNonUniformIndexing) { descIndex.pNext = &multiView; @@ -2738,7 +2737,7 @@ PalResult PAL_CALL createVkImageView( { // mimic the actual requested features at device creation if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - if (!(device->features & PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW)) { + if (!(device->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } @@ -3368,62 +3367,60 @@ PalResult PAL_CALL createVkRenderPass( } } - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING)) { - // subpass - VkSubpassDescription subpassDesc = {0}; - subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDesc.colorAttachmentCount = colorRefCount; - subpassDesc.pColorAttachments = colorRefs; - if (renderpass->hasDepth) { - subpassDesc.pDepthStencilAttachment = &depthRef; - } + // subpass + VkSubpassDescription subpassDesc = {0}; + subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDesc.colorAttachmentCount = colorRefCount; + subpassDesc.pColorAttachments = colorRefs; + if (renderpass->hasDepth) { + subpassDesc.pDepthStencilAttachment = &depthRef; + } - // render pass - VkRenderPassCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - createInfo.attachmentCount = info->attachmentCount; - createInfo.pAttachments = attachments; - createInfo.subpassCount = 1; - createInfo.pSubpasses = &subpassDesc; + // render pass + VkRenderPassCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + createInfo.attachmentCount = info->attachmentCount; + createInfo.pAttachments = attachments; + createInfo.subpassCount = 1; + createInfo.pSubpasses = &subpassDesc; - result = s_Vk.createRenderPass( - device->handle, - &createInfo, - &s_Vk.vkAllocator, - &renderpass->handle); + result = s_Vk.createRenderPass( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &renderpass->handle); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, renderpass); - return vkResultToPal(result); - } + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, renderpass); + return vkResultToPal(result); + } - // create framebuffer - VkFramebufferCreateInfo fbCreateInfo = {0}; - fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fbCreateInfo.attachmentCount = info->attachmentCount; - fbCreateInfo.pAttachments = views; - fbCreateInfo.height = info->height; - fbCreateInfo.width = info->width; - fbCreateInfo.layers = layers; - fbCreateInfo.renderPass = renderpass->handle; + // create framebuffer + VkFramebufferCreateInfo fbCreateInfo = {0}; + fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fbCreateInfo.attachmentCount = info->attachmentCount; + fbCreateInfo.pAttachments = views; + fbCreateInfo.height = info->height; + fbCreateInfo.width = info->width; + fbCreateInfo.layers = layers; + fbCreateInfo.renderPass = renderpass->handle; - result = s_Vk.createFramebuffer( + result = s_Vk.createFramebuffer( + device->handle, + &fbCreateInfo, + &s_Vk.vkAllocator, + &renderpass->framebuffer); + + if (result != VK_SUCCESS) { + s_Vk.destroyRenderPass( device->handle, - &fbCreateInfo, - &s_Vk.vkAllocator, - &renderpass->framebuffer); + renderpass->handle, + &s_Vk.vkAllocator); - if (result != VK_SUCCESS) { - s_Vk.destroyRenderPass( - device->handle, - renderpass->handle, - &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, renderpass); - // legacy rendering needs all image views to have - // the same layers/width/height - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + palFree(s_Vk.allocator, renderpass); + // legacy rendering needs all image views to have + // the same layers/width/height + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } renderpass->device = device; @@ -3508,7 +3505,7 @@ PalResult PAL_CALL waitVkFence( PalResult PAL_CALL resetVkFence(PalFence* fence) { - if (!(fence->device->features & PAL_ADAPTER_FEATURE_RESET_FENCE)) { + if (!(fence->device->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3757,27 +3754,6 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) palFree(s_Vk.allocator, cmdBuffer); } -PalResult PAL_CALL beginRenderingVk(PalCommandBuffer* cmdBuffer) -{ - VkCommandBufferBeginInfo beginInfo = {0}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - VkResult result = s_Vk.cmdBegin(cmdBuffer->handle, &beginInfo); - if (result != VK_SUCCESS) { - return vkResultToPal(result); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL endRenderingVk(PalCommandBuffer* cmdBuffer) -{ - VkResult result = s_Vk.cmdEnd(cmdBuffer->handle); - if (result != VK_SUCCESS) { - return vkResultToPal(result); - } - return PAL_RESULT_SUCCESS; -} - PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) @@ -3813,8 +3789,16 @@ PalResult PAL_CALL beginRenderPassVk( return PAL_RESULT_INSUFFICIENT_BUFFER; } - VkRenderPassBeginInfo beginInfo = {0}; - beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + VkCommandBufferBeginInfo cmdBeginInfo = {0}; + cmdBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + VkResult result = s_Vk.cmdBegin(cmdBuffer->handle, &cmdBeginInfo); + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + VkRenderPassBeginInfo renderPassBeginInfo = {0}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; VkClearValue tmp[MAX_ATTACHMENTS]; for (int i = 0; i < clearValueCount; i++) { @@ -3833,16 +3817,16 @@ PalResult PAL_CALL beginRenderPassVk( } } - beginInfo.clearValueCount = clearValueCount; - beginInfo.pClearValues = tmp; - beginInfo.framebuffer = renderPass->framebuffer; - beginInfo.renderPass = renderPass->handle; - beginInfo.renderArea.extent.width = renderPass->width; - beginInfo.renderArea.extent.height = renderPass->height; + renderPassBeginInfo.clearValueCount = clearValueCount; + renderPassBeginInfo.pClearValues = tmp; + renderPassBeginInfo.framebuffer = renderPass->framebuffer; + renderPassBeginInfo.renderPass = renderPass->handle; + renderPassBeginInfo.renderArea.extent.width = renderPass->width; + renderPassBeginInfo.renderArea.extent.height = renderPass->height; s_Vk.cmdBeginRenderPass( cmdBuffer->handle, - &beginInfo, + &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); return PAL_RESULT_SUCCESS; @@ -3850,6 +3834,11 @@ PalResult PAL_CALL beginRenderPassVk( PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer) { + VkResult result = s_Vk.cmdEnd(cmdBuffer->handle); + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + s_Vk.cmdEndRenderPass(cmdBuffer->handle); return PAL_RESULT_SUCCESS; } diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 2193cd16..e3e4c181 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -322,13 +322,6 @@ bool clearColorTest() clearValue.color[2] = 0.2f; clearValue.color[3] = 1.0f; - result = palBeginRendering(cmdBuffer); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin rendering: %s", error); - return false; - } - result = palBeginRenderPass(cmdBuffer, renderPass, 1, &clearValue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -342,13 +335,6 @@ bool clearColorTest() palLog(nullptr, "Failed to end render pass: %s", error); return false; } - - result = palEndRendering(cmdBuffer); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end rendering: %s", error); - return false; - } // cache everything so we can reference and destroy later renderPasses[i] = renderPass; diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 8a9e1a81..59237e4b 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -62,8 +62,7 @@ bool graphicsTest() return false; } - result = palGetAdapterFeatures(adapter); - + features = palGetAdapterFeatures(adapter); Uint32 vramGb = info.vram / (1024.0 * 1024.0 * 1024.0); Uint32 sharedMemGb = info.sharedMemory / (1024.0 * 1024.0 * 1024.0); @@ -144,6 +143,7 @@ bool graphicsTest() palLog(nullptr, " API Type: %s", apiTypeString); // shader formats + palLog(nullptr, ""); palLog(nullptr, " Supported Shader Formats:"); if (info.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { palLog(nullptr, " SPIRV"); @@ -170,6 +170,7 @@ bool graphicsTest() } // features + palLog(nullptr, ""); palLog(nullptr, " Supported Features:"); if (features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { palLog(nullptr, " Sampler Anisotropy"); @@ -214,6 +215,7 @@ bool graphicsTest() if (features & PAL_ADAPTER_FEATURE_SHADER_INT16) { palLog(nullptr, " Shader int16"); } + if (features & PAL_ADAPTER_FEATURE_SHADER_INT64) { palLog(nullptr, " Shader int64"); } @@ -223,7 +225,7 @@ bool graphicsTest() } if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { - palLog(nullptr, " Mesh shader"); + palLog(nullptr, " Mesh and task shader"); } if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { @@ -242,12 +244,8 @@ bool graphicsTest() palLog(nullptr, " Multiview"); } - if (features & PAL_ADAPTER_FEATURE_CUBE_ARRAY_IMAGE_VIEW) { - palLog(nullptr, " Cube array image view type"); - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_RENDERING) { - palLog(nullptr, " Dynamic rendering"); + if (features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY) { + palLog(nullptr, " Image view type Cube array"); } if (features & PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE) { @@ -258,17 +256,41 @@ bool graphicsTest() palLog(nullptr, " Transient command pool"); } - if (features & PAL_ADAPTER_FEATURE_RESET_FENCE) { + if (features & PAL_ADAPTER_FEATURE_FENCE_RESET) { palLog(nullptr, " Resetting fence"); } - if (features & PAL_ADAPTER_FEATURE_TIMEOUT_FENCE) { + if (features & PAL_ADAPTER_FEATURE_FENCE_TIMEOUT) { palLog(nullptr, " Timeout fence"); } if (features & PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE) { palLog(nullptr, " Polygon mode line"); } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { + palLog(nullptr, " Dynamic cull mode"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { + palLog(nullptr, " Dynamic front face"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { + palLog(nullptr, " Dynamic primitive topology"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { + palLog(nullptr, " Dynamic depth test enable"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { + palLog(nullptr, " Dynamic depth write enable"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { + palLog(nullptr, " Dynamic stencil op"); + } palLog(nullptr, ""); } diff --git a/tests/tests_main.c b/tests/tests_main.c index b8d7f6ac..5bf06fe6 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,7 +59,7 @@ int main(int argc, char** argv) #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest("Clear Color Test", clearColorTest); + // registerTest("Clear Color Test", clearColorTest); #endif // runTests(); From e3b21b8d8aea7818cf5ca2c5930e64fc4da5539d Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 19 Dec 2025 12:45:23 +0000 Subject: [PATCH 053/372] fix task and mesh shader vulkan bug --- include/pal/pal_graphics.h | 1 + src/graphics/pal_vulkan.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 17bcfbaa..45ef86bb 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -291,6 +291,7 @@ typedef enum { PAL_SHADER_TYPE_COMPUTE, PAL_SHADER_TYPE_GEOMETRY, PAL_SHADER_TYPE_MESH, + PAL_SHADER_TYPE_TASK, PAL_SHADER_TYPE_TESSELLATION_CONTROL, PAL_SHADER_TYPE_TESSELLATION_EVALUATION } PalShaderType; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 06f00d26..dbb5d680 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3234,10 +3234,16 @@ PalResult PAL_CALL createVkShader( stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; } else if (info->type == PAL_SHADER_TYPE_MESH) { - if (device->features & PAL_SHADER_TYPE_MESH) { + if (device->features & PAL_ADAPTER_FEATURE_MESH_SHADER) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_MESH_BIT_EXT; + + } else if (info->type == PAL_SHADER_TYPE_TASK) { + if (device->features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + stage = VK_SHADER_STAGE_TASK_BIT_EXT; } shader = palAllocate(s_Vk.allocator, sizeof(PalShader), 0); From eb130ea71ff7b8a979288e59af2a4c2351493a1b Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 19 Dec 2025 15:13:56 +0000 Subject: [PATCH 054/372] add depth stencil resolve modes --- include/pal/pal_graphics.h | 38 +++- src/graphics/pal_graphics.c | 215 ++++++++++++++++------- src/graphics/pal_vulkan.c | 336 +++++++++++++++++++++++++++--------- tests/clear_color_test.c | 2 +- tests/graphics_test.c | 6 +- tests/tests_main.c | 2 +- 6 files changed, 446 insertions(+), 153 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 45ef86bb..cf96a688 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -36,6 +36,7 @@ freely, subject to the following restrictions: #define PAL_ADAPTER_NAME_SIZE 128 #define PAL_ADAPTER_VERSION_SIZE 16 #define PAL_DEFAULT_MEMORY_OFFSET 0 +#define PAL_MAX_RESOLVE_MODES 8 typedef struct PalAdapter PalAdapter; typedef struct PalDevice PalDevice; @@ -238,7 +239,8 @@ typedef enum { PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY = PAL_BIT64(26), PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE = PAL_BIT64(27), PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(28), - PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(29) + PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(29), + PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(30) } PalAdapterFeatures; typedef enum { @@ -299,7 +301,8 @@ typedef enum { typedef enum { PAL_ATTACHMENT_TYPE_COLOR, PAL_ATTACHMENT_TYPE_DEPTH, - PAL_ATTACHMENT_TYPE_STENCIL + PAL_ATTACHMENT_TYPE_STENCIL, + PAL_ATTACHMENT_TYPE_DEPTH_STENCIL } PalAttachmentType; typedef enum { @@ -433,6 +436,14 @@ typedef enum { PAL_COLOR_MASK_ALPHA = PAL_BIT(3), } PalColorMask; +typedef enum { + PAL_RESOLVE_MODE_NONE = 0, + PAL_RESOLVE_MODE_SAMPLE_ZERO, + PAL_RESOLVE_MODE_AVERAGE, + PAL_RESOLVE_MODE_MIN, + PAL_RESOLVE_MODE_MAX +} PalResolveMode; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -471,6 +482,12 @@ typedef struct { Uint32 maxComputeWorkGroupSize[3]; } PalAdapterCapabilities; +typedef struct { + bool independentDepthStencilResolve; + bool depthResolveModes[PAL_MAX_RESOLVE_MODES]; + bool stencilResolveModes[PAL_MAX_RESOLVE_MODES]; +} PalDepthStencilCapabilities; + typedef struct { bool presentModes[PAL_PRESENT_MODE_MAX]; bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; @@ -510,6 +527,10 @@ typedef struct { PalAttachmentType type; PalLoadOp loadOp; PalStoreOp storeOp; + PalLoadOp stencilLoadOp; + PalStoreOp stencilStoreOp; + PalResolveMode resolveMode; + PalResolveMode stencilResolveMode; PalImageView* target; PalImageView* resolveTarget; } PalAttachmentDesc; @@ -661,6 +682,7 @@ typedef struct { PalShader* fragmentShader; PalShader* geometryShader; PalShader* meshShader; + PalShader* taskShader; PalShader* tessellationEvaluationShader; PalShader* tessellationControlShader; PalVertexLayout* vertexLayouts; @@ -702,6 +724,10 @@ typedef struct { PalDevice* device, PalMemory* memory); + PalResult PAL_CALL (*queryDepthStencilCapabilities)( + PalDevice* device, + PalDepthStencilCapabilities* caps); + PalResult PAL_CALL (*createQueue)( PalDevice* device, PalQueueType type, @@ -759,7 +785,7 @@ typedef struct { void PAL_CALL (*destroyImageView)(PalImageView* imageView); PalResult PAL_CALL (*querySwapchainCapabilities)( - PalAdapter* adapter, + PalDevice* device, PalGraphicsWindow* window, PalSwapchainCapabilities* caps); @@ -912,6 +938,10 @@ PAL_API void PAL_CALL palFreeMemory( PalDevice* device, PalMemory* memory); +PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( + PalDevice* device, + PalDepthStencilCapabilities* caps); + PAL_API PalResult PAL_CALL palCreateQueue( PalDevice* device, PalQueueType type, @@ -969,7 +999,7 @@ PAL_API PalResult PAL_CALL palCreateImageView( PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( - PalAdapter* adapter, + PalDevice* device, PalGraphicsWindow* window, PalSwapchainCapabilities* caps); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index a816d7bc..7fcd5907 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -60,6 +60,7 @@ typedef struct { bool shouldFree; HandleType type; Uint32 data2; + PalAdapterFeatures features; void* handle; void* data; const PalGraphicsBackend* backend; @@ -163,6 +164,10 @@ void PAL_CALL freeVkMemory( PalDevice* device, PalMemory* memory); +PalResult PAL_CALL queryVkDepthStencilCapabilities( + PalDevice* device, + PalDepthStencilCapabilities* caps); + PalResult PAL_CALL createVkQueue( PalDevice* device, PalQueueType type, @@ -220,7 +225,7 @@ PalResult PAL_CALL createVkImageView( void PAL_CALL destroyVkImageView(PalImageView* imageView); PalResult PAL_CALL queryVkSwapchainCapabilities( - PalAdapter* adapter, + PalDevice* device, PalGraphicsWindow* window, PalSwapchainCapabilities* caps); @@ -421,57 +426,58 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) // check if all the function pointers are set // clang-format off - if (!backend->enumerateAdapters || - !backend->getAdapterInfo || - !backend->getAdapterCapabilities || - !backend->getAdapterFeatures || - !backend->createDevice || - !backend->destroyDevice || - !backend->allocateMemory || - !backend->freeMemory || - !backend->createQueue || - !backend->destroyQueue || - !backend->canQueuePresent || - !backend->enumerateFormats || - !backend->isFormatSupported || - !backend->queryFormatImageUsages || - !backend->queryFormatImageViewUsages || - !backend->createImage || - !backend->destroyImage || - !backend->getImageInfo || - !backend->getImageMemoryRequirements || - !backend->bindImageMemory || - !backend->createImageView || - !backend->destroyImageView || - !backend->querySwapchainCapabilities || - !backend->createSwapchain || - !backend->destroySwapchain || - !backend->getSwapchainImage || - !backend->getNextSwapchainImage || - !backend->presentSwapchain || - !backend->createShader || - !backend->destroyShader || - !backend->createRenderPass || - !backend->destroyRenderPass || - !backend->createFence || - !backend->destroyFence || - !backend->waitFenceTimeout || - !backend->resetFence || - !backend->isFenceSignaled || - !backend->createSemaphore || - !backend->destroySemaphore || - !backend->waitSemaphore || - !backend->signalSemaphore || - !backend->getSemaphoreValue || - !backend->createCommandPool || - !backend->destroyCommandPool || - !backend->createCommandBuffer || - !backend->destroyCommandBuffer || - !backend->beginRenderPass || - !backend->endRenderPass || - !backend->createGraphicsPipeline || - !backend->destroyPipeline || - !backend->submitCommandBuffer || + if (!backend->enumerateAdapters || + !backend->getAdapterInfo || + !backend->getAdapterCapabilities || + !backend->queryDepthStencilCapabilities || + !backend->getAdapterFeatures || + !backend->createDevice || + !backend->destroyDevice || + !backend->allocateMemory || + !backend->freeMemory || + !backend->createQueue || + !backend->destroyQueue || + !backend->canQueuePresent || + !backend->enumerateFormats || + !backend->isFormatSupported || + !backend->queryFormatImageUsages || + !backend->queryFormatImageViewUsages || + !backend->createImage || + !backend->destroyImage || + !backend->getImageInfo || + !backend->getImageMemoryRequirements || + !backend->bindImageMemory || + !backend->createImageView || + !backend->destroyImageView || + !backend->querySwapchainCapabilities || + !backend->createSwapchain || + !backend->destroySwapchain || + !backend->getSwapchainImage || + !backend->getNextSwapchainImage || + !backend->presentSwapchain || + !backend->createShader || + !backend->destroyShader || + !backend->createRenderPass || + !backend->destroyRenderPass || + !backend->createFence || + !backend->destroyFence || + !backend->waitFenceTimeout || + !backend->resetFence || + !backend->isFenceSignaled || + !backend->createSemaphore || + !backend->destroySemaphore || + !backend->waitSemaphore || + !backend->signalSemaphore || + !backend->getSemaphoreValue || + !backend->createCommandPool || + !backend->destroyCommandPool || + !backend->createCommandBuffer || + !backend->destroyCommandBuffer || + !backend->beginRenderPass || + !backend->endRenderPass || + !backend->createGraphicsPipeline || + !backend->destroyPipeline || + !backend->submitCommandBuffer || !backend->submitCommandBuffer) { return PAL_RESULT_INVALID_BACKEND; } @@ -710,7 +716,7 @@ PalResult PAL_CALL palCreateDevice( deviceData->backend = adapterData->backend; deviceData->handle = device; deviceData->type = HANDLE_TYPE_DEVICE; - deviceData->data2 = features; + deviceData->features = features; *outDevice = (PalDevice*)deviceData; return PAL_RESULT_SUCCESS; @@ -766,6 +772,30 @@ void PAL_CALL palFreeMemory( } } +PalResult PAL_CALL palQueryDepthStencilCapabilities( + PalDevice* device, + PalDepthStencilCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)device; + if (data->type != HANDLE_TYPE_DEVICE) { + return PAL_RESULT_INVALID_DEVICE; + } + + if (!(data->features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + return data->backend->queryDepthStencilCapabilities(data->handle, caps); +} + // ================================================== // Queue // ================================================== @@ -808,6 +838,7 @@ PalResult PAL_CALL palCreateQueue( queueData->backend = deviceData->backend; queueData->handle = queue; queueData->type = HANDLE_TYPE_QUEUE; + queueData->features = deviceData->features; *outQueue = (PalQueue*)queueData; return PAL_RESULT_SUCCESS; @@ -957,6 +988,7 @@ PalResult PAL_CALL palCreateImage( imageData->handle = image; imageData->type = HANDLE_TYPE_IMAGE; imageData->data2 = 0; + imageData->features = data->features; *outImage = (PalImage*)imageData; return PAL_RESULT_SUCCESS; @@ -1098,6 +1130,7 @@ PalResult PAL_CALL palCreateImageView( imageViewData->backend = deviceData->backend; imageViewData->handle = imageView; imageViewData->type = HANDLE_TYPE_IMAGE_VIEW; + imageViewData->features = deviceData->features; *outImageView = (PalImageView*)imageViewData; return PAL_RESULT_SUCCESS; @@ -1119,7 +1152,7 @@ void PAL_CALL palDestroyImageView(PalImageView* imageView) // ================================================== PalResult PAL_CALL palQuerySwapchainCapabilities( - PalAdapter* adapter, + PalDevice* device, PalGraphicsWindow* window, PalSwapchainCapabilities* caps) { @@ -1127,13 +1160,17 @@ PalResult PAL_CALL palQuerySwapchainCapabilities( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!adapter || !window || !caps) { + if (!device || !window || !caps) { return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)adapter; - if (data->type != HANDLE_TYPE_ADAPTER) { - return PAL_RESULT_INVALID_ADAPTER; + HandleData* data = (HandleData*)device; + if (data->type != HANDLE_TYPE_DEVICE) { + return PAL_RESULT_INVALID_DEVICE; + } + + if (!(data->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } return data->backend->querySwapchainCapabilities( @@ -1208,6 +1245,7 @@ PalResult PAL_CALL palCreateSwapchain( tmp->data = nullptr; tmp->type = HANDLE_TYPE_IMAGE; tmp->data2 = SWAPCHAIN_IMAGE; + tmp->features = deviceData->features; } swapchainData->backend = deviceData->backend; @@ -1215,6 +1253,7 @@ PalResult PAL_CALL palCreateSwapchain( swapchainData->data = (void*)imagesData; swapchainData->data2 = info->imageCount; swapchainData->type = HANDLE_TYPE_SWAPCHAIN; + swapchainData->features = deviceData->features; *outSwapchain = (PalSwapchain*)swapchainData; return PAL_RESULT_SUCCESS; @@ -1383,15 +1422,40 @@ PalResult PAL_CALL palCreateShader( return PAL_RESULT_NULL_POINTER; } - if (info->type == PAL_SHADER_TYPE_UNDEFINED) { - return PAL_RESULT_INVALID_SHADER_TYPE; - } - HandleData* data = (HandleData*)device; if (data->type != HANDLE_TYPE_DEVICE) { return PAL_RESULT_INVALID_DEVICE; } + if (info->type == PAL_SHADER_TYPE_UNDEFINED) { + return PAL_RESULT_INVALID_SHADER_TYPE; + + } else if (info->type == PAL_SHADER_TYPE_COMPUTE) { + if (data->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_CONTROL) { + if (data->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_EVALUATION) { + if (data->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->type == PAL_SHADER_TYPE_MESH) { + if (data->features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->type == PAL_SHADER_TYPE_TASK) { + if (data->features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + // create a slot for the shader HandleData* shaderData = getFreeHandleData(); if (!shaderData) { @@ -1413,6 +1477,7 @@ PalResult PAL_CALL palCreateShader( shaderData->handle = shader; shaderData->type = HANDLE_TYPE_SHADER; shaderData->data2 = (Uint32)info->type; + shaderData->features = data->features; *outShader = (PalShader*)shaderData; return PAL_RESULT_SUCCESS; @@ -1487,8 +1552,13 @@ PalResult PAL_CALL palCreateRenderPass( attachments[i].target = tmp->handle; attachments[i].loadOp = info->attachments[i].loadOp; attachments[i].storeOp = info->attachments[i].storeOp; + attachments[i].stencilLoadOp = info->attachments[i].stencilLoadOp; + attachments[i].stencilStoreOp = info->attachments[i].stencilStoreOp; + attachments[i].resolveMode = info->attachments[i].resolveMode ; attachments[i].type = info->attachments[i].type; attachments[i].resolveTarget = nullptr; + attachments[i].stencilResolveMode = + info->attachments[i].stencilResolveMode; if (info->attachments[i].resolveTarget) { tmp = (HandleData*)info->attachments[i].resolveTarget; @@ -1519,6 +1589,7 @@ PalResult PAL_CALL palCreateRenderPass( renderPassData->backend = data->backend; renderPassData->handle = renderpass; renderPassData->type = HANDLE_TYPE_RENDER_PASS; + renderPassData->features = data->features; *outRenderPass = (PalRenderPass*)renderPassData; return PAL_RESULT_SUCCESS; @@ -1572,6 +1643,7 @@ PalResult PAL_CALL palCreateFence( fenceData->backend = data->backend; fenceData->handle = fence; fenceData->type = HANDLE_TYPE_FENCE; + fenceData->features = data->features; *outFence = (PalFence*)fenceData; return PAL_RESULT_SUCCESS; @@ -1623,6 +1695,10 @@ PalResult PAL_CALL palResetFence(PalFence* fence) return PAL_RESULT_INVALID_FENCE; } + if (!(data->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + return data->backend->resetFence(data->handle); } @@ -1674,9 +1750,10 @@ PalResult PAL_CALL palCreateSemaphore( semaphoreData->backend = data->backend; semaphoreData->handle = semaphore; semaphoreData->type = HANDLE_TYPE_SEMAPHORE; + semaphoreData->features = data->features; semaphoreData->data2 = BINARY_SEMAPHORE; - if (data->data2 & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + if (data->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { semaphoreData->data2 = TIMELINE_SEMAPHORE; } @@ -1850,6 +1927,7 @@ PalResult PAL_CALL palCreateCommandPool( poolData->backend = deviceData->backend; poolData->handle = pool; poolData->type = HANDLE_TYPE_COMMAND_POOL; + poolData->features = deviceData->features; *outPool = (PalCommandPool*)poolData; return PAL_RESULT_SUCCESS; @@ -1911,6 +1989,7 @@ PalResult PAL_CALL palCreateCommandBuffer( cmdBufferData->backend = data->backend; cmdBufferData->handle = cmdBuffer; cmdBufferData->type = HANDLE_TYPE_COMMAND_BUFFER; + cmdBufferData->features = data->features; *outCmdBuffer = (PalCommandBuffer*)cmdBufferData; return PAL_RESULT_SUCCESS; @@ -2101,6 +2180,7 @@ PalResult PAL_CALL palCreateGraphicsPipeline( void* fShaderHandle = nullptr; void* gShaderHandle = nullptr; void* mShaderHandle = nullptr; + void* taskShaderHandle = nullptr; void* tessEShaderHandle = nullptr; void* tessCShaderHandle = nullptr; @@ -2141,6 +2221,13 @@ PalResult PAL_CALL palCreateGraphicsPipeline( } } else { + // task shader + tmp = (HandleData*)info->taskShader; + if (tmp->type == HANDLE_TYPE_SHADER && + tmp->data2 == PAL_SHADER_TYPE_TASK) { + taskShaderHandle = tmp->handle; + } + // mesh shader tmp = (HandleData*)info->meshShader; if (tmp->type == HANDLE_TYPE_SHADER && @@ -2160,6 +2247,7 @@ PalResult PAL_CALL palCreateGraphicsPipeline( createInfo.fragmentShader = fShaderHandle; createInfo.geometryShader = gShaderHandle; createInfo.meshShader = mShaderHandle; + createInfo.taskShader = taskShaderHandle; createInfo.tessellationControlShader = tessCShaderHandle; createInfo.tessellationEvaluationShader = tessEShaderHandle; createInfo.vertexShader = vShaderHandle; @@ -2190,6 +2278,7 @@ PalResult PAL_CALL palCreateGraphicsPipeline( pipelineData->handle = pipeline; pipelineData->type = HANDLE_TYPE_PIPELINE; pipelineData->data2 = GRAPHICS_PIPELINE; + pipelineData->features = deviceData->features; *outPipeline = (PalPipeline*)pipelineData; return PAL_RESULT_SUCCESS; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index dbb5d680..bcaa5483 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -123,9 +123,6 @@ typedef struct { PFN_vkGetFenceStatus isFenceSignaled; PFN_vkCreateSemaphore createSemaphore; PFN_vkDestroySemaphore destroySemaphore; - PFN_vkWaitSemaphores waitSemaphores; - PFN_vkSignalSemaphore signalSemaphore; - PFN_vkGetSemaphoreCounterValue getSemaphoreValue; PFN_vkBeginCommandBuffer cmdBegin; PFN_vkEndCommandBuffer cmdEnd; @@ -170,6 +167,13 @@ struct PalDevice { PFN_vkGetSwapchainImagesKHR getSwapchainImages; PFN_vkAcquireNextImageKHR acquireNextImage; PFN_vkQueuePresentKHR queuePresent; + + // semaphore + PFN_vkCreateSemaphore createSemaphore; + PFN_vkDestroySemaphore destroySemaphore; + PFN_vkWaitSemaphores waitSemaphore; + PFN_vkSignalSemaphore signalSemaphore; + PFN_vkGetSemaphoreCounterValue getSemaphoreValue; }; struct PalQueue { @@ -1228,18 +1232,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroySemaphore"); - s_Vk.waitSemaphores = (PFN_vkWaitSemaphores)dlsym( - s_Vk.handle, - "vkWaitSemaphores"); - - s_Vk.signalSemaphore = (PFN_vkSignalSemaphore)dlsym( - s_Vk.handle, - "vkSignalSemaphore"); - - s_Vk.getSemaphoreValue = (PFN_vkGetSemaphoreCounterValue)dlsym( - s_Vk.handle, - "vkGetSemaphoreCounterValue"); - s_Vk.cmdBegin = (PFN_vkBeginCommandBuffer)dlsym( s_Vk.handle, "vkBeginCommandBuffer"); @@ -1738,6 +1730,7 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) bool descriptorIndexing = false; bool shaderFloat16 = false; bool multiiView = false; + bool dynamicstate = false; // clang-format off // check if the extensions are present @@ -1771,14 +1764,25 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) multiiView = true; } else if (strcmp(props->extensionName, "VK_EXT_extended_dynamic_state") == 0) { - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE; - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE; - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY; + dynamicstate = true; } else if (strcmp(props->extensionName, "VK_EXT_extended_dynamic_state2") == 0) { - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE; - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE; - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP; + VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynState2 = {0}; + dynState2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &dynState2; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (dynState2.extendedDynamicState2) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP; + } + + } else if (strcmp(props->extensionName, "VK_KHR_depth_stencil_resolve") == 0) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; } } @@ -1894,6 +1898,23 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } } + // dynamic state is part of core 1.3 + if (props.apiVersion >= VK_API_VERSION_1_3 || dynamicstate) { + VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynState = {0}; + dynState.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &dynState; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (dynState.extendedDynamicState) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY; + } + } + // clang-format on VkPhysicalDeviceFeatures features; s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); @@ -1988,6 +2009,7 @@ PalResult PAL_CALL createVkDevice( return PAL_RESULT_OUT_OF_MEMORY; } + memset(device, 0, sizeof(PalDevice)); device->queueCount = count; device->phyDevice = phyDevice; @@ -2078,12 +2100,23 @@ PalResult PAL_CALL createVkDevice( VkPhysicalDeviceMultiviewFeatures multiView = {0}; multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; + VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamicState = {0}; + dynamicState.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; + + VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynamicState2 = {0}; + dynamicState2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; + // clang-format on + bool coreSemaphore = false; if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { extensions[extCount++] = "VK_KHR_swapchain"; } + if (features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE) { + extensions[extCount++] = "VK_KHR_depth_stencil_resolve"; + } + if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_timeline_semaphore"; @@ -2091,6 +2124,7 @@ PalResult PAL_CALL createVkDevice( timeline.timelineSemaphore = true; start = &timeline; + coreSemaphore = true; } if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { @@ -2215,6 +2249,71 @@ PalResult PAL_CALL createVkDevice( start = &multiView; } + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE || + features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE || + features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { + if (props.apiVersion < VK_API_VERSION_1_3) { + extensions[extCount++] = "VK_EXT_extended_dynamic_state"; + } + + dynamicState.extendedDynamicState = true; + if (multiView.multiview) { + multiView.pNext = &dynamicState; + + } else if (descIndex.shaderSampledImageArrayNonUniformIndexing) { + descIndex.pNext = &dynamicState; + + } else if (vrs.pipelineFragmentShadingRate) { + vrs.pNext = &dynamicState; + + } else if (mesh.meshShader) { + mesh.pNext = &dynamicState; + + } else if (acc.accelerationStructure) { + acc.pNext = &dynamicState; + + } else if (shader16.shaderFloat16) { + shader16.pNext = &dynamicState; + + } else if (timeline.timelineSemaphore) { + timeline.pNext = &dynamicState; + } + start = &dynamicState; + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE || + features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE || + features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { + extensions[extCount++] = "VK_EXT_extended_dynamic_state2"; + dynamicState2.extendedDynamicState2 = true; + + if (dynamicState.extendedDynamicState) { + dynamicState.pNext = &dynamicState2; + + } else if (multiView.multiview) { + multiView.pNext = &dynamicState2; + + } else if (descIndex.shaderSampledImageArrayNonUniformIndexing) { + descIndex.pNext = &dynamicState2; + + } else if (vrs.pipelineFragmentShadingRate) { + vrs.pNext = &dynamicState2; + + } else if (mesh.meshShader) { + mesh.pNext = &dynamicState2; + + } else if (acc.accelerationStructure) { + acc.pNext = &dynamicState2; + + } else if (shader16.shaderFloat16) { + shader16.pNext = &dynamicState2; + + } else if (timeline.timelineSemaphore) { + timeline.pNext = &dynamicState2; + } + start = &dynamicState2; + } + VkDeviceCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pEnabledFeatures = &coreFeatures; @@ -2271,27 +2370,58 @@ PalResult PAL_CALL createVkDevice( } } - // load procs - device->createSwapchain = nullptr; - device->acquireNextImage = (PFN_vkAcquireNextImageKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkAcquireNextImageKHR"); + // load swapchain procs + if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { + device->acquireNextImage = (PFN_vkAcquireNextImageKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkAcquireNextImageKHR"); - device->createSwapchain = (PFN_vkCreateSwapchainKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCreateSwapchainKHR"); + device->createSwapchain = (PFN_vkCreateSwapchainKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateSwapchainKHR"); - device->destroySwapchain = (PFN_vkDestroySwapchainKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkDestroySwapchainKHR"); + device->destroySwapchain = (PFN_vkDestroySwapchainKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkDestroySwapchainKHR"); - device->getSwapchainImages = (PFN_vkGetSwapchainImagesKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetSwapchainImagesKHR"); + device->getSwapchainImages = (PFN_vkGetSwapchainImagesKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetSwapchainImagesKHR"); - device->queuePresent = (PFN_vkQueuePresentKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkQueuePresentKHR"); + device->queuePresent = (PFN_vkQueuePresentKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkQueuePresentKHR"); + } + + // load semaphore procs + if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + if (coreSemaphore) { + device->waitSemaphore = (PFN_vkWaitSemaphores)s_Vk.getDeviceProcAddr( + device->handle, + "vkWaitSemaphores"); + + device->signalSemaphore = (PFN_vkSignalSemaphore)s_Vk.getDeviceProcAddr( + device->handle, + "vkSignalSemaphore"); + + device->getSemaphoreValue = (PFN_vkGetSemaphoreCounterValue)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetSemaphoreCounterValue"); + + } else { + device->waitSemaphore = (PFN_vkWaitSemaphoresKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkWaitSemaphoresKHR"); + + device->signalSemaphore = (PFN_vkSignalSemaphoreKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkSignalSemaphoreKHR"); + + device->getSemaphoreValue = (PFN_vkGetSemaphoreCounterValueKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetSemaphoreCounterValueKHR"); + } + } device->features = features; palFree(s_Vk.allocator, queueProps); @@ -2359,6 +2489,60 @@ void PAL_CALL freeVkMemory( s_Vk.freeMemory(device->handle, mem, &s_Vk.vkAllocator); } +PalResult PAL_CALL queryVkDepthStencilCapabilities( + PalDevice* device, + PalDepthStencilCapabilities* caps) +{ + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + + VkPhysicalDeviceDepthStencilResolvePropertiesKHR props = {0}; + props.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR; + + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(device->phyDevice, &properties2); + + caps->independentDepthStencilResolve = props.independentResolve; + + if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { + caps->depthResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; + } + + if (props.supportedDepthResolveModes & + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { + caps->depthResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; + } + + if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_MIN_BIT_KHR) { + caps->depthResolveModes[PAL_RESOLVE_MODE_MIN] = true; + } + + if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { + caps->depthResolveModes[PAL_RESOLVE_MODE_MAX] = true; + } + + // stencil + if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { + caps->stencilResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; + } + + if (props.supportedStencilResolveModes & + VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { + caps->stencilResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; + } + + if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MIN_BIT_KHR) { + caps->stencilResolveModes[PAL_RESOLVE_MODE_MIN] = true; + } + + if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { + caps->stencilResolveModes[PAL_RESOLVE_MODE_MAX] = true; + } + + return PAL_RESULT_SUCCESS; +} + // ================================================== // Queue // ================================================== @@ -2735,13 +2919,6 @@ PalResult PAL_CALL createVkImageView( const PalImageViewCreateInfo* info, PalImageView** outImageView) { - // mimic the actual requested features at device creation - if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - if (!(device->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - VkResult result = VK_SUCCESS; PalImageView* imageView = nullptr; imageView = palAllocate(s_Vk.allocator, sizeof(PalImageView), 0); @@ -2809,7 +2986,7 @@ void PAL_CALL destroyVkImageView(PalImageView* imageView) // ================================================== PalResult PAL_CALL queryVkSwapchainCapabilities( - PalAdapter* adapter, + PalDevice* device, PalGraphicsWindow* window, PalSwapchainCapabilities* caps) { @@ -2818,7 +2995,7 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( VkSurfaceKHR surface = nullptr; VkSurfaceFormatKHR* formats = nullptr; VkPresentModeKHR* modes = nullptr; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)device->phyDevice; bool ret = createSurface(window, &surface); if (!ret) { @@ -2946,11 +3123,6 @@ PalResult PAL_CALL createVkSwapchain( VkImage* images = nullptr; PhysicalQueue* phyQueue = queue->phyQueue; - // check if we enabled swapchain feature - if (!device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - // check if the queue is a graphics queue before we check its family // index for presentation support. if (queue->usage != VK_QUEUE_GRAPHICS_BIT) { @@ -3216,33 +3388,18 @@ PalResult PAL_CALL createVkShader( stage = VK_SHADER_STAGE_FRAGMENT_BIT; } else if (info->type == PAL_SHADER_TYPE_COMPUTE) { - if (device->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } stage = VK_SHADER_STAGE_COMPUTE_BIT; } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_CONTROL) { - if (device->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_EVALUATION) { - if (device->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; } else if (info->type == PAL_SHADER_TYPE_MESH) { - if (device->features & PAL_ADAPTER_FEATURE_MESH_SHADER) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } stage = VK_SHADER_STAGE_MESH_BIT_EXT; } else if (info->type == PAL_SHADER_TYPE_TASK) { - if (device->features & PAL_ADAPTER_FEATURE_MESH_SHADER) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } stage = VK_SHADER_STAGE_TASK_BIT_EXT; } @@ -3321,13 +3478,11 @@ PalResult PAL_CALL createVkRenderPass( rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; rDesc->samples = vkSamplesToSamples(desc->target->image->info.sampleCount); rDesc->flags = 0; - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; layers = desc->target->image->info.depthOrArraySize; if (desc->resolveTarget) { - // on legacy rendering, this should make but PAL supports both - // so we use the highest on legacy rendering + // the layer count must be the same so to validate as well + // we use the highest from the attachments layers = desc->resolveTarget->image->info.depthOrArraySize; } @@ -3365,11 +3520,27 @@ PalResult PAL_CALL createVkRenderPass( } else { rDesc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - rDesc->stencilLoadOp = rDesc->loadOp; - rDesc->stencilStoreOp = rDesc->storeOp; depthRef.attachment = i; depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; renderpass->hasDepth = true; + + // stencil is only used with depth attachment + if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { + rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + + } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { + rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } } } @@ -3424,9 +3595,9 @@ PalResult PAL_CALL createVkRenderPass( &s_Vk.vkAllocator); palFree(s_Vk.allocator, renderpass); - // legacy rendering needs all image views to have - // the same layers/width/height - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + // all image views in a single render pass must have the same + // width/height/layers + return PAL_RESULT_INVALID_ARGUMENT; } renderpass->device = device; @@ -3511,10 +3682,6 @@ PalResult PAL_CALL waitVkFence( PalResult PAL_CALL resetVkFence(PalFence* fence) { - if (!(fence->device->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - VkResult ret = s_Vk.resetFence(fence->device->handle, 1, &fence->handle); if (ret != VK_SUCCESS) { return vkResultToPal(ret); @@ -3602,7 +3769,7 @@ PalResult PAL_CALL waitVkSemaphore( waitInfo.pSemaphores = &semaphore->handle; waitInfo.pValues = &value; - result = s_Vk.waitSemaphores( + result = semaphore->device->waitSemaphore( semaphore->device->handle, &waitInfo, timeout); @@ -3625,7 +3792,10 @@ PalResult PAL_CALL signalVkSemaphore( signalInfo.semaphore = semaphore->handle; signalInfo.value = value; - result = s_Vk.signalSemaphore(semaphore->device->handle, &signalInfo); + result = semaphore->device->signalSemaphore( + semaphore->device->handle, + &signalInfo); + if (result != VK_SUCCESS) { return vkResultToPal(result); } @@ -3637,7 +3807,7 @@ PalResult PAL_CALL getVkSemaphoreValue( PalSemaphore* semaphore, Uint64* value) { - VkResult result = s_Vk.getSemaphoreValue( + VkResult result = semaphore->device->getSemaphoreValue( semaphore->device->handle, semaphore->handle, value); diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index e3e4c181..3d667be7 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -167,7 +167,7 @@ bool clearColorTest() // create a swapchain with the graphics queue PalSwapchainCapabilities swapchainCaps = {0}; result = palQuerySwapchainCapabilities( - adapter, + device, &gfxWindow, &swapchainCaps); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 59237e4b..ffd696b9 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -291,7 +291,11 @@ bool graphicsTest() if (features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { palLog(nullptr, " Dynamic stencil op"); } - + + if (features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE) { + palLog(nullptr, " Depth stencil resolve"); + } + palLog(nullptr, ""); } diff --git a/tests/tests_main.c b/tests/tests_main.c index 5bf06fe6..b8d7f6ac 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,7 +59,7 @@ int main(int argc, char** argv) #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest("Clear Color Test", clearColorTest); + registerTest("Clear Color Test", clearColorTest); #endif // runTests(); From f053bc05878d43f1b18fcef4d896ef2b535ebae4 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 20 Dec 2025 09:04:07 +0000 Subject: [PATCH 055/372] add multi view render pass --- include/pal/pal_graphics.h | 1 + src/graphics/pal_vulkan.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index cf96a688..69119944 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -664,6 +664,7 @@ typedef struct { typedef struct { Uint32 width; Uint32 height; + Uint32 multiViewCount;; Uint32 attachmentCount; PalAttachmentDesc* attachments; } PalRenderPassCreateInfo; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index bcaa5483..7da603dd 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3553,6 +3553,13 @@ PalResult PAL_CALL createVkRenderPass( subpassDesc.pDepthStencilAttachment = &depthRef; } + // multi view + Uint32 viewMask = (1 << info->multiViewCount) - 1; + VkRenderPassMultiviewCreateInfo viewCreateInfo = {0}; + viewCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; + viewCreateInfo.pViewMasks = &viewMask; + viewCreateInfo.subpassCount = 1; + // render pass VkRenderPassCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; @@ -3561,6 +3568,10 @@ PalResult PAL_CALL createVkRenderPass( createInfo.subpassCount = 1; createInfo.pSubpasses = &subpassDesc; + if (info->multiViewCount > 1) { + createInfo.pNext = &viewCreateInfo; + } + result = s_Vk.createRenderPass( device->handle, &createInfo, From fa363d4738859d71c36981f6212d91f62ddf0730 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 20 Dec 2025 14:00:20 +0000 Subject: [PATCH 056/372] add fragment shading rate feature capabilities --- include/pal/pal_graphics.h | 41 ++++++++++++++++++++ src/graphics/pal_graphics.c | 33 ++++++++++++++++ src/graphics/pal_vulkan.c | 77 +++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 69119944..2661b003 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -37,6 +37,7 @@ freely, subject to the following restrictions: #define PAL_ADAPTER_VERSION_SIZE 16 #define PAL_DEFAULT_MEMORY_OFFSET 0 #define PAL_MAX_RESOLVE_MODES 8 +#define PAL_MAX_COMBINER_OPS 8 typedef struct PalAdapter PalAdapter; typedef struct PalDevice PalDevice; @@ -444,6 +445,26 @@ typedef enum { PAL_RESOLVE_MODE_MAX } PalResolveMode; +typedef enum { + PAL_FRAGMENT_SHADING_RATE_1X1, + PAL_FRAGMENT_SHADING_RATE_1X2, + PAL_FRAGMENT_SHADING_RATE_2X1, + PAL_FRAGMENT_SHADING_RATE_2X2, + PAL_FRAGMENT_SHADING_RATE_2X4, + PAL_FRAGMENT_SHADING_RATE_4X2, + PAL_FRAGMENT_SHADING_RATE_4X4, + + PAL_FRAGMENT_SHADING_RATE_MAX +} PalFragmentShadingRate; + +typedef enum { + PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP, + PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE, + PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN, + PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX, + PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL +} PalFragmentShadingRateCombinerOp; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -488,6 +509,11 @@ typedef struct { bool stencilResolveModes[PAL_MAX_RESOLVE_MODES]; } PalDepthStencilCapabilities; +typedef struct { + bool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; + bool combinerOps[PAL_MAX_COMBINER_OPS]; +} PalFragmentShadingRateCapabilities; + typedef struct { bool presentModes[PAL_PRESENT_MODE_MAX]; bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; @@ -624,6 +650,11 @@ typedef struct { PalBlendOp alphaBlendOp; } PalBlendAttachment; +typedef struct { + PalFragmentShadingRate rate; + PalFragmentShadingRateCombinerOp combinerOps[2]; +} PalFragmentShadingRateState; + typedef struct { Uint32 width; Uint32 height; @@ -676,6 +707,7 @@ typedef struct { } PalCommandPoolCreateInfo; typedef struct { + bool fragmentShadingRateEnabled; PalPrimitiveTopology topology; Uint32 vertexLayoutCount; Uint32 blendAttachmentCount; @@ -691,6 +723,7 @@ typedef struct { PalRasterizerState rasterizerState; PalMultisampleState multisampleState; PalDepthStencilState depthStencilState; + PalFragmentShadingRateState fragmentShadingRateState; } PalGraphicsPipelineCreateInfo; typedef struct { @@ -729,6 +762,10 @@ typedef struct { PalDevice* device, PalDepthStencilCapabilities* caps); + PalResult PAL_CALL (*queryFragmentShadingRateCapabilities)( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); + PalResult PAL_CALL (*createQueue)( PalDevice* device, PalQueueType type, @@ -943,6 +980,10 @@ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps); +PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); + PAL_API PalResult PAL_CALL palCreateQueue( PalDevice* device, PalQueueType type, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 7fcd5907..8d177a08 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -168,6 +168,10 @@ PalResult PAL_CALL queryVkDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps); +PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); + PalResult PAL_CALL createVkQueue( PalDevice* device, PalQueueType type, @@ -346,6 +350,8 @@ static PalGraphicsBackend s_VkBackend = { .destroyDevice = destroyVkDevice, .allocateMemory = allocateVkMemory, .freeMemory = freeVkMemory, + .queryDepthStencilCapabilities = queryVkDepthStencilCapabilities, + .queryFragmentShadingRateCapabilities = queryVkFragmentShadingRateCapabilities, .createQueue = createVkQueue, .destroyQueue = destroyVkQueue, .canQueuePresent = canVkQueuePresent, @@ -430,6 +436,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->getAdapterInfo || !backend->getAdapterCapabilities || !backend->queryDepthStencilCapabilities || + !backend->queryFragmentShadingRateCapabilities || !backend->getAdapterFeatures || !backend->createDevice || !backend->destroyDevice || @@ -796,6 +803,32 @@ PalResult PAL_CALL palQueryDepthStencilCapabilities( return data->backend->queryDepthStencilCapabilities(data->handle, caps); } +PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)device; + if (data->type != HANDLE_TYPE_DEVICE) { + return PAL_RESULT_INVALID_DEVICE; + } + + if (!(data->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + return data->backend->queryFragmentShadingRateCapabilities( + data->handle, + caps); +} + // ================================================== // Queue // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 7da603dd..f569b32a 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -174,6 +174,9 @@ struct PalDevice { PFN_vkWaitSemaphores waitSemaphore; PFN_vkSignalSemaphore signalSemaphore; PFN_vkGetSemaphoreCounterValue getSemaphoreValue; + + // fragment shading rate + PFN_vkCmdSetFragmentShadingRateKHR cmdSetFragmentShadingRate; }; struct PalQueue { @@ -992,6 +995,34 @@ static VkImageViewType palImageViewTypeToVk(PalImageViewType type) return VK_IMAGE_VIEW_TYPE_2D; } +static VkExtent2D getShadingRateSize(PalFragmentShadingRate rate) +{ + switch (rate) { + case PAL_FRAGMENT_SHADING_RATE_1X1: + return (VkExtent2D){1, 1}; + + case PAL_FRAGMENT_SHADING_RATE_1X2: + return (VkExtent2D){1, 2}; + + case PAL_FRAGMENT_SHADING_RATE_2X1: + return (VkExtent2D){2, 1}; + + case PAL_FRAGMENT_SHADING_RATE_2X2: + return (VkExtent2D){2, 2}; + + case PAL_FRAGMENT_SHADING_RATE_2X4: + return (VkExtent2D){2, 4}; + + case PAL_FRAGMENT_SHADING_RATE_4X2: + return (VkExtent2D){4, 2}; + + case PAL_FRAGMENT_SHADING_RATE_4X4: + return (VkExtent2D){4, 4}; + } + + return (VkExtent2D){0, 0}; +} + static void* vkAlloc( void* pUserData, size_t size, @@ -2423,6 +2454,14 @@ PalResult PAL_CALL createVkDevice( } } + // load fragment shading rate procs + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { + device->cmdSetFragmentShadingRate = + (PFN_vkCmdSetFragmentShadingRateKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdSetFragmentShadingRateKHR"); + } + device->features = features; palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); @@ -2543,6 +2582,44 @@ PalResult PAL_CALL queryVkDepthStencilCapabilities( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps) +{ + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + + VkPhysicalDeviceFragmentShadingRatePropertiesKHR props = {0}; + props.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; + + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(device->phyDevice, &properties2); + + memset(caps, 0, sizeof(PalFragmentShadingRateCapabilities)); + for (int i = 0; i < PAL_FRAGMENT_SHADING_RATE_MAX; i++) { + VkExtent2D size = getShadingRateSize((PalFragmentShadingRate)i); + + // clang-format off + // check against the max size + if (size.width <= props.maxFragmentSize.width || + size.height <= props.maxFragmentSize.height) { + caps->shadingRates[i] = true; + } + // clang-format on + } + + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP] = true; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE] = true; + if (props.fragmentShadingRateNonTrivialCombinerOps) { + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN] = true; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX] = true; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL] = true; + } + + return PAL_RESULT_SUCCESS; +} + // ================================================== // Queue // ================================================== From ef03cfd1fba1178912c0a53575c9687f139e874a Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 21 Dec 2025 12:56:40 +0000 Subject: [PATCH 057/372] add fragment shading rate attachment feature --- include/pal/pal_graphics.h | 15 +- src/graphics/pal_graphics.c | 7 + src/graphics/pal_vulkan.c | 420 ++++++++++++++++++++++++++++-------- tests/graphics_test.c | 4 + 4 files changed, 349 insertions(+), 97 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 2661b003..5635a214 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -198,7 +198,8 @@ typedef enum { PAL_IMAGE_VIEW_USAGE_UNDEFINED = 0, PAL_IMAGE_VIEW_USAGE_COLOR = PAL_BIT(0), PAL_IMAGE_VIEW_USAGE_DEPTH = PAL_BIT(1), - PAL_IMAGE_VIEW_USAGE_STENCIL = PAL_BIT(2) + PAL_IMAGE_VIEW_USAGE_STENCIL = PAL_BIT(2), + PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE = PAL_BIT(3) } PalImageViewUsages; typedef enum { @@ -241,7 +242,8 @@ typedef enum { PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE = PAL_BIT64(27), PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(28), PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(29), - PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(30) + PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(30), + PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(31) } PalAdapterFeatures; typedef enum { @@ -303,7 +305,8 @@ typedef enum { PAL_ATTACHMENT_TYPE_COLOR, PAL_ATTACHMENT_TYPE_DEPTH, PAL_ATTACHMENT_TYPE_STENCIL, - PAL_ATTACHMENT_TYPE_DEPTH_STENCIL + PAL_ATTACHMENT_TYPE_DEPTH_STENCIL, + PAL_ATTACHMENT_TYPE_FRAGMENT_SHADING_RATE } PalAttachmentType; typedef enum { @@ -511,6 +514,10 @@ typedef struct { typedef struct { bool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; + Uint32 minTexelWidth; + Uint32 minTexelHeight; + Uint32 maxTexelWidth; + Uint32 maxTexelHeight; bool combinerOps[PAL_MAX_COMBINER_OPS]; } PalFragmentShadingRateCapabilities; @@ -557,6 +564,8 @@ typedef struct { PalStoreOp stencilStoreOp; PalResolveMode resolveMode; PalResolveMode stencilResolveMode; + Uint32 texelWidth; + Uint32 texelHeight; PalImageView* target; PalImageView* resolveTarget; } PalAttachmentDesc; diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 8d177a08..8d6b7ebb 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -1577,6 +1577,13 @@ PalResult PAL_CALL palCreateRenderPass( return PAL_RESULT_NULL_POINTER; } + // clang-format of + if (info->attachments[i].type == PAL_ATTACHMENT_TYPE_FRAGMENT_SHADING_RATE) { + if (!(data->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + tmp = (HandleData*)info->attachments[i].target; if (tmp->type != HANDLE_TYPE_IMAGE_VIEW) { return PAL_RESULT_INVALID_IMAGE_VIEW; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index f569b32a..b57c440b 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -162,6 +162,8 @@ struct PalDevice { VkPhysicalDevice phyDevice; VkDevice handle; PhysicalQueue* phyQueues; + PFN_vkCreateRenderPass2 createRenderPass2; + PFN_vkCreateSwapchainKHR createSwapchain; PFN_vkDestroySwapchainKHR destroySwapchain; PFN_vkGetSwapchainImagesKHR getSwapchainImages; @@ -218,7 +220,6 @@ struct PalShader { }; struct PalRenderPass { - bool hasDepth; Uint32 attachmentCount; Uint32 width; Uint32 height; @@ -1867,6 +1868,11 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) if (frag.pipelineFragmentShadingRate) { adapterFeatures |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE; } + + if (frag.attachmentFragmentShadingRate) { + adapterFeatures |= + PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT; + } } // descriptor indexing is part of core 1.2 @@ -2208,12 +2214,21 @@ PalResult PAL_CALL createVkDevice( start = &mesh; } - if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { + if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || + (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_KHR_fragment_shading_rate"; + vrs.pipelineFragmentShadingRate = true; + + // fragment shading rate attachment needs this + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_create_renderpass2"; + } + vrs.attachmentFragmentShadingRate = true; + } } - vrs.pipelineFragmentShadingRate = true; if (mesh.meshShader) { mesh.pNext = &vrs; @@ -2459,7 +2474,24 @@ PalResult PAL_CALL createVkDevice( device->cmdSetFragmentShadingRate = (PFN_vkCmdSetFragmentShadingRateKHR)s_Vk.getDeviceProcAddr( device->handle, - "vkCmdSetFragmentShadingRateKHR"); + "vkCmdSetFragmentShadingRateKHR"); + + device->createRenderPass2 = (PFN_vkCreateRenderPass2)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateRenderPass2"); + } + + // load fragment shading rate attachment procs + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { + device->createRenderPass2 = (PFN_vkCreateRenderPass2)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateRenderPass2"); + + if (!device->createRenderPass2) { + device->createRenderPass2 = (PFN_vkCreateRenderPass2KHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateRenderPass2KHR"); + } } device->features = features; @@ -2617,6 +2649,14 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL] = true; } + VkExtent2D size = props.minFragmentShadingRateAttachmentTexelSize; + caps->minTexelWidth = size.width; + caps->minTexelHeight = size.height; + + size = props.maxFragmentShadingRateAttachmentTexelSize; + caps->maxTexelWidth = size.width; + caps->maxTexelHeight = size.height; + return PAL_RESULT_SUCCESS; } @@ -2760,6 +2800,12 @@ PalResult PAL_CALL enumerateVkFormats( usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; } + + // fragment shading rate + if (i == PAL_FORMAT_R8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; + usages |= PAL_IMAGE_VIEW_USAGE_COLOR; + } if (usages == 0) { usages = PAL_IMAGE_VIEW_USAGE_COLOR; @@ -2839,6 +2885,12 @@ PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; } + + // fragment shading rate + if (format == PAL_FORMAT_R8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; + usages |= PAL_IMAGE_VIEW_USAGE_COLOR; + } if (usages == 0) { usages = PAL_IMAGE_VIEW_USAGE_COLOR; @@ -3538,122 +3590,302 @@ PalResult PAL_CALL createVkRenderPass( return PAL_RESULT_OUT_OF_MEMORY; } - VkAttachmentReference depthRef; - VkAttachmentDescription attachments[MAX_ATTACHMENTS]; - VkAttachmentReference colorRefs[MAX_ATTACHMENTS]; - VkAttachmentReference resolveRefs[MAX_ATTACHMENTS]; - VkImageView views[MAX_ATTACHMENTS]; - - renderpass->hasDepth = false; + bool hasDepth = false; + bool hasFsr; Uint32 colorRefCount = 0; + Uint32 resolveRefCount = 0; Uint32 layers = 0; - for (int i = 0; i < info->attachmentCount; i++) { - PalAttachmentDesc* desc = &info->attachments[i]; - VkAttachmentDescription* rDesc = &attachments[i]; - - rDesc->format = palFormatToVk(desc->target->image->info.format); - rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rDesc->samples = vkSamplesToSamples(desc->target->image->info.sampleCount); - rDesc->flags = 0; - - layers = desc->target->image->info.depthOrArraySize; - if (desc->resolveTarget) { - // the layer count must be the same so to validate as well - // we use the highest from the attachments - layers = desc->resolveTarget->image->info.depthOrArraySize; + VkImageView views[MAX_ATTACHMENTS]; + + // multi view + Uint32 viewMask = (1 << info->multiViewCount) - 1; + VkRenderPassMultiviewCreateInfo viewCreateInfo = {0}; + viewCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; + viewCreateInfo.pViewMasks = &viewMask; + viewCreateInfo.subpassCount = 1; + + // clang-format off + if (device->createRenderPass2) { + VkAttachmentDescription2KHR attachments[MAX_ATTACHMENTS]; + VkAttachmentReference2KHR depthRef; + VkAttachmentReference2KHR fsrRef; + VkAttachmentReference2KHR colorRefs[MAX_ATTACHMENTS]; + VkAttachmentReference2KHR resolveRefs[MAX_ATTACHMENTS]; + VkFragmentShadingRateAttachmentInfoKHR fsrAttachment = {0}; + fsrAttachment.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; + + for (int i = 0; i < info->attachmentCount; i++) { + PalAttachmentDesc* desc = &info->attachments[i]; + VkAttachmentDescription2KHR* rDesc = &attachments[i]; + + rDesc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR; + rDesc->flags = 0; + rDesc->pNext = nullptr; + + rDesc->format = palFormatToVk(desc->target->image->info.format); + rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + rDesc->samples = vkSamplesToSamples(desc->target->image->info.sampleCount); + rDesc->flags = 0; + + layers = desc->target->image->info.depthOrArraySize; + VkAttachmentReference2KHR* resolveRef = &resolveRefs[resolveRefCount]; + if (desc->resolveTarget) { + // the layer count must be the same so to validate as well + // we use the highest from the attachments + layers = desc->resolveTarget->image->info.depthOrArraySize; + resolveRef->attachment = i; + resolveRef->pNext = 0; + resolveRef->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; + } + + // load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + // store op + if (desc->storeOp == PAL_STORE_OP_STORE) { + rDesc->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + + } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { + rDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + + // add the image views from the attachments into a seperate array + views[i] = desc->target->handle; + + if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { + VkAttachmentReference2KHR* ref = &colorRefs[colorRefCount]; + ref->attachment = i; + ref->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + ref->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + ref->pNext = 0; + ref->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; + + rDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + colorRefCount++; + if (desc->target->image->belongsToSwapchain) { + rDesc->finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + } + + if (resolveRef) { + resolveRef->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + resolveRef->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + resolveRefCount++; + } + + } else { + // fragment shading rate attachment + if (desc->type == PAL_ATTACHMENT_TYPE_FRAGMENT_SHADING_RATE) { + VkExtent2D size; + size.width = desc->texelWidth; + size.height = desc->texelHeight; + fsrAttachment.shadingRateAttachmentTexelSize = size; + + fsrRef.attachment = i; + rDesc->finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + fsrRef.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + fsrAttachment.pFragmentShadingRateAttachment = &fsrRef; + hasFsr = true; + + } else { + depthRef.attachment = i; + depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + depthRef.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + depthRef.pNext = 0; + depthRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; + + rDesc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + hasDepth = true; + // stencil is only used with depth attachment + if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { + rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + + } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { + rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + + if (resolveRef) { + resolveRef->layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + resolveRef->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + resolveRefCount++; + } + } + } } - // load op - if (desc->loadOp == PAL_LOAD_OP_CLEAR) { - rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + // subpass + VkSubpassDescription2 subpassDesc = {0}; + subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDesc.colorAttachmentCount = colorRefCount; + subpassDesc.pColorAttachments = colorRefs; + subpassDesc.pNext = &fsrAttachment; - } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { - rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + if (hasDepth) { + subpassDesc.pDepthStencilAttachment = &depthRef; + } - } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { - rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + if (resolveRefCount) { + subpassDesc.pResolveAttachments = resolveRefs; } - // store op - if (desc->storeOp == PAL_STORE_OP_STORE) { - rDesc->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + VkRenderPassCreateInfo2KHR createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR; + createInfo.attachmentCount = info->attachmentCount; + createInfo.pAttachments = attachments; + createInfo.subpassCount = 1; + createInfo.pSubpasses = &subpassDesc; - } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { - rDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + if (info->multiViewCount > 1) { + createInfo.pNext = &viewCreateInfo; } - // add the image views from the attachments into a seperate array - views[i] = desc->target->handle; - - if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { - VkAttachmentReference* ref = &colorRefs[colorRefCount]; - rDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - ref->attachment = i; - ref->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - colorRefCount++; - if (desc->target->image->belongsToSwapchain) { - rDesc->finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + result = device->createRenderPass2( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &renderpass->handle); + + } else { + // legacy path + VkAttachmentDescription attachments[MAX_ATTACHMENTS]; + VkAttachmentReference depthRef; + VkAttachmentReference colorRefs[MAX_ATTACHMENTS]; + VkAttachmentReference resolveRefs[MAX_ATTACHMENTS]; + + for (int i = 0; i < info->attachmentCount; i++) { + PalAttachmentDesc* desc = &info->attachments[i]; + VkAttachmentDescription* rDesc = &attachments[i]; + + rDesc->format = palFormatToVk(desc->target->image->info.format); + rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + rDesc->samples = vkSamplesToSamples(desc->target->image->info.sampleCount); + rDesc->flags = 0; + + layers = desc->target->image->info.depthOrArraySize; + VkAttachmentReference* resolveRef = &resolveRefs[resolveRefCount]; + if (desc->resolveTarget) { + // the layer count must be the same so to validate as well + // we use the highest from the attachments + layers = desc->resolveTarget->image->info.depthOrArraySize; + resolveRef->attachment = i; } - } else { - rDesc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - depthRef.attachment = i; - depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - renderpass->hasDepth = true; + // load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - // stencil is only used with depth attachment - if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + // store op + if (desc->storeOp == PAL_STORE_OP_STORE) { + rDesc->storeOp = VK_ATTACHMENT_STORE_OP_STORE; - } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { + rDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; } - if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { - rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + // add the image views from the attachments into a seperate array + views[i] = desc->target->handle; + + if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { + VkAttachmentReference* ref = &colorRefs[colorRefCount]; + ref->attachment = i; + ref->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { - rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + rDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + colorRefCount++; + if (desc->target->image->belongsToSwapchain) { + rDesc->finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + } + + if (resolveRef) { + resolveRef->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + resolveRefCount++; + } + + } else { + depthRef.attachment = i; + depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + + rDesc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + hasDepth = true; + // stencil is only used with depth attachment + if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { + rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + + } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { + rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + + if (resolveRef) { + resolveRef->layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + resolveRefCount++; + } } } - } - // subpass - VkSubpassDescription subpassDesc = {0}; - subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDesc.colorAttachmentCount = colorRefCount; - subpassDesc.pColorAttachments = colorRefs; - if (renderpass->hasDepth) { - subpassDesc.pDepthStencilAttachment = &depthRef; - } + // subpass legacy + VkSubpassDescription subpassDesc = {0}; + subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassDesc.colorAttachmentCount = colorRefCount; + subpassDesc.pColorAttachments = colorRefs; + if (hasDepth) { + subpassDesc.pDepthStencilAttachment = &depthRef; + } - // multi view - Uint32 viewMask = (1 << info->multiViewCount) - 1; - VkRenderPassMultiviewCreateInfo viewCreateInfo = {0}; - viewCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; - viewCreateInfo.pViewMasks = &viewMask; - viewCreateInfo.subpassCount = 1; + if (resolveRefCount) { + subpassDesc.pResolveAttachments = resolveRefs; + } - // render pass - VkRenderPassCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - createInfo.attachmentCount = info->attachmentCount; - createInfo.pAttachments = attachments; - createInfo.subpassCount = 1; - createInfo.pSubpasses = &subpassDesc; + VkRenderPassCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + createInfo.attachmentCount = info->attachmentCount; + createInfo.pAttachments = attachments; + createInfo.subpassCount = 1; + createInfo.pSubpasses = &subpassDesc; - if (info->multiViewCount > 1) { - createInfo.pNext = &viewCreateInfo; - } + if (info->multiViewCount > 1) { + createInfo.pNext = &viewCreateInfo; + } - result = s_Vk.createRenderPass( - device->handle, - &createInfo, - &s_Vk.vkAllocator, - &renderpass->handle); + result = s_Vk.createRenderPass( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &renderpass->handle); + } if (result != VK_SUCCESS) { palFree(s_Vk.allocator, renderpass); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index ffd696b9..983bef6f 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -296,6 +296,10 @@ bool graphicsTest() palLog(nullptr, " Depth stencil resolve"); } + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { + palLog(nullptr, " Fragment shading rate attachment"); + } + palLog(nullptr, ""); } From f142f42cf893140abba12190441afabff2c7a564 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 21 Dec 2025 18:59:11 +0000 Subject: [PATCH 058/372] add mesh shader feature and usage API --- CHANGELOG.md | 1 + include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 73 +++++++- src/graphics/pal_graphics.c | 336 ++++++++++++++++++++++++++++++------ src/graphics/pal_vulkan.c | 181 +++++++++++++++++-- tests/graphics_test.c | 4 + 6 files changed, 528 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94aa7032..63406e2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -146,6 +146,7 @@ palJoinThread(thread, &retval); - **Core:** Added **PAL_RESULT_INVALID_FENCE** to `PalResult` enum. - **Core:** Added **PAL_RESULT_INVALID_SEMAPHORE** to `PalResult` enum. - **Core:** Added **PAL_RESULT_INVALID_RENDER_PASS** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_BUFFER** to `PalResult` enum. - **Graphics:** Added **Graphics System To PAL**. diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 11f3f5aa..140c72e4 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -266,7 +266,8 @@ typedef enum { PAL_RESULT_INVALID_COMMAND_BUFFER, PAL_RESULT_INVALID_FENCE, PAL_RESULT_INVALID_SEMAPHORE, - PAL_RESULT_INVALID_RENDER_PASS + PAL_RESULT_INVALID_RENDER_PASS, + PAL_RESULT_INVALID_BUFFER } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 5635a214..9247b3d0 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -49,6 +49,7 @@ typedef struct PalImage PalImage; typedef struct PalImageView PalImageView; typedef struct PalShader PalShader; typedef struct PalRenderPass PalRenderPass; +typedef struct PalBuffer PalBuffer; typedef struct PalFence PalFence; typedef struct PalSemaphore PalSemaphore; @@ -243,7 +244,8 @@ typedef enum { PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(28), PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(29), PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(31) + PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(31), + PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT = PAL_BIT64(32) } PalAdapterFeatures; typedef enum { @@ -521,6 +523,15 @@ typedef struct { bool combinerOps[PAL_MAX_COMBINER_OPS]; } PalFragmentShadingRateCapabilities; +typedef struct { + Uint32 maxMeshOutputPrimitives; + Uint32 maxMeshOutputVertices; + Uint32 maxTaskWorkGroupInvocations; + Uint32 maxMeshWorkGroupInvocations; + Uint32 maxTaskWorkGroupCount[3]; + Uint32 maxMeshWorkGroupCount[3]; +} PalMeshShaderCapabilities; + typedef struct { bool presentModes[PAL_PRESENT_MODE_MAX]; bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; @@ -775,6 +786,10 @@ typedef struct { PalDevice* device, PalFragmentShadingRateCapabilities* caps); + PalResult PAL_CALL (*queryMeshShaderCapabilities)( + PalDevice* device, + PalMeshShaderCapabilities* caps); + PalResult PAL_CALL (*createQueue)( PalDevice* device, PalQueueType type, @@ -925,6 +940,32 @@ typedef struct { PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); + PalResult PAL_CALL (*setFragmentShadingRate)( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + + PalResult PAL_CALL (*drawMeshTasks)( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + + PalResult PAL_CALL (*drawMeshTasksIndirect)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 drawCount, + Uint32 stride); + + PalResult PAL_CALL (*drawMeshTasksIndirectCount)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride); + PalResult PAL_CALL (*beginRenderPass)( PalCommandBuffer* cmdBuffer, PalRenderPass* renderPass, @@ -993,6 +1034,10 @@ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( PalDevice* device, PalFragmentShadingRateCapabilities* caps); +PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( + PalDevice* device, + PalMeshShaderCapabilities* caps); + PAL_API PalResult PAL_CALL palCreateQueue( PalDevice* device, PalQueueType type, @@ -1149,6 +1194,32 @@ PAL_API PalResult PAL_CALL palExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); +PAL_API PalResult PAL_CALL palSetFragmentShadingRate( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + +PAL_API PalResult PAL_CALL palDrawMeshTasks( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + +PAL_API PalResult PAL_CALL palDrawMeshTasksIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 drawCount, + Uint32 stride); + +PAL_API PalResult PAL_CALL palDrawMeshTasksIndirectCount( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride); + PAL_API PalResult PAL_CALL palBeginRenderPass( PalCommandBuffer* cmdBuffer, PalRenderPass* renderPass, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 8d6b7ebb..11397f99 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -37,6 +37,7 @@ freely, subject to the following restrictions: #define GRAPHICS_PIPELINE 6 #define COMPUTE_PIPELINE 7 #define SWAPCHAIN_IMAGE 12 +#define PRIMARY_CMD_BUFFER 19 typedef enum { HANDLE_TYPE_NONE, @@ -52,7 +53,8 @@ typedef enum { HANDLE_TYPE_FENCE, HANDLE_TYPE_SEMAPHORE, HANDLE_TYPE_PIPELINE, - HANDLE_TYPE_SHADER + HANDLE_TYPE_SHADER, + HANDLE_TYPE_BUFFER, } HandleType; typedef struct { @@ -172,6 +174,10 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( PalDevice* device, PalFragmentShadingRateCapabilities* caps); +PalResult PAL_CALL queryVkMeshShaderCapabilities( + PalDevice* device, + PalMeshShaderCapabilities* caps); + PalResult PAL_CALL createVkQueue( PalDevice* device, PalQueueType type, @@ -322,6 +328,32 @@ PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); +PalResult PAL_CALL setVkFragmentShadingRate( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + +PalResult PAL_CALL drawVkMeshTasks( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + +PalResult PAL_CALL drawVkMeshTasksIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 drawCount, + Uint32 stride); + +PalResult PAL_CALL drawVkMeshTasksIndirectCount( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride); + PalResult PAL_CALL beginRenderPassVk( PalCommandBuffer* cmdBuffer, PalRenderPass* renderPass, @@ -352,6 +384,7 @@ static PalGraphicsBackend s_VkBackend = { .freeMemory = freeVkMemory, .queryDepthStencilCapabilities = queryVkDepthStencilCapabilities, .queryFragmentShadingRateCapabilities = queryVkFragmentShadingRateCapabilities, + .queryMeshShaderCapabilities = queryVkMeshShaderCapabilities, .createQueue = createVkQueue, .destroyQueue = destroyVkQueue, .canQueuePresent = canVkQueuePresent, @@ -391,6 +424,10 @@ static PalGraphicsBackend s_VkBackend = { .createCommandBuffer = createVkCommandBuffer, .destroyCommandBuffer = destroyVkCommandBuffer, .executeCommandBuffer = executeCommandBufferVk, + .setFragmentShadingRate = setVkFragmentShadingRate, + .drawMeshTasks = drawVkMeshTasks, + .drawMeshTasksIndirect = drawVkMeshTasksIndirect, + .drawMeshTasksIndirectCount = drawVkMeshTasksIndirectCount, .beginRenderPass = beginRenderPassVk, .endRenderPass = endRenderPassVk, .submitCommandBuffer = submitVkCommandBuffer, @@ -432,59 +469,65 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) // check if all the function pointers are set // clang-format off - if (!backend->enumerateAdapters || - !backend->getAdapterInfo || - !backend->getAdapterCapabilities || - !backend->queryDepthStencilCapabilities || - !backend->queryFragmentShadingRateCapabilities || - !backend->getAdapterFeatures || - !backend->createDevice || - !backend->destroyDevice || - !backend->allocateMemory || - !backend->freeMemory || - !backend->createQueue || - !backend->destroyQueue || - !backend->canQueuePresent || - !backend->enumerateFormats || - !backend->isFormatSupported || - !backend->queryFormatImageUsages || - !backend->queryFormatImageViewUsages || - !backend->createImage || - !backend->destroyImage || - !backend->getImageInfo || - !backend->getImageMemoryRequirements || - !backend->bindImageMemory || - !backend->createImageView || - !backend->destroyImageView || - !backend->querySwapchainCapabilities || - !backend->createSwapchain || - !backend->destroySwapchain || - !backend->getSwapchainImage || - !backend->getNextSwapchainImage || - !backend->presentSwapchain || - !backend->createShader || - !backend->destroyShader || - !backend->createRenderPass || - !backend->destroyRenderPass || - !backend->createFence || - !backend->destroyFence || - !backend->waitFenceTimeout || - !backend->resetFence || - !backend->isFenceSignaled || - !backend->createSemaphore || - !backend->destroySemaphore || - !backend->waitSemaphore || - !backend->signalSemaphore || - !backend->getSemaphoreValue || - !backend->createCommandPool || - !backend->destroyCommandPool || - !backend->createCommandBuffer || - !backend->destroyCommandBuffer || - !backend->beginRenderPass || - !backend->endRenderPass || - !backend->createGraphicsPipeline || - !backend->destroyPipeline || - !backend->submitCommandBuffer || + if (!backend->enumerateAdapters || + !backend->getAdapterInfo || + !backend->getAdapterCapabilities || + !backend->queryDepthStencilCapabilities || + !backend->queryFragmentShadingRateCapabilities || + !backend->queryMeshShaderCapabilities || + !backend->getAdapterFeatures || + !backend->createDevice || + !backend->destroyDevice || + !backend->allocateMemory || + !backend->freeMemory || + !backend->createQueue || + !backend->destroyQueue || + !backend->canQueuePresent || + !backend->enumerateFormats || + !backend->isFormatSupported || + !backend->queryFormatImageUsages || + !backend->queryFormatImageViewUsages || + !backend->createImage || + !backend->destroyImage || + !backend->getImageInfo || + !backend->getImageMemoryRequirements || + !backend->bindImageMemory || + !backend->createImageView || + !backend->destroyImageView || + !backend->querySwapchainCapabilities || + !backend->createSwapchain || + !backend->destroySwapchain || + !backend->getSwapchainImage || + !backend->getNextSwapchainImage || + !backend->presentSwapchain || + !backend->createShader || + !backend->destroyShader || + !backend->createRenderPass || + !backend->destroyRenderPass || + !backend->createFence || + !backend->destroyFence || + !backend->waitFenceTimeout || + !backend->resetFence || + !backend->isFenceSignaled || + !backend->createSemaphore || + !backend->destroySemaphore || + !backend->waitSemaphore || + !backend->signalSemaphore || + !backend->getSemaphoreValue || + !backend->createCommandPool || + !backend->destroyCommandPool || + !backend->createCommandBuffer || + !backend->destroyCommandBuffer || + !backend->executeCommandBuffer || + !backend->setFragmentShadingRate || + !backend->drawMeshTasks || + !backend->drawMeshTasksIndirect || + !backend->drawMeshTasksIndirectCount || + !backend->beginRenderPass || + !backend->endRenderPass || + !backend->createGraphicsPipeline || + !backend->destroyPipeline || + !backend->submitCommandBuffer || !backend->submitCommandBuffer) { return PAL_RESULT_INVALID_BACKEND; } @@ -829,6 +872,32 @@ PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( caps); } +PalResult PAL_CALL palQueryMeshShaderCapabilities( + PalDevice* device, + PalMeshShaderCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)device; + if (data->type != HANDLE_TYPE_DEVICE) { + return PAL_RESULT_INVALID_DEVICE; + } + + if (!(data->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + return data->backend->queryMeshShaderCapabilities( + data->handle, + caps); +} + // ================================================== // Queue // ================================================== @@ -2030,6 +2099,11 @@ PalResult PAL_CALL palCreateCommandBuffer( cmdBufferData->handle = cmdBuffer; cmdBufferData->type = HANDLE_TYPE_COMMAND_BUFFER; cmdBufferData->features = data->features; + cmdBufferData->data2 = 0; + + if (primary) { + cmdBufferData->data2 = PRIMARY_CMD_BUFFER; + } *outCmdBuffer = (PalCommandBuffer*)cmdBufferData; return PAL_RESULT_SUCCESS; @@ -2068,11 +2142,165 @@ PalResult PAL_CALL palExecuteCommandBuffer( return PAL_RESULT_INVALID_COMMAND_BUFFER; } + // clang-format off + // check if both are primary cmd buffers + if (primaryCmdBufferData->data2 == PRIMARY_CMD_BUFFER + && secondaryCmdBufferData->data2 == PRIMARY_CMD_BUFFER) { + return PAL_RESULT_INVALID_OPERATION; + } + + // check if both are secondary cmd buffers + if (primaryCmdBufferData->data2 == 0 + && secondaryCmdBufferData->data2 == 0) { + return PAL_RESULT_INVALID_OPERATION; + } + + if (primaryCmdBufferData->data2 != PRIMARY_CMD_BUFFER) { + return PAL_RESULT_INVALID_OPERATION; + } + // clang-format on + return primaryCmdBufferData->backend->executeCommandBuffer( primaryCmdBufferData->handle, secondaryCmdBufferData->handle); } +PalResult PAL_CALL palSetFragmentShadingRate( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !state) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)cmdBuffer; + if (data->type != HANDLE_TYPE_COMMAND_BUFFER) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + return data->backend->setFragmentShadingRate( + data->handle, + state); +} + +PalResult PAL_CALL palDrawMeshTasks( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)cmdBuffer; + if (data->type != HANDLE_TYPE_COMMAND_BUFFER) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + if (!(data->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + return data->backend->drawMeshTasks( + data->handle, + groupCountX, + groupCountY, + groupCountZ); +} + +PalResult PAL_CALL palDrawMeshTasksIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 drawCount, + Uint32 stride) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffer) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* cmdBufferData = (HandleData*)cmdBuffer; + HandleData* bufferData = (HandleData*)buffer; + if (cmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + if (bufferData->type != HANDLE_TYPE_BUFFER) { + return PAL_RESULT_INVALID_BUFFER; + } + + if (!(cmdBufferData->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + return cmdBufferData->backend->drawMeshTasksIndirect( + cmdBufferData->handle, + bufferData->handle, + offset, + drawCount, + stride); +} + +PalResult PAL_CALL palDrawMeshTasksIndirectCount( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffer || !countBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* cmdBufferData = (HandleData*)cmdBuffer; + HandleData* bufferData = (HandleData*)buffer; + HandleData* countBufferData = (HandleData*)countBuffer; + if (cmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + if (bufferData->type != HANDLE_TYPE_BUFFER) { + return PAL_RESULT_INVALID_BUFFER; + } + + if (countBufferData->type != HANDLE_TYPE_BUFFER) { + return PAL_RESULT_INVALID_BUFFER; + } + + if (!(cmdBufferData->features & + PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + return cmdBufferData->backend->drawMeshTasksIndirectCount( + cmdBufferData->handle, + bufferData->handle, + countBufferData->handle, + offset, + countBufferOffset, + maxDrawCount, + stride); +} + PalResult PAL_CALL palBeginRenderPass( PalCommandBuffer* cmdBuffer, PalRenderPass* renderPass, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index b57c440b..9b143583 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -164,6 +164,7 @@ struct PalDevice { PhysicalQueue* phyQueues; PFN_vkCreateRenderPass2 createRenderPass2; + // swapchain PFN_vkCreateSwapchainKHR createSwapchain; PFN_vkDestroySwapchainKHR destroySwapchain; PFN_vkGetSwapchainImagesKHR getSwapchainImages; @@ -179,6 +180,11 @@ struct PalDevice { // fragment shading rate PFN_vkCmdSetFragmentShadingRateKHR cmdSetFragmentShadingRate; + + // mesh shader + PFN_vkCmdDrawMeshTasksEXT cmdDrawMeshTask; + PFN_vkCmdDrawMeshTasksIndirectEXT cmdDrawMeshTaskIndirect; + PFN_vkCmdDrawMeshTasksIndirectCountEXT cmdDrawMeshTaskIndirectCount; }; struct PalQueue { @@ -251,6 +257,10 @@ struct PalSemaphore { VkSemaphore handle; }; +struct PalBuffer { + VkBuffer handle; +}; + static Vulkan s_Vk = {0}; // ================================================== @@ -1815,6 +1825,9 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } else if (strcmp(props->extensionName, "VK_KHR_depth_stencil_resolve") == 0) { adapterFeatures |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; + + } else if (strcmp(props->extensionName, "VK_KHR_draw_indirect_count") == 0) { + adapterFeatures |= PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT; } } @@ -2195,11 +2208,18 @@ PalResult PAL_CALL createVkDevice( start = &ray; } - if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + if ((features & PAL_ADAPTER_FEATURE_MESH_SHADER) || + (features & PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT)) { if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_EXT_mesh_shader"; } + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_draw_indirect_count"; + } + } + mesh.meshShader = true; mesh.taskShader = true; if (acc.accelerationStructure) { @@ -2494,6 +2514,23 @@ PalResult PAL_CALL createVkDevice( } } + // mesh shader + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + device->cmdDrawMeshTask = (PFN_vkCmdDrawMeshTasksEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawMeshTasksEXT"); + + device->cmdDrawMeshTaskIndirect = + (PFN_vkCmdDrawMeshTasksIndirectEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawMeshTasksIndirectEXT"); + + device->cmdDrawMeshTaskIndirectCount = + (PFN_vkCmdDrawMeshTasksIndirectCountEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawMeshTasksIndirectCountEXT"); + } + device->features = features; palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); @@ -2660,6 +2697,34 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL queryVkMeshShaderCapabilities( + PalDevice* device, + PalMeshShaderCapabilities* caps) +{ + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + + VkPhysicalDeviceMeshShaderPropertiesEXT props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT; + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(device->phyDevice, &properties2); + + caps->maxMeshOutputPrimitives = props.maxMeshOutputPrimitives; + caps->maxMeshOutputVertices = props.maxMeshOutputVertices; + caps->maxTaskWorkGroupInvocations = props.maxTaskWorkGroupInvocations; + caps->maxMeshWorkGroupInvocations = props.maxMeshWorkGroupInvocations; + + caps->maxTaskWorkGroupCount[0] = props.maxTaskWorkGroupCount[0]; + caps->maxTaskWorkGroupCount[1] = props.maxTaskWorkGroupCount[1]; + caps->maxTaskWorkGroupCount[2] = props.maxTaskWorkGroupCount[2]; + + caps->maxMeshWorkGroupCount[0] = props.maxMeshWorkGroupCount[0]; + caps->maxMeshWorkGroupCount[1] = props.maxMeshWorkGroupCount[1]; + caps->maxMeshWorkGroupCount[2] = props.maxMeshWorkGroupCount[2]; + + return PAL_RESULT_SUCCESS; +} + // ================================================== // Queue // ================================================== @@ -3892,6 +3957,7 @@ PalResult PAL_CALL createVkRenderPass( return vkResultToPal(result); } + // clamg-format on // create framebuffer VkFramebufferCreateInfo fbCreateInfo = {0}; fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; @@ -4254,19 +4320,6 @@ PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { - // check if both are primary cmd buffers - if (primaryCmdBuffer->primary && secondaryCmdBuffer->primary) { - return PAL_RESULT_INVALID_OPERATION; - } - - if (!primaryCmdBuffer->primary && !secondaryCmdBuffer->primary) { - return PAL_RESULT_INVALID_OPERATION; - } - - if (!primaryCmdBuffer->primary) { - return PAL_RESULT_INVALID_OPERATION; - } - s_Vk.cmdExecuteCommandBuffer( primaryCmdBuffer->handle, 1, @@ -4275,6 +4328,106 @@ PalResult PAL_CALL executeCommandBufferVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL setVkFragmentShadingRate( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state) +{ + VkExtent2D size = getShadingRateSize(state->rate); + VkFragmentShadingRateCombinerOpKHR combinerOps[2]; + + for (int i = 0; i < 2; i++) { + switch (state->combinerOps[i]) { + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP: { + combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; + continue; + } + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE: { + combinerOps[i] = + VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; + continue; + } + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN: { + combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR; + continue; + } + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX: { + combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR; + continue; + } + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL: { + combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR; + continue; + } + + combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; + } + } + + cmdBuffer->device->cmdSetFragmentShadingRate( + cmdBuffer->handle, + &size, + combinerOps); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL drawVkMeshTasks( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ) +{ + cmdBuffer->device->cmdDrawMeshTask( + cmdBuffer->handle, + groupCountX, + groupCountY, + groupCountZ); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL drawVkMeshTasksIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 drawCount, + Uint32 stride) +{ + cmdBuffer->device->cmdDrawMeshTaskIndirect( + cmdBuffer->handle, + buffer->handle, + offset, + drawCount, + stride); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL drawVkMeshTasksIndirectCount( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride) +{ + cmdBuffer->device->cmdDrawMeshTaskIndirectCount( + cmdBuffer->handle, + buffer->handle, + offset, + countBuffer->handle, + countBufferOffset, + maxDrawCount, + stride); + + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL beginRenderPassVk( PalCommandBuffer* cmdBuffer, PalRenderPass* renderPass, diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 983bef6f..eeae7380 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -300,6 +300,10 @@ bool graphicsTest() palLog(nullptr, " Fragment shading rate attachment"); } + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT) { + palLog(nullptr, " Mesh shader indirect count"); + } + palLog(nullptr, ""); } From f790376d2788268afefdda63905ddd887652cf52 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 22 Dec 2025 10:42:50 +0000 Subject: [PATCH 059/372] update license --- CHANGELOG.md | 2 +- LICENSE.txt | 2 +- include/pal/pal_core.h | 2 +- include/pal/pal_event.h | 2 +- include/pal/pal_graphics.h | 2 +- include/pal/pal_opengl.h | 2 +- include/pal/pal_system.h | 2 +- include/pal/pal_thread.h | 2 +- include/pal/pal_video.h | 2 +- src/graphics/pal_graphics.c | 2 +- src/graphics/pal_vulkan.c | 2 +- src/opengl/pal_opengl_linux.c | 2 +- src/opengl/pal_opengl_win32.c | 2 +- src/pal_core.c | 2 +- src/pal_event.c | 2 +- src/system/pal_system_linux.c | 2 +- src/system/pal_system_win32.c | 2 +- src/thread/pal_thread_linux.c | 2 +- src/thread/pal_thread_win32.c | 2 +- src/video/pal_video_linux.c | 2 +- src/video/pal_video_win32.c | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63406e2a..814440ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,7 +121,7 @@ void* retval; palJoinThread(thread, &retval); ``` -## [1.4.0] - 2025-00-00 +## [1.4.0] - 2026-01-00 ### Features diff --git a/LICENSE.txt b/LICENSE.txt index ba743483..67b45697 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,7 +1,7 @@ zlib License -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 140c72e4..369ee53e 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index f85a7b05..3f5d117c 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 9247b3d0..b77de576 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index a54a5e79..7c456f02 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index 9e671535..3b785a00 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -1,6 +1,6 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index 666f27ed..c4895096 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index d06c968e..c1bc475a 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 11397f99..f5e34225 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 9b143583..b4b8c815 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/opengl/pal_opengl_linux.c b/src/opengl/pal_opengl_linux.c index c8b3b6a8..cb957ad6 100644 --- a/src/opengl/pal_opengl_linux.c +++ b/src/opengl/pal_opengl_linux.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/opengl/pal_opengl_win32.c b/src/opengl/pal_opengl_win32.c index 0eb79f09..30dae398 100644 --- a/src/opengl/pal_opengl_win32.c +++ b/src/opengl/pal_opengl_win32.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/pal_core.c b/src/pal_core.c index 95c5768d..51f42f82 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/pal_event.c b/src/pal_event.c index b608dff5..6c3d8175 100644 --- a/src/pal_event.c +++ b/src/pal_event.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/system/pal_system_linux.c b/src/system/pal_system_linux.c index f775c41d..14a476f2 100644 --- a/src/system/pal_system_linux.c +++ b/src/system/pal_system_linux.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/system/pal_system_win32.c b/src/system/pal_system_win32.c index bcce0a74..6cc7ac1a 100644 --- a/src/system/pal_system_win32.c +++ b/src/system/pal_system_win32.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/thread/pal_thread_linux.c b/src/thread/pal_thread_linux.c index 2c5b7860..030b0690 100644 --- a/src/thread/pal_thread_linux.c +++ b/src/thread/pal_thread_linux.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/thread/pal_thread_win32.c b/src/thread/pal_thread_win32.c index 4337c639..558cfe71 100644 --- a/src/thread/pal_thread_win32.c +++ b/src/thread/pal_thread_win32.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index ffe25d33..82d1c638 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/video/pal_video_win32.c b/src/video/pal_video_win32.c index a95412f3..2c1dce80 100644 --- a/src/video/pal_video_win32.c +++ b/src/video/pal_video_win32.c @@ -1,7 +1,7 @@ /** -Copyright (C) 2025 Nicholas Agbo +Copyright (C) 2025-2026 Nicholas Agbo This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages From a0d0141d8a44a8db073d9eac0ec572ebdc5c1402 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 22 Dec 2025 11:46:15 +0000 Subject: [PATCH 060/372] add ray tracing capabilities struct --- include/pal/pal_graphics.h | 22 ++++++++ src/graphics/pal_graphics.c | 32 ++++++++++++ src/graphics/pal_vulkan.c | 100 ++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index b77de576..3c3fb04a 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -532,6 +532,20 @@ typedef struct { Uint32 maxMeshWorkGroupCount[3]; } PalMeshShaderCapabilities; +typedef struct { + Uint32 maxRecursionDepth; + Uint32 maxHitAttributeSize; + Uint32 maxInstanceCount; + Uint32 maxPrimitiveCount; + Uint32 maxGeometryCount; + Uint32 maxPayloadSize; + Uint32 maxDispatchInvocations; + Uint32 maxShaderGroupStride; + Uint32 shaderGroupHandleSize; + Uint32 shaderGroupHandleAlignment; + Uint32 shaderGroupBaseAlignment; +} PalRayTracingCapabilities; + typedef struct { bool presentModes[PAL_PRESENT_MODE_MAX]; bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; @@ -790,6 +804,10 @@ typedef struct { PalDevice* device, PalMeshShaderCapabilities* caps); + PalResult PAL_CALL (*queryRayTracingCapabilities)( + PalDevice* device, + PalRayTracingCapabilities* caps); + PalResult PAL_CALL (*createQueue)( PalDevice* device, PalQueueType type, @@ -1038,6 +1056,10 @@ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( PalDevice* device, PalMeshShaderCapabilities* caps); +PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( + PalDevice* device, + PalRayTracingCapabilities* caps); + PAL_API PalResult PAL_CALL palCreateQueue( PalDevice* device, PalQueueType type, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index f5e34225..7967d7a4 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -178,6 +178,10 @@ PalResult PAL_CALL queryVkMeshShaderCapabilities( PalDevice* device, PalMeshShaderCapabilities* caps); +PalResult PAL_CALL queryVkRayTracingCapabilities( + PalDevice* device, + PalRayTracingCapabilities* caps); + PalResult PAL_CALL createVkQueue( PalDevice* device, PalQueueType type, @@ -385,6 +389,7 @@ static PalGraphicsBackend s_VkBackend = { .queryDepthStencilCapabilities = queryVkDepthStencilCapabilities, .queryFragmentShadingRateCapabilities = queryVkFragmentShadingRateCapabilities, .queryMeshShaderCapabilities = queryVkMeshShaderCapabilities, + .queryRayTracingCapabilities = queryVkRayTracingCapabilities, .createQueue = createVkQueue, .destroyQueue = destroyVkQueue, .canQueuePresent = canVkQueuePresent, @@ -475,6 +480,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->queryDepthStencilCapabilities || !backend->queryFragmentShadingRateCapabilities || !backend->queryMeshShaderCapabilities || + !backend->queryRayTracingCapabilities || !backend->getAdapterFeatures || !backend->createDevice || !backend->destroyDevice || @@ -898,6 +904,32 @@ PalResult PAL_CALL palQueryMeshShaderCapabilities( caps); } +PalResult PAL_CALL palQueryRayTracingCapabilities( + PalDevice* device, + PalRayTracingCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)device; + if (data->type != HANDLE_TYPE_DEVICE) { + return PAL_RESULT_INVALID_DEVICE; + } + + if (!(data->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + return data->backend->queryRayTracingCapabilities( + data->handle, + caps); +} + // ================================================== // Queue // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index b4b8c815..08d76aeb 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -185,6 +185,18 @@ struct PalDevice { PFN_vkCmdDrawMeshTasksEXT cmdDrawMeshTask; PFN_vkCmdDrawMeshTasksIndirectEXT cmdDrawMeshTaskIndirect; PFN_vkCmdDrawMeshTasksIndirectCountEXT cmdDrawMeshTaskIndirectCount; + + // ray tracing + PFN_vkCreateAccelerationStructureKHR createAccelerationStructure; + PFN_vkDestroyAccelerationStructureKHR destroyAccelerationStructure; + PFN_vkGetAccelerationStructureBuildSizesKHR getAccelerationBuildsize; + PFN_vkCmdBuildAccelerationStructuresKHR cmdBuildAccelerationStructures; + PFN_vkGetAccelerationStructureDeviceAddressKHR getAccelerationDeviceAddress; + PFN_vkCmdCopyAccelerationStructureKHR cmdCopyAccelerationStructure; + PFN_vkCmdWriteAccelerationStructuresPropertiesKHR cmdWriteAccelerationProps; + PFN_vkCmdTraceRaysKHR cmdTraceRays; + PFN_vkCreateRayTracingPipelinesKHR createRayTracingPipeline; + PFN_vkCmdTraceRaysIndirectKHR cmdTraceRaysIndirect; }; struct PalQueue { @@ -2531,6 +2543,59 @@ PalResult PAL_CALL createVkDevice( "vkCmdDrawMeshTasksIndirectCountEXT"); } + // ray tracing + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + device->createAccelerationStructure = + (PFN_vkCreateAccelerationStructureKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateAccelerationStructureKHR"); + + device->destroyAccelerationStructure = + (PFN_vkDestroyAccelerationStructureKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkDestroyAccelerationStructureKHR"); + + device->getAccelerationBuildsize = + (PFN_vkGetAccelerationStructureBuildSizesKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetAccelerationStructureBuildSizesKHR"); + + device->cmdBuildAccelerationStructures = + (PFN_vkCmdBuildAccelerationStructuresKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdBuildAccelerationStructuresKHR"); + + device->getAccelerationDeviceAddress = + (PFN_vkGetAccelerationStructureDeviceAddressKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetAccelerationStructureDeviceAddressKHR"); + + device->cmdCopyAccelerationStructure = + (PFN_vkCmdCopyAccelerationStructureKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdCopyAccelerationStructureKHR"); + + device->cmdWriteAccelerationProps = + (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdWriteAccelerationStructuresPropertiesKHR"); + + device->cmdTraceRays = + (PFN_vkCmdTraceRaysKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdTraceRaysKHR"); + + device->createRayTracingPipeline = + (PFN_vkCreateRayTracingPipelinesKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateRayTracingPipelinesKHR"); + + device->cmdTraceRaysIndirect = + (PFN_vkCmdTraceRaysIndirectKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdTraceRaysIndirectKHR"); + } + device->features = features; palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); @@ -2725,6 +2790,41 @@ PalResult PAL_CALL queryVkMeshShaderCapabilities( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL queryVkRayTracingCapabilities( + PalDevice* device, + PalRayTracingCapabilities* caps) +{ + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + + VkPhysicalDeviceRayTracingPipelinePropertiesKHR props = {0}; + props.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; + + VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; + accProps.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; + + props.pNext = &accProps; + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(device->phyDevice, &properties2); + + caps->maxRecursionDepth = props.maxRayRecursionDepth; + caps->maxHitAttributeSize = props.maxRayHitAttributeSize; + caps->maxInstanceCount = accProps.maxInstanceCount; + caps->maxPrimitiveCount = accProps.maxPrimitiveCount; + caps->maxGeometryCount = accProps.maxGeometryCount; + + caps->maxPayloadSize = INT32_MAX; // depends on memory + caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; + caps->maxShaderGroupStride = props.maxShaderGroupStride; + caps->shaderGroupHandleSize = props.shaderGroupHandleSize; + caps->shaderGroupHandleAlignment = props.shaderGroupHandleAlignment; + caps->shaderGroupBaseAlignment = props.shaderGroupBaseAlignment; + + return PAL_RESULT_SUCCESS; +} + // ================================================== // Queue // ================================================== From 7d56a77a34ea0ea0db99a2aaa42266a0cd589509 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 23 Dec 2025 13:04:18 +0000 Subject: [PATCH 061/372] add extended raytracing features --- include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 128 ++++++++++- src/graphics/pal_graphics.c | 411 ++++++++++++++++++++++++++++++++++-- src/graphics/pal_vulkan.c | 144 +++++++++++-- src/pal_core.c | 3 + 5 files changed, 648 insertions(+), 41 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 369ee53e..b997c66b 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -267,7 +267,8 @@ typedef enum { PAL_RESULT_INVALID_FENCE, PAL_RESULT_INVALID_SEMAPHORE, PAL_RESULT_INVALID_RENDER_PASS, - PAL_RESULT_INVALID_BUFFER + PAL_RESULT_INVALID_BUFFER, + PAL_RESULT_INVALID_ACCELERATION_STRUCTURE } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 3c3fb04a..873b8f9e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -57,6 +57,8 @@ typedef struct PalCommandPool PalCommandPool; typedef struct PalCommandBuffer PalCommandBuffer; typedef struct PalPipeline PalPipeline; +typedef struct PalAccelerationStructure PalAccelerationStructure; + typedef enum { PAL_ADAPTER_TYPE_UNKNOWN, PAL_ADAPTER_TYPE_DISCRETE, @@ -387,6 +389,16 @@ typedef enum { PAL_VERTEX_TYPE_HALF_FLOAT16_4 } PalVertexType; +typedef enum { + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + PAL_COMMAND_BUFFER_TYPE_SECONDARY +} PalCommandBufferType; + +typedef enum { + PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX, + PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE +} PalVertexLayoutType; + typedef enum { PAL_COMPARE_OP_NEVER, PAL_COMPARE_OP_LESS, @@ -470,6 +482,21 @@ typedef enum { PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL } PalFragmentShadingRateCombinerOp; +typedef enum { + PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL, + PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL +} PalAccelerationStructureType; + +typedef enum { + PAL_GEOMETRY_TYPE_TRIANGLE, + PAL_GEOMETRY_TYPE_AABBS +} PalGeometryType; + +typedef enum { + PAL_INDEX_TYPE_UINT16, + PAL_INDEX_TYPE_UINT32 +} PalIndexType; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -635,7 +662,7 @@ typedef struct { } PalVertexAttribute; typedef struct { - bool perInstance; + PalVertexLayoutType type; Uint32 binding; Uint32 vertexCount; PalVertexAttribute* vertices; @@ -689,6 +716,58 @@ typedef struct { PalFragmentShadingRateCombinerOp combinerOps[2]; } PalFragmentShadingRateState; +typedef struct { + Uint32 instanceId; + Uint32 mask; + PalAccelerationStructure* blas; + float transform[12]; // row major (3x4) +} PalAccelerationStructureInstance; + +typedef struct { + Uint32 accelerationStructureSize; + Uint32 scratchBufferSize; +} PalAccelerationStructureBuildSize; + +typedef struct { + PalVertexType vertexType; + PalIndexType indexType; + Uint32 vertexStride; + Uint32 indexCount; + Uint32 vertexCount; + Uint64 vertexOffset; + Uint64 indexOffset; + PalBuffer* vertexBuffer; + PalBuffer* indexBuffer; +} PalGeometryDataTriangle; + +typedef struct { + Uint32 count; + Uint32 stride; + Uint64 offset; + PalBuffer* buffer; +} PalGeometryDataAABBS; + +typedef struct { + Uint32 count; + Uint64 offset; + PalBuffer* buffer; +} PalGeometryDataInstance; + +typedef struct { + Uint32 primitiveCount; + PalGeometryType type; + void* data; // based on type +} PalGeometry; + +typedef struct { + PalAccelerationStructureType type; + Uint32 geometryCount; + Uint64 scratchBufferOffset; + PalAccelerationStructure* dst; + PalBuffer* scratchBuffer; + PalGeometry* geometries; +} PalAccelerationStructureBuildInfo; + typedef struct { Uint32 width; Uint32 height; @@ -740,6 +819,13 @@ typedef struct { PalQueue* queue; } PalCommandPoolCreateInfo; +typedef struct { + PalAccelerationStructureType type; + PalBuffer* buffer; + Uint64 offset; + Uint64 size; +} PalAccelerationStructureCreateInfo; + typedef struct { bool fragmentShadingRateEnabled; PalPrimitiveTopology topology; @@ -949,7 +1035,7 @@ typedef struct { PalResult PAL_CALL (*createCommandBuffer)( PalDevice* device, PalCommandPool* pool, - bool primary, + PalCommandBufferType type, PalCommandBuffer** outCmdBuffer); void PAL_CALL (*destroyCommandBuffer)(PalCommandBuffer* cmdBuffer); @@ -984,6 +1070,11 @@ typedef struct { Uint32 maxDrawCount, Uint32 stride); + PalResult PAL_CALL (*buildAccelerationStructures)( + PalDevice* device, + Int32 infoCount, + PalAccelerationStructureBuildInfo* infos); + PalResult PAL_CALL (*beginRenderPass)( PalCommandBuffer* cmdBuffer, PalRenderPass* renderPass, @@ -996,6 +1087,19 @@ typedef struct { PalQueue* queue, PalSubmitInfo* info); + PalResult PAL_CALL (*createAccelerationstructure)( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + + void PAL_CALL (*destroyAccelerationstructure)( + PalAccelerationStructure* as); + + PalResult PAL_CALL (*getAccelerationStructureBuildSize)( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + PalResult PAL_CALL (*createGraphicsPipeline)( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, @@ -1207,7 +1311,7 @@ PAL_API bool PAL_CALL palIsTimelineSemaphore(PalSemaphore* semaphore); PAL_API PalResult PAL_CALL palCreateCommandBuffer( PalDevice* device, PalCommandPool* pool, - bool primary, + PalCommandBufferType type, PalCommandBuffer** outCmdbuffer); PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -1242,6 +1346,11 @@ PAL_API PalResult PAL_CALL palDrawMeshTasksIndirectCount( Uint32 maxDrawCount, Uint32 stride); +PAL_API PalResult PAL_CALL palBuildAccelerationStructures( + PalDevice* device, + Int32 infoCount, + PalAccelerationStructureBuildInfo* infos); + PAL_API PalResult PAL_CALL palBeginRenderPass( PalCommandBuffer* cmdBuffer, PalRenderPass* renderPass, @@ -1254,6 +1363,19 @@ PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalSubmitInfo* info); +PAL_API PalResult PAL_CALL palCreateAccelerationstructure( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + +PAL_API void PAL_CALL palDestroyAccelerationstructure( + PalAccelerationStructure* as); + +PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 7967d7a4..15284b00 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -37,7 +37,6 @@ freely, subject to the following restrictions: #define GRAPHICS_PIPELINE 6 #define COMPUTE_PIPELINE 7 #define SWAPCHAIN_IMAGE 12 -#define PRIMARY_CMD_BUFFER 19 typedef enum { HANDLE_TYPE_NONE, @@ -55,6 +54,7 @@ typedef enum { HANDLE_TYPE_PIPELINE, HANDLE_TYPE_SHADER, HANDLE_TYPE_BUFFER, + HANDLE_TYPE_ACCELERATION_STRUCTURE } HandleType; typedef struct { @@ -323,7 +323,7 @@ void PAL_CALL destroyVkCommandPool(PalCommandPool* pool); PalResult PAL_CALL createVkCommandBuffer( PalDevice* device, PalCommandPool* pool, - bool primary, + PalCommandBufferType type, PalCommandBuffer** outBuffer); void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); @@ -358,6 +358,11 @@ PalResult PAL_CALL drawVkMeshTasksIndirectCount( Uint32 maxDrawCount, Uint32 stride); +PalResult PAL_CALL buildVkAccelerationStructures( + PalDevice* device, + Int32 infoCount, + PalAccelerationStructureBuildInfo* infos); + PalResult PAL_CALL beginRenderPassVk( PalCommandBuffer* cmdBuffer, PalRenderPass* renderPass, @@ -370,6 +375,19 @@ PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalSubmitInfo* info); +PalResult PAL_CALL createVkAccelerationstructure( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + +void PAL_CALL destroyVkAccelerationstructure( + PalAccelerationStructure* as); + +PalResult PAL_CALL getVkAccelerationStructureBuildSize( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + PalResult PAL_CALL createVkGraphicsPipeline( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, @@ -433,9 +451,13 @@ static PalGraphicsBackend s_VkBackend = { .drawMeshTasks = drawVkMeshTasks, .drawMeshTasksIndirect = drawVkMeshTasksIndirect, .drawMeshTasksIndirectCount = drawVkMeshTasksIndirectCount, + .buildAccelerationStructures = buildVkAccelerationStructures, .beginRenderPass = beginRenderPassVk, .endRenderPass = endRenderPassVk, .submitCommandBuffer = submitVkCommandBuffer, + .createAccelerationstructure = createVkAccelerationstructure, + .destroyAccelerationstructure = destroyVkAccelerationstructure, + .getAccelerationStructureBuildSize = getVkAccelerationStructureBuildSize, .createGraphicsPipeline = createVkGraphicsPipeline, .destroyPipeline = destroyVkPipeline }; @@ -529,12 +551,15 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->drawMeshTasks || !backend->drawMeshTasksIndirect || !backend->drawMeshTasksIndirectCount || + !backend->buildAccelerationStructures || !backend->beginRenderPass || !backend->endRenderPass || - !backend->createGraphicsPipeline || - !backend->destroyPipeline || !backend->submitCommandBuffer || - !backend->submitCommandBuffer) { + !backend->createAccelerationstructure || + !backend->destroyAccelerationstructure || + !backend->getAccelerationStructureBuildSize || + !backend->createGraphicsPipeline || + !backend->destroyPipeline) { return PAL_RESULT_INVALID_BACKEND; } // clang-format on @@ -2088,7 +2113,7 @@ void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) PalResult PAL_CALL palCreateCommandBuffer( PalDevice* device, PalCommandPool* pool, - bool primary, + PalCommandBufferType type, PalCommandBuffer** outCmdBuffer) { if (!s_Graphics.initialized) { @@ -2120,7 +2145,7 @@ PalResult PAL_CALL palCreateCommandBuffer( ret = data->backend->createCommandBuffer( data->handle, poolData->handle, - primary, + type, &cmdBuffer); if (ret != PAL_RESULT_SUCCESS) { @@ -2131,11 +2156,7 @@ PalResult PAL_CALL palCreateCommandBuffer( cmdBufferData->handle = cmdBuffer; cmdBufferData->type = HANDLE_TYPE_COMMAND_BUFFER; cmdBufferData->features = data->features; - cmdBufferData->data2 = 0; - - if (primary) { - cmdBufferData->data2 = PRIMARY_CMD_BUFFER; - } + cmdBufferData->data2 = type; *outCmdBuffer = (PalCommandBuffer*)cmdBufferData; return PAL_RESULT_SUCCESS; @@ -2176,18 +2197,18 @@ PalResult PAL_CALL palExecuteCommandBuffer( // clang-format off // check if both are primary cmd buffers - if (primaryCmdBufferData->data2 == PRIMARY_CMD_BUFFER - && secondaryCmdBufferData->data2 == PRIMARY_CMD_BUFFER) { + if (primaryCmdBufferData->data2 == PAL_COMMAND_BUFFER_TYPE_PRIMARY && + secondaryCmdBufferData->data2 == PAL_COMMAND_BUFFER_TYPE_PRIMARY) { return PAL_RESULT_INVALID_OPERATION; } // check if both are secondary cmd buffers - if (primaryCmdBufferData->data2 == 0 - && secondaryCmdBufferData->data2 == 0) { + if (primaryCmdBufferData->data2 == PAL_COMMAND_BUFFER_TYPE_SECONDARY && + secondaryCmdBufferData->data2 == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { return PAL_RESULT_INVALID_OPERATION; } - if (primaryCmdBufferData->data2 != PRIMARY_CMD_BUFFER) { + if (primaryCmdBufferData->data2 != PAL_COMMAND_BUFFER_TYPE_PRIMARY) { return PAL_RESULT_INVALID_OPERATION; } // clang-format on @@ -2333,6 +2354,160 @@ PalResult PAL_CALL palDrawMeshTasksIndirectCount( stride); } +PalResult PAL_CALL palBuildAccelerationStructures( + PalDevice* device, + Int32 infoCount, + PalAccelerationStructureBuildInfo* infos) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !infos || infoCount <= 0) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* data = (HandleData*)device; + if (data->type != HANDLE_TYPE_DEVICE) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + + // fast path. 1 to 4 build info + bool free = false; + PalAccelerationStructureBuildInfo buildInfos[4]; + PalAccelerationStructureBuildInfo* tmpInfos = buildInfos; + if (infoCount > 4) { + // allocate memory + tmpInfos = nullptr; + tmpInfos = palAllocate( + s_Graphics.allocator, + sizeof(PalAccelerationStructureBuildInfo) * infoCount, + 0); + + if (!tmpInfos) { + return PAL_RESULT_OUT_OF_MEMORY; + } + free = true; + } + + PalGeometry* tmpBuildInfoGeometries[8]; + for (int i = 0; i < infoCount; i++) { + PalAccelerationStructureBuildInfo* info = &tmpInfos[i]; + // scratch buffer and acceleration source + HandleData* asData = (HandleData*)info->dst; + if (asData->type != HANDLE_TYPE_ACCELERATION_STRUCTURE) { + return PAL_RESULT_INVALID_ACCELERATION_STRUCTURE; + } + + HandleData* scratchBufferData = (HandleData*)info->scratchBuffer; + if (scratchBufferData->type != HANDLE_TYPE_BUFFER) { + return PAL_RESULT_INVALID_BUFFER; + } + + PalGeometry* tmp = tmpBuildInfoGeometries[i]; + PalAccelerationStructureBuildInfo buildInfo = {0}; + buildInfo.scratchBuffer = scratchBufferData->handle; + buildInfo.dst = asData->handle; + buildInfo.scratchBufferOffset = info->scratchBufferOffset; + + if (info->geometriesCount >= 1) { + // geometry path + tmp = palAllocate( + s_Graphics.allocator, + sizeof(PalGeometry) * info->geometriesCount, + 0); + + if (!tmp) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + buildInfo.instanceCount = info->instanceCount; + for (int i = 0; i < info->instanceCount; i++) { + PalGeometry* srcGeometry = &info->instances[i]; + PalGeometry* dstGeometry = &tmp[i]; + dstGeometry->type = srcGeometry->type; + dstGeometry->primitiveCount = srcGeometry->primitiveCount; + + if (srcGeometry->type == PAL_GEOMETRY_TYPE_AABBS) { + PalGeometryDataAABBS* dstData = dstGeometry->data; + PalGeometryDataAABBS* srcData = srcGeometry->data; + dstData->count = srcData->count; + dstData->offset = srcData->offset; + dstData->stride = srcData->stride; + + HandleData* BufferData = (HandleData*)srcData->buffer; + dstData->buffer = BufferData->handle; + + } else { + // triangle + PalGeometryDataTriangle* dstData = dstGeometry->data; + PalGeometryDataTriangle* srcData = srcGeometry->data; + + dstData->indexCount = srcData->indexCount; + dstData->indexOffset = srcData->indexOffset; + dstData->indexType = srcData->indexType; + dstData->vertexCount = srcData->vertexCount; + dstData->vertexOffset = srcData->vertexOffset; + dstData->vertexStride = srcData->vertexStride; + dstData->vertexType = srcData->vertexType; + + HandleData* BufferData = (HandleData*)srcData->vertexBuffer; + dstData->vertexBuffer = BufferData->handle; + + // index buffer + BufferData = (HandleData*)srcData->indexBuffer; + dstData->indexBuffer = BufferData->handle; + } + } + + } else { + // instance path + tmp = palAllocate( + s_Graphics.allocator, + sizeof(PalGeometry) * info->instanceCount, + 0); + + if (!tmp) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + buildInfo.instanceCount = info->instanceCount; + for (int i = 0; i < info->instanceCount; i++) { + PalGeometry* srcGeometry = &info->instances[i]; + PalGeometry* dstGeometry = &tmp[i]; + dstGeometry->type = srcGeometry->type; + dstGeometry->primitiveCount = srcGeometry->primitiveCount; + + // always instance data in instance path + PalGeometryDataInstance* dstData = dstGeometry->data; + PalGeometryDataInstance* srcData = srcGeometry->data; + dstData->count = srcData->count; + dstData->offset = srcData->offset; + + HandleData* bufferData = (HandleData*)srcData->buffer; + dstData->buffer = bufferData->handle; + } + } + } + + PalResult result = data->backend->buildAccelerationStructures( + data->handle, + infoCount, + tmpInfos); + + // free the allocated arrays + for (int i = 0; i < infoCount; i++) { + PalGeometry* tmp = tmpBuildInfoGeometries[i]; + palFree(s_Graphics.allocator, tmp); + } + + if (free) { + palFree(s_Graphics.allocator, tmpInfos); + } + + return result; +} + PalResult PAL_CALL palBeginRenderPass( PalCommandBuffer* cmdBuffer, PalRenderPass* renderPass, @@ -2445,6 +2620,208 @@ PalResult PAL_CALL palSubmitCommandBuffer( &submitInfo); } +// ================================================== +// Ray Tracing Pipeline +// ================================================== + +PalResult PAL_CALL palCreateAccelerationstructure( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outAs) { + return PAL_RESULT_NULL_POINTER; + } + + if (!info->buffer) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* deviceData = (HandleData*)device; + if (deviceData->type != HANDLE_TYPE_DEVICE) { + return PAL_RESULT_INVALID_DEVICE; + } + + HandleData* bufferData = (HandleData*)info->buffer; + if (bufferData->type != HANDLE_TYPE_BUFFER) { + return PAL_RESULT_INVALID_BUFFER; + } + + // create a slot for the acceleration structure + HandleData* asData = getFreeHandleData(); + if (!asData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + PalAccelerationStructureCreateInfo createInfo; + createInfo.buffer = bufferData->handle; + createInfo.type = info->type; + createInfo.offset = info->offset; + createInfo.size = info->size; + + PalResult ret; + PalAccelerationStructure* as = nullptr; + ret = deviceData->backend->createAccelerationstructure( + deviceData->handle, + &createInfo, + &as); + + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + + asData->backend = deviceData->backend; + asData->handle = as; + asData->type = HANDLE_TYPE_ACCELERATION_STRUCTURE; + asData->features = deviceData->features; + + *outAs = (PalAccelerationStructure*)asData; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyAccelerationstructure( + PalAccelerationStructure* as) +{ + if (s_Graphics.initialized && as) { + HandleData* data = (HandleData*)as; + if (data->type == HANDLE_TYPE_ACCELERATION_STRUCTURE) { + data->backend->destroyAccelerationstructure(data->handle); + freeHandleData(data); + } + } +} + +PalResult PAL_CALL palGetAccelerationStructureBuildSize( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !size) { + return PAL_RESULT_NULL_POINTER; + } + + if (!info->scratchBuffer || !info->dst) { + return PAL_RESULT_NULL_POINTER; + } + + HandleData* deviceData = (HandleData*)device; + if (deviceData->type != HANDLE_TYPE_DEVICE) { + return PAL_RESULT_INVALID_DEVICE; + } + + // scratch buffer and acceleration source + HandleData* asData = (HandleData*)info->dst; + if (asData->type != HANDLE_TYPE_ACCELERATION_STRUCTURE) { + return PAL_RESULT_INVALID_ACCELERATION_STRUCTURE; + } + + HandleData* scratchBufferData = (HandleData*)info->scratchBuffer; + if (scratchBufferData->type != HANDLE_TYPE_BUFFER) { + return PAL_RESULT_INVALID_BUFFER; + } + + PalGeometry* tmp = nullptr; + PalAccelerationStructureBuildInfo buildInfo = {0}; + buildInfo.scratchBuffer = scratchBufferData->handle; + buildInfo.dst = asData->handle; + buildInfo.scratchBufferOffset = info->scratchBufferOffset; + + if (info->geometriesCount >= 1) { + // geometry path + tmp = palAllocate( + s_Graphics.allocator, + sizeof(PalGeometry) * info->geometriesCount, + 0); + + if (!tmp) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + buildInfo.instanceCount = info->instanceCount; + for (int i = 0; i < info->instanceCount; i++) { + PalGeometry* srcGeometry = &info->instances[i]; + PalGeometry* dstGeometry = &tmp[i]; + dstGeometry->type = srcGeometry->type; + dstGeometry->primitiveCount = srcGeometry->primitiveCount; + + if (srcGeometry->type == PAL_GEOMETRY_TYPE_AABBS) { + PalGeometryDataAABBS* dstData = dstGeometry->data; + PalGeometryDataAABBS* srcData = srcGeometry->data; + dstData->count = srcData->count; + dstData->offset = srcData->offset; + dstData->stride = srcData->stride; + + HandleData* BufferData = (HandleData*)srcData->buffer; + dstData->buffer = BufferData->handle; + + } else { + // triangle + PalGeometryDataTriangle* dstData = dstGeometry->data; + PalGeometryDataTriangle* srcData = srcGeometry->data; + + dstData->indexCount = srcData->indexCount; + dstData->indexOffset = srcData->indexOffset; + dstData->indexType = srcData->indexType; + dstData->vertexCount = srcData->vertexCount; + dstData->vertexOffset = srcData->vertexOffset; + dstData->vertexStride = srcData->vertexStride; + dstData->vertexType = srcData->vertexType; + + HandleData* BufferData = (HandleData*)srcData->vertexBuffer; + dstData->vertexBuffer = BufferData->handle; + + // index buffer + BufferData = (HandleData*)srcData->indexBuffer; + dstData->indexBuffer = BufferData->handle; + } + } + + } else { + // instance path + tmp = palAllocate( + s_Graphics.allocator, + sizeof(PalGeometry) * info->instanceCount, + 0); + + if (!tmp) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + buildInfo.instanceCount = info->instanceCount; + for (int i = 0; i < info->instanceCount; i++) { + PalGeometry* srcGeometry = &info->instances[i]; + PalGeometry* dstGeometry = &tmp[i]; + dstGeometry->type = srcGeometry->type; + dstGeometry->primitiveCount = srcGeometry->primitiveCount; + + // always instance data in instance path + PalGeometryDataInstance* dstData = dstGeometry->data; + PalGeometryDataInstance* srcData = srcGeometry->data; + dstData->count = srcData->count; + dstData->offset = srcData->offset; + + HandleData* bufferData = (HandleData*)srcData->buffer; + dstData->buffer = bufferData->handle; + } + } + + PalResult result = deviceData->backend->getAccelerationStructureBuildSize( + deviceData->handle, + &buildInfo, + size); + + palFree(s_Graphics.allocator, tmp); + return result; +} + // ================================================== // Pipeline // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 08d76aeb..c9caefe8 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -192,8 +192,7 @@ struct PalDevice { PFN_vkGetAccelerationStructureBuildSizesKHR getAccelerationBuildsize; PFN_vkCmdBuildAccelerationStructuresKHR cmdBuildAccelerationStructures; PFN_vkGetAccelerationStructureDeviceAddressKHR getAccelerationDeviceAddress; - PFN_vkCmdCopyAccelerationStructureKHR cmdCopyAccelerationStructure; - PFN_vkCmdWriteAccelerationStructuresPropertiesKHR cmdWriteAccelerationProps; + PFN_vkCmdTraceRaysKHR cmdTraceRays; PFN_vkCreateRayTracingPipelinesKHR createRayTracingPipeline; PFN_vkCmdTraceRaysIndirectKHR cmdTraceRaysIndirect; @@ -273,6 +272,11 @@ struct PalBuffer { VkBuffer handle; }; +struct PalAccelerationStructure { + PalDevice* device; + VkAccelerationStructureKHR handle; +}; + static Vulkan s_Vk = {0}; // ================================================== @@ -2570,16 +2574,6 @@ PalResult PAL_CALL createVkDevice( device->handle, "vkGetAccelerationStructureDeviceAddressKHR"); - device->cmdCopyAccelerationStructure = - (PFN_vkCmdCopyAccelerationStructureKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdCopyAccelerationStructureKHR"); - - device->cmdWriteAccelerationProps = - (PFN_vkCmdWriteAccelerationStructuresPropertiesKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdWriteAccelerationStructuresPropertiesKHR"); - device->cmdTraceRays = (PFN_vkCmdTraceRaysKHR)s_Vk.getDeviceProcAddr( device->handle, @@ -4364,7 +4358,7 @@ void PAL_CALL destroyVkCommandPool(PalCommandPool* pool) PalResult PAL_CALL createVkCommandBuffer( PalDevice* device, PalCommandPool* pool, - bool primary, + PalCommandBufferType type, PalCommandBuffer** outCmdBuffer) { VkResult result; @@ -4378,9 +4372,12 @@ PalResult PAL_CALL createVkCommandBuffer( createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; createInfo.commandBufferCount = 1; createInfo.commandPool = pool->handle; + createInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - if (!primary) { + cmdBuffer->primary = true; + if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + cmdBuffer->primary = false; } result = s_Vk.createCommandBuffer( @@ -4393,14 +4390,9 @@ PalResult PAL_CALL createVkCommandBuffer( return vkResultToPal(result); } - if (primary) { - cmdBuffer->primary = true; - } else { - cmdBuffer->primary = false; - } - cmdBuffer->device = device; cmdBuffer->pool = pool->handle; + *outCmdBuffer = cmdBuffer; return PAL_RESULT_SUCCESS; } @@ -4528,6 +4520,15 @@ PalResult PAL_CALL drawVkMeshTasksIndirectCount( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL buildVkAccelerationStructures( + PalDevice* device, + Int32 infoCount, + PalAccelerationStructureBuildInfo* infos) +{ + + +} + PalResult PAL_CALL beginRenderPassVk( PalCommandBuffer* cmdBuffer, PalRenderPass* renderPass, @@ -4639,6 +4640,109 @@ PalResult PAL_CALL submitVkCommandBuffer( return PAL_RESULT_SUCCESS; } +// ================================================== +// Ray Tracing Pipeline +// ================================================== + +PalResult PAL_CALL createVkAccelerationstructure( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs) +{ + VkResult result; + PalAccelerationStructure* as = nullptr; + as = palAllocate(s_Vk.allocator, sizeof(PalAccelerationStructure), 0); + if (!as) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkAccelerationStructureCreateInfoKHR createInfo = {0}; + createInfo.sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; + + createInfo.offset = (VkDeviceSize)info->offset; + createInfo.size = (VkDeviceSize)info->size; + createInfo.buffer = info->buffer->handle; + createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + } + + result = device->createAccelerationStructure( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &as->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, as); + return vkResultToPal(result); + } + + *outAs = as; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkAccelerationstructure( + PalAccelerationStructure* as) +{ + as->device->destroyAccelerationStructure( + as->device->handle, + as->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, as); +} + +PalResult PAL_CALL getVkAccelerationStructureBuildSize( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size) +{ + Uint32* maxPrimities = nullptr; + Uint32 count = info->geometriesCount; + PalGeometry* geometries = info->geometries; + + if (info->instanceCount) { + count = info->instanceCount; + geometries = info->instances; + } + + maxPrimities = palAllocate(s_Vk.allocator, sizeof(Uint32) * count, 0); + if (!maxPrimities) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + for (int i = 0; i < count; i++) { + maxPrimities[i] = geometries[i].primitiveCount; + } + + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + buildInfo.dstAccelerationStructure = info->dst; + // buildInfo.ppGeometries + + + buildInfo.sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + + VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; + sizeInfo.sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; + + device->getAccelerationBuildsize( + device->handle, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + &buildInfo, + &count, + &sizeInfo); + + size->accelerationStructureSize = sizeInfo.accelerationStructureSize; + size->scratchBufferSize = sizeInfo.buildScratchSize; + + return PAL_RESULT_SUCCESS; +} + // ================================================== // Pipeline // ================================================== diff --git a/src/pal_core.c b/src/pal_core.c index 51f42f82..74cd1576 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -443,6 +443,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_RENDER_PASS: return "Invalid render pass"; + + case PAL_RESULT_INVALID_ACCELERATION_STRUCTURE: + return "Invalid acceleration structure"; } return "Unknown"; } From cc85d30b9435d42d708d56d15d3d6f3ea93da81a Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 23 Dec 2025 13:05:36 +0000 Subject: [PATCH 062/372] start API handles restructure --- src/graphics/pal_graphics.c | 478 ++++++++++++++++++------------------ 1 file changed, 239 insertions(+), 239 deletions(-) diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 15284b00..17d6a228 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -2359,153 +2359,153 @@ PalResult PAL_CALL palBuildAccelerationStructures( Int32 infoCount, PalAccelerationStructureBuildInfo* infos) { - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device || !infos || infoCount <= 0) { - return PAL_RESULT_NULL_POINTER; - } - - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - // fast path. 1 to 4 build info - bool free = false; - PalAccelerationStructureBuildInfo buildInfos[4]; - PalAccelerationStructureBuildInfo* tmpInfos = buildInfos; - if (infoCount > 4) { - // allocate memory - tmpInfos = nullptr; - tmpInfos = palAllocate( - s_Graphics.allocator, - sizeof(PalAccelerationStructureBuildInfo) * infoCount, - 0); - - if (!tmpInfos) { - return PAL_RESULT_OUT_OF_MEMORY; - } - free = true; - } - - PalGeometry* tmpBuildInfoGeometries[8]; - for (int i = 0; i < infoCount; i++) { - PalAccelerationStructureBuildInfo* info = &tmpInfos[i]; - // scratch buffer and acceleration source - HandleData* asData = (HandleData*)info->dst; - if (asData->type != HANDLE_TYPE_ACCELERATION_STRUCTURE) { - return PAL_RESULT_INVALID_ACCELERATION_STRUCTURE; - } - - HandleData* scratchBufferData = (HandleData*)info->scratchBuffer; - if (scratchBufferData->type != HANDLE_TYPE_BUFFER) { - return PAL_RESULT_INVALID_BUFFER; - } - - PalGeometry* tmp = tmpBuildInfoGeometries[i]; - PalAccelerationStructureBuildInfo buildInfo = {0}; - buildInfo.scratchBuffer = scratchBufferData->handle; - buildInfo.dst = asData->handle; - buildInfo.scratchBufferOffset = info->scratchBufferOffset; - - if (info->geometriesCount >= 1) { - // geometry path - tmp = palAllocate( - s_Graphics.allocator, - sizeof(PalGeometry) * info->geometriesCount, - 0); - - if (!tmp) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - buildInfo.instanceCount = info->instanceCount; - for (int i = 0; i < info->instanceCount; i++) { - PalGeometry* srcGeometry = &info->instances[i]; - PalGeometry* dstGeometry = &tmp[i]; - dstGeometry->type = srcGeometry->type; - dstGeometry->primitiveCount = srcGeometry->primitiveCount; - - if (srcGeometry->type == PAL_GEOMETRY_TYPE_AABBS) { - PalGeometryDataAABBS* dstData = dstGeometry->data; - PalGeometryDataAABBS* srcData = srcGeometry->data; - dstData->count = srcData->count; - dstData->offset = srcData->offset; - dstData->stride = srcData->stride; - - HandleData* BufferData = (HandleData*)srcData->buffer; - dstData->buffer = BufferData->handle; - - } else { - // triangle - PalGeometryDataTriangle* dstData = dstGeometry->data; - PalGeometryDataTriangle* srcData = srcGeometry->data; - - dstData->indexCount = srcData->indexCount; - dstData->indexOffset = srcData->indexOffset; - dstData->indexType = srcData->indexType; - dstData->vertexCount = srcData->vertexCount; - dstData->vertexOffset = srcData->vertexOffset; - dstData->vertexStride = srcData->vertexStride; - dstData->vertexType = srcData->vertexType; - - HandleData* BufferData = (HandleData*)srcData->vertexBuffer; - dstData->vertexBuffer = BufferData->handle; - - // index buffer - BufferData = (HandleData*)srcData->indexBuffer; - dstData->indexBuffer = BufferData->handle; - } - } - - } else { - // instance path - tmp = palAllocate( - s_Graphics.allocator, - sizeof(PalGeometry) * info->instanceCount, - 0); - - if (!tmp) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - buildInfo.instanceCount = info->instanceCount; - for (int i = 0; i < info->instanceCount; i++) { - PalGeometry* srcGeometry = &info->instances[i]; - PalGeometry* dstGeometry = &tmp[i]; - dstGeometry->type = srcGeometry->type; - dstGeometry->primitiveCount = srcGeometry->primitiveCount; - - // always instance data in instance path - PalGeometryDataInstance* dstData = dstGeometry->data; - PalGeometryDataInstance* srcData = srcGeometry->data; - dstData->count = srcData->count; - dstData->offset = srcData->offset; - - HandleData* bufferData = (HandleData*)srcData->buffer; - dstData->buffer = bufferData->handle; - } - } - } - - PalResult result = data->backend->buildAccelerationStructures( - data->handle, - infoCount, - tmpInfos); - - // free the allocated arrays - for (int i = 0; i < infoCount; i++) { - PalGeometry* tmp = tmpBuildInfoGeometries[i]; - palFree(s_Graphics.allocator, tmp); - } - - if (free) { - palFree(s_Graphics.allocator, tmpInfos); - } - - return result; + // if (!s_Graphics.initialized) { + // return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + // } + + // if (!device || !infos || infoCount <= 0) { + // return PAL_RESULT_NULL_POINTER; + // } + + // HandleData* data = (HandleData*)device; + // if (data->type != HANDLE_TYPE_DEVICE) { + // return PAL_RESULT_INVALID_COMMAND_BUFFER; + // } + + // // fast path. 1 to 4 build info + // bool free = false; + // PalAccelerationStructureBuildInfo buildInfos[4]; + // PalAccelerationStructureBuildInfo* tmpInfos = buildInfos; + // if (infoCount > 4) { + // // allocate memory + // tmpInfos = nullptr; + // tmpInfos = palAllocate( + // s_Graphics.allocator, + // sizeof(PalAccelerationStructureBuildInfo) * infoCount, + // 0); + + // if (!tmpInfos) { + // return PAL_RESULT_OUT_OF_MEMORY; + // } + // free = true; + // } + + // PalGeometry* tmpBuildInfoGeometries[8]; + // for (int i = 0; i < infoCount; i++) { + // PalAccelerationStructureBuildInfo* info = &tmpInfos[i]; + // // scratch buffer and acceleration source + // HandleData* asData = (HandleData*)info->dst; + // if (asData->type != HANDLE_TYPE_ACCELERATION_STRUCTURE) { + // return PAL_RESULT_INVALID_ACCELERATION_STRUCTURE; + // } + + // HandleData* scratchBufferData = (HandleData*)info->scratchBuffer; + // if (scratchBufferData->type != HANDLE_TYPE_BUFFER) { + // return PAL_RESULT_INVALID_BUFFER; + // } + + // PalGeometry* tmp = tmpBuildInfoGeometries[i]; + // PalAccelerationStructureBuildInfo buildInfo = {0}; + // buildInfo.scratchBuffer = scratchBufferData->handle; + // buildInfo.dst = asData->handle; + // buildInfo.scratchBufferOffset = info->scratchBufferOffset; + + // if (info->geometriesCount >= 1) { + // // geometry path + // tmp = palAllocate( + // s_Graphics.allocator, + // sizeof(PalGeometry) * info->geometriesCount, + // 0); + + // if (!tmp) { + // return PAL_RESULT_OUT_OF_MEMORY; + // } + + // buildInfo.instanceCount = info->instanceCount; + // for (int i = 0; i < info->instanceCount; i++) { + // PalGeometry* srcGeometry = &info->instances[i]; + // PalGeometry* dstGeometry = &tmp[i]; + // dstGeometry->type = srcGeometry->type; + // dstGeometry->primitiveCount = srcGeometry->primitiveCount; + + // if (srcGeometry->type == PAL_GEOMETRY_TYPE_AABBS) { + // PalGeometryDataAABBS* dstData = dstGeometry->data; + // PalGeometryDataAABBS* srcData = srcGeometry->data; + // dstData->count = srcData->count; + // dstData->offset = srcData->offset; + // dstData->stride = srcData->stride; + + // HandleData* BufferData = (HandleData*)srcData->buffer; + // dstData->buffer = BufferData->handle; + + // } else { + // // triangle + // PalGeometryDataTriangle* dstData = dstGeometry->data; + // PalGeometryDataTriangle* srcData = srcGeometry->data; + + // dstData->indexCount = srcData->indexCount; + // dstData->indexOffset = srcData->indexOffset; + // dstData->indexType = srcData->indexType; + // dstData->vertexCount = srcData->vertexCount; + // dstData->vertexOffset = srcData->vertexOffset; + // dstData->vertexStride = srcData->vertexStride; + // dstData->vertexType = srcData->vertexType; + + // HandleData* BufferData = (HandleData*)srcData->vertexBuffer; + // dstData->vertexBuffer = BufferData->handle; + + // // index buffer + // BufferData = (HandleData*)srcData->indexBuffer; + // dstData->indexBuffer = BufferData->handle; + // } + // } + + // } else { + // // instance path + // tmp = palAllocate( + // s_Graphics.allocator, + // sizeof(PalGeometry) * info->instanceCount, + // 0); + + // if (!tmp) { + // return PAL_RESULT_OUT_OF_MEMORY; + // } + + // buildInfo.instanceCount = info->instanceCount; + // for (int i = 0; i < info->instanceCount; i++) { + // PalGeometry* srcGeometry = &info->instances[i]; + // PalGeometry* dstGeometry = &tmp[i]; + // dstGeometry->type = srcGeometry->type; + // dstGeometry->primitiveCount = srcGeometry->primitiveCount; + + // // always instance data in instance path + // PalGeometryDataInstance* dstData = dstGeometry->data; + // PalGeometryDataInstance* srcData = srcGeometry->data; + // dstData->count = srcData->count; + // dstData->offset = srcData->offset; + + // HandleData* bufferData = (HandleData*)srcData->buffer; + // dstData->buffer = bufferData->handle; + // } + // } + // } + + // PalResult result = data->backend->buildAccelerationStructures( + // data->handle, + // infoCount, + // tmpInfos); + + // // free the allocated arrays + // for (int i = 0; i < infoCount; i++) { + // PalGeometry* tmp = tmpBuildInfoGeometries[i]; + // palFree(s_Graphics.allocator, tmp); + // } + + // if (free) { + // palFree(s_Graphics.allocator, tmpInfos); + // } + + // return result; } PalResult PAL_CALL palBeginRenderPass( @@ -2728,98 +2728,98 @@ PalResult PAL_CALL palGetAccelerationStructureBuildSize( return PAL_RESULT_INVALID_BUFFER; } - PalGeometry* tmp = nullptr; - PalAccelerationStructureBuildInfo buildInfo = {0}; - buildInfo.scratchBuffer = scratchBufferData->handle; - buildInfo.dst = asData->handle; - buildInfo.scratchBufferOffset = info->scratchBufferOffset; - - if (info->geometriesCount >= 1) { - // geometry path - tmp = palAllocate( - s_Graphics.allocator, - sizeof(PalGeometry) * info->geometriesCount, - 0); - - if (!tmp) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - buildInfo.instanceCount = info->instanceCount; - for (int i = 0; i < info->instanceCount; i++) { - PalGeometry* srcGeometry = &info->instances[i]; - PalGeometry* dstGeometry = &tmp[i]; - dstGeometry->type = srcGeometry->type; - dstGeometry->primitiveCount = srcGeometry->primitiveCount; - - if (srcGeometry->type == PAL_GEOMETRY_TYPE_AABBS) { - PalGeometryDataAABBS* dstData = dstGeometry->data; - PalGeometryDataAABBS* srcData = srcGeometry->data; - dstData->count = srcData->count; - dstData->offset = srcData->offset; - dstData->stride = srcData->stride; - - HandleData* BufferData = (HandleData*)srcData->buffer; - dstData->buffer = BufferData->handle; - - } else { - // triangle - PalGeometryDataTriangle* dstData = dstGeometry->data; - PalGeometryDataTriangle* srcData = srcGeometry->data; - - dstData->indexCount = srcData->indexCount; - dstData->indexOffset = srcData->indexOffset; - dstData->indexType = srcData->indexType; - dstData->vertexCount = srcData->vertexCount; - dstData->vertexOffset = srcData->vertexOffset; - dstData->vertexStride = srcData->vertexStride; - dstData->vertexType = srcData->vertexType; - - HandleData* BufferData = (HandleData*)srcData->vertexBuffer; - dstData->vertexBuffer = BufferData->handle; - - // index buffer - BufferData = (HandleData*)srcData->indexBuffer; - dstData->indexBuffer = BufferData->handle; - } - } - - } else { - // instance path - tmp = palAllocate( - s_Graphics.allocator, - sizeof(PalGeometry) * info->instanceCount, - 0); - - if (!tmp) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - buildInfo.instanceCount = info->instanceCount; - for (int i = 0; i < info->instanceCount; i++) { - PalGeometry* srcGeometry = &info->instances[i]; - PalGeometry* dstGeometry = &tmp[i]; - dstGeometry->type = srcGeometry->type; - dstGeometry->primitiveCount = srcGeometry->primitiveCount; - - // always instance data in instance path - PalGeometryDataInstance* dstData = dstGeometry->data; - PalGeometryDataInstance* srcData = srcGeometry->data; - dstData->count = srcData->count; - dstData->offset = srcData->offset; - - HandleData* bufferData = (HandleData*)srcData->buffer; - dstData->buffer = bufferData->handle; - } - } - - PalResult result = deviceData->backend->getAccelerationStructureBuildSize( - deviceData->handle, - &buildInfo, - size); - - palFree(s_Graphics.allocator, tmp); - return result; + // PalGeometry* tmp = nullptr; + // PalAccelerationStructureBuildInfo buildInfo = {0}; + // buildInfo.scratchBuffer = scratchBufferData->handle; + // buildInfo.dst = asData->handle; + // buildInfo.scratchBufferOffset = info->scratchBufferOffset; + + // if (info->geometriesCount >= 1) { + // // geometry path + // tmp = palAllocate( + // s_Graphics.allocator, + // sizeof(PalGeometry) * info->geometriesCount, + // 0); + + // if (!tmp) { + // return PAL_RESULT_OUT_OF_MEMORY; + // } + + // buildInfo.instanceCount = info->instanceCount; + // for (int i = 0; i < info->instanceCount; i++) { + // PalGeometry* srcGeometry = &info->instances[i]; + // PalGeometry* dstGeometry = &tmp[i]; + // dstGeometry->type = srcGeometry->type; + // dstGeometry->primitiveCount = srcGeometry->primitiveCount; + + // if (srcGeometry->type == PAL_GEOMETRY_TYPE_AABBS) { + // PalGeometryDataAABBS* dstData = dstGeometry->data; + // PalGeometryDataAABBS* srcData = srcGeometry->data; + // dstData->count = srcData->count; + // dstData->offset = srcData->offset; + // dstData->stride = srcData->stride; + + // HandleData* BufferData = (HandleData*)srcData->buffer; + // dstData->buffer = BufferData->handle; + + // } else { + // // triangle + // PalGeometryDataTriangle* dstData = dstGeometry->data; + // PalGeometryDataTriangle* srcData = srcGeometry->data; + + // dstData->indexCount = srcData->indexCount; + // dstData->indexOffset = srcData->indexOffset; + // dstData->indexType = srcData->indexType; + // dstData->vertexCount = srcData->vertexCount; + // dstData->vertexOffset = srcData->vertexOffset; + // dstData->vertexStride = srcData->vertexStride; + // dstData->vertexType = srcData->vertexType; + + // HandleData* BufferData = (HandleData*)srcData->vertexBuffer; + // dstData->vertexBuffer = BufferData->handle; + + // // index buffer + // BufferData = (HandleData*)srcData->indexBuffer; + // dstData->indexBuffer = BufferData->handle; + // } + // } + + // } else { + // // instance path + // tmp = palAllocate( + // s_Graphics.allocator, + // sizeof(PalGeometry) * info->instanceCount, + // 0); + + // if (!tmp) { + // return PAL_RESULT_OUT_OF_MEMORY; + // } + + // buildInfo.instanceCount = info->instanceCount; + // for (int i = 0; i < info->instanceCount; i++) { + // PalGeometry* srcGeometry = &info->instances[i]; + // PalGeometry* dstGeometry = &tmp[i]; + // dstGeometry->type = srcGeometry->type; + // dstGeometry->primitiveCount = srcGeometry->primitiveCount; + + // // always instance data in instance path + // PalGeometryDataInstance* dstData = dstGeometry->data; + // PalGeometryDataInstance* srcData = srcGeometry->data; + // dstData->count = srcData->count; + // dstData->offset = srcData->offset; + + // HandleData* bufferData = (HandleData*)srcData->buffer; + // dstData->buffer = bufferData->handle; + // } + // } + + // PalResult result = deviceData->backend->getAccelerationStructureBuildSize( + // deviceData->handle, + // &buildInfo, + // size); + + // palFree(s_Graphics.allocator, tmp); + // return result; } // ================================================== From 5e7142f42a66350e9a03bbf20618aa2ed3af0cc8 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 23 Dec 2025 22:58:11 +0000 Subject: [PATCH 063/372] end API handles restructure --- include/pal/pal_graphics.h | 8 - src/graphics/pal_graphics.c | 1632 +++++------------------------------ src/graphics/pal_vulkan.c | 884 ++++++++++++------- tests/clear_color_test.c | 7 +- tests/tests_main.c | 2 +- 5 files changed, 792 insertions(+), 1741 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 873b8f9e..2a064e51 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1234,8 +1234,6 @@ PAL_API PalResult PAL_CALL palCreateSwapchain( PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); -PAL_API Uint32 PAL_CALL palGetSwapchainImageCount(PalSwapchain* swapchain); - PAL_API PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, Int32 index); @@ -1255,8 +1253,6 @@ PAL_API PalResult PAL_CALL palCreateShader( PAL_API void PAL_CALL palDestroyShader(PalShader* shader); -PAL_API PalShaderType PAL_CALL palGetShaderType(PalShader* shader); - PAL_API PalResult PAL_CALL palCreateRenderPass( PalDevice* device, const PalRenderPassCreateInfo* info, @@ -1306,8 +1302,6 @@ PAL_API PalResult PAL_CALL palGetSemaphoreValue( PalSemaphore* semaphore, Uint64* value); -PAL_API bool PAL_CALL palIsTimelineSemaphore(PalSemaphore* semaphore); - PAL_API PalResult PAL_CALL palCreateCommandBuffer( PalDevice* device, PalCommandPool* pool, @@ -1383,8 +1377,6 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); -PAL_API bool PAL_CALL palIsGraphicsPipeline(PalPipeline* pipeline); - /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 17d6a228..ac83b530 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -32,41 +32,24 @@ freely, subject to the following restrictions: // ================================================== #define MAX_BACKENDS 32 -#define BINARY_SEMAPHORE 4 -#define TIMELINE_SEMAPHORE 5 -#define GRAPHICS_PIPELINE 6 -#define COMPUTE_PIPELINE 7 -#define SWAPCHAIN_IMAGE 12 - -typedef enum { - HANDLE_TYPE_NONE, - HANDLE_TYPE_ADAPTER, - HANDLE_TYPE_DEVICE, - HANDLE_TYPE_IMAGE, - HANDLE_TYPE_IMAGE_VIEW, - HANDLE_TYPE_SWAPCHAIN, - HANDLE_TYPE_RENDER_PASS, - HANDLE_TYPE_COMMAND_POOL, - HANDLE_TYPE_COMMAND_BUFFER, - HANDLE_TYPE_QUEUE, - HANDLE_TYPE_FENCE, - HANDLE_TYPE_SEMAPHORE, - HANDLE_TYPE_PIPELINE, - HANDLE_TYPE_SHADER, - HANDLE_TYPE_BUFFER, - HANDLE_TYPE_ACCELERATION_STRUCTURE -} HandleType; - -typedef struct { - bool used; - bool shouldFree; - HandleType type; - Uint32 data2; - PalAdapterFeatures features; - void* handle; - void* data; - const PalGraphicsBackend* backend; -} HandleData; +#define PAL_HANDLE(name) struct name { const PalGraphicsBackend* backend; }; + +PAL_HANDLE(PalAdapter) +PAL_HANDLE(PalDevice) +PAL_HANDLE(PalQueue) +PAL_HANDLE(PalSwapchain) +PAL_HANDLE(PalImage) +PAL_HANDLE(PalImageView) +PAL_HANDLE(PalShader) +PAL_HANDLE(PalRenderPass) +PAL_HANDLE(PalBuffer) + +PAL_HANDLE(PalFence) +PAL_HANDLE(PalSemaphore) +PAL_HANDLE(PalCommandPool) +PAL_HANDLE(PalCommandBuffer) +PAL_HANDLE(PalPipeline) +PAL_HANDLE(PalAccelerationStructure) typedef struct { Int32 count; @@ -77,9 +60,7 @@ typedef struct { typedef struct { bool initialized; Int32 backendCount; - Int32 maxHandleData; const PalAllocator* allocator; - HandleData* handleData; BackendData backends[MAX_BACKENDS]; } GraphicsLinux; @@ -89,39 +70,6 @@ static GraphicsLinux s_Graphics = {0}; // Internal API // ================================================== -static HandleData* getFreeHandleData() -{ - for (int i = 0; i < s_Graphics.maxHandleData; ++i) { - if (!s_Graphics.handleData[i].used) { - s_Graphics.handleData[i].used = true; - s_Graphics.handleData[i].shouldFree = false; - s_Graphics.handleData[i].type = HANDLE_TYPE_NONE; - return &s_Graphics.handleData[i]; - } - } - - // It will be rare to have more than 128 handles at the same time - HandleData* data = nullptr; - data = palAllocate(s_Graphics.allocator, sizeof(HandleData), 0); - if (!data) { - return nullptr; - } - - data->used = true; - data->shouldFree = true; - data->type = HANDLE_TYPE_NONE; - return data; -} - -static void freeHandleData(HandleData* data) -{ - if (data->shouldFree) { - palFree(s_Graphics.allocator, data); - } else { - data->used = false; - } - data->type = HANDLE_TYPE_NONE; -} // ================================================== // Vulkan API @@ -584,16 +532,6 @@ PalResult PAL_CALL palInitGraphics( return PAL_RESULT_INVALID_ALLOCATOR; } - s_Graphics.maxHandleData = 128; - s_Graphics.handleData = palAllocate( - s_Graphics.allocator, - sizeof(HandleData) * s_Graphics.maxHandleData, - 0); - - if (!s_Graphics.handleData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - #ifdef _WIN32 // vulkan and d3d12 #elif defined(__linux__) @@ -629,7 +567,6 @@ void PAL_CALL palShutdownGraphics() // metal or andriod #endif // _WIN32 - palFree(s_Graphics.allocator, s_Graphics.handleData); memset(&s_Graphics, 0, sizeof(s_Graphics)); s_Graphics.initialized = false; } @@ -667,14 +604,8 @@ PalResult PAL_CALL palEnumerateAdapters( PalAdapter** adapters = &outAdapters[backend->startIndex]; result = backend->base->enumerateAdapters(&_count, adapters); - for (int i = 0; i < backend->count; i++) { - HandleData* data = getFreeHandleData(); - data->backend = backend->base; - data->handle = adapters[i]; - data->type = HANDLE_TYPE_ADAPTER; - - // set the adapter handle into our index generated handle - adapters[i] = (PalAdapter*)data; + for (int i = 0; i < _count; i++) { + adapters[i]->backend = backend->base; } } else { @@ -709,12 +640,7 @@ PalResult PAL_CALL palGetAdapterInfo( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)adapter; - if (data->type != HANDLE_TYPE_ADAPTER) { - return PAL_RESULT_INVALID_ADAPTER; - } - - return data->backend->getAdapterInfo(data->handle, info); + return adapter->backend->getAdapterInfo(adapter, info); } PalResult PAL_CALL palGetAdapterCapabilities( @@ -729,12 +655,7 @@ PalResult PAL_CALL palGetAdapterCapabilities( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)adapter; - if (data->type != HANDLE_TYPE_ADAPTER) { - return PAL_RESULT_INVALID_ADAPTER; - } - - return data->backend->getAdapterCapabilities(data->handle, caps); + return adapter->backend->getAdapterCapabilities(adapter, caps); } PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) @@ -747,12 +668,7 @@ PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) return 0; } - HandleData* data = (HandleData*)adapter; - if (data->type != HANDLE_TYPE_ADAPTER) { - return 0; - } - - return data->backend->getAdapterFeatures(data->handle); + return adapter->backend->getAdapterFeatures(adapter); } // ================================================== @@ -772,45 +688,26 @@ PalResult PAL_CALL palCreateDevice( return PAL_RESULT_NULL_POINTER; } - HandleData* adapterData = (HandleData*)adapter; - if (adapterData->type != HANDLE_TYPE_ADAPTER) { - return PAL_RESULT_INVALID_ADAPTER; - } - - // create a slot for the device - HandleData* deviceData = getFreeHandleData(); - if (!deviceData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - PalDevice* device = nullptr; - PalResult ret; - ret = adapterData->backend->createDevice( - adapterData->handle, + PalResult result; + result = adapter->backend->createDevice( + adapter, features, &device); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + if (result != PAL_RESULT_SUCCESS) { + return result; } - - deviceData->backend = adapterData->backend; - deviceData->handle = device; - deviceData->type = HANDLE_TYPE_DEVICE; - deviceData->features = features; - *outDevice = (PalDevice*)deviceData; + device->backend = adapter->backend; + *outDevice = device; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyDevice(PalDevice* device) { if (s_Graphics.initialized && device) { - HandleData* data = (HandleData*)device; - if (data->type == HANDLE_TYPE_DEVICE) { - data->backend->destroyDevice(data->handle); - freeHandleData(data); - } + device->backend->destroyDevice(device); } } @@ -828,13 +725,8 @@ PalResult PAL_CALL palAllocateMemory( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - return data->backend->allocateMemory( - data->handle, + return device->backend->allocateMemory( + device, type, size, outMemory); @@ -845,11 +737,7 @@ void PAL_CALL palFreeMemory( PalMemory* memory) { if (s_Graphics.initialized && device && memory) { - HandleData* data = (HandleData*)device; - if (data->type == HANDLE_TYPE_DEVICE) { - data->backend->freeMemory(data->handle, memory); - freeHandleData(data); - } + device->backend->freeMemory(device, memory); } } @@ -865,16 +753,7 @@ PalResult PAL_CALL palQueryDepthStencilCapabilities( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - if (!(data->features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - return data->backend->queryDepthStencilCapabilities(data->handle, caps); + return device->backend->queryDepthStencilCapabilities(device, caps); } PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( @@ -889,17 +768,8 @@ PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - if (!(data->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - return data->backend->queryFragmentShadingRateCapabilities( - data->handle, + return device->backend->queryFragmentShadingRateCapabilities( + device, caps); } @@ -915,17 +785,8 @@ PalResult PAL_CALL palQueryMeshShaderCapabilities( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - if (!(data->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - return data->backend->queryMeshShaderCapabilities( - data->handle, + return device->backend->queryMeshShaderCapabilities( + device, caps); } @@ -941,17 +802,8 @@ PalResult PAL_CALL palQueryRayTracingCapabilities( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - if (!(data->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - return data->backend->queryRayTracingCapabilities( - data->handle, + return device->backend->queryRayTracingCapabilities( + device, caps); } @@ -972,45 +824,26 @@ PalResult PAL_CALL palCreateQueue( return PAL_RESULT_NULL_POINTER; } - HandleData* deviceData = (HandleData*)device; - if (deviceData->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - // create a slot for the queue - HandleData* queueData = getFreeHandleData(); - if (!queueData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - PalQueue* queue = nullptr; - PalResult ret; - ret = deviceData->backend->createQueue( - deviceData->handle, + PalResult result; + result = device->backend->createQueue( + device, type, &queue); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + if (result != PAL_RESULT_SUCCESS) { + return result; } - queueData->backend = deviceData->backend; - queueData->handle = queue; - queueData->type = HANDLE_TYPE_QUEUE; - queueData->features = deviceData->features; - - *outQueue = (PalQueue*)queueData; + queue->backend = device->backend; + *outQueue = queue; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyQueue(PalQueue* queue) { if (s_Graphics.initialized && queue) { - HandleData* data = (HandleData*)queue; - if (data->type == HANDLE_TYPE_QUEUE) { - data->backend->destroyQueue(data->handle); - freeHandleData(data); - } + queue->backend->destroyQueue(queue); } } @@ -1019,10 +852,7 @@ bool PAL_CALL palCanQueuePresent( PalGraphicsWindow* window) { if (s_Graphics.initialized && queue) { - HandleData* data = (HandleData*)queue; - if (data->type == HANDLE_TYPE_QUEUE) { - return data->backend->canQueuePresent(data->handle, window); - } + return queue->backend->canQueuePresent(queue, window); } return false; } @@ -1048,12 +878,7 @@ PalResult PAL_CALL palEnumerateFormats( return PAL_RESULT_INSUFFICIENT_BUFFER; } - HandleData* data = (HandleData*)adapter; - if (data->type != HANDLE_TYPE_ADAPTER) { - return PAL_RESULT_INVALID_ADAPTER; - } - - return data->backend->enumerateFormats(data->handle, count, outFormats); + return adapter->backend->enumerateFormats(adapter, count, outFormats); } bool PAL_CALL palIsFormatSupported( @@ -1064,12 +889,7 @@ bool PAL_CALL palIsFormatSupported( return false; } - HandleData* data = (HandleData*)adapter; - if (data->type != HANDLE_TYPE_ADAPTER) { - return false; - } - - return data->backend->isFormatSupported(data->handle, format); + return adapter->backend->isFormatSupported(adapter, format); } PalImageUsages PAL_CALL palQueryFormatImageUsages( @@ -1080,12 +900,7 @@ PalImageUsages PAL_CALL palQueryFormatImageUsages( return PAL_IMAGE_USAGE_UNDEFINED; } - HandleData* data = (HandleData*)adapter; - if (data->type != HANDLE_TYPE_ADAPTER) { - return PAL_IMAGE_USAGE_UNDEFINED; - } - - return data->backend->queryFormatImageUsages(data->handle, format); + return adapter->backend->queryFormatImageUsages(adapter, format); } PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( @@ -1096,12 +911,7 @@ PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( return PAL_IMAGE_VIEW_USAGE_UNDEFINED; } - HandleData* data = (HandleData*)adapter; - if (data->type == HANDLE_TYPE_ADAPTER) { - return PAL_IMAGE_VIEW_USAGE_UNDEFINED; - } - - return data->backend->queryFormatImageViewUsages(data->handle, format); + return adapter->backend->queryFormatImageViewUsages(adapter, format); } // ================================================== @@ -1121,48 +931,26 @@ PalResult PAL_CALL palCreateImage( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - // create a slot for the image - HandleData* imageData = getFreeHandleData(); - if (!imageData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - PalImage* image = nullptr; - PalResult ret; - ret = data->backend->createImage( - data->handle, + PalResult result; + result = device->backend->createImage( + device, info, &image); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + if (result != PAL_RESULT_SUCCESS) { + return result; } - imageData->backend = data->backend; - imageData->handle = image; - imageData->type = HANDLE_TYPE_IMAGE; - imageData->data2 = 0; - imageData->features = data->features; - - *outImage = (PalImage*)imageData; + image->backend = device->backend; + *outImage = image; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyImage(PalImage* image) { if (s_Graphics.initialized && image) { - HandleData* data = (HandleData*)image; - if (data->type == HANDLE_TYPE_IMAGE) { - if (data->data2 == SWAPCHAIN_IMAGE) { - data->backend->destroyImage(data->handle); - freeHandleData(data); - } - } + image->backend->destroyImage(image); } } @@ -1178,12 +966,7 @@ PalResult PAL_CALL palGetImageInfo( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)image; - if (data->type != HANDLE_TYPE_IMAGE) { - return PAL_RESULT_INVALID_IMAGE; - } - - return data->backend->getImageInfo(data->handle, info); + return image->backend->getImageInfo(image, info); } PalResult PAL_CALL palGetImageMemoryRequirements( @@ -1198,17 +981,8 @@ PalResult PAL_CALL palGetImageMemoryRequirements( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)image; - if (data->type != HANDLE_TYPE_IMAGE) { - return PAL_RESULT_INVALID_IMAGE; - } - - if (data->data2 == SWAPCHAIN_IMAGE) { - return PAL_RESULT_INVALID_IMAGE; - } - - return data->backend->getImageMemoryRequirements( - data->handle, + return image->backend->getImageMemoryRequirements( + image, requirements); } @@ -1225,17 +999,8 @@ PalResult PAL_CALL palBindImageMemory( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)image; - if (data->type != HANDLE_TYPE_IMAGE) { - return PAL_RESULT_INVALID_IMAGE; - } - - if (data->data2 == SWAPCHAIN_IMAGE) { - return PAL_RESULT_INVALID_IMAGE; - } - - return data->backend->bindImageMemory( - data->handle, + return image->backend->bindImageMemory( + image, memory, offset); } @@ -1258,51 +1023,27 @@ PalResult PAL_CALL palCreateImageView( return PAL_RESULT_NULL_POINTER; } - HandleData* deviceData = (HandleData*)device; - HandleData* imageData = (HandleData*)image; - if (deviceData->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - if (imageData->type != HANDLE_TYPE_IMAGE) { - return PAL_RESULT_INVALID_IMAGE; - } - - // create a slot for the image view - HandleData* imageViewData = getFreeHandleData(); - if (!imageViewData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - PalImageView* imageView = nullptr; - PalResult ret; - ret = deviceData->backend->createImageView( - deviceData->handle, - imageData->handle, + PalResult result; + result = device->backend->createImageView( + device, + image, info, &imageView); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + if (result != PAL_RESULT_SUCCESS) { + return result; } - imageViewData->backend = deviceData->backend; - imageViewData->handle = imageView; - imageViewData->type = HANDLE_TYPE_IMAGE_VIEW; - imageViewData->features = deviceData->features; - - *outImageView = (PalImageView*)imageViewData; + imageView->backend = device->backend; + *outImageView = imageView; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyImageView(PalImageView* imageView) { if (s_Graphics.initialized && imageView) { - HandleData* data = (HandleData*)imageView; - if (data->type == HANDLE_TYPE_IMAGE_VIEW) { - data->backend->destroyImageView(data->handle); - freeHandleData(data); - } + imageView->backend->destroyImageView(imageView); } } @@ -1323,17 +1064,8 @@ PalResult PAL_CALL palQuerySwapchainCapabilities( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - if (!(data->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - return data->backend->querySwapchainCapabilities( - data->handle, + return device->backend->querySwapchainCapabilities( + device, window, caps); } @@ -1353,94 +1085,31 @@ PalResult PAL_CALL palCreateSwapchain( return PAL_RESULT_NULL_POINTER; } - HandleData* imagesData = nullptr; - imagesData = palAllocate( - s_Graphics.allocator, - sizeof(HandleData) * info->imageCount, - 0); - - if (!imagesData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - HandleData* deviceData = (HandleData*)device; - HandleData* queueData = (HandleData*)queue; - if (deviceData->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - if (queueData->type != HANDLE_TYPE_QUEUE) { - return PAL_RESULT_INVALID_QUEUE; - } - - // create a slot for the swapchain - HandleData* swapchainData = getFreeHandleData(); - if (!swapchainData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - PalResult ret; + PalResult result; PalSwapchain* swapchain = nullptr; - ret = deviceData->backend->createSwapchain( - deviceData->handle, - queueData->handle, + result = device->backend->createSwapchain( + device, + queue, window, info, &swapchain); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - // cache the swapchain images so we dont create new handles - // for them anytime they are queried - for (int i = 0; i < info->imageCount; i++) { - PalImage* image = deviceData->backend->getSwapchainImage(swapchain, i); - HandleData* tmp = &imagesData[i]; - tmp->backend = swapchainData->backend; - tmp->handle = image; - tmp->used = true; - tmp->shouldFree = false; // we free all at once - tmp->data = nullptr; - tmp->type = HANDLE_TYPE_IMAGE; - tmp->data2 = SWAPCHAIN_IMAGE; - tmp->features = deviceData->features; + if (result != PAL_RESULT_SUCCESS) { + return result; } - swapchainData->backend = deviceData->backend; - swapchainData->handle = swapchain; - swapchainData->data = (void*)imagesData; - swapchainData->data2 = info->imageCount; - swapchainData->type = HANDLE_TYPE_SWAPCHAIN; - swapchainData->features = deviceData->features; - - *outSwapchain = (PalSwapchain*)swapchainData; + swapchain->backend = device->backend; + *outSwapchain = swapchain; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) { if (s_Graphics.initialized && swapchain) { - HandleData* data = (HandleData*)swapchain; - if (data->type == HANDLE_TYPE_SWAPCHAIN) { - data->backend->destroySwapchain(data->handle); - palFree(s_Graphics.allocator, data->data); - freeHandleData(data); - } + swapchain->backend->destroySwapchain(swapchain); } } -Uint32 PAL_CALL palGetSwapchainImageCount(PalSwapchain* swapchain) -{ - if (s_Graphics.initialized && swapchain) { - HandleData* data = (HandleData*)swapchain; - if (data->type == HANDLE_TYPE_SWAPCHAIN) { - return data->data2; - } - } - return 0; -} - PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, Int32 index) @@ -1449,17 +1118,7 @@ PalImage* PAL_CALL palGetSwapchainImage( return nullptr; } - HandleData* data = (HandleData*)swapchain; - if (data->type != HANDLE_TYPE_SWAPCHAIN) { - return nullptr; - } - - if (index > data->data2) { - return nullptr; - } - - HandleData* imagesData = data->data; - return (PalImage*)&imagesData[index]; + return swapchain->backend->getSwapchainImage(swapchain, index); } PalImage* PAL_CALL palGetNextSwapchainImage( @@ -1470,53 +1129,9 @@ PalImage* PAL_CALL palGetNextSwapchainImage( return nullptr; } - HandleData* data = (HandleData*)swapchain; - if (data->type != HANDLE_TYPE_SWAPCHAIN) { - return nullptr; - } - - void* FenceHandle = nullptr; - void* signalSemaphoreHandle = nullptr; - HandleData* tmp = (HandleData*)info->signalSemaphore; - if (info->fence) { - tmp = (HandleData*)info->signalSemaphore; - if (tmp->type != HANDLE_TYPE_FENCE) { - return nullptr; - } - FenceHandle = tmp->handle; - } - - if (info->signalSemaphore) { - tmp = (HandleData*)info->signalSemaphore; - if (tmp->type != HANDLE_TYPE_SEMAPHORE) { - return nullptr; - } - signalSemaphoreHandle = tmp->handle; - } - - PalNextImageInfo nextInfo; - nextInfo.fence = FenceHandle; - nextInfo.signalSemaphore = signalSemaphoreHandle; - nextInfo.signalValue = info->signalValue; - nextInfo.timeout = info->timeout; - - PalImage* tmpImage = data->backend->getNextSwapchainImage( - data->handle, - &nextInfo); - - // loop through all our cache images and get the handle data - // associated with the image - HandleData* imagesData = data->data; - HandleData* imageData = nullptr; - for (int i = 0; i < data->data2; i++) { - if (imagesData[i].handle == tmpImage) { - // found our handle info - imageData = &imagesData[i]; - break; - } - } - - return (PalImage*)imageData; + return swapchain->backend->getNextSwapchainImage( + swapchain, + info); } PalResult PAL_CALL palPresentSwapchain( @@ -1531,37 +1146,9 @@ PalResult PAL_CALL palPresentSwapchain( return PAL_RESULT_NULL_POINTER; } - HandleData* swapchainData = (HandleData*)swapchain; - if (swapchainData->type != HANDLE_TYPE_SWAPCHAIN) { - return PAL_RESULT_INVALID_SWAPCHAIN; - } - - HandleData* imageData = (HandleData*)info->image; - if (imageData->type != HANDLE_TYPE_IMAGE) { - return PAL_RESULT_INVALID_IMAGE; - } - - if (imageData->data2 != SWAPCHAIN_IMAGE) { - return PAL_RESULT_INVALID_IMAGE; - } - - void* waitSemaphoreHandle = nullptr; - if (info->waitSemaphore) { - HandleData* tmp = (HandleData*)info->waitSemaphore; - if (tmp->type != HANDLE_TYPE_SEMAPHORE) { - return PAL_RESULT_INVALID_SEMAPHORE; - } - waitSemaphoreHandle = tmp->handle; - } - - PalPresentInfo presentInfo; - presentInfo.image = imageData->handle; - presentInfo.waitValue = info->waitValue; - presentInfo.waitSemaphore = waitSemaphoreHandle; - - return swapchainData->backend->presentSwapchain( - swapchainData->handle, - &presentInfo); + return swapchain->backend->presentSwapchain( + swapchain, + info); } // ================================================== @@ -1581,87 +1168,27 @@ PalResult PAL_CALL palCreateShader( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - if (info->type == PAL_SHADER_TYPE_UNDEFINED) { - return PAL_RESULT_INVALID_SHADER_TYPE; - - } else if (info->type == PAL_SHADER_TYPE_COMPUTE) { - if (data->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_CONTROL) { - if (data->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_EVALUATION) { - if (data->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->type == PAL_SHADER_TYPE_MESH) { - if (data->features & PAL_ADAPTER_FEATURE_MESH_SHADER) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->type == PAL_SHADER_TYPE_TASK) { - if (data->features & PAL_ADAPTER_FEATURE_MESH_SHADER) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - // create a slot for the shader - HandleData* shaderData = getFreeHandleData(); - if (!shaderData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - PalShader* shader = nullptr; - PalResult ret; - ret = data->backend->createShader( - data->handle, + PalResult result; + result = device->backend->createShader( + device, info, &shader); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + if (result != PAL_RESULT_SUCCESS) { + return result; } - shaderData->backend = data->backend; - shaderData->handle = shader; - shaderData->type = HANDLE_TYPE_SHADER; - shaderData->data2 = (Uint32)info->type; - shaderData->features = data->features; - - *outShader = (PalShader*)shaderData; + shader->backend = device->backend; + *outShader = shader; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyShader(PalShader* shader) { if (s_Graphics.initialized && shader) { - HandleData* data = (HandleData*)shader; - if (data->type == HANDLE_TYPE_SHADER) { - data->backend->destroyShader(data->handle); - freeHandleData(data); - } - } -} - -PalShaderType PAL_CALL palGetShaderType(PalShader* shader) -{ - if (s_Graphics.initialized && shader) { - HandleData* data = (HandleData*)shader; - if (data->type == HANDLE_TYPE_SHADER) { - return (PalShaderType)data->data2; - } + shader->backend->destroyShader(shader); } - return PAL_SHADER_TYPE_UNDEFINED; } // ================================================== @@ -1685,90 +1212,26 @@ PalResult PAL_CALL palCreateRenderPass( return PAL_RESULT_INSUFFICIENT_BUFFER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - PalAttachmentDesc attachments[16]; // should be fine - PalRenderPassCreateInfo createInfo = {0}; - createInfo.attachmentCount = info->attachmentCount; - createInfo.attachments = attachments; - createInfo.width = info->width; - createInfo.height = info->height; - - HandleData* tmp = nullptr; - for (int i = 0; i < info->attachmentCount; i++) { - if (!info->attachments[i].target) { - return PAL_RESULT_NULL_POINTER; - } - - // clang-format of - if (info->attachments[i].type == PAL_ATTACHMENT_TYPE_FRAGMENT_SHADING_RATE) { - if (!(data->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - tmp = (HandleData*)info->attachments[i].target; - if (tmp->type != HANDLE_TYPE_IMAGE_VIEW) { - return PAL_RESULT_INVALID_IMAGE_VIEW; - } - - attachments[i].target = tmp->handle; - attachments[i].loadOp = info->attachments[i].loadOp; - attachments[i].storeOp = info->attachments[i].storeOp; - attachments[i].stencilLoadOp = info->attachments[i].stencilLoadOp; - attachments[i].stencilStoreOp = info->attachments[i].stencilStoreOp; - attachments[i].resolveMode = info->attachments[i].resolveMode ; - attachments[i].type = info->attachments[i].type; - attachments[i].resolveTarget = nullptr; - attachments[i].stencilResolveMode = - info->attachments[i].stencilResolveMode; - - if (info->attachments[i].resolveTarget) { - tmp = (HandleData*)info->attachments[i].resolveTarget; - if (tmp->type != HANDLE_TYPE_IMAGE_VIEW) { - return PAL_RESULT_INVALID_IMAGE_VIEW; - } - attachments[i].resolveTarget = tmp->handle; - } - } - - // create a slot for the renderpass - HandleData* renderPassData = getFreeHandleData(); - if (!renderPassData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - PalRenderPass* renderpass = nullptr; - PalResult ret; - ret = data->backend->createRenderPass( - data->handle, - &createInfo, - &renderpass); + PalRenderPass* renderPass = nullptr; + PalResult result; + result = device->backend->createRenderPass( + device, + info, + &renderPass); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + if (result != PAL_RESULT_SUCCESS) { + return result; } - renderPassData->backend = data->backend; - renderPassData->handle = renderpass; - renderPassData->type = HANDLE_TYPE_RENDER_PASS; - renderPassData->features = data->features; - - *outRenderPass = (PalRenderPass*)renderPassData; + renderPass->backend = device->backend; + *outRenderPass = renderPass; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) { if (s_Graphics.initialized && renderPass) { - HandleData* data = (HandleData*)renderPass; - if (data->type == HANDLE_TYPE_RENDER_PASS) { - data->backend->destroyRenderPass(data->handle); - freeHandleData(data); - } + renderPass->backend->destroyRenderPass(renderPass); } } @@ -1788,41 +1251,22 @@ PalResult PAL_CALL palCreateFence( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - // create a slot for the fence - HandleData* fenceData = getFreeHandleData(); - if (!fenceData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - PalFence* fence = nullptr; - PalResult ret; - ret = data->backend->createFence(data->handle, &fence); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + PalResult result; + result = device->backend->createFence(device, &fence); + if (result != PAL_RESULT_SUCCESS) { + return result; } - fenceData->backend = data->backend; - fenceData->handle = fence; - fenceData->type = HANDLE_TYPE_FENCE; - fenceData->features = data->features; - - *outFence = (PalFence*)fenceData; + fence->backend = device->backend; + *outFence = fence; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyFence(PalFence* fence) { if (s_Graphics.initialized && fence) { - HandleData* data = (HandleData*)fence; - if (data->type == HANDLE_TYPE_FENCE) { - data->backend->destroyFence(data->handle); - freeHandleData(data); - } + fence->backend->destroyFence(fence); } } @@ -1838,12 +1282,7 @@ PalResult PAL_CALL palWaitFence( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)fence; - if (data->type != HANDLE_TYPE_FENCE) { - return PAL_RESULT_INVALID_FENCE; - } - - return data->backend->waitFenceTimeout(data->handle, timeout); + return fence->backend->waitFenceTimeout(fence, timeout); } PalResult PAL_CALL palResetFence(PalFence* fence) @@ -1856,25 +1295,13 @@ PalResult PAL_CALL palResetFence(PalFence* fence) return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)fence; - if (data->type != HANDLE_TYPE_FENCE) { - return PAL_RESULT_INVALID_FENCE; - } - - if (!(data->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - return data->backend->resetFence(data->handle); + return fence->backend->resetFence(fence); } bool PAL_CALL palIsFenceSignaled(PalFence* fence) { if (s_Graphics.initialized && fence) { - HandleData* data = (HandleData*)fence; - if (data->type == HANDLE_TYPE_FENCE) { - return data->backend->isFenceSignaled(data->handle); - } + return fence->backend->isFenceSignaled(fence); } return false; } @@ -1895,46 +1322,22 @@ PalResult PAL_CALL palCreateSemaphore( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - // create a slot for the semaphore - HandleData* semaphoreData = getFreeHandleData(); - if (!semaphoreData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - PalSemaphore* semaphore = nullptr; - PalResult ret; - ret = data->backend->createSemaphore(data->handle, &semaphore); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - - semaphoreData->backend = data->backend; - semaphoreData->handle = semaphore; - semaphoreData->type = HANDLE_TYPE_SEMAPHORE; - semaphoreData->features = data->features; - - semaphoreData->data2 = BINARY_SEMAPHORE; - if (data->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - semaphoreData->data2 = TIMELINE_SEMAPHORE; + PalResult result; + result = device->backend->createSemaphore(device, &semaphore); + if (result != PAL_RESULT_SUCCESS) { + return result; } - *outSemaphore = (PalSemaphore*)semaphoreData; + semaphore->backend = device->backend; + *outSemaphore = semaphore; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore) { if (s_Graphics.initialized && semaphore) { - HandleData* data = (HandleData*)semaphore; - if (data->type != HANDLE_TYPE_SEMAPHORE) { - data->backend->destroySemaphore(data->handle); - freeHandleData(data); - } + semaphore->backend->destroySemaphore(semaphore); } } @@ -1952,19 +1355,9 @@ PalResult PAL_CALL palWaitSemaphore( return PAL_RESULT_NULL_POINTER; } - HandleData* semaphoreData = (HandleData*)semaphore; - if (semaphoreData->type != HANDLE_TYPE_SEMAPHORE) { - return PAL_RESULT_INVALID_SEMAPHORE; - } - - HandleData* queueData = (HandleData*)queue; - if (queueData->type != HANDLE_TYPE_QUEUE) { - return PAL_RESULT_INVALID_QUEUE; - } - - return semaphoreData->backend->waitSemaphore( - semaphoreData->handle, - queueData->handle, + return semaphore->backend->waitSemaphore( + semaphore, + queue, value, timeout); } @@ -1982,19 +1375,9 @@ PalResult PAL_CALL palSignalSemaphore( return PAL_RESULT_NULL_POINTER; } - HandleData* semaphoreData = (HandleData*)semaphore; - if (semaphoreData->type != HANDLE_TYPE_SEMAPHORE) { - return PAL_RESULT_INVALID_SEMAPHORE; - } - - HandleData* queueData = (HandleData*)queue; - if (queueData->type != HANDLE_TYPE_QUEUE) { - return PAL_RESULT_INVALID_QUEUE; - } - - return semaphoreData->backend->signalSemaphore( - semaphoreData->handle, - queueData->handle, + return semaphore->backend->signalSemaphore( + semaphore, + queue, value); } @@ -2010,33 +1393,11 @@ PalResult PAL_CALL palGetSemaphoreValue( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)semaphore; - if (data->type != HANDLE_TYPE_SEMAPHORE) { - return PAL_RESULT_INVALID_SEMAPHORE; - } - - if (data->data2 == BINARY_SEMAPHORE) { - return PAL_RESULT_INVALID_SEMAPHORE; - } - - return data->backend->getSemaphoreValue( - data->handle, + return semaphore->backend->getSemaphoreValue( + semaphore, value); } -bool PAL_CALL palIsTimelineSemaphore(PalSemaphore* semaphore) -{ - if (s_Graphics.initialized && semaphore) { - HandleData* data = (HandleData*)semaphore; - if (data->type == HANDLE_TYPE_SEMAPHORE) { - if (data->data2 == TIMELINE_SEMAPHORE) { - return true; - } - } - } - return false; -} - // ================================================== // Command Pool And Buffer // ================================================== @@ -2058,55 +1419,26 @@ PalResult PAL_CALL palCreateCommandPool( return PAL_RESULT_NULL_POINTER; } - HandleData* deviceData = (HandleData*)device; - if (deviceData->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - HandleData* queueData = (HandleData*)info->queue; - if (queueData->type != HANDLE_TYPE_QUEUE) { - return PAL_RESULT_INVALID_QUEUE; - } - - PalCommandPoolCreateInfo createInfo = {0}; - createInfo.queue = queueData->handle; - createInfo.resettable = info->resettable; - createInfo.transient = info->transient; - - // create a slot for the command pool - HandleData* poolData = getFreeHandleData(); - if (!poolData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - PalCommandPool* pool = nullptr; - PalResult ret; - ret = deviceData->backend->createCommandPool( - deviceData->handle, - &createInfo, + PalResult result; + result = device->backend->createCommandPool( + device, + info, &pool); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + if (result != PAL_RESULT_SUCCESS) { + return result; } - poolData->backend = deviceData->backend; - poolData->handle = pool; - poolData->type = HANDLE_TYPE_COMMAND_POOL; - poolData->features = deviceData->features; - - *outPool = (PalCommandPool*)poolData; + pool->backend = device->backend; + *outPool = pool; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) { if (s_Graphics.initialized && pool) { - HandleData* data = (HandleData*)pool; - if (data->type == HANDLE_TYPE_COMMAND_POOL) { - data->backend->destroyCommandPool(data->handle); - freeHandleData(data); - } + pool->backend->destroyCommandPool(pool); } } @@ -2124,52 +1456,27 @@ PalResult PAL_CALL palCreateCommandBuffer( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)device; - if (data->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - HandleData* poolData = (HandleData*)pool; - if (poolData->type != HANDLE_TYPE_COMMAND_POOL) { - return PAL_RESULT_INVALID_COMMAND_POOL; - } - - // create a slot for the command buffer - HandleData* cmdBufferData = getFreeHandleData(); - if (!cmdBufferData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - PalCommandBuffer* cmdBuffer = nullptr; - PalResult ret; - ret = data->backend->createCommandBuffer( - data->handle, - poolData->handle, + PalResult result; + result = device->backend->createCommandBuffer( + device, + pool, type, &cmdBuffer); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + if (result != PAL_RESULT_SUCCESS) { + return result; } - cmdBufferData->backend = data->backend; - cmdBufferData->handle = cmdBuffer; - cmdBufferData->type = HANDLE_TYPE_COMMAND_BUFFER; - cmdBufferData->features = data->features; - cmdBufferData->data2 = type; - - *outCmdBuffer = (PalCommandBuffer*)cmdBufferData; + cmdBuffer->backend = device->backend; + *outCmdBuffer = cmdBuffer; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) { if (s_Graphics.initialized && cmdBuffer) { - HandleData* data = (HandleData*)cmdBuffer; - if (data->type == HANDLE_TYPE_COMMAND_BUFFER) { - data->backend->destroyCommandBuffer(data->handle); - freeHandleData(data); - } + cmdBuffer->backend->destroyCommandBuffer(cmdBuffer); } } @@ -2185,37 +1492,9 @@ PalResult PAL_CALL palExecuteCommandBuffer( return PAL_RESULT_NULL_POINTER; } - HandleData* primaryCmdBufferData = (HandleData*)primaryCmdBuffer; - HandleData* secondaryCmdBufferData = (HandleData*)secondaryCmdBuffer; - if (primaryCmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - if (secondaryCmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - // clang-format off - // check if both are primary cmd buffers - if (primaryCmdBufferData->data2 == PAL_COMMAND_BUFFER_TYPE_PRIMARY && - secondaryCmdBufferData->data2 == PAL_COMMAND_BUFFER_TYPE_PRIMARY) { - return PAL_RESULT_INVALID_OPERATION; - } - - // check if both are secondary cmd buffers - if (primaryCmdBufferData->data2 == PAL_COMMAND_BUFFER_TYPE_SECONDARY && - secondaryCmdBufferData->data2 == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { - return PAL_RESULT_INVALID_OPERATION; - } - - if (primaryCmdBufferData->data2 != PAL_COMMAND_BUFFER_TYPE_PRIMARY) { - return PAL_RESULT_INVALID_OPERATION; - } - // clang-format on - - return primaryCmdBufferData->backend->executeCommandBuffer( - primaryCmdBufferData->handle, - secondaryCmdBufferData->handle); + return primaryCmdBuffer->backend->executeCommandBuffer( + primaryCmdBuffer, + secondaryCmdBuffer); } PalResult PAL_CALL palSetFragmentShadingRate( @@ -2230,13 +1509,8 @@ PalResult PAL_CALL palSetFragmentShadingRate( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)cmdBuffer; - if (data->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - return data->backend->setFragmentShadingRate( - data->handle, + return cmdBuffer->backend->setFragmentShadingRate( + cmdBuffer, state); } @@ -2254,17 +1528,8 @@ PalResult PAL_CALL palDrawMeshTasks( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)cmdBuffer; - if (data->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - if (!(data->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - return data->backend->drawMeshTasks( - data->handle, + return cmdBuffer->backend->drawMeshTasks( + cmdBuffer, groupCountX, groupCountY, groupCountZ); @@ -2285,23 +1550,9 @@ PalResult PAL_CALL palDrawMeshTasksIndirect( return PAL_RESULT_NULL_POINTER; } - HandleData* cmdBufferData = (HandleData*)cmdBuffer; - HandleData* bufferData = (HandleData*)buffer; - if (cmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - if (bufferData->type != HANDLE_TYPE_BUFFER) { - return PAL_RESULT_INVALID_BUFFER; - } - - if (!(cmdBufferData->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - return cmdBufferData->backend->drawMeshTasksIndirect( - cmdBufferData->handle, - bufferData->handle, + return cmdBuffer->backend->drawMeshTasksIndirect( + cmdBuffer, + buffer, offset, drawCount, stride); @@ -2324,30 +1575,10 @@ PalResult PAL_CALL palDrawMeshTasksIndirectCount( return PAL_RESULT_NULL_POINTER; } - HandleData* cmdBufferData = (HandleData*)cmdBuffer; - HandleData* bufferData = (HandleData*)buffer; - HandleData* countBufferData = (HandleData*)countBuffer; - if (cmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - if (bufferData->type != HANDLE_TYPE_BUFFER) { - return PAL_RESULT_INVALID_BUFFER; - } - - if (countBufferData->type != HANDLE_TYPE_BUFFER) { - return PAL_RESULT_INVALID_BUFFER; - } - - if (!(cmdBufferData->features & - PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - return cmdBufferData->backend->drawMeshTasksIndirectCount( - cmdBufferData->handle, - bufferData->handle, - countBufferData->handle, + return cmdBuffer->backend->drawMeshTasksIndirectCount( + cmdBuffer, + buffer, + countBuffer, offset, countBufferOffset, maxDrawCount, @@ -2359,153 +1590,18 @@ PalResult PAL_CALL palBuildAccelerationStructures( Int32 infoCount, PalAccelerationStructureBuildInfo* infos) { - // if (!s_Graphics.initialized) { - // return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - // } - - // if (!device || !infos || infoCount <= 0) { - // return PAL_RESULT_NULL_POINTER; - // } - - // HandleData* data = (HandleData*)device; - // if (data->type != HANDLE_TYPE_DEVICE) { - // return PAL_RESULT_INVALID_COMMAND_BUFFER; - // } - - // // fast path. 1 to 4 build info - // bool free = false; - // PalAccelerationStructureBuildInfo buildInfos[4]; - // PalAccelerationStructureBuildInfo* tmpInfos = buildInfos; - // if (infoCount > 4) { - // // allocate memory - // tmpInfos = nullptr; - // tmpInfos = palAllocate( - // s_Graphics.allocator, - // sizeof(PalAccelerationStructureBuildInfo) * infoCount, - // 0); - - // if (!tmpInfos) { - // return PAL_RESULT_OUT_OF_MEMORY; - // } - // free = true; - // } - - // PalGeometry* tmpBuildInfoGeometries[8]; - // for (int i = 0; i < infoCount; i++) { - // PalAccelerationStructureBuildInfo* info = &tmpInfos[i]; - // // scratch buffer and acceleration source - // HandleData* asData = (HandleData*)info->dst; - // if (asData->type != HANDLE_TYPE_ACCELERATION_STRUCTURE) { - // return PAL_RESULT_INVALID_ACCELERATION_STRUCTURE; - // } - - // HandleData* scratchBufferData = (HandleData*)info->scratchBuffer; - // if (scratchBufferData->type != HANDLE_TYPE_BUFFER) { - // return PAL_RESULT_INVALID_BUFFER; - // } - - // PalGeometry* tmp = tmpBuildInfoGeometries[i]; - // PalAccelerationStructureBuildInfo buildInfo = {0}; - // buildInfo.scratchBuffer = scratchBufferData->handle; - // buildInfo.dst = asData->handle; - // buildInfo.scratchBufferOffset = info->scratchBufferOffset; - - // if (info->geometriesCount >= 1) { - // // geometry path - // tmp = palAllocate( - // s_Graphics.allocator, - // sizeof(PalGeometry) * info->geometriesCount, - // 0); - - // if (!tmp) { - // return PAL_RESULT_OUT_OF_MEMORY; - // } - - // buildInfo.instanceCount = info->instanceCount; - // for (int i = 0; i < info->instanceCount; i++) { - // PalGeometry* srcGeometry = &info->instances[i]; - // PalGeometry* dstGeometry = &tmp[i]; - // dstGeometry->type = srcGeometry->type; - // dstGeometry->primitiveCount = srcGeometry->primitiveCount; - - // if (srcGeometry->type == PAL_GEOMETRY_TYPE_AABBS) { - // PalGeometryDataAABBS* dstData = dstGeometry->data; - // PalGeometryDataAABBS* srcData = srcGeometry->data; - // dstData->count = srcData->count; - // dstData->offset = srcData->offset; - // dstData->stride = srcData->stride; - - // HandleData* BufferData = (HandleData*)srcData->buffer; - // dstData->buffer = BufferData->handle; - - // } else { - // // triangle - // PalGeometryDataTriangle* dstData = dstGeometry->data; - // PalGeometryDataTriangle* srcData = srcGeometry->data; - - // dstData->indexCount = srcData->indexCount; - // dstData->indexOffset = srcData->indexOffset; - // dstData->indexType = srcData->indexType; - // dstData->vertexCount = srcData->vertexCount; - // dstData->vertexOffset = srcData->vertexOffset; - // dstData->vertexStride = srcData->vertexStride; - // dstData->vertexType = srcData->vertexType; - - // HandleData* BufferData = (HandleData*)srcData->vertexBuffer; - // dstData->vertexBuffer = BufferData->handle; - - // // index buffer - // BufferData = (HandleData*)srcData->indexBuffer; - // dstData->indexBuffer = BufferData->handle; - // } - // } - - // } else { - // // instance path - // tmp = palAllocate( - // s_Graphics.allocator, - // sizeof(PalGeometry) * info->instanceCount, - // 0); - - // if (!tmp) { - // return PAL_RESULT_OUT_OF_MEMORY; - // } - - // buildInfo.instanceCount = info->instanceCount; - // for (int i = 0; i < info->instanceCount; i++) { - // PalGeometry* srcGeometry = &info->instances[i]; - // PalGeometry* dstGeometry = &tmp[i]; - // dstGeometry->type = srcGeometry->type; - // dstGeometry->primitiveCount = srcGeometry->primitiveCount; - - // // always instance data in instance path - // PalGeometryDataInstance* dstData = dstGeometry->data; - // PalGeometryDataInstance* srcData = srcGeometry->data; - // dstData->count = srcData->count; - // dstData->offset = srcData->offset; - - // HandleData* bufferData = (HandleData*)srcData->buffer; - // dstData->buffer = bufferData->handle; - // } - // } - // } - - // PalResult result = data->backend->buildAccelerationStructures( - // data->handle, - // infoCount, - // tmpInfos); - - // // free the allocated arrays - // for (int i = 0; i < infoCount; i++) { - // PalGeometry* tmp = tmpBuildInfoGeometries[i]; - // palFree(s_Graphics.allocator, tmp); - // } - - // if (free) { - // palFree(s_Graphics.allocator, tmpInfos); - // } - - // return result; + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !infos || infoCount <= 0) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->buildAccelerationStructures( + device, + infoCount, + infos); } PalResult PAL_CALL palBeginRenderPass( @@ -2526,19 +1622,9 @@ PalResult PAL_CALL palBeginRenderPass( return PAL_RESULT_INSUFFICIENT_BUFFER; } - HandleData* cmdBufferData = (HandleData*)cmdBuffer; - if (cmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - HandleData* renderPassData = (HandleData*)renderPass; - if (renderPassData->type != HANDLE_TYPE_RENDER_PASS) { - return PAL_RESULT_INVALID_RENDER_PASS; - } - - return cmdBufferData->backend->beginRenderPass( - cmdBufferData->handle, - renderPassData->handle, + return cmdBuffer->backend->beginRenderPass( + cmdBuffer, + renderPass, clearValueCount, clearValues); } @@ -2553,12 +1639,7 @@ PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer) return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)cmdBuffer; - if (data->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - return data->backend->endRenderPass(data->handle); + return cmdBuffer->backend->endRenderPass(cmdBuffer); } PalResult PAL_CALL palSubmitCommandBuffer( @@ -2573,51 +1654,9 @@ PalResult PAL_CALL palSubmitCommandBuffer( return PAL_RESULT_NULL_POINTER; } - HandleData* data = (HandleData*)queue; - if (data->type != HANDLE_TYPE_QUEUE) { - return PAL_RESULT_INVALID_QUEUE; - } - - HandleData* cmdBufferData = (HandleData*)info->cmdBuffer; - if (cmdBufferData->type != HANDLE_TYPE_COMMAND_BUFFER) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - - void* fenceHandle = nullptr; - void* waitSemaphoreHandle = nullptr; - void* signalSemaphoreHandle = nullptr; - if (info->fence) { - HandleData* tmp = (HandleData*)info->fence; - if (tmp->type == HANDLE_TYPE_FENCE) { - fenceHandle = tmp->handle; - } - } - - if (info->waitSemaphore) { - HandleData* tmp = (HandleData*)info->waitSemaphore; - if (tmp->type == HANDLE_TYPE_SEMAPHORE) { - waitSemaphoreHandle = tmp->handle; - } - } - - if (info->signalSemaphore) { - HandleData* tmp = (HandleData*)info->signalSemaphore; - if (tmp->type == HANDLE_TYPE_SEMAPHORE) { - signalSemaphoreHandle = tmp->handle; - } - } - - PalSubmitInfo submitInfo; - submitInfo.cmdBuffer = cmdBufferData->handle; - submitInfo.fence = fenceHandle; - submitInfo.signalSemaphore = signalSemaphoreHandle; - submitInfo.waitSemaphore = waitSemaphoreHandle; - submitInfo.signalValue = info->signalValue; - submitInfo.waitValue = info->waitValue; - - return data->backend->submitCommandBuffer( - data->handle, - &submitInfo); + return queue->backend->submitCommandBuffer( + queue, + info); } // ================================================== @@ -2641,45 +1680,19 @@ PalResult PAL_CALL palCreateAccelerationstructure( return PAL_RESULT_NULL_POINTER; } - HandleData* deviceData = (HandleData*)device; - if (deviceData->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - HandleData* bufferData = (HandleData*)info->buffer; - if (bufferData->type != HANDLE_TYPE_BUFFER) { - return PAL_RESULT_INVALID_BUFFER; - } - - // create a slot for the acceleration structure - HandleData* asData = getFreeHandleData(); - if (!asData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - PalAccelerationStructureCreateInfo createInfo; - createInfo.buffer = bufferData->handle; - createInfo.type = info->type; - createInfo.offset = info->offset; - createInfo.size = info->size; - - PalResult ret; + PalResult result; PalAccelerationStructure* as = nullptr; - ret = deviceData->backend->createAccelerationstructure( - deviceData->handle, - &createInfo, + result = device->backend->createAccelerationstructure( + device, + info, &as); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + if (result != PAL_RESULT_SUCCESS) { + return result; } - asData->backend = deviceData->backend; - asData->handle = as; - asData->type = HANDLE_TYPE_ACCELERATION_STRUCTURE; - asData->features = deviceData->features; - - *outAs = (PalAccelerationStructure*)asData; + as->backend = device->backend; + *outAs = as; return PAL_RESULT_SUCCESS; } @@ -2687,11 +1700,7 @@ void PAL_CALL palDestroyAccelerationstructure( PalAccelerationStructure* as) { if (s_Graphics.initialized && as) { - HandleData* data = (HandleData*)as; - if (data->type == HANDLE_TYPE_ACCELERATION_STRUCTURE) { - data->backend->destroyAccelerationstructure(data->handle); - freeHandleData(data); - } + as->backend->destroyAccelerationstructure(as); } } @@ -2712,114 +1721,10 @@ PalResult PAL_CALL palGetAccelerationStructureBuildSize( return PAL_RESULT_NULL_POINTER; } - HandleData* deviceData = (HandleData*)device; - if (deviceData->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - // scratch buffer and acceleration source - HandleData* asData = (HandleData*)info->dst; - if (asData->type != HANDLE_TYPE_ACCELERATION_STRUCTURE) { - return PAL_RESULT_INVALID_ACCELERATION_STRUCTURE; - } - - HandleData* scratchBufferData = (HandleData*)info->scratchBuffer; - if (scratchBufferData->type != HANDLE_TYPE_BUFFER) { - return PAL_RESULT_INVALID_BUFFER; - } - - // PalGeometry* tmp = nullptr; - // PalAccelerationStructureBuildInfo buildInfo = {0}; - // buildInfo.scratchBuffer = scratchBufferData->handle; - // buildInfo.dst = asData->handle; - // buildInfo.scratchBufferOffset = info->scratchBufferOffset; - - // if (info->geometriesCount >= 1) { - // // geometry path - // tmp = palAllocate( - // s_Graphics.allocator, - // sizeof(PalGeometry) * info->geometriesCount, - // 0); - - // if (!tmp) { - // return PAL_RESULT_OUT_OF_MEMORY; - // } - - // buildInfo.instanceCount = info->instanceCount; - // for (int i = 0; i < info->instanceCount; i++) { - // PalGeometry* srcGeometry = &info->instances[i]; - // PalGeometry* dstGeometry = &tmp[i]; - // dstGeometry->type = srcGeometry->type; - // dstGeometry->primitiveCount = srcGeometry->primitiveCount; - - // if (srcGeometry->type == PAL_GEOMETRY_TYPE_AABBS) { - // PalGeometryDataAABBS* dstData = dstGeometry->data; - // PalGeometryDataAABBS* srcData = srcGeometry->data; - // dstData->count = srcData->count; - // dstData->offset = srcData->offset; - // dstData->stride = srcData->stride; - - // HandleData* BufferData = (HandleData*)srcData->buffer; - // dstData->buffer = BufferData->handle; - - // } else { - // // triangle - // PalGeometryDataTriangle* dstData = dstGeometry->data; - // PalGeometryDataTriangle* srcData = srcGeometry->data; - - // dstData->indexCount = srcData->indexCount; - // dstData->indexOffset = srcData->indexOffset; - // dstData->indexType = srcData->indexType; - // dstData->vertexCount = srcData->vertexCount; - // dstData->vertexOffset = srcData->vertexOffset; - // dstData->vertexStride = srcData->vertexStride; - // dstData->vertexType = srcData->vertexType; - - // HandleData* BufferData = (HandleData*)srcData->vertexBuffer; - // dstData->vertexBuffer = BufferData->handle; - - // // index buffer - // BufferData = (HandleData*)srcData->indexBuffer; - // dstData->indexBuffer = BufferData->handle; - // } - // } - - // } else { - // // instance path - // tmp = palAllocate( - // s_Graphics.allocator, - // sizeof(PalGeometry) * info->instanceCount, - // 0); - - // if (!tmp) { - // return PAL_RESULT_OUT_OF_MEMORY; - // } - - // buildInfo.instanceCount = info->instanceCount; - // for (int i = 0; i < info->instanceCount; i++) { - // PalGeometry* srcGeometry = &info->instances[i]; - // PalGeometry* dstGeometry = &tmp[i]; - // dstGeometry->type = srcGeometry->type; - // dstGeometry->primitiveCount = srcGeometry->primitiveCount; - - // // always instance data in instance path - // PalGeometryDataInstance* dstData = dstGeometry->data; - // PalGeometryDataInstance* srcData = srcGeometry->data; - // dstData->count = srcData->count; - // dstData->offset = srcData->offset; - - // HandleData* bufferData = (HandleData*)srcData->buffer; - // dstData->buffer = bufferData->handle; - // } - // } - - // PalResult result = deviceData->backend->getAccelerationStructureBuildSize( - // deviceData->handle, - // &buildInfo, - // size); - - // palFree(s_Graphics.allocator, tmp); - // return result; + return device->backend->getAccelerationStructureBuildSize( + device, + info, + size); } // ================================================== @@ -2847,140 +1752,25 @@ PalResult PAL_CALL palCreateGraphicsPipeline( return PAL_RESULT_NULL_POINTER; } - HandleData* deviceData = (HandleData*)device; - if (deviceData->type != HANDLE_TYPE_DEVICE) { - return PAL_RESULT_INVALID_DEVICE; - } - - // shaders - void* vShaderHandle = nullptr; - void* fShaderHandle = nullptr; - void* gShaderHandle = nullptr; - void* mShaderHandle = nullptr; - void* taskShaderHandle = nullptr; - void* tessEShaderHandle = nullptr; - void* tessCShaderHandle = nullptr; - - // create a slot for the pipeline - HandleData* pipelineData = getFreeHandleData(); - if (!pipelineData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - HandleData* tmp = nullptr; - // vertex shader path - if (info->vertexShader) { - tmp = (HandleData*)info->vertexShader; - if (tmp->type == HANDLE_TYPE_SHADER && - tmp->data2 == PAL_SHADER_TYPE_VERTEX) { - vShaderHandle = tmp->handle; - } - - // tessellation control shader - tmp = (HandleData*)info->tessellationControlShader; - if (tmp->type == HANDLE_TYPE_SHADER && - tmp->data2 == PAL_SHADER_TYPE_TESSELLATION_CONTROL) { - tessCShaderHandle = tmp->handle; - } - - // tessellation evaluation shader - tmp = (HandleData*)info->tessellationEvaluationShader; - if (tmp->type == HANDLE_TYPE_SHADER && - tmp->data2 == PAL_SHADER_TYPE_TESSELLATION_EVALUATION) { - tessEShaderHandle = tmp->handle; - } - - // geometry shader - tmp = (HandleData*)info->geometryShader; - if (tmp->type == HANDLE_TYPE_SHADER && - tmp->data2 == PAL_SHADER_TYPE_GEOMETRY) { - gShaderHandle = tmp->handle; - } - - } else { - // task shader - tmp = (HandleData*)info->taskShader; - if (tmp->type == HANDLE_TYPE_SHADER && - tmp->data2 == PAL_SHADER_TYPE_TASK) { - taskShaderHandle = tmp->handle; - } - - // mesh shader - tmp = (HandleData*)info->meshShader; - if (tmp->type == HANDLE_TYPE_SHADER && - tmp->data2 == PAL_SHADER_TYPE_MESH) { - mShaderHandle = tmp->handle; - } - } - - // fragment shader - tmp = (HandleData*)info->fragmentShader; - if (tmp->type == HANDLE_TYPE_SHADER && - tmp->data2 == PAL_SHADER_TYPE_FRAGMENT) { - fShaderHandle = tmp->handle; - } - - PalGraphicsPipelineCreateInfo createInfo; - createInfo.fragmentShader = fShaderHandle; - createInfo.geometryShader = gShaderHandle; - createInfo.meshShader = mShaderHandle; - createInfo.taskShader = taskShaderHandle; - createInfo.tessellationControlShader = tessCShaderHandle; - createInfo.tessellationEvaluationShader = tessEShaderHandle; - createInfo.vertexShader = vShaderHandle; - - createInfo.topology = info->topology; - createInfo.blendAttachmentCount = info->blendAttachmentCount; - createInfo.blendAttachments = info->blendAttachments; - - createInfo.depthStencilState = info->depthStencilState; - createInfo.multisampleState = info->multisampleState; - createInfo.rasterizerState = info->rasterizerState; - - createInfo.vertexLayoutCount = info->vertexLayoutCount; - createInfo.vertexLayouts = info->vertexLayouts; - - PalResult ret; + PalResult result; PalPipeline* pipeline = nullptr; - ret = deviceData->backend->createGraphicsPipeline( - deviceData->handle, - &createInfo, + result = device->backend->createGraphicsPipeline( + device, + info, &pipeline); - if (ret != PAL_RESULT_SUCCESS) { - return ret; + if (result != PAL_RESULT_SUCCESS) { + return result; } - pipelineData->backend = deviceData->backend; - pipelineData->handle = pipeline; - pipelineData->type = HANDLE_TYPE_PIPELINE; - pipelineData->data2 = GRAPHICS_PIPELINE; - pipelineData->features = deviceData->features; - - *outPipeline = (PalPipeline*)pipelineData; + pipeline->backend = device->backend; + *outPipeline = pipeline; return PAL_RESULT_SUCCESS; } void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) { if (s_Graphics.initialized && pipeline) { - HandleData* data = (HandleData*)pipeline; - if (data->type == HANDLE_TYPE_PIPELINE) { - data->backend->destroyPipeline(data->handle); - freeHandleData(data); - } + pipeline->backend->destroyPipeline(pipeline); } -} - -bool PAL_CALL palIsGraphicsPipeline(PalPipeline* pipeline) -{ - if (s_Graphics.initialized && pipeline) { - HandleData* data = (HandleData*)pipeline; - if (data->type == HANDLE_TYPE_PIPELINE) { - if (data->data2 == GRAPHICS_PIPELINE) { - return true; - } - } - } - return false; } \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index c9caefe8..eb0c6cde 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -66,9 +66,15 @@ typedef int (*wl_display_get_fd_fn)(struct wl_display*); #define VK_WAYLAND_PLATFORM 3 #define MAX_ATTACHMENTS 32 +typedef struct { + const PalGraphicsBackend* backend; + VkPhysicalDevice handle; +} Adapter; + typedef struct { bool hasDebug; void* handle; + Adapter* adapters; VkInstance instance; #ifdef __linux__ @@ -153,7 +159,9 @@ typedef struct { VkQueueFlags usedUsages; } PhysicalQueue; -struct PalDevice { +typedef struct { + const PalGraphicsBackend* backend; + PalAdapterFeatures features; Int32 queueCount; Int32 gpuOnlyMemoryIndex; @@ -196,86 +204,110 @@ struct PalDevice { PFN_vkCmdTraceRaysKHR cmdTraceRays; PFN_vkCreateRayTracingPipelinesKHR createRayTracingPipeline; PFN_vkCmdTraceRaysIndirectKHR cmdTraceRaysIndirect; -}; +} Device; + +typedef struct { + const PalGraphicsBackend* backend; -struct PalQueue { VkQueueFlags usage; PalDevice* device; PhysicalQueue* phyQueue; -}; +} Queue; + +typedef struct { + const PalGraphicsBackend* backend; -struct PalImage { bool belongsToSwapchain; Int32 index; - PalDevice* device; + Device* device; VkImage handle; PalImageInfo info; -}; +} Image; + +typedef struct { + const PalGraphicsBackend* backend; -struct PalImageView { VkImageViewType type; PalImageViewUsages usages; - PalDevice* device; - PalImage* image; + Device* device; + Image* image; VkImageView handle; -}; +} ImageView; + +typedef struct { + const PalGraphicsBackend* backend; -struct PalSwapchain { Uint32 imageCount; - PalDevice* device; - PalQueue* queue; + Device* device; + Queue* queue; VkSurfaceKHR surface; VkSwapchainKHR handle; - PalImage* images; -}; + Image* images; +} Swapchain; -struct PalShader { - PalShaderType type; - PalDevice* device; +typedef struct { + const PalGraphicsBackend* backend; + + Device* device; VkShaderModule handle; VkPipelineShaderStageCreateInfo info; -}; +} Shader; -struct PalRenderPass { +typedef struct { + const PalGraphicsBackend* backend; + Uint32 attachmentCount; Uint32 width; Uint32 height; - PalDevice* device; + Device* device; VkRenderPass handle; VkFramebuffer framebuffer; -}; +} RenderPass; -struct PalCommandPool { - PalDevice* device; +typedef struct { + const PalGraphicsBackend* backend; + + Device* device; VkCommandPool handle; -}; +} CommandPool; + +typedef struct { + const PalGraphicsBackend* backend; -struct PalCommandBuffer { bool primary; - PalDevice* device; + Device* device; VkCommandPool pool; VkCommandBuffer handle; -}; +} CommandBuffer; -struct PalFence { - PalDevice* device; +typedef struct { + const PalGraphicsBackend* backend; + + Device* device; VkFence handle; -}; +} Fence; + +typedef struct { + const PalGraphicsBackend* backend; -struct PalSemaphore { bool isTimeline; - PalDevice* device; + Device* device; VkSemaphore handle; -}; +} Semaphore; + +typedef struct { + const PalGraphicsBackend* backend; -struct PalBuffer { + Device* device; VkBuffer handle; -}; +} Buffer; -struct PalAccelerationStructure { - PalDevice* device; +typedef struct { + const PalGraphicsBackend* backend; + + Device* device; VkAccelerationStructureKHR handle; -}; +} AccelerationStructure; static Vulkan s_Vk = {0}; @@ -1523,6 +1555,7 @@ PalResult PAL_CALL initGraphicsVk( "vkGetPhysicalDeviceSurfaceFormatsKHR"); // clang-format on + s_Vk.adapters = nullptr; s_Vk.instance = instance; return PAL_RESULT_SUCCESS; } @@ -1534,6 +1567,10 @@ PalResult PAL_CALL shutdownGraphicsVk() if (s_Vk.libWayland) { dlclose(s_Vk.libWayland); } + + if (s_Vk.adapters) { + palFree(s_Vk.allocator, s_Vk.adapters); + } memset(&s_Vk, 0, sizeof(s_Vk)); } @@ -1568,9 +1605,21 @@ PalResult PAL_CALL enumerateVkAdapters( return PAL_RESULT_OUT_OF_MEMORY; } + if (s_Vk.adapters) { + // free the adapters and cache them again + palFree(s_Vk.allocator, s_Vk.adapters); + } + + s_Vk.adapters = palAllocate( + s_Vk.allocator, + sizeof(Adapter) * deviceCount, + 0); + s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, devices); for (int i = 0; i < *count && i < deviceCount; i++) { - outAdapters[i] = (PalAdapter*)devices[i]; + Adapter* tmp = &s_Vk.adapters[i]; + tmp->handle = devices[i]; + outAdapters[i] = (PalAdapter*)tmp; } palFree(s_Vk.allocator, devices); @@ -1581,7 +1630,8 @@ PalResult PAL_CALL getVkAdapterInfo( PalAdapter* adapter, PalAdapterInfo* info) { - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; VkPhysicalDeviceProperties props = {0}; VkPhysicalDeviceMemoryProperties memProps = {0}; @@ -1651,7 +1701,9 @@ PalResult PAL_CALL getVkAdapterCapabilities( PalAdapterCapabilities* caps) { VkResult ret = VK_SUCCESS; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + VkPhysicalDeviceProperties props = {0}; VkPhysicalDeviceMultiviewPropertiesKHR multiViewProps = {0}; VkPhysicalDeviceProperties2 properties2 = {0}; @@ -1747,9 +1799,11 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) VkResult ret; PalAdapterFeatures adapterFeatures = 0; Uint32 extensionCount = 0; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; VkPhysicalDeviceProperties props = {0}; + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + // get supported extensions s_Vk.getPhysicalDeviceProperties(phyDevice, &props); ret = s_Vk.enumerateDeviceExtensionProperties( @@ -2047,10 +2101,11 @@ PalResult PAL_CALL createVkDevice( float priority = 1.0f; Uint32 count = 0; VkResult ret = VK_SUCCESS; - PalDevice* device = nullptr; + Device* device = nullptr; VkPhysicalDeviceProperties props = {0}; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; s_Vk.getPhysicalDeviceProperties(phyDevice, &props); VkQueueFamilyProperties* queueProps = nullptr; @@ -2070,12 +2125,12 @@ PalResult PAL_CALL createVkDevice( sizeof(VkDeviceQueueCreateInfo) * count, 0); - device = palAllocate(s_Vk.allocator, sizeof(PalDevice), 0); + device = palAllocate(s_Vk.allocator, sizeof(Device), 0); if (!queueProps || !queueCreateInfos || !device) { return PAL_RESULT_OUT_OF_MEMORY; } - memset(device, 0, sizeof(PalDevice)); + memset(device, 0, sizeof(Device)); device->queueCount = count; device->phyDevice = phyDevice; @@ -2594,15 +2649,16 @@ PalResult PAL_CALL createVkDevice( palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); - *outDevice = device; + *outDevice = (PalDevice*)device; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkDevice(PalDevice* device) { - s_Vk.destroyDevice(device->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, device->phyQueues); - palFree(s_Vk.allocator, device); + Device* vkDevice = (Device*)device; + s_Vk.destroyDevice(vkDevice->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkDevice->phyQueues); + palFree(s_Vk.allocator, vkDevice); } // ================================================== @@ -2615,17 +2671,19 @@ PalResult PAL_CALL allocateVkMemory( Uint64 size, PalMemory** outMemory) { + Device* vkDevice = (Device*)device; VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = (VkDeviceSize)size; + if (type == PAL_MEMORY_TYPE_GPU_ONLY) { - allocateInfo.memoryTypeIndex = device->gpuOnlyMemoryIndex; + allocateInfo.memoryTypeIndex = vkDevice->gpuOnlyMemoryIndex; } else if (type == PAL_MEMORY_TYPE_CPU_UPLOAD) { - allocateInfo.memoryTypeIndex = device->cpuUploadMemoryIndex; + allocateInfo.memoryTypeIndex = vkDevice->cpuUploadMemoryIndex; } else if (type == PAL_MEMORY_TYPE_CPU_READBACK) { - allocateInfo.memoryTypeIndex = device->cpuReadbackMemoryIndex; + allocateInfo.memoryTypeIndex = vkDevice->cpuReadbackMemoryIndex; } if (allocateInfo.memoryTypeIndex == -1) { @@ -2635,7 +2693,7 @@ PalResult PAL_CALL allocateVkMemory( VkDeviceMemory memory = nullptr; VkResult result = s_Vk.allocateMemory( - device->handle, + vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &memory); @@ -2652,14 +2710,20 @@ void PAL_CALL freeVkMemory( PalDevice* device, PalMemory* memory) { + Device* vkDevice = (Device*)device; VkDeviceMemory mem = (VkDeviceMemory)memory; - s_Vk.freeMemory(device->handle, mem, &s_Vk.vkAllocator); + s_Vk.freeMemory(vkDevice->handle, mem, &s_Vk.vkAllocator); } PalResult PAL_CALL queryVkDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps) { + Device* vkDevice = (Device*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; @@ -2668,7 +2732,7 @@ PalResult PAL_CALL queryVkDepthStencilCapabilities( VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR; properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(device->phyDevice, &properties2); + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); caps->independentDepthStencilResolve = props.independentResolve; @@ -2714,6 +2778,11 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { + Device* vkDevice = (Device*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; @@ -2722,7 +2791,7 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(device->phyDevice, &properties2); + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); memset(caps, 0, sizeof(PalFragmentShadingRateCapabilities)); for (int i = 0; i < PAL_FRAGMENT_SHADING_RATE_MAX; i++) { @@ -2760,13 +2829,18 @@ PalResult PAL_CALL queryVkMeshShaderCapabilities( PalDevice* device, PalMeshShaderCapabilities* caps) { + Device* vkDevice = (Device*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceMeshShaderPropertiesEXT props = {0}; props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT; properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(device->phyDevice, &properties2); + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); caps->maxMeshOutputPrimitives = props.maxMeshOutputPrimitives; caps->maxMeshOutputVertices = props.maxMeshOutputVertices; @@ -2788,6 +2862,11 @@ PalResult PAL_CALL queryVkRayTracingCapabilities( PalDevice* device, PalRayTracingCapabilities* caps) { + Device* vkDevice = (Device*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; @@ -2801,7 +2880,7 @@ PalResult PAL_CALL queryVkRayTracingCapabilities( props.pNext = &accProps; properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(device->phyDevice, &properties2); + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); caps->maxRecursionDepth = props.maxRayRecursionDepth; caps->maxHitAttributeSize = props.maxRayHitAttributeSize; @@ -2828,13 +2907,15 @@ PalResult PAL_CALL createVkQueue( PalQueueType type, PalQueue** outQueue) { + Device* vkDevice = (Device*)device; VkQueueFlags queueFlag = 0; - PalQueue* queue = nullptr; - if (!device->handle) { + Queue* queue = nullptr; + + if (!vkDevice->handle) { return PAL_RESULT_INVALID_DEVICE; } - if (device->queueCount == 0) { + if (vkDevice->queueCount == 0) { return PAL_RESULT_OUT_OF_QUEUE; } @@ -2856,8 +2937,8 @@ PalResult PAL_CALL createVkQueue( } PhysicalQueue* phyQueue = nullptr; - for (int i = 0; i < device->queueCount; i++) { - PhysicalQueue* pq = &device->phyQueues[i]; + for (int i = 0; i < vkDevice->queueCount; i++) { + PhysicalQueue* pq = &vkDevice->phyQueues[i]; // check if the physical queue supports the requested operation // and if its not already used if (pq->usages & queueFlag && @@ -2872,7 +2953,7 @@ PalResult PAL_CALL createVkQueue( return PAL_RESULT_OUT_OF_QUEUE; } - queue = palAllocate(s_Vk.allocator, sizeof(PalQueue), 0); + queue = palAllocate(s_Vk.allocator, sizeof(Queue), 0); if (!queue) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2881,29 +2962,31 @@ PalResult PAL_CALL createVkQueue( queue->usage = queueFlag; queue->device = device; - *outQueue = queue; + *outQueue = (PalQueue*)queue; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkQueue(PalQueue* queue) { - PhysicalQueue* phyQueue = queue->phyQueue; - phyQueue->usedUsages &= ~queue->usage; - palFree(s_Vk.allocator, queue); + Queue* vkQueue = (Queue*)queue; + PhysicalQueue* phyQueue = vkQueue->phyQueue; + phyQueue->usedUsages &= ~vkQueue->usage; + palFree(s_Vk.allocator, vkQueue); } bool PAL_CALL canVkQueuePresent( PalQueue* queue, PalGraphicsWindow* window) { + Queue* vkQueue = (Queue*)queue; // check if the queue is a graphics queue before we check its family // index for presentation support. - if (queue->usage != VK_QUEUE_GRAPHICS_BIT) { + if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { return false; } Uint32 platform = checkPlatform(window->display); - PhysicalQueue* phyQueue = queue->phyQueue; + PhysicalQueue* phyQueue = vkQueue->phyQueue; if (platform == VK_WIN32_PLATFORM) { } else if (platform == VK_WAYLAND_PLATFORM) { @@ -2929,7 +3012,8 @@ PalResult PAL_CALL enumerateVkFormats( PalFormatInfo* outFormats) { Int32 fmtCount = 0; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; VkFormatProperties props = {0}; for (int i = 0; i < PAL_FORMAT_MAX; i++) { @@ -2988,7 +3072,8 @@ bool PAL_CALL isVkFormatSupported( PalAdapter* adapter, PalFormat format) { - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; VkFormatProperties props = {0}; VkFormat fmt = palFormatToVk(format); @@ -3003,7 +3088,8 @@ PalImageUsages PAL_CALL queryVkFormatImageUsages( PalAdapter* adapter, PalFormat format) { - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; VkFormatProperties props = {0}; VkFormat fmt = palFormatToVk(format); @@ -3018,7 +3104,8 @@ PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( PalAdapter* adapter, PalFormat format) { - VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapter; + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; VkFormatProperties props = {0}; VkFormat fmt = palFormatToVk(format); @@ -3067,12 +3154,14 @@ PalResult PAL_CALL createVkImage( PalImage** outImage) { VkResult result; - PalImage* image = nullptr; - if (!device->handle) { + Image* image = nullptr; + Device* vkDevice = (Device*)device; + + if (!vkDevice->handle) { return PAL_RESULT_INVALID_DEVICE; } - image = palAllocate(s_Vk.allocator, sizeof(PalImage), 0); + image = palAllocate(s_Vk.allocator, sizeof(Image), 0); if (!image) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3100,7 +3189,7 @@ PalResult PAL_CALL createVkImage( } result = s_Vk.createImage( - device->handle, + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &image->handle); @@ -3111,7 +3200,7 @@ PalResult PAL_CALL createVkImage( } image->belongsToSwapchain = false; - image->device = device; + image->device = vkDevice; image->info.depthOrArraySize = info->depthOrArraySize; image->info.type = info->type; image->info.format = info->format; @@ -3121,24 +3210,30 @@ PalResult PAL_CALL createVkImage( image->info.sampleCount = info->sampleCount; image->info.width = info->width; - *outImage = image; + *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkImage(PalImage* image) { - if (image->belongsToSwapchain) { + Image* vkImage = (Image*)image; + if (vkImage->belongsToSwapchain) { return; } - s_Vk.destroyImage(image->device->handle, image->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, image); + s_Vk.destroyImage( + vkImage->device->handle, + vkImage->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, vkImage); } PalResult PAL_CALL getVkImageInfo( PalImage* image, PalImageInfo* info) { - *info = image->info; + Image* vkImage = (Image*)image; + *info = vkImage->info; return PAL_RESULT_SUCCESS; } @@ -3146,13 +3241,14 @@ PalResult PAL_CALL getVkImageMemoryRequirements( PalImage* image, PalMemoryRequirements* requirements) { - PalDevice* device = image->device; + Image* vkImage = (Image*)image; + Device* device = vkImage->device; VkPhysicalDevice phyDevice = (VkPhysicalDevice)device->phyDevice; VkPhysicalDeviceMemoryProperties memProps = {0}; s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); VkMemoryRequirements memReq = {0}; - s_Vk.getImageMemoryRequirements(device->handle, image->handle, &memReq); + s_Vk.getImageMemoryRequirements(device->handle, vkImage->handle, &memReq); requirements->alignment = (Uint64)memReq.alignment; requirements->size = (Uint64)memReq.size; @@ -3189,12 +3285,17 @@ PalResult PAL_CALL bindVkImageMemory( PalMemory* memory, Uint64 offset) { - if (image->belongsToSwapchain) { + Image* vkImage = (Image*)image; + if (vkImage->belongsToSwapchain) { return PAL_RESULT_INVALID_OPERATION; } VkDeviceMemory mem = (VkDeviceMemory)memory; - s_Vk.bindImageMemory(image->device->handle, image->handle, mem, offset); + s_Vk.bindImageMemory( + vkImage->device->handle, + vkImage->handle, + mem, + offset); } // ================================================== @@ -3208,16 +3309,19 @@ PalResult PAL_CALL createVkImageView( PalImageView** outImageView) { VkResult result = VK_SUCCESS; - PalImageView* imageView = nullptr; - imageView = palAllocate(s_Vk.allocator, sizeof(PalImageView), 0); + ImageView* imageView = nullptr; + Device* vkDevice = (Device*)device; + Image* vkImage = (Image*)image; + + imageView = palAllocate(s_Vk.allocator, sizeof(ImageView), 0); if (!imageView) { return PAL_RESULT_OUT_OF_MEMORY; } VkImageViewCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.format = palFormatToVk(image->info.format); - createInfo.image = image->handle; + createInfo.format = palFormatToVk(vkImage->info.format); + createInfo.image = vkImage->handle; createInfo.subresourceRange.baseArrayLayer = info->startArrayLayer; createInfo.subresourceRange.baseMipLevel = info->startMipLevel; @@ -3240,7 +3344,7 @@ PalResult PAL_CALL createVkImageView( createInfo.subresourceRange .aspectMask = aspectFlags; result = s_Vk.createImageView( - device->handle, + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &imageView->handle); @@ -3250,23 +3354,24 @@ PalResult PAL_CALL createVkImageView( return vkResultToPal(result); } - imageView->device = device; - imageView->image = image; + imageView->device = vkDevice; + imageView->image = vkImage; imageView->type = createInfo.viewType; imageView->usages = info->usages; - *outImageView = imageView; + *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkImageView(PalImageView* imageView) { + ImageView* vkImageView = (ImageView*)imageView; s_Vk.destroyImageView( - imageView->device->handle, - imageView->handle, + vkImageView->device->handle, + vkImageView->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, imageView); + palFree(s_Vk.allocator, vkImageView); } // ================================================== @@ -3283,7 +3388,13 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( VkSurfaceKHR surface = nullptr; VkSurfaceFormatKHR* formats = nullptr; VkPresentModeKHR* modes = nullptr; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)device->phyDevice; + + Device* vkDevice = (Device*)device; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkDevice->phyDevice; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } bool ret = createSurface(window, &surface); if (!ret) { @@ -3356,7 +3467,6 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( } // clang-format off - // get format and colorspace caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = false; caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB] = false; @@ -3390,7 +3500,6 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( } } } - // clang-format on palFree(s_Vk.allocator, formats); @@ -3407,17 +3516,24 @@ PalResult PAL_CALL createVkSwapchain( PalSwapchain** outSwapchain) { PalFormat imageFormat = 0; - PalSwapchain* swapchain = nullptr; + Swapchain* swapchain = nullptr; VkImage* images = nullptr; - PhysicalQueue* phyQueue = queue->phyQueue; + + Device* vkDevice = (Device*)device; + Queue* vkQueue = (Queue*)queue; + PhysicalQueue* phyQueue = vkQueue->phyQueue; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } // check if the queue is a graphics queue before we check its family // index for presentation support. - if (queue->usage != VK_QUEUE_GRAPHICS_BIT) { + if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { PAL_RESULT_INVALID_QUEUE; } - swapchain = palAllocate(s_Vk.allocator, sizeof(PalSwapchain), 0); + swapchain = palAllocate(s_Vk.allocator, sizeof(Swapchain), 0); if (!swapchain) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3479,8 +3595,8 @@ PalResult PAL_CALL createVkSwapchain( } // create swapchain - VkResult result = device->createSwapchain( - device->handle, + VkResult result = vkDevice->createSwapchain( + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &swapchain->handle); @@ -3497,15 +3613,15 @@ PalResult PAL_CALL createVkSwapchain( // get and cache all images Int32 count = 0; - result = device->getSwapchainImages( - device->handle, + result = vkDevice->getSwapchainImages( + vkDevice->handle, swapchain->handle, &count, nullptr); swapchain->images = palAllocate( s_Vk.allocator, - sizeof(PalImage) * count, + sizeof(Image) * count, 0); images = palAllocate( @@ -3514,8 +3630,8 @@ PalResult PAL_CALL createVkSwapchain( 0); if (!swapchain->images || !images) { - device->destroySwapchain( - device->handle, + vkDevice->destroySwapchain( + vkDevice->handle, swapchain->handle, &s_Vk.vkAllocator ); @@ -3529,17 +3645,17 @@ PalResult PAL_CALL createVkSwapchain( return PAL_RESULT_OUT_OF_MEMORY; } - device->getSwapchainImages( - device->handle, + vkDevice->getSwapchainImages( + vkDevice->handle, swapchain->handle, &count, images); // fill all images with the creatio info for (int i = 0; i < count; i++) { - PalImage* image = &swapchain->images[i]; + Image* image = &swapchain->images[i]; image->belongsToSwapchain = true; - image->device = device; + image->device = vkDevice; image->handle = images[i]; image->index = -1; @@ -3553,35 +3669,41 @@ PalResult PAL_CALL createVkSwapchain( image->info.type = PAL_IMAGE_TYPE_2D; } - swapchain->device = device; - swapchain->queue = queue; + swapchain->device = vkDevice; + swapchain->queue = vkQueue; swapchain->imageCount = count; - *outSwapchain = swapchain; + *outSwapchain = (PalSwapchain*)swapchain; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkSwapchain(PalSwapchain* swapchain) { - swapchain->device->destroySwapchain( - swapchain->device->handle, - swapchain->handle, + Swapchain* vkSwapchain = (Swapchain*)swapchain; + vkSwapchain->device->destroySwapchain( + vkSwapchain->device->handle, + vkSwapchain->handle, &s_Vk.vkAllocator ); - s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, swapchain->images); - palFree(s_Vk.allocator, swapchain); + s_Vk.destroySurface( + s_Vk.instance, + vkSwapchain->surface, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, vkSwapchain->images); + palFree(s_Vk.allocator, vkSwapchain); } PalImage* PAL_CALL getVkSwapchainImage( PalSwapchain* swapchain, Int32 index) { - if (index > swapchain->imageCount) { + Swapchain* vkSwapchain = (Swapchain*)swapchain; + if (index > vkSwapchain->imageCount) { return nullptr; } - return &swapchain->images[index]; + return (PalImage*)&vkSwapchain->images[index]; } PalImage* PAL_CALL getVkNextSwapchainImage( @@ -3592,18 +3714,21 @@ PalImage* PAL_CALL getVkNextSwapchainImage( Uint32 index = 0; VkFence fenceHandle = nullptr; VkSemaphore semaphoreHandle = nullptr; + Swapchain* vkSwapchain = (Swapchain*)swapchain; if (info->fence) { - fenceHandle = info->fence->handle; + Fence* vkFence = (Fence*)info->fence; + fenceHandle = vkFence->handle; } if (info->signalSemaphore) { - semaphoreHandle = info->signalSemaphore->handle; + Semaphore* vkSemaphore = (Semaphore*)info->signalSemaphore; + semaphoreHandle = vkSemaphore->handle; } - result = swapchain->device->acquireNextImage( - swapchain->device->handle, - swapchain->handle, + result = vkSwapchain->device->acquireNextImage( + vkSwapchain->device->handle, + vkSwapchain->handle, info->timeout, semaphoreHandle, fenceHandle, @@ -3613,16 +3738,18 @@ PalImage* PAL_CALL getVkNextSwapchainImage( return nullptr; } - PalImage* image = &swapchain->images[index]; + Image* image = &vkSwapchain->images[index]; image->index = index; - return image; + return (PalImage*)image; } PalResult PAL_CALL presentVkSwapchain( PalSwapchain* swapchain, PalPresentInfo* info) { - if (info->image->index == -1) { + Swapchain* vkSwapchain = (Swapchain*)swapchain; + Image* vkImage = (Image*)info->image; + if (vkImage->index == -1) { // image was not the next image // this prevents UB return PAL_RESULT_INVALID_IMAGE; @@ -3631,7 +3758,8 @@ PalResult PAL_CALL presentVkSwapchain( Int32 semaphoreCount = 0; VkSemaphore semaphoreHandle = nullptr; if (info->waitSemaphore) { - semaphoreHandle = info->waitSemaphore->handle; + Semaphore* vkSemaphore = (Semaphore*)info->waitSemaphore; + semaphoreHandle = vkSemaphore->handle; semaphoreCount = 1; } @@ -3639,20 +3767,20 @@ PalResult PAL_CALL presentVkSwapchain( VkPresentInfoKHR presentInfo = {0}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &swapchain->handle; - presentInfo.pImageIndices = &info->image->index; + presentInfo.pSwapchains = &vkSwapchain->handle; + presentInfo.pImageIndices = &vkImage->index; presentInfo.pWaitSemaphores = &semaphoreHandle; presentInfo.waitSemaphoreCount = semaphoreCount; - result = swapchain->device->queuePresent( - swapchain->queue->phyQueue->handle, + result = vkSwapchain->device->queuePresent( + vkSwapchain->queue->phyQueue->handle, &presentInfo); if (result != VK_SUCCESS) { return vkResultToPal(result); } - info->image->index = -1; + vkImage->index = -1; return PAL_RESULT_SUCCESS; } @@ -3666,8 +3794,9 @@ PalResult PAL_CALL createVkShader( PalShader** outShader) { VkResult result; - PalShader* shader = nullptr; + Shader* shader = nullptr; VkShaderStageFlags stage = 0; + Device* vkDevice = (Device*)device; if (info->type == PAL_SHADER_TYPE_VERTEX) { stage = VK_SHADER_STAGE_VERTEX_BIT; @@ -3676,22 +3805,37 @@ PalResult PAL_CALL createVkShader( stage = VK_SHADER_STAGE_FRAGMENT_BIT; } else if (info->type == PAL_SHADER_TYPE_COMPUTE) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } stage = VK_SHADER_STAGE_COMPUTE_BIT; } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_CONTROL) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_EVALUATION) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; } else if (info->type == PAL_SHADER_TYPE_MESH) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } stage = VK_SHADER_STAGE_MESH_BIT_EXT; } else if (info->type == PAL_SHADER_TYPE_TASK) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } stage = VK_SHADER_STAGE_TASK_BIT_EXT; } - shader = palAllocate(s_Vk.allocator, sizeof(PalShader), 0); + shader = palAllocate(s_Vk.allocator, sizeof(Shader), 0); if (!shader) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3702,7 +3846,7 @@ PalResult PAL_CALL createVkShader( createInfo.pCode = (const Uint32*)info->bytecode; result = s_Vk.createShader( - device->handle, + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); @@ -3712,25 +3856,25 @@ PalResult PAL_CALL createVkShader( return vkResultToPal(result); } - shader->device = device; - shader->type = info->type; + shader->device = vkDevice; shader->info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader->info.module = shader->handle; shader->info.pName = "main"; shader->info.stage = stage; - *outShader = shader; + *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkShader(PalShader* shader) { + Shader* vkShader = (Shader*)shader; s_Vk.destroyShader( - shader->device->handle, - shader->handle, + vkShader->device->handle, + vkShader->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, shader); + palFree(s_Vk.allocator, vkShader); } // ================================================== @@ -3743,9 +3887,11 @@ PalResult PAL_CALL createVkRenderPass( PalRenderPass** outRenderPass) { VkResult result; - PalRenderPass* renderpass = nullptr; - renderpass = palAllocate(s_Vk.allocator, sizeof(PalRenderPass), 0); - if (!renderpass) { + RenderPass* renderPass = nullptr; + Device* vkDevice = (Device*)device; + + renderPass = palAllocate(s_Vk.allocator, sizeof(RenderPass), 0); + if (!renderPass) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3764,7 +3910,7 @@ PalResult PAL_CALL createVkRenderPass( viewCreateInfo.subpassCount = 1; // clang-format off - if (device->createRenderPass2) { + if (vkDevice->createRenderPass2) { VkAttachmentDescription2KHR attachments[MAX_ATTACHMENTS]; VkAttachmentReference2KHR depthRef; VkAttachmentReference2KHR fsrRef; @@ -3780,18 +3926,20 @@ PalResult PAL_CALL createVkRenderPass( rDesc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR; rDesc->flags = 0; rDesc->pNext = nullptr; + ImageView* vkImageView = (ImageView*)desc->target; - rDesc->format = palFormatToVk(desc->target->image->info.format); + rDesc->format = palFormatToVk(vkImageView->image->info.format); rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rDesc->samples = vkSamplesToSamples(desc->target->image->info.sampleCount); + rDesc->samples = vkSamplesToSamples(vkImageView->image->info.sampleCount); rDesc->flags = 0; - layers = desc->target->image->info.depthOrArraySize; + layers = vkImageView->image->info.depthOrArraySize; VkAttachmentReference2KHR* resolveRef = &resolveRefs[resolveRefCount]; if (desc->resolveTarget) { // the layer count must be the same so to validate as well // we use the highest from the attachments - layers = desc->resolveTarget->image->info.depthOrArraySize; + ImageView* tmp = (ImageView*)desc->resolveTarget; + layers = tmp->image->info.depthOrArraySize; resolveRef->attachment = i; resolveRef->pNext = 0; resolveRef->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; @@ -3817,7 +3965,7 @@ PalResult PAL_CALL createVkRenderPass( } // add the image views from the attachments into a seperate array - views[i] = desc->target->handle; + views[i] = vkImageView->handle; if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { VkAttachmentReference2KHR* ref = &colorRefs[colorRefCount]; @@ -3829,7 +3977,7 @@ PalResult PAL_CALL createVkRenderPass( rDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorRefCount++; - if (desc->target->image->belongsToSwapchain) { + if (vkImageView->image->belongsToSwapchain) { rDesc->finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; } @@ -3915,11 +4063,11 @@ PalResult PAL_CALL createVkRenderPass( createInfo.pNext = &viewCreateInfo; } - result = device->createRenderPass2( - device->handle, + result = vkDevice->createRenderPass2( + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, - &renderpass->handle); + &renderPass->handle); } else { // legacy path @@ -3932,17 +4080,19 @@ PalResult PAL_CALL createVkRenderPass( PalAttachmentDesc* desc = &info->attachments[i]; VkAttachmentDescription* rDesc = &attachments[i]; - rDesc->format = palFormatToVk(desc->target->image->info.format); + ImageView* vkImageView = (ImageView*)desc->target; + rDesc->format = palFormatToVk(vkImageView->image->info.format); rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rDesc->samples = vkSamplesToSamples(desc->target->image->info.sampleCount); + rDesc->samples = vkSamplesToSamples(vkImageView->image->info.sampleCount); rDesc->flags = 0; - layers = desc->target->image->info.depthOrArraySize; + layers = vkImageView->image->info.depthOrArraySize; VkAttachmentReference* resolveRef = &resolveRefs[resolveRefCount]; if (desc->resolveTarget) { // the layer count must be the same so to validate as well // we use the highest from the attachments - layers = desc->resolveTarget->image->info.depthOrArraySize; + ImageView* tmp = (ImageView*)desc->resolveTarget; + layers = tmp->image->info.depthOrArraySize; resolveRef->attachment = i; } @@ -3966,7 +4116,7 @@ PalResult PAL_CALL createVkRenderPass( } // add the image views from the attachments into a seperate array - views[i] = desc->target->handle; + views[i] = vkImageView->handle; if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { VkAttachmentReference* ref = &colorRefs[colorRefCount]; @@ -3975,7 +4125,7 @@ PalResult PAL_CALL createVkRenderPass( rDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorRefCount++; - if (desc->target->image->belongsToSwapchain) { + if (vkImageView->image->belongsToSwapchain) { rDesc->finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; } @@ -4040,14 +4190,14 @@ PalResult PAL_CALL createVkRenderPass( } result = s_Vk.createRenderPass( - device->handle, + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, - &renderpass->handle); + &renderPass->handle); } if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, renderpass); + palFree(s_Vk.allocator, renderPass); return vkResultToPal(result); } @@ -4060,45 +4210,46 @@ PalResult PAL_CALL createVkRenderPass( fbCreateInfo.height = info->height; fbCreateInfo.width = info->width; fbCreateInfo.layers = layers; - fbCreateInfo.renderPass = renderpass->handle; + fbCreateInfo.renderPass = renderPass->handle; result = s_Vk.createFramebuffer( - device->handle, + vkDevice->handle, &fbCreateInfo, &s_Vk.vkAllocator, - &renderpass->framebuffer); + &renderPass->framebuffer); if (result != VK_SUCCESS) { s_Vk.destroyRenderPass( - device->handle, - renderpass->handle, + vkDevice->handle, + renderPass->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, renderpass); + palFree(s_Vk.allocator, renderPass); // all image views in a single render pass must have the same // width/height/layers return PAL_RESULT_INVALID_ARGUMENT; } - renderpass->device = device; - renderpass->width = info->width; - renderpass->height = info->height; - renderpass->attachmentCount = info->attachmentCount; + renderPass->device = vkDevice; + renderPass->width = info->width; + renderPass->height = info->height; + renderPass->attachmentCount = info->attachmentCount; - *outRenderPass = renderpass; + *outRenderPass = (PalRenderPass*)renderPass; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass) { + RenderPass* vkRenderPass = (RenderPass*)renderPass; s_Vk.destroyFramebuffer( - renderPass->device->handle, - renderPass->framebuffer, + vkRenderPass->device->handle, + vkRenderPass->framebuffer, &s_Vk.vkAllocator); s_Vk.destroyRenderPass( - renderPass->device->handle, - renderPass->handle, + vkRenderPass->device->handle, + vkRenderPass->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, renderPass); @@ -4113,8 +4264,10 @@ PalResult PAL_CALL createVkFence( PalFence** outFence) { VkResult result; - PalFence* fence = nullptr; - fence = palAllocate(s_Vk.allocator, sizeof(PalFence), 0); + Fence* fence = nullptr; + Device* vkDevice = (Device*)device; + + fence = palAllocate(s_Vk.allocator, sizeof(Fence), 0); if (!fence) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4122,7 +4275,7 @@ PalResult PAL_CALL createVkFence( VkFenceCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; result = s_Vk.createFence( - device->handle, + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &fence->handle); @@ -4132,37 +4285,59 @@ PalResult PAL_CALL createVkFence( return vkResultToPal(result); } - fence->device = device; - *outFence = fence; + fence->device = vkDevice; + *outFence = (PalFence*)fence; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkFence(PalFence* fence) { - s_Vk.destroyFence(fence->device->handle, fence->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, fence); + Fence* vkFence = (Fence*)fence; + s_Vk.destroyFence( + vkFence->device->handle, + vkFence->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, vkFence); } PalResult PAL_CALL waitVkFence( PalFence* fence, Uint64 timeout) { + Fence* vkFence = (Fence*)fence; + if (timeout != UINT64_MAX) { + if (!(vkFence->device->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + VkResult result = s_Vk.waitFence( - fence->device->handle, + vkFence->device->handle, 1, - &fence->handle, + &vkFence->handle, true, timeout); if (result != VK_SUCCESS) { return vkResultToPal(result); } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL resetVkFence(PalFence* fence) { - VkResult ret = s_Vk.resetFence(fence->device->handle, 1, &fence->handle); + Fence* vkFence = (Fence*)fence; + if (!(vkFence->device->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkResult ret = s_Vk.resetFence( + vkFence->device->handle, + 1, + &vkFence->handle); + if (ret != VK_SUCCESS) { return vkResultToPal(ret); } @@ -4172,7 +4347,11 @@ PalResult PAL_CALL resetVkFence(PalFence* fence) bool PAL_CALL isVkFenceSignaled(PalFence* fence) { - VkResult ret = s_Vk.isFenceSignaled(fence->device->handle, fence->handle); + Fence* vkFence = (Fence*)fence; + VkResult ret = s_Vk.isFenceSignaled( + vkFence->device->handle, + vkFence->handle); + if (ret == VK_SUCCESS) { return true; } else { @@ -4189,8 +4368,10 @@ PalResult PAL_CALL createVkSemaphore( PalSemaphore** outSemaphore) { VkResult result; - PalSemaphore* semaphore = nullptr; - semaphore = palAllocate(s_Vk.allocator, sizeof(PalSemaphore), 0); + Semaphore* semaphore = nullptr; + Device* vkDevice = (Device*)device; + + semaphore = palAllocate(s_Vk.allocator, sizeof(Semaphore), 0); if (!semaphore) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4204,14 +4385,14 @@ PalResult PAL_CALL createVkSemaphore( const void* next = nullptr; semaphore->isTimeline = false; - if (device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + if (vkDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { next = &timelineCreateInfo; semaphore->isTimeline = true; } createInfo.pNext = next; result = s_Vk.createSemaphore( - device->handle, + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &semaphore->handle); @@ -4221,19 +4402,20 @@ PalResult PAL_CALL createVkSemaphore( return vkResultToPal(result); } - semaphore->device = device; - *outSemaphore = semaphore; + semaphore->device = vkDevice; + *outSemaphore = (PalSemaphore*)semaphore; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkSemaphore(PalSemaphore* semaphore) { + Semaphore* vkSemaphore = (Semaphore*)semaphore; s_Vk.destroySemaphore( - semaphore->device->handle, - semaphore->handle, + vkSemaphore->device->handle, + vkSemaphore->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, semaphore); + palFree(s_Vk.allocator, vkSemaphore); } PalResult PAL_CALL waitVkSemaphore( @@ -4243,14 +4425,20 @@ PalResult PAL_CALL waitVkSemaphore( Uint64 timeout) { VkResult result; + Semaphore* vkSemaphore = (Semaphore*)semaphore; + if (!(vkSemaphore->device->features & + PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + VkSemaphoreWaitInfo waitInfo = {0}; waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; waitInfo.semaphoreCount = 1; - waitInfo.pSemaphores = &semaphore->handle; + waitInfo.pSemaphores = &vkSemaphore->handle; waitInfo.pValues = &value; - result = semaphore->device->waitSemaphore( - semaphore->device->handle, + result = vkSemaphore->device->waitSemaphore( + vkSemaphore->device->handle, &waitInfo, timeout); @@ -4267,13 +4455,19 @@ PalResult PAL_CALL signalVkSemaphore( Uint64 value) { VkResult result; + Semaphore* vkSemaphore = (Semaphore*)semaphore; + if (!(vkSemaphore->device->features & + PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + VkSemaphoreSignalInfo signalInfo = {0}; signalInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; - signalInfo.semaphore = semaphore->handle; + signalInfo.semaphore = vkSemaphore->handle; signalInfo.value = value; - result = semaphore->device->signalSemaphore( - semaphore->device->handle, + result = vkSemaphore->device->signalSemaphore( + vkSemaphore->device->handle, &signalInfo); if (result != VK_SUCCESS) { @@ -4287,9 +4481,15 @@ PalResult PAL_CALL getVkSemaphoreValue( PalSemaphore* semaphore, Uint64* value) { - VkResult result = semaphore->device->getSemaphoreValue( - semaphore->device->handle, - semaphore->handle, + Semaphore* vkSemaphore = (Semaphore*)semaphore; + if (!(vkSemaphore->device->features & + PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkResult result = vkSemaphore->device->getSemaphoreValue( + vkSemaphore->device->handle, + vkSemaphore->handle, value); if (result != VK_SUCCESS) { @@ -4309,10 +4509,12 @@ PalResult PAL_CALL createVkCommandPool( PalCommandPool** outPool) { VkResult result; - PalCommandPool* pool = nullptr; - PhysicalQueue* phyQueue = info->queue->phyQueue; + CommandPool* pool = nullptr; + Device* vkDevice = (Device*)device; + Queue* queue = (Queue*)info->queue; + PhysicalQueue* phyQueue = queue->phyQueue; - pool = palAllocate(s_Vk.allocator, sizeof(PalCommandPool), 0); + pool = palAllocate(s_Vk.allocator, sizeof(CommandPool), 0); if (!pool) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4322,15 +4524,23 @@ PalResult PAL_CALL createVkCommandPool( createInfo.queueFamilyIndex = phyQueue->familyIndex; if (info->resettable) { + if (!(vkDevice->features & + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } createInfo.flags |= VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; } if (info->transient) { + if (!(vkDevice->features & + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } createInfo.flags |= VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; } result = s_Vk.createCommandPool( - device->handle, + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &pool->handle); @@ -4340,19 +4550,20 @@ PalResult PAL_CALL createVkCommandPool( return vkResultToPal(result); } - pool->device = device; - *outPool = pool; + pool->device = vkDevice; + *outPool = (PalCommandPool*)pool; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkCommandPool(PalCommandPool* pool) { + CommandPool* vkPool = (CommandPool*)pool; s_Vk.destroyCommandPool( - pool->device->handle, - pool->handle, + vkPool->device->handle, + vkPool->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, pool); + palFree(s_Vk.allocator, vkPool); } PalResult PAL_CALL createVkCommandBuffer( @@ -4362,8 +4573,11 @@ PalResult PAL_CALL createVkCommandBuffer( PalCommandBuffer** outCmdBuffer) { VkResult result; - PalCommandBuffer* cmdBuffer = nullptr; - cmdBuffer = palAllocate(s_Vk.allocator, sizeof(PalCommandBuffer), 0); + CommandBuffer* cmdBuffer = nullptr; + Device* vkDevice = (Device*)device; + CommandPool* vkPool = (CommandPool*)pool; + + cmdBuffer = palAllocate(s_Vk.allocator, sizeof(CommandBuffer), 0); if (!cmdBuffer) { PAL_RESULT_OUT_OF_MEMORY; } @@ -4371,7 +4585,7 @@ PalResult PAL_CALL createVkCommandBuffer( VkCommandBufferAllocateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; createInfo.commandBufferCount = 1; - createInfo.commandPool = pool->handle; + createInfo.commandPool = vkPool->handle; createInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; cmdBuffer->primary = true; @@ -4381,7 +4595,7 @@ PalResult PAL_CALL createVkCommandBuffer( } result = s_Vk.createCommandBuffer( - device->handle, + vkDevice->handle, &createInfo, &cmdBuffer->handle); @@ -4390,32 +4604,35 @@ PalResult PAL_CALL createVkCommandBuffer( return vkResultToPal(result); } - cmdBuffer->device = device; - cmdBuffer->pool = pool->handle; + cmdBuffer->device = vkDevice; + cmdBuffer->pool = vkPool->handle; - *outCmdBuffer = cmdBuffer; + *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) { + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.destroyCommandBuffer( - cmdBuffer->device->handle, - cmdBuffer->pool, + vkCmdBuffer->device->handle, + vkCmdBuffer->pool, 1, - &cmdBuffer->handle); + &vkCmdBuffer->handle); - palFree(s_Vk.allocator, cmdBuffer); + palFree(s_Vk.allocator, vkCmdBuffer); } PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { + CommandBuffer* vkCmdBuffer = (CommandBuffer*)primaryCmdBuffer; + CommandBuffer* vkCmdBuffer2 = (CommandBuffer*)secondaryCmdBuffer; s_Vk.cmdExecuteCommandBuffer( - primaryCmdBuffer->handle, + vkCmdBuffer->handle, 1, - &secondaryCmdBuffer->handle); + &vkCmdBuffer2->handle); return PAL_RESULT_SUCCESS; } @@ -4424,6 +4641,12 @@ PalResult PAL_CALL setVkFragmentShadingRate( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & + PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + VkExtent2D size = getShadingRateSize(state->rate); VkFragmentShadingRateCombinerOpKHR combinerOps[2]; @@ -4459,8 +4682,8 @@ PalResult PAL_CALL setVkFragmentShadingRate( } } - cmdBuffer->device->cmdSetFragmentShadingRate( - cmdBuffer->handle, + vkCmdBuffer->device->cmdSetFragmentShadingRate( + vkCmdBuffer->handle, &size, combinerOps); @@ -4473,8 +4696,13 @@ PalResult PAL_CALL drawVkMeshTasks( Uint32 groupCountY, Uint32 groupCountZ) { - cmdBuffer->device->cmdDrawMeshTask( - cmdBuffer->handle, + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + vkCmdBuffer->device->cmdDrawMeshTask( + vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); @@ -4489,9 +4717,15 @@ PalResult PAL_CALL drawVkMeshTasksIndirect( Uint32 drawCount, Uint32 stride) { - cmdBuffer->device->cmdDrawMeshTaskIndirect( - cmdBuffer->handle, - buffer->handle, + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + Buffer* vkBuffer = (Buffer*)buffer; + vkCmdBuffer->device->cmdDrawMeshTaskIndirect( + vkCmdBuffer->handle, + vkBuffer->handle, offset, drawCount, stride); @@ -4508,11 +4742,20 @@ PalResult PAL_CALL drawVkMeshTasksIndirectCount( Uint32 maxDrawCount, Uint32 stride) { - cmdBuffer->device->cmdDrawMeshTaskIndirectCount( - cmdBuffer->handle, - buffer->handle, + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & + PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + Buffer* vkBuffer = (Buffer*)buffer; + Buffer* vkCountBuffer = (Buffer*)countBuffer; + + vkCmdBuffer->device->cmdDrawMeshTaskIndirectCount( + vkCmdBuffer->handle, + vkBuffer->handle, offset, - countBuffer->handle, + vkCountBuffer->handle, countBufferOffset, maxDrawCount, stride); @@ -4525,8 +4768,12 @@ PalResult PAL_CALL buildVkAccelerationStructures( Int32 infoCount, PalAccelerationStructureBuildInfo* infos) { - + Device* vkDevice = (Device*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL beginRenderPassVk( @@ -4535,14 +4782,17 @@ PalResult PAL_CALL beginRenderPassVk( Int32 clearValueCount, PalClearValue* clearValues) { - if (clearValueCount != renderPass->attachmentCount) { + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + RenderPass* vkRenderPass = (RenderPass*)renderPass; + + if (clearValueCount != vkRenderPass->attachmentCount) { return PAL_RESULT_INSUFFICIENT_BUFFER; } VkCommandBufferBeginInfo cmdBeginInfo = {0}; cmdBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - VkResult result = s_Vk.cmdBegin(cmdBuffer->handle, &cmdBeginInfo); + VkResult result = s_Vk.cmdBegin(vkCmdBuffer->handle, &cmdBeginInfo); if (result != VK_SUCCESS) { return vkResultToPal(result); } @@ -4569,13 +4819,13 @@ PalResult PAL_CALL beginRenderPassVk( renderPassBeginInfo.clearValueCount = clearValueCount; renderPassBeginInfo.pClearValues = tmp; - renderPassBeginInfo.framebuffer = renderPass->framebuffer; - renderPassBeginInfo.renderPass = renderPass->handle; - renderPassBeginInfo.renderArea.extent.width = renderPass->width; - renderPassBeginInfo.renderArea.extent.height = renderPass->height; + renderPassBeginInfo.framebuffer = vkRenderPass->framebuffer; + renderPassBeginInfo.renderPass = vkRenderPass->handle; + renderPassBeginInfo.renderArea.extent.width = vkRenderPass->width; + renderPassBeginInfo.renderArea.extent.height = vkRenderPass->height; s_Vk.cmdBeginRenderPass( - cmdBuffer->handle, + vkCmdBuffer->handle, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); @@ -4584,12 +4834,13 @@ PalResult PAL_CALL beginRenderPassVk( PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer) { - VkResult result = s_Vk.cmdEnd(cmdBuffer->handle); + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + s_Vk.cmdEndRenderPass(vkCmdBuffer->handle); + + VkResult result = s_Vk.cmdEnd(vkCmdBuffer->handle); if (result != VK_SUCCESS) { return vkResultToPal(result); } - - s_Vk.cmdEndRenderPass(cmdBuffer->handle); return PAL_RESULT_SUCCESS; } @@ -4603,32 +4854,37 @@ PalResult PAL_CALL submitVkCommandBuffer( VkFence fenceHandle = nullptr; VkSemaphore waitSemaphoreHandle = nullptr; VkSemaphore signalSemaphoreHandle = nullptr; + Queue* vkQueue = (Queue*)queue; + CommandBuffer* vkCmdBuffer = (CommandBuffer*)info->cmdBuffer; if (info->waitSemaphore) { - waitSemaphoreHandle = info->waitSemaphore->handle; + Semaphore* tmp = (Semaphore*)info->waitSemaphore; + waitSemaphoreHandle = tmp->handle; waitSemaphoreCount = 1; } if (info->signalSemaphore) { - signalSemaphoreHandle = info->signalSemaphore->handle; + Semaphore* tmp = (Semaphore*)info->signalSemaphore; + signalSemaphoreHandle = tmp->handle; signalSemaphoreCount = 1; } if (info->fence) { - fenceHandle = info->fence->handle; + Fence* tmp = (Fence*)info->fence; + fenceHandle = tmp->handle; } VkSubmitInfo submitInfo = {0}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &info->cmdBuffer->handle; + submitInfo.pCommandBuffers = &vkCmdBuffer->handle; submitInfo.pSignalSemaphores = &signalSemaphoreHandle; submitInfo.pWaitSemaphores = &waitSemaphoreHandle; submitInfo.waitSemaphoreCount = waitSemaphoreCount; submitInfo.waitSemaphoreCount = signalSemaphoreCount; result = s_Vk.queueSubmit( - queue->phyQueue->handle, + vkQueue->phyQueue->handle, 1, &submitInfo, fenceHandle); @@ -4650,8 +4906,15 @@ PalResult PAL_CALL createVkAccelerationstructure( PalAccelerationStructure** outAs) { VkResult result; - PalAccelerationStructure* as = nullptr; - as = palAllocate(s_Vk.allocator, sizeof(PalAccelerationStructure), 0); + AccelerationStructure* as = nullptr; + Buffer* vkBuffer = (Buffer*)info->buffer; + Device* vkDevice = (Device*)device; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + as = palAllocate(s_Vk.allocator, sizeof(AccelerationStructure), 0); if (!as) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4662,15 +4925,15 @@ PalResult PAL_CALL createVkAccelerationstructure( createInfo.offset = (VkDeviceSize)info->offset; createInfo.size = (VkDeviceSize)info->size; - createInfo.buffer = info->buffer->handle; + createInfo.buffer = vkBuffer->handle; createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; } - result = device->createAccelerationStructure( - device->handle, + result = vkDevice->createAccelerationStructure( + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &as->handle); @@ -4680,19 +4943,20 @@ PalResult PAL_CALL createVkAccelerationstructure( return vkResultToPal(result); } - *outAs = as; + *outAs = (PalAccelerationStructure*)as; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkAccelerationstructure( PalAccelerationStructure* as) { - as->device->destroyAccelerationStructure( - as->device->handle, - as->handle, + AccelerationStructure* vkAs = (AccelerationStructure*)as; + vkAs->device->destroyAccelerationStructure( + vkAs->device->handle, + vkAs->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, as); + palFree(s_Vk.allocator, vkAs); } PalResult PAL_CALL getVkAccelerationStructureBuildSize( @@ -4700,47 +4964,47 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { - Uint32* maxPrimities = nullptr; - Uint32 count = info->geometriesCount; - PalGeometry* geometries = info->geometries; + // Uint32* maxPrimities = nullptr; + // Uint32 count = info->geometriesCount; + // PalGeometry* geometries = info->geometries; - if (info->instanceCount) { - count = info->instanceCount; - geometries = info->instances; - } + // if (info->instanceCount) { + // count = info->instanceCount; + // geometries = info->instances; + // } - maxPrimities = palAllocate(s_Vk.allocator, sizeof(Uint32) * count, 0); - if (!maxPrimities) { - return PAL_RESULT_OUT_OF_MEMORY; - } + // maxPrimities = palAllocate(s_Vk.allocator, sizeof(Uint32) * count, 0); + // if (!maxPrimities) { + // return PAL_RESULT_OUT_OF_MEMORY; + // } - for (int i = 0; i < count; i++) { - maxPrimities[i] = geometries[i].primitiveCount; - } + // for (int i = 0; i < count; i++) { + // maxPrimities[i] = geometries[i].primitiveCount; + // } - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - buildInfo.dstAccelerationStructure = info->dst; - // buildInfo.ppGeometries + // VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + // buildInfo.dstAccelerationStructure = info->dst; + // // buildInfo.ppGeometries - buildInfo.sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + // buildInfo.sType = + // VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; - VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; - sizeInfo.sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; + // VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; + // sizeInfo.sType = + // VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; - device->getAccelerationBuildsize( - device->handle, - VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, - &buildInfo, - &count, - &sizeInfo); + // device->getAccelerationBuildsize( + // device->handle, + // VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + // &buildInfo, + // &count, + // &sizeInfo); - size->accelerationStructureSize = sizeInfo.accelerationStructureSize; - size->scratchBufferSize = sizeInfo.buildScratchSize; + // size->accelerationStructureSize = sizeInfo.accelerationStructureSize; + // size->scratchBufferSize = sizeInfo.buildScratchSize; - return PAL_RESULT_SUCCESS; + // return PAL_RESULT_SUCCESS; } // ================================================== diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 3d667be7..2b269472 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -308,7 +308,12 @@ bool clearColorTest() // create a command buffer for the image view PalCommandBuffer* cmdBuffer = nullptr; - result = palCreateCommandBuffer(device, cmdPool, true, &cmdBuffer); + result = palCreateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command buffer: %s", error); diff --git a/tests/tests_main.c b/tests/tests_main.c index b8d7f6ac..17c21405 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,7 +55,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + // registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From 696ca168f49ba8aaf95bd760198772e0399ee3c1 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 24 Dec 2025 17:08:11 +0000 Subject: [PATCH 064/372] simplify graphics API --- include/pal/pal_graphics.h | 31 ++- src/graphics/pal_graphics.c | 71 ++++-- src/graphics/pal_vulkan.c | 484 ++++++++++++++++++++++++++++++++---- tests/clear_color_test.c | 18 ++ 4 files changed, 523 insertions(+), 81 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 2a064e51..29928a58 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -489,7 +489,8 @@ typedef enum { typedef enum { PAL_GEOMETRY_TYPE_TRIANGLE, - PAL_GEOMETRY_TYPE_AABBS + PAL_GEOMETRY_TYPE_AABBS, + PAL_GEOMETRY_TYPE_INSTANCE } PalGeometryType; typedef enum { @@ -741,14 +742,12 @@ typedef struct { } PalGeometryDataTriangle; typedef struct { - Uint32 count; Uint32 stride; Uint64 offset; PalBuffer* buffer; } PalGeometryDataAABBS; typedef struct { - Uint32 count; Uint64 offset; PalBuffer* buffer; } PalGeometryDataInstance; @@ -1040,6 +1039,12 @@ typedef struct { void PAL_CALL (*destroyCommandBuffer)(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL (*beginCommandBuffer)( + PalCommandBuffer* cmdBuffer, + PalRenderPass* renderPass); + + PalResult PAL_CALL (*endCommandBuffer)(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL (*executeCommandBuffer)( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -1070,10 +1075,9 @@ typedef struct { Uint32 maxDrawCount, Uint32 stride); - PalResult PAL_CALL (*buildAccelerationStructures)( - PalDevice* device, - Int32 infoCount, - PalAccelerationStructureBuildInfo* infos); + PalResult PAL_CALL (*buildAccelerationStructure)( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); PalResult PAL_CALL (*beginRenderPass)( PalCommandBuffer* cmdBuffer, @@ -1310,6 +1314,12 @@ PAL_API PalResult PAL_CALL palCreateCommandBuffer( PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); +PAL_API PalResult PAL_CALL palBeginCommandBuffer( + PalCommandBuffer* cmdBuffer, + PalRenderPass* renderPass); + +PAL_API PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer); + PAL_API PalResult PAL_CALL palExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -1340,10 +1350,9 @@ PAL_API PalResult PAL_CALL palDrawMeshTasksIndirectCount( Uint32 maxDrawCount, Uint32 stride); -PAL_API PalResult PAL_CALL palBuildAccelerationStructures( - PalDevice* device, - Int32 infoCount, - PalAccelerationStructureBuildInfo* infos); +PAL_API PalResult PAL_CALL palBuildAccelerationStructure( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); PAL_API PalResult PAL_CALL palBeginRenderPass( PalCommandBuffer* cmdBuffer, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index ac83b530..54dc5b19 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -276,6 +276,12 @@ PalResult PAL_CALL createVkCommandBuffer( void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); +PalResult PAL_CALL beginVkCommandBuffer( + PalCommandBuffer* cmdBuffer, + PalRenderPass* renderPass); + +PalResult PAL_CALL endVkCommandBuffer(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -306,10 +312,9 @@ PalResult PAL_CALL drawVkMeshTasksIndirectCount( Uint32 maxDrawCount, Uint32 stride); -PalResult PAL_CALL buildVkAccelerationStructures( - PalDevice* device, - Int32 infoCount, - PalAccelerationStructureBuildInfo* infos); +PalResult PAL_CALL buildVkAccelerationStructure( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); PalResult PAL_CALL beginRenderPassVk( PalCommandBuffer* cmdBuffer, @@ -394,12 +399,14 @@ static PalGraphicsBackend s_VkBackend = { .destroyCommandPool = destroyVkCommandPool, .createCommandBuffer = createVkCommandBuffer, .destroyCommandBuffer = destroyVkCommandBuffer, + .beginCommandBuffer = beginVkCommandBuffer, + .endCommandBuffer = endVkCommandBuffer, .executeCommandBuffer = executeCommandBufferVk, .setFragmentShadingRate = setVkFragmentShadingRate, .drawMeshTasks = drawVkMeshTasks, .drawMeshTasksIndirect = drawVkMeshTasksIndirect, .drawMeshTasksIndirectCount = drawVkMeshTasksIndirectCount, - .buildAccelerationStructures = buildVkAccelerationStructures, + .buildAccelerationStructure = buildVkAccelerationStructure, .beginRenderPass = beginRenderPassVk, .endRenderPass = endRenderPassVk, .submitCommandBuffer = submitVkCommandBuffer, @@ -447,15 +454,15 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) if (!backend->enumerateAdapters || !backend->getAdapterInfo || !backend->getAdapterCapabilities || - !backend->queryDepthStencilCapabilities || - !backend->queryFragmentShadingRateCapabilities || - !backend->queryMeshShaderCapabilities || - !backend->queryRayTracingCapabilities || !backend->getAdapterFeatures || !backend->createDevice || !backend->destroyDevice || !backend->allocateMemory || !backend->freeMemory || + !backend->queryDepthStencilCapabilities || + !backend->queryFragmentShadingRateCapabilities || + !backend->queryMeshShaderCapabilities || + !backend->queryRayTracingCapabilities || !backend->createQueue || !backend->destroyQueue || !backend->canQueuePresent || @@ -494,12 +501,14 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroyCommandPool || !backend->createCommandBuffer || !backend->destroyCommandBuffer || + !backend->beginCommandBuffer || + !backend->endCommandBuffer || !backend->executeCommandBuffer || !backend->setFragmentShadingRate || !backend->drawMeshTasks || !backend->drawMeshTasksIndirect || !backend->drawMeshTasksIndirectCount || - !backend->buildAccelerationStructures || + !backend->buildAccelerationStructure || !backend->beginRenderPass || !backend->endRenderPass || !backend->submitCommandBuffer || @@ -1480,6 +1489,34 @@ void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) } } +PalResult PAL_CALL palBeginCommandBuffer( + PalCommandBuffer* cmdBuffer, + PalRenderPass* renderPass) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->beginCommandBuffer(cmdBuffer, renderPass); +} + +PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->endCommandBuffer(cmdBuffer); +} + PalResult PAL_CALL palExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) @@ -1586,22 +1623,20 @@ PalResult PAL_CALL palDrawMeshTasksIndirectCount( } PalResult PAL_CALL palBuildAccelerationStructures( - PalDevice* device, - Int32 infoCount, - PalAccelerationStructureBuildInfo* infos) + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device || !infos || infoCount <= 0) { + if (!cmdBuffer) { return PAL_RESULT_NULL_POINTER; } - return device->backend->buildAccelerationStructures( - device, - infoCount, - infos); + return cmdBuffer->backend->buildAccelerationStructure( + cmdBuffer, + info); } PalResult PAL_CALL palBeginRenderPass( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index eb0c6cde..ff22f48e 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -298,6 +298,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + VkDeviceAddress address; Device* device; VkBuffer handle; } Buffer; @@ -305,6 +306,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + VkDeviceAddress address; Device* device; VkAccelerationStructureKHR handle; } AccelerationStructure; @@ -1082,6 +1084,109 @@ static VkExtent2D getShadingRateSize(PalFragmentShadingRate rate) return (VkExtent2D){0, 0}; } +static VkFormat vertexTypeToVkFormat(PalVertexType type) +{ + switch (type) { + case PAL_VERTEX_TYPE_INT32: + return VK_FORMAT_R32_SINT; + + case PAL_VERTEX_TYPE_INT32_2: + return VK_FORMAT_R32G32_SINT; + + case PAL_VERTEX_TYPE_INT32_3: + return VK_FORMAT_R32G32B32_SINT; + + case PAL_VERTEX_TYPE_INT32_4: + return VK_FORMAT_R32G32B32A32_SINT; + + case PAL_VERTEX_TYPE_UINT32: + return VK_FORMAT_R32_UINT; + + case PAL_VERTEX_TYPE_UINT32_2: + return VK_FORMAT_R32G32_UINT; + + case PAL_VERTEX_TYPE_UINT32_3: + return VK_FORMAT_R32G32B32_UINT; + + case PAL_VERTEX_TYPE_UINT32_4: + return VK_FORMAT_R32G32B32A32_UINT; + + + case PAL_VERTEX_TYPE_INT8_2: + return VK_FORMAT_R8G8_SINT; + + case PAL_VERTEX_TYPE_INT8_4: + return VK_FORMAT_R8G8B8A8_SINT; + + case PAL_VERTEX_TYPE_UINT8_2: + return VK_FORMAT_R8G8_UINT; + + case PAL_VERTEX_TYPE_UINT8_4: + return VK_FORMAT_R8G8B8A8_UINT; + + + case PAL_VERTEX_TYPE_INT8_2NORM: + return VK_FORMAT_R8G8_SNORM; + + case PAL_VERTEX_TYPE_INT8_4NORM: + return VK_FORMAT_R8G8B8A8_SNORM; + + case PAL_VERTEX_TYPE_UINT8_2NORM: + return VK_FORMAT_R8G8_UNORM; + + case PAL_VERTEX_TYPE_UINT8_4NORM: + return VK_FORMAT_R8G8B8A8_UNORM; + + + case PAL_VERTEX_TYPE_INT16_2: + return VK_FORMAT_R16G16_SINT; + + case PAL_VERTEX_TYPE_INT16_4: + return VK_FORMAT_R16G16B16A16_SINT; + + case PAL_VERTEX_TYPE_UINT16_2: + return VK_FORMAT_R16G16_UINT; + + case PAL_VERTEX_TYPE_UINT16_4: + return VK_FORMAT_R16G16B16A16_UINT; + + + case PAL_VERTEX_TYPE_INT16_2NORM: + return VK_FORMAT_R16G16_SNORM; + + case PAL_VERTEX_TYPE_INT16_4NORM: + return VK_FORMAT_R16G16B16A16_SNORM; + + case PAL_VERTEX_TYPE_UINT16_2NORM: + return VK_FORMAT_R16G16_UNORM; + + case PAL_VERTEX_TYPE_UINT16_4NORM: + return VK_FORMAT_R16G16B16A16_UNORM; + + + case PAL_VERTEX_TYPE_FLOAT: + return VK_FORMAT_R32_SFLOAT; + + case PAL_VERTEX_TYPE_FLOAT2: + return VK_FORMAT_R32G32_SFLOAT; + + case PAL_VERTEX_TYPE_FLOAT3: + return VK_FORMAT_R32G32B32_SFLOAT; + + case PAL_VERTEX_TYPE_FLOAT4: + return VK_FORMAT_R32G32B32A32_SFLOAT; + + + case PAL_VERTEX_TYPE_HALF_FLOAT16_2: + return VK_FORMAT_R16G16_SFLOAT; + + case PAL_VERTEX_TYPE_HALF_FLOAT16_4: + return VK_FORMAT_R16G16B16A16_SFLOAT; + } + + return VK_FORMAT_UNDEFINED; +} + static void* vkAlloc( void* pUserData, size_t size, @@ -3097,6 +3202,7 @@ PalImageUsages PAL_CALL queryVkFormatImageUsages( if (props.optimalTilingFeatures == 0) { return PAL_IMAGE_USAGE_UNDEFINED; } + return vkFeatureToPalUsage(props.optimalTilingFeatures); } @@ -3220,6 +3326,7 @@ void PAL_CALL destroyVkImage(PalImage* image) if (vkImage->belongsToSwapchain) { return; } + s_Vk.destroyImage( vkImage->device->handle, vkImage->handle, @@ -3242,6 +3349,10 @@ PalResult PAL_CALL getVkImageMemoryRequirements( PalMemoryRequirements* requirements) { Image* vkImage = (Image*)image; + if (vkImage->belongsToSwapchain) { + return PAL_RESULT_INVALID_OPERATION; + } + Device* device = vkImage->device; VkPhysicalDevice phyDevice = (VkPhysicalDevice)device->phyDevice; VkPhysicalDeviceMemoryProperties memProps = {0}; @@ -3313,6 +3424,13 @@ PalResult PAL_CALL createVkImageView( Device* vkDevice = (Device*)device; Image* vkImage = (Image*)image; + if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { + if (!(vkDevice->features & + PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + imageView = palAllocate(s_Vk.allocator, sizeof(ImageView), 0); if (!imageView) { return PAL_RESULT_OUT_OF_MEMORY; @@ -4623,6 +4741,53 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) palFree(s_Vk.allocator, vkCmdBuffer); } +PalResult PAL_CALL beginVkCommandBuffer( + PalCommandBuffer* cmdBuffer, + PalRenderPass* renderPass) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + RenderPass* vkRenderPass = (RenderPass*)renderPass; + VkRenderPass renderPassHandle = nullptr; + VkFramebuffer frambufferHandle = nullptr; + + VkCommandBufferBeginInfo beginInfo = {0}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + VkCommandBufferInheritanceInfo inheritanceInfo = {0}; + inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + + if (!vkCmdBuffer->primary) { + // secondary command buffer + if (renderPass) { + renderPassHandle = vkRenderPass->handle; + frambufferHandle = vkRenderPass->framebuffer; + inheritanceInfo.framebuffer = frambufferHandle; + inheritanceInfo.renderPass = renderPassHandle; + + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; + beginInfo .pInheritanceInfo = &inheritanceInfo; + } + } + + VkResult result = s_Vk.cmdBegin(vkCmdBuffer->handle, &beginInfo); + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL endVkCommandBuffer(PalCommandBuffer* cmdBuffer) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + VkResult result = s_Vk.cmdEnd(vkCmdBuffer->handle); + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) @@ -4763,15 +4928,138 @@ PalResult PAL_CALL drawVkMeshTasksIndirectCount( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL buildVkAccelerationStructures( - PalDevice* device, - Int32 infoCount, - PalAccelerationStructureBuildInfo* infos) +PalResult PAL_CALL buildVkAccelerationStructure( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info) { - Device* vkDevice = (Device*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + + VkAccelerationStructureGeometryKHR* geometries = nullptr; + VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; + AccelerationStructure* vkAs = (AccelerationStructure*)info->dst; + Buffer* vkScratchBuffer = (Buffer*)info->scratchBuffer; + + geometries = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount, + 0); + + rangeInfos = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->geometryCount, + 0); + + if (!rangeInfos || !geometries) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // clang-format off + for (int i = 0; i < info->geometryCount; i++) { + // fill vulkan geometry struct + VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; + tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + tmp->flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + + if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { + tmp->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + + VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; + data->pNext = nullptr; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; + + VkDeviceOrHostAddressConstKHR vertexAddress = {0}; + VkDeviceOrHostAddressConstKHR indexAddress = {0}; + PalGeometryDataTriangle* tmpData = info->geometries[i].data; + Buffer* vkVertexBuffer = (Buffer*)tmpData->vertexBuffer; + Buffer* vkIndexBuffer = (Buffer*)tmpData->indexBuffer; + + vertexAddress.deviceAddress = vkVertexBuffer->address + tmpData->vertexOffset; + data->vertexData = vertexAddress; + data->maxVertex = tmpData->vertexCount; + data->vertexFormat = vertexTypeToVkFormat(tmpData->vertexType); + data->vertexStride = tmpData->vertexStride; + + indexAddress.deviceAddress = vkIndexBuffer->address + tmpData->indexOffset; + data->indexData = indexAddress; + if (tmpData->indexType == PAL_INDEX_TYPE_UINT32) { + data->indexType = VK_INDEX_TYPE_UINT32; + } else { + data->indexType = VK_INDEX_TYPE_UINT16; + } + + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { + tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; + VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; + data->pNext = nullptr; + data->sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; + + VkDeviceOrHostAddressConstKHR address = {0}; + PalGeometryDataAABBS* tmpData = info->geometries[i].data; + Buffer* vkBuffer = (Buffer*)tmpData->buffer; + address.deviceAddress = vkBuffer->address + tmpData->offset; + data->data = address; + data->stride = tmpData->stride; + + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_INSTANCE) { + tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; + data = &tmp->geometry.instances; + data->pNext = nullptr; + data->sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + + VkDeviceOrHostAddressConstKHR address = {0}; + PalGeometryDataInstance* tmpData = info->geometries[i].data; + Buffer* vkBuffer = (Buffer*)tmpData->buffer; + address.deviceAddress = vkBuffer->address + tmpData->offset; + data->data = address; + } + + // range info + VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; + rangeInfo->primitiveCount = info->geometries[i].primitiveCount; + rangeInfo->firstVertex = 0; // PAL does not allow setting this + rangeInfo->primitiveOffset = 0; // PAL does not allow setting this + rangeInfo->transformOffset = 0; // PAL does not allow setting this + } + // clang-format on + + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + buildInfo.sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + } else { + buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + } + + buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + buildInfo.geometryCount = info->geometryCount; + buildInfo.dstAccelerationStructure = vkAs->handle; + + VkDeviceOrHostAddressKHR scratchData = {0}; + scratchData.deviceAddress = + vkScratchBuffer->address + info->scratchBufferOffset; + buildInfo.scratchData = scratchData; + + buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; + buildInfo.pGeometries = geometries; + + const VkAccelerationStructureBuildRangeInfoKHR* tmp[1]; + tmp[0] = rangeInfos; + vkCmdBuffer->device->cmdBuildAccelerationStructures( + vkCmdBuffer->handle, + 1, + &buildInfo, + tmp); + + palFree(s_Vk.allocator, geometries); + palFree(s_Vk.allocator, rangeInfos); return PAL_RESULT_SUCCESS; } @@ -4784,19 +5072,10 @@ PalResult PAL_CALL beginRenderPassVk( { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; RenderPass* vkRenderPass = (RenderPass*)renderPass; - if (clearValueCount != vkRenderPass->attachmentCount) { return PAL_RESULT_INSUFFICIENT_BUFFER; } - VkCommandBufferBeginInfo cmdBeginInfo = {0}; - cmdBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - VkResult result = s_Vk.cmdBegin(vkCmdBuffer->handle, &cmdBeginInfo); - if (result != VK_SUCCESS) { - return vkResultToPal(result); - } - VkRenderPassBeginInfo renderPassBeginInfo = {0}; renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; VkClearValue tmp[MAX_ATTACHMENTS]; @@ -4836,11 +5115,6 @@ PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.cmdEndRenderPass(vkCmdBuffer->handle); - - VkResult result = s_Vk.cmdEnd(vkCmdBuffer->handle); - if (result != VK_SUCCESS) { - return vkResultToPal(result); - } return PAL_RESULT_SUCCESS; } @@ -4914,6 +5188,10 @@ PalResult PAL_CALL createVkAccelerationstructure( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (!vkBuffer->address) { + return PAL_RESULT_INVALID_BUFFER; + } + as = palAllocate(s_Vk.allocator, sizeof(AccelerationStructure), 0); if (!as) { return PAL_RESULT_OUT_OF_MEMORY; @@ -4943,6 +5221,17 @@ PalResult PAL_CALL createVkAccelerationstructure( return vkResultToPal(result); } + // get and cache address + VkAccelerationStructureDeviceAddressInfoKHR addressInfo = {0}; + addressInfo.sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; + addressInfo.accelerationStructure = as->handle; + + as->address = vkDevice->getAccelerationDeviceAddress( + vkDevice->handle, + &addressInfo); + + as->device = vkDevice; *outAs = (PalAccelerationStructure*)as; return PAL_RESULT_SUCCESS; } @@ -4964,47 +5253,138 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { - // Uint32* maxPrimities = nullptr; - // Uint32 count = info->geometriesCount; - // PalGeometry* geometries = info->geometries; - - // if (info->instanceCount) { - // count = info->instanceCount; - // geometries = info->instances; - // } + Uint32* maxPrimities = nullptr; + VkAccelerationStructureGeometryKHR* geometries = nullptr; + + Device* vkDevice = (Device*)device; + AccelerationStructure* vkAs = (AccelerationStructure*)info->dst; + Buffer* vkScratchBuffer = (Buffer*)info->scratchBuffer; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + maxPrimities = palAllocate( + s_Vk.allocator, + sizeof(Uint32) * info->geometryCount, + 0); + + geometries = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount, + 0); - // maxPrimities = palAllocate(s_Vk.allocator, sizeof(Uint32) * count, 0); - // if (!maxPrimities) { - // return PAL_RESULT_OUT_OF_MEMORY; - // } + if (!maxPrimities || !geometries) { + return PAL_RESULT_OUT_OF_MEMORY; + } - // for (int i = 0; i < count; i++) { - // maxPrimities[i] = geometries[i].primitiveCount; - // } + // clang-format off + for (int i = 0; i < info->geometryCount; i++) { + maxPrimities[i] = info->geometries[i].primitiveCount; - // VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - // buildInfo.dstAccelerationStructure = info->dst; - // // buildInfo.ppGeometries + // fill vulkan geometry struct + VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; + tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + tmp->flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { + tmp->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - // buildInfo.sType = - // VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; + data->pNext = nullptr; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; + + VkDeviceOrHostAddressConstKHR vertexAddress = {0}; + VkDeviceOrHostAddressConstKHR indexAddress = {0}; + PalGeometryDataTriangle* tmpData = info->geometries[i].data; + Buffer* vkVertexBuffer = (Buffer*)tmpData->vertexBuffer; + Buffer* vkIndexBuffer = (Buffer*)tmpData->indexBuffer; + + vertexAddress.deviceAddress = vkVertexBuffer->address + tmpData->vertexOffset; + data->vertexData = vertexAddress; + data->maxVertex = tmpData->vertexCount; + data->vertexFormat = vertexTypeToVkFormat(tmpData->vertexType); + data->vertexStride = tmpData->vertexStride; + + indexAddress.deviceAddress = vkIndexBuffer->address + tmpData->indexOffset; + data->indexData = indexAddress; + if (tmpData->indexType == PAL_INDEX_TYPE_UINT32) { + data->indexType = VK_INDEX_TYPE_UINT32; + } else { + data->indexType = VK_INDEX_TYPE_UINT16; + } + + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { + tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; + VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; + data->pNext = nullptr; + data->sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; + + VkDeviceOrHostAddressConstKHR address = {0}; + PalGeometryDataAABBS* tmpData = info->geometries[i].data; + Buffer* vkBuffer = (Buffer*)tmpData->buffer; + address.deviceAddress = vkBuffer->address + tmpData->offset; + data->data = address; + data->stride = tmpData->stride; + + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_INSTANCE) { + tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; + data = &tmp->geometry.instances; + data->pNext = nullptr; + data->sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + + VkDeviceOrHostAddressConstKHR address = {0}; + PalGeometryDataInstance* tmpData = info->geometries[i].data; + Buffer* vkBuffer = (Buffer*)tmpData->buffer; + address.deviceAddress = vkBuffer->address + tmpData->offset; + data->data = address; + } + } + // clang-format on + + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + buildInfo.sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + } else { + buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + } - // VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; - // sizeInfo.sType = - // VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; + buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + buildInfo.geometryCount = info->geometryCount; + buildInfo.dstAccelerationStructure = vkAs->handle; - // device->getAccelerationBuildsize( - // device->handle, - // VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, - // &buildInfo, - // &count, - // &sizeInfo); + VkDeviceOrHostAddressKHR scratchData = {0}; + scratchData.deviceAddress = + vkScratchBuffer->address + info->scratchBufferOffset; + buildInfo.scratchData = scratchData; - // size->accelerationStructureSize = sizeInfo.accelerationStructureSize; - // size->scratchBufferSize = sizeInfo.buildScratchSize; + buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; + buildInfo.pGeometries = geometries; - // return PAL_RESULT_SUCCESS; + VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; + sizeInfo.sType = + VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; + + vkDevice->getAccelerationBuildsize( + vkDevice->handle, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + &buildInfo, + maxPrimities, + &sizeInfo); + + size->accelerationStructureSize = sizeInfo.accelerationStructureSize; + size->scratchBufferSize = sizeInfo.buildScratchSize; + + palFree(s_Vk.allocator, maxPrimities); + palFree(s_Vk.allocator, geometries); + + return PAL_RESULT_SUCCESS; } // ================================================== diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 2b269472..dfff5627 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -327,6 +327,16 @@ bool clearColorTest() clearValue.color[2] = 0.2f; clearValue.color[3] = 1.0f; + // begin command buffer recording + // the optional render pass is used for secondary command buffer + // which will be used with a render pass + result = palBeginCommandBuffer(cmdBuffer, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + result = palBeginRenderPass(cmdBuffer, renderPass, 1, &clearValue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -340,6 +350,14 @@ bool clearColorTest() palLog(nullptr, "Failed to end render pass: %s", error); return false; } + + // end command buffer recording + result = palEndCommandBuffer(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } // cache everything so we can reference and destroy later renderPasses[i] = renderPass; From 97f0f9f2d51443ef95388f7971bfa8451ff50c01 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 29 Dec 2025 16:34:17 +0000 Subject: [PATCH 065/372] add buffer API --- include/pal/pal_graphics.h | 91 +++++++- src/graphics/pal_graphics.c | 184 ++++++++++++++++ src/graphics/pal_vulkan.c | 415 ++++++++++++++++++++++++++++++++++-- tests/graphics_test.c | 4 + tests/tests_main.c | 2 +- 5 files changed, 671 insertions(+), 25 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 29928a58..6e274488 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -247,7 +247,8 @@ typedef enum { PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(29), PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(30), PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(31), - PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT = PAL_BIT64(32) + PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT = PAL_BIT64(32), + PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(33) } PalAdapterFeatures; typedef enum { @@ -498,6 +499,17 @@ typedef enum { PAL_INDEX_TYPE_UINT32 } PalIndexType; +typedef enum { + PAL_BUFFER_USAGE_VERTEX = PAL_BIT(0), + PAL_BUFFER_USAGE_INDEX = PAL_BIT(1), + PAL_BUFFER_USAGE_UNIFORM = PAL_BIT(2), + PAL_BUFFER_USAGE_STORAGE = PAL_BIT(3), + PAL_BUFFER_USAGE_TRANSFER_SRC = PAL_BIT(4), + PAL_BUFFER_USAGE_TRANSFER_DST = PAL_BIT(5), + PAL_BUFFER_USAGE_RAY_TRACING = PAL_BIT(6), + PAL_BUFFER_USAGE_DEVICE_ADDRESS = PAL_BIT(7) +} PalBufferUsages; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -818,6 +830,11 @@ typedef struct { PalQueue* queue; } PalCommandPoolCreateInfo; +typedef struct { + PalBufferUsages usages; + Uint64 size; +} PalBufferCreateInfo; + typedef struct { PalAccelerationStructureType type; PalBuffer* buffer; @@ -934,7 +951,7 @@ typedef struct { PalResult PAL_CALL (*getImageMemoryRequirements)( PalImage* image, - PalMemoryRequirements* requirments); + PalMemoryRequirements* requirements); PalResult PAL_CALL (*bindImageMemory)( PalImage* image, @@ -1087,6 +1104,14 @@ typedef struct { PalResult PAL_CALL (*endRenderPass)(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL (*copyBuffer)( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + Uint64 dstOffset, + Uint64 srcOffset, + Uint32 size); + PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, PalSubmitInfo* info); @@ -1104,6 +1129,33 @@ typedef struct { PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); + PalResult PAL_CALL (*createBuffer)( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + + void PAL_CALL (*destroyBuffer)(PalBuffer* buffer); + + PalResult PAL_CALL (*getBufferMemoryRequirements)( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + + PalResult PAL_CALL (*bindBufferMemory)( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset); + + PalResult PAL_CALL (*mapBuffer)( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr); + + void PAL_CALL (*unmapBuffer)( + PalBuffer* buffer, + PalMemory* memory); + PalResult PAL_CALL (*createGraphicsPipeline)( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, @@ -1362,6 +1414,14 @@ PAL_API PalResult PAL_CALL palBeginRenderPass( PAL_API PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer); +PAL_API PalResult PAL_CALL palCopyBuffer( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + Uint64 dstOffset, + Uint64 srcOffset, + Uint32 size); + PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalSubmitInfo* info); @@ -1379,6 +1439,33 @@ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); +PAL_API PalResult PAL_CALL palCreateBuffer( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + +PAL_API void PAL_CALL palDestroyBuffer(PalBuffer* buffer); + +PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + +PAL_API PalResult PAL_CALL palBindBufferMemory( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset); + +PAL_API PalResult PAL_CALL palMapBuffer( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr); + +PAL_API void PAL_CALL palUnmapBuffer( + PalBuffer* buffer, + PalMemory* memory); + PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 54dc5b19..3bf0979b 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -50,6 +50,7 @@ PAL_HANDLE(PalCommandPool) PAL_HANDLE(PalCommandBuffer) PAL_HANDLE(PalPipeline) PAL_HANDLE(PalAccelerationStructure) +PAL_HANDLE(PalBufferView) typedef struct { Int32 count; @@ -324,6 +325,14 @@ PalResult PAL_CALL beginRenderPassVk( PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer); +PalResult PAL_CALL copyVkBuffer( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + Uint64 dstOffset, + Uint64 srcOffset, + Uint32 size); + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalSubmitInfo* info); @@ -341,6 +350,33 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); +PalResult PAL_CALL createVkBuffer( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + +void PAL_CALL destroyVkBuffer(PalBuffer* buffer); + +PalResult PAL_CALL getVkBufferMemoryRequirements( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL bindVkBufferMemory( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset); + +PalResult PAL_CALL mapVkBuffer( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr); + +void PAL_CALL unmapVkBuffer( + PalBuffer* buffer, + PalMemory* memory); + PalResult PAL_CALL createVkGraphicsPipeline( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, @@ -409,10 +445,17 @@ static PalGraphicsBackend s_VkBackend = { .buildAccelerationStructure = buildVkAccelerationStructure, .beginRenderPass = beginRenderPassVk, .endRenderPass = endRenderPassVk, + .copyBuffer = copyVkBuffer, .submitCommandBuffer = submitVkCommandBuffer, .createAccelerationstructure = createVkAccelerationstructure, .destroyAccelerationstructure = destroyVkAccelerationstructure, .getAccelerationStructureBuildSize = getVkAccelerationStructureBuildSize, + .createBuffer = createVkBuffer, + .destroyBuffer = destroyVkBuffer, + .getBufferMemoryRequirements = getVkBufferMemoryRequirements, + .bindBufferMemory = bindVkBufferMemory, + .mapBuffer = mapVkBuffer, + .unmapBuffer = unmapVkBuffer, .createGraphicsPipeline = createVkGraphicsPipeline, .destroyPipeline = destroyVkPipeline }; @@ -511,10 +554,17 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->buildAccelerationStructure || !backend->beginRenderPass || !backend->endRenderPass || + !backend->copyBuffer || !backend->submitCommandBuffer || !backend->createAccelerationstructure || !backend->destroyAccelerationstructure || !backend->getAccelerationStructureBuildSize || + !backend->createBuffer || + !backend->destroyBuffer || + !backend->getBufferMemoryRequirements || + !backend->bindBufferMemory || + !backend->mapBuffer || + !backend->unmapBuffer || !backend->createGraphicsPipeline || !backend->destroyPipeline) { return PAL_RESULT_INVALID_BACKEND; @@ -1677,6 +1727,31 @@ PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer) return cmdBuffer->backend->endRenderPass(cmdBuffer); } +PalResult PAL_CALL palCopyBuffer( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + Uint64 dstOffset, + Uint64 srcOffset, + Uint32 size) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !dst || !src) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->copyBuffer( + cmdBuffer, + dst, + src, + dstOffset, + srcOffset, + size); +} + PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalSubmitInfo* info) @@ -1762,6 +1837,115 @@ PalResult PAL_CALL palGetAccelerationStructureBuildSize( size); } +// ================================================== +// Buffer +// ================================================== + +PalResult PAL_CALL palCreateBuffer( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info) { + return PAL_RESULT_NULL_POINTER; + } + + PalResult result; + PalBuffer* buffer = nullptr; + result = device->backend->createBuffer( + device, + info, + &buffer); + + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + buffer->backend = device->backend; + *outBuffer = buffer; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyBuffer(PalBuffer* buffer) +{ + if (s_Graphics.initialized && buffer) { + buffer->backend->destroyBuffer(buffer); + } +} + +PalResult PAL_CALL palGetBufferMemoryRequirements( + PalBuffer* buffer, + PalMemoryRequirements* requirements) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!buffer) { + return PAL_RESULT_NULL_POINTER; + } + + return buffer->backend->getBufferMemoryRequirements( + buffer, + requirements); +} + +PalResult PAL_CALL palBindBufferMemory( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!buffer || !memory) { + return PAL_RESULT_NULL_POINTER; + } + + return buffer->backend->bindBufferMemory( + buffer, + memory, + offset); +} + +PalResult PAL_CALL palMapBuffer( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!buffer || !memory || !outPtr) { + return PAL_RESULT_NULL_POINTER; + } + + return buffer->backend->mapBuffer( + buffer, + memory, + offset, + size, + outPtr); +} + +void PAL_CALL palUnmapBuffer( + PalBuffer* buffer, + PalMemory* memory) +{ + if (!s_Graphics.initialized || !buffer || !memory) { + return; + } + buffer->backend->unmapBuffer(buffer, memory); +} + // ================================================== // Pipeline // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index ff22f48e..4e1c32a7 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -136,6 +136,7 @@ typedef struct { PFN_vkQueueSubmit queueSubmit; PFN_vkCmdBeginRenderPass cmdBeginRenderPass; PFN_vkCmdEndRenderPass cmdEndRenderPass; + PFN_vkCmdCopyBuffer cmdCopyBuffer; PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; @@ -147,6 +148,16 @@ typedef struct { PFN_vkGetPhysicalDeviceSurfaceFormatsKHR getSurfaceFormats; PFN_vkGetPhysicalDeviceSurfacePresentModesKHR getSurfacePresentModes; + PFN_vkCreateBuffer createBuffer; + PFN_vkDestroyBuffer destroyBuffer; + PFN_vkGetBufferMemoryRequirements getBufferMemoryRequirements; + PFN_vkBindBufferMemory bindBufferMemory; + PFN_vkMapMemory mapMemory; + PFN_vkUnmapMemory unmapMemory; + + PFN_vkCreateGraphicsPipelines createGraphicsPipeline; + PFN_vkDestroyPipeline destroyPipeline; + VkAllocationCallbacks vkAllocator; const PalAllocator* allocator; } Vulkan; @@ -171,6 +182,7 @@ typedef struct { VkDevice handle; PhysicalQueue* phyQueues; PFN_vkCreateRenderPass2 createRenderPass2; + PFN_vkGetBufferDeviceAddress getBufferrAddress; // swapchain PFN_vkCreateSwapchainKHR createSwapchain; @@ -303,6 +315,14 @@ typedef struct { VkBuffer handle; } Buffer; +typedef struct { + const PalGraphicsBackend* backend; + + PalBuffer* buffer; + Device* device; + VkBufferView handle; +} BufferView; + typedef struct { const PalGraphicsBackend* backend; @@ -409,7 +429,7 @@ static PalResult vkResultToPal(VkResult result) return PAL_RESULT_PLATFORM_FAILURE; } -static VkImageUsageFlags palUsageToVk(PalImageUsages usages) +static VkImageUsageFlags palImageUsageToVk(PalImageUsages usages) { VkImageUsageFlags flags = 0; if (usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { @@ -1187,6 +1207,46 @@ static VkFormat vertexTypeToVkFormat(PalVertexType type) return VK_FORMAT_UNDEFINED; } +static VkBufferUsageFlags palBufferUsageToVk(PalBufferUsages usages) +{ + VkBufferUsageFlags flags = 0; + if (usages & PAL_BUFFER_USAGE_VERTEX) { + flags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + } + + if (usages & PAL_BUFFER_USAGE_INDEX) { + flags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + } + + if (usages & PAL_BUFFER_USAGE_UNIFORM) { + flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + } + + if (usages & PAL_BUFFER_USAGE_STORAGE) { + flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + } + + if (usages & PAL_BUFFER_USAGE_TRANSFER_SRC) { + flags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + } + + if (usages & PAL_BUFFER_USAGE_TRANSFER_DST) { + flags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + } + + if (usages & PAL_BUFFER_USAGE_RAY_TRACING) { + flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + flags |= + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + } + + if (usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + } + + return flags; +} + static void* vkAlloc( void* pUserData, size_t size, @@ -1447,10 +1507,46 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCmdEndRenderPass"); + s_Vk.cmdCopyBuffer = (PFN_vkCmdCopyBuffer)dlsym( + s_Vk.handle, + "vkCmdCopyBuffer"); + s_Vk.queueSubmit = (PFN_vkQueueSubmit)dlsym( s_Vk.handle, "vkQueueSubmit"); + s_Vk.createBuffer = (PFN_vkCreateBuffer)dlsym( + s_Vk.handle, + "vkCreateBuffer"); + + s_Vk.destroyBuffer = (PFN_vkDestroyBuffer)dlsym( + s_Vk.handle, + "vkDestroyBuffer"); + + s_Vk.mapMemory = (PFN_vkMapMemory)dlsym( + s_Vk.handle, + "vkMapMemory"); + + s_Vk.unmapMemory = (PFN_vkUnmapMemory)dlsym( + s_Vk.handle, + "vkUnmapMemory"); + + s_Vk.getBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)dlsym( + s_Vk.handle, + "vkGetBufferMemoryRequirements"); + + s_Vk.bindBufferMemory = (PFN_vkBindBufferMemory)dlsym( + s_Vk.handle, + "vkBindBufferMemory"); + + s_Vk.createGraphicsPipeline = (PFN_vkCreateGraphicsPipelines)dlsym( + s_Vk.handle, + "vkCreateGraphicsPipelines"); + + s_Vk.destroyPipeline = (PFN_vkDestroyPipeline)dlsym( + s_Vk.handle, + "vkDestroyPipeline"); + // clang-format on // get version @@ -1948,6 +2044,7 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) bool shaderFloat16 = false; bool multiiView = false; bool dynamicstate = false; + bool bufferDeviceAddress = false; // clang-format off // check if the extensions are present @@ -2003,6 +2100,9 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } else if (strcmp(props->extensionName, "VK_KHR_draw_indirect_count") == 0) { adapterFeatures |= PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT; + + } else if (strcmp(props->extensionName, "VK_KHR_buffer_device_address") == 0) { + bufferDeviceAddress = true; } } @@ -2140,6 +2240,26 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } } + // buffer device address is part of core 1.2 + // if ray tracing is supported, buffer device address will be supported as well + if (adapterFeatures & PAL_ADAPTER_FEATURE_RAY_TRACING) { + adapterFeatures |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; + } else { + if (props.apiVersion >= VK_API_VERSION_1_2 || bufferDeviceAddress) { + VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; + bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &bufferAddress; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (bufferAddress.bufferDeviceAddress) { + adapterFeatures |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; + } + } + } + // clang-format on VkPhysicalDeviceFeatures features; s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); @@ -2332,9 +2452,10 @@ PalResult PAL_CALL createVkDevice( VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynamicState2 = {0}; dynamicState2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; - // clang-format on - bool coreSemaphore = false; + VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; + bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; + // clang-format on if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { extensions[extCount++] = "VK_KHR_swapchain"; } @@ -2350,7 +2471,6 @@ PalResult PAL_CALL createVkDevice( timeline.timelineSemaphore = true; start = &timeline; - coreSemaphore = true; } if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { @@ -2556,6 +2676,42 @@ PalResult PAL_CALL createVkDevice( start = &dynamicState2; } + if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_buffer_device_address"; + } + bufferAddress.bufferDeviceAddress = true; + + if (dynamicState2.extendedDynamicState2) { + dynamicState2.pNext = &bufferAddress; + + } else if (dynamicState.extendedDynamicState) { + dynamicState.pNext = &dynamicState2; + + } else if (multiView.multiview) { + multiView.pNext = &dynamicState2; + + } else if (descIndex.shaderSampledImageArrayNonUniformIndexing) { + descIndex.pNext = &dynamicState2; + + } else if (vrs.pipelineFragmentShadingRate) { + vrs.pNext = &dynamicState2; + + } else if (mesh.meshShader) { + mesh.pNext = &dynamicState2; + + } else if (acc.accelerationStructure) { + acc.pNext = &dynamicState2; + + } else if (shader16.shaderFloat16) { + shader16.pNext = &dynamicState2; + + } else if (timeline.timelineSemaphore) { + timeline.pNext = &dynamicState2; + } + start = &dynamicState2; + } + VkDeviceCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pEnabledFeatures = &coreFeatures; @@ -2637,20 +2793,19 @@ PalResult PAL_CALL createVkDevice( // load semaphore procs if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - if (coreSemaphore) { - device->waitSemaphore = (PFN_vkWaitSemaphores)s_Vk.getDeviceProcAddr( - device->handle, - "vkWaitSemaphores"); + device->waitSemaphore = (PFN_vkWaitSemaphores)s_Vk.getDeviceProcAddr( + device->handle, + "vkWaitSemaphores"); - device->signalSemaphore = (PFN_vkSignalSemaphore)s_Vk.getDeviceProcAddr( - device->handle, - "vkSignalSemaphore"); + device->signalSemaphore = (PFN_vkSignalSemaphore)s_Vk.getDeviceProcAddr( + device->handle, + "vkSignalSemaphore"); - device->getSemaphoreValue = (PFN_vkGetSemaphoreCounterValue)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetSemaphoreCounterValue"); + device->getSemaphoreValue = (PFN_vkGetSemaphoreCounterValue)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetSemaphoreCounterValue"); - } else { + if (!device->waitSemaphore) { device->waitSemaphore = (PFN_vkWaitSemaphoresKHR)s_Vk.getDeviceProcAddr( device->handle, "vkWaitSemaphoresKHR"); @@ -2750,6 +2905,21 @@ PalResult PAL_CALL createVkDevice( "vkCmdTraceRaysIndirectKHR"); } + // buffer address + if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { + device->getBufferrAddress = + (PFN_vkGetBufferDeviceAddress)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetBufferDeviceAddress"); + + if (!device->getBufferrAddress) { + device->getBufferrAddress = + (PFN_vkGetBufferDeviceAddressKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetBufferDeviceAddressKHR"); + } + } + device->features = features; palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); @@ -3283,7 +3453,7 @@ PalResult PAL_CALL createVkImage( createInfo.format = palFormatToVk(info->format); createInfo.samples = samplesToVk(info->sampleCount); - createInfo.usage = palUsageToVk(info->usages); + createInfo.usage = palImageUsageToVk(info->usages); createInfo.arrayLayers = info->depthOrArraySize; createInfo.extent.depth = 1; @@ -3404,7 +3574,7 @@ PalResult PAL_CALL bindVkImageMemory( VkDeviceMemory mem = (VkDeviceMemory)memory; s_Vk.bindImageMemory( vkImage->device->handle, - vkImage->handle, + vkImage->handle, mem, offset); } @@ -3460,7 +3630,7 @@ PalResult PAL_CALL createVkImageView( aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT; } - createInfo.subresourceRange .aspectMask = aspectFlags; + createInfo.subresourceRange.aspectMask = aspectFlags; result = s_Vk.createImageView( vkDevice->handle, &createInfo, @@ -4939,8 +5109,8 @@ PalResult PAL_CALL buildVkAccelerationStructure( VkAccelerationStructureGeometryKHR* geometries = nullptr; VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; - AccelerationStructure* vkAs = (AccelerationStructure*)info->dst; - Buffer* vkScratchBuffer = (Buffer*)info->scratchBuffer; + AccelerationStructure* as = (AccelerationStructure*)info->dst; + Buffer* scratchBuffer = (Buffer*)info->scratchBuffer; geometries = palAllocate( s_Vk.allocator, @@ -5040,11 +5210,11 @@ PalResult PAL_CALL buildVkAccelerationStructure( buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; buildInfo.geometryCount = info->geometryCount; - buildInfo.dstAccelerationStructure = vkAs->handle; + buildInfo.dstAccelerationStructure = as->handle; VkDeviceOrHostAddressKHR scratchData = {0}; scratchData.deviceAddress = - vkScratchBuffer->address + info->scratchBufferOffset; + scratchBuffer->address + info->scratchBufferOffset; buildInfo.scratchData = scratchData; buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; @@ -5118,6 +5288,32 @@ PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer) return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL copyVkBuffer( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + Uint64 dstOffset, + Uint64 srcOffset, + Uint32 size) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* dstbuffer = (Buffer*)dst; + Buffer* srcBuffer = (Buffer*)src; + + VkBufferCopy copyRegion = {0}; + copyRegion.size = size; + copyRegion.dstOffset = dstOffset; + copyRegion.srcOffset = srcOffset; + s_Vk.cmdCopyBuffer( + vkCmdBuffer->handle, + srcBuffer->handle, + dstbuffer->handle, + 1, + ©Region); + + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalSubmitInfo* info) @@ -5387,6 +5583,180 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( return PAL_RESULT_SUCCESS; } +// ================================================== +// Buffer +// ================================================== + +PalResult PAL_CALL createVkBuffer( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer) +{ + VkResult result; + Buffer* buffer = nullptr; + Device* vkDevice = (Device*)device; + if (info->usages & PAL_BUFFER_USAGE_RAY_TRACING) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + // buffer device address feature is supported if ray tracing is + + } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + if (!(vkDevice->features & + PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + + buffer = palAllocate(s_Vk.allocator, sizeof(Buffer), 0); + if (!buffer) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkBufferCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.size = info->size; + createInfo.usage = palBufferUsageToVk(info->usages); + + result = s_Vk.createBuffer( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &buffer->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, buffer); + return vkResultToPal(result); + } + + // get the address if the address usage is set + buffer->address = 0; + if (createInfo.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) { + VkBufferDeviceAddressInfoKHR bufferInfo = {0}; + bufferInfo.buffer = buffer->handle; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; + buffer->address = + vkDevice->getBufferrAddress(vkDevice->handle, &bufferInfo); + } + + buffer->device = vkDevice; + *outBuffer = (PalBuffer*)buffer; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkBuffer(PalBuffer* buffer) +{ + Buffer* vkBuffer = (Buffer*)buffer; + s_Vk.destroyBuffer( + vkBuffer->device->handle, + vkBuffer->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, buffer); +} + +PalResult PAL_CALL getVkBufferMemoryRequirements( + PalBuffer* buffer, + PalMemoryRequirements* requirements) +{ + Buffer* vkBuffer = (Buffer*)buffer; + Device* device = vkBuffer->device; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)device->phyDevice; + VkPhysicalDeviceMemoryProperties memProps = {0}; + s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); + + VkMemoryRequirements memReq = {0}; + s_Vk.getBufferMemoryRequirements( + device->handle, + vkBuffer->handle, + &memReq); + + requirements->alignment = (Uint64)memReq.alignment; + requirements->size = (Uint64)memReq.size; + + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = false; + + for (int i = 0; i < memProps.memoryTypeCount; i++) { + if (!(memReq.memoryTypeBits & (1 << i))) { + // memory type not supported + continue; + } + + VkMemoryPropertyFlags prop = memProps.memoryTypes[i].propertyFlags; + if (prop & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; + } + + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; + } + + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; + } + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL bindVkBufferMemory( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset) +{ + VkResult result; + VkDeviceMemory mem = (VkDeviceMemory)memory; + Buffer* vkBuffer = (Buffer*)buffer; + result = s_Vk.bindBufferMemory( + vkBuffer->device->handle, + vkBuffer->handle, + mem, + offset); + + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL mapVkBuffer( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr) +{ + VkResult result; + VkDeviceMemory mem = (VkDeviceMemory)memory; + Buffer* vkBuffer = (Buffer*)buffer; + + result = s_Vk.mapMemory( + vkBuffer->device->handle, + mem, + offset, + size, + 0, + outPtr); + + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL unmapVkBuffer( + PalBuffer* buffer, + PalMemory* memory) +{ + VkDeviceMemory mem = (VkDeviceMemory)memory; + Buffer* vkBuffer = (Buffer*)buffer; + s_Vk.unmapMemory(vkBuffer->device->handle, mem); +} + // ================================================== // Pipeline // ================================================== @@ -5401,6 +5771,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( void PAL_CALL destroyVkPipeline(PalPipeline* pipeline) { + } diff --git a/tests/graphics_test.c b/tests/graphics_test.c index eeae7380..b5531b4a 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -304,6 +304,10 @@ bool graphicsTest() palLog(nullptr, " Mesh shader indirect count"); } + if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { + palLog(nullptr, " Buffer device address"); + } + palLog(nullptr, ""); } diff --git a/tests/tests_main.c b/tests/tests_main.c index 17c21405..b8d7f6ac 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,7 +55,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); + registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From e1694c4143f48f6ac4d968f48e7635bee5631c96 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 29 Dec 2025 20:48:13 +0000 Subject: [PATCH 066/372] start graphics pipeline' --- include/pal/pal_graphics.h | 38 ++- src/graphics/pal_graphics.c | 8 - src/graphics/pal_vulkan.c | 525 +++++++++++++++++++++++++++++++++++- 3 files changed, 534 insertions(+), 37 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 6e274488..1503f067 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -295,16 +295,16 @@ typedef enum { } PalSwapchainFormat; typedef enum { - PAL_SHADER_TYPE_UNDEFINED, - PAL_SHADER_TYPE_VERTEX, - PAL_SHADER_TYPE_FRAGMENT, - PAL_SHADER_TYPE_COMPUTE, - PAL_SHADER_TYPE_GEOMETRY, - PAL_SHADER_TYPE_MESH, - PAL_SHADER_TYPE_TASK, - PAL_SHADER_TYPE_TESSELLATION_CONTROL, - PAL_SHADER_TYPE_TESSELLATION_EVALUATION -} PalShaderType; + PAL_SHADER_STAGE_UNDEFINED, + PAL_SHADER_STAGE_VERTEX, + PAL_SHADER_STAGE_FRAGMENT, + PAL_SHADER_STAGE_COMPUTE, + PAL_SHADER_STAGE_GEOMETRY, + PAL_SHADER_STAGE_MESH, + PAL_SHADER_STAGE_TASK, + PAL_SHADER_STAGE_TESSELLATION_CONTROL, + PAL_SHADER_STAGE_TESSELLATION_EVALUATION +} PalShaderStage; typedef enum { PAL_ATTACHMENT_TYPE_COLOR, @@ -404,10 +404,10 @@ typedef enum { PAL_COMPARE_OP_NEVER, PAL_COMPARE_OP_LESS, PAL_COMPARE_OP_EQUAL, - PAL_COMPARE_OP_LESS_EQUAL, + PAL_COMPARE_OP_LESS_OR_EQUAL, PAL_COMPARE_OP_GREATER, PAL_COMPARE_OP_NOT_EQUAL, - PAL_COMPARE_OP_GREATER_EQUAL, + PAL_COMPARE_OP_GREATER_OR_EQUAL, PAL_COMPARE_OP_ALWAYS } PalCompareOp; @@ -693,7 +693,7 @@ typedef struct { bool enableSampleShading; bool enableAlphaToCoverage; PalSampleCount sampleCount; - Uint32 sampleMask; + Uint64 sampleMask; float minSampleShading; } PalMultisampleState; @@ -811,7 +811,7 @@ typedef struct { } PalSwapchainCreateInfo; typedef struct { - PalShaderType type; + PalShaderStage type; const void* bytecode; Uint64 bytecodeSize; } PalShaderCreateInfo; @@ -847,13 +847,9 @@ typedef struct { PalPrimitiveTopology topology; Uint32 vertexLayoutCount; Uint32 blendAttachmentCount; - PalShader* vertexShader; - PalShader* fragmentShader; - PalShader* geometryShader; - PalShader* meshShader; - PalShader* taskShader; - PalShader* tessellationEvaluationShader; - PalShader* tessellationControlShader; + Uint32 shaderCount; + PalRenderPass* renderPass; + const PalShader** shaders; PalVertexLayout* vertexLayouts; PalBlendAttachment* blendAttachments; PalRasterizerState rasterizerState; diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 3bf0979b..afb4a688 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -1963,14 +1963,6 @@ PalResult PAL_CALL palCreateGraphicsPipeline( return PAL_RESULT_NULL_POINTER; } - if (!info->fragmentShader) { - return PAL_RESULT_NULL_POINTER; - } - - if (!info->meshShader && !info->vertexShader) { - return PAL_RESULT_NULL_POINTER; - } - PalResult result; PalPipeline* pipeline = nullptr; result = device->backend->createGraphicsPipeline( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 4e1c32a7..784ac251 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -65,6 +65,9 @@ typedef int (*wl_display_get_fd_fn)(struct wl_display*); #define VK_XLIB_PLATFORM 2 #define VK_WAYLAND_PLATFORM 3 #define MAX_ATTACHMENTS 32 +#define GRAPHICS_PIPELINE 125 +#define RAY_TRACING_PIPELINE 126 +#define COMPUTE_PIPELINE 127 typedef struct { const PalGraphicsBackend* backend; @@ -331,6 +334,14 @@ typedef struct { VkAccelerationStructureKHR handle; } AccelerationStructure; +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 type; + Device* device; + VkPipeline handle; +} Pipeline; + static Vulkan s_Vk = {0}; // ================================================== @@ -1247,6 +1258,192 @@ static VkBufferUsageFlags palBufferUsageToVk(PalBufferUsages usages) return flags; } +static Uint32 getVertexTypeSize(PalVertexType type) +{ + // count x sizeof type returned as size + switch (type) { + case PAL_VERTEX_TYPE_INT8_2: + case PAL_VERTEX_TYPE_UINT8_2: + case PAL_VERTEX_TYPE_INT8_2NORM: + case PAL_VERTEX_TYPE_UINT8_2NORM: { + return 2; + } + + case PAL_VERTEX_TYPE_INT32: + case PAL_VERTEX_TYPE_UINT32: + case PAL_VERTEX_TYPE_INT8_4: + case PAL_VERTEX_TYPE_INT8_4NORM: + case PAL_VERTEX_TYPE_UINT8_4: + case PAL_VERTEX_TYPE_UINT8_4NORM: + case PAL_VERTEX_TYPE_INT16_2NORM: + case PAL_VERTEX_TYPE_INT16_2: + case PAL_VERTEX_TYPE_UINT16_2: + case PAL_VERTEX_TYPE_UINT16_2NORM: + case PAL_VERTEX_TYPE_FLOAT: + case PAL_VERTEX_TYPE_HALF_FLOAT16_2: { + return 4; + } + + case PAL_VERTEX_TYPE_INT32_2: + case PAL_VERTEX_TYPE_UINT32_2: + case PAL_VERTEX_TYPE_INT16_4: + case PAL_VERTEX_TYPE_UINT16_4: + case PAL_VERTEX_TYPE_UINT16_4NORM: + case PAL_VERTEX_TYPE_INT16_4NORM: + case PAL_VERTEX_TYPE_FLOAT2: + case PAL_VERTEX_TYPE_HALF_FLOAT16_4: { + return 8; + } + + case PAL_VERTEX_TYPE_INT32_3: + case PAL_VERTEX_TYPE_UINT32_3: + case PAL_VERTEX_TYPE_FLOAT3: { + return 12; + } + + case PAL_VERTEX_TYPE_INT32_4: + case PAL_VERTEX_TYPE_UINT32_4: + case PAL_VERTEX_TYPE_FLOAT4: { + return 16; + } + } + + return 0; +} + +static VkStencilOp stencilOpToVk(PalStencilOp op) +{ + switch (op) { + case PAL_STENCIL_OP_KEEP: + return VK_STENCIL_OP_KEEP; + + case PAL_STENCIL_OP_ZERO: + return VK_STENCIL_OP_ZERO; + + case PAL_STENCIL_OP_REPLACE: + return VK_STENCIL_OP_REPLACE; + + case PAL_STENCIL_OP_INCREMENT_AND_CLAMP: + return VK_STENCIL_OP_INCREMENT_AND_CLAMP; + + case PAL_STENCIL_OP_DECREMENT_AND_CLAMP: + return VK_STENCIL_OP_DECREMENT_AND_CLAMP; + + case PAL_STENCIL_OP_INVERT: + return VK_STENCIL_OP_INVERT; + + case PAL_STENCIL_OP_INCREMENT_AND_WRAP: + return VK_STENCIL_OP_INCREMENT_AND_WRAP; + + case PAL_STENCIL_OP_DECREMENT_AND_WRAP: + return VK_STENCIL_OP_DECREMENT_AND_WRAP; + } + + return VK_STENCIL_OP_KEEP; +} + +static VkCompareOp compareOpToVk(PalCompareOp op) +{ + switch (op) { + case PAL_COMPARE_OP_NEVER: + return VK_COMPARE_OP_NEVER; + + case PAL_COMPARE_OP_LESS: + return VK_COMPARE_OP_LESS; + + case PAL_COMPARE_OP_EQUAL: + return VK_COMPARE_OP_EQUAL; + + case PAL_COMPARE_OP_LESS_OR_EQUAL: + return VK_COMPARE_OP_LESS_OR_EQUAL; + + case PAL_COMPARE_OP_GREATER: + return VK_COMPARE_OP_GREATER; + + case PAL_COMPARE_OP_NOT_EQUAL: + return VK_COMPARE_OP_NOT_EQUAL; + + case PAL_COMPARE_OP_GREATER_OR_EQUAL: + return VK_COMPARE_OP_GREATER_OR_EQUAL; + + case PAL_COMPARE_OP_ALWAYS: + return VK_COMPARE_OP_ALWAYS; + } + + return VK_COMPARE_OP_NEVER; +} + +static VkBlendOp blendOpToVk(PalBlendOp op) +{ + switch (op) { + case PAL_BLEND_OP_ADD: + return VK_BLEND_OP_ADD; + + case PAL_BLEND_OP_SUBTRACT: + return VK_BLEND_OP_SUBTRACT; + + case PAL_BLEND_OP_REVERSE_SUBTRACT: + return VK_BLEND_OP_REVERSE_SUBTRACT; + + case PAL_BLEND_OP_MIN: + return VK_BLEND_OP_MIN; + + case PAL_BLEND_OP_MAX: + return VK_BLEND_OP_MAX; + } + + return VK_BLEND_OP_ADD; +} + +static VkBlendFactor blendFactorToVk(PalBlendFactor op) +{ + switch (op) { + case PAL_BLEND_FACTOR_ZERO: + return VK_BLEND_FACTOR_ZERO; + + case PAL_BLEND_FACTOR_ONE: + return VK_BLEND_FACTOR_ONE; + + case PAL_BLEND_FACTOR_SRC_COLOR: + return VK_BLEND_FACTOR_SRC_COLOR; + + case PAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: + return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + + case PAL_BLEND_FACTOR_DST_COLOR: + return VK_BLEND_FACTOR_DST_COLOR; + + case PAL_BLEND_FACTOR_ONE_MINUX_DST_COLOR: + return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; + + case PAL_BLEND_FACTOR_SRC_ALPHA: + return VK_BLEND_FACTOR_SRC_ALPHA; + + case PAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: + return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + case PAL_BLEND_FACTOR_DST_ALPHA: + return VK_BLEND_FACTOR_DST_ALPHA; + + case PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: + return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; + + case PAL_BLEND_FACTOR_CONSTANT_COLOR: + return VK_BLEND_FACTOR_CONSTANT_COLOR; + + case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR: + return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; + + case PAL_BLEND_FACTOR_CONSTANT_ALPHA: + return VK_BLEND_FACTOR_CONSTANT_ALPHA; + + case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: + return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; + } + + return VK_BLEND_FACTOR_ZERO; +} + static void* vkAlloc( void* pUserData, size_t size, @@ -4086,37 +4283,37 @@ PalResult PAL_CALL createVkShader( VkShaderStageFlags stage = 0; Device* vkDevice = (Device*)device; - if (info->type == PAL_SHADER_TYPE_VERTEX) { + if (info->type == PAL_SHADER_STAGE_VERTEX) { stage = VK_SHADER_STAGE_VERTEX_BIT; - } else if (info->type == PAL_SHADER_TYPE_FRAGMENT) { + } else if (info->type == PAL_SHADER_STAGE_FRAGMENT) { stage = VK_SHADER_STAGE_FRAGMENT_BIT; - } else if (info->type == PAL_SHADER_TYPE_COMPUTE) { + } else if (info->type == PAL_SHADER_STAGE_COMPUTE) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_COMPUTE_BIT; - } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_CONTROL) { + } else if (info->type == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - } else if (info->type == PAL_SHADER_TYPE_TESSELLATION_EVALUATION) { + } else if (info->type == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - } else if (info->type == PAL_SHADER_TYPE_MESH) { + } else if (info->type == PAL_SHADER_STAGE_MESH) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_MESH_BIT_EXT; - } else if (info->type == PAL_SHADER_TYPE_TASK) { + } else if (info->type == PAL_SHADER_STAGE_TASK) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5766,13 +5963,325 @@ PalResult PAL_CALL createVkGraphicsPipeline( const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline) { + VkResult result; + Pipeline* pipeline = nullptr; + Device* vkDevice = (Device*)device; + RenderPass* renderPass = (RenderPass*)info->renderPass; + VkPipelineShaderStageCreateInfo shaderStages[7]; // PAL supports 7 types + VkDynamicState dynamicStates[16]; + VkVertexInputBindingDescription* bindingDescs = nullptr; + VkVertexInputAttributeDescription* attribDescs = nullptr; + VkPipelineColorBlendAttachmentState* blendattachments = nullptr; + + VkPipelineVertexInputStateCreateInfo VI = {0}; + VI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + + VkPipelineInputAssemblyStateCreateInfo IA = {0}; + IA.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + + VkPipelineDynamicStateCreateInfo DS = {0}; + DS.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + + VkPipelineRasterizationStateCreateInfo RS = {0}; + RS.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + + VkPipelineMultisampleStateCreateInfo MS = {0}; + MS.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + + VkPipelineDepthStencilStateCreateInfo SS = {0}; + SS.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + + VkPipelineColorBlendStateCreateInfo CBS = {0}; + CBS.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + + VkGraphicsPipelineCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + + pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); + if (!pipeline) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // shaders + for (int i = 0; i < info->shaderCount; i++) { + Shader* tmp = (Shader*)info->shaders[i]; + shaderStages[i] = tmp->info; + } + + // Vertex input state + // get the max size of vertex attributes in all layouts + Uint32 vertexCount = 0; + for (int i = 0; i < info->vertexLayoutCount; i++) { + PalVertexLayout* layout = &info->vertexLayouts[i]; + vertexCount += layout->vertexCount; + } + + bindingDescs = palAllocate( + s_Vk.allocator, + sizeof(VkVertexInputBindingDescription) * info->vertexLayoutCount, + 0); + + attribDescs = palAllocate( + s_Vk.allocator, + sizeof(VkVertexInputAttributeDescription) * vertexCount, + 0); + + if (!bindingDescs || !attribDescs) { + palFree(s_Vk.allocator, pipeline); + return PAL_RESULT_OUT_OF_MEMORY; + } + + for (int i = 0; i < info->vertexLayoutCount; i++) { + PalVertexLayout* layout = &info->vertexLayouts[i]; + VkVertexInputBindingDescription* bindingDesc = &bindingDescs[i]; + bindingDesc->binding = layout->binding; + if (layout->type == PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE) { + bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; + } else { + bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + } + + // find the stride and offset of the layout + bindingDesc->stride = 0; + Uint32 offset = 0; + for (int j = 0; j < layout->vertexCount; j++) { + PalVertexAttribute* vertexAttrib = &layout->vertices[j]; + VkVertexInputAttributeDescription* attrib = &attribDescs[j]; + + attrib->format = vertexTypeToVkFormat(vertexAttrib->type); + attrib->binding = bindingDesc->binding; + attrib->location = attrib->location; + + // build offsets and stride + Uint32 size = getVertexTypeSize(vertexAttrib->type); + attrib->offset = offset; + offset += size; + bindingDesc->stride += size; + } + } + + VI.pVertexAttributeDescriptions = attribDescs; + VI.vertexAttributeDescriptionCount = vertexCount; + VI.pVertexBindingDescriptions = bindingDescs; + VI.vertexBindingDescriptionCount = info->vertexLayoutCount; + createInfo.pVertexInputState = &VI; + + // Input assembly + VkPrimitiveTopology topology; + switch (info->topology) { + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { + topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { + topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_LIST: { + topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP: { + topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_POINT_LIST: { + topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + break; + } + } + + // Dynamic states + Uint32 dynCount = 0; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_VIEWPORT; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_SCISSOR; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_LINE_WIDTH; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_BIAS; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_CULL_MODE_EXT; + } + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_FRONT_FACE_EXT; + } + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT; + } + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT; + } + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT; + } + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_STENCIL_OP_EXT; + } + + DS.dynamicStateCount = dynCount; + DS.pDynamicStates = dynamicStates; + createInfo.pDynamicState = &DS; + + // Rasterizer state + if (info->rasterizerState.cullMode == PAL_CULL_MODE_NONE) { + RS.cullMode = VK_CULL_MODE_NONE; + } else if (info->rasterizerState.cullMode == PAL_CULL_MODE_BACK) { + RS.cullMode = VK_CULL_MODE_BACK_BIT; + } else if (info->rasterizerState.cullMode == PAL_CULL_MODE_FRONT) { + RS.cullMode = VK_CULL_MODE_FRONT_BIT; + } + + if (info->rasterizerState.polygonMode == PAL_POLYGON_MODE_FILL) { + RS.cullMode = VK_POLYGON_MODE_FILL; + } else { + RS.cullMode = VK_POLYGON_MODE_LINE; + } + + if (info->rasterizerState.frontFace == PAL_FRONT_FACE_CLOCKWISE) { + RS.cullMode = VK_FRONT_FACE_CLOCKWISE; + } else { + RS.cullMode = VK_FRONT_FACE_COUNTER_CLOCKWISE; + } + + RS.depthBiasEnable = info->rasterizerState.enableDepthBias; + RS.depthClampEnable = info->rasterizerState.enableDepthClamp; + + // Multisample state + MS.alphaToCoverageEnable = info->multisampleState.enableAlphaToCoverage; + MS.minSampleShading = info->multisampleState.minSampleShading; + MS.sampleShadingEnable = info->multisampleState.enableSampleShading; + MS.rasterizationSamples = samplesToVk(info->multisampleState.sampleCount); + + VkSampleMask sampleMasks[2]; + Uint32 mask1 = 0; + Uint32 mask2 = 0; + palUnpackUint32(info->multisampleState.sampleMask, &mask1, &mask2); + sampleMasks[0] = mask1; + sampleMasks[1] = mask2; + MS.pSampleMask = sampleMasks; + + // Depth stencil state + const PalStencilOpState* front = nullptr; + const PalStencilOpState* back = nullptr; + back = &info->depthStencilState.backStencilOpState; + front = &info->depthStencilState.frontStencilOpState; + + SS.back.compareOp = compareOpToVk(back->compareOp); + SS.back.depthFailOp = stencilOpToVk(back->depthFailOp); + SS.back.failOp = stencilOpToVk(back->failOp); + SS.back.passOp = stencilOpToVk(back->passOp); + + SS.front.compareOp = compareOpToVk(front->compareOp); + SS.front.depthFailOp = stencilOpToVk(front->depthFailOp); + SS.front.failOp = stencilOpToVk(front->failOp); + SS.front.passOp = stencilOpToVk(front->passOp); + + SS.depthCompareOp = compareOpToVk(info->depthStencilState.compareOp); + SS.depthTestEnable = info->depthStencilState.enableDepthTest; + SS.depthWriteEnable = info->depthStencilState.enableDepthWrite; + SS.stencilTestEnable = info->depthStencilState.enableStencilTest; + + // Color blend state + CBS.attachmentCount = info->blendAttachmentCount; + if (info->blendAttachmentCount) { + blendattachments = palAllocate( + s_Vk.allocator, + sizeof(VkPipelineColorBlendAttachmentState) * CBS.attachmentCount, + 0); + + if (!blendattachments) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, bindingDescs); + palFree(s_Vk.allocator, attribDescs); + return PAL_RESULT_OUT_OF_MEMORY; + } + + for (int i = 0; i < CBS.attachmentCount; i++) { + VkPipelineColorBlendAttachmentState* tmp = &blendattachments[i]; + PalBlendAttachment* desc = &info->blendAttachments[i]; + + tmp->blendEnable = desc->enableBlend; + tmp->alphaBlendOp = blendOpToVk(desc->alphaBlendOp); + tmp->colorBlendOp = blendOpToVk(desc->colorBlendOp); + + tmp->srcAlphaBlendFactor = + blendFactorToVk(desc->srcAlphaBlendFactor); + tmp->srcColorBlendFactor = + blendFactorToVk(desc->srcColorBlendFactor); + + tmp->dstAlphaBlendFactor = + blendFactorToVk(desc->dstAlphaBlendFactor); + tmp->dstColorBlendFactor = + blendFactorToVk(desc->dstColorBlendFactor); + + // blend color write mask + tmp->colorWriteMask = 0; + if (desc->colorWriteMask & PAL_COLOR_MASK_RED) { + tmp->colorWriteMask |= VK_COLOR_COMPONENT_R_BIT; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_GREEN) { + tmp->colorWriteMask |= VK_COLOR_COMPONENT_G_BIT; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_BLUE) { + tmp->colorWriteMask |= VK_COLOR_COMPONENT_B_BIT; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_ALPHA) { + tmp->colorWriteMask |= VK_COLOR_COMPONENT_A_BIT; + } + } + } + + // TODO: pipeline layout + createInfo.layout = nullptr; + createInfo.stageCount = info->shaderCount; + createInfo.pStages = shaderStages; + createInfo.pVertexInputState = &VI; + createInfo.pInputAssemblyState = &IA; + createInfo.pDepthStencilState = &SS; + createInfo.pDynamicState = &DS; + createInfo.pRasterizationState = &RS; + createInfo.pMultisampleState = &MS; + createInfo.pColorBlendState = &CBS; + createInfo.renderPass = renderPass->handle; + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + return vkResultToPal(result); + } + + palFree(s_Vk.allocator, bindingDescs); + palFree(s_Vk.allocator, attribDescs); + palFree(s_Vk.allocator, blendattachments); + + pipeline->device = vkDevice; + pipeline->type = GRAPHICS_PIPELINE; + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyVkPipeline(PalPipeline* pipeline) { - + Pipeline* vkPipeline = (Pipeline*)pipeline; + s_Vk.destroyPipeline( + vkPipeline->device->handle, + vkPipeline->handle, + &s_Vk.vkAllocator); + palFree(s_Vk.allocator, pipeline); } #endif // PAL_HAS_VULKAN \ No newline at end of file From 372bd34e28edb94e4ec7746e8a7002c69e611b64 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 30 Dec 2025 15:02:12 +0000 Subject: [PATCH 067/372] add render pass view API --- include/pal/pal_graphics.h | 71 +++++-- src/graphics/pal_graphics.c | 92 +++++++-- src/graphics/pal_vulkan.c | 378 +++++++++++++++++++----------------- tests/clear_color_test.c | 207 +++++++++++++------- 4 files changed, 463 insertions(+), 285 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 1503f067..301b91ac 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -49,14 +49,15 @@ typedef struct PalImage PalImage; typedef struct PalImageView PalImageView; typedef struct PalShader PalShader; typedef struct PalRenderPass PalRenderPass; -typedef struct PalBuffer PalBuffer; +typedef struct PalRenderPassView PalRenderPassView; +typedef struct PalBuffer PalBuffer; typedef struct PalFence PalFence; typedef struct PalSemaphore PalSemaphore; typedef struct PalCommandPool PalCommandPool; typedef struct PalCommandBuffer PalCommandBuffer; -typedef struct PalPipeline PalPipeline; +typedef struct PalPipeline PalPipeline; typedef struct PalAccelerationStructure PalAccelerationStructure; typedef enum { @@ -309,8 +310,9 @@ typedef enum { typedef enum { PAL_ATTACHMENT_TYPE_COLOR, PAL_ATTACHMENT_TYPE_DEPTH, - PAL_ATTACHMENT_TYPE_STENCIL, - PAL_ATTACHMENT_TYPE_DEPTH_STENCIL, + PAL_ATTACHMENT_TYPE_COLOR_RESOLVE, + PAL_ATTACHMENT_TYPE_DEPTH_RESOLVE, + PAL_ATTACHMENT_TYPE_PRESENT, PAL_ATTACHMENT_TYPE_FRAGMENT_SHADING_RATE } PalAttachmentType; @@ -623,6 +625,8 @@ typedef struct { typedef struct { PalAttachmentType type; + PalFormat format; + PalSampleCount sampleCount; PalLoadOp loadOp; PalStoreOp storeOp; PalLoadOp stencilLoadOp; @@ -631,8 +635,6 @@ typedef struct { PalResolveMode stencilResolveMode; Uint32 texelWidth; Uint32 texelHeight; - PalImageView* target; - PalImageView* resolveTarget; } PalAttachmentDesc; typedef struct { @@ -669,6 +671,18 @@ typedef struct { PalSemaphore* waitSemaphore; } PalPresentInfo; +typedef struct { + PalRenderPass* renderPass; + PalRenderPassView* view; +} PalBeginInfo; + +typedef struct { + Int32 clearValueCount; + PalRenderPass* renderPass; + PalRenderPassView* view; + PalClearValue* clearValues; +} PalRenderPassBeginInfo; + typedef struct { PalVertexType type; Uint32 location; @@ -811,19 +825,24 @@ typedef struct { } PalSwapchainCreateInfo; typedef struct { - PalShaderStage type; + PalShaderStage stage; const void* bytecode; Uint64 bytecodeSize; } PalShaderCreateInfo; typedef struct { - Uint32 width; - Uint32 height; - Uint32 multiViewCount;; + Uint32 multiViewCount; Uint32 attachmentCount; PalAttachmentDesc* attachments; } PalRenderPassCreateInfo; +typedef struct { + Uint32 imageViewCount; + Uint32 width; + Uint32 height; + PalImageView** imageViews; +} PalRenderPassViewCreateInfo; + typedef struct { bool transient; bool resettable; @@ -984,6 +1003,8 @@ typedef struct { PalSwapchain* swapchain, PalNextImageInfo* info); + PalFormat PAL_CALL (*getSwapchainFormat)(PalSwapchain* swapchain); + PalResult PAL_CALL (*presentSwapchain)( PalSwapchain* swapchain, PalPresentInfo* info); @@ -1002,6 +1023,14 @@ typedef struct { void PAL_CALL (*destroyRenderPass)(PalRenderPass* renderPass); + PalResult PAL_CALL (*createRenderPassView)( + PalDevice* device, + PalRenderPass* renderPass, + const PalRenderPassViewCreateInfo* info, + PalRenderPassView** outRenderPassView); + + void PAL_CALL (*destroyRenderPassView)(PalRenderPassView* renderPassView); + PalResult PAL_CALL (*createFence)( PalDevice* device, PalFence** outFence); @@ -1054,7 +1083,7 @@ typedef struct { PalResult PAL_CALL (*beginCommandBuffer)( PalCommandBuffer* cmdBuffer, - PalRenderPass* renderPass); + PalBeginInfo* info); PalResult PAL_CALL (*endCommandBuffer)(PalCommandBuffer* cmdBuffer); @@ -1094,9 +1123,7 @@ typedef struct { PalResult PAL_CALL (*beginRenderPass)( PalCommandBuffer* cmdBuffer, - PalRenderPass* renderPass, - Int32 clearValuecount, - PalClearValue* clearValues); + PalRenderPassBeginInfo* info); PalResult PAL_CALL (*endRenderPass)(PalCommandBuffer* cmdBuffer); @@ -1294,6 +1321,8 @@ PAL_API PalImage* PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, PalNextImageInfo* info); +PAL_API PalFormat PAL_CALL palGetSwapchainFormat(PalSwapchain* swapchain); + PAL_API PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, PalPresentInfo* info); @@ -1312,6 +1341,14 @@ PAL_API PalResult PAL_CALL palCreateRenderPass( PAL_API void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass); +PAL_API PalResult PAL_CALL palCreateRenderPassView( + PalDevice* device, + PalRenderPass* renderPass, + const PalRenderPassViewCreateInfo* info, + PalRenderPassView** outRenderPassView); + +PAL_API void PAL_CALL palDestroyRenderPassView(PalRenderPassView* view); + PAL_API PalResult PAL_CALL palCreateCommandPool( PalDevice* device, const PalCommandPoolCreateInfo* info, @@ -1364,7 +1401,7 @@ PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); PAL_API PalResult PAL_CALL palBeginCommandBuffer( PalCommandBuffer* cmdBuffer, - PalRenderPass* renderPass); + PalBeginInfo* info); PAL_API PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -1404,9 +1441,7 @@ PAL_API PalResult PAL_CALL palBuildAccelerationStructure( PAL_API PalResult PAL_CALL palBeginRenderPass( PalCommandBuffer* cmdBuffer, - PalRenderPass* renderPass, - Int32 clearValueCount, - PalClearValue* clearValues); + PalRenderPassBeginInfo* info); PAL_API PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index afb4a688..6469ed4e 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -50,7 +50,7 @@ PAL_HANDLE(PalCommandPool) PAL_HANDLE(PalCommandBuffer) PAL_HANDLE(PalPipeline) PAL_HANDLE(PalAccelerationStructure) -PAL_HANDLE(PalBufferView) +PAL_HANDLE(PalRenderPassView) typedef struct { Int32 count; @@ -209,6 +209,8 @@ PalImage* PAL_CALL getVkNextSwapchainImage( PalSwapchain* swapchain, PalNextImageInfo* info); +PalFormat PAL_CALL getVkSwapchainFormat(PalSwapchain* swapchain); + PalResult PAL_CALL presentVkSwapchain( PalSwapchain* swapchain, PalPresentInfo* info); @@ -227,6 +229,14 @@ PalResult PAL_CALL createVkRenderPass( void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass); +PalResult PAL_CALL createVkRenderPassView( + PalDevice* device, + PalRenderPass* renderPass, + const PalRenderPassViewCreateInfo* info, + PalRenderPassView** outRenderPassView); + +void PAL_CALL destroyVkRenderPassView(PalRenderPassView* view); + PalResult PAL_CALL createVkFence( PalDevice* device, PalFence** outFence); @@ -279,7 +289,7 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); PalResult PAL_CALL beginVkCommandBuffer( PalCommandBuffer* cmdBuffer, - PalRenderPass* renderPass); + PalBeginInfo* info); PalResult PAL_CALL endVkCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -319,9 +329,7 @@ PalResult PAL_CALL buildVkAccelerationStructure( PalResult PAL_CALL beginRenderPassVk( PalCommandBuffer* cmdBuffer, - PalRenderPass* renderPass, - Int32 clearValueCount, - PalClearValue* clearValues); + PalRenderPassBeginInfo* info); PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer); @@ -416,11 +424,14 @@ static PalGraphicsBackend s_VkBackend = { .destroySwapchain = destroyVkSwapchain, .getSwapchainImage = getVkSwapchainImage, .getNextSwapchainImage = getVkNextSwapchainImage, + .getSwapchainFormat = getVkSwapchainFormat, .presentSwapchain = presentVkSwapchain, .createShader = createVkShader, .destroyShader = destroyVkShader, .createRenderPass = createVkRenderPass, .destroyRenderPass = destroyVkRenderPass, + .createRenderPassView = createVkRenderPassView, + .destroyRenderPassView = destroyVkRenderPassView, .createFence = createVkFence, .destroyFence = destroyVkFence, .waitFenceTimeout = waitVkFence, @@ -525,11 +536,14 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroySwapchain || !backend->getSwapchainImage || !backend->getNextSwapchainImage || + !backend->getSwapchainFormat || !backend->presentSwapchain || !backend->createShader || !backend->destroyShader || !backend->createRenderPass || !backend->destroyRenderPass || + !backend->createRenderPassView || + !backend->destroyRenderPassView || !backend->createFence || !backend->destroyFence || !backend->waitFenceTimeout || @@ -1193,6 +1207,14 @@ PalImage* PAL_CALL palGetNextSwapchainImage( info); } +PalFormat PAL_CALL palGetSwapchainFormat(PalSwapchain* swapchain) +{ + if (!s_Graphics.initialized || !swapchain) { + return PAL_FORMAT_UNDEFINED; + } + return swapchain->backend->getSwapchainFormat(swapchain); +} + PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, PalPresentInfo* info) @@ -1294,6 +1316,48 @@ void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) } } +PalResult PAL_CALL palCreateRenderPassView( + PalDevice* device, + PalRenderPass* renderPass, + const PalRenderPassViewCreateInfo* info, + PalRenderPassView** outRenderPassView) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !renderPass || !info || !outRenderPassView) { + return PAL_RESULT_NULL_POINTER; + } + + if (info->imageViewCount == 0 && info->imageViews) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + + PalRenderPassView* renderPassView = nullptr; + PalResult result; + result = device->backend->createRenderPassView( + device, + renderPass, + info, + &renderPassView); + + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + renderPassView->backend = device->backend; + *outRenderPassView = renderPassView; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyRenderPassView(PalRenderPassView* view) +{ + if (s_Graphics.initialized && view) { + view->backend->destroyRenderPassView(view); + } +} + // ================================================== // Fence // ================================================== @@ -1541,7 +1605,7 @@ void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL palBeginCommandBuffer( PalCommandBuffer* cmdBuffer, - PalRenderPass* renderPass) + PalBeginInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1551,7 +1615,7 @@ PalResult PAL_CALL palBeginCommandBuffer( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->beginCommandBuffer(cmdBuffer, renderPass); + return cmdBuffer->backend->beginCommandBuffer(cmdBuffer, info); } PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer) @@ -1691,27 +1755,19 @@ PalResult PAL_CALL palBuildAccelerationStructures( PalResult PAL_CALL palBeginRenderPass( PalCommandBuffer* cmdBuffer, - PalRenderPass* renderPass, - Int32 clearValueCount, - PalClearValue* clearValues) + PalRenderPassBeginInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !renderPass) { + if (!cmdBuffer || !info) { return PAL_RESULT_NULL_POINTER; } - if (clearValueCount == 0 && clearValues) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - return cmdBuffer->backend->beginRenderPass( cmdBuffer, - renderPass, - clearValueCount, - clearValues); + info); } PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 784ac251..475790d3 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -272,13 +272,19 @@ typedef struct { const PalGraphicsBackend* backend; Uint32 attachmentCount; - Uint32 width; - Uint32 height; Device* device; VkRenderPass handle; - VkFramebuffer framebuffer; } RenderPass; +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 width; + Uint32 height; + Device* device; + VkFramebuffer handle; +} RenderPassView; + typedef struct { const PalGraphicsBackend* backend; @@ -470,7 +476,7 @@ static VkImageUsageFlags palImageUsageToVk(PalImageUsages usages) return flags; } -static VkFormat palFormatToVk(PalFormat format) +static VkFormat palFormatToVk(PalFormat format) { switch (format) { case PAL_FORMAT_R8_UNORM: @@ -4228,6 +4234,12 @@ PalImage* PAL_CALL getVkNextSwapchainImage( return (PalImage*)image; } +PalFormat PAL_CALL getVkSwapchainFormat(PalSwapchain* swapchain) +{ + Swapchain* vkSwapchain = (Swapchain*)swapchain; + return vkSwapchain->images[0].info.format; +} + PalResult PAL_CALL presentVkSwapchain( PalSwapchain* swapchain, PalPresentInfo* info) @@ -4283,37 +4295,37 @@ PalResult PAL_CALL createVkShader( VkShaderStageFlags stage = 0; Device* vkDevice = (Device*)device; - if (info->type == PAL_SHADER_STAGE_VERTEX) { + if (info->stage == PAL_SHADER_STAGE_VERTEX) { stage = VK_SHADER_STAGE_VERTEX_BIT; - } else if (info->type == PAL_SHADER_STAGE_FRAGMENT) { + } else if (info->stage == PAL_SHADER_STAGE_FRAGMENT) { stage = VK_SHADER_STAGE_FRAGMENT_BIT; - } else if (info->type == PAL_SHADER_STAGE_COMPUTE) { + } else if (info->stage == PAL_SHADER_STAGE_COMPUTE) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_COMPUTE_BIT; - } else if (info->type == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { + } else if (info->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - } else if (info->type == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + } else if (info->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - } else if (info->type == PAL_SHADER_STAGE_MESH) { + } else if (info->stage == PAL_SHADER_STAGE_MESH) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_MESH_BIT_EXT; - } else if (info->type == PAL_SHADER_STAGE_TASK) { + } else if (info->stage == PAL_SHADER_STAGE_TASK) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -4384,8 +4396,6 @@ PalResult PAL_CALL createVkRenderPass( bool hasFsr; Uint32 colorRefCount = 0; Uint32 resolveRefCount = 0; - Uint32 layers = 0; - VkImageView views[MAX_ATTACHMENTS]; // multi view Uint32 viewMask = (1 << info->multiViewCount) - 1; @@ -4411,25 +4421,12 @@ PalResult PAL_CALL createVkRenderPass( rDesc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR; rDesc->flags = 0; rDesc->pNext = nullptr; - ImageView* vkImageView = (ImageView*)desc->target; - rDesc->format = palFormatToVk(vkImageView->image->info.format); + rDesc->format = palFormatToVk(desc->format); rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rDesc->samples = vkSamplesToSamples(vkImageView->image->info.sampleCount); + rDesc->samples = vkSamplesToSamples(desc->sampleCount); rDesc->flags = 0; - layers = vkImageView->image->info.depthOrArraySize; - VkAttachmentReference2KHR* resolveRef = &resolveRefs[resolveRefCount]; - if (desc->resolveTarget) { - // the layer count must be the same so to validate as well - // we use the highest from the attachments - ImageView* tmp = (ImageView*)desc->resolveTarget; - layers = tmp->image->info.depthOrArraySize; - resolveRef->attachment = i; - resolveRef->pNext = 0; - resolveRef->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; - } - // load op if (desc->loadOp == PAL_LOAD_OP_CLEAR) { rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; @@ -4449,77 +4446,73 @@ PalResult PAL_CALL createVkRenderPass( rDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; } - // add the image views from the attachments into a seperate array - views[i] = vkImageView->handle; - + VkAttachmentReference2KHR* ref = nullptr; + VkImageAspectFlags aspectMask = 0; + VkImageLayout layout = 0; if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { - VkAttachmentReference2KHR* ref = &colorRefs[colorRefCount]; - ref->attachment = i; - ref->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - ref->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - ref->pNext = 0; - ref->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; - - rDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - colorRefCount++; - if (vkImageView->image->belongsToSwapchain) { - rDesc->finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - } + ref = &colorRefs[colorRefCount++]; + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - if (resolveRef) { - resolveRef->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - resolveRef->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - resolveRefCount++; - } + } else if (desc->type == PAL_ATTACHMENT_TYPE_COLOR_RESOLVE) { + ref = &resolveRefs[resolveRefCount++]; + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - } else { - // fragment shading rate attachment - if (desc->type == PAL_ATTACHMENT_TYPE_FRAGMENT_SHADING_RATE) { - VkExtent2D size; - size.width = desc->texelWidth; - size.height = desc->texelHeight; - fsrAttachment.shadingRateAttachmentTexelSize = size; - - fsrRef.attachment = i; - rDesc->finalLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; - fsrRef.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; - fsrAttachment.pFragmentShadingRateAttachment = &fsrRef; - hasFsr = true; - - } else { - depthRef.attachment = i; - depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - depthRef.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - depthRef.pNext = 0; - depthRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; - - rDesc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - hasDepth = true; - // stencil is only used with depth attachment - if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH) { + ref = &depthRef; + layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + hasDepth = true; + // stencil is only used with depth attachment + if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } + } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { - rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } - } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { - rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - } + if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { + rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - if (resolveRef) { - resolveRef->layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - resolveRef->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - resolveRefCount++; - } + } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { + rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; } + + } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH_RESOLVE) { + ref = &resolveRefs[resolveRefCount++]; + layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + + } else if (desc->type == PAL_ATTACHMENT_TYPE_PRESENT) { + ref = &colorRefs[colorRefCount++]; + layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + } else { + // fragment shading rate attachment + VkExtent2D size; + size.width = desc->texelWidth; + size.height = desc->texelHeight; + fsrAttachment.shadingRateAttachmentTexelSize = size; + + ref = &fsrRef; + layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + aspectMask = 0; + fsrAttachment.pFragmentShadingRateAttachment = &fsrRef; + hasFsr = true; } + + ref->attachment = i; + ref->layout = layout; + ref->aspectMask = aspectMask; + ref->pNext = 0; + ref->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; + rDesc->finalLayout = layout; } // subpass @@ -4565,22 +4558,12 @@ PalResult PAL_CALL createVkRenderPass( PalAttachmentDesc* desc = &info->attachments[i]; VkAttachmentDescription* rDesc = &attachments[i]; - ImageView* vkImageView = (ImageView*)desc->target; - rDesc->format = palFormatToVk(vkImageView->image->info.format); + rDesc->flags = 0; + rDesc->format = palFormatToVk(desc->format); rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rDesc->samples = vkSamplesToSamples(vkImageView->image->info.sampleCount); + rDesc->samples = vkSamplesToSamples(desc->sampleCount); rDesc->flags = 0; - layers = vkImageView->image->info.depthOrArraySize; - VkAttachmentReference* resolveRef = &resolveRefs[resolveRefCount]; - if (desc->resolveTarget) { - // the layer count must be the same so to validate as well - // we use the highest from the attachments - ImageView* tmp = (ImageView*)desc->resolveTarget; - layers = tmp->image->info.depthOrArraySize; - resolveRef->attachment = i; - } - // load op if (desc->loadOp == PAL_LOAD_OP_CLEAR) { rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; @@ -4600,30 +4583,24 @@ PalResult PAL_CALL createVkRenderPass( rDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; } - // add the image views from the attachments into a seperate array - views[i] = vkImageView->handle; - + VkAttachmentReference* ref = nullptr; + VkImageAspectFlags aspectMask = 0; + VkImageLayout layout = 0; if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { - VkAttachmentReference* ref = &colorRefs[colorRefCount]; - ref->attachment = i; - ref->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - rDesc->finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - colorRefCount++; - if (vkImageView->image->belongsToSwapchain) { - rDesc->finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - } + ref = &colorRefs[colorRefCount++]; + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - if (resolveRef) { - resolveRef->layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - resolveRefCount++; - } + } else if (desc->type == PAL_ATTACHMENT_TYPE_COLOR_RESOLVE) { + ref = &resolveRefs[resolveRefCount++]; + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH) { + ref = &depthRef; + layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - } else { - depthRef.attachment = i; - depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - - rDesc->finalLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; hasDepth = true; // stencil is only used with depth attachment if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { @@ -4643,11 +4620,20 @@ PalResult PAL_CALL createVkRenderPass( rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; } - if (resolveRef) { - resolveRef->layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - resolveRefCount++; - } + } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH_RESOLVE) { + ref = &resolveRefs[resolveRefCount++]; + layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + + } else { + ref = &colorRefs[colorRefCount++]; + layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } + + ref->attachment = i; + ref->layout = layout; + rDesc->finalLayout = layout; } // subpass legacy @@ -4685,59 +4671,98 @@ PalResult PAL_CALL createVkRenderPass( palFree(s_Vk.allocator, renderPass); return vkResultToPal(result); } - // clamg-format on - // create framebuffer + + renderPass->device = vkDevice; + renderPass->attachmentCount = info->attachmentCount; + *outRenderPass = (PalRenderPass*)renderPass; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass) +{ + RenderPass* vkRenderPass = (RenderPass*)renderPass; + s_Vk.destroyRenderPass( + vkRenderPass->device->handle, + vkRenderPass->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, renderPass); +} + +PalResult PAL_CALL createVkRenderPassView( + PalDevice* device, + PalRenderPass* renderPass, + const PalRenderPassViewCreateInfo* info, + PalRenderPassView** outRenderPassView) +{ + VkResult result; + RenderPassView* view = nullptr; + Device* vkDevice = (Device*)device; + RenderPass* vkRenderPass = (RenderPass*)renderPass; + VkImageView attachments[MAX_ATTACHMENTS]; + + view = palAllocate(s_Vk.allocator, sizeof(RenderPassView), 0); + if (!view) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + Uint32 layers = 0; + Uint32 width = 0; + Uint32 height = 0; + for (int i = 0; i < info->imageViewCount; i++) { + ImageView* tmp = (ImageView*)info->imageViews[i]; + attachments[i] = tmp->handle; + layers = tmp->image->info.depthOrArraySize; + + // find the largest width and height from all image views + if (width < tmp->image->info.width) { + width = tmp->image->info.width; + } + + if (height < tmp->image->info.height) { + height = tmp->image->info.height; + } + } + VkFramebufferCreateInfo fbCreateInfo = {0}; fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fbCreateInfo.attachmentCount = info->attachmentCount; - fbCreateInfo.pAttachments = views; + fbCreateInfo.attachmentCount = info->imageViewCount; + fbCreateInfo.pAttachments = attachments; fbCreateInfo.height = info->height; fbCreateInfo.width = info->width; fbCreateInfo.layers = layers; - fbCreateInfo.renderPass = renderPass->handle; + fbCreateInfo.renderPass = vkRenderPass->handle; result = s_Vk.createFramebuffer( vkDevice->handle, &fbCreateInfo, &s_Vk.vkAllocator, - &renderPass->framebuffer); + &view->handle); if (result != VK_SUCCESS) { - s_Vk.destroyRenderPass( - vkDevice->handle, - renderPass->handle, - &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, renderPass); + palFree(s_Vk.allocator, view); // all image views in a single render pass must have the same // width/height/layers return PAL_RESULT_INVALID_ARGUMENT; } - renderPass->device = vkDevice; - renderPass->width = info->width; - renderPass->height = info->height; - renderPass->attachmentCount = info->attachmentCount; - - *outRenderPass = (PalRenderPass*)renderPass; + view->device = vkDevice; + view->width = width; + view->height = height; + *outRenderPassView = (PalRenderPassView*)view; return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass) +void PAL_CALL destroyVkRenderPassView(PalRenderPassView* view) { - RenderPass* vkRenderPass = (RenderPass*)renderPass; + RenderPassView* framebuffer = (RenderPassView*)view; s_Vk.destroyFramebuffer( - vkRenderPass->device->handle, - vkRenderPass->framebuffer, - &s_Vk.vkAllocator); - - s_Vk.destroyRenderPass( - vkRenderPass->device->handle, - vkRenderPass->handle, + framebuffer->device->handle, + framebuffer->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, renderPass); + palFree(s_Vk.allocator, view); } // ================================================== @@ -5110,12 +5135,11 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL beginVkCommandBuffer( PalCommandBuffer* cmdBuffer, - PalRenderPass* renderPass) + PalBeginInfo* info) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - RenderPass* vkRenderPass = (RenderPass*)renderPass; VkRenderPass renderPassHandle = nullptr; - VkFramebuffer frambufferHandle = nullptr; + VkFramebuffer viewHandle = nullptr; VkCommandBufferBeginInfo beginInfo = {0}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -5125,14 +5149,16 @@ PalResult PAL_CALL beginVkCommandBuffer( if (!vkCmdBuffer->primary) { // secondary command buffer - if (renderPass) { - renderPassHandle = vkRenderPass->handle; - frambufferHandle = vkRenderPass->framebuffer; - inheritanceInfo.framebuffer = frambufferHandle; + if (info->renderPass && info->view) { + RenderPass* renderPass = (RenderPass*)info->renderPass; + RenderPassView* view = (RenderPassView*)info->view; + renderPassHandle = renderPass->handle; + viewHandle = view->handle; + inheritanceInfo.framebuffer = viewHandle; inheritanceInfo.renderPass = renderPassHandle; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; - beginInfo .pInheritanceInfo = &inheritanceInfo; + beginInfo.pInheritanceInfo = &inheritanceInfo; } } @@ -5433,13 +5459,13 @@ PalResult PAL_CALL buildVkAccelerationStructure( PalResult PAL_CALL beginRenderPassVk( PalCommandBuffer* cmdBuffer, - PalRenderPass* renderPass, - Int32 clearValueCount, - PalClearValue* clearValues) + PalRenderPassBeginInfo* info) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - RenderPass* vkRenderPass = (RenderPass*)renderPass; - if (clearValueCount != vkRenderPass->attachmentCount) { + RenderPass* renderPass = (RenderPass*)info->renderPass; + RenderPassView* view = (RenderPassView*)info->view; + + if (info->clearValueCount != renderPass->attachmentCount) { return PAL_RESULT_INSUFFICIENT_BUFFER; } @@ -5447,8 +5473,8 @@ PalResult PAL_CALL beginRenderPassVk( renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; VkClearValue tmp[MAX_ATTACHMENTS]; - for (int i = 0; i < clearValueCount; i++) { - PalClearValue* clearValue = &clearValues[i]; + for (int i = 0; i < info->clearValueCount; i++) { + PalClearValue* clearValue = &info->clearValues[i]; if (clearValue->depth == 0 && clearValue->stencil == 0) { // color attachment tmp[i].color.float32[0] = clearValue->color[0]; @@ -5463,12 +5489,12 @@ PalResult PAL_CALL beginRenderPassVk( } } - renderPassBeginInfo.clearValueCount = clearValueCount; + renderPassBeginInfo.clearValueCount = info->clearValueCount; renderPassBeginInfo.pClearValues = tmp; - renderPassBeginInfo.framebuffer = vkRenderPass->framebuffer; - renderPassBeginInfo.renderPass = vkRenderPass->handle; - renderPassBeginInfo.renderArea.extent.width = vkRenderPass->width; - renderPassBeginInfo.renderArea.extent.height = vkRenderPass->height; + renderPassBeginInfo.framebuffer = view->handle; + renderPassBeginInfo.renderPass = renderPass->handle; + renderPassBeginInfo.renderArea.extent.width = view->width; + renderPassBeginInfo.renderArea.extent.height = view->height; s_Vk.cmdBeginRenderPass( vkCmdBuffer->handle, @@ -6258,6 +6284,8 @@ PalResult PAL_CALL createVkGraphicsPipeline( createInfo.pColorBlendState = &CBS; createInfo.renderPass = renderPass->handle; + // TODO: Fragment shading rate + if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); return vkResultToPal(result); diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index dfff5627..0ad59e21 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -3,25 +3,13 @@ #include "pal/pal_video.h" #include "tests.h" -bool clearColorTest() +static bool initVideo( + PalWindow** outWindow, + PalEventDriver** outEventDriver) { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Clear Color Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; - PalAdapter* adapter = nullptr; - PalDevice* device = nullptr; - PalQueue* queue = nullptr; - PalSwapchain* swapchain = nullptr; - PalCommandPool* cmdPool = nullptr; - PalImageView** imageViews = nullptr; - PalCommandBuffer** cmdBuffers = nullptr; - PalRenderPass** renderPasses = nullptr; // create an event driver PalEventDriverCreateInfo eventDriverCreateInfo = {0}; @@ -44,7 +32,6 @@ bool clearColorTest() PAL_DISPATCH_POLL); // initialize the video system - // you can use any library you want result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -74,8 +61,63 @@ bool clearColorTest() return false; } + *outWindow = window; + *outEventDriver = eventDriver; + return true; +} + +static PalWindowHandleInfo getWindowInfo( + PalWindow* window, + Uint32* width, + Uint32* height) +{ + *width = 640; + *height = 480; + return palGetWindowHandleInfo(window); +} + +static bool shutdownVideo( + PalWindow* window, + PalEventDriver* eventDriver) +{ + palDestroyWindow(window); + palShutdownVideo(); + palDestroyEventDriver(eventDriver); +} + +bool clearColorTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Clear Color Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + // initialize video system + PalWindow* window = nullptr; + PalEventDriver* eventDriver = nullptr; + Uint32 windowWidth = 0; + Uint32 windowHeight = 0; + PalWindowHandleInfo windowHandleInfo; + + if (!initVideo(&window, &eventDriver)) { + palLog(nullptr, "Failed to initialize video"); + return false; + } + windowHandleInfo = getWindowInfo(window, &windowWidth, &windowHeight); + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + PalCommandBuffer** cmdBuffers = nullptr; + PalRenderPass* renderPass = nullptr; + PalRenderPassView** renderPassViews = nullptr; + // initialize the graphics system - result = palInitGraphics(false, nullptr); + PalResult result = palInitGraphics(false, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -153,12 +195,9 @@ bool clearColorTest() } // check if the queue can present on our window - PalWindowHandleInfo handleInfo; PalGraphicsWindow gfxWindow; - handleInfo = palGetWindowHandleInfo(window); - gfxWindow.window = handleInfo.nativeWindow; - gfxWindow.display = handleInfo.nativeDisplay; - + gfxWindow.window = windowHandleInfo.nativeWindow; + gfxWindow.display = windowHandleInfo.nativeDisplay; if (!palCanQueuePresent(queue, &gfxWindow)) { palLog(nullptr, "Queue cannot present to window"); return false; @@ -181,21 +220,21 @@ bool clearColorTest() swapchainCreateInfo.clipped = true; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - swapchainCreateInfo.height = windowCreateInfo.height; - swapchainCreateInfo.width = windowCreateInfo.width; + swapchainCreateInfo.height = windowHeight; + swapchainCreateInfo.width = windowWidth; swapchainCreateInfo.imageArrayLayerCount = 1; // rare but possible on andriod - if (windowCreateInfo.width > swapchainCaps.maxImageWidth) { + if (windowWidth > swapchainCaps.maxImageWidth) { swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; } - if (windowCreateInfo.height > swapchainCaps.maxImageHeight) { + if (windowHeight > swapchainCaps.maxImageHeight) { swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; } // check if the minimal image count is not good for you - // and increase it nut not pass the max count + // and increase it but not pass the max count swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; @@ -230,9 +269,9 @@ bool clearColorTest() sizeof(PalImageView*) * imageCount, 0); - renderPasses = palAllocate( + renderPassViews = palAllocate( nullptr, - sizeof(PalRenderPass*) * imageCount, + sizeof(PalRenderPassView*) * imageCount, 0); cmdBuffers = palAllocate( @@ -240,11 +279,34 @@ bool clearColorTest() sizeof(PalCommandBuffer*) * imageCount, 0); - if (!imageViews || !renderPasses || !cmdBuffers) { + if (!imageViews || !renderPassViews || !cmdBuffers) { palLog(nullptr, "Failed to allocate memory"); palFree(nullptr, imageViews); palFree(nullptr, cmdBuffers); - palFree(nullptr, renderPasses); + palFree(nullptr, renderPassViews); + return false; + } + + // create render pass + PalAttachmentDesc presentAttachment = {0}; + presentAttachment.loadOp = PAL_LOAD_OP_CLEAR; + presentAttachment.storeOp = PAL_STORE_OP_STORE; + presentAttachment.type = PAL_ATTACHMENT_TYPE_PRESENT; + presentAttachment.sampleCount = PAL_SAMPLE_COUNT_1; + presentAttachment.format = palGetSwapchainFormat(swapchain); + + PalRenderPassCreateInfo renderPasscreateInfo = {0}; + renderPasscreateInfo.attachmentCount = 1; + renderPasscreateInfo.attachments = &presentAttachment; + + result = palCreateRenderPass( + device, + &renderPasscreateInfo, + &renderPass); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create render pass: %s", error); return false; } @@ -278,35 +340,8 @@ bool clearColorTest() palLog(nullptr, "Failed to create image view: %s", error); return false; } - - // create a render pass with the image view as a color attahcment - PalAttachmentDesc colorAttachment = {0}; - colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; - colorAttachment.storeOp = PAL_STORE_OP_STORE; - colorAttachment.type = PAL_ATTACHMENT_TYPE_COLOR; - colorAttachment.target = imageView; - - PalRenderPassCreateInfo renderPasscreateInfo = {0}; - renderPasscreateInfo.attachmentCount = 1; - renderPasscreateInfo.attachments = &colorAttachment; - - // render area - renderPasscreateInfo.width = swapchainCreateInfo.width; - renderPasscreateInfo.height = swapchainCreateInfo.height; - - PalRenderPass* renderPass = nullptr; - result = palCreateRenderPass( - device, - &renderPasscreateInfo, - &renderPass); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create render pass: %s", error); - return false; - } - - // create a command buffer for the image view + + // create a command buffer PalCommandBuffer* cmdBuffer = nullptr; result = palCreateCommandBuffer( device, @@ -320,12 +355,25 @@ bool clearColorTest() return false; } - // record commands - PalClearValue clearValue = {0}; - clearValue.color[0] = 0.2f; - clearValue.color[1] = 0.2f; - clearValue.color[2] = 0.2f; - clearValue.color[3] = 1.0f; + // create a render pass view + PalRenderPassView* renderPassView = nullptr; + PalRenderPassViewCreateInfo renderPassViewCreateInfo = {0}; + renderPassViewCreateInfo.width = swapchainCreateInfo.width; + renderPassViewCreateInfo.height = swapchainCreateInfo.height; + renderPassViewCreateInfo.imageViewCount = 1; + renderPassViewCreateInfo.imageViews = &imageView; + + result = palCreateRenderPassView( + device, + renderPass, + &renderPassViewCreateInfo, + &renderPassView); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create render pass view: %s", error); + return false; + } // begin command buffer recording // the optional render pass is used for secondary command buffer @@ -337,7 +385,20 @@ bool clearColorTest() return false; } - result = palBeginRenderPass(cmdBuffer, renderPass, 1, &clearValue); + // record commands + PalClearValue clearValue = {0}; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; + + PalRenderPassBeginInfo renderPassBeginInfo = {0}; + renderPassBeginInfo.clearValueCount = 1; + renderPassBeginInfo.clearValues = &clearValue; + renderPassBeginInfo.renderPass = renderPass; + renderPassBeginInfo.view = renderPassView; + + result = palBeginRenderPass(cmdBuffer, &renderPassBeginInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin render pass: %s", error); @@ -360,7 +421,7 @@ bool clearColorTest() } // cache everything so we can reference and destroy later - renderPasses[i] = renderPass; + renderPassViews[i] = renderPassView; cmdBuffers[i] = cmdBuffer; imageViews[i] = imageView; } @@ -439,24 +500,22 @@ bool clearColorTest() // cleanup for (int i = 0; i < imageCount; i++) { - palDestroyRenderPass(renderPasses[i]); + palDestroyRenderPassView(renderPassViews[i]); palDestroyCommandBuffer(cmdBuffers[i]); palDestroyImageView(imageViews[i]); } + palDestroyRenderPass(renderPass); palDestroyCommandPool(cmdPool); palDestroySwapchain(swapchain); palDestroyQueue(queue); palDestroyDevice(device); - - palDestroyWindow(window); - palShutdownVideo(); - palShutdownGraphics(); palFree(nullptr, imageViews); palFree(nullptr, cmdBuffers); - palFree(nullptr, renderPasses); + palFree(nullptr, renderPassViews); + shutdownVideo(window, eventDriver); return true; } \ No newline at end of file From 8faf39ee3a15fa2f03479a399f04a34a9e74695f Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 30 Dec 2025 15:34:55 +0000 Subject: [PATCH 068/372] start triangle test --- include/pal/pal_graphics.h | 6 +- src/graphics/pal_vulkan.c | 17 ++ tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 5 +- tests/triangle_test.c | 569 +++++++++++++++++++++++++++++++++++++ 6 files changed, 597 insertions(+), 4 deletions(-) create mode 100644 tests/triangle_test.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 301b91ac..e9d0c90d 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -536,6 +536,9 @@ typedef struct { Uint32 maxImageDepth; Uint32 maxImageArrayLayers; Uint32 maxImageMipLevels; + Uint32 maxRenderPassViewWidth; + Uint32 maxRenderPassViewHeight; + Uint32 maxRenderPassViewArrayLayers; PalSampleCount maxColorSampleCount; PalSampleCount maxDepthSampleCount; Uint32 maxColorAttachments; @@ -825,6 +828,7 @@ typedef struct { } PalSwapchainCreateInfo; typedef struct { + Uint32 patchControlPoints; PalShaderStage stage; const void* bytecode; Uint64 bytecodeSize; @@ -868,7 +872,7 @@ typedef struct { Uint32 blendAttachmentCount; Uint32 shaderCount; PalRenderPass* renderPass; - const PalShader** shaders; + PalShader** shaders; PalVertexLayout* vertexLayouts; PalBlendAttachment* blendAttachments; PalRasterizerState rasterizerState; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 475790d3..e29c21a6 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -263,6 +263,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + Uint32 patchControlPoints; Device* device; VkShaderModule handle; VkPipelineShaderStageCreateInfo info; @@ -2126,6 +2127,10 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->maxImageDepth = props.limits.maxImageDimension3D; caps->maxImageArrayLayers = props.limits.maxImageArrayLayers; + caps->maxRenderPassViewWidth = props.limits.maxFramebufferWidth; + caps->maxRenderPassViewHeight = props.limits.maxFramebufferHeight; + caps->maxRenderPassViewArrayLayers = props.limits.maxFramebufferLayers; + PalSampleCount tmp = PAL_SAMPLE_COUNT_1; tmp = vkSamplesToSamples(props.limits.framebufferColorSampleCounts); caps->maxColorSampleCount = tmp; @@ -4293,6 +4298,7 @@ PalResult PAL_CALL createVkShader( VkResult result; Shader* shader = nullptr; VkShaderStageFlags stage = 0; + Uint32 patchControlPoints = 0; Device* vkDevice = (Device*)device; if (info->stage == PAL_SHADER_STAGE_VERTEX) { @@ -4312,6 +4318,7 @@ PalResult PAL_CALL createVkShader( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + patchControlPoints = info->patchControlPoints; } else if (info->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { @@ -4354,6 +4361,7 @@ PalResult PAL_CALL createVkShader( } shader->device = vkDevice; + shader->patchControlPoints = patchControlPoints; shader->info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader->info.module = shader->handle; shader->info.pName = "main"; @@ -5990,6 +5998,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( PalPipeline** outPipeline) { VkResult result; + Uint32 patchControlPoints = 0; Pipeline* pipeline = nullptr; Device* vkDevice = (Device*)device; RenderPass* renderPass = (RenderPass*)info->renderPass; @@ -6021,6 +6030,9 @@ PalResult PAL_CALL createVkGraphicsPipeline( VkPipelineColorBlendStateCreateInfo CBS = {0}; CBS.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + VkPipelineTessellationStateCreateInfo TS = {0}; + TS.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + VkGraphicsPipelineCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -6033,6 +6045,11 @@ PalResult PAL_CALL createVkGraphicsPipeline( for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; shaderStages[i] = tmp->info; + + if (tmp->patchControlPoints) { + TS.patchControlPoints = tmp->patchControlPoints; + createInfo.pTessellationState = &TS; + } } // Vertex input state diff --git a/tests/tests.h b/tests/tests.h index a43c7bf8..41f17712 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -58,5 +58,6 @@ bool graphicsTest(); // graphics and video bool clearColorTest(); +bool triangleTest(); #endif // _TESTS_H \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index b10266ed..2cb1bff1 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -71,7 +71,8 @@ project "tests" if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { - "clear_color_test.c" + "clear_color_test.c", + "triangle_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index b8d7f6ac..ebfc9435 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,11 +55,12 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + // registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest("Clear Color Test", clearColorTest); + // registerTest("Clear Color Test", clearColorTest); + registerTest("Triangle Test", triangleTest); #endif // runTests(); diff --git a/tests/triangle_test.c b/tests/triangle_test.c new file mode 100644 index 00000000..d7721978 --- /dev/null +++ b/tests/triangle_test.c @@ -0,0 +1,569 @@ + +#include "pal/pal_graphics.h" +#include "pal/pal_video.h" +#include "tests.h" + +static bool initVideo( + PalWindow** outWindow, + PalEventDriver** outEventDriver) +{ + PalResult result; + PalWindow* window = nullptr; + PalEventDriver* eventDriver = nullptr; + + // create an event driver + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create event driver: %s", error); + return false; + } + + // we only need window close and keydown(escape) for borderless window + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_WINDOW_CLOSE, + PAL_DISPATCH_POLL); + + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_KEYDOWN, + PAL_DISPATCH_POLL); + + // initialize the video system + result = palInitVideo(nullptr, eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize video: %s", error); + return false; + } + + // create a window + PalWindowCreateInfo windowCreateInfo = {0}; + windowCreateInfo.height = 480; + windowCreateInfo.width = 640; + windowCreateInfo.show = true; + windowCreateInfo.title = "Triangle Window"; + + // check if we support decorated windows (title bar, close etc) + PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); + if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + // if we dont support, we need to create a borderless window + // and create the decorations ourselves + windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&windowCreateInfo, &window); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create window: %s", error); + return false; + } + + *outWindow = window; + *outEventDriver = eventDriver; + return true; +} + +static PalWindowHandleInfo getWindowInfo( + PalWindow* window, + Uint32* width, + Uint32* height) +{ + *width = 640; + *height = 480; + return palGetWindowHandleInfo(window); +} + +static bool shutdownVideo( + PalWindow* window, + PalEventDriver* eventDriver) +{ + palDestroyWindow(window); + palShutdownVideo(); + palDestroyEventDriver(eventDriver); +} + +bool triangleTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Triangle Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + // initialize video system + PalWindow* window = nullptr; + PalEventDriver* eventDriver = nullptr; + Uint32 windowWidth = 0; + Uint32 windowHeight = 0; + PalWindowHandleInfo windowHandleInfo; + + if (!initVideo(&window, &eventDriver)) { + palLog(nullptr, "Failed to initialize video"); + return false; + } + windowHandleInfo = getWindowInfo(window, &windowWidth, &windowHeight); + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + PalCommandBuffer** cmdBuffers = nullptr; + PalRenderPass* renderPass = nullptr; + PalRenderPassView** renderPassViews = nullptr; + + PalShader* vertexShader = nullptr; + PalShader* indexShader = nullptr; + PalPipeline* pipeline = nullptr; + + // initialize the graphics system + PalResult result = palInitGraphics(false, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 count = 0; + result = palEnumerateAdapters(&count, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (count == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", count); + + // allocate an array of adapters or use a fixed array + // Example: PalAdapter* adapters[12]; + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&count, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + // get information about all the adapters and find the adapter that + // has graphics queue + PalAdapterCapabilities caps; + for (Int32 i = 0; i < count; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (caps.maxGraphicsQueues == 0) { + continue; + } else { + break; + } + } + + palFree(nullptr, adapters); + + // create a device + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + result = palCreateDevice(adapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a graphics command queue + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + // check if the queue can present on our window + PalGraphicsWindow gfxWindow; + gfxWindow.window = windowHandleInfo.nativeWindow; + gfxWindow.display = windowHandleInfo.nativeDisplay; + if (!palCanQueuePresent(queue, &gfxWindow)) { + palLog(nullptr, "Queue cannot present to window"); + return false; + } + + // create a swapchain with the graphics queue + PalSwapchainCapabilities swapchainCaps = {0}; + result = palQuerySwapchainCapabilities( + device, + &gfxWindow, + &swapchainCaps); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to query swapchain capabilities: %s", error); + return false; + } + + PalSwapchainCreateInfo swapchainCreateInfo = {0}; + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + swapchainCreateInfo.height = windowHeight; + swapchainCreateInfo.width = windowWidth; + swapchainCreateInfo.imageArrayLayerCount = 1; + + // rare but possible on andriod + if (windowWidth > swapchainCaps.maxImageWidth) { + swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; + } + + if (windowHeight > swapchainCaps.maxImageHeight) { + swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; + } + + // check if the minimal image count is not good for you + // and increase it but not pass the max count + swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + + result = palCreateSwapchain( + device, + queue, + &gfxWindow, + &swapchainCreateInfo, + &swapchain); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create swapchain: %s", error); + return false; + } + + // create a command pool for the command buffers + PalCommandPoolCreateInfo cmdPoolCreateInfo = {0}; + cmdPoolCreateInfo.queue = queue; + result = palCreateCommandPool(device, &cmdPoolCreateInfo, &cmdPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + // get all swapchain images and create command buffers and image views + // for them. This is much faster than resetting and recording per frames + Uint32 imageCount = swapchainCreateInfo.imageCount; + imageViews = palAllocate( + nullptr, + sizeof(PalImageView*) * imageCount, + 0); + + renderPassViews = palAllocate( + nullptr, + sizeof(PalRenderPassView*) * imageCount, + 0); + + cmdBuffers = palAllocate( + nullptr, + sizeof(PalCommandBuffer*) * imageCount, + 0); + + if (!imageViews || !renderPassViews || !cmdBuffers) { + palLog(nullptr, "Failed to allocate memory"); + palFree(nullptr, imageViews); + palFree(nullptr, cmdBuffers); + palFree(nullptr, renderPassViews); + return false; + } + + // create render pass + PalAttachmentDesc presentAttachment = {0}; + presentAttachment.loadOp = PAL_LOAD_OP_CLEAR; + presentAttachment.storeOp = PAL_STORE_OP_STORE; + presentAttachment.type = PAL_ATTACHMENT_TYPE_PRESENT; + presentAttachment.sampleCount = PAL_SAMPLE_COUNT_1; + presentAttachment.format = palGetSwapchainFormat(swapchain); + + PalRenderPassCreateInfo renderPasscreateInfo = {0}; + renderPasscreateInfo.attachmentCount = 1; + renderPasscreateInfo.attachments = &presentAttachment; + + result = palCreateRenderPass( + device, + &renderPasscreateInfo, + &renderPass); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create render pass: %s", error); + return false; + } + + // create shaders + + // create graphics pipeline + // vertex attributes and vertex layout + PalVertexAttribute vertices[2]; + PalVertexLayout layout; + + PalVertexAttribute* position = &vertices[0]; + position->location = 0; + position->type = PAL_VERTEX_TYPE_FLOAT2; + + PalVertexAttribute* color = &vertices[1]; + color->location = 1; + color->type = PAL_VERTEX_TYPE_FLOAT3; // no alpha + + layout.binding = 0; + layout.type = PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX; + layout.vertexCount = 2; + layout.vertices = vertices; + + PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; + pipelineCreateInfo.vertexLayouts = &layout; + pipelineCreateInfo.vertexLayoutCount = 1; + + // Input assembly + pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + // shaders + PalShader* shaders[2]; // vertex and index + shaders[0] = vertexShader; + shaders[1] = indexShader; + pipelineCreateInfo.shaders = shaders; + pipelineCreateInfo.shaderCount = 2; + + pipelineCreateInfo.renderPass = renderPass; + // TODO: + // result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline: %s", error); + return false; + } + + for (int i = 0; i < imageCount; i++) { + // get swapchain image + PalImage* image = palGetSwapchainImage(swapchain, i); + if (!image) { + palLog(nullptr, "Failed to get swapchain image"); + } + + // create image view + // swapchain images are 2D and they only supports 2D + // and 2D array view types + PalImageView* imageView = nullptr; + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.layerArrayCount = 1; + imageViewCreateInfo.mipLevelCount = 1; + imageViewCreateInfo.startArrayLayer = 0; + imageViewCreateInfo.startMipLevel = 0; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; + + result = palCreateImageView( + device, + image, + &imageViewCreateInfo, + &imageView); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + + // create a command buffer + PalCommandBuffer* cmdBuffer = nullptr; + result = palCreateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffer); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command buffer: %s", error); + return false; + } + + // create a render pass view + PalRenderPassView* renderPassView = nullptr; + PalRenderPassViewCreateInfo renderPassViewCreateInfo = {0}; + renderPassViewCreateInfo.width = swapchainCreateInfo.width; + renderPassViewCreateInfo.height = swapchainCreateInfo.height; + renderPassViewCreateInfo.imageViewCount = 1; + renderPassViewCreateInfo.imageViews = &imageView; + + result = palCreateRenderPassView( + device, + renderPass, + &renderPassViewCreateInfo, + &renderPassView); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create render pass view: %s", error); + return false; + } + + // begin command buffer recording + // the optional render pass is used for secondary command buffer + // which will be used with a render pass + result = palBeginCommandBuffer(cmdBuffer, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + // record commands + PalClearValue clearValue = {0}; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; + + PalRenderPassBeginInfo renderPassBeginInfo = {0}; + renderPassBeginInfo.clearValueCount = 1; + renderPassBeginInfo.clearValues = &clearValue; + renderPassBeginInfo.renderPass = renderPass; + renderPassBeginInfo.view = renderPassView; + + result = palBeginRenderPass(cmdBuffer, &renderPassBeginInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin render pass: %s", error); + return false; + } + + result = palEndRenderPass(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end render pass: %s", error); + return false; + } + + // end command buffer recording + result = palEndCommandBuffer(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // cache everything so we can reference and destroy later + renderPassViews[i] = renderPassView; + cmdBuffers[i] = cmdBuffer; + imageViews[i] = imageView; + } + + // main loop + bool running = true; + while (running) { + // update the video system to push video events + palUpdateVideo(); + + PalEvent event; + while (palPollEvent(eventDriver, &event)) { + switch (event.type) { + case PAL_EVENT_WINDOW_CLOSE: { + running = false; + break; + } + + case PAL_EVENT_KEYDOWN: { + PalKeycode keycode = 0; + palUnpackUint32(event.data, &keycode, nullptr); + if (keycode == PAL_KEYCODE_ESCAPE) { + running = false; + } + break; + } + } + } + + // get the next image that we can render too + PalImage* image = nullptr; + PalNextImageInfo nextImageInfo = {0}; + nextImageInfo.timeout = UINT64_MAX; + image = palGetNextSwapchainImage(swapchain, &nextImageInfo); + + // find the command buffer associated with the image + // this is fast, the swapchain caches all it images internally + PalCommandBuffer* cmdBuffer = nullptr; + for (int i = 0; i < imageCount; i++) { + if (image == palGetSwapchainImage(swapchain, i)) { + cmdBuffer = cmdBuffers[i]; + break; + } + } + + // submit to the queue and present + PalSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffer; + + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + PalPresentInfo presentInfo = {0}; + presentInfo.image = image; + + result = palPresentSwapchain(swapchain, &presentInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to present swapchain: %s", error); + return false; + } + } + + // since we dont use a fence or sempahore, there is no way to know + // if the GPU is done presenting and we can now destroy the swapchain + // so we just wait for a while + // and we dont want to use thread system for this + Int32 counter = 0; + for (int i = 0; i < 30000; i++) { + counter++; + } + + // cleanup + for (int i = 0; i < imageCount; i++) { + palDestroyRenderPassView(renderPassViews[i]); + palDestroyCommandBuffer(cmdBuffers[i]); + palDestroyImageView(imageViews[i]); + } + + palDestroyPipeline(pipeline); + palDestroyRenderPass(renderPass); + palDestroyCommandPool(cmdPool); + palDestroySwapchain(swapchain); + palDestroyQueue(queue); + palDestroyDevice(device); + palShutdownGraphics(); + + palFree(nullptr, imageViews); + palFree(nullptr, cmdBuffers); + palFree(nullptr, renderPassViews); + + shutdownVideo(window, eventDriver); + return true; +} \ No newline at end of file From 8865474d885fe84776c7090a7d97f2dc5e4f5238 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 30 Dec 2025 16:33:23 +0000 Subject: [PATCH 069/372] add spirv shader binaries to test --- src/graphics/pal_vulkan.c | 1 - tests/shaders/triangle.fragment.spv | Bin 0 -> 564 bytes tests/shaders/triangle.vertex.spv | Bin 0 -> 1076 bytes tests/triangle_test.c | 83 ++++++++++++++++++++++++++-- 4 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 tests/shaders/triangle.fragment.spv create mode 100644 tests/shaders/triangle.vertex.spv diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e29c21a6..8b229bcd 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -6288,7 +6288,6 @@ PalResult PAL_CALL createVkGraphicsPipeline( } } - // TODO: pipeline layout createInfo.layout = nullptr; createInfo.stageCount = info->shaderCount; createInfo.pStages = shaderStages; diff --git a/tests/shaders/triangle.fragment.spv b/tests/shaders/triangle.fragment.spv new file mode 100644 index 0000000000000000000000000000000000000000..46630b0f36bb921ceb90618691b7f7f2325e2649 GIT binary patch literal 564 zcmYk2%}T>i5QWF4f426|g6^c^QYbD|1hFnevI$i20YXW#2*k9svEa^U^Qqhjo-f{( zT$s!~XU@!=8?ScJGCQ!Y^=xeaXJj=oCazg#KX?nKnSn^y|a46J2!W#WC2 z<`fPUM~b0z@LHgor>SP&YN}hu{2=t_b3b?vqtzDJ2oiSA8t6UC|YyamkO ziN0-R{s#QL!+3y0-%&;nM&DJ|FDQBRU_8KG3Zv~S%)TCP^#c5`i^Gf`F%9JhvCQr% r=zkSU@4#_Ndv54BcI*7ti^Yya@*fQ)HVc8TOv&6wL) z^nPjB6fh;5lWoejWo11j`EMPlm~j)RinY^|J69Q!n_6($TLOq_7=sxZ~#oa7^7ZjWG?1{B|HnZ(i?1;88rGG;VNz>Z&&T4-OVxcX%slr zdG0{pTV=CndGERW+wj%?^Eg8ux_lmcIOY`Ujh-zT3(WT!#ApFicU~%}xuc5IVZWr^ zuzXFntn>PD9H#!F@Th!E#@Z_|e+Tt8gvaGM54WWq+I$USSWS78@?QICftf2DeWqPr zUY9=Ls*HuM8F~7knR>JGXn?04m|4Jap4POi@_7aTS3r4+3zGIEJ= jKkjs?8r)}1#!Q*pxw?YMrzbjVGBgt7F5q7&K9T(a^`cc6 literal 0 HcmV?d00001 diff --git a/tests/triangle_test.c b/tests/triangle_test.c index d7721978..55906904 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -3,6 +3,30 @@ #include "pal/pal_video.h" #include "tests.h" +#include + +static bool readFile(const char* filename, char* buffer, Uint32* size) +{ + FILE* file = fopen(filename, "rb"); + if (!file) { + return false; + } + + if (!buffer) { + fseek(file, 0, SEEK_END); + Uint64 tmpSize = ftell(file); + fclose(file); + + *size = tmpSize; + return true; + } + + fseek(file, 0, SEEK_SET); + fread(buffer, 1, (Uint64)size, file); + fclose(file); + return true; +} + static bool initVideo( PalWindow** outWindow, PalEventDriver** outEventDriver) @@ -117,7 +141,7 @@ bool triangleTest() PalRenderPassView** renderPassViews = nullptr; PalShader* vertexShader = nullptr; - PalShader* indexShader = nullptr; + PalShader* fragmentShader = nullptr; PalPipeline* pipeline = nullptr; // initialize the graphics system @@ -315,6 +339,58 @@ bool triangleTest() } // create shaders + Uint32 vertexShaderSize = 0; + Uint32 fragmentShaderSize = 0; + char* vertexShaderBytecode = nullptr; + char* fragmentShaderBytecode = nullptr; + readFile("shaders/triangle.vertex.spv", nullptr, &vertexShaderSize); + readFile("shaders/triangle.fragment.spv", nullptr, &vertexShaderSize); + + if (!vertexShaderSize && !fragmentShaderSize) { + palLog(nullptr, "Failed to find shader files"); + return false; + } + + vertexShaderBytecode = palAllocate(nullptr, vertexShaderSize, 0); + fragmentShaderBytecode = palAllocate(nullptr, fragmentShaderSize, 0); + if (!vertexShaderBytecode && !fragmentShaderBytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile( + "shaders/triangle.vertex.spv", + vertexShaderBytecode, + &vertexShaderSize); + + readFile( + "shaders/triangle.fragment.spv", + fragmentShaderBytecode, + &vertexShaderSize); + + PalShaderCreateInfo shaderCreateInfo = {0}; + shaderCreateInfo.bytecode = (const void*)vertexShaderBytecode; + shaderCreateInfo.bytecodeSize = vertexShaderSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; + result = palCreateShader(device, &shaderCreateInfo, &vertexShader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create vertex shader: %s", error); + return false; + } + + shaderCreateInfo.bytecode = (const void*)fragmentShaderBytecode; + shaderCreateInfo.bytecodeSize = fragmentShaderSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; + result = palCreateShader(device, &shaderCreateInfo, &vertexShader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fragment shader: %s", error); + return false; + } + + palFree(nullptr, vertexShaderBytecode); + palFree(nullptr, fragmentShaderBytecode); // create graphics pipeline // vertex attributes and vertex layout @@ -342,14 +418,13 @@ bool triangleTest() pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; // shaders - PalShader* shaders[2]; // vertex and index + PalShader* shaders[2]; // vertex and fragment shaders[0] = vertexShader; - shaders[1] = indexShader; + shaders[1] = fragmentShader; pipelineCreateInfo.shaders = shaders; pipelineCreateInfo.shaderCount = 2; pipelineCreateInfo.renderPass = renderPass; - // TODO: // result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); From 471cb6e558a41d164a384b02dbbcf03ce4105116 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 2 Jan 2026 11:30:49 +0000 Subject: [PATCH 070/372] add graphics pipeline creation and deletion --- include/pal/pal_graphics.h | 25 ++- src/graphics/pal_graphics.c | 48 +++++ src/graphics/pal_vulkan.c | 366 +++++++++++++++++++----------------- tests/triangle_test.c | 56 +++--- 4 files changed, 297 insertions(+), 198 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index e9d0c90d..69593f88 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -58,6 +58,7 @@ typedef struct PalCommandPool PalCommandPool; typedef struct PalCommandBuffer PalCommandBuffer; typedef struct PalPipeline PalPipeline; +typedef struct PalPipelineLayout PalPipelineLayout; typedef struct PalAccelerationStructure PalAccelerationStructure; typedef enum { @@ -331,7 +332,8 @@ typedef enum { PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, PAL_PRIMITIVE_TOPOLOGY_LINE_LIST, PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP, - PAL_PRIMITIVE_TOPOLOGY_POINT_LIST + PAL_PRIMITIVE_TOPOLOGY_POINT_LIST, + PAL_PRIMITIVE_TOPOLOGY_PATCH } PalPrimitiveTopology; typedef enum { @@ -830,7 +832,7 @@ typedef struct { typedef struct { Uint32 patchControlPoints; PalShaderStage stage; - const void* bytecode; + void* bytecode; Uint64 bytecodeSize; } PalShaderCreateInfo; @@ -865,6 +867,10 @@ typedef struct { Uint64 size; } PalAccelerationStructureCreateInfo; +typedef struct { + bool unused; +} PalPipelineLayoutCreateInfo; + typedef struct { bool fragmentShadingRateEnabled; PalPrimitiveTopology topology; @@ -872,6 +878,7 @@ typedef struct { Uint32 blendAttachmentCount; Uint32 shaderCount; PalRenderPass* renderPass; + PalPipelineLayout* pipelineLayout; PalShader** shaders; PalVertexLayout* vertexLayouts; PalBlendAttachment* blendAttachments; @@ -1183,6 +1190,13 @@ typedef struct { PalBuffer* buffer, PalMemory* memory); + PalResult PAL_CALL (*createPipelineLayout)( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + + void PAL_CALL (*destroyPipelineLayout)(PalPipelineLayout* layout); + PalResult PAL_CALL (*createGraphicsPipeline)( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, @@ -1501,6 +1515,13 @@ PAL_API void PAL_CALL palUnmapBuffer( PalBuffer* buffer, PalMemory* memory); +PAL_API PalResult PAL_CALL palCreatePipelineLayout( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + +PAL_API void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout); + PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 6469ed4e..ea0cee2e 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -51,6 +51,7 @@ PAL_HANDLE(PalCommandBuffer) PAL_HANDLE(PalPipeline) PAL_HANDLE(PalAccelerationStructure) PAL_HANDLE(PalRenderPassView) +PAL_HANDLE(PalPipelineLayout) typedef struct { Int32 count; @@ -385,6 +386,13 @@ void PAL_CALL unmapVkBuffer( PalBuffer* buffer, PalMemory* memory); +PalResult PAL_CALL createVkPipelineLayout( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + +void PAL_CALL destroyVkPipelineLayout(PalPipelineLayout* layout); + PalResult PAL_CALL createVkGraphicsPipeline( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, @@ -467,6 +475,8 @@ static PalGraphicsBackend s_VkBackend = { .bindBufferMemory = bindVkBufferMemory, .mapBuffer = mapVkBuffer, .unmapBuffer = unmapVkBuffer, + .createPipelineLayout = createVkPipelineLayout, + .destroyPipelineLayout = destroyVkPipelineLayout, .createGraphicsPipeline = createVkGraphicsPipeline, .destroyPipeline = destroyVkPipeline }; @@ -579,6 +589,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->bindBufferMemory || !backend->mapBuffer || !backend->unmapBuffer || + !backend->createPipelineLayout || + !backend->destroyPipelineLayout || !backend->createGraphicsPipeline || !backend->destroyPipeline) { return PAL_RESULT_INVALID_BACKEND; @@ -2006,6 +2018,42 @@ void PAL_CALL palUnmapBuffer( // Pipeline // ================================================== +PalResult PAL_CALL palCreatePipelineLayout( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outLayout) { + return PAL_RESULT_NULL_POINTER; + } + + PalResult result; + PalPipelineLayout* layout = nullptr; + result = device->backend->createPipelineLayout( + device, + info, + &layout); + + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + layout->backend = device->backend; + *outLayout = layout; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout) +{ + if (s_Graphics.initialized && layout) { + layout->backend->destroyPipelineLayout(layout); + } +} + PalResult PAL_CALL palCreateGraphicsPipeline( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 8b229bcd..4ff01bc4 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -158,6 +158,8 @@ typedef struct { PFN_vkMapMemory mapMemory; PFN_vkUnmapMemory unmapMemory; + PFN_vkCreatePipelineLayout createPipelineLayout; + PFN_vkDestroyPipelineLayout destroyPipelineLayout; PFN_vkCreateGraphicsPipelines createGraphicsPipeline; PFN_vkDestroyPipeline destroyPipeline; @@ -341,6 +343,13 @@ typedef struct { VkAccelerationStructureKHR handle; } AccelerationStructure; +typedef struct { + const PalGraphicsBackend* backend; + + Device* device; + VkPipelineLayout handle; +} PipelineLayout; + typedef struct { const PalGraphicsBackend* backend; @@ -1451,6 +1460,29 @@ static VkBlendFactor blendFactorToVk(PalBlendFactor op) return VK_BLEND_FACTOR_ZERO; } +static VkFragmentShadingRateCombinerOpKHR combinerOpsToVk( + PalFragmentShadingRateCombinerOp op) +{ + switch (op) { + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR; + } + + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; +} + static void* vkAlloc( void* pUserData, size_t size, @@ -1743,6 +1775,14 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkBindBufferMemory"); + s_Vk.createPipelineLayout = (PFN_vkCreatePipelineLayout)dlsym( + s_Vk.handle, + "vkCreatePipelineLayout"); + + s_Vk.destroyPipelineLayout = (PFN_vkDestroyPipelineLayout)dlsym( + s_Vk.handle, + "vkDestroyPipelineLayout"); + s_Vk.createGraphicsPipeline = (PFN_vkCreateGraphicsPipelines)dlsym( s_Vk.handle, "vkCreateGraphicsPipelines"); @@ -2629,8 +2669,6 @@ PalResult PAL_CALL createVkDevice( const char* extensions[16] = {0}; // clang-format off - - const void* start = nullptr; VkPhysicalDeviceTimelineSemaphoreFeatures timeline = {0}; timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; @@ -2645,8 +2683,8 @@ PalResult PAL_CALL createVkDevice( ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs = {0}; - vrs.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; + VkPhysicalDeviceFragmentShadingRateFeaturesKHR fsr = {0}; + fsr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; VkPhysicalDeviceDescriptorIndexingFeatures descIndex = {0}; descIndex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; @@ -2663,6 +2701,9 @@ PalResult PAL_CALL createVkDevice( VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; + VkDeviceCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + // clang-format on if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { extensions[extCount++] = "VK_KHR_swapchain"; @@ -2678,19 +2719,17 @@ PalResult PAL_CALL createVkDevice( } timeline.timelineSemaphore = true; - start = &timeline; + createInfo.pNext = &timeline; } if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_shader_float16_int8"; } - shader16.shaderFloat16 = true; - if (timeline.timelineSemaphore) { - timeline.pNext = &shader16; - } - start = &shader16; + + shader16.pNext = &createInfo.pNext; + createInfo.pNext = &shader16; } if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { @@ -2698,18 +2737,12 @@ PalResult PAL_CALL createVkDevice( extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; extensions[extCount++] = "VK_KHR_acceleration_structure"; } - ray.rayTracingPipeline = true; acc.accelerationStructure = true; - if (shader16.shaderFloat16) { - shader16.pNext = &ray; - } else if (timeline.timelineSemaphore) { - // no shader16, check timeline - timeline.pNext = &ray; - } - ray.pNext = &acc; - start = &ray; + ray.pNext = &createInfo.pNext; + acc.pNext = ray.pNext; + createInfo.pNext = &acc; } if ((features & PAL_ADAPTER_FEATURE_MESH_SHADER) || @@ -2723,100 +2756,50 @@ PalResult PAL_CALL createVkDevice( extensions[extCount++] = "VK_KHR_draw_indirect_count"; } } - mesh.meshShader = true; mesh.taskShader = true; - if (acc.accelerationStructure) { - acc.pNext = &mesh; - } else if (shader16.shaderFloat16) { - shader16.pNext = &mesh; - - } else if (timeline.timelineSemaphore) { - timeline.pNext = &mesh; - } - start = &mesh; + mesh.pNext = &createInfo.pNext; + createInfo.pNext = &mesh; } if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_KHR_fragment_shading_rate"; - vrs.pipelineFragmentShadingRate = true; + fsr.pipelineFragmentShadingRate = true; // fragment shading rate attachment needs this if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_create_renderpass2"; } - vrs.attachmentFragmentShadingRate = true; + fsr.attachmentFragmentShadingRate = true; } } - if (mesh.meshShader) { - mesh.pNext = &vrs; - - } else if (acc.accelerationStructure) { - acc.pNext = &vrs; - - } else if (shader16.shaderFloat16) { - shader16.pNext = &vrs; - - } else if (timeline.timelineSemaphore) { - timeline.pNext = &vrs; - } - start = &vrs; + fsr.pNext = &createInfo.pNext; + createInfo.pNext = &fsr; } if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_EXT_descriptor_indexing"; } - descIndex.shaderSampledImageArrayNonUniformIndexing = true; - if (vrs.pipelineFragmentShadingRate) { - vrs.pNext = &descIndex; - - } else if (mesh.meshShader) { - mesh.pNext = &descIndex; - - } else if (acc.accelerationStructure) { - acc.pNext = &descIndex; - - } else if (shader16.shaderFloat16) { - shader16.pNext = &descIndex; - } else if (timeline.timelineSemaphore) { - timeline.pNext = &descIndex; - } - start = &descIndex; + descIndex.pNext = &createInfo.pNext; + createInfo.pNext = &descIndex; } if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_multiview"; } - multiView.multiview = true; - if (descIndex.shaderSampledImageArrayNonUniformIndexing) { - descIndex.pNext = &multiView; - - } else if (vrs.pipelineFragmentShadingRate) { - vrs.pNext = &multiView; - } else if (mesh.meshShader) { - mesh.pNext = &multiView; - - } else if (acc.accelerationStructure) { - acc.pNext = &multiView; - - } else if (shader16.shaderFloat16) { - shader16.pNext = &multiView; - - } else if (timeline.timelineSemaphore) { - timeline.pNext = &multiView; - } - start = &multiView; + multiView.pNext = &createInfo.pNext; + createInfo.pNext = &multiView; } if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE || @@ -2825,30 +2808,10 @@ PalResult PAL_CALL createVkDevice( if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_EXT_extended_dynamic_state"; } - dynamicState.extendedDynamicState = true; - if (multiView.multiview) { - multiView.pNext = &dynamicState; - - } else if (descIndex.shaderSampledImageArrayNonUniformIndexing) { - descIndex.pNext = &dynamicState; - - } else if (vrs.pipelineFragmentShadingRate) { - vrs.pNext = &dynamicState; - } else if (mesh.meshShader) { - mesh.pNext = &dynamicState; - - } else if (acc.accelerationStructure) { - acc.pNext = &dynamicState; - - } else if (shader16.shaderFloat16) { - shader16.pNext = &dynamicState; - - } else if (timeline.timelineSemaphore) { - timeline.pNext = &dynamicState; - } - start = &dynamicState; + dynamicState.pNext = &createInfo.pNext; + createInfo.pNext = &dynamicState; } if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE || @@ -2857,31 +2820,8 @@ PalResult PAL_CALL createVkDevice( extensions[extCount++] = "VK_EXT_extended_dynamic_state2"; dynamicState2.extendedDynamicState2 = true; - if (dynamicState.extendedDynamicState) { - dynamicState.pNext = &dynamicState2; - - } else if (multiView.multiview) { - multiView.pNext = &dynamicState2; - - } else if (descIndex.shaderSampledImageArrayNonUniformIndexing) { - descIndex.pNext = &dynamicState2; - - } else if (vrs.pipelineFragmentShadingRate) { - vrs.pNext = &dynamicState2; - - } else if (mesh.meshShader) { - mesh.pNext = &dynamicState2; - - } else if (acc.accelerationStructure) { - acc.pNext = &dynamicState2; - - } else if (shader16.shaderFloat16) { - shader16.pNext = &dynamicState2; - - } else if (timeline.timelineSemaphore) { - timeline.pNext = &dynamicState2; - } - start = &dynamicState2; + dynamicState2.pNext = &createInfo.pNext; + createInfo.pNext = &dynamicState2; } if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { @@ -2889,45 +2829,16 @@ PalResult PAL_CALL createVkDevice( extensions[extCount++] = "VK_KHR_buffer_device_address"; } bufferAddress.bufferDeviceAddress = true; - - if (dynamicState2.extendedDynamicState2) { - dynamicState2.pNext = &bufferAddress; - - } else if (dynamicState.extendedDynamicState) { - dynamicState.pNext = &dynamicState2; - - } else if (multiView.multiview) { - multiView.pNext = &dynamicState2; - } else if (descIndex.shaderSampledImageArrayNonUniformIndexing) { - descIndex.pNext = &dynamicState2; - - } else if (vrs.pipelineFragmentShadingRate) { - vrs.pNext = &dynamicState2; - - } else if (mesh.meshShader) { - mesh.pNext = &dynamicState2; - - } else if (acc.accelerationStructure) { - acc.pNext = &dynamicState2; - - } else if (shader16.shaderFloat16) { - shader16.pNext = &dynamicState2; - - } else if (timeline.timelineSemaphore) { - timeline.pNext = &dynamicState2; - } - start = &dynamicState2; + bufferAddress.pNext = &createInfo.pNext; + createInfo.pNext = &bufferAddress; } - VkDeviceCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pEnabledFeatures = &coreFeatures; createInfo.enabledExtensionCount = extCount; createInfo.ppEnabledExtensionNames = extensions; createInfo.pQueueCreateInfos = queueCreateInfos; createInfo.queueCreateInfoCount = count; - createInfo.pNext = start; ret = s_Vk.createDevice( phyDevice, @@ -4343,6 +4254,7 @@ PalResult PAL_CALL createVkShader( if (!shader) { return PAL_RESULT_OUT_OF_MEMORY; } + memset(shader, 0, sizeof(Shader)); VkShaderModuleCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; @@ -4432,7 +4344,7 @@ PalResult PAL_CALL createVkRenderPass( rDesc->format = palFormatToVk(desc->format); rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rDesc->samples = vkSamplesToSamples(desc->sampleCount); + rDesc->samples = samplesToVk(desc->sampleCount); rDesc->flags = 0; // load op @@ -4456,20 +4368,23 @@ PalResult PAL_CALL createVkRenderPass( VkAttachmentReference2KHR* ref = nullptr; VkImageAspectFlags aspectMask = 0; - VkImageLayout layout = 0; + VkImageLayout layout, refLayout = 0; if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { ref = &colorRefs[colorRefCount++]; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } else if (desc->type == PAL_ATTACHMENT_TYPE_COLOR_RESOLVE) { ref = &resolveRefs[resolveRefCount++]; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH) { ref = &depthRef; layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + refLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; hasDepth = true; @@ -4494,11 +4409,13 @@ PalResult PAL_CALL createVkRenderPass( } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH_RESOLVE) { ref = &resolveRefs[resolveRefCount++]; layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + refLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; } else if (desc->type == PAL_ATTACHMENT_TYPE_PRESENT) { ref = &colorRefs[colorRefCount++]; layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } else { @@ -4510,13 +4427,14 @@ PalResult PAL_CALL createVkRenderPass( ref = &fsrRef; layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + refLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; aspectMask = 0; fsrAttachment.pFragmentShadingRateAttachment = &fsrRef; hasFsr = true; } ref->attachment = i; - ref->layout = layout; + ref->layout = refLayout; ref->aspectMask = aspectMask; ref->pNext = 0; ref->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; @@ -4569,7 +4487,7 @@ PalResult PAL_CALL createVkRenderPass( rDesc->flags = 0; rDesc->format = palFormatToVk(desc->format); rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rDesc->samples = vkSamplesToSamples(desc->sampleCount); + rDesc->samples = samplesToVk(desc->sampleCount); rDesc->flags = 0; // load op @@ -4591,22 +4509,29 @@ PalResult PAL_CALL createVkRenderPass( rDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; } + // stencil op. set to default + rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + VkAttachmentReference* ref = nullptr; VkImageAspectFlags aspectMask = 0; - VkImageLayout layout = 0; + VkImageLayout layout, refLayout = 0; if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { ref = &colorRefs[colorRefCount++]; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } else if (desc->type == PAL_ATTACHMENT_TYPE_COLOR_RESOLVE) { ref = &resolveRefs[resolveRefCount++]; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH) { ref = &depthRef; layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + refLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; hasDepth = true; @@ -4631,16 +4556,18 @@ PalResult PAL_CALL createVkRenderPass( } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH_RESOLVE) { ref = &resolveRefs[resolveRefCount++]; layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + refLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; } else { ref = &colorRefs[colorRefCount++]; layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } ref->attachment = i; - ref->layout = layout; + ref->layout = refLayout; rDesc->finalLayout = layout; } @@ -5992,6 +5919,49 @@ void PAL_CALL unmapVkBuffer( // Pipeline // ================================================== +PalResult PAL_CALL createVkPipelineLayout( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout) +{ + VkResult result; + Device* vkDevice = (Device*)device; + PipelineLayout* layout = nullptr; + + layout = palAllocate(s_Vk.allocator, sizeof(PipelineLayout), 0); + if (!layout) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkPipelineLayoutCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + + result = s_Vk.createPipelineLayout( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &layout->handle); + + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + layout->device = vkDevice; + *outLayout = (PalPipelineLayout*)layout; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkPipelineLayout(PalPipelineLayout* layout) +{ + PipelineLayout* pipelineLayout = (PipelineLayout*)layout; + s_Vk.destroyPipelineLayout( + pipelineLayout->device->handle, + pipelineLayout->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, layout); +} + PalResult PAL_CALL createVkGraphicsPipeline( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, @@ -6002,6 +5972,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( Pipeline* pipeline = nullptr; Device* vkDevice = (Device*)device; RenderPass* renderPass = (RenderPass*)info->renderPass; + PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; VkPipelineShaderStageCreateInfo shaderStages[7]; // PAL supports 7 types VkDynamicState dynamicStates[16]; @@ -6010,7 +5981,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( VkPipelineColorBlendAttachmentState* blendattachments = nullptr; VkPipelineVertexInputStateCreateInfo VI = {0}; - VI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + VI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; VkPipelineInputAssemblyStateCreateInfo IA = {0}; IA.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; @@ -6033,6 +6004,13 @@ PalResult PAL_CALL createVkGraphicsPipeline( VkPipelineTessellationStateCreateInfo TS = {0}; TS.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + VkPipelineViewportStateCreateInfo VS = {0}; + VS.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + + VkPipelineFragmentShadingRateStateCreateInfoKHR FSRS = {0}; + FSRS.sType = + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; + VkGraphicsPipelineCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -6042,6 +6020,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( } // shaders + memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo)); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; shaderStages[i] = tmp->info; @@ -6049,6 +6028,11 @@ PalResult PAL_CALL createVkGraphicsPipeline( if (tmp->patchControlPoints) { TS.patchControlPoints = tmp->patchControlPoints; createInfo.pTessellationState = &TS; + + if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { + palFree(s_Vk.allocator, pipeline); + return PAL_RESULT_INVALID_OPERATION; + } } } @@ -6078,6 +6062,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( for (int i = 0; i < info->vertexLayoutCount; i++) { PalVertexLayout* layout = &info->vertexLayouts[i]; VkVertexInputBindingDescription* bindingDesc = &bindingDescs[i]; + bindingDesc->binding = layout->binding; if (layout->type == PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE) { bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; @@ -6090,15 +6075,15 @@ PalResult PAL_CALL createVkGraphicsPipeline( Uint32 offset = 0; for (int j = 0; j < layout->vertexCount; j++) { PalVertexAttribute* vertexAttrib = &layout->vertices[j]; - VkVertexInputAttributeDescription* attrib = &attribDescs[j]; + VkVertexInputAttributeDescription* attribDesc = &attribDescs[j]; - attrib->format = vertexTypeToVkFormat(vertexAttrib->type); - attrib->binding = bindingDesc->binding; - attrib->location = attrib->location; + attribDesc->format = vertexTypeToVkFormat(vertexAttrib->type); + attribDesc->binding = bindingDesc->binding; + attribDesc->location = vertexAttrib->location; // build offsets and stride Uint32 size = getVertexTypeSize(vertexAttrib->type); - attrib->offset = offset; + attribDesc->offset = offset; offset += size; bindingDesc->stride += size; } @@ -6139,6 +6124,9 @@ PalResult PAL_CALL createVkGraphicsPipeline( } } + IA.topology = topology; + IA.primitiveRestartEnable = VK_FALSE; + // Dynamic states Uint32 dynCount = 0; dynamicStates[dynCount++] = VK_DYNAMIC_STATE_VIEWPORT; @@ -6172,11 +6160,16 @@ PalResult PAL_CALL createVkGraphicsPipeline( dynamicStates[dynCount++] = VK_DYNAMIC_STATE_STENCIL_OP_EXT; } + if (info->fragmentShadingRateEnabled) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR; + } + DS.dynamicStateCount = dynCount; DS.pDynamicStates = dynamicStates; createInfo.pDynamicState = &DS; // Rasterizer state + RS.lineWidth = 1.0f; if (info->rasterizerState.cullMode == PAL_CULL_MODE_NONE) { RS.cullMode = VK_CULL_MODE_NONE; } else if (info->rasterizerState.cullMode == PAL_CULL_MODE_BACK) { @@ -6186,15 +6179,15 @@ PalResult PAL_CALL createVkGraphicsPipeline( } if (info->rasterizerState.polygonMode == PAL_POLYGON_MODE_FILL) { - RS.cullMode = VK_POLYGON_MODE_FILL; + RS.polygonMode = VK_POLYGON_MODE_FILL; } else { - RS.cullMode = VK_POLYGON_MODE_LINE; + RS.polygonMode = VK_POLYGON_MODE_LINE; } if (info->rasterizerState.frontFace == PAL_FRONT_FACE_CLOCKWISE) { - RS.cullMode = VK_FRONT_FACE_CLOCKWISE; + RS.frontFace = VK_FRONT_FACE_CLOCKWISE; } else { - RS.cullMode = VK_FRONT_FACE_COUNTER_CLOCKWISE; + RS.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; } RS.depthBiasEnable = info->rasterizerState.enableDepthBias; @@ -6287,8 +6280,12 @@ PalResult PAL_CALL createVkGraphicsPipeline( } } } + CBS.pAttachments = blendattachments; + + // viewport state + VS.viewportCount = 1; + VS.scissorCount = 1; - createInfo.layout = nullptr; createInfo.stageCount = info->shaderCount; createInfo.pStages = shaderStages; createInfo.pVertexInputState = &VI; @@ -6298,9 +6295,28 @@ PalResult PAL_CALL createVkGraphicsPipeline( createInfo.pRasterizationState = &RS; createInfo.pMultisampleState = &MS; createInfo.pColorBlendState = &CBS; + createInfo.pViewportState = &VS; createInfo.renderPass = renderPass->handle; + createInfo.layout = layout->handle; + + if (info->fragmentShadingRateEnabled) { + FSRS.combinerOps[0] = + combinerOpsToVk(info->fragmentShadingRateState.combinerOps[0]); + FSRS.combinerOps[1] = + combinerOpsToVk(info->fragmentShadingRateState.combinerOps[1]); + FSRS.fragmentSize = + getShadingRateSize(info->fragmentShadingRateState.rate); - // TODO: Fragment shading rate + createInfo.pNext = &FSRS; + } + + result = s_Vk.createGraphicsPipeline( + vkDevice->handle, + 0, + 1, + &createInfo, + &s_Vk.vkAllocator, + &pipeline->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 55906904..d3fa4bae 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -5,25 +5,23 @@ #include -static bool readFile(const char* filename, char* buffer, Uint32* size) +static bool readFile(const char* filename, void* buffer, Uint64* size) { FILE* file = fopen(filename, "rb"); if (!file) { return false; } - if (!buffer) { - fseek(file, 0, SEEK_END); - Uint64 tmpSize = ftell(file); - fclose(file); + fseek(file, 0, SEEK_END); + Uint64 tmpSize = ftell(file); + fseek(file, 0, SEEK_SET); - *size = tmpSize; - return true; + if (buffer) { + fread(buffer, 1, (size_t)size, file); } - - fseek(file, 0, SEEK_SET); - fread(buffer, 1, (Uint64)size, file); + fclose(file); + *size = tmpSize; return true; } @@ -142,6 +140,7 @@ bool triangleTest() PalShader* vertexShader = nullptr; PalShader* fragmentShader = nullptr; + PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; // initialize the graphics system @@ -339,12 +338,12 @@ bool triangleTest() } // create shaders - Uint32 vertexShaderSize = 0; - Uint32 fragmentShaderSize = 0; - char* vertexShaderBytecode = nullptr; - char* fragmentShaderBytecode = nullptr; + Uint64 vertexShaderSize = 0; + Uint64 fragmentShaderSize = 0; + void* vertexShaderBytecode = nullptr; + void* fragmentShaderBytecode = nullptr; readFile("shaders/triangle.vertex.spv", nullptr, &vertexShaderSize); - readFile("shaders/triangle.fragment.spv", nullptr, &vertexShaderSize); + readFile("shaders/triangle.fragment.spv", nullptr, &fragmentShaderSize); if (!vertexShaderSize && !fragmentShaderSize) { palLog(nullptr, "Failed to find shader files"); @@ -360,16 +359,16 @@ bool triangleTest() readFile( "shaders/triangle.vertex.spv", - vertexShaderBytecode, + vertexShaderBytecode, &vertexShaderSize); readFile( "shaders/triangle.fragment.spv", fragmentShaderBytecode, - &vertexShaderSize); + &fragmentShaderSize); PalShaderCreateInfo shaderCreateInfo = {0}; - shaderCreateInfo.bytecode = (const void*)vertexShaderBytecode; + shaderCreateInfo.bytecode = vertexShaderBytecode; shaderCreateInfo.bytecodeSize = vertexShaderSize; shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; result = palCreateShader(device, &shaderCreateInfo, &vertexShader); @@ -379,10 +378,10 @@ bool triangleTest() return false; } - shaderCreateInfo.bytecode = (const void*)fragmentShaderBytecode; + shaderCreateInfo.bytecode = fragmentShaderBytecode; shaderCreateInfo.bytecodeSize = fragmentShaderSize; shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; - result = palCreateShader(device, &shaderCreateInfo, &vertexShader); + result = palCreateShader(device, &shaderCreateInfo, &fragmentShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fragment shader: %s", error); @@ -424,8 +423,22 @@ bool triangleTest() pipelineCreateInfo.shaders = shaders; pipelineCreateInfo.shaderCount = 2; + // pipeline layput + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + result = palCreatePipelineLayout( + device, + &pipelineLayoutCreateInfo, + &pipelineLayout); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline layout: %s", error); + return false; + } + pipelineCreateInfo.renderPass = renderPass; - // result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); + pipelineCreateInfo.pipelineLayout = pipelineLayout; + result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline: %s", error); @@ -628,6 +641,7 @@ bool triangleTest() } palDestroyPipeline(pipeline); + palDestroyPipelineLayout(pipelineLayout); palDestroyRenderPass(renderPass); palDestroyCommandPool(cmdPool); palDestroySwapchain(swapchain); From 48972f9c978187fa1f83cee79fcab76cc8dbca45 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 4 Jan 2026 17:12:32 +0000 Subject: [PATCH 071/372] start dynamic rendering constraint --- include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 201 +++++++++-- pal_config.lua | 2 +- src/graphics/pal_graphics.c | 280 +++++++++++++-- src/graphics/pal_vulkan.c | 525 +++++++++++++++++++++++++--- src/pal_core.c | 3 + tests/clear_color_test.c | 2 +- tests/graphics_test.c | 6 +- tests/shaders/triangle.fragment.spv | Bin 564 -> 0 bytes tests/shaders/triangle.vertex.spv | Bin 1076 -> 0 bytes tests/shaders/triangle_frag.spv | Bin 0 -> 416 bytes tests/shaders/triangle_vert.spv | Bin 0 -> 1020 bytes tests/triangle_test.c | 256 ++++++++++++-- 13 files changed, 1163 insertions(+), 115 deletions(-) delete mode 100644 tests/shaders/triangle.fragment.spv delete mode 100644 tests/shaders/triangle.vertex.spv create mode 100644 tests/shaders/triangle_frag.spv create mode 100644 tests/shaders/triangle_vert.spv diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index b997c66b..3775938a 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -268,7 +268,8 @@ typedef enum { PAL_RESULT_INVALID_SEMAPHORE, PAL_RESULT_INVALID_RENDER_PASS, PAL_RESULT_INVALID_BUFFER, - PAL_RESULT_INVALID_ACCELERATION_STRUCTURE + PAL_RESULT_INVALID_ACCELERATION_STRUCTURE, + PAL_RESULT_MEMORY_MAP_FAILED } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 69593f88..4ff099ec 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -61,6 +61,12 @@ typedef struct PalPipeline PalPipeline; typedef struct PalPipelineLayout PalPipelineLayout; typedef struct PalAccelerationStructure PalAccelerationStructure; +typedef void(PAL_CALL* PalDebugCallback)( + void* userData, + Uint32 severity, + Uint32 type, + const char* msg); + typedef enum { PAL_ADAPTER_TYPE_UNKNOWN, PAL_ADAPTER_TYPE_DISCRETE, @@ -250,7 +256,8 @@ typedef enum { PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(30), PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(31), PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT = PAL_BIT64(32), - PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(33) + PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(33), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(34) } PalAdapterFeatures; typedef enum { @@ -514,6 +521,18 @@ typedef enum { PAL_BUFFER_USAGE_DEVICE_ADDRESS = PAL_BIT(7) } PalBufferUsages; +typedef enum { + PAL_DEBUG_MESSAGE_SEVERITY_INFO, + PAL_DEBUG_MESSAGE_SEVERITY_WARNING, + PAL_DEBUG_MESSAGE_SEVERITY_ERROR +} PalDebugMessageSeverity; + +typedef enum { + PAL_DEBUG_MESSAGE_TYPE_GENERAL, + PAL_DEBUG_MESSAGE_TYPE_VALIDATION, + PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE +} PalDebugMessageType; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -688,6 +707,37 @@ typedef struct { PalClearValue* clearValues; } PalRenderPassBeginInfo; +typedef struct { + float x; + float y; + float width; + float height; + float minDepth; + float maxDepth; +} PalViewport; + +typedef struct { + Int32 x; + Int32 y; + Uint32 width; + Uint32 height; +} PalScissor; + +typedef struct { + Uint32 vertexCount; + Uint32 instancecCount; + Uint32 firstVertex; + Uint32 firstInstance; +} PalDrawData; + +typedef struct { + Uint32 indexCount; + Uint32 instancecCount; + Uint32 firstIndex; + Int32 vertexOffset; + Uint32 firstInstance; +} PalDrawIndexedData; + typedef struct { PalVertexType type; Uint32 location; @@ -696,10 +746,15 @@ typedef struct { typedef struct { PalVertexLayoutType type; Uint32 binding; - Uint32 vertexCount; - PalVertexAttribute* vertices; + Uint32 attributeCount; + PalVertexAttribute* attributes; } PalVertexLayout; +typedef struct { + void* userData; + PalDebugCallback callback; +} PalGraphicsDebugger; + typedef struct { bool enableDepthClamp; bool enableDepthBias; @@ -920,6 +975,17 @@ typedef struct { PalDevice* device, PalMemory* memory); + PalResult PAL_CALL (*mapMemory)( + PalDevice* device, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr); + + void PAL_CALL (*unmapMemory)( + PalDevice* device, + PalMemory* memory); + PalResult PAL_CALL (*queryDepthStencilCapabilities)( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -1146,6 +1212,53 @@ typedef struct { Uint64 srcOffset, Uint32 size); + PalResult PAL_CALL (*bindPipeline)( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline); + + PalResult PAL_CALL (*setViewport)( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalViewport* viewports); + + PalResult PAL_CALL (*setScissors)( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalScissor* scissors); + + PalResult PAL_CALL (*bindVertexBuffers)( + PalCommandBuffer* cmdBuffer, + Uint32 firstSlot, + Uint32 count, + PalBuffer** buffers, + Uint64* offsets); + + PalResult PAL_CALL (*bindIndexBuffer)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + PalIndexType type); + + PalResult PAL_CALL (*draw)( + PalCommandBuffer* cmdBuffer, + PalDrawData* data); + + PalResult PAL_CALL (*drawIndirect)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count); + + PalResult PAL_CALL (*drawIndexed)( + PalCommandBuffer* cmdBuffer, + PalDrawIndexedData* data); + + PalResult PAL_CALL (*drawIndexedIndirect)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count); + PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, PalSubmitInfo* info); @@ -1179,17 +1292,6 @@ typedef struct { PalMemory* memory, Uint64 offset); - PalResult PAL_CALL (*mapBuffer)( - PalBuffer* buffer, - PalMemory* memory, - Uint64 offset, - Uint64 size, - void** outPtr); - - void PAL_CALL (*unmapBuffer)( - PalBuffer* buffer, - PalMemory* memory); - PalResult PAL_CALL (*createPipelineLayout)( PalDevice* device, const PalPipelineLayoutCreateInfo* info, @@ -1209,7 +1311,7 @@ PAL_API PalResult PAL_CALL palAddGraphicsBackend( const PalGraphicsBackend* backend); PAL_API PalResult PAL_CALL palInitGraphics( - bool enableDebugLayer, + PalGraphicsDebugger* debugger, const PalAllocator* allocator); PAL_API void PAL_CALL palShutdownGraphics(); @@ -1245,6 +1347,17 @@ PAL_API void PAL_CALL palFreeMemory( PalDevice* device, PalMemory* memory); +PAL_API PalResult PAL_CALL palMapMemory( + PalDevice* device, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr); + +PAL_API void PAL_CALL palUnmapMemory( + PalDevice* device, + PalMemory* memory); + PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -1471,6 +1584,53 @@ PAL_API PalResult PAL_CALL palCopyBuffer( Uint64 srcOffset, Uint32 size); +PAL_API PalResult PAL_CALL palBindPipeline( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline); + +PAL_API PalResult PAL_CALL palSetViewport( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalViewport* viewports); + +PAL_API PalResult PAL_CALL palSetScissors( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalScissor* scissors); + +PAL_API PalResult PAL_CALL palBindVertexBuffers( + PalCommandBuffer* cmdBuffer, + Uint32 firstSlot, + Uint32 count, + PalBuffer** buffers, + Uint64* offsets); + +PAL_API PalResult PAL_CALL palBindIndexBuffer( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + PalIndexType type); + +PAL_API PalResult PAL_CALL palDraw( + PalCommandBuffer* cmdBuffer, + PalDrawData* data); + +PAL_API PalResult PAL_CALL palDrawIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count); + +PAL_API PalResult PAL_CALL palDrawIndexed( + PalCommandBuffer* cmdBuffer, + PalDrawIndexedData* data); + +PAL_API PalResult PAL_CALL palDrawIndexedIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count); + PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalSubmitInfo* info); @@ -1504,17 +1664,6 @@ PAL_API PalResult PAL_CALL palBindBufferMemory( PalMemory* memory, Uint64 offset); -PAL_API PalResult PAL_CALL palMapBuffer( - PalBuffer* buffer, - PalMemory* memory, - Uint64 offset, - Uint64 size, - void** outPtr); - -PAL_API void PAL_CALL palUnmapBuffer( - PalBuffer* buffer, - PalMemory* memory); - PAL_API PalResult PAL_CALL palCreatePipelineLayout( PalDevice* device, const PalPipelineLayoutCreateInfo* info, diff --git a/pal_config.lua b/pal_config.lua index 14259d5a..25277c5a 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -1,6 +1,6 @@ -- build PAL as a static library -PAL_BUILD_STATIC = false +PAL_BUILD_STATIC = true -- build PAL tests as a single application PAL_BUILD_TESTS = true diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index ea0cee2e..4c023910 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -80,7 +80,7 @@ static GraphicsLinux s_Graphics = {0}; #if PAL_HAS_VULKAN PalResult PAL_CALL initGraphicsVk( - bool enableDebugLayer, + PalGraphicsDebugger* debugger, const PalAllocator* allocator); PalResult PAL_CALL shutdownGraphicsVk(); @@ -342,6 +342,53 @@ PalResult PAL_CALL copyVkBuffer( Uint64 srcOffset, Uint32 size); +PalResult PAL_CALL bindVkPipeline( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline); + +PalResult PAL_CALL setVkViewport( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalViewport* viewports); + +PalResult PAL_CALL setVkScissors( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalScissor* scissors); + +PalResult PAL_CALL bindVkVertexBuffers( + PalCommandBuffer* cmdBuffer, + Uint32 firstSlot, + Uint32 count, + PalBuffer** buffers, + Uint64* offsets); + +PalResult PAL_CALL bindVkIndexBuffer( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + PalIndexType type); + +PalResult PAL_CALL drawVk( + PalCommandBuffer* cmdBuffer, + PalDrawData* data); + +PalResult PAL_CALL drawIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count); + +PalResult PAL_CALL drawIndexedVk( + PalCommandBuffer* cmdBuffer, + PalDrawIndexedData* data); + +PalResult PAL_CALL drawIndexedIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count); + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalSubmitInfo* info); @@ -375,15 +422,15 @@ PalResult PAL_CALL bindVkBufferMemory( PalMemory* memory, Uint64 offset); -PalResult PAL_CALL mapVkBuffer( - PalBuffer* buffer, +PalResult PAL_CALL mapVkMemory( + PalDevice* device, PalMemory* memory, Uint64 offset, Uint64 size, void** outPtr); -void PAL_CALL unmapVkBuffer( - PalBuffer* buffer, +void PAL_CALL unmapVkMemory( + PalDevice* device, PalMemory* memory); PalResult PAL_CALL createVkPipelineLayout( @@ -409,6 +456,8 @@ static PalGraphicsBackend s_VkBackend = { .destroyDevice = destroyVkDevice, .allocateMemory = allocateVkMemory, .freeMemory = freeVkMemory, + .mapMemory = mapVkMemory, + .unmapMemory = unmapVkMemory, .queryDepthStencilCapabilities = queryVkDepthStencilCapabilities, .queryFragmentShadingRateCapabilities = queryVkFragmentShadingRateCapabilities, .queryMeshShaderCapabilities = queryVkMeshShaderCapabilities, @@ -465,6 +514,15 @@ static PalGraphicsBackend s_VkBackend = { .beginRenderPass = beginRenderPassVk, .endRenderPass = endRenderPassVk, .copyBuffer = copyVkBuffer, + .bindPipeline = bindVkPipeline, + .setViewport = setVkViewport, + .setScissors = setVkScissors, + .bindVertexBuffers = bindVkVertexBuffers, + .bindIndexBuffer = bindVkIndexBuffer, + .draw = drawVk, + .drawIndirect = drawIndirectVk, + .drawIndexed = drawIndexedVk, + .drawIndexedIndirect = drawIndexedIndirectVk, .submitCommandBuffer = submitVkCommandBuffer, .createAccelerationstructure = createVkAccelerationstructure, .destroyAccelerationstructure = destroyVkAccelerationstructure, @@ -473,8 +531,6 @@ static PalGraphicsBackend s_VkBackend = { .destroyBuffer = destroyVkBuffer, .getBufferMemoryRequirements = getVkBufferMemoryRequirements, .bindBufferMemory = bindVkBufferMemory, - .mapBuffer = mapVkBuffer, - .unmapBuffer = unmapVkBuffer, .createPipelineLayout = createVkPipelineLayout, .destroyPipelineLayout = destroyVkPipelineLayout, .createGraphicsPipeline = createVkGraphicsPipeline, @@ -579,6 +635,15 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->beginRenderPass || !backend->endRenderPass || !backend->copyBuffer || + !backend->bindPipeline || + !backend->setViewport || + !backend->setScissors || + !backend->bindVertexBuffers || + !backend->bindIndexBuffer || + !backend->draw || + !backend->drawIndirect || + !backend->drawIndexed || + !backend->drawIndexedIndirect || !backend->submitCommandBuffer || !backend->createAccelerationstructure || !backend->destroyAccelerationstructure || @@ -587,8 +652,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroyBuffer || !backend->getBufferMemoryRequirements || !backend->bindBufferMemory || - !backend->mapBuffer || - !backend->unmapBuffer || + !backend->mapMemory || + !backend->unmapMemory || !backend->createPipelineLayout || !backend->destroyPipelineLayout || !backend->createGraphicsPipeline || @@ -606,7 +671,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) } PalResult PAL_CALL palInitGraphics( - bool enableDebugLayer, + PalGraphicsDebugger* debugger, const PalAllocator* allocator) { if (s_Graphics.initialized) { @@ -622,7 +687,7 @@ PalResult PAL_CALL palInitGraphics( #elif defined(__linux__) // vulkan #if PAL_HAS_VULKAN - initGraphicsVk(enableDebugLayer, allocator); + initGraphicsVk(debugger, allocator); BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; attached->base = &s_VkBackend; attached->startIndex = 0; @@ -1820,6 +1885,181 @@ PalResult PAL_CALL palCopyBuffer( size); } +PalResult PAL_CALL palBindPipeline( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !pipeline) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->bindPipeline( + cmdBuffer, + pipeline); +} + +PalResult PAL_CALL palSetViewport( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalViewport* viewports) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !viewports || !count) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->setViewport( + cmdBuffer, + count, + viewports); +} + +PalResult PAL_CALL palSetScissors( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalScissor* scissors) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !scissors || !count) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->setScissors( + cmdBuffer, + count, + scissors); +} + +PalResult PAL_CALL palBindVertexBuffers( + PalCommandBuffer* cmdBuffer, + Uint32 firstSlot, + Uint32 count, + PalBuffer** buffers, + Uint64* offsets) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffers || !offsets) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->bindVertexBuffers( + cmdBuffer, + firstSlot, + count, + buffers, + offsets); +} + +PalResult PAL_CALL palBindIndexBuffer( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + PalIndexType type) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->bindIndexBuffer( + cmdBuffer, + buffer, + offset, + type); +} + +PalResult PAL_CALL palDraw( + PalCommandBuffer* cmdBuffer, + PalDrawData* data) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !data) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->draw( + cmdBuffer, + data); +} + +PalResult PAL_CALL palDrawIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->drawIndirect( + cmdBuffer, + buffer, + offset, + count); +} + +PalResult PAL_CALL palDrawIndexed( + PalCommandBuffer* cmdBuffer, + PalDrawIndexedData* data) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !data) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->drawIndexed( + cmdBuffer, + data); +} + +PalResult PAL_CALL palDrawIndexedIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->drawIndexedIndirect( + cmdBuffer, + buffer, + offset, + count); +} + PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalSubmitInfo* info) @@ -1981,8 +2221,8 @@ PalResult PAL_CALL palBindBufferMemory( offset); } -PalResult PAL_CALL palMapBuffer( - PalBuffer* buffer, +PalResult PAL_CALL palMapMemory( + PalDevice* device, PalMemory* memory, Uint64 offset, Uint64 size, @@ -1992,26 +2232,26 @@ PalResult PAL_CALL palMapBuffer( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!buffer || !memory || !outPtr) { + if (!device || !memory || !outPtr) { return PAL_RESULT_NULL_POINTER; } - return buffer->backend->mapBuffer( - buffer, + return device->backend->mapMemory( + device, memory, offset, size, outPtr); } -void PAL_CALL palUnmapBuffer( - PalBuffer* buffer, +void PAL_CALL palUnmapMemory( + PalDevice* device, PalMemory* memory) { - if (!s_Graphics.initialized || !buffer || !memory) { + if (!s_Graphics.initialized || !device || !memory) { return; } - buffer->backend->unmapBuffer(buffer, memory); + device->backend->unmapMemory(device, memory); } // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 4ff01bc4..2eabdf90 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -79,6 +79,8 @@ typedef struct { void* handle; Adapter* adapters; VkInstance instance; + VkDebugUtilsMessengerEXT messenger; + PalDebugCallback callback; #ifdef __linux__ // HACK: for display testing @@ -140,6 +142,15 @@ typedef struct { PFN_vkCmdBeginRenderPass cmdBeginRenderPass; PFN_vkCmdEndRenderPass cmdEndRenderPass; PFN_vkCmdCopyBuffer cmdCopyBuffer; + PFN_vkCmdBindPipeline cmdBindPipeline; + PFN_vkCmdSetViewport cmdSetViewports; + PFN_vkCmdSetScissor cmdSetScissors; + PFN_vkCmdBindVertexBuffers bindVertexBuffers; + PFN_vkCmdBindIndexBuffer bindIndexBuffer; + PFN_vkCmdDraw cmdDraw; + PFN_vkCmdDrawIndirect cmdDrawIndirect; + PFN_vkCmdDrawIndexed cmdDrawIndexed; + PFN_vkCmdDrawIndexedIndirect cmdDrawIndexedIndirect; PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; @@ -162,6 +173,8 @@ typedef struct { PFN_vkDestroyPipelineLayout destroyPipelineLayout; PFN_vkCreateGraphicsPipelines createGraphicsPipeline; PFN_vkDestroyPipeline destroyPipeline; + PFN_vkCreateDebugUtilsMessengerEXT createMessenger; + PFN_vkDestroyDebugUtilsMessengerEXT destroyMessenger; VkAllocationCallbacks vkAllocator; const PalAllocator* allocator; @@ -450,6 +463,9 @@ static PalResult vkResultToPal(VkResult result) case VK_TIMEOUT: return PAL_RESULT_TIMEOUT; + case VK_ERROR_MEMORY_MAP_FAILED: + return PAL_RESULT_MEMORY_MAP_FAILED; + default: return PAL_RESULT_PLATFORM_FAILURE; } @@ -1524,12 +1540,81 @@ static void* vkRealloc( return nullptr; } +VkBool32 debugCallback( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagBitsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT* data, + void* userData) +{ + if (!s_Vk.callback) { + return VK_FALSE; + } + + PalDebugMessageSeverity debugSeverity = 0; + PalDebugMessageType debugType = 0; + if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) { + debugType = PAL_DEBUG_MESSAGE_TYPE_GENERAL; + } + + if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) { + debugType = PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE; + } + + if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) { + debugType = PAL_DEBUG_MESSAGE_TYPE_VALIDATION; + } + + if (type & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { + debugSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; + } + + if (type & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + debugSeverity = PAL_DEBUG_MESSAGE_SEVERITY_WARNING; + } + + if (type & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + debugSeverity = PAL_DEBUG_MESSAGE_SEVERITY_ERROR; + } + + s_Vk.callback(userData, debugSeverity, debugType, data->pMessage); + return VK_FALSE; +} + +static Uint32 getMemoryTypeScore( + VkMemoryPropertyFlags flags, + VkMemoryPropertyFlags required, + VkMemoryPropertyFlags preferred, + VkMemoryPropertyFlags excluded) +{ + // hard constraint + if ((flags & required) != required) { + return 0; + } + + // hard constraint + if ((flags & excluded) != 0) { + return 0; + } + + int score = 0; + if (flags & preferred) { + score += 10; + } + + // GPU memory is general preferred + if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + score += 5; + } + + return score; +} + // ================================================== // Adapter // ================================================== PalResult PAL_CALL initGraphicsVk( - bool enableDebugLayer, + PalGraphicsDebugger* debugger, const PalAllocator* allocator) { s_Vk.libWayland = nullptr; @@ -1747,6 +1832,42 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCmdCopyBuffer"); + s_Vk.cmdBindPipeline = (PFN_vkCmdBindPipeline)dlsym( + s_Vk.handle, + "vkCmdBindPipeline"); + + s_Vk.cmdSetViewports = (PFN_vkCmdSetViewport)dlsym( + s_Vk.handle, + "vkCmdSetViewport"); + + s_Vk.cmdSetScissors = (PFN_vkCmdSetScissor)dlsym( + s_Vk.handle, + "vkCmdSetScissor"); + + s_Vk.bindVertexBuffers = (PFN_vkCmdBindVertexBuffers)dlsym( + s_Vk.handle, + "vkCmdBindVertexBuffers"); + + s_Vk.bindIndexBuffer = (PFN_vkCmdBindIndexBuffer)dlsym( + s_Vk.handle, + "vkCmdBindIndexBuffer"); + + s_Vk.cmdDraw = (PFN_vkCmdDraw)dlsym( + s_Vk.handle, + "vkCmdDraw"); + + s_Vk.cmdDrawIndirect = (PFN_vkCmdDrawIndirect)dlsym( + s_Vk.handle, + "vkCmdDrawIndirect"); + + s_Vk.cmdDrawIndexed = (PFN_vkCmdDrawIndexed)dlsym( + s_Vk.handle, + "vkCmdDrawIndexed"); + + s_Vk.cmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)dlsym( + s_Vk.handle, + "vkCmdDrawIndexedIndirect"); + s_Vk.queueSubmit = (PFN_vkQueueSubmit)dlsym( s_Vk.handle, "vkQueueSubmit"); @@ -1806,7 +1927,12 @@ PalResult PAL_CALL initGraphicsVk( VkResult ret; Uint32 layerCount = 0; bool hasValidationLayer = false; - if (enableDebugLayer) { + s_Vk.messenger = nullptr; + VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {0}; + debugCreateInfo.sType = + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + + if (debugger) { // layers ret = s_Vk.enumerateInstanceLayerProperties( &layerCount, @@ -1836,6 +1962,24 @@ PalResult PAL_CALL initGraphicsVk( } palFree(s_Vk.allocator, props); + + debugCreateInfo.messageType |= + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + debugCreateInfo.messageType |= + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + debugCreateInfo.messageType |= + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + + debugCreateInfo.messageSeverity |= + VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + debugCreateInfo.messageSeverity |= + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + debugCreateInfo.messageSeverity |= + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + + debugCreateInfo.pUserData = debugger->userData; + debugCreateInfo.pfnUserCallback = debugCallback; + s_Vk.callback = debugger->callback; } // extensions @@ -1930,6 +2074,10 @@ PalResult PAL_CALL initGraphicsVk( instanceCreateInfo.ppEnabledExtensionNames = extensions; instanceCreateInfo.ppEnabledLayerNames = layers; + if (debugger) { + instanceCreateInfo.pNext = &debugCreateInfo; + } + // vk allocator s_Vk.vkAllocator.pfnAllocation = vkAlloc; s_Vk.vkAllocator.pfnFree = vkFree; @@ -1998,6 +2146,21 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.getSurfaceFormats = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)s_Vk.getInstanceProcAddr( instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"); + + if (debugger) { + s_Vk.createMessenger = + (PFN_vkCreateDebugUtilsMessengerEXT)s_Vk.getInstanceProcAddr( + instance, + "vkCreateDebugUtilsMessengerEXT"); + + s_Vk.destroyMessenger = + (PFN_vkDestroyDebugUtilsMessengerEXT)s_Vk.getInstanceProcAddr( + instance, + "vkDestroyDebugUtilsMessengerEXT"); + + s_Vk.createMessenger(instance, &debugCreateInfo, &s_Vk.vkAllocator, &s_Vk.messenger); + } + // clang-format on s_Vk.adapters = nullptr; @@ -2007,6 +2170,13 @@ PalResult PAL_CALL initGraphicsVk( PalResult PAL_CALL shutdownGraphicsVk() { + if (s_Vk.messenger) { + s_Vk.destroyMessenger( + s_Vk.instance, + s_Vk.messenger, + &s_Vk.vkAllocator); + } + s_Vk.destroyInstance(s_Vk.instance, &s_Vk.vkAllocator); dlclose(s_Vk.handle); if (s_Vk.libWayland) { @@ -2557,6 +2727,7 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_TIMEOUT; adapterFeatures |= PAL_ADAPTER_FEATURE_SEMAPHORE; + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; palFree(s_Vk.allocator, extensionProps); return adapterFeatures; @@ -2870,19 +3041,52 @@ PalResult PAL_CALL createVkDevice( // cache memory type indices VkPhysicalDeviceMemoryProperties memProps = {0}; s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); + device->gpuOnlyMemoryIndex = -1; + device->cpuUploadMemoryIndex = -1; + device->cpuReadbackMemoryIndex = -1; + + Uint32 gpuBestScore = 0; + Uint32 cpuUploadBestScore = 0; + Uint32 cpuReadbackBestScore = 0; + for (int i = 0; i < memProps.memoryTypeCount; i++) { - VkMemoryPropertyFlags prop = memProps.memoryTypes[i].propertyFlags; - if (prop & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + VkMemoryPropertyFlags flags = memProps.memoryTypes[i].propertyFlags; + Uint32 score = 0; + + // GPU memory + score = getMemoryTypeScore( + flags, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + + if (score > gpuBestScore) { + gpuBestScore = score; device->gpuOnlyMemoryIndex = i; } - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { + // CPU upload + score = getMemoryTypeScore( + flags, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + 0); + + if (score > cpuUploadBestScore) { + cpuUploadBestScore = score; device->cpuUploadMemoryIndex = i; } - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + // CPU readback + score = getMemoryTypeScore( + flags, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + 0, + 0); + + if (score > cpuReadbackBestScore) { + cpuReadbackBestScore = score; device->cpuReadbackMemoryIndex = i; } } @@ -4439,7 +4643,7 @@ PalResult PAL_CALL createVkRenderPass( ref->pNext = 0; ref->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; rDesc->finalLayout = layout; - } + } // subpass VkSubpassDescription2 subpassDesc = {0}; @@ -4488,7 +4692,6 @@ PalResult PAL_CALL createVkRenderPass( rDesc->format = palFormatToVk(desc->format); rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; rDesc->samples = samplesToVk(desc->sampleCount); - rDesc->flags = 0; // load op if (desc->loadOp == PAL_LOAD_OP_CLEAR) { @@ -4514,25 +4717,20 @@ PalResult PAL_CALL createVkRenderPass( rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; VkAttachmentReference* ref = nullptr; - VkImageAspectFlags aspectMask = 0; VkImageLayout layout, refLayout = 0; if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { ref = &colorRefs[colorRefCount++]; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } else if (desc->type == PAL_ATTACHMENT_TYPE_COLOR_RESOLVE) { ref = &resolveRefs[resolveRefCount++]; layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH) { ref = &depthRef; layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; refLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; hasDepth = true; // stencil is only used with depth attachment @@ -4557,13 +4755,11 @@ PalResult PAL_CALL createVkRenderPass( ref = &resolveRefs[resolveRefCount++]; layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; refLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; } else { ref = &colorRefs[colorRefCount++]; layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } ref->attachment = i; @@ -4571,6 +4767,14 @@ PalResult PAL_CALL createVkRenderPass( rDesc->finalLayout = layout; } + VkSubpassDependency dependency = {0}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependency.srcAccessMask = 0; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + // subpass legacy VkSubpassDescription subpassDesc = {0}; subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; @@ -4590,6 +4794,8 @@ PalResult PAL_CALL createVkRenderPass( createInfo.pAttachments = attachments; createInfo.subpassCount = 1; createInfo.pSubpasses = &subpassDesc; + createInfo.dependencyCount = 1; + createInfo.pDependencies = &dependency; if (info->multiViewCount > 1) { createInfo.pNext = &viewCreateInfo; @@ -4637,6 +4843,7 @@ PalResult PAL_CALL createVkRenderPassView( RenderPass* vkRenderPass = (RenderPass*)renderPass; VkImageView attachments[MAX_ATTACHMENTS]; + memset(attachments, 0, sizeof(VkImageView) * MAX_ATTACHMENTS); view = palAllocate(s_Vk.allocator, sizeof(RenderPassView), 0); if (!view) { return PAL_RESULT_OUT_OF_MEMORY; @@ -4660,26 +4867,29 @@ PalResult PAL_CALL createVkRenderPassView( } } - VkFramebufferCreateInfo fbCreateInfo = {0}; - fbCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fbCreateInfo.attachmentCount = info->imageViewCount; - fbCreateInfo.pAttachments = attachments; - fbCreateInfo.height = info->height; - fbCreateInfo.width = info->width; - fbCreateInfo.layers = layers; - fbCreateInfo.renderPass = vkRenderPass->handle; + if (info->width > width || info->height > height) { + palFree(s_Vk.allocator, view); + return PAL_RESULT_INVALID_ARGUMENT; + } + + VkFramebufferCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + createInfo.attachmentCount = info->imageViewCount; + createInfo.pAttachments = attachments; + createInfo.height = height; + createInfo.width = width; + createInfo.layers = layers; + createInfo.renderPass = vkRenderPass->handle; result = s_Vk.createFramebuffer( vkDevice->handle, - &fbCreateInfo, + &createInfo, &s_Vk.vkAllocator, &view->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, view); - // all image views in a single render pass must have the same - // width/height/layers - return PAL_RESULT_INVALID_ARGUMENT; + return vkResultToPal(result); } view->device = vkDevice; @@ -5407,6 +5617,7 @@ PalResult PAL_CALL beginRenderPassVk( VkRenderPassBeginInfo renderPassBeginInfo = {0}; renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; VkClearValue tmp[MAX_ATTACHMENTS]; + memset(tmp, 0, sizeof(VkClearValue) * MAX_ATTACHMENTS); for (int i = 0; i < info->clearValueCount; i++) { PalClearValue* clearValue = &info->clearValues[i]; @@ -5472,6 +5683,234 @@ PalResult PAL_CALL copyVkBuffer( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL bindVkPipeline( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Pipeline* vkPipeline = (Pipeline*)pipeline; + VkPipelineBindPoint bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + if (vkPipeline->type == COMPUTE_PIPELINE) { + bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; + + } else if (vkPipeline->type == RAY_TRACING_PIPELINE) { + bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; + } + + s_Vk.cmdBindPipeline(vkCmdBuffer->handle, bindPoint, vkPipeline->handle); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL setVkViewport( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalViewport* viewports) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + VkViewport cacheViewport; + VkViewport* vkViewports = nullptr; + + if (count > 1) { + vkViewports = palAllocate( + s_Vk.allocator, + sizeof(VkViewport) * count, + 0); + + if (!vkViewports) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + } else { + vkViewports = &cacheViewport; + } + + for (int i = 0; i < count; i++) { + VkViewport* tmp = &vkViewports[i]; + tmp->x = viewports[i].x; + tmp->y = viewports[i].y; + tmp->width = viewports[i].width; + tmp->height = viewports[i].height; + tmp->minDepth = viewports[i].minDepth; + tmp->maxDepth = viewports[i].maxDepth; + } + + s_Vk.cmdSetViewports(vkCmdBuffer->handle, 0, count, vkViewports); + if (count > 1) { + palFree(s_Vk.allocator, vkViewports); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL setVkScissors( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalScissor* scissors) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + VkRect2D cacheScissor; + VkRect2D* vkScissors = nullptr; + + if (count > 1) { + vkScissors = palAllocate( + s_Vk.allocator, + sizeof(VkRect2D) * count, + 0); + + if (!vkScissors) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + } else { + vkScissors = &cacheScissor; + } + + for (int i = 0; i < count; i++) { + VkRect2D* tmp = &vkScissors[i]; + tmp->offset.x = scissors[i].x; + tmp->offset.y = scissors[i].y; + tmp->extent.width = scissors[i].width; + tmp->extent.height = scissors[i].height; + } + + s_Vk.cmdSetScissors(vkCmdBuffer->handle, 0, count, vkScissors); + if (count > 1) { + palFree(s_Vk.allocator, vkScissors); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL bindVkVertexBuffers( + PalCommandBuffer* cmdBuffer, + Uint32 firstSlot, + Uint32 count, + PalBuffer** buffers, + Uint64* offsets) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + VkBuffer cachebuffer = nullptr; + VkBuffer* vkBuffers = nullptr; + + if (count > 1) { + vkBuffers = palAllocate(s_Vk.allocator, sizeof(VkBuffer) * count, 0); + if (!vkBuffers) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + } else { + vkBuffers = &cachebuffer; + } + + for (int i = 0; i < count; i++) { + Buffer* tmp = (Buffer*)buffers[i]; + vkBuffers[i] = tmp->handle; + } + + s_Vk.bindVertexBuffers( + vkCmdBuffer->handle, + firstSlot, + count, + vkBuffers, + offsets); + + if (count > 1) { + palFree(s_Vk.allocator, vkBuffers); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL bindVkIndexBuffer( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + PalIndexType type) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* vkBuffer = (Buffer*)buffer; + VkIndexType bufferType = VK_INDEX_TYPE_UINT32; + if (type == PAL_INDEX_TYPE_UINT16) { + bufferType = VK_INDEX_TYPE_UINT16; + } + + s_Vk.bindIndexBuffer( + vkCmdBuffer->handle, + vkBuffer->handle, + offset, + bufferType); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL drawVk( + PalCommandBuffer* cmdBuffer, + PalDrawData* data) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + s_Vk.cmdDraw( + vkCmdBuffer->handle, + data->vertexCount, + data->instancecCount, + data->firstVertex, + data->firstInstance); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL drawIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* vkBuffer = (Buffer*)buffer; + Uint32 stride = sizeof(VkDrawIndirectCommand); + + s_Vk.cmdDrawIndirect( + vkCmdBuffer->handle, + vkBuffer->handle, + offset, + count, + stride); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL drawIndexedVk( + PalCommandBuffer* cmdBuffer, + PalDrawIndexedData* data) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + s_Vk.cmdDrawIndexed( + vkCmdBuffer->handle, + data->indexCount, + data->instancecCount, + data->firstIndex, + data->vertexOffset, + data->firstInstance); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL drawIndexedIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* vkBuffer = (Buffer*)buffer; + Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); + + s_Vk.cmdDrawIndexedIndirect( + vkCmdBuffer->handle, + vkBuffer->handle, + offset, + count, + stride); + + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalSubmitInfo* info) @@ -5881,8 +6320,8 @@ PalResult PAL_CALL bindVkBufferMemory( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL mapVkBuffer( - PalBuffer* buffer, +PalResult PAL_CALL mapVkMemory( + PalDevice* device, PalMemory* memory, Uint64 offset, Uint64 size, @@ -5890,12 +6329,12 @@ PalResult PAL_CALL mapVkBuffer( { VkResult result; VkDeviceMemory mem = (VkDeviceMemory)memory; - Buffer* vkBuffer = (Buffer*)buffer; + Device* vkDevice = (Device*)device; result = s_Vk.mapMemory( - vkBuffer->device->handle, - mem, - offset, + vkDevice->handle, + mem, + offset, size, 0, outPtr); @@ -5906,13 +6345,13 @@ PalResult PAL_CALL mapVkBuffer( return PAL_RESULT_SUCCESS; } -void PAL_CALL unmapVkBuffer( - PalBuffer* buffer, +void PAL_CALL unmapVkMemory( + PalDevice* device, PalMemory* memory) { VkDeviceMemory mem = (VkDeviceMemory)memory; - Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.unmapMemory(vkBuffer->device->handle, mem); + Device* vkDevice = (Device*)device; + s_Vk.unmapMemory(vkDevice->handle, mem); } // ================================================== @@ -6041,7 +6480,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( Uint32 vertexCount = 0; for (int i = 0; i < info->vertexLayoutCount; i++) { PalVertexLayout* layout = &info->vertexLayouts[i]; - vertexCount += layout->vertexCount; + vertexCount += layout->attributeCount; } bindingDescs = palAllocate( @@ -6073,8 +6512,8 @@ PalResult PAL_CALL createVkGraphicsPipeline( // find the stride and offset of the layout bindingDesc->stride = 0; Uint32 offset = 0; - for (int j = 0; j < layout->vertexCount; j++) { - PalVertexAttribute* vertexAttrib = &layout->vertices[j]; + for (int j = 0; j < layout->attributeCount; j++) { + PalVertexAttribute* vertexAttrib = &layout->attributes[j]; VkVertexInputAttributeDescription* attribDesc = &attribDescs[j]; attribDesc->format = vertexTypeToVkFormat(vertexAttrib->type); @@ -6086,6 +6525,8 @@ PalResult PAL_CALL createVkGraphicsPipeline( attribDesc->offset = offset; offset += size; bindingDesc->stride += size; + + int a = 1; } } diff --git a/src/pal_core.c b/src/pal_core.c index 74cd1576..c37263eb 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -446,6 +446,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_ACCELERATION_STRUCTURE: return "Invalid acceleration structure"; + + case PAL_RESULT_MEMORY_MAP_FAILED: + return "Memory map failed"; } return "Unknown"; } diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 0ad59e21..f993a267 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -117,7 +117,7 @@ bool clearColorTest() PalRenderPassView** renderPassViews = nullptr; // initialize the graphics system - PalResult result = palInitGraphics(false, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index b5531b4a..e1256e94 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -11,7 +11,7 @@ bool graphicsTest() palLog(nullptr, ""); // initialize the graphics system - PalResult result = palInitGraphics(false, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -308,6 +308,10 @@ bool graphicsTest() palLog(nullptr, " Buffer device address"); } + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW) { + palLog(nullptr, " Indirect draw"); + } + palLog(nullptr, ""); } diff --git a/tests/shaders/triangle.fragment.spv b/tests/shaders/triangle.fragment.spv deleted file mode 100644 index 46630b0f36bb921ceb90618691b7f7f2325e2649..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 564 zcmYk2%}T>i5QWF4f426|g6^c^QYbD|1hFnevI$i20YXW#2*k9svEa^U^Qqhjo-f{( zT$s!~XU@!=8?ScJGCQ!Y^=xeaXJj=oCazg#KX?nKnSn^y|a46J2!W#WC2 z<`fPUM~b0z@LHgor>SP&YN}hu{2=t_b3b?vqtzDJ2oiSA8t6UC|YyamkO ziN0-R{s#QL!+3y0-%&;nM&DJ|FDQBRU_8KG3Zv~S%)TCP^#c5`i^Gf`F%9JhvCQr% r=zkSU@4#_Ndv54BcI*7ti^Yya@*fQ)HVc8TOv&6wL) z^nPjB6fh;5lWoejWo11j`EMPlm~j)RinY^|J69Q!n_6($TLOq_7=sxZ~#oa7^7ZjWG?1{B|HnZ(i?1;88rGG;VNz>Z&&T4-OVxcX%slr zdG0{pTV=CndGERW+wj%?^Eg8ux_lmcIOY`Ujh-zT3(WT!#ApFicU~%}xuc5IVZWr^ zuzXFntn>PD9H#!F@Th!E#@Z_|e+Tt8gvaGM54WWq+I$USSWS78@?QICftf2DeWqPr zUY9=Ls*HuM8F~7knR>JGXn?04m|4Jap4POi@_7aTS3r4+3zGIEJ= jKkjs?8r)}1#!Q*pxw?YMrzbjVGBgt7F5q7&K9T(a^`cc6 diff --git a/tests/shaders/triangle_frag.spv b/tests/shaders/triangle_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..2dd6180ca9800cb8824e89ae97397e801d756c91 GIT binary patch literal 416 zcmYk1&1wQc5QHncas64d8Uo2pRy-OchbTfI9&+&FEl(ii5>OWs@$9qtR9*tsH@h1g zsOhfi>YkoB8a1UGrE00C^4u%3B5O&A%hl&<^1J_$~yh)iZ84Bz#0cmz2*;|%FPdjpzob35OWfraLf#cPdM(tF;~J7!?CBXo2RLm17;pDb-=#Ea;B;& zsM%6Q>JZly<>Y-?U3z_Ri>bdUT#)x=oI{8Cs?=`?FUxZuuBnLGk{aYNU%D0fWcCY( z*()4(?kOCNAq#sSk~&7wK3Sp0o`q>l7lcN%mUd3smn>4S#eV7?<9Z?4HxAB?^( z&->ufgV`$_diIN+{h{BNCkKxn?91TJ^v%(+PYykP#dz{J`e&968N1-US5km^%cX8H t!?uk6_tMjM$8mBgx9d21Cc1{>=-+oc+EdJZ^yJwQJ=q7jKTUlu`v<@5J|h4C literal 0 HcmV?d00001 diff --git a/tests/triangle_test.c b/tests/triangle_test.c index d3fa4bae..e79607c2 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -107,6 +107,15 @@ static bool shutdownVideo( palDestroyEventDriver(eventDriver); } +static void PAL_CALL onGraphicsDebug( + void* userData, + Uint32 severity, + Uint32 type, + const char* msg) +{ + palLog(nullptr, msg); +} + bool triangleTest() { palLog(nullptr, ""); @@ -138,13 +147,19 @@ bool triangleTest() PalRenderPass* renderPass = nullptr; PalRenderPassView** renderPassViews = nullptr; + PalMemory* vertexbufferMemory = nullptr; + PalBuffer* vertexBuffer = nullptr; PalShader* vertexShader = nullptr; PalShader* fragmentShader = nullptr; PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; + PalFence** fences = nullptr; // initialize the graphics system - PalResult result = palInitGraphics(false, nullptr); + PalGraphicsDebugger gfxDebugger = {0}; + gfxDebugger.callback = onGraphicsDebug; + + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -203,9 +218,14 @@ bool triangleTest() } palFree(nullptr, adapters); + PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); // create a device PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + features |= PAL_ADAPTER_FEATURE_FENCE_RESET; + } + result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -306,11 +326,13 @@ bool triangleTest() sizeof(PalCommandBuffer*) * imageCount, 0); - if (!imageViews || !renderPassViews || !cmdBuffers) { + fences = palAllocate( + nullptr, + sizeof(PalFence*) * imageCount + 1, // next image fence + 0); + + if (!imageViews || !renderPassViews || !cmdBuffers || !fences) { palLog(nullptr, "Failed to allocate memory"); - palFree(nullptr, imageViews); - palFree(nullptr, cmdBuffers); - palFree(nullptr, renderPassViews); return false; } @@ -342,8 +364,8 @@ bool triangleTest() Uint64 fragmentShaderSize = 0; void* vertexShaderBytecode = nullptr; void* fragmentShaderBytecode = nullptr; - readFile("shaders/triangle.vertex.spv", nullptr, &vertexShaderSize); - readFile("shaders/triangle.fragment.spv", nullptr, &fragmentShaderSize); + readFile("shaders/triangle_vert.spv", nullptr, &vertexShaderSize); + readFile("shaders/triangle_frag.spv", nullptr, &fragmentShaderSize); if (!vertexShaderSize && !fragmentShaderSize) { palLog(nullptr, "Failed to find shader files"); @@ -358,12 +380,12 @@ bool triangleTest() } readFile( - "shaders/triangle.vertex.spv", + "shaders/triangle_vert.spv", vertexShaderBytecode, &vertexShaderSize); readFile( - "shaders/triangle.fragment.spv", + "shaders/triangle_frag.spv", fragmentShaderBytecode, &fragmentShaderSize); @@ -393,21 +415,21 @@ bool triangleTest() // create graphics pipeline // vertex attributes and vertex layout - PalVertexAttribute vertices[2]; + PalVertexAttribute attributes[2]; PalVertexLayout layout; - PalVertexAttribute* position = &vertices[0]; + PalVertexAttribute* position = &attributes[0]; position->location = 0; position->type = PAL_VERTEX_TYPE_FLOAT2; - PalVertexAttribute* color = &vertices[1]; + PalVertexAttribute* color = &attributes[1]; color->location = 1; color->type = PAL_VERTEX_TYPE_FLOAT3; // no alpha layout.binding = 0; layout.type = PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX; - layout.vertexCount = 2; - layout.vertices = vertices; + layout.attributeCount = 2; + layout.attributes = attributes; PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; pipelineCreateInfo.vertexLayouts = &layout; @@ -416,6 +438,17 @@ bool triangleTest() // Input assembly pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + // Color blend attachment + // we need one for each attachment in our render pass + PalBlendAttachment blendAttachment = {0}; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; + + pipelineCreateInfo.blendAttachmentCount = 1; + pipelineCreateInfo.blendAttachments = &blendAttachment; + // shaders PalShader* shaders[2]; // vertex and fragment shaders[0] = vertexShader; @@ -445,6 +478,88 @@ bool triangleTest() return false; } + // triangle vertices + // float 2 for pos and float 3 for color + float vertices[] = { + 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f + }; + + PalBufferCreateInfo bufferCreateInfo = {0}; + bufferCreateInfo.size = sizeof(vertices); + bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create buffer: %s", error); + return false; + } + + PalMemoryRequirements memReq = {0}; + result = palGetBufferMemoryRequirements(vertexBuffer, &memReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create buffer: %s", error); + return false; + } + + // check if the memory type is supported + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + memReq.size, + &vertexbufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate gpu memory: %s", error); + return false; + } + + result = palBindBufferMemory(vertexBuffer, vertexbufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind gpu memory: %s", error); + return false; + } + + // map the memory and fill with our vertices + void* data = nullptr; + result = palMapMemory( + device, + vertexbufferMemory, + 0, + sizeof(vertices), + &data); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map gpu memory: %s", error); + return false; + } + + memcpy(data, vertices, sizeof(vertices)); + palUnmapMemory(device, vertexbufferMemory); + + // viewport and scissor + PalViewport viewport = {0}; + viewport.width = (float)swapchainCreateInfo.width; + viewport.height = (float)swapchainCreateInfo.height; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + PalScissor scissor = {0}; + scissor.width = swapchainCreateInfo.width; + scissor.height = swapchainCreateInfo.height; + + result = palCreateFence(device, &fences[imageCount]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + for (int i = 0; i < imageCount; i++) { // get swapchain image PalImage* image = palGetSwapchainImage(swapchain, i); @@ -490,6 +605,15 @@ bool triangleTest() return false; } + // create fences + PalFence* fence = nullptr; + result = palCreateFence(device, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + // create a render pass view PalRenderPassView* renderPassView = nullptr; PalRenderPassViewCreateInfo renderPassViewCreateInfo = {0}; @@ -540,6 +664,47 @@ bool triangleTest() return false; } + // bind pipeline and set scissors and viewports + result = palBindPipeline(cmdBuffer, pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + result = palSetViewport(cmdBuffer, 1, &viewport); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set viewport: %s", error); + return false; + } + + result = palSetScissors(cmdBuffer, 1, &scissor); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set scissor: %s", error); + return false; + } + + Uint64 offset[] = { 0 }; + result = palBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, offset); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind vertex buffer: %s", error); + return false; + } + + PalDrawData drawData = {0}; + drawData.vertexCount = 3; + drawData.instancecCount = 1; + + result = palDraw(cmdBuffer, &drawData); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to draw vertices: %s", error); + return false; + } + result = palEndRenderPass(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -559,6 +724,7 @@ bool triangleTest() renderPassViews[i] = renderPassView; cmdBuffers[i] = cmdBuffer; imageViews[i] = imageView; + fences[i] = fence; } // main loop @@ -586,18 +752,53 @@ bool triangleTest() } } + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + for (int i = 0; i < imageCount + 1; i++) { + result = palResetFence(fences[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to reset fence: %s", error); + return false; + } + } + + } else { + for (int i = 0; i < imageCount + 1; i++) { + palDestroyFence(fences[i]); + + result = palCreateFence(device, &fences[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + } + } + // get the next image that we can render too PalImage* image = nullptr; PalNextImageInfo nextImageInfo = {0}; nextImageInfo.timeout = UINT64_MAX; + nextImageInfo.fence = fences[imageCount]; + image = palGetNextSwapchainImage(swapchain, &nextImageInfo); + // wait till the image is acquired + result = palWaitFence(fences[imageCount], UINT64_MAX); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } + // find the command buffer associated with the image // this is fast, the swapchain caches all it images internally PalCommandBuffer* cmdBuffer = nullptr; + PalFence* fence = nullptr; for (int i = 0; i < imageCount; i++) { if (image == palGetSwapchainImage(swapchain, i)) { cmdBuffer = cmdBuffers[i]; + fence = fences[i]; break; } } @@ -605,6 +806,7 @@ bool triangleTest() // submit to the queue and present PalSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffer; + submitInfo.fence = fence; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -613,6 +815,14 @@ bool triangleTest() return false; } + // wait for the commands to be executed + result = palWaitFence(fence, UINT64_MAX); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } + PalPresentInfo presentInfo = {0}; presentInfo.image = image; @@ -624,26 +834,26 @@ bool triangleTest() } } - // since we dont use a fence or sempahore, there is no way to know - // if the GPU is done presenting and we can now destroy the swapchain - // so we just wait for a while - // and we dont want to use thread system for this - Int32 counter = 0; - for (int i = 0; i < 30000; i++) { - counter++; - } - // cleanup for (int i = 0; i < imageCount; i++) { palDestroyRenderPassView(renderPassViews[i]); palDestroyCommandBuffer(cmdBuffers[i]); palDestroyImageView(imageViews[i]); + palDestroyFence(fences[i]); } + palDestroyFence(fences[imageCount]); + palDestroyPipeline(pipeline); palDestroyPipelineLayout(pipelineLayout); + palDestroyBuffer(vertexBuffer); + palFreeMemory(device, vertexbufferMemory); + palDestroyRenderPass(renderPass); palDestroyCommandPool(cmdPool); + palDestroyShader(vertexShader); + palDestroyShader(fragmentShader); + palDestroySwapchain(swapchain); palDestroyQueue(queue); palDestroyDevice(device); From 38eab96ecd39002d227d16a977ab5cb6794d23b0 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 4 Jan 2026 19:31:54 +0000 Subject: [PATCH 072/372] refine graphics test --- include/pal/pal_graphics.h | 245 ++++---- src/graphics/pal_graphics.c | 159 +----- src/graphics/pal_vulkan.c | 1078 +++++++++++------------------------ tests/graphics_test.c | 4 - tests/tests.lua | 4 +- tests/tests_main.c | 4 +- 6 files changed, 461 insertions(+), 1033 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 4ff099ec..9d35ac4e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -35,7 +35,6 @@ freely, subject to the following restrictions: #define PAL_ADAPTER_NAME_SIZE 128 #define PAL_ADAPTER_VERSION_SIZE 16 -#define PAL_DEFAULT_MEMORY_OFFSET 0 #define PAL_MAX_RESOLVE_MODES 8 #define PAL_MAX_COMBINER_OPS 8 @@ -48,8 +47,6 @@ typedef struct PalSwapchain PalSwapchain; typedef struct PalImage PalImage; typedef struct PalImageView PalImageView; typedef struct PalShader PalShader; -typedef struct PalRenderPass PalRenderPass; -typedef struct PalRenderPassView PalRenderPassView; typedef struct PalBuffer PalBuffer; typedef struct PalFence PalFence; @@ -61,10 +58,13 @@ typedef struct PalPipeline PalPipeline; typedef struct PalPipelineLayout PalPipelineLayout; typedef struct PalAccelerationStructure PalAccelerationStructure; +typedef enum PalDebugMessageSeverity PalDebugMessageSeverity; +typedef enum PalDebugMessageType PalDebugMessageType; + typedef void(PAL_CALL* PalDebugCallback)( void* userData, - Uint32 severity, - Uint32 type, + PalDebugMessageSeverity severity, + PalDebugMessageType type, const char* msg); typedef enum { @@ -226,38 +226,37 @@ typedef enum { PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY = PAL_BIT64(0), PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING = PAL_BIT64(1), PAL_ADAPTER_FEATURE_MULTI_VIEWPORT = PAL_BIT64(2), - PAL_ADAPTER_FEATURE_SEMAPHORE = PAL_BIT64(3), - PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(4), - PAL_ADAPTER_FEATURE_TESSELLATION_SHADER = PAL_BIT64(5), - PAL_ADAPTER_FEATURE_GEOMETRY_SHADER = PAL_BIT64(6), - PAL_ADAPTER_FEATURE_COMPUTE_SHADER = PAL_BIT64(7), - PAL_ADAPTER_FEATURE_SHADER_FLOAT16 = PAL_BIT64(8), - PAL_ADAPTER_FEATURE_SHADER_FLOAT64 = PAL_BIT64(9), - PAL_ADAPTER_FEATURE_SHADER_INT16 = PAL_BIT64(10), - PAL_ADAPTER_FEATURE_SHADER_INT64 = PAL_BIT64(11), - PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(12), - PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(13), - PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE = PAL_BIT64(14), - PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(15), - PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(16), - PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(17), - PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY = PAL_BIT64(18), - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(19), - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(20), - PAL_ADAPTER_FEATURE_FENCE_RESET = PAL_BIT64(21), - PAL_ADAPTER_FEATURE_FENCE_TIMEOUT = PAL_BIT64(22), - PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE = PAL_BIT64(23), - PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE = PAL_BIT64(24), - PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE = PAL_BIT64(25), - PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY = PAL_BIT64(26), - PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE = PAL_BIT64(27), - PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(28), - PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(29), - PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(31), - PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT = PAL_BIT64(32), - PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(33), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(34) + PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(3), + PAL_ADAPTER_FEATURE_TESSELLATION_SHADER = PAL_BIT64(4), + PAL_ADAPTER_FEATURE_GEOMETRY_SHADER = PAL_BIT64(5), + PAL_ADAPTER_FEATURE_COMPUTE_SHADER = PAL_BIT64(6), + PAL_ADAPTER_FEATURE_SHADER_FLOAT16 = PAL_BIT64(7), + PAL_ADAPTER_FEATURE_SHADER_FLOAT64 = PAL_BIT64(8), + PAL_ADAPTER_FEATURE_SHADER_INT16 = PAL_BIT64(9), + PAL_ADAPTER_FEATURE_SHADER_INT64 = PAL_BIT64(10), + PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(11), + PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(12), + PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE = PAL_BIT64(13), + PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), + PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(15), + PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16), + PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY = PAL_BIT64(17), + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(18), + PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(19), + PAL_ADAPTER_FEATURE_FENCE_RESET = PAL_BIT64(20), + PAL_ADAPTER_FEATURE_FENCE_TIMEOUT = PAL_BIT64(21), + PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE = PAL_BIT64(22), + PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE = PAL_BIT64(23), + PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE = PAL_BIT64(24), + PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY = PAL_BIT64(25), + PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE = PAL_BIT64(26), + PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(27), + PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(28), + PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(29), + PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(30), + PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT = PAL_BIT64(31), + PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(32), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(33) } PalAdapterFeatures; typedef enum { @@ -318,9 +317,6 @@ typedef enum { typedef enum { PAL_ATTACHMENT_TYPE_COLOR, PAL_ATTACHMENT_TYPE_DEPTH, - PAL_ATTACHMENT_TYPE_COLOR_RESOLVE, - PAL_ATTACHMENT_TYPE_DEPTH_RESOLVE, - PAL_ATTACHMENT_TYPE_PRESENT, PAL_ATTACHMENT_TYPE_FRAGMENT_SHADING_RATE } PalAttachmentType; @@ -521,17 +517,17 @@ typedef enum { PAL_BUFFER_USAGE_DEVICE_ADDRESS = PAL_BIT(7) } PalBufferUsages; -typedef enum { +enum PalDebugMessageSeverity { PAL_DEBUG_MESSAGE_SEVERITY_INFO, PAL_DEBUG_MESSAGE_SEVERITY_WARNING, PAL_DEBUG_MESSAGE_SEVERITY_ERROR -} PalDebugMessageSeverity; +}; -typedef enum { +enum PalDebugMessageType { PAL_DEBUG_MESSAGE_TYPE_GENERAL, PAL_DEBUG_MESSAGE_TYPE_VALIDATION, PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE -} PalDebugMessageType; +}; typedef struct { Uint32 vendorId; @@ -557,9 +553,6 @@ typedef struct { Uint32 maxImageDepth; Uint32 maxImageArrayLayers; Uint32 maxImageMipLevels; - Uint32 maxRenderPassViewWidth; - Uint32 maxRenderPassViewHeight; - Uint32 maxRenderPassViewArrayLayers; PalSampleCount maxColorSampleCount; PalSampleCount maxDepthSampleCount; Uint32 maxColorAttachments; @@ -647,6 +640,12 @@ typedef struct { PalImageUsages usages; } PalImageInfo; +typedef struct { + float color[4]; + float depth; + Uint32 stencil; +} PalClearValue; + typedef struct { PalAttachmentType type; PalFormat format; @@ -659,20 +658,32 @@ typedef struct { PalResolveMode stencilResolveMode; Uint32 texelWidth; Uint32 texelHeight; + PalImageView* imageView; + PalClearValue clearValue; } PalAttachmentDesc; +typedef struct { + float x; + float y; + float width; + float height; + float minDepth; + float maxDepth; +} PalViewport; + +typedef struct { + Int32 x; + Int32 y; + Uint32 width; + Uint32 height; +} PalRect2D; + typedef struct { bool memoryTypes[PAL_MEMORY_TYPE_MAX]; Uint64 size; Uint32 alignment; } PalMemoryRequirements; -typedef struct { - float color[4]; - float depth; - Uint32 stencil; -} PalClearValue; - typedef struct { Uint64 waitValue; Uint64 signalValue; @@ -680,48 +691,33 @@ typedef struct { PalSemaphore* waitSemaphore; PalSemaphore* signalSemaphore; PalFence* fence; -} PalSubmitInfo; +} PalCommandBufferSubmitInfo; typedef struct { Uint64 timeout; Uint64 signalValue; PalSemaphore* signalSemaphore; PalFence* fence; -} PalNextImageInfo; +} PalSwapchainNextImageInfo; typedef struct { Uint64 waitValue; PalImage* image; PalSemaphore* waitSemaphore; -} PalPresentInfo; - -typedef struct { - PalRenderPass* renderPass; - PalRenderPassView* view; -} PalBeginInfo; - -typedef struct { - Int32 clearValueCount; - PalRenderPass* renderPass; - PalRenderPassView* view; - PalClearValue* clearValues; -} PalRenderPassBeginInfo; +} PalSwapchainPresentInfo; typedef struct { - float x; - float y; - float width; - float height; - float minDepth; - float maxDepth; -} PalViewport; + Uint32 attachmentCount; + PalAttachmentDesc* attachments; +} PalCommandBufferBeginInfo; typedef struct { - Int32 x; - Int32 y; - Uint32 width; - Uint32 height; -} PalScissor; + Uint32 layerCount; + Uint32 colorAttachentCount; + PalAttachmentDesc* colorAttachment; + PalAttachmentDesc* depthAttachment; + PalAttachmentDesc* stencilAttachment; +} PalRenderingInfo; typedef struct { Uint32 vertexCount; @@ -891,19 +887,6 @@ typedef struct { Uint64 bytecodeSize; } PalShaderCreateInfo; -typedef struct { - Uint32 multiViewCount; - Uint32 attachmentCount; - PalAttachmentDesc* attachments; -} PalRenderPassCreateInfo; - -typedef struct { - Uint32 imageViewCount; - Uint32 width; - Uint32 height; - PalImageView** imageViews; -} PalRenderPassViewCreateInfo; - typedef struct { bool transient; bool resettable; @@ -927,20 +910,18 @@ typedef struct { } PalPipelineLayoutCreateInfo; typedef struct { - bool fragmentShadingRateEnabled; - PalPrimitiveTopology topology; Uint32 vertexLayoutCount; Uint32 blendAttachmentCount; Uint32 shaderCount; - PalRenderPass* renderPass; + PalPrimitiveTopology topology; PalPipelineLayout* pipelineLayout; PalShader** shaders; PalVertexLayout* vertexLayouts; PalBlendAttachment* blendAttachments; - PalRasterizerState rasterizerState; - PalMultisampleState multisampleState; - PalDepthStencilState depthStencilState; - PalFragmentShadingRateState fragmentShadingRateState; + PalRasterizerState* rasterizerState; + PalMultisampleState* multisampleState; + PalDepthStencilState* depthStencilState; + PalFragmentShadingRateState* fragmentShadingRateState; } PalGraphicsPipelineCreateInfo; typedef struct { @@ -1078,13 +1059,13 @@ typedef struct { PalImage* PAL_CALL (*getNextSwapchainImage)( PalSwapchain* swapchain, - PalNextImageInfo* info); + PalSwapchainNextImageInfo* info); PalFormat PAL_CALL (*getSwapchainFormat)(PalSwapchain* swapchain); PalResult PAL_CALL (*presentSwapchain)( PalSwapchain* swapchain, - PalPresentInfo* info); + PalSwapchainPresentInfo* info); PalResult PAL_CALL (*createShader)( PalDevice* device, @@ -1093,21 +1074,6 @@ typedef struct { void PAL_CALL (*destroyShader)(PalShader* shader); - PalResult PAL_CALL (*createRenderPass)( - PalDevice* device, - const PalRenderPassCreateInfo* info, - PalRenderPass** outRenderPass); - - void PAL_CALL (*destroyRenderPass)(PalRenderPass* renderPass); - - PalResult PAL_CALL (*createRenderPassView)( - PalDevice* device, - PalRenderPass* renderPass, - const PalRenderPassViewCreateInfo* info, - PalRenderPassView** outRenderPassView); - - void PAL_CALL (*destroyRenderPassView)(PalRenderPassView* renderPassView); - PalResult PAL_CALL (*createFence)( PalDevice* device, PalFence** outFence); @@ -1160,7 +1126,7 @@ typedef struct { PalResult PAL_CALL (*beginCommandBuffer)( PalCommandBuffer* cmdBuffer, - PalBeginInfo* info); + PalCommandBufferBeginInfo* info); PalResult PAL_CALL (*endCommandBuffer)(PalCommandBuffer* cmdBuffer); @@ -1198,11 +1164,11 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); - PalResult PAL_CALL (*beginRenderPass)( + PalResult PAL_CALL (*beginRendering)( PalCommandBuffer* cmdBuffer, - PalRenderPassBeginInfo* info); + PalRenderingInfo* info); - PalResult PAL_CALL (*endRenderPass)(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL (*endRendering)(PalCommandBuffer* cmdBuffer); PalResult PAL_CALL (*copyBuffer)( PalCommandBuffer* cmdBuffer, @@ -1224,7 +1190,7 @@ typedef struct { PalResult PAL_CALL (*setScissors)( PalCommandBuffer* cmdBuffer, Uint32 count, - PalScissor* scissors); + PalRect2D* scissors); PalResult PAL_CALL (*bindVertexBuffers)( PalCommandBuffer* cmdBuffer, @@ -1261,7 +1227,7 @@ typedef struct { PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, - PalSubmitInfo* info); + PalCommandBufferSubmitInfo* info); PalResult PAL_CALL (*createAccelerationstructure)( PalDevice* device, @@ -1311,7 +1277,7 @@ PAL_API PalResult PAL_CALL palAddGraphicsBackend( const PalGraphicsBackend* backend); PAL_API PalResult PAL_CALL palInitGraphics( - PalGraphicsDebugger* debugger, + const PalGraphicsDebugger* debugger, const PalAllocator* allocator); PAL_API void PAL_CALL palShutdownGraphics(); @@ -1450,13 +1416,13 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PAL_API PalImage* PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, - PalNextImageInfo* info); + PalSwapchainNextImageInfo* info); PAL_API PalFormat PAL_CALL palGetSwapchainFormat(PalSwapchain* swapchain); PAL_API PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, - PalPresentInfo* info); + PalSwapchainPresentInfo* info); PAL_API PalResult PAL_CALL palCreateShader( PalDevice* device, @@ -1465,21 +1431,6 @@ PAL_API PalResult PAL_CALL palCreateShader( PAL_API void PAL_CALL palDestroyShader(PalShader* shader); -PAL_API PalResult PAL_CALL palCreateRenderPass( - PalDevice* device, - const PalRenderPassCreateInfo* info, - PalRenderPass** outRenderPass); - -PAL_API void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass); - -PAL_API PalResult PAL_CALL palCreateRenderPassView( - PalDevice* device, - PalRenderPass* renderPass, - const PalRenderPassViewCreateInfo* info, - PalRenderPassView** outRenderPassView); - -PAL_API void PAL_CALL palDestroyRenderPassView(PalRenderPassView* view); - PAL_API PalResult PAL_CALL palCreateCommandPool( PalDevice* device, const PalCommandPoolCreateInfo* info, @@ -1532,7 +1483,7 @@ PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); PAL_API PalResult PAL_CALL palBeginCommandBuffer( PalCommandBuffer* cmdBuffer, - PalBeginInfo* info); + PalCommandBufferBeginInfo* info); PAL_API PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -1570,11 +1521,11 @@ PAL_API PalResult PAL_CALL palBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); -PAL_API PalResult PAL_CALL palBeginRenderPass( +PAL_API PalResult PAL_CALL palBeginRendering( PalCommandBuffer* cmdBuffer, - PalRenderPassBeginInfo* info); + PalRenderingInfo* info); -PAL_API PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer); +PAL_API PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer); PAL_API PalResult PAL_CALL palCopyBuffer( PalCommandBuffer* cmdBuffer, @@ -1596,7 +1547,7 @@ PAL_API PalResult PAL_CALL palSetViewport( PAL_API PalResult PAL_CALL palSetScissors( PalCommandBuffer* cmdBuffer, Uint32 count, - PalScissor* scissors); + PalRect2D* scissors); PAL_API PalResult PAL_CALL palBindVertexBuffers( PalCommandBuffer* cmdBuffer, @@ -1633,7 +1584,7 @@ PAL_API PalResult PAL_CALL palDrawIndexedIndirect( PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, - PalSubmitInfo* info); + PalCommandBufferSubmitInfo* info); PAL_API PalResult PAL_CALL palCreateAccelerationstructure( PalDevice* device, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 4c023910..bf5292a5 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -41,7 +41,6 @@ PAL_HANDLE(PalSwapchain) PAL_HANDLE(PalImage) PAL_HANDLE(PalImageView) PAL_HANDLE(PalShader) -PAL_HANDLE(PalRenderPass) PAL_HANDLE(PalBuffer) PAL_HANDLE(PalFence) @@ -50,7 +49,6 @@ PAL_HANDLE(PalCommandPool) PAL_HANDLE(PalCommandBuffer) PAL_HANDLE(PalPipeline) PAL_HANDLE(PalAccelerationStructure) -PAL_HANDLE(PalRenderPassView) PAL_HANDLE(PalPipelineLayout) typedef struct { @@ -80,7 +78,7 @@ static GraphicsLinux s_Graphics = {0}; #if PAL_HAS_VULKAN PalResult PAL_CALL initGraphicsVk( - PalGraphicsDebugger* debugger, + const PalGraphicsDebugger* debugger, const PalAllocator* allocator); PalResult PAL_CALL shutdownGraphicsVk(); @@ -208,13 +206,13 @@ PalImage* PAL_CALL getVkSwapchainImage( PalImage* PAL_CALL getVkNextSwapchainImage( PalSwapchain* swapchain, - PalNextImageInfo* info); + PalSwapchainNextImageInfo* info); PalFormat PAL_CALL getVkSwapchainFormat(PalSwapchain* swapchain); PalResult PAL_CALL presentVkSwapchain( PalSwapchain* swapchain, - PalPresentInfo* info); + PalSwapchainPresentInfo* info); PalResult PAL_CALL createVkShader( PalDevice* device, @@ -223,21 +221,6 @@ PalResult PAL_CALL createVkShader( void PAL_CALL destroyVkShader(PalShader* shader); -PalResult PAL_CALL createVkRenderPass( - PalDevice* device, - const PalRenderPassCreateInfo* info, - PalRenderPass** outRenderPass); - -void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass); - -PalResult PAL_CALL createVkRenderPassView( - PalDevice* device, - PalRenderPass* renderPass, - const PalRenderPassViewCreateInfo* info, - PalRenderPassView** outRenderPassView); - -void PAL_CALL destroyVkRenderPassView(PalRenderPassView* view); - PalResult PAL_CALL createVkFence( PalDevice* device, PalFence** outFence); @@ -290,7 +273,7 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); PalResult PAL_CALL beginVkCommandBuffer( PalCommandBuffer* cmdBuffer, - PalBeginInfo* info); + PalCommandBufferBeginInfo* info); PalResult PAL_CALL endVkCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -328,11 +311,11 @@ PalResult PAL_CALL buildVkAccelerationStructure( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); -PalResult PAL_CALL beginRenderPassVk( +PalResult PAL_CALL beginRenderingVk( PalCommandBuffer* cmdBuffer, - PalRenderPassBeginInfo* info); + PalRenderingInfo* info); -PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer); +PalResult PAL_CALL endRenderingVk(PalCommandBuffer* cmdBuffer); PalResult PAL_CALL copyVkBuffer( PalCommandBuffer* cmdBuffer, @@ -354,7 +337,7 @@ PalResult PAL_CALL setVkViewport( PalResult PAL_CALL setVkScissors( PalCommandBuffer* cmdBuffer, Uint32 count, - PalScissor* scissors); + PalRect2D* scissors); PalResult PAL_CALL bindVkVertexBuffers( PalCommandBuffer* cmdBuffer, @@ -391,7 +374,7 @@ PalResult PAL_CALL drawIndexedIndirectVk( PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, - PalSubmitInfo* info); + PalCommandBufferSubmitInfo* info); PalResult PAL_CALL createVkAccelerationstructure( PalDevice* device, @@ -485,10 +468,6 @@ static PalGraphicsBackend s_VkBackend = { .presentSwapchain = presentVkSwapchain, .createShader = createVkShader, .destroyShader = destroyVkShader, - .createRenderPass = createVkRenderPass, - .destroyRenderPass = destroyVkRenderPass, - .createRenderPassView = createVkRenderPassView, - .destroyRenderPassView = destroyVkRenderPassView, .createFence = createVkFence, .destroyFence = destroyVkFence, .waitFenceTimeout = waitVkFence, @@ -511,8 +490,8 @@ static PalGraphicsBackend s_VkBackend = { .drawMeshTasksIndirect = drawVkMeshTasksIndirect, .drawMeshTasksIndirectCount = drawVkMeshTasksIndirectCount, .buildAccelerationStructure = buildVkAccelerationStructure, - .beginRenderPass = beginRenderPassVk, - .endRenderPass = endRenderPassVk, + .beginRendering = beginRenderingVk, + .endRendering = endRenderingVk, .copyBuffer = copyVkBuffer, .bindPipeline = bindVkPipeline, .setViewport = setVkViewport, @@ -606,10 +585,6 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->presentSwapchain || !backend->createShader || !backend->destroyShader || - !backend->createRenderPass || - !backend->destroyRenderPass || - !backend->createRenderPassView || - !backend->destroyRenderPassView || !backend->createFence || !backend->destroyFence || !backend->waitFenceTimeout || @@ -632,8 +607,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->drawMeshTasksIndirect || !backend->drawMeshTasksIndirectCount || !backend->buildAccelerationStructure || - !backend->beginRenderPass || - !backend->endRenderPass || + !backend->beginRendering || + !backend->endRendering || !backend->copyBuffer || !backend->bindPipeline || !backend->setViewport || @@ -671,7 +646,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) } PalResult PAL_CALL palInitGraphics( - PalGraphicsDebugger* debugger, + const PalGraphicsDebugger* debugger, const PalAllocator* allocator) { if (s_Graphics.initialized) { @@ -1273,7 +1248,7 @@ PalImage* PAL_CALL palGetSwapchainImage( PalImage* PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, - PalNextImageInfo* info) + PalSwapchainNextImageInfo* info) { if (!s_Graphics.initialized || !swapchain || !info) { return nullptr; @@ -1294,7 +1269,7 @@ PalFormat PAL_CALL palGetSwapchainFormat(PalSwapchain* swapchain) PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, - PalPresentInfo* info) + PalSwapchainPresentInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1349,92 +1324,6 @@ void PAL_CALL palDestroyShader(PalShader* shader) } } -// ================================================== -// Render Pass -// ================================================== - -PalResult PAL_CALL palCreateRenderPass( - PalDevice* device, - const PalRenderPassCreateInfo* info, - PalRenderPass** outRenderPass) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device || !info || !outRenderPass) { - return PAL_RESULT_NULL_POINTER; - } - - if (info->attachmentCount == 0 && info->attachments) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - PalRenderPass* renderPass = nullptr; - PalResult result; - result = device->backend->createRenderPass( - device, - info, - &renderPass); - - if (result != PAL_RESULT_SUCCESS) { - return result; - } - - renderPass->backend = device->backend; - *outRenderPass = renderPass; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyRenderPass(PalRenderPass* renderPass) -{ - if (s_Graphics.initialized && renderPass) { - renderPass->backend->destroyRenderPass(renderPass); - } -} - -PalResult PAL_CALL palCreateRenderPassView( - PalDevice* device, - PalRenderPass* renderPass, - const PalRenderPassViewCreateInfo* info, - PalRenderPassView** outRenderPassView) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device || !renderPass || !info || !outRenderPassView) { - return PAL_RESULT_NULL_POINTER; - } - - if (info->imageViewCount == 0 && info->imageViews) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - PalRenderPassView* renderPassView = nullptr; - PalResult result; - result = device->backend->createRenderPassView( - device, - renderPass, - info, - &renderPassView); - - if (result != PAL_RESULT_SUCCESS) { - return result; - } - - renderPassView->backend = device->backend; - *outRenderPassView = renderPassView; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyRenderPassView(PalRenderPassView* view) -{ - if (s_Graphics.initialized && view) { - view->backend->destroyRenderPassView(view); - } -} - // ================================================== // Fence // ================================================== @@ -1682,7 +1571,7 @@ void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL palBeginCommandBuffer( PalCommandBuffer* cmdBuffer, - PalBeginInfo* info) + PalCommandBufferBeginInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1830,9 +1719,9 @@ PalResult PAL_CALL palBuildAccelerationStructures( info); } -PalResult PAL_CALL palBeginRenderPass( +PalResult PAL_CALL palBeginRendering( PalCommandBuffer* cmdBuffer, - PalRenderPassBeginInfo* info) + PalRenderingInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1842,12 +1731,12 @@ PalResult PAL_CALL palBeginRenderPass( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->beginRenderPass( + return cmdBuffer->backend->beginRendering( cmdBuffer, info); } -PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1857,7 +1746,7 @@ PalResult PAL_CALL palEndRenderPass(PalCommandBuffer* cmdBuffer) return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->endRenderPass(cmdBuffer); + return cmdBuffer->backend->endRendering(cmdBuffer); } PalResult PAL_CALL palCopyBuffer( @@ -1924,7 +1813,7 @@ PalResult PAL_CALL palSetViewport( PalResult PAL_CALL palSetScissors( PalCommandBuffer* cmdBuffer, Uint32 count, - PalScissor* scissors) + PalRect2D* scissors) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2062,7 +1951,7 @@ PalResult PAL_CALL palDrawIndexedIndirect( PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, - PalSubmitInfo* info) + PalCommandBufferSubmitInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 2eabdf90..23ed7022 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -75,6 +75,7 @@ typedef struct { } Adapter; typedef struct { + bool useCache; bool hasDebug; void* handle; Adapter* adapters; @@ -118,10 +119,6 @@ typedef struct { PFN_vkDestroyImage destroyImage; PFN_vkCreateShaderModule createShader; PFN_vkDestroyShaderModule destroyShader; - PFN_vkCreateRenderPass createRenderPass; - PFN_vkDestroyRenderPass destroyRenderPass; - PFN_vkCreateFramebuffer createFramebuffer; - PFN_vkDestroyFramebuffer destroyFramebuffer; PFN_vkCreateCommandPool createCommandPool; PFN_vkDestroyCommandPool destroyCommandPool; @@ -139,8 +136,6 @@ typedef struct { PFN_vkEndCommandBuffer cmdEnd; PFN_vkCmdExecuteCommands cmdExecuteCommandBuffer; PFN_vkQueueSubmit queueSubmit; - PFN_vkCmdBeginRenderPass cmdBeginRenderPass; - PFN_vkCmdEndRenderPass cmdEndRenderPass; PFN_vkCmdCopyBuffer cmdCopyBuffer; PFN_vkCmdBindPipeline cmdBindPipeline; PFN_vkCmdSetViewport cmdSetViewports; @@ -199,7 +194,6 @@ typedef struct { VkPhysicalDevice phyDevice; VkDevice handle; PhysicalQueue* phyQueues; - PFN_vkCreateRenderPass2 createRenderPass2; PFN_vkGetBufferDeviceAddress getBufferrAddress; // swapchain @@ -234,6 +228,10 @@ typedef struct { PFN_vkCmdTraceRaysKHR cmdTraceRays; PFN_vkCreateRayTracingPipelinesKHR createRayTracingPipeline; PFN_vkCmdTraceRaysIndirectKHR cmdTraceRaysIndirect; + + // dynamic rendering + PFN_vkCmdBeginRendering cmdBeginRendering; + PFN_vkCmdEndRendering cmdEndRendering; } Device; typedef struct { @@ -284,23 +282,6 @@ typedef struct { VkPipelineShaderStageCreateInfo info; } Shader; -typedef struct { - const PalGraphicsBackend* backend; - - Uint32 attachmentCount; - Device* device; - VkRenderPass handle; -} RenderPass; - -typedef struct { - const PalGraphicsBackend* backend; - - Uint32 width; - Uint32 height; - Device* device; - VkFramebuffer handle; -} RenderPassView; - typedef struct { const PalGraphicsBackend* backend; @@ -340,14 +321,6 @@ typedef struct { VkBuffer handle; } Buffer; -typedef struct { - const PalGraphicsBackend* backend; - - PalBuffer* buffer; - Device* device; - VkBufferView handle; -} BufferView; - typedef struct { const PalGraphicsBackend* backend; @@ -1614,7 +1587,7 @@ static Uint32 getMemoryTypeScore( // ================================================== PalResult PAL_CALL initGraphicsVk( - PalGraphicsDebugger* debugger, + const PalGraphicsDebugger* debugger, const PalAllocator* allocator) { s_Vk.libWayland = nullptr; @@ -1708,22 +1681,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroyShaderModule"); - s_Vk.createRenderPass = (PFN_vkCreateRenderPass)dlsym( - s_Vk.handle, - "vkCreateRenderPass"); - - s_Vk.destroyRenderPass = (PFN_vkDestroyRenderPass)dlsym( - s_Vk.handle, - "vkDestroyRenderPass"); - - s_Vk.createFramebuffer = (PFN_vkCreateFramebuffer)dlsym( - s_Vk.handle, - "vkCreateFramebuffer"); - - s_Vk.destroyFramebuffer = (PFN_vkDestroyFramebuffer)dlsym( - s_Vk.handle, - "vkDestroyFramebuffer"); - s_Vk.getPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)dlsym( s_Vk.handle, "vkGetPhysicalDeviceProperties2"); @@ -1820,14 +1777,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCmdExecuteCommands"); - s_Vk.cmdBeginRenderPass = (PFN_vkCmdBeginRenderPass)dlsym( - s_Vk.handle, - "vkCmdBeginRenderPass"); - - s_Vk.cmdEndRenderPass = (PFN_vkCmdEndRenderPass)dlsym( - s_Vk.handle, - "vkCmdEndRenderPass"); - s_Vk.cmdCopyBuffer = (PFN_vkCmdCopyBuffer)dlsym( s_Vk.handle, "vkCmdCopyBuffer"); @@ -1924,7 +1873,7 @@ PalResult PAL_CALL initGraphicsVk( } } - VkResult ret; + VkResult result; Uint32 layerCount = 0; bool hasValidationLayer = false; s_Vk.messenger = nullptr; @@ -1934,11 +1883,11 @@ PalResult PAL_CALL initGraphicsVk( if (debugger) { // layers - ret = s_Vk.enumerateInstanceLayerProperties( + result = s_Vk.enumerateInstanceLayerProperties( &layerCount, nullptr); - if (ret != VK_SUCCESS) { + if (result != VK_SUCCESS) { s_Vk.hasDebug = false; } @@ -1985,12 +1934,12 @@ PalResult PAL_CALL initGraphicsVk( // extensions Uint32 extCount = 0; const char* extensions[8]; - ret = s_Vk.enumerateInstanceExtensionProperties( + result = s_Vk.enumerateInstanceExtensionProperties( nullptr, &extCount, nullptr); - if (ret != VK_SUCCESS) { + if (result != VK_SUCCESS) { return PAL_RESULT_PLATFORM_FAILURE; } @@ -2029,7 +1978,6 @@ PalResult PAL_CALL initGraphicsVk( hasExtDebug = true; } } - palFree(s_Vk.allocator, extensionProps); int extensionCount = 0; @@ -2084,7 +2032,7 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.vkAllocator.pfnReallocation = vkRealloc; VkInstance instance = nullptr; - VkResult result = s_Vk.createInstance( + result = s_Vk.createInstance( &instanceCreateInfo, &s_Vk.vkAllocator, &instance); @@ -2194,8 +2142,11 @@ PalResult PAL_CALL enumerateVkAdapters( PalAdapter** outAdapters) { int deviceCount = 0; - int maxCount = outAdapters ? *count : 0; + int adapterCount = 0; + int extensionCount = 0; VkResult result; + VkExtensionProperties* extensions = nullptr; + VkPhysicalDeviceProperties props = {0}; result = s_Vk.enumeratePhysicalDevices( s_Vk.instance, @@ -2206,9 +2157,8 @@ PalResult PAL_CALL enumerateVkAdapters( return PAL_RESULT_PLATFORM_FAILURE; } - if (!outAdapters) { - *count = deviceCount; - return PAL_RESULT_SUCCESS; + if (s_Vk.adapters) { + palFree(s_Vk.allocator, s_Vk.adapters); } VkPhysicalDevice* devices = nullptr; @@ -2216,25 +2166,69 @@ PalResult PAL_CALL enumerateVkAdapters( sizeof(VkPhysicalDevice) * deviceCount, 0); - if (!devices) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (s_Vk.adapters) { - // free the adapters and cache them again - palFree(s_Vk.allocator, s_Vk.adapters); - } - s_Vk.adapters = palAllocate( s_Vk.allocator, sizeof(Adapter) * deviceCount, 0); + if (!devices || !s_Vk.adapters) { + return PAL_RESULT_OUT_OF_MEMORY; + } + s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, devices); - for (int i = 0; i < *count && i < deviceCount; i++) { - Adapter* tmp = &s_Vk.adapters[i]; - tmp->handle = devices[i]; - outAdapters[i] = (PalAdapter*)tmp; + for (int i = 0; i < deviceCount; i++) { + VkPhysicalDevice phyDevice = devices[i]; + s_Vk.getPhysicalDeviceProperties(phyDevice, &props); + if (props.apiVersion < VK_API_VERSION_1_3) { + // check extension + result = s_Vk.enumerateDeviceExtensionProperties( + phyDevice, + nullptr, + &extensionCount, + nullptr); + + extensions = palAllocate( + s_Vk.allocator, + sizeof(VkExtensionProperties) * extensionCount, + 0); + + if (!extensions) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + s_Vk.enumerateDeviceExtensionProperties( + phyDevice, + nullptr, + &extensionCount, + extensions); + + bool found = false; + for (int i = 0; i < extensionCount; i++) { + const char* ext = extensions[i].extensionName; + if (strcmp(ext, "VK_KHR_dynamic_rendering") == 0) { + found = true; + break; + } + } + + palFree(s_Vk.allocator, extensions); + if (!found) { + continue; + } + } + + if (outAdapters) { + if (adapterCount < *count) { + Adapter* tmp = &s_Vk.adapters[adapterCount]; + tmp->handle = devices[i]; + outAdapters[adapterCount] = (PalAdapter*)tmp; + } + } + adapterCount++; + } + + if (!outAdapters) { + *count = adapterCount; } palFree(s_Vk.allocator, devices); @@ -2315,7 +2309,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps) { - VkResult ret = VK_SUCCESS; + VkResult result = VK_SUCCESS; Adapter* vkAdapter = (Adapter*)adapter; VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; @@ -2337,10 +2331,6 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->maxImageDepth = props.limits.maxImageDimension3D; caps->maxImageArrayLayers = props.limits.maxImageArrayLayers; - caps->maxRenderPassViewWidth = props.limits.maxFramebufferWidth; - caps->maxRenderPassViewHeight = props.limits.maxFramebufferHeight; - caps->maxRenderPassViewArrayLayers = props.limits.maxFramebufferLayers; - PalSampleCount tmp = PAL_SAMPLE_COUNT_1; tmp = vkSamplesToSamples(props.limits.framebufferColorSampleCounts); caps->maxColorSampleCount = tmp; @@ -2415,7 +2405,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) { - VkResult ret; + VkResult result; PalAdapterFeatures adapterFeatures = 0; Uint32 extensionCount = 0; VkPhysicalDeviceProperties props = {0}; @@ -2425,13 +2415,13 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) // get supported extensions s_Vk.getPhysicalDeviceProperties(phyDevice, &props); - ret = s_Vk.enumerateDeviceExtensionProperties( + result = s_Vk.enumerateDeviceExtensionProperties( phyDevice, nullptr, &extensionCount, nullptr); - if (ret != VK_SUCCESS) { + if (result != VK_SUCCESS) { // we just return without any modern features which is rare return 0; } @@ -2726,7 +2716,6 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT; adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_TIMEOUT; - adapterFeatures |= PAL_ADAPTER_FEATURE_SEMAPHORE; adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; palFree(s_Vk.allocator, extensionProps); @@ -2744,7 +2733,7 @@ PalResult PAL_CALL createVkDevice( { float priority = 1.0f; Uint32 count = 0; - VkResult ret = VK_SUCCESS; + VkResult result = VK_SUCCESS; Device* device = nullptr; VkPhysicalDeviceProperties props = {0}; @@ -2876,6 +2865,10 @@ PalResult PAL_CALL createVkDevice( createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; // clang-format on + if (props.apiVersion < VK_API_VERSION_1_3) { + extensions[extCount++] = "VK_KHR_dynamic_rendering"; + } + if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { extensions[extCount++] = "VK_KHR_swapchain"; } @@ -2942,9 +2935,6 @@ PalResult PAL_CALL createVkDevice( // fragment shading rate attachment needs this if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_KHR_create_renderpass2"; - } fsr.attachmentFragmentShadingRate = true; } } @@ -3011,18 +3001,18 @@ PalResult PAL_CALL createVkDevice( createInfo.pQueueCreateInfos = queueCreateInfos; createInfo.queueCreateInfoCount = count; - ret = s_Vk.createDevice( + result = s_Vk.createDevice( phyDevice, &createInfo, &s_Vk.vkAllocator, &device->handle); - if (ret != VK_SUCCESS) { + if (result != VK_SUCCESS) { palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); palFree(s_Vk.allocator, device->phyQueues); palFree(s_Vk.allocator, device); - return vkResultToPal(ret); + return vkResultToPal(result); } // get queues @@ -3149,23 +3139,6 @@ PalResult PAL_CALL createVkDevice( (PFN_vkCmdSetFragmentShadingRateKHR)s_Vk.getDeviceProcAddr( device->handle, "vkCmdSetFragmentShadingRateKHR"); - - device->createRenderPass2 = (PFN_vkCreateRenderPass2)s_Vk.getDeviceProcAddr( - device->handle, - "vkCreateRenderPass2"); - } - - // load fragment shading rate attachment procs - if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { - device->createRenderPass2 = (PFN_vkCreateRenderPass2)s_Vk.getDeviceProcAddr( - device->handle, - "vkCreateRenderPass2"); - - if (!device->createRenderPass2) { - device->createRenderPass2 = (PFN_vkCreateRenderPass2KHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCreateRenderPass2KHR"); - } } // mesh shader @@ -3243,6 +3216,29 @@ PalResult PAL_CALL createVkDevice( } } + // dynamic rendering + device->cmdBeginRendering = + (PFN_vkCmdBeginRendering)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdBeginRendering"); + + device->cmdEndRendering = + (PFN_vkCmdEndRendering)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdEndRendering"); + + if (!device->cmdBeginRendering) { + device->cmdBeginRendering = + (PFN_vkCmdBeginRenderingKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdBeginRenderingKHR"); + + device->cmdEndRendering = + (PFN_vkCmdEndRenderingKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdEndRenderingKHR"); + } + device->features = features; palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); @@ -3313,6 +3309,40 @@ void PAL_CALL freeVkMemory( s_Vk.freeMemory(vkDevice->handle, mem, &s_Vk.vkAllocator); } +PalResult PAL_CALL mapVkMemory( + PalDevice* device, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr) +{ + VkResult result; + VkDeviceMemory mem = (VkDeviceMemory)memory; + Device* vkDevice = (Device*)device; + + result = s_Vk.mapMemory( + vkDevice->handle, + mem, + offset, + size, + 0, + outPtr); + + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL unmapVkMemory( + PalDevice* device, + PalMemory* memory) +{ + VkDeviceMemory mem = (VkDeviceMemory)memory; + Device* vkDevice = (Device*)device; + s_Vk.unmapMemory(vkDevice->handle, mem); +} + PalResult PAL_CALL queryVkDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps) @@ -4007,8 +4037,8 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - bool ret = createSurface(window, &surface); - if (!ret) { + bool result = createSurface(window, &surface); + if (!result) { return PAL_RESULT_INVALID_GRAPHICS_WINDOW; } @@ -4149,8 +4179,7 @@ PalResult PAL_CALL createVkSwapchain( return PAL_RESULT_OUT_OF_MEMORY; } - bool ret = createSurface(window, &swapchain->surface); - if (!ret) { + if (!createSurface(window, &swapchain->surface)) { return PAL_RESULT_INVALID_GRAPHICS_WINDOW; } @@ -4319,7 +4348,7 @@ PalImage* PAL_CALL getVkSwapchainImage( PalImage* PAL_CALL getVkNextSwapchainImage( PalSwapchain* swapchain, - PalNextImageInfo* info) + PalSwapchainNextImageInfo* info) { VkResult result; Uint32 index = 0; @@ -4362,7 +4391,7 @@ PalFormat PAL_CALL getVkSwapchainFormat(PalSwapchain* swapchain) PalResult PAL_CALL presentVkSwapchain( PalSwapchain* swapchain, - PalPresentInfo* info) + PalSwapchainPresentInfo* info) { Swapchain* vkSwapchain = (Swapchain*)swapchain; Image* vkImage = (Image*)info->image; @@ -4498,418 +4527,6 @@ void PAL_CALL destroyVkShader(PalShader* shader) palFree(s_Vk.allocator, vkShader); } -// ================================================== -// Render Pass -// ================================================== - -PalResult PAL_CALL createVkRenderPass( - PalDevice* device, - const PalRenderPassCreateInfo* info, - PalRenderPass** outRenderPass) -{ - VkResult result; - RenderPass* renderPass = nullptr; - Device* vkDevice = (Device*)device; - - renderPass = palAllocate(s_Vk.allocator, sizeof(RenderPass), 0); - if (!renderPass) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - bool hasDepth = false; - bool hasFsr; - Uint32 colorRefCount = 0; - Uint32 resolveRefCount = 0; - - // multi view - Uint32 viewMask = (1 << info->multiViewCount) - 1; - VkRenderPassMultiviewCreateInfo viewCreateInfo = {0}; - viewCreateInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; - viewCreateInfo.pViewMasks = &viewMask; - viewCreateInfo.subpassCount = 1; - - // clang-format off - if (vkDevice->createRenderPass2) { - VkAttachmentDescription2KHR attachments[MAX_ATTACHMENTS]; - VkAttachmentReference2KHR depthRef; - VkAttachmentReference2KHR fsrRef; - VkAttachmentReference2KHR colorRefs[MAX_ATTACHMENTS]; - VkAttachmentReference2KHR resolveRefs[MAX_ATTACHMENTS]; - VkFragmentShadingRateAttachmentInfoKHR fsrAttachment = {0}; - fsrAttachment.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; - - for (int i = 0; i < info->attachmentCount; i++) { - PalAttachmentDesc* desc = &info->attachments[i]; - VkAttachmentDescription2KHR* rDesc = &attachments[i]; - - rDesc->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR; - rDesc->flags = 0; - rDesc->pNext = nullptr; - - rDesc->format = palFormatToVk(desc->format); - rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rDesc->samples = samplesToVk(desc->sampleCount); - rDesc->flags = 0; - - // load op - if (desc->loadOp == PAL_LOAD_OP_CLEAR) { - rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - - } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { - rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - - } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { - rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } - - // store op - if (desc->storeOp == PAL_STORE_OP_STORE) { - rDesc->storeOp = VK_ATTACHMENT_STORE_OP_STORE; - - } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { - rDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - - VkAttachmentReference2KHR* ref = nullptr; - VkImageAspectFlags aspectMask = 0; - VkImageLayout layout, refLayout = 0; - if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { - ref = &colorRefs[colorRefCount++]; - layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - } else if (desc->type == PAL_ATTACHMENT_TYPE_COLOR_RESOLVE) { - ref = &resolveRefs[resolveRefCount++]; - layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH) { - ref = &depthRef; - layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - refLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - - hasDepth = true; - // stencil is only used with depth attachment - if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - - } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - - } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } - - if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { - rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - - } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { - rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - - } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH_RESOLVE) { - ref = &resolveRefs[resolveRefCount++]; - layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - refLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - - } else if (desc->type == PAL_ATTACHMENT_TYPE_PRESENT) { - ref = &colorRefs[colorRefCount++]; - layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - } else { - // fragment shading rate attachment - VkExtent2D size; - size.width = desc->texelWidth; - size.height = desc->texelHeight; - fsrAttachment.shadingRateAttachmentTexelSize = size; - - ref = &fsrRef; - layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; - refLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; - aspectMask = 0; - fsrAttachment.pFragmentShadingRateAttachment = &fsrRef; - hasFsr = true; - } - - ref->attachment = i; - ref->layout = refLayout; - ref->aspectMask = aspectMask; - ref->pNext = 0; - ref->sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2; - rDesc->finalLayout = layout; - } - - // subpass - VkSubpassDescription2 subpassDesc = {0}; - subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDesc.colorAttachmentCount = colorRefCount; - subpassDesc.pColorAttachments = colorRefs; - subpassDesc.pNext = &fsrAttachment; - - if (hasDepth) { - subpassDesc.pDepthStencilAttachment = &depthRef; - } - - if (resolveRefCount) { - subpassDesc.pResolveAttachments = resolveRefs; - } - - VkRenderPassCreateInfo2KHR createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR; - createInfo.attachmentCount = info->attachmentCount; - createInfo.pAttachments = attachments; - createInfo.subpassCount = 1; - createInfo.pSubpasses = &subpassDesc; - - if (info->multiViewCount > 1) { - createInfo.pNext = &viewCreateInfo; - } - - result = vkDevice->createRenderPass2( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &renderPass->handle); - - } else { - // legacy path - VkAttachmentDescription attachments[MAX_ATTACHMENTS]; - VkAttachmentReference depthRef; - VkAttachmentReference colorRefs[MAX_ATTACHMENTS]; - VkAttachmentReference resolveRefs[MAX_ATTACHMENTS]; - - for (int i = 0; i < info->attachmentCount; i++) { - PalAttachmentDesc* desc = &info->attachments[i]; - VkAttachmentDescription* rDesc = &attachments[i]; - - rDesc->flags = 0; - rDesc->format = palFormatToVk(desc->format); - rDesc->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - rDesc->samples = samplesToVk(desc->sampleCount); - - // load op - if (desc->loadOp == PAL_LOAD_OP_CLEAR) { - rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - - } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { - rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - - } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { - rDesc->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } - - // store op - if (desc->storeOp == PAL_STORE_OP_STORE) { - rDesc->storeOp = VK_ATTACHMENT_STORE_OP_STORE; - - } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { - rDesc->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - - // stencil op. set to default - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - - VkAttachmentReference* ref = nullptr; - VkImageLayout layout, refLayout = 0; - if (desc->type == PAL_ATTACHMENT_TYPE_COLOR) { - ref = &colorRefs[colorRefCount++]; - layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - } else if (desc->type == PAL_ATTACHMENT_TYPE_COLOR_RESOLVE) { - ref = &resolveRefs[resolveRefCount++]; - layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH) { - ref = &depthRef; - layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - refLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - - hasDepth = true; - // stencil is only used with depth attachment - if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - - } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - - } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { - rDesc->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } - - if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { - rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - - } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { - rDesc->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - - } else if (desc->type == PAL_ATTACHMENT_TYPE_DEPTH_RESOLVE) { - ref = &resolveRefs[resolveRefCount++]; - layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - refLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - - } else { - ref = &colorRefs[colorRefCount++]; - layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - refLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } - - ref->attachment = i; - ref->layout = refLayout; - rDesc->finalLayout = layout; - } - - VkSubpassDependency dependency = {0}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - dependency.srcAccessMask = 0; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - - // subpass legacy - VkSubpassDescription subpassDesc = {0}; - subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpassDesc.colorAttachmentCount = colorRefCount; - subpassDesc.pColorAttachments = colorRefs; - if (hasDepth) { - subpassDesc.pDepthStencilAttachment = &depthRef; - } - - if (resolveRefCount) { - subpassDesc.pResolveAttachments = resolveRefs; - } - - VkRenderPassCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - createInfo.attachmentCount = info->attachmentCount; - createInfo.pAttachments = attachments; - createInfo.subpassCount = 1; - createInfo.pSubpasses = &subpassDesc; - createInfo.dependencyCount = 1; - createInfo.pDependencies = &dependency; - - if (info->multiViewCount > 1) { - createInfo.pNext = &viewCreateInfo; - } - - result = s_Vk.createRenderPass( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &renderPass->handle); - } - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, renderPass); - return vkResultToPal(result); - } - // clamg-format on - - renderPass->device = vkDevice; - renderPass->attachmentCount = info->attachmentCount; - *outRenderPass = (PalRenderPass*)renderPass; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyVkRenderPass(PalRenderPass* renderPass) -{ - RenderPass* vkRenderPass = (RenderPass*)renderPass; - s_Vk.destroyRenderPass( - vkRenderPass->device->handle, - vkRenderPass->handle, - &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, renderPass); -} - -PalResult PAL_CALL createVkRenderPassView( - PalDevice* device, - PalRenderPass* renderPass, - const PalRenderPassViewCreateInfo* info, - PalRenderPassView** outRenderPassView) -{ - VkResult result; - RenderPassView* view = nullptr; - Device* vkDevice = (Device*)device; - RenderPass* vkRenderPass = (RenderPass*)renderPass; - VkImageView attachments[MAX_ATTACHMENTS]; - - memset(attachments, 0, sizeof(VkImageView) * MAX_ATTACHMENTS); - view = palAllocate(s_Vk.allocator, sizeof(RenderPassView), 0); - if (!view) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - Uint32 layers = 0; - Uint32 width = 0; - Uint32 height = 0; - for (int i = 0; i < info->imageViewCount; i++) { - ImageView* tmp = (ImageView*)info->imageViews[i]; - attachments[i] = tmp->handle; - layers = tmp->image->info.depthOrArraySize; - - // find the largest width and height from all image views - if (width < tmp->image->info.width) { - width = tmp->image->info.width; - } - - if (height < tmp->image->info.height) { - height = tmp->image->info.height; - } - } - - if (info->width > width || info->height > height) { - palFree(s_Vk.allocator, view); - return PAL_RESULT_INVALID_ARGUMENT; - } - - VkFramebufferCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - createInfo.attachmentCount = info->imageViewCount; - createInfo.pAttachments = attachments; - createInfo.height = height; - createInfo.width = width; - createInfo.layers = layers; - createInfo.renderPass = vkRenderPass->handle; - - result = s_Vk.createFramebuffer( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &view->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, view); - return vkResultToPal(result); - } - - view->device = vkDevice; - view->width = width; - view->height = height; - *outRenderPassView = (PalRenderPassView*)view; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyVkRenderPassView(PalRenderPassView* view) -{ - RenderPassView* framebuffer = (RenderPassView*)view; - s_Vk.destroyFramebuffer( - framebuffer->device->handle, - framebuffer->handle, - &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, view); -} - // ================================================== // Fence // ================================================== @@ -4988,13 +4605,13 @@ PalResult PAL_CALL resetVkFence(PalFence* fence) return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - VkResult ret = s_Vk.resetFence( + VkResult result = s_Vk.resetFence( vkFence->device->handle, 1, &vkFence->handle); - if (ret != VK_SUCCESS) { - return vkResultToPal(ret); + if (result != VK_SUCCESS) { + return vkResultToPal(result); } return PAL_RESULT_SUCCESS; @@ -5003,11 +4620,11 @@ PalResult PAL_CALL resetVkFence(PalFence* fence) bool PAL_CALL isVkFenceSignaled(PalFence* fence) { Fence* vkFence = (Fence*)fence; - VkResult ret = s_Vk.isFenceSignaled( + VkResult result = s_Vk.isFenceSignaled( vkFence->device->handle, vkFence->handle); - if (ret == VK_SUCCESS) { + if (result == VK_SUCCESS) { return true; } else { return false; @@ -5280,7 +4897,7 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL beginVkCommandBuffer( PalCommandBuffer* cmdBuffer, - PalBeginInfo* info) + PalCommandBufferBeginInfo* info) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; VkRenderPass renderPassHandle = nullptr; @@ -5289,21 +4906,15 @@ PalResult PAL_CALL beginVkCommandBuffer( VkCommandBufferBeginInfo beginInfo = {0}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - VkCommandBufferInheritanceInfo inheritanceInfo = {0}; - inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + VkCommandBufferInheritanceRenderingInfoKHR inheritanceInfo = {0}; + inheritanceInfo.sType = + VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; if (!vkCmdBuffer->primary) { // secondary command buffer - if (info->renderPass && info->view) { - RenderPass* renderPass = (RenderPass*)info->renderPass; - RenderPassView* view = (RenderPassView*)info->view; - renderPassHandle = renderPass->handle; - viewHandle = view->handle; - inheritanceInfo.framebuffer = viewHandle; - inheritanceInfo.renderPass = renderPassHandle; - - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; - beginInfo.pInheritanceInfo = &inheritanceInfo; + if (info->attachmentCount && info->attachmentCount) { + // TODO: + beginInfo.pNext = &inheritanceInfo; } } @@ -5602,58 +5213,57 @@ PalResult PAL_CALL buildVkAccelerationStructure( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL beginRenderPassVk( +PalResult PAL_CALL beginRenderingVk( PalCommandBuffer* cmdBuffer, - PalRenderPassBeginInfo* info) + PalRenderingInfo* info) { - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - RenderPass* renderPass = (RenderPass*)info->renderPass; - RenderPassView* view = (RenderPassView*)info->view; - - if (info->clearValueCount != renderPass->attachmentCount) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - VkRenderPassBeginInfo renderPassBeginInfo = {0}; - renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - VkClearValue tmp[MAX_ATTACHMENTS]; - memset(tmp, 0, sizeof(VkClearValue) * MAX_ATTACHMENTS); - - for (int i = 0; i < info->clearValueCount; i++) { - PalClearValue* clearValue = &info->clearValues[i]; - if (clearValue->depth == 0 && clearValue->stencil == 0) { - // color attachment - tmp[i].color.float32[0] = clearValue->color[0]; - tmp[i].color.float32[1] = clearValue->color[1]; - tmp[i].color.float32[2] = clearValue->color[2]; - tmp[i].color.float32[3] = clearValue->color[3]; - - } else { - // depth/stencil attachment - tmp[i].depthStencil.depth = clearValue->depth; - tmp[i].depthStencil.stencil = clearValue->stencil; - } - } - - renderPassBeginInfo.clearValueCount = info->clearValueCount; - renderPassBeginInfo.pClearValues = tmp; - renderPassBeginInfo.framebuffer = view->handle; - renderPassBeginInfo.renderPass = renderPass->handle; - renderPassBeginInfo.renderArea.extent.width = view->width; - renderPassBeginInfo.renderArea.extent.height = view->height; - - s_Vk.cmdBeginRenderPass( - vkCmdBuffer->handle, - &renderPassBeginInfo, - VK_SUBPASS_CONTENTS_INLINE); + // TODO: + // CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + + // if (info->clearValueCount != renderPass->attachmentCount) { + // return PAL_RESULT_INSUFFICIENT_BUFFER; + // } + + // VkRenderPassBeginInfo renderPassBeginInfo = {0}; + // renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + // VkClearValue tmp[MAX_ATTACHMENTS]; + // memset(tmp, 0, sizeof(VkClearValue) * MAX_ATTACHMENTS); + + // for (int i = 0; i < info->clearValueCount; i++) { + // PalClearValue* clearValue = &info->clearValues[i]; + // if (clearValue->depth == 0 && clearValue->stencil == 0) { + // // color attachment + // tmp[i].color.float32[0] = clearValue->color[0]; + // tmp[i].color.float32[1] = clearValue->color[1]; + // tmp[i].color.float32[2] = clearValue->color[2]; + // tmp[i].color.float32[3] = clearValue->color[3]; + + // } else { + // // depth/stencil attachment + // tmp[i].depthStencil.depth = clearValue->depth; + // tmp[i].depthStencil.stencil = clearValue->stencil; + // } + // } + + // renderPassBeginInfo.clearValueCount = info->clearValueCount; + // renderPassBeginInfo.pClearValues = tmp; + // renderPassBeginInfo.framebuffer = view->handle; + // renderPassBeginInfo.renderPass = renderPass->handle; + // renderPassBeginInfo.renderArea.extent.width = view->width; + // renderPassBeginInfo.renderArea.extent.height = view->height; + + // s_Vk.cmdBeginRenderPass( + // vkCmdBuffer->handle, + // &renderPassBeginInfo, + // VK_SUBPASS_CONTENTS_INLINE); return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL endRenderPassVk(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL endRenderingVk(PalCommandBuffer* cmdBuffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - s_Vk.cmdEndRenderPass(vkCmdBuffer->handle); + vkCmdBuffer->device->cmdEndRendering(vkCmdBuffer->handle); return PAL_RESULT_SUCCESS; } @@ -5744,7 +5354,7 @@ PalResult PAL_CALL setVkViewport( PalResult PAL_CALL setVkScissors( PalCommandBuffer* cmdBuffer, Uint32 count, - PalScissor* scissors) + PalRect2D* scissors) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; VkRect2D cacheScissor; @@ -5913,7 +5523,7 @@ PalResult PAL_CALL drawIndexedIndirectVk( PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, - PalSubmitInfo* info) + PalCommandBufferSubmitInfo* info) { VkResult result; Int32 waitSemaphoreCount = 0; @@ -6320,40 +5930,6 @@ PalResult PAL_CALL bindVkBufferMemory( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL mapVkMemory( - PalDevice* device, - PalMemory* memory, - Uint64 offset, - Uint64 size, - void** outPtr) -{ - VkResult result; - VkDeviceMemory mem = (VkDeviceMemory)memory; - Device* vkDevice = (Device*)device; - - result = s_Vk.mapMemory( - vkDevice->handle, - mem, - offset, - size, - 0, - outPtr); - - if (result != VK_SUCCESS) { - return vkResultToPal(result); - } - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL unmapVkMemory( - PalDevice* device, - PalMemory* memory) -{ - VkDeviceMemory mem = (VkDeviceMemory)memory; - Device* vkDevice = (Device*)device; - s_Vk.unmapMemory(vkDevice->handle, mem); -} - // ================================================== // Pipeline // ================================================== @@ -6410,7 +5986,6 @@ PalResult PAL_CALL createVkGraphicsPipeline( Uint32 patchControlPoints = 0; Pipeline* pipeline = nullptr; Device* vkDevice = (Device*)device; - RenderPass* renderPass = (RenderPass*)info->renderPass; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; VkPipelineShaderStageCreateInfo shaderStages[7]; // PAL supports 7 types @@ -6419,40 +5994,41 @@ PalResult PAL_CALL createVkGraphicsPipeline( VkVertexInputAttributeDescription* attribDescs = nullptr; VkPipelineColorBlendAttachmentState* blendattachments = nullptr; - VkPipelineVertexInputStateCreateInfo VI = {0}; - VI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + // clang-format off + VkPipelineVertexInputStateCreateInfo vertexInputState = {0}; + vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - VkPipelineInputAssemblyStateCreateInfo IA = {0}; - IA.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {0}; + inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - VkPipelineDynamicStateCreateInfo DS = {0}; - DS.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + VkPipelineDynamicStateCreateInfo dynamicState = {0}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - VkPipelineRasterizationStateCreateInfo RS = {0}; - RS.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + VkPipelineRasterizationStateCreateInfo rasterizerState = {0}; + rasterizerState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - VkPipelineMultisampleStateCreateInfo MS = {0}; - MS.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + VkPipelineMultisampleStateCreateInfo multisampleState = {0}; + multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - VkPipelineDepthStencilStateCreateInfo SS = {0}; - SS.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + VkPipelineDepthStencilStateCreateInfo depthStencilState = {0}; + depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - VkPipelineColorBlendStateCreateInfo CBS = {0}; - CBS.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + VkPipelineColorBlendStateCreateInfo colorBlendState = {0}; + colorBlendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - VkPipelineTessellationStateCreateInfo TS = {0}; - TS.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + VkPipelineTessellationStateCreateInfo tessellationState = {0}; + tessellationState.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - VkPipelineViewportStateCreateInfo VS = {0}; - VS.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + VkPipelineViewportStateCreateInfo viewportState = {0}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - VkPipelineFragmentShadingRateStateCreateInfoKHR FSRS = {0}; - FSRS.sType = - VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; + VkPipelineFragmentShadingRateStateCreateInfoKHR fragmentShadingRateState = {0}; + fragmentShadingRateState.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; VkGraphicsPipelineCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + // clang-format on pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); if (!pipeline) { return PAL_RESULT_OUT_OF_MEMORY; @@ -6465,8 +6041,8 @@ PalResult PAL_CALL createVkGraphicsPipeline( shaderStages[i] = tmp->info; if (tmp->patchControlPoints) { - TS.patchControlPoints = tmp->patchControlPoints; - createInfo.pTessellationState = &TS; + tessellationState.patchControlPoints = tmp->patchControlPoints; + createInfo.pTessellationState = &tessellationState; if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { palFree(s_Vk.allocator, pipeline); @@ -6475,6 +6051,9 @@ PalResult PAL_CALL createVkGraphicsPipeline( } } + createInfo.stageCount = info->shaderCount; + createInfo.pStages = shaderStages; + // Vertex input state // get the max size of vertex attributes in all layouts Uint32 vertexCount = 0; @@ -6525,16 +6104,14 @@ PalResult PAL_CALL createVkGraphicsPipeline( attribDesc->offset = offset; offset += size; bindingDesc->stride += size; - - int a = 1; } } - VI.pVertexAttributeDescriptions = attribDescs; - VI.vertexAttributeDescriptionCount = vertexCount; - VI.pVertexBindingDescriptions = bindingDescs; - VI.vertexBindingDescriptionCount = info->vertexLayoutCount; - createInfo.pVertexInputState = &VI; + vertexInputState.pVertexAttributeDescriptions = attribDescs; + vertexInputState.vertexAttributeDescriptionCount = vertexCount; + vertexInputState.pVertexBindingDescriptions = bindingDescs; + vertexInputState.vertexBindingDescriptionCount = info->vertexLayoutCount; + createInfo.pVertexInputState = &vertexInputState; // Input assembly VkPrimitiveTopology topology; @@ -6565,8 +6142,9 @@ PalResult PAL_CALL createVkGraphicsPipeline( } } - IA.topology = topology; - IA.primitiveRestartEnable = VK_FALSE; + inputAssemblyState.topology = topology; + inputAssemblyState.primitiveRestartEnable = VK_FALSE; + createInfo.pInputAssemblyState = &inputAssemblyState; // Dynamic states Uint32 dynCount = 0; @@ -6601,80 +6179,99 @@ PalResult PAL_CALL createVkGraphicsPipeline( dynamicStates[dynCount++] = VK_DYNAMIC_STATE_STENCIL_OP_EXT; } - if (info->fragmentShadingRateEnabled) { + if (info->fragmentShadingRateState) { dynamicStates[dynCount++] = VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR; } - DS.dynamicStateCount = dynCount; - DS.pDynamicStates = dynamicStates; - createInfo.pDynamicState = &DS; + dynamicState.dynamicStateCount = dynCount; + dynamicState.pDynamicStates = dynamicStates; + createInfo.pDynamicState = &dynamicState; // Rasterizer state - RS.lineWidth = 1.0f; - if (info->rasterizerState.cullMode == PAL_CULL_MODE_NONE) { - RS.cullMode = VK_CULL_MODE_NONE; - } else if (info->rasterizerState.cullMode == PAL_CULL_MODE_BACK) { - RS.cullMode = VK_CULL_MODE_BACK_BIT; - } else if (info->rasterizerState.cullMode == PAL_CULL_MODE_FRONT) { - RS.cullMode = VK_CULL_MODE_FRONT_BIT; - } + if (info->rasterizerState) { + PalRasterizerState* state = info->rasterizerState; + if (state->cullMode == PAL_CULL_MODE_NONE) { + rasterizerState.cullMode = VK_CULL_MODE_NONE; - if (info->rasterizerState.polygonMode == PAL_POLYGON_MODE_FILL) { - RS.polygonMode = VK_POLYGON_MODE_FILL; - } else { - RS.polygonMode = VK_POLYGON_MODE_LINE; - } + } else if (state->cullMode == PAL_CULL_MODE_BACK) { + rasterizerState.cullMode = VK_CULL_MODE_BACK_BIT; - if (info->rasterizerState.frontFace == PAL_FRONT_FACE_CLOCKWISE) { - RS.frontFace = VK_FRONT_FACE_CLOCKWISE; - } else { - RS.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - } + } else if (state->cullMode == PAL_CULL_MODE_FRONT) { + rasterizerState.cullMode = VK_CULL_MODE_FRONT_BIT; + } + + if (state->polygonMode == PAL_POLYGON_MODE_FILL) { + rasterizerState.polygonMode = VK_POLYGON_MODE_FILL; - RS.depthBiasEnable = info->rasterizerState.enableDepthBias; - RS.depthClampEnable = info->rasterizerState.enableDepthClamp; + } else { + rasterizerState.polygonMode = VK_POLYGON_MODE_LINE; + } + + if (state->frontFace == PAL_FRONT_FACE_CLOCKWISE) { + rasterizerState.frontFace = VK_FRONT_FACE_CLOCKWISE; + + } else { + rasterizerState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + } + + rasterizerState.lineWidth = 1.0f; + rasterizerState.depthBiasEnable = state->enableDepthBias; + rasterizerState.depthClampEnable = state->enableDepthClamp; + createInfo.pRasterizationState = &rasterizerState; + } // Multisample state - MS.alphaToCoverageEnable = info->multisampleState.enableAlphaToCoverage; - MS.minSampleShading = info->multisampleState.minSampleShading; - MS.sampleShadingEnable = info->multisampleState.enableSampleShading; - MS.rasterizationSamples = samplesToVk(info->multisampleState.sampleCount); - - VkSampleMask sampleMasks[2]; - Uint32 mask1 = 0; - Uint32 mask2 = 0; - palUnpackUint32(info->multisampleState.sampleMask, &mask1, &mask2); - sampleMasks[0] = mask1; - sampleMasks[1] = mask2; - MS.pSampleMask = sampleMasks; + if (info->multisampleState) { + PalMultisampleState* state = info->multisampleState; + multisampleState.alphaToCoverageEnable = state->enableAlphaToCoverage; + multisampleState.minSampleShading = state->minSampleShading; + multisampleState.sampleShadingEnable = state->enableSampleShading; + multisampleState.rasterizationSamples = samplesToVk(state->sampleCount); + + VkSampleMask sampleMasks[2]; + Uint32 mask1 = 0; + Uint32 mask2 = 0; + palUnpackUint32(state->sampleMask, &mask1, &mask2); + sampleMasks[0] = mask1; + sampleMasks[1] = mask2; + multisampleState.pSampleMask = sampleMasks; + + createInfo.pMultisampleState = &multisampleState; + } // Depth stencil state - const PalStencilOpState* front = nullptr; - const PalStencilOpState* back = nullptr; - back = &info->depthStencilState.backStencilOpState; - front = &info->depthStencilState.frontStencilOpState; - - SS.back.compareOp = compareOpToVk(back->compareOp); - SS.back.depthFailOp = stencilOpToVk(back->depthFailOp); - SS.back.failOp = stencilOpToVk(back->failOp); - SS.back.passOp = stencilOpToVk(back->passOp); - - SS.front.compareOp = compareOpToVk(front->compareOp); - SS.front.depthFailOp = stencilOpToVk(front->depthFailOp); - SS.front.failOp = stencilOpToVk(front->failOp); - SS.front.passOp = stencilOpToVk(front->passOp); - - SS.depthCompareOp = compareOpToVk(info->depthStencilState.compareOp); - SS.depthTestEnable = info->depthStencilState.enableDepthTest; - SS.depthWriteEnable = info->depthStencilState.enableDepthWrite; - SS.stencilTestEnable = info->depthStencilState.enableStencilTest; + if (info->depthStencilState) { + PalDepthStencilState* state = info->depthStencilState; + PalStencilOpState* back = &state->backStencilOpState; + PalStencilOpState* front = &state->frontStencilOpState; + + VkStencilOpState* vkBack = &depthStencilState.back; + VkStencilOpState* vkFront = &depthStencilState.back; + + vkBack->compareOp = compareOpToVk(back->compareOp); + vkBack->depthFailOp = stencilOpToVk(back->depthFailOp); + vkBack->failOp = stencilOpToVk(back->failOp); + vkBack->passOp = stencilOpToVk(back->passOp); + + vkFront->compareOp = compareOpToVk(front->compareOp); + vkFront->depthFailOp = stencilOpToVk(front->depthFailOp); + vkFront->failOp = stencilOpToVk(front->failOp); + vkFront->passOp = stencilOpToVk(front->passOp); + + depthStencilState.depthCompareOp = compareOpToVk(state->compareOp); + depthStencilState.depthTestEnable = state->enableDepthTest; + depthStencilState.depthWriteEnable = state->enableDepthWrite; + depthStencilState.stencilTestEnable = state->enableStencilTest; + createInfo.pDepthStencilState = &depthStencilState; + } + // Color blend state - CBS.attachmentCount = info->blendAttachmentCount; if (info->blendAttachmentCount) { + Uint32 count = info->blendAttachmentCount; blendattachments = palAllocate( s_Vk.allocator, - sizeof(VkPipelineColorBlendAttachmentState) * CBS.attachmentCount, + sizeof(VkPipelineColorBlendAttachmentState) * count, 0); if (!blendattachments) { @@ -6684,7 +6281,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( return PAL_RESULT_OUT_OF_MEMORY; } - for (int i = 0; i < CBS.attachmentCount; i++) { + for (int i = 0; i < count; i++) { VkPipelineColorBlendAttachmentState* tmp = &blendattachments[i]; PalBlendAttachment* desc = &info->blendAttachments[i]; @@ -6720,35 +6317,30 @@ PalResult PAL_CALL createVkGraphicsPipeline( tmp->colorWriteMask |= VK_COLOR_COMPONENT_A_BIT; } } + + colorBlendState.attachmentCount = count; + colorBlendState.pAttachments = blendattachments; + createInfo.pColorBlendState = &colorBlendState; } - CBS.pAttachments = blendattachments; // viewport state - VS.viewportCount = 1; - VS.scissorCount = 1; + viewportState.viewportCount = 1; + viewportState.scissorCount = 1; + createInfo.pViewportState = &viewportState; - createInfo.stageCount = info->shaderCount; - createInfo.pStages = shaderStages; - createInfo.pVertexInputState = &VI; - createInfo.pInputAssemblyState = &IA; - createInfo.pDepthStencilState = &SS; - createInfo.pDynamicState = &DS; - createInfo.pRasterizationState = &RS; - createInfo.pMultisampleState = &MS; - createInfo.pColorBlendState = &CBS; - createInfo.pViewportState = &VS; - createInfo.renderPass = renderPass->handle; + createInfo.renderPass = VK_NULL_HANDLE; createInfo.layout = layout->handle; - if (info->fragmentShadingRateEnabled) { - FSRS.combinerOps[0] = - combinerOpsToVk(info->fragmentShadingRateState.combinerOps[0]); - FSRS.combinerOps[1] = - combinerOpsToVk(info->fragmentShadingRateState.combinerOps[1]); - FSRS.fragmentSize = - getShadingRateSize(info->fragmentShadingRateState.rate); + if (info->fragmentShadingRateState) { + // TODO: + // FSRS.combinerOps[0] = + // combinerOpsToVk(info->fragmentShadingRateState.combinerOps[0]); + // FSRS.combinerOps[1] = + // combinerOpsToVk(info->fragmentShadingRateState.combinerOps[1]); + // FSRS.fragmentSize = + // getShadingRateSize(info->fragmentShadingRateState.rate); - createInfo.pNext = &FSRS; + // createInfo.pNext = &FSRS; } result = s_Vk.createGraphicsPipeline( diff --git a/tests/graphics_test.c b/tests/graphics_test.c index e1256e94..96248f1e 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -184,10 +184,6 @@ bool graphicsTest() palLog(nullptr, " Multi viewport"); } - if (features & PAL_ADAPTER_FEATURE_SEMAPHORE) { - palLog(nullptr, " Semaphore"); - } - if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { palLog(nullptr, " Timeline Semaphore"); } diff --git a/tests/tests.lua b/tests/tests.lua index 2cb1bff1..9055f2ca 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -71,8 +71,8 @@ project "tests" if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { - "clear_color_test.c", - "triangle_test.c" + --"clear_color_test.c", + --"triangle_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index ebfc9435..abd19cdb 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,12 +55,12 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); + registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest("Clear Color Test", clearColorTest); - registerTest("Triangle Test", triangleTest); + // registerTest("Triangle Test", triangleTest); #endif // runTests(); From b2ae16b706af399ff0393cd0c5ebacdd9301d812 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 6 Jan 2026 17:10:30 +0000 Subject: [PATCH 073/372] update clear color test with new graphics API --- include/pal/pal_graphics.h | 134 ++++--- src/graphics/pal_graphics.c | 135 +++++-- src/graphics/pal_vulkan.c | 774 ++++++++++++++++++++++++++++-------- tests/clear_color_test.c | 509 +++++++++++++----------- tests/graphics_test.c | 8 - tests/tests.lua | 2 +- tests/tests_main.c | 4 +- 7 files changed, 1068 insertions(+), 498 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 9d35ac4e..bb706e93 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -241,22 +241,20 @@ typedef enum { PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(15), PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16), PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY = PAL_BIT64(17), - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT = PAL_BIT64(18), - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE = PAL_BIT64(19), - PAL_ADAPTER_FEATURE_FENCE_RESET = PAL_BIT64(20), - PAL_ADAPTER_FEATURE_FENCE_TIMEOUT = PAL_BIT64(21), - PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE = PAL_BIT64(22), - PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE = PAL_BIT64(23), - PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE = PAL_BIT64(24), - PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY = PAL_BIT64(25), - PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE = PAL_BIT64(26), - PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(27), - PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(28), - PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(29), - PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT = PAL_BIT64(31), - PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(32), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(33) + PAL_ADAPTER_FEATURE_FENCE_RESET = PAL_BIT64(18), + PAL_ADAPTER_FEATURE_FENCE_TIMEOUT = PAL_BIT64(19), + PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE = PAL_BIT64(20), + PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE = PAL_BIT64(21), + PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE = PAL_BIT64(22), + PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY = PAL_BIT64(23), + PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE = PAL_BIT64(24), + PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(25), + PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(26), + PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(27), + PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(28), + PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT = PAL_BIT64(29), + PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(30), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(31) } PalAdapterFeatures; typedef enum { @@ -314,12 +312,6 @@ typedef enum { PAL_SHADER_STAGE_TESSELLATION_EVALUATION } PalShaderStage; -typedef enum { - PAL_ATTACHMENT_TYPE_COLOR, - PAL_ATTACHMENT_TYPE_DEPTH, - PAL_ATTACHMENT_TYPE_FRAGMENT_SHADING_RATE -} PalAttachmentType; - typedef enum { PAL_SAMPLE_COUNT_1, PAL_SAMPLE_COUNT_2, @@ -529,6 +521,15 @@ enum PalDebugMessageType { PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE }; +typedef enum { + PAL_IMAGE_VIEW_STATE_UNDEFINED, + PAL_IMAGE_VIEW_STATE_PRESENT, + PAL_IMAGE_VIEW_STATE_COLOR_ATTACHMENT, + PAL_IMAGE_VIEW_STATE_DEPTH_ATTACHMENT, + PAL_IMAGE_VIEW_STATE_STENCIL_ATTACHMENT, + PAL_IMAGE_VIEW_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT +} PalImageViewState; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -647,18 +648,13 @@ typedef struct { } PalClearValue; typedef struct { - PalAttachmentType type; - PalFormat format; - PalSampleCount sampleCount; PalLoadOp loadOp; PalStoreOp storeOp; - PalLoadOp stencilLoadOp; - PalStoreOp stencilStoreOp; PalResolveMode resolveMode; - PalResolveMode stencilResolveMode; Uint32 texelWidth; Uint32 texelHeight; PalImageView* imageView; + PalImageView* resolveImageView; PalClearValue clearValue; } PalAttachmentDesc; @@ -701,22 +697,21 @@ typedef struct { } PalSwapchainNextImageInfo; typedef struct { + Uint32 imageIndex; Uint64 waitValue; - PalImage* image; PalSemaphore* waitSemaphore; } PalSwapchainPresentInfo; typedef struct { - Uint32 attachmentCount; - PalAttachmentDesc* attachments; -} PalCommandBufferBeginInfo; - -typedef struct { + Uint32 viewCount; Uint32 layerCount; Uint32 colorAttachentCount; - PalAttachmentDesc* colorAttachment; + PalSampleCount multisampleCount; + PalAttachmentDesc* colorAttachments; PalAttachmentDesc* depthAttachment; PalAttachmentDesc* stencilAttachment; + PalAttachmentDesc* fragmentShadingRateAttachment; + PalRect2D renderArea; } PalRenderingInfo; typedef struct { @@ -887,12 +882,6 @@ typedef struct { Uint64 bytecodeSize; } PalShaderCreateInfo; -typedef struct { - bool transient; - bool resettable; - PalQueue* queue; -} PalCommandPoolCreateInfo; - typedef struct { PalBufferUsages usages; Uint64 size; @@ -946,6 +935,8 @@ typedef struct { void PAL_CALL (*destroyDevice)(PalDevice* device); + PalResult PAL_CALL (*waitDevice)(PalDevice* device); + PalResult PAL_CALL (*allocateMemory)( PalDevice* device, PalMemoryType type, @@ -994,6 +985,8 @@ typedef struct { PalQueue* queue, PalGraphicsWindow* window); + PalResult PAL_CALL (*waitQueue)(PalQueue* queue); + PalResult PAL_CALL (*enumerateFormats)( PalAdapter* adapter, Int32* count, @@ -1057,11 +1050,10 @@ typedef struct { PalSwapchain* swapchain, Int32 index); - PalImage* PAL_CALL (*getNextSwapchainImage)( + PalResult PAL_CALL (*getNextSwapchainImage)( PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info); - - PalFormat PAL_CALL (*getSwapchainFormat)(PalSwapchain* swapchain); + PalSwapchainNextImageInfo* info, + Uint32 *outIndex); PalResult PAL_CALL (*presentSwapchain)( PalSwapchain* swapchain, @@ -1076,6 +1068,7 @@ typedef struct { PalResult PAL_CALL (*createFence)( PalDevice* device, + bool signaled, PalFence** outFence); void PAL_CALL (*destroyFence)(PalFence* fence); @@ -1111,7 +1104,7 @@ typedef struct { PalResult PAL_CALL (*createCommandPool)( PalDevice* device, - const PalCommandPoolCreateInfo* info, + PalQueue* queue, PalCommandPool** outPool); void PAL_CALL (*destroyCommandPool)(PalCommandPool* pool); @@ -1125,11 +1118,13 @@ typedef struct { void PAL_CALL (*destroyCommandBuffer)(PalCommandBuffer* cmdBuffer); PalResult PAL_CALL (*beginCommandBuffer)( - PalCommandBuffer* cmdBuffer, - PalCommandBufferBeginInfo* info); + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info); PalResult PAL_CALL (*endCommandBuffer)(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL (*resetCommandBuffer)(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL (*executeCommandBuffer)( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -1225,6 +1220,12 @@ typedef struct { Uint64 offset, Uint32 count); + PalResult PAL_CALL (*imageViewBarrier)( + PalCommandBuffer* cmdBuffer, + PalImageView* imageView, + PalImageViewState oldState, + PalImageViewState newState); + PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -1303,6 +1304,8 @@ PAL_API PalResult PAL_CALL palCreateDevice( PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); +PAL_API PalResult PAL_CALL palWaitDevice(PalDevice* device); + PAL_API PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, @@ -1351,6 +1354,8 @@ PAL_API bool PAL_CALL palCanQueuePresent( PalQueue* queue, PalGraphicsWindow* window); +PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); + PAL_API PalResult PAL_CALL palEnumerateFormats( PalAdapter* adapter, Int32* count, @@ -1414,11 +1419,10 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, Int32 index); -PAL_API PalImage* PAL_CALL palGetNextSwapchainImage( +PAL_API PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info); - -PAL_API PalFormat PAL_CALL palGetSwapchainFormat(PalSwapchain* swapchain); + PalSwapchainNextImageInfo* info, + Uint32 *outIndex); PAL_API PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, @@ -1431,15 +1435,9 @@ PAL_API PalResult PAL_CALL palCreateShader( PAL_API void PAL_CALL palDestroyShader(PalShader* shader); -PAL_API PalResult PAL_CALL palCreateCommandPool( - PalDevice* device, - const PalCommandPoolCreateInfo* info, - PalCommandPool** outPool); - -PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); - PAL_API PalResult PAL_CALL palCreateFence( PalDevice* device, + bool signaled, PalFence** outFence); PAL_API void PAL_CALL palDestroyFence(PalFence* fence); @@ -1473,6 +1471,13 @@ PAL_API PalResult PAL_CALL palGetSemaphoreValue( PalSemaphore* semaphore, Uint64* value); +PAL_API PalResult PAL_CALL palCreateCommandPool( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool); + +PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); + PAL_API PalResult PAL_CALL palCreateCommandBuffer( PalDevice* device, PalCommandPool* pool, @@ -1483,10 +1488,13 @@ PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); PAL_API PalResult PAL_CALL palBeginCommandBuffer( PalCommandBuffer* cmdBuffer, - PalCommandBufferBeginInfo* info); + // only used for secomdary command buffers + PalRenderingInfo* info); PAL_API PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer); +PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); + PAL_API PalResult PAL_CALL palExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -1582,6 +1590,12 @@ PAL_API PalResult PAL_CALL palDrawIndexedIndirect( Uint64 offset, Uint32 count); +PAL_API PalResult PAL_CALL palImageViewBarrier( + PalCommandBuffer* cmdBuffer, + PalImageView* imageView, + PalImageViewState oldState, + PalImageViewState newState); + PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index bf5292a5..b4a33ca6 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -104,6 +104,8 @@ PalResult PAL_CALL createVkDevice( void PAL_CALL destroyVkDevice(PalDevice* device); +PalResult PAL_CALL waitVkDevice(PalDevice* device); + PalResult PAL_CALL allocateVkMemory( PalDevice* device, PalMemoryType type, @@ -137,6 +139,8 @@ PalResult PAL_CALL createVkQueue( void PAL_CALL destroyVkQueue(PalQueue* queue); +PalResult PAL_CALL waitVkQueue(PalQueue* queue); + bool PAL_CALL canVkQueuePresent( PalQueue* queue, PalGraphicsWindow* window); @@ -204,11 +208,10 @@ PalImage* PAL_CALL getVkSwapchainImage( PalSwapchain* swapchain, Int32 index); -PalImage* PAL_CALL getVkNextSwapchainImage( +PalResult PAL_CALL getVkNextSwapchainImage( PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info); - -PalFormat PAL_CALL getVkSwapchainFormat(PalSwapchain* swapchain); + PalSwapchainNextImageInfo* info, + Uint32* outIndex); PalResult PAL_CALL presentVkSwapchain( PalSwapchain* swapchain, @@ -223,6 +226,7 @@ void PAL_CALL destroyVkShader(PalShader* shader); PalResult PAL_CALL createVkFence( PalDevice* device, + bool signaled, PalFence** outFence); void PAL_CALL destroyVkFence(PalFence* fence); @@ -258,11 +262,13 @@ PalResult PAL_CALL getVkSemaphoreValue( PalResult PAL_CALL createVkCommandPool( PalDevice* device, - const PalCommandPoolCreateInfo* info, + PalQueue* queue, PalCommandPool** outPool); void PAL_CALL destroyVkCommandPool(PalCommandPool* pool); +PalResult PAL_CALL resetVkCommandPool(PalCommandPool* pool); + PalResult PAL_CALL createVkCommandBuffer( PalDevice* device, PalCommandPool* pool, @@ -273,10 +279,12 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); PalResult PAL_CALL beginVkCommandBuffer( PalCommandBuffer* cmdBuffer, - PalCommandBufferBeginInfo* info); + PalRenderingInfo* info); PalResult PAL_CALL endVkCommandBuffer(PalCommandBuffer* cmdBuffer); +PalResult PAL_CALL resetVkCommandBuffer(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -372,6 +380,12 @@ PalResult PAL_CALL drawIndexedIndirectVk( Uint64 offset, Uint32 count); +PalResult PAL_CALL imageViewBarrierVk( + PalCommandBuffer* cmdBuffer, + PalImageView* imageView, + PalImageViewState oldstate, + PalImageViewState newstate); + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -437,6 +451,7 @@ static PalGraphicsBackend s_VkBackend = { .getAdapterFeatures = getVkAdapterFeatures, .createDevice = createVkDevice, .destroyDevice = destroyVkDevice, + .waitDevice = waitVkDevice, .allocateMemory = allocateVkMemory, .freeMemory = freeVkMemory, .mapMemory = mapVkMemory, @@ -447,6 +462,7 @@ static PalGraphicsBackend s_VkBackend = { .queryRayTracingCapabilities = queryVkRayTracingCapabilities, .createQueue = createVkQueue, .destroyQueue = destroyVkQueue, + .waitQueue = waitVkQueue, .canQueuePresent = canVkQueuePresent, .enumerateFormats = enumerateVkFormats, .isFormatSupported = isVkFormatSupported, @@ -464,7 +480,6 @@ static PalGraphicsBackend s_VkBackend = { .destroySwapchain = destroyVkSwapchain, .getSwapchainImage = getVkSwapchainImage, .getNextSwapchainImage = getVkNextSwapchainImage, - .getSwapchainFormat = getVkSwapchainFormat, .presentSwapchain = presentVkSwapchain, .createShader = createVkShader, .destroyShader = destroyVkShader, @@ -484,6 +499,7 @@ static PalGraphicsBackend s_VkBackend = { .destroyCommandBuffer = destroyVkCommandBuffer, .beginCommandBuffer = beginVkCommandBuffer, .endCommandBuffer = endVkCommandBuffer, + .resetCommandBuffer = resetVkCommandBuffer, .executeCommandBuffer = executeCommandBufferVk, .setFragmentShadingRate = setVkFragmentShadingRate, .drawMeshTasks = drawVkMeshTasks, @@ -502,6 +518,7 @@ static PalGraphicsBackend s_VkBackend = { .drawIndirect = drawIndirectVk, .drawIndexed = drawIndexedVk, .drawIndexedIndirect = drawIndexedIndirectVk, + .imageViewBarrier = imageViewBarrierVk, .submitCommandBuffer = submitVkCommandBuffer, .createAccelerationstructure = createVkAccelerationstructure, .destroyAccelerationstructure = destroyVkAccelerationstructure, @@ -556,6 +573,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->getAdapterFeatures || !backend->createDevice || !backend->destroyDevice || + !backend->waitDevice || !backend->allocateMemory || !backend->freeMemory || !backend->queryDepthStencilCapabilities || @@ -564,6 +582,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->queryRayTracingCapabilities || !backend->createQueue || !backend->destroyQueue || + !backend->waitQueue || !backend->canQueuePresent || !backend->enumerateFormats || !backend->isFormatSupported || @@ -581,7 +600,6 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroySwapchain || !backend->getSwapchainImage || !backend->getNextSwapchainImage || - !backend->getSwapchainFormat || !backend->presentSwapchain || !backend->createShader || !backend->destroyShader || @@ -601,6 +619,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroyCommandBuffer || !backend->beginCommandBuffer || !backend->endCommandBuffer || + !backend->resetCommandBuffer || !backend->executeCommandBuffer || !backend->setFragmentShadingRate || !backend->drawMeshTasks || @@ -619,6 +638,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->drawIndirect || !backend->drawIndexed || !backend->drawIndexedIndirect || + !backend->imageViewBarrier || !backend->submitCommandBuffer || !backend->createAccelerationstructure || !backend->destroyAccelerationstructure || @@ -836,6 +856,19 @@ void PAL_CALL palDestroyDevice(PalDevice* device) } } +PalResult PAL_CALL palWaitDevice(PalDevice* device) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->waitDevice(device); +} + PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, @@ -982,6 +1015,19 @@ bool PAL_CALL palCanQueuePresent( return false; } +PalResult PAL_CALL palWaitQueue(PalQueue* queue) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!queue) { + return PAL_RESULT_NULL_POINTER; + } + + return queue->backend->waitQueue(queue); +} + // ================================================== // Format And Usages // ================================================== @@ -1246,25 +1292,23 @@ PalImage* PAL_CALL palGetSwapchainImage( return swapchain->backend->getSwapchainImage(swapchain, index); } -PalImage* PAL_CALL palGetNextSwapchainImage( +PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info) + PalSwapchainNextImageInfo* info, + Uint32 *outIndex) { - if (!s_Graphics.initialized || !swapchain || !info) { - return nullptr; + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!swapchain || !info) { + return PAL_RESULT_NULL_POINTER; } return swapchain->backend->getNextSwapchainImage( swapchain, - info); -} - -PalFormat PAL_CALL palGetSwapchainFormat(PalSwapchain* swapchain) -{ - if (!s_Graphics.initialized || !swapchain) { - return PAL_FORMAT_UNDEFINED; - } - return swapchain->backend->getSwapchainFormat(swapchain); + info, + outIndex); } PalResult PAL_CALL palPresentSwapchain( @@ -1330,6 +1374,7 @@ void PAL_CALL palDestroyShader(PalShader* shader) PalResult PAL_CALL palCreateFence( PalDevice* device, + bool signaled, PalFence** outFence) { if (!s_Graphics.initialized) { @@ -1342,7 +1387,7 @@ PalResult PAL_CALL palCreateFence( PalFence* fence = nullptr; PalResult result; - result = device->backend->createFence(device, &fence); + result = device->backend->createFence(device, signaled, &fence); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1493,18 +1538,14 @@ PalResult PAL_CALL palGetSemaphoreValue( PalResult PAL_CALL palCreateCommandPool( PalDevice* device, - const PalCommandPoolCreateInfo* info, + PalQueue* queue, PalCommandPool** outPool) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device || !info || !outPool) { - return PAL_RESULT_NULL_POINTER; - } - - if (!info->queue) { + if (!device || !queue || !outPool) { return PAL_RESULT_NULL_POINTER; } @@ -1512,7 +1553,7 @@ PalResult PAL_CALL palCreateCommandPool( PalResult result; result = device->backend->createCommandPool( device, - info, + queue, &pool); if (result != PAL_RESULT_SUCCESS) { @@ -1571,7 +1612,7 @@ void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL palBeginCommandBuffer( PalCommandBuffer* cmdBuffer, - PalCommandBufferBeginInfo* info) + PalRenderingInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1597,6 +1638,19 @@ PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer) return cmdBuffer->backend->endCommandBuffer(cmdBuffer); } +PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->resetCommandBuffer(cmdBuffer); +} + PalResult PAL_CALL palExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) @@ -1949,6 +2003,27 @@ PalResult PAL_CALL palDrawIndexedIndirect( count); } +PAL_API PalResult PAL_CALL palImageViewBarrier( + PalCommandBuffer* cmdBuffer, + PalImageView* imageView, + PalImageViewState oldState, + PalImageViewState newState) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !imageView) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->imageViewBarrier( + cmdBuffer, + imageView, + oldState, + newState); +} + PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 23ed7022..06f3072e 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -134,8 +134,8 @@ typedef struct { PFN_vkBeginCommandBuffer cmdBegin; PFN_vkEndCommandBuffer cmdEnd; + PFN_vkResetCommandBuffer resetCommandBuffer; PFN_vkCmdExecuteCommands cmdExecuteCommandBuffer; - PFN_vkQueueSubmit queueSubmit; PFN_vkCmdCopyBuffer cmdCopyBuffer; PFN_vkCmdBindPipeline cmdBindPipeline; PFN_vkCmdSetViewport cmdSetViewports; @@ -170,6 +170,9 @@ typedef struct { PFN_vkDestroyPipeline destroyPipeline; PFN_vkCreateDebugUtilsMessengerEXT createMessenger; PFN_vkDestroyDebugUtilsMessengerEXT destroyMessenger; + PFN_vkDeviceWaitIdle waitDevice; + PFN_vkQueueWaitIdle waitQueue; + VkAllocationCallbacks vkAllocator; const PalAllocator* allocator; @@ -232,13 +235,15 @@ typedef struct { // dynamic rendering PFN_vkCmdBeginRendering cmdBeginRendering; PFN_vkCmdEndRendering cmdEndRendering; + PFN_vkCmdPipelineBarrier2 cmdPipelineBarrier; + PFN_vkQueueSubmit2 queueSubmit; } Device; typedef struct { const PalGraphicsBackend* backend; VkQueueFlags usage; - PalDevice* device; + Device* device; PhysicalQueue* phyQueue; } Queue; @@ -246,7 +251,6 @@ typedef struct { const PalGraphicsBackend* backend; bool belongsToSwapchain; - Int32 index; Device* device; VkImage handle; PalImageInfo info; @@ -260,6 +264,7 @@ typedef struct { Device* device; Image* image; VkImageView handle; + VkImageSubresourceRange range; } ImageView; typedef struct { @@ -293,8 +298,9 @@ typedef struct { const PalGraphicsBackend* backend; bool primary; + VkPipelineStageFlagBits2 dstStage; Device* device; - VkCommandPool pool; + CommandPool* pool; VkCommandBuffer handle; } CommandBuffer; @@ -344,6 +350,13 @@ typedef struct { VkPipeline handle; } Pipeline; +typedef struct ImageViewTransition { + VkPipelineStageFlags2 stages; + VkPipelineStageFlags2 dstStagess; + VkAccessFlags2 access; + VkImageLayout layout; +} ImageViewBarrier; + static Vulkan s_Vk = {0}; // ================================================== @@ -1472,6 +1485,108 @@ static VkFragmentShadingRateCombinerOpKHR combinerOpsToVk( return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; } +static VkResolveModeFlagBits resolveModeToVk(PalResolveMode mode) +{ + switch (mode) { + case PAL_RESOLVE_MODE_SAMPLE_ZERO: + return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + + case PAL_RESOLVE_MODE_AVERAGE: + return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + + case PAL_RESOLVE_MODE_MIN: + return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + + case PAL_RESOLVE_MODE_MAX: + return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + } + + return VK_RESOLVE_MODE_NONE_KHR; +} + +static ImageViewBarrier imageViewBarrierToVk(PalImageViewState state) +{ + ImageViewBarrier barrier = {0}; + switch (state) { + case PAL_IMAGE_VIEW_STATE_UNDEFINED: { + barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; + barrier.dstStagess = barrier.dstStagess; + barrier.access = 0; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + + return barrier; + } + + case PAL_IMAGE_VIEW_STATE_PRESENT: { + barrier.stages = + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; + barrier.dstStagess = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; + + barrier.access = 0; + barrier.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + return barrier; + } + + case PAL_IMAGE_VIEW_STATE_COLOR_ATTACHMENT: { + barrier.stages = + VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; + barrier.dstStagess = barrier.stages; + + barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR; + barrier.access |= VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + return barrier; + } + + case PAL_IMAGE_VIEW_STATE_DEPTH_ATTACHMENT: { + barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; + barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; + barrier.dstStagess = barrier.stages; + + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; + barrier.access |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + + return barrier; + } + + case PAL_IMAGE_VIEW_STATE_STENCIL_ATTACHMENT: { + barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; + barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; + barrier.dstStagess = barrier.stages; + + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; + barrier.access |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; + + return barrier; + } + + case PAL_IMAGE_VIEW_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT: { + barrier.stages = + VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; + barrier.dstStagess = barrier.stages; + + barrier.access = + VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; + + barrier.layout = + VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + + return barrier; + } + } + + barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; + barrier.dstStagess = barrier.stages; + barrier.access = 0; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + + return barrier; +} + static void* vkAlloc( void* pUserData, size_t size, @@ -1773,6 +1888,10 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkEndCommandBuffer"); + s_Vk.resetCommandBuffer = (PFN_vkResetCommandBuffer)dlsym( + s_Vk.handle, + "vkResetCommandBuffer"); + s_Vk.cmdExecuteCommandBuffer = (PFN_vkCmdExecuteCommands)dlsym( s_Vk.handle, "vkCmdExecuteCommands"); @@ -1817,10 +1936,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCmdDrawIndexedIndirect"); - s_Vk.queueSubmit = (PFN_vkQueueSubmit)dlsym( - s_Vk.handle, - "vkQueueSubmit"); - s_Vk.createBuffer = (PFN_vkCreateBuffer)dlsym( s_Vk.handle, "vkCreateBuffer"); @@ -1861,6 +1976,14 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroyPipeline"); + s_Vk.waitDevice = (PFN_vkDeviceWaitIdle)dlsym( + s_Vk.handle, + "vkDeviceWaitIdle"); + + s_Vk.waitQueue = (PFN_vkQueueWaitIdle)dlsym( + s_Vk.handle, + "vkQueueWaitIdle"); + // clang-format on // get version @@ -2217,6 +2340,19 @@ PalResult PAL_CALL enumerateVkAdapters( } } + VkPhysicalDeviceDynamicRenderingFeaturesKHR required = {0}; + required.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; + + VkPhysicalDeviceFeatures2KHR features = {0}; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; + features.pNext = &required; + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + + if (!required.dynamicRendering) { + continue; + } + if (outAdapters) { if (adapterCount < *count) { Adapter* tmp = &s_Vk.adapters[adapterCount]; @@ -2712,8 +2848,6 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) // this features are supported on vulkan adapterFeatures |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; adapterFeatures |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; - adapterFeatures |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE; - adapterFeatures |= PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT; adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_TIMEOUT; adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; @@ -2732,7 +2866,7 @@ PalResult PAL_CALL createVkDevice( PalDevice** outDevice) { float priority = 1.0f; - Uint32 count = 0; + Uint32 queueCount = 0; VkResult result = VK_SUCCESS; Device* device = nullptr; VkPhysicalDeviceProperties props = {0}; @@ -2745,17 +2879,17 @@ PalResult PAL_CALL createVkDevice( VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; s_Vk.getPhysicalDeviceQueueFamilyProperties( phyDevice, - &count, + &queueCount, nullptr); queueProps = palAllocate( s_Vk.allocator, - sizeof(VkQueueFamilyProperties) * count, + sizeof(VkQueueFamilyProperties) * queueCount, 0); queueCreateInfos = palAllocate( s_Vk.allocator, - sizeof(VkDeviceQueueCreateInfo) * count, + sizeof(VkDeviceQueueCreateInfo) * queueCount, 0); device = palAllocate(s_Vk.allocator, sizeof(Device), 0); @@ -2764,12 +2898,12 @@ PalResult PAL_CALL createVkDevice( } memset(device, 0, sizeof(Device)); - device->queueCount = count; + device->queueCount = queueCount; device->phyDevice = phyDevice; device->phyQueues = palAllocate( s_Vk.allocator, - sizeof(PhysicalQueue) * count, + sizeof(PhysicalQueue) * queueCount, 0); if (!device->phyQueues) { @@ -2778,10 +2912,10 @@ PalResult PAL_CALL createVkDevice( s_Vk.getPhysicalDeviceQueueFamilyProperties( phyDevice, - &count, + &queueCount, queueProps); - for (int i = 0; i < count; i++) { + for (int i = 0; i < queueCount; i++) { queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfos[i].pNext = nullptr; queueCreateInfos[i].pQueuePriorities = &priority; @@ -2825,6 +2959,7 @@ PalResult PAL_CALL createVkDevice( } // extensions and features2 + void* next = nullptr; int extCount = 0; const char* extensions[16] = {0}; @@ -2861,14 +2996,25 @@ PalResult PAL_CALL createVkDevice( VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; - VkDeviceCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRendering = {0}; + dynamicRendering.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; + + VkPhysicalDeviceSynchronization2FeaturesKHR sync2 = {0}; + sync2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR; // clang-format on if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_KHR_dynamic_rendering"; + extensions[extCount++] = "VK_KHR_synchronization2"; } + dynamicRendering.dynamicRendering = true; + sync2.synchronization2 = true; + + dynamicRendering.pNext = next; + sync2.pNext = &dynamicRendering; + next = &sync2; + if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { extensions[extCount++] = "VK_KHR_swapchain"; } @@ -2881,9 +3027,10 @@ PalResult PAL_CALL createVkDevice( if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_timeline_semaphore"; } - timeline.timelineSemaphore = true; - createInfo.pNext = &timeline; + + timeline.pNext = next; + next = &timeline; } if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { @@ -2892,8 +3039,8 @@ PalResult PAL_CALL createVkDevice( } shader16.shaderFloat16 = true; - shader16.pNext = &createInfo.pNext; - createInfo.pNext = &shader16; + shader16.pNext = next; + next = &shader16; } if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { @@ -2904,9 +3051,9 @@ PalResult PAL_CALL createVkDevice( ray.rayTracingPipeline = true; acc.accelerationStructure = true; - ray.pNext = &createInfo.pNext; - acc.pNext = ray.pNext; - createInfo.pNext = &acc; + ray.pNext = next; + acc.pNext = &ray; + next = &acc; } if ((features & PAL_ADAPTER_FEATURE_MESH_SHADER) || @@ -2923,8 +3070,8 @@ PalResult PAL_CALL createVkDevice( mesh.meshShader = true; mesh.taskShader = true; - mesh.pNext = &createInfo.pNext; - createInfo.pNext = &mesh; + mesh.pNext = next; + next = &mesh; } if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || @@ -2939,8 +3086,8 @@ PalResult PAL_CALL createVkDevice( } } - fsr.pNext = &createInfo.pNext; - createInfo.pNext = &fsr; + fsr.pNext = next; + next = &fsr; } if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { @@ -2949,8 +3096,8 @@ PalResult PAL_CALL createVkDevice( } descIndex.shaderSampledImageArrayNonUniformIndexing = true; - descIndex.pNext = &createInfo.pNext; - createInfo.pNext = &descIndex; + descIndex.pNext = next; + next = &descIndex; } if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { @@ -2959,8 +3106,8 @@ PalResult PAL_CALL createVkDevice( } multiView.multiview = true; - multiView.pNext = &createInfo.pNext; - createInfo.pNext = &multiView; + multiView.pNext = next; + next = &multiView; } if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE || @@ -2971,8 +3118,8 @@ PalResult PAL_CALL createVkDevice( } dynamicState.extendedDynamicState = true; - dynamicState.pNext = &createInfo.pNext; - createInfo.pNext = &dynamicState; + dynamicState.pNext = next; + next = &dynamicState; } if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE || @@ -2981,8 +3128,8 @@ PalResult PAL_CALL createVkDevice( extensions[extCount++] = "VK_EXT_extended_dynamic_state2"; dynamicState2.extendedDynamicState2 = true; - dynamicState2.pNext = &createInfo.pNext; - createInfo.pNext = &dynamicState2; + dynamicState2.pNext = next; + next = &dynamicState2; } if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { @@ -2991,15 +3138,18 @@ PalResult PAL_CALL createVkDevice( } bufferAddress.bufferDeviceAddress = true; - bufferAddress.pNext = &createInfo.pNext; - createInfo.pNext = &bufferAddress; + bufferAddress.pNext = next; + next = &bufferAddress; } + VkDeviceCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pEnabledFeatures = &coreFeatures; createInfo.enabledExtensionCount = extCount; createInfo.ppEnabledExtensionNames = extensions; createInfo.pQueueCreateInfos = queueCreateInfos; - createInfo.queueCreateInfoCount = count; + createInfo.queueCreateInfoCount = queueCount; + createInfo.pNext = next; result = s_Vk.createDevice( phyDevice, @@ -3016,7 +3166,7 @@ PalResult PAL_CALL createVkDevice( } // get queues - for (int i = 0; i < count; i++) { + for (int i = 0; i < queueCount; i++) { VkQueueFamilyProperties* data = &queueProps[i]; for (int j = 0; j < data->queueCount; j++) { PhysicalQueue* queue = &device->phyQueues[i]; @@ -3227,6 +3377,16 @@ PalResult PAL_CALL createVkDevice( device->handle, "vkCmdEndRendering"); + device->cmdPipelineBarrier = + (PFN_vkCmdPipelineBarrier2)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdPipelineBarrier2"); + + device->queueSubmit = + (PFN_vkQueueSubmit2)s_Vk.getDeviceProcAddr( + device->handle, + "vkQueueSubmit2"); + if (!device->cmdBeginRendering) { device->cmdBeginRendering = (PFN_vkCmdBeginRenderingKHR)s_Vk.getDeviceProcAddr( @@ -3237,6 +3397,16 @@ PalResult PAL_CALL createVkDevice( (PFN_vkCmdEndRenderingKHR)s_Vk.getDeviceProcAddr( device->handle, "vkCmdEndRenderingKHR"); + + device->cmdPipelineBarrier = + (PFN_vkCmdPipelineBarrier2KHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdPipelineBarrier2KHR"); + + device->queueSubmit = + (PFN_vkQueueSubmit2KHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkQueueSubmit2KHR"); } device->features = features; @@ -3255,6 +3425,17 @@ void PAL_CALL destroyVkDevice(PalDevice* device) palFree(s_Vk.allocator, vkDevice); } +PalResult PAL_CALL waitVkDevice(PalDevice* device) +{ + Device* vkDevice = (Device*)device; + VkResult result = s_Vk.waitDevice(vkDevice->handle); + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + return PAL_RESULT_SUCCESS; +} + // ================================================== // Memory // ================================================== @@ -3588,7 +3769,7 @@ PalResult PAL_CALL createVkQueue( queue->phyQueue = phyQueue; queue->usage = queueFlag; - queue->device = device; + queue->device = vkDevice; *outQueue = (PalQueue*)queue; return PAL_RESULT_SUCCESS; @@ -3630,6 +3811,17 @@ bool PAL_CALL canVkQueuePresent( return false; } +PalResult PAL_CALL waitVkQueue(PalQueue* queue) +{ + Queue* vkQueue = (Queue*)queue; + VkResult result = s_Vk.waitQueue(vkQueue->phyQueue->handle); + if (result != VK_SUCCESS) { + return vkResultToPal(result); + } + + return PAL_RESULT_SUCCESS; +} + // ================================================== // Formats // ================================================== @@ -3999,6 +4191,7 @@ PalResult PAL_CALL createVkImageView( imageView->image = vkImage; imageView->type = createInfo.viewType; imageView->usages = info->usages; + imageView->range = createInfo.subresourceRange; *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; @@ -4297,7 +4490,6 @@ PalResult PAL_CALL createVkSwapchain( image->belongsToSwapchain = true; image->device = vkDevice; image->handle = images[i]; - image->index = -1; image->info.depthOrArraySize = createInfo.imageArrayLayers; image->info.format = imageFormat; @@ -4346,9 +4538,10 @@ PalImage* PAL_CALL getVkSwapchainImage( return (PalImage*)&vkSwapchain->images[index]; } -PalImage* PAL_CALL getVkNextSwapchainImage( +PalResult PAL_CALL getVkNextSwapchainImage( PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info) + PalSwapchainNextImageInfo* info, + Uint32* outIndex) { VkResult result; Uint32 index = 0; @@ -4375,18 +4568,11 @@ PalImage* PAL_CALL getVkNextSwapchainImage( &index); if (result != VK_SUCCESS) { - return nullptr; + return vkResultToPal(result); } - Image* image = &vkSwapchain->images[index]; - image->index = index; - return (PalImage*)image; -} - -PalFormat PAL_CALL getVkSwapchainFormat(PalSwapchain* swapchain) -{ - Swapchain* vkSwapchain = (Swapchain*)swapchain; - return vkSwapchain->images[0].info.format; + *outIndex = index; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL presentVkSwapchain( @@ -4394,13 +4580,6 @@ PalResult PAL_CALL presentVkSwapchain( PalSwapchainPresentInfo* info) { Swapchain* vkSwapchain = (Swapchain*)swapchain; - Image* vkImage = (Image*)info->image; - if (vkImage->index == -1) { - // image was not the next image - // this prevents UB - return PAL_RESULT_INVALID_IMAGE; - } - Int32 semaphoreCount = 0; VkSemaphore semaphoreHandle = nullptr; if (info->waitSemaphore) { @@ -4414,7 +4593,7 @@ PalResult PAL_CALL presentVkSwapchain( presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = &vkSwapchain->handle; - presentInfo.pImageIndices = &vkImage->index; + presentInfo.pImageIndices = &info->imageIndex; presentInfo.pWaitSemaphores = &semaphoreHandle; presentInfo.waitSemaphoreCount = semaphoreCount; @@ -4426,7 +4605,6 @@ PalResult PAL_CALL presentVkSwapchain( return vkResultToPal(result); } - vkImage->index = -1; return PAL_RESULT_SUCCESS; } @@ -4533,6 +4711,7 @@ void PAL_CALL destroyVkShader(PalShader* shader) PalResult PAL_CALL createVkFence( PalDevice* device, + bool signaled, PalFence** outFence) { VkResult result; @@ -4546,6 +4725,10 @@ PalResult PAL_CALL createVkFence( VkFenceCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + if (signaled) { + createInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + } + result = s_Vk.createFence( vkDevice->handle, &createInfo, @@ -4777,14 +4960,14 @@ PalResult PAL_CALL getVkSemaphoreValue( PalResult PAL_CALL createVkCommandPool( PalDevice* device, - const PalCommandPoolCreateInfo* info, + PalQueue* queue, PalCommandPool** outPool) { VkResult result; CommandPool* pool = nullptr; Device* vkDevice = (Device*)device; - Queue* queue = (Queue*)info->queue; - PhysicalQueue* phyQueue = queue->phyQueue; + Queue* vkQueue = (Queue*)queue; + PhysicalQueue* phyQueue = vkQueue->phyQueue; pool = palAllocate(s_Vk.allocator, sizeof(CommandPool), 0); if (!pool) { @@ -4794,22 +4977,7 @@ PalResult PAL_CALL createVkCommandPool( VkCommandPoolCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; createInfo.queueFamilyIndex = phyQueue->familyIndex; - - if (info->resettable) { - if (!(vkDevice->features & - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - createInfo.flags |= VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - } - - if (info->transient) { - if (!(vkDevice->features & - PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - createInfo.flags |= VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; - } + createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; result = s_Vk.createCommandPool( vkDevice->handle, @@ -4877,7 +5045,7 @@ PalResult PAL_CALL createVkCommandBuffer( } cmdBuffer->device = vkDevice; - cmdBuffer->pool = vkPool->handle; + cmdBuffer->pool = vkPool; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; @@ -4888,7 +5056,7 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.destroyCommandBuffer( vkCmdBuffer->device->handle, - vkCmdBuffer->pool, + vkCmdBuffer->pool->handle, 1, &vkCmdBuffer->handle); @@ -4897,25 +5065,78 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL beginVkCommandBuffer( PalCommandBuffer* cmdBuffer, - PalCommandBufferBeginInfo* info) + PalRenderingInfo* info) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - VkRenderPass renderPassHandle = nullptr; - VkFramebuffer viewHandle = nullptr; - VkCommandBufferBeginInfo beginInfo = {0}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - VkCommandBufferInheritanceRenderingInfoKHR inheritanceInfo = {0}; - inheritanceInfo.sType = + VkCommandBufferInheritanceInfo inheritanceInfo = {0}; + inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + VkCommandBufferInheritanceRenderingInfoKHR tmp = {0}; + tmp.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; + VkRenderingFragmentShadingRateAttachmentInfoKHR fsrInfo = {0}; + fsrInfo.sType = + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; + + VkFormat format = VK_FORMAT_UNDEFINED; + ImageView* imageView = nullptr; + VkFormat colorAttachments[MAX_ATTACHMENTS]; + if (!vkCmdBuffer->primary) { // secondary command buffer - if (info->attachmentCount && info->attachmentCount) { - // TODO: - beginInfo.pNext = &inheritanceInfo; + for (int i = 0; i < info->colorAttachentCount; i++) { + imageView = (ImageView*)info->colorAttachments[i].imageView; + format = palFormatToVk(imageView->image->info.format); + colorAttachments[i] = format; + } + tmp.colorAttachmentCount = info->colorAttachentCount; + tmp.pColorAttachmentFormats = colorAttachments; + + // depth attachment + if (info->depthAttachment) { + imageView = (ImageView*)info->depthAttachment->imageView; + format = palFormatToVk(imageView->image->info.format); + tmp.depthAttachmentFormat = format; + } + + // stencil attachment + if (info->stencilAttachment) { + imageView = (ImageView*)info->stencilAttachment->imageView; + format = palFormatToVk(imageView->image->info.format); + tmp.stencilAttachmentFormat = format; + } + + // fragment shading rate attachment + if (info->fragmentShadingRateAttachment) { + imageView = + (ImageView*)info->fragmentShadingRateAttachment->imageView; + fsrInfo.imageView = imageView->handle; + + fsrInfo.shadingRateAttachmentTexelSize.width = + info->fragmentShadingRateAttachment->texelWidth; + + fsrInfo.shadingRateAttachmentTexelSize.height = + info->fragmentShadingRateAttachment->texelHeight; + + fsrInfo.imageLayout = + VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + + tmp.pNext = &fsrInfo; } + + tmp.rasterizationSamples = samplesToVk(info->multisampleCount); + + if (info->viewCount == 1) { + tmp.viewMask = 0; + } else { + tmp.viewMask = (1 << info->viewCount) - 1; + } + + inheritanceInfo.pNext = &tmp; + beginInfo.pNext = &inheritanceInfo; } VkResult result = s_Vk.cmdBegin(vkCmdBuffer->handle, &beginInfo); @@ -4937,6 +5158,13 @@ PalResult PAL_CALL endVkCommandBuffer(PalCommandBuffer* cmdBuffer) return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL resetVkCommandBuffer(PalCommandBuffer* cmdBuffer) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL executeCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) @@ -5217,46 +5445,194 @@ PalResult PAL_CALL beginRenderingVk( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { - // TODO: - // CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - - // if (info->clearValueCount != renderPass->attachmentCount) { - // return PAL_RESULT_INSUFFICIENT_BUFFER; - // } - - // VkRenderPassBeginInfo renderPassBeginInfo = {0}; - // renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - // VkClearValue tmp[MAX_ATTACHMENTS]; - // memset(tmp, 0, sizeof(VkClearValue) * MAX_ATTACHMENTS); - - // for (int i = 0; i < info->clearValueCount; i++) { - // PalClearValue* clearValue = &info->clearValues[i]; - // if (clearValue->depth == 0 && clearValue->stencil == 0) { - // // color attachment - // tmp[i].color.float32[0] = clearValue->color[0]; - // tmp[i].color.float32[1] = clearValue->color[1]; - // tmp[i].color.float32[2] = clearValue->color[2]; - // tmp[i].color.float32[3] = clearValue->color[3]; - - // } else { - // // depth/stencil attachment - // tmp[i].depthStencil.depth = clearValue->depth; - // tmp[i].depthStencil.stencil = clearValue->stencil; - // } - // } - - // renderPassBeginInfo.clearValueCount = info->clearValueCount; - // renderPassBeginInfo.pClearValues = tmp; - // renderPassBeginInfo.framebuffer = view->handle; - // renderPassBeginInfo.renderPass = renderPass->handle; - // renderPassBeginInfo.renderArea.extent.width = view->width; - // renderPassBeginInfo.renderArea.extent.height = view->height; - - // s_Vk.cmdBeginRenderPass( - // vkCmdBuffer->handle, - // &renderPassBeginInfo, - // VK_SUBPASS_CONTENTS_INLINE); + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + VkRenderingInfoKHR rendering = {0}; + rendering.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR; + + VkRenderingAttachmentInfoKHR depthAttachment = {0}; + VkRenderingAttachmentInfoKHR stencilAttachment = {0}; + VkRenderingAttachmentInfoKHR colorAttachments[MAX_ATTACHMENTS]; + + VkRenderingAttachmentInfoKHR* attachment = nullptr; + PalAttachmentDesc* desc = nullptr; + ImageView* imageView = nullptr; + ImageView* resolveImageView = nullptr; + VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL; + + VkRenderingFragmentShadingRateAttachmentInfoKHR fsrInfo = {0}; + fsrInfo.sType = + VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; + + for (int i = 0; i < info->colorAttachentCount; i++) { + attachment = &colorAttachments[i]; + desc = &info->colorAttachments[i]; + imageView = (ImageView*)desc->imageView; + resolveImageView = (ImageView*)desc->resolveImageView; + + attachment->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; + attachment->pNext = nullptr; + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment->resolveImageView = nullptr; + attachment->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + attachment->clearValue.color.float32[0] = desc->clearValue.color[0]; + attachment->clearValue.color.float32[1] = desc->clearValue.color[1]; + attachment->clearValue.color.float32[2] = desc->clearValue.color[2]; + attachment->clearValue.color.float32[3] = desc->clearValue.color[3]; + + attachment->imageView = imageView->handle; + if (resolveImageView) { + attachment->resolveImageView = resolveImageView->handle; + attachment->resolveImageLayout = layout; + } + + // load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + // store op + if (desc->storeOp == PAL_STORE_OP_STORE) { + attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + + } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { + attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + + attachment->resolveMode = resolveModeToVk(desc->resolveMode); + attachment->imageLayout = layout; + } + + rendering.colorAttachmentCount = info->colorAttachentCount; + rendering.pColorAttachments = colorAttachments; + + // depth attachment + if (info->depthAttachment) { + attachment = &depthAttachment; + desc = info->depthAttachment; + imageView = (ImageView*)desc->imageView; + resolveImageView = (ImageView*)desc->resolveImageView; + + attachment->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; + attachment->pNext = nullptr; + attachment->resolveImageView = nullptr; + attachment->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + attachment->clearValue.depthStencil.depth = desc->clearValue.depth; + layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + + attachment->imageView = imageView->handle; + if (resolveImageView) { + attachment->resolveImageView = resolveImageView->handle; + attachment->resolveImageLayout = layout; + } + + // load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + // store op + if (desc->storeOp == PAL_STORE_OP_STORE) { + attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { + attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + + attachment->resolveMode = resolveModeToVk(desc->resolveMode); + attachment->imageLayout = layout; + rendering.pStencilAttachment = &depthAttachment; + } + + // stencil attachment + if (info->stencilAttachment) { + attachment = &stencilAttachment; + desc = info->stencilAttachment; + imageView = (ImageView*)desc->imageView; + resolveImageView = (ImageView*)desc->resolveImageView; + + attachment->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; + attachment->pNext = nullptr; + attachment->resolveImageView = nullptr; + attachment->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + attachment->clearValue.depthStencil.stencil = desc->clearValue.stencil; + layout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; + + attachment->imageView = imageView->handle; + if (resolveImageView) { + attachment->resolveImageView = resolveImageView->handle; + attachment->resolveImageLayout = layout; + } + + // load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + // store op + if (desc->storeOp == PAL_STORE_OP_STORE) { + attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + + } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { + attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + + attachment->resolveMode = resolveModeToVk(desc->resolveMode); + attachment->imageLayout = layout; + rendering.pStencilAttachment = &stencilAttachment; + } + + // fragment shading rate attachment + if (info->fragmentShadingRateAttachment) { + imageView = + (ImageView*)info->fragmentShadingRateAttachment->imageView; + fsrInfo.imageView = imageView->handle; + + fsrInfo.shadingRateAttachmentTexelSize.width = + info->fragmentShadingRateAttachment->texelWidth; + + fsrInfo.shadingRateAttachmentTexelSize.height = + info->fragmentShadingRateAttachment->texelHeight; + + fsrInfo.imageLayout = + VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + + rendering.pNext = &fsrInfo; + } + + rendering.layerCount = info->layerCount; + rendering.renderArea.offset.x = info->renderArea.x; + rendering.renderArea.offset.y = info->renderArea.y; + rendering.renderArea.extent.width = info->renderArea.width; + rendering.renderArea.extent.height = info->renderArea.height; + + if (info->viewCount == 1) { + rendering.viewMask = 0; + } else { + rendering.viewMask = (1 << info->viewCount) - 1; + } + + vkCmdBuffer->device->cmdBeginRendering(vkCmdBuffer->handle, &rendering); return PAL_RESULT_SUCCESS; } @@ -5521,6 +5897,45 @@ PalResult PAL_CALL drawIndexedIndirectVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL imageViewBarrierVk( + PalCommandBuffer* cmdBuffer, + PalImageView* imageView, + PalImageViewState oldstate, + PalImageViewState newstate) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + ImageView* vkImageView = (ImageView*)imageView; + VkImageMemoryBarrier2KHR barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR; + + ImageViewBarrier old, new; + old = imageViewBarrierToVk(oldstate); + new = imageViewBarrierToVk(newstate); + + barrier.srcStageMask = old.stages; + barrier.srcAccessMask = old.access; + barrier.oldLayout = old.layout; + + barrier.dstStageMask = new.stages; + barrier.dstAccessMask = new.access; + barrier.newLayout = new.layout; + + barrier.image = vkImageView->image->handle; + barrier.subresourceRange = vkImageView->range; + + VkDependencyInfo dependencyInfo = {0}; + dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependencyInfo.imageMemoryBarrierCount = 1; + dependencyInfo.pImageMemoryBarriers = &barrier; + + vkCmdBuffer->device->cmdPipelineBarrier( + vkCmdBuffer->handle, + &dependencyInfo); + + vkCmdBuffer->dstStage = new.stages; + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) @@ -5531,6 +5946,7 @@ PalResult PAL_CALL submitVkCommandBuffer( VkFence fenceHandle = nullptr; VkSemaphore waitSemaphoreHandle = nullptr; VkSemaphore signalSemaphoreHandle = nullptr; + VkPipelineStageFlagBits2 dstStage = 0; Queue* vkQueue = (Queue*)queue; CommandBuffer* vkCmdBuffer = (CommandBuffer*)info->cmdBuffer; @@ -5538,6 +5954,7 @@ PalResult PAL_CALL submitVkCommandBuffer( Semaphore* tmp = (Semaphore*)info->waitSemaphore; waitSemaphoreHandle = tmp->handle; waitSemaphoreCount = 1; + dstStage = vkCmdBuffer->dstStage; } if (info->signalSemaphore) { @@ -5551,16 +5968,37 @@ PalResult PAL_CALL submitVkCommandBuffer( fenceHandle = tmp->handle; } - VkSubmitInfo submitInfo = {0}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &vkCmdBuffer->handle; - submitInfo.pSignalSemaphores = &signalSemaphoreHandle; - submitInfo.pWaitSemaphores = &waitSemaphoreHandle; - submitInfo.waitSemaphoreCount = waitSemaphoreCount; - submitInfo.waitSemaphoreCount = signalSemaphoreCount; + VkCommandBufferSubmitInfoKHR cmdBufferSubmitInfo = {0}; + cmdBufferSubmitInfo.commandBuffer = vkCmdBuffer->handle; + cmdBufferSubmitInfo.sType = + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR; + + VkSemaphoreSubmitInfoKHR waitSubmitInfo = {0}; + waitSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; + waitSubmitInfo.semaphore = waitSemaphoreHandle; + waitSubmitInfo.stageMask = dstStage; - result = s_Vk.queueSubmit( + VkSemaphoreSubmitInfoKHR signalSubmitInfo = {0}; + signalSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; + signalSubmitInfo.semaphore = signalSemaphoreHandle; + signalSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + + if (vkCmdBuffer->device->features & + PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + waitSubmitInfo.value = info->waitValue; + signalSubmitInfo.value = info->signalValue; + } + + VkSubmitInfo2KHR submitInfo = {0}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR; + submitInfo.commandBufferInfoCount = 1; + submitInfo.pCommandBufferInfos = &cmdBufferSubmitInfo; + submitInfo.pSignalSemaphoreInfos = &signalSubmitInfo; + submitInfo.pWaitSemaphoreInfos = &waitSubmitInfo; + submitInfo.waitSemaphoreInfoCount = waitSemaphoreCount; + submitInfo.signalSemaphoreInfoCount = signalSemaphoreCount; + + result = vkCmdBuffer->device->queueSubmit( vkQueue->phyQueue->handle, 1, &submitInfo, @@ -6214,11 +6652,20 @@ PalResult PAL_CALL createVkGraphicsPipeline( rasterizerState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; } - rasterizerState.lineWidth = 1.0f; rasterizerState.depthBiasEnable = state->enableDepthBias; rasterizerState.depthClampEnable = state->enableDepthClamp; - createInfo.pRasterizationState = &rasterizerState; + + } else { + rasterizerState.cullMode = VK_CULL_MODE_NONE; + rasterizerState.polygonMode = VK_POLYGON_MODE_FILL; + rasterizerState.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizerState.depthBiasEnable = VK_FALSE; + rasterizerState.depthClampEnable = VK_FALSE; + rasterizerState.rasterizerDiscardEnable = VK_FALSE; } + rasterizerState.rasterizerDiscardEnable = VK_FALSE; + rasterizerState.lineWidth = 1.0f; + createInfo.pRasterizationState = &rasterizerState; // Multisample state if (info->multisampleState) { @@ -6236,8 +6683,15 @@ PalResult PAL_CALL createVkGraphicsPipeline( sampleMasks[1] = mask2; multisampleState.pSampleMask = sampleMasks; - createInfo.pMultisampleState = &multisampleState; + + } else { + multisampleState.alphaToCoverageEnable = VK_FALSE; + multisampleState.minSampleShading = VK_FALSE; + multisampleState.sampleShadingEnable = VK_FALSE; + multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampleState.pSampleMask = nullptr; } + createInfo.pMultisampleState = &multisampleState; // Depth stencil state if (info->depthStencilState) { @@ -6263,8 +6717,13 @@ PalResult PAL_CALL createVkGraphicsPipeline( depthStencilState.depthWriteEnable = state->enableDepthWrite; depthStencilState.stencilTestEnable = state->enableStencilTest; - createInfo.pDepthStencilState = &depthStencilState; + } else { + depthStencilState.depthCompareOp = VK_COMPARE_OP_NEVER; + depthStencilState.depthTestEnable = VK_FALSE; + depthStencilState.depthWriteEnable = VK_FALSE; + depthStencilState.stencilTestEnable = VK_FALSE; } + createInfo.pDepthStencilState = &depthStencilState; // Color blend state if (info->blendAttachmentCount) { @@ -6332,15 +6791,16 @@ PalResult PAL_CALL createVkGraphicsPipeline( createInfo.layout = layout->handle; if (info->fragmentShadingRateState) { - // TODO: - // FSRS.combinerOps[0] = - // combinerOpsToVk(info->fragmentShadingRateState.combinerOps[0]); - // FSRS.combinerOps[1] = - // combinerOpsToVk(info->fragmentShadingRateState.combinerOps[1]); - // FSRS.fragmentSize = - // getShadingRateSize(info->fragmentShadingRateState.rate); - - // createInfo.pNext = &FSRS; + PalFragmentShadingRateState* state = info->fragmentShadingRateState; + for (int i = 0; i < 2; i++) { + VkFragmentShadingRateCombinerOpKHR combinerOp; + combinerOp = combinerOpsToVk(state->combinerOps[i]); + fragmentShadingRateState.combinerOps[i] = combinerOp; + } + + VkExtent2D size = getShadingRateSize(state->rate); + fragmentShadingRateState.fragmentSize = size; + createInfo.pNext = &fragmentShadingRateState; } result = s_Vk.createGraphicsPipeline( diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index f993a267..083a1573 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -3,15 +3,44 @@ #include "pal/pal_video.h" #include "tests.h" -static bool initVideo( - PalWindow** outWindow, - PalEventDriver** outEventDriver) +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +#define MAX_FRAMES_IN_FLIGHT 2 + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) { + palLog(nullptr, msg); +} + +bool clearColorTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Clear Color Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; + PalGraphicsWindow gfxWindow; + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + + PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* presentCompleteSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images + PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; - // create an event driver PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { @@ -20,7 +49,6 @@ static bool initVideo( return false; } - // we only need window close and keydown(escape) for borderless window palSetEventDispatchMode( eventDriver, PAL_EVENT_WINDOW_CLOSE, @@ -31,7 +59,6 @@ static bool initVideo( PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - // initialize the video system result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -39,18 +66,14 @@ static bool initVideo( return false; } - // create a window PalWindowCreateInfo windowCreateInfo = {0}; - windowCreateInfo.height = 480; - windowCreateInfo.width = 640; + windowCreateInfo.height = WINDOW_HEIGHT; + windowCreateInfo.width = WINDOW_WIDTH; windowCreateInfo.show = true; windowCreateInfo.title = "Clear Color Window"; - // check if we support decorated windows (title bar, close etc) PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { - // if we dont support, we need to create a borderless window - // and create the decorations ourselves windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } @@ -61,63 +84,15 @@ static bool initVideo( return false; } - *outWindow = window; - *outEventDriver = eventDriver; - return true; -} - -static PalWindowHandleInfo getWindowInfo( - PalWindow* window, - Uint32* width, - Uint32* height) -{ - *width = 640; - *height = 480; - return palGetWindowHandleInfo(window); -} - -static bool shutdownVideo( - PalWindow* window, - PalEventDriver* eventDriver) -{ - palDestroyWindow(window); - palShutdownVideo(); - palDestroyEventDriver(eventDriver); -} - -bool clearColorTest() -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Clear Color Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - // initialize video system - PalWindow* window = nullptr; - PalEventDriver* eventDriver = nullptr; - Uint32 windowWidth = 0; - Uint32 windowHeight = 0; - PalWindowHandleInfo windowHandleInfo; - - if (!initVideo(&window, &eventDriver)) { - palLog(nullptr, "Failed to initialize video"); - return false; - } - windowHandleInfo = getWindowInfo(window, &windowWidth, &windowHeight); + PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); + gfxWindow.display = winHandle.nativeDisplay; + gfxWindow.window = winHandle.nativeWindow; - PalAdapter* adapter = nullptr; - PalDevice* device = nullptr; - PalQueue* queue = nullptr; - PalSwapchain* swapchain = nullptr; - PalCommandPool* cmdPool = nullptr; - PalImageView** imageViews = nullptr; - PalCommandBuffer** cmdBuffers = nullptr; - PalRenderPass* renderPass = nullptr; - PalRenderPassView** renderPassViews = nullptr; + PalGraphicsDebugger debugger; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; - // initialize the graphics system - PalResult result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -125,40 +100,36 @@ bool clearColorTest() } // enumerate all available adapters - Int32 count = 0; - result = palEnumerateAdapters(&count, nullptr); + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); return false; } - if (count == 0) { + if (adapterCount == 0) { palLog(nullptr, "No adapters found"); return false; } - palLog(nullptr, "Adapter count: %d", count); + palLog(nullptr, "Adapter count: %d", adapterCount); - // allocate an array of adapters or use a fixed array - // Example: PalAdapter* adapters[12]; PalAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); return false; } - result = palEnumerateAdapters(&count, adapters); + result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); return false; } - // get information about all the adapters and find the adapter that - // has graphics queue PalAdapterCapabilities caps; - for (Int32 i = 0; i < count; i++) { + for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -176,9 +147,14 @@ bool clearColorTest() } palFree(nullptr, adapters); - + // create a device + PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + features |= PAL_ADAPTER_FEATURE_FENCE_RESET; + } + result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -194,10 +170,6 @@ bool clearColorTest() return false; } - // check if the queue can present on our window - PalGraphicsWindow gfxWindow; - gfxWindow.window = windowHandleInfo.nativeWindow; - gfxWindow.display = windowHandleInfo.nativeDisplay; if (!palCanQueuePresent(queue, &gfxWindow)) { palLog(nullptr, "Queue cannot present to window"); return false; @@ -220,16 +192,16 @@ bool clearColorTest() swapchainCreateInfo.clipped = true; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - swapchainCreateInfo.height = windowHeight; - swapchainCreateInfo.width = windowWidth; + swapchainCreateInfo.height = WINDOW_HEIGHT; + swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; // rare but possible on andriod - if (windowWidth > swapchainCaps.maxImageWidth) { + if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; } - if (windowHeight > swapchainCaps.maxImageHeight) { + if (WINDOW_HEIGHT > swapchainCaps.maxImageHeight) { swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; } @@ -251,183 +223,113 @@ bool clearColorTest() return false; } - // create a command pool for the command buffers - PalCommandPoolCreateInfo cmdPoolCreateInfo = {0}; - cmdPoolCreateInfo.queue = queue; - result = palCreateCommandPool(device, &cmdPoolCreateInfo, &cmdPool); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); - return false; - } - - // get all swapchain images and create command buffers and image views - // for them. This is much faster than resetting and recording per frames + // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate( nullptr, sizeof(PalImageView*) * imageCount, 0); - renderPassViews = palAllocate( - nullptr, - sizeof(PalRenderPassView*) * imageCount, - 0); - - cmdBuffers = palAllocate( + renderFinishedSemaphores = palAllocate( nullptr, - sizeof(PalCommandBuffer*) * imageCount, + sizeof(PalSemaphore*) * imageCount, 0); - if (!imageViews || !renderPassViews || !cmdBuffers) { + if (!imageViews || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); - palFree(nullptr, imageViews); - palFree(nullptr, cmdBuffers); - palFree(nullptr, renderPassViews); return false; } - // create render pass - PalAttachmentDesc presentAttachment = {0}; - presentAttachment.loadOp = PAL_LOAD_OP_CLEAR; - presentAttachment.storeOp = PAL_STORE_OP_STORE; - presentAttachment.type = PAL_ATTACHMENT_TYPE_PRESENT; - presentAttachment.sampleCount = PAL_SAMPLE_COUNT_1; - presentAttachment.format = palGetSwapchainFormat(swapchain); - - PalRenderPassCreateInfo renderPasscreateInfo = {0}; - renderPasscreateInfo.attachmentCount = 1; - renderPasscreateInfo.attachments = &presentAttachment; - - result = palCreateRenderPass( - device, - &renderPasscreateInfo, - &renderPass); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create render pass: %s", error); - return false; - } + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.layerArrayCount = 1; + imageViewCreateInfo.mipLevelCount = 1; + imageViewCreateInfo.startArrayLayer = 0; + imageViewCreateInfo.startMipLevel = 0; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; - for (int i = 0; i < imageCount; i++) { + for (int i = 0; i < imageCount; i++) { // get swapchain image + // this is fast since the images are cache by PAL PalImage* image = palGetSwapchainImage(swapchain, i); if (!image) { palLog(nullptr, "Failed to get swapchain image"); } - // create image view - // swapchain images are 2D and they only supports 2D - // and 2D array view types - PalImageView* imageView = nullptr; - PalImageViewCreateInfo imageViewCreateInfo = {0}; - imageViewCreateInfo.layerArrayCount = 1; - imageViewCreateInfo.mipLevelCount = 1; - imageViewCreateInfo.startArrayLayer = 0; - imageViewCreateInfo.startMipLevel = 0; - imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; - result = palCreateImageView( device, image, &imageViewCreateInfo, - &imageView); + &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); return false; } - - // create a command buffer - PalCommandBuffer* cmdBuffer = nullptr; - result = palCreateCommandBuffer( - device, - cmdPool, - PAL_COMMAND_BUFFER_TYPE_PRIMARY, - &cmdBuffer); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command buffer: %s", error); - return false; - } + } - // create a render pass view - PalRenderPassView* renderPassView = nullptr; - PalRenderPassViewCreateInfo renderPassViewCreateInfo = {0}; - renderPassViewCreateInfo.width = swapchainCreateInfo.width; - renderPassViewCreateInfo.height = swapchainCreateInfo.height; - renderPassViewCreateInfo.imageViewCount = 1; - renderPassViewCreateInfo.imageViews = &imageView; + result = palCreateCommandPool( + device, + queue, + &cmdPool); - result = palCreateRenderPassView( - device, - renderPass, - &renderPassViewCreateInfo, - &renderPassView); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + // create synchronization objects + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create render pass view: %s", error); + palLog(nullptr, "Failed to create semaphore: %s", error); return false; } - // begin command buffer recording - // the optional render pass is used for secondary command buffer - // which will be used with a render pass - result = palBeginCommandBuffer(cmdBuffer, nullptr); + result = palCreateFence(device, true, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + palLog(nullptr, "Failed to create fence: %s", error); return false; } - // record commands - PalClearValue clearValue = {0}; - clearValue.color[0] = 0.2f; - clearValue.color[1] = 0.2f; - clearValue.color[2] = 0.2f; - clearValue.color[3] = 1.0f; - - PalRenderPassBeginInfo renderPassBeginInfo = {0}; - renderPassBeginInfo.clearValueCount = 1; - renderPassBeginInfo.clearValues = &clearValue; - renderPassBeginInfo.renderPass = renderPass; - renderPassBeginInfo.view = renderPassView; - - result = palBeginRenderPass(cmdBuffer, &renderPassBeginInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin render pass: %s", error); - return false; - } + result = palCreateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffers[i]); - result = palEndRenderPass(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end render pass: %s", error); + palLog(nullptr, "Failed to create command buffer: %s", error); return false; } + } - // end command buffer recording - result = palEndCommandBuffer(cmdBuffer); + // create synchronization objects + for (int i = 0; i < imageCount; i++) { + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + palLog(nullptr, "Failed to create semaphore: %s", error); return false; } - - // cache everything so we can reference and destroy later - renderPassViews[i] = renderPassView; - cmdBuffers[i] = cmdBuffer; - imageViews[i] = imageView; } // main loop + Uint32 currentFrame = 0; bool running = true; + PalSemaphore* presentCompleteSemaphore = nullptr; + PalSemaphore* renderFinishedSemaphore = nullptr; + PalFence* fence = nullptr; + PalCommandBuffer* cmdBuffer = nullptr; + + bool firstImageViewUse[8]; + memset(firstImageViewUse, 1, sizeof(bool) * 8); + while (running) { // update the video system to push video events palUpdateVideo(); @@ -451,25 +353,149 @@ bool clearColorTest() } } - // get the next image that we can render too - PalImage* image = nullptr; - PalNextImageInfo nextImageInfo = {0}; - nextImageInfo.timeout = UINT64_MAX; - image = palGetNextSwapchainImage(swapchain, &nextImageInfo); - - // find the command buffer associated with the image - // this is fast, the swapchain caches all it images internally - PalCommandBuffer* cmdBuffer = nullptr; - for (int i = 0; i < imageCount; i++) { - if (image == palGetSwapchainImage(swapchain, i)) { - cmdBuffer = cmdBuffers[i]; - break; + fence = inFlightFences[currentFrame]; + presentCompleteSemaphore = presentCompleteSemaphores[currentFrame]; + cmdBuffer = cmdBuffers[currentFrame]; + + result = palWaitFence(fence, UINT64_MAX); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + result = palResetFence(fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; } + + } else { + // recreate since we dont support fence resetting + palDestroyFence(fence); + + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = presentCompleteSemaphore; + nextImageInfo.timeout = UINT64_MAX; + + Uint32 index = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &index); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + renderFinishedSemaphore = renderFinishedSemaphores[index]; + + // reset the command buffer + result = palResetCommandBuffer(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to reset command buffer: %s", error); + return false; + } + + result = palBeginCommandBuffer(cmdBuffer, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + PalClearValue clearValue; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; + + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.clearValue = clearValue; + colorAttachment.imageView = imageViews[index]; + + PalRenderingInfo renderingInfo = {0}; + renderingInfo.viewCount = 1; + renderingInfo.colorAttachentCount = 1; + renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.layerCount = 1; + renderingInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; + + // change the state of the image view to make it renderable + PalImageViewState oldstate; + if (firstImageViewUse[index]) { + oldstate = PAL_IMAGE_VIEW_STATE_UNDEFINED; + } else { + oldstate = PAL_IMAGE_VIEW_STATE_PRESENT; + } + + result = palImageViewBarrier( + cmdBuffer, + imageViews[index], + oldstate, + PAL_IMAGE_VIEW_STATE_COLOR_ATTACHMENT); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + result = palBeginRendering(cmdBuffer, &renderingInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin rendering: %s", error); + return false; + } + + result = palEndRendering(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end rendering: %s", error); + return false; + } + + // change the state of the image view to make it presentable + result = palImageViewBarrier( + cmdBuffer, + imageViews[index], + PAL_IMAGE_VIEW_STATE_COLOR_ATTACHMENT, + PAL_IMAGE_VIEW_STATE_PRESENT); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + result = palEndCommandBuffer(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; } - // submit to the queue and present - PalSubmitInfo submitInfo = {0}; + // submit command buffer + PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffer; + submitInfo.fence = fence; + submitInfo.waitSemaphore = presentCompleteSemaphore; + submitInfo.signalSemaphore = renderFinishedSemaphore; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -478,44 +504,47 @@ bool clearColorTest() return false; } - PalPresentInfo presentInfo = {0}; - presentInfo.image = image; - + // present + PalSwapchainPresentInfo presentInfo = {0}; + presentInfo.imageIndex = index; + presentInfo.waitSemaphore = renderFinishedSemaphore; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to present swapchain: %s", error); return false; } + + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } - // since we dont use a fence or sempahore, there is no way to know - // if the GPU is done presenting and we can now destroy the swapchain - // so we just wait for a while - // and we dont want to use thread system for this - Int32 counter = 0; - for (int i = 0; i < 30000; i++) { - counter++; + result = palWaitDevice(device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for device: %s", error); + return false; } - // cleanup - for (int i = 0; i < imageCount; i++) { - palDestroyRenderPassView(renderPassViews[i]); + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + palDestroySemaphore(presentCompleteSemaphores[i]); + palDestroyFence(inFlightFences[i]); palDestroyCommandBuffer(cmdBuffers[i]); + } + + for (int i = 0; i < imageCount; i++) { palDestroyImageView(imageViews[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); } - palDestroyRenderPass(renderPass); palDestroyCommandPool(cmdPool); palDestroySwapchain(swapchain); palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); - palFree(nullptr, imageViews); - palFree(nullptr, cmdBuffers); - palFree(nullptr, renderPassViews); - shutdownVideo(window, eventDriver); + palDestroyWindow(window); + palShutdownVideo(); + palDestroyEventDriver(eventDriver); return true; } \ No newline at end of file diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 96248f1e..647c36a2 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -244,14 +244,6 @@ bool graphicsTest() palLog(nullptr, " Image view type Cube array"); } - if (features & PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_RESETTABLE) { - palLog(nullptr, " Resettable command pool"); - } - - if (features & PAL_ADAPTER_FEATURE_COMMAND_POOL_FLAG_TRANSIENT) { - palLog(nullptr, " Transient command pool"); - } - if (features & PAL_ADAPTER_FEATURE_FENCE_RESET) { palLog(nullptr, " Resetting fence"); } diff --git a/tests/tests.lua b/tests/tests.lua index 9055f2ca..b69b2a6a 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -71,7 +71,7 @@ project "tests" if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { - --"clear_color_test.c", + "clear_color_test.c", --"triangle_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index abd19cdb..fa7c4869 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,11 +55,11 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + // registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest("Clear Color Test", clearColorTest); + registerTest("Clear Color Test", clearColorTest); // registerTest("Triangle Test", triangleTest); #endif // From 5969303021c0d5b34b456b1413a0a69059c675d6 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 6 Jan 2026 22:42:40 +0000 Subject: [PATCH 074/372] update triangle test with new graphics API --- include/pal/pal_graphics.h | 66 +- pal_config.lua | 2 +- src/graphics/pal_graphics.c | 72 ++- src/graphics/pal_vulkan.c | 253 ++++++-- tests/clear_color_test.c | 14 +- tests/shaders/triangle_frag.spv | Bin 416 -> 372 bytes tests/shaders/triangle_vert.spv | Bin 1020 -> 1140 bytes tests/tests.lua | 2 +- tests/tests_main.c | 4 +- tests/triangle_test.c | 1039 +++++++++++++++++-------------- 10 files changed, 892 insertions(+), 560 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index bb706e93..46c6284f 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -522,13 +522,21 @@ enum PalDebugMessageType { }; typedef enum { - PAL_IMAGE_VIEW_STATE_UNDEFINED, - PAL_IMAGE_VIEW_STATE_PRESENT, - PAL_IMAGE_VIEW_STATE_COLOR_ATTACHMENT, - PAL_IMAGE_VIEW_STATE_DEPTH_ATTACHMENT, - PAL_IMAGE_VIEW_STATE_STENCIL_ATTACHMENT, - PAL_IMAGE_VIEW_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT -} PalImageViewState; + PAL_USAGE_STATE_UNDEFINED, + PAL_USAGE_STATE_PRESENT, + PAL_USAGE_STATE_COLOR_ATTACHMENT, + PAL_USAGE_STATE_DEPTH_ATTACHMENT, + PAL_USAGE_STATE_STENCIL_ATTACHMENT, + PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT, + PAL_USAGE_STATE_TRANSFER_WRITE, + PAL_USAGE_STATE_TRANSFER_READ, + PAL_USAGE_STATE_VERTEX_READ, + PAL_USAGE_STATE_INDEX_READ, + PAL_USAGE_STATE_UNIFORM_READ, + PAL_USAGE_STATE_SHADER_READ, + PAL_USAGE_STATE_STORAGE_READ, + PAL_USAGE_STATE_STORAGE_WRITE +} PalUsageState; typedef struct { Uint32 vendorId; @@ -714,16 +722,26 @@ typedef struct { PalRect2D renderArea; } PalRenderingInfo; +typedef struct { + Uint32 viewCount; + Uint32 colorAttachentCount; + PalSampleCount multisampleCount; + PalFormat depthAttachmentFormat; + PalFormat stencilAttachmentFormat; + PalFormat fragmentShadingRateAttachmentFormat; + PalFormat* colorAttachmentsFormat; +} PalRenderingLayoutInfo; + typedef struct { Uint32 vertexCount; - Uint32 instancecCount; + Uint32 instanceCount; Uint32 firstVertex; Uint32 firstInstance; } PalDrawData; typedef struct { Uint32 indexCount; - Uint32 instancecCount; + Uint32 instanceCount; Uint32 firstIndex; Int32 vertexOffset; Uint32 firstInstance; @@ -911,6 +929,7 @@ typedef struct { PalMultisampleState* multisampleState; PalDepthStencilState* depthStencilState; PalFragmentShadingRateState* fragmentShadingRateState; + PalRenderingLayoutInfo* renderingLayout; } PalGraphicsPipelineCreateInfo; typedef struct { @@ -1109,6 +1128,8 @@ typedef struct { void PAL_CALL (*destroyCommandPool)(PalCommandPool* pool); + PalResult PAL_CALL (*resetCommandPool)(PalCommandPool* pool); + PalResult PAL_CALL (*createCommandBuffer)( PalDevice* device, PalCommandPool* pool, @@ -1119,7 +1140,7 @@ typedef struct { PalResult PAL_CALL (*beginCommandBuffer)( PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info); + PalRenderingLayoutInfo* info); PalResult PAL_CALL (*endCommandBuffer)(PalCommandBuffer* cmdBuffer); @@ -1223,8 +1244,14 @@ typedef struct { PalResult PAL_CALL (*imageViewBarrier)( PalCommandBuffer* cmdBuffer, PalImageView* imageView, - PalImageViewState oldState, - PalImageViewState newState); + PalUsageState oldUsageState, + PalUsageState newUsageState); + + PalResult PAL_CALL (*bufferBarrier)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState); PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, @@ -1478,6 +1505,8 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); +PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); + PAL_API PalResult PAL_CALL palCreateCommandBuffer( PalDevice* device, PalCommandPool* pool, @@ -1488,8 +1517,7 @@ PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); PAL_API PalResult PAL_CALL palBeginCommandBuffer( PalCommandBuffer* cmdBuffer, - // only used for secomdary command buffers - PalRenderingInfo* info); + PalRenderingLayoutInfo* info); PAL_API PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -1593,8 +1621,14 @@ PAL_API PalResult PAL_CALL palDrawIndexedIndirect( PAL_API PalResult PAL_CALL palImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, - PalImageViewState oldState, - PalImageViewState newState); + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PAL_API PalResult PAL_CALL palBufferBarrier( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState); PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, diff --git a/pal_config.lua b/pal_config.lua index 25277c5a..14259d5a 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -1,6 +1,6 @@ -- build PAL as a static library -PAL_BUILD_STATIC = true +PAL_BUILD_STATIC = false -- build PAL tests as a single application PAL_BUILD_TESTS = true diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index b4a33ca6..e854e720 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -279,7 +279,7 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); PalResult PAL_CALL beginVkCommandBuffer( PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info); + PalRenderingLayoutInfo* info); PalResult PAL_CALL endVkCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -383,8 +383,14 @@ PalResult PAL_CALL drawIndexedIndirectVk( PalResult PAL_CALL imageViewBarrierVk( PalCommandBuffer* cmdBuffer, PalImageView* imageView, - PalImageViewState oldstate, - PalImageViewState newstate); + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PalResult PAL_CALL bufferBarrierVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState); PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, @@ -495,6 +501,7 @@ static PalGraphicsBackend s_VkBackend = { .getSemaphoreValue = getVkSemaphoreValue, .createCommandPool = createVkCommandPool, .destroyCommandPool = destroyVkCommandPool, + .resetCommandPool = resetVkCommandPool, .createCommandBuffer = createVkCommandBuffer, .destroyCommandBuffer = destroyVkCommandBuffer, .beginCommandBuffer = beginVkCommandBuffer, @@ -519,6 +526,7 @@ static PalGraphicsBackend s_VkBackend = { .drawIndexed = drawIndexedVk, .drawIndexedIndirect = drawIndexedIndirectVk, .imageViewBarrier = imageViewBarrierVk, + .bufferBarrier = bufferBarrierVk, .submitCommandBuffer = submitVkCommandBuffer, .createAccelerationstructure = createVkAccelerationstructure, .destroyAccelerationstructure = destroyVkAccelerationstructure, @@ -615,6 +623,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->getSemaphoreValue || !backend->createCommandPool || !backend->destroyCommandPool || + !backend->resetCommandPool || !backend->createCommandBuffer || !backend->destroyCommandBuffer || !backend->beginCommandBuffer || @@ -639,6 +648,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->drawIndexed || !backend->drawIndexedIndirect || !backend->imageViewBarrier || + !backend->bufferBarrier || !backend->submitCommandBuffer || !backend->createAccelerationstructure || !backend->destroyAccelerationstructure || @@ -1268,6 +1278,12 @@ PalResult PAL_CALL palCreateSwapchain( if (result != PAL_RESULT_SUCCESS) { return result; } + + // set the backend for all swapchain images + for (int i = 0; i < info->imageCount; i++) { + PalImage* image = device->backend->getSwapchainImage(swapchain, i); + image->backend = device->backend; + } swapchain->backend = device->backend; *outSwapchain = swapchain; @@ -1572,6 +1588,19 @@ void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) } } +PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!pool) { + return PAL_RESULT_NULL_POINTER; + } + + return pool->backend->resetCommandPool(pool); +} + PalResult PAL_CALL palCreateCommandBuffer( PalDevice* device, PalCommandPool* pool, @@ -1612,7 +1641,7 @@ void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL palBeginCommandBuffer( PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info) + PalRenderingLayoutInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2003,11 +2032,11 @@ PalResult PAL_CALL palDrawIndexedIndirect( count); } -PAL_API PalResult PAL_CALL palImageViewBarrier( +PalResult PAL_CALL palImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, - PalImageViewState oldState, - PalImageViewState newState) + PalUsageState oldUsageState, + PalUsageState newUsageState) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2020,8 +2049,29 @@ PAL_API PalResult PAL_CALL palImageViewBarrier( return cmdBuffer->backend->imageViewBarrier( cmdBuffer, imageView, - oldState, - newState); + oldUsageState, + newUsageState); +} + +PalResult PAL_CALL palBufferBarrier( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->bufferBarrier( + cmdBuffer, + buffer, + oldUsageState, + newUsageState); } PalResult PAL_CALL palSubmitCommandBuffer( @@ -2271,6 +2321,10 @@ PalResult PAL_CALL palCreateGraphicsPipeline( return PAL_RESULT_NULL_POINTER; } + if (!info->renderingLayout) { + return PAL_RESULT_NULL_POINTER; + } + PalResult result; PalPipeline* pipeline = nullptr; result = device->backend->createGraphicsPipeline( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 06f3072e..1480120d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -134,6 +134,7 @@ typedef struct { PFN_vkBeginCommandBuffer cmdBegin; PFN_vkEndCommandBuffer cmdEnd; + PFN_vkResetCommandPool resetCommandPool; PFN_vkResetCommandBuffer resetCommandBuffer; PFN_vkCmdExecuteCommands cmdExecuteCommandBuffer; PFN_vkCmdCopyBuffer cmdCopyBuffer; @@ -350,12 +351,12 @@ typedef struct { VkPipeline handle; } Pipeline; -typedef struct ImageViewTransition { +typedef struct { VkPipelineStageFlags2 stages; VkPipelineStageFlags2 dstStagess; VkAccessFlags2 access; VkImageLayout layout; -} ImageViewBarrier; +} Barrier; static Vulkan s_Vk = {0}; @@ -1504,11 +1505,11 @@ static VkResolveModeFlagBits resolveModeToVk(PalResolveMode mode) return VK_RESOLVE_MODE_NONE_KHR; } -static ImageViewBarrier imageViewBarrierToVk(PalImageViewState state) +static Barrier barrierToVk(PalUsageState state) { - ImageViewBarrier barrier = {0}; + Barrier barrier = {0}; switch (state) { - case PAL_IMAGE_VIEW_STATE_UNDEFINED: { + case PAL_USAGE_STATE_UNDEFINED: { barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; barrier.dstStagess = barrier.dstStagess; barrier.access = 0; @@ -1517,7 +1518,7 @@ static ImageViewBarrier imageViewBarrierToVk(PalImageViewState state) return barrier; } - case PAL_IMAGE_VIEW_STATE_PRESENT: { + case PAL_USAGE_STATE_PRESENT: { barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.dstStagess = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; @@ -1528,7 +1529,7 @@ static ImageViewBarrier imageViewBarrierToVk(PalImageViewState state) return barrier; } - case PAL_IMAGE_VIEW_STATE_COLOR_ATTACHMENT: { + case PAL_USAGE_STATE_COLOR_ATTACHMENT: { barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.dstStagess = barrier.stages; @@ -1540,7 +1541,7 @@ static ImageViewBarrier imageViewBarrierToVk(PalImageViewState state) return barrier; } - case PAL_IMAGE_VIEW_STATE_DEPTH_ATTACHMENT: { + case PAL_USAGE_STATE_DEPTH_ATTACHMENT: { barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.dstStagess = barrier.stages; @@ -1552,7 +1553,7 @@ static ImageViewBarrier imageViewBarrierToVk(PalImageViewState state) return barrier; } - case PAL_IMAGE_VIEW_STATE_STENCIL_ATTACHMENT: { + case PAL_USAGE_STATE_STENCIL_ATTACHMENT: { barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.dstStagess = barrier.stages; @@ -1564,7 +1565,7 @@ static ImageViewBarrier imageViewBarrierToVk(PalImageViewState state) return barrier; } - case PAL_IMAGE_VIEW_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT: { + case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT: { barrier.stages = VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; barrier.dstStagess = barrier.stages; @@ -1577,6 +1578,85 @@ static ImageViewBarrier imageViewBarrierToVk(PalImageViewState state) return barrier; } + + case PAL_USAGE_STATE_TRANSFER_WRITE: { + barrier.stages = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; + barrier.dstStagess = barrier.dstStagess; + barrier.access = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + + return barrier; + } + + case PAL_USAGE_STATE_TRANSFER_READ: { + barrier.stages = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; + barrier.dstStagess = barrier.dstStagess; + barrier.access = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + + return barrier; + } + + case PAL_USAGE_STATE_VERTEX_READ: { + barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR; + barrier.dstStagess = barrier.dstStagess; + barrier.access = VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + + return barrier; + } + + case PAL_USAGE_STATE_INDEX_READ: { + barrier.stages = VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR; + barrier.dstStagess = barrier.dstStagess; + barrier.access = VK_ACCESS_2_INDEX_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + + return barrier; + } + + case PAL_USAGE_STATE_UNIFORM_READ: { + barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR; + barrier.stages |= VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR; + barrier.dstStagess = barrier.dstStagess; + + barrier.access = VK_ACCESS_2_UNIFORM_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + + return barrier; + } + + case PAL_USAGE_STATE_SHADER_READ: { + barrier.stages = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR; + barrier.dstStagess = barrier.dstStagess; + + barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + + return barrier; + } + + case PAL_USAGE_STATE_STORAGE_READ: { + barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR; + barrier.stages |= VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR; + barrier.dstStagess = barrier.dstStagess; + + barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + + return barrier; + } + + case PAL_USAGE_STATE_STORAGE_WRITE: { + barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR; + barrier.stages |= VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR; + barrier.dstStagess = barrier.dstStagess; + + barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + + return barrier; + } } barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; @@ -1888,6 +1968,10 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkEndCommandBuffer"); + s_Vk.resetCommandPool = (PFN_vkResetCommandPool)dlsym( + s_Vk.handle, + "vkResetCommandPool"); + s_Vk.resetCommandBuffer = (PFN_vkResetCommandBuffer)dlsym( s_Vk.handle, "vkResetCommandBuffer"); @@ -5006,6 +5090,13 @@ void PAL_CALL destroyVkCommandPool(PalCommandPool* pool) palFree(s_Vk.allocator, vkPool); } +PalResult PAL_CALL resetVkCommandPool(PalCommandPool* pool) +{ + CommandPool* vkCmdPool = (CommandPool*)pool; + s_Vk.resetCommandPool(vkCmdPool->device->handle, vkCmdPool->handle, 0); + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL createVkCommandBuffer( PalDevice* device, PalCommandPool* pool, @@ -5065,7 +5156,7 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL beginVkCommandBuffer( PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info) + PalRenderingLayoutInfo* info) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; VkCommandBufferBeginInfo beginInfo = {0}; @@ -5073,69 +5164,38 @@ PalResult PAL_CALL beginVkCommandBuffer( VkCommandBufferInheritanceInfo inheritanceInfo = {0}; inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; - VkCommandBufferInheritanceRenderingInfoKHR tmp = {0}; - tmp.sType = + VkCommandBufferInheritanceRenderingInfoKHR layout = {0}; + layout.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; - VkRenderingFragmentShadingRateAttachmentInfoKHR fsrInfo = {0}; - fsrInfo.sType = - VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; - VkFormat format = VK_FORMAT_UNDEFINED; - ImageView* imageView = nullptr; VkFormat colorAttachments[MAX_ATTACHMENTS]; if (!vkCmdBuffer->primary) { // secondary command buffer for (int i = 0; i < info->colorAttachentCount; i++) { - imageView = (ImageView*)info->colorAttachments[i].imageView; - format = palFormatToVk(imageView->image->info.format); + format = palFormatToVk(info->colorAttachmentsFormat[i]); colorAttachments[i] = format; } - tmp.colorAttachmentCount = info->colorAttachentCount; - tmp.pColorAttachmentFormats = colorAttachments; + layout.colorAttachmentCount = info->colorAttachentCount; + layout.pColorAttachmentFormats = colorAttachments; // depth attachment - if (info->depthAttachment) { - imageView = (ImageView*)info->depthAttachment->imageView; - format = palFormatToVk(imageView->image->info.format); - tmp.depthAttachmentFormat = format; - } + format = palFormatToVk(info->depthAttachmentFormat); + layout.depthAttachmentFormat = format; // stencil attachment - if (info->stencilAttachment) { - imageView = (ImageView*)info->stencilAttachment->imageView; - format = palFormatToVk(imageView->image->info.format); - tmp.stencilAttachmentFormat = format; - } - - // fragment shading rate attachment - if (info->fragmentShadingRateAttachment) { - imageView = - (ImageView*)info->fragmentShadingRateAttachment->imageView; - fsrInfo.imageView = imageView->handle; - - fsrInfo.shadingRateAttachmentTexelSize.width = - info->fragmentShadingRateAttachment->texelWidth; - - fsrInfo.shadingRateAttachmentTexelSize.height = - info->fragmentShadingRateAttachment->texelHeight; - - fsrInfo.imageLayout = - VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; - - tmp.pNext = &fsrInfo; - } - - tmp.rasterizationSamples = samplesToVk(info->multisampleCount); + format = palFormatToVk(info->stencilAttachmentFormat); + layout.stencilAttachmentFormat = format; + layout.rasterizationSamples = samplesToVk(info->multisampleCount); if (info->viewCount == 1) { - tmp.viewMask = 0; + layout.viewMask = 0; } else { - tmp.viewMask = (1 << info->viewCount) - 1; + layout.viewMask = (1 << info->viewCount) - 1; } - inheritanceInfo.pNext = &tmp; + inheritanceInfo.pNext = &layout; beginInfo.pNext = &inheritanceInfo; } @@ -5834,7 +5894,7 @@ PalResult PAL_CALL drawVk( s_Vk.cmdDraw( vkCmdBuffer->handle, data->vertexCount, - data->instancecCount, + data->instanceCount, data->firstVertex, data->firstInstance); @@ -5869,7 +5929,7 @@ PalResult PAL_CALL drawIndexedVk( s_Vk.cmdDrawIndexed( vkCmdBuffer->handle, data->indexCount, - data->instancecCount, + data->instanceCount, data->firstIndex, data->vertexOffset, data->firstInstance); @@ -5900,17 +5960,17 @@ PalResult PAL_CALL drawIndexedIndirectVk( PalResult PAL_CALL imageViewBarrierVk( PalCommandBuffer* cmdBuffer, PalImageView* imageView, - PalImageViewState oldstate, - PalImageViewState newstate) + PalUsageState oldUsageState, + PalUsageState newUsageState) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; ImageView* vkImageView = (ImageView*)imageView; VkImageMemoryBarrier2KHR barrier = {0}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR; - ImageViewBarrier old, new; - old = imageViewBarrierToVk(oldstate); - new = imageViewBarrierToVk(newstate); + Barrier old, new; + old = barrierToVk(oldUsageState); + new = barrierToVk(newUsageState); barrier.srcStageMask = old.stages; barrier.srcAccessMask = old.access; @@ -5936,6 +5996,44 @@ PalResult PAL_CALL imageViewBarrierVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL bufferBarrierVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* vkBuffer = (Buffer*)buffer; + VkBufferMemoryBarrier2KHR barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; + + Barrier old, new; + old = barrierToVk(oldUsageState); + new = barrierToVk(newUsageState); + + barrier.srcStageMask = old.stages; + barrier.srcAccessMask = old.access; + + barrier.dstStageMask = new.stages; + barrier.dstAccessMask = new.access; + + barrier.buffer = vkBuffer->handle; + barrier.offset = 0; + barrier.size = VK_WHOLE_SIZE; + + VkDependencyInfo dependencyInfo = {0}; + dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependencyInfo.bufferMemoryBarrierCount = 1; + dependencyInfo.pBufferMemoryBarriers = &barrier; + + vkCmdBuffer->device->cmdPipelineBarrier( + vkCmdBuffer->handle, + &dependencyInfo); + + vkCmdBuffer->dstStage = new.stages; + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) @@ -6463,6 +6561,9 @@ PalResult PAL_CALL createVkGraphicsPipeline( VkPipelineFragmentShadingRateStateCreateInfoKHR fragmentShadingRateState = {0}; fragmentShadingRateState.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; + VkPipelineRenderingCreateInfoKHR dynRendering = {0}; + dynRendering.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR; + VkGraphicsPipelineCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; @@ -6803,6 +6904,34 @@ PalResult PAL_CALL createVkGraphicsPipeline( createInfo.pNext = &fragmentShadingRateState; } + // layout info + VkFormat format = VK_FORMAT_UNDEFINED; + VkFormat colorAttachments[MAX_ATTACHMENTS]; + PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; + + // color attachments + for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { + format = palFormatToVk(renderingLayout->colorAttachmentsFormat[i]); + colorAttachments[i] = format; + } + dynRendering.colorAttachmentCount = renderingLayout->colorAttachentCount; + dynRendering.pColorAttachmentFormats = colorAttachments; + + // depth attachment + format = palFormatToVk(renderingLayout->depthAttachmentFormat); + dynRendering.depthAttachmentFormat = format; + + // stencil attachment + format = palFormatToVk(renderingLayout->stencilAttachmentFormat); + dynRendering.stencilAttachmentFormat = format; + + if (renderingLayout->viewCount == 1) { + dynRendering.viewMask = 0; + } else { + dynRendering.viewMask = (1 << renderingLayout->viewCount) - 1; + } + + createInfo.pNext = &dynRendering; result = s_Vk.createGraphicsPipeline( vkDevice->handle, 0, diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 083a1573..be6e4617 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -437,18 +437,18 @@ bool clearColorTest() renderingInfo.renderArea.height = WINDOW_HEIGHT; // change the state of the image view to make it renderable - PalImageViewState oldstate; + PalUsageState oldUsageState; if (firstImageViewUse[index]) { - oldstate = PAL_IMAGE_VIEW_STATE_UNDEFINED; + oldUsageState = PAL_USAGE_STATE_UNDEFINED; } else { - oldstate = PAL_IMAGE_VIEW_STATE_PRESENT; + oldUsageState = PAL_USAGE_STATE_PRESENT; } result = palImageViewBarrier( cmdBuffer, imageViews[index], - oldstate, - PAL_IMAGE_VIEW_STATE_COLOR_ATTACHMENT); + oldUsageState, + PAL_USAGE_STATE_COLOR_ATTACHMENT); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -474,8 +474,8 @@ bool clearColorTest() result = palImageViewBarrier( cmdBuffer, imageViews[index], - PAL_IMAGE_VIEW_STATE_COLOR_ATTACHMENT, - PAL_IMAGE_VIEW_STATE_PRESENT); + PAL_USAGE_STATE_COLOR_ATTACHMENT, + PAL_USAGE_STATE_PRESENT); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/shaders/triangle_frag.spv b/tests/shaders/triangle_frag.spv index 2dd6180ca9800cb8824e89ae97397e801d756c91..1f9fead55f8bdc6a1f66e827ceee8444b745d48d 100644 GIT binary patch delta 103 zcmZ3${Dp~^nMs+Qfq{{Mn}LIYcOtJhBlpBedmu4W9!TtrmQ-M1Vc=o_sbF9LDrB&R i^0_BxGAgUs0(l@&9w6ohVmk(A22LpdFHnyK5CZ_aVG8a5 delta 130 zcmeyuw1AnHnMs+Qfq{{Mn}LIYe=sR4-H)XNK`8G#t2#v01!o2<*IJUM|;1OUH53#b49 diff --git a/tests/shaders/triangle_vert.spv b/tests/shaders/triangle_vert.spv index a03f1dfb4bd8011b4ac1fcb6fa2174340581a2d8..15b7f9086461b6f401fe12f2e70c4619db37209b 100644 GIT binary patch literal 1140 zcmYk4T~E|d5QdMtln+5Z1q1;LD4LKEFVvVAB?OZ7f(r}@w`L;^X;OB{ZZ*am{B8a! zZ%lZewrBA))0uhaJ#*eOZM(HQ5yFEo9VWx8P_Kp10tsN_mG7LMpB@a$%Y!#>U(1*c z?TRR8E=*PN81L(D-ZOcGEn?5G9jwjM!vA4I62^G$xd~@XlV25I&$7WqHYl^7q@Xo! zY^^`c%e>zMov8SpUEz7JJkNh+@?y=is2vyi%}G8iyS;DOsHSpj--}{YOVFogSHh$A z?&!o?vv>J%+%NirI`>}PChxG{J9zGA_8YsRk61lZr+v?Jk34lnp0Sv7>hM<27UnWn z%m2Ar%R`&I3?LH-c$ez7egwZ$IR zv=rV9K5GBa=P;ML=JB4RX8SGR)gW#^b7vtIbuJORtnD>mly$18nQO8SS_sh4g4$pL^*8VZ6_t+iDB0|0Z literal 1020 zcmYL`UrPc}5XEoWs%2?rX@AUCdMu=eiXbY&z#e=sgkD2xiG@u=w}_tlY<;R;g3j-H zcfB&soHOUn%$?0<4)VqFPdjpzob35OWfraLf#cPdM(tF;~J7!?CBXo2RLm17;pDb-=#Ea;B;& zsM%6Q>JZly<>Y-?U3z_Ri>bdUT#)x=oI{8Cs?=`?FUxZuuBnLGk{aYNU%D0fWcCY( z*()4(?kOCNAq#sSk~&7wK3Sp0o`q>l7lcN%mUd3smn>4S#eV7?<9Z?4HxAB?^( z&->ufgV`$_diIN+{h{BNCkKxn?91TJ^v%(+PYykP#dz{J`e&968N1-US5km^%cX8H t!?uk6_tMjM$8mBgx9d21Cc1{>=-+oc+EdJZ^yJwQJ=q7jKTUlu`v<@5J|h4C diff --git a/tests/tests.lua b/tests/tests.lua index b69b2a6a..2cb1bff1 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -72,7 +72,7 @@ project "tests" if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { "clear_color_test.c", - --"triangle_test.c" + "triangle_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index fa7c4869..ebfc9435 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,8 +59,8 @@ int main(int argc, char** argv) #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest("Clear Color Test", clearColorTest); - // registerTest("Triangle Test", triangleTest); + // registerTest("Clear Color Test", clearColorTest); + registerTest("Triangle Test", triangleTest); #endif // runTests(); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index e79607c2..f1041cd5 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -25,15 +25,54 @@ static bool readFile(const char* filename, void* buffer, Uint64* size) return true; } -static bool initVideo( - PalWindow** outWindow, - PalEventDriver** outEventDriver) +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +#define MAX_FRAMES_IN_FLIGHT 2 + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) { + palLog(nullptr, msg); +} + +bool triangleTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Triangle Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; + PalGraphicsWindow gfxWindow; + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + + PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* presentCompleteSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images + PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + + PalPipelineLayout* pipelineLayout = nullptr; + PalPipeline* pipeline = nullptr; + PalShader* vertexShader = nullptr; + PalShader* fragmentShader = nullptr; + + PalBuffer* vertexBuffer = nullptr; + PalBuffer* stagingBuffer = nullptr; + PalMemory* vertexBufferMemory = nullptr; + PalMemory* stagingBufferMemory = nullptr; - // create an event driver PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { @@ -42,7 +81,6 @@ static bool initVideo( return false; } - // we only need window close and keydown(escape) for borderless window palSetEventDispatchMode( eventDriver, PAL_EVENT_WINDOW_CLOSE, @@ -53,7 +91,6 @@ static bool initVideo( PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - // initialize the video system result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -61,18 +98,14 @@ static bool initVideo( return false; } - // create a window PalWindowCreateInfo windowCreateInfo = {0}; - windowCreateInfo.height = 480; - windowCreateInfo.width = 640; + windowCreateInfo.height = WINDOW_HEIGHT; + windowCreateInfo.width = WINDOW_WIDTH; windowCreateInfo.show = true; - windowCreateInfo.title = "Triangle Window"; + windowCreateInfo.title = "Clear Color Window"; - // check if we support decorated windows (title bar, close etc) PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { - // if we dont support, we need to create a borderless window - // and create the decorations ourselves windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } @@ -83,83 +116,15 @@ static bool initVideo( return false; } - *outWindow = window; - *outEventDriver = eventDriver; - return true; -} + PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); + gfxWindow.display = winHandle.nativeDisplay; + gfxWindow.window = winHandle.nativeWindow; -static PalWindowHandleInfo getWindowInfo( - PalWindow* window, - Uint32* width, - Uint32* height) -{ - *width = 640; - *height = 480; - return palGetWindowHandleInfo(window); -} + PalGraphicsDebugger debugger; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; -static bool shutdownVideo( - PalWindow* window, - PalEventDriver* eventDriver) -{ - palDestroyWindow(window); - palShutdownVideo(); - palDestroyEventDriver(eventDriver); -} - -static void PAL_CALL onGraphicsDebug( - void* userData, - Uint32 severity, - Uint32 type, - const char* msg) -{ - palLog(nullptr, msg); -} - -bool triangleTest() -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Triangle Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - // initialize video system - PalWindow* window = nullptr; - PalEventDriver* eventDriver = nullptr; - Uint32 windowWidth = 0; - Uint32 windowHeight = 0; - PalWindowHandleInfo windowHandleInfo; - - if (!initVideo(&window, &eventDriver)) { - palLog(nullptr, "Failed to initialize video"); - return false; - } - windowHandleInfo = getWindowInfo(window, &windowWidth, &windowHeight); - - PalAdapter* adapter = nullptr; - PalDevice* device = nullptr; - PalQueue* queue = nullptr; - PalSwapchain* swapchain = nullptr; - PalCommandPool* cmdPool = nullptr; - PalImageView** imageViews = nullptr; - PalCommandBuffer** cmdBuffers = nullptr; - PalRenderPass* renderPass = nullptr; - PalRenderPassView** renderPassViews = nullptr; - - PalMemory* vertexbufferMemory = nullptr; - PalBuffer* vertexBuffer = nullptr; - PalShader* vertexShader = nullptr; - PalShader* fragmentShader = nullptr; - PalPipelineLayout* pipelineLayout = nullptr; - PalPipeline* pipeline = nullptr; - PalFence** fences = nullptr; - - // initialize the graphics system - PalGraphicsDebugger gfxDebugger = {0}; - gfxDebugger.callback = onGraphicsDebug; - - PalResult result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -167,40 +132,36 @@ bool triangleTest() } // enumerate all available adapters - Int32 count = 0; - result = palEnumerateAdapters(&count, nullptr); + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); return false; } - if (count == 0) { + if (adapterCount == 0) { palLog(nullptr, "No adapters found"); return false; } - palLog(nullptr, "Adapter count: %d", count); + palLog(nullptr, "Adapter count: %d", adapterCount); - // allocate an array of adapters or use a fixed array - // Example: PalAdapter* adapters[12]; PalAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); return false; } - result = palEnumerateAdapters(&count, adapters); + result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); return false; } - // get information about all the adapters and find the adapter that - // has graphics queue PalAdapterCapabilities caps; - for (Int32 i = 0; i < count; i++) { + for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -218,9 +179,9 @@ bool triangleTest() } palFree(nullptr, adapters); - PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); - + // create a device + PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { features |= PAL_ADAPTER_FEATURE_FENCE_RESET; @@ -241,10 +202,6 @@ bool triangleTest() return false; } - // check if the queue can present on our window - PalGraphicsWindow gfxWindow; - gfxWindow.window = windowHandleInfo.nativeWindow; - gfxWindow.display = windowHandleInfo.nativeDisplay; if (!palCanQueuePresent(queue, &gfxWindow)) { palLog(nullptr, "Queue cannot present to window"); return false; @@ -267,16 +224,16 @@ bool triangleTest() swapchainCreateInfo.clipped = true; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - swapchainCreateInfo.height = windowHeight; - swapchainCreateInfo.width = windowWidth; + swapchainCreateInfo.height = WINDOW_HEIGHT; + swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; // rare but possible on andriod - if (windowWidth > swapchainCaps.maxImageWidth) { + if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; } - if (windowHeight > swapchainCaps.maxImageHeight) { + if (WINDOW_HEIGHT > swapchainCaps.maxImageHeight) { swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; } @@ -298,345 +255,547 @@ bool triangleTest() return false; } - // create a command pool for the command buffers - PalCommandPoolCreateInfo cmdPoolCreateInfo = {0}; - cmdPoolCreateInfo.queue = queue; - result = palCreateCommandPool(device, &cmdPoolCreateInfo, &cmdPool); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); - return false; - } - - // get all swapchain images and create command buffers and image views - // for them. This is much faster than resetting and recording per frames + // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate( nullptr, sizeof(PalImageView*) * imageCount, 0); - renderPassViews = palAllocate( + renderFinishedSemaphores = palAllocate( nullptr, - sizeof(PalRenderPassView*) * imageCount, + sizeof(PalSemaphore*) * imageCount, 0); - cmdBuffers = palAllocate( - nullptr, - sizeof(PalCommandBuffer*) * imageCount, - 0); - - fences = palAllocate( - nullptr, - sizeof(PalFence*) * imageCount + 1, // next image fence - 0); - - if (!imageViews || !renderPassViews || !cmdBuffers || !fences) { + if (!imageViews || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); return false; } - // create render pass - PalAttachmentDesc presentAttachment = {0}; - presentAttachment.loadOp = PAL_LOAD_OP_CLEAR; - presentAttachment.storeOp = PAL_STORE_OP_STORE; - presentAttachment.type = PAL_ATTACHMENT_TYPE_PRESENT; - presentAttachment.sampleCount = PAL_SAMPLE_COUNT_1; - presentAttachment.format = palGetSwapchainFormat(swapchain); - - PalRenderPassCreateInfo renderPasscreateInfo = {0}; - renderPasscreateInfo.attachmentCount = 1; - renderPasscreateInfo.attachments = &presentAttachment; + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.layerArrayCount = 1; + imageViewCreateInfo.mipLevelCount = 1; + imageViewCreateInfo.startArrayLayer = 0; + imageViewCreateInfo.startMipLevel = 0; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; - result = palCreateRenderPass( - device, - &renderPasscreateInfo, - &renderPass); + for (int i = 0; i < imageCount; i++) { + // get swapchain image + // this is fast since the images are cache by PAL + PalImage* image = palGetSwapchainImage(swapchain, i); + if (!image) { + palLog(nullptr, "Failed to get swapchain image"); + } + + result = palCreateImageView( + device, + image, + &imageViewCreateInfo, + &imageViews[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + } + + result = palCreateCommandPool( + device, + queue, + &cmdPool); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create render pass: %s", error); + palLog(nullptr, "Failed to create command pool: %s", error); return false; } - // create shaders - Uint64 vertexShaderSize = 0; - Uint64 fragmentShaderSize = 0; - void* vertexShaderBytecode = nullptr; - void* fragmentShaderBytecode = nullptr; - readFile("shaders/triangle_vert.spv", nullptr, &vertexShaderSize); - readFile("shaders/triangle_frag.spv", nullptr, &fragmentShaderSize); - - if (!vertexShaderSize && !fragmentShaderSize) { - palLog(nullptr, "Failed to find shader files"); - return false; + // create synchronization objects + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateFence(device, true, &inFlightFences[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + result = palCreateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffers[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command buffer: %s", error); + return false; + } } - vertexShaderBytecode = palAllocate(nullptr, vertexShaderSize, 0); - fragmentShaderBytecode = palAllocate(nullptr, fragmentShaderSize, 0); - if (!vertexShaderBytecode && !fragmentShaderBytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; + // create synchronization objects + for (int i = 0; i < imageCount; i++) { + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } } - readFile( - "shaders/triangle_vert.spv", - vertexShaderBytecode, - &vertexShaderSize); + // create vertex and staging buffer + float vertices[] = { + 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + -0.5f, -0.5f, 0.0f, 0.0f, 1.0f}; - readFile( - "shaders/triangle_frag.spv", - fragmentShaderBytecode, - &fragmentShaderSize); + PalBufferCreateInfo bufferCreateInfo = {0}; + bufferCreateInfo.size = sizeof(vertices); + bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + + result = palCreateBuffer( + device, + &bufferCreateInfo, + &vertexBuffer); - PalShaderCreateInfo shaderCreateInfo = {0}; - shaderCreateInfo.bytecode = vertexShaderBytecode; - shaderCreateInfo.bytecodeSize = vertexShaderSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; - result = palCreateShader(device, &shaderCreateInfo, &vertexShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create vertex shader: %s", error); + palLog(nullptr, "Failed to create vertex buffer: %s", error); return false; } - shaderCreateInfo.bytecode = fragmentShaderBytecode; - shaderCreateInfo.bytecodeSize = fragmentShaderSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; - result = palCreateShader(device, &shaderCreateInfo, &fragmentShader); + bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send + result = palCreateBuffer( + device, + &bufferCreateInfo, + &stagingBuffer); + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fragment shader: %s", error); + palLog(nullptr, "Failed to create staging buffer: %s", error); return false; } - palFree(nullptr, vertexShaderBytecode); - palFree(nullptr, fragmentShaderBytecode); + // get buffer memory requirement and allocate memory + PalMemoryRequirements vertexBufferMemReq = {0}; + PalMemoryRequirements stagingBufferMemReq = {0}; + result = palGetBufferMemoryRequirements( + vertexBuffer, + &vertexBufferMemReq); - // create graphics pipeline - // vertex attributes and vertex layout - PalVertexAttribute attributes[2]; - PalVertexLayout layout; + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } - PalVertexAttribute* position = &attributes[0]; - position->location = 0; - position->type = PAL_VERTEX_TYPE_FLOAT2; + result = palGetBufferMemoryRequirements( + stagingBuffer, + &stagingBufferMemReq); - PalVertexAttribute* color = &attributes[1]; - color->location = 1; - color->type = PAL_VERTEX_TYPE_FLOAT3; // no alpha + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } - layout.binding = 0; - layout.type = PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX; - layout.attributeCount = 2; - layout.attributes = attributes; + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + vertexBufferMemReq.size, + &vertexBufferMemory); - PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; - pipelineCreateInfo.vertexLayouts = &layout; - pipelineCreateInfo.vertexLayoutCount = 1; + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } - // Input assembly - pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + stagingBufferMemReq.size, + &stagingBufferMemory); - // Color blend attachment - // we need one for each attachment in our render pass - PalBlendAttachment blendAttachment = {0}; - blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; - blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; - blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; - blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } - pipelineCreateInfo.blendAttachmentCount = 1; - pipelineCreateInfo.blendAttachments = &blendAttachment; + // bind memory + result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } - // shaders - PalShader* shaders[2]; // vertex and fragment - shaders[0] = vertexShader; - shaders[1] = fragmentShader; - pipelineCreateInfo.shaders = shaders; - pipelineCreateInfo.shaderCount = 2; + result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } - // pipeline layput - PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; - result = palCreatePipelineLayout( + // map the staging buffer and upload the vertices + void* ptr = nullptr; + result = palMapMemory( device, - &pipelineLayoutCreateInfo, - &pipelineLayout); + stagingBufferMemory, + 0, + sizeof(vertices), + &ptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); + palLog(nullptr, "Failed to map memory: %s", error); return false; } - pipelineCreateInfo.renderPass = renderPass; - pipelineCreateInfo.pipelineLayout = pipelineLayout; - result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); + memcpy(ptr, vertices, sizeof(vertices)); + palUnmapMemory(device, stagingBufferMemory); + + PalFence* fence = nullptr; + result = palCreateFence(device, false, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline: %s", error); + palLog(nullptr, "Failed to create fence: %s", error); return false; } - // triangle vertices - // float 2 for pos and float 3 for color - float vertices[] = { - 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, - -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, - 0.5f, -0.5f, 0.0f, 0.0f, 1.0f - }; + // use the first command buffer to upload the copy + // and reset it when done + // set a fence and check at the last line before the main loop + // to see if we have to wait for the copy to be executed + result = palBeginCommandBuffer(cmdBuffers[0], nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + result = palCopyBuffer( + cmdBuffers[0], + vertexBuffer, + stagingBuffer, + 0, + 0, + sizeof(vertices)); + + result = palBufferBarrier( + cmdBuffers[0], + vertexBuffer, + PAL_USAGE_STATE_TRANSFER_WRITE, + PAL_USAGE_STATE_VERTEX_READ); - PalBufferCreateInfo bufferCreateInfo = {0}; - bufferCreateInfo.size = sizeof(vertices); - bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; - result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create buffer: %s", error); + palLog(nullptr, "Failed to set image view barrier: %s", error); return false; } - PalMemoryRequirements memReq = {0}; - result = palGetBufferMemoryRequirements(vertexBuffer, &memReq); + result = palEndCommandBuffer(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create buffer: %s", error); + palLog(nullptr, "Failed to end command buffer: %s", error); return false; } - // check if the memory type is supported - result = palAllocateMemory( + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffers[0]; + submitInfo.fence = fence; + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // create shaders + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + PalShaderCreateInfo shaderCreateInfo = {0}; + + if (!readFile("shaders/triangle_vert.spv", nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to find shader files"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile("shaders/triangle_vert.spv", bytecode, &bytecodeSize); + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; + + result = palCreateShader( device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - memReq.size, - &vertexbufferMemory); + &shaderCreateInfo, + &vertexShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate gpu memory: %s", error); + palLog(nullptr, "Failed to create vertex shader: %s", error); + return false; + } + + // fragment shader + bytecodeSize = 0; + palFree(nullptr, bytecode); + bytecode = nullptr; + + if (!readFile("shaders/triangle_frag.spv", nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to find shader files"); return false; } - result = palBindBufferMemory(vertexBuffer, vertexbufferMemory, 0); + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile("shaders/triangle_frag.spv", bytecode, &bytecodeSize); + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; + + result = palCreateShader( + device, + &shaderCreateInfo, + &fragmentShader); + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind gpu memory: %s", error); + palLog(nullptr, "Failed to create fragment shader: %s", error); return false; } - // map the memory and fill with our vertices - void* data = nullptr; - result = palMapMemory( + palFree(nullptr, bytecode); + + // create a pipeline layout + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + result = palCreatePipelineLayout( device, - vertexbufferMemory, - 0, - sizeof(vertices), - &data); + &pipelineLayoutCreateInfo, + &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map gpu memory: %s", error); + palLog(nullptr, "Failed to create pipeline layout: %s", error); return false; } - memcpy(data, vertices, sizeof(vertices)); - palUnmapMemory(device, vertexbufferMemory); + // the graphics pipeline needs the layout of the rendering + // info it will be used with + // we get the any image from the swapchain and get the format + // on the image since our color attachment takes a swapchain image + PalImage* image = palGetSwapchainImage(swapchain, 0); + PalImageInfo imageInfo = {0}; + result = palGetImageInfo(image, &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } - // viewport and scissor - PalViewport viewport = {0}; - viewport.width = (float)swapchainCreateInfo.width; - viewport.height = (float)swapchainCreateInfo.height; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; + PalRenderingLayoutInfo renderingLayoutInfo = {0}; + renderingLayoutInfo.colorAttachentCount = 1; + renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; + renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.viewCount = 1; + + // create graphics pipeline + PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; + PalVertexLayout vertexLayout = {0}; + PalVertexAttribute vertexAttributes[2]; + + // position + vertexAttributes[0].location = 0; + vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; + + // color + vertexAttributes[1].location = 1; + vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT3; - PalScissor scissor = {0}; - scissor.width = swapchainCreateInfo.width; - scissor.height = swapchainCreateInfo.height; + vertexLayout.attributeCount = 2; + vertexLayout.attributes = vertexAttributes; + vertexLayout.binding = 0; // first vertex buffer binding slot + vertexLayout.type = PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX; + + pipelineCreateInfo.vertexLayoutCount = 1; + pipelineCreateInfo.vertexLayouts = &vertexLayout; + + // color blend attachment + PalBlendAttachment blendAttachment = {0}; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; + + pipelineCreateInfo.blendAttachments = &blendAttachment; + pipelineCreateInfo.blendAttachmentCount = 1; + + // multisample state + PalMultisampleState multisampleState = {0}; + multisampleState.sampleCount = PAL_SAMPLE_COUNT_1; + pipelineCreateInfo.multisampleState = &multisampleState; + + // shaders + PalShader* shaders[2]; + shaders[0] = vertexShader; + shaders[1] = fragmentShader; + pipelineCreateInfo.shaderCount = 2; + pipelineCreateInfo.shaders = shaders; + + pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + pipelineCreateInfo.pipelineLayout = pipelineLayout; + pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; + + result = palCreateGraphicsPipeline( + device, + &pipelineCreateInfo, + &pipeline); - result = palCreateFence(device, &fences[imageCount]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + palLog(nullptr, "Failed to create graphics pipeline: %s", error); return false; } + + palDestroyShader(vertexShader); + palDestroyShader(fragmentShader); - for (int i = 0; i < imageCount; i++) { - // get swapchain image - PalImage* image = palGetSwapchainImage(swapchain, i); - if (!image) { - palLog(nullptr, "Failed to get swapchain image"); - } + // wait for the vertices copy to be done + result = palWaitFence(fence, UINT64_MAX); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } - // create image view - // swapchain images are 2D and they only supports 2D - // and 2D array view types - PalImageView* imageView = nullptr; - PalImageViewCreateInfo imageViewCreateInfo = {0}; - imageViewCreateInfo.layerArrayCount = 1; - imageViewCreateInfo.mipLevelCount = 1; - imageViewCreateInfo.startArrayLayer = 0; - imageViewCreateInfo.startMipLevel = 0; - imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; + // the vertices have been copied + palDestroyFence(fence); + palDestroyBuffer(stagingBuffer); + palFreeMemory(device, stagingBufferMemory); - result = palCreateImageView( - device, - image, - &imageViewCreateInfo, - &imageView); + // main loop + Uint32 currentFrame = 0; + bool running = true; + PalSemaphore* presentCompleteSemaphore = nullptr; + PalSemaphore* renderFinishedSemaphore = nullptr; + fence = nullptr; + PalCommandBuffer* cmdBuffer = nullptr; - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); - return false; + bool firstImageViewUse[8]; + memset(firstImageViewUse, 1, sizeof(bool) * 8); + + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + + PalRect2D scissor = {0}; + scissor.height = WINDOW_HEIGHT; + scissor.width = WINDOW_WIDTH; + + PalDrawData drawData = {0}; + drawData.vertexCount = 3; + drawData.instanceCount = 1; + + while (running) { + // update the video system to push video events + palUpdateVideo(); + + PalEvent event; + while (palPollEvent(eventDriver, &event)) { + switch (event.type) { + case PAL_EVENT_WINDOW_CLOSE: { + running = false; + break; + } + + case PAL_EVENT_KEYDOWN: { + PalKeycode keycode = 0; + palUnpackUint32(event.data, &keycode, nullptr); + if (keycode == PAL_KEYCODE_ESCAPE) { + running = false; + } + break; + } + } } - - // create a command buffer - PalCommandBuffer* cmdBuffer = nullptr; - result = palCreateCommandBuffer( - device, - cmdPool, - PAL_COMMAND_BUFFER_TYPE_PRIMARY, - &cmdBuffer); + fence = inFlightFences[currentFrame]; + presentCompleteSemaphore = presentCompleteSemaphores[currentFrame]; + cmdBuffer = cmdBuffers[currentFrame]; + + result = palWaitFence(fence, UINT64_MAX); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command buffer: %s", error); + palLog(nullptr, "Failed to wait fence: %s", error); return false; } - // create fences - PalFence* fence = nullptr; - result = palCreateFence(device, &fence); + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + result = palResetFence(fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + } else { + // recreate since we dont support fence resetting + palDestroyFence(fence); + + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = presentCompleteSemaphore; + nextImageInfo.timeout = UINT64_MAX; + + Uint32 index = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &index); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + palLog(nullptr, "Failed to get next swapchain image: %s", error); return false; } - // create a render pass view - PalRenderPassView* renderPassView = nullptr; - PalRenderPassViewCreateInfo renderPassViewCreateInfo = {0}; - renderPassViewCreateInfo.width = swapchainCreateInfo.width; - renderPassViewCreateInfo.height = swapchainCreateInfo.height; - renderPassViewCreateInfo.imageViewCount = 1; - renderPassViewCreateInfo.imageViews = &imageView; - - result = palCreateRenderPassView( - device, - renderPass, - &renderPassViewCreateInfo, - &renderPassView); + renderFinishedSemaphore = renderFinishedSemaphores[index]; + // reset the command buffer + result = palResetCommandBuffer(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create render pass view: %s", error); + palLog(nullptr, "Failed to reset command buffer: %s", error); return false; } - // begin command buffer recording - // the optional render pass is used for secondary command buffer - // which will be used with a render pass result = palBeginCommandBuffer(cmdBuffer, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -644,27 +803,55 @@ bool triangleTest() return false; } - // record commands - PalClearValue clearValue = {0}; + // change the state of the image view to make it renderable + PalUsageState oldUsageState; + if (firstImageViewUse[index]) { + oldUsageState = PAL_USAGE_STATE_UNDEFINED; + } else { + oldUsageState = PAL_USAGE_STATE_PRESENT; + } + + result = palImageViewBarrier( + cmdBuffer, + imageViews[index], + oldUsageState, + PAL_USAGE_STATE_COLOR_ATTACHMENT); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + PalClearValue clearValue; clearValue.color[0] = 0.2f; clearValue.color[1] = 0.2f; clearValue.color[2] = 0.2f; clearValue.color[3] = 1.0f; - PalRenderPassBeginInfo renderPassBeginInfo = {0}; - renderPassBeginInfo.clearValueCount = 1; - renderPassBeginInfo.clearValues = &clearValue; - renderPassBeginInfo.renderPass = renderPass; - renderPassBeginInfo.view = renderPassView; - - result = palBeginRenderPass(cmdBuffer, &renderPassBeginInfo); + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.clearValue = clearValue; + colorAttachment.imageView = imageViews[index]; + + PalRenderingInfo renderingInfo = {0}; + renderingInfo.viewCount = 1; + renderingInfo.colorAttachentCount = 1; + renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.layerCount = 1; + renderingInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; + + result = palBeginRendering(cmdBuffer, &renderingInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin render pass: %s", error); + palLog(nullptr, "Failed to begin rendering: %s", error); return false; } - // bind pipeline and set scissors and viewports + // bind pipeline result = palBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -672,6 +859,7 @@ bool triangleTest() return false; } + // set viewport and scissors result = palSetViewport(cmdBuffer, 1, &viewport); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -682,11 +870,12 @@ bool triangleTest() result = palSetScissors(cmdBuffer, 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set scissor: %s", error); + palLog(nullptr, "Failed to set scissors: %s", error); return false; } - Uint64 offset[] = { 0 }; + // bind vertex buffer + Uint64 offset[] = {0}; result = palBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, offset); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -694,119 +883,46 @@ bool triangleTest() return false; } - PalDrawData drawData = {0}; - drawData.vertexCount = 3; - drawData.instancecCount = 1; - result = palDraw(cmdBuffer, &drawData); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to draw vertices: %s", error); + palLog(nullptr, "Failed to issue draw command: %s", error); return false; } - result = palEndRenderPass(cmdBuffer); + result = palEndRendering(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end render pass: %s", error); + palLog(nullptr, "Failed to end rendering: %s", error); return false; } - // end command buffer recording - result = palEndCommandBuffer(cmdBuffer); + // change the state of the image view to make it presentable + result = palImageViewBarrier( + cmdBuffer, + imageViews[index], + PAL_USAGE_STATE_COLOR_ATTACHMENT, + PAL_USAGE_STATE_PRESENT); + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + palLog(nullptr, "Failed to set image view barrier: %s", error); return false; } - - // cache everything so we can reference and destroy later - renderPassViews[i] = renderPassView; - cmdBuffers[i] = cmdBuffer; - imageViews[i] = imageView; - fences[i] = fence; - } - - // main loop - bool running = true; - while (running) { - // update the video system to push video events - palUpdateVideo(); - - PalEvent event; - while (palPollEvent(eventDriver, &event)) { - switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { - running = false; - break; - } - - case PAL_EVENT_KEYDOWN: { - PalKeycode keycode = 0; - palUnpackUint32(event.data, &keycode, nullptr); - if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; - } - break; - } - } - } - if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { - for (int i = 0; i < imageCount + 1; i++) { - result = palResetFence(fences[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to reset fence: %s", error); - return false; - } - } - - } else { - for (int i = 0; i < imageCount + 1; i++) { - palDestroyFence(fences[i]); - - result = palCreateFence(device, &fences[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); - return false; - } - } - } - - // get the next image that we can render too - PalImage* image = nullptr; - PalNextImageInfo nextImageInfo = {0}; - nextImageInfo.timeout = UINT64_MAX; - nextImageInfo.fence = fences[imageCount]; - - image = palGetNextSwapchainImage(swapchain, &nextImageInfo); - - // wait till the image is acquired - result = palWaitFence(fences[imageCount], UINT64_MAX); + result = palEndCommandBuffer(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); + palLog(nullptr, "Failed to end command buffer: %s", error); return false; } - // find the command buffer associated with the image - // this is fast, the swapchain caches all it images internally - PalCommandBuffer* cmdBuffer = nullptr; - PalFence* fence = nullptr; - for (int i = 0; i < imageCount; i++) { - if (image == palGetSwapchainImage(swapchain, i)) { - cmdBuffer = cmdBuffers[i]; - fence = fences[i]; - break; - } - } - - // submit to the queue and present - PalSubmitInfo submitInfo = {0}; + // submit command buffer + PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffer; submitInfo.fence = fence; + submitInfo.waitSemaphore = presentCompleteSemaphore; + submitInfo.signalSemaphore = renderFinishedSemaphore; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -815,54 +931,53 @@ bool triangleTest() return false; } - // wait for the commands to be executed - result = palWaitFence(fence, UINT64_MAX); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); - return false; - } - - PalPresentInfo presentInfo = {0}; - presentInfo.image = image; - + // present + PalSwapchainPresentInfo presentInfo = {0}; + presentInfo.imageIndex = index; + presentInfo.waitSemaphore = renderFinishedSemaphore; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to present swapchain: %s", error); return false; } - } - // cleanup - for (int i = 0; i < imageCount; i++) { - palDestroyRenderPassView(renderPassViews[i]); - palDestroyCommandBuffer(cmdBuffers[i]); - palDestroyImageView(imageViews[i]); - palDestroyFence(fences[i]); + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } - palDestroyFence(fences[imageCount]); + result = palWaitDevice(device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for device: %s", error); + return false; + } palDestroyPipeline(pipeline); palDestroyPipelineLayout(pipelineLayout); + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + palDestroySemaphore(presentCompleteSemaphores[i]); + palDestroyFence(inFlightFences[i]); + palDestroyCommandBuffer(cmdBuffers[i]); + } + + for (int i = 0; i < imageCount; i++) { + palDestroyImageView(imageViews[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); + } + palDestroyBuffer(vertexBuffer); - palFreeMemory(device, vertexbufferMemory); + palFreeMemory(device, vertexBufferMemory); - palDestroyRenderPass(renderPass); palDestroyCommandPool(cmdPool); - palDestroyShader(vertexShader); - palDestroyShader(fragmentShader); - palDestroySwapchain(swapchain); palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); - palFree(nullptr, imageViews); - palFree(nullptr, cmdBuffers); - palFree(nullptr, renderPassViews); - shutdownVideo(window, eventDriver); + palDestroyWindow(window); + palShutdownVideo(); + palDestroyEventDriver(eventDriver); return true; } \ No newline at end of file From cd971d7500403062b4d6b5fbde75bdb842480935 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 7 Jan 2026 10:54:41 +0000 Subject: [PATCH 075/372] make triangle test API agnostic --- include/pal/pal_graphics.h | 6 ++--- src/graphics/pal_vulkan.c | 50 +++++++++++++++++++++++++++++--------- tests/graphics_test.c | 4 +-- tests/tests_main.c | 2 +- tests/triangle_test.c | 28 ++++++++++++++++++--- 5 files changed, 68 insertions(+), 22 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 46c6284f..19ff0f27 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -252,9 +252,9 @@ typedef enum { PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(26), PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(27), PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(28), - PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT = PAL_BIT64(29), - PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(31) + PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(29), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(30), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(31) } PalAdapterFeatures; typedef enum { diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 1480120d..89853449 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2727,7 +2727,7 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; } else if (strcmp(props->extensionName, "VK_KHR_draw_indirect_count") == 0) { - adapterFeatures |= PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT; + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; } else if (strcmp(props->extensionName, "VK_KHR_buffer_device_address") == 0) { bufferDeviceAddress = true; @@ -2888,6 +2888,21 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } } + // indirect draw count is part of core 1.2 + if (props.apiVersion >= VK_API_VERSION_1_2) { + VkPhysicalDeviceVulkan12Features features12 = {0}; + features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &features12; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (features12.drawIndirectCount) { + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; + } + } + // clang-format on VkPhysicalDeviceFeatures features; s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); @@ -3048,8 +3063,8 @@ PalResult PAL_CALL createVkDevice( const char* extensions[16] = {0}; // clang-format off - VkPhysicalDeviceTimelineSemaphoreFeatures timeline = {0}; - timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES; + VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline = {0}; + timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; @@ -3086,6 +3101,9 @@ PalResult PAL_CALL createVkDevice( VkPhysicalDeviceSynchronization2FeaturesKHR sync2 = {0}; sync2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR; + VkPhysicalDeviceVulkan12Features features12 = {0}; + features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + // clang-format on if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_KHR_dynamic_rendering"; @@ -3112,6 +3130,7 @@ PalResult PAL_CALL createVkDevice( extensions[extCount++] = "VK_KHR_timeline_semaphore"; } timeline.timelineSemaphore = true; + features12.timelineSemaphore = true; timeline.pNext = next; next = &timeline; @@ -3122,6 +3141,8 @@ PalResult PAL_CALL createVkDevice( extensions[extCount++] = "VK_KHR_shader_float16_int8"; } shader16.shaderFloat16 = true; + features12.shaderFloat16 = true; + features12.shaderInt8 = true; shader16.pNext = next; next = &shader16; @@ -3140,17 +3161,10 @@ PalResult PAL_CALL createVkDevice( next = &acc; } - if ((features & PAL_ADAPTER_FEATURE_MESH_SHADER) || - (features & PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT)) { + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_EXT_mesh_shader"; } - - if (features & PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_KHR_draw_indirect_count"; - } - } mesh.meshShader = true; mesh.taskShader = true; @@ -3158,6 +3172,16 @@ PalResult PAL_CALL createVkDevice( next = &mesh; } + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_draw_indirect_count"; + } + features12.drawIndirectCount = true; + + features12.pNext = next; + next = &features12; + } + if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { if (props.apiVersion < VK_API_VERSION_1_3) { @@ -3179,6 +3203,7 @@ PalResult PAL_CALL createVkDevice( extensions[extCount++] = "VK_EXT_descriptor_indexing"; } descIndex.shaderSampledImageArrayNonUniformIndexing = true; + features12.descriptorIndexing = true; descIndex.pNext = next; next = &descIndex; @@ -3221,6 +3246,7 @@ PalResult PAL_CALL createVkDevice( extensions[extCount++] = "VK_KHR_buffer_device_address"; } bufferAddress.bufferDeviceAddress = true; + features12.bufferDeviceAddress = true; bufferAddress.pNext = next; next = &bufferAddress; @@ -5346,7 +5372,7 @@ PalResult PAL_CALL drawVkMeshTasksIndirectCount( { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; if (!(vkCmdBuffer->device->features & - PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT)) { + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 647c36a2..014ca654 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -288,8 +288,8 @@ bool graphicsTest() palLog(nullptr, " Fragment shading rate attachment"); } - if (features & PAL_ADAPTER_FEATURE_MESH_SHADER_INDIRECT_COUNT) { - palLog(nullptr, " Mesh shader indirect count"); + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { + palLog(nullptr, " Indirect draw count"); } if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { diff --git a/tests/tests_main.c b/tests/tests_main.c index ebfc9435..fcf2c838 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -55,7 +55,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest("Graphics Test", graphicsTest); + registerTest("Graphics Test", graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO diff --git a/tests/triangle_test.c b/tests/triangle_test.c index f1041cd5..f4ef31ed 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -178,6 +178,15 @@ bool triangleTest() } } + PalAdapterInfo adapterInfo = {0}; + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + palFree(nullptr, adapters); + return false; + } + palFree(nullptr, adapters); // create a device @@ -408,6 +417,10 @@ bool triangleTest() return false; } + // we need to check if the memory type we want are supported + // but almost every GPU supports a GPU only memory + // and CPU writable memory + result = palAllocateMemory( device, PAL_MEMORY_TYPE_GPU_ONLY, @@ -526,7 +539,14 @@ bool triangleTest() void* bytecode = nullptr; PalShaderCreateInfo shaderCreateInfo = {0}; - if (!readFile("shaders/triangle_vert.spv", nullptr, &bytecodeSize)) { + const char* vertexShaderPath = nullptr; + const char* fragShaderPath = nullptr; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + vertexShaderPath = "shaders/triangle_vert.spv"; + fragShaderPath = "shaders/triangle_frag.spv"; + } + + if (!readFile(vertexShaderPath, nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to find shader files"); return false; } @@ -537,7 +557,7 @@ bool triangleTest() return false; } - readFile("shaders/triangle_vert.spv", bytecode, &bytecodeSize); + readFile(vertexShaderPath, bytecode, &bytecodeSize); shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; @@ -558,7 +578,7 @@ bool triangleTest() palFree(nullptr, bytecode); bytecode = nullptr; - if (!readFile("shaders/triangle_frag.spv", nullptr, &bytecodeSize)) { + if (!readFile(fragShaderPath, nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to find shader files"); return false; } @@ -569,7 +589,7 @@ bool triangleTest() return false; } - readFile("shaders/triangle_frag.spv", bytecode, &bytecodeSize); + readFile(fragShaderPath, bytecode, &bytecodeSize); shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; From e3b105d69c78aee8137ea2ae1b6a9530f64739ea Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 7 Jan 2026 14:37:55 +0000 Subject: [PATCH 076/372] add mesh shader test --- src/graphics/pal_vulkan.c | 43 +-- tests/clear_color_test.c | 5 + tests/mesh_test.c | 794 ++++++++++++++++++++++++++++++++++++++ tests/shaders/mesh.spv | Bin 0 -> 1948 bytes tests/tests.c | 27 +- tests/tests.h | 6 +- tests/tests.lua | 3 +- tests/tests_main.c | 61 +-- tests/triangle_test.c | 16 +- 9 files changed, 869 insertions(+), 86 deletions(-) create mode 100644 tests/mesh_test.c create mode 100644 tests/shaders/mesh.spv diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 89853449..6da7e539 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -208,8 +208,6 @@ typedef struct { PFN_vkQueuePresentKHR queuePresent; // semaphore - PFN_vkCreateSemaphore createSemaphore; - PFN_vkDestroySemaphore destroySemaphore; PFN_vkWaitSemaphores waitSemaphore; PFN_vkSignalSemaphore signalSemaphore; PFN_vkGetSemaphoreCounterValue getSemaphoreValue; @@ -2735,10 +2733,8 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } // features that require core and extension support - // ray tracing is part of core 1.3 - if (props.apiVersion >= VK_API_VERSION_1_3 || - (rayTracingFound && accelerateFound)) { - + // ray tracing is not part of core + if (rayTracingFound && accelerateFound) { VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; @@ -2756,8 +2752,8 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } } - // mesh shader is part of core 1.3 - if (props.apiVersion >= VK_API_VERSION_1_3 || meshShader) { + // mesh shader is not part of core + if (meshShader) { VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; @@ -2771,8 +2767,8 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } } - // fragment shading rate is part of core 1.3 - if (props.apiVersion >= VK_API_VERSION_1_3 || fragmentRateShading) { + // fragment shading rate is not part of core + if (fragmentRateShading) { VkPhysicalDeviceFragmentShadingRateFeaturesKHR frag = {0}; frag.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; @@ -3149,10 +3145,8 @@ PalResult PAL_CALL createVkDevice( } if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - if (props.apiVersion < VK_API_VERSION_1_3) { - extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; - extensions[extCount++] = "VK_KHR_acceleration_structure"; - } + extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; + extensions[extCount++] = "VK_KHR_acceleration_structure"; ray.rayTracingPipeline = true; acc.accelerationStructure = true; @@ -3162,12 +3156,13 @@ PalResult PAL_CALL createVkDevice( } if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { - if (props.apiVersion < VK_API_VERSION_1_3) { - extensions[extCount++] = "VK_EXT_mesh_shader"; - } + extensions[extCount++] = "VK_EXT_mesh_shader"; mesh.meshShader = true; mesh.taskShader = true; + // mesh shader needs geometry feature for primitives + coreFeatures.geometryShader = true; + mesh.pNext = next; next = &mesh; } @@ -3184,14 +3179,12 @@ PalResult PAL_CALL createVkDevice( if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { - if (props.apiVersion < VK_API_VERSION_1_3) { - extensions[extCount++] = "VK_KHR_fragment_shading_rate"; - fsr.pipelineFragmentShadingRate = true; + extensions[extCount++] = "VK_KHR_fragment_shading_rate"; + fsr.pipelineFragmentShadingRate = true; - // fragment shading rate attachment needs this - if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { - fsr.attachmentFragmentShadingRate = true; - } + // fragment shading rate attachment needs this + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { + fsr.attachmentFragmentShadingRate = true; } fsr.pNext = next; @@ -5330,7 +5323,7 @@ PalResult PAL_CALL drawVkMeshTasks( } vkCmdBuffer->device->cmdDrawMeshTask( - vkCmdBuffer->handle, + vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index be6e4617..63e8ff66 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -147,6 +147,11 @@ bool clearColorTest() } palFree(nullptr, adapters); + if (!adapter) { + palLog(nullptr, + "Failed to find an adapter that supports graphics queue"); + return false; + } // create a device PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); diff --git a/tests/mesh_test.c b/tests/mesh_test.c new file mode 100644 index 00000000..086c151b --- /dev/null +++ b/tests/mesh_test.c @@ -0,0 +1,794 @@ + +#include "pal/pal_graphics.h" +#include "pal/pal_video.h" +#include "tests.h" + +#include + +static bool readFile(const char* filename, void* buffer, Uint64* size) +{ + FILE* file = fopen(filename, "rb"); + if (!file) { + return false; + } + + fseek(file, 0, SEEK_END); + Uint64 tmpSize = ftell(file); + fseek(file, 0, SEEK_SET); + + if (buffer) { + fread(buffer, 1, (size_t)size, file); + } + + fclose(file); + *size = tmpSize; + return true; +} + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +#define MAX_FRAMES_IN_FLIGHT 2 + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) +{ + palLog(nullptr, msg); +} + +bool meshTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Mesh Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + PalResult result; + PalWindow* window = nullptr; + PalEventDriver* eventDriver = nullptr; + PalGraphicsWindow gfxWindow; + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + + PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* presentCompleteSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images + PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + + PalPipelineLayout* pipelineLayout = nullptr; + PalPipeline* pipeline = nullptr; + PalShader* meshShader = nullptr; + PalShader* fragmentShader = nullptr; + + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create event driver: %s", error); + return false; + } + + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_WINDOW_CLOSE, + PAL_DISPATCH_POLL); + + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_KEYDOWN, + PAL_DISPATCH_POLL); + + result = palInitVideo(nullptr, eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize video: %s", error); + return false; + } + + PalWindowCreateInfo windowCreateInfo = {0}; + windowCreateInfo.height = WINDOW_HEIGHT; + windowCreateInfo.width = WINDOW_WIDTH; + windowCreateInfo.show = true; + windowCreateInfo.title = "Clear Color Window"; + + PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); + if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&windowCreateInfo, &window); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create window: %s", error); + return false; + } + + PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); + gfxWindow.display = winHandle.nativeDisplay; + gfxWindow.window = winHandle.nativeWindow; + + PalGraphicsDebugger debugger; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; + + result = palInitGraphics(nullptr, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (adapterCount == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", adapterCount); + + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&adapterCount, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + PalAdapterCapabilities caps; + PalAdapterFeatures adapterFeatures; + bool hasGfxQueue = false; + for (Int32 i = 0; i < adapterCount; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (caps.maxGraphicsQueues == 0) { + continue; + } else { + hasGfxQueue = true; + adapterFeatures = palGetAdapterFeatures(adapter); + if (adapterFeatures & PAL_ADAPTER_FEATURE_MESH_SHADER) { + break; + } + } + } + + palFree(nullptr, adapters); + if (!adapter) { + if (hasGfxQueue) { + palLog(nullptr, + "Failed to find an adapter that supports graphics queue"); + + } else { + palLog(nullptr, + "Failed to find an adapter that supports mesh shader"); + } + return false; + } + + PalAdapterInfo adapterInfo = {0}; + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // create a device + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + features |= PAL_ADAPTER_FEATURE_MESH_SHADER; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + features |= PAL_ADAPTER_FEATURE_FENCE_RESET; + } + + result = palCreateDevice(adapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a graphics command queue + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, &gfxWindow)) { + palLog(nullptr, "Queue cannot present to window"); + return false; + } + + // create a swapchain with the graphics queue + PalSwapchainCapabilities swapchainCaps = {0}; + result = palQuerySwapchainCapabilities( + device, + &gfxWindow, + &swapchainCaps); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to query swapchain capabilities: %s", error); + return false; + } + + PalSwapchainCreateInfo swapchainCreateInfo = {0}; + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + swapchainCreateInfo.height = WINDOW_HEIGHT; + swapchainCreateInfo.width = WINDOW_WIDTH; + swapchainCreateInfo.imageArrayLayerCount = 1; + + // rare but possible on andriod + if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { + swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; + } + + if (WINDOW_HEIGHT > swapchainCaps.maxImageHeight) { + swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; + } + + // check if the minimal image count is not good for you + // and increase it but not pass the max count + swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + + result = palCreateSwapchain( + device, + queue, + &gfxWindow, + &swapchainCreateInfo, + &swapchain); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create swapchain: %s", error); + return false; + } + + // get all swapchain images and create image views for them + Uint32 imageCount = swapchainCreateInfo.imageCount; + imageViews = palAllocate( + nullptr, + sizeof(PalImageView*) * imageCount, + 0); + + renderFinishedSemaphores = palAllocate( + nullptr, + sizeof(PalSemaphore*) * imageCount, + 0); + + if (!imageViews || !renderFinishedSemaphores) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.layerArrayCount = 1; + imageViewCreateInfo.mipLevelCount = 1; + imageViewCreateInfo.startArrayLayer = 0; + imageViewCreateInfo.startMipLevel = 0; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; + + for (int i = 0; i < imageCount; i++) { + // get swapchain image + // this is fast since the images are cache by PAL + PalImage* image = palGetSwapchainImage(swapchain, i); + if (!image) { + palLog(nullptr, "Failed to get swapchain image"); + } + + result = palCreateImageView( + device, + image, + &imageViewCreateInfo, + &imageViews[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + } + + result = palCreateCommandPool( + device, + queue, + &cmdPool); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + // create synchronization objects + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateFence(device, true, &inFlightFences[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + result = palCreateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffers[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command buffer: %s", error); + return false; + } + } + + // create synchronization objects + for (int i = 0; i < imageCount; i++) { + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + } + + // create shaders + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + PalShaderCreateInfo shaderCreateInfo = {0}; + + const char* meshShaderPath = nullptr; + const char* fragShaderPath = nullptr; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + meshShaderPath = "shaders/mesh.spv"; + fragShaderPath = "shaders/triangle_frag.spv"; + } + + if (!readFile(meshShaderPath, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to find shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(meshShaderPath, bytecode, &bytecodeSize); + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_MESH; + + result = palCreateShader( + device, + &shaderCreateInfo, + &meshShader); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create mesh shader: %s", error); + return false; + } + + // fragment shader + bytecodeSize = 0; + palFree(nullptr, bytecode); + bytecode = nullptr; + + if (!readFile(fragShaderPath, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to find shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(fragShaderPath, bytecode, &bytecodeSize); + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; + + result = palCreateShader( + device, + &shaderCreateInfo, + &fragmentShader); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fragment shader: %s", error); + return false; + } + + palFree(nullptr, bytecode); + + // create a pipeline layout + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + result = palCreatePipelineLayout( + device, + &pipelineLayoutCreateInfo, + &pipelineLayout); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline layout: %s", error); + return false; + } + + // the graphics pipeline needs the layout of the rendering + // info it will be used with + // we get the any image from the swapchain and get the format + // on the image since our color attachment takes a swapchain image + PalImage* image = palGetSwapchainImage(swapchain, 0); + PalImageInfo imageInfo = {0}; + result = palGetImageInfo(image, &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } + + PalRenderingLayoutInfo renderingLayoutInfo = {0}; + renderingLayoutInfo.colorAttachentCount = 1; + renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; + renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.viewCount = 1; + + // create graphics pipeline + PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; + + // color blend attachment + PalBlendAttachment blendAttachment = {0}; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; + + pipelineCreateInfo.blendAttachments = &blendAttachment; + pipelineCreateInfo.blendAttachmentCount = 1; + + // multisample state + PalMultisampleState multisampleState = {0}; + multisampleState.sampleCount = PAL_SAMPLE_COUNT_1; + pipelineCreateInfo.multisampleState = &multisampleState; + + // shaders + PalShader* shaders[2]; + shaders[0] = meshShader; + shaders[1] = fragmentShader; + pipelineCreateInfo.shaderCount = 2; + pipelineCreateInfo.shaders = shaders; + + pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + pipelineCreateInfo.pipelineLayout = pipelineLayout; + pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; + + result = palCreateGraphicsPipeline( + device, + &pipelineCreateInfo, + &pipeline); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create graphics pipeline: %s", error); + return false; + } + + palDestroyShader(meshShader); + palDestroyShader(fragmentShader); + + // main loop + Uint32 currentFrame = 0; + bool running = true; + PalSemaphore* presentCompleteSemaphore = nullptr; + PalSemaphore* renderFinishedSemaphore = nullptr; + PalFence* fence = nullptr; + PalCommandBuffer* cmdBuffer = nullptr; + + bool firstImageViewUse[8]; + memset(firstImageViewUse, 1, sizeof(bool) * 8); + + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + + PalRect2D scissor = {0}; + scissor.height = WINDOW_HEIGHT; + scissor.width = WINDOW_WIDTH; + + while (running) { + // update the video system to push video events + palUpdateVideo(); + + PalEvent event; + while (palPollEvent(eventDriver, &event)) { + switch (event.type) { + case PAL_EVENT_WINDOW_CLOSE: { + running = false; + break; + } + + case PAL_EVENT_KEYDOWN: { + PalKeycode keycode = 0; + palUnpackUint32(event.data, &keycode, nullptr); + if (keycode == PAL_KEYCODE_ESCAPE) { + running = false; + } + break; + } + } + } + + fence = inFlightFences[currentFrame]; + presentCompleteSemaphore = presentCompleteSemaphores[currentFrame]; + cmdBuffer = cmdBuffers[currentFrame]; + + result = palWaitFence(fence, UINT64_MAX); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + result = palResetFence(fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + } else { + // recreate since we dont support fence resetting + palDestroyFence(fence); + + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = presentCompleteSemaphore; + nextImageInfo.timeout = UINT64_MAX; + + Uint32 index = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &index); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + renderFinishedSemaphore = renderFinishedSemaphores[index]; + + // reset the command buffer + result = palResetCommandBuffer(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to reset command buffer: %s", error); + return false; + } + + result = palBeginCommandBuffer(cmdBuffer, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + // change the state of the image view to make it renderable + PalUsageState oldUsageState; + if (firstImageViewUse[index]) { + oldUsageState = PAL_USAGE_STATE_UNDEFINED; + } else { + oldUsageState = PAL_USAGE_STATE_PRESENT; + } + + result = palImageViewBarrier( + cmdBuffer, + imageViews[index], + oldUsageState, + PAL_USAGE_STATE_COLOR_ATTACHMENT); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + PalClearValue clearValue; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; + + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.clearValue = clearValue; + colorAttachment.imageView = imageViews[index]; + + PalRenderingInfo renderingInfo = {0}; + renderingInfo.viewCount = 1; + renderingInfo.colorAttachentCount = 1; + renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.layerCount = 1; + renderingInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; + + result = palBeginRendering(cmdBuffer, &renderingInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin rendering: %s", error); + return false; + } + + // bind pipeline + result = palBindPipeline(cmdBuffer, pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + // set viewport and scissors + result = palSetViewport(cmdBuffer, 1, &viewport); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set viewport: %s", error); + return false; + } + + result = palSetScissors(cmdBuffer, 1, &scissor); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set scissors: %s", error); + return false; + } + + // draw a single triangle with the mesh shader + result = palDrawMeshTasks(cmdBuffer, 1, 1, 1); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to issue draw command: %s", error); + return false; + } + + result = palEndRendering(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end rendering: %s", error); + return false; + } + + // change the state of the image view to make it presentable + result = palImageViewBarrier( + cmdBuffer, + imageViews[index], + PAL_USAGE_STATE_COLOR_ATTACHMENT, + PAL_USAGE_STATE_PRESENT); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + result = palEndCommandBuffer(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // submit command buffer + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffer; + submitInfo.fence = fence; + submitInfo.waitSemaphore = presentCompleteSemaphore; + submitInfo.signalSemaphore = renderFinishedSemaphore; + + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // present + PalSwapchainPresentInfo presentInfo = {0}; + presentInfo.imageIndex = index; + presentInfo.waitSemaphore = renderFinishedSemaphore; + result = palPresentSwapchain(swapchain, &presentInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to present swapchain: %s", error); + return false; + } + + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + } + + result = palWaitDevice(device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for device: %s", error); + return false; + } + + palDestroyPipeline(pipeline); + palDestroyPipelineLayout(pipelineLayout); + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + palDestroySemaphore(presentCompleteSemaphores[i]); + palDestroyFence(inFlightFences[i]); + palDestroyCommandBuffer(cmdBuffers[i]); + } + + for (int i = 0; i < imageCount; i++) { + palDestroyImageView(imageViews[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); + } + + palDestroyCommandPool(cmdPool); + palDestroySwapchain(swapchain); + palDestroyQueue(queue); + palDestroyDevice(device); + palShutdownGraphics(); + palFree(nullptr, imageViews); + + palDestroyWindow(window); + palShutdownVideo(); + palDestroyEventDriver(eventDriver); + return true; +} \ No newline at end of file diff --git a/tests/shaders/mesh.spv b/tests/shaders/mesh.spv new file mode 100644 index 0000000000000000000000000000000000000000..d744431c75e75917dda33a0555cd909efe195ccc GIT binary patch literal 1948 zcmZXU+fEZv6oxnSgrHF5jW=hlh}h$0YDO*O%!350mpG%$fl+9~M_jq%E-@CAGT zjW1y0JDGT6;{Q!&H4W}&W$*R>>$KNi)70=%&Si$&m>Y51uD2%Lu=_gg+^EaCz1l(j z&4>MZ%L`BH;Ys7j>&Q0ihGbgZ-PvbaU zW2Jo-L_)HL@h z(d%kb(}K<{blx2PyWS0bE77lNpHdaXT#R3|SJRAavcd`yRzZ4BI|5!z_zOCd({yqW zYgVzwwHG9FvY610K4_bl&b{V^GKcVB3(7!0%m)s^Zb~~Gd8tX)iTeP)k?6b?{ooF> z+6xl$P$T-BgoRGdE3xK&nodtxrt>X0_j$Xd+f&nZ2|ft6@YFJ|oxIpsF5bX$lk28L zs~@W%1#B>u`Q8#vFD>sRr(e#$3_kRqb%#)Qiq+gV76o zpG#OJY51;7z?dzI^Fn8Q;LUF%!OZWKbnL9|LNeN^k#C0o zJa*IhzeC@WH5~838JwJ($z3k$3~%}+ow4~gopNyKJGv*ccSFMLGv5gDz?fIFS=1RD z=F)7y3KFxqtur>vpV@#dNzCS+&e$+_W&_6D?dayzQ<5-C#-kS{#+MVGTBsGBc`|-E s;i&^2otZNJX~I(jJUVj)&-=cVFdLR1omnt`GvO^iI&c10U+lW%A3#rtw*UYD literal 0 HcmV?d00001 diff --git a/tests/tests.c b/tests/tests.c index 4546118c..c442633b 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -3,35 +3,22 @@ #define MAX_TESTS 64 // will change -typedef struct { - TestFn func; - const char* name; -} TestEntry; - -typedef struct { - TestEntry tests[MAX_TESTS]; - Int32 count; -} Tests; - -static Tests s_Test; +static Uint32 s_Count = 0; +static TestFn s_Test[MAX_TESTS]; static const char* s_FailedString = "FAILED"; static const char* s_PassedString = "PASSED"; -void registerTest( - const char* name, - TestFn func) +void registerTest(TestFn func) { - TestEntry* entry = &s_Test.tests[s_Test.count++]; - entry->func = func; - entry->name = name; + s_Test[s_Count++] = func; } void runTests() { bool status = false; const char* statusString = nullptr; - for (Int32 i = 0; i < s_Test.count; i++) { - status = s_Test.tests[i].func(); + for (Int32 i = 0; i < s_Count; i++) { + status = s_Test[i](); if (status) { statusString = s_PassedString; @@ -39,6 +26,6 @@ void runTests() statusString = s_FailedString; } - palLog(nullptr, "%s: %s", s_Test.tests[i].name, statusString); + palLog(nullptr, statusString); } } \ No newline at end of file diff --git a/tests/tests.h b/tests/tests.h index 41f17712..656a1d99 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -6,10 +6,7 @@ typedef bool (*TestFn)(); -void registerTest( - const char* name, - TestFn func); - +void registerTest(TestFn func); void runTests(); // core tests @@ -59,5 +56,6 @@ bool graphicsTest(); // graphics and video bool clearColorTest(); bool triangleTest(); +bool meshTest(); #endif // _TESTS_H \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index 2cb1bff1..d6622c44 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -72,7 +72,8 @@ project "tests" if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { "clear_color_test.c", - "triangle_test.c" + "triangle_test.c", + "mesh_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index fcf2c838..0bcba4ba 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -9,58 +9,59 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - // registerTest("Logger Test", loggerTest); - // registerTest("Time Test", timeTest); - // registerTest("User Event Test", userEventTest); - // registerTest("Event Test", eventTest); + // registerTest(loggerTest); + // registerTest(timeTest); + // registerTest(userEventTest); + // registerTest(eventTest); #if PAL_HAS_SYSTEM - registerTest("System Test", systemTest); + registerTest(systemTest); #endif // PAL_HAS_SYSTEM #if PAL_HAS_THREAD - registerTest("Thread Test", threadTest); - registerTest("TLS Test", tlsTest); - registerTest("Mutex Test", mutexTest); - registerTest("Condvar Test", condvarTest); + registerTest(threadTest); + registerTest(tlsTest); + registerTest(mutexTest); + registerTest(condvarTest); #endif // PAL_HAS_THREAD #if PAL_HAS_VIDEO - // registerTest("Video Test", videoTest); - // registerTest("Monitor Test", monitorTest); - // registerTest("Monitor Mode Test", monitorModeTest); - // registerTest("Window Test", windowTest); - // registerTest("Icon Test", iconTest); - // registerTest("Cursor Test", cursorTest); - // registerTest("Input Window Test", inputWindowTest); - // registerTest("System Cursor Test", systemCursorTest); - // registerTest("Attach Window Test", attachWindowTest); - // registerTest("Character Event Test", charEventTest); - // registerTest("Native Integration Test", nativeIntegrationTest); - // registerTest("Native Instance Test", nativeInstanceTest); - // registerTest("Custom Decoration Test", customDecorationTest); + // registerTest(videoTest); + // registerTest(monitorTest); + // registerTest(monitorModeTest); + // registerTest(windowTest); + // registerTest(iconTest); + // registerTest(cursorTest); + // registerTest(inputWindowTest); + // registerTest(systemCursorTest); + // registerTest(attachWindowTest); + // registerTest(charEventTest); + // registerTest(nativeIntegrationTest); + // registerTest(nativeInstanceTest); + // registerTest(customDecorationTest); #endif // PAL_HAS_VIDEO // This test can run without video system so long as your have a valid // window #if PAL_HAS_OPENGL && PAL_HAS_VIDEO - registerTest("Opengl Test", openglTest); - registerTest("Opengl FBConfig Test", openglFBConfigTest); - registerTest("Opengl Context Test", openglContextTest); - registerTest("Opengl Multi Context Test", openglMultiContextTest); + registerTest(openglTest); + registerTest(openglFBConfigTest); + registerTest(openglContextTest); + registerTest(openglMultiContextTest); #endif // PAL_HAS_OPENGL #if PAL_HAS_OPENGL && PAL_HAS_VIDEO && PAL_HAS_THREAD - registerTest("Multi Thread OpenGL Test", multiThreadOpenGlTest); + registerTest(multiThreadOpenGlTest); #endif #if PAL_HAS_GRAPHICS - registerTest("Graphics Test", graphicsTest); + registerTest(graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest("Clear Color Test", clearColorTest); - registerTest("Triangle Test", triangleTest); + // registerTest(clearColorTest); + // registerTest(triangleTest); + registerTest(meshTest); #endif // runTests(); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index f4ef31ed..b54be265 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -178,16 +178,20 @@ bool triangleTest() } } + palFree(nullptr, adapters); + if (!adapter) { + palLog(nullptr, + "Failed to find an adapter that supports graphics queue"); + return false; + } + PalAdapterInfo adapterInfo = {0}; result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - palFree(nullptr, adapters); return false; } - - palFree(nullptr, adapters); // create a device PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); @@ -513,7 +517,7 @@ bool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + palLog(nullptr, "Failed to set buffer barrier: %s", error); return false; } @@ -547,7 +551,7 @@ bool triangleTest() } if (!readFile(vertexShaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader files"); + palLog(nullptr, "Failed to find shader file"); return false; } @@ -579,7 +583,7 @@ bool triangleTest() bytecode = nullptr; if (!readFile(fragShaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader files"); + palLog(nullptr, "Failed to find shader file"); return false; } From a82bf4c72c923f754836ade227fad226ed7879ea Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 7 Jan 2026 15:14:46 +0000 Subject: [PATCH 077/372] add editor config file and change formatting style --- .clang-format | 9 +++++++-- .editorconfig | 19 +++++++++++++++++++ CHANGELOG.md | 6 ++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 .editorconfig diff --git a/.clang-format b/.clang-format index 0742e7b8..570cc945 100644 --- a/.clang-format +++ b/.clang-format @@ -1,7 +1,12 @@ BasedOnStyle: LLVM # use LLVM defauls IndentWidth: 4 -ColumnLimit: 80 +ColumnLimit: 100 +UseTab: Never +UseCRLF: false +InsertFinalNewline: true +TrimTrailingWhitespace: true +LineEnding: LF # reset if not set AllowShortFunctionsOnASingleLine: None @@ -35,4 +40,4 @@ BraceWrapping: IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true - SplitEmptyNamespace: true \ No newline at end of file + SplitEmptyNamespace: true diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..58f46355 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +tab_width = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +max_line_width = 100 + +[*.{yml, yaml}] +indent_style = space +indent_size = 2 + +[*md] +trim_trailing_whitespace = false diff --git a/CHANGELOG.md b/CHANGELOG.md index 814440ea..23d9f487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -147,6 +147,8 @@ palJoinThread(thread, &retval); - **Core:** Added **PAL_RESULT_INVALID_SEMAPHORE** to `PalResult` enum. - **Core:** Added **PAL_RESULT_INVALID_RENDER_PASS** to `PalResult` enum. - **Core:** Added **PAL_RESULT_INVALID_BUFFER** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_ACCELERATION_STRUCTURE** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_MEMORY_MAP_FAILED** to `PalResult` enum. - **Graphics:** Added **Graphics System To PAL**. @@ -156,6 +158,10 @@ palJoinThread(thread, &retval); - Added clear color example: see **clear_color_test.c** +- Added vertex shader/buffer triangle example: see **triangle_test.c** + +- Added mesh example: see **mesh_test.c.c** + ### Notes - No API or ABI changes - existing code remains compatible. - Safe upgrade from **v1.3.0** - just rebuild your project after updating. \ No newline at end of file From c9de1ece6aa989497f4d3cb3d745f07590d4e880 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 8 Jan 2026 11:11:13 +0000 Subject: [PATCH 078/372] reformat with editor config --- .github/CONTRIBUTING.md | 2 +- .github/ISSUE_TEMPLATE/config.yaml | 2 +- .github/workflows/clang-format.yml | 2 +- .gitignore | 2 +- CHANGELOG.md | 2 +- LICENSE.txt | 6 +- docs/Doxyfile | 2 +- include/pal/pal_core.h | 2 +- include/pal/pal_event.h | 2 +- include/pal/pal_graphics.h | 30 +- include/pal/pal_opengl.h | 2 +- include/pal/pal_system.h | 2 +- include/pal/pal_thread.h | 2 +- include/pal/pal_video.h | 2 +- pal.lua | 10 +- pal_config.lua | 2 +- premake/LICENSE.txt | 2 +- premake5.lua | 11 +- src/graphics/pal_graphics.c | 98 +-- src/graphics/pal_vulkan.c | 924 ++++++++++++++--------------- src/opengl/pal_opengl_linux.c | 62 +- src/opengl/pal_opengl_win32.c | 26 +- src/pal_core.c | 2 +- src/pal_event.c | 2 +- src/system/pal_system_linux.c | 2 +- src/system/pal_system_win32.c | 4 +- src/thread/pal_thread_linux.c | 2 +- src/thread/pal_thread_win32.c | 8 +- src/video/pal_video_linux.c | 572 +++++++++--------- src/video/pal_video_win32.c | 30 +- tests/attach_window_test.c | 22 +- tests/char_event_test.c | 2 +- tests/clear_color_test.c | 62 +- tests/condvar_test.c | 2 +- tests/cursor_test.c | 2 +- tests/custom_decoration_test.c | 116 ++-- tests/device_test.c | 111 ---- tests/event_test.c | 2 +- tests/graphics_test.c | 6 +- tests/icon_test.c | 2 +- tests/input_window_test.c | 2 +- tests/logger_test.c | 8 +- tests/mesh_test.c | 84 +-- tests/monitor_mode_test.c | 2 +- tests/monitor_test.c | 2 +- tests/multi_thread_opengl_test.c | 2 +- tests/mutex_test.c | 2 +- tests/native_instance_test.c | 22 +- tests/native_integration_test.c | 16 +- tests/opengl_context_test.c | 2 +- tests/opengl_fbconfig_test.c | 2 +- tests/opengl_multi_context_test.c | 2 +- tests/opengl_test.c | 2 +- tests/system_cursor_test.c | 2 +- tests/system_test.c | 2 +- tests/tests.c | 2 +- tests/tests.h | 2 +- tests/tests.lua | 18 +- tests/tests_main.c | 2 +- tests/thread_test.c | 2 +- tests/time_test.c | 2 +- tests/tls_test.c | 2 +- tests/triangle_test.c | 128 ++-- tests/user_event_test.c | 2 +- tests/video_test.c | 2 +- tests/window_test.c | 2 +- 66 files changed, 1174 insertions(+), 1286 deletions(-) delete mode 100644 tests/device_test.c diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 6bb04571..58b016f0 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -38,4 +38,4 @@ Pull request checklist: - Ensure it compiles on **all** supported platforms. - Ensure the PR is focused and changes are relevant to the feature or bug fix. -- Ensure your code is formatted with clang-format using the `clang-format` file in the repo. \ No newline at end of file +- Ensure your code is formatted with clang-format using the `clang-format` file in the repo. diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yaml index ec4bb386..3ba13e0c 100644 --- a/.github/ISSUE_TEMPLATE/config.yaml +++ b/.github/ISSUE_TEMPLATE/config.yaml @@ -1 +1 @@ -blank_issues_enabled: false \ No newline at end of file +blank_issues_enabled: false diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index d921c671..a839fff2 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -17,7 +17,7 @@ jobs: - name: Install clang-format run: | - sudo apt-get update + sudo apt-get update wget https://apt.llvm.org/llvm.sh chmod +x llvm.sh sudo ./llvm.sh 21 diff --git a/.gitignore b/.gitignore index 197514b4..afa1351a 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,4 @@ Makefile **.vcxproj # docs -docs/**html \ No newline at end of file +docs/**html diff --git a/CHANGELOG.md b/CHANGELOG.md index 23d9f487..24748565 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -164,4 +164,4 @@ palJoinThread(thread, &retval); ### Notes - No API or ABI changes - existing code remains compatible. -- Safe upgrade from **v1.3.0** - just rebuild your project after updating. \ No newline at end of file +- Safe upgrade from **v1.3.0** - just rebuild your project after updating. diff --git a/LICENSE.txt b/LICENSE.txt index 67b45697..e86100c0 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -2,7 +2,7 @@ zlib License Copyright (C) 2025-2026 Nicholas Agbo - + This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -10,11 +10,11 @@ arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: - + 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be - appreciated but is not required. + appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. diff --git a/docs/Doxyfile b/docs/Doxyfile index c6446966..812f0ffc 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1032,7 +1032,7 @@ INPUT_FILE_ENCODING = # *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.h - + # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 3775938a..9f36e38e 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -630,4 +630,4 @@ static inline void PAL_CALL palUnpackFloat( /** @} */ // end of pal_core group -#endif // _PAL_CORE_H \ No newline at end of file +#endif // _PAL_CORE_H diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 3f5d117c..b0a53945 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -585,4 +585,4 @@ PAL_API bool PAL_CALL palPollEvent( /** @} */ // end of pal_event group -#endif // _PAL_EVENT_H \ No newline at end of file +#endif // _PAL_EVENT_H diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 19ff0f27..97854bd2 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -969,7 +969,7 @@ typedef struct { PalResult PAL_CALL (*mapMemory)( PalDevice* device, PalMemory* memory, - Uint64 offset, + Uint64 offset, Uint64 size, void** outPtr); @@ -1001,7 +1001,7 @@ typedef struct { void PAL_CALL (*destroyQueue)(PalQueue* queue); bool PAL_CALL (*canQueuePresent)( - PalQueue* queue, + PalQueue* queue, PalGraphicsWindow* window); PalResult PAL_CALL (*waitQueue)(PalQueue* queue); @@ -1093,7 +1093,7 @@ typedef struct { void PAL_CALL (*destroyFence)(PalFence* fence); PalResult PAL_CALL (*waitFenceTimeout)( - PalFence* fence, + PalFence* fence, Uint64 timeout); PalResult PAL_CALL (*resetFence)(PalFence* fence); @@ -1107,18 +1107,18 @@ typedef struct { void PAL_CALL (*destroySemaphore)(PalSemaphore* semaphore); PalResult PAL_CALL (*waitSemaphore)( - PalSemaphore* semaphore, + PalSemaphore* semaphore, PalQueue* queue, Uint64 value, Uint64 timeout); PalResult PAL_CALL (*signalSemaphore)( - PalSemaphore* semaphore, + PalSemaphore* semaphore, PalQueue* queue, Uint64 value); PalResult PAL_CALL (*getSemaphoreValue)( - PalSemaphore* semaphore, + PalSemaphore* semaphore, Uint64* value); PalResult PAL_CALL (*createCommandPool)( @@ -1346,7 +1346,7 @@ PAL_API void PAL_CALL palFreeMemory( PAL_API PalResult PAL_CALL palMapMemory( PalDevice* device, PalMemory* memory, - Uint64 offset, + Uint64 offset, Uint64 size, void** outPtr); @@ -1378,7 +1378,7 @@ PAL_API PalResult PAL_CALL palCreateQueue( PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); PAL_API bool PAL_CALL palCanQueuePresent( - PalQueue* queue, + PalQueue* queue, PalGraphicsWindow* window); PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); @@ -1448,7 +1448,7 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PAL_API PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, + PalSwapchainNextImageInfo* info, Uint32 *outIndex); PAL_API PalResult PAL_CALL palPresentSwapchain( @@ -1470,7 +1470,7 @@ PAL_API PalResult PAL_CALL palCreateFence( PAL_API void PAL_CALL palDestroyFence(PalFence* fence); PAL_API PalResult PAL_CALL palWaitFence( - PalFence* fence, + PalFence* fence, Uint64 timeout); PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); @@ -1484,18 +1484,18 @@ PAL_API PalResult PAL_CALL palCreateSemaphore( PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); PAL_API PalResult PAL_CALL palWaitSemaphore( - PalSemaphore* semaphore, + PalSemaphore* semaphore, PalQueue* queue, Uint64 value, Uint64 timeout); PAL_API PalResult PAL_CALL palSignalSemaphore( - PalSemaphore* semaphore, + PalSemaphore* semaphore, PalQueue* queue, Uint64 value); PAL_API PalResult PAL_CALL palGetSemaphoreValue( - PalSemaphore* semaphore, + PalSemaphore* semaphore, Uint64* value); PAL_API PalResult PAL_CALL palCreateCommandPool( @@ -1516,7 +1516,7 @@ PAL_API PalResult PAL_CALL palCreateCommandBuffer( PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); PAL_API PalResult PAL_CALL palBeginCommandBuffer( - PalCommandBuffer* cmdBuffer, + PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); PAL_API PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -1679,4 +1679,4 @@ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); /** @} */ // end of pal_graphics group -#endif // _PAL_GRAPHICS_H \ No newline at end of file +#endif // _PAL_GRAPHICS_H diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 7c456f02..8f47974d 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -485,4 +485,4 @@ PAL_API const char* PAL_CALL palGLGetBackend(); /** @} */ // end of pal_opengl group -#endif // _PAL_OPENGL_H \ No newline at end of file +#endif // _PAL_OPENGL_H diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index 3b785a00..59458e8e 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -198,4 +198,4 @@ PAL_API PalResult PAL_CALL palGetCPUInfo( /** @} */ // end of pal_system group -#endif // _PAL_SYSTEM_H \ No newline at end of file +#endif // _PAL_SYSTEM_H diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index c4895096..9e8c994d 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -658,4 +658,4 @@ PAL_API void PAL_CALL palBroadcastCondVar(PalCondVar* condVar); /** @} */ // end of pal_thread group -#endif // _PAL_THREAD_H \ No newline at end of file +#endif // _PAL_THREAD_H diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index c1bc475a..05d1247b 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -2025,4 +2025,4 @@ PAL_API void PAL_CALL palSetPreferredInstance(void* instance); /** @} */ // end of pal_video group -#endif // _PAL_VIDEO_H \ No newline at end of file +#endif // _PAL_VIDEO_H diff --git a/pal.lua b/pal.lua index 8464567d..b4ea9326 100644 --- a/pal.lua +++ b/pal.lua @@ -35,7 +35,7 @@ function writeConfig(path) else file:write("#define PAL_HAS_GRAPHICS 0\n") end - + file:close() end @@ -46,7 +46,7 @@ project "PAL" kind "StaticLib" else kind "SharedLib" - defines { + defines { "_PAL_EXPORT", "_PAL_BUILD_DLL" } @@ -60,7 +60,7 @@ project "PAL" "src" } - files { + files { "src/pal_core.c", "src/pal_event.c" } @@ -134,7 +134,7 @@ project "PAL" else defines { "PAL_HAS_X11=0" } end - + filter {} end @@ -180,4 +180,4 @@ project "PAL" filter {} end - writeConfig("include/pal/pal_config.h") \ No newline at end of file + writeConfig("include/pal/pal_config.h") diff --git a/pal_config.lua b/pal_config.lua index 14259d5a..1e2b2700 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -18,4 +18,4 @@ PAL_BUILD_VIDEO = true PAL_BUILD_OPENGL = false -- build graphics module -PAL_BUILD_GRAPHICS = true \ No newline at end of file +PAL_BUILD_GRAPHICS = true diff --git a/premake/LICENSE.txt b/premake/LICENSE.txt index 66c3ad6f..e7611e64 100644 --- a/premake/LICENSE.txt +++ b/premake/LICENSE.txt @@ -24,4 +24,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/premake5.lua b/premake5.lua index c0aa049e..07574536 100644 --- a/premake5.lua +++ b/premake5.lua @@ -27,7 +27,7 @@ workspace "PAL_workspace" else staticruntime "off" end - + configurations { "Debug", "Release" } flags { "MultiProcessorCompile" } @@ -39,7 +39,7 @@ workspace "PAL_workspace" filter {"system:linux", "configurations:*"} architecture "x86_64" cdialect "C99" - + filter "configurations:Debug" symbols "on" runtime "Debug" @@ -60,14 +60,14 @@ workspace "PAL_workspace" "-I" .. ucrt .. "/include", "-I" .. ucrt .. "/ucrt/include", "-I" .. ucrt .. "/mingw/include", - + -- warnings "-Wno-switch", -- for switch statements "-Wno-switch-enum" -- for switch statements } linkoptions { - "-target x86_64-w64-windows-gnu", + "-target x86_64-w64-windows-gnu", "-L" .. ucrt .. "/lib", "-L" .. ucrt .. "/mingw/lib" } @@ -75,7 +75,7 @@ workspace "PAL_workspace" end if (_ACTION == "vs2022") then - if (_OPTIONS["compiler"] == "clang") then + if (_OPTIONS["compiler"] == "clang") then toolset("clang") end @@ -92,4 +92,3 @@ workspace "PAL_workspace" end include "pal.lua" - \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index e854e720..7eb9d78e 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -142,7 +142,7 @@ void PAL_CALL destroyVkQueue(PalQueue* queue); PalResult PAL_CALL waitVkQueue(PalQueue* queue); bool PAL_CALL canVkQueuePresent( - PalQueue* queue, + PalQueue* queue, PalGraphicsWindow* window); PalResult PAL_CALL enumerateVkFormats( @@ -210,11 +210,11 @@ PalImage* PAL_CALL getVkSwapchainImage( PalResult PAL_CALL getVkNextSwapchainImage( PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, + PalSwapchainNextImageInfo* info, Uint32* outIndex); PalResult PAL_CALL presentVkSwapchain( - PalSwapchain* swapchain, + PalSwapchain* swapchain, PalSwapchainPresentInfo* info); PalResult PAL_CALL createVkShader( @@ -232,7 +232,7 @@ PalResult PAL_CALL createVkFence( void PAL_CALL destroyVkFence(PalFence* fence); PalResult PAL_CALL waitVkFence( - PalFence* fence, + PalFence* fence, Uint64 timeout); PalResult PAL_CALL resetVkFence(PalFence* fence); @@ -252,12 +252,12 @@ PalResult PAL_CALL waitVkSemaphore( Uint64 timeout); PalResult PAL_CALL signalVkSemaphore( - PalSemaphore* semaphore, + PalSemaphore* semaphore, PalQueue* queue, Uint64 value); PalResult PAL_CALL getVkSemaphoreValue( - PalSemaphore* semaphore, + PalSemaphore* semaphore, Uint64* value); PalResult PAL_CALL createVkCommandPool( @@ -278,7 +278,7 @@ PalResult PAL_CALL createVkCommandBuffer( void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); PalResult PAL_CALL beginVkCommandBuffer( - PalCommandBuffer* cmdBuffer, + PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); PalResult PAL_CALL endVkCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -428,7 +428,7 @@ PalResult PAL_CALL bindVkBufferMemory( PalResult PAL_CALL mapVkMemory( PalDevice* device, PalMemory* memory, - Uint64 offset, + Uint64 offset, Uint64 size, void** outPtr); @@ -575,7 +575,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) // check if all the function pointers are set // clang-format off - if (!backend->enumerateAdapters || + if (!backend->enumerateAdapters || !backend->getAdapterInfo || !backend->getAdapterCapabilities || !backend->getAdapterFeatures || @@ -770,7 +770,7 @@ PalResult PAL_CALL palEnumerateAdapters( totalCount += _count; _count = 0; } - + // break if a backend fails if (result != PAL_RESULT_SUCCESS) { return result; @@ -846,8 +846,8 @@ PalResult PAL_CALL palCreateDevice( PalDevice* device = nullptr; PalResult result; result = adapter->backend->createDevice( - adapter, - features, + adapter, + features, &device); if (result != PAL_RESULT_SUCCESS) { @@ -894,9 +894,9 @@ PalResult PAL_CALL palAllocateMemory( } return device->backend->allocateMemory( - device, - type, - size, + device, + type, + size, outMemory); } @@ -937,7 +937,7 @@ PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( } return device->backend->queryFragmentShadingRateCapabilities( - device, + device, caps); } @@ -954,7 +954,7 @@ PalResult PAL_CALL palQueryMeshShaderCapabilities( } return device->backend->queryMeshShaderCapabilities( - device, + device, caps); } @@ -971,7 +971,7 @@ PalResult PAL_CALL palQueryRayTracingCapabilities( } return device->backend->queryRayTracingCapabilities( - device, + device, caps); } @@ -1016,7 +1016,7 @@ void PAL_CALL palDestroyQueue(PalQueue* queue) } bool PAL_CALL palCanQueuePresent( - PalQueue* queue, + PalQueue* queue, PalGraphicsWindow* window) { if (s_Graphics.initialized && queue) { @@ -1163,7 +1163,7 @@ PalResult PAL_CALL palGetImageMemoryRequirements( } return image->backend->getImageMemoryRequirements( - image, + image, requirements); } @@ -1181,8 +1181,8 @@ PalResult PAL_CALL palBindImageMemory( } return image->backend->bindImageMemory( - image, - memory, + image, + memory, offset); } @@ -1269,10 +1269,10 @@ PalResult PAL_CALL palCreateSwapchain( PalResult result; PalSwapchain* swapchain = nullptr; result = device->backend->createSwapchain( - device, - queue, - window, - info, + device, + queue, + window, + info, &swapchain); if (result != PAL_RESULT_SUCCESS) { @@ -1284,7 +1284,7 @@ PalResult PAL_CALL palCreateSwapchain( PalImage* image = device->backend->getSwapchainImage(swapchain, i); image->backend = device->backend; } - + swapchain->backend = device->backend; *outSwapchain = swapchain; return PAL_RESULT_SUCCESS; @@ -1310,7 +1310,7 @@ PalImage* PAL_CALL palGetSwapchainImage( PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, + PalSwapchainNextImageInfo* info, Uint32 *outIndex) { if (!s_Graphics.initialized) { @@ -1323,7 +1323,7 @@ PalResult PAL_CALL palGetNextSwapchainImage( return swapchain->backend->getNextSwapchainImage( swapchain, - info, + info, outIndex); } @@ -1340,7 +1340,7 @@ PalResult PAL_CALL palPresentSwapchain( } return swapchain->backend->presentSwapchain( - swapchain, + swapchain, info); } @@ -1372,7 +1372,7 @@ PalResult PAL_CALL palCreateShader( return result; } - shader->backend = device->backend; + shader->backend = device->backend; *outShader = shader; return PAL_RESULT_SUCCESS; } @@ -1421,7 +1421,7 @@ void PAL_CALL palDestroyFence(PalFence* fence) } PalResult PAL_CALL palWaitFence( - PalFence* fence, + PalFence* fence, Uint64 timeout) { if (!s_Graphics.initialized) { @@ -1492,7 +1492,7 @@ void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore) } PalResult PAL_CALL palWaitSemaphore( - PalSemaphore* semaphore, + PalSemaphore* semaphore, PalQueue* queue, Uint64 value, Uint64 timeout) @@ -1506,14 +1506,14 @@ PalResult PAL_CALL palWaitSemaphore( } return semaphore->backend->waitSemaphore( - semaphore, + semaphore, queue, value, timeout); } PalResult PAL_CALL palSignalSemaphore( - PalSemaphore* semaphore, + PalSemaphore* semaphore, PalQueue* queue, Uint64 value) { @@ -1526,13 +1526,13 @@ PalResult PAL_CALL palSignalSemaphore( } return semaphore->backend->signalSemaphore( - semaphore, + semaphore, queue, value); } PalResult PAL_CALL palGetSemaphoreValue( - PalSemaphore* semaphore, + PalSemaphore* semaphore, Uint64* value) { if (!s_Graphics.initialized) { @@ -1544,7 +1544,7 @@ PalResult PAL_CALL palGetSemaphoreValue( } return semaphore->backend->getSemaphoreValue( - semaphore, + semaphore, value); } @@ -1640,7 +1640,7 @@ void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) } PalResult PAL_CALL palBeginCommandBuffer( - PalCommandBuffer* cmdBuffer, + PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) { if (!s_Graphics.initialized) { @@ -1693,7 +1693,7 @@ PalResult PAL_CALL palExecuteCommandBuffer( } return primaryCmdBuffer->backend->executeCommandBuffer( - primaryCmdBuffer, + primaryCmdBuffer, secondaryCmdBuffer); } @@ -2122,7 +2122,7 @@ PalResult PAL_CALL palCreateAccelerationstructure( if (result != PAL_RESULT_SUCCESS) { return result; } - + as->backend = device->backend; *outAs = as; return PAL_RESULT_SUCCESS; @@ -2186,7 +2186,7 @@ PalResult PAL_CALL palCreateBuffer( if (result != PAL_RESULT_SUCCESS) { return result; } - + buffer->backend = device->backend; *outBuffer = buffer; return PAL_RESULT_SUCCESS; @@ -2212,7 +2212,7 @@ PalResult PAL_CALL palGetBufferMemoryRequirements( } return buffer->backend->getBufferMemoryRequirements( - buffer, + buffer, requirements); } @@ -2230,15 +2230,15 @@ PalResult PAL_CALL palBindBufferMemory( } return buffer->backend->bindBufferMemory( - buffer, - memory, + buffer, + memory, offset); } PalResult PAL_CALL palMapMemory( PalDevice* device, PalMemory* memory, - Uint64 offset, + Uint64 offset, Uint64 size, void** outPtr) { @@ -2295,7 +2295,7 @@ PalResult PAL_CALL palCreatePipelineLayout( if (result != PAL_RESULT_SUCCESS) { return result; } - + layout->backend = device->backend; *outLayout = layout; return PAL_RESULT_SUCCESS; @@ -2335,7 +2335,7 @@ PalResult PAL_CALL palCreateGraphicsPipeline( if (result != PAL_RESULT_SUCCESS) { return result; } - + pipeline->backend = device->backend; *outPipeline = pipeline; return PAL_RESULT_SUCCESS; @@ -2346,4 +2346,4 @@ void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) if (s_Graphics.initialized && pipeline) { pipeline->backend->destroyPipeline(pipeline); } -} \ No newline at end of file +} diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 6da7e539..df51adeb 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -88,7 +88,7 @@ typedef struct { void* libWayland; wl_display_get_fd_fn getDisplayFd; #endif // __linux__ - + PFN_vkEnumerateInstanceVersion enumerateInstanceVersion; PFN_vkEnumerateInstanceExtensionProperties enumerateInstanceExtensionProperties; PFN_vkDestroyInstance destroyInstance; @@ -110,7 +110,7 @@ typedef struct { PFN_vkAllocateMemory allocateMemory; PFN_vkFreeMemory freeMemory; PFN_vkBindImageMemory bindImageMemory; - + PFN_vkCreateDevice createDevice; PFN_vkDestroyDevice destroyDevice; PFN_vkGetDeviceQueue getDeviceQueue; @@ -173,7 +173,7 @@ typedef struct { PFN_vkDestroyDebugUtilsMessengerEXT destroyMessenger; PFN_vkDeviceWaitIdle waitDevice; PFN_vkQueueWaitIdle waitQueue; - + VkAllocationCallbacks vkAllocator; const PalAllocator* allocator; @@ -230,7 +230,7 @@ typedef struct { PFN_vkCmdTraceRaysKHR cmdTraceRays; PFN_vkCreateRayTracingPipelinesKHR createRayTracingPipeline; PFN_vkCmdTraceRaysIndirectKHR cmdTraceRaysIndirect; - + // dynamic rendering PFN_vkCmdBeginRendering cmdBeginRendering; PFN_vkCmdEndRendering cmdEndRendering; @@ -362,7 +362,7 @@ static Vulkan s_Vk = {0}; // Helper Functions // ================================================== -static Uint32 checkPlatform(struct wl_display* display) +static Uint32 checkPlatform(struct wl_display* display) { #ifdef _WIN32 #elif defined(__linux__) @@ -381,7 +381,7 @@ static Uint32 checkPlatform(struct wl_display* display) } static bool createSurface( - PalGraphicsWindow* window, + PalGraphicsWindow* window, VkSurfaceKHR* outSurface) { Uint32 platform = checkPlatform(window->display); @@ -401,9 +401,9 @@ static bool createSurface( createInfo.surface = window->window; VkResult result = s_Vk.createWaylandSurface( - s_Vk.instance, - &createInfo, - &s_Vk.vkAllocator, + s_Vk.instance, + &createInfo, + &s_Vk.vkAllocator, &surface); if (result != VK_SUCCESS) { @@ -412,13 +412,13 @@ static bool createSurface( *outSurface = surface; return true; - + } else if (platform == VK_XLIB_PLATFORM) { - + } } -static PalResult vkResultToPal(VkResult result) +static PalResult vkResultToPal(VkResult result) { switch (result) { case VK_ERROR_FEATURE_NOT_PRESENT: @@ -432,7 +432,7 @@ static PalResult vkResultToPal(VkResult result) return PAL_RESULT_OUT_OF_MEMORY; } - case VK_ERROR_INITIALIZATION_FAILED: + case VK_ERROR_INITIALIZATION_FAILED: case VK_ERROR_DEVICE_LOST: { return PAL_RESULT_PLATFORM_FAILURE; } @@ -457,7 +457,7 @@ static PalResult vkResultToPal(VkResult result) return PAL_RESULT_PLATFORM_FAILURE; } -static VkImageUsageFlags palImageUsageToVk(PalImageUsages usages) +static VkImageUsageFlags palImageUsageToVk(PalImageUsages usages) { VkImageUsageFlags flags = 0; if (usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { @@ -479,7 +479,7 @@ static VkImageUsageFlags palImageUsageToVk(PalImageUsages usages) if (usages & PAL_IMAGE_USAGE_STORAGE) { flags |= VK_IMAGE_USAGE_STORAGE_BIT; } - + if (usages & PAL_IMAGE_USAGE_SAMPLED) { flags |= VK_IMAGE_USAGE_SAMPLED_BIT; } @@ -739,7 +739,7 @@ static VkSampleCountFlags samplesToVk(PalSampleCount count) switch (count) { case PAL_SAMPLE_COUNT_2: return VK_SAMPLE_COUNT_2_BIT; - + case PAL_SAMPLE_COUNT_4: return VK_SAMPLE_COUNT_4_BIT; @@ -1235,7 +1235,7 @@ static VkFormat vertexTypeToVkFormat(PalVertexType type) return VK_FORMAT_UNDEFINED; } -static VkBufferUsageFlags palBufferUsageToVk(PalBufferUsages usages) +static VkBufferUsageFlags palBufferUsageToVk(PalBufferUsages usages) { VkBufferUsageFlags flags = 0; if (usages & PAL_BUFFER_USAGE_VERTEX) { @@ -1264,10 +1264,10 @@ static VkBufferUsageFlags palBufferUsageToVk(PalBufferUsages usages) if (usages & PAL_BUFFER_USAGE_RAY_TRACING) { flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - flags |= + flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; } - + if (usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; } @@ -1275,7 +1275,7 @@ static VkBufferUsageFlags palBufferUsageToVk(PalBufferUsages usages) return flags; } -static Uint32 getVertexTypeSize(PalVertexType type) +static Uint32 getVertexTypeSize(PalVertexType type) { // count x sizeof type returned as size switch (type) { @@ -1302,7 +1302,7 @@ static Uint32 getVertexTypeSize(PalVertexType type) } case PAL_VERTEX_TYPE_INT32_2: - case PAL_VERTEX_TYPE_UINT32_2: + case PAL_VERTEX_TYPE_UINT32_2: case PAL_VERTEX_TYPE_INT16_4: case PAL_VERTEX_TYPE_UINT16_4: case PAL_VERTEX_TYPE_UINT16_4NORM: @@ -1328,7 +1328,7 @@ static Uint32 getVertexTypeSize(PalVertexType type) return 0; } -static VkStencilOp stencilOpToVk(PalStencilOp op) +static VkStencilOp stencilOpToVk(PalStencilOp op) { switch (op) { case PAL_STENCIL_OP_KEEP: @@ -1359,7 +1359,7 @@ static VkStencilOp stencilOpToVk(PalStencilOp op) return VK_STENCIL_OP_KEEP; } -static VkCompareOp compareOpToVk(PalCompareOp op) +static VkCompareOp compareOpToVk(PalCompareOp op) { switch (op) { case PAL_COMPARE_OP_NEVER: @@ -1517,7 +1517,7 @@ static Barrier barrierToVk(PalUsageState state) } case PAL_USAGE_STATE_PRESENT: { - barrier.stages = + barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.dstStagess = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; @@ -1528,7 +1528,7 @@ static Barrier barrierToVk(PalUsageState state) } case PAL_USAGE_STATE_COLOR_ATTACHMENT: { - barrier.stages = + barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.dstStagess = barrier.stages; @@ -1564,14 +1564,14 @@ static Barrier barrierToVk(PalUsageState state) } case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT: { - barrier.stages = + barrier.stages = VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; barrier.dstStagess = barrier.stages; - barrier.access = + barrier.access = VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; - - barrier.layout = + + barrier.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; return barrier; @@ -1688,7 +1688,7 @@ static void* vkRealloc( size_t alignment, VkSystemAllocationScope allocationScope) { - // Note: This is a hack which could cost performance but + // Note: This is a hack which could cost performance but // realloc is not really called that much so it should be fine // this is because we dont know the old size void* block = realloc(pOriginal, size); @@ -1787,7 +1787,7 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.libWayland = dlopen("libwayland-client.so.0", RTLD_LAZY); if (s_Vk.libWayland) { s_Vk.getDisplayFd = (wl_display_get_fd_fn)dlsym( - s_Vk.libWayland, + s_Vk.libWayland, "wl_display_get_fd"); } @@ -1799,271 +1799,271 @@ PalResult PAL_CALL initGraphicsVk( // clang-format off s_Vk.enumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)dlsym( - s_Vk.handle, + s_Vk.handle, "vkEnumerateInstanceVersion"); s_Vk.enumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)dlsym( - s_Vk.handle, + s_Vk.handle, "vkEnumerateInstanceExtensionProperties"); s_Vk.createInstance = (PFN_vkCreateInstance)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreateInstance"); s_Vk.destroyInstance = (PFN_vkDestroyInstance)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroyInstance"); s_Vk.enumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)dlsym( - s_Vk.handle, + s_Vk.handle, "vkEnumeratePhysicalDevices"); s_Vk.getPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetPhysicalDeviceProperties"); s_Vk.getPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetPhysicalDeviceMemoryProperties"); s_Vk.enumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)dlsym( - s_Vk.handle, + s_Vk.handle, "vkEnumerateInstanceLayerProperties"); s_Vk.getPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetPhysicalDeviceQueueFamilyProperties"); s_Vk.enumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)dlsym( - s_Vk.handle, + s_Vk.handle, "vkEnumerateDeviceExtensionProperties"); s_Vk.getPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetPhysicalDeviceFeatures"); s_Vk.getPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetPhysicalDeviceFeatures2"); s_Vk.getInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetInstanceProcAddr"); s_Vk.createImage = (PFN_vkCreateImage)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreateImage"); s_Vk.destroyImage = (PFN_vkDestroyImage)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroyImage"); s_Vk.createImageView = (PFN_vkCreateImageView)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreateImageView"); s_Vk.destroyImageView = (PFN_vkDestroyImageView)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroyImageView"); s_Vk.createShader = (PFN_vkCreateShaderModule)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreateShaderModule"); s_Vk.destroyShader = (PFN_vkDestroyShaderModule)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroyShaderModule"); s_Vk.getPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetPhysicalDeviceProperties2"); s_Vk.getPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetPhysicalDeviceFormatProperties"); s_Vk.createDevice = (PFN_vkCreateDevice)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreateDevice"); s_Vk.destroyDevice = (PFN_vkDestroyDevice)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroyDevice"); s_Vk.getDeviceQueue = (PFN_vkGetDeviceQueue)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetDeviceQueue"); s_Vk.getDeviceProcAddr = (PFN_vkGetDeviceProcAddr)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetDeviceProcAddr"); s_Vk.getImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetImageMemoryRequirements"); s_Vk.allocateMemory = (PFN_vkAllocateMemory)dlsym( - s_Vk.handle, + s_Vk.handle, "vkAllocateMemory"); s_Vk.freeMemory = (PFN_vkFreeMemory)dlsym( - s_Vk.handle, + s_Vk.handle, "vkFreeMemory"); s_Vk.bindImageMemory = (PFN_vkBindImageMemory)dlsym( - s_Vk.handle, + s_Vk.handle, "vkBindImageMemory"); s_Vk.createCommandPool = (PFN_vkCreateCommandPool)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreateCommandPool"); s_Vk.destroyCommandPool = (PFN_vkDestroyCommandPool)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroyCommandPool"); s_Vk.createCommandBuffer = (PFN_vkAllocateCommandBuffers)dlsym( - s_Vk.handle, + s_Vk.handle, "vkAllocateCommandBuffers"); s_Vk.destroyCommandBuffer = (PFN_vkFreeCommandBuffers)dlsym( - s_Vk.handle, + s_Vk.handle, "vkFreeCommandBuffers"); s_Vk.createFence = (PFN_vkCreateFence)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreateFence"); s_Vk.destroyFence = (PFN_vkDestroyFence)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroyFence"); s_Vk.resetFence = (PFN_vkResetFences)dlsym( - s_Vk.handle, + s_Vk.handle, "vkResetFences"); s_Vk.waitFence = (PFN_vkWaitForFences)dlsym( - s_Vk.handle, + s_Vk.handle, "vkWaitForFences"); s_Vk.isFenceSignaled = (PFN_vkGetFenceStatus)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetFenceStatus"); s_Vk.createSemaphore = (PFN_vkCreateSemaphore)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreateSemaphore"); s_Vk.destroySemaphore = (PFN_vkDestroySemaphore)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroySemaphore"); s_Vk.cmdBegin = (PFN_vkBeginCommandBuffer)dlsym( - s_Vk.handle, + s_Vk.handle, "vkBeginCommandBuffer"); s_Vk.cmdEnd = (PFN_vkEndCommandBuffer)dlsym( - s_Vk.handle, + s_Vk.handle, "vkEndCommandBuffer"); s_Vk.resetCommandPool = (PFN_vkResetCommandPool)dlsym( - s_Vk.handle, + s_Vk.handle, "vkResetCommandPool"); s_Vk.resetCommandBuffer = (PFN_vkResetCommandBuffer)dlsym( - s_Vk.handle, + s_Vk.handle, "vkResetCommandBuffer"); s_Vk.cmdExecuteCommandBuffer = (PFN_vkCmdExecuteCommands)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdExecuteCommands"); s_Vk.cmdCopyBuffer = (PFN_vkCmdCopyBuffer)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdCopyBuffer"); s_Vk.cmdBindPipeline = (PFN_vkCmdBindPipeline)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdBindPipeline"); s_Vk.cmdSetViewports = (PFN_vkCmdSetViewport)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdSetViewport"); s_Vk.cmdSetScissors = (PFN_vkCmdSetScissor)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdSetScissor"); s_Vk.bindVertexBuffers = (PFN_vkCmdBindVertexBuffers)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdBindVertexBuffers"); s_Vk.bindIndexBuffer = (PFN_vkCmdBindIndexBuffer)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdBindIndexBuffer"); s_Vk.cmdDraw = (PFN_vkCmdDraw)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdDraw"); s_Vk.cmdDrawIndirect = (PFN_vkCmdDrawIndirect)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdDrawIndirect"); s_Vk.cmdDrawIndexed = (PFN_vkCmdDrawIndexed)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdDrawIndexed"); s_Vk.cmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCmdDrawIndexedIndirect"); s_Vk.createBuffer = (PFN_vkCreateBuffer)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreateBuffer"); s_Vk.destroyBuffer = (PFN_vkDestroyBuffer)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroyBuffer"); s_Vk.mapMemory = (PFN_vkMapMemory)dlsym( - s_Vk.handle, + s_Vk.handle, "vkMapMemory"); s_Vk.unmapMemory = (PFN_vkUnmapMemory)dlsym( - s_Vk.handle, + s_Vk.handle, "vkUnmapMemory"); s_Vk.getBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)dlsym( - s_Vk.handle, + s_Vk.handle, "vkGetBufferMemoryRequirements"); s_Vk.bindBufferMemory = (PFN_vkBindBufferMemory)dlsym( - s_Vk.handle, + s_Vk.handle, "vkBindBufferMemory"); s_Vk.createPipelineLayout = (PFN_vkCreatePipelineLayout)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreatePipelineLayout"); s_Vk.destroyPipelineLayout = (PFN_vkDestroyPipelineLayout)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroyPipelineLayout"); s_Vk.createGraphicsPipeline = (PFN_vkCreateGraphicsPipelines)dlsym( - s_Vk.handle, + s_Vk.handle, "vkCreateGraphicsPipelines"); s_Vk.destroyPipeline = (PFN_vkDestroyPipeline)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDestroyPipeline"); s_Vk.waitDevice = (PFN_vkDeviceWaitIdle)dlsym( - s_Vk.handle, + s_Vk.handle, "vkDeviceWaitIdle"); s_Vk.waitQueue = (PFN_vkQueueWaitIdle)dlsym( - s_Vk.handle, + s_Vk.handle, "vkQueueWaitIdle"); // clang-format on @@ -2083,13 +2083,13 @@ PalResult PAL_CALL initGraphicsVk( bool hasValidationLayer = false; s_Vk.messenger = nullptr; VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {0}; - debugCreateInfo.sType = + debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; if (debugger) { // layers result = s_Vk.enumerateInstanceLayerProperties( - &layerCount, + &layerCount, nullptr); if (result != VK_SUCCESS) { @@ -2098,7 +2098,7 @@ PalResult PAL_CALL initGraphicsVk( VkLayerProperties* props = nullptr; props = palAllocate( - s_Vk.allocator, + s_Vk.allocator, sizeof(VkLayerProperties) * layerCount, 0); @@ -2117,18 +2117,18 @@ PalResult PAL_CALL initGraphicsVk( palFree(s_Vk.allocator, props); - debugCreateInfo.messageType |= + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; - debugCreateInfo.messageType |= + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; - debugCreateInfo.messageType |= + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - debugCreateInfo.messageSeverity |= + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; - debugCreateInfo.messageSeverity |= + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - debugCreateInfo.messageSeverity |= + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; debugCreateInfo.pUserData = debugger->userData; @@ -2150,8 +2150,8 @@ PalResult PAL_CALL initGraphicsVk( VkExtensionProperties* extensionProps = nullptr; extensionProps = palAllocate( - s_Vk.allocator, - sizeof(VkExtensionProperties) * extCount, + s_Vk.allocator, + sizeof(VkExtensionProperties) * extCount, 0); if (!extensionProps) { @@ -2159,8 +2159,8 @@ PalResult PAL_CALL initGraphicsVk( } s_Vk.enumerateInstanceExtensionProperties( - nullptr, - &extCount, + nullptr, + &extCount, extensionProps); bool hasXlib = false; @@ -2238,8 +2238,8 @@ PalResult PAL_CALL initGraphicsVk( VkInstance instance = nullptr; result = s_Vk.createInstance( - &instanceCreateInfo, - &s_Vk.vkAllocator, + &instanceCreateInfo, + &s_Vk.vkAllocator, &instance); if (result != VK_SUCCESS) { @@ -2249,9 +2249,9 @@ PalResult PAL_CALL initGraphicsVk( // clang-format off if (versionFallback) { // load get physical device properties2 proc if we are on version 1.0 - s_Vk.getPhysicalDeviceFeatures2 = + s_Vk.getPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2KHR)s_Vk.getInstanceProcAddr( - s_Vk.handle, + s_Vk.handle, "vkGetPhysicalDeviceFeatures2KHR"); } @@ -2261,23 +2261,23 @@ PalResult PAL_CALL initGraphicsVk( if (hasWayland) { s_Vk.createWaylandSurface = (PFN_vkCreateWaylandSurfaceKHR)s_Vk.getInstanceProcAddr( - instance, + instance, "vkCreateWaylandSurfaceKHR"); - s_Vk.checkWaylandPresentSupport = + s_Vk.checkWaylandPresentSupport = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)s_Vk.getInstanceProcAddr( - instance, + instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); } if (hasXlib) { s_Vk.createXlibSurface = (PFN_vkCreateXlibSurfaceKHR)s_Vk.getInstanceProcAddr( - instance, + instance, "vkCreateXlibSurfaceKHR"); - s_Vk.checkXlibPresentSupport = + s_Vk.checkXlibPresentSupport = (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)s_Vk.getInstanceProcAddr( - instance, + instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); } @@ -2291,7 +2291,7 @@ PalResult PAL_CALL initGraphicsVk( instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); - s_Vk.getSurfacePresentModes = + s_Vk.getSurfacePresentModes = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)s_Vk.getInstanceProcAddr( instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"); @@ -2301,12 +2301,12 @@ PalResult PAL_CALL initGraphicsVk( "vkGetPhysicalDeviceSurfaceFormatsKHR"); if (debugger) { - s_Vk.createMessenger = + s_Vk.createMessenger = (PFN_vkCreateDebugUtilsMessengerEXT)s_Vk.getInstanceProcAddr( instance, "vkCreateDebugUtilsMessengerEXT"); - s_Vk.destroyMessenger = + s_Vk.destroyMessenger = (PFN_vkDestroyDebugUtilsMessengerEXT)s_Vk.getInstanceProcAddr( instance, "vkDestroyDebugUtilsMessengerEXT"); @@ -2325,8 +2325,8 @@ PalResult PAL_CALL shutdownGraphicsVk() { if (s_Vk.messenger) { s_Vk.destroyMessenger( - s_Vk.instance, - s_Vk.messenger, + s_Vk.instance, + s_Vk.messenger, &s_Vk.vkAllocator); } @@ -2354,8 +2354,8 @@ PalResult PAL_CALL enumerateVkAdapters( VkPhysicalDeviceProperties props = {0}; result = s_Vk.enumeratePhysicalDevices( - s_Vk.instance, - &deviceCount, + s_Vk.instance, + &deviceCount, nullptr); if (result != VK_SUCCESS) { @@ -2367,13 +2367,13 @@ PalResult PAL_CALL enumerateVkAdapters( } VkPhysicalDevice* devices = nullptr; - devices = palAllocate(s_Vk.allocator, - sizeof(VkPhysicalDevice) * deviceCount, + devices = palAllocate(s_Vk.allocator, + sizeof(VkPhysicalDevice) * deviceCount, 0); s_Vk.adapters = palAllocate( - s_Vk.allocator, - sizeof(Adapter) * deviceCount, + s_Vk.allocator, + sizeof(Adapter) * deviceCount, 0); if (!devices || !s_Vk.adapters) { @@ -2388,13 +2388,13 @@ PalResult PAL_CALL enumerateVkAdapters( // check extension result = s_Vk.enumerateDeviceExtensionProperties( phyDevice, - nullptr, - &extensionCount, + nullptr, + &extensionCount, nullptr); - + extensions = palAllocate( - s_Vk.allocator, - sizeof(VkExtensionProperties) * extensionCount, + s_Vk.allocator, + sizeof(VkExtensionProperties) * extensionCount, 0); if (!extensions) { @@ -2402,9 +2402,9 @@ PalResult PAL_CALL enumerateVkAdapters( } s_Vk.enumerateDeviceExtensionProperties( - phyDevice, - nullptr, - &extensionCount, + phyDevice, + nullptr, + &extensionCount, extensions); bool found = false; @@ -2423,7 +2423,7 @@ PalResult PAL_CALL enumerateVkAdapters( } VkPhysicalDeviceDynamicRenderingFeaturesKHR required = {0}; - required.sType = + required.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; VkPhysicalDeviceFeatures2KHR features = {0}; @@ -2513,8 +2513,8 @@ PalResult PAL_CALL getVkAdapterInfo( // version string snprintf( - info->versionString, - PAL_ADAPTER_VERSION_SIZE, + info->versionString, + PAL_ADAPTER_VERSION_SIZE, "%d.%d.%d", VK_VERSION_MAJOR(props.apiVersion), VK_VERSION_MINOR(props.apiVersion), @@ -2534,7 +2534,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( VkPhysicalDeviceProperties props = {0}; VkPhysicalDeviceMultiviewPropertiesKHR multiViewProps = {0}; VkPhysicalDeviceProperties2 properties2 = {0}; - multiViewProps.sType = + multiViewProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; s_Vk.getPhysicalDeviceProperties(phyDevice, &props); @@ -2560,7 +2560,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->maxUniformBufferSize = props.limits.maxUniformBufferRange; caps->maxStorageBufferSize = props.limits.maxStorageBufferRange; caps->maxPushConstantSize = props.limits.maxPushConstantsSize; - + caps->maxMultiViews = multiViewProps.maxMultiviewViewCount; if (caps->maxMultiViews == 0) { caps->maxMultiViews = 1; @@ -2575,7 +2575,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( Uint32 size = tmp > c ? tmp : c; Uint32 levels = 0; while (size > 0) { - // divide by two + // divide by two size = size / 2; levels++; } @@ -2585,24 +2585,24 @@ PalResult PAL_CALL getVkAdapterCapabilities( Uint32 count; s_Vk.getPhysicalDeviceQueueFamilyProperties( phyDevice, - &count, + &count, nullptr); VkQueueFamilyProperties* queueProps = nullptr; queueProps = palAllocate( - s_Vk.allocator, - sizeof(VkQueueFamilyProperties) * count, + s_Vk.allocator, + sizeof(VkQueueFamilyProperties) * count, 0); s_Vk.getPhysicalDeviceQueueFamilyProperties( - phyDevice, - &count, + phyDevice, + &count, queueProps); caps->maxComputeQueues = 0; caps->maxGraphicsQueues = 0; caps->maxCopyQueues = 0; - + for (int i = 0; i < count; i++) { if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { caps->maxComputeQueues += queueProps->queueCount; @@ -2635,8 +2635,8 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) s_Vk.getPhysicalDeviceProperties(phyDevice, &props); result = s_Vk.enumerateDeviceExtensionProperties( phyDevice, - nullptr, - &extensionCount, + nullptr, + &extensionCount, nullptr); if (result != VK_SUCCESS) { @@ -2646,8 +2646,8 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) VkExtensionProperties* extensionProps = nullptr; extensionProps = palAllocate( - s_Vk.allocator, - sizeof(VkExtensionProperties) * extensionCount, + s_Vk.allocator, + sizeof(VkExtensionProperties) * extensionCount, 0); if (!extensionProps) { @@ -2655,9 +2655,9 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } s_Vk.enumerateDeviceExtensionProperties( - phyDevice, - nullptr, - &extensionCount, + phyDevice, + nullptr, + &extensionCount, extensionProps); // check extensions @@ -2686,11 +2686,11 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) meshShader = true; } else if (strcmp(props->extensionName, "VK_KHR_fragment_shading_rate") == 0) { - fragmentRateShading = true; + fragmentRateShading = true; } else if (strcmp(props->extensionName, "VK_EXT_descriptor_indexing") == 0) { descriptorIndexing = true; - + } else if (strcmp(props->extensionName, "VK_KHR_swapchain") == 0) { adapterFeatures |= PAL_ADAPTER_FEATURE_SWAPCHAIN; @@ -2782,7 +2782,7 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } if (frag.attachmentFragmentShadingRate) { - adapterFeatures |= + adapterFeatures |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT; } } @@ -2973,18 +2973,18 @@ PalResult PAL_CALL createVkDevice( VkQueueFamilyProperties* queueProps = nullptr; VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; s_Vk.getPhysicalDeviceQueueFamilyProperties( - phyDevice, - &queueCount, + phyDevice, + &queueCount, nullptr); queueProps = palAllocate( - s_Vk.allocator, - sizeof(VkQueueFamilyProperties) * queueCount, + s_Vk.allocator, + sizeof(VkQueueFamilyProperties) * queueCount, 0); queueCreateInfos = palAllocate( - s_Vk.allocator, - sizeof(VkDeviceQueueCreateInfo) * queueCount, + s_Vk.allocator, + sizeof(VkDeviceQueueCreateInfo) * queueCount, 0); device = palAllocate(s_Vk.allocator, sizeof(Device), 0); @@ -2995,21 +2995,21 @@ PalResult PAL_CALL createVkDevice( memset(device, 0, sizeof(Device)); device->queueCount = queueCount; device->phyDevice = phyDevice; - + device->phyQueues = palAllocate( - s_Vk.allocator, - sizeof(PhysicalQueue) * queueCount, + s_Vk.allocator, + sizeof(PhysicalQueue) * queueCount, 0); - + if (!device->phyQueues) { return PAL_RESULT_OUT_OF_MEMORY; } s_Vk.getPhysicalDeviceQueueFamilyProperties( - phyDevice, - &queueCount, + phyDevice, + &queueCount, queueProps); - + for (int i = 0; i < queueCount; i++) { queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfos[i].pNext = nullptr; @@ -3177,11 +3177,11 @@ PalResult PAL_CALL createVkDevice( next = &features12; } - if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || + if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { extensions[extCount++] = "VK_KHR_fragment_shading_rate"; fsr.pipelineFragmentShadingRate = true; - + // fragment shading rate attachment needs this if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { fsr.attachmentFragmentShadingRate = true; @@ -3212,8 +3212,8 @@ PalResult PAL_CALL createVkDevice( next = &multiView; } - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE || - features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE || + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE || + features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE || features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_EXT_extended_dynamic_state"; @@ -3224,8 +3224,8 @@ PalResult PAL_CALL createVkDevice( next = &dynamicState; } - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE || - features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE || + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE || + features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE || features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { extensions[extCount++] = "VK_EXT_extended_dynamic_state2"; dynamicState2.extendedDynamicState2 = true; @@ -3255,9 +3255,9 @@ PalResult PAL_CALL createVkDevice( createInfo.pNext = next; result = s_Vk.createDevice( - phyDevice, - &createInfo, - &s_Vk.vkAllocator, + phyDevice, + &createInfo, + &s_Vk.vkAllocator, &device->handle); if (result != VK_SUCCESS) { @@ -3278,7 +3278,7 @@ PalResult PAL_CALL createVkDevice( queue->usedUsages = 0; queue->familyIndex = i; queue->phyDevice = phyDevice; - } + } } // cache memory type indices @@ -3298,9 +3298,9 @@ PalResult PAL_CALL createVkDevice( // GPU memory score = getMemoryTypeScore( - flags, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - 0, + flags, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + 0, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); if (score > gpuBestScore) { @@ -3310,7 +3310,7 @@ PalResult PAL_CALL createVkDevice( // CPU upload score = getMemoryTypeScore( - flags, + flags, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, 0); @@ -3322,8 +3322,8 @@ PalResult PAL_CALL createVkDevice( // CPU readback score = getMemoryTypeScore( - flags, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + flags, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, 0, 0); @@ -3337,178 +3337,178 @@ PalResult PAL_CALL createVkDevice( // load swapchain procs if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { device->acquireNextImage = (PFN_vkAcquireNextImageKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkAcquireNextImageKHR"); device->createSwapchain = (PFN_vkCreateSwapchainKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCreateSwapchainKHR"); device->destroySwapchain = (PFN_vkDestroySwapchainKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkDestroySwapchainKHR"); device->getSwapchainImages = (PFN_vkGetSwapchainImagesKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkGetSwapchainImagesKHR"); device->queuePresent = (PFN_vkQueuePresentKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkQueuePresentKHR"); } // load semaphore procs if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { device->waitSemaphore = (PFN_vkWaitSemaphores)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkWaitSemaphores"); device->signalSemaphore = (PFN_vkSignalSemaphore)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkSignalSemaphore"); device->getSemaphoreValue = (PFN_vkGetSemaphoreCounterValue)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkGetSemaphoreCounterValue"); if (!device->waitSemaphore) { device->waitSemaphore = (PFN_vkWaitSemaphoresKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkWaitSemaphoresKHR"); device->signalSemaphore = (PFN_vkSignalSemaphoreKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkSignalSemaphoreKHR"); device->getSemaphoreValue = (PFN_vkGetSemaphoreCounterValueKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkGetSemaphoreCounterValueKHR"); } } // load fragment shading rate procs if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { - device->cmdSetFragmentShadingRate = + device->cmdSetFragmentShadingRate = (PFN_vkCmdSetFragmentShadingRateKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdSetFragmentShadingRateKHR"); } // mesh shader if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { device->cmdDrawMeshTask = (PFN_vkCmdDrawMeshTasksEXT)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdDrawMeshTasksEXT"); - device->cmdDrawMeshTaskIndirect = + device->cmdDrawMeshTaskIndirect = (PFN_vkCmdDrawMeshTasksIndirectEXT)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdDrawMeshTasksIndirectEXT"); - device->cmdDrawMeshTaskIndirectCount = + device->cmdDrawMeshTaskIndirectCount = (PFN_vkCmdDrawMeshTasksIndirectCountEXT)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdDrawMeshTasksIndirectCountEXT"); + device->handle, + "vkCmdDrawMeshTasksIndirectCountEXT"); } // ray tracing if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - device->createAccelerationStructure = + device->createAccelerationStructure = (PFN_vkCreateAccelerationStructureKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCreateAccelerationStructureKHR"); - device->destroyAccelerationStructure = + device->destroyAccelerationStructure = (PFN_vkDestroyAccelerationStructureKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkDestroyAccelerationStructureKHR"); - device->getAccelerationBuildsize = + device->getAccelerationBuildsize = (PFN_vkGetAccelerationStructureBuildSizesKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkGetAccelerationStructureBuildSizesKHR"); - device->cmdBuildAccelerationStructures = + device->cmdBuildAccelerationStructures = (PFN_vkCmdBuildAccelerationStructuresKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdBuildAccelerationStructuresKHR"); - device->getAccelerationDeviceAddress = + device->getAccelerationDeviceAddress = (PFN_vkGetAccelerationStructureDeviceAddressKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkGetAccelerationStructureDeviceAddressKHR"); - device->cmdTraceRays = + device->cmdTraceRays = (PFN_vkCmdTraceRaysKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdTraceRaysKHR"); - device->createRayTracingPipeline = + device->createRayTracingPipeline = (PFN_vkCreateRayTracingPipelinesKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCreateRayTracingPipelinesKHR"); - device->cmdTraceRaysIndirect = + device->cmdTraceRaysIndirect = (PFN_vkCmdTraceRaysIndirectKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdTraceRaysIndirectKHR"); } // buffer address if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { - device->getBufferrAddress = + device->getBufferrAddress = (PFN_vkGetBufferDeviceAddress)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkGetBufferDeviceAddress"); if (!device->getBufferrAddress) { - device->getBufferrAddress = + device->getBufferrAddress = (PFN_vkGetBufferDeviceAddressKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkGetBufferDeviceAddressKHR"); } } // dynamic rendering - device->cmdBeginRendering = + device->cmdBeginRendering = (PFN_vkCmdBeginRendering)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdBeginRendering"); - device->cmdEndRendering = + device->cmdEndRendering = (PFN_vkCmdEndRendering)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdEndRendering"); - device->cmdPipelineBarrier = + device->cmdPipelineBarrier = (PFN_vkCmdPipelineBarrier2)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdPipelineBarrier2"); - device->queueSubmit = + device->queueSubmit = (PFN_vkQueueSubmit2)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkQueueSubmit2"); if (!device->cmdBeginRendering) { - device->cmdBeginRendering = + device->cmdBeginRendering = (PFN_vkCmdBeginRenderingKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdBeginRenderingKHR"); - device->cmdEndRendering = + device->cmdEndRendering = (PFN_vkCmdEndRenderingKHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdEndRenderingKHR"); - device->cmdPipelineBarrier = + device->cmdPipelineBarrier = (PFN_vkCmdPipelineBarrier2KHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkCmdPipelineBarrier2KHR"); - device->queueSubmit = + device->queueSubmit = (PFN_vkQueueSubmit2KHR)s_Vk.getDeviceProcAddr( - device->handle, + device->handle, "vkQueueSubmit2KHR"); } @@ -3571,9 +3571,9 @@ PalResult PAL_CALL allocateVkMemory( VkDeviceMemory memory = nullptr; VkResult result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, &memory); if (result != VK_SUCCESS) { @@ -3605,17 +3605,17 @@ PalResult PAL_CALL mapVkMemory( Device* vkDevice = (Device*)device; result = s_Vk.mapMemory( - vkDevice->handle, + vkDevice->handle, mem, offset, - size, - 0, + size, + 0, outPtr); if (result != VK_SUCCESS) { return vkResultToPal(result); } - return PAL_RESULT_SUCCESS; + return PAL_RESULT_SUCCESS; } void PAL_CALL unmapVkMemory( @@ -3640,7 +3640,7 @@ PalResult PAL_CALL queryVkDepthStencilCapabilities( properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceDepthStencilResolvePropertiesKHR props = {0}; - props.sType = + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR; properties2.pNext = &props; @@ -3652,7 +3652,7 @@ PalResult PAL_CALL queryVkDepthStencilCapabilities( caps->depthResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; } - if (props.supportedDepthResolveModes & + if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { caps->depthResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; } @@ -3670,7 +3670,7 @@ PalResult PAL_CALL queryVkDepthStencilCapabilities( caps->stencilResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; } - if (props.supportedStencilResolveModes & + if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { caps->stencilResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; } @@ -3699,7 +3699,7 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceFragmentShadingRatePropertiesKHR props = {0}; - props.sType = + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; properties2.pNext = &props; @@ -3711,7 +3711,7 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( // clang-format off // check against the max size - if (size.width <= props.maxFragmentSize.width || + if (size.width <= props.maxFragmentSize.width || size.height <= props.maxFragmentSize.height) { caps->shadingRates[i] = true; } @@ -3783,11 +3783,11 @@ PalResult PAL_CALL queryVkRayTracingCapabilities( properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceRayTracingPipelinePropertiesKHR props = {0}; - props.sType = + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; - accProps.sType = + accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; props.pNext = &accProps; @@ -3853,12 +3853,12 @@ PalResult PAL_CALL createVkQueue( PhysicalQueue* pq = &vkDevice->phyQueues[i]; // check if the physical queue supports the requested operation // and if its not already used - if (pq->usages & queueFlag && + if (pq->usages & queueFlag && pq->usedUsages != queueFlag) { pq->usedUsages |= queueFlag; phyQueue = pq; break; - } + } } if (!phyQueue) { @@ -3887,11 +3887,11 @@ void PAL_CALL destroyVkQueue(PalQueue* queue) } bool PAL_CALL canVkQueuePresent( - PalQueue* queue, + PalQueue* queue, PalGraphicsWindow* window) { Queue* vkQueue = (Queue*)queue; - // check if the queue is a graphics queue before we check its family + // check if the queue is a graphics queue before we check its family // index for presentation support. if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { return false; @@ -3903,13 +3903,13 @@ bool PAL_CALL canVkQueuePresent( } else if (platform == VK_WAYLAND_PLATFORM) { if (s_Vk.checkWaylandPresentSupport( - phyQueue->phyDevice, + phyQueue->phyDevice, phyQueue->familyIndex, window->display)) { return true; } } else if (platform == VK_XLIB_PLATFORM) { - + } return false; } @@ -3948,7 +3948,7 @@ PalResult PAL_CALL enumerateVkFormats( if (fmtCount < *count) { PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; fmtInfo->format = (PalFormat)i; - fmtInfo->usages = + fmtInfo->usages = vkFeatureToPalUsage(props.optimalTilingFeatures); PalImageViewUsages usages = 0; @@ -3960,8 +3960,8 @@ PalResult PAL_CALL enumerateVkFormats( usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; } - if (i == PAL_FORMAT_D32_SFLOAT_S8_UINT || - i == PAL_FORMAT_D16_UNORM_S8_UINT || + if (i == PAL_FORMAT_D32_SFLOAT_S8_UINT || + i == PAL_FORMAT_D16_UNORM_S8_UINT || i == PAL_FORMAT_D24_UNORM_S8_UINT) { usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; @@ -3972,7 +3972,7 @@ PalResult PAL_CALL enumerateVkFormats( usages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; usages |= PAL_IMAGE_VIEW_USAGE_COLOR; } - + if (usages == 0) { usages = PAL_IMAGE_VIEW_USAGE_COLOR; } @@ -4049,8 +4049,8 @@ PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; } - if (format == PAL_FORMAT_D32_SFLOAT_S8_UINT || - format == PAL_FORMAT_D16_UNORM_S8_UINT || + if (format == PAL_FORMAT_D32_SFLOAT_S8_UINT || + format == PAL_FORMAT_D16_UNORM_S8_UINT || format == PAL_FORMAT_D24_UNORM_S8_UINT) { usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; @@ -4061,7 +4061,7 @@ PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( usages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; usages |= PAL_IMAGE_VIEW_USAGE_COLOR; } - + if (usages == 0) { usages = PAL_IMAGE_VIEW_USAGE_COLOR; } @@ -4113,9 +4113,9 @@ PalResult PAL_CALL createVkImage( } result = s_Vk.createImage( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, &image->handle); if (result != VK_SUCCESS) { @@ -4146,8 +4146,8 @@ void PAL_CALL destroyVkImage(PalImage* image) } s_Vk.destroyImage( - vkImage->device->handle, - vkImage->handle, + vkImage->device->handle, + vkImage->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkImage); @@ -4196,12 +4196,12 @@ PalResult PAL_CALL getVkImageMemoryRequirements( requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; } - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; } - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; } @@ -4221,9 +4221,9 @@ PalResult PAL_CALL bindVkImageMemory( VkDeviceMemory mem = (VkDeviceMemory)memory; s_Vk.bindImageMemory( - vkImage->device->handle, + vkImage->device->handle, vkImage->handle, - mem, + mem, offset); } @@ -4243,7 +4243,7 @@ PalResult PAL_CALL createVkImageView( Image* vkImage = (Image*)image; if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - if (!(vkDevice->features & + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -4280,9 +4280,9 @@ PalResult PAL_CALL createVkImageView( createInfo.subresourceRange.aspectMask = aspectFlags; result = s_Vk.createImageView( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, &imageView->handle); if (result != VK_SUCCESS) { @@ -4304,8 +4304,8 @@ void PAL_CALL destroyVkImageView(PalImageView* imageView) { ImageView* vkImageView = (ImageView*)imageView; s_Vk.destroyImageView( - vkImageView->device->handle, - vkImageView->handle, + vkImageView->device->handle, + vkImageView->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkImageView); @@ -4342,13 +4342,13 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, nullptr); modes = palAllocate( - s_Vk.allocator, - sizeof(VkPresentModeKHR) * modeCount, + s_Vk.allocator, + sizeof(VkPresentModeKHR) * modeCount, 0); formats = palAllocate( - s_Vk.allocator, - sizeof(VkSurfaceFormatKHR) * formatCount, + s_Vk.allocator, + sizeof(VkSurfaceFormatKHR) * formatCount, 0); if (!modes || !formats) { @@ -4432,7 +4432,7 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { // find its supported colorspace - if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { + if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = true; } } @@ -4464,7 +4464,7 @@ PalResult PAL_CALL createVkSwapchain( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // check if the queue is a graphics queue before we check its family + // check if the queue is a graphics queue before we check its family // index for presentation support. if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { PAL_RESULT_INVALID_QUEUE; @@ -4532,15 +4532,15 @@ PalResult PAL_CALL createVkSwapchain( // create swapchain VkResult result = vkDevice->createSwapchain( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, &swapchain->handle); if (result != VK_SUCCESS) { s_Vk.destroySurface( - s_Vk.instance, - swapchain->surface, + s_Vk.instance, + swapchain->surface, &s_Vk.vkAllocator); palFree(s_Vk.allocator, swapchain); @@ -4551,18 +4551,18 @@ PalResult PAL_CALL createVkSwapchain( Int32 count = 0; result = vkDevice->getSwapchainImages( vkDevice->handle, - swapchain->handle, + swapchain->handle, &count, nullptr); swapchain->images = palAllocate( - s_Vk.allocator, - sizeof(Image) * count, + s_Vk.allocator, + sizeof(Image) * count, 0); images = palAllocate( - s_Vk.allocator, - sizeof(VkImage) * count, + s_Vk.allocator, + sizeof(VkImage) * count, 0); if (!swapchain->images || !images) { @@ -4573,17 +4573,17 @@ PalResult PAL_CALL createVkSwapchain( ); s_Vk.destroySurface( - s_Vk.instance, - swapchain->surface, + s_Vk.instance, + swapchain->surface, &s_Vk.vkAllocator); palFree(s_Vk.allocator, swapchain); return PAL_RESULT_OUT_OF_MEMORY; } - + vkDevice->getSwapchainImages( - vkDevice->handle, - swapchain->handle, + vkDevice->handle, + swapchain->handle, &count, images); @@ -4599,11 +4599,11 @@ PalResult PAL_CALL createVkSwapchain( image->info.usages = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; image->info.height = createInfo.imageExtent.height; image->info.width = createInfo.imageExtent.width; - image->info.mipLevelCount = 1; + image->info.mipLevelCount = 1; image->info.sampleCount = PAL_SAMPLE_COUNT_1; // swapchain images are not multisampled image->info.type = PAL_IMAGE_TYPE_2D; } - + swapchain->device = vkDevice; swapchain->queue = vkQueue; swapchain->imageCount = count; @@ -4622,8 +4622,8 @@ void PAL_CALL destroyVkSwapchain(PalSwapchain* swapchain) ); s_Vk.destroySurface( - s_Vk.instance, - vkSwapchain->surface, + s_Vk.instance, + vkSwapchain->surface, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkSwapchain->images); @@ -4643,7 +4643,7 @@ PalImage* PAL_CALL getVkSwapchainImage( PalResult PAL_CALL getVkNextSwapchainImage( PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, + PalSwapchainNextImageInfo* info, Uint32* outIndex) { VkResult result; @@ -4679,7 +4679,7 @@ PalResult PAL_CALL getVkNextSwapchainImage( } PalResult PAL_CALL presentVkSwapchain( - PalSwapchain* swapchain, + PalSwapchain* swapchain, PalSwapchainPresentInfo* info) { Swapchain* vkSwapchain = (Swapchain*)swapchain; @@ -4701,7 +4701,7 @@ PalResult PAL_CALL presentVkSwapchain( presentInfo.waitSemaphoreCount = semaphoreCount; result = vkSwapchain->device->queuePresent( - vkSwapchain->queue->phyQueue->handle, + vkSwapchain->queue->phyQueue->handle, &presentInfo); if (result != VK_SUCCESS) { @@ -4777,10 +4777,10 @@ PalResult PAL_CALL createVkShader( result = s_Vk.createShader( vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, + &createInfo, + &s_Vk.vkAllocator, &shader->handle); - + if (result != VK_SUCCESS) { palFree(s_Vk.allocator, shader); return vkResultToPal(result); @@ -4801,10 +4801,10 @@ void PAL_CALL destroyVkShader(PalShader* shader) { Shader* vkShader = (Shader*)shader; s_Vk.destroyShader( - vkShader->device->handle, - vkShader->handle, + vkShader->device->handle, + vkShader->handle, &s_Vk.vkAllocator); - + palFree(s_Vk.allocator, vkShader); } @@ -4833,9 +4833,9 @@ PalResult PAL_CALL createVkFence( } result = s_Vk.createFence( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, &fence->handle); if (result != VK_SUCCESS) { @@ -4852,15 +4852,15 @@ void PAL_CALL destroyVkFence(PalFence* fence) { Fence* vkFence = (Fence*)fence; s_Vk.destroyFence( - vkFence->device->handle, - vkFence->handle, + vkFence->device->handle, + vkFence->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkFence); } PalResult PAL_CALL waitVkFence( - PalFence* fence, + PalFence* fence, Uint64 timeout) { Fence* vkFence = (Fence*)fence; @@ -4871,9 +4871,9 @@ PalResult PAL_CALL waitVkFence( } VkResult result = s_Vk.waitFence( - vkFence->device->handle, - 1, - &vkFence->handle, + vkFence->device->handle, + 1, + &vkFence->handle, true, timeout); @@ -4892,8 +4892,8 @@ PalResult PAL_CALL resetVkFence(PalFence* fence) } VkResult result = s_Vk.resetFence( - vkFence->device->handle, - 1, + vkFence->device->handle, + 1, &vkFence->handle); if (result != VK_SUCCESS) { @@ -4907,7 +4907,7 @@ bool PAL_CALL isVkFenceSignaled(PalFence* fence) { Fence* vkFence = (Fence*)fence; VkResult result = s_Vk.isFenceSignaled( - vkFence->device->handle, + vkFence->device->handle, vkFence->handle); if (result == VK_SUCCESS) { @@ -4951,8 +4951,8 @@ PalResult PAL_CALL createVkSemaphore( createInfo.pNext = next; result = s_Vk.createSemaphore( vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, + &createInfo, + &s_Vk.vkAllocator, &semaphore->handle); if (result != VK_SUCCESS) { @@ -4969,22 +4969,22 @@ void PAL_CALL destroyVkSemaphore(PalSemaphore* semaphore) { Semaphore* vkSemaphore = (Semaphore*)semaphore; s_Vk.destroySemaphore( - vkSemaphore->device->handle, - vkSemaphore->handle, + vkSemaphore->device->handle, + vkSemaphore->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkSemaphore); } PalResult PAL_CALL waitVkSemaphore( - PalSemaphore* semaphore, + PalSemaphore* semaphore, PalQueue* queue, Uint64 value, Uint64 timeout) { VkResult result; Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!(vkSemaphore->device->features & + if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -4996,8 +4996,8 @@ PalResult PAL_CALL waitVkSemaphore( waitInfo.pValues = &value; result = vkSemaphore->device->waitSemaphore( - vkSemaphore->device->handle, - &waitInfo, + vkSemaphore->device->handle, + &waitInfo, timeout); if (result != VK_SUCCESS) { @@ -5014,7 +5014,7 @@ PalResult PAL_CALL signalVkSemaphore( { VkResult result; Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!(vkSemaphore->device->features & + if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5036,18 +5036,18 @@ PalResult PAL_CALL signalVkSemaphore( } PalResult PAL_CALL getVkSemaphoreValue( - PalSemaphore* semaphore, - Uint64* value) + PalSemaphore* semaphore, + Uint64* value) { Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!(vkSemaphore->device->features & + if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } VkResult result = vkSemaphore->device->getSemaphoreValue( - vkSemaphore->device->handle, - vkSemaphore->handle, + vkSemaphore->device->handle, + vkSemaphore->handle, value); if (result != VK_SUCCESS) { @@ -5083,9 +5083,9 @@ PalResult PAL_CALL createVkCommandPool( createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; result = s_Vk.createCommandPool( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, &pool->handle); if (result != VK_SUCCESS) { @@ -5102,8 +5102,8 @@ void PAL_CALL destroyVkCommandPool(PalCommandPool* pool) { CommandPool* vkPool = (CommandPool*)pool; s_Vk.destroyCommandPool( - vkPool->device->handle, - vkPool->handle, + vkPool->device->handle, + vkPool->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkPool); @@ -5145,8 +5145,8 @@ PalResult PAL_CALL createVkCommandBuffer( } result = s_Vk.createCommandBuffer( - vkDevice->handle, - &createInfo, + vkDevice->handle, + &createInfo, &cmdBuffer->handle); if (result != VK_SUCCESS) { @@ -5174,7 +5174,7 @@ void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) } PalResult PAL_CALL beginVkCommandBuffer( - PalCommandBuffer* cmdBuffer, + PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -5184,7 +5184,7 @@ PalResult PAL_CALL beginVkCommandBuffer( VkCommandBufferInheritanceInfo inheritanceInfo = {0}; inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; VkCommandBufferInheritanceRenderingInfoKHR layout = {0}; - layout.sType = + layout.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; VkFormat format = VK_FORMAT_UNDEFINED; @@ -5251,7 +5251,7 @@ PalResult PAL_CALL executeCommandBufferVk( CommandBuffer* vkCmdBuffer = (CommandBuffer*)primaryCmdBuffer; CommandBuffer* vkCmdBuffer2 = (CommandBuffer*)secondaryCmdBuffer; s_Vk.cmdExecuteCommandBuffer( - vkCmdBuffer->handle, + vkCmdBuffer->handle, 1, &vkCmdBuffer2->handle); @@ -5263,7 +5263,7 @@ PalResult PAL_CALL setVkFragmentShadingRate( PalFragmentShadingRateState* state) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5279,7 +5279,7 @@ PalResult PAL_CALL setVkFragmentShadingRate( } case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE: { - combinerOps[i] = + combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; continue; } @@ -5324,8 +5324,8 @@ PalResult PAL_CALL drawVkMeshTasks( vkCmdBuffer->device->cmdDrawMeshTask( vkCmdBuffer->handle, - groupCountX, - groupCountY, + groupCountX, + groupCountY, groupCountZ); return PAL_RESULT_SUCCESS; @@ -5364,7 +5364,7 @@ PalResult PAL_CALL drawVkMeshTasksIndirectCount( Uint32 stride) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5392,19 +5392,19 @@ PalResult PAL_CALL buildVkAccelerationStructure( if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - + VkAccelerationStructureGeometryKHR* geometries = nullptr; VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; AccelerationStructure* as = (AccelerationStructure*)info->dst; Buffer* scratchBuffer = (Buffer*)info->scratchBuffer; geometries = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount, + s_Vk.allocator, + sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount, 0); rangeInfos = palAllocate( - s_Vk.allocator, + s_Vk.allocator, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->geometryCount, 0); @@ -5425,7 +5425,7 @@ PalResult PAL_CALL buildVkAccelerationStructure( VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; data->pNext = nullptr; data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; - + VkDeviceOrHostAddressConstKHR vertexAddress = {0}; VkDeviceOrHostAddressConstKHR indexAddress = {0}; PalGeometryDataTriangle* tmpData = info->geometries[i].data; @@ -5445,14 +5445,14 @@ PalResult PAL_CALL buildVkAccelerationStructure( } else { data->indexType = VK_INDEX_TYPE_UINT16; } - + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; data->pNext = nullptr; - data->sType = + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; - + VkDeviceOrHostAddressConstKHR address = {0}; PalGeometryDataAABBS* tmpData = info->geometries[i].data; Buffer* vkBuffer = (Buffer*)tmpData->buffer; @@ -5465,9 +5465,9 @@ PalResult PAL_CALL buildVkAccelerationStructure( VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; data = &tmp->geometry.instances; data->pNext = nullptr; - data->sType = + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; - + VkDeviceOrHostAddressConstKHR address = {0}; PalGeometryDataInstance* tmpData = info->geometries[i].data; Buffer* vkBuffer = (Buffer*)tmpData->buffer; @@ -5485,9 +5485,9 @@ PalResult PAL_CALL buildVkAccelerationStructure( // clang-format on VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - buildInfo.sType = + buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; - + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; } else { @@ -5499,7 +5499,7 @@ PalResult PAL_CALL buildVkAccelerationStructure( buildInfo.dstAccelerationStructure = as->handle; VkDeviceOrHostAddressKHR scratchData = {0}; - scratchData.deviceAddress = + scratchData.deviceAddress = scratchBuffer->address + info->scratchBufferOffset; buildInfo.scratchData = scratchData; @@ -5539,7 +5539,7 @@ PalResult PAL_CALL beginRenderingVk( VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL; VkRenderingFragmentShadingRateAttachmentInfoKHR fsrInfo = {0}; - fsrInfo.sType = + fsrInfo.sType = VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; for (int i = 0; i < info->colorAttachentCount; i++) { @@ -5683,17 +5683,17 @@ PalResult PAL_CALL beginRenderingVk( // fragment shading rate attachment if (info->fragmentShadingRateAttachment) { - imageView = + imageView = (ImageView*)info->fragmentShadingRateAttachment->imageView; fsrInfo.imageView = imageView->handle; - fsrInfo.shadingRateAttachmentTexelSize.width = + fsrInfo.shadingRateAttachmentTexelSize.width = info->fragmentShadingRateAttachment->texelWidth; - fsrInfo.shadingRateAttachmentTexelSize.height = + fsrInfo.shadingRateAttachmentTexelSize.height = info->fragmentShadingRateAttachment->texelHeight; - fsrInfo.imageLayout = + fsrInfo.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; rendering.pNext = &fsrInfo; @@ -5739,10 +5739,10 @@ PalResult PAL_CALL copyVkBuffer( copyRegion.dstOffset = dstOffset; copyRegion.srcOffset = srcOffset; s_Vk.cmdCopyBuffer( - vkCmdBuffer->handle, - srcBuffer->handle, - dstbuffer->handle, - 1, + vkCmdBuffer->handle, + srcBuffer->handle, + dstbuffer->handle, + 1, ©Region); return PAL_RESULT_SUCCESS; @@ -5761,7 +5761,7 @@ PalResult PAL_CALL bindVkPipeline( } else if (vkPipeline->type == RAY_TRACING_PIPELINE) { bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; } - + s_Vk.cmdBindPipeline(vkCmdBuffer->handle, bindPoint, vkPipeline->handle); return PAL_RESULT_SUCCESS; } @@ -5777,8 +5777,8 @@ PalResult PAL_CALL setVkViewport( if (count > 1) { vkViewports = palAllocate( - s_Vk.allocator, - sizeof(VkViewport) * count, + s_Vk.allocator, + sizeof(VkViewport) * count, 0); if (!vkViewports) { @@ -5817,8 +5817,8 @@ PalResult PAL_CALL setVkScissors( if (count > 1) { vkScissors = palAllocate( - s_Vk.allocator, - sizeof(VkRect2D) * count, + s_Vk.allocator, + sizeof(VkRect2D) * count, 0); if (!vkScissors) { @@ -5871,10 +5871,10 @@ PalResult PAL_CALL bindVkVertexBuffers( } s_Vk.bindVertexBuffers( - vkCmdBuffer->handle, - firstSlot, - count, - vkBuffers, + vkCmdBuffer->handle, + firstSlot, + count, + vkBuffers, offsets); if (count > 1) { @@ -5897,11 +5897,11 @@ PalResult PAL_CALL bindVkIndexBuffer( } s_Vk.bindIndexBuffer( - vkCmdBuffer->handle, - vkBuffer->handle, - offset, + vkCmdBuffer->handle, + vkBuffer->handle, + offset, bufferType); - + return PAL_RESULT_SUCCESS; } @@ -5929,10 +5929,10 @@ PalResult PAL_CALL drawIndirectVk( CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; Uint32 stride = sizeof(VkDrawIndirectCommand); - + s_Vk.cmdDrawIndirect( - vkCmdBuffer->handle, - vkBuffer->handle, + vkCmdBuffer->handle, + vkBuffer->handle, offset, count, stride); @@ -5946,7 +5946,7 @@ PalResult PAL_CALL drawIndexedVk( { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.cmdDrawIndexed( - vkCmdBuffer->handle, + vkCmdBuffer->handle, data->indexCount, data->instanceCount, data->firstIndex, @@ -5968,8 +5968,8 @@ PalResult PAL_CALL drawIndexedIndirectVk( s_Vk.cmdDrawIndexedIndirect( vkCmdBuffer->handle, - vkBuffer->handle, - offset, + vkBuffer->handle, + offset, count, stride); @@ -6082,12 +6082,12 @@ PalResult PAL_CALL submitVkCommandBuffer( if (info->fence) { Fence* tmp = (Fence*)info->fence; - fenceHandle = tmp->handle; + fenceHandle = tmp->handle; } VkCommandBufferSubmitInfoKHR cmdBufferSubmitInfo = {0}; cmdBufferSubmitInfo.commandBuffer = vkCmdBuffer->handle; - cmdBufferSubmitInfo.sType = + cmdBufferSubmitInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR; VkSemaphoreSubmitInfoKHR waitSubmitInfo = {0}; @@ -6100,7 +6100,7 @@ PalResult PAL_CALL submitVkCommandBuffer( signalSubmitInfo.semaphore = signalSemaphoreHandle; signalSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - if (vkCmdBuffer->device->features & + if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { waitSubmitInfo.value = info->waitValue; signalSubmitInfo.value = info->signalValue; @@ -6118,7 +6118,7 @@ PalResult PAL_CALL submitVkCommandBuffer( result = vkCmdBuffer->device->queueSubmit( vkQueue->phyQueue->handle, 1, - &submitInfo, + &submitInfo, fenceHandle); if (result != VK_SUCCESS) { @@ -6156,7 +6156,7 @@ PalResult PAL_CALL createVkAccelerationstructure( } VkAccelerationStructureCreateInfoKHR createInfo = {0}; - createInfo.sType = + createInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; createInfo.offset = (VkDeviceSize)info->offset; @@ -6181,12 +6181,12 @@ PalResult PAL_CALL createVkAccelerationstructure( // get and cache address VkAccelerationStructureDeviceAddressInfoKHR addressInfo = {0}; - addressInfo.sType = + addressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; addressInfo.accelerationStructure = as->handle; as->address = vkDevice->getAccelerationDeviceAddress( - vkDevice->handle, + vkDevice->handle, &addressInfo); as->device = vkDevice; @@ -6199,8 +6199,8 @@ void PAL_CALL destroyVkAccelerationstructure( { AccelerationStructure* vkAs = (AccelerationStructure*)as; vkAs->device->destroyAccelerationStructure( - vkAs->device->handle, - vkAs->handle, + vkAs->device->handle, + vkAs->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkAs); @@ -6223,13 +6223,13 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( } maxPrimities = palAllocate( - s_Vk.allocator, - sizeof(Uint32) * info->geometryCount, + s_Vk.allocator, + sizeof(Uint32) * info->geometryCount, 0); geometries = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount, + s_Vk.allocator, + sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount, 0); if (!maxPrimities || !geometries) { @@ -6251,7 +6251,7 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; data->pNext = nullptr; data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; - + VkDeviceOrHostAddressConstKHR vertexAddress = {0}; VkDeviceOrHostAddressConstKHR indexAddress = {0}; PalGeometryDataTriangle* tmpData = info->geometries[i].data; @@ -6271,14 +6271,14 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( } else { data->indexType = VK_INDEX_TYPE_UINT16; } - + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; data->pNext = nullptr; - data->sType = + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; - + VkDeviceOrHostAddressConstKHR address = {0}; PalGeometryDataAABBS* tmpData = info->geometries[i].data; Buffer* vkBuffer = (Buffer*)tmpData->buffer; @@ -6291,9 +6291,9 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; data = &tmp->geometry.instances; data->pNext = nullptr; - data->sType = + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; - + VkDeviceOrHostAddressConstKHR address = {0}; PalGeometryDataInstance* tmpData = info->geometries[i].data; Buffer* vkBuffer = (Buffer*)tmpData->buffer; @@ -6304,9 +6304,9 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( // clang-format on VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - buildInfo.sType = + buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; - + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; } else { @@ -6318,7 +6318,7 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( buildInfo.dstAccelerationStructure = vkAs->handle; VkDeviceOrHostAddressKHR scratchData = {0}; - scratchData.deviceAddress = + scratchData.deviceAddress = vkScratchBuffer->address + info->scratchBufferOffset; buildInfo.scratchData = scratchData; @@ -6326,12 +6326,12 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( buildInfo.pGeometries = geometries; VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; - sizeInfo.sType = + sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; vkDevice->getAccelerationBuildsize( - vkDevice->handle, - VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + vkDevice->handle, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, maxPrimities, &sizeInfo); @@ -6341,7 +6341,7 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( palFree(s_Vk.allocator, maxPrimities); palFree(s_Vk.allocator, geometries); - + return PAL_RESULT_SUCCESS; } @@ -6364,7 +6364,7 @@ PalResult PAL_CALL createVkBuffer( // buffer device address feature is supported if ray tracing is } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - if (!(vkDevice->features & + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6380,9 +6380,9 @@ PalResult PAL_CALL createVkBuffer( createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.size = info->size; createInfo.usage = palBufferUsageToVk(info->usages); - + result = s_Vk.createBuffer( - vkDevice->handle, + vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &buffer->handle); @@ -6398,7 +6398,7 @@ PalResult PAL_CALL createVkBuffer( VkBufferDeviceAddressInfoKHR bufferInfo = {0}; bufferInfo.buffer = buffer->handle; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; - buffer->address = + buffer->address = vkDevice->getBufferrAddress(vkDevice->handle, &bufferInfo); } @@ -6411,8 +6411,8 @@ void PAL_CALL destroyVkBuffer(PalBuffer* buffer) { Buffer* vkBuffer = (Buffer*)buffer; s_Vk.destroyBuffer( - vkBuffer->device->handle, - vkBuffer->handle, + vkBuffer->device->handle, + vkBuffer->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, buffer); @@ -6430,7 +6430,7 @@ PalResult PAL_CALL getVkBufferMemoryRequirements( VkMemoryRequirements memReq = {0}; s_Vk.getBufferMemoryRequirements( - device->handle, + device->handle, vkBuffer->handle, &memReq); @@ -6452,12 +6452,12 @@ PalResult PAL_CALL getVkBufferMemoryRequirements( requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; } - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; } - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; } @@ -6474,9 +6474,9 @@ PalResult PAL_CALL bindVkBufferMemory( VkDeviceMemory mem = (VkDeviceMemory)memory; Buffer* vkBuffer = (Buffer*)buffer; result = s_Vk.bindBufferMemory( - vkBuffer->device->handle, - vkBuffer->handle, - mem, + vkBuffer->device->handle, + vkBuffer->handle, + mem, offset); if (result != VK_SUCCESS) { @@ -6507,9 +6507,9 @@ PalResult PAL_CALL createVkPipelineLayout( createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; result = s_Vk.createPipelineLayout( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, &layout->handle); if (result != VK_SUCCESS) { @@ -6526,7 +6526,7 @@ void PAL_CALL destroyVkPipelineLayout(PalPipelineLayout* layout) PipelineLayout* pipelineLayout = (PipelineLayout*)layout; s_Vk.destroyPipelineLayout( pipelineLayout->device->handle, - pipelineLayout->handle, + pipelineLayout->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, layout); @@ -6621,12 +6621,12 @@ PalResult PAL_CALL createVkGraphicsPipeline( } bindingDescs = palAllocate( - s_Vk.allocator, + s_Vk.allocator, sizeof(VkVertexInputBindingDescription) * info->vertexLayoutCount, 0); attribDescs = palAllocate( - s_Vk.allocator, + s_Vk.allocator, sizeof(VkVertexInputAttributeDescription) * vertexCount, 0); @@ -6803,7 +6803,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( sampleMasks[1] = mask2; multisampleState.pSampleMask = sampleMasks; - + } else { multisampleState.alphaToCoverageEnable = VK_FALSE; multisampleState.minSampleShading = VK_FALSE; @@ -6844,12 +6844,12 @@ PalResult PAL_CALL createVkGraphicsPipeline( depthStencilState.stencilTestEnable = VK_FALSE; } createInfo.pDepthStencilState = &depthStencilState; - + // Color blend state if (info->blendAttachmentCount) { Uint32 count = info->blendAttachmentCount; blendattachments = palAllocate( - s_Vk.allocator, + s_Vk.allocator, sizeof(VkPipelineColorBlendAttachmentState) * count, 0); @@ -6868,14 +6868,14 @@ PalResult PAL_CALL createVkGraphicsPipeline( tmp->alphaBlendOp = blendOpToVk(desc->alphaBlendOp); tmp->colorBlendOp = blendOpToVk(desc->colorBlendOp); - tmp->srcAlphaBlendFactor = + tmp->srcAlphaBlendFactor = blendFactorToVk(desc->srcAlphaBlendFactor); - tmp->srcColorBlendFactor = + tmp->srcColorBlendFactor = blendFactorToVk(desc->srcColorBlendFactor); - tmp->dstAlphaBlendFactor = + tmp->dstAlphaBlendFactor = blendFactorToVk(desc->dstAlphaBlendFactor); - tmp->dstColorBlendFactor = + tmp->dstColorBlendFactor = blendFactorToVk(desc->dstColorBlendFactor); // blend color write mask @@ -6952,11 +6952,11 @@ PalResult PAL_CALL createVkGraphicsPipeline( createInfo.pNext = &dynRendering; result = s_Vk.createGraphicsPipeline( - vkDevice->handle, - 0, - 1, - &createInfo, - &s_Vk.vkAllocator, + vkDevice->handle, + 0, + 1, + &createInfo, + &s_Vk.vkAllocator, &pipeline->handle); if (result != VK_SUCCESS) { @@ -6979,10 +6979,10 @@ void PAL_CALL destroyVkPipeline(PalPipeline* pipeline) Pipeline* vkPipeline = (Pipeline*)pipeline; s_Vk.destroyPipeline( vkPipeline->device->handle, - vkPipeline->handle, + vkPipeline->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, pipeline); } -#endif // PAL_HAS_VULKAN \ No newline at end of file +#endif // PAL_HAS_VULKAN diff --git a/src/opengl/pal_opengl_linux.c b/src/opengl/pal_opengl_linux.c index cb957ad6..b061850f 100644 --- a/src/opengl/pal_opengl_linux.c +++ b/src/opengl/pal_opengl_linux.c @@ -383,7 +383,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) // clang-format off s_GL.eglGetProcAddress = (eglGetProcAddressFn)dlsym( - s_GL.handle, + s_GL.handle, "eglGetProcAddress"); s_GL.eglCreateContext = (eglCreateContextFn)s_GL.eglGetProcAddress( @@ -436,23 +436,23 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) s_GL.glClearColor = (glClearColorFn)s_GL.eglGetProcAddress("glClearColor"); s_GL.glClear = (glClearFn)s_GL.eglGetProcAddress("glClear"); - if (!s_GL.eglBindAPI || - !s_GL.eglChooseConfig || + if (!s_GL.eglBindAPI || + !s_GL.eglChooseConfig || !s_GL.eglCreateContext || - !s_GL.eglCreatePbufferSurface || + !s_GL.eglCreatePbufferSurface || !s_GL.eglDestroyContext || - !s_GL.eglDestroySurface || + !s_GL.eglDestroySurface || !s_GL.eglGetConfigAttrib || - !s_GL.eglGetDisplay || - !s_GL.eglGetError || + !s_GL.eglGetDisplay || + !s_GL.eglGetError || !s_GL.eglGetProcAddress || - !s_GL.eglInitialize || - !s_GL.eglMakeCurrent || + !s_GL.eglInitialize || + !s_GL.eglMakeCurrent || !s_GL.eglSwapBuffers || - !s_GL.eglSwapInterval || - !s_GL.eglTerminate || + !s_GL.eglSwapInterval || + !s_GL.eglTerminate || !s_GL.eglQueryString || - !s_GL.eglGetConfigs || + !s_GL.eglGetConfigs || !s_GL.eglCreateWindowSurface) { palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; @@ -544,12 +544,12 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) EGLSurface surface = EGL_NO_SURFACE; EGLint pBufferAttribs[] = { EGL_WIDTH, 1, - EGL_HEIGHT, 1, + EGL_HEIGHT, 1, EGL_NONE}; surface = s_GL.eglCreatePbufferSurface( - tmpDisplay, - config, + tmpDisplay, + config, pBufferAttribs); if (surface == EGL_NO_SURFACE) { @@ -561,25 +561,25 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) EGLContext context = EGL_NO_CONTEXT; if (s_GL.apiType == EGL_OPENGL_API) { EGLint contextAttrib[] = { - EGL_CONTEXT_MAJOR_VERSION, 2, - EGL_CONTEXT_MINOR_VERSION, 1, + EGL_CONTEXT_MAJOR_VERSION, 2, + EGL_CONTEXT_MINOR_VERSION, 1, EGL_NONE}; - + context = s_GL.eglCreateContext( - tmpDisplay, - config, - EGL_NO_CONTEXT, + tmpDisplay, + config, + EGL_NO_CONTEXT, contextAttrib); } else { EGLint contextAttrib[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - + context = s_GL.eglCreateContext( - tmpDisplay, - config, - EGL_NO_CONTEXT, + tmpDisplay, + config, + EGL_NO_CONTEXT, contextAttrib); } @@ -649,7 +649,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) // part of the core API s_GL.info.extensions |= PAL_GL_EXTENSION_MULTISAMPLE; - if (type & EGL_OPENGL_ES_BIT || + if (type & EGL_OPENGL_ES_BIT || type & EGL_OPENGL_ES2_BIT) { s_GL.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; } @@ -1129,9 +1129,9 @@ PalResult PAL_CALL palCreateGLContext( // clang-format off // create context EGLContext context = s_GL.eglCreateContext( - s_GL.display, - config, - share, + s_GL.display, + config, + share, attribs); // clang-format on @@ -1345,4 +1345,4 @@ const char* PAL_CALL palGLGetBackend() } else { return "gles"; } -} \ No newline at end of file +} diff --git a/src/opengl/pal_opengl_win32.c b/src/opengl/pal_opengl_win32.c index 30dae398..5950e914 100644 --- a/src/opengl/pal_opengl_win32.c +++ b/src/opengl/pal_opengl_win32.c @@ -306,15 +306,15 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) // load gdi function pointers s_Gdi.choosePixelFormat = (ChoosePixelFormatFn)GetProcAddress( - s_Gdi.handle, + s_Gdi.handle, "ChoosePixelFormat"); s_Gdi.setPixelFormat = (SetPixelFormatFn)GetProcAddress( - s_Gdi.handle, + s_Gdi.handle, "SetPixelFormat"); s_Gdi.getPixelFormat = (GetPixelFormatFn)GetProcAddress( - s_Gdi.handle, + s_Gdi.handle, "GetPixelFormat"); s_Gdi.describePixelFormat = (DescribePixelFormatFn)GetProcAddress( @@ -322,28 +322,28 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) "DescribePixelFormat"); s_Gdi.swapBuffers = (SwapBuffersFn)GetProcAddress( - s_Gdi.handle, + s_Gdi.handle, "SwapBuffers"); // load wgl function pointers s_Wgl.wglGetProcAddress = (wglGetProcAddressFn)GetProcAddress( - s_Wgl.opengl, + s_Wgl.opengl, "wglGetProcAddress"); s_Wgl.wglCreateContext = (wglCreateContextFn)GetProcAddress( - s_Wgl.opengl, + s_Wgl.opengl, "wglCreateContext"); s_Wgl.wglDeleteContext = (wglDeleteContextFn)GetProcAddress( - s_Wgl.opengl, + s_Wgl.opengl, "wglDeleteContext"); s_Wgl.wglMakeCurrent = (wglMakeCurrentFn)GetProcAddress( - s_Wgl.opengl, + s_Wgl.opengl, "wglMakeCurrent"); s_Wgl.wglShareLists = (wglShareListsFn)GetProcAddress( - s_Wgl.opengl, + s_Wgl.opengl, "wglShareLists"); if (!s_Gdi.choosePixelFormat || @@ -355,9 +355,9 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) return PAL_RESULT_PLATFORM_FAILURE; } - if (!s_Wgl.wglGetProcAddress || + if (!s_Wgl.wglGetProcAddress || !s_Wgl.wglCreateContext || - !s_Wgl.wglDeleteContext || + !s_Wgl.wglDeleteContext || !s_Wgl.wglMakeCurrent) { DWORD error = GetLastError(); palSetLastPlatformError(error); @@ -411,7 +411,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) // load gl functions s_Wgl.glGetString = (glGetStringFn)GetProcAddress( - s_Wgl.opengl, + s_Wgl.opengl, "glGetString"); // clang-format on @@ -1073,4 +1073,4 @@ const char* PAL_CALL palGLGetBackend() return nullptr; } return "wgl"; -} \ No newline at end of file +} diff --git a/src/pal_core.c b/src/pal_core.c index c37263eb..1acc5de0 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -541,4 +541,4 @@ Uint64 PAL_CALL palGetPerformanceFrequency() #elif defined(__linux__) return 1000000000LL; #endif // _WIN32 -} \ No newline at end of file +} diff --git a/src/pal_event.c b/src/pal_event.c index 6c3d8175..251a19cc 100644 --- a/src/pal_event.c +++ b/src/pal_event.c @@ -209,4 +209,4 @@ bool PAL_CALL palPollEvent( } return eventDriver->queue->poll(eventDriver->queue, outEvent); -} \ No newline at end of file +} diff --git a/src/system/pal_system_linux.c b/src/system/pal_system_linux.c index 14a476f2..386afd42 100644 --- a/src/system/pal_system_linux.c +++ b/src/system/pal_system_linux.c @@ -253,4 +253,4 @@ PalResult PAL_CALL palGetCPUInfo( } return PAL_RESULT_SUCCESS; -} \ No newline at end of file +} diff --git a/src/system/pal_system_win32.c b/src/system/pal_system_win32.c index 6cc7ac1a..63fb7dbb 100644 --- a/src/system/pal_system_win32.c +++ b/src/system/pal_system_win32.c @@ -82,7 +82,7 @@ static inline bool getVersionWin32(PalVersion* version) // clang-format off RtlGetVersionFn getVer = (RtlGetVersionFn)GetProcAddress( - ntdll, + ntdll, "RtlGetVersion"); // clang-format on @@ -372,4 +372,4 @@ PalResult PAL_CALL palGetCPUInfo( info->features = features; return PAL_RESULT_SUCCESS; -} \ No newline at end of file +} diff --git a/src/thread/pal_thread_linux.c b/src/thread/pal_thread_linux.c index 030b0690..d2940177 100644 --- a/src/thread/pal_thread_linux.c +++ b/src/thread/pal_thread_linux.c @@ -484,4 +484,4 @@ void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) if (condVar) { pthread_cond_broadcast(&condVar->handle); } -} \ No newline at end of file +} diff --git a/src/thread/pal_thread_win32.c b/src/thread/pal_thread_win32.c index 558cfe71..d2b76684 100644 --- a/src/thread/pal_thread_win32.c +++ b/src/thread/pal_thread_win32.c @@ -206,7 +206,7 @@ PalThreadFeatures PAL_CALL palGetThreadFeatures() if (kernel32) { // clang-format off FARPROC setThreadDesc = GetProcAddress( - kernel32, + kernel32, "SetThreadDescription"); // clang-format on @@ -562,8 +562,8 @@ PalResult PAL_CALL palWaitCondVarTimeout( // clang-format off BOOL ret = SleepConditionVariableCS( - &condVar->cv, - &mutex->sc, + &condVar->cv, + &mutex->sc, (DWORD)milliseconds); // clang-format on @@ -591,4 +591,4 @@ void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) if (condVar) { WakeAllConditionVariable(&condVar->cv); } -} \ No newline at end of file +} diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index 82d1c638..a982e836 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -868,20 +868,20 @@ typedef int (*wl_display_dispatch_fn)(struct wl_display*); typedef void (*wl_proxy_destroy_fn)(struct wl_proxy*); typedef int (*wl_proxy_add_listener_fn)( - struct wl_proxy*, + struct wl_proxy*, void (**)(void), void*); typedef struct wl_proxy* (*wl_proxy_marshal_constructor_v_fn)( - struct wl_proxy*, - uint32_t, - const struct wl_interface*, + struct wl_proxy*, + uint32_t, + const struct wl_interface*, uint32_t, ...); typedef struct wl_proxy* (*wl_proxy_marshal_flags_fn)( - struct wl_proxy*, - uint32_t, - const struct wl_interface*, - uint32_t, + struct wl_proxy*, + uint32_t, + const struct wl_interface*, + uint32_t, uint32_t, ...); typedef uint32_t (*wl_proxy_get_version_fn)(struct wl_proxy*); @@ -907,11 +907,11 @@ typedef struct xkb_context* (*xkb_context_new_fn)(enum xkb_context_flags); typedef uint32_t (*xkb_keysym_to_utf32_fn)(xkb_keysym_t); typedef xkb_keysym_t (*xkb_state_key_get_one_sym_fn)( - struct xkb_state*, + struct xkb_state*, xkb_keycode_t); typedef struct xkb_keymap* (*xkb_keymap_new_from_string_fn)( - struct xkb_context*, + struct xkb_context*, const char*, enum xkb_keymap_format, enum xkb_keymap_compile_flags); @@ -926,13 +926,13 @@ typedef enum xkb_state_component (*xkb_state_update_mask_fn)( xkb_layout_index_t); typedef int (*xkb_keymap_key_repeats_fn)( - struct xkb_keymap*, + struct xkb_keymap*, xkb_keycode_t); // wayland cursor typedef struct wl_cursor_theme* (*wl_cursor_theme_load_fn)( - const char*, - int, + const char*, + int, struct wl_shm*); typedef struct wl_cursor* (*wl_cursor_theme_get_cursor_fn)( @@ -948,22 +948,22 @@ struct wl_surface; typedef struct wl_egl_window* (*wl_egl_window_create_fn)( struct wl_surface*, - int, + int, int); typedef void (*wl_egl_window_destroy_fn)(struct wl_egl_window*); typedef void (*wl_egl_window_resize_fn)( struct wl_egl_window*, - int, - int, - int, + int, + int, + int, int); typedef struct { bool checkFeatures; int monitorCount; - + void* handle; void* xkbCommon; void* libCursor; @@ -1061,21 +1061,21 @@ static inline Uint64 getTime() } static inline void* wlRegistryBind( - struct wl_registry *wl_registry, - uint32_t name, - const struct wl_interface *interface, + struct wl_registry *wl_registry, + uint32_t name, + const struct wl_interface *interface, uint32_t version) { struct wl_proxy *id; id = s_Wl.proxyMarshalFlags( (struct wl_proxy *)wl_registry, - WL_REGISTRY_BIND, - interface, - version, - 0, - name, - interface->name, - version, + WL_REGISTRY_BIND, + interface, + version, + 0, + name, + interface->name, + version, NULL); return (void *)id; @@ -1083,7 +1083,7 @@ static inline void* wlRegistryBind( static inline int wlRegistryAddListener( struct wl_registry *wl_registry, - const struct wl_registry_listener *listener, + const struct wl_registry_listener *listener, void *data) { return s_Wl.proxyAddListener( @@ -1098,10 +1098,10 @@ static inline struct wl_registry* wlDisplayGetRegistry( registry = s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_display, 1, // WL_DISPLAY_GET_REGISTRY - s_Wl.registryInterface, + s_Wl.registryInterface, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_display), - 0, + (struct wl_proxy *) wl_display), + 0, NULL); return (struct wl_registry *)registry; @@ -1109,7 +1109,7 @@ static inline struct wl_registry* wlDisplayGetRegistry( static inline int wlOutputAddListener( struct wl_output *wl_output, - const struct wl_output_listener *listener, + const struct wl_output_listener *listener, void *data) { return s_Wl.proxyAddListener( @@ -1124,10 +1124,10 @@ static inline struct wl_surface* wlCompositorCreateSurface( id = s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_compositor, 0, // WL_COMPOSITOR_CREATE_SURFACE, - s_Wl.surfaceInterface, + s_Wl.surfaceInterface, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_compositor), - 0, + (struct wl_proxy *) wl_compositor), + 0, NULL); return (struct wl_surface*) id; @@ -1138,9 +1138,9 @@ static inline void wlSurfaceCommit(struct wl_surface *wl_surface) s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_surface, 6, // WL_SURFACE_COMMIT - NULL, + NULL, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), + (struct wl_proxy *) wl_surface), 0); } @@ -1149,27 +1149,27 @@ static inline void wlSurfaceDestroy(struct wl_surface *wl_surface) s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_surface, 0, // WL_SURFACE_DESTROY - NULL, + NULL, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), + (struct wl_proxy *) wl_surface), WL_MARSHAL_FLAG_DESTROY); } static inline struct wl_shm_pool* wlShmCreatePool( - struct wl_shm *wl_shm, - int32_t fd, + struct wl_shm *wl_shm, + int32_t fd, int32_t size) { struct wl_proxy *id; id = s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_shm, 0, // WL_SHM_CREATE_POOL - s_Wl.shmPoolInterface, + s_Wl.shmPoolInterface, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_shm), - 0, - NULL, - fd, + (struct wl_proxy *) wl_shm), + 0, + NULL, + fd, size); return (struct wl_shm_pool *) id; @@ -1179,34 +1179,34 @@ static inline void wlShmPoolDestroy(struct wl_shm_pool *wl_shm_pool) { s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_DESTROY, - NULL, + WL_SHM_POOL_DESTROY, + NULL, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_shm_pool), + (struct wl_proxy *) wl_shm_pool), WL_MARSHAL_FLAG_DESTROY); } static inline struct wl_buffer* wlShmPoolCreateBuffer( - struct wl_shm_pool *wl_shm_pool, - int32_t offset, - int32_t width, - int32_t height, - int32_t stride, + struct wl_shm_pool *wl_shm_pool, + int32_t offset, + int32_t width, + int32_t height, + int32_t stride, uint32_t format) { struct wl_proxy *id; id = s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_CREATE_BUFFER, - s_Wl.bufferInterface, + WL_SHM_POOL_CREATE_BUFFER, + s_Wl.bufferInterface, s_Wl.proxyGetVersion( (struct wl_proxy *) wl_shm_pool), - 0, - NULL, + 0, + NULL, offset, - width, - height, - stride, + width, + height, + stride, format); return (struct wl_buffer *) id; @@ -1216,54 +1216,54 @@ static inline void wlBufferDestroy(struct wl_buffer *wl_buffer) { s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_buffer, - WL_BUFFER_DESTROY, - NULL, + WL_BUFFER_DESTROY, + NULL, s_Wl.proxyGetVersion( (struct wl_proxy *) wl_buffer), WL_MARSHAL_FLAG_DESTROY); } static inline void wlSurfaceAttach( - struct wl_surface *wl_surface, - struct wl_buffer *buffer, - int32_t x, + struct wl_surface *wl_surface, + struct wl_buffer *buffer, + int32_t x, int32_t y) { s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_surface, - WL_SURFACE_ATTACH, - NULL, + WL_SURFACE_ATTACH, + NULL, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0, - buffer, - x, + (struct wl_proxy *) wl_surface), + 0, + buffer, + x, y); } static inline void wlSurfaceDamageBuffer( - struct wl_surface *wl_surface, - int32_t x, - int32_t y, - int32_t width, + struct wl_surface *wl_surface, + int32_t x, + int32_t y, + int32_t width, int32_t height) { s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_surface, - WL_SURFACE_DAMAGE_BUFFER, - NULL, + WL_SURFACE_DAMAGE_BUFFER, + NULL, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0, - x, - y, - width, + (struct wl_proxy *) wl_surface), + 0, + x, + y, + width, height); } static inline int wlSurfaceAddListener( struct wl_surface *wl_surface, - const struct wl_surface_listener *listener, + const struct wl_surface_listener *listener, void *data) { return s_Wl.proxyAddListener( @@ -1273,7 +1273,7 @@ static inline int wlSurfaceAddListener( static inline int wlSeatAddListener( struct wl_seat *wl_seat, - const struct wl_seat_listener *listener, + const struct wl_seat_listener *listener, void *data) { return s_Wl.proxyAddListener( @@ -1286,11 +1286,11 @@ static inline struct wl_pointer* wlSeatGetPointer(struct wl_seat *wl_seat) struct wl_proxy *id; id = s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_seat, - WL_SEAT_GET_POINTER, - s_Wl.pointerInterface, + WL_SEAT_GET_POINTER, + s_Wl.pointerInterface, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_seat), - 0, + (struct wl_proxy *) wl_seat), + 0, NULL); return (struct wl_pointer *) id; @@ -1301,11 +1301,11 @@ static inline struct wl_keyboard* wlSeatGetKeyboard(struct wl_seat *wl_seat) struct wl_proxy *id; id = s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_seat, - WL_SEAT_GET_KEYBOARD, - s_Wl.keyboardInterface, + WL_SEAT_GET_KEYBOARD, + s_Wl.keyboardInterface, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_seat), - 0, + (struct wl_proxy *) wl_seat), + 0, NULL); return (struct wl_keyboard *) id; @@ -1313,7 +1313,7 @@ static inline struct wl_keyboard* wlSeatGetKeyboard(struct wl_seat *wl_seat) static inline int wlPointerAddListener( struct wl_pointer *wl_pointer, - const struct wl_pointer_listener *listener, + const struct wl_pointer_listener *listener, void *data) { return s_Wl.proxyAddListener( @@ -1322,28 +1322,28 @@ static inline int wlPointerAddListener( } static inline void wlPointerSetCursor( - struct wl_pointer *wl_pointer, - uint32_t serial, - struct wl_surface *surface, - int32_t hotspot_x, + struct wl_pointer *wl_pointer, + uint32_t serial, + struct wl_surface *surface, + int32_t hotspot_x, int32_t hotspot_y) { s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_pointer, - WL_POINTER_SET_CURSOR, - NULL, + WL_POINTER_SET_CURSOR, + NULL, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_pointer), - 0, - serial, - surface, - hotspot_x, + (struct wl_proxy *) wl_pointer), + 0, + serial, + surface, + hotspot_x, hotspot_y); } static inline int wlKeyboardAddListener( struct wl_keyboard *wl_keyboard, - const struct wl_keyboard_listener *listener, + const struct wl_keyboard_listener *listener, void *data) { return s_Wl.proxyAddListener( @@ -1357,47 +1357,47 @@ static inline struct wl_region* wlCompositorCreateRegion( struct wl_proxy *id; id = s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_compositor, - WL_COMPOSITOR_CREATE_REGION, - s_Wl.regionInterface, + WL_COMPOSITOR_CREATE_REGION, + s_Wl.regionInterface, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_compositor), - 0, + (struct wl_proxy *) wl_compositor), + 0, NULL); return (struct wl_region *) id; } static inline void wlRegionAdd( - struct wl_region *wl_region, - int32_t x, - int32_t y, - int32_t width, + struct wl_region *wl_region, + int32_t x, + int32_t y, + int32_t width, int32_t height) { s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_region, - WL_REGION_ADD, - NULL, + WL_REGION_ADD, + NULL, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_region), - 0, - x, - y, - width, + (struct wl_proxy *) wl_region), + 0, + x, + y, + width, height); } static inline void wlSurfaceSetOpaqueRegion( - struct wl_surface *wl_surface, + struct wl_surface *wl_surface, struct wl_region *region) { s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_surface, - WL_SURFACE_SET_OPAQUE_REGION, - NULL, + WL_SURFACE_SET_OPAQUE_REGION, + NULL, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0, + (struct wl_proxy *) wl_surface), + 0, region); } @@ -1405,10 +1405,10 @@ static inline void wlRegionDestroy(struct wl_region *wl_region) { s_Wl.proxyMarshalFlags( (struct wl_proxy *) wl_region, - WL_REGION_DESTROY, - NULL, + WL_REGION_DESTROY, + NULL, s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_region), + (struct wl_proxy *) wl_region), WL_MARSHAL_FLAG_DESTROY); } @@ -1456,11 +1456,11 @@ static void surfaceHandleEnter( if (data->dpi == 0) { // this is triggered when the window is created // we cache the DPI and skip the event - data->dpi = monitorData->dpi; + data->dpi = monitorData->dpi; return; } - // the code below should be skipped if users are not + // the code below should be skipped if users are not // interested in DPI changed events PalDispatchMode mode = PAL_DISPATCH_NONE; PalEventType type = PAL_EVENT_MONITOR_DPI_CHANGED; @@ -1545,10 +1545,10 @@ static void pointerHandleEnter( // our window WaylandCursor* cursor = data->cursor; wlPointerSetCursor( - pointer, - serial, + pointer, + serial, cursor->surface, - cursor->hotspotX, + cursor->hotspotX, cursor->hotspotY); } @@ -1628,7 +1628,7 @@ static void pointerHandleButton( // cannot recieve events without a focused surface return; } - + bool pressed = state == WL_POINTER_BUTTON_STATE_PRESSED; PalMouseButton _button = 0; PalEventType type = PAL_EVENT_MOUSE_BUTTONUP; @@ -1688,7 +1688,7 @@ static void pointerHandleAxis( s_Mouse.tmpScrollY += delta; s_Mouse.accumScrollY += delta; } - + s_Mouse.pendingScroll = true; } @@ -1706,7 +1706,7 @@ static void pointerHandleAxisDiscrete( s_Mouse.tmpScrollY += discrete; s_Mouse.accumScrollY += discrete; } - + s_Mouse.pendingScroll = true; } @@ -1765,7 +1765,7 @@ static void pointerHandleAxisStop( uint32_t time, uint32_t axis) { - + } static void keyboardHandleEnter( @@ -1873,7 +1873,7 @@ static void keyboardHandleKey( scancode = PAL_SCANCODE_UP; } else if (key == 102) { scancode = PAL_SCANCODE_HOME; - + } else { scancode = s_Keyboard.scancodes[key]; } @@ -2035,7 +2035,7 @@ static void seatHandleName( struct wl_seat* seat, const char* name) { - + } static struct wl_seat_listener seatListener = { @@ -3044,8 +3044,8 @@ static PalResult glxBackend(const int index) int count = 0; GLXFBConfig* configs = s_X11.glxGetFBConfigs( - s_X11.display, - s_X11.screen, + s_X11.display, + s_X11.screen, &count); GLXFBConfig fbConfig = configs[index]; @@ -3055,7 +3055,7 @@ static PalResult glxBackend(const int index) // get a matching visual XVisualInfo* visualInfo = s_X11.glxGetVisualFromFBConfig( - s_X11.display, + s_X11.display, fbConfig); if (!visualInfo) { @@ -3067,7 +3067,7 @@ static PalResult glxBackend(const int index) } static PalResult eglXBackend(int index) -{ +{ // user choose EGL FBConfig backend if (!s_Egl.handle) { palSetLastPlatformError(errno); @@ -3110,9 +3110,9 @@ static PalResult eglXBackend(int index) // clang-format off // get a matching visual info XVisualInfo* visualInfo = s_X11.getVisualInfo( - s_X11.display, - VisualIDMask, - &tmp, + s_X11.display, + VisualIDMask, + &tmp, &numVisuals); // clang-format on @@ -3513,301 +3513,301 @@ static PalResult xInitVideo() // load procs s_X11.openDisplay = (XOpenDisplayFn)dlsym( - s_X11.handle, + s_X11.handle, "XOpenDisplay"); s_X11.closeDisplay = (XCloseDisplayFn)dlsym( - s_X11.handle, + s_X11.handle, "XCloseDisplay"); s_X11.getWindowAttributes = (XGetWindowAttributesFn)dlsym( - s_X11.handle, + s_X11.handle, "XGetWindowAttributes"); s_X11.setCrtcConfig = (XRRSetCrtcConfigFn)dlsym( - s_X11.handle, + s_X11.handle, "XRRSetCrtcConfig"); s_X11.getWindowProperty = (XGetWindowPropertyFn)dlsym( - s_X11.handle, + s_X11.handle, "XGetWindowProperty"); s_X11.internAtom = (XInternAtomFn)dlsym( - s_X11.handle, + s_X11.handle, "XInternAtom"); s_X11.getSelectionOwner = (XGetSelectionOwnerFn)dlsym( - s_X11.handle, + s_X11.handle, "XGetSelectionOwner"); s_X11.freeColormap = (XFreeColormapFn)dlsym( - s_X11.handle, + s_X11.handle, "XFreeColormap"); s_X11.storeName = (XStoreNameFn)dlsym( - s_X11.handle, + s_X11.handle, "XStoreName"); s_X11.changeProperty = (XChangePropertyFn)dlsym( - s_X11.handle, + s_X11.handle, "XChangeProperty"); s_X11.flush = (XFlushFn)dlsym( - s_X11.handle, + s_X11.handle, "XFlush"); s_X11.createColormap = (XCreateColormapFn)dlsym( - s_X11.handle, + s_X11.handle, "XCreateColormap"); s_X11.mapWindow = (XMapWindowFn)dlsym( - s_X11.handle, + s_X11.handle, "XMapWindow"); s_X11.unmapWindow = (XUnmapWindowFn)dlsym( - s_X11.handle, + s_X11.handle, "XUnmapWindow"); s_X11.createWindow = (XCreateWindowFn)dlsym( - s_X11.handle, + s_X11.handle, "XCreateWindow"); - + s_X11.destroyWindow = (XDestroyWindowFn)dlsym( - s_X11.handle, + s_X11.handle, "XDestroyWindow"); s_X11.matchVisualInfo = (XMatchVisualInfoFn)dlsym( - s_X11.handle, + s_X11.handle, "XMatchVisualInfo"); s_X11.pending = (XPendingFn)dlsym( - s_X11.handle, + s_X11.handle, "XPending"); s_X11.setWMProtocols = (XSetWMProtocolsFn)dlsym( - s_X11.handle, + s_X11.handle, "XSetWMProtocols"); s_X11.nextEvent = (XNextEventFn)dlsym( - s_X11.handle, + s_X11.handle, "XNextEvent"); s_X11.setWMNormalHints = (XSetWMNormalHintsFn)dlsym( - s_X11.handle, + s_X11.handle, "XSetWMNormalHints"); s_X11.getWMNormalHints = (XGetWMNormalHintsFn)dlsym( - s_X11.handle, + s_X11.handle, "XGetWMNormalHints"); s_X11.sendEvent = (XSendEventFn)dlsym( - s_X11.handle, + s_X11.handle, "XSendEvent"); s_X11.moveWindow = (XMoveWindowFn)dlsym( - s_X11.handle, + s_X11.handle, "XMoveWindow"); s_X11.resizeWindow = (XResizeWindowFn)dlsym( - s_X11.handle, + s_X11.handle, "XResizeWindow"); s_X11.iconifyWindow = (XIconifyWindowFn)dlsym( - s_X11.handle, + s_X11.handle, "XIconifyWindow"); s_X11.setErrorHandler = (XSetErrorHandlerFn)dlsym( - s_X11.handle, + s_X11.handle, "XSetErrorHandler"); s_X11.sync = (XSyncFn)dlsym( - s_X11.handle, + s_X11.handle, "XSync"); s_X11.saveContext = (XSaveContextFn)dlsym( - s_X11.handle, + s_X11.handle, "XSaveContext"); s_X11.findContext = (XFindContextFn)dlsym( - s_X11.handle, + s_X11.handle, "XFindContext"); s_X11.uniqueContext = (XrmUniqueQuarkFn)dlsym( - s_X11.handle, + s_X11.handle, "XrmUniqueQuark"); // load Xrandr functions s_X11.getScreenResources = (XRRGetScreenResourcesFn)dlsym( - s_X11.xrandr, + s_X11.xrandr, "XRRGetScreenResources"); s_X11.getOutputPrimary = (XRRGetOutputPrimaryFn)dlsym( - s_X11.xrandr, + s_X11.xrandr, "XRRGetOutputPrimary"); s_X11.getOutputInfo = (XRRGetOutputInfoFn)dlsym( - s_X11.xrandr, + s_X11.xrandr, "XRRGetOutputInfo"); - + s_X11.getCrtcInfo = (XRRGetCrtcInfoFn)dlsym( - s_X11.xrandr, + s_X11.xrandr, "XRRGetCrtcInfo"); - + s_X11.freeScreenResources = (XRRFreeScreenResourcesFn)dlsym( - s_X11.xrandr, + s_X11.xrandr, "XRRFreeScreenResources"); - + s_X11.freeOutputInfo = (XRRFreeOutputInfoFn)dlsym( - s_X11.xrandr, + s_X11.xrandr, "XRRFreeScreenResources"); - + s_X11.freeCrtcInfo = (XRRFreeCrtcInfoFn)dlsym( - s_X11.xrandr, + s_X11.xrandr, "XRRFreeCrtcInfo"); s_X11.selectRRInput = (XRRSelectInputFn)dlsym( - s_X11.xrandr, + s_X11.xrandr, "XRRSelectInput"); s_X11.queryRRExtension = (XRRQueryExtensionFn)dlsym( - s_X11.xrandr, + s_X11.xrandr, "XRRQueryExtension"); s_X11.allocClassHint = (XAllocClassHintFn)dlsym( - s_X11.handle, + s_X11.handle, "XAllocClassHint"); s_X11.setClassHint = (XSetClassHintFn)dlsym( - s_X11.handle, + s_X11.handle, "XSetClassHint"); s_X11.free = (XFreeFn)dlsym( - s_X11.handle, + s_X11.handle, "XFree"); s_X11.getVisualInfo = (XGetVisualInfoFn)dlsym( - s_X11.handle, + s_X11.handle, "XGetVisualInfo"); s_X11.createFontCursor = (XCreateFontCursorFn)dlsym( - s_X11.handle, + s_X11.handle, "XCreateFontCursor"); - + s_X11.freePixmap = (XFreePixmapFn)dlsym( - s_X11.handle, + s_X11.handle, "XFreePixmap"); s_X11.setWMHints = (XSetWMHintsFn)dlsym( - s_X11.handle, + s_X11.handle, "XSetWMHints"); s_X11.grabPointer = (XGrabPointerFn)dlsym( - s_X11.handle, + s_X11.handle, "XGrabPointer"); s_X11.createPixmapCursor = (XCreatePixmapCursorFn)dlsym( - s_X11.handle, + s_X11.handle, "XCreatePixmapCursor"); s_X11.warpPointer = (XWarpPointerFn)dlsym( - s_X11.handle, + s_X11.handle, "XWarpPointer"); s_X11.getWMName = (XGetWMNameFn)dlsym( - s_X11.handle, + s_X11.handle, "XGetWMName"); s_X11.queryPointer = (XQueryPointerFn)dlsym( - s_X11.handle, + s_X11.handle, "XQueryPointer"); s_X11.ungrabPointer = (XUngrabPointerFn)dlsym( - s_X11.handle, + s_X11.handle, "XUngrabPointer"); s_X11.allocWMHints = (XAllocWMHintsFn)dlsym( - s_X11.handle, + s_X11.handle, "XAllocWMHints"); s_X11.mapRaised = (XMapRaisedFn)dlsym( - s_X11.handle, + s_X11.handle, "XMapRaised"); s_X11.undefineCursor = (XUndefineCursorFn)dlsym( - s_X11.handle, + s_X11.handle, "XUndefineCursor"); s_X11.defineCursor = (XDefineCursorFn)dlsym( - s_X11.handle, + s_X11.handle, "XDefineCursor"); s_X11.freeCursor = (XFreeCursorFn)dlsym( - s_X11.handle, + s_X11.handle, "XFreeCursor"); s_X11.getWMHints = (XGetWMHintsFn)dlsym( - s_X11.handle, + s_X11.handle, "XGetWMHints"); s_X11.createPixmap = (XCreatePixmapFn)dlsym( - s_X11.handle, + s_X11.handle, "XCreatePixmap"); s_X11.setInputFocus = (XSetInputFocusFn)dlsym( - s_X11.handle, + s_X11.handle, "XSetInputFocus"); s_X11.getInputFocus = (XGetInputFocusFn)dlsym( - s_X11.handle, + s_X11.handle, "XGetInputFocus"); s_X11.selectInput = (XSelectInputFn)dlsym( - s_X11.handle, + s_X11.handle, "XSelectInput"); // libXcursor s_X11.cursorImageLoadCursor = (XcursorImageLoadCursorFn)dlsym( - s_X11.libCursor, + s_X11.libCursor, "XcursorImageLoadCursor"); s_X11.cursorImageCreate = (XcursorImageCreateFn)dlsym( - s_X11.libCursor, + s_X11.libCursor, "XcursorImageCreate"); s_X11.cursorImageDestroy = (XcursorImageDestroyFn)dlsym( - s_X11.libCursor, + s_X11.libCursor, "XcursorImageDestroy"); s_X11.lookupKeysym = (XLookupKeysymFn)dlsym( - s_X11.libCursor, + s_X11.libCursor, "XLookupKeysym"); s_X11.setDetectableAutoRepeat = (XkbSetDetectableAutoRepeatFn)dlsym( - s_X11.handle, + s_X11.handle, "XkbSetDetectableAutoRepeat"); s_X11.setLocaleModifiers = (XSetLocaleModifiersFn)dlsym( - s_X11.handle, + s_X11.handle, "XSetLocaleModifiers"); s_X11.openIM = (XOpenIMFn)dlsym( - s_X11.handle, + s_X11.handle, "XOpenIM"); s_X11.closeIM = (XCloseIMFn)dlsym( - s_X11.handle, + s_X11.handle, "XCloseIM"); s_X11.createIC = (XCreateICFn)dlsym( - s_X11.handle, + s_X11.handle, "XCreateIC"); s_X11.destroyIC = (XDestroyICFn)dlsym( - s_X11.handle, + s_X11.handle, "XDestroyIC"); s_X11.utf8LookupString = (Xutf8LookupStringFn)dlsym( - s_X11.handle, + s_X11.handle, "Xutf8LookupString"); // X11 server @@ -3828,11 +3828,11 @@ static PalResult xInitVideo() s_X11.screen = DefaultScreen(s_X11.display); xCheckFeatures(); - + // subscribe for monitor events s_X11.selectRRInput( - s_X11.display, - s_X11.root, + s_X11.display, + s_X11.root, RRScreenChangeNotifyMask | RRNotify); int eventBase, errorBase = 0; @@ -3915,7 +3915,7 @@ PalResult xSetFBConfig( if (backend == PAL_CONFIG_BACKEND_GLX) { return glxBackend(index); - } else if (backend == PAL_CONFIG_BACKEND_EGL || + } else if (backend == PAL_CONFIG_BACKEND_EGL || backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { return eglXBackend(index); @@ -4155,7 +4155,7 @@ static void xUpdateVideo() } break; } - + case MotionNotify: { // mouse moved const int x = event.xmotion.x; @@ -4366,17 +4366,17 @@ static void xUpdateVideo() } else if ((ch >> 4) == 0xE && len >= 3) { // 3 byte // clang-format off - codepoint = ((ch & 0x0F) << 12) | - ((buffer[1] & 0x3F) << 6) | + codepoint = ((ch & 0x0F) << 12) | + ((buffer[1] & 0x3F) << 6) | (buffer[2] & 0x3F); // clang-format on } else if ((ch >> 3) == 0x1E && len >= 4) { // 4 byte // clang-format off - codepoint = ((ch & 0x07) << 18) | - ((buffer[1] & 0x3F) << 12) | - ((buffer[2] & 0x3F) << 6) | + codepoint = ((ch & 0x07) << 18) | + ((buffer[1] & 0x3F) << 12) | + ((buffer[2] & 0x3F) << 6) | (buffer[3] & 0x3F); // clang-format on } @@ -4861,11 +4861,11 @@ static PalResult xCreateWindow( borderPixel = 0; // clang-format off - + colormap = s_X11.createColormap( - s_X11.display, - s_X11.root, - visual, + s_X11.display, + s_X11.root, + visual, AllocNone); // clang-format on @@ -4933,8 +4933,8 @@ static PalResult xCreateWindow( // clang-format off XRRCrtcInfo* crtc = s_X11.getCrtcInfo( - s_X11.display, - resources, + s_X11.display, + resources, outputInfo->crtc); // clang-format on @@ -5778,7 +5778,7 @@ PalResult xCreateIcon( Uint8 a = info->pixels[i * 4 + 3]; // Alpha // clang-format off - icon[2 + i] = ((unsigned long)a << 24) | + icon[2 + i] = ((unsigned long)a << 24) | ((unsigned long)r << 16) | ((unsigned long)g << 8) | ((unsigned long)b); @@ -5839,7 +5839,7 @@ PalResult xCreateCursor( Uint8 a = info->pixels[i * 4 + 3]; // Alpha // clang-format off - image->pixels[i] = ((unsigned long)a << 24) | + image->pixels[i] = ((unsigned long)a << 24) | ((unsigned long)r << 16) | ((unsigned long)g << 8) | ((unsigned long)b); @@ -6300,7 +6300,7 @@ static struct wl_buffer* createShmBuffer( Uint8 a = pixels[i * 4 + 3]; // Alpha // clang-format off - dataPixels[i] = ((unsigned long)a << 24) | + dataPixels[i] = ((unsigned long)a << 24) | ((unsigned long)r << 16) | ((unsigned long)g << 8) | ((unsigned long)b); @@ -6533,9 +6533,9 @@ PalResult wlInitVideo() s_Wl.libWaylandEgl = dlopen("libwayland-egl.so", RTLD_LAZY); // clang-format off - if (!s_Wl.handle || - !s_Wl.xkbCommon || - !s_Wl.libCursor || + if (!s_Wl.handle || + !s_Wl.xkbCommon || + !s_Wl.libCursor || !s_Wl.libWaylandEgl) { palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; @@ -6556,134 +6556,134 @@ PalResult wlInitVideo() // load function procs s_Wl.displayConnect = (wl_display_connect_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_connect"); s_Wl.displayDisconnect = (wl_display_disconnect_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_disconnect"); s_Wl.displayRoundtrip = (wl_display_roundtrip_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_roundtrip"); s_Wl.displayDispatch = (wl_display_dispatch_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_dispatch"); s_Wl.proxyAddListener = (wl_proxy_add_listener_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_proxy_add_listener"); s_Wl.proxyMarshalCnstructor = (wl_proxy_marshal_constructor_v_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_proxy_marshal_constructor_versioned"); s_Wl.proxyDestroy = (wl_proxy_destroy_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_proxy_destroy"); s_Wl.proxyMarshalFlags = (wl_proxy_marshal_flags_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_proxy_marshal_flags"); s_Wl.proxyGetVersion = (wl_proxy_get_version_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_proxy_get_version"); s_Wl.getError = (wl_display_get_error_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_get_error"); s_Wl.dispatchPending = (wl_display_dispatch_pending_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_dispatch_pending"); s_Wl.displayFlush = (wl_display_flush_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_flush"); s_Wl.prepareRead = (wl_display_prepare_read_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_prepare_read"); s_Wl.readEvents = (wl_display_read_events_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_read_events"); s_Wl.displayGetFd = (wl_display_get_fd_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_get_fd"); s_Wl.cancelRead = (wl_display_cancel_read_fn)dlsym( - s_Wl.handle, + s_Wl.handle, "wl_display_cancel_read"); // load xkbcommon procs s_Wl.xkbKeymapUnref = (xkb_keymap_unref_fn)dlsym( - s_Wl.xkbCommon, + s_Wl.xkbCommon, "xkb_keymap_unref"); s_Wl.xkbStateKeyGetOneSym = (xkb_state_key_get_one_sym_fn)dlsym( - s_Wl.xkbCommon, + s_Wl.xkbCommon, "xkb_state_key_get_one_sym"); s_Wl.xkbStateNew = (xkb_state_new_fn)dlsym( - s_Wl.xkbCommon, + s_Wl.xkbCommon, "xkb_state_new"); s_Wl.xkbStateUnref = (xkb_state_unref_fn)dlsym( - s_Wl.xkbCommon, + s_Wl.xkbCommon, "xkb_state_unref"); s_Wl.xkbContextUnref = (xkb_context_unref_fn)dlsym( - s_Wl.xkbCommon, + s_Wl.xkbCommon, "xkb_context_unref"); s_Wl.xkbContextNew = (xkb_context_new_fn)dlsym( - s_Wl.xkbCommon, + s_Wl.xkbCommon, "xkb_context_new"); s_Wl.xkbKeymapNewFromString = (xkb_keymap_new_from_string_fn)dlsym( - s_Wl.xkbCommon, + s_Wl.xkbCommon, "xkb_keymap_new_from_string"); s_Wl.xkbKeysymToUtf32 = (xkb_keysym_to_utf32_fn)dlsym( - s_Wl.xkbCommon, + s_Wl.xkbCommon, "xkb_keysym_to_utf32"); s_Wl.xkbStateUpdateMask = (xkb_state_update_mask_fn)dlsym( - s_Wl.xkbCommon, + s_Wl.xkbCommon, "xkb_state_update_mask"); s_Wl.xkbKeymapKeyRepeats = (xkb_keymap_key_repeats_fn)dlsym( - s_Wl.xkbCommon, + s_Wl.xkbCommon, "xkb_keymap_key_repeats"); // load wayland cursor procs s_Wl.cursorImageGetBuffer = (wl_cursor_image_get_buffer_fn)dlsym( - s_Wl.libCursor, + s_Wl.libCursor, "wl_cursor_image_get_buffer"); s_Wl.cursorThemeLoad = (wl_cursor_theme_load_fn)dlsym( - s_Wl.libCursor, + s_Wl.libCursor, "wl_cursor_theme_load"); s_Wl.cursorThemeGetCursor = (wl_cursor_theme_get_cursor_fn)dlsym( - s_Wl.libCursor, + s_Wl.libCursor, "wl_cursor_theme_get_cursor"); // wl_egl procs s_Wl.eglWindowCreate = (wl_egl_window_create_fn)dlsym( - s_Wl.libWaylandEgl, + s_Wl.libWaylandEgl, "wl_egl_window_create"); s_Wl.eglWindowDestroy = (wl_egl_window_destroy_fn)dlsym( - s_Wl.libWaylandEgl, + s_Wl.libWaylandEgl, "wl_egl_window_destroy"); s_Wl.eglWindowResize = (wl_egl_window_resize_fn)dlsym( - s_Wl.libWaylandEgl, + s_Wl.libWaylandEgl, "wl_egl_window_resize"); // clang-format on @@ -8030,9 +8030,9 @@ PalResult PAL_CALL palGetWindowTitle( // clang-format off return s_Video.backend->getWindowTitle( - window, - bufferSize, - outSize, + window, + bufferSize, + outSize, outBuffer); // clang-format on } @@ -8492,4 +8492,4 @@ void PAL_CALL palSetPreferredInstance(void* instance) if (!s_Video.initialized && instance) { s_Video.platformInstance = instance; } -} \ No newline at end of file +} diff --git a/src/video/pal_video_win32.c b/src/video/pal_video_win32.c index 2c1dce80..38bff6fa 100644 --- a/src/video/pal_video_win32.c +++ b/src/video/pal_video_win32.c @@ -527,9 +527,9 @@ LRESULT CALLBACK videoProc( // clang-format off // check if we pressed or released the button - if (msg == WM_LBUTTONDOWN || + if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || - msg == WM_MBUTTONDOWN || + msg == WM_MBUTTONDOWN || msg == WM_XBUTTONDOWN) { pressed = true; type = PAL_EVENT_MOUSE_BUTTONDOWN; @@ -821,8 +821,8 @@ static inline bool compareMonitorMode( // clang-format off - return a->bpp == b->bpp && - a->width == b->width && + return a->bpp == b->bpp && + a->width == b->width && a->height == b->height && a->refreshRate == b->refreshRate; @@ -1160,15 +1160,15 @@ PalResult PAL_CALL palInitVideo( s_Video.gdi = LoadLibraryA("gdi32.dll"); if (s_Video.gdi) { s_Video.createDIBSection = (CreateDIBSectionFn)GetProcAddress( - s_Video.gdi, + s_Video.gdi, "CreateDIBSection"); s_Video.createBitmap = (CreateBitmapFn)GetProcAddress( - s_Video.gdi, + s_Video.gdi, "CreateBitmap"); s_Video.deleteObject = (DeleteObjectFn)GetProcAddress( - s_Video.gdi, + s_Video.gdi, "DeleteObject"); s_Video.describePixelFormat = (DescribePixelFormatFn)GetProcAddress( @@ -1176,7 +1176,7 @@ PalResult PAL_CALL palInitVideo( "DescribePixelFormat"); s_Video.setPixelFormat = (SetPixelFormatFn)GetProcAddress( - s_Video.gdi, + s_Video.gdi, "SetPixelFormat"); } @@ -1677,10 +1677,10 @@ PalResult PAL_CALL palSetMonitorOrientation( // clang-format off // only swap size if switching between landscape and portrait - bool isMonitorLandscape = (monitorOrientation == DMDO_DEFAULT || + bool isMonitorLandscape = (monitorOrientation == DMDO_DEFAULT || monitorOrientation == DMDO_180); - bool isLandscape = (win32Orientation == DMDO_DEFAULT || + bool isLandscape = (win32Orientation == DMDO_DEFAULT || win32Orientation == DMDO_180); if (isMonitorLandscape != isLandscape) { @@ -1693,10 +1693,10 @@ PalResult PAL_CALL palSetMonitorOrientation( devMode.dmDisplayOrientation = win32Orientation; ULONG result = ChangeDisplaySettingsExW( - mi.szDevice, - &devMode, - NULL, - CDS_RESET, + mi.szDevice, + &devMode, + NULL, + CDS_RESET, NULL); // clang-format on @@ -3114,4 +3114,4 @@ void PAL_CALL palSetPreferredInstance(void* instance) if (!s_Video.initialized && instance) { s_Video.instance = instance; } -} \ No newline at end of file +} diff --git a/tests/attach_window_test.c b/tests/attach_window_test.c index 25e0e924..65bc0567 100644 --- a/tests/attach_window_test.c +++ b/tests/attach_window_test.c @@ -73,19 +73,19 @@ static void* createX11Window() // clang-format off s_XCreateWindow = (XCreateSimpleWindowFn)dlsym( - s_LibX, + s_LibX, "XCreateSimpleWindow"); - + s_XSync = (XSyncFn)dlsym( - s_LibX, + s_LibX, "XSync"); s_XMapRaised = (XMapRaisedFn)dlsym( - s_LibX, + s_LibX, "XMapRaised"); s_XDestroyWindow = (XDestroyWindowFn)dlsym( - s_LibX, + s_LibX, "XDestroyWindow"); if (!s_XCreateWindow || !s_XSync || !s_XMapRaised || !s_XDestroyWindow) { @@ -102,11 +102,11 @@ static void* createX11Window() Window root = RootWindow(display, screen); Window window = s_XCreateWindow( - display, - root, - WINDOW_POSX, - WINDOW_POSX, - WINDOW_WIDTH, + display, + root, + WINDOW_POSX, + WINDOW_POSX, + WINDOW_WIDTH, WINDOW_HEIGHT, 1, BlackPixel(display, screen), @@ -385,4 +385,4 @@ bool attachWindowTest() palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/char_event_test.c b/tests/char_event_test.c index ea34b916..5f50641e 100644 --- a/tests/char_event_test.c +++ b/tests/char_event_test.c @@ -124,4 +124,4 @@ bool charEventTest() palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 63e8ff66..a38bf07f 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -50,13 +50,13 @@ bool clearColorTest() } palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, + eventDriver, + PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode( - eventDriver, - PAL_EVENT_KEYDOWN, + eventDriver, + PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); result = palInitVideo(nullptr, eventDriver); @@ -148,11 +148,11 @@ bool clearColorTest() palFree(nullptr, adapters); if (!adapter) { - palLog(nullptr, + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); return false; } - + // create a device PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; @@ -183,8 +183,8 @@ bool clearColorTest() // create a swapchain with the graphics queue PalSwapchainCapabilities swapchainCaps = {0}; result = palQuerySwapchainCapabilities( - device, - &gfxWindow, + device, + &gfxWindow, &swapchainCaps); if (result != PAL_RESULT_SUCCESS) { @@ -210,16 +210,16 @@ bool clearColorTest() swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; } - // check if the minimal image count is not good for you + // check if the minimal image count is not good for you // and increase it but not pass the max count swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; result = palCreateSwapchain( - device, - queue, - &gfxWindow, - &swapchainCreateInfo, + device, + queue, + &gfxWindow, + &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { @@ -231,12 +231,12 @@ bool clearColorTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate( - nullptr, + nullptr, sizeof(PalImageView*) * imageCount, 0); renderFinishedSemaphores = palAllocate( - nullptr, + nullptr, sizeof(PalSemaphore*) * imageCount, 0); @@ -262,9 +262,9 @@ bool clearColorTest() } result = palCreateImageView( - device, - image, - &imageViewCreateInfo, + device, + image, + &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { @@ -302,9 +302,9 @@ bool clearColorTest() } result = palCreateCommandBuffer( - device, - cmdPool, - PAL_COMMAND_BUFFER_TYPE_PRIMARY, + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, &cmdBuffers[i]); if (result != PAL_RESULT_SUCCESS) { @@ -380,7 +380,7 @@ bool clearColorTest() } else { // recreate since we dont support fence resetting palDestroyFence(fence); - + result = palCreateFence(device, false, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -450,9 +450,9 @@ bool clearColorTest() } result = palImageViewBarrier( - cmdBuffer, - imageViews[index], - oldUsageState, + cmdBuffer, + imageViews[index], + oldUsageState, PAL_USAGE_STATE_COLOR_ATTACHMENT); if (result != PAL_RESULT_SUCCESS) { @@ -477,11 +477,11 @@ bool clearColorTest() // change the state of the image view to make it presentable result = palImageViewBarrier( - cmdBuffer, - imageViews[index], - PAL_USAGE_STATE_COLOR_ATTACHMENT, + cmdBuffer, + imageViews[index], + PAL_USAGE_STATE_COLOR_ATTACHMENT, PAL_USAGE_STATE_PRESENT); - + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); @@ -542,7 +542,7 @@ bool clearColorTest() } palDestroyCommandPool(cmdPool); - palDestroySwapchain(swapchain); + palDestroySwapchain(swapchain); palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); @@ -552,4 +552,4 @@ bool clearColorTest() palShutdownVideo(); palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/condvar_test.c b/tests/condvar_test.c index 266b7078..cc79c7cd 100644 --- a/tests/condvar_test.c +++ b/tests/condvar_test.c @@ -119,4 +119,4 @@ bool condvarTest() palFree(nullptr, data); return true; -} \ No newline at end of file +} diff --git a/tests/cursor_test.c b/tests/cursor_test.c index 59620be1..b3e684f6 100644 --- a/tests/cursor_test.c +++ b/tests/cursor_test.c @@ -163,4 +163,4 @@ bool cursorTest() palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/custom_decoration_test.c b/tests/custom_decoration_test.c index d0965cb3..bd7d4590 100644 --- a/tests/custom_decoration_test.c +++ b/tests/custom_decoration_test.c @@ -448,31 +448,31 @@ static void openDisplayWayland() // clang-format off s_wl_display_connect = (wl_display_connect_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_display_connect"); s_wl_display_disconnect = (wl_display_disconnect_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_display_disconnect"); s_wl_display_roundtrip = (wl_display_roundtrip_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_display_roundtrip"); s_wl_proxy_marshal_flags = (wl_proxy_marshal_flags_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_proxy_marshal_flags"); s_wl_proxy_get_version = (wl_proxy_get_version_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_proxy_get_version"); s_wl_proxy_add_listener = (wl_proxy_add_listener_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_proxy_add_listener"); s_wl_proxy_destroy = (wl_proxy_destroy_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_proxy_destroy"); registryInterface = dlsym(s_LibWayland, "wl_registry_interface"); @@ -560,7 +560,7 @@ static struct wl_buffer* createShmBuffer( if (!buffer) { return nullptr; } - + wlShmPoolDestroy(pool); *outPixels = (Uint32*)data; @@ -570,13 +570,13 @@ static struct wl_buffer* createShmBuffer( } void fillRect( - uint32_t *pixels, - int stride, - int x, - int y, - int w, - int h, - uint32_t color) + uint32_t *pixels, + int stride, + int x, + int y, + int w, + int h, + uint32_t color) { for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { @@ -615,7 +615,7 @@ static const Uint8 s_FontBasic[128][8] = { ['X'] = {0x42,0x42,0x24,0x18,0x18,0x24,0x42,0x42}, ['Y'] = {0x42,0x42,0x24,0x18,0x08,0x08,0x08,0x08}, ['Z'] = {0x7E,0x02,0x04,0x08,0x10,0x20,0x40,0x7E}, - + ['a'] = {0x00,0x00,0x3C,0x02,0x3E,0x42,0x46,0x3A}, ['b'] = {0x40,0x40,0x5C,0x62,0x42,0x42,0x62,0x5C}, ['c'] = {0x00,0x00,0x3C,0x42,0x40,0x40,0x42,0x3C}, @@ -645,12 +645,12 @@ static const Uint8 s_FontBasic[128][8] = { }; void drawCharacter( - uint32_t *pixels, - int stride, - int x, - int y, - char c, - uint32_t color) + uint32_t *pixels, + int stride, + int x, + int y, + char c, + uint32_t color) { if (c < 0 || c > 127) return; // not in out font @@ -670,12 +670,12 @@ void drawCharacter( } void drawText( - uint32_t *pixels, - int stride, - int x, - int y, - const char *text, - uint32_t color) + uint32_t *pixels, + int stride, + int x, + int y, + const char *text, + uint32_t color) { while (*text) { drawCharacter(pixels, stride, x, y, *text, color); @@ -726,43 +726,43 @@ static void createDecoration() // write pixels // title bar color (dark grey) fillRect( - s_Decoration.pixels, - width, - 0, + s_Decoration.pixels, + width, + 0, 0, - width, - TITLEBAR_HEIGHT, + width, + TITLEBAR_HEIGHT, 0x002F3030); // Close button // this is just a rectangle for this simple example // to show CSD works with PAL fillRect( - s_Decoration.pixels, - width, - width - BUTTON_SIZE, - BUTTON_POSY, - BUTTON_SIZE, + s_Decoration.pixels, + width, + width - BUTTON_SIZE, + BUTTON_POSY, + BUTTON_SIZE, TITLEBAR_HEIGHT / 2, // half of the size of the title bar 0x00AA3333); // Maximize button fillRect( - s_Decoration.pixels, - width, - width - (BUTTON_OFFSET + BUTTON_SIZE), + s_Decoration.pixels, + width, + width - (BUTTON_OFFSET + BUTTON_SIZE), BUTTON_POSY, - BUTTON_SIZE, + BUTTON_SIZE, TITLEBAR_HEIGHT / 2, // half of the size of the title bar 0x0033AA33); // Minimize button fillRect( s_Decoration.pixels, - width, - width - (BUTTON_OFFSET * 2 + BUTTON_SIZE), + width, + width - (BUTTON_OFFSET * 2 + BUTTON_SIZE), BUTTON_POSY, - BUTTON_SIZE, + BUTTON_SIZE, TITLEBAR_HEIGHT / 2, // half of the size of the title bar 0x0033AAAA); @@ -780,11 +780,11 @@ static void createDecoration() int y = (TITLEBAR_HEIGHT - 8) / 2; drawText( - s_Decoration.pixels, - width, - x, - y, - WINDOW_TITLE, + s_Decoration.pixels, + width, + x, + y, + WINDOW_TITLE, 0x00FFFFFF); // set opaque regions for optimazation @@ -829,9 +829,9 @@ static void PAL_CALL onEvent( // we skip maximize and minimize button for simplicity // we just deal with the close button int buttonX = 640 - BUTTON_SIZE; - if (x >= buttonX && - x < buttonX + BUTTON_SIZE && - y >= BUTTON_POSY && + if (x >= buttonX && + x < buttonX + BUTTON_SIZE && + y >= BUTTON_POSY && y < BUTTON_POSY + BUTTON_SIZE) { // inside close button // trigger a window close event @@ -841,7 +841,7 @@ static void PAL_CALL onEvent( event.type = PAL_EVENT_WINDOW_CLOSE; palPushEvent(s_Decoration.driver, &event); } - } + } } else if (event->type == PAL_EVENT_MOUSE_MOVE) { Int32 x, y; @@ -861,7 +861,7 @@ bool customDecorationTest() palLog(nullptr, "Custom Decoration Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, + palLog(nullptr, "This only implements close and window movement for simplicity"); palLog(nullptr, "==========================================="); @@ -900,7 +900,7 @@ bool customDecorationTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - // we use PAL_DISPATCH_CALLBACK for the mouse button to get + // we use PAL_DISPATCH_CALLBACK for the mouse button to get // real time events which we then use for moving and resizing palSetEventDispatchMode( eventDriver, @@ -1004,11 +1004,11 @@ bool customDecorationTest() return true; } -#else +#else #include "tests.h" bool customDecorationTest() { return false; } -#endif // __linux__ \ No newline at end of file +#endif // __linux__ diff --git a/tests/device_test.c b/tests/device_test.c deleted file mode 100644 index c5413a90..00000000 --- a/tests/device_test.c +++ /dev/null @@ -1,111 +0,0 @@ - -#include "pal/pal_graphics.h" -#include "tests.h" - -bool deviceTest() -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Device Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - // initialize the graphics system - PalResult result = palInitGraphics(false, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; - } - - // enumerate all available adapters - Int32 count = 0; - result = palEnumerateAdapters(&count, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - if (count == 0) { - palLog(nullptr, "No adapters found"); - return false; - } - palLog(nullptr, "Adapter count: %d", count); - - // allocate an array of adapters or use a fixed array - // Example: PalAdapter* adapters[12]; - PalAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); - if (!adapters) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - result = palEnumerateAdapters(&count, adapters); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - // filter the adapters for Vulkan - PalAdapter* vulkanAdapter = nullptr; - PalAdapterInfo info = {0}; - - for (Int32 i = 0; i < count; i++) { - PalAdapter* adapter = adapters[i]; - result = palGetAdapterInfo(adapter, &info); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - palFree(nullptr, adapters); - return false; - } - - // check if its Vulkan - if (info.apiType == PAL_ADAPTER_API_TYPE_VULKAN) { - vulkanAdapter = adapter; - break; - } - } - - palFree(nullptr, adapters); - if (!vulkanAdapter) { - palLog(nullptr, "Failed to find a vulkan adapter"); - return false; - } - - // get capabilities about the adapter - PalAdapterCapabilities caps = {0}; - result = palGetAdapterCapabilities(vulkanAdapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); - return false; - } - - // create a device with the vulkan adapter - PalDevice* device = nullptr; - PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; - - // enable multi viewport if supported - if (caps.features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { - features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; - } - - result = palCreateDevice(vulkanAdapter, features, &device); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); - return false; - } - - // destroy the device - palDestroyDevice(device); - - // shutdown the graphics system - palShutdownGraphics(); - - return true; -} \ No newline at end of file diff --git a/tests/event_test.c b/tests/event_test.c index 2bd211a0..c913b2da 100644 --- a/tests/event_test.c +++ b/tests/event_test.c @@ -136,4 +136,4 @@ bool eventTest() palLog(nullptr, "Poll counter: %d", s_PollCounter); return true; -} \ No newline at end of file +} diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 014ca654..25894db7 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -10,7 +10,7 @@ bool graphicsTest() palLog(nullptr, "==========================================="); palLog(nullptr, ""); - // initialize the graphics system + // initialize the graphics system PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -307,6 +307,6 @@ bool graphicsTest() palShutdownGraphics(); palFree(nullptr, adapters); - + return true; -} \ No newline at end of file +} diff --git a/tests/icon_test.c b/tests/icon_test.c index 46829268..a3be2783 100644 --- a/tests/icon_test.c +++ b/tests/icon_test.c @@ -159,4 +159,4 @@ bool iconTest() palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/input_window_test.c b/tests/input_window_test.c index 0abbee3e..5500483f 100644 --- a/tests/input_window_test.c +++ b/tests/input_window_test.c @@ -566,4 +566,4 @@ bool inputWindowTest() palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/logger_test.c b/tests/logger_test.c index a5dc04e8..b3957369 100644 --- a/tests/logger_test.c +++ b/tests/logger_test.c @@ -5,9 +5,9 @@ // clang-format off static const char* g_LoggerNames[LOGGER_COUNT] = { - "Logger1", - "Logger2", - "Logger3", + "Logger1", + "Logger2", + "Logger3", "Logger4"}; // clang-format on @@ -45,4 +45,4 @@ bool loggerTest() } return true; -} \ No newline at end of file +} diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 086c151b..d0da47ee 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -19,7 +19,7 @@ static bool readFile(const char* filename, void* buffer, Uint64* size) if (buffer) { fread(buffer, 1, (size_t)size, file); } - + fclose(file); *size = tmpSize; return true; @@ -77,13 +77,13 @@ bool meshTest() } palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, + eventDriver, + PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode( - eventDriver, - PAL_EVENT_KEYDOWN, + eventDriver, + PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); result = palInitVideo(nullptr, eventDriver); @@ -175,18 +175,18 @@ bool meshTest() adapterFeatures = palGetAdapterFeatures(adapter); if (adapterFeatures & PAL_ADAPTER_FEATURE_MESH_SHADER) { break; - } + } } } palFree(nullptr, adapters); if (!adapter) { if (hasGfxQueue) { - palLog(nullptr, + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); } else { - palLog(nullptr, + palLog(nullptr, "Failed to find an adapter that supports mesh shader"); } return false; @@ -199,7 +199,7 @@ bool meshTest() palLog(nullptr, "Failed to get adapter info: %s", error); return false; } - + // create a device PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; features |= PAL_ADAPTER_FEATURE_MESH_SHADER; @@ -230,8 +230,8 @@ bool meshTest() // create a swapchain with the graphics queue PalSwapchainCapabilities swapchainCaps = {0}; result = palQuerySwapchainCapabilities( - device, - &gfxWindow, + device, + &gfxWindow, &swapchainCaps); if (result != PAL_RESULT_SUCCESS) { @@ -257,16 +257,16 @@ bool meshTest() swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; } - // check if the minimal image count is not good for you + // check if the minimal image count is not good for you // and increase it but not pass the max count swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; result = palCreateSwapchain( - device, - queue, - &gfxWindow, - &swapchainCreateInfo, + device, + queue, + &gfxWindow, + &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { @@ -278,12 +278,12 @@ bool meshTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate( - nullptr, + nullptr, sizeof(PalImageView*) * imageCount, 0); renderFinishedSemaphores = palAllocate( - nullptr, + nullptr, sizeof(PalSemaphore*) * imageCount, 0); @@ -309,9 +309,9 @@ bool meshTest() } result = palCreateImageView( - device, - image, - &imageViewCreateInfo, + device, + image, + &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { @@ -349,9 +349,9 @@ bool meshTest() } result = palCreateCommandBuffer( - device, - cmdPool, - PAL_COMMAND_BUFFER_TYPE_PRIMARY, + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, &cmdBuffers[i]); if (result != PAL_RESULT_SUCCESS) { @@ -400,8 +400,8 @@ bool meshTest() shaderCreateInfo.stage = PAL_SHADER_STAGE_MESH; result = palCreateShader( - device, - &shaderCreateInfo, + device, + &shaderCreateInfo, &meshShader); if (result != PAL_RESULT_SUCCESS) { @@ -432,8 +432,8 @@ bool meshTest() shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; result = palCreateShader( - device, - &shaderCreateInfo, + device, + &shaderCreateInfo, &fragmentShader); if (result != PAL_RESULT_SUCCESS) { @@ -447,8 +447,8 @@ bool meshTest() // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout( - device, - &pipelineLayoutCreateInfo, + device, + &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { @@ -506,7 +506,7 @@ bool meshTest() pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; result = palCreateGraphicsPipeline( - device, + device, &pipelineCreateInfo, &pipeline); @@ -515,7 +515,7 @@ bool meshTest() palLog(nullptr, "Failed to create graphics pipeline: %s", error); return false; } - + palDestroyShader(meshShader); palDestroyShader(fragmentShader); @@ -585,7 +585,7 @@ bool meshTest() } else { // recreate since we dont support fence resetting palDestroyFence(fence); - + result = palCreateFence(device, false, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -634,9 +634,9 @@ bool meshTest() } result = palImageViewBarrier( - cmdBuffer, - imageViews[index], - oldUsageState, + cmdBuffer, + imageViews[index], + oldUsageState, PAL_USAGE_STATE_COLOR_ATTACHMENT); if (result != PAL_RESULT_SUCCESS) { @@ -713,11 +713,11 @@ bool meshTest() // change the state of the image view to make it presentable result = palImageViewBarrier( - cmdBuffer, - imageViews[index], - PAL_USAGE_STATE_COLOR_ATTACHMENT, + cmdBuffer, + imageViews[index], + PAL_USAGE_STATE_COLOR_ATTACHMENT, PAL_USAGE_STATE_PRESENT); - + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); @@ -781,7 +781,7 @@ bool meshTest() } palDestroyCommandPool(cmdPool); - palDestroySwapchain(swapchain); + palDestroySwapchain(swapchain); palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); @@ -791,4 +791,4 @@ bool meshTest() palShutdownVideo(); palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/monitor_mode_test.c b/tests/monitor_mode_test.c index e67db812..bca2aad4 100644 --- a/tests/monitor_mode_test.c +++ b/tests/monitor_mode_test.c @@ -131,4 +131,4 @@ bool monitorModeTest() palFree(nullptr, monitors); return true; -} \ No newline at end of file +} diff --git a/tests/monitor_test.c b/tests/monitor_test.c index 6d65e608..cba992f9 100644 --- a/tests/monitor_test.c +++ b/tests/monitor_test.c @@ -108,4 +108,4 @@ bool monitorTest() palFree(nullptr, monitors); return true; -} \ No newline at end of file +} diff --git a/tests/multi_thread_opengl_test.c b/tests/multi_thread_opengl_test.c index 09501564..6f328690 100644 --- a/tests/multi_thread_opengl_test.c +++ b/tests/multi_thread_opengl_test.c @@ -465,4 +465,4 @@ bool multiThreadOpenGlTest() palFree(nullptr, fbConfigs); return true; -} \ No newline at end of file +} diff --git a/tests/mutex_test.c b/tests/mutex_test.c index 048d8aa0..b3c8114a 100644 --- a/tests/mutex_test.c +++ b/tests/mutex_test.c @@ -84,4 +84,4 @@ bool mutexTest() palFree(nullptr, data); return true; -} \ No newline at end of file +} diff --git a/tests/native_instance_test.c b/tests/native_instance_test.c index dd4f2bed..25009002 100644 --- a/tests/native_instance_test.c +++ b/tests/native_instance_test.c @@ -180,11 +180,11 @@ void* openDisplayX11() // clang-format off s_XOpenDisplay = (XOpenDisplayFn)dlsym( - s_LibX, + s_LibX, "XOpenDisplay"); s_XCloseDisplay = (XCloseDisplayFn)dlsym( - s_LibX, + s_LibX, "XCloseDisplay"); return s_XOpenDisplay(nullptr); @@ -210,31 +210,31 @@ void* openDisplayWayland() // clang-format off s_wl_display_connect = (wl_display_connect_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_display_connect"); s_wl_display_disconnect = (wl_display_disconnect_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_display_disconnect"); s_wl_display_roundtrip = (wl_display_roundtrip_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_display_roundtrip"); s_wl_proxy_marshal_flags = (wl_proxy_marshal_flags_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_proxy_marshal_flags"); s_wl_proxy_get_version = (wl_proxy_get_version_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_proxy_get_version"); s_wl_proxy_add_listener = (wl_proxy_add_listener_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_proxy_add_listener"); s_wl_proxy_destroy = (wl_proxy_destroy_fn)dlsym( - s_LibWayland, + s_LibWayland, "wl_proxy_destroy"); registryInterface = dlsym(s_LibWayland, "wl_registry_interface"); @@ -360,7 +360,7 @@ bool nativeInstanceTest() createInfo.show = true; createInfo.style = PAL_WINDOW_STYLE_RESIZABLE; createInfo.title = "Native Instance Test"; - + // check if we support decorated windows (title bar, close etc) PalVideoFeatures64 features = palGetVideoFeaturesEx(); if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { @@ -425,4 +425,4 @@ bool nativeInstanceTest() closeInstance(instance); return true; -} \ No newline at end of file +} diff --git a/tests/native_integration_test.c b/tests/native_integration_test.c index 80eabd79..2e39d56a 100644 --- a/tests/native_integration_test.c +++ b/tests/native_integration_test.c @@ -132,31 +132,31 @@ void setWindowTitleX11(PalWindowHandleInfoEx* windowInfo) // clang-format off s_XInternAtom = (XInternAtomFn)dlsym( - s_X11Lib, + s_X11Lib, "XInternAtom"); s_XChangeProperty = (XChangePropertyFn)dlsym( - s_X11Lib, + s_X11Lib, "XChangeProperty"); s_XGetWMName = (XGetWMNameFn)dlsym( - s_X11Lib, + s_X11Lib, "XGetWMName"); s_XStoreName = (XStoreNameFn)dlsym( - s_X11Lib, + s_X11Lib, "XStoreName"); s_XGetWindowProperty = (XGetWindowPropertyFn)dlsym( - s_X11Lib, + s_X11Lib, "XGetWindowProperty"); s_XFlush = (XFlushFn)dlsym( - s_X11Lib, + s_X11Lib, "XFlush"); s_XFree = (XFreeFn)dlsym( - s_X11Lib, + s_X11Lib, "XFree"); // clang-format on @@ -443,4 +443,4 @@ bool nativeIntegrationTest() palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/opengl_context_test.c b/tests/opengl_context_test.c index 5a1491f7..cc893ad3 100644 --- a/tests/opengl_context_test.c +++ b/tests/opengl_context_test.c @@ -337,4 +337,4 @@ bool openglContextTest() palFree(nullptr, fbConfigs); return true; -} \ No newline at end of file +} diff --git a/tests/opengl_fbconfig_test.c b/tests/opengl_fbconfig_test.c index ebd14ffd..9a7b1ad9 100644 --- a/tests/opengl_fbconfig_test.c +++ b/tests/opengl_fbconfig_test.c @@ -145,4 +145,4 @@ bool openglFBConfigTest() palFree(nullptr, fbConfigs); return true; -} \ No newline at end of file +} diff --git a/tests/opengl_multi_context_test.c b/tests/opengl_multi_context_test.c index 70c3cd19..5ae9072d 100644 --- a/tests/opengl_multi_context_test.c +++ b/tests/opengl_multi_context_test.c @@ -394,4 +394,4 @@ bool openglMultiContextTest() palFree(nullptr, fbConfigs); return true; -} \ No newline at end of file +} diff --git a/tests/opengl_test.c b/tests/opengl_test.c index a61d7f0e..38351642 100644 --- a/tests/opengl_test.c +++ b/tests/opengl_test.c @@ -90,4 +90,4 @@ bool openglTest() palShutdownVideo(); return true; -} \ No newline at end of file +} diff --git a/tests/system_cursor_test.c b/tests/system_cursor_test.c index a0f4ec73..c1cbf875 100644 --- a/tests/system_cursor_test.c +++ b/tests/system_cursor_test.c @@ -134,4 +134,4 @@ bool systemCursorTest() palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/system_test.c b/tests/system_test.c index 126c085d..ecfe7215 100644 --- a/tests/system_test.c +++ b/tests/system_test.c @@ -169,4 +169,4 @@ bool systemTest() palLog(nullptr, " Instructions Sets: %s", instructionSets); return true; -} \ No newline at end of file +} diff --git a/tests/tests.c b/tests/tests.c index c442633b..41cce2d8 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -28,4 +28,4 @@ void runTests() palLog(nullptr, statusString); } -} \ No newline at end of file +} diff --git a/tests/tests.h b/tests/tests.h index 656a1d99..d92b1937 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -58,4 +58,4 @@ bool clearColorTest(); bool triangleTest(); bool meshTest(); -#endif // _TESTS_H \ No newline at end of file +#endif // _TESTS_H diff --git a/tests/tests.lua b/tests/tests.lua index d6622c44..4d13756b 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -6,7 +6,7 @@ project "tests" targetdir(target_dir) objdir(obj_dir) - files { + files { "tests_main.c", "tests.c", "logger_test.c", @@ -16,13 +16,13 @@ project "tests" } if (PAL_BUILD_SYSTEM) then - files { + files { "system_test.c" } end if (PAL_BUILD_THREAD) then - files { + files { "thread_test.c", "tls_test.c", "mutex_test.c", @@ -31,7 +31,7 @@ project "tests" end if (PAL_BUILD_VIDEO) then - files { + files { "video_test.c", "monitor_test.c", "monitor_mode_test.c", @@ -49,7 +49,7 @@ project "tests" end if (PAL_BUILD_OPENGL and PAL_BUILD_VIDEO) then - files { + files { "opengl_test.c", "opengl_fbconfig_test.c", "opengl_context_test.c", @@ -58,19 +58,19 @@ project "tests" end if (PAL_BUILD_OPENGL and PAL_BUILD_VIDEO and PAL_BUILD_THREAD) then - files { + files { "multi_thread_opengl_test.c" } end if (PAL_BUILD_GRAPHICS) then - files { + files { "graphics_test.c" } end if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then - files { + files { "clear_color_test.c", "triangle_test.c", "mesh_test.c" @@ -78,4 +78,4 @@ project "tests" end includedirs { "%{wks.location}/include" } - links { "PAL" } \ No newline at end of file + links { "PAL" } diff --git a/tests/tests_main.c b/tests/tests_main.c index 0bcba4ba..ebe241ac 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -66,4 +66,4 @@ int main(int argc, char** argv) runTests(); return 0; -} \ No newline at end of file +} diff --git a/tests/thread_test.c b/tests/thread_test.c index 16f0bd95..f51b64a8 100644 --- a/tests/thread_test.c +++ b/tests/thread_test.c @@ -58,4 +58,4 @@ bool threadTest() palLog(nullptr, "All threads finished successfully"); return true; -} \ No newline at end of file +} diff --git a/tests/time_test.c b/tests/time_test.c index 02042bd2..d3c427b2 100644 --- a/tests/time_test.c +++ b/tests/time_test.c @@ -54,4 +54,4 @@ bool timeTest() frameCount); return true; -} \ No newline at end of file +} diff --git a/tests/tls_test.c b/tests/tls_test.c index fcbd3e50..bfe4ab73 100644 --- a/tests/tls_test.c +++ b/tests/tls_test.c @@ -97,4 +97,4 @@ bool tlsTest() palFree(nullptr, threadData); return true; -} \ No newline at end of file +} diff --git a/tests/triangle_test.c b/tests/triangle_test.c index b54be265..12f753b9 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -19,7 +19,7 @@ static bool readFile(const char* filename, void* buffer, Uint64* size) if (buffer) { fread(buffer, 1, (size_t)size, file); } - + fclose(file); *size = tmpSize; return true; @@ -67,7 +67,7 @@ bool triangleTest() PalPipeline* pipeline = nullptr; PalShader* vertexShader = nullptr; PalShader* fragmentShader = nullptr; - + PalBuffer* vertexBuffer = nullptr; PalBuffer* stagingBuffer = nullptr; PalMemory* vertexBufferMemory = nullptr; @@ -82,13 +82,13 @@ bool triangleTest() } palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, + eventDriver, + PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode( - eventDriver, - PAL_EVENT_KEYDOWN, + eventDriver, + PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); result = palInitVideo(nullptr, eventDriver); @@ -180,7 +180,7 @@ bool triangleTest() palFree(nullptr, adapters); if (!adapter) { - palLog(nullptr, + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); return false; } @@ -192,7 +192,7 @@ bool triangleTest() palLog(nullptr, "Failed to get adapter info: %s", error); return false; } - + // create a device PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; @@ -223,8 +223,8 @@ bool triangleTest() // create a swapchain with the graphics queue PalSwapchainCapabilities swapchainCaps = {0}; result = palQuerySwapchainCapabilities( - device, - &gfxWindow, + device, + &gfxWindow, &swapchainCaps); if (result != PAL_RESULT_SUCCESS) { @@ -250,16 +250,16 @@ bool triangleTest() swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; } - // check if the minimal image count is not good for you + // check if the minimal image count is not good for you // and increase it but not pass the max count swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; result = palCreateSwapchain( - device, - queue, - &gfxWindow, - &swapchainCreateInfo, + device, + queue, + &gfxWindow, + &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { @@ -271,12 +271,12 @@ bool triangleTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate( - nullptr, + nullptr, sizeof(PalImageView*) * imageCount, 0); renderFinishedSemaphores = palAllocate( - nullptr, + nullptr, sizeof(PalSemaphore*) * imageCount, 0); @@ -302,9 +302,9 @@ bool triangleTest() } result = palCreateImageView( - device, - image, - &imageViewCreateInfo, + device, + image, + &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { @@ -342,9 +342,9 @@ bool triangleTest() } result = palCreateCommandBuffer( - device, - cmdPool, - PAL_COMMAND_BUFFER_TYPE_PRIMARY, + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, &cmdBuffers[i]); if (result != PAL_RESULT_SUCCESS) { @@ -376,7 +376,7 @@ bool triangleTest() bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve result = palCreateBuffer( - device, + device, &bufferCreateInfo, &vertexBuffer); @@ -388,7 +388,7 @@ bool triangleTest() bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send result = palCreateBuffer( - device, + device, &bufferCreateInfo, &stagingBuffer); @@ -402,7 +402,7 @@ bool triangleTest() PalMemoryRequirements vertexBufferMemReq = {0}; PalMemoryRequirements stagingBufferMemReq = {0}; result = palGetBufferMemoryRequirements( - vertexBuffer, + vertexBuffer, &vertexBufferMemReq); if (result != PAL_RESULT_SUCCESS) { @@ -412,7 +412,7 @@ bool triangleTest() } result = palGetBufferMemoryRequirements( - stagingBuffer, + stagingBuffer, &stagingBufferMemReq); if (result != PAL_RESULT_SUCCESS) { @@ -422,13 +422,13 @@ bool triangleTest() } // we need to check if the memory type we want are supported - // but almost every GPU supports a GPU only memory + // but almost every GPU supports a GPU only memory // and CPU writable memory result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - vertexBufferMemReq.size, + device, + PAL_MEMORY_TYPE_GPU_ONLY, + vertexBufferMemReq.size, &vertexBufferMemory); if (result != PAL_RESULT_SUCCESS) { @@ -438,9 +438,9 @@ bool triangleTest() } result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - stagingBufferMemReq.size, + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + stagingBufferMemReq.size, &stagingBufferMemory); if (result != PAL_RESULT_SUCCESS) { @@ -467,10 +467,10 @@ bool triangleTest() // map the staging buffer and upload the vertices void* ptr = nullptr; result = palMapMemory( - device, - stagingBufferMemory, - 0, - sizeof(vertices), + device, + stagingBufferMemory, + 0, + sizeof(vertices), &ptr); if (result != PAL_RESULT_SUCCESS) { @@ -502,17 +502,17 @@ bool triangleTest() } result = palCopyBuffer( - cmdBuffers[0], - vertexBuffer, - stagingBuffer, - 0, - 0, + cmdBuffers[0], + vertexBuffer, + stagingBuffer, + 0, + 0, sizeof(vertices)); result = palBufferBarrier( - cmdBuffers[0], - vertexBuffer, - PAL_USAGE_STATE_TRANSFER_WRITE, + cmdBuffers[0], + vertexBuffer, + PAL_USAGE_STATE_TRANSFER_WRITE, PAL_USAGE_STATE_VERTEX_READ); if (result != PAL_RESULT_SUCCESS) { @@ -567,8 +567,8 @@ bool triangleTest() shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; result = palCreateShader( - device, - &shaderCreateInfo, + device, + &shaderCreateInfo, &vertexShader); if (result != PAL_RESULT_SUCCESS) { @@ -599,8 +599,8 @@ bool triangleTest() shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; result = palCreateShader( - device, - &shaderCreateInfo, + device, + &shaderCreateInfo, &fragmentShader); if (result != PAL_RESULT_SUCCESS) { @@ -614,8 +614,8 @@ bool triangleTest() // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout( - device, - &pipelineLayoutCreateInfo, + device, + &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { @@ -691,7 +691,7 @@ bool triangleTest() pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; result = palCreateGraphicsPipeline( - device, + device, &pipelineCreateInfo, &pipeline); @@ -700,7 +700,7 @@ bool triangleTest() palLog(nullptr, "Failed to create graphics pipeline: %s", error); return false; } - + palDestroyShader(vertexShader); palDestroyShader(fragmentShader); @@ -787,7 +787,7 @@ bool triangleTest() } else { // recreate since we dont support fence resetting palDestroyFence(fence); - + result = palCreateFence(device, false, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -836,9 +836,9 @@ bool triangleTest() } result = palImageViewBarrier( - cmdBuffer, - imageViews[index], - oldUsageState, + cmdBuffer, + imageViews[index], + oldUsageState, PAL_USAGE_STATE_COLOR_ATTACHMENT); if (result != PAL_RESULT_SUCCESS) { @@ -923,11 +923,11 @@ bool triangleTest() // change the state of the image view to make it presentable result = palImageViewBarrier( - cmdBuffer, - imageViews[index], - PAL_USAGE_STATE_COLOR_ATTACHMENT, + cmdBuffer, + imageViews[index], + PAL_USAGE_STATE_COLOR_ATTACHMENT, PAL_USAGE_STATE_PRESENT); - + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); @@ -994,7 +994,7 @@ bool triangleTest() palFreeMemory(device, vertexBufferMemory); palDestroyCommandPool(cmdPool); - palDestroySwapchain(swapchain); + palDestroySwapchain(swapchain); palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); @@ -1004,4 +1004,4 @@ bool triangleTest() palShutdownVideo(); palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/user_event_test.c b/tests/user_event_test.c index 75fb7f6c..0847f0af 100644 --- a/tests/user_event_test.c +++ b/tests/user_event_test.c @@ -108,4 +108,4 @@ bool userEventTest() palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} diff --git a/tests/video_test.c b/tests/video_test.c index c018c741..5868f9b5 100644 --- a/tests/video_test.c +++ b/tests/video_test.c @@ -187,4 +187,4 @@ bool videoTest() palShutdownVideo(); return true; -} \ No newline at end of file +} diff --git a/tests/window_test.c b/tests/window_test.c index 7210dabc..5d425779 100644 --- a/tests/window_test.c +++ b/tests/window_test.c @@ -377,4 +377,4 @@ bool windowTest() palDestroyEventDriver(eventDriver); return true; -} \ No newline at end of file +} From e12fbe68a2f3b5cec15a160cc989b8c3af777df7 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 8 Jan 2026 14:52:08 +0000 Subject: [PATCH 079/372] add workgroup build info helper API --- include/pal/pal_graphics.h | 70 ++++++++++++++ src/graphics/pal_graphics.c | 183 ++++++++++++++++++++++++++++++++++++ src/graphics/pal_vulkan.c | 128 ++++++++++++++++++++++++- tests/mesh_test.c | 3 + tests/tests_main.c | 2 + 5 files changed, 385 insertions(+), 1 deletion(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 97854bd2..e9dad95f 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -732,6 +732,17 @@ typedef struct { PalFormat* colorAttachmentsFormat; } PalRenderingLayoutInfo; +typedef struct { + Uint32 workCount[3]; + Uint32 workGroupSize[3]; + Uint32 workGroupCount[3]; +} PalWorkGroupBuildData; + +typedef struct { + Uint32 workGroupBase[3]; + Uint32 workGroupCount[3]; +} PalWorkGroupInfo; + typedef struct { Uint32 vertexCount; Uint32 instanceCount; @@ -1231,6 +1242,14 @@ typedef struct { Uint64 offset, Uint32 count); + PalResult PAL_CALL (*drawIndirectCount)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 count); + PalResult PAL_CALL (*drawIndexed)( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data); @@ -1241,6 +1260,14 @@ typedef struct { Uint64 offset, Uint32 count); + PalResult PAL_CALL (*drawIndexedIndirectCount)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 count); + PalResult PAL_CALL (*imageViewBarrier)( PalCommandBuffer* cmdBuffer, PalImageView* imageView, @@ -1253,6 +1280,17 @@ typedef struct { PalUsageState oldUsageState, PalUsageState newUsageState); + PalResult PAL_CALL (*dispatch)( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + + PalResult PAL_CALL (*dispatchIndirect)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset); + PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -1608,6 +1646,14 @@ PAL_API PalResult PAL_CALL palDrawIndirect( Uint64 offset, Uint32 count); +PAL_API PalResult PAL_CALL palDrawIndirectCount( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 count); + PAL_API PalResult PAL_CALL palDrawIndexed( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data); @@ -1618,6 +1664,14 @@ PAL_API PalResult PAL_CALL palDrawIndexedIndirect( Uint64 offset, Uint32 count); +PAL_API PalResult PAL_CALL palDrawIndexedIndirectCount( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 count); + PAL_API PalResult PAL_CALL palImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, @@ -1630,6 +1684,17 @@ PAL_API PalResult PAL_CALL palBufferBarrier( PalUsageState oldUsageState, PalUsageState newUsageState); +PAL_API PalResult PAL_CALL palDispatch( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + +PAL_API PalResult PAL_CALL palDispatchIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset); + PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -1677,6 +1742,11 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); +PAL_API bool PAL_CALL palBuildWorkGroupInfo( + const PalWorkGroupBuildData* data, + Int32* count, + PalWorkGroupInfo* info); + /** @} */ // end of pal_graphics group #endif // _PAL_GRAPHICS_H diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 7eb9d78e..36ac08a6 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -70,6 +70,15 @@ static GraphicsLinux s_Graphics = {0}; // Internal API // ================================================== +static inline Uint32 _ceil(Uint32 a, Uint32 b) +{ + return (a + b - 1) / b; +} + +static inline Uint32 _min(Uint32 a, Uint32 b) +{ + return (a < b) ? a : b; +} // ================================================== // Vulkan API @@ -370,6 +379,14 @@ PalResult PAL_CALL drawIndirectVk( Uint64 offset, Uint32 count); +PalResult PAL_CALL drawIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 count); + PalResult PAL_CALL drawIndexedVk( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data); @@ -380,6 +397,14 @@ PalResult PAL_CALL drawIndexedIndirectVk( Uint64 offset, Uint32 count); +PalResult PAL_CALL drawIndexedIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 count); + PalResult PAL_CALL imageViewBarrierVk( PalCommandBuffer* cmdBuffer, PalImageView* imageView, @@ -392,6 +417,17 @@ PalResult PAL_CALL bufferBarrierVk( PalUsageState oldUsageState, PalUsageState newUsageState); +PalResult PAL_CALL dispatchVk( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + +PalResult PAL_CALL dispatchIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset); + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -523,10 +559,14 @@ static PalGraphicsBackend s_VkBackend = { .bindIndexBuffer = bindVkIndexBuffer, .draw = drawVk, .drawIndirect = drawIndirectVk, + .drawIndexedIndirectCount = drawIndirectCountVk, .drawIndexed = drawIndexedVk, .drawIndexedIndirect = drawIndexedIndirectVk, + .drawIndexedIndirectCount = drawIndexedIndirectCountVk, .imageViewBarrier = imageViewBarrierVk, .bufferBarrier = bufferBarrierVk, + .dispatch = dispatchVk, + .dispatchIndirect = dispatchIndirectVk, .submitCommandBuffer = submitVkCommandBuffer, .createAccelerationstructure = createVkAccelerationstructure, .destroyAccelerationstructure = destroyVkAccelerationstructure, @@ -645,10 +685,14 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->bindIndexBuffer || !backend->draw || !backend->drawIndirect || + !backend->drawIndirectCount || !backend->drawIndexed || !backend->drawIndexedIndirect || + !backend->drawIndexedIndirectCount || !backend->imageViewBarrier || !backend->bufferBarrier || + !backend->dispatch || + !backend->dispatchIndirect || !backend->submitCommandBuffer || !backend->createAccelerationstructure || !backend->destroyAccelerationstructure || @@ -1994,6 +2038,31 @@ PalResult PAL_CALL palDrawIndirect( count); } +PalResult PAL_CALL palDrawIndirectCount( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 count) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffer || !countBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->drawIndirectCount( + cmdBuffer, + buffer, + countBuffer, + offset, + countBufferOffset, + count); +} + PalResult PAL_CALL palDrawIndexed( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data) @@ -2032,6 +2101,31 @@ PalResult PAL_CALL palDrawIndexedIndirect( count); } +PalResult PAL_CALL palDrawIndexedIndirectCount( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 count) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffer || !countBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->drawIndexedIndirectCount( + cmdBuffer, + buffer, + countBuffer, + offset, + countBufferOffset, + count); +} + PalResult PAL_CALL palImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, @@ -2074,6 +2168,46 @@ PalResult PAL_CALL palBufferBarrier( newUsageState); } +PalResult PAL_CALL palDispatch( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->dispatch( + cmdBuffer, + groupCountX, + groupCountY, + groupCountZ); +} + +PalResult PAL_CALL palDispatchIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->dispatchIndirect( + cmdBuffer, + buffer, + offset); +} + PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) @@ -2347,3 +2481,52 @@ void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) pipeline->backend->destroyPipeline(pipeline); } } + +// ================================================== +// Helpers +// ================================================== + +bool PAL_CALL palBuildWorkGroupInfo( + const PalWorkGroupBuildData* data, + Int32* count, + PalWorkGroupInfo* info) +{ + if (!data) { + return false; + } + + Uint32 workGroupCount[3]; + Uint32 groupInfoCount[3]; + for (int i = 0; i < 3; i++) { + Uint32 tmp = _ceil(data->workCount[i], data->workGroupSize[i]); + workGroupCount[i] = tmp; + groupInfoCount[i] = _ceil(tmp, data->workGroupCount[i]); + } + + if (!info) { + // total number of group build info on all axis + *count = groupInfoCount[0] * groupInfoCount[1] * groupInfoCount[2];; + return true; + } + + for (int i = 0; i < *count; i++) { + PalWorkGroupInfo* buildInfo = &info[i]; + // find index + Uint32 index[3]; + index[0] = i % groupInfoCount[0]; + index[1] = (i / groupInfoCount[0]) % groupInfoCount[1]; + index[2] = i / (groupInfoCount[0] * groupInfoCount[1]); + + // fill group build info + for (int j = 0; j < 3; j++) { + buildInfo->workGroupBase[j] = index[j] * data->workGroupCount[j]; + buildInfo->workGroupBase[j] = index[j] * data->workGroupCount[j]; + buildInfo->workGroupBase[j] = index[j] * data->workGroupCount[j]; + + Uint32 tmp = workGroupCount[j] - buildInfo->workGroupBase[j]; + buildInfo->workGroupCount[j] = _min(data->workGroupCount[j], tmp); + } + } + + return true; +} diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index df51adeb..75193e89 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -147,6 +147,8 @@ typedef struct { PFN_vkCmdDrawIndirect cmdDrawIndirect; PFN_vkCmdDrawIndexed cmdDrawIndexed; PFN_vkCmdDrawIndexedIndirect cmdDrawIndexedIndirect; + PFN_vkCmdDispatch cmdDispatch; + PFN_vkCmdDispatchIndirect cmdDispatchIndirect; PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; @@ -174,7 +176,6 @@ typedef struct { PFN_vkDeviceWaitIdle waitDevice; PFN_vkQueueWaitIdle waitQueue; - VkAllocationCallbacks vkAllocator; const PalAllocator* allocator; } Vulkan; @@ -200,6 +201,10 @@ typedef struct { PhysicalQueue* phyQueues; PFN_vkGetBufferDeviceAddress getBufferrAddress; + // draw indirect + PFN_vkCmdDrawIndirectCount cmdDrawIndirectCount; + PFN_vkCmdDrawIndexedIndirectCount cmdDrawIndexedIndirectCount; + // swapchain PFN_vkCreateSwapchainKHR createSwapchain; PFN_vkDestroySwapchainKHR destroySwapchain; @@ -2018,6 +2023,14 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCmdDrawIndexedIndirect"); + s_Vk.cmdDispatch = (PFN_vkCmdDispatch)dlsym( + s_Vk.handle, + "vkCmdDispatch"); + + s_Vk.cmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)dlsym( + s_Vk.handle, + "vkCmdDispatchIndirect"); + s_Vk.createBuffer = (PFN_vkCreateBuffer)dlsym( s_Vk.handle, "vkCreateBuffer"); @@ -3469,6 +3482,31 @@ PalResult PAL_CALL createVkDevice( } } + // buffer address + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { + device->cmdDrawIndirectCount = + (PFN_vkCmdDrawIndirectCount)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawIndirectCount"); + + device->cmdDrawIndexedIndirectCount = + (PFN_vkCmdDrawIndexedIndirectCount)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawIndexedIndirectCount"); + + if (!device->cmdDrawIndirectCount) { + device->cmdDrawIndirectCount = + (PFN_vkCmdDrawIndirectCountKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawIndirectCountKHR"); + + device->cmdDrawIndexedIndirectCount = + (PFN_vkCmdDrawIndexedIndirectCountKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawIndexedIndirectCountKHR"); + } + } + // dynamic rendering device->cmdBeginRendering = (PFN_vkCmdBeginRendering)s_Vk.getDeviceProcAddr( @@ -5940,6 +5978,36 @@ PalResult PAL_CALL drawIndirectVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL drawIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 count) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* vkBuffer = (Buffer*)buffer; + Buffer* vkCountBuffer = (Buffer*)countBuffer; + Uint32 stride = sizeof(VkDrawIndirectCommand); + + if (!(vkCmdBuffer->device->features & + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + vkCmdBuffer->device->cmdDrawIndirectCount( + vkCmdBuffer->handle, + vkBuffer->handle, + offset, + vkCountBuffer->handle, + countBufferOffset, + count, + stride); + + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL drawIndexedVk( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data) @@ -5976,6 +6044,36 @@ PalResult PAL_CALL drawIndexedIndirectVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL drawIndexedIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 count) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* vkBuffer = (Buffer*)buffer; + Buffer* vkCountBuffer = (Buffer*)countBuffer; + Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); + + if (!(vkCmdBuffer->device->features & + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + vkCmdBuffer->device->cmdDrawIndexedIndirectCount( + vkCmdBuffer->handle, + vkBuffer->handle, + offset, + vkCountBuffer->handle, + countBufferOffset, + count, + stride); + + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL imageViewBarrierVk( PalCommandBuffer* cmdBuffer, PalImageView* imageView, @@ -6053,6 +6151,34 @@ PalResult PAL_CALL bufferBarrierVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL dispatchVk( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + s_Vk.cmdDispatch( + vkCmdBuffer->handle, + groupCountX, + groupCountY, + groupCountZ); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL dispatchIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* vkBuffer = (Buffer*)buffer; + + s_Vk.cmdDispatchIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset); + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) diff --git a/tests/mesh_test.c b/tests/mesh_test.c index d0da47ee..cfd4f0bf 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -697,6 +697,9 @@ bool meshTest() } // draw a single triangle with the mesh shader + // palBuildWorkGroupInfo() is a helper to build + // the workgroup count per axis using normal + // workCount (image size, buffer size) result = palDrawMeshTasks(cmdBuffer, 1, 1, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/tests_main.c b/tests/tests_main.c index ebe241ac..bf6e1b15 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -2,6 +2,8 @@ #include "pal/pal_config.h" // for systems reflection #include "tests.h" +#include "pal/pal_graphics.h" + // clang-format off int main(int argc, char** argv) { From fbeb51b3c369cd15e3c53600c79ddb2a6aba68ff Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 8 Jan 2026 15:21:17 +0000 Subject: [PATCH 080/372] add dispatch base function --- include/pal/pal_graphics.h | 21 ++++++++- src/graphics/pal_graphics.c | 38 ++++++++++++++++ src/graphics/pal_vulkan.c | 90 +++++++++++++++++++++++++++++++++---- tests/graphics_test.c | 4 ++ tests/tests.h | 1 + 5 files changed, 145 insertions(+), 9 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index e9dad95f..4c524803 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -254,7 +254,8 @@ typedef enum { PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(28), PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(29), PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(31) + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(31), + PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(32) } PalAdapterFeatures; typedef enum { @@ -1286,6 +1287,15 @@ typedef struct { Uint32 groupCountY, Uint32 groupCountZ); + PalResult PAL_CALL (*dispatchBase)( + PalCommandBuffer* cmdBuffer, + Uint32 baseGroupX, + Uint32 baseGroupY, + Uint32 baseGroupZ, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + PalResult PAL_CALL (*dispatchIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, @@ -1690,6 +1700,15 @@ PAL_API PalResult PAL_CALL palDispatch( Uint32 groupCountY, Uint32 groupCountZ); +PAL_API PalResult PAL_CALL palDispatchBase( + PalCommandBuffer* cmdBuffer, + Uint32 baseGroupX, + Uint32 baseGroupY, + Uint32 baseGroupZ, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + PAL_API PalResult PAL_CALL palDispatchIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 36ac08a6..98aff22f 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -423,6 +423,15 @@ PalResult PAL_CALL dispatchVk( Uint32 groupCountY, Uint32 groupCountZ); +PalResult PAL_CALL dispatchBaseVk( + PalCommandBuffer* cmdBuffer, + Uint32 baseGroupX, + Uint32 baseGroupY, + Uint32 baseGroupZ, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + PalResult PAL_CALL dispatchIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, @@ -566,6 +575,7 @@ static PalGraphicsBackend s_VkBackend = { .imageViewBarrier = imageViewBarrierVk, .bufferBarrier = bufferBarrierVk, .dispatch = dispatchVk, + .dispatchBase = dispatchBaseVk, .dispatchIndirect = dispatchIndirectVk, .submitCommandBuffer = submitVkCommandBuffer, .createAccelerationstructure = createVkAccelerationstructure, @@ -692,6 +702,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->imageViewBarrier || !backend->bufferBarrier || !backend->dispatch || + !backend->dispatchBase || !backend->dispatchIndirect || !backend->submitCommandBuffer || !backend->createAccelerationstructure || @@ -2189,6 +2200,33 @@ PalResult PAL_CALL palDispatch( groupCountZ); } +PalResult PAL_CALL palDispatchBase( + PalCommandBuffer* cmdBuffer, + Uint32 baseGroupX, + Uint32 baseGroupY, + Uint32 baseGroupZ, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->dispatchBase( + cmdBuffer, + baseGroupX, + baseGroupY, + baseGroupZ, + groupCountX, + groupCountY, + groupCountZ); +} + PalResult PAL_CALL palDispatchIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 75193e89..50bdd5d7 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -200,6 +200,7 @@ typedef struct { VkDevice handle; PhysicalQueue* phyQueues; PFN_vkGetBufferDeviceAddress getBufferrAddress; + PFN_vkCmdDispatchBase cmdDispatchBase; // draw indirect PFN_vkCmdDrawIndirectCount cmdDrawIndirectCount; @@ -2684,6 +2685,7 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) bool multiiView = false; bool dynamicstate = false; bool bufferDeviceAddress = false; + bool shaderParameters = false; // clang-format off // check if the extensions are present @@ -2742,6 +2744,9 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } else if (strcmp(props->extensionName, "VK_KHR_buffer_device_address") == 0) { bufferDeviceAddress = true; + + } else if (strcmp(props->extensionName, "VK_KHR_shader_draw_parameters") == 0) { + shaderParameters = true; } } @@ -2912,6 +2917,21 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } } + // shader draw parameters is part of core 1.2 + if (props.apiVersion >= VK_API_VERSION_1_2 || shaderParameters) { + VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {0}; + drawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &drawParameters; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (drawParameters.shaderDrawParameters) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DISPATCH_BASE; + } + } + // clang-format on VkPhysicalDeviceFeatures features; s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); @@ -3113,6 +3133,9 @@ PalResult PAL_CALL createVkDevice( VkPhysicalDeviceVulkan12Features features12 = {0}; features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {0}; + drawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; + // clang-format on if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_KHR_dynamic_rendering"; @@ -3258,6 +3281,16 @@ PalResult PAL_CALL createVkDevice( next = &bufferAddress; } + if (features & PAL_ADAPTER_FEATURE_DISPATCH_BASE) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_shader_draw_parameters"; + } + drawParameters.shaderDrawParameters = true; + + drawParameters.pNext = next; + next = &drawParameters; + } + VkDeviceCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pEnabledFeatures = &coreFeatures; @@ -3347,7 +3380,7 @@ PalResult PAL_CALL createVkDevice( } } - // load swapchain procs + // swapchain procs if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { device->acquireNextImage = (PFN_vkAcquireNextImageKHR)s_Vk.getDeviceProcAddr( device->handle, @@ -3370,7 +3403,7 @@ PalResult PAL_CALL createVkDevice( "vkQueuePresentKHR"); } - // load semaphore procs + // semaphore procs if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { device->waitSemaphore = (PFN_vkWaitSemaphores)s_Vk.getDeviceProcAddr( device->handle, @@ -3399,7 +3432,7 @@ PalResult PAL_CALL createVkDevice( } } - // load fragment shading rate procs + // fragment shading rate procs if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { device->cmdSetFragmentShadingRate = (PFN_vkCmdSetFragmentShadingRateKHR)s_Vk.getDeviceProcAddr( @@ -3407,7 +3440,7 @@ PalResult PAL_CALL createVkDevice( "vkCmdSetFragmentShadingRateKHR"); } - // mesh shader + // mesh shader procs if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { device->cmdDrawMeshTask = (PFN_vkCmdDrawMeshTasksEXT)s_Vk.getDeviceProcAddr( device->handle, @@ -3424,7 +3457,7 @@ PalResult PAL_CALL createVkDevice( "vkCmdDrawMeshTasksIndirectCountEXT"); } - // ray tracing + // ray tracing procs if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { device->createAccelerationStructure = (PFN_vkCreateAccelerationStructureKHR)s_Vk.getDeviceProcAddr( @@ -3467,7 +3500,7 @@ PalResult PAL_CALL createVkDevice( "vkCmdTraceRaysIndirectKHR"); } - // buffer address + // buffer address procs if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { device->getBufferrAddress = (PFN_vkGetBufferDeviceAddress)s_Vk.getDeviceProcAddr( @@ -3482,7 +3515,7 @@ PalResult PAL_CALL createVkDevice( } } - // buffer address + // indirect draw count procs if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { device->cmdDrawIndirectCount = (PFN_vkCmdDrawIndirectCount)s_Vk.getDeviceProcAddr( @@ -3507,7 +3540,22 @@ PalResult PAL_CALL createVkDevice( } } - // dynamic rendering + // dispatch base procs + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { + device->cmdDispatchBase = + (PFN_vkCmdDispatchBase)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDispatchBase"); + + if (!device->cmdDispatchBase) { + device->cmdDispatchBase = + (PFN_vkCmdDispatchBaseKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDispatchBaseKHR"); + } + } + + // dynamic rendering procs device->cmdBeginRendering = (PFN_vkCmdBeginRendering)s_Vk.getDeviceProcAddr( device->handle, @@ -6167,6 +6215,32 @@ PalResult PAL_CALL dispatchVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL dispatchBaseVk( + PalCommandBuffer* cmdBuffer, + Uint32 baseGroupX, + Uint32 baseGroupY, + Uint32 baseGroupZ, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DISPATCH_BASE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + vkCmdBuffer->device->cmdDispatchBase( + vkCmdBuffer->handle, + baseGroupX, + baseGroupY, + baseGroupZ, + groupCountX, + groupCountY, + groupCountZ); + + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL dispatchIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 25894db7..3adb4b8e 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -300,6 +300,10 @@ bool graphicsTest() palLog(nullptr, " Indirect draw"); } + if (features & PAL_ADAPTER_FEATURE_DISPATCH_BASE) { + palLog(nullptr, " Dispatch base"); + } + palLog(nullptr, ""); } diff --git a/tests/tests.h b/tests/tests.h index d92b1937..40aacdff 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -52,6 +52,7 @@ bool multiThreadOpenGlTest(); // graphics bool graphicsTest(); +bool meshTest(); // graphics and video bool clearColorTest(); From 885872fe8a9563847da94393f8aa774269aaa3b2 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 9 Jan 2026 12:26:30 +0000 Subject: [PATCH 081/372] use new clang format configuration --- .clang-format | 2 - include/pal/pal_event.h | 2 +- include/pal/pal_graphics.h | 13 +- include/pal/pal_thread.h | 2 +- src/graphics/pal_graphics.c | 344 ++++----------- src/graphics/pal_vulkan.c | 689 ++++++++--------------------- src/opengl/pal_opengl_linux.c | 192 ++------ src/opengl/pal_opengl_win32.c | 28 +- src/pal_core.c | 8 +- src/system/pal_system_win32.c | 16 +- src/thread/pal_thread_win32.c | 31 +- src/video/pal_video_linux.c | 711 +++++++++++------------------- src/video/pal_video_win32.c | 108 +---- tests/attach_window_test.c | 17 +- tests/char_event_test.c | 5 +- tests/clear_color_test.c | 48 +- tests/cursor_test.c | 6 +- tests/custom_decoration_test.c | 200 ++++----- tests/icon_test.c | 6 +- tests/input_window_test.c | 33 +- tests/mesh_test.c | 76 +--- tests/multi_thread_opengl_test.c | 29 +- tests/native_instance_test.c | 23 +- tests/native_integration_test.c | 22 +- tests/opengl_context_test.c | 8 +- tests/opengl_multi_context_test.c | 8 +- tests/system_cursor_test.c | 6 +- tests/time_test.c | 12 +- tests/triangle_test.c | 124 ++---- tests/window_test.c | 31 +- 30 files changed, 810 insertions(+), 1990 deletions(-) diff --git a/.clang-format b/.clang-format index 570cc945..7af30b94 100644 --- a/.clang-format +++ b/.clang-format @@ -4,8 +4,6 @@ IndentWidth: 4 ColumnLimit: 100 UseTab: Never UseCRLF: false -InsertFinalNewline: true -TrimTrailingWhitespace: true LineEnding: LF # reset if not set diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index b0a53945..bb0a4b39 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -430,7 +430,7 @@ typedef struct { const PalAllocator* allocator; /**< Set to nullptr to use default.*/ PalEventQueue* queue; /**< Set to nullptr to use default.*/ PalEventCallback callback; /**< Can be nullptr.*/ - void* userData; /**< Optional user-provided data. Can be nullptr.*/ + void* userData; /**< Optional user-provided data. Can be nullptr.*/ } PalEventDriverCreateInfo; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 4c524803..4cbd463e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1084,7 +1084,7 @@ typedef struct { PalResult PAL_CALL (*getNextSwapchainImage)( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32 *outIndex); + Uint32* outIndex); PalResult PAL_CALL (*presentSwapchain)( PalSwapchain* swapchain, @@ -1310,8 +1310,7 @@ typedef struct { const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs); - void PAL_CALL (*destroyAccelerationstructure)( - PalAccelerationStructure* as); + void PAL_CALL (*destroyAccelerationstructure)(PalAccelerationStructure* as); PalResult PAL_CALL (*getAccelerationStructureBuildSize)( PalDevice* device, @@ -1349,8 +1348,7 @@ typedef struct { void PAL_CALL (*destroyPipeline)(PalPipeline* pipeline); } PalGraphicsBackend; -PAL_API PalResult PAL_CALL palAddGraphicsBackend( - const PalGraphicsBackend* backend); +PAL_API PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend); PAL_API PalResult PAL_CALL palInitGraphics( const PalGraphicsDebugger* debugger, @@ -1497,7 +1495,7 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PAL_API PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32 *outIndex); + Uint32* outIndex); PAL_API PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, @@ -1723,8 +1721,7 @@ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs); -PAL_API void PAL_CALL palDestroyAccelerationstructure( - PalAccelerationStructure* as); +PAL_API void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* as); PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( PalDevice* device, diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index 9e8c994d..8cf5b80e 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -142,7 +142,7 @@ typedef struct { Uint64 stackSize; /**< Set to 0 to use default*/ const PalAllocator* allocator; /**< Set to nullptr to use default.*/ PalThreadFn entry; /**< Thread entry function*/ - void* arg; /**< Optional user-provided data. Can be nullptr.*/ + void* arg; /**< Optional user-provided data. Can be nullptr.*/ } PalThreadCreateInfo; /** diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 98aff22f..df056524 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -32,7 +32,10 @@ freely, subject to the following restrictions: // ================================================== #define MAX_BACKENDS 32 -#define PAL_HANDLE(name) struct name { const PalGraphicsBackend* backend; }; +#define PAL_HANDLE(name) \ + struct name { \ + const PalGraphicsBackend* backend; \ + }; PAL_HANDLE(PalAdapter) PAL_HANDLE(PalDevice) @@ -70,12 +73,16 @@ static GraphicsLinux s_Graphics = {0}; // Internal API // ================================================== -static inline Uint32 _ceil(Uint32 a, Uint32 b) +static inline Uint32 _ceil( + Uint32 a, + Uint32 b) { return (a + b - 1) / b; } -static inline Uint32 _min(Uint32 a, Uint32 b) +static inline Uint32 _min( + Uint32 a, + Uint32 b) { return (a < b) ? a : b; } @@ -446,8 +453,7 @@ PalResult PAL_CALL createVkAccelerationstructure( const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs); -void PAL_CALL destroyVkAccelerationstructure( - PalAccelerationStructure* as); +void PAL_CALL destroyVkAccelerationstructure(PalAccelerationStructure* as); PalResult PAL_CALL getVkAccelerationStructureBuildSize( PalDevice* device, @@ -497,41 +503,41 @@ void PAL_CALL destroyVkPipeline(PalPipeline* pipeline); static PalGraphicsBackend s_VkBackend = { .enumerateAdapters = enumerateVkAdapters, - .getAdapterInfo = getVkAdapterInfo, - .getAdapterCapabilities = getVkAdapterCapabilities, + .getAdapterInfo = getVkAdapterInfo, + .getAdapterCapabilities = getVkAdapterCapabilities, .getAdapterFeatures = getVkAdapterFeatures, - .createDevice = createVkDevice, - .destroyDevice = destroyVkDevice, + .createDevice = createVkDevice, + .destroyDevice = destroyVkDevice, .waitDevice = waitVkDevice, - .allocateMemory = allocateVkMemory, - .freeMemory = freeVkMemory, + .allocateMemory = allocateVkMemory, + .freeMemory = freeVkMemory, .mapMemory = mapVkMemory, .unmapMemory = unmapVkMemory, .queryDepthStencilCapabilities = queryVkDepthStencilCapabilities, .queryFragmentShadingRateCapabilities = queryVkFragmentShadingRateCapabilities, .queryMeshShaderCapabilities = queryVkMeshShaderCapabilities, .queryRayTracingCapabilities = queryVkRayTracingCapabilities, - .createQueue = createVkQueue, - .destroyQueue = destroyVkQueue, + .createQueue = createVkQueue, + .destroyQueue = destroyVkQueue, .waitQueue = waitVkQueue, - .canQueuePresent = canVkQueuePresent, - .enumerateFormats = enumerateVkFormats, - .isFormatSupported = isVkFormatSupported, - .queryFormatImageUsages = queryVkFormatImageUsages, - .queryFormatImageViewUsages = queryVkFormatImageViewUsages, - .createImage = createVkImage, - .destroyImage = destroyVkImage, - .getImageInfo = getVkImageInfo, - .getImageMemoryRequirements = getVkImageMemoryRequirements, - .bindImageMemory = bindVkImageMemory, - .createImageView = createVkImageView, - .destroyImageView = destroyVkImageView, - .querySwapchainCapabilities = queryVkSwapchainCapabilities, - .createSwapchain = createVkSwapchain, - .destroySwapchain = destroyVkSwapchain, - .getSwapchainImage = getVkSwapchainImage, - .getNextSwapchainImage = getVkNextSwapchainImage, - .presentSwapchain = presentVkSwapchain, + .canQueuePresent = canVkQueuePresent, + .enumerateFormats = enumerateVkFormats, + .isFormatSupported = isVkFormatSupported, + .queryFormatImageUsages = queryVkFormatImageUsages, + .queryFormatImageViewUsages = queryVkFormatImageViewUsages, + .createImage = createVkImage, + .destroyImage = destroyVkImage, + .getImageInfo = getVkImageInfo, + .getImageMemoryRequirements = getVkImageMemoryRequirements, + .bindImageMemory = bindVkImageMemory, + .createImageView = createVkImageView, + .destroyImageView = destroyVkImageView, + .querySwapchainCapabilities = queryVkSwapchainCapabilities, + .createSwapchain = createVkSwapchain, + .destroySwapchain = destroyVkSwapchain, + .getSwapchainImage = getVkSwapchainImage, + .getNextSwapchainImage = getVkNextSwapchainImage, + .presentSwapchain = presentVkSwapchain, .createShader = createVkShader, .destroyShader = destroyVkShader, .createFence = createVkFence, @@ -588,8 +594,7 @@ static PalGraphicsBackend s_VkBackend = { .createPipelineLayout = createVkPipelineLayout, .destroyPipelineLayout = destroyVkPipelineLayout, .createGraphicsPipeline = createVkGraphicsPipeline, - .destroyPipeline = destroyVkPipeline -}; + .destroyPipeline = destroyVkPipeline}; #endif // PAL_HAS_VULKAN @@ -900,10 +905,7 @@ PalResult PAL_CALL palCreateDevice( PalDevice* device = nullptr; PalResult result; - result = adapter->backend->createDevice( - adapter, - features, - &device); + result = adapter->backend->createDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { return result; @@ -948,11 +950,7 @@ PalResult PAL_CALL palAllocateMemory( return PAL_RESULT_NULL_POINTER; } - return device->backend->allocateMemory( - device, - type, - size, - outMemory); + return device->backend->allocateMemory(device, type, size, outMemory); } void PAL_CALL palFreeMemory( @@ -991,9 +989,7 @@ PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( return PAL_RESULT_NULL_POINTER; } - return device->backend->queryFragmentShadingRateCapabilities( - device, - caps); + return device->backend->queryFragmentShadingRateCapabilities(device, caps); } PalResult PAL_CALL palQueryMeshShaderCapabilities( @@ -1008,9 +1004,7 @@ PalResult PAL_CALL palQueryMeshShaderCapabilities( return PAL_RESULT_NULL_POINTER; } - return device->backend->queryMeshShaderCapabilities( - device, - caps); + return device->backend->queryMeshShaderCapabilities(device, caps); } PalResult PAL_CALL palQueryRayTracingCapabilities( @@ -1025,9 +1019,7 @@ PalResult PAL_CALL palQueryRayTracingCapabilities( return PAL_RESULT_NULL_POINTER; } - return device->backend->queryRayTracingCapabilities( - device, - caps); + return device->backend->queryRayTracingCapabilities(device, caps); } // ================================================== @@ -1049,10 +1041,7 @@ PalResult PAL_CALL palCreateQueue( PalQueue* queue = nullptr; PalResult result; - result = device->backend->createQueue( - device, - type, - &queue); + result = device->backend->createQueue(device, type, &queue); if (result != PAL_RESULT_SUCCESS) { return result; @@ -1163,16 +1152,13 @@ PalResult PAL_CALL palCreateImage( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device ||!info || !outImage) { + if (!device || !info || !outImage) { return PAL_RESULT_NULL_POINTER; } PalImage* image = nullptr; PalResult result; - result = device->backend->createImage( - device, - info, - &image); + result = device->backend->createImage(device, info, &image); if (result != PAL_RESULT_SUCCESS) { return result; @@ -1217,9 +1203,7 @@ PalResult PAL_CALL palGetImageMemoryRequirements( return PAL_RESULT_NULL_POINTER; } - return image->backend->getImageMemoryRequirements( - image, - requirements); + return image->backend->getImageMemoryRequirements(image, requirements); } PalResult PAL_CALL palBindImageMemory( @@ -1235,10 +1219,7 @@ PalResult PAL_CALL palBindImageMemory( return PAL_RESULT_NULL_POINTER; } - return image->backend->bindImageMemory( - image, - memory, - offset); + return image->backend->bindImageMemory(image, memory, offset); } // ================================================== @@ -1255,17 +1236,13 @@ PalResult PAL_CALL palCreateImageView( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device ||!image || !info || !outImageView) { + if (!device || !image || !info || !outImageView) { return PAL_RESULT_NULL_POINTER; } PalImageView* imageView = nullptr; PalResult result; - result = device->backend->createImageView( - device, - image, - info, - &imageView); + result = device->backend->createImageView(device, image, info, &imageView); if (result != PAL_RESULT_SUCCESS) { return result; @@ -1300,10 +1277,7 @@ PalResult PAL_CALL palQuerySwapchainCapabilities( return PAL_RESULT_NULL_POINTER; } - return device->backend->querySwapchainCapabilities( - device, - window, - caps); + return device->backend->querySwapchainCapabilities(device, window, caps); } PalResult PAL_CALL palCreateSwapchain( @@ -1323,12 +1297,7 @@ PalResult PAL_CALL palCreateSwapchain( PalResult result; PalSwapchain* swapchain = nullptr; - result = device->backend->createSwapchain( - device, - queue, - window, - info, - &swapchain); + result = device->backend->createSwapchain(device, queue, window, info, &swapchain); if (result != PAL_RESULT_SUCCESS) { return result; @@ -1366,7 +1335,7 @@ PalImage* PAL_CALL palGetSwapchainImage( PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32 *outIndex) + Uint32* outIndex) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1376,10 +1345,7 @@ PalResult PAL_CALL palGetNextSwapchainImage( return PAL_RESULT_NULL_POINTER; } - return swapchain->backend->getNextSwapchainImage( - swapchain, - info, - outIndex); + return swapchain->backend->getNextSwapchainImage(swapchain, info, outIndex); } PalResult PAL_CALL palPresentSwapchain( @@ -1394,9 +1360,7 @@ PalResult PAL_CALL palPresentSwapchain( return PAL_RESULT_NULL_POINTER; } - return swapchain->backend->presentSwapchain( - swapchain, - info); + return swapchain->backend->presentSwapchain(swapchain, info); } // ================================================== @@ -1418,10 +1382,7 @@ PalResult PAL_CALL palCreateShader( PalShader* shader = nullptr; PalResult result; - result = device->backend->createShader( - device, - info, - &shader); + result = device->backend->createShader(device, info, &shader); if (result != PAL_RESULT_SUCCESS) { return result; @@ -1560,11 +1521,7 @@ PalResult PAL_CALL palWaitSemaphore( return PAL_RESULT_NULL_POINTER; } - return semaphore->backend->waitSemaphore( - semaphore, - queue, - value, - timeout); + return semaphore->backend->waitSemaphore(semaphore, queue, value, timeout); } PalResult PAL_CALL palSignalSemaphore( @@ -1580,10 +1537,7 @@ PalResult PAL_CALL palSignalSemaphore( return PAL_RESULT_NULL_POINTER; } - return semaphore->backend->signalSemaphore( - semaphore, - queue, - value); + return semaphore->backend->signalSemaphore(semaphore, queue, value); } PalResult PAL_CALL palGetSemaphoreValue( @@ -1598,9 +1552,7 @@ PalResult PAL_CALL palGetSemaphoreValue( return PAL_RESULT_NULL_POINTER; } - return semaphore->backend->getSemaphoreValue( - semaphore, - value); + return semaphore->backend->getSemaphoreValue(semaphore, value); } // ================================================== @@ -1622,10 +1574,7 @@ PalResult PAL_CALL palCreateCommandPool( PalCommandPool* pool = nullptr; PalResult result; - result = device->backend->createCommandPool( - device, - queue, - &pool); + result = device->backend->createCommandPool(device, queue, &pool); if (result != PAL_RESULT_SUCCESS) { return result; @@ -1672,11 +1621,7 @@ PalResult PAL_CALL palCreateCommandBuffer( PalCommandBuffer* cmdBuffer = nullptr; PalResult result; - result = device->backend->createCommandBuffer( - device, - pool, - type, - &cmdBuffer); + result = device->backend->createCommandBuffer(device, pool, type, &cmdBuffer); if (result != PAL_RESULT_SUCCESS) { return result; @@ -1747,9 +1692,7 @@ PalResult PAL_CALL palExecuteCommandBuffer( return PAL_RESULT_NULL_POINTER; } - return primaryCmdBuffer->backend->executeCommandBuffer( - primaryCmdBuffer, - secondaryCmdBuffer); + return primaryCmdBuffer->backend->executeCommandBuffer(primaryCmdBuffer, secondaryCmdBuffer); } PalResult PAL_CALL palSetFragmentShadingRate( @@ -1764,9 +1707,7 @@ PalResult PAL_CALL palSetFragmentShadingRate( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->setFragmentShadingRate( - cmdBuffer, - state); + return cmdBuffer->backend->setFragmentShadingRate(cmdBuffer, state); } PalResult PAL_CALL palDrawMeshTasks( @@ -1783,11 +1724,7 @@ PalResult PAL_CALL palDrawMeshTasks( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawMeshTasks( - cmdBuffer, - groupCountX, - groupCountY, - groupCountZ); + return cmdBuffer->backend->drawMeshTasks(cmdBuffer, groupCountX, groupCountY, groupCountZ); } PalResult PAL_CALL palDrawMeshTasksIndirect( @@ -1805,12 +1742,7 @@ PalResult PAL_CALL palDrawMeshTasksIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawMeshTasksIndirect( - cmdBuffer, - buffer, - offset, - drawCount, - stride); + return cmdBuffer->backend->drawMeshTasksIndirect(cmdBuffer, buffer, offset, drawCount, stride); } PalResult PAL_CALL palDrawMeshTasksIndirectCount( @@ -1852,9 +1784,7 @@ PalResult PAL_CALL palBuildAccelerationStructures( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->buildAccelerationStructure( - cmdBuffer, - info); + return cmdBuffer->backend->buildAccelerationStructure(cmdBuffer, info); } PalResult PAL_CALL palBeginRendering( @@ -1869,9 +1799,7 @@ PalResult PAL_CALL palBeginRendering( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->beginRendering( - cmdBuffer, - info); + return cmdBuffer->backend->beginRendering(cmdBuffer, info); } PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer) @@ -1903,13 +1831,7 @@ PalResult PAL_CALL palCopyBuffer( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->copyBuffer( - cmdBuffer, - dst, - src, - dstOffset, - srcOffset, - size); + return cmdBuffer->backend->copyBuffer(cmdBuffer, dst, src, dstOffset, srcOffset, size); } PalResult PAL_CALL palBindPipeline( @@ -1924,9 +1846,7 @@ PalResult PAL_CALL palBindPipeline( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->bindPipeline( - cmdBuffer, - pipeline); + return cmdBuffer->backend->bindPipeline(cmdBuffer, pipeline); } PalResult PAL_CALL palSetViewport( @@ -1942,10 +1862,7 @@ PalResult PAL_CALL palSetViewport( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->setViewport( - cmdBuffer, - count, - viewports); + return cmdBuffer->backend->setViewport(cmdBuffer, count, viewports); } PalResult PAL_CALL palSetScissors( @@ -1961,10 +1878,7 @@ PalResult PAL_CALL palSetScissors( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->setScissors( - cmdBuffer, - count, - scissors); + return cmdBuffer->backend->setScissors(cmdBuffer, count, scissors); } PalResult PAL_CALL palBindVertexBuffers( @@ -1982,12 +1896,7 @@ PalResult PAL_CALL palBindVertexBuffers( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->bindVertexBuffers( - cmdBuffer, - firstSlot, - count, - buffers, - offsets); + return cmdBuffer->backend->bindVertexBuffers(cmdBuffer, firstSlot, count, buffers, offsets); } PalResult PAL_CALL palBindIndexBuffer( @@ -2004,11 +1913,7 @@ PalResult PAL_CALL palBindIndexBuffer( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->bindIndexBuffer( - cmdBuffer, - buffer, - offset, - type); + return cmdBuffer->backend->bindIndexBuffer(cmdBuffer, buffer, offset, type); } PalResult PAL_CALL palDraw( @@ -2023,9 +1928,7 @@ PalResult PAL_CALL palDraw( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->draw( - cmdBuffer, - data); + return cmdBuffer->backend->draw(cmdBuffer, data); } PalResult PAL_CALL palDrawIndirect( @@ -2042,11 +1945,7 @@ PalResult PAL_CALL palDrawIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawIndirect( - cmdBuffer, - buffer, - offset, - count); + return cmdBuffer->backend->drawIndirect(cmdBuffer, buffer, offset, count); } PalResult PAL_CALL palDrawIndirectCount( @@ -2065,13 +1964,8 @@ PalResult PAL_CALL palDrawIndirectCount( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawIndirectCount( - cmdBuffer, - buffer, - countBuffer, - offset, - countBufferOffset, - count); + return cmdBuffer->backend + ->drawIndirectCount(cmdBuffer, buffer, countBuffer, offset, countBufferOffset, count); } PalResult PAL_CALL palDrawIndexed( @@ -2086,9 +1980,7 @@ PalResult PAL_CALL palDrawIndexed( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawIndexed( - cmdBuffer, - data); + return cmdBuffer->backend->drawIndexed(cmdBuffer, data); } PalResult PAL_CALL palDrawIndexedIndirect( @@ -2105,11 +1997,7 @@ PalResult PAL_CALL palDrawIndexedIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawIndexedIndirect( - cmdBuffer, - buffer, - offset, - count); + return cmdBuffer->backend->drawIndexedIndirect(cmdBuffer, buffer, offset, count); } PalResult PAL_CALL palDrawIndexedIndirectCount( @@ -2151,11 +2039,7 @@ PalResult PAL_CALL palImageViewBarrier( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->imageViewBarrier( - cmdBuffer, - imageView, - oldUsageState, - newUsageState); + return cmdBuffer->backend->imageViewBarrier(cmdBuffer, imageView, oldUsageState, newUsageState); } PalResult PAL_CALL palBufferBarrier( @@ -2172,11 +2056,7 @@ PalResult PAL_CALL palBufferBarrier( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->bufferBarrier( - cmdBuffer, - buffer, - oldUsageState, - newUsageState); + return cmdBuffer->backend->bufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); } PalResult PAL_CALL palDispatch( @@ -2193,11 +2073,7 @@ PalResult PAL_CALL palDispatch( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->dispatch( - cmdBuffer, - groupCountX, - groupCountY, - groupCountZ); + return cmdBuffer->backend->dispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); } PalResult PAL_CALL palDispatchBase( @@ -2240,10 +2116,7 @@ PalResult PAL_CALL palDispatchIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->dispatchIndirect( - cmdBuffer, - buffer, - offset); + return cmdBuffer->backend->dispatchIndirect(cmdBuffer, buffer, offset); } PalResult PAL_CALL palSubmitCommandBuffer( @@ -2258,9 +2131,7 @@ PalResult PAL_CALL palSubmitCommandBuffer( return PAL_RESULT_NULL_POINTER; } - return queue->backend->submitCommandBuffer( - queue, - info); + return queue->backend->submitCommandBuffer(queue, info); } // ================================================== @@ -2286,10 +2157,7 @@ PalResult PAL_CALL palCreateAccelerationstructure( PalResult result; PalAccelerationStructure* as = nullptr; - result = device->backend->createAccelerationstructure( - device, - info, - &as); + result = device->backend->createAccelerationstructure(device, info, &as); if (result != PAL_RESULT_SUCCESS) { return result; @@ -2300,8 +2168,7 @@ PalResult PAL_CALL palCreateAccelerationstructure( return PAL_RESULT_SUCCESS; } -void PAL_CALL palDestroyAccelerationstructure( - PalAccelerationStructure* as) +void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* as) { if (s_Graphics.initialized && as) { as->backend->destroyAccelerationstructure(as); @@ -2325,10 +2192,7 @@ PalResult PAL_CALL palGetAccelerationStructureBuildSize( return PAL_RESULT_NULL_POINTER; } - return device->backend->getAccelerationStructureBuildSize( - device, - info, - size); + return device->backend->getAccelerationStructureBuildSize(device, info, size); } // ================================================== @@ -2350,10 +2214,7 @@ PalResult PAL_CALL palCreateBuffer( PalResult result; PalBuffer* buffer = nullptr; - result = device->backend->createBuffer( - device, - info, - &buffer); + result = device->backend->createBuffer(device, info, &buffer); if (result != PAL_RESULT_SUCCESS) { return result; @@ -2383,9 +2244,7 @@ PalResult PAL_CALL palGetBufferMemoryRequirements( return PAL_RESULT_NULL_POINTER; } - return buffer->backend->getBufferMemoryRequirements( - buffer, - requirements); + return buffer->backend->getBufferMemoryRequirements(buffer, requirements); } PalResult PAL_CALL palBindBufferMemory( @@ -2401,10 +2260,7 @@ PalResult PAL_CALL palBindBufferMemory( return PAL_RESULT_NULL_POINTER; } - return buffer->backend->bindBufferMemory( - buffer, - memory, - offset); + return buffer->backend->bindBufferMemory(buffer, memory, offset); } PalResult PAL_CALL palMapMemory( @@ -2422,12 +2278,7 @@ PalResult PAL_CALL palMapMemory( return PAL_RESULT_NULL_POINTER; } - return device->backend->mapMemory( - device, - memory, - offset, - size, - outPtr); + return device->backend->mapMemory(device, memory, offset, size, outPtr); } void PAL_CALL palUnmapMemory( @@ -2459,10 +2310,7 @@ PalResult PAL_CALL palCreatePipelineLayout( PalResult result; PalPipelineLayout* layout = nullptr; - result = device->backend->createPipelineLayout( - device, - info, - &layout); + result = device->backend->createPipelineLayout(device, info, &layout); if (result != PAL_RESULT_SUCCESS) { return result; @@ -2499,10 +2347,7 @@ PalResult PAL_CALL palCreateGraphicsPipeline( PalResult result; PalPipeline* pipeline = nullptr; - result = device->backend->createGraphicsPipeline( - device, - info, - &pipeline); + result = device->backend->createGraphicsPipeline(device, info, &pipeline); if (result != PAL_RESULT_SUCCESS) { return result; @@ -2543,7 +2388,8 @@ bool PAL_CALL palBuildWorkGroupInfo( if (!info) { // total number of group build info on all axis - *count = groupInfoCount[0] * groupInfoCount[1] * groupInfoCount[2];; + *count = groupInfoCount[0] * groupInfoCount[1] * groupInfoCount[2]; + ; return true; } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 50bdd5d7..cc6e550d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -28,11 +28,11 @@ freely, subject to the following restrictions: #include "pal/pal_graphics.h" #if PAL_HAS_VULKAN -#include -#include #include -#include #include +#include +#include +#include // HACK: Needed to determine display type if on linux #ifdef _WIN32 @@ -46,8 +46,8 @@ typedef unsigned long Window; typedef unsigned long VisualID; typedef int (*wl_display_get_fd_fn)(struct wl_display*); -#include #include +#include #define VK_LIB_NAME "libvulkan.so" @@ -406,11 +406,8 @@ static bool createSurface( createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; createInfo.surface = window->window; - VkResult result = s_Vk.createWaylandSurface( - s_Vk.instance, - &createInfo, - &s_Vk.vkAllocator, - &surface); + VkResult result = + s_Vk.createWaylandSurface(s_Vk.instance, &createInfo, &s_Vk.vkAllocator, &surface); if (result != VK_SUCCESS) { return false; @@ -420,7 +417,6 @@ static bool createSurface( return true; } else if (platform == VK_XLIB_PLATFORM) { - } } @@ -1165,7 +1161,6 @@ static VkFormat vertexTypeToVkFormat(PalVertexType type) case PAL_VERTEX_TYPE_UINT32_4: return VK_FORMAT_R32G32B32A32_UINT; - case PAL_VERTEX_TYPE_INT8_2: return VK_FORMAT_R8G8_SINT; @@ -1178,7 +1173,6 @@ static VkFormat vertexTypeToVkFormat(PalVertexType type) case PAL_VERTEX_TYPE_UINT8_4: return VK_FORMAT_R8G8B8A8_UINT; - case PAL_VERTEX_TYPE_INT8_2NORM: return VK_FORMAT_R8G8_SNORM; @@ -1191,7 +1185,6 @@ static VkFormat vertexTypeToVkFormat(PalVertexType type) case PAL_VERTEX_TYPE_UINT8_4NORM: return VK_FORMAT_R8G8B8A8_UNORM; - case PAL_VERTEX_TYPE_INT16_2: return VK_FORMAT_R16G16_SINT; @@ -1204,7 +1197,6 @@ static VkFormat vertexTypeToVkFormat(PalVertexType type) case PAL_VERTEX_TYPE_UINT16_4: return VK_FORMAT_R16G16B16A16_UINT; - case PAL_VERTEX_TYPE_INT16_2NORM: return VK_FORMAT_R16G16_SNORM; @@ -1217,7 +1209,6 @@ static VkFormat vertexTypeToVkFormat(PalVertexType type) case PAL_VERTEX_TYPE_UINT16_4NORM: return VK_FORMAT_R16G16B16A16_UNORM; - case PAL_VERTEX_TYPE_FLOAT: return VK_FORMAT_R32_SFLOAT; @@ -1230,7 +1221,6 @@ static VkFormat vertexTypeToVkFormat(PalVertexType type) case PAL_VERTEX_TYPE_FLOAT4: return VK_FORMAT_R32G32B32A32_SFLOAT; - case PAL_VERTEX_TYPE_HALF_FLOAT16_2: return VK_FORMAT_R16G16_SFLOAT; @@ -1270,8 +1260,7 @@ static VkBufferUsageFlags palBufferUsageToVk(PalBufferUsages usages) if (usages & PAL_BUFFER_USAGE_RAY_TRACING) { flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - flags |= - VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; } if (usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { @@ -1467,8 +1456,7 @@ static VkBlendFactor blendFactorToVk(PalBlendFactor op) return VK_BLEND_FACTOR_ZERO; } -static VkFragmentShadingRateCombinerOpKHR combinerOpsToVk( - PalFragmentShadingRateCombinerOp op) +static VkFragmentShadingRateCombinerOpKHR combinerOpsToVk(PalFragmentShadingRateCombinerOp op) { switch (op) { case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP: @@ -1523,8 +1511,7 @@ static Barrier barrierToVk(PalUsageState state) } case PAL_USAGE_STATE_PRESENT: { - barrier.stages = - VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; + barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.dstStagess = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; barrier.access = 0; @@ -1534,8 +1521,7 @@ static Barrier barrierToVk(PalUsageState state) } case PAL_USAGE_STATE_COLOR_ATTACHMENT: { - barrier.stages = - VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; + barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.dstStagess = barrier.stages; barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR; @@ -1570,15 +1556,12 @@ static Barrier barrierToVk(PalUsageState state) } case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT: { - barrier.stages = - VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; + barrier.stages = VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; barrier.dstStagess = barrier.stages; - barrier.access = - VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; + barrier.access = VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; - barrier.layout = - VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + barrier.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; return barrier; } @@ -1792,9 +1775,7 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.libWayland = nullptr; s_Vk.libWayland = dlopen("libwayland-client.so.0", RTLD_LAZY); if (s_Vk.libWayland) { - s_Vk.getDisplayFd = (wl_display_get_fd_fn)dlsym( - s_Vk.libWayland, - "wl_display_get_fd"); + s_Vk.getDisplayFd = (wl_display_get_fd_fn)dlsym(s_Vk.libWayland, "wl_display_get_fd"); } // load vulkan @@ -2079,7 +2060,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.waitQueue = (PFN_vkQueueWaitIdle)dlsym( s_Vk.handle, "vkQueueWaitIdle"); - // clang-format on // get version @@ -2097,24 +2077,18 @@ PalResult PAL_CALL initGraphicsVk( bool hasValidationLayer = false; s_Vk.messenger = nullptr; VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {0}; - debugCreateInfo.sType = - VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; if (debugger) { // layers - result = s_Vk.enumerateInstanceLayerProperties( - &layerCount, - nullptr); + result = s_Vk.enumerateInstanceLayerProperties(&layerCount, nullptr); if (result != VK_SUCCESS) { s_Vk.hasDebug = false; } VkLayerProperties* props = nullptr; - props = palAllocate( - s_Vk.allocator, - sizeof(VkLayerProperties) * layerCount, - 0); + props = palAllocate(s_Vk.allocator, sizeof(VkLayerProperties) * layerCount, 0); if (!props) { return PAL_RESULT_OUT_OF_MEMORY; @@ -2131,19 +2105,13 @@ PalResult PAL_CALL initGraphicsVk( palFree(s_Vk.allocator, props); - debugCreateInfo.messageType |= - VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; - debugCreateInfo.messageType |= - VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; - debugCreateInfo.messageType |= - VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - debugCreateInfo.messageSeverity |= - VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; - debugCreateInfo.messageSeverity |= - VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - debugCreateInfo.messageSeverity |= - VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; debugCreateInfo.pUserData = debugger->userData; debugCreateInfo.pfnUserCallback = debugCallback; @@ -2153,29 +2121,20 @@ PalResult PAL_CALL initGraphicsVk( // extensions Uint32 extCount = 0; const char* extensions[8]; - result = s_Vk.enumerateInstanceExtensionProperties( - nullptr, - &extCount, - nullptr); + result = s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, nullptr); if (result != VK_SUCCESS) { return PAL_RESULT_PLATFORM_FAILURE; } VkExtensionProperties* extensionProps = nullptr; - extensionProps = palAllocate( - s_Vk.allocator, - sizeof(VkExtensionProperties) * extCount, - 0); + extensionProps = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extCount, 0); if (!extensionProps) { return PAL_RESULT_SUCCESS; } - s_Vk.enumerateInstanceExtensionProperties( - nullptr, - &extCount, - extensionProps); + s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, extensionProps); bool hasXlib = false; bool hasWayland = false; @@ -2251,10 +2210,7 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.vkAllocator.pfnReallocation = vkRealloc; VkInstance instance = nullptr; - result = s_Vk.createInstance( - &instanceCreateInfo, - &s_Vk.vkAllocator, - &instance); + result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.vkAllocator, &instance); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -2327,7 +2283,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.createMessenger(instance, &debugCreateInfo, &s_Vk.vkAllocator, &s_Vk.messenger); } - // clang-format on s_Vk.adapters = nullptr; @@ -2338,10 +2293,7 @@ PalResult PAL_CALL initGraphicsVk( PalResult PAL_CALL shutdownGraphicsVk() { if (s_Vk.messenger) { - s_Vk.destroyMessenger( - s_Vk.instance, - s_Vk.messenger, - &s_Vk.vkAllocator); + s_Vk.destroyMessenger(s_Vk.instance, s_Vk.messenger, &s_Vk.vkAllocator); } s_Vk.destroyInstance(s_Vk.instance, &s_Vk.vkAllocator); @@ -2367,10 +2319,7 @@ PalResult PAL_CALL enumerateVkAdapters( VkExtensionProperties* extensions = nullptr; VkPhysicalDeviceProperties props = {0}; - result = s_Vk.enumeratePhysicalDevices( - s_Vk.instance, - &deviceCount, - nullptr); + result = s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, nullptr); if (result != VK_SUCCESS) { return PAL_RESULT_PLATFORM_FAILURE; @@ -2381,14 +2330,9 @@ PalResult PAL_CALL enumerateVkAdapters( } VkPhysicalDevice* devices = nullptr; - devices = palAllocate(s_Vk.allocator, - sizeof(VkPhysicalDevice) * deviceCount, - 0); + devices = palAllocate(s_Vk.allocator, sizeof(VkPhysicalDevice) * deviceCount, 0); - s_Vk.adapters = palAllocate( - s_Vk.allocator, - sizeof(Adapter) * deviceCount, - 0); + s_Vk.adapters = palAllocate(s_Vk.allocator, sizeof(Adapter) * deviceCount, 0); if (!devices || !s_Vk.adapters) { return PAL_RESULT_OUT_OF_MEMORY; @@ -2406,10 +2350,8 @@ PalResult PAL_CALL enumerateVkAdapters( &extensionCount, nullptr); - extensions = palAllocate( - s_Vk.allocator, - sizeof(VkExtensionProperties) * extensionCount, - 0); + extensions = + palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extensionCount, 0); if (!extensions) { return PAL_RESULT_OUT_OF_MEMORY; @@ -2437,8 +2379,7 @@ PalResult PAL_CALL enumerateVkAdapters( } VkPhysicalDeviceDynamicRenderingFeaturesKHR required = {0}; - required.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; + required.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; VkPhysicalDeviceFeatures2KHR features = {0}; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; @@ -2548,8 +2489,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( VkPhysicalDeviceProperties props = {0}; VkPhysicalDeviceMultiviewPropertiesKHR multiViewProps = {0}; VkPhysicalDeviceProperties2 properties2 = {0}; - multiViewProps.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; + multiViewProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; s_Vk.getPhysicalDeviceProperties(phyDevice, &props); properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; @@ -2597,21 +2537,12 @@ PalResult PAL_CALL getVkAdapterCapabilities( // get supported queue commands Uint32 count; - s_Vk.getPhysicalDeviceQueueFamilyProperties( - phyDevice, - &count, - nullptr); + s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &count, nullptr); VkQueueFamilyProperties* queueProps = nullptr; - queueProps = palAllocate( - s_Vk.allocator, - sizeof(VkQueueFamilyProperties) * count, - 0); + queueProps = palAllocate(s_Vk.allocator, sizeof(VkQueueFamilyProperties) * count, 0); - s_Vk.getPhysicalDeviceQueueFamilyProperties( - phyDevice, - &count, - queueProps); + s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &count, queueProps); caps->maxComputeQueues = 0; caps->maxGraphicsQueues = 0; @@ -2647,11 +2578,7 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) // get supported extensions s_Vk.getPhysicalDeviceProperties(phyDevice, &props); - result = s_Vk.enumerateDeviceExtensionProperties( - phyDevice, - nullptr, - &extensionCount, - nullptr); + result = s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, nullptr); if (result != VK_SUCCESS) { // we just return without any modern features which is rare @@ -2659,20 +2586,13 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) } VkExtensionProperties* extensionProps = nullptr; - extensionProps = palAllocate( - s_Vk.allocator, - sizeof(VkExtensionProperties) * extensionCount, - 0); + extensionProps = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extensionCount, 0); if (!extensionProps) { return 0; } - s_Vk.enumerateDeviceExtensionProperties( - phyDevice, - nullptr, - &extensionCount, - extensionProps); + s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, extensionProps); // check extensions bool rayTracingFound = false; @@ -2931,8 +2851,8 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_DISPATCH_BASE; } } - // clang-format on + VkPhysicalDeviceFeatures features; s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); @@ -3005,20 +2925,11 @@ PalResult PAL_CALL createVkDevice( VkQueueFamilyProperties* queueProps = nullptr; VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; - s_Vk.getPhysicalDeviceQueueFamilyProperties( - phyDevice, - &queueCount, - nullptr); + s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueCount, nullptr); - queueProps = palAllocate( - s_Vk.allocator, - sizeof(VkQueueFamilyProperties) * queueCount, - 0); + queueProps = palAllocate(s_Vk.allocator, sizeof(VkQueueFamilyProperties) * queueCount, 0); - queueCreateInfos = palAllocate( - s_Vk.allocator, - sizeof(VkDeviceQueueCreateInfo) * queueCount, - 0); + queueCreateInfos = palAllocate(s_Vk.allocator, sizeof(VkDeviceQueueCreateInfo) * queueCount, 0); device = palAllocate(s_Vk.allocator, sizeof(Device), 0); if (!queueProps || !queueCreateInfos || !device) { @@ -3029,19 +2940,13 @@ PalResult PAL_CALL createVkDevice( device->queueCount = queueCount; device->phyDevice = phyDevice; - device->phyQueues = palAllocate( - s_Vk.allocator, - sizeof(PhysicalQueue) * queueCount, - 0); + device->phyQueues = palAllocate(s_Vk.allocator, sizeof(PhysicalQueue) * queueCount, 0); if (!device->phyQueues) { return PAL_RESULT_OUT_OF_MEMORY; } - s_Vk.getPhysicalDeviceQueueFamilyProperties( - phyDevice, - &queueCount, - queueProps); + s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueCount, queueProps); for (int i = 0; i < queueCount; i++) { queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; @@ -3091,7 +2996,6 @@ PalResult PAL_CALL createVkDevice( int extCount = 0; const char* extensions[16] = {0}; - // clang-format off VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline = {0}; timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; @@ -3136,7 +3040,6 @@ PalResult PAL_CALL createVkDevice( VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {0}; drawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; - // clang-format on if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_KHR_dynamic_rendering"; extensions[extCount++] = "VK_KHR_synchronization2"; @@ -3214,7 +3117,7 @@ PalResult PAL_CALL createVkDevice( } if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || - (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { + (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { extensions[extCount++] = "VK_KHR_fragment_shading_rate"; fsr.pipelineFragmentShadingRate = true; @@ -3300,11 +3203,7 @@ PalResult PAL_CALL createVkDevice( createInfo.queueCreateInfoCount = queueCount; createInfo.pNext = next; - result = s_Vk.createDevice( - phyDevice, - &createInfo, - &s_Vk.vkAllocator, - &device->handle); + result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.vkAllocator, &device->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, queueProps); @@ -3369,8 +3268,7 @@ PalResult PAL_CALL createVkDevice( // CPU readback score = getMemoryTypeScore( flags, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | - VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, 0, 0); @@ -3380,6 +3278,7 @@ PalResult PAL_CALL createVkDevice( } } + // clang-format off // swapchain procs if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { device->acquireNextImage = (PFN_vkAcquireNextImageKHR)s_Vk.getDeviceProcAddr( @@ -3597,6 +3496,7 @@ PalResult PAL_CALL createVkDevice( device->handle, "vkQueueSubmit2KHR"); } + // clang-format on device->features = features; palFree(s_Vk.allocator, queueProps); @@ -3656,11 +3556,8 @@ PalResult PAL_CALL allocateVkMemory( } VkDeviceMemory memory = nullptr; - VkResult result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, - &memory); + VkResult result = + s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &memory); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -3690,13 +3587,7 @@ PalResult PAL_CALL mapVkMemory( VkDeviceMemory mem = (VkDeviceMemory)memory; Device* vkDevice = (Device*)device; - result = s_Vk.mapMemory( - vkDevice->handle, - mem, - offset, - size, - 0, - outPtr); + result = s_Vk.mapMemory(vkDevice->handle, mem, offset, size, 0, outPtr); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -3726,8 +3617,7 @@ PalResult PAL_CALL queryVkDepthStencilCapabilities( properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceDepthStencilResolvePropertiesKHR props = {0}; - props.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR; properties2.pNext = &props; s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); @@ -3738,8 +3628,7 @@ PalResult PAL_CALL queryVkDepthStencilCapabilities( caps->depthResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; } - if (props.supportedDepthResolveModes & - VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { + if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { caps->depthResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; } @@ -3756,8 +3645,7 @@ PalResult PAL_CALL queryVkDepthStencilCapabilities( caps->stencilResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; } - if (props.supportedStencilResolveModes & - VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { + if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { caps->stencilResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; } @@ -3785,8 +3673,7 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceFragmentShadingRatePropertiesKHR props = {0}; - props.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; properties2.pNext = &props; s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); @@ -3795,13 +3682,11 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( for (int i = 0; i < PAL_FRAGMENT_SHADING_RATE_MAX; i++) { VkExtent2D size = getShadingRateSize((PalFragmentShadingRate)i); - // clang-format off // check against the max size if (size.width <= props.maxFragmentSize.width || size.height <= props.maxFragmentSize.height) { caps->shadingRates[i] = true; } - // clang-format on } caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP] = true; @@ -3869,12 +3754,10 @@ PalResult PAL_CALL queryVkRayTracingCapabilities( properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceRayTracingPipelinePropertiesKHR props = {0}; - props.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; - accProps.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; + accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; props.pNext = &accProps; properties2.pNext = &props; @@ -3939,8 +3822,7 @@ PalResult PAL_CALL createVkQueue( PhysicalQueue* pq = &vkDevice->phyQueues[i]; // check if the physical queue supports the requested operation // and if its not already used - if (pq->usages & queueFlag && - pq->usedUsages != queueFlag) { + if (pq->usages & queueFlag && pq->usedUsages != queueFlag) { pq->usedUsages |= queueFlag; phyQueue = pq; break; @@ -3989,13 +3871,13 @@ bool PAL_CALL canVkQueuePresent( } else if (platform == VK_WAYLAND_PLATFORM) { if (s_Vk.checkWaylandPresentSupport( - phyQueue->phyDevice, - phyQueue->familyIndex, window->display)) { + phyQueue->phyDevice, + phyQueue->familyIndex, + window->display)) { return true; } } else if (platform == VK_XLIB_PLATFORM) { - } return false; } @@ -4034,8 +3916,7 @@ PalResult PAL_CALL enumerateVkFormats( if (fmtCount < *count) { PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; fmtInfo->format = (PalFormat)i; - fmtInfo->usages = - vkFeatureToPalUsage(props.optimalTilingFeatures); + fmtInfo->usages = vkFeatureToPalUsage(props.optimalTilingFeatures); PalImageViewUsages usages = 0; if (i == PAL_FORMAT_S8_UINT) { @@ -4046,8 +3927,7 @@ PalResult PAL_CALL enumerateVkFormats( usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; } - if (i == PAL_FORMAT_D32_SFLOAT_S8_UINT || - i == PAL_FORMAT_D16_UNORM_S8_UINT || + if (i == PAL_FORMAT_D32_SFLOAT_S8_UINT || i == PAL_FORMAT_D16_UNORM_S8_UINT || i == PAL_FORMAT_D24_UNORM_S8_UINT) { usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; @@ -4135,8 +4015,7 @@ PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; } - if (format == PAL_FORMAT_D32_SFLOAT_S8_UINT || - format == PAL_FORMAT_D16_UNORM_S8_UINT || + if (format == PAL_FORMAT_D32_SFLOAT_S8_UINT || format == PAL_FORMAT_D16_UNORM_S8_UINT || format == PAL_FORMAT_D24_UNORM_S8_UINT) { usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; @@ -4198,11 +4077,7 @@ PalResult PAL_CALL createVkImage( createInfo.extent.depth = info->depthOrArraySize; } - result = s_Vk.createImage( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &image->handle); + result = s_Vk.createImage(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &image->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, image); @@ -4231,10 +4106,7 @@ void PAL_CALL destroyVkImage(PalImage* image) return; } - s_Vk.destroyImage( - vkImage->device->handle, - vkImage->handle, - &s_Vk.vkAllocator); + s_Vk.destroyImage(vkImage->device->handle, vkImage->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkImage); } @@ -4283,12 +4155,12 @@ PalResult PAL_CALL getVkImageMemoryRequirements( } if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { + prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; } if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; } } @@ -4306,11 +4178,7 @@ PalResult PAL_CALL bindVkImageMemory( } VkDeviceMemory mem = (VkDeviceMemory)memory; - s_Vk.bindImageMemory( - vkImage->device->handle, - vkImage->handle, - mem, - offset); + s_Vk.bindImageMemory(vkImage->device->handle, vkImage->handle, mem, offset); } // ================================================== @@ -4329,8 +4197,7 @@ PalResult PAL_CALL createVkImageView( Image* vkImage = (Image*)image; if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - if (!(vkDevice->features & - PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } @@ -4365,11 +4232,8 @@ PalResult PAL_CALL createVkImageView( } createInfo.subresourceRange.aspectMask = aspectFlags; - result = s_Vk.createImageView( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &imageView->handle); + result = + s_Vk.createImageView(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &imageView->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, imageView); @@ -4389,10 +4253,7 @@ PalResult PAL_CALL createVkImageView( void PAL_CALL destroyVkImageView(PalImageView* imageView) { ImageView* vkImageView = (ImageView*)imageView; - s_Vk.destroyImageView( - vkImageView->device->handle, - vkImageView->handle, - &s_Vk.vkAllocator); + s_Vk.destroyImageView(vkImageView->device->handle, vkImageView->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkImageView); } @@ -4427,15 +4288,9 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, nullptr); s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, nullptr); - modes = palAllocate( - s_Vk.allocator, - sizeof(VkPresentModeKHR) * modeCount, - 0); + modes = palAllocate(s_Vk.allocator, sizeof(VkPresentModeKHR) * modeCount, 0); - formats = palAllocate( - s_Vk.allocator, - sizeof(VkSurfaceFormatKHR) * formatCount, - 0); + formats = palAllocate(s_Vk.allocator, sizeof(VkSurfaceFormatKHR) * formatCount, 0); if (!modes || !formats) { s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.vkAllocator); @@ -4489,7 +4344,6 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( } } - // clang-format off // get format and colorspace caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = false; caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB] = false; @@ -4523,7 +4377,6 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( } } } - // clang-format on palFree(s_Vk.allocator, formats); palFree(s_Vk.allocator, modes); @@ -4624,10 +4477,7 @@ PalResult PAL_CALL createVkSwapchain( &swapchain->handle); if (result != VK_SUCCESS) { - s_Vk.destroySurface( - s_Vk.instance, - swapchain->surface, - &s_Vk.vkAllocator); + s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.vkAllocator); palFree(s_Vk.allocator, swapchain); return vkResultToPal(result); @@ -4635,43 +4485,22 @@ PalResult PAL_CALL createVkSwapchain( // get and cache all images Int32 count = 0; - result = vkDevice->getSwapchainImages( - vkDevice->handle, - swapchain->handle, - &count, - nullptr); + result = vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, nullptr); - swapchain->images = palAllocate( - s_Vk.allocator, - sizeof(Image) * count, - 0); + swapchain->images = palAllocate(s_Vk.allocator, sizeof(Image) * count, 0); - images = palAllocate( - s_Vk.allocator, - sizeof(VkImage) * count, - 0); + images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); if (!swapchain->images || !images) { - vkDevice->destroySwapchain( - vkDevice->handle, - swapchain->handle, - &s_Vk.vkAllocator - ); + vkDevice->destroySwapchain(vkDevice->handle, swapchain->handle, &s_Vk.vkAllocator); - s_Vk.destroySurface( - s_Vk.instance, - swapchain->surface, - &s_Vk.vkAllocator); + s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.vkAllocator); palFree(s_Vk.allocator, swapchain); return PAL_RESULT_OUT_OF_MEMORY; } - vkDevice->getSwapchainImages( - vkDevice->handle, - swapchain->handle, - &count, - images); + vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, images); // fill all images with the creatio info for (int i = 0; i < count; i++) { @@ -4704,14 +4533,10 @@ void PAL_CALL destroyVkSwapchain(PalSwapchain* swapchain) vkSwapchain->device->destroySwapchain( vkSwapchain->device->handle, vkSwapchain->handle, - &s_Vk.vkAllocator - ); - - s_Vk.destroySurface( - s_Vk.instance, - vkSwapchain->surface, &s_Vk.vkAllocator); + s_Vk.destroySurface(s_Vk.instance, vkSwapchain->surface, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkSwapchain->images); palFree(s_Vk.allocator, vkSwapchain); } @@ -4786,9 +4611,7 @@ PalResult PAL_CALL presentVkSwapchain( presentInfo.pWaitSemaphores = &semaphoreHandle; presentInfo.waitSemaphoreCount = semaphoreCount; - result = vkSwapchain->device->queuePresent( - vkSwapchain->queue->phyQueue->handle, - &presentInfo); + result = vkSwapchain->device->queuePresent(vkSwapchain->queue->phyQueue->handle, &presentInfo); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -4861,11 +4684,7 @@ PalResult PAL_CALL createVkShader( createInfo.codeSize = info->bytecodeSize; createInfo.pCode = (const Uint32*)info->bytecode; - result = s_Vk.createShader( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &shader->handle); + result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, shader); @@ -4886,10 +4705,7 @@ PalResult PAL_CALL createVkShader( void PAL_CALL destroyVkShader(PalShader* shader) { Shader* vkShader = (Shader*)shader; - s_Vk.destroyShader( - vkShader->device->handle, - vkShader->handle, - &s_Vk.vkAllocator); + s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkShader); } @@ -4918,11 +4734,7 @@ PalResult PAL_CALL createVkFence( createInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; } - result = s_Vk.createFence( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &fence->handle); + result = s_Vk.createFence(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &fence->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, fence); @@ -4937,10 +4749,7 @@ PalResult PAL_CALL createVkFence( void PAL_CALL destroyVkFence(PalFence* fence) { Fence* vkFence = (Fence*)fence; - s_Vk.destroyFence( - vkFence->device->handle, - vkFence->handle, - &s_Vk.vkAllocator); + s_Vk.destroyFence(vkFence->device->handle, vkFence->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkFence); } @@ -4956,12 +4765,7 @@ PalResult PAL_CALL waitVkFence( } } - VkResult result = s_Vk.waitFence( - vkFence->device->handle, - 1, - &vkFence->handle, - true, - timeout); + VkResult result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, true, timeout); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -4977,10 +4781,7 @@ PalResult PAL_CALL resetVkFence(PalFence* fence) return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - VkResult result = s_Vk.resetFence( - vkFence->device->handle, - 1, - &vkFence->handle); + VkResult result = s_Vk.resetFence(vkFence->device->handle, 1, &vkFence->handle); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -4992,9 +4793,7 @@ PalResult PAL_CALL resetVkFence(PalFence* fence) bool PAL_CALL isVkFenceSignaled(PalFence* fence) { Fence* vkFence = (Fence*)fence; - VkResult result = s_Vk.isFenceSignaled( - vkFence->device->handle, - vkFence->handle); + VkResult result = s_Vk.isFenceSignaled(vkFence->device->handle, vkFence->handle); if (result == VK_SUCCESS) { return true; @@ -5035,11 +4834,8 @@ PalResult PAL_CALL createVkSemaphore( } createInfo.pNext = next; - result = s_Vk.createSemaphore( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &semaphore->handle); + result = + s_Vk.createSemaphore(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &semaphore->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, semaphore); @@ -5054,10 +4850,7 @@ PalResult PAL_CALL createVkSemaphore( void PAL_CALL destroyVkSemaphore(PalSemaphore* semaphore) { Semaphore* vkSemaphore = (Semaphore*)semaphore; - s_Vk.destroySemaphore( - vkSemaphore->device->handle, - vkSemaphore->handle, - &s_Vk.vkAllocator); + s_Vk.destroySemaphore(vkSemaphore->device->handle, vkSemaphore->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkSemaphore); } @@ -5070,8 +4863,7 @@ PalResult PAL_CALL waitVkSemaphore( { VkResult result; Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!(vkSemaphore->device->features & - PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { + if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5081,10 +4873,7 @@ PalResult PAL_CALL waitVkSemaphore( waitInfo.pSemaphores = &vkSemaphore->handle; waitInfo.pValues = &value; - result = vkSemaphore->device->waitSemaphore( - vkSemaphore->device->handle, - &waitInfo, - timeout); + result = vkSemaphore->device->waitSemaphore(vkSemaphore->device->handle, &waitInfo, timeout); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -5100,8 +4889,7 @@ PalResult PAL_CALL signalVkSemaphore( { VkResult result; Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!(vkSemaphore->device->features & - PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { + if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5110,9 +4898,7 @@ PalResult PAL_CALL signalVkSemaphore( signalInfo.semaphore = vkSemaphore->handle; signalInfo.value = value; - result = vkSemaphore->device->signalSemaphore( - vkSemaphore->device->handle, - &signalInfo); + result = vkSemaphore->device->signalSemaphore(vkSemaphore->device->handle, &signalInfo); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -5126,8 +4912,7 @@ PalResult PAL_CALL getVkSemaphoreValue( Uint64* value) { Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!(vkSemaphore->device->features & - PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { + if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5168,11 +4953,8 @@ PalResult PAL_CALL createVkCommandPool( createInfo.queueFamilyIndex = phyQueue->familyIndex; createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - result = s_Vk.createCommandPool( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &pool->handle); + result = + s_Vk.createCommandPool(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &pool->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pool); @@ -5187,10 +4969,7 @@ PalResult PAL_CALL createVkCommandPool( void PAL_CALL destroyVkCommandPool(PalCommandPool* pool) { CommandPool* vkPool = (CommandPool*)pool; - s_Vk.destroyCommandPool( - vkPool->device->handle, - vkPool->handle, - &s_Vk.vkAllocator); + s_Vk.destroyCommandPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkPool); } @@ -5230,10 +5009,7 @@ PalResult PAL_CALL createVkCommandBuffer( cmdBuffer->primary = false; } - result = s_Vk.createCommandBuffer( - vkDevice->handle, - &createInfo, - &cmdBuffer->handle); + result = s_Vk.createCommandBuffer(vkDevice->handle, &createInfo, &cmdBuffer->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, cmdBuffer); @@ -5270,8 +5046,7 @@ PalResult PAL_CALL beginVkCommandBuffer( VkCommandBufferInheritanceInfo inheritanceInfo = {0}; inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; VkCommandBufferInheritanceRenderingInfoKHR layout = {0}; - layout.sType = - VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; + layout.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; VkFormat format = VK_FORMAT_UNDEFINED; VkFormat colorAttachments[MAX_ATTACHMENTS]; @@ -5336,10 +5111,7 @@ PalResult PAL_CALL executeCommandBufferVk( { CommandBuffer* vkCmdBuffer = (CommandBuffer*)primaryCmdBuffer; CommandBuffer* vkCmdBuffer2 = (CommandBuffer*)secondaryCmdBuffer; - s_Vk.cmdExecuteCommandBuffer( - vkCmdBuffer->handle, - 1, - &vkCmdBuffer2->handle); + s_Vk.cmdExecuteCommandBuffer(vkCmdBuffer->handle, 1, &vkCmdBuffer2->handle); return PAL_RESULT_SUCCESS; } @@ -5349,8 +5121,7 @@ PalResult PAL_CALL setVkFragmentShadingRate( PalFragmentShadingRateState* state) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & - PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5365,8 +5136,7 @@ PalResult PAL_CALL setVkFragmentShadingRate( } case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE: { - combinerOps[i] = - VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; + combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; continue; } @@ -5385,14 +5155,11 @@ PalResult PAL_CALL setVkFragmentShadingRate( continue; } - combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; + combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; } } - vkCmdBuffer->device->cmdSetFragmentShadingRate( - vkCmdBuffer->handle, - &size, - combinerOps); + vkCmdBuffer->device->cmdSetFragmentShadingRate(vkCmdBuffer->handle, &size, combinerOps); return PAL_RESULT_SUCCESS; } @@ -5408,11 +5175,8 @@ PalResult PAL_CALL drawVkMeshTasks( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - vkCmdBuffer->device->cmdDrawMeshTask( - vkCmdBuffer->handle, - groupCountX, - groupCountY, - groupCountZ); + vkCmdBuffer->device + ->cmdDrawMeshTask(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); return PAL_RESULT_SUCCESS; } @@ -5430,12 +5194,8 @@ PalResult PAL_CALL drawVkMeshTasksIndirect( } Buffer* vkBuffer = (Buffer*)buffer; - vkCmdBuffer->device->cmdDrawMeshTaskIndirect( - vkCmdBuffer->handle, - vkBuffer->handle, - offset, - drawCount, - stride); + vkCmdBuffer->device + ->cmdDrawMeshTaskIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset, drawCount, stride); return PAL_RESULT_SUCCESS; } @@ -5450,8 +5210,7 @@ PalResult PAL_CALL drawVkMeshTasksIndirectCount( Uint32 stride) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5498,7 +5257,6 @@ PalResult PAL_CALL buildVkAccelerationStructure( return PAL_RESULT_OUT_OF_MEMORY; } - // clang-format off for (int i = 0; i < info->geometryCount; i++) { // fill vulkan geometry struct VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; @@ -5536,8 +5294,7 @@ PalResult PAL_CALL buildVkAccelerationStructure( tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; data->pNext = nullptr; - data->sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; VkDeviceOrHostAddressConstKHR address = {0}; PalGeometryDataAABBS* tmpData = info->geometries[i].data; @@ -5551,8 +5308,7 @@ PalResult PAL_CALL buildVkAccelerationStructure( VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; data = &tmp->geometry.instances; data->pNext = nullptr; - data->sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; VkDeviceOrHostAddressConstKHR address = {0}; PalGeometryDataInstance* tmpData = info->geometries[i].data; @@ -5564,15 +5320,13 @@ PalResult PAL_CALL buildVkAccelerationStructure( // range info VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; rangeInfo->primitiveCount = info->geometries[i].primitiveCount; - rangeInfo->firstVertex = 0; // PAL does not allow setting this + rangeInfo->firstVertex = 0; // PAL does not allow setting this rangeInfo->primitiveOffset = 0; // PAL does not allow setting this rangeInfo->transformOffset = 0; // PAL does not allow setting this } - // clang-format on VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - buildInfo.sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; @@ -5585,8 +5339,7 @@ PalResult PAL_CALL buildVkAccelerationStructure( buildInfo.dstAccelerationStructure = as->handle; VkDeviceOrHostAddressKHR scratchData = {0}; - scratchData.deviceAddress = - scratchBuffer->address + info->scratchBufferOffset; + scratchData.deviceAddress = scratchBuffer->address + info->scratchBufferOffset; buildInfo.scratchData = scratchData; buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; @@ -5594,11 +5347,7 @@ PalResult PAL_CALL buildVkAccelerationStructure( const VkAccelerationStructureBuildRangeInfoKHR* tmp[1]; tmp[0] = rangeInfos; - vkCmdBuffer->device->cmdBuildAccelerationStructures( - vkCmdBuffer->handle, - 1, - &buildInfo, - tmp); + vkCmdBuffer->device->cmdBuildAccelerationStructures(vkCmdBuffer->handle, 1, &buildInfo, tmp); palFree(s_Vk.allocator, geometries); palFree(s_Vk.allocator, rangeInfos); @@ -5625,8 +5374,7 @@ PalResult PAL_CALL beginRenderingVk( VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL; VkRenderingFragmentShadingRateAttachmentInfoKHR fsrInfo = {0}; - fsrInfo.sType = - VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; + fsrInfo.sType = VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; for (int i = 0; i < info->colorAttachentCount; i++) { attachment = &colorAttachments[i]; @@ -5769,8 +5517,7 @@ PalResult PAL_CALL beginRenderingVk( // fragment shading rate attachment if (info->fragmentShadingRateAttachment) { - imageView = - (ImageView*)info->fragmentShadingRateAttachment->imageView; + imageView = (ImageView*)info->fragmentShadingRateAttachment->imageView; fsrInfo.imageView = imageView->handle; fsrInfo.shadingRateAttachmentTexelSize.width = @@ -5779,8 +5526,7 @@ PalResult PAL_CALL beginRenderingVk( fsrInfo.shadingRateAttachmentTexelSize.height = info->fragmentShadingRateAttachment->texelHeight; - fsrInfo.imageLayout = - VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + fsrInfo.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; rendering.pNext = &fsrInfo; } @@ -5824,12 +5570,7 @@ PalResult PAL_CALL copyVkBuffer( copyRegion.size = size; copyRegion.dstOffset = dstOffset; copyRegion.srcOffset = srcOffset; - s_Vk.cmdCopyBuffer( - vkCmdBuffer->handle, - srcBuffer->handle, - dstbuffer->handle, - 1, - ©Region); + s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, srcBuffer->handle, dstbuffer->handle, 1, ©Region); return PAL_RESULT_SUCCESS; } @@ -5862,10 +5603,7 @@ PalResult PAL_CALL setVkViewport( VkViewport* vkViewports = nullptr; if (count > 1) { - vkViewports = palAllocate( - s_Vk.allocator, - sizeof(VkViewport) * count, - 0); + vkViewports = palAllocate(s_Vk.allocator, sizeof(VkViewport) * count, 0); if (!vkViewports) { return PAL_RESULT_OUT_OF_MEMORY; @@ -5902,10 +5640,7 @@ PalResult PAL_CALL setVkScissors( VkRect2D* vkScissors = nullptr; if (count > 1) { - vkScissors = palAllocate( - s_Vk.allocator, - sizeof(VkRect2D) * count, - 0); + vkScissors = palAllocate(s_Vk.allocator, sizeof(VkRect2D) * count, 0); if (!vkScissors) { return PAL_RESULT_OUT_OF_MEMORY; @@ -5956,12 +5691,7 @@ PalResult PAL_CALL bindVkVertexBuffers( vkBuffers[i] = tmp->handle; } - s_Vk.bindVertexBuffers( - vkCmdBuffer->handle, - firstSlot, - count, - vkBuffers, - offsets); + s_Vk.bindVertexBuffers(vkCmdBuffer->handle, firstSlot, count, vkBuffers, offsets); if (count > 1) { palFree(s_Vk.allocator, vkBuffers); @@ -5982,11 +5712,7 @@ PalResult PAL_CALL bindVkIndexBuffer( bufferType = VK_INDEX_TYPE_UINT16; } - s_Vk.bindIndexBuffer( - vkCmdBuffer->handle, - vkBuffer->handle, - offset, - bufferType); + s_Vk.bindIndexBuffer(vkCmdBuffer->handle, vkBuffer->handle, offset, bufferType); return PAL_RESULT_SUCCESS; } @@ -6016,12 +5742,7 @@ PalResult PAL_CALL drawIndirectVk( Buffer* vkBuffer = (Buffer*)buffer; Uint32 stride = sizeof(VkDrawIndirectCommand); - s_Vk.cmdDrawIndirect( - vkCmdBuffer->handle, - vkBuffer->handle, - offset, - count, - stride); + s_Vk.cmdDrawIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset, count, stride); return PAL_RESULT_SUCCESS; } @@ -6039,8 +5760,7 @@ PalResult PAL_CALL drawIndirectCountVk( Buffer* vkCountBuffer = (Buffer*)countBuffer; Uint32 stride = sizeof(VkDrawIndirectCommand); - if (!(vkCmdBuffer->device->features & - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6082,12 +5802,7 @@ PalResult PAL_CALL drawIndexedIndirectVk( Buffer* vkBuffer = (Buffer*)buffer; Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); - s_Vk.cmdDrawIndexedIndirect( - vkCmdBuffer->handle, - vkBuffer->handle, - offset, - count, - stride); + s_Vk.cmdDrawIndexedIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset, count, stride); return PAL_RESULT_SUCCESS; } @@ -6105,8 +5820,7 @@ PalResult PAL_CALL drawIndexedIndirectCountVk( Buffer* vkCountBuffer = (Buffer*)countBuffer; Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); - if (!(vkCmdBuffer->device->features & - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6153,9 +5867,7 @@ PalResult PAL_CALL imageViewBarrierVk( dependencyInfo.imageMemoryBarrierCount = 1; dependencyInfo.pImageMemoryBarriers = &barrier; - vkCmdBuffer->device->cmdPipelineBarrier( - vkCmdBuffer->handle, - &dependencyInfo); + vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); vkCmdBuffer->dstStage = new.stages; return PAL_RESULT_SUCCESS; @@ -6191,9 +5903,7 @@ PalResult PAL_CALL bufferBarrierVk( dependencyInfo.bufferMemoryBarrierCount = 1; dependencyInfo.pBufferMemoryBarriers = &barrier; - vkCmdBuffer->device->cmdPipelineBarrier( - vkCmdBuffer->handle, - &dependencyInfo); + vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); vkCmdBuffer->dstStage = new.stages; return PAL_RESULT_SUCCESS; @@ -6206,11 +5916,7 @@ PalResult PAL_CALL dispatchVk( Uint32 groupCountZ) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - s_Vk.cmdDispatch( - vkCmdBuffer->handle, - groupCountX, - groupCountY, - groupCountZ); + s_Vk.cmdDispatch(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); return PAL_RESULT_SUCCESS; } @@ -6287,8 +5993,7 @@ PalResult PAL_CALL submitVkCommandBuffer( VkCommandBufferSubmitInfoKHR cmdBufferSubmitInfo = {0}; cmdBufferSubmitInfo.commandBuffer = vkCmdBuffer->handle; - cmdBufferSubmitInfo.sType = - VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR; + cmdBufferSubmitInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR; VkSemaphoreSubmitInfoKHR waitSubmitInfo = {0}; waitSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; @@ -6300,8 +6005,7 @@ PalResult PAL_CALL submitVkCommandBuffer( signalSubmitInfo.semaphore = signalSemaphoreHandle; signalSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - if (vkCmdBuffer->device->features & - PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { waitSubmitInfo.value = info->waitValue; signalSubmitInfo.value = info->signalValue; } @@ -6315,11 +6019,8 @@ PalResult PAL_CALL submitVkCommandBuffer( submitInfo.waitSemaphoreInfoCount = waitSemaphoreCount; submitInfo.signalSemaphoreInfoCount = signalSemaphoreCount; - result = vkCmdBuffer->device->queueSubmit( - vkQueue->phyQueue->handle, - 1, - &submitInfo, - fenceHandle); + result = + vkCmdBuffer->device->queueSubmit(vkQueue->phyQueue->handle, 1, &submitInfo, fenceHandle); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -6356,8 +6057,7 @@ PalResult PAL_CALL createVkAccelerationstructure( } VkAccelerationStructureCreateInfoKHR createInfo = {0}; - createInfo.sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; + createInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; createInfo.offset = (VkDeviceSize)info->offset; createInfo.size = (VkDeviceSize)info->size; @@ -6381,21 +6081,17 @@ PalResult PAL_CALL createVkAccelerationstructure( // get and cache address VkAccelerationStructureDeviceAddressInfoKHR addressInfo = {0}; - addressInfo.sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; + addressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; addressInfo.accelerationStructure = as->handle; - as->address = vkDevice->getAccelerationDeviceAddress( - vkDevice->handle, - &addressInfo); + as->address = vkDevice->getAccelerationDeviceAddress(vkDevice->handle, &addressInfo); as->device = vkDevice; *outAs = (PalAccelerationStructure*)as; return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkAccelerationstructure( - PalAccelerationStructure* as) +void PAL_CALL destroyVkAccelerationstructure(PalAccelerationStructure* as) { AccelerationStructure* vkAs = (AccelerationStructure*)as; vkAs->device->destroyAccelerationStructure( @@ -6422,10 +6118,7 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - maxPrimities = palAllocate( - s_Vk.allocator, - sizeof(Uint32) * info->geometryCount, - 0); + maxPrimities = palAllocate(s_Vk.allocator, sizeof(Uint32) * info->geometryCount, 0); geometries = palAllocate( s_Vk.allocator, @@ -6436,7 +6129,6 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( return PAL_RESULT_OUT_OF_MEMORY; } - // clang-format off for (int i = 0; i < info->geometryCount; i++) { maxPrimities[i] = info->geometries[i].primitiveCount; @@ -6476,8 +6168,7 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; data->pNext = nullptr; - data->sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; VkDeviceOrHostAddressConstKHR address = {0}; PalGeometryDataAABBS* tmpData = info->geometries[i].data; @@ -6491,8 +6182,7 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; data = &tmp->geometry.instances; data->pNext = nullptr; - data->sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; VkDeviceOrHostAddressConstKHR address = {0}; PalGeometryDataInstance* tmpData = info->geometries[i].data; @@ -6501,11 +6191,9 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( data->data = address; } } - // clang-format on VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - buildInfo.sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; @@ -6518,16 +6206,14 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( buildInfo.dstAccelerationStructure = vkAs->handle; VkDeviceOrHostAddressKHR scratchData = {0}; - scratchData.deviceAddress = - vkScratchBuffer->address + info->scratchBufferOffset; + scratchData.deviceAddress = vkScratchBuffer->address + info->scratchBufferOffset; buildInfo.scratchData = scratchData; buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; buildInfo.pGeometries = geometries; VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; - sizeInfo.sType = - VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; + sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; vkDevice->getAccelerationBuildsize( vkDevice->handle, @@ -6564,8 +6250,7 @@ PalResult PAL_CALL createVkBuffer( // buffer device address feature is supported if ray tracing is } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - if (!(vkDevice->features & - PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } @@ -6581,11 +6266,7 @@ PalResult PAL_CALL createVkBuffer( createInfo.size = info->size; createInfo.usage = palBufferUsageToVk(info->usages); - result = s_Vk.createBuffer( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &buffer->handle); + result = s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &buffer->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, buffer); @@ -6598,8 +6279,7 @@ PalResult PAL_CALL createVkBuffer( VkBufferDeviceAddressInfoKHR bufferInfo = {0}; bufferInfo.buffer = buffer->handle; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; - buffer->address = - vkDevice->getBufferrAddress(vkDevice->handle, &bufferInfo); + buffer->address = vkDevice->getBufferrAddress(vkDevice->handle, &bufferInfo); } buffer->device = vkDevice; @@ -6610,10 +6290,7 @@ PalResult PAL_CALL createVkBuffer( void PAL_CALL destroyVkBuffer(PalBuffer* buffer) { Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.destroyBuffer( - vkBuffer->device->handle, - vkBuffer->handle, - &s_Vk.vkAllocator); + s_Vk.destroyBuffer(vkBuffer->device->handle, vkBuffer->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, buffer); } @@ -6629,10 +6306,7 @@ PalResult PAL_CALL getVkBufferMemoryRequirements( s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); VkMemoryRequirements memReq = {0}; - s_Vk.getBufferMemoryRequirements( - device->handle, - vkBuffer->handle, - &memReq); + s_Vk.getBufferMemoryRequirements(device->handle, vkBuffer->handle, &memReq); requirements->alignment = (Uint64)memReq.alignment; requirements->size = (Uint64)memReq.size; @@ -6653,12 +6327,12 @@ PalResult PAL_CALL getVkBufferMemoryRequirements( } if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { + prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; } if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; } } @@ -6673,11 +6347,7 @@ PalResult PAL_CALL bindVkBufferMemory( VkResult result; VkDeviceMemory mem = (VkDeviceMemory)memory; Buffer* vkBuffer = (Buffer*)buffer; - result = s_Vk.bindBufferMemory( - vkBuffer->device->handle, - vkBuffer->handle, - mem, - offset); + result = s_Vk.bindBufferMemory(vkBuffer->device->handle, vkBuffer->handle, mem, offset); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -6749,7 +6419,6 @@ PalResult PAL_CALL createVkGraphicsPipeline( VkVertexInputAttributeDescription* attribDescs = nullptr; VkPipelineColorBlendAttachmentState* blendattachments = nullptr; - // clang-format off VkPipelineVertexInputStateCreateInfo vertexInputState = {0}; vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; @@ -6778,7 +6447,8 @@ PalResult PAL_CALL createVkGraphicsPipeline( viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; VkPipelineFragmentShadingRateStateCreateInfoKHR fragmentShadingRateState = {0}; - fragmentShadingRateState.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; + fragmentShadingRateState.sType = + VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; VkPipelineRenderingCreateInfoKHR dynRendering = {0}; dynRendering.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR; @@ -6786,7 +6456,6 @@ PalResult PAL_CALL createVkGraphicsPipeline( VkGraphicsPipelineCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - // clang-format on pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); if (!pipeline) { return PAL_RESULT_OUT_OF_MEMORY; @@ -6825,10 +6494,8 @@ PalResult PAL_CALL createVkGraphicsPipeline( sizeof(VkVertexInputBindingDescription) * info->vertexLayoutCount, 0); - attribDescs = palAllocate( - s_Vk.allocator, - sizeof(VkVertexInputAttributeDescription) * vertexCount, - 0); + attribDescs = + palAllocate(s_Vk.allocator, sizeof(VkVertexInputAttributeDescription) * vertexCount, 0); if (!bindingDescs || !attribDescs) { palFree(s_Vk.allocator, pipeline); @@ -7003,7 +6670,6 @@ PalResult PAL_CALL createVkGraphicsPipeline( sampleMasks[1] = mask2; multisampleState.pSampleMask = sampleMasks; - } else { multisampleState.alphaToCoverageEnable = VK_FALSE; multisampleState.minSampleShading = VK_FALSE; @@ -7048,10 +6714,8 @@ PalResult PAL_CALL createVkGraphicsPipeline( // Color blend state if (info->blendAttachmentCount) { Uint32 count = info->blendAttachmentCount; - blendattachments = palAllocate( - s_Vk.allocator, - sizeof(VkPipelineColorBlendAttachmentState) * count, - 0); + blendattachments = + palAllocate(s_Vk.allocator, sizeof(VkPipelineColorBlendAttachmentState) * count, 0); if (!blendattachments) { palFree(s_Vk.allocator, pipeline); @@ -7068,15 +6732,11 @@ PalResult PAL_CALL createVkGraphicsPipeline( tmp->alphaBlendOp = blendOpToVk(desc->alphaBlendOp); tmp->colorBlendOp = blendOpToVk(desc->colorBlendOp); - tmp->srcAlphaBlendFactor = - blendFactorToVk(desc->srcAlphaBlendFactor); - tmp->srcColorBlendFactor = - blendFactorToVk(desc->srcColorBlendFactor); + tmp->srcAlphaBlendFactor = blendFactorToVk(desc->srcAlphaBlendFactor); + tmp->srcColorBlendFactor = blendFactorToVk(desc->srcColorBlendFactor); - tmp->dstAlphaBlendFactor = - blendFactorToVk(desc->dstAlphaBlendFactor); - tmp->dstColorBlendFactor = - blendFactorToVk(desc->dstColorBlendFactor); + tmp->dstAlphaBlendFactor = blendFactorToVk(desc->dstAlphaBlendFactor); + tmp->dstColorBlendFactor = blendFactorToVk(desc->dstColorBlendFactor); // blend color write mask tmp->colorWriteMask = 0; @@ -7177,10 +6837,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( void PAL_CALL destroyVkPipeline(PalPipeline* pipeline) { Pipeline* vkPipeline = (Pipeline*)pipeline; - s_Vk.destroyPipeline( - vkPipeline->device->handle, - vkPipeline->handle, - &s_Vk.vkAllocator); + s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, pipeline); } diff --git a/src/opengl/pal_opengl_linux.c b/src/opengl/pal_opengl_linux.c index b061850f..89661ea9 100644 --- a/src/opengl/pal_opengl_linux.c +++ b/src/opengl/pal_opengl_linux.c @@ -308,10 +308,7 @@ static ContextData* getFreeContextData() int freeIndex = s_GL.maxContextData + 1; data = palAllocate(s_GL.allocator, sizeof(ContextData) * count, 0); if (data) { - memcpy( - data, - s_GL.contextData, - s_GL.maxContextData * sizeof(ContextData)); + memcpy(data, s_GL.contextData, s_GL.maxContextData * sizeof(ContextData)); palFree(s_GL.allocator, s_GL.contextData); s_GL.contextData = data; @@ -326,8 +323,7 @@ static ContextData* getFreeContextData() static ContextData* findContextData(PalGLContext* context) { for (int i = 0; i < s_GL.maxContextData; ++i) { - if (s_GL.contextData[i].used && - s_GL.contextData[i].context == context) { + if (s_GL.contextData[i].used && s_GL.contextData[i].context == context) { return &s_GL.contextData[i]; } } @@ -336,8 +332,7 @@ static ContextData* findContextData(PalGLContext* context) static void freeContextData(PalGLContext* context) { for (int i = 0; i < s_GL.maxContextData; ++i) { - if (s_GL.contextData[i].used && - s_GL.contextData[i].context == context) { + if (s_GL.contextData[i].used && s_GL.contextData[i].context == context) { s_GL.contextData[i].used = false; } } @@ -365,10 +360,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) } s_GL.maxContextData = 16; // initial size - s_GL.contextData = palAllocate( - s_GL.allocator, - sizeof(ContextData) * s_GL.maxContextData, - 0); + s_GL.contextData = palAllocate(s_GL.allocator, sizeof(ContextData) * s_GL.maxContextData, 0); if (!s_GL.maxContextData) { return PAL_RESULT_OUT_OF_MEMORY; @@ -381,7 +373,6 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) } // clang-format off - s_GL.eglGetProcAddress = (eglGetProcAddressFn)dlsym( s_GL.handle, "eglGetProcAddress"); @@ -457,6 +448,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; } + // clang-format on // get backend type const char* session = getenv("XDG_SESSION_TYPE"); @@ -477,7 +469,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) } EGLDisplay display = s_GL.eglGetDisplay(s_GL.platformDisplay); - EGLDisplay * tmpDisplay = EGL_NO_DISPLAY; + EGLDisplay* tmpDisplay = EGL_NO_DISPLAY; if (display == EGL_NO_DISPLAY) { palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; @@ -492,12 +484,8 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) EGLConfig config; int numConfigs; EGLint type; - EGLint attribs[] = { - EGL_RENDERABLE_TYPE, - s_GL.apiTypeBit, - EGL_SURFACE_TYPE, - EGL_PBUFFER_BIT, - EGL_NONE}; + EGLint attribs[] = + {EGL_RENDERABLE_TYPE, s_GL.apiTypeBit, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_NONE}; s_GL.eglChooseConfig(display, attribs, &config, 1, &numConfigs); if (!config || numConfigs == 0) { @@ -542,15 +530,9 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) } EGLSurface surface = EGL_NO_SURFACE; - EGLint pBufferAttribs[] = { - EGL_WIDTH, 1, - EGL_HEIGHT, 1, - EGL_NONE}; + EGLint pBufferAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; - surface = s_GL.eglCreatePbufferSurface( - tmpDisplay, - config, - pBufferAttribs); + surface = s_GL.eglCreatePbufferSurface(tmpDisplay, config, pBufferAttribs); if (surface == EGL_NO_SURFACE) { palSetLastPlatformError(errno); @@ -560,27 +542,15 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) // create a dummy context EGLContext context = EGL_NO_CONTEXT; if (s_GL.apiType == EGL_OPENGL_API) { - EGLint contextAttrib[] = { - EGL_CONTEXT_MAJOR_VERSION, 2, - EGL_CONTEXT_MINOR_VERSION, 1, - EGL_NONE}; + EGLint contextAttrib[] = + {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_CONTEXT_MINOR_VERSION, 1, EGL_NONE}; - context = s_GL.eglCreateContext( - tmpDisplay, - config, - EGL_NO_CONTEXT, - contextAttrib); + context = s_GL.eglCreateContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); } else { - EGLint contextAttrib[] = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL_NONE}; + EGLint contextAttrib[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - context = s_GL.eglCreateContext( - tmpDisplay, - config, - EGL_NO_CONTEXT, - contextAttrib); + context = s_GL.eglCreateContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); } if (context == EGL_NO_CONTEXT) { @@ -649,8 +619,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) // part of the core API s_GL.info.extensions |= PAL_GL_EXTENSION_MULTISAMPLE; - if (type & EGL_OPENGL_ES_BIT || - type & EGL_OPENGL_ES2_BIT) { + if (type & EGL_OPENGL_ES_BIT || type & EGL_OPENGL_ES2_BIT) { s_GL.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; } @@ -670,13 +639,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) } } - s_GL.eglMakeCurrent( - tmpDisplay, - EGL_NO_SURFACE, - EGL_NO_SURFACE, - EGL_NO_CONTEXT); - - // clang-format on + s_GL.eglMakeCurrent(tmpDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); s_GL.eglDestroyContext(tmpDisplay, context); s_GL.eglDestroySurface(tmpDisplay, surface); @@ -761,23 +724,11 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( EGLint colorType = 0; EGLConfig config = eglConfigs[i]; - s_GL.eglGetConfigAttrib( - s_GL.display, - config, - EGL_SURFACE_TYPE, - &surfaceType); - - s_GL.eglGetConfigAttrib( - s_GL.display, - config, - EGL_RENDERABLE_TYPE, - &renderable); - - s_GL.eglGetConfigAttrib( - s_GL.display, - config, - EGL_COLOR_BUFFER_TYPE, - &colorType); + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_SURFACE_TYPE, &surfaceType); + + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_RENDERABLE_TYPE, &renderable); + + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_COLOR_BUFFER_TYPE, &colorType); // we need only opengl API configs if (colorType != EGL_RGB_BUFFER) { @@ -786,8 +737,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( if (s_GL.apiType == EGL_OPENGL_ES3_BIT) { // EGL_OPENGL_ES2_BIT - if (!(renderable & EGL_OPENGL_ES2_BIT) && - !(renderable & EGL_OPENGL_ES3_BIT)) { + if (!(renderable & EGL_OPENGL_ES2_BIT) && !(renderable & EGL_OPENGL_ES3_BIT)) { continue; } @@ -814,47 +764,19 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( EGLint redBits, greenBits, blueBits, alphaBits; EGLint depthBits, stencilBits, samples; - s_GL.eglGetConfigAttrib( - s_GL.display, - config, - EGL_RED_SIZE, - &redBits); - - s_GL.eglGetConfigAttrib( - s_GL.display, - config, - EGL_GREEN_SIZE, - &greenBits); - - s_GL.eglGetConfigAttrib( - s_GL.display, - config, - EGL_BLUE_SIZE, - &blueBits); - - s_GL.eglGetConfigAttrib( - s_GL.display, - config, - EGL_ALPHA_SIZE, - &alphaBits); - - s_GL.eglGetConfigAttrib( - s_GL.display, - config, - EGL_DEPTH_SIZE, - &depthBits); - - s_GL.eglGetConfigAttrib( - s_GL.display, - config, - EGL_STENCIL_SIZE, - &stencilBits); - - s_GL.eglGetConfigAttrib( - s_GL.display, - config, - EGL_SAMPLES, - &samples); + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_RED_SIZE, &redBits); + + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_GREEN_SIZE, &greenBits); + + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_BLUE_SIZE, &blueBits); + + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_ALPHA_SIZE, &alphaBits); + + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_DEPTH_SIZE, &depthBits); + + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_STENCIL_SIZE, &stencilBits); + + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_SAMPLES, &samples); if (samples == 0) { samples = 1; @@ -875,8 +797,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( if (s_GL.info.extensions & PAL_GL_EXTENSION_COLORSPACE_SRGB) { // since EGL does not have a bit to check SRGB support // we check if all the color bits are greater than or equal to 8 - if (fbConfig->redBits >= 8 && fbConfig->greenBits >= 8 && - fbConfig->blueBits >= 8) { + if (fbConfig->redBits >= 8 && fbConfig->greenBits >= 8 && fbConfig->blueBits >= 8) { fbConfig->sRGB = true; } } else { @@ -1011,12 +932,9 @@ PalResult PAL_CALL palCreateGLContext( } } - // clang-format off - // check version bool valid = info->major < s_GL.info.major || - (info->major == s_GL.info.major && info->minor <= s_GL.info.minor); - // clang-format on + (info->major == s_GL.info.major && info->minor <= s_GL.info.minor); if (!valid) { return PAL_RESULT_INVALID_GL_VERSION; @@ -1123,17 +1041,10 @@ PalResult PAL_CALL palCreateGLContext( attribs[index++] = EGL_CONTEXT_FLAGS_KHR; attribs[index++] = flags; } - attribs[index++] = EGL_NONE; - // clang-format off // create context - EGLContext context = s_GL.eglCreateContext( - s_GL.display, - config, - share, - attribs); - // clang-format on + EGLContext context = s_GL.eglCreateContext(s_GL.display, config, share, attribs); if (context == EGL_NO_CONTEXT) { EGLint error = s_GL.eglGetError(); @@ -1187,11 +1098,7 @@ PalResult PAL_CALL palCreateGLContext( s_GL.eglSwapBuffers(s_GL.display, surface); // revert - s_GL.eglMakeCurrent( - s_GL.display, - EGL_NO_SURFACE, - EGL_NO_SURFACE, - EGL_NO_CONTEXT); + s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } palFree(s_GL.allocator, eglConfigs); @@ -1208,11 +1115,7 @@ void PAL_CALL palDestroyGLContext(PalGLContext* context) ContextData* data = findContextData(context); if (data) { // make it not current if it was current - s_GL.eglMakeCurrent( - s_GL.display, - EGL_NO_SURFACE, - EGL_NO_SURFACE, - EGL_NO_CONTEXT); + s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); s_GL.eglDestroyContext(s_GL.display, (EGLContext)context); s_GL.eglDestroySurface(s_GL.display, data->surface); @@ -1239,11 +1142,8 @@ PalResult PAL_CALL palMakeContextCurrent( return PAL_RESULT_INVALID_GL_CONTEXT; } - EGLint ret = s_GL.eglMakeCurrent( - s_GL.display, - data->surface, - data->surface, - (EGLConfig)context); + EGLint ret = + s_GL.eglMakeCurrent(s_GL.display, data->surface, data->surface, (EGLConfig)context); if (!ret) { EGLint error = s_GL.eglGetError(); @@ -1261,11 +1161,7 @@ PalResult PAL_CALL palMakeContextCurrent( } } else if (!context && !glWindow) { - s_GL.eglMakeCurrent( - s_GL.display, - EGL_NO_SURFACE, - EGL_NO_SURFACE, - EGL_NO_CONTEXT); + s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } return PAL_RESULT_SUCCESS; diff --git a/src/opengl/pal_opengl_win32.c b/src/opengl/pal_opengl_win32.c index 5950e914..44809d34 100644 --- a/src/opengl/pal_opengl_win32.c +++ b/src/opengl/pal_opengl_win32.c @@ -303,7 +303,6 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) } // clang-format off - // load gdi function pointers s_Gdi.choosePixelFormat = (ChoosePixelFormatFn)GetProcAddress( s_Gdi.handle, @@ -363,7 +362,6 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) palSetLastPlatformError(error); return PAL_RESULT_PLATFORM_FAILURE; } - // clang-format on s_Wgl.hdc = GetDC(s_Wgl.window); @@ -389,7 +387,6 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) } // clang-format off - // load wgl extension function pointers s_Wgl.wglChoosePixelFormatARB = (wglChoosePixelFormatARBFn)s_Wgl.wglGetProcAddress( "wglChoosePixelFormatARB"); @@ -413,7 +410,6 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) s_Wgl.glGetString = (glGetStringFn)GetProcAddress( s_Wgl.opengl, "glGetString"); - // clang-format on const char* version = (const char*)s_Wgl.glGetString(GL_VERSION); @@ -570,13 +566,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( // check if we support modern extention if (s_Wgl.wglGetPixelFormatAttribivARB) { // get framebuffer config with extensions - if (!s_Wgl.wglGetPixelFormatAttribivARB( - s_Wgl.hdc, - 0, - 0, - 1, - &configAttrib, - &nativeCount)) { + if (!s_Wgl.wglGetPixelFormatAttribivARB(s_Wgl.hdc, 0, 0, 1, &configAttrib, &nativeCount)) { DWORD error = GetLastError(); palSetLastPlatformError(error); return PAL_RESULT_PLATFORM_FAILURE; @@ -662,17 +652,12 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( for (Int32 i = 1; i <= nativeCount; i++) { PIXELFORMATDESCRIPTOR pfd; - if (!s_Gdi.describePixelFormat( - s_Wgl.hdc, - i, - sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) { + if (!s_Gdi.describePixelFormat(s_Wgl.hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { continue; } // filter for opengl pixel formats - if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) || - !(pfd.dwFlags & PFD_DRAW_TO_WINDOW)) { + if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) || !(pfd.dwFlags & PFD_DRAW_TO_WINDOW)) { continue; } @@ -680,8 +665,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( continue; } - if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && - (pfd.dwFlags & PFD_GENERIC_FORMAT)) { + if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && (pfd.dwFlags & PFD_GENERIC_FORMAT)) { continue; } @@ -699,10 +683,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( config->stereo = (pfd.dwFlags & PFD_STEREO) ? true : false; config->sRGB = false; - - // clang-format off config->doubleBuffer = (pfd.dwFlags & PFD_DOUBLEBUFFER) ? true : false; - // clang-format on } configCount++; } @@ -822,7 +803,6 @@ PalResult PAL_CALL palCreateGLContext( } // clang-format off - // check version bool valid = info->major < s_Wgl.info.major || (info->major == s_Wgl.info.major && info->minor <= s_Wgl.info.minor); diff --git a/src/pal_core.c b/src/pal_core.c index 1acc5de0..6c072b0e 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -110,8 +110,7 @@ static inline void* alignedAlloc( { #if defined(_MSC_VER) || defined(__MINGW32__) return _aligned_malloc(size, alignment); -#elif defined(_ISOC11_SOURCE) || \ - defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#elif defined(_ISOC11_SOURCE) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L return aligned_alloc(alignment, size); #else void* ptr = nullptr; @@ -158,10 +157,7 @@ static inline LogTLSData* getLogTlsData() return nullptr; } else { // update the TLS using atomic operations to avoid thread race - LONG prev = InterlockedCompareExchange( - (volatile LONG*)&s_TlsID, - (LONG)TLSIndex, - 0); + LONG prev = InterlockedCompareExchange((volatile LONG*)&s_TlsID, (LONG)TLSIndex, 0); if (prev != 0) { // Another thread has already set this, diff --git a/src/system/pal_system_win32.c b/src/system/pal_system_win32.c index 63fb7dbb..b40ba1b4 100644 --- a/src/system/pal_system_win32.c +++ b/src/system/pal_system_win32.c @@ -66,10 +66,9 @@ static inline void cpuid( __cpuidex(regs, leaf, subLeaf); #else // gcc, clang - __asm__ __volatile__( - "cpuid" - : "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) - : "a"(leaf), "b"(subLeaf)); + __asm__ __volatile__("cpuid" + : "=a"(regs[0]), "=b"(regs[1]), "=c"(regs[2]), "=d"(regs[3]) + : "a"(leaf), "b"(subLeaf)); #endif // _MSC_VER } @@ -77,15 +76,8 @@ static inline bool getVersionWin32(PalVersion* version) { OSVERSIONINFOEXW ver = {0}; ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); - HINSTANCE ntdll = GetModuleHandleW(L"ntdll.dll"); - - // clang-format off - RtlGetVersionFn getVer = (RtlGetVersionFn)GetProcAddress( - ntdll, - "RtlGetVersion"); - // clang-format on - + RtlGetVersionFn getVer = (RtlGetVersionFn)GetProcAddress(ntdll, "RtlGetVersion"); if (!getVer) { return false; } diff --git a/src/thread/pal_thread_win32.c b/src/thread/pal_thread_win32.c index d2b76684..7f03bc17 100644 --- a/src/thread/pal_thread_win32.c +++ b/src/thread/pal_thread_win32.c @@ -116,13 +116,7 @@ PalResult PAL_CALL palCreateThread( data->func = info->entry; data->allocator = info->allocator; - HANDLE thread = CreateThread( - nullptr, - info->stackSize, - threadEntryToWin32, - data, - 0, - nullptr); + HANDLE thread = CreateThread(nullptr, info->stackSize, threadEntryToWin32, data, 0, nullptr); if (!thread) { // error @@ -204,11 +198,7 @@ PalThreadFeatures PAL_CALL palGetThreadFeatures() // check support for PAL_THREAD_FEATURE_NAME feature HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); if (kernel32) { - // clang-format off - FARPROC setThreadDesc = GetProcAddress( - kernel32, - "SetThreadDescription"); - // clang-format on + FARPROC setThreadDesc = GetProcAddress(kernel32, "SetThreadDescription"); if (setThreadDesc) { features |= PAL_THREAD_FEATURE_NAME; @@ -269,9 +259,8 @@ PalResult PAL_CALL palGetThreadName( HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); GetThreadDescriptionFn getThreadDescription = nullptr; if (kernel32) { - getThreadDescription = (GetThreadDescriptionFn)GetProcAddress( - kernel32, - "GetThreadDescription"); + getThreadDescription = + (GetThreadDescriptionFn)GetProcAddress(kernel32, "GetThreadDescription"); } if (!getThreadDescription) { @@ -378,9 +367,8 @@ PalResult PAL_CALL palSetThreadName( HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); SetThreadDescriptionFn setThreadDescription = nullptr; if (kernel32) { - setThreadDescription = (SetThreadDescriptionFn)GetProcAddress( - kernel32, - "SetThreadDescription"); + setThreadDescription = + (SetThreadDescriptionFn)GetProcAddress(kernel32, "SetThreadDescription"); } if (!setThreadDescription) { @@ -560,12 +548,7 @@ PalResult PAL_CALL palWaitCondVarTimeout( return PAL_RESULT_NULL_POINTER; } - // clang-format off - BOOL ret = SleepConditionVariableCS( - &condVar->cv, - &mutex->sc, - (DWORD)milliseconds); - // clang-format on + BOOL ret = SleepConditionVariableCS(&condVar->cv, &mutex->sc, (DWORD)milliseconds); if (!ret) { DWORD error = GetLastError(); diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index a982e836..1c250bbf 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -281,7 +281,7 @@ typedef struct { PalResult (*attachWindow)(void*, PalWindow**); PalResult (*detachWindow)(PalWindow*, void**); - // clang-format off + // clang-format on } Backend; typedef struct { @@ -869,26 +869,30 @@ typedef void (*wl_proxy_destroy_fn)(struct wl_proxy*); typedef int (*wl_proxy_add_listener_fn)( struct wl_proxy*, - void (**)(void), void*); + void (**)(void), + void*); typedef struct wl_proxy* (*wl_proxy_marshal_constructor_v_fn)( struct wl_proxy*, uint32_t, const struct wl_interface*, - uint32_t, ...); + uint32_t, + ...); typedef struct wl_proxy* (*wl_proxy_marshal_flags_fn)( struct wl_proxy*, uint32_t, const struct wl_interface*, uint32_t, - uint32_t, ...); + uint32_t, + ...); typedef uint32_t (*wl_proxy_get_version_fn)(struct wl_proxy*); typedef int (*wl_proxy_add_listener_fn)( struct wl_proxy*, - void (**)(void), void*); + void (**)(void), + void*); typedef int (*wl_display_get_error_fn)(struct wl_display*); typedef int (*wl_display_dispatch_pending_fn)(struct wl_display*); @@ -939,8 +943,7 @@ typedef struct wl_cursor* (*wl_cursor_theme_get_cursor_fn)( struct wl_cursor_theme*, const char*); -typedef struct wl_buffer* (*wl_cursor_image_get_buffer_fn)( - struct wl_cursor_image*); +typedef struct wl_buffer* (*wl_cursor_image_get_buffer_fn)(struct wl_cursor_image*); // egl_window struct wl_egl_window; @@ -1061,14 +1064,14 @@ static inline Uint64 getTime() } static inline void* wlRegistryBind( - struct wl_registry *wl_registry, + struct wl_registry* wl_registry, uint32_t name, - const struct wl_interface *interface, + const struct wl_interface* interface, uint32_t version) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *)wl_registry, + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_registry, WL_REGISTRY_BIND, interface, version, @@ -1078,338 +1081,306 @@ static inline void* wlRegistryBind( version, NULL); - return (void *)id; + return (void*)id; } static inline int wlRegistryAddListener( - struct wl_registry *wl_registry, - const struct wl_registry_listener *listener, - void *data) + struct wl_registry* wl_registry, + const struct wl_registry_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_registry, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); } -static inline struct wl_registry* wlDisplayGetRegistry( - struct wl_display *wl_display) +static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_display) { - struct wl_proxy *registry; - registry = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_display, + struct wl_proxy* registry; + registry = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_display, 1, // WL_DISPLAY_GET_REGISTRY s_Wl.registryInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_display), - 0, - NULL); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_display), + 0, + NULL); - return (struct wl_registry *)registry; + return (struct wl_registry*)registry; } static inline int wlOutputAddListener( - struct wl_output *wl_output, - const struct wl_output_listener *listener, - void *data) + struct wl_output* wl_output, + const struct wl_output_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_output, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_output, (void (**)(void))listener, data); } -static inline struct wl_surface* wlCompositorCreateSurface( - struct wl_compositor *wl_compositor) +static inline struct wl_surface* wlCompositorCreateSurface(struct wl_compositor* wl_compositor) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_compositor, + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_compositor, 0, // WL_COMPOSITOR_CREATE_SURFACE, s_Wl.surfaceInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_compositor), - 0, - NULL); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_compositor), + 0, + NULL); - return (struct wl_surface*) id; + return (struct wl_surface*)id; } -static inline void wlSurfaceCommit(struct wl_surface *wl_surface) +static inline void wlSurfaceCommit(struct wl_surface* wl_surface) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_surface, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, 6, // WL_SURFACE_COMMIT NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0); } -static inline void wlSurfaceDestroy(struct wl_surface *wl_surface) +static inline void wlSurfaceDestroy(struct wl_surface* wl_surface) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_surface, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, 0, // WL_SURFACE_DESTROY NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - WL_MARSHAL_FLAG_DESTROY); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + WL_MARSHAL_FLAG_DESTROY); } static inline struct wl_shm_pool* wlShmCreatePool( - struct wl_shm *wl_shm, + struct wl_shm* wl_shm, int32_t fd, int32_t size) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_shm, + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_shm, 0, // WL_SHM_CREATE_POOL s_Wl.shmPoolInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_shm), - 0, - NULL, - fd, - size); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm), + 0, + NULL, + fd, + size); - return (struct wl_shm_pool *) id; + return (struct wl_shm_pool*)id; } -static inline void wlShmPoolDestroy(struct wl_shm_pool *wl_shm_pool) +static inline void wlShmPoolDestroy(struct wl_shm_pool* wl_shm_pool) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_shm_pool, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_shm_pool, WL_SHM_POOL_DESTROY, NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_shm_pool), - WL_MARSHAL_FLAG_DESTROY); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm_pool), + WL_MARSHAL_FLAG_DESTROY); } static inline struct wl_buffer* wlShmPoolCreateBuffer( - struct wl_shm_pool *wl_shm_pool, + struct wl_shm_pool* wl_shm_pool, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_shm_pool, + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_shm_pool, WL_SHM_POOL_CREATE_BUFFER, s_Wl.bufferInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_shm_pool), - 0, - NULL, - offset, - width, - height, - stride, - format); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm_pool), + 0, + NULL, + offset, + width, + height, + stride, + format); - return (struct wl_buffer *) id; + return (struct wl_buffer*)id; } -static inline void wlBufferDestroy(struct wl_buffer *wl_buffer) +static inline void wlBufferDestroy(struct wl_buffer* wl_buffer) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_buffer, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_buffer, WL_BUFFER_DESTROY, NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_buffer), - WL_MARSHAL_FLAG_DESTROY); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_buffer), + WL_MARSHAL_FLAG_DESTROY); } static inline void wlSurfaceAttach( - struct wl_surface *wl_surface, - struct wl_buffer *buffer, + struct wl_surface* wl_surface, + struct wl_buffer* buffer, int32_t x, int32_t y) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_surface, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, WL_SURFACE_ATTACH, NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0, - buffer, - x, - y); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0, + buffer, + x, + y); } static inline void wlSurfaceDamageBuffer( - struct wl_surface *wl_surface, + struct wl_surface* wl_surface, int32_t x, int32_t y, int32_t width, int32_t height) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_surface, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, WL_SURFACE_DAMAGE_BUFFER, NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0, - x, - y, - width, - height); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0, + x, + y, + width, + height); } static inline int wlSurfaceAddListener( - struct wl_surface *wl_surface, - const struct wl_surface_listener *listener, - void *data) + struct wl_surface* wl_surface, + const struct wl_surface_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_surface, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_surface, (void (**)(void))listener, data); } static inline int wlSeatAddListener( - struct wl_seat *wl_seat, - const struct wl_seat_listener *listener, - void *data) + struct wl_seat* wl_seat, + const struct wl_seat_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_seat, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_seat, (void (**)(void))listener, data); } -static inline struct wl_pointer* wlSeatGetPointer(struct wl_seat *wl_seat) +static inline struct wl_pointer* wlSeatGetPointer(struct wl_seat* wl_seat) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_seat, + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_seat, WL_SEAT_GET_POINTER, s_Wl.pointerInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_seat), - 0, - NULL); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_seat), + 0, + NULL); - return (struct wl_pointer *) id; + return (struct wl_pointer*)id; } -static inline struct wl_keyboard* wlSeatGetKeyboard(struct wl_seat *wl_seat) +static inline struct wl_keyboard* wlSeatGetKeyboard(struct wl_seat* wl_seat) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_seat, + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_seat, WL_SEAT_GET_KEYBOARD, s_Wl.keyboardInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_seat), - 0, - NULL); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_seat), + 0, + NULL); - return (struct wl_keyboard *) id; + return (struct wl_keyboard*)id; } static inline int wlPointerAddListener( - struct wl_pointer *wl_pointer, - const struct wl_pointer_listener *listener, - void *data) + struct wl_pointer* wl_pointer, + const struct wl_pointer_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_pointer, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_pointer, (void (**)(void))listener, data); } static inline void wlPointerSetCursor( - struct wl_pointer *wl_pointer, + struct wl_pointer* wl_pointer, uint32_t serial, - struct wl_surface *surface, + struct wl_surface* surface, int32_t hotspot_x, int32_t hotspot_y) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_pointer, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_pointer, WL_POINTER_SET_CURSOR, NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_pointer), - 0, - serial, - surface, - hotspot_x, - hotspot_y); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_pointer), + 0, + serial, + surface, + hotspot_x, + hotspot_y); } static inline int wlKeyboardAddListener( - struct wl_keyboard *wl_keyboard, - const struct wl_keyboard_listener *listener, - void *data) + struct wl_keyboard* wl_keyboard, + const struct wl_keyboard_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_keyboard, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_keyboard, (void (**)(void))listener, data); } -static inline struct wl_region* wlCompositorCreateRegion( - struct wl_compositor *wl_compositor) +static inline struct wl_region* wlCompositorCreateRegion(struct wl_compositor* wl_compositor) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_compositor, + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_compositor, WL_COMPOSITOR_CREATE_REGION, s_Wl.regionInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_compositor), - 0, - NULL); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_compositor), + 0, + NULL); - return (struct wl_region *) id; + return (struct wl_region*)id; } static inline void wlRegionAdd( - struct wl_region *wl_region, + struct wl_region* wl_region, int32_t x, int32_t y, int32_t width, int32_t height) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_region, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_region, WL_REGION_ADD, NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_region), - 0, - x, - y, - width, - height); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_region), + 0, + x, + y, + width, + height); } static inline void wlSurfaceSetOpaqueRegion( - struct wl_surface *wl_surface, - struct wl_region *region) + struct wl_surface* wl_surface, + struct wl_region* region) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_surface, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, WL_SURFACE_SET_OPAQUE_REGION, NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0, - region); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0, + region); } -static inline void wlRegionDestroy(struct wl_region *wl_region) +static inline void wlRegionDestroy(struct wl_region* wl_region) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_region, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_region, WL_REGION_DESTROY, NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_region), - WL_MARSHAL_FLAG_DESTROY); + s_Wl.proxyGetVersion((struct wl_proxy*)wl_region), + WL_MARSHAL_FLAG_DESTROY); } static void surfaceHandleEnter( @@ -1525,8 +1496,7 @@ static void surfaceHandleLeave( static struct wl_surface_listener surfaceListener = { .enter = surfaceHandleEnter, - .leave = surfaceHandleLeave -}; + .leave = surfaceHandleLeave}; static void pointerHandleEnter( void* userData, @@ -1544,12 +1514,7 @@ static void pointerHandleEnter( if (data->cursor) { // our window WaylandCursor* cursor = data->cursor; - wlPointerSetCursor( - pointer, - serial, - cursor->surface, - cursor->hotspotX, - cursor->hotspotY); + wlPointerSetCursor(pointer, serial, cursor->surface, cursor->hotspotX, cursor->hotspotY); } // cache the surface the pointer is currently on @@ -1756,16 +1721,14 @@ static void pointerHandleAxisSource( struct wl_pointer* pointer, uint32_t axis_source) { - } static void pointerHandleAxisStop( void* userData, struct wl_pointer* pointer, uint32_t time, - uint32_t axis) + uint32_t axis) { - } static void keyboardHandleEnter( @@ -1982,14 +1945,7 @@ static void keyboardHandleModifiers( uint32_t group) { if (s_Wl.state) { - s_Wl.xkbStateUpdateMask( - s_Wl.state, - mods_depressed, - mods_latched, - mods_locked, - group, - 0, - 0); + s_Wl.xkbStateUpdateMask(s_Wl.state, mods_depressed, mods_latched, mods_locked, group, 0, 0); } } @@ -2002,8 +1958,7 @@ static struct wl_pointer_listener pointerListener = { .axis_discrete = pointerHandleAxisDiscrete, .frame = pointerHandleFrame, .axis_source = pointerHandleAxisSource, - .axis_stop = pointerHandleAxisStop -}; + .axis_stop = pointerHandleAxisStop}; static struct wl_keyboard_listener keyboardListener = { .enter = keyboardHandleEnter, @@ -2011,8 +1966,7 @@ static struct wl_keyboard_listener keyboardListener = { .keymap = keyboardHandleRemap, .key = keyboardHandleKey, .repeat_info = keyboardHandleRepeatInfo, - .modifiers = keyboardHandleModifiers -}; + .modifiers = keyboardHandleModifiers}; static void seatHandleCapabilities( void* userData, @@ -2035,13 +1989,11 @@ static void seatHandleName( struct wl_seat* seat, const char* name) { - } static struct wl_seat_listener seatListener = { .capabilities = seatHandleCapabilities, - .name = seatHandleName -}; + .name = seatHandleName}; #endif // PAL_HAS_WAYLAND #pragma endregion @@ -2066,11 +2018,17 @@ const struct wl_interface xdg_surface_interface; const struct wl_interface xdg_toplevel_interface; struct xdg_wm_base_listener { - void (*ping)(void*, struct xdg_wm_base*, uint32_t); + void (*ping)( + void*, + struct xdg_wm_base*, + uint32_t); }; struct xdg_surface_listener { - void (*configure)(void*, struct xdg_surface*, uint32_t); + void (*configure)( + void*, + struct xdg_surface*, + uint32_t); }; struct xdg_toplevel_listener { @@ -2100,10 +2058,7 @@ static inline int xdgWmBaseAddListener( const struct xdg_wm_base_listener* listener, void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy*)xdg_wm_base, - (void (**)(void))listener, - data); + return s_Wl.proxyAddListener((struct wl_proxy*)xdg_wm_base, (void (**)(void))listener, data); } static inline struct xdg_surface* xdgWmBaseGetXdgSurface( @@ -2123,8 +2078,7 @@ static inline struct xdg_surface* xdgWmBaseGetXdgSurface( return (struct xdg_surface*)id; } -static inline struct xdg_toplevel* -xdgSurfaceGetToplevel(struct xdg_surface* xdg_surface) +static inline struct xdg_toplevel* xdgSurfaceGetToplevel(struct xdg_surface* xdg_surface) { struct wl_proxy* id; id = s_Wl.proxyMarshalFlags( @@ -2171,18 +2125,12 @@ static void xdgSurfaceHandleConfigure( if (!winData->skipConfigure) { if (winData->pushConfigureEvent) { if (winData->eglWindow) { - s_Wl.eglWindowResize( - winData->eglWindow, - winData->w, - winData->h, - 0, - 0); + s_Wl.eglWindowResize(winData->eglWindow, winData->w, winData->h, 0, 0); } else { // create a new buffer with the new size struct wl_buffer* buffer = nullptr; - buffer = - createShmBuffer(winData->w, winData->h, nullptr, false); + buffer = createShmBuffer(winData->w, winData->h, nullptr, false); if (!buffer) { return; } @@ -2329,10 +2277,7 @@ static inline int xdgSurfaceAddListener( const struct xdg_surface_listener* listener, void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy*)xdg_surface, - (void (**)(void))listener, - data); + return s_Wl.proxyAddListener((struct wl_proxy*)xdg_surface, (void (**)(void))listener, data); } static inline void xdgSurfaceDestroy(struct xdg_surface* xdg_surface) @@ -2393,10 +2338,7 @@ static inline int xdgToplevelAddListener( const struct xdg_toplevel_listener* listener, void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy*)xdg_toplevel, - (void (**)(void))listener, - data); + return s_Wl.proxyAddListener((struct wl_proxy*)xdg_toplevel, (void (**)(void))listener, data); } static inline void xdgToplevelSetMinSize( @@ -2601,8 +2543,7 @@ static void setupXdgShellProtocol() xdg_shell_types[25] = NULL; } -static const struct xdg_wm_base_listener wmBaseListener = { - .ping = wmBaseHandlePing}; +static const struct xdg_wm_base_listener wmBaseListener = {.ping = wmBaseHandlePing}; static const struct xdg_surface_listener xdgSurfaceListener = { .configure = xdgSurfaceHandleConfigure}; @@ -2633,8 +2574,8 @@ struct zxdg_toplevel_decoration_v1_listener { const struct wl_interface zxdg_decoration_manager_v1_interface; const struct wl_interface zxdg_toplevel_decoration_v1_interface; -static inline void zxdgDecorationManagerV1Destroy( - struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1) +static inline void +zxdgDecorationManagerV1Destroy(struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1) { s_Wl.proxyMarshalFlags( (struct wl_proxy*)zxdg_decoration_manager_v1, @@ -2672,8 +2613,8 @@ static inline int zxdgToplevelDecorationV1AddListener( data); } -static inline void zxdgToplevelDecorationV1Destroy( - struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1) +static inline void +zxdgToplevelDecorationV1Destroy(struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1) { s_Wl.proxyMarshalFlags( (struct wl_proxy*)zxdg_toplevel_decoration_v1, @@ -2814,10 +2755,7 @@ static WindowData* getFreeWindowData() int freeIndex = s_Video.maxWindowData + 1; data = palAllocate(s_Video.allocator, sizeof(WindowData) * count, 0); if (data) { - memcpy( - data, - s_Video.windowData, - s_Video.maxWindowData * sizeof(WindowData)); + memcpy(data, s_Video.windowData, s_Video.maxWindowData * sizeof(WindowData)); palFree(s_Video.allocator, s_Video.windowData); s_Video.windowData = data; @@ -2832,8 +2770,7 @@ static WindowData* getFreeWindowData() static WindowData* findWindowData(PalWindow* window) { for (int i = 0; i < s_Video.maxWindowData; ++i) { - if (s_Video.windowData[i].used && - s_Video.windowData[i].window == window) { + if (s_Video.windowData[i].used && s_Video.windowData[i].window == window) { return &s_Video.windowData[i]; } } @@ -2842,10 +2779,7 @@ static WindowData* findWindowData(PalWindow* window) static void resetMonitorData() { - memset( - s_Video.monitorData, - 0, - s_Video.maxMonitorData * sizeof(MonitorData)); + memset(s_Video.monitorData, 0, s_Video.maxMonitorData * sizeof(MonitorData)); } static MonitorData* getFreeMonitorData() @@ -2864,10 +2798,7 @@ static MonitorData* getFreeMonitorData() int freeIndex = s_Video.maxMonitorData + 1; data = palAllocate(s_Video.allocator, sizeof(MonitorData) * count, 0); if (data) { - memcpy( - data, - s_Video.monitorData, - s_Video.maxMonitorData * sizeof(MonitorData)); + memcpy(data, s_Video.monitorData, s_Video.maxMonitorData * sizeof(MonitorData)); palFree(s_Video.allocator, s_Video.monitorData); s_Video.monitorData = data; @@ -2882,8 +2813,7 @@ static MonitorData* getFreeMonitorData() static MonitorData* findMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (s_Video.monitorData[i].used && - s_Video.monitorData[i].monitor == monitor) { + if (s_Video.monitorData[i].used && s_Video.monitorData[i].monitor == monitor) { return &s_Video.monitorData[i]; } } @@ -2893,8 +2823,7 @@ static MonitorData* findMonitorData(PalMonitor* monitor) static void freeMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (s_Video.monitorData[i].used && - s_Video.monitorData[i].monitor == monitor) { + if (s_Video.monitorData[i].used && s_Video.monitorData[i].monitor == monitor) { s_Video.monitorData[i].used = false; } } @@ -3040,13 +2969,9 @@ static PalResult glxBackend(const int index) palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; } - // clang-format off int count = 0; - GLXFBConfig* configs = s_X11.glxGetFBConfigs( - s_X11.display, - s_X11.screen, - &count); + GLXFBConfig* configs = s_X11.glxGetFBConfigs(s_X11.display, s_X11.screen, &count); GLXFBConfig fbConfig = configs[index]; if (!fbConfig) { @@ -3054,9 +2979,7 @@ static PalResult glxBackend(const int index) } // get a matching visual - XVisualInfo* visualInfo = s_X11.glxGetVisualFromFBConfig( - s_X11.display, - fbConfig); + XVisualInfo* visualInfo = s_X11.glxGetVisualFromFBConfig(s_X11.display, fbConfig); if (!visualInfo) { return PAL_RESULT_INVALID_GL_FBCONFIG; @@ -3107,14 +3030,8 @@ static PalResult eglXBackend(int index) XVisualInfo tmp; tmp.visualid = visualID; - // clang-format off // get a matching visual info - XVisualInfo* visualInfo = s_X11.getVisualInfo( - s_X11.display, - VisualIDMask, - &tmp, - &numVisuals); - // clang-format on + XVisualInfo* visualInfo = s_X11.getVisualInfo(s_X11.display, VisualIDMask, &tmp, &numVisuals); if (!visualInfo) { return PAL_RESULT_INVALID_GL_FBCONFIG; @@ -3335,10 +3252,7 @@ static void xCacheMonitors() for (int i = 0; i < resources->noutput; ++i) { RROutput output = resources->outputs[i]; - // clang-format off XRROutputInfo* info = s_X11.getOutputInfo(s_X11.display, resources, output); - // clang-format on - if (info->connection == RR_Connected && info->crtc != None) { // get monitor data and update info PalMonitor* monitor = TO_PAL_HANDLE(PalMonitor, output); @@ -3349,10 +3263,7 @@ static void xCacheMonitors() } data->monitor = monitor; - - // clang-format off XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, info->crtc); - // clang-format on // get DPI float raw = crtc->width / 1920.0f; @@ -3510,7 +3421,6 @@ static PalResult xInitVideo() } // clang-format off - // load procs s_X11.openDisplay = (XOpenDisplayFn)dlsym( s_X11.handle, @@ -3809,6 +3719,7 @@ static PalResult xInitVideo() s_X11.utf8LookupString = (Xutf8LookupStringFn)dlsym( s_X11.handle, "Xutf8LookupString"); + // clang-format on // X11 server if (s_Video.platformInstance) { @@ -3830,10 +3741,7 @@ static PalResult xInitVideo() xCheckFeatures(); // subscribe for monitor events - s_X11.selectRRInput( - s_X11.display, - s_X11.root, - RRScreenChangeNotifyMask | RRNotify); + s_X11.selectRRInput(s_X11.display, s_X11.root, RRScreenChangeNotifyMask | RRNotify); int eventBase, errorBase = 0; s_X11.queryRRExtension(s_X11.display, &eventBase, &errorBase); @@ -3854,18 +3762,14 @@ static PalResult xInitVideo() if (s_X11.glxHandle) { GLXGetProcAddressFn load = nullptr; - load = (GLXGetProcAddressFn)dlsym( - s_X11.glxHandle, - "glXGetProcAddress"); + load = (GLXGetProcAddressFn)dlsym(s_X11.glxHandle, "glXGetProcAddress"); - s_X11.glxGetFBConfigs = (GLXGetFBConfigsFn)load( - "glXGetFBConfigs"); + s_X11.glxGetFBConfigs = (GLXGetFBConfigsFn)load("glXGetFBConfigs"); - s_X11.glxGetFBConfigAttrib = (GLXGetFBConfigAttribFn)load( - "glXGetFBConfigAttrib"); + s_X11.glxGetFBConfigAttrib = (GLXGetFBConfigAttribFn)load("glXGetFBConfigAttrib"); - s_X11.glxGetVisualFromFBConfig = (GLXGetVisualFromFBConfigFn)load( - "glXGetVisualFromFBConfig"); + s_X11.glxGetVisualFromFBConfig = + (GLXGetVisualFromFBConfigFn)load("glXGetVisualFromFBConfig"); } xCreateKeycodeTable(); @@ -3915,8 +3819,7 @@ PalResult xSetFBConfig( if (backend == PAL_CONFIG_BACKEND_GLX) { return glxBackend(index); - } else if (backend == PAL_CONFIG_BACKEND_EGL || - backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { + } else if (backend == PAL_CONFIG_BACKEND_EGL || backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { return eglXBackend(index); } else { @@ -3976,8 +3879,7 @@ static void xUpdateVideo() // real configure event if (s_Video.eventDriver) { // check if its a resize event - if (data->w != event.xconfigure.width || - data->h != event.xconfigure.height) { + if (data->w != event.xconfigure.width || data->h != event.xconfigure.height) { data->w = event.xconfigure.width; data->h = event.xconfigure.height; @@ -4005,8 +3907,7 @@ static void xUpdateVideo() } // check if its a move event - if (data->x != event.xconfigure.x || - data->y != event.xconfigure.y) { + if (data->x != event.xconfigure.x || data->y != event.xconfigure.y) { data->x = event.xconfigure.x; data->y = event.xconfigure.y; @@ -4248,10 +4149,7 @@ static void xUpdateVideo() s_Mouse.WheelY = scrollY; if (s_Video.eventDriver && (scrollX || scrollY)) { PalEventDriver* driver = s_Video.eventDriver; - // clang-format off mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_WHEEL); - // clang-format on - if (mode != PAL_DISPATCH_NONE) { PalEvent event = {0}; event.type = PAL_EVENT_MOUSE_WHEEL; @@ -4402,18 +4300,11 @@ static PalResult xEnumerateMonitors( { int _count = 0; int maxCount = outMonitors ? *count : 0; - // clang-format off XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - // clang-format on - for (int i = 0; i < resources->noutput; ++i) { RROutput output = resources->outputs[i]; - // clang-format off XRROutputInfo* outputInfo = s_X11.getOutputInfo(s_X11.display, resources, output); - // clang-format on - - if (outputInfo->connection == RR_Connected && - outputInfo->crtc != None) { + if (outputInfo->connection == RR_Connected && outputInfo->crtc != None) { // a monitor if (outMonitors) { if (_count < maxCount) { @@ -4446,14 +4337,9 @@ static PalResult xGetMonitorInfo( PalMonitor* monitor, PalMonitorInfo* info) { - // clang-format off XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - // clang-format on - - XRROutputInfo* outputInfo = s_X11.getOutputInfo( - s_X11.display, - resources, - FROM_PAL_HANDLE(RROutput, monitor)); + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); if (!outputInfo) { // invalid monitor @@ -4479,10 +4365,7 @@ static PalResult xGetMonitorInfo( } // get monitor pos and size - // clang-format off XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - // clang-format on - info->x = crtc->x; info->y = crtc->y; info->width = crtc->width; @@ -4558,16 +4441,11 @@ static PalResult xEnumerateMonitorModes( { Int32 modeCount = 0; int maxModeCount = modes ? *count : 0; - - // clang-format off XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - // clang-format on // get the monitor info - XRROutputInfo* outputInfo = s_X11.getOutputInfo( - s_X11.display, - resources, - FROM_PAL_HANDLE(RROutput, monitor)); + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); if (!outputInfo) { // invalid monitor @@ -4595,11 +4473,8 @@ static PalResult xEnumerateMonitorModes( mode->height = info->height; mode->bpp = s_X11.bpp; - // clang-format off - double tmp = (double)info->hTotal * (double)info->vTotal; - // clang-format on - - double rate = (double)info->dotClock / tmp; + double tmp = (double)info->hTotal * (double)info->vTotal double rate = + (double)info->dotClock / tmp; mode->refreshRate = rate + 0.5; } } @@ -4622,15 +4497,11 @@ static PalResult xGetCurrentMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - // clang-format off XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - // clang-format on // get the monitor info - XRROutputInfo* outputInfo = s_X11.getOutputInfo( - s_X11.display, - resources, - FROM_PAL_HANDLE(RROutput, monitor)); + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); if (!outputInfo) { // invalid monitor @@ -4645,9 +4516,7 @@ static PalResult xGetCurrentMonitorMode( } // get the current display mode - // clang-format off XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - // clang-format on // find the display mode XRRModeInfo* info = nullptr; @@ -4680,15 +4549,11 @@ static PalResult xSetMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - // clang-format off XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - // clang-format on // get the monitor info - XRROutputInfo* outputInfo = s_X11.getOutputInfo( - s_X11.display, - resources, - FROM_PAL_HANDLE(RROutput, monitor)); + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); if (!outputInfo) { // invalid monitor @@ -4711,9 +4576,7 @@ static PalResult xSetMonitorMode( } // apply the display mode - // clang-format off XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - // clang-format on RROutput output = FROM_PAL_HANDLE(RROutput, monitor); int ret = s_X11.setCrtcConfig( @@ -4751,15 +4614,11 @@ static PalResult xSetMonitorOrientation( PalMonitor* monitor, PalOrientation orientation) { - // clang-format off XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - // clang-format on // get the monitor info - XRROutputInfo* outputInfo = s_X11.getOutputInfo( - s_X11.display, - resources, - FROM_PAL_HANDLE(RROutput, monitor)); + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); if (!outputInfo) { // invalid monitor @@ -4774,9 +4633,7 @@ static PalResult xSetMonitorOrientation( } // get the current display mode - // clang-format off XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - // clang-format on // check if the new orientation is supported Rotation rotation = 0; @@ -4859,15 +4716,7 @@ static PalResult xCreateWindow( depth = s_X11.visualInfo->depth; bgPixel = 0; borderPixel = 0; - - // clang-format off - - colormap = s_X11.createColormap( - s_X11.display, - s_X11.root, - visual, - AllocNone); - // clang-format on + colormap = s_X11.createColormap(s_X11.display, s_X11.root, visual, AllocNone); if (!colormap) { palSetLastPlatformError(errno); @@ -4919,24 +4768,16 @@ static PalResult xCreateWindow( resources = s_X11.getScreenResources(s_X11.display, s_X11.root); for (int i = 0; i < resources->noutput; ++i) { RROutput output = resources->outputs[i]; - XRROutputInfo* outputInfo = s_X11.getOutputInfo( - s_X11.display, - resources, - FROM_PAL_HANDLE(RROutput, monitor)); + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); // check if its a monitor - if (outputInfo->connection != RR_Connected || - outputInfo->crtc == None) { + if (outputInfo->connection != RR_Connected || outputInfo->crtc == None) { s_X11.freeOutputInfo(outputInfo); continue; } - // clang-format off - XRRCrtcInfo* crtc = s_X11.getCrtcInfo( - s_X11.display, - resources, - outputInfo->crtc); - // clang-format on + XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); monitorX = crtc->x; monitorY = crtc->y; @@ -5203,8 +5044,7 @@ static PalResult xCreateWindow( s_X11.iconifyWindow(s_X11.display, window, s_X11.screen); } - s_X11 - .setWMProtocols(s_X11.display, window, &s_X11Atoms.WM_DELETE_WINDOW, 1); + s_X11.setWMProtocols(s_X11.display, window, &s_X11Atoms.WM_DELETE_WINDOW, 1); s_X11.flush(s_X11.display); @@ -5737,14 +5577,8 @@ PalResult xSetFocusWindow(PalWindow* window) } if (s_X11Atoms._NET_ACTIVE_WINDOW) { - xSendWMEvent( - xWin, - s_X11Atoms._NET_ACTIVE_WINDOW, - CurrentTime, - 0, - 0, - 0, - true); // 1 + xSendWMEvent(xWin, s_X11Atoms._NET_ACTIVE_WINDOW, CurrentTime, 0, 0, 0, + true); // 1 } else { s_X11.setInputFocus(s_X11.display, xWin, RevertToParent, CurrentTime); @@ -5953,16 +5787,7 @@ PalResult xGetCursorPos( Window root, rootChild; int rootX, rootY, winX, winY; unsigned int mask; - s_X11.queryPointer( - s_X11.display, - xWin, - &root, - &rootChild, - &rootX, - &rootY, - &winX, - &winY, - &mask); + s_X11.queryPointer(s_X11.display, xWin, &root, &rootChild, &rootX, &rootY, &winX, &winY, &mask); if (x) { *x = winX; @@ -6459,12 +6284,10 @@ static void globalHandle( } if (strcmp(interface, "wl_compositor") == 0) { - s_Wl.compositor = - wlRegistryBind(registry, name, s_Wl.compositorInterface, 4); + s_Wl.compositor = wlRegistryBind(registry, name, s_Wl.compositorInterface, 4); } else if (strcmp(interface, "xdg_wm_base") == 0) { - s_Wl.xdgBase = - wlRegistryBind(registry, name, &xdg_wm_base_interface, 1); + s_Wl.xdgBase = wlRegistryBind(registry, name, &xdg_wm_base_interface, 1); xdgWmBaseAddListener(s_Wl.xdgBase, &wmBaseListener, nullptr); @@ -6477,11 +6300,8 @@ static void globalHandle( wlSeatAddListener(s_Wl.seat, &seatListener, nullptr); } else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) { - s_Wl.decorationManager = wlRegistryBind( - registry, - name, - &zxdg_decoration_manager_v1_interface, - 1); + s_Wl.decorationManager = + wlRegistryBind(registry, name, &zxdg_decoration_manager_v1_interface, 1); s_Video.features64 |= PAL_VIDEO_FEATURE64_DECORATED_WINDOW; @@ -6510,8 +6330,7 @@ static void globalRemove( uint32_t name) { for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (s_Video.monitorData[i].used && - s_Video.monitorData[i].wlName == name) { + if (s_Video.monitorData[i].used && s_Video.monitorData[i].wlName == name) { MonitorData* data = &s_Video.monitorData[i]; data->used = false; s_Wl.proxyDestroy((struct wl_proxy*)data->monitor); @@ -6685,7 +6504,6 @@ PalResult wlInitVideo() s_Wl.eglWindowResize = (wl_egl_window_resize_fn)dlsym( s_Wl.libWaylandEgl, "wl_egl_window_resize"); - // clang-format on // initialize wayland @@ -6774,8 +6592,7 @@ PalResult wlSetFBConfig( const int index, PalFBConfigBackend backend) { - if (backend == PAL_CONFIG_BACKEND_GLES || - backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { + if (backend == PAL_CONFIG_BACKEND_GLES || backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { return eglWlBackend(index); } else { @@ -7023,13 +6840,9 @@ PalResult wlCreateWindow( // decorated window if (!(info->style & PAL_WINDOW_STYLE_BORDERLESS)) { struct zxdg_toplevel_decoration_v1* decoration = nullptr; - decoration = - zxdgGetToplevelDecoration(s_Wl.decorationManager, xdgToplevel); + decoration = zxdgGetToplevelDecoration(s_Wl.decorationManager, xdgToplevel); - zxdgToplevelDecorationV1AddListener( - decoration, - &decorationListener, - surface); + zxdgToplevelDecorationV1AddListener(decoration, &decorationListener, surface); zxdgToplevelDecorationV1SetMode(decoration, 2); data->decoration = decoration; @@ -7372,8 +7185,7 @@ PalResult wlCreateCursor( return PAL_RESULT_PLATFORM_FAILURE; } - cursor->buffer = - createShmBuffer(info->width, info->height, info->pixels, true); + cursor->buffer = createShmBuffer(info->width, info->height, info->pixels, true); if (!cursor->buffer) { palSetLastPlatformError(errno); @@ -7608,15 +7420,11 @@ PalResult PAL_CALL palInitVideo( s_Video.maxMonitorData = 16; // initial size s_Video.maxWindowData = 32; // initial size - s_Video.windowData = palAllocate( - s_Video.allocator, - sizeof(WindowData) * s_Video.maxWindowData, - 0); + s_Video.windowData = + palAllocate(s_Video.allocator, sizeof(WindowData) * s_Video.maxWindowData, 0); - s_Video.monitorData = palAllocate( - s_Video.allocator, - sizeof(MonitorData) * s_Video.maxMonitorData, - 0); + s_Video.monitorData = + palAllocate(s_Video.allocator, sizeof(MonitorData) * s_Video.maxMonitorData, 0); if (!s_Video.monitorData || !s_Video.windowData) { return PAL_RESULT_OUT_OF_MEMORY; @@ -7661,10 +7469,7 @@ PalResult PAL_CALL palInitVideo( s_Egl.eglGetError = (eglGetErrorFn)load("eglGetError"); s_Egl.eglBindAPI = (eglBindAPIFn)load("eglBindAPI"); s_Egl.eglGetConfigs = (eglGetConfigsFn)load("eglGetConfigs"); - - // clang-format off s_Egl.eglGetConfigAttrib = (eglGetConfigAttribFn)load("eglGetConfigAttrib"); - // clang-format on } s_Video.allocator = allocator; @@ -7797,11 +7602,7 @@ PalResult PAL_CALL palEnumerateMonitorModes( return PAL_RESULT_INSUFFICIENT_BUFFER; } - // clang-format off - PalResult ret = s_Video.backend->enumerateMonitorModes(monitor, count, modes); - // clang-format on - if (ret == PAL_RESULT_SUCCESS && modes) { // sort the modes so that they are lowest to highest qsort(modes, *count, sizeof(PalMonitorMode), compareModes); @@ -8028,13 +7829,7 @@ PalResult PAL_CALL palGetWindowTitle( return PAL_RESULT_NULL_POINTER; } - // clang-format off - return s_Video.backend->getWindowTitle( - window, - bufferSize, - outSize, - outBuffer); - // clang-format on + return s_Video.backend->getWindowTitle(window, bufferSize, outSize, outBuffer); } PalResult PAL_CALL palGetWindowPos( diff --git a/src/video/pal_video_win32.c b/src/video/pal_video_win32.c index 38bff6fa..6c33906e 100644 --- a/src/video/pal_video_win32.c +++ b/src/video/pal_video_win32.c @@ -525,7 +525,6 @@ LRESULT CALLBACK videoProc( } // clang-format off - // check if we pressed or released the button if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || @@ -538,7 +537,6 @@ LRESULT CALLBACK videoProc( pressed = false; type = PAL_EVENT_MOUSE_BUTTONUP; } - // clang-format on // set mouse capture @@ -800,12 +798,7 @@ static inline PalResult setMonitorMode( settingsFlag = CDS_TEST; } - ULONG result = ChangeDisplaySettingsExW( - mi.szDevice, - &devMode, - NULL, - settingsFlag, - NULL); + ULONG result = ChangeDisplaySettingsExW(mi.szDevice, &devMode, NULL, settingsFlag, NULL); if (result == DISP_CHANGE_SUCCESSFUL) { return PAL_RESULT_SUCCESS; @@ -820,12 +813,10 @@ static inline bool compareMonitorMode( { // clang-format off - return a->bpp == b->bpp && a->width == b->width && a->height == b->height && a->refreshRate == b->refreshRate; - // clang-format on } @@ -1039,10 +1030,7 @@ static WindowData* getFreeWindowData() int freeIndex = s_Video.maxWindowData + 1; data = palAllocate(s_Video.allocator, sizeof(WindowData) * count, 0); if (data) { - memcpy( - data, - s_Video.windowData, - s_Video.maxWindowData * sizeof(WindowData)); + memcpy(data, s_Video.windowData, s_Video.maxWindowData * sizeof(WindowData)); palFree(s_Video.allocator, s_Video.windowData); s_Video.windowData = data; @@ -1071,10 +1059,8 @@ PalResult PAL_CALL palInitVideo( } s_Video.maxWindowData = 32; - s_Video.windowData = palAllocate( - s_Video.allocator, - sizeof(WindowData) * s_Video.maxWindowData, - 0); + s_Video.windowData = + palAllocate(s_Video.allocator, sizeof(WindowData) * s_Video.maxWindowData, 0); // get the instance if (!s_Video.instance) { @@ -1145,17 +1131,14 @@ PalResult PAL_CALL palInitVideo( // shcore s_Video.shcore = LoadLibraryA("shcore.dll"); if (s_Video.shcore) { - s_Video.getDpiForMonitor = (GetDpiForMonitorFn)GetProcAddress( - s_Video.shcore, - "GetDpiForMonitor"); + s_Video.getDpiForMonitor = + (GetDpiForMonitorFn)GetProcAddress(s_Video.shcore, "GetDpiForMonitor"); - s_Video.setProcessAwareness = (SetProcessAwarenessFn)GetProcAddress( - s_Video.shcore, - "SetProcessDpiAwareness"); + s_Video.setProcessAwareness = + (SetProcessAwarenessFn)GetProcAddress(s_Video.shcore, "SetProcessDpiAwareness"); } // clang-format off - // gdi functios s_Video.gdi = LoadLibraryA("gdi32.dll"); if (s_Video.gdi) { @@ -1179,7 +1162,6 @@ PalResult PAL_CALL palInitVideo( s_Video.gdi, "SetPixelFormat"); } - // clang-format on // set features @@ -1364,8 +1346,7 @@ PalResult PAL_CALL palSetFBConfig( return PAL_RESULT_VIDEO_NOT_INITIALIZED; } - if (backend == PAL_CONFIG_BACKEND_EGL || - backend == PAL_CONFIG_BACKEND_GLES || + if (backend == PAL_CONFIG_BACKEND_EGL || backend == PAL_CONFIG_BACKEND_GLES || backend == PAL_CONFIG_BACKEND_GLX) { return PAL_RESULT_INVALID_FBCONFIG_BACKEND; } @@ -1462,15 +1443,7 @@ PalResult PAL_CALL palGetMonitorInfo( info->height = mi.rcMonitor.bottom - mi.rcWork.top; // get name - WideCharToMultiByte( - CP_UTF8, - 0, - mi.szDevice, - -1, - info->name, - 32, - NULL, - NULL); + WideCharToMultiByte(CP_UTF8, 0, mi.szDevice, -1, info->name, 32, NULL, NULL); DEVMODE devMode = {0}; devMode.dmSize = sizeof(DEVMODE); @@ -1540,10 +1513,7 @@ PalResult PAL_CALL palEnumerateMonitorModes( if (!modes) { // allocate and store tmp monitor modesand check for the interested // fields. - monitorModes = palAllocate( - s_Video.allocator, - sizeof(PalMonitorMode) * MAX_MODE_COUNT, - 0); + monitorModes = palAllocate(s_Video.allocator, sizeof(PalMonitorMode) * MAX_MODE_COUNT, 0); if (!monitorModes) { return PAL_RESULT_OUT_OF_MEMORY; @@ -1675,13 +1645,13 @@ PalResult PAL_CALL palSetMonitorOrientation( DWORD monitorOrientation = devMode.dmDisplayOrientation; // clang-format off - // only swap size if switching between landscape and portrait bool isMonitorLandscape = (monitorOrientation == DMDO_DEFAULT || monitorOrientation == DMDO_180); bool isLandscape = (win32Orientation == DMDO_DEFAULT || win32Orientation == DMDO_180); + // clang-format on if (isMonitorLandscape != isLandscape) { DWORD tmp = devMode.dmPelsWidth; @@ -1692,14 +1662,7 @@ PalResult PAL_CALL palSetMonitorOrientation( devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYORIENTATION; devMode.dmDisplayOrientation = win32Orientation; - ULONG result = ChangeDisplaySettingsExW( - mi.szDevice, - &devMode, - NULL, - CDS_RESET, - NULL); - - // clang-format on + ULONG result = ChangeDisplaySettingsExW(mi.szDevice, &devMode, NULL, CDS_RESET, NULL); if (result == DISP_CHANGE_SUCCESSFUL) { return PAL_RESULT_SUCCESS; @@ -1777,9 +1740,7 @@ PalResult PAL_CALL palCreateWindow( } else { // get primary monitor - monitor = (PalMonitor*)MonitorFromPoint( - (POINT){0, 0}, - MONITOR_DEFAULTTOPRIMARY); + monitor = (PalMonitor*)MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); if (!monitor) { DWORD error = GetLastError(); @@ -2403,11 +2364,7 @@ PalResult PAL_CALL palSetWindowOpacity( opacity = 1.0f; } - bool ret = SetLayeredWindowAttributes( - (HWND)window, - 0, - (BYTE)(opacity * 255), - LWA_ALPHA); + bool ret = SetLayeredWindowAttributes((HWND)window, 0, (BYTE)(opacity * 255), LWA_ALPHA); if (!ret) { DWORD error = GetLastError(); @@ -2545,14 +2502,8 @@ PalResult PAL_CALL palSetWindowPos( return PAL_RESULT_NULL_POINTER; } - bool success = SetWindowPos( - (HWND)window, - nullptr, - x, - y, - 0, - 0, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); + bool success = + SetWindowPos((HWND)window, nullptr, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); if (!success) { DWORD error = GetLastError(); @@ -2666,13 +2617,9 @@ PalResult PAL_CALL palCreateIcon( void* dibPixels = nullptr; // create dib section - HBITMAP bitmap = s_Video.createDIBSection( - hdc, - (BITMAPINFO*)&bitInfo, - DIB_RGB_COLORS, - &dibPixels, - nullptr, - 0); + HBITMAP bitmap = + s_Video + .createDIBSection(hdc, (BITMAPINFO*)&bitInfo, DIB_RGB_COLORS, &dibPixels, nullptr, 0); if (!bitmap) { ReleaseDC(nullptr, hdc); @@ -2787,13 +2734,9 @@ PalResult PAL_CALL palCreateCursor( void* dibPixels = nullptr; // create dib section - HBITMAP bitmap = s_Video.createDIBSection( - hdc, - (BITMAPINFO*)&bitInfo, - DIB_RGB_COLORS, - &dibPixels, - nullptr, - 0); + HBITMAP bitmap = + s_Video + .createDIBSection(hdc, (BITMAPINFO*)&bitInfo, DIB_RGB_COLORS, &dibPixels, nullptr, 0); if (!bitmap) { ReleaseDC(nullptr, hdc); @@ -3060,10 +3003,7 @@ PalResult PAL_CALL palAttachWindow( PalWindow* window = (PalWindow*)windowHandle; data->isAttached = true; - data->wndProc = SetWindowLongPtrW( - (HWND)windowHandle, - GWLP_WNDPROC, - (LONG_PTR)videoProc); + data->wndProc = SetWindowLongPtrW((HWND)windowHandle, GWLP_WNDPROC, (LONG_PTR)videoProc); // use default PAL video cursor // there is no way to get the cursor set on the native window diff --git a/tests/attach_window_test.c b/tests/attach_window_test.c index 65bc0567..9b506102 100644 --- a/tests/attach_window_test.c +++ b/tests/attach_window_test.c @@ -87,6 +87,7 @@ static void* createX11Window() s_XDestroyWindow = (XDestroyWindowFn)dlsym( s_LibX, "XDestroyWindow"); + // clang-format on if (!s_XCreateWindow || !s_XSync || !s_XMapRaised || !s_XDestroyWindow) { return nullptr; @@ -119,7 +120,6 @@ static void* createX11Window() // make sure the window is mapped s_XMapRaised(display, window); s_XSync(display, False); - // clang-format on return (void*)(UintPtr)window; #endif // __linux__ @@ -242,25 +242,16 @@ bool attachWindowTest() // check for support PalVideoFeatures64 features = palGetVideoFeaturesEx(); if (!(features & PAL_VIDEO_FEATURE64_FOREIGN_WINDOWS)) { - // clang-format off palLog(nullptr, "Attaching and detaching foreign windows feature not supported"); - // clang-format on - palDestroyEventDriver(eventDriver); palShutdownVideo(); return false; } // we are interested in move and close events - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); - - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_MOVE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); + + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_MOVE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); diff --git a/tests/char_event_test.c b/tests/char_event_test.c index 5f50641e..68bded0a 100644 --- a/tests/char_event_test.c +++ b/tests/char_event_test.c @@ -61,10 +61,7 @@ bool charEventTest() } // we only neeed PAL_EVENT_KEYCHAR and PAL_EVENT_WINDOW_CLOSE - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index a38bf07f..2b3188dc 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -49,15 +49,9 @@ bool clearColorTest() return false; } - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_KEYDOWN, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { @@ -148,8 +142,7 @@ bool clearColorTest() palFree(nullptr, adapters); if (!adapter) { - palLog(nullptr, - "Failed to find an adapter that supports graphics queue"); + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); return false; } @@ -182,10 +175,7 @@ bool clearColorTest() // create a swapchain with the graphics queue PalSwapchainCapabilities swapchainCaps = {0}; - result = palQuerySwapchainCapabilities( - device, - &gfxWindow, - &swapchainCaps); + result = palQuerySwapchainCapabilities(device, &gfxWindow, &swapchainCaps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -215,12 +205,7 @@ bool clearColorTest() swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - result = palCreateSwapchain( - device, - queue, - &gfxWindow, - &swapchainCreateInfo, - &swapchain); + result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -230,15 +215,9 @@ bool clearColorTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; - imageViews = palAllocate( - nullptr, - sizeof(PalImageView*) * imageCount, - 0); + imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - renderFinishedSemaphores = palAllocate( - nullptr, - sizeof(PalSemaphore*) * imageCount, - 0); + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); @@ -253,7 +232,7 @@ bool clearColorTest() imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; - for (int i = 0; i < imageCount; i++) { + for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL PalImage* image = palGetSwapchainImage(swapchain, i); @@ -261,11 +240,7 @@ bool clearColorTest() palLog(nullptr, "Failed to get swapchain image"); } - result = palCreateImageView( - device, - image, - &imageViewCreateInfo, - &imageViews[i]); + result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -274,10 +249,7 @@ bool clearColorTest() } } - result = palCreateCommandPool( - device, - queue, - &cmdPool); + result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/cursor_test.c b/tests/cursor_test.c index b3e684f6..8a832166 100644 --- a/tests/cursor_test.c +++ b/tests/cursor_test.c @@ -115,10 +115,8 @@ bool cursorTest() } // set the dispatch mode for window close event to recieve it - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); // polling + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, + PAL_DISPATCH_POLL); // polling palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); diff --git a/tests/custom_decoration_test.c b/tests/custom_decoration_test.c index bd7d4590..e57042e3 100644 --- a/tests/custom_decoration_test.c +++ b/tests/custom_decoration_test.c @@ -145,14 +145,10 @@ static inline int wlRegistryAddListener( const struct wl_registry_listener* listener, void* data) { - return s_wl_proxy_add_listener( - (struct wl_proxy*)wl_registry, - (void (**)(void))listener, - data); + return s_wl_proxy_add_listener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); } -static inline struct wl_registry* -wlDisplayGetRegistry(struct wl_display* wl_display) +static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_display) { struct wl_proxy* registry; registry = s_wl_proxy_marshal_flags( @@ -166,8 +162,7 @@ wlDisplayGetRegistry(struct wl_display* wl_display) return (struct wl_registry*)registry; } -static inline struct wl_surface* -wlCompositorCreateSurface(struct wl_compositor* wl_compositor) +static inline struct wl_surface* wlCompositorCreateSurface(struct wl_compositor* wl_compositor) { struct wl_proxy* id; id = s_wl_proxy_marshal_flags( @@ -301,8 +296,7 @@ static inline void wlSurfaceDamageBuffer( height); } -static inline void -wlSubcompositorDestroy(struct wl_subcompositor* wl_subcompositor) +static inline void wlSubcompositorDestroy(struct wl_subcompositor* wl_subcompositor) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_subcompositor, @@ -380,8 +374,7 @@ static void globalHandle( s_Compositor = wlRegistryBind(registry, name, compositorInterface, 4); } else if (strcmp(interface, "wl_subcompositor") == 0) { - s_Subcompositor = - wlRegistryBind(registry, name, subCompositorInterface, 1); + s_Subcompositor = wlRegistryBind(registry, name, subCompositorInterface, 1); } else if (strcmp(interface, "wl_shm") == 0) { s_Shm = wlRegistryBind(registry, name, shmInterface, 1); @@ -474,6 +467,7 @@ static void openDisplayWayland() s_wl_proxy_destroy = (wl_proxy_destroy_fn)dlsym( s_LibWayland, "wl_proxy_destroy"); + // clang-format on registryInterface = dlsym(s_LibWayland, "wl_registry_interface"); seatInterface = dlsym(s_LibWayland, "wl_seat_interface"); @@ -502,9 +496,9 @@ static void openDisplayWayland() static void closeDisplayWayland() { if (s_Compositor) { - s_wl_proxy_destroy((struct wl_proxy *)s_Compositor); - s_wl_proxy_destroy((struct wl_proxy *)s_Shm); - s_wl_proxy_destroy((struct wl_proxy *)s_Seat); + s_wl_proxy_destroy((struct wl_proxy*)s_Compositor); + s_wl_proxy_destroy((struct wl_proxy*)s_Shm); + s_wl_proxy_destroy((struct wl_proxy*)s_Seat); wlSubcompositorDestroy(s_Subcompositor); } @@ -570,7 +564,7 @@ static struct wl_buffer* createShmBuffer( } void fillRect( - uint32_t *pixels, + uint32_t* pixels, int stride, int x, int y, @@ -589,80 +583,81 @@ void fillRect( // exchange with your font // Each byte = one row of 8 pixels, MSB = leftmost pixel static const Uint8 s_FontBasic[128][8] = { - ['A'] = {0x18,0x24,0x42,0x42,0x7E,0x42,0x42,0x42}, - ['B'] = {0x7C,0x42,0x42,0x7C,0x42,0x42,0x42,0x7C}, - ['C'] = {0x3C,0x42,0x40,0x40,0x40,0x40,0x42,0x3C}, - ['D'] = {0x78,0x44,0x42,0x42,0x42,0x42,0x44,0x78}, - ['E'] = {0x7E,0x40,0x40,0x7C,0x40,0x40,0x40,0x7E}, - ['F'] = {0x7E,0x40,0x40,0x7C,0x40,0x40,0x40,0x40}, - ['G'] = {0x3C,0x42,0x40,0x40,0x4E,0x42,0x42,0x3C}, - ['H'] = {0x42,0x42,0x42,0x7E,0x42,0x42,0x42,0x42}, - ['I'] = {0x3E,0x08,0x08,0x08,0x08,0x08,0x08,0x3E}, - ['J'] = {0x1E,0x04,0x04,0x04,0x04,0x44,0x44,0x38}, - ['K'] = {0x42,0x44,0x48,0x70,0x48,0x44,0x42,0x42}, - ['L'] = {0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x7E}, - ['M'] = {0x42,0x66,0x5A,0x5A,0x42,0x42,0x42,0x42}, - ['N'] = {0x42,0x62,0x52,0x4A,0x46,0x42,0x42,0x42}, - ['O'] = {0x3C,0x42,0x42,0x42,0x42,0x42,0x42,0x3C}, - ['P'] = {0x7C,0x42,0x42,0x7C,0x40,0x40,0x40,0x40}, - ['Q'] = {0x3C,0x42,0x42,0x42,0x42,0x4A,0x44,0x3A}, - ['R'] = {0x7C,0x42,0x42,0x7C,0x48,0x44,0x42,0x42}, - ['S'] = {0x3C,0x42,0x40,0x3C,0x02,0x02,0x42,0x3C}, - ['T'] = {0x7F,0x49,0x08,0x08,0x08,0x08,0x08,0x08}, - ['U'] = {0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x3C}, - ['V'] = {0x42,0x42,0x42,0x42,0x42,0x24,0x24,0x18}, - ['W'] = {0x42,0x42,0x42,0x5A,0x5A,0x5A,0x66,0x42}, - ['X'] = {0x42,0x42,0x24,0x18,0x18,0x24,0x42,0x42}, - ['Y'] = {0x42,0x42,0x24,0x18,0x08,0x08,0x08,0x08}, - ['Z'] = {0x7E,0x02,0x04,0x08,0x10,0x20,0x40,0x7E}, - - ['a'] = {0x00,0x00,0x3C,0x02,0x3E,0x42,0x46,0x3A}, - ['b'] = {0x40,0x40,0x5C,0x62,0x42,0x42,0x62,0x5C}, - ['c'] = {0x00,0x00,0x3C,0x42,0x40,0x40,0x42,0x3C}, - ['d'] = {0x02,0x02,0x3A,0x46,0x42,0x42,0x46,0x3A}, - ['e'] = {0x00,0x00,0x3C,0x42,0x7E,0x40,0x42,0x3C}, - ['f'] = {0x0C,0x12,0x10,0x3C,0x10,0x10,0x10,0x10}, - ['g'] = {0x00,0x00,0x3A,0x46,0x46,0x3E,0x02,0x3C}, - ['h'] = {0x40,0x40,0x5C,0x62,0x42,0x42,0x42,0x42}, - ['i'] = {0x08,0x00,0x18,0x08,0x08,0x08,0x08,0x1C}, - ['j'] = {0x04,0x00,0x0C,0x04,0x04,0x04,0x44,0x38}, - ['k'] = {0x40,0x40,0x44,0x48,0x70,0x48,0x44,0x42}, - ['l'] = {0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x1C}, - ['m'] = {0x00,0x00,0x6C,0x52,0x52,0x42,0x42,0x42}, - ['n'] = {0x00,0x00,0x5C,0x62,0x42,0x42,0x42,0x42}, - ['o'] = {0x00,0x00,0x3C,0x42,0x42,0x42,0x42,0x3C}, - ['p'] = {0x00,0x00,0x5C,0x62,0x42,0x62,0x40,0x40}, - ['q'] = {0x00,0x00,0x3A,0x46,0x42,0x46,0x02,0x02}, - ['r'] = {0x00,0x00,0x5C,0x62,0x40,0x40,0x40,0x40}, - ['s'] = {0x00,0x00,0x3E,0x40,0x3C,0x02,0x42,0x3C}, - ['t'] = {0x10,0x10,0x3C,0x10,0x10,0x12,0x0C,0x00}, - ['u'] = {0x00,0x00,0x42,0x42,0x42,0x42,0x46,0x3A}, - ['v'] = {0x00,0x00,0x42,0x42,0x42,0x24,0x24,0x18}, - ['w'] = {0x00,0x00,0x42,0x42,0x42,0x52,0x52,0x2C}, - ['x'] = {0x00,0x00,0x42,0x24,0x18,0x18,0x24,0x42}, - ['y'] = {0x00,0x00,0x42,0x42,0x46,0x3A,0x02,0x3C}, - ['z'] = {0x00,0x00,0x7E,0x04,0x08,0x10,0x20,0x7E}, + ['A'] = {0x18, 0x24, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42}, + ['B'] = {0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x42, 0x7C}, + ['C'] = {0x3C, 0x42, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3C}, + ['D'] = {0x78, 0x44, 0x42, 0x42, 0x42, 0x42, 0x44, 0x78}, + ['E'] = {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x7E}, + ['F'] = {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x40}, + ['G'] = {0x3C, 0x42, 0x40, 0x40, 0x4E, 0x42, 0x42, 0x3C}, + ['H'] = {0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x42}, + ['I'] = {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E}, + ['J'] = {0x1E, 0x04, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38}, + ['K'] = {0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x42}, + ['L'] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E}, + ['M'] = {0x42, 0x66, 0x5A, 0x5A, 0x42, 0x42, 0x42, 0x42}, + ['N'] = {0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x42}, + ['O'] = {0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C}, + ['P'] = {0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x40}, + ['Q'] = {0x3C, 0x42, 0x42, 0x42, 0x42, 0x4A, 0x44, 0x3A}, + ['R'] = {0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x42, 0x42}, + ['S'] = {0x3C, 0x42, 0x40, 0x3C, 0x02, 0x02, 0x42, 0x3C}, + ['T'] = {0x7F, 0x49, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, + ['U'] = {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C}, + ['V'] = {0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18}, + ['W'] = {0x42, 0x42, 0x42, 0x5A, 0x5A, 0x5A, 0x66, 0x42}, + ['X'] = {0x42, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x42}, + ['Y'] = {0x42, 0x42, 0x24, 0x18, 0x08, 0x08, 0x08, 0x08}, + ['Z'] = {0x7E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7E}, + + ['a'] = {0x00, 0x00, 0x3C, 0x02, 0x3E, 0x42, 0x46, 0x3A}, + ['b'] = {0x40, 0x40, 0x5C, 0x62, 0x42, 0x42, 0x62, 0x5C}, + ['c'] = {0x00, 0x00, 0x3C, 0x42, 0x40, 0x40, 0x42, 0x3C}, + ['d'] = {0x02, 0x02, 0x3A, 0x46, 0x42, 0x42, 0x46, 0x3A}, + ['e'] = {0x00, 0x00, 0x3C, 0x42, 0x7E, 0x40, 0x42, 0x3C}, + ['f'] = {0x0C, 0x12, 0x10, 0x3C, 0x10, 0x10, 0x10, 0x10}, + ['g'] = {0x00, 0x00, 0x3A, 0x46, 0x46, 0x3E, 0x02, 0x3C}, + ['h'] = {0x40, 0x40, 0x5C, 0x62, 0x42, 0x42, 0x42, 0x42}, + ['i'] = {0x08, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x1C}, + ['j'] = {0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x44, 0x38}, + ['k'] = {0x40, 0x40, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42}, + ['l'] = {0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x1C}, + ['m'] = {0x00, 0x00, 0x6C, 0x52, 0x52, 0x42, 0x42, 0x42}, + ['n'] = {0x00, 0x00, 0x5C, 0x62, 0x42, 0x42, 0x42, 0x42}, + ['o'] = {0x00, 0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x3C}, + ['p'] = {0x00, 0x00, 0x5C, 0x62, 0x42, 0x62, 0x40, 0x40}, + ['q'] = {0x00, 0x00, 0x3A, 0x46, 0x42, 0x46, 0x02, 0x02}, + ['r'] = {0x00, 0x00, 0x5C, 0x62, 0x40, 0x40, 0x40, 0x40}, + ['s'] = {0x00, 0x00, 0x3E, 0x40, 0x3C, 0x02, 0x42, 0x3C}, + ['t'] = {0x10, 0x10, 0x3C, 0x10, 0x10, 0x12, 0x0C, 0x00}, + ['u'] = {0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3A}, + ['v'] = {0x00, 0x00, 0x42, 0x42, 0x42, 0x24, 0x24, 0x18}, + ['w'] = {0x00, 0x00, 0x42, 0x42, 0x42, 0x52, 0x52, 0x2C}, + ['x'] = {0x00, 0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42}, + ['y'] = {0x00, 0x00, 0x42, 0x42, 0x46, 0x3A, 0x02, 0x3C}, + ['z'] = {0x00, 0x00, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E}, }; void drawCharacter( - uint32_t *pixels, + uint32_t* pixels, int stride, int x, int y, char c, uint32_t color) { - if (c < 0 || c > 127) return; // not in out font + if (c < 0 || c > 127) + return; // not in out font - const uint8_t *bitmap = s_FontBasic[(int)c]; + const uint8_t* bitmap = s_FontBasic[(int)c]; for (int row = 0; row < 8; row++) { uint8_t bits = bitmap[row]; for (int col = 0; col < 8; col++) { - if (bits & (1 << (7-col))) { + if (bits & (1 << (7 - col))) { int px = x + col; int py = y + row; if (px < stride && py < TITLEBAR_HEIGHT) { - pixels[py*stride + px] = color; + pixels[py * stride + px] = color; } } } @@ -670,11 +665,11 @@ void drawCharacter( } void drawText( - uint32_t *pixels, + uint32_t* pixels, int stride, int x, int y, - const char *text, + const char* text, uint32_t color) { while (*text) { @@ -697,8 +692,7 @@ static void createDecoration() s_Decoration.subsurface = wlSubcompositorGetSubsurface( s_Subcompositor, s_Decoration.surface, - (struct wl_surface*)s_WinHandle.nativeWindow - ); + (struct wl_surface*)s_WinHandle.nativeWindow); if (!s_Decoration.subsurface) { palLog(nullptr, "Failed to create wayland subsurface"); @@ -725,14 +719,7 @@ static void createDecoration() // write pixels // title bar color (dark grey) - fillRect( - s_Decoration.pixels, - width, - 0, - 0, - width, - TITLEBAR_HEIGHT, - 0x002F3030); + fillRect(s_Decoration.pixels, width, 0, 0, width, TITLEBAR_HEIGHT, 0x002F3030); // Close button // this is just a rectangle for this simple example @@ -779,13 +766,7 @@ static void createDecoration() int x = (width - textWidth) / 2; int y = (TITLEBAR_HEIGHT - 8) / 2; - drawText( - s_Decoration.pixels, - width, - x, - y, - WINDOW_TITLE, - 0x00FFFFFF); + drawText(s_Decoration.pixels, width, x, y, WINDOW_TITLE, 0x00FFFFFF); // set opaque regions for optimazation // we wont do this in this example @@ -829,9 +810,7 @@ static void PAL_CALL onEvent( // we skip maximize and minimize button for simplicity // we just deal with the close button int buttonX = 640 - BUTTON_SIZE; - if (x >= buttonX && - x < buttonX + BUTTON_SIZE && - y >= BUTTON_POSY && + if (x >= buttonX && x < buttonX + BUTTON_SIZE && y >= BUTTON_POSY && y < BUTTON_POSY + BUTTON_SIZE) { // inside close button // trigger a window close event @@ -861,8 +840,7 @@ bool customDecorationTest() palLog(nullptr, "Custom Decoration Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, - "This only implements close and window movement for simplicity"); + palLog(nullptr, "This only implements close and window movement for simplicity"); palLog(nullptr, "==========================================="); palLog(nullptr, ""); @@ -888,34 +866,19 @@ bool customDecorationTest() return false; } - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_DECORATION_MODE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_DECORATION_MODE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // we use PAL_DISPATCH_CALLBACK for the mouse button to get // real time events which we then use for moving and resizing - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_MOUSE_BUTTONDOWN, - PAL_DISPATCH_CALLBACK); + palSetEventDispatchMode(eventDriver, PAL_EVENT_MOUSE_BUTTONDOWN, PAL_DISPATCH_CALLBACK); - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_MOUSE_MOVE, - PAL_DISPATCH_CALLBACK); + palSetEventDispatchMode(eventDriver, PAL_EVENT_MOUSE_MOVE, PAL_DISPATCH_CALLBACK); - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_MONITOR_DPI_CHANGED, - PAL_DISPATCH_CALLBACK); + palSetEventDispatchMode(eventDriver, PAL_EVENT_MONITOR_DPI_CHANGED, PAL_DISPATCH_CALLBACK); // tell the video system to use out instance rather // than creating a new one @@ -984,7 +947,6 @@ bool customDecorationTest() } } } - } // destroy decoration diff --git a/tests/icon_test.c b/tests/icon_test.c index a3be2783..e328b770 100644 --- a/tests/icon_test.c +++ b/tests/icon_test.c @@ -106,10 +106,8 @@ bool iconTest() } // set the dispatch mode for window close event to recieve it - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); // polling + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, + PAL_DISPATCH_POLL); // polling palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); diff --git a/tests/input_window_test.c b/tests/input_window_test.c index 5500483f..968ee504 100644 --- a/tests/input_window_test.c +++ b/tests/input_window_test.c @@ -284,12 +284,7 @@ static inline void onKeydown(const PalEvent* event) // get keycode and scancode name const char* keyName = s_KeyNames[keycode]; const char* scancodeName = s_ScancodeNames[scancode]; - palLog( - nullptr, - "%s: Key pressed: (%s, %s)", - dispatchString, - keyName, - scancodeName); + palLog(nullptr, "%s: Key pressed: (%s, %s)", dispatchString, keyName, scancodeName); if (keycode == PAL_KEYCODE_ESCAPE) { s_Running = false; @@ -305,12 +300,7 @@ static inline void onKeyrepeat(const PalEvent* event) // get keycode and scancode name const char* keyName = s_KeyNames[keycode]; const char* scancodeName = s_ScancodeNames[scancode]; - palLog( - nullptr, - "%s: Key repeat: (%s, %s)", - dispatchString, - keyName, - scancodeName); + palLog(nullptr, "%s: Key repeat: (%s, %s)", dispatchString, keyName, scancodeName); } static inline void onKeyup(const PalEvent* event) @@ -322,12 +312,7 @@ static inline void onKeyup(const PalEvent* event) // get keycode and scancode name const char* keyName = s_KeyNames[keycode]; const char* scancodeName = s_ScancodeNames[scancode]; - palLog( - nullptr, - "%s: Key released: (%s, %s)", - dispatchString, - keyName, - scancodeName); + palLog(nullptr, "%s: Key released: (%s, %s)", dispatchString, keyName, scancodeName); } static inline void onMouseButtondown(const PalEvent* event) @@ -379,12 +364,7 @@ static inline void onMouseWheel(const PalEvent* event) PalWindow* window = palUnpackPointer(event->data2); palLog(nullptr, "%s: Mouse Wheel: (%d, %d)", dispatchString, dx, dy); - palLog( - nullptr, - "%s: Mouse Wheel Raw: (%.2f, %.2f)", - dispatchString, - fdx, - fdy); + palLog(nullptr, "%s: Mouse Wheel Raw: (%.2f, %.2f)", dispatchString, fdx, fdy); } static void PAL_CALL onEvent( @@ -484,10 +464,7 @@ bool inputWindowTest() } // we set window close to poll - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); PalDispatchMode dispatchMode = PAL_DISPATCH_NONE; #if DISPATCH_MODE_POLL diff --git a/tests/mesh_test.c b/tests/mesh_test.c index cfd4f0bf..48b19560 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -5,7 +5,10 @@ #include -static bool readFile(const char* filename, void* buffer, Uint64* size) +static bool readFile( + const char* filename, + void* buffer, + Uint64* size) { FILE* file = fopen(filename, "rb"); if (!file) { @@ -76,15 +79,9 @@ bool meshTest() return false; } - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_KEYDOWN, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { @@ -182,12 +179,10 @@ bool meshTest() palFree(nullptr, adapters); if (!adapter) { if (hasGfxQueue) { - palLog(nullptr, - "Failed to find an adapter that supports graphics queue"); + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); } else { - palLog(nullptr, - "Failed to find an adapter that supports mesh shader"); + palLog(nullptr, "Failed to find an adapter that supports mesh shader"); } return false; } @@ -229,10 +224,7 @@ bool meshTest() // create a swapchain with the graphics queue PalSwapchainCapabilities swapchainCaps = {0}; - result = palQuerySwapchainCapabilities( - device, - &gfxWindow, - &swapchainCaps); + result = palQuerySwapchainCapabilities(device, &gfxWindow, &swapchainCaps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -262,12 +254,7 @@ bool meshTest() swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - result = palCreateSwapchain( - device, - queue, - &gfxWindow, - &swapchainCreateInfo, - &swapchain); + result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -277,15 +264,9 @@ bool meshTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; - imageViews = palAllocate( - nullptr, - sizeof(PalImageView*) * imageCount, - 0); + imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - renderFinishedSemaphores = palAllocate( - nullptr, - sizeof(PalSemaphore*) * imageCount, - 0); + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); @@ -300,7 +281,7 @@ bool meshTest() imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; - for (int i = 0; i < imageCount; i++) { + for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL PalImage* image = palGetSwapchainImage(swapchain, i); @@ -308,11 +289,7 @@ bool meshTest() palLog(nullptr, "Failed to get swapchain image"); } - result = palCreateImageView( - device, - image, - &imageViewCreateInfo, - &imageViews[i]); + result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -321,10 +298,7 @@ bool meshTest() } } - result = palCreateCommandPool( - device, - queue, - &cmdPool); + result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -399,10 +373,7 @@ bool meshTest() shaderCreateInfo.bytecodeSize = bytecodeSize; shaderCreateInfo.stage = PAL_SHADER_STAGE_MESH; - result = palCreateShader( - device, - &shaderCreateInfo, - &meshShader); + result = palCreateShader(device, &shaderCreateInfo, &meshShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -431,10 +402,7 @@ bool meshTest() shaderCreateInfo.bytecodeSize = bytecodeSize; shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; - result = palCreateShader( - device, - &shaderCreateInfo, - &fragmentShader); + result = palCreateShader(device, &shaderCreateInfo, &fragmentShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -446,10 +414,7 @@ bool meshTest() // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; - result = palCreatePipelineLayout( - device, - &pipelineLayoutCreateInfo, - &pipelineLayout); + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -505,10 +470,7 @@ bool meshTest() pipelineCreateInfo.pipelineLayout = pipelineLayout; pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; - result = palCreateGraphicsPipeline( - device, - &pipelineCreateInfo, - &pipeline); + result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/multi_thread_opengl_test.c b/tests/multi_thread_opengl_test.c index 6f328690..80260810 100644 --- a/tests/multi_thread_opengl_test.c +++ b/tests/multi_thread_opengl_test.c @@ -11,8 +11,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARCOLORPROC)( float blue, float alpha); -typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)( - Uint32 mask); // use GL typedefs if needed +typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(Uint32 mask); // use GL typedefs if needed typedef void (*glFlushFn)(); typedef void (*glBeginFn)(unsigned int); @@ -70,26 +69,14 @@ static void* PAL_CALL eventDriverWorker(void* arg) } // set dispatch modes. opengl needs only window resize - palSetEventDispatchMode( - shared->openglEventDriver, - PAL_EVENT_WINDOW_SIZE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(shared->openglEventDriver, PAL_EVENT_WINDOW_SIZE, PAL_DISPATCH_POLL); // video needs window close and resize - palSetEventDispatchMode( - shared->videoEventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(shared->videoEventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode( - shared->videoEventDriver, - PAL_EVENT_WINDOW_SIZE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(shared->videoEventDriver, PAL_EVENT_WINDOW_SIZE, PAL_DISPATCH_POLL); - palSetEventDispatchMode( - shared->videoEventDriver, - PAL_EVENT_KEYDOWN, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(shared->videoEventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // we are done shared->driverCreated = true; @@ -147,11 +134,7 @@ static void* PAL_CALL rendererWorkder(void* arg) case PAL_EVENT_WINDOW_SIZE: { Uint32 width, height; palUnpackUint32(event.data, &width, &height); - palLog( - nullptr, - "Video driver sent a resize event (%d, %d)", - width, - height); + palLog(nullptr, "Video driver sent a resize event (%d, %d)", width, height); glViewport(0, 0, width, height); // we can optionally send back a user event diff --git a/tests/native_instance_test.c b/tests/native_instance_test.c index 25009002..d7803d7f 100644 --- a/tests/native_instance_test.c +++ b/tests/native_instance_test.c @@ -115,14 +115,10 @@ static inline int wlRegistryAddListener( const struct wl_registry_listener* listener, void* data) { - return s_wl_proxy_add_listener( - (struct wl_proxy*)wl_registry, - (void (**)(void))listener, - data); + return s_wl_proxy_add_listener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); } -static inline struct wl_registry* -wlDisplayGetRegistry(struct wl_display* wl_display) +static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_display) { struct wl_proxy* registry; registry = s_wl_proxy_marshal_flags( @@ -186,6 +182,7 @@ void* openDisplayX11() s_XCloseDisplay = (XCloseDisplayFn)dlsym( s_LibX, "XCloseDisplay"); + // clang-format on return s_XOpenDisplay(nullptr); #endif // __linux__ @@ -236,9 +233,9 @@ void* openDisplayWayland() s_wl_proxy_destroy = (wl_proxy_destroy_fn)dlsym( s_LibWayland, "wl_proxy_destroy"); + // clang-format on registryInterface = dlsym(s_LibWayland, "wl_registry_interface"); - struct wl_display* display = s_wl_display_connect(nullptr); if (display) { s_Registry = wlDisplayGetRegistry(display); @@ -377,15 +374,9 @@ bool nativeInstanceTest() } // we set window close to poll - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); - - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_KEYDOWN, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); + + palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); bool running = true; while (running) { diff --git a/tests/native_integration_test.c b/tests/native_integration_test.c index 2e39d56a..0ab66aaa 100644 --- a/tests/native_integration_test.c +++ b/tests/native_integration_test.c @@ -158,7 +158,6 @@ void setWindowTitleX11(PalWindowHandleInfoEx* windowInfo) s_XFree = (XFreeFn)dlsym( s_X11Lib, "XFree"); - // clang-format on Display* display = (Display*)windowInfo->nativeDisplay; @@ -236,15 +235,12 @@ void setWindowTitleWayland(PalWindowHandleInfoEx* windowInfo) return; } - s_wl_proxy_marshal_flags = (wl_proxy_marshal_flags_fn)dlsym( - s_WaylandLib, - "wl_proxy_marshal_flags"); + s_wl_proxy_marshal_flags = + (wl_proxy_marshal_flags_fn)dlsym(s_WaylandLib, "wl_proxy_marshal_flags"); - s_wl_proxy_get_version = - (wl_proxy_get_version_fn)dlsym(s_WaylandLib, "wl_proxy_get_version"); + s_wl_proxy_get_version = (wl_proxy_get_version_fn)dlsym(s_WaylandLib, "wl_proxy_get_version"); - s_wl_display_flush = - (wl_display_flush_fn)dlsym(s_WaylandLib, "wl_display_flush"); + s_wl_display_flush = (wl_display_flush_fn)dlsym(s_WaylandLib, "wl_display_flush"); struct xdg_toplevel* toplevel = nullptr; struct wl_display* display = nullptr; @@ -277,10 +273,7 @@ void setWindowTitleWin32(PalWindowHandleInfoEx* windowInfo) void getWindowTitleWin32(PalWindowHandleInfoEx* windowInfo) { #ifdef _WIN32 - GetWindowTextA( - (HWND)windowInfo->nativeWindow, - s_TitleBuffer, - sizeof(s_TitleBuffer)); + GetWindowTextA((HWND)windowInfo->nativeWindow, s_TitleBuffer, sizeof(s_TitleBuffer)); #endif // _WIN32 } @@ -378,10 +371,7 @@ bool nativeIntegrationTest() } // we set window close to poll - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); diff --git a/tests/opengl_context_test.c b/tests/opengl_context_test.c index cc893ad3..62d42a45 100644 --- a/tests/opengl_context_test.c +++ b/tests/opengl_context_test.c @@ -12,8 +12,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARCOLORPROC)( float blue, float alpha); -typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)( - Uint32 mask); // use GL typedefs if needed +typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(Uint32 mask); // use GL typedefs if needed bool openglContextTest() { @@ -196,10 +195,7 @@ bool openglContextTest() } // we set window close to poll - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); diff --git a/tests/opengl_multi_context_test.c b/tests/opengl_multi_context_test.c index 5ae9072d..9b6dcf3f 100644 --- a/tests/opengl_multi_context_test.c +++ b/tests/opengl_multi_context_test.c @@ -12,8 +12,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARCOLORPROC)( float blue, float alpha); -typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)( - Uint32 mask); // use GL typedefs if needed +typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(Uint32 mask); // use GL typedefs if needed bool openglMultiContextTest() { @@ -196,10 +195,7 @@ bool openglMultiContextTest() } // we set window close to poll - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); diff --git a/tests/system_cursor_test.c b/tests/system_cursor_test.c index c1cbf875..0ad37025 100644 --- a/tests/system_cursor_test.c +++ b/tests/system_cursor_test.c @@ -86,10 +86,8 @@ bool systemCursorTest() } // set the dispatch mode for window close event to recieve it - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); // polling + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, + PAL_DISPATCH_POLL); // polling palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); diff --git a/tests/time_test.c b/tests/time_test.c index d3c427b2..e5ae19ce 100644 --- a/tests/time_test.c +++ b/tests/time_test.c @@ -38,20 +38,12 @@ bool timeTest() double now = getTime(&timer); totalTime = now - lastTime; - palLog( - nullptr, - "Frame %d, Total Time %f seconds", - frameCount, - totalTime); + palLog(nullptr, "Frame %d, Total Time %f seconds", frameCount, totalTime); frameCount++; } - palLog( - nullptr, - "Loop finished after %f seconds and %d frames", - totalTime, - frameCount); + palLog(nullptr, "Loop finished after %f seconds and %d frames", totalTime, frameCount); return true; } diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 12f753b9..db2d7fdd 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -5,7 +5,10 @@ #include -static bool readFile(const char* filename, void* buffer, Uint64* size) +static bool readFile( + const char* filename, + void* buffer, + Uint64* size) { FILE* file = fopen(filename, "rb"); if (!file) { @@ -81,15 +84,9 @@ bool triangleTest() return false; } - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_KEYDOWN, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { @@ -180,8 +177,7 @@ bool triangleTest() palFree(nullptr, adapters); if (!adapter) { - palLog(nullptr, - "Failed to find an adapter that supports graphics queue"); + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); return false; } @@ -222,10 +218,7 @@ bool triangleTest() // create a swapchain with the graphics queue PalSwapchainCapabilities swapchainCaps = {0}; - result = palQuerySwapchainCapabilities( - device, - &gfxWindow, - &swapchainCaps); + result = palQuerySwapchainCapabilities(device, &gfxWindow, &swapchainCaps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -255,12 +248,7 @@ bool triangleTest() swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - result = palCreateSwapchain( - device, - queue, - &gfxWindow, - &swapchainCreateInfo, - &swapchain); + result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -270,15 +258,9 @@ bool triangleTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; - imageViews = palAllocate( - nullptr, - sizeof(PalImageView*) * imageCount, - 0); + imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - renderFinishedSemaphores = palAllocate( - nullptr, - sizeof(PalSemaphore*) * imageCount, - 0); + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); @@ -293,7 +275,7 @@ bool triangleTest() imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; - for (int i = 0; i < imageCount; i++) { + for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL PalImage* image = palGetSwapchainImage(swapchain, i); @@ -301,11 +283,7 @@ bool triangleTest() palLog(nullptr, "Failed to get swapchain image"); } - result = palCreateImageView( - device, - image, - &imageViewCreateInfo, - &imageViews[i]); + result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -314,10 +292,7 @@ bool triangleTest() } } - result = palCreateCommandPool( - device, - queue, - &cmdPool); + result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -366,19 +341,28 @@ bool triangleTest() // create vertex and staging buffer float vertices[] = { - 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, - 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.0f, 0.0f, 1.0f}; + 0.0f, + 0.5f, + 1.0f, + 0.0f, + 0.0f, + 0.5f, + -0.5f, + 0.0f, + 1.0f, + 0.0f, + -0.5f, + -0.5f, + 0.0f, + 0.0f, + 1.0f}; PalBufferCreateInfo bufferCreateInfo = {0}; bufferCreateInfo.size = sizeof(vertices); bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve - result = palCreateBuffer( - device, - &bufferCreateInfo, - &vertexBuffer); + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -387,10 +371,7 @@ bool triangleTest() } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send - result = palCreateBuffer( - device, - &bufferCreateInfo, - &stagingBuffer); + result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -401,9 +382,7 @@ bool triangleTest() // get buffer memory requirement and allocate memory PalMemoryRequirements vertexBufferMemReq = {0}; PalMemoryRequirements stagingBufferMemReq = {0}; - result = palGetBufferMemoryRequirements( - vertexBuffer, - &vertexBufferMemReq); + result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -411,9 +390,7 @@ bool triangleTest() return false; } - result = palGetBufferMemoryRequirements( - stagingBuffer, - &stagingBufferMemReq); + result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -466,12 +443,7 @@ bool triangleTest() // map the staging buffer and upload the vertices void* ptr = nullptr; - result = palMapMemory( - device, - stagingBufferMemory, - 0, - sizeof(vertices), - &ptr); + result = palMapMemory(device, stagingBufferMemory, 0, sizeof(vertices), &ptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -501,13 +473,7 @@ bool triangleTest() return false; } - result = palCopyBuffer( - cmdBuffers[0], - vertexBuffer, - stagingBuffer, - 0, - 0, - sizeof(vertices)); + result = palCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, 0, 0, sizeof(vertices)); result = palBufferBarrier( cmdBuffers[0], @@ -566,10 +532,7 @@ bool triangleTest() shaderCreateInfo.bytecodeSize = bytecodeSize; shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; - result = palCreateShader( - device, - &shaderCreateInfo, - &vertexShader); + result = palCreateShader(device, &shaderCreateInfo, &vertexShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -598,10 +561,7 @@ bool triangleTest() shaderCreateInfo.bytecodeSize = bytecodeSize; shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; - result = palCreateShader( - device, - &shaderCreateInfo, - &fragmentShader); + result = palCreateShader(device, &shaderCreateInfo, &fragmentShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -613,10 +573,7 @@ bool triangleTest() // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; - result = palCreatePipelineLayout( - device, - &pipelineLayoutCreateInfo, - &pipelineLayout); + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -690,10 +647,7 @@ bool triangleTest() pipelineCreateInfo.pipelineLayout = pipelineLayout; pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; - result = palCreateGraphicsPipeline( - device, - &pipelineCreateInfo, - &pipeline); + result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/window_test.c b/tests/window_test.c index 5d425779..4b2b554b 100644 --- a/tests/window_test.c +++ b/tests/window_test.c @@ -33,12 +33,7 @@ static inline void onWindowResize(const PalEvent* event) Uint32 width, height; // width == low, height == high palUnpackUint32(event->data, &width, &height); PalWindow* window = palUnpackPointer(event->data2); - palLog( - nullptr, - "%s: Window Resized: (%d, %d)", - dispatchString, - width, - height); + palLog(nullptr, "%s: Window Resized: (%d, %d)", dispatchString, width, height); } static inline void onWindowMove(const PalEvent* event) @@ -192,29 +187,17 @@ bool windowTest() } // we set window close to poll - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // we set callback mode for modal begin and end. Since we want to capture // that instantly - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_MODAL_BEGIN, - PAL_DISPATCH_CALLBACK); - - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_MODAL_END, - PAL_DISPATCH_CALLBACK); - - palSetEventDispatchMode( - eventDriver, - PAL_EVENT_WINDOW_DECORATION_MODE, - PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_MODAL_BEGIN, PAL_DISPATCH_CALLBACK); + + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_MODAL_END, PAL_DISPATCH_CALLBACK); + + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_DECORATION_MODE, PAL_DISPATCH_POLL); // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must From 41ca7776062dc7584180624d02475e10438e9cce Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 10 Jan 2026 12:08:21 +0000 Subject: [PATCH 082/372] add descriptor pool and set layout API --- include/pal/pal_graphics.h | 78 +++++++++++-- src/graphics/pal_graphics.c | 114 ++++++++++++++++-- src/graphics/pal_vulkan.c | 227 ++++++++++++++++++++++++++++++++++-- src/video/pal_video_linux.c | 4 +- tests/clear_color_test.c | 6 +- tests/mesh_test.c | 12 +- tests/tests.h | 1 - tests/tests_main.c | 6 +- tests/triangle_test.c | 12 +- 9 files changed, 409 insertions(+), 51 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 4cbd463e..e9ddde78 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -54,8 +54,13 @@ typedef struct PalSemaphore PalSemaphore; typedef struct PalCommandPool PalCommandPool; typedef struct PalCommandBuffer PalCommandBuffer; -typedef struct PalPipeline PalPipeline; +typedef struct PalDescriptorSetLayout PalDescriptorSetLayout; +typedef struct PalDescriptorPool PalDescriptorPool; + +typedef struct PalDescriptorSet PalDescriptorSet; typedef struct PalPipelineLayout PalPipelineLayout; + +typedef struct PalPipeline PalPipeline; typedef struct PalAccelerationStructure PalAccelerationStructure; typedef enum PalDebugMessageSeverity PalDebugMessageSeverity; @@ -539,6 +544,11 @@ typedef enum { PAL_USAGE_STATE_STORAGE_WRITE } PalUsageState; +typedef enum { + PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER, + PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER +} PalDescriptorType; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -817,7 +827,7 @@ typedef struct { PalBlendFactor srcAlphaBlendFactor; PalBlendFactor dstAlphaBlendFactor; PalBlendOp alphaBlendOp; -} PalBlendAttachment; +} PalColorBlendAttachment; typedef struct { PalFragmentShadingRate rate; @@ -874,6 +884,19 @@ typedef struct { PalGeometry* geometries; } PalAccelerationStructureBuildInfo; +typedef struct { + Uint32 binding; + Uint32 descriptorCount; + Uint32 shaderStageCount; + PalShaderStage* shaderStages; + PalDescriptorType descriptorType; +} PalDescriptorSetLayoutBinding; + +typedef struct { + Uint32 bindingCount; + PalDescriptorType descriptorType; +} PalDescriptorPoolBindingSize; + typedef struct { Uint32 width; Uint32 height; @@ -924,19 +947,30 @@ typedef struct { Uint64 size; } PalAccelerationStructureCreateInfo; +typedef struct { + Uint32 bindingCount; + PalDescriptorSetLayoutBinding* bindings; +} PalDescriptorSetLayoutCreateInfo; + +typedef struct { + Uint32 maxDescriptorSets; + Uint32 maxDescriptorBindingSizes; + PalDescriptorPoolBindingSize* bindingSizes; +} PalDescriptorPoolCreateInfo; + typedef struct { bool unused; } PalPipelineLayoutCreateInfo; typedef struct { Uint32 vertexLayoutCount; - Uint32 blendAttachmentCount; + Uint32 colorBlendAttachmentCount; Uint32 shaderCount; PalPrimitiveTopology topology; PalPipelineLayout* pipelineLayout; PalShader** shaders; PalVertexLayout* vertexLayouts; - PalBlendAttachment* blendAttachments; + PalColorBlendAttachment* colorBlendAttachments; PalRasterizerState* rasterizerState; PalMultisampleState* multisampleState; PalDepthStencilState* depthStencilState; @@ -1142,13 +1176,13 @@ typedef struct { PalResult PAL_CALL (*resetCommandPool)(PalCommandPool* pool); - PalResult PAL_CALL (*createCommandBuffer)( + PalResult PAL_CALL (*allocateCommandBuffer)( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, PalCommandBuffer** outCmdBuffer); - void PAL_CALL (*destroyCommandBuffer)(PalCommandBuffer* cmdBuffer); + void PAL_CALL (*freeCommandBuffer)(PalCommandBuffer* cmdBuffer); PalResult PAL_CALL (*beginCommandBuffer)( PalCommandBuffer* cmdBuffer, @@ -1333,6 +1367,20 @@ typedef struct { PalMemory* memory, Uint64 offset); + PalResult PAL_CALL (*createDescriptorSetLayout)( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + + void PAL_CALL (*destroyDescriptorSetLayout)(PalDescriptorSetLayout* layout); + + PalResult PAL_CALL (*createDescriptorPool)( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + + void PAL_CALL (*destroyDescriptorPool)(PalDescriptorPool* pool); + PalResult PAL_CALL (*createPipelineLayout)( PalDevice* device, const PalPipelineLayoutCreateInfo* info, @@ -1553,13 +1601,13 @@ PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); -PAL_API PalResult PAL_CALL palCreateCommandBuffer( +PAL_API PalResult PAL_CALL palAllocateCommandBuffer( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, PalCommandBuffer** outCmdbuffer); -PAL_API void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer); +PAL_API void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer); PAL_API PalResult PAL_CALL palBeginCommandBuffer( PalCommandBuffer* cmdBuffer, @@ -1744,6 +1792,20 @@ PAL_API PalResult PAL_CALL palBindBufferMemory( PalMemory* memory, Uint64 offset); +PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + +PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layout); + +PAL_API PalResult PAL_CALL palCreateDescriptorPool( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + +PAL_API void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool); + PAL_API PalResult PAL_CALL palCreatePipelineLayout( PalDevice* device, const PalPipelineLayoutCreateInfo* info, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index df056524..3daccbf0 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -53,6 +53,8 @@ PAL_HANDLE(PalCommandBuffer) PAL_HANDLE(PalPipeline) PAL_HANDLE(PalAccelerationStructure) PAL_HANDLE(PalPipelineLayout) +PAL_HANDLE(PalDescriptorSetLayout) +PAL_HANDLE(PalDescriptorPool) typedef struct { Int32 count; @@ -285,13 +287,13 @@ void PAL_CALL destroyVkCommandPool(PalCommandPool* pool); PalResult PAL_CALL resetVkCommandPool(PalCommandPool* pool); -PalResult PAL_CALL createVkCommandBuffer( +PalResult PAL_CALL allocateVkCommandBuffer( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, PalCommandBuffer** outBuffer); -void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* buffer); +void PAL_CALL freeVkCommandBuffer(PalCommandBuffer* buffer); PalResult PAL_CALL beginVkCommandBuffer( PalCommandBuffer* cmdBuffer, @@ -487,6 +489,20 @@ void PAL_CALL unmapVkMemory( PalDevice* device, PalMemory* memory); +PalResult PAL_CALL createVkDescriptorSetLayout( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + +void PAL_CALL destroyVkDescriptorSetLayout(PalDescriptorSetLayout* layout); + +PalResult PAL_CALL createVkDescriptorPool( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + +void PAL_CALL destroyVkDescriptorPool(PalDescriptorPool* pool); + PalResult PAL_CALL createVkPipelineLayout( PalDevice* device, const PalPipelineLayoutCreateInfo* info, @@ -553,8 +569,8 @@ static PalGraphicsBackend s_VkBackend = { .createCommandPool = createVkCommandPool, .destroyCommandPool = destroyVkCommandPool, .resetCommandPool = resetVkCommandPool, - .createCommandBuffer = createVkCommandBuffer, - .destroyCommandBuffer = destroyVkCommandBuffer, + .allocateCommandBuffer = allocateVkCommandBuffer, + .freeCommandBuffer = freeVkCommandBuffer, .beginCommandBuffer = beginVkCommandBuffer, .endCommandBuffer = endVkCommandBuffer, .resetCommandBuffer = resetVkCommandBuffer, @@ -591,6 +607,10 @@ static PalGraphicsBackend s_VkBackend = { .destroyBuffer = destroyVkBuffer, .getBufferMemoryRequirements = getVkBufferMemoryRequirements, .bindBufferMemory = bindVkBufferMemory, + .createDescriptorSetLayout = createVkDescriptorSetLayout, + .destroyDescriptorSetLayout = destroyVkDescriptorSetLayout, + .createDescriptorPool = createVkDescriptorPool, + .destroyDescriptorPool = destroyVkDescriptorPool, .createPipelineLayout = createVkPipelineLayout, .destroyPipelineLayout = destroyVkPipelineLayout, .createGraphicsPipeline = createVkGraphicsPipeline, @@ -679,8 +699,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->createCommandPool || !backend->destroyCommandPool || !backend->resetCommandPool || - !backend->createCommandBuffer || - !backend->destroyCommandBuffer || + !backend->allocateCommandBuffer || + !backend->freeCommandBuffer || !backend->beginCommandBuffer || !backend->endCommandBuffer || !backend->resetCommandBuffer || @@ -719,6 +739,10 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->bindBufferMemory || !backend->mapMemory || !backend->unmapMemory || + !backend->createDescriptorSetLayout || + !backend->destroyDescriptorSetLayout || + !backend->createDescriptorPool || + !backend->destroyDescriptorPool || !backend->createPipelineLayout || !backend->destroyPipelineLayout || !backend->createGraphicsPipeline || @@ -1605,7 +1629,7 @@ PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool) return pool->backend->resetCommandPool(pool); } -PalResult PAL_CALL palCreateCommandBuffer( +PalResult PAL_CALL palAllocateCommandBuffer( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, @@ -1621,7 +1645,7 @@ PalResult PAL_CALL palCreateCommandBuffer( PalCommandBuffer* cmdBuffer = nullptr; PalResult result; - result = device->backend->createCommandBuffer(device, pool, type, &cmdBuffer); + result = device->backend->allocateCommandBuffer(device, pool, type, &cmdBuffer); if (result != PAL_RESULT_SUCCESS) { return result; @@ -1632,10 +1656,10 @@ PalResult PAL_CALL palCreateCommandBuffer( return PAL_RESULT_SUCCESS; } -void PAL_CALL palDestroyCommandBuffer(PalCommandBuffer* cmdBuffer) +void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer) { if (s_Graphics.initialized && cmdBuffer) { - cmdBuffer->backend->destroyCommandBuffer(cmdBuffer); + cmdBuffer->backend->freeCommandBuffer(cmdBuffer); } } @@ -2291,6 +2315,74 @@ void PAL_CALL palUnmapMemory( device->backend->unmapMemory(device, memory); } +// ================================================== +// Descriptor Pool, Set and Layout +// ================================================== + +PalResult PAL_CALL palCreateDescriptorSetLayout( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outLayout) { + return PAL_RESULT_NULL_POINTER; + } + + PalResult result; + PalDescriptorSetLayout* layout = nullptr; + result = device->backend->createDescriptorSetLayout(device, info, &layout); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + layout->backend = device->backend; + *outLayout = layout; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layout) +{ + if (s_Graphics.initialized && layout) { + layout->backend->destroyDescriptorSetLayout(layout); + } +} + +PalResult PAL_CALL palCreateDescriptorPool( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outPool) { + return PAL_RESULT_NULL_POINTER; + } + + PalResult result; + PalDescriptorPool* pool = nullptr; + result = device->backend->createDescriptorPool(device, info, &pool); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + pool->backend = device->backend; + *outPool = pool; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool) +{ + if (s_Graphics.initialized && pool) { + pool->backend->destroyDescriptorPool(pool); + } +} + // ================================================== // Pipeline // ================================================== @@ -2366,7 +2458,7 @@ void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) } // ================================================== -// Helpers +// Utils // ================================================== bool PAL_CALL palBuildWorkGroupInfo( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index cc6e550d..e013fb3d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -122,8 +122,8 @@ typedef struct { PFN_vkCreateCommandPool createCommandPool; PFN_vkDestroyCommandPool destroyCommandPool; - PFN_vkAllocateCommandBuffers createCommandBuffer; - PFN_vkFreeCommandBuffers destroyCommandBuffer; + PFN_vkAllocateCommandBuffers allocateCommandBuffer; + PFN_vkFreeCommandBuffers freeCommandBuffer; PFN_vkCreateFence createFence; PFN_vkDestroyFence destroyFence; PFN_vkResetFences resetFence; @@ -167,6 +167,11 @@ typedef struct { PFN_vkMapMemory mapMemory; PFN_vkUnmapMemory unmapMemory; + PFN_vkCreateDescriptorSetLayout createDescriptorSetLayout; + PFN_vkDestroyDescriptorSetLayout destroyDescriptorSetLayout; + PFN_vkCreateDescriptorPool createDescriptorPool; + PFN_vkDestroyDescriptorPool destroyDescriptorPool; + PFN_vkCreatePipelineLayout createPipelineLayout; PFN_vkDestroyPipelineLayout destroyPipelineLayout; PFN_vkCreateGraphicsPipelines createGraphicsPipeline; @@ -340,6 +345,20 @@ typedef struct { VkAccelerationStructureKHR handle; } AccelerationStructure; +typedef struct { + const PalGraphicsBackend* backend; + + Device* device; + VkDescriptorSetLayout handle; +} DescriptorSetLayout; + +typedef struct { + const PalGraphicsBackend* backend; + + Device* device; + VkDescriptorPool handle; +} DescriptorPool; + typedef struct { const PalGraphicsBackend* backend; @@ -1654,6 +1673,50 @@ static Barrier barrierToVk(PalUsageState state) return barrier; } +static VkDescriptorType descriptortypeToVk(PalDescriptorType type) +{ + switch (type) { + case PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER: + return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + + case PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + } + + return 0; +} + +static VkShaderStageFlagBits shaderStageToVK(PalShaderStage stage) +{ + switch (stage) { + case PAL_SHADER_STAGE_VERTEX: + return VK_SHADER_STAGE_VERTEX_BIT; + + case PAL_SHADER_STAGE_FRAGMENT: + return VK_SHADER_STAGE_FRAGMENT_BIT; + + case PAL_SHADER_STAGE_COMPUTE: + return VK_SHADER_STAGE_COMPUTE_BIT; + + case PAL_SHADER_STAGE_GEOMETRY: + return VK_SHADER_STAGE_GEOMETRY_BIT; + + case PAL_SHADER_STAGE_MESH: + return VK_SHADER_STAGE_MESH_BIT_EXT; + + case PAL_SHADER_STAGE_TASK: + return VK_SHADER_STAGE_TASK_BIT_EXT; + + case PAL_SHADER_STAGE_TESSELLATION_CONTROL: + return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + + case PAL_SHADER_STAGE_TESSELLATION_EVALUATION: + return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + } + + return 0; +} + static void* vkAlloc( void* pUserData, size_t size, @@ -1909,11 +1972,11 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroyCommandPool"); - s_Vk.createCommandBuffer = (PFN_vkAllocateCommandBuffers)dlsym( + s_Vk.allocateCommandBuffer = (PFN_vkAllocateCommandBuffers)dlsym( s_Vk.handle, "vkAllocateCommandBuffers"); - s_Vk.destroyCommandBuffer = (PFN_vkFreeCommandBuffers)dlsym( + s_Vk.freeCommandBuffer = (PFN_vkFreeCommandBuffers)dlsym( s_Vk.handle, "vkFreeCommandBuffers"); @@ -2037,6 +2100,22 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkBindBufferMemory"); + s_Vk.createDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)dlsym( + s_Vk.handle, + "vkCreateDescriptorSetLayout"); + + s_Vk.destroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)dlsym( + s_Vk.handle, + "vkDestroyDescriptorSetLayout"); + + s_Vk.createDescriptorPool = (PFN_vkCreateDescriptorPool)dlsym( + s_Vk.handle, + "vkCreateDescriptorPool"); + + s_Vk.destroyDescriptorPool = (PFN_vkDestroyDescriptorPool)dlsym( + s_Vk.handle, + "vkDestroyDescriptorPool"); + s_Vk.createPipelineLayout = (PFN_vkCreatePipelineLayout)dlsym( s_Vk.handle, "vkCreatePipelineLayout"); @@ -4981,7 +5060,7 @@ PalResult PAL_CALL resetVkCommandPool(PalCommandPool* pool) return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL createVkCommandBuffer( +PalResult PAL_CALL allocateVkCommandBuffer( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, @@ -5009,7 +5088,7 @@ PalResult PAL_CALL createVkCommandBuffer( cmdBuffer->primary = false; } - result = s_Vk.createCommandBuffer(vkDevice->handle, &createInfo, &cmdBuffer->handle); + result = s_Vk.allocateCommandBuffer(vkDevice->handle, &createInfo, &cmdBuffer->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, cmdBuffer); @@ -5023,10 +5102,10 @@ PalResult PAL_CALL createVkCommandBuffer( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkCommandBuffer(PalCommandBuffer* cmdBuffer) +void PAL_CALL freeVkCommandBuffer(PalCommandBuffer* cmdBuffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - s_Vk.destroyCommandBuffer( + s_Vk.freeCommandBuffer( vkCmdBuffer->device->handle, vkCmdBuffer->pool->handle, 1, @@ -6355,6 +6434,132 @@ PalResult PAL_CALL bindVkBufferMemory( return PAL_RESULT_SUCCESS; } +// ================================================== +// Descriptor Pool, Set and Layout +// ================================================== + +PalResult PAL_CALL createVkDescriptorSetLayout( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout) +{ + VkResult result; + Device* vkDevice = (Device*)device; + VkDescriptorSetLayoutBinding* bindings = nullptr; + DescriptorSetLayout* layout = nullptr; + + layout = palAllocate(s_Vk.allocator, sizeof(DescriptorSetLayout), 0); + bindings = palAllocate( + s_Vk.allocator, + sizeof(VkDescriptorSetLayoutBinding) * info->bindingCount, + 0); + + if (!layout || !bindings) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkDescriptorSetLayoutCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + createInfo.bindingCount = info->bindingCount; + createInfo.pBindings = bindings; + + for (int i = 0; i < info->bindingCount; i++) { + VkDescriptorSetLayoutBinding* binding = &bindings[i]; + binding->binding = info->bindings[i].binding; + binding->descriptorCount = info->bindings[i].descriptorCount; + binding->descriptorType = descriptortypeToVk(info->bindings[i].descriptorType); + + binding->pImmutableSamplers = nullptr; + binding->stageFlags = 0; + for (int j = 0; j < info->bindings[i].shaderStageCount; j++) { + VkShaderStageFlagBits bit = shaderStageToVK(info->bindings[i].shaderStages[j]); + binding->stageFlags |= bit; + } + } + + result = s_Vk.createDescriptorSetLayout( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &layout->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, layout); + palFree(s_Vk.allocator, bindings); + return vkResultToPal(result); + } + + layout->device = vkDevice; + palFree(s_Vk.allocator, bindings); + *outLayout = (PalDescriptorSetLayout*)layout; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkDescriptorSetLayout(PalDescriptorSetLayout* layout) +{ + DescriptorSetLayout* vkLayout = (DescriptorSetLayout*)layout; + s_Vk.destroyDescriptorSetLayout(vkLayout->device->handle, vkLayout->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, layout); +} + +PalResult PAL_CALL createVkDescriptorPool( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool) +{ + VkResult result; + Device* vkDevice = (Device*)device; + DescriptorPool* pool = nullptr; + VkDescriptorPoolSize* poolSizes = nullptr; + + pool = palAllocate(s_Vk.allocator, sizeof(DescriptorPool), 0); + poolSizes = palAllocate( + s_Vk.allocator, + sizeof(VkDescriptorPoolSize) * info->maxDescriptorBindingSizes, + 0); + + if (!pool || !poolSizes) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + for (int i = 0; i < info->maxDescriptorBindingSizes; i++) { + VkDescriptorPoolSize* poolSize = &poolSizes[i]; + + poolSize->descriptorCount = info->bindingSizes[i].bindingCount; + poolSize->type = descriptortypeToVk(info->bindingSizes[i].descriptorType); + } + + VkDescriptorPoolCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + createInfo.maxSets = info->maxDescriptorSets; + createInfo.poolSizeCount = info->maxDescriptorBindingSizes; + createInfo.pPoolSizes = poolSizes; + + result = s_Vk.createDescriptorPool( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &pool->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pool); + palFree(s_Vk.allocator, poolSizes); + return vkResultToPal(result); + } + + pool->device = vkDevice; + palFree(s_Vk.allocator, poolSizes); + *outPool = (PalDescriptorPool*)pool; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyVkDescriptorPool(PalDescriptorPool* pool) +{ + DescriptorPool* vkPool = (DescriptorPool*)pool; + s_Vk.destroyDescriptorPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, pool); +} + // ================================================== // Pipeline // ================================================== @@ -6712,8 +6917,8 @@ PalResult PAL_CALL createVkGraphicsPipeline( createInfo.pDepthStencilState = &depthStencilState; // Color blend state - if (info->blendAttachmentCount) { - Uint32 count = info->blendAttachmentCount; + if (info->colorBlendAttachmentCount) { + Uint32 count = info->colorBlendAttachmentCount; blendattachments = palAllocate(s_Vk.allocator, sizeof(VkPipelineColorBlendAttachmentState) * count, 0); @@ -6726,7 +6931,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( for (int i = 0; i < count; i++) { VkPipelineColorBlendAttachmentState* tmp = &blendattachments[i]; - PalBlendAttachment* desc = &info->blendAttachments[i]; + PalColorBlendAttachment* desc = &info->colorBlendAttachments[i]; tmp->blendEnable = desc->enableBlend; tmp->alphaBlendOp = blendOpToVk(desc->alphaBlendOp); diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index 1c250bbf..a4e015ea 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -4473,8 +4473,8 @@ static PalResult xEnumerateMonitorModes( mode->height = info->height; mode->bpp = s_X11.bpp; - double tmp = (double)info->hTotal * (double)info->vTotal double rate = - (double)info->dotClock / tmp; + double tmp = (double)info->hTotal * (double)info->vTotal; + double rate = (double)info->dotClock / tmp; mode->refreshRate = rate + 0.5; } } diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 2b3188dc..bdadaf22 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -257,7 +257,7 @@ bool clearColorTest() return false; } - // create synchronization objects + // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { @@ -273,7 +273,7 @@ bool clearColorTest() return false; } - result = palCreateCommandBuffer( + result = palAllocateCommandBuffer( device, cmdPool, PAL_COMMAND_BUFFER_TYPE_PRIMARY, @@ -505,7 +505,7 @@ bool clearColorTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { palDestroySemaphore(presentCompleteSemaphores[i]); palDestroyFence(inFlightFences[i]); - palDestroyCommandBuffer(cmdBuffers[i]); + palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 48b19560..f16b368d 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -306,7 +306,7 @@ bool meshTest() return false; } - // create synchronization objects + // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { @@ -322,7 +322,7 @@ bool meshTest() return false; } - result = palCreateCommandBuffer( + result = palAllocateCommandBuffer( device, cmdPool, PAL_COMMAND_BUFFER_TYPE_PRIMARY, @@ -445,14 +445,14 @@ bool meshTest() PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; // color blend attachment - PalBlendAttachment blendAttachment = {0}; + PalColorBlendAttachment blendAttachment = {0}; blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; - pipelineCreateInfo.blendAttachments = &blendAttachment; - pipelineCreateInfo.blendAttachmentCount = 1; + pipelineCreateInfo.colorBlendAttachments = &blendAttachment; + pipelineCreateInfo.colorBlendAttachmentCount = 1; // multisample state PalMultisampleState multisampleState = {0}; @@ -737,7 +737,7 @@ bool meshTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { palDestroySemaphore(presentCompleteSemaphores[i]); palDestroyFence(inFlightFences[i]); - palDestroyCommandBuffer(cmdBuffers[i]); + palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { diff --git a/tests/tests.h b/tests/tests.h index 40aacdff..d92b1937 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -52,7 +52,6 @@ bool multiThreadOpenGlTest(); // graphics bool graphicsTest(); -bool meshTest(); // graphics and video bool clearColorTest(); diff --git a/tests/tests_main.c b/tests/tests_main.c index bf6e1b15..d1d19108 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,13 +57,13 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest); + // registerTest(graphicsTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest); - // registerTest(triangleTest); - registerTest(meshTest); + registerTest(triangleTest); + // registerTest(meshTest); #endif // runTests(); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index db2d7fdd..a1c5a370 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -300,7 +300,7 @@ bool triangleTest() return false; } - // create synchronization objects + // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { @@ -316,7 +316,7 @@ bool triangleTest() return false; } - result = palCreateCommandBuffer( + result = palAllocateCommandBuffer( device, cmdPool, PAL_COMMAND_BUFFER_TYPE_PRIMARY, @@ -622,14 +622,14 @@ bool triangleTest() pipelineCreateInfo.vertexLayouts = &vertexLayout; // color blend attachment - PalBlendAttachment blendAttachment = {0}; + PalColorBlendAttachment blendAttachment = {0}; blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; - pipelineCreateInfo.blendAttachments = &blendAttachment; - pipelineCreateInfo.blendAttachmentCount = 1; + pipelineCreateInfo.colorBlendAttachments = &blendAttachment; + pipelineCreateInfo.colorBlendAttachmentCount = 1; // multisample state PalMultisampleState multisampleState = {0}; @@ -936,7 +936,7 @@ bool triangleTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { palDestroySemaphore(presentCompleteSemaphores[i]); palDestroyFence(inFlightFences[i]); - palDestroyCommandBuffer(cmdBuffers[i]); + palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { From c7044f98c9dd95e0c16af88214e9c2980007e653 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 10 Jan 2026 12:58:54 +0000 Subject: [PATCH 083/372] add descriptor set, more shader stage enums and more descriptor types --- include/pal/pal_graphics.h | 30 +++++++- src/graphics/pal_graphics.c | 46 ++++++++++++ src/graphics/pal_vulkan.c | 143 ++++++++++++++++++++++++++---------- 3 files changed, 179 insertions(+), 40 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index e9ddde78..041a9428 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -56,7 +56,6 @@ typedef struct PalCommandBuffer PalCommandBuffer; typedef struct PalDescriptorSetLayout PalDescriptorSetLayout; typedef struct PalDescriptorPool PalDescriptorPool; - typedef struct PalDescriptorSet PalDescriptorSet; typedef struct PalPipelineLayout PalPipelineLayout; @@ -315,7 +314,13 @@ typedef enum { PAL_SHADER_STAGE_MESH, PAL_SHADER_STAGE_TASK, PAL_SHADER_STAGE_TESSELLATION_CONTROL, - PAL_SHADER_STAGE_TESSELLATION_EVALUATION + PAL_SHADER_STAGE_TESSELLATION_EVALUATION, + PAL_SHADER_STAGE_RAYGEN, + PAL_SHADER_STAGE_CLOSEST_HIT, + PAL_SHADER_STAGE_ANY_HIT, + PAL_SHADER_STAGE_MISS, + PAL_SHADER_STAGE_INTERSECTION, + PAL_SHADER_STAGE_CALLABLE } PalShaderStage; typedef enum { @@ -546,7 +551,10 @@ typedef enum { typedef enum { PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER, - PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER + PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE, + PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE, + PAL_DESCRIPTOR_TYPE_SAMPLER } PalDescriptorType; typedef struct { @@ -1381,6 +1389,14 @@ typedef struct { void PAL_CALL (*destroyDescriptorPool)(PalDescriptorPool* pool); + PalResult PAL_CALL (*allocateDescriptorSet)( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + + void PAL_CALL (*freeDescriptorSet)(PalDescriptorSet* set); + PalResult PAL_CALL (*createPipelineLayout)( PalDevice* device, const PalPipelineLayoutCreateInfo* info, @@ -1806,6 +1822,14 @@ PAL_API PalResult PAL_CALL palCreateDescriptorPool( PAL_API void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool); +PAL_API PalResult PAL_CALL palAllocateDescriptorSet( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + +PAL_API void PAL_CALL palFreeDescriptorSet(PalDescriptorSet* set); + PAL_API PalResult PAL_CALL palCreatePipelineLayout( PalDevice* device, const PalPipelineLayoutCreateInfo* info, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 3daccbf0..27461bef 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -55,6 +55,7 @@ PAL_HANDLE(PalAccelerationStructure) PAL_HANDLE(PalPipelineLayout) PAL_HANDLE(PalDescriptorSetLayout) PAL_HANDLE(PalDescriptorPool) +PAL_HANDLE(PalDescriptorSet) typedef struct { Int32 count; @@ -503,6 +504,14 @@ PalResult PAL_CALL createVkDescriptorPool( void PAL_CALL destroyVkDescriptorPool(PalDescriptorPool* pool); +PalResult PAL_CALL allocateVkDescriptorSet( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + +void PAL_CALL freeVkDescriptorSet(PalDescriptorSet* set); + PalResult PAL_CALL createVkPipelineLayout( PalDevice* device, const PalPipelineLayoutCreateInfo* info, @@ -611,6 +620,8 @@ static PalGraphicsBackend s_VkBackend = { .destroyDescriptorSetLayout = destroyVkDescriptorSetLayout, .createDescriptorPool = createVkDescriptorPool, .destroyDescriptorPool = destroyVkDescriptorPool, + .allocateDescriptorSet = allocateVkDescriptorSet, + .freeDescriptorSet = freeVkDescriptorSet, .createPipelineLayout = createVkPipelineLayout, .destroyPipelineLayout = destroyVkPipelineLayout, .createGraphicsPipeline = createVkGraphicsPipeline, @@ -743,6 +754,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroyDescriptorSetLayout || !backend->createDescriptorPool || !backend->destroyDescriptorPool || + !backend->allocateDescriptorSet || + !backend->freeDescriptorSet || !backend->createPipelineLayout || !backend->destroyPipelineLayout || !backend->createGraphicsPipeline || @@ -2383,6 +2396,39 @@ void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool) } } +PalResult PAL_CALL palAllocateDescriptorSet( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !pool || !layout || !outSet) { + return PAL_RESULT_NULL_POINTER; + } + + PalResult result; + PalDescriptorSet* set = nullptr; + result = device->backend->allocateDescriptorSet(device, pool, layout, &set); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + set->backend = device->backend; + *outSet = set; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palFreeDescriptorSet(PalDescriptorSet* set) +{ + if (s_Graphics.initialized && set) { + set->backend->freeDescriptorSet(set); + } +} + // ================================================== // Pipeline // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e013fb3d..5df61cf1 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -171,6 +171,8 @@ typedef struct { PFN_vkDestroyDescriptorSetLayout destroyDescriptorSetLayout; PFN_vkCreateDescriptorPool createDescriptorPool; PFN_vkDestroyDescriptorPool destroyDescriptorPool; + PFN_vkAllocateDescriptorSets allocateDescriptorSet; + PFN_vkFreeDescriptorSets freeDescriptorSet; PFN_vkCreatePipelineLayout createPipelineLayout; PFN_vkDestroyPipelineLayout destroyPipelineLayout; @@ -359,6 +361,14 @@ typedef struct { VkDescriptorPool handle; } DescriptorPool; +typedef struct { + const PalGraphicsBackend* backend; + + Device* device; + DescriptorPool* pool; + VkDescriptorSet handle; +} DescriptorSet; + typedef struct { const PalGraphicsBackend* backend; @@ -1681,6 +1691,15 @@ static VkDescriptorType descriptortypeToVk(PalDescriptorType type) case PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + + case PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + + case PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE: + return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + + case PAL_DESCRIPTOR_TYPE_SAMPLER: + return VK_DESCRIPTOR_TYPE_SAMPLER; } return 0; @@ -1712,6 +1731,25 @@ static VkShaderStageFlagBits shaderStageToVK(PalShaderStage stage) case PAL_SHADER_STAGE_TESSELLATION_EVALUATION: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + + case PAL_SHADER_STAGE_RAYGEN: + return VK_SHADER_STAGE_RAYGEN_BIT_KHR; + + case PAL_SHADER_STAGE_CLOSEST_HIT: + return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + + case PAL_SHADER_STAGE_ANY_HIT: + return VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + + case PAL_SHADER_STAGE_MISS: + return VK_SHADER_STAGE_MISS_BIT_KHR; + + case PAL_SHADER_STAGE_INTERSECTION: + return VK_SHADER_STAGE_INTERSECTION_BIT_KHR; + + case PAL_SHADER_STAGE_CALLABLE: + return VK_SHADER_STAGE_CALLABLE_BIT_KHR; + } return 0; @@ -2116,6 +2154,14 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroyDescriptorPool"); + s_Vk.allocateDescriptorSet = (PFN_vkAllocateDescriptorSets)dlsym( + s_Vk.handle, + "vkAllocateDescriptorSets"); + + s_Vk.freeDescriptorSet = (PFN_vkFreeDescriptorSets)dlsym( + s_Vk.handle, + "vkFreeDescriptorSets"); + s_Vk.createPipelineLayout = (PFN_vkCreatePipelineLayout)dlsym( s_Vk.handle, "vkCreatePipelineLayout"); @@ -4714,43 +4760,24 @@ PalResult PAL_CALL createVkShader( Uint32 patchControlPoints = 0; Device* vkDevice = (Device*)device; - if (info->stage == PAL_SHADER_STAGE_VERTEX) { - stage = VK_SHADER_STAGE_VERTEX_BIT; - - } else if (info->stage == PAL_SHADER_STAGE_FRAGMENT) { - stage = VK_SHADER_STAGE_FRAGMENT_BIT; - - } else if (info->stage == PAL_SHADER_STAGE_COMPUTE) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - stage = VK_SHADER_STAGE_COMPUTE_BIT; - - } else if (info->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - patchControlPoints = info->patchControlPoints; - - } else if (info->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - - } else if (info->stage == PAL_SHADER_STAGE_MESH) { + stage = shaderStageToVK(info->stage); + if (info->stage == PAL_SHADER_STAGE_MESH || info->stage == PAL_SHADER_STAGE_TASK) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - stage = VK_SHADER_STAGE_MESH_BIT_EXT; - } else if (info->stage == PAL_SHADER_STAGE_TASK) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + // clang-format off + } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || + info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || + info->stage == PAL_SHADER_STAGE_ANY_HIT || + info->stage == PAL_SHADER_STAGE_MISS || + info->stage == PAL_SHADER_STAGE_INTERSECTION || + info->stage == PAL_SHADER_STAGE_CALLABLE) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - stage = VK_SHADER_STAGE_TASK_BIT_EXT; } + // clang-format on shader = palAllocate(s_Vk.allocator, sizeof(Shader), 0); if (!shader) { @@ -5076,19 +5103,19 @@ PalResult PAL_CALL allocateVkCommandBuffer( PAL_RESULT_OUT_OF_MEMORY; } - VkCommandBufferAllocateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - createInfo.commandBufferCount = 1; - createInfo.commandPool = vkPool->handle; + VkCommandBufferAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.commandBufferCount = 1; + allocateInfo.commandPool = vkPool->handle; - createInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; cmdBuffer->primary = true; if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { - createInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; cmdBuffer->primary = false; } - result = s_Vk.allocateCommandBuffer(vkDevice->handle, &createInfo, &cmdBuffer->handle); + result = s_Vk.allocateCommandBuffer(vkDevice->handle, &allocateInfo, &cmdBuffer->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, cmdBuffer); @@ -6560,6 +6587,48 @@ void PAL_CALL destroyVkDescriptorPool(PalDescriptorPool* pool) palFree(s_Vk.allocator, pool); } +PalResult PAL_CALL allocateVkDescriptorSet( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet) +{ + VkResult result; + Device* vkDevice = (Device*)device; + DescriptorPool* vkPool = (DescriptorPool*)pool; + DescriptorSetLayout* vkLayout = (DescriptorSetLayout*)layout; + DescriptorSet* set = nullptr; + + set = palAllocate(s_Vk.allocator, sizeof(DescriptorSet), 0); + if (!set) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkDescriptorSetAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocateInfo.descriptorPool = vkPool->handle; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &vkLayout->handle; + + result = s_Vk.allocateDescriptorSet(vkDevice->handle, &allocateInfo, &set->handle); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, set); + return vkResultToPal(result); + } + + set->pool = vkPool; + set->device = vkDevice; + *outSet = (PalDescriptorSet*)set; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL freeVkDescriptorSet(PalDescriptorSet* set) +{ + DescriptorSet* vkSet = (DescriptorSet*)set; + s_Vk.freeDescriptorSet(vkSet->device->handle, vkSet->pool->handle, 1, &vkSet->handle); + palFree(s_Vk.allocator, set); +} + // ================================================== // Pipeline // ================================================== From 8105ffc6ce9eeb8ed8dca360e230ad0c79c20bae Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 10 Jan 2026 14:57:52 +0000 Subject: [PATCH 084/372] finish descriptor set API --- CHANGELOG.md | 1 + include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 52 ++++++++++++- src/graphics/pal_graphics.c | 69 +++++++++++++++-- src/graphics/pal_vulkan.c | 144 +++++++++++++++++++++++++++++++----- src/pal_core.c | 3 + 6 files changed, 246 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24748565..88abe702 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -149,6 +149,7 @@ palJoinThread(thread, &retval); - **Core:** Added **PAL_RESULT_INVALID_BUFFER** to `PalResult` enum. - **Core:** Added **PAL_RESULT_INVALID_ACCELERATION_STRUCTURE** to `PalResult` enum. - **Core:** Added **PAL_RESULT_MEMORY_MAP_FAILED** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_DEVICE_LOST** to `PalResult` enum. - **Graphics:** Added **Graphics System To PAL**. diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 9f36e38e..0aa8edff 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -269,7 +269,8 @@ typedef enum { PAL_RESULT_INVALID_RENDER_PASS, PAL_RESULT_INVALID_BUFFER, PAL_RESULT_INVALID_ACCELERATION_STRUCTURE, - PAL_RESULT_MEMORY_MAP_FAILED + PAL_RESULT_MEMORY_MAP_FAILED, + PAL_RESULT_DEVICE_LOST } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 041a9428..7c0b1821 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -57,8 +57,9 @@ typedef struct PalCommandBuffer PalCommandBuffer; typedef struct PalDescriptorSetLayout PalDescriptorSetLayout; typedef struct PalDescriptorPool PalDescriptorPool; typedef struct PalDescriptorSet PalDescriptorSet; -typedef struct PalPipelineLayout PalPipelineLayout; +typedef struct PalSampler PalSampler; +typedef struct PalPipelineLayout PalPipelineLayout; typedef struct PalPipeline PalPipeline; typedef struct PalAccelerationStructure PalAccelerationStructure; @@ -905,6 +906,27 @@ typedef struct { PalDescriptorType descriptorType; } PalDescriptorPoolBindingSize; +typedef struct { + Uint32 size; + Uint64 offset; + PalBuffer* buffer; +} PalDescriptorBufferInfo; + +typedef struct { + PalSampler* sampler; + PalImageView* imageView; +} PalDescriptorImageViewInfo; + +typedef struct { + Uint32 binding; + Uint32 arrayElement; + Uint32 descriptorCount; + PalDescriptorType descriptorType; + PalDescriptorSet* descriptorSet; + PalDescriptorBufferInfo* bufferInfo; + PalDescriptorImageViewInfo* imageViewInfo; +} PalDescriptorSetWriteInfo; + typedef struct { Uint32 width; Uint32 height; @@ -1343,6 +1365,13 @@ typedef struct { PalBuffer* buffer, Uint64 offset); + PalResult PAL_CALL (*bindDescriptorSet)( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline, + PalPipelineLayout* layout, + Uint32 setIndex, + PalDescriptorSet* set); + PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -1389,13 +1418,18 @@ typedef struct { void PAL_CALL (*destroyDescriptorPool)(PalDescriptorPool* pool); + PalResult PAL_CALL (*resetDescriptorPool)(PalDescriptorPool* pool); + PalResult PAL_CALL (*allocateDescriptorSet)( PalDevice* device, PalDescriptorPool* pool, PalDescriptorSetLayout* layout, PalDescriptorSet** outSet); - void PAL_CALL (*freeDescriptorSet)(PalDescriptorSet* set); + PalResult PAL_CALL (*updateDescriptorSet)( + PalDevice* device, + Uint32 count, + PalDescriptorSetWriteInfo* infos); PalResult PAL_CALL (*createPipelineLayout)( PalDevice* device, @@ -1776,6 +1810,13 @@ PAL_API PalResult PAL_CALL palDispatchIndirect( PalBuffer* buffer, Uint64 offset); +PAL_API PalResult PAL_CALL palBindDescriptorSet( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline, + PalPipelineLayout* layout, + Uint32 setIndex, + PalDescriptorSet* set); + PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -1822,13 +1863,18 @@ PAL_API PalResult PAL_CALL palCreateDescriptorPool( PAL_API void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool); +PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); + PAL_API PalResult PAL_CALL palAllocateDescriptorSet( PalDevice* device, PalDescriptorPool* pool, PalDescriptorSetLayout* layout, PalDescriptorSet** outSet); -PAL_API void PAL_CALL palFreeDescriptorSet(PalDescriptorSet* set); +PAL_API PalResult PAL_CALL palUpdateDescriptorSet( + PalDevice* device, + Uint32 count, + PalDescriptorSetWriteInfo* infos); PAL_API PalResult PAL_CALL palCreatePipelineLayout( PalDevice* device, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 27461bef..e98f6c56 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -56,6 +56,7 @@ PAL_HANDLE(PalPipelineLayout) PAL_HANDLE(PalDescriptorSetLayout) PAL_HANDLE(PalDescriptorPool) PAL_HANDLE(PalDescriptorSet) +PAL_HANDLE(PalSampler) typedef struct { Int32 count; @@ -447,6 +448,13 @@ PalResult PAL_CALL dispatchIndirectVk( PalBuffer* buffer, Uint64 offset); +PalResult PAL_CALL bindVkDescriptorSet( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline, + PalPipelineLayout* layout, + Uint32 setIndex, + PalDescriptorSet* set); + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -504,6 +512,8 @@ PalResult PAL_CALL createVkDescriptorPool( void PAL_CALL destroyVkDescriptorPool(PalDescriptorPool* pool); +PalResult PAL_CALL resetVkDescriptorPool(PalDescriptorPool* pool); + PalResult PAL_CALL allocateVkDescriptorSet( PalDevice* device, PalDescriptorPool* pool, @@ -512,6 +522,11 @@ PalResult PAL_CALL allocateVkDescriptorSet( void PAL_CALL freeVkDescriptorSet(PalDescriptorSet* set); +PalResult PAL_CALL updateVkDescriptorSet( + PalDevice* device, + Uint32 count, + PalDescriptorSetWriteInfo* infos); + PalResult PAL_CALL createVkPipelineLayout( PalDevice* device, const PalPipelineLayoutCreateInfo* info, @@ -608,6 +623,7 @@ static PalGraphicsBackend s_VkBackend = { .dispatch = dispatchVk, .dispatchBase = dispatchBaseVk, .dispatchIndirect = dispatchIndirectVk, + .bindDescriptorSet = bindVkDescriptorSet, .submitCommandBuffer = submitVkCommandBuffer, .createAccelerationstructure = createVkAccelerationstructure, .destroyAccelerationstructure = destroyVkAccelerationstructure, @@ -620,8 +636,9 @@ static PalGraphicsBackend s_VkBackend = { .destroyDescriptorSetLayout = destroyVkDescriptorSetLayout, .createDescriptorPool = createVkDescriptorPool, .destroyDescriptorPool = destroyVkDescriptorPool, + .resetDescriptorPool = resetVkDescriptorPool, .allocateDescriptorSet = allocateVkDescriptorSet, - .freeDescriptorSet = freeVkDescriptorSet, + .updateDescriptorSet = updateVkDescriptorSet, .createPipelineLayout = createVkPipelineLayout, .destroyPipelineLayout = destroyVkPipelineLayout, .createGraphicsPipeline = createVkGraphicsPipeline, @@ -740,6 +757,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->dispatch || !backend->dispatchBase || !backend->dispatchIndirect || + !backend->bindDescriptorSet || !backend->submitCommandBuffer || !backend->createAccelerationstructure || !backend->destroyAccelerationstructure || @@ -754,8 +772,9 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroyDescriptorSetLayout || !backend->createDescriptorPool || !backend->destroyDescriptorPool || + !backend->resetDescriptorPool || !backend->allocateDescriptorSet || - !backend->freeDescriptorSet || + !backend->updateDescriptorSet || !backend->createPipelineLayout || !backend->destroyPipelineLayout || !backend->createGraphicsPipeline || @@ -2156,6 +2175,24 @@ PalResult PAL_CALL palDispatchIndirect( return cmdBuffer->backend->dispatchIndirect(cmdBuffer, buffer, offset); } +PalResult PAL_CALL palBindDescriptorSet( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline, + PalPipelineLayout* layout, + Uint32 setIndex, + PalDescriptorSet* set) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !pipeline || !layout || !set) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->bindDescriptorSet(cmdBuffer, pipeline, layout, setIndex, set); +} + PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) @@ -2396,6 +2433,19 @@ void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool) } } +PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!pool) { + return PAL_RESULT_NULL_POINTER; + } + + return pool->backend->resetDescriptorPool(pool); +} + PalResult PAL_CALL palAllocateDescriptorSet( PalDevice* device, PalDescriptorPool* pool, @@ -2422,11 +2472,20 @@ PalResult PAL_CALL palAllocateDescriptorSet( return PAL_RESULT_SUCCESS; } -void PAL_CALL palFreeDescriptorSet(PalDescriptorSet* set) +PalResult PAL_CALL palUpdateDescriptorSet( + PalDevice* device, + Uint32 count, + PalDescriptorSetWriteInfo* infos) { - if (s_Graphics.initialized && set) { - set->backend->freeDescriptorSet(set); + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } + + if (!device || !infos) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->updateDescriptorSet(device, count, infos); } // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 5df61cf1..8013ed85 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -149,6 +149,7 @@ typedef struct { PFN_vkCmdDrawIndexedIndirect cmdDrawIndexedIndirect; PFN_vkCmdDispatch cmdDispatch; PFN_vkCmdDispatchIndirect cmdDispatchIndirect; + PFN_vkCmdBindDescriptorSets bindDescriptorSets; PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; @@ -171,8 +172,10 @@ typedef struct { PFN_vkDestroyDescriptorSetLayout destroyDescriptorSetLayout; PFN_vkCreateDescriptorPool createDescriptorPool; PFN_vkDestroyDescriptorPool destroyDescriptorPool; + PFN_vkResetDescriptorPool resetDescriptorPool; PFN_vkAllocateDescriptorSets allocateDescriptorSet; PFN_vkFreeDescriptorSets freeDescriptorSet; + PFN_vkUpdateDescriptorSets updateDescriptorSet; PFN_vkCreatePipelineLayout createPipelineLayout; PFN_vkDestroyPipelineLayout destroyPipelineLayout; @@ -369,6 +372,13 @@ typedef struct { VkDescriptorSet handle; } DescriptorSet; +typedef struct { + const PalGraphicsBackend* backend; + + Device* device; + VkSampler handle; +} Sampler; + typedef struct { const PalGraphicsBackend* backend; @@ -379,7 +389,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 type; + VkPipelineBindPoint bindPoint; Device* device; VkPipeline handle; } Pipeline; @@ -464,9 +474,7 @@ static PalResult vkResultToPal(VkResult result) } case VK_ERROR_INITIALIZATION_FAILED: - case VK_ERROR_DEVICE_LOST: { return PAL_RESULT_PLATFORM_FAILURE; - } case VK_ERROR_INCOMPATIBLE_DRIVER: return PAL_RESULT_INVALID_DRIVER; @@ -482,6 +490,9 @@ static PalResult vkResultToPal(VkResult result) case VK_ERROR_MEMORY_MAP_FAILED: return PAL_RESULT_MEMORY_MAP_FAILED; + case VK_ERROR_DEVICE_LOST: + return PAL_RESULT_DEVICE_LOST; + default: return PAL_RESULT_PLATFORM_FAILURE; } @@ -2114,6 +2125,10 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCmdDispatchIndirect"); + s_Vk.bindDescriptorSets = (PFN_vkCmdBindDescriptorSets)dlsym( + s_Vk.handle, + "vkCmdBindDescriptorSets"); + s_Vk.createBuffer = (PFN_vkCreateBuffer)dlsym( s_Vk.handle, "vkCreateBuffer"); @@ -2154,6 +2169,10 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroyDescriptorPool"); + s_Vk.resetDescriptorPool = (PFN_vkResetDescriptorPool)dlsym( + s_Vk.handle, + "vkResetDescriptorPool"); + s_Vk.allocateDescriptorSet = (PFN_vkAllocateDescriptorSets)dlsym( s_Vk.handle, "vkAllocateDescriptorSets"); @@ -2162,6 +2181,10 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkFreeDescriptorSets"); + s_Vk.updateDescriptorSet = (PFN_vkUpdateDescriptorSets)dlsym( + s_Vk.handle, + "vkUpdateDescriptorSets"); + s_Vk.createPipelineLayout = (PFN_vkCreatePipelineLayout)dlsym( s_Vk.handle, "vkCreatePipelineLayout"); @@ -5687,15 +5710,7 @@ PalResult PAL_CALL bindVkPipeline( { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* vkPipeline = (Pipeline*)pipeline; - VkPipelineBindPoint bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - if (vkPipeline->type == COMPUTE_PIPELINE) { - bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; - - } else if (vkPipeline->type == RAY_TRACING_PIPELINE) { - bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; - } - - s_Vk.cmdBindPipeline(vkCmdBuffer->handle, bindPoint, vkPipeline->handle); + s_Vk.cmdBindPipeline(vkCmdBuffer->handle, vkPipeline->bindPoint, vkPipeline->handle); return PAL_RESULT_SUCCESS; } @@ -6065,6 +6080,31 @@ PalResult PAL_CALL dispatchIndirectVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL bindVkDescriptorSet( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline, + PalPipelineLayout* layout, + Uint32 setIndex, + PalDescriptorSet* set) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Pipeline* vkPipeline = (Pipeline*)pipeline; + PipelineLayout* vkLayout = (PipelineLayout*)layout; + DescriptorSet* vkSet = (DescriptorSet*)set; + + s_Vk.bindDescriptorSets( + vkCmdBuffer->handle, + vkPipeline->bindPoint, + vkLayout->handle, + setIndex, + 1, + &vkSet->handle, + 0, + nullptr); + + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) @@ -6622,11 +6662,81 @@ PalResult PAL_CALL allocateVkDescriptorSet( return PAL_RESULT_SUCCESS; } -void PAL_CALL freeVkDescriptorSet(PalDescriptorSet* set) +PalResult PAL_CALL resetVkDescriptorPool(PalDescriptorPool* pool) { - DescriptorSet* vkSet = (DescriptorSet*)set; - s_Vk.freeDescriptorSet(vkSet->device->handle, vkSet->pool->handle, 1, &vkSet->handle); - palFree(s_Vk.allocator, set); + DescriptorPool* vkPool = (DescriptorPool*)pool; + s_Vk.resetDescriptorPool(vkPool->device->handle, vkPool->handle, 0); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL updateVkDescriptorSet( + PalDevice* device, + Uint32 count, + PalDescriptorSetWriteInfo* infos) +{ + VkResult result; + Device* vkDevice = (Device*)device; + VkWriteDescriptorSet* writes = nullptr; + VkDescriptorBufferInfo* bufferInfos = nullptr; + VkDescriptorImageInfo* imageInfos = nullptr; + + writes = palAllocate(s_Vk.allocator, sizeof(VkWriteDescriptorSet) * count, 0); + + // FIXME: loop through to find the buffers from the images + bufferInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBufferInfo) * count, 0); + imageInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorImageInfo) * count, 0); + if (!writes || !bufferInfos || !imageInfos) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + Uint32 bufferIndex = 0; + Uint32 imageIndex = 0; + for (int i = 0; i < count; i++) { + VkWriteDescriptorSet* write = &writes[i]; + write->dstArrayElement = infos[i].arrayElement; + write->dstBinding = infos[i].binding; + write->descriptorCount = infos[i].descriptorCount; + write->descriptorType = descriptortypeToVk(infos[i].descriptorType); + + DescriptorSet* set = (DescriptorSet*)infos[i].descriptorSet; + write->dstSet = set->handle; + + if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || + infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + VkDescriptorBufferInfo* bufferInfo = &bufferInfos[bufferIndex++]; + Buffer* vkBuffer = (Buffer*)infos[i].bufferInfo->buffer; + bufferInfo->buffer = vkBuffer->handle; + bufferInfo->offset = infos[i].bufferInfo->offset; + bufferInfo->range = infos[i].bufferInfo->size; + + } else { + VkDescriptorImageInfo* imageInfo = &imageInfos[imageIndex++]; + ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; + Sampler* vkSampler = (Sampler*)infos[i].imageViewInfo->sampler; + + if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { + imageInfo->sampler = vkSampler->handle; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo->imageView = nullptr; + + } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { + imageInfo->sampler = vkSampler->handle; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageInfo->imageView = vkImageView->handle; + + } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + imageInfo->sampler = vkSampler->handle; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo->imageView = vkImageView->handle; + } + } + } + s_Vk.updateDescriptorSet(vkDevice->handle, count, writes, 0, nullptr); + + palFree(s_Vk.allocator, writes); + palFree(s_Vk.allocator, bufferInfos); + palFree(s_Vk.allocator, imageInfos); + return PAL_RESULT_SUCCESS; } // ================================================== @@ -7103,7 +7213,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( palFree(s_Vk.allocator, blendattachments); pipeline->device = vkDevice; - pipeline->type = GRAPHICS_PIPELINE; + pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } diff --git a/src/pal_core.c b/src/pal_core.c index 6c072b0e..9981ace5 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -445,6 +445,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_MEMORY_MAP_FAILED: return "Memory map failed"; + + case PAL_RESULT_DEVICE_LOST: + return "Device lost"; } return "Unknown"; } From 9a1929390caa164c9473ef25cca2838e25027fc9 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 12 Jan 2026 10:52:05 +0000 Subject: [PATCH 085/372] add push constants API --- include/pal/pal_graphics.h | 30 +++++++++++- src/graphics/pal_graphics.c | 38 +++++++++++++++ src/graphics/pal_vulkan.c | 92 +++++++++++++++++++++++++++++++++---- 3 files changed, 149 insertions(+), 11 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 7c0b1821..9b6ddff3 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -927,6 +927,13 @@ typedef struct { PalDescriptorImageViewInfo* imageViewInfo; } PalDescriptorSetWriteInfo; +typedef struct { + Uint64 offset; + Uint64 size; + Uint32 shaderStageCount; + PalShaderStage* shaderStages; +} PalPushConstantRange; + typedef struct { Uint32 width; Uint32 height; @@ -989,7 +996,10 @@ typedef struct { } PalDescriptorPoolCreateInfo; typedef struct { - bool unused; + Uint32 descriptorSetLayoutCount; + Uint32 pushConstantRangeCount; + PalDescriptorSetLayout** descriptorSetLayouts; + PalPushConstantRange* pushConstantRanges; } PalPipelineLayoutCreateInfo; typedef struct { @@ -1372,6 +1382,15 @@ typedef struct { Uint32 setIndex, PalDescriptorSet* set); + PalResult PAL_CALL (*pushConstants)( + PalCommandBuffer* cmdBuffer, + PalPipelineLayout* layout, + Uint32 shaderStageCount, + PalShaderStage* shaderStages, + Uint32 offset, + Uint32 size, + const void* value); + PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -1817,6 +1836,15 @@ PAL_API PalResult PAL_CALL palBindDescriptorSet( Uint32 setIndex, PalDescriptorSet* set); +PAL_API PalResult PAL_CALL palPushConstants( + PalCommandBuffer* cmdBuffer, + PalPipelineLayout* layout, + Uint32 shaderStageCount, + PalShaderStage* shaderStages, + Uint32 offset, + Uint32 size, + const void* value); + PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index e98f6c56..c14cef19 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -455,6 +455,15 @@ PalResult PAL_CALL bindVkDescriptorSet( Uint32 setIndex, PalDescriptorSet* set); +PalResult PAL_CALL pushConstantsVk( + PalCommandBuffer* cmdBuffer, + PalPipelineLayout* layout, + Uint32 shaderStageCount, + PalShaderStage* shaderStages, + Uint32 offset, + Uint32 size, + const void* value); + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -624,6 +633,7 @@ static PalGraphicsBackend s_VkBackend = { .dispatchBase = dispatchBaseVk, .dispatchIndirect = dispatchIndirectVk, .bindDescriptorSet = bindVkDescriptorSet, + .pushConstants = pushConstantsVk, .submitCommandBuffer = submitVkCommandBuffer, .createAccelerationstructure = createVkAccelerationstructure, .destroyAccelerationstructure = destroyVkAccelerationstructure, @@ -758,6 +768,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->dispatchBase || !backend->dispatchIndirect || !backend->bindDescriptorSet || + !backend->pushConstants || !backend->submitCommandBuffer || !backend->createAccelerationstructure || !backend->destroyAccelerationstructure || @@ -2193,6 +2204,33 @@ PalResult PAL_CALL palBindDescriptorSet( return cmdBuffer->backend->bindDescriptorSet(cmdBuffer, pipeline, layout, setIndex, set); } +PalResult PAL_CALL palPushConstants( + PalCommandBuffer* cmdBuffer, + PalPipelineLayout* layout, + Uint32 shaderStageCount, + PalShaderStage* shaderStages, + Uint32 offset, + Uint32 size, + const void* value) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !layout || !shaderStages || !value) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->pushConstants( + cmdBuffer, + layout, + shaderStageCount, + shaderStages, + offset, + size, + value); +} + PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 8013ed85..f5853b86 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -141,15 +141,16 @@ typedef struct { PFN_vkCmdBindPipeline cmdBindPipeline; PFN_vkCmdSetViewport cmdSetViewports; PFN_vkCmdSetScissor cmdSetScissors; - PFN_vkCmdBindVertexBuffers bindVertexBuffers; - PFN_vkCmdBindIndexBuffer bindIndexBuffer; + PFN_vkCmdBindVertexBuffers cmdBindVertexBuffers; + PFN_vkCmdBindIndexBuffer cmdBindIndexBuffer; PFN_vkCmdDraw cmdDraw; PFN_vkCmdDrawIndirect cmdDrawIndirect; PFN_vkCmdDrawIndexed cmdDrawIndexed; PFN_vkCmdDrawIndexedIndirect cmdDrawIndexedIndirect; PFN_vkCmdDispatch cmdDispatch; PFN_vkCmdDispatchIndirect cmdDispatchIndirect; - PFN_vkCmdBindDescriptorSets bindDescriptorSets; + PFN_vkCmdBindDescriptorSets cmdBindDescriptorSets; + PFN_vkCmdPushConstants cmdPushConstants; PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; @@ -2093,11 +2094,11 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCmdSetScissor"); - s_Vk.bindVertexBuffers = (PFN_vkCmdBindVertexBuffers)dlsym( + s_Vk.cmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)dlsym( s_Vk.handle, "vkCmdBindVertexBuffers"); - s_Vk.bindIndexBuffer = (PFN_vkCmdBindIndexBuffer)dlsym( + s_Vk.cmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)dlsym( s_Vk.handle, "vkCmdBindIndexBuffer"); @@ -2125,10 +2126,14 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCmdDispatchIndirect"); - s_Vk.bindDescriptorSets = (PFN_vkCmdBindDescriptorSets)dlsym( + s_Vk.cmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)dlsym( s_Vk.handle, "vkCmdBindDescriptorSets"); + s_Vk.cmdPushConstants = (PFN_vkCmdPushConstants)dlsym( + s_Vk.handle, + "vkCmdPushConstants"); + s_Vk.createBuffer = (PFN_vkCreateBuffer)dlsym( s_Vk.handle, "vkCreateBuffer"); @@ -5812,7 +5817,7 @@ PalResult PAL_CALL bindVkVertexBuffers( vkBuffers[i] = tmp->handle; } - s_Vk.bindVertexBuffers(vkCmdBuffer->handle, firstSlot, count, vkBuffers, offsets); + s_Vk.cmdBindVertexBuffers(vkCmdBuffer->handle, firstSlot, count, vkBuffers, offsets); if (count > 1) { palFree(s_Vk.allocator, vkBuffers); @@ -5833,7 +5838,7 @@ PalResult PAL_CALL bindVkIndexBuffer( bufferType = VK_INDEX_TYPE_UINT16; } - s_Vk.bindIndexBuffer(vkCmdBuffer->handle, vkBuffer->handle, offset, bufferType); + s_Vk.cmdBindIndexBuffer(vkCmdBuffer->handle, vkBuffer->handle, offset, bufferType); return PAL_RESULT_SUCCESS; } @@ -6092,7 +6097,7 @@ PalResult PAL_CALL bindVkDescriptorSet( PipelineLayout* vkLayout = (PipelineLayout*)layout; DescriptorSet* vkSet = (DescriptorSet*)set; - s_Vk.bindDescriptorSets( + s_Vk.cmdBindDescriptorSets( vkCmdBuffer->handle, vkPipeline->bindPoint, vkLayout->handle, @@ -6105,6 +6110,33 @@ PalResult PAL_CALL bindVkDescriptorSet( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL pushConstantsVk( + PalCommandBuffer* cmdBuffer, + PalPipelineLayout* layout, + Uint32 shaderStageCount, + PalShaderStage* shaderStages, + Uint64 offset, + Uint64 size, + const void* value) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + PipelineLayout* vkLayout = (PipelineLayout*)layout; + VkShaderStageFlags stages = 0; + + for (int i = 0; i < shaderStageCount; i++) { + VkShaderStageFlagBits bit = shaderStageToVK(shaderStages[i]); + stages |= bit; + } + + s_Vk.cmdPushConstants( + vkCmdBuffer->handle, + vkLayout->handle, + stages, + offset, + size, + value); +} + PalResult PAL_CALL submitVkCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) @@ -6751,14 +6783,48 @@ PalResult PAL_CALL createVkPipelineLayout( VkResult result; Device* vkDevice = (Device*)device; PipelineLayout* layout = nullptr; + VkPushConstantRange* pushConstants = nullptr; + VkDescriptorSetLayout* descriptorLayouts = nullptr; layout = palAllocate(s_Vk.allocator, sizeof(PipelineLayout), 0); - if (!layout) { + pushConstants = palAllocate( + s_Vk.allocator, + sizeof(VkPushConstantRange) * info->pushConstantRangeCount, + 0); + + descriptorLayouts = palAllocate( + s_Vk.allocator, + sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount, + 0); + + if (!layout || !pushConstants || !descriptorLayouts) { return PAL_RESULT_OUT_OF_MEMORY; } + for (int i = 0; i < info->descriptorSetLayoutCount; i++) { + DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; + descriptorLayouts[i] = tmp->handle; + } + + for (int i = 0; i < info->pushConstantRangeCount; i++) { + VkPushConstantRange* range = &pushConstants[i]; + range->offset = info->pushConstantRanges[i].offset; + range->size = info->pushConstantRanges[i].size; + + range->offset = info->pushConstantRanges[i].offset; + for (int j = 0; j < info->pushConstantRanges[i].shaderStageCount; j++) { + VkShaderStageFlagBits bit = + shaderStageToVK(info->pushConstantRanges[i].shaderStages[j]); + range->stageFlags |= bit; + } + } + VkPipelineLayoutCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + createInfo.setLayoutCount = info->descriptorSetLayoutCount; + createInfo.pSetLayouts = descriptorLayouts; + createInfo.pPushConstantRanges = pushConstants; + createInfo.pushConstantRangeCount = info->pushConstantRangeCount; result = s_Vk.createPipelineLayout( vkDevice->handle, @@ -6767,9 +6833,15 @@ PalResult PAL_CALL createVkPipelineLayout( &layout->handle); if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, descriptorLayouts); + palFree(s_Vk.allocator, pushConstants); + palFree(s_Vk.allocator, layout); return vkResultToPal(result); } + palFree(s_Vk.allocator, descriptorLayouts); + palFree(s_Vk.allocator, pushConstants); + layout->device = vkDevice; *outLayout = (PalPipelineLayout*)layout; return PAL_RESULT_SUCCESS; From 0c01aa3d3699d387b235f83b16e7bf07a67ab96a Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 12 Jan 2026 17:52:21 +0000 Subject: [PATCH 086/372] add compute test --- .gitignore | 3 + include/pal/pal_graphics.h | 54 ++- src/graphics/pal_graphics.c | 60 +++- src/graphics/pal_vulkan.c | 246 ++++++++++---- tests/clear_color_test.c | 27 +- tests/compute_test.c | 655 ++++++++++++++++++++++++++++++++++++ tests/mesh_test.c | 21 +- tests/shaders/compute.spv | Bin 0 -> 1668 bytes tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 3 +- tests/triangle_test.c | 54 ++- 12 files changed, 994 insertions(+), 133 deletions(-) create mode 100644 tests/compute_test.c create mode 100644 tests/shaders/compute.spv diff --git a/.gitignore b/.gitignore index afa1351a..944ea572 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ Makefile # docs docs/**html + +# ppm files +**.ppm diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 9b6ddff3..4d51924c 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -536,18 +536,24 @@ enum PalDebugMessageType { typedef enum { PAL_USAGE_STATE_UNDEFINED, PAL_USAGE_STATE_PRESENT, - PAL_USAGE_STATE_COLOR_ATTACHMENT, - PAL_USAGE_STATE_DEPTH_ATTACHMENT, - PAL_USAGE_STATE_STENCIL_ATTACHMENT, - PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT, - PAL_USAGE_STATE_TRANSFER_WRITE, + PAL_USAGE_STATE_COLOR_ATTACHMENT_READ, + PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE, + PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ, + PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE, + PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ, + PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE, + PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ, PAL_USAGE_STATE_TRANSFER_READ, + PAL_USAGE_STATE_TRANSFER_WRITE, PAL_USAGE_STATE_VERTEX_READ, PAL_USAGE_STATE_INDEX_READ, PAL_USAGE_STATE_UNIFORM_READ, PAL_USAGE_STATE_SHADER_READ, + PAL_USAGE_STATE_SHADER_WRITE, PAL_USAGE_STATE_STORAGE_READ, - PAL_USAGE_STATE_STORAGE_WRITE + PAL_USAGE_STATE_STORAGE_WRITE, + PAL_USAGE_STATE_HOST_READ, + PAL_USAGE_STATE_HOST_WRITE, } PalUsageState; typedef enum { @@ -686,6 +692,11 @@ typedef struct { PalClearValue clearValue; } PalAttachmentDesc; +typedef struct { + PalUsageState usageState; + PalShaderStage shaderStage; +} PalUsageStateInfo; + typedef struct { float x; float y; @@ -1018,6 +1029,11 @@ typedef struct { PalRenderingLayoutInfo* renderingLayout; } PalGraphicsPipelineCreateInfo; +typedef struct { + PalPipelineLayout* pipelineLayout; + PalShader* computeShader; +} PalComputePipelineCreateInfo; + typedef struct { PalResult PAL_CALL (*enumerateAdapters)( Int32* count, @@ -1346,14 +1362,14 @@ typedef struct { PalResult PAL_CALL (*imageViewBarrier)( PalCommandBuffer* cmdBuffer, PalImageView* imageView, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); PalResult PAL_CALL (*bufferBarrier)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); PalResult PAL_CALL (*dispatch)( PalCommandBuffer* cmdBuffer, @@ -1462,6 +1478,11 @@ typedef struct { const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline); + PalResult PAL_CALL (*createComputePipeline)( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + void PAL_CALL (*destroyPipeline)(PalPipeline* pipeline); } PalGraphicsBackend; @@ -1800,14 +1821,14 @@ PAL_API PalResult PAL_CALL palDrawIndexedIndirectCount( PAL_API PalResult PAL_CALL palImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); PAL_API PalResult PAL_CALL palBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); PAL_API PalResult PAL_CALL palDispatch( PalCommandBuffer* cmdBuffer, @@ -1916,6 +1937,11 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline); +PAL_API PalResult PAL_CALL palCreateComputePipeline( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); PAL_API bool PAL_CALL palBuildWorkGroupInfo( diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index c14cef19..3c2a93fe 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -419,14 +419,14 @@ PalResult PAL_CALL drawIndexedIndirectCountVk( PalResult PAL_CALL imageViewBarrierVk( PalCommandBuffer* cmdBuffer, PalImageView* imageView, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); PalResult PAL_CALL bufferBarrierVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); PalResult PAL_CALL dispatchVk( PalCommandBuffer* cmdBuffer, @@ -548,6 +548,11 @@ PalResult PAL_CALL createVkGraphicsPipeline( const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline); +PalResult PAL_CALL createVkComputePipeline( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + void PAL_CALL destroyVkPipeline(PalPipeline* pipeline); static PalGraphicsBackend s_VkBackend = { @@ -652,6 +657,7 @@ static PalGraphicsBackend s_VkBackend = { .createPipelineLayout = createVkPipelineLayout, .destroyPipelineLayout = destroyVkPipelineLayout, .createGraphicsPipeline = createVkGraphicsPipeline, + .createComputePipeline = createVkComputePipeline, .destroyPipeline = destroyVkPipeline}; #endif // PAL_HAS_VULKAN @@ -789,6 +795,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->createPipelineLayout || !backend->destroyPipelineLayout || !backend->createGraphicsPipeline || + !backend->createComputePipeline || !backend->destroyPipeline) { return PAL_RESULT_INVALID_BACKEND; } @@ -2095,8 +2102,8 @@ PalResult PAL_CALL palDrawIndexedIndirectCount( PalResult PAL_CALL palImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2106,14 +2113,18 @@ PalResult PAL_CALL palImageViewBarrier( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->imageViewBarrier(cmdBuffer, imageView, oldUsageState, newUsageState); + return cmdBuffer->backend->imageViewBarrier( + cmdBuffer, + imageView, + oldUsageStateInfo, + newUsageStateInfo); } PalResult PAL_CALL palBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2123,7 +2134,11 @@ PalResult PAL_CALL palBufferBarrier( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->bufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); + return cmdBuffer->backend->bufferBarrier( + cmdBuffer, + buffer, + oldUsageStateInfo, + newUsageStateInfo); } PalResult PAL_CALL palDispatch( @@ -2593,6 +2608,31 @@ PalResult PAL_CALL palCreateGraphicsPipeline( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL palCreateComputePipeline( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outPipeline) { + return PAL_RESULT_NULL_POINTER; + } + + PalResult result; + PalPipeline* pipeline = nullptr; + result = device->backend->createComputePipeline(device, info, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + pipeline->backend = device->backend; + *outPipeline = pipeline; + return PAL_RESULT_SUCCESS; +} + void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) { if (s_Graphics.initialized && pipeline) { diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index f5853b86..c93cf023 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -181,6 +181,7 @@ typedef struct { PFN_vkCreatePipelineLayout createPipelineLayout; PFN_vkDestroyPipelineLayout destroyPipelineLayout; PFN_vkCreateGraphicsPipelines createGraphicsPipeline; + PFN_vkCreateComputePipelines createComputePipeline; PFN_vkDestroyPipeline destroyPipeline; PFN_vkCreateDebugUtilsMessengerEXT createMessenger; PFN_vkDestroyDebugUtilsMessengerEXT destroyMessenger; @@ -397,7 +398,7 @@ typedef struct { typedef struct { VkPipelineStageFlags2 stages; - VkPipelineStageFlags2 dstStagess; + VkPipelineStageFlags2 dstStages; VkAccessFlags2 access; VkImageLayout layout; } Barrier; @@ -1519,7 +1520,7 @@ static VkFragmentShadingRateCombinerOpKHR combinerOpsToVk(PalFragmentShadingRate return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; } -static VkResolveModeFlagBits resolveModeToVk(PalResolveMode mode) +static VkResolveModeFlags resolveModeToVk(PalResolveMode mode) { switch (mode) { case PAL_RESOLVE_MODE_SAMPLE_ZERO: @@ -1538,157 +1539,214 @@ static VkResolveModeFlagBits resolveModeToVk(PalResolveMode mode) return VK_RESOLVE_MODE_NONE_KHR; } -static Barrier barrierToVk(PalUsageState state) +static VkPipelineStageFlags2 stageToVkPipelineStage(PalShaderStage stage) +{ + switch (stage) { + case PAL_SHADER_STAGE_VERTEX: + return VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT; + + case PAL_SHADER_STAGE_FRAGMENT: + return VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; + + case PAL_SHADER_STAGE_COMPUTE: + return VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + + case PAL_SHADER_STAGE_GEOMETRY: + return VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT; + + case PAL_SHADER_STAGE_MESH: + return VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT; + + case PAL_SHADER_STAGE_TASK: + return VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT; + + case PAL_SHADER_STAGE_TESSELLATION_CONTROL: + return VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT; + + case PAL_SHADER_STAGE_TESSELLATION_EVALUATION: + return VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT; + + case PAL_SHADER_STAGE_RAYGEN: + case PAL_SHADER_STAGE_CLOSEST_HIT: + case PAL_SHADER_STAGE_ANY_HIT: + case PAL_SHADER_STAGE_MISS: + case PAL_SHADER_STAGE_INTERSECTION: + case PAL_SHADER_STAGE_CALLABLE: { + return VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; + } + } + return 0; +} + +static Barrier barrierToVk(PalUsageState state, + PalShaderStage shaderStage) { Barrier barrier = {0}; switch (state) { case PAL_USAGE_STATE_UNDEFINED: { barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; - barrier.dstStagess = barrier.dstStagess; + barrier.dstStages = barrier.dstStages; barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; } case PAL_USAGE_STATE_PRESENT: { barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; - barrier.dstStagess = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; - + barrier.dstStages = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - return barrier; } - case PAL_USAGE_STATE_COLOR_ATTACHMENT: { + case PAL_USAGE_STATE_COLOR_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; - barrier.dstStagess = barrier.stages; - + barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR; - barrier.access |= VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + return barrier; + } + case PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE: { + barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; return barrier; } - case PAL_USAGE_STATE_DEPTH_ATTACHMENT: { + case PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; - barrier.dstStagess = barrier.stages; - + barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; - barrier.access |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + return barrier; + } + case PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE: { + barrier.stages = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; return barrier; } - case PAL_USAGE_STATE_STENCIL_ATTACHMENT: { + case PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; - barrier.dstStagess = barrier.stages; - + barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; - barrier.access |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; + return barrier; + } + case PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE: { + barrier.stages = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; return barrier; } - case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT: { + case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; - barrier.dstStagess = barrier.stages; - + barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; - + VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; - return barrier; } case PAL_USAGE_STATE_TRANSFER_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; - barrier.dstStagess = barrier.dstStagess; + barrier.dstStages = barrier.dstStages; barrier.access = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; } case PAL_USAGE_STATE_TRANSFER_READ: { barrier.stages = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; - barrier.dstStagess = barrier.dstStagess; + barrier.dstStages = barrier.dstStages; barrier.access = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; } case PAL_USAGE_STATE_VERTEX_READ: { barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR; - barrier.dstStagess = barrier.dstStagess; + barrier.dstStages = barrier.dstStages; barrier.access = VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; } case PAL_USAGE_STATE_INDEX_READ: { barrier.stages = VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR; - barrier.dstStagess = barrier.dstStagess; + barrier.dstStages = barrier.dstStages; barrier.access = VK_ACCESS_2_INDEX_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; } case PAL_USAGE_STATE_UNIFORM_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR; - barrier.stages |= VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR; - barrier.dstStagess = barrier.dstStagess; - + barrier.stages = stageToVkPipelineStage(shaderStage); + barrier.dstStages = barrier.dstStages; barrier.access = VK_ACCESS_2_UNIFORM_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; } case PAL_USAGE_STATE_SHADER_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR; - barrier.dstStagess = barrier.dstStagess; - + barrier.stages = stageToVkPipelineStage(shaderStage); + barrier.dstStages = barrier.dstStages; barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + case PAL_USAGE_STATE_SHADER_WRITE: { + barrier.stages = stageToVkPipelineStage(shaderStage); + barrier.dstStages = barrier.dstStages; + barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_STORAGE_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR; - barrier.stages |= VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR; - barrier.dstStagess = barrier.dstStagess; - + barrier.stages = stageToVkPipelineStage(shaderStage); + barrier.dstStages = barrier.dstStages; barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; } case PAL_USAGE_STATE_STORAGE_WRITE: { - barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR; - barrier.stages |= VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR; - barrier.dstStagess = barrier.dstStagess; - + barrier.stages = stageToVkPipelineStage(shaderStage); + barrier.dstStages = barrier.dstStages; barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + + case PAL_USAGE_STATE_HOST_READ: { + barrier.stages = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; + barrier.dstStages = barrier.dstStages; + barrier.access = VK_ACCESS_2_HOST_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + case PAL_USAGE_STATE_HOST_WRITE: { + barrier.stages = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; + barrier.dstStages = barrier.dstStages; + barrier.access = VK_ACCESS_2_HOST_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } } barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; - barrier.dstStagess = barrier.stages; + barrier.dstStages = barrier.stages; barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -1717,7 +1775,7 @@ static VkDescriptorType descriptortypeToVk(PalDescriptorType type) return 0; } -static VkShaderStageFlagBits shaderStageToVK(PalShaderStage stage) +static VkShaderStageFlags shaderStageToVK(PalShaderStage stage) { switch (stage) { case PAL_SHADER_STAGE_VERTEX: @@ -2202,6 +2260,10 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCreateGraphicsPipelines"); + s_Vk.createComputePipeline = (PFN_vkCreateComputePipelines)dlsym( + s_Vk.handle, + "vkCreateComputePipelines"); + s_Vk.destroyPipeline = (PFN_vkDestroyPipeline)dlsym( s_Vk.handle, "vkDestroyPipeline"); @@ -2715,6 +2777,14 @@ PalResult PAL_CALL getVkAdapterCapabilities( } } + caps->maxComputeWorkGroupInvocations = props.limits.maxComputeWorkGroupInvocations; + caps->maxComputeWorkGroupCount[0] = props.limits.maxComputeWorkGroupCount[0]; + caps->maxComputeWorkGroupCount[1] = props.limits.maxComputeWorkGroupCount[1]; + caps->maxComputeWorkGroupCount[2] = props.limits.maxComputeWorkGroupCount[2]; + caps->maxComputeWorkGroupSize[0] = props.limits.maxComputeWorkGroupSize[0]; + caps->maxComputeWorkGroupSize[1] = props.limits.maxComputeWorkGroupSize[1]; + caps->maxComputeWorkGroupSize[2] = props.limits.maxComputeWorkGroupSize[2]; + palFree(s_Vk.allocator, queueProps); return PAL_RESULT_SUCCESS; } @@ -5965,8 +6035,8 @@ PalResult PAL_CALL drawIndexedIndirectCountVk( PalResult PAL_CALL imageViewBarrierVk( PalCommandBuffer* cmdBuffer, PalImageView* imageView, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; ImageView* vkImageView = (ImageView*)imageView; @@ -5974,8 +6044,8 @@ PalResult PAL_CALL imageViewBarrierVk( barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR; Barrier old, new; - old = barrierToVk(oldUsageState); - new = barrierToVk(newUsageState); + old = barrierToVk(oldUsageStateInfo->usageState, oldUsageStateInfo->shaderStage); + new = barrierToVk(newUsageStateInfo->usageState, newUsageStateInfo->shaderStage); barrier.srcStageMask = old.stages; barrier.srcAccessMask = old.access; @@ -6002,8 +6072,8 @@ PalResult PAL_CALL imageViewBarrierVk( PalResult PAL_CALL bufferBarrierVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; @@ -6011,8 +6081,8 @@ PalResult PAL_CALL bufferBarrierVk( barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; Barrier old, new; - old = barrierToVk(oldUsageState); - new = barrierToVk(newUsageState); + old = barrierToVk(oldUsageStateInfo->usageState, oldUsageStateInfo->shaderStage); + new = barrierToVk(newUsageStateInfo->usageState, newUsageStateInfo->shaderStage); barrier.srcStageMask = old.stages; barrier.srcAccessMask = old.access; @@ -6135,6 +6205,8 @@ PalResult PAL_CALL pushConstantsVk( offset, size, value); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL submitVkCommandBuffer( @@ -6725,6 +6797,12 @@ PalResult PAL_CALL updateVkDescriptorSet( Uint32 imageIndex = 0; for (int i = 0; i < count; i++) { VkWriteDescriptorSet* write = &writes[i]; + write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write->pBufferInfo = nullptr; + write->pImageInfo = nullptr; + write->pTexelBufferView = nullptr; + write->pNext = nullptr; + write->dstArrayElement = infos[i].arrayElement; write->dstBinding = infos[i].binding; write->descriptorCount = infos[i].descriptorCount; @@ -6740,6 +6818,7 @@ PalResult PAL_CALL updateVkDescriptorSet( bufferInfo->buffer = vkBuffer->handle; bufferInfo->offset = infos[i].bufferInfo->offset; bufferInfo->range = infos[i].bufferInfo->size; + write->pBufferInfo = bufferInfo; } else { VkDescriptorImageInfo* imageInfo = &imageInfos[imageIndex++]; @@ -6761,6 +6840,7 @@ PalResult PAL_CALL updateVkDescriptorSet( imageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo->imageView = vkImageView->handle; } + write->pImageInfo = imageInfo; } } s_Vk.updateDescriptorSet(vkDevice->handle, count, writes, 0, nullptr); @@ -6810,10 +6890,11 @@ PalResult PAL_CALL createVkPipelineLayout( VkPushConstantRange* range = &pushConstants[i]; range->offset = info->pushConstantRanges[i].offset; range->size = info->pushConstantRanges[i].size; + range->stageFlags = 0; range->offset = info->pushConstantRanges[i].offset; for (int j = 0; j < info->pushConstantRanges[i].shaderStageCount; j++) { - VkShaderStageFlagBits bit = + VkShaderStageFlags bit = shaderStageToVK(info->pushConstantRanges[i].shaderStages[j]); range->stageFlags |= bit; } @@ -7290,6 +7371,45 @@ PalResult PAL_CALL createVkGraphicsPipeline( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL createVkComputePipeline( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + Device* vkDevice = (Device*)device; + PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; + Shader* shader = (Shader*)info->computeShader; + Pipeline* pipeline = nullptr; + + pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); + if (!pipeline) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkComputePipelineCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + createInfo.layout = layout->handle; + createInfo.stage = shader->info; + + VkResult result = s_Vk.createComputePipeline( + vkDevice->handle, + nullptr, + 1, + &createInfo, + &s_Vk.vkAllocator, + &pipeline->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + return vkResultToPal(result); + } + + pipeline->device = vkDevice; + pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; +} + void PAL_CALL destroyVkPipeline(PalPipeline* pipeline) { Pipeline* vkPipeline = (Pipeline*)pipeline; diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index bdadaf22..677125f5 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -281,7 +281,7 @@ bool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command buffer: %s", error); + palLog(nullptr, "Failed to allocate command buffer: %s", error); return false; } } @@ -414,18 +414,27 @@ bool clearColorTest() renderingInfo.renderArea.height = WINDOW_HEIGHT; // change the state of the image view to make it renderable - PalUsageState oldUsageState; + PalUsageStateInfo oldUsageStateInfo = {0}; + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + if (firstImageViewUse[index]) { - oldUsageState = PAL_USAGE_STATE_UNDEFINED; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; } else { - oldUsageState = PAL_USAGE_STATE_PRESENT; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; } result = palImageViewBarrier( cmdBuffer, imageViews[index], - oldUsageState, - PAL_USAGE_STATE_COLOR_ATTACHMENT); + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -448,11 +457,13 @@ bool clearColorTest() } // change the state of the image view to make it presentable + oldUsageStateInfo = newUsageStateInfo; + newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; result = palImageViewBarrier( cmdBuffer, imageViews[index], - PAL_USAGE_STATE_COLOR_ATTACHMENT, - PAL_USAGE_STATE_PRESENT); + &oldUsageStateInfo, + &newUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/compute_test.c b/tests/compute_test.c new file mode 100644 index 00000000..036550ff --- /dev/null +++ b/tests/compute_test.c @@ -0,0 +1,655 @@ + +#include "pal/pal_graphics.h" +#include "tests.h" + +#include + +#define BUFFER_SIZE 400 + +// the storage buffer needs alignment of 16 +typedef struct { + Uint32 width; + Uint32 height; + Uint32 _padding[2]; + float color[4]; +} PushConstant; + +static bool readFile( + const char* filename, + void* buffer, + Uint64* size) +{ + FILE* file = fopen(filename, "rb"); + if (!file) { + return false; + } + + fseek(file, 0, SEEK_END); + Uint64 tmpSize = ftell(file); + fseek(file, 0, SEEK_SET); + + if (buffer) { + fread(buffer, 1, (size_t)size, file); + } + + fclose(file); + *size = tmpSize; + return true; +} + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) +{ + palLog(nullptr, msg); +} + +bool computeTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Compute Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalQueue* queue = nullptr; + PalCommandPool* cmdPool = nullptr; + PalCommandBuffer* cmdBuffer; + PalShader* shader = nullptr; + PalBuffer* buffer = nullptr; + PalBuffer* stagingBuffer = nullptr; + PalMemory* bufferMemory = nullptr; + PalMemory* stagingBufferMemory = nullptr; + + PalDescriptorSetLayout* descriptorSetLayout = nullptr; + PalDescriptorPool* descriptorPool = nullptr; + PalDescriptorSet* descriptorSet = nullptr; + PalPipelineLayout* pipelineLayout; + PalPipeline* pipeline = nullptr; + PalFence* fence = nullptr; + + PalGraphicsDebugger debugger; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; + + PalResult result = palInitGraphics(nullptr, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (adapterCount == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", adapterCount); + + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&adapterCount, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + PalAdapterCapabilities caps; + PalAdapterFeatures adapterFeatures = 0; + bool hasComputeQueue = false; + for (Int32 i = 0; i < adapterCount; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (caps.maxComputeQueues == 0) { + continue; + + } else { + hasComputeQueue = true; + adapterFeatures = palGetAdapterFeatures(adapter); + if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { + break; + } + } + } + + palFree(nullptr, adapters); + if (!adapter) { + if (hasComputeQueue) { + palLog(nullptr, "Failed to find an adapter that supports compute queue"); + + } else { + palLog(nullptr, "Failed to find an adapter that supports compute shader"); + } + return false; + } + + PalAdapterInfo adapterInfo = {0}; + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // create a device + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_COMPUTE_SHADER; + result = palCreateDevice(adapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a graphics command queue + result = palCreateQueue(device, PAL_QUEUE_TYPE_COMPUTE, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + result = palCreateCommandPool(device, queue, &cmdPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + result = palAllocateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffer); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate command buffer: %s", error); + return false; + } + + // create a compute shader + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + PalShaderCreateInfo shaderCreateInfo = {0}; + const char* shaderPath = nullptr; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + shaderPath = "shaders/compute.spv"; + } + + if (!readFile(shaderPath, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to find shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(shaderPath, bytecode, &bytecodeSize); + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_COMPUTE; + + result = palCreateShader(device, &shaderCreateInfo, &shader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create compute shader: %s", error); + return false; + } + + // create a storage buffer + Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader + PalBufferCreateInfo bufferCreateInfo = {0}; + bufferCreateInfo.size = bufferBytes; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE | PAL_BUFFER_USAGE_TRANSFER_SRC; + + result = palCreateBuffer(device, &bufferCreateInfo, &buffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create buffer: %s", error); + return false; + } + + bufferCreateInfo.size = bufferBytes; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_DST; + + result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create staging buffer: %s", error); + return false; + } + + // get buffer memory requirement and allocate memory + PalMemoryRequirements bufferMemReq = {0}; + PalMemoryRequirements stagingBufferMemReq = {0}; + result = palGetBufferMemoryRequirements(buffer, &bufferMemReq); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + // we need to check if the memory type we want are supported + // but almost every GPU supports a GPU only memory + // and CPU writable memory + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + bufferMemReq.size, + &bufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_READBACK, + stagingBufferMemReq.size, + &stagingBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + // bind memory + result = palBindBufferMemory(buffer, bufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + // create descriptor set layout + PalDescriptorSetLayoutBinding descriptorBinding = {0}; + PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_COMPUTE }; + + descriptorBinding.binding = 0; + descriptorBinding.descriptorCount = 1; // not an array + descriptorBinding.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorBinding.shaderStageCount = 1; + descriptorBinding.shaderStages = shaderStages; + + PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; + descriptorSetLayoutcreateInfo.bindingCount = 1; + descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; + + result = palCreateDescriptorSetLayout( + device, + &descriptorSetLayoutcreateInfo, + &descriptorSetLayout); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor set layout: %s", error); + return false; + } + + // create descriptor pool + PalDescriptorPoolBindingSize storageBufferBindingsize = {0}; + storageBufferBindingsize.bindingCount = 1; + storageBufferBindingsize.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + + PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; + descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set + descriptorPoolCreateInfo.maxDescriptorBindingSizes = 1; // one binding type + descriptorPoolCreateInfo.bindingSizes = &storageBufferBindingsize; + + result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor pool: %s", error); + return false; + } + + // allocate a single descriptor set from the descriptor pool + // using the layout we created above + result = palAllocateDescriptorSet(device, descriptorPool, descriptorSetLayout, &descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate descriptor set: %s", error); + return false; + } + + // write the inital data to the descriptor set since its created empty + PalDescriptorBufferInfo descriptorBufferInfo = {0}; + descriptorBufferInfo.buffer = buffer; + descriptorBufferInfo.offset = 0; + descriptorBufferInfo.size = bufferBytes; + + PalDescriptorSetWriteInfo writeInfo = {0}; + writeInfo.binding = 0; + writeInfo.bufferInfo = &descriptorBufferInfo; + writeInfo.descriptorSet = descriptorSet; + writeInfo.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + writeInfo.descriptorCount = 1; + + result = palUpdateDescriptorSet(device, 1, &writeInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to update descriptor set: %s", error); + return false; + } + + // push constants + // size must be less than the max size from the adapter capabilities struct + PalPushConstantRange pushConstantRange = {0}; + pushConstantRange.offset = 0; + pushConstantRange.size = sizeof(PushConstant); // must match shader + pushConstantRange.shaderStageCount = 1; + pushConstantRange.shaderStages = shaderStages; + + // create pipeline layout + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + pipelineLayoutCreateInfo.descriptorSetLayoutCount = 1; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.descriptorSetLayouts = &descriptorSetLayout; + pipelineLayoutCreateInfo.pushConstantRanges = &pushConstantRange; + + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline layout: %s", error); + return false; + } + + // create a compute pipeline + PalComputePipelineCreateInfo pipelineCreateInfo = {0}; + pipelineCreateInfo.computeShader = shader; + pipelineCreateInfo.pipelineLayout = pipelineLayout; + + result = palCreateComputePipeline(device, &pipelineCreateInfo, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create compute pipeline: %s", error); + return false; + } + + palDestroyShader(shader); + + // create fence + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + // record commands + result = palBeginCommandBuffer(cmdBuffer, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + PushConstant pushConstant = {0}; + pushConstant.width = BUFFER_SIZE; + pushConstant.height = BUFFER_SIZE; + pushConstant.color[0] = 1.0f; + pushConstant.color[1] = 0.0f; + pushConstant.color[2] = 0.0f; + pushConstant.color[3] = 1.0f; + + result = palBindPipeline(cmdBuffer, pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + palLog(nullptr, "%d", sizeof(PushConstant)); + + result = palPushConstants( + cmdBuffer, + pipelineLayout, + 1, + shaderStages, + 0, + sizeof(PushConstant), + &pushConstant); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to push constants: %s", error); + return false; + } + + result = palBindDescriptorSet(cmdBuffer, pipeline, pipelineLayout, 0, descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind descriptor set: %s", error); + return false; + } + + // we will use a helper function to calculate the number of group count + // we need on each axis. The workGroupSize on each axis must be less or equal + // to maxComputeWorkGroupInvocations from the adapter capabilities struct + PalWorkGroupBuildData buildData = {0}; + buildData.workCount[0] = BUFFER_SIZE; + buildData.workCount[1] = BUFFER_SIZE; + buildData.workCount[2] = 1; // no Z + + buildData.workGroupSize[0] = 16; // must match shader (local_size on glsl) + buildData.workGroupSize[1] = 16; // must match shader (local_size on glsl) + buildData.workGroupSize[2] = 1; // must match shader (local_size on glsl) + + // device limits + buildData.workGroupCount[0] = caps.maxComputeWorkGroupCount[0]; + buildData.workGroupCount[1] = caps.maxComputeWorkGroupCount[1]; + buildData.workGroupCount[2] = caps.maxComputeWorkGroupCount[2]; + + Uint32 workGroupInfoCount = 0; + PalWorkGroupInfo* workGroupInfos = nullptr; + bool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); + if (!ret) { + palLog(nullptr, "Failed to build work group info"); + return false; + } + + workGroupInfos = palAllocate(nullptr, sizeof(PalWorkGroupInfo) * workGroupInfoCount, 0); + if (!workGroupInfos) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, workGroupInfos); + + // set a barrier on the buffer + PalUsageStateInfo oldUsageStateInfo = {0}; + oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; + + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_COMPUTE; + newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; + + result = palBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // dispatch with the work group info + for (int i = 0; i < workGroupInfoCount; i++) { + // palDispatchBase is not supported on all platforms so we dont use it for this example + // We cap the buffer size small so we only get a single dispatch + // but you can add fields in yout constants to send the base to the shader driectly + Uint32 groupCountX = workGroupInfos[i].workGroupCount[0]; + Uint32 groupCountY = workGroupInfos[i].workGroupCount[1]; + Uint32 groupCountZ = workGroupInfos[i].workGroupCount[2]; + + result = palDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to dispatch: %s", error); + return false; + } + } + palFree(nullptr, workGroupInfos); + + // set a barrier so we only read from the buffer after the shader has + // written to it + oldUsageStateInfo = newUsageStateInfo; + newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; + + result = palBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // set a barrier on the staging buffer + oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; + oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + + newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + + result = palBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // now we copy from the GPU buffer into the staging buffer + result = palCopyBuffer(cmdBuffer, stagingBuffer, buffer, 0, 0, bufferBytes); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer: %s", error); + return false; + } + + // if we want to copy to the ppm buffer in the command buffer + // we need a barrier to with the state PAL_USAGE_STATE_HOST_READ + // but we map and copy outside the command buffer since + // we wait for a fence (the command buffer has been executed). + + result = palEndCommandBuffer(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // submit the command buffer to the GPU + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffer; + submitInfo.fence = fence; + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // wait for the fence + result = palWaitFence(fence, UINT64_MAX); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } + + // now our staging buffer has the contents of the GPU buffer + // we map it and copy the contents to a ppm buffer and save it + void* ptr = nullptr; + result = palMapMemory(device, stagingBufferMemory, 0, bufferBytes, &ptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map memory: %s", error); + return false; + } + + // write to a ppm output file + FILE* file = fopen("compute_output.ppm", "wb"); + fprintf(file, "P6\n%d %d\n255\n", BUFFER_SIZE, BUFFER_SIZE); + float* pixels = (float*)ptr; + for (int y = 0; y < BUFFER_SIZE; y++) { + int row = BUFFER_SIZE - 1 - y; // flip y + for (int x = 0; x < BUFFER_SIZE; x++) { + int index = row * BUFFER_SIZE + x; + Uint8 rgb[3]; + + rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; + rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; + rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255: 0; + fwrite(rgb, 1, 3, file); + } + } + + fclose(file); + + palUnmapMemory(device, stagingBufferMemory); + + palDestroyPipeline(pipeline); + palDestroyPipelineLayout(pipelineLayout); + palFreeCommandBuffer(cmdBuffer); + palDestroyCommandPool(cmdPool); + + palDestroyDescriptorPool(descriptorPool); + palDestroyDescriptorSetLayout(descriptorSetLayout); + + palDestroyBuffer(buffer); + palDestroyBuffer(stagingBuffer); + palFreeMemory(device, bufferMemory); + palFreeMemory(device, stagingBufferMemory); + + palDestroyFence(fence); + palDestroyQueue(queue); + palDestroyDevice(device); + palShutdownGraphics(); + return true; +} diff --git a/tests/mesh_test.c b/tests/mesh_test.c index f16b368d..c8d182ff 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -330,7 +330,7 @@ bool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command buffer: %s", error); + palLog(nullptr, "Failed to allocate command buffer: %s", error); return false; } } @@ -588,18 +588,21 @@ bool meshTest() } // change the state of the image view to make it renderable - PalUsageState oldUsageState; + PalUsageStateInfo oldUsageStateInfo = {0}; + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + if (firstImageViewUse[index]) { - oldUsageState = PAL_USAGE_STATE_UNDEFINED; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; } else { - oldUsageState = PAL_USAGE_STATE_PRESENT; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; } result = palImageViewBarrier( cmdBuffer, imageViews[index], - oldUsageState, - PAL_USAGE_STATE_COLOR_ATTACHMENT); + &oldUsageStateInfo, + &newUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -677,11 +680,13 @@ bool meshTest() } // change the state of the image view to make it presentable + oldUsageStateInfo = newUsageStateInfo; + newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; result = palImageViewBarrier( cmdBuffer, imageViews[index], - PAL_USAGE_STATE_COLOR_ATTACHMENT, - PAL_USAGE_STATE_PRESENT); + &oldUsageStateInfo, + &newUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/shaders/compute.spv b/tests/shaders/compute.spv new file mode 100644 index 0000000000000000000000000000000000000000..4597b5d42cbdeee583f351d8dcb629aeca437b7f GIT binary patch literal 1668 zcmZ9L+fGwa5QZ0&B8q~@$rHE%&nTh-qR1(lR1y+Rd;n8{&?dDdwpG0I!iVw7hwz<@ zhs4D1Tir{Ei~P*Yzvi@ORtw!T$3o}|{h=>xhRzuZ-7o>JH_FoX%k8;lYj7ED4B}Hn_JB9#YTb)|a2j52DC*i)2}Bmi9>Q0QA|6NMirn>acL<7T=Gm{kD%BdV z%eAfgyT(qrRc+L_p2qt^%=sbez2PkKMY~yf(x^9E<$4Pe>7RN^dG)uaDd0)= zbjOVL2D*Ko1H*J^y(#)Nr}`*4td{{#hRs8YkRQiBj#M|s`xD46Ait8^){vXU*7qdv z=zj|7oqW3YJ;{yG#RzhY>|@9bSaUpbomoxhGc{g#XI{U_9-O^>XuE4Uzv}`r1J<#w zw)^rJKY>i&mhP{>=|4d~?!sD==+0i-xFw{sle4b2dyq?c9_F_GkI=1?`d-cNw9`D+ z(R~BA_(FX*fShnvOU%Ihz8#Od_yOZ@)*jrMzd2>H&3DxH&1-KGc z;5#+a+yBL#{4|hr7V0VQWpw*VwXdRE+x;e=Yv}T+_H}gQJ ve)8_cy~`#4Wpp`b Date: Fri, 16 Jan 2026 11:54:42 +0000 Subject: [PATCH 087/372] add descriptor indexing capabilities struct --- include/pal/pal_graphics.h | 20 +++++++++ src/graphics/pal_graphics.c | 21 +++++++++ src/graphics/pal_vulkan.c | 88 ++++++++++++++++++++++++++++++++++--- tests/compute_test.c | 2 - 4 files changed, 122 insertions(+), 9 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 4d51924c..56ff7010 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -640,6 +640,18 @@ typedef struct { Uint32 shaderGroupBaseAlignment; } PalRayTracingCapabilities; +typedef struct { + bool bindlessStorageBuffers; + bool bindlessUniformBuffers; + Uint32 maxImagesPerShaderStage; + Uint32 maxImagesPerDescriptorSet; + Uint32 maxStorageBuffersPerShaderStage; + Uint32 maxStorageBuffersPerDescriptorSet; + Uint32 maxUniformBuffersPerShaderStage; + Uint32 maxUniformBuffersPerDescriptorSet; + Uint32 maxDescriptors; +} PalDescriptorIndexingCapabilities; + typedef struct { bool presentModes[PAL_PRESENT_MODE_MAX]; bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; @@ -1095,6 +1107,10 @@ typedef struct { PalDevice* device, PalRayTracingCapabilities* caps); + PalResult PAL_CALL (*queryDescriptorIndexingCapabilities)( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); + PalResult PAL_CALL (*createQueue)( PalDevice* device, PalQueueType type, @@ -1554,6 +1570,10 @@ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( PalDevice* device, PalRayTracingCapabilities* caps); +PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); + PAL_API PalResult PAL_CALL palCreateQueue( PalDevice* device, PalQueueType type, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 3c2a93fe..1e579b7e 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -152,6 +152,10 @@ PalResult PAL_CALL queryVkRayTracingCapabilities( PalDevice* device, PalRayTracingCapabilities* caps); +PalResult PAL_CALL queryVkDescriptorIndexingCapabilities( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); + PalResult PAL_CALL createVkQueue( PalDevice* device, PalQueueType type, @@ -571,6 +575,7 @@ static PalGraphicsBackend s_VkBackend = { .queryFragmentShadingRateCapabilities = queryVkFragmentShadingRateCapabilities, .queryMeshShaderCapabilities = queryVkMeshShaderCapabilities, .queryRayTracingCapabilities = queryVkRayTracingCapabilities, + .queryDescriptorIndexingCapabilities = queryVkDescriptorIndexingCapabilities, .createQueue = createVkQueue, .destroyQueue = destroyVkQueue, .waitQueue = waitVkQueue, @@ -707,6 +712,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->queryFragmentShadingRateCapabilities || !backend->queryMeshShaderCapabilities || !backend->queryRayTracingCapabilities || + !backend->queryDescriptorIndexingCapabilities || !backend->createQueue || !backend->destroyQueue || !backend->waitQueue || @@ -1096,6 +1102,21 @@ PalResult PAL_CALL palQueryRayTracingCapabilities( return device->backend->queryRayTracingCapabilities(device, caps); } +PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->queryDescriptorIndexingCapabilities(device, caps); +} + // ================================================== // Queue // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index c93cf023..d8a3caf9 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -70,6 +70,9 @@ typedef int (*wl_display_get_fd_fn)(struct wl_display*); #define COMPUTE_PIPELINE 127 typedef struct { + // For descriptor Indexing + bool bindlessStorageBuffers; + bool bindlessUniformBuffers; const PalGraphicsBackend* backend; VkPhysicalDevice handle; } Adapter; @@ -203,6 +206,8 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + bool bindlessStorageBuffers; + bool bindlessUniformBuffers; PalAdapterFeatures features; Int32 queueCount; Int32 gpuOnlyMemoryIndex; @@ -2609,6 +2614,8 @@ PalResult PAL_CALL enumerateVkAdapters( if (adapterCount < *count) { Adapter* tmp = &s_Vk.adapters[adapterCount]; tmp->handle = devices[i]; + tmp->bindlessStorageBuffers = false; + tmp->bindlessUniformBuffers = false; outAdapters[adapterCount] = (PalAdapter*)tmp; } } @@ -2802,7 +2809,6 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) // get supported extensions s_Vk.getPhysicalDeviceProperties(phyDevice, &props); result = s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, nullptr); - if (result != VK_SUCCESS) { // we just return without any modern features which is rare return 0; @@ -2810,7 +2816,6 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) VkExtensionProperties* extensionProps = nullptr; extensionProps = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extensionCount, 0); - if (!extensionProps) { return 0; } @@ -2958,9 +2963,24 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) features.pNext = &desc; s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (desc.shaderSampledImageArrayNonUniformIndexing) { + if (desc.runtimeDescriptorArray && + desc.descriptorBindingPartiallyBound && + desc.shaderSampledImageArrayNonUniformIndexing && + desc.descriptorBindingSampledImageUpdateAfterBind) { adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } + + // check for bindless storage buffers + if (desc.shaderStorageBufferArrayNonUniformIndexing && + desc.descriptorBindingStorageBufferUpdateAfterBind) { + vkAdapter->bindlessStorageBuffers = true; + } + + // check for bindless uniform buffers + if (desc.shaderUniformBufferArrayNonUniformIndexing && + desc.descriptorBindingUniformBufferUpdateAfterBind) { + vkAdapter->bindlessUniformBuffers = true; + } } // timeline semaphore is part of core 1.2 @@ -3151,9 +3171,7 @@ PalResult PAL_CALL createVkDevice( s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueCount, nullptr); queueProps = palAllocate(s_Vk.allocator, sizeof(VkQueueFamilyProperties) * queueCount, 0); - queueCreateInfos = palAllocate(s_Vk.allocator, sizeof(VkDeviceQueueCreateInfo) * queueCount, 0); - device = palAllocate(s_Vk.allocator, sizeof(Device), 0); if (!queueProps || !queueCreateInfos || !device) { return PAL_RESULT_OUT_OF_MEMORY; @@ -3164,13 +3182,11 @@ PalResult PAL_CALL createVkDevice( device->phyDevice = phyDevice; device->phyQueues = palAllocate(s_Vk.allocator, sizeof(PhysicalQueue) * queueCount, 0); - if (!device->phyQueues) { return PAL_RESULT_OUT_OF_MEMORY; } s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueCount, queueProps); - for (int i = 0; i < queueCount; i++) { queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfos[i].pNext = nullptr; @@ -3357,9 +3373,25 @@ PalResult PAL_CALL createVkDevice( if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_EXT_descriptor_indexing"; } + + descIndex.runtimeDescriptorArray = true; + descIndex.descriptorBindingPartiallyBound = true; descIndex.shaderSampledImageArrayNonUniformIndexing = true; + descIndex.descriptorBindingSampledImageUpdateAfterBind = true; features12.descriptorIndexing = true; + if (vkAdapter->bindlessStorageBuffers) { + descIndex.shaderStorageBufferArrayNonUniformIndexing = true; + descIndex.descriptorBindingStorageBufferUpdateAfterBind = true; + device->bindlessStorageBuffers = true; + } + + if (vkAdapter->bindlessUniformBuffers) { + descIndex.shaderUniformBufferArrayNonUniformIndexing = true; + descIndex.descriptorBindingUniformBufferUpdateAfterBind = true; + device->bindlessUniformBuffers = true; + } + descIndex.pNext = next; next = &descIndex; } @@ -4002,6 +4034,48 @@ PalResult PAL_CALL queryVkRayTracingCapabilities( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL queryVkDescriptorIndexingCapabilities( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps) +{ + Device* vkDevice = (Device*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + + VkPhysicalDeviceDescriptorIndexingPropertiesEXT props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT; + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + + caps->bindlessStorageBuffers = false; + caps->bindlessUniformBuffers = false; + if (vkDevice->bindlessStorageBuffers) { + caps->bindlessStorageBuffers = true; + } + + if (vkDevice->bindlessUniformBuffers) { + caps->bindlessUniformBuffers = true; + } + + caps->maxImagesPerShaderStage = props.maxPerStageDescriptorUpdateAfterBindSampledImages; + caps->maxImagesPerDescriptorSet = props.maxDescriptorSetUpdateAfterBindSampledImages; + + caps->maxStorageBuffersPerShaderStage = + props.maxPerStageDescriptorUpdateAfterBindStorageBuffers; + caps->maxStorageBuffersPerDescriptorSet = props.maxDescriptorSetUpdateAfterBindStorageBuffers; + + caps->maxUniformBuffersPerShaderStage = + props.maxPerStageDescriptorUpdateAfterBindUniformBuffers; + caps->maxUniformBuffersPerDescriptorSet = props.maxDescriptorSetUpdateAfterBindUniformBuffers; + + caps->maxDescriptors = props.maxUpdateAfterBindDescriptorsInAllPools; + return PAL_RESULT_SUCCESS; +} + // ================================================== // Queue // ================================================== diff --git a/tests/compute_test.c b/tests/compute_test.c index 036550ff..dc05f833 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -446,8 +446,6 @@ bool computeTest() return false; } - palLog(nullptr, "%d", sizeof(PushConstant)); - result = palPushConstants( cmdBuffer, pipelineLayout, From 8a8dd82a820e2c389e2426d6df11f46497d06094 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 2 Feb 2026 10:19:03 +0000 Subject: [PATCH 088/372] add ray tracing pipeline creation and deletion --- include/pal/pal_graphics.h | 37 ++- src/graphics/pal_graphics.c | 32 +++ src/graphics/pal_vulkan.c | 509 ++++++++++++++++++++++++++++++++++-- tests/tests_main.c | 4 +- 4 files changed, 553 insertions(+), 29 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 56ff7010..bf8d4be4 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -564,6 +564,12 @@ typedef enum { PAL_DESCRIPTOR_TYPE_SAMPLER } PalDescriptorType; +typedef enum { + PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL, + PAL_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT, + PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT +} PalRayTracingShaderGroupType; + typedef struct { Uint32 vendorId; Uint32 deviceId; @@ -634,10 +640,6 @@ typedef struct { Uint32 maxGeometryCount; Uint32 maxPayloadSize; Uint32 maxDispatchInvocations; - Uint32 maxShaderGroupStride; - Uint32 shaderGroupHandleSize; - Uint32 shaderGroupHandleAlignment; - Uint32 shaderGroupBaseAlignment; } PalRayTracingCapabilities; typedef struct { @@ -1046,6 +1048,23 @@ typedef struct { PalShader* computeShader; } PalComputePipelineCreateInfo; +typedef struct { + PalRayTracingShaderGroupType type; + Uint32 anyHitShaderIndex; + Uint32 closestHitShaderIndex; + Uint32 generalShaderIndex; + Uint32 intersectionShaderIndex; +} PalRayTracingShaderGroupCreateInfo; + +typedef struct { + Uint32 shaderCount; + Uint32 shaderGroupCount; + Uint32 maxRecursionDepth; + PalPipelineLayout* pipelineLayout; + PalRayTracingShaderGroupCreateInfo* shaderGroups; + PalShader** shaders; +} PalRayTracingPipelineCreateInfo; + typedef struct { PalResult PAL_CALL (*enumerateAdapters)( Int32* count, @@ -1499,6 +1518,11 @@ typedef struct { const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline); + PalResult PAL_CALL (*createRayTracingPipeline)( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + void PAL_CALL (*destroyPipeline)(PalPipeline* pipeline); } PalGraphicsBackend; @@ -1962,6 +1986,11 @@ PAL_API PalResult PAL_CALL palCreateComputePipeline( const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline); +PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); PAL_API bool PAL_CALL palBuildWorkGroupInfo( diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 1e579b7e..e2649374 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -557,6 +557,11 @@ PalResult PAL_CALL createVkComputePipeline( const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline); +PalResult PAL_CALL createVkRayTracingPipeline( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + void PAL_CALL destroyVkPipeline(PalPipeline* pipeline); static PalGraphicsBackend s_VkBackend = { @@ -663,6 +668,7 @@ static PalGraphicsBackend s_VkBackend = { .destroyPipelineLayout = destroyVkPipelineLayout, .createGraphicsPipeline = createVkGraphicsPipeline, .createComputePipeline = createVkComputePipeline, + .createRayTracingPipeline = createVkRayTracingPipeline, .destroyPipeline = destroyVkPipeline}; #endif // PAL_HAS_VULKAN @@ -802,6 +808,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroyPipelineLayout || !backend->createGraphicsPipeline || !backend->createComputePipeline || + !backend->createRayTracingPipeline || !backend->destroyPipeline) { return PAL_RESULT_INVALID_BACKEND; } @@ -2654,6 +2661,31 @@ PalResult PAL_CALL palCreateComputePipeline( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL palCreateRayTracingPipeline( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outPipeline) { + return PAL_RESULT_NULL_POINTER; + } + + PalResult result; + PalPipeline* pipeline = nullptr; + result = device->backend->createRayTracingPipeline(device, info, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + pipeline->backend = device->backend; + *outPipeline = pipeline; + return PAL_RESULT_SUCCESS; +} + void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) { if (s_Graphics.initialized && pipeline) { diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index d8a3caf9..350b105c 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -117,6 +117,7 @@ typedef struct { PFN_vkCreateDevice createDevice; PFN_vkDestroyDevice destroyDevice; PFN_vkGetDeviceQueue getDeviceQueue; + PFN_vkQueueSubmit queueSubmit; PFN_vkGetDeviceProcAddr getDeviceProcAddr; PFN_vkCreateImage createImage; PFN_vkDestroyImage destroyImage; @@ -253,6 +254,7 @@ typedef struct { PFN_vkCmdTraceRaysKHR cmdTraceRays; PFN_vkCreateRayTracingPipelinesKHR createRayTracingPipeline; PFN_vkCmdTraceRaysIndirectKHR cmdTraceRaysIndirect; + PFN_vkGetRayTracingShaderGroupHandlesKHR getRayTracingShaderGroupHandles; // dynamic rendering PFN_vkCmdBeginRendering cmdBeginRendering; @@ -320,6 +322,7 @@ typedef struct { const PalGraphicsBackend* backend; bool primary; + bool hasTraceRays; VkPipelineStageFlagBits2 dstStage; Device* device; CommandPool* pool; @@ -393,12 +396,34 @@ typedef struct { VkPipelineLayout handle; } PipelineLayout; +typedef struct { + Uint32 raygenOffset; + Uint32 missOffset; + Uint32 hitOffset; + Uint32 callableOffset; + + Uint32 raygenStride; + Uint32 missStride; + Uint32 hitStride; + Uint32 callableStride; + + VkBuffer buffer; + VkBuffer stagingBuffer; + VkDeviceMemory bufferMemory; + VkDeviceMemory stagingBufferMemory; + VkDeviceAddress baseAddress; + VkSemaphore semaphore; + VkCommandPool pool; + VkCommandBuffer cmdBuffer; +} ShaderBindingTable; + typedef struct { const PalGraphicsBackend* backend; VkPipelineBindPoint bindPoint; Device* device; VkPipeline handle; + ShaderBindingTable* sbt; } Pipeline; typedef struct { @@ -1590,7 +1615,8 @@ static Barrier barrierToVk(PalUsageState state, switch (state) { case PAL_USAGE_STATE_UNDEFINED: { barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1599,6 +1625,7 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_PRESENT: { barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.dstStages = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; + barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; return barrier; @@ -1607,6 +1634,7 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_COLOR_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; return barrier; @@ -1615,6 +1643,7 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; return barrier; @@ -1623,6 +1652,7 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; return barrier; @@ -1631,6 +1661,7 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; return barrier; @@ -1639,6 +1670,7 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; return barrier; @@ -1647,6 +1679,7 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; return barrier; @@ -1655,6 +1688,7 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; @@ -1663,7 +1697,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_TRANSFER_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1671,7 +1706,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_TRANSFER_READ: { barrier.stages = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1679,7 +1715,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_VERTEX_READ: { barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR; - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1687,7 +1724,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_INDEX_READ: { barrier.stages = VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR; - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_INDEX_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1695,7 +1733,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_UNIFORM_READ: { barrier.stages = stageToVkPipelineStage(shaderStage); - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_UNIFORM_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1703,7 +1742,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_SHADER_READ: { barrier.stages = stageToVkPipelineStage(shaderStage); - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1711,7 +1751,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_SHADER_WRITE: { barrier.stages = stageToVkPipelineStage(shaderStage); - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1719,7 +1760,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_STORAGE_READ: { barrier.stages = stageToVkPipelineStage(shaderStage); - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1727,7 +1769,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_STORAGE_WRITE: { barrier.stages = stageToVkPipelineStage(shaderStage); - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1735,7 +1778,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_HOST_READ: { barrier.stages = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_HOST_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1743,7 +1787,8 @@ static Barrier barrierToVk(PalUsageState state, case PAL_USAGE_STATE_HOST_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; - barrier.dstStages = barrier.dstStages; + barrier.dstStages = barrier.stages; + barrier.access = VK_ACCESS_2_HOST_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1752,6 +1797,7 @@ static Barrier barrierToVk(PalUsageState state, barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; barrier.dstStages = barrier.stages; + barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -1940,6 +1986,11 @@ static Uint32 getMemoryTypeScore( return score; } +static inline Uint32 align(Uint32 value, Uint32 alignment) +{ + return (value + alignment - 1) & ~(alignment - 1); +} + // ================================================== // Adapter // ================================================== @@ -2057,6 +2108,10 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkGetDeviceQueue"); + s_Vk.queueSubmit = (PFN_vkQueueSubmit)dlsym( + s_Vk.handle, + "vkQueueSubmit"); + s_Vk.getDeviceProcAddr = (PFN_vkGetDeviceProcAddr)dlsym( s_Vk.handle, "vkGetDeviceProcAddr"); @@ -2965,6 +3020,7 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); if (desc.runtimeDescriptorArray && desc.descriptorBindingPartiallyBound && + desc.descriptorBindingVariableDescriptorCount && desc.shaderSampledImageArrayNonUniformIndexing && desc.descriptorBindingSampledImageUpdateAfterBind) { adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; @@ -3378,6 +3434,7 @@ PalResult PAL_CALL createVkDevice( descIndex.descriptorBindingPartiallyBound = true; descIndex.shaderSampledImageArrayNonUniformIndexing = true; descIndex.descriptorBindingSampledImageUpdateAfterBind = true; + descIndex.descriptorBindingVariableDescriptorCount = true; features12.descriptorIndexing = true; if (vkAdapter->bindlessStorageBuffers) { @@ -3652,6 +3709,11 @@ PalResult PAL_CALL createVkDevice( (PFN_vkCmdTraceRaysIndirectKHR)s_Vk.getDeviceProcAddr( device->handle, "vkCmdTraceRaysIndirectKHR"); + + device->getRayTracingShaderGroupHandles = + (PFN_vkGetRayTracingShaderGroupHandlesKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetRayTracingShaderGroupHandlesKHR"); } // buffer address procs @@ -4026,11 +4088,6 @@ PalResult PAL_CALL queryVkRayTracingCapabilities( caps->maxPayloadSize = INT32_MAX; // depends on memory caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; - caps->maxShaderGroupStride = props.maxShaderGroupStride; - caps->shaderGroupHandleSize = props.shaderGroupHandleSize; - caps->shaderGroupHandleAlignment = props.shaderGroupHandleAlignment; - caps->shaderGroupBaseAlignment = props.shaderGroupBaseAlignment; - return PAL_RESULT_SUCCESS; } @@ -5296,6 +5353,7 @@ PalResult PAL_CALL allocateVkCommandBuffer( cmdBuffer->device = vkDevice; cmdBuffer->pool = vkPool; + cmdBuffer->hasTraceRays = false; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; @@ -5380,6 +5438,7 @@ PalResult PAL_CALL resetVkCommandBuffer(PalCommandBuffer* cmdBuffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); + vkCmdBuffer->hasTraceRays = false; return PAL_RESULT_SUCCESS; } @@ -6691,6 +6750,7 @@ PalResult PAL_CALL createVkDescriptorSetLayout( VkResult result; Device* vkDevice = (Device*)device; VkDescriptorSetLayoutBinding* bindings = nullptr; + VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlags = {0}; DescriptorSetLayout* layout = nullptr; layout = palAllocate(s_Vk.allocator, sizeof(DescriptorSetLayout), 0); @@ -6722,6 +6782,16 @@ PalResult PAL_CALL createVkDescriptorSetLayout( } } + if (vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + bindingFlags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; + bindingFlags.bindingCount = info->bindingCount; + VkDescriptorBindingFlags flags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; + flags |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT; + flags |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; + bindingFlags.pBindingFlags = &flags; + createInfo.pNext = &bindingFlags; + } + result = s_Vk.createDescriptorSetLayout( vkDevice->handle, &createInfo, @@ -6769,7 +6839,6 @@ PalResult PAL_CALL createVkDescriptorPool( for (int i = 0; i < info->maxDescriptorBindingSizes; i++) { VkDescriptorPoolSize* poolSize = &poolSizes[i]; - poolSize->descriptorCount = info->bindingSizes[i].bindingCount; poolSize->type = descriptortypeToVk(info->bindingSizes[i].descriptorType); } @@ -6779,6 +6848,7 @@ PalResult PAL_CALL createVkDescriptorPool( createInfo.maxSets = info->maxDescriptorSets; createInfo.poolSizeCount = info->maxDescriptorBindingSizes; createInfo.pPoolSizes = poolSizes; + createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; result = s_Vk.createDescriptorPool( vkDevice->handle, @@ -6857,12 +6927,22 @@ PalResult PAL_CALL updateVkDescriptorSet( VkWriteDescriptorSet* writes = nullptr; VkDescriptorBufferInfo* bufferInfos = nullptr; VkDescriptorImageInfo* imageInfos = nullptr; + Uint32 bufferCount = 0; + Uint32 imageCount = 0; - writes = palAllocate(s_Vk.allocator, sizeof(VkWriteDescriptorSet) * count, 0); + for (int i = 0; i < count; i++) { + if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || + infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + bufferCount++; - // FIXME: loop through to find the buffers from the images - bufferInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBufferInfo) * count, 0); - imageInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorImageInfo) * count, 0); + } else { + imageCount++; + } + } + + writes = palAllocate(s_Vk.allocator, sizeof(VkWriteDescriptorSet) * count, 0); + bufferInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBufferInfo) * bufferCount, 0); + imageInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorImageInfo) * imageCount, 0); if (!writes || !bufferInfos || !imageInfos) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7024,7 +7104,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( Device* vkDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - VkPipelineShaderStageCreateInfo shaderStages[7]; // PAL supports 7 types + VkPipelineShaderStageCreateInfo shaderStages[7]; // 7 shader types for graphics pipeline VkDynamicState dynamicStates[16]; VkVertexInputBindingDescription* bindingDescs = nullptr; VkVertexInputAttributeDescription* attribDescs = nullptr; @@ -7441,6 +7521,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( pipeline->device = vkDevice; pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + pipeline->sbt = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -7480,6 +7561,372 @@ PalResult PAL_CALL createVkComputePipeline( pipeline->device = vkDevice; pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; + pipeline->sbt = nullptr; + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL createVkRayTracingPipeline( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + VkResult result; + Device* vkDevice = (Device*)device; + PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; + Pipeline* pipeline = nullptr; + VkPipelineShaderStageCreateInfo shaderStages[6]; // 6 shader types for ray tracing pipeline + VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; + ShaderBindingTable* sbt = nullptr; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkRayTracingPipelineCreateInfoKHR createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; + + pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); + sbt = palAllocate(s_Vk.allocator, sizeof(ShaderBindingTable), 0); + groups = palAllocate( + s_Vk.allocator, + sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount, + 0); + + if (!pipeline || !groups || !sbt) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount); + memset(groups, 0, sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount); + memset(sbt, 0, sizeof(ShaderBindingTable)); + + // shaders + for (int i = 0; i < info->shaderCount; i++) { + Shader* tmp = (Shader*)info->shaders[i]; + shaderStages[i] = tmp->info; + } + + // shader groups + Uint32 numRaygen = 0; + Uint32 numMiss = 0; + Uint32 numHit = 0; + Uint32 numCallable = 0; + for (int i = 0; i < info->shaderGroupCount; i++) { + VkRayTracingShaderGroupCreateInfoKHR* group = &groups[i]; + group->sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + if (info->shaderGroups[i].type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + + // check which general shader it is + Shader* tmp = (Shader*)info->shaders[info->shaderGroups[i].generalShaderIndex]; + if (tmp->info.stage == VK_SHADER_STAGE_CALLABLE_BIT_KHR) { + numCallable++; + + } else if (tmp->info.stage == VK_SHADER_STAGE_MISS_BIT_KHR) { + numMiss++; + + } else { + numRaygen++; + } + + } else if (info->shaderGroups[i].type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + numHit++; + + } else { + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; + numHit++; + } + + group->anyHitShader = info->shaderGroups[i].anyHitShaderIndex; + group->closestHitShader = info->shaderGroups[i].closestHitShaderIndex; + group->generalShader= info->shaderGroups[i].generalShaderIndex; + group->intersectionShader = info->shaderGroups[i].intersectionShaderIndex; + } + + createInfo.stageCount = info->shaderCount; + createInfo.pStages = shaderStages; + createInfo.pGroups = groups; + createInfo.groupCount = info->shaderGroupCount; + createInfo.maxPipelineRayRecursionDepth = info->maxRecursionDepth; + + result = vkDevice->createRayTracingPipeline( + vkDevice->handle, + nullptr, + nullptr, + 1, + &createInfo, + &s_Vk.vkAllocator, + &pipeline->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, groups); + return vkResultToPal(result); + } + palFree(s_Vk.allocator, groups); + + // create SBT and dispatch buffer + VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayProps = {0}; + rayProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; + + VkPhysicalDeviceProperties2KHR props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; + props.pNext = &rayProps; + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &props); + + Uint32 groupHandleSize = rayProps.shaderGroupHandleSize; + Uint32 groupHandleAlignment = rayProps.shaderGroupHandleAlignment; + Uint32 groupBaseAlignment = rayProps.shaderGroupBaseAlignment; + Uint32 stride = align(groupHandleSize, groupHandleAlignment); + + // get region size + Uint32 raygenRegionSize = stride * numRaygen; + Uint32 missRegionSize = stride * numMiss; + Uint32 hitRegionSize = stride * numHit; + Uint32 callableRegionSize = stride * numCallable; + + // get offsets + Uint32 raygenOffset = 0; // always 0 + Uint32 missOffset = align(raygenRegionSize, groupBaseAlignment); + Uint32 hitOffset = align(missOffset + missRegionSize, groupBaseAlignment); + Uint32 callableOffset = align(hitOffset + hitRegionSize, groupBaseAlignment); + Uint32 bufferSize = callableOffset + callableRegionSize; + + // create gpu buffer + VkBufferCreateInfo bufCreateInfo = {0}; + bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufCreateInfo.size = bufferSize; + bufCreateInfo.usage = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR; + bufCreateInfo.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; + bufCreateInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + + // allocate GPU only memory and bind + VkMemoryRequirements memReq = {0}; + s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->buffer, &memReq); + + VkMemoryAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = memReq.size; + allocateInfo.memoryTypeIndex = vkDevice->gpuOnlyMemoryIndex; + + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &sbt->bufferMemory); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); + + // create staging buffer + bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufCreateInfo.size = bufferSize; + bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + result = s_Vk.createBuffer( + vkDevice->handle, + &bufCreateInfo, + &s_Vk.vkAllocator, + &sbt->stagingBuffer); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + + s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->stagingBuffer, &memReq); + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = memReq.size; + allocateInfo.memoryTypeIndex = vkDevice->cpuUploadMemoryIndex; + + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &sbt->stagingBufferMemory); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->stagingBufferMemory, 0); + + // get shader handles + Uint32 totalGroups = numRaygen + numHit + numMiss + numCallable; + Uint8* handles = palAllocate(s_Vk.allocator, totalGroups * groupHandleSize, 0); + if (!handles) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return PAL_RESULT_OUT_OF_MEMORY; + } + + result = vkDevice->getRayTracingShaderGroupHandles( + vkDevice->handle, + pipeline->handle, + 0, totalGroups, + totalGroups * groupHandleSize, + handles); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + + // copy handles into the GPU buffer + // we need a one time submit command buffer to do this operation + Uint32 index = 0; + void* ptr = nullptr; + result = s_Vk.mapMemory(vkDevice->handle, sbt->stagingBufferMemory, 0, memReq.size, 0, ptr); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + + // raygen + for (int i = 0; i < numRaygen; i++) { + memcpy( + ptr + raygenOffset + i * stride, + handles + index * groupHandleSize, + groupHandleSize); + + index++; + } + + // miss + for (int i = 0; i < numMiss; i++) { + memcpy( + ptr + raygenOffset + i * stride, + handles + index * groupHandleSize, + groupHandleSize); + + index++; + } + + // hit + for (int i = 0; i < numHit; i++) { + memcpy( + ptr + hitOffset + i * stride, + handles + index * groupHandleSize, + groupHandleSize); + + index++; + } + + // callable + for (int i = 0; i < numCallable; i++) { + memcpy( + ptr + callableOffset + i * stride, + handles + index * groupHandleSize, + groupHandleSize); + + index++; + } + s_Vk.unmapMemory(vkDevice->handle, sbt->bufferMemory); + + // copy to the GPU buffer + VkCommandPoolCreateInfo poolCreateInfo = {0}; + poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + + // technically, every queue type (compute, graphics, etc) will support + // buffer copy operation. So we use the first physical queue + poolCreateInfo.queueFamilyIndex = vkDevice->phyQueues[0].familyIndex; + result = s_Vk.createCommandPool( + vkDevice->handle, + &poolCreateInfo, + &s_Vk.vkAllocator, + &sbt->pool); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + + VkCommandBufferAllocateInfo cmdAllocateInfo = {0}; + cmdAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdAllocateInfo.commandBufferCount = 1; + cmdAllocateInfo.commandPool = sbt->pool; + cmdAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + result = s_Vk.allocateCommandBuffer(vkDevice->handle, &cmdAllocateInfo, &sbt->cmdBuffer); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + + // make copy + VkCommandBufferBeginInfo cmdBeginInfo = {0}; + cmdBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + result = s_Vk.cmdBegin(sbt->cmdBuffer, &cmdBeginInfo); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + + VkBufferCopy copyRegion = {0}; + copyRegion.size = bufferSize; + s_Vk.cmdCopyBuffer(sbt->cmdBuffer, sbt->stagingBuffer, sbt->buffer, 1, ©Region); + + result = s_Vk.cmdEnd(sbt->cmdBuffer); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + + // create a signal semaphore so we dont block until GPU finishes + VkSemaphoreCreateInfo semaphoreCreateInfo = {0}; + semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + result = s_Vk.createSemaphore( + vkDevice->handle, + &semaphoreCreateInfo, + &s_Vk.vkAllocator, + &sbt->semaphore); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + + VkSubmitInfo submitInfo = {0}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &sbt->cmdBuffer; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &sbt->semaphore; + + result = s_Vk.queueSubmit(vkDevice->phyQueues[0].handle, 1, &submitInfo, VK_NULL_HANDLE); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + palFree(s_Vk.allocator, sbt); + return vkResultToPal(result); + } + + palFree(s_Vk.allocator, handles); + pipeline->device = vkDevice; + pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -7489,6 +7936,22 @@ void PAL_CALL destroyVkPipeline(PalPipeline* pipeline) Pipeline* vkPipeline = (Pipeline*)pipeline; s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); + if (vkPipeline->sbt) { + VkDevice device = vkPipeline->device->handle; + ShaderBindingTable* sbt = vkPipeline->sbt; + + s_Vk.freeCommandBuffer(device, sbt->pool, 1, &sbt->cmdBuffer); + s_Vk.destroyCommandPool(device, sbt->pool, &s_Vk.vkAllocator); + s_Vk.destroySemaphore(device, sbt->semaphore, &s_Vk.vkAllocator); + + s_Vk.destroyBuffer(device, sbt->buffer, &s_Vk.vkAllocator); + s_Vk.freeMemory(device, sbt->bufferMemory, &s_Vk.vkAllocator); + s_Vk.destroyBuffer(device, sbt->stagingBuffer, &s_Vk.vkAllocator); + s_Vk.freeMemory(device, sbt->stagingBufferMemory, &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, vkPipeline->sbt); + } + palFree(s_Vk.allocator, pipeline); } diff --git a/tests/tests_main.c b/tests/tests_main.c index 8498128f..4237a23b 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,12 +58,12 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest); - registerTest(computeTest); + // registerTest(computeTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest); - // registerTest(triangleTest); + registerTest(triangleTest); // registerTest(meshTest); #endif // From 48dff3841ef78e09af34a6d24dfea4abf9105b92 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 2 Feb 2026 14:46:11 +0000 Subject: [PATCH 089/372] fix vulkan adapter struct ordering and add ray initial ray tracing test --- src/graphics/pal_graphics.c | 4 +- src/graphics/pal_vulkan.c | 5 +- tests/compute_test.c | 2 +- tests/ray_tracing_test.c | 286 ++++++++++++++++++++++++++++++++++ tests/shaders/closest_hit.spv | Bin 0 -> 216 bytes tests/shaders/miss.spv | Bin 0 -> 216 bytes tests/shaders/raygen.spv | Bin 0 -> 2040 bytes tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 3 +- 10 files changed, 296 insertions(+), 8 deletions(-) create mode 100644 tests/ray_tracing_test.c create mode 100644 tests/shaders/closest_hit.spv create mode 100644 tests/shaders/miss.spv create mode 100644 tests/shaders/raygen.spv diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index e2649374..41ab0c16 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -906,8 +906,8 @@ PalResult PAL_CALL palEnumerateAdapters( PalAdapter** adapters = &outAdapters[backend->startIndex]; result = backend->base->enumerateAdapters(&_count, adapters); - for (int i = 0; i < _count; i++) { - adapters[i]->backend = backend->base; + for (int j = 0; j < _count; j++) { + adapters[j]->backend = backend->base; } } else { diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 350b105c..488f4259 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -70,10 +70,11 @@ typedef int (*wl_display_get_fd_fn)(struct wl_display*); #define COMPUTE_PIPELINE 127 typedef struct { + const PalGraphicsBackend* backend; + // For descriptor Indexing bool bindlessStorageBuffers; bool bindlessUniformBuffers; - const PalGraphicsBackend* backend; VkPhysicalDevice handle; } Adapter; @@ -2595,7 +2596,6 @@ PalResult PAL_CALL enumerateVkAdapters( VkPhysicalDeviceProperties props = {0}; result = s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, nullptr); - if (result != VK_SUCCESS) { return PAL_RESULT_PLATFORM_FAILURE; } @@ -2606,7 +2606,6 @@ PalResult PAL_CALL enumerateVkAdapters( VkPhysicalDevice* devices = nullptr; devices = palAllocate(s_Vk.allocator, sizeof(VkPhysicalDevice) * deviceCount, 0); - s_Vk.adapters = palAllocate(s_Vk.allocator, sizeof(Adapter) * deviceCount, 0); if (!devices || !s_Vk.adapters) { diff --git a/tests/compute_test.c b/tests/compute_test.c index dc05f833..05dde829 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -165,7 +165,7 @@ bool computeTest() return false; } - // create a graphics command queue + // create a compute command queue result = palCreateQueue(device, PAL_QUEUE_TYPE_COMPUTE, &queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c new file mode 100644 index 00000000..0ef97c5e --- /dev/null +++ b/tests/ray_tracing_test.c @@ -0,0 +1,286 @@ + +#include "pal/pal_graphics.h" +#include "tests.h" + +#include + +#define BUFFER_SIZE 400 + +static bool readFile( + const char* filename, + void* buffer, + Uint64* size) +{ + FILE* file = fopen(filename, "rb"); + if (!file) { + return false; + } + + fseek(file, 0, SEEK_END); + Uint64 tmpSize = ftell(file); + fseek(file, 0, SEEK_SET); + + if (buffer) { + fread(buffer, 1, (size_t)size, file); + } + + fclose(file); + *size = tmpSize; + return true; +} + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) +{ + palLog(nullptr, msg); +} + +bool rayTracingTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Ray Tracing Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalQueue* queue = nullptr; + PalCommandPool* cmdPool = nullptr; + PalCommandBuffer* cmdBuffer; + + PalShader* raygenShader = nullptr; + PalShader* missShader = nullptr; + PalShader* closestHitShader = nullptr; + + PalGraphicsDebugger debugger; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; + + PalResult result = palInitGraphics(nullptr, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (adapterCount == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", adapterCount); + + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&adapterCount, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + PalAdapterCapabilities caps; + PalAdapterFeatures adapterFeatures = 0; + bool hasGraphicsQueue = false; + for (Int32 i = 0; i < adapterCount; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + // Ray tracing is generally implemented on the graphics queue + if (caps.maxGraphicsQueues == 0) { + continue; + + } else { + hasGraphicsQueue = true; + adapterFeatures = palGetAdapterFeatures(adapter); + if (adapterFeatures & PAL_ADAPTER_FEATURE_RAY_TRACING) { + break; + } + } + } + + palFree(nullptr, adapters); + if (!adapter) { + if (hasGraphicsQueue) { + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); + + } else { + palLog(nullptr, "Failed to find an adapter that supports ray tracing"); + } + return false; + } + + PalAdapterInfo adapterInfo = {0}; + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // create a device + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_RAY_TRACING; + result = palCreateDevice(adapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a graphics command queue + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + result = palCreateCommandPool(device, queue, &cmdPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + result = palAllocateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffer); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate command buffer: %s", error); + return false; + } + + // create a raygen shader + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + PalShaderCreateInfo shaderCreateInfo = {0}; + const char* shaderPath = nullptr; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + shaderPath = "shaders/raygen.spv"; + } + + if (!readFile(shaderPath, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to find shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(shaderPath, bytecode, &bytecodeSize); + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_RAYGEN; + + result = palCreateShader(device, &shaderCreateInfo, &raygenShader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create raygen shader: %s", error); + return false; + } + palFree(nullptr, bytecode); + + // create a miss shader + bytecodeSize = 0; + bytecode = nullptr; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + shaderPath = "shaders/miss.spv"; + } + + if (!readFile(shaderPath, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to find shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(shaderPath, bytecode, &bytecodeSize); + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_MISS; + + result = palCreateShader(device, &shaderCreateInfo, &missShader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create miss shader: %s", error); + return false; + } + palFree(nullptr, bytecode); + + // create a closest hit shader + bytecodeSize = 0; + bytecode = nullptr; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + shaderPath = "shaders/closest_hit.spv"; + } + + if (!readFile(shaderPath, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to find shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(shaderPath, bytecode, &bytecodeSize); + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_CLOSEST_HIT; + + result = palCreateShader(device, &shaderCreateInfo, &closestHitShader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create closest hit shader: %s", error); + return false; + } + palFree(nullptr, bytecode); + + palDestroyShader(raygenShader); + palDestroyShader(missShader); + palDestroyShader(closestHitShader); + + palFreeCommandBuffer(cmdBuffer); + palDestroyCommandPool(cmdPool); + palDestroyQueue(queue); + palDestroyDevice(device); + + palShutdownGraphics(); + return true; +} diff --git a/tests/shaders/closest_hit.spv b/tests/shaders/closest_hit.spv new file mode 100644 index 0000000000000000000000000000000000000000..2947099b66cce3ea06bad4c95a8673abccecddee GIT binary patch literal 216 zcmZQ(Qf6mhWn|!H;9y{5fB-=TCWd-J1_mymNN_+{ythYCd{JU$d`VGaa%NsSP%Rq+ zBT%WkPq2?(aY>4viKzidCm#bd*Z`0mKLabn5fKIk79cw}F*6S&!3=~7?&0SnL! ycb|CIh!7N`fx1{w^aulWfb=MWbu)n3W4viKzidCm#bd*Z`0mKLabnQ4t0P79cw}F*6S&!3=~7?&0SnL! ycb|CIh!7N`fx1{w^aulWfb=MWbu)n3WtBohqGqw6W+P2Vwv{bH?`<5HCeFKC2X08jlq=0+tsrRWnggo)%=~~^5PHZza zj^+4k#eYSdr(UUCy*@ShUz<>1C!1d&r-PhlSb-et%`aBV(<}9vg`3yNm(PU_@Xr%X zJ}^RfTAOVwB)C24|2L;ndoh<}nU@dS&@9Z=<`)`Gyc1lj&(1ab<->k(eRgIFm*{(& z_))|+2=1*kmR87bLm_r8)t=2QE;ncM?5-01oL~FQkYc}$_)Chf6SrZWr^LCe=QkVA z)OIG9`PS}9&_BE{#a(2Y+e001$#^q4)-PhNBDfu|$!`U(N@H`}UyX0Ue8>eu4klaKp6t%QsDo?FcpChNf$6Uzr@cNRHw^+zz)XvD`7_-dq^6P+QB{9wX| z5zlaq*j(SzZhH7#<@ONYz>A%=gm-p1XA}EP<@{DR@kOi!vyb=|=8ApGO&EHa+#Yu@ zIp>VtUU$LPRTH%nsYYGYp5?B+D`$6k4?kcEcxUwcbYS|3eJ@$ebNUba&a?Zz^N9WC zzNswkP4O6Az0Y-+ckcX`n8CYUkI7$VLgx`j{U&1d-h0${5zDK0UUAfKA@)sV>u&|i ztM@$OsNYVkK3jhWSYEy7702GYi0v8iZenY`;e4KD52i*wYW5O)u2-q1NUToY9)80j z7WD^+)kl1g*dFiF{6oZQ~n%Rd$vBX z=Z}3)604Dqefx>!W8YK6a@oG8!Sb=MZ$i$#&N_g}ePB+1hi6mH-(l38BX-`1hltJj znC6@(RwMsDYOY}SG3PRNF5lK|%(pTIx{JSujbpbk_qhb**8oSmOb4wnhaUYq)0(xd|*=!&<-j?=^(|0TTv^=l}o! literal 0 HcmV?d00001 diff --git a/tests/tests.h b/tests/tests.h index 73c3c2ff..95a51daf 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -53,6 +53,7 @@ bool multiThreadOpenGlTest(); // graphics bool graphicsTest(); bool computeTest(); +bool rayTracingTest(); // graphics and video bool clearColorTest(); diff --git a/tests/tests.lua b/tests/tests.lua index 0d0cbd1e..21d313fa 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -66,7 +66,8 @@ project "tests" if (PAL_BUILD_GRAPHICS) then files { "graphics_test.c", - "compute_test.c" + "compute_test.c", + "ray_tracing_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 4237a23b..5153763e 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,11 +59,12 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest); // registerTest(computeTest); + registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest); - registerTest(triangleTest); + // registerTest(triangleTest); // registerTest(meshTest); #endif // From 03f4859cb215a4e7bb01e5b0eaa647970aca3f21 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 6 Feb 2026 11:59:12 +0000 Subject: [PATCH 090/372] fix graphics memory allocation bug on CPU drivers --- include/pal/pal_graphics.h | 24 ++ src/graphics/pal_graphics.c | 50 +++- src/graphics/pal_vulkan.c | 468 +++++++++++++++++++++--------------- tests/compute_test.c | 5 +- tests/ray_tracing_test.c | 376 ++++++++++++++++++++++++++++- tests/triangle_test.c | 8 +- 6 files changed, 729 insertions(+), 202 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index bf8d4be4..1382ac55 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -37,6 +37,7 @@ freely, subject to the following restrictions: #define PAL_ADAPTER_VERSION_SIZE 16 #define PAL_MAX_RESOLVE_MODES 8 #define PAL_MAX_COMBINER_OPS 8 +#define PAL_UNUSED_SHADER_INDEX UINT32_MAX typedef struct PalAdapter PalAdapter; typedef struct PalDevice PalDevice; @@ -731,6 +732,7 @@ typedef struct { bool memoryTypes[PAL_MEMORY_TYPE_MAX]; Uint64 size; Uint32 alignment; + Uint32 memoryMask; } PalMemoryRequirements; typedef struct { @@ -1092,6 +1094,7 @@ typedef struct { PalResult PAL_CALL (*allocateMemory)( PalDevice* device, PalMemoryType type, + Uint32 memoryMask, Uint64 size, PalMemory** outMemory); @@ -1426,6 +1429,16 @@ typedef struct { PalBuffer* buffer, Uint64 offset); + PalResult PAL_CALL (*traceRays)( + PalCommandBuffer* cmdBuffer, + Uint32 width, + Uint32 height, + Uint32 depth); + + PalResult PAL_CALL (*traceRaysIndirect)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer); + PalResult PAL_CALL (*bindDescriptorSet)( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, @@ -1560,6 +1573,7 @@ PAL_API PalResult PAL_CALL palWaitDevice(PalDevice* device); PAL_API PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, + Uint32 memoryMask, Uint64 size, PalMemory** outMemory); @@ -1894,6 +1908,16 @@ PAL_API PalResult PAL_CALL palDispatchIndirect( PalBuffer* buffer, Uint64 offset); +PAL_API PalResult PAL_CALL palTraceRays( + PalCommandBuffer* cmdBuffer, + Uint32 width, + Uint32 height, + Uint32 depth); + +PAL_API PalResult PAL_CALL palTraceRaysIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer); + PAL_API PalResult PAL_CALL palBindDescriptorSet( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 41ab0c16..45fdcca4 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -129,6 +129,7 @@ PalResult PAL_CALL waitVkDevice(PalDevice* device); PalResult PAL_CALL allocateVkMemory( PalDevice* device, PalMemoryType type, + Uint32 memoryMask, Uint64 size, PalMemory** outMemory); @@ -452,6 +453,16 @@ PalResult PAL_CALL dispatchIndirectVk( PalBuffer* buffer, Uint64 offset); +PalResult PAL_CALL traceRaysVk( + PalCommandBuffer* cmdBuffer, + Uint32 width, + Uint32 height, + Uint32 depth); + +PalResult PAL_CALL traceRaysIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer); + PalResult PAL_CALL bindVkDescriptorSet( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, @@ -647,6 +658,8 @@ static PalGraphicsBackend s_VkBackend = { .dispatch = dispatchVk, .dispatchBase = dispatchBaseVk, .dispatchIndirect = dispatchIndirectVk, + .traceRays = traceRaysVk, + .traceRaysIndirect = traceRaysIndirectVk, .bindDescriptorSet = bindVkDescriptorSet, .pushConstants = pushConstantsVk, .submitCommandBuffer = submitVkCommandBuffer, @@ -785,6 +798,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->dispatch || !backend->dispatchBase || !backend->dispatchIndirect || + !backend->traceRays || + !backend->traceRaysIndirect || !backend->bindDescriptorSet || !backend->pushConstants || !backend->submitCommandBuffer || @@ -1026,6 +1041,7 @@ PalResult PAL_CALL palWaitDevice(PalDevice* device) PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, + Uint32 memoryMask, Uint64 size, PalMemory** outMemory) { @@ -1037,7 +1053,7 @@ PalResult PAL_CALL palAllocateMemory( return PAL_RESULT_NULL_POINTER; } - return device->backend->allocateMemory(device, type, size, outMemory); + return device->backend->allocateMemory(device, type, memoryMask, size, outMemory); } void PAL_CALL palFreeMemory( @@ -2229,6 +2245,38 @@ PalResult PAL_CALL palDispatchIndirect( return cmdBuffer->backend->dispatchIndirect(cmdBuffer, buffer, offset); } +PalResult PAL_CALL palTraceRays( + PalCommandBuffer* cmdBuffer, + Uint32 width, + Uint32 height, + Uint32 depth) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->traceRays(cmdBuffer, width, height, depth); +} + +PalResult PAL_CALL palTraceRaysIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !buffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->traceRaysIndirect(cmdBuffer, buffer); +} + PalResult PAL_CALL palBindDescriptorSet( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 488f4259..357234dd 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -173,6 +173,7 @@ typedef struct { PFN_vkBindBufferMemory bindBufferMemory; PFN_vkMapMemory mapMemory; PFN_vkUnmapMemory unmapMemory; + PFN_vkGetBufferDeviceAddress getBufferDeviceAddress; PFN_vkCreateDescriptorSetLayout createDescriptorSetLayout; PFN_vkDestroyDescriptorSetLayout destroyDescriptorSetLayout; @@ -212,12 +213,12 @@ typedef struct { bool bindlessUniformBuffers; PalAdapterFeatures features; Int32 queueCount; - Int32 gpuOnlyMemoryIndex; - Int32 cpuUploadMemoryIndex; - Int32 cpuReadbackMemoryIndex; + Uint32 memoryClassMask[3]; VkPhysicalDevice phyDevice; VkDevice handle; PhysicalQueue* phyQueues; + VkCommandPool cmdPool; + VkCommandBuffer cmdBuffer; PFN_vkGetBufferDeviceAddress getBufferrAddress; PFN_vkCmdDispatchBase cmdDispatchBase; @@ -319,11 +320,25 @@ typedef struct { VkCommandPool handle; } CommandPool; +typedef struct { + VkBuffer buffer; + VkBuffer stagingBuffer; + VkDeviceMemory bufferMemory; + VkDeviceMemory stagingBufferMemory; + VkDeviceAddress baseAddress; + VkSemaphore semaphore; + + VkStridedDeviceAddressRegionKHR raygenAddress; + VkStridedDeviceAddressRegionKHR missAddress; + VkStridedDeviceAddressRegionKHR hitAddress; + VkStridedDeviceAddressRegionKHR callableAddress; +} ShaderBindingTable; + typedef struct { const PalGraphicsBackend* backend; bool primary; - bool hasTraceRays; + ShaderBindingTable* sbt; VkPipelineStageFlagBits2 dstStage; Device* device; CommandPool* pool; @@ -397,27 +412,6 @@ typedef struct { VkPipelineLayout handle; } PipelineLayout; -typedef struct { - Uint32 raygenOffset; - Uint32 missOffset; - Uint32 hitOffset; - Uint32 callableOffset; - - Uint32 raygenStride; - Uint32 missStride; - Uint32 hitStride; - Uint32 callableStride; - - VkBuffer buffer; - VkBuffer stagingBuffer; - VkDeviceMemory bufferMemory; - VkDeviceMemory stagingBufferMemory; - VkDeviceAddress baseAddress; - VkSemaphore semaphore; - VkCommandPool pool; - VkCommandBuffer cmdBuffer; -} ShaderBindingTable; - typedef struct { const PalGraphicsBackend* backend; @@ -1958,33 +1952,47 @@ VkBool32 debugCallback( return VK_FALSE; } -static Uint32 getMemoryTypeScore( - VkMemoryPropertyFlags flags, - VkMemoryPropertyFlags required, - VkMemoryPropertyFlags preferred, - VkMemoryPropertyFlags excluded) +static Uint32 findBestMemoryIndex( + VkPhysicalDevice phyDevice, + Uint32 memoryMask) { - // hard constraint - if ((flags & required) != required) { - return 0; - } + int bestScore = -1; + Uint32 bestIndex = UINT32_MAX; + VkPhysicalDeviceMemoryProperties memProps = {0}; + s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); - // hard constraint - if ((flags & excluded) != 0) { - return 0; - } + for (int i = 0; i < memProps.memoryTypeCount; i++) { + if (!(memoryMask & (1u << i))) { + continue; + } - int score = 0; - if (flags & preferred) { - score += 10; - } + int score = 0; + VkMemoryPropertyFlags flags = memProps.memoryTypes[i].propertyFlags; + + // GPU only memory + if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + score += 100; + } - // GPU memory is general preferred - if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { - score += 5; + // CPU memory + if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { + score += 50; + } + + if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { + score += 25; + } + + if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + score += 10; + } + + if (score > bestScore) { + bestIndex = i; + } } - return score; + return bestIndex; } static inline Uint32 align(Uint32 value, Uint32 alignment) @@ -2269,6 +2277,10 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkUnmapMemory"); + s_Vk.getBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)dlsym( + s_Vk.handle, + "vkGetBufferDeviceAddress"); + s_Vk.getBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)dlsym( s_Vk.handle, "vkGetBufferMemoryRequirements"); @@ -3228,6 +3240,7 @@ PalResult PAL_CALL createVkDevice( queueProps = palAllocate(s_Vk.allocator, sizeof(VkQueueFamilyProperties) * queueCount, 0); queueCreateInfos = palAllocate(s_Vk.allocator, sizeof(VkDeviceQueueCreateInfo) * queueCount, 0); device = palAllocate(s_Vk.allocator, sizeof(Device), 0); + if (!queueProps || !queueCreateInfos || !device) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3380,12 +3393,21 @@ PalResult PAL_CALL createVkDevice( if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; extensions[extCount++] = "VK_KHR_acceleration_structure"; + extensions[extCount++] = "VK_KHR_deferred_host_operations"; ray.rayTracingPipeline = true; acc.accelerationStructure = true; + // ray tracing needs buffer address feature enabled + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_buffer_device_address"; + } + bufferAddress.bufferDeviceAddress = true; + features12.bufferDeviceAddress = true; + ray.pNext = next; acc.pNext = &ray; - next = &acc; + bufferAddress.pNext = &acc; + next = &bufferAddress; } if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { @@ -3540,55 +3562,34 @@ PalResult PAL_CALL createVkDevice( // cache memory type indices VkPhysicalDeviceMemoryProperties memProps = {0}; s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); - device->gpuOnlyMemoryIndex = -1; - device->cpuUploadMemoryIndex = -1; - device->cpuReadbackMemoryIndex = -1; - - Uint32 gpuBestScore = 0; - Uint32 cpuUploadBestScore = 0; - Uint32 cpuReadbackBestScore = 0; + memset(device->memoryClassMask, 0, sizeof(Uint32) * 3); for (int i = 0; i < memProps.memoryTypeCount; i++) { VkMemoryPropertyFlags flags = memProps.memoryTypes[i].propertyFlags; - Uint32 score = 0; - - // GPU memory - score = getMemoryTypeScore( - flags, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - 0, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - if (score > gpuBestScore) { - gpuBestScore = score; - device->gpuOnlyMemoryIndex = i; + Uint32 bit = (1u << i); + if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) && + !(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] |= bit; } - // CPU upload - score = getMemoryTypeScore( - flags, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, - VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - 0); - - if (score > cpuUploadBestScore) { - cpuUploadBestScore = score; - device->cpuUploadMemoryIndex = i; + if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] |= bit; } - // CPU readback - score = getMemoryTypeScore( - flags, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT, - 0, - 0); - - if (score > cpuReadbackBestScore) { - cpuReadbackBestScore = score; - device->cpuReadbackMemoryIndex = i; + if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)) { + device->memoryClassMask[PAL_MEMORY_TYPE_CPU_READBACK] |= bit; } } + // HACK: most CPU drivers dont have a vram so we set the vram to system memory + if (device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] == 0) { + device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] = + device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD]; + } + // clang-format off // swapchain procs if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { @@ -3713,6 +3714,36 @@ PalResult PAL_CALL createVkDevice( (PFN_vkGetRayTracingShaderGroupHandlesKHR)s_Vk.getDeviceProcAddr( device->handle, "vkGetRayTracingShaderGroupHandlesKHR"); + + // create a temporary command pool and buffer to be used with ray tracing pipeline + // copy to the GPU buffer + VkCommandPoolCreateInfo poolCreateInfo = {0}; + poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + + // technically, every queue type (compute, graphics, etc) will support + // buffer copy operation. So we use the first physical queue + poolCreateInfo.queueFamilyIndex = device->phyQueues[0].familyIndex; + result = s_Vk.createCommandPool( + device->handle, + &poolCreateInfo, + &s_Vk.vkAllocator, + &device->cmdPool); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, device); + return vkResultToPal(result); + } + + VkCommandBufferAllocateInfo cmdAllocateInfo = {0}; + cmdAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdAllocateInfo.commandBufferCount = 1; + cmdAllocateInfo.commandPool = device->cmdPool; + cmdAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + result = s_Vk.allocateCommandBuffer(device->handle, &cmdAllocateInfo, &device->cmdBuffer); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, device); + return vkResultToPal(result); + } } // buffer address procs @@ -3825,6 +3856,11 @@ PalResult PAL_CALL createVkDevice( void PAL_CALL destroyVkDevice(PalDevice* device) { Device* vkDevice = (Device*)device; + if (vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + s_Vk.freeCommandBuffer(vkDevice->handle, vkDevice->cmdPool, 1, &vkDevice->cmdBuffer); + s_Vk.destroyCommandPool(vkDevice->handle, vkDevice->cmdPool, &s_Vk.vkAllocator); + } + s_Vk.destroyDevice(vkDevice->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkDevice->phyQueues); palFree(s_Vk.allocator, vkDevice); @@ -3848,33 +3884,36 @@ PalResult PAL_CALL waitVkDevice(PalDevice* device) PalResult PAL_CALL allocateVkMemory( PalDevice* device, PalMemoryType type, + Uint32 memoryMask, Uint64 size, PalMemory** outMemory) { + VkResult result; + VkDeviceMemory memory = nullptr; + Device* vkDevice = (Device*)device; VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = (VkDeviceSize)size; - if (type == PAL_MEMORY_TYPE_GPU_ONLY) { - allocateInfo.memoryTypeIndex = vkDevice->gpuOnlyMemoryIndex; - - } else if (type == PAL_MEMORY_TYPE_CPU_UPLOAD) { - allocateInfo.memoryTypeIndex = vkDevice->cpuUploadMemoryIndex; - - } else if (type == PAL_MEMORY_TYPE_CPU_READBACK) { - allocateInfo.memoryTypeIndex = vkDevice->cpuReadbackMemoryIndex; + Uint32 memoryClassMask = vkDevice->memoryClassMask[type] & memoryMask; + if (memoryClassMask == 0) { + return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; } - if (allocateInfo.memoryTypeIndex == -1) { - // not supported + // pick an index using the scoring system + Uint32 memoryIndex = findBestMemoryIndex(vkDevice->phyDevice, memoryMask); + if (memoryIndex == UINT32_MAX) { return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; } - VkDeviceMemory memory = nullptr; - VkResult result = - s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &memory); + // check if the memory index is valid + if (!(memoryMask & (1u << memoryIndex))) { + return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; + } + allocateInfo.memoryTypeIndex = memoryIndex; + result = s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &memory); if (result != VK_SUCCESS) { return vkResultToPal(result); } @@ -4483,40 +4522,20 @@ PalResult PAL_CALL getVkImageMemoryRequirements( } Device* device = vkImage->device; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)device->phyDevice; - VkPhysicalDeviceMemoryProperties memProps = {0}; - s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); - VkMemoryRequirements memReq = {0}; s_Vk.getImageMemoryRequirements(device->handle, vkImage->handle, &memReq); requirements->alignment = (Uint64)memReq.alignment; requirements->size = (Uint64)memReq.size; + requirements->memoryMask = memReq.memoryTypeBits; requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = false; - for (int i = 0; i < memProps.memoryTypeCount; i++) { - if (!(memReq.memoryTypeBits & (1 << i))) { - // memory type not supported - continue; - } - - VkMemoryPropertyFlags prop = memProps.memoryTypes[i].propertyFlags; - if (prop & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; - } - - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; - } - - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; - } + for (int i = 0; i < PAL_MEMORY_TYPE_MAX; i++) { + requirements->memoryTypes[i] = (memReq.memoryTypeBits & device->memoryClassMask[i]) != 0; } + return PAL_RESULT_SUCCESS; } @@ -5352,7 +5371,7 @@ PalResult PAL_CALL allocateVkCommandBuffer( cmdBuffer->device = vkDevice; cmdBuffer->pool = vkPool; - cmdBuffer->hasTraceRays = false; + cmdBuffer->sbt = nullptr; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; @@ -5437,7 +5456,7 @@ PalResult PAL_CALL resetVkCommandBuffer(PalCommandBuffer* cmdBuffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); - vkCmdBuffer->hasTraceRays = false; + vkCmdBuffer->sbt = nullptr; return PAL_RESULT_SUCCESS; } @@ -5918,6 +5937,11 @@ PalResult PAL_CALL bindVkPipeline( CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* vkPipeline = (Pipeline*)pipeline; s_Vk.cmdBindPipeline(vkCmdBuffer->handle, vkPipeline->bindPoint, vkPipeline->handle); + + if (vkPipeline->bindPoint == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) { + vkCmdBuffer->sbt = vkPipeline->sbt; + } + return PAL_RESULT_SUCCESS; } @@ -6287,6 +6311,77 @@ PalResult PAL_CALL dispatchIndirectVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL traceRaysVk( + PalCommandBuffer* cmdBuffer, + Uint32 width, + Uint32 height, + Uint32 depth) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + ShaderBindingTable* sbt = vkCmdBuffer->sbt; + if (!sbt) { + return PAL_RESULT_INVALID_OPERATION; + } + + vkCmdBuffer->device->cmdTraceRays( + vkCmdBuffer->handle, + &sbt->raygenAddress, + &sbt->missAddress, + &sbt->hitAddress, + &sbt->callableAddress, + width, + height, + depth); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL traceRaysIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* vkBuffer = (Buffer*)buffer; + + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + ShaderBindingTable* sbt = vkCmdBuffer->sbt; + if (!sbt) { + return PAL_RESULT_INVALID_OPERATION; + } + + VkStridedDeviceAddressRegionKHR* miss = nullptr; + VkStridedDeviceAddressRegionKHR* hit = nullptr; + VkStridedDeviceAddressRegionKHR* callable = nullptr; + if (sbt->missAddress.size == 0) { + miss = &sbt->missAddress; + } + + if (sbt->hitAddress.size == 0) { + hit = &sbt->hitAddress; + } + + if (sbt->callableAddress.size == 0) { + callable = &sbt->callableAddress; + } + + vkCmdBuffer->device->cmdTraceRaysIndirect( + vkCmdBuffer->handle, + &sbt->raygenAddress, + miss, + hit, + callable, + vkBuffer->address); + + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL bindVkDescriptorSet( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, @@ -6392,6 +6487,10 @@ PalResult PAL_CALL submitVkCommandBuffer( signalSubmitInfo.value = info->signalValue; } + if (vkCmdBuffer->sbt) { + vkCmdBuffer->dstStage |= VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; + } + VkSubmitInfo2KHR submitInfo = {0}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR; submitInfo.commandBufferInfoCount = 1; @@ -6683,41 +6782,21 @@ PalResult PAL_CALL getVkBufferMemoryRequirements( { Buffer* vkBuffer = (Buffer*)buffer; Device* device = vkBuffer->device; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)device->phyDevice; - VkPhysicalDeviceMemoryProperties memProps = {0}; - s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); - VkMemoryRequirements memReq = {0}; s_Vk.getBufferMemoryRequirements(device->handle, vkBuffer->handle, &memReq); requirements->alignment = (Uint64)memReq.alignment; requirements->size = (Uint64)memReq.size; + requirements->memoryMask = memReq.memoryTypeBits; requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = false; - for (int i = 0; i < memProps.memoryTypeCount; i++) { - if (!(memReq.memoryTypeBits & (1 << i))) { - // memory type not supported - continue; - } - - VkMemoryPropertyFlags prop = memProps.memoryTypes[i].propertyFlags; - if (prop & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; - } - - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; - } - - if ((prop & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - prop & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; - } + for (int i = 0; i < PAL_MEMORY_TYPE_MAX; i++) { + requirements->memoryTypes[i] = (memReq.memoryTypeBits & device->memoryClassMask[i]) != 0; } + return PAL_RESULT_SUCCESS; } @@ -7649,6 +7728,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( createInfo.pGroups = groups; createInfo.groupCount = info->shaderGroupCount; createInfo.maxPipelineRayRecursionDepth = info->maxRecursionDepth; + createInfo.layout = layout->handle; result = vkDevice->createRayTracingPipeline( vkDevice->handle, @@ -7666,7 +7746,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( } palFree(s_Vk.allocator, groups); - // create SBT and dispatch buffer + // create SBT buffer VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayProps = {0}; rayProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; @@ -7716,7 +7796,14 @@ PalResult PAL_CALL createVkRayTracingPipeline( VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memReq.size; - allocateInfo.memoryTypeIndex = vkDevice->gpuOnlyMemoryIndex; + + Uint32 memoryIndex = findBestMemoryIndex(vkDevice->phyDevice, memReq.memoryTypeBits); + allocateInfo.memoryTypeIndex = memoryIndex; + + VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; + allocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + allocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + allocateInfo.pNext = &allocateFlagsInfo; result = s_Vk.allocateMemory( vkDevice->handle, @@ -7752,7 +7839,9 @@ PalResult PAL_CALL createVkRayTracingPipeline( s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->stagingBuffer, &memReq); allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memReq.size; - allocateInfo.memoryTypeIndex = vkDevice->cpuUploadMemoryIndex; + + memoryIndex = findBestMemoryIndex(vkDevice->phyDevice, memReq.memoryTypeBits); + allocateInfo.memoryTypeIndex = memoryIndex; result = s_Vk.allocateMemory( vkDevice->handle, @@ -7765,7 +7854,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( palFree(s_Vk.allocator, sbt); return vkResultToPal(result); } - s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->stagingBufferMemory, 0); + s_Vk.bindBufferMemory(vkDevice->handle, sbt->stagingBuffer, sbt->stagingBufferMemory, 0); // get shader handles Uint32 totalGroups = numRaygen + numHit + numMiss + numCallable; @@ -7793,7 +7882,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( // we need a one time submit command buffer to do this operation Uint32 index = 0; void* ptr = nullptr; - result = s_Vk.mapMemory(vkDevice->handle, sbt->stagingBufferMemory, 0, memReq.size, 0, ptr); + result = s_Vk.mapMemory(vkDevice->handle, sbt->stagingBufferMemory, 0, memReq.size, 0, &ptr); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); @@ -7839,43 +7928,12 @@ PalResult PAL_CALL createVkRayTracingPipeline( index++; } - s_Vk.unmapMemory(vkDevice->handle, sbt->bufferMemory); - - // copy to the GPU buffer - VkCommandPoolCreateInfo poolCreateInfo = {0}; - poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - - // technically, every queue type (compute, graphics, etc) will support - // buffer copy operation. So we use the first physical queue - poolCreateInfo.queueFamilyIndex = vkDevice->phyQueues[0].familyIndex; - result = s_Vk.createCommandPool( - vkDevice->handle, - &poolCreateInfo, - &s_Vk.vkAllocator, - &sbt->pool); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); - } - - VkCommandBufferAllocateInfo cmdAllocateInfo = {0}; - cmdAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - cmdAllocateInfo.commandBufferCount = 1; - cmdAllocateInfo.commandPool = sbt->pool; - cmdAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - result = s_Vk.allocateCommandBuffer(vkDevice->handle, &cmdAllocateInfo, &sbt->cmdBuffer); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); - } + s_Vk.unmapMemory(vkDevice->handle, sbt->stagingBufferMemory); - // make copy + // copy CPU buffer to GPU buffer VkCommandBufferBeginInfo cmdBeginInfo = {0}; cmdBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - result = s_Vk.cmdBegin(sbt->cmdBuffer, &cmdBeginInfo); + result = s_Vk.cmdBegin(vkDevice->cmdBuffer, &cmdBeginInfo); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); @@ -7884,9 +7942,9 @@ PalResult PAL_CALL createVkRayTracingPipeline( VkBufferCopy copyRegion = {0}; copyRegion.size = bufferSize; - s_Vk.cmdCopyBuffer(sbt->cmdBuffer, sbt->stagingBuffer, sbt->buffer, 1, ©Region); + s_Vk.cmdCopyBuffer(vkDevice->cmdBuffer, sbt->stagingBuffer, sbt->buffer, 1, ©Region); - result = s_Vk.cmdEnd(sbt->cmdBuffer); + result = s_Vk.cmdEnd(vkDevice->cmdBuffer); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); @@ -7912,7 +7970,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( VkSubmitInfo submitInfo = {0}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &sbt->cmdBuffer; + submitInfo.pCommandBuffers = &vkDevice->cmdBuffer; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = &sbt->semaphore; @@ -7923,8 +7981,35 @@ PalResult PAL_CALL createVkRayTracingPipeline( return vkResultToPal(result); } + // cache SBT fields and offsets address + VkBufferDeviceAddressInfo bufferAddressInfo = {0}; + bufferAddressInfo.buffer = sbt->buffer; + bufferAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; + sbt->baseAddress = s_Vk.getBufferDeviceAddress(vkDevice->handle, &bufferAddressInfo); + + // raygen + sbt->raygenAddress.deviceAddress = sbt->baseAddress + raygenOffset; + sbt->raygenAddress.size = raygenRegionSize; + sbt->raygenAddress.stride = stride; + + // miss + sbt->missAddress.deviceAddress = sbt->baseAddress + missOffset; + sbt->missAddress.size = missRegionSize; + sbt->missAddress.stride = stride; + + // hit + sbt->hitAddress.deviceAddress = sbt->baseAddress + hitOffset; + sbt->hitAddress.size = hitRegionSize; + sbt->hitAddress.stride = stride; + + // callable + sbt->callableAddress.deviceAddress = sbt->baseAddress + callableOffset; + sbt->callableAddress.size = callableRegionSize; + sbt->callableAddress.stride = stride; + palFree(s_Vk.allocator, handles); pipeline->device = vkDevice; + pipeline->sbt = sbt; pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -7939,10 +8024,7 @@ void PAL_CALL destroyVkPipeline(PalPipeline* pipeline) VkDevice device = vkPipeline->device->handle; ShaderBindingTable* sbt = vkPipeline->sbt; - s_Vk.freeCommandBuffer(device, sbt->pool, 1, &sbt->cmdBuffer); - s_Vk.destroyCommandPool(device, sbt->pool, &s_Vk.vkAllocator); s_Vk.destroySemaphore(device, sbt->semaphore, &s_Vk.vkAllocator); - s_Vk.destroyBuffer(device, sbt->buffer, &s_Vk.vkAllocator); s_Vk.freeMemory(device, sbt->bufferMemory, &s_Vk.vkAllocator); s_Vk.destroyBuffer(device, sbt->stagingBuffer, &s_Vk.vkAllocator); diff --git a/tests/compute_test.c b/tests/compute_test.c index 05dde829..aad7ddcb 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -68,7 +68,7 @@ bool computeTest() PalDescriptorSetLayout* descriptorSetLayout = nullptr; PalDescriptorPool* descriptorPool = nullptr; PalDescriptorSet* descriptorSet = nullptr; - PalPipelineLayout* pipelineLayout; + PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; PalFence* fence = nullptr; @@ -272,6 +272,7 @@ bool computeTest() result = palAllocateMemory( device, PAL_MEMORY_TYPE_GPU_ONLY, + bufferMemReq.memoryMask, bufferMemReq.size, &bufferMemory); @@ -284,6 +285,7 @@ bool computeTest() result = palAllocateMemory( device, PAL_MEMORY_TYPE_CPU_READBACK, + stagingBufferMemReq.memoryMask, stagingBufferMemReq.size, &stagingBufferMemory); @@ -629,7 +631,6 @@ bool computeTest() } fclose(file); - palUnmapMemory(device, stagingBufferMemory); palDestroyPipeline(pipeline); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 0ef97c5e..8e46ad05 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -55,12 +55,23 @@ bool rayTracingTest() PalShader* raygenShader = nullptr; PalShader* missShader = nullptr; PalShader* closestHitShader = nullptr; + PalBuffer* buffer = nullptr; + PalBuffer* stagingBuffer = nullptr; + PalMemory* bufferMemory = nullptr; + PalMemory* stagingBufferMemory = nullptr; + + PalDescriptorSetLayout* descriptorSetLayout = nullptr; + PalDescriptorPool* descriptorPool = nullptr; + PalDescriptorSet* descriptorSet = nullptr; + PalPipelineLayout* pipelineLayout = nullptr; + PalPipeline* pipeline = nullptr; + PalFence* fence = nullptr; PalGraphicsDebugger debugger; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -272,6 +283,369 @@ bool rayTracingTest() } palFree(nullptr, bytecode); + Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader + PalBufferCreateInfo bufferCreateInfo = {0}; + bufferCreateInfo.size = bufferBytes; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE | PAL_BUFFER_USAGE_TRANSFER_SRC; + + result = palCreateBuffer(device, &bufferCreateInfo, &buffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create buffer: %s", error); + return false; + } + + bufferCreateInfo.size = bufferBytes; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_DST; + + result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create staging buffer: %s", error); + return false; + } + + // get buffer memory requirement and allocate memory + PalMemoryRequirements bufferMemReq = {0}; + PalMemoryRequirements stagingBufferMemReq = {0}; + + result = palGetBufferMemoryRequirements(buffer, &bufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + // we need to check if the memory type we want are supported + // but almost every GPU supports a GPU only memory + // and CPU writable memory + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + bufferMemReq.memoryMask, + bufferMemReq.size, + &bufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_READBACK, + stagingBufferMemReq.memoryMask, + stagingBufferMemReq.size, + &stagingBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + // bind memory + result = palBindBufferMemory(buffer, bufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + // create descriptor set layout + PalDescriptorSetLayoutBinding descriptorBinding = {0}; + PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_RAYGEN }; + + descriptorBinding.binding = 0; + descriptorBinding.descriptorCount = 1; // not an array + descriptorBinding.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorBinding.shaderStageCount = 1; + descriptorBinding.shaderStages = shaderStages; + + PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; + descriptorSetLayoutcreateInfo.bindingCount = 1; + descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; + + result = palCreateDescriptorSetLayout( + device, + &descriptorSetLayoutcreateInfo, + &descriptorSetLayout); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor set layout: %s", error); + return false; + } + + // create descriptor pool + PalDescriptorPoolBindingSize storageBufferBindingsize = {0}; + storageBufferBindingsize.bindingCount = 1; + storageBufferBindingsize.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + + PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; + descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set + descriptorPoolCreateInfo.maxDescriptorBindingSizes = 1; // one binding type + descriptorPoolCreateInfo.bindingSizes = &storageBufferBindingsize; + + result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor pool: %s", error); + return false; + } + + // allocate a single descriptor set from the descriptor pool + // using the layout we created above + result = palAllocateDescriptorSet(device, descriptorPool, descriptorSetLayout, &descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate descriptor set: %s", error); + return false; + } + + // write the inital data to the descriptor set since its created empty + PalDescriptorBufferInfo descriptorBufferInfo = {0}; + descriptorBufferInfo.buffer = buffer; + descriptorBufferInfo.offset = 0; + descriptorBufferInfo.size = bufferBytes; + + PalDescriptorSetWriteInfo writeInfo = {0}; + writeInfo.binding = 0; + writeInfo.bufferInfo = &descriptorBufferInfo; + writeInfo.descriptorSet = descriptorSet; + writeInfo.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + writeInfo.descriptorCount = 1; + + result = palUpdateDescriptorSet(device, 1, &writeInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to update descriptor set: %s", error); + return false; + } + + // create pipeline layout + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + pipelineLayoutCreateInfo.descriptorSetLayoutCount = 1; + pipelineLayoutCreateInfo.descriptorSetLayouts = &descriptorSetLayout; + + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline layout: %s", error); + return false; + } + + // shader and shader groups + PalShader* shaders[3]; + shaders[0] = raygenShader; + shaders[1] = missShader; + shaders[2] = closestHitShader; + + PalRayTracingShaderGroupCreateInfo shaderGroupCreateInfos[3] = {0}; + shaderGroupCreateInfos[0].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; + shaderGroupCreateInfos[0].generalShaderIndex = 0; // must match raygen index + shaderGroupCreateInfos[0].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[0].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[0].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + + shaderGroupCreateInfos[1].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; + shaderGroupCreateInfos[1].generalShaderIndex = 1; // must match miss index + shaderGroupCreateInfos[1].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[1].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[1].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + + shaderGroupCreateInfos[2].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT; + shaderGroupCreateInfos[2].closestHitShaderIndex = 2; // must match closest hit index + shaderGroupCreateInfos[2].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[2].generalShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[2].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + + // create a ray tracing pipeline + PalRayTracingPipelineCreateInfo pipelineCreateInfo = {0}; + pipelineCreateInfo.maxRecursionDepth = 1; + pipelineCreateInfo.pipelineLayout = pipelineLayout; + pipelineCreateInfo.shaderCount = 3; + pipelineCreateInfo.shaderGroupCount = 3; + pipelineCreateInfo.shaderGroups = shaderGroupCreateInfos; + pipelineCreateInfo.shaders = shaders; + + result = palCreateRayTracingPipeline(device, &pipelineCreateInfo, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create ray tracing pipeline: %s", error); + return false; + } + + // create fence + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + // record commands + result = palBeginCommandBuffer(cmdBuffer, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + result = palBindPipeline(cmdBuffer, pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + result = palBindDescriptorSet(cmdBuffer, pipeline, pipelineLayout, 0, descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind descriptor set: %s", error); + return false; + } + + // set a barrier on the buffer + PalUsageStateInfo oldUsageStateInfo = {0}; + oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; + + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_RAYGEN; + newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; + + result = palBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + result = palTraceRays(cmdBuffer, BUFFER_SIZE, BUFFER_SIZE, 1); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to trace rays: %s", error); + return false; + } + + // set a barrier so we only read from the buffer after the shader has + // written to it + oldUsageStateInfo = newUsageStateInfo; + newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; + + result = palBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // set a barrier on the staging buffer + oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; + oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + + newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + + result = palBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // now we copy from the GPU buffer into the staging buffer + result = palCopyBuffer(cmdBuffer, stagingBuffer, buffer, 0, 0, bufferBytes); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer: %s", error); + return false; + } + + result = palEndCommandBuffer(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // submit the command buffer to the GPU + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffer; + submitInfo.fence = fence; + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // wait for the fence + result = palWaitFence(fence, UINT64_MAX); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } + + // now our staging buffer has the contents of the GPU buffer + // we map it and copy the contents to a ppm buffer and save it + void* ptr = nullptr; + result = palMapMemory(device, stagingBufferMemory, 0, bufferBytes, &ptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map memory: %s", error); + return false; + } + + // write to a ppm output file + FILE* file = fopen("ray_tracing_output.ppm", "wb"); + fprintf(file, "P6\n%d %d\n255\n", BUFFER_SIZE, BUFFER_SIZE); + float* pixels = (float*)ptr; + for (int y = 0; y < BUFFER_SIZE; y++) { + int row = BUFFER_SIZE - 1 - y; // flip y + for (int x = 0; x < BUFFER_SIZE; x++) { + int index = row * BUFFER_SIZE + x; + Uint8 rgb[3]; + + rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; + rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; + rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255: 0; + fwrite(rgb, 1, 3, file); + } + } + + fclose(file); + palUnmapMemory(device, stagingBufferMemory); + + palDestroyFence(fence); + palDestroyPipeline(pipeline); + palDestroyPipelineLayout(pipelineLayout); + palDestroyDescriptorPool(descriptorPool); + palDestroyDescriptorSetLayout(descriptorSetLayout); + + palDestroyBuffer(buffer); + palDestroyBuffer(stagingBuffer); + palFreeMemory(device, bufferMemory); + palFreeMemory(device, stagingBufferMemory); + palDestroyShader(raygenShader); palDestroyShader(missShader); palDestroyShader(closestHitShader); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 01cf4d4b..0ea0e7a4 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -85,7 +85,6 @@ bool triangleTest() } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); result = palInitVideo(nullptr, eventDriver); @@ -353,7 +352,6 @@ bool triangleTest() bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create vertex buffer: %s", error); @@ -372,8 +370,8 @@ bool triangleTest() // get buffer memory requirement and allocate memory PalMemoryRequirements vertexBufferMemReq = {0}; PalMemoryRequirements stagingBufferMemReq = {0}; - result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); + result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); @@ -381,7 +379,6 @@ bool triangleTest() } result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); @@ -391,10 +388,10 @@ bool triangleTest() // we need to check if the memory type we want are supported // but almost every GPU supports a GPU only memory // and CPU writable memory - result = palAllocateMemory( device, PAL_MEMORY_TYPE_GPU_ONLY, + vertexBufferMemReq.memoryMask, vertexBufferMemReq.size, &vertexBufferMemory); @@ -407,6 +404,7 @@ bool triangleTest() result = palAllocateMemory( device, PAL_MEMORY_TYPE_CPU_UPLOAD, + stagingBufferMemReq.memoryMask, stagingBufferMemReq.size, &stagingBufferMemory); From a2b7d75388b1441599cbdc2d240bb6abc9e0fc7f Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 7 Feb 2026 14:14:21 +0000 Subject: [PATCH 091/372] optimize ray tracing pipeline creation --- include/pal/pal_graphics.h | 35 ++- src/graphics/pal_graphics.c | 34 ++- src/graphics/pal_vulkan.c | 543 +++++++++++++--------------------- tests/ray_tracing_test.c | 445 ++++++++++++++++++++++++++-- tests/shaders/closest_hit.spv | Bin 216 -> 372 bytes tests/shaders/miss.spv | Bin 216 -> 356 bytes tests/shaders/raygen.spv | Bin 2040 -> 2124 bytes 7 files changed, 677 insertions(+), 380 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 1382ac55..9dc885fb 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -66,6 +66,7 @@ typedef struct PalAccelerationStructure PalAccelerationStructure; typedef enum PalDebugMessageSeverity PalDebugMessageSeverity; typedef enum PalDebugMessageType PalDebugMessageType; +typedef Uint64 PalDeviceAddress; typedef void(PAL_CALL* PalDebugCallback)( void* userData, @@ -518,7 +519,7 @@ typedef enum { PAL_BUFFER_USAGE_STORAGE = PAL_BIT(3), PAL_BUFFER_USAGE_TRANSFER_SRC = PAL_BIT(4), PAL_BUFFER_USAGE_TRANSFER_DST = PAL_BIT(5), - PAL_BUFFER_USAGE_RAY_TRACING = PAL_BIT(6), + PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE = PAL_BIT(6), PAL_BUFFER_USAGE_DEVICE_ADDRESS = PAL_BIT(7) } PalBufferUsages; @@ -562,7 +563,8 @@ typedef enum { PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER, PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE, PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE, - PAL_DESCRIPTOR_TYPE_SAMPLER + PAL_DESCRIPTOR_TYPE_SAMPLER, + PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE } PalDescriptorType; typedef enum { @@ -730,9 +732,9 @@ typedef struct { typedef struct { bool memoryTypes[PAL_MEMORY_TYPE_MAX]; + Uint64 memoryMask; Uint64 size; Uint32 alignment; - Uint32 memoryMask; } PalMemoryRequirements; typedef struct { @@ -890,19 +892,19 @@ typedef struct { Uint32 vertexCount; Uint64 vertexOffset; Uint64 indexOffset; - PalBuffer* vertexBuffer; - PalBuffer* indexBuffer; + PalDeviceAddress vertexBufferAddress; + PalDeviceAddress indexBufferAddress; } PalGeometryDataTriangle; typedef struct { Uint32 stride; Uint64 offset; - PalBuffer* buffer; + PalDeviceAddress bufferAddress; } PalGeometryDataAABBS; typedef struct { Uint64 offset; - PalBuffer* buffer; + PalDeviceAddress bufferAddress; } PalGeometryDataInstance; typedef struct { @@ -916,7 +918,7 @@ typedef struct { Uint32 geometryCount; Uint64 scratchBufferOffset; PalAccelerationStructure* dst; - PalBuffer* scratchBuffer; + PalDeviceAddress scratchBufferAddress; PalGeometry* geometries; } PalAccelerationStructureBuildInfo; @@ -944,6 +946,10 @@ typedef struct { PalImageView* imageView; } PalDescriptorImageViewInfo; +typedef struct { + PalAccelerationStructure* tlas; +} PalDescriptorTLASInfo; + typedef struct { Uint32 binding; Uint32 arrayElement; @@ -952,6 +958,7 @@ typedef struct { PalDescriptorSet* descriptorSet; PalDescriptorBufferInfo* bufferInfo; PalDescriptorImageViewInfo* imageViewInfo; + PalDescriptorTLASInfo* tlasInfo; } PalDescriptorSetWriteInfo; typedef struct { @@ -1094,7 +1101,7 @@ typedef struct { PalResult PAL_CALL (*allocateMemory)( PalDevice* device, PalMemoryType type, - Uint32 memoryMask, + Uint64 memoryMask, Uint64 size, PalMemory** outMemory); @@ -1437,7 +1444,7 @@ typedef struct { PalResult PAL_CALL (*traceRaysIndirect)( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer); + PalDeviceAddress bufferAddress); PalResult PAL_CALL (*bindDescriptorSet)( PalCommandBuffer* cmdBuffer, @@ -1487,6 +1494,8 @@ typedef struct { PalMemory* memory, Uint64 offset); + PalDeviceAddress PAL_CALL (*getBufferDeviceAddress)(PalBuffer* buffer); + PalResult PAL_CALL (*createDescriptorSetLayout)( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, @@ -1573,7 +1582,7 @@ PAL_API PalResult PAL_CALL palWaitDevice(PalDevice* device); PAL_API PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, - Uint32 memoryMask, + Uint64 memoryMask, Uint64 size, PalMemory** outMemory); @@ -1916,7 +1925,7 @@ PAL_API PalResult PAL_CALL palTraceRays( PAL_API PalResult PAL_CALL palTraceRaysIndirect( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer); + PalDeviceAddress bufferAddress); PAL_API PalResult PAL_CALL palBindDescriptorSet( PalCommandBuffer* cmdBuffer, @@ -1966,6 +1975,8 @@ PAL_API PalResult PAL_CALL palBindBufferMemory( PalMemory* memory, Uint64 offset); +PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); + PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 45fdcca4..9ddfade3 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -129,7 +129,7 @@ PalResult PAL_CALL waitVkDevice(PalDevice* device); PalResult PAL_CALL allocateVkMemory( PalDevice* device, PalMemoryType type, - Uint32 memoryMask, + Uint64 memoryMask, Uint64 size, PalMemory** outMemory); @@ -461,7 +461,7 @@ PalResult PAL_CALL traceRaysVk( PalResult PAL_CALL traceRaysIndirectVk( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer); + PalDeviceAddress bufferAddress); PalResult PAL_CALL bindVkDescriptorSet( PalCommandBuffer* cmdBuffer, @@ -511,6 +511,8 @@ PalResult PAL_CALL bindVkBufferMemory( PalMemory* memory, Uint64 offset); +PalDeviceAddress PAL_CALL getVkBufferDeviceAddress(PalBuffer* buffer); + PalResult PAL_CALL mapVkMemory( PalDevice* device, PalMemory* memory, @@ -670,6 +672,7 @@ static PalGraphicsBackend s_VkBackend = { .destroyBuffer = destroyVkBuffer, .getBufferMemoryRequirements = getVkBufferMemoryRequirements, .bindBufferMemory = bindVkBufferMemory, + .getBufferDeviceAddress = getVkBufferDeviceAddress, .createDescriptorSetLayout = createVkDescriptorSetLayout, .destroyDescriptorSetLayout = destroyVkDescriptorSetLayout, .createDescriptorPool = createVkDescriptorPool, @@ -810,6 +813,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroyBuffer || !backend->getBufferMemoryRequirements || !backend->bindBufferMemory || + !backend->getBufferDeviceAddress || !backend->mapMemory || !backend->unmapMemory || !backend->createDescriptorSetLayout || @@ -1041,7 +1045,7 @@ PalResult PAL_CALL palWaitDevice(PalDevice* device) PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, - Uint32 memoryMask, + Uint64 memoryMask, Uint64 size, PalMemory** outMemory) { @@ -1890,7 +1894,7 @@ PalResult PAL_CALL palDrawMeshTasksIndirectCount( stride); } -PalResult PAL_CALL palBuildAccelerationStructures( +PalResult PAL_CALL palBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { @@ -1902,6 +1906,10 @@ PalResult PAL_CALL palBuildAccelerationStructures( return PAL_RESULT_NULL_POINTER; } + if (!info->dst || info->scratchBufferAddress == 0) { + return PAL_RESULT_NULL_POINTER; + } + return cmdBuffer->backend->buildAccelerationStructure(cmdBuffer, info); } @@ -2264,17 +2272,17 @@ PalResult PAL_CALL palTraceRays( PalResult PAL_CALL palTraceRaysIndirect( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer) + PalDeviceAddress bufferAddress) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !buffer) { + if (!cmdBuffer) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->traceRaysIndirect(cmdBuffer, buffer); + return cmdBuffer->backend->traceRaysIndirect(cmdBuffer, bufferAddress); } PalResult PAL_CALL palBindDescriptorSet( @@ -2391,10 +2399,6 @@ PalResult PAL_CALL palGetAccelerationStructureBuildSize( return PAL_RESULT_NULL_POINTER; } - if (!info->scratchBuffer || !info->dst) { - return PAL_RESULT_NULL_POINTER; - } - return device->backend->getAccelerationStructureBuildSize(device, info, size); } @@ -2494,6 +2498,14 @@ void PAL_CALL palUnmapMemory( device->backend->unmapMemory(device, memory); } +PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer) +{ + if (!s_Graphics.initialized || !buffer) { + return 0; + } + return buffer->backend->getBufferDeviceAddress(buffer); +} + // ================================================== // Descriptor Pool, Set and Layout // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 357234dd..8674ccd6 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -322,11 +322,8 @@ typedef struct { typedef struct { VkBuffer buffer; - VkBuffer stagingBuffer; VkDeviceMemory bufferMemory; - VkDeviceMemory stagingBufferMemory; VkDeviceAddress baseAddress; - VkSemaphore semaphore; VkStridedDeviceAddressRegionKHR raygenAddress; VkStridedDeviceAddressRegionKHR missAddress; @@ -338,11 +335,11 @@ typedef struct { const PalGraphicsBackend* backend; bool primary; - ShaderBindingTable* sbt; VkPipelineStageFlagBits2 dstStage; Device* device; CommandPool* pool; VkCommandBuffer handle; + ShaderBindingTable* sbt; } CommandBuffer; typedef struct { @@ -363,7 +360,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - VkDeviceAddress address; + PalBufferUsages usages; Device* device; VkBuffer handle; } Buffer; @@ -372,6 +369,9 @@ typedef struct { const PalGraphicsBackend* backend; VkDeviceAddress address; + VkBuffer buffer; + VkDeviceMemory bufferMemory; + VkDeviceAddress bufferAddress; Device* device; VkAccelerationStructureKHR handle; } AccelerationStructure; @@ -1325,9 +1325,10 @@ static VkBufferUsageFlags palBufferUsageToVk(PalBufferUsages usages) flags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; } - if (usages & PAL_BUFFER_USAGE_RAY_TRACING) { + if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR; } if (usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { @@ -1816,6 +1817,9 @@ static VkDescriptorType descriptortypeToVk(PalDescriptorType type) case PAL_DESCRIPTOR_TYPE_SAMPLER: return VK_DESCRIPTOR_TYPE_SAMPLER; + + case PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE: + return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; } return 0; @@ -2000,6 +2004,104 @@ static inline Uint32 align(Uint32 value, Uint32 alignment) return (value + alignment - 1) & ~(alignment - 1); } +static void fillVkBuildInfo( + PalAccelerationStructureBuildInfo* info, + Uint32* maxPrimities, + VkAccelerationStructureGeometryKHR* geometries, + VkAccelerationStructureKHR as, + VkAccelerationStructureBuildRangeInfoKHR* rangeInfos, + VkAccelerationStructureBuildGeometryInfoKHR* buildInfo) +{ + for (int i = 0; i < info->geometryCount; i++) { + if (maxPrimities) { + maxPrimities[i] = info->geometries[i].primitiveCount; + } + + // fill vulkan geometry struct + VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; + tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + tmp->flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + + if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { + tmp->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; + + VkDeviceOrHostAddressConstKHR vertexAddress = {0}; + VkDeviceOrHostAddressConstKHR indexAddress = {0}; + PalGeometryDataTriangle* tmpData = info->geometries[i].data; + + vertexAddress.deviceAddress = tmpData->vertexBufferAddress + tmpData->vertexOffset; + data->vertexData = vertexAddress; + data->maxVertex = tmpData->vertexCount; + data->vertexFormat = vertexTypeToVkFormat(tmpData->vertexType); + data->vertexStride = tmpData->vertexStride; + + indexAddress.deviceAddress = tmpData->indexBufferAddress + tmpData->indexOffset; + data->indexData = indexAddress; + if (tmpData->indexType == PAL_INDEX_TYPE_UINT32) { + data->indexType = VK_INDEX_TYPE_UINT32; + } else { + data->indexType = VK_INDEX_TYPE_UINT16; + } + + // set to none if there is no index buffer address + if (!tmpData->indexBufferAddress) { + data->indexType = VK_INDEX_TYPE_NONE_KHR; + } + + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { + tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; + VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; + + VkDeviceOrHostAddressConstKHR address = {0}; + PalGeometryDataAABBS* tmpData = info->geometries[i].data; + address.deviceAddress = tmpData->bufferAddress + tmpData->offset; + data->data = address; + data->stride = tmpData->stride; + + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_INSTANCE) { + tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; + data = &tmp->geometry.instances; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + data->arrayOfPointers = false; + + VkDeviceOrHostAddressConstKHR address = {0}; + PalGeometryDataInstance* tmpData = info->geometries[i].data; + address.deviceAddress = tmpData->bufferAddress + tmpData->offset; + data->data = address; + } + + // range info + if (rangeInfos) { + VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; + rangeInfo->primitiveCount = info->geometries[i].primitiveCount; + rangeInfo->firstVertex = 0; // PAL does not allow setting this + rangeInfo->primitiveOffset = 0; // PAL does not allow setting this + rangeInfo->transformOffset = 0; // PAL does not allow setting this + } + } + + buildInfo->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + buildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + } else { + buildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + } + + buildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + buildInfo->geometryCount = info->geometryCount; + buildInfo->dstAccelerationStructure = as; + buildInfo->flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; + buildInfo->pGeometries = geometries; + + VkDeviceOrHostAddressKHR scratchData = {0}; + scratchData.deviceAddress = info->scratchBufferAddress + info->scratchBufferOffset; + buildInfo->scratchData = scratchData; +} + // ================================================== // Adapter // ================================================== @@ -3537,7 +3639,6 @@ PalResult PAL_CALL createVkDevice( createInfo.pNext = next; result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.vkAllocator, &device->handle); - if (result != VK_SUCCESS) { palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); @@ -3546,6 +3647,7 @@ PalResult PAL_CALL createVkDevice( return vkResultToPal(result); } + device->features = features; // get queues for (int i = 0; i < queueCount; i++) { VkQueueFamilyProperties* data = &queueProps[i]; @@ -3715,6 +3817,19 @@ PalResult PAL_CALL createVkDevice( device->handle, "vkGetRayTracingShaderGroupHandlesKHR"); + device->getBufferrAddress = + (PFN_vkGetBufferDeviceAddress)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetBufferDeviceAddress"); + + if (!device->getBufferrAddress) { + device->getBufferrAddress = + (PFN_vkGetBufferDeviceAddressKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetBufferDeviceAddressKHR"); + } + device->features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; + // create a temporary command pool and buffer to be used with ray tracing pipeline // copy to the GPU buffer VkCommandPoolCreateInfo poolCreateInfo = {0}; @@ -3845,7 +3960,6 @@ PalResult PAL_CALL createVkDevice( } // clang-format on - device->features = features; palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); @@ -3884,35 +3998,44 @@ PalResult PAL_CALL waitVkDevice(PalDevice* device) PalResult PAL_CALL allocateVkMemory( PalDevice* device, PalMemoryType type, - Uint32 memoryMask, + Uint64 memoryMask, Uint64 size, PalMemory** outMemory) { VkResult result; VkDeviceMemory memory = nullptr; - Device* vkDevice = (Device*)device; VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = (VkDeviceSize)size; + VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; - Uint32 memoryClassMask = vkDevice->memoryClassMask[type] & memoryMask; + Uint32 memoryTypeMask = 0; + Uint32 usages = 0; + palUnpackUint32(memoryMask, &memoryTypeMask, &usages); + Uint32 memoryClassMask = vkDevice->memoryClassMask[type] & memoryTypeMask; if (memoryClassMask == 0) { return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; } // pick an index using the scoring system - Uint32 memoryIndex = findBestMemoryIndex(vkDevice->phyDevice, memoryMask); + Uint32 memoryIndex = findBestMemoryIndex(vkDevice->phyDevice, memoryClassMask); if (memoryIndex == UINT32_MAX) { return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; } // check if the memory index is valid - if (!(memoryMask & (1u << memoryIndex))) { + if (!(memoryClassMask & (1u << memoryIndex))) { return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; } allocateInfo.memoryTypeIndex = memoryIndex; + if (usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + allocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + allocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + allocateInfo.pNext = &allocateFlagsInfo; + } + result = s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &memory); if (result != VK_SUCCESS) { return vkResultToPal(result); @@ -4526,7 +4649,7 @@ PalResult PAL_CALL getVkImageMemoryRequirements( s_Vk.getImageMemoryRequirements(device->handle, vkImage->handle, &memReq); requirements->alignment = (Uint64)memReq.alignment; requirements->size = (Uint64)memReq.size; - requirements->memoryMask = memReq.memoryTypeBits; + requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, 0); requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; @@ -5119,7 +5242,6 @@ PalResult PAL_CALL waitVkFence( } VkResult result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, true, timeout); - if (result != VK_SUCCESS) { return vkResultToPal(result); } @@ -5596,7 +5718,7 @@ PalResult PAL_CALL buildVkAccelerationStructure( VkAccelerationStructureGeometryKHR* geometries = nullptr; VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; AccelerationStructure* as = (AccelerationStructure*)info->dst; - Buffer* scratchBuffer = (Buffer*)info->scratchBuffer; + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; geometries = palAllocate( s_Vk.allocator, @@ -5612,94 +5734,10 @@ PalResult PAL_CALL buildVkAccelerationStructure( return PAL_RESULT_OUT_OF_MEMORY; } - for (int i = 0; i < info->geometryCount; i++) { - // fill vulkan geometry struct - VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; - tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - tmp->flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - - if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { - tmp->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - - VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; - data->pNext = nullptr; - data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; - - VkDeviceOrHostAddressConstKHR vertexAddress = {0}; - VkDeviceOrHostAddressConstKHR indexAddress = {0}; - PalGeometryDataTriangle* tmpData = info->geometries[i].data; - Buffer* vkVertexBuffer = (Buffer*)tmpData->vertexBuffer; - Buffer* vkIndexBuffer = (Buffer*)tmpData->indexBuffer; - - vertexAddress.deviceAddress = vkVertexBuffer->address + tmpData->vertexOffset; - data->vertexData = vertexAddress; - data->maxVertex = tmpData->vertexCount; - data->vertexFormat = vertexTypeToVkFormat(tmpData->vertexType); - data->vertexStride = tmpData->vertexStride; - - indexAddress.deviceAddress = vkIndexBuffer->address + tmpData->indexOffset; - data->indexData = indexAddress; - if (tmpData->indexType == PAL_INDEX_TYPE_UINT32) { - data->indexType = VK_INDEX_TYPE_UINT32; - } else { - data->indexType = VK_INDEX_TYPE_UINT16; - } - - } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { - tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; - VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; - data->pNext = nullptr; - data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; - - VkDeviceOrHostAddressConstKHR address = {0}; - PalGeometryDataAABBS* tmpData = info->geometries[i].data; - Buffer* vkBuffer = (Buffer*)tmpData->buffer; - address.deviceAddress = vkBuffer->address + tmpData->offset; - data->data = address; - data->stride = tmpData->stride; - - } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_INSTANCE) { - tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; - data = &tmp->geometry.instances; - data->pNext = nullptr; - data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; - - VkDeviceOrHostAddressConstKHR address = {0}; - PalGeometryDataInstance* tmpData = info->geometries[i].data; - Buffer* vkBuffer = (Buffer*)tmpData->buffer; - address.deviceAddress = vkBuffer->address + tmpData->offset; - data->data = address; - } - - // range info - VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; - rangeInfo->primitiveCount = info->geometries[i].primitiveCount; - rangeInfo->firstVertex = 0; // PAL does not allow setting this - rangeInfo->primitiveOffset = 0; // PAL does not allow setting this - rangeInfo->transformOffset = 0; // PAL does not allow setting this - } - - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; - - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - } else { - buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - } - - buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - buildInfo.geometryCount = info->geometryCount; - buildInfo.dstAccelerationStructure = as->handle; - - VkDeviceOrHostAddressKHR scratchData = {0}; - scratchData.deviceAddress = scratchBuffer->address + info->scratchBufferOffset; - buildInfo.scratchData = scratchData; - - buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; - buildInfo.pGeometries = geometries; + memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount); + memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->geometryCount); + fillVkBuildInfo(info, nullptr, geometries, as->handle, rangeInfos, &buildInfo); const VkAccelerationStructureBuildRangeInfoKHR* tmp[1]; tmp[0] = rangeInfos; vkCmdBuffer->device->cmdBuildAccelerationStructures(vkCmdBuffer->handle, 1, &buildInfo, tmp); @@ -6342,11 +6380,9 @@ PalResult PAL_CALL traceRaysVk( PalResult PAL_CALL traceRaysIndirectVk( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer) + PalDeviceAddress bufferAddress) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* vkBuffer = (Buffer*)buffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6356,28 +6392,13 @@ PalResult PAL_CALL traceRaysIndirectVk( return PAL_RESULT_INVALID_OPERATION; } - VkStridedDeviceAddressRegionKHR* miss = nullptr; - VkStridedDeviceAddressRegionKHR* hit = nullptr; - VkStridedDeviceAddressRegionKHR* callable = nullptr; - if (sbt->missAddress.size == 0) { - miss = &sbt->missAddress; - } - - if (sbt->hitAddress.size == 0) { - hit = &sbt->hitAddress; - } - - if (sbt->callableAddress.size == 0) { - callable = &sbt->callableAddress; - } - vkCmdBuffer->device->cmdTraceRaysIndirect( vkCmdBuffer->handle, &sbt->raygenAddress, - miss, - hit, - callable, - vkBuffer->address); + &sbt->missAddress, + &sbt->hitAddress, + &sbt->callableAddress, + bufferAddress); return PAL_RESULT_SUCCESS; } @@ -6521,17 +6542,12 @@ PalResult PAL_CALL createVkAccelerationstructure( { VkResult result; AccelerationStructure* as = nullptr; - Buffer* vkBuffer = (Buffer*)info->buffer; Device* vkDevice = (Device*)device; - + Buffer* buffer = (Buffer*)info->buffer; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - if (!vkBuffer->address) { - return PAL_RESULT_INVALID_BUFFER; - } - as = palAllocate(s_Vk.allocator, sizeof(AccelerationStructure), 0); if (!as) { return PAL_RESULT_OUT_OF_MEMORY; @@ -6539,10 +6555,9 @@ PalResult PAL_CALL createVkAccelerationstructure( VkAccelerationStructureCreateInfoKHR createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; - createInfo.offset = (VkDeviceSize)info->offset; createInfo.size = (VkDeviceSize)info->size; - createInfo.buffer = vkBuffer->handle; + createInfo.buffer = buffer->handle; createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { @@ -6564,7 +6579,6 @@ PalResult PAL_CALL createVkAccelerationstructure( VkAccelerationStructureDeviceAddressInfoKHR addressInfo = {0}; addressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; addressInfo.accelerationStructure = as->handle; - as->address = vkDevice->getAccelerationDeviceAddress(vkDevice->handle, &addressInfo); as->device = vkDevice; @@ -6590,17 +6604,13 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( { Uint32* maxPrimities = nullptr; VkAccelerationStructureGeometryKHR* geometries = nullptr; - Device* vkDevice = (Device*)device; - AccelerationStructure* vkAs = (AccelerationStructure*)info->dst; - Buffer* vkScratchBuffer = (Buffer*)info->scratchBuffer; - + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } maxPrimities = palAllocate(s_Vk.allocator, sizeof(Uint32) * info->geometryCount, 0); - geometries = palAllocate( s_Vk.allocator, sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount, @@ -6610,89 +6620,10 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( return PAL_RESULT_OUT_OF_MEMORY; } - for (int i = 0; i < info->geometryCount; i++) { - maxPrimities[i] = info->geometries[i].primitiveCount; - - // fill vulkan geometry struct - VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; - tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - tmp->flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - - if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { - tmp->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - - VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; - data->pNext = nullptr; - data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; - - VkDeviceOrHostAddressConstKHR vertexAddress = {0}; - VkDeviceOrHostAddressConstKHR indexAddress = {0}; - PalGeometryDataTriangle* tmpData = info->geometries[i].data; - Buffer* vkVertexBuffer = (Buffer*)tmpData->vertexBuffer; - Buffer* vkIndexBuffer = (Buffer*)tmpData->indexBuffer; - - vertexAddress.deviceAddress = vkVertexBuffer->address + tmpData->vertexOffset; - data->vertexData = vertexAddress; - data->maxVertex = tmpData->vertexCount; - data->vertexFormat = vertexTypeToVkFormat(tmpData->vertexType); - data->vertexStride = tmpData->vertexStride; - - indexAddress.deviceAddress = vkIndexBuffer->address + tmpData->indexOffset; - data->indexData = indexAddress; - if (tmpData->indexType == PAL_INDEX_TYPE_UINT32) { - data->indexType = VK_INDEX_TYPE_UINT32; - } else { - data->indexType = VK_INDEX_TYPE_UINT16; - } - - } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { - tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; - VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; - data->pNext = nullptr; - data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; - - VkDeviceOrHostAddressConstKHR address = {0}; - PalGeometryDataAABBS* tmpData = info->geometries[i].data; - Buffer* vkBuffer = (Buffer*)tmpData->buffer; - address.deviceAddress = vkBuffer->address + tmpData->offset; - data->data = address; - data->stride = tmpData->stride; - - } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_INSTANCE) { - tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; - data = &tmp->geometry.instances; - data->pNext = nullptr; - data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; - - VkDeviceOrHostAddressConstKHR address = {0}; - PalGeometryDataInstance* tmpData = info->geometries[i].data; - Buffer* vkBuffer = (Buffer*)tmpData->buffer; - address.deviceAddress = vkBuffer->address + tmpData->offset; - data->data = address; - } - } - - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - buildInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; - - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - } else { - buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - } - - buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - buildInfo.geometryCount = info->geometryCount; - buildInfo.dstAccelerationStructure = vkAs->handle; - - VkDeviceOrHostAddressKHR scratchData = {0}; - scratchData.deviceAddress = vkScratchBuffer->address + info->scratchBufferOffset; - buildInfo.scratchData = scratchData; - - buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; - buildInfo.pGeometries = geometries; + memset(maxPrimities, 0, sizeof(Uint32) * info->geometryCount); + memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount); + fillVkBuildInfo(info, maxPrimities, geometries, nullptr, nullptr, &buildInfo); VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; @@ -6724,7 +6655,7 @@ PalResult PAL_CALL createVkBuffer( VkResult result; Buffer* buffer = nullptr; Device* vkDevice = (Device*)device; - if (info->usages & PAL_BUFFER_USAGE_RAY_TRACING) { + if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6748,19 +6679,14 @@ PalResult PAL_CALL createVkBuffer( createInfo.usage = palBufferUsageToVk(info->usages); result = s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &buffer->handle); - if (result != VK_SUCCESS) { palFree(s_Vk.allocator, buffer); return vkResultToPal(result); } - // get the address if the address usage is set - buffer->address = 0; - if (createInfo.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) { - VkBufferDeviceAddressInfoKHR bufferInfo = {0}; - bufferInfo.buffer = buffer->handle; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; - buffer->address = vkDevice->getBufferrAddress(vkDevice->handle, &bufferInfo); + buffer->usages = info->usages; + if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { + buffer->usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; } buffer->device = vkDevice; @@ -6787,7 +6713,7 @@ PalResult PAL_CALL getVkBufferMemoryRequirements( requirements->alignment = (Uint64)memReq.alignment; requirements->size = (Uint64)memReq.size; - requirements->memoryMask = memReq.memoryTypeBits; + requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, vkBuffer->usages); requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; @@ -6816,6 +6742,19 @@ PalResult PAL_CALL bindVkBufferMemory( return PAL_RESULT_SUCCESS; } +PalDeviceAddress PAL_CALL getVkBufferDeviceAddress(PalBuffer* buffer) +{ + Buffer* vkBuffer = (Buffer*)buffer; + if (!(vkBuffer->device->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { + return 0; + } + + VkBufferDeviceAddressInfoKHR bufferInfo = {0}; + bufferInfo.buffer = vkBuffer->handle; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; + return vkBuffer->device->getBufferrAddress(vkBuffer->device->handle, &bufferInfo); +} + // ================================================== // Descriptor Pool, Set and Layout // ================================================== @@ -7005,28 +6944,52 @@ PalResult PAL_CALL updateVkDescriptorSet( VkWriteDescriptorSet* writes = nullptr; VkDescriptorBufferInfo* bufferInfos = nullptr; VkDescriptorImageInfo* imageInfos = nullptr; + VkWriteDescriptorSetAccelerationStructureKHR* tlasInfos = nullptr; + Uint32 bufferCount = 0; Uint32 imageCount = 0; + Uint32 tlasCount = 0; for (int i = 0; i < count; i++) { if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { bufferCount++; + } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + tlasCount++; + } else { imageCount++; } } writes = palAllocate(s_Vk.allocator, sizeof(VkWriteDescriptorSet) * count, 0); + if (!writes) { + return PAL_RESULT_OUT_OF_MEMORY; + } + bufferInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBufferInfo) * bufferCount, 0); + if (!bufferInfos && bufferCount) { + return PAL_RESULT_OUT_OF_MEMORY; + } + imageInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorImageInfo) * imageCount, 0); - if (!writes || !bufferInfos || !imageInfos) { + if (!imageInfos && imageCount) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + tlasInfos = palAllocate( + s_Vk.allocator, + sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasCount, + 0); + + if (!tlasInfos && tlasCount) { return PAL_RESULT_OUT_OF_MEMORY; } Uint32 bufferIndex = 0; Uint32 imageIndex = 0; + Uint32 tlasIndex = 0; for (int i = 0; i < count; i++) { VkWriteDescriptorSet* write = &writes[i]; write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -7052,6 +7015,17 @@ PalResult PAL_CALL updateVkDescriptorSet( bufferInfo->range = infos[i].bufferInfo->size; write->pBufferInfo = bufferInfo; + } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + VkWriteDescriptorSetAccelerationStructureKHR* tlasInfo = &tlasInfos[tlasIndex++]; + AccelerationStructure* ac = (AccelerationStructure*)infos[i].tlasInfo->tlas; + + tlasInfo->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; + tlasInfo->accelerationStructureCount = 1; + tlasInfo->pAccelerationStructures = &ac->handle; + tlasInfo->pNext = nullptr; + write->pNext = tlasInfo; + + } else { VkDescriptorImageInfo* imageInfo = &imageInfos[imageIndex++]; ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; @@ -7080,6 +7054,7 @@ PalResult PAL_CALL updateVkDescriptorSet( palFree(s_Vk.allocator, writes); palFree(s_Vk.allocator, bufferInfos); palFree(s_Vk.allocator, imageInfos); + palFree(s_Vk.allocator, tlasInfos); return PAL_RESULT_SUCCESS; } @@ -7789,7 +7764,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( return vkResultToPal(result); } - // allocate GPU only memory and bind + // allocate CPU upload memory and bind VkMemoryRequirements memReq = {0}; s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->buffer, &memReq); @@ -7797,7 +7772,8 @@ PalResult PAL_CALL createVkRayTracingPipeline( allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memReq.size; - Uint32 memoryIndex = findBestMemoryIndex(vkDevice->phyDevice, memReq.memoryTypeBits); + Uint32 mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] & memReq.memoryTypeBits; + Uint32 memoryIndex = findBestMemoryIndex(vkDevice->phyDevice, mask); allocateInfo.memoryTypeIndex = memoryIndex; VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; @@ -7818,44 +7794,6 @@ PalResult PAL_CALL createVkRayTracingPipeline( } s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); - // create staging buffer - bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufCreateInfo.size = bufferSize; - bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - result = s_Vk.createBuffer( - vkDevice->handle, - &bufCreateInfo, - &s_Vk.vkAllocator, - &sbt->stagingBuffer); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); - } - - s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->stagingBuffer, &memReq); - allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.allocationSize = memReq.size; - - memoryIndex = findBestMemoryIndex(vkDevice->phyDevice, memReq.memoryTypeBits); - allocateInfo.memoryTypeIndex = memoryIndex; - - result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, - &sbt->stagingBufferMemory); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); - } - s_Vk.bindBufferMemory(vkDevice->handle, sbt->stagingBuffer, sbt->stagingBufferMemory, 0); - // get shader handles Uint32 totalGroups = numRaygen + numHit + numMiss + numCallable; Uint8* handles = palAllocate(s_Vk.allocator, totalGroups * groupHandleSize, 0); @@ -7878,11 +7816,10 @@ PalResult PAL_CALL createVkRayTracingPipeline( return vkResultToPal(result); } - // copy handles into the GPU buffer - // we need a one time submit command buffer to do this operation + // copy handles into the buffer Uint32 index = 0; void* ptr = nullptr; - result = s_Vk.mapMemory(vkDevice->handle, sbt->stagingBufferMemory, 0, memReq.size, 0, &ptr); + result = s_Vk.mapMemory(vkDevice->handle, sbt->bufferMemory, 0, memReq.size, 0, &ptr); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); @@ -7928,58 +7865,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( index++; } - s_Vk.unmapMemory(vkDevice->handle, sbt->stagingBufferMemory); - - // copy CPU buffer to GPU buffer - VkCommandBufferBeginInfo cmdBeginInfo = {0}; - cmdBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - result = s_Vk.cmdBegin(vkDevice->cmdBuffer, &cmdBeginInfo); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); - } - - VkBufferCopy copyRegion = {0}; - copyRegion.size = bufferSize; - s_Vk.cmdCopyBuffer(vkDevice->cmdBuffer, sbt->stagingBuffer, sbt->buffer, 1, ©Region); - - result = s_Vk.cmdEnd(vkDevice->cmdBuffer); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); - } - - // create a signal semaphore so we dont block until GPU finishes - VkSemaphoreCreateInfo semaphoreCreateInfo = {0}; - semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - - result = s_Vk.createSemaphore( - vkDevice->handle, - &semaphoreCreateInfo, - &s_Vk.vkAllocator, - &sbt->semaphore); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); - } - - VkSubmitInfo submitInfo = {0}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &vkDevice->cmdBuffer; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &sbt->semaphore; - - result = s_Vk.queueSubmit(vkDevice->phyQueues[0].handle, 1, &submitInfo, VK_NULL_HANDLE); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); - } + s_Vk.unmapMemory(vkDevice->handle, sbt->bufferMemory); // cache SBT fields and offsets address VkBufferDeviceAddressInfo bufferAddressInfo = {0}; @@ -8024,11 +7910,8 @@ void PAL_CALL destroyVkPipeline(PalPipeline* pipeline) VkDevice device = vkPipeline->device->handle; ShaderBindingTable* sbt = vkPipeline->sbt; - s_Vk.destroySemaphore(device, sbt->semaphore, &s_Vk.vkAllocator); s_Vk.destroyBuffer(device, sbt->buffer, &s_Vk.vkAllocator); s_Vk.freeMemory(device, sbt->bufferMemory, &s_Vk.vkAllocator); - s_Vk.destroyBuffer(device, sbt->stagingBuffer, &s_Vk.vkAllocator); - s_Vk.freeMemory(device, sbt->stagingBufferMemory, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkPipeline->sbt); } diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 8e46ad05..f8dc3a3c 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -55,10 +55,22 @@ bool rayTracingTest() PalShader* raygenShader = nullptr; PalShader* missShader = nullptr; PalShader* closestHitShader = nullptr; + PalBuffer* buffer = nullptr; PalBuffer* stagingBuffer = nullptr; + PalBuffer* vertexBuffer = nullptr; + PalBuffer* instanceBuffer = nullptr; + PalBuffer* blasBuffer = nullptr; + PalBuffer* tlasBuffer = nullptr; + PalBuffer* scratchBuffer = nullptr; + PalMemory* bufferMemory = nullptr; PalMemory* stagingBufferMemory = nullptr; + PalMemory* vertexBufferMemory = nullptr; + PalMemory* instanceBufferMemory = nullptr; + PalMemory* blasBufferMemory = nullptr; + PalMemory* tlasBufferMemory = nullptr; + PalMemory* scratchBufferMemory = nullptr; PalDescriptorSetLayout* descriptorSetLayout = nullptr; PalDescriptorPool* descriptorPool = nullptr; @@ -67,11 +79,14 @@ bool rayTracingTest() PalPipeline* pipeline = nullptr; PalFence* fence = nullptr; + PalAccelerationStructure* blas = nullptr; + PalAccelerationStructure* tlas = nullptr; + PalGraphicsDebugger debugger; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -367,19 +382,347 @@ bool rayTracingTest() return false; } + // create a vertex buffer to store the vertices in + float vertices[] = { + 0.0f, 0.5f, + 0.5f, -0.5f, + -0.5f, -0.5f}; + + bufferCreateInfo.size = sizeof(vertices); + bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; + + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create vertex buffer: %s", error); + return false; + } + + // we dont create a staging buffer to copy the vertices + // since we just need the buffer to create the acceleration structure + // its still recommended to create a staging buffer so the vertex buffer + // is GPU memory only + result = palGetBufferMemoryRequirements(vertexBuffer, &bufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + bufferMemReq.memoryMask, + bufferMemReq.size, + &vertexBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + // copy vertices + void* data = nullptr; + result = palMapMemory(device, vertexBufferMemory, 0, sizeof(vertices), &data); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map memory: %s", error); + return false; + } + + memcpy(data, vertices, sizeof(vertices)); + palUnmapMemory(device, vertexBufferMemory); + + // fill BLAS and triangle geometry + PalDeviceAddress vertexBufferAddress = palGetBufferDeviceAddress(vertexBuffer); + PalGeometryDataTriangle triangle = {0}; + triangle.vertexBufferAddress = vertexBufferAddress; + triangle.vertexCount = 3; + triangle.vertexOffset = 0; + triangle.vertexType = PAL_VERTEX_TYPE_FLOAT2; + triangle.vertexStride = sizeof(float) * 2; + + PalGeometry geometry = {0}; + geometry.data = ▵ + geometry.primitiveCount = 1; + geometry.type = PAL_GEOMETRY_TYPE_TRIANGLE; + + PalAccelerationStructureBuildInfo blasBuildInfo = {0}; + blasBuildInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + blasBuildInfo.scratchBufferOffset = 0; + blasBuildInfo.geometryCount = 1; + blasBuildInfo.geometries = &geometry; + + // get the build sizes for blas + PalAccelerationStructureBuildSize buildSizes = {0}; + result = palGetAccelerationStructureBuildSize(device, &blasBuildInfo, &buildSizes); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get blas build sizes: %s", error); + return false; + } + + // create the blas buffer and blas + bufferCreateInfo.size = buildSizes.accelerationStructureSize; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; + + result = palCreateBuffer(device, &bufferCreateInfo, &blasBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create blas buffer: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(blasBuffer, &bufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + bufferMemReq.memoryMask, + bufferMemReq.size, + &blasBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palBindBufferMemory(blasBuffer, blasBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + PalAccelerationStructureCreateInfo asCreateInfo = {0}; + asCreateInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + asCreateInfo.buffer = blasBuffer; + asCreateInfo.size = buildSizes.accelerationStructureSize; + + result = palCreateAccelerationstructure(device, &asCreateInfo, &blas); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create blas: %s", error); + return false; + } + + // create instance buffer + PalAccelerationStructureInstance asInstance = {0}; + asInstance.blas = blas; + asInstance.instanceId = 0; + asInstance.mask = 0xFF; + + float transform[12] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f + }; + // memcpy(asInstance.transform, transform, sizeof(float) * 12); + + bufferCreateInfo.size = sizeof(PalAccelerationStructureInstance); + bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; + + result = palCreateBuffer(device, &bufferCreateInfo, &instanceBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create instance buffer: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(instanceBuffer, &bufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + bufferMemReq.memoryMask, + bufferMemReq.size, + &instanceBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palBindBufferMemory(instanceBuffer, instanceBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + // copy instance struct to the buffer + data = nullptr; + result = palMapMemory( + device, + instanceBufferMemory, + 0, + sizeof(PalAccelerationStructureInstance), + &data); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map memory: %s", error); + return false; + } + + memcpy(data, &asInstance, sizeof(PalAccelerationStructureInstance)); + palUnmapMemory(device, instanceBufferMemory); + + // fill TLAS and instance geometry + PalDeviceAddress instanceBufferAddress = palGetBufferDeviceAddress(instanceBuffer); + PalGeometryDataInstance instance = {0}; + instance.offset = 0; + instance.bufferAddress = instanceBufferAddress; + + PalGeometry instanceGeometry = {0}; + instanceGeometry.data = &instance; + instanceGeometry.primitiveCount = 1; + instanceGeometry.type = PAL_GEOMETRY_TYPE_INSTANCE; + + PalAccelerationStructureBuildInfo tlasBuildInfo = {0}; + tlasBuildInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + tlasBuildInfo.scratchBufferOffset = 0; + tlasBuildInfo.geometryCount = 1; + tlasBuildInfo.geometries = &instanceGeometry; + + // get the build sizes for tlas + Uint32 blasScratchSize = buildSizes.scratchBufferSize; + result = palGetAccelerationStructureBuildSize(device, &tlasBuildInfo, &buildSizes); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get tlas build sizes: %s", error); + return false; + } + + // create the tlas buffer and tlas + bufferCreateInfo.size = buildSizes.accelerationStructureSize; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; + + result = palCreateBuffer(device, &bufferCreateInfo, &tlasBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create tlas buffer: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(tlasBuffer, &bufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + bufferMemReq.memoryMask, + bufferMemReq.size, + &tlasBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palBindBufferMemory(tlasBuffer, tlasBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + asCreateInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + asCreateInfo.buffer = tlasBuffer; + asCreateInfo.size = buildSizes.accelerationStructureSize; + + result = palCreateAccelerationstructure(device, &asCreateInfo, &tlas); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create tlas: %s", error); + return false; + } + + // create scratch buffer + bufferCreateInfo.size = buildSizes.scratchBufferSize + blasScratchSize;; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; + + result = palCreateBuffer(device, &bufferCreateInfo, &scratchBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create scratch buffer: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(scratchBuffer, &bufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + bufferMemReq.memoryMask, + bufferMemReq.size, + &scratchBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palBindBufferMemory(scratchBuffer, scratchBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + // create descriptor set layout - PalDescriptorSetLayoutBinding descriptorBinding = {0}; + PalDescriptorSetLayoutBinding descriptorBindings[2]; PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_RAYGEN }; - descriptorBinding.binding = 0; - descriptorBinding.descriptorCount = 1; // not an array - descriptorBinding.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorBinding.shaderStageCount = 1; - descriptorBinding.shaderStages = shaderStages; + // storage buffer to write to + descriptorBindings[0].binding = 0; + descriptorBindings[0].descriptorCount = 1; // not an array + descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorBindings[0].shaderStageCount = 1; + descriptorBindings[0].shaderStages = shaderStages; + + // acceleration buffer + descriptorBindings[1].binding = 1; + descriptorBindings[1].descriptorCount = 1; // not an array + descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE; + descriptorBindings[1].shaderStageCount = 1; + descriptorBindings[1].shaderStages = shaderStages; PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; - descriptorSetLayoutcreateInfo.bindingCount = 1; - descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; + descriptorSetLayoutcreateInfo.bindingCount = 2; + descriptorSetLayoutcreateInfo.bindings = descriptorBindings; result = palCreateDescriptorSetLayout( device, @@ -393,14 +736,17 @@ bool rayTracingTest() } // create descriptor pool - PalDescriptorPoolBindingSize storageBufferBindingsize = {0}; - storageBufferBindingsize.bindingCount = 1; - storageBufferBindingsize.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + PalDescriptorPoolBindingSize bindingSizes[2]; + bindingSizes[0].bindingCount = 1; + bindingSizes[0].descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + + bindingSizes[1].bindingCount = 1; + bindingSizes[1].descriptorType = PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE; PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set - descriptorPoolCreateInfo.maxDescriptorBindingSizes = 1; // one binding type - descriptorPoolCreateInfo.bindingSizes = &storageBufferBindingsize; + descriptorPoolCreateInfo.maxDescriptorBindingSizes = 2; // two binding type + descriptorPoolCreateInfo.bindingSizes = bindingSizes; result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); if (result != PAL_RESULT_SUCCESS) { @@ -419,19 +765,28 @@ bool rayTracingTest() } // write the inital data to the descriptor set since its created empty - PalDescriptorBufferInfo descriptorBufferInfo = {0}; - descriptorBufferInfo.buffer = buffer; - descriptorBufferInfo.offset = 0; - descriptorBufferInfo.size = bufferBytes; - - PalDescriptorSetWriteInfo writeInfo = {0}; - writeInfo.binding = 0; - writeInfo.bufferInfo = &descriptorBufferInfo; - writeInfo.descriptorSet = descriptorSet; - writeInfo.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; - writeInfo.descriptorCount = 1; - - result = palUpdateDescriptorSet(device, 1, &writeInfo); + PalDescriptorBufferInfo descriptorStorageBufferInfo = {0}; + descriptorStorageBufferInfo.buffer = buffer; + descriptorStorageBufferInfo.offset = 0; + descriptorStorageBufferInfo.size = bufferBytes; + + PalDescriptorTLASInfo descriptorTlasInfo; + descriptorTlasInfo.tlas = tlas; + + PalDescriptorSetWriteInfo writeInfos[2]; + writeInfos[0].binding = 0; + writeInfos[0].bufferInfo = &descriptorStorageBufferInfo; + writeInfos[0].descriptorSet = descriptorSet; + writeInfos[0].descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + writeInfos[0].descriptorCount = 1; + + writeInfos[1].binding = 1; + writeInfos[1].tlasInfo = &descriptorTlasInfo; + writeInfos[1].descriptorSet = descriptorSet; + writeInfos[1].descriptorType = PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE; + writeInfos[1].descriptorCount = 1; + + result = palUpdateDescriptorSet(device, 2, writeInfos); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); @@ -537,6 +892,28 @@ bool rayTracingTest() return false; } + // build the blas and tlas infos + PalDeviceAddress scratchBufferAddress = palGetBufferDeviceAddress(scratchBuffer); + blasBuildInfo.dst = blas; + blasBuildInfo.scratchBufferAddress = scratchBufferAddress; + + tlasBuildInfo.dst = tlas; + tlasBuildInfo.scratchBufferAddress = scratchBufferAddress; + + result = palBuildAccelerationStructure(cmdBuffer, &blasBuildInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to build blas: %s", error); + return false; + } + + result = palBuildAccelerationStructure(cmdBuffer, &tlasBuildInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to build tlas: %s", error); + return false; + } + result = palTraceRays(cmdBuffer, BUFFER_SIZE, BUFFER_SIZE, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -635,6 +1012,9 @@ bool rayTracingTest() fclose(file); palUnmapMemory(device, stagingBufferMemory); + palDestroyAccelerationstructure(blas); + palDestroyAccelerationstructure(tlas); + palDestroyFence(fence); palDestroyPipeline(pipeline); palDestroyPipelineLayout(pipelineLayout); @@ -643,8 +1023,19 @@ bool rayTracingTest() palDestroyBuffer(buffer); palDestroyBuffer(stagingBuffer); + palDestroyBuffer(vertexBuffer); + palDestroyBuffer(instanceBuffer); + palDestroyBuffer(blasBuffer); + palDestroyBuffer(tlasBuffer); + palDestroyBuffer(scratchBuffer); + palFreeMemory(device, bufferMemory); palFreeMemory(device, stagingBufferMemory); + palFreeMemory(device, vertexBufferMemory); + palFreeMemory(device, instanceBufferMemory); + palFreeMemory(device, blasBufferMemory); + palFreeMemory(device, tlasBufferMemory); + palFreeMemory(device, scratchBufferMemory); palDestroyShader(raygenShader); palDestroyShader(missShader); diff --git a/tests/shaders/closest_hit.spv b/tests/shaders/closest_hit.spv index 2947099b66cce3ea06bad4c95a8673abccecddee..3d28d92ecc41b7da990f89103fe9f8720a004094 100644 GIT binary patch delta 220 zcmXwzJqiLb6oe;<*&o*wVo=KkORZH9w6OLN0h@)@6+0`vLVE9F;~}g(g{|N`(ZDc# z?`K{f>ZP60qZC%5Kn54xrkCLEffj&WsP;7Ev6^{{1UcalPIVKu>!xmw@j5*BVb}pm zYQVLWE^MfhoY9{Ql=|Ywk|VV-S!UamygwITx~wMb%3g<(8L5j;VWH{#WW06#lE)-c J#@83`~<98Ra?tGB7e&05Je`4hduc diff --git a/tests/shaders/miss.spv b/tests/shaders/miss.spv index aacc88603f23ca94dff4631c525931e28c12f7ac..ead00b0a2c55011f0f31a9c344ccd577ab437df1 100644 GIT binary patch delta 190 zcmcb?_=Jg83`~;^8Ra?tGB7e&05Je>4GBd6 diff --git a/tests/shaders/raygen.spv b/tests/shaders/raygen.spv index f9095cdbaf3e1280c6b9a9058da6febd3e637e0d..eca6aea295927cafcfc3df9fff287ca2b5d0d8ff 100644 GIT binary patch literal 2124 zcmY+ETW^$A6o&VlS||mroIC(d0jXH5s0C4kS}9JEkq#{}-k8ax)6_}EPBWbv;Kmxg z@Lw6P^uk|Y;{Wi*=<|H+MaDgOv(|doaUZ^^lrK!CS}7e#hti|;Y|W%{`hF&*sWg!` zT3@#BudcU;ohR+lu(R3Q*(P=(l?ZJ#H<}B3qwd1uwX0?xOO>L4z8A>;^+ZZl^lv-8 z9Uar)MKA}Jz+rUvoK8t1C)Z6K9JuYIa={#~U>}@-}J)C>D^Q1rM zbnguMgCQn-CCwxEzf-TJMf7fOxV1Uz4cxRdxYtp?vxg|`d&sr@(eC~zQMHz|UAw)< zTYaLe>Djm%c;5P=;_6)Uu&$jhvL2)O!pR>D+Uqwy;^BUB)pJ%>0*82js%XoWR z&lPsmJ5Hv#v()jn)lZUR{W@@+#-2pV>91oSLdpsKQ%L>R(C>aqK>lX7-M3uW&aZ9! zab)zE$F|nV><{~8Y}YBeypF5`dn>i0_bj@#>cCumaUNk`giGmQ=?b0dXm0>xgg$4w zg#42`sUw|PdoFX4_a=7aDV^ss(w=cvZ=pMneDq&HXDx+&qc9JC`RhbE-9oqj?Se~% zZGY{h%$esIErWkS)LAL~PglIdyXbXL0{XQ-11{%mAf2-c&T@LbE4g#%zA0_z_#Elo z$vKC%Z%R)8de+Uo&Kq>!)^t_C-!L_#xxSmj!1D;(Z#rz>0Z0Dao<%=DW_y04)0IS zeEVDja?$rXdi4D<*Z3gE>3az0yZsQzyMp@&UCz5|eskJ&BWQ*Hv6uy+qH(vimuuRu=tBohqGqw6W+P2Vwv{bH?`<5HCeFKC2X08jlq=0+tsrRWnggo)%=~~^5PHZza zj^+4k#eYSdr(UUCy*@ShUz<>1C!1d&r-PhlSb-et%`aBV(<}9vg`3yNm(PU_@Xr%X zJ}^RfTAOVwB)C24|2L;ndoh<}nU@dS&@9Z=<`)`Gyc1lj&(1ab<->k(eRgIFm*{(& z_))|+2=1*kmR87bLm_r8)t=2QE;ncM?5-01oL~FQkYc}$_)Chf6SrZWr^LCe=QkVA z)OIG9`PS}9&_BE{#a(2Y+e001$#^q4)-PhNBDfu|$!`U(N@H`}UyX0Ue8>eu4klaKp6t%QsDo?FcpChNf$6Uzr@cNRHw^+zz)XvD`7_-dq^6P+QB{9wX| z5zlaq*j(SzZhH7#<@ONYz>A%=gm-p1XA}EP<@{DR@kOi!vyb=|=8ApGO&EHa+#Yu@ zIp>VtUU$LPRTH%nsYYGYp5?B+D`$6k4?kcEcxUwcbYS|3eJ@$ebNUba&a?Zz^N9WC zzNswkP4O6Az0Y-+ckcX`n8CYUkI7$VLgx`j{U&1d-h0${5zDK0UUAfKA@)sV>u&|i ztM@$OsNYVkK3jhWSYEy7702GYi0v8iZenY`;e4KD52i*wYW5O)u2-q1NUToY9)80j z7WD^+)kl1g*dFiF{6oZQ~n%Rd$vBX z=Z}3)604Dqefx>!W8YK6a@oG8!Sb=MZ$i$#&N_g}ePB+1hi6mH-(l38BX-`1hltJj znC6@(RwMsDYOY}SG3PRNF5lK|%(pTIx{JSujbpbk_qhb**8oSmOb4wnhaUYq)0(xd|*=!&<-j?=^(|0TTv^=l}o! From 38a4b8296e81e6e5bbecb593f3168764727b1a4b Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 13 Feb 2026 14:04:16 +0000 Subject: [PATCH 092/372] finish ray tracing example --- include/pal/pal_graphics.h | 44 +++++++- src/graphics/pal_graphics.c | 83 +++++++++++++- src/graphics/pal_vulkan.c | 211 +++++++++++++++++++++--------------- tests/ray_tracing_test.c | 63 +++++++++-- tests/shaders/raygen.spv | Bin 2124 -> 2320 bytes 5 files changed, 297 insertions(+), 104 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 9dc885fb..9896252b 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -556,6 +556,8 @@ typedef enum { PAL_USAGE_STATE_STORAGE_WRITE, PAL_USAGE_STATE_HOST_READ, PAL_USAGE_STATE_HOST_WRITE, + PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ, + PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE } PalUsageState; typedef enum { @@ -737,6 +739,11 @@ typedef struct { Uint32 alignment; } PalMemoryRequirements; +typedef struct { + Uint64 size; + Uint32 alignment; +} PalInstanceBufferRequirements; + typedef struct { Uint64 waitValue; Uint64 signalValue; @@ -890,20 +897,16 @@ typedef struct { Uint32 vertexStride; Uint32 indexCount; Uint32 vertexCount; - Uint64 vertexOffset; - Uint64 indexOffset; PalDeviceAddress vertexBufferAddress; PalDeviceAddress indexBufferAddress; } PalGeometryDataTriangle; typedef struct { Uint32 stride; - Uint64 offset; PalDeviceAddress bufferAddress; } PalGeometryDataAABBS; typedef struct { - Uint64 offset; PalDeviceAddress bufferAddress; } PalGeometryDataInstance; @@ -916,7 +919,6 @@ typedef struct { typedef struct { PalAccelerationStructureType type; Uint32 geometryCount; - Uint64 scratchBufferOffset; PalAccelerationStructure* dst; PalDeviceAddress scratchBufferAddress; PalGeometry* geometries; @@ -1404,6 +1406,11 @@ typedef struct { Uint64 countBufferOffset, Uint32 count); + PalResult PAL_CALL (*memoryBarrier)( + PalCommandBuffer* cmdBuffer, + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); + PalResult PAL_CALL (*imageViewBarrier)( PalCommandBuffer* cmdBuffer, PalImageView* imageView, @@ -1489,6 +1496,17 @@ typedef struct { PalBuffer* buffer, PalMemoryRequirements* requirements); + PalResult PAL_CALL (*computeInstanceBufferRequirements)( + PalDevice* device, + PalInstanceBufferRequirements* requirements, + Uint32 instanceCount); + + PalResult PAL_CALL (*writeInstancesToMappedMemory)( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + Uint32 instanceCount); + PalResult PAL_CALL (*bindBufferMemory)( PalBuffer* buffer, PalMemory* memory, @@ -1885,6 +1903,11 @@ PAL_API PalResult PAL_CALL palDrawIndexedIndirectCount( Uint64 countBufferOffset, Uint32 count); +PAL_API PalResult PAL_CALL palMemoryBarrier( + PalCommandBuffer* cmdBuffer, + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); + PAL_API PalResult PAL_CALL palImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, @@ -1970,6 +1993,17 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( PalBuffer* buffer, PalMemoryRequirements* requirements); +PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( + PalDevice* device, + PalInstanceBufferRequirements* requirements, + Uint32 instanceCount); + +PAL_API PalResult PAL_CALL palWriteInstancesToMappedMemory( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + Uint32 instanceCount); + PAL_API PalResult PAL_CALL palBindBufferMemory( PalBuffer* buffer, PalMemory* memory, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 9ddfade3..056c21e5 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -421,6 +421,11 @@ PalResult PAL_CALL drawIndexedIndirectCountVk( Uint64 countBufferOffset, Uint32 count); +PalResult PAL_CALL memoryBarrierVk( + PalCommandBuffer* cmdBuffer, + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); + PalResult PAL_CALL imageViewBarrierVk( PalCommandBuffer* cmdBuffer, PalImageView* imageView, @@ -506,6 +511,17 @@ PalResult PAL_CALL getVkBufferMemoryRequirements( PalBuffer* buffer, PalMemoryRequirements* requirements); +PalResult PAL_CALL computeVkInstanceBufferRequirements( + PalDevice* device, + PalInstanceBufferRequirements* requirements, + Uint32 instanceCount); + +PalResult PAL_CALL writeVkInstancesToMappedMemory( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + Uint32 instanceCount); + PalResult PAL_CALL bindVkBufferMemory( PalBuffer* buffer, PalMemory* memory, @@ -655,6 +671,7 @@ static PalGraphicsBackend s_VkBackend = { .drawIndexed = drawIndexedVk, .drawIndexedIndirect = drawIndexedIndirectVk, .drawIndexedIndirectCount = drawIndexedIndirectCountVk, + .memoryBarrier = memoryBarrierVk, .imageViewBarrier = imageViewBarrierVk, .bufferBarrier = bufferBarrierVk, .dispatch = dispatchVk, @@ -671,6 +688,8 @@ static PalGraphicsBackend s_VkBackend = { .createBuffer = createVkBuffer, .destroyBuffer = destroyVkBuffer, .getBufferMemoryRequirements = getVkBufferMemoryRequirements, + .computeInstanceBufferRequirements = computeVkInstanceBufferRequirements, + .writeInstancesToMappedMemory = writeVkInstancesToMappedMemory, .bindBufferMemory = bindVkBufferMemory, .getBufferDeviceAddress = getVkBufferDeviceAddress, .createDescriptorSetLayout = createVkDescriptorSetLayout, @@ -796,6 +815,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->drawIndexed || !backend->drawIndexedIndirect || !backend->drawIndexedIndirectCount || + !backend->memoryBarrier || !backend->imageViewBarrier || !backend->bufferBarrier || !backend->dispatch || @@ -812,6 +832,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->createBuffer || !backend->destroyBuffer || !backend->getBufferMemoryRequirements || + !backend->computeInstanceBufferRequirements || + !backend->writeInstancesToMappedMemory || !backend->bindBufferMemory || !backend->getBufferDeviceAddress || !backend->mapMemory || @@ -2151,6 +2173,25 @@ PalResult PAL_CALL palDrawIndexedIndirectCount( count); } +PalResult PAL_CALL palMemoryBarrier( + PalCommandBuffer* cmdBuffer, + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !oldUsageStateInfo || !newUsageStateInfo) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->memoryBarrier( + cmdBuffer, + oldUsageStateInfo, + newUsageStateInfo); +} + PalResult PAL_CALL palImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, @@ -2161,7 +2202,7 @@ PalResult PAL_CALL palImageViewBarrier( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !imageView) { + if (!cmdBuffer || !imageView || !oldUsageStateInfo || !newUsageStateInfo) { return PAL_RESULT_NULL_POINTER; } @@ -2182,7 +2223,7 @@ PalResult PAL_CALL palBufferBarrier( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !buffer) { + if (!cmdBuffer || !buffer || !oldUsageStateInfo || !newUsageStateInfo) { return PAL_RESULT_NULL_POINTER; } @@ -2454,6 +2495,44 @@ PalResult PAL_CALL palGetBufferMemoryRequirements( return buffer->backend->getBufferMemoryRequirements(buffer, requirements); } +PalResult PAL_CALL palComputeInstanceBufferRequirements( + PalDevice* device, + PalInstanceBufferRequirements* requirements, + Uint32 instanceCount) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->computeInstanceBufferRequirements(device, requirements, instanceCount); +} + +PalResult PAL_CALL palWriteInstancesToMappedMemory( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + Uint32 instanceCount) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !ptr || !instances || instanceCount == 0) { + return PAL_RESULT_NULL_POINTER; + } + + // HACK: since all blas have backend pointer, we use the first one + return device->backend->writeInstancesToMappedMemory( + device, + ptr, + instances, + instanceCount); +} + PalResult PAL_CALL palBindBufferMemory( PalBuffer* buffer, PalMemory* memory, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 8674ccd6..d44ffd30 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -217,8 +217,6 @@ typedef struct { VkPhysicalDevice phyDevice; VkDevice handle; PhysicalQueue* phyQueues; - VkCommandPool cmdPool; - VkCommandBuffer cmdBuffer; PFN_vkGetBufferDeviceAddress getBufferrAddress; PFN_vkCmdDispatchBase cmdDispatchBase; @@ -1789,6 +1787,24 @@ static Barrier barrierToVk(PalUsageState state, barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } + + case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: { + barrier.stages = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; + barrier.dstStages = barrier.stages; + + barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + + case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE: { + barrier.stages = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; + barrier.dstStages = barrier.stages; + + barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } } barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; @@ -2031,13 +2047,13 @@ static void fillVkBuildInfo( VkDeviceOrHostAddressConstKHR indexAddress = {0}; PalGeometryDataTriangle* tmpData = info->geometries[i].data; - vertexAddress.deviceAddress = tmpData->vertexBufferAddress + tmpData->vertexOffset; + vertexAddress.deviceAddress = tmpData->vertexBufferAddress; data->vertexData = vertexAddress; - data->maxVertex = tmpData->vertexCount; + data->maxVertex = tmpData->vertexCount - 1; data->vertexFormat = vertexTypeToVkFormat(tmpData->vertexType); data->vertexStride = tmpData->vertexStride; - indexAddress.deviceAddress = tmpData->indexBufferAddress + tmpData->indexOffset; + indexAddress.deviceAddress = tmpData->indexBufferAddress; data->indexData = indexAddress; if (tmpData->indexType == PAL_INDEX_TYPE_UINT32) { data->indexType = VK_INDEX_TYPE_UINT32; @@ -2057,7 +2073,7 @@ static void fillVkBuildInfo( VkDeviceOrHostAddressConstKHR address = {0}; PalGeometryDataAABBS* tmpData = info->geometries[i].data; - address.deviceAddress = tmpData->bufferAddress + tmpData->offset; + address.deviceAddress = tmpData->bufferAddress; data->data = address; data->stride = tmpData->stride; @@ -2070,7 +2086,7 @@ static void fillVkBuildInfo( VkDeviceOrHostAddressConstKHR address = {0}; PalGeometryDataInstance* tmpData = info->geometries[i].data; - address.deviceAddress = tmpData->bufferAddress + tmpData->offset; + address.deviceAddress = tmpData->bufferAddress; data->data = address; } @@ -2098,7 +2114,7 @@ static void fillVkBuildInfo( buildInfo->pGeometries = geometries; VkDeviceOrHostAddressKHR scratchData = {0}; - scratchData.deviceAddress = info->scratchBufferAddress + info->scratchBufferOffset; + scratchData.deviceAddress = info->scratchBufferAddress; buildInfo->scratchData = scratchData; } @@ -3829,36 +3845,6 @@ PalResult PAL_CALL createVkDevice( "vkGetBufferDeviceAddressKHR"); } device->features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; - - // create a temporary command pool and buffer to be used with ray tracing pipeline - // copy to the GPU buffer - VkCommandPoolCreateInfo poolCreateInfo = {0}; - poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - - // technically, every queue type (compute, graphics, etc) will support - // buffer copy operation. So we use the first physical queue - poolCreateInfo.queueFamilyIndex = device->phyQueues[0].familyIndex; - result = s_Vk.createCommandPool( - device->handle, - &poolCreateInfo, - &s_Vk.vkAllocator, - &device->cmdPool); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, device); - return vkResultToPal(result); - } - - VkCommandBufferAllocateInfo cmdAllocateInfo = {0}; - cmdAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - cmdAllocateInfo.commandBufferCount = 1; - cmdAllocateInfo.commandPool = device->cmdPool; - cmdAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - result = s_Vk.allocateCommandBuffer(device->handle, &cmdAllocateInfo, &device->cmdBuffer); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, device); - return vkResultToPal(result); - } } // buffer address procs @@ -3970,11 +3956,6 @@ PalResult PAL_CALL createVkDevice( void PAL_CALL destroyVkDevice(PalDevice* device) { Device* vkDevice = (Device*)device; - if (vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - s_Vk.freeCommandBuffer(vkDevice->handle, vkDevice->cmdPool, 1, &vkDevice->cmdBuffer); - s_Vk.destroyCommandPool(vkDevice->handle, vkDevice->cmdPool, &s_Vk.vkAllocator); - } - s_Vk.destroyDevice(vkDevice->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkDevice->phyQueues); palFree(s_Vk.allocator, vkDevice); @@ -6226,6 +6207,36 @@ PalResult PAL_CALL drawIndexedIndirectCountVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL memoryBarrierVk( + PalCommandBuffer* cmdBuffer, + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + VkMemoryBarrier2KHR barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR; + + Barrier old, new; + old = barrierToVk(oldUsageStateInfo->usageState, oldUsageStateInfo->shaderStage); + new = barrierToVk(newUsageStateInfo->usageState, newUsageStateInfo->shaderStage); + + barrier.srcStageMask = old.stages; + barrier.srcAccessMask = old.access; + + barrier.dstStageMask = new.stages; + barrier.dstAccessMask = new.access; + + VkDependencyInfo dependencyInfo = {0}; + dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependencyInfo.memoryBarrierCount = 1; + dependencyInfo.pMemoryBarriers = &barrier; + + vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); + vkCmdBuffer->dstStage = new.stages; + return PAL_RESULT_SUCCESS; + +} + PalResult PAL_CALL imageViewBarrierVk( PalCommandBuffer* cmdBuffer, PalImageView* imageView, @@ -6258,7 +6269,6 @@ PalResult PAL_CALL imageViewBarrierVk( dependencyInfo.pImageMemoryBarriers = &barrier; vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - vkCmdBuffer->dstStage = new.stages; return PAL_RESULT_SUCCESS; } @@ -6294,7 +6304,6 @@ PalResult PAL_CALL bufferBarrierVk( dependencyInfo.pBufferMemoryBarriers = &barrier; vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - vkCmdBuffer->dstStage = new.stages; return PAL_RESULT_SUCCESS; } @@ -6471,6 +6480,10 @@ PalResult PAL_CALL submitVkCommandBuffer( Queue* vkQueue = (Queue*)queue; CommandBuffer* vkCmdBuffer = (CommandBuffer*)info->cmdBuffer; + if (vkCmdBuffer->sbt) { + vkCmdBuffer->dstStage |= VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; + } + if (info->waitSemaphore) { Semaphore* tmp = (Semaphore*)info->waitSemaphore; waitSemaphoreHandle = tmp->handle; @@ -6508,10 +6521,6 @@ PalResult PAL_CALL submitVkCommandBuffer( signalSubmitInfo.value = info->signalValue; } - if (vkCmdBuffer->sbt) { - vkCmdBuffer->dstStage |= VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; - } - VkSubmitInfo2KHR submitInfo = {0}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR; submitInfo.commandBufferInfoCount = 1; @@ -6726,6 +6735,38 @@ PalResult PAL_CALL getVkBufferMemoryRequirements( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL computeVkInstanceBufferRequirements( + PalDevice* device, + PalInstanceBufferRequirements* requirements, + Uint32 instanceCount) +{ + requirements->size = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; + requirements->alignment = 16; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL writeVkInstancesToMappedMemory( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + Uint32 instanceCount) +{ + VkAccelerationStructureInstanceKHR* data = ptr; + for (int i = 0; i < instanceCount; i++) { + PalAccelerationStructureInstance* src = &instances[i]; + VkAccelerationStructureInstanceKHR* dst = &data[i]; + AccelerationStructure* as = (AccelerationStructure*)src->blas; + + dst->mask = src->mask & 0xFF; + dst->instanceCustomIndex = src->instanceId * 0xFFFFFF; + dst->accelerationStructureReference = as->address; + dst->instanceShaderBindingTableRecordOffset = 0; + dst->flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; + memcpy(dst->transform.matrix, src->transform, sizeof(float) * 12); + } + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL bindVkBufferMemory( PalBuffer* buffer, PalMemory* memory, @@ -7694,7 +7735,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( group->anyHitShader = info->shaderGroups[i].anyHitShaderIndex; group->closestHitShader = info->shaderGroups[i].closestHitShaderIndex; - group->generalShader= info->shaderGroups[i].generalShaderIndex; + group->generalShader = info->shaderGroups[i].generalShaderIndex; group->intersectionShader = info->shaderGroups[i].intersectionShaderIndex; } @@ -7741,12 +7782,17 @@ PalResult PAL_CALL createVkRayTracingPipeline( Uint32 hitRegionSize = stride * numHit; Uint32 callableRegionSize = stride * numCallable; + // get aligned region size + Uint32 raygenAlignedRegionSize = align(raygenRegionSize, groupBaseAlignment); + Uint32 missAlignedRegionSize = align(missRegionSize, groupBaseAlignment);; + Uint32 hitAlignedRegionSize = align(hitRegionSize, groupBaseAlignment); + Uint32 callableAligneRegionSize = align(callableRegionSize, groupBaseAlignment); + // get offsets - Uint32 raygenOffset = 0; // always 0 - Uint32 missOffset = align(raygenRegionSize, groupBaseAlignment); - Uint32 hitOffset = align(missOffset + missRegionSize, groupBaseAlignment); - Uint32 callableOffset = align(hitOffset + hitRegionSize, groupBaseAlignment); - Uint32 bufferSize = callableOffset + callableRegionSize; + Uint32 missOffset = raygenAlignedRegionSize; + Uint32 hitOffset = missOffset + missAlignedRegionSize; + Uint32 callableOffset = hitOffset + hitAlignedRegionSize; + Uint32 bufferSize = callableOffset + callableAligneRegionSize; // create gpu buffer VkBufferCreateInfo bufCreateInfo = {0}; @@ -7754,7 +7800,6 @@ PalResult PAL_CALL createVkRayTracingPipeline( bufCreateInfo.size = bufferSize; bufCreateInfo.usage = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR; bufCreateInfo.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; - bufCreateInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); @@ -7796,7 +7841,8 @@ PalResult PAL_CALL createVkRayTracingPipeline( // get shader handles Uint32 totalGroups = numRaygen + numHit + numMiss + numCallable; - Uint8* handles = palAllocate(s_Vk.allocator, totalGroups * groupHandleSize, 0); + Uint32 sbtSize = totalGroups * groupHandleSize; + Uint8* handles = palAllocate(s_Vk.allocator, sbtSize, 0); if (!handles) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); @@ -7806,8 +7852,9 @@ PalResult PAL_CALL createVkRayTracingPipeline( result = vkDevice->getRayTracingShaderGroupHandles( vkDevice->handle, pipeline->handle, - 0, totalGroups, - totalGroups * groupHandleSize, + 0, + totalGroups, + sbtSize, handles); if (result != VK_SUCCESS) { @@ -7817,7 +7864,6 @@ PalResult PAL_CALL createVkRayTracingPipeline( } // copy handles into the buffer - Uint32 index = 0; void* ptr = nullptr; result = s_Vk.mapMemory(vkDevice->handle, sbt->bufferMemory, 0, memReq.size, 0, &ptr); if (result != VK_SUCCESS) { @@ -7826,45 +7872,40 @@ PalResult PAL_CALL createVkRayTracingPipeline( return vkResultToPal(result); } - // raygen - for (int i = 0; i < numRaygen; i++) { - memcpy( - ptr + raygenOffset + i * stride, - handles + index * groupHandleSize, - groupHandleSize); + Uint8* dstPtr = ptr; + Uint8* srcPtr = handles; - index++; - } + // raygen + memcpy(dstPtr, handles, groupHandleSize); + srcPtr += numRaygen * groupHandleSize; // miss for (int i = 0; i < numMiss; i++) { memcpy( - ptr + raygenOffset + i * stride, - handles + index * groupHandleSize, + dstPtr + missOffset + i * stride, + srcPtr + i * groupHandleSize, groupHandleSize); - - index++; } + srcPtr += numMiss * groupHandleSize; // hit for (int i = 0; i < numHit; i++) { memcpy( - ptr + hitOffset + i * stride, - handles + index * groupHandleSize, + dstPtr + hitOffset + i * stride, + srcPtr + i * groupHandleSize, groupHandleSize); - - index++; } + srcPtr += numHit * groupHandleSize; // callable for (int i = 0; i < numCallable; i++) { memcpy( - ptr + callableOffset + i * stride, - handles + index * groupHandleSize, + dstPtr + callableOffset + i * stride, + srcPtr + i * groupHandleSize, groupHandleSize); - - index++; } + srcPtr += numCallable * groupHandleSize; + s_Vk.unmapMemory(vkDevice->handle, sbt->bufferMemory); // cache SBT fields and offsets address @@ -7874,23 +7915,23 @@ PalResult PAL_CALL createVkRayTracingPipeline( sbt->baseAddress = s_Vk.getBufferDeviceAddress(vkDevice->handle, &bufferAddressInfo); // raygen - sbt->raygenAddress.deviceAddress = sbt->baseAddress + raygenOffset; - sbt->raygenAddress.size = raygenRegionSize; + sbt->raygenAddress.deviceAddress = sbt->baseAddress; + sbt->raygenAddress.size = raygenAlignedRegionSize; sbt->raygenAddress.stride = stride; // miss sbt->missAddress.deviceAddress = sbt->baseAddress + missOffset; - sbt->missAddress.size = missRegionSize; + sbt->missAddress.size = missAlignedRegionSize; sbt->missAddress.stride = stride; // hit sbt->hitAddress.deviceAddress = sbt->baseAddress + hitOffset; - sbt->hitAddress.size = hitRegionSize; + sbt->hitAddress.size = hitAlignedRegionSize; sbt->hitAddress.stride = stride; // callable sbt->callableAddress.deviceAddress = sbt->baseAddress + callableOffset; - sbt->callableAddress.size = callableRegionSize; + sbt->callableAddress.size = callableAligneRegionSize; sbt->callableAddress.stride = stride; palFree(s_Vk.allocator, handles); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index f8dc3a3c..c8d86b4e 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -86,7 +86,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -384,9 +384,9 @@ bool rayTracingTest() // create a vertex buffer to store the vertices in float vertices[] = { - 0.0f, 0.5f, - 0.5f, -0.5f, - -0.5f, -0.5f}; + 0.0f, 1.0f, + 1.0f, -1.0f, + -1.0f, -1.0f}; bufferCreateInfo.size = sizeof(vertices); bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; @@ -446,7 +446,6 @@ bool rayTracingTest() PalGeometryDataTriangle triangle = {0}; triangle.vertexBufferAddress = vertexBufferAddress; triangle.vertexCount = 3; - triangle.vertexOffset = 0; triangle.vertexType = PAL_VERTEX_TYPE_FLOAT2; triangle.vertexStride = sizeof(float) * 2; @@ -457,7 +456,6 @@ bool rayTracingTest() PalAccelerationStructureBuildInfo blasBuildInfo = {0}; blasBuildInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; - blasBuildInfo.scratchBufferOffset = 0; blasBuildInfo.geometryCount = 1; blasBuildInfo.geometries = &geometry; @@ -531,9 +529,17 @@ bool rayTracingTest() 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f }; - // memcpy(asInstance.transform, transform, sizeof(float) * 12); + memcpy(asInstance.transform, transform, sizeof(float) * 12); - bufferCreateInfo.size = sizeof(PalAccelerationStructureInstance); + PalInstanceBufferRequirements instanceBufferReq = {0}; + result = palComputeInstanceBufferRequirements(device, &instanceBufferReq, 1); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to compute instance buffer requirement: %s", error); + return false; + } + + bufferCreateInfo.size = instanceBufferReq.size; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; result = palCreateBuffer(device, &bufferCreateInfo, &instanceBuffer); @@ -576,7 +582,7 @@ bool rayTracingTest() device, instanceBufferMemory, 0, - sizeof(PalAccelerationStructureInstance), + instanceBufferReq.size, &data); if (result != PAL_RESULT_SUCCESS) { @@ -585,13 +591,19 @@ bool rayTracingTest() return false; } - memcpy(data, &asInstance, sizeof(PalAccelerationStructureInstance)); + // we can not use a direct memcpy for instance buffers + result = palWriteInstancesToMappedMemory(device, data, &asInstance, 1); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to write instances to instance buffer: %s", error); + return false; + } + palUnmapMemory(device, instanceBufferMemory); // fill TLAS and instance geometry PalDeviceAddress instanceBufferAddress = palGetBufferDeviceAddress(instanceBuffer); PalGeometryDataInstance instance = {0}; - instance.offset = 0; instance.bufferAddress = instanceBufferAddress; PalGeometry instanceGeometry = {0}; @@ -601,7 +613,6 @@ bool rayTracingTest() PalAccelerationStructureBuildInfo tlasBuildInfo = {0}; tlasBuildInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; - tlasBuildInfo.scratchBufferOffset = 0; tlasBuildInfo.geometryCount = 1; tlasBuildInfo.geometries = &instanceGeometry; @@ -907,6 +918,22 @@ bool rayTracingTest() return false; } + // make sure the BLAS builds before the TLAS + PalUsageStateInfo oldAsUsageStateInfo = {0}; + oldAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + oldAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; + + PalUsageStateInfo newAsUsageStateInfo = {0}; + newAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + newAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; + + result = palMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set memory barrier: %s", error); + return false; + } + result = palBuildAccelerationStructure(cmdBuffer, &tlasBuildInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -914,6 +941,18 @@ bool rayTracingTest() return false; } + // make sure the TLAS builds before the tracing + oldAsUsageStateInfo = newAsUsageStateInfo; + newAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + newAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; + + result = palMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set memory barrier: %s", error); + return false; + } + result = palTraceRays(cmdBuffer, BUFFER_SIZE, BUFFER_SIZE, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/shaders/raygen.spv b/tests/shaders/raygen.spv index eca6aea295927cafcfc3df9fff287ca2b5d0d8ff..24c7895338e7f6e52c32f1a7ae63ea24c0e6f674 100644 GIT binary patch literal 2320 zcmZ9MYj2cQ5XVpV(jru(mHQaV(|X zX*jJc-K*c4zg_P(9@l%_#%gP09pB+Jglo07Qk&Z9HK)#HaMN!S{*lPJ??R{@wnY-G_Q5qoh}f*l-G+u7avC);@jw9#JDQCUC;BM zA6R=5?9kt}&F2Ul`SufO>_m2p{X7SWF@FVd90re|<@Bw9ccJAJ=Xax>w|ks-KSPN8 zA)xZc*a^k#?~il zy@+kReE46&b_BlMhrgbpGW|Y9^iiA(zZvY5o=&@`Ygm7Ar~12Ru{|Xhd9H&akNWw6 zLb`!AzKV8;jThSs4%hRHK1cq|v3sf^o$+UvqMikCN>Apz(?zTbGK4rUUP2t6%QD&= z{-;Md9s5k~7`8nowyry9?^4dX#P*n+^WWySu@~q`d&Zm&&-`zgGTK=C$alc=5A6RQ z*uLPnUf>G$#18C#9sb^>|MnpE-xgnCJ^S%x#99|&<@e^Cyu3wGw1gp=Q-UVGv#L@r|9#@<=)J8<$5^DegBFVta<_Ym{Q zKg+rIbN&SS=bSr*E$=^Tz23K6tUZOj^E^L|@)2_uTQ2H7 zhixADsP{a!{9wHo!17VA{U~Sc_M&fvcj_5jMchx|X>9$M@^@txTOauuWHjeL!?wSC zFZw=3a-<~hI&=A)d2e9fM0_j6zCX7RYYF^CW~cOEY&7%rTzpIHqYz_ih`tMmYZz}Y z-b3u8$oD0-^UL`i-p7`61osuTocjpw>zpf~m-ri((cd7(>+k#wGRvyID-V#ni0_s) NxOX{Y{vq>4L4z8A>;^+ZZl^lv-8 z9Uar)MKA}Jz+rUvoK8t1C)Z6K9JuYIa={#~U>}@-}J)C>D^Q1rM zbnguMgCQn-CCwxEzf-TJMf7fOxV1Uz4cxRdxYtp?vxg|`d&sr@(eC~zQMHz|UAw)< zTYaLe>Djm%c;5P=;_6)Uu&$jhvL2)O!pR>D+Uqwy;^BUB)pJ%>0*82js%XoWR z&lPsmJ5Hv#v()jn)lZUR{W@@+#-2pV>91oSLdpsKQ%L>R(C>aqK>lX7-M3uW&aZ9! zab)zE$F|nV><{~8Y}YBeypF5`dn>i0_bj@#>cCumaUNk`giGmQ=?b0dXm0>xgg$4w zg#42`sUw|PdoFX4_a=7aDV^ss(w=cvZ=pMneDq&HXDx+&qc9JC`RhbE-9oqj?Se~% zZGY{h%$esIErWkS)LAL~PglIdyXbXL0{XQ-11{%mAf2-c&T@LbE4g#%zA0_z_#Elo z$vKC%Z%R)8de+Uo&Kq>!)^t_C-!L_#xxSmj!1D;(Z#rz>0Z0Dao<%=DW_y04)0IS zeEVDja?$rXdi4D<*Z3gE>3az0yZsQzyMp@&UCz5|eskJ&BWQ*Hv6uy+qH(vimuuRu= Date: Fri, 13 Feb 2026 16:45:43 +0000 Subject: [PATCH 093/372] start API renaming and cleanup --- include/pal/pal_graphics.h | 144 +++---- src/graphics/pal_graphics.c | 790 ++++++++++++++++++++---------------- src/graphics/pal_vulkan.c | 750 +++++++++++++++++----------------- tests/clear_color_test.c | 12 +- tests/compute_test.c | 20 +- tests/mesh_test.c | 20 +- tests/ray_tracing_test.c | 35 +- tests/tests_main.c | 10 +- tests/triangle_test.c | 30 +- 9 files changed, 968 insertions(+), 843 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 9896252b..478d2710 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -204,6 +204,7 @@ typedef enum { typedef enum { PAL_IMAGE_USAGE_UNDEFINED = 0, + PAL_IMAGE_USAGE_COLOR_ATTACHEMENT = PAL_BIT(0), PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT = PAL_BIT(1), PAL_IMAGE_USAGE_TRANSFER_SRC = PAL_BIT(2), @@ -214,6 +215,8 @@ typedef enum { typedef enum { PAL_IMAGE_VIEW_USAGE_UNDEFINED = 0, + + PAL_IMAGE_VIEW_USAGE_COLOR = PAL_BIT(0), PAL_IMAGE_VIEW_USAGE_DEPTH = PAL_BIT(1), PAL_IMAGE_VIEW_USAGE_STENCIL = PAL_BIT(2), @@ -280,6 +283,7 @@ typedef enum { PAL_MEMORY_TYPE_GPU_ONLY, PAL_MEMORY_TYPE_CPU_UPLOAD, PAL_MEMORY_TYPE_CPU_READBACK, + PAL_MEMORY_TYPE_MAX } PalMemoryType; @@ -310,6 +314,7 @@ typedef enum { typedef enum { PAL_SHADER_STAGE_UNDEFINED, + PAL_SHADER_STAGE_VERTEX, PAL_SHADER_STAGE_FRAGMENT, PAL_SHADER_STAGE_COMPUTE, @@ -462,6 +467,7 @@ typedef enum { typedef enum { PAL_COLOR_MASK_NONE = 0, + PAL_COLOR_MASK_RED = PAL_BIT(0), PAL_COLOR_MASK_GREEN = PAL_BIT(1), PAL_COLOR_MASK_BLUE = PAL_BIT(2), @@ -470,6 +476,7 @@ typedef enum { typedef enum { PAL_RESOLVE_MODE_NONE = 0, + PAL_RESOLVE_MODE_SAMPLE_ZERO, PAL_RESOLVE_MODE_AVERAGE, PAL_RESOLVE_MODE_MIN, @@ -537,6 +544,7 @@ enum PalDebugMessageType { typedef enum { PAL_USAGE_STATE_UNDEFINED, + PAL_USAGE_STATE_PRESENT, PAL_USAGE_STATE_COLOR_ATTACHMENT_READ, PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE, @@ -1287,36 +1295,36 @@ typedef struct { void PAL_CALL (*freeCommandBuffer)(PalCommandBuffer* cmdBuffer); - PalResult PAL_CALL (*beginCommandBuffer)( + PalResult PAL_CALL (*resetCommandBuffer)(PalCommandBuffer* cmdBuffer); + + PalResult PAL_CALL (*cmdBegin)( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); - PalResult PAL_CALL (*endCommandBuffer)(PalCommandBuffer* cmdBuffer); - - PalResult PAL_CALL (*resetCommandBuffer)(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL (*cmdEnd)(PalCommandBuffer* cmdBuffer); - PalResult PAL_CALL (*executeCommandBuffer)( + PalResult PAL_CALL (*cmdExecuteCommandBuffer)( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); - PalResult PAL_CALL (*setFragmentShadingRate)( + PalResult PAL_CALL (*cmdSetFragmentShadingRate)( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state); - PalResult PAL_CALL (*drawMeshTasks)( + PalResult PAL_CALL (*cmdDrawMeshTasks)( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, Uint32 groupCountZ); - PalResult PAL_CALL (*drawMeshTasksIndirect)( + PalResult PAL_CALL (*cmdDrawMeshTasksIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 drawCount, Uint32 stride); - PalResult PAL_CALL (*drawMeshTasksIndirectCount)( + PalResult PAL_CALL (*cmdDrawMeshTasksIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -1325,17 +1333,17 @@ typedef struct { Uint32 maxDrawCount, Uint32 stride); - PalResult PAL_CALL (*buildAccelerationStructure)( + PalResult PAL_CALL (*cmdBuildAccelerationStructure)( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); - PalResult PAL_CALL (*beginRendering)( + PalResult PAL_CALL (*cmdBeginRendering)( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info); - PalResult PAL_CALL (*endRendering)(PalCommandBuffer* cmdBuffer); + PalResult PAL_CALL (*cmdEndRendering)(PalCommandBuffer* cmdBuffer); - PalResult PAL_CALL (*copyBuffer)( + PalResult PAL_CALL (*cmdCopyBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -1343,44 +1351,44 @@ typedef struct { Uint64 srcOffset, Uint32 size); - PalResult PAL_CALL (*bindPipeline)( + PalResult PAL_CALL (*cmdBindPipeline)( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline); - PalResult PAL_CALL (*setViewport)( + PalResult PAL_CALL (*cmdSetViewport)( PalCommandBuffer* cmdBuffer, Uint32 count, PalViewport* viewports); - PalResult PAL_CALL (*setScissors)( + PalResult PAL_CALL (*cmdSetScissors)( PalCommandBuffer* cmdBuffer, Uint32 count, PalRect2D* scissors); - PalResult PAL_CALL (*bindVertexBuffers)( + PalResult PAL_CALL (*cmdBindVertexBuffers)( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, PalBuffer** buffers, Uint64* offsets); - PalResult PAL_CALL (*bindIndexBuffer)( + PalResult PAL_CALL (*cmdBindIndexBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, PalIndexType type); - PalResult PAL_CALL (*draw)( + PalResult PAL_CALL (*cmdDraw)( PalCommandBuffer* cmdBuffer, PalDrawData* data); - PalResult PAL_CALL (*drawIndirect)( + PalResult PAL_CALL (*cmdDrawIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 count); - PalResult PAL_CALL (*drawIndirectCount)( + PalResult PAL_CALL (*cmdDrawIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -1388,17 +1396,17 @@ typedef struct { Uint64 countBufferOffset, Uint32 count); - PalResult PAL_CALL (*drawIndexed)( + PalResult PAL_CALL (*cmdDrawIndexed)( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data); - PalResult PAL_CALL (*drawIndexedIndirect)( + PalResult PAL_CALL (*cmdDrawIndexedIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 count); - PalResult PAL_CALL (*drawIndexedIndirectCount)( + PalResult PAL_CALL (*cmdDrawIndexedIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -1406,30 +1414,30 @@ typedef struct { Uint64 countBufferOffset, Uint32 count); - PalResult PAL_CALL (*memoryBarrier)( + PalResult PAL_CALL (*cmdMemoryBarrier)( PalCommandBuffer* cmdBuffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); - PalResult PAL_CALL (*imageViewBarrier)( + PalResult PAL_CALL (*cmdImageViewBarrier)( PalCommandBuffer* cmdBuffer, PalImageView* imageView, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); - PalResult PAL_CALL (*bufferBarrier)( + PalResult PAL_CALL (*cmdBufferBarrier)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); - PalResult PAL_CALL (*dispatch)( + PalResult PAL_CALL (*cmdDispatch)( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, Uint32 groupCountZ); - PalResult PAL_CALL (*dispatchBase)( + PalResult PAL_CALL (*cmdDispatchBase)( PalCommandBuffer* cmdBuffer, Uint32 baseGroupX, Uint32 baseGroupY, @@ -1438,29 +1446,29 @@ typedef struct { Uint32 groupCountY, Uint32 groupCountZ); - PalResult PAL_CALL (*dispatchIndirect)( + PalResult PAL_CALL (*cmdDispatchIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset); - PalResult PAL_CALL (*traceRays)( + PalResult PAL_CALL (*cmdTraceRays)( PalCommandBuffer* cmdBuffer, Uint32 width, Uint32 height, Uint32 depth); - PalResult PAL_CALL (*traceRaysIndirect)( + PalResult PAL_CALL (*cmdTraceRaysIndirect)( PalCommandBuffer* cmdBuffer, PalDeviceAddress bufferAddress); - PalResult PAL_CALL (*bindDescriptorSet)( + PalResult PAL_CALL (*cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set); - PalResult PAL_CALL (*pushConstants)( + PalResult PAL_CALL (*cmdPushConstants)( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, Uint32 shaderStageCount, @@ -1784,36 +1792,36 @@ PAL_API PalResult PAL_CALL palAllocateCommandBuffer( PAL_API void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer); -PAL_API PalResult PAL_CALL palBeginCommandBuffer( +PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); + +PAL_API PalResult PAL_CALL palCmdBegin( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); -PAL_API PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer); - -PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); +PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); -PAL_API PalResult PAL_CALL palExecuteCommandBuffer( +PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); -PAL_API PalResult PAL_CALL palSetFragmentShadingRate( +PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state); -PAL_API PalResult PAL_CALL palDrawMeshTasks( +PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, Uint32 groupCountZ); -PAL_API PalResult PAL_CALL palDrawMeshTasksIndirect( +PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 drawCount, Uint32 stride); -PAL_API PalResult PAL_CALL palDrawMeshTasksIndirectCount( +PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -1822,17 +1830,17 @@ PAL_API PalResult PAL_CALL palDrawMeshTasksIndirectCount( Uint32 maxDrawCount, Uint32 stride); -PAL_API PalResult PAL_CALL palBuildAccelerationStructure( +PAL_API PalResult PAL_CALL palCmdBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); -PAL_API PalResult PAL_CALL palBeginRendering( +PAL_API PalResult PAL_CALL palCmdBeginRendering( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info); -PAL_API PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer); +PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); -PAL_API PalResult PAL_CALL palCopyBuffer( +PAL_API PalResult PAL_CALL palCmdCopyBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -1840,44 +1848,44 @@ PAL_API PalResult PAL_CALL palCopyBuffer( Uint64 srcOffset, Uint32 size); -PAL_API PalResult PAL_CALL palBindPipeline( +PAL_API PalResult PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline); -PAL_API PalResult PAL_CALL palSetViewport( +PAL_API PalResult PAL_CALL palCmdSetViewport( PalCommandBuffer* cmdBuffer, Uint32 count, PalViewport* viewports); -PAL_API PalResult PAL_CALL palSetScissors( +PAL_API PalResult PAL_CALL palCmdSetScissors( PalCommandBuffer* cmdBuffer, Uint32 count, PalRect2D* scissors); -PAL_API PalResult PAL_CALL palBindVertexBuffers( +PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, PalBuffer** buffers, Uint64* offsets); -PAL_API PalResult PAL_CALL palBindIndexBuffer( +PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, PalIndexType type); -PAL_API PalResult PAL_CALL palDraw( +PAL_API PalResult PAL_CALL palCmdDraw( PalCommandBuffer* cmdBuffer, PalDrawData* data); -PAL_API PalResult PAL_CALL palDrawIndirect( +PAL_API PalResult PAL_CALL palCmdDrawIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 count); -PAL_API PalResult PAL_CALL palDrawIndirectCount( +PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -1885,17 +1893,17 @@ PAL_API PalResult PAL_CALL palDrawIndirectCount( Uint64 countBufferOffset, Uint32 count); -PAL_API PalResult PAL_CALL palDrawIndexed( +PAL_API PalResult PAL_CALL palCmdDrawIndexed( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data); -PAL_API PalResult PAL_CALL palDrawIndexedIndirect( +PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 count); -PAL_API PalResult PAL_CALL palDrawIndexedIndirectCount( +PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -1903,30 +1911,30 @@ PAL_API PalResult PAL_CALL palDrawIndexedIndirectCount( Uint64 countBufferOffset, Uint32 count); -PAL_API PalResult PAL_CALL palMemoryBarrier( +PAL_API PalResult PAL_CALL palCmdMemoryBarrier( PalCommandBuffer* cmdBuffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); -PAL_API PalResult PAL_CALL palImageViewBarrier( +PAL_API PalResult PAL_CALL palCmdImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); -PAL_API PalResult PAL_CALL palBufferBarrier( +PAL_API PalResult PAL_CALL palCmdBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); -PAL_API PalResult PAL_CALL palDispatch( +PAL_API PalResult PAL_CALL palCmdDispatch( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, Uint32 groupCountZ); -PAL_API PalResult PAL_CALL palDispatchBase( +PAL_API PalResult PAL_CALL palCmdDispatchBase( PalCommandBuffer* cmdBuffer, Uint32 baseGroupX, Uint32 baseGroupY, @@ -1935,29 +1943,29 @@ PAL_API PalResult PAL_CALL palDispatchBase( Uint32 groupCountY, Uint32 groupCountZ); -PAL_API PalResult PAL_CALL palDispatchIndirect( +PAL_API PalResult PAL_CALL palCmdDispatchIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset); -PAL_API PalResult PAL_CALL palTraceRays( +PAL_API PalResult PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, Uint32 width, Uint32 height, Uint32 depth); -PAL_API PalResult PAL_CALL palTraceRaysIndirect( +PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, PalDeviceAddress bufferAddress); -PAL_API PalResult PAL_CALL palBindDescriptorSet( +PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set); -PAL_API PalResult PAL_CALL palPushConstants( +PAL_API PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, Uint32 shaderStageCount, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 056c21e5..7897d01f 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -103,235 +103,235 @@ PalResult PAL_CALL initGraphicsVk( PalResult PAL_CALL shutdownGraphicsVk(); -PalResult PAL_CALL enumerateVkAdapters( +PalResult PAL_CALL enumerateAdaptersVk( Int32* count, PalAdapter** outAdapters); -PalResult PAL_CALL getVkAdapterInfo( +PalResult PAL_CALL getAdapterInfoVk( PalAdapter* adapter, PalAdapterInfo* info); -PalResult PAL_CALL getVkAdapterCapabilities( +PalResult PAL_CALL getAdapterCapabilitiesVk( PalAdapter* adapter, PalAdapterCapabilities* caps); -PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter); +PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter); -PalResult PAL_CALL createVkDevice( +PalResult PAL_CALL createDeviceVk( PalAdapter* adapter, PalAdapterFeatures features, PalDevice** outDevice); -void PAL_CALL destroyVkDevice(PalDevice* device); +void PAL_CALL destroyDeviceVk(PalDevice* device); -PalResult PAL_CALL waitVkDevice(PalDevice* device); +PalResult PAL_CALL waitDeviceVk(PalDevice* device); -PalResult PAL_CALL allocateVkMemory( +PalResult PAL_CALL allocateMemoryVk( PalDevice* device, PalMemoryType type, Uint64 memoryMask, Uint64 size, PalMemory** outMemory); -void PAL_CALL freeVkMemory( +void PAL_CALL freeMemoryVk( PalDevice* device, PalMemory* memory); -PalResult PAL_CALL queryVkDepthStencilCapabilities( +PalResult PAL_CALL queryDepthStencilCapabilitiesVk( PalDevice* device, PalDepthStencilCapabilities* caps); -PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk( PalDevice* device, PalFragmentShadingRateCapabilities* caps); -PalResult PAL_CALL queryVkMeshShaderCapabilities( +PalResult PAL_CALL queryMeshShaderCapabilitiesVk( PalDevice* device, PalMeshShaderCapabilities* caps); -PalResult PAL_CALL queryVkRayTracingCapabilities( +PalResult PAL_CALL queryRayTracingCapabilitiesVk( PalDevice* device, PalRayTracingCapabilities* caps); -PalResult PAL_CALL queryVkDescriptorIndexingCapabilities( +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( PalDevice* device, PalDescriptorIndexingCapabilities* caps); -PalResult PAL_CALL createVkQueue( +PalResult PAL_CALL createQueueVk( PalDevice* device, PalQueueType type, PalQueue** outQueue); -void PAL_CALL destroyVkQueue(PalQueue* queue); +void PAL_CALL destroyQueueVk(PalQueue* queue); -PalResult PAL_CALL waitVkQueue(PalQueue* queue); +PalResult PAL_CALL waitQueueVk(PalQueue* queue); -bool PAL_CALL canVkQueuePresent( +bool PAL_CALL canQueuePresentVk( PalQueue* queue, PalGraphicsWindow* window); -PalResult PAL_CALL enumerateVkFormats( +PalResult PAL_CALL enumerateFormatsVk( PalAdapter* adapter, Int32* count, PalFormatInfo* outFormats); -bool PAL_CALL isVkFormatSupported( +bool PAL_CALL isFormatSupportedVk( PalAdapter* adapter, PalFormat format); -PalImageUsages PAL_CALL queryVkFormatImageUsages( +PalImageUsages PAL_CALL queryFormatImageUsagesVk( PalAdapter* adapter, PalFormat format); -PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( +PalImageViewUsages PAL_CALL queryFormatImageViewUsagesVk( PalAdapter* adapter, PalFormat format); -PalResult PAL_CALL createVkImage( +PalResult PAL_CALL createImageVk( PalDevice* device, const PalImageCreateInfo* info, PalImage** outImage); -void PAL_CALL destroyVkImage(PalImage* image); +void PAL_CALL destroyImageVk(PalImage* image); -PalResult PAL_CALL getVkImageInfo( +PalResult PAL_CALL getImageInfoVk( PalImage* image, PalImageInfo* info); -PalResult PAL_CALL getVkImageMemoryRequirements( +PalResult PAL_CALL getImageMemoryRequirementsVk( PalImage* image, PalMemoryRequirements* requirements); -PalResult PAL_CALL bindVkImageMemory( +PalResult PAL_CALL bindImageMemoryVk( PalImage* image, PalMemory* memory, Uint64 offset); -PalResult PAL_CALL createVkImageView( +PalResult PAL_CALL createImageViewVk( PalDevice* device, PalImage* image, const PalImageViewCreateInfo* info, PalImageView** outImageView); -void PAL_CALL destroyVkImageView(PalImageView* imageView); +void PAL_CALL destroyImageViewVk(PalImageView* imageView); -PalResult PAL_CALL queryVkSwapchainCapabilities( +PalResult PAL_CALL querySwapchainCapabilitiesVk( PalDevice* device, PalGraphicsWindow* window, PalSwapchainCapabilities* caps); -PalResult PAL_CALL createVkSwapchain( +PalResult PAL_CALL createSwapchainVk( PalDevice* device, PalQueue* queue, PalGraphicsWindow* window, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain); -void PAL_CALL destroyVkSwapchain(PalSwapchain* swapchain); +void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain); -PalImage* PAL_CALL getVkSwapchainImage( +PalImage* PAL_CALL getSwapchainImageVk( PalSwapchain* swapchain, Int32 index); -PalResult PAL_CALL getVkNextSwapchainImage( +PalResult PAL_CALL getNextSwapchainImageVk( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, Uint32* outIndex); -PalResult PAL_CALL presentVkSwapchain( +PalResult PAL_CALL presentSwapchainVk( PalSwapchain* swapchain, PalSwapchainPresentInfo* info); -PalResult PAL_CALL createVkShader( +PalResult PAL_CALL createShaderVk( PalDevice* device, const PalShaderCreateInfo* info, PalShader** outShader); -void PAL_CALL destroyVkShader(PalShader* shader); +void PAL_CALL destroyShaderVk(PalShader* shader); -PalResult PAL_CALL createVkFence( +PalResult PAL_CALL createFenceVk( PalDevice* device, bool signaled, PalFence** outFence); -void PAL_CALL destroyVkFence(PalFence* fence); +void PAL_CALL destroyFenceVk(PalFence* fence); -PalResult PAL_CALL waitVkFence( +PalResult PAL_CALL waitFenceVk( PalFence* fence, Uint64 timeout); -PalResult PAL_CALL resetVkFence(PalFence* fence); +PalResult PAL_CALL resetFenceVk(PalFence* fence); -bool PAL_CALL isVkFenceSignaled(PalFence* fence); +bool PAL_CALL isFenceSignaledVk(PalFence* fence); -PalResult PAL_CALL createVkSemaphore( +PalResult PAL_CALL createSemaphoreVk( PalDevice* device, PalSemaphore** outSemaphore); -void PAL_CALL destroyVkSemaphore(PalSemaphore* semaphore); +void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore); -PalResult PAL_CALL waitVkSemaphore( +PalResult PAL_CALL waitSemaphoreVk( PalSemaphore* semaphore, PalQueue* queue, Uint64 value, Uint64 timeout); -PalResult PAL_CALL signalVkSemaphore( +PalResult PAL_CALL signalSemaphoreVk( PalSemaphore* semaphore, PalQueue* queue, Uint64 value); -PalResult PAL_CALL getVkSemaphoreValue( +PalResult PAL_CALL getSemaphoreValueVk( PalSemaphore* semaphore, Uint64* value); -PalResult PAL_CALL createVkCommandPool( +PalResult PAL_CALL createCommandPoolVk( PalDevice* device, PalQueue* queue, PalCommandPool** outPool); -void PAL_CALL destroyVkCommandPool(PalCommandPool* pool); +void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool); -PalResult PAL_CALL resetVkCommandPool(PalCommandPool* pool); +PalResult PAL_CALL resetCommandPoolVk(PalCommandPool* pool); -PalResult PAL_CALL allocateVkCommandBuffer( +PalResult PAL_CALL allocateCommandBufferVk( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, PalCommandBuffer** outBuffer); -void PAL_CALL freeVkCommandBuffer(PalCommandBuffer* buffer); +void PAL_CALL freeCommandBufferVk(PalCommandBuffer* buffer); -PalResult PAL_CALL beginVkCommandBuffer( +PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdBeginVk( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); -PalResult PAL_CALL endVkCommandBuffer(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL resetVkCommandBuffer(PalCommandBuffer* cmdBuffer); +PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer); -PalResult PAL_CALL executeCommandBufferVk( +PalResult PAL_CALL cmdExecuteCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); -PalResult PAL_CALL setVkFragmentShadingRate( +PalResult PAL_CALL cmdSetFragmentShadingRateVk( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state); -PalResult PAL_CALL drawVkMeshTasks( +PalResult PAL_CALL cmdDrawMeshTasksVk( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, Uint32 groupCountZ); -PalResult PAL_CALL drawVkMeshTasksIndirect( +PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 drawCount, Uint32 stride); -PalResult PAL_CALL drawVkMeshTasksIndirectCount( +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -340,17 +340,17 @@ PalResult PAL_CALL drawVkMeshTasksIndirectCount( Uint32 maxDrawCount, Uint32 stride); -PalResult PAL_CALL buildVkAccelerationStructure( +PalResult PAL_CALL cmdBuildAccelerationStructureVk( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); -PalResult PAL_CALL beginRenderingVk( +PalResult PAL_CALL cmdBeginRenderingVk( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info); -PalResult PAL_CALL endRenderingVk(PalCommandBuffer* cmdBuffer); +PalResult PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer); -PalResult PAL_CALL copyVkBuffer( +PalResult PAL_CALL cmdCopyBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -358,44 +358,44 @@ PalResult PAL_CALL copyVkBuffer( Uint64 srcOffset, Uint32 size); -PalResult PAL_CALL bindVkPipeline( +PalResult PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline); -PalResult PAL_CALL setVkViewport( +PalResult PAL_CALL cmdSetViewportVk( PalCommandBuffer* cmdBuffer, Uint32 count, PalViewport* viewports); -PalResult PAL_CALL setVkScissors( +PalResult PAL_CALL cmdSetScissorsVk( PalCommandBuffer* cmdBuffer, Uint32 count, PalRect2D* scissors); -PalResult PAL_CALL bindVkVertexBuffers( +PalResult PAL_CALL cmdBindVertexBuffersVk( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, PalBuffer** buffers, Uint64* offsets); -PalResult PAL_CALL bindVkIndexBuffer( +PalResult PAL_CALL cmdBindIndexBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, PalIndexType type); -PalResult PAL_CALL drawVk( +PalResult PAL_CALL cmdDrawVk( PalCommandBuffer* cmdBuffer, PalDrawData* data); -PalResult PAL_CALL drawIndirectVk( +PalResult PAL_CALL cmdDrawIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 count); -PalResult PAL_CALL drawIndirectCountVk( +PalResult PAL_CALL cmdDrawIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -403,17 +403,17 @@ PalResult PAL_CALL drawIndirectCountVk( Uint64 countBufferOffset, Uint32 count); -PalResult PAL_CALL drawIndexedVk( +PalResult PAL_CALL cmdDrawIndexedVk( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data); -PalResult PAL_CALL drawIndexedIndirectVk( +PalResult PAL_CALL cmdDrawIndexedIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 count); -PalResult PAL_CALL drawIndexedIndirectCountVk( +PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -421,30 +421,30 @@ PalResult PAL_CALL drawIndexedIndirectCountVk( Uint64 countBufferOffset, Uint32 count); -PalResult PAL_CALL memoryBarrierVk( +PalResult PAL_CALL cmdMemoryBarrierVk( PalCommandBuffer* cmdBuffer, - PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* oldsUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); -PalResult PAL_CALL imageViewBarrierVk( +PalResult PAL_CALL cmdImageViewBarrierVk( PalCommandBuffer* cmdBuffer, PalImageView* imageView, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); -PalResult PAL_CALL bufferBarrierVk( +PalResult PAL_CALL cmdBufferBarrierVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); -PalResult PAL_CALL dispatchVk( +PalResult PAL_CALL cmdDispatchVk( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, Uint32 groupCountZ); -PalResult PAL_CALL dispatchBaseVk( +PalResult PAL_CALL cmdDispatchBaseVk( PalCommandBuffer* cmdBuffer, Uint32 baseGroupX, Uint32 baseGroupY, @@ -453,29 +453,29 @@ PalResult PAL_CALL dispatchBaseVk( Uint32 groupCountY, Uint32 groupCountZ); -PalResult PAL_CALL dispatchIndirectVk( +PalResult PAL_CALL cmdDispatchIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset); -PalResult PAL_CALL traceRaysVk( +PalResult PAL_CALL cmdTraceRaysVk( PalCommandBuffer* cmdBuffer, Uint32 width, Uint32 height, Uint32 depth); -PalResult PAL_CALL traceRaysIndirectVk( +PalResult PAL_CALL cmdTraceRaysIndirectVk( PalCommandBuffer* cmdBuffer, PalDeviceAddress bufferAddress); -PalResult PAL_CALL bindVkDescriptorSet( +PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set); -PalResult PAL_CALL pushConstantsVk( +PalResult PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, Uint32 shaderStageCount, @@ -484,227 +484,264 @@ PalResult PAL_CALL pushConstantsVk( Uint32 size, const void* value); -PalResult PAL_CALL submitVkCommandBuffer( +PalResult PAL_CALL submitCommandBufferVk( PalQueue* queue, PalCommandBufferSubmitInfo* info); -PalResult PAL_CALL createVkAccelerationstructure( +PalResult PAL_CALL createAccelerationstructureVk( PalDevice* device, const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs); -void PAL_CALL destroyVkAccelerationstructure(PalAccelerationStructure* as); +void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as); -PalResult PAL_CALL getVkAccelerationStructureBuildSize( +PalResult PAL_CALL getAccelerationStructureBuildSizeVk( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); -PalResult PAL_CALL createVkBuffer( +PalResult PAL_CALL createBufferVk( PalDevice* device, const PalBufferCreateInfo* info, PalBuffer** outBuffer); -void PAL_CALL destroyVkBuffer(PalBuffer* buffer); +void PAL_CALL destroyBufferVk(PalBuffer* buffer); -PalResult PAL_CALL getVkBufferMemoryRequirements( +PalResult PAL_CALL getBufferMemoryRequirementsVk( PalBuffer* buffer, PalMemoryRequirements* requirements); -PalResult PAL_CALL computeVkInstanceBufferRequirements( +PalResult PAL_CALL computeInstanceBufferRequirementsVk( PalDevice* device, PalInstanceBufferRequirements* requirements, Uint32 instanceCount); -PalResult PAL_CALL writeVkInstancesToMappedMemory( +PalResult PAL_CALL writeInstancesToMappedMemoryVk( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, Uint32 instanceCount); -PalResult PAL_CALL bindVkBufferMemory( +PalResult PAL_CALL bindBufferMemoryVk( PalBuffer* buffer, PalMemory* memory, Uint64 offset); -PalDeviceAddress PAL_CALL getVkBufferDeviceAddress(PalBuffer* buffer); +PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer); -PalResult PAL_CALL mapVkMemory( +PalResult PAL_CALL mapMemoryVk( PalDevice* device, PalMemory* memory, Uint64 offset, Uint64 size, void** outPtr); -void PAL_CALL unmapVkMemory( +void PAL_CALL unmapMemoryVk( PalDevice* device, PalMemory* memory); -PalResult PAL_CALL createVkDescriptorSetLayout( +PalResult PAL_CALL createDescriptorSetLayoutVk( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout); -void PAL_CALL destroyVkDescriptorSetLayout(PalDescriptorSetLayout* layout); +void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout); -PalResult PAL_CALL createVkDescriptorPool( +PalResult PAL_CALL createDescriptorPoolVk( PalDevice* device, const PalDescriptorPoolCreateInfo* info, PalDescriptorPool** outPool); -void PAL_CALL destroyVkDescriptorPool(PalDescriptorPool* pool); +void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool); -PalResult PAL_CALL resetVkDescriptorPool(PalDescriptorPool* pool); +PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool); -PalResult PAL_CALL allocateVkDescriptorSet( +PalResult PAL_CALL allocateDescriptorSetVk( PalDevice* device, PalDescriptorPool* pool, PalDescriptorSetLayout* layout, PalDescriptorSet** outSet); -void PAL_CALL freeVkDescriptorSet(PalDescriptorSet* set); +void PAL_CALL freeDescriptorSetVk(PalDescriptorSet* set); -PalResult PAL_CALL updateVkDescriptorSet( +PalResult PAL_CALL updateDescriptorSetVk( PalDevice* device, Uint32 count, PalDescriptorSetWriteInfo* infos); -PalResult PAL_CALL createVkPipelineLayout( +PalResult PAL_CALL createPipelineLayoutVk( PalDevice* device, const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout); -void PAL_CALL destroyVkPipelineLayout(PalPipelineLayout* layout); +void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout); -PalResult PAL_CALL createVkGraphicsPipeline( +PalResult PAL_CALL createGraphicsPipelineVk( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline); -PalResult PAL_CALL createVkComputePipeline( +PalResult PAL_CALL createComputePipelineVk( PalDevice* device, const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline); -PalResult PAL_CALL createVkRayTracingPipeline( +PalResult PAL_CALL createRayTracingPipelineVk( PalDevice* device, const PalRayTracingPipelineCreateInfo* info, PalPipeline** outPipeline); -void PAL_CALL destroyVkPipeline(PalPipeline* pipeline); +void PAL_CALL destroyPipelineVk(PalPipeline* pipeline); static PalGraphicsBackend s_VkBackend = { - .enumerateAdapters = enumerateVkAdapters, - .getAdapterInfo = getVkAdapterInfo, - .getAdapterCapabilities = getVkAdapterCapabilities, - .getAdapterFeatures = getVkAdapterFeatures, - .createDevice = createVkDevice, - .destroyDevice = destroyVkDevice, - .waitDevice = waitVkDevice, - .allocateMemory = allocateVkMemory, - .freeMemory = freeVkMemory, - .mapMemory = mapVkMemory, - .unmapMemory = unmapVkMemory, - .queryDepthStencilCapabilities = queryVkDepthStencilCapabilities, - .queryFragmentShadingRateCapabilities = queryVkFragmentShadingRateCapabilities, - .queryMeshShaderCapabilities = queryVkMeshShaderCapabilities, - .queryRayTracingCapabilities = queryVkRayTracingCapabilities, - .queryDescriptorIndexingCapabilities = queryVkDescriptorIndexingCapabilities, - .createQueue = createVkQueue, - .destroyQueue = destroyVkQueue, - .waitQueue = waitVkQueue, - .canQueuePresent = canVkQueuePresent, - .enumerateFormats = enumerateVkFormats, - .isFormatSupported = isVkFormatSupported, - .queryFormatImageUsages = queryVkFormatImageUsages, - .queryFormatImageViewUsages = queryVkFormatImageViewUsages, - .createImage = createVkImage, - .destroyImage = destroyVkImage, - .getImageInfo = getVkImageInfo, - .getImageMemoryRequirements = getVkImageMemoryRequirements, - .bindImageMemory = bindVkImageMemory, - .createImageView = createVkImageView, - .destroyImageView = destroyVkImageView, - .querySwapchainCapabilities = queryVkSwapchainCapabilities, - .createSwapchain = createVkSwapchain, - .destroySwapchain = destroyVkSwapchain, - .getSwapchainImage = getVkSwapchainImage, - .getNextSwapchainImage = getVkNextSwapchainImage, - .presentSwapchain = presentVkSwapchain, - .createShader = createVkShader, - .destroyShader = destroyVkShader, - .createFence = createVkFence, - .destroyFence = destroyVkFence, - .waitFenceTimeout = waitVkFence, - .resetFence = resetVkFence, - .isFenceSignaled = isVkFenceSignaled, - .createSemaphore = createVkSemaphore, - .destroySemaphore = destroyVkSemaphore, - .waitSemaphore = waitVkSemaphore, - .signalSemaphore = signalVkSemaphore, - .getSemaphoreValue = getVkSemaphoreValue, - .createCommandPool = createVkCommandPool, - .destroyCommandPool = destroyVkCommandPool, - .resetCommandPool = resetVkCommandPool, - .allocateCommandBuffer = allocateVkCommandBuffer, - .freeCommandBuffer = freeVkCommandBuffer, - .beginCommandBuffer = beginVkCommandBuffer, - .endCommandBuffer = endVkCommandBuffer, - .resetCommandBuffer = resetVkCommandBuffer, - .executeCommandBuffer = executeCommandBufferVk, - .setFragmentShadingRate = setVkFragmentShadingRate, - .drawMeshTasks = drawVkMeshTasks, - .drawMeshTasksIndirect = drawVkMeshTasksIndirect, - .drawMeshTasksIndirectCount = drawVkMeshTasksIndirectCount, - .buildAccelerationStructure = buildVkAccelerationStructure, - .beginRendering = beginRenderingVk, - .endRendering = endRenderingVk, - .copyBuffer = copyVkBuffer, - .bindPipeline = bindVkPipeline, - .setViewport = setVkViewport, - .setScissors = setVkScissors, - .bindVertexBuffers = bindVkVertexBuffers, - .bindIndexBuffer = bindVkIndexBuffer, - .draw = drawVk, - .drawIndirect = drawIndirectVk, - .drawIndexedIndirectCount = drawIndirectCountVk, - .drawIndexed = drawIndexedVk, - .drawIndexedIndirect = drawIndexedIndirectVk, - .drawIndexedIndirectCount = drawIndexedIndirectCountVk, - .memoryBarrier = memoryBarrierVk, - .imageViewBarrier = imageViewBarrierVk, - .bufferBarrier = bufferBarrierVk, - .dispatch = dispatchVk, - .dispatchBase = dispatchBaseVk, - .dispatchIndirect = dispatchIndirectVk, - .traceRays = traceRaysVk, - .traceRaysIndirect = traceRaysIndirectVk, - .bindDescriptorSet = bindVkDescriptorSet, - .pushConstants = pushConstantsVk, - .submitCommandBuffer = submitVkCommandBuffer, - .createAccelerationstructure = createVkAccelerationstructure, - .destroyAccelerationstructure = destroyVkAccelerationstructure, - .getAccelerationStructureBuildSize = getVkAccelerationStructureBuildSize, - .createBuffer = createVkBuffer, - .destroyBuffer = destroyVkBuffer, - .getBufferMemoryRequirements = getVkBufferMemoryRequirements, - .computeInstanceBufferRequirements = computeVkInstanceBufferRequirements, - .writeInstancesToMappedMemory = writeVkInstancesToMappedMemory, - .bindBufferMemory = bindVkBufferMemory, - .getBufferDeviceAddress = getVkBufferDeviceAddress, - .createDescriptorSetLayout = createVkDescriptorSetLayout, - .destroyDescriptorSetLayout = destroyVkDescriptorSetLayout, - .createDescriptorPool = createVkDescriptorPool, - .destroyDescriptorPool = destroyVkDescriptorPool, - .resetDescriptorPool = resetVkDescriptorPool, - .allocateDescriptorSet = allocateVkDescriptorSet, - .updateDescriptorSet = updateVkDescriptorSet, - .createPipelineLayout = createVkPipelineLayout, - .destroyPipelineLayout = destroyVkPipelineLayout, - .createGraphicsPipeline = createVkGraphicsPipeline, - .createComputePipeline = createVkComputePipeline, - .createRayTracingPipeline = createVkRayTracingPipeline, - .destroyPipeline = destroyVkPipeline}; + // adapter + .enumerateAdapters = enumerateAdaptersVk, + .getAdapterInfo = getAdapterInfoVk, + .getAdapterCapabilities = getAdapterCapabilitiesVk, + .getAdapterFeatures = getAdapterFeaturesVk, + + // device + .createDevice = createDeviceVk, + .destroyDevice = destroyDeviceVk, + .waitDevice = waitDeviceVk, + + // memory + .allocateMemory = allocateMemoryVk, + .freeMemory = freeMemoryVk, + .mapMemory = mapMemoryVk, + .unmapMemory = unmapMemoryVk, + + // extended adapter features + .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesVk, + .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesVk, + .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesVk, + .queryRayTracingCapabilities = queryRayTracingCapabilitiesVk, + .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesVk, + + // queue + .createQueue = createQueueVk, + .destroyQueue = destroyQueueVk, + .waitQueue = waitQueueVk, + .canQueuePresent = canQueuePresentVk, + + // format + .enumerateFormats = enumerateFormatsVk, + .isFormatSupported = isFormatSupportedVk, + .queryFormatImageUsages = queryFormatImageUsagesVk, + .queryFormatImageViewUsages = queryFormatImageViewUsagesVk, + + // image + .createImage = createImageVk, + .destroyImage = destroyImageVk, + .getImageInfo = getImageInfoVk, + .getImageMemoryRequirements = getImageMemoryRequirementsVk, + .bindImageMemory = bindImageMemoryVk, + + // image view + .createImageView = createImageViewVk, + .destroyImageView = destroyImageViewVk, + + // swapchain + .querySwapchainCapabilities = querySwapchainCapabilitiesVk, + .createSwapchain = createSwapchainVk, + .destroySwapchain = destroySwapchainVk, + .getSwapchainImage = getSwapchainImageVk, + .getNextSwapchainImage = getNextSwapchainImageVk, + .presentSwapchain = presentSwapchainVk, + + // shader + .createShader = createShaderVk, + .destroyShader = destroyShaderVk, + + // fence + .createFence = createFenceVk, + .destroyFence = destroyFenceVk, + .waitFenceTimeout = waitFenceVk, + .resetFence = resetFenceVk, + .isFenceSignaled = isFenceSignaledVk, + + // semaphore + .createSemaphore = createSemaphoreVk, + .destroySemaphore = destroySemaphoreVk, + .waitSemaphore = waitSemaphoreVk, + .signalSemaphore = signalSemaphoreVk, + .getSemaphoreValue = getSemaphoreValueVk, + + // command pool and command buffer + .createCommandPool = createCommandPoolVk, + .destroyCommandPool = destroyCommandPoolVk, + .resetCommandPool = resetCommandPoolVk, + .allocateCommandBuffer = allocateCommandBufferVk, + .freeCommandBuffer = freeCommandBufferVk, + .resetCommandBuffer = resetCommandBufferVk, + .submitCommandBuffer = submitCommandBufferVk, + + // command recording + .cmdBegin = cmdBeginVk, + .cmdEnd = cmdEndVk, + .cmdExecuteCommandBuffer = cmdExecuteCommandBufferVk, + .cmdSetFragmentShadingRate = cmdSetFragmentShadingRateVk, + .cmdDrawMeshTasks = cmdDrawMeshTasksVk, + .cmdDrawMeshTasksIndirect = cmdDrawMeshTasksIndirectVk, + .cmdDrawMeshTasksIndirectCount = cmdDrawMeshTasksIndirectCountVk, + .cmdBuildAccelerationStructure = cmdBuildAccelerationStructureVk, + .cmdBeginRendering = cmdBeginRenderingVk, + .cmdEndRendering = cmdEndRenderingVk, + .cmdCopyBuffer = cmdCopyBufferVk, + .cmdBindPipeline = cmdBindPipelineVk, + .cmdSetViewport = cmdSetViewportVk, + .cmdSetScissors = cmdSetScissorsVk, + .cmdBindVertexBuffers = cmdBindVertexBuffersVk, + .cmdBindIndexBuffer = cmdBindIndexBufferVk, + .cmdDraw = cmdDrawVk, + .cmdDrawIndirect = cmdDrawIndirectVk, + .cmdDrawIndexedIndirectCount = cmdDrawIndirectCountVk, + .cmdDrawIndexed = cmdDrawIndexedVk, + .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectVk, + .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountVk, + .cmdMemoryBarrier = cmdMemoryBarrierVk, + .cmdImageViewBarrier = cmdImageViewBarrierVk, + .cmdBufferBarrier = cmdBufferBarrierVk, + .cmdDispatch = cmdDispatchVk, + .cmdDispatchBase = cmdDispatchBaseVk, + .cmdDispatchIndirect = cmdDispatchIndirectVk, + .cmdTraceRays = cmdTraceRaysVk, + .cmdTraceRaysIndirect = cmdTraceRaysIndirectVk, + .cmdBindDescriptorSet = cmdBindDescriptorSetVk, + .cmdPushConstants = cmdPushConstantsVk, + + // acceleration structure + .createAccelerationstructure = createAccelerationstructureVk, + .destroyAccelerationstructure = destroyAccelerationstructureVk, + .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeVk, + + // buffer + .createBuffer = createBufferVk, + .destroyBuffer = destroyBufferVk, + .getBufferMemoryRequirements = getBufferMemoryRequirementsVk, + .computeInstanceBufferRequirements = computeInstanceBufferRequirementsVk, + .writeInstancesToMappedMemory = writeInstancesToMappedMemoryVk, + .bindBufferMemory = bindBufferMemoryVk, + .getBufferDeviceAddress = getBufferDeviceAddressVk, + + // descriptor set layout, descriptor pool and descriptor set + .createDescriptorSetLayout = createDescriptorSetLayoutVk, + .destroyDescriptorSetLayout = destroyDescriptorSetLayoutVk, + .createDescriptorPool = createDescriptorPoolVk, + .destroyDescriptorPool = destroyDescriptorPoolVk, + .resetDescriptorPool = resetDescriptorPoolVk, + .allocateDescriptorSet = allocateDescriptorSetVk, + .updateDescriptorSet = updateDescriptorSetVk, + + // pipeline layout + .createPipelineLayout = createPipelineLayoutVk, + .destroyPipelineLayout = destroyPipelineLayoutVk, + + // pipeline + .createGraphicsPipeline = createGraphicsPipelineVk, + .createComputePipeline = createComputePipelineVk, + .createRayTracingPipeline = createRayTracingPipelineVk, + .destroyPipeline = destroyPipelineVk}; #endif // PAL_HAS_VULKAN @@ -740,95 +777,128 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) // check if all the function pointers are set // clang-format off + // adapter if (!backend->enumerateAdapters || !backend->getAdapterInfo || !backend->getAdapterCapabilities || !backend->getAdapterFeatures || + + // device !backend->createDevice || !backend->destroyDevice || !backend->waitDevice || + + // memory !backend->allocateMemory || !backend->freeMemory || + !backend->mapMemory || + !backend->unmapMemory || + + // extended adapter features !backend->queryDepthStencilCapabilities || !backend->queryFragmentShadingRateCapabilities || !backend->queryMeshShaderCapabilities || !backend->queryRayTracingCapabilities || !backend->queryDescriptorIndexingCapabilities || + + // queue !backend->createQueue || !backend->destroyQueue || !backend->waitQueue || !backend->canQueuePresent || + + // formats !backend->enumerateFormats || !backend->isFormatSupported || !backend->queryFormatImageUsages || !backend->queryFormatImageViewUsages || + + // image !backend->createImage || !backend->destroyImage || !backend->getImageInfo || !backend->getImageMemoryRequirements || !backend->bindImageMemory || + + // image view !backend->createImageView || !backend->destroyImageView || + + // swapchain !backend->querySwapchainCapabilities || !backend->createSwapchain || !backend->destroySwapchain || !backend->getSwapchainImage || !backend->getNextSwapchainImage || !backend->presentSwapchain || + + // shader !backend->createShader || !backend->destroyShader || + + // fence !backend->createFence || !backend->destroyFence || !backend->waitFenceTimeout || !backend->resetFence || !backend->isFenceSignaled || + + // semaphore !backend->createSemaphore || !backend->destroySemaphore || !backend->waitSemaphore || !backend->signalSemaphore || !backend->getSemaphoreValue || + + // command pool and command buffer !backend->createCommandPool || !backend->destroyCommandPool || !backend->resetCommandPool || !backend->allocateCommandBuffer || !backend->freeCommandBuffer || - !backend->beginCommandBuffer || - !backend->endCommandBuffer || - !backend->resetCommandBuffer || - !backend->executeCommandBuffer || - !backend->setFragmentShadingRate || - !backend->drawMeshTasks || - !backend->drawMeshTasksIndirect || - !backend->drawMeshTasksIndirectCount || - !backend->buildAccelerationStructure || - !backend->beginRendering || - !backend->endRendering || - !backend->copyBuffer || - !backend->bindPipeline || - !backend->setViewport || - !backend->setScissors || - !backend->bindVertexBuffers || - !backend->bindIndexBuffer || - !backend->draw || - !backend->drawIndirect || - !backend->drawIndirectCount || - !backend->drawIndexed || - !backend->drawIndexedIndirect || - !backend->drawIndexedIndirectCount || - !backend->memoryBarrier || - !backend->imageViewBarrier || - !backend->bufferBarrier || - !backend->dispatch || - !backend->dispatchBase || - !backend->dispatchIndirect || - !backend->traceRays || - !backend->traceRaysIndirect || - !backend->bindDescriptorSet || - !backend->pushConstants || !backend->submitCommandBuffer || + + // command recording + !backend->cmdBegin || + !backend->cmdEnd || + !backend->resetCommandBuffer || + !backend->cmdExecuteCommandBuffer || + !backend->cmdSetFragmentShadingRate || + !backend->cmdDrawMeshTasks || + !backend->cmdDrawMeshTasksIndirect || + !backend->cmdDrawMeshTasksIndirectCount || + !backend->cmdBuildAccelerationStructure || + !backend->cmdBeginRendering || + !backend->cmdEndRendering || + !backend->cmdCopyBuffer || + !backend->cmdBindPipeline || + !backend->cmdSetViewport || + !backend->cmdSetScissors || + !backend->cmdBindVertexBuffers || + !backend->cmdBindIndexBuffer || + !backend->cmdDraw || + !backend->cmdDrawIndirect || + !backend->cmdDrawIndirectCount || + !backend->cmdDrawIndexed || + !backend->cmdDrawIndexedIndirect || + !backend->cmdDrawIndexedIndirectCount || + !backend->cmdMemoryBarrier || + !backend->cmdImageViewBarrier || + !backend->cmdBufferBarrier || + !backend->cmdDispatch || + !backend->cmdDispatchBase || + !backend->cmdDispatchIndirect || + !backend->cmdTraceRays || + !backend->cmdTraceRaysIndirect || + !backend->cmdBindDescriptorSet || + !backend->cmdPushConstants || + + // acceleration structure !backend->createAccelerationstructure || !backend->destroyAccelerationstructure || !backend->getAccelerationStructureBuildSize || + + // buffer !backend->createBuffer || !backend->destroyBuffer || !backend->getBufferMemoryRequirements || @@ -836,8 +906,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->writeInstancesToMappedMemory || !backend->bindBufferMemory || !backend->getBufferDeviceAddress || - !backend->mapMemory || - !backend->unmapMemory || + + // descriptor set layout, descriptor pool and descriptor set !backend->createDescriptorSetLayout || !backend->destroyDescriptorSetLayout || !backend->createDescriptorPool || @@ -845,8 +915,12 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->resetDescriptorPool || !backend->allocateDescriptorSet || !backend->updateDescriptorSet || + + // pipeline layout !backend->createPipelineLayout || !backend->destroyPipelineLayout || + + // pipeline !backend->createGraphicsPipeline || !backend->createComputePipeline || !backend->createRayTracingPipeline || @@ -1091,6 +1165,10 @@ void PAL_CALL palFreeMemory( } } +// ================================================== +// Extended Adapter Features +// ================================================== + PalResult PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps) @@ -1783,9 +1861,7 @@ void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer) } } -PalResult PAL_CALL palBeginCommandBuffer( - PalCommandBuffer* cmdBuffer, - PalRenderingLayoutInfo* info) +PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1795,10 +1871,31 @@ PalResult PAL_CALL palBeginCommandBuffer( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->beginCommandBuffer(cmdBuffer, info); + return cmdBuffer->backend->resetCommandBuffer(cmdBuffer); } -PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL palSubmitCommandBuffer( + PalQueue* queue, + PalCommandBufferSubmitInfo* info) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!queue || !info) { + return PAL_RESULT_NULL_POINTER; + } + + return queue->backend->submitCommandBuffer(queue, info); +} + +// ================================================== +// Command Recording +// ================================================== + +PalResult PAL_CALL palCmdBegin( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1808,10 +1905,10 @@ PalResult PAL_CALL palEndCommandBuffer(PalCommandBuffer* cmdBuffer) return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->endCommandBuffer(cmdBuffer); + return cmdBuffer->backend->cmdBegin(cmdBuffer, info); } -PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1821,10 +1918,10 @@ PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer) return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->resetCommandBuffer(cmdBuffer); + return cmdBuffer->backend->cmdEnd(cmdBuffer); } -PalResult PAL_CALL palExecuteCommandBuffer( +PalResult PAL_CALL palCmdExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { @@ -1836,10 +1933,12 @@ PalResult PAL_CALL palExecuteCommandBuffer( return PAL_RESULT_NULL_POINTER; } - return primaryCmdBuffer->backend->executeCommandBuffer(primaryCmdBuffer, secondaryCmdBuffer); + return primaryCmdBuffer->backend->cmdExecuteCommandBuffer( + primaryCmdBuffer, + secondaryCmdBuffer); } -PalResult PAL_CALL palSetFragmentShadingRate( +PalResult PAL_CALL palCmdSetFragmentShadingRate( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { @@ -1851,10 +1950,10 @@ PalResult PAL_CALL palSetFragmentShadingRate( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->setFragmentShadingRate(cmdBuffer, state); + return cmdBuffer->backend->cmdSetFragmentShadingRate(cmdBuffer, state); } -PalResult PAL_CALL palDrawMeshTasks( +PalResult PAL_CALL palCmdDrawMeshTasks( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, @@ -1868,10 +1967,10 @@ PalResult PAL_CALL palDrawMeshTasks( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawMeshTasks(cmdBuffer, groupCountX, groupCountY, groupCountZ); + return cmdBuffer->backend->cmdDrawMeshTasks(cmdBuffer, groupCountX, groupCountY, groupCountZ); } -PalResult PAL_CALL palDrawMeshTasksIndirect( +PalResult PAL_CALL palCmdDrawMeshTasksIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, @@ -1886,10 +1985,15 @@ PalResult PAL_CALL palDrawMeshTasksIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawMeshTasksIndirect(cmdBuffer, buffer, offset, drawCount, stride); + return cmdBuffer->backend->cmdDrawMeshTasksIndirect( + cmdBuffer, + buffer, + offset, + drawCount, + stride); } -PalResult PAL_CALL palDrawMeshTasksIndirectCount( +PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -1906,7 +2010,7 @@ PalResult PAL_CALL palDrawMeshTasksIndirectCount( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawMeshTasksIndirectCount( + return cmdBuffer->backend->cmdDrawMeshTasksIndirectCount( cmdBuffer, buffer, countBuffer, @@ -1916,7 +2020,7 @@ PalResult PAL_CALL palDrawMeshTasksIndirectCount( stride); } -PalResult PAL_CALL palBuildAccelerationStructure( +PalResult PAL_CALL palCmdBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { @@ -1932,10 +2036,10 @@ PalResult PAL_CALL palBuildAccelerationStructure( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->buildAccelerationStructure(cmdBuffer, info); + return cmdBuffer->backend->cmdBuildAccelerationStructure(cmdBuffer, info); } -PalResult PAL_CALL palBeginRendering( +PalResult PAL_CALL palCmdBeginRendering( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { @@ -1947,10 +2051,10 @@ PalResult PAL_CALL palBeginRendering( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->beginRendering(cmdBuffer, info); + return cmdBuffer->backend->cmdBeginRendering(cmdBuffer, info); } -PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -1960,10 +2064,10 @@ PalResult PAL_CALL palEndRendering(PalCommandBuffer* cmdBuffer) return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->endRendering(cmdBuffer); + return cmdBuffer->backend->cmdEndRendering(cmdBuffer); } -PalResult PAL_CALL palCopyBuffer( +PalResult PAL_CALL palCmdCopyBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -1979,10 +2083,10 @@ PalResult PAL_CALL palCopyBuffer( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->copyBuffer(cmdBuffer, dst, src, dstOffset, srcOffset, size); + return cmdBuffer->backend->cmdCopyBuffer(cmdBuffer, dst, src, dstOffset, srcOffset, size); } -PalResult PAL_CALL palBindPipeline( +PalResult PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline) { @@ -1994,10 +2098,10 @@ PalResult PAL_CALL palBindPipeline( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->bindPipeline(cmdBuffer, pipeline); + return cmdBuffer->backend->cmdBindPipeline(cmdBuffer, pipeline); } -PalResult PAL_CALL palSetViewport( +PalResult PAL_CALL palCmdSetViewport( PalCommandBuffer* cmdBuffer, Uint32 count, PalViewport* viewports) @@ -2010,10 +2114,10 @@ PalResult PAL_CALL palSetViewport( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->setViewport(cmdBuffer, count, viewports); + return cmdBuffer->backend->cmdSetViewport(cmdBuffer, count, viewports); } -PalResult PAL_CALL palSetScissors( +PalResult PAL_CALL palCmdSetScissors( PalCommandBuffer* cmdBuffer, Uint32 count, PalRect2D* scissors) @@ -2026,10 +2130,10 @@ PalResult PAL_CALL palSetScissors( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->setScissors(cmdBuffer, count, scissors); + return cmdBuffer->backend->cmdSetScissors(cmdBuffer, count, scissors); } -PalResult PAL_CALL palBindVertexBuffers( +PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, @@ -2044,10 +2148,10 @@ PalResult PAL_CALL palBindVertexBuffers( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->bindVertexBuffers(cmdBuffer, firstSlot, count, buffers, offsets); + return cmdBuffer->backend->cmdBindVertexBuffers(cmdBuffer, firstSlot, count, buffers, offsets); } -PalResult PAL_CALL palBindIndexBuffer( +PalResult PAL_CALL palCmdBindIndexBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, @@ -2061,10 +2165,10 @@ PalResult PAL_CALL palBindIndexBuffer( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->bindIndexBuffer(cmdBuffer, buffer, offset, type); + return cmdBuffer->backend->cmdBindIndexBuffer(cmdBuffer, buffer, offset, type); } -PalResult PAL_CALL palDraw( +PalResult PAL_CALL palCmdDraw( PalCommandBuffer* cmdBuffer, PalDrawData* data) { @@ -2076,10 +2180,10 @@ PalResult PAL_CALL palDraw( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->draw(cmdBuffer, data); + return cmdBuffer->backend->cmdDraw(cmdBuffer, data); } -PalResult PAL_CALL palDrawIndirect( +PalResult PAL_CALL palCmdDrawIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, @@ -2093,10 +2197,10 @@ PalResult PAL_CALL palDrawIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawIndirect(cmdBuffer, buffer, offset, count); + return cmdBuffer->backend->cmdDrawIndirect(cmdBuffer, buffer, offset, count); } -PalResult PAL_CALL palDrawIndirectCount( +PalResult PAL_CALL palCmdDrawIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -2112,11 +2216,16 @@ PalResult PAL_CALL palDrawIndirectCount( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend - ->drawIndirectCount(cmdBuffer, buffer, countBuffer, offset, countBufferOffset, count); + return cmdBuffer->backend->cmdDrawIndirectCount( + cmdBuffer, + buffer, + countBuffer, + offset, + countBufferOffset, + count); } -PalResult PAL_CALL palDrawIndexed( +PalResult PAL_CALL palCmdDrawIndexed( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data) { @@ -2128,10 +2237,10 @@ PalResult PAL_CALL palDrawIndexed( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawIndexed(cmdBuffer, data); + return cmdBuffer->backend->cmdDrawIndexed(cmdBuffer, data); } -PalResult PAL_CALL palDrawIndexedIndirect( +PalResult PAL_CALL palCmdDrawIndexedIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, @@ -2145,10 +2254,10 @@ PalResult PAL_CALL palDrawIndexedIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawIndexedIndirect(cmdBuffer, buffer, offset, count); + return cmdBuffer->backend->cmdDrawIndexedIndirect(cmdBuffer, buffer, offset, count); } -PalResult PAL_CALL palDrawIndexedIndirectCount( +PalResult PAL_CALL palCmdDrawIndexedIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -2164,7 +2273,7 @@ PalResult PAL_CALL palDrawIndexedIndirectCount( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->drawIndexedIndirectCount( + return cmdBuffer->backend->cmdDrawIndexedIndirectCount( cmdBuffer, buffer, countBuffer, @@ -2173,7 +2282,7 @@ PalResult PAL_CALL palDrawIndexedIndirectCount( count); } -PalResult PAL_CALL palMemoryBarrier( +PalResult PAL_CALL palCmdMemoryBarrier( PalCommandBuffer* cmdBuffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) @@ -2186,13 +2295,13 @@ PalResult PAL_CALL palMemoryBarrier( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->memoryBarrier( + return cmdBuffer->backend->cmdMemoryBarrier( cmdBuffer, oldUsageStateInfo, newUsageStateInfo); } -PalResult PAL_CALL palImageViewBarrier( +PalResult PAL_CALL palCmdImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, PalUsageStateInfo* oldUsageStateInfo, @@ -2206,14 +2315,14 @@ PalResult PAL_CALL palImageViewBarrier( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->imageViewBarrier( + return cmdBuffer->backend->cmdImageViewBarrier( cmdBuffer, imageView, oldUsageStateInfo, newUsageStateInfo); } -PalResult PAL_CALL palBufferBarrier( +PalResult PAL_CALL palCmdBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageStateInfo* oldUsageStateInfo, @@ -2227,14 +2336,14 @@ PalResult PAL_CALL palBufferBarrier( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->bufferBarrier( + return cmdBuffer->backend->cmdBufferBarrier( cmdBuffer, buffer, oldUsageStateInfo, newUsageStateInfo); } -PalResult PAL_CALL palDispatch( +PalResult PAL_CALL palCmdDispatch( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, @@ -2248,10 +2357,10 @@ PalResult PAL_CALL palDispatch( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->dispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); + return cmdBuffer->backend->cmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); } -PalResult PAL_CALL palDispatchBase( +PalResult PAL_CALL palCmdDispatchBase( PalCommandBuffer* cmdBuffer, Uint32 baseGroupX, Uint32 baseGroupY, @@ -2268,7 +2377,7 @@ PalResult PAL_CALL palDispatchBase( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->dispatchBase( + return cmdBuffer->backend->cmdDispatchBase( cmdBuffer, baseGroupX, baseGroupY, @@ -2278,7 +2387,7 @@ PalResult PAL_CALL palDispatchBase( groupCountZ); } -PalResult PAL_CALL palDispatchIndirect( +PalResult PAL_CALL palCmdDispatchIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset) @@ -2291,10 +2400,10 @@ PalResult PAL_CALL palDispatchIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->dispatchIndirect(cmdBuffer, buffer, offset); + return cmdBuffer->backend->cmdDispatchIndirect(cmdBuffer, buffer, offset); } -PalResult PAL_CALL palTraceRays( +PalResult PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, Uint32 width, Uint32 height, @@ -2308,10 +2417,10 @@ PalResult PAL_CALL palTraceRays( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->traceRays(cmdBuffer, width, height, depth); + return cmdBuffer->backend->cmdTraceRays(cmdBuffer, width, height, depth); } -PalResult PAL_CALL palTraceRaysIndirect( +PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, PalDeviceAddress bufferAddress) { @@ -2323,10 +2432,10 @@ PalResult PAL_CALL palTraceRaysIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->traceRaysIndirect(cmdBuffer, bufferAddress); + return cmdBuffer->backend->cmdTraceRaysIndirect(cmdBuffer, bufferAddress); } -PalResult PAL_CALL palBindDescriptorSet( +PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, PalPipelineLayout* layout, @@ -2341,10 +2450,10 @@ PalResult PAL_CALL palBindDescriptorSet( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->bindDescriptorSet(cmdBuffer, pipeline, layout, setIndex, set); + return cmdBuffer->backend->cmdBindDescriptorSet(cmdBuffer, pipeline, layout, setIndex, set); } -PalResult PAL_CALL palPushConstants( +PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, Uint32 shaderStageCount, @@ -2361,7 +2470,7 @@ PalResult PAL_CALL palPushConstants( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->pushConstants( + return cmdBuffer->backend->cmdPushConstants( cmdBuffer, layout, shaderStageCount, @@ -2371,23 +2480,8 @@ PalResult PAL_CALL palPushConstants( value); } -PalResult PAL_CALL palSubmitCommandBuffer( - PalQueue* queue, - PalCommandBufferSubmitInfo* info) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!queue || !info) { - return PAL_RESULT_NULL_POINTER; - } - - return queue->backend->submitCommandBuffer(queue, info); -} - // ================================================== -// Ray Tracing Pipeline +// Acceleration Structure // ================================================== PalResult PAL_CALL palCreateAccelerationstructure( @@ -2709,7 +2803,7 @@ PalResult PAL_CALL palUpdateDescriptorSet( } // ================================================== -// Pipeline +// Pipeline Layout // ================================================== PalResult PAL_CALL palCreatePipelineLayout( @@ -2745,6 +2839,10 @@ void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout) } } +// ================================================== +// Pipeline +// ================================================== + PalResult PAL_CALL palCreateGraphicsPipeline( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index d44ffd30..ebc49241 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -194,7 +194,7 @@ typedef struct { PFN_vkDeviceWaitIdle waitDevice; PFN_vkQueueWaitIdle waitQueue; - VkAllocationCallbacks vkAllocator; + VkAllocationCallbacks allocateVkator; const PalAllocator* allocator; } Vulkan; @@ -432,7 +432,7 @@ static Vulkan s_Vk = {0}; // Helper Functions // ================================================== -static Uint32 checkPlatform(struct wl_display* display) +static Uint32 checkPlatformVk(struct wl_display* display) { #ifdef _WIN32 #elif defined(__linux__) @@ -450,11 +450,11 @@ static Uint32 checkPlatform(struct wl_display* display) #endif // _WIN32 } -static bool createSurface( +static bool createSurfaceVk( PalGraphicsWindow* window, VkSurfaceKHR* outSurface) { - Uint32 platform = checkPlatform(window->display); + Uint32 platform = checkPlatformVk(window->display); if (platform == VK_WIN32_PLATFORM) { } else if (platform == VK_WAYLAND_PLATFORM) { @@ -471,7 +471,7 @@ static bool createSurface( createInfo.surface = window->window; VkResult result = - s_Vk.createWaylandSurface(s_Vk.instance, &createInfo, &s_Vk.vkAllocator, &surface); + s_Vk.createWaylandSurface(s_Vk.instance, &createInfo, &s_Vk.allocateVkator, &surface); if (result != VK_SUCCESS) { return false; @@ -484,7 +484,7 @@ static bool createSurface( } } -static PalResult vkResultToPal(VkResult result) +static PalResult resultFromVk(VkResult result) { switch (result) { case VK_ERROR_FEATURE_NOT_PRESENT: @@ -524,7 +524,7 @@ static PalResult vkResultToPal(VkResult result) return PAL_RESULT_PLATFORM_FAILURE; } -static VkImageUsageFlags palImageUsageToVk(PalImageUsages usages) +static VkImageUsageFlags imageUsageToVk(PalImageUsages usages) { VkImageUsageFlags flags = 0; if (usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { @@ -554,7 +554,7 @@ static VkImageUsageFlags palImageUsageToVk(PalImageUsages usages) return flags; } -static VkFormat palFormatToVk(PalFormat format) +static VkFormat formatToVk(PalFormat format) { switch (format) { case PAL_FORMAT_R8_UNORM: @@ -826,7 +826,7 @@ static VkSampleCountFlags samplesToVk(PalSampleCount count) return VK_SAMPLE_COUNT_1_BIT; } -static PalSampleCount vkSamplesToSamples(VkSampleCountFlags count) +static PalSampleCount samplesFromVk(VkSampleCountFlags count) { if (count & VK_SAMPLE_COUNT_2_BIT) { return PAL_SAMPLE_COUNT_2; @@ -850,7 +850,7 @@ static PalSampleCount vkSamplesToSamples(VkSampleCountFlags count) return PAL_SAMPLE_COUNT_1; } -static PalFormat vkFormatToPal(VkFormat format) +static PalFormat formatFromVk(VkFormat format) { switch (format) { case VK_FORMAT_R8_UNORM: @@ -1097,7 +1097,7 @@ static PalFormat vkFormatToPal(VkFormat format) return PAL_FORMAT_UNDEFINED; } -static PalImageUsages vkFeatureToPalUsage(VkFormatFeatureFlags flags) +static PalImageUsages ImageUsageFromVk(VkFormatFeatureFlags flags) { PalImageUsages usages = 0; if (flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { @@ -1127,7 +1127,7 @@ static PalImageUsages vkFeatureToPalUsage(VkFormatFeatureFlags flags) return usages; } -static VkImageType palImageTypeToVk(PalImageType type) +static VkImageType imageTypeToVk(PalImageType type) { switch (type) { case PAL_IMAGE_TYPE_1D: @@ -1143,7 +1143,7 @@ static VkImageType palImageTypeToVk(PalImageType type) return VK_IMAGE_TYPE_2D; } -static VkImageViewType palImageViewTypeToVk(PalImageViewType type) +static VkImageViewType imageViewTypeToVk(PalImageViewType type) { switch (type) { case PAL_IMAGE_VIEW_TYPE_1D: @@ -1171,7 +1171,7 @@ static VkImageViewType palImageViewTypeToVk(PalImageViewType type) return VK_IMAGE_VIEW_TYPE_2D; } -static VkExtent2D getShadingRateSize(PalFragmentShadingRate rate) +static VkExtent2D getShadingRateSizeVk(PalFragmentShadingRate rate) { switch (rate) { case PAL_FRAGMENT_SHADING_RATE_1X1: @@ -1199,7 +1199,7 @@ static VkExtent2D getShadingRateSize(PalFragmentShadingRate rate) return (VkExtent2D){0, 0}; } -static VkFormat vertexTypeToVkFormat(PalVertexType type) +static VkFormat vertexTypeToVk(PalVertexType type) { switch (type) { case PAL_VERTEX_TYPE_INT32: @@ -1296,7 +1296,7 @@ static VkFormat vertexTypeToVkFormat(PalVertexType type) return VK_FORMAT_UNDEFINED; } -static VkBufferUsageFlags palBufferUsageToVk(PalBufferUsages usages) +static VkBufferUsageFlags bufferUsageToVk(PalBufferUsages usages) { VkBufferUsageFlags flags = 0; if (usages & PAL_BUFFER_USAGE_VERTEX) { @@ -1336,7 +1336,7 @@ static VkBufferUsageFlags palBufferUsageToVk(PalBufferUsages usages) return flags; } -static Uint32 getVertexTypeSize(PalVertexType type) +static Uint32 getVertexTypeSizeVk(PalVertexType type) { // count x sizeof type returned as size switch (type) { @@ -1563,7 +1563,7 @@ static VkResolveModeFlags resolveModeToVk(PalResolveMode mode) return VK_RESOLVE_MODE_NONE_KHR; } -static VkPipelineStageFlags2 stageToVkPipelineStage(PalShaderStage stage) +static VkPipelineStageFlags2 pipelineStageToVk(PalShaderStage stage) { switch (stage) { case PAL_SHADER_STAGE_VERTEX: @@ -1726,7 +1726,7 @@ static Barrier barrierToVk(PalUsageState state, } case PAL_USAGE_STATE_UNIFORM_READ: { - barrier.stages = stageToVkPipelineStage(shaderStage); + barrier.stages = pipelineStageToVk(shaderStage); barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_UNIFORM_READ_BIT_KHR; @@ -1735,7 +1735,7 @@ static Barrier barrierToVk(PalUsageState state, } case PAL_USAGE_STATE_SHADER_READ: { - barrier.stages = stageToVkPipelineStage(shaderStage); + barrier.stages = pipelineStageToVk(shaderStage); barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; @@ -1744,7 +1744,7 @@ static Barrier barrierToVk(PalUsageState state, } case PAL_USAGE_STATE_SHADER_WRITE: { - barrier.stages = stageToVkPipelineStage(shaderStage); + barrier.stages = pipelineStageToVk(shaderStage); barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; @@ -1753,7 +1753,7 @@ static Barrier barrierToVk(PalUsageState state, } case PAL_USAGE_STATE_STORAGE_READ: { - barrier.stages = stageToVkPipelineStage(shaderStage); + barrier.stages = pipelineStageToVk(shaderStage); barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; @@ -1762,7 +1762,7 @@ static Barrier barrierToVk(PalUsageState state, } case PAL_USAGE_STATE_STORAGE_WRITE: { - barrier.stages = stageToVkPipelineStage(shaderStage); + barrier.stages = pipelineStageToVk(shaderStage); barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; @@ -1891,27 +1891,27 @@ static VkShaderStageFlags shaderStageToVK(PalShaderStage stage) return 0; } -static void* vkAlloc( +static void* allocateVk( void* pUserData, size_t size, - size_t alignment, + size_t alignVkment, VkSystemAllocationScope allocationScope) { - return palAllocate(s_Vk.allocator, size, alignment); + return palAllocate(s_Vk.allocator, size, alignVkment); } -static void vkFree( +static void freeVk( void* pUserData, void* ptr) { palFree(s_Vk.allocator, ptr); } -static void* vkRealloc( +static void* reallocVk( void* pUserData, void* pOriginal, size_t size, - size_t alignment, + size_t alignVkment, VkSystemAllocationScope allocationScope) { // Note: This is a hack which could cost performance but @@ -1919,7 +1919,7 @@ static void* vkRealloc( // this is because we dont know the old size void* block = realloc(pOriginal, size); if (block) { - void* memory = palAllocate(s_Vk.allocator, size, alignment); + void* memory = palAllocate(s_Vk.allocator, size, alignVkment); if (!memory) { free(block); return nullptr; @@ -1932,7 +1932,7 @@ static void* vkRealloc( return nullptr; } -VkBool32 debugCallback( +VkBool32 debugCallbackVk( VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagBitsEXT type, const VkDebugUtilsMessengerCallbackDataEXT* data, @@ -1972,7 +1972,7 @@ VkBool32 debugCallback( return VK_FALSE; } -static Uint32 findBestMemoryIndex( +static Uint32 findBestMemoryIndexVk( VkPhysicalDevice phyDevice, Uint32 memoryMask) { @@ -2015,12 +2015,12 @@ static Uint32 findBestMemoryIndex( return bestIndex; } -static inline Uint32 align(Uint32 value, Uint32 alignment) +static inline Uint32 alignVk(Uint32 value, Uint32 alignVkment) { - return (value + alignment - 1) & ~(alignment - 1); + return (value + alignVkment - 1) & ~(alignVkment - 1); } -static void fillVkBuildInfo( +static void fillVkBuildInfoVk( PalAccelerationStructureBuildInfo* info, Uint32* maxPrimities, VkAccelerationStructureGeometryKHR* geometries, @@ -2050,7 +2050,7 @@ static void fillVkBuildInfo( vertexAddress.deviceAddress = tmpData->vertexBufferAddress; data->vertexData = vertexAddress; data->maxVertex = tmpData->vertexCount - 1; - data->vertexFormat = vertexTypeToVkFormat(tmpData->vertexType); + data->vertexFormat = vertexTypeToVk(tmpData->vertexType); data->vertexStride = tmpData->vertexStride; indexAddress.deviceAddress = tmpData->indexBufferAddress; @@ -2520,7 +2520,7 @@ PalResult PAL_CALL initGraphicsVk( debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; debugCreateInfo.pUserData = debugger->userData; - debugCreateInfo.pfnUserCallback = debugCallback; + debugCreateInfo.pfnUserCallback = debugCallbackVk; s_Vk.callback = debugger->callback; } @@ -2611,15 +2611,15 @@ PalResult PAL_CALL initGraphicsVk( } // vk allocator - s_Vk.vkAllocator.pfnAllocation = vkAlloc; - s_Vk.vkAllocator.pfnFree = vkFree; - s_Vk.vkAllocator.pfnReallocation = vkRealloc; + s_Vk.allocateVkator.pfnAllocation = allocateVk; + s_Vk.allocateVkator.pfnFree = freeVk; + s_Vk.allocateVkator.pfnReallocation = reallocVk; VkInstance instance = nullptr; - result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.vkAllocator, &instance); + result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.allocateVkator, &instance); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } // clang-format off @@ -2687,7 +2687,7 @@ PalResult PAL_CALL initGraphicsVk( instance, "vkDestroyDebugUtilsMessengerEXT"); - s_Vk.createMessenger(instance, &debugCreateInfo, &s_Vk.vkAllocator, &s_Vk.messenger); + s_Vk.createMessenger(instance, &debugCreateInfo, &s_Vk.allocateVkator, &s_Vk.messenger); } // clang-format on @@ -2699,10 +2699,10 @@ PalResult PAL_CALL initGraphicsVk( PalResult PAL_CALL shutdownGraphicsVk() { if (s_Vk.messenger) { - s_Vk.destroyMessenger(s_Vk.instance, s_Vk.messenger, &s_Vk.vkAllocator); + s_Vk.destroyMessenger(s_Vk.instance, s_Vk.messenger, &s_Vk.allocateVkator); } - s_Vk.destroyInstance(s_Vk.instance, &s_Vk.vkAllocator); + s_Vk.destroyInstance(s_Vk.instance, &s_Vk.allocateVkator); dlclose(s_Vk.handle); if (s_Vk.libWayland) { dlclose(s_Vk.libWayland); @@ -2714,7 +2714,7 @@ PalResult PAL_CALL shutdownGraphicsVk() memset(&s_Vk, 0, sizeof(s_Vk)); } -PalResult PAL_CALL enumerateVkAdapters( +PalResult PAL_CALL enumerateAdaptersVk( Int32* count, PalAdapter** outAdapters) { @@ -2814,7 +2814,7 @@ PalResult PAL_CALL enumerateVkAdapters( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getVkAdapterInfo( +PalResult PAL_CALL getAdapterInfoVk( PalAdapter* adapter, PalAdapterInfo* info) { @@ -2884,7 +2884,7 @@ PalResult PAL_CALL getVkAdapterInfo( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getVkAdapterCapabilities( +PalResult PAL_CALL getAdapterCapabilitiesVk( PalAdapter* adapter, PalAdapterCapabilities* caps) { @@ -2910,9 +2910,9 @@ PalResult PAL_CALL getVkAdapterCapabilities( caps->maxImageArrayLayers = props.limits.maxImageArrayLayers; PalSampleCount tmp = PAL_SAMPLE_COUNT_1; - tmp = vkSamplesToSamples(props.limits.framebufferColorSampleCounts); + tmp = samplesFromVk(props.limits.framebufferColorSampleCounts); caps->maxColorSampleCount = tmp; - tmp = vkSamplesToSamples(props.limits.framebufferDepthSampleCounts); + tmp = samplesFromVk(props.limits.framebufferDepthSampleCounts); caps->maxDepthSampleCount = tmp; caps->maxViewports = props.limits.maxViewports; @@ -2980,7 +2980,7 @@ PalResult PAL_CALL getVkAdapterCapabilities( return PAL_RESULT_SUCCESS; } -PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) +PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) { VkResult result; PalAdapterFeatures adapterFeatures = 0; @@ -3336,7 +3336,7 @@ PalAdapterFeatures PAL_CALL getVkAdapterFeatures(PalAdapter* adapter) // Device // ================================================== -PalResult PAL_CALL createVkDevice( +PalResult PAL_CALL createDeviceVk( PalAdapter* adapter, PalAdapterFeatures features, PalDevice** outDevice) @@ -3654,13 +3654,13 @@ PalResult PAL_CALL createVkDevice( createInfo.queueCreateInfoCount = queueCount; createInfo.pNext = next; - result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.vkAllocator, &device->handle); + result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.allocateVkator, &device->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); palFree(s_Vk.allocator, device->phyQueues); palFree(s_Vk.allocator, device); - return vkResultToPal(result); + return resultFromVk(result); } device->features = features; @@ -3953,20 +3953,20 @@ PalResult PAL_CALL createVkDevice( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkDevice(PalDevice* device) +void PAL_CALL destroyDeviceVk(PalDevice* device) { Device* vkDevice = (Device*)device; - s_Vk.destroyDevice(vkDevice->handle, &s_Vk.vkAllocator); + s_Vk.destroyDevice(vkDevice->handle, &s_Vk.allocateVkator); palFree(s_Vk.allocator, vkDevice->phyQueues); palFree(s_Vk.allocator, vkDevice); } -PalResult PAL_CALL waitVkDevice(PalDevice* device) +PalResult PAL_CALL waitDeviceVk(PalDevice* device) { Device* vkDevice = (Device*)device; VkResult result = s_Vk.waitDevice(vkDevice->handle); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; @@ -3976,7 +3976,7 @@ PalResult PAL_CALL waitVkDevice(PalDevice* device) // Memory // ================================================== -PalResult PAL_CALL allocateVkMemory( +PalResult PAL_CALL allocateMemoryVk( PalDevice* device, PalMemoryType type, Uint64 memoryMask, @@ -4000,7 +4000,7 @@ PalResult PAL_CALL allocateVkMemory( } // pick an index using the scoring system - Uint32 memoryIndex = findBestMemoryIndex(vkDevice->phyDevice, memoryClassMask); + Uint32 memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, memoryClassMask); if (memoryIndex == UINT32_MAX) { return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; } @@ -4017,25 +4017,25 @@ PalResult PAL_CALL allocateVkMemory( allocateInfo.pNext = &allocateFlagsInfo; } - result = s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &memory); + result = s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.allocateVkator, &memory); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } *outMemory = (PalMemory*)memory; return PAL_RESULT_SUCCESS; } -void PAL_CALL freeVkMemory( +void PAL_CALL freeMemoryVk( PalDevice* device, PalMemory* memory) { Device* vkDevice = (Device*)device; VkDeviceMemory mem = (VkDeviceMemory)memory; - s_Vk.freeMemory(vkDevice->handle, mem, &s_Vk.vkAllocator); + s_Vk.freeMemory(vkDevice->handle, mem, &s_Vk.allocateVkator); } -PalResult PAL_CALL mapVkMemory( +PalResult PAL_CALL mapMemoryVk( PalDevice* device, PalMemory* memory, Uint64 offset, @@ -4049,12 +4049,12 @@ PalResult PAL_CALL mapVkMemory( result = s_Vk.mapMemory(vkDevice->handle, mem, offset, size, 0, outPtr); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; } -void PAL_CALL unmapVkMemory( +void PAL_CALL unmapMemoryVk( PalDevice* device, PalMemory* memory) { @@ -4063,7 +4063,11 @@ void PAL_CALL unmapVkMemory( s_Vk.unmapMemory(vkDevice->handle, mem); } -PalResult PAL_CALL queryVkDepthStencilCapabilities( +// ================================================== +// Extended Adapter Features +// ================================================== + +PalResult PAL_CALL queryDepthStencilCapabilitiesVk( PalDevice* device, PalDepthStencilCapabilities* caps) { @@ -4119,7 +4123,7 @@ PalResult PAL_CALL queryVkDepthStencilCapabilities( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { @@ -4139,7 +4143,7 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( memset(caps, 0, sizeof(PalFragmentShadingRateCapabilities)); for (int i = 0; i < PAL_FRAGMENT_SHADING_RATE_MAX; i++) { - VkExtent2D size = getShadingRateSize((PalFragmentShadingRate)i); + VkExtent2D size = getShadingRateSizeVk((PalFragmentShadingRate)i); // check against the max size if (size.width <= props.maxFragmentSize.width || @@ -4167,7 +4171,7 @@ PalResult PAL_CALL queryVkFragmentShadingRateCapabilities( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryVkMeshShaderCapabilities( +PalResult PAL_CALL queryMeshShaderCapabilitiesVk( PalDevice* device, PalMeshShaderCapabilities* caps) { @@ -4200,7 +4204,7 @@ PalResult PAL_CALL queryVkMeshShaderCapabilities( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryVkRayTracingCapabilities( +PalResult PAL_CALL queryRayTracingCapabilitiesVk( PalDevice* device, PalRayTracingCapabilities* caps) { @@ -4233,7 +4237,7 @@ PalResult PAL_CALL queryVkRayTracingCapabilities( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryVkDescriptorIndexingCapabilities( +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( PalDevice* device, PalDescriptorIndexingCapabilities* caps) { @@ -4279,7 +4283,7 @@ PalResult PAL_CALL queryVkDescriptorIndexingCapabilities( // Queue // ================================================== -PalResult PAL_CALL createVkQueue( +PalResult PAL_CALL createQueueVk( PalDevice* device, PalQueueType type, PalQueue** outQueue) @@ -4342,7 +4346,7 @@ PalResult PAL_CALL createVkQueue( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkQueue(PalQueue* queue) +void PAL_CALL destroyQueueVk(PalQueue* queue) { Queue* vkQueue = (Queue*)queue; PhysicalQueue* phyQueue = vkQueue->phyQueue; @@ -4350,7 +4354,18 @@ void PAL_CALL destroyVkQueue(PalQueue* queue) palFree(s_Vk.allocator, vkQueue); } -bool PAL_CALL canVkQueuePresent( +PalResult PAL_CALL waitQueueVk(PalQueue* queue) +{ + Queue* vkQueue = (Queue*)queue; + VkResult result = s_Vk.waitQueue(vkQueue->phyQueue->handle); + if (result != VK_SUCCESS) { + return resultFromVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +bool PAL_CALL canQueuePresentVk( PalQueue* queue, PalGraphicsWindow* window) { @@ -4361,7 +4376,7 @@ bool PAL_CALL canVkQueuePresent( return false; } - Uint32 platform = checkPlatform(window->display); + Uint32 platform = checkPlatformVk(window->display); PhysicalQueue* phyQueue = vkQueue->phyQueue; if (platform == VK_WIN32_PLATFORM) { @@ -4378,22 +4393,11 @@ bool PAL_CALL canVkQueuePresent( return false; } -PalResult PAL_CALL waitVkQueue(PalQueue* queue) -{ - Queue* vkQueue = (Queue*)queue; - VkResult result = s_Vk.waitQueue(vkQueue->phyQueue->handle); - if (result != VK_SUCCESS) { - return vkResultToPal(result); - } - - return PAL_RESULT_SUCCESS; -} - // ================================================== // Formats // ================================================== -PalResult PAL_CALL enumerateVkFormats( +PalResult PAL_CALL enumerateFormatsVk( PalAdapter* adapter, Int32* count, PalFormatInfo* outFormats) @@ -4404,7 +4408,7 @@ PalResult PAL_CALL enumerateVkFormats( VkFormatProperties props = {0}; for (int i = 0; i < PAL_FORMAT_MAX; i++) { - VkFormat fmt = palFormatToVk((PalFormat)i); + VkFormat fmt = formatToVk((PalFormat)i); s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); if (props.optimalTilingFeatures != 0) { // format supported @@ -4412,7 +4416,7 @@ PalResult PAL_CALL enumerateVkFormats( if (fmtCount < *count) { PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; fmtInfo->format = (PalFormat)i; - fmtInfo->usages = vkFeatureToPalUsage(props.optimalTilingFeatures); + fmtInfo->usages = ImageUsageFromVk(props.optimalTilingFeatures); PalImageViewUsages usages = 0; if (i == PAL_FORMAT_S8_UINT) { @@ -4453,7 +4457,7 @@ PalResult PAL_CALL enumerateVkFormats( return PAL_RESULT_SUCCESS; } -bool PAL_CALL isVkFormatSupported( +bool PAL_CALL isFormatSupportedVk( PalAdapter* adapter, PalFormat format) { @@ -4461,7 +4465,7 @@ bool PAL_CALL isVkFormatSupported( VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; VkFormatProperties props = {0}; - VkFormat fmt = palFormatToVk(format); + VkFormat fmt = formatToVk(format); s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); if (props.optimalTilingFeatures != 0) { return true; @@ -4469,7 +4473,7 @@ bool PAL_CALL isVkFormatSupported( return false; } -PalImageUsages PAL_CALL queryVkFormatImageUsages( +PalImageUsages PAL_CALL queryFormatImageUsagesVk( PalAdapter* adapter, PalFormat format) { @@ -4477,16 +4481,16 @@ PalImageUsages PAL_CALL queryVkFormatImageUsages( VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; VkFormatProperties props = {0}; - VkFormat fmt = palFormatToVk(format); + VkFormat fmt = formatToVk(format); s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); if (props.optimalTilingFeatures == 0) { return PAL_IMAGE_USAGE_UNDEFINED; } - return vkFeatureToPalUsage(props.optimalTilingFeatures); + return ImageUsageFromVk(props.optimalTilingFeatures); } -PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( +PalImageViewUsages PAL_CALL queryFormatImageViewUsagesVk( PalAdapter* adapter, PalFormat format) { @@ -4494,7 +4498,7 @@ PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; VkFormatProperties props = {0}; - VkFormat fmt = palFormatToVk(format); + VkFormat fmt = formatToVk(format); s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); if (props.optimalTilingFeatures == 0) { return PAL_IMAGE_VIEW_USAGE_UNDEFINED; @@ -4533,7 +4537,7 @@ PalImageViewUsages PAL_CALL queryVkFormatImageViewUsages( // Image // ================================================== -PalResult PAL_CALL createVkImage( +PalResult PAL_CALL createImageVk( PalDevice* device, const PalImageCreateInfo* info, PalImage** outImage) @@ -4560,24 +4564,24 @@ PalResult PAL_CALL createVkImage( createInfo.extent.height = info->height; createInfo.mipLevels = info->mipLevelCount; - createInfo.format = palFormatToVk(info->format); + createInfo.format = formatToVk(info->format); createInfo.samples = samplesToVk(info->sampleCount); - createInfo.usage = palImageUsageToVk(info->usages); + createInfo.usage = imageUsageToVk(info->usages); createInfo.arrayLayers = info->depthOrArraySize; createInfo.extent.depth = 1; - createInfo.imageType = palImageTypeToVk(info->type); + createInfo.imageType = imageTypeToVk(info->type); if (info->type == PAL_IMAGE_TYPE_3D) { createInfo.arrayLayers = 1; createInfo.extent.depth = info->depthOrArraySize; } - result = s_Vk.createImage(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &image->handle); + result = s_Vk.createImage(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &image->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, image); - return vkResultToPal(result); + return resultFromVk(result); } image->belongsToSwapchain = false; @@ -4595,19 +4599,19 @@ PalResult PAL_CALL createVkImage( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkImage(PalImage* image) +void PAL_CALL destroyImageVk(PalImage* image) { Image* vkImage = (Image*)image; if (vkImage->belongsToSwapchain) { return; } - s_Vk.destroyImage(vkImage->device->handle, vkImage->handle, &s_Vk.vkAllocator); + s_Vk.destroyImage(vkImage->device->handle, vkImage->handle, &s_Vk.allocateVkator); palFree(s_Vk.allocator, vkImage); } -PalResult PAL_CALL getVkImageInfo( +PalResult PAL_CALL getImageInfoVk( PalImage* image, PalImageInfo* info) { @@ -4616,7 +4620,7 @@ PalResult PAL_CALL getVkImageInfo( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getVkImageMemoryRequirements( +PalResult PAL_CALL getImageMemoryRequirementsVk( PalImage* image, PalMemoryRequirements* requirements) { @@ -4643,7 +4647,7 @@ PalResult PAL_CALL getVkImageMemoryRequirements( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL bindVkImageMemory( +PalResult PAL_CALL bindImageMemoryVk( PalImage* image, PalMemory* memory, Uint64 offset) @@ -4661,7 +4665,7 @@ PalResult PAL_CALL bindVkImageMemory( // Image View // ================================================== -PalResult PAL_CALL createVkImageView( +PalResult PAL_CALL createImageViewVk( PalDevice* device, PalImage* image, const PalImageViewCreateInfo* info, @@ -4685,14 +4689,14 @@ PalResult PAL_CALL createVkImageView( VkImageViewCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.format = palFormatToVk(vkImage->info.format); + createInfo.format = formatToVk(vkImage->info.format); createInfo.image = vkImage->handle; createInfo.subresourceRange.baseArrayLayer = info->startArrayLayer; createInfo.subresourceRange.baseMipLevel = info->startMipLevel; createInfo.subresourceRange.levelCount = info->mipLevelCount; createInfo.subresourceRange.layerCount = info->layerArrayCount; - createInfo.viewType = palImageViewTypeToVk(info->type); + createInfo.viewType = imageViewTypeToVk(info->type); VkImageAspectFlags aspectFlags = 0; if (info->usages & PAL_IMAGE_VIEW_USAGE_DEPTH) { @@ -4709,11 +4713,11 @@ PalResult PAL_CALL createVkImageView( createInfo.subresourceRange.aspectMask = aspectFlags; result = - s_Vk.createImageView(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &imageView->handle); + s_Vk.createImageView(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &imageView->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, imageView); - return vkResultToPal(result); + return resultFromVk(result); } imageView->device = vkDevice; @@ -4726,10 +4730,10 @@ PalResult PAL_CALL createVkImageView( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkImageView(PalImageView* imageView) +void PAL_CALL destroyImageViewVk(PalImageView* imageView) { ImageView* vkImageView = (ImageView*)imageView; - s_Vk.destroyImageView(vkImageView->device->handle, vkImageView->handle, &s_Vk.vkAllocator); + s_Vk.destroyImageView(vkImageView->device->handle, vkImageView->handle, &s_Vk.allocateVkator); palFree(s_Vk.allocator, vkImageView); } @@ -4738,7 +4742,7 @@ void PAL_CALL destroyVkImageView(PalImageView* imageView) // Swapchain // ================================================== -PalResult PAL_CALL queryVkSwapchainCapabilities( +PalResult PAL_CALL querySwapchainCapabilitiesVk( PalDevice* device, PalGraphicsWindow* window, PalSwapchainCapabilities* caps) @@ -4756,7 +4760,7 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - bool result = createSurface(window, &surface); + bool result = createSurfaceVk(window, &surface); if (!result) { return PAL_RESULT_INVALID_GRAPHICS_WINDOW; } @@ -4769,7 +4773,7 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( formats = palAllocate(s_Vk.allocator, sizeof(VkSurfaceFormatKHR) * formatCount, 0); if (!modes || !formats) { - s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.vkAllocator); + s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocateVkator); return PAL_RESULT_OUT_OF_MEMORY; } @@ -4856,11 +4860,11 @@ PalResult PAL_CALL queryVkSwapchainCapabilities( palFree(s_Vk.allocator, formats); palFree(s_Vk.allocator, modes); - s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.vkAllocator); + s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocateVkator); return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL createVkSwapchain( +PalResult PAL_CALL createSwapchainVk( PalDevice* device, PalQueue* queue, PalGraphicsWindow* window, @@ -4890,7 +4894,7 @@ PalResult PAL_CALL createVkSwapchain( return PAL_RESULT_OUT_OF_MEMORY; } - if (!createSurface(window, &swapchain->surface)) { + if (!createSurfaceVk(window, &swapchain->surface)) { return PAL_RESULT_INVALID_GRAPHICS_WINDOW; } @@ -4949,14 +4953,14 @@ PalResult PAL_CALL createVkSwapchain( VkResult result = vkDevice->createSwapchain( vkDevice->handle, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocateVkator, &swapchain->handle); if (result != VK_SUCCESS) { - s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.vkAllocator); + s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.allocateVkator); palFree(s_Vk.allocator, swapchain); - return vkResultToPal(result); + return resultFromVk(result); } // get and cache all images @@ -4968,9 +4972,9 @@ PalResult PAL_CALL createVkSwapchain( images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); if (!swapchain->images || !images) { - vkDevice->destroySwapchain(vkDevice->handle, swapchain->handle, &s_Vk.vkAllocator); + vkDevice->destroySwapchain(vkDevice->handle, swapchain->handle, &s_Vk.allocateVkator); - s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.vkAllocator); + s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.allocateVkator); palFree(s_Vk.allocator, swapchain); return PAL_RESULT_OUT_OF_MEMORY; @@ -5003,21 +5007,21 @@ PalResult PAL_CALL createVkSwapchain( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkSwapchain(PalSwapchain* swapchain) +void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain) { Swapchain* vkSwapchain = (Swapchain*)swapchain; vkSwapchain->device->destroySwapchain( vkSwapchain->device->handle, vkSwapchain->handle, - &s_Vk.vkAllocator); + &s_Vk.allocateVkator); - s_Vk.destroySurface(s_Vk.instance, vkSwapchain->surface, &s_Vk.vkAllocator); + s_Vk.destroySurface(s_Vk.instance, vkSwapchain->surface, &s_Vk.allocateVkator); palFree(s_Vk.allocator, vkSwapchain->images); palFree(s_Vk.allocator, vkSwapchain); } -PalImage* PAL_CALL getVkSwapchainImage( +PalImage* PAL_CALL getSwapchainImageVk( PalSwapchain* swapchain, Int32 index) { @@ -5028,7 +5032,7 @@ PalImage* PAL_CALL getVkSwapchainImage( return (PalImage*)&vkSwapchain->images[index]; } -PalResult PAL_CALL getVkNextSwapchainImage( +PalResult PAL_CALL getNextSwapchainImageVk( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, Uint32* outIndex) @@ -5058,14 +5062,14 @@ PalResult PAL_CALL getVkNextSwapchainImage( &index); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } *outIndex = index; return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL presentVkSwapchain( +PalResult PAL_CALL presentSwapchainVk( PalSwapchain* swapchain, PalSwapchainPresentInfo* info) { @@ -5090,7 +5094,7 @@ PalResult PAL_CALL presentVkSwapchain( result = vkSwapchain->device->queuePresent(vkSwapchain->queue->phyQueue->handle, &presentInfo); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; @@ -5100,7 +5104,7 @@ PalResult PAL_CALL presentVkSwapchain( // Shader // ================================================== -PalResult PAL_CALL createVkShader( +PalResult PAL_CALL createShaderVk( PalDevice* device, const PalShaderCreateInfo* info, PalShader** outShader) @@ -5141,11 +5145,11 @@ PalResult PAL_CALL createVkShader( createInfo.codeSize = info->bytecodeSize; createInfo.pCode = (const Uint32*)info->bytecode; - result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); + result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &shader->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, shader); - return vkResultToPal(result); + return resultFromVk(result); } shader->device = vkDevice; @@ -5159,10 +5163,10 @@ PalResult PAL_CALL createVkShader( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkShader(PalShader* shader) +void PAL_CALL destroyShaderVk(PalShader* shader) { Shader* vkShader = (Shader*)shader; - s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.vkAllocator); + s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.allocateVkator); palFree(s_Vk.allocator, vkShader); } @@ -5171,7 +5175,7 @@ void PAL_CALL destroyVkShader(PalShader* shader) // Fence // ================================================== -PalResult PAL_CALL createVkFence( +PalResult PAL_CALL createFenceVk( PalDevice* device, bool signaled, PalFence** outFence) @@ -5191,11 +5195,11 @@ PalResult PAL_CALL createVkFence( createInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; } - result = s_Vk.createFence(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &fence->handle); + result = s_Vk.createFence(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &fence->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, fence); - return vkResultToPal(result); + return resultFromVk(result); } fence->device = vkDevice; @@ -5203,15 +5207,15 @@ PalResult PAL_CALL createVkFence( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkFence(PalFence* fence) +void PAL_CALL destroyFenceVk(PalFence* fence) { Fence* vkFence = (Fence*)fence; - s_Vk.destroyFence(vkFence->device->handle, vkFence->handle, &s_Vk.vkAllocator); + s_Vk.destroyFence(vkFence->device->handle, vkFence->handle, &s_Vk.allocateVkator); palFree(s_Vk.allocator, vkFence); } -PalResult PAL_CALL waitVkFence( +PalResult PAL_CALL waitFenceVk( PalFence* fence, Uint64 timeout) { @@ -5224,13 +5228,13 @@ PalResult PAL_CALL waitVkFence( VkResult result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, true, timeout); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL resetVkFence(PalFence* fence) +PalResult PAL_CALL resetFenceVk(PalFence* fence) { Fence* vkFence = (Fence*)fence; if (!(vkFence->device->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { @@ -5240,13 +5244,13 @@ PalResult PAL_CALL resetVkFence(PalFence* fence) VkResult result = s_Vk.resetFence(vkFence->device->handle, 1, &vkFence->handle); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; } -bool PAL_CALL isVkFenceSignaled(PalFence* fence) +bool PAL_CALL isFenceSignaledVk(PalFence* fence) { Fence* vkFence = (Fence*)fence; VkResult result = s_Vk.isFenceSignaled(vkFence->device->handle, vkFence->handle); @@ -5262,7 +5266,7 @@ bool PAL_CALL isVkFenceSignaled(PalFence* fence) // Semaphore // ================================================== -PalResult PAL_CALL createVkSemaphore( +PalResult PAL_CALL createSemaphoreVk( PalDevice* device, PalSemaphore** outSemaphore) { @@ -5291,11 +5295,11 @@ PalResult PAL_CALL createVkSemaphore( createInfo.pNext = next; result = - s_Vk.createSemaphore(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &semaphore->handle); + s_Vk.createSemaphore(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &semaphore->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, semaphore); - return vkResultToPal(result); + return resultFromVk(result); } semaphore->device = vkDevice; @@ -5303,15 +5307,15 @@ PalResult PAL_CALL createVkSemaphore( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkSemaphore(PalSemaphore* semaphore) +void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore) { Semaphore* vkSemaphore = (Semaphore*)semaphore; - s_Vk.destroySemaphore(vkSemaphore->device->handle, vkSemaphore->handle, &s_Vk.vkAllocator); + s_Vk.destroySemaphore(vkSemaphore->device->handle, vkSemaphore->handle, &s_Vk.allocateVkator); palFree(s_Vk.allocator, vkSemaphore); } -PalResult PAL_CALL waitVkSemaphore( +PalResult PAL_CALL waitSemaphoreVk( PalSemaphore* semaphore, PalQueue* queue, Uint64 value, @@ -5332,13 +5336,13 @@ PalResult PAL_CALL waitVkSemaphore( result = vkSemaphore->device->waitSemaphore(vkSemaphore->device->handle, &waitInfo, timeout); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL signalVkSemaphore( +PalResult PAL_CALL signalSemaphoreVk( PalSemaphore* semaphore, PalQueue* queue, Uint64 value) @@ -5357,13 +5361,13 @@ PalResult PAL_CALL signalVkSemaphore( result = vkSemaphore->device->signalSemaphore(vkSemaphore->device->handle, &signalInfo); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getVkSemaphoreValue( +PalResult PAL_CALL getSemaphoreValueVk( PalSemaphore* semaphore, Uint64* value) { @@ -5378,7 +5382,7 @@ PalResult PAL_CALL getVkSemaphoreValue( value); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; @@ -5388,7 +5392,7 @@ PalResult PAL_CALL getVkSemaphoreValue( // Command Pool And Buffer // ================================================== -PalResult PAL_CALL createVkCommandPool( +PalResult PAL_CALL createCommandPoolVk( PalDevice* device, PalQueue* queue, PalCommandPool** outPool) @@ -5410,11 +5414,11 @@ PalResult PAL_CALL createVkCommandPool( createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; result = - s_Vk.createCommandPool(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &pool->handle); + s_Vk.createCommandPool(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &pool->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pool); - return vkResultToPal(result); + return resultFromVk(result); } pool->device = vkDevice; @@ -5422,22 +5426,22 @@ PalResult PAL_CALL createVkCommandPool( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkCommandPool(PalCommandPool* pool) +void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool) { CommandPool* vkPool = (CommandPool*)pool; - s_Vk.destroyCommandPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); + s_Vk.destroyCommandPool(vkPool->device->handle, vkPool->handle, &s_Vk.allocateVkator); palFree(s_Vk.allocator, vkPool); } -PalResult PAL_CALL resetVkCommandPool(PalCommandPool* pool) +PalResult PAL_CALL resetCommandPoolVk(PalCommandPool* pool) { CommandPool* vkCmdPool = (CommandPool*)pool; s_Vk.resetCommandPool(vkCmdPool->device->handle, vkCmdPool->handle, 0); return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL allocateVkCommandBuffer( +PalResult PAL_CALL allocateCommandBufferVk( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, @@ -5469,7 +5473,7 @@ PalResult PAL_CALL allocateVkCommandBuffer( if (result != VK_SUCCESS) { palFree(s_Vk.allocator, cmdBuffer); - return vkResultToPal(result); + return resultFromVk(result); } cmdBuffer->device = vkDevice; @@ -5480,7 +5484,7 @@ PalResult PAL_CALL allocateVkCommandBuffer( return PAL_RESULT_SUCCESS; } -void PAL_CALL freeVkCommandBuffer(PalCommandBuffer* cmdBuffer) +void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.freeCommandBuffer( @@ -5492,7 +5496,93 @@ void PAL_CALL freeVkCommandBuffer(PalCommandBuffer* cmdBuffer) palFree(s_Vk.allocator, vkCmdBuffer); } -PalResult PAL_CALL beginVkCommandBuffer( +PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); + vkCmdBuffer->sbt = nullptr; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL submitCommandBufferVk( + PalQueue* queue, + PalCommandBufferSubmitInfo* info) +{ + VkResult result; + Int32 waitSemaphoreCount = 0; + Int32 signalSemaphoreCount = 0; + VkFence fenceHandle = nullptr; + VkSemaphore waitSemaphoreHandle = nullptr; + VkSemaphore signalSemaphoreHandle = nullptr; + VkPipelineStageFlagBits2 dstStage = 0; + Queue* vkQueue = (Queue*)queue; + CommandBuffer* vkCmdBuffer = (CommandBuffer*)info->cmdBuffer; + + if (vkCmdBuffer->sbt) { + vkCmdBuffer->dstStage |= VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; + } + + if (info->waitSemaphore) { + Semaphore* tmp = (Semaphore*)info->waitSemaphore; + waitSemaphoreHandle = tmp->handle; + waitSemaphoreCount = 1; + dstStage = vkCmdBuffer->dstStage; + } + + if (info->signalSemaphore) { + Semaphore* tmp = (Semaphore*)info->signalSemaphore; + signalSemaphoreHandle = tmp->handle; + signalSemaphoreCount = 1; + } + + if (info->fence) { + Fence* tmp = (Fence*)info->fence; + fenceHandle = tmp->handle; + } + + VkCommandBufferSubmitInfoKHR cmdBufferSubmitInfo = {0}; + cmdBufferSubmitInfo.commandBuffer = vkCmdBuffer->handle; + cmdBufferSubmitInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR; + + VkSemaphoreSubmitInfoKHR waitSubmitInfo = {0}; + waitSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; + waitSubmitInfo.semaphore = waitSemaphoreHandle; + waitSubmitInfo.stageMask = dstStage; + + VkSemaphoreSubmitInfoKHR signalSubmitInfo = {0}; + signalSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; + signalSubmitInfo.semaphore = signalSemaphoreHandle; + signalSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + + if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + waitSubmitInfo.value = info->waitValue; + signalSubmitInfo.value = info->signalValue; + } + + VkSubmitInfo2KHR submitInfo = {0}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR; + submitInfo.commandBufferInfoCount = 1; + submitInfo.pCommandBufferInfos = &cmdBufferSubmitInfo; + submitInfo.pSignalSemaphoreInfos = &signalSubmitInfo; + submitInfo.pWaitSemaphoreInfos = &waitSubmitInfo; + submitInfo.waitSemaphoreInfoCount = waitSemaphoreCount; + submitInfo.signalSemaphoreInfoCount = signalSemaphoreCount; + + result = + vkCmdBuffer->device->queueSubmit(vkQueue->phyQueue->handle, 1, &submitInfo, fenceHandle); + + if (result != VK_SUCCESS) { + return resultFromVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +// ================================================== +// Command Recording +// ================================================== + +PalResult PAL_CALL cmdBeginVk( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) { @@ -5511,18 +5601,18 @@ PalResult PAL_CALL beginVkCommandBuffer( if (!vkCmdBuffer->primary) { // secondary command buffer for (int i = 0; i < info->colorAttachentCount; i++) { - format = palFormatToVk(info->colorAttachmentsFormat[i]); + format = formatToVk(info->colorAttachmentsFormat[i]); colorAttachments[i] = format; } layout.colorAttachmentCount = info->colorAttachentCount; layout.pColorAttachmentFormats = colorAttachments; // depth attachment - format = palFormatToVk(info->depthAttachmentFormat); + format = formatToVk(info->depthAttachmentFormat); layout.depthAttachmentFormat = format; // stencil attachment - format = palFormatToVk(info->stencilAttachmentFormat); + format = formatToVk(info->stencilAttachmentFormat); layout.stencilAttachmentFormat = format; layout.rasterizationSamples = samplesToVk(info->multisampleCount); @@ -5538,32 +5628,24 @@ PalResult PAL_CALL beginVkCommandBuffer( VkResult result = s_Vk.cmdBegin(vkCmdBuffer->handle, &beginInfo); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL endVkCommandBuffer(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; VkResult result = s_Vk.cmdEnd(vkCmdBuffer->handle); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL resetVkCommandBuffer(PalCommandBuffer* cmdBuffer) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); - vkCmdBuffer->sbt = nullptr; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL executeCommandBufferVk( +PalResult PAL_CALL cmdExecuteCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { @@ -5574,7 +5656,7 @@ PalResult PAL_CALL executeCommandBufferVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL setVkFragmentShadingRate( +PalResult PAL_CALL cmdSetFragmentShadingRateVk( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { @@ -5583,7 +5665,7 @@ PalResult PAL_CALL setVkFragmentShadingRate( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - VkExtent2D size = getShadingRateSize(state->rate); + VkExtent2D size = getShadingRateSizeVk(state->rate); VkFragmentShadingRateCombinerOpKHR combinerOps[2]; for (int i = 0; i < 2; i++) { @@ -5622,7 +5704,7 @@ PalResult PAL_CALL setVkFragmentShadingRate( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL drawVkMeshTasks( +PalResult PAL_CALL cmdDrawMeshTasksVk( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, @@ -5639,7 +5721,7 @@ PalResult PAL_CALL drawVkMeshTasks( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL drawVkMeshTasksIndirect( +PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, @@ -5658,7 +5740,7 @@ PalResult PAL_CALL drawVkMeshTasksIndirect( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL drawVkMeshTasksIndirectCount( +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -5687,7 +5769,7 @@ PalResult PAL_CALL drawVkMeshTasksIndirectCount( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL buildVkAccelerationStructure( +PalResult PAL_CALL cmdBuildAccelerationStructureVk( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { @@ -5718,7 +5800,7 @@ PalResult PAL_CALL buildVkAccelerationStructure( memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount); memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->geometryCount); - fillVkBuildInfo(info, nullptr, geometries, as->handle, rangeInfos, &buildInfo); + fillVkBuildInfoVk(info, nullptr, geometries, as->handle, rangeInfos, &buildInfo); const VkAccelerationStructureBuildRangeInfoKHR* tmp[1]; tmp[0] = rangeInfos; vkCmdBuffer->device->cmdBuildAccelerationStructures(vkCmdBuffer->handle, 1, &buildInfo, tmp); @@ -5729,7 +5811,7 @@ PalResult PAL_CALL buildVkAccelerationStructure( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL beginRenderingVk( +PalResult PAL_CALL cmdBeginRenderingVk( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { @@ -5921,14 +6003,14 @@ PalResult PAL_CALL beginRenderingVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL endRenderingVk(PalCommandBuffer* cmdBuffer) +PalResult PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; vkCmdBuffer->device->cmdEndRendering(vkCmdBuffer->handle); return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL copyVkBuffer( +PalResult PAL_CALL cmdCopyBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -5949,7 +6031,7 @@ PalResult PAL_CALL copyVkBuffer( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL bindVkPipeline( +PalResult PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline) { @@ -5964,7 +6046,7 @@ PalResult PAL_CALL bindVkPipeline( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL setVkViewport( +PalResult PAL_CALL cmdSetViewportVk( PalCommandBuffer* cmdBuffer, Uint32 count, PalViewport* viewports) @@ -6001,7 +6083,7 @@ PalResult PAL_CALL setVkViewport( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL setVkScissors( +PalResult PAL_CALL cmdSetScissorsVk( PalCommandBuffer* cmdBuffer, Uint32 count, PalRect2D* scissors) @@ -6036,7 +6118,7 @@ PalResult PAL_CALL setVkScissors( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL bindVkVertexBuffers( +PalResult PAL_CALL cmdBindVertexBuffersVk( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, @@ -6070,7 +6152,7 @@ PalResult PAL_CALL bindVkVertexBuffers( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL bindVkIndexBuffer( +PalResult PAL_CALL cmdBindIndexBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, @@ -6088,7 +6170,7 @@ PalResult PAL_CALL bindVkIndexBuffer( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL drawVk( +PalResult PAL_CALL cmdDrawVk( PalCommandBuffer* cmdBuffer, PalDrawData* data) { @@ -6103,7 +6185,7 @@ PalResult PAL_CALL drawVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL drawIndirectVk( +PalResult PAL_CALL cmdDrawIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, @@ -6118,7 +6200,7 @@ PalResult PAL_CALL drawIndirectVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL drawIndirectCountVk( +PalResult PAL_CALL cmdDrawIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -6147,7 +6229,7 @@ PalResult PAL_CALL drawIndirectCountVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL drawIndexedVk( +PalResult PAL_CALL cmdDrawIndexedVk( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data) { @@ -6163,7 +6245,7 @@ PalResult PAL_CALL drawIndexedVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL drawIndexedIndirectVk( +PalResult PAL_CALL cmdDrawIndexedIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, @@ -6178,7 +6260,7 @@ PalResult PAL_CALL drawIndexedIndirectVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL drawIndexedIndirectCountVk( +PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -6207,7 +6289,7 @@ PalResult PAL_CALL drawIndexedIndirectCountVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL memoryBarrierVk( +PalResult PAL_CALL cmdMemoryBarrierVk( PalCommandBuffer* cmdBuffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) @@ -6237,7 +6319,7 @@ PalResult PAL_CALL memoryBarrierVk( } -PalResult PAL_CALL imageViewBarrierVk( +PalResult PAL_CALL cmdImageViewBarrierVk( PalCommandBuffer* cmdBuffer, PalImageView* imageView, PalUsageStateInfo* oldUsageStateInfo, @@ -6273,7 +6355,7 @@ PalResult PAL_CALL imageViewBarrierVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL bufferBarrierVk( +PalResult PAL_CALL cmdBufferBarrierVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageStateInfo* oldUsageStateInfo, @@ -6308,7 +6390,7 @@ PalResult PAL_CALL bufferBarrierVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL dispatchVk( +PalResult PAL_CALL cmdDispatchVk( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, @@ -6320,7 +6402,7 @@ PalResult PAL_CALL dispatchVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL dispatchBaseVk( +PalResult PAL_CALL cmdDispatchBaseVk( PalCommandBuffer* cmdBuffer, Uint32 baseGroupX, Uint32 baseGroupY, @@ -6346,7 +6428,7 @@ PalResult PAL_CALL dispatchBaseVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL dispatchIndirectVk( +PalResult PAL_CALL cmdDispatchIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset) @@ -6358,7 +6440,7 @@ PalResult PAL_CALL dispatchIndirectVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL traceRaysVk( +PalResult PAL_CALL cmdTraceRaysVk( PalCommandBuffer* cmdBuffer, Uint32 width, Uint32 height, @@ -6387,7 +6469,7 @@ PalResult PAL_CALL traceRaysVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL traceRaysIndirectVk( +PalResult PAL_CALL cmdTraceRaysIndirectVk( PalCommandBuffer* cmdBuffer, PalDeviceAddress bufferAddress) { @@ -6412,7 +6494,7 @@ PalResult PAL_CALL traceRaysIndirectVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL bindVkDescriptorSet( +PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, PalPipelineLayout* layout, @@ -6437,7 +6519,7 @@ PalResult PAL_CALL bindVkDescriptorSet( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL pushConstantsVk( +PalResult PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, Uint32 shaderStageCount, @@ -6466,85 +6548,11 @@ PalResult PAL_CALL pushConstantsVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL submitVkCommandBuffer( - PalQueue* queue, - PalCommandBufferSubmitInfo* info) -{ - VkResult result; - Int32 waitSemaphoreCount = 0; - Int32 signalSemaphoreCount = 0; - VkFence fenceHandle = nullptr; - VkSemaphore waitSemaphoreHandle = nullptr; - VkSemaphore signalSemaphoreHandle = nullptr; - VkPipelineStageFlagBits2 dstStage = 0; - Queue* vkQueue = (Queue*)queue; - CommandBuffer* vkCmdBuffer = (CommandBuffer*)info->cmdBuffer; - - if (vkCmdBuffer->sbt) { - vkCmdBuffer->dstStage |= VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; - } - - if (info->waitSemaphore) { - Semaphore* tmp = (Semaphore*)info->waitSemaphore; - waitSemaphoreHandle = tmp->handle; - waitSemaphoreCount = 1; - dstStage = vkCmdBuffer->dstStage; - } - - if (info->signalSemaphore) { - Semaphore* tmp = (Semaphore*)info->signalSemaphore; - signalSemaphoreHandle = tmp->handle; - signalSemaphoreCount = 1; - } - - if (info->fence) { - Fence* tmp = (Fence*)info->fence; - fenceHandle = tmp->handle; - } - - VkCommandBufferSubmitInfoKHR cmdBufferSubmitInfo = {0}; - cmdBufferSubmitInfo.commandBuffer = vkCmdBuffer->handle; - cmdBufferSubmitInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR; - - VkSemaphoreSubmitInfoKHR waitSubmitInfo = {0}; - waitSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; - waitSubmitInfo.semaphore = waitSemaphoreHandle; - waitSubmitInfo.stageMask = dstStage; - - VkSemaphoreSubmitInfoKHR signalSubmitInfo = {0}; - signalSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; - signalSubmitInfo.semaphore = signalSemaphoreHandle; - signalSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - - if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - waitSubmitInfo.value = info->waitValue; - signalSubmitInfo.value = info->signalValue; - } - - VkSubmitInfo2KHR submitInfo = {0}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR; - submitInfo.commandBufferInfoCount = 1; - submitInfo.pCommandBufferInfos = &cmdBufferSubmitInfo; - submitInfo.pSignalSemaphoreInfos = &signalSubmitInfo; - submitInfo.pWaitSemaphoreInfos = &waitSubmitInfo; - submitInfo.waitSemaphoreInfoCount = waitSemaphoreCount; - submitInfo.signalSemaphoreInfoCount = signalSemaphoreCount; - - result = - vkCmdBuffer->device->queueSubmit(vkQueue->phyQueue->handle, 1, &submitInfo, fenceHandle); - - if (result != VK_SUCCESS) { - return vkResultToPal(result); - } - - return PAL_RESULT_SUCCESS; -} - // ================================================== -// Ray Tracing Pipeline +// Acceleration Structure // ================================================== -PalResult PAL_CALL createVkAccelerationstructure( +PalResult PAL_CALL createAccelerationstructureVk( PalDevice* device, const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs) @@ -6576,12 +6584,12 @@ PalResult PAL_CALL createVkAccelerationstructure( result = vkDevice->createAccelerationStructure( vkDevice->handle, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocateVkator, &as->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, as); - return vkResultToPal(result); + return resultFromVk(result); } // get and cache address @@ -6595,18 +6603,18 @@ PalResult PAL_CALL createVkAccelerationstructure( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkAccelerationstructure(PalAccelerationStructure* as) +void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as) { AccelerationStructure* vkAs = (AccelerationStructure*)as; vkAs->device->destroyAccelerationStructure( vkAs->device->handle, vkAs->handle, - &s_Vk.vkAllocator); + &s_Vk.allocateVkator); palFree(s_Vk.allocator, vkAs); } -PalResult PAL_CALL getVkAccelerationStructureBuildSize( +PalResult PAL_CALL getAccelerationStructureBuildSizeVk( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) @@ -6632,7 +6640,7 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( memset(maxPrimities, 0, sizeof(Uint32) * info->geometryCount); memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount); - fillVkBuildInfo(info, maxPrimities, geometries, nullptr, nullptr, &buildInfo); + fillVkBuildInfoVk(info, maxPrimities, geometries, nullptr, nullptr, &buildInfo); VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; @@ -6656,7 +6664,7 @@ PalResult PAL_CALL getVkAccelerationStructureBuildSize( // Buffer // ================================================== -PalResult PAL_CALL createVkBuffer( +PalResult PAL_CALL createBufferVk( PalDevice* device, const PalBufferCreateInfo* info, PalBuffer** outBuffer) @@ -6685,12 +6693,12 @@ PalResult PAL_CALL createVkBuffer( createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.size = info->size; - createInfo.usage = palBufferUsageToVk(info->usages); + createInfo.usage = bufferUsageToVk(info->usages); - result = s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &buffer->handle); + result = s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &buffer->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, buffer); - return vkResultToPal(result); + return resultFromVk(result); } buffer->usages = info->usages; @@ -6703,15 +6711,15 @@ PalResult PAL_CALL createVkBuffer( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkBuffer(PalBuffer* buffer) +void PAL_CALL destroyBufferVk(PalBuffer* buffer) { Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.destroyBuffer(vkBuffer->device->handle, vkBuffer->handle, &s_Vk.vkAllocator); + s_Vk.destroyBuffer(vkBuffer->device->handle, vkBuffer->handle, &s_Vk.allocateVkator); palFree(s_Vk.allocator, buffer); } -PalResult PAL_CALL getVkBufferMemoryRequirements( +PalResult PAL_CALL getBufferMemoryRequirementsVk( PalBuffer* buffer, PalMemoryRequirements* requirements) { @@ -6735,7 +6743,7 @@ PalResult PAL_CALL getVkBufferMemoryRequirements( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL computeVkInstanceBufferRequirements( +PalResult PAL_CALL computeInstanceBufferRequirementsVk( PalDevice* device, PalInstanceBufferRequirements* requirements, Uint32 instanceCount) @@ -6745,7 +6753,7 @@ PalResult PAL_CALL computeVkInstanceBufferRequirements( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL writeVkInstancesToMappedMemory( +PalResult PAL_CALL writeInstancesToMappedMemoryVk( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, @@ -6767,7 +6775,7 @@ PalResult PAL_CALL writeVkInstancesToMappedMemory( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL bindVkBufferMemory( +PalResult PAL_CALL bindBufferMemoryVk( PalBuffer* buffer, PalMemory* memory, Uint64 offset) @@ -6778,12 +6786,12 @@ PalResult PAL_CALL bindVkBufferMemory( result = s_Vk.bindBufferMemory(vkBuffer->device->handle, vkBuffer->handle, mem, offset); if (result != VK_SUCCESS) { - return vkResultToPal(result); + return resultFromVk(result); } return PAL_RESULT_SUCCESS; } -PalDeviceAddress PAL_CALL getVkBufferDeviceAddress(PalBuffer* buffer) +PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer) { Buffer* vkBuffer = (Buffer*)buffer; if (!(vkBuffer->device->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { @@ -6800,7 +6808,7 @@ PalDeviceAddress PAL_CALL getVkBufferDeviceAddress(PalBuffer* buffer) // Descriptor Pool, Set and Layout // ================================================== -PalResult PAL_CALL createVkDescriptorSetLayout( +PalResult PAL_CALL createDescriptorSetLayoutVk( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout) @@ -6853,13 +6861,13 @@ PalResult PAL_CALL createVkDescriptorSetLayout( result = s_Vk.createDescriptorSetLayout( vkDevice->handle, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocateVkator, &layout->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, layout); palFree(s_Vk.allocator, bindings); - return vkResultToPal(result); + return resultFromVk(result); } layout->device = vkDevice; @@ -6868,14 +6876,14 @@ PalResult PAL_CALL createVkDescriptorSetLayout( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkDescriptorSetLayout(PalDescriptorSetLayout* layout) +void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout) { DescriptorSetLayout* vkLayout = (DescriptorSetLayout*)layout; - s_Vk.destroyDescriptorSetLayout(vkLayout->device->handle, vkLayout->handle, &s_Vk.vkAllocator); + s_Vk.destroyDescriptorSetLayout(vkLayout->device->handle, vkLayout->handle, &s_Vk.allocateVkator); palFree(s_Vk.allocator, layout); } -PalResult PAL_CALL createVkDescriptorPool( +PalResult PAL_CALL createDescriptorPoolVk( PalDevice* device, const PalDescriptorPoolCreateInfo* info, PalDescriptorPool** outPool) @@ -6911,13 +6919,13 @@ PalResult PAL_CALL createVkDescriptorPool( result = s_Vk.createDescriptorPool( vkDevice->handle, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocateVkator, &pool->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pool); palFree(s_Vk.allocator, poolSizes); - return vkResultToPal(result); + return resultFromVk(result); } pool->device = vkDevice; @@ -6926,14 +6934,21 @@ PalResult PAL_CALL createVkDescriptorPool( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkDescriptorPool(PalDescriptorPool* pool) +void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool) { DescriptorPool* vkPool = (DescriptorPool*)pool; - s_Vk.destroyDescriptorPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); + s_Vk.destroyDescriptorPool(vkPool->device->handle, vkPool->handle, &s_Vk.allocateVkator); palFree(s_Vk.allocator, pool); } -PalResult PAL_CALL allocateVkDescriptorSet( +PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool) +{ + DescriptorPool* vkPool = (DescriptorPool*)pool; + s_Vk.resetDescriptorPool(vkPool->device->handle, vkPool->handle, 0); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL allocateDescriptorSetVk( PalDevice* device, PalDescriptorPool* pool, PalDescriptorSetLayout* layout, @@ -6959,7 +6974,7 @@ PalResult PAL_CALL allocateVkDescriptorSet( result = s_Vk.allocateDescriptorSet(vkDevice->handle, &allocateInfo, &set->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, set); - return vkResultToPal(result); + return resultFromVk(result); } set->pool = vkPool; @@ -6968,14 +6983,7 @@ PalResult PAL_CALL allocateVkDescriptorSet( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL resetVkDescriptorPool(PalDescriptorPool* pool) -{ - DescriptorPool* vkPool = (DescriptorPool*)pool; - s_Vk.resetDescriptorPool(vkPool->device->handle, vkPool->handle, 0); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL updateVkDescriptorSet( +PalResult PAL_CALL updateDescriptorSetVk( PalDevice* device, Uint32 count, PalDescriptorSetWriteInfo* infos) @@ -7100,10 +7108,10 @@ PalResult PAL_CALL updateVkDescriptorSet( } // ================================================== -// Pipeline +// Pipeline Layout // ================================================== -PalResult PAL_CALL createVkPipelineLayout( +PalResult PAL_CALL createPipelineLayoutVk( PalDevice* device, const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout) @@ -7158,14 +7166,14 @@ PalResult PAL_CALL createVkPipelineLayout( result = s_Vk.createPipelineLayout( vkDevice->handle, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocateVkator, &layout->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, descriptorLayouts); palFree(s_Vk.allocator, pushConstants); palFree(s_Vk.allocator, layout); - return vkResultToPal(result); + return resultFromVk(result); } palFree(s_Vk.allocator, descriptorLayouts); @@ -7176,18 +7184,22 @@ PalResult PAL_CALL createVkPipelineLayout( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkPipelineLayout(PalPipelineLayout* layout) +void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout) { PipelineLayout* pipelineLayout = (PipelineLayout*)layout; s_Vk.destroyPipelineLayout( pipelineLayout->device->handle, pipelineLayout->handle, - &s_Vk.vkAllocator); + &s_Vk.allocateVkator); palFree(s_Vk.allocator, layout); } -PalResult PAL_CALL createVkGraphicsPipeline( +// ================================================== +// Pipeline +// ================================================== + +PalResult PAL_CALL createGraphicsPipelineVk( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline) @@ -7305,12 +7317,12 @@ PalResult PAL_CALL createVkGraphicsPipeline( PalVertexAttribute* vertexAttrib = &layout->attributes[j]; VkVertexInputAttributeDescription* attribDesc = &attribDescs[j]; - attribDesc->format = vertexTypeToVkFormat(vertexAttrib->type); + attribDesc->format = vertexTypeToVk(vertexAttrib->type); attribDesc->binding = bindingDesc->binding; attribDesc->location = vertexAttrib->location; // build offsets and stride - Uint32 size = getVertexTypeSize(vertexAttrib->type); + Uint32 size = getVertexTypeSizeVk(vertexAttrib->type); attribDesc->offset = offset; offset += size; bindingDesc->stride += size; @@ -7563,7 +7575,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( fragmentShadingRateState.combinerOps[i] = combinerOp; } - VkExtent2D size = getShadingRateSize(state->rate); + VkExtent2D size = getShadingRateSizeVk(state->rate); fragmentShadingRateState.fragmentSize = size; createInfo.pNext = &fragmentShadingRateState; } @@ -7575,18 +7587,18 @@ PalResult PAL_CALL createVkGraphicsPipeline( // color attachments for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { - format = palFormatToVk(renderingLayout->colorAttachmentsFormat[i]); + format = formatToVk(renderingLayout->colorAttachmentsFormat[i]); colorAttachments[i] = format; } dynRendering.colorAttachmentCount = renderingLayout->colorAttachentCount; dynRendering.pColorAttachmentFormats = colorAttachments; // depth attachment - format = palFormatToVk(renderingLayout->depthAttachmentFormat); + format = formatToVk(renderingLayout->depthAttachmentFormat); dynRendering.depthAttachmentFormat = format; // stencil attachment - format = palFormatToVk(renderingLayout->stencilAttachmentFormat); + format = formatToVk(renderingLayout->stencilAttachmentFormat); dynRendering.stencilAttachmentFormat = format; if (renderingLayout->viewCount == 1) { @@ -7601,12 +7613,12 @@ PalResult PAL_CALL createVkGraphicsPipeline( 0, 1, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocateVkator, &pipeline->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); - return vkResultToPal(result); + return resultFromVk(result); } palFree(s_Vk.allocator, bindingDescs); @@ -7620,7 +7632,7 @@ PalResult PAL_CALL createVkGraphicsPipeline( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL createVkComputePipeline( +PalResult PAL_CALL createComputePipelineVk( PalDevice* device, const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline) @@ -7645,12 +7657,12 @@ PalResult PAL_CALL createVkComputePipeline( nullptr, 1, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocateVkator, &pipeline->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); - return vkResultToPal(result); + return resultFromVk(result); } pipeline->device = vkDevice; @@ -7660,7 +7672,7 @@ PalResult PAL_CALL createVkComputePipeline( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL createVkRayTracingPipeline( +PalResult PAL_CALL createRayTracingPipelineVk( PalDevice* device, const PalRayTracingPipelineCreateInfo* info, PalPipeline** outPipeline) @@ -7752,13 +7764,13 @@ PalResult PAL_CALL createVkRayTracingPipeline( nullptr, 1, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocateVkator, &pipeline->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, groups); - return vkResultToPal(result); + return resultFromVk(result); } palFree(s_Vk.allocator, groups); @@ -7774,7 +7786,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( Uint32 groupHandleSize = rayProps.shaderGroupHandleSize; Uint32 groupHandleAlignment = rayProps.shaderGroupHandleAlignment; Uint32 groupBaseAlignment = rayProps.shaderGroupBaseAlignment; - Uint32 stride = align(groupHandleSize, groupHandleAlignment); + Uint32 stride = alignVk(groupHandleSize, groupHandleAlignment); // get region size Uint32 raygenRegionSize = stride * numRaygen; @@ -7782,11 +7794,11 @@ PalResult PAL_CALL createVkRayTracingPipeline( Uint32 hitRegionSize = stride * numHit; Uint32 callableRegionSize = stride * numCallable; - // get aligned region size - Uint32 raygenAlignedRegionSize = align(raygenRegionSize, groupBaseAlignment); - Uint32 missAlignedRegionSize = align(missRegionSize, groupBaseAlignment);; - Uint32 hitAlignedRegionSize = align(hitRegionSize, groupBaseAlignment); - Uint32 callableAligneRegionSize = align(callableRegionSize, groupBaseAlignment); + // get alignVked region size + Uint32 raygenAlignedRegionSize = alignVk(raygenRegionSize, groupBaseAlignment); + Uint32 missAlignedRegionSize = alignVk(missRegionSize, groupBaseAlignment);; + Uint32 hitAlignedRegionSize = alignVk(hitRegionSize, groupBaseAlignment); + Uint32 callableAligneRegionSize = alignVk(callableRegionSize, groupBaseAlignment); // get offsets Uint32 missOffset = raygenAlignedRegionSize; @@ -7802,11 +7814,11 @@ PalResult PAL_CALL createVkRayTracingPipeline( bufCreateInfo.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); + result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.allocateVkator, &sbt->buffer); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); + return resultFromVk(result); } // allocate CPU upload memory and bind @@ -7818,7 +7830,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( allocateInfo.allocationSize = memReq.size; Uint32 mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] & memReq.memoryTypeBits; - Uint32 memoryIndex = findBestMemoryIndex(vkDevice->phyDevice, mask); + Uint32 memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); allocateInfo.memoryTypeIndex = memoryIndex; VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; @@ -7829,13 +7841,13 @@ PalResult PAL_CALL createVkRayTracingPipeline( result = s_Vk.allocateMemory( vkDevice->handle, &allocateInfo, - &s_Vk.vkAllocator, + &s_Vk.allocateVkator, &sbt->bufferMemory); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); + return resultFromVk(result); } s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); @@ -7860,7 +7872,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); + return resultFromVk(result); } // copy handles into the buffer @@ -7869,7 +7881,7 @@ PalResult PAL_CALL createVkRayTracingPipeline( if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); - return vkResultToPal(result); + return resultFromVk(result); } Uint8* dstPtr = ptr; @@ -7942,17 +7954,17 @@ PalResult PAL_CALL createVkRayTracingPipeline( return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyVkPipeline(PalPipeline* pipeline) +void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) { Pipeline* vkPipeline = (Pipeline*)pipeline; - s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); + s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.allocateVkator); if (vkPipeline->sbt) { VkDevice device = vkPipeline->device->handle; ShaderBindingTable* sbt = vkPipeline->sbt; - s_Vk.destroyBuffer(device, sbt->buffer, &s_Vk.vkAllocator); - s_Vk.freeMemory(device, sbt->bufferMemory, &s_Vk.vkAllocator); + s_Vk.destroyBuffer(device, sbt->buffer, &s_Vk.allocateVkator); + s_Vk.freeMemory(device, sbt->bufferMemory, &s_Vk.allocateVkator); palFree(s_Vk.allocator, vkPipeline->sbt); } diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 677125f5..7c81d300 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -385,7 +385,7 @@ bool clearColorTest() return false; } - result = palBeginCommandBuffer(cmdBuffer, nullptr); + result = palCmdBegin(cmdBuffer, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); @@ -424,7 +424,7 @@ bool clearColorTest() oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; } - result = palImageViewBarrier( + result = palCmdImageViewBarrier( cmdBuffer, imageViews[index], &oldUsageStateInfo, @@ -442,14 +442,14 @@ bool clearColorTest() return false; } - result = palBeginRendering(cmdBuffer, &renderingInfo); + result = palCmdBeginRendering(cmdBuffer, &renderingInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); return false; } - result = palEndRendering(cmdBuffer); + result = palCmdEndRendering(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); @@ -459,7 +459,7 @@ bool clearColorTest() // change the state of the image view to make it presentable oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - result = palImageViewBarrier( + result = palCmdImageViewBarrier( cmdBuffer, imageViews[index], &oldUsageStateInfo, @@ -471,7 +471,7 @@ bool clearColorTest() return false; } - result = palEndCommandBuffer(cmdBuffer); + result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); diff --git a/tests/compute_test.c b/tests/compute_test.c index aad7ddcb..33f5ae93 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -426,7 +426,7 @@ bool computeTest() } // record commands - result = palBeginCommandBuffer(cmdBuffer, nullptr); + result = palCmdBegin(cmdBuffer, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); @@ -441,14 +441,14 @@ bool computeTest() pushConstant.color[2] = 0.0f; pushConstant.color[3] = 1.0f; - result = palBindPipeline(cmdBuffer, pipeline); + result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); return false; } - result = palPushConstants( + result = palCmdPushConstants( cmdBuffer, pipelineLayout, 1, @@ -463,7 +463,7 @@ bool computeTest() return false; } - result = palBindDescriptorSet(cmdBuffer, pipeline, pipelineLayout, 0, descriptorSet); + result = palCmdBindDescriptorSet(cmdBuffer, pipeline, pipelineLayout, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); @@ -512,7 +512,7 @@ bool computeTest() newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_COMPUTE; newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; - result = palBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); @@ -528,7 +528,7 @@ bool computeTest() Uint32 groupCountY = workGroupInfos[i].workGroupCount[1]; Uint32 groupCountZ = workGroupInfos[i].workGroupCount[2]; - result = palDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); + result = palCmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to dispatch: %s", error); @@ -543,7 +543,7 @@ bool computeTest() newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; - result = palBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); @@ -557,7 +557,7 @@ bool computeTest() newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - result = palBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); @@ -565,7 +565,7 @@ bool computeTest() } // now we copy from the GPU buffer into the staging buffer - result = palCopyBuffer(cmdBuffer, stagingBuffer, buffer, 0, 0, bufferBytes); + result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, 0, 0, bufferBytes); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); @@ -577,7 +577,7 @@ bool computeTest() // but we map and copy outside the command buffer since // we wait for a fence (the command buffer has been executed). - result = palEndCommandBuffer(cmdBuffer); + result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); diff --git a/tests/mesh_test.c b/tests/mesh_test.c index c8d182ff..44c17811 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -580,7 +580,7 @@ bool meshTest() return false; } - result = palBeginCommandBuffer(cmdBuffer, nullptr); + result = palCmdBegin(cmdBuffer, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); @@ -598,7 +598,7 @@ bool meshTest() oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; } - result = palImageViewBarrier( + result = palCmdImageViewBarrier( cmdBuffer, imageViews[index], &oldUsageStateInfo, @@ -631,7 +631,7 @@ bool meshTest() renderingInfo.renderArea.width = WINDOW_WIDTH; renderingInfo.renderArea.height = WINDOW_HEIGHT; - result = palBeginRendering(cmdBuffer, &renderingInfo); + result = palCmdBeginRendering(cmdBuffer, &renderingInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); @@ -639,7 +639,7 @@ bool meshTest() } // bind pipeline - result = palBindPipeline(cmdBuffer, pipeline); + result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); @@ -647,14 +647,14 @@ bool meshTest() } // set viewport and scissors - result = palSetViewport(cmdBuffer, 1, &viewport); + result = palCmdSetViewport(cmdBuffer, 1, &viewport); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); return false; } - result = palSetScissors(cmdBuffer, 1, &scissor); + result = palCmdSetScissors(cmdBuffer, 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); @@ -665,14 +665,14 @@ bool meshTest() // palBuildWorkGroupInfo() is a helper to build // the workgroup count per axis using normal // workCount (image size, buffer size) - result = palDrawMeshTasks(cmdBuffer, 1, 1, 1); + result = palCmdDrawMeshTasks(cmdBuffer, 1, 1, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); return false; } - result = palEndRendering(cmdBuffer); + result = palCmdEndRendering(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); @@ -682,7 +682,7 @@ bool meshTest() // change the state of the image view to make it presentable oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - result = palImageViewBarrier( + result = palCmdImageViewBarrier( cmdBuffer, imageViews[index], &oldUsageStateInfo, @@ -694,7 +694,7 @@ bool meshTest() return false; } - result = palEndCommandBuffer(cmdBuffer); + result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index c8d86b4e..c9988a75 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -86,7 +86,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -790,12 +790,19 @@ bool rayTracingTest() writeInfos[0].descriptorSet = descriptorSet; writeInfos[0].descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; writeInfos[0].descriptorCount = 1; + writeInfos[0].arrayElement = 0; + writeInfos[0].imageViewInfo = nullptr; + writeInfos[0].tlasInfo = nullptr; + writeInfos[1].binding = 1; writeInfos[1].tlasInfo = &descriptorTlasInfo; writeInfos[1].descriptorSet = descriptorSet; writeInfos[1].descriptorType = PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE; writeInfos[1].descriptorCount = 1; + writeInfos[1].arrayElement = 0; + writeInfos[1].imageViewInfo = nullptr; + writeInfos[1].bufferInfo = nullptr; result = palUpdateDescriptorSet(device, 2, writeInfos); if (result != PAL_RESULT_SUCCESS) { @@ -866,21 +873,21 @@ bool rayTracingTest() } // record commands - result = palBeginCommandBuffer(cmdBuffer, nullptr); + result = palCmdBegin(cmdBuffer, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); return false; } - result = palBindPipeline(cmdBuffer, pipeline); + result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); return false; } - result = palBindDescriptorSet(cmdBuffer, pipeline, pipelineLayout, 0, descriptorSet); + result = palCmdBindDescriptorSet(cmdBuffer, pipeline, pipelineLayout, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); @@ -896,7 +903,7 @@ bool rayTracingTest() newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_RAYGEN; newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; - result = palBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); @@ -911,7 +918,7 @@ bool rayTracingTest() tlasBuildInfo.dst = tlas; tlasBuildInfo.scratchBufferAddress = scratchBufferAddress; - result = palBuildAccelerationStructure(cmdBuffer, &blasBuildInfo); + result = palCmdBuildAccelerationStructure(cmdBuffer, &blasBuildInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to build blas: %s", error); @@ -927,14 +934,14 @@ bool rayTracingTest() newAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; newAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; - result = palMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); + result = palCmdMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set memory barrier: %s", error); return false; } - result = palBuildAccelerationStructure(cmdBuffer, &tlasBuildInfo); + result = palCmdBuildAccelerationStructure(cmdBuffer, &tlasBuildInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to build tlas: %s", error); @@ -946,14 +953,14 @@ bool rayTracingTest() newAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; newAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; - result = palMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); + result = palCmdMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set memory barrier: %s", error); return false; } - result = palTraceRays(cmdBuffer, BUFFER_SIZE, BUFFER_SIZE, 1); + result = palCmdTraceRays(cmdBuffer, BUFFER_SIZE, BUFFER_SIZE, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to trace rays: %s", error); @@ -966,7 +973,7 @@ bool rayTracingTest() newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; - result = palBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); @@ -980,7 +987,7 @@ bool rayTracingTest() newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - result = palBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); @@ -988,14 +995,14 @@ bool rayTracingTest() } // now we copy from the GPU buffer into the staging buffer - result = palCopyBuffer(cmdBuffer, stagingBuffer, buffer, 0, 0, bufferBytes); + result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, 0, 0, bufferBytes); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); return false; } - result = palEndCommandBuffer(cmdBuffer); + result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); diff --git a/tests/tests_main.c b/tests/tests_main.c index 5153763e..08c2be64 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,15 +57,15 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest); - // registerTest(computeTest); + registerTest(graphicsTest); + registerTest(computeTest); registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest(clearColorTest); - // registerTest(triangleTest); - // registerTest(meshTest); + registerTest(clearColorTest); + registerTest(triangleTest); + registerTest(meshTest); #endif // runTests(); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 0ea0e7a4..b7d2d15a 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -454,14 +454,14 @@ bool triangleTest() // and reset it when done // set a fence and check at the last line before the main loop // to see if we have to wait for the copy to be executed - result = palBeginCommandBuffer(cmdBuffers[0], nullptr); + result = palCmdBegin(cmdBuffers[0], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); return false; } - result = palCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, 0, 0, sizeof(vertices)); + result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, 0, 0, sizeof(vertices)); PalUsageStateInfo oldUsageStateInfo = {0}; oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; @@ -471,14 +471,14 @@ bool triangleTest() newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_VERTEX; newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; - result = palBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); return false; } - result = palEndCommandBuffer(cmdBuffers[0]); + result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); @@ -765,7 +765,7 @@ bool triangleTest() return false; } - result = palBeginCommandBuffer(cmdBuffer, nullptr); + result = palCmdBegin(cmdBuffer, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); @@ -783,7 +783,7 @@ bool triangleTest() oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; } - result = palImageViewBarrier( + result = palCmdImageViewBarrier( cmdBuffer, imageViews[index], &oldUsageStateInfo, @@ -816,7 +816,7 @@ bool triangleTest() renderingInfo.renderArea.width = WINDOW_WIDTH; renderingInfo.renderArea.height = WINDOW_HEIGHT; - result = palBeginRendering(cmdBuffer, &renderingInfo); + result = palCmdBeginRendering(cmdBuffer, &renderingInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); @@ -824,7 +824,7 @@ bool triangleTest() } // bind pipeline - result = palBindPipeline(cmdBuffer, pipeline); + result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); @@ -832,14 +832,14 @@ bool triangleTest() } // set viewport and scissors - result = palSetViewport(cmdBuffer, 1, &viewport); + result = palCmdSetViewport(cmdBuffer, 1, &viewport); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); return false; } - result = palSetScissors(cmdBuffer, 1, &scissor); + result = palCmdSetScissors(cmdBuffer, 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); @@ -848,21 +848,21 @@ bool triangleTest() // bind vertex buffer Uint64 offset[] = {0}; - result = palBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, offset); + result = palCmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, offset); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind vertex buffer: %s", error); return false; } - result = palDraw(cmdBuffer, &drawData); + result = palCmdDraw(cmdBuffer, &drawData); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); return false; } - result = palEndRendering(cmdBuffer); + result = palCmdEndRendering(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); @@ -872,7 +872,7 @@ bool triangleTest() // change the state of the image view to make it presentable oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - result = palImageViewBarrier( + result = palCmdImageViewBarrier( cmdBuffer, imageViews[index], &oldUsageStateInfo, @@ -884,7 +884,7 @@ bool triangleTest() return false; } - result = palEndCommandBuffer(cmdBuffer); + result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); From ee484eccaa752a65af2dca72c85d34e8d5be3d43 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 23 Feb 2026 12:11:21 +0000 Subject: [PATCH 094/372] begin graphics system docs --- include/pal/pal_core.h | 22 +- include/pal/pal_event.h | 6 +- include/pal/pal_graphics.h | 695 ++++++++++++++++++++++++++++++++++--- tests/ray_tracing_test.c | 5 +- 4 files changed, 669 insertions(+), 59 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 0aa8edff..694a2783 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -159,10 +159,9 @@ typedef uintptr_t UintPtr; * @typedef PalAllocateFn * @brief Function pointer type used for memory allocations. * - * @param[in] userData Optional pointer to user data passed from ::PalAllocator. - * Can be nullptr. - * @param[in] size Number of bytes to allocate. - * @param[in] alignment Must be power of two. Set to 0 to use default. + * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. + * @param[in] size Number of bytes to allocate. Must not be 0. + * @param[in] alignment Must be power of two. Set to 0 to use default (16). * * @return Pointer to the allocated memory on success or nullptr on failure. * @@ -179,9 +178,8 @@ typedef void*(PAL_CALL* PalAllocateFn)( * @typedef PalFreeFn * @brief Function pointer type used for memory deallocations. * - * @param[in] userData Optional pointer to user data passed from ::PalAllocator. - * Can be nullptr. - * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. + * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. + * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must return safely if pointer is nullptr. * * @since 1.0 * @ingroup pal_core @@ -195,8 +193,7 @@ typedef void(PAL_CALL* PalFreeFn)( * @typedef PalLogCallback * @brief Function pointer type used for log callbacks. * - * @param userData Optional pointer to user data passed from ::PalLogger. Can be - * nullptr. + * @param userData Optional pointer to user data passed from ::PalLogger. Can be nullptr. * @param msg Null-terminated UTF-8 log message. * * @since 1.0 @@ -211,8 +208,7 @@ typedef void(PAL_CALL* PalLogCallback)( * @enum PalResult * @brief Codes returned by most PAL functions. This is not a bitmask. * - * All result codes follow the format `PAL_RESULT_**` for consistency and API - * use. + * All result codes follow the format `PAL_RESULT_**` for consistency and API use. * * @since 1.0 * @ingroup pal_core @@ -364,8 +360,8 @@ PAL_API const char* PAL_CALL palFormatResult(PalResult result); * * @return Pointer to allocated memory on success, or nullptr on failure. * - * Thread safety: Thread safe only if the provided allocator is thread - * safe. The default allocator is thread safe. + * Thread safety: Thread safe only if the provided allocator is thread safe. The default allocator + * is thread safe. * * @since 1.0 * @ingroup pal_core diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index bb0a4b39..dc57caae 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -56,7 +56,7 @@ typedef struct PalEvent PalEvent; * @brief Function pointer type used for event callbacks. * * @param[in] userData Optional pointer to user data. Can be nullptr. - * @param[in] event The event. + * @param[in] event Pointer to the event. * * @since 1.0 * @ingroup pal_event @@ -71,7 +71,7 @@ typedef void(PAL_CALL* PalEventCallback)( * @brief Function pointer type used for pushing events into event queues. * * @param[in] userData Optional pointer to user data. Can be nullptr. - * @param[in] event The event to push. + * @param[in] event Pointer to the event to push. * * @since 1.0 * @ingroup pal_event @@ -90,7 +90,7 @@ typedef void(PAL_CALL* PalPushFn)( * true. * * @param[in] userData Optional pointer to user data. Can be nullptr. - * @param[out] event Pointer to a PalEvent to recieve the event. + * @param[out] event Pointer to the PalEvent to recieve the event. * * @since 1.0 * @ingroup pal_event diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 478d2710..24bc8a0a 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -33,47 +33,268 @@ freely, subject to the following restrictions: #include "pal_core.h" +/** + * @brief The maximum name size of an adapter (GPU). + * @since 1.4 + * @ingroup pal_graphics + */ #define PAL_ADAPTER_NAME_SIZE 128 + +/** + * @brief The maximum version string size of an adapter. + * @since 1.4 + * @ingroup pal_graphics + */ #define PAL_ADAPTER_VERSION_SIZE 16 + #define PAL_MAX_RESOLVE_MODES 8 #define PAL_MAX_COMBINER_OPS 8 + +/** + * @brief A Unused shader index. Used to make a shader index invalid. + * @since 1.4 + * @ingroup pal_graphics + */ #define PAL_UNUSED_SHADER_INDEX UINT32_MAX +/** + * @struct PalAdapter + * @brief Opaque handle to an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalAdapter PalAdapter; + +/** + * @struct PalDevice + * @brief Opaque handle to a device. Devices are created from an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalDevice PalDevice; + +/** + * @struct PalMemory + * @brief Opaque handle to a device memory. This is not `CPU` memory. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalMemory PalMemory; + +/** + * @struct PalQueue + * @brief Opaque handle to a queue. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalQueue PalQueue; + +/** + * @struct PalSwapchain + * @brief Opaque handle to a swapchain. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalSwapchain PalSwapchain; +/** + * @struct PalImage + * @brief Opaque handle to an image. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalImage PalImage; + +/** + * @struct PalImageView + * @brief Opaque handle to an image view. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalImageView PalImageView; + +/** + * @struct PalShader + * @brief Opaque handle to a shader. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalShader PalShader; +/** + * @struct PalBuffer + * @brief Opaque handle to a buffer. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalBuffer PalBuffer; + +/** + * @struct PalFence + * @brief Opaque handle to a fence. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalFence PalFence; + +/** + * @struct PalSemaphore + * @brief Opaque handle to a semaphore. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalSemaphore PalSemaphore; + +/** + * @struct PalCommandPool + * @brief Opaque handle to a command pool. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalCommandPool PalCommandPool; + +/** + * @struct PalCommandBuffer + * @brief Opaque handle to a command buffer. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalCommandBuffer PalCommandBuffer; +/** + * @struct PalDescriptorSetLayout + * @brief Opaque handle to a descriptor set layout. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalDescriptorSetLayout PalDescriptorSetLayout; + +/** + * @struct PalDescriptorPool + * @brief Opaque handle to a descriptor pool. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalDescriptorPool PalDescriptorPool; + +/** + * @struct PalDescriptorSet + * @brief Opaque handle to a descriptor set. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalDescriptorSet PalDescriptorSet; + +/** + * @struct PalSampler + * @brief Opaque handle to a sampler. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalSampler PalSampler; +/** + * @struct PalPipelineLayout + * @brief Opaque handle to a pipeline layout. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalPipelineLayout PalPipelineLayout; + +/** + * @struct PalPipeline + * @brief Opaque handle to a pipeline. This is the same handle used for all pipeline types (Graphics, Compute and Ray tracing). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalPipeline PalPipeline; + +/** + * @struct PalAccelerationStructure + * @brief Opaque handle to an acceleration structure. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct PalAccelerationStructure PalAccelerationStructure; +/** + * @enum PalDebugMessageSeverity + * @brief Debugger messages severity types used to filter incoming messages. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum PalDebugMessageSeverity PalDebugMessageSeverity; + +/** + * @enum PalDebugMessageType + * @brief Debugger messages types used to filter incoming messages. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum PalDebugMessageType PalDebugMessageType; + +/** + * @typedef PalDeviceAddress + * @brief Adapter address. Used to get adapter (GPU) address of mostly buffers. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef Uint64 PalDeviceAddress; +/** + * @typedef PalDebugCallback + * @brief Function pointer type used for debug callbacks. + * + * @param userData Optional pointer to user data passed from ::PalGraphicsDebugger. Can be nullptr. + * @param severity Severity of the message. (`PAL_DEBUG_MESSAGE_SEVERITY_INFO`, + * `PAL_DEBUG_MESSAGE_SEVERITY_WARNING` and `PAL_DEBUG_MESSAGE_SEVERITY_ERROR`). + * @param type Type of the message. (`PAL_DEBUG_MESSAGE_TYPE_GENERAL`, + * `PAL_DEBUG_MESSAGE_TYPE_VALIDATION` and `PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE`). + * @param msg Null-terminated UTF-8 debug message. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palInitGraphics + */ typedef void(PAL_CALL* PalDebugCallback)( void* userData, PalDebugMessageSeverity severity, PalDebugMessageType type, const char* msg); +/** + * @enum PalAdapterType + * @brief Adapter (GPU) types. + * + * All adapter types follow the format `PAL_ADAPTER_TYPE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_ADAPTER_TYPE_UNKNOWN, PAL_ADAPTER_TYPE_DISCRETE, @@ -82,6 +303,20 @@ typedef enum { PAL_ADAPTER_TYPE_CPU } PalAdapterType; +/** + * @enum PalAdapterApiType + * @brief Adapter API types. + * + * All adapter api types follow the format `PAL_ADAPTER_API_TYPE_**` for + * consistency and API use. + * + * (`PAL_ADAPTER_API_TYPE_OPENGL`, `PAL_ADAPTER_API_TYPE_GLES`, `PAL_ADAPTER_API_TYPE_D3D11` + * `PAL_ADAPTER_API_TYPE_D3D9`, `PAL_ADAPTER_API_TYPE_PPM`, etc) will not be supported by the + * core graphics system. These are custom backends that can be use to extend the graphics systems. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_ADAPTER_API_TYPE_VULKAN, PAL_ADAPTER_API_TYPE_D3D12, @@ -93,28 +328,68 @@ typedef enum { PAL_ADAPTER_API_TYPE_PPM } PalAdapterApiType; +/** + * @enum PalQueueType + * @brief Queue types. + * + * All queue types follow the format `PAL_QUEUE_TYPE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_QUEUE_TYPE_GRAPHICS, PAL_QUEUE_TYPE_COMPUTE, PAL_QUEUE_TYPE_COPY } PalQueueType; +/** + * @enum PalPresentMode + * @brief Present modes + * + * All present modes follow the format `PAL_PRESENT_MODE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { - PAL_PRESENT_MODE_FIFO, + PAL_PRESENT_MODE_FIFO, /**< V-Sync.*/ PAL_PRESENT_MODE_IMMEDIATE, PAL_PRESENT_MODE_MAILBOX, PAL_PRESENT_MODE_MAX } PalPresentMode; +/** + * @enum PalCompositeAplha + * @brief Composite alphas + * + * All composite alphas follow the format `PAL_COMPOSITE_ALPHA_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { - PAL_COMPOSITE_ALPHA_OPAQUE, + PAL_COMPOSITE_ALPHA_OPAQUE, /**< Default behavior.*/ PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED, PAL_COMPOSITE_ALPHA_POST_MULTIPLIED, PAL_COMPOSITE_ALPHA_MAX } PalCompositeAplha; +/** + * @enum PalFormat + * @brief Format types. + * + * All format types follow the format `PAL_FORMAT_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_FORMAT_UNDEFINED, @@ -202,6 +477,16 @@ typedef enum { PAL_FORMAT_MAX } PalFormat; +/** + * @enum PalImageUsages + * @brief Image usages. + * + * All image usages follow the format `PAL_IMAGE_USAGE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_IMAGE_USAGE_UNDEFINED = 0, @@ -213,16 +498,35 @@ typedef enum { PAL_IMAGE_USAGE_SAMPLED = PAL_BIT(5) } PalImageUsages; +/** + * @enum PalImageViewUsages + * @brief Image view usages. + * + * All image view usages follow the format `PAL_IMAGE_VIEW_USAGE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_IMAGE_VIEW_USAGE_UNDEFINED = 0, - PAL_IMAGE_VIEW_USAGE_COLOR = PAL_BIT(0), PAL_IMAGE_VIEW_USAGE_DEPTH = PAL_BIT(1), PAL_IMAGE_VIEW_USAGE_STENCIL = PAL_BIT(2), PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE = PAL_BIT(3) } PalImageViewUsages; +/** + * @enum PalShaderFormats + * @brief Shader formats. + * + * All shader formats follow the format `PAL_SHADER_FORMAT_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_SHADER_FORMAT_SPIRV = PAL_BIT(0), PAL_SHADER_FORMAT_DXIL = PAL_BIT(1), @@ -232,6 +536,16 @@ typedef enum { PAL_SHADER_FORMAT_PPM = PAL_BIT(5) } PalShaderFormats; +/** + * @enum PalAdapterFeatures + * @brief Adapter features. + * + * All adapter features follow the format `PAL_ADAPTER_FEATURE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY = PAL_BIT64(0), PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING = PAL_BIT64(1), @@ -268,17 +582,47 @@ typedef enum { PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(32) } PalAdapterFeatures; +/** + * @enum PalLoadOp + * @brief Load operation type. + * + * All load operation type follow the format `PAL_LOAD_OP_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_LOAD_OP_LOAD, PAL_LOAD_OP_CLEAR, PAL_LOAD_OP_DONT_CARE, } PalLoadOp; +/** + * @enum PalStoreOp + * @brief Store operation type. + * + * All store operation type follow the format `PAL_STORE_OP_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_STORE_OP_STORE, PAL_STORE_OP_DONT_CARE } PalStoreOp; +/** + * @enum PalMemoryType + * @brief Memory types. + * + * All memory types follow the format `PAL_MEMORY_TYPE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_MEMORY_TYPE_GPU_ONLY, PAL_MEMORY_TYPE_CPU_UPLOAD, @@ -287,12 +631,32 @@ typedef enum { PAL_MEMORY_TYPE_MAX } PalMemoryType; +/** + * @enum PalImageType + * @brief Image types. + * + * All image types follow the format `PAL_IMAGE_TYPE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_IMAGE_TYPE_1D, PAL_IMAGE_TYPE_2D, PAL_IMAGE_TYPE_3D } PalImageType; +/** + * @enum PalImageViewType + * @brief Image view types. + * + * All image view types follow the format `PAL_IMAGE_VIEW_TYPE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_IMAGE_VIEW_TYPE_1D, PAL_IMAGE_VIEW_TYPE_1D_ARRAY, @@ -303,15 +667,35 @@ typedef enum { PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY, } PalImageViewType; +/** + * @enum PalSwapchainFormat + * @brief swapchain format types. + * + * All swapchain format types follow the format `PAL_SWAPCHAIN_FORMAT_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB, PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB, PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB, - PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10, + PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10, /**< HDR.*/ PAL_SWAPCHAIN_FORMAT_MAX } PalSwapchainFormat; +/** + * @enum PalShaderStage + * @brief shader stage types. + * + * All shader stage types follow the format `PAL_SHADER_STAGE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_SHADER_STAGE_UNDEFINED, @@ -331,6 +715,16 @@ typedef enum { PAL_SHADER_STAGE_CALLABLE } PalShaderStage; +/** + * @enum PalSampleCount + * @brief sample count. + * + * All sample count follow the format `PAL_SAMPLE_COUNT_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_SAMPLE_COUNT_1, PAL_SAMPLE_COUNT_2, @@ -341,6 +735,16 @@ typedef enum { PAL_SAMPLE_COUNT_64 } PalSampleCount; +/** + * @enum PalPrimitiveTopology + * @brief Primitve topology types. + * + * All primitve topology types follow the format `PAL_PRIMITIVE_TOPOLOGY_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, @@ -350,74 +754,144 @@ typedef enum { PAL_PRIMITIVE_TOPOLOGY_PATCH } PalPrimitiveTopology; +/** + * @enum PalCullMode + * @brief Cull modes. + * + * All cull modes follow the format `PAL_CULL_MODE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_CULL_MODE_NONE, PAL_CULL_MODE_FRONT, PAL_CULL_MODE_BACK } PalCullMode; +/** + * @enum PalFrontFace + * @brief Front face modes. + * + * All front face modes follow the format `PAL_FRONT_FACE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_FRONT_FACE_CLOCKWISE, PAL_FRONT_FACE_COUNTER_CLOCKWISE } PalFrontFace; +/** + * @enum PalPolygonMode + * @brief Polygon modes. + * + * All polygon modes follow the format `PAL_POLYGON_MODE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_POLYGON_MODE_FILL, PAL_POLYGON_MODE_LINE } PalPolygonMode; +/** + * @enum PalVertexType + * @brief Vertex attribute types. + * + * All vertex attribute types follow the format `PAL_VERTEX_TYPE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_VERTEX_TYPE_UNDEFINED, - PAL_VERTEX_TYPE_INT32, - PAL_VERTEX_TYPE_INT32_2, - PAL_VERTEX_TYPE_INT32_3, - PAL_VERTEX_TYPE_INT32_4, - - PAL_VERTEX_TYPE_UINT32, - PAL_VERTEX_TYPE_UINT32_2, - PAL_VERTEX_TYPE_UINT32_3, - PAL_VERTEX_TYPE_UINT32_4, - - PAL_VERTEX_TYPE_INT8_2, - PAL_VERTEX_TYPE_INT8_4, - PAL_VERTEX_TYPE_UINT8_2, - PAL_VERTEX_TYPE_UINT8_4, - - PAL_VERTEX_TYPE_INT8_2NORM, - PAL_VERTEX_TYPE_INT8_4NORM, - PAL_VERTEX_TYPE_UINT8_2NORM, - PAL_VERTEX_TYPE_UINT8_4NORM, - - PAL_VERTEX_TYPE_INT16_2, - PAL_VERTEX_TYPE_INT16_4, - PAL_VERTEX_TYPE_UINT16_2, - PAL_VERTEX_TYPE_UINT16_4, - - PAL_VERTEX_TYPE_INT16_2NORM, - PAL_VERTEX_TYPE_INT16_4NORM, - PAL_VERTEX_TYPE_UINT16_2NORM, - PAL_VERTEX_TYPE_UINT16_4NORM, - - PAL_VERTEX_TYPE_FLOAT, - PAL_VERTEX_TYPE_FLOAT2, - PAL_VERTEX_TYPE_FLOAT3, - PAL_VERTEX_TYPE_FLOAT4, - - PAL_VERTEX_TYPE_HALF_FLOAT16_2, - PAL_VERTEX_TYPE_HALF_FLOAT16_4 + PAL_VERTEX_TYPE_INT32, /**< Int32.*/ + PAL_VERTEX_TYPE_INT32_2, /**< Int32 vec2 or array[2].*/ + PAL_VERTEX_TYPE_INT32_3, /**< Int32 vec3 or array[3].*/ + PAL_VERTEX_TYPE_INT32_4, /**< Int32 vec4 or array[4].*/ + + PAL_VERTEX_TYPE_UINT32, /**< Uint32.*/ + PAL_VERTEX_TYPE_UINT32_2, /**< Uint32 vec2 or array[2].*/ + PAL_VERTEX_TYPE_UINT32_3, /**< Uint32 vec3 or array[3].*/ + PAL_VERTEX_TYPE_UINT32_4, /**< Uint32 vec4 or array[4].*/ + + PAL_VERTEX_TYPE_INT8_2, /**< Int8 vec2 or array[2].*/ + PAL_VERTEX_TYPE_INT8_4, /**< Int8 vec4 or array[4].*/ + PAL_VERTEX_TYPE_UINT8_2, /**< Uint8 vec2 or array[2].*/ + PAL_VERTEX_TYPE_UINT8_4, /**< Uint8 vec4 or array[4].*/ + + PAL_VERTEX_TYPE_INT8_2NORM, /**< Int8 vec2 or array[2] normalized.*/ + PAL_VERTEX_TYPE_INT8_4NORM, /**< Int8 vec4 or array[4] normalized.*/ + PAL_VERTEX_TYPE_UINT8_2NORM, /**< Uint8 vec2 or array[2] normalized.*/ + PAL_VERTEX_TYPE_UINT8_4NORM, /**< Uint8 vec4 or array[4] normalized.*/ + + PAL_VERTEX_TYPE_INT16_2, /**< Int16 vec2 or array[2].*/ + PAL_VERTEX_TYPE_INT16_4, /**< Int16 vec4 or array[4].*/ + PAL_VERTEX_TYPE_UINT16_2, /**< Uint16 vec2 or array[2].*/ + PAL_VERTEX_TYPE_UINT16_4, /**< Uint16 vec4 or array[4].*/ + + PAL_VERTEX_TYPE_INT16_2NORM, /**< Int16 vec2 or array[2] normalized.*/ + PAL_VERTEX_TYPE_INT16_4NORM, /**< Int16 vec4 or array[4] normalized.*/ + PAL_VERTEX_TYPE_UINT16_2NORM, /**< Uint16 vec2 or array[2] normalized.*/ + PAL_VERTEX_TYPE_UINT16_4NORM, /**< Uint16 vec4 or array[4] normalized.*/ + + PAL_VERTEX_TYPE_FLOAT, /**< float*/ + PAL_VERTEX_TYPE_FLOAT2, /**< float vec2 or array[2].*/ + PAL_VERTEX_TYPE_FLOAT3, /**< float vec3 or array[3].*/ + PAL_VERTEX_TYPE_FLOAT4, /**< float vec4 or array[4].*/ + + PAL_VERTEX_TYPE_HALF_FLOAT16_2, /**< float16 vec2 or array[2].*/ + PAL_VERTEX_TYPE_HALF_FLOAT16_4 /**< float16 vec4 or array[4].*/ } PalVertexType; +/** + * @enum PalCommandBufferType + * @brief Command buffer types. + * + * All command buffer types follow the format `PAL_COMMAND_BUFFER_TYPE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_COMMAND_BUFFER_TYPE_PRIMARY, PAL_COMMAND_BUFFER_TYPE_SECONDARY } PalCommandBufferType; +/** + * @enum PalVertexLayoutType + * @brief Vertex layout types. + * + * All vertex layout types follow the format `PAL_VERTEX_LAYOUT_TYPE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX, PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE } PalVertexLayoutType; +/** + * @enum PalCompareOp + * @brief Compare operation modes. + * + * All compare operation modes follow the format `PAL_COMPARE_OP_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_COMPARE_OP_NEVER, PAL_COMPARE_OP_LESS, @@ -429,6 +903,16 @@ typedef enum { PAL_COMPARE_OP_ALWAYS } PalCompareOp; +/** + * @enum PalStencilOp + * @brief Stencil operation modes. + * + * All stencil operation modes follow the format `PAL_STENCIL_OP_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_STENCIL_OP_KEEP, PAL_STENCIL_OP_ZERO, @@ -440,6 +924,16 @@ typedef enum { PAL_STENCIL_OP_DECREMENT_AND_WRAP } PalStencilOp; +/** + * @enum PalBlendOp + * @brief Blend operation modes. + * + * All blend operation modes follow the format `PAL_BLEND_OP_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_BLEND_OP_ADD, PAL_BLEND_OP_SUBTRACT, @@ -448,6 +942,16 @@ typedef enum { PAL_BLEND_OP_MAX } PalBlendOp; +/** + * @enum PalBlendOp + * @brief Blend factor modes. + * + * All blend factor modes follow the format `PAL_BLEND_FACTOR_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_BLEND_FACTOR_ZERO, PAL_BLEND_FACTOR_ONE, @@ -465,6 +969,19 @@ typedef enum { PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA } PalBlendFactor; +/** + * @enum PalColorMask + * @brief Color mask flags. Multiple color mask flags can be OR'ed together using bitwise + * OR operator (`|`). + * + * `PAL_COLOR_MASK_NONE` is not a bit and must not be combined with other bits. + * + * All color mask flags follow the format `PAL_BLEND_FACTOR_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_COLOR_MASK_NONE = 0, @@ -474,6 +991,16 @@ typedef enum { PAL_COLOR_MASK_ALPHA = PAL_BIT(3), } PalColorMask; +/** + * @enum PalResolveMode + * @brief Resolve modes. + * + * All resolve modes follow the format `PAL_RESOLVE_MODE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_RESOLVE_MODE_NONE = 0, @@ -483,6 +1010,16 @@ typedef enum { PAL_RESOLVE_MODE_MAX } PalResolveMode; +/** + * @enum PalFragmentShadingRate + * @brief Fragment shading rates. + * + * All fragment shading rates follow the format `PAL_FRAGMENT_SHADING_RATE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_FRAGMENT_SHADING_RATE_1X1, PAL_FRAGMENT_SHADING_RATE_1X2, @@ -495,6 +1032,16 @@ typedef enum { PAL_FRAGMENT_SHADING_RATE_MAX } PalFragmentShadingRate; +/** + * @enum PalFragmentShadingRateCombinerOp + * @brief Fragment shading rate combiner operaton modes. + * + * All fragment shading rate combiner operation modes follow the format + * `PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_**` for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP, PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE, @@ -503,22 +1050,60 @@ typedef enum { PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL } PalFragmentShadingRateCombinerOp; +/** + * @enum PalAccelerationStructureType + * @brief Acceleration structure types. + * + * All acceleration structure types follow the format `PAL_ACCELERATION_STRUCTURE_TYPE_**` + * for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL, PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL } PalAccelerationStructureType; +/** + * @enum PalGeometryType + * @brief Geometry types. + * + * All geometry types follow the format `PAL_GEOMETRY_TYPE_**` for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_GEOMETRY_TYPE_TRIANGLE, PAL_GEOMETRY_TYPE_AABBS, PAL_GEOMETRY_TYPE_INSTANCE } PalGeometryType; +/** + * @enum PalIndexType + * @brief Index types. + * + * All index types follow the format `PAL_INDEX_TYPE_**` for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_INDEX_TYPE_UINT16, PAL_INDEX_TYPE_UINT32 } PalIndexType; +/** + * @enum PalBufferUsages + * @brief Buffer usages. Multiple buffer usages can be OR'ed together using bitwise + * OR operator (`|`). + * + * All buffer usages follow the format `PAL_BUFFER_USAGE_**` for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_BUFFER_USAGE_VERTEX = PAL_BIT(0), PAL_BUFFER_USAGE_INDEX = PAL_BIT(1), @@ -542,6 +1127,15 @@ enum PalDebugMessageType { PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE }; +/** + * @enum PalUsageState + * @brief Usage states. + * + * All usage states follow the format `PAL_USAGE_STATE_**` for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_USAGE_STATE_UNDEFINED, @@ -568,6 +1162,15 @@ typedef enum { PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE } PalUsageState; +/** + * @enum PalDescriptorType + * @brief Descriptor types. + * + * All descriptor types follow the format `PAL_DESCRIPTOR_TYPE_**` for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER, PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER, @@ -577,6 +1180,16 @@ typedef enum { PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE } PalDescriptorType; +/** + * @enum PalRayTracingShaderGroupType + * @brief Ray tracing shader group types. + * + * All ray tracing shader group types follow the format `PAL_RAY_TRACING_SHADER_GROUP_TYPE_**` + * for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef enum { PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL, PAL_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT, diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index c9988a75..01292112 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -949,9 +949,10 @@ bool rayTracingTest() } // make sure the TLAS builds before the tracing - oldAsUsageStateInfo = newAsUsageStateInfo; + oldAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; + oldAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; newAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; - newAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; + newAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; result = palCmdMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { From 96c7618d963b2d7c39bc21269ff5677e73a0608c Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 23 Feb 2026 15:58:13 +0000 Subject: [PATCH 095/372] add more graphics system docs --- include/pal/pal_core.h | 1 + include/pal/pal_graphics.h | 297 ++++++++++++++++++++++++++++++------- src/graphics/pal_vulkan.c | 63 ++++---- 3 files changed, 280 insertions(+), 81 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 694a2783..e88ce5d6 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -84,6 +84,7 @@ typedef _Bool bool; #define PAL_BIT(x) 1 << x #define PAL_BIT64(x) 1ULL << x +#define PAL_INFINITE UINT32_MAX /** * @brief A signed 8-bit integer diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 24bc8a0a..21fa63c7 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1196,25 +1196,38 @@ typedef enum { PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT } PalRayTracingShaderGroupType; +/** + * @struct PalAdapterInfo + * @brief Information about an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 vendorId; Uint32 deviceId; - PalAdapterType type; - PalAdapterApiType apiType; - PalShaderFormats shaderFormats; + PalAdapterType type; /**< Discrete, Integrated, etc.*/ + PalAdapterApiType apiType; /**< Vulkan, D3D12, etc.*/ + PalShaderFormats shaderFormats; /**< Supported shader formats mask (eg. Spirv, DXIL, ect).*/ Uint64 vram; Uint64 sharedMemory; - Uint64 version; - char versionString[PAL_ADAPTER_VERSION_SIZE]; + Uint64 version; /**< Adapter version.*/ + char versionString[PAL_ADAPTER_VERSION_SIZE]; /**< Adapter version in string.*/ char name[PAL_ADAPTER_NAME_SIZE]; - char backendName[PAL_ADAPTER_NAME_SIZE]; + char backendName[PAL_ADAPTER_NAME_SIZE]; /**< Adapter backend name (eg. `PAL`, `Custom`).*/ } PalAdapterInfo; +/** + * @struct PalAdapterCapabilities + * @brief Capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - bool debugLayer; - Uint32 maxComputeQueues; - Uint32 maxGraphicsQueues; - Uint32 maxCopyQueues; + Uint32 maxComputeQueues; /**< Number of compute queues that can be created.*/ + Uint32 maxGraphicsQueues; /**< Number of graphics queues that can be created.*/ + Uint32 maxCopyQueues; /**< Number of copy queues that can be created.*/ Uint32 maxImageWidth; Uint32 maxImageHeight; Uint32 maxImageDepth; @@ -1229,48 +1242,97 @@ typedef struct { Uint32 maxUniformBufferSize; Uint32 maxStorageBufferSize; Uint32 maxPushConstantSize; - Uint32 maxComputeWorkGroupInvocations; - Uint32 maxComputeWorkGroupCount[3]; - Uint32 maxComputeWorkGroupSize[3]; + Uint32 maxComputeWorkGroupInvocations; /**< Max compute threads per workgroup across all axis.*/ + Uint32 maxComputeWorkGroupCount[3]; /**< Max compute workgroups per axis.*/ + Uint32 maxComputeWorkGroupSize[3]; /**< Max compute threads per workgroup per axis.*/ } PalAdapterCapabilities; +/** + * @struct PalDepthStencilCapabilities + * @brief Depth stencil capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - bool independentDepthStencilResolve; - bool depthResolveModes[PAL_MAX_RESOLVE_MODES]; + /** If false, depth and stencil resolve modes must be the same.*/ + bool independentDepthStencilResolve; + + /** Bool array of supported depth resolve modes. + * (eg. depthResolveModes[`PAL_RESOLVE_MODE_SAMPLE_ZERO`]).*/ + bool depthResolveModes[PAL_MAX_RESOLVE_MODES]; + + /** Bool array of supported stencil resolve modes. + * (eg. stencilResolveModes[`PAL_RESOLVE_MODE_SAMPLE_ZERO`]).*/ bool stencilResolveModes[PAL_MAX_RESOLVE_MODES]; } PalDepthStencilCapabilities; +/** + * @struct PalFragmentShadingRateCapabilities + * @brief Fragment shading rate capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { + /** Bool array of supported fragment shading rates. + * (eg. shadingRates[`PAL_FRAGMENT_SHADING_RATE_2X1`]).*/ bool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; Uint32 minTexelWidth; Uint32 minTexelHeight; Uint32 maxTexelWidth; Uint32 maxTexelHeight; + + /** Bool array of supported fragment shading rate combiner operations. + * (eg. combinerOps[`PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP`]).*/ bool combinerOps[PAL_MAX_COMBINER_OPS]; } PalFragmentShadingRateCapabilities; +/** + * @struct PalMeshShaderCapabilities + * @brief Mesh shader capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 maxMeshOutputPrimitives; - Uint32 maxMeshOutputVertices; - Uint32 maxTaskWorkGroupInvocations; - Uint32 maxMeshWorkGroupInvocations; - Uint32 maxTaskWorkGroupCount[3]; - Uint32 maxMeshWorkGroupCount[3]; + Uint32 maxMeshOutputPrimitives; /**< Max mesh primitives per workgroup.*/ + Uint32 maxMeshOutputVertices; /**< Max mesh vertices per workgroup.*/ + Uint32 maxTaskWorkGroupInvocations; /**< Max task threads per workgroup.*/ + Uint32 maxMeshWorkGroupInvocations; /**< Max mesh threads per workgroup.*/ + Uint32 maxTaskWorkGroupCount[3]; /**< Max task workgroups per axis.*/ + Uint32 maxMeshWorkGroupCount[3]; /**< Max mesh workgroups per axis.*/ } PalMeshShaderCapabilities; +/** + * @struct PalRayTracingCapabilities + * @brief Ray tracing capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 maxRecursionDepth; - Uint32 maxHitAttributeSize; + Uint32 maxHitAttributeSize; /**< Max memory per intersection attributes.*/ Uint32 maxInstanceCount; Uint32 maxPrimitiveCount; Uint32 maxGeometryCount; - Uint32 maxPayloadSize; - Uint32 maxDispatchInvocations; + Uint32 maxPayloadSize; /**< Max memory per ray.*/ + Uint32 maxDispatchInvocations; /**< Max ray threads per dispatch.*/ } PalRayTracingCapabilities; +/** + * @struct PalDescriptorIndexingCapabilities + * @brief Descriptor indexing capabilities of an adapter (GPU). + * + * Bindless images are always supported if Descriptor indexing is supported. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - bool bindlessStorageBuffers; - bool bindlessUniformBuffers; + bool bindlessStorageBuffers; /**< If true, bindless storage buffers are supported.*/ + bool bindlessUniformBuffers; /**< If true, bindless uniform buffers are supported.*/ Uint32 maxImagesPerShaderStage; Uint32 maxImagesPerDescriptorSet; Uint32 maxStorageBuffersPerShaderStage; @@ -1280,11 +1342,26 @@ typedef struct { Uint32 maxDescriptors; } PalDescriptorIndexingCapabilities; +/** + * @struct PalSwapchainCapabilities + * @brief swapchain capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { + /** Bool array of supported present modes. + * (eg. presentModes[`PAL_PRESENT_MODE_FIFO`]).*/ bool presentModes[PAL_PRESENT_MODE_MAX]; + + /** Bool array of supported composite alphas. + * (eg. compositeAlphas[`PAL_COMPOSITE_ALPHA_OPAQUE`]).*/ bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; + + /** Bool array of supported swapchain formats. + * (eg. formats[`PAL_COMPOSITE_ALPHA_OPAQUE`]).*/ bool formats[PAL_SWAPCHAIN_FORMAT_MAX]; - Uint32 minImageCount; + Uint32 minImageCount; Uint32 maxImageCount; Uint32 minImageWidth; Uint32 minImageHeight; @@ -1293,50 +1370,110 @@ typedef struct { Uint32 maxImageArrayLayers; } PalSwapchainCapabilities; +/** + * @struct PalGraphicsWindow + * @brief Information about a graphics window. + * + * This can be allocated statically or dynamically since its used for + * holding native handles. The handles will not be copied. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - void* display; - void* window; + void* display; /**< Can be nullptr depending on platform (eg. Windows).*/ + void* window; /**< Must not be nullptr.*/ } PalGraphicsWindow; +/** + * @struct PalFormatInfo + * @brief Information about a format. This includes the supported image and image view usages + * from the provided format. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - PalFormat format; - PalImageUsages usages; - PalImageViewUsages viewUsages; + PalFormat format; /**< The format.*/ + PalImageUsages usages; /**< Supported image usages of the format.*/ + PalImageViewUsages viewUsages; /**< Supported image view usages of the format.*/ } PalFormatInfo; +/** + * @struct PalImageInfo + * @brief Information about an image. This can be a swapchain image. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 width; - Uint32 height; - Uint32 depthOrArraySize; + Uint32 width; /**< Width of the image in pixels.*/ + Uint32 height; /**< Height of the image in pixels.*/ + Uint32 depthOrArraySize; /**< Depth for 3D image and array size for 2D image.*/ Uint32 mipLevelCount; PalSampleCount sampleCount; - PalImageType type; + PalImageType type; /**< 1D, 2D, 3D.*/ PalFormat format; PalImageUsages usages; } PalImageInfo; +/** + * @struct PalClearValue + * @brief Clear values used with rendering. + * + * If used with a color attachment, the color values will be used and depth and stencil + * will be used with depth stencil attachments. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - float color[4]; - float depth; - Uint32 stencil; + float color[4]; /**< Color for color attachments.*/ + float depth; /**< Depth for depth stencil attachments.*/ + Uint32 stencil; /**< Stencil for depth stencil attachments.*/ } PalClearValue; +/** + * @struct PalAttachmentDesc + * @brief An attachment description. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { PalLoadOp loadOp; PalStoreOp storeOp; - PalResolveMode resolveMode; - Uint32 texelWidth; - Uint32 texelHeight; - PalImageView* imageView; - PalImageView* resolveImageView; + PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ + Uint32 texelWidth; /**< Texel width for fragment shading rate attachment.*/ + Uint32 texelHeight; /**< Texel height for fragment shading rate attachment.*/ + PalImageView* imageView; /**< Image view. Must not be nullptr.*/ + PalImageView* resolveImageView; /**< Optional resolve image view.*/ PalClearValue clearValue; } PalAttachmentDesc; +/** + * @struct PalUsageStateInfo + * @brief Information about resource usage state. This is used with barrier commands. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { PalUsageState usageState; PalShaderStage shaderStage; } PalUsageStateInfo; +/** + * @struct PalViewport + * @brief A viewport in pixels (float). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { float x; float y; @@ -1346,6 +1483,13 @@ typedef struct { float maxDepth; } PalViewport; +/** + * @struct PalRect2D + * @brief A 2D rectangle in pixels. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Int32 x; Int32 y; @@ -1353,40 +1497,93 @@ typedef struct { Uint32 height; } PalRect2D; +/** + * @struct PalMemoryRequirements + * @brief Memory requirements for a resource (image, buffer etc). + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { + /** Bool array of supported memory types. + * (eg. memoryTypes[`PAL_MEMORY_TYPE_GPU_ONLY`]).*/ bool memoryTypes[PAL_MEMORY_TYPE_MAX]; + Uint64 memoryMask; Uint64 size; Uint32 alignment; } PalMemoryRequirements; +/** + * @struct PalInstanceBufferRequirements + * @brief Instance buffer requirements. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint64 size; Uint32 alignment; } PalInstanceBufferRequirements; +/** + * @struct PalCommandBufferSubmitInfo + * @brief Submit information of a command buffer. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint64 waitValue; - Uint64 signalValue; + Uint64 waitValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ + Uint64 signalValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ PalCommandBuffer* cmdBuffer; PalSemaphore* waitSemaphore; PalSemaphore* signalSemaphore; PalFence* fence; } PalCommandBufferSubmitInfo; +/** + * @struct PalSwapchainNextImageInfo + * @brief Next image information of a swapchain. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint64 timeout; - Uint64 signalValue; + Uint64 timeout; /**< Timeout in milliseconds.*/ + Uint64 signalValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ PalSemaphore* signalSemaphore; PalFence* fence; } PalSwapchainNextImageInfo; +/** + * @struct PalSwapchainPresentInfo + * @brief Present information of a swapchain. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 imageIndex; - Uint64 waitValue; + Uint32 imageIndex; /**< Image index to present. Must be 0 and less than max images.*/ + Uint64 waitValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ PalSemaphore* waitSemaphore; } PalSwapchainPresentInfo; +/** + * @struct PalRenderingInfo + * @brief Present information of a swapchain. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 viewCount; Uint32 layerCount; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index ebc49241..da565e69 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -80,7 +80,6 @@ typedef struct { typedef struct { bool useCache; - bool hasDebug; void* handle; Adapter* adapters; VkInstance instance; @@ -2488,40 +2487,36 @@ PalResult PAL_CALL initGraphicsVk( if (debugger) { // layers result = s_Vk.enumerateInstanceLayerProperties(&layerCount, nullptr); - if (result != VK_SUCCESS) { - s_Vk.hasDebug = false; - } - - VkLayerProperties* props = nullptr; - props = palAllocate(s_Vk.allocator, sizeof(VkLayerProperties) * layerCount, 0); - - if (!props) { - return PAL_RESULT_OUT_OF_MEMORY; - } + VkLayerProperties* props = nullptr; + props = palAllocate(s_Vk.allocator, sizeof(VkLayerProperties) * layerCount, 0); + if (!props) { + return PAL_RESULT_OUT_OF_MEMORY; + } - s_Vk.enumerateInstanceLayerProperties(&layerCount, props); - for (int i = 0; i < layerCount; i++) { - const char* name = props[i].layerName; - if (strcmp(name, "VK_LAYER_KHRONOS_validation") == 0) { - hasValidationLayer = true; - break; + s_Vk.enumerateInstanceLayerProperties(&layerCount, props); + for (int i = 0; i < layerCount; i++) { + const char* name = props[i].layerName; + if (strcmp(name, "VK_LAYER_KHRONOS_validation") == 0) { + hasValidationLayer = true; + break; + } } - } - palFree(s_Vk.allocator, props); + palFree(s_Vk.allocator, props); - debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; - debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; - debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; - debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - debugCreateInfo.pUserData = debugger->userData; - debugCreateInfo.pfnUserCallback = debugCallbackVk; - s_Vk.callback = debugger->callback; + debugCreateInfo.pUserData = debugger->userData; + debugCreateInfo.pfnUserCallback = debugCallbackVk; + s_Vk.callback = debugger->callback; + } } // extensions @@ -2579,7 +2574,6 @@ PalResult PAL_CALL initGraphicsVk( const char* layers[2]; layerCount = 0; if (hasValidationLayer && hasExtDebug) { - s_Vk.hasDebug = true; extensions[extensionCount++] = "VK_EXT_debug_utils"; layers[layerCount++] = "VK_LAYER_KHRONOS_validation"; } @@ -2902,7 +2896,6 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( properties2.pNext = &multiViewProps; s_Vk.getPhysicalDeviceProperties2(phyDevice, &properties2); - caps->debugLayer = s_Vk.hasDebug; caps->maxColorAttachments = props.limits.maxColorAttachments; caps->maxImageWidth = props.limits.maxImageDimension2D; caps->maxImageHeight = props.limits.maxImageDimension2D; @@ -5039,6 +5032,7 @@ PalResult PAL_CALL getNextSwapchainImageVk( { VkResult result; Uint32 index = 0; + Uint64 timeInNanoseconds = 0; VkFence fenceHandle = nullptr; VkSemaphore semaphoreHandle = nullptr; Swapchain* vkSwapchain = (Swapchain*)swapchain; @@ -5053,10 +5047,17 @@ PalResult PAL_CALL getNextSwapchainImageVk( semaphoreHandle = vkSemaphore->handle; } + if (info->timeout) { + if (info->timeout == PAL_INFINITE) { + timeInNanoseconds = UINT64_MAX; + } + timeInNanoseconds = info->timeout * 1000000; + } + result = vkSwapchain->device->acquireNextImage( vkSwapchain->device->handle, vkSwapchain->handle, - info->timeout, + timeInNanoseconds, semaphoreHandle, fenceHandle, &index); From cb098e1ff9f4b0d09d08524f3d921962703ee14d Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 28 Feb 2026 13:23:33 +0000 Subject: [PATCH 096/372] start graphics dispatch table docs --- include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 803 ++++++++++++++++++++++++++++++------- 2 files changed, 649 insertions(+), 157 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index e88ce5d6..75c1e257 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -180,7 +180,8 @@ typedef void*(PAL_CALL* PalAllocateFn)( * @brief Function pointer type used for memory deallocations. * * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. - * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must return safely if pointer is nullptr. + * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must return safely if + * pointer is nullptr. * * @since 1.0 * @ingroup pal_core diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 21fa63c7..8af95801 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -221,7 +221,8 @@ typedef struct PalPipelineLayout PalPipelineLayout; /** * @struct PalPipeline - * @brief Opaque handle to a pipeline. This is the same handle used for all pipeline types (Graphics, Compute and Ray tracing). + * @brief Opaque handle to a pipeline. This is the same handle used for all pipeline types + * (Graphics, Compute and Ray tracing). * * @since 1.4 * @ingroup pal_graphics @@ -269,9 +270,9 @@ typedef Uint64 PalDeviceAddress; * @brief Function pointer type used for debug callbacks. * * @param userData Optional pointer to user data passed from ::PalGraphicsDebugger. Can be nullptr. - * @param severity Severity of the message. (`PAL_DEBUG_MESSAGE_SEVERITY_INFO`, + * @param severity Severity of the message. (`PAL_DEBUG_MESSAGE_SEVERITY_INFO`, * `PAL_DEBUG_MESSAGE_SEVERITY_WARNING` and `PAL_DEBUG_MESSAGE_SEVERITY_ERROR`). - * @param type Type of the message. (`PAL_DEBUG_MESSAGE_TYPE_GENERAL`, + * @param type Type of the message. (`PAL_DEBUG_MESSAGE_TYPE_GENERAL`, * `PAL_DEBUG_MESSAGE_TYPE_VALIDATION` and `PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE`). * @param msg Null-terminated UTF-8 debug message. * @@ -309,9 +310,9 @@ typedef enum { * * All adapter api types follow the format `PAL_ADAPTER_API_TYPE_**` for * consistency and API use. - * + * * (`PAL_ADAPTER_API_TYPE_OPENGL`, `PAL_ADAPTER_API_TYPE_GLES`, `PAL_ADAPTER_API_TYPE_D3D11` - * `PAL_ADAPTER_API_TYPE_D3D9`, `PAL_ADAPTER_API_TYPE_PPM`, etc) will not be supported by the + * `PAL_ADAPTER_API_TYPE_D3D9`, `PAL_ADAPTER_API_TYPE_PPM`, etc) will not be supported by the * core graphics system. These are custom backends that can be use to extend the graphics systems. * * @since 1.4 @@ -479,7 +480,8 @@ typedef enum { /** * @enum PalImageUsages - * @brief Image usages. + * @brief Image usages. Multiple image usages can be OR'ed together using bitwise + * OR operator (`|`). * * All image usages follow the format `PAL_IMAGE_USAGE_**` for * consistency and API use. @@ -500,7 +502,8 @@ typedef enum { /** * @enum PalImageViewUsages - * @brief Image view usages. + * @brief Image view usages. Multiple image view usages can be OR'ed together using bitwise + * OR operator (`|`). * * All image view usages follow the format `PAL_IMAGE_VIEW_USAGE_**` for * consistency and API use. @@ -519,7 +522,7 @@ typedef enum { /** * @enum PalShaderFormats - * @brief Shader formats. + * @brief Shader formats. This is a bitmask. * * All shader formats follow the format `PAL_SHADER_FORMAT_**` for * consistency and API use. @@ -538,7 +541,7 @@ typedef enum { /** * @enum PalAdapterFeatures - * @brief Adapter features. + * @brief Adapter features. This is a bitmask. * * All adapter features follow the format `PAL_ADAPTER_FEATURE_**` for * consistency and API use. @@ -813,43 +816,43 @@ typedef enum { typedef enum { PAL_VERTEX_TYPE_UNDEFINED, - PAL_VERTEX_TYPE_INT32, /**< Int32.*/ + PAL_VERTEX_TYPE_INT32, /**< Int32.*/ PAL_VERTEX_TYPE_INT32_2, /**< Int32 vec2 or array[2].*/ PAL_VERTEX_TYPE_INT32_3, /**< Int32 vec3 or array[3].*/ PAL_VERTEX_TYPE_INT32_4, /**< Int32 vec4 or array[4].*/ - PAL_VERTEX_TYPE_UINT32, /**< Uint32.*/ + PAL_VERTEX_TYPE_UINT32, /**< Uint32.*/ PAL_VERTEX_TYPE_UINT32_2, /**< Uint32 vec2 or array[2].*/ PAL_VERTEX_TYPE_UINT32_3, /**< Uint32 vec3 or array[3].*/ PAL_VERTEX_TYPE_UINT32_4, /**< Uint32 vec4 or array[4].*/ - PAL_VERTEX_TYPE_INT8_2, /**< Int8 vec2 or array[2].*/ - PAL_VERTEX_TYPE_INT8_4, /**< Int8 vec4 or array[4].*/ + PAL_VERTEX_TYPE_INT8_2, /**< Int8 vec2 or array[2].*/ + PAL_VERTEX_TYPE_INT8_4, /**< Int8 vec4 or array[4].*/ PAL_VERTEX_TYPE_UINT8_2, /**< Uint8 vec2 or array[2].*/ PAL_VERTEX_TYPE_UINT8_4, /**< Uint8 vec4 or array[4].*/ - PAL_VERTEX_TYPE_INT8_2NORM, /**< Int8 vec2 or array[2] normalized.*/ - PAL_VERTEX_TYPE_INT8_4NORM, /**< Int8 vec4 or array[4] normalized.*/ + PAL_VERTEX_TYPE_INT8_2NORM, /**< Int8 vec2 or array[2] normalized.*/ + PAL_VERTEX_TYPE_INT8_4NORM, /**< Int8 vec4 or array[4] normalized.*/ PAL_VERTEX_TYPE_UINT8_2NORM, /**< Uint8 vec2 or array[2] normalized.*/ PAL_VERTEX_TYPE_UINT8_4NORM, /**< Uint8 vec4 or array[4] normalized.*/ - PAL_VERTEX_TYPE_INT16_2, /**< Int16 vec2 or array[2].*/ - PAL_VERTEX_TYPE_INT16_4, /**< Int16 vec4 or array[4].*/ + PAL_VERTEX_TYPE_INT16_2, /**< Int16 vec2 or array[2].*/ + PAL_VERTEX_TYPE_INT16_4, /**< Int16 vec4 or array[4].*/ PAL_VERTEX_TYPE_UINT16_2, /**< Uint16 vec2 or array[2].*/ PAL_VERTEX_TYPE_UINT16_4, /**< Uint16 vec4 or array[4].*/ - PAL_VERTEX_TYPE_INT16_2NORM, /**< Int16 vec2 or array[2] normalized.*/ - PAL_VERTEX_TYPE_INT16_4NORM, /**< Int16 vec4 or array[4] normalized.*/ + PAL_VERTEX_TYPE_INT16_2NORM, /**< Int16 vec2 or array[2] normalized.*/ + PAL_VERTEX_TYPE_INT16_4NORM, /**< Int16 vec4 or array[4] normalized.*/ PAL_VERTEX_TYPE_UINT16_2NORM, /**< Uint16 vec2 or array[2] normalized.*/ PAL_VERTEX_TYPE_UINT16_4NORM, /**< Uint16 vec4 or array[4] normalized.*/ - PAL_VERTEX_TYPE_FLOAT, /**< float*/ + PAL_VERTEX_TYPE_FLOAT, /**< float*/ PAL_VERTEX_TYPE_FLOAT2, /**< float vec2 or array[2].*/ PAL_VERTEX_TYPE_FLOAT3, /**< float vec3 or array[3].*/ PAL_VERTEX_TYPE_FLOAT4, /**< float vec4 or array[4].*/ PAL_VERTEX_TYPE_HALF_FLOAT16_2, /**< float16 vec2 or array[2].*/ - PAL_VERTEX_TYPE_HALF_FLOAT16_4 /**< float16 vec4 or array[4].*/ + PAL_VERTEX_TYPE_HALF_FLOAT16_4 /**< float16 vec4 or array[4].*/ } PalVertexType; /** @@ -971,7 +974,7 @@ typedef enum { /** * @enum PalColorMask - * @brief Color mask flags. Multiple color mask flags can be OR'ed together using bitwise + * @brief Color mask flags. Multiple color mask flags can be OR'ed together using bitwise * OR operator (`|`). * * `PAL_COLOR_MASK_NONE` is not a bit and must not be combined with other bits. @@ -1036,7 +1039,7 @@ typedef enum { * @enum PalFragmentShadingRateCombinerOp * @brief Fragment shading rate combiner operaton modes. * - * All fragment shading rate combiner operation modes follow the format + * All fragment shading rate combiner operation modes follow the format * `PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_**` for consistency and API use. * * @since 1.4 @@ -1054,7 +1057,7 @@ typedef enum { * @enum PalAccelerationStructureType * @brief Acceleration structure types. * - * All acceleration structure types follow the format `PAL_ACCELERATION_STRUCTURE_TYPE_**` + * All acceleration structure types follow the format `PAL_ACCELERATION_STRUCTURE_TYPE_**` * for consistency and API use. * * @since 1.4 @@ -1184,7 +1187,7 @@ typedef enum { * @enum PalRayTracingShaderGroupType * @brief Ray tracing shader group types. * - * All ray tracing shader group types follow the format `PAL_RAY_TRACING_SHADER_GROUP_TYPE_**` + * All ray tracing shader group types follow the format `PAL_RAY_TRACING_SHADER_GROUP_TYPE_**` * for consistency and API use. * * @since 1.4 @@ -1206,12 +1209,12 @@ typedef enum { typedef struct { Uint32 vendorId; Uint32 deviceId; - PalAdapterType type; /**< Discrete, Integrated, etc.*/ - PalAdapterApiType apiType; /**< Vulkan, D3D12, etc.*/ + PalAdapterType type; /**< Discrete, Integrated, etc.*/ + PalAdapterApiType apiType; /**< Vulkan, D3D12, etc.*/ PalShaderFormats shaderFormats; /**< Supported shader formats mask (eg. Spirv, DXIL, ect).*/ Uint64 vram; Uint64 sharedMemory; - Uint64 version; /**< Adapter version.*/ + Uint64 version; /**< Adapter version.*/ char versionString[PAL_ADAPTER_VERSION_SIZE]; /**< Adapter version in string.*/ char name[PAL_ADAPTER_NAME_SIZE]; char backendName[PAL_ADAPTER_NAME_SIZE]; /**< Adapter backend name (eg. `PAL`, `Custom`).*/ @@ -1225,9 +1228,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxComputeQueues; /**< Number of compute queues that can be created.*/ + Uint32 maxComputeQueues; /**< Number of compute queues that can be created.*/ Uint32 maxGraphicsQueues; /**< Number of graphics queues that can be created.*/ - Uint32 maxCopyQueues; /**< Number of copy queues that can be created.*/ + Uint32 maxCopyQueues; /**< Number of copy queues that can be created.*/ Uint32 maxImageWidth; Uint32 maxImageHeight; Uint32 maxImageDepth; @@ -1243,24 +1246,24 @@ typedef struct { Uint32 maxStorageBufferSize; Uint32 maxPushConstantSize; Uint32 maxComputeWorkGroupInvocations; /**< Max compute threads per workgroup across all axis.*/ - Uint32 maxComputeWorkGroupCount[3]; /**< Max compute workgroups per axis.*/ - Uint32 maxComputeWorkGroupSize[3]; /**< Max compute threads per workgroup per axis.*/ + Uint32 maxComputeWorkGroupCount[3]; /**< Max compute workgroups per axis.*/ + Uint32 maxComputeWorkGroupSize[3]; /**< Max compute threads per workgroup per axis.*/ } PalAdapterCapabilities; /** * @struct PalDepthStencilCapabilities * @brief Depth stencil capabilities of an adapter (GPU). - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { /** If false, depth and stencil resolve modes must be the same.*/ - bool independentDepthStencilResolve; + bool independentDepthStencilResolve; - /** Bool array of supported depth resolve modes. + /** Bool array of supported depth resolve modes. * (eg. depthResolveModes[`PAL_RESOLVE_MODE_SAMPLE_ZERO`]).*/ - bool depthResolveModes[PAL_MAX_RESOLVE_MODES]; + bool depthResolveModes[PAL_MAX_RESOLVE_MODES]; /** Bool array of supported stencil resolve modes. * (eg. stencilResolveModes[`PAL_RESOLVE_MODE_SAMPLE_ZERO`]).*/ @@ -1270,12 +1273,12 @@ typedef struct { /** * @struct PalFragmentShadingRateCapabilities * @brief Fragment shading rate capabilities of an adapter (GPU). - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - /** Bool array of supported fragment shading rates. + /** Bool array of supported fragment shading rates. * (eg. shadingRates[`PAL_FRAGMENT_SHADING_RATE_2X1`]).*/ bool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; Uint32 minTexelWidth; @@ -1291,23 +1294,23 @@ typedef struct { /** * @struct PalMeshShaderCapabilities * @brief Mesh shader capabilities of an adapter (GPU). - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - Uint32 maxMeshOutputPrimitives; /**< Max mesh primitives per workgroup.*/ - Uint32 maxMeshOutputVertices; /**< Max mesh vertices per workgroup.*/ + Uint32 maxMeshOutputPrimitives; /**< Max mesh primitives per workgroup.*/ + Uint32 maxMeshOutputVertices; /**< Max mesh vertices per workgroup.*/ Uint32 maxTaskWorkGroupInvocations; /**< Max task threads per workgroup.*/ Uint32 maxMeshWorkGroupInvocations; /**< Max mesh threads per workgroup.*/ - Uint32 maxTaskWorkGroupCount[3]; /**< Max task workgroups per axis.*/ - Uint32 maxMeshWorkGroupCount[3]; /**< Max mesh workgroups per axis.*/ + Uint32 maxTaskWorkGroupCount[3]; /**< Max task workgroups per axis.*/ + Uint32 maxMeshWorkGroupCount[3]; /**< Max mesh workgroups per axis.*/ } PalMeshShaderCapabilities; /** * @struct PalRayTracingCapabilities * @brief Ray tracing capabilities of an adapter (GPU). - * + * * @since 1.4 * @ingroup pal_graphics */ @@ -1317,16 +1320,16 @@ typedef struct { Uint32 maxInstanceCount; Uint32 maxPrimitiveCount; Uint32 maxGeometryCount; - Uint32 maxPayloadSize; /**< Max memory per ray.*/ + Uint32 maxPayloadSize; /**< Max memory per ray.*/ Uint32 maxDispatchInvocations; /**< Max ray threads per dispatch.*/ } PalRayTracingCapabilities; /** * @struct PalDescriptorIndexingCapabilities * @brief Descriptor indexing capabilities of an adapter (GPU). - * + * * Bindless images are always supported if Descriptor indexing is supported. - * + * * @since 1.4 * @ingroup pal_graphics */ @@ -1345,7 +1348,7 @@ typedef struct { /** * @struct PalSwapchainCapabilities * @brief swapchain capabilities of an adapter (GPU). - * + * * @since 1.4 * @ingroup pal_graphics */ @@ -1353,7 +1356,7 @@ typedef struct { /** Bool array of supported present modes. * (eg. presentModes[`PAL_PRESENT_MODE_FIFO`]).*/ bool presentModes[PAL_PRESENT_MODE_MAX]; - + /** Bool array of supported composite alphas. * (eg. compositeAlphas[`PAL_COMPOSITE_ALPHA_OPAQUE`]).*/ bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; @@ -1361,7 +1364,7 @@ typedef struct { /** Bool array of supported swapchain formats. * (eg. formats[`PAL_COMPOSITE_ALPHA_OPAQUE`]).*/ bool formats[PAL_SWAPCHAIN_FORMAT_MAX]; - Uint32 minImageCount; + Uint32 minImageCount; Uint32 maxImageCount; Uint32 minImageWidth; Uint32 minImageHeight; @@ -1373,42 +1376,42 @@ typedef struct { /** * @struct PalGraphicsWindow * @brief Information about a graphics window. - * + * * This can be allocated statically or dynamically since its used for * holding native handles. The handles will not be copied. - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { void* display; /**< Can be nullptr depending on platform (eg. Windows).*/ - void* window; /**< Must not be nullptr.*/ + void* window; /**< Must not be nullptr.*/ } PalGraphicsWindow; /** * @struct PalFormatInfo * @brief Information about a format. This includes the supported image and image view usages * from the provided format. - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - PalFormat format; /**< The format.*/ - PalImageUsages usages; /**< Supported image usages of the format.*/ + PalFormat format; /**< The format.*/ + PalImageUsages usages; /**< Supported image usages of the format.*/ PalImageViewUsages viewUsages; /**< Supported image view usages of the format.*/ } PalFormatInfo; /** * @struct PalImageInfo * @brief Information about an image. This can be a swapchain image. - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - Uint32 width; /**< Width of the image in pixels.*/ - Uint32 height; /**< Height of the image in pixels.*/ + Uint32 width; /**< Width of the image in pixels.*/ + Uint32 height; /**< Height of the image in pixels.*/ Uint32 depthOrArraySize; /**< Depth for 3D image and array size for 2D image.*/ Uint32 mipLevelCount; PalSampleCount sampleCount; @@ -1420,35 +1423,35 @@ typedef struct { /** * @struct PalClearValue * @brief Clear values used with rendering. - * + * * If used with a color attachment, the color values will be used and depth and stencil * will be used with depth stencil attachments. - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { float color[4]; /**< Color for color attachments.*/ - float depth; /**< Depth for depth stencil attachments.*/ + float depth; /**< Depth for depth stencil attachments.*/ Uint32 stencil; /**< Stencil for depth stencil attachments.*/ } PalClearValue; /** * @struct PalAttachmentDesc * @brief An attachment description. - * + * * Uninitialized fields may result in undefined behavior. - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { PalLoadOp loadOp; PalStoreOp storeOp; - PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ - Uint32 texelWidth; /**< Texel width for fragment shading rate attachment.*/ - Uint32 texelHeight; /**< Texel height for fragment shading rate attachment.*/ - PalImageView* imageView; /**< Image view. Must not be nullptr.*/ + PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ + Uint32 texelWidth; /**< Texel width for fragment shading rate attachment.*/ + Uint32 texelHeight; /**< Texel height for fragment shading rate attachment.*/ + PalImageView* imageView; /**< Image view. Must not be nullptr.*/ PalImageView* resolveImageView; /**< Optional resolve image view.*/ PalClearValue clearValue; } PalAttachmentDesc; @@ -1456,9 +1459,9 @@ typedef struct { /** * @struct PalUsageStateInfo * @brief Information about resource usage state. This is used with barrier commands. - * + * * Uninitialized fields may result in undefined behavior. - * + * * @since 1.4 * @ingroup pal_graphics */ @@ -1470,7 +1473,7 @@ typedef struct { /** * @struct PalViewport * @brief A viewport in pixels (float). - * + * * @since 1.4 * @ingroup pal_graphics */ @@ -1486,7 +1489,7 @@ typedef struct { /** * @struct PalRect2D * @brief A 2D rectangle in pixels. - * + * * @since 1.4 * @ingroup pal_graphics */ @@ -1500,7 +1503,7 @@ typedef struct { /** * @struct PalMemoryRequirements * @brief Memory requirements for a resource (image, buffer etc). - * + * * @since 1.4 * @ingroup pal_graphics */ @@ -1517,7 +1520,7 @@ typedef struct { /** * @struct PalInstanceBufferRequirements * @brief Instance buffer requirements. - * + * * @since 1.4 * @ingroup pal_graphics */ @@ -1529,14 +1532,14 @@ typedef struct { /** * @struct PalCommandBufferSubmitInfo * @brief Submit information of a command buffer. - * + * * Uninitialized fields may result in undefined behavior. - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - Uint64 waitValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ + Uint64 waitValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ Uint64 signalValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ PalCommandBuffer* cmdBuffer; PalSemaphore* waitSemaphore; @@ -1547,14 +1550,14 @@ typedef struct { /** * @struct PalSwapchainNextImageInfo * @brief Next image information of a swapchain. - * + * * Uninitialized fields may result in undefined behavior. - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - Uint64 timeout; /**< Timeout in milliseconds.*/ + Uint64 timeout; /**< Timeout in milliseconds.*/ Uint64 signalValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ PalSemaphore* signalSemaphore; PalFence* fence; @@ -1563,29 +1566,29 @@ typedef struct { /** * @struct PalSwapchainPresentInfo * @brief Present information of a swapchain. - * + * * Uninitialized fields may result in undefined behavior. - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { Uint32 imageIndex; /**< Image index to present. Must be 0 and less than max images.*/ - Uint64 waitValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ + Uint64 waitValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ PalSemaphore* waitSemaphore; } PalSwapchainPresentInfo; /** * @struct PalRenderingInfo - * @brief Present information of a swapchain. - * + * @brief Information about how rendering should be done in graphics pipeline. + * * Uninitialized fields may result in undefined behavior. - * + * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - Uint32 viewCount; + Uint32 viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ Uint32 layerCount; Uint32 colorAttachentCount; PalSampleCount multisampleCount; @@ -1596,8 +1599,18 @@ typedef struct { PalRect2D renderArea; } PalRenderingInfo; +/** + * @struct PalRenderingLayoutInfo + * @brief Information about a pre-existing PalRenderingInfo. + * This is used to reference the already existing PalRenderingInfo. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 viewCount; + Uint32 viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ Uint32 colorAttachentCount; PalSampleCount multisampleCount; PalFormat depthAttachmentFormat; @@ -1606,57 +1619,140 @@ typedef struct { PalFormat* colorAttachmentsFormat; } PalRenderingLayoutInfo; +/** + * @struct PalWorkGroupBuildData + * @brief Compute or Mesh(or Task) workgroup input data build helper. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { + /** Workcount can be specified in pixels, vertices etc. + * eg. an image of 800 x 600 will have a workcount of workCount[0] = 800, + * workCount[1] = 600, workCount[2] = 1.*/ Uint32 workCount[3]; - Uint32 workGroupSize[3]; - Uint32 workGroupCount[3]; + Uint32 workGroupSize[3]; /**< Threads per workgroup per axis of the adapter (GPU).*/ + Uint32 workGroupCount[3]; /**< Workgroups per axis of the adapter (GPU).*/ } PalWorkGroupBuildData; +/** + * @struct PalWorkGroupInfo + * @brief Information about compute or mesh(or task) dispatch data or a dispatch tile. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 workGroupBase[3]; - Uint32 workGroupCount[3]; + Uint32 workGroupBase[3]; /**< Offset per axis of a dispatch tile.*/ + Uint32 workGroupCount[3]; /**< Workgroup count per axis of a dispatch tile.*/ } PalWorkGroupInfo; +/** + * @struct PalDrawData + * @brief Draw data of a single draw call. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 vertexCount; - Uint32 instanceCount; - Uint32 firstVertex; - Uint32 firstInstance; + Uint32 vertexCount; /**< Number of vertices to draw.*/ + Uint32 instanceCount; /**< Number of instances to draw. Set to 1 if not using instanced draw.*/ + Uint32 firstVertex; /**< First vertex. Set to 0 for default behavior.*/ + Uint32 firstInstance; /**< First instance. Set to 0 for default behavior.*/ } PalDrawData; +/** + * @struct PalDrawData + * @brief Draw indexed data of a single draw call. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 indexCount; - Uint32 instanceCount; - Uint32 firstIndex; - Int32 vertexOffset; - Uint32 firstInstance; + Uint32 indexCount; /**< Number of indices to draw.*/ + Uint32 instanceCount; /**< Number of instances to draw. Set to 1 if not using instanced draw.*/ + Uint32 firstIndex; /**< First index. Set to 0 for default behavior.*/ + Int32 vertexOffset; /**< Vertex offset. Set to 0 for default behavior.*/ + Uint32 firstInstance; /**< First instance. Set to 0 for default behavior.*/ } PalDrawIndexedData; +/** + * @struct PalVertexAttribute + * @brief Vertex attribute. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - PalVertexType type; + PalVertexType type; /**< (eg. PAL_VERTEX_TYPE_FLOAT).*/ Uint32 location; } PalVertexAttribute; +/** + * @struct PalVertexLayout + * @brief Vertex layout. + * This defines the layout and the number of vertex attributes the layout uses. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - PalVertexLayoutType type; + PalVertexLayoutType type; /**< (eg. PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX).*/ Uint32 binding; Uint32 attributeCount; PalVertexAttribute* attributes; } PalVertexLayout; +/** + * @struct PalGraphicsDebugger + * @brief Graphics debugger. + * + * The debugger will not be initialized if PalGraphicsDebugger::callback is set and valid. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { void* userData; PalDebugCallback callback; } PalGraphicsDebugger; +/** + * @struct PalRasterizerState + * @brief Rasterizer state. This is used with a graphics pipeline. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { bool enableDepthClamp; bool enableDepthBias; - PalPolygonMode polygonMode; - PalCullMode cullMode; - PalFrontFace frontFace; + PalPolygonMode polygonMode; /**< (eg. PAL_POLYGON_MODE_FILL).*/ + PalCullMode cullMode; /**< (eg. PAL_CULL_MODE_BACK).*/ + PalFrontFace frontFace; /**< (eg. PAL_FRONT_FACE_CLOCKWISE).*/ } PalRasterizerState; +/** + * @struct PalMultisampleState + * @brief Multisample state. This is used with a graphics pipeline. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { bool enableSampleShading; bool enableAlphaToCoverage; @@ -1665,6 +1761,15 @@ typedef struct { float minSampleShading; } PalMultisampleState; +/** + * @struct PalStencilOpState + * @brief Stencil operation state. This is used with a graphics pipeline. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { PalStencilOp failOp; PalStencilOp passOp; @@ -1672,6 +1777,15 @@ typedef struct { PalCompareOp compareOp; } PalStencilOpState; +/** + * @struct PalDepthStencilState + * @brief Depth stencil state. This is used with a graphics pipeline. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { bool enableDepthTest; bool enableDepthWrite; @@ -1681,6 +1795,18 @@ typedef struct { PalStencilOpState backStencilOpState; } PalDepthStencilState; +/** + * @struct PalColorBlendAttachment + * @brief Color blend attachmeent. This is used with a graphics pipeline. + * + * Every rendering attachment (color, etc) must have a color blend attachment to + * describe how blending is applied to the attachment. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { bool enableBlend; PalColorMask colorWriteMask; @@ -1692,26 +1818,60 @@ typedef struct { PalBlendOp alphaBlendOp; } PalColorBlendAttachment; +/** + * @struct PalFragmentShadingRateState + * @brief Fragment shading rate state. This is used with a graphics pipeline. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - PalFragmentShadingRate rate; + PalFragmentShadingRate rate; /**< (eg. PAL_FRAGMENT_SHADING_RATE_2X1).*/ PalFragmentShadingRateCombinerOp combinerOps[2]; } PalFragmentShadingRateState; +/** + * @struct PalAccelerationStructureInstance + * @brief Acceleration structure instance base data. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 instanceId; + Uint32 instanceId; /**< User defined id.*/ Uint32 mask; - PalAccelerationStructure* blas; - float transform[12]; // row major (3x4) + PalAccelerationStructure* blas; /**< BLAS to use.*/ + float transform[12]; /**< row major (3x4).*/ } PalAccelerationStructureInstance; +/** + * @struct PalAccelerationStructureBuildSize + * @brief Acceleration structure build size. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 accelerationStructureSize; - Uint32 scratchBufferSize; + Uint32 accelerationStructureSize; /**< Required acceleration structure size.*/ + Uint32 scratchBufferSize; /**< Required scratch buffer size.*/ } PalAccelerationStructureBuildSize; +/** + * @struct PalGeometryDataTriangle + * @brief Acceleration structure triangle geometry data. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - PalVertexType vertexType; - PalIndexType indexType; + PalVertexType vertexType; /**< (eg. PAL_VERTEX_TYPE_FLOAT3).*/ + PalIndexType indexType; /**< (eg. PAL_INDEX_TYPE_UINT32). If indexBufferAddress is not 0.*/ Uint32 vertexStride; Uint32 indexCount; Uint32 vertexCount; @@ -1719,136 +1879,317 @@ typedef struct { PalDeviceAddress indexBufferAddress; } PalGeometryDataTriangle; +/** + * @struct PalGeometryDataAABBS + * @brief Acceleration structure AABBS geometry data. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 stride; PalDeviceAddress bufferAddress; } PalGeometryDataAABBS; +/** + * @struct PalGeometryDataInstance + * @brief Acceleration structure instance geometry data. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { PalDeviceAddress bufferAddress; } PalGeometryDataInstance; +/** + * @struct PalGeometryDataInstance + * @brief Acceleration structure geometry. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 primitiveCount; - PalGeometryType type; - void* data; // based on type + PalGeometryType type; /**< (eg. PAL_GEOMETRY_TYPE_TRIANGLE).*/ + void* data; /**< Pointer to geometry data. This will be casted based on the geometry type.*/ } PalGeometry; +/** + * @struct PalAccelerationStructureBuildInfo + * @brief Build information of an acceleration structure. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - PalAccelerationStructureType type; + PalAccelerationStructureType type; /**< (eg. PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL).*/ Uint32 geometryCount; PalAccelerationStructure* dst; PalDeviceAddress scratchBufferAddress; PalGeometry* geometries; } PalAccelerationStructureBuildInfo; +/** + * @struct PalDescriptorSetLayoutBinding + * @brief Single descriptor set layout binding. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 binding; Uint32 descriptorCount; Uint32 shaderStageCount; - PalShaderStage* shaderStages; - PalDescriptorType descriptorType; + PalShaderStage* shaderStages; /**< Array of shader stages that can access the descriptor.*/ + PalDescriptorType descriptorType; /**< (eg. PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER).*/ } PalDescriptorSetLayoutBinding; +/** + * @struct PalDescriptorPoolBindingSize + * @brief Descriptor pool binding size. + * Describes the sizes of each descriptor type in the descriptor pool. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 bindingCount; - PalDescriptorType descriptorType; + Uint32 bindingCount; /**< Number of descriptors of `descriptorType` that will be used.*/ + PalDescriptorType descriptorType; /**< (eg. PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER).*/ } PalDescriptorPoolBindingSize; +/** + * @struct PalDescriptorBufferInfo + * @brief Information about a buffer descriptor. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 size; Uint64 offset; PalBuffer* buffer; } PalDescriptorBufferInfo; +/** + * @struct PalDescriptorImageViewInfo + * @brief Information about an image view descriptor. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { PalSampler* sampler; PalImageView* imageView; } PalDescriptorImageViewInfo; +/** + * @struct PalDescriptorTLASInfo + * @brief Information about a TLAS descriptor. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { PalAccelerationStructure* tlas; } PalDescriptorTLASInfo; +/** + * @struct PalDescriptorSetWriteInfo + * @brief Write information of a descriptor set. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 binding; - Uint32 arrayElement; - Uint32 descriptorCount; + Uint32 arrayElement; /**< 0 If not using PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING.*/ + Uint32 descriptorCount; /**< 1 If not using PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING.*/ PalDescriptorType descriptorType; PalDescriptorSet* descriptorSet; - PalDescriptorBufferInfo* bufferInfo; - PalDescriptorImageViewInfo* imageViewInfo; - PalDescriptorTLASInfo* tlasInfo; + PalDescriptorBufferInfo* bufferInfo; /**< If PAL_DESCRIPTOR_TYPE* uniform or storage buffer.*/ + PalDescriptorImageViewInfo* imageViewInfo; /**< If PAL_DESCRIPTOR_TYPE* sampler or image.*/ + PalDescriptorTLASInfo* tlasInfo; /**< If PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE.*/ } PalDescriptorSetWriteInfo; +/** + * @struct PalPushConstantRange + * @brief Push constant range. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint64 offset; Uint64 size; Uint32 shaderStageCount; - PalShaderStage* shaderStages; + PalShaderStage* shaderStages; /**< Array of shader stages that can access the push constant.*/ } PalPushConstantRange; +/** + * @struct PalImageCreateInfo + * @brief Creation parameters for an image. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 width; - Uint32 height; + Uint32 width; /**< Width of the image in pixels.*/ + Uint32 height; /**< Height of the image in pixels.*/ Uint32 depthOrArraySize; Uint32 mipLevelCount; PalSampleCount sampleCount; - PalImageType type; - PalFormat format; - PalImageUsages usages; + PalImageType type; /**< (eg. PAL_IMAGE_TYPE_2D).*/ + PalFormat format; /**< Format of the image.*/ + PalImageUsages usages; /**< (eg. PAL_IMAGE_USAGE_COLOR_ATTACHEMENT).*/ } PalImageCreateInfo; +/** + * @struct PalImageCreateInfo + * @brief Creation parameters for an image view. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 startMipLevel; Uint32 mipLevelCount; Uint32 startArrayLayer; Uint32 layerArrayCount; - PalImageViewType type; - PalImageViewUsages usages; + PalImageViewType type; /**< (eg. PAL_IMAGE_VIEW_TYPE_2D).*/ + PalImageViewUsages usages; /**< (eg. PAL_IMAGE_VIEW_USAGE_COLOR).*/ } PalImageViewCreateInfo; +/** + * @struct PalSwapchainCreateInfo + * @brief Creation parameters for a swapchain. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { bool clipped; - Uint32 width; - Uint32 height; - Uint32 imageCount; - Uint32 imageArrayLayerCount; - PalPresentMode presentMode; - PalCompositeAplha compositeAlpha; - PalSwapchainFormat format; + Uint32 width; /**< Width of the swapchain in pixels.*/ + Uint32 height; /**< Height of the swapchain in pixels.*/ + Uint32 imageCount; /**< Number of swapchain images.*/ + Uint32 imageArrayLayerCount; /**< Set to 1 for default.*/ + PalPresentMode presentMode; /**< (eg. PAL_PRESENT_MODE_FIFO).*/ + PalCompositeAplha compositeAlpha; /**< (eg. PAL_COMPOSITE_ALPHA_OPAQUE).*/ + PalSwapchainFormat format; /**< (eg. PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB).*/ } PalSwapchainCreateInfo; +/** + * @struct PalShaderCreateInfo + * @brief Creation parameters for a shader. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - Uint32 patchControlPoints; + Uint32 patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ PalShaderStage stage; void* bytecode; Uint64 bytecodeSize; } PalShaderCreateInfo; +/** + * @struct PalBufferCreateInfo + * @brief Creation parameters for a buffer. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - PalBufferUsages usages; + PalBufferUsages usages; /**< (eg. PAL_BUFFER_USAGE_STORAGE).*/ Uint64 size; } PalBufferCreateInfo; +/** + * @struct PalAccelerationStructureCreateInfo + * @brief Creation parameters for an acceleration structure. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - PalAccelerationStructureType type; + PalAccelerationStructureType type; /**< (eg. PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL).*/ PalBuffer* buffer; Uint64 offset; Uint64 size; } PalAccelerationStructureCreateInfo; +/** + * @struct PalDescriptorSetLayoutCreateInfo + * @brief Creation parameters for a descriptor set layout. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 bindingCount; PalDescriptorSetLayoutBinding* bindings; } PalDescriptorSetLayoutCreateInfo; +/** + * @struct PalDescriptorPoolCreateInfo + * @brief Creation parameters for a descriptor pool. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 maxDescriptorSets; Uint32 maxDescriptorBindingSizes; PalDescriptorPoolBindingSize* bindingSizes; } PalDescriptorPoolCreateInfo; +/** + * @struct PalPipelineLayoutCreateInfo + * @brief Creation parameters for a pipeline layout. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 descriptorSetLayoutCount; Uint32 pushConstantRangeCount; @@ -1856,6 +2197,15 @@ typedef struct { PalPushConstantRange* pushConstantRanges; } PalPipelineLayoutCreateInfo; +/** + * @struct PalGraphicsPipelineCreateInfo + * @brief Creation parameters for a graphics pipeline. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 vertexLayoutCount; Uint32 colorBlendAttachmentCount; @@ -1864,60 +2214,136 @@ typedef struct { PalPipelineLayout* pipelineLayout; PalShader** shaders; PalVertexLayout* vertexLayouts; - PalColorBlendAttachment* colorBlendAttachments; - PalRasterizerState* rasterizerState; - PalMultisampleState* multisampleState; - PalDepthStencilState* depthStencilState; - PalFragmentShadingRateState* fragmentShadingRateState; + PalColorBlendAttachment* colorBlendAttachments; /**< Must not be nullptr.*/ + PalRasterizerState* rasterizerState; /**< Set to nullptr for default.*/ + PalMultisampleState* multisampleState; /**< Set to nullptr for default.*/ + PalDepthStencilState* depthStencilState; /**< Set to nullptr for default.*/ + PalFragmentShadingRateState* fragmentShadingRateState; /**< Set to nullptr for default.*/ PalRenderingLayoutInfo* renderingLayout; } PalGraphicsPipelineCreateInfo; +/** + * @struct PalComputePipelineCreateInfo + * @brief Creation parameters for a compute pipeline. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { PalPipelineLayout* pipelineLayout; PalShader* computeShader; } PalComputePipelineCreateInfo; +/** + * @struct PalRayTracingShaderGroupCreateInfo + * @brief Creation parameters for a ray tracing pipeline shader group. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { - PalRayTracingShaderGroupType type; - Uint32 anyHitShaderIndex; - Uint32 closestHitShaderIndex; - Uint32 generalShaderIndex; - Uint32 intersectionShaderIndex; + PalRayTracingShaderGroupType type; /**< (eg. PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL).*/ + Uint32 anyHitShaderIndex; /**< Index of any hit shader from shader array.*/ + Uint32 closestHitShaderIndex; /**< Index of closest hit shader from shader array.*/ + Uint32 generalShaderIndex; /**< Index of general hit shader from shader array.*/ + Uint32 intersectionShaderIndex; /**< Index of intersection hit shader from shader array.*/ } PalRayTracingShaderGroupCreateInfo; +/** + * @struct PalRayTracingPipelineCreateInfo + * @brief Creation parameters for a ray tracing pipeline. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { Uint32 shaderCount; Uint32 shaderGroupCount; Uint32 maxRecursionDepth; PalPipelineLayout* pipelineLayout; - PalRayTracingShaderGroupCreateInfo* shaderGroups; - PalShader** shaders; + PalRayTracingShaderGroupCreateInfo* shaderGroups; /**< Array of shader group create info.*/ + PalShader** shaders; /**< Array of shader stage. This is used by `shaderGroups`.*/ } PalRayTracingPipelineCreateInfo; +/** + * @struct PalGraphicsBackend + * @brief Dispatch table for PAL graphics system backends. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ typedef struct { + /** + * Backend implementation of ::palEnumerateAdapters. + * + * This function must obey the rules and semantics documented in palEnumerateAdapters(). + */ PalResult PAL_CALL (*enumerateAdapters)( Int32* count, PalAdapter** outAdapters); + /** + * Backend implementation of ::palGetAdapterInfo. + * + * This function must obey the rules and semantics documented in palGetAdapterInfo(). + */ PalResult PAL_CALL (*getAdapterInfo)( PalAdapter* adapter, PalAdapterInfo* info); + /** + * Backend implementation of ::palGetAdapterCapabilities. + * + * This function must obey the rules and semantics documented in palGetAdapterCapabilities(). + */ PalResult PAL_CALL (*getAdapterCapabilities)( PalAdapter* adapter, PalAdapterCapabilities* caps); + /** + * Backend implementation of ::palGetAdapterFeatures. + * + * This function must obey the rules and semantics documented in palGetAdapterFeatures(). + */ PalAdapterFeatures PAL_CALL (*getAdapterFeatures)(PalAdapter* adapter); + /** + * Backend implementation of ::palCreateDevice. + * + * This function must obey the rules and semantics documented in palCreateDevice(). + */ PalResult PAL_CALL (*createDevice)( PalAdapter* adapter, PalAdapterFeatures features, PalDevice** outDevice); + /** + * Backend implementation of ::palDestroyDevice. + * + * This function must obey the rules and semantics documented in palDestroyDevice(). + */ void PAL_CALL (*destroyDevice)(PalDevice* device); + /** + * Backend implementation of ::palWaitDevice. + * + * This function must obey the rules and semantics documented in palWaitDevice(). + */ PalResult PAL_CALL (*waitDevice)(PalDevice* device); + /** + * Backend implementation of ::palAllocateMemory. + * + * This function must obey the rules and semantics documented in palAllocateMemory(). + */ PalResult PAL_CALL (*allocateMemory)( PalDevice* device, PalMemoryType type, @@ -1925,10 +2351,20 @@ typedef struct { Uint64 size, PalMemory** outMemory); + /** + * Backend implementation of ::palFreeMemory. + * + * This function must obey the rules and semantics documented in palFreeMemory(). + */ void PAL_CALL (*freeMemory)( PalDevice* device, PalMemory* memory); + /** + * Backend implementation of ::palMapMemory. + * + * This function must obey the rules and semantics documented in palMapMemory(). + */ PalResult PAL_CALL (*mapMemory)( PalDevice* device, PalMemory* memory, @@ -1936,41 +2372,96 @@ typedef struct { Uint64 size, void** outPtr); + /** + * Backend implementation of ::palUnmapMemory. + * + * This function must obey the rules and semantics documented in palUnmapMemory(). + */ void PAL_CALL (*unmapMemory)( PalDevice* device, PalMemory* memory); + /** + * Backend implementation of ::palQueryDepthStencilCapabilities. + * + * This function must obey the rules and semantics documented in + * palQueryDepthStencilCapabilities(). + */ PalResult PAL_CALL (*queryDepthStencilCapabilities)( PalDevice* device, PalDepthStencilCapabilities* caps); + /** + * Backend implementation of ::palQueryFragmentShadingRateCapabilities. + * + * This function must obey the rules and semantics documented in + * palQueryFragmentShadingRateCapabilities(). + */ PalResult PAL_CALL (*queryFragmentShadingRateCapabilities)( PalDevice* device, PalFragmentShadingRateCapabilities* caps); + /** + * Backend implementation of ::palQueryMeshShaderCapabilities. + * + * This function must obey the rules and semantics documented in + * palQueryMeshShaderCapabilities(). + */ PalResult PAL_CALL (*queryMeshShaderCapabilities)( PalDevice* device, PalMeshShaderCapabilities* caps); + /** + * Backend implementation of ::palQueryRayTracingCapabilities. + * + * This function must obey the rules and semantics documented in + * palQueryRayTracingCapabilities(). + */ PalResult PAL_CALL (*queryRayTracingCapabilities)( PalDevice* device, PalRayTracingCapabilities* caps); + /** + * Backend implementation of ::palQueryDescriptorIndexingCapabilities. + * + * This function must obey the rules and semantics documented in + * palQueryDescriptorIndexingCapabilities(). + */ PalResult PAL_CALL (*queryDescriptorIndexingCapabilities)( PalDevice* device, PalDescriptorIndexingCapabilities* caps); + /** + * Backend implementation of ::palCreateQueue. + * + * This function must obey the rules and semantics documented in palCreateQueue(). + */ PalResult PAL_CALL (*createQueue)( PalDevice* device, PalQueueType type, PalQueue** outQueue); + /** + * Backend implementation of ::palDestroyQueue. + * + * This function must obey the rules and semantics documented in palDestroyQueue(). + */ void PAL_CALL (*destroyQueue)(PalQueue* queue); + /** + * Backend implementation of ::palCanQueuePresent. + * + * This function must obey the rules and semantics documented in palCanQueuePresent(). + */ bool PAL_CALL (*canQueuePresent)( PalQueue* queue, PalGraphicsWindow* window); + /** + * Backend implementation of ::palWaitQueue. + * + * This function must obey the rules and semantics documented in palWaitQueue(). + */ PalResult PAL_CALL (*waitQueue)(PalQueue* queue); PalResult PAL_CALL (*enumerateFormats)( From 893d6c942c2936f726c6f6322459d2ebaa14831d Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 2 Mar 2026 11:01:03 +0000 Subject: [PATCH 097/372] change thread local to per thread in API docs to remove misunderstanding with thread local keyword --- include/pal/pal_core.h | 2 +- include/pal/pal_event.h | 4 +- include/pal/pal_graphics.h | 656 ++++++++++++++++++++++++++++++++++++ include/pal/pal_opengl.h | 2 +- include/pal/pal_system.h | 4 +- include/pal/pal_thread.h | 12 +- src/graphics/pal_graphics.c | 2 +- 7 files changed, 669 insertions(+), 13 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 75c1e257..db8242ce 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -396,7 +396,7 @@ PAL_API void PAL_CALL palFree( /** * Log a formatted message. * - * @param logger Logger instance. Must not be NULL. + * @param logger Logger instance. Set to nullptr to use default logger. * @param fmt printf-style format string. * @param ... Arguments for the format string. * diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index dc57caae..348b0fa1 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -450,7 +450,7 @@ typedef struct { * failure. Call palFormatResult() for more information. * * Thread safety: This function is thread safe if the provided allocator is - * thread safe and `outEventDriver` is thread local. The default allocator is + * thread safe and `outEventDriver` is per thread. The default allocator is * thread safe. * * @since 1.0 @@ -470,7 +470,7 @@ PAL_API PalResult PAL_CALL palCreateEventDriver( * @param[in] eventDriver Pointer to the event driver to destroy. * * Thread safety: This function is thread safe if the allocator used to create - * the event driver is thread safe and `eventDriver` is thread local. + * the event driver is thread safe and `eventDriver` is per thread. * * @since 1.0 * @ingroup pal_event diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 8af95801..87bf0052 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2464,56 +2464,121 @@ typedef struct { */ PalResult PAL_CALL (*waitQueue)(PalQueue* queue); + /** + * Backend implementation of ::palEnumerateFormats. + * + * This function must obey the rules and semantics documented in palEnumerateFormats(). + */ PalResult PAL_CALL (*enumerateFormats)( PalAdapter* adapter, Int32* count, PalFormatInfo* outFormats); + /** + * Backend implementation of ::palIsFormatSupported. + * + * This function must obey the rules and semantics documented in palIsFormatSupported(). + */ bool PAL_CALL (*isFormatSupported)( PalAdapter* adapter, PalFormat format); + /** + * Backend implementation of ::palQueryFormatImageUsages. + * + * This function must obey the rules and semantics documented in palQueryFormatImageUsages(). + */ PalImageUsages PAL_CALL (*queryFormatImageUsages)( PalAdapter* adapter, PalFormat format); + /** + * Backend implementation of ::palQueryFormatImageViewUsages. + * + * This function must obey the rules and semantics documented in palQueryFormatImageViewUsages(). + */ PalImageViewUsages PAL_CALL (*queryFormatImageViewUsages)( PalAdapter* adapter, PalFormat format); + /** + * Backend implementation of ::palCreateImage. + * + * This function must obey the rules and semantics documented in palCreateImage(). + */ PalResult PAL_CALL (*createImage)( PalDevice* device, const PalImageCreateInfo* info, PalImage** outImage); + /** + * Backend implementation of ::palDestroyImage. + * + * This function must obey the rules and semantics documented in palDestroyImage(). + */ void PAL_CALL (*destroyImage)(PalImage* image); + /** + * Backend implementation of ::palGetImageInfo. + * + * This function must obey the rules and semantics documented in palGetImageInfo(). + */ PalResult PAL_CALL (*getImageInfo)( PalImage* image, PalImageInfo* info); + /** + * Backend implementation of ::palGetImageMemoryRequirements. + * + * This function must obey the rules and semantics documented in palGetImageMemoryRequirements(). + */ PalResult PAL_CALL (*getImageMemoryRequirements)( PalImage* image, PalMemoryRequirements* requirements); + /** + * Backend implementation of ::palBindImageMemory. + * + * This function must obey the rules and semantics documented in palBindImageMemory(). + */ PalResult PAL_CALL (*bindImageMemory)( PalImage* image, PalMemory* memory, Uint64 offset); + /** + * Backend implementation of ::palCreateImageView. + * + * This function must obey the rules and semantics documented in palCreateImageView(). + */ PalResult PAL_CALL (*createImageView)( PalDevice* device, PalImage* image, const PalImageViewCreateInfo* info, PalImageView** outImageView); + /** + * Backend implementation of ::palDestroyImageView. + * + * This function must obey the rules and semantics documented in palDestroyImageView(). + */ void PAL_CALL (*destroyImageView)(PalImageView* imageView); + /** + * Backend implementation of ::palQuerySwapchainCapabilities. + * + * This function must obey the rules and semantics documented in palQuerySwapchainCapabilities(). + */ PalResult PAL_CALL (*querySwapchainCapabilities)( PalDevice* device, PalGraphicsWindow* window, PalSwapchainCapabilities* caps); + /** + * Backend implementation of ::palCreateSwapchain. + * + * This function must obey the rules and semantics documented in palCreateSwapchain(). + */ PalResult PAL_CALL (*createSwapchain)( PalDevice* device, PalQueue* queue, @@ -2521,103 +2586,243 @@ typedef struct { const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain); + /** + * Backend implementation of ::palDestroySwapchain. + * + * This function must obey the rules and semantics documented in palDestroySwapchain(). + */ void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); + /** + * Backend implementation of ::palGetSwapchainImage. + * + * This function must obey the rules and semantics documented in palGetSwapchainImage(). + */ PalImage* PAL_CALL (*getSwapchainImage)( PalSwapchain* swapchain, Int32 index); + /** + * Backend implementation of ::palGetNextSwapchainImage. + * + * This function must obey the rules and semantics documented in palGetNextSwapchainImage(). + */ PalResult PAL_CALL (*getNextSwapchainImage)( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, Uint32* outIndex); + /** + * Backend implementation of ::palPresentSwapchain. + * + * This function must obey the rules and semantics documented in palPresentSwapchain(). + */ PalResult PAL_CALL (*presentSwapchain)( PalSwapchain* swapchain, PalSwapchainPresentInfo* info); + /** + * Backend implementation of ::palCreateShader. + * + * This function must obey the rules and semantics documented in palCreateShader(). + */ PalResult PAL_CALL (*createShader)( PalDevice* device, const PalShaderCreateInfo* info, PalShader** outShader); + /** + * Backend implementation of ::palDestroyShader. + * + * This function must obey the rules and semantics documented in palDestroyShader(). + */ void PAL_CALL (*destroyShader)(PalShader* shader); + /** + * Backend implementation of ::palCreateFence. + * + * This function must obey the rules and semantics documented in palCreateFence(). + */ PalResult PAL_CALL (*createFence)( PalDevice* device, bool signaled, PalFence** outFence); + /** + * Backend implementation of ::palDestroyFence. + * + * This function must obey the rules and semantics documented in palDestroyFence(). + */ void PAL_CALL (*destroyFence)(PalFence* fence); + /** + * Backend implementation of ::palWaitFenceTimeout. + * + * This function must obey the rules and semantics documented in palWaitFenceTimeout(). + */ PalResult PAL_CALL (*waitFenceTimeout)( PalFence* fence, Uint64 timeout); + /** + * Backend implementation of ::palResetFence. + * + * This function must obey the rules and semantics documented in palResetFence(). + */ PalResult PAL_CALL (*resetFence)(PalFence* fence); + /** + * Backend implementation of ::palIsFenceSignaled. + * + * This function must obey the rules and semantics documented in palIsFenceSignaled(). + */ bool PAL_CALL (*isFenceSignaled)(PalFence* fence); + /** + * Backend implementation of ::palCreateSemaphore. + * + * This function must obey the rules and semantics documented in palCreateSemaphore(). + */ PalResult PAL_CALL (*createSemaphore)( PalDevice* device, PalSemaphore** outSemaphore); + /** + * Backend implementation of ::palDestroySemaphore. + * + * This function must obey the rules and semantics documented in palDestroySemaphore(). + */ void PAL_CALL (*destroySemaphore)(PalSemaphore* semaphore); + /** + * Backend implementation of ::palWaitSemaphore. + * + * This function must obey the rules and semantics documented in palWaitSemaphore(). + */ PalResult PAL_CALL (*waitSemaphore)( PalSemaphore* semaphore, PalQueue* queue, Uint64 value, Uint64 timeout); + /** + * Backend implementation of ::palSignalSemaphore. + * + * This function must obey the rules and semantics documented in palSignalSemaphore(). + */ PalResult PAL_CALL (*signalSemaphore)( PalSemaphore* semaphore, PalQueue* queue, Uint64 value); + /** + * Backend implementation of ::palGetSemaphoreValue. + * + * This function must obey the rules and semantics documented in palGetSemaphoreValue(). + */ PalResult PAL_CALL (*getSemaphoreValue)( PalSemaphore* semaphore, Uint64* value); + /** + * Backend implementation of ::palCreateCommandPool. + * + * This function must obey the rules and semantics documented in palCreateCommandPool(). + */ PalResult PAL_CALL (*createCommandPool)( PalDevice* device, PalQueue* queue, PalCommandPool** outPool); + /** + * Backend implementation of ::palDestroyCommandPool. + * + * This function must obey the rules and semantics documented in palDestroyCommandPool(). + */ void PAL_CALL (*destroyCommandPool)(PalCommandPool* pool); + /** + * Backend implementation of ::palResetCommandPool. + * + * This function must obey the rules and semantics documented in palResetCommandPool(). + */ PalResult PAL_CALL (*resetCommandPool)(PalCommandPool* pool); + /** + * Backend implementation of ::palAllocateCommandBuffer. + * + * This function must obey the rules and semantics documented in palAllocateCommandBuffer(). + */ PalResult PAL_CALL (*allocateCommandBuffer)( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, PalCommandBuffer** outCmdBuffer); + /** + * Backend implementation of ::palFreeCommandBuffer. + * + * This function must obey the rules and semantics documented in palFreeCommandBuffer(). + */ void PAL_CALL (*freeCommandBuffer)(PalCommandBuffer* cmdBuffer); + /** + * Backend implementation of ::palResetCommandBuffer. + * + * This function must obey the rules and semantics documented in palResetCommandBuffer(). + */ PalResult PAL_CALL (*resetCommandBuffer)(PalCommandBuffer* cmdBuffer); + /** + * Backend implementation of ::palCmdBegin. + * + * This function must obey the rules and semantics documented in palCmdBegin(). + */ PalResult PAL_CALL (*cmdBegin)( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); + /** + * Backend implementation of ::palCmdEnd. + * + * This function must obey the rules and semantics documented in palCmdEnd(). + */ PalResult PAL_CALL (*cmdEnd)(PalCommandBuffer* cmdBuffer); + /** + * Backend implementation of ::palCmdExecuteCommandBuffer. + * + * This function must obey the rules and semantics documented in palCmdExecuteCommandBuffer(). + */ PalResult PAL_CALL (*cmdExecuteCommandBuffer)( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); + /** + * Backend implementation of ::palCmdSetFragmentShadingRate. + * + * This function must obey the rules and semantics documented in palCmdSetFragmentShadingRate(). + */ PalResult PAL_CALL (*cmdSetFragmentShadingRate)( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state); + /** + * Backend implementation of ::palCmdDrawMeshTasks. + * + * This function must obey the rules and semantics documented in palCmdDrawMeshTasks(). + */ PalResult PAL_CALL (*cmdDrawMeshTasks)( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, Uint32 groupCountZ); + /** + * Backend implementation of ::palCmdDrawMeshTasksIndirect. + * + * This function must obey the rules and semantics documented in palCmdDrawMeshTasksIndirect(). + */ PalResult PAL_CALL (*cmdDrawMeshTasksIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, @@ -2625,6 +2830,11 @@ typedef struct { Uint32 drawCount, Uint32 stride); + /** + * Backend implementation of ::palCmdDrawMeshTasksIndirectCount. + * + * This function must obey the rules and semantics documented in palCmdDrawMeshTasksIndirectCount(). + */ PalResult PAL_CALL (*cmdDrawMeshTasksIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, @@ -2634,16 +2844,36 @@ typedef struct { Uint32 maxDrawCount, Uint32 stride); + /** + * Backend implementation of ::palCmdBuildAccelerationStructure. + * + * This function must obey the rules and semantics documented in palCmdBuildAccelerationStructure(). + */ PalResult PAL_CALL (*cmdBuildAccelerationStructure)( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); + /** + * Backend implementation of ::palCmdBeginRendering. + * + * This function must obey the rules and semantics documented in palCmdBeginRendering(). + */ PalResult PAL_CALL (*cmdBeginRendering)( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info); + /** + * Backend implementation of ::palCmdEndRendering. + * + * This function must obey the rules and semantics documented in palCmdEndRendering(). + */ PalResult PAL_CALL (*cmdEndRendering)(PalCommandBuffer* cmdBuffer); + /** + * Backend implementation of ::palCmdCopyBuffer. + * + * This function must obey the rules and semantics documented in palCmdCopyBuffer(). + */ PalResult PAL_CALL (*cmdCopyBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* dst, @@ -2652,20 +2882,40 @@ typedef struct { Uint64 srcOffset, Uint32 size); + /** + * Backend implementation of ::palCmdBindPipeline. + * + * This function must obey the rules and semantics documented in palCmdBindPipeline(). + */ PalResult PAL_CALL (*cmdBindPipeline)( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline); + /** + * Backend implementation of ::palCmdSetViewport. + * + * This function must obey the rules and semantics documented in palCmdSetViewport(). + */ PalResult PAL_CALL (*cmdSetViewport)( PalCommandBuffer* cmdBuffer, Uint32 count, PalViewport* viewports); + /** + * Backend implementation of ::palCmdSetScissors. + * + * This function must obey the rules and semantics documented in palCmdSetScissors(). + */ PalResult PAL_CALL (*cmdSetScissors)( PalCommandBuffer* cmdBuffer, Uint32 count, PalRect2D* scissors); + /** + * Backend implementation of ::palCmdBindVertexBuffers. + * + * This function must obey the rules and semantics documented in palCmdBindVertexBuffers(). + */ PalResult PAL_CALL (*cmdBindVertexBuffers)( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, @@ -2673,22 +2923,42 @@ typedef struct { PalBuffer** buffers, Uint64* offsets); + /** + * Backend implementation of ::palCmdBindIndexBuffer. + * + * This function must obey the rules and semantics documented in palCmdBindIndexBuffer(). + */ PalResult PAL_CALL (*cmdBindIndexBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, PalIndexType type); + /** + * Backend implementation of ::palCmdDraw. + * + * This function must obey the rules and semantics documented in palCmdDraw(). + */ PalResult PAL_CALL (*cmdDraw)( PalCommandBuffer* cmdBuffer, PalDrawData* data); + /** + * Backend implementation of ::palCmdDrawIndirect. + * + * This function must obey the rules and semantics documented in palCmdDrawIndirect(). + */ PalResult PAL_CALL (*cmdDrawIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 count); + /** + * Backend implementation of ::palCmdDrawIndirectCount. + * + * This function must obey the rules and semantics documented in palCmdDrawIndirectCount(). + */ PalResult PAL_CALL (*cmdDrawIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, @@ -2697,16 +2967,31 @@ typedef struct { Uint64 countBufferOffset, Uint32 count); + /** + * Backend implementation of ::palCmdDrawIndexed. + * + * This function must obey the rules and semantics documented in palCmdDrawIndexed(). + */ PalResult PAL_CALL (*cmdDrawIndexed)( PalCommandBuffer* cmdBuffer, PalDrawIndexedData* data); + /** + * Backend implementation of ::palCmdDrawIndexedIndirect. + * + * This function must obey the rules and semantics documented in palCmdDrawIndexedIndirect(). + */ PalResult PAL_CALL (*cmdDrawIndexedIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 count); + /** + * Backend implementation of ::palCmdDrawIndexedIndirectCount. + * + * This function must obey the rules and semantics documented in palCmdDrawIndexedIndirectCount(). + */ PalResult PAL_CALL (*cmdDrawIndexedIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, @@ -2715,29 +3000,54 @@ typedef struct { Uint64 countBufferOffset, Uint32 count); + /** + * Backend implementation of ::palCmdMemoryBarrier. + * + * This function must obey the rules and semantics documented in palCmdMemoryBarrier(). + */ PalResult PAL_CALL (*cmdMemoryBarrier)( PalCommandBuffer* cmdBuffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); + /** + * Backend implementation of ::palCmdImageViewBarrier. + * + * This function must obey the rules and semantics documented in palCmdImageViewBarrier(). + */ PalResult PAL_CALL (*cmdImageViewBarrier)( PalCommandBuffer* cmdBuffer, PalImageView* imageView, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); + /** + * Backend implementation of ::palCmdBufferBarrier. + * + * This function must obey the rules and semantics documented in palCmdBufferBarrier(). + */ PalResult PAL_CALL (*cmdBufferBarrier)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); + /** + * Backend implementation of ::palCmdDispatch. + * + * This function must obey the rules and semantics documented in palCmdDispatch(). + */ PalResult PAL_CALL (*cmdDispatch)( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, Uint32 groupCountZ); + /** + * Backend implementation of ::palCmdDispatchBase. + * + * This function must obey the rules and semantics documented in palCmdDispatchBase(). + */ PalResult PAL_CALL (*cmdDispatchBase)( PalCommandBuffer* cmdBuffer, Uint32 baseGroupX, @@ -2747,21 +3057,41 @@ typedef struct { Uint32 groupCountY, Uint32 groupCountZ); + /** + * Backend implementation of ::palCmdDispatchIndirect. + * + * This function must obey the rules and semantics documented in palCmdDispatchIndirect(). + */ PalResult PAL_CALL (*cmdDispatchIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset); + /** + * Backend implementation of ::palCmdTraceRays. + * + * This function must obey the rules and semantics documented in palCmdTraceRays(). + */ PalResult PAL_CALL (*cmdTraceRays)( PalCommandBuffer* cmdBuffer, Uint32 width, Uint32 height, Uint32 depth); + /** + * Backend implementation of ::palCmdTraceRaysIndirect. + * + * This function must obey the rules and semantics documented in palCmdTraceRaysIndirect(). + */ PalResult PAL_CALL (*cmdTraceRaysIndirect)( PalCommandBuffer* cmdBuffer, PalDeviceAddress bufferAddress); + /** + * Backend implementation of ::palCmdBindDescriptorSet. + * + * This function must obey the rules and semantics documented in palCmdBindDescriptorSet(). + */ PalResult PAL_CALL (*cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, @@ -2769,6 +3099,11 @@ typedef struct { Uint32 setIndex, PalDescriptorSet* set); + /** + * Backend implementation of ::palCmdPushConstants. + * + * This function must obey the rules and semantics documented in palCmdPushConstants(). + */ PalResult PAL_CALL (*cmdPushConstants)( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, @@ -2778,132 +3113,453 @@ typedef struct { Uint32 size, const void* value); + /** + * Backend implementation of ::palSubmitCommandBuffer. + * + * This function must obey the rules and semantics documented in palSubmitCommandBuffer(). + */ PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, PalCommandBufferSubmitInfo* info); + /** + * Backend implementation of ::palCreateAccelerationstructure. + * + * This function must obey the rules and semantics documented in palCreateAccelerationstructure(). + */ PalResult PAL_CALL (*createAccelerationstructure)( PalDevice* device, const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs); + /** + * Backend implementation of ::palDestroyAccelerationstructure. + * + * This function must obey the rules and semantics documented in palDestroyAccelerationstructure(). + */ void PAL_CALL (*destroyAccelerationstructure)(PalAccelerationStructure* as); + /** + * Backend implementation of ::palGetAccelerationStructureBuildSize. + * + * This function must obey the rules and semantics documented in palGetAccelerationStructureBuildSize(). + */ PalResult PAL_CALL (*getAccelerationStructureBuildSize)( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); + /** + * Backend implementation of ::palCreateBuffer. + * + * This function must obey the rules and semantics documented in palCreateBuffer(). + */ PalResult PAL_CALL (*createBuffer)( PalDevice* device, const PalBufferCreateInfo* info, PalBuffer** outBuffer); + /** + * Backend implementation of ::palDestroyBuffer. + * + * This function must obey the rules and semantics documented in palDestroyBuffer(). + */ void PAL_CALL (*destroyBuffer)(PalBuffer* buffer); + /** + * Backend implementation of ::palGetBufferMemoryRequirements. + * + * This function must obey the rules and semantics documented in palGetBufferMemoryRequirements(). + */ PalResult PAL_CALL (*getBufferMemoryRequirements)( PalBuffer* buffer, PalMemoryRequirements* requirements); + /** + * Backend implementation of ::palComputeInstanceBufferRequirements. + * + * This function must obey the rules and semantics documented in palComputeInstanceBufferRequirements(). + */ PalResult PAL_CALL (*computeInstanceBufferRequirements)( PalDevice* device, PalInstanceBufferRequirements* requirements, Uint32 instanceCount); + /** + * Backend implementation of ::palWriteInstancesToMappedMemory. + * + * This function must obey the rules and semantics documented in palWriteInstancesToMappedMemory(). + */ PalResult PAL_CALL (*writeInstancesToMappedMemory)( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, Uint32 instanceCount); + /** + * Backend implementation of ::palBindBufferMemory. + * + * This function must obey the rules and semantics documented in palBindBufferMemory(). + */ PalResult PAL_CALL (*bindBufferMemory)( PalBuffer* buffer, PalMemory* memory, Uint64 offset); + /** + * Backend implementation of ::palGetBufferDeviceAddress. + * + * This function must obey the rules and semantics documented in palGetBufferDeviceAddress(). + */ PalDeviceAddress PAL_CALL (*getBufferDeviceAddress)(PalBuffer* buffer); + /** + * Backend implementation of ::palCreateDescriptorSetLayout. + * + * This function must obey the rules and semantics documented in palCreateDescriptorSetLayout(). + */ PalResult PAL_CALL (*createDescriptorSetLayout)( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout); + /** + * Backend implementation of ::palDestroyDescriptorSetLayout. + * + * This function must obey the rules and semantics documented in palDestroyDescriptorSetLayout(). + */ void PAL_CALL (*destroyDescriptorSetLayout)(PalDescriptorSetLayout* layout); + /** + * Backend implementation of ::palCreateDescriptorPool. + * + * This function must obey the rules and semantics documented in palCreateDescriptorPool(). + */ PalResult PAL_CALL (*createDescriptorPool)( PalDevice* device, const PalDescriptorPoolCreateInfo* info, PalDescriptorPool** outPool); + /** + * Backend implementation of ::palDestroyDescriptorPool. + * + * This function must obey the rules and semantics documented in palDestroyDescriptorPool(). + */ void PAL_CALL (*destroyDescriptorPool)(PalDescriptorPool* pool); + /** + * Backend implementation of ::palResetDescriptorPool. + * + * This function must obey the rules and semantics documented in palResetDescriptorPool(). + */ PalResult PAL_CALL (*resetDescriptorPool)(PalDescriptorPool* pool); + /** + * Backend implementation of ::palAllocateDescriptorSet. + * + * This function must obey the rules and semantics documented in palAllocateDescriptorSet(). + */ PalResult PAL_CALL (*allocateDescriptorSet)( PalDevice* device, PalDescriptorPool* pool, PalDescriptorSetLayout* layout, PalDescriptorSet** outSet); + /** + * Backend implementation of ::palUpdateDescriptorSet. + * + * This function must obey the rules and semantics documented in palUpdateDescriptorSet(). + */ PalResult PAL_CALL (*updateDescriptorSet)( PalDevice* device, Uint32 count, PalDescriptorSetWriteInfo* infos); + /** + * Backend implementation of ::palCreatePipelineLayout. + * + * This function must obey the rules and semantics documented in palCreatePipelineLayout(). + */ PalResult PAL_CALL (*createPipelineLayout)( PalDevice* device, const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout); + /** + * Backend implementation of ::palDestroyPipelineLayout. + * + * This function must obey the rules and semantics documented in palDestroyPipelineLayout(). + */ void PAL_CALL (*destroyPipelineLayout)(PalPipelineLayout* layout); + /** + * Backend implementation of ::palCreateGraphicsPipeline. + * + * This function must obey the rules and semantics documented in palCreateGraphicsPipeline(). + */ PalResult PAL_CALL (*createGraphicsPipeline)( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline); + /** + * Backend implementation of ::palCreateComputePipeline. + * + * This function must obey the rules and semantics documented in palCreateComputePipeline(). + */ PalResult PAL_CALL (*createComputePipeline)( PalDevice* device, const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline); + /** + * Backend implementation of ::palCreateRayTracingPipeline. + * + * This function must obey the rules and semantics documented in palCreateRayTracingPipeline(). + */ PalResult PAL_CALL (*createRayTracingPipeline)( PalDevice* device, const PalRayTracingPipelineCreateInfo* info, PalPipeline** outPipeline); + /** + * Backend implementation of ::palDestroyPipeline. + * + * This function must obey the rules and semantics documented in palDestroyPipeline(). + */ void PAL_CALL (*destroyPipeline)(PalPipeline* pipeline); } PalGraphicsBackend; +/** + * @brief Add a custom graphics backend to the graphics system. + * + * The graphics system must not be initialized before this call. If already initialized, + * the system should be shutdown and re-initialized after this call. + * The graphics system supports 16 custom backends. + * + * The `backend` dispatch table must have its function pointers all set even if a + * function will not be used. If a feature is not supported by the backend, + * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED` must be returned by the appropriate function. + * If any of the function pointers are not set, this function will fail and + * `PAL_RESULT_INVALID_BACKEND` will be returned. + * + * The backend will not not copied, therefore the pointer must remain valid + * until the graphics system is shutdown. + * + * @param[in] backend Pointer to the backend dispatch table to add. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: This function must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palInitGraphics + * @sa palShutdownGraphics + */ PAL_API PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend); +/** + * @brief Initialize the graphics system. + * + * Any custom backends added with palAddGraphicsBackend() will be registered with the + * graphics system. The graphics system must be shutdown with palShutdownGraphics() when no longer needed. + * + * The debugger and allocator will not not copied, therefore the pointers must remain valid + * until the graphics system is shutdown. Set the debugger or PalGraphicsDebugger::callback to + * nullptr to disable debugging and validation layers. + * + * @param[in] debugger Optional debugger. Set to nullptr to disable debugging and validation + * layers. + * @param[in] allocator Optional user-provided allocator. Set to nullptr to use default. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: This function must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palAddGraphicsBackend + * @sa palShutdownGraphics + */ PAL_API PalResult PAL_CALL palInitGraphics( const PalGraphicsDebugger* debugger, const PalAllocator* allocator); +/** + * @brief Shutdown the graphics system. + * + * If the graphics system has not been initialized, the function returns silently. + * All created devices, queues, images, swapchains etc must be destroyed before this call. + * + * Thread safety: This function must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palInitGraphics + */ PAL_API void PAL_CALL palShutdownGraphics(); +/** + * @brief Return a list of all adapters (GPU) from custom and internal backends. + * + * The graphics system must be initialized before this call. + * + * If a custom backend which implements an adapter with its API type of Vulkan, and there is an + * adapter from the internal backends with the same specifications, this function will return both + * of them in the list. Use PalAdapterInfo::backendName to differentiate between custom and + * internal backend. the backend name for internal backend is `PAL`. + * + * Call this function first with PalAdapter array set to nullptr to get the number of adapters. + * Allocate memory for the PalAdapter array and passed in the count and the allocated array. If + * the count of the array is less than the number of adapters, PAL will write upto that limit. + * + * If the count is 0 and the PalAdapter array is nullptr, the function fails + * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. + * + * The adapter handles must not be freed by the user, they are managed by the + * graphics system. Users are required to cache this, and call this function again + * if adapters are added or removed which is rare except for virtual ones. + * + * @param[in] count Capacity of the PalAdapter array. + * @param[out] outAdapters User allocated array of PalAdapter. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: This function must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palEnumerateAdapters( Int32* count, PalAdapter** outAdapters); +/** + * @brief Get information about an adapter (GPU). + * + * The graphics system must be initialized before this call. + * + * @param[in] adapter Adapter to query information on. + * @param[out] info Pointer to a PalAdapterInfo to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: This function is thread safe if `info` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palEnumerateAdapters + */ PAL_API PalResult PAL_CALL palGetAdapterInfo( PalAdapter* adapter, PalAdapterInfo* info); +/** + * @brief Get capabilites or limits about an adapter (GPU). + * + * The graphics system must be initialized before this call. + * + * @param[in] adapter Adapter to query capabilities on. + * @param[out] caps Pointer to a PalAdapterCapabilities to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: This function is thread safe if `caps` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palEnumerateAdapters + */ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps); +/** + * @brief Get the supported features of an adapter (GPU). + * + * The graphics system must be initialized before this call. + * + * @param[in] adapter Adapter to query features on. + * + * @return adapter features on success or `0` on failure. + * + * Thread safety: This function is thread safe. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palEnumerateAdapters + */ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); +/** + * @brief Create a device from an adapter (GPU). + * + * The graphics system must be initialized before this call. PAL does not enable any features + * implicitly not even common ones like `PAL_ADAPTER_FEATURE_SWAPCHAIN`. + * + * Every requested feature must be supported by the adapter. Use palGetAdapterFeatures to check + * the supported features of the adapter that can be enabled. Using a feature which is not + * supported will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] adapter Adapter to create the device with. + * @param[in] features Adapter features to enable. Must be supported. + * @param[out] outDevice Pointer to a PalDevice to recieve the created device. Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: This function must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyDevice + */ PAL_API PalResult PAL_CALL palCreateDevice( PalAdapter* adapter, PalAdapterFeatures features, PalDevice** outDevice); +/** + * @brief Destroy a device. + * + * The graphics system must be initialized before this call. + * If the provided device is invalid or nullptr, this function returns + * silently. + * + * @param[in] device Pointer to the device to destroy. + * + * Thread safety: This function must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateDevice + */ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); +/** + * @brief Blocks indefinitely untill the device becomes idle. + * + * The graphics system must be initialized before this call. + * + * This function blocks indefinitely untill all submitted work on the device has been completetd. + * Returns `PAL_RESULT_SUCCESS` to indicate all pending operations has been completetd. + * + * @param[in] device Pointer to device to wait. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: This function is thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palWaitDevice(PalDevice* device); PAL_API PalResult PAL_CALL palAllocateMemory( diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 8f47974d..c3c47fbc 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -349,7 +349,7 @@ PAL_API PalResult PAL_CALL palCreateGLContext( * * @param[in] context Pointer to the context to destroy. * - * Thread safety: This function is thread safe if the `context` is thread local. + * Thread safety: This function is thread safe if the `context` is per thread. * * @since 1.0 * @ingroup pal_opengl diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index 59458e8e..562f75ad 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -169,7 +169,7 @@ typedef struct { * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread-safe if `info` is thread local. + * Thread safety: This function is thread-safe if `info` is per thread. * * @since 1.0 * @ingroup pal_system @@ -187,7 +187,7 @@ PAL_API PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info); * failure. Call palFormatResult() for more information. * * Thread safety: This function is thread-safe if the proivded allocator is - * thread safe and `info` is thread local. The default allocator is thread safe. + * thread safe and `info` is per thread. The default allocator is thread safe. * * @since 1.0 * @ingroup pal_system diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index 8cf5b80e..b0f76d97 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -165,7 +165,7 @@ typedef struct { * failure. Call palFormatResult() for more information. * * Thread safety: This function is thread safe if the provided allocator is - * thread safe and `outThread` is thread local. The default allocator is + * thread safe and `outThread` is per thread. The default allocator is * thread safe. * * @since 1.0 @@ -190,7 +190,7 @@ PAL_API PalResult PAL_CALL palCreateThread( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe if `retval` is thread local. + * Thread safety: This function is thread safe if `retval` is per thread. * * @since 1.0 * @ingroup pal_thread @@ -488,7 +488,7 @@ PAL_API void PAL_CALL palSetTLS( * failure. Call palFormatResult() for more information. * * Thread safety: This function is thread safe if the provided allocator is - * thread safe and `outMutex` is thread local. + * thread safe and `outMutex` is per thread. * * @since 1.0 * @ingroup pal_thread @@ -507,7 +507,7 @@ PAL_API PalResult PAL_CALL palCreateMutex( * @param[in] mutex Pointer to the mutex. * * Thread safety: This function is thread safe if the allocator used to create - * the mutex is thread safe and `mutex` is thread local. + * the mutex is thread safe and `mutex` is per thread. * * @since 1.0 * @ingroup pal_thread @@ -555,7 +555,7 @@ PAL_API void PAL_CALL palUnlockMutex(PalMutex* mutex); * failure. Call palFormatResult() for more information. * * Thread safety: This function is thread safe if the provided allocator is - * thread safe and `outCondVar` is thread local. + * thread safe and `outCondVar` is per thread. * * @since 1.0 * @ingroup pal_thread @@ -575,7 +575,7 @@ PAL_API PalResult PAL_CALL palCreateCondVar( * @param[in] condVar Pointer to the condition to destroy * * Thread safety: This function is thread safe if the allocator used to create - * the condition varibale is thread safe and `condVar` is thread local. + * the condition varibale is thread safe and `condVar` is per thread. * * @since 1.0 * @ingroup pal_thread diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 7897d01f..78ab6fd6 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -31,7 +31,7 @@ freely, subject to the following restrictions: // Typedefs, enums and structs // ================================================== -#define MAX_BACKENDS 32 +#define MAX_BACKENDS 18 // 16 for users #define PAL_HANDLE(name) \ struct name { \ const PalGraphicsBackend* backend; \ From e9dae9a43e4e08f3e26d281acdd85abd359b2f6f Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 3 Mar 2026 14:58:21 +0000 Subject: [PATCH 098/372] rename thread safety notes --- include/pal/pal_core.h | 28 +- include/pal/pal_event.h | 12 +- include/pal/pal_graphics.h | 638 ++++++++++++++++++++++++++++++------- include/pal/pal_opengl.h | 26 +- include/pal/pal_system.h | 4 +- include/pal/pal_thread.h | 56 ++-- include/pal/pal_video.h | 120 +++---- 7 files changed, 637 insertions(+), 247 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index db8242ce..1e98512c 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -318,7 +318,7 @@ typedef struct { * * @return PAL version (major, minor, build). * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_core @@ -331,7 +331,7 @@ PAL_API PalVersion PAL_CALL palGetVersion(); * * @return Null-terminated string containing the PAL version. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_core @@ -346,7 +346,7 @@ PAL_API const char* PAL_CALL palGetVersionString(); * * @return Null-terminated static string describing the result. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_core @@ -400,7 +400,7 @@ PAL_API void PAL_CALL palFree( * @param fmt printf-style format string. * @param ... Arguments for the format string. * - * Thread safety: This function is thread safe, but log output and + * Thread safety: Thread safe, but log output and * callbacks may be invoked concurrently. The user must ensure the callback * implementation is thread safe. * @@ -418,7 +418,7 @@ PAL_API void PAL_CALL palLog( * * @return Current performance counter value. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_core @@ -431,7 +431,7 @@ PAL_API Uint64 PAL_CALL palGetPerformanceCounter(); * * @return Performance counter frequency, in counts per second. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_core @@ -445,7 +445,7 @@ PAL_API Uint64 PAL_CALL palGetPerformanceFrequency(); * * @return The combined 64-bit signed integer. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_core @@ -464,7 +464,7 @@ static inline Int64 PAL_CALL palPackUint32( * * @return The combined 64-bit signed integer. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_core @@ -482,7 +482,7 @@ static inline Int64 PAL_CALL palPackInt32( * * @return The packed 64-bit signed integer. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_core @@ -498,7 +498,7 @@ static inline Int64 PAL_CALL palPackPointer(void* ptr) * * @return The combined 64-bit signed integer. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.3 * @ingroup pal_core @@ -526,7 +526,7 @@ static inline Int64 PAL_CALL palPackFloat( * @param[out] outLow Low value of the 64-bit signed integer. * @param[out] outHigh High value of the 64-bit signed integer. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_core @@ -552,7 +552,7 @@ static inline void PAL_CALL palUnpackUint32( * @param[out] outLow Low value of the 64-bit signed integer. * @param[out] outHigh High value of the 64-bit signed integer. * - * Thread safety: This function is thread-safe if `outLow` and `outHigh` are + * Thread safety: Thread-safe if `outLow` and `outHigh` are * thread local. * * @since 1.0 @@ -578,7 +578,7 @@ static inline void PAL_CALL palUnpackInt32( * * @return The pointer from the 64-bit signed integer. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_core @@ -595,7 +595,7 @@ static inline void* PAL_CALL palUnpackPointer(Int64 data) * @param[out] outLow Low value of the 64-bit signed integer. * @param[out] outHigh High value of the 64-bit signed integer. * - * Thread safety: This function is thread-safe if `outLow` and `outHigh` are + * Thread safety: Thread-safe if `outLow` and `outHigh` are * thread local. * * @since 1.3 diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 348b0fa1..bc1b9a9d 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -449,7 +449,7 @@ typedef struct { * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe if the provided allocator is + * Thread safety: Thread safe if the provided allocator is * thread safe and `outEventDriver` is per thread. The default allocator is * thread safe. * @@ -469,7 +469,7 @@ PAL_API PalResult PAL_CALL palCreateEventDriver( * * @param[in] eventDriver Pointer to the event driver to destroy. * - * Thread safety: This function is thread safe if the allocator used to create + * Thread safety: Thread safe if the allocator used to create * the event driver is thread safe and `eventDriver` is per thread. * * @since 1.0 @@ -495,7 +495,7 @@ PAL_API void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver); * @param[in] type Event type to set dispatch mode for. * @param[in] mode Dispatch mode to use. * - * Thread safety: This function is thread if multiple threads are not + * Thread safety: Thread if multiple threads are not * simultaneously setting dispatch mode on the same `eventDriver`. * * @since 1.0 @@ -516,7 +516,7 @@ PAL_API void PAL_CALL palSetEventDispatchMode( * * @return The dispatch mode on success or `PAL_DISPATCH_NONE` on failure. * - * Thread safety: This function is thread if multiple threads are not + * Thread safety: Thread if multiple threads are not * simultaneously setting dispatch mode on the same `eventDriver`. * * @since 1.0 @@ -544,7 +544,7 @@ PAL_API PalDispatchMode PAL_CALL palGetEventDispatchMode( * @param[in] eventDriver Pointer to the event driver. * @param[in] event Pointer to the event to push. * - * Thread safety: This function is thread if the provided event queue is thread + * Thread safety: Thread if the provided event queue is thread * safe or every thread has its own `eventDriver`. The default event queue is * not thread safe. * @@ -571,7 +571,7 @@ PAL_API void PAL_CALL palPushEvent( * @param[out] outEvent Pointer to a PalEvent to recieve the event. Must be * valid. * - * Thread safety: This function is thread if the provided event queue is thread + * Thread safety: Thread if the provided event queue is thread * safe or every thread has its own `eventDriver`. The default event queue is * not thread safe. * diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 87bf0052..e7efa752 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2284,7 +2284,7 @@ typedef struct { /** * Backend implementation of ::palEnumerateAdapters. * - * This function must obey the rules and semantics documented in palEnumerateAdapters(). + * Must obey the rules and semantics documented in palEnumerateAdapters(). */ PalResult PAL_CALL (*enumerateAdapters)( Int32* count, @@ -2293,7 +2293,7 @@ typedef struct { /** * Backend implementation of ::palGetAdapterInfo. * - * This function must obey the rules and semantics documented in palGetAdapterInfo(). + * Must obey the rules and semantics documented in palGetAdapterInfo(). */ PalResult PAL_CALL (*getAdapterInfo)( PalAdapter* adapter, @@ -2302,7 +2302,7 @@ typedef struct { /** * Backend implementation of ::palGetAdapterCapabilities. * - * This function must obey the rules and semantics documented in palGetAdapterCapabilities(). + * Must obey the rules and semantics documented in palGetAdapterCapabilities(). */ PalResult PAL_CALL (*getAdapterCapabilities)( PalAdapter* adapter, @@ -2311,14 +2311,14 @@ typedef struct { /** * Backend implementation of ::palGetAdapterFeatures. * - * This function must obey the rules and semantics documented in palGetAdapterFeatures(). + * Must obey the rules and semantics documented in palGetAdapterFeatures(). */ PalAdapterFeatures PAL_CALL (*getAdapterFeatures)(PalAdapter* adapter); /** * Backend implementation of ::palCreateDevice. * - * This function must obey the rules and semantics documented in palCreateDevice(). + * Must obey the rules and semantics documented in palCreateDevice(). */ PalResult PAL_CALL (*createDevice)( PalAdapter* adapter, @@ -2328,21 +2328,21 @@ typedef struct { /** * Backend implementation of ::palDestroyDevice. * - * This function must obey the rules and semantics documented in palDestroyDevice(). + * Must obey the rules and semantics documented in palDestroyDevice(). */ void PAL_CALL (*destroyDevice)(PalDevice* device); /** * Backend implementation of ::palWaitDevice. * - * This function must obey the rules and semantics documented in palWaitDevice(). + * Must obey the rules and semantics documented in palWaitDevice(). */ PalResult PAL_CALL (*waitDevice)(PalDevice* device); /** * Backend implementation of ::palAllocateMemory. * - * This function must obey the rules and semantics documented in palAllocateMemory(). + * Must obey the rules and semantics documented in palAllocateMemory(). */ PalResult PAL_CALL (*allocateMemory)( PalDevice* device, @@ -2354,7 +2354,7 @@ typedef struct { /** * Backend implementation of ::palFreeMemory. * - * This function must obey the rules and semantics documented in palFreeMemory(). + * Must obey the rules and semantics documented in palFreeMemory(). */ void PAL_CALL (*freeMemory)( PalDevice* device, @@ -2363,7 +2363,7 @@ typedef struct { /** * Backend implementation of ::palMapMemory. * - * This function must obey the rules and semantics documented in palMapMemory(). + * Must obey the rules and semantics documented in palMapMemory(). */ PalResult PAL_CALL (*mapMemory)( PalDevice* device, @@ -2375,7 +2375,7 @@ typedef struct { /** * Backend implementation of ::palUnmapMemory. * - * This function must obey the rules and semantics documented in palUnmapMemory(). + * Must obey the rules and semantics documented in palUnmapMemory(). */ void PAL_CALL (*unmapMemory)( PalDevice* device, @@ -2384,7 +2384,7 @@ typedef struct { /** * Backend implementation of ::palQueryDepthStencilCapabilities. * - * This function must obey the rules and semantics documented in + * Must obey the rules and semantics documented in * palQueryDepthStencilCapabilities(). */ PalResult PAL_CALL (*queryDepthStencilCapabilities)( @@ -2394,7 +2394,7 @@ typedef struct { /** * Backend implementation of ::palQueryFragmentShadingRateCapabilities. * - * This function must obey the rules and semantics documented in + * Must obey the rules and semantics documented in * palQueryFragmentShadingRateCapabilities(). */ PalResult PAL_CALL (*queryFragmentShadingRateCapabilities)( @@ -2404,7 +2404,7 @@ typedef struct { /** * Backend implementation of ::palQueryMeshShaderCapabilities. * - * This function must obey the rules and semantics documented in + * Must obey the rules and semantics documented in * palQueryMeshShaderCapabilities(). */ PalResult PAL_CALL (*queryMeshShaderCapabilities)( @@ -2414,7 +2414,7 @@ typedef struct { /** * Backend implementation of ::palQueryRayTracingCapabilities. * - * This function must obey the rules and semantics documented in + * Must obey the rules and semantics documented in * palQueryRayTracingCapabilities(). */ PalResult PAL_CALL (*queryRayTracingCapabilities)( @@ -2424,7 +2424,7 @@ typedef struct { /** * Backend implementation of ::palQueryDescriptorIndexingCapabilities. * - * This function must obey the rules and semantics documented in + * Must obey the rules and semantics documented in * palQueryDescriptorIndexingCapabilities(). */ PalResult PAL_CALL (*queryDescriptorIndexingCapabilities)( @@ -2434,7 +2434,7 @@ typedef struct { /** * Backend implementation of ::palCreateQueue. * - * This function must obey the rules and semantics documented in palCreateQueue(). + * Must obey the rules and semantics documented in palCreateQueue(). */ PalResult PAL_CALL (*createQueue)( PalDevice* device, @@ -2444,14 +2444,14 @@ typedef struct { /** * Backend implementation of ::palDestroyQueue. * - * This function must obey the rules and semantics documented in palDestroyQueue(). + * Must obey the rules and semantics documented in palDestroyQueue(). */ void PAL_CALL (*destroyQueue)(PalQueue* queue); /** * Backend implementation of ::palCanQueuePresent. * - * This function must obey the rules and semantics documented in palCanQueuePresent(). + * Must obey the rules and semantics documented in palCanQueuePresent(). */ bool PAL_CALL (*canQueuePresent)( PalQueue* queue, @@ -2460,14 +2460,14 @@ typedef struct { /** * Backend implementation of ::palWaitQueue. * - * This function must obey the rules and semantics documented in palWaitQueue(). + * Must obey the rules and semantics documented in palWaitQueue(). */ PalResult PAL_CALL (*waitQueue)(PalQueue* queue); /** * Backend implementation of ::palEnumerateFormats. * - * This function must obey the rules and semantics documented in palEnumerateFormats(). + * Must obey the rules and semantics documented in palEnumerateFormats(). */ PalResult PAL_CALL (*enumerateFormats)( PalAdapter* adapter, @@ -2477,7 +2477,7 @@ typedef struct { /** * Backend implementation of ::palIsFormatSupported. * - * This function must obey the rules and semantics documented in palIsFormatSupported(). + * Must obey the rules and semantics documented in palIsFormatSupported(). */ bool PAL_CALL (*isFormatSupported)( PalAdapter* adapter, @@ -2486,7 +2486,7 @@ typedef struct { /** * Backend implementation of ::palQueryFormatImageUsages. * - * This function must obey the rules and semantics documented in palQueryFormatImageUsages(). + * Must obey the rules and semantics documented in palQueryFormatImageUsages(). */ PalImageUsages PAL_CALL (*queryFormatImageUsages)( PalAdapter* adapter, @@ -2495,7 +2495,7 @@ typedef struct { /** * Backend implementation of ::palQueryFormatImageViewUsages. * - * This function must obey the rules and semantics documented in palQueryFormatImageViewUsages(). + * Must obey the rules and semantics documented in palQueryFormatImageViewUsages(). */ PalImageViewUsages PAL_CALL (*queryFormatImageViewUsages)( PalAdapter* adapter, @@ -2504,7 +2504,7 @@ typedef struct { /** * Backend implementation of ::palCreateImage. * - * This function must obey the rules and semantics documented in palCreateImage(). + * Must obey the rules and semantics documented in palCreateImage(). */ PalResult PAL_CALL (*createImage)( PalDevice* device, @@ -2514,14 +2514,14 @@ typedef struct { /** * Backend implementation of ::palDestroyImage. * - * This function must obey the rules and semantics documented in palDestroyImage(). + * Must obey the rules and semantics documented in palDestroyImage(). */ void PAL_CALL (*destroyImage)(PalImage* image); /** * Backend implementation of ::palGetImageInfo. * - * This function must obey the rules and semantics documented in palGetImageInfo(). + * Must obey the rules and semantics documented in palGetImageInfo(). */ PalResult PAL_CALL (*getImageInfo)( PalImage* image, @@ -2530,7 +2530,7 @@ typedef struct { /** * Backend implementation of ::palGetImageMemoryRequirements. * - * This function must obey the rules and semantics documented in palGetImageMemoryRequirements(). + * Must obey the rules and semantics documented in palGetImageMemoryRequirements(). */ PalResult PAL_CALL (*getImageMemoryRequirements)( PalImage* image, @@ -2539,7 +2539,7 @@ typedef struct { /** * Backend implementation of ::palBindImageMemory. * - * This function must obey the rules and semantics documented in palBindImageMemory(). + * Must obey the rules and semantics documented in palBindImageMemory(). */ PalResult PAL_CALL (*bindImageMemory)( PalImage* image, @@ -2549,7 +2549,7 @@ typedef struct { /** * Backend implementation of ::palCreateImageView. * - * This function must obey the rules and semantics documented in palCreateImageView(). + * Must obey the rules and semantics documented in palCreateImageView(). */ PalResult PAL_CALL (*createImageView)( PalDevice* device, @@ -2560,14 +2560,14 @@ typedef struct { /** * Backend implementation of ::palDestroyImageView. * - * This function must obey the rules and semantics documented in palDestroyImageView(). + * Must obey the rules and semantics documented in palDestroyImageView(). */ void PAL_CALL (*destroyImageView)(PalImageView* imageView); /** * Backend implementation of ::palQuerySwapchainCapabilities. * - * This function must obey the rules and semantics documented in palQuerySwapchainCapabilities(). + * Must obey the rules and semantics documented in palQuerySwapchainCapabilities(). */ PalResult PAL_CALL (*querySwapchainCapabilities)( PalDevice* device, @@ -2577,7 +2577,7 @@ typedef struct { /** * Backend implementation of ::palCreateSwapchain. * - * This function must obey the rules and semantics documented in palCreateSwapchain(). + * Must obey the rules and semantics documented in palCreateSwapchain(). */ PalResult PAL_CALL (*createSwapchain)( PalDevice* device, @@ -2589,14 +2589,14 @@ typedef struct { /** * Backend implementation of ::palDestroySwapchain. * - * This function must obey the rules and semantics documented in palDestroySwapchain(). + * Must obey the rules and semantics documented in palDestroySwapchain(). */ void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); /** * Backend implementation of ::palGetSwapchainImage. * - * This function must obey the rules and semantics documented in palGetSwapchainImage(). + * Must obey the rules and semantics documented in palGetSwapchainImage(). */ PalImage* PAL_CALL (*getSwapchainImage)( PalSwapchain* swapchain, @@ -2605,7 +2605,7 @@ typedef struct { /** * Backend implementation of ::palGetNextSwapchainImage. * - * This function must obey the rules and semantics documented in palGetNextSwapchainImage(). + * Must obey the rules and semantics documented in palGetNextSwapchainImage(). */ PalResult PAL_CALL (*getNextSwapchainImage)( PalSwapchain* swapchain, @@ -2615,7 +2615,7 @@ typedef struct { /** * Backend implementation of ::palPresentSwapchain. * - * This function must obey the rules and semantics documented in palPresentSwapchain(). + * Must obey the rules and semantics documented in palPresentSwapchain(). */ PalResult PAL_CALL (*presentSwapchain)( PalSwapchain* swapchain, @@ -2624,7 +2624,7 @@ typedef struct { /** * Backend implementation of ::palCreateShader. * - * This function must obey the rules and semantics documented in palCreateShader(). + * Must obey the rules and semantics documented in palCreateShader(). */ PalResult PAL_CALL (*createShader)( PalDevice* device, @@ -2634,14 +2634,14 @@ typedef struct { /** * Backend implementation of ::palDestroyShader. * - * This function must obey the rules and semantics documented in palDestroyShader(). + * Must obey the rules and semantics documented in palDestroyShader(). */ void PAL_CALL (*destroyShader)(PalShader* shader); /** * Backend implementation of ::palCreateFence. * - * This function must obey the rules and semantics documented in palCreateFence(). + * Must obey the rules and semantics documented in palCreateFence(). */ PalResult PAL_CALL (*createFence)( PalDevice* device, @@ -2651,14 +2651,14 @@ typedef struct { /** * Backend implementation of ::palDestroyFence. * - * This function must obey the rules and semantics documented in palDestroyFence(). + * Must obey the rules and semantics documented in palDestroyFence(). */ void PAL_CALL (*destroyFence)(PalFence* fence); /** * Backend implementation of ::palWaitFenceTimeout. * - * This function must obey the rules and semantics documented in palWaitFenceTimeout(). + * Must obey the rules and semantics documented in palWaitFenceTimeout(). */ PalResult PAL_CALL (*waitFenceTimeout)( PalFence* fence, @@ -2667,21 +2667,21 @@ typedef struct { /** * Backend implementation of ::palResetFence. * - * This function must obey the rules and semantics documented in palResetFence(). + * Must obey the rules and semantics documented in palResetFence(). */ PalResult PAL_CALL (*resetFence)(PalFence* fence); /** * Backend implementation of ::palIsFenceSignaled. * - * This function must obey the rules and semantics documented in palIsFenceSignaled(). + * Must obey the rules and semantics documented in palIsFenceSignaled(). */ bool PAL_CALL (*isFenceSignaled)(PalFence* fence); /** * Backend implementation of ::palCreateSemaphore. * - * This function must obey the rules and semantics documented in palCreateSemaphore(). + * Must obey the rules and semantics documented in palCreateSemaphore(). */ PalResult PAL_CALL (*createSemaphore)( PalDevice* device, @@ -2690,14 +2690,14 @@ typedef struct { /** * Backend implementation of ::palDestroySemaphore. * - * This function must obey the rules and semantics documented in palDestroySemaphore(). + * Must obey the rules and semantics documented in palDestroySemaphore(). */ void PAL_CALL (*destroySemaphore)(PalSemaphore* semaphore); /** * Backend implementation of ::palWaitSemaphore. * - * This function must obey the rules and semantics documented in palWaitSemaphore(). + * Must obey the rules and semantics documented in palWaitSemaphore(). */ PalResult PAL_CALL (*waitSemaphore)( PalSemaphore* semaphore, @@ -2708,7 +2708,7 @@ typedef struct { /** * Backend implementation of ::palSignalSemaphore. * - * This function must obey the rules and semantics documented in palSignalSemaphore(). + * Must obey the rules and semantics documented in palSignalSemaphore(). */ PalResult PAL_CALL (*signalSemaphore)( PalSemaphore* semaphore, @@ -2718,7 +2718,7 @@ typedef struct { /** * Backend implementation of ::palGetSemaphoreValue. * - * This function must obey the rules and semantics documented in palGetSemaphoreValue(). + * Must obey the rules and semantics documented in palGetSemaphoreValue(). */ PalResult PAL_CALL (*getSemaphoreValue)( PalSemaphore* semaphore, @@ -2727,7 +2727,7 @@ typedef struct { /** * Backend implementation of ::palCreateCommandPool. * - * This function must obey the rules and semantics documented in palCreateCommandPool(). + * Must obey the rules and semantics documented in palCreateCommandPool(). */ PalResult PAL_CALL (*createCommandPool)( PalDevice* device, @@ -2737,21 +2737,21 @@ typedef struct { /** * Backend implementation of ::palDestroyCommandPool. * - * This function must obey the rules and semantics documented in palDestroyCommandPool(). + * Must obey the rules and semantics documented in palDestroyCommandPool(). */ void PAL_CALL (*destroyCommandPool)(PalCommandPool* pool); /** * Backend implementation of ::palResetCommandPool. * - * This function must obey the rules and semantics documented in palResetCommandPool(). + * Must obey the rules and semantics documented in palResetCommandPool(). */ PalResult PAL_CALL (*resetCommandPool)(PalCommandPool* pool); /** * Backend implementation of ::palAllocateCommandBuffer. * - * This function must obey the rules and semantics documented in palAllocateCommandBuffer(). + * Must obey the rules and semantics documented in palAllocateCommandBuffer(). */ PalResult PAL_CALL (*allocateCommandBuffer)( PalDevice* device, @@ -2762,21 +2762,21 @@ typedef struct { /** * Backend implementation of ::palFreeCommandBuffer. * - * This function must obey the rules and semantics documented in palFreeCommandBuffer(). + * Must obey the rules and semantics documented in palFreeCommandBuffer(). */ void PAL_CALL (*freeCommandBuffer)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palResetCommandBuffer. * - * This function must obey the rules and semantics documented in palResetCommandBuffer(). + * Must obey the rules and semantics documented in palResetCommandBuffer(). */ PalResult PAL_CALL (*resetCommandBuffer)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palCmdBegin. * - * This function must obey the rules and semantics documented in palCmdBegin(). + * Must obey the rules and semantics documented in palCmdBegin(). */ PalResult PAL_CALL (*cmdBegin)( PalCommandBuffer* cmdBuffer, @@ -2785,14 +2785,14 @@ typedef struct { /** * Backend implementation of ::palCmdEnd. * - * This function must obey the rules and semantics documented in palCmdEnd(). + * Must obey the rules and semantics documented in palCmdEnd(). */ PalResult PAL_CALL (*cmdEnd)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palCmdExecuteCommandBuffer. * - * This function must obey the rules and semantics documented in palCmdExecuteCommandBuffer(). + * Must obey the rules and semantics documented in palCmdExecuteCommandBuffer(). */ PalResult PAL_CALL (*cmdExecuteCommandBuffer)( PalCommandBuffer* primaryCmdBuffer, @@ -2801,7 +2801,7 @@ typedef struct { /** * Backend implementation of ::palCmdSetFragmentShadingRate. * - * This function must obey the rules and semantics documented in palCmdSetFragmentShadingRate(). + * Must obey the rules and semantics documented in palCmdSetFragmentShadingRate(). */ PalResult PAL_CALL (*cmdSetFragmentShadingRate)( PalCommandBuffer* cmdBuffer, @@ -2810,7 +2810,7 @@ typedef struct { /** * Backend implementation of ::palCmdDrawMeshTasks. * - * This function must obey the rules and semantics documented in palCmdDrawMeshTasks(). + * Must obey the rules and semantics documented in palCmdDrawMeshTasks(). */ PalResult PAL_CALL (*cmdDrawMeshTasks)( PalCommandBuffer* cmdBuffer, @@ -2821,7 +2821,7 @@ typedef struct { /** * Backend implementation of ::palCmdDrawMeshTasksIndirect. * - * This function must obey the rules and semantics documented in palCmdDrawMeshTasksIndirect(). + * Must obey the rules and semantics documented in palCmdDrawMeshTasksIndirect(). */ PalResult PAL_CALL (*cmdDrawMeshTasksIndirect)( PalCommandBuffer* cmdBuffer, @@ -2833,7 +2833,7 @@ typedef struct { /** * Backend implementation of ::palCmdDrawMeshTasksIndirectCount. * - * This function must obey the rules and semantics documented in palCmdDrawMeshTasksIndirectCount(). + * Must obey the rules and semantics documented in palCmdDrawMeshTasksIndirectCount(). */ PalResult PAL_CALL (*cmdDrawMeshTasksIndirectCount)( PalCommandBuffer* cmdBuffer, @@ -2847,7 +2847,7 @@ typedef struct { /** * Backend implementation of ::palCmdBuildAccelerationStructure. * - * This function must obey the rules and semantics documented in palCmdBuildAccelerationStructure(). + * Must obey the rules and semantics documented in palCmdBuildAccelerationStructure(). */ PalResult PAL_CALL (*cmdBuildAccelerationStructure)( PalCommandBuffer* cmdBuffer, @@ -2856,7 +2856,7 @@ typedef struct { /** * Backend implementation of ::palCmdBeginRendering. * - * This function must obey the rules and semantics documented in palCmdBeginRendering(). + * Must obey the rules and semantics documented in palCmdBeginRendering(). */ PalResult PAL_CALL (*cmdBeginRendering)( PalCommandBuffer* cmdBuffer, @@ -2865,14 +2865,14 @@ typedef struct { /** * Backend implementation of ::palCmdEndRendering. * - * This function must obey the rules and semantics documented in palCmdEndRendering(). + * Must obey the rules and semantics documented in palCmdEndRendering(). */ PalResult PAL_CALL (*cmdEndRendering)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palCmdCopyBuffer. * - * This function must obey the rules and semantics documented in palCmdCopyBuffer(). + * Must obey the rules and semantics documented in palCmdCopyBuffer(). */ PalResult PAL_CALL (*cmdCopyBuffer)( PalCommandBuffer* cmdBuffer, @@ -2885,7 +2885,7 @@ typedef struct { /** * Backend implementation of ::palCmdBindPipeline. * - * This function must obey the rules and semantics documented in palCmdBindPipeline(). + * Must obey the rules and semantics documented in palCmdBindPipeline(). */ PalResult PAL_CALL (*cmdBindPipeline)( PalCommandBuffer* cmdBuffer, @@ -2894,7 +2894,7 @@ typedef struct { /** * Backend implementation of ::palCmdSetViewport. * - * This function must obey the rules and semantics documented in palCmdSetViewport(). + * Must obey the rules and semantics documented in palCmdSetViewport(). */ PalResult PAL_CALL (*cmdSetViewport)( PalCommandBuffer* cmdBuffer, @@ -2904,7 +2904,7 @@ typedef struct { /** * Backend implementation of ::palCmdSetScissors. * - * This function must obey the rules and semantics documented in palCmdSetScissors(). + * Must obey the rules and semantics documented in palCmdSetScissors(). */ PalResult PAL_CALL (*cmdSetScissors)( PalCommandBuffer* cmdBuffer, @@ -2914,7 +2914,7 @@ typedef struct { /** * Backend implementation of ::palCmdBindVertexBuffers. * - * This function must obey the rules and semantics documented in palCmdBindVertexBuffers(). + * Must obey the rules and semantics documented in palCmdBindVertexBuffers(). */ PalResult PAL_CALL (*cmdBindVertexBuffers)( PalCommandBuffer* cmdBuffer, @@ -2926,7 +2926,7 @@ typedef struct { /** * Backend implementation of ::palCmdBindIndexBuffer. * - * This function must obey the rules and semantics documented in palCmdBindIndexBuffer(). + * Must obey the rules and semantics documented in palCmdBindIndexBuffer(). */ PalResult PAL_CALL (*cmdBindIndexBuffer)( PalCommandBuffer* cmdBuffer, @@ -2937,7 +2937,7 @@ typedef struct { /** * Backend implementation of ::palCmdDraw. * - * This function must obey the rules and semantics documented in palCmdDraw(). + * Must obey the rules and semantics documented in palCmdDraw(). */ PalResult PAL_CALL (*cmdDraw)( PalCommandBuffer* cmdBuffer, @@ -2946,7 +2946,7 @@ typedef struct { /** * Backend implementation of ::palCmdDrawIndirect. * - * This function must obey the rules and semantics documented in palCmdDrawIndirect(). + * Must obey the rules and semantics documented in palCmdDrawIndirect(). */ PalResult PAL_CALL (*cmdDrawIndirect)( PalCommandBuffer* cmdBuffer, @@ -2957,7 +2957,7 @@ typedef struct { /** * Backend implementation of ::palCmdDrawIndirectCount. * - * This function must obey the rules and semantics documented in palCmdDrawIndirectCount(). + * Must obey the rules and semantics documented in palCmdDrawIndirectCount(). */ PalResult PAL_CALL (*cmdDrawIndirectCount)( PalCommandBuffer* cmdBuffer, @@ -2970,7 +2970,7 @@ typedef struct { /** * Backend implementation of ::palCmdDrawIndexed. * - * This function must obey the rules and semantics documented in palCmdDrawIndexed(). + * Must obey the rules and semantics documented in palCmdDrawIndexed(). */ PalResult PAL_CALL (*cmdDrawIndexed)( PalCommandBuffer* cmdBuffer, @@ -2979,7 +2979,7 @@ typedef struct { /** * Backend implementation of ::palCmdDrawIndexedIndirect. * - * This function must obey the rules and semantics documented in palCmdDrawIndexedIndirect(). + * Must obey the rules and semantics documented in palCmdDrawIndexedIndirect(). */ PalResult PAL_CALL (*cmdDrawIndexedIndirect)( PalCommandBuffer* cmdBuffer, @@ -2990,7 +2990,7 @@ typedef struct { /** * Backend implementation of ::palCmdDrawIndexedIndirectCount. * - * This function must obey the rules and semantics documented in palCmdDrawIndexedIndirectCount(). + * Must obey the rules and semantics documented in palCmdDrawIndexedIndirectCount(). */ PalResult PAL_CALL (*cmdDrawIndexedIndirectCount)( PalCommandBuffer* cmdBuffer, @@ -3003,7 +3003,7 @@ typedef struct { /** * Backend implementation of ::palCmdMemoryBarrier. * - * This function must obey the rules and semantics documented in palCmdMemoryBarrier(). + * Must obey the rules and semantics documented in palCmdMemoryBarrier(). */ PalResult PAL_CALL (*cmdMemoryBarrier)( PalCommandBuffer* cmdBuffer, @@ -3013,7 +3013,7 @@ typedef struct { /** * Backend implementation of ::palCmdImageViewBarrier. * - * This function must obey the rules and semantics documented in palCmdImageViewBarrier(). + * Must obey the rules and semantics documented in palCmdImageViewBarrier(). */ PalResult PAL_CALL (*cmdImageViewBarrier)( PalCommandBuffer* cmdBuffer, @@ -3024,7 +3024,7 @@ typedef struct { /** * Backend implementation of ::palCmdBufferBarrier. * - * This function must obey the rules and semantics documented in palCmdBufferBarrier(). + * Must obey the rules and semantics documented in palCmdBufferBarrier(). */ PalResult PAL_CALL (*cmdBufferBarrier)( PalCommandBuffer* cmdBuffer, @@ -3035,7 +3035,7 @@ typedef struct { /** * Backend implementation of ::palCmdDispatch. * - * This function must obey the rules and semantics documented in palCmdDispatch(). + * Must obey the rules and semantics documented in palCmdDispatch(). */ PalResult PAL_CALL (*cmdDispatch)( PalCommandBuffer* cmdBuffer, @@ -3046,7 +3046,7 @@ typedef struct { /** * Backend implementation of ::palCmdDispatchBase. * - * This function must obey the rules and semantics documented in palCmdDispatchBase(). + * Must obey the rules and semantics documented in palCmdDispatchBase(). */ PalResult PAL_CALL (*cmdDispatchBase)( PalCommandBuffer* cmdBuffer, @@ -3060,7 +3060,7 @@ typedef struct { /** * Backend implementation of ::palCmdDispatchIndirect. * - * This function must obey the rules and semantics documented in palCmdDispatchIndirect(). + * Must obey the rules and semantics documented in palCmdDispatchIndirect(). */ PalResult PAL_CALL (*cmdDispatchIndirect)( PalCommandBuffer* cmdBuffer, @@ -3070,7 +3070,7 @@ typedef struct { /** * Backend implementation of ::palCmdTraceRays. * - * This function must obey the rules and semantics documented in palCmdTraceRays(). + * Must obey the rules and semantics documented in palCmdTraceRays(). */ PalResult PAL_CALL (*cmdTraceRays)( PalCommandBuffer* cmdBuffer, @@ -3081,7 +3081,7 @@ typedef struct { /** * Backend implementation of ::palCmdTraceRaysIndirect. * - * This function must obey the rules and semantics documented in palCmdTraceRaysIndirect(). + * Must obey the rules and semantics documented in palCmdTraceRaysIndirect(). */ PalResult PAL_CALL (*cmdTraceRaysIndirect)( PalCommandBuffer* cmdBuffer, @@ -3090,7 +3090,7 @@ typedef struct { /** * Backend implementation of ::palCmdBindDescriptorSet. * - * This function must obey the rules and semantics documented in palCmdBindDescriptorSet(). + * Must obey the rules and semantics documented in palCmdBindDescriptorSet(). */ PalResult PAL_CALL (*cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, @@ -3102,7 +3102,7 @@ typedef struct { /** * Backend implementation of ::palCmdPushConstants. * - * This function must obey the rules and semantics documented in palCmdPushConstants(). + * Must obey the rules and semantics documented in palCmdPushConstants(). */ PalResult PAL_CALL (*cmdPushConstants)( PalCommandBuffer* cmdBuffer, @@ -3116,7 +3116,7 @@ typedef struct { /** * Backend implementation of ::palSubmitCommandBuffer. * - * This function must obey the rules and semantics documented in palSubmitCommandBuffer(). + * Must obey the rules and semantics documented in palSubmitCommandBuffer(). */ PalResult PAL_CALL (*submitCommandBuffer)( PalQueue* queue, @@ -3125,7 +3125,7 @@ typedef struct { /** * Backend implementation of ::palCreateAccelerationstructure. * - * This function must obey the rules and semantics documented in palCreateAccelerationstructure(). + * Must obey the rules and semantics documented in palCreateAccelerationstructure(). */ PalResult PAL_CALL (*createAccelerationstructure)( PalDevice* device, @@ -3135,14 +3135,14 @@ typedef struct { /** * Backend implementation of ::palDestroyAccelerationstructure. * - * This function must obey the rules and semantics documented in palDestroyAccelerationstructure(). + * Must obey the rules and semantics documented in palDestroyAccelerationstructure(). */ void PAL_CALL (*destroyAccelerationstructure)(PalAccelerationStructure* as); /** * Backend implementation of ::palGetAccelerationStructureBuildSize. * - * This function must obey the rules and semantics documented in palGetAccelerationStructureBuildSize(). + * Must obey the rules and semantics documented in palGetAccelerationStructureBuildSize(). */ PalResult PAL_CALL (*getAccelerationStructureBuildSize)( PalDevice* device, @@ -3152,7 +3152,7 @@ typedef struct { /** * Backend implementation of ::palCreateBuffer. * - * This function must obey the rules and semantics documented in palCreateBuffer(). + * Must obey the rules and semantics documented in palCreateBuffer(). */ PalResult PAL_CALL (*createBuffer)( PalDevice* device, @@ -3162,14 +3162,14 @@ typedef struct { /** * Backend implementation of ::palDestroyBuffer. * - * This function must obey the rules and semantics documented in palDestroyBuffer(). + * Must obey the rules and semantics documented in palDestroyBuffer(). */ void PAL_CALL (*destroyBuffer)(PalBuffer* buffer); /** * Backend implementation of ::palGetBufferMemoryRequirements. * - * This function must obey the rules and semantics documented in palGetBufferMemoryRequirements(). + * Must obey the rules and semantics documented in palGetBufferMemoryRequirements(). */ PalResult PAL_CALL (*getBufferMemoryRequirements)( PalBuffer* buffer, @@ -3178,7 +3178,7 @@ typedef struct { /** * Backend implementation of ::palComputeInstanceBufferRequirements. * - * This function must obey the rules and semantics documented in palComputeInstanceBufferRequirements(). + * Must obey the rules and semantics documented in palComputeInstanceBufferRequirements(). */ PalResult PAL_CALL (*computeInstanceBufferRequirements)( PalDevice* device, @@ -3188,7 +3188,7 @@ typedef struct { /** * Backend implementation of ::palWriteInstancesToMappedMemory. * - * This function must obey the rules and semantics documented in palWriteInstancesToMappedMemory(). + * Must obey the rules and semantics documented in palWriteInstancesToMappedMemory(). */ PalResult PAL_CALL (*writeInstancesToMappedMemory)( PalDevice* device, @@ -3199,7 +3199,7 @@ typedef struct { /** * Backend implementation of ::palBindBufferMemory. * - * This function must obey the rules and semantics documented in palBindBufferMemory(). + * Must obey the rules and semantics documented in palBindBufferMemory(). */ PalResult PAL_CALL (*bindBufferMemory)( PalBuffer* buffer, @@ -3209,14 +3209,14 @@ typedef struct { /** * Backend implementation of ::palGetBufferDeviceAddress. * - * This function must obey the rules and semantics documented in palGetBufferDeviceAddress(). + * Must obey the rules and semantics documented in palGetBufferDeviceAddress(). */ PalDeviceAddress PAL_CALL (*getBufferDeviceAddress)(PalBuffer* buffer); /** * Backend implementation of ::palCreateDescriptorSetLayout. * - * This function must obey the rules and semantics documented in palCreateDescriptorSetLayout(). + * Must obey the rules and semantics documented in palCreateDescriptorSetLayout(). */ PalResult PAL_CALL (*createDescriptorSetLayout)( PalDevice* device, @@ -3226,14 +3226,14 @@ typedef struct { /** * Backend implementation of ::palDestroyDescriptorSetLayout. * - * This function must obey the rules and semantics documented in palDestroyDescriptorSetLayout(). + * Must obey the rules and semantics documented in palDestroyDescriptorSetLayout(). */ void PAL_CALL (*destroyDescriptorSetLayout)(PalDescriptorSetLayout* layout); /** * Backend implementation of ::palCreateDescriptorPool. * - * This function must obey the rules and semantics documented in palCreateDescriptorPool(). + * Must obey the rules and semantics documented in palCreateDescriptorPool(). */ PalResult PAL_CALL (*createDescriptorPool)( PalDevice* device, @@ -3243,21 +3243,21 @@ typedef struct { /** * Backend implementation of ::palDestroyDescriptorPool. * - * This function must obey the rules and semantics documented in palDestroyDescriptorPool(). + * Must obey the rules and semantics documented in palDestroyDescriptorPool(). */ void PAL_CALL (*destroyDescriptorPool)(PalDescriptorPool* pool); /** * Backend implementation of ::palResetDescriptorPool. * - * This function must obey the rules and semantics documented in palResetDescriptorPool(). + * Must obey the rules and semantics documented in palResetDescriptorPool(). */ PalResult PAL_CALL (*resetDescriptorPool)(PalDescriptorPool* pool); /** * Backend implementation of ::palAllocateDescriptorSet. * - * This function must obey the rules and semantics documented in palAllocateDescriptorSet(). + * Must obey the rules and semantics documented in palAllocateDescriptorSet(). */ PalResult PAL_CALL (*allocateDescriptorSet)( PalDevice* device, @@ -3268,7 +3268,7 @@ typedef struct { /** * Backend implementation of ::palUpdateDescriptorSet. * - * This function must obey the rules and semantics documented in palUpdateDescriptorSet(). + * Must obey the rules and semantics documented in palUpdateDescriptorSet(). */ PalResult PAL_CALL (*updateDescriptorSet)( PalDevice* device, @@ -3278,7 +3278,7 @@ typedef struct { /** * Backend implementation of ::palCreatePipelineLayout. * - * This function must obey the rules and semantics documented in palCreatePipelineLayout(). + * Must obey the rules and semantics documented in palCreatePipelineLayout(). */ PalResult PAL_CALL (*createPipelineLayout)( PalDevice* device, @@ -3288,14 +3288,14 @@ typedef struct { /** * Backend implementation of ::palDestroyPipelineLayout. * - * This function must obey the rules and semantics documented in palDestroyPipelineLayout(). + * Must obey the rules and semantics documented in palDestroyPipelineLayout(). */ void PAL_CALL (*destroyPipelineLayout)(PalPipelineLayout* layout); /** * Backend implementation of ::palCreateGraphicsPipeline. * - * This function must obey the rules and semantics documented in palCreateGraphicsPipeline(). + * Must obey the rules and semantics documented in palCreateGraphicsPipeline(). */ PalResult PAL_CALL (*createGraphicsPipeline)( PalDevice* device, @@ -3305,7 +3305,7 @@ typedef struct { /** * Backend implementation of ::palCreateComputePipeline. * - * This function must obey the rules and semantics documented in palCreateComputePipeline(). + * Must obey the rules and semantics documented in palCreateComputePipeline(). */ PalResult PAL_CALL (*createComputePipeline)( PalDevice* device, @@ -3315,7 +3315,7 @@ typedef struct { /** * Backend implementation of ::palCreateRayTracingPipeline. * - * This function must obey the rules and semantics documented in palCreateRayTracingPipeline(). + * Must obey the rules and semantics documented in palCreateRayTracingPipeline(). */ PalResult PAL_CALL (*createRayTracingPipeline)( PalDevice* device, @@ -3325,7 +3325,7 @@ typedef struct { /** * Backend implementation of ::palDestroyPipeline. * - * This function must obey the rules and semantics documented in palDestroyPipeline(). + * Must obey the rules and semantics documented in palDestroyPipeline(). */ void PAL_CALL (*destroyPipeline)(PalPipeline* pipeline); } PalGraphicsBackend; @@ -3351,7 +3351,7 @@ typedef struct { * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.4 * @ingroup pal_graphics @@ -3377,7 +3377,7 @@ PAL_API PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backe * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.4 * @ingroup pal_graphics @@ -3394,7 +3394,7 @@ PAL_API PalResult PAL_CALL palInitGraphics( * If the graphics system has not been initialized, the function returns silently. * All created devices, queues, images, swapchains etc must be destroyed before this call. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.4 * @ingroup pal_graphics @@ -3403,7 +3403,7 @@ PAL_API PalResult PAL_CALL palInitGraphics( PAL_API void PAL_CALL palShutdownGraphics(); /** - * @brief Return a list of all adapters (GPU) from custom and internal backends. + * @brief Returns a list of all adapters (GPU) from custom and internal backends. * * The graphics system must be initialized before this call. * @@ -3429,7 +3429,7 @@ PAL_API void PAL_CALL palShutdownGraphics(); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.4 * @ingroup pal_graphics @@ -3449,7 +3449,7 @@ PAL_API PalResult PAL_CALL palEnumerateAdapters( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe if `info` is per thread. + * Thread safety: Thread safe if `info` is per thread. * * @since 1.4 * @ingroup pal_graphics @@ -3470,7 +3470,7 @@ PAL_API PalResult PAL_CALL palGetAdapterInfo( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe if `caps` is per thread. + * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 * @ingroup pal_graphics @@ -3489,7 +3489,7 @@ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( * * @return adapter features on success or `0` on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.4 * @ingroup pal_graphics @@ -3514,7 +3514,7 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.4 * @ingroup pal_graphics @@ -3534,7 +3534,7 @@ PAL_API PalResult PAL_CALL palCreateDevice( * * @param[in] device Pointer to the device to destroy. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.4 * @ingroup pal_graphics @@ -3543,11 +3543,11 @@ PAL_API PalResult PAL_CALL palCreateDevice( PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); /** - * @brief Blocks indefinitely untill the device becomes idle. + * @brief Blocks indefinitely until the device becomes idle. * * The graphics system must be initialized before this call. * - * This function blocks indefinitely untill all submitted work on the device has been completetd. + * This function blocks indefinitely until all submitted work on the device has been completetd. * Returns `PAL_RESULT_SUCCESS` to indicate all pending operations has been completetd. * * @param[in] device Pointer to device to wait. @@ -3555,13 +3555,37 @@ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe if `device` is externally synchronized. + * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palWaitDevice(PalDevice* device); +/** + * @brief Allocates GPU memory for the specified device. + * + * The graphics system must be initialized before this call. On CPU adapters, there is usually no + * `PAL_MEMORY_TYPE_GPU_ONLY` memory type available. So it uses shared memory as the vram and set + * the shared memory to the `PAL_MEMORY_TYPE_GPU_ONLY` for correctness. + * + * @param[in] device Pointer to device to allocate memory on. + * @param[in] type Memory type to allocate. Must be supported by the adapter associated with the + * device. + * @param[in] memoryMask Memory mask. Must match memory type. + * @param[in] size Number of bytes to allocate. Must not be 0. + * @param[out] outMemory Pointer to a PalMemory to recieved the allocated GPU memory. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized and + * `outMemory` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palFreeMemory + */ PAL_API PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, @@ -3569,10 +3593,53 @@ PAL_API PalResult PAL_CALL palAllocateMemory( Uint64 size, PalMemory** outMemory); +/** + * @brief Free GPU memory allocated by palAllocateMemory. + * + * The graphics system must be initialized before this call. + * If `memory` is nullptr, this function will return silently. + * + * @param[in] device Pointer to device to free memory on. + * @param[in] memory Pointer to memory to free. + * + * Thread safety: Thread safe if `device` is externally synchronized and + * `outMemory` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palAllocateMemory + */ PAL_API void PAL_CALL palFreeMemory( PalDevice* device, PalMemory* memory); +/** + * @brief Maps GPU memory to CPU visible address space. + * + * The graphics system must be initialized before this call. + * + * Only `PAL_MEMORY_TYPE_CPU_UPLOAD` and `PAL_MEMORY_TYPE_CPU_READBACK` can be mapped to + * CPU visible space. MApping `PAL_MEMORY_TYPE_GPU_ONLY` will fail and return + * `PAL_RESULT_MEMORY_MAP_FAILED`. + * + * @param[in] device Pointer to device memory belongs to. + * @param[in] memory Pointer to memory to map. + * @param[in] offset Starting point within the memory. + * @param[in] size Number of bytes to map from the offset. `offset + size` must not be + * greater than memory size. + * @param[out] outPtr Pointer to a void* to recieved the mapped memory. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` and `memory` is externally synchronized. + * Mapping with different offsets into the same memory is thread safe as long as `device` + * is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palUnmapMemory + */ PAL_API PalResult PAL_CALL palMapMemory( PalDevice* device, PalMemory* memory, @@ -3580,67 +3647,390 @@ PAL_API PalResult PAL_CALL palMapMemory( Uint64 size, void** outPtr); +/** + * @brief Unmap GPU memory from CPU visible address space. + * + * The graphics system must be initialized before this call. The memory must be mapped + * before this call. After this call, the CPU pointer must not be used anymore. + * + * @param[in] device Pointer to device memory belongs to. + * @param[in] memory Pointer to memory to unmap. + * + * Thread safety: Thread safe if `device` and `memory` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palMapMemory + */ PAL_API void PAL_CALL palUnmapMemory( PalDevice* device, PalMemory* memory); +/** + * @brief Get depth stencil feature capabilites or limits about a device. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to query depth stencil feature capabilities on. + * @param[out] caps Pointer to a PalDepthStencilCapabilities to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `caps` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps); +/** + * @brief Get fragment shading rate feature capabilites or limits about a device. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to query fragment shading rate feature capabilities on. + * @param[out] caps Pointer to a PalFragmentShadingRateCapabilities to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `caps` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( PalDevice* device, PalFragmentShadingRateCapabilities* caps); +/** + * @brief Get mesh shader feature capabilites or limits about a device. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to query mesh shader feature capabilities on. + * @param[out] caps Pointer to a PalMeshShaderCapabilities to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `caps` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( PalDevice* device, PalMeshShaderCapabilities* caps); +/** + * @brief Get ray tracing feature capabilites or limits about a device. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to query ray tracing feature capabilities on. + * @param[out] caps Pointer to a PalRayTracingCapabilities to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `caps` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( PalDevice* device, PalRayTracingCapabilities* caps); +/** + * @brief Get descriptor indexing feature capabilites or limits about a device. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to query descriptor indexing feature capabilities on. + * @param[out] caps Pointer to a PalDescriptorIndexingCapabilities to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `caps` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( PalDevice* device, PalDescriptorIndexingCapabilities* caps); +/** + * @brief Create a queue from a device. + * + * The graphics system must be initialized before this call. + * + * The number of queues of each type which can be created is limited per adapter. check with + * PalAdapterCapabilities::maxComputeQueues, PalAdapterCapabilities::maxGraphicsQueues and + * PalAdapterCapabilities::maxCopyQueues respectively for the limit for each queue type. + * Creating more queues than the supported will fail and return `PAL_RESULT_OUT_OF_QUEUE`. + * + * On most adapters, compute and graphics queues can also do copy operations. + * + * @param[in] device Device to create queue on. + * @param[in] type Queue type. (eg. PAL_QUEUE_TYPE_GRAPHICS). + * @param[out] outQueue Pointer to a PalQueue to recieve the created queue. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyQueue + */ PAL_API PalResult PAL_CALL palCreateQueue( PalDevice* device, PalQueueType type, PalQueue** outQueue); +/** + * @brief Destroy a queue. + * + * The graphics system must be initialized before this call. + * If the provided queue is invalid or nullptr, this function returns + * silently. + * + * @param[in] queue Queue to destroy. + * + * Thread safety: Thread safe if the device used to create the queue is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateQueue + */ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); +/** + * @brief Check if a queue is presentable to the provided window. + * + * The graphics system must be initialized before this call. + * + * @param[in] queue Queue to query. + * @param[in] window Window to check presentation support for. + * + * @return True if queue can present otherwise false if queue can not present. + * + * Thread safety: Must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateQueue + */ PAL_API bool PAL_CALL palCanQueuePresent( PalQueue* queue, PalGraphicsWindow* window); +/** + * @brief Blocks indefinitely until the queue becomes idle. + * + * The graphics system must be initialized before this call. + * + * This function blocks indefinitely until all submitted work on the queue has been completetd. + * Returns `PAL_RESULT_SUCCESS` to indicate all pending operations has been completetd. + * + * @param[in] queue Pointer to queue to wait. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `queue` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); +/** + * @brief Returns a list of all supported formats of an adapter (GPU). + * + * The graphics system must be initialized before this call. + * + * This function returns the supported format with the supported image and image view usages + * associated with the format. This is a handy way of selecting a format based on the image + * or image view usages. Use palIsFormatSupported() to check for a specific format. + * + * Call this function first with PalFormatInfo array set to nullptr to get the number of formats. + * Allocate memory for the PalFormatInfo array and passed in the count and the allocated array. If + * the count of the array is less than the number of formats, PAL will write upto that limit. + * + * If the count is 0 and the PalFormatInfo array is nullptr, the function fails + * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. + * + * @param[in] adapter Adapter to query formats on. + * @param[in] count Capacity of the PalFormatInfo array. + * @param[out] outFormats User allocated array of PalFormatInfo. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palIsFormatSupported + */ PAL_API PalResult PAL_CALL palEnumerateFormats( PalAdapter* adapter, Int32* count, PalFormatInfo* outFormats); +/** + * @brief Check support for a format on an adapter (GPU). + * + * The graphics system must be initialized before this call. + * + * This is much faster than enumerating all the formats to pick one. You directly check support + * for the format you want to use. Call palQueryFormatImageUsages() and + * palQueryFormatImageViewUsages() to check for supported image and image view usages respectively + * if format is supported. + * + * @param[in] adapter Adapter to query format on. + * @param[in] format Format to query support for. + * + * @return True if format is supported otherwise false if not supported. + * + * Thread safety: Must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palQueryFormatImageUsages + * @sa palQueryFormatImageViewUsages + */ PAL_API bool PAL_CALL palIsFormatSupported( PalAdapter* adapter, PalFormat format); +/** + * @brief Checks supported image usages associated with a format. + * + * The graphics system must be initialized before this call. + * + * @param[in] adapter Adapter to query format on. + * @param[in] format Format to query image usages for. + * + * @return Supported image usages on success otherwise `0` on failure. + * + * Thread safety: Must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalImageUsages PAL_CALL palQueryFormatImageUsages( PalAdapter* adapter, PalFormat format); +/** + * @brief Checks supported image view usages associated with a format. + * + * The graphics system must be initialized before this call. + * + * @param[in] adapter Adapter to query format on. + * @param[in] format Format to query image view usages for. + * + * @return Supported image view usages on success otherwise `0` on failure. + * + * Thread safety: Must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( PalAdapter* adapter, PalFormat format); +/** + * @brief Create an image. + * + * The graphics system must be initialized before this call. + * + * PalImageCreateInfo::width, PalImageCreateInfo::height and PalImageCreateInfo::sampleCount + * must not be greater than the limits of the adapter used to create the device. Check + * adapter capabilities for the limits. + * + * @param[in] device Device to create image on. + * @param[in] info Pointer to a PalImageCreateInfo struct that specifies paramters. + * Must not be nullptr. + * @param[out] outImage Pointer to a PalImage to recieve the created image. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyImage + */ PAL_API PalResult PAL_CALL palCreateImage( PalDevice* device, const PalImageCreateInfo* info, PalImage** outImage); +/** + * @brief Destroy an image. + * + * The graphics system must be initialized before this call. + * If the provided image is invalid or nullptr, this function returns + * silently. + * + * @param[in] image Image to destroy. + * + * Thread safety: Thread safe if the device used to create the image is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateImage + */ PAL_API void PAL_CALL palDestroyImage(PalImage* image); +/** + * @brief Get information about an image. + * + * The graphics system must be initialized before this call. + * This function also supports swapchain images. + * + * @param[in] adapter Adapter to query information on. + * @param[out] info Pointer to a PalAdapterInfo to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `info` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateImage + */ PAL_API PalResult PAL_CALL palGetImageInfo( PalImage* image, PalImageInfo* info); diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index c3c47fbc..130ca822 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -210,7 +210,7 @@ typedef struct { * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_opengl @@ -225,7 +225,7 @@ PAL_API PalResult PAL_CALL palInitGL(const PalAllocator* allocator); * If the opengl system has not been initialized, the function returns silently. * All created contexts must be destroyed before this call. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_opengl @@ -241,7 +241,7 @@ PAL_API void PAL_CALL palShutdownGL(); * * @return A pointer to a PalGLInfo on success or nullptr on failure. * - * Thread safety: This function is thread-safe. + * Thread safety: Thread-safe. * * @since 1.0 * @ingroup pal_opengl @@ -269,7 +269,7 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_opengl @@ -298,7 +298,7 @@ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( * * @return The closest PalGLFBConfig on success or nullptr on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_opengl @@ -329,7 +329,7 @@ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_opengl @@ -349,7 +349,7 @@ PAL_API PalResult PAL_CALL palCreateGLContext( * * @param[in] context Pointer to the context to destroy. * - * Thread safety: This function is thread safe if the `context` is per thread. + * Thread safety: Thread safe if the `context` is per thread. * * @since 1.0 * @ingroup pal_opengl @@ -377,7 +377,7 @@ PAL_API void PAL_CALL palDestroyGLContext(PalGLContext* context); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe, but only one thread may have the + * Thread safety: Thread safe, but only one thread may have the * current context at a time. * * @since 1.0 @@ -396,7 +396,7 @@ PAL_API PalResult PAL_CALL palMakeContextCurrent( * * @return the pointer to the function on success or nullptr on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_opengl @@ -416,7 +416,7 @@ PAL_API void* PAL_CALL palGLGetProcAddress(const char* name); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from a thread that has a + * Thread safety: Must only be called from a thread that has a * bound context. * * @since 1.0 @@ -440,7 +440,7 @@ PAL_API PalResult PAL_CALL palSwapBuffers( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from a thread with a bound + * Thread safety: Must only be called from a thread with a bound * context. * * @since 1.0 @@ -460,7 +460,7 @@ PAL_API PalResult PAL_CALL palSetSwapInterval(Int32 interval); * On Windows: This is the HINSTANCE of the process. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @note The provided instance will not be freed by the opengl system. * @@ -476,7 +476,7 @@ PAL_API void PAL_CALL palGLSetInstance(void* instance); * The opengl system must be initialized before this call. * Possible values are `wgl`, `glx`, `gles`, `egl`. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.3 * @ingroup pal_opengl diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index 562f75ad..3b133e4c 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -169,7 +169,7 @@ typedef struct { * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread-safe if `info` is per thread. + * Thread safety: Thread-safe if `info` is per thread. * * @since 1.0 * @ingroup pal_system @@ -186,7 +186,7 @@ PAL_API PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread-safe if the proivded allocator is + * Thread safety: Thread-safe if the proivded allocator is * thread safe and `info` is per thread. The default allocator is thread safe. * * @since 1.0 diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index b0f76d97..bac13df7 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -164,7 +164,7 @@ typedef struct { * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe if the provided allocator is + * Thread safety: Thread safe if the provided allocator is * thread safe and `outThread` is per thread. The default allocator is * thread safe. * @@ -190,7 +190,7 @@ PAL_API PalResult PAL_CALL palCreateThread( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe if `retval` is per thread. + * Thread safety: Thread safe if `retval` is per thread. * * @since 1.0 * @ingroup pal_thread @@ -202,7 +202,7 @@ PAL_API PalResult PAL_CALL palJoinThread( /** * @brief Release the thread's resources and destroy it. * - * This function must be called when the thread is done executing. + * Must be called when the thread is done executing. * After this call, the thread cannot be attached or used anymore. * If the thread is invalid or nullptr, this function returns silently. * @@ -210,7 +210,7 @@ PAL_API PalResult PAL_CALL palJoinThread( * * @param[in] thread Pointer to the thread to detach. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -222,7 +222,7 @@ PAL_API void PAL_CALL palDetachThread(PalThread* thread); * * @param[in] milliseconds Number of milliseconds to sleep. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -233,7 +233,7 @@ PAL_API void PAL_CALL palSleep(Uint64 milliseconds); * @brief Yield the remainder of the calling threads time sliced, * allowing other threads of equal priority to run. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -245,7 +245,7 @@ PAL_API void PAL_CALL palYield(); * * @return The current thread on success or nullptr on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -259,7 +259,7 @@ PAL_API PalThread* PAL_CALL palGetCurrentThread(); * * @return The thread features on success or 0 on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -275,7 +275,7 @@ PAL_API PalThreadFeatures PAL_CALL palGetThreadFeatures(); * * @return The thread priority on success or 0 on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -292,7 +292,7 @@ PAL_API PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread); * * @return The thread affinity on success or 0 on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -315,7 +315,7 @@ PAL_API Uint64 PAL_CALL palGetThreadAffinity(PalThread* thread); * @param[out] outBuffer Pointer to a user provided buffer to recieve the name. * Can be nullptr. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @note On Linux: Thread names are limited to 16 characters including the null * terminator. @@ -346,7 +346,7 @@ PAL_API PalResult PAL_CALL palGetThreadName( * * @return * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -375,7 +375,7 @@ PAL_API PalResult PAL_CALL palSetThreadPriority( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -396,7 +396,7 @@ PAL_API PalResult PAL_CALL palSetThreadAffinity( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @note On Linux: Thread names are limited to 16 characters including the null * terminator. @@ -424,7 +424,7 @@ PAL_API PalResult PAL_CALL palSetThreadName( * * @return The TLS on success or 0 on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -437,7 +437,7 @@ PAL_API PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor); * * @param[in] id The TLS to destroy. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -452,7 +452,7 @@ PAL_API void PAL_CALL palDestroyTLS(PalTLSId id); * * @return the value on success or nullptr on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -466,7 +466,7 @@ PAL_API void* PAL_CALL palGetTLS(PalTLSId id); * @param[in] id The TLS to set value to. * @param[in] data The value to set for the calling thread * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -487,7 +487,7 @@ PAL_API void PAL_CALL palSetTLS( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe if the provided allocator is + * Thread safety: Thread safe if the provided allocator is * thread safe and `outMutex` is per thread. * * @since 1.0 @@ -506,7 +506,7 @@ PAL_API PalResult PAL_CALL palCreateMutex( * * @param[in] mutex Pointer to the mutex. * - * Thread safety: This function is thread safe if the allocator used to create + * Thread safety: Thread safe if the allocator used to create * the mutex is thread safe and `mutex` is per thread. * * @since 1.0 @@ -520,7 +520,7 @@ PAL_API void PAL_CALL palDestroyMutex(PalMutex* mutex); * * @param[in] mutex Pointer to the mutex to lock. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -535,7 +535,7 @@ PAL_API void PAL_CALL palLockMutex(PalMutex* mutex); * * @param[in] mutex Pointer to the mutex to unlock. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -554,7 +554,7 @@ PAL_API void PAL_CALL palUnlockMutex(PalMutex* mutex); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function is thread safe if the provided allocator is + * Thread safety: Thread safe if the provided allocator is * thread safe and `outCondVar` is per thread. * * @since 1.0 @@ -574,7 +574,7 @@ PAL_API PalResult PAL_CALL palCreateCondVar( * * @param[in] condVar Pointer to the condition to destroy * - * Thread safety: This function is thread safe if the allocator used to create + * Thread safety: Thread safe if the allocator used to create * the condition varibale is thread safe and `condVar` is per thread. * * @since 1.0 @@ -598,7 +598,7 @@ PAL_API void PAL_CALL palDestroyCondVar(PalCondVar* condVar); * @param[in] condVar Pointer to the condition variable. * @param[in] mutex Pointer to the mutex. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -619,7 +619,7 @@ PAL_API PalResult PAL_CALL palWaitCondVar( * @param[in] mutex Pointer to the mutex. * @param[in] milliseconds Timeout in milliseconds. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -635,7 +635,7 @@ PAL_API PalResult PAL_CALL palWaitCondVarTimeout( * * @param[in] condVar Pointer to the condition variable. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_thread @@ -648,7 +648,7 @@ PAL_API void PAL_CALL palSignalCondVar(PalCondVar* condVar); * * @param[in] condVar Pointer to the condition variable. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0. * @ingroup pal_thread diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 05d1247b..a6ed75fb 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -704,7 +704,7 @@ typedef struct { * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -721,7 +721,7 @@ PAL_API PalResult PAL_CALL palInitVideo( * If the video system has not been initialized, the function returns silently. * All created windows, icons, and cursors must be destroyed before this call. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -736,7 +736,7 @@ PAL_API void PAL_CALL palShutdownVideo(); * This function pushes generated video events to the event driver set at * palInitVideo(). * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -751,7 +751,7 @@ PAL_API void PAL_CALL palUpdateVideo(); * * @return video features on success or `0` on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.0 * @ingroup pal_video @@ -768,7 +768,7 @@ PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures(); * * @return video features on success or `0` on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @since 1.3 * @ingroup pal_video @@ -802,7 +802,7 @@ PAL_API PalVideoFeatures64 PAL_CALL palGetVideoFeaturesEx(); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.1 * @ingroup pal_video @@ -835,7 +835,7 @@ PAL_API PalResult PAL_CALL palSetFBConfig( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -860,7 +860,7 @@ PAL_API PalResult PAL_CALL palEnumerateMonitors( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -883,7 +883,7 @@ PAL_API PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -914,7 +914,7 @@ PAL_API PalResult PAL_CALL palGetMonitorInfo( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -937,7 +937,7 @@ PAL_API PalResult PAL_CALL palEnumerateMonitorModes( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -967,7 +967,7 @@ PAL_API PalResult PAL_CALL palGetCurrentMonitorMode( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -989,7 +989,7 @@ PAL_API PalResult PAL_CALL palSetMonitorMode( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1012,7 +1012,7 @@ PAL_API PalResult PAL_CALL palValidateMonitorMode( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1034,7 +1034,7 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @note On Wayland * @@ -1061,7 +1061,7 @@ PAL_API PalResult PAL_CALL palCreateWindow( * * @param[in] window Pointer to the window to destroy. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1081,7 +1081,7 @@ PAL_API void PAL_CALL palDestroyWindow(PalWindow* window); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1102,7 +1102,7 @@ PAL_API PalResult PAL_CALL palMinimizeWindow(PalWindow* window); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1123,7 +1123,7 @@ PAL_API PalResult PAL_CALL palMaximizeWindow(PalWindow* window); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @note Wayland does not support restoring a minimized windows. * @@ -1147,7 +1147,7 @@ PAL_API PalResult PAL_CALL palRestoreWindow(PalWindow* window); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1167,7 +1167,7 @@ PAL_API PalResult PAL_CALL palShowWindow(PalWindow* window); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1192,7 +1192,7 @@ PAL_API PalResult PAL_CALL palHideWindow(PalWindow* window); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1213,7 +1213,7 @@ PAL_API PalResult PAL_CALL palFlashWindow( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1235,7 +1235,7 @@ PAL_API PalResult PAL_CALL palGetWindowStyle( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1260,7 +1260,7 @@ PAL_API PalResult PAL_CALL palGetWindowMonitor( * @param[out] outBuffer Pointer to a user provided buffer to recieve the title. * Can be nullptr. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1285,7 +1285,7 @@ PAL_API PalResult PAL_CALL palGetWindowTitle( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1309,7 +1309,7 @@ PAL_API PalResult PAL_CALL palGetWindowPos( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1332,7 +1332,7 @@ PAL_API PalResult PAL_CALL palGetWindowSize( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1353,7 +1353,7 @@ PAL_API PalResult PAL_CALL palGetWindowState( * * @return A pointer to the keycodes array on success or nullptr on failure. * - * Thread safety: This function is thread-safe. + * Thread safety: Thread-safe. * * @since 1.0 * @ingroup pal_video @@ -1372,7 +1372,7 @@ PAL_API const bool* PAL_CALL palGetKeycodeState(); * * @return A pointer to the scancodes array on success or nullptr on failure. * - * Thread safety: This function is thread-safe. + * Thread safety: Thread-safe. * * @since 1.0 * @ingroup pal_video @@ -1390,7 +1390,7 @@ PAL_API const bool* PAL_CALL palGetScancodeState(); * * @return A pointer to the mouse button array on success or nullptr on failure. * - * @Thread safety: This function is thread-safe. + * @Thread safety: Thread-safe. * * @since 1.0 * @ingroup pal_video @@ -1408,7 +1408,7 @@ PAL_API const bool* PAL_CALL palGetMouseState(); * @param[in] dy Pointer to recieve the mouse relative movement y. Can be * nullptr. * - * Thread safety: This function is thread-safe if `dx` and `dy` are thread + * Thread safety: Thread-safe if `dx` and `dy` are thread * local. * * @since 1.0 @@ -1427,7 +1427,7 @@ PAL_API void PAL_CALL palGetMouseDelta( * @param[in] dx Pointer to recieve the mouse wheel delta x. Can be nullptr. * @param[in] dy Pointer to recieve the mouse wheel delta y. Can be nullptr. * - * Thread safety: This function is thread-safe if `dx` and `dy` are thread + * Thread safety: Thread-safe if `dx` and `dy` are thread * local. * * @since 1.0 @@ -1448,7 +1448,7 @@ PAL_API void PAL_CALL palGetMouseWheelDelta( * @param[in] dy Pointer to recieve the mouse wheel delta y in floats. Can be * nullptr. * - * Thread safety: This function is thread-safe if `dx` and `dy` are thread + * Thread safety: Thread-safe if `dx` and `dy` are thread * local. * * @since 1.3 @@ -1468,7 +1468,7 @@ PAL_API void PAL_CALL palGetRawMouseWheelDelta( * * @return `true` if the window is visible otherwise `false`. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1484,7 +1484,7 @@ PAL_API bool PAL_CALL palIsWindowVisible(PalWindow* window); * @return The current input-focused window on success or nullptr on * failure. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1500,7 +1500,7 @@ PAL_API PalWindow* PAL_CALL palGetFocusWindow(); * * @return The native handle of the window on success or nullptr on failure. * - * Thread safety: This function is thread-safe. + * Thread safety: Thread-safe. * * @since 1.0 * @ingroup pal_video @@ -1521,7 +1521,7 @@ PAL_API PalWindowHandleInfo PAL_CALL palGetWindowHandleInfo(PalWindow* window); * * @return The native handles of the window on success or nullptr on failure. * - * Thread safety: This function is thread-safe. + * Thread safety: Thread-safe. * * @since 1.3 * @ingroup pal_video @@ -1541,7 +1541,7 @@ PAL_API PalWindowHandleInfoEx PAL_CALL palGetWindowHandleInfoEx(PalWindow* w); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1562,7 +1562,7 @@ PAL_API PalResult PAL_CALL palSetWindowOpacity( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1585,7 +1585,7 @@ PAL_API PalResult PAL_CALL palSetWindowStyle( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1608,7 +1608,7 @@ PAL_API PalResult PAL_CALL palSetWindowTitle( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1634,7 +1634,7 @@ PAL_API PalResult PAL_CALL palSetWindowPos( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1656,7 +1656,7 @@ PAL_API PalResult PAL_CALL palSetWindowSize( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1678,7 +1678,7 @@ PAL_API PalResult PAL_CALL palSetFocusWindow(PalWindow* window); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1698,7 +1698,7 @@ PAL_API PalResult PAL_CALL palCreateIcon( * * @param[in] icon Pointer to the icon to destroy. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1718,7 +1718,7 @@ PAL_API void PAL_CALL palDestroyIcon(PalIcon* icon); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1740,7 +1740,7 @@ PAL_API PalResult PAL_CALL palSetWindowIcon( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1762,7 +1762,7 @@ PAL_API PalResult PAL_CALL palCreateCursor( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must only be called from the main thread. + * Thread safety: Must only be called from the main thread. * * @since 1.1 * @ingroup pal_video @@ -1782,7 +1782,7 @@ PAL_API PalResult PAL_CALL palCreateCursorFrom( * * @param[in] cursor Pointer to the cursor to destroy. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1801,7 +1801,7 @@ PAL_API void PAL_CALL palDestroyCursor(PalCursor* cursor); * * @param[in] show True to make the cursor visible otherwise false. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1824,7 +1824,7 @@ PAL_API void PAL_CALL palShowCursor(bool show); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1849,7 +1849,7 @@ PAL_API PalResult PAL_CALL palClipCursor( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1873,7 +1873,7 @@ PAL_API PalResult PAL_CALL palGetCursorPos( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1894,7 +1894,7 @@ PAL_API PalResult PAL_CALL palSetCursorPos( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.0 * @ingroup pal_video @@ -1917,7 +1917,7 @@ PAL_API PalResult PAL_CALL palSetWindowCursor( * * @return The instance or display on success or nullptr on failure. * - * Thread safety: This function is thread safe. + * Thread safety: Thread safe. * * @note The returned instance or display must not be freed. * @@ -1955,7 +1955,7 @@ PAL_API void* PAL_CALL palGetInstance(); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.2 * @ingroup pal_video @@ -1992,7 +1992,7 @@ PAL_API PalResult PAL_CALL palAttachWindow( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @since 1.2 * @ingroup pal_video @@ -2005,7 +2005,7 @@ PAL_API PalResult PAL_CALL palDetachWindow( /** * @brief Set the preferred instance the video system should use. * - * This function must be called before palInitVideo(). This will be ignored + * Must be called before palInitVideo(). This will be ignored * if the video system is already initialized. * If there is no preferred instance set, the video system creates one. * @@ -2013,7 +2013,7 @@ PAL_API PalResult PAL_CALL palDetachWindow( * On Windows: This is the HINSTANCE of the process. * - * Thread safety: This function must be called from the main thread. + * Thread safety: Must be called from the main thread. * * @note The provided instance will not be freed by the video system. * From 6609cd92e6beec7972fa2190454a20ce3edcfa7a Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 6 Mar 2026 12:17:28 +0000 Subject: [PATCH 099/372] remove fence timeout feature bit --- include/pal/pal_graphics.h | 403 +++++++++++++++++++++++++++++++++++-- src/graphics/pal_vulkan.c | 1 - tests/graphics_test.c | 4 - 3 files changed, 387 insertions(+), 21 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index e7efa752..31e479a0 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -569,20 +569,19 @@ typedef enum { PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16), PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY = PAL_BIT64(17), PAL_ADAPTER_FEATURE_FENCE_RESET = PAL_BIT64(18), - PAL_ADAPTER_FEATURE_FENCE_TIMEOUT = PAL_BIT64(19), - PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE = PAL_BIT64(20), - PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE = PAL_BIT64(21), - PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE = PAL_BIT64(22), - PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY = PAL_BIT64(23), - PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE = PAL_BIT64(24), - PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(25), - PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(26), - PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(27), - PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(28), - PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(29), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(31), - PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(32) + PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE = PAL_BIT64(19), + PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE = PAL_BIT64(20), + PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE = PAL_BIT64(21), + PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY = PAL_BIT64(22), + PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE = PAL_BIT64(23), + PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(24), + PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(25), + PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(26), + PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(27), + PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(28), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(29), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(30), + PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(31) } PalAdapterFeatures; /** @@ -4019,8 +4018,8 @@ PAL_API void PAL_CALL palDestroyImage(PalImage* image); * The graphics system must be initialized before this call. * This function also supports swapchain images. * - * @param[in] adapter Adapter to query information on. - * @param[out] info Pointer to a PalAdapterInfo to fill. + * @param[in] image Image to query information on. + * @param[out] info Pointer to a PalImageInfo to fill. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -4035,28 +4034,151 @@ PAL_API PalResult PAL_CALL palGetImageInfo( PalImage* image, PalImageInfo* info); +/** + * @brief Get memory requirements for the provided image. + * + * The graphics system must be initialized before this call. + * + * @param[in] image Image to query memory requirements on. + * @param[out] requirements Pointer to a PalMemoryRequirements to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `requirements` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( PalImage* image, PalMemoryRequirements* requirements); +/** + * @brief Bind an allocated GPU memory to an image. + * + * The graphics system must be initialized before this call. + * The memory size and alignment should match the requirements of the image. + * Get the requirements with palGetImageMemoryRequirements(). + * + * @param[in] image Image to bind memory to. + * @param[in] memory Memory to bind. Must not be nullptr. + * @param[in] offset Starting point within the memory. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `requirements` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palGetImageMemoryRequirements + */ PAL_API PalResult PAL_CALL palBindImageMemory( PalImage* image, PalMemory* memory, Uint64 offset); +/** + * @brief Create an image view. + * + * The graphics system must be initialized before this call. + * + * PalImageViewCreateInfo::type must be compatible by the type of the base image. Eg. A 2D base + * image must be have an image view of either `PAL_IMAGE_VIEW_TYPE_2D` or + * `PAL_IMAGE_VIEW_TYPE_2D_ARRAY`. + * + * `PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY` must be supported and enabled by the device + * used to create the image view if `PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY` will be used. + * + * @param[in] device Device to create image view on. + * @param[in] image Image to create the image view with. + * @param[in] info Pointer to a PalImageViewCreateInfo struct that specifies paramters. + * Must not be nullptr. + * @param[out] outImageView Pointer to a PalImageView to recieve the created image view. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyImageView + */ PAL_API PalResult PAL_CALL palCreateImageView( PalDevice* device, PalImage* image, const PalImageViewCreateInfo* info, PalImageView** outImageView); +/** + * @brief Destroy an image view. + * + * The graphics system must be initialized before this call. + * If the provided image view is invalid or nullptr, this function returns + * silently. + * + * @param[in] imageView Image view to destroy. + * + * Thread safety: Thread safe if the device used to create the image view is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateImageView + */ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); +/** + * @brief Get swapchain feature capabilites or limits about a device against a window. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to query swapchain feature capabilities on. + * @param[in] window Window to query swapchain feature capabilities against. + * @param[out] caps Pointer to a PalSwapchainCapabilities to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `caps` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( PalDevice* device, PalGraphicsWindow* window, PalSwapchainCapabilities* caps); +/** + * @brief Create a swaphain. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to create swapchain on. + * @param[in] queue Queue to create swapchain with. This must be a graphics queue. + * @param[in] window Window to create swapchain with. + * @param[in] info Pointer to a PalSwapchainCreateInfo struct that specifies paramters. + * Must not be nullptr. + * @param[out] outSwapchain Pointer to a PalSwapchain to recieve the created swapchain. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroySwapchain + */ PAL_API PalResult PAL_CALL palCreateSwapchain( PalDevice* device, PalQueue* queue, @@ -4064,47 +4186,296 @@ PAL_API PalResult PAL_CALL palCreateSwapchain( const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain); +/** + * @brief Destroy a swapchain. + * + * The graphics system must be initialized before this call. + * If the provided swapchain is invalid or nullptr, this function returns + * silently. + * + * @param[in] swapchain Swapchain to destroy. + * + * Thread safety: Thread safe if the device used to create the swapchain is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateSwapchain + */ PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); +/** + * @brief Get a swapchain image from the list of images with an index. + * + * The graphics system must be initialized before this call. + * + * @param[in] swapchain Swapchain to get image from. + * @param[in] index Index of image in the list. Must not be greater than the image count. + * + * @return A pointer to the image on success otherwise nullptr on failure. + * + * Thread safety: Thread safe. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palGetNextSwapchainImage + */ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, Int32 index); +/** + * @brief Get the next available image from the swapchain image list. + * + * The graphics system must be initialized before this call. + * + * @param[in] swapchain Swapchain to get image index from. + * @param[in] info Pointer to a PalSwapchainNextImageInfo struct that specifies paramters. + * Must not be nullptr. + * @param[out] outIndex Pointer to a Uint32 to recieve the next image index. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palGetSwapchainImage + */ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, Uint32* outIndex); +/** + * @brief Present the swapchain. + * + * The graphics system must be initialized before this call. + * + * @param[in] swapchain Swapchain to present. + * @param[in] info Pointer to a PalSwapchainPresentInfo struct that specifies paramters. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, PalSwapchainPresentInfo* info); +/** + * @brief Create a shader. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if + * `PAL_SHADER_STAGE_COMPUTE` will be used. + * + * `PAL_ADAPTER_FEATURE_GEOMETRY_SHADER` must be supported and enabled by the device if + * `PAL_SHADER_STAGE_GEOMETRY` will be used. + * + * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled by the device if + * `PAL_SHADER_STAGE_MESH` or `PAL_SHADER_STAGE_TASK` will be used. + * + * `PAL_ADAPTER_FEATURE_TESSELLATION_SHADER` must be supported and enabled by the device if + * `PAL_SHADER_STAGE_TESSELLATION_CONTROL` or `PAL_SHADER_STAGE_TESSELLATION_EVALUATION` will + * be used. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if + * `PAL_SHADER_STAGE_RAYGEN` or `PAL_SHADER_STAGE_CLOSEST_HIT` or `PAL_SHADER_STAGE_ANY_HIT` or + * `PAL_SHADER_STAGE_MISS` or `PAL_SHADER_STAGE_INTERSECTION` or `PAL_SHADER_STAGE_CALLABLE` will + * be used. + * + * @param[in] device Device to create shader on. + * @param[in] info Pointer to a PalShaderCreateInfo struct that specifies paramters. + * Must not be nullptr. + * @param[out] outShader Pointer to a PalShader to recieve the created shader. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyShader + */ PAL_API PalResult PAL_CALL palCreateShader( PalDevice* device, const PalShaderCreateInfo* info, PalShader** outShader); +/** + * @brief Destroy a shader. + * + * The graphics system must be initialized before this call. + * If the provided shader is invalid or nullptr, this function returns + * silently. + * + * @param[in] shader Shader to destroy. + * + * Thread safety: Thread safe if the device used to create the shader is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateShader + */ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); +/** + * @brief Create a fence. + * + * The graphics system must be initialized before this call. + * + * @param[in] device Device to create fence on. + * @param[in] signaled True if fence should be created signaled. If true, the fence must be reset + * before waiting for it to prevent waiting forever. + * @param[out] outFence Pointer to a PalFence to recieve the created fence. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyFence + */ PAL_API PalResult PAL_CALL palCreateFence( PalDevice* device, bool signaled, PalFence** outFence); +/** + * @brief Destroy a fence. + * + * The graphics system must be initialized before this call. + * If the provided fence is invalid or nullptr, this function returns + * silently. + * + * @param[in] fence Fence to destroy. + * + * Thread safety: Thread safe if the device used to create the fence is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateFence + */ PAL_API void PAL_CALL palDestroyFence(PalFence* fence); +/** + * @brief Wait for a fence. + * + * The graphics system must be initialized before this call. + * + * This function blocks for `timeout` until the fence is signaled or there is a timeout. + * Returns `PAL_RESULT_SUCCESS` or `PAL_RESULT_TIMEOUT` respectively. + * + * @param[in] fence Fence to wait for. + * @param[in] timeout Time to wait for in milliseconds. Set to `PAL_INFINITE` for indefintely. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `fence` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palIsFenceSignaled + */ PAL_API PalResult PAL_CALL palWaitFence( PalFence* fence, Uint64 timeout); +/** + * @brief Reset a fence to an unsignaled state. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_FENCE_RESET` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] fence Fence to reset. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `fence` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palIsFenceSignaled + */ PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); +/** + * @brief Checks if the provided fence is in a signaled state. + * + * The graphics system must be initialized before this call. + * + * @param[in] fence Fence to check. + * + * @return True if signaled otherwise false. + * + * Thread safety: Thread safe. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palResetFence + * @sa palWaitFence + */ PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); +/** + * @brief Create a semaphore. + * + * The graphics system must be initialized before this call. + * + * A binary semaphore is created by default. To create a timeline + * semaphore, enable `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` when creating the device. + * The feature must be supported by the device if not, this function will fail and return + * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to create semaphore on. + * @param[out] outSemaphore Pointer to a PalSemaphore to recieve the created semaphore. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroySemaphore + */ PAL_API PalResult PAL_CALL palCreateSemaphore( PalDevice* device, PalSemaphore** outSemaphore); +/** + * @brief Destroy a semaphore. + * + * The graphics system must be initialized before this call. + * If the provided semaphore is invalid or nullptr, this function returns + * silently. + * + * @param[in] semaphore Semaphore to destroy. + * + * Thread safety: Thread safe if the device used to create the semaphore is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateSemaphore + */ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); PAL_API PalResult PAL_CALL palWaitSemaphore( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index da565e69..e06bdc25 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3318,7 +3318,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; adapterFeatures |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; - adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_TIMEOUT; adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; palFree(s_Vk.allocator, extensionProps); diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 3adb4b8e..2c56dd71 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -248,10 +248,6 @@ bool graphicsTest() palLog(nullptr, " Resetting fence"); } - if (features & PAL_ADAPTER_FEATURE_FENCE_TIMEOUT) { - palLog(nullptr, " Timeout fence"); - } - if (features & PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE) { palLog(nullptr, " Polygon mode line"); } From 8897ccd91e0b9d78f47e3a2f2046ecdf8f4b384e Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 12 Mar 2026 14:58:51 +0000 Subject: [PATCH 100/372] allow control on stride for draw indirect commands --- include/pal/pal_event.h | 2 +- include/pal/pal_graphics.h | 725 ++++++++++++++++++++++++++++++++++-- include/pal/pal_opengl.h | 2 +- include/pal/pal_thread.h | 2 +- include/pal/pal_video.h | 8 +- src/graphics/pal_graphics.c | 87 +++-- src/graphics/pal_vulkan.c | 64 ++-- 7 files changed, 791 insertions(+), 99 deletions(-) diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index bc1b9a9d..ad059f08 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -442,7 +442,7 @@ typedef struct { * longer needed. * * @param[in] info Pointer to a PalEventDriverCreateInfo struct that specifies - * paramters. Must not be nullptr. + * parameters. Must not be nullptr. * @param[out] outEventDriver Pointer to a PalEventDriver to recieve the created * event driver. Must not be nullptr. * diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 31e479a0..d0087760 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1649,8 +1649,8 @@ typedef struct { } PalWorkGroupInfo; /** - * @struct PalDrawData - * @brief Draw data of a single draw call. + * @struct PalDrawIndirectData + * @brief Draw indirect data of a single draw call. * * Uninitialized fields may result in undefined behavior. * @@ -1662,11 +1662,11 @@ typedef struct { Uint32 instanceCount; /**< Number of instances to draw. Set to 1 if not using instanced draw.*/ Uint32 firstVertex; /**< First vertex. Set to 0 for default behavior.*/ Uint32 firstInstance; /**< First instance. Set to 0 for default behavior.*/ -} PalDrawData; +} PalDrawIndirectData; /** - * @struct PalDrawData - * @brief Draw indexed data of a single draw call. + * @struct PalDrawIndexedIndirectData + * @brief Draw indexed indirect data of a single draw call. * * Uninitialized fields may result in undefined behavior. * @@ -1679,7 +1679,22 @@ typedef struct { Uint32 firstIndex; /**< First index. Set to 0 for default behavior.*/ Int32 vertexOffset; /**< Vertex offset. Set to 0 for default behavior.*/ Uint32 firstInstance; /**< First instance. Set to 0 for default behavior.*/ -} PalDrawIndexedData; +} PalDrawIndexedIndirectData; + +/** + * @struct PalDispatchIndirectData + * @brief Draw or dispatch indirect data of a single dispatch call. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 groupCountX; /**< Number of groups on the x axis.*/ + Uint32 groupCountY; /**< Number of groups on the y axis.*/ + Uint32 groupCountZ; /**< Number of groups on the z axis.*/ +} PalDispatchIndirectData; /** * @struct PalVertexAttribute @@ -1933,6 +1948,7 @@ typedef struct { PalAccelerationStructureType type; /**< (eg. PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL).*/ Uint32 geometryCount; PalAccelerationStructure* dst; + PalAccelerationStructure* src; PalDeviceAddress scratchBufferAddress; PalGeometry* geometries; } PalAccelerationStructureBuildInfo; @@ -2655,11 +2671,11 @@ typedef struct { void PAL_CALL (*destroyFence)(PalFence* fence); /** - * Backend implementation of ::palWaitFenceTimeout. + * Backend implementation of ::palWaitFence. * - * Must obey the rules and semantics documented in palWaitFenceTimeout(). + * Must obey the rules and semantics documented in palWaitFence(). */ - PalResult PAL_CALL (*waitFenceTimeout)( + PalResult PAL_CALL (*waitFence)( PalFence* fence, Uint64 timeout); @@ -2700,7 +2716,6 @@ typedef struct { */ PalResult PAL_CALL (*waitSemaphore)( PalSemaphore* semaphore, - PalQueue* queue, Uint64 value, Uint64 timeout); @@ -2940,7 +2955,10 @@ typedef struct { */ PalResult PAL_CALL (*cmdDraw)( PalCommandBuffer* cmdBuffer, - PalDrawData* data); + Uint32 vertexCount, + Uint32 instanceCount, + Uint32 firstVertex, + Uint32 firstInstance); /** * Backend implementation of ::palCmdDrawIndirect. @@ -2951,7 +2969,8 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - Uint32 count); + Uint32 count, + Uint32 stride); /** * Backend implementation of ::palCmdDrawIndirectCount. @@ -2964,7 +2983,8 @@ typedef struct { PalBuffer* countBuffer, Uint64 offset, Uint64 countBufferOffset, - Uint32 count); + Uint32 count, + Uint32 stride); /** * Backend implementation of ::palCmdDrawIndexed. @@ -2973,7 +2993,11 @@ typedef struct { */ PalResult PAL_CALL (*cmdDrawIndexed)( PalCommandBuffer* cmdBuffer, - PalDrawIndexedData* data); + Uint32 indexCount, + Uint32 instanceCount, + Uint32 firstIndex, + Int32 vertexOffset, + Uint32 firstInstance); /** * Backend implementation of ::palCmdDrawIndexedIndirect. @@ -2984,7 +3008,8 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - Uint32 count); + Uint32 count, + Uint32 stride); /** * Backend implementation of ::palCmdDrawIndexedIndirectCount. @@ -2997,7 +3022,8 @@ typedef struct { PalBuffer* countBuffer, Uint64 offset, Uint64 countBufferOffset, - Uint32 count); + Uint32 count, + Uint32 stride); /** * Backend implementation of ::palCmdMemoryBarrier. @@ -3554,7 +3580,7 @@ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -3799,7 +3825,7 @@ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -3976,14 +4002,14 @@ PAL_API PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( * adapter capabilities for the limits. * * @param[in] device Device to create image on. - * @param[in] info Pointer to a PalImageCreateInfo struct that specifies paramters. + * @param[in] info Pointer to a PalImageCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outImage Pointer to a PalImage to recieve the created image. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4093,14 +4119,14 @@ PAL_API PalResult PAL_CALL palBindImageMemory( * * @param[in] device Device to create image view on. * @param[in] image Image to create the image view with. - * @param[in] info Pointer to a PalImageViewCreateInfo struct that specifies paramters. + * @param[in] info Pointer to a PalImageViewCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outImageView Pointer to a PalImageView to recieve the created image view. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4166,14 +4192,14 @@ PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( * @param[in] device Device to create swapchain on. * @param[in] queue Queue to create swapchain with. This must be a graphics queue. * @param[in] window Window to create swapchain with. - * @param[in] info Pointer to a PalSwapchainCreateInfo struct that specifies paramters. + * @param[in] info Pointer to a PalSwapchainCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outSwapchain Pointer to a PalSwapchain to recieve the created swapchain. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4230,7 +4256,7 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( * The graphics system must be initialized before this call. * * @param[in] swapchain Swapchain to get image index from. - * @param[in] info Pointer to a PalSwapchainNextImageInfo struct that specifies paramters. + * @param[in] info Pointer to a PalSwapchainNextImageInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outIndex Pointer to a Uint32 to recieve the next image index. * @@ -4254,7 +4280,7 @@ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( * The graphics system must be initialized before this call. * * @param[in] swapchain Swapchain to present. - * @param[in] info Pointer to a PalSwapchainPresentInfo struct that specifies paramters. + * @param[in] info Pointer to a PalSwapchainPresentInfo struct that specifies parameters. * Must not be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4293,14 +4319,14 @@ PAL_API PalResult PAL_CALL palPresentSwapchain( * be used. * * @param[in] device Device to create shader on. - * @param[in] info Pointer to a PalShaderCreateInfo struct that specifies paramters. + * @param[in] info Pointer to a PalShaderCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outShader Pointer to a PalShader to recieve the created shader. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4342,7 +4368,7 @@ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4450,7 +4476,7 @@ PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4478,60 +4504,340 @@ PAL_API PalResult PAL_CALL palCreateSemaphore( */ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); +/** + * @brief Waits for a semaphore to reach the provided value. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] semaphore Semaphore to wait on. + * @param[in] value Value to wait for. + * @param[in] timeout Time to wait for in milliseconds. Set to `PAL_INFINITE` for indefintely. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `semaphore` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palSignalSemaphore + * @sa palGetSemaphoreValue + */ PAL_API PalResult PAL_CALL palWaitSemaphore( PalSemaphore* semaphore, - PalQueue* queue, Uint64 value, Uint64 timeout); +/** + * @brief Signals a semaphore from the provided value. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] semaphore Semaphore to signal. + * @param[in] queue Queue used to signal the semaphore. + * @param[in] value Value to signal. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `queue` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palWaitSemaphore + * @sa palGetSemaphoreValue + */ PAL_API PalResult PAL_CALL palSignalSemaphore( PalSemaphore* semaphore, PalQueue* queue, Uint64 value); +/** + * @brief Get the value of a semaphore. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] semaphore Semaphore to get its value. + * @param[out] value Pointer to a Uint64 to receive the semaphore value. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `semaphore` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palWaitSemaphore + * @sa palSignalSemaphore + */ PAL_API PalResult PAL_CALL palGetSemaphoreValue( PalSemaphore* semaphore, Uint64* value); +/** + * @brief Create a command pool from a device. + * + * The graphics system must be initialized before this call. + * + * @param[in] device Device to create command pool on. + * @param[in] queue Queue the command pool buffers will be submitted to. + * @param[out] outPool Pointer to a PalCommandPool to recieve the created command pool. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyCommandPool + */ PAL_API PalResult PAL_CALL palCreateCommandPool( PalDevice* device, PalQueue* queue, PalCommandPool** outPool); +/** + * @brief Destroy a command pool. + * + * The graphics system must be initialized before this call. + * If the provided command pool is invalid or nullptr, this function returns + * silently. All command buffers allocated from the command pool must be freed before this + * function. + * + * @param[in] pool Command pool to destroy. + * + * Thread safety: Thread safe if the device used to create the command pool is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateCommandPool + */ PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); +/** + * @brief Reset all command buffers allocated from the provided command pool. + * + * The graphics system must be initialized before this call. + * + * @param[in] pool Command pool to reset its command buffers. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `pool` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); +/** + * @brief Allocate a command buffer from the provided command pool. + * + * The graphics system must be initialized before this call. + * + * @param[in] device Device to allocate command buffer on. + * @param[in] pool Command pool to allocate command buffer on. + * @param[in] type Type of the command buffer (eg. PAL_COMMAND_BUFFER_TYPE_PRIMARY). + * @param[out] outCmdBuffer Pointer to a PalCommandBuffer to recieve the created command buffer. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` and `pool` are externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palFreeCommandBuffer + */ PAL_API PalResult PAL_CALL palAllocateCommandBuffer( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, PalCommandBuffer** outCmdbuffer); +/** + * @brief Free an allocated command buffer. + * + * The graphics system must be initialized before this call. + * If the provided command buffer is invalid or nullptr, this function returns + * silently. + * + * @param[in] cmdBuffer Command buffer to free. + * + * Thread safety: Thread safe if the command pool used to create the command buffer is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palAllocateCommandBuffer + */ PAL_API void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer); +/** + * @brief Reset the provided command buffer. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer to reset. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); +/** + * @brief Begin recording commands to the provided command buffer. + * + * The graphics system must be initialized before this call. This function must be called + * before any other `palCmd**` function is used. + * + * @param[in] cmdBuffer Command buffer to begin recording. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCmdEnd + */ PAL_API PalResult PAL_CALL palCmdBegin( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); +/** + * @brief End recording commands to the provided command buffer. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer to begin recording. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCmdBegin + */ PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); +/** + * @brief Execute a secondary command buffer within a primary command buffer. + * + * The graphics system must be initialized before this call. The `secondaryCmdBuffer` must + * be created with the type `PAL_COMMAND_BUFFER_TYPE_SECONDARY`. + * + * @param[in] primaryCmdBuffer Primary command buffer. Must be in recording state. + * @param[in] secondaryCmdBuffer Secondary command buffer. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `primaryCmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); +/** + * @brief Set the fragment shading rate used for draw calls. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] state Pointer to a PalFragmentShadingRateState struct that specifies parameters. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state); +/** + * @brief Dispatch mesh shader workgroups. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] groupCountX Number of mesh shader groups to dispatch on the x axis. + * @param[in] groupCountY Number of mesh shader groups to dispatch on the y axis. + * @param[in] groupCountZ Number of mesh shader groups to dispatch on the z axis. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, Uint32 groupCountZ); +/** + * @brief Dispatch mesh shader workgroups using parameters from a buffer. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported + * and enabled by the device if not, this function will fail and return + * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. + * Can be a single struct. + * @param[in] offset Starting byte offset into `buffer`. + * @param[in] drawCount Number of draws to perform. + * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * Must be greater or equal to sizeof(PalDispatchIndirectData). + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, @@ -4539,6 +4845,33 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( Uint32 drawCount, Uint32 stride); +/** + * @brief Dispatch mesh shader workgroups using parameters from buffers. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be + * supported and enabled by the device if not, this function will fail and return + * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. + * Can be a single struct. + * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. + * @param[in] offset Starting byte offset into `buffer`. + * @param[in] countBufferOffset Starting byte offset into `countBuffer`. + * @param[in] maxDrawCount Maximum Number of draws to perform. + * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * Must be greater or equal to sizeof(PalDispatchIndirectData). + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, @@ -4548,16 +4881,88 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( Uint32 maxDrawCount, Uint32 stride); +/** + * @brief Build or update an acceleration structure. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] info Pointer to a PalAccelerationStructureBuildInfo struct that specifies parameters. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); +/** + * @brief Begin a rendering pass. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] info Pointer to a PalRenderingInfo struct that specifies parameters. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdBeginRendering( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info); +/** + * @brief End a rendering pass. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); +/** + * @brief Copy data from one buffer to the other. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] dst Destination buffer. + * @param[in] src Source buffer. + * @param[in] dstOffset Starting byte offset in the destination buffer. + * @param[in] srcOffset Starting byte offset in the source buffer. + * @param[in] size Size in bytes to copy from the source buffer. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdCopyBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dst, @@ -4566,20 +4971,92 @@ PAL_API PalResult PAL_CALL palCmdCopyBuffer( Uint64 srcOffset, Uint32 size); +/** + * @brief Bind a pipeline. + * + * The graphics system must be initialized before this call. Every pipeline knows it types which is + * set at the respective creation functions. (`palCreate**Graphics/Compute/RayTracing**Pipeline`). + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] pipeline Pipeline to bind. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline); +/** + * @brief Set the viewport(s) used in draw commands. + * + * The graphics system must be initialized before this call. This always overwrites any previous + * viewports that were set since the first viewport index is always 0. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] count Number of viewports in the array. + * @param[in] viewports Pointer to an array of viewports. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdSetViewport( PalCommandBuffer* cmdBuffer, Uint32 count, PalViewport* viewports); +/** + * @brief Set the scissor(s) used in draw commands. + * + * The graphics system must be initialized before this call. This always overwrites any previous + * scissors that were set since the first scissor index is always 0. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] count Number of scissors in the array. + * @param[in] scissors Pointer to an array of scissors. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdSetScissors( PalCommandBuffer* cmdBuffer, Uint32 count, PalRect2D* scissors); +/** + * @brief Bind vertex buffer(s) used in draw commands. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] firstSlot Index of the first vertex buffer binding slot. + * @param[in] count Number of vertex buffers to bind. + * @param[in] buffers Pointer to an array of vertex buffers. + * @param[in] offsets Pointer to an array of offsets in bytes into each vertex buffer. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, @@ -4587,47 +5064,221 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( PalBuffer** buffers, Uint64* offsets); +/** + * @brief Bind index buffer used in draw commands. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] buffer Index buffer to bind. + * @param[in] offset Offset in bytes into the index buffer. + * @param[in] type Type of indices stored in the index buffer. (eg. `PAL_INDEX_TYPE_UINT32`). + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, PalIndexType type); +/** + * @brief Issue a non-indexed draw command. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] vertexCount Number of vertices to draw. + * @param[in] instanceCount Number of instances to draw. + * @param[in] firstVertex Index of the first vertex to draw. + * @param[in] firstInstance Index of the first instance to draw. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDrawIndexed + */ PAL_API PalResult PAL_CALL palCmdDraw( PalCommandBuffer* cmdBuffer, - PalDrawData* data); + Uint32 vertexCount, + Uint32 instanceCount, + Uint32 firstVertex, + Uint32 firstInstance); +/** + * @brief Issue a non-indexed draw command using buffers. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. + * Can be a single struct. + * @param[in] offset Starting byte offset into `buffer`. + * @param[in] count Number of draws to perform. + * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * Must be greater or equal to sizeof(PalDrawIndirectData). + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDrawIndexedIndirect + */ PAL_API PalResult PAL_CALL palCmdDrawIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - Uint32 count); + Uint32 count, + Uint32 stride); +/** + * @brief Issue a non-indexed draw command using buffers. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. + * Can be a single struct. + * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. + * @param[in] offset Starting byte offset into `buffer`. + * @param[in] countBufferOffset Starting byte offset into `countBuffer`. + * @param[in] maxDrawCount Maximum Number of draws to perform. + * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * Must be greater or equal to sizeof(PalDrawIndirectData). + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCmdDrawIndexedIndirectCount + */ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, Uint64 offset, Uint64 countBufferOffset, - Uint32 count); + Uint32 maxDrawCount, + Uint32 stride); +/** + * @brief Issue an indexed draw command. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] indexCount Number of indices to draw. + * @param[in] instanceCount Number of instances to draw. + * @param[in] firstIndex Index of the first index to draw. + * @param[in] vertexOffset Added offset to vertex indices. + * @param[in] firstInstance Index of the first instance to draw. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDraw + */ PAL_API PalResult PAL_CALL palCmdDrawIndexed( PalCommandBuffer* cmdBuffer, - PalDrawIndexedData* data); + Uint32 indexCount, + Uint32 instanceCount, + Uint32 firstIndex, + Int32 vertexOffset, + Uint32 firstInstance); +/** + * @brief Issue an indexed draw command using buffers. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. + * Can be a single struct. + * @param[in] offset Starting byte offset into `buffer`. + * @param[in] count Number of draws to perform. + * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * Must be greater or equal to sizeof(PalDrawIndexedIndirectData). + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDrawIndirect + */ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - Uint32 count); + Uint32 count, + Uint32 stride); +/** + * @brief Issue an indexed draw command using buffers. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. + * Can be a single struct. + * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. + * @param[in] offset Starting byte offset into `buffer`. + * @param[in] countBufferOffset Starting byte offset into `countBuffer`. + * @param[in] maxDrawCount Maximum Number of draws to perform. + * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * Must be greater or equal to sizeof(PalDrawIndexedIndirectData). + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCmdDrawIndirectCount + */ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, Uint64 offset, Uint64 countBufferOffset, - Uint32 count); + Uint32 maxDrawCount, + Uint32 stride); PAL_API PalResult PAL_CALL palCmdMemoryBarrier( PalCommandBuffer* cmdBuffer, diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 130ca822..fc986d87 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -322,7 +322,7 @@ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( * not the wl_surface. * * @param[in] info Pointer to a PalGLContextCreateInfo struct that specifies - * paramters. Must not be nullptr. + * parameters. Must not be nullptr. * @param[out] outContext Pointer to a PalGLContext to recieve the created * context. Must not be nullptr. * diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index bac13df7..a50ec654 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -157,7 +157,7 @@ typedef struct { * until the entry function has finished executing or its detached. * * @param[in] info Pointer to a PalThreadCreateInfo struct that specifies - * paramters. Must not be nullptr. + * parameters. Must not be nullptr. * @param[out] outThread Pointer to a PalThread to recieve the created * thread. Must not be nullptr. * diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index a6ed75fb..8d51abd8 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -1027,7 +1027,7 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * The video system must be initialized before this call. * * @param[in] info Pointer to a PalWindowCreateInfo struct that specifies - * paramters. Must not be nullptr. + * parameters. Must not be nullptr. * @param[out] outWindow Pointer to a PalWindow to recieve the created * window. Must not be nullptr. * @@ -1187,7 +1187,7 @@ PAL_API PalResult PAL_CALL palHideWindow(PalWindow* window); * supported. * * @param[in] window Pointer to the window. - * @param[in] info Pointer to a PalFlashInfo struct with flash paramters. + * @param[in] info Pointer to a PalFlashInfo struct with flash parameters. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1671,7 +1671,7 @@ PAL_API PalResult PAL_CALL palSetFocusWindow(PalWindow* window); * `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported. * * @param[in] info Pointer to a PalIconCreateInfo struct that specifies - * paramters. Must not be nullptr. + * parameters. Must not be nullptr. * @param[out] outIcon Pointer to a PalIcon to recieve the created * icon. Must not be nullptr. * @@ -1733,7 +1733,7 @@ PAL_API PalResult PAL_CALL palSetWindowIcon( * The video system must be initialized before this call. * * @param[in] info Pointer to a PalCursorCreateInfo struct that specifies - * paramters. Must not be nullptr. + * parameters. Must not be nullptr. * @param[out] outCursor Pointer to a PalCursor to recieve the created * cursor. Must not be nullptr. * diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 78ab6fd6..5f4a1d49 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -272,7 +272,6 @@ void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore); PalResult PAL_CALL waitSemaphoreVk( PalSemaphore* semaphore, - PalQueue* queue, Uint64 value, Uint64 timeout); @@ -387,13 +386,17 @@ PalResult PAL_CALL cmdBindIndexBufferVk( PalResult PAL_CALL cmdDrawVk( PalCommandBuffer* cmdBuffer, - PalDrawData* data); + Uint32 vertexCount, + Uint32 instanceCount, + Uint32 firstVertex, + Uint32 firstInstance); PalResult PAL_CALL cmdDrawIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - Uint32 count); + Uint32 count, + Uint32 stride); PalResult PAL_CALL cmdDrawIndirectCountVk( PalCommandBuffer* cmdBuffer, @@ -401,17 +404,23 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( PalBuffer* countBuffer, Uint64 offset, Uint64 countBufferOffset, - Uint32 count); + Uint32 maxDrawCount, + Uint32 stride); PalResult PAL_CALL cmdDrawIndexedVk( PalCommandBuffer* cmdBuffer, - PalDrawIndexedData* data); + Uint32 indexCount, + Uint32 instanceCount, + Uint32 firstIndex, + Int32 vertexOffset, + Uint32 firstInstance); PalResult PAL_CALL cmdDrawIndexedIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - Uint32 count); + Uint32 count, + Uint32 stride); PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( PalCommandBuffer* cmdBuffer, @@ -419,7 +428,8 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( PalBuffer* countBuffer, Uint64 offset, Uint64 countBufferOffset, - Uint32 count); + Uint32 maxDrawCount, + Uint32 stride); PalResult PAL_CALL cmdMemoryBarrierVk( PalCommandBuffer* cmdBuffer, @@ -656,7 +666,7 @@ static PalGraphicsBackend s_VkBackend = { // fence .createFence = createFenceVk, .destroyFence = destroyFenceVk, - .waitFenceTimeout = waitFenceVk, + .waitFence = waitFenceVk, .resetFence = resetFenceVk, .isFenceSignaled = isFenceSignaledVk, @@ -839,7 +849,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) // fence !backend->createFence || !backend->destroyFence || - !backend->waitFenceTimeout || + !backend->waitFence || !backend->resetFence || !backend->isFenceSignaled || @@ -1670,7 +1680,7 @@ PalResult PAL_CALL palWaitFence( return PAL_RESULT_NULL_POINTER; } - return fence->backend->waitFenceTimeout(fence, timeout); + return fence->backend->waitFence(fence, timeout); } PalResult PAL_CALL palResetFence(PalFence* fence) @@ -1731,7 +1741,6 @@ void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore) PalResult PAL_CALL palWaitSemaphore( PalSemaphore* semaphore, - PalQueue* queue, Uint64 value, Uint64 timeout) { @@ -1739,11 +1748,11 @@ PalResult PAL_CALL palWaitSemaphore( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!semaphore || !queue) { + if (!semaphore) { return PAL_RESULT_NULL_POINTER; } - return semaphore->backend->waitSemaphore(semaphore, queue, value, timeout); + return semaphore->backend->waitSemaphore(semaphore, value, timeout); } PalResult PAL_CALL palSignalSemaphore( @@ -2170,24 +2179,33 @@ PalResult PAL_CALL palCmdBindIndexBuffer( PalResult PAL_CALL palCmdDraw( PalCommandBuffer* cmdBuffer, - PalDrawData* data) + Uint32 vertexCount, + Uint32 instanceCount, + Uint32 firstVertex, + Uint32 firstInstance) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !data) { + if (!cmdBuffer) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdDraw(cmdBuffer, data); + return cmdBuffer->backend->cmdDraw( + cmdBuffer, + vertexCount, + instanceCount, + firstVertex, + firstInstance); } PalResult PAL_CALL palCmdDrawIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - Uint32 count) + Uint32 count, + Uint32 stride) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2197,7 +2215,7 @@ PalResult PAL_CALL palCmdDrawIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdDrawIndirect(cmdBuffer, buffer, offset, count); + return cmdBuffer->backend->cmdDrawIndirect(cmdBuffer, buffer, offset, count, stride); } PalResult PAL_CALL palCmdDrawIndirectCount( @@ -2206,7 +2224,8 @@ PalResult PAL_CALL palCmdDrawIndirectCount( PalBuffer* countBuffer, Uint64 offset, Uint64 countBufferOffset, - Uint32 count) + Uint32 maxDrawCount, + Uint32 stride) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2222,29 +2241,41 @@ PalResult PAL_CALL palCmdDrawIndirectCount( countBuffer, offset, countBufferOffset, - count); + maxDrawCount, + stride); } PalResult PAL_CALL palCmdDrawIndexed( PalCommandBuffer* cmdBuffer, - PalDrawIndexedData* data) + Uint32 indexCount, + Uint32 instanceCount, + Uint32 firstIndex, + Int32 vertexOffset, + Uint32 firstInstance) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !data) { + if (!cmdBuffer) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdDrawIndexed(cmdBuffer, data); + return cmdBuffer->backend->cmdDrawIndexed( + cmdBuffer, + indexCount, + instanceCount, + firstIndex, + vertexOffset, + firstInstance); } PalResult PAL_CALL palCmdDrawIndexedIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - Uint32 count) + Uint32 count, + Uint32 stride) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2254,7 +2285,7 @@ PalResult PAL_CALL palCmdDrawIndexedIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdDrawIndexedIndirect(cmdBuffer, buffer, offset, count); + return cmdBuffer->backend->cmdDrawIndexedIndirect(cmdBuffer, buffer, offset, count, stride); } PalResult PAL_CALL palCmdDrawIndexedIndirectCount( @@ -2263,7 +2294,8 @@ PalResult PAL_CALL palCmdDrawIndexedIndirectCount( PalBuffer* countBuffer, Uint64 offset, Uint64 countBufferOffset, - Uint32 count) + Uint32 maxDrawCount, + Uint32 stride) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2279,7 +2311,8 @@ PalResult PAL_CALL palCmdDrawIndexedIndirectCount( countBuffer, offset, countBufferOffset, - count); + maxDrawCount, + stride); } PalResult PAL_CALL palCmdMemoryBarrier( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e06bdc25..25c17b22 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -5317,7 +5317,6 @@ void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore) PalResult PAL_CALL waitSemaphoreVk( PalSemaphore* semaphore, - PalQueue* queue, Uint64 value, Uint64 timeout) { @@ -5733,6 +5732,10 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + Buffer* vkBuffer = (Buffer*)buffer; vkCmdBuffer->device ->cmdDrawMeshTaskIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset, drawCount, stride); @@ -5750,6 +5753,10 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( Uint32 stride) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6172,15 +6179,18 @@ PalResult PAL_CALL cmdBindIndexBufferVk( PalResult PAL_CALL cmdDrawVk( PalCommandBuffer* cmdBuffer, - PalDrawData* data) + Uint32 vertexCount, + Uint32 instanceCount, + Uint32 firstVertex, + Uint32 firstInstance) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.cmdDraw( vkCmdBuffer->handle, - data->vertexCount, - data->instanceCount, - data->firstVertex, - data->firstInstance); + vertexCount, + instanceCount, + firstVertex, + firstInstance); return PAL_RESULT_SUCCESS; } @@ -6189,14 +6199,12 @@ PalResult PAL_CALL cmdDrawIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - Uint32 count) + Uint32 count, + Uint32 stride) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; - Uint32 stride = sizeof(VkDrawIndirectCommand); - s_Vk.cmdDrawIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset, count, stride); - return PAL_RESULT_SUCCESS; } @@ -6206,13 +6214,12 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( PalBuffer* countBuffer, Uint64 offset, Uint64 countBufferOffset, - Uint32 count) + Uint32 maxDrawCount, + Uint32 stride) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; Buffer* vkCountBuffer = (Buffer*)countBuffer; - Uint32 stride = sizeof(VkDrawIndirectCommand); - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6223,7 +6230,7 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( offset, vkCountBuffer->handle, countBufferOffset, - count, + maxDrawCount, stride); return PAL_RESULT_SUCCESS; @@ -6231,16 +6238,20 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( PalResult PAL_CALL cmdDrawIndexedVk( PalCommandBuffer* cmdBuffer, - PalDrawIndexedData* data) + Uint32 indexCount, + Uint32 instanceCount, + Uint32 firstIndex, + Int32 vertexOffset, + Uint32 firstInstance) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.cmdDrawIndexed( vkCmdBuffer->handle, - data->indexCount, - data->instanceCount, - data->firstIndex, - data->vertexOffset, - data->firstInstance); + indexCount, + instanceCount, + firstIndex, + vertexOffset, + firstInstance); return PAL_RESULT_SUCCESS; } @@ -6249,14 +6260,12 @@ PalResult PAL_CALL cmdDrawIndexedIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - Uint32 count) + Uint32 count, + Uint32 stride) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; - Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); - s_Vk.cmdDrawIndexedIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset, count, stride); - return PAL_RESULT_SUCCESS; } @@ -6266,13 +6275,12 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( PalBuffer* countBuffer, Uint64 offset, Uint64 countBufferOffset, - Uint32 count) + Uint32 maxDrawCount, + Uint32 stride) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; Buffer* vkCountBuffer = (Buffer*)countBuffer; - Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6283,7 +6291,7 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( offset, vkCountBuffer->handle, countBufferOffset, - count, + maxDrawCount, stride); return PAL_RESULT_SUCCESS; From 86bb20a75e25500d7d8692561e9002ab87eec902 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 17 Mar 2026 14:06:35 +0000 Subject: [PATCH 101/372] finish initial graphics system docs --- include/pal/pal_graphics.h | 780 ++++++++++++++++++++++++++++++++++-- include/pal/pal_opengl.h | 2 +- include/pal/pal_video.h | 4 +- src/graphics/pal_graphics.c | 10 +- 4 files changed, 765 insertions(+), 31 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d0087760..dbb36955 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1691,9 +1691,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 groupCountX; /**< Number of groups on the x axis.*/ - Uint32 groupCountY; /**< Number of groups on the y axis.*/ - Uint32 groupCountZ; /**< Number of groups on the z axis.*/ + Uint32 groupCountXOrWidth; /**< Number of groups on the x axis or width.*/ + Uint32 groupCountXOrHeight; /**< Number of groups on the y axis or height.*/ + Uint32 groupCountXOrDepth; /**< Number of groups on the z axis or depth.*/ } PalDispatchIndirectData; /** @@ -3448,7 +3448,7 @@ PAL_API void PAL_CALL palShutdownGraphics(); * graphics system. Users are required to cache this, and call this function again * if adapters are added or removed which is rare except for virtual ones. * - * @param[in] count Capacity of the PalAdapter array. + * @param[in, out] count Capacity of the PalAdapter array. * @param[out] outAdapters User allocated array of PalAdapter. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -3532,7 +3532,7 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); * the supported features of the adapter that can be enabled. Using a feature which is not * supported will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * - * @param[in] adapter Adapter to create the device with. + * @param[in] adapter Adapter that creates the device. * @param[in] features Adapter features to enable. Must be supported. * @param[out] outDevice Pointer to a PalDevice to recieve the created device. Must not be nullptr. * @@ -3580,7 +3580,7 @@ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -3818,7 +3818,7 @@ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( * * On most adapters, compute and graphics queues can also do copy operations. * - * @param[in] device Device to create queue on. + * @param[in] device Device that creates the queue. * @param[in] type Queue type. (eg. PAL_QUEUE_TYPE_GRAPHICS). * @param[out] outQueue Pointer to a PalQueue to recieve the created queue. * @@ -3911,7 +3911,7 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. * * @param[in] adapter Adapter to query formats on. - * @param[in] count Capacity of the PalFormatInfo array. + * @param[in, out] count Capacity of the PalFormatInfo array. * @param[out] outFormats User allocated array of PalFormatInfo. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4001,7 +4001,7 @@ PAL_API PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( * must not be greater than the limits of the adapter used to create the device. Check * adapter capabilities for the limits. * - * @param[in] device Device to create image on. + * @param[in] device Device that creates the image. * @param[in] info Pointer to a PalImageCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outImage Pointer to a PalImage to recieve the created image. @@ -4009,7 +4009,7 @@ PAL_API PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4081,7 +4081,7 @@ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( PalMemoryRequirements* requirements); /** - * @brief Bind an allocated GPU memory to an image. + * @brief Bind an allocated memory to an image. * * The graphics system must be initialized before this call. * The memory size and alignment should match the requirements of the image. @@ -4117,7 +4117,7 @@ PAL_API PalResult PAL_CALL palBindImageMemory( * `PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY` must be supported and enabled by the device * used to create the image view if `PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY` will be used. * - * @param[in] device Device to create image view on. + * @param[in] device Device that creates the image view. * @param[in] image Image to create the image view with. * @param[in] info Pointer to a PalImageViewCreateInfo struct that specifies parameters. * Must not be nullptr. @@ -4126,7 +4126,7 @@ PAL_API PalResult PAL_CALL palBindImageMemory( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4189,7 +4189,7 @@ PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * - * @param[in] device Device to create swapchain on. + * @param[in] device Device that creates the swapchain. * @param[in] queue Queue to create swapchain with. This must be a graphics queue. * @param[in] window Window to create swapchain with. * @param[in] info Pointer to a PalSwapchainCreateInfo struct that specifies parameters. @@ -4199,7 +4199,7 @@ PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4318,7 +4318,7 @@ PAL_API PalResult PAL_CALL palPresentSwapchain( * `PAL_SHADER_STAGE_MISS` or `PAL_SHADER_STAGE_INTERSECTION` or `PAL_SHADER_STAGE_CALLABLE` will * be used. * - * @param[in] device Device to create shader on. + * @param[in] device Device that creates the shader. * @param[in] info Pointer to a PalShaderCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outShader Pointer to a PalShader to recieve the created shader. @@ -4326,7 +4326,7 @@ PAL_API PalResult PAL_CALL palPresentSwapchain( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4360,7 +4360,7 @@ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); * * The graphics system must be initialized before this call. * - * @param[in] device Device to create fence on. + * @param[in] device Device that creates the fence. * @param[in] signaled True if fence should be created signaled. If true, the fence must be reset * before waiting for it to prevent waiting forever. * @param[out] outFence Pointer to a PalFence to recieve the created fence. @@ -4368,7 +4368,7 @@ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4470,13 +4470,13 @@ PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); * The feature must be supported by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * - * @param[in] device Device to create semaphore on. + * @param[in] device Device that creates the semaphore. * @param[out] outSemaphore Pointer to a PalSemaphore to recieve the created semaphore. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4588,7 +4588,7 @@ PAL_API PalResult PAL_CALL palGetSemaphoreValue( * * The graphics system must be initialized before this call. * - * @param[in] device Device to create command pool on. + * @param[in] device Device that creates the command pool. * @param[in] queue Queue the command pool buffers will be submitted to. * @param[out] outPool Pointer to a PalCommandPool to recieve the created command pool. * @@ -4648,7 +4648,7 @@ PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); * The graphics system must be initialized before this call. * * @param[in] device Device to allocate command buffer on. - * @param[in] pool Command pool to allocate command buffer on. + * @param[in] pool Command pool to allocate command buffer from. * @param[in] type Type of the command buffer (eg. PAL_COMMAND_BUFFER_TYPE_PRIMARY). * @param[out] outCmdBuffer Pointer to a PalCommandBuffer to recieve the created command buffer. * @@ -4806,6 +4806,7 @@ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( * * @since 1.4 * @ingroup pal_graphics + * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( PalCommandBuffer* cmdBuffer, @@ -4837,6 +4838,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( * * @since 1.4 * @ingroup pal_graphics + * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( PalCommandBuffer* cmdBuffer, @@ -4871,6 +4873,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( * * @since 1.4 * @ingroup pal_graphics + * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( PalCommandBuffer* cmdBuffer, @@ -4999,7 +5002,7 @@ PAL_API PalResult PAL_CALL palCmdBindPipeline( * viewports that were set since the first viewport index is always 0. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] count Number of viewports in the array. + * @param[in] count Capacity of the PalViewport array. * @param[in] viewports Pointer to an array of viewports. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -5022,7 +5025,7 @@ PAL_API PalResult PAL_CALL palCmdSetViewport( * scissors that were set since the first scissor index is always 0. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] count Number of scissors in the array. + * @param[in] count Capacity of the PalRect2D array. * @param[in] scissors Pointer to an array of scissors. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -5280,29 +5283,156 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( Uint32 maxDrawCount, Uint32 stride); +/** + * @brief Insert a memory barrier into the command buffer. + * + * The graphics system must be initialized before this call. This functions makes memory invisible + * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. + * + * Example: To make sure an acceleration structure build is completed and memory is visible to the + * raygen shader before it executes, `oldUsageStateInfo.usageState` should be + * `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE` after the build function is called and + * `newUsageStateInfo.usageState` should be `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ` to make + * sure its in read state before its visible to the raygen shader. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. + * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCmdImageViewBarrier + * @sa palCmdBufferBarrier + */ PAL_API PalResult PAL_CALL palCmdMemoryBarrier( PalCommandBuffer* cmdBuffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); +/** + * @brief Insert an image view memory barrier into the command buffer. + * + * The graphics system must be initialized before this call. This functions makes memory invisible + * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. + * + * Example: To make sure an image view has been rendered to fully and prepared for presenting, + * `oldUsageStateInfo.usageState` should be `PAL_USAGE_STATE_UNDEFINED` or `PAL_USAGE_STATE_PRESENT` + * depending on the previous state of the image view. `newUsageStateInfo.usageState` should be + * `PAL_USAGE_STATE_PRESENT` to make sure its in present state. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] imageView Image view to set barrier on. + * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. + * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCmdMemoryBarrier + * @sa palCmdBufferBarrier + */ PAL_API PalResult PAL_CALL palCmdImageViewBarrier( PalCommandBuffer* cmdBuffer, PalImageView* imageView, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); +/** + * @brief Insert a buffer memory barrier into the command buffer. + * + * The graphics system must be initialized before this call. This functions makes memory invisible + * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. + * + * Example: To make sure a GPU memory buffer has been written to by the shader and ready to be + * copied to a CPU memory buffer, `oldUsageStateInfo.usageState` should be + * `PAL_USAGE_STATE_SHADER_WRITE` and optional `oldUsageStateInfo.shaderStage` set to indicate + * which shader stage will write to the buffer. `newUsageStateInfo.usageState` should be + * `PAL_USAGE_STATE_TRANSFER_READ` to make sure its in read state. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] buffer Buffer to set barrier on. + * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. + * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCmdMemoryBarrier + * @sa palCmdImageViewBarrier + */ PAL_API PalResult PAL_CALL palCmdBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); +/** + * @brief Dispatch compute shader workgroups. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] groupCountX Number of compute shader groups to dispatch on the x axis. + * @param[in] groupCountY Number of compute shader groups to dispatch on the y axis. + * @param[in] groupCountZ Number of compute shader groups to dispatch on the z axis. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palBuildWorkGroupInfo + */ PAL_API PalResult PAL_CALL palCmdDispatch( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, Uint32 groupCountZ); +/** + * @brief Dispatch compute shader workgroups with base offset. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` and `PAL_ADAPTER_FEATURE_DISPATCH_BASE` must be supported + * and enabled by the device if not, this function will fail and return + * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] baseGroupX Base group offset on the x axis. + * @param[in] baseGroupY Base group offset on the y axis. + * @param[in] baseGroupZ Base group offset on the z axis. + * @param[in] groupCountX Number of compute shader groups to dispatch on the x axis. + * @param[in] groupCountY Number of compute shader groups to dispatch on the y axis. + * @param[in] groupCountZ Number of compute shader groups to dispatch on the z axis. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palBuildWorkGroupInfo + */ PAL_API PalResult PAL_CALL palCmdDispatchBase( PalCommandBuffer* cmdBuffer, Uint32 baseGroupX, @@ -5312,21 +5442,105 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( Uint32 groupCountY, Uint32 groupCountZ); +/** + * @brief Dispatch compute shader workgroups using parameters from a buffer. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported + * and enabled by the device if not, this function will fail and return + * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. + * Can be a single struct. + * @param[in] offset Starting byte offset into `buffer`. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palBuildWorkGroupInfo + */ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset); +/** + * @brief Dispatch rays. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, + * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] width Number of rays to trace on the x axis. + * @param[in] height Number of rays to trace on the y axis. + * @param[in] depth Number of rays to trace on the z axis. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, Uint32 width, Uint32 height, Uint32 depth); +/** + * @brief Dispatch rays using parameters from a buffer. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported + * and enabled by the device if not, this function will fail and return + * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] bufferAddress Buffer address of buffer containing an array of + * PalDispatchIndirectData structs. Can be a single struct. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, PalDeviceAddress bufferAddress); +/** + * @brief Bind a descriptor set to the provided command buffer. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] pipeline Pipeline to associate the descriptor set to. + * @param[in] layout The pipeline layout that defines the descriptor interface. + * @param[in] setIndex Index of the descriptor set to bind. + * @param[in] set Descriptor set to bind. Must be compatible with `layout`. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline, @@ -5334,6 +5548,27 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( Uint32 setIndex, PalDescriptorSet* set); +/** + * @brief Update push constant data for the provided command buffer. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] layout The pipeline layout that defines the push constant range. + * @param[in] shaderStageCount Capacity of the PalShaderStage array. + * @param[in] shaderStages Array of shader stages that can access the push constant. + * @param[in] offset Offset in bytes into the push constant range. + * @param[in] size Size of `value` in bytes. + * @param[in] value Pointer to the push constant range data to write. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, @@ -5343,102 +5578,597 @@ PAL_API PalResult PAL_CALL palCmdPushConstants( Uint32 size, const void* value); +/** + * @brief Submit a command buffer to the provided queue for execution. + * + * The graphics system must be initialized before this call. The command buffer must not + * be in a recording state. + * + * @param[in] queue Queue to execute the command buffer. + * @param[in] info Pointer to a PalCommandBufferSubmitInfo struct that specifies parameters. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `queue` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info); +/** + * @brief Create an acceleration structure. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device that creates the acceleration structure. + * @param[in] info Pointer to a PalAccelerationStructureCreateInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outAs Pointer to a PalAccelerationStructure to recieve the created acceleration structure. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyAccelerationstructure + */ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( PalDevice* device, const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs); +/** + * @brief Destroy an acceleration structure. + * + * The graphics system must be initialized before this call. + * If the provided acceleration structure is invalid or nullptr, this function returns + * silently. + * + * @param[in] as Acceleration structure to destroy. + * + * Thread safety: Thread safe if the device used to create the acceleration structure is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateAccelerationstructure + */ PAL_API void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* as); +/** + * @brief Get the build size of an acceleration structure. + * + * The graphics system must be initialized before this call. + * PalAccelerationStructureBuildInfo::dst, PalAccelerationStructureBuildInfo::scratchBufferAddress + * and PalAccelerationStructureBuildInfo::src must be set to nullptr. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to query. + * @param[in] info Pointer to a PalAccelerationStructureBuildInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] size Pointer to a PalAccelerationStructureBuildSize to recieve the build size. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); +/** + * @brief Create a buffer. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` or `PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS` must be + * supported and enabled by the device if `PAL_BUFFER_USAGE_DEVICE_ADDRESS` will be used. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if + * `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE` will be used. + * + * @param[in] device Device that creates the buffer. + * @param[in] info Pointer to a PalBufferCreateInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outBuffer Pointer to a PalBuffer to recieve the created buffer. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyBuffer + */ PAL_API PalResult PAL_CALL palCreateBuffer( PalDevice* device, const PalBufferCreateInfo* info, PalBuffer** outBuffer); +/** + * @brief Destroy a buffer. + * + * The graphics system must be initialized before this call. + * If the provided buffer is invalid or nullptr, this function returns + * silently. + * + * @param[in] buffer buffer to destroy. + * + * Thread safety: Thread safe if the device used to create the buffer is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateBuffer + */ PAL_API void PAL_CALL palDestroyBuffer(PalBuffer* buffer); +/** + * @brief Get memory requirements for the provided buffer. + * + * The graphics system must be initialized before this call. + * + * @param[in] buffer Buffer to query memory requirements on. + * @param[out] requirements Pointer to a PalMemoryRequirements to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `requirements` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( PalBuffer* buffer, PalMemoryRequirements* requirements); +/** + * @brief Compute size and alignment requirements for an instance buffer. + * + * The graphics system must be initialized before this call. This does not allocate memory + * for the buffer. + * + * PalInstanceBufferRequirements::size and PalInstanceBufferRequirements::alignment are the + * size and alignment which must be used to create the instance buffer. This will be computed + * with regards to the provided `instanceCount`. This function must be used and required for all + * instance buffers. This is used with acceleration structure (`TLAS`). + * + * @param[in] device Device to compute instance buffer requirements with. + * @param[out] requirements Pointer to a PalInstanceBufferRequirements to fill. + * @param[in] instanceCount Number of instances the instance buffer will hold. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized and `requirements` is per + * thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( PalDevice* device, PalInstanceBufferRequirements* requirements, Uint32 instanceCount); +/** + * @brief Update or write instances to the mapped memory of an instance buffer. + * + * The graphics system must be initialized before this call. Instance buffers must not be updated + * or written to with `memcpy`. + * + * @param[in] device The device. Must match the one used to create the instance buffer. + * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. + * @param[in] instances Array of PalAccelerationStructureInstances struct to write. + * Can be a single struct. + * @param[in] instanceCount Number of instances in `instances`. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palWriteInstancesToMappedMemory( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, Uint32 instanceCount); +/** + * @brief Bind an allocated memory to a buffer. + * + * The graphics system must be initialized before this call. + * The memory size and alignment should match the requirements of the buffer. + * Get the requirements with palGetBufferMemoryRequirements(). + * + * @param[in] buffer Buffer to bind memory to. + * @param[in] memory Memory to bind. Must not be nullptr. + * @param[in] offset Starting point within the memory. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `requirements` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palGetBufferMemoryRequirements + */ PAL_API PalResult PAL_CALL palBindBufferMemory( PalBuffer* buffer, PalMemory* memory, Uint64 offset); +/** + * @brief Get the device address of the provided buffer. + * + * The graphics system must be initialized before this call. Buffer must have + * `PAL_BUFFER_USAGE_DEVICE_ADDRESS` usage flag. + * + * @param[in] buffer Buffer to get its device address. + * + * @return Buffer device address on success or `0` on failure. + * + * Thread safety: Thread safe if `buffer` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); +/** + * @brief Create a descriptor set layout that defines the bindings used by descriptor sets. + * + * The graphics system must be initialized before this call. + * + * Enable `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` when creating the device for descriptor + * indexing (bindless resources). The feature must be supported by the device if not, + * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device that creates the descriptor set layout. + * @param[in] info Pointer to a PalDescriptorSetLayoutCreateInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outLayout Pointer to a PalDescriptorSetLayout to recieve the created descriptor + * set layout. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyDescriptorSetLayout + */ PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout); +/** + * @brief Destroy a descriptor set layout. + * + * The graphics system must be initialized before this call. + * If the provided descriptor set layout is invalid or nullptr, this function returns + * silently. + * + * @param[in] layout Descriptor set layout to destroy. + * + * Thread safety: Thread safe if the device used to create the descriptor set layout is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateDescriptorSetLayout + */ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layout); +/** + * @brief Create a descriptor pool to allocate descriptor sets. + * + * The graphics system must be initialized before this call. + * + * Enable `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` when creating the device for descriptor + * indexing (bindless resources). The feature must be supported by the device if not, + * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device that creates the descriptor pool. + * @param[in] info Pointer to a PalDescriptorPoolCreateInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outPool Pointer to a PalDescriptorPool to recieve the created descriptor pool. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyDescriptorPool + */ PAL_API PalResult PAL_CALL palCreateDescriptorPool( PalDevice* device, const PalDescriptorPoolCreateInfo* info, PalDescriptorPool** outPool); +/** + * @brief Destroy a descriptor pool. + * + * The graphics system must be initialized before this call. + * If the provided descriptor pool is invalid or nullptr, this function returns + * silently. + * + * @param[in] pool Descriptor pool to destroy. + * + * Thread safety: Thread safe if the device used to create the descriptor pool is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateDescriptorPool + */ PAL_API void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool); +/** + * @brief Reset the provided descriptor pool. This resets all allocated descriptor sets. + * + * The graphics system must be initialized before this call. + * + * @param[in] pool Descriptor pool to reset. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `pool` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); +/** + * @brief Allocate a descriptor set from the provided descriptor pool. + * + * The graphics system must be initialized before this call. The descriptor set will be + * allocated uninitialized therefore update it before use. + * + * @param[in] device Device to allocate descriptor set on. + * @param[in] pool Descriptor pool to allocate descriptor set from. + * @param[in] layout Descriptor set layout that defines the bindings. + * @param[out] outSet Pointer to a PalDescriptorSet to recieve the created descriptor set. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` and `pool` are externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( PalDevice* device, PalDescriptorPool* pool, PalDescriptorSetLayout* layout, PalDescriptorSet** outSet); +/** + * @brief Update a descriptor set with descriptors (resources). + * + * The graphics system must be initialized before this call. + * + * PalDescriptorSetWriteInfo::descriptorCount must be `1` if not using + * `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` feature for all descriptors. + * + * @param[in] device The Device. Must match the one used to allocate descriptor set. + * @param[in] count Capacity of the PalDescriptorSetWriteInfo array. + * @param[in] infos Array of PalDescriptorSetWriteInfo to write. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ PAL_API PalResult PAL_CALL palUpdateDescriptorSet( PalDevice* device, Uint32 count, PalDescriptorSetWriteInfo* infos); +/** + * @brief Create a pipeline layout. This defines the descriptor set interfaces and push + * constant ranges. + * + * The graphics system must be initialized before this call. + * + * @param[in] device Device that creates the pipeline layout. + * @param[in] info Pointer to a PalPipelineLayoutCreateInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outLayout Pointer to a PalPipelineLayout to recieve the created pipeline layout. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyPipelineLayout + */ PAL_API PalResult PAL_CALL palCreatePipelineLayout( PalDevice* device, const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout); +/** + * @brief Destroy a pipeline layout. + * + * The graphics system must be initialized before this call. + * If the provided pipeline layout is invalid or nullptr, this function returns + * silently. + * + * @param[in] layout Pipeline layout to destroy. + * + * Thread safety: Thread safe if the device used to create the pipeline layout is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreatePipelineLayout + */ PAL_API void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout); +/** + * @brief Create a graphics pipeline. + * + * The graphics system must be initialized before this call. + * + * @param[in] device Device that creates the graphics pipeline. + * @param[in] info Pointer to a PalGraphicsPipelineCreateInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyPipeline + */ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline); +/** + * @brief Create a compute pipeline. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device that creates the compute pipeline. + * @param[in] info Pointer to a PalComputePipelineCreateInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyPipeline + */ PAL_API PalResult PAL_CALL palCreateComputePipeline( PalDevice* device, const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline); +/** + * @brief Create a ray tracing pipeline. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device that creates the ray tracing pipeline. + * @param[in] info Pointer to a PalRayTracingPipelineCreateInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyPipeline + */ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( PalDevice* device, const PalRayTracingPipelineCreateInfo* info, PalPipeline** outPipeline); +/** + * @brief Destroy a pipeline. + * + * The graphics system must be initialized before this call. + * If the provided pipeline is invalid or nullptr, this function returns + * silently. + * + * @param[in] pipeline Pipeline to destroy. + * + * Thread safety: Thread safe if the device used to create the pipeline is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateGraphicsPipeline + * @sa palCreateComputePipeline + * @sa palCreateRayTracingPipeline + */ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); +/** + * @brief Build work group info(s) from work inputs specified in pixels, vertices etc. + * + * Call this function first with PalWorkGroupInfo array set to nullptr to get the number of work group infos. + * Allocate memory for the PalWorkGroupInfo array and passed in the count and the allocated array. If + * the count of the array is less than the number of work group infos, PAL will write upto that limit. + * + * If the count is 0 and the PalWorkGroupInfo array is nullptr, the function fails + * and returns `false`. + * + * This function works the maths for how many work groups to dispatch in each axis and how many + * times it needs to be dispatch in order for the work to be done. It works well with + * palCmdDispatchBase() since its also gives the base for each work group. + * + * @param[in] data Pointer to a PalWorkGroupBuildData with paramters. + * @param[in, out] count Capacity of the PalWorkGroupInfo array. + * @param[out] infos Pointer to an Array of PalWorkGroupInfo. + * + * @return True on success otherwise false. + * + * Thread safety: Must only be called from the main thread. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCmdDrawMeshTasks + * @sa palCmdDrawMeshTasksIndirect + * @sa palCmdDrawMeshTasksIndirectCount + * @sa palCmdDispatch + * @sa palCmdDispatchBase + */ PAL_API bool PAL_CALL palBuildWorkGroupInfo( const PalWorkGroupBuildData* data, Int32* count, diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index fc986d87..14f22c20 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -263,7 +263,7 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. * * @param[in] glWindow Set to nullptr. - * @param[in] count Capacity of the PalGLFBConfig array. + * @param[in, out] count Capacity of the PalGLFBConfig array. * @param[out] configs User allocated array of PalGLFBConfig. * * @return `PAL_RESULT_SUCCESS` on success or a result code on diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 8d51abd8..de81785f 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -829,7 +829,7 @@ PAL_API PalResult PAL_CALL palSetFBConfig( * platform (OS). Users are required to cache this, and call this function again * if monitors are added or removed. * - * @param[in] count Capacity of the PalMonitor array. + * @param[in, out] count Capacity of the PalMonitor array. * @param[out] monitors User allocated array of PalMonitor. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -908,7 +908,7 @@ PAL_API PalResult PAL_CALL palGetMonitorInfo( * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. * * @param[in] monitor Monitor to query display modes on. - * @param[in] count Capacity of the PalMonitorMode array. + * @param[in, out] count Capacity of the PalMonitorMode array. * @param[out] modes User allocated array of PalMonitorMode. * * @return `PAL_RESULT_SUCCESS` on success or a result code on diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 5f4a1d49..b2b434f0 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -2970,12 +2970,16 @@ void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) bool PAL_CALL palBuildWorkGroupInfo( const PalWorkGroupBuildData* data, Int32* count, - PalWorkGroupInfo* info) + PalWorkGroupInfo* infos) { if (!data) { return false; } + if (*count == 0 && infos) { + return false; + } + Uint32 workGroupCount[3]; Uint32 groupInfoCount[3]; for (int i = 0; i < 3; i++) { @@ -2984,7 +2988,7 @@ bool PAL_CALL palBuildWorkGroupInfo( groupInfoCount[i] = _ceil(tmp, data->workGroupCount[i]); } - if (!info) { + if (!infos) { // total number of group build info on all axis *count = groupInfoCount[0] * groupInfoCount[1] * groupInfoCount[2]; ; @@ -2992,7 +2996,7 @@ bool PAL_CALL palBuildWorkGroupInfo( } for (int i = 0; i < *count; i++) { - PalWorkGroupInfo* buildInfo = &info[i]; + PalWorkGroupInfo* buildInfo = &infos[i]; // find index Uint32 index[3]; index[0] = i % groupInfoCount[0]; From e5ff0e99bf0db707e4d7023ae59be776d611f85e Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 17 Mar 2026 14:09:00 +0000 Subject: [PATCH 102/372] begin addition of sampler and more ray tracing features --- include/pal/pal_graphics.h | 1029 ++++++++++++++++++------------------ 1 file changed, 516 insertions(+), 513 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index dbb36955..0107d004 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1691,9 +1691,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 groupCountXOrWidth; /**< Number of groups on the x axis or width.*/ + Uint32 groupCountXOrWidth; /**< Number of groups on the x axis or width.*/ Uint32 groupCountXOrHeight; /**< Number of groups on the y axis or height.*/ - Uint32 groupCountXOrDepth; /**< Number of groups on the z axis or depth.*/ + Uint32 groupCountXOrDepth; /**< Number of groups on the z axis or depth.*/ } PalDispatchIndirectData; /** @@ -3357,17 +3357,17 @@ typedef struct { /** * @brief Add a custom graphics backend to the graphics system. - * - * The graphics system must not be initialized before this call. If already initialized, - * the system should be shutdown and re-initialized after this call. + * + * The graphics system must not be initialized before this call. If already initialized, + * the system should be shutdown and re-initialized after this call. * The graphics system supports 16 custom backends. - * - * The `backend` dispatch table must have its function pointers all set even if a - * function will not be used. If a feature is not supported by the backend, + * + * The `backend` dispatch table must have its function pointers all set even if a + * function will not be used. If a feature is not supported by the backend, * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED` must be returned by the appropriate function. - * If any of the function pointers are not set, this function will fail and + * If any of the function pointers are not set, this function will fail and * `PAL_RESULT_INVALID_BACKEND` will be returned. - * + * * The backend will not not copied, therefore the pointer must remain valid * until the graphics system is shutdown. * @@ -3387,21 +3387,22 @@ PAL_API PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backe /** * @brief Initialize the graphics system. - * - * Any custom backends added with palAddGraphicsBackend() will be registered with the - * graphics system. The graphics system must be shutdown with palShutdownGraphics() when no longer needed. - * + * + * Any custom backends added with palAddGraphicsBackend() will be registered with the + * graphics system. The graphics system must be shutdown with palShutdownGraphics() when no longer + * needed. + * * The debugger and allocator will not not copied, therefore the pointers must remain valid * until the graphics system is shutdown. Set the debugger or PalGraphicsDebugger::callback to * nullptr to disable debugging and validation layers. * - * @param[in] debugger Optional debugger. Set to nullptr to disable debugging and validation + * @param[in] debugger Optional debugger. Set to nullptr to disable debugging and validation * layers. * @param[in] allocator Optional user-provided allocator. Set to nullptr to use default. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -3415,10 +3416,10 @@ PAL_API PalResult PAL_CALL palInitGraphics( /** * @brief Shutdown the graphics system. - * + * * If the graphics system has not been initialized, the function returns silently. * All created devices, queues, images, swapchains etc must be destroyed before this call. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -3429,18 +3430,18 @@ PAL_API void PAL_CALL palShutdownGraphics(); /** * @brief Returns a list of all adapters (GPU) from custom and internal backends. - * + * * The graphics system must be initialized before this call. - * - * If a custom backend which implements an adapter with its API type of Vulkan, and there is an + * + * If a custom backend which implements an adapter with its API type of Vulkan, and there is an * adapter from the internal backends with the same specifications, this function will return both - * of them in the list. Use PalAdapterInfo::backendName to differentiate between custom and + * of them in the list. Use PalAdapterInfo::backendName to differentiate between custom and * internal backend. the backend name for internal backend is `PAL`. - * - * Call this function first with PalAdapter array set to nullptr to get the number of adapters. - * Allocate memory for the PalAdapter array and passed in the count and the allocated array. If + * + * Call this function first with PalAdapter array set to nullptr to get the number of adapters. + * Allocate memory for the PalAdapter array and passed in the count and the allocated array. If * the count of the array is less than the number of adapters, PAL will write upto that limit. - * + * * If the count is 0 and the PalAdapter array is nullptr, the function fails * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. * @@ -3453,7 +3454,7 @@ PAL_API void PAL_CALL palShutdownGraphics(); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -3465,7 +3466,7 @@ PAL_API PalResult PAL_CALL palEnumerateAdapters( /** * @brief Get information about an adapter (GPU). - * + * * The graphics system must be initialized before this call. * * @param[in] adapter Adapter to query information on. @@ -3473,7 +3474,7 @@ PAL_API PalResult PAL_CALL palEnumerateAdapters( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `info` is per thread. * * @since 1.4 @@ -3486,7 +3487,7 @@ PAL_API PalResult PAL_CALL palGetAdapterInfo( /** * @brief Get capabilites or limits about an adapter (GPU). - * + * * The graphics system must be initialized before this call. * * @param[in] adapter Adapter to query capabilities on. @@ -3494,7 +3495,7 @@ PAL_API PalResult PAL_CALL palGetAdapterInfo( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 @@ -3507,13 +3508,13 @@ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( /** * @brief Get the supported features of an adapter (GPU). - * + * * The graphics system must be initialized before this call. * * @param[in] adapter Adapter to query features on. * * @return adapter features on success or `0` on failure. - * + * * Thread safety: Thread safe. * * @since 1.4 @@ -3524,12 +3525,12 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); /** * @brief Create a device from an adapter (GPU). - * + * * The graphics system must be initialized before this call. PAL does not enable any features * implicitly not even common ones like `PAL_ADAPTER_FEATURE_SWAPCHAIN`. - * + * * Every requested feature must be supported by the adapter. Use palGetAdapterFeatures to check - * the supported features of the adapter that can be enabled. Using a feature which is not + * the supported features of the adapter that can be enabled. Using a feature which is not * supported will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] adapter Adapter that creates the device. @@ -3538,7 +3539,7 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -3552,13 +3553,13 @@ PAL_API PalResult PAL_CALL palCreateDevice( /** * @brief Destroy a device. - * + * * The graphics system must be initialized before this call. * If the provided device is invalid or nullptr, this function returns * silently. * * @param[in] device Pointer to the device to destroy. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -3569,9 +3570,9 @@ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); /** * @brief Blocks indefinitely until the device becomes idle. - * + * * The graphics system must be initialized before this call. - * + * * This function blocks indefinitely until all submitted work on the device has been completetd. * Returns `PAL_RESULT_SUCCESS` to indicate all pending operations has been completetd. * @@ -3579,7 +3580,7 @@ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -3589,13 +3590,13 @@ PAL_API PalResult PAL_CALL palWaitDevice(PalDevice* device); /** * @brief Allocates GPU memory for the specified device. - * + * * The graphics system must be initialized before this call. On CPU adapters, there is usually no * `PAL_MEMORY_TYPE_GPU_ONLY` memory type available. So it uses shared memory as the vram and set - * the shared memory to the `PAL_MEMORY_TYPE_GPU_ONLY` for correctness. + * the shared memory to the `PAL_MEMORY_TYPE_GPU_ONLY` for correctness. * * @param[in] device Pointer to device to allocate memory on. - * @param[in] type Memory type to allocate. Must be supported by the adapter associated with the + * @param[in] type Memory type to allocate. Must be supported by the adapter associated with the * device. * @param[in] memoryMask Memory mask. Must match memory type. * @param[in] size Number of bytes to allocate. Must not be 0. @@ -3603,7 +3604,7 @@ PAL_API PalResult PAL_CALL palWaitDevice(PalDevice* device); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized and * `outMemory` is per thread. * @@ -3620,13 +3621,13 @@ PAL_API PalResult PAL_CALL palAllocateMemory( /** * @brief Free GPU memory allocated by palAllocateMemory. - * - * The graphics system must be initialized before this call. + * + * The graphics system must be initialized before this call. * If `memory` is nullptr, this function will return silently. * * @param[in] device Pointer to device to free memory on. * @param[in] memory Pointer to memory to free. - * + * * Thread safety: Thread safe if `device` is externally synchronized and * `outMemory` is per thread. * @@ -3640,25 +3641,25 @@ PAL_API void PAL_CALL palFreeMemory( /** * @brief Maps GPU memory to CPU visible address space. - * + * * The graphics system must be initialized before this call. - * - * Only `PAL_MEMORY_TYPE_CPU_UPLOAD` and `PAL_MEMORY_TYPE_CPU_READBACK` can be mapped to - * CPU visible space. MApping `PAL_MEMORY_TYPE_GPU_ONLY` will fail and return + * + * Only `PAL_MEMORY_TYPE_CPU_UPLOAD` and `PAL_MEMORY_TYPE_CPU_READBACK` can be mapped to + * CPU visible space. MApping `PAL_MEMORY_TYPE_GPU_ONLY` will fail and return * `PAL_RESULT_MEMORY_MAP_FAILED`. * * @param[in] device Pointer to device memory belongs to. * @param[in] memory Pointer to memory to map. * @param[in] offset Starting point within the memory. - * @param[in] size Number of bytes to map from the offset. `offset + size` must not be + * @param[in] size Number of bytes to map from the offset. `offset + size` must not be * greater than memory size. * @param[out] outPtr Pointer to a void* to recieved the mapped memory. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` and `memory` is externally synchronized. - * Mapping with different offsets into the same memory is thread safe as long as `device` + * Mapping with different offsets into the same memory is thread safe as long as `device` * is externally synchronized. * * @since 1.4 @@ -3674,13 +3675,13 @@ PAL_API PalResult PAL_CALL palMapMemory( /** * @brief Unmap GPU memory from CPU visible address space. - * - * The graphics system must be initialized before this call. The memory must be mapped + * + * The graphics system must be initialized before this call. The memory must be mapped * before this call. After this call, the CPU pointer must not be used anymore. * * @param[in] device Pointer to device memory belongs to. * @param[in] memory Pointer to memory to unmap. - * + * * Thread safety: Thread safe if `device` and `memory` is externally synchronized. * * @since 1.4 @@ -3693,10 +3694,10 @@ PAL_API void PAL_CALL palUnmapMemory( /** * @brief Get depth stencil feature capabilites or limits about a device. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE` must be supported and enabled when creating the + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device to query depth stencil feature capabilities on. @@ -3704,7 +3705,7 @@ PAL_API void PAL_CALL palUnmapMemory( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 @@ -3716,10 +3717,10 @@ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( /** * @brief Get fragment shading rate feature capabilites or limits about a device. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled when creating the + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device to query fragment shading rate feature capabilities on. @@ -3727,7 +3728,7 @@ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 @@ -3739,10 +3740,10 @@ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( /** * @brief Get mesh shader feature capabilites or limits about a device. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled when creating the + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device to query mesh shader feature capabilities on. @@ -3750,7 +3751,7 @@ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 @@ -3762,10 +3763,10 @@ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( /** * @brief Get ray tracing feature capabilites or limits about a device. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled when creating the + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device to query ray tracing feature capabilities on. @@ -3773,7 +3774,7 @@ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 @@ -3785,10 +3786,10 @@ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( /** * @brief Get descriptor indexing feature capabilites or limits about a device. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled when creating the + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device to query descriptor indexing feature capabilities on. @@ -3796,7 +3797,7 @@ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 @@ -3808,14 +3809,14 @@ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( /** * @brief Create a queue from a device. - * + * * The graphics system must be initialized before this call. - * + * * The number of queues of each type which can be created is limited per adapter. check with - * PalAdapterCapabilities::maxComputeQueues, PalAdapterCapabilities::maxGraphicsQueues and - * PalAdapterCapabilities::maxCopyQueues respectively for the limit for each queue type. + * PalAdapterCapabilities::maxComputeQueues, PalAdapterCapabilities::maxGraphicsQueues and + * PalAdapterCapabilities::maxCopyQueues respectively for the limit for each queue type. * Creating more queues than the supported will fail and return `PAL_RESULT_OUT_OF_QUEUE`. - * + * * On most adapters, compute and graphics queues can also do copy operations. * * @param[in] device Device that creates the queue. @@ -3824,7 +3825,7 @@ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -3838,14 +3839,14 @@ PAL_API PalResult PAL_CALL palCreateQueue( /** * @brief Destroy a queue. - * + * * The graphics system must be initialized before this call. * If the provided queue is invalid or nullptr, this function returns * silently. - * + * * @param[in] queue Queue to destroy. - * - * Thread safety: Thread safe if the device used to create the queue is + * + * Thread safety: Thread safe if the device used to create the queue is * externally synchronized. * * @since 1.4 @@ -3856,14 +3857,14 @@ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); /** * @brief Check if a queue is presentable to the provided window. - * + * * The graphics system must be initialized before this call. - * + * * @param[in] queue Queue to query. * @param[in] window Window to check presentation support for. - * + * * @return True if queue can present otherwise false if queue can not present. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -3876,9 +3877,9 @@ PAL_API bool PAL_CALL palCanQueuePresent( /** * @brief Blocks indefinitely until the queue becomes idle. - * + * * The graphics system must be initialized before this call. - * + * * This function blocks indefinitely until all submitted work on the queue has been completetd. * Returns `PAL_RESULT_SUCCESS` to indicate all pending operations has been completetd. * @@ -3886,7 +3887,7 @@ PAL_API bool PAL_CALL palCanQueuePresent( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `queue` is externally synchronized. * * @since 1.4 @@ -3896,17 +3897,17 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); /** * @brief Returns a list of all supported formats of an adapter (GPU). - * + * * The graphics system must be initialized before this call. - * - * This function returns the supported format with the supported image and image view usages - * associated with the format. This is a handy way of selecting a format based on the image + * + * This function returns the supported format with the supported image and image view usages + * associated with the format. This is a handy way of selecting a format based on the image * or image view usages. Use palIsFormatSupported() to check for a specific format. - * - * Call this function first with PalFormatInfo array set to nullptr to get the number of formats. - * Allocate memory for the PalFormatInfo array and passed in the count and the allocated array. If + * + * Call this function first with PalFormatInfo array set to nullptr to get the number of formats. + * Allocate memory for the PalFormatInfo array and passed in the count and the allocated array. If * the count of the array is less than the number of formats, PAL will write upto that limit. - * + * * If the count is 0 and the PalFormatInfo array is nullptr, the function fails * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. * @@ -3916,7 +3917,7 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -3930,19 +3931,19 @@ PAL_API PalResult PAL_CALL palEnumerateFormats( /** * @brief Check support for a format on an adapter (GPU). - * + * * The graphics system must be initialized before this call. - * + * * This is much faster than enumerating all the formats to pick one. You directly check support - * for the format you want to use. Call palQueryFormatImageUsages() and - * palQueryFormatImageViewUsages() to check for supported image and image view usages respectively + * for the format you want to use. Call palQueryFormatImageUsages() and + * palQueryFormatImageViewUsages() to check for supported image and image view usages respectively * if format is supported. * * @param[in] adapter Adapter to query format on. * @param[in] format Format to query support for. - * + * * @return True if format is supported otherwise false if not supported. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -3956,14 +3957,14 @@ PAL_API bool PAL_CALL palIsFormatSupported( /** * @brief Checks supported image usages associated with a format. - * + * * The graphics system must be initialized before this call. * * @param[in] adapter Adapter to query format on. * @param[in] format Format to query image usages for. - * + * * @return Supported image usages on success otherwise `0` on failure. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -3975,14 +3976,14 @@ PAL_API PalImageUsages PAL_CALL palQueryFormatImageUsages( /** * @brief Checks supported image view usages associated with a format. - * + * * The graphics system must be initialized before this call. * * @param[in] adapter Adapter to query format on. * @param[in] format Format to query image view usages for. - * + * * @return Supported image view usages on success otherwise `0` on failure. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -3994,21 +3995,21 @@ PAL_API PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( /** * @brief Create an image. - * + * * The graphics system must be initialized before this call. - * - * PalImageCreateInfo::width, PalImageCreateInfo::height and PalImageCreateInfo::sampleCount + * + * PalImageCreateInfo::width, PalImageCreateInfo::height and PalImageCreateInfo::sampleCount * must not be greater than the limits of the adapter used to create the device. Check * adapter capabilities for the limits. * * @param[in] device Device that creates the image. - * @param[in] info Pointer to a PalImageCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalImageCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outImage Pointer to a PalImage to recieve the created image. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -4022,14 +4023,14 @@ PAL_API PalResult PAL_CALL palCreateImage( /** * @brief Destroy an image. - * + * * The graphics system must be initialized before this call. * If the provided image is invalid or nullptr, this function returns * silently. - * + * * @param[in] image Image to destroy. - * - * Thread safety: Thread safe if the device used to create the image is + * + * Thread safety: Thread safe if the device used to create the image is * externally synchronized. * * @since 1.4 @@ -4040,8 +4041,8 @@ PAL_API void PAL_CALL palDestroyImage(PalImage* image); /** * @brief Get information about an image. - * - * The graphics system must be initialized before this call. + * + * The graphics system must be initialized before this call. * This function also supports swapchain images. * * @param[in] image Image to query information on. @@ -4049,7 +4050,7 @@ PAL_API void PAL_CALL palDestroyImage(PalImage* image); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `info` is per thread. * * @since 1.4 @@ -4062,15 +4063,15 @@ PAL_API PalResult PAL_CALL palGetImageInfo( /** * @brief Get memory requirements for the provided image. - * - * The graphics system must be initialized before this call. + * + * The graphics system must be initialized before this call. * * @param[in] image Image to query memory requirements on. * @param[out] requirements Pointer to a PalMemoryRequirements to fill. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `requirements` is per thread. * * @since 1.4 @@ -4082,8 +4083,8 @@ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( /** * @brief Bind an allocated memory to an image. - * - * The graphics system must be initialized before this call. + * + * The graphics system must be initialized before this call. * The memory size and alignment should match the requirements of the image. * Get the requirements with palGetImageMemoryRequirements(). * @@ -4093,7 +4094,7 @@ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `requirements` is per thread. * * @since 1.4 @@ -4107,25 +4108,25 @@ PAL_API PalResult PAL_CALL palBindImageMemory( /** * @brief Create an image view. - * + * * The graphics system must be initialized before this call. - * - * PalImageViewCreateInfo::type must be compatible by the type of the base image. Eg. A 2D base - * image must be have an image view of either `PAL_IMAGE_VIEW_TYPE_2D` or - * `PAL_IMAGE_VIEW_TYPE_2D_ARRAY`. - * + * + * PalImageViewCreateInfo::type must be compatible by the type of the base image. Eg. A 2D base + * image must be have an image view of either `PAL_IMAGE_VIEW_TYPE_2D` or + * `PAL_IMAGE_VIEW_TYPE_2D_ARRAY`. + * * `PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY` must be supported and enabled by the device * used to create the image view if `PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY` will be used. * * @param[in] device Device that creates the image view. * @param[in] image Image to create the image view with. - * @param[in] info Pointer to a PalImageViewCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalImageViewCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outImageView Pointer to a PalImageView to recieve the created image view. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -4140,14 +4141,14 @@ PAL_API PalResult PAL_CALL palCreateImageView( /** * @brief Destroy an image view. - * + * * The graphics system must be initialized before this call. * If the provided image view is invalid or nullptr, this function returns * silently. - * + * * @param[in] imageView Image view to destroy. - * - * Thread safety: Thread safe if the device used to create the image view is + * + * Thread safety: Thread safe if the device used to create the image view is * externally synchronized. * * @since 1.4 @@ -4158,10 +4159,10 @@ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); /** * @brief Get swapchain feature capabilites or limits about a device against a window. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device to query swapchain feature capabilities on. @@ -4170,7 +4171,7 @@ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 @@ -4183,22 +4184,22 @@ PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( /** * @brief Create a swaphain. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled by the device if not, this + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device that creates the swapchain. * @param[in] queue Queue to create swapchain with. This must be a graphics queue. * @param[in] window Window to create swapchain with. - * @param[in] info Pointer to a PalSwapchainCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalSwapchainCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outSwapchain Pointer to a PalSwapchain to recieve the created swapchain. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -4214,14 +4215,14 @@ PAL_API PalResult PAL_CALL palCreateSwapchain( /** * @brief Destroy a swapchain. - * + * * The graphics system must be initialized before this call. * If the provided swapchain is invalid or nullptr, this function returns * silently. - * + * * @param[in] swapchain Swapchain to destroy. - * - * Thread safety: Thread safe if the device used to create the swapchain is + * + * Thread safety: Thread safe if the device used to create the swapchain is * externally synchronized. * * @since 1.4 @@ -4232,14 +4233,14 @@ PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); /** * @brief Get a swapchain image from the list of images with an index. - * + * * The graphics system must be initialized before this call. - * + * * @param[in] swapchain Swapchain to get image from. * @param[in] index Index of image in the list. Must not be greater than the image count. - * + * * @return A pointer to the image on success otherwise nullptr on failure. - * + * * Thread safety: Thread safe. * * @since 1.4 @@ -4252,18 +4253,18 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( /** * @brief Get the next available image from the swapchain image list. - * + * * The graphics system must be initialized before this call. - * + * * @param[in] swapchain Swapchain to get image index from. - * @param[in] info Pointer to a PalSwapchainNextImageInfo struct that specifies parameters. + * @param[in] info Pointer to a PalSwapchainNextImageInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outIndex Pointer to a Uint32 to recieve the next image index. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if externally synchronized. + * + * Thread safety: Thread safe if externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4276,16 +4277,16 @@ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( /** * @brief Present the swapchain. - * + * * The graphics system must be initialized before this call. - * + * * @param[in] swapchain Swapchain to present. - * @param[in] info Pointer to a PalSwapchainPresentInfo struct that specifies parameters. + * @param[in] info Pointer to a PalSwapchainPresentInfo struct that specifies parameters. * Must not be nullptr. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 @@ -4297,35 +4298,35 @@ PAL_API PalResult PAL_CALL palPresentSwapchain( /** * @brief Create a shader. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if * `PAL_SHADER_STAGE_COMPUTE` will be used. - * - * `PAL_ADAPTER_FEATURE_GEOMETRY_SHADER` must be supported and enabled by the device if + * + * `PAL_ADAPTER_FEATURE_GEOMETRY_SHADER` must be supported and enabled by the device if * `PAL_SHADER_STAGE_GEOMETRY` will be used. - * - * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled by the device if + * + * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled by the device if * `PAL_SHADER_STAGE_MESH` or `PAL_SHADER_STAGE_TASK` will be used. - * - * `PAL_ADAPTER_FEATURE_TESSELLATION_SHADER` must be supported and enabled by the device if - * `PAL_SHADER_STAGE_TESSELLATION_CONTROL` or `PAL_SHADER_STAGE_TESSELLATION_EVALUATION` will + * + * `PAL_ADAPTER_FEATURE_TESSELLATION_SHADER` must be supported and enabled by the device if + * `PAL_SHADER_STAGE_TESSELLATION_CONTROL` or `PAL_SHADER_STAGE_TESSELLATION_EVALUATION` will * be used. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if * `PAL_SHADER_STAGE_RAYGEN` or `PAL_SHADER_STAGE_CLOSEST_HIT` or `PAL_SHADER_STAGE_ANY_HIT` or - * `PAL_SHADER_STAGE_MISS` or `PAL_SHADER_STAGE_INTERSECTION` or `PAL_SHADER_STAGE_CALLABLE` will + * `PAL_SHADER_STAGE_MISS` or `PAL_SHADER_STAGE_INTERSECTION` or `PAL_SHADER_STAGE_CALLABLE` will * be used. * * @param[in] device Device that creates the shader. - * @param[in] info Pointer to a PalShaderCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalShaderCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outShader Pointer to a PalShader to recieve the created shader. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -4339,14 +4340,14 @@ PAL_API PalResult PAL_CALL palCreateShader( /** * @brief Destroy a shader. - * + * * The graphics system must be initialized before this call. * If the provided shader is invalid or nullptr, this function returns * silently. - * + * * @param[in] shader Shader to destroy. - * - * Thread safety: Thread safe if the device used to create the shader is + * + * Thread safety: Thread safe if the device used to create the shader is * externally synchronized. * * @since 1.4 @@ -4357,8 +4358,8 @@ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); /** * @brief Create a fence. - * - * The graphics system must be initialized before this call. + * + * The graphics system must be initialized before this call. * * @param[in] device Device that creates the fence. * @param[in] signaled True if fence should be created signaled. If true, the fence must be reset @@ -4367,7 +4368,7 @@ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -4381,14 +4382,14 @@ PAL_API PalResult PAL_CALL palCreateFence( /** * @brief Destroy a fence. - * + * * The graphics system must be initialized before this call. * If the provided fence is invalid or nullptr, this function returns * silently. - * + * * @param[in] fence Fence to destroy. - * - * Thread safety: Thread safe if the device used to create the fence is + * + * Thread safety: Thread safe if the device used to create the fence is * externally synchronized. * * @since 1.4 @@ -4399,18 +4400,18 @@ PAL_API void PAL_CALL palDestroyFence(PalFence* fence); /** * @brief Wait for a fence. - * + * * The graphics system must be initialized before this call. - * + * * This function blocks for `timeout` until the fence is signaled or there is a timeout. * Returns `PAL_RESULT_SUCCESS` or `PAL_RESULT_TIMEOUT` respectively. - * + * * @param[in] fence Fence to wait for. * @param[in] timeout Time to wait for in milliseconds. Set to `PAL_INFINITE` for indefintely. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `fence` is externally synchronized. * * @since 1.4 @@ -4423,17 +4424,17 @@ PAL_API PalResult PAL_CALL palWaitFence( /** * @brief Reset a fence to an unsignaled state. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_FENCE_RESET` must be supported and enabled when creating the + * + * `PAL_ADAPTER_FEATURE_FENCE_RESET` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * + * * @param[in] fence Fence to reset. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `fence` is externally synchronized. * * @since 1.4 @@ -4444,13 +4445,13 @@ PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); /** * @brief Checks if the provided fence is in a signaled state. - * + * * The graphics system must be initialized before this call. - * + * * @param[in] fence Fence to check. - * + * * @return True if signaled otherwise false. - * + * * Thread safety: Thread safe. * * @since 1.4 @@ -4462,12 +4463,12 @@ PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); /** * @brief Create a semaphore. - * - * The graphics system must be initialized before this call. - * + * + * The graphics system must be initialized before this call. + * * A binary semaphore is created by default. To create a timeline - * semaphore, enable `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` when creating the device. - * The feature must be supported by the device if not, this function will fail and return + * semaphore, enable `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` when creating the device. + * The feature must be supported by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device that creates the semaphore. @@ -4475,7 +4476,7 @@ PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -4488,14 +4489,14 @@ PAL_API PalResult PAL_CALL palCreateSemaphore( /** * @brief Destroy a semaphore. - * + * * The graphics system must be initialized before this call. * If the provided semaphore is invalid or nullptr, this function returns * silently. - * + * * @param[in] semaphore Semaphore to destroy. - * - * Thread safety: Thread safe if the device used to create the semaphore is + * + * Thread safety: Thread safe if the device used to create the semaphore is * externally synchronized. * * @since 1.4 @@ -4506,19 +4507,19 @@ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); /** * @brief Waits for a semaphore to reach the provided value. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the + * + * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * + * * @param[in] semaphore Semaphore to wait on. * @param[in] value Value to wait for. * @param[in] timeout Time to wait for in milliseconds. Set to `PAL_INFINITE` for indefintely. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `semaphore` is externally synchronized. * * @since 1.4 @@ -4533,19 +4534,19 @@ PAL_API PalResult PAL_CALL palWaitSemaphore( /** * @brief Signals a semaphore from the provided value. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the + * + * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * + * * @param[in] semaphore Semaphore to signal. * @param[in] queue Queue used to signal the semaphore. * @param[in] value Value to signal. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `queue` is externally synchronized. * * @since 1.4 @@ -4560,18 +4561,18 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( /** * @brief Get the value of a semaphore. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the + * + * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * + * * @param[in] semaphore Semaphore to get its value. * @param[out] value Pointer to a Uint64 to receive the semaphore value. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `semaphore` is externally synchronized. * * @since 1.4 @@ -4585,7 +4586,7 @@ PAL_API PalResult PAL_CALL palGetSemaphoreValue( /** * @brief Create a command pool from a device. - * + * * The graphics system must be initialized before this call. * * @param[in] device Device that creates the command pool. @@ -4594,7 +4595,7 @@ PAL_API PalResult PAL_CALL palGetSemaphoreValue( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -4608,15 +4609,15 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( /** * @brief Destroy a command pool. - * + * * The graphics system must be initialized before this call. * If the provided command pool is invalid or nullptr, this function returns - * silently. All command buffers allocated from the command pool must be freed before this + * silently. All command buffers allocated from the command pool must be freed before this * function. - * + * * @param[in] pool Command pool to destroy. - * - * Thread safety: Thread safe if the device used to create the command pool is + * + * Thread safety: Thread safe if the device used to create the command pool is * externally synchronized. * * @since 1.4 @@ -4627,14 +4628,14 @@ PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); /** * @brief Reset all command buffers allocated from the provided command pool. - * + * * The graphics system must be initialized before this call. * * @param[in] pool Command pool to reset its command buffers. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `pool` is externally synchronized. * * @since 1.4 @@ -4644,7 +4645,7 @@ PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); /** * @brief Allocate a command buffer from the provided command pool. - * + * * The graphics system must be initialized before this call. * * @param[in] device Device to allocate command buffer on. @@ -4654,7 +4655,7 @@ PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` and `pool` are externally synchronized. * * @since 1.4 @@ -4669,14 +4670,14 @@ PAL_API PalResult PAL_CALL palAllocateCommandBuffer( /** * @brief Free an allocated command buffer. - * + * * The graphics system must be initialized before this call. * If the provided command buffer is invalid or nullptr, this function returns * silently. - * + * * @param[in] cmdBuffer Command buffer to free. - * - * Thread safety: Thread safe if the command pool used to create the command buffer is + * + * Thread safety: Thread safe if the command pool used to create the command buffer is * externally synchronized. * * @since 1.4 @@ -4687,14 +4688,14 @@ PAL_API void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer); /** * @brief Reset the provided command buffer. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer to reset. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4704,7 +4705,7 @@ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); /** * @brief Begin recording commands to the provided command buffer. - * + * * The graphics system must be initialized before this call. This function must be called * before any other `palCmd**` function is used. * @@ -4712,7 +4713,7 @@ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4725,14 +4726,14 @@ PAL_API PalResult PAL_CALL palCmdBegin( /** * @brief End recording commands to the provided command buffer. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer to begin recording. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4743,7 +4744,7 @@ PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); /** * @brief Execute a secondary command buffer within a primary command buffer. - * + * * The graphics system must be initialized before this call. The `secondaryCmdBuffer` must * be created with the type `PAL_COMMAND_BUFFER_TYPE_SECONDARY`. * @@ -4752,7 +4753,7 @@ PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `primaryCmdBuffer` is externally synchronized. * * @since 1.4 @@ -4764,19 +4765,19 @@ PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( /** * @brief Set the fragment shading rate used for draw calls. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled by the device if not, + * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] state Pointer to a PalFragmentShadingRateState struct that specifies parameters. + * @param[in] state Pointer to a PalFragmentShadingRateState struct that specifies parameters. * Must not be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4788,10 +4789,10 @@ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( /** * @brief Dispatch mesh shader workgroups. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled by the device if not, this + * + * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -4801,7 +4802,7 @@ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4816,24 +4817,24 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( /** * @brief Dispatch mesh shader workgroups using parameters from a buffer. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported - * and enabled by the device if not, this function will fail and return + * + * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported + * and enabled by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. + * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. * Can be a single struct. * @param[in] offset Starting byte offset into `buffer`. * @param[in] drawCount Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * @param[in] stride Size in bytes of each parameter struct in `buffer`. * Must be greater or equal to sizeof(PalDispatchIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4849,26 +4850,26 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( /** * @brief Dispatch mesh shader workgroups using parameters from buffers. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be - * supported and enabled by the device if not, this function will fail and return + * + * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be + * supported and enabled by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. + * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. * Can be a single struct. * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. * @param[in] offset Starting byte offset into `buffer`. * @param[in] countBufferOffset Starting byte offset into `countBuffer`. * @param[in] maxDrawCount Maximum Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * @param[in] stride Size in bytes of each parameter struct in `buffer`. * Must be greater or equal to sizeof(PalDispatchIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4886,19 +4887,19 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( /** * @brief Build or update an acceleration structure. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] info Pointer to a PalAccelerationStructureBuildInfo struct that specifies parameters. + * @param[in] info Pointer to a PalAccelerationStructureBuildInfo struct that specifies parameters. * Must not be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4910,16 +4911,16 @@ PAL_API PalResult PAL_CALL palCmdBuildAccelerationStructure( /** * @brief Begin a rendering pass. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] info Pointer to a PalRenderingInfo struct that specifies parameters. + * @param[in] info Pointer to a PalRenderingInfo struct that specifies parameters. * Must not be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4931,14 +4932,14 @@ PAL_API PalResult PAL_CALL palCmdBeginRendering( /** * @brief End a rendering pass. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4948,7 +4949,7 @@ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); /** * @brief Copy data from one buffer to the other. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. @@ -4960,7 +4961,7 @@ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4976,7 +4977,7 @@ PAL_API PalResult PAL_CALL palCmdCopyBuffer( /** * @brief Bind a pipeline. - * + * * The graphics system must be initialized before this call. Every pipeline knows it types which is * set at the respective creation functions. (`palCreate**Graphics/Compute/RayTracing**Pipeline`). * @@ -4985,7 +4986,7 @@ PAL_API PalResult PAL_CALL palCmdCopyBuffer( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -4997,7 +4998,7 @@ PAL_API PalResult PAL_CALL palCmdBindPipeline( /** * @brief Set the viewport(s) used in draw commands. - * + * * The graphics system must be initialized before this call. This always overwrites any previous * viewports that were set since the first viewport index is always 0. * @@ -5007,7 +5008,7 @@ PAL_API PalResult PAL_CALL palCmdBindPipeline( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5020,7 +5021,7 @@ PAL_API PalResult PAL_CALL palCmdSetViewport( /** * @brief Set the scissor(s) used in draw commands. - * + * * The graphics system must be initialized before this call. This always overwrites any previous * scissors that were set since the first scissor index is always 0. * @@ -5030,7 +5031,7 @@ PAL_API PalResult PAL_CALL palCmdSetViewport( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5043,7 +5044,7 @@ PAL_API PalResult PAL_CALL palCmdSetScissors( /** * @brief Bind vertex buffer(s) used in draw commands. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. @@ -5054,7 +5055,7 @@ PAL_API PalResult PAL_CALL palCmdSetScissors( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5069,7 +5070,7 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( /** * @brief Bind index buffer used in draw commands. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. @@ -5079,7 +5080,7 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5093,7 +5094,7 @@ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( /** * @brief Issue a non-indexed draw command. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. @@ -5104,7 +5105,7 @@ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5120,23 +5121,23 @@ PAL_API PalResult PAL_CALL palCmdDraw( /** * @brief Issue a non-indexed draw command using buffers. - * + * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device if not, this + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. + * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. * Can be a single struct. * @param[in] offset Starting byte offset into `buffer`. * @param[in] count Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * @param[in] stride Size in bytes of each parameter struct in `buffer`. * Must be greater or equal to sizeof(PalDrawIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5152,25 +5153,25 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirect( /** * @brief Issue a non-indexed draw command using buffers. - * + * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device if not, + * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. + * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. * Can be a single struct. * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. * @param[in] offset Starting byte offset into `buffer`. * @param[in] countBufferOffset Starting byte offset into `countBuffer`. * @param[in] maxDrawCount Maximum Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. - * Must be greater or equal to sizeof(PalDrawIndirectData). + * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * Must be greater or equal to sizeof(PalDrawIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5188,7 +5189,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( /** * @brief Issue an indexed draw command. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. @@ -5200,7 +5201,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5217,23 +5218,23 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexed( /** * @brief Issue an indexed draw command using buffers. - * + * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device if not, this + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. + * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. * Can be a single struct. * @param[in] offset Starting byte offset into `buffer`. * @param[in] count Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * @param[in] stride Size in bytes of each parameter struct in `buffer`. * Must be greater or equal to sizeof(PalDrawIndexedIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5249,25 +5250,25 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( /** * @brief Issue an indexed draw command using buffers. - * + * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device if not, + * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. + * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. * Can be a single struct. * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. * @param[in] offset Starting byte offset into `buffer`. * @param[in] countBufferOffset Starting byte offset into `countBuffer`. * @param[in] maxDrawCount Maximum Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. - * Must be greater or equal to sizeof(PalDrawIndexedIndirectData). + * @param[in] stride Size in bytes of each parameter struct in `buffer`. + * Must be greater or equal to sizeof(PalDrawIndexedIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5285,23 +5286,23 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( /** * @brief Insert a memory barrier into the command buffer. - * + * * The graphics system must be initialized before this call. This functions makes memory invisible * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. - * + * * Example: To make sure an acceleration structure build is completed and memory is visible to the - * raygen shader before it executes, `oldUsageStateInfo.usageState` should be - * `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE` after the build function is called and + * raygen shader before it executes, `oldUsageStateInfo.usageState` should be + * `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE` after the build function is called and * `newUsageStateInfo.usageState` should be `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ` to make * sure its in read state before its visible to the raygen shader. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5316,23 +5317,23 @@ PAL_API PalResult PAL_CALL palCmdMemoryBarrier( /** * @brief Insert an image view memory barrier into the command buffer. - * + * * The graphics system must be initialized before this call. This functions makes memory invisible * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. - * - * Example: To make sure an image view has been rendered to fully and prepared for presenting, - * `oldUsageStateInfo.usageState` should be `PAL_USAGE_STATE_UNDEFINED` or `PAL_USAGE_STATE_PRESENT` - * depending on the previous state of the image view. `newUsageStateInfo.usageState` should be + * + * Example: To make sure an image view has been rendered to fully and prepared for presenting, + * `oldUsageStateInfo.usageState` should be `PAL_USAGE_STATE_UNDEFINED` or `PAL_USAGE_STATE_PRESENT` + * depending on the previous state of the image view. `newUsageStateInfo.usageState` should be * `PAL_USAGE_STATE_PRESENT` to make sure its in present state. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] imageView Image view to set barrier on. * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5348,24 +5349,24 @@ PAL_API PalResult PAL_CALL palCmdImageViewBarrier( /** * @brief Insert a buffer memory barrier into the command buffer. - * + * * The graphics system must be initialized before this call. This functions makes memory invisible * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. - * - * Example: To make sure a GPU memory buffer has been written to by the shader and ready to be - * copied to a CPU memory buffer, `oldUsageStateInfo.usageState` should be + * + * Example: To make sure a GPU memory buffer has been written to by the shader and ready to be + * copied to a CPU memory buffer, `oldUsageStateInfo.usageState` should be * `PAL_USAGE_STATE_SHADER_WRITE` and optional `oldUsageStateInfo.shaderStage` set to indicate - * which shader stage will write to the buffer. `newUsageStateInfo.usageState` should be + * which shader stage will write to the buffer. `newUsageStateInfo.usageState` should be * `PAL_USAGE_STATE_TRANSFER_READ` to make sure its in read state. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer to set barrier on. * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5381,10 +5382,10 @@ PAL_API PalResult PAL_CALL palCmdBufferBarrier( /** * @brief Dispatch compute shader workgroups. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if not, this + * + * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -5394,7 +5395,7 @@ PAL_API PalResult PAL_CALL palCmdBufferBarrier( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5409,10 +5410,10 @@ PAL_API PalResult PAL_CALL palCmdDispatch( /** * @brief Dispatch compute shader workgroups with base offset. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` and `PAL_ADAPTER_FEATURE_DISPATCH_BASE` must be supported + * + * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` and `PAL_ADAPTER_FEATURE_DISPATCH_BASE` must be supported * and enabled by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * @@ -5426,7 +5427,7 @@ PAL_API PalResult PAL_CALL palCmdDispatch( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5444,21 +5445,21 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( /** * @brief Dispatch compute shader workgroups using parameters from a buffer. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported - * and enabled by the device if not, this function will fail and return + * + * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported + * and enabled by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. + * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. * Can be a single struct. * @param[in] offset Starting byte offset into `buffer`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5472,10 +5473,10 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( /** * @brief Dispatch rays. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -5485,7 +5486,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5499,20 +5500,20 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( /** * @brief Dispatch rays using parameters from a buffer. - * + * * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported - * and enabled by the device if not, this function will fail and return + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported + * and enabled by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] bufferAddress Buffer address of buffer containing an array of + * @param[in] bufferAddress Buffer address of buffer containing an array of * PalDispatchIndirectData structs. Can be a single struct. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5524,7 +5525,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( /** * @brief Bind a descriptor set to the provided command buffer. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. @@ -5535,7 +5536,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5550,7 +5551,7 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( /** * @brief Update push constant data for the provided command buffer. - * + * * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. @@ -5563,7 +5564,7 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5580,17 +5581,17 @@ PAL_API PalResult PAL_CALL palCmdPushConstants( /** * @brief Submit a command buffer to the provided queue for execution. - * + * * The graphics system must be initialized before this call. The command buffer must not * be in a recording state. * * @param[in] queue Queue to execute the command buffer. - * @param[in] info Pointer to a PalCommandBufferSubmitInfo struct that specifies parameters. + * @param[in] info Pointer to a PalCommandBufferSubmitInfo struct that specifies parameters. * Must not be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `queue` is externally synchronized. * * @since 1.4 @@ -5602,20 +5603,21 @@ PAL_API PalResult PAL_CALL palSubmitCommandBuffer( /** * @brief Create an acceleration structure. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device that creates the acceleration structure. - * @param[in] info Pointer to a PalAccelerationStructureCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalAccelerationStructureCreateInfo struct that specifies parameters. * Must not be nullptr. - * @param[out] outAs Pointer to a PalAccelerationStructure to recieve the created acceleration structure. + * @param[out] outAs Pointer to a PalAccelerationStructure to recieve the created acceleration + * structure. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -5629,14 +5631,14 @@ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( /** * @brief Destroy an acceleration structure. - * + * * The graphics system must be initialized before this call. * If the provided acceleration structure is invalid or nullptr, this function returns * silently. - * + * * @param[in] as Acceleration structure to destroy. - * - * Thread safety: Thread safe if the device used to create the acceleration structure is + * + * Thread safety: Thread safe if the device used to create the acceleration structure is * externally synchronized. * * @since 1.4 @@ -5647,22 +5649,22 @@ PAL_API void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* /** * @brief Get the build size of an acceleration structure. - * - * The graphics system must be initialized before this call. + * + * The graphics system must be initialized before this call. * PalAccelerationStructureBuildInfo::dst, PalAccelerationStructureBuildInfo::scratchBufferAddress * and PalAccelerationStructureBuildInfo::src must be set to nullptr. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device to query. - * @param[in] info Pointer to a PalAccelerationStructureBuildInfo struct that specifies parameters. + * @param[in] info Pointer to a PalAccelerationStructureBuildInfo struct that specifies parameters. * Must not be nullptr. * @param[out] size Pointer to a PalAccelerationStructureBuildSize to recieve the build size. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 @@ -5675,23 +5677,23 @@ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( /** * @brief Create a buffer. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` or `PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS` must be + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` or `PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS` must be * supported and enabled by the device if `PAL_BUFFER_USAGE_DEVICE_ADDRESS` will be used. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if * `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE` will be used. * * @param[in] device Device that creates the buffer. - * @param[in] info Pointer to a PalBufferCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalBufferCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outBuffer Pointer to a PalBuffer to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -5705,14 +5707,14 @@ PAL_API PalResult PAL_CALL palCreateBuffer( /** * @brief Destroy a buffer. - * + * * The graphics system must be initialized before this call. * If the provided buffer is invalid or nullptr, this function returns * silently. - * + * * @param[in] buffer buffer to destroy. - * - * Thread safety: Thread safe if the device used to create the buffer is + * + * Thread safety: Thread safe if the device used to create the buffer is * externally synchronized. * * @since 1.4 @@ -5723,15 +5725,15 @@ PAL_API void PAL_CALL palDestroyBuffer(PalBuffer* buffer); /** * @brief Get memory requirements for the provided buffer. - * - * The graphics system must be initialized before this call. + * + * The graphics system must be initialized before this call. * * @param[in] buffer Buffer to query memory requirements on. * @param[out] requirements Pointer to a PalMemoryRequirements to fill. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `requirements` is per thread. * * @since 1.4 @@ -5743,10 +5745,10 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( /** * @brief Compute size and alignment requirements for an instance buffer. - * - * The graphics system must be initialized before this call. This does not allocate memory + * + * The graphics system must be initialized before this call. This does not allocate memory * for the buffer. - * + * * PalInstanceBufferRequirements::size and PalInstanceBufferRequirements::alignment are the * size and alignment which must be used to create the instance buffer. This will be computed * with regards to the provided `instanceCount`. This function must be used and required for all @@ -5758,7 +5760,7 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized and `requirements` is per * thread. * @@ -5772,8 +5774,8 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( /** * @brief Update or write instances to the mapped memory of an instance buffer. - * - * The graphics system must be initialized before this call. Instance buffers must not be updated + * + * The graphics system must be initialized before this call. Instance buffers must not be updated * or written to with `memcpy`. * * @param[in] device The device. Must match the one used to create the instance buffer. @@ -5784,7 +5786,7 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -5798,8 +5800,8 @@ PAL_API PalResult PAL_CALL palWriteInstancesToMappedMemory( /** * @brief Bind an allocated memory to a buffer. - * - * The graphics system must be initialized before this call. + * + * The graphics system must be initialized before this call. * The memory size and alignment should match the requirements of the buffer. * Get the requirements with palGetBufferMemoryRequirements(). * @@ -5809,7 +5811,7 @@ PAL_API PalResult PAL_CALL palWriteInstancesToMappedMemory( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `requirements` is per thread. * * @since 1.4 @@ -5823,14 +5825,14 @@ PAL_API PalResult PAL_CALL palBindBufferMemory( /** * @brief Get the device address of the provided buffer. - * + * * The graphics system must be initialized before this call. Buffer must have * `PAL_BUFFER_USAGE_DEVICE_ADDRESS` usage flag. * * @param[in] buffer Buffer to get its device address. - * + * * @return Buffer device address on success or `0` on failure. - * + * * Thread safety: Thread safe if `buffer` is per thread. * * @since 1.4 @@ -5840,22 +5842,22 @@ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); /** * @brief Create a descriptor set layout that defines the bindings used by descriptor sets. - * - * The graphics system must be initialized before this call. - * - * Enable `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` when creating the device for descriptor - * indexing (bindless resources). The feature must be supported by the device if not, + * + * The graphics system must be initialized before this call. + * + * Enable `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` when creating the device for descriptor + * indexing (bindless resources). The feature must be supported by the device if not, * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device that creates the descriptor set layout. - * @param[in] info Pointer to a PalDescriptorSetLayoutCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalDescriptorSetLayoutCreateInfo struct that specifies parameters. * Must not be nullptr. - * @param[out] outLayout Pointer to a PalDescriptorSetLayout to recieve the created descriptor + * @param[out] outLayout Pointer to a PalDescriptorSetLayout to recieve the created descriptor * set layout. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -5869,14 +5871,14 @@ PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( /** * @brief Destroy a descriptor set layout. - * + * * The graphics system must be initialized before this call. * If the provided descriptor set layout is invalid or nullptr, this function returns * silently. - * + * * @param[in] layout Descriptor set layout to destroy. - * - * Thread safety: Thread safe if the device used to create the descriptor set layout is + * + * Thread safety: Thread safe if the device used to create the descriptor set layout is * externally synchronized. * * @since 1.4 @@ -5887,21 +5889,21 @@ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layo /** * @brief Create a descriptor pool to allocate descriptor sets. - * - * The graphics system must be initialized before this call. - * - * Enable `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` when creating the device for descriptor - * indexing (bindless resources). The feature must be supported by the device if not, + * + * The graphics system must be initialized before this call. + * + * Enable `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` when creating the device for descriptor + * indexing (bindless resources). The feature must be supported by the device if not, * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device that creates the descriptor pool. - * @param[in] info Pointer to a PalDescriptorPoolCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalDescriptorPoolCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outPool Pointer to a PalDescriptorPool to recieve the created descriptor pool. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -5915,14 +5917,14 @@ PAL_API PalResult PAL_CALL palCreateDescriptorPool( /** * @brief Destroy a descriptor pool. - * + * * The graphics system must be initialized before this call. * If the provided descriptor pool is invalid or nullptr, this function returns * silently. - * + * * @param[in] pool Descriptor pool to destroy. - * - * Thread safety: Thread safe if the device used to create the descriptor pool is + * + * Thread safety: Thread safe if the device used to create the descriptor pool is * externally synchronized. * * @since 1.4 @@ -5933,14 +5935,14 @@ PAL_API void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool); /** * @brief Reset the provided descriptor pool. This resets all allocated descriptor sets. - * + * * The graphics system must be initialized before this call. * * @param[in] pool Descriptor pool to reset. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `pool` is externally synchronized. * * @since 1.4 @@ -5950,7 +5952,7 @@ PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); /** * @brief Allocate a descriptor set from the provided descriptor pool. - * + * * The graphics system must be initialized before this call. The descriptor set will be * allocated uninitialized therefore update it before use. * @@ -5961,7 +5963,7 @@ PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` and `pool` are externally synchronized. * * @since 1.4 @@ -5975,9 +5977,9 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( /** * @brief Update a descriptor set with descriptors (resources). - * + * * The graphics system must be initialized before this call. - * + * * PalDescriptorSetWriteInfo::descriptorCount must be `1` if not using * `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` feature for all descriptors. * @@ -5987,7 +5989,7 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -5999,19 +6001,19 @@ PAL_API PalResult PAL_CALL palUpdateDescriptorSet( PalDescriptorSetWriteInfo* infos); /** - * @brief Create a pipeline layout. This defines the descriptor set interfaces and push + * @brief Create a pipeline layout. This defines the descriptor set interfaces and push * constant ranges. - * + * * The graphics system must be initialized before this call. * * @param[in] device Device that creates the pipeline layout. - * @param[in] info Pointer to a PalPipelineLayoutCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalPipelineLayoutCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outLayout Pointer to a PalPipelineLayout to recieve the created pipeline layout. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -6025,14 +6027,14 @@ PAL_API PalResult PAL_CALL palCreatePipelineLayout( /** * @brief Destroy a pipeline layout. - * + * * The graphics system must be initialized before this call. * If the provided pipeline layout is invalid or nullptr, this function returns * silently. - * + * * @param[in] layout Pipeline layout to destroy. - * - * Thread safety: Thread safe if the device used to create the pipeline layout is + * + * Thread safety: Thread safe if the device used to create the pipeline layout is * externally synchronized. * * @since 1.4 @@ -6043,17 +6045,17 @@ PAL_API void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout); /** * @brief Create a graphics pipeline. - * - * The graphics system must be initialized before this call. + * + * The graphics system must be initialized before this call. * * @param[in] device Device that creates the graphics pipeline. - * @param[in] info Pointer to a PalGraphicsPipelineCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalGraphicsPipelineCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -6067,20 +6069,20 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( /** * @brief Create a compute pipeline. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if not, this + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device that creates the compute pipeline. - * @param[in] info Pointer to a PalComputePipelineCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalComputePipelineCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -6094,20 +6096,20 @@ PAL_API PalResult PAL_CALL palCreateComputePipeline( /** * @brief Create a ray tracing pipeline. - * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device that creates the ray tracing pipeline. - * @param[in] info Pointer to a PalRayTracingPipelineCreateInfo struct that specifies parameters. + * @param[in] info Pointer to a PalRayTracingPipelineCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 @@ -6121,14 +6123,14 @@ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( /** * @brief Destroy a pipeline. - * + * * The graphics system must be initialized before this call. * If the provided pipeline is invalid or nullptr, this function returns * silently. - * + * * @param[in] pipeline Pipeline to destroy. - * - * Thread safety: Thread safe if the device used to create the pipeline is + * + * Thread safety: Thread safe if the device used to create the pipeline is * externally synchronized. * * @since 1.4 @@ -6141,24 +6143,25 @@ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); /** * @brief Build work group info(s) from work inputs specified in pixels, vertices etc. - * - * Call this function first with PalWorkGroupInfo array set to nullptr to get the number of work group infos. - * Allocate memory for the PalWorkGroupInfo array and passed in the count and the allocated array. If - * the count of the array is less than the number of work group infos, PAL will write upto that limit. - * + * + * Call this function first with PalWorkGroupInfo array set to nullptr to get the number of work + * group infos. Allocate memory for the PalWorkGroupInfo array and passed in the count and the + * allocated array. If the count of the array is less than the number of work group infos, PAL will + * write upto that limit. + * * If the count is 0 and the PalWorkGroupInfo array is nullptr, the function fails * and returns `false`. - * + * * This function works the maths for how many work groups to dispatch in each axis and how many - * times it needs to be dispatch in order for the work to be done. It works well with + * times it needs to be dispatch in order for the work to be done. It works well with * palCmdDispatchBase() since its also gives the base for each work group. - * + * * @param[in] data Pointer to a PalWorkGroupBuildData with paramters. * @param[in, out] count Capacity of the PalWorkGroupInfo array. * @param[out] infos Pointer to an Array of PalWorkGroupInfo. - * + * * @return True on success otherwise false. - * + * * Thread safety: Must only be called from the main thread. * * @since 1.4 From f75296b444c23894e7077aa272d5b46f96cece5a Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 17 Mar 2026 20:42:36 +0000 Subject: [PATCH 103/372] format PAL source files --- src/graphics/pal_graphics.c | 75 +++---------- src/graphics/pal_vulkan.c | 199 +++++++++++++--------------------- src/opengl/pal_opengl_linux.c | 21 +--- src/opengl/pal_opengl_win32.c | 2 +- src/pal_core.c | 3 - src/pal_event.c | 1 - src/system/pal_system_win32.c | 1 - src/thread/pal_thread_win32.c | 2 - src/video/pal_video_linux.c | 11 -- src/video/pal_video_win32.c | 13 +-- 10 files changed, 95 insertions(+), 233 deletions(-) diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index b2b434f0..9ed7a092 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -1087,11 +1087,7 @@ PalResult PAL_CALL palGetAdapterCapabilities( PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) { - if (!s_Graphics.initialized) { - return 0; - } - - if (!adapter) { + if (!s_Graphics.initialized || !adapter) { return 0; } @@ -1118,7 +1114,6 @@ PalResult PAL_CALL palCreateDevice( PalDevice* device = nullptr; PalResult result; result = adapter->backend->createDevice(adapter, features, &device); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1274,7 +1269,6 @@ PalResult PAL_CALL palCreateQueue( PalQueue* queue = nullptr; PalResult result; result = device->backend->createQueue(device, type, &queue); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1391,7 +1385,6 @@ PalResult PAL_CALL palCreateImage( PalImage* image = nullptr; PalResult result; result = device->backend->createImage(device, info, &image); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1475,7 +1468,6 @@ PalResult PAL_CALL palCreateImageView( PalImageView* imageView = nullptr; PalResult result; result = device->backend->createImageView(device, image, info, &imageView); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1530,7 +1522,6 @@ PalResult PAL_CALL palCreateSwapchain( PalResult result; PalSwapchain* swapchain = nullptr; result = device->backend->createSwapchain(device, queue, window, info, &swapchain); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1615,7 +1606,6 @@ PalResult PAL_CALL palCreateShader( PalShader* shader = nullptr; PalResult result; result = device->backend->createShader(device, info, &shader); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1806,7 +1796,6 @@ PalResult PAL_CALL palCreateCommandPool( PalCommandPool* pool = nullptr; PalResult result; result = device->backend->createCommandPool(device, queue, &pool); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1853,7 +1842,6 @@ PalResult PAL_CALL palAllocateCommandBuffer( PalCommandBuffer* cmdBuffer = nullptr; PalResult result; result = device->backend->allocateCommandBuffer(device, pool, type, &cmdBuffer); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1942,9 +1930,7 @@ PalResult PAL_CALL palCmdExecuteCommandBuffer( return PAL_RESULT_NULL_POINTER; } - return primaryCmdBuffer->backend->cmdExecuteCommandBuffer( - primaryCmdBuffer, - secondaryCmdBuffer); + return primaryCmdBuffer->backend->cmdExecuteCommandBuffer(primaryCmdBuffer, secondaryCmdBuffer); } PalResult PAL_CALL palCmdSetFragmentShadingRate( @@ -1994,12 +1980,8 @@ PalResult PAL_CALL palCmdDrawMeshTasksIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdDrawMeshTasksIndirect( - cmdBuffer, - buffer, - offset, - drawCount, - stride); + return cmdBuffer->backend + ->cmdDrawMeshTasksIndirect(cmdBuffer, buffer, offset, drawCount, stride); } PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( @@ -2192,12 +2174,8 @@ PalResult PAL_CALL palCmdDraw( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdDraw( - cmdBuffer, - vertexCount, - instanceCount, - firstVertex, - firstInstance); + return cmdBuffer->backend + ->cmdDraw(cmdBuffer, vertexCount, instanceCount, firstVertex, firstInstance); } PalResult PAL_CALL palCmdDrawIndirect( @@ -2328,10 +2306,7 @@ PalResult PAL_CALL palCmdMemoryBarrier( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdMemoryBarrier( - cmdBuffer, - oldUsageStateInfo, - newUsageStateInfo); + return cmdBuffer->backend->cmdMemoryBarrier(cmdBuffer, oldUsageStateInfo, newUsageStateInfo); } PalResult PAL_CALL palCmdImageViewBarrier( @@ -2348,11 +2323,8 @@ PalResult PAL_CALL palCmdImageViewBarrier( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdImageViewBarrier( - cmdBuffer, - imageView, - oldUsageStateInfo, - newUsageStateInfo); + return cmdBuffer->backend + ->cmdImageViewBarrier(cmdBuffer, imageView, oldUsageStateInfo, newUsageStateInfo); } PalResult PAL_CALL palCmdBufferBarrier( @@ -2369,11 +2341,8 @@ PalResult PAL_CALL palCmdBufferBarrier( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdBufferBarrier( - cmdBuffer, - buffer, - oldUsageStateInfo, - newUsageStateInfo); + return cmdBuffer->backend + ->cmdBufferBarrier(cmdBuffer, buffer, oldUsageStateInfo, newUsageStateInfo); } PalResult PAL_CALL palCmdDispatch( @@ -2503,14 +2472,8 @@ PalResult PAL_CALL palCmdPushConstants( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdPushConstants( - cmdBuffer, - layout, - shaderStageCount, - shaderStages, - offset, - size, - value); + return cmdBuffer->backend + ->cmdPushConstants(cmdBuffer, layout, shaderStageCount, shaderStages, offset, size, value); } // ================================================== @@ -2537,7 +2500,6 @@ PalResult PAL_CALL palCreateAccelerationstructure( PalResult result; PalAccelerationStructure* as = nullptr; result = device->backend->createAccelerationstructure(device, info, &as); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -2590,7 +2552,6 @@ PalResult PAL_CALL palCreateBuffer( PalResult result; PalBuffer* buffer = nullptr; result = device->backend->createBuffer(device, info, &buffer); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -2652,12 +2613,8 @@ PalResult PAL_CALL palWriteInstancesToMappedMemory( return PAL_RESULT_NULL_POINTER; } - // HACK: since all blas have backend pointer, we use the first one - return device->backend->writeInstancesToMappedMemory( - device, - ptr, - instances, - instanceCount); + // since all blas have backend pointer, we use the first one + return device->backend->writeInstancesToMappedMemory(device, ptr, instances, instanceCount); } PalResult PAL_CALL palBindBufferMemory( @@ -2855,7 +2812,6 @@ PalResult PAL_CALL palCreatePipelineLayout( PalResult result; PalPipelineLayout* layout = nullptr; result = device->backend->createPipelineLayout(device, info, &layout); - if (result != PAL_RESULT_SUCCESS) { return result; } @@ -2896,7 +2852,6 @@ PalResult PAL_CALL palCreateGraphicsPipeline( PalResult result; PalPipeline* pipeline = nullptr; result = device->backend->createGraphicsPipeline(device, info, &pipeline); - if (result != PAL_RESULT_SUCCESS) { return result; } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 25c17b22..9f0a1e5e 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -453,6 +453,8 @@ static bool createSurfaceVk( PalGraphicsWindow* window, VkSurfaceKHR* outSurface) { + VkResult result; + VkSurfaceKHR surface = nullptr; Uint32 platform = checkPlatformVk(window->display); if (platform == VK_WIN32_PLATFORM) { @@ -461,17 +463,14 @@ static bool createSurfaceVk( return false; } - VkSurfaceKHR surface = nullptr; - VkWaylandSurfaceCreateInfoKHR createInfo = {0}; - createInfo.display = window->display; - createInfo.pNext = nullptr; - createInfo.flags = 0; - createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; - createInfo.surface = window->window; - - VkResult result = - s_Vk.createWaylandSurface(s_Vk.instance, &createInfo, &s_Vk.allocateVkator, &surface); + VkWaylandSurfaceCreateInfoKHR cInfo = {0}; + cInfo.display = window->display; + cInfo.pNext = nullptr; + cInfo.flags = 0; + cInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + cInfo.surface = window->window; + result = s_Vk.createWaylandSurface(s_Vk.instance, &cInfo, &s_Vk.allocateVkator, &surface); if (result != VK_SUCCESS) { return false; } @@ -1601,7 +1600,8 @@ static VkPipelineStageFlags2 pipelineStageToVk(PalShaderStage stage) return 0; } -static Barrier barrierToVk(PalUsageState state, +static Barrier barrierToVk( + PalUsageState state, PalShaderStage shaderStage) { Barrier barrier = {0}; @@ -1884,7 +1884,6 @@ static VkShaderStageFlags shaderStageToVK(PalShaderStage stage) case PAL_SHADER_STAGE_CALLABLE: return VK_SHADER_STAGE_CALLABLE_BIT_KHR; - } return 0; @@ -2014,7 +2013,9 @@ static Uint32 findBestMemoryIndexVk( return bestIndex; } -static inline Uint32 alignVk(Uint32 value, Uint32 alignVkment) +static inline Uint32 alignVk( + Uint32 value, + Uint32 alignVkment) { return (value + alignVkment - 1) & ~(alignVkment - 1); } @@ -2502,7 +2503,6 @@ PalResult PAL_CALL initGraphicsVk( break; } } - palFree(s_Vk.allocator, props); debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; @@ -2523,24 +2523,21 @@ PalResult PAL_CALL initGraphicsVk( Uint32 extCount = 0; const char* extensions[8]; result = s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, nullptr); - if (result != VK_SUCCESS) { return PAL_RESULT_PLATFORM_FAILURE; } VkExtensionProperties* extensionProps = nullptr; extensionProps = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extCount, 0); - if (!extensionProps) { return PAL_RESULT_SUCCESS; } - s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, extensionProps); - bool hasXlib = false; bool hasWayland = false; bool hasSurface = false; bool hasExtDebug = false; + s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, extensionProps); for (int i = 0; i < extCount; i++) { VkExtensionProperties* prop = &extensionProps[i]; @@ -2596,7 +2593,6 @@ PalResult PAL_CALL initGraphicsVk( instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceCreateInfo.enabledExtensionCount = extensionCount; instanceCreateInfo.enabledLayerCount = layerCount; - instanceCreateInfo.ppEnabledExtensionNames = extensions; instanceCreateInfo.ppEnabledLayerNames = layers; @@ -2611,7 +2607,6 @@ PalResult PAL_CALL initGraphicsVk( VkInstance instance = nullptr; result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.allocateVkator, &instance); - if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -2714,13 +2709,13 @@ PalResult PAL_CALL enumerateAdaptersVk( { int deviceCount = 0; int adapterCount = 0; - int extensionCount = 0; - VkResult result; - VkExtensionProperties* extensions = nullptr; + int extCount = 0; + VkResult ret; + VkExtensionProperties* exts = nullptr; VkPhysicalDeviceProperties props = {0}; - result = s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, nullptr); - if (result != VK_SUCCESS) { + ret = s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, nullptr); + if (ret != VK_SUCCESS) { return PAL_RESULT_PLATFORM_FAILURE; } @@ -2731,7 +2726,6 @@ PalResult PAL_CALL enumerateAdaptersVk( VkPhysicalDevice* devices = nullptr; devices = palAllocate(s_Vk.allocator, sizeof(VkPhysicalDevice) * deviceCount, 0); s_Vk.adapters = palAllocate(s_Vk.allocator, sizeof(Adapter) * deviceCount, 0); - if (!devices || !s_Vk.adapters) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2742,35 +2736,24 @@ PalResult PAL_CALL enumerateAdaptersVk( s_Vk.getPhysicalDeviceProperties(phyDevice, &props); if (props.apiVersion < VK_API_VERSION_1_3) { // check extension - result = s_Vk.enumerateDeviceExtensionProperties( - phyDevice, - nullptr, - &extensionCount, - nullptr); - - extensions = - palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extensionCount, 0); - - if (!extensions) { + ret = s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extCount, nullptr); + exts = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extCount, 0); + if (!exts) { return PAL_RESULT_OUT_OF_MEMORY; } - s_Vk.enumerateDeviceExtensionProperties( - phyDevice, - nullptr, - &extensionCount, - extensions); - bool found = false; - for (int i = 0; i < extensionCount; i++) { - const char* ext = extensions[i].extensionName; + s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extCount, exts); + + for (int i = 0; i < extCount; i++) { + const char* ext = exts[i].extensionName; if (strcmp(ext, "VK_KHR_dynamic_rendering") == 0) { found = true; break; } } - palFree(s_Vk.allocator, extensions); + palFree(s_Vk.allocator, exts); if (!found) { continue; } @@ -2935,12 +2918,11 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( caps->maxImageMipLevels = levels; // get supported queue commands - Uint32 count; + Uint32 count = 0; s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &count, nullptr); VkQueueFamilyProperties* queueProps = nullptr; queueProps = palAllocate(s_Vk.allocator, sizeof(VkQueueFamilyProperties) * count, 0); - s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &count, queueProps); caps->maxComputeQueues = 0; @@ -2997,8 +2979,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) return 0; } - s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, extensionProps); - // check extensions bool rayTracingFound = false; bool accelerateFound = false; @@ -3011,6 +2991,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) bool dynamicstate = false; bool bufferDeviceAddress = false; bool shaderParameters = false; + s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, extensionProps); // clang-format off // check if the extensions are present @@ -3350,7 +3331,6 @@ PalResult PAL_CALL createDeviceVk( queueProps = palAllocate(s_Vk.allocator, sizeof(VkQueueFamilyProperties) * queueCount, 0); queueCreateInfos = palAllocate(s_Vk.allocator, sizeof(VkDeviceQueueCreateInfo) * queueCount, 0); device = palAllocate(s_Vk.allocator, sizeof(Device), 0); - if (!queueProps || !queueCreateInfos || !device) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3679,17 +3659,17 @@ PalResult PAL_CALL createDeviceVk( Uint32 bit = (1u << i); if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) && - !(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + !(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] |= bit; } if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] |= bit; } if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)) { + (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)) { device->memoryClassMask[PAL_MEMORY_TYPE_CPU_READBACK] |= bit; } } @@ -3697,7 +3677,7 @@ PalResult PAL_CALL createDeviceVk( // HACK: most CPU drivers dont have a vram so we set the vram to system memory if (device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] == 0) { device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] = - device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD]; + device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD]; } // clang-format off @@ -4039,7 +4019,6 @@ PalResult PAL_CALL mapMemoryVk( Device* vkDevice = (Device*)device; result = s_Vk.mapMemory(vkDevice->handle, mem, offset, size, 0, outPtr); - if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -4078,7 +4057,6 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesVk( s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); caps->independentDepthStencilResolve = props.independentResolve; - if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { caps->depthResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; } @@ -4570,7 +4548,6 @@ PalResult PAL_CALL createImageVk( } result = s_Vk.createImage(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &image->handle); - if (result != VK_SUCCESS) { palFree(s_Vk.allocator, image); return resultFromVk(result); @@ -4599,7 +4576,6 @@ void PAL_CALL destroyImageVk(PalImage* image) } s_Vk.destroyImage(vkImage->device->handle, vkImage->handle, &s_Vk.allocateVkator); - palFree(s_Vk.allocator, vkImage); } @@ -4651,6 +4627,7 @@ PalResult PAL_CALL bindImageMemoryVk( VkDeviceMemory mem = (VkDeviceMemory)memory; s_Vk.bindImageMemory(vkImage->device->handle, vkImage->handle, mem, offset); + return PAL_RESULT_SUCCESS; } // ================================================== @@ -4704,8 +4681,11 @@ PalResult PAL_CALL createImageViewVk( } createInfo.subresourceRange.aspectMask = aspectFlags; - result = - s_Vk.createImageView(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &imageView->handle); + result = s_Vk.createImageView( + vkDevice->handle, + &createInfo, + &s_Vk.allocateVkator, + &imageView->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, imageView); @@ -4761,9 +4741,7 @@ PalResult PAL_CALL querySwapchainCapabilitiesVk( s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, nullptr); modes = palAllocate(s_Vk.allocator, sizeof(VkPresentModeKHR) * modeCount, 0); - formats = palAllocate(s_Vk.allocator, sizeof(VkSurfaceFormatKHR) * formatCount, 0); - if (!modes || !formats) { s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocateVkator); return PAL_RESULT_OUT_OF_MEMORY; @@ -4960,18 +4938,13 @@ PalResult PAL_CALL createSwapchainVk( result = vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, nullptr); swapchain->images = palAllocate(s_Vk.allocator, sizeof(Image) * count, 0); - images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); - if (!swapchain->images || !images) { vkDevice->destroySwapchain(vkDevice->handle, swapchain->handle, &s_Vk.allocateVkator); - s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.allocateVkator); - palFree(s_Vk.allocator, swapchain); return PAL_RESULT_OUT_OF_MEMORY; } - vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, images); // fill all images with the creatio info @@ -5092,7 +5065,6 @@ PalResult PAL_CALL presentSwapchainVk( presentInfo.waitSemaphoreCount = semaphoreCount; result = vkSwapchain->device->queuePresent(vkSwapchain->queue->phyQueue->handle, &presentInfo); - if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -5121,7 +5093,7 @@ PalResult PAL_CALL createShaderVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // clang-format off + // clang-format off } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || info->stage == PAL_SHADER_STAGE_ANY_HIT || @@ -5145,7 +5117,8 @@ PalResult PAL_CALL createShaderVk( createInfo.codeSize = info->bytecodeSize; createInfo.pCode = (const Uint32*)info->bytecode; - result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &shader->handle); + result = + s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &shader->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, shader); @@ -5196,7 +5169,6 @@ PalResult PAL_CALL createFenceVk( } result = s_Vk.createFence(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &fence->handle); - if (result != VK_SUCCESS) { palFree(s_Vk.allocator, fence); return resultFromVk(result); @@ -5242,7 +5214,6 @@ PalResult PAL_CALL resetFenceVk(PalFence* fence) } VkResult result = s_Vk.resetFence(vkFence->device->handle, 1, &vkFence->handle); - if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -5294,8 +5265,11 @@ PalResult PAL_CALL createSemaphoreVk( } createInfo.pNext = next; - result = - s_Vk.createSemaphore(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &semaphore->handle); + result = s_Vk.createSemaphore( + vkDevice->handle, + &createInfo, + &s_Vk.allocateVkator, + &semaphore->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, semaphore); @@ -5333,7 +5307,6 @@ PalResult PAL_CALL waitSemaphoreVk( waitInfo.pValues = &value; result = vkSemaphore->device->waitSemaphore(vkSemaphore->device->handle, &waitInfo, timeout); - if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -5358,7 +5331,6 @@ PalResult PAL_CALL signalSemaphoreVk( signalInfo.value = value; result = vkSemaphore->device->signalSemaphore(vkSemaphore->device->handle, &signalInfo); - if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -5469,7 +5441,6 @@ PalResult PAL_CALL allocateCommandBufferVk( } result = s_Vk.allocateCommandBuffer(vkDevice->handle, &allocateInfo, &cmdBuffer->handle); - if (result != VK_SUCCESS) { palFree(s_Vk.allocator, cmdBuffer); return resultFromVk(result); @@ -5693,11 +5664,8 @@ PalResult PAL_CALL cmdSetFragmentShadingRateVk( combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR; continue; } - - combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; } } - vkCmdBuffer->device->cmdSetFragmentShadingRate(vkCmdBuffer->handle, &size, combinerOps); return PAL_RESULT_SUCCESS; @@ -5756,7 +5724,7 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6152,7 +6120,6 @@ PalResult PAL_CALL cmdBindVertexBuffersVk( } s_Vk.cmdBindVertexBuffers(vkCmdBuffer->handle, firstSlot, count, vkBuffers, offsets); - if (count > 1) { palFree(s_Vk.allocator, vkBuffers); } @@ -6171,7 +6138,6 @@ PalResult PAL_CALL cmdBindIndexBufferVk( if (type == PAL_INDEX_TYPE_UINT16) { bufferType = VK_INDEX_TYPE_UINT16; } - s_Vk.cmdBindIndexBuffer(vkCmdBuffer->handle, vkBuffer->handle, offset, bufferType); return PAL_RESULT_SUCCESS; @@ -6185,12 +6151,7 @@ PalResult PAL_CALL cmdDrawVk( Uint32 firstInstance) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - s_Vk.cmdDraw( - vkCmdBuffer->handle, - vertexCount, - instanceCount, - firstVertex, - firstInstance); + s_Vk.cmdDraw(vkCmdBuffer->handle, vertexCount, instanceCount, firstVertex, firstInstance); return PAL_RESULT_SUCCESS; } @@ -6324,7 +6285,6 @@ PalResult PAL_CALL cmdMemoryBarrierVk( vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); vkCmdBuffer->dstStage = new.stages; return PAL_RESULT_SUCCESS; - } PalResult PAL_CALL cmdImageViewBarrierVk( @@ -6544,14 +6504,7 @@ PalResult PAL_CALL cmdPushConstantsVk( VkShaderStageFlagBits bit = shaderStageToVK(shaderStages[i]); stages |= bit; } - - s_Vk.cmdPushConstants( - vkCmdBuffer->handle, - vkLayout->handle, - stages, - offset, - size, - value); + s_Vk.cmdPushConstants(vkCmdBuffer->handle, vkLayout->handle, stages, offset, size, value); return PAL_RESULT_SUCCESS; } @@ -6703,7 +6656,9 @@ PalResult PAL_CALL createBufferVk( createInfo.size = info->size; createInfo.usage = bufferUsageToVk(info->usages); - result = s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &buffer->handle); + result = + s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &buffer->handle); + if (result != VK_SUCCESS) { palFree(s_Vk.allocator, buffer); return resultFromVk(result); @@ -6791,11 +6746,12 @@ PalResult PAL_CALL bindBufferMemoryVk( VkResult result; VkDeviceMemory mem = (VkDeviceMemory)memory; Buffer* vkBuffer = (Buffer*)buffer; - result = s_Vk.bindBufferMemory(vkBuffer->device->handle, vkBuffer->handle, mem, offset); + result = s_Vk.bindBufferMemory(vkBuffer->device->handle, vkBuffer->handle, mem, offset); if (result != VK_SUCCESS) { return resultFromVk(result); } + return PAL_RESULT_SUCCESS; } @@ -6828,10 +6784,8 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( DescriptorSetLayout* layout = nullptr; layout = palAllocate(s_Vk.allocator, sizeof(DescriptorSetLayout), 0); - bindings = palAllocate( - s_Vk.allocator, - sizeof(VkDescriptorSetLayoutBinding) * info->bindingCount, - 0); + bindings = + palAllocate(s_Vk.allocator, sizeof(VkDescriptorSetLayoutBinding) * info->bindingCount, 0); if (!layout || !bindings) { return PAL_RESULT_OUT_OF_MEMORY; @@ -6887,7 +6841,10 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout) { DescriptorSetLayout* vkLayout = (DescriptorSetLayout*)layout; - s_Vk.destroyDescriptorSetLayout(vkLayout->device->handle, vkLayout->handle, &s_Vk.allocateVkator); + s_Vk.destroyDescriptorSetLayout( + vkLayout->device->handle, + vkLayout->handle, + &s_Vk.allocateVkator); palFree(s_Vk.allocator, layout); } @@ -7082,7 +7039,6 @@ PalResult PAL_CALL updateDescriptorSetVk( tlasInfo->pNext = nullptr; write->pNext = tlasInfo; - } else { VkDescriptorImageInfo* imageInfo = &imageInfos[imageIndex++]; ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; @@ -7131,10 +7087,8 @@ PalResult PAL_CALL createPipelineLayoutVk( VkDescriptorSetLayout* descriptorLayouts = nullptr; layout = palAllocate(s_Vk.allocator, sizeof(PipelineLayout), 0); - pushConstants = palAllocate( - s_Vk.allocator, - sizeof(VkPushConstantRange) * info->pushConstantRangeCount, - 0); + pushConstants = + palAllocate(s_Vk.allocator, sizeof(VkPushConstantRange) * info->pushConstantRangeCount, 0); descriptorLayouts = palAllocate( s_Vk.allocator, @@ -7158,8 +7112,7 @@ PalResult PAL_CALL createPipelineLayoutVk( range->offset = info->pushConstantRanges[i].offset; for (int j = 0; j < info->pushConstantRanges[i].shaderStageCount; j++) { - VkShaderStageFlags bit = - shaderStageToVK(info->pushConstantRanges[i].shaderStages[j]); + VkShaderStageFlags bit = shaderStageToVK(info->pushConstantRanges[i].shaderStages[j]); range->stageFlags |= bit; } } @@ -7804,7 +7757,8 @@ PalResult PAL_CALL createRayTracingPipelineVk( // get alignVked region size Uint32 raygenAlignedRegionSize = alignVk(raygenRegionSize, groupBaseAlignment); - Uint32 missAlignedRegionSize = alignVk(missRegionSize, groupBaseAlignment);; + Uint32 missAlignedRegionSize = alignVk(missRegionSize, groupBaseAlignment); + ; Uint32 hitAlignedRegionSize = alignVk(hitRegionSize, groupBaseAlignment); Uint32 callableAligneRegionSize = alignVk(callableRegionSize, groupBaseAlignment); @@ -7822,7 +7776,9 @@ PalResult PAL_CALL createRayTracingPipelineVk( bufCreateInfo.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.allocateVkator, &sbt->buffer); + result = + s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.allocateVkator, &sbt->buffer); + if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); @@ -7901,28 +7857,19 @@ PalResult PAL_CALL createRayTracingPipelineVk( // miss for (int i = 0; i < numMiss; i++) { - memcpy( - dstPtr + missOffset + i * stride, - srcPtr + i * groupHandleSize, - groupHandleSize); + memcpy(dstPtr + missOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); } srcPtr += numMiss * groupHandleSize; // hit for (int i = 0; i < numHit; i++) { - memcpy( - dstPtr + hitOffset + i * stride, - srcPtr + i * groupHandleSize, - groupHandleSize); + memcpy(dstPtr + hitOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); } srcPtr += numHit * groupHandleSize; // callable for (int i = 0; i < numCallable; i++) { - memcpy( - dstPtr + callableOffset + i * stride, - srcPtr + i * groupHandleSize, - groupHandleSize); + memcpy(dstPtr + callableOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); } srcPtr += numCallable * groupHandleSize; diff --git a/src/opengl/pal_opengl_linux.c b/src/opengl/pal_opengl_linux.c index 89661ea9..b1f2bd2f 100644 --- a/src/opengl/pal_opengl_linux.c +++ b/src/opengl/pal_opengl_linux.c @@ -361,7 +361,6 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) s_GL.maxContextData = 16; // initial size s_GL.contextData = palAllocate(s_GL.allocator, sizeof(ContextData) * s_GL.maxContextData, 0); - if (!s_GL.maxContextData) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -533,7 +532,6 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) EGLint pBufferAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; surface = s_GL.eglCreatePbufferSurface(tmpDisplay, config, pBufferAttribs); - if (surface == EGL_NO_SURFACE) { palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; @@ -544,12 +542,10 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) if (s_GL.apiType == EGL_OPENGL_API) { EGLint contextAttrib[] = {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_CONTEXT_MINOR_VERSION, 1, EGL_NONE}; - context = s_GL.eglCreateContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); } else { EGLint contextAttrib[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - context = s_GL.eglCreateContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); } @@ -618,7 +614,6 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) // part of the core API s_GL.info.extensions |= PAL_GL_EXTENSION_MULTISAMPLE; - if (type & EGL_OPENGL_ES_BIT || type & EGL_OPENGL_ES2_BIT) { s_GL.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; } @@ -640,7 +635,6 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) } s_GL.eglMakeCurrent(tmpDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - s_GL.eglDestroyContext(tmpDisplay, context); s_GL.eglDestroySurface(tmpDisplay, surface); @@ -725,9 +719,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( EGLConfig config = eglConfigs[i]; s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_SURFACE_TYPE, &surfaceType); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_RENDERABLE_TYPE, &renderable); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_COLOR_BUFFER_TYPE, &colorType); // we need only opengl API configs @@ -765,19 +757,12 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( EGLint depthBits, stencilBits, samples; s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_RED_SIZE, &redBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_GREEN_SIZE, &greenBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_BLUE_SIZE, &blueBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_ALPHA_SIZE, &alphaBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_DEPTH_SIZE, &depthBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_STENCIL_SIZE, &stencilBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_SAMPLES, &samples); - if (samples == 0) { samples = 1; } @@ -1045,7 +1030,6 @@ PalResult PAL_CALL palCreateGLContext( // create context EGLContext context = s_GL.eglCreateContext(s_GL.display, config, share, attribs); - if (context == EGL_NO_CONTEXT) { EGLint error = s_GL.eglGetError(); if (error == EGL_BAD_CONFIG) { @@ -1142,9 +1126,8 @@ PalResult PAL_CALL palMakeContextCurrent( return PAL_RESULT_INVALID_GL_CONTEXT; } - EGLint ret = - s_GL.eglMakeCurrent(s_GL.display, data->surface, data->surface, (EGLConfig)context); - + EGLint ret; + ret = s_GL.eglMakeCurrent(s_GL.display, data->surface, data->surface, (EGLConfig)context); if (!ret) { EGLint error = s_GL.eglGetError(); if (error == EGL_BAD_CONTEXT) { diff --git a/src/opengl/pal_opengl_win32.c b/src/opengl/pal_opengl_win32.c index 44809d34..d7791292 100644 --- a/src/opengl/pal_opengl_win32.c +++ b/src/opengl/pal_opengl_win32.c @@ -378,8 +378,8 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) Int32 pixelFormat = s_Gdi.choosePixelFormat(s_Wgl.hdc, &pfd); s_Gdi.setPixelFormat(s_Wgl.hdc, pixelFormat, &pfd); - s_Wgl.context = s_Wgl.wglCreateContext(s_Wgl.hdc); + if (!s_Wgl.wglMakeCurrent(s_Wgl.hdc, s_Wgl.context)) { DWORD error = GetLastError(); palSetLastPlatformError(error); diff --git a/src/pal_core.c b/src/pal_core.c index 9981ace5..2816535f 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -147,7 +147,6 @@ static inline LogTLSData* getLogTlsData() if (!data) { data = palAllocate(nullptr, sizeof(LogTLSData), 0); memset(data, 0, sizeof(LogTLSData)); - // create TLS if it has not been created #ifdef _WIN32 if (s_TlsID == 0) { @@ -158,7 +157,6 @@ static inline LogTLSData* getLogTlsData() } else { // update the TLS using atomic operations to avoid thread race LONG prev = InterlockedCompareExchange((volatile LONG*)&s_TlsID, (LONG)TLSIndex, 0); - if (prev != 0) { // Another thread has already set this, // destroy the tls index @@ -236,7 +234,6 @@ void palSetLastPlatformError(Uint32 e) { LogTLSData* data = getLogTlsData(); memset(data->platformResultDesc, 0, PAL_LOG_MSG_SIZE); - if (e == 0) { return; } diff --git a/src/pal_event.c b/src/pal_event.c index 251a19cc..eed4454f 100644 --- a/src/pal_event.c +++ b/src/pal_event.c @@ -122,7 +122,6 @@ PalResult PAL_CALL palCreateEventDriver( // we create a default event queue data QueueData* queueData = nullptr; queueData = palAllocate(info->allocator, sizeof(QueueData), 0); - if (!queueData) { palFree(info->allocator, queue); palFree(info->allocator, driver); diff --git a/src/system/pal_system_win32.c b/src/system/pal_system_win32.c index b40ba1b4..183ba674 100644 --- a/src/system/pal_system_win32.c +++ b/src/system/pal_system_win32.c @@ -270,7 +270,6 @@ PalResult PAL_CALL palGetCPUInfo( } BOOL ret = GetLogicalProcessorInformationEx(RelationAll, buffer, &len); - if (!ret) { palFree(allocator, buffer); DWORD error = GetLastError(); diff --git a/src/thread/pal_thread_win32.c b/src/thread/pal_thread_win32.c index 7f03bc17..b1e2c5b1 100644 --- a/src/thread/pal_thread_win32.c +++ b/src/thread/pal_thread_win32.c @@ -117,7 +117,6 @@ PalResult PAL_CALL palCreateThread( data->allocator = info->allocator; HANDLE thread = CreateThread(nullptr, info->stackSize, threadEntryToWin32, data, 0, nullptr); - if (!thread) { // error DWORD error = GetLastError(); @@ -549,7 +548,6 @@ PalResult PAL_CALL palWaitCondVarTimeout( } BOOL ret = SleepConditionVariableCS(&condVar->cv, &mutex->sc, (DWORD)milliseconds); - if (!ret) { DWORD error = GetLastError(); if (error == ERROR_TIMEOUT) { diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index a4e015ea..ba79e128 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -2980,7 +2980,6 @@ static PalResult glxBackend(const int index) // get a matching visual XVisualInfo* visualInfo = s_X11.glxGetVisualFromFBConfig(s_X11.display, fbConfig); - if (!visualInfo) { return PAL_RESULT_INVALID_GL_FBCONFIG; } @@ -3032,7 +3031,6 @@ static PalResult eglXBackend(int index) // get a matching visual info XVisualInfo* visualInfo = s_X11.getVisualInfo(s_X11.display, VisualIDMask, &tmp, &numVisuals); - if (!visualInfo) { return PAL_RESULT_INVALID_GL_FBCONFIG; } @@ -3246,7 +3244,6 @@ static PalWindowState xQueryWindowState(Window xWin) static void xCacheMonitors() { resetMonitorData(); - XRRScreenResources* resources = nullptr; resources = s_X11.getScreenResources(s_X11.display, s_X11.root); @@ -3760,14 +3757,10 @@ static PalResult xInitVideo() // we load GLX s_X11.glxHandle = dlopen("libGL.so.1", RTLD_LAZY); if (s_X11.glxHandle) { - GLXGetProcAddressFn load = nullptr; load = (GLXGetProcAddressFn)dlsym(s_X11.glxHandle, "glXGetProcAddress"); - s_X11.glxGetFBConfigs = (GLXGetFBConfigsFn)load("glXGetFBConfigs"); - s_X11.glxGetFBConfigAttrib = (GLXGetFBConfigAttribFn)load("glXGetFBConfigAttrib"); - s_X11.glxGetVisualFromFBConfig = (GLXGetVisualFromFBConfigFn)load("glXGetVisualFromFBConfig"); } @@ -5045,7 +5038,6 @@ static PalResult xCreateWindow( } s_X11.setWMProtocols(s_X11.display, window, &s_X11Atoms.WM_DELETE_WINDOW, 1); - s_X11.flush(s_X11.display); // attach the window data to the window @@ -6841,9 +6833,7 @@ PalResult wlCreateWindow( if (!(info->style & PAL_WINDOW_STYLE_BORDERLESS)) { struct zxdg_toplevel_decoration_v1* decoration = nullptr; decoration = zxdgGetToplevelDecoration(s_Wl.decorationManager, xdgToplevel); - zxdgToplevelDecorationV1AddListener(decoration, &decorationListener, surface); - zxdgToplevelDecorationV1SetMode(decoration, 2); data->decoration = decoration; } @@ -7186,7 +7176,6 @@ PalResult wlCreateCursor( } cursor->buffer = createShmBuffer(info->width, info->height, info->pixels, true); - if (!cursor->buffer) { palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; diff --git a/src/video/pal_video_win32.c b/src/video/pal_video_win32.c index 6c33906e..9b491d10 100644 --- a/src/video/pal_video_win32.c +++ b/src/video/pal_video_win32.c @@ -799,7 +799,6 @@ static inline PalResult setMonitorMode( } ULONG result = ChangeDisplaySettingsExW(mi.szDevice, &devMode, NULL, settingsFlag, NULL); - if (result == DISP_CHANGE_SUCCESSFUL) { return PAL_RESULT_SUCCESS; } else { @@ -1464,7 +1463,6 @@ PalResult PAL_CALL palGetMonitorInfo( // check for primary monitor HMONITOR primary = nullptr; primary = MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); - if (!primary) { info->primary = false; } @@ -1514,7 +1512,6 @@ PalResult PAL_CALL palEnumerateMonitorModes( // allocate and store tmp monitor modesand check for the interested // fields. monitorModes = palAllocate(s_Video.allocator, sizeof(PalMonitorMode) * MAX_MODE_COUNT, 0); - if (!monitorModes) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -1663,7 +1660,6 @@ PalResult PAL_CALL palSetMonitorOrientation( devMode.dmDisplayOrientation = win32Orientation; ULONG result = ChangeDisplaySettingsExW(mi.szDevice, &devMode, NULL, CDS_RESET, NULL); - if (result == DISP_CHANGE_SUCCESSFUL) { return PAL_RESULT_SUCCESS; @@ -1741,7 +1737,6 @@ PalResult PAL_CALL palCreateWindow( } else { // get primary monitor monitor = (PalMonitor*)MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); - if (!monitor) { DWORD error = GetLastError(); palSetLastPlatformError(error); @@ -2365,7 +2360,6 @@ PalResult PAL_CALL palSetWindowOpacity( } bool ret = SetLayeredWindowAttributes((HWND)window, 0, (BYTE)(opacity * 255), LWA_ALPHA); - if (!ret) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { @@ -2617,7 +2611,8 @@ PalResult PAL_CALL palCreateIcon( void* dibPixels = nullptr; // create dib section - HBITMAP bitmap = + HBITMAP bitmap = nullptr; + bitmap = s_Video .createDIBSection(hdc, (BITMAPINFO*)&bitInfo, DIB_RGB_COLORS, &dibPixels, nullptr, 0); @@ -2734,7 +2729,8 @@ PalResult PAL_CALL palCreateCursor( void* dibPixels = nullptr; // create dib section - HBITMAP bitmap = + HBITMAP bitmap = nullptr; + bitmap = s_Video .createDIBSection(hdc, (BITMAPINFO*)&bitInfo, DIB_RGB_COLORS, &dibPixels, nullptr, 0); @@ -2794,7 +2790,6 @@ PalResult PAL_CALL palCreateCursorFrom( PalCursorType type, PalCursor** outCursor) { - if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; } From 143b840389716442d05b0b02f01544ab96e52ff6 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 17 Mar 2026 21:14:53 +0000 Subject: [PATCH 104/372] format PAL test files --- CHANGELOG.md | 6 +++++- tests/attach_window_test.c | 2 -- tests/char_event_test.c | 2 -- tests/clear_color_test.c | 5 ----- tests/compute_test.c | 1 - tests/custom_decoration_test.c | 4 ---- tests/mesh_test.c | 9 --------- tests/multi_thread_opengl_test.c | 2 -- tests/native_instance_test.c | 1 - tests/native_integration_test.c | 2 -- tests/opengl_context_test.c | 1 - tests/opengl_multi_context_test.c | 1 - tests/ray_tracing_test.c | 1 - tests/triangle_test.c | 18 +----------------- tests/window_test.c | 3 --- 15 files changed, 6 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88abe702..9de24f09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -161,7 +161,11 @@ palJoinThread(thread, &retval); - Added vertex shader/buffer triangle example: see **triangle_test.c** -- Added mesh example: see **mesh_test.c.c** +- Added mesh example: see **mesh_test.c** + +- Added compute example: see **compute_test.c** + +- Added ray tracing example: see **ray_tracing_test.c** ### Notes - No API or ABI changes - existing code remains compatible. diff --git a/tests/attach_window_test.c b/tests/attach_window_test.c index 9b506102..8ed3fdc1 100644 --- a/tests/attach_window_test.c +++ b/tests/attach_window_test.c @@ -250,9 +250,7 @@ bool attachWindowTest() // we are interested in move and close events palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_MOVE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // we listen for key release events to attach and detach the window diff --git a/tests/char_event_test.c b/tests/char_event_test.c index 68bded0a..57897a45 100644 --- a/tests/char_event_test.c +++ b/tests/char_event_test.c @@ -62,9 +62,7 @@ bool charEventTest() // we only neeed PAL_EVENT_KEYCHAR and PAL_EVENT_WINDOW_CLOSE palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYCHAR, PAL_DISPATCH_POLL); bool running = true; diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 7c81d300..af03af20 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -50,7 +50,6 @@ bool clearColorTest() } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); result = palInitVideo(nullptr, eventDriver); @@ -206,7 +205,6 @@ bool clearColorTest() swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); @@ -216,7 +214,6 @@ bool clearColorTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !renderFinishedSemaphores) { @@ -241,7 +238,6 @@ bool clearColorTest() } result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); @@ -250,7 +246,6 @@ bool clearColorTest() } result = palCreateCommandPool(device, queue, &cmdPool); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); diff --git a/tests/compute_test.c b/tests/compute_test.c index 33f5ae93..ad931dce 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -259,7 +259,6 @@ bool computeTest() } result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); diff --git a/tests/custom_decoration_test.c b/tests/custom_decoration_test.c index e57042e3..ae90c316 100644 --- a/tests/custom_decoration_test.c +++ b/tests/custom_decoration_test.c @@ -867,17 +867,13 @@ bool customDecorationTest() } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_DECORATION_MODE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // we use PAL_DISPATCH_CALLBACK for the mouse button to get // real time events which we then use for moving and resizing palSetEventDispatchMode(eventDriver, PAL_EVENT_MOUSE_BUTTONDOWN, PAL_DISPATCH_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_MOUSE_MOVE, PAL_DISPATCH_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_MONITOR_DPI_CHANGED, PAL_DISPATCH_CALLBACK); // tell the video system to use out instance rather diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 44c17811..79f03f47 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -80,7 +80,6 @@ bool meshTest() } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); result = palInitVideo(nullptr, eventDriver); @@ -255,7 +254,6 @@ bool meshTest() swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); @@ -265,7 +263,6 @@ bool meshTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !renderFinishedSemaphores) { @@ -290,7 +287,6 @@ bool meshTest() } result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); @@ -299,7 +295,6 @@ bool meshTest() } result = palCreateCommandPool(device, queue, &cmdPool); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); @@ -374,7 +369,6 @@ bool meshTest() shaderCreateInfo.stage = PAL_SHADER_STAGE_MESH; result = palCreateShader(device, &shaderCreateInfo, &meshShader); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create mesh shader: %s", error); @@ -403,7 +397,6 @@ bool meshTest() shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; result = palCreateShader(device, &shaderCreateInfo, &fragmentShader); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fragment shader: %s", error); @@ -415,7 +408,6 @@ bool meshTest() // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); @@ -471,7 +463,6 @@ bool meshTest() pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create graphics pipeline: %s", error); diff --git a/tests/multi_thread_opengl_test.c b/tests/multi_thread_opengl_test.c index 80260810..b6bf5787 100644 --- a/tests/multi_thread_opengl_test.c +++ b/tests/multi_thread_opengl_test.c @@ -73,9 +73,7 @@ static void* PAL_CALL eventDriverWorker(void* arg) // video needs window close and resize palSetEventDispatchMode(shared->videoEventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(shared->videoEventDriver, PAL_EVENT_WINDOW_SIZE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(shared->videoEventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // we are done diff --git a/tests/native_instance_test.c b/tests/native_instance_test.c index d7803d7f..960d5002 100644 --- a/tests/native_instance_test.c +++ b/tests/native_instance_test.c @@ -375,7 +375,6 @@ bool nativeInstanceTest() // we set window close to poll palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); bool running = true; diff --git a/tests/native_integration_test.c b/tests/native_integration_test.c index 0ab66aaa..66629edf 100644 --- a/tests/native_integration_test.c +++ b/tests/native_integration_test.c @@ -239,7 +239,6 @@ void setWindowTitleWayland(PalWindowHandleInfoEx* windowInfo) (wl_proxy_marshal_flags_fn)dlsym(s_WaylandLib, "wl_proxy_marshal_flags"); s_wl_proxy_get_version = (wl_proxy_get_version_fn)dlsym(s_WaylandLib, "wl_proxy_get_version"); - s_wl_display_flush = (wl_display_flush_fn)dlsym(s_WaylandLib, "wl_display_flush"); struct xdg_toplevel* toplevel = nullptr; @@ -372,7 +371,6 @@ bool nativeIntegrationTest() // we set window close to poll palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // set the window title using native APIs diff --git a/tests/opengl_context_test.c b/tests/opengl_context_test.c index 62d42a45..75dd067b 100644 --- a/tests/opengl_context_test.c +++ b/tests/opengl_context_test.c @@ -196,7 +196,6 @@ bool openglContextTest() // we set window close to poll palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // get window handle. You can use any window from any library diff --git a/tests/opengl_multi_context_test.c b/tests/opengl_multi_context_test.c index 9b6dcf3f..0e2156c1 100644 --- a/tests/opengl_multi_context_test.c +++ b/tests/opengl_multi_context_test.c @@ -196,7 +196,6 @@ bool openglMultiContextTest() // we set window close to poll palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // get window handle. You can use any window from any library diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 01292112..b28d8c5b 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -794,7 +794,6 @@ bool rayTracingTest() writeInfos[0].imageViewInfo = nullptr; writeInfos[0].tlasInfo = nullptr; - writeInfos[1].binding = 1; writeInfos[1].tlasInfo = &descriptorTlasInfo; writeInfos[1].descriptorSet = descriptorSet; diff --git a/tests/triangle_test.c b/tests/triangle_test.c index b7d2d15a..cc4aab00 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -218,7 +218,6 @@ bool triangleTest() // create a swapchain with the graphics queue PalSwapchainCapabilities swapchainCaps = {0}; result = palQuerySwapchainCapabilities(device, &gfxWindow, &swapchainCaps); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to query swapchain capabilities: %s", error); @@ -248,7 +247,6 @@ bool triangleTest() swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); @@ -258,7 +256,6 @@ bool triangleTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !renderFinishedSemaphores) { @@ -283,7 +280,6 @@ bool triangleTest() } result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); @@ -292,7 +288,6 @@ bool triangleTest() } result = palCreateCommandPool(device, queue, &cmdPool); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); @@ -350,7 +345,6 @@ bool triangleTest() bufferCreateInfo.size = sizeof(vertices); bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve - result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -360,7 +354,6 @@ bool triangleTest() bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create staging buffer: %s", error); @@ -432,7 +425,6 @@ bool triangleTest() // map the staging buffer and upload the vertices void* ptr = nullptr; result = palMapMemory(device, stagingBufferMemory, 0, sizeof(vertices), &ptr); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map memory: %s", error); @@ -524,7 +516,6 @@ bool triangleTest() shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; result = palCreateShader(device, &shaderCreateInfo, &vertexShader); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create vertex shader: %s", error); @@ -553,7 +544,6 @@ bool triangleTest() shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; result = palCreateShader(device, &shaderCreateInfo, &fragmentShader); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fragment shader: %s", error); @@ -565,7 +555,6 @@ bool triangleTest() // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); @@ -639,7 +628,6 @@ bool triangleTest() pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create graphics pipeline: %s", error); @@ -683,10 +671,6 @@ bool triangleTest() scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; - PalDrawData drawData = {0}; - drawData.vertexCount = 3; - drawData.instanceCount = 1; - while (running) { // update the video system to push video events palUpdateVideo(); @@ -855,7 +839,7 @@ bool triangleTest() return false; } - result = palCmdDraw(cmdBuffer, &drawData); + result = palCmdDraw(cmdBuffer, 3, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); diff --git a/tests/window_test.c b/tests/window_test.c index 4b2b554b..8848d7e5 100644 --- a/tests/window_test.c +++ b/tests/window_test.c @@ -188,15 +188,12 @@ bool windowTest() // we set window close to poll palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // we set callback mode for modal begin and end. Since we want to capture // that instantly palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_MODAL_BEGIN, PAL_DISPATCH_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_MODAL_END, PAL_DISPATCH_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_DECORATION_MODE, PAL_DISPATCH_POLL); // initialize the video system. We pass the event driver to recieve video From b6fae86459192e016217c44c2e79135df78a4b55 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 18 Mar 2026 00:18:24 +0000 Subject: [PATCH 105/372] add more command recording functions --- include/pal/pal_graphics.h | 284 ++++++++++++++++++++++++++++++++++-- src/graphics/pal_graphics.c | 140 +++++++++++++++++- src/graphics/pal_vulkan.c | 247 +++++++++++++++++++++++++++++++ 3 files changed, 653 insertions(+), 18 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 0107d004..abc23147 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -802,6 +802,23 @@ typedef enum { PAL_POLYGON_MODE_LINE } PalPolygonMode; +/** + * @enum PalStencilFaceFlags + * @brief Stencil face flags. Multiple stencil face flags can be OR'ed together using bitwise + * OR operator (`|`). + * + * All tencil face flags follow the format `PAL_STENCIL_FACE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_STENCIL_FACE_FRONT = PAL_BIT(0), + PAL_STENCIL_FACE_BACK = PAL_BIT(1), + PAL_STENCIL_FACE_BOTH = PAL_STENCIL_FACE_FRONT | PAL_STENCIL_FACE_BACK +} PalStencilFaceFlags; + /** * @enum PalVertexType * @brief Vertex attribute types. @@ -2101,6 +2118,24 @@ typedef struct { PalImageViewUsages usages; /**< (eg. PAL_IMAGE_VIEW_USAGE_COLOR).*/ } PalImageViewCreateInfo; +/** + * @struct PalSamplerCreateInfo + * @brief Creation parameters for a sampler. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 startMipLevel; + Uint32 mipLevelCount; + Uint32 startArrayLayer; + Uint32 layerArrayCount; + PalImageViewType type; + PalImageViewUsages usages; +} PalSamplerCreateInfo; + /** * @struct PalSwapchainCreateInfo * @brief Creation parameters for a swapchain. @@ -2787,6 +2822,15 @@ typedef struct { */ PalResult PAL_CALL (*resetCommandBuffer)(PalCommandBuffer* cmdBuffer); + /** + * Backend implementation of ::palSubmitCommandBuffer. + * + * Must obey the rules and semantics documented in palSubmitCommandBuffer(). + */ + PalResult PAL_CALL (*submitCommandBuffer)( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + /** * Backend implementation of ::palCmdBegin. * @@ -3139,13 +3183,62 @@ typedef struct { const void* value); /** - * Backend implementation of ::palSubmitCommandBuffer. + * Backend implementation of ::palCmdSetCullMode. * - * Must obey the rules and semantics documented in palSubmitCommandBuffer(). + * Must obey the rules and semantics documented in palCmdSetCullMode(). */ - PalResult PAL_CALL (*submitCommandBuffer)( - PalQueue* queue, - PalCommandBufferSubmitInfo* info); + PalResult PAL_CALL (*cmdSetCullMode)( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + + /** + * Backend implementation of ::palCmdSetFrontFace. + * + * Must obey the rules and semantics documented in palCmdSetFrontFace(). + */ + PalResult PAL_CALL (*cmdSetFrontFace)( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + + /** + * Backend implementation of ::palCmdSetPrimitiveTopology. + * + * Must obey the rules and semantics documented in palCmdSetPrimitiveTopology(). + */ + PalResult PAL_CALL (*cmdSetPrimitiveTopology)( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + + /** + * Backend implementation of ::palCmdSetDepthTestEnable. + * + * Must obey the rules and semantics documented in palCmdSetDepthTestEnable(). + */ + PalResult PAL_CALL (*cmdSetDepthTestEnable)( + PalCommandBuffer* cmdBuffer, + bool enable); + + /** + * Backend implementation of ::palCmdSetDepthWriteEnable. + * + * Must obey the rules and semantics documented in palCmdSetDepthWriteEnable(). + */ + PalResult PAL_CALL (*cmdSetDepthWriteEnable)( + PalCommandBuffer* cmdBuffer, + bool enable); + + /** + * Backend implementation of ::palCmdSetStencilOp. + * + * Must obey the rules and semantics documented in palCmdSetStencilOp(). + */ + PalResult PAL_CALL (*cmdSetStencilOp)( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); /** * Backend implementation of ::palCreateAccelerationstructure. @@ -4157,6 +4250,21 @@ PAL_API PalResult PAL_CALL palCreateImageView( */ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); +// TODO: docs +PAL_API PalResult PAL_CALL palCreateImageView( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + +// TODO: docs +PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); + +// TODO: docs +PAL_API PalResult PAL_CALL palGetImageInfo( + PalImage* image, + PalImageInfo* info); + /** * @brief Get swapchain feature capabilites or limits about a device against a window. * @@ -4703,6 +4811,28 @@ PAL_API void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer); */ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); +/** + * @brief Submit a command buffer to the provided queue for execution. + * + * The graphics system must be initialized before this call. The command buffer must not + * be in a recording state. + * + * @param[in] queue Queue to execute the command buffer. + * @param[in] info Pointer to a PalCommandBufferSubmitInfo struct that specifies parameters. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `queue` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palSubmitCommandBuffer( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + /** * @brief Begin recording commands to the provided command buffer. * @@ -5580,26 +5710,150 @@ PAL_API PalResult PAL_CALL palCmdPushConstants( const void* value); /** - * @brief Submit a command buffer to the provided queue for execution. + * @brief Set the cull mode for the provided command buffer. * - * The graphics system must be initialized before this call. The command buffer must not - * be in a recording state. + * The graphics system must be initialized before this call. * - * @param[in] queue Queue to execute the command buffer. - * @param[in] info Pointer to a PalCommandBufferSubmitInfo struct that specifies parameters. - * Must not be nullptr. + * `PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE` must be supported and enabled by the device if not, + * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] cullMode Cull mode to set. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safe if `queue` is externally synchronized. + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics */ -PAL_API PalResult PAL_CALL palSubmitCommandBuffer( - PalQueue* queue, - PalCommandBufferSubmitInfo* info); +PAL_API PalResult PAL_CALL palCmdSetCullMode( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + +/** + * @brief Set the front face for the provided command buffer. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE` must be supported and enabled by the device if not, + * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] frontFace Front face to set. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palCmdSetFrontFace( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + +/** + * @brief Set the primitive topology for the provided command buffer. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY` must be supported and enabled by the device + * if not, this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] topology Topology to set. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palCmdSetPrimitiveTopology( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + +/** + * @brief Set depth test enable for the provided command buffer. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE` must be supported and enabled by the device + * if not, this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] enable True to enable. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palCmdSetDepthTestEnable( + PalCommandBuffer* cmdBuffer, + bool enable); + +/** + * @brief Set depth write enable for the provided command buffer. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE` must be supported and enabled by the device + * if not, this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] enable True to enable. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palCmdSetDepthWriteEnable( + PalCommandBuffer* cmdBuffer, + bool enable); + +/** + * @brief Set depth stencil operation for the provided command buffer. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP` must be supported and enabled by the device + * if not, this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] faceMask Bitmask specifying faces to apply the stencil to. + * @param[in] failOp Stencil operation to perform when stencil fails. + * @param[in] passOp Stencil operation to perform when stencil and depth passes. + * @param[in] depthFailOp Stencil operation to perform when stencil passes but depth fails. + * @param[in] compareOp Compare operation for stencil tests. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palCmdSetStencilOp( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); /** * @brief Create an acceleration structure. diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 9ed7a092..80eafc6b 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -303,6 +303,10 @@ void PAL_CALL freeCommandBufferVk(PalCommandBuffer* buffer); PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer); +PalResult PAL_CALL submitCommandBufferVk( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + PalResult PAL_CALL cmdBeginVk( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); @@ -494,9 +498,33 @@ PalResult PAL_CALL cmdPushConstantsVk( Uint32 size, const void* value); -PalResult PAL_CALL submitCommandBufferVk( - PalQueue* queue, - PalCommandBufferSubmitInfo* info); +PalResult PAL_CALL cmdSetCullModeVk( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + +PalResult PAL_CALL cmdSetFrontFaceVk( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + +PalResult PAL_CALL cmdSetPrimitiveTopologyVk( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + +PalResult PAL_CALL cmdSetDepthTestEnableVk( + PalCommandBuffer* cmdBuffer, + bool enable); + +PalResult PAL_CALL cmdSetDepthWriteEnableVk( + PalCommandBuffer* cmdBuffer, + bool enable); + +PalResult PAL_CALL cmdSetStencilOpVk( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); PalResult PAL_CALL createAccelerationstructureVk( PalDevice* device, @@ -902,6 +930,12 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->cmdTraceRaysIndirect || !backend->cmdBindDescriptorSet || !backend->cmdPushConstants || + !backend->cmdSetCullMode || + !backend->cmdSetFrontFace || + !backend->cmdSetPrimitiveTopology || + !backend->cmdSetDepthTestEnable || + !backend->cmdSetDepthWriteEnable || + !backend->cmdSetStencilOp || // acceleration structure !backend->createAccelerationstructure || @@ -2476,6 +2510,106 @@ PalResult PAL_CALL palCmdPushConstants( ->cmdPushConstants(cmdBuffer, layout, shaderStageCount, shaderStages, offset, size, value); } +PalResult PAL_CALL palCmdSetCullMode( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->cmdSetCullMode(cmdBuffer, cullMode); +} + +PalResult PAL_CALL palCmdSetFrontFace( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->cmdSetFrontFace(cmdBuffer, frontFace); +} + +PalResult PAL_CALL palCmdSetPrimitiveTopology( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->cmdSetPrimitiveTopology(cmdBuffer, topology); +} + +PalResult PAL_CALL palCmdSetDepthTestEnable( + PalCommandBuffer* cmdBuffer, + bool enable) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->cmdSetDepthTestEnable(cmdBuffer, enable); +} + +PalResult PAL_CALL palCmdSetDepthWriteEnable( + PalCommandBuffer* cmdBuffer, + bool enable) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->cmdSetDepthWriteEnable(cmdBuffer, enable); +} + +PalResult PAL_CALL palCmdSetStencilOp( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->cmdSetStencilOp( + cmdBuffer, + faceMask, + failOp, + passOp, + depthFailOp, + compareOp); +} + // ================================================== // Acceleration Structure // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 9f0a1e5e..53f603ff 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -260,6 +260,15 @@ typedef struct { PFN_vkCmdEndRendering cmdEndRendering; PFN_vkCmdPipelineBarrier2 cmdPipelineBarrier; PFN_vkQueueSubmit2 queueSubmit; + + // dynamic states + PFN_vkCmdSetCullMode cmdSetCullMode; + PFN_vkCmdSetFrontFace cmdSetFrontFace; + PFN_vkCmdSetPrimitiveTopology cmdSetPrimitiveTopology; + + PFN_vkCmdSetDepthTestEnable cmdSetDepthTestEnable; + PFN_vkCmdSetDepthWriteEnable cmdSetDepthWriteEnable; + PFN_vkCmdSetStencilOp cmdSetStencilOp; } Device; typedef struct { @@ -3916,6 +3925,92 @@ PalResult PAL_CALL createDeviceVk( device->handle, "vkQueueSubmit2KHR"); } + + // dynamic states + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { + device->cmdSetCullMode = + (PFN_vkCmdSetCullMode)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdSetCullMode"); + + if (!device->cmdSetCullMode) { + device->cmdSetCullMode = + (PFN_vkCmdSetCullModeEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdSetCullModeEXT"); + } + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { + device->cmdSetFrontFace = + (PFN_vkCmdSetFrontFace)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetFrontFace"); + + if (!device->cmdSetFrontFace) { + device->cmdSetFrontFace = + (PFN_vkCmdSetFrontFaceEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetFrontFaceEXT"); + } + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { + device->cmdSetPrimitiveTopology = + (PFN_vkCmdSetPrimitiveTopology)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetPrimitiveTopology"); + + if (!device->cmdSetPrimitiveTopology) { + device->cmdSetPrimitiveTopology = + (PFN_vkCmdSetPrimitiveTopologyEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetPrimitiveTopologyEXT"); + } + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { + device->cmdSetDepthTestEnable = + (PFN_vkCmdSetDepthTestEnable)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetDepthTestEnable"); + + if (!device->cmdSetDepthTestEnable) { + device->cmdSetDepthTestEnable = + (PFN_vkCmdSetDepthTestEnableEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetDepthTestEnableEXT"); + } + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { + device->cmdSetDepthWriteEnable = + (PFN_vkCmdSetDepthWriteEnable)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetDepthWriteEnable"); + + if (!device->cmdSetDepthWriteEnable) { + device->cmdSetDepthWriteEnable = + (PFN_vkCmdSetDepthWriteEnableEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetDepthWriteEnableEXT"); + } + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { + device->cmdSetStencilOp = + (PFN_vkCmdSetStencilOp)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetStencilOp"); + + if (!device->cmdSetStencilOp) { + device->cmdSetStencilOp = + (PFN_vkCmdSetStencilOpEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetStencilOpEXT"); + } + } + // clang-format on palFree(s_Vk.allocator, queueProps); @@ -6509,6 +6604,158 @@ PalResult PAL_CALL cmdPushConstantsVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL cmdSetCullModeVk( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkCullModeFlags vkCullMode = 0; + switch (cullMode) { + case PAL_CULL_MODE_BACK: + vkCullMode = VK_CULL_MODE_BACK_BIT; + + case PAL_CULL_MODE_FRONT: + vkCullMode = VK_CULL_MODE_FRONT_BIT; + + case PAL_CULL_MODE_NONE: + vkCullMode = VK_CULL_MODE_NONE; + } + vkCmdBuffer->device->cmdSetCullMode(vkCmdBuffer->handle, vkCullMode); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetFrontFaceVk( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkFrontFace vkFrontFace = 0; + switch (frontFace) { + case PAL_FRONT_FACE_CLOCKWISE: + vkFrontFace = VK_FRONT_FACE_CLOCKWISE; + + case PAL_FRONT_FACE_COUNTER_CLOCKWISE: + vkFrontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + } + vkCmdBuffer->device->cmdSetFrontFace(vkCmdBuffer->handle, vkFrontFace); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetPrimitiveTopologyVk( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkPrimitiveTopology vkTopology = 0; + switch (topology) { + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { + vkTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { + vkTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_LIST: { + vkTopology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP: { + vkTopology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_POINT_LIST: { + vkTopology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + break; + } + } + vkCmdBuffer->device->cmdSetPrimitiveTopology(vkCmdBuffer->handle, vkTopology); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetDepthTestEnableVk( + PalCommandBuffer* cmdBuffer, + bool enable) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + vkCmdBuffer->device->cmdSetDepthTestEnable(vkCmdBuffer->handle, enable); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetDepthWriteEnableVk( + PalCommandBuffer* cmdBuffer, + bool enable) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + vkCmdBuffer->device->cmdSetDepthWriteEnable(vkCmdBuffer->handle, enable); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetStencilOpVk( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp) +{ + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkStencilFaceFlags faceFlags = 0; + if (faceMask & PAL_STENCIL_FACE_BACK) { + faceFlags |= VK_STENCIL_FACE_BACK_BIT; + } + + if (faceMask & PAL_STENCIL_FACE_FRONT) { + faceFlags |= VK_STENCIL_FACE_FRONT_BIT; + } + + VkStencilOp vkFailOp = stencilOpToVk(failOp); + VkStencilOp vkPassOp = stencilOpToVk(passOp); + VkStencilOp vkDepthFailOp = stencilOpToVk(depthFailOp); + VkCompareOp vkCompareOp = compareOpToVk(compareOp); + + vkCmdBuffer->device->cmdSetStencilOp( + vkCmdBuffer->handle, + faceFlags, + failOp, + passOp, + depthFailOp, + compareOp); + + return PAL_RESULT_SUCCESS; +} + // ================================================== // Acceleration Structure // ================================================== From 98c0160a91bca6001dcf2195a66a4dd3bd925c1a Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 18 Mar 2026 15:06:11 +0000 Subject: [PATCH 106/372] finish ray tracing feature --- include/pal/pal_graphics.h | 191 ++++++++++++++++++++++++++++++++---- src/graphics/pal_graphics.c | 57 +++++++++++ src/graphics/pal_vulkan.c | 62 ++++++++++-- tests/ray_tracing_test.c | 4 + 4 files changed, 288 insertions(+), 26 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index abc23147..6dc86c04 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -669,6 +669,72 @@ typedef enum { PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY, } PalImageViewType; +/** + * @enum PalFilterMode + * @brief Filter modes. + * + * All filter modes follow the format `PAL_FILTER_MODE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_FILTER_MODE_NEAREST, + PAL_FILTER_MODE_LINEAR +} PalFilterMode; + +/** + * @enum PalSamplerMipmapMode + * @brief Sampler mipmap modes. + * + * All sampler mipmap modes follow the format `PAL_SAMPLER_MIPMAP_MODE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_SAMPLER_MIPMAP_MODE_NEAREST, + PAL_SAMPLER_MIPMAP_MODE_LINEAR +} PalSamplerMipmapMode; + +/** + * @enum PalSamplerAddressMode + * @brief Sampler address modes. + * + * All sampler address modes follow the format `PAL_SAMPLER_ADDRESS_MODE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_SAMPLER_ADDRESS_MODE_REPEAT, + PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, + PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, + PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER +} PalSamplerAddressMode; + +/** + * @enum PalBorderColor + * @brief Border color. + * + * All border colors follow the format `PAL_BORDER_COLOR_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, + PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK, + PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK, + PAL_BORDER_COLOR_INT_OPAQUE_BLACK, + PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE, + PAL_BORDER_COLOR_INT_OPAQUE_WHITE +} PalBorderColor; + /** * @enum PalSwapchainFormat * @brief swapchain format types. @@ -1084,6 +1150,38 @@ typedef enum { PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL } PalAccelerationStructureType; +/** + * @enum PalAccelerationStructureBuildMode + * @brief Acceleration structure build modes. + * + * All acceleration structure build modes follow the format + * `PAL_ACCELERATION_STRUCTURE_BUILD_MODE_**` for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD, + PAL_ACCELERATION_STRUCTURE_BUILD_MODE_UPDATE +} PalAccelerationStructureBuildMode; + +/** + * @enum PalAccelerationStructureBuildHints + * @brief Acceleration structure build hints. Multiple hints can be OR'ed together using + * bitwise OR operator (`|`). Hints can be ignored by the driver. + * + * All acceleration structure build hints follow the format + * `PAL_ACCELERATION_STRUCTURE_BUILD_HINT_**` for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD = PAL_BIT(0), + PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE = PAL_BIT(1), + PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY = PAL_BIT(2) +} PalAccelerationStructureBuildHints; + /** * @enum PalGeometryType * @brief Geometry types. @@ -1889,6 +1987,7 @@ typedef struct { typedef struct { Uint32 accelerationStructureSize; /**< Required acceleration structure size.*/ Uint32 scratchBufferSize; /**< Required scratch buffer size.*/ + Uint32 updateScratchBufferSize; /**< Required scratch buffer size for updates.*/ } PalAccelerationStructureBuildSize; /** @@ -1964,6 +2063,8 @@ typedef struct { typedef struct { PalAccelerationStructureType type; /**< (eg. PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL).*/ Uint32 geometryCount; + PalAccelerationStructureBuildHints buildHints; + PalAccelerationStructureBuildMode buildMode; PalAccelerationStructure* dst; PalAccelerationStructure* src; PalDeviceAddress scratchBufferAddress; @@ -2128,12 +2229,20 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 startMipLevel; - Uint32 mipLevelCount; - Uint32 startArrayLayer; - Uint32 layerArrayCount; - PalImageViewType type; - PalImageViewUsages usages; + bool enableCompare; + bool enableAnisotropy; /**< `PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY` must be supported.*/ + float mipLodBias; + float minLod; + float maxLod; + float maxAnisotropy; + PalFilterMode minFilterMode; + PalFilterMode magFilterMode; + PalSamplerMipmapMode mipmapMode; + PalSamplerAddressMode addressModeU; + PalSamplerAddressMode addressModeV; + PalSamplerAddressMode addressModeW; + PalCompareOp compareOp; + PalBorderColor borderColor; } PalSamplerCreateInfo; /** @@ -2614,6 +2723,23 @@ typedef struct { */ void PAL_CALL (*destroyImageView)(PalImageView* imageView); + /** + * Backend implementation of ::palCreateSampler. + * + * Must obey the rules and semantics documented in palCreateSampler(). + */ + PalResult PAL_CALL (*createSampler)( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler); + + /** + * Backend implementation of ::palDestroySampler. + * + * Must obey the rules and semantics documented in palDestroySampler(). + */ + void PAL_CALL (*destroySampler)(PalSampler* sampler); + /** * Backend implementation of ::palQuerySwapchainCapabilities. * @@ -4250,20 +4376,49 @@ PAL_API PalResult PAL_CALL palCreateImageView( */ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); -// TODO: docs -PAL_API PalResult PAL_CALL palCreateImageView( +/** + * @brief Create a sampler. + * + * The graphics system must be initialized before this call. + * Samplers are immutable so any paramter used to create it cannot will be fixed after + * creation. + * + * @param[in] device Device that creates the sampler. + * @param[in] info Pointer to a PalSamplerCreateInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outSampler Pointer to a PalSampler to recieve the created sampler. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroySampler + */ +PAL_API PalResult PAL_CALL palCreateSampler( PalDevice* device, - PalImage* image, - const PalImageViewCreateInfo* info, - PalImageView** outImageView); - -// TODO: docs -PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); + const PalSamplerCreateInfo* info, + PalSampler** outSampler); -// TODO: docs -PAL_API PalResult PAL_CALL palGetImageInfo( - PalImage* image, - PalImageInfo* info); +/** + * @brief Destroy a sampler. + * + * The graphics system must be initialized before this call. + * If the provided sampler is invalid or nullptr, this function returns + * silently. + * + * @param[in] sampler Sampler to destroy. + * + * Thread safety: Thread safe if the device used to create the sampler is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateSampler + */ +PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); /** * @brief Get swapchain feature capabilites or limits about a device against a window. diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 80eafc6b..7658c252 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -215,6 +215,13 @@ PalResult PAL_CALL createImageViewVk( void PAL_CALL destroyImageViewVk(PalImageView* imageView); +PalResult PAL_CALL createSamplerVk( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler); + +void PAL_CALL destroySamplerVk(PalSampler* sampler); + PalResult PAL_CALL querySwapchainCapabilitiesVk( PalDevice* device, PalGraphicsWindow* window, @@ -679,6 +686,10 @@ static PalGraphicsBackend s_VkBackend = { .createImageView = createImageViewVk, .destroyImageView = destroyImageViewVk, + // sampler + .createSampler = createSamplerVk, + .destroySampler = destroySamplerVk, + // swapchain .querySwapchainCapabilities = querySwapchainCapabilitiesVk, .createSwapchain = createSwapchainVk, @@ -747,6 +758,12 @@ static PalGraphicsBackend s_VkBackend = { .cmdTraceRaysIndirect = cmdTraceRaysIndirectVk, .cmdBindDescriptorSet = cmdBindDescriptorSetVk, .cmdPushConstants = cmdPushConstantsVk, + .cmdSetCullMode = cmdSetCullModeVk, + .cmdSetFrontFace = cmdSetFrontFaceVk, + .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyVk, + .cmdSetDepthTestEnable = cmdSetDepthTestEnableVk, + .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableVk, + .cmdSetStencilOp = cmdSetStencilOpVk, // acceleration structure .createAccelerationstructure = createAccelerationstructureVk, @@ -862,6 +879,10 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->createImageView || !backend->destroyImageView || + // sampler + !backend->createSampler || + !backend->destroySampler || + // swapchain !backend->querySwapchainCapabilities || !backend->createSwapchain || @@ -1518,6 +1539,42 @@ void PAL_CALL palDestroyImageView(PalImageView* imageView) } } +// ================================================== +// Sampler +// ================================================== + +PalResult PAL_CALL palCreateSampler( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outSampler) { + return PAL_RESULT_NULL_POINTER; + } + + PalSampler* sampler = nullptr; + PalResult result; + result = device->backend->createSampler(device, info, &sampler); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + sampler->backend = device->backend; + *outSampler = sampler; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroySampler(PalSampler* sampler) +{ + if (s_Graphics.initialized && sampler) { + sampler->backend->destroySampler(sampler); + } +} + // ================================================== // Swapchain // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 53f603ff..f3641a1c 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2033,7 +2033,8 @@ static void fillVkBuildInfoVk( PalAccelerationStructureBuildInfo* info, Uint32* maxPrimities, VkAccelerationStructureGeometryKHR* geometries, - VkAccelerationStructureKHR as, + VkAccelerationStructureKHR srcAs, + VkAccelerationStructureKHR dstAs, VkAccelerationStructureBuildRangeInfoKHR* rangeInfos, VkAccelerationStructureBuildGeometryInfoKHR* buildInfo) { @@ -2045,7 +2046,7 @@ static void fillVkBuildInfoVk( // fill vulkan geometry struct VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - tmp->flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + tmp->flags = VK_GEOMETRY_OPAQUE_BIT_KHR; // always opaque if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { tmp->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; @@ -2116,10 +2117,30 @@ static void fillVkBuildInfoVk( buildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; } - buildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + // build mode + if (info->buildMode == PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD) { + buildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + } else { + buildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR; + } + + // build hints + buildInfo->flags = 0; + if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD) { + buildInfo->flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; + } + + if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE) { + buildInfo->flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + } + + if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY) { + buildInfo->flags = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; + } + buildInfo->geometryCount = info->geometryCount; - buildInfo->dstAccelerationStructure = as; - buildInfo->flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; + buildInfo->srcAccelerationStructure = srcAs; + buildInfo->dstAccelerationStructure = dstAs; buildInfo->pGeometries = geometries; VkDeviceOrHostAddressKHR scratchData = {0}; @@ -4299,6 +4320,7 @@ PalResult PAL_CALL queryRayTracingCapabilitiesVk( caps->maxPayloadSize = INT32_MAX; // depends on memory caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; + return PAL_RESULT_SUCCESS; } @@ -4805,6 +4827,23 @@ void PAL_CALL destroyImageViewVk(PalImageView* imageView) palFree(s_Vk.allocator, vkImageView); } +// ================================================== +// Sampler +// ================================================== + +PalResult PAL_CALL createSamplerVk( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler) +{ + // TODO: sampler +} + +void PAL_CALL destroySamplerVk(PalSampler* sampler) +{ + // TODO: sampler +} + // ================================================== // Swapchain // ================================================== @@ -5850,8 +5889,14 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( VkAccelerationStructureGeometryKHR* geometries = nullptr; VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; - AccelerationStructure* as = (AccelerationStructure*)info->dst; + AccelerationStructure* tmpAs = (AccelerationStructure*)info->src; + AccelerationStructure* dstAs = (AccelerationStructure*)info->dst; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + + VkAccelerationStructureKHR srcAs = nullptr; + if (tmpAs) { + srcAs = tmpAs->handle; + } geometries = palAllocate( s_Vk.allocator, @@ -5870,7 +5915,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount); memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->geometryCount); - fillVkBuildInfoVk(info, nullptr, geometries, as->handle, rangeInfos, &buildInfo); + fillVkBuildInfoVk(info, nullptr, geometries, srcAs, dstAs->handle, rangeInfos, &buildInfo); const VkAccelerationStructureBuildRangeInfoKHR* tmp[1]; tmp[0] = rangeInfos; vkCmdBuffer->device->cmdBuildAccelerationStructures(vkCmdBuffer->handle, 1, &buildInfo, tmp); @@ -6848,7 +6893,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( memset(maxPrimities, 0, sizeof(Uint32) * info->geometryCount); memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount); - fillVkBuildInfoVk(info, maxPrimities, geometries, nullptr, nullptr, &buildInfo); + fillVkBuildInfoVk(info, maxPrimities, geometries, nullptr, nullptr, nullptr, &buildInfo); VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; @@ -6861,6 +6906,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( size->accelerationStructureSize = sizeInfo.accelerationStructureSize; size->scratchBufferSize = sizeInfo.buildScratchSize; + size->updateScratchBufferSize = sizeInfo.updateScratchSize; palFree(s_Vk.allocator, maxPrimities); palFree(s_Vk.allocator, geometries); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index b28d8c5b..31ad7751 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -458,6 +458,8 @@ bool rayTracingTest() blasBuildInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; blasBuildInfo.geometryCount = 1; blasBuildInfo.geometries = &geometry; + blasBuildInfo.buildHints = PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD; + blasBuildInfo.buildMode = PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD; // get the build sizes for blas PalAccelerationStructureBuildSize buildSizes = {0}; @@ -615,6 +617,8 @@ bool rayTracingTest() tlasBuildInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; tlasBuildInfo.geometryCount = 1; tlasBuildInfo.geometries = &instanceGeometry; + tlasBuildInfo.buildHints = PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD; + tlasBuildInfo.buildMode = PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD; // get the build sizes for tlas Uint32 blasScratchSize = buildSizes.scratchBufferSize; From 1b2738a5c6cba254a58a43eadb15d794f418bfb3 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 18 Mar 2026 23:29:43 +0000 Subject: [PATCH 107/372] start texture rendering test --- CHANGELOG.md | 2 + include/pal/pal_graphics.h | 44 +- src/graphics/pal_graphics.c | 24 +- src/graphics/pal_vulkan.c | 189 +++++- tests/clear_color_test.c | 25 +- tests/mesh_test.c | 33 +- tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 13 +- tests/texture_test.c | 1103 +++++++++++++++++++++++++++++++++++ tests/triangle_test.c | 33 +- 11 files changed, 1391 insertions(+), 79 deletions(-) create mode 100644 tests/texture_test.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 9de24f09..80d491c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -167,6 +167,8 @@ palJoinThread(thread, &retval); - Added ray tracing example: see **ray_tracing_test.c** +- Added texture rendering example: see **texture_test.c** + ### Notes - No API or ABI changes - existing code remains compatible. - Safe upgrade from **v1.3.0** - just rebuild your project after updating. diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 6dc86c04..83d1477b 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2202,8 +2202,8 @@ typedef struct { } PalImageCreateInfo; /** - * @struct PalImageCreateInfo - * @brief Creation parameters for an image view. + * @struct PalImageSubresourceRange + * @brief Subresource range for images and image views. * * Uninitialized fields may result in undefined behavior. * @@ -2215,8 +2215,21 @@ typedef struct { Uint32 mipLevelCount; Uint32 startArrayLayer; Uint32 layerArrayCount; +} PalImageSubresourceRange; + +/** + * @struct PalImageCreateInfo + * @brief Creation parameters for an image view. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { PalImageViewType type; /**< (eg. PAL_IMAGE_VIEW_TYPE_2D).*/ PalImageViewUsages usages; /**< (eg. PAL_IMAGE_VIEW_USAGE_COLOR).*/ + PalImageSubresourceRange subresourceRange; } PalImageViewCreateInfo; /** @@ -3206,13 +3219,14 @@ typedef struct { PalUsageStateInfo* newUsageStateInfo); /** - * Backend implementation of ::palCmdImageViewBarrier. + * Backend implementation of ::palCmdImageBarrier. * - * Must obey the rules and semantics documented in palCmdImageViewBarrier(). + * Must obey the rules and semantics documented in palCmdImageBarrier(). */ - PalResult PAL_CALL (*cmdImageViewBarrier)( + PalResult PAL_CALL (*cmdImageBarrier)( PalCommandBuffer* cmdBuffer, - PalImageView* imageView, + PalImage* image, + PalImageSubresourceRange* subresourceRange, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); @@ -5592,7 +5606,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * * @since 1.4 * @ingroup pal_graphics - * @sa palCmdImageViewBarrier + * @sa palCmdImageBarrier * @sa palCmdBufferBarrier */ PAL_API PalResult PAL_CALL palCmdMemoryBarrier( @@ -5601,18 +5615,19 @@ PAL_API PalResult PAL_CALL palCmdMemoryBarrier( PalUsageStateInfo* newUsageStateInfo); /** - * @brief Insert an image view memory barrier into the command buffer. + * @brief Insert an image memory barrier into the command buffer. * * The graphics system must be initialized before this call. This functions makes memory invisible * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. * - * Example: To make sure an image view has been rendered to fully and prepared for presenting, + * Example: To make sure an image has been rendered to fully and prepared for presenting, * `oldUsageStateInfo.usageState` should be `PAL_USAGE_STATE_UNDEFINED` or `PAL_USAGE_STATE_PRESENT` - * depending on the previous state of the image view. `newUsageStateInfo.usageState` should be + * depending on the previous state of the image. `newUsageStateInfo.usageState` should be * `PAL_USAGE_STATE_PRESENT` to make sure its in present state. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] imageView Image view to set barrier on. + * @param[in] image Image to set barrier on. + * @param[in] subresourceRange Pointer to a PalImageSubresourceRange specifying the image. * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. * @@ -5626,9 +5641,10 @@ PAL_API PalResult PAL_CALL palCmdMemoryBarrier( * @sa palCmdMemoryBarrier * @sa palCmdBufferBarrier */ -PAL_API PalResult PAL_CALL palCmdImageViewBarrier( +PAL_API PalResult PAL_CALL palCmdImageBarrier( PalCommandBuffer* cmdBuffer, - PalImageView* imageView, + PalImage* image, + PalImageSubresourceRange* subresourceRange, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); @@ -5657,7 +5673,7 @@ PAL_API PalResult PAL_CALL palCmdImageViewBarrier( * @since 1.4 * @ingroup pal_graphics * @sa palCmdMemoryBarrier - * @sa palCmdImageViewBarrier + * @sa palCmdImageBarrier */ PAL_API PalResult PAL_CALL palCmdBufferBarrier( PalCommandBuffer* cmdBuffer, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 7658c252..91ef444b 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -447,9 +447,10 @@ PalResult PAL_CALL cmdMemoryBarrierVk( PalUsageStateInfo* oldsUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); -PalResult PAL_CALL cmdImageViewBarrierVk( +PalResult PAL_CALL cmdImageBarrierVk( PalCommandBuffer* cmdBuffer, - PalImageView* imageView, + PalImage* image, + PalImageSubresourceRange* subresourceRange, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); @@ -749,7 +750,7 @@ static PalGraphicsBackend s_VkBackend = { .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectVk, .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountVk, .cmdMemoryBarrier = cmdMemoryBarrierVk, - .cmdImageViewBarrier = cmdImageViewBarrierVk, + .cmdImageBarrier = cmdImageBarrierVk, .cmdBufferBarrier = cmdBufferBarrierVk, .cmdDispatch = cmdDispatchVk, .cmdDispatchBase = cmdDispatchBaseVk, @@ -942,7 +943,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->cmdDrawIndexedIndirect || !backend->cmdDrawIndexedIndirectCount || !backend->cmdMemoryBarrier || - !backend->cmdImageViewBarrier || + !backend->cmdImageBarrier || !backend->cmdBufferBarrier || !backend->cmdDispatch || !backend->cmdDispatchBase || @@ -2400,9 +2401,10 @@ PalResult PAL_CALL palCmdMemoryBarrier( return cmdBuffer->backend->cmdMemoryBarrier(cmdBuffer, oldUsageStateInfo, newUsageStateInfo); } -PalResult PAL_CALL palCmdImageViewBarrier( +PalResult PAL_CALL palCmdImageBarrier( PalCommandBuffer* cmdBuffer, - PalImageView* imageView, + PalImage* image, + PalImageSubresourceRange* subresourceRange, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) { @@ -2410,12 +2412,16 @@ PalResult PAL_CALL palCmdImageViewBarrier( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !imageView || !oldUsageStateInfo || !newUsageStateInfo) { + if (!cmdBuffer || !image ||!subresourceRange || !oldUsageStateInfo || !newUsageStateInfo) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend - ->cmdImageViewBarrier(cmdBuffer, imageView, oldUsageStateInfo, newUsageStateInfo); + return cmdBuffer->backend->cmdImageBarrier( + cmdBuffer, + image, + subresourceRange, + oldUsageStateInfo, + newUsageStateInfo); } PalResult PAL_CALL palCmdBufferBarrier( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index f3641a1c..d968b2d4 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -123,6 +123,8 @@ typedef struct { PFN_vkDestroyImage destroyImage; PFN_vkCreateShaderModule createShader; PFN_vkDestroyShaderModule destroyShader; + PFN_vkCreateSampler createSampler; + PFN_vkDestroySampler destroySampler; PFN_vkCreateCommandPool createCommandPool; PFN_vkDestroyCommandPool destroyCommandPool; @@ -283,6 +285,7 @@ typedef struct { const PalGraphicsBackend* backend; bool belongsToSwapchain; + VkImageAspectFlags aspectMask; Device* device; VkImage handle; PalImageInfo info; @@ -1702,7 +1705,7 @@ static Barrier barrierToVk( barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; return barrier; } @@ -1711,7 +1714,7 @@ static Barrier barrierToVk( barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; return barrier; } @@ -1747,7 +1750,7 @@ static Barrier barrierToVk( barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; return barrier; } @@ -1756,7 +1759,7 @@ static Barrier barrierToVk( barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.layout = VK_IMAGE_LAYOUT_GENERAL; return barrier; } @@ -1765,7 +1768,7 @@ static Barrier barrierToVk( barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; return barrier; } @@ -1774,7 +1777,7 @@ static Barrier barrierToVk( barrier.dstStages = barrier.stages; barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + barrier.layout = VK_IMAGE_LAYOUT_GENERAL; return barrier; } @@ -2245,6 +2248,14 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroyShaderModule"); + s_Vk.createSampler = (PFN_vkCreateSampler)dlsym( + s_Vk.handle, + "vkCreateSampler"); + + s_Vk.destroySampler = (PFN_vkDestroySampler)dlsym( + s_Vk.handle, + "vkDestroySampler"); + s_Vk.getPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)dlsym( s_Vk.handle, "vkGetPhysicalDeviceProperties2"); @@ -4681,6 +4692,16 @@ PalResult PAL_CALL createImageVk( image->info.sampleCount = info->sampleCount; image->info.width = info->width; + // get aspect masks + image->aspectMask = 0; + if (info->usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { + image->aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT; + } + + if (info->usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { + image->aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + } + *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } @@ -4778,10 +4799,10 @@ PalResult PAL_CALL createImageViewVk( createInfo.format = formatToVk(vkImage->info.format); createInfo.image = vkImage->handle; - createInfo.subresourceRange.baseArrayLayer = info->startArrayLayer; - createInfo.subresourceRange.baseMipLevel = info->startMipLevel; - createInfo.subresourceRange.levelCount = info->mipLevelCount; - createInfo.subresourceRange.layerCount = info->layerArrayCount; + createInfo.subresourceRange.baseArrayLayer = info->subresourceRange.startArrayLayer; + createInfo.subresourceRange.baseMipLevel = info->subresourceRange.startMipLevel; + createInfo.subresourceRange.levelCount = info->subresourceRange.mipLevelCount; + createInfo.subresourceRange.layerCount = info->subresourceRange.layerArrayCount; createInfo.viewType = imageViewTypeToVk(info->type); VkImageAspectFlags aspectFlags = 0; @@ -4836,12 +4857,141 @@ PalResult PAL_CALL createSamplerVk( const PalSamplerCreateInfo* info, PalSampler** outSampler) { - // TODO: sampler + VkResult result = VK_SUCCESS; + Sampler* sampler = nullptr; + Device* vkDevice = (Device*)device; + + sampler = palAllocate(s_Vk.allocator, sizeof(Sampler), 0); + if (!sampler) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + VkSamplerCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + createInfo.anisotropyEnable = info->enableAnisotropy; + createInfo.compareEnable = info->enableCompare; + + createInfo.mipLodBias = info->mipLodBias; + createInfo.minLod = info->minLod; + createInfo.maxLod = info->maxLod; + createInfo.maxAnisotropy = info->maxAnisotropy; + createInfo.compareOp = compareOpToVk(info->compareOp); + + // min filter mode + switch (info->minFilterMode) { + case PAL_FILTER_MODE_LINEAR: + createInfo.minFilter = VK_FILTER_LINEAR; + + case PAL_FILTER_MODE_NEAREST: + createInfo.minFilter = VK_FILTER_NEAREST; + } + + // mag filter mode + switch (info->magFilterMode) { + case PAL_FILTER_MODE_LINEAR: + createInfo.magFilter = VK_FILTER_LINEAR; + + case PAL_FILTER_MODE_NEAREST: + createInfo.magFilter = VK_FILTER_NEAREST; + } + + // sampler mipmap mode + switch (info->mipmapMode) { + case PAL_SAMPLER_MIPMAP_MODE_LINEAR: + createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + + case PAL_SAMPLER_MIPMAP_MODE_NEAREST: + createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + } + + // sampler address mode u + switch (info->addressModeU) { + case PAL_SAMPLER_ADDRESS_MODE_REPEAT: + createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + + case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + } + + // sampler address mode v + switch (info->addressModeV) { + case PAL_SAMPLER_ADDRESS_MODE_REPEAT: + createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + + case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + } + + // sampler address mode w + switch (info->addressModeW) { + case PAL_SAMPLER_ADDRESS_MODE_REPEAT: + createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + + case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + } + + // border color + switch (info->borderColor) { + case PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK: + createInfo.addressModeW = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK; + + case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: + createInfo.addressModeW = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + + case PAL_BORDER_COLOR_INT_OPAQUE_BLACK: + createInfo.addressModeW = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK: + createInfo.addressModeW = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + + case PAL_BORDER_COLOR_INT_OPAQUE_WHITE: + createInfo.addressModeW = VK_BORDER_COLOR_INT_OPAQUE_WHITE; + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE: + createInfo.addressModeW = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + } + + result = s_Vk.createSampler( + vkDevice->handle, + &createInfo, + &s_Vk.allocateVkator, + &sampler->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, sampler); + return resultFromVk(result); + } + + sampler->device = vkDevice; + *outSampler = (PalSampler*)sampler; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroySamplerVk(PalSampler* sampler) { - // TODO: sampler + Sampler* vkSampler = (Sampler*)sampler; + s_Vk.destroySampler(vkSampler->device->handle, vkSampler->handle, &s_Vk.allocateVkator); + + palFree(s_Vk.allocator, vkSampler); } // ================================================== @@ -6427,14 +6577,15 @@ PalResult PAL_CALL cmdMemoryBarrierVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdImageViewBarrierVk( +PalResult PAL_CALL cmdImageBarrierVk( PalCommandBuffer* cmdBuffer, - PalImageView* imageView, + PalImage* image, + PalImageSubresourceRange* subresourceRange, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - ImageView* vkImageView = (ImageView*)imageView; + Image* vkImage = (Image*)image; VkImageMemoryBarrier2KHR barrier = {0}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR; @@ -6450,8 +6601,12 @@ PalResult PAL_CALL cmdImageViewBarrierVk( barrier.dstAccessMask = new.access; barrier.newLayout = new.layout; - barrier.image = vkImageView->image->handle; - barrier.subresourceRange = vkImageView->range; + barrier.image = vkImage->handle; + barrier.subresourceRange.aspectMask = vkImage->aspectMask; + barrier.subresourceRange.baseArrayLayer = subresourceRange->startArrayLayer; + barrier.subresourceRange.baseMipLevel = subresourceRange->startMipLevel; + barrier.subresourceRange.layerCount = subresourceRange->layerArrayCount; + barrier.subresourceRange.levelCount = subresourceRange->mipLevelCount; VkDependencyInfo dependencyInfo = {0}; dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index af03af20..cea1130a 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -222,12 +222,12 @@ bool clearColorTest() } PalImageViewCreateInfo imageViewCreateInfo = {0}; - imageViewCreateInfo.layerArrayCount = 1; - imageViewCreateInfo.mipLevelCount = 1; - imageViewCreateInfo.startArrayLayer = 0; - imageViewCreateInfo.startMipLevel = 0; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; + imageViewCreateInfo.subresourceRange.layerArrayCount = 1; + imageViewCreateInfo.subresourceRange.mipLevelCount = 1; + imageViewCreateInfo.subresourceRange.startArrayLayer = 0; + imageViewCreateInfo.subresourceRange.startMipLevel = 0; for (int i = 0; i < imageCount; i++) { // get swapchain image @@ -419,9 +419,17 @@ bool clearColorTest() oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; } - result = palCmdImageViewBarrier( + PalImageSubresourceRange imageRange = {0}; + imageRange.layerArrayCount = 1; + imageRange.mipLevelCount = 1; + imageRange.startArrayLayer = 0; + imageRange.startMipLevel = 0; + + PalImage* image = palGetSwapchainImage(swapchain, index); + result = palCmdImageBarrier( cmdBuffer, - imageViews[index], + image, + &imageRange, &oldUsageStateInfo, &newUsageStateInfo); @@ -454,9 +462,10 @@ bool clearColorTest() // change the state of the image view to make it presentable oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageViewBarrier( + result = palCmdImageBarrier( cmdBuffer, - imageViews[index], + image, + &imageRange, &oldUsageStateInfo, &newUsageStateInfo); diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 79f03f47..de11581b 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -5,6 +5,10 @@ #include +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +#define MAX_FRAMES_IN_FLIGHT 2 + static bool readFile( const char* filename, void* buffer, @@ -28,10 +32,6 @@ static bool readFile( return true; } -#define WINDOW_WIDTH 640 -#define WINDOW_HEIGHT 480 -#define MAX_FRAMES_IN_FLIGHT 2 - static void PAL_CALL onGraphicsDebug( void* userData, PalDebugMessageSeverity severity, @@ -271,12 +271,12 @@ bool meshTest() } PalImageViewCreateInfo imageViewCreateInfo = {0}; - imageViewCreateInfo.layerArrayCount = 1; - imageViewCreateInfo.mipLevelCount = 1; - imageViewCreateInfo.startArrayLayer = 0; - imageViewCreateInfo.startMipLevel = 0; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; + imageViewCreateInfo.subresourceRange.layerArrayCount = 1; + imageViewCreateInfo.subresourceRange.mipLevelCount = 1; + imageViewCreateInfo.subresourceRange.startArrayLayer = 0; + imageViewCreateInfo.subresourceRange.startMipLevel = 0; for (int i = 0; i < imageCount; i++) { // get swapchain image @@ -589,9 +589,17 @@ bool meshTest() oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; } - result = palCmdImageViewBarrier( + PalImageSubresourceRange imageRange = {0}; + imageRange.layerArrayCount = 1; + imageRange.mipLevelCount = 1; + imageRange.startArrayLayer = 0; + imageRange.startMipLevel = 0; + + PalImage* image = palGetSwapchainImage(swapchain, index); + result = palCmdImageBarrier( cmdBuffer, - imageViews[index], + image, + &imageRange, &oldUsageStateInfo, &newUsageStateInfo); @@ -673,9 +681,10 @@ bool meshTest() // change the state of the image view to make it presentable oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageViewBarrier( + result = palCmdImageBarrier( cmdBuffer, - imageViews[index], + image, + &imageRange, &oldUsageStateInfo, &newUsageStateInfo); diff --git a/tests/tests.h b/tests/tests.h index 95a51daf..e468b74e 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -59,5 +59,6 @@ bool rayTracingTest(); bool clearColorTest(); bool triangleTest(); bool meshTest(); +bool textureTest(); #endif // _TESTS_H diff --git a/tests/tests.lua b/tests/tests.lua index 21d313fa..d5627338 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -75,7 +75,8 @@ project "tests" files { "clear_color_test.c", "triangle_test.c", - "mesh_test.c" + "mesh_test.c", + "texture_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 08c2be64..7a34b1b6 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,15 +57,16 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest); - registerTest(computeTest); - registerTest(rayTracingTest); + // registerTest(graphicsTest); + // registerTest(computeTest); + // registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest(clearColorTest); - registerTest(triangleTest); - registerTest(meshTest); + // registerTest(clearColorTest); + // registerTest(triangleTest); + // registerTest(meshTest); + registerTest(textureTest); #endif // runTests(); diff --git a/tests/texture_test.c b/tests/texture_test.c new file mode 100644 index 00000000..002b52be --- /dev/null +++ b/tests/texture_test.c @@ -0,0 +1,1103 @@ + +#include "pal/pal_graphics.h" +#include "pal/pal_video.h" +#include "tests.h" + +#include + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +#define MAX_FRAMES_IN_FLIGHT 2 +#define TEXTURE_WIDTH 128 +#define TEXTURE_HEIGHT 128 +#define CHECKER_SIZE 8 + +static bool readFile( + const char* filename, + void* buffer, + Uint64* size) +{ + FILE* file = fopen(filename, "rb"); + if (!file) { + return false; + } + + fseek(file, 0, SEEK_END); + Uint64 tmpSize = ftell(file); + fseek(file, 0, SEEK_SET); + + if (buffer) { + fread(buffer, 1, (size_t)size, file); + } + + fclose(file); + *size = tmpSize; + return true; +} + +static void createCheckerboardTexture( + Uint32* texture, + Uint32 width, + Uint32 height, + Uint32 checkerSize) +{ + Uint8* pixels = (Uint8*)texture; + for (Int32 y = 0; y < height; ++y) { + for (Int32 x = 0; x < width; ++x) { + Int32 i = (y * width + x) * 4; + int checker = ((x / checkerSize) ^ (y / checkerSize)) & 1; + if (checker) { + pixels[i + 0] = 255; // Red bit + pixels[i + 1] = 0; // Green bit + pixels[i + 2] = 0; // Blue bit + pixels[i + 3] = 255; // Alpha bit + + } else { + pixels[i + 0] = 0; // Red bit + pixels[i + 1] = 255; // Green bit + pixels[i + 2] = 0; // Blue bit + pixels[i + 3] = 255; // Alpha bit + } + } + } +} + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) +{ + palLog(nullptr, msg); +} + +bool textureTest() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Texture Test"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + PalResult result; + PalWindow* window = nullptr; + PalEventDriver* eventDriver = nullptr; + PalGraphicsWindow gfxWindow; + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + + PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* presentCompleteSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images + PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + + PalPipelineLayout* pipelineLayout = nullptr; + PalPipeline* pipeline = nullptr; + PalShader* vertexShader = nullptr; + PalShader* fragmentShader = nullptr; + + PalBuffer* vertexBuffer = nullptr; + PalBuffer* stagingBuffer = nullptr; + PalMemory* vertexBufferMemory = nullptr; + PalMemory* stagingBufferMemory = nullptr; + + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create event driver: %s", error); + return false; + } + + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + + result = palInitVideo(nullptr, eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize video: %s", error); + return false; + } + + PalWindowCreateInfo windowCreateInfo = {0}; + windowCreateInfo.height = WINDOW_HEIGHT; + windowCreateInfo.width = WINDOW_WIDTH; + windowCreateInfo.show = true; + windowCreateInfo.title = "Texture Window"; + + PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); + if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&windowCreateInfo, &window); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create window: %s", error); + return false; + } + + PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); + gfxWindow.display = winHandle.nativeDisplay; + gfxWindow.window = winHandle.nativeWindow; + + PalGraphicsDebugger debugger; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; + + result = palInitGraphics(nullptr, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (adapterCount == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", adapterCount); + + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&adapterCount, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + PalAdapterCapabilities caps; + for (Int32 i = 0; i < adapterCount; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (caps.maxGraphicsQueues == 0) { + continue; + } else { + break; + } + } + + palFree(nullptr, adapters); + if (!adapter) { + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); + return false; + } + + PalAdapterInfo adapterInfo = {0}; + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // create a device + PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + features |= PAL_ADAPTER_FEATURE_FENCE_RESET; + } + + result = palCreateDevice(adapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a graphics command queue + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, &gfxWindow)) { + palLog(nullptr, "Queue cannot present to window"); + return false; + } + + // create a swapchain with the graphics queue + PalSwapchainCapabilities swapchainCaps = {0}; + result = palQuerySwapchainCapabilities(device, &gfxWindow, &swapchainCaps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to query swapchain capabilities: %s", error); + return false; + } + + PalSwapchainCreateInfo swapchainCreateInfo = {0}; + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + swapchainCreateInfo.height = WINDOW_HEIGHT; + swapchainCreateInfo.width = WINDOW_WIDTH; + swapchainCreateInfo.imageArrayLayerCount = 1; + + // rare but possible on andriod + if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { + swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; + } + + if (WINDOW_HEIGHT > swapchainCaps.maxImageHeight) { + swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; + } + + // check if the minimal image count is not good for you + // and increase it but not pass the max count + swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + + result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create swapchain: %s", error); + return false; + } + + // get all swapchain images and create image views for them + Uint32 imageCount = swapchainCreateInfo.imageCount; + imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); + + if (!imageViews || !renderFinishedSemaphores) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; + imageViewCreateInfo.subresourceRange.layerArrayCount = 1; + imageViewCreateInfo.subresourceRange.mipLevelCount = 1; + imageViewCreateInfo.subresourceRange.startArrayLayer = 0; + imageViewCreateInfo.subresourceRange.startMipLevel = 0; + + for (int i = 0; i < imageCount; i++) { + // get swapchain image + // this is fast since the images are cache by PAL + PalImage* image = palGetSwapchainImage(swapchain, i); + if (!image) { + palLog(nullptr, "Failed to get swapchain image"); + } + + result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + } + + result = palCreateCommandPool(device, queue, &cmdPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + // create synchronization objects and command buffers + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateFence(device, true, &inFlightFences[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + result = palAllocateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffers[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate command buffer: %s", error); + return false; + } + } + + // create synchronization objects + for (int i = 0; i < imageCount; i++) { + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + } + + // create vertex and staging buffer + // clang-format off + float vertices[] = { + -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, + + -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.0f, 0.0f, 1.0f}; + // clang-format on + + PalBufferCreateInfo bufferCreateInfo = {0}; + bufferCreateInfo.size = sizeof(vertices); + bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create vertex buffer: %s", error); + return false; + } + + bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send + result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create staging buffer: %s", error); + return false; + } + + // get buffer memory requirement and allocate memory + PalMemoryRequirements vertexBufferMemReq = {0}; + PalMemoryRequirements stagingBufferMemReq = {0}; + + result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + // we need to check if the memory type we want are supported + // but almost every GPU supports a GPU only memory + // and CPU writable memory + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + vertexBufferMemReq.memoryMask, + vertexBufferMemReq.size, + &vertexBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + stagingBufferMemReq.memoryMask, + stagingBufferMemReq.size, + &stagingBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + // bind memory + result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + // map the staging buffer and upload the vertices + void* ptr = nullptr; + result = palMapMemory(device, stagingBufferMemory, 0, sizeof(vertices), &ptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map memory: %s", error); + return false; + } + + memcpy(ptr, vertices, sizeof(vertices)); + palUnmapMemory(device, stagingBufferMemory); + + PalFence* fence = nullptr; + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + // we dont want to load the texture from disk so we will create a + // checkerboard texture and use that rather + Uint32 texture[TEXTURE_WIDTH * TEXTURE_HEIGHT * 4]; + createCheckerboardTexture(texture, TEXTURE_WIDTH, TEXTURE_HEIGHT, CHECKER_SIZE); + + // create image for the texture + PalImage* checkerboard = nullptr; + PalImageCreateInfo imageCreateInfo = {0}; + imageCreateInfo.depthOrArraySize = 1; + imageCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; + imageCreateInfo.mipLevelCount = 1; // simple + imageCreateInfo.sampleCount = PAL_SAMPLE_COUNT_1; // simple + imageCreateInfo.type = PAL_IMAGE_TYPE_2D; + imageCreateInfo.usages = PAL_IMAGE_USAGE_TRANSFER_DST | PAL_IMAGE_USAGE_SAMPLED; + imageCreateInfo.width = TEXTURE_WIDTH; + imageCreateInfo.height = TEXTURE_HEIGHT; + + result = palCreateImage(device, &imageCreateInfo, &checkerboard); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image: %s", error); + return false; + } + + // allocate memory for the image + PalMemoryRequirements imageMemReq = {0}; + result = palGetImageMemoryRequirements(checkerboard, &imageMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image memory requirement: %s", error); + return false; + } + + PalMemory* checkerboardMemory = nullptr; + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + imageMemReq.memoryMask, + imageMemReq.size, + &checkerboardMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory: %s", error); + return false; + } + + result = palBindImageMemory(checkerboard, checkerboardMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind image memory: %s", error); + return false; + } + + // create staging buffer to transfer the data to the image + PalBuffer* imageStagingBuffer = nullptr; + PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; + imageStagingBufferCreateInfo.size = TEXTURE_WIDTH * TEXTURE_HEIGHT * 4; + imageStagingBufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; + + result = palCreateBuffer(device, &imageStagingBufferCreateInfo, &imageStagingBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image staging buffer: %s", error); + return false; + } + + PalMemoryRequirements imageStagingBufferMemReq = {0}; + result = palGetBufferMemoryRequirements(imageStagingBuffer, &imageStagingBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image staging buffer memory requirement: %s", error); + return false; + } + + PalMemory* imageStagingBufferMemory = nullptr; + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + imageStagingBufferMemReq.memoryMask, + imageStagingBufferMemReq.size, + &imageStagingBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory: %s", error); + return false; + } + + result = palBindBufferMemory(imageStagingBuffer, imageStagingBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind image staging buffer memory: %s", error); + return false; + } + + // copy data + void* data = nullptr; + result = palMapMemory( + device, + imageStagingBufferMemory, + 0, + imageStagingBufferCreateInfo.size, + &data); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map memory: %s", error); + return false; + } + + memcpy(data, texture, imageStagingBufferCreateInfo.size); + palUnmapMemory(device, imageStagingBufferMemory); + + // use the first command buffer to upload the copy + // and reset it when done + // set a fence and check at the last line before the main loop + // to see if we have to wait for the copy to be executed + result = palCmdBegin(cmdBuffers[0], nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, 0, 0, sizeof(vertices)); + + PalUsageStateInfo oldUsageStateInfo = {0}; + oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_VERTEX; + newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; + + result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // copy image staing buffer to the checkerboard image + // first the image must be in the correct layout + PalUsageStateInfo oldImageUsageState = {0}; + PalUsageStateInfo newImageUsageState = {0}; + + result = palCmdEnd(cmdBuffers[0]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffers[0]; + submitInfo.fence = fence; + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // create shaders + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + PalShaderCreateInfo shaderCreateInfo = {0}; + + const char* vertexShaderPath = nullptr; + const char* fragShaderPath = nullptr; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + vertexShaderPath = "shaders/triangle_vert.spv"; + fragShaderPath = "shaders/triangle_frag.spv"; + } + + if (!readFile(vertexShaderPath, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to find shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(vertexShaderPath, bytecode, &bytecodeSize); + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; + + result = palCreateShader(device, &shaderCreateInfo, &vertexShader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create vertex shader: %s", error); + return false; + } + + // fragment shader + bytecodeSize = 0; + palFree(nullptr, bytecode); + bytecode = nullptr; + + if (!readFile(fragShaderPath, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to find shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(fragShaderPath, bytecode, &bytecodeSize); + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; + + result = palCreateShader(device, &shaderCreateInfo, &fragmentShader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fragment shader: %s", error); + return false; + } + + palFree(nullptr, bytecode); + + // create a pipeline layout + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline layout: %s", error); + return false; + } + + // the graphics pipeline needs the layout of the rendering + // info it will be used with + // we get the any image from the swapchain and get the format + // on the image since our color attachment takes a swapchain image + PalImage* image = palGetSwapchainImage(swapchain, 0); + PalImageInfo imageInfo = {0}; + result = palGetImageInfo(image, &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } + + PalRenderingLayoutInfo renderingLayoutInfo = {0}; + renderingLayoutInfo.colorAttachentCount = 1; + renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; + renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.viewCount = 1; + + // create graphics pipeline + PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; + PalVertexLayout vertexLayout = {0}; + PalVertexAttribute vertexAttributes[2]; + + // position + vertexAttributes[0].location = 0; + vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; + + // color + vertexAttributes[1].location = 1; + vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT3; + + vertexLayout.attributeCount = 2; + vertexLayout.attributes = vertexAttributes; + vertexLayout.binding = 0; // first vertex buffer binding slot + vertexLayout.type = PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX; + + pipelineCreateInfo.vertexLayoutCount = 1; + pipelineCreateInfo.vertexLayouts = &vertexLayout; + + // color blend attachment + PalColorBlendAttachment blendAttachment = {0}; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; + + pipelineCreateInfo.colorBlendAttachments = &blendAttachment; + pipelineCreateInfo.colorBlendAttachmentCount = 1; + + // multisample state + PalMultisampleState multisampleState = {0}; + multisampleState.sampleCount = PAL_SAMPLE_COUNT_1; + pipelineCreateInfo.multisampleState = &multisampleState; + + // shaders + PalShader* shaders[2]; + shaders[0] = vertexShader; + shaders[1] = fragmentShader; + pipelineCreateInfo.shaderCount = 2; + pipelineCreateInfo.shaders = shaders; + + pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + pipelineCreateInfo.pipelineLayout = pipelineLayout; + pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; + + result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create graphics pipeline: %s", error); + return false; + } + + palDestroyShader(vertexShader); + palDestroyShader(fragmentShader); + + // wait for the vertices copy to be done + result = palWaitFence(fence, UINT64_MAX); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } + + // the vertices have been copied + palDestroyFence(fence); + palDestroyBuffer(stagingBuffer); + palFreeMemory(device, stagingBufferMemory); + + // main loop + Uint32 currentFrame = 0; + bool running = true; + PalSemaphore* presentCompleteSemaphore = nullptr; + PalSemaphore* renderFinishedSemaphore = nullptr; + fence = nullptr; + PalCommandBuffer* cmdBuffer = nullptr; + + bool firstImageViewUse[8]; + memset(firstImageViewUse, 1, sizeof(bool) * 8); + + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + + PalRect2D scissor = {0}; + scissor.height = WINDOW_HEIGHT; + scissor.width = WINDOW_WIDTH; + + while (running) { + // update the video system to push video events + palUpdateVideo(); + + PalEvent event; + while (palPollEvent(eventDriver, &event)) { + switch (event.type) { + case PAL_EVENT_WINDOW_CLOSE: { + running = false; + break; + } + + case PAL_EVENT_KEYDOWN: { + PalKeycode keycode = 0; + palUnpackUint32(event.data, &keycode, nullptr); + if (keycode == PAL_KEYCODE_ESCAPE) { + running = false; + } + break; + } + } + } + + fence = inFlightFences[currentFrame]; + presentCompleteSemaphore = presentCompleteSemaphores[currentFrame]; + cmdBuffer = cmdBuffers[currentFrame]; + + result = palWaitFence(fence, UINT64_MAX); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + result = palResetFence(fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + } else { + // recreate since we dont support fence resetting + palDestroyFence(fence); + + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = presentCompleteSemaphore; + nextImageInfo.timeout = UINT64_MAX; + + Uint32 index = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &index); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + renderFinishedSemaphore = renderFinishedSemaphores[index]; + + // reset the command buffer + result = palResetCommandBuffer(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to reset command buffer: %s", error); + return false; + } + + result = palCmdBegin(cmdBuffer, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + // change the state of the image view to make it renderable + PalUsageStateInfo oldUsageStateInfo = {0}; + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + + if (firstImageViewUse[index]) { + oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; + } else { + oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + } + + PalImageSubresourceRange imageRange = {0}; + imageRange.layerArrayCount = 1; + imageRange.mipLevelCount = 1; + imageRange.startArrayLayer = 0; + imageRange.startMipLevel = 0; + + PalImage* image = palGetSwapchainImage(swapchain, index); + result = palCmdImageBarrier( + cmdBuffer, + image, + &imageRange, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + PalClearValue clearValue; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; + + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.clearValue = clearValue; + colorAttachment.imageView = imageViews[index]; + + PalRenderingInfo renderingInfo = {0}; + renderingInfo.viewCount = 1; + renderingInfo.colorAttachentCount = 1; + renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.layerCount = 1; + renderingInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; + + result = palCmdBeginRendering(cmdBuffer, &renderingInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin rendering: %s", error); + return false; + } + + // bind pipeline + result = palCmdBindPipeline(cmdBuffer, pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + // set viewport and scissors + result = palCmdSetViewport(cmdBuffer, 1, &viewport); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set viewport: %s", error); + return false; + } + + result = palCmdSetScissors(cmdBuffer, 1, &scissor); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set scissors: %s", error); + return false; + } + + // bind vertex buffer + Uint64 offset[] = {0}; + result = palCmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, offset); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind vertex buffer: %s", error); + return false; + } + + result = palCmdDraw(cmdBuffer, 6, 1, 0, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to issue draw command: %s", error); + return false; + } + + result = palCmdEndRendering(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end rendering: %s", error); + return false; + } + + // change the state of the image view to make it presentable + oldUsageStateInfo = newUsageStateInfo; + newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + result = palCmdImageBarrier( + cmdBuffer, + image, + &imageRange, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + result = palCmdEnd(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // submit command buffer + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffer; + submitInfo.fence = fence; + submitInfo.waitSemaphore = presentCompleteSemaphore; + submitInfo.signalSemaphore = renderFinishedSemaphore; + + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // present + PalSwapchainPresentInfo presentInfo = {0}; + presentInfo.imageIndex = index; + presentInfo.waitSemaphore = renderFinishedSemaphore; + result = palPresentSwapchain(swapchain, &presentInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to present swapchain: %s", error); + return false; + } + + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + } + + result = palWaitDevice(device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for device: %s", error); + return false; + } + + palDestroyPipeline(pipeline); + palDestroyPipelineLayout(pipelineLayout); + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + palDestroySemaphore(presentCompleteSemaphores[i]); + palDestroyFence(inFlightFences[i]); + palFreeCommandBuffer(cmdBuffers[i]); + } + + for (int i = 0; i < imageCount; i++) { + palDestroyImageView(imageViews[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); + } + + palDestroyBuffer(vertexBuffer); + palFreeMemory(device, vertexBufferMemory); + + palDestroyCommandPool(cmdPool); + palDestroySwapchain(swapchain); + palDestroyQueue(queue); + palDestroyDevice(device); + palShutdownGraphics(); + palFree(nullptr, imageViews); + + palDestroyWindow(window); + palShutdownVideo(); + palDestroyEventDriver(eventDriver); + return true; +} diff --git a/tests/triangle_test.c b/tests/triangle_test.c index cc4aab00..4313c654 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -5,6 +5,10 @@ #include +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +#define MAX_FRAMES_IN_FLIGHT 2 + static bool readFile( const char* filename, void* buffer, @@ -28,10 +32,6 @@ static bool readFile( return true; } -#define WINDOW_WIDTH 640 -#define WINDOW_HEIGHT 480 -#define MAX_FRAMES_IN_FLIGHT 2 - static void PAL_CALL onGraphicsDebug( void* userData, PalDebugMessageSeverity severity, @@ -264,12 +264,12 @@ bool triangleTest() } PalImageViewCreateInfo imageViewCreateInfo = {0}; - imageViewCreateInfo.layerArrayCount = 1; - imageViewCreateInfo.mipLevelCount = 1; - imageViewCreateInfo.startArrayLayer = 0; - imageViewCreateInfo.startMipLevel = 0; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; + imageViewCreateInfo.subresourceRange.layerArrayCount = 1; + imageViewCreateInfo.subresourceRange.mipLevelCount = 1; + imageViewCreateInfo.subresourceRange.startArrayLayer = 0; + imageViewCreateInfo.subresourceRange.startMipLevel = 0; for (int i = 0; i < imageCount; i++) { // get swapchain image @@ -767,9 +767,17 @@ bool triangleTest() oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; } - result = palCmdImageViewBarrier( + PalImageSubresourceRange imageRange = {0}; + imageRange.layerArrayCount = 1; + imageRange.mipLevelCount = 1; + imageRange.startArrayLayer = 0; + imageRange.startMipLevel = 0; + + PalImage* image = palGetSwapchainImage(swapchain, index); + result = palCmdImageBarrier( cmdBuffer, - imageViews[index], + image, + &imageRange, &oldUsageStateInfo, &newUsageStateInfo); @@ -856,9 +864,10 @@ bool triangleTest() // change the state of the image view to make it presentable oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageViewBarrier( + result = palCmdImageBarrier( cmdBuffer, - imageViews[index], + image, + &imageRange, &oldUsageStateInfo, &newUsageStateInfo); From 0151c2d6f45453789f19432e933e019e1f78a587 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 19 Mar 2026 06:27:52 +0000 Subject: [PATCH 108/372] add copy commands for images and buffers --- include/pal/pal_graphics.h | 245 ++++++++++++++++++++++++++++++++---- src/graphics/pal_graphics.c | 99 +++++++++++++-- src/graphics/pal_vulkan.c | 37 +++++- tests/compute_test.c | 5 +- tests/ray_tracing_test.c | 5 +- tests/texture_test.c | 10 +- tests/triangle_test.c | 10 +- 7 files changed, 368 insertions(+), 43 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 83d1477b..7c787e38 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2182,8 +2182,8 @@ typedef struct { } PalPushConstantRange; /** - * @struct PalImageCreateInfo - * @brief Creation parameters for an image. + * @struct PalImageSubresourceRange + * @brief Subresource range for images and image views. * * Uninitialized fields may result in undefined behavior. * @@ -2191,19 +2191,15 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 width; /**< Width of the image in pixels.*/ - Uint32 height; /**< Height of the image in pixels.*/ - Uint32 depthOrArraySize; + Uint32 startMipLevel; Uint32 mipLevelCount; - PalSampleCount sampleCount; - PalImageType type; /**< (eg. PAL_IMAGE_TYPE_2D).*/ - PalFormat format; /**< Format of the image.*/ - PalImageUsages usages; /**< (eg. PAL_IMAGE_USAGE_COLOR_ATTACHEMENT).*/ -} PalImageCreateInfo; + Uint32 startArrayLayer; + Uint32 layerArrayCount; +} PalImageSubresourceRange; /** - * @struct PalImageSubresourceRange - * @brief Subresource range for images and image views. + * @struct PalBufferCopyInfo + * @brief Copy information for buffer to buffer. * * Uninitialized fields may result in undefined behavior. * @@ -2211,11 +2207,104 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 startMipLevel; + Uint32 size; + Uint64 dstOffset; + Uint64 srcOffset; +} PalBufferCopyInfo; + +/** + * @struct PalBufferImageCopyInfo + * @brief Copy information for buffer to image. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint64 bufferOffset; + Uint32 bufferRowLength; + Uint32 bufferImageHeight; + Uint32 ImageMipLevel; + Uint32 ImageStartArrayLayer; + Uint32 ImageArrayLayerCount; + Int32 imageOffsetX; + Int32 imageOffsetY; + Int32 imageOffsetZ; + Uint32 imageWidth; + Uint32 imageHeight; + Uint32 imageDepth; +} PalBufferImageCopyInfo; + +/** + * @struct PalImageCopyInfo + * @brief Copy information for image to image. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 dstMipLevel; + Uint32 srcMipLevel; + Uint32 dstStartArrayLayer; + Uint32 srcStartArrayLayer; + Uint32 arrayLayerCount; + Int32 dstOffsetX; + Int32 srcOffsetX; + Int32 dstOffsetY; + Int32 srcOffsetY; + Int32 dstOffsetZ; + Int32 srcOffsetZ; + Uint32 width; + Uint32 height; + Uint32 depth; +} PalImageCopyInfo; + +/** + * @struct PalImageBufferCopyInfo + * @brief Copy information for image to buffer. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint64 bufferOffset; + Uint32 bufferRowLength; + Uint32 bufferImageHeight; + Uint32 ImageMipLevel; + Uint32 ImageStartArrayLayer; + Uint32 ImageArrayLayerCount; + Int32 imageOffsetX; + Int32 imageOffsetY; + Int32 imageOffsetZ; + Uint32 imageWidth; + Uint32 imageHeight; + Uint32 imageDepth; +} PalImageBufferCopyInfo; + +/** + * @struct PalImageCreateInfo + * @brief Creation parameters for an image. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 width; /**< Width of the image in pixels.*/ + Uint32 height; /**< Height of the image in pixels.*/ + Uint32 depthOrArraySize; Uint32 mipLevelCount; - Uint32 startArrayLayer; - Uint32 layerArrayCount; -} PalImageSubresourceRange; + PalSampleCount sampleCount; + PalImageType type; /**< (eg. PAL_IMAGE_TYPE_2D).*/ + PalFormat format; /**< Format of the image.*/ + PalImageUsages usages; /**< (eg. PAL_IMAGE_USAGE_COLOR_ATTACHEMENT).*/ +} PalImageCreateInfo; /** * @struct PalImageCreateInfo @@ -3075,9 +3164,40 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, - Uint64 dstOffset, - Uint64 srcOffset, - Uint32 size); + PalBufferCopyInfo* copyInfo); + + /** + * Backend implementation of ::palCmdCopyBufferToImage. + * + * Must obey the rules and semantics documented in palCmdCopyBufferToImage(). + */ + PalResult PAL_CALL (*cmdCopyBufferToImage)( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + + /** + * Backend implementation of ::cmdCopyImage. + * + * Must obey the rules and semantics documented in cmdCopyImage(). + */ + PalResult PAL_CALL (*cmdCopyImage)( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + + /** + * Backend implementation of ::palCmdCopyImageToBuffer. + * + * Must obey the rules and semantics documented in palCmdCopyImageToBuffer(). + */ + PalResult PAL_CALL (*cmdCopyImageToBuffer)( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalImageBufferCopyInfo* copyInfo); /** * Backend implementation of ::palCmdBindPipeline. @@ -5254,9 +5374,11 @@ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); * @param[in] cmdBuffer Command buffer being recorded. * @param[in] dst Destination buffer. * @param[in] src Source buffer. - * @param[in] dstOffset Starting byte offset in the destination buffer. - * @param[in] srcOffset Starting byte offset in the source buffer. - * @param[in] size Size in bytes to copy from the source buffer. + * @param[in] copyInfo Pointer to a PalBufferCopyInfo struct that specifies parameters. + * Must not be nullptr. + * + * Pointer to a PalImageCreateInfo struct that specifies parameters. + * Must not be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5270,9 +5392,82 @@ PAL_API PalResult PAL_CALL palCmdCopyBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, - Uint64 dstOffset, - Uint64 srcOffset, - Uint32 size); + PalBufferCopyInfo* copyInfo); + +/** + * @brief Copy data from a buffer to an image. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] dstImage Destination image. + * @param[in] srcBuffer Source buffer. + * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palCmdCopyBufferToImage( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + +/** + * @brief Copy data from one image to the other. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] dst Destination image. + * @param[in] src Source image. + * @param[in] copyInfo Pointer to a PalImageCopyInfo struct that specifies parameters. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palCmdCopyImage( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + +/** + * @brief Copy data from an image to a buffer. + * + * The graphics system must be initialized before this call. + * + * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] dstBuffer Destination buffer. + * @param[in] srcImage Source image. + * @param[in] copyInfo Pointer to a PalImageBufferCopyInfo struct that specifies parameters. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalImageBufferCopyInfo* copyInfo); /** * @brief Bind a pipeline. diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 91ef444b..44f73cc0 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -364,9 +364,25 @@ PalResult PAL_CALL cmdCopyBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, - Uint64 dstOffset, - Uint64 srcOffset, - Uint32 size); + PalBufferCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyBufferToImageVk( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageVk( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageToBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalImageBufferCopyInfo* copyInfo); PalResult PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, @@ -738,6 +754,9 @@ static PalGraphicsBackend s_VkBackend = { .cmdBeginRendering = cmdBeginRenderingVk, .cmdEndRendering = cmdEndRenderingVk, .cmdCopyBuffer = cmdCopyBufferVk, + .cmdCopyBufferToImage = cmdCopyBufferToImageVk, + .cmdCopyImage = cmdCopyImageVk, + .cmdCopyImageToBuffer = cmdCopyImageToBufferVk, .cmdBindPipeline = cmdBindPipelineVk, .cmdSetViewport = cmdSetViewportVk, .cmdSetScissors = cmdSetScissorsVk, @@ -931,6 +950,9 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->cmdBeginRendering || !backend->cmdEndRendering || !backend->cmdCopyBuffer || + !backend->cmdCopyBufferToImage || + !backend->cmdCopyImage || + !backend->cmdCopyImageToBuffer || !backend->cmdBindPipeline || !backend->cmdSetViewport || !backend->cmdSetScissors || @@ -2154,19 +2176,80 @@ PalResult PAL_CALL palCmdCopyBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, - Uint64 dstOffset, - Uint64 srcOffset, - Uint32 size) + PalBufferCopyInfo* copyInfo) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !dst || !src) { + if (!cmdBuffer || !dst || !src || !copyInfo) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdCopyBuffer(cmdBuffer, dst, src, dstOffset, srcOffset, size); + return cmdBuffer->backend->cmdCopyBuffer(cmdBuffer, dst, src, copyInfo); +} + +PalResult PAL_CALL palCmdCopyBufferToImage( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !dstImage || !srcBuffer || !copyInfo) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->cmdCopyBufferToImage( + cmdBuffer, + dstImage, + srcBuffer, + copyInfo); +} + +PalResult PAL_CALL palCmdCopyImage( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !dst || !src || !copyInfo) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->cmdCopyImage( + cmdBuffer, + dst, + src, + copyInfo); +} + +PalResult PAL_CALL palCmdCopyImageToBuffer( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalImageBufferCopyInfo* copyInfo) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!cmdBuffer || !dstBuffer || !srcImage || !copyInfo) { + return PAL_RESULT_NULL_POINTER; + } + + return cmdBuffer->backend->cmdCopyImageToBuffer( + cmdBuffer, + dstBuffer, + srcImage, + copyInfo); } PalResult PAL_CALL palCmdBindPipeline( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index d968b2d4..3de26c99 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -6279,23 +6279,48 @@ PalResult PAL_CALL cmdCopyBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, - Uint64 dstOffset, - Uint64 srcOffset, - Uint32 size) + PalBufferCopyInfo* copyInfo) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* dstbuffer = (Buffer*)dst; Buffer* srcBuffer = (Buffer*)src; VkBufferCopy copyRegion = {0}; - copyRegion.size = size; - copyRegion.dstOffset = dstOffset; - copyRegion.srcOffset = srcOffset; + copyRegion.size = copyInfo->size; + copyRegion.dstOffset = copyInfo->dstOffset; + copyRegion.srcOffset = copyInfo->srcOffset; s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, srcBuffer->handle, dstbuffer->handle, 1, ©Region); return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL cmdCopyBufferToImageVk( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo) +{ + // TODO: buffer to image copy +} + +PalResult PAL_CALL cmdCopyImageVk( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo) +{ + // TODO: image to image copy +} + +PalResult PAL_CALL cmdCopyImageToBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalImageBufferCopyInfo* copyInfo) +{ + // TODO: image to buffer copy +} + PalResult PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline) diff --git a/tests/compute_test.c b/tests/compute_test.c index ad931dce..e5b76675 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -564,7 +564,10 @@ bool computeTest() } // now we copy from the GPU buffer into the staging buffer - result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, 0, 0, bufferBytes); + PalBufferCopyInfo copyInfo = {0}; + copyInfo.size = bufferBytes; + + result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 31ad7751..19996931 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -999,7 +999,10 @@ bool rayTracingTest() } // now we copy from the GPU buffer into the staging buffer - result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, 0, 0, bufferBytes); + PalBufferCopyInfo copyInfo = {0}; + copyInfo.size = bufferBytes; + + result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); diff --git a/tests/texture_test.c b/tests/texture_test.c index 002b52be..0182b4c4 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -601,7 +601,15 @@ bool textureTest() return false; } - result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, 0, 0, sizeof(vertices)); + PalBufferCopyInfo copyInfo = {0}; + copyInfo.size = sizeof(vertices); + + result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer: %s", error); + return false; + } PalUsageStateInfo oldUsageStateInfo = {0}; oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 4313c654..1236aa40 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -453,7 +453,15 @@ bool triangleTest() return false; } - result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, 0, 0, sizeof(vertices)); + PalBufferCopyInfo copyInfo = {0}; + copyInfo.size = sizeof(vertices); + + result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer: %s", error); + return false; + } PalUsageStateInfo oldUsageStateInfo = {0}; oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; From ecd7aeb10d52ac7525b21eae8b098a8ee44d890f Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 19 Mar 2026 14:54:18 +0000 Subject: [PATCH 109/372] finish added copy commands --- include/pal/pal_graphics.h | 36 ++--------- src/graphics/pal_graphics.c | 4 +- src/graphics/pal_vulkan.c | 119 ++++++++++++++++++++++++++++++++++-- tests/texture_test.c | 5 +- 4 files changed, 127 insertions(+), 37 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 7c787e38..1eb6ce6e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2199,7 +2199,7 @@ typedef struct { /** * @struct PalBufferCopyInfo - * @brief Copy information for buffer to buffer. + * @brief Information for buffer to buffer copies. * * Uninitialized fields may result in undefined behavior. * @@ -2214,7 +2214,7 @@ typedef struct { /** * @struct PalBufferImageCopyInfo - * @brief Copy information for buffer to image. + * @brief Information for image to buffer and vice versa copies. * * Uninitialized fields may result in undefined behavior. * @@ -2238,7 +2238,7 @@ typedef struct { /** * @struct PalImageCopyInfo - * @brief Copy information for image to image. + * @brief Information for image to image copies. * * Uninitialized fields may result in undefined behavior. * @@ -2262,30 +2262,6 @@ typedef struct { Uint32 depth; } PalImageCopyInfo; -/** - * @struct PalImageBufferCopyInfo - * @brief Copy information for image to buffer. - * - * Uninitialized fields may result in undefined behavior. - * - * @since 1.4 - * @ingroup pal_graphics - */ -typedef struct { - Uint64 bufferOffset; - Uint32 bufferRowLength; - Uint32 bufferImageHeight; - Uint32 ImageMipLevel; - Uint32 ImageStartArrayLayer; - Uint32 ImageArrayLayerCount; - Int32 imageOffsetX; - Int32 imageOffsetY; - Int32 imageOffsetZ; - Uint32 imageWidth; - Uint32 imageHeight; - Uint32 imageDepth; -} PalImageBufferCopyInfo; - /** * @struct PalImageCreateInfo * @brief Creation parameters for an image. @@ -3197,7 +3173,7 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, - PalImageBufferCopyInfo* copyInfo); + PalBufferImageCopyInfo* copyInfo); /** * Backend implementation of ::palCmdBindPipeline. @@ -5452,7 +5428,7 @@ PAL_API PalResult PAL_CALL palCmdCopyImage( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] dstBuffer Destination buffer. * @param[in] srcImage Source image. - * @param[in] copyInfo Pointer to a PalImageBufferCopyInfo struct that specifies parameters. + * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * Must not be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -5467,7 +5443,7 @@ PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, - PalImageBufferCopyInfo* copyInfo); + PalBufferImageCopyInfo* copyInfo); /** * @brief Bind a pipeline. diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 44f73cc0..f2167086 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -382,7 +382,7 @@ PalResult PAL_CALL cmdCopyImageToBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, - PalImageBufferCopyInfo* copyInfo); + PalBufferImageCopyInfo* copyInfo); PalResult PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, @@ -2235,7 +2235,7 @@ PalResult PAL_CALL palCmdCopyImageToBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, - PalImageBufferCopyInfo* copyInfo) + PalBufferImageCopyInfo* copyInfo) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 3de26c99..5032d64e 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -144,6 +144,9 @@ typedef struct { PFN_vkResetCommandBuffer resetCommandBuffer; PFN_vkCmdExecuteCommands cmdExecuteCommandBuffer; PFN_vkCmdCopyBuffer cmdCopyBuffer; + PFN_vkCmdCopyBufferToImage cmdCopyBufferToImage; + PFN_vkCmdCopyImage cmdCopyImage; + PFN_vkCmdCopyImageToBuffer cmdCopyImageToBuffer; PFN_vkCmdBindPipeline cmdBindPipeline; PFN_vkCmdSetViewport cmdSetViewports; PFN_vkCmdSetScissor cmdSetScissors; @@ -2368,6 +2371,18 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkCmdCopyBuffer"); + s_Vk.cmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)dlsym( + s_Vk.handle, + "vkCmdCopyBufferToImage"); + + s_Vk.cmdCopyImage = (PFN_vkCmdCopyImage)dlsym( + s_Vk.handle, + "vkCmdCopyImage"); + + s_Vk.cmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)dlsym( + s_Vk.handle, + "vkCmdCopyImageToBuffer"); + s_Vk.cmdBindPipeline = (PFN_vkCmdBindPipeline)dlsym( s_Vk.handle, "vkCmdBindPipeline"); @@ -6300,7 +6315,37 @@ PalResult PAL_CALL cmdCopyBufferToImageVk( PalBuffer* srcBuffer, PalBufferImageCopyInfo* copyInfo) { - // TODO: buffer to image copy + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Image* dst = (Image*)dstImage; + Buffer* src = (Buffer*)srcBuffer; + + VkBufferImageCopy copyRegion = {0}; + copyRegion.bufferImageHeight = copyInfo->bufferImageHeight; + copyRegion.bufferOffset = copyInfo->bufferOffset; + copyRegion.bufferRowLength = copyInfo->bufferRowLength; + + copyRegion.imageOffset.x = copyInfo->imageOffsetX; + copyRegion.imageOffset.y = copyInfo->imageOffsetY; + copyRegion.imageOffset.z = copyInfo->imageOffsetZ; + + copyRegion.imageExtent.x = copyInfo->imageWidth; + copyRegion.imageExtent.y = copyInfo->imageHeight; + copyRegion.imageExtent.z = copyInfo->imageDepth; + + copyRegion.imageSubresource.aspectMask = dst->aspectMask; + copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; + copyRegion.imageSubresource.layerCount = copyInfo->ImageArrayLayerCount; + copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; + + s_Vk.cmdCopyBufferToImage( + vkCmdBuffer->handle, + src->handle, + dst->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ©Region); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdCopyImageVk( @@ -6309,16 +6354,82 @@ PalResult PAL_CALL cmdCopyImageVk( PalImage* src, PalImageCopyInfo* copyInfo) { - // TODO: image to image copy + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Image* dstImage = (Image*)dst; + Image* srcImage = (Image*)src; + + VkImageCopy copyRegion = {0}; + copyRegion.dstOffset.x = copyInfo->dstOffsetX; + copyRegion.dstOffset.y = copyInfo->dstOffsetY; + copyRegion.dstOffset.z = copyInfo->dstOffsetZ; + + copyRegion.srcOffset.x = copyInfo->srcOffsetX; + copyRegion.srcOffset.y = copyInfo->srcOffsetY; + copyRegion.srcOffset.z = copyInfo->srcOffsetZ; + + copyRegion.extent.x = copyInfo->width; + copyRegion.extent.y = copyInfo->height; + copyRegion.extent.z = copyInfo->depth; + + copyRegion.dstSubresource.aspectMask = dstImage->aspectMask; + copyRegion.dstSubresource.baseArrayLayer = copyInfo->dstStartArrayLayer; + copyRegion.dstSubresource.layerCount = copyInfo->arrayLayerCount; + copyRegion.dstSubresource.mipLevel = copyInfo->dstMipLevel; + + copyRegion.srcSubresource.aspectMask = srcImage->aspectMask; + copyRegion.srcSubresource.baseArrayLayer = copyInfo->srcStartArrayLayer; + copyRegion.srcSubresource.layerCount = copyInfo->arrayLayerCount; + copyRegion.srcSubresource.mipLevel = copyInfo->srcMipLevel; + + s_Vk.cmdCopyImage( + vkCmdBuffer->handle, + srcImage->handle, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dstImage->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ©Region); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdCopyImageToBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, - PalImageBufferCopyInfo* copyInfo) + PalBufferImageCopyInfo* copyInfo) { - // TODO: image to buffer copy + CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* dst = (Buffer*)dstBuffer; + Image* src = (Image*)srcImage; + + VkBufferImageCopy copyRegion = {0}; + copyRegion.bufferImageHeight = copyInfo->bufferImageHeight; + copyRegion.bufferOffset = copyInfo->bufferOffset; + copyRegion.bufferRowLength = copyInfo->bufferRowLength; + + copyRegion.imageOffset.x = copyInfo->imageOffsetX; + copyRegion.imageOffset.y = copyInfo->imageOffsetY; + copyRegion.imageOffset.z = copyInfo->imageOffsetZ; + + copyRegion.imageExtent.x = copyInfo->imageWidth; + copyRegion.imageExtent.y = copyInfo->imageHeight; + copyRegion.imageExtent.z = copyInfo->imageDepth; + + copyRegion.imageSubresource.aspectMask = src->aspectMask; + copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; + copyRegion.imageSubresource.layerCount = copyInfo->ImageArrayLayerCount; + copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; + + s_Vk.cmdCopyImageToBuffer( + vkCmdBuffer->handle, + src->handle, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dst->handle, + 1, + ©Region); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdBindPipelineVk( diff --git a/tests/texture_test.c b/tests/texture_test.c index 0182b4c4..2fe6b5bd 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -626,11 +626,14 @@ bool textureTest() return false; } - // copy image staing buffer to the checkerboard image + // copy image staging buffer to the checkerboard image // first the image must be in the correct layout PalUsageStateInfo oldImageUsageState = {0}; PalUsageStateInfo newImageUsageState = {0}; + // TODO: finish copying + PalBufferImageCopyInfo bufferImageCopyInfo = {0}; + result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); From 5b4b401ae19ab5574255c3be906d9c2ee8d83e0a Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 19 Mar 2026 21:08:35 +0000 Subject: [PATCH 110/372] finish texture test and fix some bugs --- include/pal/pal_graphics.h | 17 ++- src/graphics/pal_vulkan.c | 174 ++++++++++++++-------- tests/shaders/texture_frag.spv | Bin 0 -> 680 bytes tests/shaders/texture_vert.spv | Bin 0 -> 980 bytes tests/texture_test.c | 256 +++++++++++++++++++++++++++++++-- 5 files changed, 374 insertions(+), 73 deletions(-) create mode 100644 tests/shaders/texture_frag.spv create mode 100644 tests/shaders/texture_vert.spv diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 1eb6ce6e..57b3fb1a 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2128,10 +2128,22 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - PalSampler* sampler; PalImageView* imageView; } PalDescriptorImageViewInfo; +/** + * @struct PalDescriptorSamplerInfo + * @brief Information about a sampler descriptor. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + PalSampler* sampler; +} PalDescriptorSamplerInfo; + /** * @struct PalDescriptorTLASInfo * @brief Information about a TLAS descriptor. @@ -2161,7 +2173,8 @@ typedef struct { PalDescriptorType descriptorType; PalDescriptorSet* descriptorSet; PalDescriptorBufferInfo* bufferInfo; /**< If PAL_DESCRIPTOR_TYPE* uniform or storage buffer.*/ - PalDescriptorImageViewInfo* imageViewInfo; /**< If PAL_DESCRIPTOR_TYPE* sampler or image.*/ + PalDescriptorImageViewInfo* imageViewInfo; /**< If PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE*/ + PalDescriptorSamplerInfo* samplerInfo; /**< If PAL_DESCRIPTOR_TYPE_SAMPLER.*/ PalDescriptorTLASInfo* tlasInfo; /**< If PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE.*/ } PalDescriptorSetWriteInfo; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 5032d64e..da6ad535 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2544,7 +2544,7 @@ PalResult PAL_CALL initGraphicsVk( if (debugger) { // layers result = s_Vk.enumerateInstanceLayerProperties(&layerCount, nullptr); - if (result != VK_SUCCESS) { + if (result == VK_SUCCESS) { VkLayerProperties* props = nullptr; props = palAllocate(s_Vk.allocator, sizeof(VkLayerProperties) * layerCount, 0); if (!props) { @@ -4707,14 +4707,21 @@ PalResult PAL_CALL createImageVk( image->info.sampleCount = info->sampleCount; image->info.width = info->width; - // get aspect masks - image->aspectMask = 0; - if (info->usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { - image->aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT; + // get aspect masks from image format + image->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + if (info->format == PAL_FORMAT_S8_UINT) { + image->aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + } + + if (info->format == PAL_FORMAT_D16_UNORM || info->format == PAL_FORMAT_D32_SFLOAT) { + image->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; } - if (info->usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { - image->aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (info->format == PAL_FORMAT_D32_SFLOAT_S8_UINT || + info->format == PAL_FORMAT_D16_UNORM_S8_UINT || + info->format == PAL_FORMAT_D24_UNORM_S8_UINT) { + image->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + image->aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; } *outImage = (PalImage*)image; @@ -4894,95 +4901,143 @@ PalResult PAL_CALL createSamplerVk( // min filter mode switch (info->minFilterMode) { - case PAL_FILTER_MODE_LINEAR: + case PAL_FILTER_MODE_LINEAR: { createInfo.minFilter = VK_FILTER_LINEAR; - - case PAL_FILTER_MODE_NEAREST: + break; + } + + case PAL_FILTER_MODE_NEAREST: { createInfo.minFilter = VK_FILTER_NEAREST; + break; + } } // mag filter mode switch (info->magFilterMode) { - case PAL_FILTER_MODE_LINEAR: + case PAL_FILTER_MODE_LINEAR: { createInfo.magFilter = VK_FILTER_LINEAR; - - case PAL_FILTER_MODE_NEAREST: + break; + } + + case PAL_FILTER_MODE_NEAREST: { createInfo.magFilter = VK_FILTER_NEAREST; + break; + } } // sampler mipmap mode switch (info->mipmapMode) { - case PAL_SAMPLER_MIPMAP_MODE_LINEAR: + case PAL_SAMPLER_MIPMAP_MODE_LINEAR: { createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - - case PAL_SAMPLER_MIPMAP_MODE_NEAREST: + break; + } + + case PAL_SAMPLER_MIPMAP_MODE_NEAREST: { createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + break; + } } // sampler address mode u switch (info->addressModeU) { - case PAL_SAMPLER_ADDRESS_MODE_REPEAT: + case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - - case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + break; + } + + case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + break; + } - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + break; + } - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + break; + } } // sampler address mode v switch (info->addressModeV) { - case PAL_SAMPLER_ADDRESS_MODE_REPEAT: + case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - - case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + break; + } + + case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + break; + } - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + break; + } - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + break; + } } // sampler address mode w switch (info->addressModeW) { - case PAL_SAMPLER_ADDRESS_MODE_REPEAT: + case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - - case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: + break; + } + + case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + break; + } - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + break; + } - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + break; + } } // border color switch (info->borderColor) { - case PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK: + case PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK: { createInfo.addressModeW = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK; - - case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: + break; + } + + case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: { createInfo.addressModeW = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - - case PAL_BORDER_COLOR_INT_OPAQUE_BLACK: + break; + } + + case PAL_BORDER_COLOR_INT_OPAQUE_BLACK: { createInfo.addressModeW = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - - case PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK: + break; + } + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK: { createInfo.addressModeW = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - - case PAL_BORDER_COLOR_INT_OPAQUE_WHITE: + break; + } + + case PAL_BORDER_COLOR_INT_OPAQUE_WHITE: { createInfo.addressModeW = VK_BORDER_COLOR_INT_OPAQUE_WHITE; - - case PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE: + break; + } + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE: { createInfo.addressModeW = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + break; + } } result = s_Vk.createSampler( @@ -5261,6 +5316,7 @@ PalResult PAL_CALL createSwapchainVk( image->info.mipLevelCount = 1; image->info.sampleCount = PAL_SAMPLE_COUNT_1; // swapchain images are not multisampled image->info.type = PAL_IMAGE_TYPE_2D; + image->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } swapchain->device = vkDevice; @@ -6328,9 +6384,9 @@ PalResult PAL_CALL cmdCopyBufferToImageVk( copyRegion.imageOffset.y = copyInfo->imageOffsetY; copyRegion.imageOffset.z = copyInfo->imageOffsetZ; - copyRegion.imageExtent.x = copyInfo->imageWidth; - copyRegion.imageExtent.y = copyInfo->imageHeight; - copyRegion.imageExtent.z = copyInfo->imageDepth; + copyRegion.imageExtent.width = copyInfo->imageWidth; + copyRegion.imageExtent.height = copyInfo->imageHeight; + copyRegion.imageExtent.depth = copyInfo->imageDepth; copyRegion.imageSubresource.aspectMask = dst->aspectMask; copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; @@ -6367,9 +6423,9 @@ PalResult PAL_CALL cmdCopyImageVk( copyRegion.srcOffset.y = copyInfo->srcOffsetY; copyRegion.srcOffset.z = copyInfo->srcOffsetZ; - copyRegion.extent.x = copyInfo->width; - copyRegion.extent.y = copyInfo->height; - copyRegion.extent.z = copyInfo->depth; + copyRegion.extent.width = copyInfo->width; + copyRegion.extent.height = copyInfo->height; + copyRegion.extent.depth = copyInfo->depth; copyRegion.dstSubresource.aspectMask = dstImage->aspectMask; copyRegion.dstSubresource.baseArrayLayer = copyInfo->dstStartArrayLayer; @@ -6412,9 +6468,9 @@ PalResult PAL_CALL cmdCopyImageToBufferVk( copyRegion.imageOffset.y = copyInfo->imageOffsetY; copyRegion.imageOffset.z = copyInfo->imageOffsetZ; - copyRegion.imageExtent.x = copyInfo->imageWidth; - copyRegion.imageExtent.y = copyInfo->imageHeight; - copyRegion.imageExtent.z = copyInfo->imageDepth; + copyRegion.imageExtent.width = copyInfo->imageWidth; + copyRegion.imageExtent.height = copyInfo->imageHeight; + copyRegion.imageExtent.depth = copyInfo->imageDepth; copyRegion.imageSubresource.aspectMask = src->aspectMask; copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; @@ -7625,22 +7681,26 @@ PalResult PAL_CALL updateDescriptorSetVk( } else { VkDescriptorImageInfo* imageInfo = &imageInfos[imageIndex++]; - ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; - Sampler* vkSampler = (Sampler*)infos[i].imageViewInfo->sampler; - + if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { + Sampler* vkSampler = (Sampler*)infos[i].samplerInfo->sampler; + imageInfo->sampler = vkSampler->handle; imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageInfo->imageView = nullptr; } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - imageInfo->sampler = vkSampler->handle; + ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; + + imageInfo->sampler = nullptr; imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; imageInfo->imageView = vkImageView->handle; } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - imageInfo->sampler = vkSampler->handle; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; + + imageInfo->sampler = nullptr; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; imageInfo->imageView = vkImageView->handle; } write->pImageInfo = imageInfo; diff --git a/tests/shaders/texture_frag.spv b/tests/shaders/texture_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..17938b750bfef6611bcfbdf50299c3a94008bfc5 GIT binary patch literal 680 zcmYk3&r3o<6on^WFD=U-S(*i*wU-tZLDa^D8+S#m1ziN$3pMcX>#u4P^nIh!8@TVz zIdkTod*>yE%VG#yp&Uw~9agIz3NQg~C+5NMY1o@D#=YyCD;1THM4_5$D28paF&({q zc(6+}i5fb24A>=94dI(hDQsS!!gwe9TJ*E`Y{nKQ3H#*5WEu4}_Vdy7b9I)+`lIK` zvY%zMG30=X);L$d5_`WJ(LcV(VQYHs9O}jSb7$DpYtX&@cjF`>?wjm);5tN$`_3tL zwhrGC*_V>PUt@ceYt!u>S-t-GwZYaXuMgB(L+o6xQ@W^-)m0pb2)ChIA$huGQWZh3um&g8Q9ADEQ<0Bg+y!k)zX*9pB}Q0dzs)X1yRr$y-T VipKXjA=Jq~;^I5W{nEu9@dwg$9{~UW literal 0 HcmV?d00001 diff --git a/tests/shaders/texture_vert.spv b/tests/shaders/texture_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..75218a43c15ef0e8a1209a73a6d43b8657426958 GIT binary patch literal 980 zcmYk4PfG$(6vbcasAXklYJbd(mVvaW2%;hkY~jK%+J@v11Jf8fg|zCk^{Ltfo!`tn z^$pki&UyEpd*+Vm)KSiuB~vhYb710CGAS`eTsF#`Zok`_gu~Y9*$EZvCLI-0Q#8xb zKBM2affoSQ6q|~=VqcNglT!ZC1;=Fc%xfL>CpkDkwJQ*>g6Uc%e56 z#O9)UdPlq$gnjSJrOuwwOJ{B0d%yE0;UIW%XJIj&~a@a2@IJF7&^b4tti(mWyZ0)aP~Fp$>nxjy)Xn>gX3=4FwB~r$vk( zFuG;AK=V+F=&-M9msM^mYPzovA7S(>!g=MUf_0o=zAk!o;T2`>!!@+So7LcqXsT{i z*?PZBF!P0@&w5lB>(U2YRIu>1p-dk;!YR$TTEd~(lM}pbE2!lR h|9HNY27Y%H%#68Qt1Fm#+mr8%N6zg3;7^V(6#wHuKVSd= literal 0 HcmV?d00001 diff --git a/tests/texture_test.c b/tests/texture_test.c index 2fe6b5bd..46f550c4 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -10,7 +10,7 @@ #define MAX_FRAMES_IN_FLIGHT 2 #define TEXTURE_WIDTH 128 #define TEXTURE_HEIGHT 128 -#define CHECKER_SIZE 8 +#define CHECKER_SIZE 16 static bool readFile( const char* filename, @@ -106,6 +106,10 @@ bool textureTest() PalMemory* vertexBufferMemory = nullptr; PalMemory* stagingBufferMemory = nullptr; + PalDescriptorSetLayout* descriptorSetLayout = nullptr; + PalDescriptorPool* descriptorPool = nullptr; + PalDescriptorSet* descriptorSet = nullptr; + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { @@ -366,13 +370,13 @@ bool textureTest() // create vertex and staging buffer // clang-format off float vertices[] = { - -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, - 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, + -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, -0.5f, 1.0f, 1.0f, - -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, - 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.0f, 0.0f, 1.0f}; + -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, -0.5f, 0.0f, 1.0f}; // clang-format on PalBufferCreateInfo bufferCreateInfo = {0}; @@ -478,7 +482,8 @@ bool textureTest() // we dont want to load the texture from disk so we will create a // checkerboard texture and use that rather - Uint32 texture[TEXTURE_WIDTH * TEXTURE_HEIGHT * 4]; + Uint32 texture[TEXTURE_WIDTH * TEXTURE_HEIGHT]; + memset(texture, 0, TEXTURE_WIDTH * TEXTURE_HEIGHT); createCheckerboardTexture(texture, TEXTURE_WIDTH, TEXTURE_HEIGHT, CHECKER_SIZE); // create image for the texture @@ -629,10 +634,69 @@ bool textureTest() // copy image staging buffer to the checkerboard image // first the image must be in the correct layout PalUsageStateInfo oldImageUsageState = {0}; + oldImageUsageState.usageState = PAL_USAGE_STATE_UNDEFINED; + oldImageUsageState.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + PalUsageStateInfo newImageUsageState = {0}; + newImageUsageState.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + newImageUsageState.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + + // set a barrier on the image to transition it into transfer dst state + PalImageSubresourceRange checkerboardRange = {0}; + checkerboardRange.startMipLevel = 0; + checkerboardRange.startArrayLayer = 0; + checkerboardRange.mipLevelCount = 1; + checkerboardRange.layerArrayCount = 1; + + result = palCmdImageBarrier( + cmdBuffers[0], + checkerboard, + &checkerboardRange, + &oldImageUsageState, + &newImageUsageState); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image barrier: %s", error); + return false; + } - // TODO: finish copying PalBufferImageCopyInfo bufferImageCopyInfo = {0}; + bufferImageCopyInfo.ImageArrayLayerCount = 1; + bufferImageCopyInfo.imageWidth = TEXTURE_WIDTH; + bufferImageCopyInfo.imageHeight = TEXTURE_HEIGHT; + bufferImageCopyInfo.imageDepth = 1; // 2D image + + result = palCmdCopyBufferToImage( + cmdBuffers[0], + checkerboard, + imageStagingBuffer, + &bufferImageCopyInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer to image: %s", error); + return false; + } + + // we should transition the image into a shader read state so we dont do that + // in the main loop + oldImageUsageState = newImageUsageState; + newImageUsageState.usageState = PAL_USAGE_STATE_SHADER_READ; + newImageUsageState.shaderStage = PAL_SHADER_STAGE_FRAGMENT; // fragment shader will read + + result = palCmdImageBarrier( + cmdBuffers[0], + checkerboard, + &checkerboardRange, + &oldImageUsageState, + &newImageUsageState); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image barrier: %s", error); + return false; + } result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { @@ -651,6 +715,51 @@ bool textureTest() return false; } + // now we have the checkerboard texture data in the image + // we need an image view and a sampler + PalImageView* checkerboardImageView = nullptr; + PalImageViewCreateInfo checkerboardImageViewCreateInfo = {0}; + checkerboardImageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + checkerboardImageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; + checkerboardImageViewCreateInfo.subresourceRange = checkerboardRange; + + result = palCreateImageView( + device, + checkerboard, + &checkerboardImageViewCreateInfo, + &checkerboardImageView); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create checkerboard image view: %s", error); + return false; + } + + PalSampler* sampler = nullptr; + PalSamplerCreateInfo samplerCreateInfo = {0}; + samplerCreateInfo.addressModeU = PAL_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.addressModeV = PAL_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.addressModeW = PAL_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.borderColor = PAL_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerCreateInfo.compareOp = PAL_COMPARE_OP_NEVER; // will not be used if its not enabled + + samplerCreateInfo.enableAnisotropy = false; + samplerCreateInfo.enableCompare = false; + samplerCreateInfo.magFilterMode = PAL_FILTER_MODE_LINEAR; + samplerCreateInfo.minFilterMode = PAL_FILTER_MODE_LINEAR; + samplerCreateInfo.maxAnisotropy = 1.0f; + + result = palCreateSampler( + device, + &samplerCreateInfo, + &sampler); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create sampler: %s", error); + return false; + } + // create shaders Uint64 bytecodeSize = 0; void* bytecode = nullptr; @@ -659,8 +768,8 @@ bool textureTest() const char* vertexShaderPath = nullptr; const char* fragShaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - vertexShaderPath = "shaders/triangle_vert.spv"; - fragShaderPath = "shaders/triangle_frag.spv"; + vertexShaderPath = "shaders/texture_vert.spv"; + fragShaderPath = "shaders/texture_frag.spv"; } if (!readFile(vertexShaderPath, nullptr, &bytecodeSize)) { @@ -716,8 +825,108 @@ bool textureTest() palFree(nullptr, bytecode); - // create a pipeline layout + // create descriptor set layout + PalDescriptorSetLayoutBinding descriptorBindings[2]; + PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; + + descriptorBindings[0].binding = 0; + descriptorBindings[0].descriptorCount = 1; // not an array + descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + descriptorBindings[0].shaderStageCount = 1; + descriptorBindings[0].shaderStages = shaderStages; + + descriptorBindings[1].binding = 1; + descriptorBindings[1].descriptorCount = 1; // not an array + descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; + descriptorBindings[1].shaderStageCount = 1; + descriptorBindings[1].shaderStages = shaderStages; + + PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; + descriptorSetLayoutcreateInfo.bindingCount = 2; + descriptorSetLayoutcreateInfo.bindings = descriptorBindings; + + result = palCreateDescriptorSetLayout( + device, + &descriptorSetLayoutcreateInfo, + &descriptorSetLayout); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor set layout: %s", error); + return false; + } + + // create descriptor pool + PalDescriptorPoolBindingSize storageBufferBindingsizes[2]; + storageBufferBindingsizes[0].bindingCount = 1; + storageBufferBindingsizes[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + + storageBufferBindingsizes[1].bindingCount = 1; + storageBufferBindingsizes[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; + + PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; + descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set + descriptorPoolCreateInfo.maxDescriptorBindingSizes = 2; + descriptorPoolCreateInfo.bindingSizes = storageBufferBindingsizes; + + result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor pool: %s", error); + return false; + } + + // allocate a single descriptor set from the descriptor pool + // using the layout we created above + result = palAllocateDescriptorSet(device, descriptorPool, descriptorSetLayout, &descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate descriptor set: %s", error); + return false; + } + + // write the inital data to the descriptor set since its created empty + PalDescriptorImageViewInfo descriptorImageInfo = {0}; + descriptorImageInfo.imageView = checkerboardImageView; + + PalDescriptorSamplerInfo descriptorSamplerInfo = {0}; + descriptorSamplerInfo.sampler = sampler; + + PalDescriptorSetWriteInfo writeInfos[2]; + writeInfos[0].binding = 0; + writeInfos[0].imageViewInfo = &descriptorImageInfo; + writeInfos[0].descriptorSet = descriptorSet; + writeInfos[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + writeInfos[0].descriptorCount = 1; + + writeInfos[0].arrayElement = 0; + writeInfos[0].bufferInfo = nullptr; + writeInfos[0].samplerInfo = nullptr; + writeInfos[0].tlasInfo = nullptr; + + writeInfos[1].binding = 1; + writeInfos[1].samplerInfo = &descriptorSamplerInfo; + writeInfos[1].descriptorSet = descriptorSet; + writeInfos[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; + writeInfos[1].descriptorCount = 1; + + writeInfos[1].arrayElement = 0; + writeInfos[1].imageViewInfo = nullptr; + writeInfos[1].tlasInfo = nullptr; + writeInfos[1].bufferInfo = nullptr; + + result = palUpdateDescriptorSet(device, 2, writeInfos); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to update descriptor set: %s", error); + return false; + } + + // create pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + pipelineLayoutCreateInfo.descriptorSetLayoutCount = 1; + pipelineLayoutCreateInfo.descriptorSetLayouts = &descriptorSetLayout; + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -753,9 +962,9 @@ bool textureTest() vertexAttributes[0].location = 0; vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; - // color + // texture coordinates vertexAttributes[1].location = 1; - vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT3; + vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT2; vertexLayout.attributeCount = 2; vertexLayout.attributes = vertexAttributes; @@ -814,6 +1023,10 @@ bool textureTest() palDestroyBuffer(stagingBuffer); palFreeMemory(device, stagingBufferMemory); + // we can destroy the image staging buffer + palDestroyBuffer(imageStagingBuffer); + palFreeMemory(device, imageStagingBufferMemory); + // main loop Uint32 currentFrame = 0; bool running = true; @@ -987,6 +1200,13 @@ bool textureTest() return false; } + result = palCmdBindDescriptorSet(cmdBuffer, pipeline, pipelineLayout, 0, descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind descriptor set: %s", error); + return false; + } + // set viewport and scissors result = palCmdSetViewport(cmdBuffer, 1, &viewport); if (result != PAL_RESULT_SUCCESS) { @@ -1097,6 +1317,14 @@ bool textureTest() palDestroySemaphore(renderFinishedSemaphores[i]); } + palDestroyDescriptorPool(descriptorPool); + palDestroyDescriptorSetLayout(descriptorSetLayout); + + palDestroySampler(sampler); + palDestroyImageView(checkerboardImageView); + palDestroyImage(checkerboard); + palFreeMemory(device, checkerboardMemory); + palDestroyBuffer(vertexBuffer); palFreeMemory(device, vertexBufferMemory); From 73269d2d89a636a2a004df285d271445f7ee5d2e Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 19 Mar 2026 23:50:04 +0000 Subject: [PATCH 111/372] begin vulkan backend portability --- include/pal/pal_graphics.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 57b3fb1a..c0fc057a 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3882,7 +3882,7 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Must only be called from the main thread. + * Thread safety: Thread safe if `adapter` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -3902,7 +3902,8 @@ PAL_API PalResult PAL_CALL palCreateDevice( * * @param[in] device Pointer to the device to destroy. * - * Thread safety: Must only be called from the main thread. + * Thread safety: Thread safe if the adapter used to create the device is + * externally synchronized. * * @since 1.4 * @ingroup pal_graphics From c96d7ab5c2b4a348767e4b2bb17383486d616806 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 21 Mar 2026 13:53:14 +0000 Subject: [PATCH 112/372] graphics test: vulkan on windows --- include/pal/pal_graphics.h | 17 ++ pal.lua | 6 +- src/graphics/pal_vulkan.c | 406 +++++++++++++++++++++++-------------- tests/tests_main.c | 4 +- 4 files changed, 282 insertions(+), 151 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index c0fc057a..d9359ab6 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -754,6 +754,22 @@ typedef enum { PAL_SWAPCHAIN_FORMAT_MAX } PalSwapchainFormat; +/** + * @enum PalGraphicsWindowDisplayType + * @brief Display types for a graphics window. + * + * All graphics window display types follow the format `PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND, + PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11, + PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB +} PalGraphicsWindowDisplayType; + /** * @enum PalShaderStage * @brief shader stage types. @@ -1498,6 +1514,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + PalGraphicsWindowDisplayType displayType; /**< Will be used only on linux platform.*/ void* display; /**< Can be nullptr depending on platform (eg. Windows).*/ void* window; /**< Must not be nullptr.*/ } PalGraphicsWindow; diff --git a/pal.lua b/pal.lua index b4ea9326..8599ce7a 100644 --- a/pal.lua +++ b/pal.lua @@ -171,12 +171,16 @@ project "PAL" files { "src/graphics/pal_graphics.c" } filter {"system:windows", "configurations:*"} - -- files { "src/graphics/pal_graphics_win32.c" } + -- files { "src/graphics/pal_d3d12.c" } + if (hasVulkan) then + files { "src/graphics/pal_vulkan.c" } + end filter {"system:linux", "configurations:*"} if (hasVulkan) then files { "src/graphics/pal_vulkan.c" } end + filter {} end diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index da6ad535..aa2c895f 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -25,50 +25,58 @@ freely, subject to the following restrictions: // Includes // ================================================== -#include "pal/pal_graphics.h" - -#if PAL_HAS_VULKAN -#include #include #include #include + +#include "pal/pal_graphics.h" + +#if PAL_HAS_VULKAN #include // HACK: Needed to determine display type if on linux #ifdef _WIN32 -#define VK_LIB_NAME "" - +#include +#include +#define VK_LIB_NAME "vulkan-1.dll" #elif defined(__linux__) -struct wl_display; -struct wl_surface; -typedef struct _XDisplay Display; -typedef unsigned long Window; -typedef unsigned long VisualID; -typedef int (*wl_display_get_fd_fn)(struct wl_display*); - -#include -#include - +#include #define VK_LIB_NAME "libvulkan.so" - #else // Android #define VK_LIB_NAME "" - #endif // _WIN32 // ================================================== // Typedefs, enums and structs // ================================================== -#define VK_WIN32_PLATFORM 1 -#define VK_XLIB_PLATFORM 2 -#define VK_WAYLAND_PLATFORM 3 #define MAX_ATTACHMENTS 32 #define GRAPHICS_PIPELINE 125 #define RAY_TRACING_PIPELINE 126 #define COMPUTE_PIPELINE 127 +struct wl_display; +struct wl_surface; +typedef struct _XDisplay Display; +typedef unsigned long Window; +typedef unsigned long VisualID; + +typedef struct xcb_connection_t xcb_connection_t; +typedef uint32_t xcb_window_t; +typedef uint32_t xcb_visualid_t; + +typedef unsigned long DWORD; +typedef int WINBOOL; +typedef void *LPVOID; +typedef const wchar_t *LPCWSTR,*PCWSTR; +typedef void *HANDLE; + +#include +#include +#include +#include + typedef struct { const PalGraphicsBackend* backend; @@ -86,12 +94,6 @@ typedef struct { VkDebugUtilsMessengerEXT messenger; PalDebugCallback callback; -#ifdef __linux__ - // HACK: for display testing - void* libWayland; - wl_display_get_fd_fn getDisplayFd; -#endif // __linux__ - PFN_vkEnumerateInstanceVersion enumerateInstanceVersion; PFN_vkEnumerateInstanceExtensionProperties enumerateInstanceExtensionProperties; PFN_vkDestroyInstance destroyInstance; @@ -165,6 +167,10 @@ typedef struct { PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; PFN_vkCreateXlibSurfaceKHR createXlibSurface; PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR checkXlibPresentSupport; + PFN_vkCreateXcbSurfaceKHR createXcbSurface; + PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR checkXcbPresentSupport; + PFN_vkCreateWin32SurfaceKHR createWin32Surface; + PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR checkWin32PresentSupport; PFN_vkDestroySurfaceKHR destroySurface; PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR getSurfaceCapabilities; @@ -446,22 +452,31 @@ static Vulkan s_Vk = {0}; // Helper Functions // ================================================== -static Uint32 checkPlatformVk(struct wl_display* display) +static void* loadLibrary(const char* name) { -#ifdef _WIN32 -#elif defined(__linux__) - if (!s_Vk.libWayland) { - return VK_XLIB_PLATFORM; - } +#ifdef __WIN32 + return LoadLibraryA(name); +#elif defined (__linux__) + return dlopen(name, RTLD_LAZY); +#endif +} - int fd = s_Vk.getDisplayFd(display); - if (fd <= 0 || fd > 1024) { // fds are usaually 0-30 but this is fine - return VK_XLIB_PLATFORM; - } - return VK_WAYLAND_PLATFORM; -#else - // Android -#endif // _WIN32 +static void freeLibrary(void* lib) +{ +#ifdef __WIN32 + FreeLibrary((HMODULE)lib); +#elif defined (__linux__) + dlclose(lib); +#endif +} + +static void* loadProc(void* lib, const char* name) +{ +#ifdef __WIN32 + return GetProcAddress((HMODULE)lib, name); +#elif defined (__linux__) + return loadProc(lib, name); +#endif } static bool createSurfaceVk( @@ -470,10 +485,26 @@ static bool createSurfaceVk( { VkResult result; VkSurfaceKHR surface = nullptr; - Uint32 platform = checkPlatformVk(window->display); - if (platform == VK_WIN32_PLATFORM) { - } else if (platform == VK_WAYLAND_PLATFORM) { +#ifdef __WIN32 + if (!s_Vk.createWin32Surface) { + return false; + } + + VkWin32SurfaceCreateInfoKHR cInfo = {0}; + cInfo.hinstance = GetModuleHandle(nullptr); + cInfo.hwnd = window->window; + cInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + + result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.allocateVkator, &surface); + if (result != VK_SUCCESS) { + return false; + } + + *outSurface = surface; + return true; +#else + if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND) { if (!s_Vk.createWaylandSurface) { return false; } @@ -493,8 +524,43 @@ static bool createSurfaceVk( *outSurface = surface; return true; - } else if (platform == VK_XLIB_PLATFORM) { + } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11) { + if (!s_Vk.createXlibSurface) { + return false; + } + + VkXlibSurfaceCreateInfoKHR cInfo = {0}; + cInfo.dpy = window->display; + cInfo.window = window->window; + cInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + + result = s_Vk.createXlibSurface(s_Vk.instance, &cInfo, &s_Vk.allocateVkator, &surface); + if (result != VK_SUCCESS) { + return false; + } + + *outSurface = surface; + return true; + + } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB) { + if (!s_Vk.createXcbSurface) { + return false; + } + + VkXcbSurfaceCreateInfoKHR cInfo = {0}; + cInfo.connection = window->display; + cInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + + result = s_Vk.createXcbSurface(s_Vk.instance, &cInfo, &s_Vk.allocateVkator, &surface); + if (result != VK_SUCCESS) { + return false; + } + + *outSurface = surface; + return true; } + +#endif // __WIN32 } static PalResult resultFromVk(VkResult result) @@ -2162,364 +2228,358 @@ PalResult PAL_CALL initGraphicsVk( const PalGraphicsDebugger* debugger, const PalAllocator* allocator) { - s_Vk.libWayland = nullptr; - s_Vk.libWayland = dlopen("libwayland-client.so.0", RTLD_LAZY); - if (s_Vk.libWayland) { - s_Vk.getDisplayFd = (wl_display_get_fd_fn)dlsym(s_Vk.libWayland, "wl_display_get_fd"); - } - // load vulkan - s_Vk.handle = dlopen(VK_LIB_NAME, RTLD_LAZY); + s_Vk.handle = loadLibrary(VK_LIB_NAME); if (!s_Vk.handle) { return PAL_RESULT_PLATFORM_FAILURE; } // clang-format off - s_Vk.enumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)dlsym( + s_Vk.enumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)loadProc( s_Vk.handle, "vkEnumerateInstanceVersion"); - s_Vk.enumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)dlsym( + s_Vk.enumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)loadProc( s_Vk.handle, "vkEnumerateInstanceExtensionProperties"); - s_Vk.createInstance = (PFN_vkCreateInstance)dlsym( + s_Vk.createInstance = (PFN_vkCreateInstance)loadProc( s_Vk.handle, "vkCreateInstance"); - s_Vk.destroyInstance = (PFN_vkDestroyInstance)dlsym( + s_Vk.destroyInstance = (PFN_vkDestroyInstance)loadProc( s_Vk.handle, "vkDestroyInstance"); - s_Vk.enumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)dlsym( + s_Vk.enumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)loadProc( s_Vk.handle, "vkEnumeratePhysicalDevices"); - s_Vk.getPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)dlsym( + s_Vk.getPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)loadProc( s_Vk.handle, "vkGetPhysicalDeviceProperties"); - s_Vk.getPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)dlsym( + s_Vk.getPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)loadProc( s_Vk.handle, "vkGetPhysicalDeviceMemoryProperties"); - s_Vk.enumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)dlsym( + s_Vk.enumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)loadProc( s_Vk.handle, "vkEnumerateInstanceLayerProperties"); - s_Vk.getPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)dlsym( + s_Vk.getPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)loadProc( s_Vk.handle, "vkGetPhysicalDeviceQueueFamilyProperties"); - s_Vk.enumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)dlsym( + s_Vk.enumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)loadProc( s_Vk.handle, "vkEnumerateDeviceExtensionProperties"); - s_Vk.getPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)dlsym( + s_Vk.getPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)loadProc( s_Vk.handle, "vkGetPhysicalDeviceFeatures"); - s_Vk.getPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)dlsym( + s_Vk.getPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)loadProc( s_Vk.handle, "vkGetPhysicalDeviceFeatures2"); - s_Vk.getInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym( + s_Vk.getInstanceProcAddr = (PFN_vkGetInstanceProcAddr)loadProc( s_Vk.handle, "vkGetInstanceProcAddr"); - s_Vk.createImage = (PFN_vkCreateImage)dlsym( + s_Vk.createImage = (PFN_vkCreateImage)loadProc( s_Vk.handle, "vkCreateImage"); - s_Vk.destroyImage = (PFN_vkDestroyImage)dlsym( + s_Vk.destroyImage = (PFN_vkDestroyImage)loadProc( s_Vk.handle, "vkDestroyImage"); - s_Vk.createImageView = (PFN_vkCreateImageView)dlsym( + s_Vk.createImageView = (PFN_vkCreateImageView)loadProc( s_Vk.handle, "vkCreateImageView"); - s_Vk.destroyImageView = (PFN_vkDestroyImageView)dlsym( + s_Vk.destroyImageView = (PFN_vkDestroyImageView)loadProc( s_Vk.handle, "vkDestroyImageView"); - s_Vk.createShader = (PFN_vkCreateShaderModule)dlsym( + s_Vk.createShader = (PFN_vkCreateShaderModule)loadProc( s_Vk.handle, "vkCreateShaderModule"); - s_Vk.destroyShader = (PFN_vkDestroyShaderModule)dlsym( + s_Vk.destroyShader = (PFN_vkDestroyShaderModule)loadProc( s_Vk.handle, "vkDestroyShaderModule"); - s_Vk.createSampler = (PFN_vkCreateSampler)dlsym( + s_Vk.createSampler = (PFN_vkCreateSampler)loadProc( s_Vk.handle, "vkCreateSampler"); - s_Vk.destroySampler = (PFN_vkDestroySampler)dlsym( + s_Vk.destroySampler = (PFN_vkDestroySampler)loadProc( s_Vk.handle, "vkDestroySampler"); - s_Vk.getPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)dlsym( + s_Vk.getPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)loadProc( s_Vk.handle, "vkGetPhysicalDeviceProperties2"); - s_Vk.getPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)dlsym( + s_Vk.getPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)loadProc( s_Vk.handle, "vkGetPhysicalDeviceFormatProperties"); - s_Vk.createDevice = (PFN_vkCreateDevice)dlsym( + s_Vk.createDevice = (PFN_vkCreateDevice)loadProc( s_Vk.handle, "vkCreateDevice"); - s_Vk.destroyDevice = (PFN_vkDestroyDevice)dlsym( + s_Vk.destroyDevice = (PFN_vkDestroyDevice)loadProc( s_Vk.handle, "vkDestroyDevice"); - s_Vk.getDeviceQueue = (PFN_vkGetDeviceQueue)dlsym( + s_Vk.getDeviceQueue = (PFN_vkGetDeviceQueue)loadProc( s_Vk.handle, "vkGetDeviceQueue"); - s_Vk.queueSubmit = (PFN_vkQueueSubmit)dlsym( + s_Vk.queueSubmit = (PFN_vkQueueSubmit)loadProc( s_Vk.handle, "vkQueueSubmit"); - s_Vk.getDeviceProcAddr = (PFN_vkGetDeviceProcAddr)dlsym( + s_Vk.getDeviceProcAddr = (PFN_vkGetDeviceProcAddr)loadProc( s_Vk.handle, "vkGetDeviceProcAddr"); - s_Vk.getImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)dlsym( + s_Vk.getImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)loadProc( s_Vk.handle, "vkGetImageMemoryRequirements"); - s_Vk.allocateMemory = (PFN_vkAllocateMemory)dlsym( + s_Vk.allocateMemory = (PFN_vkAllocateMemory)loadProc( s_Vk.handle, "vkAllocateMemory"); - s_Vk.freeMemory = (PFN_vkFreeMemory)dlsym( + s_Vk.freeMemory = (PFN_vkFreeMemory)loadProc( s_Vk.handle, "vkFreeMemory"); - s_Vk.bindImageMemory = (PFN_vkBindImageMemory)dlsym( + s_Vk.bindImageMemory = (PFN_vkBindImageMemory)loadProc( s_Vk.handle, "vkBindImageMemory"); - s_Vk.createCommandPool = (PFN_vkCreateCommandPool)dlsym( + s_Vk.createCommandPool = (PFN_vkCreateCommandPool)loadProc( s_Vk.handle, "vkCreateCommandPool"); - s_Vk.destroyCommandPool = (PFN_vkDestroyCommandPool)dlsym( + s_Vk.destroyCommandPool = (PFN_vkDestroyCommandPool)loadProc( s_Vk.handle, "vkDestroyCommandPool"); - s_Vk.allocateCommandBuffer = (PFN_vkAllocateCommandBuffers)dlsym( + s_Vk.allocateCommandBuffer = (PFN_vkAllocateCommandBuffers)loadProc( s_Vk.handle, "vkAllocateCommandBuffers"); - s_Vk.freeCommandBuffer = (PFN_vkFreeCommandBuffers)dlsym( + s_Vk.freeCommandBuffer = (PFN_vkFreeCommandBuffers)loadProc( s_Vk.handle, "vkFreeCommandBuffers"); - s_Vk.createFence = (PFN_vkCreateFence)dlsym( + s_Vk.createFence = (PFN_vkCreateFence)loadProc( s_Vk.handle, "vkCreateFence"); - s_Vk.destroyFence = (PFN_vkDestroyFence)dlsym( + s_Vk.destroyFence = (PFN_vkDestroyFence)loadProc( s_Vk.handle, "vkDestroyFence"); - s_Vk.resetFence = (PFN_vkResetFences)dlsym( + s_Vk.resetFence = (PFN_vkResetFences)loadProc( s_Vk.handle, "vkResetFences"); - s_Vk.waitFence = (PFN_vkWaitForFences)dlsym( + s_Vk.waitFence = (PFN_vkWaitForFences)loadProc( s_Vk.handle, "vkWaitForFences"); - s_Vk.isFenceSignaled = (PFN_vkGetFenceStatus)dlsym( + s_Vk.isFenceSignaled = (PFN_vkGetFenceStatus)loadProc( s_Vk.handle, "vkGetFenceStatus"); - s_Vk.createSemaphore = (PFN_vkCreateSemaphore)dlsym( + s_Vk.createSemaphore = (PFN_vkCreateSemaphore)loadProc( s_Vk.handle, "vkCreateSemaphore"); - s_Vk.destroySemaphore = (PFN_vkDestroySemaphore)dlsym( + s_Vk.destroySemaphore = (PFN_vkDestroySemaphore)loadProc( s_Vk.handle, "vkDestroySemaphore"); - s_Vk.cmdBegin = (PFN_vkBeginCommandBuffer)dlsym( + s_Vk.cmdBegin = (PFN_vkBeginCommandBuffer)loadProc( s_Vk.handle, "vkBeginCommandBuffer"); - s_Vk.cmdEnd = (PFN_vkEndCommandBuffer)dlsym( + s_Vk.cmdEnd = (PFN_vkEndCommandBuffer)loadProc( s_Vk.handle, "vkEndCommandBuffer"); - s_Vk.resetCommandPool = (PFN_vkResetCommandPool)dlsym( + s_Vk.resetCommandPool = (PFN_vkResetCommandPool)loadProc( s_Vk.handle, "vkResetCommandPool"); - s_Vk.resetCommandBuffer = (PFN_vkResetCommandBuffer)dlsym( + s_Vk.resetCommandBuffer = (PFN_vkResetCommandBuffer)loadProc( s_Vk.handle, "vkResetCommandBuffer"); - s_Vk.cmdExecuteCommandBuffer = (PFN_vkCmdExecuteCommands)dlsym( + s_Vk.cmdExecuteCommandBuffer = (PFN_vkCmdExecuteCommands)loadProc( s_Vk.handle, "vkCmdExecuteCommands"); - s_Vk.cmdCopyBuffer = (PFN_vkCmdCopyBuffer)dlsym( + s_Vk.cmdCopyBuffer = (PFN_vkCmdCopyBuffer)loadProc( s_Vk.handle, "vkCmdCopyBuffer"); - s_Vk.cmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)dlsym( + s_Vk.cmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)loadProc( s_Vk.handle, "vkCmdCopyBufferToImage"); - s_Vk.cmdCopyImage = (PFN_vkCmdCopyImage)dlsym( + s_Vk.cmdCopyImage = (PFN_vkCmdCopyImage)loadProc( s_Vk.handle, "vkCmdCopyImage"); - s_Vk.cmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)dlsym( + s_Vk.cmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)loadProc( s_Vk.handle, "vkCmdCopyImageToBuffer"); - s_Vk.cmdBindPipeline = (PFN_vkCmdBindPipeline)dlsym( + s_Vk.cmdBindPipeline = (PFN_vkCmdBindPipeline)loadProc( s_Vk.handle, "vkCmdBindPipeline"); - s_Vk.cmdSetViewports = (PFN_vkCmdSetViewport)dlsym( + s_Vk.cmdSetViewports = (PFN_vkCmdSetViewport)loadProc( s_Vk.handle, "vkCmdSetViewport"); - s_Vk.cmdSetScissors = (PFN_vkCmdSetScissor)dlsym( + s_Vk.cmdSetScissors = (PFN_vkCmdSetScissor)loadProc( s_Vk.handle, "vkCmdSetScissor"); - s_Vk.cmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)dlsym( + s_Vk.cmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)loadProc( s_Vk.handle, "vkCmdBindVertexBuffers"); - s_Vk.cmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)dlsym( + s_Vk.cmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)loadProc( s_Vk.handle, "vkCmdBindIndexBuffer"); - s_Vk.cmdDraw = (PFN_vkCmdDraw)dlsym( + s_Vk.cmdDraw = (PFN_vkCmdDraw)loadProc( s_Vk.handle, "vkCmdDraw"); - s_Vk.cmdDrawIndirect = (PFN_vkCmdDrawIndirect)dlsym( + s_Vk.cmdDrawIndirect = (PFN_vkCmdDrawIndirect)loadProc( s_Vk.handle, "vkCmdDrawIndirect"); - s_Vk.cmdDrawIndexed = (PFN_vkCmdDrawIndexed)dlsym( + s_Vk.cmdDrawIndexed = (PFN_vkCmdDrawIndexed)loadProc( s_Vk.handle, "vkCmdDrawIndexed"); - s_Vk.cmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)dlsym( + s_Vk.cmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)loadProc( s_Vk.handle, "vkCmdDrawIndexedIndirect"); - s_Vk.cmdDispatch = (PFN_vkCmdDispatch)dlsym( + s_Vk.cmdDispatch = (PFN_vkCmdDispatch)loadProc( s_Vk.handle, "vkCmdDispatch"); - s_Vk.cmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)dlsym( + s_Vk.cmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)loadProc( s_Vk.handle, "vkCmdDispatchIndirect"); - s_Vk.cmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)dlsym( + s_Vk.cmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)loadProc( s_Vk.handle, "vkCmdBindDescriptorSets"); - s_Vk.cmdPushConstants = (PFN_vkCmdPushConstants)dlsym( + s_Vk.cmdPushConstants = (PFN_vkCmdPushConstants)loadProc( s_Vk.handle, "vkCmdPushConstants"); - s_Vk.createBuffer = (PFN_vkCreateBuffer)dlsym( + s_Vk.createBuffer = (PFN_vkCreateBuffer)loadProc( s_Vk.handle, "vkCreateBuffer"); - s_Vk.destroyBuffer = (PFN_vkDestroyBuffer)dlsym( + s_Vk.destroyBuffer = (PFN_vkDestroyBuffer)loadProc( s_Vk.handle, "vkDestroyBuffer"); - s_Vk.mapMemory = (PFN_vkMapMemory)dlsym( + s_Vk.mapMemory = (PFN_vkMapMemory)loadProc( s_Vk.handle, "vkMapMemory"); - s_Vk.unmapMemory = (PFN_vkUnmapMemory)dlsym( + s_Vk.unmapMemory = (PFN_vkUnmapMemory)loadProc( s_Vk.handle, "vkUnmapMemory"); - s_Vk.getBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)dlsym( + s_Vk.getBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)loadProc( s_Vk.handle, "vkGetBufferDeviceAddress"); - s_Vk.getBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)dlsym( + s_Vk.getBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)loadProc( s_Vk.handle, "vkGetBufferMemoryRequirements"); - s_Vk.bindBufferMemory = (PFN_vkBindBufferMemory)dlsym( + s_Vk.bindBufferMemory = (PFN_vkBindBufferMemory)loadProc( s_Vk.handle, "vkBindBufferMemory"); - s_Vk.createDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)dlsym( + s_Vk.createDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)loadProc( s_Vk.handle, "vkCreateDescriptorSetLayout"); - s_Vk.destroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)dlsym( + s_Vk.destroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)loadProc( s_Vk.handle, "vkDestroyDescriptorSetLayout"); - s_Vk.createDescriptorPool = (PFN_vkCreateDescriptorPool)dlsym( + s_Vk.createDescriptorPool = (PFN_vkCreateDescriptorPool)loadProc( s_Vk.handle, "vkCreateDescriptorPool"); - s_Vk.destroyDescriptorPool = (PFN_vkDestroyDescriptorPool)dlsym( + s_Vk.destroyDescriptorPool = (PFN_vkDestroyDescriptorPool)loadProc( s_Vk.handle, "vkDestroyDescriptorPool"); - s_Vk.resetDescriptorPool = (PFN_vkResetDescriptorPool)dlsym( + s_Vk.resetDescriptorPool = (PFN_vkResetDescriptorPool)loadProc( s_Vk.handle, "vkResetDescriptorPool"); - s_Vk.allocateDescriptorSet = (PFN_vkAllocateDescriptorSets)dlsym( + s_Vk.allocateDescriptorSet = (PFN_vkAllocateDescriptorSets)loadProc( s_Vk.handle, "vkAllocateDescriptorSets"); - s_Vk.freeDescriptorSet = (PFN_vkFreeDescriptorSets)dlsym( + s_Vk.freeDescriptorSet = (PFN_vkFreeDescriptorSets)loadProc( s_Vk.handle, "vkFreeDescriptorSets"); - s_Vk.updateDescriptorSet = (PFN_vkUpdateDescriptorSets)dlsym( + s_Vk.updateDescriptorSet = (PFN_vkUpdateDescriptorSets)loadProc( s_Vk.handle, "vkUpdateDescriptorSets"); - s_Vk.createPipelineLayout = (PFN_vkCreatePipelineLayout)dlsym( + s_Vk.createPipelineLayout = (PFN_vkCreatePipelineLayout)loadProc( s_Vk.handle, "vkCreatePipelineLayout"); - s_Vk.destroyPipelineLayout = (PFN_vkDestroyPipelineLayout)dlsym( + s_Vk.destroyPipelineLayout = (PFN_vkDestroyPipelineLayout)loadProc( s_Vk.handle, "vkDestroyPipelineLayout"); - s_Vk.createGraphicsPipeline = (PFN_vkCreateGraphicsPipelines)dlsym( + s_Vk.createGraphicsPipeline = (PFN_vkCreateGraphicsPipelines)loadProc( s_Vk.handle, "vkCreateGraphicsPipelines"); - s_Vk.createComputePipeline = (PFN_vkCreateComputePipelines)dlsym( + s_Vk.createComputePipeline = (PFN_vkCreateComputePipelines)loadProc( s_Vk.handle, "vkCreateComputePipelines"); - s_Vk.destroyPipeline = (PFN_vkDestroyPipeline)dlsym( + s_Vk.destroyPipeline = (PFN_vkDestroyPipeline)loadProc( s_Vk.handle, "vkDestroyPipeline"); - s_Vk.waitDevice = (PFN_vkDeviceWaitIdle)dlsym( + s_Vk.waitDevice = (PFN_vkDeviceWaitIdle)loadProc( s_Vk.handle, "vkDeviceWaitIdle"); - s_Vk.waitQueue = (PFN_vkQueueWaitIdle)dlsym( + s_Vk.waitQueue = (PFN_vkQueueWaitIdle)loadProc( s_Vk.handle, "vkQueueWaitIdle"); // clang-format on @@ -2590,7 +2650,9 @@ PalResult PAL_CALL initGraphicsVk( } bool hasXlib = false; + bool hasXcb = false; bool hasWayland = false; + bool hasWin32 = false; bool hasSurface = false; bool hasExtDebug = false; s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, extensionProps); @@ -2600,9 +2662,15 @@ PalResult PAL_CALL initGraphicsVk( if (strcmp(prop->extensionName, "VK_KHR_xlib_surface") == 0) { hasXlib = true; + } else if (strcmp(prop->extensionName, "VK_KHR_xcb_surface") == 0) { + hasXcb = true; + } else if (strcmp(prop->extensionName, "VK_KHR_wayland_surface") == 0) { hasWayland = true; + } else if (strcmp(prop->extensionName, "VK_KHR_win32_surface") == 0) { + hasWin32 = true; + } else if (strcmp(prop->extensionName, "VK_KHR_surface") == 0) { hasSurface = true; @@ -2702,6 +2770,28 @@ PalResult PAL_CALL initGraphicsVk( "vkGetPhysicalDeviceXlibPresentationSupportKHR"); } + if (hasXcb) { + s_Vk.createXcbSurface = (PFN_vkCreateXcbSurfaceKHR)s_Vk.getInstanceProcAddr( + instance, + "vkCreateXcbSurfaceKHR"); + + s_Vk.checkXcbPresentSupport = + (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceXcbPresentationSupportKHR"); + } + + if (hasWin32) { + s_Vk.createWin32Surface = (PFN_vkCreateWin32SurfaceKHR)s_Vk.getInstanceProcAddr( + instance, + "vkCreateWin32SurfaceKHR"); + + s_Vk.checkWin32PresentSupport = + (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceWin32PresentationSupportKHR"); + } + // remaining function procs s_Vk.destroySurface = (PFN_vkDestroySurfaceKHR)s_Vk.getInstanceProcAddr( instance, @@ -2748,10 +2838,7 @@ PalResult PAL_CALL shutdownGraphicsVk() } s_Vk.destroyInstance(s_Vk.instance, &s_Vk.allocateVkator); - dlclose(s_Vk.handle); - if (s_Vk.libWayland) { - dlclose(s_Vk.libWayland); - } + freeLibrary(s_Vk.handle); if (s_Vk.adapters) { palFree(s_Vk.allocator, s_Vk.adapters); @@ -4489,11 +4576,15 @@ bool PAL_CALL canQueuePresentVk( return false; } - Uint32 platform = checkPlatformVk(window->display); PhysicalQueue* phyQueue = vkQueue->phyQueue; - if (platform == VK_WIN32_PLATFORM) { - - } else if (platform == VK_WAYLAND_PLATFORM) { +#ifdef __WIN32 + if (s_Vk.checkWin32PresentSupport( + phyQueue->phyDevice, + phyQueue->familyIndex)) { + return true; + } +#else + if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND) { if (s_Vk.checkWaylandPresentSupport( phyQueue->phyDevice, phyQueue->familyIndex, @@ -4501,8 +4592,27 @@ bool PAL_CALL canQueuePresentVk( return true; } - } else if (platform == VK_XLIB_PLATFORM) { + } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11) { + // TODO: get visual ID + + // if (s_Vk.checkXlibPresentSupport( + // phyQueue->phyDevice, + // phyQueue->familyIndex, + // window->display)) { + // return true; + // } + + } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB) { + // TODO: get visual ID + + // if (s_Vk.checkXcbPresentSupport( + // phyQueue->phyDevice, + // phyQueue->familyIndex, + // window->display)) { + // return true; + // } } +#endif // __WIN32 return false; } diff --git a/tests/tests_main.c b/tests/tests_main.c index 7a34b1b6..11c555b0 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,7 +57,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest); + registerTest(graphicsTest); // registerTest(computeTest); // registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS @@ -66,7 +66,7 @@ int main(int argc, char** argv) // registerTest(clearColorTest); // registerTest(triangleTest); // registerTest(meshTest); - registerTest(textureTest); + // registerTest(textureTest); #endif // runTests(); From a94354538631d8d21d4a6fcf5b9d16721603ecb7 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 22 Mar 2026 00:20:41 +0000 Subject: [PATCH 113/372] finish linux portability --- src/graphics/pal_vulkan.c | 359 +++++++++++++++++++++++++++++--------- 1 file changed, 276 insertions(+), 83 deletions(-) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index aa2c895f..13ae4aae 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -37,7 +37,6 @@ freely, subject to the following restrictions: // HACK: Needed to determine display type if on linux #ifdef _WIN32 #include -#include #define VK_LIB_NAME "vulkan-1.dll" #elif defined(__linux__) #include @@ -56,27 +55,166 @@ freely, subject to the following restrictions: #define RAY_TRACING_PIPELINE 126 #define COMPUTE_PIPELINE 127 +#pragma region Video + struct wl_display; struct wl_surface; typedef struct _XDisplay Display; typedef unsigned long Window; typedef unsigned long VisualID; +typedef unsigned long Colormap; +typedef char *XPointer; +typedef struct _XGC *GC; + +typedef struct _XExtData { + int number; + struct _XExtData *next; + int (*free_private)( + struct _XExtData *extension + ); + XPointer private_data; +} XExtData; + +typedef struct { + XExtData *ext_data; + VisualID visualid; + int class; + unsigned long red_mask, green_mask, blue_mask; + int bits_per_rgb; + int map_entries; +} Visual; + +typedef struct { + int depth; + int nvisuals; + Visual *visuals; +} Depth; + +typedef struct { + XExtData *ext_data; + struct _XDisplay *display; + Window root; + int width, height; + int mwidth, mheight; + int ndepths; + Depth *depths; + int root_depth; + Visual *root_visual; + GC default_gc; + Colormap cmap; + unsigned long white_pixel; + unsigned long black_pixel; + int max_maps, min_maps; + int backing_store; + int save_unders; + long root_input_mask; +} Screen; + +typedef struct { + int x, y; + int width, height; + int border_width; + int depth; + Visual *visual; + Window root; + int class; + int bit_gravity; + int win_gravity; + int backing_store; + unsigned long backing_planes; + unsigned long backing_pixel; + int save_under; + Colormap colormap; + int map_installed; + int map_state; + long all_event_masks; + long your_event_mask; + long do_not_propagate_mask; + int override_redirect; + Screen *screen; +} XWindowAttributes; + +typedef int (*XGetWindowAttributesFn)( + Display*, + Window, + XWindowAttributes*); + +typedef VisualID (*XVisualIDFromVisualFn)(Visual*); typedef struct xcb_connection_t xcb_connection_t; typedef uint32_t xcb_window_t; typedef uint32_t xcb_visualid_t; +typedef uint32_t xcb_colormap_t; + +typedef struct xcb_get_window_attributes_cookie_t { + unsigned int sequence; +} xcb_get_window_attributes_cookie_t; + +typedef struct xcb_get_window_attributes_reply_t { + uint8_t response_type; + uint8_t backing_store; + uint16_t sequence; + uint32_t length; + xcb_visualid_t visual; + uint16_t _class; + uint8_t bit_gravity; + uint8_t win_gravity; + uint32_t backing_planes; + uint32_t backing_pixel; + uint8_t save_under; + uint8_t map_is_installed; + uint8_t map_state; + uint8_t override_redirect; + xcb_colormap_t colormap; + uint32_t all_event_masks; + uint32_t your_event_mask; + uint16_t do_not_propagate_mask; + uint8_t pad0[2]; +} xcb_get_window_attributes_reply_t; + +typedef struct { + uint8_t response_type; + uint8_t error_code; + uint16_t sequence; + uint32_t resource_id; + uint16_t minor_code; + uint8_t major_code; + uint8_t pad0; + uint32_t pad[5]; + uint32_t full_sequence; +} xcb_generic_error_t; + +typedef xcb_get_window_attributes_cookie_t (*xcb_get_window_attributes_fn)( + xcb_connection_t*, + xcb_window_t); + +typedef xcb_get_window_attributes_reply_t* (*xcb_get_window_attributes_reply_fn)( + xcb_connection_t*, + xcb_get_window_attributes_cookie_t, + xcb_generic_error_t**); typedef unsigned long DWORD; typedef int WINBOOL; typedef void *LPVOID; typedef const wchar_t *LPCWSTR,*PCWSTR; typedef void *HANDLE; +typedef struct HINSTANCE__ *HINSTANCE; +typedef struct HWND__ *HWND; +typedef struct HMONITOR__ *HMONITOR; + +typedef struct _SECURITY_ATTRIBUTES { + DWORD nLength; + LPVOID ipSecurityDescriptor; + WINBOOL bInheritHandle; +} SECURITY_ATTRIBUTES; #include #include #include #include +#pragma endregion + typedef struct { const PalGraphicsBackend* backend; @@ -94,6 +232,14 @@ typedef struct { VkDebugUtilsMessengerEXT messenger; PalDebugCallback callback; + void* libX; + XGetWindowAttributesFn XGetWindowAttributes; + XVisualIDFromVisualFn XVisualIDFromVisual; + + void* libXcb; + xcb_get_window_attributes_fn xcbGetWindowAttributes; + xcb_get_window_attributes_reply_fn xcbGetWindowAttributesReply; + PFN_vkEnumerateInstanceVersion enumerateInstanceVersion; PFN_vkEnumerateInstanceExtensionProperties enumerateInstanceExtensionProperties; PFN_vkDestroyInstance destroyInstance; @@ -204,7 +350,7 @@ typedef struct { PFN_vkDeviceWaitIdle waitDevice; PFN_vkQueueWaitIdle waitQueue; - VkAllocationCallbacks allocateVkator; + VkAllocationCallbacks vkAllocator; const PalAllocator* allocator; } Vulkan; @@ -475,7 +621,7 @@ static void* loadProc(void* lib, const char* name) #ifdef __WIN32 return GetProcAddress((HMODULE)lib, name); #elif defined (__linux__) - return loadProc(lib, name); + return dlsym(lib, name); #endif } @@ -496,7 +642,7 @@ static bool createSurfaceVk( cInfo.hwnd = window->window; cInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; - result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.allocateVkator, &surface); + result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &surface); if (result != VK_SUCCESS) { return false; } @@ -516,7 +662,7 @@ static bool createSurfaceVk( cInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; cInfo.surface = window->window; - result = s_Vk.createWaylandSurface(s_Vk.instance, &cInfo, &s_Vk.allocateVkator, &surface); + result = s_Vk.createWaylandSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &surface); if (result != VK_SUCCESS) { return false; } @@ -531,10 +677,10 @@ static bool createSurfaceVk( VkXlibSurfaceCreateInfoKHR cInfo = {0}; cInfo.dpy = window->display; - cInfo.window = window->window; + cInfo.window = (Window)(UintPtr)(window->window); cInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - result = s_Vk.createXlibSurface(s_Vk.instance, &cInfo, &s_Vk.allocateVkator, &surface); + result = s_Vk.createXlibSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &surface); if (result != VK_SUCCESS) { return false; } @@ -551,7 +697,7 @@ static bool createSurfaceVk( cInfo.connection = window->display; cInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; - result = s_Vk.createXcbSurface(s_Vk.instance, &cInfo, &s_Vk.allocateVkator, &surface); + result = s_Vk.createXcbSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &surface); if (result != VK_SUCCESS) { return false; } @@ -1970,27 +2116,27 @@ static VkShaderStageFlags shaderStageToVK(PalShaderStage stage) return 0; } -static void* allocateVk( +static void* VKAPI_CALL allocateVk( void* pUserData, size_t size, - size_t alignVkment, + size_t alignment, VkSystemAllocationScope allocationScope) { - return palAllocate(s_Vk.allocator, size, alignVkment); + return palAllocate(s_Vk.allocator, size, alignment); } -static void freeVk( +static void VKAPI_CALL freeVk( void* pUserData, void* ptr) { palFree(s_Vk.allocator, ptr); } -static void* reallocVk( +static void* VKAPI_CALL reallocVk( void* pUserData, void* pOriginal, size_t size, - size_t alignVkment, + size_t alignment, VkSystemAllocationScope allocationScope) { // Note: This is a hack which could cost performance but @@ -1998,7 +2144,7 @@ static void* reallocVk( // this is because we dont know the old size void* block = realloc(pOriginal, size); if (block) { - void* memory = palAllocate(s_Vk.allocator, size, alignVkment); + void* memory = palAllocate(s_Vk.allocator, size, alignment); if (!memory) { free(block); return nullptr; @@ -2011,7 +2157,7 @@ static void* reallocVk( return nullptr; } -VkBool32 debugCallbackVk( +VkBool32 VKAPI_CALL debugCallbackVk( VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagBitsEXT type, const VkDebugUtilsMessengerCallbackDataEXT* data, @@ -2096,9 +2242,9 @@ static Uint32 findBestMemoryIndexVk( static inline Uint32 alignVk( Uint32 value, - Uint32 alignVkment) + Uint32 alignment) { - return (value + alignVkment - 1) & ~(alignVkment - 1); + return (value + alignment - 1) & ~(alignment - 1); } static void fillVkBuildInfoVk( @@ -2725,12 +2871,12 @@ PalResult PAL_CALL initGraphicsVk( } // vk allocator - s_Vk.allocateVkator.pfnAllocation = allocateVk; - s_Vk.allocateVkator.pfnFree = freeVk; - s_Vk.allocateVkator.pfnReallocation = reallocVk; + s_Vk.vkAllocator.pfnAllocation = allocateVk; + s_Vk.vkAllocator.pfnFree = freeVk; + s_Vk.vkAllocator.pfnReallocation = reallocVk; VkInstance instance = nullptr; - result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.allocateVkator, &instance); + result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.vkAllocator, &instance); if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -2760,6 +2906,17 @@ PalResult PAL_CALL initGraphicsVk( } if (hasXlib) { + s_Vk.libX = loadLibrary("libX11.so"); + if (s_Vk.libX) { + s_Vk.XGetWindowAttributes = (XGetWindowAttributesFn)loadProc( + s_Vk.libX, + "XGetWindowAttributes"); + + s_Vk.XVisualIDFromVisual = (XVisualIDFromVisualFn)loadProc( + s_Vk.libX, + "XVisualIDFromVisual"); + } + s_Vk.createXlibSurface = (PFN_vkCreateXlibSurfaceKHR)s_Vk.getInstanceProcAddr( instance, "vkCreateXlibSurfaceKHR"); @@ -2771,6 +2928,17 @@ PalResult PAL_CALL initGraphicsVk( } if (hasXcb) { + s_Vk.libXcb = loadLibrary("libxcb.so.1"); + if (s_Vk.libXcb) { + s_Vk.xcbGetWindowAttributes = (xcb_get_window_attributes_fn)loadProc( + s_Vk.libXcb, + "xcb_get_window_attributes"); + + s_Vk.xcbGetWindowAttributesReply = (xcb_get_window_attributes_reply_fn)loadProc( + s_Vk.libXcb, + "xcb_get_window_attributes_reply"); + } + s_Vk.createXcbSurface = (PFN_vkCreateXcbSurfaceKHR)s_Vk.getInstanceProcAddr( instance, "vkCreateXcbSurfaceKHR"); @@ -2822,7 +2990,7 @@ PalResult PAL_CALL initGraphicsVk( instance, "vkDestroyDebugUtilsMessengerEXT"); - s_Vk.createMessenger(instance, &debugCreateInfo, &s_Vk.allocateVkator, &s_Vk.messenger); + s_Vk.createMessenger(instance, &debugCreateInfo, &s_Vk.vkAllocator, &s_Vk.messenger); } // clang-format on @@ -2834,12 +3002,20 @@ PalResult PAL_CALL initGraphicsVk( PalResult PAL_CALL shutdownGraphicsVk() { if (s_Vk.messenger) { - s_Vk.destroyMessenger(s_Vk.instance, s_Vk.messenger, &s_Vk.allocateVkator); + s_Vk.destroyMessenger(s_Vk.instance, s_Vk.messenger, &s_Vk.vkAllocator); } - s_Vk.destroyInstance(s_Vk.instance, &s_Vk.allocateVkator); + s_Vk.destroyInstance(s_Vk.instance, &s_Vk.vkAllocator); freeLibrary(s_Vk.handle); + if (s_Vk.libX) { + freeLibrary(s_Vk.libX); + } + + if (s_Vk.libXcb) { + freeLibrary(s_Vk.libXcb); + } + if (s_Vk.adapters) { palFree(s_Vk.allocator, s_Vk.adapters); } @@ -3769,7 +3945,7 @@ PalResult PAL_CALL createDeviceVk( createInfo.queueCreateInfoCount = queueCount; createInfo.pNext = next; - result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.allocateVkator, &device->handle); + result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.vkAllocator, &device->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, queueProps); palFree(s_Vk.allocator, queueCreateInfos); @@ -4157,7 +4333,7 @@ PalResult PAL_CALL createDeviceVk( void PAL_CALL destroyDeviceVk(PalDevice* device) { Device* vkDevice = (Device*)device; - s_Vk.destroyDevice(vkDevice->handle, &s_Vk.allocateVkator); + s_Vk.destroyDevice(vkDevice->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkDevice->phyQueues); palFree(s_Vk.allocator, vkDevice); } @@ -4218,7 +4394,7 @@ PalResult PAL_CALL allocateMemoryVk( allocateInfo.pNext = &allocateFlagsInfo; } - result = s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.allocateVkator, &memory); + result = s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &memory); if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -4233,7 +4409,7 @@ void PAL_CALL freeMemoryVk( { Device* vkDevice = (Device*)device; VkDeviceMemory mem = (VkDeviceMemory)memory; - s_Vk.freeMemory(vkDevice->handle, mem, &s_Vk.allocateVkator); + s_Vk.freeMemory(vkDevice->handle, mem, &s_Vk.vkAllocator); } PalResult PAL_CALL mapMemoryVk( @@ -4593,24 +4769,41 @@ bool PAL_CALL canQueuePresentVk( } } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11) { - // TODO: get visual ID + XWindowAttributes attrs = {0}; + Window xWin = (Window)(UintPtr)(window->window); + VisualID visualID = 0; - // if (s_Vk.checkXlibPresentSupport( - // phyQueue->phyDevice, - // phyQueue->familyIndex, - // window->display)) { - // return true; - // } + if (s_Vk.XGetWindowAttributes(window->display, xWin, &attrs)) { + visualID = s_Vk.XVisualIDFromVisual(attrs.visual); + } + + if (s_Vk.checkXlibPresentSupport( + phyQueue->phyDevice, + phyQueue->familyIndex, + window->display, + visualID)) { + return true; + } } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB) { - // TODO: get visual ID + xcb_get_window_attributes_cookie_t cookie = {0}; + xcb_get_window_attributes_reply_t* reply = nullptr; + xcb_window_t xcbWin = (xcb_window_t)(UintPtr)(window->window); + + cookie = s_Vk.xcbGetWindowAttributes(window->display, xcbWin); + reply = s_Vk.xcbGetWindowAttributesReply(window->display, cookie, nullptr); + if (!reply) { + return false; + } - // if (s_Vk.checkXcbPresentSupport( - // phyQueue->phyDevice, - // phyQueue->familyIndex, - // window->display)) { - // return true; - // } + if (s_Vk.checkXcbPresentSupport( + phyQueue->phyDevice, + phyQueue->familyIndex, + window->display, + reply->visual)) { + free(reply); + return true; + } } #endif // __WIN32 return false; @@ -4800,7 +4993,7 @@ PalResult PAL_CALL createImageVk( createInfo.extent.depth = info->depthOrArraySize; } - result = s_Vk.createImage(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &image->handle); + result = s_Vk.createImage(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &image->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, image); return resultFromVk(result); @@ -4845,7 +5038,7 @@ void PAL_CALL destroyImageVk(PalImage* image) return; } - s_Vk.destroyImage(vkImage->device->handle, vkImage->handle, &s_Vk.allocateVkator); + s_Vk.destroyImage(vkImage->device->handle, vkImage->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkImage); } @@ -4954,7 +5147,7 @@ PalResult PAL_CALL createImageViewVk( result = s_Vk.createImageView( vkDevice->handle, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &imageView->handle); if (result != VK_SUCCESS) { @@ -4975,7 +5168,7 @@ PalResult PAL_CALL createImageViewVk( void PAL_CALL destroyImageViewVk(PalImageView* imageView) { ImageView* vkImageView = (ImageView*)imageView; - s_Vk.destroyImageView(vkImageView->device->handle, vkImageView->handle, &s_Vk.allocateVkator); + s_Vk.destroyImageView(vkImageView->device->handle, vkImageView->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkImageView); } @@ -5153,7 +5346,7 @@ PalResult PAL_CALL createSamplerVk( result = s_Vk.createSampler( vkDevice->handle, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &sampler->handle); if (result != VK_SUCCESS) { @@ -5169,7 +5362,7 @@ PalResult PAL_CALL createSamplerVk( void PAL_CALL destroySamplerVk(PalSampler* sampler) { Sampler* vkSampler = (Sampler*)sampler; - s_Vk.destroySampler(vkSampler->device->handle, vkSampler->handle, &s_Vk.allocateVkator); + s_Vk.destroySampler(vkSampler->device->handle, vkSampler->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkSampler); } @@ -5207,7 +5400,7 @@ PalResult PAL_CALL querySwapchainCapabilitiesVk( modes = palAllocate(s_Vk.allocator, sizeof(VkPresentModeKHR) * modeCount, 0); formats = palAllocate(s_Vk.allocator, sizeof(VkSurfaceFormatKHR) * formatCount, 0); if (!modes || !formats) { - s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocateVkator); + s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.vkAllocator); return PAL_RESULT_OUT_OF_MEMORY; } @@ -5294,7 +5487,7 @@ PalResult PAL_CALL querySwapchainCapabilitiesVk( palFree(s_Vk.allocator, formats); palFree(s_Vk.allocator, modes); - s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.allocateVkator); + s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.vkAllocator); return PAL_RESULT_SUCCESS; } @@ -5387,11 +5580,11 @@ PalResult PAL_CALL createSwapchainVk( VkResult result = vkDevice->createSwapchain( vkDevice->handle, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &swapchain->handle); if (result != VK_SUCCESS) { - s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.allocateVkator); + s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.vkAllocator); palFree(s_Vk.allocator, swapchain); return resultFromVk(result); @@ -5404,8 +5597,8 @@ PalResult PAL_CALL createSwapchainVk( swapchain->images = palAllocate(s_Vk.allocator, sizeof(Image) * count, 0); images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); if (!swapchain->images || !images) { - vkDevice->destroySwapchain(vkDevice->handle, swapchain->handle, &s_Vk.allocateVkator); - s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.allocateVkator); + vkDevice->destroySwapchain(vkDevice->handle, swapchain->handle, &s_Vk.vkAllocator); + s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.vkAllocator); palFree(s_Vk.allocator, swapchain); return PAL_RESULT_OUT_OF_MEMORY; } @@ -5443,9 +5636,9 @@ void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain) vkSwapchain->device->destroySwapchain( vkSwapchain->device->handle, vkSwapchain->handle, - &s_Vk.allocateVkator); + &s_Vk.vkAllocator); - s_Vk.destroySurface(s_Vk.instance, vkSwapchain->surface, &s_Vk.allocateVkator); + s_Vk.destroySurface(s_Vk.instance, vkSwapchain->surface, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkSwapchain->images); palFree(s_Vk.allocator, vkSwapchain); @@ -5583,7 +5776,7 @@ PalResult PAL_CALL createShaderVk( createInfo.pCode = (const Uint32*)info->bytecode; result = - s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &shader->handle); + s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, shader); @@ -5604,7 +5797,7 @@ PalResult PAL_CALL createShaderVk( void PAL_CALL destroyShaderVk(PalShader* shader) { Shader* vkShader = (Shader*)shader; - s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.allocateVkator); + s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkShader); } @@ -5633,7 +5826,7 @@ PalResult PAL_CALL createFenceVk( createInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; } - result = s_Vk.createFence(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &fence->handle); + result = s_Vk.createFence(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &fence->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, fence); return resultFromVk(result); @@ -5647,7 +5840,7 @@ PalResult PAL_CALL createFenceVk( void PAL_CALL destroyFenceVk(PalFence* fence) { Fence* vkFence = (Fence*)fence; - s_Vk.destroyFence(vkFence->device->handle, vkFence->handle, &s_Vk.allocateVkator); + s_Vk.destroyFence(vkFence->device->handle, vkFence->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkFence); } @@ -5733,7 +5926,7 @@ PalResult PAL_CALL createSemaphoreVk( result = s_Vk.createSemaphore( vkDevice->handle, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &semaphore->handle); if (result != VK_SUCCESS) { @@ -5749,7 +5942,7 @@ PalResult PAL_CALL createSemaphoreVk( void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore) { Semaphore* vkSemaphore = (Semaphore*)semaphore; - s_Vk.destroySemaphore(vkSemaphore->device->handle, vkSemaphore->handle, &s_Vk.allocateVkator); + s_Vk.destroySemaphore(vkSemaphore->device->handle, vkSemaphore->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkSemaphore); } @@ -5850,7 +6043,7 @@ PalResult PAL_CALL createCommandPoolVk( createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; result = - s_Vk.createCommandPool(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &pool->handle); + s_Vk.createCommandPool(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &pool->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pool); @@ -5865,7 +6058,7 @@ PalResult PAL_CALL createCommandPoolVk( void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool) { CommandPool* vkPool = (CommandPool*)pool; - s_Vk.destroyCommandPool(vkPool->device->handle, vkPool->handle, &s_Vk.allocateVkator); + s_Vk.destroyCommandPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkPool); } @@ -7294,7 +7487,7 @@ PalResult PAL_CALL createAccelerationstructureVk( result = vkDevice->createAccelerationStructure( vkDevice->handle, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &as->handle); if (result != VK_SUCCESS) { @@ -7319,7 +7512,7 @@ void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as) vkAs->device->destroyAccelerationStructure( vkAs->device->handle, vkAs->handle, - &s_Vk.allocateVkator); + &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkAs); } @@ -7407,7 +7600,7 @@ PalResult PAL_CALL createBufferVk( createInfo.usage = bufferUsageToVk(info->usages); result = - s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.allocateVkator, &buffer->handle); + s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &buffer->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, buffer); @@ -7427,7 +7620,7 @@ PalResult PAL_CALL createBufferVk( void PAL_CALL destroyBufferVk(PalBuffer* buffer) { Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.destroyBuffer(vkBuffer->device->handle, vkBuffer->handle, &s_Vk.allocateVkator); + s_Vk.destroyBuffer(vkBuffer->device->handle, vkBuffer->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, buffer); } @@ -7573,7 +7766,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( result = s_Vk.createDescriptorSetLayout( vkDevice->handle, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &layout->handle); if (result != VK_SUCCESS) { @@ -7594,7 +7787,7 @@ void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout) s_Vk.destroyDescriptorSetLayout( vkLayout->device->handle, vkLayout->handle, - &s_Vk.allocateVkator); + &s_Vk.vkAllocator); palFree(s_Vk.allocator, layout); } @@ -7634,7 +7827,7 @@ PalResult PAL_CALL createDescriptorPoolVk( result = s_Vk.createDescriptorPool( vkDevice->handle, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &pool->handle); if (result != VK_SUCCESS) { @@ -7652,7 +7845,7 @@ PalResult PAL_CALL createDescriptorPoolVk( void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool) { DescriptorPool* vkPool = (DescriptorPool*)pool; - s_Vk.destroyDescriptorPool(vkPool->device->handle, vkPool->handle, &s_Vk.allocateVkator); + s_Vk.destroyDescriptorPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, pool); } @@ -7881,7 +8074,7 @@ PalResult PAL_CALL createPipelineLayoutVk( result = s_Vk.createPipelineLayout( vkDevice->handle, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &layout->handle); if (result != VK_SUCCESS) { @@ -7905,7 +8098,7 @@ void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout) s_Vk.destroyPipelineLayout( pipelineLayout->device->handle, pipelineLayout->handle, - &s_Vk.allocateVkator); + &s_Vk.vkAllocator); palFree(s_Vk.allocator, layout); } @@ -8328,7 +8521,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( 0, 1, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &pipeline->handle); if (result != VK_SUCCESS) { @@ -8372,7 +8565,7 @@ PalResult PAL_CALL createComputePipelineVk( nullptr, 1, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &pipeline->handle); if (result != VK_SUCCESS) { @@ -8479,7 +8672,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( nullptr, 1, &createInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &pipeline->handle); if (result != VK_SUCCESS) { @@ -8531,7 +8724,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; result = - s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.allocateVkator, &sbt->buffer); + s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); @@ -8559,7 +8752,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( result = s_Vk.allocateMemory( vkDevice->handle, &allocateInfo, - &s_Vk.allocateVkator, + &s_Vk.vkAllocator, &sbt->bufferMemory); if (result != VK_SUCCESS) { @@ -8666,14 +8859,14 @@ PalResult PAL_CALL createRayTracingPipelineVk( void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) { Pipeline* vkPipeline = (Pipeline*)pipeline; - s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.allocateVkator); + s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); if (vkPipeline->sbt) { VkDevice device = vkPipeline->device->handle; ShaderBindingTable* sbt = vkPipeline->sbt; - s_Vk.destroyBuffer(device, sbt->buffer, &s_Vk.allocateVkator); - s_Vk.freeMemory(device, sbt->bufferMemory, &s_Vk.allocateVkator); + s_Vk.destroyBuffer(device, sbt->buffer, &s_Vk.vkAllocator); + s_Vk.freeMemory(device, sbt->bufferMemory, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkPipeline->sbt); } From 25844ec51e1c926236c80d18bf81b65d26c7b6a0 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 22 Mar 2026 09:18:21 -0700 Subject: [PATCH 114/372] fix memory allocation bug on windows --- src/graphics/pal_graphics.c | 10 ++++++++-- src/graphics/pal_vulkan.c | 38 ++++++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index f2167086..699d73ef 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -1038,7 +1038,12 @@ PalResult PAL_CALL palInitGraphics( } #ifdef _WIN32 - // vulkan and d3d12 + // vulkan + initGraphicsVk(debugger, allocator); + BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; + attached->base = &s_VkBackend; + attached->startIndex = 0; + attached->count = 0; #elif defined(__linux__) // vulkan #if PAL_HAS_VULKAN @@ -1064,7 +1069,8 @@ void PAL_CALL palShutdownGraphics() } #ifdef _WIN32 -// vulkan and d3d12 + // vulkan + shutdownGraphicsVk(); #elif defined(__linux__) // vulkan shutdownGraphicsVk(); diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 13ae4aae..ee51c08a 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -202,11 +202,14 @@ typedef struct HINSTANCE__ *HINSTANCE; typedef struct HWND__ *HWND; typedef struct HMONITOR__ *HMONITOR; +// only define the struct if not on windows +#ifndef _MINWINBASE_ typedef struct _SECURITY_ATTRIBUTES { DWORD nLength; LPVOID ipSecurityDescriptor; WINBOOL bInheritHandle; } SECURITY_ATTRIBUTES; +#endif // _MINWINBASE_ #include #include @@ -2116,6 +2119,27 @@ static VkShaderStageFlags shaderStageToVK(PalShaderStage stage) return 0; } +static inline void* alignedRealloc( + void* memory, + Uint64 size, + Uint64 alignment) +{ +#if defined(_MSC_VER) || defined(__MINGW32__) + _aligned_realloc(memory, size, alignment); +#else + realloc(memory, size); +#endif // _MSC_VER +} + +static inline void alignedFree(void* ptr) +{ +#if defined(_MSC_VER) || defined(__MINGW32__) + _aligned_free(ptr); +#else + free(ptr); +#endif // _MSC_VER +} + static void* VKAPI_CALL allocateVk( void* pUserData, size_t size, @@ -2142,16 +2166,16 @@ static void* VKAPI_CALL reallocVk( // Note: This is a hack which could cost performance but // realloc is not really called that much so it should be fine // this is because we dont know the old size - void* block = realloc(pOriginal, size); + void* block = alignedRealloc(pOriginal, size, alignment); if (block) { void* memory = palAllocate(s_Vk.allocator, size, alignment); if (!memory) { - free(block); + alignedFree(block); return nullptr; } memcpy(memory, block, size); - free(block); + alignedFree(block); return memory; } return nullptr; @@ -2836,6 +2860,14 @@ PalResult PAL_CALL initGraphicsVk( if (hasXlib) { extensions[extensionCount++] = "VK_KHR_xlib_surface"; } + + if (hasXcb) { + extensions[extensionCount++] = "VK_KHR_xcb_surface"; + } + + if (hasWin32) { + extensions[extensionCount++] = "VK_KHR_win32_surface"; + } } const char* layers[2]; From 6dde9e81b8de986f3b10f492a62f3c5214b45cfb Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 22 Mar 2026 12:45:58 -0700 Subject: [PATCH 115/372] compute test: vulkan on windows --- src/graphics/pal_graphics.c | 2 +- tests/compute_test.c | 6 +++++- tests/mesh_test.c | 6 +++++- tests/ray_tracing_test.c | 6 +++++- tests/tests_main.c | 4 ++-- tests/texture_test.c | 6 +++++- tests/triangle_test.c | 6 +++++- 7 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 699d73ef..2cb64dbf 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -764,7 +764,7 @@ static PalGraphicsBackend s_VkBackend = { .cmdBindIndexBuffer = cmdBindIndexBufferVk, .cmdDraw = cmdDrawVk, .cmdDrawIndirect = cmdDrawIndirectVk, - .cmdDrawIndexedIndirectCount = cmdDrawIndirectCountVk, + .cmdDrawIndirectCount = cmdDrawIndirectCountVk, .cmdDrawIndexed = cmdDrawIndexedVk, .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectVk, .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountVk, diff --git a/tests/compute_test.c b/tests/compute_test.c index e5b76675..30d27645 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -29,7 +29,11 @@ static bool readFile( fseek(file, 0, SEEK_SET); if (buffer) { - fread(buffer, 1, (size_t)size, file); + tmpSize = *size; + size_t read = fread(buffer, 1, tmpSize, file); + if (read != tmpSize) { + return false; + } } fclose(file); diff --git a/tests/mesh_test.c b/tests/mesh_test.c index de11581b..bee32cbb 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -24,7 +24,11 @@ static bool readFile( fseek(file, 0, SEEK_SET); if (buffer) { - fread(buffer, 1, (size_t)size, file); + tmpSize = *size; + size_t read = fread(buffer, 1, tmpSize, file); + if (read != tmpSize) { + return false; + } } fclose(file); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 19996931..39b8f081 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -21,7 +21,11 @@ static bool readFile( fseek(file, 0, SEEK_SET); if (buffer) { - fread(buffer, 1, (size_t)size, file); + tmpSize = *size; + size_t read = fread(buffer, 1, tmpSize, file); + if (read != tmpSize) { + return false; + } } fclose(file); diff --git a/tests/tests_main.c b/tests/tests_main.c index 11c555b0..880c48eb 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,8 +57,8 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest); - // registerTest(computeTest); + // registerTest(graphicsTest); + registerTest(computeTest); // registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS diff --git a/tests/texture_test.c b/tests/texture_test.c index 46f550c4..63ceffda 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -27,7 +27,11 @@ static bool readFile( fseek(file, 0, SEEK_SET); if (buffer) { - fread(buffer, 1, (size_t)size, file); + tmpSize = *size; + size_t read = fread(buffer, 1, tmpSize, file); + if (read != tmpSize) { + return false; + } } fclose(file); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 1236aa40..ffa49ea5 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -24,7 +24,11 @@ static bool readFile( fseek(file, 0, SEEK_SET); if (buffer) { - fread(buffer, 1, (size_t)size, file); + tmpSize = *size; + size_t read = fread(buffer, 1, tmpSize, file); + if (read != tmpSize) { + return false; + } } fclose(file); From 0713c7fcb71f56c63dace239aaa6e9aa362eb19b Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 22 Mar 2026 12:48:36 -0700 Subject: [PATCH 116/372] ray tracing test: vulkan on windows --- tests/tests_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests_main.c b/tests/tests_main.c index 880c48eb..0c98e1b3 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,8 +58,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest); - registerTest(computeTest); - // registerTest(rayTracingTest); + // registerTest(computeTest); + registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From 9a48bf8837085877a9f6b394fd754dcd1e4d976a Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 22 Mar 2026 12:52:43 -0700 Subject: [PATCH 117/372] clear color test: vulkan on windows --- src/graphics/pal_vulkan.c | 2 +- tests/tests_main.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index ee51c08a..e365a7ed 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -643,7 +643,7 @@ static bool createSurfaceVk( VkWin32SurfaceCreateInfoKHR cInfo = {0}; cInfo.hinstance = GetModuleHandle(nullptr); cInfo.hwnd = window->window; - cInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + cInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &surface); if (result != VK_SUCCESS) { diff --git a/tests/tests_main.c b/tests/tests_main.c index 0c98e1b3..21276f29 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,11 +59,11 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest); // registerTest(computeTest); - registerTest(rayTracingTest); + // registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest(clearColorTest); + registerTest(clearColorTest); // registerTest(triangleTest); // registerTest(meshTest); // registerTest(textureTest); From bc93efa70fb37da95b5b4a270e062c784a92334e Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 22 Mar 2026 17:32:59 -0700 Subject: [PATCH 118/372] add component mapping feature --- include/pal/pal_graphics.h | 38 +++++++++++++++++++++++++++++++++++++- src/graphics/pal_vulkan.c | 30 ++++++++++++++++++++++++++++++ tests/clear_color_test.c | 31 +++++++++++++++++++++++++++++-- tests/graphics_test.c | 4 ++++ 4 files changed, 100 insertions(+), 3 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d9359ab6..3c52c55d 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -520,6 +520,24 @@ typedef enum { PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE = PAL_BIT(3) } PalImageViewUsages; +/** + * @enum PalComponentSwizzle + * @brief Component swizzle channels. + * + * All component swizzle channels follow the format `PAL_COMPONENT_SWIZZLE**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_COMPONENT_SWIZZLE_IDENTITY, + PAL_COMPONENT_SWIZZLE_R, + PAL_COMPONENT_SWIZZLE_G, + PAL_COMPONENT_SWIZZLE_B, + PAL_COMPONENT_SWIZZLE_A +} PalComponentSwizzle; + /** * @enum PalShaderFormats * @brief Shader formats. This is a bitmask. @@ -581,7 +599,8 @@ typedef enum { PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(28), PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(29), PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(31) + PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(31), + PAL_ADAPTER_FEATURE_COMPONENT_MAPPING = PAL_BIT64(32) } PalAdapterFeatures; /** @@ -2227,6 +2246,22 @@ typedef struct { Uint32 layerArrayCount; } PalImageSubresourceRange; +/** + * @struct PalComponentMapping + * @brief Component mapping for images views. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + PalComponentSwizzle r; + PalComponentSwizzle g; + PalComponentSwizzle b; + PalComponentSwizzle a; +} PalComponentMapping; + /** * @struct PalBufferCopyInfo * @brief Information for buffer to buffer copies. @@ -2324,6 +2359,7 @@ typedef struct { typedef struct { PalImageViewType type; /**< (eg. PAL_IMAGE_VIEW_TYPE_2D).*/ PalImageViewUsages usages; /**< (eg. PAL_IMAGE_VIEW_USAGE_COLOR).*/ + PalComponentMapping mapping; /**< (eg. PAL_IMAGE_VIEW_USAGE_COLOR).*/ PalImageSubresourceRange subresourceRange; } PalImageViewCreateInfo; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e365a7ed..dd438bf6 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2390,6 +2390,28 @@ static void fillVkBuildInfoVk( buildInfo->scratchData = scratchData; } +static VkComponentSwizzle componentSwizzleToVk(PalComponentSwizzle swizzle) +{ + switch (swizzle) { + case PAL_COMPONENT_SWIZZLE_IDENTITY: + return VK_COMPONENT_SWIZZLE_IDENTITY; + + case PAL_COMPONENT_SWIZZLE_R: + return VK_COMPONENT_SWIZZLE_R; + + case PAL_COMPONENT_SWIZZLE_G: + return VK_COMPONENT_SWIZZLE_G; + + case PAL_COMPONENT_SWIZZLE_B: + return VK_COMPONENT_SWIZZLE_B; + + case PAL_COMPONENT_SWIZZLE_A: + return VK_COMPONENT_SWIZZLE_A; + } + + return VK_COMPONENT_SWIZZLE_IDENTITY; +} + // ================================================== // Adapter // ================================================== @@ -3651,6 +3673,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; + adapterFeatures |= PAL_ADAPTER_FEATURE_COMPONENT_MAPPING; palFree(s_Vk.allocator, extensionProps); return adapterFeatures; @@ -5162,6 +5185,13 @@ PalResult PAL_CALL createImageViewVk( createInfo.subresourceRange.layerCount = info->subresourceRange.layerArrayCount; createInfo.viewType = imageViewTypeToVk(info->type); + if (vkDevice->features & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { + createInfo.components.r = componentSwizzleToVk(info->mapping.r); + createInfo.components.g = componentSwizzleToVk(info->mapping.g); + createInfo.components.b = componentSwizzleToVk(info->mapping.b); + createInfo.components.a = componentSwizzleToVk(info->mapping.a); + } + VkImageAspectFlags aspectFlags = 0; if (info->usages & PAL_IMAGE_VIEW_USAGE_DEPTH) { aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index cea1130a..8a0ee376 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -185,10 +185,21 @@ bool clearColorTest() PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = true; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + + // TODO: windows natively supports BGRA so we need to swizzle the component + // so we dont change the shader + // we dont use shaders in this example but there is no harm in doing it anyway + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { + // the format is not supported. we default to BGRA + // if component mapping is not supported, we have to remap the component + // from the shader rather instead of mapping when creating the image views + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; + } // rare but possible on andriod if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { @@ -202,7 +213,13 @@ bool clearColorTest() // check if the minimal image count is not good for you // and increase it but not pass the max count swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; - swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + if (swapchainCreateInfo.imageCount == 1) { + swapchainCreateInfo.imageCount++; + if (swapchainCaps.maxImageCount < 2) { + palLog(nullptr, "Swapchain does not support double buffers"); + return false; + } + } result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { @@ -229,6 +246,16 @@ bool clearColorTest() imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; + // check multiple BGRA formats + if (swapchainCreateInfo.format == PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB) { + if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { + imageViewCreateInfo.mapping.r = PAL_COMPONENT_SWIZZLE_B; + imageViewCreateInfo.mapping.g = PAL_COMPONENT_SWIZZLE_G; + imageViewCreateInfo.mapping.b = PAL_COMPONENT_SWIZZLE_R; + imageViewCreateInfo.mapping.a = PAL_COMPONENT_SWIZZLE_A; + } + } + for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 2c56dd71..4b77e701 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -300,6 +300,10 @@ bool graphicsTest() palLog(nullptr, " Dispatch base"); } + if (features & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { + palLog(nullptr, " Component mapping"); + } + palLog(nullptr, ""); } From 79058914b5420f3265be228324c0cb4c30f0b1db Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 22 Mar 2026 17:48:12 -0700 Subject: [PATCH 119/372] fix swapchain min image being 1 --- tests/clear_color_test.c | 3 --- tests/mesh_test.c | 28 ++++++++++++++++++++++++++-- tests/tests_main.c | 4 ++-- tests/texture_test.c | 28 ++++++++++++++++++++++++++-- tests/triangle_test.c | 34 ++++++++++++++++++++++++++++++---- 5 files changed, 84 insertions(+), 13 deletions(-) diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 8a0ee376..15dff16d 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -190,9 +190,6 @@ bool clearColorTest() swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - // TODO: windows natively supports BGRA so we need to swizzle the component - // so we dont change the shader - // we dont use shaders in this example but there is no harm in doing it anyway swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { // the format is not supported. we default to BGRA diff --git a/tests/mesh_test.c b/tests/mesh_test.c index bee32cbb..cf6fd638 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -238,10 +238,18 @@ bool meshTest() PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = true; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { + // the format is not supported. we default to BGRA + // if component mapping is not supported, we have to remap the component + // from the shader rather instead of mapping when creating the image views + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; + } // rare but possible on andriod if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { @@ -255,7 +263,13 @@ bool meshTest() // check if the minimal image count is not good for you // and increase it but not pass the max count swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; - swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + if (swapchainCreateInfo.imageCount == 1) { + swapchainCreateInfo.imageCount = 2; + if (swapchainCaps.maxImageCount < 2) { + palLog(nullptr, "Swapchain does not support double buffers"); + return false; + } + } result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { @@ -282,6 +296,16 @@ bool meshTest() imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; + // check multiple BGRA formats + if (swapchainCreateInfo.format == PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB) { + if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { + imageViewCreateInfo.mapping.r = PAL_COMPONENT_SWIZZLE_B; + imageViewCreateInfo.mapping.g = PAL_COMPONENT_SWIZZLE_G; + imageViewCreateInfo.mapping.b = PAL_COMPONENT_SWIZZLE_R; + imageViewCreateInfo.mapping.a = PAL_COMPONENT_SWIZZLE_A; + } + } + for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL diff --git a/tests/tests_main.c b/tests/tests_main.c index 21276f29..365ed98c 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -63,8 +63,8 @@ int main(int argc, char** argv) #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest(clearColorTest); - // registerTest(triangleTest); + // registerTest(clearColorTest); + registerTest(triangleTest); // registerTest(meshTest); // registerTest(textureTest); #endif // diff --git a/tests/texture_test.c b/tests/texture_test.c index 63ceffda..b862a1ed 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -265,10 +265,18 @@ bool textureTest() PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = true; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { + // the format is not supported. we default to BGRA + // if component mapping is not supported, we have to remap the component + // from the shader rather instead of mapping when creating the image views + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; + } // rare but possible on andriod if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { @@ -282,7 +290,13 @@ bool textureTest() // check if the minimal image count is not good for you // and increase it but not pass the max count swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; - swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + if (swapchainCreateInfo.imageCount == 1) { + swapchainCreateInfo.imageCount = 2; + if (swapchainCaps.maxImageCount < 2) { + palLog(nullptr, "Swapchain does not support double buffers"); + return false; + } + } result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { @@ -309,6 +323,16 @@ bool textureTest() imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; + // check multiple BGRA formats + if (swapchainCreateInfo.format == PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB) { + if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { + imageViewCreateInfo.mapping.r = PAL_COMPONENT_SWIZZLE_B; + imageViewCreateInfo.mapping.g = PAL_COMPONENT_SWIZZLE_G; + imageViewCreateInfo.mapping.b = PAL_COMPONENT_SWIZZLE_R; + imageViewCreateInfo.mapping.a = PAL_COMPONENT_SWIZZLE_A; + } + } + for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL diff --git a/tests/triangle_test.c b/tests/triangle_test.c index ffa49ea5..9ae4c5a4 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -102,7 +102,7 @@ bool triangleTest() windowCreateInfo.height = WINDOW_HEIGHT; windowCreateInfo.width = WINDOW_WIDTH; windowCreateInfo.show = true; - windowCreateInfo.title = "Clear Color Window"; + windowCreateInfo.title = "Triangle Window"; PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { @@ -124,7 +124,7 @@ bool triangleTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -231,10 +231,18 @@ bool triangleTest() PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = true; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { + // the format is not supported. we default to BGRA + // if component mapping is not supported, we have to remap the component + // from the shader rather instead of mapping when creating the image views + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; + } // rare but possible on andriod if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { @@ -248,7 +256,13 @@ bool triangleTest() // check if the minimal image count is not good for you // and increase it but not pass the max count swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; - swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + if (swapchainCreateInfo.imageCount == 1) { + swapchainCreateInfo.imageCount = 2; + if (swapchainCaps.maxImageCount < 2) { + palLog(nullptr, "Swapchain does not support double buffers"); + return false; + } + } result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { @@ -275,6 +289,16 @@ bool triangleTest() imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; + // check multiple BGRA formats + if (swapchainCreateInfo.format == PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB) { + if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { + imageViewCreateInfo.mapping.r = PAL_COMPONENT_SWIZZLE_B; + imageViewCreateInfo.mapping.g = PAL_COMPONENT_SWIZZLE_G; + imageViewCreateInfo.mapping.b = PAL_COMPONENT_SWIZZLE_R; + imageViewCreateInfo.mapping.a = PAL_COMPONENT_SWIZZLE_A; + } + } + for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL @@ -751,6 +775,8 @@ bool triangleTest() return false; } + // TODO: remove + palLog(nullptr, "Image index %d", index); renderFinishedSemaphore = renderFinishedSemaphores[index]; // reset the command buffer From b742e6f5eca2491f7badf397b75876107716f92e Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 23 Mar 2026 08:35:45 +0000 Subject: [PATCH 120/372] bug: triangle not showing in x11 and windows (BGRA swapchain format) --- include/pal/pal_config.h | 2 +- pal_config.lua | 2 +- src/graphics/pal_vulkan.c | 4 ++-- tests/clear_color_test.c | 23 +++++++++++++++++++++++ tests/mesh_test.c | 23 +++++++++++++++++++++++ tests/texture_test.c | 23 +++++++++++++++++++++++ tests/triangle_test.c | 23 +++++++++++++++++++++++ 7 files changed, 96 insertions(+), 4 deletions(-) diff --git a/include/pal/pal_config.h b/include/pal/pal_config.h index 1bb59aa7..b066298b 100644 --- a/include/pal/pal_config.h +++ b/include/pal/pal_config.h @@ -2,7 +2,7 @@ // Auto Generated Config Header From pal_config.lua // Must not be edited manually -#define PAL_HAS_SYSTEM 0 +#define PAL_HAS_SYSTEM 1 #define PAL_HAS_THREAD 0 #define PAL_HAS_VIDEO 1 #define PAL_HAS_OPENGL 0 diff --git a/pal_config.lua b/pal_config.lua index 1e2b2700..36970328 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -6,7 +6,7 @@ PAL_BUILD_STATIC = false PAL_BUILD_TESTS = true -- build system module -PAL_BUILD_SYSTEM = false +PAL_BUILD_SYSTEM = true -- build thread module PAL_BUILD_THREAD = false diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index dd438bf6..2484b8b0 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2125,9 +2125,9 @@ static inline void* alignedRealloc( Uint64 alignment) { #if defined(_MSC_VER) || defined(__MINGW32__) - _aligned_realloc(memory, size, alignment); + return _aligned_realloc(memory, size, alignment); #else - realloc(memory, size); + return realloc(memory, size); #endif // _MSC_VER } diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 15dff16d..26b9deb2 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -1,6 +1,7 @@ #include "pal/pal_graphics.h" #include "pal/pal_video.h" +#include "pal/pal_system.h" #include "tests.h" #define WINDOW_WIDTH 640 @@ -81,6 +82,28 @@ bool clearColorTest() gfxWindow.display = winHandle.nativeDisplay; gfxWindow.window = winHandle.nativeWindow; + // using pal_system.h will be easy to know the underlying windowing API + // or use typedefs. We will use the pal_system module. This is needed + // for systems which multiple windowing APIs (linux). + PalPlatformInfo platformInfo = {0}; + result = palGetPlatformInfo(&platformInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get platform information: %s", error); + return false; + } + + if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + + } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + + } else { + // automatically this is xcb + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } + PalGraphicsDebugger debugger; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; diff --git a/tests/mesh_test.c b/tests/mesh_test.c index cf6fd638..2b98307e 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -1,6 +1,7 @@ #include "pal/pal_graphics.h" #include "pal/pal_video.h" +#include "pal/pal_system.h" #include "tests.h" #include @@ -115,6 +116,28 @@ bool meshTest() gfxWindow.display = winHandle.nativeDisplay; gfxWindow.window = winHandle.nativeWindow; + // using pal_system.h will be easy to know the underlying windowing API + // or use typedefs. We will use the pal_system module. This is needed + // for systems which multiple windowing APIs (linux). + PalPlatformInfo platformInfo = {0}; + result = palGetPlatformInfo(&platformInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get platform information: %s", error); + return false; + } + + if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + + } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + + } else { + // automatically this is xcb + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } + PalGraphicsDebugger debugger; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; diff --git a/tests/texture_test.c b/tests/texture_test.c index b862a1ed..b25be7f4 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -1,6 +1,7 @@ #include "pal/pal_graphics.h" #include "pal/pal_video.h" +#include "pal/pal_system.h" #include "tests.h" #include @@ -154,6 +155,28 @@ bool textureTest() gfxWindow.display = winHandle.nativeDisplay; gfxWindow.window = winHandle.nativeWindow; + // using pal_system.h will be easy to know the underlying windowing API + // or use typedefs. We will use the pal_system module. This is needed + // for systems which multiple windowing APIs (linux). + PalPlatformInfo platformInfo = {0}; + result = palGetPlatformInfo(&platformInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get platform information: %s", error); + return false; + } + + if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + + } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + + } else { + // automatically this is xcb + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } + PalGraphicsDebugger debugger; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 9ae4c5a4..f385a818 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -1,6 +1,7 @@ #include "pal/pal_graphics.h" #include "pal/pal_video.h" +#include "pal/pal_system.h" #include "tests.h" #include @@ -119,6 +120,28 @@ bool triangleTest() PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); gfxWindow.display = winHandle.nativeDisplay; gfxWindow.window = winHandle.nativeWindow; + + // using pal_system.h will be easy to know the underlying windowing API + // or use typedefs. We will use the pal_system module. This is needed + // for systems which multiple windowing APIs (linux). + PalPlatformInfo platformInfo = {0}; + result = palGetPlatformInfo(&platformInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get platform information: %s", error); + return false; + } + + if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + + } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + + } else { + // automatically this is xcb + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } PalGraphicsDebugger debugger; debugger.callback = onGraphicsDebug; From 0b4ca6f316387bea2b896541500394dff564c0b9 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 24 Mar 2026 20:47:41 +0000 Subject: [PATCH 121/372] fix main loop: triangle test --- include/pal/pal_graphics.h | 38 +------- src/graphics/pal_vulkan.c | 61 +++++-------- tests/clear_color_test.c | 10 -- tests/graphics_test.c | 4 - tests/mesh_test.c | 10 -- tests/tests_main.c | 20 ++-- tests/texture_test.c | 10 -- tests/triangle_test.c | 181 +++++++++++++++++-------------------- 8 files changed, 116 insertions(+), 218 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 3c52c55d..d9359ab6 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -520,24 +520,6 @@ typedef enum { PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE = PAL_BIT(3) } PalImageViewUsages; -/** - * @enum PalComponentSwizzle - * @brief Component swizzle channels. - * - * All component swizzle channels follow the format `PAL_COMPONENT_SWIZZLE**` for - * consistency and API use. - * - * @since 1.4 - * @ingroup pal_graphics - */ -typedef enum { - PAL_COMPONENT_SWIZZLE_IDENTITY, - PAL_COMPONENT_SWIZZLE_R, - PAL_COMPONENT_SWIZZLE_G, - PAL_COMPONENT_SWIZZLE_B, - PAL_COMPONENT_SWIZZLE_A -} PalComponentSwizzle; - /** * @enum PalShaderFormats * @brief Shader formats. This is a bitmask. @@ -599,8 +581,7 @@ typedef enum { PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(28), PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(29), PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(31), - PAL_ADAPTER_FEATURE_COMPONENT_MAPPING = PAL_BIT64(32) + PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(31) } PalAdapterFeatures; /** @@ -2246,22 +2227,6 @@ typedef struct { Uint32 layerArrayCount; } PalImageSubresourceRange; -/** - * @struct PalComponentMapping - * @brief Component mapping for images views. - * - * Uninitialized fields may result in undefined behavior. - * - * @since 1.4 - * @ingroup pal_graphics - */ -typedef struct { - PalComponentSwizzle r; - PalComponentSwizzle g; - PalComponentSwizzle b; - PalComponentSwizzle a; -} PalComponentMapping; - /** * @struct PalBufferCopyInfo * @brief Information for buffer to buffer copies. @@ -2359,7 +2324,6 @@ typedef struct { typedef struct { PalImageViewType type; /**< (eg. PAL_IMAGE_VIEW_TYPE_2D).*/ PalImageViewUsages usages; /**< (eg. PAL_IMAGE_VIEW_USAGE_COLOR).*/ - PalComponentMapping mapping; /**< (eg. PAL_IMAGE_VIEW_USAGE_COLOR).*/ PalImageSubresourceRange subresourceRange; } PalImageViewCreateInfo; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 2484b8b0..91e324ca 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2390,28 +2390,6 @@ static void fillVkBuildInfoVk( buildInfo->scratchData = scratchData; } -static VkComponentSwizzle componentSwizzleToVk(PalComponentSwizzle swizzle) -{ - switch (swizzle) { - case PAL_COMPONENT_SWIZZLE_IDENTITY: - return VK_COMPONENT_SWIZZLE_IDENTITY; - - case PAL_COMPONENT_SWIZZLE_R: - return VK_COMPONENT_SWIZZLE_R; - - case PAL_COMPONENT_SWIZZLE_G: - return VK_COMPONENT_SWIZZLE_G; - - case PAL_COMPONENT_SWIZZLE_B: - return VK_COMPONENT_SWIZZLE_B; - - case PAL_COMPONENT_SWIZZLE_A: - return VK_COMPONENT_SWIZZLE_A; - } - - return VK_COMPONENT_SWIZZLE_IDENTITY; -} - // ================================================== // Adapter // ================================================== @@ -3673,7 +3651,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; - adapterFeatures |= PAL_ADAPTER_FEATURE_COMPONENT_MAPPING; palFree(s_Vk.allocator, extensionProps); return adapterFeatures; @@ -5185,13 +5162,6 @@ PalResult PAL_CALL createImageViewVk( createInfo.subresourceRange.layerCount = info->subresourceRange.layerArrayCount; createInfo.viewType = imageViewTypeToVk(info->type); - if (vkDevice->features & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { - createInfo.components.r = componentSwizzleToVk(info->mapping.r); - createInfo.components.g = componentSwizzleToVk(info->mapping.g); - createInfo.components.b = componentSwizzleToVk(info->mapping.b); - createInfo.components.a = componentSwizzleToVk(info->mapping.a); - } - VkImageAspectFlags aspectFlags = 0; if (info->usages & PAL_IMAGE_VIEW_USAGE_DEPTH) { aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; @@ -5583,6 +5553,7 @@ PalResult PAL_CALL createSwapchainVk( return PAL_RESULT_OUT_OF_MEMORY; } + memset(swapchain, 0, sizeof(Swapchain)); if (!createSurfaceVk(window, &swapchain->surface)) { return PAL_RESULT_INVALID_GRAPHICS_WINDOW; } @@ -5594,7 +5565,7 @@ PalResult PAL_CALL createSwapchainVk( createInfo.imageExtent.width = info->width; createInfo.imageExtent.height = info->height; createInfo.minImageCount = info->imageCount; - createInfo.clipped = (VkBool32)info->clipped; + createInfo.clipped = VK_FALSE; createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; @@ -5912,13 +5883,17 @@ PalResult PAL_CALL waitFenceVk( Uint64 timeout) { Fence* vkFence = (Fence*)fence; - if (timeout != UINT64_MAX) { - if (!(vkFence->device->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + VkResult result; + Uint64 timeInNanoseconds = 0; + + if (timeout) { + if (timeout == PAL_INFINITE) { + timeInNanoseconds = UINT64_MAX; } + timeInNanoseconds = timeout * 1000000; } - VkResult result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, true, timeout); + result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, true, timeout); if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -6015,18 +5990,30 @@ PalResult PAL_CALL waitSemaphoreVk( Uint64 timeout) { VkResult result; + Uint64 timeInNanoseconds = 0; Semaphore* vkSemaphore = (Semaphore*)semaphore; if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (timeout) { + if (timeout == PAL_INFINITE) { + timeInNanoseconds = UINT64_MAX; + } + timeInNanoseconds = timeout * 1000000; + } + VkSemaphoreWaitInfo waitInfo = {0}; waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; waitInfo.semaphoreCount = 1; waitInfo.pSemaphores = &vkSemaphore->handle; waitInfo.pValues = &value; - result = vkSemaphore->device->waitSemaphore(vkSemaphore->device->handle, &waitInfo, timeout); + result = vkSemaphore->device->waitSemaphore( + vkSemaphore->device->handle, + &waitInfo, + timeInNanoseconds); + if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -6191,6 +6178,7 @@ PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer) CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); vkCmdBuffer->sbt = nullptr; + vkCmdBuffer->dstStage = 0; return PAL_RESULT_SUCCESS; } @@ -6684,7 +6672,6 @@ PalResult PAL_CALL cmdBeginRenderingVk( info->fragmentShadingRateAttachment->texelHeight; fsrInfo.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; - rendering.pNext = &fsrInfo; } diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 26b9deb2..91a8de62 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -266,16 +266,6 @@ bool clearColorTest() imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; - // check multiple BGRA formats - if (swapchainCreateInfo.format == PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB) { - if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { - imageViewCreateInfo.mapping.r = PAL_COMPONENT_SWIZZLE_B; - imageViewCreateInfo.mapping.g = PAL_COMPONENT_SWIZZLE_G; - imageViewCreateInfo.mapping.b = PAL_COMPONENT_SWIZZLE_R; - imageViewCreateInfo.mapping.a = PAL_COMPONENT_SWIZZLE_A; - } - } - for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 4b77e701..2c56dd71 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -300,10 +300,6 @@ bool graphicsTest() palLog(nullptr, " Dispatch base"); } - if (features & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { - palLog(nullptr, " Component mapping"); - } - palLog(nullptr, ""); } diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 2b98307e..b86d781f 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -319,16 +319,6 @@ bool meshTest() imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; - // check multiple BGRA formats - if (swapchainCreateInfo.format == PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB) { - if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { - imageViewCreateInfo.mapping.r = PAL_COMPONENT_SWIZZLE_B; - imageViewCreateInfo.mapping.g = PAL_COMPONENT_SWIZZLE_G; - imageViewCreateInfo.mapping.b = PAL_COMPONENT_SWIZZLE_R; - imageViewCreateInfo.mapping.a = PAL_COMPONENT_SWIZZLE_A; - } - } - for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL diff --git a/tests/tests_main.c b/tests/tests_main.c index 365ed98c..6520e5f5 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -17,14 +17,14 @@ int main(int argc, char** argv) // registerTest(eventTest); #if PAL_HAS_SYSTEM - registerTest(systemTest); + // registerTest(systemTest); #endif // PAL_HAS_SYSTEM #if PAL_HAS_THREAD - registerTest(threadTest); - registerTest(tlsTest); - registerTest(mutexTest); - registerTest(condvarTest); + // registerTest(threadTest); + // registerTest(tlsTest); + // registerTest(mutexTest); + // registerTest(condvarTest); #endif // PAL_HAS_THREAD #if PAL_HAS_VIDEO @@ -46,14 +46,14 @@ int main(int argc, char** argv) // This test can run without video system so long as your have a valid // window #if PAL_HAS_OPENGL && PAL_HAS_VIDEO - registerTest(openglTest); - registerTest(openglFBConfigTest); - registerTest(openglContextTest); - registerTest(openglMultiContextTest); + // registerTest(openglTest); + // registerTest(openglFBConfigTest); + // registerTest(openglContextTest); + // registerTest(openglMultiContextTest); #endif // PAL_HAS_OPENGL #if PAL_HAS_OPENGL && PAL_HAS_VIDEO && PAL_HAS_THREAD - registerTest(multiThreadOpenGlTest); + // registerTest(multiThreadOpenGlTest); #endif #if PAL_HAS_GRAPHICS diff --git a/tests/texture_test.c b/tests/texture_test.c index b25be7f4..8604d65f 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -346,16 +346,6 @@ bool textureTest() imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; - // check multiple BGRA formats - if (swapchainCreateInfo.format == PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB) { - if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { - imageViewCreateInfo.mapping.r = PAL_COMPONENT_SWIZZLE_B; - imageViewCreateInfo.mapping.g = PAL_COMPONENT_SWIZZLE_G; - imageViewCreateInfo.mapping.b = PAL_COMPONENT_SWIZZLE_R; - imageViewCreateInfo.mapping.a = PAL_COMPONENT_SWIZZLE_A; - } - } - for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL diff --git a/tests/triangle_test.c b/tests/triangle_test.c index f385a818..82ab42d6 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -67,9 +67,10 @@ bool triangleTest() PalImageView** imageViews = nullptr; PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* presentCompleteSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore** renderFinishedSemaphores; // count of swapchain images + PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -147,7 +148,7 @@ bool triangleTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(&debugger, nullptr); + result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -259,13 +260,12 @@ bool triangleTest() swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { - // the format is not supported. we default to BGRA - // if component mapping is not supported, we have to remap the component - // from the shader rather instead of mapping when creating the image views - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; - } + // swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; + // if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { + // // the format is not supported. We default to BGRA + // swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; + // } // rare but possible on andriod if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { @@ -280,9 +280,9 @@ bool triangleTest() // and increase it but not pass the max count swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; if (swapchainCreateInfo.imageCount == 1) { - swapchainCreateInfo.imageCount = 2; - if (swapchainCaps.maxImageCount < 2) { - palLog(nullptr, "Swapchain does not support double buffers"); + swapchainCreateInfo.imageCount = 3; + if (swapchainCaps.maxImageCount < 3) { + palLog(nullptr, "Swapchain does not support the required buffers"); return false; } } @@ -297,9 +297,9 @@ bool triangleTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); + inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); - if (!imageViews || !renderFinishedSemaphores) { + if (!imageViews || !inFlightImages) { palLog(nullptr, "Failed to allocate memory"); return false; } @@ -312,16 +312,6 @@ bool triangleTest() imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; - // check multiple BGRA formats - if (swapchainCreateInfo.format == PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB) { - if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPONENT_MAPPING) { - imageViewCreateInfo.mapping.r = PAL_COMPONENT_SWIZZLE_B; - imageViewCreateInfo.mapping.g = PAL_COMPONENT_SWIZZLE_G; - imageViewCreateInfo.mapping.b = PAL_COMPONENT_SWIZZLE_R; - imageViewCreateInfo.mapping.a = PAL_COMPONENT_SWIZZLE_A; - } - } - for (int i = 0; i < imageCount; i++) { // get swapchain image // this is fast since the images are cache by PAL @@ -336,6 +326,8 @@ bool triangleTest() palLog(nullptr, "Failed to create image view: %s", error); return false; } + + inFlightImages[i] = nullptr; } result = palCreateCommandPool(device, queue, &cmdPool); @@ -347,7 +339,14 @@ bool triangleTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); + result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -374,16 +373,6 @@ bool triangleTest() } } - // create synchronization objects - for (int i = 0; i < imageCount; i++) { - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - } - // create vertex and staging buffer // clang-format off float vertices[] = { @@ -485,8 +474,8 @@ bool triangleTest() memcpy(ptr, vertices, sizeof(vertices)); palUnmapMemory(device, stagingBufferMemory); - PalFence* fence = nullptr; - result = palCreateFence(device, false, &fence); + PalFence* tmpFence = nullptr; + result = palCreateFence(device, false, &tmpFence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); @@ -538,7 +527,7 @@ bool triangleTest() PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffers[0]; - submitInfo.fence = fence; + submitInfo.fence = tmpFence; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -697,7 +686,7 @@ bool triangleTest() palDestroyShader(fragmentShader); // wait for the vertices copy to be done - result = palWaitFence(fence, UINT64_MAX); + result = palWaitFence(tmpFence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); @@ -705,20 +694,13 @@ bool triangleTest() } // the vertices have been copied - palDestroyFence(fence); + palDestroyFence(tmpFence); palDestroyBuffer(stagingBuffer); palFreeMemory(device, stagingBufferMemory); // main loop Uint32 currentFrame = 0; bool running = true; - PalSemaphore* presentCompleteSemaphore = nullptr; - PalSemaphore* renderFinishedSemaphore = nullptr; - fence = nullptr; - PalCommandBuffer* cmdBuffer = nullptr; - - bool firstImageViewUse[8]; - memset(firstImageViewUse, 1, sizeof(bool) * 8); // we are not resizing for the viewport and scissor will not change PalViewport viewport = {0}; @@ -753,19 +735,39 @@ bool triangleTest() } } - fence = inFlightFences[currentFrame]; - presentCompleteSemaphore = presentCompleteSemaphores[currentFrame]; - cmdBuffer = cmdBuffers[currentFrame]; - - result = palWaitFence(fence, UINT64_MAX); + result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); return false; } + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; + nextImageInfo.timeout = PAL_INFINITE; + + Uint32 imageIndex = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + if (inFlightImages[imageIndex] != nullptr) { + result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + inFlightImages[imageIndex] = inFlightFences[currentFrame]; if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { - result = palResetFence(fence); + result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); @@ -774,9 +776,9 @@ bool triangleTest() } else { // recreate since we dont support fence resetting - palDestroyFence(fence); + palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, false, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); @@ -784,33 +786,18 @@ bool triangleTest() } } - // get next swapchain image - PalSwapchainNextImageInfo nextImageInfo = {0}; - nextImageInfo.fence = nullptr; - nextImageInfo.signalSemaphore = presentCompleteSemaphore; - nextImageInfo.timeout = UINT64_MAX; - - Uint32 index = 0; - result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &index); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; - } - // TODO: remove - palLog(nullptr, "Image index %d", index); - renderFinishedSemaphore = renderFinishedSemaphores[index]; + palLog(nullptr, "Image index %d", imageIndex); // reset the command buffer - result = palResetCommandBuffer(cmdBuffer); + result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); return false; } - result = palCmdBegin(cmdBuffer, nullptr); + result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); @@ -822,21 +809,15 @@ bool triangleTest() PalUsageStateInfo newUsageStateInfo = {0}; newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; - if (firstImageViewUse[index]) { - oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - } else { - oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - } - PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; imageRange.mipLevelCount = 1; imageRange.startArrayLayer = 0; imageRange.startMipLevel = 0; - PalImage* image = palGetSwapchainImage(swapchain, index); + PalImage* image = palGetSwapchainImage(swapchain, imageIndex); result = palCmdImageBarrier( - cmdBuffer, + cmdBuffers[currentFrame], image, &imageRange, &oldUsageStateInfo, @@ -858,7 +839,7 @@ bool triangleTest() colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; colorAttachment.storeOp = PAL_STORE_OP_STORE; colorAttachment.clearValue = clearValue; - colorAttachment.imageView = imageViews[index]; + colorAttachment.imageView = imageViews[imageIndex]; PalRenderingInfo renderingInfo = {0}; renderingInfo.viewCount = 1; @@ -869,7 +850,7 @@ bool triangleTest() renderingInfo.renderArea.width = WINDOW_WIDTH; renderingInfo.renderArea.height = WINDOW_HEIGHT; - result = palCmdBeginRendering(cmdBuffer, &renderingInfo); + result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); @@ -877,7 +858,7 @@ bool triangleTest() } // bind pipeline - result = palCmdBindPipeline(cmdBuffer, pipeline); + result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); @@ -885,14 +866,14 @@ bool triangleTest() } // set viewport and scissors - result = palCmdSetViewport(cmdBuffer, 1, &viewport); + result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); return false; } - result = palCmdSetScissors(cmdBuffer, 1, &scissor); + result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); @@ -901,21 +882,21 @@ bool triangleTest() // bind vertex buffer Uint64 offset[] = {0}; - result = palCmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, offset); + result = palCmdBindVertexBuffers(cmdBuffers[currentFrame], 0, 1, &vertexBuffer, offset); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind vertex buffer: %s", error); return false; } - result = palCmdDraw(cmdBuffer, 3, 1, 0, 0); + result = palCmdDraw(cmdBuffers[currentFrame], 3, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); return false; } - result = palCmdEndRendering(cmdBuffer); + result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); @@ -926,7 +907,7 @@ bool triangleTest() oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( - cmdBuffer, + cmdBuffers[currentFrame], image, &imageRange, &oldUsageStateInfo, @@ -938,7 +919,7 @@ bool triangleTest() return false; } - result = palCmdEnd(cmdBuffer); + result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); @@ -947,10 +928,10 @@ bool triangleTest() // submit command buffer PalCommandBufferSubmitInfo submitInfo = {0}; - submitInfo.cmdBuffer = cmdBuffer; - submitInfo.fence = fence; - submitInfo.waitSemaphore = presentCompleteSemaphore; - submitInfo.signalSemaphore = renderFinishedSemaphore; + submitInfo.cmdBuffer = cmdBuffers[currentFrame]; + submitInfo.fence = inFlightFences[currentFrame]; + submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -961,8 +942,8 @@ bool triangleTest() // present PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = index; - presentInfo.waitSemaphore = renderFinishedSemaphore; + presentInfo.imageIndex = imageIndex; + presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -984,14 +965,14 @@ bool triangleTest() palDestroyPipelineLayout(pipelineLayout); for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - palDestroySemaphore(presentCompleteSemaphores[i]); + palDestroySemaphore(imageAvailableSemaphores[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); palDestroyFence(inFlightFences[i]); palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { palDestroyImageView(imageViews[i]); - palDestroySemaphore(renderFinishedSemaphores[i]); } palDestroyBuffer(vertexBuffer); From 15e76506fc6493ea93e8d6a43ea0bec191ce2e5b Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 27 Mar 2026 16:26:56 +0000 Subject: [PATCH 122/372] fix bug: triangle test on windows vulkan --- include/pal/pal_graphics.h | 4 +- src/graphics/pal_graphics.c | 14 +- src/graphics/pal_vulkan.c | 480 ++++++++++++++++++------------------ src/pal_core.c | 2 +- tests/clear_color_test.c | 186 ++++++-------- tests/triangle_test.c | 9 - 6 files changed, 331 insertions(+), 364 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d9359ab6..8a73a059 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2481,10 +2481,10 @@ typedef struct { PalPipelineLayout* pipelineLayout; PalShader** shaders; PalVertexLayout* vertexLayouts; - PalColorBlendAttachment* colorBlendAttachments; /**< Must not be nullptr.*/ + PalColorBlendAttachment* colorBlendAttachments; /**< Depth only: Can be nullptr.*/ PalRasterizerState* rasterizerState; /**< Set to nullptr for default.*/ PalMultisampleState* multisampleState; /**< Set to nullptr for default.*/ - PalDepthStencilState* depthStencilState; /**< Set to nullptr for default.*/ + PalDepthStencilState* depthStencilState; /**< Color only: Can be nullptr.*/ PalFragmentShadingRateState* fragmentShadingRateState; /**< Set to nullptr for default.*/ PalRenderingLayoutInfo* renderingLayout; } PalGraphicsPipelineCreateInfo; diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 2cb64dbf..f071591b 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -101,7 +101,7 @@ PalResult PAL_CALL initGraphicsVk( const PalGraphicsDebugger* debugger, const PalAllocator* allocator); -PalResult PAL_CALL shutdownGraphicsVk(); +void PAL_CALL shutdownGraphicsVk(); PalResult PAL_CALL enumerateAdaptersVk( Int32* count, @@ -1039,7 +1039,11 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan - initGraphicsVk(debugger, allocator); + PalResult result = initGraphicsVk(debugger, allocator); + if (result != PAL_RESULT_SUCCESS) { + return PAL_RESULT_PLATFORM_FAILURE; + } + BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; attached->base = &s_VkBackend; attached->startIndex = 0; @@ -1047,7 +1051,11 @@ PalResult PAL_CALL palInitGraphics( #elif defined(__linux__) // vulkan #if PAL_HAS_VULKAN - initGraphicsVk(debugger, allocator); + PalResult result = initGraphicsVk(debugger, allocator); + if (result != PAL_RESULT_SUCCESS) { + return PAL_RESULT_PLATFORM_FAILURE; + } + BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; attached->base = &s_VkBackend; attached->startIndex = 0; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 91e324ca..c346c4a4 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2925,6 +2925,8 @@ PalResult PAL_CALL initGraphicsVk( // load surface creation function pointers s_Vk.createWaylandSurface = nullptr; s_Vk.createXlibSurface = nullptr; + s_Vk.createXcbSurface = nullptr; + s_Vk.createWin32Surface = nullptr; if (hasWayland) { s_Vk.createWaylandSurface = (PFN_vkCreateWaylandSurfaceKHR)s_Vk.getInstanceProcAddr( @@ -3031,7 +3033,7 @@ PalResult PAL_CALL initGraphicsVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL shutdownGraphicsVk() +void PAL_CALL shutdownGraphicsVk() { if (s_Vk.messenger) { s_Vk.destroyMessenger(s_Vk.instance, s_Vk.messenger, &s_Vk.vkAllocator); @@ -5655,6 +5657,8 @@ PalResult PAL_CALL createSwapchainVk( image->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } + palFree(s_Vk.allocator, images); + swapchain->device = vkDevice; swapchain->queue = vkQueue; swapchain->imageCount = count; @@ -5713,8 +5717,9 @@ PalResult PAL_CALL getNextSwapchainImageVk( if (info->timeout) { if (info->timeout == PAL_INFINITE) { timeInNanoseconds = UINT64_MAX; + } else { + timeInNanoseconds = info->timeout * 1000000; } - timeInNanoseconds = info->timeout * 1000000; } result = vkSwapchain->device->acquireNextImage( @@ -5784,7 +5789,7 @@ PalResult PAL_CALL createShaderVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // clang-format off + // clang-format off } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || info->stage == PAL_SHADER_STAGE_ANY_HIT || @@ -5808,9 +5813,7 @@ PalResult PAL_CALL createShaderVk( createInfo.codeSize = info->bytecodeSize; createInfo.pCode = (const Uint32*)info->bytecode; - result = - s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); - + result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, shader); return resultFromVk(result); @@ -5889,8 +5892,9 @@ PalResult PAL_CALL waitFenceVk( if (timeout) { if (timeout == PAL_INFINITE) { timeInNanoseconds = UINT64_MAX; + } else { + timeInNanoseconds = timeout * 1000000; } - timeInNanoseconds = timeout * 1000000; } result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, true, timeout); @@ -5920,7 +5924,6 @@ bool PAL_CALL isFenceSignaledVk(PalFence* fence) { Fence* vkFence = (Fence*)fence; VkResult result = s_Vk.isFenceSignaled(vkFence->device->handle, vkFence->handle); - if (result == VK_SUCCESS) { return true; } else { @@ -5999,8 +6002,9 @@ PalResult PAL_CALL waitSemaphoreVk( if (timeout) { if (timeout == PAL_INFINITE) { timeInNanoseconds = UINT64_MAX; + } else { + timeInNanoseconds = timeout * 1000000; } - timeInNanoseconds = timeout * 1000000; } VkSemaphoreWaitInfo waitInfo = {0}; @@ -6086,14 +6090,12 @@ PalResult PAL_CALL createCommandPoolVk( return PAL_RESULT_OUT_OF_MEMORY; } - VkCommandPoolCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - createInfo.queueFamilyIndex = phyQueue->familyIndex; - createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - - result = - s_Vk.createCommandPool(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &pool->handle); + VkCommandPoolCreateInfo cInfo = {0}; + cInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cInfo.queueFamilyIndex = phyQueue->familyIndex; + cInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + result = s_Vk.createCommandPool(vkDevice->handle, &cInfo, &s_Vk.vkAllocator, &pool->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pool); return resultFromVk(result); @@ -6195,6 +6197,7 @@ PalResult PAL_CALL submitCommandBufferVk( VkPipelineStageFlagBits2 dstStage = 0; Queue* vkQueue = (Queue*)queue; CommandBuffer* vkCmdBuffer = (CommandBuffer*)info->cmdBuffer; + PhysicalQueue* phyQueue = vkQueue->phyQueue; if (vkCmdBuffer->sbt) { vkCmdBuffer->dstStage |= VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; @@ -6246,9 +6249,7 @@ PalResult PAL_CALL submitCommandBufferVk( submitInfo.waitSemaphoreInfoCount = waitSemaphoreCount; submitInfo.signalSemaphoreInfoCount = signalSemaphoreCount; - result = - vkCmdBuffer->device->queueSubmit(vkQueue->phyQueue->handle, 1, &submitInfo, fenceHandle); - + result = vkCmdBuffer->device->queueSubmit(phyQueue->handle, 1, &submitInfo, fenceHandle); if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -6329,8 +6330,8 @@ PalResult PAL_CALL cmdExecuteCommandBufferVk( { CommandBuffer* vkCmdBuffer = (CommandBuffer*)primaryCmdBuffer; CommandBuffer* vkCmdBuffer2 = (CommandBuffer*)secondaryCmdBuffer; - s_Vk.cmdExecuteCommandBuffer(vkCmdBuffer->handle, 1, &vkCmdBuffer2->handle); + s_Vk.cmdExecuteCommandBuffer(vkCmdBuffer->handle, 1, &vkCmdBuffer2->handle); return PAL_RESULT_SUCCESS; } @@ -6339,7 +6340,9 @@ PalResult PAL_CALL cmdSetFragmentShadingRateVk( PalFragmentShadingRateState* state) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6374,8 +6377,8 @@ PalResult PAL_CALL cmdSetFragmentShadingRateVk( } } } - vkCmdBuffer->device->cmdSetFragmentShadingRate(vkCmdBuffer->handle, &size, combinerOps); + device->cmdSetFragmentShadingRate(vkCmdBuffer->handle, &size, combinerOps); return PAL_RESULT_SUCCESS; } @@ -6386,13 +6389,13 @@ PalResult PAL_CALL cmdDrawMeshTasksVk( Uint32 groupCountZ) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - vkCmdBuffer->device - ->cmdDrawMeshTask(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); - + device->cmdDrawMeshTask(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); return PAL_RESULT_SUCCESS; } @@ -6404,17 +6407,23 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( Uint32 stride) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + Device* device = vkCmdBuffer->device; + Buffer* vkBuffer = (Buffer*)buffer; + + if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Buffer* vkBuffer = (Buffer*)buffer; - vkCmdBuffer->device - ->cmdDrawMeshTaskIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset, drawCount, stride); + device->cmdDrawMeshTaskIndirect( + vkCmdBuffer->handle, + vkBuffer->handle, + offset, + drawCount, + stride); return PAL_RESULT_SUCCESS; } @@ -6429,18 +6438,19 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( Uint32 stride) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + Device* device = vkCmdBuffer->device; + Buffer* vkBuffer = (Buffer*)buffer; + Buffer* vkCountBuffer = (Buffer*)countBuffer; + + if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Buffer* vkBuffer = (Buffer*)buffer; - Buffer* vkCountBuffer = (Buffer*)countBuffer; - - vkCmdBuffer->device->cmdDrawMeshTaskIndirectCount( + device->cmdDrawMeshTaskIndirectCount( vkCmdBuffer->handle, vkBuffer->handle, offset, @@ -6457,17 +6467,18 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( PalAccelerationStructureBuildInfo* info) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - + Device* device = vkCmdBuffer->device; VkAccelerationStructureGeometryKHR* geometries = nullptr; VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; AccelerationStructure* tmpAs = (AccelerationStructure*)info->src; AccelerationStructure* dstAs = (AccelerationStructure*)info->dst; - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - VkAccelerationStructureKHR srcAs = nullptr; + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + + if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + if (tmpAs) { srcAs = tmpAs->handle; } @@ -6496,7 +6507,6 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( palFree(s_Vk.allocator, geometries); palFree(s_Vk.allocator, rangeInfos); - return PAL_RESULT_SUCCESS; } @@ -6861,18 +6871,17 @@ PalResult PAL_CALL cmdSetViewportVk( PalViewport* viewports) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - VkViewport cacheViewport; + VkViewport cachedViewport; VkViewport* vkViewports = nullptr; if (count > 1) { vkViewports = palAllocate(s_Vk.allocator, sizeof(VkViewport) * count, 0); - if (!vkViewports) { return PAL_RESULT_OUT_OF_MEMORY; } } else { - vkViewports = &cacheViewport; + vkViewports = &cachedViewport; } for (int i = 0; i < count; i++) { @@ -6898,18 +6907,17 @@ PalResult PAL_CALL cmdSetScissorsVk( PalRect2D* scissors) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - VkRect2D cacheScissor; + VkRect2D cachedScissor; VkRect2D* vkScissors = nullptr; if (count > 1) { vkScissors = palAllocate(s_Vk.allocator, sizeof(VkRect2D) * count, 0); - if (!vkScissors) { return PAL_RESULT_OUT_OF_MEMORY; } } else { - vkScissors = &cacheScissor; + vkScissors = &cachedScissor; } for (int i = 0; i < count; i++) { @@ -6935,7 +6943,7 @@ PalResult PAL_CALL cmdBindVertexBuffersVk( Uint64* offsets) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - VkBuffer cachebuffer = nullptr; + VkBuffer cachedbuffer = nullptr; VkBuffer* vkBuffers = nullptr; if (count > 1) { @@ -6945,7 +6953,7 @@ PalResult PAL_CALL cmdBindVertexBuffersVk( } } else { - vkBuffers = &cachebuffer; + vkBuffers = &cachedbuffer; } for (int i = 0; i < count; i++) { @@ -6972,8 +6980,8 @@ PalResult PAL_CALL cmdBindIndexBufferVk( if (type == PAL_INDEX_TYPE_UINT16) { bufferType = VK_INDEX_TYPE_UINT16; } - s_Vk.cmdBindIndexBuffer(vkCmdBuffer->handle, vkBuffer->handle, offset, bufferType); + s_Vk.cmdBindIndexBuffer(vkCmdBuffer->handle, vkBuffer->handle, offset, bufferType); return PAL_RESULT_SUCCESS; } @@ -6986,7 +6994,6 @@ PalResult PAL_CALL cmdDrawVk( { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.cmdDraw(vkCmdBuffer->handle, vertexCount, instanceCount, firstVertex, firstInstance); - return PAL_RESULT_SUCCESS; } @@ -7015,11 +7022,13 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; Buffer* vkCountBuffer = (Buffer*)countBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - vkCmdBuffer->device->cmdDrawIndirectCount( + device->cmdDrawIndirectCount( vkCmdBuffer->handle, vkBuffer->handle, offset, @@ -7076,11 +7085,13 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; Buffer* vkCountBuffer = (Buffer*)countBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - vkCmdBuffer->device->cmdDrawIndexedIndirectCount( + device->cmdDrawIndexedIndirectCount( vkCmdBuffer->handle, vkBuffer->handle, offset, @@ -7117,7 +7128,6 @@ PalResult PAL_CALL cmdMemoryBarrierVk( dependencyInfo.pMemoryBarriers = &barrier; vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - vkCmdBuffer->dstStage = new.stages; return PAL_RESULT_SUCCESS; } @@ -7158,7 +7168,6 @@ PalResult PAL_CALL cmdImageBarrierVk( dependencyInfo.pImageMemoryBarriers = &barrier; vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - vkCmdBuffer->dstStage = new.stages; return PAL_RESULT_SUCCESS; } @@ -7193,7 +7202,6 @@ PalResult PAL_CALL cmdBufferBarrierVk( dependencyInfo.pBufferMemoryBarriers = &barrier; vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - vkCmdBuffer->dstStage = new.stages; return PAL_RESULT_SUCCESS; } @@ -7205,7 +7213,6 @@ PalResult PAL_CALL cmdDispatchVk( { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.cmdDispatch(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); - return PAL_RESULT_SUCCESS; } @@ -7219,11 +7226,13 @@ PalResult PAL_CALL cmdDispatchBaseVk( Uint32 groupCountZ) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DISPATCH_BASE)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_DISPATCH_BASE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - vkCmdBuffer->device->cmdDispatchBase( + device->cmdDispatchBase( vkCmdBuffer->handle, baseGroupX, baseGroupY, @@ -7242,7 +7251,6 @@ PalResult PAL_CALL cmdDispatchIndirectVk( { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.cmdDispatchIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset); return PAL_RESULT_SUCCESS; } @@ -7254,7 +7262,9 @@ PalResult PAL_CALL cmdTraceRaysVk( Uint32 depth) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7343,8 +7353,8 @@ PalResult PAL_CALL cmdPushConstantsVk( VkShaderStageFlagBits bit = shaderStageToVK(shaderStages[i]); stages |= bit; } - s_Vk.cmdPushConstants(vkCmdBuffer->handle, vkLayout->handle, stages, offset, size, value); + s_Vk.cmdPushConstants(vkCmdBuffer->handle, vkLayout->handle, stages, offset, size, value); return PAL_RESULT_SUCCESS; } @@ -7353,7 +7363,9 @@ PalResult PAL_CALL cmdSetCullModeVk( PalCullMode cullMode) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7368,8 +7380,8 @@ PalResult PAL_CALL cmdSetCullModeVk( case PAL_CULL_MODE_NONE: vkCullMode = VK_CULL_MODE_NONE; } - vkCmdBuffer->device->cmdSetCullMode(vkCmdBuffer->handle, vkCullMode); - + + device->cmdSetCullMode(vkCmdBuffer->handle, vkCullMode); return PAL_RESULT_SUCCESS; } @@ -7378,7 +7390,9 @@ PalResult PAL_CALL cmdSetFrontFaceVk( PalFrontFace frontFace) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7390,8 +7404,8 @@ PalResult PAL_CALL cmdSetFrontFaceVk( case PAL_FRONT_FACE_COUNTER_CLOCKWISE: vkFrontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; } - vkCmdBuffer->device->cmdSetFrontFace(vkCmdBuffer->handle, vkFrontFace); + device->cmdSetFrontFace(vkCmdBuffer->handle, vkFrontFace); return PAL_RESULT_SUCCESS; } @@ -7400,7 +7414,9 @@ PalResult PAL_CALL cmdSetPrimitiveTopologyVk( PalPrimitiveTopology topology) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7431,8 +7447,8 @@ PalResult PAL_CALL cmdSetPrimitiveTopologyVk( break; } } - vkCmdBuffer->device->cmdSetPrimitiveTopology(vkCmdBuffer->handle, vkTopology); + device->cmdSetPrimitiveTopology(vkCmdBuffer->handle, vkTopology); return PAL_RESULT_SUCCESS; } @@ -7441,11 +7457,13 @@ PalResult PAL_CALL cmdSetDepthTestEnableVk( bool enable) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - vkCmdBuffer->device->cmdSetDepthTestEnable(vkCmdBuffer->handle, enable); + device->cmdSetDepthTestEnable(vkCmdBuffer->handle, enable); return PAL_RESULT_SUCCESS; } @@ -7454,11 +7472,13 @@ PalResult PAL_CALL cmdSetDepthWriteEnableVk( bool enable) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - vkCmdBuffer->device->cmdSetDepthWriteEnable(vkCmdBuffer->handle, enable); + device->cmdSetDepthWriteEnable(vkCmdBuffer->handle, enable); return PAL_RESULT_SUCCESS; } @@ -7471,7 +7491,9 @@ PalResult PAL_CALL cmdSetStencilOpVk( PalCompareOp compareOp) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP)) { + Device* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7489,7 +7511,7 @@ PalResult PAL_CALL cmdSetStencilOpVk( VkStencilOp vkDepthFailOp = stencilOpToVk(depthFailOp); VkCompareOp vkCompareOp = compareOpToVk(compareOp); - vkCmdBuffer->device->cmdSetStencilOp( + device->cmdSetStencilOp( vkCmdBuffer->handle, faceFlags, failOp, @@ -7513,6 +7535,7 @@ PalResult PAL_CALL createAccelerationstructureVk( AccelerationStructure* as = nullptr; Device* vkDevice = (Device*)device; Buffer* buffer = (Buffer*)info->buffer; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7575,6 +7598,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( VkAccelerationStructureGeometryKHR* geometries = nullptr; Device* vkDevice = (Device*)device; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7609,7 +7633,6 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( palFree(s_Vk.allocator, maxPrimities); palFree(s_Vk.allocator, geometries); - return PAL_RESULT_SUCCESS; } @@ -7625,6 +7648,7 @@ PalResult PAL_CALL createBufferVk( VkResult result; Buffer* buffer = nullptr; Device* vkDevice = (Device*)device; + if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -7648,9 +7672,7 @@ PalResult PAL_CALL createBufferVk( createInfo.size = info->size; createInfo.usage = bufferUsageToVk(info->usages); - result = - s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &buffer->handle); - + result = s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &buffer->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, buffer); return resultFromVk(result); @@ -7670,7 +7692,6 @@ void PAL_CALL destroyBufferVk(PalBuffer* buffer) { Buffer* vkBuffer = (Buffer*)buffer; s_Vk.destroyBuffer(vkBuffer->device->handle, vkBuffer->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, buffer); } @@ -7694,7 +7715,6 @@ PalResult PAL_CALL getBufferMemoryRequirementsVk( for (int i = 0; i < PAL_MEMORY_TYPE_MAX; i++) { requirements->memoryTypes[i] = (memReq.memoryTypeBits & device->memoryClassMask[i]) != 0; } - return PAL_RESULT_SUCCESS; } @@ -7743,7 +7763,6 @@ PalResult PAL_CALL bindBufferMemoryVk( if (result != VK_SUCCESS) { return resultFromVk(result); } - return PAL_RESULT_SUCCESS; } @@ -7774,21 +7793,20 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( VkDescriptorSetLayoutBinding* bindings = nullptr; VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlags = {0}; DescriptorSetLayout* layout = nullptr; + Uint32 count = info->bindingCount; layout = palAllocate(s_Vk.allocator, sizeof(DescriptorSetLayout), 0); - bindings = - palAllocate(s_Vk.allocator, sizeof(VkDescriptorSetLayoutBinding) * info->bindingCount, 0); - + bindings = palAllocate(s_Vk.allocator, sizeof(VkDescriptorSetLayoutBinding) * count, 0); if (!layout || !bindings) { return PAL_RESULT_OUT_OF_MEMORY; } VkDescriptorSetLayoutCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - createInfo.bindingCount = info->bindingCount; + createInfo.bindingCount = count; createInfo.pBindings = bindings; - for (int i = 0; i < info->bindingCount; i++) { + for (int i = 0; i < count; i++) { VkDescriptorSetLayoutBinding* binding = &bindings[i]; binding->binding = info->bindings[i].binding; binding->descriptorCount = info->bindings[i].descriptorCount; @@ -7804,7 +7822,8 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( if (vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { bindingFlags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; - bindingFlags.bindingCount = info->bindingCount; + bindingFlags.bindingCount = count; + VkDescriptorBindingFlags flags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; flags |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT; flags |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; @@ -7837,6 +7856,7 @@ void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout) vkLayout->device->handle, vkLayout->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, layout); } @@ -7849,18 +7869,15 @@ PalResult PAL_CALL createDescriptorPoolVk( Device* vkDevice = (Device*)device; DescriptorPool* pool = nullptr; VkDescriptorPoolSize* poolSizes = nullptr; + Uint32 maxBindings = info->maxDescriptorBindingSizes; pool = palAllocate(s_Vk.allocator, sizeof(DescriptorPool), 0); - poolSizes = palAllocate( - s_Vk.allocator, - sizeof(VkDescriptorPoolSize) * info->maxDescriptorBindingSizes, - 0); - + poolSizes = palAllocate(s_Vk.allocator, sizeof(VkDescriptorPoolSize) * maxBindings, 0); if (!pool || !poolSizes) { return PAL_RESULT_OUT_OF_MEMORY; } - for (int i = 0; i < info->maxDescriptorBindingSizes; i++) { + for (int i = 0; i < maxBindings; i++) { VkDescriptorPoolSize* poolSize = &poolSizes[i]; poolSize->descriptorCount = info->bindingSizes[i].bindingCount; poolSize->type = descriptortypeToVk(info->bindingSizes[i].descriptorType); @@ -7869,7 +7886,7 @@ PalResult PAL_CALL createDescriptorPoolVk( VkDescriptorPoolCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; createInfo.maxSets = info->maxDescriptorSets; - createInfo.poolSizeCount = info->maxDescriptorBindingSizes; + createInfo.poolSizeCount = maxBindings; createInfo.pPoolSizes = poolSizes; createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; @@ -7955,6 +7972,9 @@ PalResult PAL_CALL updateDescriptorSetVk( Uint32 bufferCount = 0; Uint32 imageCount = 0; Uint32 tlasCount = 0; + Uint32 bufferIndex = 0; + Uint32 imageIndex = 0; + Uint32 tlasIndex = 0; for (int i = 0; i < count; i++) { if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || @@ -7984,18 +8004,12 @@ PalResult PAL_CALL updateDescriptorSetVk( return PAL_RESULT_OUT_OF_MEMORY; } - tlasInfos = palAllocate( - s_Vk.allocator, - sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasCount, - 0); - + Uint32 tlasInfoSize = sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasCount; + tlasInfos = palAllocate(s_Vk.allocator, tlasInfoSize, 0); if (!tlasInfos && tlasCount) { return PAL_RESULT_OUT_OF_MEMORY; } - Uint32 bufferIndex = 0; - Uint32 imageIndex = 0; - Uint32 tlasIndex = 0; for (int i = 0; i < count; i++) { VkWriteDescriptorSet* write = &writes[i]; write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; @@ -8033,7 +8047,6 @@ PalResult PAL_CALL updateDescriptorSetVk( } else { VkDescriptorImageInfo* imageInfo = &imageInfos[imageIndex++]; - if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { Sampler* vkSampler = (Sampler*)infos[i].samplerInfo->sampler; @@ -8058,8 +8071,8 @@ PalResult PAL_CALL updateDescriptorSetVk( write->pImageInfo = imageInfo; } } - s_Vk.updateDescriptorSet(vkDevice->handle, count, writes, 0, nullptr); + s_Vk.updateDescriptorSet(vkDevice->handle, count, writes, 0, nullptr); palFree(s_Vk.allocator, writes); palFree(s_Vk.allocator, bufferInfos); palFree(s_Vk.allocator, imageInfos); @@ -8081,16 +8094,12 @@ PalResult PAL_CALL createPipelineLayoutVk( PipelineLayout* layout = nullptr; VkPushConstantRange* pushConstants = nullptr; VkDescriptorSetLayout* descriptorLayouts = nullptr; + Uint32 pushConstantSize = sizeof(VkPushConstantRange) * info->pushConstantRangeCount; + Uint32 setLayoutSize = sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount; layout = palAllocate(s_Vk.allocator, sizeof(PipelineLayout), 0); - pushConstants = - palAllocate(s_Vk.allocator, sizeof(VkPushConstantRange) * info->pushConstantRangeCount, 0); - - descriptorLayouts = palAllocate( - s_Vk.allocator, - sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount, - 0); - + pushConstants = palAllocate(s_Vk.allocator, pushConstantSize, 0); + descriptorLayouts = palAllocate(s_Vk.allocator, setLayoutSize, 0); if (!layout || !pushConstants || !descriptorLayouts) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -8135,7 +8144,6 @@ PalResult PAL_CALL createPipelineLayoutVk( palFree(s_Vk.allocator, descriptorLayouts); palFree(s_Vk.allocator, pushConstants); - layout->device = vkDevice; *outLayout = (PalPipelineLayout*)layout; return PAL_RESULT_SUCCESS; @@ -8200,15 +8208,16 @@ PalResult PAL_CALL createGraphicsPipelineVk( VkPipelineViewportStateCreateInfo viewportState = {0}; viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - VkPipelineFragmentShadingRateStateCreateInfoKHR fragmentShadingRateState = {0}; - fragmentShadingRateState.sType = - VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; + VkPipelineFragmentShadingRateStateCreateInfoKHR fsrState = {0}; + fsrState.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; VkPipelineRenderingCreateInfoKHR dynRendering = {0}; dynRendering.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR; VkGraphicsPipelineCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + createInfo.renderPass = VK_NULL_HANDLE; + createInfo.layout = layout->handle; pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); if (!pipeline) { @@ -8216,7 +8225,6 @@ PalResult PAL_CALL createGraphicsPipelineVk( } // shaders - memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo)); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; shaderStages[i] = tmp->info; @@ -8231,7 +8239,6 @@ PalResult PAL_CALL createGraphicsPipelineVk( } } } - createInfo.stageCount = info->shaderCount; createInfo.pStages = shaderStages; @@ -8243,57 +8250,55 @@ PalResult PAL_CALL createGraphicsPipelineVk( vertexCount += layout->attributeCount; } - bindingDescs = palAllocate( - s_Vk.allocator, - sizeof(VkVertexInputBindingDescription) * info->vertexLayoutCount, - 0); - - attribDescs = - palAllocate(s_Vk.allocator, sizeof(VkVertexInputAttributeDescription) * vertexCount, 0); - - if (!bindingDescs || !attribDescs) { - palFree(s_Vk.allocator, pipeline); - return PAL_RESULT_OUT_OF_MEMORY; - } - - for (int i = 0; i < info->vertexLayoutCount; i++) { - PalVertexLayout* layout = &info->vertexLayouts[i]; - VkVertexInputBindingDescription* bindingDesc = &bindingDescs[i]; - - bindingDesc->binding = layout->binding; - if (layout->type == PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE) { - bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; - } else { - bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + if (vertexCount) { + Uint32 tmpBindingSize = sizeof(VkVertexInputBindingDescription) * info->vertexLayoutCount; + Uint32 tmpAttribSize = sizeof(VkVertexInputAttributeDescription) * vertexCount; + bindingDescs = palAllocate(s_Vk.allocator, tmpBindingSize, 0); + attribDescs = palAllocate(s_Vk.allocator, tmpAttribSize, 0); + if (!bindingDescs || !attribDescs) { + palFree(s_Vk.allocator, pipeline); + return PAL_RESULT_OUT_OF_MEMORY; } - // find the stride and offset of the layout - bindingDesc->stride = 0; - Uint32 offset = 0; - for (int j = 0; j < layout->attributeCount; j++) { - PalVertexAttribute* vertexAttrib = &layout->attributes[j]; - VkVertexInputAttributeDescription* attribDesc = &attribDescs[j]; + for (int i = 0; i < info->vertexLayoutCount; i++) { + PalVertexLayout* layout = &info->vertexLayouts[i]; + VkVertexInputBindingDescription* bindingDesc = &bindingDescs[i]; - attribDesc->format = vertexTypeToVk(vertexAttrib->type); - attribDesc->binding = bindingDesc->binding; - attribDesc->location = vertexAttrib->location; + bindingDesc->binding = layout->binding; + if (layout->type == PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE) { + bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; + } else { + bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + } - // build offsets and stride - Uint32 size = getVertexTypeSizeVk(vertexAttrib->type); - attribDesc->offset = offset; - offset += size; - bindingDesc->stride += size; + // find the stride and offset of the layout + bindingDesc->stride = 0; + Uint32 offset = 0; + for (int j = 0; j < layout->attributeCount; j++) { + PalVertexAttribute* vertexAttrib = &layout->attributes[j]; + VkVertexInputAttributeDescription* attribDesc = &attribDescs[j]; + + attribDesc->format = vertexTypeToVk(vertexAttrib->type); + attribDesc->binding = bindingDesc->binding; + attribDesc->location = vertexAttrib->location; + + // build offsets and stride + Uint32 size = getVertexTypeSizeVk(vertexAttrib->type); + attribDesc->offset = offset; + offset += size; + bindingDesc->stride += size; + } } - } - vertexInputState.pVertexAttributeDescriptions = attribDescs; - vertexInputState.vertexAttributeDescriptionCount = vertexCount; - vertexInputState.pVertexBindingDescriptions = bindingDescs; - vertexInputState.vertexBindingDescriptionCount = info->vertexLayoutCount; + vertexInputState.pVertexAttributeDescriptions = attribDescs; + vertexInputState.vertexAttributeDescriptionCount = vertexCount; + vertexInputState.pVertexBindingDescriptions = bindingDescs; + vertexInputState.vertexBindingDescriptionCount = info->vertexLayoutCount; + } createInfo.pVertexInputState = &vertexInputState; // Input assembly - VkPrimitiveTopology topology; + VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; switch (info->topology) { case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; @@ -8320,9 +8325,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( break; } } - inputAssemblyState.topology = topology; - inputAssemblyState.primitiveRestartEnable = VK_FALSE; createInfo.pInputAssemblyState = &inputAssemblyState; // Dynamic states @@ -8367,6 +8370,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( createInfo.pDynamicState = &dynamicState; // Rasterizer state + rasterizerState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; if (info->rasterizerState) { PalRasterizerState* state = info->rasterizerState; if (state->cullMode == PAL_CULL_MODE_NONE) { @@ -8395,20 +8399,14 @@ PalResult PAL_CALL createGraphicsPipelineVk( rasterizerState.depthBiasEnable = state->enableDepthBias; rasterizerState.depthClampEnable = state->enableDepthClamp; - - } else { - rasterizerState.cullMode = VK_CULL_MODE_NONE; - rasterizerState.polygonMode = VK_POLYGON_MODE_FILL; - rasterizerState.frontFace = VK_FRONT_FACE_CLOCKWISE; - rasterizerState.depthBiasEnable = VK_FALSE; - rasterizerState.depthClampEnable = VK_FALSE; - rasterizerState.rasterizerDiscardEnable = VK_FALSE; - } - rasterizerState.rasterizerDiscardEnable = VK_FALSE; + } rasterizerState.lineWidth = 1.0f; createInfo.pRasterizationState = &rasterizerState; // Multisample state + Uint32 sampleMask[2] = {0}; // PAL supports upto 64 samples + multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampleState.pSampleMask = nullptr; if (info->multisampleState) { PalMultisampleState* state = info->multisampleState; multisampleState.alphaToCoverageEnable = state->enableAlphaToCoverage; @@ -8416,20 +8414,26 @@ PalResult PAL_CALL createGraphicsPipelineVk( multisampleState.sampleShadingEnable = state->enableSampleShading; multisampleState.rasterizationSamples = samplesToVk(state->sampleCount); - VkSampleMask sampleMasks[2]; - Uint32 mask1 = 0; - Uint32 mask2 = 0; - palUnpackUint32(state->sampleMask, &mask1, &mask2); - sampleMasks[0] = mask1; - sampleMasks[1] = mask2; - multisampleState.pSampleMask = sampleMasks; + // clang-format off + if (state->sampleMask) { + if (info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_1 || + info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_2 || + info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_4 || + info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_8 || + info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_16 || + info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_32) { + sampleMask[0] = (Uint32)(info->multisampleState->sampleMask & 0xFFFFFFFFULL); - } else { - multisampleState.alphaToCoverageEnable = VK_FALSE; - multisampleState.minSampleShading = VK_FALSE; - multisampleState.sampleShadingEnable = VK_FALSE; - multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampleState.pSampleMask = nullptr; + } else { + sampleMask[0] = (Uint32)(info->multisampleState->sampleMask & 0xFFFFFFFFULL); + sampleMask[1] = (Uint32)((info->multisampleState->sampleMask >> 32) & 0xFFFFFFFFULL); + } + multisampleState.pSampleMask = sampleMask; + + } else { + multisampleState.pSampleMask = nullptr; + } + // clang-format on } createInfo.pMultisampleState = &multisampleState; @@ -8456,25 +8460,15 @@ PalResult PAL_CALL createGraphicsPipelineVk( depthStencilState.depthTestEnable = state->enableDepthTest; depthStencilState.depthWriteEnable = state->enableDepthWrite; depthStencilState.stencilTestEnable = state->enableStencilTest; - - } else { - depthStencilState.depthCompareOp = VK_COMPARE_OP_NEVER; - depthStencilState.depthTestEnable = VK_FALSE; - depthStencilState.depthWriteEnable = VK_FALSE; - depthStencilState.stencilTestEnable = VK_FALSE; } createInfo.pDepthStencilState = &depthStencilState; // Color blend state if (info->colorBlendAttachmentCount) { Uint32 count = info->colorBlendAttachmentCount; - blendattachments = - palAllocate(s_Vk.allocator, sizeof(VkPipelineColorBlendAttachmentState) * count, 0); - + Uint32 size = sizeof(VkPipelineColorBlendAttachmentState) * count; + blendattachments = palAllocate(s_Vk.allocator, size, 0); if (!blendattachments) { - palFree(s_Vk.allocator, pipeline); - palFree(s_Vk.allocator, bindingDescs); - palFree(s_Vk.allocator, attribDescs); return PAL_RESULT_OUT_OF_MEMORY; } @@ -8513,58 +8507,58 @@ PalResult PAL_CALL createGraphicsPipelineVk( colorBlendState.attachmentCount = count; colorBlendState.pAttachments = blendattachments; - createInfo.pColorBlendState = &colorBlendState; } + createInfo.pColorBlendState = &colorBlendState; // viewport state viewportState.viewportCount = 1; viewportState.scissorCount = 1; createInfo.pViewportState = &viewportState; - createInfo.renderPass = VK_NULL_HANDLE; - createInfo.layout = layout->handle; - if (info->fragmentShadingRateState) { PalFragmentShadingRateState* state = info->fragmentShadingRateState; for (int i = 0; i < 2; i++) { VkFragmentShadingRateCombinerOpKHR combinerOp; combinerOp = combinerOpsToVk(state->combinerOps[i]); - fragmentShadingRateState.combinerOps[i] = combinerOp; + fsrState.combinerOps[i] = combinerOp; } VkExtent2D size = getShadingRateSizeVk(state->rate); - fragmentShadingRateState.fragmentSize = size; - createInfo.pNext = &fragmentShadingRateState; + fsrState.fragmentSize = size; + createInfo.pNext = &fsrState; } // layout info - VkFormat format = VK_FORMAT_UNDEFINED; - VkFormat colorAttachments[MAX_ATTACHMENTS]; - PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; + if (info->renderingLayout) { + VkFormat format = VK_FORMAT_UNDEFINED; + VkFormat colorAttachments[MAX_ATTACHMENTS]; + PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; + + // color attachments + for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { + format = formatToVk(renderingLayout->colorAttachmentsFormat[i]); + colorAttachments[i] = format; + } + dynRendering.colorAttachmentCount = renderingLayout->colorAttachentCount; + dynRendering.pColorAttachmentFormats = colorAttachments; - // color attachments - for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { - format = formatToVk(renderingLayout->colorAttachmentsFormat[i]); - colorAttachments[i] = format; - } - dynRendering.colorAttachmentCount = renderingLayout->colorAttachentCount; - dynRendering.pColorAttachmentFormats = colorAttachments; + // depth attachment + format = formatToVk(renderingLayout->depthAttachmentFormat); + dynRendering.depthAttachmentFormat = format; - // depth attachment - format = formatToVk(renderingLayout->depthAttachmentFormat); - dynRendering.depthAttachmentFormat = format; + // stencil attachment + format = formatToVk(renderingLayout->stencilAttachmentFormat); + dynRendering.stencilAttachmentFormat = format; - // stencil attachment - format = formatToVk(renderingLayout->stencilAttachmentFormat); - dynRendering.stencilAttachmentFormat = format; + if (renderingLayout->viewCount == 1) { + dynRendering.viewMask = 0; + } else { + dynRendering.viewMask = (1 << renderingLayout->viewCount) - 1; + } - if (renderingLayout->viewCount == 1) { - dynRendering.viewMask = 0; - } else { - dynRendering.viewMask = (1 << renderingLayout->viewCount) - 1; + createInfo.pNext = &dynRendering; } - createInfo.pNext = &dynRendering; result = s_Vk.createGraphicsPipeline( vkDevice->handle, 0, @@ -8578,9 +8572,14 @@ PalResult PAL_CALL createGraphicsPipelineVk( return resultFromVk(result); } - palFree(s_Vk.allocator, bindingDescs); - palFree(s_Vk.allocator, attribDescs); - palFree(s_Vk.allocator, blendattachments); + if (info->vertexLayoutCount) { + palFree(s_Vk.allocator, bindingDescs); + palFree(s_Vk.allocator, attribDescs); + } + + if (info->colorBlendAttachmentCount) { + palFree(s_Vk.allocator, blendattachments); + } pipeline->device = vkDevice; pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; @@ -8641,6 +8640,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( VkPipelineShaderStageCreateInfo shaderStages[6]; // 6 shader types for ray tracing pipeline VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; ShaderBindingTable* sbt = nullptr; + Uint32 groupSize = sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -8651,16 +8651,11 @@ PalResult PAL_CALL createRayTracingPipelineVk( pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); sbt = palAllocate(s_Vk.allocator, sizeof(ShaderBindingTable), 0); - groups = palAllocate( - s_Vk.allocator, - sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount, - 0); - + groups = palAllocate(s_Vk.allocator, groupSize, 0); if (!pipeline || !groups || !sbt) { return PAL_RESULT_OUT_OF_MEMORY; } - memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount); memset(groups, 0, sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount); memset(sbt, 0, sizeof(ShaderBindingTable)); @@ -8772,9 +8767,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( bufCreateInfo.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - result = - s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); - + result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); @@ -8919,7 +8912,6 @@ void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) palFree(s_Vk.allocator, vkPipeline->sbt); } - palFree(s_Vk.allocator, pipeline); } diff --git a/src/pal_core.c b/src/pal_core.c index 2816535f..ff177ff0 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -459,7 +459,7 @@ void* PAL_CALL palAllocate( align = PAL_DEFAULT_ALIGNMENT; } - if (allocator && allocator->allocate) { + if (allocator && allocator->allocate && size != 0) { return allocator->allocate(allocator->userData, size, align); } return alignedAlloc(size, align); diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 91a8de62..6d118b02 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -38,9 +38,10 @@ bool clearColorTest() PalImageView** imageViews = nullptr; PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* presentCompleteSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore** renderFinishedSemaphores; // count of swapchain images + PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalFence** inFlightImages; // count of swapchain images PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); @@ -212,14 +213,7 @@ bool clearColorTest() swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { - // the format is not supported. we default to BGRA - // if component mapping is not supported, we have to remap the component - // from the shader rather instead of mapping when creating the image views - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; - } + swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; // rare but possible on andriod if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { @@ -251,9 +245,8 @@ bool clearColorTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); - - if (!imageViews || !renderFinishedSemaphores) { + inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); + if (!imageViews || !inFlightImages) { palLog(nullptr, "Failed to allocate memory"); return false; } @@ -280,6 +273,8 @@ bool clearColorTest() palLog(nullptr, "Failed to create image view: %s", error); return false; } + + inFlightImages[i] = nullptr; } result = palCreateCommandPool(device, queue, &cmdPool); @@ -291,7 +286,14 @@ bool clearColorTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); + result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -318,27 +320,9 @@ bool clearColorTest() } } - // create synchronization objects - for (int i = 0; i < imageCount; i++) { - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - } - // main loop Uint32 currentFrame = 0; bool running = true; - PalSemaphore* presentCompleteSemaphore = nullptr; - PalSemaphore* renderFinishedSemaphore = nullptr; - PalFence* fence = nullptr; - PalCommandBuffer* cmdBuffer = nullptr; - - bool firstImageViewUse[8]; - memset(firstImageViewUse, 1, sizeof(bool) * 8); - while (running) { // update the video system to push video events palUpdateVideo(); @@ -362,19 +346,39 @@ bool clearColorTest() } } - fence = inFlightFences[currentFrame]; - presentCompleteSemaphore = presentCompleteSemaphores[currentFrame]; - cmdBuffer = cmdBuffers[currentFrame]; - - result = palWaitFence(fence, UINT64_MAX); + result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); return false; } + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; + nextImageInfo.timeout = PAL_INFINITE; + + Uint32 imageIndex = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + if (inFlightImages[imageIndex] != nullptr) { + result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + inFlightImages[imageIndex] = inFlightFences[currentFrame]; if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { - result = palResetFence(fence); + result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); @@ -383,9 +387,9 @@ bool clearColorTest() } else { // recreate since we dont support fence resetting - palDestroyFence(fence); + palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, false, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); @@ -393,78 +397,35 @@ bool clearColorTest() } } - // get next swapchain image - PalSwapchainNextImageInfo nextImageInfo = {0}; - nextImageInfo.fence = nullptr; - nextImageInfo.signalSemaphore = presentCompleteSemaphore; - nextImageInfo.timeout = UINT64_MAX; - - Uint32 index = 0; - result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &index); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; - } - - renderFinishedSemaphore = renderFinishedSemaphores[index]; - // reset the command buffer - result = palResetCommandBuffer(cmdBuffer); + result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); return false; } - result = palCmdBegin(cmdBuffer, nullptr); + result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); return false; } - PalClearValue clearValue; - clearValue.color[0] = 0.2f; - clearValue.color[1] = 0.2f; - clearValue.color[2] = 0.2f; - clearValue.color[3] = 1.0f; - - PalAttachmentDesc colorAttachment = {0}; - colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; - colorAttachment.storeOp = PAL_STORE_OP_STORE; - colorAttachment.clearValue = clearValue; - colorAttachment.imageView = imageViews[index]; - - PalRenderingInfo renderingInfo = {0}; - renderingInfo.viewCount = 1; - renderingInfo.colorAttachentCount = 1; - renderingInfo.colorAttachments = &colorAttachment; - renderingInfo.layerCount = 1; - renderingInfo.multisampleCount = PAL_SAMPLE_COUNT_1; - renderingInfo.renderArea.width = WINDOW_WIDTH; - renderingInfo.renderArea.height = WINDOW_HEIGHT; - // change the state of the image view to make it renderable PalUsageStateInfo oldUsageStateInfo = {0}; PalUsageStateInfo newUsageStateInfo = {0}; newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; - if (firstImageViewUse[index]) { - oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - } else { - oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - } - PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; imageRange.mipLevelCount = 1; imageRange.startArrayLayer = 0; imageRange.startMipLevel = 0; - PalImage* image = palGetSwapchainImage(swapchain, index); + PalImage* image = palGetSwapchainImage(swapchain, imageIndex); result = palCmdImageBarrier( - cmdBuffer, + cmdBuffers[currentFrame], image, &imageRange, &oldUsageStateInfo, @@ -476,20 +437,35 @@ bool clearColorTest() return false; } - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; - } + PalClearValue clearValue; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; - result = palCmdBeginRendering(cmdBuffer, &renderingInfo); + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.clearValue = clearValue; + colorAttachment.imageView = imageViews[imageIndex]; + + PalRenderingInfo renderingInfo = {0}; + renderingInfo.viewCount = 1; + renderingInfo.colorAttachentCount = 1; + renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.layerCount = 1; + renderingInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; + + result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); return false; } - result = palCmdEndRendering(cmdBuffer); + result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); @@ -500,7 +476,7 @@ bool clearColorTest() oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( - cmdBuffer, + cmdBuffers[currentFrame], image, &imageRange, &oldUsageStateInfo, @@ -512,7 +488,7 @@ bool clearColorTest() return false; } - result = palCmdEnd(cmdBuffer); + result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); @@ -521,10 +497,10 @@ bool clearColorTest() // submit command buffer PalCommandBufferSubmitInfo submitInfo = {0}; - submitInfo.cmdBuffer = cmdBuffer; - submitInfo.fence = fence; - submitInfo.waitSemaphore = presentCompleteSemaphore; - submitInfo.signalSemaphore = renderFinishedSemaphore; + submitInfo.cmdBuffer = cmdBuffers[currentFrame]; + submitInfo.fence = inFlightFences[currentFrame]; + submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -535,8 +511,8 @@ bool clearColorTest() // present PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = index; - presentInfo.waitSemaphore = renderFinishedSemaphore; + presentInfo.imageIndex = imageIndex; + presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -555,14 +531,14 @@ bool clearColorTest() } for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - palDestroySemaphore(presentCompleteSemaphores[i]); + palDestroySemaphore(imageAvailableSemaphores[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); palDestroyFence(inFlightFences[i]); palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { - palDestroyImageView(imageViews[i]); - palDestroySemaphore(renderFinishedSemaphores[i]); + palDestroyImageView(imageViews[i]); } palDestroyCommandPool(cmdPool); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 82ab42d6..6b01d91c 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -298,7 +298,6 @@ bool triangleTest() Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); - if (!imageViews || !inFlightImages) { palLog(nullptr, "Failed to allocate memory"); return false; @@ -659,11 +658,6 @@ bool triangleTest() pipelineCreateInfo.colorBlendAttachments = &blendAttachment; pipelineCreateInfo.colorBlendAttachmentCount = 1; - // multisample state - PalMultisampleState multisampleState = {0}; - multisampleState.sampleCount = PAL_SAMPLE_COUNT_1; - pipelineCreateInfo.multisampleState = &multisampleState; - // shaders PalShader* shaders[2]; shaders[0] = vertexShader; @@ -786,9 +780,6 @@ bool triangleTest() } } - // TODO: remove - palLog(nullptr, "Image index %d", imageIndex); - // reset the command buffer result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { From c7383876759538d69b5b2a1a5453251b9e496a63 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 27 Mar 2026 20:24:13 +0000 Subject: [PATCH 123/372] add surface API --- include/pal/pal_graphics.h | 132 ++++++++++--- src/graphics/pal_graphics.c | 84 +++++++-- src/graphics/pal_vulkan.c | 367 ++++++++++++++++-------------------- src/video/pal_video_linux.c | 1 - tests/clear_color_test.c | 38 ++-- tests/mesh_test.c | 47 ++--- tests/texture_test.c | 47 ++--- tests/triangle_test.c | 46 ++--- 8 files changed, 434 insertions(+), 328 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 8a73a059..53cf998b 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -93,6 +93,15 @@ typedef struct PalMemory PalMemory; */ typedef struct PalQueue PalQueue; +/** + * @struct PalSurface + * @brief Opaque handle to a surface. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct PalSurface PalSurface; + /** * @struct PalSwapchain * @brief Opaque handle to a swapchain. @@ -736,23 +745,23 @@ typedef enum { } PalBorderColor; /** - * @enum PalSwapchainFormat - * @brief swapchain format types. + * @enum PalSurfaceFormat + * @brief Surface format types. * - * All swapchain format types follow the format `PAL_SWAPCHAIN_FORMAT_**` for + * All surface format types follow the format `PAL_SURFACE_FORMAT_**` for * consistency and API use. * * @since 1.4 * @ingroup pal_graphics */ typedef enum { - PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB, - PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB, - PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB, - PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10, /**< HDR.*/ + PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB, + PAL_SURFACE_FORMAT_BGRA8_SRGB_SRGB, + PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB, + PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10, /**< HDR.*/ - PAL_SWAPCHAIN_FORMAT_MAX -} PalSwapchainFormat; + PAL_SURFACE_FORMAT_MAX +} PalSurfaceFormat; /** * @enum PalGraphicsWindowDisplayType @@ -1476,8 +1485,8 @@ typedef struct { } PalDescriptorIndexingCapabilities; /** - * @struct PalSwapchainCapabilities - * @brief swapchain capabilities of an adapter (GPU). + * @struct PalSurfaceCapabilities + * @brief surface capabilities of an adapter (GPU). * * @since 1.4 * @ingroup pal_graphics @@ -1493,7 +1502,7 @@ typedef struct { /** Bool array of supported swapchain formats. * (eg. formats[`PAL_COMPOSITE_ALPHA_OPAQUE`]).*/ - bool formats[PAL_SWAPCHAIN_FORMAT_MAX]; + bool formats[PAL_SURFACE_FORMAT_MAX]; Uint32 minImageCount; Uint32 maxImageCount; Uint32 minImageWidth; @@ -1501,7 +1510,7 @@ typedef struct { Uint32 maxImageWidth; Uint32 maxImageHeight; Uint32 maxImageArrayLayers; -} PalSwapchainCapabilities; +} PalSurfaceCapabilities; /** * @struct PalGraphicsWindow @@ -2370,7 +2379,7 @@ typedef struct { Uint32 imageArrayLayerCount; /**< Set to 1 for default.*/ PalPresentMode presentMode; /**< (eg. PAL_PRESENT_MODE_FIFO).*/ PalCompositeAplha compositeAlpha; /**< (eg. PAL_COMPOSITE_ALPHA_OPAQUE).*/ - PalSwapchainFormat format; /**< (eg. PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB).*/ + PalSurfaceFormat format; /**< (eg. PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB).*/ } PalSwapchainCreateInfo; /** @@ -2722,7 +2731,7 @@ typedef struct { */ bool PAL_CALL (*canQueuePresent)( PalQueue* queue, - PalGraphicsWindow* window); + PalSurface* surface); /** * Backend implementation of ::palWaitQueue. @@ -2849,14 +2858,31 @@ typedef struct { void PAL_CALL (*destroySampler)(PalSampler* sampler); /** - * Backend implementation of ::palQuerySwapchainCapabilities. + * Backend implementation of ::palCreateSurface. * - * Must obey the rules and semantics documented in palQuerySwapchainCapabilities(). + * Must obey the rules and semantics documented in palCreateSurface(). */ - PalResult PAL_CALL (*querySwapchainCapabilities)( + PalResult PAL_CALL (*createSurface)( PalDevice* device, PalGraphicsWindow* window, - PalSwapchainCapabilities* caps); + PalSurface** outSurface); + + /** + * Backend implementation of ::palDestroySurface. + * + * Must obey the rules and semantics documented in palDestroySurface(). + */ + void PAL_CALL (*destroySurface)(PalSurface* surface); + + /** + * Backend implementation of ::palGetSurfaceCapabilities. + * + * Must obey the rules and semantics documented in palGetSurfaceCapabilities(). + */ + PalResult PAL_CALL (*getSurfaceCapabilities)( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps); /** * Backend implementation of ::palCreateSwapchain. @@ -2866,7 +2892,7 @@ typedef struct { PalResult PAL_CALL (*createSwapchain)( PalDevice* device, PalQueue* queue, - PalGraphicsWindow* window, + PalSurface* surface, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain); @@ -4221,7 +4247,7 @@ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); * The graphics system must be initialized before this call. * * @param[in] queue Queue to query. - * @param[in] window Window to check presentation support for. + * @param[in] surface Surface to check presentation support for. * * @return True if queue can present otherwise false if queue can not present. * @@ -4233,7 +4259,7 @@ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); */ PAL_API bool PAL_CALL palCanQueuePresent( PalQueue* queue, - PalGraphicsWindow* window); + PalSurface* surface); /** * @brief Blocks indefinitely until the queue becomes idle. @@ -4562,16 +4588,60 @@ PAL_API PalResult PAL_CALL palCreateSampler( PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); /** - * @brief Get swapchain feature capabilites or limits about a device against a window. + * @brief Create a surface for a window. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device that creates the surface. + * @param[in] window Window to create the surface for. + * @param[out] outSurface Pointer to a PalSurface to recieve the created surface. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroySurface + */ +PAL_API PalResult PAL_CALL palCreateSurface( + PalDevice* device, + PalGraphicsWindow* window, + PalSurface** outSurface); + +/** + * @brief Destroy a surface. + * + * The graphics system must be initialized before this call. + * If the provided surface is invalid or nullptr, this function returns + * silently. + * + * @param[in] surface Surface to destroy. + * + * Thread safety: Thread safe if the device used to create the surface is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateSurface + */ +PAL_API void PAL_CALL palDestroySurface(PalSurface* surface); + +/** + * @brief Get surface capabilites about a device. * * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * - * @param[in] device Device to query swapchain feature capabilities on. - * @param[in] window Window to query swapchain feature capabilities against. - * @param[out] caps Pointer to a PalSwapchainCapabilities to fill. + * @param[in] device Device to query surface feature capabilities on. + * @param[in] surface Surface to query capabilities. + * @param[out] caps Pointer to a PalSurfaceCapabilities to fill. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -4581,10 +4651,10 @@ PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); * @since 1.4 * @ingroup pal_graphics */ -PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( +PAL_API PalResult PAL_CALL palGetSurfaceCapabilities( PalDevice* device, - PalGraphicsWindow* window, - PalSwapchainCapabilities* caps); + PalSurface* surface, + PalSurfaceCapabilities* caps); /** * @brief Create a swaphain. @@ -4596,7 +4666,7 @@ PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( * * @param[in] device Device that creates the swapchain. * @param[in] queue Queue to create swapchain with. This must be a graphics queue. - * @param[in] window Window to create swapchain with. + * @param[in] surface Surface to create swapchain with. * @param[in] info Pointer to a PalSwapchainCreateInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outSwapchain Pointer to a PalSwapchain to recieve the created swapchain. @@ -4613,7 +4683,7 @@ PAL_API PalResult PAL_CALL palQuerySwapchainCapabilities( PAL_API PalResult PAL_CALL palCreateSwapchain( PalDevice* device, PalQueue* queue, - PalGraphicsWindow* window, + PalSurface* surface, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index f071591b..979903b9 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -57,6 +57,7 @@ PAL_HANDLE(PalDescriptorSetLayout) PAL_HANDLE(PalDescriptorPool) PAL_HANDLE(PalDescriptorSet) PAL_HANDLE(PalSampler) +PAL_HANDLE(PalSurface) typedef struct { Int32 count; @@ -168,7 +169,7 @@ PalResult PAL_CALL waitQueueVk(PalQueue* queue); bool PAL_CALL canQueuePresentVk( PalQueue* queue, - PalGraphicsWindow* window); + PalSurface* surface); PalResult PAL_CALL enumerateFormatsVk( PalAdapter* adapter, @@ -222,15 +223,22 @@ PalResult PAL_CALL createSamplerVk( void PAL_CALL destroySamplerVk(PalSampler* sampler); -PalResult PAL_CALL querySwapchainCapabilitiesVk( +PalResult PAL_CALL createSurfaceVk( PalDevice* device, PalGraphicsWindow* window, - PalSwapchainCapabilities* caps); + PalSurface** outSurface); + +void PAL_CALL destroySurfaceVk(PalSurface* surface); + +PalResult PAL_CALL getSurfaceCapabilitiesVk( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps); PalResult PAL_CALL createSwapchainVk( PalDevice* device, PalQueue* queue, - PalGraphicsWindow* window, + PalSurface* surface, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain); @@ -707,8 +715,12 @@ static PalGraphicsBackend s_VkBackend = { .createSampler = createSamplerVk, .destroySampler = destroySamplerVk, + // surface + .createSurface = createSurfaceVk, + .destroySurface = destroySurfaceVk, + .getSurfaceCapabilities = getSurfaceCapabilitiesVk, + // swapchain - .querySwapchainCapabilities = querySwapchainCapabilitiesVk, .createSwapchain = createSwapchainVk, .destroySwapchain = destroySwapchainVk, .getSwapchainImage = getSwapchainImageVk, @@ -903,8 +915,12 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->createSampler || !backend->destroySampler || + // surface + !backend->createSurface || + !backend->destroySurface || + !backend->getSurfaceCapabilities || + // swapchain - !backend->querySwapchainCapabilities || !backend->createSwapchain || !backend->destroySwapchain || !backend->getSwapchainImage || @@ -1379,10 +1395,10 @@ void PAL_CALL palDestroyQueue(PalQueue* queue) bool PAL_CALL palCanQueuePresent( PalQueue* queue, - PalGraphicsWindow* window) + PalSurface* surface) { if (s_Graphics.initialized && queue) { - return queue->backend->canQueuePresent(queue, window); + return queue->backend->canQueuePresent(queue, surface); } return false; } @@ -1613,29 +1629,65 @@ void PAL_CALL palDestroySampler(PalSampler* sampler) } // ================================================== -// Swapchain +// Surface // ================================================== -PalResult PAL_CALL palQuerySwapchainCapabilities( +PalResult PAL_CALL palCreateSurface( PalDevice* device, PalGraphicsWindow* window, - PalSwapchainCapabilities* caps) + PalSurface** outSurface) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device || !window || !caps) { + if (!device || !window || !outSurface) { return PAL_RESULT_NULL_POINTER; } - return device->backend->querySwapchainCapabilities(device, window, caps); + PalSurface* surface = nullptr; + PalResult result; + result = device->backend->createSurface(device, window, &surface); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + surface->backend = device->backend; + *outSurface = surface; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroySurface(PalSurface* surface) +{ + if (s_Graphics.initialized && surface) { + surface->backend->destroySurface(surface); + } } +PalResult PAL_CALL palGetSurfaceCapabilities( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !surface || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->getSurfaceCapabilities(device, surface, caps); +} + +// ================================================== +// Swapchain +// ================================================== + PalResult PAL_CALL palCreateSwapchain( PalDevice* device, PalQueue* queue, - PalGraphicsWindow* window, + PalSurface* surface, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain) { @@ -1643,13 +1695,13 @@ PalResult PAL_CALL palCreateSwapchain( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device || !queue || !window || !info || !outSwapchain) { + if (!device || !queue || !surface || !info || !outSwapchain) { return PAL_RESULT_NULL_POINTER; } PalResult result; PalSwapchain* swapchain = nullptr; - result = device->backend->createSwapchain(device, queue, window, info, &swapchain); + result = device->backend->createSwapchain(device, queue, surface, info, &swapchain); if (result != PAL_RESULT_SUCCESS) { return result; } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index c346c4a4..d586985c 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -313,18 +313,15 @@ typedef struct { PFN_vkCmdPushConstants cmdPushConstants; PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; - PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR checkWaylandPresentSupport; PFN_vkCreateXlibSurfaceKHR createXlibSurface; - PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR checkXlibPresentSupport; PFN_vkCreateXcbSurfaceKHR createXcbSurface; - PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR checkXcbPresentSupport; PFN_vkCreateWin32SurfaceKHR createWin32Surface; - PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR checkWin32PresentSupport; PFN_vkDestroySurfaceKHR destroySurface; PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR getSurfaceCapabilities; PFN_vkGetPhysicalDeviceSurfaceFormatsKHR getSurfaceFormats; PFN_vkGetPhysicalDeviceSurfacePresentModesKHR getSurfacePresentModes; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR checkSurfaceSupport; PFN_vkCreateBuffer createBuffer; PFN_vkDestroyBuffer destroyBuffer; @@ -460,13 +457,19 @@ typedef struct { VkImageSubresourceRange range; } ImageView; +typedef struct { + const PalGraphicsBackend* backend; + + Device* device; + VkSurfaceKHR handle; +} Surface; + typedef struct { const PalGraphicsBackend* backend; Uint32 imageCount; Device* device; Queue* queue; - VkSurfaceKHR surface; VkSwapchainKHR handle; Image* images; } Swapchain; @@ -628,90 +631,6 @@ static void* loadProc(void* lib, const char* name) #endif } -static bool createSurfaceVk( - PalGraphicsWindow* window, - VkSurfaceKHR* outSurface) -{ - VkResult result; - VkSurfaceKHR surface = nullptr; - -#ifdef __WIN32 - if (!s_Vk.createWin32Surface) { - return false; - } - - VkWin32SurfaceCreateInfoKHR cInfo = {0}; - cInfo.hinstance = GetModuleHandle(nullptr); - cInfo.hwnd = window->window; - cInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - - result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &surface); - if (result != VK_SUCCESS) { - return false; - } - - *outSurface = surface; - return true; -#else - if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND) { - if (!s_Vk.createWaylandSurface) { - return false; - } - - VkWaylandSurfaceCreateInfoKHR cInfo = {0}; - cInfo.display = window->display; - cInfo.pNext = nullptr; - cInfo.flags = 0; - cInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; - cInfo.surface = window->window; - - result = s_Vk.createWaylandSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &surface); - if (result != VK_SUCCESS) { - return false; - } - - *outSurface = surface; - return true; - - } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11) { - if (!s_Vk.createXlibSurface) { - return false; - } - - VkXlibSurfaceCreateInfoKHR cInfo = {0}; - cInfo.dpy = window->display; - cInfo.window = (Window)(UintPtr)(window->window); - cInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - - result = s_Vk.createXlibSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &surface); - if (result != VK_SUCCESS) { - return false; - } - - *outSurface = surface; - return true; - - } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB) { - if (!s_Vk.createXcbSurface) { - return false; - } - - VkXcbSurfaceCreateInfoKHR cInfo = {0}; - cInfo.connection = window->display; - cInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; - - result = s_Vk.createXcbSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &surface); - if (result != VK_SUCCESS) { - return false; - } - - *outSurface = surface; - return true; - } - -#endif // __WIN32 -} - static PalResult resultFromVk(VkResult result) { switch (result) { @@ -2932,11 +2851,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.createWaylandSurface = (PFN_vkCreateWaylandSurfaceKHR)s_Vk.getInstanceProcAddr( instance, "vkCreateWaylandSurfaceKHR"); - - s_Vk.checkWaylandPresentSupport = - (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)s_Vk.getInstanceProcAddr( - instance, - "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); } if (hasXlib) { @@ -2954,11 +2868,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.createXlibSurface = (PFN_vkCreateXlibSurfaceKHR)s_Vk.getInstanceProcAddr( instance, "vkCreateXlibSurfaceKHR"); - - s_Vk.checkXlibPresentSupport = - (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)s_Vk.getInstanceProcAddr( - instance, - "vkGetPhysicalDeviceXlibPresentationSupportKHR"); } if (hasXcb) { @@ -2976,22 +2885,12 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.createXcbSurface = (PFN_vkCreateXcbSurfaceKHR)s_Vk.getInstanceProcAddr( instance, "vkCreateXcbSurfaceKHR"); - - s_Vk.checkXcbPresentSupport = - (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)s_Vk.getInstanceProcAddr( - instance, - "vkGetPhysicalDeviceXcbPresentationSupportKHR"); } if (hasWin32) { s_Vk.createWin32Surface = (PFN_vkCreateWin32SurfaceKHR)s_Vk.getInstanceProcAddr( instance, "vkCreateWin32SurfaceKHR"); - - s_Vk.checkWin32PresentSupport = - (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)s_Vk.getInstanceProcAddr( - instance, - "vkGetPhysicalDeviceWin32PresentationSupportKHR"); } // remaining function procs @@ -3013,6 +2912,10 @@ PalResult PAL_CALL initGraphicsVk( instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"); + s_Vk.checkSurfaceSupport = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceSurfaceSupportKHR"); + if (debugger) { s_Vk.createMessenger = (PFN_vkCreateDebugUtilsMessengerEXT)s_Vk.getInstanceProcAddr( @@ -4777,69 +4680,30 @@ PalResult PAL_CALL waitQueueVk(PalQueue* queue) bool PAL_CALL canQueuePresentVk( PalQueue* queue, - PalGraphicsWindow* window) + PalSurface* surface) { + VkResult result; Queue* vkQueue = (Queue*)queue; + PhysicalQueue* phyQueue = vkQueue->phyQueue; + Surface* vkSurface = (Surface*)surface; + // check if the queue is a graphics queue before we check its family // index for presentation support. if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { return false; } - PhysicalQueue* phyQueue = vkQueue->phyQueue; -#ifdef __WIN32 - if (s_Vk.checkWin32PresentSupport( - phyQueue->phyDevice, - phyQueue->familyIndex)) { + VkBool32 supported = false; + result = s_Vk.checkSurfaceSupport( + phyQueue->phyDevice, + phyQueue->familyIndex, + vkSurface->handle, + &supported); + + if (result == VK_SUCCESS && supported) { return true; } -#else - if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND) { - if (s_Vk.checkWaylandPresentSupport( - phyQueue->phyDevice, - phyQueue->familyIndex, - window->display)) { - return true; - } - - } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11) { - XWindowAttributes attrs = {0}; - Window xWin = (Window)(UintPtr)(window->window); - VisualID visualID = 0; - - if (s_Vk.XGetWindowAttributes(window->display, xWin, &attrs)) { - visualID = s_Vk.XVisualIDFromVisual(attrs.visual); - } - - if (s_Vk.checkXlibPresentSupport( - phyQueue->phyDevice, - phyQueue->familyIndex, - window->display, - visualID)) { - return true; - } - - } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB) { - xcb_get_window_attributes_cookie_t cookie = {0}; - xcb_get_window_attributes_reply_t* reply = nullptr; - xcb_window_t xcbWin = (xcb_window_t)(UintPtr)(window->window); - cookie = s_Vk.xcbGetWindowAttributes(window->display, xcbWin); - reply = s_Vk.xcbGetWindowAttributesReply(window->display, cookie, nullptr); - if (!reply) { - return false; - } - - if (s_Vk.checkXcbPresentSupport( - phyQueue->phyDevice, - phyQueue->familyIndex, - window->display, - reply->visual)) { - free(reply); - return true; - } - } -#endif // __WIN32 return false; } @@ -5402,17 +5266,129 @@ void PAL_CALL destroySamplerVk(PalSampler* sampler) } // ================================================== -// Swapchain +// Surface // ================================================== -PalResult PAL_CALL querySwapchainCapabilitiesVk( +PalResult PAL_CALL createSurfaceVk( PalDevice* device, PalGraphicsWindow* window, - PalSwapchainCapabilities* caps) + PalSurface** outSurface) +{ + VkResult result; + Surface* surface = nullptr; + Device* vkDevice = (Device*)device; + + surface = palAllocate(s_Vk.allocator, sizeof(Surface), 0); + if (!surface) { + return PAL_RESULT_OUT_OF_MEMORY; + } + +#ifdef __WIN32 + if (!s_Vk.createWin32Surface) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkWin32SurfaceCreateInfoKHR cInfo = {0}; + cInfo.hinstance = GetModuleHandle(nullptr); + cInfo.hwnd = window->window; + cInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + + VkSurfaceKHR tmp = nullptr; + result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + if (result != VK_SUCCESS) { + return resultFromVk(result); + } + + surface->device = vkDevice; + surface->handle = tmp; + *outSurface = (PalSurface*)surface; + return PAL_RESULT_SUCCESS; + +#else + if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND) { + if (!s_Vk.createWaylandSurface) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkWaylandSurfaceCreateInfoKHR cInfo = {0}; + cInfo.display = window->display; + cInfo.pNext = nullptr; + cInfo.flags = 0; + cInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + cInfo.surface = window->window; + + VkSurfaceKHR tmp = nullptr; + result = s_Vk.createWaylandSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + if (result != VK_SUCCESS) { + return resultFromVk(result); + } + + surface->device = vkDevice; + surface->handle = tmp; + *outSurface = (PalSurface*)surface; + return PAL_RESULT_SUCCESS; + + } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11) { + if (!s_Vk.createXlibSurface) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkXlibSurfaceCreateInfoKHR cInfo = {0}; + cInfo.dpy = window->display; + cInfo.window = (Window)(UintPtr)(window->window); + cInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + + VkSurfaceKHR tmp = nullptr; + result = s_Vk.createXlibSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + if (result != VK_SUCCESS) { + return resultFromVk(result); + } + + surface->device = vkDevice; + surface->handle = tmp; + *outSurface = (PalSurface*)surface; + return PAL_RESULT_SUCCESS; + + } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB) { + if (!s_Vk.createXcbSurface) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkXcbSurfaceCreateInfoKHR cInfo = {0}; + cInfo.connection = window->display; + cInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + + VkSurfaceKHR tmp = nullptr; + result = s_Vk.createXcbSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + if (result != VK_SUCCESS) { + return resultFromVk(result); + } + + surface->device = vkDevice; + surface->handle = tmp; + *outSurface = (PalSurface*)surface; + return PAL_RESULT_SUCCESS; + } + +#endif // __WIN32 +} + +void PAL_CALL destroySurfaceVk(PalSurface* surface) +{ + Surface* vkSurface = (Surface*)surface; + s_Vk.destroySurface(s_Vk.instance, vkSurface->handle, &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, vkSurface); +} + +PalResult PAL_CALL getSurfaceCapabilitiesVk( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps) { Int32 formatCount = 0; Int32 modeCount = 0; - VkSurfaceKHR surface = nullptr; + Surface* vkSurface = (Surface*)surface; VkSurfaceFormatKHR* formats = nullptr; VkPresentModeKHR* modes = nullptr; @@ -5423,26 +5399,21 @@ PalResult PAL_CALL querySwapchainCapabilitiesVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - bool result = createSurfaceVk(window, &surface); - if (!result) { - return PAL_RESULT_INVALID_GRAPHICS_WINDOW; - } - - s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, nullptr); - s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, nullptr); + s_Vk.getSurfacePresentModes(phyDevice, vkSurface->handle, &modeCount, nullptr); + s_Vk.getSurfaceFormats(phyDevice, vkSurface->handle, &formatCount, nullptr); modes = palAllocate(s_Vk.allocator, sizeof(VkPresentModeKHR) * modeCount, 0); formats = palAllocate(s_Vk.allocator, sizeof(VkSurfaceFormatKHR) * formatCount, 0); if (!modes || !formats) { - s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.vkAllocator); return PAL_RESULT_OUT_OF_MEMORY; } - s_Vk.getSurfacePresentModes(phyDevice, surface, &modeCount, modes); - s_Vk.getSurfaceFormats(phyDevice, surface, &formatCount, formats); + s_Vk.getSurfacePresentModes(phyDevice, vkSurface->handle, &modeCount, modes); + s_Vk.getSurfaceFormats(phyDevice, vkSurface->handle, &formatCount, formats); VkSurfaceCapabilitiesKHR surfaceCaps; - s_Vk.getSurfaceCapabilities(phyDevice, surface, &surfaceCaps); + s_Vk.getSurfaceCapabilities(phyDevice, vkSurface->handle, &surfaceCaps); + caps->minImageWidth = surfaceCaps.minImageExtent.width; caps->minImageHeight = surfaceCaps.minImageExtent.height; caps->maxImageWidth = surfaceCaps.maxImageExtent.width; @@ -5486,49 +5457,52 @@ PalResult PAL_CALL querySwapchainCapabilitiesVk( } // get format and colorspace - caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = false; - caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB] = false; - caps->formats[PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB] = false; - caps->formats[PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB] = false; + caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = false; + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB] = false; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_SRGB] = false; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB] = false; for (int i = 0; i < formatCount; i++) { VkSurfaceFormatKHR* fmt = &formats[i]; if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB] = true; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB] = true; } } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB] = true; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_SRGB] = true; } } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB] = true; + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB] = true; } } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { - caps->formats[PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10] = true; + caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = true; } } } palFree(s_Vk.allocator, formats); palFree(s_Vk.allocator, modes); - s_Vk.destroySurface(s_Vk.instance, surface, &s_Vk.vkAllocator); return PAL_RESULT_SUCCESS; } +// ================================================== +// Swapchain +// ================================================== + PalResult PAL_CALL createSwapchainVk( PalDevice* device, PalQueue* queue, - PalGraphicsWindow* window, + PalSurface* surface, const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain) { @@ -5539,6 +5513,7 @@ PalResult PAL_CALL createSwapchainVk( Device* vkDevice = (Device*)device; Queue* vkQueue = (Queue*)queue; PhysicalQueue* phyQueue = vkQueue->phyQueue; + Surface* vkSurface = (Surface*)surface; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -5554,20 +5529,16 @@ PalResult PAL_CALL createSwapchainVk( if (!swapchain) { return PAL_RESULT_OUT_OF_MEMORY; } - memset(swapchain, 0, sizeof(Swapchain)); - if (!createSurfaceVk(window, &swapchain->surface)) { - return PAL_RESULT_INVALID_GRAPHICS_WINDOW; - } VkSwapchainCreateInfoKHR createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.surface = swapchain->surface; + createInfo.surface = vkSurface->handle; createInfo.imageArrayLayers = info->imageArrayLayerCount; createInfo.imageExtent.width = info->width; createInfo.imageExtent.height = info->height; createInfo.minImageCount = info->imageCount; - createInfo.clipped = VK_FALSE; + createInfo.clipped = info->clipped; createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; @@ -5595,17 +5566,17 @@ PalResult PAL_CALL createSwapchainVk( createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; imageFormat = PAL_FORMAT_B8G8R8A8_UNORM; - if (info->format == PAL_SWAPCHAIN_FORMAT_BGRA8_SRGB_SRGB) { + if (info->format == PAL_SURFACE_FORMAT_BGRA8_SRGB_SRGB) { createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; imageFormat = PAL_FORMAT_B8G8R8A8_SRGB; - } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB) { + } else if (info->format == PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB) { createInfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; imageFormat = PAL_FORMAT_R8G8B8A8_UNORM; - } else if (info->format == PAL_SWAPCHAIN_FORMAT_RGBA16_FLOAT_HDR10) { + } else if (info->format == PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10) { createInfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; createInfo.imageColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; imageFormat = PAL_FORMAT_R16G16B16A16_SFLOAT; @@ -5619,8 +5590,6 @@ PalResult PAL_CALL createSwapchainVk( &swapchain->handle); if (result != VK_SUCCESS) { - s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, swapchain); return resultFromVk(result); } @@ -5633,7 +5602,6 @@ PalResult PAL_CALL createSwapchainVk( images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); if (!swapchain->images || !images) { vkDevice->destroySwapchain(vkDevice->handle, swapchain->handle, &s_Vk.vkAllocator); - s_Vk.destroySurface(s_Vk.instance, swapchain->surface, &s_Vk.vkAllocator); palFree(s_Vk.allocator, swapchain); return PAL_RESULT_OUT_OF_MEMORY; } @@ -5658,7 +5626,6 @@ PalResult PAL_CALL createSwapchainVk( } palFree(s_Vk.allocator, images); - swapchain->device = vkDevice; swapchain->queue = vkQueue; swapchain->imageCount = count; @@ -5675,8 +5642,6 @@ void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain) vkSwapchain->handle, &s_Vk.vkAllocator); - s_Vk.destroySurface(s_Vk.instance, vkSwapchain->surface, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkSwapchain->images); palFree(s_Vk.allocator, vkSwapchain); } diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index ba79e128..3a004ce5 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -6134,7 +6134,6 @@ static struct wl_buffer* createShmBuffer( } buffer = wlShmPoolCreateBuffer(pool, 0, width, height, stride, format); - if (!buffer) { return nullptr; } diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 6d118b02..bded762e 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -32,6 +32,7 @@ bool clearColorTest() PalAdapter* adapter = nullptr; PalDevice* device = nullptr; + PalSurface* surface = nullptr; PalQueue* queue = nullptr; PalSwapchain* swapchain = nullptr; PalCommandPool* cmdPool = nullptr; @@ -191,18 +192,26 @@ bool clearColorTest() return false; } - if (!palCanQueuePresent(queue, &gfxWindow)) { - palLog(nullptr, "Queue cannot present to window"); + // create surface + result = palCreateSurface(device, &gfxWindow, &surface); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create surface: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palLog(nullptr, "Queue cannot present to surface"); return false; } // create a swapchain with the graphics queue - PalSwapchainCapabilities swapchainCaps = {0}; - result = palQuerySwapchainCapabilities(device, &gfxWindow, &swapchainCaps); + PalSurfaceCapabilities surfaceCaps = {0}; + result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query swapchain capabilities: %s", error); + palLog(nullptr, "Failed to get surface capabilities: %s", error); return false; } @@ -213,29 +222,29 @@ bool clearColorTest() swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB; // rare but possible on andriod - if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { - swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; + if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { + swapchainCreateInfo.width = surfaceCaps.maxImageWidth / 2; } - if (WINDOW_HEIGHT > swapchainCaps.maxImageHeight) { - swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; + if (WINDOW_HEIGHT > surfaceCaps.maxImageHeight) { + swapchainCreateInfo.height = surfaceCaps.maxImageHeight / 2; } // check if the minimal image count is not good for you // and increase it but not pass the max count - swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; + swapchainCreateInfo.imageCount = surfaceCaps.minImageCount; if (swapchainCreateInfo.imageCount == 1) { swapchainCreateInfo.imageCount++; - if (swapchainCaps.maxImageCount < 2) { - palLog(nullptr, "Swapchain does not support double buffers"); + if (surfaceCaps.maxImageCount < 2) { + palLog(nullptr, "Surface does not support double buffers"); return false; } } - result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); + result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); @@ -543,6 +552,7 @@ bool clearColorTest() palDestroyCommandPool(cmdPool); palDestroySwapchain(swapchain); + palDestroySurface(surface); palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); diff --git a/tests/mesh_test.c b/tests/mesh_test.c index b86d781f..12ae16d1 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -61,6 +61,7 @@ bool meshTest() PalAdapter* adapter = nullptr; PalDevice* device = nullptr; + PalSurface* surface = nullptr; PalQueue* queue = nullptr; PalSwapchain* swapchain = nullptr; PalCommandPool* cmdPool = nullptr; @@ -243,18 +244,26 @@ bool meshTest() return false; } - if (!palCanQueuePresent(queue, &gfxWindow)) { - palLog(nullptr, "Queue cannot present to window"); + // create surface + result = palCreateSurface(device, &gfxWindow, &surface); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create surface: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palLog(nullptr, "Queue cannot present to surface"); return false; } // create a swapchain with the graphics queue - PalSwapchainCapabilities swapchainCaps = {0}; - result = palQuerySwapchainCapabilities(device, &gfxWindow, &swapchainCaps); + PalSurfaceCapabilities surfaceCaps = {0}; + result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query swapchain capabilities: %s", error); + palLog(nullptr, "Failed to get surface capabilities: %s", error); return false; } @@ -265,36 +274,29 @@ bool meshTest() swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { - // the format is not supported. we default to BGRA - // if component mapping is not supported, we have to remap the component - // from the shader rather instead of mapping when creating the image views - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; - } + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB; // rare but possible on andriod - if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { - swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; + if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { + swapchainCreateInfo.width = surfaceCaps.maxImageWidth / 2; } - if (WINDOW_HEIGHT > swapchainCaps.maxImageHeight) { - swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; + if (WINDOW_HEIGHT > surfaceCaps.maxImageHeight) { + swapchainCreateInfo.height = surfaceCaps.maxImageHeight / 2; } // check if the minimal image count is not good for you // and increase it but not pass the max count - swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; + swapchainCreateInfo.imageCount = surfaceCaps.minImageCount; if (swapchainCreateInfo.imageCount == 1) { - swapchainCreateInfo.imageCount = 2; - if (swapchainCaps.maxImageCount < 2) { - palLog(nullptr, "Swapchain does not support double buffers"); + swapchainCreateInfo.imageCount++; + if (surfaceCaps.maxImageCount < 2) { + palLog(nullptr, "Surface does not support double buffers"); return false; } } - result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); + result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); @@ -792,6 +794,7 @@ bool meshTest() } palDestroyCommandPool(cmdPool); + palDestroySurface(surface); palDestroySwapchain(swapchain); palDestroyQueue(queue); palDestroyDevice(device); diff --git a/tests/texture_test.c b/tests/texture_test.c index 8604d65f..8916168e 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -91,6 +91,7 @@ bool textureTest() PalAdapter* adapter = nullptr; PalDevice* device = nullptr; + PalSurface* surface = nullptr; PalQueue* queue = nullptr; PalSwapchain* swapchain = nullptr; PalCommandPool* cmdPool = nullptr; @@ -271,17 +272,25 @@ bool textureTest() return false; } - if (!palCanQueuePresent(queue, &gfxWindow)) { - palLog(nullptr, "Queue cannot present to window"); + // create surface + result = palCreateSurface(device, &gfxWindow, &surface); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create surface: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palLog(nullptr, "Queue cannot present to surface"); return false; } // create a swapchain with the graphics queue - PalSwapchainCapabilities swapchainCaps = {0}; - result = palQuerySwapchainCapabilities(device, &gfxWindow, &swapchainCaps); + PalSurfaceCapabilities surfaceCaps = {0}; + result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query swapchain capabilities: %s", error); + palLog(nullptr, "Failed to get surface capabilities: %s", error); return false; } @@ -292,36 +301,29 @@ bool textureTest() swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { - // the format is not supported. we default to BGRA - // if component mapping is not supported, we have to remap the component - // from the shader rather instead of mapping when creating the image views - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; - } + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB; // rare but possible on andriod - if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { - swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; + if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { + swapchainCreateInfo.width = surfaceCaps.maxImageWidth / 2; } - if (WINDOW_HEIGHT > swapchainCaps.maxImageHeight) { - swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; + if (WINDOW_HEIGHT > surfaceCaps.maxImageHeight) { + swapchainCreateInfo.height = surfaceCaps.maxImageHeight / 2; } // check if the minimal image count is not good for you // and increase it but not pass the max count - swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; + swapchainCreateInfo.imageCount = surfaceCaps.minImageCount; if (swapchainCreateInfo.imageCount == 1) { - swapchainCreateInfo.imageCount = 2; - if (swapchainCaps.maxImageCount < 2) { - palLog(nullptr, "Swapchain does not support double buffers"); + swapchainCreateInfo.imageCount++; + if (surfaceCaps.maxImageCount < 2) { + palLog(nullptr, "Surface does not support double buffers"); return false; } } - result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); + result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); @@ -1370,6 +1372,7 @@ bool textureTest() palFreeMemory(device, vertexBufferMemory); palDestroyCommandPool(cmdPool); + palDestroySurface(surface); palDestroySwapchain(swapchain); palDestroyQueue(queue); palDestroyDevice(device); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 6b01d91c..24ea5ecd 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -61,6 +61,7 @@ bool triangleTest() PalAdapter* adapter = nullptr; PalDevice* device = nullptr; + PalSurface* surface = nullptr; PalQueue* queue = nullptr; PalSwapchain* swapchain = nullptr; PalCommandPool* cmdPool = nullptr; @@ -238,17 +239,25 @@ bool triangleTest() return false; } - if (!palCanQueuePresent(queue, &gfxWindow)) { - palLog(nullptr, "Queue cannot present to window"); + // create surface + result = palCreateSurface(device, &gfxWindow, &surface); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create surface: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palLog(nullptr, "Queue cannot present to surface"); return false; } // create a swapchain with the graphics queue - PalSwapchainCapabilities swapchainCaps = {0}; - result = palQuerySwapchainCapabilities(device, &gfxWindow, &swapchainCaps); + PalSurfaceCapabilities surfaceCaps = {0}; + result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query swapchain capabilities: %s", error); + palLog(nullptr, "Failed to get surface capabilities: %s", error); return false; } @@ -259,35 +268,29 @@ bool triangleTest() swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - - // swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB; - swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; - // if (!swapchainCaps.formats[PAL_SWAPCHAIN_FORMAT_RGBA8_UNORM_SRGB]) { - // // the format is not supported. We default to BGRA - // swapchainCreateInfo.format = PAL_SWAPCHAIN_FORMAT_BGRA8_UNORM_SRGB; - // } + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB; // rare but possible on andriod - if (WINDOW_WIDTH > swapchainCaps.maxImageWidth) { - swapchainCreateInfo.width = swapchainCaps.maxImageWidth / 2; + if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { + swapchainCreateInfo.width = surfaceCaps.maxImageWidth / 2; } - if (WINDOW_HEIGHT > swapchainCaps.maxImageHeight) { - swapchainCreateInfo.height = swapchainCaps.maxImageHeight / 2; + if (WINDOW_HEIGHT > surfaceCaps.maxImageHeight) { + swapchainCreateInfo.height = surfaceCaps.maxImageHeight / 2; } // check if the minimal image count is not good for you // and increase it but not pass the max count - swapchainCreateInfo.imageCount = swapchainCaps.minImageCount; + swapchainCreateInfo.imageCount = surfaceCaps.minImageCount; if (swapchainCreateInfo.imageCount == 1) { - swapchainCreateInfo.imageCount = 3; - if (swapchainCaps.maxImageCount < 3) { - palLog(nullptr, "Swapchain does not support the required buffers"); + swapchainCreateInfo.imageCount++; + if (surfaceCaps.maxImageCount < 2) { + palLog(nullptr, "Surface does not support double buffers"); return false; } } - result = palCreateSwapchain(device, queue, &gfxWindow, &swapchainCreateInfo, &swapchain); + result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); @@ -970,6 +973,7 @@ bool triangleTest() palFreeMemory(device, vertexBufferMemory); palDestroyCommandPool(cmdPool); + palDestroySurface(surface); palDestroySwapchain(swapchain); palDestroyQueue(queue); palDestroyDevice(device); From b86cd7ab46b12fa49381d918342193034a654755 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 27 Mar 2026 20:48:12 +0000 Subject: [PATCH 124/372] fix all graphics test --- tests/mesh_test.c | 145 ++++++++++++++++++---------------------- tests/texture_test.c | 153 ++++++++++++++++++++----------------------- 2 files changed, 137 insertions(+), 161 deletions(-) diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 12ae16d1..54566372 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -68,9 +68,10 @@ bool meshTest() PalImageView** imageViews = nullptr; PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* presentCompleteSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore** renderFinishedSemaphores; // count of swapchain images + PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -99,7 +100,7 @@ bool meshTest() windowCreateInfo.height = WINDOW_HEIGHT; windowCreateInfo.width = WINDOW_WIDTH; windowCreateInfo.show = true; - windowCreateInfo.title = "Clear Color Window"; + windowCreateInfo.title = "Mesh Window"; PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { @@ -306,9 +307,8 @@ bool meshTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); - - if (!imageViews || !renderFinishedSemaphores) { + inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); + if (!imageViews || !inFlightImages) { palLog(nullptr, "Failed to allocate memory"); return false; } @@ -335,6 +335,8 @@ bool meshTest() palLog(nullptr, "Failed to create image view: %s", error); return false; } + + inFlightImages[i] = nullptr; } result = palCreateCommandPool(device, queue, &cmdPool); @@ -346,7 +348,14 @@ bool meshTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); + result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -373,16 +382,6 @@ bool meshTest() } } - // create synchronization objects - for (int i = 0; i < imageCount; i++) { - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - } - // create shaders Uint64 bytecodeSize = 0; void* bytecode = nullptr; @@ -489,11 +488,6 @@ bool meshTest() pipelineCreateInfo.colorBlendAttachments = &blendAttachment; pipelineCreateInfo.colorBlendAttachmentCount = 1; - // multisample state - PalMultisampleState multisampleState = {0}; - multisampleState.sampleCount = PAL_SAMPLE_COUNT_1; - pipelineCreateInfo.multisampleState = &multisampleState; - // shaders PalShader* shaders[2]; shaders[0] = meshShader; @@ -518,13 +512,6 @@ bool meshTest() // main loop Uint32 currentFrame = 0; bool running = true; - PalSemaphore* presentCompleteSemaphore = nullptr; - PalSemaphore* renderFinishedSemaphore = nullptr; - PalFence* fence = nullptr; - PalCommandBuffer* cmdBuffer = nullptr; - - bool firstImageViewUse[8]; - memset(firstImageViewUse, 1, sizeof(bool) * 8); // we are not resizing for the viewport and scissor will not change PalViewport viewport = {0}; @@ -559,19 +546,39 @@ bool meshTest() } } - fence = inFlightFences[currentFrame]; - presentCompleteSemaphore = presentCompleteSemaphores[currentFrame]; - cmdBuffer = cmdBuffers[currentFrame]; - - result = palWaitFence(fence, UINT64_MAX); + result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); return false; } + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; + nextImageInfo.timeout = PAL_INFINITE; + + Uint32 imageIndex = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + if (inFlightImages[imageIndex] != nullptr) { + result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + inFlightImages[imageIndex] = inFlightFences[currentFrame]; if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { - result = palResetFence(fence); + result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); @@ -580,9 +587,9 @@ bool meshTest() } else { // recreate since we dont support fence resetting - palDestroyFence(fence); + palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, false, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); @@ -590,31 +597,15 @@ bool meshTest() } } - // get next swapchain image - PalSwapchainNextImageInfo nextImageInfo = {0}; - nextImageInfo.fence = nullptr; - nextImageInfo.signalSemaphore = presentCompleteSemaphore; - nextImageInfo.timeout = UINT64_MAX; - - Uint32 index = 0; - result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &index); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; - } - - renderFinishedSemaphore = renderFinishedSemaphores[index]; - // reset the command buffer - result = palResetCommandBuffer(cmdBuffer); + result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); return false; } - result = palCmdBegin(cmdBuffer, nullptr); + result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); @@ -626,21 +617,15 @@ bool meshTest() PalUsageStateInfo newUsageStateInfo = {0}; newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; - if (firstImageViewUse[index]) { - oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - } else { - oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - } - PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; imageRange.mipLevelCount = 1; imageRange.startArrayLayer = 0; imageRange.startMipLevel = 0; - PalImage* image = palGetSwapchainImage(swapchain, index); + PalImage* image = palGetSwapchainImage(swapchain, imageIndex); result = palCmdImageBarrier( - cmdBuffer, + cmdBuffers[currentFrame], image, &imageRange, &oldUsageStateInfo, @@ -662,7 +647,7 @@ bool meshTest() colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; colorAttachment.storeOp = PAL_STORE_OP_STORE; colorAttachment.clearValue = clearValue; - colorAttachment.imageView = imageViews[index]; + colorAttachment.imageView = imageViews[imageIndex]; PalRenderingInfo renderingInfo = {0}; renderingInfo.viewCount = 1; @@ -673,7 +658,7 @@ bool meshTest() renderingInfo.renderArea.width = WINDOW_WIDTH; renderingInfo.renderArea.height = WINDOW_HEIGHT; - result = palCmdBeginRendering(cmdBuffer, &renderingInfo); + result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); @@ -681,7 +666,7 @@ bool meshTest() } // bind pipeline - result = palCmdBindPipeline(cmdBuffer, pipeline); + result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); @@ -689,14 +674,14 @@ bool meshTest() } // set viewport and scissors - result = palCmdSetViewport(cmdBuffer, 1, &viewport); + result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); return false; } - result = palCmdSetScissors(cmdBuffer, 1, &scissor); + result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); @@ -707,14 +692,14 @@ bool meshTest() // palBuildWorkGroupInfo() is a helper to build // the workgroup count per axis using normal // workCount (image size, buffer size) - result = palCmdDrawMeshTasks(cmdBuffer, 1, 1, 1); + result = palCmdDrawMeshTasks(cmdBuffers[currentFrame], 1, 1, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); return false; } - result = palCmdEndRendering(cmdBuffer); + result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); @@ -725,7 +710,7 @@ bool meshTest() oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( - cmdBuffer, + cmdBuffers[currentFrame], image, &imageRange, &oldUsageStateInfo, @@ -737,7 +722,7 @@ bool meshTest() return false; } - result = palCmdEnd(cmdBuffer); + result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); @@ -746,10 +731,10 @@ bool meshTest() // submit command buffer PalCommandBufferSubmitInfo submitInfo = {0}; - submitInfo.cmdBuffer = cmdBuffer; - submitInfo.fence = fence; - submitInfo.waitSemaphore = presentCompleteSemaphore; - submitInfo.signalSemaphore = renderFinishedSemaphore; + submitInfo.cmdBuffer = cmdBuffers[currentFrame]; + submitInfo.fence = inFlightFences[currentFrame]; + submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -760,8 +745,8 @@ bool meshTest() // present PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = index; - presentInfo.waitSemaphore = renderFinishedSemaphore; + presentInfo.imageIndex = imageIndex; + presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -783,14 +768,14 @@ bool meshTest() palDestroyPipelineLayout(pipelineLayout); for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - palDestroySemaphore(presentCompleteSemaphores[i]); + palDestroySemaphore(imageAvailableSemaphores[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); palDestroyFence(inFlightFences[i]); palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { palDestroyImageView(imageViews[i]); - palDestroySemaphore(renderFinishedSemaphores[i]); } palDestroyCommandPool(cmdPool); diff --git a/tests/texture_test.c b/tests/texture_test.c index 8916168e..4c4a1d62 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -98,9 +98,10 @@ bool textureTest() PalImageView** imageViews = nullptr; PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* presentCompleteSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore** renderFinishedSemaphores; // count of swapchain images + PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -333,9 +334,8 @@ bool textureTest() // get all swapchain images and create image views for them Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); - - if (!imageViews || !renderFinishedSemaphores) { + inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); + if (!imageViews || !inFlightImages) { palLog(nullptr, "Failed to allocate memory"); return false; } @@ -362,6 +362,8 @@ bool textureTest() palLog(nullptr, "Failed to create image view: %s", error); return false; } + + inFlightImages[i] = nullptr; } result = palCreateCommandPool(device, queue, &cmdPool); @@ -373,7 +375,14 @@ bool textureTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &presentCompleteSemaphores[i]); + result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -400,16 +409,6 @@ bool textureTest() } } - // create synchronization objects - for (int i = 0; i < imageCount; i++) { - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - } - // create vertex and staging buffer // clang-format off float vertices[] = { @@ -1027,11 +1026,6 @@ bool textureTest() pipelineCreateInfo.colorBlendAttachments = &blendAttachment; pipelineCreateInfo.colorBlendAttachmentCount = 1; - // multisample state - PalMultisampleState multisampleState = {0}; - multisampleState.sampleCount = PAL_SAMPLE_COUNT_1; - pipelineCreateInfo.multisampleState = &multisampleState; - // shaders PalShader* shaders[2]; shaders[0] = vertexShader; @@ -1073,13 +1067,6 @@ bool textureTest() // main loop Uint32 currentFrame = 0; bool running = true; - PalSemaphore* presentCompleteSemaphore = nullptr; - PalSemaphore* renderFinishedSemaphore = nullptr; - fence = nullptr; - PalCommandBuffer* cmdBuffer = nullptr; - - bool firstImageViewUse[8]; - memset(firstImageViewUse, 1, sizeof(bool) * 8); // we are not resizing for the viewport and scissor will not change PalViewport viewport = {0}; @@ -1114,19 +1101,39 @@ bool textureTest() } } - fence = inFlightFences[currentFrame]; - presentCompleteSemaphore = presentCompleteSemaphores[currentFrame]; - cmdBuffer = cmdBuffers[currentFrame]; - - result = palWaitFence(fence, UINT64_MAX); + result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); return false; } + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; + nextImageInfo.timeout = PAL_INFINITE; + + Uint32 imageIndex = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + if (inFlightImages[imageIndex] != nullptr) { + result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + inFlightImages[imageIndex] = inFlightFences[currentFrame]; if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { - result = palResetFence(fence); + result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); @@ -1135,9 +1142,9 @@ bool textureTest() } else { // recreate since we dont support fence resetting - palDestroyFence(fence); + palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, false, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); @@ -1145,31 +1152,15 @@ bool textureTest() } } - // get next swapchain image - PalSwapchainNextImageInfo nextImageInfo = {0}; - nextImageInfo.fence = nullptr; - nextImageInfo.signalSemaphore = presentCompleteSemaphore; - nextImageInfo.timeout = UINT64_MAX; - - Uint32 index = 0; - result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &index); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; - } - - renderFinishedSemaphore = renderFinishedSemaphores[index]; - // reset the command buffer - result = palResetCommandBuffer(cmdBuffer); + result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); return false; } - result = palCmdBegin(cmdBuffer, nullptr); + result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); @@ -1181,21 +1172,15 @@ bool textureTest() PalUsageStateInfo newUsageStateInfo = {0}; newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; - if (firstImageViewUse[index]) { - oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - } else { - oldUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - } - PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; imageRange.mipLevelCount = 1; imageRange.startArrayLayer = 0; imageRange.startMipLevel = 0; - PalImage* image = palGetSwapchainImage(swapchain, index); + PalImage* image = palGetSwapchainImage(swapchain, imageIndex); result = palCmdImageBarrier( - cmdBuffer, + cmdBuffers[currentFrame], image, &imageRange, &oldUsageStateInfo, @@ -1217,7 +1202,7 @@ bool textureTest() colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; colorAttachment.storeOp = PAL_STORE_OP_STORE; colorAttachment.clearValue = clearValue; - colorAttachment.imageView = imageViews[index]; + colorAttachment.imageView = imageViews[imageIndex]; PalRenderingInfo renderingInfo = {0}; renderingInfo.viewCount = 1; @@ -1228,7 +1213,7 @@ bool textureTest() renderingInfo.renderArea.width = WINDOW_WIDTH; renderingInfo.renderArea.height = WINDOW_HEIGHT; - result = palCmdBeginRendering(cmdBuffer, &renderingInfo); + result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); @@ -1236,14 +1221,20 @@ bool textureTest() } // bind pipeline - result = palCmdBindPipeline(cmdBuffer, pipeline); + result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); return false; } - result = palCmdBindDescriptorSet(cmdBuffer, pipeline, pipelineLayout, 0, descriptorSet); + result = palCmdBindDescriptorSet( + cmdBuffers[currentFrame], + pipeline, + pipelineLayout, + 0, + descriptorSet); + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); @@ -1251,14 +1242,14 @@ bool textureTest() } // set viewport and scissors - result = palCmdSetViewport(cmdBuffer, 1, &viewport); + result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); return false; } - result = palCmdSetScissors(cmdBuffer, 1, &scissor); + result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); @@ -1267,21 +1258,21 @@ bool textureTest() // bind vertex buffer Uint64 offset[] = {0}; - result = palCmdBindVertexBuffers(cmdBuffer, 0, 1, &vertexBuffer, offset); + result = palCmdBindVertexBuffers(cmdBuffers[currentFrame], 0, 1, &vertexBuffer, offset); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind vertex buffer: %s", error); return false; } - result = palCmdDraw(cmdBuffer, 6, 1, 0, 0); + result = palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); return false; } - result = palCmdEndRendering(cmdBuffer); + result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); @@ -1292,7 +1283,7 @@ bool textureTest() oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( - cmdBuffer, + cmdBuffers[currentFrame], image, &imageRange, &oldUsageStateInfo, @@ -1304,7 +1295,7 @@ bool textureTest() return false; } - result = palCmdEnd(cmdBuffer); + result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); @@ -1313,10 +1304,10 @@ bool textureTest() // submit command buffer PalCommandBufferSubmitInfo submitInfo = {0}; - submitInfo.cmdBuffer = cmdBuffer; - submitInfo.fence = fence; - submitInfo.waitSemaphore = presentCompleteSemaphore; - submitInfo.signalSemaphore = renderFinishedSemaphore; + submitInfo.cmdBuffer = cmdBuffers[currentFrame]; + submitInfo.fence = inFlightFences[currentFrame]; + submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -1327,8 +1318,8 @@ bool textureTest() // present PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = index; - presentInfo.waitSemaphore = renderFinishedSemaphore; + presentInfo.imageIndex = imageIndex; + presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -1350,14 +1341,14 @@ bool textureTest() palDestroyPipelineLayout(pipelineLayout); for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - palDestroySemaphore(presentCompleteSemaphores[i]); + palDestroySemaphore(imageAvailableSemaphores[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); palDestroyFence(inFlightFences[i]); palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { palDestroyImageView(imageViews[i]); - palDestroySemaphore(renderFinishedSemaphores[i]); } palDestroyDescriptorPool(descriptorPool); From 838c3070396f4b375a499174abbad3fed38ab54f Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 27 Mar 2026 22:32:00 +0000 Subject: [PATCH 125/372] improve queue detection on vulkan --- include/pal/pal_graphics.h | 6 ++- src/graphics/pal_vulkan.c | 84 ++++++++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 53cf998b..e99b8828 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -4202,8 +4202,10 @@ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( * PalAdapterCapabilities::maxComputeQueues, PalAdapterCapabilities::maxGraphicsQueues and * PalAdapterCapabilities::maxCopyQueues respectively for the limit for each queue type. * Creating more queues than the supported will fail and return `PAL_RESULT_OUT_OF_QUEUE`. - * - * On most adapters, compute and graphics queues can also do copy operations. + * + * Not all graphics queues support presentation. Create a graphics queue and then check if + * its support presentation for the provided surface. see palCanQueuePresent(). Any graphics + * queue supports offscreen rendering. * * @param[in] device Device that creates the queue. * @param[in] type Queue type. (eg. PAL_QUEUE_TYPE_GRAPHICS). diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index d586985c..d4237982 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -368,7 +368,9 @@ typedef struct { bool bindlessStorageBuffers; bool bindlessUniformBuffers; PalAdapterFeatures features; - Int32 queueCount; + Int32 phyQueueCount; + Int32 phyQueueIndex; + Int32 queueFamilyCount; Uint32 memoryClassMask[3]; VkPhysicalDevice phyDevice; VkDevice handle; @@ -3571,7 +3573,8 @@ PalResult PAL_CALL createDeviceVk( PalDevice** outDevice) { float priority = 1.0f; - Uint32 queueCount = 0; + Uint32 phyQueueCount = 0; + Uint32 queueFamilyCount = 0; VkResult result = VK_SUCCESS; Device* device = nullptr; VkPhysicalDeviceProperties props = {0}; @@ -3580,34 +3583,38 @@ PalResult PAL_CALL createDeviceVk( VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; s_Vk.getPhysicalDeviceProperties(phyDevice, &props); - VkQueueFamilyProperties* queueProps = nullptr; + VkQueueFamilyProperties* queueFamilyProps = nullptr; VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; - s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueCount, nullptr); + s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueFamilyCount, nullptr); + + Uint32 queueFamilySize = sizeof(VkQueueFamilyProperties) * queueFamilyCount; + Uint32 queueCreateInfosSize = sizeof(VkDeviceQueueCreateInfo) * queueFamilyCount; - queueProps = palAllocate(s_Vk.allocator, sizeof(VkQueueFamilyProperties) * queueCount, 0); - queueCreateInfos = palAllocate(s_Vk.allocator, sizeof(VkDeviceQueueCreateInfo) * queueCount, 0); + queueFamilyProps = palAllocate(s_Vk.allocator, queueFamilySize, 0); + queueCreateInfos = palAllocate(s_Vk.allocator, queueCreateInfosSize, 0); device = palAllocate(s_Vk.allocator, sizeof(Device), 0); - if (!queueProps || !queueCreateInfos || !device) { + if (!queueFamilyProps || !queueCreateInfos || !device) { return PAL_RESULT_OUT_OF_MEMORY; } memset(device, 0, sizeof(Device)); - device->queueCount = queueCount; device->phyDevice = phyDevice; - - device->phyQueues = palAllocate(s_Vk.allocator, sizeof(PhysicalQueue) * queueCount, 0); - if (!device->phyQueues) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueCount, queueProps); - for (int i = 0; i < queueCount; i++) { + s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueFamilyCount, queueFamilyProps); + for (int i = 0; i < queueFamilyCount; i++) { queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfos[i].pNext = nullptr; queueCreateInfos[i].pQueuePriorities = &priority; queueCreateInfos[i].queueFamilyIndex = i; - queueCreateInfos[i].queueCount = queueProps[i].queueCount; + queueCreateInfos[i].queueCount = queueFamilyProps[i].queueCount; queueCreateInfos[i].flags = 0; + + // we need the total number of physical queues + phyQueueCount += queueFamilyProps[i].queueCount; + } + + device->phyQueues = palAllocate(s_Vk.allocator, sizeof(PhysicalQueue) * phyQueueCount, 0); + if (!device->phyQueues) { + return PAL_RESULT_OUT_OF_MEMORY; } // build features and extensions capabilities @@ -3879,22 +3886,26 @@ PalResult PAL_CALL createDeviceVk( createInfo.enabledExtensionCount = extCount; createInfo.ppEnabledExtensionNames = extensions; createInfo.pQueueCreateInfos = queueCreateInfos; - createInfo.queueCreateInfoCount = queueCount; + createInfo.queueCreateInfoCount = queueFamilyCount; createInfo.pNext = next; result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.vkAllocator, &device->handle); if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, queueProps); + palFree(s_Vk.allocator, queueFamilyProps); palFree(s_Vk.allocator, queueCreateInfos); palFree(s_Vk.allocator, device->phyQueues); palFree(s_Vk.allocator, device); return resultFromVk(result); } + device->phyQueueIndex = 0; + device->queueFamilyCount = queueFamilyCount; + device->phyQueueCount = phyQueueCount; device->features = features; + // get queues - for (int i = 0; i < queueCount; i++) { - VkQueueFamilyProperties* data = &queueProps[i]; + for (int i = 0; i < queueFamilyCount; i++) { + VkQueueFamilyProperties* data = &queueFamilyProps[i]; for (int j = 0; j < data->queueCount; j++) { PhysicalQueue* queue = &device->phyQueues[i]; s_Vk.getDeviceQueue(device->handle, i, j, &queue->handle); @@ -4260,7 +4271,7 @@ PalResult PAL_CALL createDeviceVk( // clang-format on - palFree(s_Vk.allocator, queueProps); + palFree(s_Vk.allocator, queueFamilyProps); palFree(s_Vk.allocator, queueCreateInfos); *outDevice = (PalDevice*)device; @@ -4609,7 +4620,7 @@ PalResult PAL_CALL createQueueVk( return PAL_RESULT_INVALID_DEVICE; } - if (vkDevice->queueCount == 0) { + if (vkDevice->phyQueueCount == 0) { return PAL_RESULT_OUT_OF_QUEUE; } @@ -4630,8 +4641,10 @@ PalResult PAL_CALL createQueueVk( } } + // we index the for loop so we dont always start at the beginning, this way + // we cycle through all queue families each time we create a queue PhysicalQueue* phyQueue = nullptr; - for (int i = 0; i < vkDevice->queueCount; i++) { + for (int i = vkDevice->phyQueueIndex; i < vkDevice->phyQueueCount; i++) { PhysicalQueue* pq = &vkDevice->phyQueues[i]; // check if the physical queue supports the requested operation // and if its not already used @@ -4643,7 +4656,27 @@ PalResult PAL_CALL createQueueVk( } if (!phyQueue) { - return PAL_RESULT_OUT_OF_QUEUE; + // we didnt get any queue, we check if we started the loop at the beginning or mid way + if (vkDevice->phyQueueIndex == 0) { + // we searched all queue families + return PAL_RESULT_OUT_OF_QUEUE; + + } else { + // we start at the beginning and go through the queue families again + vkDevice->phyQueueIndex = 0; + for (int i = vkDevice->phyQueueIndex; i < vkDevice->phyQueueCount; i++) { + PhysicalQueue* pq = &vkDevice->phyQueues[i]; + if (pq->usages & queueFlag && pq->usedUsages != queueFlag) { + pq->usedUsages |= queueFlag; + phyQueue = pq; + break; + } + } + + if (!phyQueue) { + return PAL_RESULT_OUT_OF_QUEUE; + } + } } queue = palAllocate(s_Vk.allocator, sizeof(Queue), 0); @@ -4651,6 +4684,7 @@ PalResult PAL_CALL createQueueVk( return PAL_RESULT_OUT_OF_MEMORY; } + vkDevice->phyQueueIndex = (vkDevice->phyQueueIndex + 1) % vkDevice->phyQueueCount; queue->phyQueue = phyQueue; queue->usage = queueFlag; queue->device = vkDevice; From f71b38c2a68c71d2800b73d7464a334486b86f67 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 28 Mar 2026 00:57:15 +0000 Subject: [PATCH 126/372] add shader binding table API --- include/pal/pal_graphics.h | 126 +++++++++++++++++++++++- src/graphics/pal_graphics.c | 93 +++++++++++++++--- src/graphics/pal_vulkan.c | 184 ++++++++++++++++++++---------------- tests/compute_test.c | 5 +- tests/mesh_test.c | 5 +- tests/ray_tracing_test.c | 23 ++++- tests/tests_main.c | 12 +-- tests/texture_test.c | 7 +- tests/triangle_test.c | 5 +- 9 files changed, 347 insertions(+), 113 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index e99b8828..f62b6723 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -238,6 +238,15 @@ typedef struct PalPipelineLayout PalPipelineLayout; */ typedef struct PalPipeline PalPipeline; +/** + * @struct PalShaderBindingTable + * @brief Opaque handle to a shader binding table. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct PalShaderBindingTable PalShaderBindingTable; + /** * @struct PalAccelerationStructure * @brief Opaque handle to an acceleration structure. @@ -1338,6 +1347,22 @@ typedef enum { PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT } PalRayTracingShaderGroupType; +/** + * @enum PalPipelineBindPoint + * @brief Binding point for pipeline and pipeline layouts. + * + * All pipeline bind points follow the format `PAL_PIPELINE_BIND_POINT_**` + * for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_PIPELINE_BIND_POINT_GRAPHICS, + PAL_PIPELINE_BIND_POINT_COMPUTE, + PAL_PIPELINE_BIND_POINT_RAY_TRACING +} PalPipelineBindPoint; + /** * @struct PalAdapterInfo * @brief Information about an adapter (GPU). @@ -2547,6 +2572,23 @@ typedef struct { PalShader** shaders; /**< Array of shader stage. This is used by `shaderGroups`.*/ } PalRayTracingPipelineCreateInfo; +/** + * @struct PalShaderBindingTableCreateInfo + * @brief Creation parameters for a shader binding table. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 raygenGroupCount; + Uint32 missGroupCount; + Uint32 hitGroupCount; + Uint32 callableGroupCount; + PalPipeline* rayTracingPipeline; +} PalShaderBindingTableCreateInfo; + /** * @struct PalGraphicsBackend * @brief Dispatch table for PAL graphics system backends. @@ -3238,6 +3280,7 @@ typedef struct { */ PalResult PAL_CALL (*cmdBindPipeline)( PalCommandBuffer* cmdBuffer, + PalPipelineBindPoint bindPoint, PalPipeline* pipeline); /** @@ -3435,6 +3478,8 @@ typedef struct { */ PalResult PAL_CALL (*cmdTraceRays)( PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + Uint32 raygenIndex, Uint32 width, Uint32 height, Uint32 depth); @@ -3446,6 +3491,8 @@ typedef struct { */ PalResult PAL_CALL (*cmdTraceRaysIndirect)( PalCommandBuffer* cmdBuffer, + Uint32 raygenIndex, + PalShaderBindingTable* sbt, PalDeviceAddress bufferAddress); /** @@ -3455,7 +3502,7 @@ typedef struct { */ PalResult PAL_CALL (*cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline, + PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set); @@ -3738,6 +3785,23 @@ typedef struct { * Must obey the rules and semantics documented in palDestroyPipeline(). */ void PAL_CALL (*destroyPipeline)(PalPipeline* pipeline); + + /** + * Backend implementation of ::palCreateShaderBindingTable. + * + * Must obey the rules and semantics documented in palCreateShaderBindingTable(). + */ + PalResult PAL_CALL (*createShaderBindingTable)( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + + /** + * Backend implementation of ::palDestroyShaderBindingTable. + * + * Must obey the rules and semantics documented in palDestroyShaderBindingTable(). + */ + void PAL_CALL (*destroyShaderBindingTable)(PalShaderBindingTable* sbt); } PalGraphicsBackend; /** @@ -5555,6 +5619,7 @@ PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( * set at the respective creation functions. (`palCreate**Graphics/Compute/RayTracing**Pipeline`). * * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] bindPoint The Binding point. Must match pipeline type. * @param[in] pipeline Pipeline to bind. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -5567,6 +5632,7 @@ PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( */ PAL_API PalResult PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, + PalPipelineBindPoint bindPoint, PalPipeline* pipeline); /** @@ -6055,6 +6121,8 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] sbt The shader binding table to use. + * @param[in] raygenIndex Index of the raygen shader to execute. * @param[in] width Number of rays to trace on the x axis. * @param[in] height Number of rays to trace on the y axis. * @param[in] depth Number of rays to trace on the z axis. @@ -6069,6 +6137,8 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( */ PAL_API PalResult PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + Uint32 raygenIndex, Uint32 width, Uint32 height, Uint32 depth); @@ -6083,6 +6153,8 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] raygenIndex Index of the raygen shader to execute. + * @param[in] sbt The shader binding table to use. * @param[in] bufferAddress Buffer address of buffer containing an array of * PalDispatchIndirectData structs. Can be a single struct. * @@ -6096,6 +6168,8 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( */ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, + Uint32 raygenIndex, + PalShaderBindingTable* sbt, PalDeviceAddress bufferAddress); /** @@ -6104,7 +6178,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] pipeline Pipeline to associate the descriptor set to. + * @param[in] bindPoint The Binding point. * @param[in] layout The pipeline layout that defines the descriptor interface. * @param[in] setIndex Index of the descriptor set to bind. * @param[in] set Descriptor set to bind. Must be compatible with `layout`. @@ -6119,7 +6193,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( */ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline, + PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set); @@ -6840,6 +6914,52 @@ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( */ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); +/** + * @brief Create a shader binding table. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device that creates the shader binding table. + * @param[in] info Pointer to a PalShaderBindingTableCreateInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outSbt Pointer to a PalShaderBindingTable to recieve the created shader binding + * table. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palDestroyShaderBindingTable + */ +PAL_API PalResult PAL_CALL palCreateShaderBindingTable( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + +/** + * @brief Destroy a shader binding table. + * + * The graphics system must be initialized before this call. + * If the provided shader binding table is invalid or nullptr, this function returns + * silently. + * + * @param[in] sbt Shader binding table to destroy. + * + * Thread safety: Thread safe if the device used to create the shader binding table is + * externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palCreateShaderBindingTable + */ +PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); + /** * @brief Build work group info(s) from work inputs specified in pixels, vertices etc. * diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 979903b9..6e4dfc64 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -58,6 +58,7 @@ PAL_HANDLE(PalDescriptorPool) PAL_HANDLE(PalDescriptorSet) PAL_HANDLE(PalSampler) PAL_HANDLE(PalSurface) +PAL_HANDLE(PalShaderBindingTable) typedef struct { Int32 count; @@ -394,6 +395,7 @@ PalResult PAL_CALL cmdCopyImageToBufferVk( PalResult PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, + PalPipelineBindPoint bindPoint, PalPipeline* pipeline); PalResult PAL_CALL cmdSetViewportVk( @@ -506,17 +508,21 @@ PalResult PAL_CALL cmdDispatchIndirectVk( PalResult PAL_CALL cmdTraceRaysVk( PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + Uint32 raygenIndex, Uint32 width, Uint32 height, Uint32 depth); PalResult PAL_CALL cmdTraceRaysIndirectVk( PalCommandBuffer* cmdBuffer, + Uint32 raygenIndex, + PalShaderBindingTable* sbt, PalDeviceAddress bufferAddress); PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline, + PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set); @@ -663,6 +669,13 @@ PalResult PAL_CALL createRayTracingPipelineVk( void PAL_CALL destroyPipelineVk(PalPipeline* pipeline); +PalResult PAL_CALL createShaderBindingTableVk( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + +void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt); + static PalGraphicsBackend s_VkBackend = { // adapter .enumerateAdapters = enumerateAdaptersVk, @@ -828,7 +841,11 @@ static PalGraphicsBackend s_VkBackend = { .createGraphicsPipeline = createGraphicsPipelineVk, .createComputePipeline = createComputePipelineVk, .createRayTracingPipeline = createRayTracingPipelineVk, - .destroyPipeline = destroyPipelineVk}; + .destroyPipeline = destroyPipelineVk, + + // shader binding table + .createShaderBindingTable = createShaderBindingTableVk, + .destroyShaderBindingTable = destroyShaderBindingTableVk}; #endif // PAL_HAS_VULKAN @@ -1028,7 +1045,11 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->createGraphicsPipeline || !backend->createComputePipeline || !backend->createRayTracingPipeline || - !backend->destroyPipeline) { + !backend->destroyPipeline || + + // shader binding table + !backend->createShaderBindingTable || + !backend->destroyShaderBindingTable) { return PAL_RESULT_INVALID_BACKEND; } // clang-format on @@ -2320,6 +2341,7 @@ PalResult PAL_CALL palCmdCopyImageToBuffer( PalResult PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, + PalPipelineBindPoint bindPoint, PalPipeline* pipeline) { if (!s_Graphics.initialized) { @@ -2330,7 +2352,7 @@ PalResult PAL_CALL palCmdBindPipeline( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdBindPipeline(cmdBuffer, pipeline); + return cmdBuffer->backend->cmdBindPipeline(cmdBuffer, bindPoint, pipeline); } PalResult PAL_CALL palCmdSetViewport( @@ -2653,6 +2675,8 @@ PalResult PAL_CALL palCmdDispatchIndirect( PalResult PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + Uint32 raygenIndex, Uint32 width, Uint32 height, Uint32 depth) @@ -2661,31 +2685,33 @@ PalResult PAL_CALL palCmdTraceRays( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer) { + if (!cmdBuffer || !sbt) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdTraceRays(cmdBuffer, width, height, depth); + return cmdBuffer->backend->cmdTraceRays(cmdBuffer, sbt, raygenIndex, width, height, depth); } PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, + Uint32 raygenIndex, + PalShaderBindingTable* sbt, PalDeviceAddress bufferAddress) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer) { + if (!cmdBuffer || !sbt) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdTraceRaysIndirect(cmdBuffer, bufferAddress); + return cmdBuffer->backend->cmdTraceRaysIndirect(cmdBuffer, raygenIndex, sbt, bufferAddress); } PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline, + PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set) @@ -2694,11 +2720,16 @@ PalResult PAL_CALL palCmdBindDescriptorSet( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !pipeline || !layout || !set) { + if (!cmdBuffer || !layout || !set) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdBindDescriptorSet(cmdBuffer, pipeline, layout, setIndex, set); + return cmdBuffer->backend->cmdBindDescriptorSet( + cmdBuffer, + bindPoint, + layout, + setIndex, + set); } PalResult PAL_CALL palCmdPushConstants( @@ -3264,6 +3295,46 @@ void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) } } +// ================================================== +// Shader Binding Table +// ================================================== + +PalResult PAL_CALL palCreateShaderBindingTable( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !info || !outSbt) { + return PAL_RESULT_NULL_POINTER; + } + + if (!info->rayTracingPipeline) { + return PAL_RESULT_NULL_POINTER; + } + + PalResult result; + PalShaderBindingTable* sbt = nullptr; + result = device->backend->createShaderBindingTable(device, info, &sbt); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + sbt->backend = device->backend; + *outSbt = sbt; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt) +{ + if (s_Graphics.initialized && sbt) { + sbt->backend->destroyShaderBindingTable(sbt); + } +} + // ================================================== // Utils // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index d4237982..593d98f4 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -493,6 +493,9 @@ typedef struct { } CommandPool; typedef struct { + const PalGraphicsBackend* backend; + + Device* device; VkBuffer buffer; VkDeviceMemory bufferMemory; VkDeviceAddress baseAddress; @@ -507,11 +510,9 @@ typedef struct { const PalGraphicsBackend* backend; bool primary; - VkPipelineStageFlagBits2 dstStage; Device* device; CommandPool* pool; VkCommandBuffer handle; - ShaderBindingTable* sbt; } CommandBuffer; typedef struct { @@ -587,10 +588,8 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - VkPipelineBindPoint bindPoint; Device* device; VkPipeline handle; - ShaderBindingTable* sbt; } Pipeline; typedef struct { @@ -6156,7 +6155,6 @@ PalResult PAL_CALL allocateCommandBufferVk( cmdBuffer->device = vkDevice; cmdBuffer->pool = vkPool; - cmdBuffer->sbt = nullptr; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; @@ -6178,8 +6176,6 @@ PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); - vkCmdBuffer->sbt = nullptr; - vkCmdBuffer->dstStage = 0; return PAL_RESULT_SUCCESS; } @@ -6193,20 +6189,14 @@ PalResult PAL_CALL submitCommandBufferVk( VkFence fenceHandle = nullptr; VkSemaphore waitSemaphoreHandle = nullptr; VkSemaphore signalSemaphoreHandle = nullptr; - VkPipelineStageFlagBits2 dstStage = 0; Queue* vkQueue = (Queue*)queue; CommandBuffer* vkCmdBuffer = (CommandBuffer*)info->cmdBuffer; PhysicalQueue* phyQueue = vkQueue->phyQueue; - if (vkCmdBuffer->sbt) { - vkCmdBuffer->dstStage |= VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; - } - if (info->waitSemaphore) { Semaphore* tmp = (Semaphore*)info->waitSemaphore; waitSemaphoreHandle = tmp->handle; waitSemaphoreCount = 1; - dstStage = vkCmdBuffer->dstStage; } if (info->signalSemaphore) { @@ -6227,7 +6217,7 @@ PalResult PAL_CALL submitCommandBufferVk( VkSemaphoreSubmitInfoKHR waitSubmitInfo = {0}; waitSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; waitSubmitInfo.semaphore = waitSemaphoreHandle; - waitSubmitInfo.stageMask = dstStage; + waitSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; VkSemaphoreSubmitInfoKHR signalSubmitInfo = {0}; signalSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; @@ -6851,16 +6841,21 @@ PalResult PAL_CALL cmdCopyImageToBufferVk( PalResult PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, + PalPipelineBindPoint bindPoint, PalPipeline* pipeline) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* vkPipeline = (Pipeline*)pipeline; - s_Vk.cmdBindPipeline(vkCmdBuffer->handle, vkPipeline->bindPoint, vkPipeline->handle); - if (vkPipeline->bindPoint == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) { - vkCmdBuffer->sbt = vkPipeline->sbt; + VkPipelineBindPoint point = VK_PIPELINE_BIND_POINT_GRAPHICS; + if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { + point = VK_PIPELINE_BIND_POINT_COMPUTE; + + } else if (bindPoint == PAL_PIPELINE_BIND_POINT_RAY_TRACING) { + point = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; } + s_Vk.cmdBindPipeline(vkCmdBuffer->handle, point, vkPipeline->handle); return PAL_RESULT_SUCCESS; } @@ -7256,28 +7251,29 @@ PalResult PAL_CALL cmdDispatchIndirectVk( PalResult PAL_CALL cmdTraceRaysVk( PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + Uint32 raygenIndex, Uint32 width, Uint32 height, Uint32 depth) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = vkCmdBuffer->device; + ShaderBindingTable* vkSbt = (ShaderBindingTable*)sbt; if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - ShaderBindingTable* sbt = vkCmdBuffer->sbt; - if (!sbt) { - return PAL_RESULT_INVALID_OPERATION; - } + PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygenAddress.stride; + vkSbt->raygenAddress.deviceAddress = address; vkCmdBuffer->device->cmdTraceRays( vkCmdBuffer->handle, - &sbt->raygenAddress, - &sbt->missAddress, - &sbt->hitAddress, - &sbt->callableAddress, + &vkSbt->raygenAddress, + &vkSbt->missAddress, + &vkSbt->hitAddress, + &vkSbt->callableAddress, width, height, depth); @@ -7287,24 +7283,26 @@ PalResult PAL_CALL cmdTraceRaysVk( PalResult PAL_CALL cmdTraceRaysIndirectVk( PalCommandBuffer* cmdBuffer, + Uint32 raygenIndex, + PalShaderBindingTable* sbt, PalDeviceAddress bufferAddress) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + ShaderBindingTable* vkSbt = (ShaderBindingTable*)sbt; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - ShaderBindingTable* sbt = vkCmdBuffer->sbt; - if (!sbt) { - return PAL_RESULT_INVALID_OPERATION; - } + PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygenAddress.stride; + vkSbt->raygenAddress.deviceAddress = address; vkCmdBuffer->device->cmdTraceRaysIndirect( vkCmdBuffer->handle, - &sbt->raygenAddress, - &sbt->missAddress, - &sbt->hitAddress, - &sbt->callableAddress, + &vkSbt->raygenAddress, + &vkSbt->missAddress, + &vkSbt->hitAddress, + &vkSbt->callableAddress, bufferAddress); return PAL_RESULT_SUCCESS; @@ -7312,19 +7310,26 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline, + PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Pipeline* vkPipeline = (Pipeline*)pipeline; PipelineLayout* vkLayout = (PipelineLayout*)layout; DescriptorSet* vkSet = (DescriptorSet*)set; + VkPipelineBindPoint point = VK_PIPELINE_BIND_POINT_GRAPHICS; + if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { + point = VK_PIPELINE_BIND_POINT_COMPUTE; + + } else if (bindPoint == PAL_PIPELINE_BIND_POINT_RAY_TRACING) { + point = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; + } + s_Vk.cmdBindDescriptorSets( vkCmdBuffer->handle, - vkPipeline->bindPoint, + point, vkLayout->handle, setIndex, 1, @@ -8581,8 +8586,6 @@ PalResult PAL_CALL createGraphicsPipelineVk( } pipeline->device = vkDevice; - pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - pipeline->sbt = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -8621,8 +8624,6 @@ PalResult PAL_CALL createComputePipelineVk( } pipeline->device = vkDevice; - pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; - pipeline->sbt = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -8638,7 +8639,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( Pipeline* pipeline = nullptr; VkPipelineShaderStageCreateInfo shaderStages[6]; // 6 shader types for ray tracing pipeline VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; - ShaderBindingTable* sbt = nullptr; Uint32 groupSize = sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { @@ -8649,16 +8649,13 @@ PalResult PAL_CALL createRayTracingPipelineVk( createInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); - sbt = palAllocate(s_Vk.allocator, sizeof(ShaderBindingTable), 0); groups = palAllocate(s_Vk.allocator, groupSize, 0); - if (!pipeline || !groups || !sbt) { + if (!pipeline || !groups) { return PAL_RESULT_OUT_OF_MEMORY; } - memset(groups, 0, sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount); - memset(sbt, 0, sizeof(ShaderBindingTable)); - // shaders + memset(groups, 0, sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; shaderStages[i] = tmp->info; @@ -8723,7 +8720,43 @@ PalResult PAL_CALL createRayTracingPipelineVk( palFree(s_Vk.allocator, groups); return resultFromVk(result); } + palFree(s_Vk.allocator, groups); + pipeline->device = vkDevice; + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) +{ + Pipeline* vkPipeline = (Pipeline*)pipeline; + s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, pipeline); +} + +// ================================================== +// Shader Binding Table +// ================================================== + +PalResult PAL_CALL createShaderBindingTableVk( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt) +{ + VkResult result; + Device* vkDevice = (Device*)device; + ShaderBindingTable* sbt = nullptr; + Pipeline* pipeline = (Pipeline*)info->rayTracingPipeline; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + sbt = palAllocate(s_Vk.allocator, sizeof(ShaderBindingTable), 0); + if (!sbt) { + return PAL_RESULT_OUT_OF_MEMORY; + } // create SBT buffer VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayProps = {0}; @@ -8740,10 +8773,10 @@ PalResult PAL_CALL createRayTracingPipelineVk( Uint32 stride = alignVk(groupHandleSize, groupHandleAlignment); // get region size - Uint32 raygenRegionSize = stride * numRaygen; - Uint32 missRegionSize = stride * numMiss; - Uint32 hitRegionSize = stride * numHit; - Uint32 callableRegionSize = stride * numCallable; + Uint32 raygenRegionSize = stride * info->raygenGroupCount; + Uint32 missRegionSize = stride * info->missGroupCount; + Uint32 hitRegionSize = stride * info->hitGroupCount; + Uint32 callableRegionSize = stride * info->callableGroupCount; // get alignVked region size Uint32 raygenAlignedRegionSize = alignVk(raygenRegionSize, groupBaseAlignment); @@ -8768,7 +8801,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); return resultFromVk(result); } @@ -8797,18 +8829,17 @@ PalResult PAL_CALL createRayTracingPipelineVk( &sbt->bufferMemory); if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); return resultFromVk(result); } s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); // get shader handles - Uint32 totalGroups = numRaygen + numHit + numMiss + numCallable; + Uint32 totalGroups = info->raygenGroupCount + info->hitGroupCount; + totalGroups += info->missGroupCount + info->callableGroupCount; Uint32 sbtSize = totalGroups * groupHandleSize; Uint8* handles = palAllocate(s_Vk.allocator, sbtSize, 0); if (!handles) { - palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); return PAL_RESULT_OUT_OF_MEMORY; } @@ -8822,7 +8853,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( handles); if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); return resultFromVk(result); } @@ -8831,7 +8861,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( void* ptr = nullptr; result = s_Vk.mapMemory(vkDevice->handle, sbt->bufferMemory, 0, memReq.size, 0, &ptr); if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); palFree(s_Vk.allocator, sbt); return resultFromVk(result); } @@ -8840,26 +8869,28 @@ PalResult PAL_CALL createRayTracingPipelineVk( Uint8* srcPtr = handles; // raygen - memcpy(dstPtr, handles, groupHandleSize); - srcPtr += numRaygen * groupHandleSize; + for (int i = 0; i < info->raygenGroupCount; i++) { + memcpy(dstPtr + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); + } + srcPtr += info->raygenGroupCount * groupHandleSize; // miss - for (int i = 0; i < numMiss; i++) { + for (int i = 0; i < info->missGroupCount; i++) { memcpy(dstPtr + missOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); } - srcPtr += numMiss * groupHandleSize; + srcPtr += info->missGroupCount * groupHandleSize; // hit - for (int i = 0; i < numHit; i++) { + for (int i = 0; i < info->hitGroupCount; i++) { memcpy(dstPtr + hitOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); } - srcPtr += numHit * groupHandleSize; + srcPtr += info->hitGroupCount * groupHandleSize; // callable - for (int i = 0; i < numCallable; i++) { + for (int i = 0; i < info->callableGroupCount; i++) { memcpy(dstPtr + callableOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); } - srcPtr += numCallable * groupHandleSize; + srcPtr += info->callableGroupCount * groupHandleSize; s_Vk.unmapMemory(vkDevice->handle, sbt->bufferMemory); @@ -8890,28 +8921,19 @@ PalResult PAL_CALL createRayTracingPipelineVk( sbt->callableAddress.stride = stride; palFree(s_Vk.allocator, handles); - pipeline->device = vkDevice; - pipeline->sbt = sbt; - pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; - *outPipeline = (PalPipeline*)pipeline; + sbt->device = vkDevice; + *outSbt = (PalShaderBindingTable*)sbt; return PAL_RESULT_SUCCESS; } -void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) +void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt) { - Pipeline* vkPipeline = (Pipeline*)pipeline; - s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); + ShaderBindingTable* vkSbt = (ShaderBindingTable*)sbt; + Device* device = vkSbt->device; - if (vkPipeline->sbt) { - VkDevice device = vkPipeline->device->handle; - ShaderBindingTable* sbt = vkPipeline->sbt; - - s_Vk.destroyBuffer(device, sbt->buffer, &s_Vk.vkAllocator); - s_Vk.freeMemory(device, sbt->bufferMemory, &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, vkPipeline->sbt); - } - palFree(s_Vk.allocator, pipeline); + s_Vk.destroyBuffer(device->handle, vkSbt->buffer, &s_Vk.vkAllocator); + s_Vk.freeMemory(device->handle, vkSbt->bufferMemory, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkSbt); } #endif // PAL_HAS_VULKAN diff --git a/tests/compute_test.c b/tests/compute_test.c index 30d27645..4761c2e6 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -444,7 +444,8 @@ bool computeTest() pushConstant.color[2] = 0.0f; pushConstant.color[3] = 1.0f; - result = palCmdBindPipeline(cmdBuffer, pipeline); + PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_COMPUTE; + result = palCmdBindPipeline(cmdBuffer, bindPoint, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); @@ -466,7 +467,7 @@ bool computeTest() return false; } - result = palCmdBindDescriptorSet(cmdBuffer, pipeline, pipelineLayout, 0, descriptorSet); + result = palCmdBindDescriptorSet(cmdBuffer, bindPoint, pipelineLayout, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 54566372..9d765ec9 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -666,7 +666,8 @@ bool meshTest() } // bind pipeline - result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_GRAPHICS; + result = palCmdBindPipeline(cmdBuffers[currentFrame], bindPoint, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); @@ -779,8 +780,8 @@ bool meshTest() } palDestroyCommandPool(cmdPool); - palDestroySurface(surface); palDestroySwapchain(swapchain); + palDestroySurface(surface); palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 39b8f081..023b93e0 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -83,6 +83,7 @@ bool rayTracingTest() PalPipeline* pipeline = nullptr; PalFence* fence = nullptr; + PalShaderBindingTable* sbt = nullptr; PalAccelerationStructure* blas = nullptr; PalAccelerationStructure* tlas = nullptr; @@ -871,6 +872,20 @@ bool rayTracingTest() return false; } + // create shader binding table + PalShaderBindingTableCreateInfo sbtCreateInfo = {0}; + sbtCreateInfo.rayTracingPipeline = pipeline; + sbtCreateInfo.raygenGroupCount = 1; + sbtCreateInfo.missGroupCount = 1; + sbtCreateInfo.hitGroupCount = 1; + + result = palCreateShaderBindingTable(device, &sbtCreateInfo, &sbt); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create shader binding table: %s", error); + return false; + } + // create fence result = palCreateFence(device, false, &fence); if (result != PAL_RESULT_SUCCESS) { @@ -887,14 +902,15 @@ bool rayTracingTest() return false; } - result = palCmdBindPipeline(cmdBuffer, pipeline); + PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_RAY_TRACING; + result = palCmdBindPipeline(cmdBuffer, bindPoint, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); return false; } - result = palCmdBindDescriptorSet(cmdBuffer, pipeline, pipelineLayout, 0, descriptorSet); + result = palCmdBindDescriptorSet(cmdBuffer, bindPoint, pipelineLayout, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); @@ -968,7 +984,7 @@ bool rayTracingTest() return false; } - result = palCmdTraceRays(cmdBuffer, BUFFER_SIZE, BUFFER_SIZE, 1); + result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to trace rays: %s", error); @@ -1074,6 +1090,7 @@ bool rayTracingTest() palDestroyFence(fence); palDestroyPipeline(pipeline); + palDestroyShaderBindingTable(sbt); palDestroyPipelineLayout(pipelineLayout); palDestroyDescriptorPool(descriptorPool); palDestroyDescriptorSetLayout(descriptorSetLayout); diff --git a/tests/tests_main.c b/tests/tests_main.c index 6520e5f5..d7e9a0d3 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,16 +57,16 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest); - // registerTest(computeTest); - // registerTest(rayTracingTest); + registerTest(graphicsTest); + registerTest(computeTest); + registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest(clearColorTest); + registerTest(clearColorTest); registerTest(triangleTest); - // registerTest(meshTest); - // registerTest(textureTest); + registerTest(meshTest); + registerTest(textureTest); #endif // runTests(); diff --git a/tests/texture_test.c b/tests/texture_test.c index 4c4a1d62..7fd216a5 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -1221,7 +1221,8 @@ bool textureTest() } // bind pipeline - result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_GRAPHICS; + result = palCmdBindPipeline(cmdBuffers[currentFrame], bindPoint, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); @@ -1230,7 +1231,7 @@ bool textureTest() result = palCmdBindDescriptorSet( cmdBuffers[currentFrame], - pipeline, + bindPoint, pipelineLayout, 0, descriptorSet); @@ -1363,8 +1364,8 @@ bool textureTest() palFreeMemory(device, vertexBufferMemory); palDestroyCommandPool(cmdPool); - palDestroySurface(surface); palDestroySwapchain(swapchain); + palDestroySurface(surface); palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 24ea5ecd..c05ef133 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -852,7 +852,8 @@ bool triangleTest() } // bind pipeline - result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_GRAPHICS; + result = palCmdBindPipeline(cmdBuffers[currentFrame], bindPoint, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); @@ -973,8 +974,8 @@ bool triangleTest() palFreeMemory(device, vertexBufferMemory); palDestroyCommandPool(cmdPool); - palDestroySurface(surface); palDestroySwapchain(swapchain); + palDestroySurface(surface); palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); From 8266c4b126c534aca54060c054b2d3dd5570f449 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 28 Mar 2026 20:19:16 +0000 Subject: [PATCH 127/372] improve barrier commands --- include/pal/pal_graphics.h | 3 +- src/graphics/pal_vulkan.c | 139 ++++++++++++++++++------------------- tests/compute_test.c | 14 ++-- tests/ray_tracing_test.c | 21 ++---- tests/texture_test.c | 13 ++-- tests/triangle_test.c | 5 +- 6 files changed, 91 insertions(+), 104 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index f62b6723..831cac85 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1631,8 +1631,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + Uint32 shaderStageCount; PalUsageState usageState; - PalShaderStage shaderStage; + PalShaderStage* shaderStages; } PalUsageStateInfo; /** diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 593d98f4..87af0497 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1751,24 +1751,21 @@ static VkPipelineStageFlags2 pipelineStageToVk(PalShaderStage stage) } static Barrier barrierToVk( + Uint32 stageCount, PalUsageState state, - PalShaderStage shaderStage) + PalShaderStage* shaderStages) { Barrier barrier = {0}; switch (state) { case PAL_USAGE_STATE_UNDEFINED: { barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; - barrier.dstStages = barrier.stages; - barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_PRESENT: { - barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; - barrier.dstStages = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; - + barrier.stages = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; return barrier; @@ -1776,8 +1773,6 @@ static Barrier barrierToVk( case PAL_USAGE_STATE_COLOR_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; - barrier.dstStages = barrier.stages; - barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; return barrier; @@ -1785,8 +1780,6 @@ static Barrier barrierToVk( case PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; - barrier.dstStages = barrier.stages; - barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; return barrier; @@ -1794,72 +1787,59 @@ static Barrier barrierToVk( case PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.dstStages = barrier.stages; - + barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; return barrier; } case PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE: { - barrier.stages = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; - barrier.dstStages = barrier.stages; - + barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; + barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; return barrier; } case PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.dstStages = barrier.stages; - + barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; + barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; return barrier; } case PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE: { - barrier.stages = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; - barrier.dstStages = barrier.stages; - + barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; + barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; + barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; return barrier; } case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ: { barrier.stages = VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; - barrier.dstStages = barrier.stages; - barrier.access = VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; - VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; return barrier; } - case PAL_USAGE_STATE_TRANSFER_WRITE: { + case PAL_USAGE_STATE_TRANSFER_READ: { barrier.stages = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; - barrier.dstStages = barrier.stages; - - barrier.access = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.access = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; return barrier; } - case PAL_USAGE_STATE_TRANSFER_READ: { + case PAL_USAGE_STATE_TRANSFER_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; - barrier.dstStages = barrier.stages; - - barrier.access = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.access = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; return barrier; } case PAL_USAGE_STATE_VERTEX_READ: { barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR; - barrier.dstStages = barrier.stages; - barrier.access = VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1867,25 +1847,25 @@ static Barrier barrierToVk( case PAL_USAGE_STATE_INDEX_READ: { barrier.stages = VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR; - barrier.dstStages = barrier.stages; - barrier.access = VK_ACCESS_2_INDEX_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_UNIFORM_READ: { - barrier.stages = pipelineStageToVk(shaderStage); - barrier.dstStages = barrier.stages; - + for (int i = 0; i < stageCount; i++) { + barrier.stages |= pipelineStageToVk(shaderStages[i]); + } + barrier.access = VK_ACCESS_2_UNIFORM_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_SHADER_READ: { - barrier.stages = pipelineStageToVk(shaderStage); - barrier.dstStages = barrier.stages; + for (int i = 0; i < stageCount; i++) { + barrier.stages |= pipelineStageToVk(shaderStages[i]); + } barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -1893,26 +1873,29 @@ static Barrier barrierToVk( } case PAL_USAGE_STATE_SHADER_WRITE: { - barrier.stages = pipelineStageToVk(shaderStage); - barrier.dstStages = barrier.stages; + for (int i = 0; i < stageCount; i++) { + barrier.stages |= pipelineStageToVk(shaderStages[i]); + } - barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; + barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_GENERAL; return barrier; } case PAL_USAGE_STATE_STORAGE_READ: { - barrier.stages = pipelineStageToVk(shaderStage); - barrier.dstStages = barrier.stages; + for (int i = 0; i < stageCount; i++) { + barrier.stages |= pipelineStageToVk(shaderStages[i]); + } barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.layout = VK_IMAGE_LAYOUT_GENERAL; return barrier; } case PAL_USAGE_STATE_STORAGE_WRITE: { - barrier.stages = pipelineStageToVk(shaderStage); - barrier.dstStages = barrier.stages; + for (int i = 0; i < stageCount; i++) { + barrier.stages |= pipelineStageToVk(shaderStages[i]); + } barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_GENERAL; @@ -1921,8 +1904,6 @@ static Barrier barrierToVk( case PAL_USAGE_STATE_HOST_READ: { barrier.stages = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; - barrier.dstStages = barrier.stages; - barrier.access = VK_ACCESS_2_HOST_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1930,17 +1911,17 @@ static Barrier barrierToVk( case PAL_USAGE_STATE_HOST_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; - barrier.dstStages = barrier.stages; - barrier.access = VK_ACCESS_2_HOST_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; - barrier.dstStages = barrier.stages; + for (int i = 0; i < stageCount; i++) { + barrier.stages |= pipelineStageToVk(shaderStages[i]); + } + barrier.stages |= VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1948,8 +1929,6 @@ static Barrier barrierToVk( case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; - barrier.dstStages = barrier.stages; - barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -1957,11 +1936,8 @@ static Barrier barrierToVk( } barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; - barrier.dstStages = barrier.stages; - barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; } @@ -7107,8 +7083,15 @@ PalResult PAL_CALL cmdMemoryBarrierVk( barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR; Barrier old, new; - old = barrierToVk(oldUsageStateInfo->usageState, oldUsageStateInfo->shaderStage); - new = barrierToVk(newUsageStateInfo->usageState, newUsageStateInfo->shaderStage); + old = barrierToVk( + oldUsageStateInfo->shaderStageCount, + oldUsageStateInfo->usageState, + oldUsageStateInfo->shaderStages); + + new = barrierToVk( + newUsageStateInfo->shaderStageCount, + newUsageStateInfo->usageState, + newUsageStateInfo->shaderStages); barrier.srcStageMask = old.stages; barrier.srcAccessMask = old.access; @@ -7138,8 +7121,15 @@ PalResult PAL_CALL cmdImageBarrierVk( barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR; Barrier old, new; - old = barrierToVk(oldUsageStateInfo->usageState, oldUsageStateInfo->shaderStage); - new = barrierToVk(newUsageStateInfo->usageState, newUsageStateInfo->shaderStage); + old = barrierToVk( + oldUsageStateInfo->shaderStageCount, + oldUsageStateInfo->usageState, + oldUsageStateInfo->shaderStages); + + new = barrierToVk( + newUsageStateInfo->shaderStageCount, + newUsageStateInfo->usageState, + newUsageStateInfo->shaderStages); barrier.srcStageMask = old.stages; barrier.srcAccessMask = old.access; @@ -7177,8 +7167,15 @@ PalResult PAL_CALL cmdBufferBarrierVk( barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; Barrier old, new; - old = barrierToVk(oldUsageStateInfo->usageState, oldUsageStateInfo->shaderStage); - new = barrierToVk(newUsageStateInfo->usageState, newUsageStateInfo->shaderStage); + old = barrierToVk( + oldUsageStateInfo->shaderStageCount, + oldUsageStateInfo->usageState, + oldUsageStateInfo->shaderStages); + + new = barrierToVk( + newUsageStateInfo->shaderStageCount, + newUsageStateInfo->usageState, + newUsageStateInfo->shaderStages); barrier.srcStageMask = old.stages; barrier.srcAccessMask = old.access; diff --git a/tests/compute_test.c b/tests/compute_test.c index 4761c2e6..cb863328 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -509,11 +509,9 @@ bool computeTest() // set a barrier on the buffer PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_COMPUTE; + newUsageStateInfo.shaderStageCount = 1; + newUsageStateInfo.shaderStages = shaderStages; newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); @@ -544,7 +542,8 @@ bool computeTest() // set a barrier so we only read from the buffer after the shader has // written to it oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + newUsageStateInfo.shaderStageCount = 0; + newUsageStateInfo.shaderStages = nullptr; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); @@ -556,9 +555,8 @@ bool computeTest() // set a barrier on the staging buffer oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; - - newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + oldUsageStateInfo.shaderStageCount = 0; + oldUsageStateInfo.shaderStages = nullptr; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; result = palCmdBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 023b93e0..0b43e495 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -919,11 +919,9 @@ bool rayTracingTest() // set a barrier on the buffer PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_RAYGEN; + newUsageStateInfo.shaderStageCount = 1; + newUsageStateInfo.shaderStages = shaderStages; newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); @@ -950,11 +948,9 @@ bool rayTracingTest() // make sure the BLAS builds before the TLAS PalUsageStateInfo oldAsUsageStateInfo = {0}; - oldAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; oldAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; PalUsageStateInfo newAsUsageStateInfo = {0}; - newAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; newAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; result = palCmdMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); @@ -972,11 +968,6 @@ bool rayTracingTest() } // make sure the TLAS builds before the tracing - oldAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; - oldAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; - newAsUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; - newAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; - result = palCmdMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -994,7 +985,8 @@ bool rayTracingTest() // set a barrier so we only read from the buffer after the shader has // written to it oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; + newUsageStateInfo.shaderStageCount = 0; + newUsageStateInfo.shaderStages = nullptr; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); @@ -1005,10 +997,9 @@ bool rayTracingTest() } // set a barrier on the staging buffer + oldUsageStateInfo.shaderStageCount = 0; + oldUsageStateInfo.shaderStages = nullptr; oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; - - newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; result = palCmdBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); diff --git a/tests/texture_test.c b/tests/texture_test.c index 7fd216a5..21876903 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -658,12 +658,13 @@ bool textureTest() return false; } + PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_VERTEX; + newUsageStateInfo.shaderStageCount = 1; + newUsageStateInfo.shaderStages = vertexShaderStage; newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); @@ -676,12 +677,8 @@ bool textureTest() // copy image staging buffer to the checkerboard image // first the image must be in the correct layout PalUsageStateInfo oldImageUsageState = {0}; - oldImageUsageState.usageState = PAL_USAGE_STATE_UNDEFINED; - oldImageUsageState.shaderStage = PAL_SHADER_STAGE_UNDEFINED; - PalUsageStateInfo newImageUsageState = {0}; newImageUsageState.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - newImageUsageState.shaderStage = PAL_SHADER_STAGE_UNDEFINED; // set a barrier on the image to transition it into transfer dst state PalImageSubresourceRange checkerboardRange = {0}; @@ -723,9 +720,11 @@ bool textureTest() // we should transition the image into a shader read state so we dont do that // in the main loop + PalShaderStage fragmentShaderStage[] = { PAL_SHADER_STAGE_FRAGMENT }; oldImageUsageState = newImageUsageState; newImageUsageState.usageState = PAL_USAGE_STATE_SHADER_READ; - newImageUsageState.shaderStage = PAL_SHADER_STAGE_FRAGMENT; // fragment shader will read + newImageUsageState.shaderStageCount = 1; + newImageUsageState.shaderStages = fragmentShaderStage; // fragment shader will read result = palCmdImageBarrier( cmdBuffers[0], diff --git a/tests/triangle_test.c b/tests/triangle_test.c index c05ef133..c87a6f80 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -505,12 +505,13 @@ bool triangleTest() return false; } + PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.shaderStage = PAL_SHADER_STAGE_UNDEFINED; oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStage = PAL_SHADER_STAGE_VERTEX; + newUsageStateInfo.shaderStageCount = 1; + newUsageStateInfo.shaderStages = vertexShaderStage; newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); From 83f8316c38ce6f95f11ab696180d18a086086c2b Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 29 Mar 2026 04:52:50 +0100 Subject: [PATCH 128/372] start d3d12 graphics backend --- pal.lua | 46 +- premake5.lua | 3 +- src/graphics/pal_d3d12.c | 705 +++++++++++++++++++++ src/graphics/pal_graphics.c | 1165 +++++++++++++++++++++++++++++++---- 4 files changed, 1805 insertions(+), 114 deletions(-) create mode 100644 src/graphics/pal_d3d12.c diff --git a/pal.lua b/pal.lua index 8599ce7a..8a40ee92 100644 --- a/pal.lua +++ b/pal.lua @@ -149,8 +149,8 @@ project "PAL" if (PAL_BUILD_GRAPHICS) then -- check for vulkan support. This is cross compiler - vulkan_sdk = os.getenv("VULKAN_SDK") - hasVulkan = false + local vulkan_sdk = os.getenv("VULKAN_SDK") + local hasVulkan = false if (vulkan_sdk) then hasVulkan = true -- add to include path if compiler does not see it @@ -158,24 +158,56 @@ project "PAL" path.join(vulkan_sdk, "include") } - libdirs { - path.join(vulkan_sdk, "Lib") - } - defines { "PAL_HAS_VULKAN=1" } else defines { "PAL_HAS_VULKAN=0" } end + -- check for d3d12 support. This is cross compiler + local hasD3D12 = false + local d3d12_include = os.getenv("D3D12_INCLUDE") + if (os.isfile(path.join(d3d12_include, "d3d12.h"))) then + hasD3D12 = true + + else + if (_ACTION == "vs2022") then + local sdkDir = os.getenv("WindowsSdkDir") + local sdkVer = os.getenv("WindowsSDKVersion") + if (sdkDir and sdkVer) then + d3d12_include = path.join(sdkDir, "Include", sdkVer, "um") + end + else + d3d12_include = path.join(ucrt, "include") + end + + if (os.isfile(path.join(d3d12_include, "d3d12.h"))) then + hasD3D12 = true + end + end + + if (hasD3D12) then + -- add to include path if compiler does not see it + includedirs { + d3d12_include + } + + defines { "PAL_HAS_D3D12=1" } + else + defines { "PAL_HAS_D3D12=0" } + end + -- base graphics file files { "src/graphics/pal_graphics.c" } filter {"system:windows", "configurations:*"} - -- files { "src/graphics/pal_d3d12.c" } if (hasVulkan) then files { "src/graphics/pal_vulkan.c" } end + if (hasD3D12) then + files { "src/graphics/pal_d3d12.c" } + end + filter {"system:linux", "configurations:*"} if (hasVulkan) then files { "src/graphics/pal_vulkan.c" } diff --git a/premake5.lua b/premake5.lua index 07574536..38ce9f91 100644 --- a/premake5.lua +++ b/premake5.lua @@ -3,8 +3,7 @@ dofile("pal_config.lua") target_dir = "%{wks.location}/bin/%{cfg.buildcfg}" obj_dir = "%{wks.location}/build" - -local ucrt = os.getenv("UCRT64") or "C:/msys64/ucrt64" +ucrt = os.getenv("UCRT64") or "C:/msys64/ucrt64" newoption { trigger = "compiler", diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c new file mode 100644 index 00000000..92abb052 --- /dev/null +++ b/src/graphics/pal_d3d12.c @@ -0,0 +1,705 @@ + +/** + +Copyright (C) 2025-2026 Nicholas Agbo + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + + */ + +// ================================================== +// Includes +// ================================================== + +#include "pal/pal_graphics.h" + +#if PAL_HAS_D3D12 + +// ================================================== +// Typedefs, enums and structs +// ================================================== + +// ================================================== +// Helper Functions +// ================================================== + +// ================================================== +// Adapter +// ================================================== + +PalResult PAL_CALL initGraphicsD3D12( + const PalGraphicsDebugger* debugger, + const PalAllocator* allocator); + +void PAL_CALL shutdownGraphicsD3D12(); + +PalResult PAL_CALL enumerateAdaptersD3D12( + Int32* count, + PalAdapter** outAdapters); + +PalResult PAL_CALL getAdapterInfoD3D12( + PalAdapter* adapter, + PalAdapterInfo* info); + +PalResult PAL_CALL getAdapterCapabilitiesD3D12( + PalAdapter* adapter, + PalAdapterCapabilities* caps); + +PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); + +// ================================================== +// Device +// ================================================== + +PalResult PAL_CALL createDeviceD3D12( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); + +void PAL_CALL destroyDeviceD3D12(PalDevice* device); + +PalResult PAL_CALL waitDeviceD3D12(PalDevice* device); + +// ================================================== +// Memory +// ================================================== + +PalResult PAL_CALL allocateMemoryD3D12( + PalDevice* device, + PalMemoryType type, + Uint64 memoryMask, + Uint64 size, + PalMemory** outMemory); + +void PAL_CALL freeMemoryD3D12( + PalDevice* device, + PalMemory* memory); + +PalResult PAL_CALL mapMemoryD3D12( + PalDevice* device, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr); + +void PAL_CALL unmapMemoryD3D12( + PalDevice* device, + PalMemory* memory); + +// ================================================== +// Extended Adapter Features +// ================================================== + +PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( + PalDevice* device, + PalDepthStencilCapabilities* caps); + +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); + +PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( + PalDevice* device, + PalMeshShaderCapabilities* caps); + +PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( + PalDevice* device, + PalRayTracingCapabilities* caps); + +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); + +// ================================================== +// Queue +// ================================================== + +PalResult PAL_CALL createQueueD3D12( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); + +void PAL_CALL destroyQueueD3D12(PalQueue* queue); + +PalResult PAL_CALL waitQueueD3D12(PalQueue* queue); + +bool PAL_CALL canQueuePresentD3D12( + PalQueue* queue, + PalSurface* surface); + +// ================================================== +// Formats +// ================================================== + +PalResult PAL_CALL enumerateFormatsD3D12( + PalAdapter* adapter, + Int32* count, + PalFormatInfo* outFormats); + +bool PAL_CALL isFormatSupportedD3D12( + PalAdapter* adapter, + PalFormat format); + +PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( + PalAdapter* adapter, + PalFormat format); + +PalImageViewUsages PAL_CALL queryFormatImageViewUsagesD3D12( + PalAdapter* adapter, + PalFormat format); + +// ================================================== +// Image +// ================================================== + +PalResult PAL_CALL createImageD3D12( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + +void PAL_CALL destroyImageD3D12(PalImage* image); + +PalResult PAL_CALL getImageInfoD3D12( + PalImage* image, + PalImageInfo* info); + +PalResult PAL_CALL getImageMemoryRequirementsD3D12( + PalImage* image, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL bindImageMemoryD3D12( + PalImage* image, + PalMemory* memory, + Uint64 offset); + +// ================================================== +// Image View +// ================================================== + +PalResult PAL_CALL createImageViewD3D12( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + +void PAL_CALL destroyImageViewD3D12(PalImageView* imageView); + +// ================================================== +// Sampler +// ================================================== + +PalResult PAL_CALL createSamplerD3D12( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler); + +void PAL_CALL destroySamplerD3D12(PalSampler* sampler); + +// ================================================== +// Surface +// ================================================== + +PalResult PAL_CALL createSurfaceD3D12( + PalDevice* device, + PalGraphicsWindow* window, + PalSurface** outSurface); + +void PAL_CALL destroySurfaceD3D12(PalSurface* surface); + +PalResult PAL_CALL getSurfaceCapabilitiesD3D12( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps); + +// ================================================== +// Swapchain +// ================================================== + +PalResult PAL_CALL createSwapchainD3D12( + PalDevice* device, + PalQueue* queue, + PalSurface* surface, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + +void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain); + +PalImage* PAL_CALL getSwapchainImageD3D12( + PalSwapchain* swapchain, + Int32 index); + +PalResult PAL_CALL getNextSwapchainImageD3D12( + PalSwapchain* swapchain, + PalSwapchainNextImageInfo* info, + Uint32* outIndex); + +PalResult PAL_CALL presentSwapchainD3D12( + PalSwapchain* swapchain, + PalSwapchainPresentInfo* info); + +// ================================================== +// Shader +// ================================================== + +PalResult PAL_CALL createShaderD3D12( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + +void PAL_CALL destroyShaderD3D12(PalShader* shader); + +// ================================================== +// Fence +// ================================================== + +PalResult PAL_CALL createFenceD3D12( + PalDevice* device, + bool signaled, + PalFence** outFence); + +void PAL_CALL destroyFenceD3D12(PalFence* fence); + +PalResult PAL_CALL waitFenceD3D12( + PalFence* fence, + Uint64 timeout); + +PalResult PAL_CALL resetFenceD3D12(PalFence* fence); + +bool PAL_CALL isFenceSignaledD3D12(PalFence* fence); + +// ================================================== +// Semaphore +// ================================================== + +PalResult PAL_CALL createSemaphoreD3D12( + PalDevice* device, + PalSemaphore** outSemaphore); + +void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); + +PalResult PAL_CALL waitSemaphoreD3D12( + PalSemaphore* semaphore, + Uint64 value, + Uint64 timeout); + +PalResult PAL_CALL signalSemaphoreD3D12( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value); + +PalResult PAL_CALL getSemaphoreValueD3D12( + PalSemaphore* semaphore, + Uint64* value); + +// ================================================== +// Command Pool And Buffer +// ================================================== + +PalResult PAL_CALL createCommandPoolD3D12( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool); + +void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool); + +PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool); + +PalResult PAL_CALL allocateCommandBufferD3D12( + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outBuffer); + +void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* buffer); + +PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL submitCommandBufferD3D12( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + +// ================================================== +// Command Recording +// ================================================== + +PalResult PAL_CALL cmdBeginD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info); + +PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdExecuteCommandBufferD3D12( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + +PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + +PalResult PAL_CALL cmdDrawMeshTasksD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + +PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 drawCount, + Uint32 stride); + +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride); + +PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); + +PalResult PAL_CALL cmdBeginRenderingD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info); + +PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdCopyBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyBufferToImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageToBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdBindPipelineD3D12( + PalCommandBuffer* cmdBuffer, + PalPipelineBindPoint bindPoint, + PalPipeline* pipeline); + +PalResult PAL_CALL cmdSetViewportD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalViewport* viewports); + +PalResult PAL_CALL cmdSetScissorsD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalRect2D* scissors); + +PalResult PAL_CALL cmdBindVertexBuffersD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 firstSlot, + Uint32 count, + PalBuffer** buffers, + Uint64* offsets); + +PalResult PAL_CALL cmdBindIndexBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + PalIndexType type); + +PalResult PAL_CALL cmdDrawD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 vertexCount, + Uint32 instanceCount, + Uint32 firstVertex, + Uint32 firstInstance); + +PalResult PAL_CALL cmdDrawIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count, + Uint32 stride); + +PalResult PAL_CALL cmdDrawIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride); + +PalResult PAL_CALL cmdDrawIndexedD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 indexCount, + Uint32 instanceCount, + Uint32 firstIndex, + Int32 vertexOffset, + Uint32 firstInstance); + +PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count, + Uint32 stride); + +PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride); + +PalResult PAL_CALL cmdMemoryBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalUsageStateInfo* oldsUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); + +PalResult PAL_CALL cmdImageBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); + +PalResult PAL_CALL cmdBufferBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); + +PalResult PAL_CALL cmdDispatchD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + +PalResult PAL_CALL cmdDispatchBaseD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 baseGroupX, + Uint32 baseGroupY, + Uint32 baseGroupZ, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + +PalResult PAL_CALL cmdDispatchIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset); + +PalResult PAL_CALL cmdTraceRaysD3D12( + PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + Uint32 raygenIndex, + Uint32 width, + Uint32 height, + Uint32 depth); + +PalResult PAL_CALL cmdTraceRaysIndirectD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 raygenIndex, + PalShaderBindingTable* sbt, + PalDeviceAddress bufferAddress); + +PalResult PAL_CALL cmdBindDescriptorSetD3D12( + PalCommandBuffer* cmdBuffer, + PalPipelineBindPoint bindPoint, + PalPipelineLayout* layout, + Uint32 setIndex, + PalDescriptorSet* set); + +PalResult PAL_CALL cmdPushConstantsD3D12( + PalCommandBuffer* cmdBuffer, + PalPipelineLayout* layout, + Uint32 shaderStageCount, + PalShaderStage* shaderStages, + Uint32 offset, + Uint32 size, + const void* value); + +PalResult PAL_CALL cmdSetCullModeD3D12( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + +PalResult PAL_CALL cmdSetFrontFaceD3D12( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + +PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + +PalResult PAL_CALL cmdSetDepthTestEnableD3D12( + PalCommandBuffer* cmdBuffer, + bool enable); + +PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( + PalCommandBuffer* cmdBuffer, + bool enable); + +PalResult PAL_CALL cmdSetStencilOpD3D12( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); + +// ================================================== +// Acceleration Structure +// ================================================== + +PalResult PAL_CALL createAccelerationstructureD3D12( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + +void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as); + +PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + +// ================================================== +// Buffer +// ================================================== + +PalResult PAL_CALL createBufferD3D12( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + +void PAL_CALL destroyBufferD3D12(PalBuffer* buffer); + +PalResult PAL_CALL getBufferMemoryRequirementsD3D12( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( + PalDevice* device, + PalInstanceBufferRequirements* requirements, + Uint32 instanceCount); + +PalResult PAL_CALL writeInstancesToMappedMemoryD3D12( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + Uint32 instanceCount); + +PalResult PAL_CALL bindBufferMemoryD3D12( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset); + +PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); + +// ================================================== +// Descriptor Pool, Set and Layout +// ================================================== + +PalResult PAL_CALL createDescriptorSetLayoutD3D12( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + +void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout); + +PalResult PAL_CALL createDescriptorPoolD3D12( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + +void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool); + +PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool); + +PalResult PAL_CALL allocateDescriptorSetD3D12( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + +void PAL_CALL freeDescriptorSetD3D12(PalDescriptorSet* set); + +PalResult PAL_CALL updateDescriptorSetD3D12( + PalDevice* device, + Uint32 count, + PalDescriptorSetWriteInfo* infos); + +// ================================================== +// Pipeline Layout +// ================================================== + +PalResult PAL_CALL createPipelineLayoutD3D12( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + +void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout); + +// ================================================== +// Pipeline +// ================================================== + +PalResult PAL_CALL createGraphicsPipelineD3D12( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createComputePipelineD3D12( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createRayTracingPipelineD3D12( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + +void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline); + +// ================================================== +// Shader Binding Table +// ================================================== + +PalResult PAL_CALL createShaderBindingTableD3D12( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + +void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); + +#endif // PAL_HAS_D3D12 \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 6e4dfc64..4c7705a9 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -99,6 +99,10 @@ static inline Uint32 _min( #if PAL_HAS_VULKAN +// ================================================== +// Adapter +// ================================================== + PalResult PAL_CALL initGraphicsVk( const PalGraphicsDebugger* debugger, const PalAllocator* allocator); @@ -119,6 +123,10 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter); +// ================================================== +// Device +// ================================================== + PalResult PAL_CALL createDeviceVk( PalAdapter* adapter, PalAdapterFeatures features, @@ -128,6 +136,10 @@ void PAL_CALL destroyDeviceVk(PalDevice* device); PalResult PAL_CALL waitDeviceVk(PalDevice* device); +// ================================================== +// Memory +// ================================================== + PalResult PAL_CALL allocateMemoryVk( PalDevice* device, PalMemoryType type, @@ -139,6 +151,21 @@ void PAL_CALL freeMemoryVk( PalDevice* device, PalMemory* memory); +PalResult PAL_CALL mapMemoryVk( + PalDevice* device, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr); + +void PAL_CALL unmapMemoryVk( + PalDevice* device, + PalMemory* memory); + +// ================================================== +// Extended Adapter Features +// ================================================== + PalResult PAL_CALL queryDepthStencilCapabilitiesVk( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -159,6 +186,10 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( PalDevice* device, PalDescriptorIndexingCapabilities* caps); +// ================================================== +// Queue +// ================================================== + PalResult PAL_CALL createQueueVk( PalDevice* device, PalQueueType type, @@ -172,6 +203,10 @@ bool PAL_CALL canQueuePresentVk( PalQueue* queue, PalSurface* surface); +// ================================================== +// Formats +// ================================================== + PalResult PAL_CALL enumerateFormatsVk( PalAdapter* adapter, Int32* count, @@ -189,6 +224,10 @@ PalImageViewUsages PAL_CALL queryFormatImageViewUsagesVk( PalAdapter* adapter, PalFormat format); +// ================================================== +// Image +// ================================================== + PalResult PAL_CALL createImageVk( PalDevice* device, const PalImageCreateInfo* info, @@ -209,6 +248,10 @@ PalResult PAL_CALL bindImageMemoryVk( PalMemory* memory, Uint64 offset); +// ================================================== +// Image View +// ================================================== + PalResult PAL_CALL createImageViewVk( PalDevice* device, PalImage* image, @@ -217,6 +260,10 @@ PalResult PAL_CALL createImageViewVk( void PAL_CALL destroyImageViewVk(PalImageView* imageView); +// ================================================== +// Sampler +// ================================================== + PalResult PAL_CALL createSamplerVk( PalDevice* device, const PalSamplerCreateInfo* info, @@ -224,6 +271,10 @@ PalResult PAL_CALL createSamplerVk( void PAL_CALL destroySamplerVk(PalSampler* sampler); +// ================================================== +// Surface +// ================================================== + PalResult PAL_CALL createSurfaceVk( PalDevice* device, PalGraphicsWindow* window, @@ -236,6 +287,10 @@ PalResult PAL_CALL getSurfaceCapabilitiesVk( PalSurface* surface, PalSurfaceCapabilities* caps); +// ================================================== +// Swapchain +// ================================================== + PalResult PAL_CALL createSwapchainVk( PalDevice* device, PalQueue* queue, @@ -258,6 +313,10 @@ PalResult PAL_CALL presentSwapchainVk( PalSwapchain* swapchain, PalSwapchainPresentInfo* info); +// ================================================== +// Shader +// ================================================== + PalResult PAL_CALL createShaderVk( PalDevice* device, const PalShaderCreateInfo* info, @@ -265,6 +324,10 @@ PalResult PAL_CALL createShaderVk( void PAL_CALL destroyShaderVk(PalShader* shader); +// ================================================== +// Fence +// ================================================== + PalResult PAL_CALL createFenceVk( PalDevice* device, bool signaled, @@ -280,6 +343,10 @@ PalResult PAL_CALL resetFenceVk(PalFence* fence); bool PAL_CALL isFenceSignaledVk(PalFence* fence); +// ================================================== +// Semaphore +// ================================================== + PalResult PAL_CALL createSemaphoreVk( PalDevice* device, PalSemaphore** outSemaphore); @@ -300,6 +367,10 @@ PalResult PAL_CALL getSemaphoreValueVk( PalSemaphore* semaphore, Uint64* value); +// ================================================== +// Command Pool And Buffer +// ================================================== + PalResult PAL_CALL createCommandPoolVk( PalDevice* device, PalQueue* queue, @@ -323,6 +394,10 @@ PalResult PAL_CALL submitCommandBufferVk( PalQueue* queue, PalCommandBufferSubmitInfo* info); +// ================================================== +// Command Recording +// ================================================== + PalResult PAL_CALL cmdBeginVk( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); @@ -564,6 +639,10 @@ PalResult PAL_CALL cmdSetStencilOpVk( PalStencilOp depthFailOp, PalCompareOp compareOp); +// ================================================== +// Acceleration Structure +// ================================================== + PalResult PAL_CALL createAccelerationstructureVk( PalDevice* device, const PalAccelerationStructureCreateInfo* info, @@ -576,6 +655,10 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); +// ================================================== +// Buffer +// ================================================== + PalResult PAL_CALL createBufferVk( PalDevice* device, const PalBufferCreateInfo* info, @@ -605,16 +688,9 @@ PalResult PAL_CALL bindBufferMemoryVk( PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer); -PalResult PAL_CALL mapMemoryVk( - PalDevice* device, - PalMemory* memory, - Uint64 offset, - Uint64 size, - void** outPtr); - -void PAL_CALL unmapMemoryVk( - PalDevice* device, - PalMemory* memory); +// ================================================== +// Descriptor Pool, Set and Layout +// ================================================== PalResult PAL_CALL createDescriptorSetLayoutVk( PalDevice* device, @@ -645,6 +721,10 @@ PalResult PAL_CALL updateDescriptorSetVk( Uint32 count, PalDescriptorSetWriteInfo* infos); +// ================================================== +// Pipeline Layout +// ================================================== + PalResult PAL_CALL createPipelineLayoutVk( PalDevice* device, const PalPipelineLayoutCreateInfo* info, @@ -652,6 +732,10 @@ PalResult PAL_CALL createPipelineLayoutVk( void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout); +// ================================================== +// Pipeline +// ================================================== + PalResult PAL_CALL createGraphicsPipelineVk( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, @@ -669,6 +753,10 @@ PalResult PAL_CALL createRayTracingPipelineVk( void PAL_CALL destroyPipelineVk(PalPipeline* pipeline); +// ================================================== +// Shader Binding Table +// ================================================== + PalResult PAL_CALL createShaderBindingTableVk( PalDevice* device, const PalShaderBindingTableCreateInfo* info, @@ -853,124 +941,964 @@ static PalGraphicsBackend s_VkBackend = { // D3D12 API // ================================================== +#if PAL_HAS_D3D12 + // ================================================== -// Metal API +// Adapter // ================================================== +PalResult PAL_CALL initGraphicsD3D12( + const PalGraphicsDebugger* debugger, + const PalAllocator* allocator); + +void PAL_CALL shutdownGraphicsD3D12(); + +PalResult PAL_CALL enumerateAdaptersD3D12( + Int32* count, + PalAdapter** outAdapters); + +PalResult PAL_CALL getAdapterInfoD3D12( + PalAdapter* adapter, + PalAdapterInfo* info); + +PalResult PAL_CALL getAdapterCapabilitiesD3D12( + PalAdapter* adapter, + PalAdapterCapabilities* caps); + +PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); + // ================================================== -// Public API +// Device // ================================================== -PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) -{ - if (s_Graphics.initialized) { - return PAL_RESULT_INVALID_BACKEND; - } +PalResult PAL_CALL createDeviceD3D12( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); -#ifdef _WIN32 - // we reserve two slots for vulkan and d3d12 - if (s_Graphics.backendCount == MAX_BACKENDS - 2) { - return PAL_RESULT_INVALID_BACKEND; - } -#else - // we reserve one slot for vulkan or metal depending on platform - if (s_Graphics.backendCount == MAX_BACKENDS - 1) { - return PAL_RESULT_INVALID_BACKEND; - } -#endif // _WIN32 +void PAL_CALL destroyDeviceD3D12(PalDevice* device); - // check if all the function pointers are set - // clang-format off - // adapter - if (!backend->enumerateAdapters || - !backend->getAdapterInfo || - !backend->getAdapterCapabilities || - !backend->getAdapterFeatures || +PalResult PAL_CALL waitDeviceD3D12(PalDevice* device); - // device - !backend->createDevice || - !backend->destroyDevice || - !backend->waitDevice || +// ================================================== +// Memory +// ================================================== - // memory - !backend->allocateMemory || - !backend->freeMemory || - !backend->mapMemory || - !backend->unmapMemory || +PalResult PAL_CALL allocateMemoryD3D12( + PalDevice* device, + PalMemoryType type, + Uint64 memoryMask, + Uint64 size, + PalMemory** outMemory); - // extended adapter features - !backend->queryDepthStencilCapabilities || - !backend->queryFragmentShadingRateCapabilities || - !backend->queryMeshShaderCapabilities || - !backend->queryRayTracingCapabilities || - !backend->queryDescriptorIndexingCapabilities || +void PAL_CALL freeMemoryD3D12( + PalDevice* device, + PalMemory* memory); - // queue - !backend->createQueue || - !backend->destroyQueue || - !backend->waitQueue || - !backend->canQueuePresent || +PalResult PAL_CALL mapMemoryD3D12( + PalDevice* device, + PalMemory* memory, + Uint64 offset, + Uint64 size, + void** outPtr); - // formats - !backend->enumerateFormats || - !backend->isFormatSupported || - !backend->queryFormatImageUsages || - !backend->queryFormatImageViewUsages || +void PAL_CALL unmapMemoryD3D12( + PalDevice* device, + PalMemory* memory); - // image - !backend->createImage || - !backend->destroyImage || - !backend->getImageInfo || - !backend->getImageMemoryRequirements || - !backend->bindImageMemory || +// ================================================== +// Extended Adapter Features +// ================================================== - // image view - !backend->createImageView || - !backend->destroyImageView || +PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( + PalDevice* device, + PalDepthStencilCapabilities* caps); - // sampler - !backend->createSampler || - !backend->destroySampler || +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); - // surface - !backend->createSurface || - !backend->destroySurface || - !backend->getSurfaceCapabilities || +PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( + PalDevice* device, + PalMeshShaderCapabilities* caps); - // swapchain - !backend->createSwapchain || - !backend->destroySwapchain || - !backend->getSwapchainImage || - !backend->getNextSwapchainImage || - !backend->presentSwapchain || +PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( + PalDevice* device, + PalRayTracingCapabilities* caps); - // shader - !backend->createShader || - !backend->destroyShader || +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); - // fence - !backend->createFence || - !backend->destroyFence || - !backend->waitFence || - !backend->resetFence || - !backend->isFenceSignaled || +// ================================================== +// Queue +// ================================================== - // semaphore - !backend->createSemaphore || - !backend->destroySemaphore || - !backend->waitSemaphore || - !backend->signalSemaphore || - !backend->getSemaphoreValue || +PalResult PAL_CALL createQueueD3D12( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); - // command pool and command buffer - !backend->createCommandPool || - !backend->destroyCommandPool || - !backend->resetCommandPool || - !backend->allocateCommandBuffer || - !backend->freeCommandBuffer || - !backend->submitCommandBuffer || +void PAL_CALL destroyQueueD3D12(PalQueue* queue); - // command recording +PalResult PAL_CALL waitQueueD3D12(PalQueue* queue); + +bool PAL_CALL canQueuePresentD3D12( + PalQueue* queue, + PalSurface* surface); + +// ================================================== +// Formats +// ================================================== + +PalResult PAL_CALL enumerateFormatsD3D12( + PalAdapter* adapter, + Int32* count, + PalFormatInfo* outFormats); + +bool PAL_CALL isFormatSupportedD3D12( + PalAdapter* adapter, + PalFormat format); + +PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( + PalAdapter* adapter, + PalFormat format); + +PalImageViewUsages PAL_CALL queryFormatImageViewUsagesD3D12( + PalAdapter* adapter, + PalFormat format); + +// ================================================== +// Image +// ================================================== + +PalResult PAL_CALL createImageD3D12( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + +void PAL_CALL destroyImageD3D12(PalImage* image); + +PalResult PAL_CALL getImageInfoD3D12( + PalImage* image, + PalImageInfo* info); + +PalResult PAL_CALL getImageMemoryRequirementsD3D12( + PalImage* image, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL bindImageMemoryD3D12( + PalImage* image, + PalMemory* memory, + Uint64 offset); + +// ================================================== +// Image View +// ================================================== + +PalResult PAL_CALL createImageViewD3D12( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + +void PAL_CALL destroyImageViewD3D12(PalImageView* imageView); + +// ================================================== +// Sampler +// ================================================== + +PalResult PAL_CALL createSamplerD3D12( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler); + +void PAL_CALL destroySamplerD3D12(PalSampler* sampler); + +// ================================================== +// Surface +// ================================================== + +PalResult PAL_CALL createSurfaceD3D12( + PalDevice* device, + PalGraphicsWindow* window, + PalSurface** outSurface); + +void PAL_CALL destroySurfaceD3D12(PalSurface* surface); + +PalResult PAL_CALL getSurfaceCapabilitiesD3D12( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps); + +// ================================================== +// Swapchain +// ================================================== + +PalResult PAL_CALL createSwapchainD3D12( + PalDevice* device, + PalQueue* queue, + PalSurface* surface, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + +void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain); + +PalImage* PAL_CALL getSwapchainImageD3D12( + PalSwapchain* swapchain, + Int32 index); + +PalResult PAL_CALL getNextSwapchainImageD3D12( + PalSwapchain* swapchain, + PalSwapchainNextImageInfo* info, + Uint32* outIndex); + +PalResult PAL_CALL presentSwapchainD3D12( + PalSwapchain* swapchain, + PalSwapchainPresentInfo* info); + +// ================================================== +// Shader +// ================================================== + +PalResult PAL_CALL createShaderD3D12( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + +void PAL_CALL destroyShaderD3D12(PalShader* shader); + +// ================================================== +// Fence +// ================================================== + +PalResult PAL_CALL createFenceD3D12( + PalDevice* device, + bool signaled, + PalFence** outFence); + +void PAL_CALL destroyFenceD3D12(PalFence* fence); + +PalResult PAL_CALL waitFenceD3D12( + PalFence* fence, + Uint64 timeout); + +PalResult PAL_CALL resetFenceD3D12(PalFence* fence); + +bool PAL_CALL isFenceSignaledD3D12(PalFence* fence); + +// ================================================== +// Semaphore +// ================================================== + +PalResult PAL_CALL createSemaphoreD3D12( + PalDevice* device, + PalSemaphore** outSemaphore); + +void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); + +PalResult PAL_CALL waitSemaphoreD3D12( + PalSemaphore* semaphore, + Uint64 value, + Uint64 timeout); + +PalResult PAL_CALL signalSemaphoreD3D12( + PalSemaphore* semaphore, + PalQueue* queue, + Uint64 value); + +PalResult PAL_CALL getSemaphoreValueD3D12( + PalSemaphore* semaphore, + Uint64* value); + +// ================================================== +// Command Pool And Buffer +// ================================================== + +PalResult PAL_CALL createCommandPoolD3D12( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool); + +void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool); + +PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool); + +PalResult PAL_CALL allocateCommandBufferD3D12( + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outBuffer); + +void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* buffer); + +PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL submitCommandBufferD3D12( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + +// ================================================== +// Command Recording +// ================================================== + +PalResult PAL_CALL cmdBeginD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info); + +PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdExecuteCommandBufferD3D12( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + +PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + +PalResult PAL_CALL cmdDrawMeshTasksD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + +PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 drawCount, + Uint32 stride); + +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride); + +PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); + +PalResult PAL_CALL cmdBeginRenderingD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info); + +PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdCopyBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyBufferToImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageToBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdBindPipelineD3D12( + PalCommandBuffer* cmdBuffer, + PalPipelineBindPoint bindPoint, + PalPipeline* pipeline); + +PalResult PAL_CALL cmdSetViewportD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalViewport* viewports); + +PalResult PAL_CALL cmdSetScissorsD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 count, + PalRect2D* scissors); + +PalResult PAL_CALL cmdBindVertexBuffersD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 firstSlot, + Uint32 count, + PalBuffer** buffers, + Uint64* offsets); + +PalResult PAL_CALL cmdBindIndexBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + PalIndexType type); + +PalResult PAL_CALL cmdDrawD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 vertexCount, + Uint32 instanceCount, + Uint32 firstVertex, + Uint32 firstInstance); + +PalResult PAL_CALL cmdDrawIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count, + Uint32 stride); + +PalResult PAL_CALL cmdDrawIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride); + +PalResult PAL_CALL cmdDrawIndexedD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 indexCount, + Uint32 instanceCount, + Uint32 firstIndex, + Int32 vertexOffset, + Uint32 firstInstance); + +PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset, + Uint32 count, + Uint32 stride); + +PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + Uint64 offset, + Uint64 countBufferOffset, + Uint32 maxDrawCount, + Uint32 stride); + +PalResult PAL_CALL cmdMemoryBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalUsageStateInfo* oldsUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); + +PalResult PAL_CALL cmdImageBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); + +PalResult PAL_CALL cmdBufferBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageStateInfo* oldUsageStateInfo, + PalUsageStateInfo* newUsageStateInfo); + +PalResult PAL_CALL cmdDispatchD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + +PalResult PAL_CALL cmdDispatchBaseD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 baseGroupX, + Uint32 baseGroupY, + Uint32 baseGroupZ, + Uint32 groupCountX, + Uint32 groupCountY, + Uint32 groupCountZ); + +PalResult PAL_CALL cmdDispatchIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + Uint64 offset); + +PalResult PAL_CALL cmdTraceRaysD3D12( + PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + Uint32 raygenIndex, + Uint32 width, + Uint32 height, + Uint32 depth); + +PalResult PAL_CALL cmdTraceRaysIndirectD3D12( + PalCommandBuffer* cmdBuffer, + Uint32 raygenIndex, + PalShaderBindingTable* sbt, + PalDeviceAddress bufferAddress); + +PalResult PAL_CALL cmdBindDescriptorSetD3D12( + PalCommandBuffer* cmdBuffer, + PalPipelineBindPoint bindPoint, + PalPipelineLayout* layout, + Uint32 setIndex, + PalDescriptorSet* set); + +PalResult PAL_CALL cmdPushConstantsD3D12( + PalCommandBuffer* cmdBuffer, + PalPipelineLayout* layout, + Uint32 shaderStageCount, + PalShaderStage* shaderStages, + Uint32 offset, + Uint32 size, + const void* value); + +PalResult PAL_CALL cmdSetCullModeD3D12( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + +PalResult PAL_CALL cmdSetFrontFaceD3D12( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + +PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + +PalResult PAL_CALL cmdSetDepthTestEnableD3D12( + PalCommandBuffer* cmdBuffer, + bool enable); + +PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( + PalCommandBuffer* cmdBuffer, + bool enable); + +PalResult PAL_CALL cmdSetStencilOpD3D12( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); + +// ================================================== +// Acceleration Structure +// ================================================== + +PalResult PAL_CALL createAccelerationstructureD3D12( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + +void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as); + +PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + +// ================================================== +// Buffer +// ================================================== + +PalResult PAL_CALL createBufferD3D12( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + +void PAL_CALL destroyBufferD3D12(PalBuffer* buffer); + +PalResult PAL_CALL getBufferMemoryRequirementsD3D12( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( + PalDevice* device, + PalInstanceBufferRequirements* requirements, + Uint32 instanceCount); + +PalResult PAL_CALL writeInstancesToMappedMemoryD3D12( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + Uint32 instanceCount); + +PalResult PAL_CALL bindBufferMemoryD3D12( + PalBuffer* buffer, + PalMemory* memory, + Uint64 offset); + +PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); + +// ================================================== +// Descriptor Pool, Set and Layout +// ================================================== + +PalResult PAL_CALL createDescriptorSetLayoutD3D12( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + +void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout); + +PalResult PAL_CALL createDescriptorPoolD3D12( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + +void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool); + +PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool); + +PalResult PAL_CALL allocateDescriptorSetD3D12( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + +void PAL_CALL freeDescriptorSetD3D12(PalDescriptorSet* set); + +PalResult PAL_CALL updateDescriptorSetD3D12( + PalDevice* device, + Uint32 count, + PalDescriptorSetWriteInfo* infos); + +// ================================================== +// Pipeline Layout +// ================================================== + +PalResult PAL_CALL createPipelineLayoutD3D12( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + +void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout); + +// ================================================== +// Pipeline +// ================================================== + +PalResult PAL_CALL createGraphicsPipelineD3D12( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createComputePipelineD3D12( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createRayTracingPipelineD3D12( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + +void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline); + +// ================================================== +// Shader Binding Table +// ================================================== + +PalResult PAL_CALL createShaderBindingTableD3D12( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + +void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); + +static PalGraphicsBackend s_D3D12Backend = { + // adapter + .enumerateAdapters = enumerateAdaptersD3D12, + .getAdapterInfo = getAdapterInfoD3D12, + .getAdapterCapabilities = getAdapterCapabilitiesD3D12, + .getAdapterFeatures = getAdapterFeaturesD3D12, + + // device + .createDevice = createDeviceD3D12, + .destroyDevice = destroyDeviceD3D12, + .waitDevice = waitDeviceD3D12, + + // memory + .allocateMemory = allocateMemoryD3D12, + .freeMemory = freeMemoryD3D12, + .mapMemory = mapMemoryD3D12, + .unmapMemory = unmapMemoryD3D12, + + // extended adapter features + .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesD3D12, + .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesD3D12, + .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesD3D12, + .queryRayTracingCapabilities = queryRayTracingCapabilitiesD3D12, + .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesD3D12, + + // queue + .createQueue = createQueueD3D12, + .destroyQueue = destroyQueueD3D12, + .waitQueue = waitQueueD3D12, + .canQueuePresent = canQueuePresentD3D12, + + // format + .enumerateFormats = enumerateFormatsD3D12, + .isFormatSupported = isFormatSupportedD3D12, + .queryFormatImageUsages = queryFormatImageUsagesD3D12, + .queryFormatImageViewUsages = queryFormatImageViewUsagesD3D12, + + // image + .createImage = createImageD3D12, + .destroyImage = destroyImageD3D12, + .getImageInfo = getImageInfoD3D12, + .getImageMemoryRequirements = getImageMemoryRequirementsD3D12, + .bindImageMemory = bindImageMemoryD3D12, + + // image view + .createImageView = createImageViewD3D12, + .destroyImageView = destroyImageViewD3D12, + + // sampler + .createSampler = createSamplerD3D12, + .destroySampler = destroySamplerD3D12, + + // surface + .createSurface = createSurfaceD3D12, + .destroySurface = destroySurfaceD3D12, + .getSurfaceCapabilities = getSurfaceCapabilitiesD3D12, + + // swapchain + .createSwapchain = createSwapchainD3D12, + .destroySwapchain = destroySwapchainD3D12, + .getSwapchainImage = getSwapchainImageD3D12, + .getNextSwapchainImage = getNextSwapchainImageD3D12, + .presentSwapchain = presentSwapchainD3D12, + + // shader + .createShader = createShaderD3D12, + .destroyShader = destroyShaderD3D12, + + // fence + .createFence = createFenceD3D12, + .destroyFence = destroyFenceD3D12, + .waitFence = waitFenceD3D12, + .resetFence = resetFenceD3D12, + .isFenceSignaled = isFenceSignaledD3D12, + + // semaphore + .createSemaphore = createSemaphoreD3D12, + .destroySemaphore = destroySemaphoreD3D12, + .waitSemaphore = waitSemaphoreD3D12, + .signalSemaphore = signalSemaphoreD3D12, + .getSemaphoreValue = getSemaphoreValueD3D12, + + // command pool and command buffer + .createCommandPool = createCommandPoolD3D12, + .destroyCommandPool = destroyCommandPoolD3D12, + .resetCommandPool = resetCommandPoolD3D12, + .allocateCommandBuffer = allocateCommandBufferD3D12, + .freeCommandBuffer = freeCommandBufferD3D12, + .resetCommandBuffer = resetCommandBufferD3D12, + .submitCommandBuffer = submitCommandBufferD3D12, + + // command recording + .cmdBegin = cmdBeginD3D12, + .cmdEnd = cmdEndD3D12, + .cmdExecuteCommandBuffer = cmdExecuteCommandBufferD3D12, + .cmdSetFragmentShadingRate = cmdSetFragmentShadingRateD3D12, + .cmdDrawMeshTasks = cmdDrawMeshTasksD3D12, + .cmdDrawMeshTasksIndirect = cmdDrawMeshTasksIndirectD3D12, + .cmdDrawMeshTasksIndirectCount = cmdDrawMeshTasksIndirectCountD3D12, + .cmdBuildAccelerationStructure = cmdBuildAccelerationStructureD3D12, + .cmdBeginRendering = cmdBeginRenderingD3D12, + .cmdEndRendering = cmdEndRenderingD3D12, + .cmdCopyBuffer = cmdCopyBufferD3D12, + .cmdCopyBufferToImage = cmdCopyBufferToImageD3D12, + .cmdCopyImage = cmdCopyImageD3D12, + .cmdCopyImageToBuffer = cmdCopyImageToBufferD3D12, + .cmdBindPipeline = cmdBindPipelineD3D12, + .cmdSetViewport = cmdSetViewportD3D12, + .cmdSetScissors = cmdSetScissorsD3D12, + .cmdBindVertexBuffers = cmdBindVertexBuffersD3D12, + .cmdBindIndexBuffer = cmdBindIndexBufferD3D12, + .cmdDraw = cmdDrawD3D12, + .cmdDrawIndirect = cmdDrawIndirectD3D12, + .cmdDrawIndirectCount = cmdDrawIndirectCountD3D12, + .cmdDrawIndexed = cmdDrawIndexedD3D12, + .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectD3D12, + .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountD3D12, + .cmdMemoryBarrier = cmdMemoryBarrierD3D12, + .cmdImageBarrier = cmdImageBarrierD3D12, + .cmdBufferBarrier = cmdBufferBarrierD3D12, + .cmdDispatch = cmdDispatchD3D12, + .cmdDispatchBase = cmdDispatchBaseD3D12, + .cmdDispatchIndirect = cmdDispatchIndirectD3D12, + .cmdTraceRays = cmdTraceRaysD3D12, + .cmdTraceRaysIndirect = cmdTraceRaysIndirectD3D12, + .cmdBindDescriptorSet = cmdBindDescriptorSetD3D12, + .cmdPushConstants = cmdPushConstantsD3D12, + .cmdSetCullMode = cmdSetCullModeD3D12, + .cmdSetFrontFace = cmdSetFrontFaceD3D12, + .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyD3D12, + .cmdSetDepthTestEnable = cmdSetDepthTestEnableD3D12, + .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableD3D12, + .cmdSetStencilOp = cmdSetStencilOpD3D12, + + // acceleration structure + .createAccelerationstructure = createAccelerationstructureD3D12, + .destroyAccelerationstructure = destroyAccelerationstructureD3D12, + .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeD3D12, + + // buffer + .createBuffer = createBufferD3D12, + .destroyBuffer = destroyBufferD3D12, + .getBufferMemoryRequirements = getBufferMemoryRequirementsD3D12, + .computeInstanceBufferRequirements = computeInstanceBufferRequirementsD3D12, + .writeInstancesToMappedMemory = writeInstancesToMappedMemoryD3D12, + .bindBufferMemory = bindBufferMemoryD3D12, + .getBufferDeviceAddress = getBufferDeviceAddressD3D12, + + // descriptor set layout, descriptor pool and descriptor set + .createDescriptorSetLayout = createDescriptorSetLayoutD3D12, + .destroyDescriptorSetLayout = destroyDescriptorSetLayoutD3D12, + .createDescriptorPool = createDescriptorPoolD3D12, + .destroyDescriptorPool = destroyDescriptorPoolD3D12, + .resetDescriptorPool = resetDescriptorPoolD3D12, + .allocateDescriptorSet = allocateDescriptorSetD3D12, + .updateDescriptorSet = updateDescriptorSetD3D12, + + // pipeline layout + .createPipelineLayout = createPipelineLayoutD3D12, + .destroyPipelineLayout = destroyPipelineLayoutD3D12, + + // pipeline + .createGraphicsPipeline = createGraphicsPipelineD3D12, + .createComputePipeline = createComputePipelineD3D12, + .createRayTracingPipeline = createRayTracingPipelineD3D12, + .destroyPipeline = destroyPipelineD3D12, + + // shader binding table + .createShaderBindingTable = createShaderBindingTableD3D12, + .destroyShaderBindingTable = destroyShaderBindingTableD3D12}; + +#endif // PAL_HAS_D3D12 + +// ================================================== +// Metal API +// ================================================== + +// ================================================== +// Public API +// ================================================== + +PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) +{ + if (s_Graphics.initialized) { + return PAL_RESULT_INVALID_BACKEND; + } + +#ifdef _WIN32 + // we reserve two slots for vulkan and d3d12 + if (s_Graphics.backendCount == MAX_BACKENDS - 2) { + return PAL_RESULT_INVALID_BACKEND; + } +#else + // we reserve one slot for vulkan or metal depending on platform + if (s_Graphics.backendCount == MAX_BACKENDS - 1) { + return PAL_RESULT_INVALID_BACKEND; + } +#endif // _WIN32 + + // check if all the function pointers are set + // clang-format off + // adapter + if (!backend->enumerateAdapters || + !backend->getAdapterInfo || + !backend->getAdapterCapabilities || + !backend->getAdapterFeatures || + + // device + !backend->createDevice || + !backend->destroyDevice || + !backend->waitDevice || + + // memory + !backend->allocateMemory || + !backend->freeMemory || + !backend->mapMemory || + !backend->unmapMemory || + + // extended adapter features + !backend->queryDepthStencilCapabilities || + !backend->queryFragmentShadingRateCapabilities || + !backend->queryMeshShaderCapabilities || + !backend->queryRayTracingCapabilities || + !backend->queryDescriptorIndexingCapabilities || + + // queue + !backend->createQueue || + !backend->destroyQueue || + !backend->waitQueue || + !backend->canQueuePresent || + + // formats + !backend->enumerateFormats || + !backend->isFormatSupported || + !backend->queryFormatImageUsages || + !backend->queryFormatImageViewUsages || + + // image + !backend->createImage || + !backend->destroyImage || + !backend->getImageInfo || + !backend->getImageMemoryRequirements || + !backend->bindImageMemory || + + // image view + !backend->createImageView || + !backend->destroyImageView || + + // sampler + !backend->createSampler || + !backend->destroySampler || + + // surface + !backend->createSurface || + !backend->destroySurface || + !backend->getSurfaceCapabilities || + + // swapchain + !backend->createSwapchain || + !backend->destroySwapchain || + !backend->getSwapchainImage || + !backend->getNextSwapchainImage || + !backend->presentSwapchain || + + // shader + !backend->createShader || + !backend->destroyShader || + + // fence + !backend->createFence || + !backend->destroyFence || + !backend->waitFence || + !backend->resetFence || + !backend->isFenceSignaled || + + // semaphore + !backend->createSemaphore || + !backend->destroySemaphore || + !backend->waitSemaphore || + !backend->signalSemaphore || + !backend->getSemaphoreValue || + + // command pool and command buffer + !backend->createCommandPool || + !backend->destroyCommandPool || + !backend->resetCommandPool || + !backend->allocateCommandBuffer || + !backend->freeCommandBuffer || + !backend->submitCommandBuffer || + + // command recording !backend->cmdBegin || !backend->cmdEnd || !backend->resetCommandBuffer || @@ -1076,6 +2004,7 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan +#if PAL_HAS_VULKAN PalResult result = initGraphicsVk(debugger, allocator); if (result != PAL_RESULT_SUCCESS) { return PAL_RESULT_PLATFORM_FAILURE; @@ -1085,6 +2014,21 @@ PalResult PAL_CALL palInitGraphics( attached->base = &s_VkBackend; attached->startIndex = 0; attached->count = 0; +#endif // PAL_HAS_VULKAN + + // D3D12 +#if PAL_HAS_D3D12 + PalResult result = initGraphicsD3D12(debugger, allocator); + if (result != PAL_RESULT_SUCCESS) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; + attached->base = &s_D3D12Backend; + attached->startIndex = 0; + attached->count = 0; +#endif // PAL_HAS_D3D12 + #elif defined(__linux__) // vulkan #if PAL_HAS_VULKAN @@ -1115,10 +2059,21 @@ void PAL_CALL palShutdownGraphics() #ifdef _WIN32 // vulkan +#if PAL_HAS_VULKAN shutdownGraphicsVk(); +#endif // PAL_HAS_VULKAN + + // D3D12 +#if PAL_HAS_D3D12 + shutdownGraphicsD3D12(); +#endif // PAL_HAS_D3D12 + #elif defined(__linux__) // vulkan +#if PAL_HAS_VULKAN shutdownGraphicsVk(); +#endif // PAL_HAS_VULKAN + #else // metal or andriod #endif // _WIN32 From 531754d832c80fe4147464a75296917e7f81c1c9 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 30 Mar 2026 01:16:32 +0000 Subject: [PATCH 129/372] graphics test: d3d12 --- include/pal/pal_graphics.h | 4 +- src/graphics/pal_d3d12.c | 1031 ++++++++++++++++++++++++++++++----- src/graphics/pal_graphics.c | 56 +- tests/graphics_test.c | 10 +- tests/tests_main.c | 12 +- 5 files changed, 944 insertions(+), 169 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 831cac85..4289ff08 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1400,8 +1400,8 @@ typedef struct { Uint32 maxImageDepth; Uint32 maxImageArrayLayers; Uint32 maxImageMipLevels; - PalSampleCount maxColorSampleCount; - PalSampleCount maxDepthSampleCount; + PalSampleCount maxColorSampleCount; // TODO: Remove + PalSampleCount maxDepthSampleCount; // TODO: Remove Uint32 maxColorAttachments; Uint32 maxMultiViews; Uint32 maxViewports; diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 92abb052..7ae11330 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -29,10 +29,45 @@ freely, subject to the following restrictions: #if PAL_HAS_D3D12 +#ifdef __WIN32 +#include +#include +#include + // ================================================== // Typedefs, enums and structs // ================================================== +// IIDS +const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; +const IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0xd2,0x4e}; +const IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0,0x3c, 0x77,0x90,0x0a,0x0a,0x1d,0x17}; + +typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( + UINT, + REFIID, + void**); + +typedef struct { + const PalGraphicsBackend* backend; + + IDXGIAdapter4* handle; +} Adapter; + +typedef struct { + HMODULE handle; + HMODULE dxgi; + Adapter* adapters; + IDXGIFactory6* factory; + + PFN_D3D12_CREATE_DEVICE createDevice; + PFN_CreateDXGIFactory2 createDXGIFactory; + + const PalAllocator* allocator; +} D3D12; + +static D3D12 s_D3D12 = {0}; + // ================================================== // Helper Functions // ================================================== @@ -43,23 +78,384 @@ freely, subject to the following restrictions: PalResult PAL_CALL initGraphicsD3D12( const PalGraphicsDebugger* debugger, - const PalAllocator* allocator); - -void PAL_CALL shutdownGraphicsD3D12(); + const PalAllocator* allocator) +{ + // load d3d12 + s_D3D12.handle = LoadLibraryA("d3d12.dll"); + s_D3D12.dxgi = LoadLibraryA("dxgi.dll"); + if (!s_D3D12.handle || !s_D3D12.dxgi) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + // clang-format off + s_D3D12.createDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress( + s_D3D12.handle, + "D3D12CreateDevice"); + + s_D3D12.createDXGIFactory = (PFN_CreateDXGIFactory2)GetProcAddress( + s_D3D12.dxgi, + "CreateDXGIFactory2"); + + // clang-format on + + s_D3D12.factory = nullptr; + s_D3D12.adapters = nullptr; + HRESULT result = s_D3D12.createDXGIFactory(0, &IID_Factory, (void**)&s_D3D12.factory); + if (FAILED(result)) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL shutdownGraphicsD3D12() +{ + s_D3D12.factory->lpVtbl->Release(s_D3D12.factory); + FreeLibrary(s_D3D12.handle); + FreeLibrary(s_D3D12.dxgi); + if (s_D3D12.adapters) { + palFree(s_D3D12.allocator, s_D3D12.adapters); + } + memset(&s_D3D12, 0, sizeof(s_D3D12)); +} PalResult PAL_CALL enumerateAdaptersD3D12( Int32* count, - PalAdapter** outAdapters); + PalAdapter** outAdapters) +{ + Uint32 adapterCount = 0; + IDXGIAdapter* adapter = nullptr; + IDXGIAdapter4* dxAdapters[32]; // should be more than enough + + if (s_D3D12.adapters) { + palFree(s_D3D12.allocator, s_D3D12.adapters); + } + + while (s_D3D12.factory->lpVtbl->EnumAdapters( + s_D3D12.factory, + adapterCount, + &adapter) != DXGI_ERROR_NOT_FOUND) { + if (outAdapters) { + IDXGIAdapter4* tmp = nullptr; + if SUCCEEDED((adapter->lpVtbl->QueryInterface(adapter, &IID_Adapter, (void**)&tmp))) { + dxAdapters[adapterCount] = tmp; + } + } + adapter->lpVtbl->Release(adapter); + adapterCount++; + } + + if (outAdapters) { + s_D3D12.adapters = palAllocate(s_D3D12.allocator, sizeof(Adapter) * adapterCount, 0); + if (!s_D3D12.adapters) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // fill the array with Adapter structs + for (int i = 0; i < *count; i++) { + Adapter* tmp = &s_D3D12.adapters[i]; + tmp->handle = dxAdapters[i]; + outAdapters[i] = (PalAdapter*)tmp; + } + + } else { + *count = adapterCount; + } + + return PAL_RESULT_SUCCESS; +} PalResult PAL_CALL getAdapterInfoD3D12( PalAdapter* adapter, - PalAdapterInfo* info); + PalAdapterInfo* info) +{ + Adapter* d3dAdapter = (Adapter*)adapter; + IDXGIAdapter4* adapterHandle = d3dAdapter->handle; + DXGI_ADAPTER_DESC3 desc; + D3D12_FEATURE_DATA_ARCHITECTURE1 arch = {0}; + ID3D12Device* device = nullptr; + + HRESULT result = adapterHandle->lpVtbl->GetDesc3(adapterHandle, &desc); + if (FAILED(result)) { + return PAL_RESULT_INVALID_ADAPTER; + } + + D3D_FEATURE_LEVEL supportedLevel = D3D_FEATURE_LEVEL_11_0; + D3D_FEATURE_LEVEL levels[] = { + D3D_FEATURE_LEVEL_12_2, + D3D_FEATURE_LEVEL_12_1, + D3D_FEATURE_LEVEL_12_0, + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0 + }; + + const char* levelStrings[] = { + "12_2", + "12_1", + "12_0", + "11_1", + "11_0" + }; + + info->vendorId = desc.VendorId; + info->deviceId= desc.DeviceId; + info->apiType = PAL_ADAPTER_API_TYPE_D3D12; + info->shaderFormats = PAL_SHADER_FORMAT_DXIL; + info->sharedMemory = desc.SharedSystemMemory; + strcpy(info->backendName, "PAL"); + + WideCharToMultiByte( + CP_UTF8, + 0, + desc.Description, + -1, + info->name, + PAL_ADAPTER_NAME_SIZE, + nullptr, + nullptr); + + // create a temporary device to check the supported version + Uint32 levelIndex = 0; + for (int i = 0; i < 4; i++) { + result = s_D3D12.createDevice( + (IUnknown*)adapterHandle, + levels[i], + &IID_Device, + (void**)&device); + + if (SUCCEEDED(result)) { + supportedLevel = levels[i]; + levelIndex = i; + break; + } + } + + device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_ARCHITECTURE1, + &arch, + sizeof(arch)); + + if (arch.UMA == true) { + info->type = PAL_ADAPTER_TYPE_INTEGRATED; + + } else { + info->type = PAL_ADAPTER_TYPE_DISCRETE; + } + + if (desc.Flags & DXGI_ADAPTER_FLAG3_SOFTWARE) { + info->type = PAL_ADAPTER_TYPE_CPU; + } + + if (desc.DedicatedVideoMemory > 0) { + info->vram = desc.DedicatedVideoMemory; + + } else if (desc.DedicatedVideoMemory == 0 && desc.DedicatedSystemMemory > 0) { + info->vram = desc.DedicatedSystemMemory; + } + + info->version = supportedLevel; + strcpy(info->versionString, levelStrings[levelIndex]); + + device->lpVtbl->Release(device); + return PAL_RESULT_SUCCESS; +} PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapter* adapter, - PalAdapterCapabilities* caps); - -PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); + PalAdapterCapabilities* caps) +{ + caps->maxComputeQueues = PAL_INFINITE; + caps->maxGraphicsQueues = PAL_INFINITE; + caps->maxCopyQueues = PAL_INFINITE; + + caps->maxImageWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + caps->maxImageHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + caps->maxImageDepth = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + caps->maxImageArrayLayers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + // d3d12 does not give this but we calculate from the max width and width + Uint32 a = caps->maxImageWidth; + Uint32 b = caps->maxImageHeight; + Uint32 c = caps->maxImageDepth; + + Uint32 tmp = a > b ? a : b; + Uint32 size = tmp > c ? tmp : c; + Uint32 levels = 0; + while (size > 0) { + // divide by two + size = size / 2; + levels++; + } + + caps->maxImageMipLevels = levels; + caps->maxColorAttachments = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; + caps->maxViewports = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + caps->maxSamplers = D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE; + + caps->maxMultiViews = D3D12_MAX_VIEW_INSTANCE_COUNT; + if (caps->maxMultiViews == 0) { + caps->maxMultiViews = 1; + } + + caps->maxUniformBufferSize = D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT * 16; + caps->maxStorageBufferSize = PAL_INFINITE; + caps->maxPushConstantSize = D3D12_MAX_ROOT_COST * 4; + + caps->maxComputeWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; + caps->maxComputeWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + caps->maxComputeWorkGroupCount[1] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + caps->maxComputeWorkGroupCount[2] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + + caps->maxComputeWorkGroupSize[0] = D3D12_CS_THREAD_GROUP_MAX_X; + caps->maxComputeWorkGroupSize[1] = D3D12_CS_THREAD_GROUP_MAX_Y; + caps->maxComputeWorkGroupSize[2] = D3D12_CS_THREAD_GROUP_MAX_Z; + + return PAL_RESULT_SUCCESS; +} + +PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) +{ + HRESULT result; + ID3D12Device* device = nullptr; + Adapter* d3dAdapter = (Adapter*)adapter; + IDXGIAdapter4* adapterHandle = d3dAdapter->handle; + PalAdapterFeatures features = 0; + + D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; + D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {0}; + D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = {0}; + D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {0}; + D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = {0}; + D3D12_FEATURE_DATA_D3D12_OPTIONS12 options12 = {0}; + D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; + + D3D_FEATURE_LEVEL levels[] = { + D3D_FEATURE_LEVEL_12_2, + D3D_FEATURE_LEVEL_12_1, + D3D_FEATURE_LEVEL_12_0, + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0 + }; + + for (int i = 0; i < 4; i++) { + result = s_D3D12.createDevice( + (IUnknown*)adapterHandle, + levels[i], + &IID_Device, + (void**)&device); + + if (SUCCEEDED(result)) { + if (levels[i] >= D3D_FEATURE_LEVEL_12_0) { + features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; + } + break; + } + } + + device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS, + &options, + sizeof(options)); + + device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS3, + &options3, + sizeof(options3)); + + device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS5, + &options5, + sizeof(options5)); + + device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS6, + &options6, + sizeof(options6)); + + device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS7, + &options7, + sizeof(options7)); + + shaderModel.HighestShaderModel = D3D_SHADER_MODEL_5_1; + HRESULT hr = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_5_1 && hr == S_OK) { + features |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; + features |= PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING; + features |= PAL_ADAPTER_FEATURE_SHADER_FLOAT64; + } + + shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_2; + hr = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_2 && hr == S_OK) { + features |= PAL_ADAPTER_FEATURE_SHADER_FLOAT16; + features |= PAL_ADAPTER_FEATURE_SHADER_INT16; + } + + shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; + hr = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0 && hr == S_OK) { + features |= PAL_ADAPTER_FEATURE_SHADER_INT64; + } + + if (options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED) { + features |= PAL_ADAPTER_FEATURE_MULTI_VIEW; + } + + if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED) { + features |= PAL_ADAPTER_FEATURE_RAY_TRACING; + } + + if (options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED) { + features |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE; + features |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT; + } + + if (options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED) { + features |= PAL_ADAPTER_FEATURE_MESH_SHADER; + } + + if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_3) { + features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + } + + // this features are supported on d3d12 + features |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; + features |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; + features |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; + features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; + features |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; + features |= PAL_ADAPTER_FEATURE_SWAPCHAIN; + features |= PAL_ADAPTER_FEATURE_FENCE_RESET; + features |= PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE; + features |= PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY; + features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; + + device->lpVtbl->Release(device); + return features; +} // ================================================== // Device @@ -68,11 +464,20 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); PalResult PAL_CALL createDeviceD3D12( PalAdapter* adapter, PalAdapterFeatures features, - PalDevice** outDevice); + PalDevice** outDevice) +{ + +} + +void PAL_CALL destroyDeviceD3D12(PalDevice* device) +{ + +} -void PAL_CALL destroyDeviceD3D12(PalDevice* device); +PalResult PAL_CALL waitDeviceD3D12(PalDevice* device) +{ -PalResult PAL_CALL waitDeviceD3D12(PalDevice* device); +} // ================================================== // Memory @@ -83,22 +488,34 @@ PalResult PAL_CALL allocateMemoryD3D12( PalMemoryType type, Uint64 memoryMask, Uint64 size, - PalMemory** outMemory); + PalMemory** outMemory) +{ + +} void PAL_CALL freeMemoryD3D12( PalDevice* device, - PalMemory* memory); + PalMemory* memory) +{ + +} PalResult PAL_CALL mapMemoryD3D12( PalDevice* device, PalMemory* memory, Uint64 offset, Uint64 size, - void** outPtr); + void** outPtr) +{ + +} void PAL_CALL unmapMemoryD3D12( PalDevice* device, - PalMemory* memory); + PalMemory* memory) +{ + +} // ================================================== // Extended Adapter Features @@ -106,23 +523,38 @@ void PAL_CALL unmapMemoryD3D12( PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( PalDevice* device, - PalDepthStencilCapabilities* caps); + PalDepthStencilCapabilities* caps) +{ + +} PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( PalDevice* device, - PalFragmentShadingRateCapabilities* caps); + PalFragmentShadingRateCapabilities* caps) +{ + +} PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( PalDevice* device, - PalMeshShaderCapabilities* caps); + PalMeshShaderCapabilities* caps) +{ + +} PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( PalDevice* device, - PalRayTracingCapabilities* caps); + PalRayTracingCapabilities* caps) +{ + +} PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( PalDevice* device, - PalDescriptorIndexingCapabilities* caps); + PalDescriptorIndexingCapabilities* caps) +{ + +} // ================================================== // Queue @@ -131,15 +563,27 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( PalResult PAL_CALL createQueueD3D12( PalDevice* device, PalQueueType type, - PalQueue** outQueue); + PalQueue** outQueue) +{ -void PAL_CALL destroyQueueD3D12(PalQueue* queue); +} -PalResult PAL_CALL waitQueueD3D12(PalQueue* queue); +void PAL_CALL destroyQueueD3D12(PalQueue* queue) +{ + +} + +PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) +{ + +} bool PAL_CALL canQueuePresentD3D12( PalQueue* queue, - PalSurface* surface); + PalSurface* surface) +{ + +} // ================================================== // Formats @@ -148,19 +592,31 @@ bool PAL_CALL canQueuePresentD3D12( PalResult PAL_CALL enumerateFormatsD3D12( PalAdapter* adapter, Int32* count, - PalFormatInfo* outFormats); + PalFormatInfo* outFormats) +{ + +} bool PAL_CALL isFormatSupportedD3D12( PalAdapter* adapter, - PalFormat format); + PalFormat format) +{ + +} PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( PalAdapter* adapter, - PalFormat format); + PalFormat format) +{ + +} PalImageViewUsages PAL_CALL queryFormatImageViewUsagesD3D12( PalAdapter* adapter, - PalFormat format); + PalFormat format) +{ + +} // ================================================== // Image @@ -169,22 +625,37 @@ PalImageViewUsages PAL_CALL queryFormatImageViewUsagesD3D12( PalResult PAL_CALL createImageD3D12( PalDevice* device, const PalImageCreateInfo* info, - PalImage** outImage); + PalImage** outImage) +{ -void PAL_CALL destroyImageD3D12(PalImage* image); +} + +void PAL_CALL destroyImageD3D12(PalImage* image) +{ + +} PalResult PAL_CALL getImageInfoD3D12( PalImage* image, - PalImageInfo* info); + PalImageInfo* info) +{ + +} PalResult PAL_CALL getImageMemoryRequirementsD3D12( PalImage* image, - PalMemoryRequirements* requirements); + PalMemoryRequirements* requirements) +{ + +} PalResult PAL_CALL bindImageMemoryD3D12( PalImage* image, PalMemory* memory, - Uint64 offset); + Uint64 offset) +{ + +} // ================================================== // Image View @@ -194,9 +665,15 @@ PalResult PAL_CALL createImageViewD3D12( PalDevice* device, PalImage* image, const PalImageViewCreateInfo* info, - PalImageView** outImageView); + PalImageView** outImageView) +{ + +} + +void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) +{ -void PAL_CALL destroyImageViewD3D12(PalImageView* imageView); +} // ================================================== // Sampler @@ -205,9 +682,15 @@ void PAL_CALL destroyImageViewD3D12(PalImageView* imageView); PalResult PAL_CALL createSamplerD3D12( PalDevice* device, const PalSamplerCreateInfo* info, - PalSampler** outSampler); + PalSampler** outSampler) +{ + +} + +void PAL_CALL destroySamplerD3D12(PalSampler* sampler) +{ -void PAL_CALL destroySamplerD3D12(PalSampler* sampler); +} // ================================================== // Surface @@ -216,14 +699,23 @@ void PAL_CALL destroySamplerD3D12(PalSampler* sampler); PalResult PAL_CALL createSurfaceD3D12( PalDevice* device, PalGraphicsWindow* window, - PalSurface** outSurface); + PalSurface** outSurface) +{ -void PAL_CALL destroySurfaceD3D12(PalSurface* surface); +} + +void PAL_CALL destroySurfaceD3D12(PalSurface* surface) +{ + +} PalResult PAL_CALL getSurfaceCapabilitiesD3D12( PalDevice* device, PalSurface* surface, - PalSurfaceCapabilities* caps); + PalSurfaceCapabilities* caps) +{ + +} // ================================================== // Swapchain @@ -234,22 +726,37 @@ PalResult PAL_CALL createSwapchainD3D12( PalQueue* queue, PalSurface* surface, const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain); + PalSwapchain** outSwapchain) +{ + +} -void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain); +void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) +{ + +} PalImage* PAL_CALL getSwapchainImageD3D12( PalSwapchain* swapchain, - Int32 index); + Int32 index) +{ + +} PalResult PAL_CALL getNextSwapchainImageD3D12( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32* outIndex); + Uint32* outIndex) +{ + +} PalResult PAL_CALL presentSwapchainD3D12( PalSwapchain* swapchain, - PalSwapchainPresentInfo* info); + PalSwapchainPresentInfo* info) +{ + +} // ================================================== // Shader @@ -258,9 +765,15 @@ PalResult PAL_CALL presentSwapchainD3D12( PalResult PAL_CALL createShaderD3D12( PalDevice* device, const PalShaderCreateInfo* info, - PalShader** outShader); + PalShader** outShader) +{ -void PAL_CALL destroyShaderD3D12(PalShader* shader); +} + +void PAL_CALL destroyShaderD3D12(PalShader* shader) +{ + +} // ================================================== // Fence @@ -269,17 +782,32 @@ void PAL_CALL destroyShaderD3D12(PalShader* shader); PalResult PAL_CALL createFenceD3D12( PalDevice* device, bool signaled, - PalFence** outFence); + PalFence** outFence) +{ + +} + +void PAL_CALL destroyFenceD3D12(PalFence* fence) +{ -void PAL_CALL destroyFenceD3D12(PalFence* fence); +} PalResult PAL_CALL waitFenceD3D12( PalFence* fence, - Uint64 timeout); + Uint64 timeout) +{ -PalResult PAL_CALL resetFenceD3D12(PalFence* fence); +} -bool PAL_CALL isFenceSignaledD3D12(PalFence* fence); +PalResult PAL_CALL resetFenceD3D12(PalFence* fence) +{ + +} + +bool PAL_CALL isFenceSignaledD3D12(PalFence* fence) +{ + +} // ================================================== // Semaphore @@ -287,23 +815,38 @@ bool PAL_CALL isFenceSignaledD3D12(PalFence* fence); PalResult PAL_CALL createSemaphoreD3D12( PalDevice* device, - PalSemaphore** outSemaphore); + PalSemaphore** outSemaphore) +{ + +} -void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); +void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore) +{ + +} PalResult PAL_CALL waitSemaphoreD3D12( PalSemaphore* semaphore, Uint64 value, - Uint64 timeout); + Uint64 timeout) +{ + +} PalResult PAL_CALL signalSemaphoreD3D12( PalSemaphore* semaphore, PalQueue* queue, - Uint64 value); + Uint64 value) +{ + +} PalResult PAL_CALL getSemaphoreValueD3D12( PalSemaphore* semaphore, - Uint64* value); + Uint64* value) +{ + +} // ================================================== // Command Pool And Buffer @@ -312,25 +855,46 @@ PalResult PAL_CALL getSemaphoreValueD3D12( PalResult PAL_CALL createCommandPoolD3D12( PalDevice* device, PalQueue* queue, - PalCommandPool** outPool); + PalCommandPool** outPool) +{ -void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool); +} -PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool); +void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) +{ + +} + +PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool) +{ + +} PalResult PAL_CALL allocateCommandBufferD3D12( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, - PalCommandBuffer** outBuffer); + PalCommandBuffer** outBuffer) +{ + +} -void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* buffer); +void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* buffer) +{ -PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer); +} + +PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) +{ + +} PalResult PAL_CALL submitCommandBufferD3D12( PalQueue* queue, - PalCommandBufferSubmitInfo* info); + PalCommandBufferSubmitInfo* info) +{ + +} // ================================================== // Command Recording @@ -338,30 +902,48 @@ PalResult PAL_CALL submitCommandBufferD3D12( PalResult PAL_CALL cmdBeginD3D12( PalCommandBuffer* cmdBuffer, - PalRenderingLayoutInfo* info); + PalRenderingLayoutInfo* info) +{ + +} -PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer); +PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer) +{ + +} PalResult PAL_CALL cmdExecuteCommandBufferD3D12( PalCommandBuffer* primaryCmdBuffer, - PalCommandBuffer* secondaryCmdBuffer); + PalCommandBuffer* secondaryCmdBuffer) +{ + +} PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( PalCommandBuffer* cmdBuffer, - PalFragmentShadingRateState* state); + PalFragmentShadingRateState* state) +{ + +} PalResult PAL_CALL cmdDrawMeshTasksD3D12( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, - Uint32 groupCountZ); + Uint32 groupCountZ) +{ + +} PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 drawCount, - Uint32 stride); + Uint32 stride) +{ + +} PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( PalCommandBuffer* cmdBuffer, @@ -370,83 +952,128 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( Uint64 offset, Uint64 countBufferOffset, Uint32 maxDrawCount, - Uint32 stride); + Uint32 stride) +{ + +} PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( PalCommandBuffer* cmdBuffer, - PalAccelerationStructureBuildInfo* info); + PalAccelerationStructureBuildInfo* info) +{ + +} PalResult PAL_CALL cmdBeginRenderingD3D12( PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info); + PalRenderingInfo* info) +{ + +} + +PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer) +{ -PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer); +} PalResult PAL_CALL cmdCopyBufferD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, - PalBufferCopyInfo* copyInfo); + PalBufferCopyInfo* copyInfo) +{ + +} PalResult PAL_CALL cmdCopyBufferToImageD3D12( PalCommandBuffer* cmdBuffer, PalImage* dstImage, PalBuffer* srcBuffer, - PalBufferImageCopyInfo* copyInfo); + PalBufferImageCopyInfo* copyInfo) +{ + +} PalResult PAL_CALL cmdCopyImageD3D12( PalCommandBuffer* cmdBuffer, PalImage* dst, PalImage* src, - PalImageCopyInfo* copyInfo); + PalImageCopyInfo* copyInfo) +{ + +} PalResult PAL_CALL cmdCopyImageToBufferD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, - PalBufferImageCopyInfo* copyInfo); + PalBufferImageCopyInfo* copyInfo) +{ + +} PalResult PAL_CALL cmdBindPipelineD3D12( PalCommandBuffer* cmdBuffer, PalPipelineBindPoint bindPoint, - PalPipeline* pipeline); + PalPipeline* pipeline) +{ + +} PalResult PAL_CALL cmdSetViewportD3D12( PalCommandBuffer* cmdBuffer, Uint32 count, - PalViewport* viewports); + PalViewport* viewports) +{ + +} PalResult PAL_CALL cmdSetScissorsD3D12( PalCommandBuffer* cmdBuffer, Uint32 count, - PalRect2D* scissors); + PalRect2D* scissors) +{ + +} PalResult PAL_CALL cmdBindVertexBuffersD3D12( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, PalBuffer** buffers, - Uint64* offsets); + Uint64* offsets) +{ + +} PalResult PAL_CALL cmdBindIndexBufferD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, - PalIndexType type); + PalIndexType type) +{ + +} PalResult PAL_CALL cmdDrawD3D12( PalCommandBuffer* cmdBuffer, Uint32 vertexCount, Uint32 instanceCount, Uint32 firstVertex, - Uint32 firstInstance); + Uint32 firstInstance) +{ + +} PalResult PAL_CALL cmdDrawIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 count, - Uint32 stride); + Uint32 stride) +{ + +} PalResult PAL_CALL cmdDrawIndirectCountD3D12( PalCommandBuffer* cmdBuffer, @@ -455,7 +1082,10 @@ PalResult PAL_CALL cmdDrawIndirectCountD3D12( Uint64 offset, Uint64 countBufferOffset, Uint32 maxDrawCount, - Uint32 stride); + Uint32 stride) +{ + +} PalResult PAL_CALL cmdDrawIndexedD3D12( PalCommandBuffer* cmdBuffer, @@ -463,14 +1093,20 @@ PalResult PAL_CALL cmdDrawIndexedD3D12( Uint32 instanceCount, Uint32 firstIndex, Int32 vertexOffset, - Uint32 firstInstance); + Uint32 firstInstance) +{ + +} PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, Uint32 count, - Uint32 stride); + Uint32 stride) +{ + +} PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( PalCommandBuffer* cmdBuffer, @@ -479,31 +1115,46 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( Uint64 offset, Uint64 countBufferOffset, Uint32 maxDrawCount, - Uint32 stride); + Uint32 stride) +{ + +} PalResult PAL_CALL cmdMemoryBarrierD3D12( PalCommandBuffer* cmdBuffer, PalUsageStateInfo* oldsUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); + PalUsageStateInfo* newUsageStateInfo) +{ + +} PalResult PAL_CALL cmdImageBarrierD3D12( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); + PalUsageStateInfo* newUsageStateInfo) +{ + +} PalResult PAL_CALL cmdBufferBarrierD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); + PalUsageStateInfo* newUsageStateInfo) +{ + +} PalResult PAL_CALL cmdDispatchD3D12( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, - Uint32 groupCountZ); + Uint32 groupCountZ) +{ + +} PalResult PAL_CALL cmdDispatchBaseD3D12( PalCommandBuffer* cmdBuffer, @@ -512,12 +1163,18 @@ PalResult PAL_CALL cmdDispatchBaseD3D12( Uint32 baseGroupZ, Uint32 groupCountX, Uint32 groupCountY, - Uint32 groupCountZ); + Uint32 groupCountZ) +{ + +} PalResult PAL_CALL cmdDispatchIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset); + Uint64 offset) +{ + +} PalResult PAL_CALL cmdTraceRaysD3D12( PalCommandBuffer* cmdBuffer, @@ -525,20 +1182,29 @@ PalResult PAL_CALL cmdTraceRaysD3D12( Uint32 raygenIndex, Uint32 width, Uint32 height, - Uint32 depth); + Uint32 depth) +{ + +} PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalCommandBuffer* cmdBuffer, Uint32 raygenIndex, PalShaderBindingTable* sbt, - PalDeviceAddress bufferAddress); + PalDeviceAddress bufferAddress) +{ + +} PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, Uint32 setIndex, - PalDescriptorSet* set); + PalDescriptorSet* set) +{ + +} PalResult PAL_CALL cmdPushConstantsD3D12( PalCommandBuffer* cmdBuffer, @@ -547,27 +1213,45 @@ PalResult PAL_CALL cmdPushConstantsD3D12( PalShaderStage* shaderStages, Uint32 offset, Uint32 size, - const void* value); + const void* value) +{ + +} PalResult PAL_CALL cmdSetCullModeD3D12( PalCommandBuffer* cmdBuffer, - PalCullMode cullMode); + PalCullMode cullMode) +{ + +} PalResult PAL_CALL cmdSetFrontFaceD3D12( PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace); + PalFrontFace frontFace) +{ + +} PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology); + PalPrimitiveTopology topology) +{ + +} PalResult PAL_CALL cmdSetDepthTestEnableD3D12( PalCommandBuffer* cmdBuffer, - bool enable); + bool enable) +{ + +} PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( PalCommandBuffer* cmdBuffer, - bool enable); + bool enable) +{ + +} PalResult PAL_CALL cmdSetStencilOpD3D12( PalCommandBuffer* cmdBuffer, @@ -575,7 +1259,10 @@ PalResult PAL_CALL cmdSetStencilOpD3D12( PalStencilOp failOp, PalStencilOp passOp, PalStencilOp depthFailOp, - PalCompareOp compareOp); + PalCompareOp compareOp) +{ + +} // ================================================== // Acceleration Structure @@ -584,14 +1271,23 @@ PalResult PAL_CALL cmdSetStencilOpD3D12( PalResult PAL_CALL createAccelerationstructureD3D12( PalDevice* device, const PalAccelerationStructureCreateInfo* info, - PalAccelerationStructure** outAs); + PalAccelerationStructure** outAs) +{ + +} -void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as); +void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as) +{ + +} PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( PalDevice* device, PalAccelerationStructureBuildInfo* info, - PalAccelerationStructureBuildSize* size); + PalAccelerationStructureBuildSize* size) +{ + +} // ================================================== // Buffer @@ -600,31 +1296,52 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( PalResult PAL_CALL createBufferD3D12( PalDevice* device, const PalBufferCreateInfo* info, - PalBuffer** outBuffer); + PalBuffer** outBuffer) +{ -void PAL_CALL destroyBufferD3D12(PalBuffer* buffer); +} + +void PAL_CALL destroyBufferD3D12(PalBuffer* buffer) +{ + +} PalResult PAL_CALL getBufferMemoryRequirementsD3D12( PalBuffer* buffer, - PalMemoryRequirements* requirements); + PalMemoryRequirements* requirements) +{ + +} PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( PalDevice* device, PalInstanceBufferRequirements* requirements, - Uint32 instanceCount); + Uint32 instanceCount) +{ + +} PalResult PAL_CALL writeInstancesToMappedMemoryD3D12( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, - Uint32 instanceCount); + Uint32 instanceCount) +{ + +} PalResult PAL_CALL bindBufferMemoryD3D12( PalBuffer* buffer, PalMemory* memory, - Uint64 offset); + Uint64 offset) +{ + +} -PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); +PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer) +{ + +} // ================================================== // Descriptor Pool, Set and Layout @@ -633,31 +1350,55 @@ PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); PalResult PAL_CALL createDescriptorSetLayoutD3D12( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout); + PalDescriptorSetLayout** outLayout) +{ + +} -void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout); +void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout) +{ + +} PalResult PAL_CALL createDescriptorPoolD3D12( PalDevice* device, const PalDescriptorPoolCreateInfo* info, - PalDescriptorPool** outPool); + PalDescriptorPool** outPool) +{ + +} + +void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) +{ + +} -void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool); +PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool) +{ -PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool); +} PalResult PAL_CALL allocateDescriptorSetD3D12( PalDevice* device, PalDescriptorPool* pool, PalDescriptorSetLayout* layout, - PalDescriptorSet** outSet); + PalDescriptorSet** outSet) +{ -void PAL_CALL freeDescriptorSetD3D12(PalDescriptorSet* set); +} + +void PAL_CALL freeDescriptorSetD3D12(PalDescriptorSet* set) +{ + +} PalResult PAL_CALL updateDescriptorSetD3D12( PalDevice* device, Uint32 count, - PalDescriptorSetWriteInfo* infos); + PalDescriptorSetWriteInfo* infos) +{ + +} // ================================================== // Pipeline Layout @@ -666,9 +1407,15 @@ PalResult PAL_CALL updateDescriptorSetD3D12( PalResult PAL_CALL createPipelineLayoutD3D12( PalDevice* device, const PalPipelineLayoutCreateInfo* info, - PalPipelineLayout** outLayout); + PalPipelineLayout** outLayout) +{ + +} -void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout); +void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout) +{ + +} // ================================================== // Pipeline @@ -677,19 +1424,31 @@ void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout); PalResult PAL_CALL createGraphicsPipelineD3D12( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, - PalPipeline** outPipeline); + PalPipeline** outPipeline) +{ + +} PalResult PAL_CALL createComputePipelineD3D12( PalDevice* device, const PalComputePipelineCreateInfo* info, - PalPipeline** outPipeline); + PalPipeline** outPipeline) +{ + +} PalResult PAL_CALL createRayTracingPipelineD3D12( PalDevice* device, const PalRayTracingPipelineCreateInfo* info, - PalPipeline** outPipeline); + PalPipeline** outPipeline) +{ + +} -void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline); +void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) +{ + +} // ================================================== // Shader Binding Table @@ -698,8 +1457,16 @@ void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline); PalResult PAL_CALL createShaderBindingTableD3D12( PalDevice* device, const PalShaderBindingTableCreateInfo* info, - PalShaderBindingTable** outSbt); + PalShaderBindingTable** outSbt) +{ + +} + +void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) +{ + +} -void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); +#endif // PAL_HAS_D3D12 -#endif // PAL_HAS_D3D12 \ No newline at end of file +#endif // __WIN32 \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 4c7705a9..e0be0ca8 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -2002,45 +2002,47 @@ PalResult PAL_CALL palInitGraphics( return PAL_RESULT_INVALID_ALLOCATOR; } + PalResult result; + BackendData* attachedBackend = nullptr; #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - PalResult result = initGraphicsVk(debugger, allocator); + result = initGraphicsVk(debugger, allocator); if (result != PAL_RESULT_SUCCESS) { - return PAL_RESULT_PLATFORM_FAILURE; + return result; } - BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; - attached->base = &s_VkBackend; - attached->startIndex = 0; - attached->count = 0; + attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + attachedBackend->base = &s_VkBackend; + attachedBackend->startIndex = 0; + attachedBackend->count = 0; #endif // PAL_HAS_VULKAN // D3D12 #if PAL_HAS_D3D12 - PalResult result = initGraphicsD3D12(debugger, allocator); + result = initGraphicsD3D12(debugger, allocator); if (result != PAL_RESULT_SUCCESS) { - return PAL_RESULT_PLATFORM_FAILURE; + return result; } - BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; - attached->base = &s_D3D12Backend; - attached->startIndex = 0; - attached->count = 0; + attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + attachedBackend->base = &s_D3D12Backend; + attachedBackend->startIndex = 0; + attachedBackend->count = 0; #endif // PAL_HAS_D3D12 #elif defined(__linux__) // vulkan #if PAL_HAS_VULKAN - PalResult result = initGraphicsVk(debugger, allocator); + result = initGraphicsVk(debugger, allocator); if (result != PAL_RESULT_SUCCESS) { - return PAL_RESULT_PLATFORM_FAILURE; + return result; } - BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; - attached->base = &s_VkBackend; - attached->startIndex = 0; - attached->count = 0; + attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + attachedBackend->base = &s_VkBackend; + attachedBackend->startIndex = 0; + attachedBackend->count = 0; #endif // PAL_HAS_VULKAN #else // metal or andriod @@ -2106,31 +2108,37 @@ PalResult PAL_CALL palEnumerateAdapters( PalResult result; int totalCount = 0; int index = 0; - int _count = outAdapters ? *count : 0; + int _count = 0; for (int i = 0; i < s_Graphics.backendCount; i++) { BackendData* backend = &s_Graphics.backends[i]; if (outAdapters) { // offset into the array so all backends write at the correct index PalAdapter** adapters = &outAdapters[backend->startIndex]; + _count = backend->count; result = backend->base->enumerateAdapters(&_count, adapters); + // break if a backend fails + if (result != PAL_RESULT_SUCCESS) { + return result; + } for (int j = 0; j < _count; j++) { + PalAdapter* tmp = adapters[j]; adapters[j]->backend = backend->base; } } else { result = backend->base->enumerateAdapters(&_count, nullptr); + // break if a backend fails + if (result != PAL_RESULT_SUCCESS) { + return result; + } + backend->startIndex = totalCount; backend->count = _count; totalCount += _count; _count = 0; } - - // break if a backend fails - if (result != PAL_RESULT_SUCCESS) { - return result; - } } if (!outAdapters) { diff --git a/tests/graphics_test.c b/tests/graphics_test.c index 2c56dd71..f284a645 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -63,15 +63,15 @@ bool graphicsTest() } features = palGetAdapterFeatures(adapter); - Uint32 vramGb = info.vram / (1024.0 * 1024.0 * 1024.0); - Uint32 sharedMemGb = info.sharedMemory / (1024.0 * 1024.0 * 1024.0); + Uint32 vramMb = info.vram / (1024.0 * 1024.0); + Uint32 sharedMemMb = info.sharedMemory / (1024.0 * 1024.0); palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Backend Name: %s", info.backendName); palLog(nullptr, " Vendor Id: %d", info.vendorId); palLog(nullptr, " Device Id: %d", info.deviceId); - palLog(nullptr, " Vram %dGB", vramGb); - palLog(nullptr, " Shared Memory %dGB", sharedMemGb); + palLog(nullptr, " Vram %dMB", vramMb); + palLog(nullptr, " Shared Memory %dMB", sharedMemMb); palLog(nullptr, " API Version: %s", info.versionString); const char* typeString; @@ -225,7 +225,7 @@ bool graphicsTest() } if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { - palLog(nullptr, " Fragment rendering rate"); + palLog(nullptr, " Fragment shading rate"); } if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { diff --git a/tests/tests_main.c b/tests/tests_main.c index d7e9a0d3..e73e2b84 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,15 +58,15 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS registerTest(graphicsTest); - registerTest(computeTest); - registerTest(rayTracingTest); + // registerTest(computeTest); + // registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest(clearColorTest); - registerTest(triangleTest); - registerTest(meshTest); - registerTest(textureTest); + // registerTest(clearColorTest); + // registerTest(triangleTest); + // registerTest(meshTest); + // registerTest(textureTest); #endif // runTests(); From 7f58d7155544371807845bdad93ba967d59c659c Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 30 Mar 2026 12:55:52 +0000 Subject: [PATCH 130/372] add device API d3d12 and remove device wait function --- include/pal/pal_graphics.h | 30 +-------- src/graphics/pal_d3d12.c | 125 ++++++++++++++++++++++++++++++++++-- src/graphics/pal_graphics.c | 16 ----- src/graphics/pal_vulkan.c | 21 +----- tests/clear_color_test.c | 4 +- tests/compute_test.c | 2 +- tests/mesh_test.c | 4 +- tests/tests_main.c | 4 +- tests/texture_test.c | 4 +- tests/triangle_test.c | 4 +- 10 files changed, 136 insertions(+), 78 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 4289ff08..9addfd2c 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2651,13 +2651,6 @@ typedef struct { */ void PAL_CALL (*destroyDevice)(PalDevice* device); - /** - * Backend implementation of ::palWaitDevice. - * - * Must obey the rules and semantics documented in palWaitDevice(). - */ - PalResult PAL_CALL (*waitDevice)(PalDevice* device); - /** * Backend implementation of ::palAllocateMemory. * @@ -3845,6 +3838,9 @@ PAL_API PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backe * The debugger and allocator will not not copied, therefore the pointers must remain valid * until the graphics system is shutdown. Set the debugger or PalGraphicsDebugger::callback to * nullptr to disable debugging and validation layers. + * + * If `debugger` is not nullptr and there is no debug layers, this function will not fail but + * debugging will be disabled. * * @param[in] debugger Optional debugger. Set to nullptr to disable debugging and validation * layers. @@ -4019,26 +4015,6 @@ PAL_API PalResult PAL_CALL palCreateDevice( */ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); -/** - * @brief Blocks indefinitely until the device becomes idle. - * - * The graphics system must be initialized before this call. - * - * This function blocks indefinitely until all submitted work on the device has been completetd. - * Returns `PAL_RESULT_SUCCESS` to indicate all pending operations has been completetd. - * - * @param[in] device Pointer to device to wait. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if `device` is externally synchronized. - * - * @since 1.4 - * @ingroup pal_graphics - */ -PAL_API PalResult PAL_CALL palWaitDevice(PalDevice* device); - /** * @brief Allocates GPU memory for the specified device. * diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 7ae11330..82fcdb97 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -33,15 +33,24 @@ freely, subject to the following restrictions: #include #include #include +#include // ================================================== // Typedefs, enums and structs // ================================================== +// on older SDKs, D3D_FEATURE_LEVEL_12_2 is not defined +#ifndef D3D_FEATURE_LEVEL_12_2 +#define D3D_FEATURE_LEVEL_12_2 0xc200 +#endif // D3D_FEATURE_LEVEL_12_2 + // IIDS const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; const IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0xd2,0x4e}; const IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0,0x3c, 0x77,0x90,0x0a,0x0a,0x1d,0x17}; +const IID IID_Debug = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0}; +const IID IID_Debug1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; +const IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4,0xe6,0x14,0x58}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -55,17 +64,30 @@ typedef struct { } Adapter; typedef struct { + bool debugLayer; HMODULE handle; HMODULE dxgi; Adapter* adapters; IDXGIFactory6* factory; + ID3D12Debug* debugController; + ID3D12Debug1* debugController1; PFN_D3D12_CREATE_DEVICE createDevice; PFN_CreateDXGIFactory2 createDXGIFactory; + PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface; const PalAllocator* allocator; } D3D12; +typedef struct { + const PalGraphicsBackend* backend; + + PalAdapterFeatures features; + IDXGIAdapter4* adapter; + ID3D12InfoQueue* infoQueue; + ID3D12Device* handle; +} Device; + static D3D12 s_D3D12 = {0}; // ================================================== @@ -96,6 +118,29 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D12.dxgi, "CreateDXGIFactory2"); + if (debugger && debugger->callback) { + s_D3D12.getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress( + s_D3D12.handle, + "D3D12GetDebugInterface"); + + if (s_D3D12.getDebugInterface) { + HRESULT hr; + hr = s_D3D12.getDebugInterface(&IID_Debug, (void**)&s_D3D12.debugController); + if (SUCCEEDED(hr)) { + s_D3D12.debugController->lpVtbl->EnableDebugLayer(s_D3D12.debugController); + } + + hr = s_D3D12.getDebugInterface(&IID_Debug1, (void**)&s_D3D12.debugController1); + if (SUCCEEDED(hr)) { + s_D3D12.debugController1->lpVtbl->SetEnableGPUBasedValidation( + s_D3D12.debugController1, + TRUE); + } + + s_D3D12.debugLayer = true; + } + } + // clang-format on s_D3D12.factory = nullptr; @@ -105,11 +150,20 @@ PalResult PAL_CALL initGraphicsD3D12( return PAL_RESULT_PLATFORM_FAILURE; } + s_D3D12.allocator = allocator; return PAL_RESULT_SUCCESS; } void PAL_CALL shutdownGraphicsD3D12() { + if (s_D3D12.debugController) { + s_D3D12.debugController->lpVtbl->Release(s_D3D12.debugController); + } + + if (s_D3D12.debugController1) { + s_D3D12.debugController1->lpVtbl->Release(s_D3D12.debugController1); + } + s_D3D12.factory->lpVtbl->Release(s_D3D12.factory); FreeLibrary(s_D3D12.handle); FreeLibrary(s_D3D12.dxgi); @@ -216,7 +270,7 @@ PalResult PAL_CALL getAdapterInfoD3D12( // create a temporary device to check the supported version Uint32 levelIndex = 0; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 5; i++) { result = s_D3D12.createDevice( (IUnknown*)adapterHandle, levels[i], @@ -338,7 +392,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) D3D_FEATURE_LEVEL_11_0 }; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 5; i++) { result = s_D3D12.createDevice( (IUnknown*)adapterHandle, levels[i], @@ -466,17 +520,76 @@ PalResult PAL_CALL createDeviceD3D12( PalAdapterFeatures features, PalDevice** outDevice) { + HRESULT result; + Device* device = nullptr; + Adapter* d3d12Adapter = (Adapter*)adapter; -} + device = palAllocate(s_D3D12.allocator, sizeof(Device), 0); + if (!device) { + return PAL_RESULT_OUT_OF_MEMORY; + } -void PAL_CALL destroyDeviceD3D12(PalDevice* device) -{ + memset(device, 0, sizeof(Device)); + D3D_FEATURE_LEVEL levels[] = { + D3D_FEATURE_LEVEL_12_2, + D3D_FEATURE_LEVEL_12_1, + D3D_FEATURE_LEVEL_12_0, + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0 + }; + + for (int i = 0; i < 5; i++) { + result = s_D3D12.createDevice( + (IUnknown*)d3d12Adapter->handle, + levels[i], + &IID_Device, + (void**)&device->handle); + + if (SUCCEEDED(result)) { + break; + } + } + + if (s_D3D12.debugLayer) { + result = device->handle->lpVtbl->QueryInterface( + device->handle, + &IID_InfoQueue, + (void**)&device->infoQueue); + + if (SUCCEEDED(result)) { + D3D12_MESSAGE_SEVERITY severities[] = { + D3D12_MESSAGE_SEVERITY_WARNING, + D3D12_MESSAGE_SEVERITY_ERROR, + D3D12_MESSAGE_SEVERITY_CORRUPTION + }; + + D3D12_MESSAGE_ID denyIDs[] = { D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE }; + + D3D12_INFO_QUEUE_FILTER filter = {0}; + filter.AllowList.NumSeverities = 3; + filter.AllowList.pSeverityList = severities; + filter.DenyList.NumIDs = 1; + filter.DenyList.pIDList = denyIDs; + device->infoQueue->lpVtbl->PushStorageFilter(device->infoQueue, &filter); + } + } + + device->adapter = d3d12Adapter->handle; + device->features = features; + *outDevice = (PalDevice*)device; + return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL waitDeviceD3D12(PalDevice* device) +void PAL_CALL destroyDeviceD3D12(PalDevice* device) { + Device* d3d12Device = (Device*)device; + d3d12Device->handle->lpVtbl->Release(d3d12Device->handle); + if (d3d12Device->infoQueue) { + d3d12Device->infoQueue->lpVtbl->Release(d3d12Device->infoQueue); + } + palFree(s_D3D12.allocator, d3d12Device); } // ================================================== diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index e0be0ca8..5fa32cdf 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -774,7 +774,6 @@ static PalGraphicsBackend s_VkBackend = { // device .createDevice = createDeviceVk, .destroyDevice = destroyDeviceVk, - .waitDevice = waitDeviceVk, // memory .allocateMemory = allocateMemoryVk, @@ -1618,7 +1617,6 @@ static PalGraphicsBackend s_D3D12Backend = { // device .createDevice = createDeviceD3D12, .destroyDevice = destroyDeviceD3D12, - .waitDevice = waitDeviceD3D12, // memory .allocateMemory = allocateMemoryD3D12, @@ -1818,7 +1816,6 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) // device !backend->createDevice || !backend->destroyDevice || - !backend->waitDevice || // memory !backend->allocateMemory || @@ -2222,19 +2219,6 @@ void PAL_CALL palDestroyDevice(PalDevice* device) } } -PalResult PAL_CALL palWaitDevice(PalDevice* device) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device) { - return PAL_RESULT_NULL_POINTER; - } - - return device->backend->waitDevice(device); -} - PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 87af0497..9af81028 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -347,7 +347,6 @@ typedef struct { PFN_vkDestroyPipeline destroyPipeline; PFN_vkCreateDebugUtilsMessengerEXT createMessenger; PFN_vkDestroyDebugUtilsMessengerEXT destroyMessenger; - PFN_vkDeviceWaitIdle waitDevice; PFN_vkQueueWaitIdle waitQueue; VkAllocationCallbacks vkAllocator; @@ -2641,10 +2640,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkDestroyPipeline"); - s_Vk.waitDevice = (PFN_vkDeviceWaitIdle)loadProc( - s_Vk.handle, - "vkDeviceWaitIdle"); - s_Vk.waitQueue = (PFN_vkQueueWaitIdle)loadProc( s_Vk.handle, "vkQueueWaitIdle"); @@ -2664,10 +2659,11 @@ PalResult PAL_CALL initGraphicsVk( Uint32 layerCount = 0; bool hasValidationLayer = false; s_Vk.messenger = nullptr; + s_Vk.allocator = allocator; VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {0}; debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - if (debugger) { + if (debugger && debugger->callback) { // layers result = s_Vk.enumerateInstanceLayerProperties(&layerCount, nullptr); if (result == VK_SUCCESS) { @@ -2794,7 +2790,7 @@ PalResult PAL_CALL initGraphicsVk( instanceCreateInfo.ppEnabledExtensionNames = extensions; instanceCreateInfo.ppEnabledLayerNames = layers; - if (debugger) { + if (debugger && debugger->callback) { instanceCreateInfo.pNext = &debugCreateInfo; } @@ -4261,17 +4257,6 @@ void PAL_CALL destroyDeviceVk(PalDevice* device) palFree(s_Vk.allocator, vkDevice); } -PalResult PAL_CALL waitDeviceVk(PalDevice* device) -{ - Device* vkDevice = (Device*)device; - VkResult result = s_Vk.waitDevice(vkDevice->handle); - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - - return PAL_RESULT_SUCCESS; -} - // ================================================== // Memory // ================================================== diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index bded762e..f9b59bba 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -532,10 +532,10 @@ bool clearColorTest() currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } - result = palWaitDevice(device); + result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for device: %s", error); + palLog(nullptr, "Failed to wait for queue: %s", error); return false; } diff --git a/tests/compute_test.c b/tests/compute_test.c index cb863328..577c1b02 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -120,7 +120,7 @@ bool computeTest() PalAdapterFeatures adapterFeatures = 0; bool hasComputeQueue = false; for (Int32 i = 0; i < adapterCount; i++) { - adapter = adapters[i]; + adapter = adapters[1]; // TODO: remove result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 9d765ec9..aceff9c1 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -758,10 +758,10 @@ bool meshTest() currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } - result = palWaitDevice(device); + result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for device: %s", error); + palLog(nullptr, "Failed to wait for queue: %s", error); return false; } diff --git a/tests/tests_main.c b/tests/tests_main.c index e73e2b84..88a7373f 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,8 +57,8 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest); - // registerTest(computeTest); + // registerTest(graphicsTest); + registerTest(computeTest); // registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS diff --git a/tests/texture_test.c b/tests/texture_test.c index 21876903..ae5726bf 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -1330,10 +1330,10 @@ bool textureTest() currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } - result = palWaitDevice(device); + result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for device: %s", error); + palLog(nullptr, "Failed to wait for queue: %s", error); return false; } diff --git a/tests/triangle_test.c b/tests/triangle_test.c index c87a6f80..e3fe0555 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -950,10 +950,10 @@ bool triangleTest() currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; } - result = palWaitDevice(device); + result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for device: %s", error); + palLog(nullptr, "Failed to wait for queue: %s", error); return false; } From 6ee2784631a58779526e3f937fbcb2f30724f563 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 31 Mar 2026 10:43:50 +0000 Subject: [PATCH 131/372] change memory mapping API to per resource (image and buffers --- include/pal/pal_graphics.h | 208 +++++++++++++++++++++++------------- src/graphics/pal_d3d12.c | 71 +++++++++--- src/graphics/pal_graphics.c | 114 +++++++++++++------- src/graphics/pal_vulkan.c | 88 ++++++++++----- tests/compute_test.c | 8 +- tests/ray_tracing_test.c | 21 ++-- tests/texture_test.c | 15 ++- tests/triangle_test.c | 6 +- 8 files changed, 350 insertions(+), 181 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 9addfd2c..7f1f1778 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2672,27 +2672,6 @@ typedef struct { PalDevice* device, PalMemory* memory); - /** - * Backend implementation of ::palMapMemory. - * - * Must obey the rules and semantics documented in palMapMemory(). - */ - PalResult PAL_CALL (*mapMemory)( - PalDevice* device, - PalMemory* memory, - Uint64 offset, - Uint64 size, - void** outPtr); - - /** - * Backend implementation of ::palUnmapMemory. - * - * Must obey the rules and semantics documented in palUnmapMemory(). - */ - void PAL_CALL (*unmapMemory)( - PalDevice* device, - PalMemory* memory); - /** * Backend implementation of ::palQueryDepthStencilCapabilities. * @@ -2858,6 +2837,24 @@ typedef struct { PalMemory* memory, Uint64 offset); + /** + * Backend implementation of ::palMapImageMemory. + * + * Must obey the rules and semantics documented in palMapImageMemory(). + */ + PalResult PAL_CALL (*mapImageMemory)( + PalImage* image, + Uint64 offset, + Uint64 size, + void** outPtr); + + /** + * Backend implementation of ::palUnmapImageMemory. + * + * Must obey the rules and semantics documented in palUnmapImageMemory(). + */ + void PAL_CALL (*unmapImageMemory)(PalImage* image); + /** * Backend implementation of ::palCreateImageView. * @@ -3657,6 +3654,24 @@ typedef struct { PalMemory* memory, Uint64 offset); + /** + * Backend implementation of ::palMapBufferMemory. + * + * Must obey the rules and semantics documented in palMapBufferMemory(). + */ + PalResult PAL_CALL (*mapBufferMemory)( + PalBuffer* buffer, + Uint64 offset, + Uint64 size, + void** outPtr); + + /** + * Backend implementation of ::palUnmapBufferMemory. + * + * Must obey the rules and semantics documented in palUnmapBufferMemory(). + */ + void PAL_CALL (*unmapBufferMemory)(PalBuffer* buffer); + /** * Backend implementation of ::palGetBufferDeviceAddress. * @@ -4066,59 +4081,6 @@ PAL_API void PAL_CALL palFreeMemory( PalDevice* device, PalMemory* memory); -/** - * @brief Maps GPU memory to CPU visible address space. - * - * The graphics system must be initialized before this call. - * - * Only `PAL_MEMORY_TYPE_CPU_UPLOAD` and `PAL_MEMORY_TYPE_CPU_READBACK` can be mapped to - * CPU visible space. MApping `PAL_MEMORY_TYPE_GPU_ONLY` will fail and return - * `PAL_RESULT_MEMORY_MAP_FAILED`. - * - * @param[in] device Pointer to device memory belongs to. - * @param[in] memory Pointer to memory to map. - * @param[in] offset Starting point within the memory. - * @param[in] size Number of bytes to map from the offset. `offset + size` must not be - * greater than memory size. - * @param[out] outPtr Pointer to a void* to recieved the mapped memory. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if `device` and `memory` is externally synchronized. - * Mapping with different offsets into the same memory is thread safe as long as `device` - * is externally synchronized. - * - * @since 1.4 - * @ingroup pal_graphics - * @sa palUnmapMemory - */ -PAL_API PalResult PAL_CALL palMapMemory( - PalDevice* device, - PalMemory* memory, - Uint64 offset, - Uint64 size, - void** outPtr); - -/** - * @brief Unmap GPU memory from CPU visible address space. - * - * The graphics system must be initialized before this call. The memory must be mapped - * before this call. After this call, the CPU pointer must not be used anymore. - * - * @param[in] device Pointer to device memory belongs to. - * @param[in] memory Pointer to memory to unmap. - * - * Thread safety: Thread safe if `device` and `memory` is externally synchronized. - * - * @since 1.4 - * @ingroup pal_graphics - * @sa palMapMemory - */ -PAL_API void PAL_CALL palUnmapMemory( - PalDevice* device, - PalMemory* memory); - /** * @brief Get depth stencil feature capabilites or limits about a device. * @@ -4535,6 +4497,55 @@ PAL_API PalResult PAL_CALL palBindImageMemory( PalMemory* memory, Uint64 offset); +/** + * @brief Maps image to CPU visible address space. + * + * The graphics system must be initialized before this call. The image must have a valid + * memory bound to it before this call. + * + * Only `PAL_MEMORY_TYPE_CPU_UPLOAD` and `PAL_MEMORY_TYPE_CPU_READBACK` can be mapped to + * CPU visible space. Mapping `PAL_MEMORY_TYPE_GPU_ONLY` will fail and return + * `PAL_RESULT_MEMORY_MAP_FAILED`. + * + * @param[in] image Pointer to image to map. Memory must be bound. + * @param[in] offset Starting point within the image. + * @param[in] size Number of bytes to map from the offset. `offset + size` must not be + * greater than image size. + * @param[out] outPtr Pointer to a void* to recieved the mapped memory. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `image` is externally synchronized. + * Mapping with different offsets into the same image is thread safe as long as `image` + * is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palUnmapImageMemory + */ +PAL_API PalResult PAL_CALL palMapImageMemory( + PalImage* image, + Uint64 offset, + Uint64 size, + void** outPtr); + +/** + * @brief Unmap image from CPU visible address space. + * + * The graphics system must be initialized before this call. The image must be mapped + * before this call. After this call, the CPU pointer must not be used anymore. + * + * @param[in] image Pointer to image to unmap. + * + * Thread safety: Thread safe if `image` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palMapImageMemory + */ +PAL_API void PAL_CALL palUnmapImageMemory(PalImage* image); + /** * @brief Create an image view. * @@ -6573,6 +6584,55 @@ PAL_API PalResult PAL_CALL palBindBufferMemory( PalMemory* memory, Uint64 offset); +/** + * @brief Maps buffer to CPU visible address space. + * + * The graphics system must be initialized before this call. The buffer must have a valid + * memory bound to it before this call. + * + * Only `PAL_MEMORY_TYPE_CPU_UPLOAD` and `PAL_MEMORY_TYPE_CPU_READBACK` can be mapped to + * CPU visible space. Mapping `PAL_MEMORY_TYPE_GPU_ONLY` will fail and return + * `PAL_RESULT_MEMORY_MAP_FAILED`. + * + * @param[in] buffer Pointer to buffer to map. Memory must be bound. + * @param[in] offset Starting point within the buffer. + * @param[in] size Number of bytes to map from the offset. `offset + size` must not be + * greater than buffer size. + * @param[out] outPtr Pointer to a void* to recieved the mapped memory. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `buffer` is externally synchronized. + * Mapping with different offsets into the same buffer is thread safe as long as `buffer` + * is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palUnmapBufferMemory + */ +PAL_API PalResult PAL_CALL palMapBufferMemory( + PalBuffer* buffer, + Uint64 offset, + Uint64 size, + void** outPtr); + +/** + * @brief Unmap buffer from CPU visible address space. + * + * The graphics system must be initialized before this call. The buffer must be mapped + * before this call. After this call, the CPU pointer must not be used anymore. + * + * @param[in] buffer Pointer to buffer to unmap. + * + * Thread safety: Thread safe if `buffer` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palMapBufferMemory + */ +PAL_API void PAL_CALL palUnmapBufferMemory(PalBuffer* buffer); + /** * @brief Get the device address of the provided buffer. * diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 82fcdb97..4aad58c0 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -51,6 +51,7 @@ const IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0,0x3c, 0x77,0x90,0x0a,0 const IID IID_Debug = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0}; const IID IID_Debug1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; const IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4,0xe6,0x14,0x58}; +const IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -94,6 +95,7 @@ static D3D12 s_D3D12 = {0}; // Helper Functions // ================================================== + // ================================================== // Adapter // ================================================== @@ -603,31 +605,41 @@ PalResult PAL_CALL allocateMemoryD3D12( Uint64 size, PalMemory** outMemory) { + HRESULT result; + Device* d3d12Device = (Device*)device; + ID3D12Heap* memory = nullptr; -} + D3D12_HEAP_DESC desc = {0}; + desc.SizeInBytes = size; + + desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; + if (type == PAL_MEMORY_TYPE_CPU_READBACK) { + desc.Properties.Type = D3D12_HEAP_TYPE_READBACK; -void PAL_CALL freeMemoryD3D12( - PalDevice* device, - PalMemory* memory) -{ + } else if (type == PAL_MEMORY_TYPE_CPU_UPLOAD) { + desc.Properties.Type = D3D12_HEAP_TYPE_UPLOAD; + } -} + result = d3d12Device->handle->lpVtbl->CreateHeap( + d3d12Device->handle, + &desc, + &IID_Heap, + (void**)&memory); -PalResult PAL_CALL mapMemoryD3D12( - PalDevice* device, - PalMemory* memory, - Uint64 offset, - Uint64 size, - void** outPtr) -{ + if (FAILED(result)) { + return PAL_RESULT_OUT_OF_MEMORY; + } + *outMemory = (PalMemory*)memory; + return PAL_RESULT_SUCCESS; } -void PAL_CALL unmapMemoryD3D12( +void PAL_CALL freeMemoryD3D12( PalDevice* device, PalMemory* memory) { - + ID3D12Heap* mem = (ID3D12Heap*)memory; + mem->lpVtbl->Release(mem); } // ================================================== @@ -638,6 +650,7 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( PalDevice* device, PalDepthStencilCapabilities* caps) { + // TODO: } @@ -770,6 +783,20 @@ PalResult PAL_CALL bindImageMemoryD3D12( } +PalResult PAL_CALL mapImageMemoryD3D12( + PalImage* image, + Uint64 offset, + Uint64 size, + void** outPtr) +{ + +} + +void PAL_CALL unmapImageMemoryD3D12(PalImage* image) +{ + +} + // ================================================== // Image View // ================================================== @@ -1451,6 +1478,20 @@ PalResult PAL_CALL bindBufferMemoryD3D12( } +PalResult PAL_CALL mapBufferMemoryD3D12( + PalBuffer* buffer, + Uint64 offset, + Uint64 size, + void** outPtr) +{ + +} + +void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer) +{ + +} + PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer) { diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 5fa32cdf..c4982bd2 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -151,17 +151,6 @@ void PAL_CALL freeMemoryVk( PalDevice* device, PalMemory* memory); -PalResult PAL_CALL mapMemoryVk( - PalDevice* device, - PalMemory* memory, - Uint64 offset, - Uint64 size, - void** outPtr); - -void PAL_CALL unmapMemoryVk( - PalDevice* device, - PalMemory* memory); - // ================================================== // Extended Adapter Features // ================================================== @@ -248,6 +237,14 @@ PalResult PAL_CALL bindImageMemoryVk( PalMemory* memory, Uint64 offset); +PalResult PAL_CALL mapImageMemoryVk( + PalImage* image, + Uint64 offset, + Uint64 size, + void** outPtr); + +void PAL_CALL unmapImageMemoryVk(PalImage* image); + // ================================================== // Image View // ================================================== @@ -686,6 +683,14 @@ PalResult PAL_CALL bindBufferMemoryVk( PalMemory* memory, Uint64 offset); +PalResult PAL_CALL mapBufferMemoryVk( + PalBuffer* buffer, + Uint64 offset, + Uint64 size, + void** outPtr); + +void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer); + PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer); // ================================================== @@ -778,8 +783,6 @@ static PalGraphicsBackend s_VkBackend = { // memory .allocateMemory = allocateMemoryVk, .freeMemory = freeMemoryVk, - .mapMemory = mapMemoryVk, - .unmapMemory = unmapMemoryVk, // extended adapter features .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesVk, @@ -806,6 +809,8 @@ static PalGraphicsBackend s_VkBackend = { .getImageInfo = getImageInfoVk, .getImageMemoryRequirements = getImageMemoryRequirementsVk, .bindImageMemory = bindImageMemoryVk, + .mapImageMemory = mapImageMemoryVk, + .unmapImageMemory = unmapImageMemoryVk, // image view .createImageView = createImageViewVk, @@ -910,6 +915,8 @@ static PalGraphicsBackend s_VkBackend = { .writeInstancesToMappedMemory = writeInstancesToMappedMemoryVk, .bindBufferMemory = bindBufferMemoryVk, .getBufferDeviceAddress = getBufferDeviceAddressVk, + .mapBufferMemory = mapBufferMemoryVk, + .unmapBufferMemory = unmapBufferMemoryVk, // descriptor set layout, descriptor pool and descriptor set .createDescriptorSetLayout = createDescriptorSetLayoutVk, @@ -994,17 +1001,6 @@ void PAL_CALL freeMemoryD3D12( PalDevice* device, PalMemory* memory); -PalResult PAL_CALL mapMemoryD3D12( - PalDevice* device, - PalMemory* memory, - Uint64 offset, - Uint64 size, - void** outPtr); - -void PAL_CALL unmapMemoryD3D12( - PalDevice* device, - PalMemory* memory); - // ================================================== // Extended Adapter Features // ================================================== @@ -1091,6 +1087,14 @@ PalResult PAL_CALL bindImageMemoryD3D12( PalMemory* memory, Uint64 offset); +PalResult PAL_CALL mapImageMemoryD3D12( + PalImage* image, + Uint64 offset, + Uint64 size, + void** outPtr); + +void PAL_CALL unmapImageMemoryD3D12(PalImage* image); + // ================================================== // Image View // ================================================== @@ -1529,6 +1533,14 @@ PalResult PAL_CALL bindBufferMemoryD3D12( PalMemory* memory, Uint64 offset); +PalResult PAL_CALL mapBufferMemoryD3D12( + PalBuffer* buffer, + Uint64 offset, + Uint64 size, + void** outPtr); + +void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer); + PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); // ================================================== @@ -1621,8 +1633,6 @@ static PalGraphicsBackend s_D3D12Backend = { // memory .allocateMemory = allocateMemoryD3D12, .freeMemory = freeMemoryD3D12, - .mapMemory = mapMemoryD3D12, - .unmapMemory = unmapMemoryD3D12, // extended adapter features .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesD3D12, @@ -1649,6 +1659,8 @@ static PalGraphicsBackend s_D3D12Backend = { .getImageInfo = getImageInfoD3D12, .getImageMemoryRequirements = getImageMemoryRequirementsD3D12, .bindImageMemory = bindImageMemoryD3D12, + .mapImageMemory = mapImageMemoryD3D12, + .unmapImageMemory = unmapImageMemoryD3D12, // image view .createImageView = createImageViewD3D12, @@ -1753,6 +1765,8 @@ static PalGraphicsBackend s_D3D12Backend = { .writeInstancesToMappedMemory = writeInstancesToMappedMemoryD3D12, .bindBufferMemory = bindBufferMemoryD3D12, .getBufferDeviceAddress = getBufferDeviceAddressD3D12, + .mapBufferMemory = mapBufferMemoryD3D12, + .unmapBufferMemory = unmapBufferMemoryD3D12, // descriptor set layout, descriptor pool and descriptor set .createDescriptorSetLayout = createDescriptorSetLayoutD3D12, @@ -1820,8 +1834,6 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) // memory !backend->allocateMemory || !backend->freeMemory || - !backend->mapMemory || - !backend->unmapMemory || // extended adapter features !backend->queryDepthStencilCapabilities || @@ -1848,6 +1860,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->getImageInfo || !backend->getImageMemoryRequirements || !backend->bindImageMemory || + !backend->mapImageMemory || + !backend->unmapImageMemory || // image view !backend->createImageView || @@ -1952,6 +1966,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->writeInstancesToMappedMemory || !backend->bindBufferMemory || !backend->getBufferDeviceAddress || + !backend->mapBufferMemory || + !backend->unmapBufferMemory || // descriptor set layout, descriptor pool and descriptor set !backend->createDescriptorSetLayout || @@ -2523,6 +2539,30 @@ PalResult PAL_CALL palBindImageMemory( return image->backend->bindImageMemory(image, memory, offset); } +PalResult PAL_CALL palMapImageMemory( + PalImage* image, + Uint64 offset, + Uint64 size, + void** outPtr) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!image) { + return PAL_RESULT_NULL_POINTER; + } + + return image->backend->mapImageMemory(image, offset, size, outPtr); +} + +void PAL_CALL palUnmapImageMemory(PalImage* image) +{ + if (s_Graphics.initialized && image) { + image->backend->unmapImageMemory(image); + } +} + // ================================================== // Image View // ================================================== @@ -3957,9 +3997,8 @@ PalResult PAL_CALL palBindBufferMemory( return buffer->backend->bindBufferMemory(buffer, memory, offset); } -PalResult PAL_CALL palMapMemory( - PalDevice* device, - PalMemory* memory, +PalResult PAL_CALL palMapBufferMemory( + PalBuffer* buffer, Uint64 offset, Uint64 size, void** outPtr) @@ -3968,21 +4007,18 @@ PalResult PAL_CALL palMapMemory( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device || !memory || !outPtr) { + if (!buffer) { return PAL_RESULT_NULL_POINTER; } - return device->backend->mapMemory(device, memory, offset, size, outPtr); + return buffer->backend->mapBufferMemory(buffer, offset, size, outPtr); } -void PAL_CALL palUnmapMemory( - PalDevice* device, - PalMemory* memory) +void PAL_CALL palUnmapBufferMemory(PalBuffer* buffer) { - if (!s_Graphics.initialized || !device || !memory) { - return; + if (s_Graphics.initialized && buffer) { + buffer->backend->unmapBufferMemory(buffer); } - device->backend->unmapMemory(device, memory); } PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 9af81028..7b40887e 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -443,6 +443,7 @@ typedef struct { bool belongsToSwapchain; VkImageAspectFlags aspectMask; Device* device; + VkDeviceMemory memory; VkImage handle; PalImageInfo info; } Image; @@ -533,6 +534,7 @@ typedef struct { const PalGraphicsBackend* backend; PalBufferUsages usages; + VkDeviceMemory memory; Device* device; VkBuffer handle; } Buffer; @@ -4320,33 +4322,6 @@ void PAL_CALL freeMemoryVk( s_Vk.freeMemory(vkDevice->handle, mem, &s_Vk.vkAllocator); } -PalResult PAL_CALL mapMemoryVk( - PalDevice* device, - PalMemory* memory, - Uint64 offset, - Uint64 size, - void** outPtr) -{ - VkResult result; - VkDeviceMemory mem = (VkDeviceMemory)memory; - Device* vkDevice = (Device*)device; - - result = s_Vk.mapMemory(vkDevice->handle, mem, offset, size, 0, outPtr); - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL unmapMemoryVk( - PalDevice* device, - PalMemory* memory) -{ - VkDeviceMemory mem = (VkDeviceMemory)memory; - Device* vkDevice = (Device*)device; - s_Vk.unmapMemory(vkDevice->handle, mem); -} - // ================================================== // Extended Adapter Features // ================================================== @@ -4919,6 +4894,7 @@ PalResult PAL_CALL createImageVk( image->aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; } + image->memory = nullptr; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } @@ -4980,11 +4956,39 @@ PalResult PAL_CALL bindImageMemoryVk( return PAL_RESULT_INVALID_OPERATION; } + if (vkImage->memory) { + return PAL_RESULT_INVALID_OPERATION; + } + VkDeviceMemory mem = (VkDeviceMemory)memory; s_Vk.bindImageMemory(vkImage->device->handle, vkImage->handle, mem, offset); + vkImage->memory = mem; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL mapImageMemoryVk( + PalImage* image, + Uint64 offset, + Uint64 size, + void** outPtr) +{ + VkResult result; + Image* vkImage = (Image*)image; + Device* device = vkImage->device; + + result = s_Vk.mapMemory(device->handle, vkImage->memory, offset, size, 0, outPtr); + if (result != VK_SUCCESS) { + return resultFromVk(result); + } return PAL_RESULT_SUCCESS; } +void PAL_CALL unmapImageMemoryVk(PalImage* image) +{ + Image* vkImage = (Image*)image; + s_Vk.unmapMemory(vkImage->device->handle, vkImage->memory); +} + // ================================================== // Image View // ================================================== @@ -7670,6 +7674,7 @@ PalResult PAL_CALL createBufferVk( } buffer->device = vkDevice; + buffer->memory = nullptr; *outBuffer = (PalBuffer*)buffer; return PAL_RESULT_SUCCESS; } @@ -7745,13 +7750,42 @@ PalResult PAL_CALL bindBufferMemoryVk( VkDeviceMemory mem = (VkDeviceMemory)memory; Buffer* vkBuffer = (Buffer*)buffer; + if (vkBuffer->memory) { + return PAL_RESULT_INVALID_OPERATION; + } + result = s_Vk.bindBufferMemory(vkBuffer->device->handle, vkBuffer->handle, mem, offset); if (result != VK_SUCCESS) { return resultFromVk(result); } + + vkBuffer->memory = mem; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL mapBufferMemoryVk( + PalBuffer* buffer, + Uint64 offset, + Uint64 size, + void** outPtr) +{ + VkResult result; + Buffer* vkBuffer = (Buffer*)buffer; + Device* device = vkBuffer->device; + + result = s_Vk.mapMemory(device->handle, vkBuffer->memory, offset, size, 0, outPtr); + if (result != VK_SUCCESS) { + return resultFromVk(result); + } return PAL_RESULT_SUCCESS; } +void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer) +{ + Buffer* vkBuffer = (Buffer*)buffer; + s_Vk.unmapMemory(vkBuffer->device->handle, vkBuffer->memory); +} + PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer) { Buffer* vkBuffer = (Buffer*)buffer; diff --git a/tests/compute_test.c b/tests/compute_test.c index 577c1b02..3df4e55b 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -120,7 +120,7 @@ bool computeTest() PalAdapterFeatures adapterFeatures = 0; bool hasComputeQueue = false; for (Int32 i = 0; i < adapterCount; i++) { - adapter = adapters[1]; // TODO: remove + adapter = adapters[1]; // TODO: use the correct i index result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -611,10 +611,10 @@ bool computeTest() // now our staging buffer has the contents of the GPU buffer // we map it and copy the contents to a ppm buffer and save it void* ptr = nullptr; - result = palMapMemory(device, stagingBufferMemory, 0, bufferBytes, &ptr); + result = palMapBufferMemory(stagingBuffer, 0, bufferBytes, &ptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map memory: %s", error); + palLog(nullptr, "Failed to map buffer memory: %s", error); return false; } @@ -636,7 +636,7 @@ bool computeTest() } fclose(file); - palUnmapMemory(device, stagingBufferMemory); + palUnmapBufferMemory(stagingBuffer); palDestroyPipeline(pipeline); palDestroyPipelineLayout(pipelineLayout); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 0b43e495..5ecf52cd 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -436,15 +436,15 @@ bool rayTracingTest() // copy vertices void* data = nullptr; - result = palMapMemory(device, vertexBufferMemory, 0, sizeof(vertices), &data); + result = palMapBufferMemory(vertexBuffer, 0, sizeof(vertices), &data); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map memory: %s", error); + palLog(nullptr, "Failed to map buffer memory: %s", error); return false; } memcpy(data, vertices, sizeof(vertices)); - palUnmapMemory(device, vertexBufferMemory); + palUnmapBufferMemory(vertexBuffer); // fill BLAS and triangle geometry PalDeviceAddress vertexBufferAddress = palGetBufferDeviceAddress(vertexBuffer); @@ -585,16 +585,15 @@ bool rayTracingTest() // copy instance struct to the buffer data = nullptr; - result = palMapMemory( - device, - instanceBufferMemory, + result = palMapBufferMemory( + instanceBuffer, 0, instanceBufferReq.size, &data); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map memory: %s", error); + palLog(nullptr, "Failed to map buffer memory: %s", error); return false; } @@ -606,7 +605,7 @@ bool rayTracingTest() return false; } - palUnmapMemory(device, instanceBufferMemory); + palUnmapBufferMemory(instanceBuffer); // fill TLAS and instance geometry PalDeviceAddress instanceBufferAddress = palGetBufferDeviceAddress(instanceBuffer); @@ -1049,10 +1048,10 @@ bool rayTracingTest() // now our staging buffer has the contents of the GPU buffer // we map it and copy the contents to a ppm buffer and save it void* ptr = nullptr; - result = palMapMemory(device, stagingBufferMemory, 0, bufferBytes, &ptr); + result = palMapBufferMemory(stagingBuffer, 0, bufferBytes, &ptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map memory: %s", error); + palLog(nullptr, "Failed to map buffer memory: %s", error); return false; } @@ -1074,7 +1073,7 @@ bool rayTracingTest() } fclose(file); - palUnmapMemory(device, stagingBufferMemory); + palUnmapBufferMemory(stagingBuffer); palDestroyAccelerationstructure(blas); palDestroyAccelerationstructure(tlas); diff --git a/tests/texture_test.c b/tests/texture_test.c index ae5726bf..8c2e9df9 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -504,15 +504,15 @@ bool textureTest() // map the staging buffer and upload the vertices void* ptr = nullptr; - result = palMapMemory(device, stagingBufferMemory, 0, sizeof(vertices), &ptr); + result = palMapBufferMemory(stagingBuffer, 0, sizeof(vertices), &ptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map memory: %s", error); + palLog(nullptr, "Failed to map buffer memory: %s", error); return false; } memcpy(ptr, vertices, sizeof(vertices)); - palUnmapMemory(device, stagingBufferMemory); + palUnmapBufferMemory(stagingBuffer); PalFence* fence = nullptr; result = palCreateFence(device, false, &fence); @@ -621,21 +621,20 @@ bool textureTest() // copy data void* data = nullptr; - result = palMapMemory( - device, - imageStagingBufferMemory, + result = palMapBufferMemory( + imageStagingBuffer, 0, imageStagingBufferCreateInfo.size, &data); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map memory: %s", error); + palLog(nullptr, "Failed to map buffer memory: %s", error); return false; } memcpy(data, texture, imageStagingBufferCreateInfo.size); - palUnmapMemory(device, imageStagingBufferMemory); + palUnmapBufferMemory(imageStagingBuffer); // use the first command buffer to upload the copy // and reset it when done diff --git a/tests/triangle_test.c b/tests/triangle_test.c index e3fe0555..53fd673d 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -466,15 +466,15 @@ bool triangleTest() // map the staging buffer and upload the vertices void* ptr = nullptr; - result = palMapMemory(device, stagingBufferMemory, 0, sizeof(vertices), &ptr); + result = palMapBufferMemory(stagingBuffer, 0, sizeof(vertices), &ptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map memory: %s", error); + palLog(nullptr, "Failed to map buffer memory: %s", error); return false; } memcpy(ptr, vertices, sizeof(vertices)); - palUnmapMemory(device, stagingBufferMemory); + palUnmapBufferMemory(stagingBuffer); PalFence* tmpFence = nullptr; result = palCreateFence(device, false, &tmpFence); From edda41b1e1b09311200f327cf2df9de7fd724c6f Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 31 Mar 2026 11:41:34 +0000 Subject: [PATCH 132/372] add sampler anisotropy feature capabilities API --- include/pal/pal_graphics.h | 44 +++++++++++++++++++++++++++++++++++++ src/graphics/pal_d3d12.c | 14 +++++++++++- src/graphics/pal_graphics.c | 26 ++++++++++++++++++++++ src/graphics/pal_vulkan.c | 16 ++++++++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 7f1f1778..72564e33 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1414,6 +1414,17 @@ typedef struct { Uint32 maxComputeWorkGroupSize[3]; /**< Max compute threads per workgroup per axis.*/ } PalAdapterCapabilities; +/** + * @struct PalSamplerAnisotropyCapabilities + * @brief Sampler anisotropy capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 maxAnisotropy; +} PalSamplerAnisotropyCapabilities; + /** * @struct PalDepthStencilCapabilities * @brief Depth stencil capabilities of an adapter (GPU). @@ -2672,6 +2683,16 @@ typedef struct { PalDevice* device, PalMemory* memory); + /** + * Backend implementation of ::palQuerySamplerAnisotropyCapabilities. + * + * Must obey the rules and semantics documented in + * palQuerySamplerAnisotropyCapabilities(). + */ + PalResult PAL_CALL (*querySamplerAnisotropyCapabilities)( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps); + /** * Backend implementation of ::palQueryDepthStencilCapabilities. * @@ -4081,6 +4102,29 @@ PAL_API void PAL_CALL palFreeMemory( PalDevice* device, PalMemory* memory); +/** + * @brief Get sampler anisotropy feature capabilites or limits about a device. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to query sampler anisotropy feature capabilities on. + * @param[out] caps Pointer to a PalSamplerAnisotropyCapabilities to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `caps` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps); + /** * @brief Get depth stencil feature capabilites or limits about a device. * diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 4aad58c0..ee510c9f 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -646,11 +646,23 @@ void PAL_CALL freeMemoryD3D12( // Extended Adapter Features // ================================================== +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps) +{ + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + caps->maxAnisotropy = 16; // default on most d3d12 hardwares + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( PalDevice* device, PalDepthStencilCapabilities* caps) { - // TODO: } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index c4982bd2..a14146ae 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -155,6 +155,10 @@ void PAL_CALL freeMemoryVk( // Extended Adapter Features // ================================================== +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps); + PalResult PAL_CALL queryDepthStencilCapabilitiesVk( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -785,6 +789,7 @@ static PalGraphicsBackend s_VkBackend = { .freeMemory = freeMemoryVk, // extended adapter features + .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesVk, .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesVk, .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesVk, .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesVk, @@ -1005,6 +1010,10 @@ void PAL_CALL freeMemoryD3D12( // Extended Adapter Features // ================================================== +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps); + PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -1635,6 +1644,7 @@ static PalGraphicsBackend s_D3D12Backend = { .freeMemory = freeMemoryD3D12, // extended adapter features + .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesD3D12, .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesD3D12, .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesD3D12, .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesD3D12, @@ -1836,6 +1846,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->freeMemory || // extended adapter features + !backend->querySamplerAnisotropyCapabilities || !backend->queryDepthStencilCapabilities || !backend->queryFragmentShadingRateCapabilities || !backend->queryMeshShaderCapabilities || @@ -2266,6 +2277,21 @@ void PAL_CALL palFreeMemory( // Extended Adapter Features // ================================================== +PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->querySamplerAnisotropyCapabilities(device, caps); +} + PalResult PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 7b40887e..c6b6ac09 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -4326,6 +4326,22 @@ void PAL_CALL freeMemoryVk( // Extended Adapter Features // ================================================== +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps) +{ + Device* vkDevice = (Device*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceProperties props = {0}; + s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); + + caps->maxAnisotropy = props.limits.maxSamplerAnisotropy; + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL queryDepthStencilCapabilitiesVk( PalDevice* device, PalDepthStencilCapabilities* caps) From e48e4ad814723f289a99af213e8fee7e787fdf0a Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 31 Mar 2026 13:42:05 +0000 Subject: [PATCH 133/372] add extended feature query API d3d12 --- include/pal/pal_graphics.h | 3 + src/graphics/pal_d3d12.c | 112 ++++++++++++++++++++++++++++++++++++- src/graphics/pal_vulkan.c | 59 ++++++++++--------- 3 files changed, 146 insertions(+), 28 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 72564e33..2ddceb80 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1509,10 +1509,13 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + bool bindlessSamplers; /**< If true, bindless samplers are supported.*/ bool bindlessStorageBuffers; /**< If true, bindless storage buffers are supported.*/ bool bindlessUniformBuffers; /**< If true, bindless uniform buffers are supported.*/ Uint32 maxImagesPerShaderStage; Uint32 maxImagesPerDescriptorSet; + Uint32 maxSamplersPerShaderStage; + Uint32 maxSamplersPerDescriptorSet; Uint32 maxStorageBuffersPerShaderStage; Uint32 maxStorageBuffersPerDescriptorSet; Uint32 maxUniformBuffersPerShaderStage; diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index ee510c9f..f77142a3 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -383,7 +383,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = {0}; D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {0}; D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = {0}; - D3D12_FEATURE_DATA_D3D12_OPTIONS12 options12 = {0}; D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; D3D_FEATURE_LEVEL levels[] = { @@ -663,35 +662,146 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( PalDevice* device, PalDepthStencilCapabilities* caps) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + caps->depthResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; + caps->depthResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; + caps->depthResolveModes[PAL_RESOLVE_MODE_MIN] = true; + caps->depthResolveModes[PAL_RESOLVE_MODE_MAX] = true; + caps->stencilResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; + caps->stencilResolveModes[PAL_RESOLVE_MODE_AVERAGE] = false; + caps->stencilResolveModes[PAL_RESOLVE_MODE_MIN] = true; + caps->stencilResolveModes[PAL_RESOLVE_MODE_MAX] = true; + + caps->independentDepthStencilResolve = true; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + // these are supported if fragment shading rate feature is + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_1X1] = true; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_1X2] = true; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X1] = true; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X2] = true; + + D3D12_FEATURE_DATA_D3D12_OPTIONS6 options = {0}; + d3d12Device->handle->lpVtbl->CheckFeatureSupport( + d3d12Device->handle, + D3D12_FEATURE_D3D12_OPTIONS6, + &options, + sizeof(options)); + + if (options.AdditionalShadingRatesSupported) { + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X4] = true; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X2] = true; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X4] = true; + + } else { + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X4] = false; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X2] = false; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X4] = false; + } + // there are supported if fragment shading rate feature is + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP] = true; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE] = true; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN] = true; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX] = true; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL] = true; + + caps->minTexelWidth = 1; // safe default + caps->minTexelHeight = 1; // safe default + caps->maxTexelWidth = options.ShadingRateImageTileSize; + caps->maxTexelHeight = options.ShadingRateImageTileSize; + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( PalDevice* device, PalMeshShaderCapabilities* caps) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + // these are not exposed by d3d12. We use the offical mesh shader spec + caps->maxMeshOutputPrimitives = 256; + caps->maxMeshOutputVertices = 256; + caps->maxTaskWorkGroupInvocations = 128; + caps->maxMeshWorkGroupInvocations = 128; + + caps->maxTaskWorkGroupCount[0] = 65535; + caps->maxTaskWorkGroupCount[1] = 65535; + caps->maxTaskWorkGroupCount[2] = 65535; + caps->maxMeshWorkGroupCount[0] = 65535; + caps->maxMeshWorkGroupCount[1] = 65535; + caps->maxMeshWorkGroupCount[2] = 65535; + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( PalDevice* device, PalRayTracingCapabilities* caps) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + // these are only limited by memory. D3d12 does not expose them + caps->maxRecursionDepth = 32; // 32 - 1; + caps->maxHitAttributeSize = PAL_INFINITE; + caps->maxInstanceCount = PAL_INFINITE; + caps->maxPrimitiveCount = PAL_INFINITE; + caps->maxGeometryCount = PAL_INFINITE; + caps->maxPayloadSize = PAL_INFINITE; + caps->maxDispatchInvocations = PAL_INFINITE; + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( PalDevice* device, PalDescriptorIndexingCapabilities* caps) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + // these are supported if descriptor indexing is + caps->bindlessStorageBuffers = true; + caps->bindlessUniformBuffers = true; + caps->bindlessSamplers = true; + + // these are not exposed by d3d12. We use the offical resource binding spec + caps->maxImagesPerShaderStage = PAL_INFINITE; + caps->maxImagesPerDescriptorSet = PAL_INFINITE; + caps->maxSamplersPerShaderStage = 2048; + caps->maxSamplersPerDescriptorSet = PAL_INFINITE; + caps->maxStorageBuffersPerShaderStage = PAL_INFINITE; + caps->maxUniformBuffersPerShaderStage = PAL_INFINITE; + caps->maxStorageBuffersPerDescriptorSet = PAL_INFINITE; + caps->maxUniformBuffersPerDescriptorSet = PAL_INFINITE; + caps->maxDescriptors = PAL_INFINITE; + + return PAL_RESULT_SUCCESS; } // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index c6b6ac09..8ae7e61a 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -221,9 +221,6 @@ typedef struct _SECURITY_ATTRIBUTES { typedef struct { const PalGraphicsBackend* backend; - // For descriptor Indexing - bool bindlessStorageBuffers; - bool bindlessUniformBuffers; VkPhysicalDevice handle; } Adapter; @@ -364,8 +361,6 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool bindlessStorageBuffers; - bool bindlessUniformBuffers; PalAdapterFeatures features; Int32 phyQueueCount; Int32 phyQueueIndex; @@ -3006,8 +3001,6 @@ PalResult PAL_CALL enumerateAdaptersVk( if (adapterCount < *count) { Adapter* tmp = &s_Vk.adapters[adapterCount]; tmp->handle = devices[i]; - tmp->bindlessStorageBuffers = false; - tmp->bindlessUniformBuffers = false; outAdapters[adapterCount] = (PalAdapter*)tmp; } } @@ -3359,18 +3352,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) desc.descriptorBindingSampledImageUpdateAfterBind) { adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } - - // check for bindless storage buffers - if (desc.shaderStorageBufferArrayNonUniformIndexing && - desc.descriptorBindingStorageBufferUpdateAfterBind) { - vkAdapter->bindlessStorageBuffers = true; - } - - // check for bindless uniform buffers - if (desc.shaderUniformBufferArrayNonUniformIndexing && - desc.descriptorBindingUniformBufferUpdateAfterBind) { - vkAdapter->bindlessUniformBuffers = true; - } } // timeline semaphore is part of core 1.2 @@ -3784,16 +3765,25 @@ PalResult PAL_CALL createDeviceVk( descIndex.descriptorBindingVariableDescriptorCount = true; features12.descriptorIndexing = true; - if (vkAdapter->bindlessStorageBuffers) { + // check support for bindless storage and uniform buffers + VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; + desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &desc; + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + + if (desc.shaderStorageBufferArrayNonUniformIndexing && + desc.descriptorBindingStorageBufferUpdateAfterBind) { descIndex.shaderStorageBufferArrayNonUniformIndexing = true; descIndex.descriptorBindingStorageBufferUpdateAfterBind = true; - device->bindlessStorageBuffers = true; } - if (vkAdapter->bindlessUniformBuffers) { + if (desc.shaderUniformBufferArrayNonUniformIndexing && + desc.descriptorBindingUniformBufferUpdateAfterBind) { descIndex.shaderUniformBufferArrayNonUniformIndexing = true; descIndex.descriptorBindingUniformBufferUpdateAfterBind = true; - device->bindlessUniformBuffers = true; } descIndex.pNext = next; @@ -4521,27 +4511,42 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + caps->bindlessSamplers = true; + VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; + desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; + VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceDescriptorIndexingPropertiesEXT props = {0}; props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + + features.pNext = &desc; properties2.pNext = &props; + s_Vk.getPhysicalDeviceFeatures2(vkDevice->phyDevice, &features); s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - caps->bindlessStorageBuffers = false; - caps->bindlessUniformBuffers = false; - if (vkDevice->bindlessStorageBuffers) { + // check for bindless storage buffers + if (desc.shaderStorageBufferArrayNonUniformIndexing && + desc.descriptorBindingStorageBufferUpdateAfterBind) { caps->bindlessStorageBuffers = true; } - if (vkDevice->bindlessUniformBuffers) { + // check for bindless uniform buffers + if (desc.shaderUniformBufferArrayNonUniformIndexing && + desc.descriptorBindingUniformBufferUpdateAfterBind) { caps->bindlessUniformBuffers = true; } caps->maxImagesPerShaderStage = props.maxPerStageDescriptorUpdateAfterBindSampledImages; caps->maxImagesPerDescriptorSet = props.maxDescriptorSetUpdateAfterBindSampledImages; + caps->maxSamplersPerShaderStage = props.maxPerStageDescriptorUpdateAfterBindSamplers; + caps->maxSamplersPerDescriptorSet = props.maxDescriptorSetUpdateAfterBindSamplers; + caps->maxStorageBuffersPerShaderStage = props.maxPerStageDescriptorUpdateAfterBindStorageBuffers; caps->maxStorageBuffersPerDescriptorSet = props.maxDescriptorSetUpdateAfterBindStorageBuffers; From 990e20c67f39eeeda95a02017cf548d8c89c9b4e Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 31 Mar 2026 15:21:03 +0000 Subject: [PATCH 134/372] add command queue API d3d12 --- include/pal/pal_graphics.h | 57 ++++++++++++++++++- src/graphics/pal_d3d12.c | 111 ++++++++++++++++++++++++++++++++++++- src/graphics/pal_vulkan.c | 4 -- 3 files changed, 163 insertions(+), 9 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 2ddceb80..736378c4 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -33,6 +33,13 @@ freely, subject to the following restrictions: #include "pal_core.h" +/** + * @brief Value for indicating an unknown limit. + * @since 1.4 + * @ingroup pal_graphics + */ +#define PAL_LIMIT_UNKNOWN UINT32_MAX + /** * @brief The maximum name size of an adapter (GPU). * @since 1.4 @@ -1387,6 +1394,9 @@ typedef struct { /** * @struct PalAdapterCapabilities * @brief Capabilities of an adapter (GPU). + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * @since 1.4 * @ingroup pal_graphics @@ -1417,6 +1427,9 @@ typedef struct { /** * @struct PalSamplerAnisotropyCapabilities * @brief Sampler anisotropy capabilities of an adapter (GPU). + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * @since 1.4 * @ingroup pal_graphics @@ -1428,6 +1441,9 @@ typedef struct { /** * @struct PalDepthStencilCapabilities * @brief Depth stencil capabilities of an adapter (GPU). + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * @since 1.4 * @ingroup pal_graphics @@ -1448,6 +1464,9 @@ typedef struct { /** * @struct PalFragmentShadingRateCapabilities * @brief Fragment shading rate capabilities of an adapter (GPU). + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * @since 1.4 * @ingroup pal_graphics @@ -1469,6 +1488,9 @@ typedef struct { /** * @struct PalMeshShaderCapabilities * @brief Mesh shader capabilities of an adapter (GPU). + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * @since 1.4 * @ingroup pal_graphics @@ -1485,6 +1507,9 @@ typedef struct { /** * @struct PalRayTracingCapabilities * @brief Ray tracing capabilities of an adapter (GPU). + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * @since 1.4 * @ingroup pal_graphics @@ -1502,8 +1527,9 @@ typedef struct { /** * @struct PalDescriptorIndexingCapabilities * @brief Descriptor indexing capabilities of an adapter (GPU). - * - * Bindless images are always supported if Descriptor indexing is supported. + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. Bindless images are always supported if Descriptor indexing is supported. * * @since 1.4 * @ingroup pal_graphics @@ -1526,6 +1552,9 @@ typedef struct { /** * @struct PalSurfaceCapabilities * @brief surface capabilities of an adapter (GPU). + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * @since 1.4 * @ingroup pal_graphics @@ -3974,6 +4003,9 @@ PAL_API PalResult PAL_CALL palGetAdapterInfo( * @brief Get capabilites or limits about an adapter (GPU). * * The graphics system must be initialized before this call. + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * @param[in] adapter Adapter to query capabilities on. * @param[out] caps Pointer to a PalAdapterCapabilities to fill. @@ -4109,6 +4141,9 @@ PAL_API void PAL_CALL palFreeMemory( * @brief Get sampler anisotropy feature capabilites or limits about a device. * * The graphics system must be initialized before this call. + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * `PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4132,6 +4167,9 @@ PAL_API PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( * @brief Get depth stencil feature capabilites or limits about a device. * * The graphics system must be initialized before this call. + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * `PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4155,6 +4193,9 @@ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( * @brief Get fragment shading rate feature capabilites or limits about a device. * * The graphics system must be initialized before this call. + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4178,6 +4219,9 @@ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( * @brief Get mesh shader feature capabilites or limits about a device. * * The graphics system must be initialized before this call. + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4201,6 +4245,9 @@ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( * @brief Get ray tracing feature capabilites or limits about a device. * * The graphics system must be initialized before this call. + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4224,6 +4271,9 @@ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( * @brief Get descriptor indexing feature capabilites or limits about a device. * * The graphics system must be initialized before this call. + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4736,6 +4786,9 @@ PAL_API void PAL_CALL palDestroySurface(PalSurface* surface); * @brief Get surface capabilites about a device. * * The graphics system must be initialized before this call. + * + * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the + * value. * * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index f77142a3..73890081 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -52,6 +52,8 @@ const IID IID_Debug = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x8 const IID IID_Debug1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; const IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4,0xe6,0x14,0x58}; const IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3}; +const IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed}; +const IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -89,13 +91,27 @@ typedef struct { ID3D12Device* handle; } Device; +typedef struct { + const PalGraphicsBackend* backend; + + UINT64 fenceValue; + PalQueueType type; + ID3D12Fence* fence; + ID3D12CommandQueue* handle; +} Queue; + +typedef struct { + const PalGraphicsBackend* backend; + + HWND handle; +} Surface; + static D3D12 s_D3D12 = {0}; // ================================================== // Helper Functions // ================================================== - // ================================================== // Adapter // ================================================== @@ -551,6 +567,11 @@ PalResult PAL_CALL createDeviceD3D12( } } + if (!device->handle) { + palFree(s_D3D12.allocator, device); + return PAL_RESULT_INVALID_DRIVER; + } + if (s_D3D12.debugLayer) { result = device->handle->lpVtbl->QueryInterface( device->handle, @@ -813,24 +834,108 @@ PalResult PAL_CALL createQueueD3D12( PalQueueType type, PalQueue** outQueue) { + HRESULT result; + Device* d3d12Device = (Device*)device; + Queue* queue = nullptr; + D3D12_COMMAND_QUEUE_DESC desc = {0}; + + switch (type) { + case PAL_QUEUE_TYPE_COMPUTE: { + desc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; + break; + } + + case PAL_QUEUE_TYPE_GRAPHICS: { + desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + break; + } + + case PAL_QUEUE_TYPE_COPY: { + desc.Type = D3D12_COMMAND_LIST_TYPE_COPY; + break; + } + } + + queue = palAllocate(s_D3D12.allocator, sizeof(Queue), 0); + if (!queue) { + return PAL_RESULT_OUT_OF_MEMORY; + } + result = d3d12Device->handle->lpVtbl->CreateCommandQueue( + d3d12Device->handle, + &desc, + &IID_Queue, + (void**)&queue->handle); + + if (FAILED(result)) { + palFree(s_D3D12.allocator, queue); + + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } else { + return PAL_RESULT_PLATFORM_FAILURE; + } + } + + // create fence used for queue wait + result = d3d12Device->handle->lpVtbl->CreateFence( + d3d12Device->handle, + 0, + 0, + &IID_Fence, + (void**)&queue->fence); + + if (FAILED(result)) { + palFree(s_D3D12.allocator, queue); + + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } else { + return PAL_RESULT_PLATFORM_FAILURE; + } + } + + queue->fenceValue = 1; + queue->type = type; + *outQueue = (PalQueue*)queue; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyQueueD3D12(PalQueue* queue) { - + Queue* d3d12Queue = (Device*)queue; + d3d12Queue->fence->lpVtbl->Release(d3d12Queue->fence); + d3d12Queue->handle->lpVtbl->Release(d3d12Queue->handle); + palFree(s_D3D12.allocator, d3d12Queue); } PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) { + Queue* d3d12Queue = (Device*)queue; + ID3D12Fence* fence = d3d12Queue->fence; + fence->lpVtbl->Signal(fence, d3d12Queue->fenceValue); + + // wait on the fence if the submited work is not done + if (fence->lpVtbl->GetCompletedValue(fence) < d3d12Queue->fenceValue) { + HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + fence->lpVtbl->SetEventOnCompletion(fence, d3d12Queue->fenceValue, event); + WaitForSingleObject(event, INFINITE); + CloseHandle(event); + } + d3d12Queue->fenceValue++; + return PAL_RESULT_SUCCESS; } bool PAL_CALL canQueuePresentD3D12( PalQueue* queue, PalSurface* surface) { - + Queue* d3d12Queue = (Device*)queue; + if (d3d12Queue->type == PAL_QUEUE_TYPE_GRAPHICS) { + return true; // all graphics queues support presentation + } + return false; } // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 8ae7e61a..11ed26e8 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -4572,10 +4572,6 @@ PalResult PAL_CALL createQueueVk( VkQueueFlags queueFlag = 0; Queue* queue = nullptr; - if (!vkDevice->handle) { - return PAL_RESULT_INVALID_DEVICE; - } - if (vkDevice->phyQueueCount == 0) { return PAL_RESULT_OUT_OF_QUEUE; } From 04980305a3e60e66ff00aa467b210f365adb74ad Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 31 Mar 2026 18:11:42 +0000 Subject: [PATCH 135/372] add format API d3d12 --- include/pal/pal_graphics.h | 45 ++- src/graphics/pal_d3d12.c | 673 +++++++++++++++++++++++++++++++----- src/graphics/pal_graphics.c | 22 ++ src/graphics/pal_vulkan.c | 108 +++--- 4 files changed, 701 insertions(+), 147 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 736378c4..aff288e8 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -496,8 +496,8 @@ typedef enum { PAL_FORMAT_S8_UINT, PAL_FORMAT_D16_UNORM, PAL_FORMAT_D32_SFLOAT, - PAL_FORMAT_D32_SFLOAT_S8_UINT, PAL_FORMAT_D16_UNORM_S8_UINT, + PAL_FORMAT_D32_SFLOAT_S8_UINT, PAL_FORMAT_D24_UNORM_S8_UINT, PAL_FORMAT_MAX @@ -1410,8 +1410,6 @@ typedef struct { Uint32 maxImageDepth; Uint32 maxImageArrayLayers; Uint32 maxImageMipLevels; - PalSampleCount maxColorSampleCount; // TODO: Remove - PalSampleCount maxDepthSampleCount; // TODO: Remove Uint32 maxColorAttachments; Uint32 maxMultiViews; Uint32 maxViewports; @@ -1598,8 +1596,8 @@ typedef struct { /** * @struct PalFormatInfo - * @brief Information about a format. This includes the supported image and image view usages - * from the provided format. + * @brief Information about a format. This includes the supported image, image view usages and + * sample count from the provided format. * * @since 1.4 * @ingroup pal_graphics @@ -1608,6 +1606,7 @@ typedef struct { PalFormat format; /**< The format.*/ PalImageUsages usages; /**< Supported image usages of the format.*/ PalImageViewUsages viewUsages; /**< Supported image view usages of the format.*/ + PalSampleCount maxSampleCount; /**< Supported multisample count.*/ } PalFormatInfo; /** @@ -2845,6 +2844,15 @@ typedef struct { PalAdapter* adapter, PalFormat format); + /** + * Backend implementation of ::palQueryFormatSampleCount. + * + * Must obey the rules and semantics documented in palQueryFormatSampleCount(). + */ + PalSampleCount PAL_CALL (*queryFormatSampleCount)( + PalAdapter* adapter, + PalFormat format); + /** * Backend implementation of ::palCreateImage. * @@ -4406,7 +4414,7 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Must only be called from the main thread. + * Thread safety: Thread safe if `outFormats` is per thread. * * @since 1.4 * @ingroup pal_graphics @@ -4432,7 +4440,7 @@ PAL_API PalResult PAL_CALL palEnumerateFormats( * * @return True if format is supported otherwise false if not supported. * - * Thread safety: Must only be called from the main thread. + * Thread safety: Thread safe. * * @since 1.4 * @ingroup pal_graphics @@ -4453,7 +4461,7 @@ PAL_API bool PAL_CALL palIsFormatSupported( * * @return Supported image usages on success otherwise `0` on failure. * - * Thread safety: Must only be called from the main thread. + * Thread safety: Thread safe. * * @since 1.4 * @ingroup pal_graphics @@ -4472,7 +4480,7 @@ PAL_API PalImageUsages PAL_CALL palQueryFormatImageUsages( * * @return Supported image view usages on success otherwise `0` on failure. * - * Thread safety: Must only be called from the main thread. + * Thread safety: Thread safe. * * @since 1.4 * @ingroup pal_graphics @@ -4481,6 +4489,25 @@ PAL_API PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( PalAdapter* adapter, PalFormat format); +/** + * @brief Checks supported sample count associated with a format. + * + * The graphics system must be initialized before this call. + * + * @param[in] adapter Adapter to query format on. + * @param[in] format Format to query sample count for. + * + * @return Supported sample count on success otherwise `0` on failure. + * + * Thread safety: Thread safe. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalSampleCount PAL_CALL palQueryFormatSampleCount( + PalAdapter* adapter, + PalFormat format); + /** * @brief Create an image. * diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 73890081..73860c9f 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -63,11 +63,14 @@ typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( typedef struct { const PalGraphicsBackend* backend; + D3D_FEATURE_LEVEL level; + ID3D12Device* tmpDevice; IDXGIAdapter4* handle; } Adapter; typedef struct { bool debugLayer; + Uint32 adapterCount; HMODULE handle; HMODULE dxgi; Adapter* adapters; @@ -112,6 +115,273 @@ static D3D12 s_D3D12 = {0}; // Helper Functions // ================================================== +static DXGI_FORMAT formatToD3D12(PalFormat format) +{ + switch (format) { + case PAL_FORMAT_R8_UNORM: + return DXGI_FORMAT_R8_UNORM; + + case PAL_FORMAT_R8_SNORM: + return DXGI_FORMAT_R8_SNORM; + + case PAL_FORMAT_R8_UINT: + return DXGI_FORMAT_R8_UINT; + + case PAL_FORMAT_R8_SINT: + return DXGI_FORMAT_R8_SINT; + + case PAL_FORMAT_R8_SRGB: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R16_UNORM: + return DXGI_FORMAT_R16_UNORM; + + case PAL_FORMAT_R16_SNORM: + return DXGI_FORMAT_R16_SNORM; + + case PAL_FORMAT_R16_UINT: + return DXGI_FORMAT_R16_UINT; + + case PAL_FORMAT_R16_SINT: + return DXGI_FORMAT_R16_SINT; + + case PAL_FORMAT_R16_SFLOAT: + return DXGI_FORMAT_R16_FLOAT; + + case PAL_FORMAT_R32_UINT: + return DXGI_FORMAT_R32_UINT; + + case PAL_FORMAT_R32_SINT: + return DXGI_FORMAT_R32_SINT; + + case PAL_FORMAT_R32_SFLOAT: + return DXGI_FORMAT_R32_FLOAT; + + case PAL_FORMAT_R64_UINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R64_SINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R64_SFLOAT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R8G8_UNORM: + return DXGI_FORMAT_R8G8_UNORM; + + case PAL_FORMAT_R8G8_SNORM: + return DXGI_FORMAT_R8G8_SNORM; + + case PAL_FORMAT_R8G8_UINT: + return DXGI_FORMAT_R8G8_UINT; + + case PAL_FORMAT_R8G8_SINT: + return DXGI_FORMAT_R8G8_SINT; + + case PAL_FORMAT_R8G8_SRGB: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R16G16_UNORM: + return DXGI_FORMAT_R16G16_UNORM; + + case PAL_FORMAT_R16G16_SNORM: + return DXGI_FORMAT_R16G16_SNORM; + + case PAL_FORMAT_R16G16_UINT: + return DXGI_FORMAT_R16G16_UINT; + + case PAL_FORMAT_R16G16_SINT: + return DXGI_FORMAT_R16G16_SINT; + + case PAL_FORMAT_R16G16_SFLOAT: + return DXGI_FORMAT_R16G16_FLOAT; + + case PAL_FORMAT_R32G32_UINT: + return DXGI_FORMAT_R32G32_UINT; + + case PAL_FORMAT_R32G32_SINT: + return DXGI_FORMAT_R32G32_SINT; + + case PAL_FORMAT_R32G32_SFLOAT: + return DXGI_FORMAT_R32G32_FLOAT; + + case PAL_FORMAT_R64G64_UINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R64G64_SINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R64G64_SFLOAT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R8G8B8_UNORM: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R8G8B8_SNORM: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R8G8B8_UINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R8G8B8_SINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R8G8B8_SRGB: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R16G16B16_UNORM: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R16G16B16_SNORM: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R16G16B16_UINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R16G16B16_SINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R16G16B16_SFLOAT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R32G32B32_UINT: + return DXGI_FORMAT_R32G32B32_UINT; + + case PAL_FORMAT_R32G32B32_SINT: + return DXGI_FORMAT_R32G32B32_SINT; + + case PAL_FORMAT_R32G32B32_SFLOAT: + return DXGI_FORMAT_R32G32B32_FLOAT; + + case PAL_FORMAT_R64G64B64_UINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R64G64B64_SINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R64G64B64_SFLOAT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_B8G8R8_UNORM: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_B8G8R8_SNORM: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_B8G8R8_UINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_B8G8R8_SINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_B8G8R8_SRGB: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R8G8B8A8_UNORM: + return DXGI_FORMAT_R8G8B8A8_UNORM; + + case PAL_FORMAT_R8G8B8A8_SNORM: + return DXGI_FORMAT_R8G8B8A8_SNORM; + + case PAL_FORMAT_R8G8B8A8_UINT: + return DXGI_FORMAT_R8G8B8A8_UINT; + + case PAL_FORMAT_R8G8B8A8_SINT: + return DXGI_FORMAT_R8G8B8A8_SINT; + + case PAL_FORMAT_R8G8B8A8_SRGB: + return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + + case PAL_FORMAT_R16G16B16A16_UNORM: + return DXGI_FORMAT_R16G16B16A16_UNORM; + + case PAL_FORMAT_R16G16B16A16_SNORM: + return DXGI_FORMAT_R16G16B16A16_SNORM; + + case PAL_FORMAT_R16G16B16A16_UINT: + return DXGI_FORMAT_R16G16B16A16_UINT; + + case PAL_FORMAT_R16G16B16A16_SINT: + return DXGI_FORMAT_R16G16B16A16_SINT; + + case PAL_FORMAT_R16G16B16A16_SFLOAT: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + + case PAL_FORMAT_R32G32B32A32_UINT: + return DXGI_FORMAT_R32G32B32A32_UINT; + + case PAL_FORMAT_R32G32B32A32_SINT: + return DXGI_FORMAT_R32G32B32A32_SINT; + + case PAL_FORMAT_R32G32B32A32_SFLOAT: + return DXGI_FORMAT_R32G32B32A32_FLOAT; + + case PAL_FORMAT_R64G64B64A64_UINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R64G64B64A64_SINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_R64G64B64A64_SFLOAT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_B8G8R8A8_UNORM: + return DXGI_FORMAT_B8G8R8A8_UNORM; + + case PAL_FORMAT_B8G8R8A8_SNORM: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_B8G8R8A8_UINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_B8G8R8A8_SINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_B8G8R8A8_SRGB: + return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + + case PAL_FORMAT_S8_UINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_D16_UNORM: + return DXGI_FORMAT_D16_UNORM; + + case PAL_FORMAT_D32_SFLOAT: + return DXGI_FORMAT_D32_FLOAT; + + case PAL_FORMAT_D32_SFLOAT_S8_UINT: + return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + + case PAL_FORMAT_D16_UNORM_S8_UINT: + return DXGI_FORMAT_UNKNOWN; + + case PAL_FORMAT_D24_UNORM_S8_UINT: + return DXGI_FORMAT_D24_UNORM_S8_UINT; + } + + return DXGI_FORMAT_UNKNOWN; +} + +static PalImageUsages ImageUsageFromD3D12(D3D12_FORMAT_SUPPORT1 flags) +{ + PalImageUsages usages = 0; + if (flags & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) { + usages |= PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; + } + + if (flags & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) { + usages |= PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT; + } + + if (flags & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE) { + usages |= PAL_IMAGE_USAGE_SAMPLED; + } + + usages |= PAL_IMAGE_USAGE_TRANSFER_DST; + usages |= PAL_IMAGE_USAGE_TRANSFER_SRC; + return usages; +} + // ================================================== // Adapter // ================================================== @@ -163,6 +433,7 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D12.factory = nullptr; s_D3D12.adapters = nullptr; + s_D3D12.adapterCount = 0; HRESULT result = s_D3D12.createDXGIFactory(0, &IID_Factory, (void**)&s_D3D12.factory); if (FAILED(result)) { return PAL_RESULT_PLATFORM_FAILURE; @@ -182,9 +453,14 @@ void PAL_CALL shutdownGraphicsD3D12() s_D3D12.debugController1->lpVtbl->Release(s_D3D12.debugController1); } + for (int i = 0; i < s_D3D12.adapterCount; i++) { + s_D3D12.adapters[i].handle->lpVtbl->Release(s_D3D12.adapters[i].handle); + } + s_D3D12.factory->lpVtbl->Release(s_D3D12.factory); FreeLibrary(s_D3D12.handle); FreeLibrary(s_D3D12.dxgi); + if (s_D3D12.adapters) { palFree(s_D3D12.allocator, s_D3D12.adapters); } @@ -198,6 +474,16 @@ PalResult PAL_CALL enumerateAdaptersD3D12( Uint32 adapterCount = 0; IDXGIAdapter* adapter = nullptr; IDXGIAdapter4* dxAdapters[32]; // should be more than enough + ID3D12Device* devices[32]; // should be more than enough + D3D_FEATURE_LEVEL deviceLevels[32]; // should be more than enough + + D3D_FEATURE_LEVEL levels[] = { + D3D_FEATURE_LEVEL_12_2, + D3D_FEATURE_LEVEL_12_1, + D3D_FEATURE_LEVEL_12_0, + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0 + }; if (s_D3D12.adapters) { palFree(s_D3D12.allocator, s_D3D12.adapters); @@ -212,6 +498,23 @@ PalResult PAL_CALL enumerateAdaptersD3D12( if SUCCEEDED((adapter->lpVtbl->QueryInterface(adapter, &IID_Adapter, (void**)&tmp))) { dxAdapters[adapterCount] = tmp; } + + // create a temp device for every adapter to use as an instance to check features, + // capabilities etc. + ID3D12Device* device = nullptr; + for (int i = 0; i < 5; i++) { + HRESULT result = s_D3D12.createDevice( + (IUnknown*)tmp, + levels[i], + &IID_Device, + (void**)&device); + + if (SUCCEEDED(result)) { + deviceLevels[adapterCount] = levels[i]; + devices[adapterCount] = device; + break; + } + } } adapter->lpVtbl->Release(adapter); adapterCount++; @@ -227,8 +530,11 @@ PalResult PAL_CALL enumerateAdaptersD3D12( for (int i = 0; i < *count; i++) { Adapter* tmp = &s_D3D12.adapters[i]; tmp->handle = dxAdapters[i]; + tmp->tmpDevice = devices[i]; + tmp->level = levels[i]; outAdapters[i] = (PalAdapter*)tmp; } + s_D3D12.adapterCount = *count; } else { *count = adapterCount; @@ -241,34 +547,17 @@ PalResult PAL_CALL getAdapterInfoD3D12( PalAdapter* adapter, PalAdapterInfo* info) { - Adapter* d3dAdapter = (Adapter*)adapter; - IDXGIAdapter4* adapterHandle = d3dAdapter->handle; + Adapter* d3d12Adapter = (Adapter*)adapter; + IDXGIAdapter4* adapterHandle = d3d12Adapter->handle; DXGI_ADAPTER_DESC3 desc; D3D12_FEATURE_DATA_ARCHITECTURE1 arch = {0}; - ID3D12Device* device = nullptr; + ID3D12Device* device = d3d12Adapter->tmpDevice; HRESULT result = adapterHandle->lpVtbl->GetDesc3(adapterHandle, &desc); if (FAILED(result)) { return PAL_RESULT_INVALID_ADAPTER; } - D3D_FEATURE_LEVEL supportedLevel = D3D_FEATURE_LEVEL_11_0; - D3D_FEATURE_LEVEL levels[] = { - D3D_FEATURE_LEVEL_12_2, - D3D_FEATURE_LEVEL_12_1, - D3D_FEATURE_LEVEL_12_0, - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0 - }; - - const char* levelStrings[] = { - "12_2", - "12_1", - "12_0", - "11_1", - "11_0" - }; - info->vendorId = desc.VendorId; info->deviceId= desc.DeviceId; info->apiType = PAL_ADAPTER_API_TYPE_D3D12; @@ -286,22 +575,6 @@ PalResult PAL_CALL getAdapterInfoD3D12( nullptr, nullptr); - // create a temporary device to check the supported version - Uint32 levelIndex = 0; - for (int i = 0; i < 5; i++) { - result = s_D3D12.createDevice( - (IUnknown*)adapterHandle, - levels[i], - &IID_Device, - (void**)&device); - - if (SUCCEEDED(result)) { - supportedLevel = levels[i]; - levelIndex = i; - break; - } - } - device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_ARCHITECTURE1, @@ -326,10 +599,23 @@ PalResult PAL_CALL getAdapterInfoD3D12( info->vram = desc.DedicatedSystemMemory; } - info->version = supportedLevel; - strcpy(info->versionString, levelStrings[levelIndex]); + info->version = d3d12Adapter->level; + if (d3d12Adapter->level == D3D_FEATURE_LEVEL_12_2) { + strcpy(info->versionString, "12_2"); + + } else if (d3d12Adapter->level == D3D_FEATURE_LEVEL_12_1) { + strcpy(info->versionString, "12_1"); + + } else if (d3d12Adapter->level == D3D_FEATURE_LEVEL_12_0) { + strcpy(info->versionString, "12_0"); + + } else if (d3d12Adapter->level == D3D_FEATURE_LEVEL_11_1) { + strcpy(info->versionString, "11_1"); + + } else if (d3d12Adapter->level == D3D_FEATURE_LEVEL_11_0) { + strcpy(info->versionString, "11_0"); + } - device->lpVtbl->Release(device); return PAL_RESULT_SUCCESS; } @@ -389,10 +675,10 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) { HRESULT result; - ID3D12Device* device = nullptr; - Adapter* d3dAdapter = (Adapter*)adapter; - IDXGIAdapter4* adapterHandle = d3dAdapter->handle; + Adapter* d3d12Adapter = (Adapter*)adapter; + IDXGIAdapter4* adapterHandle = d3d12Adapter->handle; PalAdapterFeatures features = 0; + ID3D12Device* device = d3d12Adapter->tmpDevice; D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {0}; @@ -401,29 +687,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = {0}; D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; - D3D_FEATURE_LEVEL levels[] = { - D3D_FEATURE_LEVEL_12_2, - D3D_FEATURE_LEVEL_12_1, - D3D_FEATURE_LEVEL_12_0, - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0 - }; - - for (int i = 0; i < 5; i++) { - result = s_D3D12.createDevice( - (IUnknown*)adapterHandle, - levels[i], - &IID_Device, - (void**)&device); - - if (SUCCEEDED(result)) { - if (levels[i] >= D3D_FEATURE_LEVEL_12_0) { - features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; - } - break; - } - } - device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_D3D12_OPTIONS, @@ -524,7 +787,9 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; - device->lpVtbl->Release(device); + if (d3d12Adapter->level >= D3D_FEATURE_LEVEL_12_0) { + features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; + } return features; } @@ -547,27 +812,13 @@ PalResult PAL_CALL createDeviceD3D12( } memset(device, 0, sizeof(Device)); - D3D_FEATURE_LEVEL levels[] = { - D3D_FEATURE_LEVEL_12_2, - D3D_FEATURE_LEVEL_12_1, - D3D_FEATURE_LEVEL_12_0, - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0 - }; - - for (int i = 0; i < 5; i++) { - result = s_D3D12.createDevice( - (IUnknown*)d3d12Adapter->handle, - levels[i], - &IID_Device, - (void**)&device->handle); - - if (SUCCEEDED(result)) { - break; - } - } - - if (!device->handle) { + result = s_D3D12.createDevice( + (IUnknown*)d3d12Adapter->handle, + d3d12Adapter->level, + &IID_Device, + (void**)&device->handle); + + if (FAILED(result)) { palFree(s_D3D12.allocator, device); return PAL_RESULT_INVALID_DRIVER; } @@ -869,7 +1120,6 @@ PalResult PAL_CALL createQueueD3D12( if (FAILED(result)) { palFree(s_D3D12.allocator, queue); - if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } else { @@ -887,7 +1137,6 @@ PalResult PAL_CALL createQueueD3D12( if (FAILED(result)) { palFree(s_D3D12.allocator, queue); - if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } else { @@ -903,7 +1152,7 @@ PalResult PAL_CALL createQueueD3D12( void PAL_CALL destroyQueueD3D12(PalQueue* queue) { - Queue* d3d12Queue = (Device*)queue; + Queue* d3d12Queue = (Queue*)queue; d3d12Queue->fence->lpVtbl->Release(d3d12Queue->fence); d3d12Queue->handle->lpVtbl->Release(d3d12Queue->handle); palFree(s_D3D12.allocator, d3d12Queue); @@ -911,7 +1160,7 @@ void PAL_CALL destroyQueueD3D12(PalQueue* queue) PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) { - Queue* d3d12Queue = (Device*)queue; + Queue* d3d12Queue = (Queue*)queue; ID3D12Fence* fence = d3d12Queue->fence; fence->lpVtbl->Signal(fence, d3d12Queue->fenceValue); @@ -931,7 +1180,7 @@ bool PAL_CALL canQueuePresentD3D12( PalQueue* queue, PalSurface* surface) { - Queue* d3d12Queue = (Device*)queue; + Queue* d3d12Queue = (Queue*)queue; if (d3d12Queue->type == PAL_QUEUE_TYPE_GRAPHICS) { return true; // all graphics queues support presentation } @@ -947,28 +1196,268 @@ PalResult PAL_CALL enumerateFormatsD3D12( Int32* count, PalFormatInfo* outFormats) { + Int32 fmtCount = 0; + HRESULT result; + Adapter* d3d12Adapter = (Adapter*)adapter; + ID3D12Device* device = d3d12Adapter->tmpDevice; + D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; + + for (int i = 0; i < PAL_FORMAT_MAX; i++) { + DXGI_FORMAT fmt = formatToD3D12((PalFormat)i); + if (fmt == DXGI_FORMAT_UNKNOWN) { + continue; + } + + support.Format = fmt; + result = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, + sizeof(support)); + + if (SUCCEEDED(result)) { + if (support.Support1 == 0 && support.Support2 == 0) { + // format not supported + continue; + } + if (outFormats) { + if (fmtCount < *count) { + PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; + fmtInfo->format = (PalFormat)i; + fmtInfo->usages = ImageUsageFromD3D12(support.Support1); + + if (support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE || + support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD) { + fmtInfo->usages |= PAL_IMAGE_USAGE_STORAGE; + } + + fmtInfo->viewUsages = 0; + if (fmtInfo->usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_COLOR; + if (i == PAL_FORMAT_R8_UINT) { + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; + } + } + + if (fmtInfo->usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { + if (i == PAL_FORMAT_S8_UINT) { + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + + } else if (i == PAL_FORMAT_D16_UNORM || i == PAL_FORMAT_D32_SFLOAT) { + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + + } else { + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } + } + } + + } else { + fmtCount++; + } + } + } + if (!outFormats) { + *count = fmtCount; + } + return PAL_RESULT_SUCCESS; } bool PAL_CALL isFormatSupportedD3D12( PalAdapter* adapter, PalFormat format) { + HRESULT result; + Adapter* d3d12Adapter = (Adapter*)adapter; + ID3D12Device* device = d3d12Adapter->tmpDevice; + D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; + + DXGI_FORMAT fmt = formatToD3D12(format); + if (fmt == DXGI_FORMAT_UNKNOWN) { + return false; + } + support.Format = fmt; + result = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, + sizeof(support)); + + if (FAILED(result)) { + return false; + } + + if (support.Support1 == 0 && support.Support2 == 0) { + // format not supported + return false; + } + + return true; } PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( PalAdapter* adapter, PalFormat format) { + HRESULT result; + Adapter* d3d12Adapter = (Adapter*)adapter; + ID3D12Device* device = d3d12Adapter->tmpDevice; + D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; + + DXGI_FORMAT fmt = formatToD3D12(format); + if (fmt == DXGI_FORMAT_UNKNOWN) { + return 0; + } + + support.Format = fmt; + result = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, + sizeof(support)); + + if (FAILED(result)) { + return 0; + } + + if (support.Support1 == 0 && support.Support2 == 0) { + // format not supported + return 0; + } + + PalImageUsages usages = ImageUsageFromD3D12(support.Support1); + if (support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE || + support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD) { + usages |= PAL_IMAGE_USAGE_STORAGE; + } + return usages; } PalImageViewUsages PAL_CALL queryFormatImageViewUsagesD3D12( PalAdapter* adapter, PalFormat format) { + HRESULT result; + Adapter* d3d12Adapter = (Adapter*)adapter; + ID3D12Device* device = d3d12Adapter->tmpDevice; + D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; + + DXGI_FORMAT fmt = formatToD3D12(format); + if (fmt == DXGI_FORMAT_UNKNOWN) { + return 0; + } + + support.Format = fmt; + result = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, + sizeof(support)); + if (FAILED(result)) { + return 0; + } + + if (support.Support1 == 0 && support.Support2 == 0) { + // format not supported + return 0; + } + + PalImageUsages imageUsages = ImageUsageFromD3D12(support.Support1); + if (support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE || + support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD) { + imageUsages |= PAL_IMAGE_USAGE_STORAGE; + } + + PalImageViewUsages usages = 0; + if (imageUsages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { + usages |= PAL_IMAGE_VIEW_USAGE_COLOR; + if (format == PAL_FORMAT_R8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; + } + } + + if (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { + if (format == PAL_FORMAT_D16_UNORM || format == PAL_FORMAT_D32_SFLOAT) { + usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + + } else { + usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } + } + return usages; +} + +PalSampleCount PAL_CALL queryFormatSampleCountD3D12( + PalAdapter* adapter, + PalFormat format) +{ + HRESULT result; + Adapter* d3d12Adapter = (Adapter*)adapter; + ID3D12Device* device = d3d12Adapter->tmpDevice; + D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; + + DXGI_FORMAT fmt = formatToD3D12(format); + if (fmt == DXGI_FORMAT_UNKNOWN) { + return false; + } + + support.Format = fmt; + result = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, + sizeof(support)); + + if (FAILED(result)) { + return false; + } + + if (support.Support1 == 0 && support.Support2 == 0) { + // format not supported + return false; + } + + // check sample count + UINT sampleCounts[] = {64, 32, 16, 8, 4, 2}; + D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS samples = {0}; + samples.Format = fmt; + + Uint32 tmp = 0; + for (int i = 0; i < 6; i++) { + samples.SampleCount = sampleCounts[i]; + result = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, + &samples, + sizeof(samples)); + + if (SUCCEEDED(result) && samples.NumQualityLevels > 0) { + tmp = samples.SampleCount; + break; + } + } + + if (tmp == 64) { + return PAL_SAMPLE_COUNT_64; + } else if (tmp == 32) { + return PAL_SAMPLE_COUNT_32; + } else if (tmp == 16) { + return PAL_SAMPLE_COUNT_16; + } else if (tmp == 8) { + return PAL_SAMPLE_COUNT_8; + } else if (tmp == 4) { + return PAL_SAMPLE_COUNT_4; + } else if (tmp == 2) { + return PAL_SAMPLE_COUNT_2; + } else { + return PAL_SAMPLE_COUNT_1; + } } // ================================================== diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index a14146ae..0755e6e6 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -217,6 +217,10 @@ PalImageViewUsages PAL_CALL queryFormatImageViewUsagesVk( PalAdapter* adapter, PalFormat format); +PalSampleCount PAL_CALL queryFormatSampleCountVk( + PalAdapter* adapter, + PalFormat format); + // ================================================== // Image // ================================================== @@ -807,6 +811,7 @@ static PalGraphicsBackend s_VkBackend = { .isFormatSupported = isFormatSupportedVk, .queryFormatImageUsages = queryFormatImageUsagesVk, .queryFormatImageViewUsages = queryFormatImageViewUsagesVk, + .queryFormatSampleCount = queryFormatSampleCountVk, // image .createImage = createImageVk, @@ -1072,6 +1077,10 @@ PalImageViewUsages PAL_CALL queryFormatImageViewUsagesD3D12( PalAdapter* adapter, PalFormat format); +PalSampleCount PAL_CALL queryFormatSampleCountD3D12( + PalAdapter* adapter, + PalFormat format); + // ================================================== // Image // ================================================== @@ -1662,6 +1671,7 @@ static PalGraphicsBackend s_D3D12Backend = { .isFormatSupported = isFormatSupportedD3D12, .queryFormatImageUsages = queryFormatImageUsagesD3D12, .queryFormatImageViewUsages = queryFormatImageViewUsagesD3D12, + .queryFormatSampleCount = queryFormatSampleCountD3D12, // image .createImage = createImageD3D12, @@ -1864,6 +1874,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->isFormatSupported || !backend->queryFormatImageUsages || !backend->queryFormatImageViewUsages || + !backend->queryFormatSampleCount || // image !backend->createImage || @@ -2483,6 +2494,17 @@ PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( return adapter->backend->queryFormatImageViewUsages(adapter, format); } +PalSampleCount PAL_CALL palQueryFormatSampleCount( + PalAdapter* adapter, + PalFormat format) +{ + if (!s_Graphics.initialized || !adapter) { + return PAL_SAMPLE_COUNT_1; + } + + return adapter->backend->queryFormatSampleCount(adapter, format); +} + // ================================================== // Image // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 11ed26e8..2c180930 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3109,12 +3109,6 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( caps->maxImageDepth = props.limits.maxImageDimension3D; caps->maxImageArrayLayers = props.limits.maxImageArrayLayers; - PalSampleCount tmp = PAL_SAMPLE_COUNT_1; - tmp = samplesFromVk(props.limits.framebufferColorSampleCounts); - caps->maxColorSampleCount = tmp; - tmp = samplesFromVk(props.limits.framebufferDepthSampleCounts); - caps->maxDepthSampleCount = tmp; - caps->maxViewports = props.limits.maxViewports; caps->maxSamplers = props.limits.maxSamplerAllocationCount; caps->maxUniformBufferSize = props.limits.maxUniformBufferRange; @@ -3131,7 +3125,7 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( Uint32 b = caps->maxImageHeight; Uint32 c = caps->maxImageDepth; - tmp = a > b ? a : b; + Uint32 tmp = a > b ? a : b; Uint32 size = tmp > c ? tmp : c; Uint32 levels = 0; while (size > 0) { @@ -4718,32 +4712,26 @@ PalResult PAL_CALL enumerateFormatsVk( fmtInfo->format = (PalFormat)i; fmtInfo->usages = ImageUsageFromVk(props.optimalTilingFeatures); - PalImageViewUsages usages = 0; - if (i == PAL_FORMAT_S8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - } - - if (i == PAL_FORMAT_D16_UNORM || i == PAL_FORMAT_D32_SFLOAT) { - usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + fmtInfo->viewUsages = 0; + if (fmtInfo->usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_COLOR; + if (i == PAL_FORMAT_R8_UINT) { + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; + } } - if (i == PAL_FORMAT_D32_SFLOAT_S8_UINT || i == PAL_FORMAT_D16_UNORM_S8_UINT || - i == PAL_FORMAT_D24_UNORM_S8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - } + if (fmtInfo->usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { + if (i == PAL_FORMAT_S8_UINT) { + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - // fragment shading rate - if (i == PAL_FORMAT_R8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; - usages |= PAL_IMAGE_VIEW_USAGE_COLOR; - } + } else if (i == PAL_FORMAT_D16_UNORM || i == PAL_FORMAT_D32_SFLOAT) { + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - if (usages == 0) { - usages = PAL_IMAGE_VIEW_USAGE_COLOR; + } else { + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } } - - fmtInfo->viewUsages = usages; } } else { @@ -4804,33 +4792,61 @@ PalImageViewUsages PAL_CALL queryFormatImageViewUsagesVk( return PAL_IMAGE_VIEW_USAGE_UNDEFINED; } - // format supported. check if we have any depth or stencil component - // Note: this is a hack PalImageViewUsages usages = 0; - if (format == PAL_FORMAT_S8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + PalImageUsages imageUsages = ImageUsageFromVk(props.optimalTilingFeatures); + if (imageUsages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { + usages |= PAL_IMAGE_VIEW_USAGE_COLOR; + if (format == PAL_FORMAT_R8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; + } } - if (format == PAL_FORMAT_D16_UNORM || format == PAL_FORMAT_D32_SFLOAT) { - usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - } + if (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { + if (format == PAL_FORMAT_S8_UINT) { + usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - if (format == PAL_FORMAT_D32_SFLOAT_S8_UINT || format == PAL_FORMAT_D16_UNORM_S8_UINT || - format == PAL_FORMAT_D24_UNORM_S8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } else if (format == PAL_FORMAT_D16_UNORM || format == PAL_FORMAT_D32_SFLOAT) { + usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + + } else { + usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; + usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; + } } + return usages; +} - // fragment shading rate - if (format == PAL_FORMAT_R8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; - usages |= PAL_IMAGE_VIEW_USAGE_COLOR; +PalSampleCount PAL_CALL queryFormatSampleCountVk( + PalAdapter* adapter, + PalFormat format) +{ + // TODO: query for each format + PalSampleCount tmp = PAL_SAMPLE_COUNT_1; + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDeviceProperties deviceProps = {0}; + VkFormatProperties props = {0}; + + VkFormat fmt = formatToVk(format); + s_Vk.getPhysicalDeviceFormatProperties(vkAdapter->handle, fmt, &props); + s_Vk.getPhysicalDeviceProperties(vkAdapter->handle, &deviceProps); + if (props.optimalTilingFeatures == 0) { + return PAL_SAMPLE_COUNT_1; } - if (usages == 0) { - usages = PAL_IMAGE_VIEW_USAGE_COLOR; + // clang-format off + if (format == PAL_FORMAT_S8_UINT || + format == PAL_FORMAT_D16_UNORM || + format == PAL_FORMAT_D32_SFLOAT || + format == PAL_FORMAT_D16_UNORM_S8_UINT || + format == PAL_FORMAT_D32_SFLOAT_S8_UINT || + format == PAL_FORMAT_D24_UNORM_S8_UINT) { + // depth/stencil format + return samplesFromVk(deviceProps.limits.framebufferDepthSampleCounts); + } else { + // color format + return samplesFromVk(deviceProps.limits.framebufferColorSampleCounts); } - return usages; + // clang-format on } // ================================================== From 3886cacf9e50e6feeeabe007730165da48fd0674 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 31 Mar 2026 19:42:38 +0000 Subject: [PATCH 136/372] improve format sample count query vulkan --- src/graphics/pal_vulkan.c | 44 +++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 2c180930..1a585fd1 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -257,6 +257,7 @@ typedef struct { PFN_vkDestroyImageView destroyImageView; PFN_vkGetPhysicalDeviceProperties2 getPhysicalDeviceProperties2; PFN_vkGetPhysicalDeviceFormatProperties getPhysicalDeviceFormatProperties; + PFN_vkGetPhysicalDeviceImageFormatProperties getPhysicalDeviceImageFormatProperties; PFN_vkGetImageMemoryRequirements getImageMemoryRequirements; PFN_vkAllocateMemory allocateMemory; PFN_vkFreeMemory freeMemory; @@ -2389,6 +2390,10 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkGetPhysicalDeviceFormatProperties"); + s_Vk.getPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties)loadProc( + s_Vk.handle, + "vkGetPhysicalDeviceImageFormatProperties"); + s_Vk.createDevice = (PFN_vkCreateDevice)loadProc( s_Vk.handle, "vkCreateDevice"); @@ -4820,33 +4825,40 @@ PalSampleCount PAL_CALL queryFormatSampleCountVk( PalAdapter* adapter, PalFormat format) { - // TODO: query for each format - PalSampleCount tmp = PAL_SAMPLE_COUNT_1; + VkResult result; Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDeviceProperties deviceProps = {0}; VkFormatProperties props = {0}; + VkImageFormatProperties formatProps = {0}; VkFormat fmt = formatToVk(format); s_Vk.getPhysicalDeviceFormatProperties(vkAdapter->handle, fmt, &props); - s_Vk.getPhysicalDeviceProperties(vkAdapter->handle, &deviceProps); if (props.optimalTilingFeatures == 0) { return PAL_SAMPLE_COUNT_1; } - // clang-format off - if (format == PAL_FORMAT_S8_UINT || - format == PAL_FORMAT_D16_UNORM || - format == PAL_FORMAT_D32_SFLOAT || - format == PAL_FORMAT_D16_UNORM_S8_UINT || - format == PAL_FORMAT_D32_SFLOAT_S8_UINT || - format == PAL_FORMAT_D24_UNORM_S8_UINT) { - // depth/stencil format - return samplesFromVk(deviceProps.limits.framebufferDepthSampleCounts); + VkImageUsageFlags vkImageUsage = 0; + PalImageUsages imageUsages = ImageUsageFromVk(props.optimalTilingFeatures); + bool isDepth = (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) != 0; + if (isDepth) { + vkImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } else { - // color format - return samplesFromVk(deviceProps.limits.framebufferColorSampleCounts); + vkImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } - // clang-format on + + result = s_Vk.getPhysicalDeviceImageFormatProperties( + vkAdapter->handle, + fmt, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TILING_OPTIMAL, + vkImageUsage, + 0, + &formatProps); + + if (result != VK_SUCCESS) { + return PAL_SAMPLE_COUNT_1; + } + + return samplesFromVk(formatProps.sampleCounts); } // ================================================== From d386fd6a02fd6c692f1d13ca9f6e54b5af348130 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 1 Apr 2026 11:01:24 +0000 Subject: [PATCH 137/372] add image API d3d12 --- src/graphics/pal_d3d12.c | 190 +++++++++++++++++++++++++++++++++----- src/graphics/pal_vulkan.c | 27 +----- 2 files changed, 173 insertions(+), 44 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 73860c9f..2c3ad084 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -54,6 +54,7 @@ const IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4 const IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3}; const IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed}; const IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; +const IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -109,6 +110,16 @@ typedef struct { HWND handle; } Surface; +typedef struct { + const PalGraphicsBackend* backend; + + bool belongsToSwapchain; + ID3D12Device* device; + ID3D12Resource* handle; + PalImageInfo info; + D3D12_RESOURCE_DESC desc; +} Image; + static D3D12 s_D3D12 = {0}; // ================================================== @@ -382,6 +393,31 @@ static PalImageUsages ImageUsageFromD3D12(D3D12_FORMAT_SUPPORT1 flags) return usages; } +static Uint32 samplesToD3D12(PalSampleCount count) +{ + switch (count) { + case PAL_SAMPLE_COUNT_2: + return 2; + + case PAL_SAMPLE_COUNT_4: + return 4; + + case PAL_SAMPLE_COUNT_8: + return 8; + + case PAL_SAMPLE_COUNT_16: + return 16; + + case PAL_SAMPLE_COUNT_32: + return 32; + + case PAL_SAMPLE_COUNT_64: + return 64; + } + + return 1; +} + // ================================================== // Adapter // ================================================== @@ -623,9 +659,9 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapter* adapter, PalAdapterCapabilities* caps) { - caps->maxComputeQueues = PAL_INFINITE; - caps->maxGraphicsQueues = PAL_INFINITE; - caps->maxCopyQueues = PAL_INFINITE; + caps->maxComputeQueues = PAL_LIMIT_UNKNOWN; + caps->maxGraphicsQueues = PAL_LIMIT_UNKNOWN; + caps->maxCopyQueues = PAL_LIMIT_UNKNOWN; caps->maxImageWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; caps->maxImageHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; @@ -657,7 +693,7 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( } caps->maxUniformBufferSize = D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT * 16; - caps->maxStorageBufferSize = PAL_INFINITE; + caps->maxStorageBufferSize = PAL_LIMIT_UNKNOWN; caps->maxPushConstantSize = D3D12_MAX_ROOT_COST * 4; caps->maxComputeWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; @@ -820,6 +856,9 @@ PalResult PAL_CALL createDeviceD3D12( if (FAILED(result)) { palFree(s_D3D12.allocator, device); + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } return PAL_RESULT_INVALID_DRIVER; } @@ -1038,12 +1077,12 @@ PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( // these are only limited by memory. D3d12 does not expose them caps->maxRecursionDepth = 32; // 32 - 1; - caps->maxHitAttributeSize = PAL_INFINITE; - caps->maxInstanceCount = PAL_INFINITE; - caps->maxPrimitiveCount = PAL_INFINITE; - caps->maxGeometryCount = PAL_INFINITE; - caps->maxPayloadSize = PAL_INFINITE; - caps->maxDispatchInvocations = PAL_INFINITE; + caps->maxHitAttributeSize = PAL_LIMIT_UNKNOWN; + caps->maxInstanceCount = PAL_LIMIT_UNKNOWN; + caps->maxPrimitiveCount = PAL_LIMIT_UNKNOWN; + caps->maxGeometryCount = PAL_LIMIT_UNKNOWN; + caps->maxPayloadSize = PAL_LIMIT_UNKNOWN; + caps->maxDispatchInvocations = PAL_LIMIT_UNKNOWN; return PAL_RESULT_SUCCESS; } @@ -1063,15 +1102,15 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( caps->bindlessSamplers = true; // these are not exposed by d3d12. We use the offical resource binding spec - caps->maxImagesPerShaderStage = PAL_INFINITE; - caps->maxImagesPerDescriptorSet = PAL_INFINITE; + caps->maxImagesPerShaderStage = PAL_LIMIT_UNKNOWN; + caps->maxImagesPerDescriptorSet = PAL_LIMIT_UNKNOWN; caps->maxSamplersPerShaderStage = 2048; - caps->maxSamplersPerDescriptorSet = PAL_INFINITE; - caps->maxStorageBuffersPerShaderStage = PAL_INFINITE; - caps->maxUniformBuffersPerShaderStage = PAL_INFINITE; - caps->maxStorageBuffersPerDescriptorSet = PAL_INFINITE; - caps->maxUniformBuffersPerDescriptorSet = PAL_INFINITE; - caps->maxDescriptors = PAL_INFINITE; + caps->maxSamplersPerDescriptorSet = PAL_LIMIT_UNKNOWN; + caps->maxStorageBuffersPerShaderStage = PAL_LIMIT_UNKNOWN; + caps->maxUniformBuffersPerShaderStage = PAL_LIMIT_UNKNOWN; + caps->maxStorageBuffersPerDescriptorSet = PAL_LIMIT_UNKNOWN; + caps->maxUniformBuffersPerDescriptorSet = PAL_LIMIT_UNKNOWN; + caps->maxDescriptors = PAL_LIMIT_UNKNOWN; return PAL_RESULT_SUCCESS; } @@ -1469,26 +1508,104 @@ PalResult PAL_CALL createImageD3D12( const PalImageCreateInfo* info, PalImage** outImage) { + HRESULT result; + Image* image = nullptr; + Device* d3d12Device = (Device*)device; + + image = palAllocate(s_D3D12.allocator, sizeof(Image), 0); + if (!image) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(image, 0, sizeof(Image)); + image->desc.Width = (UINT64)info->width; + image->desc.Height = (UINT64)info->height; + image->desc.DepthOrArraySize = (UINT16)info->depthOrArraySize; + image->desc.MipLevels = (UINT16)info->mipLevelCount; + image->desc.Format = formatToD3D12(info->format); + image->desc.SampleDesc.Count = samplesToD3D12(info->sampleCount); + image->desc.SampleDesc.Quality = 0; + + image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + if (info->type == PAL_IMAGE_TYPE_3D) { + image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + + } else if (info->type == PAL_IMAGE_TYPE_1D) { + image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D; + } + + if (info->usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { + image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + } + + if (info->usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { + image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + } + if (info->usages & PAL_IMAGE_USAGE_STORAGE) { + image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + } + + image->belongsToSwapchain = false; + image->info.depthOrArraySize = info->depthOrArraySize; + image->info.type = info->type; + image->info.format = info->format; + image->info.usages = info->usages; + image->info.height = info->height; + image->info.mipLevelCount = info->mipLevelCount; + image->info.sampleCount = info->sampleCount; + image->info.width = info->width; + + image->device = d3d12Device->handle; + *outImage = (PalImage*)image; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyImageD3D12(PalImage* image) { - + Image* d3d12Image = (Image*)image; + // check if memory has been attached to the image + if (d3d12Image->handle) { + d3d12Image->handle->lpVtbl->Release(d3d12Image->handle); + } + palFree(s_D3D12.allocator, d3d12Image); } PalResult PAL_CALL getImageInfoD3D12( PalImage* image, PalImageInfo* info) { - + Image* d3d12Image = (Image*)image; + *info = d3d12Image->info; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL getImageMemoryRequirementsD3D12( PalImage* image, PalMemoryRequirements* requirements) { + Image* d3d12Image = (Image*)image; + if (d3d12Image->belongsToSwapchain) { + return PAL_RESULT_INVALID_OPERATION; + } + + D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; + D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; + allocationInfo = *d3d12Image->device->lpVtbl->GetResourceAllocationInfo( + d3d12Image->device, + &__ret, + 0, + 1, + &d3d12Image->desc); + // d3d12 allows images to be used with only GPU only heap + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = false; + + requirements->alignment = allocationInfo.Alignment; + requirements->size = allocationInfo.SizeInBytes; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL bindImageMemoryD3D12( @@ -1496,7 +1613,36 @@ PalResult PAL_CALL bindImageMemoryD3D12( PalMemory* memory, Uint64 offset) { + HRESULT result; + Image* d3d12Image = (Image*)image; + if (d3d12Image->belongsToSwapchain) { + return PAL_RESULT_INVALID_OPERATION; + } + + ID3D12Heap* mem = (ID3D12Heap*)memory; + result = d3d12Image->device->lpVtbl->CreatePlacedResource( + d3d12Image->device, + mem, + offset, + &d3d12Image->desc, + 0, + nullptr, + &IID_Resource, + (void**)d3d12Image->handle); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } else if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + + } else { + return PAL_RESULT_PLATFORM_FAILURE; + } + } + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL mapImageMemoryD3D12( @@ -1505,12 +1651,12 @@ PalResult PAL_CALL mapImageMemoryD3D12( Uint64 size, void** outPtr) { - + return PAL_RESULT_MEMORY_MAP_FAILED; } void PAL_CALL unmapImageMemoryD3D12(PalImage* image) { - + // do nothing. } // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 1a585fd1..1404fcf3 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1272,22 +1272,6 @@ static PalImageUsages ImageUsageFromVk(VkFormatFeatureFlags flags) return usages; } -static VkImageType imageTypeToVk(PalImageType type) -{ - switch (type) { - case PAL_IMAGE_TYPE_1D: - return VK_IMAGE_TYPE_1D; - - case PAL_IMAGE_TYPE_2D: - return VK_IMAGE_TYPE_2D; - - case PAL_IMAGE_TYPE_3D: - return VK_IMAGE_TYPE_3D; - } - - return VK_IMAGE_TYPE_2D; -} - static VkImageViewType imageViewTypeToVk(PalImageViewType type) { switch (type) { @@ -4874,10 +4858,6 @@ PalResult PAL_CALL createImageVk( Image* image = nullptr; Device* vkDevice = (Device*)device; - if (!vkDevice->handle) { - return PAL_RESULT_INVALID_DEVICE; - } - image = palAllocate(s_Vk.allocator, sizeof(Image), 0); if (!image) { return PAL_RESULT_OUT_OF_MEMORY; @@ -4895,14 +4875,17 @@ PalResult PAL_CALL createImageVk( createInfo.format = formatToVk(info->format); createInfo.samples = samplesToVk(info->sampleCount); createInfo.usage = imageUsageToVk(info->usages); - createInfo.arrayLayers = info->depthOrArraySize; createInfo.extent.depth = 1; - createInfo.imageType = imageTypeToVk(info->type); + createInfo.imageType = VK_IMAGE_TYPE_2D; if (info->type == PAL_IMAGE_TYPE_3D) { createInfo.arrayLayers = 1; createInfo.extent.depth = info->depthOrArraySize; + createInfo.imageType = VK_IMAGE_TYPE_3D; + + } else if (info->type == PAL_IMAGE_TYPE_1D) { + createInfo.imageType = VK_IMAGE_TYPE_1D; } result = s_Vk.createImage(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &image->handle); From ed78afb6a6d75449b5a7cd58a389fa66efa05dd0 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 1 Apr 2026 11:26:42 +0000 Subject: [PATCH 138/372] add image view API d3d12 --- include/pal/pal_graphics.h | 2 +- src/graphics/pal_d3d12.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index aff288e8..38a11673 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -528,7 +528,7 @@ typedef enum { /** * @enum PalImageViewUsages * @brief Image view usages. Multiple image view usages can be OR'ed together using bitwise - * OR operator (`|`). + * OR operator (`|`). Not all combination are valid. * * All image view usages follow the format `PAL_IMAGE_VIEW_USAGE_**` for * consistency and API use. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 2c3ad084..22c07b5e 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -120,6 +120,16 @@ typedef struct { D3D12_RESOURCE_DESC desc; } Image; +typedef struct { + const PalGraphicsBackend* backend; + + PalImageViewType type; + PalImageViewUsages usages; + Image* image; + D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; + D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle; +} ImageView; + static D3D12 s_D3D12 = {0}; // ================================================== @@ -1669,12 +1679,35 @@ PalResult PAL_CALL createImageViewD3D12( const PalImageViewCreateInfo* info, PalImageView** outImageView) { + HRESULT result; + ImageView* imageView = nullptr; + Device* d3d12Device = (Device*)device; + Image* d3d12Image = (Image*)image; + + if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + + imageView = palAllocate(s_D3D12.allocator, sizeof(ImageView), 0); + if (!imageView) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(imageView, 0, sizeof(ImageView)); + imageView->type = info->type; + imageView->usages = info->usages; + imageView->image = d3d12Image; + *outImageView = (ImageView*)imageView; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) { - + ImageView* d3d12ImageView = (ImageView*)imageView; + palFree(s_D3D12.allocator, d3d12ImageView); } // ================================================== From 89bbba9b6fa3b3e13c8776140e28723c1e34cb7c Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 1 Apr 2026 12:46:44 +0000 Subject: [PATCH 139/372] add sampler API d3d12 --- src/graphics/pal_d3d12.c | 190 +++++++++++++++++++++++++++++++- src/graphics/pal_vulkan.c | 226 +++++++++++++++----------------------- 2 files changed, 275 insertions(+), 141 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 22c07b5e..7f831bdf 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -130,6 +130,14 @@ typedef struct { D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle; } ImageView; +typedef struct { + const PalGraphicsBackend* backend; + + D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; + D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle; + D3D12_SAMPLER_DESC desc; +} Sampler; + static D3D12 s_D3D12 = {0}; // ================================================== @@ -428,6 +436,151 @@ static Uint32 samplesToD3D12(PalSampleCount count) return 1; } +static D3D12_COMPARISON_FUNC compareOpToD3D12(PalCompareOp op) +{ + switch (op) { + case PAL_COMPARE_OP_NEVER: + return D3D12_COMPARISON_FUNC_NEVER; + + case PAL_COMPARE_OP_LESS: + return D3D12_COMPARISON_FUNC_LESS; + + case PAL_COMPARE_OP_EQUAL: + return D3D12_COMPARISON_FUNC_EQUAL; + + case PAL_COMPARE_OP_LESS_OR_EQUAL: + return D3D12_COMPARISON_FUNC_LESS_EQUAL; + + case PAL_COMPARE_OP_GREATER: + return D3D12_COMPARISON_FUNC_GREATER; + + case PAL_COMPARE_OP_NOT_EQUAL: + return D3D12_COMPARISON_FUNC_NOT_EQUAL; + + case PAL_COMPARE_OP_GREATER_OR_EQUAL: + return D3D12_COMPARISON_FUNC_GREATER_EQUAL; + + case PAL_COMPARE_OP_ALWAYS: + return D3D12_COMPARISON_FUNC_ALWAYS; + } + + return D3D12_COMPARISON_FUNC_NEVER; +} + +static D3D12_FILTER filterToD3D12( + PalFilterMode minFilter, + PalFilterMode magFilter, + PalSamplerMipmapMode mode) +{ + // all the enums start with min so we start with min filter + switch (minFilter) { + case PAL_FILTER_MODE_NEAREST: { + switch (magFilter) { + case PAL_FILTER_MODE_NEAREST: { + // min and mag are nearest. Check sampler mipmap mode + if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { + return D3D12_FILTER_MIN_MAG_MIP_POINT; // sampler mode nearest + } else { + return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR; // sampler mode linear + } + } + + case PAL_FILTER_MODE_LINEAR: { + // min is nearest, mag is linear . Check sampler mipmap mode + if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { + return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; // sampler mode nearest + } else { + return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR; // sampler mode linear + } + } + } + } + + case PAL_FILTER_MODE_LINEAR: { + switch (magFilter) { + case PAL_FILTER_MODE_NEAREST: { + // min is linear, mag is nearest. Check sampler mipmap mode + if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { + return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT; // sampler mode nearest + } else { + return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; // sampler mode linear + } + } + + case PAL_FILTER_MODE_LINEAR: { + // min and mag are linear. Check sampler mipmap mode + if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { + return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; // sampler mode nearest + } else { + return D3D12_FILTER_MIN_MAG_MIP_LINEAR; // sampler mode linear + } + } + } + } + } + + return D3D12_FILTER_MIN_MAG_MIP_POINT; +} + +static D3D12_TEXTURE_ADDRESS_MODE addressModeToD3D12(PalSamplerAddressMode mode) +{ + switch (mode) { + case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { + return D3D12_TEXTURE_ADDRESS_MODE_WRAP; + } + + case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { + return D3D12_TEXTURE_ADDRESS_MODE_MIRROR; + + } + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { + return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + + } + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { + return D3D12_TEXTURE_ADDRESS_MODE_BORDER; + } + } + return D3D12_TEXTURE_ADDRESS_MODE_WRAP; +} + +static void borderColorToD3D12(PalBorderColor color, float outColor[4]) +{ + switch (color) { + case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: + case PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK: { + outColor[0] = 0.0f; + outColor[1] = 0.0f; + outColor[2] = 0.0f; + outColor[3] = 0.0f; + break; + } + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK: + case PAL_BORDER_COLOR_INT_OPAQUE_BLACK: { + outColor[0] = 0.0f; + outColor[1] = 0.0f; + outColor[2] = 0.0f; + outColor[3] = 1.0f; + break; + } + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE: + case PAL_BORDER_COLOR_INT_OPAQUE_WHITE: { + outColor[0] = 1.0f; + outColor[1] = 1.0f; + outColor[2] = 1.0f; + outColor[3] = 1.0f; + break; + } + } + + outColor[0] = 0.0f; + outColor[1] = 0.0f; + outColor[2] = 0.0f; + outColor[3] = 0.0f; +} + // ================================================== // Adapter // ================================================== @@ -1700,7 +1853,7 @@ PalResult PAL_CALL createImageViewD3D12( imageView->usages = info->usages; imageView->image = d3d12Image; - *outImageView = (ImageView*)imageView; + *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; } @@ -1719,12 +1872,45 @@ PalResult PAL_CALL createSamplerD3D12( const PalSamplerCreateInfo* info, PalSampler** outSampler) { + Sampler* sampler = nullptr; + sampler = palAllocate(s_D3D12.allocator, sizeof(Sampler), 0); + if (!sampler) { + return PAL_RESULT_OUT_OF_MEMORY; + } + memset(sampler, 0, sizeof(Sampler)); + sampler->desc.MaxLOD = info->maxLod; + sampler->desc.MinLOD = info->minLod; + sampler->desc.MipLODBias = info->mipLodBias; + + sampler->desc.MaxAnisotropy = 1; + if (info->enableAnisotropy) { + sampler->desc.MaxAnisotropy = info->maxAnisotropy; + } + + sampler->desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; + if (info->enableCompare) { + sampler->desc.ComparisonFunc = compareOpToD3D12(info->compareOp); + } + + borderColorToD3D12(info->borderColor, sampler->desc.BorderColor); + sampler->desc.AddressU = addressModeToD3D12(info->addressModeU); + sampler->desc.AddressV = addressModeToD3D12(info->addressModeV); + sampler->desc.AddressW = addressModeToD3D12(info->addressModeW); + + sampler->desc.Filter = filterToD3D12( + info->minFilterMode, + info->magFilterMode, + info->mipmapMode); + + *outSampler = (PalSampler*)sampler; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroySamplerD3D12(PalSampler* sampler) { - + Sampler* d3d12Sampler = (Sampler*)sampler; + palFree(s_D3D12.allocator, d3d12Sampler); } // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 1404fcf3..cc5d0471 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1730,6 +1730,86 @@ static VkPipelineStageFlags2 pipelineStageToVk(PalShaderStage stage) } return 0; } + +static VkFilter filterToVk(PalFilterMode mode) +{ + switch (mode) { + case PAL_FILTER_MODE_NEAREST: { + return VK_FILTER_NEAREST; + } + + case PAL_FILTER_MODE_LINEAR: { + return VK_FILTER_LINEAR; + } + } + return VK_FILTER_NEAREST; +} + +static VkSamplerMipmapMode mipmapModeToVk(PalSamplerMipmapMode mode) +{ + switch (mode) { + case PAL_SAMPLER_MIPMAP_MODE_NEAREST: { + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + } + + case PAL_SAMPLER_MIPMAP_MODE_LINEAR: { + return VK_SAMPLER_MIPMAP_MODE_LINEAR; + } + } + return VK_SAMPLER_MIPMAP_MODE_NEAREST; +} + +static VkSamplerAddressMode addressModeToVk(PalSamplerAddressMode mode) +{ + switch (mode) { + case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + } + + case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { + return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + + } + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + + } + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + } + } + return VK_SAMPLER_ADDRESS_MODE_REPEAT; +} + +static VkBorderColor borderColorToVk(PalBorderColor color) +{ + switch (color) { + case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: { + return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + } + + case PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK: { + return VK_BORDER_COLOR_INT_TRANSPARENT_BLACK; + } + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK: { + return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + } + + case PAL_BORDER_COLOR_INT_OPAQUE_BLACK: { + return VK_BORDER_COLOR_INT_OPAQUE_BLACK; + } + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE: { + return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + } + + case PAL_BORDER_COLOR_INT_OPAQUE_WHITE: { + return VK_BORDER_COLOR_INT_OPAQUE_WHITE; + } + } + return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; +} static Barrier barrierToVk( Uint32 stageCount, @@ -5126,146 +5206,14 @@ PalResult PAL_CALL createSamplerVk( createInfo.maxAnisotropy = info->maxAnisotropy; createInfo.compareOp = compareOpToVk(info->compareOp); - // min filter mode - switch (info->minFilterMode) { - case PAL_FILTER_MODE_LINEAR: { - createInfo.minFilter = VK_FILTER_LINEAR; - break; - } - - case PAL_FILTER_MODE_NEAREST: { - createInfo.minFilter = VK_FILTER_NEAREST; - break; - } - } + createInfo.minFilter = filterToVk(info->minFilterMode); + createInfo.magFilter = filterToVk(info->magFilterMode); + createInfo.mipmapMode = mipmapModeToVk(info->mipmapMode); - // mag filter mode - switch (info->magFilterMode) { - case PAL_FILTER_MODE_LINEAR: { - createInfo.magFilter = VK_FILTER_LINEAR; - break; - } - - case PAL_FILTER_MODE_NEAREST: { - createInfo.magFilter = VK_FILTER_NEAREST; - break; - } - } - - // sampler mipmap mode - switch (info->mipmapMode) { - case PAL_SAMPLER_MIPMAP_MODE_LINEAR: { - createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - break; - } - - case PAL_SAMPLER_MIPMAP_MODE_NEAREST: { - createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; - break; - } - } - - // sampler address mode u - switch (info->addressModeU) { - case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { - createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - break; - } - - case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { - createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; - break; - } - - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { - createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - break; - } - - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { - createInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - break; - } - } - - // sampler address mode v - switch (info->addressModeV) { - case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { - createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - break; - } - - case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { - createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; - break; - } - - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { - createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - break; - } - - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { - createInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - break; - } - } - - // sampler address mode w - switch (info->addressModeW) { - case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { - createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - break; - } - - case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { - createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; - break; - } - - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { - createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - break; - } - - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { - createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - break; - } - } - - // border color - switch (info->borderColor) { - case PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK: { - createInfo.addressModeW = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK; - break; - } - - case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: { - createInfo.addressModeW = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - break; - } - - case PAL_BORDER_COLOR_INT_OPAQUE_BLACK: { - createInfo.addressModeW = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - break; - } - - case PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK: { - createInfo.addressModeW = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - break; - } - - case PAL_BORDER_COLOR_INT_OPAQUE_WHITE: { - createInfo.addressModeW = VK_BORDER_COLOR_INT_OPAQUE_WHITE; - break; - } - - case PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE: { - createInfo.addressModeW = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - break; - } - } + createInfo.addressModeU = addressModeToVk(info->addressModeU); + createInfo.addressModeV = addressModeToVk(info->addressModeV); + createInfo.addressModeW = addressModeToVk(info->addressModeW); + createInfo.borderColor = borderColorToVk(info->borderColor); result = s_Vk.createSampler( vkDevice->handle, From f5cbd33542cd05bf08294d02490924a0404bfd8f Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 1 Apr 2026 16:19:17 +0000 Subject: [PATCH 140/372] add surface API d3d12 --- include/pal/pal_graphics.h | 8 +- src/graphics/pal_d3d12.c | 177 +++++++++++++++++++++++++++++++++++-- src/graphics/pal_vulkan.c | 16 ++-- tests/clear_color_test.c | 2 +- tests/mesh_test.c | 2 +- tests/texture_test.c | 2 +- tests/triangle_test.c | 2 +- 7 files changed, 184 insertions(+), 25 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 38a11673..81998a81 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -771,9 +771,9 @@ typedef enum { * @ingroup pal_graphics */ typedef enum { - PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB, - PAL_SURFACE_FORMAT_BGRA8_SRGB_SRGB, - PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB, + PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR, + PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR, + PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR, PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10, /**< HDR.*/ PAL_SURFACE_FORMAT_MAX @@ -2447,7 +2447,7 @@ typedef struct { Uint32 imageArrayLayerCount; /**< Set to 1 for default.*/ PalPresentMode presentMode; /**< (eg. PAL_PRESENT_MODE_FIFO).*/ PalCompositeAplha compositeAlpha; /**< (eg. PAL_COMPOSITE_ALPHA_OPAQUE).*/ - PalSurfaceFormat format; /**< (eg. PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB).*/ + PalSurfaceFormat format; /**< (eg. PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR).*/ } PalSwapchainCreateInfo; /** diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 7f831bdf..31d0f110 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -55,6 +55,7 @@ const IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e const IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed}; const IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; const IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad}; +const IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -92,6 +93,7 @@ typedef struct { PalAdapterFeatures features; IDXGIAdapter4* adapter; ID3D12InfoQueue* infoQueue; + ID3D12CommandQueue* queue; ID3D12Device* handle; } Device; @@ -138,6 +140,16 @@ typedef struct { D3D12_SAMPLER_DESC desc; } Sampler; +typedef struct { + const PalGraphicsBackend* backend; + + DXGI_SWAP_EFFECT swapEffect; + Uint32 syncInterval; + DXGI_FEATURE presentFlags; + Surface* surface; + IDXGISwapChain3* handle; +} Swapchain; + static D3D12 s_D3D12 = {0}; // ================================================== @@ -688,10 +700,10 @@ PalResult PAL_CALL enumerateAdaptersD3D12( palFree(s_D3D12.allocator, s_D3D12.adapters); } - while (s_D3D12.factory->lpVtbl->EnumAdapters( + while (SUCCEEDED(s_D3D12.factory->lpVtbl->EnumAdapters( s_D3D12.factory, adapterCount, - &adapter) != DXGI_ERROR_NOT_FOUND) { + &adapter))) { if (outAdapters) { IDXGIAdapter4* tmp = nullptr; if SUCCEEDED((adapter->lpVtbl->QueryInterface(adapter, &IID_Adapter, (void**)&tmp))) { @@ -1050,6 +1062,24 @@ PalResult PAL_CALL createDeviceD3D12( } } + // create a temporary graphics queue + D3D12_COMMAND_QUEUE_DESC desc = {0}; + desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + + result = device->handle->lpVtbl->CreateCommandQueue( + device->handle, + &desc, + &IID_Queue, + (void**)&device->queue); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } else { + return PAL_RESULT_PLATFORM_FAILURE; + } + } + device->adapter = d3d12Adapter->handle; device->features = features; *outDevice = (PalDevice*)device; @@ -1059,6 +1089,7 @@ PalResult PAL_CALL createDeviceD3D12( void PAL_CALL destroyDeviceD3D12(PalDevice* device) { Device* d3d12Device = (Device*)device; + d3d12Device->queue->lpVtbl->Release(d3d12Device->queue); d3d12Device->handle->lpVtbl->Release(d3d12Device->handle); if (d3d12Device->infoQueue) { d3d12Device->infoQueue->lpVtbl->Release(d3d12Device->infoQueue); @@ -1488,12 +1519,7 @@ bool PAL_CALL isFormatSupportedD3D12( &support, sizeof(support)); - if (FAILED(result)) { - return false; - } - - if (support.Support1 == 0 && support.Support2 == 0) { - // format not supported + if (FAILED(result) || (support.Support1 == 0 && support.Support2 == 0)) { return false; } @@ -1922,12 +1948,26 @@ PalResult PAL_CALL createSurfaceD3D12( PalGraphicsWindow* window, PalSurface** outSurface) { + Surface* surface = nullptr; + surface = palAllocate(s_D3D12.allocator, sizeof(Surface), 0); + if (!surface) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // validate if the window is valid + if (!IsWindow((HWND)window->window)) { + return PAL_RESULT_INVALID_GRAPHICS_WINDOW; + } + surface->handle = window->window; + *outSurface = (PalSurface*)surface; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroySurfaceD3D12(PalSurface* surface) { - + Surface* d3d12Surface = (Surface*)surface; + palFree(s_D3D12.allocator, d3d12Surface); } PalResult PAL_CALL getSurfaceCapabilitiesD3D12( @@ -1935,7 +1975,126 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( PalSurface* surface, PalSurfaceCapabilities* caps) { + HRESULT result; + Surface* d3d12Surface = (Surface*)surface; + Device* d3d12Device = (Device*)device; + bool supportHDR10 = false; + IDXGISwapChain1* swapchain1 = nullptr; + IDXGISwapChain3* swapchain3 = nullptr; + + DXGI_SWAP_CHAIN_DESC1 desc = {0}; + desc.Width = 1; + desc.Height = 1; + desc.SampleDesc.Count = 1; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = 1; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + + result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( + s_D3D12.factory, + (IUnknown*)d3d12Device->queue, + d3d12Surface->handle, + &desc, + nullptr, + nullptr, + &swapchain1); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + swapchain1->lpVtbl->QueryInterface(swapchain1, &IID_Swapchain, (void**)&swapchain3); + swapchain1->lpVtbl->Release(swapchain1); + + // check for HDR10 color space support + UINT flags = 0; + result = swapchain3->lpVtbl->CheckColorSpaceSupport( + swapchain3, + DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, + &flags); + + if (SUCCEEDED(result) && (flags & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) { + supportHDR10 = true; + } + + BOOL allowTearing = FALSE; + s_D3D12.factory->lpVtbl->CheckFeatureSupport( + s_D3D12.factory, + DXGI_FEATURE_PRESENT_ALLOW_TEARING, + &allowTearing, + sizeof(allowTearing)); + + caps->presentModes[PAL_PRESENT_MODE_FIFO] = true; + if (allowTearing) { + caps->minImageCount = 3; + caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = true; + caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = true; + } else { + caps->minImageCount = 2; + caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = false; + caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = false; + } + + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = true; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = false; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = false; + + caps->maxImageCount = PAL_LIMIT_UNKNOWN; + caps->minImageWidth = 1; + caps->minImageHeight = 1; + caps->maxImageWidth = PAL_LIMIT_UNKNOWN; + caps->maxImageHeight = PAL_LIMIT_UNKNOWN; + caps->maxImageArrayLayers = 1; + + // check support for the base format + D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport = {0}; + DXGI_FORMAT baseFormats[PAL_SURFACE_FORMAT_MAX]; + baseFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM; + baseFormats[1] = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + baseFormats[2] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + baseFormats[3] = DXGI_FORMAT_R16G16B16A16_FLOAT; + + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = false; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = false; + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = false; + caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = false; + + for (int i = 0; i < PAL_SURFACE_FORMAT_MAX; i++) { + formatSupport.Format = baseFormats[i]; + result = d3d12Device->handle->lpVtbl->CheckFeatureSupport( + d3d12Device->handle, + D3D12_FEATURE_FORMAT_SUPPORT, + &formatSupport, + sizeof(formatSupport)); + + if (SUCCEEDED(result) && (formatSupport.Support1 != 0 || formatSupport.Support2 != 0)) { + if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM) { + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = true; + } + + if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) { + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = true; + } + + if (baseFormats[i] == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) { + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = true; + } + + if (baseFormats[i] == DXGI_FORMAT_R16G16B16A16_FLOAT) { + // check HDR10 color space + if (supportHDR10) { + caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = true; + } + } + } + } + + swapchain3->lpVtbl->Release(swapchain3); + return PAL_RESULT_SUCCESS; } // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index cc5d0471..0051c439 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -5432,28 +5432,28 @@ PalResult PAL_CALL getSurfaceCapabilitiesVk( // get format and colorspace caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = false; - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB] = false; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_SRGB] = false; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB] = false; + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = false; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = false; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = false; for (int i = 0; i < formatCount; i++) { VkSurfaceFormatKHR* fmt = &formats[i]; if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB] = true; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = true; } } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_SRGB] = true; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = true; } } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB] = true; + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = true; } } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { @@ -5540,12 +5540,12 @@ PalResult PAL_CALL createSwapchainVk( createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; imageFormat = PAL_FORMAT_B8G8R8A8_UNORM; - if (info->format == PAL_SURFACE_FORMAT_BGRA8_SRGB_SRGB) { + if (info->format == PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR) { createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; imageFormat = PAL_FORMAT_B8G8R8A8_SRGB; - } else if (info->format == PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB) { + } else if (info->format == PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR) { createInfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; imageFormat = PAL_FORMAT_R8G8B8A8_UNORM; diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index f9b59bba..de56f980 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -222,7 +222,7 @@ bool clearColorTest() swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB; + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR; // rare but possible on andriod if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { diff --git a/tests/mesh_test.c b/tests/mesh_test.c index aceff9c1..af213dd3 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -275,7 +275,7 @@ bool meshTest() swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB; + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR; // rare but possible on andriod if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { diff --git a/tests/texture_test.c b/tests/texture_test.c index 8c2e9df9..ab246961 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -302,7 +302,7 @@ bool textureTest() swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB; + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR; // rare but possible on andriod if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 53fd673d..3c07238b 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -268,7 +268,7 @@ bool triangleTest() swapchainCreateInfo.width = WINDOW_WIDTH; swapchainCreateInfo.imageArrayLayerCount = 1; swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB; + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR; // rare but possible on andriod if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { From 079150f32f01b7ca7d19cef9ee0c78ae9986edcc Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 2 Apr 2026 17:26:13 +0000 Subject: [PATCH 141/372] add swapchain API d3d12 --- include/pal/pal_core.h | 4 +- include/pal/pal_graphics.h | 37 ++++- src/graphics/pal_d3d12.c | 303 ++++++++++++++++++++++++++++++++++-- src/graphics/pal_graphics.c | 29 ++++ src/graphics/pal_vulkan.c | 59 ++++++- src/pal_core.c | 6 + 6 files changed, 424 insertions(+), 14 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 1e98512c..ab4527fc 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -268,7 +268,9 @@ typedef enum { PAL_RESULT_INVALID_BUFFER, PAL_RESULT_INVALID_ACCELERATION_STRUCTURE, PAL_RESULT_MEMORY_MAP_FAILED, - PAL_RESULT_DEVICE_LOST + PAL_RESULT_DEVICE_LOST, + PAL_RESULT_SURFACE_LOST, + PAL_RESULT_SWAPCHAIN_OUT_OF_DATE } PalResult; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 81998a81..72648448 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3025,6 +3025,16 @@ typedef struct { PalSwapchain* swapchain, PalSwapchainPresentInfo* info); + /** + * Backend implementation of ::palResizeSwapchain. + * + * Must obey the rules and semantics documented in palResizeSwapchain(). + */ + PalResult PAL_CALL (*resizeSwapchain)( + PalSwapchain* swapchain, + Uint32 newWidth, + Uint32 newHeight); + /** * Backend implementation of ::palCreateShader. * @@ -4919,7 +4929,7 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safe if externally synchronized. + * Thread safety: Thread safe if `swapchain` externally synchronized. * * @since 1.4 * @ingroup pal_graphics @@ -4951,6 +4961,31 @@ PAL_API PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, PalSwapchainPresentInfo* info); +/** + * @brief Resize the provided swapchain. + * + * The graphics system must be initialized before this call. + * + * The swapchain images must not be in use before this call. All resources (image views) that + * reference the swapchain images must be destroyed and recreated. + * + * @param[in] swapchain Swapchain to resize. + * @param[in] newWidth The new width of the swapchain. + * @param[in] newHeight The new height of the swapchain. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `swapchain` externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palResizeSwapchain( + PalSwapchain* swapchain, + Uint32 newWidth, + Uint32 newHeight); + /** * @brief Create a shader. * diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 31d0f110..ba413bd3 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -100,7 +100,6 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - UINT64 fenceValue; PalQueueType type; ID3D12Fence* fence; ID3D12CommandQueue* handle; @@ -143,13 +142,28 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - DXGI_SWAP_EFFECT swapEffect; + Uint32 imageCount; Uint32 syncInterval; + Uint32 windowWidth; + Uint32 windowHeight; + Uint32 flags; + DXGI_FORMAT format; DXGI_FEATURE presentFlags; Surface* surface; + Image* images; + ID3D12CommandQueue* queue; IDXGISwapChain3* handle; } Swapchain; +typedef struct { + const PalGraphicsBackend* backend; + + bool isTimeline; + bool signaled; + UINT64 value; // for timeline semaphores + ID3D12Fence* handle; +} Fence, Semaphore; + static D3D12 s_D3D12 = {0}; // ================================================== @@ -1377,7 +1391,6 @@ PalResult PAL_CALL createQueueD3D12( } } - queue->fenceValue = 1; queue->type = type; *outQueue = (PalQueue*)queue; return PAL_RESULT_SUCCESS; @@ -1395,17 +1408,16 @@ PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) { Queue* d3d12Queue = (Queue*)queue; ID3D12Fence* fence = d3d12Queue->fence; - fence->lpVtbl->Signal(fence, d3d12Queue->fenceValue); + fence->lpVtbl->Signal(fence, 1); // wait on the fence if the submited work is not done - if (fence->lpVtbl->GetCompletedValue(fence) < d3d12Queue->fenceValue) { + if (fence->lpVtbl->GetCompletedValue(fence) < 1) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); - fence->lpVtbl->SetEventOnCompletion(fence, d3d12Queue->fenceValue, event); + fence->lpVtbl->SetEventOnCompletion(fence, 1, event); WaitForSingleObject(event, INFINITE); CloseHandle(event); } - d3d12Queue->fenceValue++; return PAL_RESULT_SUCCESS; } @@ -1948,6 +1960,11 @@ PalResult PAL_CALL createSurfaceD3D12( PalGraphicsWindow* window, PalSurface** outSurface) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + Surface* surface = nullptr; surface = palAllocate(s_D3D12.allocator, sizeof(Surface), 0); if (!surface) { @@ -1982,6 +1999,10 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( IDXGISwapChain1* swapchain1 = nullptr; IDXGISwapChain3* swapchain3 = nullptr; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + DXGI_SWAP_CHAIN_DESC1 desc = {0}; desc.Width = 1; desc.Height = 1; @@ -2039,6 +2060,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = false; } + // FIXME: Add support for pre and post multplied composite alpha caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = true; caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = false; caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = false; @@ -2108,19 +2130,170 @@ PalResult PAL_CALL createSwapchainD3D12( const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain) { + HRESULT result; + Surface* d3d12Surface = (Surface*)surface; + Device* d3d12Device = (Device*)device; + Queue* d3d12Queue = (Queue*)queue; + Swapchain* swapchain = nullptr; + bool isHDRColorspace = false; + + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + if (d3d12Queue->type != PAL_QUEUE_TYPE_GRAPHICS) { + return PAL_RESULT_INVALID_QUEUE; + } + + // FIXME: Add support for pre and post multplied composite alpha + if (info->compositeAlpha != PAL_COMPOSITE_ALPHA_OPAQUE) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (info->presentMode == PAL_PRESENT_MODE_MAILBOX && info->imageCount < 3) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + swapchain = palAllocate(s_D3D12.allocator, sizeof(Swapchain), 0); + if (!swapchain) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + IDXGISwapChain1* swapchain1 = nullptr; + DXGI_SWAP_CHAIN_DESC1 desc = {0}; + desc.Width = info->width; + desc.Height = info->height; + desc.SampleDesc.Count = 1; + desc.BufferCount = info->imageCount; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.Stereo = false; + desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + desc.Scaling = DXGI_SCALING_NONE; + + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + if (info->presentMode == PAL_PRESENT_MODE_FIFO) { + swapchain->presentFlags = 0; + swapchain->syncInterval = 1; + + } else if (info->presentMode == PAL_PRESENT_MODE_IMMEDIATE) { + desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + swapchain->presentFlags = DXGI_PRESENT_ALLOW_TEARING; + swapchain->syncInterval = 0; + + } else { + desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + swapchain->presentFlags = DXGI_PRESENT_ALLOW_TEARING; + swapchain->syncInterval = 0; + } + + PalFormat imageFormat; + if (info->format == PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR) { + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + imageFormat = PAL_FORMAT_B8G8R8A8_UNORM; + + } else if (info->format == PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR) { + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + imageFormat = PAL_FORMAT_B8G8R8A8_SRGB; + + } else if (info->format == PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR) { + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + imageFormat = PAL_FORMAT_R8G8B8A8_SRGB; + + } else if (info->format == PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10) { + desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + imageFormat = PAL_FORMAT_R16G16B16A16_SFLOAT; + isHDRColorspace = true; + } + + swapchain->format = desc.Format; + swapchain->flags = desc.Flags; + result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( + s_D3D12.factory, + (IUnknown*)d3d12Queue->handle, + d3d12Surface->handle, + &desc, + nullptr, + nullptr, + &swapchain1); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } else if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else { + return PAL_RESULT_PLATFORM_FAILURE; + } + } + + swapchain1->lpVtbl->QueryInterface(swapchain1, &IID_Swapchain, (void**)&swapchain->handle); + swapchain1->lpVtbl->Release(swapchain1); + + if (isHDRColorspace) { + swapchain->handle->lpVtbl->SetColorSpace1( + swapchain->handle, + DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); + } else { + swapchain->handle->lpVtbl->SetColorSpace1( + swapchain->handle, DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709); + } + // get and cache swapchain images + swapchain->images = nullptr; + swapchain->images = palAllocate(s_D3D12.allocator, sizeof(Image) * info->imageCount, 0); + if (!swapchain->imageCount) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // fill all images with the creatio info + for (int i = 0; i < info->imageCount; i++) { + ID3D12Resource* tmp = nullptr; + swapchain->handle->lpVtbl->GetBuffer(swapchain->handle, i, &IID_Resource, (void**)&tmp); + + Image* image = &swapchain->images[i]; + image->belongsToSwapchain = true; + image->device = d3d12Device->handle; + image->handle = tmp; + + image->info.depthOrArraySize = 1; // always 1 + image->info.format = imageFormat; + image->info.usages = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; + image->info.height = info->height; + image->info.width = info->width; + image->info.mipLevelCount = 1; + image->info.sampleCount = PAL_SAMPLE_COUNT_1; // swapchain images are not multisampled + image->info.type = PAL_IMAGE_TYPE_2D; + } + + // get and cache window size for swapchain out of date error + RECT windowRect; + GetClientRect((HWND)d3d12Surface->handle, &windowRect); + swapchain->windowWidth = windowRect.right - windowRect.left; + swapchain->windowWidth = windowRect.bottom - windowRect.top; + + swapchain->queue = d3d12Queue->handle; + swapchain->imageCount = info->imageCount; + *outSwapchain = (PalSwapchain*)swapchain; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) { - + Swapchain* d3d12Swapchain = (Swapchain*)swapchain; + d3d12Swapchain->handle->lpVtbl->Release(d3d12Swapchain->handle); + palFree(s_D3D12.allocator, d3d12Swapchain->images); + palFree(s_D3D12.allocator, d3d12Swapchain); } PalImage* PAL_CALL getSwapchainImageD3D12( PalSwapchain* swapchain, Int32 index) { - + Swapchain* d3d12Swapchain = (Swapchain*)swapchain; + if (index > d3d12Swapchain->imageCount) { + return nullptr; + } + return (PalImage*)&d3d12Swapchain->images[index]; } PalResult PAL_CALL getNextSwapchainImageD3D12( @@ -2128,14 +2301,126 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( PalSwapchainNextImageInfo* info, Uint32* outIndex) { + Uint32 index = 0; + Swapchain* d3d12Swapchain = (Swapchain*)swapchain; + ID3D12CommandQueue* queue = d3d12Swapchain->queue; + + index = d3d12Swapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3d12Swapchain->handle); + if (info->fence) { + Fence* fence = (Fence*)info->fence; + queue->lpVtbl->Signal(queue, fence->handle, 1); + fence->signaled = true; + } + if (info->signalSemaphore) { + Semaphore* semaphore = (Semaphore*)info->signalSemaphore; + if (semaphore->isTimeline) { + queue->lpVtbl->Signal(queue, semaphore->handle, info->signalValue); + } else { + queue->lpVtbl->Signal(queue, semaphore->handle, 1); + semaphore->signaled = true; + } + } + + *outIndex = index; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL presentSwapchainD3D12( PalSwapchain* swapchain, PalSwapchainPresentInfo* info) { + HRESULT result; + Swapchain* d3d12Swapchain = (Swapchain*)swapchain; + ID3D12CommandQueue* queue = d3d12Swapchain->queue; + + if (info->waitSemaphore) { + Semaphore* semaphore = (Semaphore*)info->waitSemaphore; + if (semaphore->isTimeline) { + queue->lpVtbl->Wait(queue, semaphore->handle, info->waitValue); + } else { + queue->lpVtbl->Signal(queue, semaphore->handle, 1); + semaphore->signaled = false; + } + } + + result = d3d12Swapchain->handle->lpVtbl->Present( + d3d12Swapchain->handle, + d3d12Swapchain->syncInterval, + d3d12Swapchain->presentFlags); + + if (FAILED(result)) { + if (result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET) { + return PAL_RESULT_DEVICE_LOST; + } + + // check if swapchain needs to be resize + RECT windowRect; + Uint32 w, h; + bool ret = GetClientRect((HWND)d3d12Swapchain->surface->handle, &windowRect); + w = windowRect.right - windowRect.left; + w = windowRect.bottom - windowRect.top; + + if (!ret) { + return PAL_RESULT_SURFACE_LOST; + } + + if (w != d3d12Swapchain->windowWidth || h != d3d12Swapchain->windowHeight) { + return PAL_RESULT_SWAPCHAIN_OUT_OF_DATE; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL resizeSwapchainD3D12( + PalSwapchain* swapchain, + Uint32 newWidth, + Uint32 newHeight) +{ + HRESULT result; + Swapchain* d3d12Swapchain = (Swapchain*)swapchain; + result = d3d12Swapchain->handle->lpVtbl->ResizeBuffers( + d3d12Swapchain->handle, + d3d12Swapchain->imageCount, + newWidth, + newHeight, + d3d12Swapchain->format, + d3d12Swapchain->flags); + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + // fill all images with the creatio info + for (int i = 0; i < d3d12Swapchain->imageCount; i++) { + ID3D12Resource* tmp = nullptr; + d3d12Swapchain->handle->lpVtbl->GetBuffer( + d3d12Swapchain->handle, + i, + &IID_Resource, + (void**)&tmp); + + Image* image = &d3d12Swapchain->images[i]; + image->handle = tmp; + image->info.height = newHeight; + image->info.width = newWidth; + } + + // get and cache window size for swapchain out of date error + RECT windowRect; + Surface* surface = d3d12Swapchain->surface; + if (!GetClientRect((HWND)surface->handle, &windowRect)) { + return PAL_RESULT_SURFACE_LOST; + } + + d3d12Swapchain->windowWidth = windowRect.right - windowRect.left; + d3d12Swapchain->windowWidth = windowRect.bottom - windowRect.top; + return PAL_RESULT_SUCCESS; } // ================================================== diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 0755e6e6..9ede6a6c 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -318,6 +318,11 @@ PalResult PAL_CALL presentSwapchainVk( PalSwapchain* swapchain, PalSwapchainPresentInfo* info); +PalResult PAL_CALL resizeSwapchainVk( + PalSwapchain* swapchain, + Uint32 newWidth, + Uint32 newHeight); + // ================================================== // Shader // ================================================== @@ -841,6 +846,7 @@ static PalGraphicsBackend s_VkBackend = { .getSwapchainImage = getSwapchainImageVk, .getNextSwapchainImage = getNextSwapchainImageVk, .presentSwapchain = presentSwapchainVk, + .resizeSwapchain = resizeSwapchainVk, // shader .createShader = createShaderVk, @@ -1178,6 +1184,11 @@ PalResult PAL_CALL presentSwapchainD3D12( PalSwapchain* swapchain, PalSwapchainPresentInfo* info); +PalResult PAL_CALL resizeSwapchainD3D12( + PalSwapchain* swapchain, + Uint32 newWidth, + Uint32 newHeight); + // ================================================== // Shader // ================================================== @@ -1701,6 +1712,7 @@ static PalGraphicsBackend s_D3D12Backend = { .getSwapchainImage = getSwapchainImageD3D12, .getNextSwapchainImage = getNextSwapchainImageD3D12, .presentSwapchain = presentSwapchainD3D12, + .resizeSwapchain = resizeSwapchainD3D12, // shader .createShader = createShaderD3D12, @@ -1904,6 +1916,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->getSwapchainImage || !backend->getNextSwapchainImage || !backend->presentSwapchain || + !backend->resizeSwapchain || // shader !backend->createShader || @@ -2822,6 +2835,22 @@ PalResult PAL_CALL palPresentSwapchain( return swapchain->backend->presentSwapchain(swapchain, info); } +PalResult PAL_CALL palResizeSwapchain( + PalSwapchain* swapchain, + Uint32 newWidth, + Uint32 newHeight) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!swapchain) { + return PAL_RESULT_NULL_POINTER; + } + + return swapchain->backend->resizeSwapchain(swapchain, newWidth, newHeight); +} + // ================================================== // Shader // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 0051c439..cbd55b8c 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -649,8 +649,7 @@ static PalResult resultFromVk(VkResult result) case VK_ERROR_INCOMPATIBLE_DRIVER: return PAL_RESULT_INVALID_DRIVER; - case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: - case VK_ERROR_SURFACE_LOST_KHR: { + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: { return PAL_RESULT_INVALID_WINDOW; } @@ -663,6 +662,12 @@ static PalResult resultFromVk(VkResult result) case VK_ERROR_DEVICE_LOST: return PAL_RESULT_DEVICE_LOST; + case VK_ERROR_SURFACE_LOST_KHR: + return PAL_RESULT_SURFACE_LOST; + + case VK_ERROR_OUT_OF_DATE_KHR: + return PAL_RESULT_SWAPCHAIN_OUT_OF_DATE; + default: return PAL_RESULT_PLATFORM_FAILURE; } @@ -5496,7 +5501,7 @@ PalResult PAL_CALL createSwapchainVk( // check if the queue is a graphics queue before we check its family // index for presentation support. if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { - PAL_RESULT_INVALID_QUEUE; + return PAL_RESULT_INVALID_QUEUE; } swapchain = palAllocate(s_Vk.allocator, sizeof(Swapchain), 0); @@ -5707,6 +5712,54 @@ PalResult PAL_CALL presentSwapchainVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL resizeSwapchainVk( + PalSwapchain* swapchain, + Uint32 newWidth, + Uint32 newHeight) +{ + VkResult result; + Swapchain* vkSwapchain = (Swapchain*)swapchain; + VkSwapchainKHR oldSwapchain = vkSwapchain->handle; + Device* device = vkSwapchain->device; + VkImage* images = nullptr; + + VkSwapchainCreateInfoKHR createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.oldSwapchain = oldSwapchain; + createInfo.imageExtent.width = newWidth; + createInfo.imageExtent.height = newHeight; + + result = device->createSwapchain( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &vkSwapchain->handle); + + if (result != VK_SUCCESS) { + return resultFromVk(result); + } + + Uint32 count = vkSwapchain->imageCount; + images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); + if (!images) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + device->destroySwapchain(device->handle, oldSwapchain, &s_Vk.vkAllocator); + device->getSwapchainImages(device->handle, vkSwapchain->handle, &count, images); + + // fill all images with the creatio info + for (int i = 0; i < count; i++) { + Image* image = &vkSwapchain->images[i]; + image->handle = images[i]; + image->info.height = createInfo.imageExtent.height; + image->info.width = createInfo.imageExtent.width; + } + + palFree(s_Vk.allocator, images); + return PAL_RESULT_SUCCESS; +} + // ================================================== // Shader // ================================================== diff --git a/src/pal_core.c b/src/pal_core.c index ff177ff0..d0096814 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -445,6 +445,12 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_DEVICE_LOST: return "Device lost"; + + case PAL_RESULT_SURFACE_LOST: + return "Surface lost"; + + case PAL_RESULT_SWAPCHAIN_OUT_OF_DATE: + return "Swapchain out of date"; } return "Unknown"; } From b0f1c82aded0eed248182d46f6f2793d830430fd Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 4 Apr 2026 12:21:47 +0000 Subject: [PATCH 142/372] add shader API d3d12 --- src/graphics/pal_d3d12.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index ba413bd3..3e60bf8c 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -164,6 +164,13 @@ typedef struct { ID3D12Fence* handle; } Fence, Semaphore; +typedef struct { + const PalGraphicsBackend* backend; + + PalShaderStage stage; + D3D12_SHADER_BYTECODE byteCode; +} Shader; + static D3D12 s_D3D12 = {0}; // ================================================== @@ -2432,12 +2439,43 @@ PalResult PAL_CALL createShaderD3D12( const PalShaderCreateInfo* info, PalShader** outShader) { + Device* d3d12Device = (Device*)device; + Shader* shader = nullptr; + if (info->stage == PAL_SHADER_STAGE_MESH || info->stage == PAL_SHADER_STAGE_TASK) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + // clang-format off + } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || + info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || + info->stage == PAL_SHADER_STAGE_ANY_HIT || + info->stage == PAL_SHADER_STAGE_MISS || + info->stage == PAL_SHADER_STAGE_INTERSECTION || + info->stage == PAL_SHADER_STAGE_CALLABLE) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + // clang-format on + + shader = palAllocate(s_D3D12.allocator, sizeof(Shader), 0); + if (!shader) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + shader->byteCode.pShaderBytecode = info->bytecode; + shader->byteCode.BytecodeLength = info->bytecodeSize; + shader->stage = info->stage; + *outShader = (Shader*)shader; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyShaderD3D12(PalShader* shader) { - + Shader* d3d12Shader = (Shader*)shader; + palFree(s_D3D12.allocator, d3d12Shader); } // ================================================== From 1ed553120573d14be88f2154da6e1da05d14ee5c Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 4 Apr 2026 12:41:20 +0000 Subject: [PATCH 143/372] add sempahore API d3d12 --- src/graphics/pal_d3d12.c | 81 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 3e60bf8c..b536940f 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -160,6 +160,7 @@ typedef struct { bool isTimeline; bool signaled; + bool canReset; UINT64 value; // for timeline semaphores ID3D12Fence* handle; } Fence, Semaphore; @@ -1418,7 +1419,7 @@ PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) fence->lpVtbl->Signal(fence, 1); // wait on the fence if the submited work is not done - if (fence->lpVtbl->GetCompletedValue(fence) < 1) { + if (fence->lpVtbl->GetCompletedValue(fence) != 1) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); fence->lpVtbl->SetEventOnCompletion(fence, 1, event); WaitForSingleObject(event, INFINITE); @@ -2315,8 +2316,10 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( index = d3d12Swapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3d12Swapchain->handle); if (info->fence) { Fence* fence = (Fence*)info->fence; - queue->lpVtbl->Signal(queue, fence->handle, 1); - fence->signaled = true; + if (!fence->signaled) { + queue->lpVtbl->Signal(queue, fence->handle, 1); + fence->signaled = true; + } } if (info->signalSemaphore) { @@ -2487,29 +2490,97 @@ PalResult PAL_CALL createFenceD3D12( bool signaled, PalFence** outFence) { + HRESULT result; + Device* d3d12Device = (Device*)device; + Fence* fence = nullptr; + fence = palAllocate(s_D3D12.allocator, sizeof(Fence), 0); + + if (!fence) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + result = d3d12Device->handle->lpVtbl->CreateFence( + d3d12Device->handle, + 0, + 0, + &IID_Fence, + (void**)&fence->handle); + if (FAILED(result)) { + palFree(s_D3D12.allocator, fence); + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } else { + return PAL_RESULT_PLATFORM_FAILURE; + } + } + + fence->signaled = false; + if (signaled) { + fence->signaled = true; + } + + fence->canReset = false; + if (d3d12Device->features & PAL_ADAPTER_FEATURE_FENCE_RESET) { + fence->canReset = true; + } + + fence->isTimeline = false; // for sempaphores + fence->value = 0; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyFenceD3D12(PalFence* fence) { - + Fence* d3d12Fence = (Fence*)fence; + d3d12Fence->handle->lpVtbl->Release(d3d12Fence->handle); + palFree(s_D3D12.allocator, d3d12Fence); } PalResult PAL_CALL waitFenceD3D12( PalFence* fence, Uint64 timeout) { + Fence* d3d12Fence = (Fence*)fence; + DWORD ret = 0; + if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) != 1) { + HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + d3d12Fence->handle->lpVtbl->SetEventOnCompletion(d3d12Fence->handle, 1, event); + + if (timeout == PAL_INFINITE) { + ret = WaitForSingleObject(event, INFINITE); + + } else { + ret = WaitForSingleObject(event, timeout); + } + CloseHandle(event); + } + + if (ret == WAIT_TIMEOUT) { + return PAL_RESULT_TIMEOUT; + } else if (ret == WAIT_FAILED) { + return PAL_RESULT_INVALID_FENCE; + } + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL resetFenceD3D12(PalFence* fence) { + Fence* d3d12Fence = (Fence*)fence; + if (!d3d12Fence->canReset) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + d3d12Fence->signaled = false; + return PAL_RESULT_SUCCESS; } bool PAL_CALL isFenceSignaledD3D12(PalFence* fence) { - + Fence* d3d12Fence = (Fence*)fence; + return d3d12Fence->signaled; } // ================================================== From 7cc0bd80e7aa2946ad2eca7ecd22e39eaa76674d Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 4 Apr 2026 13:55:14 +0000 Subject: [PATCH 144/372] add semaphore API d3d12 --- include/pal/pal_graphics.h | 6 +- src/graphics/pal_d3d12.c | 176 +++++++++++++++++++++++++++--------- src/graphics/pal_graphics.c | 10 +- src/graphics/pal_vulkan.c | 4 +- 4 files changed, 141 insertions(+), 55 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 72648448..0aaad5ba 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3135,7 +3135,7 @@ typedef struct { */ PalResult PAL_CALL (*getSemaphoreValue)( PalSemaphore* semaphore, - Uint64* value); + Uint64* outValue); /** * Backend implementation of ::palCreateCommandPool. @@ -5258,7 +5258,7 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] semaphore Semaphore to get its value. - * @param[out] value Pointer to a Uint64 to receive the semaphore value. + * @param[out] outValue Pointer to a Uint64 to receive the semaphore value. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5272,7 +5272,7 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( */ PAL_API PalResult PAL_CALL palGetSemaphoreValue( PalSemaphore* semaphore, - Uint64* value); + Uint64* outValue); /** * @brief Create a command pool from a device. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index b536940f..f05dcabe 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -100,6 +100,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + Uint32 fenceValue; PalQueueType type; ID3D12Fence* fence; ID3D12CommandQueue* handle; @@ -159,9 +160,8 @@ typedef struct { const PalGraphicsBackend* backend; bool isTimeline; - bool signaled; bool canReset; - UINT64 value; // for timeline semaphores + UINT64 value; ID3D12Fence* handle; } Fence, Semaphore; @@ -1097,9 +1097,8 @@ PalResult PAL_CALL createDeviceD3D12( if (FAILED(result)) { if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; - } else { - return PAL_RESULT_PLATFORM_FAILURE; } + return PAL_RESULT_PLATFORM_FAILURE; } device->adapter = d3d12Adapter->handle; @@ -1377,9 +1376,8 @@ PalResult PAL_CALL createQueueD3D12( palFree(s_D3D12.allocator, queue); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; - } else { - return PAL_RESULT_PLATFORM_FAILURE; } + return PAL_RESULT_PLATFORM_FAILURE; } // create fence used for queue wait @@ -1394,11 +1392,11 @@ PalResult PAL_CALL createQueueD3D12( palFree(s_D3D12.allocator, queue); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; - } else { - return PAL_RESULT_PLATFORM_FAILURE; } + return PAL_RESULT_PLATFORM_FAILURE; } + queue->fenceValue = 0; queue->type = type; *outQueue = (PalQueue*)queue; return PAL_RESULT_SUCCESS; @@ -1416,16 +1414,16 @@ PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) { Queue* d3d12Queue = (Queue*)queue; ID3D12Fence* fence = d3d12Queue->fence; - fence->lpVtbl->Signal(fence, 1); + d3d12Queue->fenceValue++; + fence->lpVtbl->Signal(fence, d3d12Queue->fenceValue); // wait on the fence if the submited work is not done - if (fence->lpVtbl->GetCompletedValue(fence) != 1) { + if (fence->lpVtbl->GetCompletedValue(fence) < d3d12Queue->fenceValue) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); - fence->lpVtbl->SetEventOnCompletion(fence, 1, event); + fence->lpVtbl->SetEventOnCompletion(fence, d3d12Queue->fenceValue, event); WaitForSingleObject(event, INFINITE); CloseHandle(event); } - return PAL_RESULT_SUCCESS; } @@ -1842,13 +1840,10 @@ PalResult PAL_CALL bindImageMemoryD3D12( if (FAILED(result)) { if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; - } else if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; - - } else { - return PAL_RESULT_PLATFORM_FAILURE; } + return PAL_RESULT_PLATFORM_FAILURE; } return PAL_RESULT_SUCCESS; @@ -2229,9 +2224,8 @@ PalResult PAL_CALL createSwapchainD3D12( return PAL_RESULT_OUT_OF_MEMORY; } else if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; - } else { - return PAL_RESULT_PLATFORM_FAILURE; } + return PAL_RESULT_PLATFORM_FAILURE; } swapchain1->lpVtbl->QueryInterface(swapchain1, &IID_Swapchain, (void**)&swapchain->handle); @@ -2316,10 +2310,8 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( index = d3d12Swapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3d12Swapchain->handle); if (info->fence) { Fence* fence = (Fence*)info->fence; - if (!fence->signaled) { - queue->lpVtbl->Signal(queue, fence->handle, 1); - fence->signaled = true; - } + fence->value++; + queue->lpVtbl->Signal(queue, fence->handle, fence->value++); } if (info->signalSemaphore) { @@ -2327,8 +2319,8 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( if (semaphore->isTimeline) { queue->lpVtbl->Signal(queue, semaphore->handle, info->signalValue); } else { - queue->lpVtbl->Signal(queue, semaphore->handle, 1); - semaphore->signaled = true; + semaphore->value = 1; + queue->lpVtbl->Signal(queue, semaphore->handle, semaphore->value); } } @@ -2349,8 +2341,9 @@ PalResult PAL_CALL presentSwapchainD3D12( if (semaphore->isTimeline) { queue->lpVtbl->Wait(queue, semaphore->handle, info->waitValue); } else { - queue->lpVtbl->Signal(queue, semaphore->handle, 1); - semaphore->signaled = false; + queue->lpVtbl->Wait(queue, semaphore->handle, semaphore->value); + semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); + semaphore->value = 0; } } @@ -2471,7 +2464,7 @@ PalResult PAL_CALL createShaderD3D12( shader->byteCode.pShaderBytecode = info->bytecode; shader->byteCode.BytecodeLength = info->bytecodeSize; shader->stage = info->stage; - *outShader = (Shader*)shader; + *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } @@ -2493,8 +2486,8 @@ PalResult PAL_CALL createFenceD3D12( HRESULT result; Device* d3d12Device = (Device*)device; Fence* fence = nullptr; + fence = palAllocate(s_D3D12.allocator, sizeof(Fence), 0); - if (!fence) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2510,14 +2503,8 @@ PalResult PAL_CALL createFenceD3D12( palFree(s_D3D12.allocator, fence); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; - } else { - return PAL_RESULT_PLATFORM_FAILURE; } - } - - fence->signaled = false; - if (signaled) { - fence->signaled = true; + return PAL_RESULT_PLATFORM_FAILURE; } fence->canReset = false; @@ -2527,6 +2514,7 @@ PalResult PAL_CALL createFenceD3D12( fence->isTimeline = false; // for sempaphores fence->value = 0; + *outFence = (PalFence*)fence; return PAL_RESULT_SUCCESS; } @@ -2541,16 +2529,27 @@ PalResult PAL_CALL waitFenceD3D12( PalFence* fence, Uint64 timeout) { + HRESULT result; Fence* d3d12Fence = (Fence*)fence; DWORD ret = 0; + Uint64 value = d3d12Fence->value; - if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) != 1) { + if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) < value) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); - d3d12Fence->handle->lpVtbl->SetEventOnCompletion(d3d12Fence->handle, 1, event); - + result = d3d12Fence->handle->lpVtbl->SetEventOnCompletion( + d3d12Fence->handle, + value, + event); + + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_FENCE; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + if (timeout == PAL_INFINITE) { ret = WaitForSingleObject(event, INFINITE); - } else { ret = WaitForSingleObject(event, timeout); } @@ -2559,8 +2558,6 @@ PalResult PAL_CALL waitFenceD3D12( if (ret == WAIT_TIMEOUT) { return PAL_RESULT_TIMEOUT; - } else if (ret == WAIT_FAILED) { - return PAL_RESULT_INVALID_FENCE; } return PAL_RESULT_SUCCESS; @@ -2573,14 +2570,18 @@ PalResult PAL_CALL resetFenceD3D12(PalFence* fence) return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - d3d12Fence->signaled = false; + d3d12Fence->handle->lpVtbl->Signal(d3d12Fence->handle, 0); + d3d12Fence->value = 0; return PAL_RESULT_SUCCESS; } bool PAL_CALL isFenceSignaledD3D12(PalFence* fence) { Fence* d3d12Fence = (Fence*)fence; - return d3d12Fence->signaled; + if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) == 0) { + return false; + } + return true; } // ================================================== @@ -2591,12 +2592,46 @@ PalResult PAL_CALL createSemaphoreD3D12( PalDevice* device, PalSemaphore** outSemaphore) { + HRESULT result; + Device* d3d12Device = (Device*)device; + Semaphore* semaphore = nullptr; + + semaphore = palAllocate(s_D3D12.allocator, sizeof(Semaphore), 0); + if (!semaphore) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + result = d3d12Device->handle->lpVtbl->CreateFence( + d3d12Device->handle, + 0, + 0, + &IID_Fence, + (void**)&semaphore->handle); + + if (FAILED(result)) { + palFree(s_D3D12.allocator, semaphore); + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + semaphore->isTimeline = false; + if (d3d12Device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + semaphore->isTimeline = true; + } + semaphore->canReset = false; + semaphore->value = 0; + *outSemaphore = (PalSemaphore*)semaphore; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore) { - + Semaphore* d3d12Semaphore = (Semaphore*)semaphore; + d3d12Semaphore->handle->lpVtbl->Release(d3d12Semaphore->handle); + palFree(s_D3D12.allocator, d3d12Semaphore); } PalResult PAL_CALL waitSemaphoreD3D12( @@ -2604,7 +2639,39 @@ PalResult PAL_CALL waitSemaphoreD3D12( Uint64 value, Uint64 timeout) { + HRESULT result; + DWORD ret = 0; + Semaphore* d3d12Semaphore = (Semaphore*)semaphore; + if (!d3d12Semaphore->isTimeline) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + if (d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle) < value) { + HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + result = d3d12Semaphore->handle->lpVtbl->SetEventOnCompletion( + d3d12Semaphore->handle, + value, + event); + + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_SEMAPHORE; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + if (timeout == PAL_INFINITE) { + ret = WaitForSingleObject(event, INFINITE); + } else { + ret = WaitForSingleObject(event, timeout); + } + CloseHandle(event); + } + + if (ret == WAIT_TIMEOUT) { + return PAL_RESULT_TIMEOUT; + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL signalSemaphoreD3D12( @@ -2612,14 +2679,33 @@ PalResult PAL_CALL signalSemaphoreD3D12( PalQueue* queue, Uint64 value) { + Semaphore* d3d12Semaphore = (Semaphore*)semaphore; + if (!d3d12Semaphore->isTimeline) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + HRESULT result = d3d12Semaphore->handle->lpVtbl->Signal(d3d12Semaphore->handle, value); + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_SEMAPHORE; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL getSemaphoreValueD3D12( PalSemaphore* semaphore, - Uint64* value) + Uint64* outValue) { + Semaphore* d3d12Semaphore = (Semaphore*)semaphore; + if (!d3d12Semaphore->isTimeline) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + UINT64 tmp = d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle); + *outValue = tmp; + return PAL_RESULT_SUCCESS; } // ================================================== diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 9ede6a6c..cd500814 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -375,7 +375,7 @@ PalResult PAL_CALL signalSemaphoreVk( PalResult PAL_CALL getSemaphoreValueVk( PalSemaphore* semaphore, - Uint64* value); + Uint64* outValue); // ================================================== // Command Pool And Buffer @@ -1241,7 +1241,7 @@ PalResult PAL_CALL signalSemaphoreD3D12( PalResult PAL_CALL getSemaphoreValueD3D12( PalSemaphore* semaphore, - Uint64* value); + Uint64* outValue); // ================================================== // Command Pool And Buffer @@ -3028,17 +3028,17 @@ PalResult PAL_CALL palSignalSemaphore( PalResult PAL_CALL palGetSemaphoreValue( PalSemaphore* semaphore, - Uint64* value) + Uint64* outValue) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!semaphore || !value) { + if (!semaphore || !outValue) { return PAL_RESULT_NULL_POINTER; } - return semaphore->backend->getSemaphoreValue(semaphore, value); + return semaphore->backend->getSemaphoreValue(semaphore, outValue); } // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index cbd55b8c..e5232523 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -6043,7 +6043,7 @@ PalResult PAL_CALL signalSemaphoreVk( PalResult PAL_CALL getSemaphoreValueVk( PalSemaphore* semaphore, - Uint64* value) + Uint64* outValue) { Semaphore* vkSemaphore = (Semaphore*)semaphore; if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { @@ -6053,7 +6053,7 @@ PalResult PAL_CALL getSemaphoreValueVk( VkResult result = vkSemaphore->device->getSemaphoreValue( vkSemaphore->device->handle, vkSemaphore->handle, - value); + outValue); if (result != VK_SUCCESS) { return resultFromVk(result); From 3a708a2c7c2b99344eebd97f731602a2879a79cc Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 4 Apr 2026 22:31:34 +0000 Subject: [PATCH 145/372] add command pool and buffer API d3d12 --- src/graphics/pal_d3d12.c | 218 +++++++++++++++++++++++++++++++++++- src/graphics/pal_graphics.c | 8 +- 2 files changed, 219 insertions(+), 7 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index f05dcabe..fd7bb482 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -56,6 +56,8 @@ const IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x7 const IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; const IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad}; const IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1}; +const IID IID_CmdAlloc = {0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73,0xf0,0x9b,0x24}; +const IID IID_CmdList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -172,6 +174,27 @@ typedef struct { D3D12_SHADER_BYTECODE byteCode; } Shader; +typedef struct { + const PalGraphicsBackend* backend; + + bool primary; + void* pool; // CommandPool + ID3D12CommandAllocator* allocator; + ID3D12GraphicsCommandList* handle; +} CommandBuffer; + +typedef struct { + bool used; + CommandBuffer* cmdBuffer; +} CommandBufferData; + +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 size; + CommandBufferData* cmdBuffersData; +} CommandPool; + static D3D12 s_D3D12 = {0}; // ================================================== @@ -615,6 +638,46 @@ static void borderColorToD3D12(PalBorderColor color, float outColor[4]) outColor[3] = 0.0f; } +static CommandBufferData* getFreeCmdBufferData(CommandPool* pool) +{ + for (int i = 0; i < pool->size; ++i) { + if (!pool->cmdBuffersData[i].used) { + pool->cmdBuffersData[i].used = true; + return &pool->cmdBuffersData[i]; + } + } + + // resize the data array + CommandBufferData* data = nullptr; + int count = pool->size * 2; // double the size + int freeIndex = pool->size + 1; + + data = palAllocate(s_D3D12.allocator, sizeof(CommandBufferData) * count, 0); + if (data) { + memcpy(data, pool->cmdBuffersData, pool->size * sizeof(CommandBufferData)); + + palFree(s_D3D12.allocator, pool->cmdBuffersData); + pool->cmdBuffersData = data; + pool->size = count; + + pool->cmdBuffersData[freeIndex].used = true; + return &pool->cmdBuffersData[freeIndex]; + } + return nullptr; +} + +static CommandBufferData* findCmdBufferData( + CommandPool* pool, + CommandBuffer* cmdBuffer) +{ + for (int i = 0; i < pool->size; ++i) { + if (pool->cmdBuffersData[i].used && pool->cmdBuffersData[i].cmdBuffer == cmdBuffer) { + return &pool->cmdBuffersData[i]; + } + } + return nullptr; +} + // ================================================== // Adapter // ================================================== @@ -2311,7 +2374,7 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( if (info->fence) { Fence* fence = (Fence*)info->fence; fence->value++; - queue->lpVtbl->Signal(queue, fence->handle, fence->value++); + queue->lpVtbl->Signal(queue, fence->handle, fence->value); } if (info->signalSemaphore) { @@ -2717,43 +2780,192 @@ PalResult PAL_CALL createCommandPoolD3D12( PalQueue* queue, PalCommandPool** outPool) { + HRESULT result; + CommandPool* pool = nullptr; + pool = palAllocate(s_D3D12.allocator, sizeof(CommandPool), 0); + if (!pool) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + pool->size = 8; + pool->cmdBuffersData = nullptr; + Uint32 size = sizeof(CommandBufferData) * pool->size; + pool->cmdBuffersData = palAllocate(s_D3D12.allocator, size, 0); + if (!pool->cmdBuffersData) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + *outPool = (PalCommandPool*)pool; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) { + CommandPool* cmdPool = (CommandPool*)pool; + for (int i = 0; i < cmdPool->size; i++) { + if (!cmdPool->cmdBuffersData[i].used) { + continue; + } + + CommandBuffer* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; + cmdBuffer->handle->lpVtbl->Release(cmdBuffer->handle); + cmdBuffer->allocator->lpVtbl->Release(cmdBuffer->allocator); + palFree(s_D3D12.allocator, cmdBuffer); + } + palFree(s_D3D12.allocator, cmdPool->cmdBuffersData); + palFree(s_D3D12.allocator, cmdPool); } PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool) { + CommandPool* cmdPool = (CommandPool*)pool; + for (int i = 0; i < cmdPool->size; i++) { + if (!cmdPool->cmdBuffersData[i].used) { + continue; + } + CommandBuffer* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; + cmdBuffer->handle->lpVtbl->Reset(cmdBuffer->handle, cmdBuffer->allocator, nullptr); + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL allocateCommandBufferD3D12( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, - PalCommandBuffer** outBuffer) + PalCommandBuffer** outCmdBuffer) { + HRESULT result; + Device* d3d12Device = (Device*)device; + CommandBuffer* cmdBuffer = nullptr; + CommandPool* cmdPool = (CommandPool*)pool; + + cmdBuffer = palAllocate(s_D3D12.allocator, sizeof(CommandBuffer), 0); + if (!cmdBuffer) { + return PAL_RESULT_OUT_OF_MEMORY; + } + D3D12_COMMAND_LIST_TYPE cmdBufferType = D3D12_COMMAND_LIST_TYPE_DIRECT; + cmdBuffer->primary = true; + if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { + cmdBufferType = D3D12_COMMAND_LIST_TYPE_BUNDLE; + cmdBuffer->primary = false; + } + + // create an allocator + result = d3d12Device->handle->lpVtbl->CreateCommandAllocator( + d3d12Device->handle, + cmdBufferType, + &IID_CmdAlloc, + (void**)&cmdBuffer->allocator); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + // create the command list + result = d3d12Device->handle->lpVtbl->CreateCommandList( + d3d12Device->handle, + 0, + cmdBufferType, + cmdBuffer->allocator, + nullptr, + &IID_CmdList, + (void**)&cmdBuffer->handle); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + cmdBuffer->pool = cmdPool; + *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; + return PAL_RESULT_SUCCESS; } -void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* buffer) +void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) { + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + CommandPool* pool = d3d12CmdBuffer->pool; + CommandBufferData* data = findCmdBufferData(pool, d3d12CmdBuffer); + if (data) { + d3d12CmdBuffer->handle->lpVtbl->Release(d3d12CmdBuffer->handle); + d3d12CmdBuffer->allocator->lpVtbl->Release(d3d12CmdBuffer->allocator); + palFree(s_D3D12.allocator, cmdBuffer); + data->cmdBuffer = nullptr; + data->used = false; + } } PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) { + HRESULT result; + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + result = d3d12CmdBuffer->allocator->lpVtbl->Reset(d3d12CmdBuffer->allocator); + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + d3d12CmdBuffer->handle->lpVtbl->Reset( + d3d12CmdBuffer->handle, + d3d12CmdBuffer->allocator, + nullptr); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL submitCommandBufferD3D12( PalQueue* queue, PalCommandBufferSubmitInfo* info) { + HRESULT result; + Queue* d3d12Queue = (Queue*)queue; + ID3D12CommandQueue* queueHandle = d3d12Queue->handle; + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)info->cmdBuffer; + + // wait semaphore + if (info->waitSemaphore) { + Semaphore* semaphore = (Semaphore*)info->waitSemaphore; + if (semaphore->isTimeline) { + queueHandle->lpVtbl->Wait(queueHandle, semaphore->handle, info->waitValue); + } else { + queueHandle->lpVtbl->Wait(queueHandle, semaphore->handle, semaphore->value); + semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); + semaphore->value = 0; + } + } + ID3D12CommandList* tmp = (ID3D12CommandList*)d3d12CmdBuffer->handle; + queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, &tmp); + if (info->fence) { + Fence* fence = (Fence*)info->fence; + fence->value++; + queueHandle->lpVtbl->Signal(queueHandle, fence->handle, fence->value); + } + + if (info->signalSemaphore) { + Semaphore* semaphore = (Semaphore*)info->signalSemaphore; + if (semaphore->isTimeline) { + queueHandle->lpVtbl->Signal(queueHandle, semaphore->handle, info->signalValue); + } else { + semaphore->value = 1; + queueHandle->lpVtbl->Signal(queueHandle, semaphore->handle, semaphore->value); + } + } + + return PAL_RESULT_SUCCESS; } // ================================================== diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index cd500814..dc789b09 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -394,9 +394,9 @@ PalResult PAL_CALL allocateCommandBufferVk( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, - PalCommandBuffer** outBuffer); + PalCommandBuffer** outCmdBuffer); -void PAL_CALL freeCommandBufferVk(PalCommandBuffer* buffer); +void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer); PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer); @@ -1260,9 +1260,9 @@ PalResult PAL_CALL allocateCommandBufferD3D12( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, - PalCommandBuffer** outBuffer); + PalCommandBuffer** outCmdBuffer); -void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* buffer); +void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer); PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer); From e7706e9544c175b1cd10825a2e05b273c584be54 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 5 Apr 2026 01:36:47 +0000 Subject: [PATCH 146/372] add command recording API part 1 d3d12 --- include/pal/pal_graphics.h | 90 +++--------- src/graphics/pal_d3d12.c | 279 ++++++++++++++++++++++++++++++++---- src/graphics/pal_graphics.c | 114 ++++----------- src/graphics/pal_vulkan.c | 111 +++++--------- tests/graphics_test.c | 16 ++- 5 files changed, 352 insertions(+), 258 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 0aaad5ba..db824093 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -606,7 +606,9 @@ typedef enum { PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(28), PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(29), PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(31) + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH = PAL_BIT64(31), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT = PAL_BIT64(32), + PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(33) } PalAdapterFeatures; /** @@ -3248,9 +3250,7 @@ typedef struct { PalResult PAL_CALL (*cmdDrawMeshTasksIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 drawCount, - Uint32 stride); + Uint32 drawCount); /** * Backend implementation of ::palCmdDrawMeshTasksIndirectCount. @@ -3261,10 +3261,7 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride); + Uint32 maxDrawCount); /** * Backend implementation of ::palCmdBuildAccelerationStructure. @@ -3408,9 +3405,7 @@ typedef struct { PalResult PAL_CALL (*cmdDrawIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride); + Uint32 count); /** * Backend implementation of ::palCmdDrawIndirectCount. @@ -3421,10 +3416,7 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 count, - Uint32 stride); + Uint32 count); /** * Backend implementation of ::palCmdDrawIndexed. @@ -3447,9 +3439,7 @@ typedef struct { PalResult PAL_CALL (*cmdDrawIndexedIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride); + Uint32 count); /** * Backend implementation of ::palCmdDrawIndexedIndirectCount. @@ -3460,10 +3450,7 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 count, - Uint32 stride); + Uint32 count); /** * Backend implementation of ::palCmdMemoryBarrier. @@ -3530,8 +3517,7 @@ typedef struct { */ PalResult PAL_CALL (*cmdDispatchIndirect)( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - Uint64 offset); + PalBuffer* buffer); /** * Backend implementation of ::palCmdTraceRays. @@ -5532,17 +5518,14 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported + * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH` must be supported * and enabled by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. * Can be a single struct. - * @param[in] offset Starting byte offset into `buffer`. * @param[in] drawCount Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. - * Must be greater or equal to sizeof(PalDispatchIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5556,16 +5539,14 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 drawCount, - Uint32 stride); + Uint32 drawCount); /** * @brief Dispatch mesh shader workgroups using parameters from buffers. * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be + * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT` must be * supported and enabled by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * @@ -5573,11 +5554,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. * Can be a single struct. * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. - * @param[in] offset Starting byte offset into `buffer`. - * @param[in] countBufferOffset Starting byte offset into `countBuffer`. * @param[in] maxDrawCount Maximum Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. - * Must be greater or equal to sizeof(PalDispatchIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5592,10 +5569,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride); + Uint32 maxDrawCount); /** * @brief Build or update an acceleration structure. @@ -5919,10 +5893,7 @@ PAL_API PalResult PAL_CALL palCmdDraw( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. * Can be a single struct. - * @param[in] offset Starting byte offset into `buffer`. * @param[in] count Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. - * Must be greater or equal to sizeof(PalDrawIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5936,9 +5907,7 @@ PAL_API PalResult PAL_CALL palCmdDraw( PAL_API PalResult PAL_CALL palCmdDrawIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride); + Uint32 count); /** * @brief Issue a non-indexed draw command using buffers. @@ -5952,11 +5921,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirect( * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. * Can be a single struct. * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. - * @param[in] offset Starting byte offset into `buffer`. - * @param[in] countBufferOffset Starting byte offset into `countBuffer`. * @param[in] maxDrawCount Maximum Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. - * Must be greater or equal to sizeof(PalDrawIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5971,10 +5936,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride); + Uint32 maxDrawCount); /** * @brief Issue an indexed draw command. @@ -6016,10 +5978,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexed( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. * Can be a single struct. - * @param[in] offset Starting byte offset into `buffer`. * @param[in] count Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. - * Must be greater or equal to sizeof(PalDrawIndexedIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6033,9 +5992,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexed( PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride); + Uint32 count); /** * @brief Issue an indexed draw command using buffers. @@ -6049,11 +6006,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. * Can be a single struct. * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. - * @param[in] offset Starting byte offset into `buffer`. - * @param[in] countBufferOffset Starting byte offset into `countBuffer`. * @param[in] maxDrawCount Maximum Number of draws to perform. - * @param[in] stride Size in bytes of each parameter struct in `buffer`. - * Must be greater or equal to sizeof(PalDrawIndexedIndirectData). * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6068,10 +6021,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride); + Uint32 maxDrawCount); /** * @brief Insert a memory barrier into the command buffer. @@ -6246,7 +6196,6 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. * Can be a single struct. - * @param[in] offset Starting byte offset into `buffer`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6259,8 +6208,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( */ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - Uint64 offset); + PalBuffer* buffer); /** * @brief Dispatch rays. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index fd7bb482..224d0184 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -58,6 +58,8 @@ const IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98, const IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1}; const IID IID_CmdAlloc = {0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73,0xf0,0x9b,0x24}; const IID IID_CmdList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5}; +const IID IID_CmdList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96,0xcf, 0x56,0x89,0xa9,0x37,0x0f,0x80}; +const IID IID_Signature = {0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -94,6 +96,10 @@ typedef struct { PalAdapterFeatures features; IDXGIAdapter4* adapter; + ID3D12CommandSignature* meshSignature; + ID3D12CommandSignature* drawIndexedSignature; + ID3D12CommandSignature* drawSignature; + ID3D12CommandSignature* dispatchSignature; ID3D12InfoQueue* infoQueue; ID3D12CommandQueue* queue; ID3D12Device* handle; @@ -179,8 +185,10 @@ typedef struct { bool primary; void* pool; // CommandPool + Device* device; ID3D12CommandAllocator* allocator; ID3D12GraphicsCommandList* handle; + ID3D12GraphicsCommandList6* handle6; } CommandBuffer; typedef struct { @@ -195,6 +203,12 @@ typedef struct { CommandBufferData* cmdBuffersData; } CommandPool; +typedef struct { + const PalGraphicsBackend* backend; + + ID3D12Resource* handle; +} Buffer; + static D3D12 s_D3D12 = {0}; // ================================================== @@ -678,6 +692,56 @@ static CommandBufferData* findCmdBufferData( return nullptr; } +static D3D12_SHADING_RATE_COMBINER combinerOpsToD3D12(PalFragmentShadingRateCombinerOp op) +{ + switch (op) { + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP: + return D3D12_SHADING_RATE_COMBINER_PASSTHROUGH; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE: + return D3D12_SHADING_RATE_COMBINER_OVERRIDE; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN: + return D3D12_SHADING_RATE_COMBINER_MIN; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX: + return D3D12_SHADING_RATE_COMBINER_MAX; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL: + return D3D12_SHADING_RATE_COMBINER_SUM; + } + + return D3D12_SHADING_RATE_COMBINER_PASSTHROUGH; +} + +static D3D12_SHADING_RATE shadingRateToD3D12(PalFragmentShadingRate rate) +{ + switch (rate) { + case PAL_FRAGMENT_SHADING_RATE_1X1: + return D3D12_SHADING_RATE_1X1; + + case PAL_FRAGMENT_SHADING_RATE_1X2: + return D3D12_SHADING_RATE_1X2; + + case PAL_FRAGMENT_SHADING_RATE_2X1: + return D3D12_SHADING_RATE_2X1; + + case PAL_FRAGMENT_SHADING_RATE_2X2: + return D3D12_SHADING_RATE_2X2; + + case PAL_FRAGMENT_SHADING_RATE_2X4: + return D3D12_SHADING_RATE_2X4; + + case PAL_FRAGMENT_SHADING_RATE_4X2: + return D3D12_SHADING_RATE_4X2; + + case PAL_FRAGMENT_SHADING_RATE_4X4: + return D3D12_SHADING_RATE_4X4; + } + + return D3D12_SHADING_RATE_1X1; +} + // ================================================== // Adapter // ================================================== @@ -1064,6 +1128,8 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) if (options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED) { features |= PAL_ADAPTER_FEATURE_MESH_SHADER; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT; } if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_3) { @@ -1082,6 +1148,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY; features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; if (d3d12Adapter->level >= D3D_FEATURE_LEVEL_12_0) { features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; @@ -1164,6 +1231,87 @@ PalResult PAL_CALL createDeviceD3D12( return PAL_RESULT_PLATFORM_FAILURE; } + // create command signatures + D3D12_INDIRECT_ARGUMENT_DESC argumentDesc = {0}; + D3D12_COMMAND_SIGNATURE_DESC signatureDesc = {0}; + signatureDesc.NumArgumentDescs = 1; + signatureDesc.pArgumentDescs = &argumentDesc; + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH) { + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH; + signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_MESH_ARGUMENTS); + + result = device->handle->lpVtbl->CreateCommandSignature( + device->handle, + &signatureDesc, + nullptr, + &IID_Signature, + (void**)&device->meshSignature); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW) { + // disptach indexed + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; + signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS); + + result = device->handle->lpVtbl->CreateCommandSignature( + device->handle, + &signatureDesc, + nullptr, + &IID_Signature, + (void**)&device->dispatchSignature); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + // draw indexed + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; + signatureDesc.ByteStride = sizeof(D3D12_DRAW_INDEXED_ARGUMENTS); + + result = device->handle->lpVtbl->CreateCommandSignature( + device->handle, + &signatureDesc, + nullptr, + &IID_Signature, + (void**)&device->drawIndexedSignature); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + // draw + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; + signatureDesc.ByteStride = sizeof(D3D12_DRAW_ARGUMENTS); + + result = device->handle->lpVtbl->CreateCommandSignature( + device->handle, + &signatureDesc, + nullptr, + &IID_Signature, + (void**)&device->drawSignature); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + } + device->adapter = d3d12Adapter->handle; device->features = features; *outDevice = (PalDevice*)device; @@ -1173,6 +1321,23 @@ PalResult PAL_CALL createDeviceD3D12( void PAL_CALL destroyDeviceD3D12(PalDevice* device) { Device* d3d12Device = (Device*)device; + + if (d3d12Device->meshSignature) { + d3d12Device->meshSignature->lpVtbl->Release(d3d12Device->meshSignature); + } + + if (d3d12Device->dispatchSignature) { + d3d12Device->dispatchSignature->lpVtbl->Release(d3d12Device->dispatchSignature); + } + + if (d3d12Device->drawIndexedSignature) { + d3d12Device->drawIndexedSignature->lpVtbl->Release(d3d12Device->drawIndexedSignature); + } + + if (d3d12Device->drawSignature) { + d3d12Device->drawSignature->lpVtbl->Release(d3d12Device->drawSignature); + } + d3d12Device->queue->lpVtbl->Release(d3d12Device->queue); d3d12Device->handle->lpVtbl->Release(d3d12Device->handle); if (d3d12Device->infoQueue) { @@ -2809,6 +2974,7 @@ void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) } CommandBuffer* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; + cmdBuffer->handle6->lpVtbl->Release(cmdBuffer->handle6); cmdBuffer->handle->lpVtbl->Release(cmdBuffer->handle); cmdBuffer->allocator->lpVtbl->Release(cmdBuffer->allocator); palFree(s_D3D12.allocator, cmdBuffer); @@ -2886,7 +3052,13 @@ PalResult PAL_CALL allocateCommandBufferD3D12( return PAL_RESULT_PLATFORM_FAILURE; } + cmdBuffer->handle->lpVtbl->QueryInterface( + cmdBuffer->handle, + &IID_CmdList6, + (void**)&cmdBuffer->handle6); + cmdBuffer->pool = cmdPool; + cmdBuffer->device = d3d12Device; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; } @@ -2897,6 +3069,7 @@ void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) CommandPool* pool = d3d12CmdBuffer->pool; CommandBufferData* data = findCmdBufferData(pool, d3d12CmdBuffer); if (data) { + d3d12CmdBuffer->handle6->lpVtbl->Release(d3d12CmdBuffer->handle6); d3d12CmdBuffer->handle->lpVtbl->Release(d3d12CmdBuffer->handle); d3d12CmdBuffer->allocator->lpVtbl->Release(d3d12CmdBuffer->allocator); palFree(s_D3D12.allocator, cmdBuffer); @@ -2976,26 +3149,53 @@ PalResult PAL_CALL cmdBeginD3D12( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) { - + return resetCommandBufferD3D12(cmdBuffer); } PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer) { - + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + d3d12CmdBuffer->handle->lpVtbl->Close(d3d12CmdBuffer->handle); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdExecuteCommandBufferD3D12( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { + CommandBuffer* d3d12PrimaryCmdBuffer = (CommandBuffer*)primaryCmdBuffer; + CommandBuffer* d3d12SecondaryCmdBuffer = (CommandBuffer*)secondaryCmdBuffer; + d3d12PrimaryCmdBuffer->handle->lpVtbl->ExecuteBundle( + d3d12PrimaryCmdBuffer->handle, + d3d12SecondaryCmdBuffer->handle); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { + HRESULT result; + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + D3D12_SHADING_RATE shadingRate = shadingRateToD3D12(state->rate); + D3D12_SHADING_RATE_COMBINER combinerOps[2]; + for (int i = 0; i < 2; i++) { + combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); + } + + d3d12CmdBuffer->handle6->lpVtbl->RSSetShadingRate( + d3d12CmdBuffer->handle6, + shadingRate, + combinerOps); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdDrawMeshTasksD3D12( @@ -3004,29 +3204,69 @@ PalResult PAL_CALL cmdDrawMeshTasksD3D12( Uint32 groupCountY, Uint32 groupCountZ) { + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + d3d12CmdBuffer->handle6->lpVtbl->DispatchMesh( + d3d12CmdBuffer->handle6, + groupCountX, + groupCountY, + groupCountZ); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 drawCount, - Uint32 stride) + Uint32 drawCount) { + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + Buffer* d3d12Buffer = (Buffer*)buffer; + d3d12CmdBuffer->handle6->lpVtbl->ExecuteIndirect( + d3d12CmdBuffer->handle6, + device->meshSignature, + drawCount, + d3d12Buffer->handle, + 0, + nullptr, + 0); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride) + Uint32 maxDrawCount) { + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + Buffer* d3d12Buffer = (Buffer*)buffer; + Buffer* d3d12CountBuffer = (Buffer*)countBuffer; + d3d12CmdBuffer->handle6->lpVtbl->ExecuteIndirect( + d3d12CmdBuffer->handle6, + device->meshSignature, + maxDrawCount, + d3d12Buffer->handle, + 0, + d3d12CountBuffer->handle, + 0); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( @@ -3140,9 +3380,7 @@ PalResult PAL_CALL cmdDrawD3D12( PalResult PAL_CALL cmdDrawIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride) + Uint32 count) { } @@ -3151,10 +3389,7 @@ PalResult PAL_CALL cmdDrawIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride) + Uint32 maxDrawCount) { } @@ -3173,9 +3408,7 @@ PalResult PAL_CALL cmdDrawIndexedD3D12( PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride) + Uint32 count) { } @@ -3184,10 +3417,7 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride) + Uint32 maxDrawCount) { } @@ -3242,8 +3472,7 @@ PalResult PAL_CALL cmdDispatchBaseD3D12( PalResult PAL_CALL cmdDispatchIndirectD3D12( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - Uint64 offset) + PalBuffer* buffer) { } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index dc789b09..571a4af3 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -431,18 +431,13 @@ PalResult PAL_CALL cmdDrawMeshTasksVk( PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 drawCount, - Uint32 stride); + Uint32 drawCount); PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride); + Uint32 maxDrawCount); PalResult PAL_CALL cmdBuildAccelerationStructureVk( PalCommandBuffer* cmdBuffer, @@ -516,18 +511,13 @@ PalResult PAL_CALL cmdDrawVk( PalResult PAL_CALL cmdDrawIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride); + Uint32 count); PalResult PAL_CALL cmdDrawIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride); + Uint32 maxDrawCount); PalResult PAL_CALL cmdDrawIndexedVk( PalCommandBuffer* cmdBuffer, @@ -540,18 +530,13 @@ PalResult PAL_CALL cmdDrawIndexedVk( PalResult PAL_CALL cmdDrawIndexedIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride); + Uint32 count); PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride); + Uint32 maxDrawCount); PalResult PAL_CALL cmdMemoryBarrierVk( PalCommandBuffer* cmdBuffer, @@ -588,8 +573,7 @@ PalResult PAL_CALL cmdDispatchBaseVk( PalResult PAL_CALL cmdDispatchIndirectVk( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - Uint64 offset); + PalBuffer* buffer); PalResult PAL_CALL cmdTraceRaysVk( PalCommandBuffer* cmdBuffer, @@ -1297,18 +1281,13 @@ PalResult PAL_CALL cmdDrawMeshTasksD3D12( PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 drawCount, - Uint32 stride); + Uint32 drawCount); PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride); + Uint32 maxDrawCount); PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( PalCommandBuffer* cmdBuffer, @@ -1382,18 +1361,13 @@ PalResult PAL_CALL cmdDrawD3D12( PalResult PAL_CALL cmdDrawIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride); + Uint32 count); PalResult PAL_CALL cmdDrawIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride); + Uint32 maxDrawCount); PalResult PAL_CALL cmdDrawIndexedD3D12( PalCommandBuffer* cmdBuffer, @@ -1406,18 +1380,13 @@ PalResult PAL_CALL cmdDrawIndexedD3D12( PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride); + Uint32 count); PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride); + Uint32 maxDrawCount); PalResult PAL_CALL cmdMemoryBarrierD3D12( PalCommandBuffer* cmdBuffer, @@ -1454,8 +1423,7 @@ PalResult PAL_CALL cmdDispatchBaseD3D12( PalResult PAL_CALL cmdDispatchIndirectD3D12( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - Uint64 offset); + PalBuffer* buffer); PalResult PAL_CALL cmdTraceRaysD3D12( PalCommandBuffer* cmdBuffer, @@ -3233,9 +3201,7 @@ PalResult PAL_CALL palCmdDrawMeshTasks( PalResult PAL_CALL palCmdDrawMeshTasksIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 drawCount, - Uint32 stride) + Uint32 drawCount) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3245,18 +3211,14 @@ PalResult PAL_CALL palCmdDrawMeshTasksIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend - ->cmdDrawMeshTasksIndirect(cmdBuffer, buffer, offset, drawCount, stride); + return cmdBuffer->backend->cmdDrawMeshTasksIndirect(cmdBuffer, buffer, drawCount); } PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride) + Uint32 maxDrawCount) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3270,10 +3232,7 @@ PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( cmdBuffer, buffer, countBuffer, - offset, - countBufferOffset, - maxDrawCount, - stride); + maxDrawCount); } PalResult PAL_CALL palCmdBuildAccelerationStructure( @@ -3508,9 +3467,7 @@ PalResult PAL_CALL palCmdDraw( PalResult PAL_CALL palCmdDrawIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride) + Uint32 count) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3520,17 +3477,14 @@ PalResult PAL_CALL palCmdDrawIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdDrawIndirect(cmdBuffer, buffer, offset, count, stride); + return cmdBuffer->backend->cmdDrawIndirect(cmdBuffer, buffer, count); } PalResult PAL_CALL palCmdDrawIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride) + Uint32 maxDrawCount) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3544,10 +3498,7 @@ PalResult PAL_CALL palCmdDrawIndirectCount( cmdBuffer, buffer, countBuffer, - offset, - countBufferOffset, - maxDrawCount, - stride); + maxDrawCount); } PalResult PAL_CALL palCmdDrawIndexed( @@ -3578,9 +3529,7 @@ PalResult PAL_CALL palCmdDrawIndexed( PalResult PAL_CALL palCmdDrawIndexedIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride) + Uint32 count) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3590,17 +3539,14 @@ PalResult PAL_CALL palCmdDrawIndexedIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdDrawIndexedIndirect(cmdBuffer, buffer, offset, count, stride); + return cmdBuffer->backend->cmdDrawIndexedIndirect(cmdBuffer, buffer, count); } PalResult PAL_CALL palCmdDrawIndexedIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride) + Uint32 maxDrawCount) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3614,10 +3560,7 @@ PalResult PAL_CALL palCmdDrawIndexedIndirectCount( cmdBuffer, buffer, countBuffer, - offset, - countBufferOffset, - maxDrawCount, - stride); + maxDrawCount); } PalResult PAL_CALL palCmdMemoryBarrier( @@ -3723,8 +3666,7 @@ PalResult PAL_CALL palCmdDispatchBase( PalResult PAL_CALL palCmdDispatchIndirect( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - Uint64 offset) + PalBuffer* buffer) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3734,7 +3676,7 @@ PalResult PAL_CALL palCmdDispatchIndirect( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdDispatchIndirect(cmdBuffer, buffer, offset); + return cmdBuffer->backend->cmdDispatchIndirect(cmdBuffer, buffer); } PalResult PAL_CALL palCmdTraceRays( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e5232523..70c87016 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3340,6 +3340,9 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } else if (strcmp(props->extensionName, "VK_KHR_draw_indirect_count") == 0) { adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; + } else if (strcmp(props->extensionName, "VK_KHR_draw_mesh_tasks_indirect_count") == 0) { + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT; + } else if (strcmp(props->extensionName, "VK_KHR_buffer_device_address") == 0) { bufferDeviceAddress = true; @@ -3380,6 +3383,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); if (mesh.meshShader && mesh.taskShader) { adapterFeatures |= PAL_ADAPTER_FEATURE_MESH_SHADER; + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH; } } @@ -3793,6 +3797,11 @@ PalResult PAL_CALL createDeviceVk( // mesh shader needs geometry feature for primitives coreFeatures.geometryShader = true; + // msh draw indirect count + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT) { + extensions[extCount++] = "VK_KHR_draw_mesh_tasks_indirect_count"; + } + mesh.pNext = next; next = &mesh; } @@ -6331,34 +6340,8 @@ PalResult PAL_CALL cmdSetFragmentShadingRateVk( VkExtent2D size = getShadingRateSizeVk(state->rate); VkFragmentShadingRateCombinerOpKHR combinerOps[2]; - for (int i = 0; i < 2; i++) { - switch (state->combinerOps[i]) { - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP: { - combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; - continue; - } - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE: { - combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; - continue; - } - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN: { - combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR; - continue; - } - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX: { - combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR; - continue; - } - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL: { - combinerOps[i] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR; - continue; - } - } + combinerOps[i] = combinerOpsToVk(state->combinerOps[i]); } device->cmdSetFragmentShadingRate(vkCmdBuffer->handle, &size, combinerOps); @@ -6385,27 +6368,22 @@ PalResult PAL_CALL cmdDrawMeshTasksVk( PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 drawCount, - Uint32 stride) + Uint32 drawCount) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = vkCmdBuffer->device; Buffer* vkBuffer = (Buffer*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + Uint32 stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); device->cmdDrawMeshTaskIndirect( vkCmdBuffer->handle, - vkBuffer->handle, - offset, - drawCount, + vkBuffer->handle, + 0, + drawCount, stride); return PAL_RESULT_SUCCESS; @@ -6415,30 +6393,24 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride) + Uint32 maxDrawCount) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = vkCmdBuffer->device; Buffer* vkBuffer = (Buffer*)buffer; Buffer* vkCountBuffer = (Buffer*)countBuffer; - if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + Uint32 stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); device->cmdDrawMeshTaskIndirectCount( vkCmdBuffer->handle, vkBuffer->handle, - offset, + 0, vkCountBuffer->handle, - countBufferOffset, + 0, maxDrawCount, stride); @@ -6988,13 +6960,13 @@ PalResult PAL_CALL cmdDrawVk( PalResult PAL_CALL cmdDrawIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride) + Uint32 count) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.cmdDrawIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset, count, stride); + Uint32 stride = sizeof(VkDrawIndirectCommand); + + s_Vk.cmdDrawIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); return PAL_RESULT_SUCCESS; } @@ -7002,10 +6974,7 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride) + Uint32 maxDrawCount) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; @@ -7016,12 +6985,13 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + Uint32 stride = sizeof(VkDrawIndirectCommand); device->cmdDrawIndirectCount( vkCmdBuffer->handle, vkBuffer->handle, - offset, + 0, vkCountBuffer->handle, - countBufferOffset, + 0, maxDrawCount, stride); @@ -7051,13 +7021,13 @@ PalResult PAL_CALL cmdDrawIndexedVk( PalResult PAL_CALL cmdDrawIndexedIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, - Uint32 count, - Uint32 stride) + Uint32 count) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.cmdDrawIndexedIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset, count, stride); + Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); + + s_Vk.cmdDrawIndexedIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); return PAL_RESULT_SUCCESS; } @@ -7065,10 +7035,7 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint64 offset, - Uint64 countBufferOffset, - Uint32 maxDrawCount, - Uint32 stride) + Uint32 maxDrawCount) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; @@ -7079,12 +7046,13 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); device->cmdDrawIndexedIndirectCount( vkCmdBuffer->handle, vkBuffer->handle, - offset, + 0, vkCountBuffer->handle, - countBufferOffset, + 0, maxDrawCount, stride); @@ -7255,12 +7223,11 @@ PalResult PAL_CALL cmdDispatchBaseVk( PalResult PAL_CALL cmdDispatchIndirectVk( PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - Uint64 offset) + PalBuffer* buffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.cmdDispatchIndirect(vkCmdBuffer->handle, vkBuffer->handle, offset); + s_Vk.cmdDispatchIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0); return PAL_RESULT_SUCCESS; } diff --git a/tests/graphics_test.c b/tests/graphics_test.c index f284a645..ec4d60b2 100644 --- a/tests/graphics_test.c +++ b/tests/graphics_test.c @@ -284,10 +284,6 @@ bool graphicsTest() palLog(nullptr, " Fragment shading rate attachment"); } - if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { - palLog(nullptr, " Indirect draw count"); - } - if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { palLog(nullptr, " Buffer device address"); } @@ -296,6 +292,18 @@ bool graphicsTest() palLog(nullptr, " Indirect draw"); } + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { + palLog(nullptr, " Indirect draw count"); + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH) { + palLog(nullptr, " Indirect mesh draw"); + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT) { + palLog(nullptr, " Indirect mesh draw count"); + } + if (features & PAL_ADAPTER_FEATURE_DISPATCH_BASE) { palLog(nullptr, " Dispatch base"); } From 8e0f50177bfbafbe0338dd543c9226dd896efa8a Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 5 Apr 2026 15:13:20 +0000 Subject: [PATCH 147/372] add rendering commands API d3d12 --- include/pal/pal_graphics.h | 34 ++-- src/graphics/pal_d3d12.c | 316 ++++++++++++++++++++++++++++++++++++- src/graphics/pal_vulkan.c | 262 ++++++++++++++++++------------ tests/clear_color_test.c | 4 - tests/mesh_test.c | 4 - tests/ray_tracing_test.c | 12 +- tests/texture_test.c | 4 - tests/triangle_test.c | 4 - 8 files changed, 492 insertions(+), 148 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index db824093..33dddcb9 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1236,8 +1236,7 @@ typedef enum { */ typedef enum { PAL_GEOMETRY_TYPE_TRIANGLE, - PAL_GEOMETRY_TYPE_AABBS, - PAL_GEOMETRY_TYPE_INSTANCE + PAL_GEOMETRY_TYPE_AABBS } PalGeometryType; /** @@ -1657,6 +1656,8 @@ typedef struct { typedef struct { PalLoadOp loadOp; PalStoreOp storeOp; + PalLoadOp stencilLoadOp; + PalStoreOp stencilStoreOp; PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ Uint32 texelWidth; /**< Texel width for fragment shading rate attachment.*/ Uint32 texelHeight; /**< Texel height for fragment shading rate attachment.*/ @@ -1799,20 +1800,16 @@ typedef struct { */ typedef struct { Uint32 viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ - Uint32 layerCount; Uint32 colorAttachentCount; - PalSampleCount multisampleCount; PalAttachmentDesc* colorAttachments; - PalAttachmentDesc* depthAttachment; - PalAttachmentDesc* stencilAttachment; + PalAttachmentDesc* depthStencilAttachment; PalAttachmentDesc* fragmentShadingRateAttachment; - PalRect2D renderArea; } PalRenderingInfo; /** * @struct PalRenderingLayoutInfo * @brief Information about a pre-existing PalRenderingInfo. - * This is used to reference the already existing PalRenderingInfo. + * This is used to reference an already existing PalRenderingInfo. * * Uninitialized fields may result in undefined behavior. * @@ -2120,20 +2117,7 @@ typedef struct { } PalGeometryDataAABBS; /** - * @struct PalGeometryDataInstance - * @brief Acceleration structure instance geometry data. - * - * Uninitialized fields may result in undefined behavior. - * - * @since 1.4 - * @ingroup pal_graphics - */ -typedef struct { - PalDeviceAddress bufferAddress; -} PalGeometryDataInstance; - -/** - * @struct PalGeometryDataInstance + * @struct PalGeometry * @brief Acceleration structure geometry. * * Uninitialized fields may result in undefined behavior. @@ -2159,11 +2143,13 @@ typedef struct { typedef struct { PalAccelerationStructureType type; /**< (eg. PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL).*/ Uint32 geometryCount; + Uint32 instanceCount; PalAccelerationStructureBuildHints buildHints; PalAccelerationStructureBuildMode buildMode; + PalDeviceAddress scratchBufferAddress; + PalDeviceAddress instanceBufferAddress; PalAccelerationStructure* dst; PalAccelerationStructure* src; - PalDeviceAddress scratchBufferAddress; PalGeometry* geometries; } PalAccelerationStructureBuildInfo; @@ -6651,7 +6637,7 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * * @param[in] device The device. Must match the one used to create the instance buffer. * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. - * @param[in] instances Array of PalAccelerationStructureInstances struct to write. + * @param[in] instances Array of PalAccelerationStructureInstance struct to write. * Can be a single struct. * @param[in] instanceCount Number of instances in `instances`. * diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 224d0184..659cdc96 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -44,6 +44,8 @@ freely, subject to the following restrictions: #define D3D_FEATURE_LEVEL_12_2 0xc200 #endif // D3D_FEATURE_LEVEL_12_2 +#define MAX_ATTACHMENTS 32 + // IIDS const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; const IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0xd2,0x4e}; @@ -209,6 +211,16 @@ typedef struct { ID3D12Resource* handle; } Buffer; +typedef struct { + const PalGraphicsBackend* backend; + + D3D12_GPU_VIRTUAL_ADDRESS address; + ID3D12Resource* buffer; + ID3D12Heap* bufferMemory; + D3D12_GPU_VIRTUAL_ADDRESS bufferAddress; + ID3D12Resource* handle; +} AccelerationStructure; + static D3D12 s_D3D12 = {0}; // ================================================== @@ -742,6 +754,180 @@ static D3D12_SHADING_RATE shadingRateToD3D12(PalFragmentShadingRate rate) return D3D12_SHADING_RATE_1X1; } +static DXGI_FORMAT vertexTypeToD3D12(PalVertexType type) +{ + switch (type) { + case PAL_VERTEX_TYPE_INT32: + return DXGI_FORMAT_R32_SINT; + + case PAL_VERTEX_TYPE_INT32_2: + return DXGI_FORMAT_R32G32_SINT; + + case PAL_VERTEX_TYPE_INT32_3: + return DXGI_FORMAT_R32G32B32_SINT; + + case PAL_VERTEX_TYPE_INT32_4: + return DXGI_FORMAT_R32G32B32A32_SINT; + + case PAL_VERTEX_TYPE_UINT32: + return DXGI_FORMAT_R32_UINT; + + case PAL_VERTEX_TYPE_UINT32_2: + return DXGI_FORMAT_R32G32_UINT; + + case PAL_VERTEX_TYPE_UINT32_3: + return DXGI_FORMAT_R32G32B32_UINT; + + case PAL_VERTEX_TYPE_UINT32_4: + return DXGI_FORMAT_R32G32B32A32_UINT; + + case PAL_VERTEX_TYPE_INT8_2: + return DXGI_FORMAT_R8G8_SINT; + + case PAL_VERTEX_TYPE_INT8_4: + return DXGI_FORMAT_R8G8B8A8_SINT; + + case PAL_VERTEX_TYPE_UINT8_2: + return DXGI_FORMAT_R8G8_UINT; + + case PAL_VERTEX_TYPE_UINT8_4: + return DXGI_FORMAT_R8G8B8A8_UINT; + + case PAL_VERTEX_TYPE_INT8_2NORM: + return DXGI_FORMAT_R8G8_SNORM; + + case PAL_VERTEX_TYPE_INT8_4NORM: + return DXGI_FORMAT_R8G8B8A8_SNORM; + + case PAL_VERTEX_TYPE_UINT8_2NORM: + return DXGI_FORMAT_R8G8_UNORM; + + case PAL_VERTEX_TYPE_UINT8_4NORM: + return DXGI_FORMAT_R8G8B8A8_UNORM; + + case PAL_VERTEX_TYPE_INT16_2: + return DXGI_FORMAT_R16G16_SINT; + + case PAL_VERTEX_TYPE_INT16_4: + return DXGI_FORMAT_R16G16B16A16_SINT; + + case PAL_VERTEX_TYPE_UINT16_2: + return DXGI_FORMAT_R16G16_UINT; + + case PAL_VERTEX_TYPE_UINT16_4: + return DXGI_FORMAT_R16G16B16A16_UINT; + + case PAL_VERTEX_TYPE_INT16_2NORM: + return DXGI_FORMAT_R16G16_SNORM; + + case PAL_VERTEX_TYPE_INT16_4NORM: + return DXGI_FORMAT_R16G16B16A16_SNORM; + + case PAL_VERTEX_TYPE_UINT16_2NORM: + return DXGI_FORMAT_R16G16_UNORM; + + case PAL_VERTEX_TYPE_UINT16_4NORM: + return DXGI_FORMAT_R16G16B16A16_UNORM; + + case PAL_VERTEX_TYPE_FLOAT: + return DXGI_FORMAT_R32_FLOAT; + + case PAL_VERTEX_TYPE_FLOAT2: + return DXGI_FORMAT_R32G32_FLOAT; + + case PAL_VERTEX_TYPE_FLOAT3: + return DXGI_FORMAT_R32G32B32_FLOAT; + + case PAL_VERTEX_TYPE_FLOAT4: + return DXGI_FORMAT_R32G32B32A32_FLOAT; + + case PAL_VERTEX_TYPE_HALF_FLOAT16_2: + return DXGI_FORMAT_R16G16_FLOAT; + + case PAL_VERTEX_TYPE_HALF_FLOAT16_4: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + } + + return DXGI_FORMAT_UNKNOWN; +} + +static void fillVkBuildInfoD3D12( + PalAccelerationStructureBuildInfo* info, + D3D12_RAYTRACING_GEOMETRY_DESC* geometries, + D3D12_GPU_VIRTUAL_ADDRESS srcAs, + D3D12_GPU_VIRTUAL_ADDRESS dstAs, + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC* buildInfo) +{ + for (int i = 0; i < info->geometryCount; i++) { + D3D12_RAYTRACING_GEOMETRY_DESC* tmp = &geometries[i]; + tmp->Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; + + if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { + tmp->Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + PalGeometryDataTriangle* tmpData = info->geometries[i].data; + + tmp->Triangles.VertexBuffer.StartAddress = tmpData->vertexBufferAddress; + tmp->Triangles.VertexBuffer.StrideInBytes = tmpData->vertexStride; + tmp->Triangles.VertexCount = tmpData->vertexCount; + tmp->Triangles.VertexFormat = vertexTypeToD3D12(tmpData->vertexType); + + tmp->Triangles.IndexBuffer = tmpData->indexBufferAddress; + tmp->Triangles.IndexCount = tmpData->indexCount; + if (tmpData->indexType == PAL_INDEX_TYPE_UINT16) { + tmp->Triangles.IndexFormat = DXGI_FORMAT_R16_FLOAT; + } else { + tmp->Triangles.IndexFormat = DXGI_FORMAT_R32_FLOAT; + } + + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { + tmp->Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; + PalGeometryDataAABBS* tmpData = info->geometries[i].data; + + tmp->AABBs.AABBCount = info->geometries[i].primitiveCount; + tmp->AABBs.AABBs.StartAddress = tmpData->bufferAddress; + tmp->AABBs.AABBs.StrideInBytes = tmpData->stride; + } + } + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { + buildInfo->Inputs.NumDescs = info->instanceCount; + buildInfo->Inputs.InstanceDescs = info->instanceBufferAddress; + } else { + buildInfo->Inputs.NumDescs = info->geometryCount; + buildInfo->Inputs.pGeometryDescs = geometries; + } + + buildInfo->Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + buildInfo->Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + } else { + buildInfo->Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + } + + // build mode + buildInfo->Inputs.Flags = 0; + if (info->buildMode == PAL_ACCELERATION_STRUCTURE_BUILD_MODE_UPDATE) { + buildInfo->Inputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE; + } + + // build hints + if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD) { + buildInfo->Inputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; + } + + if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE) { + buildInfo->Inputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; + } + + if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY) { + buildInfo->Inputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_MINIMIZE_MEMORY; + } + + buildInfo->ScratchAccelerationStructureData = info->scratchBufferAddress; + buildInfo->SourceAccelerationStructureData = srcAs; + buildInfo->DestAccelerationStructureData = dstAs; +} + // ================================================== // Adapter // ================================================== @@ -3273,19 +3459,147 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; + AccelerationStructure* tmpAs = (AccelerationStructure*)info->src; + AccelerationStructure* dstAs = (AccelerationStructure*)info->dst; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; + D3D12_GPU_VIRTUAL_ADDRESS srcAsAddress = 0; + + if (tmpAs) { + srcAsAddress = tmpAs->address; + } + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + geometries = palAllocate( + s_D3D12.allocator, + sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount, + 0); + + if (!geometries) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); + fillVkBuildInfoD3D12( + info, + geometries, + srcAsAddress, + dstAs->address, + &buildInfo); + + palFree(s_D3D12.allocator, geometries); + d3d12CmdBuffer->handle6->lpVtbl->BuildRaytracingAccelerationStructure( + d3d12CmdBuffer->handle6, + &buildInfo, + 0, + nullptr); + + } else { + fillVkBuildInfoD3D12( + info, + geometries, + srcAsAddress, + dstAs->address, + &buildInfo); + + d3d12CmdBuffer->handle6->lpVtbl->BuildRaytracingAccelerationStructure( + d3d12CmdBuffer->handle6, + &buildInfo, + 0, + nullptr); + } + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdBeginRenderingD3D12( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + D3D12_CPU_DESCRIPTOR_HANDLE colorAttachments[MAX_ATTACHMENTS]; + D3D12_CPU_DESCRIPTOR_HANDLE depthStencilAttachment; + D3D12_CPU_DESCRIPTOR_HANDLE fsrAttachment; + for (int i = 0; i < info->colorAttachentCount; i++) { + ImageView* tmp = (ImageView*)info->colorAttachments[i].imageView; + colorAttachments[i] = tmp->cpuHandle; + } + + ImageView* tmpDepth = (ImageView*)info->depthStencilAttachment->imageView; + if (tmpDepth) { + d3d12CmdBuffer->handle6->lpVtbl->OMSetRenderTargets( + d3d12CmdBuffer->handle6, + info->colorAttachentCount, + colorAttachments, + FALSE, + &tmpDepth->cpuHandle); + + } else { + d3d12CmdBuffer->handle6->lpVtbl->OMSetRenderTargets( + d3d12CmdBuffer->handle6, + info->colorAttachentCount, + colorAttachments, + FALSE, + nullptr); + } + + for (int i = 0; i < info->colorAttachentCount; i++) { + ImageView* tmp = (ImageView*)info->colorAttachments[i].imageView; + float color[4]; + color[0] = info->colorAttachments[i].clearValue.color[0]; + color[1] = info->colorAttachments[i].clearValue.color[1]; + color[2] = info->colorAttachments[i].clearValue.color[2]; + color[3] = info->colorAttachments[i].clearValue.color[3]; + + d3d12CmdBuffer->handle6->lpVtbl->ClearRenderTargetView( + d3d12CmdBuffer->handle6, + colorAttachments[i], color, 0, nullptr); + } + + if (tmpDepth) { + D3D12_CLEAR_FLAGS clearFlags = 0; + UINT8 stencil = 0; + float depth = 0; + + if (info->depthStencilAttachment->loadOp == PAL_LOAD_OP_CLEAR) { + depth = info->depthStencilAttachment->clearValue.depth; + clearFlags |= D3D12_CLEAR_FLAG_DEPTH; + } + + if (info->depthStencilAttachment->stencilLoadOp == PAL_LOAD_OP_CLEAR) { + stencil = (UINT8)info->depthStencilAttachment->clearValue.stencil; + clearFlags |= D3D12_CLEAR_FLAG_STENCIL; + } + d3d12CmdBuffer->handle6->lpVtbl->ClearDepthStencilView( + d3d12CmdBuffer->handle6, + depthStencilAttachment, + clearFlags, + depth, + stencil, + 0, + nullptr); + } + + if (info->fragmentShadingRateAttachment) { + ImageView* tmp = (ImageView*)info->fragmentShadingRateAttachment->imageView; + d3d12CmdBuffer->handle6->lpVtbl->RSSetShadingRateImage( + d3d12CmdBuffer->handle6, + tmp->image->handle); + } + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer) { - + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdCopyBufferD3D12( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 70c87016..b84ba5c3 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2234,6 +2234,7 @@ static inline Uint32 alignVk( } static void fillVkBuildInfoVk( + Uint32 count, PalAccelerationStructureBuildInfo* info, Uint32* maxPrimities, VkAccelerationStructureGeometryKHR* geometries, @@ -2242,7 +2243,7 @@ static void fillVkBuildInfoVk( VkAccelerationStructureBuildRangeInfoKHR* rangeInfos, VkAccelerationStructureBuildGeometryInfoKHR* buildInfo) { - for (int i = 0; i < info->geometryCount; i++) { + for (int i = 0; i < count; i++) { if (maxPrimities) { maxPrimities[i] = info->geometries[i].primitiveCount; } @@ -2252,6 +2253,31 @@ static void fillVkBuildInfoVk( tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; tmp->flags = VK_GEOMETRY_OPAQUE_BIT_KHR; // always opaque + // range info + if (rangeInfos) { + VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; + rangeInfo->primitiveCount = info->geometries[i].primitiveCount; + rangeInfo->firstVertex = 0; // PAL does not allow setting this + rangeInfo->primitiveOffset = 0; // PAL does not allow setting this + rangeInfo->transformOffset = 0; // PAL does not allow setting this + } + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { + tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; + data = &tmp->geometry.instances; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + data->arrayOfPointers = false; + + VkDeviceOrHostAddressConstKHR address = {0}; + address.deviceAddress = info->instanceBufferAddress; + data->data = address; + + VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; + rangeInfo->primitiveCount = info->instanceCount; + break; + } + if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { tmp->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; @@ -2290,27 +2316,6 @@ static void fillVkBuildInfoVk( address.deviceAddress = tmpData->bufferAddress; data->data = address; data->stride = tmpData->stride; - - } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_INSTANCE) { - tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; - data = &tmp->geometry.instances; - data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; - data->arrayOfPointers = false; - - VkDeviceOrHostAddressConstKHR address = {0}; - PalGeometryDataInstance* tmpData = info->geometries[i].data; - address.deviceAddress = tmpData->bufferAddress; - data->data = address; - } - - // range info - if (rangeInfos) { - VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; - rangeInfo->primitiveCount = info->geometries[i].primitiveCount; - rangeInfo->firstVertex = 0; // PAL does not allow setting this - rangeInfo->primitiveOffset = 0; // PAL does not allow setting this - rangeInfo->transformOffset = 0; // PAL does not allow setting this } } @@ -2342,7 +2347,7 @@ static void fillVkBuildInfoVk( buildInfo->flags = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; } - buildInfo->geometryCount = info->geometryCount; + buildInfo->geometryCount = count; buildInfo->srcAccelerationStructure = srcAs; buildInfo->dstAccelerationStructure = dstAs; buildInfo->pGeometries = geometries; @@ -6430,6 +6435,16 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( VkAccelerationStructureKHR srcAs = nullptr; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + // cache these for top level as + VkAccelerationStructureBuildRangeInfoKHR cachedRangeInfo = {0}; + VkAccelerationStructureGeometryKHR cachedGeometries = {0}; + Uint32 geometryCount = info->geometryCount; + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { + geometryCount = 1; + rangeInfos = &cachedRangeInfo; + geometries = &cachedGeometries; + } + if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6438,30 +6453,43 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( srcAs = tmpAs->handle; } - geometries = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount, - 0); + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + geometries = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureGeometryKHR) * geometryCount, + 0); - rangeInfos = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->geometryCount, - 0); + rangeInfos = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureBuildRangeInfoKHR) * geometryCount, + 0); - if (!rangeInfos || !geometries) { - return PAL_RESULT_OUT_OF_MEMORY; + if (!rangeInfos || !geometries) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * geometryCount); + memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * geometryCount); } - memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount); - memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->geometryCount); + fillVkBuildInfoVk( + geometryCount, + info, + nullptr, + geometries, + srcAs, + dstAs->handle, + rangeInfos, + &buildInfo); - fillVkBuildInfoVk(info, nullptr, geometries, srcAs, dstAs->handle, rangeInfos, &buildInfo); const VkAccelerationStructureBuildRangeInfoKHR* tmp[1]; tmp[0] = rangeInfos; vkCmdBuffer->device->cmdBuildAccelerationStructures(vkCmdBuffer->handle, 1, &buildInfo, tmp); - palFree(s_Vk.allocator, geometries); - palFree(s_Vk.allocator, rangeInfos); + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + palFree(s_Vk.allocator, geometries); + palFree(s_Vk.allocator, rangeInfos); + } return PAL_RESULT_SUCCESS; } @@ -6486,6 +6514,9 @@ PalResult PAL_CALL cmdBeginRenderingVk( VkRenderingFragmentShadingRateAttachmentInfoKHR fsrInfo = {0}; fsrInfo.sType = VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; + Uint32 layerCount = UINT32_MAX; + Uint32 renderWidth = UINT32_MAX; + Uint32 renderHeight = UINT32_MAX; for (int i = 0; i < info->colorAttachentCount; i++) { attachment = &colorAttachments[i]; desc = &info->colorAttachments[i]; @@ -6530,15 +6561,26 @@ PalResult PAL_CALL cmdBeginRenderingVk( attachment->resolveMode = resolveModeToVk(desc->resolveMode); attachment->imageLayout = layout; + + // compute layer count and render area + layerCount = min(layerCount, imageView->range.layerCount); + renderWidth = min(renderWidth, imageView->image->info.width); + renderHeight = min(renderHeight, imageView->image->info.height); + + if (resolveImageView) { + layerCount = min(layerCount, resolveImageView->range.layerCount); + renderWidth = min(renderWidth, resolveImageView->image->info.width); + renderHeight = min(renderHeight, resolveImageView->image->info.height); + } } rendering.colorAttachmentCount = info->colorAttachentCount; rendering.pColorAttachments = colorAttachments; // depth attachment - if (info->depthAttachment) { + if (info->depthStencilAttachment) { attachment = &depthAttachment; - desc = info->depthAttachment; + desc = info->depthStencilAttachment; imageView = (ImageView*)desc->imageView; resolveImageView = (ImageView*)desc->resolveImageView; @@ -6547,13 +6589,22 @@ PalResult PAL_CALL cmdBeginRenderingVk( attachment->resolveImageView = nullptr; attachment->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachment->clearValue.depthStencil.depth = desc->clearValue.depth; - layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + stencilAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; + stencilAttachment.pNext = nullptr; + stencilAttachment.resolveImageView = nullptr; + stencilAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment->clearValue.depthStencil.depth = desc->clearValue.depth; + stencilAttachment.clearValue.depthStencil.stencil = desc->clearValue.stencil; + attachment->imageView = imageView->handle; + stencilAttachment.imageView = imageView->handle; if (resolveImageView) { attachment->resolveImageView = resolveImageView->handle; attachment->resolveImageLayout = layout; + + stencilAttachment.resolveImageView = resolveImageView->handle; + stencilAttachment.resolveImageLayout = layout; } // load op @@ -6575,54 +6626,43 @@ PalResult PAL_CALL cmdBeginRenderingVk( attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; } - attachment->resolveMode = resolveModeToVk(desc->resolveMode); - attachment->imageLayout = layout; - rendering.pStencilAttachment = &depthAttachment; - } + // stencil load op + if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { + stencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - // stencil attachment - if (info->stencilAttachment) { - attachment = &stencilAttachment; - desc = info->stencilAttachment; - imageView = (ImageView*)desc->imageView; - resolveImageView = (ImageView*)desc->resolveImageView; + } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { + stencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachment->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; - attachment->pNext = nullptr; - attachment->resolveImageView = nullptr; - attachment->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { + stencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } - attachment->clearValue.depthStencil.stencil = desc->clearValue.stencil; - layout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; + // stencil store op + if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { + stencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachment->imageView = imageView->handle; - if (resolveImageView) { - attachment->resolveImageView = resolveImageView->handle; - attachment->resolveImageLayout = layout; + } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { + stencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; } - // load op - if (desc->loadOp == PAL_LOAD_OP_CLEAR) { - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - - } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + attachment->resolveMode = resolveModeToVk(desc->resolveMode); + attachment->imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + stencilAttachment.resolveMode = resolveModeToVk(desc->resolveMode); + stencilAttachment.imageLayout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; - } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } + rendering.pDepthAttachment = &depthAttachment; + rendering.pStencilAttachment = &stencilAttachment; - // store op - if (desc->storeOp == PAL_STORE_OP_STORE) { - attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + // compute layer count and render area + layerCount = min(layerCount, imageView->range.layerCount); + renderWidth = min(renderWidth, imageView->image->info.width); + renderHeight = min(renderHeight, imageView->image->info.height); - } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { - attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + if (resolveImageView) { + layerCount = min(layerCount, resolveImageView->range.layerCount); + renderWidth = min(renderWidth, resolveImageView->image->info.width); + renderHeight = min(renderHeight, resolveImageView->image->info.height); } - - attachment->resolveMode = resolveModeToVk(desc->resolveMode); - attachment->imageLayout = layout; - rendering.pStencilAttachment = &stencilAttachment; } // fragment shading rate attachment @@ -6638,13 +6678,18 @@ PalResult PAL_CALL cmdBeginRenderingVk( fsrInfo.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; rendering.pNext = &fsrInfo; + + // compute layer count and render area + layerCount = min(layerCount, imageView->range.layerCount); + renderWidth = min(renderWidth, imageView->image->info.width); + renderHeight = min(renderHeight, imageView->image->info.height); } - rendering.layerCount = info->layerCount; - rendering.renderArea.offset.x = info->renderArea.x; - rendering.renderArea.offset.y = info->renderArea.y; - rendering.renderArea.extent.width = info->renderArea.width; - rendering.renderArea.extent.height = info->renderArea.height; + rendering.layerCount = layerCount; + rendering.renderArea.offset.x = 0; + rendering.renderArea.offset.y = 0; + rendering.renderArea.extent.width = renderWidth; + rendering.renderArea.extent.height = renderHeight; if (info->viewCount == 1) { rendering.viewMask = 0; @@ -7585,24 +7630,45 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( Device* vkDevice = (Device*)device; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + // cache these for top level as + VkAccelerationStructureGeometryKHR cachedGeometries = {0}; + Uint32 cachedPrimitives[1]; + Uint32 geometryCount = info->geometryCount; + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { + geometryCount = 1; + geometries = &cachedGeometries; + maxPrimities = cachedPrimitives; + } + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - maxPrimities = palAllocate(s_Vk.allocator, sizeof(Uint32) * info->geometryCount, 0); - geometries = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount, - 0); + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + geometries = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureGeometryKHR) * geometryCount, + 0); - if (!maxPrimities || !geometries) { - return PAL_RESULT_OUT_OF_MEMORY; + maxPrimities = palAllocate(s_Vk.allocator, sizeof(Uint32) * geometryCount, 0); + if (!maxPrimities || !geometries) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * geometryCount); + memset(maxPrimities, 0, sizeof(Uint32) * geometryCount); } - memset(maxPrimities, 0, sizeof(Uint32) * info->geometryCount); - memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->geometryCount); + fillVkBuildInfoVk( + geometryCount, + info, + maxPrimities, + geometries, + nullptr, + nullptr, + nullptr, + &buildInfo); - fillVkBuildInfoVk(info, maxPrimities, geometries, nullptr, nullptr, nullptr, &buildInfo); VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; @@ -7617,8 +7683,10 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( size->scratchBufferSize = sizeInfo.buildScratchSize; size->updateScratchBufferSize = sizeInfo.updateScratchSize; - palFree(s_Vk.allocator, maxPrimities); - palFree(s_Vk.allocator, geometries); + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + palFree(s_Vk.allocator, geometries); + palFree(s_Vk.allocator, maxPrimities); + } return PAL_RESULT_SUCCESS; } diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index de56f980..07786c7b 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -462,10 +462,6 @@ bool clearColorTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - renderingInfo.layerCount = 1; - renderingInfo.multisampleCount = PAL_SAMPLE_COUNT_1; - renderingInfo.renderArea.width = WINDOW_WIDTH; - renderingInfo.renderArea.height = WINDOW_HEIGHT; result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/mesh_test.c b/tests/mesh_test.c index af213dd3..88337f8d 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -653,10 +653,6 @@ bool meshTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - renderingInfo.layerCount = 1; - renderingInfo.multisampleCount = PAL_SAMPLE_COUNT_1; - renderingInfo.renderArea.width = WINDOW_WIDTH; - renderingInfo.renderArea.height = WINDOW_HEIGHT; result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 5ecf52cd..eab7a3a0 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -609,18 +609,10 @@ bool rayTracingTest() // fill TLAS and instance geometry PalDeviceAddress instanceBufferAddress = palGetBufferDeviceAddress(instanceBuffer); - PalGeometryDataInstance instance = {0}; - instance.bufferAddress = instanceBufferAddress; - - PalGeometry instanceGeometry = {0}; - instanceGeometry.data = &instance; - instanceGeometry.primitiveCount = 1; - instanceGeometry.type = PAL_GEOMETRY_TYPE_INSTANCE; - PalAccelerationStructureBuildInfo tlasBuildInfo = {0}; tlasBuildInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; - tlasBuildInfo.geometryCount = 1; - tlasBuildInfo.geometries = &instanceGeometry; + tlasBuildInfo.instanceCount = 1; + tlasBuildInfo.instanceBufferAddress = instanceBufferAddress; tlasBuildInfo.buildHints = PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD; tlasBuildInfo.buildMode = PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD; diff --git a/tests/texture_test.c b/tests/texture_test.c index ab246961..280fb586 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -1206,10 +1206,6 @@ bool textureTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - renderingInfo.layerCount = 1; - renderingInfo.multisampleCount = PAL_SAMPLE_COUNT_1; - renderingInfo.renderArea.width = WINDOW_WIDTH; - renderingInfo.renderArea.height = WINDOW_HEIGHT; result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 3c07238b..ca5a9c08 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -840,10 +840,6 @@ bool triangleTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - renderingInfo.layerCount = 1; - renderingInfo.multisampleCount = PAL_SAMPLE_COUNT_1; - renderingInfo.renderArea.width = WINDOW_WIDTH; - renderingInfo.renderArea.height = WINDOW_HEIGHT; result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { From ef47375b0de13a7fe7806c415c556b7ee33f485a Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 5 Apr 2026 18:55:43 +0000 Subject: [PATCH 148/372] start compute image copy staging buffer API --- include/pal/pal_graphics.h | 132 ++++++++++++++++++++++++++++-------- src/graphics/pal_d3d12.c | 40 +++++++++-- src/graphics/pal_graphics.c | 109 +++++++++++++++++++++++++---- src/graphics/pal_vulkan.c | 30 ++++++-- 4 files changed, 257 insertions(+), 54 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 33dddcb9..96feecf3 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1728,18 +1728,6 @@ typedef struct { Uint32 alignment; } PalMemoryRequirements; -/** - * @struct PalInstanceBufferRequirements - * @brief Instance buffer requirements. - * - * @since 1.4 - * @ingroup pal_graphics - */ -typedef struct { - Uint64 size; - Uint32 alignment; -} PalInstanceBufferRequirements; - /** * @struct PalCommandBufferSubmitInfo * @brief Submit information of a command buffer. @@ -3673,20 +3661,44 @@ typedef struct { */ PalResult PAL_CALL (*computeInstanceBufferRequirements)( PalDevice* device, - PalInstanceBufferRequirements* requirements, - Uint32 instanceCount); + Uint32 instanceCount, + Uint32* outAlignment, + Uint64* outSize); + + /** + * Backend implementation of ::palComputeImageCopyStagingBufferRequirements. + * + * Must obey the rules and semantics documented in palComputeImageCopyStagingBufferRequirements(). + */ + PalResult PAL_CALL (*computeImageCopyStagingBufferRequirements)( + PalDevice* device, + PalImage* image, + PalBufferImageCopyInfo* copyInfo, + Uint32* outAlignment, + Uint64* outSize); /** - * Backend implementation of ::palWriteInstancesToMappedMemory. + * Backend implementation of ::palWriteToInstanceBuffer. * - * Must obey the rules and semantics documented in palWriteInstancesToMappedMemory(). + * Must obey the rules and semantics documented in palWriteToInstanceBuffer(). */ - PalResult PAL_CALL (*writeInstancesToMappedMemory)( + PalResult PAL_CALL (*writeToInstanceBuffer)( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, Uint32 instanceCount); + /** + * Backend implementation of ::palWriteToImageCopyStagingBuffer. + * + * Must obey the rules and semantics documented in palWriteToImageCopyStagingBuffer(). + */ + PalResult PAL_CALL (*writeToImageCopyStagingBuffer)( + PalDevice* device, + void* ptr, + PalBufferImageCopyInfo* copyInfo, + PalFormat imageFormat); + /** * Backend implementation of ::palBindBufferMemory. * @@ -6606,34 +6618,69 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( * The graphics system must be initialized before this call. This does not allocate memory * for the buffer. * - * PalInstanceBufferRequirements::size and PalInstanceBufferRequirements::alignment are the - * size and alignment which must be used to create the instance buffer. This will be computed - * with regards to the provided `instanceCount`. This function must be used and required for all - * instance buffers. This is used with acceleration structure (`TLAS`). + * `outSize` and `outAlignment` are the size and alignment which must be used to create the + * instance buffer. This will be computed with regards to the provided `instanceCount`. This + * function must be used and required for all instance buffers. This is used with acceleration + * structure (`TLAS`). * * @param[in] device Device to compute instance buffer requirements with. - * @param[out] requirements Pointer to a PalInstanceBufferRequirements to fill. * @param[in] instanceCount Number of instances the instance buffer will hold. + * @param[out] outAlignment Pointer to a Uint32 to recieve the required alignment. + * @param[out] outSize Pointer to a Uint64 to recieve the required size. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * - * Thread safety: Thread safe if `device` is externally synchronized and `requirements` is per - * thread. + * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( PalDevice* device, - PalInstanceBufferRequirements* requirements, - Uint32 instanceCount); + Uint32 instanceCount, + Uint32* outAlignment, + Uint64* outSize); /** - * @brief Update or write instances to the mapped memory of an instance buffer. + * @brief Compute size and alignment requirements for an image copy staging buffer. * - * The graphics system must be initialized before this call. Instance buffers must not be updated - * or written to with `memcpy`. + * The graphics system must be initialized before this call. This does not allocate memory + * for the buffer. + * + * `outSize` and `outAlignment` are the size and alignment which must be used to create the + * image copy staging buffer. This will be computed with regards to the provided `image` + * and `copyInfo`. This function must be used and required for all image copy staging buffers. + * + * PalBufferImageCopyInfo::bufferRowLength and PalBufferImageCopyInfo::bufferImageHeight are hints. + * The driver might used it defaults if the requested is not supported. + * + * @param[in] device Device to compute image copy staging buffer requirements with. + * @param[in] image Destination image. + * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. + * Must not be nullptr. + * @param[out] outAlignment Pointer to a Uint32 to recieve the required alignment. + * @param[out] outSize Pointer to a Uint64 to recieve the required size. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( + PalDevice* device, + PalImage* image, + PalBufferImageCopyInfo* copyInfo, + Uint32* outAlignment, + Uint64* outSize); + +/** + * @brief Update or write data to an instance buffer. + * + * The graphics system must be initialized before this call. * * @param[in] device The device. Must match the one used to create the instance buffer. * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. @@ -6649,12 +6696,37 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * @since 1.4 * @ingroup pal_graphics */ -PAL_API PalResult PAL_CALL palWriteInstancesToMappedMemory( +PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, Uint32 instanceCount); +/** + * @brief Update or write data to an image copy staging buffer. + * + * The graphics system must be initialized before this call. + * + * @param[in] device The device. Must match the one used to create the image copy staging buffer. + * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. + * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. + * Must not be nullptr. + * @param[in] imageFormat Destination image format. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `device` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palWriteToImageCopyStagingBuffer( + PalDevice* device, + void* ptr, + PalBufferImageCopyInfo* copyInfo, + PalFormat imageFormat); + /** * @brief Bind an allocated memory to a buffer. * diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 659cdc96..406be617 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -3608,7 +3608,19 @@ PalResult PAL_CALL cmdCopyBufferD3D12( PalBuffer* src, PalBufferCopyInfo* copyInfo) { + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* dstbuffer = (Buffer*)dst; + Buffer* srcBuffer = (Buffer*)src; + + d3d12CmdBuffer->handle6->lpVtbl->CopyBufferRegion( + d3d12CmdBuffer->handle6, + dstbuffer->handle, + copyInfo->dstOffset, + srcBuffer->handle, + copyInfo->srcOffset, + copyInfo->size); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdCopyBufferToImageD3D12( @@ -3617,7 +3629,7 @@ PalResult PAL_CALL cmdCopyBufferToImageD3D12( PalBuffer* srcBuffer, PalBufferImageCopyInfo* copyInfo) { - + // TODO: } PalResult PAL_CALL cmdCopyImageD3D12( @@ -3930,13 +3942,24 @@ PalResult PAL_CALL getBufferMemoryRequirementsD3D12( PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( PalDevice* device, - PalInstanceBufferRequirements* requirements, - Uint32 instanceCount) + Uint32 instanceCount, + Uint32* outAlignment, + Uint64* outSize) { } -PalResult PAL_CALL writeInstancesToMappedMemoryD3D12( +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( + PalDevice* device, + PalImage* image, + PalBufferImageCopyInfo* copyInfo, + Uint32* outAlignment, + Uint64* outSize) +{ + +} + +PalResult PAL_CALL writeToInstanceBufferD3D12( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, @@ -3945,6 +3968,15 @@ PalResult PAL_CALL writeInstancesToMappedMemoryD3D12( } +PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( + PalDevice* device, + void* ptr, + PalBufferImageCopyInfo* copyInfo, + PalFormat imageFormat) +{ + +} + PalResult PAL_CALL bindBufferMemoryD3D12( PalBuffer* buffer, PalMemory* memory, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 571a4af3..a25528cd 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -666,15 +666,29 @@ PalResult PAL_CALL getBufferMemoryRequirementsVk( PalResult PAL_CALL computeInstanceBufferRequirementsVk( PalDevice* device, - PalInstanceBufferRequirements* requirements, - Uint32 instanceCount); + Uint32 instanceCount, + Uint32* outAlignment, + Uint64* outSize); + +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( + PalDevice* device, + PalImage* image, + PalBufferImageCopyInfo* copyInfo, + Uint32* outAlignment, + Uint64* outSize); -PalResult PAL_CALL writeInstancesToMappedMemoryVk( +PalResult PAL_CALL writeToInstanceBufferVk( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, Uint32 instanceCount); +PalResult PAL_CALL writeToImageCopyStagingBufferVk( + PalDevice* device, + void* ptr, + PalBufferImageCopyInfo* copyInfo, + PalFormat imageFormat); + PalResult PAL_CALL bindBufferMemoryVk( PalBuffer* buffer, PalMemory* memory, @@ -912,7 +926,9 @@ static PalGraphicsBackend s_VkBackend = { .destroyBuffer = destroyBufferVk, .getBufferMemoryRequirements = getBufferMemoryRequirementsVk, .computeInstanceBufferRequirements = computeInstanceBufferRequirementsVk, - .writeInstancesToMappedMemory = writeInstancesToMappedMemoryVk, + .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsVk, + .writeToInstanceBuffer = writeToInstanceBufferVk, + .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferVk, .bindBufferMemory = bindBufferMemoryVk, .getBufferDeviceAddress = getBufferDeviceAddressVk, .mapBufferMemory = mapBufferMemoryVk, @@ -1516,15 +1532,29 @@ PalResult PAL_CALL getBufferMemoryRequirementsD3D12( PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( PalDevice* device, - PalInstanceBufferRequirements* requirements, - Uint32 instanceCount); + Uint32 instanceCount, + Uint32* outAlignment, + Uint64* outSize); + +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( + PalDevice* device, + PalImage* image, + PalBufferImageCopyInfo* copyInfo, + Uint32* outAlignment, + Uint64* outSize); -PalResult PAL_CALL writeInstancesToMappedMemoryD3D12( +PalResult PAL_CALL writeToInstanceBufferD3D12( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, Uint32 instanceCount); +PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( + PalDevice* device, + void* ptr, + PalBufferImageCopyInfo* copyInfo, + PalFormat imageFormat); + PalResult PAL_CALL bindBufferMemoryD3D12( PalBuffer* buffer, PalMemory* memory, @@ -1762,7 +1792,9 @@ static PalGraphicsBackend s_D3D12Backend = { .destroyBuffer = destroyBufferD3D12, .getBufferMemoryRequirements = getBufferMemoryRequirementsD3D12, .computeInstanceBufferRequirements = computeInstanceBufferRequirementsD3D12, - .writeInstancesToMappedMemory = writeInstancesToMappedMemoryD3D12, + .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsD3D12, + .writeToInstanceBuffer = writeToInstanceBufferD3D12, + .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferD3D12, .bindBufferMemory = bindBufferMemoryD3D12, .getBufferDeviceAddress = getBufferDeviceAddressD3D12, .mapBufferMemory = mapBufferMemoryD3D12, @@ -1966,7 +1998,9 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->destroyBuffer || !backend->getBufferMemoryRequirements || !backend->computeInstanceBufferRequirements || - !backend->writeInstancesToMappedMemory || + !backend->computeImageCopyStagingBufferRequirements || + !backend->writeToInstanceBuffer || + !backend->writeToImageCopyStagingBuffer || !backend->bindBufferMemory || !backend->getBufferDeviceAddress || !backend->mapBufferMemory || @@ -3968,8 +4002,9 @@ PalResult PAL_CALL palGetBufferMemoryRequirements( PalResult PAL_CALL palComputeInstanceBufferRequirements( PalDevice* device, - PalInstanceBufferRequirements* requirements, - Uint32 instanceCount) + Uint32 instanceCount, + Uint32* outAlignment, + Uint64* outSize) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3979,10 +4014,37 @@ PalResult PAL_CALL palComputeInstanceBufferRequirements( return PAL_RESULT_NULL_POINTER; } - return device->backend->computeInstanceBufferRequirements(device, requirements, instanceCount); + return device->backend->computeInstanceBufferRequirements( + device, + instanceCount, + outAlignment, + outSize); } -PalResult PAL_CALL palWriteInstancesToMappedMemory( +PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( + PalDevice* device, + PalImage* image, + PalBufferImageCopyInfo* copyInfo, + Uint32* outAlignment, + Uint64* outSize) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->computeImageCopyStagingBufferRequirements( + device, + image, + copyInfo, + outAlignment, + outSize); +} + +PalResult PAL_CALL palWriteToInstanceBuffer( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, @@ -3996,8 +4058,25 @@ PalResult PAL_CALL palWriteInstancesToMappedMemory( return PAL_RESULT_NULL_POINTER; } - // since all blas have backend pointer, we use the first one - return device->backend->writeInstancesToMappedMemory(device, ptr, instances, instanceCount); + // since all tlas have backend pointer, we use the first one + return device->backend->writeToInstanceBuffer(device, ptr, instances, instanceCount); +} + +PalResult PAL_CALL palWriteToImageCopyStagingBuffer( + PalDevice* device, + void* ptr, + PalBufferImageCopyInfo* copyInfo, + PalFormat imageFormat) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !ptr || !copyInfo) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->writeToImageCopyStagingBuffer(device, ptr, copyInfo, imageFormat); } PalResult PAL_CALL palBindBufferMemory( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index b84ba5c3..19d11dcd 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -7775,15 +7775,26 @@ PalResult PAL_CALL getBufferMemoryRequirementsVk( PalResult PAL_CALL computeInstanceBufferRequirementsVk( PalDevice* device, - PalInstanceBufferRequirements* requirements, - Uint32 instanceCount) + Uint32 instanceCount, + Uint32* outAlignment, + Uint64* outSize) { - requirements->size = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; - requirements->alignment = 16; + *outSize = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; + *outAlignment = 16; return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL writeInstancesToMappedMemoryVk( +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( + PalDevice* device, + PalImage* image, + PalBufferImageCopyInfo* copyInfo, + Uint32* outAlignment, + Uint64* outSize) +{ + // TODO: +} + +PalResult PAL_CALL writeToInstanceBufferVk( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, @@ -7805,6 +7816,15 @@ PalResult PAL_CALL writeInstancesToMappedMemoryVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL writeToImageCopyStagingBufferVk( + PalDevice* device, + void* ptr, + PalBufferImageCopyInfo* copyInfo, + PalFormat imageFormat) +{ + // TODO: +} + PalResult PAL_CALL bindBufferMemoryVk( PalBuffer* buffer, PalMemory* memory, From 89375a40ec073c86f91acb527ff4d7bb473cc404 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 6 Apr 2026 13:44:40 +0000 Subject: [PATCH 149/372] find raytracing test bug --- include/pal/pal_graphics.h | 11 +++- src/graphics/pal_d3d12.c | 9 +-- src/graphics/pal_graphics.c | 8 +++ src/graphics/pal_vulkan.c | 121 +++++++++++++++++++----------------- tests/compute_test.c | 4 +- tests/ray_tracing_test.c | 34 ++++++---- tests/tests_main.c | 4 +- tests/texture_test.c | 2 +- 8 files changed, 114 insertions(+), 79 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 96feecf3..14d05416 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3674,6 +3674,8 @@ typedef struct { PalDevice* device, PalImage* image, PalBufferImageCopyInfo* copyInfo, + Uint32* outBufferRowLength, + Uint32* outBufferImageHeight, Uint32* outAlignment, Uint64* outSize); @@ -6651,14 +6653,19 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * `outSize` and `outAlignment` are the size and alignment which must be used to create the * image copy staging buffer. This will be computed with regards to the provided `image` * and `copyInfo`. This function must be used and required for all image copy staging buffers. + * This is used with image copy commands. * * PalBufferImageCopyInfo::bufferRowLength and PalBufferImageCopyInfo::bufferImageHeight are hints. - * The driver might used it defaults if the requested is not supported. + * The driver might used it defaults if the requested is not supported. Check `outBufferRowLength` + * and `outBufferImageHeight` to see the values the driver used. Set the new values to the + * `copyInfo` before writing to the buffer with `palWriteToImageCopyStagingBuffer()`. * * @param[in] device Device to compute image copy staging buffer requirements with. * @param[in] image Destination image. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * Must not be nullptr. + * @param[out] outBufferRowLength Pointer to a Uint32 to recieve the required buffer row length. + * @param[out] outBufferImageHeight Pointer to a Uint32 to recieve the required buffer imag height. * @param[out] outAlignment Pointer to a Uint32 to recieve the required alignment. * @param[out] outSize Pointer to a Uint64 to recieve the required size. * @@ -6674,6 +6681,8 @@ PAL_API PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( PalDevice* device, PalImage* image, PalBufferImageCopyInfo* copyInfo, + Uint32* outBufferRowLength, + Uint32* outBufferImageHeight, Uint32* outAlignment, Uint64* outSize); diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 406be617..c2ed1ca4 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -923,9 +923,9 @@ static void fillVkBuildInfoD3D12( buildInfo->Inputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_MINIMIZE_MEMORY; } - buildInfo->ScratchAccelerationStructureData = info->scratchBufferAddress; buildInfo->SourceAccelerationStructureData = srcAs; buildInfo->DestAccelerationStructureData = dstAs; + buildInfo->ScratchAccelerationStructureData = info->scratchBufferAddress; } // ================================================== @@ -1077,7 +1077,7 @@ PalResult PAL_CALL enumerateAdaptersD3D12( Adapter* tmp = &s_D3D12.adapters[i]; tmp->handle = dxAdapters[i]; tmp->tmpDevice = devices[i]; - tmp->level = levels[i]; + tmp->level = deviceLevels[i]; outAdapters[i] = (PalAdapter*)tmp; } s_D3D12.adapterCount = *count; @@ -3163,7 +3163,6 @@ void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) cmdBuffer->handle6->lpVtbl->Release(cmdBuffer->handle6); cmdBuffer->handle->lpVtbl->Release(cmdBuffer->handle); cmdBuffer->allocator->lpVtbl->Release(cmdBuffer->allocator); - palFree(s_D3D12.allocator, cmdBuffer); } palFree(s_D3D12.allocator, cmdPool->cmdBuffersData); @@ -3953,10 +3952,12 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( PalDevice* device, PalImage* image, PalBufferImageCopyInfo* copyInfo, + Uint32* outBufferRowLength, + Uint32* outBufferImageHeight, Uint32* outAlignment, Uint64* outSize) { - + } PalResult PAL_CALL writeToInstanceBufferD3D12( diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index a25528cd..d708ce72 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -674,6 +674,8 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( PalDevice* device, PalImage* image, PalBufferImageCopyInfo* copyInfo, + Uint32* outBufferRowLength, + Uint32* outBufferImageHeight, Uint32* outAlignment, Uint64* outSize); @@ -1540,6 +1542,8 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( PalDevice* device, PalImage* image, PalBufferImageCopyInfo* copyInfo, + Uint32* outBufferRowLength, + Uint32* outBufferImageHeight, Uint32* outAlignment, Uint64* outSize); @@ -4025,6 +4029,8 @@ PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( PalDevice* device, PalImage* image, PalBufferImageCopyInfo* copyInfo, + Uint32* outBufferRowLength, + Uint32* outBufferImageHeight, Uint32* outAlignment, Uint64* outSize) { @@ -4040,6 +4046,8 @@ PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( device, image, copyInfo, + outBufferRowLength, + outBufferImageHeight, outAlignment, outSize); } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 19d11dcd..9c9c0f91 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1983,12 +1983,22 @@ static Barrier barrierToVk( } case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: { + barrier.stages = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; + barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR; + + // HACK: small performance lost for the case of a single scratch buffer used for + // BLAS and TLAS builds. + barrier.access |= VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; + for (int i = 0; i < stageCount; i++) { + if (i == 0) { + barrier.stages = 0; + } + barrier.stages |= pipelineStageToVk(shaderStages[i]); + barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR; } - barrier.stages |= VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; - barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } @@ -2244,24 +2254,11 @@ static void fillVkBuildInfoVk( VkAccelerationStructureBuildGeometryInfoKHR* buildInfo) { for (int i = 0; i < count; i++) { - if (maxPrimities) { - maxPrimities[i] = info->geometries[i].primitiveCount; - } - // fill vulkan geometry struct VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; tmp->flags = VK_GEOMETRY_OPAQUE_BIT_KHR; // always opaque - // range info - if (rangeInfos) { - VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; - rangeInfo->primitiveCount = info->geometries[i].primitiveCount; - rangeInfo->firstVertex = 0; // PAL does not allow setting this - rangeInfo->primitiveOffset = 0; // PAL does not allow setting this - rangeInfo->transformOffset = 0; // PAL does not allow setting this - } - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; @@ -2273,9 +2270,33 @@ static void fillVkBuildInfoVk( address.deviceAddress = info->instanceBufferAddress; data->data = address; - VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; - rangeInfo->primitiveCount = info->instanceCount; + if (maxPrimities) { + maxPrimities[i] = info->instanceCount; + } + + // range info + if (rangeInfos) { + VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; + rangeInfo->primitiveCount = info->instanceCount; + rangeInfo->firstVertex = 0; // PAL does not allow setting this + rangeInfo->primitiveOffset = 0; // PAL does not allow setting this + rangeInfo->transformOffset = 0; // PAL does not allow setting this + } break; + + } else { + if (maxPrimities) { + maxPrimities[i] = info->geometries[i].primitiveCount; + } + + // range info + if (rangeInfos) { + VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; + rangeInfo->primitiveCount = info->geometries[i].primitiveCount; + rangeInfo->firstVertex = 0; // PAL does not allow setting this + rangeInfo->primitiveOffset = 0; // PAL does not allow setting this + rangeInfo->transformOffset = 0; // PAL does not allow setting this + } } if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { @@ -2336,15 +2357,15 @@ static void fillVkBuildInfoVk( // build hints buildInfo->flags = 0; if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD) { - buildInfo->flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; + buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; } if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE) { - buildInfo->flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; } if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY) { - buildInfo->flags = VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; + buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; } buildInfo->geometryCount = count; @@ -5903,7 +5924,7 @@ PalResult PAL_CALL waitFenceVk( } } - result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, true, timeout); + result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, true, timeInNanoseconds); if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -6435,6 +6456,10 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( VkAccelerationStructureKHR srcAs = nullptr; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + // cache these for top level as VkAccelerationStructureBuildRangeInfoKHR cachedRangeInfo = {0}; VkAccelerationStructureGeometryKHR cachedGeometries = {0}; @@ -6445,10 +6470,6 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( geometries = &cachedGeometries; } - if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - if (tmpAs) { srcAs = tmpAs->handle; } @@ -7292,8 +7313,8 @@ PalResult PAL_CALL cmdTraceRaysVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygenAddress.stride; - vkSbt->raygenAddress.deviceAddress = address; + // PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygenAddress.stride; + // vkSbt->raygenAddress.deviceAddress = address; vkCmdBuffer->device->cmdTraceRays( vkCmdBuffer->handle, @@ -7630,18 +7651,18 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( Device* vkDevice = (Device*)device; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + // cache these for top level as VkAccelerationStructureGeometryKHR cachedGeometries = {0}; - Uint32 cachedPrimitives[1]; + Uint32 cachedPrimitives = 0; Uint32 geometryCount = info->geometryCount; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { geometryCount = 1; geometries = &cachedGeometries; - maxPrimities = cachedPrimitives; - } - - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + maxPrimities = &cachedPrimitives; } if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { @@ -7779,8 +7800,13 @@ PalResult PAL_CALL computeInstanceBufferRequirementsVk( Uint32* outAlignment, Uint64* outSize) { - *outSize = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; - *outAlignment = 16; + if (outSize) { + *outSize = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; + } + + if (outAlignment) { + *outAlignment = 16; + } return PAL_RESULT_SUCCESS; } @@ -7788,10 +7814,12 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( PalDevice* device, PalImage* image, PalBufferImageCopyInfo* copyInfo, + Uint32* outBufferRowLength, + Uint32* outBufferImageHeight, Uint32* outAlignment, Uint64* outSize) { - // TODO: + // TODO: } PalResult PAL_CALL writeToInstanceBufferVk( @@ -8762,35 +8790,17 @@ PalResult PAL_CALL createRayTracingPipelineVk( } // shader groups - Uint32 numRaygen = 0; - Uint32 numMiss = 0; - Uint32 numHit = 0; - Uint32 numCallable = 0; for (int i = 0; i < info->shaderGroupCount; i++) { VkRayTracingShaderGroupCreateInfoKHR* group = &groups[i]; group->sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; if (info->shaderGroups[i].type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - // check which general shader it is - Shader* tmp = (Shader*)info->shaders[info->shaderGroups[i].generalShaderIndex]; - if (tmp->info.stage == VK_SHADER_STAGE_CALLABLE_BIT_KHR) { - numCallable++; - - } else if (tmp->info.stage == VK_SHADER_STAGE_MISS_BIT_KHR) { - numMiss++; - - } else { - numRaygen++; - } - } else if (info->shaderGroups[i].type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - numHit++; } else { group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; - numHit++; } group->anyHitShader = info->shaderGroups[i].anyHitShaderIndex; @@ -8815,13 +8825,12 @@ PalResult PAL_CALL createRayTracingPipelineVk( &s_Vk.vkAllocator, &pipeline->handle); + palFree(s_Vk.allocator, groups); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); - palFree(s_Vk.allocator, groups); return resultFromVk(result); } - palFree(s_Vk.allocator, groups); pipeline->device = vkDevice; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; diff --git a/tests/compute_test.c b/tests/compute_test.c index 3df4e55b..df6d94ed 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -120,7 +120,7 @@ bool computeTest() PalAdapterFeatures adapterFeatures = 0; bool hasComputeQueue = false; for (Int32 i = 0; i < adapterCount; i++) { - adapter = adapters[1]; // TODO: use the correct i index + adapter = adapters[i]; // TODO: use the correct i index result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -601,7 +601,7 @@ bool computeTest() } // wait for the fence - result = palWaitFence(fence, UINT64_MAX); + result = palWaitFence(fence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index eab7a3a0..76626e51 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -91,7 +91,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -538,15 +538,20 @@ bool rayTracingTest() }; memcpy(asInstance.transform, transform, sizeof(float) * 12); - PalInstanceBufferRequirements instanceBufferReq = {0}; - result = palComputeInstanceBufferRequirements(device, &instanceBufferReq, 1); + Uint64 instanceBufferSize = 0; + result = palComputeInstanceBufferRequirements( + device, + 1, + nullptr, // we dont need the alignment. We are not doing suballocations + &instanceBufferSize); + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to compute instance buffer requirement: %s", error); return false; } - bufferCreateInfo.size = instanceBufferReq.size; + bufferCreateInfo.size = instanceBufferSize; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; result = palCreateBuffer(device, &bufferCreateInfo, &instanceBuffer); @@ -588,7 +593,7 @@ bool rayTracingTest() result = palMapBufferMemory( instanceBuffer, 0, - instanceBufferReq.size, + instanceBufferSize, &data); if (result != PAL_RESULT_SUCCESS) { @@ -598,7 +603,7 @@ bool rayTracingTest() } // we can not use a direct memcpy for instance buffers - result = palWriteInstancesToMappedMemory(device, data, &asInstance, 1); + result = palWriteToInstanceBuffer(device, data, &asInstance, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to write instances to instance buffer: %s", error); @@ -958,6 +963,9 @@ bool rayTracingTest() return false; } + newAsUsageStateInfo.shaderStageCount = 1; + newAsUsageStateInfo.shaderStages = shaderStages; + // make sure the TLAS builds before the tracing result = palCmdMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); if (result != PAL_RESULT_SUCCESS) { @@ -966,12 +974,12 @@ bool rayTracingTest() return false; } - result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to trace rays: %s", error); - return false; - } + // result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); + // if (result != PAL_RESULT_SUCCESS) { + // const char* error = palFormatResult(result); + // palLog(nullptr, "Failed to trace rays: %s", error); + // return false; + // } // set a barrier so we only read from the buffer after the shader has // written to it @@ -1030,7 +1038,7 @@ bool rayTracingTest() } // wait for the fence - result = palWaitFence(fence, UINT64_MAX); + result = palWaitFence(fence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); diff --git a/tests/tests_main.c b/tests/tests_main.c index 88a7373f..ced95fcc 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,8 +58,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest); - registerTest(computeTest); - // registerTest(rayTracingTest); + // registerTest(computeTest); + registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO diff --git a/tests/texture_test.c b/tests/texture_test.c index 280fb586..47fc1176 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -1046,7 +1046,7 @@ bool textureTest() palDestroyShader(fragmentShader); // wait for the vertices copy to be done - result = palWaitFence(fence, UINT64_MAX); + result = palWaitFence(fence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); From e460497ec556763cd705d5a56ebcaa6602cf207c Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 6 Apr 2026 22:56:11 +0000 Subject: [PATCH 150/372] fix all graphics tests vulkan backend(linux) --- include/pal/pal_graphics.h | 32 ++++--- src/graphics/pal_d3d12.c | 7 +- src/graphics/pal_graphics.c | 163 ++++++++++++++++++++++++++++++++---- src/graphics/pal_vulkan.c | 102 +++++++++++++++------- tests/ray_tracing_test.c | 17 ++-- tests/tests_main.c | 12 +-- tests/texture_test.c | 48 +++++++++-- 7 files changed, 287 insertions(+), 94 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 14d05416..209cd02e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3662,7 +3662,6 @@ typedef struct { PalResult PAL_CALL (*computeInstanceBufferRequirements)( PalDevice* device, Uint32 instanceCount, - Uint32* outAlignment, Uint64* outSize); /** @@ -3672,11 +3671,10 @@ typedef struct { */ PalResult PAL_CALL (*computeImageCopyStagingBufferRequirements)( PalDevice* device, - PalImage* image, + Uint32 imageFormatSize, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, - Uint32* outAlignment, Uint64* outSize); /** @@ -3698,8 +3696,9 @@ typedef struct { PalResult PAL_CALL (*writeToImageCopyStagingBuffer)( PalDevice* device, void* ptr, + void* srcData, PalBufferImageCopyInfo* copyInfo, - PalFormat imageFormat); + Uint32 imageFormatSize); /** * Backend implementation of ::palBindBufferMemory. @@ -6620,14 +6619,13 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( * The graphics system must be initialized before this call. This does not allocate memory * for the buffer. * - * `outSize` and `outAlignment` are the size and alignment which must be used to create the - * instance buffer. This will be computed with regards to the provided `instanceCount`. This - * function must be used and required for all instance buffers. This is used with acceleration + * `outSize` must be the size that is used to create the instance buffer. It will be + * computed with regards to the provided `instanceCount`. This function must be used and required + * for all instance buffers. This is used with acceleration * structure (`TLAS`). * * @param[in] device Device to compute instance buffer requirements with. * @param[in] instanceCount Number of instances the instance buffer will hold. - * @param[out] outAlignment Pointer to a Uint32 to recieve the required alignment. * @param[out] outSize Pointer to a Uint64 to recieve the required size. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6641,7 +6639,6 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( PalDevice* device, Uint32 instanceCount, - Uint32* outAlignment, Uint64* outSize); /** @@ -6650,23 +6647,21 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * The graphics system must be initialized before this call. This does not allocate memory * for the buffer. * - * `outSize` and `outAlignment` are the size and alignment which must be used to create the - * image copy staging buffer. This will be computed with regards to the provided `image` - * and `copyInfo`. This function must be used and required for all image copy staging buffers. - * This is used with image copy commands. + * `outSize` must be the size that is used to create the image copy staging buffer. It will be + * computed with regards to the provided `imageFormat` and `copyInfo`. This function must be + * used and required for all image copy staging buffers. This is used with image copy commands. * * PalBufferImageCopyInfo::bufferRowLength and PalBufferImageCopyInfo::bufferImageHeight are hints. * The driver might used it defaults if the requested is not supported. Check `outBufferRowLength` - * and `outBufferImageHeight` to see the values the driver used. Set the new values to the + * and `outBufferImageHeight` to see the values the driver used. Set the new values to * `copyInfo` before writing to the buffer with `palWriteToImageCopyStagingBuffer()`. * * @param[in] device Device to compute image copy staging buffer requirements with. - * @param[in] image Destination image. + * @param[in] imageFormat Destination image format. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outBufferRowLength Pointer to a Uint32 to recieve the required buffer row length. * @param[out] outBufferImageHeight Pointer to a Uint32 to recieve the required buffer imag height. - * @param[out] outAlignment Pointer to a Uint32 to recieve the required alignment. * @param[out] outSize Pointer to a Uint64 to recieve the required size. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6679,11 +6674,10 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( */ PAL_API PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( PalDevice* device, - PalImage* image, + PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, - Uint32* outAlignment, Uint64* outSize); /** @@ -6718,6 +6712,7 @@ PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( * * @param[in] device The device. Must match the one used to create the image copy staging buffer. * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. + * @param[out] srcData Pointer to the CPU visible memory with the data. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * Must not be nullptr. * @param[in] imageFormat Destination image format. @@ -6733,6 +6728,7 @@ PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( PAL_API PalResult PAL_CALL palWriteToImageCopyStagingBuffer( PalDevice* device, void* ptr, + void* srcData, PalBufferImageCopyInfo* copyInfo, PalFormat imageFormat); diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index c2ed1ca4..0b0c3376 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -3942,7 +3942,6 @@ PalResult PAL_CALL getBufferMemoryRequirementsD3D12( PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( PalDevice* device, Uint32 instanceCount, - Uint32* outAlignment, Uint64* outSize) { @@ -3950,11 +3949,10 @@ PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( PalDevice* device, - PalImage* image, + Uint32 imageFormatSize, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, - Uint32* outAlignment, Uint64* outSize) { @@ -3972,8 +3970,9 @@ PalResult PAL_CALL writeToInstanceBufferD3D12( PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( PalDevice* device, void* ptr, + void* srcData, PalBufferImageCopyInfo* copyInfo, - PalFormat imageFormat) + Uint32 imageFormatSize) { } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index d708ce72..703fb0c5 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -93,6 +93,115 @@ static inline Uint32 _min( return (a < b) ? a : b; } +static Uint32 getFormatSize(PalFormat format) +{ + switch (format) { + case PAL_FORMAT_R8_UNORM: + case PAL_FORMAT_R8_SNORM: + case PAL_FORMAT_R8_UINT: + case PAL_FORMAT_R8_SINT: + case PAL_FORMAT_R8_SRGB: + case PAL_FORMAT_S8_UINT: + return 1; + + case PAL_FORMAT_R16_UNORM: + case PAL_FORMAT_R16_SNORM: + case PAL_FORMAT_R16_UINT: + case PAL_FORMAT_R16_SINT: + case PAL_FORMAT_R16_SFLOAT: + case PAL_FORMAT_R8G8_UNORM: + case PAL_FORMAT_R8G8_SNORM: + case PAL_FORMAT_R8G8_UINT: + case PAL_FORMAT_R8G8_SINT: + case PAL_FORMAT_R8G8_SRGB: + case PAL_FORMAT_D16_UNORM: + return 2; + + case PAL_FORMAT_R8G8B8_UNORM: + case PAL_FORMAT_R8G8B8_SNORM: + case PAL_FORMAT_R8G8B8_UINT: + case PAL_FORMAT_R8G8B8_SINT: + case PAL_FORMAT_R8G8B8_SRGB: + case PAL_FORMAT_B8G8R8_UNORM: + case PAL_FORMAT_B8G8R8_SNORM: + case PAL_FORMAT_B8G8R8_UINT: + case PAL_FORMAT_B8G8R8_SINT: + case PAL_FORMAT_B8G8R8_SRGB: + case PAL_FORMAT_D16_UNORM_S8_UINT: + return 3; + + case PAL_FORMAT_R32_UINT: + case PAL_FORMAT_R32_SINT: + case PAL_FORMAT_R32_SFLOAT: + case PAL_FORMAT_R16G16_UNORM: + case PAL_FORMAT_R16G16_SNORM: + case PAL_FORMAT_R16G16_UINT: + case PAL_FORMAT_R16G16_SINT: + case PAL_FORMAT_R16G16_SFLOAT: + case PAL_FORMAT_R8G8B8A8_UNORM: + case PAL_FORMAT_R8G8B8A8_SNORM: + case PAL_FORMAT_R8G8B8A8_UINT: + case PAL_FORMAT_R8G8B8A8_SINT: + case PAL_FORMAT_R8G8B8A8_SRGB: + case PAL_FORMAT_B8G8R8A8_UNORM: + case PAL_FORMAT_B8G8R8A8_SNORM: + case PAL_FORMAT_B8G8R8A8_UINT: + case PAL_FORMAT_B8G8R8A8_SINT: + case PAL_FORMAT_B8G8R8A8_SRGB: + case PAL_FORMAT_D32_SFLOAT: + case PAL_FORMAT_D24_UNORM_S8_UINT: + return 4; + + case PAL_FORMAT_D32_SFLOAT_S8_UINT: + return 5; + + case PAL_FORMAT_R16G16B16_UNORM: + case PAL_FORMAT_R16G16B16_SNORM: + case PAL_FORMAT_R16G16B16_UINT: + case PAL_FORMAT_R16G16B16_SINT: + case PAL_FORMAT_R16G16B16_SFLOAT: + return 6; + + case PAL_FORMAT_R64_UINT: + case PAL_FORMAT_R64_SINT: + case PAL_FORMAT_R64_SFLOAT: + case PAL_FORMAT_R32G32_UINT: + case PAL_FORMAT_R32G32_SINT: + case PAL_FORMAT_R32G32_SFLOAT: + case PAL_FORMAT_R16G16B16A16_UNORM: + case PAL_FORMAT_R16G16B16A16_SNORM: + case PAL_FORMAT_R16G16B16A16_UINT: + case PAL_FORMAT_R16G16B16A16_SINT: + case PAL_FORMAT_R16G16B16A16_SFLOAT: + return 8; + + case PAL_FORMAT_R32G32B32_UINT: + case PAL_FORMAT_R32G32B32_SINT: + case PAL_FORMAT_R32G32B32_SFLOAT: + return 12; + + case PAL_FORMAT_R64G64_UINT: + case PAL_FORMAT_R64G64_SINT: + case PAL_FORMAT_R64G64_SFLOAT: + case PAL_FORMAT_R32G32B32A32_UINT: + case PAL_FORMAT_R32G32B32A32_SINT: + case PAL_FORMAT_R32G32B32A32_SFLOAT: + return 16; + + case PAL_FORMAT_R64G64B64_UINT: + case PAL_FORMAT_R64G64B64_SINT: + case PAL_FORMAT_R64G64B64_SFLOAT: + return 24; + + case PAL_FORMAT_R64G64B64A64_UINT: + case PAL_FORMAT_R64G64B64A64_SINT: + case PAL_FORMAT_R64G64B64A64_SFLOAT: + return 32; + } + + return 0; +} + // ================================================== // Vulkan API // ================================================== @@ -667,16 +776,14 @@ PalResult PAL_CALL getBufferMemoryRequirementsVk( PalResult PAL_CALL computeInstanceBufferRequirementsVk( PalDevice* device, Uint32 instanceCount, - Uint32* outAlignment, Uint64* outSize); PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( PalDevice* device, - PalImage* image, + Uint32 imageFormatSize, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, - Uint32* outAlignment, Uint64* outSize); PalResult PAL_CALL writeToInstanceBufferVk( @@ -688,8 +795,9 @@ PalResult PAL_CALL writeToInstanceBufferVk( PalResult PAL_CALL writeToImageCopyStagingBufferVk( PalDevice* device, void* ptr, + void* srcData, PalBufferImageCopyInfo* copyInfo, - PalFormat imageFormat); + Uint32 imageFormatSize); PalResult PAL_CALL bindBufferMemoryVk( PalBuffer* buffer, @@ -1535,16 +1643,14 @@ PalResult PAL_CALL getBufferMemoryRequirementsD3D12( PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( PalDevice* device, Uint32 instanceCount, - Uint32* outAlignment, Uint64* outSize); PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( PalDevice* device, - PalImage* image, + Uint32 imageFormatSize, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, - Uint32* outAlignment, Uint64* outSize); PalResult PAL_CALL writeToInstanceBufferD3D12( @@ -1556,8 +1662,9 @@ PalResult PAL_CALL writeToInstanceBufferD3D12( PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( PalDevice* device, void* ptr, + void* srcData, PalBufferImageCopyInfo* copyInfo, - PalFormat imageFormat); + Uint32 imageFormatSize); PalResult PAL_CALL bindBufferMemoryD3D12( PalBuffer* buffer, @@ -4007,48 +4114,53 @@ PalResult PAL_CALL palGetBufferMemoryRequirements( PalResult PAL_CALL palComputeInstanceBufferRequirements( PalDevice* device, Uint32 instanceCount, - Uint32* outAlignment, Uint64* outSize) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device) { + if (!device || !outSize) { return PAL_RESULT_NULL_POINTER; } return device->backend->computeInstanceBufferRequirements( device, instanceCount, - outAlignment, outSize); } PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( PalDevice* device, - PalImage* image, + PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, - Uint32* outAlignment, Uint64* outSize) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device) { + if (!device || !outBufferRowLength || !outBufferImageHeight || !outSize) { return PAL_RESULT_NULL_POINTER; } + if (copyInfo->bufferRowLength < copyInfo->imageWidth && copyInfo->bufferRowLength) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (copyInfo->bufferImageHeight < copyInfo->imageHeight && copyInfo->bufferImageHeight) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + Uint32 formatSize = getFormatSize(imageFormat); return device->backend->computeImageCopyStagingBufferRequirements( device, - image, + formatSize, copyInfo, outBufferRowLength, outBufferImageHeight, - outAlignment, outSize); } @@ -4073,6 +4185,7 @@ PalResult PAL_CALL palWriteToInstanceBuffer( PalResult PAL_CALL palWriteToImageCopyStagingBuffer( PalDevice* device, void* ptr, + void* srcData, PalBufferImageCopyInfo* copyInfo, PalFormat imageFormat) { @@ -4080,11 +4193,25 @@ PalResult PAL_CALL palWriteToImageCopyStagingBuffer( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!device || !ptr || !copyInfo) { + if (!device || !ptr || !srcData || !copyInfo) { return PAL_RESULT_NULL_POINTER; } - return device->backend->writeToImageCopyStagingBuffer(device, ptr, copyInfo, imageFormat); + if (copyInfo->bufferRowLength < copyInfo->imageWidth && copyInfo->bufferRowLength) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (copyInfo->bufferImageHeight < copyInfo->imageHeight && copyInfo->bufferImageHeight) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + Uint32 formatSize = getFormatSize(imageFormat); + return device->backend->writeToImageCopyStagingBuffer( + device, + ptr, + srcData, + copyInfo, + formatSize); } PalResult PAL_CALL palBindBufferMemory( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 9c9c0f91..36950b2e 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2243,6 +2243,13 @@ static inline Uint32 alignVk( return (value + alignment - 1) & ~(alignment - 1); } +static inline Uint32 minVk( + Uint32 a, + Uint32 b) +{ + return (a < b) ? a : b; +} + static void fillVkBuildInfoVk( Uint32 count, PalAccelerationStructureBuildInfo* info, @@ -6584,14 +6591,14 @@ PalResult PAL_CALL cmdBeginRenderingVk( attachment->imageLayout = layout; // compute layer count and render area - layerCount = min(layerCount, imageView->range.layerCount); - renderWidth = min(renderWidth, imageView->image->info.width); - renderHeight = min(renderHeight, imageView->image->info.height); + layerCount = minVk(layerCount, imageView->range.layerCount); + renderWidth = minVk(renderWidth, imageView->image->info.width); + renderHeight = minVk(renderHeight, imageView->image->info.height); if (resolveImageView) { - layerCount = min(layerCount, resolveImageView->range.layerCount); - renderWidth = min(renderWidth, resolveImageView->image->info.width); - renderHeight = min(renderHeight, resolveImageView->image->info.height); + layerCount = minVk(layerCount, resolveImageView->range.layerCount); + renderWidth = minVk(renderWidth, resolveImageView->image->info.width); + renderHeight = minVk(renderHeight, resolveImageView->image->info.height); } } @@ -6675,14 +6682,14 @@ PalResult PAL_CALL cmdBeginRenderingVk( rendering.pStencilAttachment = &stencilAttachment; // compute layer count and render area - layerCount = min(layerCount, imageView->range.layerCount); - renderWidth = min(renderWidth, imageView->image->info.width); - renderHeight = min(renderHeight, imageView->image->info.height); + layerCount = minVk(layerCount, imageView->range.layerCount); + renderWidth = minVk(renderWidth, imageView->image->info.width); + renderHeight = minVk(renderHeight, imageView->image->info.height); if (resolveImageView) { - layerCount = min(layerCount, resolveImageView->range.layerCount); - renderWidth = min(renderWidth, resolveImageView->image->info.width); - renderHeight = min(renderHeight, resolveImageView->image->info.height); + layerCount = minVk(layerCount, resolveImageView->range.layerCount); + renderWidth = minVk(renderWidth, resolveImageView->image->info.width); + renderHeight = minVk(renderHeight, resolveImageView->image->info.height); } } @@ -6701,9 +6708,9 @@ PalResult PAL_CALL cmdBeginRenderingVk( rendering.pNext = &fsrInfo; // compute layer count and render area - layerCount = min(layerCount, imageView->range.layerCount); - renderWidth = min(renderWidth, imageView->image->info.width); - renderHeight = min(renderHeight, imageView->image->info.height); + layerCount = minVk(layerCount, imageView->range.layerCount); + renderWidth = minVk(renderWidth, imageView->image->info.width); + renderHeight = minVk(renderHeight, imageView->image->info.height); } rendering.layerCount = layerCount; @@ -7313,12 +7320,14 @@ PalResult PAL_CALL cmdTraceRaysVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygenAddress.stride; - // vkSbt->raygenAddress.deviceAddress = address; + VkStridedDeviceAddressRegionKHR raygenAddress = {0}; + raygenAddress.size = vkSbt->raygenAddress.size; + raygenAddress.stride = vkSbt->raygenAddress.stride; + raygenAddress.deviceAddress = vkSbt->baseAddress + raygenIndex * vkSbt->raygenAddress.stride; vkCmdBuffer->device->cmdTraceRays( vkCmdBuffer->handle, - &vkSbt->raygenAddress, + &raygenAddress, &vkSbt->missAddress, &vkSbt->hitAddress, &vkSbt->callableAddress, @@ -7797,29 +7806,30 @@ PalResult PAL_CALL getBufferMemoryRequirementsVk( PalResult PAL_CALL computeInstanceBufferRequirementsVk( PalDevice* device, Uint32 instanceCount, - Uint32* outAlignment, Uint64* outSize) { - if (outSize) { - *outSize = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; - } - - if (outAlignment) { - *outAlignment = 16; - } + *outSize = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; return PAL_RESULT_SUCCESS; } PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( PalDevice* device, - PalImage* image, + Uint32 imageFormatSize, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, - Uint32* outAlignment, Uint64* outSize) { - // TODO: + Uint32 length, height; + length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; + height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; + Uint32 rowPitch = length * imageFormatSize; + Uint32 slicePitch = rowPitch * height; + + *outBufferRowLength = copyInfo->bufferRowLength; + *outBufferImageHeight = copyInfo->bufferImageHeight; + *outSize = slicePitch * copyInfo->imageDepth; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL writeToInstanceBufferVk( @@ -7847,10 +7857,40 @@ PalResult PAL_CALL writeToInstanceBufferVk( PalResult PAL_CALL writeToImageCopyStagingBufferVk( PalDevice* device, void* ptr, + void* srcData, PalBufferImageCopyInfo* copyInfo, - PalFormat imageFormat) + Uint32 imageFormatSize) { - // TODO: + if (copyInfo->bufferRowLength == 0 && copyInfo->bufferImageHeight == 0) { + Uint64 size = copyInfo->imageWidth * copyInfo->imageHeight * copyInfo->imageDepth; + // normal path. Simple memcpy works + memcpy(ptr, srcData, size * imageFormatSize); + return PAL_RESULT_SUCCESS; + } + + Uint32 length, height; + length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; + height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; + Uint32 rowPitch = length * imageFormatSize; + Uint32 slicePitch = rowPitch * height; + + // manually offset the buffer with the provided offset + Uint8* dst = (Uint8*)ptr + copyInfo->bufferOffset; + const Uint8* src = (const Uint8*)srcData; + Uint64 tmpSizeDest = length * height * imageFormatSize; + Uint64 tmpSizeSrc = copyInfo->imageWidth * copyInfo->imageHeight * imageFormatSize; + + // write to destination pointer + for (Uint32 z = 0; z < copyInfo->imageDepth; z++) { + for (Uint32 y = 0; y < copyInfo->imageWidth; y++) { + memcpy( + dst + z * tmpSizeDest + y * (length * imageFormatSize), + src + z * tmpSizeSrc + y * (copyInfo->imageWidth * imageFormatSize), + copyInfo->imageWidth * imageFormatSize); + } + } + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL bindBufferMemoryVk( diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 76626e51..a2bfaee3 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -91,7 +91,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -541,8 +541,7 @@ bool rayTracingTest() Uint64 instanceBufferSize = 0; result = palComputeInstanceBufferRequirements( device, - 1, - nullptr, // we dont need the alignment. We are not doing suballocations + 1, &instanceBufferSize); if (result != PAL_RESULT_SUCCESS) { @@ -974,12 +973,12 @@ bool rayTracingTest() return false; } - // result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); - // if (result != PAL_RESULT_SUCCESS) { - // const char* error = palFormatResult(result); - // palLog(nullptr, "Failed to trace rays: %s", error); - // return false; - // } + result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to trace rays: %s", error); + return false; + } // set a barrier so we only read from the buffer after the shader has // written to it diff --git a/tests/tests_main.c b/tests/tests_main.c index ced95fcc..d7e9a0d3 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,16 +57,16 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest); - // registerTest(computeTest); + registerTest(graphicsTest); + registerTest(computeTest); registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest(clearColorTest); - // registerTest(triangleTest); - // registerTest(meshTest); - // registerTest(textureTest); + registerTest(clearColorTest); + registerTest(triangleTest); + registerTest(meshTest); + registerTest(textureTest); #endif // runTests(); diff --git a/tests/texture_test.c b/tests/texture_test.c index 47fc1176..6e99bfdb 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -577,10 +577,35 @@ bool textureTest() return false; } + // create staging buffer to transfer the data to the image + PalBufferImageCopyInfo bufferImageCopyInfo = {0}; + bufferImageCopyInfo.ImageArrayLayerCount = 1; + bufferImageCopyInfo.imageWidth = TEXTURE_WIDTH; + bufferImageCopyInfo.imageHeight = TEXTURE_HEIGHT; + bufferImageCopyInfo.imageDepth = 1; // 2D image + + Uint64 imageCopyStagingBufferSize = 0; + Uint32 bufferRowLength = 0; + Uint32 bufferImageHeight = 0; + + result = palComputeImageCopyStagingBufferRequirements( + device, + imageCreateInfo.format, + &bufferImageCopyInfo, + &bufferRowLength, + &bufferImageHeight, + &imageCopyStagingBufferSize); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to compute image copy staging buffer info: %s", error); + return false; + } + // create staging buffer to transfer the data to the image PalBuffer* imageStagingBuffer = nullptr; PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; - imageStagingBufferCreateInfo.size = TEXTURE_WIDTH * TEXTURE_HEIGHT * 4; + imageStagingBufferCreateInfo.size = imageCopyStagingBufferSize; imageStagingBufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; result = palCreateBuffer(device, &imageStagingBufferCreateInfo, &imageStagingBuffer); @@ -633,7 +658,20 @@ bool textureTest() return false; } - memcpy(data, texture, imageStagingBufferCreateInfo.size); + // write data to the mapped image copy staging buffer + result = palWriteToImageCopyStagingBuffer( + device, + data, + texture, + &bufferImageCopyInfo, + imageCreateInfo.format); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to write to image copy staging buffer: %s", error); + return false; + } + palUnmapBufferMemory(imageStagingBuffer); // use the first command buffer to upload the copy @@ -699,12 +737,6 @@ bool textureTest() return false; } - PalBufferImageCopyInfo bufferImageCopyInfo = {0}; - bufferImageCopyInfo.ImageArrayLayerCount = 1; - bufferImageCopyInfo.imageWidth = TEXTURE_WIDTH; - bufferImageCopyInfo.imageHeight = TEXTURE_HEIGHT; - bufferImageCopyInfo.imageDepth = 1; // 2D image - result = palCmdCopyBufferToImage( cmdBuffers[0], checkerboard, From dd82c5fcbac1734e913d8142633c136356768196 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 7 Apr 2026 15:40:34 +0000 Subject: [PATCH 151/372] add copy image command API d3d12 --- include/pal/pal_graphics.h | 12 +-- src/graphics/pal_d3d12.c | 156 +++++++++++++++++++++++++++++++++++- src/graphics/pal_graphics.c | 133 +++--------------------------- src/graphics/pal_vulkan.c | 118 ++++++++++++++++++++++++++- tests/tests_main.c | 12 +-- tests/texture_test.c | 4 +- 6 files changed, 294 insertions(+), 141 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 209cd02e..e9f92e1f 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3671,7 +3671,7 @@ typedef struct { */ PalResult PAL_CALL (*computeImageCopyStagingBufferRequirements)( PalDevice* device, - Uint32 imageFormatSize, + PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, @@ -3697,8 +3697,8 @@ typedef struct { PalDevice* device, void* ptr, void* srcData, - PalBufferImageCopyInfo* copyInfo, - Uint32 imageFormatSize); + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo); /** * Backend implementation of ::palBindBufferMemory. @@ -6713,9 +6713,9 @@ PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( * @param[in] device The device. Must match the one used to create the image copy staging buffer. * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. * @param[out] srcData Pointer to the CPU visible memory with the data. + * @param[in] imageFormat Destination image format. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * Must not be nullptr. - * @param[in] imageFormat Destination image format. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6729,8 +6729,8 @@ PAL_API PalResult PAL_CALL palWriteToImageCopyStagingBuffer( PalDevice* device, void* ptr, void* srcData, - PalBufferImageCopyInfo* copyInfo, - PalFormat imageFormat); + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo); /** * @brief Bind an allocated memory to a buffer. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 0b0c3376..0283ba44 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -45,6 +45,7 @@ freely, subject to the following restrictions: #endif // D3D_FEATURE_LEVEL_12_2 #define MAX_ATTACHMENTS 32 +#define TEXTURE_PITCH 256 // IIDS const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; @@ -928,6 +929,122 @@ static void fillVkBuildInfoD3D12( buildInfo->ScratchAccelerationStructureData = info->scratchBufferAddress; } +static Uint32 getFormatSizeD3D12(PalFormat format) +{ + switch (format) { + case PAL_FORMAT_R8_UNORM: + case PAL_FORMAT_R8_SNORM: + case PAL_FORMAT_R8_UINT: + case PAL_FORMAT_R8_SINT: + case PAL_FORMAT_R8_SRGB: + case PAL_FORMAT_S8_UINT: + return 1; + + case PAL_FORMAT_R16_UNORM: + case PAL_FORMAT_R16_SNORM: + case PAL_FORMAT_R16_UINT: + case PAL_FORMAT_R16_SINT: + case PAL_FORMAT_R16_SFLOAT: + case PAL_FORMAT_R8G8_UNORM: + case PAL_FORMAT_R8G8_SNORM: + case PAL_FORMAT_R8G8_UINT: + case PAL_FORMAT_R8G8_SINT: + case PAL_FORMAT_R8G8_SRGB: + case PAL_FORMAT_D16_UNORM: + return 2; + + case PAL_FORMAT_R8G8B8_UNORM: + case PAL_FORMAT_R8G8B8_SNORM: + case PAL_FORMAT_R8G8B8_UINT: + case PAL_FORMAT_R8G8B8_SINT: + case PAL_FORMAT_R8G8B8_SRGB: + case PAL_FORMAT_B8G8R8_UNORM: + case PAL_FORMAT_B8G8R8_SNORM: + case PAL_FORMAT_B8G8R8_UINT: + case PAL_FORMAT_B8G8R8_SINT: + case PAL_FORMAT_B8G8R8_SRGB: + case PAL_FORMAT_D16_UNORM_S8_UINT: + return 3; + + case PAL_FORMAT_R32_UINT: + case PAL_FORMAT_R32_SINT: + case PAL_FORMAT_R32_SFLOAT: + case PAL_FORMAT_R16G16_UNORM: + case PAL_FORMAT_R16G16_SNORM: + case PAL_FORMAT_R16G16_UINT: + case PAL_FORMAT_R16G16_SINT: + case PAL_FORMAT_R16G16_SFLOAT: + case PAL_FORMAT_R8G8B8A8_UNORM: + case PAL_FORMAT_R8G8B8A8_SNORM: + case PAL_FORMAT_R8G8B8A8_UINT: + case PAL_FORMAT_R8G8B8A8_SINT: + case PAL_FORMAT_R8G8B8A8_SRGB: + case PAL_FORMAT_B8G8R8A8_UNORM: + case PAL_FORMAT_B8G8R8A8_SNORM: + case PAL_FORMAT_B8G8R8A8_UINT: + case PAL_FORMAT_B8G8R8A8_SINT: + case PAL_FORMAT_B8G8R8A8_SRGB: + case PAL_FORMAT_D32_SFLOAT: + case PAL_FORMAT_D24_UNORM_S8_UINT: + return 4; + + case PAL_FORMAT_D32_SFLOAT_S8_UINT: + return 5; + + case PAL_FORMAT_R16G16B16_UNORM: + case PAL_FORMAT_R16G16B16_SNORM: + case PAL_FORMAT_R16G16B16_UINT: + case PAL_FORMAT_R16G16B16_SINT: + case PAL_FORMAT_R16G16B16_SFLOAT: + return 6; + + case PAL_FORMAT_R64_UINT: + case PAL_FORMAT_R64_SINT: + case PAL_FORMAT_R64_SFLOAT: + case PAL_FORMAT_R32G32_UINT: + case PAL_FORMAT_R32G32_SINT: + case PAL_FORMAT_R32G32_SFLOAT: + case PAL_FORMAT_R16G16B16A16_UNORM: + case PAL_FORMAT_R16G16B16A16_SNORM: + case PAL_FORMAT_R16G16B16A16_UINT: + case PAL_FORMAT_R16G16B16A16_SINT: + case PAL_FORMAT_R16G16B16A16_SFLOAT: + return 8; + + case PAL_FORMAT_R32G32B32_UINT: + case PAL_FORMAT_R32G32B32_SINT: + case PAL_FORMAT_R32G32B32_SFLOAT: + return 12; + + case PAL_FORMAT_R64G64_UINT: + case PAL_FORMAT_R64G64_SINT: + case PAL_FORMAT_R64G64_SFLOAT: + case PAL_FORMAT_R32G32B32A32_UINT: + case PAL_FORMAT_R32G32B32A32_SINT: + case PAL_FORMAT_R32G32B32A32_SFLOAT: + return 16; + + case PAL_FORMAT_R64G64B64_UINT: + case PAL_FORMAT_R64G64B64_SINT: + case PAL_FORMAT_R64G64B64_SFLOAT: + return 24; + + case PAL_FORMAT_R64G64B64A64_UINT: + case PAL_FORMAT_R64G64B64A64_SINT: + case PAL_FORMAT_R64G64B64A64_SFLOAT: + return 32; + } + + return 0; +} + +static inline Uint32 alignD3D12( + Uint32 value, + Uint32 alignment) +{ + return (value + alignment - 1) & ~(alignment - 1); +} + // ================================================== // Adapter // ================================================== @@ -3628,7 +3745,44 @@ PalResult PAL_CALL cmdCopyBufferToImageD3D12( PalBuffer* srcBuffer, PalBufferImageCopyInfo* copyInfo) { - // TODO: + CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + Image* dst = (Image*)dstImage; + Buffer* src = (Buffer*)srcBuffer; + + D3D12_TEXTURE_COPY_LOCATION dstLocation = {0}; + dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstLocation.pResource = dst->handle; + + D3D12_TEXTURE_COPY_LOCATION srcLocation = {0}; + srcLocation.pResource = src->handle; + srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT* footPrint = &srcLocation.PlacedFootprint; + + footPrint->Offset = copyInfo->bufferOffset; + footPrint->Footprint.Width = copyInfo->imageWidth; + footPrint->Footprint.Height = copyInfo->imageHeight; + footPrint->Footprint.Depth = copyInfo->imageDepth; + footPrint->Footprint.Format = formatToD3D12(dst->info.format); + + Uint32 imageFormatSize = getFormatSizeVk(dst->info.format); + Uint64 rowPitch = alignD3D12((Uint64)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + footPrint->Footprint.RowPitch = (UINT)rowPitch; + + D3D12_BOX box = {0}; + box.right = copyInfo->imageWidth; + box.bottom= copyInfo->imageHeight; + box.back = copyInfo->imageDepth; + + d3d12CmdBuffer->handle6->lpVtbl->CopyTextureRegion( + d3d12CmdBuffer->handle6, + &dstLocation, + copyInfo->imageOffsetX, + copyInfo->imageOffsetY, + copyInfo->imageOffsetZ, + &srcLocation, + &box); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdCopyImageD3D12( diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 703fb0c5..1b4dfefd 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -93,115 +93,6 @@ static inline Uint32 _min( return (a < b) ? a : b; } -static Uint32 getFormatSize(PalFormat format) -{ - switch (format) { - case PAL_FORMAT_R8_UNORM: - case PAL_FORMAT_R8_SNORM: - case PAL_FORMAT_R8_UINT: - case PAL_FORMAT_R8_SINT: - case PAL_FORMAT_R8_SRGB: - case PAL_FORMAT_S8_UINT: - return 1; - - case PAL_FORMAT_R16_UNORM: - case PAL_FORMAT_R16_SNORM: - case PAL_FORMAT_R16_UINT: - case PAL_FORMAT_R16_SINT: - case PAL_FORMAT_R16_SFLOAT: - case PAL_FORMAT_R8G8_UNORM: - case PAL_FORMAT_R8G8_SNORM: - case PAL_FORMAT_R8G8_UINT: - case PAL_FORMAT_R8G8_SINT: - case PAL_FORMAT_R8G8_SRGB: - case PAL_FORMAT_D16_UNORM: - return 2; - - case PAL_FORMAT_R8G8B8_UNORM: - case PAL_FORMAT_R8G8B8_SNORM: - case PAL_FORMAT_R8G8B8_UINT: - case PAL_FORMAT_R8G8B8_SINT: - case PAL_FORMAT_R8G8B8_SRGB: - case PAL_FORMAT_B8G8R8_UNORM: - case PAL_FORMAT_B8G8R8_SNORM: - case PAL_FORMAT_B8G8R8_UINT: - case PAL_FORMAT_B8G8R8_SINT: - case PAL_FORMAT_B8G8R8_SRGB: - case PAL_FORMAT_D16_UNORM_S8_UINT: - return 3; - - case PAL_FORMAT_R32_UINT: - case PAL_FORMAT_R32_SINT: - case PAL_FORMAT_R32_SFLOAT: - case PAL_FORMAT_R16G16_UNORM: - case PAL_FORMAT_R16G16_SNORM: - case PAL_FORMAT_R16G16_UINT: - case PAL_FORMAT_R16G16_SINT: - case PAL_FORMAT_R16G16_SFLOAT: - case PAL_FORMAT_R8G8B8A8_UNORM: - case PAL_FORMAT_R8G8B8A8_SNORM: - case PAL_FORMAT_R8G8B8A8_UINT: - case PAL_FORMAT_R8G8B8A8_SINT: - case PAL_FORMAT_R8G8B8A8_SRGB: - case PAL_FORMAT_B8G8R8A8_UNORM: - case PAL_FORMAT_B8G8R8A8_SNORM: - case PAL_FORMAT_B8G8R8A8_UINT: - case PAL_FORMAT_B8G8R8A8_SINT: - case PAL_FORMAT_B8G8R8A8_SRGB: - case PAL_FORMAT_D32_SFLOAT: - case PAL_FORMAT_D24_UNORM_S8_UINT: - return 4; - - case PAL_FORMAT_D32_SFLOAT_S8_UINT: - return 5; - - case PAL_FORMAT_R16G16B16_UNORM: - case PAL_FORMAT_R16G16B16_SNORM: - case PAL_FORMAT_R16G16B16_UINT: - case PAL_FORMAT_R16G16B16_SINT: - case PAL_FORMAT_R16G16B16_SFLOAT: - return 6; - - case PAL_FORMAT_R64_UINT: - case PAL_FORMAT_R64_SINT: - case PAL_FORMAT_R64_SFLOAT: - case PAL_FORMAT_R32G32_UINT: - case PAL_FORMAT_R32G32_SINT: - case PAL_FORMAT_R32G32_SFLOAT: - case PAL_FORMAT_R16G16B16A16_UNORM: - case PAL_FORMAT_R16G16B16A16_SNORM: - case PAL_FORMAT_R16G16B16A16_UINT: - case PAL_FORMAT_R16G16B16A16_SINT: - case PAL_FORMAT_R16G16B16A16_SFLOAT: - return 8; - - case PAL_FORMAT_R32G32B32_UINT: - case PAL_FORMAT_R32G32B32_SINT: - case PAL_FORMAT_R32G32B32_SFLOAT: - return 12; - - case PAL_FORMAT_R64G64_UINT: - case PAL_FORMAT_R64G64_SINT: - case PAL_FORMAT_R64G64_SFLOAT: - case PAL_FORMAT_R32G32B32A32_UINT: - case PAL_FORMAT_R32G32B32A32_SINT: - case PAL_FORMAT_R32G32B32A32_SFLOAT: - return 16; - - case PAL_FORMAT_R64G64B64_UINT: - case PAL_FORMAT_R64G64B64_SINT: - case PAL_FORMAT_R64G64B64_SFLOAT: - return 24; - - case PAL_FORMAT_R64G64B64A64_UINT: - case PAL_FORMAT_R64G64B64A64_SINT: - case PAL_FORMAT_R64G64B64A64_SFLOAT: - return 32; - } - - return 0; -} - // ================================================== // Vulkan API // ================================================== @@ -780,7 +671,7 @@ PalResult PAL_CALL computeInstanceBufferRequirementsVk( PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( PalDevice* device, - Uint32 imageFormatSize, + PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, @@ -796,8 +687,8 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( PalDevice* device, void* ptr, void* srcData, - PalBufferImageCopyInfo* copyInfo, - Uint32 imageFormatSize); + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo); PalResult PAL_CALL bindBufferMemoryVk( PalBuffer* buffer, @@ -1647,7 +1538,7 @@ PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( PalDevice* device, - Uint32 imageFormatSize, + PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, @@ -1663,8 +1554,8 @@ PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( PalDevice* device, void* ptr, void* srcData, - PalBufferImageCopyInfo* copyInfo, - Uint32 imageFormatSize); + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo); PalResult PAL_CALL bindBufferMemoryD3D12( PalBuffer* buffer, @@ -4154,10 +4045,9 @@ PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( return PAL_RESULT_INVALID_ARGUMENT; } - Uint32 formatSize = getFormatSize(imageFormat); return device->backend->computeImageCopyStagingBufferRequirements( device, - formatSize, + imageFormat, copyInfo, outBufferRowLength, outBufferImageHeight, @@ -4186,8 +4076,8 @@ PalResult PAL_CALL palWriteToImageCopyStagingBuffer( PalDevice* device, void* ptr, void* srcData, - PalBufferImageCopyInfo* copyInfo, - PalFormat imageFormat) + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -4205,13 +4095,12 @@ PalResult PAL_CALL palWriteToImageCopyStagingBuffer( return PAL_RESULT_INVALID_ARGUMENT; } - Uint32 formatSize = getFormatSize(imageFormat); return device->backend->writeToImageCopyStagingBuffer( device, ptr, srcData, - copyInfo, - formatSize); + imageFormat, + copyInfo); } PalResult PAL_CALL palBindBufferMemory( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 36950b2e..7c22e856 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2385,6 +2385,115 @@ static void fillVkBuildInfoVk( buildInfo->scratchData = scratchData; } +static Uint32 getFormatSizeVk(PalFormat format) +{ + switch (format) { + case PAL_FORMAT_R8_UNORM: + case PAL_FORMAT_R8_SNORM: + case PAL_FORMAT_R8_UINT: + case PAL_FORMAT_R8_SINT: + case PAL_FORMAT_R8_SRGB: + case PAL_FORMAT_S8_UINT: + return 1; + + case PAL_FORMAT_R16_UNORM: + case PAL_FORMAT_R16_SNORM: + case PAL_FORMAT_R16_UINT: + case PAL_FORMAT_R16_SINT: + case PAL_FORMAT_R16_SFLOAT: + case PAL_FORMAT_R8G8_UNORM: + case PAL_FORMAT_R8G8_SNORM: + case PAL_FORMAT_R8G8_UINT: + case PAL_FORMAT_R8G8_SINT: + case PAL_FORMAT_R8G8_SRGB: + case PAL_FORMAT_D16_UNORM: + return 2; + + case PAL_FORMAT_R8G8B8_UNORM: + case PAL_FORMAT_R8G8B8_SNORM: + case PAL_FORMAT_R8G8B8_UINT: + case PAL_FORMAT_R8G8B8_SINT: + case PAL_FORMAT_R8G8B8_SRGB: + case PAL_FORMAT_B8G8R8_UNORM: + case PAL_FORMAT_B8G8R8_SNORM: + case PAL_FORMAT_B8G8R8_UINT: + case PAL_FORMAT_B8G8R8_SINT: + case PAL_FORMAT_B8G8R8_SRGB: + case PAL_FORMAT_D16_UNORM_S8_UINT: + return 3; + + case PAL_FORMAT_R32_UINT: + case PAL_FORMAT_R32_SINT: + case PAL_FORMAT_R32_SFLOAT: + case PAL_FORMAT_R16G16_UNORM: + case PAL_FORMAT_R16G16_SNORM: + case PAL_FORMAT_R16G16_UINT: + case PAL_FORMAT_R16G16_SINT: + case PAL_FORMAT_R16G16_SFLOAT: + case PAL_FORMAT_R8G8B8A8_UNORM: + case PAL_FORMAT_R8G8B8A8_SNORM: + case PAL_FORMAT_R8G8B8A8_UINT: + case PAL_FORMAT_R8G8B8A8_SINT: + case PAL_FORMAT_R8G8B8A8_SRGB: + case PAL_FORMAT_B8G8R8A8_UNORM: + case PAL_FORMAT_B8G8R8A8_SNORM: + case PAL_FORMAT_B8G8R8A8_UINT: + case PAL_FORMAT_B8G8R8A8_SINT: + case PAL_FORMAT_B8G8R8A8_SRGB: + case PAL_FORMAT_D32_SFLOAT: + case PAL_FORMAT_D24_UNORM_S8_UINT: + return 4; + + case PAL_FORMAT_D32_SFLOAT_S8_UINT: + return 5; + + case PAL_FORMAT_R16G16B16_UNORM: + case PAL_FORMAT_R16G16B16_SNORM: + case PAL_FORMAT_R16G16B16_UINT: + case PAL_FORMAT_R16G16B16_SINT: + case PAL_FORMAT_R16G16B16_SFLOAT: + return 6; + + case PAL_FORMAT_R64_UINT: + case PAL_FORMAT_R64_SINT: + case PAL_FORMAT_R64_SFLOAT: + case PAL_FORMAT_R32G32_UINT: + case PAL_FORMAT_R32G32_SINT: + case PAL_FORMAT_R32G32_SFLOAT: + case PAL_FORMAT_R16G16B16A16_UNORM: + case PAL_FORMAT_R16G16B16A16_SNORM: + case PAL_FORMAT_R16G16B16A16_UINT: + case PAL_FORMAT_R16G16B16A16_SINT: + case PAL_FORMAT_R16G16B16A16_SFLOAT: + return 8; + + case PAL_FORMAT_R32G32B32_UINT: + case PAL_FORMAT_R32G32B32_SINT: + case PAL_FORMAT_R32G32B32_SFLOAT: + return 12; + + case PAL_FORMAT_R64G64_UINT: + case PAL_FORMAT_R64G64_SINT: + case PAL_FORMAT_R64G64_SFLOAT: + case PAL_FORMAT_R32G32B32A32_UINT: + case PAL_FORMAT_R32G32B32A32_SINT: + case PAL_FORMAT_R32G32B32A32_SFLOAT: + return 16; + + case PAL_FORMAT_R64G64B64_UINT: + case PAL_FORMAT_R64G64B64_SINT: + case PAL_FORMAT_R64G64B64_SFLOAT: + return 24; + + case PAL_FORMAT_R64G64B64A64_UINT: + case PAL_FORMAT_R64G64B64A64_SINT: + case PAL_FORMAT_R64G64B64A64_SFLOAT: + return 32; + } + + return 0; +} + // ================================================== // Adapter // ================================================== @@ -7814,7 +7923,7 @@ PalResult PAL_CALL computeInstanceBufferRequirementsVk( PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( PalDevice* device, - Uint32 imageFormatSize, + PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, @@ -7823,7 +7932,7 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( Uint32 length, height; length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; - Uint32 rowPitch = length * imageFormatSize; + Uint32 rowPitch = length * getFormatSizeVk(imageFormat); Uint32 slicePitch = rowPitch * height; *outBufferRowLength = copyInfo->bufferRowLength; @@ -7858,9 +7967,10 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( PalDevice* device, void* ptr, void* srcData, - PalBufferImageCopyInfo* copyInfo, - Uint32 imageFormatSize) + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo) { + Uint32 imageFormatSize = getFormatSizeVk(imageFormat); if (copyInfo->bufferRowLength == 0 && copyInfo->bufferImageHeight == 0) { Uint64 size = copyInfo->imageWidth * copyInfo->imageHeight * copyInfo->imageDepth; // normal path. Simple memcpy works diff --git a/tests/tests_main.c b/tests/tests_main.c index d7e9a0d3..88a7373f 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,16 +57,16 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest); + // registerTest(graphicsTest); registerTest(computeTest); - registerTest(rayTracingTest); + // registerTest(rayTracingTest); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest(clearColorTest); - registerTest(triangleTest); - registerTest(meshTest); - registerTest(textureTest); + // registerTest(clearColorTest); + // registerTest(triangleTest); + // registerTest(meshTest); + // registerTest(textureTest); #endif // runTests(); diff --git a/tests/texture_test.c b/tests/texture_test.c index 6e99bfdb..14c66161 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -663,8 +663,8 @@ bool textureTest() device, data, texture, - &bufferImageCopyInfo, - imageCreateInfo.format); + imageCreateInfo.format, + &bufferImageCopyInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); From 4d65b3279f48546b78f8414fff36d0cad7d01fd4 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 8 Apr 2026 03:13:53 +0000 Subject: [PATCH 152/372] add more command buffer recording commands d3d12 --- include/pal/pal_graphics.h | 4 +- src/graphics/pal_d3d12.c | 1101 ++++++++++++++++++++++++----------- src/graphics/pal_graphics.c | 13 +- src/graphics/pal_vulkan.c | 8 +- tests/texture_test.c | 10 +- tests/triangle_test.c | 10 +- 6 files changed, 781 insertions(+), 365 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index e9f92e1f..4634c4c8 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1299,7 +1299,6 @@ typedef enum { PAL_USAGE_STATE_UNDEFINED, PAL_USAGE_STATE_PRESENT, - PAL_USAGE_STATE_COLOR_ATTACHMENT_READ, PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE, PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ, PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE, @@ -3345,6 +3344,7 @@ typedef struct { PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, + Uint32* strides, PalBuffer** buffers, Uint64* offsets); @@ -5812,6 +5812,7 @@ PAL_API PalResult PAL_CALL palCmdSetScissors( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] firstSlot Index of the first vertex buffer binding slot. * @param[in] count Number of vertex buffers to bind. + * @param[in] strides Pointer to an array of strides for each vertex buffer. * @param[in] buffers Pointer to an array of vertex buffers. * @param[in] offsets Pointer to an array of offsets in bytes into each vertex buffer. * @@ -5827,6 +5828,7 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, + Uint32* strides, PalBuffer** buffers, Uint64* offsets); diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 0283ba44..a0b3c0f9 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -209,6 +209,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + Uint64 size; ID3D12Resource* handle; } Buffer; @@ -222,7 +223,13 @@ typedef struct { ID3D12Resource* handle; } AccelerationStructure; -static D3D12 s_D3D12 = {0}; +typedef struct { + const PalGraphicsBackend* backend; + + void* handle; +} Pipeline; + +static D3D12 s_D3D = {0}; // ================================================== // Helper Functions @@ -679,11 +686,11 @@ static CommandBufferData* getFreeCmdBufferData(CommandPool* pool) int count = pool->size * 2; // double the size int freeIndex = pool->size + 1; - data = palAllocate(s_D3D12.allocator, sizeof(CommandBufferData) * count, 0); + data = palAllocate(s_D3D.allocator, sizeof(CommandBufferData) * count, 0); if (data) { memcpy(data, pool->cmdBuffersData, pool->size * sizeof(CommandBufferData)); - palFree(s_D3D12.allocator, pool->cmdBuffersData); + palFree(s_D3D.allocator, pool->cmdBuffersData); pool->cmdBuffersData = data; pool->size = count; @@ -1045,6 +1052,102 @@ static inline Uint32 alignD3D12( return (value + alignment - 1) & ~(alignment - 1); } +static D3D12_RESOURCE_STATES barrierToD3D12( + Uint32 stageCount, + PalUsageState state, + PalShaderStage* shaderStages) +{ + switch (state) { + case PAL_USAGE_STATE_UNDEFINED: { + return D3D12_RESOURCE_STATE_COMMON; + } + + case PAL_USAGE_STATE_PRESENT: { + return D3D12_RESOURCE_STATE_PRESENT; + } + + case PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE: { + return D3D12_RESOURCE_STATE_RENDER_TARGET; + } + + case PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ: + case PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ: { + return D3D12_RESOURCE_STATE_DEPTH_READ; + } + + case PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE: + case PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE: { + return D3D12_RESOURCE_STATE_DEPTH_WRITE; + } + + case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ: { + return D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE; + } + + case PAL_USAGE_STATE_TRANSFER_READ: { + return D3D12_RESOURCE_STATE_COPY_SOURCE; + } + + case PAL_USAGE_STATE_TRANSFER_WRITE: { + return D3D12_RESOURCE_STATE_COPY_DEST; + } + + case PAL_USAGE_STATE_VERTEX_READ: { + return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; + } + + case PAL_USAGE_STATE_INDEX_READ: { + return D3D12_RESOURCE_STATE_INDEX_BUFFER; + } + + case PAL_USAGE_STATE_UNIFORM_READ: { + return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; + } + + case PAL_USAGE_STATE_SHADER_READ: { + // TODO: continue + return 0; + } + + case PAL_USAGE_STATE_SHADER_WRITE: { + // TODO: continue + return 0; + } + + case PAL_USAGE_STATE_STORAGE_READ: { + // TODO: continue + return 0; + } + + case PAL_USAGE_STATE_STORAGE_WRITE: { + // TODO: continue + return 0; + } + + case PAL_USAGE_STATE_HOST_READ: { + // TODO: continue + return 0; + } + + case PAL_USAGE_STATE_HOST_WRITE: { + // TODO: continue + return 0; + } + + case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: { + // TODO: continue + return 0; + } + + case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE: { + // TODO: continue + return 0; + } + } + + return D3D12_RESOURCE_STATE_COMMON; +} + // ================================================== // Adapter // ================================================== @@ -1054,80 +1157,80 @@ PalResult PAL_CALL initGraphicsD3D12( const PalAllocator* allocator) { // load d3d12 - s_D3D12.handle = LoadLibraryA("d3d12.dll"); - s_D3D12.dxgi = LoadLibraryA("dxgi.dll"); - if (!s_D3D12.handle || !s_D3D12.dxgi) { + s_D3D.handle = LoadLibraryA("d3d12.dll"); + s_D3D.dxgi = LoadLibraryA("dxgi.dll"); + if (!s_D3D.handle || !s_D3D.dxgi) { return PAL_RESULT_PLATFORM_FAILURE; } // clang-format off - s_D3D12.createDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress( - s_D3D12.handle, + s_D3D.createDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress( + s_D3D.handle, "D3D12CreateDevice"); - s_D3D12.createDXGIFactory = (PFN_CreateDXGIFactory2)GetProcAddress( - s_D3D12.dxgi, + s_D3D.createDXGIFactory = (PFN_CreateDXGIFactory2)GetProcAddress( + s_D3D.dxgi, "CreateDXGIFactory2"); if (debugger && debugger->callback) { - s_D3D12.getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress( - s_D3D12.handle, + s_D3D.getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress( + s_D3D.handle, "D3D12GetDebugInterface"); - if (s_D3D12.getDebugInterface) { + if (s_D3D.getDebugInterface) { HRESULT hr; - hr = s_D3D12.getDebugInterface(&IID_Debug, (void**)&s_D3D12.debugController); + hr = s_D3D.getDebugInterface(&IID_Debug, (void**)&s_D3D.debugController); if (SUCCEEDED(hr)) { - s_D3D12.debugController->lpVtbl->EnableDebugLayer(s_D3D12.debugController); + s_D3D.debugController->lpVtbl->EnableDebugLayer(s_D3D.debugController); } - hr = s_D3D12.getDebugInterface(&IID_Debug1, (void**)&s_D3D12.debugController1); + hr = s_D3D.getDebugInterface(&IID_Debug1, (void**)&s_D3D.debugController1); if (SUCCEEDED(hr)) { - s_D3D12.debugController1->lpVtbl->SetEnableGPUBasedValidation( - s_D3D12.debugController1, + s_D3D.debugController1->lpVtbl->SetEnableGPUBasedValidation( + s_D3D.debugController1, TRUE); } - s_D3D12.debugLayer = true; + s_D3D.debugLayer = true; } } // clang-format on - s_D3D12.factory = nullptr; - s_D3D12.adapters = nullptr; - s_D3D12.adapterCount = 0; - HRESULT result = s_D3D12.createDXGIFactory(0, &IID_Factory, (void**)&s_D3D12.factory); + s_D3D.factory = nullptr; + s_D3D.adapters = nullptr; + s_D3D.adapterCount = 0; + HRESULT result = s_D3D.createDXGIFactory(0, &IID_Factory, (void**)&s_D3D.factory); if (FAILED(result)) { return PAL_RESULT_PLATFORM_FAILURE; } - s_D3D12.allocator = allocator; + s_D3D.allocator = allocator; return PAL_RESULT_SUCCESS; } void PAL_CALL shutdownGraphicsD3D12() { - if (s_D3D12.debugController) { - s_D3D12.debugController->lpVtbl->Release(s_D3D12.debugController); + if (s_D3D.debugController) { + s_D3D.debugController->lpVtbl->Release(s_D3D.debugController); } - if (s_D3D12.debugController1) { - s_D3D12.debugController1->lpVtbl->Release(s_D3D12.debugController1); + if (s_D3D.debugController1) { + s_D3D.debugController1->lpVtbl->Release(s_D3D.debugController1); } - for (int i = 0; i < s_D3D12.adapterCount; i++) { - s_D3D12.adapters[i].handle->lpVtbl->Release(s_D3D12.adapters[i].handle); + for (int i = 0; i < s_D3D.adapterCount; i++) { + s_D3D.adapters[i].handle->lpVtbl->Release(s_D3D.adapters[i].handle); } - s_D3D12.factory->lpVtbl->Release(s_D3D12.factory); - FreeLibrary(s_D3D12.handle); - FreeLibrary(s_D3D12.dxgi); + s_D3D.factory->lpVtbl->Release(s_D3D.factory); + FreeLibrary(s_D3D.handle); + FreeLibrary(s_D3D.dxgi); - if (s_D3D12.adapters) { - palFree(s_D3D12.allocator, s_D3D12.adapters); + if (s_D3D.adapters) { + palFree(s_D3D.allocator, s_D3D.adapters); } - memset(&s_D3D12, 0, sizeof(s_D3D12)); + memset(&s_D3D, 0, sizeof(s_D3D)); } PalResult PAL_CALL enumerateAdaptersD3D12( @@ -1148,12 +1251,12 @@ PalResult PAL_CALL enumerateAdaptersD3D12( D3D_FEATURE_LEVEL_11_0 }; - if (s_D3D12.adapters) { - palFree(s_D3D12.allocator, s_D3D12.adapters); + if (s_D3D.adapters) { + palFree(s_D3D.allocator, s_D3D.adapters); } - while (SUCCEEDED(s_D3D12.factory->lpVtbl->EnumAdapters( - s_D3D12.factory, + while (SUCCEEDED(s_D3D.factory->lpVtbl->EnumAdapters( + s_D3D.factory, adapterCount, &adapter))) { if (outAdapters) { @@ -1166,7 +1269,7 @@ PalResult PAL_CALL enumerateAdaptersD3D12( // capabilities etc. ID3D12Device* device = nullptr; for (int i = 0; i < 5; i++) { - HRESULT result = s_D3D12.createDevice( + HRESULT result = s_D3D.createDevice( (IUnknown*)tmp, levels[i], &IID_Device, @@ -1184,20 +1287,20 @@ PalResult PAL_CALL enumerateAdaptersD3D12( } if (outAdapters) { - s_D3D12.adapters = palAllocate(s_D3D12.allocator, sizeof(Adapter) * adapterCount, 0); - if (!s_D3D12.adapters) { + s_D3D.adapters = palAllocate(s_D3D.allocator, sizeof(Adapter) * adapterCount, 0); + if (!s_D3D.adapters) { return PAL_RESULT_OUT_OF_MEMORY; } // fill the array with Adapter structs for (int i = 0; i < *count; i++) { - Adapter* tmp = &s_D3D12.adapters[i]; + Adapter* tmp = &s_D3D.adapters[i]; tmp->handle = dxAdapters[i]; tmp->tmpDevice = devices[i]; tmp->level = deviceLevels[i]; outAdapters[i] = (PalAdapter*)tmp; } - s_D3D12.adapterCount = *count; + s_D3D.adapterCount = *count; } else { *count = adapterCount; @@ -1210,11 +1313,11 @@ PalResult PAL_CALL getAdapterInfoD3D12( PalAdapter* adapter, PalAdapterInfo* info) { - Adapter* d3d12Adapter = (Adapter*)adapter; - IDXGIAdapter4* adapterHandle = d3d12Adapter->handle; + Adapter* d3dAdapter = (Adapter*)adapter; + IDXGIAdapter4* adapterHandle = d3dAdapter->handle; DXGI_ADAPTER_DESC3 desc; D3D12_FEATURE_DATA_ARCHITECTURE1 arch = {0}; - ID3D12Device* device = d3d12Adapter->tmpDevice; + ID3D12Device* device = d3dAdapter->tmpDevice; HRESULT result = adapterHandle->lpVtbl->GetDesc3(adapterHandle, &desc); if (FAILED(result)) { @@ -1262,20 +1365,20 @@ PalResult PAL_CALL getAdapterInfoD3D12( info->vram = desc.DedicatedSystemMemory; } - info->version = d3d12Adapter->level; - if (d3d12Adapter->level == D3D_FEATURE_LEVEL_12_2) { + info->version = d3dAdapter->level; + if (d3dAdapter->level == D3D_FEATURE_LEVEL_12_2) { strcpy(info->versionString, "12_2"); - } else if (d3d12Adapter->level == D3D_FEATURE_LEVEL_12_1) { + } else if (d3dAdapter->level == D3D_FEATURE_LEVEL_12_1) { strcpy(info->versionString, "12_1"); - } else if (d3d12Adapter->level == D3D_FEATURE_LEVEL_12_0) { + } else if (d3dAdapter->level == D3D_FEATURE_LEVEL_12_0) { strcpy(info->versionString, "12_0"); - } else if (d3d12Adapter->level == D3D_FEATURE_LEVEL_11_1) { + } else if (d3dAdapter->level == D3D_FEATURE_LEVEL_11_1) { strcpy(info->versionString, "11_1"); - } else if (d3d12Adapter->level == D3D_FEATURE_LEVEL_11_0) { + } else if (d3dAdapter->level == D3D_FEATURE_LEVEL_11_0) { strcpy(info->versionString, "11_0"); } @@ -1338,10 +1441,10 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) { HRESULT result; - Adapter* d3d12Adapter = (Adapter*)adapter; - IDXGIAdapter4* adapterHandle = d3d12Adapter->handle; + Adapter* d3dAdapter = (Adapter*)adapter; + IDXGIAdapter4* adapterHandle = d3dAdapter->handle; PalAdapterFeatures features = 0; - ID3D12Device* device = d3d12Adapter->tmpDevice; + ID3D12Device* device = d3dAdapter->tmpDevice; D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {0}; @@ -1453,7 +1556,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; - if (d3d12Adapter->level >= D3D_FEATURE_LEVEL_12_0) { + if (d3dAdapter->level >= D3D_FEATURE_LEVEL_12_0) { features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; } return features; @@ -1470,29 +1573,29 @@ PalResult PAL_CALL createDeviceD3D12( { HRESULT result; Device* device = nullptr; - Adapter* d3d12Adapter = (Adapter*)adapter; + Adapter* d3dAdapter = (Adapter*)adapter; - device = palAllocate(s_D3D12.allocator, sizeof(Device), 0); + device = palAllocate(s_D3D.allocator, sizeof(Device), 0); if (!device) { return PAL_RESULT_OUT_OF_MEMORY; } memset(device, 0, sizeof(Device)); - result = s_D3D12.createDevice( - (IUnknown*)d3d12Adapter->handle, - d3d12Adapter->level, + result = s_D3D.createDevice( + (IUnknown*)d3dAdapter->handle, + d3dAdapter->level, &IID_Device, (void**)&device->handle); if (FAILED(result)) { - palFree(s_D3D12.allocator, device); + palFree(s_D3D.allocator, device); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } return PAL_RESULT_INVALID_DRIVER; } - if (s_D3D12.debugLayer) { + if (s_D3D.debugLayer) { result = device->handle->lpVtbl->QueryInterface( device->handle, &IID_InfoQueue, @@ -1615,7 +1718,7 @@ PalResult PAL_CALL createDeviceD3D12( } } - device->adapter = d3d12Adapter->handle; + device->adapter = d3dAdapter->handle; device->features = features; *outDevice = (PalDevice*)device; return PAL_RESULT_SUCCESS; @@ -1623,31 +1726,31 @@ PalResult PAL_CALL createDeviceD3D12( void PAL_CALL destroyDeviceD3D12(PalDevice* device) { - Device* d3d12Device = (Device*)device; + Device* d3dDevice = (Device*)device; - if (d3d12Device->meshSignature) { - d3d12Device->meshSignature->lpVtbl->Release(d3d12Device->meshSignature); + if (d3dDevice->meshSignature) { + d3dDevice->meshSignature->lpVtbl->Release(d3dDevice->meshSignature); } - if (d3d12Device->dispatchSignature) { - d3d12Device->dispatchSignature->lpVtbl->Release(d3d12Device->dispatchSignature); + if (d3dDevice->dispatchSignature) { + d3dDevice->dispatchSignature->lpVtbl->Release(d3dDevice->dispatchSignature); } - if (d3d12Device->drawIndexedSignature) { - d3d12Device->drawIndexedSignature->lpVtbl->Release(d3d12Device->drawIndexedSignature); + if (d3dDevice->drawIndexedSignature) { + d3dDevice->drawIndexedSignature->lpVtbl->Release(d3dDevice->drawIndexedSignature); } - if (d3d12Device->drawSignature) { - d3d12Device->drawSignature->lpVtbl->Release(d3d12Device->drawSignature); + if (d3dDevice->drawSignature) { + d3dDevice->drawSignature->lpVtbl->Release(d3dDevice->drawSignature); } - d3d12Device->queue->lpVtbl->Release(d3d12Device->queue); - d3d12Device->handle->lpVtbl->Release(d3d12Device->handle); - if (d3d12Device->infoQueue) { - d3d12Device->infoQueue->lpVtbl->Release(d3d12Device->infoQueue); + d3dDevice->queue->lpVtbl->Release(d3dDevice->queue); + d3dDevice->handle->lpVtbl->Release(d3dDevice->handle); + if (d3dDevice->infoQueue) { + d3dDevice->infoQueue->lpVtbl->Release(d3dDevice->infoQueue); } - palFree(s_D3D12.allocator, d3d12Device); + palFree(s_D3D.allocator, d3dDevice); } // ================================================== @@ -1662,7 +1765,7 @@ PalResult PAL_CALL allocateMemoryD3D12( PalMemory** outMemory) { HRESULT result; - Device* d3d12Device = (Device*)device; + Device* d3dDevice = (Device*)device; ID3D12Heap* memory = nullptr; D3D12_HEAP_DESC desc = {0}; @@ -1676,8 +1779,8 @@ PalResult PAL_CALL allocateMemoryD3D12( desc.Properties.Type = D3D12_HEAP_TYPE_UPLOAD; } - result = d3d12Device->handle->lpVtbl->CreateHeap( - d3d12Device->handle, + result = d3dDevice->handle->lpVtbl->CreateHeap( + d3dDevice->handle, &desc, &IID_Heap, (void**)&memory); @@ -1706,8 +1809,8 @@ PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( PalDevice* device, PalSamplerAnisotropyCapabilities* caps) { - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + Device* d3dDevice = (Device*)device; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -1719,8 +1822,8 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( PalDevice* device, PalDepthStencilCapabilities* caps) { - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + Device* d3dDevice = (Device*)device; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -1742,8 +1845,8 @@ PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + Device* d3dDevice = (Device*)device; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -1754,8 +1857,8 @@ PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X2] = true; D3D12_FEATURE_DATA_D3D12_OPTIONS6 options = {0}; - d3d12Device->handle->lpVtbl->CheckFeatureSupport( - d3d12Device->handle, + d3dDevice->handle->lpVtbl->CheckFeatureSupport( + d3dDevice->handle, D3D12_FEATURE_D3D12_OPTIONS6, &options, sizeof(options)); @@ -1790,8 +1893,8 @@ PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( PalDevice* device, PalMeshShaderCapabilities* caps) { - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + Device* d3dDevice = (Device*)device; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -1816,8 +1919,8 @@ PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( PalDevice* device, PalRayTracingCapabilities* caps) { - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + Device* d3dDevice = (Device*)device; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -1837,8 +1940,8 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( PalDevice* device, PalDescriptorIndexingCapabilities* caps) { - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { + Device* d3dDevice = (Device*)device; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -1871,7 +1974,7 @@ PalResult PAL_CALL createQueueD3D12( PalQueue** outQueue) { HRESULT result; - Device* d3d12Device = (Device*)device; + Device* d3dDevice = (Device*)device; Queue* queue = nullptr; D3D12_COMMAND_QUEUE_DESC desc = {0}; @@ -1892,19 +1995,19 @@ PalResult PAL_CALL createQueueD3D12( } } - queue = palAllocate(s_D3D12.allocator, sizeof(Queue), 0); + queue = palAllocate(s_D3D.allocator, sizeof(Queue), 0); if (!queue) { return PAL_RESULT_OUT_OF_MEMORY; } - result = d3d12Device->handle->lpVtbl->CreateCommandQueue( - d3d12Device->handle, + result = d3dDevice->handle->lpVtbl->CreateCommandQueue( + d3dDevice->handle, &desc, &IID_Queue, (void**)&queue->handle); if (FAILED(result)) { - palFree(s_D3D12.allocator, queue); + palFree(s_D3D.allocator, queue); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -1912,15 +2015,15 @@ PalResult PAL_CALL createQueueD3D12( } // create fence used for queue wait - result = d3d12Device->handle->lpVtbl->CreateFence( - d3d12Device->handle, + result = d3dDevice->handle->lpVtbl->CreateFence( + d3dDevice->handle, 0, 0, &IID_Fence, (void**)&queue->fence); if (FAILED(result)) { - palFree(s_D3D12.allocator, queue); + palFree(s_D3D.allocator, queue); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -1935,23 +2038,23 @@ PalResult PAL_CALL createQueueD3D12( void PAL_CALL destroyQueueD3D12(PalQueue* queue) { - Queue* d3d12Queue = (Queue*)queue; - d3d12Queue->fence->lpVtbl->Release(d3d12Queue->fence); - d3d12Queue->handle->lpVtbl->Release(d3d12Queue->handle); - palFree(s_D3D12.allocator, d3d12Queue); + Queue* d3dQueue = (Queue*)queue; + d3dQueue->fence->lpVtbl->Release(d3dQueue->fence); + d3dQueue->handle->lpVtbl->Release(d3dQueue->handle); + palFree(s_D3D.allocator, d3dQueue); } PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) { - Queue* d3d12Queue = (Queue*)queue; - ID3D12Fence* fence = d3d12Queue->fence; - d3d12Queue->fenceValue++; - fence->lpVtbl->Signal(fence, d3d12Queue->fenceValue); + Queue* d3dQueue = (Queue*)queue; + ID3D12Fence* fence = d3dQueue->fence; + d3dQueue->fenceValue++; + fence->lpVtbl->Signal(fence, d3dQueue->fenceValue); // wait on the fence if the submited work is not done - if (fence->lpVtbl->GetCompletedValue(fence) < d3d12Queue->fenceValue) { + if (fence->lpVtbl->GetCompletedValue(fence) < d3dQueue->fenceValue) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); - fence->lpVtbl->SetEventOnCompletion(fence, d3d12Queue->fenceValue, event); + fence->lpVtbl->SetEventOnCompletion(fence, d3dQueue->fenceValue, event); WaitForSingleObject(event, INFINITE); CloseHandle(event); } @@ -1962,8 +2065,8 @@ bool PAL_CALL canQueuePresentD3D12( PalQueue* queue, PalSurface* surface) { - Queue* d3d12Queue = (Queue*)queue; - if (d3d12Queue->type == PAL_QUEUE_TYPE_GRAPHICS) { + Queue* d3dQueue = (Queue*)queue; + if (d3dQueue->type == PAL_QUEUE_TYPE_GRAPHICS) { return true; // all graphics queues support presentation } return false; @@ -1980,8 +2083,8 @@ PalResult PAL_CALL enumerateFormatsD3D12( { Int32 fmtCount = 0; HRESULT result; - Adapter* d3d12Adapter = (Adapter*)adapter; - ID3D12Device* device = d3d12Adapter->tmpDevice; + Adapter* d3dAdapter = (Adapter*)adapter; + ID3D12Device* device = d3dAdapter->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; for (int i = 0; i < PAL_FORMAT_MAX; i++) { @@ -2052,8 +2155,8 @@ bool PAL_CALL isFormatSupportedD3D12( PalFormat format) { HRESULT result; - Adapter* d3d12Adapter = (Adapter*)adapter; - ID3D12Device* device = d3d12Adapter->tmpDevice; + Adapter* d3dAdapter = (Adapter*)adapter; + ID3D12Device* device = d3dAdapter->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; DXGI_FORMAT fmt = formatToD3D12(format); @@ -2080,8 +2183,8 @@ PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( PalFormat format) { HRESULT result; - Adapter* d3d12Adapter = (Adapter*)adapter; - ID3D12Device* device = d3d12Adapter->tmpDevice; + Adapter* d3dAdapter = (Adapter*)adapter; + ID3D12Device* device = d3dAdapter->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; DXGI_FORMAT fmt = formatToD3D12(format); @@ -2119,8 +2222,8 @@ PalImageViewUsages PAL_CALL queryFormatImageViewUsagesD3D12( PalFormat format) { HRESULT result; - Adapter* d3d12Adapter = (Adapter*)adapter; - ID3D12Device* device = d3d12Adapter->tmpDevice; + Adapter* d3dAdapter = (Adapter*)adapter; + ID3D12Device* device = d3dAdapter->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; DXGI_FORMAT fmt = formatToD3D12(format); @@ -2175,8 +2278,8 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( PalFormat format) { HRESULT result; - Adapter* d3d12Adapter = (Adapter*)adapter; - ID3D12Device* device = d3d12Adapter->tmpDevice; + Adapter* d3dAdapter = (Adapter*)adapter; + ID3D12Device* device = d3dAdapter->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; DXGI_FORMAT fmt = formatToD3D12(format); @@ -2248,9 +2351,9 @@ PalResult PAL_CALL createImageD3D12( { HRESULT result; Image* image = nullptr; - Device* d3d12Device = (Device*)device; + Device* d3dDevice = (Device*)device; - image = palAllocate(s_D3D12.allocator, sizeof(Image), 0); + image = palAllocate(s_D3D.allocator, sizeof(Image), 0); if (!image) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2294,27 +2397,27 @@ PalResult PAL_CALL createImageD3D12( image->info.sampleCount = info->sampleCount; image->info.width = info->width; - image->device = d3d12Device->handle; + image->device = d3dDevice->handle; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyImageD3D12(PalImage* image) { - Image* d3d12Image = (Image*)image; + Image* d3dImage = (Image*)image; // check if memory has been attached to the image - if (d3d12Image->handle) { - d3d12Image->handle->lpVtbl->Release(d3d12Image->handle); + if (d3dImage->handle) { + d3dImage->handle->lpVtbl->Release(d3dImage->handle); } - palFree(s_D3D12.allocator, d3d12Image); + palFree(s_D3D.allocator, d3dImage); } PalResult PAL_CALL getImageInfoD3D12( PalImage* image, PalImageInfo* info) { - Image* d3d12Image = (Image*)image; - *info = d3d12Image->info; + Image* d3dImage = (Image*)image; + *info = d3dImage->info; return PAL_RESULT_SUCCESS; } @@ -2322,19 +2425,19 @@ PalResult PAL_CALL getImageMemoryRequirementsD3D12( PalImage* image, PalMemoryRequirements* requirements) { - Image* d3d12Image = (Image*)image; - if (d3d12Image->belongsToSwapchain) { + Image* d3dImage = (Image*)image; + if (d3dImage->belongsToSwapchain) { return PAL_RESULT_INVALID_OPERATION; } D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; - allocationInfo = *d3d12Image->device->lpVtbl->GetResourceAllocationInfo( - d3d12Image->device, + allocationInfo = *d3dImage->device->lpVtbl->GetResourceAllocationInfo( + d3dImage->device, &__ret, 0, 1, - &d3d12Image->desc); + &d3dImage->desc); // d3d12 allows images to be used with only GPU only heap requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; @@ -2352,21 +2455,21 @@ PalResult PAL_CALL bindImageMemoryD3D12( Uint64 offset) { HRESULT result; - Image* d3d12Image = (Image*)image; - if (d3d12Image->belongsToSwapchain) { + Image* d3dImage = (Image*)image; + if (d3dImage->belongsToSwapchain) { return PAL_RESULT_INVALID_OPERATION; } ID3D12Heap* mem = (ID3D12Heap*)memory; - result = d3d12Image->device->lpVtbl->CreatePlacedResource( - d3d12Image->device, + result = d3dImage->device->lpVtbl->CreatePlacedResource( + d3dImage->device, mem, offset, - &d3d12Image->desc, + &d3dImage->desc, 0, nullptr, &IID_Resource, - (void**)d3d12Image->handle); + (void**)d3dImage->handle); if (FAILED(result)) { if (result == E_OUTOFMEMORY) { @@ -2406,16 +2509,16 @@ PalResult PAL_CALL createImageViewD3D12( { HRESULT result; ImageView* imageView = nullptr; - Device* d3d12Device = (Device*)device; - Image* d3d12Image = (Image*)image; + Device* d3dDevice = (Device*)device; + Image* d3dImage = (Image*)image; if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } - imageView = palAllocate(s_D3D12.allocator, sizeof(ImageView), 0); + imageView = palAllocate(s_D3D.allocator, sizeof(ImageView), 0); if (!imageView) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2423,7 +2526,7 @@ PalResult PAL_CALL createImageViewD3D12( memset(imageView, 0, sizeof(ImageView)); imageView->type = info->type; imageView->usages = info->usages; - imageView->image = d3d12Image; + imageView->image = d3dImage; *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; @@ -2431,8 +2534,8 @@ PalResult PAL_CALL createImageViewD3D12( void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) { - ImageView* d3d12ImageView = (ImageView*)imageView; - palFree(s_D3D12.allocator, d3d12ImageView); + ImageView* d3dImageView = (ImageView*)imageView; + palFree(s_D3D.allocator, d3dImageView); } // ================================================== @@ -2445,7 +2548,7 @@ PalResult PAL_CALL createSamplerD3D12( PalSampler** outSampler) { Sampler* sampler = nullptr; - sampler = palAllocate(s_D3D12.allocator, sizeof(Sampler), 0); + sampler = palAllocate(s_D3D.allocator, sizeof(Sampler), 0); if (!sampler) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2481,8 +2584,8 @@ PalResult PAL_CALL createSamplerD3D12( void PAL_CALL destroySamplerD3D12(PalSampler* sampler) { - Sampler* d3d12Sampler = (Sampler*)sampler; - palFree(s_D3D12.allocator, d3d12Sampler); + Sampler* d3dSampler = (Sampler*)sampler; + palFree(s_D3D.allocator, d3dSampler); } // ================================================== @@ -2494,13 +2597,13 @@ PalResult PAL_CALL createSurfaceD3D12( PalGraphicsWindow* window, PalSurface** outSurface) { - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + Device* d3dDevice = (Device*)device; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } Surface* surface = nullptr; - surface = palAllocate(s_D3D12.allocator, sizeof(Surface), 0); + surface = palAllocate(s_D3D.allocator, sizeof(Surface), 0); if (!surface) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2517,8 +2620,8 @@ PalResult PAL_CALL createSurfaceD3D12( void PAL_CALL destroySurfaceD3D12(PalSurface* surface) { - Surface* d3d12Surface = (Surface*)surface; - palFree(s_D3D12.allocator, d3d12Surface); + Surface* d3dSurface = (Surface*)surface; + palFree(s_D3D.allocator, d3dSurface); } PalResult PAL_CALL getSurfaceCapabilitiesD3D12( @@ -2527,13 +2630,13 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( PalSurfaceCapabilities* caps) { HRESULT result; - Surface* d3d12Surface = (Surface*)surface; - Device* d3d12Device = (Device*)device; + Surface* d3dSurface = (Surface*)surface; + Device* d3dDevice = (Device*)device; bool supportHDR10 = false; IDXGISwapChain1* swapchain1 = nullptr; IDXGISwapChain3* swapchain3 = nullptr; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -2545,10 +2648,10 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( desc.BufferCount = 1; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( - s_D3D12.factory, - (IUnknown*)d3d12Device->queue, - d3d12Surface->handle, + result = s_D3D.factory->lpVtbl->CreateSwapChainForHwnd( + s_D3D.factory, + (IUnknown*)d3dDevice->queue, + d3dSurface->handle, &desc, nullptr, nullptr, @@ -2576,8 +2679,8 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( } BOOL allowTearing = FALSE; - s_D3D12.factory->lpVtbl->CheckFeatureSupport( - s_D3D12.factory, + s_D3D.factory->lpVtbl->CheckFeatureSupport( + s_D3D.factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing)); @@ -2621,8 +2724,8 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( for (int i = 0; i < PAL_SURFACE_FORMAT_MAX; i++) { formatSupport.Format = baseFormats[i]; - result = d3d12Device->handle->lpVtbl->CheckFeatureSupport( - d3d12Device->handle, + result = d3dDevice->handle->lpVtbl->CheckFeatureSupport( + d3dDevice->handle, D3D12_FEATURE_FORMAT_SUPPORT, &formatSupport, sizeof(formatSupport)); @@ -2665,17 +2768,17 @@ PalResult PAL_CALL createSwapchainD3D12( PalSwapchain** outSwapchain) { HRESULT result; - Surface* d3d12Surface = (Surface*)surface; - Device* d3d12Device = (Device*)device; - Queue* d3d12Queue = (Queue*)queue; + Surface* d3dSurface = (Surface*)surface; + Device* d3dDevice = (Device*)device; + Queue* d3dQueue = (Queue*)queue; Swapchain* swapchain = nullptr; bool isHDRColorspace = false; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - if (d3d12Queue->type != PAL_QUEUE_TYPE_GRAPHICS) { + if (d3dQueue->type != PAL_QUEUE_TYPE_GRAPHICS) { return PAL_RESULT_INVALID_QUEUE; } @@ -2688,7 +2791,7 @@ PalResult PAL_CALL createSwapchainD3D12( return PAL_RESULT_INVALID_ARGUMENT; } - swapchain = palAllocate(s_D3D12.allocator, sizeof(Swapchain), 0); + swapchain = palAllocate(s_D3D.allocator, sizeof(Swapchain), 0); if (!swapchain) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2741,10 +2844,10 @@ PalResult PAL_CALL createSwapchainD3D12( swapchain->format = desc.Format; swapchain->flags = desc.Flags; - result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( - s_D3D12.factory, - (IUnknown*)d3d12Queue->handle, - d3d12Surface->handle, + result = s_D3D.factory->lpVtbl->CreateSwapChainForHwnd( + s_D3D.factory, + (IUnknown*)d3dQueue->handle, + d3dSurface->handle, &desc, nullptr, nullptr, @@ -2773,7 +2876,7 @@ PalResult PAL_CALL createSwapchainD3D12( // get and cache swapchain images swapchain->images = nullptr; - swapchain->images = palAllocate(s_D3D12.allocator, sizeof(Image) * info->imageCount, 0); + swapchain->images = palAllocate(s_D3D.allocator, sizeof(Image) * info->imageCount, 0); if (!swapchain->imageCount) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2785,7 +2888,7 @@ PalResult PAL_CALL createSwapchainD3D12( Image* image = &swapchain->images[i]; image->belongsToSwapchain = true; - image->device = d3d12Device->handle; + image->device = d3dDevice->handle; image->handle = tmp; image->info.depthOrArraySize = 1; // always 1 @@ -2800,11 +2903,11 @@ PalResult PAL_CALL createSwapchainD3D12( // get and cache window size for swapchain out of date error RECT windowRect; - GetClientRect((HWND)d3d12Surface->handle, &windowRect); + GetClientRect((HWND)d3dSurface->handle, &windowRect); swapchain->windowWidth = windowRect.right - windowRect.left; swapchain->windowWidth = windowRect.bottom - windowRect.top; - swapchain->queue = d3d12Queue->handle; + swapchain->queue = d3dQueue->handle; swapchain->imageCount = info->imageCount; *outSwapchain = (PalSwapchain*)swapchain; return PAL_RESULT_SUCCESS; @@ -2812,21 +2915,21 @@ PalResult PAL_CALL createSwapchainD3D12( void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) { - Swapchain* d3d12Swapchain = (Swapchain*)swapchain; - d3d12Swapchain->handle->lpVtbl->Release(d3d12Swapchain->handle); - palFree(s_D3D12.allocator, d3d12Swapchain->images); - palFree(s_D3D12.allocator, d3d12Swapchain); + Swapchain* d3dSwapchain = (Swapchain*)swapchain; + d3dSwapchain->handle->lpVtbl->Release(d3dSwapchain->handle); + palFree(s_D3D.allocator, d3dSwapchain->images); + palFree(s_D3D.allocator, d3dSwapchain); } PalImage* PAL_CALL getSwapchainImageD3D12( PalSwapchain* swapchain, Int32 index) { - Swapchain* d3d12Swapchain = (Swapchain*)swapchain; - if (index > d3d12Swapchain->imageCount) { + Swapchain* d3dSwapchain = (Swapchain*)swapchain; + if (index > d3dSwapchain->imageCount) { return nullptr; } - return (PalImage*)&d3d12Swapchain->images[index]; + return (PalImage*)&d3dSwapchain->images[index]; } PalResult PAL_CALL getNextSwapchainImageD3D12( @@ -2835,10 +2938,10 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( Uint32* outIndex) { Uint32 index = 0; - Swapchain* d3d12Swapchain = (Swapchain*)swapchain; - ID3D12CommandQueue* queue = d3d12Swapchain->queue; + Swapchain* d3dSwapchain = (Swapchain*)swapchain; + ID3D12CommandQueue* queue = d3dSwapchain->queue; - index = d3d12Swapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3d12Swapchain->handle); + index = d3dSwapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3dSwapchain->handle); if (info->fence) { Fence* fence = (Fence*)info->fence; fence->value++; @@ -2864,8 +2967,8 @@ PalResult PAL_CALL presentSwapchainD3D12( PalSwapchainPresentInfo* info) { HRESULT result; - Swapchain* d3d12Swapchain = (Swapchain*)swapchain; - ID3D12CommandQueue* queue = d3d12Swapchain->queue; + Swapchain* d3dSwapchain = (Swapchain*)swapchain; + ID3D12CommandQueue* queue = d3dSwapchain->queue; if (info->waitSemaphore) { Semaphore* semaphore = (Semaphore*)info->waitSemaphore; @@ -2878,10 +2981,10 @@ PalResult PAL_CALL presentSwapchainD3D12( } } - result = d3d12Swapchain->handle->lpVtbl->Present( - d3d12Swapchain->handle, - d3d12Swapchain->syncInterval, - d3d12Swapchain->presentFlags); + result = d3dSwapchain->handle->lpVtbl->Present( + d3dSwapchain->handle, + d3dSwapchain->syncInterval, + d3dSwapchain->presentFlags); if (FAILED(result)) { if (result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET) { @@ -2891,7 +2994,7 @@ PalResult PAL_CALL presentSwapchainD3D12( // check if swapchain needs to be resize RECT windowRect; Uint32 w, h; - bool ret = GetClientRect((HWND)d3d12Swapchain->surface->handle, &windowRect); + bool ret = GetClientRect((HWND)d3dSwapchain->surface->handle, &windowRect); w = windowRect.right - windowRect.left; w = windowRect.bottom - windowRect.top; @@ -2899,7 +3002,7 @@ PalResult PAL_CALL presentSwapchainD3D12( return PAL_RESULT_SURFACE_LOST; } - if (w != d3d12Swapchain->windowWidth || h != d3d12Swapchain->windowHeight) { + if (w != d3dSwapchain->windowWidth || h != d3dSwapchain->windowHeight) { return PAL_RESULT_SWAPCHAIN_OUT_OF_DATE; } return PAL_RESULT_PLATFORM_FAILURE; @@ -2914,14 +3017,14 @@ PalResult PAL_CALL resizeSwapchainD3D12( Uint32 newHeight) { HRESULT result; - Swapchain* d3d12Swapchain = (Swapchain*)swapchain; - result = d3d12Swapchain->handle->lpVtbl->ResizeBuffers( - d3d12Swapchain->handle, - d3d12Swapchain->imageCount, + Swapchain* d3dSwapchain = (Swapchain*)swapchain; + result = d3dSwapchain->handle->lpVtbl->ResizeBuffers( + d3dSwapchain->handle, + d3dSwapchain->imageCount, newWidth, newHeight, - d3d12Swapchain->format, - d3d12Swapchain->flags); + d3dSwapchain->format, + d3dSwapchain->flags); if (FAILED(result)) { if (result == E_INVALIDARG) { @@ -2931,15 +3034,15 @@ PalResult PAL_CALL resizeSwapchainD3D12( } // fill all images with the creatio info - for (int i = 0; i < d3d12Swapchain->imageCount; i++) { + for (int i = 0; i < d3dSwapchain->imageCount; i++) { ID3D12Resource* tmp = nullptr; - d3d12Swapchain->handle->lpVtbl->GetBuffer( - d3d12Swapchain->handle, + d3dSwapchain->handle->lpVtbl->GetBuffer( + d3dSwapchain->handle, i, &IID_Resource, (void**)&tmp); - Image* image = &d3d12Swapchain->images[i]; + Image* image = &d3dSwapchain->images[i]; image->handle = tmp; image->info.height = newHeight; image->info.width = newWidth; @@ -2947,13 +3050,13 @@ PalResult PAL_CALL resizeSwapchainD3D12( // get and cache window size for swapchain out of date error RECT windowRect; - Surface* surface = d3d12Swapchain->surface; + Surface* surface = d3dSwapchain->surface; if (!GetClientRect((HWND)surface->handle, &windowRect)) { return PAL_RESULT_SURFACE_LOST; } - d3d12Swapchain->windowWidth = windowRect.right - windowRect.left; - d3d12Swapchain->windowWidth = windowRect.bottom - windowRect.top; + d3dSwapchain->windowWidth = windowRect.right - windowRect.left; + d3dSwapchain->windowWidth = windowRect.bottom - windowRect.top; return PAL_RESULT_SUCCESS; } @@ -2966,11 +3069,11 @@ PalResult PAL_CALL createShaderD3D12( const PalShaderCreateInfo* info, PalShader** outShader) { - Device* d3d12Device = (Device*)device; + Device* d3dDevice = (Device*)device; Shader* shader = nullptr; if (info->stage == PAL_SHADER_STAGE_MESH || info->stage == PAL_SHADER_STAGE_TASK) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -2981,13 +3084,13 @@ PalResult PAL_CALL createShaderD3D12( info->stage == PAL_SHADER_STAGE_MISS || info->stage == PAL_SHADER_STAGE_INTERSECTION || info->stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } // clang-format on - shader = palAllocate(s_D3D12.allocator, sizeof(Shader), 0); + shader = palAllocate(s_D3D.allocator, sizeof(Shader), 0); if (!shader) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3001,8 +3104,8 @@ PalResult PAL_CALL createShaderD3D12( void PAL_CALL destroyShaderD3D12(PalShader* shader) { - Shader* d3d12Shader = (Shader*)shader; - palFree(s_D3D12.allocator, d3d12Shader); + Shader* d3dShader = (Shader*)shader; + palFree(s_D3D.allocator, d3dShader); } // ================================================== @@ -3015,23 +3118,23 @@ PalResult PAL_CALL createFenceD3D12( PalFence** outFence) { HRESULT result; - Device* d3d12Device = (Device*)device; + Device* d3dDevice = (Device*)device; Fence* fence = nullptr; - fence = palAllocate(s_D3D12.allocator, sizeof(Fence), 0); + fence = palAllocate(s_D3D.allocator, sizeof(Fence), 0); if (!fence) { return PAL_RESULT_OUT_OF_MEMORY; } - result = d3d12Device->handle->lpVtbl->CreateFence( - d3d12Device->handle, + result = d3dDevice->handle->lpVtbl->CreateFence( + d3dDevice->handle, 0, 0, &IID_Fence, (void**)&fence->handle); if (FAILED(result)) { - palFree(s_D3D12.allocator, fence); + palFree(s_D3D.allocator, fence); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3039,7 +3142,7 @@ PalResult PAL_CALL createFenceD3D12( } fence->canReset = false; - if (d3d12Device->features & PAL_ADAPTER_FEATURE_FENCE_RESET) { + if (d3dDevice->features & PAL_ADAPTER_FEATURE_FENCE_RESET) { fence->canReset = true; } @@ -3051,9 +3154,9 @@ PalResult PAL_CALL createFenceD3D12( void PAL_CALL destroyFenceD3D12(PalFence* fence) { - Fence* d3d12Fence = (Fence*)fence; - d3d12Fence->handle->lpVtbl->Release(d3d12Fence->handle); - palFree(s_D3D12.allocator, d3d12Fence); + Fence* d3dFence = (Fence*)fence; + d3dFence->handle->lpVtbl->Release(d3dFence->handle); + palFree(s_D3D.allocator, d3dFence); } PalResult PAL_CALL waitFenceD3D12( @@ -3061,14 +3164,14 @@ PalResult PAL_CALL waitFenceD3D12( Uint64 timeout) { HRESULT result; - Fence* d3d12Fence = (Fence*)fence; + Fence* d3dFence = (Fence*)fence; DWORD ret = 0; - Uint64 value = d3d12Fence->value; + Uint64 value = d3dFence->value; - if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) < value) { + if (d3dFence->handle->lpVtbl->GetCompletedValue(d3dFence->handle) < value) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); - result = d3d12Fence->handle->lpVtbl->SetEventOnCompletion( - d3d12Fence->handle, + result = d3dFence->handle->lpVtbl->SetEventOnCompletion( + d3dFence->handle, value, event); @@ -3096,20 +3199,20 @@ PalResult PAL_CALL waitFenceD3D12( PalResult PAL_CALL resetFenceD3D12(PalFence* fence) { - Fence* d3d12Fence = (Fence*)fence; - if (!d3d12Fence->canReset) { + Fence* d3dFence = (Fence*)fence; + if (!d3dFence->canReset) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - d3d12Fence->handle->lpVtbl->Signal(d3d12Fence->handle, 0); - d3d12Fence->value = 0; + d3dFence->handle->lpVtbl->Signal(d3dFence->handle, 0); + d3dFence->value = 0; return PAL_RESULT_SUCCESS; } bool PAL_CALL isFenceSignaledD3D12(PalFence* fence) { - Fence* d3d12Fence = (Fence*)fence; - if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) == 0) { + Fence* d3dFence = (Fence*)fence; + if (d3dFence->handle->lpVtbl->GetCompletedValue(d3dFence->handle) == 0) { return false; } return true; @@ -3124,23 +3227,23 @@ PalResult PAL_CALL createSemaphoreD3D12( PalSemaphore** outSemaphore) { HRESULT result; - Device* d3d12Device = (Device*)device; + Device* d3dDevice = (Device*)device; Semaphore* semaphore = nullptr; - semaphore = palAllocate(s_D3D12.allocator, sizeof(Semaphore), 0); + semaphore = palAllocate(s_D3D.allocator, sizeof(Semaphore), 0); if (!semaphore) { return PAL_RESULT_OUT_OF_MEMORY; } - result = d3d12Device->handle->lpVtbl->CreateFence( - d3d12Device->handle, + result = d3dDevice->handle->lpVtbl->CreateFence( + d3dDevice->handle, 0, 0, &IID_Fence, (void**)&semaphore->handle); if (FAILED(result)) { - palFree(s_D3D12.allocator, semaphore); + palFree(s_D3D.allocator, semaphore); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3148,7 +3251,7 @@ PalResult PAL_CALL createSemaphoreD3D12( } semaphore->isTimeline = false; - if (d3d12Device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + if (d3dDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { semaphore->isTimeline = true; } @@ -3160,9 +3263,9 @@ PalResult PAL_CALL createSemaphoreD3D12( void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore) { - Semaphore* d3d12Semaphore = (Semaphore*)semaphore; - d3d12Semaphore->handle->lpVtbl->Release(d3d12Semaphore->handle); - palFree(s_D3D12.allocator, d3d12Semaphore); + Semaphore* d3dSemaphore = (Semaphore*)semaphore; + d3dSemaphore->handle->lpVtbl->Release(d3dSemaphore->handle); + palFree(s_D3D.allocator, d3dSemaphore); } PalResult PAL_CALL waitSemaphoreD3D12( @@ -3172,15 +3275,15 @@ PalResult PAL_CALL waitSemaphoreD3D12( { HRESULT result; DWORD ret = 0; - Semaphore* d3d12Semaphore = (Semaphore*)semaphore; - if (!d3d12Semaphore->isTimeline) { + Semaphore* d3dSemaphore = (Semaphore*)semaphore; + if (!d3dSemaphore->isTimeline) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - if (d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle) < value) { + if (d3dSemaphore->handle->lpVtbl->GetCompletedValue(d3dSemaphore->handle) < value) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); - result = d3d12Semaphore->handle->lpVtbl->SetEventOnCompletion( - d3d12Semaphore->handle, + result = d3dSemaphore->handle->lpVtbl->SetEventOnCompletion( + d3dSemaphore->handle, value, event); @@ -3210,12 +3313,12 @@ PalResult PAL_CALL signalSemaphoreD3D12( PalQueue* queue, Uint64 value) { - Semaphore* d3d12Semaphore = (Semaphore*)semaphore; - if (!d3d12Semaphore->isTimeline) { + Semaphore* d3dSemaphore = (Semaphore*)semaphore; + if (!d3dSemaphore->isTimeline) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - HRESULT result = d3d12Semaphore->handle->lpVtbl->Signal(d3d12Semaphore->handle, value); + HRESULT result = d3dSemaphore->handle->lpVtbl->Signal(d3dSemaphore->handle, value); if (FAILED(result)) { if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_SEMAPHORE; @@ -3229,12 +3332,12 @@ PalResult PAL_CALL getSemaphoreValueD3D12( PalSemaphore* semaphore, Uint64* outValue) { - Semaphore* d3d12Semaphore = (Semaphore*)semaphore; - if (!d3d12Semaphore->isTimeline) { + Semaphore* d3dSemaphore = (Semaphore*)semaphore; + if (!d3dSemaphore->isTimeline) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - UINT64 tmp = d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle); + UINT64 tmp = d3dSemaphore->handle->lpVtbl->GetCompletedValue(d3dSemaphore->handle); *outValue = tmp; return PAL_RESULT_SUCCESS; } @@ -3251,7 +3354,7 @@ PalResult PAL_CALL createCommandPoolD3D12( HRESULT result; CommandPool* pool = nullptr; - pool = palAllocate(s_D3D12.allocator, sizeof(CommandPool), 0); + pool = palAllocate(s_D3D.allocator, sizeof(CommandPool), 0); if (!pool) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3259,7 +3362,7 @@ PalResult PAL_CALL createCommandPoolD3D12( pool->size = 8; pool->cmdBuffersData = nullptr; Uint32 size = sizeof(CommandBufferData) * pool->size; - pool->cmdBuffersData = palAllocate(s_D3D12.allocator, size, 0); + pool->cmdBuffersData = palAllocate(s_D3D.allocator, size, 0); if (!pool->cmdBuffersData) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3282,8 +3385,8 @@ void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) cmdBuffer->allocator->lpVtbl->Release(cmdBuffer->allocator); } - palFree(s_D3D12.allocator, cmdPool->cmdBuffersData); - palFree(s_D3D12.allocator, cmdPool); + palFree(s_D3D.allocator, cmdPool->cmdBuffersData); + palFree(s_D3D.allocator, cmdPool); } PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool) @@ -3307,11 +3410,11 @@ PalResult PAL_CALL allocateCommandBufferD3D12( PalCommandBuffer** outCmdBuffer) { HRESULT result; - Device* d3d12Device = (Device*)device; + Device* d3dDevice = (Device*)device; CommandBuffer* cmdBuffer = nullptr; CommandPool* cmdPool = (CommandPool*)pool; - cmdBuffer = palAllocate(s_D3D12.allocator, sizeof(CommandBuffer), 0); + cmdBuffer = palAllocate(s_D3D.allocator, sizeof(CommandBuffer), 0); if (!cmdBuffer) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3324,8 +3427,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( } // create an allocator - result = d3d12Device->handle->lpVtbl->CreateCommandAllocator( - d3d12Device->handle, + result = d3dDevice->handle->lpVtbl->CreateCommandAllocator( + d3dDevice->handle, cmdBufferType, &IID_CmdAlloc, (void**)&cmdBuffer->allocator); @@ -3338,8 +3441,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( } // create the command list - result = d3d12Device->handle->lpVtbl->CreateCommandList( - d3d12Device->handle, + result = d3dDevice->handle->lpVtbl->CreateCommandList( + d3dDevice->handle, 0, cmdBufferType, cmdBuffer->allocator, @@ -3360,21 +3463,21 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdBuffer->handle6); cmdBuffer->pool = cmdPool; - cmdBuffer->device = d3d12Device; + cmdBuffer->device = d3dDevice; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; } void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) { - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; - CommandPool* pool = d3d12CmdBuffer->pool; - CommandBufferData* data = findCmdBufferData(pool, d3d12CmdBuffer); + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + CommandPool* pool = d3dCmdBuffer->pool; + CommandBufferData* data = findCmdBufferData(pool, d3dCmdBuffer); if (data) { - d3d12CmdBuffer->handle6->lpVtbl->Release(d3d12CmdBuffer->handle6); - d3d12CmdBuffer->handle->lpVtbl->Release(d3d12CmdBuffer->handle); - d3d12CmdBuffer->allocator->lpVtbl->Release(d3d12CmdBuffer->allocator); - palFree(s_D3D12.allocator, cmdBuffer); + d3dCmdBuffer->handle6->lpVtbl->Release(d3dCmdBuffer->handle6); + d3dCmdBuffer->handle->lpVtbl->Release(d3dCmdBuffer->handle); + d3dCmdBuffer->allocator->lpVtbl->Release(d3dCmdBuffer->allocator); + palFree(s_D3D.allocator, cmdBuffer); data->cmdBuffer = nullptr; data->used = false; @@ -3384,8 +3487,8 @@ void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) { HRESULT result; - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; - result = d3d12CmdBuffer->allocator->lpVtbl->Reset(d3d12CmdBuffer->allocator); + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + result = d3dCmdBuffer->allocator->lpVtbl->Reset(d3dCmdBuffer->allocator); if (FAILED(result)) { if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_COMMAND_BUFFER; @@ -3393,9 +3496,9 @@ PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) return PAL_RESULT_PLATFORM_FAILURE; } - d3d12CmdBuffer->handle->lpVtbl->Reset( - d3d12CmdBuffer->handle, - d3d12CmdBuffer->allocator, + d3dCmdBuffer->handle->lpVtbl->Reset( + d3dCmdBuffer->handle, + d3dCmdBuffer->allocator, nullptr); return PAL_RESULT_SUCCESS; @@ -3406,9 +3509,9 @@ PalResult PAL_CALL submitCommandBufferD3D12( PalCommandBufferSubmitInfo* info) { HRESULT result; - Queue* d3d12Queue = (Queue*)queue; - ID3D12CommandQueue* queueHandle = d3d12Queue->handle; - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)info->cmdBuffer; + Queue* d3dQueue = (Queue*)queue; + ID3D12CommandQueue* queueHandle = d3dQueue->handle; + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)info->cmdBuffer; // wait semaphore if (info->waitSemaphore) { @@ -3422,7 +3525,7 @@ PalResult PAL_CALL submitCommandBufferD3D12( } } - ID3D12CommandList* tmp = (ID3D12CommandList*)d3d12CmdBuffer->handle; + ID3D12CommandList* tmp = (ID3D12CommandList*)d3dCmdBuffer->handle; queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, &tmp); if (info->fence) { Fence* fence = (Fence*)info->fence; @@ -3456,8 +3559,8 @@ PalResult PAL_CALL cmdBeginD3D12( PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer) { - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; - d3d12CmdBuffer->handle->lpVtbl->Close(d3d12CmdBuffer->handle); + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + d3dCmdBuffer->handle->lpVtbl->Close(d3dCmdBuffer->handle); return PAL_RESULT_SUCCESS; } @@ -3465,12 +3568,12 @@ PalResult PAL_CALL cmdExecuteCommandBufferD3D12( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { - CommandBuffer* d3d12PrimaryCmdBuffer = (CommandBuffer*)primaryCmdBuffer; - CommandBuffer* d3d12SecondaryCmdBuffer = (CommandBuffer*)secondaryCmdBuffer; + CommandBuffer* d3dPrimaryCmdBuffer = (CommandBuffer*)primaryCmdBuffer; + CommandBuffer* d3dSecondaryCmdBuffer = (CommandBuffer*)secondaryCmdBuffer; - d3d12PrimaryCmdBuffer->handle->lpVtbl->ExecuteBundle( - d3d12PrimaryCmdBuffer->handle, - d3d12SecondaryCmdBuffer->handle); + d3dPrimaryCmdBuffer->handle->lpVtbl->ExecuteBundle( + d3dPrimaryCmdBuffer->handle, + d3dSecondaryCmdBuffer->handle); return PAL_RESULT_SUCCESS; } @@ -3480,8 +3583,8 @@ PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( PalFragmentShadingRateState* state) { HRESULT result; - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3d12CmdBuffer->device; + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3dCmdBuffer->device; if (!(device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3492,8 +3595,8 @@ PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); } - d3d12CmdBuffer->handle6->lpVtbl->RSSetShadingRate( - d3d12CmdBuffer->handle6, + d3dCmdBuffer->handle6->lpVtbl->RSSetShadingRate( + d3dCmdBuffer->handle6, shadingRate, combinerOps); @@ -3506,14 +3609,14 @@ PalResult PAL_CALL cmdDrawMeshTasksD3D12( Uint32 groupCountY, Uint32 groupCountZ) { - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3d12CmdBuffer->device; + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3dCmdBuffer->device; if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - d3d12CmdBuffer->handle6->lpVtbl->DispatchMesh( - d3d12CmdBuffer->handle6, + d3dCmdBuffer->handle6->lpVtbl->DispatchMesh( + d3dCmdBuffer->handle6, groupCountX, groupCountY, groupCountZ); @@ -3526,18 +3629,18 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( PalBuffer* buffer, Uint32 drawCount) { - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3d12CmdBuffer->device; + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3dCmdBuffer->device; if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Buffer* d3d12Buffer = (Buffer*)buffer; - d3d12CmdBuffer->handle6->lpVtbl->ExecuteIndirect( - d3d12CmdBuffer->handle6, + Buffer* d3dBuffer = (Buffer*)buffer; + d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle6, device->meshSignature, drawCount, - d3d12Buffer->handle, + d3dBuffer->handle, 0, nullptr, 0); @@ -3551,21 +3654,21 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( PalBuffer* countBuffer, Uint32 maxDrawCount) { - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3d12CmdBuffer->device; + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3dCmdBuffer->device; if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Buffer* d3d12Buffer = (Buffer*)buffer; - Buffer* d3d12CountBuffer = (Buffer*)countBuffer; - d3d12CmdBuffer->handle6->lpVtbl->ExecuteIndirect( - d3d12CmdBuffer->handle6, + Buffer* d3dBuffer = (Buffer*)buffer; + Buffer* d3dCountBuffer = (Buffer*)countBuffer; + d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle6, device->meshSignature, maxDrawCount, - d3d12Buffer->handle, + d3dBuffer->handle, 0, - d3d12CountBuffer->handle, + d3dCountBuffer->handle, 0); return PAL_RESULT_SUCCESS; @@ -3575,8 +3678,8 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3d12CmdBuffer->device; + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3dCmdBuffer->device; if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3593,7 +3696,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { geometries = palAllocate( - s_D3D12.allocator, + s_D3D.allocator, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount, 0); @@ -3609,9 +3712,9 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( dstAs->address, &buildInfo); - palFree(s_D3D12.allocator, geometries); - d3d12CmdBuffer->handle6->lpVtbl->BuildRaytracingAccelerationStructure( - d3d12CmdBuffer->handle6, + palFree(s_D3D.allocator, geometries); + d3dCmdBuffer->handle6->lpVtbl->BuildRaytracingAccelerationStructure( + d3dCmdBuffer->handle6, &buildInfo, 0, nullptr); @@ -3624,8 +3727,8 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( dstAs->address, &buildInfo); - d3d12CmdBuffer->handle6->lpVtbl->BuildRaytracingAccelerationStructure( - d3d12CmdBuffer->handle6, + d3dCmdBuffer->handle6->lpVtbl->BuildRaytracingAccelerationStructure( + d3dCmdBuffer->handle6, &buildInfo, 0, nullptr); @@ -3638,7 +3741,7 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; D3D12_CPU_DESCRIPTOR_HANDLE colorAttachments[MAX_ATTACHMENTS]; D3D12_CPU_DESCRIPTOR_HANDLE depthStencilAttachment; D3D12_CPU_DESCRIPTOR_HANDLE fsrAttachment; @@ -3649,16 +3752,16 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( ImageView* tmpDepth = (ImageView*)info->depthStencilAttachment->imageView; if (tmpDepth) { - d3d12CmdBuffer->handle6->lpVtbl->OMSetRenderTargets( - d3d12CmdBuffer->handle6, + d3dCmdBuffer->handle6->lpVtbl->OMSetRenderTargets( + d3dCmdBuffer->handle6, info->colorAttachentCount, colorAttachments, FALSE, &tmpDepth->cpuHandle); } else { - d3d12CmdBuffer->handle6->lpVtbl->OMSetRenderTargets( - d3d12CmdBuffer->handle6, + d3dCmdBuffer->handle6->lpVtbl->OMSetRenderTargets( + d3dCmdBuffer->handle6, info->colorAttachentCount, colorAttachments, FALSE, @@ -3673,8 +3776,8 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( color[2] = info->colorAttachments[i].clearValue.color[2]; color[3] = info->colorAttachments[i].clearValue.color[3]; - d3d12CmdBuffer->handle6->lpVtbl->ClearRenderTargetView( - d3d12CmdBuffer->handle6, + d3dCmdBuffer->handle6->lpVtbl->ClearRenderTargetView( + d3dCmdBuffer->handle6, colorAttachments[i], color, 0, nullptr); } @@ -3693,8 +3796,8 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( clearFlags |= D3D12_CLEAR_FLAG_STENCIL; } - d3d12CmdBuffer->handle6->lpVtbl->ClearDepthStencilView( - d3d12CmdBuffer->handle6, + d3dCmdBuffer->handle6->lpVtbl->ClearDepthStencilView( + d3dCmdBuffer->handle6, depthStencilAttachment, clearFlags, depth, @@ -3705,8 +3808,8 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( if (info->fragmentShadingRateAttachment) { ImageView* tmp = (ImageView*)info->fragmentShadingRateAttachment->imageView; - d3d12CmdBuffer->handle6->lpVtbl->RSSetShadingRateImage( - d3d12CmdBuffer->handle6, + d3dCmdBuffer->handle6->lpVtbl->RSSetShadingRateImage( + d3dCmdBuffer->handle6, tmp->image->handle); } @@ -3724,12 +3827,12 @@ PalResult PAL_CALL cmdCopyBufferD3D12( PalBuffer* src, PalBufferCopyInfo* copyInfo) { - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* dstbuffer = (Buffer*)dst; Buffer* srcBuffer = (Buffer*)src; - d3d12CmdBuffer->handle6->lpVtbl->CopyBufferRegion( - d3d12CmdBuffer->handle6, + d3dCmdBuffer->handle6->lpVtbl->CopyBufferRegion( + d3dCmdBuffer->handle6, dstbuffer->handle, copyInfo->dstOffset, srcBuffer->handle, @@ -3745,7 +3848,7 @@ PalResult PAL_CALL cmdCopyBufferToImageD3D12( PalBuffer* srcBuffer, PalBufferImageCopyInfo* copyInfo) { - CommandBuffer* d3d12CmdBuffer = (CommandBuffer*)cmdBuffer; + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Image* dst = (Image*)dstImage; Buffer* src = (Buffer*)srcBuffer; @@ -3764,23 +3867,29 @@ PalResult PAL_CALL cmdCopyBufferToImageD3D12( footPrint->Footprint.Depth = copyInfo->imageDepth; footPrint->Footprint.Format = formatToD3D12(dst->info.format); - Uint32 imageFormatSize = getFormatSizeVk(dst->info.format); + Uint32 imageFormatSize = getFormatSizeD3D12(dst->info.format); Uint64 rowPitch = alignD3D12((Uint64)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); footPrint->Footprint.RowPitch = (UINT)rowPitch; D3D12_BOX box = {0}; box.right = copyInfo->imageWidth; - box.bottom= copyInfo->imageHeight; + box.bottom = copyInfo->imageHeight; box.back = copyInfo->imageDepth; - d3d12CmdBuffer->handle6->lpVtbl->CopyTextureRegion( - d3d12CmdBuffer->handle6, - &dstLocation, - copyInfo->imageOffsetX, - copyInfo->imageOffsetY, - copyInfo->imageOffsetZ, - &srcLocation, - &box); + // copy the array layers manually + for (Uint32 layer = 0; layer < copyInfo->ImageArrayLayerCount; layer++) { + Uint32 tmp = (copyInfo->ImageStartArrayLayer + layer) * dst->info.mipLevelCount; + dstLocation.SubresourceIndex = copyInfo->ImageMipLevel + tmp; + + d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( + d3dCmdBuffer->handle6, + &dstLocation, + copyInfo->imageOffsetX, + copyInfo->imageOffsetY, + copyInfo->imageOffsetZ, + &srcLocation, + &box); + } return PAL_RESULT_SUCCESS; } @@ -3791,7 +3900,44 @@ PalResult PAL_CALL cmdCopyImageD3D12( PalImage* src, PalImageCopyInfo* copyInfo) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Image* dstImage = (Image*)dst; + Image* srcImage = (Image*)src; + + D3D12_TEXTURE_COPY_LOCATION dstLocation = {0}; + dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstLocation.pResource = dstImage->handle; + + D3D12_TEXTURE_COPY_LOCATION srcLocation = {0}; + srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + srcLocation.pResource = srcImage->handle; + + D3D12_BOX box = {0}; + box.left = copyInfo->srcOffsetX; + box.top = copyInfo->srcOffsetY; + box.front = copyInfo->srcOffsetZ; + box.right = copyInfo->srcOffsetX + copyInfo->width; + box.bottom = copyInfo->srcOffsetY + copyInfo->height; + box.back = copyInfo->srcOffsetZ + copyInfo->depth; + + // copy the array layers manually + for (Uint32 layer = 0; layer < copyInfo->arrayLayerCount; layer++) { + Uint32 dstTmp = (copyInfo->dstStartArrayLayer + layer) * dstImage->info.mipLevelCount; + Uint32 srcTmp = (copyInfo->srcStartArrayLayer + layer) * srcImage->info.mipLevelCount; + dstLocation.SubresourceIndex = copyInfo->dstMipLevel + dstTmp; + srcLocation.SubresourceIndex = copyInfo->srcMipLevel + srcTmp; + + d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( + d3dCmdBuffer->handle6, + &dstLocation, + copyInfo->dstOffsetX, + copyInfo->dstOffsetY, + copyInfo->dstOffsetZ, + &srcLocation, + &box); + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdCopyImageToBufferD3D12( @@ -3800,7 +3946,52 @@ PalResult PAL_CALL cmdCopyImageToBufferD3D12( PalImage* srcImage, PalBufferImageCopyInfo* copyInfo) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* dst = (Buffer*)dstBuffer; + Image* src = (Image*)srcImage; + + D3D12_TEXTURE_COPY_LOCATION dstLocation = {0}; + dstLocation.pResource = dst->handle; + dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT* footPrint = &dstLocation.PlacedFootprint; + footPrint->Offset = copyInfo->bufferOffset; + footPrint->Footprint.Width = copyInfo->imageWidth; + footPrint->Footprint.Height = copyInfo->imageHeight; + footPrint->Footprint.Depth = copyInfo->imageDepth; + footPrint->Footprint.Format = formatToD3D12(src->info.format); + + D3D12_TEXTURE_COPY_LOCATION srcLocation = {0}; + srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + srcLocation.pResource = src->handle; + + Uint32 imageFormatSize = getFormatSizeD3D12(src->info.format); + Uint64 rowPitch = alignD3D12((Uint64)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + footPrint->Footprint.RowPitch = (UINT)rowPitch; + + D3D12_BOX box = {0}; + box.left = copyInfo->imageOffsetX; + box.top = copyInfo->imageOffsetY; + box.front = copyInfo->imageOffsetZ; + box.right = copyInfo->imageOffsetX + copyInfo->imageWidth; + box.bottom = copyInfo->imageOffsetY + copyInfo->imageHeight; + box.back = copyInfo->imageOffsetX + copyInfo->imageDepth; + + // copy the array layers manually + for (Uint32 layer = 0; layer < copyInfo->ImageArrayLayerCount; layer++) { + Uint32 tmp = (copyInfo->ImageStartArrayLayer + layer) * src->info.mipLevelCount; + srcLocation.SubresourceIndex = copyInfo->ImageMipLevel + tmp; + + d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( + d3dCmdBuffer->handle6, + &dstLocation, + 0, + 0, + 0, + &srcLocation, + &box); + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdBindPipelineD3D12( @@ -3808,7 +3999,20 @@ PalResult PAL_CALL cmdBindPipelineD3D12( PalPipelineBindPoint bindPoint, PalPipeline* pipeline) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Pipeline* d3dPipeline = (Pipeline*)pipeline; + if (bindPoint == PAL_PIPELINE_BIND_POINT_RAY_TRACING) { + d3dCmdBuffer->handle6->lpVtbl->SetPipelineState1( + d3dCmdBuffer->handle6, + d3dPipeline->handle); + } else { + d3dCmdBuffer->handle6->lpVtbl->SetPipelineState( + d3dCmdBuffer->handle6, + d3dPipeline->handle); + } + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdSetViewportD3D12( @@ -3816,7 +4020,35 @@ PalResult PAL_CALL cmdSetViewportD3D12( Uint32 count, PalViewport* viewports) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + D3D12_VIEWPORT cachedViewport; + D3D12_VIEWPORT* d3dViewports = nullptr; + + if (count > 1) { + d3dViewports = palAllocate(s_D3D.allocator, sizeof(D3D12_VIEWPORT) * count, 0); + if (!d3dViewports) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + } else { + d3dViewports = &cachedViewport; + } + for (int i = 0; i < count; i++) { + D3D12_VIEWPORT* tmp = &d3dViewports[i]; + tmp->TopLeftX = viewports[i].x; + tmp->TopLeftY = viewports[i].y; + tmp->Width = viewports[i].width; + tmp->Height = viewports[i].height; + tmp->MinDepth = viewports[i].minDepth; + tmp->MaxDepth = viewports[i].maxDepth; + } + + d3dCmdBuffer->handle6->lpVtbl->RSSetViewports(d3dCmdBuffer->handle6, count, d3dViewports); + if (count > 1) { + palFree(s_D3D.allocator, d3dViewports); + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdSetScissorsD3D12( @@ -3824,17 +4056,75 @@ PalResult PAL_CALL cmdSetScissorsD3D12( Uint32 count, PalRect2D* scissors) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + D3D12_RECT cachedScissor; + D3D12_RECT* d3dScissors = nullptr; + + if (count > 1) { + d3dScissors = palAllocate(s_D3D.allocator, sizeof(D3D12_RECT) * count, 0); + if (!d3dScissors) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } else { + d3dScissors = &cachedScissor; + } + + for (int i = 0; i < count; i++) { + D3D12_RECT* tmp = &d3dScissors[i]; + tmp->left = scissors[i].x; + tmp->top = scissors[i].y; + tmp->right = scissors[i].width; + tmp->bottom = scissors[i].height; + } + + d3dCmdBuffer->handle6->lpVtbl->RSSetScissorRects(d3dCmdBuffer->handle6, count, d3dScissors); + if (count > 1) { + palFree(s_D3D.allocator, d3dScissors); + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdBindVertexBuffersD3D12( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, + Uint32* strides, PalBuffer** buffers, Uint64* offsets) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + D3D12_VERTEX_BUFFER_VIEW cachedView = {0}; + D3D12_VERTEX_BUFFER_VIEW* views = nullptr; + + if (count > 1) { + views = palAllocate(s_D3D.allocator, sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, 0); + if (!views) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } else { + views = &cachedView; + } + + for (int i = 0; i < count; i++) { + Buffer* tmp = (Buffer*)buffers[i]; + views[i].BufferLocation = tmp->handle->lpVtbl->GetGPUVirtualAddress(tmp->handle); + views[i].BufferLocation = views[i].BufferLocation + offsets[i]; + views[i].SizeInBytes = tmp->size; + views[i].StrideInBytes = strides[i]; + } + + d3dCmdBuffer->handle6->lpVtbl->IASetVertexBuffers( + d3dCmdBuffer->handle6, + firstSlot, + count, + views); + + if (count > 1) { + palFree(s_D3D.allocator, views); + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdBindIndexBufferD3D12( @@ -3843,7 +4133,21 @@ PalResult PAL_CALL cmdBindIndexBufferD3D12( Uint64 offset, PalIndexType type) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + D3D12_INDEX_BUFFER_VIEW view = {0}; + Buffer* indexBuffer = (Buffer*)buffer; + view.BufferLocation = indexBuffer->handle->lpVtbl->GetGPUVirtualAddress(indexBuffer->handle); + view.BufferLocation = view.BufferLocation + offset; + view.SizeInBytes = indexBuffer->size; + if (type == PAL_INDEX_TYPE_UINT16) { + view.Format = DXGI_FORMAT_R16_UINT; + } else { + view.Format = DXGI_FORMAT_R32_UINT; + } + + d3dCmdBuffer->handle6->lpVtbl->IASetIndexBuffer(d3dCmdBuffer->handle6, &view); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdDrawD3D12( @@ -3853,7 +4157,15 @@ PalResult PAL_CALL cmdDrawD3D12( Uint32 firstVertex, Uint32 firstInstance) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + d3dCmdBuffer->handle6->lpVtbl->DrawInstanced( + d3dCmdBuffer->handle6, + vertexCount, + instanceCount, + firstVertex, + firstInstance); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdDrawIndirectD3D12( @@ -3861,7 +4173,23 @@ PalResult PAL_CALL cmdDrawIndirectD3D12( PalBuffer* buffer, Uint32 count) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3dCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + Buffer* d3dBuffer = (Buffer*)buffer; + d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle6, + device->drawSignature, + count, + d3dBuffer->handle, + 0, + nullptr, + 0); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdDrawIndirectCountD3D12( @@ -3870,7 +4198,24 @@ PalResult PAL_CALL cmdDrawIndirectCountD3D12( PalBuffer* countBuffer, Uint32 maxDrawCount) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3dCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + Buffer* d3dBuffer = (Buffer*)buffer; + Buffer* d3dCountBuffer = (Buffer*)countBuffer; + d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle6, + device->drawSignature, + maxDrawCount, + d3dBuffer->handle, + 0, + d3dCountBuffer->handle, + 0); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdDrawIndexedD3D12( @@ -3881,7 +4226,16 @@ PalResult PAL_CALL cmdDrawIndexedD3D12( Int32 vertexOffset, Uint32 firstInstance) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + d3dCmdBuffer->handle6->lpVtbl->DrawIndexedInstanced( + d3dCmdBuffer->handle6, + indexCount, + instanceCount, + firstIndex, + vertexOffset, + firstInstance); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( @@ -3889,7 +4243,23 @@ PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( PalBuffer* buffer, Uint32 count) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3dCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + Buffer* d3dBuffer = (Buffer*)buffer; + d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle6, + device->drawIndexedSignature, + count, + d3dBuffer->handle, + 0, + nullptr, + 0); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( @@ -3898,7 +4268,24 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( PalBuffer* countBuffer, Uint32 maxDrawCount) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3dCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + Buffer* d3dBuffer = (Buffer*)buffer; + Buffer* d3dCountBuffer = (Buffer*)countBuffer; + d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle6, + device->drawIndexedSignature, + maxDrawCount, + d3dBuffer->handle, + 0, + d3dCountBuffer->handle, + 0); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdMemoryBarrierD3D12( @@ -3906,7 +4293,15 @@ PalResult PAL_CALL cmdMemoryBarrierD3D12( PalUsageStateInfo* oldsUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) { + // TODO: + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + D3D12_RESOURCE_BARRIER barrier = {0}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + // barrier.Transition.pResource + // barrier.Transition. + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdImageBarrierD3D12( diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 1b4dfefd..a7dda27e 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -492,6 +492,7 @@ PalResult PAL_CALL cmdBindVertexBuffersVk( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, + Uint32* strides, PalBuffer** buffers, Uint64* offsets); @@ -1359,6 +1360,7 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, + Uint32* strides, PalBuffer** buffers, Uint64* offsets); @@ -3450,6 +3452,7 @@ PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, + Uint32* strides, PalBuffer** buffers, Uint64* offsets) { @@ -3457,11 +3460,17 @@ PalResult PAL_CALL palCmdBindVertexBuffers( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !buffers || !offsets) { + if (!cmdBuffer || !buffers || !strides || !offsets) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdBindVertexBuffers(cmdBuffer, firstSlot, count, buffers, offsets); + return cmdBuffer->backend->cmdBindVertexBuffers( + cmdBuffer, + firstSlot, + count, + strides, + buffers, + offsets); } PalResult PAL_CALL palCmdBindIndexBuffer( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 7c22e856..bde12478 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1837,13 +1837,6 @@ static Barrier barrierToVk( return barrier; } - case PAL_USAGE_STATE_COLOR_ATTACHMENT_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; - barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - return barrier; - } - case PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE: { barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR; @@ -7081,6 +7074,7 @@ PalResult PAL_CALL cmdBindVertexBuffersVk( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, + Uint32* strides, PalBuffer** buffers, Uint64* offsets) { diff --git a/tests/texture_test.c b/tests/texture_test.c index 14c66161..f03692f7 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -1284,8 +1284,16 @@ bool textureTest() } // bind vertex buffer + Uint32 strides[] = { 16 }; Uint64 offset[] = {0}; - result = palCmdBindVertexBuffers(cmdBuffers[currentFrame], 0, 1, &vertexBuffer, offset); + result = palCmdBindVertexBuffers( + cmdBuffers[currentFrame], + 0, + 1, + strides, + &vertexBuffer, + offset); + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind vertex buffer: %s", error); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index ca5a9c08..8d714d12 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -873,8 +873,16 @@ bool triangleTest() } // bind vertex buffer + Uint32 strides[] = { 20 }; Uint64 offset[] = {0}; - result = palCmdBindVertexBuffers(cmdBuffers[currentFrame], 0, 1, &vertexBuffer, offset); + result = palCmdBindVertexBuffers( + cmdBuffers[currentFrame], + 0, + 1, + strides, + &vertexBuffer, + offset); + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind vertex buffer: %s", error); From f1fac2f8183a070e08088a234dac0a55b0963500 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 8 Apr 2026 16:11:51 +0000 Subject: [PATCH 153/372] remove plain memory barrier function --- include/pal/pal_graphics.h | 16 +++++--- src/graphics/pal_d3d12.c | 79 ++++++++++++++++++++----------------- src/graphics/pal_graphics.c | 27 ++++++++----- src/graphics/pal_vulkan.c | 7 +++- 4 files changed, 76 insertions(+), 53 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 4634c4c8..3672283c 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3427,12 +3427,13 @@ typedef struct { Uint32 count); /** - * Backend implementation of ::palCmdMemoryBarrier. + * Backend implementation of ::palCmdAccelerationStructureBarrier. * - * Must obey the rules and semantics documented in palCmdMemoryBarrier(). + * Must obey the rules and semantics documented in palCmdAccelerationStructureBarrier(). */ - PalResult PAL_CALL (*cmdMemoryBarrier)( + PalResult PAL_CALL (*cmdAccelerationStructureBarrier)( PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); @@ -6025,7 +6026,10 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( Uint32 maxDrawCount); /** - * @brief Insert a memory barrier into the command buffer. + * @brief Insert an acceleration structure memory barrier into the command buffer. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, + * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * The graphics system must be initialized before this call. This functions makes memory invisible * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. @@ -6037,6 +6041,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * sure its in read state before its visible to the raygen shader. * * @param[in] cmdBuffer Command buffer being recorded. + * @param[in] as Acceleration structure to set barrier on. * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. * @@ -6050,8 +6055,9 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * @sa palCmdImageBarrier * @sa palCmdBufferBarrier */ -PAL_API PalResult PAL_CALL palCmdMemoryBarrier( +PAL_API PalResult PAL_CALL palCmdAccelerationStructureBarrier( PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index a0b3c0f9..1647749f 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -1088,7 +1088,8 @@ static D3D12_RESOURCE_STATES barrierToD3D12( return D3D12_RESOURCE_STATE_COPY_SOURCE; } - case PAL_USAGE_STATE_TRANSFER_WRITE: { + case PAL_USAGE_STATE_TRANSFER_WRITE: + case PAL_USAGE_STATE_HOST_READ: { return D3D12_RESOURCE_STATE_COPY_DEST; } @@ -1105,43 +1106,30 @@ static D3D12_RESOURCE_STATES barrierToD3D12( } case PAL_USAGE_STATE_SHADER_READ: { - // TODO: continue - return 0; - } - - case PAL_USAGE_STATE_SHADER_WRITE: { - // TODO: continue - return 0; - } - - case PAL_USAGE_STATE_STORAGE_READ: { - // TODO: continue - return 0; + if (stageCount == 1) { + if (shaderStages[0] == PAL_SHADER_STAGE_FRAGMENT) { + return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + } else { + return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + } + } else { + return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; + } } + case PAL_USAGE_STATE_STORAGE_READ: + case PAL_USAGE_STATE_SHADER_WRITE: case PAL_USAGE_STATE_STORAGE_WRITE: { - // TODO: continue - return 0; - } - - case PAL_USAGE_STATE_HOST_READ: { - // TODO: continue - return 0; + return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } case PAL_USAGE_STATE_HOST_WRITE: { - // TODO: continue - return 0; - } - - case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: { - // TODO: continue - return 0; + return D3D12_RESOURCE_STATE_GENERIC_READ; } + case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE: { - // TODO: continue - return 0; + return D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; } } @@ -4288,19 +4276,35 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdMemoryBarrierD3D12( +PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( PalCommandBuffer* cmdBuffer, - PalUsageStateInfo* oldsUsageStateInfo, + PalAccelerationStructure* as, + PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) { - // TODO: CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - D3D12_RESOURCE_BARRIER barrier = {0}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - // barrier.Transition.pResource - // barrier.Transition. + if (!(d3dCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + AccelerationStructure* d3dAS = (AccelerationStructure*)as; + D3D12_RESOURCE_STATES old, new; + old = barrierToD3D12( + oldUsageStateInfo->shaderStageCount, + oldUsageStateInfo->usageState, + oldUsageStateInfo->shaderStages); + new = barrierToD3D12( + newUsageStateInfo->shaderStageCount, + newUsageStateInfo->usageState, + newUsageStateInfo->shaderStages); + + D3D12_RESOURCE_BARRIER barrier = {0}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrier.UAV.pResource = d3dAS->handle; + + d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, 1, &barrier); return PAL_RESULT_SUCCESS; } @@ -4311,7 +4315,8 @@ PalResult PAL_CALL cmdImageBarrierD3D12( PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) { - + // TODO: + } PalResult PAL_CALL cmdBufferBarrierD3D12( diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index a7dda27e..9563ae8f 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -539,9 +539,10 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( PalBuffer* countBuffer, Uint32 maxDrawCount); -PalResult PAL_CALL cmdMemoryBarrierVk( +PalResult PAL_CALL cmdAccelerationStructureBarrierVk( PalCommandBuffer* cmdBuffer, - PalUsageStateInfo* oldsUsageStateInfo, + PalAccelerationStructure* as, + PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); PalResult PAL_CALL cmdImageBarrierVk( @@ -901,7 +902,7 @@ static PalGraphicsBackend s_VkBackend = { .cmdDrawIndexed = cmdDrawIndexedVk, .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectVk, .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountVk, - .cmdMemoryBarrier = cmdMemoryBarrierVk, + .cmdAccelerationStructureBarrier = cmdAccelerationStructureBarrierVk, .cmdImageBarrier = cmdImageBarrierVk, .cmdBufferBarrier = cmdBufferBarrierVk, .cmdDispatch = cmdDispatchVk, @@ -1407,9 +1408,10 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( PalBuffer* countBuffer, Uint32 maxDrawCount); -PalResult PAL_CALL cmdMemoryBarrierD3D12( +PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( PalCommandBuffer* cmdBuffer, - PalUsageStateInfo* oldsUsageStateInfo, + PalAccelerationStructure* as, + PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo); PalResult PAL_CALL cmdImageBarrierD3D12( @@ -1769,7 +1771,7 @@ static PalGraphicsBackend s_D3D12Backend = { .cmdDrawIndexed = cmdDrawIndexedD3D12, .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectD3D12, .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountD3D12, - .cmdMemoryBarrier = cmdMemoryBarrierD3D12, + .cmdAccelerationStructureBarrier = cmdAccelerationStructureBarrierD3D12, .cmdImageBarrier = cmdImageBarrierD3D12, .cmdBufferBarrier = cmdBufferBarrierD3D12, .cmdDispatch = cmdDispatchD3D12, @@ -1975,7 +1977,7 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->cmdDrawIndexed || !backend->cmdDrawIndexedIndirect || !backend->cmdDrawIndexedIndirectCount || - !backend->cmdMemoryBarrier || + !backend->cmdAccelerationStructureBarrier || !backend->cmdImageBarrier || !backend->cmdBufferBarrier || !backend->cmdDispatch || @@ -3608,8 +3610,9 @@ PalResult PAL_CALL palCmdDrawIndexedIndirectCount( maxDrawCount); } -PalResult PAL_CALL palCmdMemoryBarrier( +PalResult PAL_CALL palCmdAccelerationStructureBarrier( PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) { @@ -3617,11 +3620,15 @@ PalResult PAL_CALL palCmdMemoryBarrier( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !oldUsageStateInfo || !newUsageStateInfo) { + if (!cmdBuffer || !as || !oldUsageStateInfo || !newUsageStateInfo) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdMemoryBarrier(cmdBuffer, oldUsageStateInfo, newUsageStateInfo); + return cmdBuffer->backend->cmdAccelerationStructureBarrier( + cmdBuffer, + as, + oldUsageStateInfo, + newUsageStateInfo); } PalResult PAL_CALL palCmdImageBarrier( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index bde12478..9ce21469 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -7235,12 +7235,17 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdMemoryBarrierVk( +PalResult PAL_CALL cmdAccelerationStructureBarrierVk( PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + VkMemoryBarrier2KHR barrier = {0}; barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR; From 3ce34ea9e42f83f02a6b280fa1956fdbb7115acd Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 9 Apr 2026 18:56:21 +0000 Subject: [PATCH 154/372] make indirect dispatch use only CPU UPLOAD memory --- include/pal/pal_graphics.h | 15 +- src/graphics/pal_d3d12.c | 292 +++++++++++++++++++++++++++++++++++- src/graphics/pal_graphics.c | 10 +- src/graphics/pal_vulkan.c | 83 +++++++--- tests/ray_tracing_test.c | 14 +- 5 files changed, 380 insertions(+), 34 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 3672283c..f5a0fe39 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3516,7 +3516,7 @@ typedef struct { PalCommandBuffer* cmdBuffer, Uint32 raygenIndex, PalShaderBindingTable* sbt, - PalDeviceAddress bufferAddress); + PalBuffer* buffer); /** * Backend implementation of ::palCmdBindDescriptorSet. @@ -6201,8 +6201,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. - * Can be a single struct. + * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6256,17 +6255,21 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * `PAL_ADAPTER_FEATURE_RAY_TRACING` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported * and enabled by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * If buffer memory type is not `PAL_MEMORY_TYPE_CPU_UPLOAD`, this function will fail and return + * `PAL_RESULT_MEMORY_MAP_FAILED`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] raygenIndex Index of the raygen shader to execute. * @param[in] sbt The shader binding table to use. - * @param[in] bufferAddress Buffer address of buffer containing an array of - * PalDispatchIndirectData structs. Can be a single struct. + * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note The memory associated with the buffer must be `PAL_MEMORY_TYPE_CPU_UPLOAD`. * * @since 1.4 * @ingroup pal_graphics @@ -6275,7 +6278,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, Uint32 raygenIndex, PalShaderBindingTable* sbt, - PalDeviceAddress bufferAddress); + PalBuffer* buffer); /** * @brief Bind a descriptor set to the provided command buffer. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 1647749f..232cc62b 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -103,6 +103,7 @@ typedef struct { ID3D12CommandSignature* drawIndexedSignature; ID3D12CommandSignature* drawSignature; ID3D12CommandSignature* dispatchSignature; + ID3D12CommandSignature* raySignature; ID3D12InfoQueue* infoQueue; ID3D12CommandQueue* queue; ID3D12Device* handle; @@ -127,6 +128,7 @@ typedef struct { const PalGraphicsBackend* backend; bool belongsToSwapchain; + Uint32 planeCount; ID3D12Device* device; ID3D12Resource* handle; PalImageInfo info; @@ -189,6 +191,7 @@ typedef struct { bool primary; void* pool; // CommandPool Device* device; + ID3D12Resource* tmpBuffer; ID3D12CommandAllocator* allocator; ID3D12GraphicsCommandList* handle; ID3D12GraphicsCommandList6* handle6; @@ -229,6 +232,20 @@ typedef struct { void* handle; } Pipeline; +typedef struct { + const PalGraphicsBackend* backend; + + Uint64 raygenStride; + ID3D12Resource* buffer; + ID3D12Heap* bufferMemory; + D3D12_GPU_VIRTUAL_ADDRESS baseAddress; + + D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress; + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE missAddress; + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE hitAddress; + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE callableAddress; +} ShaderBindingTable; + static D3D12 s_D3D = {0}; // ================================================== @@ -1650,6 +1667,25 @@ PalResult PAL_CALL createDeviceD3D12( } } + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_RAYS; + signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_RAYS_DESC); + + result = device->handle->lpVtbl->CreateCommandSignature( + device->handle, + &signatureDesc, + nullptr, + &IID_Signature, + (void**)&device->raySignature); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + } + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW) { // disptach indexed argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; @@ -1720,6 +1756,10 @@ void PAL_CALL destroyDeviceD3D12(PalDevice* device) d3dDevice->meshSignature->lpVtbl->Release(d3dDevice->meshSignature); } + if (d3dDevice->raySignature) { + d3dDevice->raySignature->lpVtbl->Release(d3dDevice->raySignature); + } + if (d3dDevice->dispatchSignature) { d3dDevice->dispatchSignature->lpVtbl->Release(d3dDevice->dispatchSignature); } @@ -2385,6 +2425,14 @@ PalResult PAL_CALL createImageD3D12( image->info.sampleCount = info->sampleCount; image->info.width = info->width; + // get plane count from image format + image->planeCount = 1; // for color or depth + if (info->format == PAL_FORMAT_D32_SFLOAT_S8_UINT || + info->format == PAL_FORMAT_D16_UNORM_S8_UINT || + info->format == PAL_FORMAT_D24_UNORM_S8_UINT) { + image->planeCount = 2; + } + image->device = d3dDevice->handle; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; @@ -3445,6 +3493,37 @@ PalResult PAL_CALL allocateCommandBufferD3D12( return PAL_RESULT_PLATFORM_FAILURE; } + // we need a tmp upload buffer if ray tracing is enabled + D3D12_HEAP_PROPERTIES heapProps = {0}; + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + heapProps.VisibleNodeMask = 1; + heapProps.CreationNodeMask = 1; + + D3D12_RESOURCE_DESC bufferDesc = {0}; + bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + bufferDesc.Width = sizeof(D3D12_DISPATCH_RAYS_DESC); + bufferDesc.Height = 1; + bufferDesc.DepthOrArraySize = 1; + bufferDesc.MipLevels = 1; + bufferDesc.SampleDesc.Count = 1; + bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + + result = d3dDevice->handle->lpVtbl->CreateCommittedResource( + d3dDevice->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + &IID_Resource, (void**)&cmdBuffer->tmpBuffer); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + cmdBuffer->handle->lpVtbl->QueryInterface( cmdBuffer->handle, &IID_CmdList6, @@ -3465,6 +3544,7 @@ void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) d3dCmdBuffer->handle6->lpVtbl->Release(d3dCmdBuffer->handle6); d3dCmdBuffer->handle->lpVtbl->Release(d3dCmdBuffer->handle); d3dCmdBuffer->allocator->lpVtbl->Release(d3dCmdBuffer->allocator); + d3dCmdBuffer->tmpBuffer->lpVtbl->Release(d3dCmdBuffer->tmpBuffer); palFree(s_D3D.allocator, cmdBuffer); data->cmdBuffer = nullptr; @@ -4315,8 +4395,88 @@ PalResult PAL_CALL cmdImageBarrierD3D12( PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) { - // TODO: - + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Image* d3dImage = (Image*)image; + D3D12_RESOURCE_STATES old, new; + D3D12_RESOURCE_BARRIER barrier = {0}; + + old = barrierToD3D12( + oldUsageStateInfo->shaderStageCount, + oldUsageStateInfo->usageState, + oldUsageStateInfo->shaderStages); + + new = barrierToD3D12( + newUsageStateInfo->shaderStageCount, + newUsageStateInfo->usageState, + newUsageStateInfo->shaderStages); + + // read/write barrier without transition + if (old == new && old == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrier.UAV.pResource = d3dImage->handle; + d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, 1, &barrier); + return PAL_RESULT_SUCCESS; + } + + D3D12_RESOURCE_BARRIER* barriers = nullptr; + Uint32 levelCount = subresourceRange->mipLevelCount; + Uint32 layerCount = subresourceRange->layerArrayCount; + Uint32 planeCount = d3dImage->planeCount; + + Uint32 startLevel = subresourceRange->startMipLevel; + Uint32 startLayer = subresourceRange->startArrayLayer; + Uint32 maxLevels = d3dImage->info.mipLevelCount; + Uint32 maxLayers = d3dImage->info.depthOrArraySize; + Uint32 barrierCount = layerCount * levelCount * d3dImage->planeCount; + + if (startLevel == 0 && levelCount == maxLevels && startLayer == 0 && layerCount == maxLayers) { + // full resource + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = d3dImage->handle; + barrier.Transition.StateBefore = old; + barrier.Transition.StateAfter = new; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + + d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, 1, &barrier); + return PAL_RESULT_SUCCESS; + } + + if (layerCount == 1 && layerCount == 1 && planeCount == 1) { + // single plane + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = d3dImage->handle; + barrier.Transition.StateBefore = old; + barrier.Transition.StateAfter = new; + barrier.Transition.Subresource = startLevel + startLayer * maxLevels; + + d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, 1, &barrier); + return PAL_RESULT_SUCCESS; + } + + barriers = palAllocate(s_D3D.allocator, sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, 0); + if (!barriers) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + Uint32 count = 0; + for (Uint32 plane = 0; plane < d3dImage->planeCount; plane++) { + for (Uint32 layer = startLayer; layer < startLayer + layerCount; layer++) { + for (Uint32 level = startLevel; level < startLevel + levelCount; level++) { + Uint32 index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); + + D3D12_RESOURCE_BARRIER* tmp = &barriers[count++]; + tmp->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + tmp->Transition.pResource = d3dImage->handle; + tmp->Transition.StateBefore = old; + tmp->Transition.StateAfter = new; + tmp->Transition.Subresource = index; + } + } + } + + d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, barrierCount, barriers); + palFree(s_D3D.allocator, barriers); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdBufferBarrierD3D12( @@ -4325,7 +4485,33 @@ PalResult PAL_CALL cmdBufferBarrierD3D12( PalUsageStateInfo* oldUsageStateInfo, PalUsageStateInfo* newUsageStateInfo) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* d3dBuffer = (Buffer*)buffer; + D3D12_RESOURCE_STATES old, new; + + old = barrierToD3D12( + oldUsageStateInfo->shaderStageCount, + oldUsageStateInfo->usageState, + oldUsageStateInfo->shaderStages); + new = barrierToD3D12( + newUsageStateInfo->shaderStageCount, + newUsageStateInfo->usageState, + newUsageStateInfo->shaderStages); + + D3D12_RESOURCE_BARRIER barrier = {0}; + if (old == new && D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrier.UAV.pResource = d3dBuffer->handle; + } else { + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = d3dBuffer->handle; + barrier.Transition.StateBefore = old; + barrier.Transition.StateAfter = new; + } + + d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, 1, &barrier); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdDispatchD3D12( @@ -4334,6 +4520,14 @@ PalResult PAL_CALL cmdDispatchD3D12( Uint32 groupCountY, Uint32 groupCountZ) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + d3dCmdBuffer->handle6->lpVtbl->Dispatch( + d3dCmdBuffer->handle6, + groupCountX, + groupCountY, + groupCountZ); + + return PAL_RESULT_SUCCESS; } @@ -4346,14 +4540,34 @@ PalResult PAL_CALL cmdDispatchBaseD3D12( Uint32 groupCountY, Uint32 groupCountZ) { - + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } PalResult PAL_CALL cmdDispatchIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Device* device = d3dCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + Buffer* d3dBuffer = (Buffer*)buffer; + d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle6, + device->dispatchSignature, + 1, // one dispatch + d3dBuffer->handle, + 0, + nullptr, + 0); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdTraceRaysD3D12( @@ -4364,16 +4578,85 @@ PalResult PAL_CALL cmdTraceRaysD3D12( Uint32 height, Uint32 depth) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; + if (!(d3dCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; + raygenAddress.SizeInBytes = d3dSbt->raygenAddress.SizeInBytes; + raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * d3dSbt->raygenStride; + D3D12_DISPATCH_RAYS_DESC desc = {0}; + desc.Width = width; + desc.Height = height; + desc.Depth = depth; + desc.RayGenerationShaderRecord = raygenAddress; + desc.HitGroupTable = d3dSbt->hitAddress; + desc.MissShaderTable = d3dSbt->missAddress; + desc.CallableShaderTable = d3dSbt->callableAddress; + + d3dCmdBuffer->handle6->lpVtbl->DispatchRays(d3dCmdBuffer->handle6, &desc); + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalCommandBuffer* cmdBuffer, Uint32 raygenIndex, PalShaderBindingTable* sbt, - PalDeviceAddress bufferAddress) + PalBuffer* buffer) { + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; + Buffer* d3dBuffer = (Buffer*)buffer; + Device* device = (Device*)d3dCmdBuffer->device; + D3D12_DISPATCH_RAYS_DESC desc = {0}; + + if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + // get width, height and depth from provided buffer + void* ptr = nullptr; + HRESULT result = d3dBuffer->handle->lpVtbl->Map(d3dBuffer->handle, 0, nullptr, &ptr); + if (FAILED(result)) { + return PAL_RESULT_MEMORY_MAP_FAILED; + } + + PalDispatchIndirectData data = {0}; + memcpy(&data, ptr, sizeof(PalDispatchIndirectData)); + d3dBuffer->handle->lpVtbl->Unmap(d3dBuffer->handle, 0, nullptr); + + desc.Width = data.groupCountXOrWidth; + desc.Height = data.groupCountXOrHeight; + desc.Depth = data.groupCountXOrDepth; + + D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; + raygenAddress.SizeInBytes = d3dSbt->raygenAddress.SizeInBytes; + raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * d3dSbt->raygenStride; + desc.RayGenerationShaderRecord = raygenAddress; + desc.HitGroupTable = d3dSbt->hitAddress; + desc.MissShaderTable = d3dSbt->missAddress; + desc.CallableShaderTable = d3dSbt->callableAddress; + + // fill the data into the tmp upload buffer of the command buffer + ptr = nullptr; + d3dCmdBuffer->tmpBuffer->lpVtbl->Map(d3dCmdBuffer->tmpBuffer, 0, nullptr, &ptr); + memcpy(ptr, &desc, sizeof(D3D12_DISPATCH_RAYS_DESC)); + d3dCmdBuffer->tmpBuffer->lpVtbl->Unmap(d3dCmdBuffer->tmpBuffer, 0, nullptr); + + d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle6, + device->raySignature, + 1, + d3dCmdBuffer->tmpBuffer, + 0, + nullptr, + 0); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdBindDescriptorSetD3D12( @@ -4383,6 +4666,7 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( Uint32 setIndex, PalDescriptorSet* set) { + // TODO: } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 9563ae8f..6d8a2e3a 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -589,7 +589,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalCommandBuffer* cmdBuffer, Uint32 raygenIndex, PalShaderBindingTable* sbt, - PalDeviceAddress bufferAddress); + PalBuffer* buffer); PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, @@ -1458,7 +1458,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalCommandBuffer* cmdBuffer, Uint32 raygenIndex, PalShaderBindingTable* sbt, - PalDeviceAddress bufferAddress); + PalBuffer* buffer); PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, @@ -3754,17 +3754,17 @@ PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, Uint32 raygenIndex, PalShaderBindingTable* sbt, - PalDeviceAddress bufferAddress) + PalBuffer* buffer) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !sbt) { + if (!cmdBuffer || !sbt || !buffer) { return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdTraceRaysIndirect(cmdBuffer, raygenIndex, sbt, bufferAddress); + return cmdBuffer->backend->cmdTraceRaysIndirect(cmdBuffer, raygenIndex, sbt, buffer); } PalResult PAL_CALL palCmdBindDescriptorSet( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 9ce21469..fcdbd5ed 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -433,13 +433,18 @@ typedef struct { PhysicalQueue* phyQueue; } Queue; +typedef struct { + PalMemoryType type; + VkDeviceMemory handle; +} Memory; + typedef struct { const PalGraphicsBackend* backend; bool belongsToSwapchain; VkImageAspectFlags aspectMask; Device* device; - VkDeviceMemory memory; + Memory* memory; VkImage handle; PalImageInfo info; } Image; @@ -530,7 +535,7 @@ typedef struct { const PalGraphicsBackend* backend; PalBufferUsages usages; - VkDeviceMemory memory; + Memory* memory; Device* device; VkBuffer handle; } Buffer; @@ -4473,13 +4478,18 @@ PalResult PAL_CALL allocateMemoryVk( PalMemory** outMemory) { VkResult result; - VkDeviceMemory memory = nullptr; + Memory* memory = nullptr; Device* vkDevice = (Device*)device; VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = (VkDeviceSize)size; VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; + memory = palAllocate(s_Vk.allocator, sizeof(Memory), 0); + if (!memory) { + return PAL_RESULT_NULL_POINTER; + } + Uint32 memoryTypeMask = 0; Uint32 usages = 0; palUnpackUint32(memoryMask, &memoryTypeMask, &usages); @@ -4506,11 +4516,17 @@ PalResult PAL_CALL allocateMemoryVk( allocateInfo.pNext = &allocateFlagsInfo; } - result = s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &memory); + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &memory->handle); + if (result != VK_SUCCESS) { return resultFromVk(result); } + memory->type = type; *outMemory = (PalMemory*)memory; return PAL_RESULT_SUCCESS; } @@ -4520,8 +4536,9 @@ void PAL_CALL freeMemoryVk( PalMemory* memory) { Device* vkDevice = (Device*)device; - VkDeviceMemory mem = (VkDeviceMemory)memory; - s_Vk.freeMemory(vkDevice->handle, mem, &s_Vk.vkAllocator); + Memory* vkMemory = (Memory*)memory; + s_Vk.freeMemory(vkDevice->handle, vkMemory->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkMemory); } // ================================================== @@ -5217,9 +5234,9 @@ PalResult PAL_CALL bindImageMemoryVk( return PAL_RESULT_INVALID_OPERATION; } - VkDeviceMemory mem = (VkDeviceMemory)memory; - s_Vk.bindImageMemory(vkImage->device->handle, vkImage->handle, mem, offset); - vkImage->memory = mem; + Memory* vkMemory = (Memory*)memory; + s_Vk.bindImageMemory(vkImage->device->handle, vkImage->handle, vkMemory->handle, offset); + vkImage->memory = vkMemory; return PAL_RESULT_SUCCESS; } @@ -5233,7 +5250,11 @@ PalResult PAL_CALL mapImageMemoryVk( Image* vkImage = (Image*)image; Device* device = vkImage->device; - result = s_Vk.mapMemory(device->handle, vkImage->memory, offset, size, 0, outPtr); + if (vkImage->memory->type == PAL_MEMORY_TYPE_GPU_ONLY) { + return PAL_RESULT_MEMORY_MAP_FAILED; + } + + result = s_Vk.mapMemory(device->handle, vkImage->memory->handle, offset, size, 0, outPtr); if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -5243,7 +5264,7 @@ PalResult PAL_CALL mapImageMemoryVk( void PAL_CALL unmapImageMemoryVk(PalImage* image) { Image* vkImage = (Image*)image; - s_Vk.unmapMemory(vkImage->device->handle, vkImage->memory); + s_Vk.unmapMemory(vkImage->device->handle, vkImage->memory->handle); } // ================================================== @@ -7407,6 +7428,14 @@ PalResult PAL_CALL cmdDispatchIndirectVk( PalBuffer* buffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + Buffer* vkBuffer = (Buffer*)buffer; s_Vk.cmdDispatchIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0); return PAL_RESULT_SUCCESS; @@ -7450,17 +7479,28 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalCommandBuffer* cmdBuffer, Uint32 raygenIndex, PalShaderBindingTable* sbt, - PalDeviceAddress bufferAddress) + PalBuffer* buffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; ShaderBindingTable* vkSbt = (ShaderBindingTable*)sbt; + Buffer* vkBuffer = (Buffer*)buffer; if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (vkBuffer->memory->type != PAL_MEMORY_TYPE_CPU_UPLOAD) { + return PAL_RESULT_MEMORY_MAP_FAILED; + } + PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygenAddress.stride; vkSbt->raygenAddress.deviceAddress = address; + + VkDeviceAddress bufferAddress = 0; + VkBufferDeviceAddressInfoKHR bufferInfo = {0}; + bufferInfo.buffer = vkBuffer->handle; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; + bufferAddress = vkBuffer->device->getBufferrAddress(vkBuffer->device->handle, &bufferInfo); vkCmdBuffer->device->cmdTraceRaysIndirect( vkCmdBuffer->handle, @@ -8008,19 +8048,24 @@ PalResult PAL_CALL bindBufferMemoryVk( Uint64 offset) { VkResult result; - VkDeviceMemory mem = (VkDeviceMemory)memory; + Memory* vkMemory = (Memory*)memory; Buffer* vkBuffer = (Buffer*)buffer; if (vkBuffer->memory) { return PAL_RESULT_INVALID_OPERATION; } - result = s_Vk.bindBufferMemory(vkBuffer->device->handle, vkBuffer->handle, mem, offset); + result = s_Vk.bindBufferMemory( + vkBuffer->device->handle, + vkBuffer->handle, + vkMemory->handle, + offset); + if (result != VK_SUCCESS) { return resultFromVk(result); } - vkBuffer->memory = mem; + vkBuffer->memory = vkMemory; return PAL_RESULT_SUCCESS; } @@ -8034,7 +8079,11 @@ PalResult PAL_CALL mapBufferMemoryVk( Buffer* vkBuffer = (Buffer*)buffer; Device* device = vkBuffer->device; - result = s_Vk.mapMemory(device->handle, vkBuffer->memory, offset, size, 0, outPtr); + if (vkBuffer->memory->type == PAL_MEMORY_TYPE_GPU_ONLY) { + return PAL_RESULT_MEMORY_MAP_FAILED; + } + + result = s_Vk.mapMemory(device->handle, vkBuffer->memory->handle, offset, size, 0, outPtr); if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -8044,7 +8093,7 @@ PalResult PAL_CALL mapBufferMemoryVk( void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer) { Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.unmapMemory(vkBuffer->device->handle, vkBuffer->memory); + s_Vk.unmapMemory(vkBuffer->device->handle, vkBuffer->memory->handle); } PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer) diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index a2bfaee3..e34de547 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -948,7 +948,12 @@ bool rayTracingTest() PalUsageStateInfo newAsUsageStateInfo = {0}; newAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; - result = palCmdMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); + result = palCmdAccelerationStructureBarrier( + cmdBuffer, + blas, + &oldAsUsageStateInfo, + &newAsUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set memory barrier: %s", error); @@ -966,7 +971,12 @@ bool rayTracingTest() newAsUsageStateInfo.shaderStages = shaderStages; // make sure the TLAS builds before the tracing - result = palCmdMemoryBarrier(cmdBuffer, &oldAsUsageStateInfo, &newAsUsageStateInfo); + result = palCmdAccelerationStructureBarrier( + cmdBuffer, + tlas, + &oldAsUsageStateInfo, + &newAsUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set memory barrier: %s", error); From 44c782f0997d6125a1492863c27a5d65ed9d4664 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 13 Apr 2026 06:01:52 +0000 Subject: [PATCH 155/372] begin d3d12 API redesign --- src/graphics/pal_d3d12.c | 419 +++++++++++++++++++++++++++++++++++- src/graphics/pal_graphics.c | 4 - src/graphics/pal_vulkan.c | 5 - 3 files changed, 409 insertions(+), 19 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 232cc62b..f5c05aeb 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -63,6 +63,7 @@ const IID IID_CmdAlloc = {0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73, const IID IID_CmdList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5}; const IID IID_CmdList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96,0xcf, 0x56,0x89,0xa9,0x37,0x0f,0x80}; const IID IID_Signature = {0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1}; +const IID IID_DescHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -140,16 +141,14 @@ typedef struct { PalImageViewType type; PalImageViewUsages usages; - Image* image; D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; - D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle; + Image* image; + D3D12_SHADER_RESOURCE_VIEW_DESC desc; } ImageView; typedef struct { const PalGraphicsBackend* backend; - D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; - D3D12_GPU_DESCRIPTOR_HANDLE gpuHandle; D3D12_SAMPLER_DESC desc; } Sampler; @@ -246,6 +245,59 @@ typedef struct { D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE callableAddress; } ShaderBindingTable; +typedef struct { + Uint32 offset; + PalDescriptorType type; + D3D12_DESCRIPTOR_RANGE range; +} DescriptorSetLayoutBinding; + +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 tableIndex; + Uint32 bindingCount; + DescriptorSetLayoutBinding* bindings; + D3D12_ROOT_PARAMETER param; +} DescriptorSetLayout; + +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 offset; + Uint32 samplerOffset; + DescriptorSetLayout* layout; + void* pool; // DescriptorPool +} DescriptorSet; + +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 maxUniformBuffers; + Uint32 maxSampledImages; + Uint32 maxStorageBuffers; + Uint32 maxSamplers; + Uint32 maxStorageImages; + Uint32 maxAs; + Uint32 maxSets; + + Uint32 usedUniformBuffers; + Uint32 usedSampledImages; + Uint32 usedStorageBuffers; + Uint32 usedSamplers; + Uint32 usedStorageImages; + Uint32 usedAs; + Uint32 usedSets; + + Uint32 samplerOffset; + Uint32 offset; + Uint32 samplerSize; + Uint32 size; + + ID3D12DescriptorHeap* heap; + ID3D12DescriptorHeap* sampleHeap; + DescriptorSet* sets; +} DescriptorPool; + static D3D12 s_D3D = {0}; // ================================================== @@ -1153,6 +1205,19 @@ static D3D12_RESOURCE_STATES barrierToD3D12( return D3D12_RESOURCE_STATE_COMMON; } +static D3D12_CPU_DESCRIPTOR_HANDLE getCPUDescriptorHandle( + ID3D12DescriptorHeap* heap, + Uint32 index, + Uint32 size) +{ + D3D12_CPU_DESCRIPTOR_HANDLE handle; + D3D12_CPU_DESCRIPTOR_HANDLE __ret; + handle = *heap->lpVtbl->GetCPUDescriptorHandleForHeapStart(heap, &__ret); + + handle.ptr += index * size; + return handle; +} + // ================================================== // Adapter // ================================================== @@ -1543,7 +1608,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT; } - if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_3) { + if (!(options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1)) { features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } @@ -1560,6 +1625,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; + features |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; if (d3dAdapter->level >= D3D_FEATURE_LEVEL_12_0) { features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; @@ -2559,11 +2625,77 @@ PalResult PAL_CALL createImageViewD3D12( return PAL_RESULT_OUT_OF_MEMORY; } + imageView->desc.Format = formatToD3D12(d3dImage->info.format); + if (info->type == PAL_IMAGE_VIEW_TYPE_1D) { + imageView->desc.Texture1D.MipLevels = info->subresourceRange.mipLevelCount; + imageView->desc.Texture1D.MostDetailedMip = info->subresourceRange.startMipLevel; + imageView->desc.Texture1D.ResourceMinLODClamp = 0; + imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; + + } else if (info->type == PAL_IMAGE_VIEW_TYPE_1D_ARRAY) { + imageView->desc.Texture1DArray.MipLevels = info->subresourceRange.mipLevelCount; + imageView->desc.Texture1DArray.MostDetailedMip = info->subresourceRange.startMipLevel; + imageView->desc.Texture1DArray.FirstArraySlice = info->subresourceRange.startArrayLayer; + imageView->desc.Texture1DArray.ArraySize = info->subresourceRange.layerArrayCount; + imageView->desc.Texture1DArray.ResourceMinLODClamp = 0; + imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + + } else if (info->type == PAL_IMAGE_VIEW_TYPE_2D) { + imageView->desc.Texture2D.MipLevels = info->subresourceRange.mipLevelCount; + imageView->desc.Texture2D.MostDetailedMip = info->subresourceRange.startMipLevel; + imageView->desc.Texture2D.PlaneSlice = 0; + imageView->desc.Texture2D.ResourceMinLODClamp = 0; + imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + + } else if (info->type == PAL_IMAGE_VIEW_TYPE_2D_ARRAY) { + imageView->desc.Texture2DArray.MipLevels = info->subresourceRange.mipLevelCount; + imageView->desc.Texture2DArray.MostDetailedMip = info->subresourceRange.startMipLevel; + imageView->desc.Texture2DArray.FirstArraySlice = info->subresourceRange.startArrayLayer; + imageView->desc.Texture2DArray.ArraySize = info->subresourceRange.layerArrayCount; + imageView->desc.Texture2DArray.ResourceMinLODClamp = 0; + imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + + } else if (info->type == PAL_IMAGE_VIEW_TYPE_3D) { + imageView->desc.Texture3D.MipLevels = info->subresourceRange.mipLevelCount; + imageView->desc.Texture3D.MostDetailedMip = info->subresourceRange.startMipLevel; + imageView->desc.Texture3D.ResourceMinLODClamp = 0; + imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; + + } else if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE) { + imageView->desc.TextureCube.MipLevels = info->subresourceRange.mipLevelCount; + imageView->desc.TextureCube.MostDetailedMip = info->subresourceRange.startMipLevel; + imageView->desc.TextureCube.ResourceMinLODClamp = 0; + imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; + + } else if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { + imageView->desc.TextureCubeArray.MipLevels = info->subresourceRange.mipLevelCount; + imageView->desc.TextureCubeArray.MostDetailedMip = info->subresourceRange.startMipLevel; + imageView->desc.TextureCubeArray.First2DArrayFace = info->subresourceRange.startArrayLayer; + imageView->desc.TextureCubeArray.NumCubes = info->subresourceRange.layerArrayCount; + imageView->desc.TextureCubeArray.ResourceMinLODClamp = 0; + imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; + } + + // VkImageAspectFlags aspectFlags = 0; + // if (info->usages & PAL_IMAGE_VIEW_USAGE_DEPTH) {s + // aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; + // } + + // if (info->usages & PAL_IMAGE_VIEW_USAGE_STENCIL) { + // aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; + // } + + // if (info->usages & PAL_IMAGE_VIEW_USAGE_COLOR) { + // aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT; + // } + memset(imageView, 0, sizeof(ImageView)); imageView->type = info->type; imageView->usages = info->usages; imageView->image = d3dImage; + // TODO: create a temporary RTV/DTV heap and create the image view on it + *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; } @@ -4851,7 +4983,47 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout) { + HRESULT result; + Device* d3dDevice = (Device*)device; + DescriptorSetLayout* layout = nullptr; + DescriptorSetLayoutBinding* bindings = nullptr; + Uint32 count = info->bindingCount; + + layout = palAllocate(s_D3D.allocator, sizeof(DescriptorSetLayout), 0); + bindings = palAllocate(s_D3D.allocator, sizeof(DescriptorSetLayoutBinding) * count, 0); + if (!layout || !bindings) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + Uint32 offset = 0; + for (int i = 0; i < count; i++) { + DescriptorSetLayoutBinding* binding = &bindings[i]; + binding->offset = offset; + binding->range.NumDescriptors = info->bindings[i].descriptorCount; + binding->range.BaseShaderRegister = info->bindings[i].binding; + binding->range.RegisterSpace = 0; + + binding->range.OffsetInDescriptorsFromTableStart = 0; + binding->range.RangeType = 1; + + + + + // VkDescriptorSetLayoutBinding* binding = &bindings[i]; + // binding->binding = info->bindings[i].binding; + // binding->descriptorCount = info->bindings[i].descriptorCount; + // binding->descriptorType = descriptortypeToVk(info->bindings[i].descriptorType); + + // binding->pImmutableSamplers = nullptr; + // binding->stageFlags = 0; + // for (int j = 0; j < info->bindings[i].shaderStageCount; j++) { + // VkShaderStageFlagBits bit = shaderStageToVK(info->bindings[i].shaderStages[j]); + // binding->stageFlags |= bit; + // } + } + + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout) @@ -4864,17 +5036,112 @@ PalResult PAL_CALL createDescriptorPoolD3D12( const PalDescriptorPoolCreateInfo* info, PalDescriptorPool** outPool) { + HRESULT result; + Device* d3dDevice = (Device*)device; + DescriptorPool* pool = nullptr; + pool = palAllocate(s_D3D.allocator, sizeof(DescriptorPool), 0); + if (!pool) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(pool, 0, sizeof(DescriptorPool)); + pool->sets = palAllocate(s_D3D.allocator, sizeof(DescriptorSet) * info->maxDescriptorSets, 0); + if (!pool->sets) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + Uint32 count = 0; + for (int i = 0; i < info->maxDescriptorBindingSizes; i++) { + PalDescriptorPoolBindingSize* bindingSize = &info->bindingSizes[i]; + if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { + pool->maxSamplers += bindingSize->bindingCount; + + } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + pool->maxUniformBuffers += bindingSize->bindingCount; + count += bindingSize->bindingCount; + + } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER) { + pool->maxStorageBuffers += bindingSize->bindingCount; + count += bindingSize->bindingCount; + + } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + pool->maxSampledImages += bindingSize->bindingCount; + count += bindingSize->bindingCount; + + } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { + pool->maxStorageImages += bindingSize->bindingCount; + count += bindingSize->bindingCount; + + } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + pool->maxAs += bindingSize->bindingCount; + count += bindingSize->bindingCount; + } + } + + D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + desc.NumDescriptors = count * info->maxDescriptorSets; + + D3D12_DESCRIPTOR_HEAP_DESC samplerDesc = {0}; + samplerDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + samplerDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; + samplerDesc.NumDescriptors = pool->maxSamplers * info->maxDescriptorSets; + + result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( + d3dDevice->handle, + &desc, + &IID_DescHeap, + (void**)&pool->heap); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( + d3dDevice->handle, + &samplerDesc, + &IID_DescHeap, + (void**)&pool->sampleHeap); + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + pool->size = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( + d3dDevice->handle, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + pool->samplerSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( + d3dDevice->handle, + D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + + pool->maxSets = info->maxDescriptorSets; + *outPool = (PalDescriptorPool*)pool; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) { - + DescriptorPool* d3dPool = (DescriptorPool*)pool; + d3dPool->heap->lpVtbl->Release(d3dPool->heap); + d3dPool->sampleHeap->lpVtbl->Release(d3dPool->sampleHeap); + palFree(s_D3D.allocator, d3dPool->sets); + palFree(s_D3D.allocator, d3dPool); } PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool) { - + DescriptorPool* d3dPool = (DescriptorPool*)pool; + d3dPool->offset = 0; + d3dPool->samplerOffset = 0; + d3dPool->usedSets = 0; } PalResult PAL_CALL allocateDescriptorSetD3D12( @@ -4883,12 +5150,85 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( PalDescriptorSetLayout* layout, PalDescriptorSet** outSet) { + DescriptorPool* d3dPool = (DescriptorPool*)pool; + DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; + DescriptorSet* set = nullptr; -} + Uint32 reqStorageImages = 0; + Uint32 reqSamplers = 0; + Uint32 reqStorageBuffers = 0; + Uint32 reqUniformBuffers = 0; + Uint32 reqAs = 0; + Uint32 reqSampledImages = 0; -void PAL_CALL freeDescriptorSetD3D12(PalDescriptorSet* set) -{ + // get requirements for the sets using the provided layout + for (int i = 0; i < d3dLayout->bindingCount; i++) { + DescriptorSetLayoutBinding* binding = &d3dLayout->bindings[i]; + if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { + reqSamplers += binding->range.NumDescriptors; + + } else if (binding->type == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER) { + reqStorageBuffers += binding->range.NumDescriptors; + + } else if (binding->type == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { + reqStorageImages += binding->range.NumDescriptors; + + } else if (binding->type == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + reqUniformBuffers += binding->range.NumDescriptors; + + } else if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + reqSampledImages += binding->range.NumDescriptors; + + } else if (binding->type == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + reqAs += binding->range.NumDescriptors; + } + } + + // validate descriptor sets limits + if (d3dPool->usedSets + 1 > d3dPool->maxSets) { + // all sets are used + return PAL_RESULT_OUT_OF_MEMORY; + } + + // check descriptor limits + if (d3dPool->usedAs + reqAs > d3dPool->maxAs) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + if (d3dPool->usedSampledImages + reqSampledImages > d3dPool->maxSampledImages) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + if (d3dPool->usedSamplers + reqSamplers > d3dPool->maxSamplers) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + if (d3dPool->usedStorageBuffers + reqStorageBuffers > d3dPool->maxStorageBuffers) { + return PAL_RESULT_OUT_OF_MEMORY; + } + if (d3dPool->usedStorageImages + reqStorageImages > d3dPool->maxStorageImages) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + if (d3dPool->usedUniformBuffers+ reqUniformBuffers > d3dPool->maxUniformBuffers) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // assign offset base to the set so we know where to start and end for each set. + set = &d3dPool->sets[d3dPool->usedSets++]; + set->offset = d3dPool->offset; // CSV, UAV, SRV + set->samplerOffset = d3dPool->samplerOffset; + set->layout = d3dLayout; + set->pool = d3dPool; + + d3dPool->offset += reqAs + reqStorageBuffers + reqUniformBuffers; + d3dPool->offset += reqSampledImages + reqStorageImages; + d3dPool->samplerOffset += reqSamplers; + d3dPool->usedSets++; + + *outSet = (DescriptorSet*)set; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL updateDescriptorSetD3D12( @@ -4896,7 +5236,66 @@ PalResult PAL_CALL updateDescriptorSetD3D12( Uint32 count, PalDescriptorSetWriteInfo* infos) { + Device* d3dDevice = (Device*)device; + for (int i = 0; i < count; i++) { + PalDescriptorSetWriteInfo* info = &infos[i]; + DescriptorSet* set = (DescriptorSet*)info->descriptorSet; + DescriptorPool* pool = set->pool; + DescriptorSetLayout* layout = set->layout; + DescriptorSetLayoutBinding* binding = &layout->bindings[info->binding]; + + Uint32 size = 0; + Uint32 offset = 0; + ID3D12DescriptorHeap* heap = nullptr; + D3D12_DESCRIPTOR_HEAP_TYPE heapType; + if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { + heap = pool->sampleHeap; + size = pool->samplerSize; + offset = set->samplerOffset; + heapType = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; + } else { + heap = pool->heap; + size = pool->size; + offset = set->offset; + heapType = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + } + + // compute the heap index and copy all the descriptors + Uint32 index = offset + binding->offset + info->arrayElement; + if (info->arrayElement + binding->range.NumDescriptors > layout->bindingCount) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + for (int y = 0; y < binding->range.NumDescriptors; y++) { + D3D12_CPU_DESCRIPTOR_HANDLE dst = getCPUDescriptorHandle(heap, index + y, size); + + if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { + Sampler* sampler = (Sampler*)info->samplerInfo->sampler; + d3dDevice->handle->lpVtbl->CreateSampler(d3dDevice->handle, &sampler->desc, dst); + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + AccelerationStructure* tlas = (AccelerationStructure*)info->tlasInfo->tlas; + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + ImageView* imageView = (ImageView*)info->imageViewInfo->imageView; + d3dDevice->handle->lpVtbl->CreateShaderResourceView( + d3dDevice->handle, + imageView->image->handle, + &imageView->desc, + dst); + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { + ImageView* imageView = (ImageView*)info->imageViewInfo->imageView; + + } else { + // storage and uniform buffers + Buffer* buffer = (Buffer*)info->bufferInfo->buffer; + } + } + } + + return PAL_RESULT_SUCCESS; } // ================================================== diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 6d8a2e3a..4188a262 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -733,8 +733,6 @@ PalResult PAL_CALL allocateDescriptorSetVk( PalDescriptorSetLayout* layout, PalDescriptorSet** outSet); -void PAL_CALL freeDescriptorSetVk(PalDescriptorSet* set); - PalResult PAL_CALL updateDescriptorSetVk( PalDevice* device, Uint32 count, @@ -1602,8 +1600,6 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( PalDescriptorSetLayout* layout, PalDescriptorSet** outSet); -void PAL_CALL freeDescriptorSetD3D12(PalDescriptorSet* set); - PalResult PAL_CALL updateDescriptorSetD3D12( PalDevice* device, Uint32 count, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index fcdbd5ed..6a8ca7e9 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -335,7 +335,6 @@ typedef struct { PFN_vkDestroyDescriptorPool destroyDescriptorPool; PFN_vkResetDescriptorPool resetDescriptorPool; PFN_vkAllocateDescriptorSets allocateDescriptorSet; - PFN_vkFreeDescriptorSets freeDescriptorSet; PFN_vkUpdateDescriptorSets updateDescriptorSet; PFN_vkCreatePipelineLayout createPipelineLayout; @@ -2823,10 +2822,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkAllocateDescriptorSets"); - s_Vk.freeDescriptorSet = (PFN_vkFreeDescriptorSets)loadProc( - s_Vk.handle, - "vkFreeDescriptorSets"); - s_Vk.updateDescriptorSet = (PFN_vkUpdateDescriptorSets)loadProc( s_Vk.handle, "vkUpdateDescriptorSets"); From e03fdfcf6da55b95d0aefd36a86003ab0737d8ad Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 14 Apr 2026 06:36:54 +0000 Subject: [PATCH 156/372] add image aspect and remove image view usages API --- include/pal/pal_graphics.h | 71 ++++------- src/graphics/pal_d3d12.c | 242 ++++++++++++++---------------------- src/graphics/pal_graphics.c | 22 ---- src/graphics/pal_vulkan.c | 144 +++++---------------- tests/clear_color_test.c | 10 +- tests/mesh_test.c | 23 ++-- tests/texture_test.c | 25 ++-- tests/triangle_test.c | 23 ++-- 8 files changed, 183 insertions(+), 377 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index f5a0fe39..30819909 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -525,26 +525,6 @@ typedef enum { PAL_IMAGE_USAGE_SAMPLED = PAL_BIT(5) } PalImageUsages; -/** - * @enum PalImageViewUsages - * @brief Image view usages. Multiple image view usages can be OR'ed together using bitwise - * OR operator (`|`). Not all combination are valid. - * - * All image view usages follow the format `PAL_IMAGE_VIEW_USAGE_**` for - * consistency and API use. - * - * @since 1.4 - * @ingroup pal_graphics - */ -typedef enum { - PAL_IMAGE_VIEW_USAGE_UNDEFINED = 0, - - PAL_IMAGE_VIEW_USAGE_COLOR = PAL_BIT(0), - PAL_IMAGE_VIEW_USAGE_DEPTH = PAL_BIT(1), - PAL_IMAGE_VIEW_USAGE_STENCIL = PAL_BIT(2), - PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE = PAL_BIT(3) -} PalImageViewUsages; - /** * @enum PalShaderFormats * @brief Shader formats. This is a bitmask. @@ -676,6 +656,23 @@ typedef enum { PAL_IMAGE_TYPE_3D } PalImageType; +/** + * @enum PalImageAspect + * @brief Image aspects. + * + * All image aspect follow the format `PAL_IMAGE_ASPECT_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_IMAGE_ASPECT_COLOR, + PAL_IMAGE_ASPECT_DEPTH, + PAL_IMAGE_ASPECT_STENCIL, + PAL_IMAGE_ASPECT_DEPTH_STENCIL +} PalImageAspect; + /** * @enum PalImageViewType * @brief Image view types. @@ -1605,7 +1602,6 @@ typedef struct { typedef struct { PalFormat format; /**< The format.*/ PalImageUsages usages; /**< Supported image usages of the format.*/ - PalImageViewUsages viewUsages; /**< Supported image view usages of the format.*/ PalSampleCount maxSampleCount; /**< Supported multisample count.*/ } PalFormatInfo; @@ -2277,6 +2273,7 @@ typedef struct { Uint32 mipLevelCount; Uint32 startArrayLayer; Uint32 layerArrayCount; + PalImageAspect aspect; /**< Must be compatible with the image format.*/ } PalImageSubresourceRange; /** @@ -2316,6 +2313,7 @@ typedef struct { Uint32 imageWidth; Uint32 imageHeight; Uint32 imageDepth; + PalImageAspect imageAspect; } PalBufferImageCopyInfo; /** @@ -2342,6 +2340,7 @@ typedef struct { Uint32 width; Uint32 height; Uint32 depth; + PalImageAspect aspect; } PalImageCopyInfo; /** @@ -2374,8 +2373,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + PalFormat format; /**< Must be compatible with the image format.*/ PalImageViewType type; /**< (eg. PAL_IMAGE_VIEW_TYPE_2D).*/ - PalImageViewUsages usages; /**< (eg. PAL_IMAGE_VIEW_USAGE_COLOR).*/ PalImageSubresourceRange subresourceRange; } PalImageViewCreateInfo; @@ -2810,15 +2809,6 @@ typedef struct { PalAdapter* adapter, PalFormat format); - /** - * Backend implementation of ::palQueryFormatImageViewUsages. - * - * Must obey the rules and semantics documented in palQueryFormatImageViewUsages(). - */ - PalImageViewUsages PAL_CALL (*queryFormatImageViewUsages)( - PalAdapter* adapter, - PalFormat format); - /** * Backend implementation of ::palQueryFormatSampleCount. * @@ -4466,25 +4456,6 @@ PAL_API PalImageUsages PAL_CALL palQueryFormatImageUsages( PalAdapter* adapter, PalFormat format); -/** - * @brief Checks supported image view usages associated with a format. - * - * The graphics system must be initialized before this call. - * - * @param[in] adapter Adapter to query format on. - * @param[in] format Format to query image view usages for. - * - * @return Supported image view usages on success otherwise `0` on failure. - * - * Thread safety: Thread safe. - * - * @since 1.4 - * @ingroup pal_graphics - */ -PAL_API PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( - PalAdapter* adapter, - PalFormat format); - /** * @brief Checks supported sample count associated with a format. * diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index f5c05aeb..dd2179ad 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -129,7 +129,6 @@ typedef struct { const PalGraphicsBackend* backend; bool belongsToSwapchain; - Uint32 planeCount; ID3D12Device* device; ID3D12Resource* handle; PalImageInfo info; @@ -139,8 +138,6 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - PalImageViewType type; - PalImageViewUsages usages; D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; Image* image; D3D12_SHADER_RESOURCE_VIEW_DESC desc; @@ -2205,32 +2202,6 @@ PalResult PAL_CALL enumerateFormatsD3D12( PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; fmtInfo->format = (PalFormat)i; fmtInfo->usages = ImageUsageFromD3D12(support.Support1); - - if (support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE || - support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD) { - fmtInfo->usages |= PAL_IMAGE_USAGE_STORAGE; - } - - fmtInfo->viewUsages = 0; - if (fmtInfo->usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_COLOR; - if (i == PAL_FORMAT_R8_UINT) { - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; - } - } - - if (fmtInfo->usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { - if (i == PAL_FORMAT_S8_UINT) { - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - - } else if (i == PAL_FORMAT_D16_UNORM || i == PAL_FORMAT_D32_SFLOAT) { - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - - } else { - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - } - } } } else { @@ -2311,62 +2282,6 @@ PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( return usages; } -PalImageViewUsages PAL_CALL queryFormatImageViewUsagesD3D12( - PalAdapter* adapter, - PalFormat format) -{ - HRESULT result; - Adapter* d3dAdapter = (Adapter*)adapter; - ID3D12Device* device = d3dAdapter->tmpDevice; - D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; - - DXGI_FORMAT fmt = formatToD3D12(format); - if (fmt == DXGI_FORMAT_UNKNOWN) { - return 0; - } - - support.Format = fmt; - result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, - sizeof(support)); - - if (FAILED(result)) { - return 0; - } - - if (support.Support1 == 0 && support.Support2 == 0) { - // format not supported - return 0; - } - - PalImageUsages imageUsages = ImageUsageFromD3D12(support.Support1); - if (support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE || - support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD) { - imageUsages |= PAL_IMAGE_USAGE_STORAGE; - } - - PalImageViewUsages usages = 0; - if (imageUsages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { - usages |= PAL_IMAGE_VIEW_USAGE_COLOR; - if (format == PAL_FORMAT_R8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; - } - } - - if (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { - if (format == PAL_FORMAT_D16_UNORM || format == PAL_FORMAT_D32_SFLOAT) { - usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - - } else { - usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - } - } - return usages; -} - PalSampleCount PAL_CALL queryFormatSampleCountD3D12( PalAdapter* adapter, PalFormat format) @@ -2491,14 +2406,6 @@ PalResult PAL_CALL createImageD3D12( image->info.sampleCount = info->sampleCount; image->info.width = info->width; - // get plane count from image format - image->planeCount = 1; // for color or depth - if (info->format == PAL_FORMAT_D32_SFLOAT_S8_UINT || - info->format == PAL_FORMAT_D16_UNORM_S8_UINT || - info->format == PAL_FORMAT_D24_UNORM_S8_UINT) { - image->planeCount = 2; - } - image->device = d3dDevice->handle; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; @@ -2676,22 +2583,7 @@ PalResult PAL_CALL createImageViewD3D12( imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; } - // VkImageAspectFlags aspectFlags = 0; - // if (info->usages & PAL_IMAGE_VIEW_USAGE_DEPTH) {s - // aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; - // } - - // if (info->usages & PAL_IMAGE_VIEW_USAGE_STENCIL) { - // aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - // } - - // if (info->usages & PAL_IMAGE_VIEW_USAGE_COLOR) { - // aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT; - // } - memset(imageView, 0, sizeof(ImageView)); - imageView->type = info->type; - imageView->usages = info->usages; imageView->image = d3dImage; // TODO: create a temporary RTV/DTV heap and create the image view on it @@ -4071,24 +3963,36 @@ PalResult PAL_CALL cmdCopyBufferToImageD3D12( Uint64 rowPitch = alignD3D12((Uint64)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); footPrint->Footprint.RowPitch = (UINT)rowPitch; + Uint32 planeCount = 1; + if (copyInfo->imageAspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { + planeCount = 2; + } + D3D12_BOX box = {0}; box.right = copyInfo->imageWidth; box.bottom = copyInfo->imageHeight; box.back = copyInfo->imageDepth; - // copy the array layers manually - for (Uint32 layer = 0; layer < copyInfo->ImageArrayLayerCount; layer++) { - Uint32 tmp = (copyInfo->ImageStartArrayLayer + layer) * dst->info.mipLevelCount; - dstLocation.SubresourceIndex = copyInfo->ImageMipLevel + tmp; + Uint32 level = copyInfo->ImageMipLevel; + Uint32 startLayer = copyInfo->ImageStartArrayLayer; + Uint32 layerCount = copyInfo->ImageArrayLayerCount; + Uint32 maxLayers = dst->info.depthOrArraySize; + Uint32 maxLevels = dst->info.mipLevelCount; - d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle6, - &dstLocation, - copyInfo->imageOffsetX, - copyInfo->imageOffsetY, - copyInfo->imageOffsetZ, - &srcLocation, - &box); + for (Uint32 plane = 0; plane < planeCount; plane++) { + for (Uint32 layer = startLayer; layer < startLayer + layerCount; layer++) { + Uint32 index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); + + dstLocation.SubresourceIndex = index; + d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( + d3dCmdBuffer->handle6, + &dstLocation, + copyInfo->imageOffsetX, + copyInfo->imageOffsetY, + copyInfo->imageOffsetZ, + &srcLocation, + &box); + } } return PAL_RESULT_SUCCESS; @@ -4120,21 +4024,41 @@ PalResult PAL_CALL cmdCopyImageD3D12( box.bottom = copyInfo->srcOffsetY + copyInfo->height; box.back = copyInfo->srcOffsetZ + copyInfo->depth; - // copy the array layers manually - for (Uint32 layer = 0; layer < copyInfo->arrayLayerCount; layer++) { - Uint32 dstTmp = (copyInfo->dstStartArrayLayer + layer) * dstImage->info.mipLevelCount; - Uint32 srcTmp = (copyInfo->srcStartArrayLayer + layer) * srcImage->info.mipLevelCount; - dstLocation.SubresourceIndex = copyInfo->dstMipLevel + dstTmp; - srcLocation.SubresourceIndex = copyInfo->srcMipLevel + srcTmp; - - d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle6, - &dstLocation, - copyInfo->dstOffsetX, - copyInfo->dstOffsetY, - copyInfo->dstOffsetZ, - &srcLocation, - &box); + Uint32 planeCount = 1; + Uint32 layerCount = copyInfo->arrayLayerCount; + if (copyInfo->aspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { + planeCount = 2; + } + + Uint32 dstLevel = copyInfo->dstMipLevel; + Uint32 dstStartLayer = copyInfo->dstStartArrayLayer; + Uint32 dstMaxLayers = dstImage->info.depthOrArraySize; + Uint32 dstMaxLevels = dstImage->info.mipLevelCount; + + Uint32 srcLevel = copyInfo->srcMipLevel; + Uint32 srcStartLayer = copyInfo->srcStartArrayLayer; + Uint32 srcMaxLayers = srcImage->info.depthOrArraySize; + Uint32 srcMaxLevels = srcImage->info.mipLevelCount; + + for (Uint32 plane = 0; plane < planeCount; plane++) { + for (Uint32 layer = 0; layer + layerCount; layer++) { + // clang-format off + Uint32 dstIndex = dstLevel + (dstStartLayer + layer * dstMaxLevels) + (plane * dstMaxLevels * dstMaxLayers); + Uint32 srcIndex = srcLevel + (srcStartLayer + layer * srcMaxLevels) + (plane * srcMaxLevels * srcMaxLayers); + // clang-format on + + dstLocation.SubresourceIndex = dstIndex; + srcLocation.SubresourceIndex = srcIndex; + + d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( + d3dCmdBuffer->handle6, + &dstLocation, + copyInfo->dstOffsetX, + copyInfo->dstOffsetY, + copyInfo->dstOffsetZ, + &srcLocation, + &box); + } } return PAL_RESULT_SUCCESS; @@ -4176,19 +4100,31 @@ PalResult PAL_CALL cmdCopyImageToBufferD3D12( box.bottom = copyInfo->imageOffsetY + copyInfo->imageHeight; box.back = copyInfo->imageOffsetX + copyInfo->imageDepth; - // copy the array layers manually - for (Uint32 layer = 0; layer < copyInfo->ImageArrayLayerCount; layer++) { - Uint32 tmp = (copyInfo->ImageStartArrayLayer + layer) * src->info.mipLevelCount; - srcLocation.SubresourceIndex = copyInfo->ImageMipLevel + tmp; + Uint32 planeCount = 1; + if (copyInfo->imageAspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { + planeCount = 2; + } + + Uint32 level = copyInfo->ImageMipLevel; + Uint32 startLayer = copyInfo->ImageStartArrayLayer; + Uint32 layerCount = copyInfo->ImageArrayLayerCount; + Uint32 maxLayers = src->info.depthOrArraySize; + Uint32 maxLevels = src->info.mipLevelCount; - d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle6, - &dstLocation, - 0, - 0, - 0, - &srcLocation, - &box); + for (Uint32 plane = 0; plane < planeCount; plane++) { + for (Uint32 layer = startLayer; layer < startLayer + layerCount; layer++) { + Uint32 index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); + + srcLocation.SubresourceIndex = index; + d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( + d3dCmdBuffer->handle6, + &dstLocation, + 0, + 0, + 0, + &srcLocation, + &box); + } } return PAL_RESULT_SUCCESS; @@ -4550,16 +4486,20 @@ PalResult PAL_CALL cmdImageBarrierD3D12( return PAL_RESULT_SUCCESS; } + Uint32 planeCount = 1; // for color or depth + if (subresourceRange->aspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { + planeCount = 2; + } + D3D12_RESOURCE_BARRIER* barriers = nullptr; Uint32 levelCount = subresourceRange->mipLevelCount; Uint32 layerCount = subresourceRange->layerArrayCount; - Uint32 planeCount = d3dImage->planeCount; Uint32 startLevel = subresourceRange->startMipLevel; Uint32 startLayer = subresourceRange->startArrayLayer; Uint32 maxLevels = d3dImage->info.mipLevelCount; Uint32 maxLayers = d3dImage->info.depthOrArraySize; - Uint32 barrierCount = layerCount * levelCount * d3dImage->planeCount; + Uint32 barrierCount = layerCount * levelCount * planeCount; if (startLevel == 0 && levelCount == maxLevels && startLayer == 0 && layerCount == maxLayers) { // full resource @@ -4591,7 +4531,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( } Uint32 count = 0; - for (Uint32 plane = 0; plane < d3dImage->planeCount; plane++) { + for (Uint32 plane = 0; plane < planeCount; plane++) { for (Uint32 layer = startLayer; layer < startLayer + layerCount; layer++) { for (Uint32 level = startLevel; level < startLevel + levelCount; level++) { Uint32 index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); @@ -5227,7 +5167,7 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( d3dPool->samplerOffset += reqSamplers; d3dPool->usedSets++; - *outSet = (DescriptorSet*)set; + *outSet = (PalDescriptorSet*)set; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 4188a262..04fc4af1 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -213,10 +213,6 @@ PalImageUsages PAL_CALL queryFormatImageUsagesVk( PalAdapter* adapter, PalFormat format); -PalImageViewUsages PAL_CALL queryFormatImageViewUsagesVk( - PalAdapter* adapter, - PalFormat format); - PalSampleCount PAL_CALL queryFormatSampleCountVk( PalAdapter* adapter, PalFormat format); @@ -814,7 +810,6 @@ static PalGraphicsBackend s_VkBackend = { .enumerateFormats = enumerateFormatsVk, .isFormatSupported = isFormatSupportedVk, .queryFormatImageUsages = queryFormatImageUsagesVk, - .queryFormatImageViewUsages = queryFormatImageViewUsagesVk, .queryFormatSampleCount = queryFormatSampleCountVk, // image @@ -1080,10 +1075,6 @@ PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( PalAdapter* adapter, PalFormat format); -PalImageViewUsages PAL_CALL queryFormatImageViewUsagesD3D12( - PalAdapter* adapter, - PalFormat format); - PalSampleCount PAL_CALL queryFormatSampleCountD3D12( PalAdapter* adapter, PalFormat format); @@ -1681,7 +1672,6 @@ static PalGraphicsBackend s_D3D12Backend = { .enumerateFormats = enumerateFormatsD3D12, .isFormatSupported = isFormatSupportedD3D12, .queryFormatImageUsages = queryFormatImageUsagesD3D12, - .queryFormatImageViewUsages = queryFormatImageViewUsagesD3D12, .queryFormatSampleCount = queryFormatSampleCountD3D12, // image @@ -1887,7 +1877,6 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->enumerateFormats || !backend->isFormatSupported || !backend->queryFormatImageUsages || - !backend->queryFormatImageViewUsages || !backend->queryFormatSampleCount || // image @@ -2500,17 +2489,6 @@ PalImageUsages PAL_CALL palQueryFormatImageUsages( return adapter->backend->queryFormatImageUsages(adapter, format); } -PalImageViewUsages PAL_CALL palQueryFormatImageViewUsages( - PalAdapter* adapter, - PalFormat format) -{ - if (!s_Graphics.initialized || !adapter) { - return PAL_IMAGE_VIEW_USAGE_UNDEFINED; - } - - return adapter->backend->queryFormatImageViewUsages(adapter, format); -} - PalSampleCount PAL_CALL palQueryFormatSampleCount( PalAdapter* adapter, PalFormat format) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 6a8ca7e9..79ea6d0f 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -441,7 +441,6 @@ typedef struct { const PalGraphicsBackend* backend; bool belongsToSwapchain; - VkImageAspectFlags aspectMask; Device* device; Memory* memory; VkImage handle; @@ -451,12 +450,10 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - VkImageViewType type; - PalImageViewUsages usages; + Uint32 layerCount; Device* device; Image* image; VkImageView handle; - VkImageSubresourceRange range; } ImageView; typedef struct { @@ -2491,6 +2488,25 @@ static Uint32 getFormatSizeVk(PalFormat format) return 0; } +static VkImageAspectFlags imageAspectToVk(PalImageAspect aspect) +{ + switch (aspect) { + case PAL_IMAGE_ASPECT_COLOR: + return VK_IMAGE_ASPECT_COLOR_BIT; + + case PAL_IMAGE_ASPECT_DEPTH: + return VK_IMAGE_ASPECT_DEPTH_BIT; + + case PAL_IMAGE_ASPECT_STENCIL: + return VK_IMAGE_ASPECT_STENCIL_BIT; + + case PAL_IMAGE_ASPECT_DEPTH_STENCIL: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + } + + return VK_IMAGE_ASPECT_COLOR_BIT; +} + // ================================================== // Adapter // ================================================== @@ -4941,27 +4957,6 @@ PalResult PAL_CALL enumerateFormatsVk( PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; fmtInfo->format = (PalFormat)i; fmtInfo->usages = ImageUsageFromVk(props.optimalTilingFeatures); - - fmtInfo->viewUsages = 0; - if (fmtInfo->usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_COLOR; - if (i == PAL_FORMAT_R8_UINT) { - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; - } - } - - if (fmtInfo->usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { - if (i == PAL_FORMAT_S8_UINT) { - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - - } else if (i == PAL_FORMAT_D16_UNORM || i == PAL_FORMAT_D32_SFLOAT) { - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - - } else { - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - fmtInfo->viewUsages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - } - } } } else { @@ -5008,44 +5003,6 @@ PalImageUsages PAL_CALL queryFormatImageUsagesVk( return ImageUsageFromVk(props.optimalTilingFeatures); } -PalImageViewUsages PAL_CALL queryFormatImageViewUsagesVk( - PalAdapter* adapter, - PalFormat format) -{ - Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; - VkFormatProperties props = {0}; - - VkFormat fmt = formatToVk(format); - s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); - if (props.optimalTilingFeatures == 0) { - return PAL_IMAGE_VIEW_USAGE_UNDEFINED; - } - - PalImageViewUsages usages = 0; - PalImageUsages imageUsages = ImageUsageFromVk(props.optimalTilingFeatures); - if (imageUsages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { - usages |= PAL_IMAGE_VIEW_USAGE_COLOR; - if (format == PAL_FORMAT_R8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_FRAGMENT_SHADING_RATE; - } - } - - if (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { - if (format == PAL_FORMAT_S8_UINT) { - usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - - } else if (format == PAL_FORMAT_D16_UNORM || format == PAL_FORMAT_D32_SFLOAT) { - usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - - } else { - usages |= PAL_IMAGE_VIEW_USAGE_DEPTH; - usages |= PAL_IMAGE_VIEW_USAGE_STENCIL; - } - } - return usages; -} - PalSampleCount PAL_CALL queryFormatSampleCountVk( PalAdapter* adapter, PalFormat format) @@ -5146,23 +5103,6 @@ PalResult PAL_CALL createImageVk( image->info.sampleCount = info->sampleCount; image->info.width = info->width; - // get aspect masks from image format - image->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - if (info->format == PAL_FORMAT_S8_UINT) { - image->aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - } - - if (info->format == PAL_FORMAT_D16_UNORM || info->format == PAL_FORMAT_D32_SFLOAT) { - image->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - } - - if (info->format == PAL_FORMAT_D32_SFLOAT_S8_UINT || - info->format == PAL_FORMAT_D16_UNORM_S8_UINT || - info->format == PAL_FORMAT_D24_UNORM_S8_UINT) { - image->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - image->aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - image->memory = nullptr; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; @@ -5290,29 +5230,16 @@ PalResult PAL_CALL createImageViewVk( VkImageViewCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.format = formatToVk(vkImage->info.format); + createInfo.format = formatToVk(info->format); createInfo.image = vkImage->handle; + createInfo.viewType = imageViewTypeToVk(info->type); + createInfo.subresourceRange.aspectMask = imageAspectToVk(info->subresourceRange.aspect); createInfo.subresourceRange.baseArrayLayer = info->subresourceRange.startArrayLayer; createInfo.subresourceRange.baseMipLevel = info->subresourceRange.startMipLevel; createInfo.subresourceRange.levelCount = info->subresourceRange.mipLevelCount; createInfo.subresourceRange.layerCount = info->subresourceRange.layerArrayCount; - createInfo.viewType = imageViewTypeToVk(info->type); - - VkImageAspectFlags aspectFlags = 0; - if (info->usages & PAL_IMAGE_VIEW_USAGE_DEPTH) { - aspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT; - } - - if (info->usages & PAL_IMAGE_VIEW_USAGE_STENCIL) { - aspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT; - } - - if (info->usages & PAL_IMAGE_VIEW_USAGE_COLOR) { - aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT; - } - createInfo.subresourceRange.aspectMask = aspectFlags; result = s_Vk.createImageView( vkDevice->handle, &createInfo, @@ -5326,9 +5253,7 @@ PalResult PAL_CALL createImageViewVk( imageView->device = vkDevice; imageView->image = vkImage; - imageView->type = createInfo.viewType; - imageView->usages = info->usages; - imageView->range = createInfo.subresourceRange; + imageView->layerCount = createInfo.subresourceRange.layerCount; *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; @@ -5761,7 +5686,6 @@ PalResult PAL_CALL createSwapchainVk( image->info.mipLevelCount = 1; image->info.sampleCount = PAL_SAMPLE_COUNT_1; // swapchain images are not multisampled image->info.type = PAL_IMAGE_TYPE_2D; - image->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; } palFree(s_Vk.allocator, images); @@ -6709,12 +6633,12 @@ PalResult PAL_CALL cmdBeginRenderingVk( attachment->imageLayout = layout; // compute layer count and render area - layerCount = minVk(layerCount, imageView->range.layerCount); + layerCount = minVk(layerCount, imageView->layerCount); renderWidth = minVk(renderWidth, imageView->image->info.width); renderHeight = minVk(renderHeight, imageView->image->info.height); if (resolveImageView) { - layerCount = minVk(layerCount, resolveImageView->range.layerCount); + layerCount = minVk(layerCount, resolveImageView->layerCount); renderWidth = minVk(renderWidth, resolveImageView->image->info.width); renderHeight = minVk(renderHeight, resolveImageView->image->info.height); } @@ -6800,12 +6724,12 @@ PalResult PAL_CALL cmdBeginRenderingVk( rendering.pStencilAttachment = &stencilAttachment; // compute layer count and render area - layerCount = minVk(layerCount, imageView->range.layerCount); + layerCount = minVk(layerCount, imageView->layerCount); renderWidth = minVk(renderWidth, imageView->image->info.width); renderHeight = minVk(renderHeight, imageView->image->info.height); if (resolveImageView) { - layerCount = minVk(layerCount, resolveImageView->range.layerCount); + layerCount = minVk(layerCount, resolveImageView->layerCount); renderWidth = minVk(renderWidth, resolveImageView->image->info.width); renderHeight = minVk(renderHeight, resolveImageView->image->info.height); } @@ -6826,7 +6750,7 @@ PalResult PAL_CALL cmdBeginRenderingVk( rendering.pNext = &fsrInfo; // compute layer count and render area - layerCount = minVk(layerCount, imageView->range.layerCount); + layerCount = minVk(layerCount, imageView->layerCount); renderWidth = minVk(renderWidth, imageView->image->info.width); renderHeight = minVk(renderHeight, imageView->image->info.height); } @@ -6896,7 +6820,7 @@ PalResult PAL_CALL cmdCopyBufferToImageVk( copyRegion.imageExtent.height = copyInfo->imageHeight; copyRegion.imageExtent.depth = copyInfo->imageDepth; - copyRegion.imageSubresource.aspectMask = dst->aspectMask; + copyRegion.imageSubresource.aspectMask = imageAspectToVk(copyInfo->imageAspect); copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; copyRegion.imageSubresource.layerCount = copyInfo->ImageArrayLayerCount; copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; @@ -6935,12 +6859,12 @@ PalResult PAL_CALL cmdCopyImageVk( copyRegion.extent.height = copyInfo->height; copyRegion.extent.depth = copyInfo->depth; - copyRegion.dstSubresource.aspectMask = dstImage->aspectMask; + copyRegion.dstSubresource.aspectMask = imageAspectToVk(copyInfo->aspect); copyRegion.dstSubresource.baseArrayLayer = copyInfo->dstStartArrayLayer; copyRegion.dstSubresource.layerCount = copyInfo->arrayLayerCount; copyRegion.dstSubresource.mipLevel = copyInfo->dstMipLevel; - copyRegion.srcSubresource.aspectMask = srcImage->aspectMask; + copyRegion.srcSubresource.aspectMask = imageAspectToVk(copyInfo->aspect); copyRegion.srcSubresource.baseArrayLayer = copyInfo->srcStartArrayLayer; copyRegion.srcSubresource.layerCount = copyInfo->arrayLayerCount; copyRegion.srcSubresource.mipLevel = copyInfo->srcMipLevel; @@ -6980,7 +6904,7 @@ PalResult PAL_CALL cmdCopyImageToBufferVk( copyRegion.imageExtent.height = copyInfo->imageHeight; copyRegion.imageExtent.depth = copyInfo->imageDepth; - copyRegion.imageSubresource.aspectMask = src->aspectMask; + copyRegion.imageSubresource.aspectMask = imageAspectToVk(copyInfo->imageAspect); copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; copyRegion.imageSubresource.layerCount = copyInfo->ImageArrayLayerCount; copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; @@ -7323,7 +7247,7 @@ PalResult PAL_CALL cmdImageBarrierVk( barrier.newLayout = new.layout; barrier.image = vkImage->handle; - barrier.subresourceRange.aspectMask = vkImage->aspectMask; + barrier.subresourceRange.aspectMask = imageAspectToVk(subresourceRange->aspect); barrier.subresourceRange.baseArrayLayer = subresourceRange->startArrayLayer; barrier.subresourceRange.baseMipLevel = subresourceRange->startMipLevel; barrier.subresourceRange.layerCount = subresourceRange->layerArrayCount; diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 07786c7b..7c6c591b 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -260,13 +260,21 @@ bool clearColorTest() return false; } + PalImageInfo imageInfo; + result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } + PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; imageViewCreateInfo.subresourceRange.layerArrayCount = 1; imageViewCreateInfo.subresourceRange.mipLevelCount = 1; imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; + imageViewCreateInfo.format = imageInfo.format; for (int i = 0; i < imageCount; i++) { // get swapchain image diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 88337f8d..337cf50e 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -313,13 +313,21 @@ bool meshTest() return false; } + PalImageInfo imageInfo; + result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } + PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; imageViewCreateInfo.subresourceRange.layerArrayCount = 1; imageViewCreateInfo.subresourceRange.mipLevelCount = 1; imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; + imageViewCreateInfo.format = imageInfo.format; for (int i = 0; i < imageCount; i++) { // get swapchain image @@ -456,19 +464,6 @@ bool meshTest() return false; } - // the graphics pipeline needs the layout of the rendering - // info it will be used with - // we get the any image from the swapchain and get the format - // on the image since our color attachment takes a swapchain image - PalImage* image = palGetSwapchainImage(swapchain, 0); - PalImageInfo imageInfo = {0}; - result = palGetImageInfo(image, &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); - return false; - } - PalRenderingLayoutInfo renderingLayoutInfo = {0}; renderingLayoutInfo.colorAttachentCount = 1; renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; diff --git a/tests/texture_test.c b/tests/texture_test.c index f03692f7..1ba0a8c8 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -340,13 +340,21 @@ bool textureTest() return false; } + PalImageInfo imageInfo; + result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } + PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; imageViewCreateInfo.subresourceRange.layerArrayCount = 1; imageViewCreateInfo.subresourceRange.mipLevelCount = 1; imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; + imageViewCreateInfo.format = imageInfo.format; for (int i = 0; i < imageCount; i++) { // get swapchain image @@ -792,8 +800,8 @@ bool textureTest() PalImageView* checkerboardImageView = nullptr; PalImageViewCreateInfo checkerboardImageViewCreateInfo = {0}; checkerboardImageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - checkerboardImageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; checkerboardImageViewCreateInfo.subresourceRange = checkerboardRange; + checkerboardImageViewCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; result = palCreateImageView( device, @@ -1006,19 +1014,6 @@ bool textureTest() return false; } - // the graphics pipeline needs the layout of the rendering - // info it will be used with - // we get the any image from the swapchain and get the format - // on the image since our color attachment takes a swapchain image - PalImage* image = palGetSwapchainImage(swapchain, 0); - PalImageInfo imageInfo = {0}; - result = palGetImageInfo(image, &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); - return false; - } - PalRenderingLayoutInfo renderingLayoutInfo = {0}; renderingLayoutInfo.colorAttachentCount = 1; renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 8d714d12..3cbc7818 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -306,13 +306,21 @@ bool triangleTest() return false; } + PalImageInfo imageInfo; + result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } + PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.usages = PAL_IMAGE_VIEW_USAGE_COLOR; imageViewCreateInfo.subresourceRange.layerArrayCount = 1; imageViewCreateInfo.subresourceRange.mipLevelCount = 1; imageViewCreateInfo.subresourceRange.startArrayLayer = 0; imageViewCreateInfo.subresourceRange.startMipLevel = 0; + imageViewCreateInfo.format = imageInfo.format; for (int i = 0; i < imageCount; i++) { // get swapchain image @@ -612,19 +620,6 @@ bool triangleTest() return false; } - // the graphics pipeline needs the layout of the rendering - // info it will be used with - // we get the any image from the swapchain and get the format - // on the image since our color attachment takes a swapchain image - PalImage* image = palGetSwapchainImage(swapchain, 0); - PalImageInfo imageInfo = {0}; - result = palGetImageInfo(image, &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); - return false; - } - PalRenderingLayoutInfo renderingLayoutInfo = {0}; renderingLayoutInfo.colorAttachentCount = 1; renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; From db34167d3534290ebda940ba52da45b496d01a81 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 14 Apr 2026 15:20:58 +0000 Subject: [PATCH 157/372] finish update descriptor set API --- include/pal/pal_graphics.h | 1 + src/graphics/pal_d3d12.c | 418 +++++++++++++++++++++++++++++++------ tests/tests_main.c | 2 + 3 files changed, 357 insertions(+), 64 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 30819909..8d09508d 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2178,6 +2178,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + bool readOnly; /**< For PAL_DESCRIPTOR_TYPE_STORAGE.*/ Uint32 size; Uint64 offset; PalBuffer* buffer; diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index dd2179ad..b79b9968 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -46,6 +46,8 @@ freely, subject to the following restrictions: #define MAX_ATTACHMENTS 32 #define TEXTURE_PITCH 256 +#define MAX_RTV 1024 +#define MAX_DSV 512 // IIDS const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; @@ -95,6 +97,20 @@ typedef struct { const PalAllocator* allocator; } D3D12; +typedef struct { + Uint32 incrementSize; + Uint32 freeTop; + ID3D12DescriptorHeap* heap; + Uint32 freeList[MAX_RTV]; +} RTVHeapAllocator; + +typedef struct { + Uint32 incrementSize; + Uint32 freeTop; + ID3D12DescriptorHeap* heap; + Uint32 freeList[MAX_DSV]; +} DSVHeapAllocator; + typedef struct { const PalGraphicsBackend* backend; @@ -108,6 +124,8 @@ typedef struct { ID3D12InfoQueue* infoQueue; ID3D12CommandQueue* queue; ID3D12Device* handle; + RTVHeapAllocator rtvAllocator; + DSVHeapAllocator dsvAllocator; } Device; typedef struct { @@ -138,9 +156,12 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; + Uint32 heapIndex; + PalImageViewType type; + DXGI_FORMAT format; Image* image; - D3D12_SHADER_RESOURCE_VIEW_DESC desc; + Device* device; + PalImageSubresourceRange range; } ImageView; typedef struct { @@ -1215,6 +1236,147 @@ static D3D12_CPU_DESCRIPTOR_HANDLE getCPUDescriptorHandle( return handle; } +static void fillSubresourceD3D12( + PalImageViewType type, + const PalImageSubresourceRange* range, + D3D12_RENDER_TARGET_VIEW_DESC* rtvDesc, + D3D12_DEPTH_STENCIL_VIEW_DESC* dsvDesc, + D3D12_SHADER_RESOURCE_VIEW_DESC* srvDesc, + D3D12_UNORDERED_ACCESS_VIEW_DESC* uavDesc) +{ + if (rtvDesc) { + if (type == PAL_IMAGE_VIEW_TYPE_1D) { + rtvDesc->Texture1D.MipSlice = range->startMipLevel; + rtvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; + + } else if (type == PAL_IMAGE_VIEW_TYPE_1D_ARRAY) { + rtvDesc->Texture1DArray.MipSlice = range->startMipLevel; + rtvDesc->Texture1DArray.FirstArraySlice = range->startArrayLayer; + rtvDesc->Texture1DArray.ArraySize = range->layerArrayCount; + rtvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + + } else if (type == PAL_IMAGE_VIEW_TYPE_2D) { + rtvDesc->Texture2D.MipSlice = range->startMipLevel; + rtvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + + } else if (type == PAL_IMAGE_VIEW_TYPE_2D_ARRAY) { + rtvDesc->Texture2DArray.MipSlice = range->startMipLevel; + rtvDesc->Texture2DArray.FirstArraySlice = range->startArrayLayer; + rtvDesc->Texture2DArray.ArraySize = range->layerArrayCount; + rtvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + + } else if (type == PAL_IMAGE_VIEW_TYPE_3D) { + rtvDesc->Texture3D.MipSlice = range->startMipLevel; + rtvDesc->Texture3D.FirstWSlice = range->startArrayLayer; + rtvDesc->Texture3D.WSize = range->layerArrayCount; + rtvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; + } + return; + + } else if (dsvDesc) { + if (range->aspect == PAL_IMAGE_ASPECT_DEPTH) { + dsvDesc->Flags = D3D12_DSV_FLAG_READ_ONLY_DEPTH; + } else if (range->aspect == PAL_IMAGE_ASPECT_STENCIL) { + dsvDesc->Flags = D3D12_DSV_FLAG_READ_ONLY_STENCIL; + } + + if (type == PAL_IMAGE_VIEW_TYPE_1D) { + dsvDesc->Texture1D.MipSlice = range->startMipLevel; + dsvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; + + } else if (type == PAL_IMAGE_VIEW_TYPE_1D_ARRAY) { + dsvDesc->Texture1DArray.MipSlice = range->startMipLevel; + dsvDesc->Texture1DArray.FirstArraySlice = range->startArrayLayer; + dsvDesc->Texture1DArray.ArraySize = range->layerArrayCount; + dsvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + + } else if (type == PAL_IMAGE_VIEW_TYPE_2D) { + dsvDesc->Texture2D.MipSlice = range->startMipLevel; + dsvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + + } else if (type == PAL_IMAGE_VIEW_TYPE_2D_ARRAY) { + dsvDesc->Texture2DArray.MipSlice = range->startMipLevel; + dsvDesc->Texture2DArray.FirstArraySlice = range->startArrayLayer; + dsvDesc->Texture2DArray.ArraySize = range->layerArrayCount; + dsvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + } + return; + + } else if (srvDesc) { + if (type == PAL_IMAGE_VIEW_TYPE_1D) { + srvDesc->Texture1D.MipLevels = range->mipLevelCount; + srvDesc->Texture1D.MostDetailedMip = range->startMipLevel; + srvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; + + } else if (type == PAL_IMAGE_VIEW_TYPE_1D_ARRAY) { + srvDesc->Texture1DArray.MipLevels = range->mipLevelCount; + srvDesc->Texture1DArray.MostDetailedMip = range->startMipLevel; + srvDesc->Texture1DArray.FirstArraySlice = range->startArrayLayer; + srvDesc->Texture1DArray.ArraySize = range->layerArrayCount; + srvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + + } else if (type == PAL_IMAGE_VIEW_TYPE_2D) { + srvDesc->Texture2D.MipLevels = range->mipLevelCount; + srvDesc->Texture2D.MostDetailedMip = range->startMipLevel; + srvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + + } else if (type == PAL_IMAGE_VIEW_TYPE_2D_ARRAY) { + srvDesc->Texture2DArray.MipLevels = range->mipLevelCount; + srvDesc->Texture2DArray.MostDetailedMip = range->startMipLevel; + srvDesc->Texture2DArray.FirstArraySlice = range->startArrayLayer; + srvDesc->Texture2DArray.ArraySize = range->layerArrayCount; + srvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + + } else if (type == PAL_IMAGE_VIEW_TYPE_3D) { + srvDesc->Texture3D.MipLevels = range->mipLevelCount; + srvDesc->Texture3D.MostDetailedMip = range->startMipLevel; + srvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; + + } else if (type == PAL_IMAGE_VIEW_TYPE_CUBE) { + srvDesc->TextureCube.MipLevels = range->mipLevelCount; + srvDesc->TextureCube.MostDetailedMip = range->startMipLevel; + srvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; + + } else if (type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { + srvDesc->TextureCubeArray.MipLevels = range->mipLevelCount; + srvDesc->TextureCubeArray.MostDetailedMip = range->startMipLevel; + srvDesc->TextureCubeArray.First2DArrayFace = range->startArrayLayer; + srvDesc->TextureCubeArray.NumCubes = range->layerArrayCount; + srvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; + } + return; + + } else if (uavDesc) { + if (type == PAL_IMAGE_VIEW_TYPE_1D) { + uavDesc->Texture1D.MipSlice = range->startMipLevel; + uavDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; + + } else if (type == PAL_IMAGE_VIEW_TYPE_1D_ARRAY) { + uavDesc->Texture1DArray.MipSlice = range->startMipLevel; + uavDesc->Texture1DArray.FirstArraySlice = range->startArrayLayer; + uavDesc->Texture1DArray.ArraySize = range->layerArrayCount; + uavDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + + } else if (type == PAL_IMAGE_VIEW_TYPE_2D) { + uavDesc->Texture2D.MipSlice = range->startMipLevel; + uavDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + + } else if (type == PAL_IMAGE_VIEW_TYPE_2D_ARRAY) { + uavDesc->Texture2DArray.MipSlice = range->startMipLevel; + uavDesc->Texture2DArray.FirstArraySlice = range->startArrayLayer; + uavDesc->Texture2DArray.ArraySize = range->layerArrayCount; + uavDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + + } else if (type == PAL_IMAGE_VIEW_TYPE_3D) { + uavDesc->Texture3D.MipSlice = range->startMipLevel; + uavDesc->Texture3D.FirstWSlice = range->startArrayLayer; + uavDesc->Texture3D.WSize = range->layerArrayCount; + uavDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; + } + return; + } +} + // ================================================== // Adapter // ================================================== @@ -1805,6 +1967,57 @@ PalResult PAL_CALL createDeviceD3D12( } } + // create an internal heap for RTV and DSV + D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {0}; + heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + heapDesc.NumDescriptors = MAX_RTV; + + result = device->handle->lpVtbl->CreateDescriptorHeap( + device->handle, + &heapDesc, + &IID_DescHeap, + (void**)&device->rtvAllocator.heap); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; + heapDesc.NumDescriptors = MAX_DSV; + result = device->handle->lpVtbl->CreateDescriptorHeap( + device->handle, + &heapDesc, + &IID_DescHeap, + (void**)&device->dsvAllocator.heap); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + for (int i = 0; i < MAX_RTV; i++) { + device->rtvAllocator.freeList[i] = i; + } + + for (int i = 0; i < MAX_DSV; i++) { + device->dsvAllocator.freeList[i] = i; + } + + device->rtvAllocator.freeTop = MAX_RTV; + device->rtvAllocator.incrementSize = device->handle->lpVtbl->GetDescriptorHandleIncrementSize( + device->handle, + D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + + device->dsvAllocator.freeTop = MAX_DSV; + device->dsvAllocator.incrementSize = device->handle->lpVtbl->GetDescriptorHandleIncrementSize( + device->handle, + D3D12_DESCRIPTOR_HEAP_TYPE_DSV); + device->adapter = d3dAdapter->handle; device->features = features; *outDevice = (PalDevice*)device; @@ -1835,6 +2048,9 @@ void PAL_CALL destroyDeviceD3D12(PalDevice* device) d3dDevice->drawSignature->lpVtbl->Release(d3dDevice->drawSignature); } + d3dDevice->rtvAllocator.heap->lpVtbl->Release(d3dDevice->rtvAllocator.heap); + d3dDevice->dsvAllocator.heap->lpVtbl->Release(d3dDevice->dsvAllocator.heap); + d3dDevice->queue->lpVtbl->Release(d3dDevice->queue); d3dDevice->handle->lpVtbl->Release(d3dDevice->handle); if (d3dDevice->infoQueue) { @@ -2532,62 +2748,45 @@ PalResult PAL_CALL createImageViewD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - imageView->desc.Format = formatToD3D12(d3dImage->info.format); - if (info->type == PAL_IMAGE_VIEW_TYPE_1D) { - imageView->desc.Texture1D.MipLevels = info->subresourceRange.mipLevelCount; - imageView->desc.Texture1D.MostDetailedMip = info->subresourceRange.startMipLevel; - imageView->desc.Texture1D.ResourceMinLODClamp = 0; - imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; - - } else if (info->type == PAL_IMAGE_VIEW_TYPE_1D_ARRAY) { - imageView->desc.Texture1DArray.MipLevels = info->subresourceRange.mipLevelCount; - imageView->desc.Texture1DArray.MostDetailedMip = info->subresourceRange.startMipLevel; - imageView->desc.Texture1DArray.FirstArraySlice = info->subresourceRange.startArrayLayer; - imageView->desc.Texture1DArray.ArraySize = info->subresourceRange.layerArrayCount; - imageView->desc.Texture1DArray.ResourceMinLODClamp = 0; - imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; - - } else if (info->type == PAL_IMAGE_VIEW_TYPE_2D) { - imageView->desc.Texture2D.MipLevels = info->subresourceRange.mipLevelCount; - imageView->desc.Texture2D.MostDetailedMip = info->subresourceRange.startMipLevel; - imageView->desc.Texture2D.PlaneSlice = 0; - imageView->desc.Texture2D.ResourceMinLODClamp = 0; - imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - - } else if (info->type == PAL_IMAGE_VIEW_TYPE_2D_ARRAY) { - imageView->desc.Texture2DArray.MipLevels = info->subresourceRange.mipLevelCount; - imageView->desc.Texture2DArray.MostDetailedMip = info->subresourceRange.startMipLevel; - imageView->desc.Texture2DArray.FirstArraySlice = info->subresourceRange.startArrayLayer; - imageView->desc.Texture2DArray.ArraySize = info->subresourceRange.layerArrayCount; - imageView->desc.Texture2DArray.ResourceMinLODClamp = 0; - imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; - - } else if (info->type == PAL_IMAGE_VIEW_TYPE_3D) { - imageView->desc.Texture3D.MipLevels = info->subresourceRange.mipLevelCount; - imageView->desc.Texture3D.MostDetailedMip = info->subresourceRange.startMipLevel; - imageView->desc.Texture3D.ResourceMinLODClamp = 0; - imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; - - } else if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE) { - imageView->desc.TextureCube.MipLevels = info->subresourceRange.mipLevelCount; - imageView->desc.TextureCube.MostDetailedMip = info->subresourceRange.startMipLevel; - imageView->desc.TextureCube.ResourceMinLODClamp = 0; - imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; - - } else if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - imageView->desc.TextureCubeArray.MipLevels = info->subresourceRange.mipLevelCount; - imageView->desc.TextureCubeArray.MostDetailedMip = info->subresourceRange.startMipLevel; - imageView->desc.TextureCubeArray.First2DArrayFace = info->subresourceRange.startArrayLayer; - imageView->desc.TextureCubeArray.NumCubes = info->subresourceRange.layerArrayCount; - imageView->desc.TextureCubeArray.ResourceMinLODClamp = 0; - imageView->desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; - } - - memset(imageView, 0, sizeof(ImageView)); - imageView->image = d3dImage; + imageView->format = formatToD3D12(info->format); + if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR) { + RTVHeapAllocator* allocator = &d3dDevice->rtvAllocator; + Uint32 index = allocator->freeList[--allocator->freeTop]; + Uint32 size = allocator->incrementSize; + D3D12_CPU_DESCRIPTOR_HANDLE dst = getCPUDescriptorHandle(allocator->heap, index, size); - // TODO: create a temporary RTV/DTV heap and create the image view on it + D3D12_RENDER_TARGET_VIEW_DESC desc = {0}; + desc.Format = imageView->format; + fillSubresourceD3D12(info->type, &info->subresourceRange, &desc, nullptr, nullptr, nullptr); + imageView->heapIndex = index; + d3dDevice->handle->lpVtbl->CreateRenderTargetView( + d3dDevice->handle, + d3dImage->handle, + &desc, + dst); + + } else { + DSVHeapAllocator* allocator = &d3dDevice->dsvAllocator; + Uint32 index = allocator->freeList[--allocator->freeTop]; + Uint32 size = allocator->incrementSize; + D3D12_CPU_DESCRIPTOR_HANDLE dst = getCPUDescriptorHandle(allocator->heap, index, size); + + D3D12_DEPTH_STENCIL_VIEW_DESC desc = {0}; + desc.Format = imageView->format; + fillSubresourceD3D12(info->type, &info->subresourceRange, nullptr, &desc, nullptr, nullptr); + imageView->heapIndex = index; + + d3dDevice->handle->lpVtbl->CreateDepthStencilView( + d3dDevice->handle, + d3dImage->handle, + &desc, + dst); + } + + imageView->range = info->subresourceRange; + imageView->type = info->type; + imageView->image = d3dImage; *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; } @@ -2595,6 +2794,14 @@ PalResult PAL_CALL createImageViewD3D12( void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) { ImageView* d3dImageView = (ImageView*)imageView; + Device* device = d3dImageView->device; + if (d3dImageView->range.aspect == PAL_IMAGE_ASPECT_COLOR) { + device->rtvAllocator.freeList[device->rtvAllocator.freeTop++] = d3dImageView->heapIndex; + + } else { + device->dsvAllocator.freeList[device->dsvAllocator.freeTop++] = d3dImageView->heapIndex; + } + palFree(s_D3D.allocator, d3dImageView); } @@ -3839,17 +4046,24 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( D3D12_CPU_DESCRIPTOR_HANDLE fsrAttachment; for (int i = 0; i < info->colorAttachentCount; i++) { ImageView* tmp = (ImageView*)info->colorAttachments[i].imageView; - colorAttachments[i] = tmp->cpuHandle; + + RTVHeapAllocator* allocator = &tmp->device->rtvAllocator; + Uint32 size = allocator->incrementSize; + colorAttachments[i] = getCPUDescriptorHandle(allocator->heap, tmp->heapIndex, size); } - ImageView* tmpDepth = (ImageView*)info->depthStencilAttachment->imageView; - if (tmpDepth) { + ImageView* tmp = (ImageView*)info->depthStencilAttachment->imageView; + if (tmp) { + DSVHeapAllocator* allocator = &tmp->device->dsvAllocator; + Uint32 size = allocator->incrementSize; + depthStencilAttachment = getCPUDescriptorHandle(allocator->heap, tmp->heapIndex, size); + d3dCmdBuffer->handle6->lpVtbl->OMSetRenderTargets( d3dCmdBuffer->handle6, info->colorAttachentCount, colorAttachments, FALSE, - &tmpDepth->cpuHandle); + &depthStencilAttachment); } else { d3dCmdBuffer->handle6->lpVtbl->OMSetRenderTargets( @@ -3873,7 +4087,7 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( colorAttachments[i], color, 0, nullptr); } - if (tmpDepth) { + if (tmp) { D3D12_CLEAR_FLAGS clearFlags = 0; UINT8 stencil = 0; float depth = 0; @@ -4738,7 +4952,7 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( Uint32 setIndex, PalDescriptorSet* set) { - // TODO: + // TODO: finish descriptor set binding } @@ -4923,6 +5137,7 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout) { + // TODO: finish descriptor set layout HRESULT result; Device* d3dDevice = (Device*)device; DescriptorSetLayout* layout = nullptr; @@ -5216,21 +5431,96 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { AccelerationStructure* tlas = (AccelerationStructure*)info->tlasInfo->tlas; + D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; + desc.RaytracingAccelerationStructure.Location = tlas->address; + desc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; + + d3dDevice->handle->lpVtbl->CreateShaderResourceView( + d3dDevice->handle, + nullptr, + &desc, + dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { ImageView* imageView = (ImageView*)info->imageViewInfo->imageView; + D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; + desc.Format = imageView->format; + fillSubresourceD3D12( + imageView->type, + &imageView->range, + nullptr, + nullptr, + &desc, + nullptr); + d3dDevice->handle->lpVtbl->CreateShaderResourceView( d3dDevice->handle, imageView->image->handle, - &imageView->desc, + &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { ImageView* imageView = (ImageView*)info->imageViewInfo->imageView; + D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; + desc.Format = imageView->format; + fillSubresourceD3D12( + imageView->type, + &imageView->range, + nullptr, + nullptr, + nullptr, + &desc); + + d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( + d3dDevice->handle, + imageView->image->handle, + nullptr, + &desc, + dst); + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + Buffer* buffer = (Buffer*)info->bufferInfo->buffer; + D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {0}; + desc.SizeInBytes = info->bufferInfo->size; + + D3D12_GPU_VIRTUAL_ADDRESS address = 0; + address = buffer->handle->lpVtbl->GetGPUVirtualAddress(buffer->handle); + desc.BufferLocation = address + offset; + + d3dDevice->handle->lpVtbl->CreateConstantBufferView( + d3dDevice->handle, + &desc, + dst); } else { - // storage and uniform buffers + // storage buffer Buffer* buffer = (Buffer*)info->bufferInfo->buffer; + if (info->bufferInfo->readOnly) { + D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; + desc.Buffer.FirstElement = info->bufferInfo->offset; + desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; + desc.Buffer.NumElements = info->bufferInfo->size; + + d3dDevice->handle->lpVtbl->CreateShaderResourceView( + d3dDevice->handle, + buffer->handle, + &desc, + dst); + + } else { + D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; + desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + desc.Buffer.FirstElement = info->bufferInfo->offset; + desc.Buffer.NumElements = info->bufferInfo->size; + desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; + + d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( + d3dDevice->handle, + buffer->handle, + nullptr, + &desc, + dst); + } } } } diff --git a/tests/tests_main.c b/tests/tests_main.c index 88a7373f..7650b1b1 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -63,6 +63,8 @@ int main(int argc, char** argv) #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO + // TODO: correctly loop and create graphics queues till we find one + // that be present for the tests below // registerTest(clearColorTest); // registerTest(triangleTest); // registerTest(meshTest); From 81d8f135faa71ec1265bf41a42c5d17e155c7126 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 14 Apr 2026 19:17:09 +0000 Subject: [PATCH 158/372] finish descriptor API --- include/pal/pal_graphics.h | 1 + src/graphics/pal_d3d12.c | 114 ++++++++++++++++++++++++++++++------- tests/clear_color_test.c | 32 +++++++---- tests/mesh_test.c | 32 +++++++---- tests/tests_main.c | 2 - tests/texture_test.c | 32 +++++++---- tests/triangle_test.c | 32 +++++++---- 7 files changed, 181 insertions(+), 64 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 8d09508d..8a8990ee 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2146,6 +2146,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + bool readOnly; /**< For PAL_DESCRIPTOR_TYPE_STORAGE.*/ Uint32 binding; Uint32 descriptorCount; Uint32 shaderStageCount; diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index b79b9968..8d15a99f 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -66,12 +66,18 @@ const IID IID_CmdList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0 const IID IID_CmdList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96,0xcf, 0x56,0x89,0xa9,0x37,0x0f,0x80}; const IID IID_Signature = {0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1}; const IID IID_DescHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51}; +const IID IID_RootSig = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, REFIID, void**); +typedef HRESULT (__stdcall *PFN_D3D12SerializeVersionedRootSignature)( + const D3D12_VERSIONED_ROOT_SIGNATURE_DESC*, + ID3DBlob**, + ID3DBlob**); + typedef struct { const PalGraphicsBackend* backend; @@ -93,6 +99,7 @@ typedef struct { PFN_D3D12_CREATE_DEVICE createDevice; PFN_CreateDXGIFactory2 createDXGIFactory; PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface; + PFN_D3D12SerializeVersionedRootSignature serializeVersionedRootSignature; const PalAllocator* allocator; } D3D12; @@ -266,16 +273,15 @@ typedef struct { typedef struct { Uint32 offset; PalDescriptorType type; - D3D12_DESCRIPTOR_RANGE range; + D3D12_DESCRIPTOR_RANGE1 range; } DescriptorSetLayoutBinding; typedef struct { const PalGraphicsBackend* backend; - Uint32 tableIndex; Uint32 bindingCount; + Uint32 samplerCount; DescriptorSetLayoutBinding* bindings; - D3D12_ROOT_PARAMETER param; } DescriptorSetLayout; typedef struct { @@ -1236,6 +1242,19 @@ static D3D12_CPU_DESCRIPTOR_HANDLE getCPUDescriptorHandle( return handle; } +static D3D12_GPU_DESCRIPTOR_HANDLE getGPUDescriptorHandle( + ID3D12DescriptorHeap* heap, + Uint32 index, + Uint32 size) +{ + D3D12_GPU_DESCRIPTOR_HANDLE handle; + D3D12_GPU_DESCRIPTOR_HANDLE __ret; + handle = *heap->lpVtbl->GetGPUDescriptorHandleForHeapStart(heap, &__ret); + + handle.ptr += index * size; + return handle; +} + static void fillSubresourceD3D12( PalImageViewType type, const PalImageSubresourceRange* range, @@ -1401,6 +1420,10 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D.dxgi, "CreateDXGIFactory2"); + s_D3D.serializeVersionedRootSignature = (PFN_D3D12SerializeVersionedRootSignature)GetProcAddress( + s_D3D.handle, + "D3D12SerializeVersionedRootSignature"); + if (debugger && debugger->callback) { s_D3D.getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress( s_D3D.handle, @@ -2964,7 +2987,6 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = false; } - // FIXME: Add support for pre and post multplied composite alpha caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = true; caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = false; caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = false; @@ -3049,7 +3071,6 @@ PalResult PAL_CALL createSwapchainD3D12( return PAL_RESULT_INVALID_QUEUE; } - // FIXME: Add support for pre and post multplied composite alpha if (info->compositeAlpha != PAL_COMPOSITE_ALPHA_OPAQUE) { return PAL_RESULT_INVALID_ARGUMENT; } @@ -4952,8 +4973,25 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( Uint32 setIndex, PalDescriptorSet* set) { - // TODO: finish descriptor set binding + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + DescriptorSet* d3dSet = (DescriptorSet*)set; + DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; + DescriptorPool* pool = d3dSet->pool; + + ID3D12DescriptorHeap* heaps[] = { pool->heap, pool->sampleHeap }; + d3dCmdBuffer->handle6->lpVtbl->SetDescriptorHeaps(d3dCmdBuffer->handle6, 2, heaps); + + Uint32 indexes[] = { d3dSet->offset, d3dSet->samplerOffset }; + Uint32 sizes[] = { pool->size, pool->samplerSize }; + for (int i = 0; i < 2; i++) { + D3D12_GPU_DESCRIPTOR_HANDLE base = getGPUDescriptorHandle(heaps[i], indexes[i], sizes[i]); + d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRootDescriptorTable( + d3dCmdBuffer->handle6, + i, + base); + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdPushConstantsD3D12( @@ -5137,7 +5175,6 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout) { - // TODO: finish descriptor set layout HRESULT result; Device* d3dDevice = (Device*)device; DescriptorSetLayout* layout = nullptr; @@ -5151,39 +5188,66 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( } Uint32 offset = 0; + Uint32 samplerCount = 0; for (int i = 0; i < count; i++) { DescriptorSetLayoutBinding* binding = &bindings[i]; binding->offset = offset; binding->range.NumDescriptors = info->bindings[i].descriptorCount; binding->range.BaseShaderRegister = info->bindings[i].binding; - binding->range.RegisterSpace = 0; - - binding->range.OffsetInDescriptorsFromTableStart = 0; - binding->range.RangeType = 1; + binding->type = info->bindings[i].descriptorType; + binding->range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; + binding->range.RegisterSpace = 0; + binding->range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + binding->offset = offset; + offset += info->bindings[i].descriptorCount; + switch (binding->type) { + case PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE: + case PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + break; + } + case PAL_DESCRIPTOR_TYPE_SAMPLER: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + samplerCount++; + break; + } + case PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER: { + if (info->bindings[i].readOnly) { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + } else { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + } + break; + } - // VkDescriptorSetLayoutBinding* binding = &bindings[i]; - // binding->binding = info->bindings[i].binding; - // binding->descriptorCount = info->bindings[i].descriptorCount; - // binding->descriptorType = descriptortypeToVk(info->bindings[i].descriptorType); + case PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + break; + } - // binding->pImmutableSamplers = nullptr; - // binding->stageFlags = 0; - // for (int j = 0; j < info->bindings[i].shaderStageCount; j++) { - // VkShaderStageFlagBits bit = shaderStageToVK(info->bindings[i].shaderStages[j]); - // binding->stageFlags |= bit; - // } + case PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; + break; + } + } } + layout->bindingCount = info->bindingCount; + layout->samplerCount = samplerCount; + layout->bindings = bindings; + *outLayout = (PalDescriptorSetLayout*)layout; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout) { - + DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; + palFree(s_D3D.allocator, d3dLayout->bindings); + palFree(s_D3D.allocator, d3dLayout); } PalResult PAL_CALL createDescriptorPoolD3D12( @@ -5380,6 +5444,12 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( d3dPool->offset += reqAs + reqStorageBuffers + reqUniformBuffers; d3dPool->offset += reqSampledImages + reqStorageImages; d3dPool->samplerOffset += reqSamplers; + + d3dPool->usedAs += reqAs; + d3dPool->usedSampledImages += reqSampledImages; + d3dPool->usedSamplers += reqSamplers; + d3dPool->usedStorageBuffers += reqStorageBuffers; + d3dPool->usedUniformBuffers += reqUniformBuffers; d3dPool->usedSets++; *outSet = (PalDescriptorSet*)set; diff --git a/tests/clear_color_test.c b/tests/clear_color_test.c index 7c6c591b..5ebe624f 100644 --- a/tests/clear_color_test.c +++ b/tests/clear_color_test.c @@ -184,14 +184,6 @@ bool clearColorTest() return false; } - // create a graphics command queue - result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); - return false; - } - // create surface result = palCreateSurface(device, &gfxWindow, &surface); if (result != PAL_RESULT_SUCCESS) { @@ -200,8 +192,28 @@ bool clearColorTest() return false; } - if (!palCanQueuePresent(queue, surface)) { - palLog(nullptr, "Queue cannot present to surface"); + // create a graphics command queue and check if its supports presenting to the surface + bool foundQueue = false; + for (int i = 0; i < caps.maxGraphicsQueues; i++) { + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palDestroyQueue(queue); + queue = nullptr; + } else { + // found a queue + foundQueue = true; + break; + } + } + + if (!foundQueue) { + palLog(nullptr, "Failed to find a queue that can present to the surface"); return false; } diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 337cf50e..602a1a8d 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -237,14 +237,6 @@ bool meshTest() return false; } - // create a graphics command queue - result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); - return false; - } - // create surface result = palCreateSurface(device, &gfxWindow, &surface); if (result != PAL_RESULT_SUCCESS) { @@ -253,8 +245,28 @@ bool meshTest() return false; } - if (!palCanQueuePresent(queue, surface)) { - palLog(nullptr, "Queue cannot present to surface"); + // create a graphics command queue and check if its supports presenting to the surface + bool foundQueue = false; + for (int i = 0; i < caps.maxGraphicsQueues; i++) { + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palDestroyQueue(queue); + queue = nullptr; + } else { + // found a queue + foundQueue = true; + break; + } + } + + if (!foundQueue) { + palLog(nullptr, "Failed to find a queue that can present to the surface"); return false; } diff --git a/tests/tests_main.c b/tests/tests_main.c index 7650b1b1..88a7373f 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -63,8 +63,6 @@ int main(int argc, char** argv) #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // TODO: correctly loop and create graphics queues till we find one - // that be present for the tests below // registerTest(clearColorTest); // registerTest(triangleTest); // registerTest(meshTest); diff --git a/tests/texture_test.c b/tests/texture_test.c index 1ba0a8c8..20a5f538 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -265,14 +265,6 @@ bool textureTest() return false; } - // create a graphics command queue - result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); - return false; - } - // create surface result = palCreateSurface(device, &gfxWindow, &surface); if (result != PAL_RESULT_SUCCESS) { @@ -281,8 +273,28 @@ bool textureTest() return false; } - if (!palCanQueuePresent(queue, surface)) { - palLog(nullptr, "Queue cannot present to surface"); + // create a graphics command queue and check if its supports presenting to the surface + bool foundQueue = false; + for (int i = 0; i < caps.maxGraphicsQueues; i++) { + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palDestroyQueue(queue); + queue = nullptr; + } else { + // found a queue + foundQueue = true; + break; + } + } + + if (!foundQueue) { + palLog(nullptr, "Failed to find a queue that can present to the surface"); return false; } diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 3cbc7818..0bf5b507 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -231,14 +231,6 @@ bool triangleTest() return false; } - // create a graphics command queue - result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); - return false; - } - // create surface result = palCreateSurface(device, &gfxWindow, &surface); if (result != PAL_RESULT_SUCCESS) { @@ -247,8 +239,28 @@ bool triangleTest() return false; } - if (!palCanQueuePresent(queue, surface)) { - palLog(nullptr, "Queue cannot present to surface"); + // create a graphics command queue and check if its supports presenting to the surface + bool foundQueue = false; + for (int i = 0; i < caps.maxGraphicsQueues; i++) { + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palDestroyQueue(queue); + queue = nullptr; + } else { + // found a queue + foundQueue = true; + break; + } + } + + if (!foundQueue) { + palLog(nullptr, "Failed to find a queue that can present to the surface"); return false; } From 1cf5d91239ca6850eeb9a1e021901b93b4193897 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 15 Apr 2026 20:32:04 +0000 Subject: [PATCH 159/372] optimize descriptor API d3d12 --- src/graphics/pal_d3d12.c | 317 +++++++++++++++++++++++---------------- tests/compute_test.c | 2 - 2 files changed, 185 insertions(+), 134 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 8d15a99f..b455b7f0 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -107,6 +107,7 @@ typedef struct { typedef struct { Uint32 incrementSize; Uint32 freeTop; + Uint64 baseOffset; ID3D12DescriptorHeap* heap; Uint32 freeList[MAX_RTV]; } RTVHeapAllocator; @@ -114,6 +115,7 @@ typedef struct { typedef struct { Uint32 incrementSize; Uint32 freeTop; + Uint64 baseOffset; ID3D12DescriptorHeap* heap; Uint32 freeList[MAX_DSV]; } DSVHeapAllocator; @@ -271,38 +273,33 @@ typedef struct { } ShaderBindingTable; typedef struct { - Uint32 offset; PalDescriptorType type; D3D12_DESCRIPTOR_RANGE1 range; -} DescriptorSetLayoutBinding; +} DescriptorSetBinding; typedef struct { const PalGraphicsBackend* backend; Uint32 bindingCount; Uint32 samplerCount; - DescriptorSetLayoutBinding* bindings; + DescriptorSetBinding* bindings; } DescriptorSetLayout; typedef struct { - const PalGraphicsBackend* backend; - - Uint32 offset; - Uint32 samplerOffset; - DescriptorSetLayout* layout; - void* pool; // DescriptorPool -} DescriptorSet; + Uint32 incrementSize; + Uint32 nextOffset; + Uint64 cpuBase; + Uint64 gpuBase; + ID3D12DescriptorHeap* handle; +} DescriptorHeap; typedef struct { - const PalGraphicsBackend* backend; - Uint32 maxUniformBuffers; Uint32 maxSampledImages; Uint32 maxStorageBuffers; Uint32 maxSamplers; Uint32 maxStorageImages; Uint32 maxAs; - Uint32 maxSets; Uint32 usedUniformBuffers; Uint32 usedSampledImages; @@ -310,18 +307,35 @@ typedef struct { Uint32 usedSamplers; Uint32 usedStorageImages; Uint32 usedAs; - Uint32 usedSets; +} DescriptorHeapLimits; + +typedef struct { + const PalGraphicsBackend* backend; - Uint32 samplerOffset; Uint32 offset; - Uint32 samplerSize; - Uint32 size; + Uint32 samplerOffset; + DescriptorSetLayout* layout; + void* pool; // DescriptorPool +} DescriptorSet; - ID3D12DescriptorHeap* heap; - ID3D12DescriptorHeap* sampleHeap; +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 maxSets; + Uint32 usedSets; + DescriptorHeapLimits limits; + DescriptorHeap heap; + DescriptorHeap samplerHeap; DescriptorSet* sets; } DescriptorPool; +typedef struct { + Uint32 rootIndex; // CBV SRV UAV + Uint32 samplerRootIndex; + ID3D12RootSignature* handle; + D3D12_ROOT_PARAMETER1 params[2]; +} PipelineLayout; + static D3D12 s_D3D = {0}; // ================================================== @@ -1229,32 +1243,6 @@ static D3D12_RESOURCE_STATES barrierToD3D12( return D3D12_RESOURCE_STATE_COMMON; } -static D3D12_CPU_DESCRIPTOR_HANDLE getCPUDescriptorHandle( - ID3D12DescriptorHeap* heap, - Uint32 index, - Uint32 size) -{ - D3D12_CPU_DESCRIPTOR_HANDLE handle; - D3D12_CPU_DESCRIPTOR_HANDLE __ret; - handle = *heap->lpVtbl->GetCPUDescriptorHandleForHeapStart(heap, &__ret); - - handle.ptr += index * size; - return handle; -} - -static D3D12_GPU_DESCRIPTOR_HANDLE getGPUDescriptorHandle( - ID3D12DescriptorHeap* heap, - Uint32 index, - Uint32 size) -{ - D3D12_GPU_DESCRIPTOR_HANDLE handle; - D3D12_GPU_DESCRIPTOR_HANDLE __ret; - handle = *heap->lpVtbl->GetGPUDescriptorHandleForHeapStart(heap, &__ret); - - handle.ptr += index * size; - return handle; -} - static void fillSubresourceD3D12( PalImageViewType type, const PalImageSubresourceRange* range, @@ -1396,6 +1384,14 @@ static void fillSubresourceD3D12( } } +static inline Uint64 getDescriptorHandleD3D12( + Uint32 index, + Uint32 size, + Uint64 baseOffset) +{ + return baseOffset + index * size; +} + // ================================================== // Adapter // ================================================== @@ -2041,6 +2037,20 @@ PalResult PAL_CALL createDeviceD3D12( device->handle, D3D12_DESCRIPTOR_HEAP_TYPE_DSV); + // get base CPU pointer + D3D12_CPU_DESCRIPTOR_HANDLE __ret, dst; + dst = *device->rtvAllocator.heap->lpVtbl->GetCPUDescriptorHandleForHeapStart( + device->rtvAllocator.heap, + &__ret + ); + device->rtvAllocator.baseOffset = dst.ptr; + + dst = *device->dsvAllocator.heap->lpVtbl->GetCPUDescriptorHandleForHeapStart( + device->dsvAllocator.heap, + &__ret + ); + device->dsvAllocator.baseOffset = dst.ptr; + device->adapter = d3dAdapter->handle; device->features = features; *outDevice = (PalDevice*)device; @@ -2775,8 +2785,8 @@ PalResult PAL_CALL createImageViewD3D12( if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR) { RTVHeapAllocator* allocator = &d3dDevice->rtvAllocator; Uint32 index = allocator->freeList[--allocator->freeTop]; - Uint32 size = allocator->incrementSize; - D3D12_CPU_DESCRIPTOR_HANDLE dst = getCPUDescriptorHandle(allocator->heap, index, size); + D3D12_CPU_DESCRIPTOR_HANDLE dst; + dst.ptr = getDescriptorHandleD3D12(index, allocator->incrementSize, allocator->baseOffset); D3D12_RENDER_TARGET_VIEW_DESC desc = {0}; desc.Format = imageView->format; @@ -2792,8 +2802,8 @@ PalResult PAL_CALL createImageViewD3D12( } else { DSVHeapAllocator* allocator = &d3dDevice->dsvAllocator; Uint32 index = allocator->freeList[--allocator->freeTop]; - Uint32 size = allocator->incrementSize; - D3D12_CPU_DESCRIPTOR_HANDLE dst = getCPUDescriptorHandle(allocator->heap, index, size); + D3D12_CPU_DESCRIPTOR_HANDLE dst; + dst.ptr = getDescriptorHandleD3D12(index, allocator->incrementSize, allocator->baseOffset); D3D12_DEPTH_STENCIL_VIEW_DESC desc = {0}; desc.Format = imageView->format; @@ -4070,14 +4080,16 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( RTVHeapAllocator* allocator = &tmp->device->rtvAllocator; Uint32 size = allocator->incrementSize; - colorAttachments[i] = getCPUDescriptorHandle(allocator->heap, tmp->heapIndex, size); + Uint32 base = allocator->baseOffset; + colorAttachments[i].ptr = getDescriptorHandleD3D12(tmp->heapIndex, size, base); } ImageView* tmp = (ImageView*)info->depthStencilAttachment->imageView; if (tmp) { DSVHeapAllocator* allocator = &tmp->device->dsvAllocator; Uint32 size = allocator->incrementSize; - depthStencilAttachment = getCPUDescriptorHandle(allocator->heap, tmp->heapIndex, size); + Uint32 base = allocator->baseOffset; + depthStencilAttachment.ptr = getDescriptorHandleD3D12(tmp->heapIndex, size, base); d3dCmdBuffer->handle6->lpVtbl->OMSetRenderTargets( d3dCmdBuffer->handle6, @@ -4975,21 +4987,32 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; DescriptorSet* d3dSet = (DescriptorSet*)set; - DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; + PipelineLayout* pipelineLayout = (PipelineLayout*)layout; DescriptorPool* pool = d3dSet->pool; - ID3D12DescriptorHeap* heaps[] = { pool->heap, pool->sampleHeap }; + D3D12_GPU_DESCRIPTOR_HANDLE base, samplerBase; + base.ptr = getDescriptorHandleD3D12( + d3dSet->offset, + pool->heap.incrementSize, + pool->heap.gpuBase); + + samplerBase.ptr = getDescriptorHandleD3D12( + d3dSet->offset, + pool->heap.incrementSize, + pool->heap.gpuBase); + + ID3D12DescriptorHeap* heaps[] = { pool->heap.handle, pool->samplerHeap.handle }; d3dCmdBuffer->handle6->lpVtbl->SetDescriptorHeaps(d3dCmdBuffer->handle6, 2, heaps); - Uint32 indexes[] = { d3dSet->offset, d3dSet->samplerOffset }; - Uint32 sizes[] = { pool->size, pool->samplerSize }; - for (int i = 0; i < 2; i++) { - D3D12_GPU_DESCRIPTOR_HANDLE base = getGPUDescriptorHandle(heaps[i], indexes[i], sizes[i]); - d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRootDescriptorTable( - d3dCmdBuffer->handle6, - i, - base); - } + d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRootDescriptorTable( + d3dCmdBuffer->handle6, + pipelineLayout->rootIndex, + base); + + d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRootDescriptorTable( + d3dCmdBuffer->handle6, + pipelineLayout->samplerRootIndex, + samplerBase); return PAL_RESULT_SUCCESS; } @@ -5003,6 +5026,7 @@ PalResult PAL_CALL cmdPushConstantsD3D12( Uint32 size, const void* value) { + // TODO: } @@ -5178,11 +5202,11 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( HRESULT result; Device* d3dDevice = (Device*)device; DescriptorSetLayout* layout = nullptr; - DescriptorSetLayoutBinding* bindings = nullptr; + DescriptorSetBinding* bindings = nullptr; Uint32 count = info->bindingCount; layout = palAllocate(s_D3D.allocator, sizeof(DescriptorSetLayout), 0); - bindings = palAllocate(s_D3D.allocator, sizeof(DescriptorSetLayoutBinding) * count, 0); + bindings = palAllocate(s_D3D.allocator, sizeof(DescriptorSetBinding) * count, 0); if (!layout || !bindings) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -5190,19 +5214,18 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( Uint32 offset = 0; Uint32 samplerCount = 0; for (int i = 0; i < count; i++) { - DescriptorSetLayoutBinding* binding = &bindings[i]; - binding->offset = offset; + DescriptorSetBinding* binding = &bindings[i]; + binding->type = info->bindings[i].descriptorType; + binding->range.NumDescriptors = info->bindings[i].descriptorCount; binding->range.BaseShaderRegister = info->bindings[i].binding; - binding->type = info->bindings[i].descriptorType; binding->range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; binding->range.RegisterSpace = 0; - binding->range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - binding->offset = offset; + binding->range.OffsetInDescriptorsFromTableStart = offset; offset += info->bindings[i].descriptorCount; - switch (binding->type) { + switch (info->bindings[i].descriptorType) { case PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE: case PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; @@ -5270,29 +5293,30 @@ PalResult PAL_CALL createDescriptorPoolD3D12( } Uint32 count = 0; + DescriptorHeapLimits* limits = &pool->limits; for (int i = 0; i < info->maxDescriptorBindingSizes; i++) { PalDescriptorPoolBindingSize* bindingSize = &info->bindingSizes[i]; if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { - pool->maxSamplers += bindingSize->bindingCount; + limits->maxSamplers += bindingSize->bindingCount; } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - pool->maxUniformBuffers += bindingSize->bindingCount; + limits->maxUniformBuffers += bindingSize->bindingCount; count += bindingSize->bindingCount; } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER) { - pool->maxStorageBuffers += bindingSize->bindingCount; + limits->maxStorageBuffers += bindingSize->bindingCount; count += bindingSize->bindingCount; } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - pool->maxSampledImages += bindingSize->bindingCount; + limits->maxSampledImages += bindingSize->bindingCount; count += bindingSize->bindingCount; } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - pool->maxStorageImages += bindingSize->bindingCount; + limits->maxStorageImages += bindingSize->bindingCount; count += bindingSize->bindingCount; } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - pool->maxAs += bindingSize->bindingCount; + limits->maxAs += bindingSize->bindingCount; count += bindingSize->bindingCount; } } @@ -5305,13 +5329,13 @@ PalResult PAL_CALL createDescriptorPoolD3D12( D3D12_DESCRIPTOR_HEAP_DESC samplerDesc = {0}; samplerDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; samplerDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; - samplerDesc.NumDescriptors = pool->maxSamplers * info->maxDescriptorSets; + samplerDesc.NumDescriptors = limits->maxSamplers * info->maxDescriptorSets; result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( d3dDevice->handle, &desc, &IID_DescHeap, - (void**)&pool->heap); + (void**)&pool->heap.handle); if (FAILED(result)) { if (result == E_OUTOFMEMORY) { @@ -5324,7 +5348,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( d3dDevice->handle, &samplerDesc, &IID_DescHeap, - (void**)&pool->sampleHeap); + (void**)&pool->samplerHeap.handle); if (FAILED(result)) { if (result == E_OUTOFMEMORY) { @@ -5333,14 +5357,41 @@ PalResult PAL_CALL createDescriptorPoolD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - pool->size = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( + DescriptorHeap* heap = &pool->heap; + DescriptorHeap* samplerHeap = &pool->samplerHeap; + heap->incrementSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( d3dDevice->handle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - pool->samplerSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( + samplerHeap->incrementSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( d3dDevice->handle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + // get base CPU and GPU base pointer + D3D12_CPU_DESCRIPTOR_HANDLE __ret, handle; + D3D12_GPU_DESCRIPTOR_HANDLE __gpuRet, gpuHandle; + + handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( + heap->handle, + &__ret); + heap->cpuBase = handle.ptr; + + gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( + heap->handle, + &__gpuRet); + heap->gpuBase = gpuHandle.ptr; + + // sampler heap + handle = *samplerHeap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( + samplerHeap->handle, + &__ret); + samplerHeap->cpuBase = handle.ptr; + + gpuHandle = *samplerHeap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( + samplerHeap->handle, + &__gpuRet); + samplerHeap->gpuBase = gpuHandle.ptr; + pool->maxSets = info->maxDescriptorSets; *outPool = (PalDescriptorPool*)pool; return PAL_RESULT_SUCCESS; @@ -5349,8 +5400,8 @@ PalResult PAL_CALL createDescriptorPoolD3D12( void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) { DescriptorPool* d3dPool = (DescriptorPool*)pool; - d3dPool->heap->lpVtbl->Release(d3dPool->heap); - d3dPool->sampleHeap->lpVtbl->Release(d3dPool->sampleHeap); + d3dPool->heap.handle->lpVtbl->Release(d3dPool->heap.handle); + d3dPool->samplerHeap.handle->lpVtbl->Release(d3dPool->samplerHeap.handle); palFree(s_D3D.allocator, d3dPool->sets); palFree(s_D3D.allocator, d3dPool); } @@ -5358,9 +5409,17 @@ void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool) { DescriptorPool* d3dPool = (DescriptorPool*)pool; - d3dPool->offset = 0; - d3dPool->samplerOffset = 0; + d3dPool->heap.nextOffset = 0; + d3dPool->samplerHeap.nextOffset = 0; d3dPool->usedSets = 0; + + d3dPool->limits.usedAs = 0; + d3dPool->limits.usedSampledImages = 0; + d3dPool->limits.usedSamplers = 0; + d3dPool->limits.usedStorageBuffers = 0; + d3dPool->limits.usedStorageImages = 0; + d3dPool->limits.usedUniformBuffers = 0; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL allocateDescriptorSetD3D12( @@ -5373,33 +5432,34 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; DescriptorSet* set = nullptr; - Uint32 reqStorageImages = 0; - Uint32 reqSamplers = 0; - Uint32 reqStorageBuffers = 0; - Uint32 reqUniformBuffers = 0; - Uint32 reqAs = 0; - Uint32 reqSampledImages = 0; + Uint32 storageImageCount = 0; + Uint32 samplerCount = 0; + Uint32 storageBufferCount = 0; + Uint32 uniformBufferCount = 0; + Uint32 sampledImageCount = 0; + Uint32 asCount = 0; // get requirements for the sets using the provided layout for (int i = 0; i < d3dLayout->bindingCount; i++) { - DescriptorSetLayoutBinding* binding = &d3dLayout->bindings[i]; + DescriptorSetBinding* binding = &d3dLayout->bindings[i]; + if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { - reqSamplers += binding->range.NumDescriptors; + samplerCount += binding->range.NumDescriptors; } else if (binding->type == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER) { - reqStorageBuffers += binding->range.NumDescriptors; + storageBufferCount += binding->range.NumDescriptors; } else if (binding->type == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - reqStorageImages += binding->range.NumDescriptors; + storageImageCount += binding->range.NumDescriptors; } else if (binding->type == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - reqUniformBuffers += binding->range.NumDescriptors; + uniformBufferCount += binding->range.NumDescriptors; } else if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - reqSampledImages += binding->range.NumDescriptors; + sampledImageCount += binding->range.NumDescriptors; } else if (binding->type == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - reqAs += binding->range.NumDescriptors; + asCount += binding->range.NumDescriptors; } } @@ -5410,46 +5470,48 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( } // check descriptor limits - if (d3dPool->usedAs + reqAs > d3dPool->maxAs) { + DescriptorHeapLimits* limits = &d3dPool->limits; + if (limits->usedAs + asCount > limits->maxAs) { return PAL_RESULT_OUT_OF_MEMORY; } - if (d3dPool->usedSampledImages + reqSampledImages > d3dPool->maxSampledImages) { + if (limits->usedSampledImages + sampledImageCount > limits->maxSampledImages) { return PAL_RESULT_OUT_OF_MEMORY; } - if (d3dPool->usedSamplers + reqSamplers > d3dPool->maxSamplers) { + if (limits->usedSamplers + samplerCount > limits->maxSamplers) { return PAL_RESULT_OUT_OF_MEMORY; } - if (d3dPool->usedStorageBuffers + reqStorageBuffers > d3dPool->maxStorageBuffers) { + if (limits->usedStorageBuffers + storageBufferCount > limits->maxStorageBuffers) { return PAL_RESULT_OUT_OF_MEMORY; } - if (d3dPool->usedStorageImages + reqStorageImages > d3dPool->maxStorageImages) { + if (limits->usedStorageImages + storageImageCount > limits->maxStorageImages) { return PAL_RESULT_OUT_OF_MEMORY; } - if (d3dPool->usedUniformBuffers+ reqUniformBuffers > d3dPool->maxUniformBuffers) { + if (limits->usedUniformBuffers + uniformBufferCount > limits->maxUniformBuffers) { return PAL_RESULT_OUT_OF_MEMORY; } // assign offset base to the set so we know where to start and end for each set. set = &d3dPool->sets[d3dPool->usedSets++]; - set->offset = d3dPool->offset; // CSV, UAV, SRV - set->samplerOffset = d3dPool->samplerOffset; + set->offset = d3dPool->heap.nextOffset; // CSV, UAV, SRV + set->samplerOffset = d3dPool->samplerHeap.nextOffset; set->layout = d3dLayout; set->pool = d3dPool; - d3dPool->offset += reqAs + reqStorageBuffers + reqUniformBuffers; - d3dPool->offset += reqSampledImages + reqStorageImages; - d3dPool->samplerOffset += reqSamplers; + Uint32 totalDescriptors = asCount + storageBufferCount + uniformBufferCount; + totalDescriptors += sampledImageCount + storageImageCount; + d3dPool->heap.nextOffset += totalDescriptors; + d3dPool->samplerHeap.nextOffset += totalDescriptors; - d3dPool->usedAs += reqAs; - d3dPool->usedSampledImages += reqSampledImages; - d3dPool->usedSamplers += reqSamplers; - d3dPool->usedStorageBuffers += reqStorageBuffers; - d3dPool->usedUniformBuffers += reqUniformBuffers; + limits->usedAs += asCount; + limits->usedSampledImages += sampledImageCount; + limits->usedSamplers += samplerCount; + limits->usedStorageBuffers += storageBufferCount; + limits->usedUniformBuffers += uniformBufferCount; d3dPool->usedSets++; *outSet = (PalDescriptorSet*)set; @@ -5467,33 +5529,25 @@ PalResult PAL_CALL updateDescriptorSetD3D12( DescriptorSet* set = (DescriptorSet*)info->descriptorSet; DescriptorPool* pool = set->pool; DescriptorSetLayout* layout = set->layout; - DescriptorSetLayoutBinding* binding = &layout->bindings[info->binding]; + DescriptorSetBinding* binding = &layout->bindings[info->binding]; - Uint32 size = 0; - Uint32 offset = 0; - ID3D12DescriptorHeap* heap = nullptr; - D3D12_DESCRIPTOR_HEAP_TYPE heapType; + DescriptorHeap* heap = nullptr; if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { - heap = pool->sampleHeap; - size = pool->samplerSize; - offset = set->samplerOffset; - heapType = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; - + heap = &pool->samplerHeap; } else { - heap = pool->heap; - size = pool->size; - offset = set->offset; - heapType = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + heap = &pool->heap; } // compute the heap index and copy all the descriptors - Uint32 index = offset + binding->offset + info->arrayElement; + Uint32 bindingOffsetffset = binding->range.OffsetInDescriptorsFromTableStart; + Uint32 index = heap->nextOffset + bindingOffsetffset + info->arrayElement; if (info->arrayElement + binding->range.NumDescriptors > layout->bindingCount) { return PAL_RESULT_INVALID_ARGUMENT; } for (int y = 0; y < binding->range.NumDescriptors; y++) { - D3D12_CPU_DESCRIPTOR_HANDLE dst = getCPUDescriptorHandle(heap, index + y, size); + D3D12_CPU_DESCRIPTOR_HANDLE dst; + dst.ptr = getDescriptorHandleD3D12(index + y, heap->incrementSize, heap->cpuBase); if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { Sampler* sampler = (Sampler*)info->samplerInfo->sampler; @@ -5555,7 +5609,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( D3D12_GPU_VIRTUAL_ADDRESS address = 0; address = buffer->handle->lpVtbl->GetGPUVirtualAddress(buffer->handle); - desc.BufferLocation = address + offset; + desc.BufferLocation = address + info->bufferInfo->offset; d3dDevice->handle->lpVtbl->CreateConstantBufferView( d3dDevice->handle, @@ -5594,7 +5648,6 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } } } - return PAL_RESULT_SUCCESS; } diff --git a/tests/compute_test.c b/tests/compute_test.c index df6d94ed..b03577a9 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -6,11 +6,9 @@ #define BUFFER_SIZE 400 -// the storage buffer needs alignment of 16 typedef struct { Uint32 width; Uint32 height; - Uint32 _padding[2]; float color[4]; } PushConstant; From e14bb81c00ee37cf69b194503cdf1cb3f0a29aa8 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 16 Apr 2026 05:56:11 +0000 Subject: [PATCH 160/372] add push constant command API d3d12 --- include/pal/pal_graphics.h | 9 +- src/graphics/pal_d3d12.c | 272 ++++++++++++++++++++++++------------ src/graphics/pal_graphics.c | 28 +++- src/graphics/pal_vulkan.c | 3 +- tests/compute_test.c | 5 +- tests/ray_tracing_test.c | 2 +- tests/texture_test.c | 2 +- 7 files changed, 215 insertions(+), 106 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 8a8990ee..07875496 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3517,8 +3517,8 @@ typedef struct { */ PalResult PAL_CALL (*cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set); @@ -3530,6 +3530,7 @@ typedef struct { PalResult PAL_CALL (*cmdPushConstants)( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -6259,8 +6260,8 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] bindPoint The Binding point. * @param[in] layout The pipeline layout that defines the descriptor interface. + * @param[in] bindPoint The Binding point. * @param[in] setIndex Index of the descriptor set to bind. * @param[in] set Descriptor set to bind. Must be compatible with `layout`. * @@ -6274,8 +6275,8 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( */ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set); @@ -6286,6 +6287,7 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] layout The pipeline layout that defines the push constant range. + * @param[in] bindPoint The Binding point. * @param[in] shaderStageCount Capacity of the PalShaderStage array. * @param[in] shaderStages Array of shader stages that can access the push constant. * @param[in] offset Offset in bytes into the push constant range. @@ -6303,6 +6305,7 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PAL_API PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index b455b7f0..7f869a94 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -48,6 +48,9 @@ freely, subject to the following restrictions: #define TEXTURE_PITCH 256 #define MAX_RTV 1024 #define MAX_DSV 512 +#define CONSTANT_INDEX 0 +#define DESCRIPTOR_TABLE_INDEX 1 +#define SAMPLER_DESCRIPTOR_TABLE_INDEX 2 // IIDS const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; @@ -312,7 +315,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 offset; + Uint32 resourceOffset; Uint32 samplerOffset; DescriptorSetLayout* layout; void* pool; // DescriptorPool @@ -321,19 +324,22 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + bool hasResourceHeap; + bool hasSamplerHeap; Uint32 maxSets; Uint32 usedSets; DescriptorHeapLimits limits; - DescriptorHeap heap; + DescriptorHeap resourceHeap; DescriptorHeap samplerHeap; DescriptorSet* sets; } DescriptorPool; typedef struct { - Uint32 rootIndex; // CBV SRV UAV - Uint32 samplerRootIndex; + Uint32 constantIndex; + Uint32 resourceIndex; + Uint32 samplerIndex; ID3D12RootSignature* handle; - D3D12_ROOT_PARAMETER1 params[2]; + D3D12_ROOT_PARAMETER1 params[3]; } PipelineLayout; static D3D12 s_D3D = {0}; @@ -4980,8 +4986,8 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set) { @@ -4990,29 +4996,68 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( PipelineLayout* pipelineLayout = (PipelineLayout*)layout; DescriptorPool* pool = d3dSet->pool; - D3D12_GPU_DESCRIPTOR_HANDLE base, samplerBase; - base.ptr = getDescriptorHandleD3D12( - d3dSet->offset, - pool->heap.incrementSize, - pool->heap.gpuBase); + // bind heaps + Uint32 heapCount = 0; + ID3D12DescriptorHeap* heaps[2]; + if (pool->hasResourceHeap) { + heaps[heapCount++] = pool->resourceHeap.handle; + } - samplerBase.ptr = getDescriptorHandleD3D12( - d3dSet->offset, - pool->heap.incrementSize, - pool->heap.gpuBase); + if (pool->hasSamplerHeap) { + heaps[heapCount++] = pool->samplerHeap.handle; + } + d3dCmdBuffer->handle6->lpVtbl->SetDescriptorHeaps(d3dCmdBuffer->handle6, heapCount, heaps); - ID3D12DescriptorHeap* heaps[] = { pool->heap.handle, pool->samplerHeap.handle }; - d3dCmdBuffer->handle6->lpVtbl->SetDescriptorHeaps(d3dCmdBuffer->handle6, 2, heaps); + // bind descriptor tables + if (pipelineLayout->resourceIndex != UINT32_MAX) { + // a valid index + D3D12_GPU_DESCRIPTOR_HANDLE base; + base.ptr = getDescriptorHandleD3D12( + d3dSet->resourceOffset, + pool->resourceHeap.incrementSize, + pool->resourceHeap.gpuBase); - d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRootDescriptorTable( - d3dCmdBuffer->handle6, - pipelineLayout->rootIndex, - base); + if (bindPoint == PAL_PIPELINE_BIND_POINT_GRAPHICS) { + d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRootDescriptorTable( + d3dCmdBuffer->handle6, + pipelineLayout->resourceIndex, + base); - d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRootDescriptorTable( - d3dCmdBuffer->handle6, - pipelineLayout->samplerRootIndex, - samplerBase); + } else if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { + d3dCmdBuffer->handle6->lpVtbl->SetComputeRootDescriptorTable( + d3dCmdBuffer->handle6, + pipelineLayout->resourceIndex, + base); + + } else { + // TODO: ray tracing bind point + } + } + + if (pipelineLayout->samplerIndex != UINT32_MAX) { + // a valid index + D3D12_GPU_DESCRIPTOR_HANDLE base; + base.ptr = getDescriptorHandleD3D12( + d3dSet->samplerOffset, + pool->samplerHeap.incrementSize, + pool->samplerHeap.gpuBase); + + if (bindPoint == PAL_PIPELINE_BIND_POINT_GRAPHICS) { + d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRootDescriptorTable( + d3dCmdBuffer->handle6, + pipelineLayout->samplerIndex, + base); + + } else if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { + d3dCmdBuffer->handle6->lpVtbl->SetComputeRootDescriptorTable( + d3dCmdBuffer->handle6, + pipelineLayout->samplerIndex, + base); + + } else { + // TODO: ray tracing bind point + } + } return PAL_RESULT_SUCCESS; } @@ -5020,14 +5065,39 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalResult PAL_CALL cmdPushConstantsD3D12( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, Uint32 size, const void* value) { - // TODO: + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + PipelineLayout* pipelineLayout = (PipelineLayout*)layout; + if (pipelineLayout->constantIndex != UINT32_MAX) { + if (bindPoint == PAL_PIPELINE_BIND_POINT_GRAPHICS) { + d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRoot32BitConstants( + d3dCmdBuffer->handle6, + pipelineLayout->constantIndex, + size / 4, + value, + offset / 4); + + } else if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { + d3dCmdBuffer->handle6->lpVtbl->SetComputeRoot32BitConstants( + d3dCmdBuffer->handle6, + pipelineLayout->constantIndex, + size / 4, + value, + offset / 4); + + } else { + // TODO: ray tracing bind point + } + } + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdSetCullModeD3D12( @@ -5292,7 +5362,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - Uint32 count = 0; + Uint32 resourceCount = 0; DescriptorHeapLimits* limits = &pool->limits; for (int i = 0; i < info->maxDescriptorBindingSizes; i++) { PalDescriptorPoolBindingSize* bindingSize = &info->bindingSizes[i]; @@ -5301,96 +5371,111 @@ PalResult PAL_CALL createDescriptorPoolD3D12( } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { limits->maxUniformBuffers += bindingSize->bindingCount; - count += bindingSize->bindingCount; + resourceCount += bindingSize->bindingCount; } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER) { limits->maxStorageBuffers += bindingSize->bindingCount; - count += bindingSize->bindingCount; + resourceCount += bindingSize->bindingCount; } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { limits->maxSampledImages += bindingSize->bindingCount; - count += bindingSize->bindingCount; + resourceCount += bindingSize->bindingCount; } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { limits->maxStorageImages += bindingSize->bindingCount; - count += bindingSize->bindingCount; + resourceCount += bindingSize->bindingCount; } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { limits->maxAs += bindingSize->bindingCount; - count += bindingSize->bindingCount; + resourceCount += bindingSize->bindingCount; } } - D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; - desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - desc.NumDescriptors = count * info->maxDescriptorSets; + // resource heap + if (resourceCount) { + DescriptorHeap* heap = &pool->resourceHeap; + D3D12_CPU_DESCRIPTOR_HANDLE __ret, handle; + D3D12_GPU_DESCRIPTOR_HANDLE __gpuRet, gpuHandle; - D3D12_DESCRIPTOR_HEAP_DESC samplerDesc = {0}; - samplerDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - samplerDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; - samplerDesc.NumDescriptors = limits->maxSamplers * info->maxDescriptorSets; + D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + desc.NumDescriptors = resourceCount * info->maxDescriptorSets; - result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( - d3dDevice->handle, - &desc, - &IID_DescHeap, - (void**)&pool->heap.handle); + result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( + d3dDevice->handle, + &desc, + &IID_DescHeap, + (void**)&heap->handle); - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; } - return PAL_RESULT_PLATFORM_FAILURE; - } - result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( - d3dDevice->handle, - &samplerDesc, - &IID_DescHeap, - (void**)&pool->samplerHeap.handle); + // get increment size + heap->incrementSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( + d3dDevice->handle, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; + // get base CPU and GPU base pointer + handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( + heap->handle, + &__ret); + heap->cpuBase = handle.ptr; + + gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( + heap->handle, + &__gpuRet); + heap->gpuBase = gpuHandle.ptr; + + pool->hasResourceHeap = true; } - DescriptorHeap* heap = &pool->heap; - DescriptorHeap* samplerHeap = &pool->samplerHeap; - heap->incrementSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( - d3dDevice->handle, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + // sampler heap + if (limits->maxSamplers) { + DescriptorHeap* heap = &pool->samplerHeap; + D3D12_CPU_DESCRIPTOR_HANDLE __ret, handle; + D3D12_GPU_DESCRIPTOR_HANDLE __gpuRet, gpuHandle; - samplerHeap->incrementSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( - d3dDevice->handle, - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; + desc.NumDescriptors = limits->maxSamplers * info->maxDescriptorSets; - // get base CPU and GPU base pointer - D3D12_CPU_DESCRIPTOR_HANDLE __ret, handle; - D3D12_GPU_DESCRIPTOR_HANDLE __gpuRet, gpuHandle; + result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( + d3dDevice->handle, + &desc, + &IID_DescHeap, + (void**)&heap->handle); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } - handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( - heap->handle, - &__ret); - heap->cpuBase = handle.ptr; + // get increment size + heap->incrementSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( + d3dDevice->handle, + D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( - heap->handle, - &__gpuRet); - heap->gpuBase = gpuHandle.ptr; + // get base CPU and GPU base pointer + handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( + heap->handle, + &__ret); + heap->cpuBase = handle.ptr; - // sampler heap - handle = *samplerHeap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( - samplerHeap->handle, - &__ret); - samplerHeap->cpuBase = handle.ptr; + gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( + heap->handle, + &__gpuRet); + heap->gpuBase = gpuHandle.ptr; - gpuHandle = *samplerHeap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( - samplerHeap->handle, - &__gpuRet); - samplerHeap->gpuBase = gpuHandle.ptr; + pool->hasSamplerHeap = true; + } pool->maxSets = info->maxDescriptorSets; *outPool = (PalDescriptorPool*)pool; @@ -5400,8 +5485,9 @@ PalResult PAL_CALL createDescriptorPoolD3D12( void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) { DescriptorPool* d3dPool = (DescriptorPool*)pool; - d3dPool->heap.handle->lpVtbl->Release(d3dPool->heap.handle); + d3dPool->resourceHeap.handle->lpVtbl->Release(d3dPool->resourceHeap.handle); d3dPool->samplerHeap.handle->lpVtbl->Release(d3dPool->samplerHeap.handle); + palFree(s_D3D.allocator, d3dPool->sets); palFree(s_D3D.allocator, d3dPool); } @@ -5409,7 +5495,7 @@ void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool) { DescriptorPool* d3dPool = (DescriptorPool*)pool; - d3dPool->heap.nextOffset = 0; + d3dPool->resourceHeap.nextOffset = 0; d3dPool->samplerHeap.nextOffset = 0; d3dPool->usedSets = 0; @@ -5497,14 +5583,14 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( // assign offset base to the set so we know where to start and end for each set. set = &d3dPool->sets[d3dPool->usedSets++]; - set->offset = d3dPool->heap.nextOffset; // CSV, UAV, SRV + set->resourceOffset = d3dPool->resourceHeap.nextOffset; set->samplerOffset = d3dPool->samplerHeap.nextOffset; set->layout = d3dLayout; set->pool = d3dPool; Uint32 totalDescriptors = asCount + storageBufferCount + uniformBufferCount; totalDescriptors += sampledImageCount + storageImageCount; - d3dPool->heap.nextOffset += totalDescriptors; + d3dPool->resourceHeap.nextOffset += totalDescriptors; d3dPool->samplerHeap.nextOffset += totalDescriptors; limits->usedAs += asCount; @@ -5535,7 +5621,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { heap = &pool->samplerHeap; } else { - heap = &pool->heap; + heap = &pool->resourceHeap; } // compute the heap index and copy all the descriptors diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 04fc4af1..8a666d5a 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -589,14 +589,15 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set); PalResult PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -1451,14 +1452,15 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set); PalResult PAL_CALL cmdPushConstantsD3D12( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -3743,8 +3745,8 @@ PalResult PAL_CALL palCmdTraceRaysIndirect( PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set) { @@ -3758,8 +3760,8 @@ PalResult PAL_CALL palCmdBindDescriptorSet( return cmdBuffer->backend->cmdBindDescriptorSet( cmdBuffer, - bindPoint, layout, + bindPoint, setIndex, set); } @@ -3767,6 +3769,7 @@ PalResult PAL_CALL palCmdBindDescriptorSet( PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -3781,8 +3784,17 @@ PalResult PAL_CALL palCmdPushConstants( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend - ->cmdPushConstants(cmdBuffer, layout, shaderStageCount, shaderStages, offset, size, value); + // clang-format off + return cmdBuffer->backend->cmdPushConstants( + cmdBuffer, + layout, + bindPoint, + shaderStageCount, + shaderStages, + offset, + size, + value); + // clang-format on } PalResult PAL_CALL palCmdSetCullMode( @@ -4190,6 +4202,10 @@ PalResult PAL_CALL palCreateDescriptorPool( return PAL_RESULT_NULL_POINTER; } + if (!info->maxDescriptorSets) { + return PAL_RESULT_INVALID_ARGUMENT; + } + PalResult result; PalDescriptorPool* pool = nullptr; result = device->backend->createDescriptorPool(device, info, &pool); diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 79ea6d0f..e2bf7cce 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -7434,8 +7434,8 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set) { @@ -7467,6 +7467,7 @@ PalResult PAL_CALL cmdBindDescriptorSetVk( PalResult PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, + PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint64 offset, diff --git a/tests/compute_test.c b/tests/compute_test.c index b03577a9..ca91b58a 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -6,9 +6,11 @@ #define BUFFER_SIZE 400 +// layout must match shader typedef struct { Uint32 width; Uint32 height; + Uint32 _padding[2]; float color[4]; } PushConstant; @@ -453,6 +455,7 @@ bool computeTest() result = palCmdPushConstants( cmdBuffer, pipelineLayout, + bindPoint, 1, shaderStages, 0, @@ -465,7 +468,7 @@ bool computeTest() return false; } - result = palCmdBindDescriptorSet(cmdBuffer, bindPoint, pipelineLayout, 0, descriptorSet); + result = palCmdBindDescriptorSet(cmdBuffer, pipelineLayout, bindPoint, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index e34de547..73e86139 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -905,7 +905,7 @@ bool rayTracingTest() return false; } - result = palCmdBindDescriptorSet(cmdBuffer, bindPoint, pipelineLayout, 0, descriptorSet); + result = palCmdBindDescriptorSet(cmdBuffer, pipelineLayout, bindPoint, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); diff --git a/tests/texture_test.c b/tests/texture_test.c index 20a5f538..25569d30 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -1264,8 +1264,8 @@ bool textureTest() result = palCmdBindDescriptorSet( cmdBuffers[currentFrame], - bindPoint, pipelineLayout, + bindPoint, 0, descriptorSet); From cbeb421d70aa5b73e503e1ced3f02dd80dffb7ff Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 16 Apr 2026 10:41:52 +0000 Subject: [PATCH 161/372] remove bind point redundancy d3d12 --- include/pal/pal_graphics.h | 3 --- src/graphics/pal_d3d12.c | 10 ++++------ src/graphics/pal_graphics.c | 5 +---- src/graphics/pal_vulkan.c | 19 +++++-------------- tests/compute_test.c | 4 ++-- tests/mesh_test.c | 3 +-- tests/ray_tracing_test.c | 4 ++-- tests/texture_test.c | 4 ++-- tests/triangle_test.c | 3 +-- 9 files changed, 18 insertions(+), 37 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 07875496..6fe93337 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3304,7 +3304,6 @@ typedef struct { */ PalResult PAL_CALL (*cmdBindPipeline)( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipeline* pipeline); /** @@ -5717,7 +5716,6 @@ PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( * set at the respective creation functions. (`palCreate**Graphics/Compute/RayTracing**Pipeline`). * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] bindPoint The Binding point. Must match pipeline type. * @param[in] pipeline Pipeline to bind. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -5730,7 +5728,6 @@ PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( */ PAL_API PalResult PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipeline* pipeline); /** diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 7f869a94..8424a8b8 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -48,9 +48,7 @@ freely, subject to the following restrictions: #define TEXTURE_PITCH 256 #define MAX_RTV 1024 #define MAX_DSV 512 -#define CONSTANT_INDEX 0 -#define DESCRIPTOR_TABLE_INDEX 1 -#define SAMPLER_DESCRIPTOR_TABLE_INDEX 2 +#define RAY_TRACING_PIPELINE 1220 // IIDS const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; @@ -258,6 +256,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + Uint32 type; void* handle; } Pipeline; @@ -1678,7 +1677,7 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( caps->maxUniformBufferSize = D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT * 16; caps->maxStorageBufferSize = PAL_LIMIT_UNKNOWN; - caps->maxPushConstantSize = D3D12_MAX_ROOT_COST * 4; + caps->maxPushConstantSize = (D3D12_MAX_ROOT_COST - 2) * 4; caps->maxComputeWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; caps->maxComputeWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; @@ -4385,12 +4384,11 @@ PalResult PAL_CALL cmdCopyImageToBufferD3D12( PalResult PAL_CALL cmdBindPipelineD3D12( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipeline* pipeline) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* d3dPipeline = (Pipeline*)pipeline; - if (bindPoint == PAL_PIPELINE_BIND_POINT_RAY_TRACING) { + if (d3dPipeline->type == RAY_TRACING_PIPELINE) { d3dCmdBuffer->handle6->lpVtbl->SetPipelineState1( d3dCmdBuffer->handle6, d3dPipeline->handle); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 8a666d5a..022e1b60 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -471,7 +471,6 @@ PalResult PAL_CALL cmdCopyImageToBufferVk( PalResult PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipeline* pipeline); PalResult PAL_CALL cmdSetViewportVk( @@ -1334,7 +1333,6 @@ PalResult PAL_CALL cmdCopyImageToBufferD3D12( PalResult PAL_CALL cmdBindPipelineD3D12( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipeline* pipeline); PalResult PAL_CALL cmdSetViewportD3D12( @@ -3380,7 +3378,6 @@ PalResult PAL_CALL palCmdCopyImageToBuffer( PalResult PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipeline* pipeline) { if (!s_Graphics.initialized) { @@ -3391,7 +3388,7 @@ PalResult PAL_CALL palCmdBindPipeline( return PAL_RESULT_NULL_POINTER; } - return cmdBuffer->backend->cmdBindPipeline(cmdBuffer, bindPoint, pipeline); + return cmdBuffer->backend->cmdBindPipeline(cmdBuffer, pipeline); } PalResult PAL_CALL palCmdSetViewport( diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e2bf7cce..ff6f1d04 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -51,9 +51,6 @@ freely, subject to the following restrictions: // ================================================== #define MAX_ATTACHMENTS 32 -#define GRAPHICS_PIPELINE 125 -#define RAY_TRACING_PIPELINE 126 -#define COMPUTE_PIPELINE 127 #pragma region Video @@ -586,6 +583,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + VkPipelineBindPoint bindPoint; Device* device; VkPipeline handle; } Pipeline; @@ -6922,21 +6920,11 @@ PalResult PAL_CALL cmdCopyImageToBufferVk( PalResult PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, - PalPipelineBindPoint bindPoint, PalPipeline* pipeline) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* vkPipeline = (Pipeline*)pipeline; - - VkPipelineBindPoint point = VK_PIPELINE_BIND_POINT_GRAPHICS; - if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { - point = VK_PIPELINE_BIND_POINT_COMPUTE; - - } else if (bindPoint == PAL_PIPELINE_BIND_POINT_RAY_TRACING) { - point = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; - } - - s_Vk.cmdBindPipeline(vkCmdBuffer->handle, point, vkPipeline->handle); + s_Vk.cmdBindPipeline(vkCmdBuffer->handle, vkPipeline->bindPoint, vkPipeline->handle); return PAL_RESULT_SUCCESS; } @@ -8831,6 +8819,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( palFree(s_Vk.allocator, blendattachments); } + pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; pipeline->device = vkDevice; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -8869,6 +8858,7 @@ PalResult PAL_CALL createComputePipelineVk( return resultFromVk(result); } + pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; pipeline->device = vkDevice; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -8949,6 +8939,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( return resultFromVk(result); } + pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; pipeline->device = vkDevice; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; diff --git a/tests/compute_test.c b/tests/compute_test.c index ca91b58a..d7b57e98 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -444,14 +444,14 @@ bool computeTest() pushConstant.color[2] = 0.0f; pushConstant.color[3] = 1.0f; - PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_COMPUTE; - result = palCmdBindPipeline(cmdBuffer, bindPoint, pipeline); + result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); return false; } + PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_COMPUTE; result = palCmdPushConstants( cmdBuffer, pipelineLayout, diff --git a/tests/mesh_test.c b/tests/mesh_test.c index 602a1a8d..7241591e 100644 --- a/tests/mesh_test.c +++ b/tests/mesh_test.c @@ -669,8 +669,7 @@ bool meshTest() } // bind pipeline - PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_GRAPHICS; - result = palCmdBindPipeline(cmdBuffers[currentFrame], bindPoint, pipeline); + result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index 73e86139..b4f89f2a 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -897,14 +897,14 @@ bool rayTracingTest() return false; } - PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_RAY_TRACING; - result = palCmdBindPipeline(cmdBuffer, bindPoint, pipeline); + result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); return false; } + PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_RAY_TRACING; result = palCmdBindDescriptorSet(cmdBuffer, pipelineLayout, bindPoint, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/texture_test.c b/tests/texture_test.c index 25569d30..0ec88730 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -1254,14 +1254,14 @@ bool textureTest() } // bind pipeline - PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_GRAPHICS; - result = palCmdBindPipeline(cmdBuffers[currentFrame], bindPoint, pipeline); + result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); return false; } + PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_GRAPHICS; result = palCmdBindDescriptorSet( cmdBuffers[currentFrame], pipelineLayout, diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 0bf5b507..69d9ea15 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -856,8 +856,7 @@ bool triangleTest() } // bind pipeline - PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_GRAPHICS; - result = palCmdBindPipeline(cmdBuffers[currentFrame], bindPoint, pipeline); + result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); From 31e8bb3907b02a623ced8202a6ebb4a518736d96 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 16 Apr 2026 13:06:17 +0000 Subject: [PATCH 162/372] add acceleration structure API d3d12 --- include/pal/pal_graphics.h | 3 + src/graphics/pal_d3d12.c | 292 ++++++++++++++++++++++++------------- 2 files changed, 192 insertions(+), 103 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 6fe93337..fa199946 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -6473,6 +6473,9 @@ PAL_API PalResult PAL_CALL palCmdSetStencilOp( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. + * + * @note The memory associated with PalAccelerationStructureCreateInfo::buffer must be + * `PAL_MEMORY_TYPE_GPU_ONLY`. * * @since 1.4 * @ingroup pal_graphics diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 8424a8b8..084416b1 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -48,7 +48,10 @@ freely, subject to the following restrictions: #define TEXTURE_PITCH 256 #define MAX_RTV 1024 #define MAX_DSV 512 -#define RAY_TRACING_PIPELINE 1220 + +#define GRAPHICS_PIPELINE 1220 +#define COMPUTE_PIPELINE 1221 +#define RAY_TRACING_PIPELINE 1222 // IIDS const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; @@ -68,6 +71,7 @@ const IID IID_CmdList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96,0xcf, 0x56,0x89,0xa9, const IID IID_Signature = {0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1}; const IID IID_DescHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51}; const IID IID_RootSig = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14}; +const IID IID_Device5 = {0x8b4f173b, 0x2fea, 0x4b80, 0x8f,0x58, 0x43,0x07,0x19,0x1a,0xb9,0x5d}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -133,7 +137,7 @@ typedef struct { ID3D12CommandSignature* raySignature; ID3D12InfoQueue* infoQueue; ID3D12CommandQueue* queue; - ID3D12Device* handle; + ID3D12Device5* handle; RTVHeapAllocator rtvAllocator; DSVHeapAllocator dsvAllocator; } Device; @@ -220,8 +224,7 @@ typedef struct { Device* device; ID3D12Resource* tmpBuffer; ID3D12CommandAllocator* allocator; - ID3D12GraphicsCommandList* handle; - ID3D12GraphicsCommandList6* handle6; + ID3D12GraphicsCommandList6* handle; } CommandBuffer; typedef struct { @@ -246,10 +249,8 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + PalAccelerationStructureType type; D3D12_GPU_VIRTUAL_ADDRESS address; - ID3D12Resource* buffer; - ID3D12Heap* bufferMemory; - D3D12_GPU_VIRTUAL_ADDRESS bufferAddress; ID3D12Resource* handle; } AccelerationStructure; @@ -257,6 +258,7 @@ typedef struct { const PalGraphicsBackend* backend; Uint32 type; + D3D_PRIMITIVE_TOPOLOGY topology; void* handle; } Pipeline; @@ -1804,7 +1806,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_SWAPCHAIN; features |= PAL_ADAPTER_FEATURE_FENCE_RESET; features |= PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE; - features |= PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY; features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; @@ -1834,12 +1835,14 @@ PalResult PAL_CALL createDeviceD3D12( return PAL_RESULT_OUT_OF_MEMORY; } + ID3D12Device* tmpDevice = nullptr; memset(device, 0, sizeof(Device)); + result = s_D3D.createDevice( (IUnknown*)d3dAdapter->handle, d3dAdapter->level, &IID_Device, - (void**)&device->handle); + (void**)&tmpDevice); if (FAILED(result)) { palFree(s_D3D.allocator, device); @@ -1849,6 +1852,12 @@ PalResult PAL_CALL createDeviceD3D12( return PAL_RESULT_INVALID_DRIVER; } + result = tmpDevice->lpVtbl->QueryInterface( + tmpDevice, + &IID_Device5, + (void**)&device->handle); + + tmpDevice->lpVtbl->Release(tmpDevice); if (s_D3D.debugLayer) { result = device->handle->lpVtbl->QueryInterface( device->handle, @@ -3683,7 +3692,6 @@ void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) } CommandBuffer* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; - cmdBuffer->handle6->lpVtbl->Release(cmdBuffer->handle6); cmdBuffer->handle->lpVtbl->Release(cmdBuffer->handle); cmdBuffer->allocator->lpVtbl->Release(cmdBuffer->allocator); } @@ -3744,6 +3752,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( } // create the command list + ID3D12GraphicsCommandList* cmdList = nullptr; result = d3dDevice->handle->lpVtbl->CreateCommandList( d3dDevice->handle, 0, @@ -3751,7 +3760,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( cmdBuffer->allocator, nullptr, &IID_CmdList, - (void**)&cmdBuffer->handle); + (void**)&cmdList); if (FAILED(result)) { if (result == E_OUTOFMEMORY) { @@ -3791,11 +3800,12 @@ PalResult PAL_CALL allocateCommandBufferD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - cmdBuffer->handle->lpVtbl->QueryInterface( - cmdBuffer->handle, + cmdList->lpVtbl->QueryInterface( + cmdList, &IID_CmdList6, - (void**)&cmdBuffer->handle6); + (void**)&cmdBuffer->handle); + cmdList->lpVtbl->Release(cmdList); cmdBuffer->pool = cmdPool; cmdBuffer->device = d3dDevice; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; @@ -3808,7 +3818,6 @@ void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) CommandPool* pool = d3dCmdBuffer->pool; CommandBufferData* data = findCmdBufferData(pool, d3dCmdBuffer); if (data) { - d3dCmdBuffer->handle6->lpVtbl->Release(d3dCmdBuffer->handle6); d3dCmdBuffer->handle->lpVtbl->Release(d3dCmdBuffer->handle); d3dCmdBuffer->allocator->lpVtbl->Release(d3dCmdBuffer->allocator); d3dCmdBuffer->tmpBuffer->lpVtbl->Release(d3dCmdBuffer->tmpBuffer); @@ -3930,8 +3939,8 @@ PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); } - d3dCmdBuffer->handle6->lpVtbl->RSSetShadingRate( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->RSSetShadingRate( + d3dCmdBuffer->handle, shadingRate, combinerOps); @@ -3950,8 +3959,8 @@ PalResult PAL_CALL cmdDrawMeshTasksD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - d3dCmdBuffer->handle6->lpVtbl->DispatchMesh( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->DispatchMesh( + d3dCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); @@ -3971,8 +3980,8 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( } Buffer* d3dBuffer = (Buffer*)buffer; - d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle, device->meshSignature, drawCount, d3dBuffer->handle, @@ -3997,8 +4006,8 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( Buffer* d3dBuffer = (Buffer*)buffer; Buffer* d3dCountBuffer = (Buffer*)countBuffer; - d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle, device->meshSignature, maxDrawCount, d3dBuffer->handle, @@ -4047,23 +4056,24 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( dstAs->address, &buildInfo); - palFree(s_D3D.allocator, geometries); - d3dCmdBuffer->handle6->lpVtbl->BuildRaytracingAccelerationStructure( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( + d3dCmdBuffer->handle, &buildInfo, 0, nullptr); + palFree(s_D3D.allocator, geometries); + } else { fillVkBuildInfoD3D12( info, - geometries, + nullptr, srcAsAddress, dstAs->address, &buildInfo); - d3dCmdBuffer->handle6->lpVtbl->BuildRaytracingAccelerationStructure( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( + d3dCmdBuffer->handle, &buildInfo, 0, nullptr); @@ -4096,16 +4106,16 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( Uint32 base = allocator->baseOffset; depthStencilAttachment.ptr = getDescriptorHandleD3D12(tmp->heapIndex, size, base); - d3dCmdBuffer->handle6->lpVtbl->OMSetRenderTargets( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->OMSetRenderTargets( + d3dCmdBuffer->handle, info->colorAttachentCount, colorAttachments, FALSE, &depthStencilAttachment); } else { - d3dCmdBuffer->handle6->lpVtbl->OMSetRenderTargets( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->OMSetRenderTargets( + d3dCmdBuffer->handle, info->colorAttachentCount, colorAttachments, FALSE, @@ -4120,8 +4130,8 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( color[2] = info->colorAttachments[i].clearValue.color[2]; color[3] = info->colorAttachments[i].clearValue.color[3]; - d3dCmdBuffer->handle6->lpVtbl->ClearRenderTargetView( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->ClearRenderTargetView( + d3dCmdBuffer->handle, colorAttachments[i], color, 0, nullptr); } @@ -4140,8 +4150,8 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( clearFlags |= D3D12_CLEAR_FLAG_STENCIL; } - d3dCmdBuffer->handle6->lpVtbl->ClearDepthStencilView( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->ClearDepthStencilView( + d3dCmdBuffer->handle, depthStencilAttachment, clearFlags, depth, @@ -4152,8 +4162,8 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( if (info->fragmentShadingRateAttachment) { ImageView* tmp = (ImageView*)info->fragmentShadingRateAttachment->imageView; - d3dCmdBuffer->handle6->lpVtbl->RSSetShadingRateImage( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->RSSetShadingRateImage( + d3dCmdBuffer->handle, tmp->image->handle); } @@ -4175,8 +4185,8 @@ PalResult PAL_CALL cmdCopyBufferD3D12( Buffer* dstbuffer = (Buffer*)dst; Buffer* srcBuffer = (Buffer*)src; - d3dCmdBuffer->handle6->lpVtbl->CopyBufferRegion( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->CopyBufferRegion( + d3dCmdBuffer->handle, dstbuffer->handle, copyInfo->dstOffset, srcBuffer->handle, @@ -4236,8 +4246,8 @@ PalResult PAL_CALL cmdCopyBufferToImageD3D12( Uint32 index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); dstLocation.SubresourceIndex = index; - d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( + d3dCmdBuffer->handle, &dstLocation, copyInfo->imageOffsetX, copyInfo->imageOffsetY, @@ -4302,8 +4312,8 @@ PalResult PAL_CALL cmdCopyImageD3D12( dstLocation.SubresourceIndex = dstIndex; srcLocation.SubresourceIndex = srcIndex; - d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( + d3dCmdBuffer->handle, &dstLocation, copyInfo->dstOffsetX, copyInfo->dstOffsetY, @@ -4368,8 +4378,8 @@ PalResult PAL_CALL cmdCopyImageToBufferD3D12( Uint32 index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); srcLocation.SubresourceIndex = index; - d3dCmdBuffer->handle6->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( + d3dCmdBuffer->handle, &dstLocation, 0, 0, @@ -4389,14 +4399,20 @@ PalResult PAL_CALL cmdBindPipelineD3D12( CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* d3dPipeline = (Pipeline*)pipeline; if (d3dPipeline->type == RAY_TRACING_PIPELINE) { - d3dCmdBuffer->handle6->lpVtbl->SetPipelineState1( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->SetPipelineState1( + d3dCmdBuffer->handle, d3dPipeline->handle); } else { - d3dCmdBuffer->handle6->lpVtbl->SetPipelineState( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->SetPipelineState( + d3dCmdBuffer->handle, d3dPipeline->handle); + + if (d3dPipeline->type == GRAPHICS_PIPELINE) { + d3dCmdBuffer->handle->lpVtbl->IASetPrimitiveTopology( + d3dCmdBuffer->handle, + d3dPipeline->topology); + } } return PAL_RESULT_SUCCESS; @@ -4431,7 +4447,7 @@ PalResult PAL_CALL cmdSetViewportD3D12( tmp->MaxDepth = viewports[i].maxDepth; } - d3dCmdBuffer->handle6->lpVtbl->RSSetViewports(d3dCmdBuffer->handle6, count, d3dViewports); + d3dCmdBuffer->handle->lpVtbl->RSSetViewports(d3dCmdBuffer->handle, count, d3dViewports); if (count > 1) { palFree(s_D3D.allocator, d3dViewports); } @@ -4465,7 +4481,7 @@ PalResult PAL_CALL cmdSetScissorsD3D12( tmp->bottom = scissors[i].height; } - d3dCmdBuffer->handle6->lpVtbl->RSSetScissorRects(d3dCmdBuffer->handle6, count, d3dScissors); + d3dCmdBuffer->handle->lpVtbl->RSSetScissorRects(d3dCmdBuffer->handle, count, d3dScissors); if (count > 1) { palFree(s_D3D.allocator, d3dScissors); } @@ -4502,8 +4518,8 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( views[i].StrideInBytes = strides[i]; } - d3dCmdBuffer->handle6->lpVtbl->IASetVertexBuffers( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->IASetVertexBuffers( + d3dCmdBuffer->handle, firstSlot, count, views); @@ -4533,7 +4549,7 @@ PalResult PAL_CALL cmdBindIndexBufferD3D12( view.Format = DXGI_FORMAT_R32_UINT; } - d3dCmdBuffer->handle6->lpVtbl->IASetIndexBuffer(d3dCmdBuffer->handle6, &view); + d3dCmdBuffer->handle->lpVtbl->IASetIndexBuffer(d3dCmdBuffer->handle, &view); return PAL_RESULT_SUCCESS; } @@ -4545,8 +4561,8 @@ PalResult PAL_CALL cmdDrawD3D12( Uint32 firstInstance) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - d3dCmdBuffer->handle6->lpVtbl->DrawInstanced( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->DrawInstanced( + d3dCmdBuffer->handle, vertexCount, instanceCount, firstVertex, @@ -4567,8 +4583,8 @@ PalResult PAL_CALL cmdDrawIndirectD3D12( } Buffer* d3dBuffer = (Buffer*)buffer; - d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle, device->drawSignature, count, d3dBuffer->handle, @@ -4593,8 +4609,8 @@ PalResult PAL_CALL cmdDrawIndirectCountD3D12( Buffer* d3dBuffer = (Buffer*)buffer; Buffer* d3dCountBuffer = (Buffer*)countBuffer; - d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle, device->drawSignature, maxDrawCount, d3dBuffer->handle, @@ -4614,8 +4630,8 @@ PalResult PAL_CALL cmdDrawIndexedD3D12( Uint32 firstInstance) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - d3dCmdBuffer->handle6->lpVtbl->DrawIndexedInstanced( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->DrawIndexedInstanced( + d3dCmdBuffer->handle, indexCount, instanceCount, firstIndex, @@ -4637,8 +4653,8 @@ PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( } Buffer* d3dBuffer = (Buffer*)buffer; - d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle, device->drawIndexedSignature, count, d3dBuffer->handle, @@ -4663,8 +4679,8 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( Buffer* d3dBuffer = (Buffer*)buffer; Buffer* d3dCountBuffer = (Buffer*)countBuffer; - d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle, device->drawIndexedSignature, maxDrawCount, d3dBuffer->handle, @@ -4703,7 +4719,7 @@ PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.UAV.pResource = d3dAS->handle; - d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, 1, &barrier); + d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); return PAL_RESULT_SUCCESS; } @@ -4733,7 +4749,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( if (old == new && old == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.UAV.pResource = d3dImage->handle; - d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, 1, &barrier); + d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); return PAL_RESULT_SUCCESS; } @@ -4760,7 +4776,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( barrier.Transition.StateAfter = new; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, 1, &barrier); + d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); return PAL_RESULT_SUCCESS; } @@ -4772,7 +4788,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( barrier.Transition.StateAfter = new; barrier.Transition.Subresource = startLevel + startLayer * maxLevels; - d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, 1, &barrier); + d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); return PAL_RESULT_SUCCESS; } @@ -4797,7 +4813,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( } } - d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, barrierCount, barriers); + d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, barrierCount, barriers); palFree(s_D3D.allocator, barriers); return PAL_RESULT_SUCCESS; } @@ -4833,7 +4849,7 @@ PalResult PAL_CALL cmdBufferBarrierD3D12( barrier.Transition.StateAfter = new; } - d3dCmdBuffer->handle6->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle6, 1, &barrier); + d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); return PAL_RESULT_SUCCESS; } @@ -4844,14 +4860,13 @@ PalResult PAL_CALL cmdDispatchD3D12( Uint32 groupCountZ) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - d3dCmdBuffer->handle6->lpVtbl->Dispatch( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->Dispatch( + d3dCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); return PAL_RESULT_SUCCESS; - } PalResult PAL_CALL cmdDispatchBaseD3D12( @@ -4881,8 +4896,8 @@ PalResult PAL_CALL cmdDispatchIndirectD3D12( } Buffer* d3dBuffer = (Buffer*)buffer; - d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle, device->dispatchSignature, 1, // one dispatch d3dBuffer->handle, @@ -4920,7 +4935,7 @@ PalResult PAL_CALL cmdTraceRaysD3D12( desc.MissShaderTable = d3dSbt->missAddress; desc.CallableShaderTable = d3dSbt->callableAddress; - d3dCmdBuffer->handle6->lpVtbl->DispatchRays(d3dCmdBuffer->handle6, &desc); + d3dCmdBuffer->handle->lpVtbl->DispatchRays(d3dCmdBuffer->handle, &desc); return PAL_RESULT_SUCCESS; } @@ -4970,8 +4985,8 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( memcpy(ptr, &desc, sizeof(D3D12_DISPATCH_RAYS_DESC)); d3dCmdBuffer->tmpBuffer->lpVtbl->Unmap(d3dCmdBuffer->tmpBuffer, 0, nullptr); - d3dCmdBuffer->handle6->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3dCmdBuffer->handle, device->raySignature, 1, d3dCmdBuffer->tmpBuffer, @@ -5004,7 +5019,7 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( if (pool->hasSamplerHeap) { heaps[heapCount++] = pool->samplerHeap.handle; } - d3dCmdBuffer->handle6->lpVtbl->SetDescriptorHeaps(d3dCmdBuffer->handle6, heapCount, heaps); + d3dCmdBuffer->handle->lpVtbl->SetDescriptorHeaps(d3dCmdBuffer->handle, heapCount, heaps); // bind descriptor tables if (pipelineLayout->resourceIndex != UINT32_MAX) { @@ -5016,14 +5031,14 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( pool->resourceHeap.gpuBase); if (bindPoint == PAL_PIPELINE_BIND_POINT_GRAPHICS) { - d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRootDescriptorTable( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( + d3dCmdBuffer->handle, pipelineLayout->resourceIndex, base); } else if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { - d3dCmdBuffer->handle6->lpVtbl->SetComputeRootDescriptorTable( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( + d3dCmdBuffer->handle, pipelineLayout->resourceIndex, base); @@ -5041,14 +5056,14 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( pool->samplerHeap.gpuBase); if (bindPoint == PAL_PIPELINE_BIND_POINT_GRAPHICS) { - d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRootDescriptorTable( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( + d3dCmdBuffer->handle, pipelineLayout->samplerIndex, base); } else if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { - d3dCmdBuffer->handle6->lpVtbl->SetComputeRootDescriptorTable( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( + d3dCmdBuffer->handle, pipelineLayout->samplerIndex, base); @@ -5073,18 +5088,17 @@ PalResult PAL_CALL cmdPushConstantsD3D12( CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; PipelineLayout* pipelineLayout = (PipelineLayout*)layout; if (pipelineLayout->constantIndex != UINT32_MAX) { - if (bindPoint == PAL_PIPELINE_BIND_POINT_GRAPHICS) { - d3dCmdBuffer->handle6->lpVtbl->SetGraphicsRoot32BitConstants( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->SetGraphicsRoot32BitConstants( + d3dCmdBuffer->handle, pipelineLayout->constantIndex, size / 4, value, offset / 4); } else if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { - d3dCmdBuffer->handle6->lpVtbl->SetComputeRoot32BitConstants( - d3dCmdBuffer->handle6, + d3dCmdBuffer->handle->lpVtbl->SetComputeRoot32BitConstants( + d3dCmdBuffer->handle, pipelineLayout->constantIndex, size / 4, value, @@ -5102,35 +5116,35 @@ PalResult PAL_CALL cmdSetCullModeD3D12( PalCommandBuffer* cmdBuffer, PalCullMode cullMode) { - + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } PalResult PAL_CALL cmdSetFrontFaceD3D12( PalCommandBuffer* cmdBuffer, PalFrontFace frontFace) { - + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( PalCommandBuffer* cmdBuffer, PalPrimitiveTopology topology) { - + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } PalResult PAL_CALL cmdSetDepthTestEnableD3D12( PalCommandBuffer* cmdBuffer, bool enable) { - + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( PalCommandBuffer* cmdBuffer, bool enable) { - + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } PalResult PAL_CALL cmdSetStencilOpD3D12( @@ -5141,7 +5155,7 @@ PalResult PAL_CALL cmdSetStencilOpD3D12( PalStencilOp depthFailOp, PalCompareOp compareOp) { - + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } // ================================================== @@ -5153,12 +5167,33 @@ PalResult PAL_CALL createAccelerationstructureD3D12( const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs) { + HRESULT result; + AccelerationStructure* as = nullptr; + Device* d3dDevice = (Device*)device; + Buffer* d3dBuffer = (Buffer*)info->buffer; + + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + as = palAllocate(s_D3D.allocator, sizeof(AccelerationStructure), 0); + if (!as) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + as->type = info->type; + as->handle = d3dBuffer->handle; + as->address = as->handle->lpVtbl->GetGPUVirtualAddress(as->handle); + as->address += info->offset; + *outAs = (PalAccelerationStructure*)as; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as) { - + AccelerationStructure* d3dAs = (AccelerationStructure*)as; + palFree(s_D3D.allocator, d3dAs); } PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( @@ -5166,7 +5201,58 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { + Device* d3dDevice = (Device*)device; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO sizeInfo = {0}; + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + geometries = palAllocate( + s_D3D.allocator, + sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount, + 0); + + if (!geometries) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); + fillVkBuildInfoD3D12( + info, + geometries, + nullptr, + nullptr, + &buildInfo); + + d3dDevice->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( + d3dDevice->handle, + &buildInfo.Inputs, + &sizeInfo); + + palFree(s_D3D.allocator, geometries); + + } else { + fillVkBuildInfoD3D12( + info, + nullptr, + nullptr, + nullptr, + &buildInfo); + + d3dDevice->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( + d3dDevice->handle, + &buildInfo.Inputs, + &sizeInfo); + } + + size->accelerationStructureSize = sizeInfo.ResultDataMaxSizeInBytes; + size->scratchBufferSize = sizeInfo.ScratchDataSizeInBytes; + size->updateScratchBufferSize = sizeInfo.UpdateScratchDataSizeInBytes; + return PAL_RESULT_SUCCESS; } // ================================================== From f9e8a34cfe6a457b0bca59eb5b4d8e5f0f4640fd Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 16 Apr 2026 23:55:30 +0000 Subject: [PATCH 163/372] add pipeline layout API d3d12 --- include/pal/pal_graphics.h | 36 ++++ src/graphics/pal_d3d12.c | 325 ++++++++++++++++++++++++++++++++++--- src/graphics/pal_vulkan.c | 59 +++++-- 3 files changed, 390 insertions(+), 30 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index fa199946..603d2196 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1222,6 +1222,24 @@ typedef enum { PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY = PAL_BIT(2) } PalAccelerationStructureBuildHints; +/** + * @enum PalAccelerationStructureInstanceFlags + * @brief Acceleration structure instance flags. Multiple flags can be OR'ed together using + * bitwise OR operator (`|`). Not all combinations are valid. + * + * All acceleration structure instance flags follow the format + * `PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_**` for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE = PAL_BIT(0), + PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE = PAL_BIT(1), + PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE = PAL_BIT(2), + PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE = PAL_BIT(3) +} PalAccelerationStructureInstanceFlags; + /** * @enum PalGeometryType * @brief Geometry types. @@ -1236,6 +1254,21 @@ typedef enum { PAL_GEOMETRY_TYPE_AABBS } PalGeometryType; +/** + * @enum PalGeometryFlags + * @brief Geometry flags. Multiple flags can be OR'ed together using + * bitwise OR operator (`|`). Not all combinations are valid. + * + * All geometry flags follow the format `PAL_GEOMETRY_FLAG_**` for consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_GEOMETRY_FLAG_OPAQUE = PAL_BIT(0), + PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT = PAL_BIT(1) +} PalGeometryFlags; + /** * @enum PalIndexType * @brief Index types. @@ -2049,6 +2082,8 @@ typedef struct { typedef struct { Uint32 instanceId; /**< User defined id.*/ Uint32 mask; + Uint32 hitGroupOffset; + PalAccelerationStructureInstanceFlags flags; PalAccelerationStructure* blas; /**< BLAS to use.*/ float transform[12]; /**< row major (3x4).*/ } PalAccelerationStructureInstance; @@ -2109,6 +2144,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + PalGeometryFlags flags; Uint32 primitiveCount; PalGeometryType type; /**< (eg. PAL_GEOMETRY_TYPE_TRIANGLE).*/ void* data; /**< Pointer to geometry data. This will be casted based on the geometry type.*/ diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 084416b1..6eb3e5d8 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -161,7 +161,7 @@ typedef struct { const PalGraphicsBackend* backend; bool belongsToSwapchain; - ID3D12Device* device; + ID3D12Device5* device; ID3D12Resource* handle; PalImageInfo info; D3D12_RESOURCE_DESC desc; @@ -242,8 +242,11 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + bool supportsAddress; Uint64 size; ID3D12Resource* handle; + ID3D12Device5* device; + D3D12_RESOURCE_DESC desc; } Buffer; typedef struct { @@ -982,7 +985,14 @@ static void fillVkBuildInfoD3D12( { for (int i = 0; i < info->geometryCount; i++) { D3D12_RAYTRACING_GEOMETRY_DESC* tmp = &geometries[i]; - tmp->Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; + tmp->Flags = 0; + if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_OPAQUE) { + tmp->Flags |= D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; + } + + if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT) { + tmp->Flags |= D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION; + } if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { tmp->Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; @@ -1399,6 +1409,29 @@ static inline Uint64 getDescriptorHandleD3D12( return baseOffset + index * size; } +static D3D12_RAYTRACING_INSTANCE_FLAGS instanceFlagsToD3D12( + PalAccelerationStructureInstanceFlags flags) +{ + D3D12_RAYTRACING_INSTANCE_FLAGS instanceFlags = 0; + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE) { + instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_OPAQUE; + } + + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE) { + instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_NON_OPAQUE; + } + + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE) { + instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_CULL_DISABLE; + } + + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE) { + instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE; + } + + return instanceFlags; +} + // ================================================== // Adapter // ================================================== @@ -3916,8 +3949,8 @@ PalResult PAL_CALL cmdExecuteCommandBufferD3D12( CommandBuffer* d3dSecondaryCmdBuffer = (CommandBuffer*)secondaryCmdBuffer; d3dPrimaryCmdBuffer->handle->lpVtbl->ExecuteBundle( - d3dPrimaryCmdBuffer->handle, - d3dSecondaryCmdBuffer->handle); + d3dPrimaryCmdBuffer->handle, + (ID3D12GraphicsCommandList*)d3dSecondaryCmdBuffer->handle); return PAL_RESULT_SUCCESS; } @@ -4066,7 +4099,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( } else { fillVkBuildInfoD3D12( - info, + info, nullptr, srcAsAddress, dstAs->address, @@ -5224,8 +5257,8 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( fillVkBuildInfoD3D12( info, geometries, - nullptr, - nullptr, + 0, + 0, &buildInfo); d3dDevice->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( @@ -5239,8 +5272,8 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( fillVkBuildInfoD3D12( info, nullptr, - nullptr, - nullptr, + 0, + 0, &buildInfo); d3dDevice->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( @@ -5264,19 +5297,65 @@ PalResult PAL_CALL createBufferD3D12( const PalBufferCreateInfo* info, PalBuffer** outBuffer) { + HRESULT result; + Buffer* buffer = nullptr; + Device* d3dDevice = (Device*)device; + + buffer = palAllocate(s_D3D.allocator, sizeof(Buffer), 0); + if (!buffer) { + return PAL_RESULT_OUT_OF_MEMORY; + } + memset(buffer, 0, sizeof(Buffer)); + buffer->desc.Width = (UINT64)info->size; + buffer->desc.Height = 1; + buffer->desc.DepthOrArraySize = 1; + buffer->desc.MipLevels = 1; + buffer->desc.SampleDesc.Count = 1; + buffer->desc.SampleDesc.Quality = 0; + buffer->desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + + if (d3dDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { + buffer->supportsAddress = true; + } + + buffer->device = d3dDevice->handle; + *outBuffer = (PalBuffer*)buffer; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyBufferD3D12(PalBuffer* buffer) { - + Buffer* d3dBuffer = (Buffer*)buffer; + // check if memory has been attached to the buffer + if (d3dBuffer->handle) { + d3dBuffer->handle->lpVtbl->Release(d3dBuffer->handle); + } + palFree(s_D3D.allocator, d3dBuffer); } PalResult PAL_CALL getBufferMemoryRequirementsD3D12( PalBuffer* buffer, PalMemoryRequirements* requirements) { + Buffer* d3dBuffer = (Buffer*)buffer; + D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; + D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; + allocationInfo = *d3dBuffer->device->lpVtbl->GetResourceAllocationInfo( + d3dBuffer->device, + &__ret, + 0, + 1, + &d3dBuffer->desc); + // d3d12 allows buffers to be used with all memory heap types + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; + + requirements->alignment = allocationInfo.Alignment; + requirements->size = allocationInfo.SizeInBytes; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( @@ -5284,18 +5363,32 @@ PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( Uint32 instanceCount, Uint64* outSize) { - + *outSize = sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * instanceCount; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( PalDevice* device, - Uint32 imageFormatSize, + PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, Uint32* outBufferRowLength, Uint32* outBufferImageHeight, Uint64* outSize) { - + Uint32 imageFormatSize = getFormatSizeD3D12(imageFormat); + Uint32 height = 0; + Uint64 rowPitch = alignD3D12((Uint64)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; + + *outBufferRowLength = rowPitch; + if (height == copyInfo->imageHeight) { + *outBufferImageHeight = 0; + } else { + *outBufferImageHeight = height; + } + + *outSize = rowPitch * height * copyInfo->imageDepth; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL writeToInstanceBufferD3D12( @@ -5304,17 +5397,51 @@ PalResult PAL_CALL writeToInstanceBufferD3D12( PalAccelerationStructureInstance* instances, Uint32 instanceCount) { + D3D12_RAYTRACING_INSTANCE_DESC* data = ptr; + for (int i = 0; i < instanceCount; i++) { + PalAccelerationStructureInstance* src = &instances[i]; + D3D12_RAYTRACING_INSTANCE_DESC* dst = &data[i]; + AccelerationStructure* as = (AccelerationStructure*)src->blas; + dst->InstanceMask = src->mask; + dst->InstanceID = src->instanceId; + dst->AccelerationStructure = as->address; + dst->InstanceContributionToHitGroupIndex = src->hitGroupOffset; + dst->Flags = instanceFlagsToD3D12(src->flags); + memcpy(dst->Transform, src->transform, sizeof(float) * 12); + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( PalDevice* device, void* ptr, void* srcData, - PalBufferImageCopyInfo* copyInfo, - Uint32 imageFormatSize) + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo) { + Uint32 imageFormatSize = getFormatSizeD3D12(imageFormat); + Uint32 length, height; + length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; + height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; + + // manually offset the buffer with the provided offset + Uint8* dst = (Uint8*)ptr + copyInfo->bufferOffset; + const Uint8* src = (const Uint8*)srcData; + Uint64 tmpSizeDest = length * height * imageFormatSize; + Uint64 tmpSizeSrc = copyInfo->imageWidth * copyInfo->imageHeight * imageFormatSize; + + // write to destination pointer + for (Uint32 z = 0; z < copyInfo->imageDepth; z++) { + for (Uint32 y = 0; y < copyInfo->imageHeight; y++) { + memcpy( + dst + z * tmpSizeDest + y * (length * imageFormatSize), + src + z * tmpSizeSrc + y * (copyInfo->imageWidth * imageFormatSize), + copyInfo->imageWidth * imageFormatSize); + } + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL bindBufferMemoryD3D12( @@ -5322,7 +5449,30 @@ PalResult PAL_CALL bindBufferMemoryD3D12( PalMemory* memory, Uint64 offset) { + HRESULT result; + Buffer* d3dBuffer = (Buffer*)buffer; + + ID3D12Heap* mem = (ID3D12Heap*)memory; + result = d3dBuffer->device->lpVtbl->CreatePlacedResource( + d3dBuffer->device, + mem, + offset, + &d3dBuffer->desc, + 0, + nullptr, + &IID_Resource, + (void**)d3dBuffer->handle); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } else if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL mapBufferMemoryD3D12( @@ -5331,17 +5481,31 @@ PalResult PAL_CALL mapBufferMemoryD3D12( Uint64 size, void** outPtr) { - + void* ptr = nullptr; + Buffer* d3dBuffer = (Buffer*)buffer; + HRESULT result = d3dBuffer->handle->lpVtbl->Map(d3dBuffer->handle, 0, nullptr, &ptr); + if (FAILED(result)) { + return PAL_RESULT_MEMORY_MAP_FAILED; + } + + *outPtr = ptr + offset; + return PAL_RESULT_SUCCESS; } void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer) { - + Buffer* d3dBuffer = (Buffer*)buffer; + d3dBuffer->handle->lpVtbl->Unmap(d3dBuffer->handle, 0, nullptr); } PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer) { - + Buffer* d3dBuffer = (Buffer*)buffer; + if (!d3dBuffer->supportsAddress) { + return 0; + } + + return d3dBuffer->handle->lpVtbl->GetGPUVirtualAddress(d3dBuffer->handle); } // ================================================== @@ -5830,12 +5994,135 @@ PalResult PAL_CALL createPipelineLayoutD3D12( const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout) { + Device* d3dDevice = (Device*)device; + PipelineLayout* layout = nullptr; + Uint32 resourceCount = 0; + Uint32 samplerCount = 0; + Uint32 pushConstantSize = 0; + D3D12_DESCRIPTOR_RANGE1* ranges = nullptr; + D3D12_DESCRIPTOR_RANGE1* samplerRanges = nullptr; + + // get the total resource and sampler ranges for all provided descriptor set layouts + for (int i = 0; i < info->descriptorSetLayoutCount; i++) { + DescriptorSetLayout* tmp = (DescriptorSetLayout*)&info->descriptorSetLayouts[i]; + resourceCount += tmp->bindingCount - tmp->samplerCount; + samplerCount += tmp->samplerCount; + } + + // get the total size needed for all provided push constant range + for (int i = 0; i < info->pushConstantRangeCount; i++) { + PalPushConstantRange* tmp = &info->pushConstantRanges[i]; + if (tmp->offset + tmp->size > pushConstantSize) { + pushConstantSize = tmp->offset + tmp->size; + } + } + + Uint32 sizeInBytes = sizeof(D3D12_DESCRIPTOR_RANGE1); + layout = palAllocate(s_D3D.allocator, sizeof(PipelineLayout), 0); + ranges = palAllocate(s_D3D.allocator, sizeInBytes * resourceCount, 0); + samplerRanges = palAllocate(s_D3D.allocator, sizeInBytes * samplerCount, 0); + if (!layout || !ranges || !samplerRanges) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + for (int i = 0; i < info->descriptorSetLayoutCount; i++) { + DescriptorSetLayout* tmp = (DescriptorSetLayout*)&info->descriptorSetLayouts[i]; + // seperate the samplers from the remaining descriptors + for (int i = 0; i < tmp->bindingCount; i++) { + DescriptorSetBinding* binding = &tmp->bindings[i]; + if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { + samplerRanges[i] = binding->range; + } else { + ranges[i] = binding->range; + } + } + } + + Uint32 paramCount = 0; + layout->constantIndex = UINT32_MAX; + layout->resourceIndex = UINT32_MAX; + layout->samplerIndex = UINT32_MAX; + + // push constant parameter + if (pushConstantSize) { + D3D12_ROOT_PARAMETER1* tmp = &layout->params[paramCount]; + tmp->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + tmp->Constants.Num32BitValues = pushConstantSize / 4; + tmp->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + layout->constantIndex = paramCount; + paramCount++; + } + + // resource parameter + if (resourceCount) { + D3D12_ROOT_PARAMETER1* tmp = &layout->params[paramCount]; + tmp->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + tmp->DescriptorTable.NumDescriptorRanges = resourceCount; + tmp->DescriptorTable.pDescriptorRanges = ranges; + tmp->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + layout->resourceIndex = paramCount; + paramCount++; + } + + // sampler parameter + if (samplerCount) { + D3D12_ROOT_PARAMETER1* tmp = &layout->params[paramCount]; + tmp->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + tmp->DescriptorTable.NumDescriptorRanges = samplerCount; + tmp->DescriptorTable.pDescriptorRanges = samplerRanges; + tmp->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + layout->samplerIndex = paramCount; + paramCount++; + } + + // create root signature + D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; + rootDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; + rootDesc.Desc_1_1.NumParameters = paramCount; + rootDesc.Desc_1_1.pParameters = layout->params; + rootDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ID3DBlob* blob = nullptr; + HRESULT result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + result = d3dDevice->handle->lpVtbl->CreateRootSignature( + d3dDevice->handle, + 0, + blob->lpVtbl->GetBufferPointer(blob), + blob->lpVtbl->GetBufferSize(blob), + &IID_RootSig, + (void**)&layout->handle); + + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + blob->lpVtbl->Release(blob); + palFree(s_D3D.allocator, ranges); + palFree(s_D3D.allocator, samplerRanges); + *outLayout = (PalPipelineLayout*)layout; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout) { - + PipelineLayout* d3dLayout = (PipelineLayout*)layout; + d3dLayout->handle->lpVtbl->Release(d3dLayout->handle); + palFree(s_D3D.allocator, d3dLayout); } // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index ff6f1d04..ecfda63d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2256,7 +2256,15 @@ static void fillVkBuildInfoVk( // fill vulkan geometry struct VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - tmp->flags = VK_GEOMETRY_OPAQUE_BIT_KHR; // always opaque + + tmp->flags = 0; + if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_OPAQUE) { + tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; + } + + if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT) { + tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; + } if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; @@ -2505,6 +2513,28 @@ static VkImageAspectFlags imageAspectToVk(PalImageAspect aspect) return VK_IMAGE_ASPECT_COLOR_BIT; } +static VkGeometryInstanceFlagsKHR instanceFlagsToVk(PalAccelerationStructureInstanceFlags flags) +{ + VkGeometryInstanceFlagsKHR instanceFlags = 0; + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE) { + instanceFlags |= VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR; + } + + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE) { + instanceFlags |= VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR; + } + + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE) { + instanceFlags |= VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; + } + + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE) { + instanceFlags |= VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR; + } + + return instanceFlags; +} + // ================================================== // Adapter // ================================================== @@ -7880,11 +7910,20 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; Uint32 rowPitch = length * getFormatSizeVk(imageFormat); - Uint32 slicePitch = rowPitch * height; - *outBufferRowLength = copyInfo->bufferRowLength; - *outBufferImageHeight = copyInfo->bufferImageHeight; - *outSize = slicePitch * copyInfo->imageDepth; + if (length == copyInfo->imageWidth) { + *outBufferRowLength = 0; + } else { + *outBufferRowLength = length; + } + + if (height == copyInfo->imageHeight) { + *outBufferImageHeight = 0; + } else { + *outBufferImageHeight = height; + } + + *outSize = rowPitch * height * copyInfo->imageDepth; return PAL_RESULT_SUCCESS; } @@ -7901,10 +7940,10 @@ PalResult PAL_CALL writeToInstanceBufferVk( AccelerationStructure* as = (AccelerationStructure*)src->blas; dst->mask = src->mask & 0xFF; - dst->instanceCustomIndex = src->instanceId * 0xFFFFFF; + dst->instanceCustomIndex = src->instanceId & 0xFFFFFF; dst->accelerationStructureReference = as->address; - dst->instanceShaderBindingTableRecordOffset = 0; - dst->flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; + dst->instanceShaderBindingTableRecordOffset = src->hitGroupOffset & 0xFFFFFF; + dst->flags = instanceFlagsToVk(src->flags); memcpy(dst->transform.matrix, src->transform, sizeof(float) * 12); } return PAL_RESULT_SUCCESS; @@ -7928,8 +7967,6 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( Uint32 length, height; length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; - Uint32 rowPitch = length * imageFormatSize; - Uint32 slicePitch = rowPitch * height; // manually offset the buffer with the provided offset Uint8* dst = (Uint8*)ptr + copyInfo->bufferOffset; @@ -7939,7 +7976,7 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( // write to destination pointer for (Uint32 z = 0; z < copyInfo->imageDepth; z++) { - for (Uint32 y = 0; y < copyInfo->imageWidth; y++) { + for (Uint32 y = 0; y < copyInfo->imageHeight; y++) { memcpy( dst + z * tmpSizeDest + y * (length * imageFormatSize), src + z * tmpSizeSrc + y * (copyInfo->imageWidth * imageFormatSize), From 0ce562f573b5e703898d8c730ce5832035d0d447 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 19 Apr 2026 08:41:07 +0000 Subject: [PATCH 164/372] optimize graphics debugger --- include/pal/pal_graphics.h | 8 +++++ src/graphics/pal_d3d12.c | 62 +++++++++++++++++++++++++++++++------- src/graphics/pal_vulkan.c | 33 ++++++++++++++++---- 3 files changed, 86 insertions(+), 17 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 603d2196..266244cb 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1447,6 +1447,8 @@ typedef struct { Uint32 maxUniformBufferSize; Uint32 maxStorageBufferSize; Uint32 maxPushConstantSize; + Uint32 maxVertexLayouts; + Uint32 maxVertexAttributes; Uint32 maxComputeWorkGroupInvocations; /**< Max compute threads per workgroup across all axis.*/ Uint32 maxComputeWorkGroupCount[3]; /**< Max compute workgroups per axis.*/ Uint32 maxComputeWorkGroupSize[3]; /**< Max compute threads per workgroup per axis.*/ @@ -1961,6 +1963,12 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + bool denyGeneral; /**< Disable general messages.*/ + bool denyValidation; /**< Disable validation messages.*/ + bool denyPerformance; /**< Disable performance messages.*/ + bool denyInfoSeverity; + bool denyWarningSeverity; + bool denyErrorSeverity; void* userData; PalDebugCallback callback; } PalGraphicsDebugger; diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 6eb3e5d8..f955718a 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -94,6 +94,8 @@ typedef struct { typedef struct { bool debugLayer; Uint32 adapterCount; + Uint32 severityCount; + Uint32 categoryCount; HMODULE handle; HMODULE dxgi; Adapter* adapters; @@ -107,6 +109,8 @@ typedef struct { PFN_D3D12SerializeVersionedRootSignature serializeVersionedRootSignature; const PalAllocator* allocator; + D3D12_MESSAGE_SEVERITY severities[3]; + D3D12_MESSAGE_CATEGORY categories[3]; } D3D12; typedef struct { @@ -1477,12 +1481,43 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D.debugController1->lpVtbl->SetEnableGPUBasedValidation( s_D3D.debugController1, TRUE); - } + // message types + if (!debugger->denyGeneral) { + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_INITIALIZATION; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_CLEANUP; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_COMPILATION; + } + + if (!debugger->denyPerformance) { + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_EXECUTION; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_SHADER; + } + + if (!debugger->denyValidation) { + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_CREATION; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_GETTING; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_SETTING; + } + + // message severities + if (!debugger->denyInfoSeverity) { + s_D3D.severities[s_D3D.severityCount++] = D3D12_MESSAGE_SEVERITY_INFO; + } + + if (!debugger->denyWarningSeverity) { + s_D3D.severities[s_D3D.severityCount++] = D3D12_MESSAGE_SEVERITY_WARNING; + } + + if (!debugger->denyErrorSeverity) { + s_D3D.severities[s_D3D.severityCount++] = D3D12_MESSAGE_SEVERITY_ERROR; + s_D3D.severities[s_D3D.severityCount++] = D3D12_MESSAGE_SEVERITY_CORRUPTION; + } + } s_D3D.debugLayer = true; } } - // clang-format on s_D3D.factory = nullptr; @@ -1713,6 +1748,8 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( caps->maxUniformBufferSize = D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT * 16; caps->maxStorageBufferSize = PAL_LIMIT_UNKNOWN; caps->maxPushConstantSize = (D3D12_MAX_ROOT_COST - 2) * 4; + caps->maxVertexLayouts = PAL_LIMIT_UNKNOWN; + caps->maxVertexAttributes = PAL_LIMIT_UNKNOWN; caps->maxComputeWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; caps->maxComputeWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; @@ -1898,17 +1935,12 @@ PalResult PAL_CALL createDeviceD3D12( (void**)&device->infoQueue); if (SUCCEEDED(result)) { - D3D12_MESSAGE_SEVERITY severities[] = { - D3D12_MESSAGE_SEVERITY_WARNING, - D3D12_MESSAGE_SEVERITY_ERROR, - D3D12_MESSAGE_SEVERITY_CORRUPTION - }; - D3D12_MESSAGE_ID denyIDs[] = { D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE }; - D3D12_INFO_QUEUE_FILTER filter = {0}; - filter.AllowList.NumSeverities = 3; - filter.AllowList.pSeverityList = severities; + filter.AllowList.NumSeverities = s_D3D.severityCount; + filter.AllowList.pSeverityList = s_D3D.severities; + filter.AllowList.NumCategories = s_D3D.categoryCount; + filter.AllowList.pCategoryList = s_D3D.categories; filter.DenyList.NumIDs = 1; filter.DenyList.pIDList = denyIDs; @@ -5762,6 +5794,7 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( PalDescriptorSetLayout* layout, PalDescriptorSet** outSet) { + Device* d3dDevice = (Device*)device; DescriptorPool* d3dPool = (DescriptorPool*)pool; DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; DescriptorSet* set = nullptr; @@ -5795,6 +5828,13 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( } else if (binding->type == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { asCount += binding->range.NumDescriptors; } + + // check if descriptor indexing is supported and enabled + if (binding->range.NumDescriptors > 1) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } } // validate descriptor sets limits diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index ecfda63d..594099ed 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2933,13 +2933,31 @@ PalResult PAL_CALL initGraphicsVk( } palFree(s_Vk.allocator, props); - debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; - debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; - debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + // message types + if (!debugger->denyGeneral) { + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + } + + if (!debugger->denyPerformance) { + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + } - debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; - debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + if (!debugger->denyValidation) { + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + } + + // message severities + if (!debugger->denyInfoSeverity) { + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + } + + if (!debugger->denyWarningSeverity) { + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + } + + if (!debugger->denyErrorSeverity) { + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + } debugCreateInfo.pUserData = debugger->userData; debugCreateInfo.pfnUserCallback = debugCallbackVk; @@ -3414,6 +3432,9 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( } } + caps->maxVertexLayouts = props.limits.maxVertexInputBindings; + caps->maxVertexAttributes = props.limits.maxVertexInputAttributes; + caps->maxComputeWorkGroupInvocations = props.limits.maxComputeWorkGroupInvocations; caps->maxComputeWorkGroupCount[0] = props.limits.maxComputeWorkGroupCount[0]; caps->maxComputeWorkGroupCount[1] = props.limits.maxComputeWorkGroupCount[1]; From 031da8580f764cd2249efc72f73b456510ba65b6 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 19 Apr 2026 09:32:52 +0000 Subject: [PATCH 165/372] simplify API --- include/pal/pal_graphics.h | 88 ++++++++++++++++++++++++++----------- src/graphics/pal_d3d12.c | 28 +++++++----- src/graphics/pal_graphics.c | 16 +------ src/graphics/pal_vulkan.c | 21 +++------ tests/compute_test.c | 4 +- tests/ray_tracing_test.c | 5 +-- tests/texture_test.c | 10 ++--- tests/triangle_test.c | 10 ++--- 8 files changed, 99 insertions(+), 83 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 266244cb..8f49e922 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -977,6 +977,24 @@ typedef enum { PAL_VERTEX_TYPE_HALF_FLOAT16_4 /**< float16 vec4 or array[4].*/ } PalVertexType; +/** + * @enum PalVertexSemanticID + * @brief Vertex semantic id types. + * + * All vertex semantic id types follow the format `PAL_VERTEX_SEMANTIC_ID_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_VERTEX_SEMANTIC_ID_POSITION, + PAL_VERTEX_SEMANTIC_ID_COLOR, + PAL_VERTEX_SEMANTIC_ID_UV, + PAL_VERTEX_SEMANTIC_ID_NORMAL, + PAL_VERTEX_SEMANTIC_ID_TANGENT +} PalVertexSemanticID; + /** * @enum PalCommandBufferType * @brief Command buffer types. @@ -1384,22 +1402,6 @@ typedef enum { PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT } PalRayTracingShaderGroupType; -/** - * @enum PalPipelineBindPoint - * @brief Binding point for pipeline and pipeline layouts. - * - * All pipeline bind points follow the format `PAL_PIPELINE_BIND_POINT_**` - * for consistency and API use. - * - * @since 1.4 - * @ingroup pal_graphics - */ -typedef enum { - PAL_PIPELINE_BIND_POINT_GRAPHICS, - PAL_PIPELINE_BIND_POINT_COMPUTE, - PAL_PIPELINE_BIND_POINT_RAY_TRACING -} PalPipelineBindPoint; - /** * @struct PalAdapterInfo * @brief Information about an adapter (GPU). @@ -1932,14 +1934,18 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + PalVertexSemanticID semanticID; /**< (eg. PAL_VERTEX_SEMANTIC_ID_POSITION).*/ PalVertexType type; /**< (eg. PAL_VERTEX_TYPE_FLOAT).*/ - Uint32 location; } PalVertexAttribute; /** * @struct PalVertexLayout * @brief Vertex layout. - * This defines the layout and the number of vertex attributes the layout uses. + * This defines the layout, ordering and the number of vertex attributes the layout uses. + * + * This layouts should reflect the exact layout of the shaders. Eg. attributes[0] = position + * attribute and attributes[1] = color attribute is not the same as attributes[0] = color attribute + * and attributes[1] = position attribute. The ordering must be correct. * * Uninitialized fields may result in undefined behavior. * @@ -2574,6 +2580,7 @@ typedef struct { Uint32 vertexLayoutCount; Uint32 colorBlendAttachmentCount; Uint32 shaderCount; + Uint32 primitiveRestartEnable; /**< 0 to disable.*/ PalPrimitiveTopology topology; PalPipelineLayout* pipelineLayout; PalShader** shaders; @@ -3379,7 +3386,6 @@ typedef struct { PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, - Uint32* strides, PalBuffer** buffers, Uint64* offsets); @@ -3561,7 +3567,6 @@ typedef struct { PalResult PAL_CALL (*cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set); @@ -3573,7 +3578,6 @@ typedef struct { PalResult PAL_CALL (*cmdPushConstants)( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -5519,6 +5523,8 @@ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -5548,6 +5554,8 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -5577,6 +5585,8 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -5836,6 +5846,8 @@ PAL_API PalResult PAL_CALL palCmdSetScissors( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -5844,7 +5856,6 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, - Uint32* strides, PalBuffer** buffers, Uint64* offsets); @@ -5862,6 +5873,8 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -5887,6 +5900,8 @@ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -5916,6 +5931,8 @@ PAL_API PalResult PAL_CALL palCmdDraw( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -5944,6 +5961,8 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirect( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -5971,6 +5990,8 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6001,6 +6022,8 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexed( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6029,6 +6052,8 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6064,6 +6089,8 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6160,6 +6187,8 @@ PAL_API PalResult PAL_CALL palCmdBufferBarrier( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6192,6 +6221,8 @@ PAL_API PalResult PAL_CALL palCmdDispatch( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6222,6 +6253,8 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6250,6 +6283,8 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6285,6 +6320,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note The memory associated with the buffer must be `PAL_MEMORY_TYPE_CPU_UPLOAD`. + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6302,7 +6338,6 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] layout The pipeline layout that defines the descriptor interface. - * @param[in] bindPoint The Binding point. * @param[in] setIndex Index of the descriptor set to bind. * @param[in] set Descriptor set to bind. Must be compatible with `layout`. * @@ -6310,6 +6345,8 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6317,7 +6354,6 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set); @@ -6328,7 +6364,6 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] layout The pipeline layout that defines the push constant range. - * @param[in] bindPoint The Binding point. * @param[in] shaderStageCount Capacity of the PalShaderStage array. * @param[in] shaderStages Array of shader stages that can access the push constant. * @param[in] offset Offset in bytes into the push constant range. @@ -6339,6 +6374,8 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. + * + * @note A pipeline must be bound before this call. * * @since 1.4 * @ingroup pal_graphics @@ -6346,7 +6383,6 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PAL_API PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index f955718a..bd77ae24 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -224,6 +224,8 @@ typedef struct { const PalGraphicsBackend* backend; bool primary; + Uint32 pipelineType; + Uint32* strides; void* pool; // CommandPool Device* device; ID3D12Resource* tmpBuffer; @@ -266,6 +268,7 @@ typedef struct { Uint32 type; D3D_PRIMITIVE_TOPOLOGY topology; + Uint32* strides; void* handle; } Pipeline; @@ -3871,6 +3874,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdBuffer->handle); cmdList->lpVtbl->Release(cmdList); + cmdBuffer->strides = nullptr; cmdBuffer->pool = cmdPool; cmdBuffer->device = d3dDevice; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; @@ -3910,6 +3914,7 @@ PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) d3dCmdBuffer->allocator, nullptr); + d3dCmdBuffer->strides = nullptr; return PAL_RESULT_SUCCESS; } @@ -4480,6 +4485,8 @@ PalResult PAL_CALL cmdBindPipelineD3D12( } } + d3dCmdBuffer->pipelineType = d3dPipeline->type; + d3dCmdBuffer->strides = d3dPipeline->strides; return PAL_RESULT_SUCCESS; } @@ -4557,7 +4564,6 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, - Uint32* strides, PalBuffer** buffers, Uint64* offsets) { @@ -4565,6 +4571,10 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( D3D12_VERTEX_BUFFER_VIEW cachedView = {0}; D3D12_VERTEX_BUFFER_VIEW* views = nullptr; + if (!d3dCmdBuffer->strides) { + return PAL_RESULT_INVALID_OPERATION; + } + if (count > 1) { views = palAllocate(s_D3D.allocator, sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, 0); if (!views) { @@ -4580,7 +4590,7 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( views[i].BufferLocation = tmp->handle->lpVtbl->GetGPUVirtualAddress(tmp->handle); views[i].BufferLocation = views[i].BufferLocation + offsets[i]; views[i].SizeInBytes = tmp->size; - views[i].StrideInBytes = strides[i]; + views[i].StrideInBytes = d3dCmdBuffer->strides[i]; } d3dCmdBuffer->handle->lpVtbl->IASetVertexBuffers( @@ -5065,7 +5075,6 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set) { @@ -5095,13 +5104,13 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( pool->resourceHeap.incrementSize, pool->resourceHeap.gpuBase); - if (bindPoint == PAL_PIPELINE_BIND_POINT_GRAPHICS) { + if (d3dCmdBuffer->pipelineType == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( d3dCmdBuffer->handle, pipelineLayout->resourceIndex, base); - } else if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { + } else if (d3dCmdBuffer->pipelineType == COMPUTE_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( d3dCmdBuffer->handle, pipelineLayout->resourceIndex, @@ -5120,13 +5129,13 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( pool->samplerHeap.incrementSize, pool->samplerHeap.gpuBase); - if (bindPoint == PAL_PIPELINE_BIND_POINT_GRAPHICS) { + if (d3dCmdBuffer->pipelineType == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( d3dCmdBuffer->handle, pipelineLayout->samplerIndex, base); - } else if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { + } else if (d3dCmdBuffer->pipelineType == COMPUTE_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( d3dCmdBuffer->handle, pipelineLayout->samplerIndex, @@ -5143,7 +5152,6 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalResult PAL_CALL cmdPushConstantsD3D12( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -5153,7 +5161,7 @@ PalResult PAL_CALL cmdPushConstantsD3D12( CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; PipelineLayout* pipelineLayout = (PipelineLayout*)layout; if (pipelineLayout->constantIndex != UINT32_MAX) { - if (bindPoint == PAL_PIPELINE_BIND_POINT_GRAPHICS) { + if (d3dCmdBuffer->pipelineType == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRoot32BitConstants( d3dCmdBuffer->handle, pipelineLayout->constantIndex, @@ -5161,7 +5169,7 @@ PalResult PAL_CALL cmdPushConstantsD3D12( value, offset / 4); - } else if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { + } else if (d3dCmdBuffer->pipelineType == COMPUTE_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetComputeRoot32BitConstants( d3dCmdBuffer->handle, pipelineLayout->constantIndex, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 022e1b60..6917da7c 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -487,7 +487,6 @@ PalResult PAL_CALL cmdBindVertexBuffersVk( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, - Uint32* strides, PalBuffer** buffers, Uint64* offsets); @@ -589,14 +588,12 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set); PalResult PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -1349,7 +1346,6 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, - Uint32* strides, PalBuffer** buffers, Uint64* offsets); @@ -1451,14 +1447,12 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set); PalResult PAL_CALL cmdPushConstantsD3D12( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -3427,7 +3421,6 @@ PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, - Uint32* strides, PalBuffer** buffers, Uint64* offsets) { @@ -3435,7 +3428,7 @@ PalResult PAL_CALL palCmdBindVertexBuffers( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !buffers || !strides || !offsets) { + if (!cmdBuffer || !buffers || !offsets) { return PAL_RESULT_NULL_POINTER; } @@ -3443,7 +3436,6 @@ PalResult PAL_CALL palCmdBindVertexBuffers( cmdBuffer, firstSlot, count, - strides, buffers, offsets); } @@ -3743,7 +3735,6 @@ PalResult PAL_CALL palCmdTraceRaysIndirect( PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set) { @@ -3757,8 +3748,7 @@ PalResult PAL_CALL palCmdBindDescriptorSet( return cmdBuffer->backend->cmdBindDescriptorSet( cmdBuffer, - layout, - bindPoint, + layout, setIndex, set); } @@ -3766,7 +3756,6 @@ PalResult PAL_CALL palCmdBindDescriptorSet( PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -3785,7 +3774,6 @@ PalResult PAL_CALL palCmdPushConstants( return cmdBuffer->backend->cmdPushConstants( cmdBuffer, layout, - bindPoint, shaderStageCount, shaderStages, offset, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 594099ed..9f127896 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -504,6 +504,7 @@ typedef struct { const PalGraphicsBackend* backend; bool primary; + VkPipelineBindPoint bindPoint; Device* device; CommandPool* pool; VkCommandBuffer handle; @@ -6976,6 +6977,8 @@ PalResult PAL_CALL cmdBindPipelineVk( CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* vkPipeline = (Pipeline*)pipeline; s_Vk.cmdBindPipeline(vkCmdBuffer->handle, vkPipeline->bindPoint, vkPipeline->handle); + + vkCmdBuffer->bindPoint = vkPipeline->bindPoint; return PAL_RESULT_SUCCESS; } @@ -7053,7 +7056,6 @@ PalResult PAL_CALL cmdBindVertexBuffersVk( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, - Uint32* strides, PalBuffer** buffers, Uint64* offsets) { @@ -7474,7 +7476,6 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 setIndex, PalDescriptorSet* set) { @@ -7482,17 +7483,9 @@ PalResult PAL_CALL cmdBindDescriptorSetVk( PipelineLayout* vkLayout = (PipelineLayout*)layout; DescriptorSet* vkSet = (DescriptorSet*)set; - VkPipelineBindPoint point = VK_PIPELINE_BIND_POINT_GRAPHICS; - if (bindPoint == PAL_PIPELINE_BIND_POINT_COMPUTE) { - point = VK_PIPELINE_BIND_POINT_COMPUTE; - - } else if (bindPoint == PAL_PIPELINE_BIND_POINT_RAY_TRACING) { - point = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; - } - s_Vk.cmdBindDescriptorSets( vkCmdBuffer->handle, - point, + vkCmdBuffer->bindPoint, vkLayout->handle, setIndex, 1, @@ -7506,7 +7499,6 @@ PalResult PAL_CALL cmdBindDescriptorSetVk( PalResult PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, PalPipelineLayout* layout, - PalPipelineBindPoint bindPoint, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint64 offset, @@ -8556,6 +8548,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( return PAL_RESULT_OUT_OF_MEMORY; } + Uint32 location = 0; for (int i = 0; i < info->vertexLayoutCount; i++) { PalVertexLayout* layout = &info->vertexLayouts[i]; VkVertexInputBindingDescription* bindingDesc = &bindingDescs[i]; @@ -8576,7 +8569,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( attribDesc->format = vertexTypeToVk(vertexAttrib->type); attribDesc->binding = bindingDesc->binding; - attribDesc->location = vertexAttrib->location; + attribDesc->location = location++; // build offsets and stride Uint32 size = getVertexTypeSizeVk(vertexAttrib->type); @@ -8622,6 +8615,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( } } inputAssemblyState.topology = topology; + inputAssemblyState.primitiveRestartEnable = info->primitiveRestartEnable; createInfo.pInputAssemblyState = &inputAssemblyState; // Dynamic states @@ -8851,7 +8845,6 @@ PalResult PAL_CALL createGraphicsPipelineVk( } else { dynRendering.viewMask = (1 << renderingLayout->viewCount) - 1; } - createInfo.pNext = &dynRendering; } diff --git a/tests/compute_test.c b/tests/compute_test.c index d7b57e98..0d8d0779 100644 --- a/tests/compute_test.c +++ b/tests/compute_test.c @@ -451,11 +451,9 @@ bool computeTest() return false; } - PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_COMPUTE; result = palCmdPushConstants( cmdBuffer, pipelineLayout, - bindPoint, 1, shaderStages, 0, @@ -468,7 +466,7 @@ bool computeTest() return false; } - result = palCmdBindDescriptorSet(cmdBuffer, pipelineLayout, bindPoint, 0, descriptorSet); + result = palCmdBindDescriptorSet(cmdBuffer, pipelineLayout, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); diff --git a/tests/ray_tracing_test.c b/tests/ray_tracing_test.c index b4f89f2a..fef02e15 100644 --- a/tests/ray_tracing_test.c +++ b/tests/ray_tracing_test.c @@ -903,9 +903,8 @@ bool rayTracingTest() palLog(nullptr, "Failed to bind pipeline: %s", error); return false; } - - PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_RAY_TRACING; - result = palCmdBindDescriptorSet(cmdBuffer, pipelineLayout, bindPoint, 0, descriptorSet); + + result = palCmdBindDescriptorSet(cmdBuffer, pipelineLayout, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); diff --git a/tests/texture_test.c b/tests/texture_test.c index 0ec88730..3375f875 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -1038,11 +1038,11 @@ bool textureTest() PalVertexAttribute vertexAttributes[2]; // position - vertexAttributes[0].location = 0; + vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; // texture coordinates - vertexAttributes[1].location = 1; + vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_UV; vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT2; vertexLayout.attributeCount = 2; @@ -1261,11 +1261,9 @@ bool textureTest() return false; } - PalPipelineBindPoint bindPoint = PAL_PIPELINE_BIND_POINT_GRAPHICS; result = palCmdBindDescriptorSet( cmdBuffers[currentFrame], - pipelineLayout, - bindPoint, + pipelineLayout, 0, descriptorSet); @@ -1291,13 +1289,11 @@ bool textureTest() } // bind vertex buffer - Uint32 strides[] = { 16 }; Uint64 offset[] = {0}; result = palCmdBindVertexBuffers( cmdBuffers[currentFrame], 0, 1, - strides, &vertexBuffer, offset); diff --git a/tests/triangle_test.c b/tests/triangle_test.c index 69d9ea15..f17c54d1 100644 --- a/tests/triangle_test.c +++ b/tests/triangle_test.c @@ -644,11 +644,11 @@ bool triangleTest() PalVertexAttribute vertexAttributes[2]; // position - vertexAttributes[0].location = 0; + vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; // color - vertexAttributes[1].location = 1; + vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_COLOR; vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT3; vertexLayout.attributeCount = 2; @@ -879,14 +879,12 @@ bool triangleTest() } // bind vertex buffer - Uint32 strides[] = { 20 }; Uint64 offset[] = {0}; result = palCmdBindVertexBuffers( cmdBuffers[currentFrame], 0, - 1, - strides, - &vertexBuffer, + 1, + &vertexBuffer, offset); if (result != PAL_RESULT_SUCCESS) { From da5543927e78946cebe04cda7936ab727d0de5da Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 19 Apr 2026 16:37:47 +0000 Subject: [PATCH 166/372] add graphics pipeline API d3d12 --- include/pal/pal_graphics.h | 16 +- src/graphics/pal_d3d12.c | 781 +++++++++++++++++++++++++++++++++++++ src/graphics/pal_vulkan.c | 62 ++- tests/texture_test.c | 2 +- 4 files changed, 823 insertions(+), 38 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 8f49e922..da8ea4a2 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -990,7 +990,7 @@ typedef enum { typedef enum { PAL_VERTEX_SEMANTIC_ID_POSITION, PAL_VERTEX_SEMANTIC_ID_COLOR, - PAL_VERTEX_SEMANTIC_ID_UV, + PAL_VERTEX_SEMANTIC_ID_TEXCOORD, PAL_VERTEX_SEMANTIC_ID_NORMAL, PAL_VERTEX_SEMANTIC_ID_TANGENT } PalVertexSemanticID; @@ -1451,6 +1451,7 @@ typedef struct { Uint32 maxPushConstantSize; Uint32 maxVertexLayouts; Uint32 maxVertexAttributes; + Uint32 maxTessellationPatchPoint; Uint32 maxComputeWorkGroupInvocations; /**< Max compute threads per workgroup across all axis.*/ Uint32 maxComputeWorkGroupCount[3]; /**< Max compute workgroups per axis.*/ Uint32 maxComputeWorkGroupSize[3]; /**< Max compute threads per workgroup per axis.*/ @@ -1840,8 +1841,7 @@ typedef struct { Uint32 viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ Uint32 colorAttachentCount; PalSampleCount multisampleCount; - PalFormat depthAttachmentFormat; - PalFormat stencilAttachmentFormat; + PalFormat depthStencilAttachmentFormat; PalFormat fragmentShadingRateAttachmentFormat; PalFormat* colorAttachmentsFormat; } PalRenderingLayoutInfo; @@ -1936,6 +1936,10 @@ typedef struct { typedef struct { PalVertexSemanticID semanticID; /**< (eg. PAL_VERTEX_SEMANTIC_ID_POSITION).*/ PalVertexType type; /**< (eg. PAL_VERTEX_TYPE_FLOAT).*/ + + /** Must not include the index (eg. "position" or "myown"). Set to nullptr to use the default + * that will be derived from `semanticID`.*/ + const char* semanticName; } PalVertexAttribute; /** @@ -1991,6 +1995,9 @@ typedef struct { typedef struct { bool enableDepthClamp; bool enableDepthBias; + float depthBiasConstant; + float depthBiasSlope; + float depthBiasClamp; PalPolygonMode polygonMode; /**< (eg. PAL_POLYGON_MODE_FILL).*/ PalCullMode cullMode; /**< (eg. PAL_CULL_MODE_BACK).*/ PalFrontFace frontFace; /**< (eg. PAL_FRONT_FACE_CLOCKWISE).*/ @@ -2577,10 +2584,11 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + bool primitiveRestartEnable; /**< False to disable.*/ Uint32 vertexLayoutCount; Uint32 colorBlendAttachmentCount; Uint32 shaderCount; - Uint32 primitiveRestartEnable; /**< 0 to disable.*/ + PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is true.*/ PalPrimitiveTopology topology; PalPipelineLayout* pipelineLayout; PalShader** shaders; diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index bd77ae24..bb935f08 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -72,6 +72,7 @@ const IID IID_Signature = {0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47 const IID IID_DescHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51}; const IID IID_RootSig = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14}; const IID IID_Device5 = {0x8b4f173b, 0x2fea, 0x4b80, 0x8f,0x58, 0x43,0x07,0x19,0x1a,0xb9,0x5d}; +const IID IID_Pipeline = {0x765a30f3, 0xf624, 0x4c6f, 0xa8,0x28, 0xac,0xe9,0x48,0x62,0x24,0x45}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -216,6 +217,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + Uint32 patchControlPoints; PalShaderStage stage; D3D12_SHADER_BYTECODE byteCode; } Shader; @@ -266,10 +268,13 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + bool hasFsr; Uint32 type; + D3D12_SHADING_RATE shadingRate; D3D_PRIMITIVE_TOPOLOGY topology; Uint32* strides; void* handle; + D3D12_SHADING_RATE_COMBINER combinerOps[2]; } Pipeline; typedef struct { @@ -353,6 +358,86 @@ typedef struct { D3D12_ROOT_PARAMETER1 params[3]; } PipelineLayout; +typedef struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + ID3D12RootSignature* root; +} RootSignatureStream; + +typedef struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_INPUT_LAYOUT_DESC desc; +} InputLayoutStream; + +typedef struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE ibType; + D3D12_PRIMITIVE_TOPOLOGY_TYPE topology; + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue; +} InputAssemblyStream; + +typedef struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_RASTERIZER_DESC desc; +} RasterizerStream; + +typedef struct { + UINT sampleMask; + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE maskType; + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + DXGI_SAMPLE_DESC desc; +} MultisampleStream; + +typedef struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_DEPTH_STENCIL_DESC desc; +} DepthStencilStream; + +typedef struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_BLEND_DESC desc; +} ColorBlendStream; + +typedef struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE dsvType; + UINT NumRenderTargets; + DXGI_FORMAT DSVFormat; + DXGI_FORMAT RTVFormats[8]; +} RenderingLayoutStream; + +typedef struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_PIPELINE_STATE_FLAGS flags; +} PipelineFlagsStream; + +typedef struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_SHADER_BYTECODE desc; +} ShaderStream; + +typedef struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_VIEW_INSTANCING_DESC desc; +} ViewInstancingStream; + +typedef struct { + RootSignatureStream layout; + InputLayoutStream inputLayout; + InputAssemblyStream inputAssembly; + RasterizerStream rasterizer; + MultisampleStream multisample; + DepthStencilStream depthStencil; + ColorBlendStream colorBlend; + RenderingLayoutStream renderingLayout; + ViewInstancingStream viewInstancing; + PipelineFlagsStream flags; +} FixedPipelineHeader; + +typedef struct { + FixedPipelineHeader header; + ShaderStream shaders[7]; // 7 shader types for graphics pipeline +} GraphicsPipelineeStreamDesc; + static D3D12 s_D3D = {0}; // ================================================== @@ -681,6 +766,104 @@ static D3D12_COMPARISON_FUNC compareOpToD3D12(PalCompareOp op) return D3D12_COMPARISON_FUNC_NEVER; } + +static D3D12_STENCIL_OP stencilOpToD3D12(PalStencilOp op) +{ + switch (op) { + case PAL_STENCIL_OP_KEEP: + return D3D12_STENCIL_OP_KEEP; + + case PAL_STENCIL_OP_ZERO: + return D3D12_STENCIL_OP_ZERO; + + case PAL_STENCIL_OP_REPLACE: + return D3D12_STENCIL_OP_REPLACE; + + case PAL_STENCIL_OP_INCREMENT_AND_CLAMP: + return D3D12_STENCIL_OP_INCR_SAT; + + case PAL_STENCIL_OP_DECREMENT_AND_CLAMP: + return D3D12_STENCIL_OP_DECR_SAT; + + case PAL_STENCIL_OP_INVERT: + return D3D12_STENCIL_OP_INVERT; + + case PAL_STENCIL_OP_INCREMENT_AND_WRAP: + return D3D12_STENCIL_OP_INCR; + + case PAL_STENCIL_OP_DECREMENT_AND_WRAP: + return D3D12_STENCIL_OP_DECR; + } + + return D3D12_STENCIL_OP_KEEP; +} + +static D3D12_BLEND_OP blendOpToD3D12(PalBlendOp op) +{ + switch (op) { + case PAL_BLEND_OP_ADD: + return D3D12_BLEND_OP_ADD; + + case PAL_BLEND_OP_SUBTRACT: + return D3D12_BLEND_OP_SUBTRACT; + + case PAL_BLEND_OP_REVERSE_SUBTRACT: + return D3D12_BLEND_OP_REV_SUBTRACT; + + case PAL_BLEND_OP_MIN: + return D3D12_BLEND_OP_MIN; + + case PAL_BLEND_OP_MAX: + return D3D12_BLEND_OP_MAX; + } + + return D3D12_BLEND_OP_ADD; +} + +static D3D12_BLEND blendFactorToD3D12(PalBlendFactor op) +{ + switch (op) { + case PAL_BLEND_FACTOR_ZERO: + return D3D12_BLEND_ZERO; + + case PAL_BLEND_FACTOR_ONE: + return D3D12_BLEND_ONE; + + case PAL_BLEND_FACTOR_SRC_COLOR: + return D3D12_BLEND_SRC_COLOR; + + case PAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: + return D3D12_BLEND_INV_SRC_COLOR; + + case PAL_BLEND_FACTOR_DST_COLOR: + return D3D12_BLEND_DEST_COLOR; + + case PAL_BLEND_FACTOR_ONE_MINUX_DST_COLOR: + return D3D12_BLEND_INV_DEST_COLOR; + + case PAL_BLEND_FACTOR_SRC_ALPHA: + return D3D12_BLEND_SRC_ALPHA; + + case PAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: + return D3D12_BLEND_INV_SRC_ALPHA; + + case PAL_BLEND_FACTOR_DST_ALPHA: + return D3D12_BLEND_DEST_ALPHA; + + case PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: + return D3D12_BLEND_INV_DEST_ALPHA; + + case PAL_BLEND_FACTOR_CONSTANT_COLOR: + case PAL_BLEND_FACTOR_CONSTANT_ALPHA: + return D3D12_BLEND_BLEND_FACTOR; + + case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR: + case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: + return D3D12_BLEND_INV_BLEND_FACTOR; + } + + return D3D12_BLEND_ZERO; +} static D3D12_FILTER filterToD3D12( PalFilterMode minFilter, @@ -1439,6 +1622,156 @@ static D3D12_RAYTRACING_INSTANCE_FLAGS instanceFlagsToD3D12( return instanceFlags; } +static D3D_PRIMITIVE_TOPOLOGY getPatchTopology(Uint32 patch) +{ + switch (patch) { + case 1: + return D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST; + + case 2: + return D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST; + + case 3: + return D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST; + + case 4: + return D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST; + + case 5: + return D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST; + + case 6: + return D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST; + + case 7: + return D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST; + + case 8: + return D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST; + + case 9: + return D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST; + + case 10: + return D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST; + + case 11: + return D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST; + + case 12: + return D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST; + + case 13: + return D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST; + + case 14: + return D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST; + + case 15: + return D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST; + + case 16: + return D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST; + + case 17: + return D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST; + + case 18: + return D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST; + + case 19: + return D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST; + + case 20: + return D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST; + + case 21: + return D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST; + + case 22: + return D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST; + + case 23: + return D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST; + + case 24: + return D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST; + + case 25: + return D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST; + + case 26: + return D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST; + + case 27: + return D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST; + + case 28: + return D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST; + + case 29: + return D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST; + + case 30: + return D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST; + } + + return D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST; +} + +static Uint32 getVertexTypeSizeD3D12(PalVertexType type) +{ + // count x sizeof type returned as size + switch (type) { + case PAL_VERTEX_TYPE_INT8_2: + case PAL_VERTEX_TYPE_UINT8_2: + case PAL_VERTEX_TYPE_INT8_2NORM: + case PAL_VERTEX_TYPE_UINT8_2NORM: { + return 2; + } + + case PAL_VERTEX_TYPE_INT32: + case PAL_VERTEX_TYPE_UINT32: + case PAL_VERTEX_TYPE_INT8_4: + case PAL_VERTEX_TYPE_INT8_4NORM: + case PAL_VERTEX_TYPE_UINT8_4: + case PAL_VERTEX_TYPE_UINT8_4NORM: + case PAL_VERTEX_TYPE_INT16_2NORM: + case PAL_VERTEX_TYPE_INT16_2: + case PAL_VERTEX_TYPE_UINT16_2: + case PAL_VERTEX_TYPE_UINT16_2NORM: + case PAL_VERTEX_TYPE_FLOAT: + case PAL_VERTEX_TYPE_HALF_FLOAT16_2: { + return 4; + } + + case PAL_VERTEX_TYPE_INT32_2: + case PAL_VERTEX_TYPE_UINT32_2: + case PAL_VERTEX_TYPE_INT16_4: + case PAL_VERTEX_TYPE_UINT16_4: + case PAL_VERTEX_TYPE_UINT16_4NORM: + case PAL_VERTEX_TYPE_INT16_4NORM: + case PAL_VERTEX_TYPE_FLOAT2: + case PAL_VERTEX_TYPE_HALF_FLOAT16_4: { + return 8; + } + + case PAL_VERTEX_TYPE_INT32_3: + case PAL_VERTEX_TYPE_UINT32_3: + case PAL_VERTEX_TYPE_FLOAT3: { + return 12; + } + + case PAL_VERTEX_TYPE_INT32_4: + case PAL_VERTEX_TYPE_UINT32_4: + case PAL_VERTEX_TYPE_FLOAT4: { + return 16; + } + } + + return 0; +} + // ================================================== // Adapter // ================================================== @@ -1753,6 +2086,7 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( caps->maxPushConstantSize = (D3D12_MAX_ROOT_COST - 2) * 4; caps->maxVertexLayouts = PAL_LIMIT_UNKNOWN; caps->maxVertexAttributes = PAL_LIMIT_UNKNOWN; + caps->maxTessellationPatchPoint = 32; caps->maxComputeWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; caps->maxComputeWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; @@ -3478,6 +3812,7 @@ PalResult PAL_CALL createShaderD3D12( shader->byteCode.pShaderBytecode = info->bytecode; shader->byteCode.BytecodeLength = info->bytecodeSize; shader->stage = info->stage; + shader->patchControlPoints = info->patchControlPoints; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } @@ -4482,6 +4817,13 @@ PalResult PAL_CALL cmdBindPipelineD3D12( d3dCmdBuffer->handle->lpVtbl->IASetPrimitiveTopology( d3dCmdBuffer->handle, d3dPipeline->topology); + + if (d3dPipeline->hasFsr) { + d3dCmdBuffer->handle->lpVtbl->RSSetShadingRate( + d3dCmdBuffer->handle, + d3dPipeline->shadingRate, + d3dPipeline->combinerOps); + } } } @@ -6182,7 +6524,435 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline) { + HRESULT result; + Uint32 patchControlPoints = 0; + Uint32 totalSize = 0; + bool alphaToCoverageEnable = false; + Pipeline* pipeline = nullptr; + Device* d3dDevice = (Device*)device; + PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; + + GraphicsPipelineeStreamDesc desc = {0}; + memset(&desc, 0, sizeof(GraphicsPipelineeStreamDesc)); + + desc.header.layout.root = layout->handle; + desc.header.layout.type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE; + + ShaderStream shaderStreams[7]; // 7 shader types for graphics pipeline + D3D12_INPUT_ELEMENT_DESC* elementDescs = nullptr; + D3D12_VIEW_INSTANCE_LOCATION* viewLocations = nullptr; + D3D12_VIEW_INSTANCE_LOCATION cachedViewLocation = {0}; + + InputLayoutStream* inputLayoutDesc = &desc.header.inputLayout; + InputAssemblyStream* inputAssemblyDesc = &desc.header.inputAssembly; + RasterizerStream* rasterizerDesc = &desc.header.rasterizer; + MultisampleStream* multisampleDesc = &desc.header.multisample; + DepthStencilStream* depthStencilDesc = &desc.header.depthStencil; + ColorBlendStream* colorBlendDesc = &desc.header.colorBlend; + RenderingLayoutStream* renderingLayoutDesc = &desc.header.renderingLayout; + PipelineFlagsStream* flagsDesc = &desc.header.flags; + ViewInstancingStream* viewInstancingDesc = &desc.header.viewInstancing; + + pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); + if (!pipeline) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + if (info->renderingLayout->viewCount > 1) { + viewLocations = palAllocate( + s_D3D.allocator, + sizeof(D3D12_VIEW_INSTANCE_LOCATION) * info->renderingLayout->viewCount, + 0); + + if (!viewLocations) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + } else { + viewLocations = &cachedViewLocation; + } + + totalSize = sizeof(FixedPipelineHeader) + (sizeof(ShaderStream) * info->shaderCount); + // shaders + for (int i = 0; i < info->shaderCount; i++) { + Shader* tmp = (Shader*)info->shaders[i]; + if (tmp->patchControlPoints) { + patchControlPoints = tmp->patchControlPoints; + if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { + palFree(s_D3D.allocator, pipeline); + return PAL_RESULT_INVALID_OPERATION; + } + } + + if (tmp->stage == PAL_SHADER_STAGE_VERTEX) { + shaderStreams[i].desc = tmp->byteCode; + shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS; + + } else if (tmp->stage == PAL_SHADER_STAGE_FRAGMENT) { + shaderStreams[i].desc = tmp->byteCode; + shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS; + + } else if (tmp->stage == PAL_SHADER_STAGE_GEOMETRY) { + shaderStreams[i].desc = tmp->byteCode; + shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS; + + } else if (tmp->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { + shaderStreams[i].desc = tmp->byteCode; + shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS; + + } else if (tmp->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + shaderStreams[i].desc = tmp->byteCode; + shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS; + + } else if (tmp->stage == PAL_SHADER_STAGE_TASK) { + shaderStreams[i].desc = tmp->byteCode; + shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS; + + } else { + // mesh shader + shaderStreams[i].desc = tmp->byteCode; + shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS; + } + } + + // Vertex input state + // get the max size of vertex attributes in all layouts + Uint32 vertexCount = 0; + Uint32 vertexLayoutCount = info->vertexLayoutCount; + for (int i = 0; i < vertexLayoutCount; i++) { + PalVertexLayout* layout = &info->vertexLayouts[i]; + vertexCount += layout->attributeCount; + } + + inputLayoutDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT; + pipeline->strides = nullptr; + if (vertexCount) { + pipeline->strides = palAllocate(s_D3D.allocator, sizeof(Uint32) * vertexLayoutCount, 0); + if (!pipeline->strides) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + elementDescs = palAllocate( + s_D3D.allocator, + sizeof(D3D12_INPUT_ELEMENT_DESC) * vertexCount, + 0); + + if (!elementDescs) { + palFree(s_D3D.allocator, elementDescs); + return PAL_RESULT_OUT_OF_MEMORY; + } + + Uint32 positionIndex = 0; + Uint32 colorIndex = 0; + Uint32 texCoordIndex = 0; + Uint32 normalIndex = 0; + Uint32 tangentIndex = 0; + + for (int i = 0; i < info->vertexLayoutCount; i++) { + PalVertexLayout* layout = &info->vertexLayouts[i]; + Uint32 stride = 0; + Uint32 offset = 0; + + for (int j = 0; j < layout->attributeCount; j++) { + PalVertexAttribute* vertexAttrib = &layout->attributes[j]; + D3D12_INPUT_ELEMENT_DESC* elementDesc = &elementDescs[j]; + + elementDesc->Format = vertexTypeToD3D12(vertexAttrib->type); + elementDesc->InputSlot = layout->binding; + if (vertexAttrib->semanticName) { + elementDesc->SemanticName = vertexAttrib->semanticName; + } + + if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_POSITION) { + elementDesc->SemanticIndex = positionIndex++; + + } else if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_COLOR) { + elementDesc->SemanticIndex = colorIndex++; + + } else if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_TEXCOORD) { + elementDesc->SemanticIndex = texCoordIndex++; + + } else if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_NORMAL) { + elementDesc->SemanticIndex = normalIndex++; + + } else { + // tangent + elementDesc->SemanticIndex = tangentIndex++; + } + + if (layout->type == PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE) { + elementDesc->InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA; + elementDesc->InstanceDataStepRate = 1; + } else { + elementDesc->InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; + elementDesc->InstanceDataStepRate = 0; + } + + // build offsets and stride + Uint32 size = getVertexTypeSizeD3D12(vertexAttrib->type); + elementDesc->AlignedByteOffset = offset; + offset += size; + stride += size; + } + + // cache the computed stride to be used later by the vertex buffer + pipeline->strides[i] = stride; + } + + inputLayoutDesc->desc.NumElements = vertexCount; + inputLayoutDesc->desc.pInputElementDescs = elementDescs; + } + + // Input assembly + D3D12_PRIMITIVE_TOPOLOGY_TYPE topologyType = 0; + D3D_PRIMITIVE_TOPOLOGY topology = 0; + switch (info->topology) { + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_LIST: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_POINT_LIST: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; + topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_PATCH: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH; + topology = getPatchTopology(patchControlPoints); + break; + } + } + + inputAssemblyDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY; + inputAssemblyDesc->ibType = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE; + inputAssemblyDesc->topology = topologyType; + if (info->primitiveRestartEnable == false) { + inputAssemblyDesc->IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + + } else { + if (info->indexType == PAL_INDEX_TYPE_UINT16) { + inputAssemblyDesc->IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; + } else { + inputAssemblyDesc->IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF; + } + } + + // Rasterizer + rasterizerDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER; + rasterizerDesc->desc.FrontCounterClockwise = TRUE; + if (info->rasterizerState) { + PalRasterizerState* state = info->rasterizerState; + if (state->cullMode == PAL_CULL_MODE_NONE) { + rasterizerDesc->desc.CullMode = D3D12_CULL_MODE_NONE; + + } else if (state->cullMode == PAL_CULL_MODE_BACK) { + rasterizerDesc->desc.CullMode = D3D12_CULL_MODE_BACK; + + } else if (state->cullMode == PAL_CULL_MODE_FRONT) { + rasterizerDesc->desc.CullMode = D3D12_CULL_MODE_FRONT; + } + + if (state->polygonMode == PAL_POLYGON_MODE_FILL) { + rasterizerDesc->desc.FillMode = D3D12_FILL_MODE_SOLID; + + } else { + rasterizerDesc->desc.FillMode = D3D12_FILL_MODE_WIREFRAME; + } + + if (state->frontFace == PAL_FRONT_FACE_CLOCKWISE) { + rasterizerDesc->desc.FrontCounterClockwise = FALSE; + + } else { + rasterizerDesc->desc.FrontCounterClockwise = TRUE; + } + + rasterizerDesc->desc.DepthClipEnable = !state->enableDepthClamp; + rasterizerDesc->desc.DepthBias = (INT)state->depthBiasConstant; + rasterizerDesc->desc.SlopeScaledDepthBias = state->depthBiasSlope; + rasterizerDesc->desc.DepthBiasClamp = state->depthBiasClamp; + } + + // Multisample + multisampleDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC; + multisampleDesc->maskType = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK; + multisampleDesc->desc.Quality = 0; + multisampleDesc->desc.Count = 1; + if (info->multisampleState) { + PalMultisampleState* state = info->multisampleState; + if (state->sampleMask) { + multisampleDesc->sampleMask = (UINT)state->sampleMask; + } else { + multisampleDesc->sampleMask = UINT32_MAX; + } + + multisampleDesc->desc.Count = samplesToD3D12(state->sampleCount); + alphaToCoverageEnable = state->enableAlphaToCoverage; + } + + // Depth stencil + depthStencilDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL; + if (info->depthStencilState) { + PalDepthStencilState* state = info->depthStencilState; + PalStencilOpState* back = &state->backStencilOpState; + PalStencilOpState* front = &state->frontStencilOpState; + + D3D12_DEPTH_STENCILOP_DESC* d3dBack = &depthStencilDesc->desc.BackFace; + D3D12_DEPTH_STENCILOP_DESC* d3dFront = &depthStencilDesc->desc.FrontFace; + + d3dBack->StencilFunc = compareOpToD3D12(back->compareOp); + d3dBack->StencilDepthFailOp = stencilOpToD3D12(back->depthFailOp); + d3dBack->StencilFailOp = stencilOpToD3D12(back->failOp); + d3dBack->StencilPassOp = stencilOpToD3D12(back->passOp); + + d3dFront->StencilFunc = compareOpToD3D12(front->compareOp); + d3dFront->StencilDepthFailOp = stencilOpToD3D12(front->depthFailOp); + d3dFront->StencilFailOp = stencilOpToD3D12(front->failOp); + d3dFront->StencilPassOp = stencilOpToD3D12(front->passOp); + + depthStencilDesc->desc.DepthFunc = compareOpToD3D12(state->compareOp); + depthStencilDesc->desc.DepthEnable = state->enableDepthTest; + depthStencilDesc->desc.StencilEnable = state->enableStencilTest; + if (state->enableDepthWrite) { + depthStencilDesc->desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + } else { + depthStencilDesc->desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + } + } + + // Color blend + colorBlendDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND; + colorBlendDesc->desc.IndependentBlendEnable = TRUE; + colorBlendDesc->desc.AlphaToCoverageEnable = alphaToCoverageEnable; + if (info->colorBlendAttachmentCount) { + for (int i = 0; i < info->colorBlendAttachmentCount; i++) { + D3D12_RENDER_TARGET_BLEND_DESC* tmp = colorBlendDesc[i].desc.RenderTarget; + PalColorBlendAttachment* desc = &info->colorBlendAttachments[i]; + + tmp->BlendEnable = desc->enableBlend; + tmp->BlendOpAlpha = blendOpToD3D12(desc->alphaBlendOp); + tmp->BlendOp = blendOpToD3D12(desc->colorBlendOp); + + tmp->SrcBlendAlpha = blendFactorToD3D12(desc->srcAlphaBlendFactor); + tmp->SrcBlend = blendFactorToD3D12(desc->srcColorBlendFactor); + + tmp->DestBlendAlpha = blendFactorToD3D12(desc->dstAlphaBlendFactor); + tmp->DestBlend = blendFactorToD3D12(desc->dstColorBlendFactor); + + // blend color write mask + tmp->RenderTargetWriteMask = 0; + if (desc->colorWriteMask & PAL_COLOR_MASK_RED) { + tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_GREEN) { + tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_GREEN; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_BLUE) { + tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_BLUE; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_ALPHA) { + tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA; + } + } + } + + // Fragment shading rate + pipeline->hasFsr = false; + if (info->fragmentShadingRateState) { + PalFragmentShadingRateState* state = info->fragmentShadingRateState; + pipeline->shadingRate = shadingRateToD3D12(state->rate); + for (int i = 0; i < 2; i++) { + pipeline->combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); + } + } + + // Rendering Layout + renderingLayoutDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS; + renderingLayoutDesc->dsvType = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT; + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; + + // color attachments + renderingLayoutDesc->NumRenderTargets = renderingLayout->colorAttachentCount; + for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { + format = formatToD3D12(renderingLayout->colorAttachmentsFormat[i]); + renderingLayoutDesc->RTVFormats[i] = format; + } + + // depth stencil attachment + format = formatToD3D12(renderingLayout->depthStencilAttachmentFormat); + renderingLayoutDesc->DSVFormat = format; + // View Instancing + viewInstancingDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING; + viewInstancingDesc->desc.ViewInstanceCount = info->renderingLayout->viewCount; + viewInstancingDesc->desc.pViewInstanceLocations = viewLocations; + for (int i = 0; i < info->renderingLayout->viewCount; i++) { + viewLocations[i].RenderTargetArrayIndex = i; + viewLocations[i].RenderTargetArrayIndex = i; + } + + // Flags + flagsDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS; + flagsDesc->flags = D3D12_PIPELINE_STATE_FLAG_NONE; + if (s_D3D.debugLayer) { + flagsDesc->flags = D3D12_PIPELINE_STATE_FLAG_DEBUG; + } + + D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {0}; + streamDesc.pPipelineStateSubobjectStream = &desc; + streamDesc.SizeInBytes = totalSize; + + result = d3dDevice->handle->lpVtbl->CreatePipelineState( + d3dDevice->handle, + &streamDesc, + &IID_Pipeline, + &pipeline->handle); + + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + if (info->vertexLayoutCount) { + palFree(s_D3D.allocator, elementDescs); + } + + if (info->renderingLayout->viewCount > 1) { + palFree(s_D3D.allocator, viewLocations); + } + + pipeline->topology = topology; + pipeline->type = GRAPHICS_PIPELINE; + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL createComputePipelineD3D12( @@ -6203,7 +6973,18 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) { + Pipeline* d3dPipeline = (Pipeline*)pipeline; + if (d3dPipeline->type == RAY_TRACING_PIPELINE) { + // TODO: ray tracing pipeline + } else { + ID3D12PipelineState* handle = d3dPipeline->handle; + handle->lpVtbl->Release(handle); + } + if (d3dPipeline->strides) { + palFree(s_D3D.allocator, d3dPipeline->strides); + } + palFree(s_D3D.allocator, d3dPipeline); } // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 9f127896..d0f1e328 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3435,6 +3435,7 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( caps->maxVertexLayouts = props.limits.maxVertexInputBindings; caps->maxVertexAttributes = props.limits.maxVertexInputAttributes; + caps->maxTessellationPatchPoint = props.limits.maxTessellationPatchSize; caps->maxComputeWorkGroupInvocations = props.limits.maxComputeWorkGroupInvocations; caps->maxComputeWorkGroupCount[0] = props.limits.maxComputeWorkGroupCount[0]; @@ -5906,7 +5907,6 @@ PalResult PAL_CALL createShaderVk( VkResult result; Shader* shader = nullptr; VkShaderStageFlags stage = 0; - Uint32 patchControlPoints = 0; Device* vkDevice = (Device*)device; stage = shaderStageToVK(info->stage); @@ -5946,7 +5946,7 @@ PalResult PAL_CALL createShaderVk( } shader->device = vkDevice; - shader->patchControlPoints = patchControlPoints; + shader->patchControlPoints = info->patchControlPoints; shader->info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; shader->info.module = shader->handle; shader->info.pName = "main"; @@ -6403,12 +6403,9 @@ PalResult PAL_CALL cmdBeginVk( layout.colorAttachmentCount = info->colorAttachentCount; layout.pColorAttachmentFormats = colorAttachments; - // depth attachment - format = formatToVk(info->depthAttachmentFormat); + // depth stencil attachment + format = formatToVk(info->depthStencilAttachmentFormat); layout.depthAttachmentFormat = format; - - // stencil attachment - format = formatToVk(info->stencilAttachmentFormat); layout.stencilAttachmentFormat = format; layout.rasterizationSamples = samplesToVk(info->multisampleCount); @@ -8458,7 +8455,6 @@ PalResult PAL_CALL createGraphicsPipelineVk( PalPipeline** outPipeline) { VkResult result; - Uint32 patchControlPoints = 0; Pipeline* pipeline = nullptr; Device* vkDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; @@ -8689,7 +8685,11 @@ PalResult PAL_CALL createGraphicsPipelineVk( rasterizerState.depthBiasEnable = state->enableDepthBias; rasterizerState.depthClampEnable = state->enableDepthClamp; + rasterizerState.depthBiasConstantFactor = state->depthBiasConstant; + rasterizerState.depthBiasSlopeFactor = state->depthBiasSlope; + rasterizerState.depthBiasClamp = state->depthBiasClamp; } + rasterizerState.lineWidth = 1.0f; createInfo.pRasterizationState = &rasterizerState; @@ -8734,7 +8734,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( PalStencilOpState* front = &state->frontStencilOpState; VkStencilOpState* vkBack = &depthStencilState.back; - VkStencilOpState* vkFront = &depthStencilState.back; + VkStencilOpState* vkFront = &depthStencilState.front; vkBack->compareOp = compareOpToVk(back->compareOp); vkBack->depthFailOp = stencilOpToVk(back->depthFailOp); @@ -8805,6 +8805,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( viewportState.scissorCount = 1; createInfo.pViewportState = &viewportState; + // Fragment shading rate if (info->fragmentShadingRateState) { PalFragmentShadingRateState* state = info->fragmentShadingRateState; for (int i = 0; i < 2; i++) { @@ -8819,34 +8820,29 @@ PalResult PAL_CALL createGraphicsPipelineVk( } // layout info - if (info->renderingLayout) { - VkFormat format = VK_FORMAT_UNDEFINED; - VkFormat colorAttachments[MAX_ATTACHMENTS]; - PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; - - // color attachments - for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { - format = formatToVk(renderingLayout->colorAttachmentsFormat[i]); - colorAttachments[i] = format; - } - dynRendering.colorAttachmentCount = renderingLayout->colorAttachentCount; - dynRendering.pColorAttachmentFormats = colorAttachments; + VkFormat format = VK_FORMAT_UNDEFINED; + VkFormat colorAttachments[MAX_ATTACHMENTS]; + PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; - // depth attachment - format = formatToVk(renderingLayout->depthAttachmentFormat); - dynRendering.depthAttachmentFormat = format; + // color attachments + for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { + format = formatToVk(renderingLayout->colorAttachmentsFormat[i]); + colorAttachments[i] = format; + } + dynRendering.colorAttachmentCount = renderingLayout->colorAttachentCount; + dynRendering.pColorAttachmentFormats = colorAttachments; - // stencil attachment - format = formatToVk(renderingLayout->stencilAttachmentFormat); - dynRendering.stencilAttachmentFormat = format; + // depth stencil attachment + format = formatToVk(renderingLayout->depthStencilAttachmentFormat); + dynRendering.depthAttachmentFormat = format; + dynRendering.stencilAttachmentFormat = format; - if (renderingLayout->viewCount == 1) { - dynRendering.viewMask = 0; - } else { - dynRendering.viewMask = (1 << renderingLayout->viewCount) - 1; - } - createInfo.pNext = &dynRendering; + if (renderingLayout->viewCount == 1) { + dynRendering.viewMask = 0; + } else { + dynRendering.viewMask = (1 << renderingLayout->viewCount) - 1; } + createInfo.pNext = &dynRendering; result = s_Vk.createGraphicsPipeline( vkDevice->handle, diff --git a/tests/texture_test.c b/tests/texture_test.c index 3375f875..1a15b6ff 100644 --- a/tests/texture_test.c +++ b/tests/texture_test.c @@ -1042,7 +1042,7 @@ bool textureTest() vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; // texture coordinates - vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_UV; + vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_TEXCOORD; vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT2; vertexLayout.attributeCount = 2; From c2ae60164ea0893239e1face95946cdc3ea96d01 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 19 Apr 2026 16:45:11 +0000 Subject: [PATCH 167/372] add compute pipeline d3d12 --- src/graphics/pal_d3d12.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index bb935f08..dc012465 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -6960,7 +6960,43 @@ PalResult PAL_CALL createComputePipelineD3D12( const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline) { + Device* d3dDevice = (Device*)device; + PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; + Shader* shader = (Shader*)info->computeShader; + Pipeline* pipeline = nullptr; + + pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); + if (!pipeline) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + D3D12_COMPUTE_PIPELINE_STATE_DESC desc = {0}; + desc.CS = shader->byteCode; + desc.pRootSignature = layout->handle; + if (s_D3D.debugLayer) { + desc.Flags = D3D12_PIPELINE_STATE_FLAG_DEBUG; + } + + HRESULT result = d3dDevice->handle->lpVtbl->CreateComputePipelineState( + d3dDevice->handle, + &desc, + &IID_Pipeline, + &pipeline->handle); + + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + pipeline->type = COMPUTE_PIPELINE; + pipeline->strides = nullptr; + pipeline->hasFsr = false; + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL createRayTracingPipelineD3D12( From 17f89544790139c052b153db684b1f4b90d8e170 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 20 Apr 2026 00:33:46 +0000 Subject: [PATCH 168/372] start ray tracing pipeline API d3d12 --- include/pal/pal_graphics.h | 4 +++ src/graphics/pal_d3d12.c | 59 ++++++++++++++++++++++++++++++++++++++ src/graphics/pal_vulkan.c | 2 ++ 3 files changed, 65 insertions(+) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index da8ea4a2..1e678c42 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1548,6 +1548,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + bool RequiresShaderExportName; + bool RequiresShaderGroupExportName; Uint32 maxRecursionDepth; Uint32 maxHitAttributeSize; /**< Max memory per intersection attributes.*/ Uint32 maxInstanceCount; @@ -2497,6 +2499,7 @@ typedef struct { PalShaderStage stage; void* bytecode; Uint64 bytecodeSize; + const char* exportName; /**< Check PalRayTracingCapabilities::RequiresShaderExportName.*/ } PalShaderCreateInfo; /** @@ -2630,6 +2633,7 @@ typedef struct { Uint32 closestHitShaderIndex; /**< Index of closest hit shader from shader array.*/ Uint32 generalShaderIndex; /**< Index of general hit shader from shader array.*/ Uint32 intersectionShaderIndex; /**< Index of intersection hit shader from shader array.*/ + const char* exportName; /**< Check PalRayTracingCapabilities::RequiresShaderGroupExportName.*/ } PalRayTracingShaderGroupCreateInfo; /** diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index dc012465..50b5fdd0 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -219,6 +219,7 @@ typedef struct { Uint32 patchControlPoints; PalShaderStage stage; + const char* exportName; D3D12_SHADER_BYTECODE byteCode; } Shader; @@ -1772,6 +1773,25 @@ static Uint32 getVertexTypeSizeD3D12(PalVertexType type) return 0; } +static const wchar_t* convertToWcharD3D12( + wchar_t* buffer, + Uint32* offset, + const char* name) +{ + Uint32 size = 65536; + wchar_t* dst = buffer[*offset]; + int written = MultiByteToWideChar( + CP_UTF8, + 0, + name, + -1, + dst, + size - *offset); + + *offset += written; + return dst; +} + // ================================================== // Adapter // ================================================== @@ -2689,6 +2709,8 @@ PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( caps->maxPayloadSize = PAL_LIMIT_UNKNOWN; caps->maxDispatchInvocations = PAL_LIMIT_UNKNOWN; + caps->RequiresShaderExportName = true; + caps->RequiresShaderGroupExportName = true; return PAL_RESULT_SUCCESS; } @@ -3801,6 +3823,10 @@ PalResult PAL_CALL createShaderD3D12( if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + + if (!info->exportName) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } } // clang-format on @@ -3813,6 +3839,7 @@ PalResult PAL_CALL createShaderD3D12( shader->byteCode.BytecodeLength = info->bytecodeSize; shader->stage = info->stage; shader->patchControlPoints = info->patchControlPoints; + shader->exportName = info->exportName; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } @@ -7004,7 +7031,39 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( const PalRayTracingPipelineCreateInfo* info, PalPipeline** outPipeline) { + HRESULT result; + Device* d3dDevice = (Device*)device; + PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; + Pipeline* pipeline = nullptr; + D3D12_EXPORT_DESC shaderExports[6]; // 6 shader types for ray tracing pipeline + D3D12_HIT_GROUP_DESC* groups = nullptr; + Uint32 groupSize = sizeof(D3D12_HIT_GROUP_DESC) * info->shaderGroupCount; + wchar_t* scratchBuffer = nullptr; + Uint32 offset = 0; + + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + D3D12_STATE_OBJECT_DESC desc = {0}; + pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); + groups = palAllocate(s_D3D.allocator, groupSize, 0); + scratchBuffer = palAllocate(s_D3D.allocator, 65536 * sizeof(wchar_t), 0); + if (!pipeline || !groups || !scratchBuffer) { + return PAL_RESULT_OUT_OF_MEMORY; + } + // shaders + memset(groups, 0, sizeof(D3D12_HIT_GROUP_DESC) * info->shaderGroupCount); + for (int i = 0; i < info->shaderCount; i++) { + Shader* tmp = (Shader*)info->shaders[i]; + shaderExports[i].Name = convertToWcharD3D12(scratchBuffer, &offset, tmp->exportName); + } + + palFree(s_D3D.allocator, groups); + palFree(s_D3D.allocator, scratchBuffer); + + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index d0f1e328..599303f8 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -4790,6 +4790,8 @@ PalResult PAL_CALL queryRayTracingCapabilitiesVk( caps->maxPayloadSize = INT32_MAX; // depends on memory caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; + caps->RequiresShaderExportName = false; + caps->RequiresShaderGroupExportName = false; return PAL_RESULT_SUCCESS; } From fdad4ad50474bfb09a5118ad581f2e40cfe94d18 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 20 Apr 2026 11:22:53 +0000 Subject: [PATCH 169/372] finish ray tracing pipeline API d3d12 --- include/pal/pal_graphics.h | 2 + src/graphics/pal_d3d12.c | 124 ++++++++++++++++++++++++++++++++++--- src/graphics/pal_vulkan.c | 7 ++- 3 files changed, 123 insertions(+), 10 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 1e678c42..93d18950 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2649,6 +2649,8 @@ typedef struct { Uint32 shaderCount; Uint32 shaderGroupCount; Uint32 maxRecursionDepth; + Uint32 maxAttributeSize; + Uint32 maxPayloadSize; PalPipelineLayout* pipelineLayout; PalRayTracingShaderGroupCreateInfo* shaderGroups; /**< Array of shader group create info.*/ PalShader** shaders; /**< Array of shader stage. This is used by `shaderGroups`.*/ diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 50b5fdd0..9f3dceb8 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -73,6 +73,7 @@ const IID IID_DescHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7, const IID IID_RootSig = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14}; const IID IID_Device5 = {0x8b4f173b, 0x2fea, 0x4b80, 0x8f,0x58, 0x43,0x07,0x19,0x1a,0xb9,0x5d}; const IID IID_Pipeline = {0x765a30f3, 0xf624, 0x4c6f, 0xa8,0x28, 0xac,0xe9,0x48,0x62,0x24,0x45}; +const IID IID_StateObject = {0x47016943, 0xfca8, 0x4594, 0x93,0xea, 0xaf,0x25,0x8b,0x55,0x34,0x6d}; typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -439,6 +440,11 @@ typedef struct { ShaderStream shaders[7]; // 7 shader types for graphics pipeline } GraphicsPipelineeStreamDesc; +typedef struct { + D3D12_EXPORT_DESC exports; + D3D12_DXIL_LIBRARY_DESC dxil; +} RayTracingShader; + static D3D12 s_D3D = {0}; // ================================================== @@ -1779,7 +1785,7 @@ static const wchar_t* convertToWcharD3D12( const char* name) { Uint32 size = 65536; - wchar_t* dst = buffer[*offset]; + wchar_t* dst = buffer + *offset; int written = MultiByteToWideChar( CP_UTF8, 0, @@ -7035,21 +7041,27 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( Device* d3dDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; Pipeline* pipeline = nullptr; - D3D12_EXPORT_DESC shaderExports[6]; // 6 shader types for ray tracing pipeline + + Uint32 offset = 0; + wchar_t* scratchBuffer = nullptr; D3D12_HIT_GROUP_DESC* groups = nullptr; + RayTracingShader* shaders = nullptr; + D3D12_STATE_SUBOBJECT* subObjects = nullptr; Uint32 groupSize = sizeof(D3D12_HIT_GROUP_DESC) * info->shaderGroupCount; - wchar_t* scratchBuffer = nullptr; - Uint32 offset = 0; + Uint32 shaderSize = sizeof(RayTracingShader) * info->shaderCount; + Uint32 subObjectCount = info->shaderCount + info->shaderGroupCount + 3; + Uint32 subObjectIndex = 0; if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - D3D12_STATE_OBJECT_DESC desc = {0}; pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); groups = palAllocate(s_D3D.allocator, groupSize, 0); + shaders = palAllocate(s_D3D.allocator, shaderSize, 0); + subObjects = palAllocate(s_D3D.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); scratchBuffer = palAllocate(s_D3D.allocator, 65536 * sizeof(wchar_t), 0); - if (!pipeline || !groups || !scratchBuffer) { + if (!pipeline || !groups || !shaders || !subObjects || !scratchBuffer) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7057,12 +7069,107 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( memset(groups, 0, sizeof(D3D12_HIT_GROUP_DESC) * info->shaderGroupCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; - shaderExports[i].Name = convertToWcharD3D12(scratchBuffer, &offset, tmp->exportName); + shaders[i].exports.Name = convertToWcharD3D12(scratchBuffer, &offset, tmp->exportName); + shaders[i].exports.ExportToRename = nullptr; + shaders[i].exports.Flags = D3D12_EXPORT_FLAG_NONE; + + shaders[i].dxil.pExports = &shaders[i].exports; + shaders[i].dxil.NumExports = 1; + shaders[i].dxil.DXILLibrary = tmp->byteCode; + + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; + subObjects[subObjectIndex].pDesc = &shaders[i].dxil; + subObjectIndex++; + } + + // hit groups + for (int i = 0; i < info->shaderGroupCount; i++) { + PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; + D3D12_HIT_GROUP_DESC* group = &groups[i]; + + group->AnyHitShaderImport = nullptr; + group->ClosestHitShaderImport = nullptr; + group->IntersectionShaderImport = nullptr; + group->HitGroupExport = convertToWcharD3D12(scratchBuffer, &offset, tmp->exportName); + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { + group->Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; + + } else { + group->Type = D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE; + } + + // any hit shader + if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { + RayTracingShader* shader = &shaders[tmp->anyHitShaderIndex]; + if (shader) { + group->AnyHitShaderImport = shader->exports.Name; + } + } + + // closest hit shader + if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { + RayTracingShader* shader = &shaders[tmp->closestHitShaderIndex]; + if (shader) { + group->ClosestHitShaderImport = shader->exports.Name; + } + } + + // intersection shader + if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { + RayTracingShader* shader = &shaders[tmp->intersectionShaderIndex]; + if (shader) { + group->IntersectionShaderImport = shader->exports.Name; + } + } + + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP; + subObjects[subObjectIndex].pDesc = group; + subObjectIndex++; + } + + // ray tracing config + D3D12_RAYTRACING_SHADER_CONFIG shaderConfig = {0}; + shaderConfig.MaxAttributeSizeInBytes = info->maxAttributeSize; + shaderConfig.MaxPayloadSizeInBytes = info->maxPayloadSize; + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG; + subObjects[subObjectIndex].pDesc = &shaderConfig; + subObjectIndex++; + + D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = {0}; + pipelineConfig.MaxTraceRecursionDepth = info->maxRecursionDepth; + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG; + subObjects[subObjectIndex].pDesc = &pipelineConfig; + subObjectIndex++; + + D3D12_STATE_OBJECT_DESC desc = {0}; + desc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; + desc.NumSubobjects = subObjectCount; + desc.pSubobjects = subObjects; + + result = d3dDevice->handle->lpVtbl->CreateStateObject( + d3dDevice->handle, + &desc, + &IID_StateObject, + &pipeline->handle); + + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; } palFree(s_D3D.allocator, groups); + palFree(s_D3D.allocator, shaders); + palFree(s_D3D.allocator, subObjects); palFree(s_D3D.allocator, scratchBuffer); + pipeline->type = RAY_TRACING_PIPELINE; + pipeline->strides = nullptr; + pipeline->hasFsr = false; + *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -7070,7 +7177,8 @@ void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) { Pipeline* d3dPipeline = (Pipeline*)pipeline; if (d3dPipeline->type == RAY_TRACING_PIPELINE) { - // TODO: ray tracing pipeline + ID3D12StateObject* handle = d3dPipeline->handle; + handle->lpVtbl->Release(handle); } else { ID3D12PipelineState* handle = d3dPipeline->handle; handle->lpVtbl->Release(handle); diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 599303f8..105a0513 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -8922,9 +8922,10 @@ PalResult PAL_CALL createRayTracingPipelineVk( Device* vkDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; Pipeline* pipeline = nullptr; - VkPipelineShaderStageCreateInfo shaderStages[6]; // 6 shader types for ray tracing pipeline + VkPipelineShaderStageCreateInfo* shaderStages = nullptr; VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; Uint32 groupSize = sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount; + Uint32 shaderSize = sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -8935,7 +8936,8 @@ PalResult PAL_CALL createRayTracingPipelineVk( pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); groups = palAllocate(s_Vk.allocator, groupSize, 0); - if (!pipeline || !groups) { + shaderStages = palAllocate(s_Vk.allocator, shaderSize, 0); + if (!pipeline || !groups || !shaderStages) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -8983,6 +8985,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( &pipeline->handle); palFree(s_Vk.allocator, groups); + palFree(s_Vk.allocator, shaderStages); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pipeline); return resultFromVk(result); From b5963655e4dd1b357ebb1dc62160d84df356bf86 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 21 Apr 2026 12:59:19 +0000 Subject: [PATCH 170/372] finish d3d12 graphics backend --- include/pal/pal_core.h | 2 +- src/graphics/pal_d3d12.c | 332 +++++++++++++++++++++++++++++++------- src/graphics/pal_vulkan.c | 13 +- src/pal_core.c | 7 +- 4 files changed, 286 insertions(+), 68 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index ab4527fc..620ab0e3 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -264,9 +264,9 @@ typedef enum { PAL_RESULT_INVALID_COMMAND_BUFFER, PAL_RESULT_INVALID_FENCE, PAL_RESULT_INVALID_SEMAPHORE, - PAL_RESULT_INVALID_RENDER_PASS, PAL_RESULT_INVALID_BUFFER, PAL_RESULT_INVALID_ACCELERATION_STRUCTURE, + PAL_RESULT_INVALID_PIPELINE, PAL_RESULT_MEMORY_MAP_FAILED, PAL_RESULT_DEVICE_LOST, PAL_RESULT_SURFACE_LOST, diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 9f3dceb8..b3590308 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -48,32 +48,36 @@ freely, subject to the following restrictions: #define TEXTURE_PITCH 256 #define MAX_RTV 1024 #define MAX_DSV 512 +#define MAX_SCRATCH_BUFFER_SIZE 65536 * sizeof(wchar_t) #define GRAPHICS_PIPELINE 1220 #define COMPUTE_PIPELINE 1221 #define RAY_TRACING_PIPELINE 1222 +// clang-format off // IIDS const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; const IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0xd2,0x4e}; const IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0,0x3c, 0x77,0x90,0x0a,0x0a,0x1d,0x17}; -const IID IID_Debug = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0}; -const IID IID_Debug1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; +const IID IID_DebugController = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0}; +const IID IID_DebugController1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; const IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4,0xe6,0x14,0x58}; const IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3}; const IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed}; const IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; const IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad}; const IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1}; -const IID IID_CmdAlloc = {0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73,0xf0,0x9b,0x24}; -const IID IID_CmdList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5}; -const IID IID_CmdList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96,0xcf, 0x56,0x89,0xa9,0x37,0x0f,0x80}; -const IID IID_Signature = {0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1}; -const IID IID_DescHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51}; -const IID IID_RootSig = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14}; +const IID IID_CommandAllocator = {0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73,0xf0,0x9b,0x24}; +const IID IID_CommandList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5}; +const IID IID_CommandList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96,0xcf, 0x56,0x89,0xa9,0x37,0x0f,0x80}; +const IID IID_CommandSignature = {0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1}; +const IID IID_DescriptorHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51}; +const IID IID_RootSignature = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14}; const IID IID_Device5 = {0x8b4f173b, 0x2fea, 0x4b80, 0x8f,0x58, 0x43,0x07,0x19,0x1a,0xb9,0x5d}; -const IID IID_Pipeline = {0x765a30f3, 0xf624, 0x4c6f, 0xa8,0x28, 0xac,0xe9,0x48,0x62,0x24,0x45}; +const IID IID_PipelineState = {0x765a30f3, 0xf624, 0x4c6f, 0xa8,0x28, 0xac,0xe9,0x48,0x62,0x24,0x45}; const IID IID_StateObject = {0x47016943, 0xfca8, 0x4594, 0x93,0xea, 0xaf,0x25,0x8b,0x55,0x34,0x6d}; +const IID IID_StateObjectProps = {0xde5fa827, 0x9bf9, 0x4f26, 0x89,0xff, 0xd7,0xf5,0x6f,0xde,0x38,0x60}; +// clang-format on typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -267,6 +271,12 @@ typedef struct { ID3D12Resource* handle; } AccelerationStructure; +typedef struct { + PalShaderStage stage; + D3D12_EXPORT_DESC exports; + D3D12_DXIL_LIBRARY_DESC dxil; +} RayTracingShader; + typedef struct { const PalGraphicsBackend* backend; @@ -276,17 +286,16 @@ typedef struct { D3D_PRIMITIVE_TOPOLOGY topology; Uint32* strides; void* handle; + wchar_t* scratchBuffer; + RayTracingShader* shaders; D3D12_SHADING_RATE_COMBINER combinerOps[2]; } Pipeline; typedef struct { const PalGraphicsBackend* backend; - Uint64 raygenStride; ID3D12Resource* buffer; - ID3D12Heap* bufferMemory; D3D12_GPU_VIRTUAL_ADDRESS baseAddress; - D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress; D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE missAddress; D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE hitAddress; @@ -440,11 +449,6 @@ typedef struct { ShaderStream shaders[7]; // 7 shader types for graphics pipeline } GraphicsPipelineeStreamDesc; -typedef struct { - D3D12_EXPORT_DESC exports; - D3D12_DXIL_LIBRARY_DESC dxil; -} RayTracingShader; - static D3D12 s_D3D = {0}; // ================================================== @@ -1779,21 +1783,45 @@ static Uint32 getVertexTypeSizeD3D12(PalVertexType type) return 0; } -static const wchar_t* convertToWcharD3D12( +static wchar_t* convertToWcharD3D12( wchar_t* buffer, Uint32* offset, const char* name) { - Uint32 size = 65536; + if (!name) { + return nullptr; + } + size_t srcLen = strlen(name); + int dstLen = MultiByteToWideChar( + CP_UTF8, + 0, + name, + srcLen, + nullptr, + 0); + + if (!dstLen) { + return nullptr; + } + + if (*offset + dstLen + 1 > MAX_SCRATCH_BUFFER_SIZE) { + return nullptr; + } + wchar_t* dst = buffer + *offset; int written = MultiByteToWideChar( CP_UTF8, 0, name, - -1, + srcLen, dst, - size - *offset); + dstLen); + + if (!written) { + return nullptr; + } + dst[written] = L'\0'; *offset += written; return dst; } @@ -1833,12 +1861,12 @@ PalResult PAL_CALL initGraphicsD3D12( if (s_D3D.getDebugInterface) { HRESULT hr; - hr = s_D3D.getDebugInterface(&IID_Debug, (void**)&s_D3D.debugController); + hr = s_D3D.getDebugInterface(&IID_DebugController, (void**)&s_D3D.debugController); if (SUCCEEDED(hr)) { s_D3D.debugController->lpVtbl->EnableDebugLayer(s_D3D.debugController); } - hr = s_D3D.getDebugInterface(&IID_Debug1, (void**)&s_D3D.debugController1); + hr = s_D3D.getDebugInterface(&IID_DebugController1, (void**)&s_D3D.debugController1); if (SUCCEEDED(hr)) { s_D3D.debugController1->lpVtbl->SetEnableGPUBasedValidation( s_D3D.debugController1, @@ -2342,7 +2370,7 @@ PalResult PAL_CALL createDeviceD3D12( device->handle, &signatureDesc, nullptr, - &IID_Signature, + &IID_CommandSignature, (void**)&device->meshSignature); if (FAILED(result)) { @@ -2361,7 +2389,7 @@ PalResult PAL_CALL createDeviceD3D12( device->handle, &signatureDesc, nullptr, - &IID_Signature, + &IID_CommandSignature, (void**)&device->raySignature); if (FAILED(result)) { @@ -2381,7 +2409,7 @@ PalResult PAL_CALL createDeviceD3D12( device->handle, &signatureDesc, nullptr, - &IID_Signature, + &IID_CommandSignature, (void**)&device->dispatchSignature); if (FAILED(result)) { @@ -2399,7 +2427,7 @@ PalResult PAL_CALL createDeviceD3D12( device->handle, &signatureDesc, nullptr, - &IID_Signature, + &IID_CommandSignature, (void**)&device->drawIndexedSignature); if (FAILED(result)) { @@ -2417,7 +2445,7 @@ PalResult PAL_CALL createDeviceD3D12( device->handle, &signatureDesc, nullptr, - &IID_Signature, + &IID_CommandSignature, (void**)&device->drawSignature); if (FAILED(result)) { @@ -2436,7 +2464,7 @@ PalResult PAL_CALL createDeviceD3D12( result = device->handle->lpVtbl->CreateDescriptorHeap( device->handle, &heapDesc, - &IID_DescHeap, + &IID_DescriptorHeap, (void**)&device->rtvAllocator.heap); if (FAILED(result)) { @@ -2451,7 +2479,7 @@ PalResult PAL_CALL createDeviceD3D12( result = device->handle->lpVtbl->CreateDescriptorHeap( device->handle, &heapDesc, - &IID_DescHeap, + &IID_DescriptorHeap, (void**)&device->dsvAllocator.heap); if (FAILED(result)) { @@ -4177,7 +4205,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( result = d3dDevice->handle->lpVtbl->CreateCommandAllocator( d3dDevice->handle, cmdBufferType, - &IID_CmdAlloc, + &IID_CommandAllocator, (void**)&cmdBuffer->allocator); if (FAILED(result)) { @@ -4195,7 +4223,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( cmdBufferType, cmdBuffer->allocator, nullptr, - &IID_CmdList, + &IID_CommandList, (void**)&cmdList); if (FAILED(result)) { @@ -4238,7 +4266,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( cmdList->lpVtbl->QueryInterface( cmdList, - &IID_CmdList6, + &IID_CommandList6, (void**)&cmdBuffer->handle); cmdList->lpVtbl->Release(cmdList); @@ -5372,9 +5400,10 @@ PalResult PAL_CALL cmdTraceRaysD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + Uint32 stride = d3dSbt->hitAddress.StrideInBytes; // same for raygen D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; raygenAddress.SizeInBytes = d3dSbt->raygenAddress.SizeInBytes; - raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * d3dSbt->raygenStride; + raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * stride; D3D12_DISPATCH_RAYS_DESC desc = {0}; desc.Width = width; @@ -5420,9 +5449,10 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( desc.Height = data.groupCountXOrHeight; desc.Depth = data.groupCountXOrDepth; + Uint32 stride = d3dSbt->hitAddress.StrideInBytes; // same for raygen D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; raygenAddress.SizeInBytes = d3dSbt->raygenAddress.SizeInBytes; - raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * d3dSbt->raygenStride; + raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * stride; desc.RayGenerationShaderRecord = raygenAddress; desc.HitGroupTable = d3dSbt->hitAddress; @@ -5485,14 +5515,12 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( pipelineLayout->resourceIndex, base); - } else if (d3dCmdBuffer->pipelineType == COMPUTE_PIPELINE) { + } else { + // ray tracing uses the compute path d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( d3dCmdBuffer->handle, pipelineLayout->resourceIndex, base); - - } else { - // TODO: ray tracing bind point } } @@ -5510,14 +5538,12 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( pipelineLayout->samplerIndex, base); - } else if (d3dCmdBuffer->pipelineType == COMPUTE_PIPELINE) { + } else { + // ray tracing uses the compute path d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( d3dCmdBuffer->handle, pipelineLayout->samplerIndex, base); - - } else { - // TODO: ray tracing bind point } } @@ -5544,16 +5570,14 @@ PalResult PAL_CALL cmdPushConstantsD3D12( value, offset / 4); - } else if (d3dCmdBuffer->pipelineType == COMPUTE_PIPELINE) { + } else { + // ray tracing uses the compute path d3dCmdBuffer->handle->lpVtbl->SetComputeRoot32BitConstants( d3dCmdBuffer->handle, pipelineLayout->constantIndex, size / 4, value, offset / 4); - - } else { - // TODO: ray tracing bind point } } @@ -6068,7 +6092,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( d3dDevice->handle, &desc, - &IID_DescHeap, + &IID_DescriptorHeap, (void**)&heap->handle); if (FAILED(result)) { @@ -6111,7 +6135,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( d3dDevice->handle, &desc, - &IID_DescHeap, + &IID_DescriptorHeap, (void**)&heap->handle); if (FAILED(result)) { @@ -6522,7 +6546,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( 0, blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), - &IID_RootSig, + &IID_RootSignature, (void**)&layout->handle); if (FAILED(result)) { @@ -6962,7 +6986,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( result = d3dDevice->handle->lpVtbl->CreatePipelineState( d3dDevice->handle, &streamDesc, - &IID_Pipeline, + &IID_PipelineState, &pipeline->handle); if (FAILED(result)) { @@ -6984,6 +7008,8 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( pipeline->topology = topology; pipeline->type = GRAPHICS_PIPELINE; + pipeline->shaders = nullptr; + pipeline->scratchBuffer = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -7013,7 +7039,7 @@ PalResult PAL_CALL createComputePipelineD3D12( HRESULT result = d3dDevice->handle->lpVtbl->CreateComputePipelineState( d3dDevice->handle, &desc, - &IID_Pipeline, + &IID_PipelineState, &pipeline->handle); if (FAILED(result)) { @@ -7027,6 +7053,8 @@ PalResult PAL_CALL createComputePipelineD3D12( pipeline->type = COMPUTE_PIPELINE; pipeline->strides = nullptr; + pipeline->shaders = nullptr; + pipeline->scratchBuffer = nullptr; pipeline->hasFsr = false; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -7043,10 +7071,11 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( Pipeline* pipeline = nullptr; Uint32 offset = 0; - wchar_t* scratchBuffer = nullptr; D3D12_HIT_GROUP_DESC* groups = nullptr; - RayTracingShader* shaders = nullptr; D3D12_STATE_SUBOBJECT* subObjects = nullptr; + RayTracingShader* shaders = nullptr; + wchar_t* scratchBuffer = nullptr; + Uint32 groupSize = sizeof(D3D12_HIT_GROUP_DESC) * info->shaderGroupCount; Uint32 shaderSize = sizeof(RayTracingShader) * info->shaderCount; Uint32 subObjectCount = info->shaderCount + info->shaderGroupCount + 3; @@ -7060,7 +7089,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( groups = palAllocate(s_D3D.allocator, groupSize, 0); shaders = palAllocate(s_D3D.allocator, shaderSize, 0); subObjects = palAllocate(s_D3D.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); - scratchBuffer = palAllocate(s_D3D.allocator, 65536 * sizeof(wchar_t), 0); + scratchBuffer = palAllocate(s_D3D.allocator, MAX_SCRATCH_BUFFER_SIZE, 0); if (!pipeline || !groups || !shaders || !subObjects || !scratchBuffer) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7069,7 +7098,9 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( memset(groups, 0, sizeof(D3D12_HIT_GROUP_DESC) * info->shaderGroupCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; + shaders[i].stage = tmp->stage; shaders[i].exports.Name = convertToWcharD3D12(scratchBuffer, &offset, tmp->exportName); + shaders[i].exports.ExportToRename = nullptr; shaders[i].exports.Flags = D3D12_EXPORT_FLAG_NONE; @@ -7091,6 +7122,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( group->ClosestHitShaderImport = nullptr; group->IntersectionShaderImport = nullptr; group->HitGroupExport = convertToWcharD3D12(scratchBuffer, &offset, tmp->exportName); + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { group->Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; @@ -7162,13 +7194,14 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( } palFree(s_D3D.allocator, groups); - palFree(s_D3D.allocator, shaders); palFree(s_D3D.allocator, subObjects); - palFree(s_D3D.allocator, scratchBuffer); pipeline->type = RAY_TRACING_PIPELINE; pipeline->strides = nullptr; pipeline->hasFsr = false; + pipeline->shaders = shaders; + pipeline->scratchBuffer = scratchBuffer; + *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -7187,6 +7220,14 @@ void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) if (d3dPipeline->strides) { palFree(s_D3D.allocator, d3dPipeline->strides); } + + if (d3dPipeline->shaders) { + palFree(s_D3D.allocator, d3dPipeline->shaders); + } + + if (d3dPipeline->scratchBuffer) { + palFree(s_D3D.allocator, d3dPipeline->scratchBuffer); + } palFree(s_D3D.allocator, d3dPipeline); } @@ -7199,12 +7240,187 @@ PalResult PAL_CALL createShaderBindingTableD3D12( const PalShaderBindingTableCreateInfo* info, PalShaderBindingTable** outSbt) { + HRESULT result; + Device* d3dDevice = (Device*)device; + ShaderBindingTable* sbt = nullptr; + Pipeline* pipeline = (Pipeline*)info->rayTracingPipeline; + + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + void** raygenHandles = nullptr; + void** missHandles = nullptr; + void** hitHandles = nullptr; + void** callableHandles = nullptr; + + sbt = palAllocate(s_D3D.allocator, sizeof(ShaderBindingTable), 0); + raygenHandles = palAllocate(s_D3D.allocator, sizeof(void*) * info->raygenGroupCount, 0); + missHandles = palAllocate(s_D3D.allocator, sizeof(void*) * info->missGroupCount, 0); + hitHandles = palAllocate(s_D3D.allocator, sizeof(void*) * info->hitGroupCount, 0); + callableHandles = palAllocate(s_D3D.allocator, sizeof(void*) * info->callableGroupCount, 0); + if (!sbt || !raygenHandles || !missHandles || !hitHandles || !callableHandles) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // create SBT buffer + ID3D12StateObject* pipelineHandle = pipeline->handle; + ID3D12StateObjectProperties* props = NULL; + result = pipelineHandle->lpVtbl->QueryInterface( + pipelineHandle, + &IID_StateObjectProps, + (void**)&props); + + if (FAILED(result)) { + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_PIPELINE; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + Uint32 groupHandleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + Uint32 groupHandleAlignment = 32; // PAL does not allow local signatures + Uint32 groupBaseAlignment = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; + Uint32 stride = alignD3D12(groupHandleSize, groupHandleAlignment); + + // get region size + Uint32 raygenRegionSize = stride * info->raygenGroupCount; + Uint32 missRegionSize = stride * info->missGroupCount; + Uint32 hitRegionSize = stride * info->hitGroupCount; + Uint32 callableRegionSize = stride * info->callableGroupCount; + + // get aligned region size + Uint32 raygenAlignedRegionSize = alignD3D12(raygenRegionSize, groupBaseAlignment); + Uint32 missAlignedRegionSize = alignD3D12(missRegionSize, groupBaseAlignment); + Uint32 hitAlignedRegionSize = alignD3D12(hitRegionSize, groupBaseAlignment); + Uint32 callableAligneRegionSize = alignD3D12(callableRegionSize, groupBaseAlignment); + + // get offsets + Uint32 missOffset = raygenAlignedRegionSize; + Uint32 hitOffset = missOffset + missAlignedRegionSize; + Uint32 callableOffset = hitOffset + hitAlignedRegionSize; + Uint32 bufferSize = callableOffset + callableAligneRegionSize; + + // create gpu buffer + D3D12_HEAP_PROPERTIES heapProps = {0}; + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + heapProps.VisibleNodeMask = 1; + heapProps.CreationNodeMask = 1; + + D3D12_RESOURCE_DESC bufferDesc = {0}; + bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + bufferDesc.Width = bufferSize; + bufferDesc.Height = 1; + bufferDesc.DepthOrArraySize = 1; + bufferDesc.MipLevels = 1; + bufferDesc.SampleDesc.Count = 1; + bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + + result = d3dDevice->handle->lpVtbl->CreateCommittedResource( + d3dDevice->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + &IID_Resource, (void**)&sbt->buffer); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + // get shader group handles + Uint32 totalGroups = info->raygenGroupCount + info->hitGroupCount; + totalGroups += info->missGroupCount + info->callableGroupCount; + for (int i = 0; i < totalGroups; i++) { + RayTracingShader* tmp = &pipeline->shaders[i]; + PalShaderStage stage = tmp->stage; + + if (stage == PAL_SHADER_STAGE_RAYGEN) { + raygenHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->exports.Name); + + } else if (stage == PAL_SHADER_STAGE_MISS) { + missHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->exports.Name); + + } else if (stage == PAL_SHADER_STAGE_ANY_HIT || + stage == PAL_SHADER_STAGE_CLOSEST_HIT || + stage == PAL_SHADER_STAGE_INTERSECTION) { + hitHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->exports.Name); + + } else if (stage == PAL_SHADER_STAGE_CALLABLE) { + callableHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->exports.Name); + } + } + + // copy shader group handles into the buffer + void* ptr = nullptr; + Uint8* dstPtr = ptr; + result = sbt->buffer->lpVtbl->Map(sbt->buffer, 0, nullptr, &ptr); + if (FAILED(result)) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + // raygen + for (int i = 0; i < info->raygenGroupCount; i++) { + memcpy(dstPtr + i * stride, raygenHandles[i], groupHandleSize); + } + + // miss + for (int i = 0; i < info->missGroupCount; i++) { + memcpy(dstPtr + missOffset + i * stride, missHandles[i], groupHandleSize); + } + + // hit group + for (int i = 0; i < info->hitGroupCount; i++) { + memcpy(dstPtr + hitOffset + i * stride, hitHandles[i], groupHandleSize); + } + + // callable group + for (int i = 0; i < info->callableGroupCount; i++) { + memcpy(dstPtr + callableOffset + i * stride, callableHandles[i], groupHandleSize); + } + + // cache SBT fields and offsets address + sbt->buffer->lpVtbl->Unmap(sbt->buffer, 0, nullptr); + sbt->baseAddress = sbt->buffer->lpVtbl->GetGPUVirtualAddress(sbt->buffer); + // raygen + sbt->raygenAddress.StartAddress = sbt->baseAddress; + sbt->raygenAddress.SizeInBytes = raygenAlignedRegionSize; + + // miss + sbt->missAddress.StartAddress = sbt->baseAddress + missOffset; + sbt->missAddress.SizeInBytes = missAlignedRegionSize; + sbt->missAddress.StrideInBytes = stride; + + // hit + sbt->hitAddress.StartAddress = sbt->baseAddress + hitOffset; + sbt->hitAddress.SizeInBytes = hitAlignedRegionSize; + sbt->hitAddress.StrideInBytes = stride; + + // callable + sbt->callableAddress.StartAddress = sbt->baseAddress + callableOffset; + sbt->callableAddress.SizeInBytes = callableAligneRegionSize; + sbt->callableAddress.StrideInBytes = stride; + + props->lpVtbl->Release(props); + palFree(s_D3D.allocator, raygenHandles); + palFree(s_D3D.allocator, missHandles); + palFree(s_D3D.allocator, hitHandles); + palFree(s_D3D.allocator, callableHandles); + + *outSbt = (PalShaderBindingTable*)sbt; + return PAL_RESULT_SUCCESS; } void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) { - + ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; + d3dSbt->buffer->lpVtbl->Release(d3dSbt->buffer); + palFree(s_D3D.allocator, d3dSbt); } #endif // PAL_HAS_D3D12 diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 105a0513..ae8f53fa 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -9048,10 +9048,9 @@ PalResult PAL_CALL createShaderBindingTableVk( Uint32 hitRegionSize = stride * info->hitGroupCount; Uint32 callableRegionSize = stride * info->callableGroupCount; - // get alignVked region size + // get aligned region size Uint32 raygenAlignedRegionSize = alignVk(raygenRegionSize, groupBaseAlignment); Uint32 missAlignedRegionSize = alignVk(missRegionSize, groupBaseAlignment); - ; Uint32 hitAlignedRegionSize = alignVk(hitRegionSize, groupBaseAlignment); Uint32 callableAligneRegionSize = alignVk(callableRegionSize, groupBaseAlignment); @@ -9104,7 +9103,7 @@ PalResult PAL_CALL createShaderBindingTableVk( } s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); - // get shader handles + // get shader group handles Uint32 totalGroups = info->raygenGroupCount + info->hitGroupCount; totalGroups += info->missGroupCount + info->callableGroupCount; Uint32 sbtSize = totalGroups * groupHandleSize; @@ -9142,25 +9141,25 @@ PalResult PAL_CALL createShaderBindingTableVk( for (int i = 0; i < info->raygenGroupCount; i++) { memcpy(dstPtr + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); } - srcPtr += info->raygenGroupCount * groupHandleSize; + srcPtr += raygenRegionSize; // miss for (int i = 0; i < info->missGroupCount; i++) { memcpy(dstPtr + missOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); } - srcPtr += info->missGroupCount * groupHandleSize; + srcPtr += missRegionSize; // hit for (int i = 0; i < info->hitGroupCount; i++) { memcpy(dstPtr + hitOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); } - srcPtr += info->hitGroupCount * groupHandleSize; + srcPtr += hitRegionSize; // callable for (int i = 0; i < info->callableGroupCount; i++) { memcpy(dstPtr + callableOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); } - srcPtr += info->callableGroupCount * groupHandleSize; + srcPtr += callableRegionSize; s_Vk.unmapMemory(vkDevice->handle, sbt->bufferMemory); diff --git a/src/pal_core.c b/src/pal_core.c index d0096814..8ff8c816 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -434,8 +434,11 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_SEMAPHORE: return "Invalid semaphore"; - case PAL_RESULT_INVALID_RENDER_PASS: - return "Invalid render pass"; + case PAL_RESULT_INVALID_BUFFER: + return "Invalid buffer"; + + case PAL_RESULT_INVALID_PIPELINE: + return "Invalid pipeline"; case PAL_RESULT_INVALID_ACCELERATION_STRUCTURE: return "Invalid acceleration structure"; From 4e1da97c140a5ce711e71dea4fbcacf55b7ef74c Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 21 Apr 2026 15:30:08 +0000 Subject: [PATCH 171/372] repack tests into sub directories --- include/pal/pal_config.h | 4 +- tests/{ => core}/logger_test.c | 6 -- tests/{ => core}/time_test.c | 6 -- tests/{ => event}/event_test.c | 7 -- tests/{ => event}/user_event_test.c | 6 -- tests/{ => graphics}/clear_color_test.c | 6 -- tests/{ => graphics}/compute_test.c | 6 -- tests/{ => graphics}/graphics_test.c | 6 -- tests/{ => graphics}/mesh_test.c | 6 -- tests/{ => graphics}/ray_tracing_test.c | 6 -- tests/{ => graphics}/texture_test.c | 6 -- tests/{ => graphics}/triangle_test.c | 6 -- tests/{ => opengl}/multi_thread_opengl_test.c | 6 -- tests/{ => opengl}/opengl_context_test.c | 6 -- tests/{ => opengl}/opengl_fbconfig_test.c | 6 -- .../{ => opengl}/opengl_multi_context_test.c | 6 -- tests/{ => opengl}/opengl_test.c | 6 -- tests/shaders/closest_hit.spv | Bin 372 -> 0 bytes tests/shaders/compute.spv | Bin 1668 -> 0 bytes tests/shaders/mesh.spv | Bin 1948 -> 0 bytes tests/shaders/miss.spv | Bin 356 -> 0 bytes tests/shaders/raygen.spv | Bin 2320 -> 0 bytes tests/shaders/texture_frag.spv | Bin 680 -> 0 bytes tests/shaders/texture_vert.spv | Bin 980 -> 0 bytes tests/shaders/triangle_frag.spv | Bin 372 -> 0 bytes tests/shaders/triangle_vert.spv | Bin 1140 -> 0 bytes tests/{ => system}/system_test.c | 6 -- tests/tests.c | 19 ++++- tests/tests.h | 2 +- tests/tests.lua | 77 ++++++++++-------- tests/tests_main.c | 72 ++++++++-------- tests/{ => thread}/condvar_test.c | 6 -- tests/{ => thread}/mutex_test.c | 6 -- tests/{ => thread}/thread_test.c | 6 -- tests/{ => thread}/tls_test.c | 6 -- tests/{ => video}/attach_window_test.c | 7 +- tests/{ => video}/char_event_test.c | 7 +- tests/{ => video}/cursor_test.c | 7 +- tests/{ => video}/custom_decoration_test.c | 9 +- tests/{ => video}/icon_test.c | 7 +- tests/{ => video}/input_window_test.c | 7 +- tests/{ => video}/monitor_mode_test.c | 6 -- tests/{ => video}/monitor_test.c | 6 -- tests/{ => video}/native_instance_test.c | 7 +- tests/{ => video}/native_integration_test.c | 7 +- tests/{ => video}/system_cursor_test.c | 7 +- tests/{ => video}/video_test.c | 8 +- tests/{ => video}/window_test.c | 7 +- 48 files changed, 108 insertions(+), 285 deletions(-) rename tests/{ => core}/logger_test.c (82%) rename tests/{ => core}/time_test.c (83%) rename tests/{ => event}/event_test.c (93%) rename tests/{ => event}/user_event_test.c (93%) rename tests/{ => graphics}/clear_color_test.c (98%) rename tests/{ => graphics}/compute_test.c (99%) rename tests/{ => graphics}/graphics_test.c (97%) rename tests/{ => graphics}/mesh_test.c (99%) rename tests/{ => graphics}/ray_tracing_test.c (99%) rename tests/{ => graphics}/texture_test.c (99%) rename tests/{ => graphics}/triangle_test.c (99%) rename tests/{ => opengl}/multi_thread_opengl_test.c (98%) rename tests/{ => opengl}/opengl_context_test.c (98%) rename tests/{ => opengl}/opengl_fbconfig_test.c (95%) rename tests/{ => opengl}/opengl_multi_context_test.c (98%) rename tests/{ => opengl}/opengl_test.c (92%) delete mode 100644 tests/shaders/closest_hit.spv delete mode 100644 tests/shaders/compute.spv delete mode 100644 tests/shaders/mesh.spv delete mode 100644 tests/shaders/miss.spv delete mode 100644 tests/shaders/raygen.spv delete mode 100644 tests/shaders/texture_frag.spv delete mode 100644 tests/shaders/texture_vert.spv delete mode 100644 tests/shaders/triangle_frag.spv delete mode 100644 tests/shaders/triangle_vert.spv rename tests/{ => system}/system_test.c (95%) rename tests/{ => thread}/condvar_test.c (93%) rename tests/{ => thread}/mutex_test.c (90%) rename tests/{ => thread}/thread_test.c (88%) rename tests/{ => thread}/tls_test.c (91%) rename tests/{ => video}/attach_window_test.c (97%) rename tests/{ => video}/char_event_test.c (94%) rename tests/{ => video}/cursor_test.c (95%) rename tests/{ => video}/custom_decoration_test.c (99%) rename tests/{ => video}/icon_test.c (95%) rename tests/{ => video}/input_window_test.c (98%) rename tests/{ => video}/monitor_mode_test.c (95%) rename tests/{ => video}/monitor_test.c (93%) rename tests/{ => video}/native_instance_test.c (97%) rename tests/{ => video}/native_integration_test.c (97%) rename tests/{ => video}/system_cursor_test.c (94%) rename tests/{ => video}/video_test.c (96%) rename tests/{ => video}/window_test.c (98%) diff --git a/include/pal/pal_config.h b/include/pal/pal_config.h index b066298b..e9f4450c 100644 --- a/include/pal/pal_config.h +++ b/include/pal/pal_config.h @@ -3,7 +3,7 @@ // Must not be edited manually #define PAL_HAS_SYSTEM 1 -#define PAL_HAS_THREAD 0 +#define PAL_HAS_THREAD 1 #define PAL_HAS_VIDEO 1 -#define PAL_HAS_OPENGL 0 +#define PAL_HAS_OPENGL 1 #define PAL_HAS_GRAPHICS 1 diff --git a/tests/logger_test.c b/tests/core/logger_test.c similarity index 82% rename from tests/logger_test.c rename to tests/core/logger_test.c index b3957369..3dcabbb6 100644 --- a/tests/logger_test.c +++ b/tests/core/logger_test.c @@ -27,12 +27,6 @@ static void PAL_CALL onLogger( bool loggerTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Logger Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalLogger loggers[LOGGER_COUNT]; for (Int32 i = 0; i < LOGGER_COUNT; i++) { loggers[i].callback = onLogger; diff --git a/tests/time_test.c b/tests/core/time_test.c similarity index 83% rename from tests/time_test.c rename to tests/core/time_test.c index e5ae19ce..1515a281 100644 --- a/tests/time_test.c +++ b/tests/core/time_test.c @@ -16,12 +16,6 @@ static inline double getTime(MyTimer* timer) bool timeTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Time Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - // create and set the frequency and start time for time related calculations MyTimer timer; timer.frequency = palGetPerformanceFrequency(); diff --git a/tests/event_test.c b/tests/event/event_test.c similarity index 93% rename from tests/event_test.c rename to tests/event/event_test.c index c913b2da..37b41e7b 100644 --- a/tests/event_test.c +++ b/tests/event/event_test.c @@ -78,13 +78,6 @@ static inline void eventDispatchTest(bool poll) bool eventTest() { - - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Event Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - MyTimer timer; timer.frequency = palGetPerformanceFrequency(); timer.startTime = palGetPerformanceCounter(); diff --git a/tests/user_event_test.c b/tests/event/user_event_test.c similarity index 93% rename from tests/user_event_test.c rename to tests/event/user_event_test.c index 0847f0af..c7d50353 100644 --- a/tests/user_event_test.c +++ b/tests/event/user_event_test.c @@ -20,12 +20,6 @@ static inline double getTime(MyTimer* timer) bool userEventTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "User Event Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalEventDriver* eventDriver = nullptr; PalEventDriverCreateInfo createInfo; diff --git a/tests/clear_color_test.c b/tests/graphics/clear_color_test.c similarity index 98% rename from tests/clear_color_test.c rename to tests/graphics/clear_color_test.c index 5ebe624f..346bb19b 100644 --- a/tests/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -19,12 +19,6 @@ static void PAL_CALL onGraphicsDebug( bool clearColorTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Clear Color Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; diff --git a/tests/compute_test.c b/tests/graphics/compute_test.c similarity index 99% rename from tests/compute_test.c rename to tests/graphics/compute_test.c index 0d8d0779..b3cb00a7 100644 --- a/tests/compute_test.c +++ b/tests/graphics/compute_test.c @@ -52,12 +52,6 @@ static void PAL_CALL onGraphicsDebug( bool computeTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Compute Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalAdapter* adapter = nullptr; PalDevice* device = nullptr; PalQueue* queue = nullptr; diff --git a/tests/graphics_test.c b/tests/graphics/graphics_test.c similarity index 97% rename from tests/graphics_test.c rename to tests/graphics/graphics_test.c index ec4d60b2..6dbdd8e5 100644 --- a/tests/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -4,12 +4,6 @@ bool graphicsTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Graphics Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - // initialize the graphics system PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/mesh_test.c b/tests/graphics/mesh_test.c similarity index 99% rename from tests/mesh_test.c rename to tests/graphics/mesh_test.c index 7241591e..4ea289f4 100644 --- a/tests/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -48,12 +48,6 @@ static void PAL_CALL onGraphicsDebug( bool meshTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Mesh Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; diff --git a/tests/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c similarity index 99% rename from tests/ray_tracing_test.c rename to tests/graphics/ray_tracing_test.c index fef02e15..91299efc 100644 --- a/tests/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -44,12 +44,6 @@ static void PAL_CALL onGraphicsDebug( bool rayTracingTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Ray Tracing Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalAdapter* adapter = nullptr; PalDevice* device = nullptr; PalQueue* queue = nullptr; diff --git a/tests/texture_test.c b/tests/graphics/texture_test.c similarity index 99% rename from tests/texture_test.c rename to tests/graphics/texture_test.c index 1a15b6ff..81cb5548 100644 --- a/tests/texture_test.c +++ b/tests/graphics/texture_test.c @@ -78,12 +78,6 @@ static void PAL_CALL onGraphicsDebug( bool textureTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Texture Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; diff --git a/tests/triangle_test.c b/tests/graphics/triangle_test.c similarity index 99% rename from tests/triangle_test.c rename to tests/graphics/triangle_test.c index f17c54d1..4f818594 100644 --- a/tests/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -48,12 +48,6 @@ static void PAL_CALL onGraphicsDebug( bool triangleTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Triangle Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; diff --git a/tests/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c similarity index 98% rename from tests/multi_thread_opengl_test.c rename to tests/opengl/multi_thread_opengl_test.c index b6bf5787..d747edbd 100644 --- a/tests/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -175,13 +175,7 @@ static void* PAL_CALL rendererWorkder(void* arg) bool multiThreadOpenGlTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Multi Thread OpenGL Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalThread* eventDriverThread = nullptr; diff --git a/tests/opengl_context_test.c b/tests/opengl/opengl_context_test.c similarity index 98% rename from tests/opengl_context_test.c rename to tests/opengl/opengl_context_test.c index 75dd067b..cd9b7cab 100644 --- a/tests/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -16,13 +16,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(Uint32 mask); // use GL typedefs i bool openglContextTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Opengl Context Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalEventDriver* eventDriver = nullptr; PalEventDriverCreateInfo eventDriverCreateInfo = {0}; diff --git a/tests/opengl_fbconfig_test.c b/tests/opengl/opengl_fbconfig_test.c similarity index 95% rename from tests/opengl_fbconfig_test.c rename to tests/opengl/opengl_fbconfig_test.c index 9a7b1ad9..c4f15ada 100644 --- a/tests/opengl_fbconfig_test.c +++ b/tests/opengl/opengl_fbconfig_test.c @@ -7,12 +7,6 @@ static const char* g_BoolsToSting[2] = {"False", "True"}; bool openglFBConfigTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Opengl FBConfig Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - // initialize the video system and create a window PalResult result = palInitVideo(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c similarity index 98% rename from tests/opengl_multi_context_test.c rename to tests/opengl/opengl_multi_context_test.c index 0e2156c1..2923922c 100644 --- a/tests/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -16,13 +16,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(Uint32 mask); // use GL typedefs i bool openglMultiContextTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Opengl Multi Context Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalEventDriver* eventDriver = nullptr; PalEventDriverCreateInfo eventDriverCreateInfo = {0}; diff --git a/tests/opengl_test.c b/tests/opengl/opengl_test.c similarity index 92% rename from tests/opengl_test.c rename to tests/opengl/opengl_test.c index 38351642..d0e70e14 100644 --- a/tests/opengl_test.c +++ b/tests/opengl/opengl_test.c @@ -5,12 +5,6 @@ bool openglTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Opengl Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - // initialize the video system and create a window PalResult result = palInitVideo(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/shaders/closest_hit.spv b/tests/shaders/closest_hit.spv deleted file mode 100644 index 3d28d92ecc41b7da990f89103fe9f8720a004094..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmY*V%}T>y5S-?(wW*b0(QCw`5R6mQ|ffE3z9(q4M159hJZ;B$Bp zoJlR%{a9vacXqPGwl3>%Yw*#)F?JEa!X^Nk@GyCtrsL65TAFpbD$VOGf1}nzjnX)o zB++t}Mcv+wHruc(1IxG%+8XPfgK8v`e$e|`q(&5YVfjwMK{_nZeY4_c% z=Y`1z#k?pND0Jdm;0jE_I@~E(^&U#4p~Z{@ov!w|ZCP(l(ijJ@+g2 l@o>$l_F7D7)ED-7vF^~#3VrLF9hZ1dCV%bx@UPu6e*tQfBvSwY diff --git a/tests/shaders/compute.spv b/tests/shaders/compute.spv deleted file mode 100644 index 4597b5d42cbdeee583f351d8dcb629aeca437b7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1668 zcmZ9L+fGwa5QZ0&B8q~@$rHE%&nTh-qR1(lR1y+Rd;n8{&?dDdwpG0I!iVw7hwz<@ zhs4D1Tir{Ei~P*Yzvi@ORtw!T$3o}|{h=>xhRzuZ-7o>JH_FoX%k8;lYj7ED4B}Hn_JB9#YTb)|a2j52DC*i)2}Bmi9>Q0QA|6NMirn>acL<7T=Gm{kD%BdV z%eAfgyT(qrRc+L_p2qt^%=sbez2PkKMY~yf(x^9E<$4Pe>7RN^dG)uaDd0)= zbjOVL2D*Ko1H*J^y(#)Nr}`*4td{{#hRs8YkRQiBj#M|s`xD46Ait8^){vXU*7qdv z=zj|7oqW3YJ;{yG#RzhY>|@9bSaUpbomoxhGc{g#XI{U_9-O^>XuE4Uzv}`r1J<#w zw)^rJKY>i&mhP{>=|4d~?!sD==+0i-xFw{sle4b2dyq?c9_F_GkI=1?`d-cNw9`D+ z(R~BA_(FX*fShnvOU%Ihz8#Od_yOZ@)*jrMzd2>H&3DxH&1-KGc z;5#+a+yBL#{4|hr7V0VQWpw*VwXdRE+x;e=Yv}T+_H}gQJ ve)8_cy~`#4Wpp`bjW=hlh}h$0YDO*O%!350mpG%$fl+9~M_jq%E-@CAGT zjW1y0JDGT6;{Q!&H4W}&W$*R>>$KNi)70=%&Si$&m>Y51uD2%Lu=_gg+^EaCz1l(j z&4>MZ%L`BH;Ys7j>&Q0ihGbgZ-PvbaU zW2Jo-L_)HL@h z(d%kb(}K<{blx2PyWS0bE77lNpHdaXT#R3|SJRAavcd`yRzZ4BI|5!z_zOCd({yqW zYgVzwwHG9FvY610K4_bl&b{V^GKcVB3(7!0%m)s^Zb~~Gd8tX)iTeP)k?6b?{ooF> z+6xl$P$T-BgoRGdE3xK&nodtxrt>X0_j$Xd+f&nZ2|ft6@YFJ|oxIpsF5bX$lk28L zs~@W%1#B>u`Q8#vFD>sRr(e#$3_kRqb%#)Qiq+gV76o zpG#OJY51;7z?dzI^Fn8Q;LUF%!OZWKbnL9|LNeN^k#C0o zJa*IhzeC@WH5~838JwJ($z3k$3~%}+ow4~gopNyKJGv*ccSFMLGv5gDz?fIFS=1RD z=F)7y3KFxqtur>vpV@#dNzCS+&e$+_W&_6D?dayzQ<5-C#-kS{#+MVGTBsGBc`|-E s;i&^2otZNJX~I(jJUVj)&-=cVFdLR1omnt`GvO^iI&c10U+lW%A3#rtw*UYD diff --git a/tests/shaders/miss.spv b/tests/shaders/miss.spv deleted file mode 100644 index ead00b0a2c55011f0f31a9c344ccd577ab437df1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 356 zcmY*V&1%A65FGPonn;VZ=+)ArC3t8{LGU8QLURyP#9R1KkU(lm>cvx^&YRERb9fP) zi7mAIG3?In>|}{;-PPgN5W+_T=V-#hcM}NUAsJ88x7SHpnoYVc%{*Hzsr68!bQC9X z^tE0@505=kw_a)S1O~S%=(b-t#W?`#)UX>UGJb4G6_OnRFqc c-Y=ebp}wmd74kl?<1!D(mHQaV(|X zX*jJc-K*c4zg_P(9@l%_#%gP09pB+Jglo07Qk&Z9HK)#HaMN!S{*lPJ??R{@wnY-G_Q5qoh}f*l-G+u7avC);@jw9#JDQCUC;BM zA6R=5?9kt}&F2Ul`SufO>_m2p{X7SWF@FVd90re|<@Bw9ccJAJ=Xax>w|ks-KSPN8 zA)xZc*a^k#?~il zy@+kReE46&b_BlMhrgbpGW|Y9^iiA(zZvY5o=&@`Ygm7Ar~12Ru{|Xhd9H&akNWw6 zLb`!AzKV8;jThSs4%hRHK1cq|v3sf^o$+UvqMikCN>Apz(?zTbGK4rUUP2t6%QD&= z{-;Md9s5k~7`8nowyry9?^4dX#P*n+^WWySu@~q`d&Zm&&-`zgGTK=C$alc=5A6RQ z*uLPnUf>G$#18C#9sb^>|MnpE-xgnCJ^S%x#99|&<@e^Cyu3wGw1gp=Q-UVGv#L@r|9#@<=)J8<$5^DegBFVta<_Ym{Q zKg+rIbN&SS=bSr*E$=^Tz23K6tUZOj^E^L|@)2_uTQ2H7 zhixADsP{a!{9wHo!17VA{U~Sc_M&fvcj_5jMchx|X>9$M@^@txTOauuWHjeL!?wSC zFZw=3a-<~hI&=A)d2e9fM0_j6zCX7RYYF^CW~cOEY&7%rTzpIHqYz_ih`tMmYZz}Y z-b3u8$oD0-^UL`i-p7`61osuTocjpw>zpf~m-ri((cd7(>+k#wGRvyID-V#ni0_s) NxOX{Y{vq>4#u4P^nIh!8@TVz zIdkTod*>yE%VG#yp&Uw~9agIz3NQg~C+5NMY1o@D#=YyCD;1THM4_5$D28paF&({q zc(6+}i5fb24A>=94dI(hDQsS!!gwe9TJ*E`Y{nKQ3H#*5WEu4}_Vdy7b9I)+`lIK` zvY%zMG30=X);L$d5_`WJ(LcV(VQYHs9O}jSb7$DpYtX&@cjF`>?wjm);5tN$`_3tL zwhrGC*_V>PUt@ceYt!u>S-t-GwZYaXuMgB(L+o6xQ@W^-)m0pb2)ChIA$huGQWZh3um&g8Q9ADEQ<0Bg+y!k)zX*9pB}Q0dzs)X1yRr$y-T VipKXjA=Jq~;^I5W{nEu9@dwg$9{~UW diff --git a/tests/shaders/texture_vert.spv b/tests/shaders/texture_vert.spv deleted file mode 100644 index 75218a43c15ef0e8a1209a73a6d43b8657426958..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 980 zcmYk4PfG$(6vbcasAXklYJbd(mVvaW2%;hkY~jK%+J@v11Jf8fg|zCk^{Ltfo!`tn z^$pki&UyEpd*+Vm)KSiuB~vhYb710CGAS`eTsF#`Zok`_gu~Y9*$EZvCLI-0Q#8xb zKBM2affoSQ6q|~=VqcNglT!ZC1;=Fc%xfL>CpkDkwJQ*>g6Uc%e56 z#O9)UdPlq$gnjSJrOuwwOJ{B0d%yE0;UIW%XJIj&~a@a2@IJF7&^b4tti(mWyZ0)aP~Fp$>nxjy)Xn>gX3=4FwB~r$vk( zFuG;AK=V+F=&-M9msM^mYPzovA7S(>!g=MUf_0o=zAk!o;T2`>!!@+So7LcqXsT{i z*?PZBF!P0@&w5lB>(U2YRIu>1p-dk;!YR$TTEd~(lM}pbE2!lR h|9HNY27Y%H%#68Qt1Fm#+mr8%N6zg3;7^V(6#wHuKVSd= diff --git a/tests/shaders/triangle_frag.spv b/tests/shaders/triangle_frag.spv deleted file mode 100644 index 1f9fead55f8bdc6a1f66e827ceee8444b745d48d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmYk1%MQU%5QayqE$SKxJE_<=7KlXHSaj2!Cy>}k&;;>-p2|kz|Jo8KnKScWX678% znFMAP3$11?D^AZGF(%H>bCT}T_;x?Uv-uQ9+uYoUr(=Otm5KBIctNNuLPb|Tcr8%n zYO2{&O`h0)KbW4!Halh4LZ^RU;-u6^;y7URFYaqHv&Z=s%jHkj4!xnQr~Y&>JK+}k0sEN6q30#WQ(lW@W>bNGBbB+}x4M^#4-efFJOBUy diff --git a/tests/shaders/triangle_vert.spv b/tests/shaders/triangle_vert.spv deleted file mode 100644 index 15b7f9086461b6f401fe12f2e70c4619db37209b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1140 zcmYk4T~E|d5QdMtln+5Z1q1;LD4LKEFVvVAB?OZ7f(r}@w`L;^X;OB{ZZ*am{B8a! zZ%lZewrBA))0uhaJ#*eOZM(HQ5yFEo9VWx8P_Kp10tsN_mG7LMpB@a$%Y!#>U(1*c z?TRR8E=*PN81L(D-ZOcGEn?5G9jwjM!vA4I62^G$xd~@XlV25I&$7WqHYl^7q@Xo! zY^^`c%e>zMov8SpUEz7JJkNh+@?y=is2vyi%}G8iyS;DOsHSpj--}{YOVFogSHh$A z?&!o?vv>J%+%NirI`>}PChxG{J9zGA_8YsRk61lZr+v?Jk34lnp0Sv7>hM<27UnWn z%m2Ar%R`&I3?LH-c$ez7egwZ$IR zv=rV9K5GBa=P;ML=JB4RX8SGR)gW#^b7vtIbuJORtnD>mly$18nQO8SS_sh4g4$pL^*8VZ6_t+iDB0|0Z diff --git a/tests/system_test.c b/tests/system/system_test.c similarity index 95% rename from tests/system_test.c rename to tests/system/system_test.c index ecfe7215..0580d971 100644 --- a/tests/system_test.c +++ b/tests/system/system_test.c @@ -63,12 +63,6 @@ static inline const char* cpuArchToString(PalCpuArch arch) bool systemTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "System Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalCPUInfo cpuInfo; PalPlatformInfo platformInfo; diff --git a/tests/tests.c b/tests/tests.c index 41cce2d8..04c0e382 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -3,14 +3,20 @@ #define MAX_TESTS 64 // will change +typedef struct { + TestFn func; + const char* name; +} TestEntry; + static Uint32 s_Count = 0; -static TestFn s_Test[MAX_TESTS]; +static TestEntry s_Test[MAX_TESTS]; static const char* s_FailedString = "FAILED"; static const char* s_PassedString = "PASSED"; -void registerTest(TestFn func) +void registerTest(TestFn func, const char* name) { - s_Test[s_Count++] = func; + TestEntry entry = { func, name }; + s_Test[s_Count++] = entry; } void runTests() @@ -18,8 +24,13 @@ void runTests() bool status = false; const char* statusString = nullptr; for (Int32 i = 0; i < s_Count; i++) { - status = s_Test[i](); + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, s_Test[i].name); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + status = s_Test[i].func(); if (status) { statusString = s_PassedString; } else { diff --git a/tests/tests.h b/tests/tests.h index e468b74e..551333f9 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -6,7 +6,7 @@ typedef bool (*TestFn)(); -void registerTest(TestFn func); +void registerTest(TestFn func, const char* name); void runTests(); // core tests diff --git a/tests/tests.lua b/tests/tests.lua index d5627338..c84fe701 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -9,76 +9,83 @@ project "tests" files { "tests_main.c", "tests.c", - "logger_test.c", - "time_test.c", - "user_event_test.c", - "event_test.c" + + -- core + "core/logger_test.c", + "core/time_test.c", + + -- event + "event/user_event_test.c", + "event/event_test.c" } if (PAL_BUILD_SYSTEM) then files { - "system_test.c" + "system/system_test.c" } end if (PAL_BUILD_THREAD) then files { - "thread_test.c", - "tls_test.c", - "mutex_test.c", - "condvar_test.c" + "thread/thread_test.c", + "thread/tls_test.c", + "thread/mutex_test.c", + "thread/condvar_test.c" } end if (PAL_BUILD_VIDEO) then files { - "video_test.c", - "monitor_test.c", - "monitor_mode_test.c", - "window_test.c", - "icon_test.c", - "cursor_test.c", - "input_window_test.c", - "system_cursor_test.c", - "attach_window_test.c", - "char_event_test.c", - "native_integration_test.c", - "native_instance_test.c", - "custom_decoration_test.c" + "video/video_test.c", + "video/monitor_test.c", + "video/monitor_mode_test.c", + "video/window_test.c", + "video/icon_test.c", + "video/cursor_test.c", + "video/input_window_test.c", + "video/system_cursor_test.c", + "video/attach_window_test.c", + "video/char_event_test.c", + "video/native_integration_test.c", + "video/native_instance_test.c", + "video/custom_decoration_test.c" } end if (PAL_BUILD_OPENGL and PAL_BUILD_VIDEO) then files { - "opengl_test.c", - "opengl_fbconfig_test.c", - "opengl_context_test.c", - "opengl_multi_context_test.c" + "opengl/opengl_test.c", + "opengl/opengl_fbconfig_test.c", + "opengl/opengl_context_test.c", + "opengl/opengl_multi_context_test.c" } end if (PAL_BUILD_OPENGL and PAL_BUILD_VIDEO and PAL_BUILD_THREAD) then files { - "multi_thread_opengl_test.c" + "opengl/multi_thread_opengl_test.c" } end if (PAL_BUILD_GRAPHICS) then files { - "graphics_test.c", - "compute_test.c", - "ray_tracing_test.c" + "graphics/graphics_test.c", + "graphics/compute_test.c", + "graphics/ray_tracing_test.c" } end if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { - "clear_color_test.c", - "triangle_test.c", - "mesh_test.c", - "texture_test.c" + "graphics/clear_color_test.c", + "graphics/triangle_test.c", + "graphics/mesh_test.c", + "graphics/texture_test.c" } end - includedirs { "%{wks.location}/include" } + includedirs { + "%{wks.location}/include", + "%{wks.location}/tests" + } links { "PAL" } diff --git a/tests/tests_main.c b/tests/tests_main.c index 88a7373f..b0359452 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -2,8 +2,6 @@ #include "pal/pal_config.h" // for systems reflection #include "tests.h" -#include "pal/pal_graphics.h" - // clang-format off int main(int argc, char** argv) { @@ -11,62 +9,64 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - // registerTest(loggerTest); - // registerTest(timeTest); - // registerTest(userEventTest); - // registerTest(eventTest); + // registerTest(loggerTest, "Logger Test"); + // registerTest(timeTest, "Time Test"); + + // event + // registerTest(eventTest, "Event test"); + // registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM - // registerTest(systemTest); + // registerTest(systemTest, "System Test"); #endif // PAL_HAS_SYSTEM #if PAL_HAS_THREAD - // registerTest(threadTest); - // registerTest(tlsTest); - // registerTest(mutexTest); - // registerTest(condvarTest); + // registerTest(threadTest, "Thread Test"); + // registerTest(tlsTest, "TLS Test"); + // registerTest(mutexTest, "Mutex Test"); + // registerTest(condvarTest, "Condvar Test"); #endif // PAL_HAS_THREAD #if PAL_HAS_VIDEO - // registerTest(videoTest); - // registerTest(monitorTest); - // registerTest(monitorModeTest); - // registerTest(windowTest); - // registerTest(iconTest); - // registerTest(cursorTest); - // registerTest(inputWindowTest); - // registerTest(systemCursorTest); - // registerTest(attachWindowTest); - // registerTest(charEventTest); - // registerTest(nativeIntegrationTest); - // registerTest(nativeInstanceTest); - // registerTest(customDecorationTest); + // registerTest(videoTest, "Video Test"); + // registerTest(monitorTest, "Monitor Test"); + // registerTest(monitorModeTest, "Monitor Mode Test"); + // registerTest(windowTest, "Window Test"); + // registerTest(iconTest, "Icon Test"); + // registerTest(cursorTest, "Cursor Test"); + // registerTest(inputWindowTest, "Input Window Test"); + // registerTest(systemCursorTest, "System Cursor Test"); + // registerTest(attachWindowTest, "Attach Window Test"); + // registerTest(charEventTest, "Char Event Test"); + // registerTest(nativeIntegrationTest, "Native Integration Test"); + // registerTest(nativeInstanceTest, "Native Instance Test"); + // registerTest(customDecorationTest, "Custom Decoration Test"); #endif // PAL_HAS_VIDEO // This test can run without video system so long as your have a valid // window #if PAL_HAS_OPENGL && PAL_HAS_VIDEO - // registerTest(openglTest); - // registerTest(openglFBConfigTest); - // registerTest(openglContextTest); - // registerTest(openglMultiContextTest); + // registerTest(openglTest, "Opengl Test"); + // registerTest(openglFBConfigTest, "Opengl FBConfig Test"); + // registerTest(openglContextTest, "Context Test"); + // registerTest(openglMultiContextTest, "Opengl Multi Context Test"); #endif // PAL_HAS_OPENGL #if PAL_HAS_OPENGL && PAL_HAS_VIDEO && PAL_HAS_THREAD - // registerTest(multiThreadOpenGlTest); + // registerTest(multiThreadOpenGlTest, "Multi Thread Opengl Test"); #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest); - registerTest(computeTest); - // registerTest(rayTracingTest); + // registerTest(graphicsTest, "Graphics Test"); + registerTest(computeTest, "Compute Test"); + // registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest(clearColorTest); - // registerTest(triangleTest); - // registerTest(meshTest); - // registerTest(textureTest); + // registerTest(clearColorTest, "Clear Color Test"); + // registerTest(triangleTest, "Triangle Test"); + // registerTest(meshTest, "Mesh Test"); + // registerTest(textureTest, "Texture Test"); #endif // runTests(); diff --git a/tests/condvar_test.c b/tests/thread/condvar_test.c similarity index 93% rename from tests/condvar_test.c rename to tests/thread/condvar_test.c index cc79c7cd..dfbf3300 100644 --- a/tests/condvar_test.c +++ b/tests/thread/condvar_test.c @@ -30,12 +30,6 @@ static void* PAL_CALL worker(void* arg) bool condvarTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Condvar Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalThread* threads[THREAD_COUNT]; diff --git a/tests/mutex_test.c b/tests/thread/mutex_test.c similarity index 90% rename from tests/mutex_test.c rename to tests/thread/mutex_test.c index b3c8114a..3a158697 100644 --- a/tests/mutex_test.c +++ b/tests/thread/mutex_test.c @@ -27,12 +27,6 @@ static void* PAL_CALL worker(void* arg) bool mutexTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Mutex Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalThread* threads[THREAD_COUNT]; PalMutex* mutex = nullptr; diff --git a/tests/thread_test.c b/tests/thread/thread_test.c similarity index 88% rename from tests/thread_test.c rename to tests/thread/thread_test.c index f51b64a8..84d6db64 100644 --- a/tests/thread_test.c +++ b/tests/thread/thread_test.c @@ -18,12 +18,6 @@ static void* PAL_CALL worker(void* arg) bool threadTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Thread Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalResult result; PalThread* threads[THREAD_COUNT]; diff --git a/tests/tls_test.c b/tests/thread/tls_test.c similarity index 91% rename from tests/tls_test.c rename to tests/thread/tls_test.c index bfe4ab73..53498c15 100644 --- a/tests/tls_test.c +++ b/tests/thread/tls_test.c @@ -51,12 +51,6 @@ static void* PAL_CALL worker(void* arg) bool tlsTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "TLS Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalThread* thread = nullptr; // create tls diff --git a/tests/attach_window_test.c b/tests/video/attach_window_test.c similarity index 97% rename from tests/attach_window_test.c rename to tests/video/attach_window_test.c index 8ed3fdc1..d4b48a7f 100644 --- a/tests/attach_window_test.c +++ b/tests/video/attach_window_test.c @@ -207,14 +207,9 @@ static void destroyPlatformWindow(void* windowHandle) bool attachWindowTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Attach Window Test"); palLog(nullptr, "Press A to attach and D to detach window"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + PalResult result; // event driver diff --git a/tests/char_event_test.c b/tests/video/char_event_test.c similarity index 94% rename from tests/char_event_test.c rename to tests/video/char_event_test.c index 57897a45..e99da998 100644 --- a/tests/char_event_test.c +++ b/tests/video/char_event_test.c @@ -4,13 +4,8 @@ bool charEventTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Character Event Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + PalResult result; PalWindow* window = nullptr; PalWindowCreateInfo createInfo = {0}; diff --git a/tests/cursor_test.c b/tests/video/cursor_test.c similarity index 95% rename from tests/cursor_test.c rename to tests/video/cursor_test.c index 8a832166..0f157d0d 100644 --- a/tests/cursor_test.c +++ b/tests/video/cursor_test.c @@ -4,13 +4,8 @@ bool cursorTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Cursor Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + PalResult result; PalWindow* window = nullptr; PalCursor* cursor = nullptr; diff --git a/tests/custom_decoration_test.c b/tests/video/custom_decoration_test.c similarity index 99% rename from tests/custom_decoration_test.c rename to tests/video/custom_decoration_test.c index ae90c316..00d3c27a 100644 --- a/tests/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -835,16 +835,9 @@ static void PAL_CALL onEvent( bool customDecorationTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Custom Decoration Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "This only implements close and window movement for simplicity"); - - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + openDisplayWayland(); if (!s_Display) { // not on wayland diff --git a/tests/icon_test.c b/tests/video/icon_test.c similarity index 95% rename from tests/icon_test.c rename to tests/video/icon_test.c index e328b770..fba46c6f 100644 --- a/tests/icon_test.c +++ b/tests/video/icon_test.c @@ -4,13 +4,8 @@ bool iconTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Icon Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + PalResult result; PalWindow* window = nullptr; PalIcon* icon = nullptr; diff --git a/tests/input_window_test.c b/tests/video/input_window_test.c similarity index 98% rename from tests/input_window_test.c rename to tests/video/input_window_test.c index 968ee504..164427a3 100644 --- a/tests/input_window_test.c +++ b/tests/video/input_window_test.c @@ -399,13 +399,8 @@ static void PAL_CALL onEvent( bool inputWindowTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Input Window Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + PalResult result; PalWindow* window = nullptr; PalWindowCreateInfo createInfo = {0}; diff --git a/tests/monitor_mode_test.c b/tests/video/monitor_mode_test.c similarity index 95% rename from tests/monitor_mode_test.c rename to tests/video/monitor_mode_test.c index bca2aad4..18e9db48 100644 --- a/tests/monitor_mode_test.c +++ b/tests/video/monitor_mode_test.c @@ -4,12 +4,6 @@ bool monitorModeTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Monitor Mode Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalMonitorInfo info; Int32 count = 0; Int32 modeCount = 0; diff --git a/tests/monitor_test.c b/tests/video/monitor_test.c similarity index 93% rename from tests/monitor_test.c rename to tests/video/monitor_test.c index cba992f9..33c11978 100644 --- a/tests/monitor_test.c +++ b/tests/video/monitor_test.c @@ -4,12 +4,6 @@ bool monitorTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Monitor Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - PalMonitorInfo info; Int32 count = 0; diff --git a/tests/native_instance_test.c b/tests/video/native_instance_test.c similarity index 97% rename from tests/native_instance_test.c rename to tests/video/native_instance_test.c index 960d5002..6819b0b9 100644 --- a/tests/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -306,13 +306,8 @@ void closeInstance(void* instance) bool nativeInstanceTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Native Instance Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + PalResult result; // event driver diff --git a/tests/native_integration_test.c b/tests/video/native_integration_test.c similarity index 97% rename from tests/native_integration_test.c rename to tests/video/native_integration_test.c index 66629edf..89777ce4 100644 --- a/tests/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -314,13 +314,8 @@ void getWindowTitle(PalWindowHandleInfoEx* windowInfo) bool nativeIntegrationTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Native Integration Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + PalResult result; // event driver diff --git a/tests/system_cursor_test.c b/tests/video/system_cursor_test.c similarity index 94% rename from tests/system_cursor_test.c rename to tests/video/system_cursor_test.c index 0ad37025..a492cbe8 100644 --- a/tests/system_cursor_test.c +++ b/tests/video/system_cursor_test.c @@ -4,13 +4,8 @@ bool systemCursorTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "System Cursor Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + PalResult result; PalWindow* window = nullptr; PalCursor* cursor = nullptr; diff --git a/tests/video_test.c b/tests/video/video_test.c similarity index 96% rename from tests/video_test.c rename to tests/video/video_test.c index 5868f9b5..916da27f 100644 --- a/tests/video_test.c +++ b/tests/video/video_test.c @@ -4,12 +4,8 @@ bool videoTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Video Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + palLog(nullptr, "Press Escape or click close button to close Test"); + PalResult result; // initialize the video system diff --git a/tests/window_test.c b/tests/video/window_test.c similarity index 98% rename from tests/window_test.c rename to tests/video/window_test.c index 8848d7e5..3b65142b 100644 --- a/tests/window_test.c +++ b/tests/video/window_test.c @@ -144,13 +144,8 @@ static void PAL_CALL onEvent( bool windowTest() { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Window Test"); palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - + PalResult result; PalWindow* window = nullptr; PalWindowCreateInfo createInfo = {0}; From 32effe210cc7d3d8ae7cceaf7398287a65e1b915 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 22 Apr 2026 19:52:11 +0000 Subject: [PATCH 172/372] add compute shader bytecode and source spirv --- include/pal/pal_config.h | 4 +-- tests/graphics/compute_test.c | 35 ++------------------- tests/graphics/mesh_test.c | 29 ----------------- tests/graphics/ray_tracing_test.c | 29 ----------------- tests/graphics/shaders/compute_shader.glsl | 27 ++++++++++++++++ tests/graphics/shaders/compute_shader.spv | Bin 0 -> 1704 bytes tests/graphics/texture_test.c | 29 ----------------- tests/graphics/triangle_test.c | 29 ----------------- tests/tests.h | 29 +++++++++++++++++ 9 files changed, 61 insertions(+), 150 deletions(-) create mode 100644 tests/graphics/shaders/compute_shader.glsl create mode 100644 tests/graphics/shaders/compute_shader.spv diff --git a/include/pal/pal_config.h b/include/pal/pal_config.h index e9f4450c..b066298b 100644 --- a/include/pal/pal_config.h +++ b/include/pal/pal_config.h @@ -3,7 +3,7 @@ // Must not be edited manually #define PAL_HAS_SYSTEM 1 -#define PAL_HAS_THREAD 1 +#define PAL_HAS_THREAD 0 #define PAL_HAS_VIDEO 1 -#define PAL_HAS_OPENGL 1 +#define PAL_HAS_OPENGL 0 #define PAL_HAS_GRAPHICS 1 diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index b3cb00a7..d1166a09 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -2,8 +2,6 @@ #include "pal/pal_graphics.h" #include "tests.h" -#include - #define BUFFER_SIZE 400 // layout must match shader @@ -14,33 +12,6 @@ typedef struct { float color[4]; } PushConstant; -static bool readFile( - const char* filename, - void* buffer, - Uint64* size) -{ - FILE* file = fopen(filename, "rb"); - if (!file) { - return false; - } - - fseek(file, 0, SEEK_END); - Uint64 tmpSize = ftell(file); - fseek(file, 0, SEEK_SET); - - if (buffer) { - tmpSize = *size; - size_t read = fread(buffer, 1, tmpSize, file); - if (read != tmpSize) { - return false; - } - } - - fclose(file); - *size = tmpSize; - return true; -} - static void PAL_CALL onGraphicsDebug( void* userData, PalDebugMessageSeverity severity, @@ -114,7 +85,7 @@ bool computeTest() PalAdapterFeatures adapterFeatures = 0; bool hasComputeQueue = false; for (Int32 i = 0; i < adapterCount; i++) { - adapter = adapters[i]; // TODO: use the correct i index + adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -196,7 +167,7 @@ bool computeTest() PalShaderCreateInfo shaderCreateInfo = {0}; const char* shaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - shaderPath = "shaders/compute.spv"; + shaderPath = "graphics/shaders/compute_shader.spv"; } if (!readFile(shaderPath, nullptr, &bytecodeSize)) { @@ -612,7 +583,7 @@ bool computeTest() } // write to a ppm output file - FILE* file = fopen("compute_output.ppm", "wb"); + FILE* file = fopen("graphics/compute_output.ppm", "wb"); fprintf(file, "P6\n%d %d\n255\n", BUFFER_SIZE, BUFFER_SIZE); float* pixels = (float*)ptr; for (int y = 0; y < BUFFER_SIZE; y++) { diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 4ea289f4..0c23e52d 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -4,39 +4,10 @@ #include "pal/pal_system.h" #include "tests.h" -#include - #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define MAX_FRAMES_IN_FLIGHT 2 -static bool readFile( - const char* filename, - void* buffer, - Uint64* size) -{ - FILE* file = fopen(filename, "rb"); - if (!file) { - return false; - } - - fseek(file, 0, SEEK_END); - Uint64 tmpSize = ftell(file); - fseek(file, 0, SEEK_SET); - - if (buffer) { - tmpSize = *size; - size_t read = fread(buffer, 1, tmpSize, file); - if (read != tmpSize) { - return false; - } - } - - fclose(file); - *size = tmpSize; - return true; -} - static void PAL_CALL onGraphicsDebug( void* userData, PalDebugMessageSeverity severity, diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 91299efc..db5dfc53 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -2,37 +2,8 @@ #include "pal/pal_graphics.h" #include "tests.h" -#include - #define BUFFER_SIZE 400 -static bool readFile( - const char* filename, - void* buffer, - Uint64* size) -{ - FILE* file = fopen(filename, "rb"); - if (!file) { - return false; - } - - fseek(file, 0, SEEK_END); - Uint64 tmpSize = ftell(file); - fseek(file, 0, SEEK_SET); - - if (buffer) { - tmpSize = *size; - size_t read = fread(buffer, 1, tmpSize, file); - if (read != tmpSize) { - return false; - } - } - - fclose(file); - *size = tmpSize; - return true; -} - static void PAL_CALL onGraphicsDebug( void* userData, PalDebugMessageSeverity severity, diff --git a/tests/graphics/shaders/compute_shader.glsl b/tests/graphics/shaders/compute_shader.glsl new file mode 100644 index 00000000..2b633bcb --- /dev/null +++ b/tests/graphics/shaders/compute_shader.glsl @@ -0,0 +1,27 @@ + +#version 450 + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 0) buffer OutputBuffer +{ + vec4 pixels[]; +} outBuffer; + +layout(push_constant) uniform PushConstants +{ + uint width; + uint height; + vec4 color; +} pc; + +void main() +{ + uvec2 id = gl_GlobalInvocationID.xy; + if (id.x >= pc.width || id.y >= pc.height) { + return; + } + + uint index = id.y * pc.width + id.x; + outBuffer.pixels[index] = pc.color; +} \ No newline at end of file diff --git a/tests/graphics/shaders/compute_shader.spv b/tests/graphics/shaders/compute_shader.spv new file mode 100644 index 0000000000000000000000000000000000000000..6b369782f113f376998164b299dda8f88aaa839a GIT binary patch literal 1704 zcmZ9L+fGwa5QaC@Rul!1lP9o%XB1HZQ3N@dR1y+Qd;n8vp*yK9vAfEp7e0(vK7{XN zJR~N5-|k-8u$sxt{B!#Etkqoa%*iO~iTb0yXe;WRp{N%m0xP7twDWpru9Z~g78d8t z7>IIdqB(=)z?nWK9YeZ$F<(Os7(c8XYBG1iy%IjFxW z)thh2_3g%o=3Y68n~m)k#J8o2}M`^4OJx1@glf!nh+1}r;T9Wn__Z-GY)jA~d{GQ-9 zyAn%$se9>1t{^35$wHgP))?JJQoJ)`6kFe2O=df_UNPp}akOvD-8)y`I~Vi2{N^Ge z59jM&LOj-AMw@HTz;7D6JO6s-Pr%Q+arPv(ccE{eWwg5zlZU?dA{OSZWWM>&usa+( z_0O}Iy#tR8Y~RFP*tyqDL`;$65<9WK`|)@eKSBKe%E3ExhWpib*Zv3eSMlw67V(~T zLB$6$Ox)9htkKy%#y03~pYw>A{Oslah7oad+^hc!@4|hDoQVwoN{(-060uJF3w^|{ zBH}-oJB9ZACMI4)#QaX}z{mfCeB4Wzbq!lQ@VS94AMZ2d+{6|Sd~RV|C;p2WVV3$k z8gA-BW!zj-_ZiT_@}IH5!+gE@7ebu7WVTLTg;xm*;Pa?zGZWKuWPAoP9gFguOq&F Q@7;R)uBW=QgJt&c7bi+&tpET3 literal 0 HcmV?d00001 diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 81cb5548..d3d60e0f 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -4,8 +4,6 @@ #include "pal/pal_system.h" #include "tests.h" -#include - #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define MAX_FRAMES_IN_FLIGHT 2 @@ -13,33 +11,6 @@ #define TEXTURE_HEIGHT 128 #define CHECKER_SIZE 16 -static bool readFile( - const char* filename, - void* buffer, - Uint64* size) -{ - FILE* file = fopen(filename, "rb"); - if (!file) { - return false; - } - - fseek(file, 0, SEEK_END); - Uint64 tmpSize = ftell(file); - fseek(file, 0, SEEK_SET); - - if (buffer) { - tmpSize = *size; - size_t read = fread(buffer, 1, tmpSize, file); - if (read != tmpSize) { - return false; - } - } - - fclose(file); - *size = tmpSize; - return true; -} - static void createCheckerboardTexture( Uint32* texture, Uint32 width, diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 4f818594..2ee8b7d3 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -4,39 +4,10 @@ #include "pal/pal_system.h" #include "tests.h" -#include - #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define MAX_FRAMES_IN_FLIGHT 2 -static bool readFile( - const char* filename, - void* buffer, - Uint64* size) -{ - FILE* file = fopen(filename, "rb"); - if (!file) { - return false; - } - - fseek(file, 0, SEEK_END); - Uint64 tmpSize = ftell(file); - fseek(file, 0, SEEK_SET); - - if (buffer) { - tmpSize = *size; - size_t read = fread(buffer, 1, tmpSize, file); - if (read != tmpSize) { - return false; - } - } - - fclose(file); - *size = tmpSize; - return true; -} - static void PAL_CALL onGraphicsDebug( void* userData, PalDebugMessageSeverity severity, diff --git a/tests/tests.h b/tests/tests.h index 551333f9..20890798 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -3,12 +3,41 @@ #define _TESTS_H #include "pal/pal_core.h" +#include + typedef bool (*TestFn)(); void registerTest(TestFn func, const char* name); void runTests(); +static bool readFile( + const char* filename, + void* buffer, + Uint64* size) +{ + FILE* file = fopen(filename, "rb"); + if (!file) { + return false; + } + + fseek(file, 0, SEEK_END); + Uint64 tmpSize = ftell(file); + fseek(file, 0, SEEK_SET); + + if (buffer) { + tmpSize = *size; + size_t read = fread(buffer, 1, tmpSize, file); + if (read != tmpSize) { + return false; + } + } + + fclose(file); + *size = tmpSize; + return true; +} + // core tests bool loggerTest(); bool timeTest(); From b307862d5836ca7beba9055f8b90e6c33409dd31 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 22 Apr 2026 20:37:08 +0000 Subject: [PATCH 173/372] add ray tracing shaders bytecode and source spirv --- src/graphics/pal_vulkan.c | 16 +++---- tests/graphics/ray_tracing_test.c | 8 ++-- .../graphics/shaders/closest_hit_shader.glsl | 10 ++++ tests/graphics/shaders/closest_hit_shader.spv | Bin 0 -> 372 bytes tests/graphics/shaders/miss_shader.glsl | 10 ++++ tests/graphics/shaders/miss_shader.spv | Bin 0 -> 356 bytes tests/graphics/shaders/raygen_shader.glsl | 44 ++++++++++++++++++ tests/graphics/shaders/raygen_shader.spv | Bin 0 -> 2620 bytes tests/tests_main.c | 4 +- 9 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 tests/graphics/shaders/closest_hit_shader.glsl create mode 100644 tests/graphics/shaders/closest_hit_shader.spv create mode 100644 tests/graphics/shaders/miss_shader.glsl create mode 100644 tests/graphics/shaders/miss_shader.spv create mode 100644 tests/graphics/shaders/raygen_shader.glsl create mode 100644 tests/graphics/shaders/raygen_shader.spv diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index ae8f53fa..33441d23 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2257,15 +2257,7 @@ static void fillVkBuildInfoVk( // fill vulkan geometry struct VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - tmp->flags = 0; - if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_OPAQUE) { - tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; - } - - if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT) { - tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; - } if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; @@ -2293,6 +2285,14 @@ static void fillVkBuildInfoVk( break; } else { + if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_OPAQUE) { + tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; + } + + if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT) { + tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; + } + if (maxPrimities) { maxPrimities[i] = info->geometries[i].primitiveCount; } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index db5dfc53..601e8fae 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -179,7 +179,7 @@ bool rayTracingTest() PalShaderCreateInfo shaderCreateInfo = {0}; const char* shaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - shaderPath = "shaders/raygen.spv"; + shaderPath = "graphics/shaders/raygen_shader.spv"; } if (!readFile(shaderPath, nullptr, &bytecodeSize)) { @@ -210,7 +210,7 @@ bool rayTracingTest() bytecodeSize = 0; bytecode = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - shaderPath = "shaders/miss.spv"; + shaderPath = "graphics/shaders/miss_shader.spv"; } if (!readFile(shaderPath, nullptr, &bytecodeSize)) { @@ -241,7 +241,7 @@ bool rayTracingTest() bytecodeSize = 0; bytecode = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - shaderPath = "shaders/closest_hit.spv"; + shaderPath = "graphics/shaders/closest_hit_shader.spv"; } if (!readFile(shaderPath, nullptr, &bytecodeSize)) { @@ -1029,7 +1029,7 @@ bool rayTracingTest() } // write to a ppm output file - FILE* file = fopen("ray_tracing_output.ppm", "wb"); + FILE* file = fopen("graphics/ray_tracing_output.ppm", "wb"); fprintf(file, "P6\n%d %d\n255\n", BUFFER_SIZE, BUFFER_SIZE); float* pixels = (float*)ptr; for (int y = 0; y < BUFFER_SIZE; y++) { diff --git a/tests/graphics/shaders/closest_hit_shader.glsl b/tests/graphics/shaders/closest_hit_shader.glsl new file mode 100644 index 00000000..626fb050 --- /dev/null +++ b/tests/graphics/shaders/closest_hit_shader.glsl @@ -0,0 +1,10 @@ + +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(location = 0) rayPayloadInEXT vec3 payloadColor; + +void main() +{ + payloadColor = vec3(0.0, 1.0, 0.0); +} \ No newline at end of file diff --git a/tests/graphics/shaders/closest_hit_shader.spv b/tests/graphics/shaders/closest_hit_shader.spv new file mode 100644 index 0000000000000000000000000000000000000000..2ee524ac28481cce7ff123a25392b46219e34994 GIT binary patch literal 372 zcmY*V!D_-#5F8VeSgkFh)T`oA5f8NpLOqBmm_yN0yoHB?2-ZmS;>mtokNpO}!;9cd zs-XK=W@mSHvc$G39^3>nNFj^=$ic!s2c+R*{P7hG2csY|yI>oc>0&jf)y5S;wSR4SpO*NDeT@L-Ej@FJyxIfxPQ7CsD=LQEv>rKdifH=n`h=%wIH ztf2cb?9T4&WQk*+2ktfZK*F`<2)`vyuEX%WW zxhm7E(WN%~a5@9cj;Q%K23*!}W>IT!KsbCh^Cv|vHM6XkzC8W2hsVj^J&!u=zMFN` znDVx%nwAs;I?3y-b46F5u=d$Yh*P=*%;LH%ArG0qc$fN&LUBPRU5`-j b7h_(i@9IW{ytnLl%r|86)6R~6>6-Wk9DyTJ literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/raygen_shader.glsl b/tests/graphics/shaders/raygen_shader.glsl new file mode 100644 index 00000000..4af8153e --- /dev/null +++ b/tests/graphics/shaders/raygen_shader.glsl @@ -0,0 +1,44 @@ + +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(set = 0, binding = 0) buffer OutputBuffer +{ + vec4 pixels[]; +} outBuffer; + +layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; +layout(location = 0) rayPayloadEXT vec3 payloadColor; + +void main() +{ + uvec2 pixel = gl_LaunchIDEXT.xy; + uvec2 size = gl_LaunchSizeEXT.xy; + payloadColor = vec3(0.0); + + vec2 uv = (vec2(pixel) + 0.5) / vec2(size); + vec2 ndcUv = uv * 2.0 - 1.0; + vec3 origin = vec3(0.0, 0.0, -3.0); + vec3 direction = normalize(vec3(ndcUv.x, ndcUv.y, 1.0)); + + traceRayEXT( + tlas, + gl_RayFlagsOpaqueEXT, + 0xFF, + 0, + 0, + 0, + origin, + 0.001, + direction, + 1000.0, + 0 + ); + + if (pixel.x >= size.x || pixel.y >= size.y) { + return; + } + + uint index = pixel.y * size.x + pixel.x; + outBuffer.pixels[index] = vec4(payloadColor, 1.0); +} \ No newline at end of file diff --git a/tests/graphics/shaders/raygen_shader.spv b/tests/graphics/shaders/raygen_shader.spv new file mode 100644 index 0000000000000000000000000000000000000000..4d24a2da959a30ad33e80765d34c6e92a06ba219 GIT binary patch literal 2620 zcmZ9MTXU0D6oz-xBt@uTX#r1QN>Nd2MFm6<+R|c*L>njw9xx3_TB4!pq^Sekh=Uhi z@jJZoH|UjK@C%&rXE+{a9DSZI-`3cjd1tNn-D|DAzJ17GW@0Gh2f~i9E!+;hF%mN2 z%aIVahkRHne^9x&aJkZ{-mP>y)mn3HmDqe3AhcLoDot&4>r=;$A2oAl7)%N{w~Oo_ z#zM&A->x>-oEQdAfW6=}sDnX%8SEpHveYe>D(A0X`QLIO$4q}6`D5g)H}5oB*c^G* zUTsxM)y=iqtqb$iP|wmw2pi3N4GerJS^wX-B_@){UJd(NuikC7tM$2dtKI4442EZL zHoxfAJA}VhuU&;E^(V3IPIJ{S%<+2_UT=09wQjTRN85wn+HF-gFbThgZLZZDcM_ft zH?fPG-Sy4xxy_Z8MzU_6NOec@on%|zJ!|&`7OC&I?*Kot-*Wd@{!_|be;g!dmiBWH z?l8WJ%>(m_oQLaXz(QXS6L5#|_Fz3n180yx%hb)K90}?^cW4{^fhg8pRfXwb+J)$69;fKO?G}EBEZxj=;^`2ON`h zVce5I?LTD0Q*dMBH$07R|LU>M0er@E&5w3lKGkMV;@uS z*n@M%xlc!vIKMd?UcXtXM7H?09?m;`5bVJu}kw<*FBH5Kl}E4ma*2(g8iIb6}t=$;NQf`&8uNO zb2a;wdl%K5|2*}Vu_w5@8LTxOgWz|R9M)X#oBtv95xM^rk$aZD`+k0?k9$^=TexpO z#`}%eQhtW@ytj`7dtD^TxSgq{?ic`P>D0cQi+TJNCvP+6?S`ufN6fQ-=d9s<_RdKb9`?zU>10$_V2py0M9diqi?C0>M>>k?pgK6T!5>8N1b`>yTCm4Z|PO- zB2fR0?|KjG_>(#H5>WFk>BqI+$G4xjpZ2o|)MHE;-+uaIF2U7fKbP^%Q~!fC;#%5Y zxykmo1ne&djJFSay^3|%t1(xAn!W1(#i{A5#h$L?Z|(a-H1!zs5&qVF{1{FBYr61T zKLO^c$GjW(*6!c`PvPqK)4U44x$52{|1;FQC)RBMwRmq<@Vy6@$REY70yRg}ZsDtW qN2AtEHUAUK?Bg=_Ghn{)&L0M|tm^-03)I0Jum^inGsk^A3H||(*S-M& literal 0 HcmV?d00001 diff --git a/tests/tests_main.c b/tests/tests_main.c index b0359452..a58159ad 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,8 +58,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(computeTest, "Compute Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From 725db57da301bef95b7c91cfd406f815e24f6652 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 23 Apr 2026 04:55:04 +0000 Subject: [PATCH 174/372] add triangle shaders bytecode and source spirv --- src/graphics/pal_d3d12.c | 2 +- src/graphics/pal_vulkan.c | 2 +- tests/graphics/shaders/triangle_frag_shader.glsl | 11 +++++++++++ tests/graphics/shaders/triangle_frag_shader.spv | Bin 0 -> 372 bytes tests/graphics/shaders/triangle_vert_shader.glsl | 13 +++++++++++++ tests/graphics/shaders/triangle_vert_shader.spv | Bin 0 -> 1140 bytes tests/graphics/triangle_test.c | 4 ++-- tests/tests_main.c | 4 ++-- 8 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 tests/graphics/shaders/triangle_frag_shader.glsl create mode 100644 tests/graphics/shaders/triangle_frag_shader.spv create mode 100644 tests/graphics/shaders/triangle_vert_shader.glsl create mode 100644 tests/graphics/shaders/triangle_vert_shader.spv diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index b3590308..aaea3851 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -6817,7 +6817,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( // Rasterizer rasterizerDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER; - rasterizerDesc->desc.FrontCounterClockwise = TRUE; + rasterizerDesc->desc.FrontCounterClockwise = FALSE; if (info->rasterizerState) { PalRasterizerState* state = info->rasterizerState; if (state->cullMode == PAL_CULL_MODE_NONE) { diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 33441d23..4acc24a4 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -8658,7 +8658,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( createInfo.pDynamicState = &dynamicState; // Rasterizer state - rasterizerState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizerState.frontFace = VK_FRONT_FACE_CLOCKWISE; if (info->rasterizerState) { PalRasterizerState* state = info->rasterizerState; if (state->cullMode == PAL_CULL_MODE_NONE) { diff --git a/tests/graphics/shaders/triangle_frag_shader.glsl b/tests/graphics/shaders/triangle_frag_shader.glsl new file mode 100644 index 00000000..384d9720 --- /dev/null +++ b/tests/graphics/shaders/triangle_frag_shader.glsl @@ -0,0 +1,11 @@ + +#version 450 + +layout(location = 0) in vec4 aColor; + +layout(location = 0) out vec4 color; + +void main() +{ + color = aColor; +} \ No newline at end of file diff --git a/tests/graphics/shaders/triangle_frag_shader.spv b/tests/graphics/shaders/triangle_frag_shader.spv new file mode 100644 index 0000000000000000000000000000000000000000..2faee3a9764b9c5565146fcb371fb4138aac027a GIT binary patch literal 372 zcmYk1y9&Zk5JWeLCeipr&`u)u!9qn4Z7kBH^9zDDf*Mf2(66!)oD&~-!`!_yJNt;| zjsx=@i!8LJy-(L%bM%bNFJqc*v*dc)C)3#kN6Wm@h^K9VRTRM~Kb%R_gh=SfhaL!? zK3DOsqN>z?Kb)FfaV##1aO(5TTS!0op)?Mh{FnFCnckyvik0ua-oCV07|72KaOTFk xLq+}qefi<+fJVNqs8xS?I5W}a+K_ql;!yLDQdL|@rDsFHzgCvM@TaO5!VAoI66^o~ literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/triangle_vert_shader.glsl b/tests/graphics/shaders/triangle_vert_shader.glsl new file mode 100644 index 00000000..55b9831a --- /dev/null +++ b/tests/graphics/shaders/triangle_vert_shader.glsl @@ -0,0 +1,13 @@ + +#version 450 + +layout(location = 0) in vec2 aPosition; +layout(location = 1) in vec3 aColor; + +layout(location = 0) out vec4 vColor; + +void main() +{ + gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); + vColor = vec4(aColor, 1.0); +} \ No newline at end of file diff --git a/tests/graphics/shaders/triangle_vert_shader.spv b/tests/graphics/shaders/triangle_vert_shader.spv new file mode 100644 index 0000000000000000000000000000000000000000..b98a577bd42c6c2154f51b8219e26e2f992998ad GIT binary patch literal 1140 zcmYk4U2D`(5Qa~8o88vcet-B;YihL>gyMyYASzN}z34@y;H@k+ltA1qyJ;!CslUx% z<&EI;Bsr@mOlIbt_sn_EB<eiG02A|cd!-g5%w5s^R)24*pP%-o`2kgGkWA_#kb>Z{52bw*%c{h zjT>7VP4Y4y4MDpV-?J+`AC@QibtW&?Jd4_4k)MCcC*@%HJ)724ZtbEdrnLlpYIY?& zY9CBbtTlU=%fnGI8rQk^8Z>#I{ocWIKeON16@A3&nTBen5p$0`bw$ir%sKUWt7jW? znXBdhTrKAIUqyvIcj#yz;|-z?KE*cK-^H8Tf1URnKE+(mo7}Hzzb*1xc==-6L~4sY ztZ6B{+xV#cZIe4!G0$13cy(XTF<-=7>RQ5kj+*Vaj8}uW{mh+(Sk$>n?2^BRw`LFP z`umtG<`1gu=Lh)@iPh#^>~HRD#nhAH?O`r|2XFrrlW*?q#a{E>)$L4O?)eRp;6L(K z+d8IxHNS&t?+r{mayE(OIP1u{ODulV?72rQc8qehZ(;Tk_rBiIe%{Cb!f)W5-=oT0 wzP(fYF6JG+z*o(!~g&Q literal 0 HcmV?d00001 diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 2ee8b7d3..9ec62d03 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -531,8 +531,8 @@ bool triangleTest() const char* vertexShaderPath = nullptr; const char* fragShaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - vertexShaderPath = "shaders/triangle_vert.spv"; - fragShaderPath = "shaders/triangle_frag.spv"; + vertexShaderPath = "graphics/shaders/triangle_vert_shader.spv"; + fragShaderPath = "graphics/shaders/triangle_frag_shader.spv"; } if (!readFile(vertexShaderPath, nullptr, &bytecodeSize)) { diff --git a/tests/tests_main.c b/tests/tests_main.c index a58159ad..3c2d0110 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,12 +59,12 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); - // registerTest(triangleTest, "Triangle Test"); + registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); #endif // From 5e6890a994bbff6e010f39838ee115f1c32b87e2 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 23 Apr 2026 05:11:50 +0000 Subject: [PATCH 175/372] add mesh shader bytecode and source spirv --- tests/graphics/mesh_test.c | 4 ++-- tests/graphics/shaders/mesh_shader.glsl | 27 ++++++++++++++++++++++++ tests/graphics/shaders/mesh_shader.spv | Bin 0 -> 1756 bytes tests/tests_main.c | 4 ++-- 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 tests/graphics/shaders/mesh_shader.glsl create mode 100644 tests/graphics/shaders/mesh_shader.spv diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 0c23e52d..98d82112 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -375,8 +375,8 @@ bool meshTest() const char* meshShaderPath = nullptr; const char* fragShaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - meshShaderPath = "shaders/mesh.spv"; - fragShaderPath = "shaders/triangle_frag.spv"; + meshShaderPath = "graphics/shaders/mesh_shader.spv"; + fragShaderPath = "graphics/shaders/triangle_frag_shader.spv"; } if (!readFile(meshShaderPath, nullptr, &bytecodeSize)) { diff --git a/tests/graphics/shaders/mesh_shader.glsl b/tests/graphics/shaders/mesh_shader.glsl new file mode 100644 index 00000000..a0fbe477 --- /dev/null +++ b/tests/graphics/shaders/mesh_shader.glsl @@ -0,0 +1,27 @@ + +#version 460 +#extension GL_EXT_mesh_shader : require + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; +layout(max_vertices = 4, max_primitives = 2) out; +layout(triangles) out; + +layout(location = 0) out vec4 vColors[]; + +void main() +{ + SetMeshOutputsEXT(4, 2); + gl_MeshVerticesEXT[0].gl_Position = vec4(-0.5, 0.5, 0.0, 1.0); + gl_MeshVerticesEXT[1].gl_Position = vec4( 0.5, 0.5, 0.0, 1.0); + gl_MeshVerticesEXT[2].gl_Position = vec4( 0.5,-0.5, 0.0, 1.0); + gl_MeshVerticesEXT[3].gl_Position = vec4(-0.5,-0.5, 0.0, 1.0); + + // colors + vColors[0] = vec4(1.0, 0.0, 0.0, 1.0); + vColors[1] = vec4(0.0, 1.0, 0.0, 1.0); + vColors[2] = vec4(0.0, 0.0, 1.0, 1.0); + vColors[3] = vec4(1.0, 0.0, 0.0, 1.0); + + gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); + gl_PrimitiveTriangleIndicesEXT[1] = uvec3(0, 2, 3); +} \ No newline at end of file diff --git a/tests/graphics/shaders/mesh_shader.spv b/tests/graphics/shaders/mesh_shader.spv new file mode 100644 index 0000000000000000000000000000000000000000..1aef01631fc058035295b825bd69d944d1b1bc89 GIT binary patch literal 1756 zcmZXU+fEZv6oz*xEm)L;oID^7;+a|z0Wl^Lf~Fd4(xilV*EDnjleAMaQ;G4)r|<=Q z0F5u;3-~%F-kA7*(^<^~H(A|#{r@`cwf2x7Ssio5oSSgt?x`EB88_m-&N)|dMc1ew zHebFwXmpu$%rxu|^U-pWr{F=k*8nO9@9+Q?>SAsjeUX(|9B`kF22>)HPm{nF{tRzzz z)G#lbqA*XwT1$22O>Wc2btZ@D=X564f?}1ldy++2kP98#CHb~66ZbV6I0U;% z?QrDrq)%z*Zs5;SomqfU^Ne;+Vl|>)l(49g8fFvC{WM)IVC|YdKhTHv3yJ=Dx2(BS zW*~m-RKJWZb-m*KNjb)&iKHa-&Ts5-?nu8@PRXYN9XMSvTc2X%!2pI zBJLj{1?}JF@<~65v8Q^N`(+95khg|Bmj@Vc#cY;z#)daxHekF7v$?J_HoOJ10pl&0 z%?+Kg@g!yg#v9mEh17FL!d#6H)kG>(nAO491-twa}o4@*6b|n7*<-m6t literal 0 HcmV?d00001 diff --git a/tests/tests_main.c b/tests/tests_main.c index 3c2d0110..b011e7e9 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -64,8 +64,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); - registerTest(triangleTest, "Triangle Test"); - // registerTest(meshTest, "Mesh Test"); + // registerTest(triangleTest, "Triangle Test"); + registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); #endif // From 488555450309d790c37a6b4b6118b2fd3a468694 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 23 Apr 2026 05:25:30 +0000 Subject: [PATCH 176/372] add texture shaders bytecode and source spirv --- tests/graphics/shaders/texture_frag_shader.glsl | 14 ++++++++++++++ tests/graphics/shaders/texture_frag_shader.spv | Bin 0 -> 684 bytes tests/graphics/shaders/texture_vert_shader.glsl | 13 +++++++++++++ tests/graphics/shaders/texture_vert_shader.spv | Bin 0 -> 1044 bytes tests/graphics/texture_test.c | 4 ++-- tests/tests_main.c | 4 ++-- 6 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 tests/graphics/shaders/texture_frag_shader.glsl create mode 100644 tests/graphics/shaders/texture_frag_shader.spv create mode 100644 tests/graphics/shaders/texture_vert_shader.glsl create mode 100644 tests/graphics/shaders/texture_vert_shader.spv diff --git a/tests/graphics/shaders/texture_frag_shader.glsl b/tests/graphics/shaders/texture_frag_shader.glsl new file mode 100644 index 00000000..457b1f86 --- /dev/null +++ b/tests/graphics/shaders/texture_frag_shader.glsl @@ -0,0 +1,14 @@ + +#version 450 + +layout(set = 0, binding = 0) uniform texture2D tex; +layout(set = 0, binding = 0) uniform sampler samp; + +layout(location = 0) in vec2 aTexCoord; + +layout(location = 0) out vec4 color; + +void main() +{ + color = texture(sampler2D(tex, samp), aTexCoord); +} \ No newline at end of file diff --git a/tests/graphics/shaders/texture_frag_shader.spv b/tests/graphics/shaders/texture_frag_shader.spv new file mode 100644 index 0000000000000000000000000000000000000000..f6aeea6cec9ae85dd4c21ae9277ce490eb7cfcd2 GIT binary patch literal 684 zcmYk3y-or_7)1xxEL?}$eH9*1h`BXM0o-;t)As=_{ zojc#pY*M@^hf*QbLM3#@jn2z2* zJ*W~p#2(R#n8fok`-EQ+{N{3sn!hLa?pyYe&A=3|c@~pp^qOxzntlQBH0B;XPnM5a zHXEZ2*7wgeu;kwFMfT6nbKIQyb9w&U{x|uWbZ+mxI7Nv27W)!fmuOSZ8RgE^<-Y>@ zTIzRe?u=?3rrieh7l{1YaC6kw2YSsRcP`fnUDQE+ji~s2RzA7&xK62f0Gh)-4?*iX zk9UtiYpPpA?(AweytO`Oa@qS2N($binsb-1C%N_a32VRLvTl>mqprs~ZNeI_czmB@ RLZA8rReUG4U%I#@{s5gk9qRx9 literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/texture_vert_shader.glsl b/tests/graphics/shaders/texture_vert_shader.glsl new file mode 100644 index 00000000..ac9a01d3 --- /dev/null +++ b/tests/graphics/shaders/texture_vert_shader.glsl @@ -0,0 +1,13 @@ + +#version 450 + +layout(location = 0) in vec2 aPosition; +layout(location = 1) in vec2 aTexCoord; + +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); + vTexCoord = aTexCoord; +} \ No newline at end of file diff --git a/tests/graphics/shaders/texture_vert_shader.spv b/tests/graphics/shaders/texture_vert_shader.spv new file mode 100644 index 0000000000000000000000000000000000000000..77d1b67794c35bbda578f3cf9595649dbbd94a9c GIT binary patch literal 1044 zcmYk4UrPc}5XG+AiXbYYz#e)Cie5u_~nRBn^vaN#2XH3ZyP0OTKFFJe+niwlv8_)qDjq@J~U&V9<+BS8&l2~ z_kJIYF9(BR&-QV)?iAP29L~c2Yt13YTyz}T;fRjo8#weijvS8r>gbKGZ8-+^6{j(J zz|5^m1v8tP$Q<%jWqCzkUf1^pMKJSgdKVRaIksmpzb^9{!gGrB!)+@=o0~xm_tiJA z=(L|$%>BZ#XEEtZ=duS}mSgBzQe+RBnO9Ln13dG<+y$J|SyhhFzoJNu8Ptgza?Ih) z1bv;;zoi^)oCUmNvD*jsE$8+(h1qeW-x;0UA;z2^F`nXu-e{@G(Tm1Yt7p~nuBUE$ zxLen=rX2p$ezUF|?p8|C+K@8`p7U`g=5ZeW2i!ULdL~t1`kBqScIBLbns4#1PIN5) E1K@H&od5s; literal 0 HcmV?d00001 diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index d3d60e0f..72e7c593 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -825,8 +825,8 @@ bool textureTest() const char* vertexShaderPath = nullptr; const char* fragShaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - vertexShaderPath = "shaders/texture_vert.spv"; - fragShaderPath = "shaders/texture_frag.spv"; + vertexShaderPath = "graphics/shaders/texture_vert_shader.spv"; + fragShaderPath = "graphics/shaders/texture_frag_shader.spv"; } if (!readFile(vertexShaderPath, nullptr, &bytecodeSize)) { diff --git a/tests/tests_main.c b/tests/tests_main.c index b011e7e9..f62e99aa 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -65,8 +65,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); - registerTest(meshTest, "Mesh Test"); - // registerTest(textureTest, "Texture Test"); + // registerTest(meshTest, "Mesh Test"); + registerTest(textureTest, "Texture Test"); #endif // runTests(); From c4d0502a86b6d351c4f219162a836c34770b88bb Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 23 Apr 2026 14:37:46 +0000 Subject: [PATCH 177/372] add debug message polling d3d12 --- include/pal/pal_graphics.h | 9 +- src/graphics/pal_d3d12.c | 927 ++++++++++++--------- src/graphics/pal_graphics.c | 18 +- src/graphics/pal_vulkan.c | 2 - tests/graphics/compute_test.c | 8 +- tests/graphics/shaders/compute_shader.dxil | Bin 0 -> 3416 bytes tests/graphics/shaders/compute_shader.hlsl | 22 + tests/tests_main.c | 4 +- 8 files changed, 574 insertions(+), 416 deletions(-) create mode 100644 tests/graphics/shaders/compute_shader.dxil create mode 100644 tests/graphics/shaders/compute_shader.hlsl diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 93d18950..d78c939f 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1548,8 +1548,6 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool RequiresShaderExportName; - bool RequiresShaderGroupExportName; Uint32 maxRecursionDepth; Uint32 maxHitAttributeSize; /**< Max memory per intersection attributes.*/ Uint32 maxInstanceCount; @@ -2499,7 +2497,7 @@ typedef struct { PalShaderStage stage; void* bytecode; Uint64 bytecodeSize; - const char* exportName; /**< Check PalRayTracingCapabilities::RequiresShaderExportName.*/ + const char* exportName; /**< Set to nullptr if shader does not have an export name.*/ } PalShaderCreateInfo; /** @@ -2633,7 +2631,7 @@ typedef struct { Uint32 closestHitShaderIndex; /**< Index of closest hit shader from shader array.*/ Uint32 generalShaderIndex; /**< Index of general hit shader from shader array.*/ Uint32 intersectionShaderIndex; /**< Index of intersection hit shader from shader array.*/ - const char* exportName; /**< Check PalRayTracingCapabilities::RequiresShaderGroupExportName.*/ + const char* exportName; /**< Set to nullptr if shader group does not have an export name.*/ } PalRayTracingShaderGroupCreateInfo; /** @@ -5039,6 +5037,9 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. + * + * @note All shader stages must use `main` as the entry point. Pal does not support custom + * entry points. * * @since 1.4 * @ingroup pal_graphics diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index aaea3851..8886a078 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -49,6 +49,7 @@ freely, subject to the following restrictions: #define MAX_RTV 1024 #define MAX_DSV 512 #define MAX_SCRATCH_BUFFER_SIZE 65536 * sizeof(wchar_t) +#define MAX_MESSAGE_SIZE 4096 #define GRAPHICS_PIPELINE 1220 #define COMPUTE_PIPELINE 1221 @@ -81,7 +82,7 @@ const IID IID_StateObjectProps = {0xde5fa827, 0x9bf9, 0x4f26, 0x89,0xff, 0xd7,0x typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, - REFIID, + REFIID, void**); typedef HRESULT (__stdcall *PFN_D3D12SerializeVersionedRootSignature)( @@ -106,17 +107,17 @@ typedef struct { HMODULE dxgi; Adapter* adapters; IDXGIFactory6* factory; - ID3D12Debug* debugController; - ID3D12Debug1* debugController1; PFN_D3D12_CREATE_DEVICE createDevice; PFN_CreateDXGIFactory2 createDXGIFactory; PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface; PFN_D3D12SerializeVersionedRootSignature serializeVersionedRootSignature; - + + PalDebugCallback debugCallback; + void* debugUserData; const PalAllocator* allocator; - D3D12_MESSAGE_SEVERITY severities[3]; - D3D12_MESSAGE_CATEGORY categories[3]; + D3D12_MESSAGE_SEVERITY severities[6]; + D3D12_MESSAGE_CATEGORY categories[12]; } D3D12; typedef struct { @@ -171,7 +172,7 @@ typedef struct { const PalGraphicsBackend* backend; bool belongsToSwapchain; - ID3D12Device5* device; + Device* device; ID3D12Resource* handle; PalImageInfo info; D3D12_RESOURCE_DESC desc; @@ -206,6 +207,7 @@ typedef struct { DXGI_FEATURE presentFlags; Surface* surface; Image* images; + Device* device; ID3D12CommandQueue* queue; IDXGISwapChain3* handle; } Swapchain; @@ -259,7 +261,7 @@ typedef struct { bool supportsAddress; Uint64 size; ID3D12Resource* handle; - ID3D12Device5* device; + Device* device; D3D12_RESOURCE_DESC desc; } Buffer; @@ -875,10 +877,10 @@ static D3D12_BLEND blendFactorToD3D12(PalBlendFactor op) return D3D12_BLEND_ZERO; } - + static D3D12_FILTER filterToD3D12( - PalFilterMode minFilter, - PalFilterMode magFilter, + PalFilterMode minFilter, + PalFilterMode magFilter, PalSamplerMipmapMode mode) { // all the enums start with min so we start with min filter @@ -1203,7 +1205,7 @@ static void fillVkBuildInfoD3D12( tmp->Triangles.VertexBuffer.StrideInBytes = tmpData->vertexStride; tmp->Triangles.VertexCount = tmpData->vertexCount; tmp->Triangles.VertexFormat = vertexTypeToD3D12(tmpData->vertexType); - + tmp->Triangles.IndexBuffer = tmpData->indexBufferAddress; tmp->Triangles.IndexCount = tmpData->indexCount; if (tmpData->indexType == PAL_INDEX_TYPE_UINT16) { @@ -1215,7 +1217,7 @@ static void fillVkBuildInfoD3D12( } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { tmp->Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; PalGeometryDataAABBS* tmpData = info->geometries[i].data; - + tmp->AABBs.AABBCount = info->geometries[i].primitiveCount; tmp->AABBs.AABBs.StartAddress = tmpData->bufferAddress; tmp->AABBs.AABBs.StrideInBytes = tmpData->stride; @@ -1462,9 +1464,9 @@ static D3D12_RESOURCE_STATES barrierToD3D12( } static void fillSubresourceD3D12( - PalImageViewType type, - const PalImageSubresourceRange* range, - D3D12_RENDER_TARGET_VIEW_DESC* rtvDesc, + PalImageViewType type, + const PalImageSubresourceRange* range, + D3D12_RENDER_TARGET_VIEW_DESC* rtvDesc, D3D12_DEPTH_STENCIL_VIEW_DESC* dsvDesc, D3D12_SHADER_RESOURCE_VIEW_DESC* srvDesc, D3D12_UNORDERED_ACCESS_VIEW_DESC* uavDesc) @@ -1603,8 +1605,8 @@ static void fillSubresourceD3D12( } static inline Uint64 getDescriptorHandleD3D12( - Uint32 index, - Uint32 size, + Uint32 index, + Uint32 size, Uint64 baseOffset) { return baseOffset + index * size; @@ -1633,12 +1635,12 @@ static D3D12_RAYTRACING_INSTANCE_FLAGS instanceFlagsToD3D12( return instanceFlags; } -static D3D_PRIMITIVE_TOPOLOGY getPatchTopology(Uint32 patch) +static D3D_PRIMITIVE_TOPOLOGY getPatchTopology(Uint32 patch) { switch (patch) { case 1: return D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST; - + case 2: return D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST; @@ -1784,7 +1786,7 @@ static Uint32 getVertexTypeSizeD3D12(PalVertexType type) } static wchar_t* convertToWcharD3D12( - wchar_t* buffer, + wchar_t* buffer, Uint32* offset, const char* name) { @@ -1826,6 +1828,75 @@ static wchar_t* convertToWcharD3D12( return dst; } +static void pollMessagesD3D12(Device* device) +{ + ID3D12InfoQueue* queue = device->infoQueue; + if (!queue) { + return; + } + + Uint8* tmpBuffer[MAX_MESSAGE_SIZE]; + UINT64 messageCount = queue->lpVtbl->GetNumStoredMessages(queue); + for (int i = 0; i < messageCount; i++) { + SIZE_T size = 0; + queue->lpVtbl->GetMessageA(queue, i, nullptr, &size); + if (size > sizeof(tmpBuffer)) { + size = sizeof(tmpBuffer); + } + + queue->lpVtbl->GetMessageA(queue, i, (D3D12_MESSAGE*)tmpBuffer, &size); + const char* message = ((D3D12_MESSAGE*)tmpBuffer)->pDescription; + D3D12_MESSAGE_CATEGORY category = ((D3D12_MESSAGE*)tmpBuffer)->Category; + D3D12_MESSAGE_SEVERITY severity = ((D3D12_MESSAGE*)tmpBuffer)->Severity; + + PalDebugMessageSeverity msgSeverity = 0; + PalDebugMessageType msgType = 0; + switch (category) { + case D3D12_MESSAGE_CATEGORY_INITIALIZATION: + case D3D12_MESSAGE_CATEGORY_CLEANUP: + case D3D12_MESSAGE_CATEGORY_COMPILATION: { + msgType = PAL_DEBUG_MESSAGE_TYPE_GENERAL; + break; + } + + case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: + case D3D12_MESSAGE_CATEGORY_EXECUTION: + case D3D12_MESSAGE_CATEGORY_SHADER: { + msgType = PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE; + break; + } + + case D3D12_MESSAGE_CATEGORY_STATE_CREATION: + case D3D12_MESSAGE_CATEGORY_STATE_GETTING: + case D3D12_MESSAGE_CATEGORY_STATE_SETTING: { + msgType = PAL_DEBUG_MESSAGE_TYPE_VALIDATION; + break; + } + } + + switch (severity) { + case D3D12_MESSAGE_SEVERITY_INFO: { + msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; + break; + } + + case D3D12_MESSAGE_SEVERITY_WARNING: { + msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; + break; + } + + case D3D12_MESSAGE_SEVERITY_ERROR: + case D3D12_MESSAGE_SEVERITY_CORRUPTION: { + msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_ERROR; + break; + } + } + + s_D3D.debugCallback(s_D3D.debugUserData, msgSeverity, msgType, message); + } + queue->lpVtbl->ClearStoredMessages(queue); +} + // ================================================== // Adapter // ================================================== @@ -1861,17 +1932,23 @@ PalResult PAL_CALL initGraphicsD3D12( if (s_D3D.getDebugInterface) { HRESULT hr; - hr = s_D3D.getDebugInterface(&IID_DebugController, (void**)&s_D3D.debugController); + ID3D12Debug* debugController = nullptr; + ID3D12Debug1* debugController1 = nullptr; + + hr = s_D3D.getDebugInterface(&IID_DebugController, (void**)&debugController); if (SUCCEEDED(hr)) { - s_D3D.debugController->lpVtbl->EnableDebugLayer(s_D3D.debugController); + debugController->lpVtbl->EnableDebugLayer(debugController); + debugController->lpVtbl->Release(debugController); } - hr = s_D3D.getDebugInterface(&IID_DebugController1, (void**)&s_D3D.debugController1); + hr = s_D3D.getDebugInterface(&IID_DebugController1, (void**)&debugController1); if (SUCCEEDED(hr)) { - s_D3D.debugController1->lpVtbl->SetEnableGPUBasedValidation( - s_D3D.debugController1, + debugController1->lpVtbl->SetEnableGPUBasedValidation( + debugController1, TRUE); + debugController1->lpVtbl->Release(debugController1); + // message types if (!debugger->denyGeneral) { s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_INITIALIZATION; @@ -1906,6 +1983,7 @@ PalResult PAL_CALL initGraphicsD3D12( } } s_D3D.debugLayer = true; + s_D3D.debugCallback = debugger->callback; } } // clang-format on @@ -1924,14 +2002,6 @@ PalResult PAL_CALL initGraphicsD3D12( void PAL_CALL shutdownGraphicsD3D12() { - if (s_D3D.debugController) { - s_D3D.debugController->lpVtbl->Release(s_D3D.debugController); - } - - if (s_D3D.debugController1) { - s_D3D.debugController1->lpVtbl->Release(s_D3D.debugController1); - } - for (int i = 0; i < s_D3D.adapterCount; i++) { s_D3D.adapters[i].handle->lpVtbl->Release(s_D3D.adapters[i].handle); } @@ -1969,8 +2039,8 @@ PalResult PAL_CALL enumerateAdaptersD3D12( } while (SUCCEEDED(s_D3D.factory->lpVtbl->EnumAdapters( - s_D3D.factory, - adapterCount, + s_D3D.factory, + adapterCount, &adapter))) { if (outAdapters) { IDXGIAdapter4* tmp = nullptr; @@ -1978,16 +2048,16 @@ PalResult PAL_CALL enumerateAdaptersD3D12( dxAdapters[adapterCount] = tmp; } - // create a temp device for every adapter to use as an instance to check features, + // create a temp device for every adapter to use as an instance to check features, // capabilities etc. ID3D12Device* device = nullptr; for (int i = 0; i < 5; i++) { HRESULT result = s_D3D.createDevice( (IUnknown*)tmp, - levels[i], - &IID_Device, + levels[i], + &IID_Device, (void**)&device); - + if (SUCCEEDED(result)) { deviceLevels[adapterCount] = levels[i]; devices[adapterCount] = device; @@ -2045,19 +2115,19 @@ PalResult PAL_CALL getAdapterInfoD3D12( strcpy(info->backendName, "PAL"); WideCharToMultiByte( - CP_UTF8, - 0, - desc.Description, - -1, - info->name, - PAL_ADAPTER_NAME_SIZE, - nullptr, + CP_UTF8, + 0, + desc.Description, + -1, + info->name, + PAL_ADAPTER_NAME_SIZE, + nullptr, nullptr); device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_ARCHITECTURE1, - &arch, + device, + D3D12_FEATURE_ARCHITECTURE1, + &arch, sizeof(arch)); if (arch.UMA == true) { @@ -2170,40 +2240,40 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS, - &options, + device, + D3D12_FEATURE_D3D12_OPTIONS, + &options, sizeof(options)); device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS3, - &options3, + device, + D3D12_FEATURE_D3D12_OPTIONS3, + &options3, sizeof(options3)); device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS5, - &options5, + device, + D3D12_FEATURE_D3D12_OPTIONS5, + &options5, sizeof(options5)); device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS6, - &options6, + device, + D3D12_FEATURE_D3D12_OPTIONS6, + &options6, sizeof(options6)); device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS7, - &options7, + device, + D3D12_FEATURE_D3D12_OPTIONS7, + &options7, sizeof(options7)); shaderModel.HighestShaderModel = D3D_SHADER_MODEL_5_1; HRESULT hr = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, sizeof(shaderModel)); if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_5_1 && hr == S_OK) { @@ -2214,9 +2284,9 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_2; hr = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, sizeof(shaderModel)); if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_2 && hr == S_OK) { @@ -2226,9 +2296,9 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; hr = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, sizeof(shaderModel)); if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0 && hr == S_OK) { @@ -2300,11 +2370,11 @@ PalResult PAL_CALL createDeviceD3D12( memset(device, 0, sizeof(Device)); result = s_D3D.createDevice( - (IUnknown*)d3dAdapter->handle, - d3dAdapter->level, - &IID_Device, + (IUnknown*)d3dAdapter->handle, + d3dAdapter->level, + &IID_Device, (void**)&tmpDevice); - + if (FAILED(result)) { palFree(s_D3D.allocator, device); if (result == E_OUTOFMEMORY) { @@ -2314,15 +2384,15 @@ PalResult PAL_CALL createDeviceD3D12( } result = tmpDevice->lpVtbl->QueryInterface( - tmpDevice, - &IID_Device5, + tmpDevice, + &IID_Device5, (void**)&device->handle); tmpDevice->lpVtbl->Release(tmpDevice); if (s_D3D.debugLayer) { result = device->handle->lpVtbl->QueryInterface( - device->handle, - &IID_InfoQueue, + device->handle, + &IID_InfoQueue, (void**)&device->infoQueue); if (SUCCEEDED(result)) { @@ -2346,7 +2416,7 @@ PalResult PAL_CALL createDeviceD3D12( result = device->handle->lpVtbl->CreateCommandQueue( device->handle, &desc, - &IID_Queue, + &IID_Queue, (void**)&device->queue); if (FAILED(result)) { @@ -2370,7 +2440,7 @@ PalResult PAL_CALL createDeviceD3D12( device->handle, &signatureDesc, nullptr, - &IID_CommandSignature, + &IID_CommandSignature, (void**)&device->meshSignature); if (FAILED(result)) { @@ -2389,7 +2459,7 @@ PalResult PAL_CALL createDeviceD3D12( device->handle, &signatureDesc, nullptr, - &IID_CommandSignature, + &IID_CommandSignature, (void**)&device->raySignature); if (FAILED(result)) { @@ -2406,10 +2476,10 @@ PalResult PAL_CALL createDeviceD3D12( signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS); result = device->handle->lpVtbl->CreateCommandSignature( - device->handle, - &signatureDesc, - nullptr, - &IID_CommandSignature, + device->handle, + &signatureDesc, + nullptr, + &IID_CommandSignature, (void**)&device->dispatchSignature); if (FAILED(result)) { @@ -2424,10 +2494,10 @@ PalResult PAL_CALL createDeviceD3D12( signatureDesc.ByteStride = sizeof(D3D12_DRAW_INDEXED_ARGUMENTS); result = device->handle->lpVtbl->CreateCommandSignature( - device->handle, - &signatureDesc, - nullptr, - &IID_CommandSignature, + device->handle, + &signatureDesc, + nullptr, + &IID_CommandSignature, (void**)&device->drawIndexedSignature); if (FAILED(result)) { @@ -2442,10 +2512,10 @@ PalResult PAL_CALL createDeviceD3D12( signatureDesc.ByteStride = sizeof(D3D12_DRAW_ARGUMENTS); result = device->handle->lpVtbl->CreateCommandSignature( - device->handle, - &signatureDesc, - nullptr, - &IID_CommandSignature, + device->handle, + &signatureDesc, + nullptr, + &IID_CommandSignature, (void**)&device->drawSignature); if (FAILED(result)) { @@ -2462,9 +2532,9 @@ PalResult PAL_CALL createDeviceD3D12( heapDesc.NumDescriptors = MAX_RTV; result = device->handle->lpVtbl->CreateDescriptorHeap( - device->handle, - &heapDesc, - &IID_DescriptorHeap, + device->handle, + &heapDesc, + &IID_DescriptorHeap, (void**)&device->rtvAllocator.heap); if (FAILED(result)) { @@ -2477,9 +2547,9 @@ PalResult PAL_CALL createDeviceD3D12( heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; heapDesc.NumDescriptors = MAX_DSV; result = device->handle->lpVtbl->CreateDescriptorHeap( - device->handle, - &heapDesc, - &IID_DescriptorHeap, + device->handle, + &heapDesc, + &IID_DescriptorHeap, (void**)&device->dsvAllocator.heap); if (FAILED(result)) { @@ -2499,12 +2569,12 @@ PalResult PAL_CALL createDeviceD3D12( device->rtvAllocator.freeTop = MAX_RTV; device->rtvAllocator.incrementSize = device->handle->lpVtbl->GetDescriptorHandleIncrementSize( - device->handle, + device->handle, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); device->dsvAllocator.freeTop = MAX_DSV; device->dsvAllocator.incrementSize = device->handle->lpVtbl->GetDescriptorHandleIncrementSize( - device->handle, + device->handle, D3D12_DESCRIPTOR_HEAP_TYPE_DSV); // get base CPU pointer @@ -2580,7 +2650,7 @@ PalResult PAL_CALL allocateMemoryD3D12( D3D12_HEAP_DESC desc = {0}; desc.SizeInBytes = size; - + desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; if (type == PAL_MEMORY_TYPE_CPU_READBACK) { desc.Properties.Type = D3D12_HEAP_TYPE_READBACK; @@ -2590,12 +2660,13 @@ PalResult PAL_CALL allocateMemoryD3D12( } result = d3dDevice->handle->lpVtbl->CreateHeap( - d3dDevice->handle, - &desc, - &IID_Heap, + d3dDevice->handle, + &desc, + &IID_Heap, (void**)&memory); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); return PAL_RESULT_OUT_OF_MEMORY; } @@ -2668,9 +2739,9 @@ PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( D3D12_FEATURE_DATA_D3D12_OPTIONS6 options = {0}; d3dDevice->handle->lpVtbl->CheckFeatureSupport( - d3dDevice->handle, - D3D12_FEATURE_D3D12_OPTIONS6, - &options, + d3dDevice->handle, + D3D12_FEATURE_D3D12_OPTIONS6, + &options, sizeof(options)); if (options.AdditionalShadingRatesSupported) { @@ -2709,7 +2780,7 @@ PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( } // these are not exposed by d3d12. We use the offical mesh shader spec - caps->maxMeshOutputPrimitives = 256; + caps->maxMeshOutputPrimitives = 256; caps->maxMeshOutputVertices = 256; caps->maxTaskWorkGroupInvocations = 128; caps->maxMeshWorkGroupInvocations = 128; @@ -2743,8 +2814,6 @@ PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( caps->maxPayloadSize = PAL_LIMIT_UNKNOWN; caps->maxDispatchInvocations = PAL_LIMIT_UNKNOWN; - caps->RequiresShaderExportName = true; - caps->RequiresShaderGroupExportName = true; return PAL_RESULT_SUCCESS; } @@ -2813,12 +2882,13 @@ PalResult PAL_CALL createQueueD3D12( } result = d3dDevice->handle->lpVtbl->CreateCommandQueue( - d3dDevice->handle, + d3dDevice->handle, &desc, - &IID_Queue, + &IID_Queue, (void**)&queue->handle); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); palFree(s_D3D.allocator, queue); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; @@ -2828,13 +2898,14 @@ PalResult PAL_CALL createQueueD3D12( // create fence used for queue wait result = d3dDevice->handle->lpVtbl->CreateFence( - d3dDevice->handle, - 0, - 0, + d3dDevice->handle, + 0, + 0, &IID_Fence, (void**)&queue->fence); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); palFree(s_D3D.allocator, queue); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; @@ -2907,9 +2978,9 @@ PalResult PAL_CALL enumerateFormatsD3D12( support.Format = fmt; result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, sizeof(support)); if (SUCCEEDED(result)) { @@ -2952,9 +3023,9 @@ bool PAL_CALL isFormatSupportedD3D12( support.Format = fmt; result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, sizeof(support)); if (FAILED(result) || (support.Support1 == 0 && support.Support2 == 0)) { @@ -2980,9 +3051,9 @@ PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( support.Format = fmt; result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, sizeof(support)); if (FAILED(result)) { @@ -3019,9 +3090,9 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( support.Format = fmt; result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, sizeof(support)); if (FAILED(result)) { @@ -3042,9 +3113,9 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( for (int i = 0; i < 6; i++) { samples.SampleCount = sampleCounts[i]; result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, - &samples, + device, + D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, + &samples, sizeof(samples)); if (SUCCEEDED(result) && samples.NumQualityLevels > 0) { @@ -3127,7 +3198,7 @@ PalResult PAL_CALL createImageD3D12( image->info.sampleCount = info->sampleCount; image->info.width = info->width; - image->device = d3dDevice->handle; + image->device = d3dDevice; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } @@ -3156,14 +3227,15 @@ PalResult PAL_CALL getImageMemoryRequirementsD3D12( PalMemoryRequirements* requirements) { Image* d3dImage = (Image*)image; + ID3D12Device5* device = d3dImage->device->handle; if (d3dImage->belongsToSwapchain) { return PAL_RESULT_INVALID_OPERATION; } D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; - allocationInfo = *d3dImage->device->lpVtbl->GetResourceAllocationInfo( - d3dImage->device, + allocationInfo = *device->lpVtbl->GetResourceAllocationInfo( + device, &__ret, 0, 1, @@ -3186,22 +3258,36 @@ PalResult PAL_CALL bindImageMemoryD3D12( { HRESULT result; Image* d3dImage = (Image*)image; + ID3D12Device5* device = d3dImage->device->handle; if (d3dImage->belongsToSwapchain) { return PAL_RESULT_INVALID_OPERATION; } + D3D12_RESOURCE_STATES state = 0; ID3D12Heap* mem = (ID3D12Heap*)memory; - result = d3dImage->device->lpVtbl->CreatePlacedResource( - d3dImage->device, - mem, - offset, - &d3dImage->desc, - 0, - nullptr, - &IID_Resource, + D3D12_HEAP_DESC __ret = {0}; + D3D12_HEAP_DESC heapProps = {0}; + heapProps = *mem->lpVtbl->GetDesc(mem, &__ret); + + if (heapProps.Properties.Type == D3D12_HEAP_TYPE_UPLOAD) { + state = D3D12_RESOURCE_STATE_GENERIC_READ; + + } else if (heapProps.Properties.Type == D3D12_HEAP_TYPE_READBACK) { + state = D3D12_RESOURCE_STATE_COPY_DEST; + } + + result = device->lpVtbl->CreatePlacedResource( + device, + mem, + offset, + &d3dImage->desc, + state, + nullptr, + &IID_Resource, (void**)d3dImage->handle); if (FAILED(result)) { + pollMessagesD3D12(d3dImage->device); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } else if (result == E_INVALIDARG) { @@ -3266,9 +3352,9 @@ PalResult PAL_CALL createImageViewD3D12( imageView->heapIndex = index; d3dDevice->handle->lpVtbl->CreateRenderTargetView( - d3dDevice->handle, - d3dImage->handle, - &desc, + d3dDevice->handle, + d3dImage->handle, + &desc, dst); } else { @@ -3283,9 +3369,9 @@ PalResult PAL_CALL createImageViewD3D12( imageView->heapIndex = index; d3dDevice->handle->lpVtbl->CreateDepthStencilView( - d3dDevice->handle, - d3dImage->handle, - &desc, + d3dDevice->handle, + d3dImage->handle, + &desc, dst); } @@ -3346,8 +3432,8 @@ PalResult PAL_CALL createSamplerD3D12( sampler->desc.AddressW = addressModeToD3D12(info->addressModeW); sampler->desc.Filter = filterToD3D12( - info->minFilterMode, - info->magFilterMode, + info->minFilterMode, + info->magFilterMode, info->mipmapMode); *outSampler = (PalSampler*)sampler; @@ -3430,6 +3516,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( &swapchain1); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3442,8 +3529,8 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( // check for HDR10 color space support UINT flags = 0; result = swapchain3->lpVtbl->CheckColorSpaceSupport( - swapchain3, - DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, + swapchain3, + DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, &flags); if (SUCCEEDED(result) && (flags & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) { @@ -3452,7 +3539,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( BOOL allowTearing = FALSE; s_D3D.factory->lpVtbl->CheckFeatureSupport( - s_D3D.factory, + s_D3D.factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing)); @@ -3496,9 +3583,9 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( for (int i = 0; i < PAL_SURFACE_FORMAT_MAX; i++) { formatSupport.Format = baseFormats[i]; result = d3dDevice->handle->lpVtbl->CheckFeatureSupport( - d3dDevice->handle, - D3D12_FEATURE_FORMAT_SUPPORT, - &formatSupport, + d3dDevice->handle, + D3D12_FEATURE_FORMAT_SUPPORT, + &formatSupport, sizeof(formatSupport)); if (SUCCEEDED(result) && (formatSupport.Support1 != 0 || formatSupport.Support2 != 0)) { @@ -3605,7 +3692,7 @@ PalResult PAL_CALL createSwapchainD3D12( } else if (info->format == PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR) { desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; imageFormat = PAL_FORMAT_R8G8B8A8_SRGB; - + } else if (info->format == PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10) { desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; imageFormat = PAL_FORMAT_R16G16B16A16_SFLOAT; @@ -3624,6 +3711,7 @@ PalResult PAL_CALL createSwapchainD3D12( &swapchain1); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } else if (result == E_INVALIDARG) { @@ -3637,7 +3725,7 @@ PalResult PAL_CALL createSwapchainD3D12( if (isHDRColorspace) { swapchain->handle->lpVtbl->SetColorSpace1( - swapchain->handle, + swapchain->handle, DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); } else { swapchain->handle->lpVtbl->SetColorSpace1( @@ -3658,7 +3746,7 @@ PalResult PAL_CALL createSwapchainD3D12( Image* image = &swapchain->images[i]; image->belongsToSwapchain = true; - image->device = d3dDevice->handle; + image->device = d3dDevice; image->handle = tmp; image->info.depthOrArraySize = 1; // always 1 @@ -3677,6 +3765,7 @@ PalResult PAL_CALL createSwapchainD3D12( swapchain->windowWidth = windowRect.right - windowRect.left; swapchain->windowWidth = windowRect.bottom - windowRect.top; + swapchain->device = d3dDevice; swapchain->queue = d3dQueue->handle; swapchain->imageCount = info->imageCount; *outSwapchain = (PalSwapchain*)swapchain; @@ -3752,11 +3841,12 @@ PalResult PAL_CALL presentSwapchainD3D12( } result = d3dSwapchain->handle->lpVtbl->Present( - d3dSwapchain->handle, - d3dSwapchain->syncInterval, + d3dSwapchain->handle, + d3dSwapchain->syncInterval, d3dSwapchain->presentFlags); if (FAILED(result)) { + pollMessagesD3D12(d3dSwapchain->device); if (result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET) { return PAL_RESULT_DEVICE_LOST; } @@ -3789,11 +3879,11 @@ PalResult PAL_CALL resizeSwapchainD3D12( HRESULT result; Swapchain* d3dSwapchain = (Swapchain*)swapchain; result = d3dSwapchain->handle->lpVtbl->ResizeBuffers( - d3dSwapchain->handle, - d3dSwapchain->imageCount, - newWidth, - newHeight, - d3dSwapchain->format, + d3dSwapchain->handle, + d3dSwapchain->imageCount, + newWidth, + newHeight, + d3dSwapchain->format, d3dSwapchain->flags); if (FAILED(result)) { @@ -3807,9 +3897,9 @@ PalResult PAL_CALL resizeSwapchainD3D12( for (int i = 0; i < d3dSwapchain->imageCount; i++) { ID3D12Resource* tmp = nullptr; d3dSwapchain->handle->lpVtbl->GetBuffer( - d3dSwapchain->handle, - i, - &IID_Resource, + d3dSwapchain->handle, + i, + &IID_Resource, (void**)&tmp); Image* image = &d3dSwapchain->images[i]; @@ -3903,13 +3993,14 @@ PalResult PAL_CALL createFenceD3D12( } result = d3dDevice->handle->lpVtbl->CreateFence( - d3dDevice->handle, - 0, - 0, + d3dDevice->handle, + 0, + 0, &IID_Fence, (void**)&fence->handle); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); palFree(s_D3D.allocator, fence); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; @@ -3947,8 +4038,8 @@ PalResult PAL_CALL waitFenceD3D12( if (d3dFence->handle->lpVtbl->GetCompletedValue(d3dFence->handle) < value) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); result = d3dFence->handle->lpVtbl->SetEventOnCompletion( - d3dFence->handle, - value, + d3dFence->handle, + value, event); if (FAILED(result)) { @@ -4012,20 +4103,21 @@ PalResult PAL_CALL createSemaphoreD3D12( } result = d3dDevice->handle->lpVtbl->CreateFence( - d3dDevice->handle, - 0, - 0, + d3dDevice->handle, + 0, + 0, &IID_Fence, (void**)&semaphore->handle); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); palFree(s_D3D.allocator, semaphore); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } return PAL_RESULT_PLATFORM_FAILURE; } - + semaphore->isTimeline = false; if (d3dDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { semaphore->isTimeline = true; @@ -4059,8 +4151,8 @@ PalResult PAL_CALL waitSemaphoreD3D12( if (d3dSemaphore->handle->lpVtbl->GetCompletedValue(d3dSemaphore->handle) < value) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); result = d3dSemaphore->handle->lpVtbl->SetEventOnCompletion( - d3dSemaphore->handle, - value, + d3dSemaphore->handle, + value, event); if (FAILED(result)) { @@ -4203,12 +4295,13 @@ PalResult PAL_CALL allocateCommandBufferD3D12( // create an allocator result = d3dDevice->handle->lpVtbl->CreateCommandAllocator( - d3dDevice->handle, - cmdBufferType, - &IID_CommandAllocator, + d3dDevice->handle, + cmdBufferType, + &IID_CommandAllocator, (void**)&cmdBuffer->allocator); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4227,6 +4320,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdList); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4249,12 +4343,12 @@ PalResult PAL_CALL allocateCommandBufferD3D12( bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; result = d3dDevice->handle->lpVtbl->CreateCommittedResource( - d3dDevice->handle, - &heapProps, - 0, - &bufferDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, + d3dDevice->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, &IID_Resource, (void**)&cmdBuffer->tmpBuffer); if (FAILED(result)) { @@ -4265,8 +4359,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( } cmdList->lpVtbl->QueryInterface( - cmdList, - &IID_CommandList6, + cmdList, + &IID_CommandList6, (void**)&cmdBuffer->handle); cmdList->lpVtbl->Release(cmdList); @@ -4306,8 +4400,8 @@ PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) } d3dCmdBuffer->handle->lpVtbl->Reset( - d3dCmdBuffer->handle, - d3dCmdBuffer->allocator, + d3dCmdBuffer->handle, + d3dCmdBuffer->allocator, nullptr); d3dCmdBuffer->strides = nullptr; @@ -4322,7 +4416,7 @@ PalResult PAL_CALL submitCommandBufferD3D12( Queue* d3dQueue = (Queue*)queue; ID3D12CommandQueue* queueHandle = d3dQueue->handle; CommandBuffer* d3dCmdBuffer = (CommandBuffer*)info->cmdBuffer; - + // wait semaphore if (info->waitSemaphore) { Semaphore* semaphore = (Semaphore*)info->waitSemaphore; @@ -4406,8 +4500,8 @@ PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( } d3dCmdBuffer->handle->lpVtbl->RSSetShadingRate( - d3dCmdBuffer->handle, - shadingRate, + d3dCmdBuffer->handle, + shadingRate, combinerOps); return PAL_RESULT_SUCCESS; @@ -4426,9 +4520,9 @@ PalResult PAL_CALL cmdDrawMeshTasksD3D12( } d3dCmdBuffer->handle->lpVtbl->DispatchMesh( - d3dCmdBuffer->handle, - groupCountX, - groupCountY, + d3dCmdBuffer->handle, + groupCountX, + groupCountY, groupCountZ); return PAL_RESULT_SUCCESS; @@ -4447,12 +4541,12 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( Buffer* d3dBuffer = (Buffer*)buffer; d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->meshSignature, - drawCount, + d3dCmdBuffer->handle, + device->meshSignature, + drawCount, d3dBuffer->handle, - 0, - nullptr, + 0, + nullptr, 0); return PAL_RESULT_SUCCESS; @@ -4473,12 +4567,12 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( Buffer* d3dBuffer = (Buffer*)buffer; Buffer* d3dCountBuffer = (Buffer*)countBuffer; d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->meshSignature, - maxDrawCount, + d3dCmdBuffer->handle, + device->meshSignature, + maxDrawCount, d3dBuffer->handle, - 0, - d3dCountBuffer->handle, + 0, + d3dCountBuffer->handle, 0); return PAL_RESULT_SUCCESS; @@ -4516,16 +4610,16 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); fillVkBuildInfoD3D12( - info, + info, geometries, - srcAsAddress, + srcAsAddress, dstAs->address, &buildInfo); d3dCmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( d3dCmdBuffer->handle, - &buildInfo, - 0, + &buildInfo, + 0, nullptr); palFree(s_D3D.allocator, geometries); @@ -4534,14 +4628,14 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( fillVkBuildInfoD3D12( info, nullptr, - srcAsAddress, + srcAsAddress, dstAs->address, &buildInfo); d3dCmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( d3dCmdBuffer->handle, - &buildInfo, - 0, + &buildInfo, + 0, nullptr); } @@ -4573,18 +4667,18 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( depthStencilAttachment.ptr = getDescriptorHandleD3D12(tmp->heapIndex, size, base); d3dCmdBuffer->handle->lpVtbl->OMSetRenderTargets( - d3dCmdBuffer->handle, - info->colorAttachentCount, - colorAttachments, - FALSE, + d3dCmdBuffer->handle, + info->colorAttachentCount, + colorAttachments, + FALSE, &depthStencilAttachment); } else { d3dCmdBuffer->handle->lpVtbl->OMSetRenderTargets( - d3dCmdBuffer->handle, - info->colorAttachentCount, - colorAttachments, - FALSE, + d3dCmdBuffer->handle, + info->colorAttachentCount, + colorAttachments, + FALSE, nullptr); } @@ -4597,7 +4691,7 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( color[3] = info->colorAttachments[i].clearValue.color[3]; d3dCmdBuffer->handle->lpVtbl->ClearRenderTargetView( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, colorAttachments[i], color, 0, nullptr); } @@ -4618,11 +4712,11 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( d3dCmdBuffer->handle->lpVtbl->ClearDepthStencilView( d3dCmdBuffer->handle, - depthStencilAttachment, - clearFlags, - depth, - stencil, - 0, + depthStencilAttachment, + clearFlags, + depth, + stencil, + 0, nullptr); } @@ -4652,7 +4746,7 @@ PalResult PAL_CALL cmdCopyBufferD3D12( Buffer* srcBuffer = (Buffer*)src; d3dCmdBuffer->handle->lpVtbl->CopyBufferRegion( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, dstbuffer->handle, copyInfo->dstOffset, srcBuffer->handle, @@ -4713,7 +4807,7 @@ PalResult PAL_CALL cmdCopyBufferToImageD3D12( dstLocation.SubresourceIndex = index; d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, &dstLocation, copyInfo->imageOffsetX, copyInfo->imageOffsetY, @@ -4779,11 +4873,11 @@ PalResult PAL_CALL cmdCopyImageD3D12( srcLocation.SubresourceIndex = srcIndex; d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle, - &dstLocation, - copyInfo->dstOffsetX, - copyInfo->dstOffsetY, - copyInfo->dstOffsetZ, + d3dCmdBuffer->handle, + &dstLocation, + copyInfo->dstOffsetX, + copyInfo->dstOffsetY, + copyInfo->dstOffsetZ, &srcLocation, &box); } @@ -4845,7 +4939,7 @@ PalResult PAL_CALL cmdCopyImageToBufferD3D12( srcLocation.SubresourceIndex = index; d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, &dstLocation, 0, 0, @@ -4866,23 +4960,23 @@ PalResult PAL_CALL cmdBindPipelineD3D12( Pipeline* d3dPipeline = (Pipeline*)pipeline; if (d3dPipeline->type == RAY_TRACING_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetPipelineState1( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, d3dPipeline->handle); } else { d3dCmdBuffer->handle->lpVtbl->SetPipelineState( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, d3dPipeline->handle); if (d3dPipeline->type == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->IASetPrimitiveTopology( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, d3dPipeline->topology); if (d3dPipeline->hasFsr) { d3dCmdBuffer->handle->lpVtbl->RSSetShadingRate( - d3dCmdBuffer->handle, - d3dPipeline->shadingRate, + d3dCmdBuffer->handle, + d3dPipeline->shadingRate, d3dPipeline->combinerOps); } } @@ -4997,9 +5091,9 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( } d3dCmdBuffer->handle->lpVtbl->IASetVertexBuffers( - d3dCmdBuffer->handle, - firstSlot, - count, + d3dCmdBuffer->handle, + firstSlot, + count, views); if (count > 1) { @@ -5026,7 +5120,7 @@ PalResult PAL_CALL cmdBindIndexBufferD3D12( } else { view.Format = DXGI_FORMAT_R32_UINT; } - + d3dCmdBuffer->handle->lpVtbl->IASetIndexBuffer(d3dCmdBuffer->handle, &view); return PAL_RESULT_SUCCESS; } @@ -5040,10 +5134,10 @@ PalResult PAL_CALL cmdDrawD3D12( { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; d3dCmdBuffer->handle->lpVtbl->DrawInstanced( - d3dCmdBuffer->handle, - vertexCount, - instanceCount, - firstVertex, + d3dCmdBuffer->handle, + vertexCount, + instanceCount, + firstVertex, firstInstance); return PAL_RESULT_SUCCESS; @@ -5062,12 +5156,12 @@ PalResult PAL_CALL cmdDrawIndirectD3D12( Buffer* d3dBuffer = (Buffer*)buffer; d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, device->drawSignature, count, d3dBuffer->handle, - 0, - nullptr, + 0, + nullptr, 0); return PAL_RESULT_SUCCESS; @@ -5088,12 +5182,12 @@ PalResult PAL_CALL cmdDrawIndirectCountD3D12( Buffer* d3dBuffer = (Buffer*)buffer; Buffer* d3dCountBuffer = (Buffer*)countBuffer; d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, device->drawSignature, - maxDrawCount, + maxDrawCount, d3dBuffer->handle, - 0, - d3dCountBuffer->handle, + 0, + d3dCountBuffer->handle, 0); return PAL_RESULT_SUCCESS; @@ -5132,12 +5226,12 @@ PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( Buffer* d3dBuffer = (Buffer*)buffer; d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, device->drawIndexedSignature, count, d3dBuffer->handle, - 0, - nullptr, + 0, + nullptr, 0); return PAL_RESULT_SUCCESS; @@ -5158,12 +5252,12 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( Buffer* d3dBuffer = (Buffer*)buffer; Buffer* d3dCountBuffer = (Buffer*)countBuffer; d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, device->drawIndexedSignature, - maxDrawCount, + maxDrawCount, d3dBuffer->handle, - 0, - d3dCountBuffer->handle, + 0, + d3dCountBuffer->handle, 0); return PAL_RESULT_SUCCESS; @@ -5184,13 +5278,13 @@ PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( D3D12_RESOURCE_STATES old, new; old = barrierToD3D12( - oldUsageStateInfo->shaderStageCount, - oldUsageStateInfo->usageState, + oldUsageStateInfo->shaderStageCount, + oldUsageStateInfo->usageState, oldUsageStateInfo->shaderStages); new = barrierToD3D12( - newUsageStateInfo->shaderStageCount, - newUsageStateInfo->usageState, + newUsageStateInfo->shaderStageCount, + newUsageStateInfo->usageState, newUsageStateInfo->shaderStages); D3D12_RESOURCE_BARRIER barrier = {0}; @@ -5214,13 +5308,13 @@ PalResult PAL_CALL cmdImageBarrierD3D12( D3D12_RESOURCE_BARRIER barrier = {0}; old = barrierToD3D12( - oldUsageStateInfo->shaderStageCount, - oldUsageStateInfo->usageState, + oldUsageStateInfo->shaderStageCount, + oldUsageStateInfo->usageState, oldUsageStateInfo->shaderStages); new = barrierToD3D12( - newUsageStateInfo->shaderStageCount, - newUsageStateInfo->usageState, + newUsageStateInfo->shaderStageCount, + newUsageStateInfo->usageState, newUsageStateInfo->shaderStages); // read/write barrier without transition @@ -5307,13 +5401,13 @@ PalResult PAL_CALL cmdBufferBarrierD3D12( D3D12_RESOURCE_STATES old, new; old = barrierToD3D12( - oldUsageStateInfo->shaderStageCount, - oldUsageStateInfo->usageState, + oldUsageStateInfo->shaderStageCount, + oldUsageStateInfo->usageState, oldUsageStateInfo->shaderStages); new = barrierToD3D12( - newUsageStateInfo->shaderStageCount, - newUsageStateInfo->usageState, + newUsageStateInfo->shaderStageCount, + newUsageStateInfo->usageState, newUsageStateInfo->shaderStages); D3D12_RESOURCE_BARRIER barrier = {0}; @@ -5326,7 +5420,7 @@ PalResult PAL_CALL cmdBufferBarrierD3D12( barrier.Transition.StateBefore = old; barrier.Transition.StateAfter = new; } - + d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); return PAL_RESULT_SUCCESS; } @@ -5339,9 +5433,9 @@ PalResult PAL_CALL cmdDispatchD3D12( { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; d3dCmdBuffer->handle->lpVtbl->Dispatch( - d3dCmdBuffer->handle, - groupCountX, - groupCountY, + d3dCmdBuffer->handle, + groupCountX, + groupCountY, groupCountZ); return PAL_RESULT_SUCCESS; @@ -5375,12 +5469,12 @@ PalResult PAL_CALL cmdDispatchIndirectD3D12( Buffer* d3dBuffer = (Buffer*)buffer; d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, device->dispatchSignature, 1, // one dispatch d3dBuffer->handle, - 0, - nullptr, + 0, + nullptr, 0); return PAL_RESULT_SUCCESS; @@ -5466,14 +5560,14 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( d3dCmdBuffer->tmpBuffer->lpVtbl->Unmap(d3dCmdBuffer->tmpBuffer, 0, nullptr); d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->raySignature, - 1, - d3dCmdBuffer->tmpBuffer, - 0, - nullptr, + d3dCmdBuffer->handle, + device->raySignature, + 1, + d3dCmdBuffer->tmpBuffer, + 0, + nullptr, 0); - + return PAL_RESULT_SUCCESS; } @@ -5506,12 +5600,12 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( D3D12_GPU_DESCRIPTOR_HANDLE base; base.ptr = getDescriptorHandleD3D12( d3dSet->resourceOffset, - pool->resourceHeap.incrementSize, + pool->resourceHeap.incrementSize, pool->resourceHeap.gpuBase); if (d3dCmdBuffer->pipelineType == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, pipelineLayout->resourceIndex, base); @@ -5529,12 +5623,12 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( D3D12_GPU_DESCRIPTOR_HANDLE base; base.ptr = getDescriptorHandleD3D12( d3dSet->samplerOffset, - pool->samplerHeap.incrementSize, + pool->samplerHeap.incrementSize, pool->samplerHeap.gpuBase); if (d3dCmdBuffer->pipelineType == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( - d3dCmdBuffer->handle, + d3dCmdBuffer->handle, pipelineLayout->samplerIndex, base); @@ -5564,19 +5658,19 @@ PalResult PAL_CALL cmdPushConstantsD3D12( if (pipelineLayout->constantIndex != UINT32_MAX) { if (d3dCmdBuffer->pipelineType == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRoot32BitConstants( - d3dCmdBuffer->handle, - pipelineLayout->constantIndex, - size / 4, - value, + d3dCmdBuffer->handle, + pipelineLayout->constantIndex, + size / 4, + value, offset / 4); } else { // ray tracing uses the compute path d3dCmdBuffer->handle->lpVtbl->SetComputeRoot32BitConstants( - d3dCmdBuffer->handle, - pipelineLayout->constantIndex, - size / 4, - value, + d3dCmdBuffer->handle, + pipelineLayout->constantIndex, + size / 4, + value, offset / 4); } } @@ -5643,7 +5737,7 @@ PalResult PAL_CALL createAccelerationstructureD3D12( AccelerationStructure* as = nullptr; Device* d3dDevice = (Device*)device; Buffer* d3dBuffer = (Buffer*)info->buffer; - + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5694,9 +5788,9 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); fillVkBuildInfoD3D12( - info, + info, geometries, - 0, + 0, 0, &buildInfo); @@ -5709,9 +5803,9 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( } else { fillVkBuildInfoD3D12( - info, + info, nullptr, - 0, + 0, 0, &buildInfo); @@ -5753,12 +5847,24 @@ PalResult PAL_CALL createBufferD3D12( buffer->desc.SampleDesc.Count = 1; buffer->desc.SampleDesc.Quality = 0; buffer->desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + buffer->desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - if (d3dDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { - buffer->supportsAddress = true; + if (info->usages & PAL_BUFFER_USAGE_STORAGE) { + buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } - buffer->device = d3dDevice->handle; + if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { + buffer->desc.Flags |= D3D12_RESOURCE_FLAG_RAYTRACING_ACCELERATION_STRUCTURE; + } + + if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + buffer->supportsAddress = true; + } + + buffer->device = d3dDevice; *outBuffer = (PalBuffer*)buffer; return PAL_RESULT_SUCCESS; } @@ -5778,10 +5884,12 @@ PalResult PAL_CALL getBufferMemoryRequirementsD3D12( PalMemoryRequirements* requirements) { Buffer* d3dBuffer = (Buffer*)buffer; + ID3D12Device5* device = d3dBuffer->device->handle; + D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; - allocationInfo = *d3dBuffer->device->lpVtbl->GetResourceAllocationInfo( - d3dBuffer->device, + allocationInfo = *device->lpVtbl->GetResourceAllocationInfo( + device, &__ret, 0, 1, @@ -5874,8 +5982,8 @@ PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( for (Uint32 z = 0; z < copyInfo->imageDepth; z++) { for (Uint32 y = 0; y < copyInfo->imageHeight; y++) { memcpy( - dst + z * tmpSizeDest + y * (length * imageFormatSize), - src + z * tmpSizeSrc + y * (copyInfo->imageWidth * imageFormatSize), + dst + z * tmpSizeDest + y * (length * imageFormatSize), + src + z * tmpSizeSrc + y * (copyInfo->imageWidth * imageFormatSize), copyInfo->imageWidth * imageFormatSize); } } @@ -5890,19 +5998,33 @@ PalResult PAL_CALL bindBufferMemoryD3D12( { HRESULT result; Buffer* d3dBuffer = (Buffer*)buffer; - + ID3D12Device5* device = d3dBuffer->device->handle; + + D3D12_RESOURCE_STATES state = 0; ID3D12Heap* mem = (ID3D12Heap*)memory; - result = d3dBuffer->device->lpVtbl->CreatePlacedResource( - d3dBuffer->device, - mem, - offset, - &d3dBuffer->desc, - 0, - nullptr, - &IID_Resource, - (void**)d3dBuffer->handle); + D3D12_HEAP_DESC __ret = {0}; + D3D12_HEAP_DESC heapProps = {0}; + heapProps = *mem->lpVtbl->GetDesc(mem, &__ret); + + if (heapProps.Properties.Type == D3D12_HEAP_TYPE_UPLOAD) { + state = D3D12_RESOURCE_STATE_GENERIC_READ; + + } else if (heapProps.Properties.Type == D3D12_HEAP_TYPE_READBACK) { + state = D3D12_RESOURCE_STATE_COPY_DEST; + } + + result = device->lpVtbl->CreatePlacedResource( + device, + mem, + offset, + &d3dBuffer->desc, + state, + nullptr, + &IID_Resource, + (void**)&d3dBuffer->handle); if (FAILED(result)) { + pollMessagesD3D12(d3dBuffer->device); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } else if (result == E_INVALIDARG) { @@ -5928,7 +6050,7 @@ PalResult PAL_CALL mapBufferMemoryD3D12( } *outPtr = ptr + offset; - return PAL_RESULT_SUCCESS; + return PAL_RESULT_SUCCESS; } void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer) @@ -5943,7 +6065,7 @@ PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer) if (!d3dBuffer->supportsAddress) { return 0; } - + return d3dBuffer->handle->lpVtbl->GetGPUVirtualAddress(d3dBuffer->handle); } @@ -6090,12 +6212,13 @@ PalResult PAL_CALL createDescriptorPoolD3D12( desc.NumDescriptors = resourceCount * info->maxDescriptorSets; result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( - d3dDevice->handle, - &desc, - &IID_DescriptorHeap, + d3dDevice->handle, + &desc, + &IID_DescriptorHeap, (void**)&heap->handle); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -6104,17 +6227,17 @@ PalResult PAL_CALL createDescriptorPoolD3D12( // get increment size heap->incrementSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( - d3dDevice->handle, + d3dDevice->handle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); // get base CPU and GPU base pointer handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( - heap->handle, + heap->handle, &__ret); heap->cpuBase = handle.ptr; gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( - heap->handle, + heap->handle, &__gpuRet); heap->gpuBase = gpuHandle.ptr; @@ -6133,13 +6256,14 @@ PalResult PAL_CALL createDescriptorPoolD3D12( desc.NumDescriptors = limits->maxSamplers * info->maxDescriptorSets; result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( - d3dDevice->handle, - &desc, - &IID_DescriptorHeap, + d3dDevice->handle, + &desc, + &IID_DescriptorHeap, (void**)&heap->handle); if (FAILED(result)) { if (result == E_OUTOFMEMORY) { + pollMessagesD3D12(d3dDevice); return PAL_RESULT_OUT_OF_MEMORY; } return PAL_RESULT_PLATFORM_FAILURE; @@ -6147,17 +6271,17 @@ PalResult PAL_CALL createDescriptorPoolD3D12( // get increment size heap->incrementSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( - d3dDevice->handle, + d3dDevice->handle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); // get base CPU and GPU base pointer handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( - heap->handle, + heap->handle, &__ret); heap->cpuBase = handle.ptr; gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( - heap->handle, + heap->handle, &__gpuRet); heap->gpuBase = gpuHandle.ptr; @@ -6185,7 +6309,7 @@ PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool) d3dPool->resourceHeap.nextOffset = 0; d3dPool->samplerHeap.nextOffset = 0; d3dPool->usedSets = 0; - + d3dPool->limits.usedAs = 0; d3dPool->limits.usedSampledImages = 0; d3dPool->limits.usedSamplers = 0; @@ -6313,17 +6437,19 @@ PalResult PAL_CALL updateDescriptorSetD3D12( DescriptorSetBinding* binding = &layout->bindings[info->binding]; DescriptorHeap* heap = nullptr; + Uint32 index = 0; + Uint32 bindingOffsetffset = binding->range.OffsetInDescriptorsFromTableStart; + if (info->arrayElement + binding->range.NumDescriptors > layout->bindingCount) { + return PAL_RESULT_INVALID_ARGUMENT; + } + if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { heap = &pool->samplerHeap; + index = set->samplerOffset + bindingOffsetffset + info->arrayElement; + } else { heap = &pool->resourceHeap; - } - - // compute the heap index and copy all the descriptors - Uint32 bindingOffsetffset = binding->range.OffsetInDescriptorsFromTableStart; - Uint32 index = heap->nextOffset + bindingOffsetffset + info->arrayElement; - if (info->arrayElement + binding->range.NumDescriptors > layout->bindingCount) { - return PAL_RESULT_INVALID_ARGUMENT; + index = set->resourceOffset + bindingOffsetffset + info->arrayElement; } for (int y = 0; y < binding->range.NumDescriptors; y++) { @@ -6341,9 +6467,9 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; d3dDevice->handle->lpVtbl->CreateShaderResourceView( - d3dDevice->handle, - nullptr, - &desc, + d3dDevice->handle, + nullptr, + &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { @@ -6351,17 +6477,17 @@ PalResult PAL_CALL updateDescriptorSetD3D12( D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; desc.Format = imageView->format; fillSubresourceD3D12( - imageView->type, - &imageView->range, - nullptr, - nullptr, - &desc, + imageView->type, + &imageView->range, + nullptr, + nullptr, + &desc, nullptr); d3dDevice->handle->lpVtbl->CreateShaderResourceView( - d3dDevice->handle, - imageView->image->handle, - &desc, + d3dDevice->handle, + imageView->image->handle, + &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { @@ -6369,18 +6495,18 @@ PalResult PAL_CALL updateDescriptorSetD3D12( D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; desc.Format = imageView->format; fillSubresourceD3D12( - imageView->type, - &imageView->range, - nullptr, - nullptr, + imageView->type, + &imageView->range, + nullptr, + nullptr, nullptr, &desc); d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( d3dDevice->handle, - imageView->image->handle, + imageView->image->handle, nullptr, - &desc, + &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { @@ -6394,7 +6520,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( d3dDevice->handle->lpVtbl->CreateConstantBufferView( d3dDevice->handle, - &desc, + &desc, dst); } else { @@ -6405,11 +6531,12 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.Buffer.FirstElement = info->bufferInfo->offset; desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; desc.Buffer.NumElements = info->bufferInfo->size; + desc.Format = DXGI_FORMAT_R32_TYPELESS; d3dDevice->handle->lpVtbl->CreateShaderResourceView( - d3dDevice->handle, + d3dDevice->handle, buffer->handle, - &desc, + &desc, dst); } else { @@ -6418,12 +6545,13 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.Buffer.FirstElement = info->bufferInfo->offset; desc.Buffer.NumElements = info->bufferInfo->size; desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; + desc.Format = DXGI_FORMAT_R32_TYPELESS; d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( d3dDevice->handle, buffer->handle, nullptr, - &desc, + &desc, dst); } } @@ -6448,14 +6576,14 @@ PalResult PAL_CALL createPipelineLayoutD3D12( Uint32 pushConstantSize = 0; D3D12_DESCRIPTOR_RANGE1* ranges = nullptr; D3D12_DESCRIPTOR_RANGE1* samplerRanges = nullptr; - + // get the total resource and sampler ranges for all provided descriptor set layouts for (int i = 0; i < info->descriptorSetLayoutCount; i++) { - DescriptorSetLayout* tmp = (DescriptorSetLayout*)&info->descriptorSetLayouts[i]; + DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; resourceCount += tmp->bindingCount - tmp->samplerCount; samplerCount += tmp->samplerCount; } - + // get the total size needed for all provided push constant range for (int i = 0; i < info->pushConstantRangeCount; i++) { PalPushConstantRange* tmp = &info->pushConstantRanges[i]; @@ -6473,7 +6601,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } for (int i = 0; i < info->descriptorSetLayoutCount; i++) { - DescriptorSetLayout* tmp = (DescriptorSetLayout*)&info->descriptorSetLayouts[i]; + DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; // seperate the samplers from the remaining descriptors for (int i = 0; i < tmp->bindingCount; i++) { DescriptorSetBinding* binding = &tmp->bindings[i]; @@ -6535,21 +6663,24 @@ PalResult PAL_CALL createPipelineLayoutD3D12( ID3DBlob* blob = nullptr; HRESULT result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } return PAL_RESULT_PLATFORM_FAILURE; } + // TODO: fix buffer size result = d3dDevice->handle->lpVtbl->CreateRootSignature( - d3dDevice->handle, - 0, - blob->lpVtbl->GetBufferPointer(blob), - blob->lpVtbl->GetBufferSize(blob), + d3dDevice->handle, + 0, + blob->lpVtbl->GetBufferPointer(blob), + blob->lpVtbl->GetBufferSize(blob), &IID_RootSignature, (void**)&layout->handle); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } else if (result == E_OUTOFMEMORY) { @@ -6617,8 +6748,8 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( if (info->renderingLayout->viewCount > 1) { viewLocations = palAllocate( - s_D3D.allocator, - sizeof(D3D12_VIEW_INSTANCE_LOCATION) * info->renderingLayout->viewCount, + s_D3D.allocator, + sizeof(D3D12_VIEW_INSTANCE_LOCATION) * info->renderingLayout->viewCount, 0); if (!viewLocations) { @@ -6690,8 +6821,8 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( } elementDescs = palAllocate( - s_D3D.allocator, - sizeof(D3D12_INPUT_ELEMENT_DESC) * vertexCount, + s_D3D.allocator, + sizeof(D3D12_INPUT_ELEMENT_DESC) * vertexCount, 0); if (!elementDescs) { @@ -6984,12 +7115,13 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( streamDesc.SizeInBytes = totalSize; result = d3dDevice->handle->lpVtbl->CreatePipelineState( - d3dDevice->handle, + d3dDevice->handle, &streamDesc, - &IID_PipelineState, + &IID_PipelineState, &pipeline->handle); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } else if (result == E_OUTOFMEMORY) { @@ -7043,6 +7175,7 @@ PalResult PAL_CALL createComputePipelineD3D12( &pipeline->handle); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } else if (result == E_OUTOFMEMORY) { @@ -7179,12 +7312,13 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( desc.pSubobjects = subObjects; result = d3dDevice->handle->lpVtbl->CreateStateObject( - d3dDevice->handle, - &desc, - &IID_StateObject, + d3dDevice->handle, + &desc, + &IID_StateObject, &pipeline->handle); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } else if (result == E_OUTOFMEMORY) { @@ -7272,6 +7406,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( (void**)&props); if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_PIPELINE; } @@ -7317,12 +7452,12 @@ PalResult PAL_CALL createShaderBindingTableD3D12( bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; result = d3dDevice->handle->lpVtbl->CreateCommittedResource( - d3dDevice->handle, - &heapProps, - 0, - &bufferDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, + d3dDevice->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, &IID_Resource, (void**)&sbt->buffer); if (FAILED(result)) { @@ -7345,7 +7480,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( } else if (stage == PAL_SHADER_STAGE_MISS) { missHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->exports.Name); - } else if (stage == PAL_SHADER_STAGE_ANY_HIT || + } else if (stage == PAL_SHADER_STAGE_ANY_HIT || stage == PAL_SHADER_STAGE_CLOSEST_HIT || stage == PAL_SHADER_STAGE_INTERSECTION) { hitHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->exports.Name); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 6917da7c..e58b377a 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -2042,15 +2042,15 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - result = initGraphicsVk(debugger, allocator); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - - attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base = &s_VkBackend; - attachedBackend->startIndex = 0; - attachedBackend->count = 0; + // result = initGraphicsVk(debugger, allocator); + // if (result != PAL_RESULT_SUCCESS) { + // return result; + // } + + // attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + // attachedBackend->base = &s_VkBackend; + // attachedBackend->startIndex = 0; + // attachedBackend->count = 0; // TODO: uncomment #endif // PAL_HAS_VULKAN // D3D12 diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 4acc24a4..40a381e8 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -4790,8 +4790,6 @@ PalResult PAL_CALL queryRayTracingCapabilitiesVk( caps->maxPayloadSize = INT32_MAX; // depends on memory caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; - caps->RequiresShaderExportName = false; - caps->RequiresShaderGroupExportName = false; return PAL_RESULT_SUCCESS; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index d1166a09..ee4d8d0d 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -41,11 +41,11 @@ bool computeTest() PalPipeline* pipeline = nullptr; PalFence* fence = nullptr; - PalGraphicsDebugger debugger; + PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -168,6 +168,9 @@ bool computeTest() const char* shaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { shaderPath = "graphics/shaders/compute_shader.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + shaderPath = "graphics/shaders/compute_shader.dxil"; } if (!readFile(shaderPath, nullptr, &bytecodeSize)) { @@ -220,7 +223,6 @@ bool computeTest() PalMemoryRequirements bufferMemReq = {0}; PalMemoryRequirements stagingBufferMemReq = {0}; result = palGetBufferMemoryRequirements(buffer, &bufferMemReq); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); diff --git a/tests/graphics/shaders/compute_shader.dxil b/tests/graphics/shaders/compute_shader.dxil new file mode 100644 index 0000000000000000000000000000000000000000..44f34dff066ebbb468a778ed97e34c7295aff6cc GIT binary patch literal 3416 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 UJVWT2-ik2>`6R_^0m%URC&A1;5C8xG literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/compute_shader.hlsl b/tests/graphics/shaders/compute_shader.hlsl new file mode 100644 index 00000000..f02e313b --- /dev/null +++ b/tests/graphics/shaders/compute_shader.hlsl @@ -0,0 +1,22 @@ + +struct PushConstants +{ + uint width; + uint height; + float4 color; +}; + +RWByteAddressBuffer outBuffer : register(u0); +ConstantBuffer pc : register(b0); + +[numThreads(16, 16, 1)] +void main(uint3 id : SV_DispatchThreadID) +{ + if (id.x >= pc.width || id.y >= pc.height) { + return; + } + + uint index = id.y * pc.width + id.x; + uint offset = index * 16; // sizeof(float4) + outBuffer.Store4(offset, asuint(pc.color)); +} \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index f62e99aa..b0359452 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,7 +58,7 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - // registerTest(computeTest, "Compute Test"); + registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS @@ -66,7 +66,7 @@ int main(int argc, char** argv) // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); - registerTest(textureTest, "Texture Test"); + // registerTest(textureTest, "Texture Test"); #endif // runTests(); From beef1bc3a33b428b8e6473f0f8d5f029ea90d942 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 24 Apr 2026 15:41:10 +0000 Subject: [PATCH 178/372] compute test working on d3d12 --- include/pal/pal_graphics.h | 108 +++++++-- src/graphics/pal_d3d12.c | 382 ++++++++++++++++++++++-------- src/graphics/pal_graphics.c | 60 ++++- src/graphics/pal_vulkan.c | 100 ++++++-- tests/graphics/compute_test.c | 47 ++-- tests/graphics/graphics_test.c | 101 ++++---- tests/graphics/ray_tracing_test.c | 2 +- tests/graphics/texture_test.c | 7 +- 8 files changed, 604 insertions(+), 203 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d78c939f..352e69ff 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -47,13 +47,6 @@ freely, subject to the following restrictions: */ #define PAL_ADAPTER_NAME_SIZE 128 -/** - * @brief The maximum version string size of an adapter. - * @since 1.4 - * @ingroup pal_graphics - */ -#define PAL_ADAPTER_VERSION_SIZE 16 - #define PAL_MAX_RESOLVE_MODES 8 #define PAL_MAX_COMBINER_OPS 8 @@ -544,6 +537,36 @@ typedef enum { PAL_SHADER_FORMAT_PPM = PAL_BIT(5) } PalShaderFormats; +/** + * @enum PalShaderTarget + * @brief Shader targets. + * + * All shader targets follow the format `PAL_SHADER_TARGET_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef enum { + PAL_SHADER_TARGET_UNKNOWN, + PAL_SHADER_TARGET_SPIRV_1_0, + PAL_SHADER_TARGET_SPIRV_1_1, + PAL_SHADER_TARGET_SPIRV_1_2, + PAL_SHADER_TARGET_SPIRV_1_3, + PAL_SHADER_TARGET_SPIRV_1_4, + PAL_SHADER_TARGET_SPIRV_1_5, + PAL_SHADER_TARGET_SPIRV_1_6, + PAL_SHADER_TARGET_DXIL_5_1, + PAL_SHADER_TARGET_DXIL_6_0, + PAL_SHADER_TARGET_DXIL_6_1, + PAL_SHADER_TARGET_DXIL_6_2, + PAL_SHADER_TARGET_DXIL_6_3, + PAL_SHADER_TARGET_DXIL_6_4, + PAL_SHADER_TARGET_DXIL_6_5, + PAL_SHADER_TARGET_DXIL_6_6, + PAL_SHADER_TARGET_DXIL_6_7 +} PalShaderTarget; + /** * @enum PalAdapterFeatures * @brief Adapter features. This is a bitmask. @@ -1417,8 +1440,6 @@ typedef struct { PalShaderFormats shaderFormats; /**< Supported shader formats mask (eg. Spirv, DXIL, ect).*/ Uint64 vram; Uint64 sharedMemory; - Uint64 version; /**< Adapter version.*/ - char versionString[PAL_ADAPTER_VERSION_SIZE]; /**< Adapter version in string.*/ char name[PAL_ADAPTER_NAME_SIZE]; char backendName[PAL_ADAPTER_NAME_SIZE]; /**< Adapter backend name (eg. `PAL`, `Custom`).*/ } PalAdapterInfo; @@ -2237,8 +2258,9 @@ typedef struct { */ typedef struct { bool readOnly; /**< For PAL_DESCRIPTOR_TYPE_STORAGE.*/ - Uint32 size; - Uint64 offset; + Uint32 size; + Uint32 stride; /**< For structured buffers. Will be ignored if not supported. 0 for default.*/ + Uint64 offset; /**< Offset in bytes. If structured, will be divided by `stride`.*/ PalBuffer* buffer; } PalDescriptorBufferInfo; @@ -2715,6 +2737,24 @@ typedef struct { */ PalAdapterFeatures PAL_CALL (*getAdapterFeatures)(PalAdapter* adapter); + /** + * Backend implementation of ::palIsShaderTargetSupported. + * + * Must obey the rules and semantics documented in palIsShaderTargetSupported(). + */ + bool PAL_CALL (*isShaderTargetSupported)( + PalAdapter* adapter, + PalShaderTarget target); + + /** + * Backend implementation of ::palGetHighestSupportedShaderTarget. + * + * Must obey the rules and semantics documented in palGetHighestSupportedShaderTarget(). + */ + PalShaderTarget PAL_CALL (*getHighestSupportedShaderTarget)( + PalAdapter* adapter, + PalShaderFormats shaderFormat); + /** * Backend implementation of ::palCreateDevice. * @@ -3578,7 +3618,6 @@ typedef struct { */ PalResult PAL_CALL (*cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set); @@ -3589,7 +3628,6 @@ typedef struct { */ PalResult PAL_CALL (*cmdPushConstants)( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -4096,6 +4134,46 @@ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( */ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); +/** + * @brief Check if the provided shader target is supported by an adapter (GPU). + * + * The graphics system must be initialized before this call. + * + * @param[in] adapter Adapter to query. + * + * @return True if target is supported otherwise false. + * + * Thread safety: Thread safe. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palEnumerateAdapters + */ +PAL_API bool PAL_CALL palIsShaderTargetSupported( + PalAdapter* adapter, + PalShaderTarget target); + +/** + * @brief Get the highest supported shader target of an adapter (GPU). + * + * The graphics system must be initialized before this call. + * + * @param[in] adapter Adapter to query. + * @param[in] shaderFormat The shader format. Must have only a single bit set. + * + * @return The highest supported shader target on success or `PAL_SHADER_TARGET_UNKNOWN` + * on failure. + * + * Thread safety: Thread safe. + * + * @since 1.4 + * @ingroup pal_graphics + * @sa palEnumerateAdapters + */ +PAL_API PalShaderTarget PAL_CALL palGetHighestSupportedShaderTarget( + PalAdapter* adapter, + PalShaderFormats shaderFormat); + /** * @brief Create a device from an adapter (GPU). * @@ -6352,7 +6430,6 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] layout The pipeline layout that defines the descriptor interface. * @param[in] setIndex Index of the descriptor set to bind. * @param[in] set Descriptor set to bind. Must be compatible with `layout`. * @@ -6368,7 +6445,6 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( */ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set); @@ -6378,7 +6454,6 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] layout The pipeline layout that defines the push constant range. * @param[in] shaderStageCount Capacity of the PalShaderStage array. * @param[in] shaderStages Array of shader stages that can access the push constant. * @param[in] offset Offset in bytes into the push constant range. @@ -6397,7 +6472,6 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( */ PAL_API PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 8886a078..dc4216b1 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -234,12 +234,11 @@ typedef struct { const PalGraphicsBackend* backend; bool primary; - Uint32 pipelineType; - Uint32* strides; void* pool; // CommandPool Device* device; ID3D12Resource* tmpBuffer; ID3D12CommandAllocator* allocator; + void* pipeline; ID3D12GraphicsCommandList6* handle; } CommandBuffer; @@ -252,6 +251,7 @@ typedef struct { const PalGraphicsBackend* backend; Uint32 size; + D3D12_COMMAND_LIST_TYPE type; CommandBufferData* cmdBuffersData; } CommandPool; @@ -259,6 +259,7 @@ typedef struct { const PalGraphicsBackend* backend; bool supportsAddress; + bool canChangeState; Uint64 size; ID3D12Resource* handle; Device* device; @@ -279,6 +280,16 @@ typedef struct { D3D12_DXIL_LIBRARY_DESC dxil; } RayTracingShader; +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 constantIndex; + Uint32 resourceIndex; + Uint32 samplerIndex; + ID3D12RootSignature* handle; + D3D12_ROOT_PARAMETER1 params[3]; +} PipelineLayout; + typedef struct { const PalGraphicsBackend* backend; @@ -290,6 +301,7 @@ typedef struct { void* handle; wchar_t* scratchBuffer; RayTracingShader* shaders; + PipelineLayout* layout; D3D12_SHADING_RATE_COMBINER combinerOps[2]; } Pipeline; @@ -363,14 +375,6 @@ typedef struct { DescriptorSet* sets; } DescriptorPool; -typedef struct { - Uint32 constantIndex; - Uint32 resourceIndex; - Uint32 samplerIndex; - ID3D12RootSignature* handle; - D3D12_ROOT_PARAMETER1 params[3]; -} PipelineLayout; - typedef struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; ID3D12RootSignature* root; @@ -418,11 +422,6 @@ typedef struct { DXGI_FORMAT RTVFormats[8]; } RenderingLayoutStream; -typedef struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_PIPELINE_STATE_FLAGS flags; -} PipelineFlagsStream; - typedef struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; D3D12_SHADER_BYTECODE desc; @@ -443,7 +442,6 @@ typedef struct { ColorBlendStream colorBlend; RenderingLayoutStream renderingLayout; ViewInstancingStream viewInstancing; - PipelineFlagsStream flags; } FixedPipelineHeader; typedef struct { @@ -1179,7 +1177,7 @@ static DXGI_FORMAT vertexTypeToD3D12(PalVertexType type) return DXGI_FORMAT_UNKNOWN; } -static void fillVkBuildInfoD3D12( +static void fillBuildInfoD3D12( PalAccelerationStructureBuildInfo* info, D3D12_RAYTRACING_GEOMETRY_DESC* geometries, D3D12_GPU_VIRTUAL_ADDRESS srcAs, @@ -2148,23 +2146,6 @@ PalResult PAL_CALL getAdapterInfoD3D12( info->vram = desc.DedicatedSystemMemory; } - info->version = d3dAdapter->level; - if (d3dAdapter->level == D3D_FEATURE_LEVEL_12_2) { - strcpy(info->versionString, "12_2"); - - } else if (d3dAdapter->level == D3D_FEATURE_LEVEL_12_1) { - strcpy(info->versionString, "12_1"); - - } else if (d3dAdapter->level == D3D_FEATURE_LEVEL_12_0) { - strcpy(info->versionString, "12_0"); - - } else if (d3dAdapter->level == D3D_FEATURE_LEVEL_11_1) { - strcpy(info->versionString, "11_1"); - - } else if (d3dAdapter->level == D3D_FEATURE_LEVEL_11_0) { - strcpy(info->versionString, "11_0"); - } - return PAL_RESULT_SUCCESS; } @@ -2348,6 +2329,170 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) return features; } +bool PAL_CALL isShaderTargetSupportedD3D12( + PalAdapter* adapter, + PalShaderTarget target) +{ + Adapter* d3dAdapter = (Adapter*)adapter; + D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; + + D3D_SHADER_MODEL models[8]; + models[0] = D3D_SHADER_MODEL_6_7; + models[1] = D3D_SHADER_MODEL_6_6; + models[2] = D3D_SHADER_MODEL_6_5; + models[3] = D3D_SHADER_MODEL_6_4; + models[4] = D3D_SHADER_MODEL_6_3; + models[5] = D3D_SHADER_MODEL_6_2; + models[6] = D3D_SHADER_MODEL_6_1; + models[7] = D3D_SHADER_MODEL_6_0; + models[8] = D3D_SHADER_MODEL_5_1; + + // find the highest supported shader model + HRESULT result = 0; + D3D_SHADER_MODEL highestModel = D3D_SHADER_MODEL_5_1; + for (int i = 0; i < 8; i++) { + shaderModel.HighestShaderModel = models[i]; + result = d3dAdapter->tmpDevice->lpVtbl->CheckFeatureSupport( + d3dAdapter->tmpDevice, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + if (shaderModel.HighestShaderModel >= models[i] && result == S_OK) { + highestModel = models[i]; + break; + } + } + + switch (target) { + case PAL_SHADER_TARGET_DXIL_5_1: { + if (highestModel >= D3D_SHADER_MODEL_5_1) { + return true; + } + } + + case PAL_SHADER_TARGET_DXIL_6_0: { + if (highestModel >= D3D_SHADER_MODEL_6_0) { + return true; + } + } + + + case PAL_SHADER_TARGET_DXIL_6_1: { + if (highestModel >= D3D_SHADER_MODEL_6_1) { + return true; + } + } + + case PAL_SHADER_TARGET_DXIL_6_2: { + if (highestModel >= D3D_SHADER_MODEL_6_2) { + return true; + } + } + + case PAL_SHADER_TARGET_DXIL_6_3: { + if (highestModel >= D3D_SHADER_MODEL_6_3) { + return true; + } + } + + case PAL_SHADER_TARGET_DXIL_6_4: { + if (highestModel >= D3D_SHADER_MODEL_6_4) { + return true; + } + } + + case PAL_SHADER_TARGET_DXIL_6_5: { + if (highestModel >= D3D_SHADER_MODEL_6_5) { + return true; + } + } + case PAL_SHADER_TARGET_DXIL_6_6: { + if (highestModel >= D3D_SHADER_MODEL_6_6) { + return true; + } + } + + case PAL_SHADER_TARGET_DXIL_6_7: { + if (highestModel >= D3D_SHADER_MODEL_6_7) { + return true; + } + } + } + + return false; +} + +PalShaderTarget PAL_CALL getHighestSupportedShaderTargetD3D12( + PalAdapter* adapter, + PalShaderTarget shaderFormat) +{ + if (shaderFormat != PAL_SHADER_FORMAT_DXIL) { + return PAL_SHADER_TARGET_UNKNOWN; + } + + Adapter* d3dAdapter = (Adapter*)adapter; + D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; + + D3D_SHADER_MODEL models[8]; + models[0] = D3D_SHADER_MODEL_6_7; + models[1] = D3D_SHADER_MODEL_6_6; + models[2] = D3D_SHADER_MODEL_6_5; + models[3] = D3D_SHADER_MODEL_6_4; + models[4] = D3D_SHADER_MODEL_6_3; + models[5] = D3D_SHADER_MODEL_6_2; + models[6] = D3D_SHADER_MODEL_6_1; + models[7] = D3D_SHADER_MODEL_6_0; + models[8] = D3D_SHADER_MODEL_5_1; + + // find the highest supported shader model + HRESULT result = 0; + D3D_SHADER_MODEL highestModel = D3D_SHADER_MODEL_5_1; + for (int i = 0; i < 8; i++) { + shaderModel.HighestShaderModel = models[i]; + result = d3dAdapter->tmpDevice->lpVtbl->CheckFeatureSupport( + d3dAdapter->tmpDevice, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + if (shaderModel.HighestShaderModel >= models[i] && result == S_OK) { + highestModel = models[i]; + break; + } + } + + if (highestModel >= D3D_SHADER_MODEL_6_7) { + return PAL_SHADER_TARGET_DXIL_6_7; + + } else if (highestModel >= D3D_SHADER_MODEL_6_6) { + return PAL_SHADER_TARGET_DXIL_6_6; + + } else if (highestModel >= D3D_SHADER_MODEL_6_5) { + return PAL_SHADER_TARGET_DXIL_6_5; + + } else if (highestModel >= D3D_SHADER_MODEL_6_4) { + return PAL_SHADER_TARGET_DXIL_6_4; + + } else if (highestModel >= D3D_SHADER_MODEL_6_3) { + return PAL_SHADER_TARGET_DXIL_6_3; + + } else if (highestModel >= D3D_SHADER_MODEL_6_2) { + return PAL_SHADER_TARGET_DXIL_6_2; + + } else if (highestModel >= D3D_SHADER_MODEL_6_1) { + return PAL_SHADER_TARGET_DXIL_6_1; + + } else if (highestModel >= D3D_SHADER_MODEL_6_0) { + return PAL_SHADER_TARGET_DXIL_6_0; + + } else if (highestModel >= D3D_SHADER_MODEL_5_1) { + return PAL_SHADER_TARGET_DXIL_5_1; + } + + return PAL_SHADER_TARGET_UNKNOWN; +} + // ================================================== // Device // ================================================== @@ -2600,7 +2745,6 @@ PalResult PAL_CALL createDeviceD3D12( void PAL_CALL destroyDeviceD3D12(PalDevice* device) { Device* d3dDevice = (Device*)device; - if (d3dDevice->meshSignature) { d3dDevice->meshSignature->lpVtbl->Release(d3dDevice->meshSignature); } @@ -3887,6 +4031,7 @@ PalResult PAL_CALL resizeSwapchainD3D12( d3dSwapchain->flags); if (FAILED(result)) { + pollMessagesD3D12(d3dSwapchain->device); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } @@ -3931,6 +4076,7 @@ PalResult PAL_CALL createShaderD3D12( { Device* d3dDevice = (Device*)device; Shader* shader = nullptr; + void* bytecode = nullptr; if (info->stage == PAL_SHADER_STAGE_MESH || info->stage == PAL_SHADER_STAGE_TASK) { if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { @@ -3955,11 +4101,13 @@ PalResult PAL_CALL createShaderD3D12( // clang-format on shader = palAllocate(s_D3D.allocator, sizeof(Shader), 0); - if (!shader) { + bytecode = palAllocate(s_D3D.allocator, info->bytecodeSize, 0); + if (!shader || !bytecode) { return PAL_RESULT_OUT_OF_MEMORY; } - shader->byteCode.pShaderBytecode = info->bytecode; + memcpy(bytecode, info->bytecode, info->bytecodeSize); + shader->byteCode.pShaderBytecode = bytecode; shader->byteCode.BytecodeLength = info->bytecodeSize; shader->stage = info->stage; shader->patchControlPoints = info->patchControlPoints; @@ -3971,6 +4119,7 @@ PalResult PAL_CALL createShaderD3D12( void PAL_CALL destroyShaderD3D12(PalShader* shader) { Shader* d3dShader = (Shader*)shader; + palFree(s_D3D.allocator, (void*)d3dShader->byteCode.pShaderBytecode); palFree(s_D3D.allocator, d3dShader); } @@ -4221,6 +4370,7 @@ PalResult PAL_CALL createCommandPoolD3D12( { HRESULT result; CommandPool* pool = nullptr; + Queue* d3dQueue = (Queue*)queue; pool = palAllocate(s_D3D.allocator, sizeof(CommandPool), 0); if (!pool) { @@ -4235,6 +4385,20 @@ PalResult PAL_CALL createCommandPoolD3D12( return PAL_RESULT_OUT_OF_MEMORY; } + switch (d3dQueue->type) { + case PAL_QUEUE_TYPE_COMPUTE: { + pool->type = D3D12_COMMAND_LIST_TYPE_COMPUTE; + } + + case PAL_QUEUE_TYPE_GRAPHICS: { + pool->type = D3D12_COMMAND_LIST_TYPE_DIRECT; + } + + case PAL_QUEUE_TYPE_COPY: { + pool->type = D3D12_COMMAND_LIST_TYPE_COPY; + } + } + *outPool = (PalCommandPool*)pool; return PAL_RESULT_SUCCESS; } @@ -4286,8 +4450,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - D3D12_COMMAND_LIST_TYPE cmdBufferType = D3D12_COMMAND_LIST_TYPE_DIRECT; cmdBuffer->primary = true; + D3D12_COMMAND_LIST_TYPE cmdBufferType = cmdPool->type; if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { cmdBufferType = D3D12_COMMAND_LIST_TYPE_BUNDLE; cmdBuffer->primary = false; @@ -4364,7 +4528,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdBuffer->handle); cmdList->lpVtbl->Release(cmdList); - cmdBuffer->strides = nullptr; + cmdBuffer->handle->lpVtbl->Close(cmdBuffer->handle); + cmdBuffer->pool = cmdPool; cmdBuffer->device = d3dDevice; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; @@ -4393,6 +4558,7 @@ PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; result = d3dCmdBuffer->allocator->lpVtbl->Reset(d3dCmdBuffer->allocator); if (FAILED(result)) { + pollMessagesD3D12(d3dCmdBuffer->device); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_COMMAND_BUFFER; } @@ -4404,7 +4570,7 @@ PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) d3dCmdBuffer->allocator, nullptr); - d3dCmdBuffer->strides = nullptr; + d3dCmdBuffer->pipeline = nullptr; return PAL_RESULT_SUCCESS; } @@ -4609,7 +4775,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( } memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); - fillVkBuildInfoD3D12( + fillBuildInfoD3D12( info, geometries, srcAsAddress, @@ -4625,7 +4791,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( palFree(s_D3D.allocator, geometries); } else { - fillVkBuildInfoD3D12( + fillBuildInfoD3D12( info, nullptr, srcAsAddress, @@ -4958,6 +5124,7 @@ PalResult PAL_CALL cmdBindPipelineD3D12( { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* d3dPipeline = (Pipeline*)pipeline; + if (d3dPipeline->type == RAY_TRACING_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetPipelineState1( d3dCmdBuffer->handle, @@ -4973,17 +5140,25 @@ PalResult PAL_CALL cmdBindPipelineD3D12( d3dCmdBuffer->handle, d3dPipeline->topology); + d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootSignature( + d3dCmdBuffer->handle, + d3dPipeline->layout->handle); + if (d3dPipeline->hasFsr) { d3dCmdBuffer->handle->lpVtbl->RSSetShadingRate( d3dCmdBuffer->handle, d3dPipeline->shadingRate, d3dPipeline->combinerOps); } + + } else if (d3dPipeline->type == COMPUTE_PIPELINE) { + d3dCmdBuffer->handle->lpVtbl->SetComputeRootSignature( + d3dCmdBuffer->handle, + d3dPipeline->layout->handle); } } - d3dCmdBuffer->pipelineType = d3dPipeline->type; - d3dCmdBuffer->strides = d3dPipeline->strides; + d3dCmdBuffer->pipeline = d3dPipeline; return PAL_RESULT_SUCCESS; } @@ -5065,10 +5240,11 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( Uint64* offsets) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Pipeline* pipeline = d3dCmdBuffer->pipeline; D3D12_VERTEX_BUFFER_VIEW cachedView = {0}; D3D12_VERTEX_BUFFER_VIEW* views = nullptr; - if (!d3dCmdBuffer->strides) { + if (!pipeline) { return PAL_RESULT_INVALID_OPERATION; } @@ -5087,7 +5263,7 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( views[i].BufferLocation = tmp->handle->lpVtbl->GetGPUVirtualAddress(tmp->handle); views[i].BufferLocation = views[i].BufferLocation + offsets[i]; views[i].SizeInBytes = tmp->size; - views[i].StrideInBytes = d3dCmdBuffer->strides[i]; + views[i].StrideInBytes = pipeline->strides[i]; } d3dCmdBuffer->handle->lpVtbl->IASetVertexBuffers( @@ -5399,6 +5575,9 @@ PalResult PAL_CALL cmdBufferBarrierD3D12( CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* d3dBuffer = (Buffer*)buffer; D3D12_RESOURCE_STATES old, new; + if (!d3dBuffer->canChangeState) { + return PAL_RESULT_SUCCESS; + } old = barrierToD3D12( oldUsageStateInfo->shaderStageCount, @@ -5573,13 +5752,12 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + Pipeline* pipeline = d3dCmdBuffer->pipeline; DescriptorSet* d3dSet = (DescriptorSet*)set; - PipelineLayout* pipelineLayout = (PipelineLayout*)layout; DescriptorPool* pool = d3dSet->pool; // bind heaps @@ -5595,7 +5773,7 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( d3dCmdBuffer->handle->lpVtbl->SetDescriptorHeaps(d3dCmdBuffer->handle, heapCount, heaps); // bind descriptor tables - if (pipelineLayout->resourceIndex != UINT32_MAX) { + if (pipeline->layout->resourceIndex != UINT32_MAX) { // a valid index D3D12_GPU_DESCRIPTOR_HANDLE base; base.ptr = getDescriptorHandleD3D12( @@ -5603,22 +5781,22 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( pool->resourceHeap.incrementSize, pool->resourceHeap.gpuBase); - if (d3dCmdBuffer->pipelineType == GRAPHICS_PIPELINE) { + if (pipeline->type == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( d3dCmdBuffer->handle, - pipelineLayout->resourceIndex, - base); + pipeline->layout->resourceIndex, + base); } else { // ray tracing uses the compute path d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( - d3dCmdBuffer->handle, - pipelineLayout->resourceIndex, - base); + d3dCmdBuffer->handle, + pipeline->layout->resourceIndex, + base); } } - if (pipelineLayout->samplerIndex != UINT32_MAX) { + if (pipeline->layout->samplerIndex != UINT32_MAX) { // a valid index D3D12_GPU_DESCRIPTOR_HANDLE base; base.ptr = getDescriptorHandleD3D12( @@ -5626,18 +5804,18 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( pool->samplerHeap.incrementSize, pool->samplerHeap.gpuBase); - if (d3dCmdBuffer->pipelineType == GRAPHICS_PIPELINE) { + if (pipeline->type == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( d3dCmdBuffer->handle, - pipelineLayout->samplerIndex, - base); + pipeline->layout->samplerIndex, + base); } else { // ray tracing uses the compute path d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( - d3dCmdBuffer->handle, - pipelineLayout->samplerIndex, - base); + d3dCmdBuffer->handle, + pipeline->layout->samplerIndex, + base); } } @@ -5646,7 +5824,6 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalResult PAL_CALL cmdPushConstantsD3D12( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -5654,12 +5831,13 @@ PalResult PAL_CALL cmdPushConstantsD3D12( const void* value) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - PipelineLayout* pipelineLayout = (PipelineLayout*)layout; - if (pipelineLayout->constantIndex != UINT32_MAX) { - if (d3dCmdBuffer->pipelineType == GRAPHICS_PIPELINE) { + Pipeline* pipeline = d3dCmdBuffer->pipeline; + + if (pipeline->layout->constantIndex != UINT32_MAX) { + if (pipeline->type == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRoot32BitConstants( d3dCmdBuffer->handle, - pipelineLayout->constantIndex, + pipeline->layout->constantIndex, size / 4, value, offset / 4); @@ -5668,7 +5846,7 @@ PalResult PAL_CALL cmdPushConstantsD3D12( // ray tracing uses the compute path d3dCmdBuffer->handle->lpVtbl->SetComputeRoot32BitConstants( d3dCmdBuffer->handle, - pipelineLayout->constantIndex, + pipeline->layout->constantIndex, size / 4, value, offset / 4); @@ -5787,7 +5965,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( } memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); - fillVkBuildInfoD3D12( + fillBuildInfoD3D12( info, geometries, 0, @@ -5802,7 +5980,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( palFree(s_D3D.allocator, geometries); } else { - fillVkBuildInfoD3D12( + fillBuildInfoD3D12( info, nullptr, 0, @@ -6006,11 +6184,14 @@ PalResult PAL_CALL bindBufferMemoryD3D12( D3D12_HEAP_DESC heapProps = {0}; heapProps = *mem->lpVtbl->GetDesc(mem, &__ret); + d3dBuffer->canChangeState = true; if (heapProps.Properties.Type == D3D12_HEAP_TYPE_UPLOAD) { state = D3D12_RESOURCE_STATE_GENERIC_READ; + d3dBuffer->canChangeState = false; } else if (heapProps.Properties.Type == D3D12_HEAP_TYPE_READBACK) { state = D3D12_RESOURCE_STATE_COPY_DEST; + d3dBuffer->canChangeState = false; } result = device->lpVtbl->CreatePlacedResource( @@ -6046,6 +6227,7 @@ PalResult PAL_CALL mapBufferMemoryD3D12( Buffer* d3dBuffer = (Buffer*)buffer; HRESULT result = d3dBuffer->handle->lpVtbl->Map(d3dBuffer->handle, 0, nullptr, &ptr); if (FAILED(result)) { + pollMessagesD3D12(d3dBuffer->device); return PAL_RESULT_MEMORY_MAP_FAILED; } @@ -6296,8 +6478,13 @@ PalResult PAL_CALL createDescriptorPoolD3D12( void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) { DescriptorPool* d3dPool = (DescriptorPool*)pool; - d3dPool->resourceHeap.handle->lpVtbl->Release(d3dPool->resourceHeap.handle); - d3dPool->samplerHeap.handle->lpVtbl->Release(d3dPool->samplerHeap.handle); + if (d3dPool->hasResourceHeap) { + d3dPool->resourceHeap.handle->lpVtbl->Release(d3dPool->resourceHeap.handle); + } + + if (d3dPool->hasSamplerHeap) { + d3dPool->samplerHeap.handle->lpVtbl->Release(d3dPool->samplerHeap.handle); + } palFree(s_D3D.allocator, d3dPool->sets); palFree(s_D3D.allocator, d3dPool); @@ -6528,10 +6715,18 @@ PalResult PAL_CALL updateDescriptorSetD3D12( Buffer* buffer = (Buffer*)info->bufferInfo->buffer; if (info->bufferInfo->readOnly) { D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; - desc.Buffer.FirstElement = info->bufferInfo->offset; - desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; - desc.Buffer.NumElements = info->bufferInfo->size; - desc.Format = DXGI_FORMAT_R32_TYPELESS; + Uint32 stride = 4; + if (info->bufferInfo->stride) { + stride = info->bufferInfo->stride; + desc.Buffer.StructureByteStride = info->bufferInfo->stride; + } else { + desc.Format = DXGI_FORMAT_R32_TYPELESS; + desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; + } + + desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + desc.Buffer.FirstElement = info->bufferInfo->offset / stride; + desc.Buffer.NumElements = info->bufferInfo->size / stride; d3dDevice->handle->lpVtbl->CreateShaderResourceView( d3dDevice->handle, @@ -6541,11 +6736,18 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } else { D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; - desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - desc.Buffer.FirstElement = info->bufferInfo->offset; - desc.Buffer.NumElements = info->bufferInfo->size; - desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; - desc.Format = DXGI_FORMAT_R32_TYPELESS; + Uint32 stride = 4; + if (info->bufferInfo->stride) { + stride = info->bufferInfo->stride; + desc.Buffer.StructureByteStride = info->bufferInfo->stride; + } else { + desc.Format = DXGI_FORMAT_R32_TYPELESS; + desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; + } + + desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + desc.Buffer.FirstElement = info->bufferInfo->offset / stride; + desc.Buffer.NumElements = info->bufferInfo->size / stride; d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( d3dDevice->handle, @@ -6600,6 +6802,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( return PAL_RESULT_OUT_OF_MEMORY; } + memset(layout, 0, sizeof(PipelineLayout)); for (int i = 0; i < info->descriptorSetLayoutCount; i++) { DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; // seperate the samplers from the remaining descriptors @@ -6670,7 +6873,6 @@ PalResult PAL_CALL createPipelineLayoutD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - // TODO: fix buffer size result = d3dDevice->handle->lpVtbl->CreateRootSignature( d3dDevice->handle, 0, @@ -6738,7 +6940,6 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( DepthStencilStream* depthStencilDesc = &desc.header.depthStencil; ColorBlendStream* colorBlendDesc = &desc.header.colorBlend; RenderingLayoutStream* renderingLayoutDesc = &desc.header.renderingLayout; - PipelineFlagsStream* flagsDesc = &desc.header.flags; ViewInstancingStream* viewInstancingDesc = &desc.header.viewInstancing; pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); @@ -7103,13 +7304,6 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( viewLocations[i].RenderTargetArrayIndex = i; } - // Flags - flagsDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_FLAGS; - flagsDesc->flags = D3D12_PIPELINE_STATE_FLAG_NONE; - if (s_D3D.debugLayer) { - flagsDesc->flags = D3D12_PIPELINE_STATE_FLAG_DEBUG; - } - D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {0}; streamDesc.pPipelineStateSubobjectStream = &desc; streamDesc.SizeInBytes = totalSize; @@ -7142,6 +7336,8 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( pipeline->type = GRAPHICS_PIPELINE; pipeline->shaders = nullptr; pipeline->scratchBuffer = nullptr; + pipeline->layout = layout; + *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -7164,9 +7360,6 @@ PalResult PAL_CALL createComputePipelineD3D12( D3D12_COMPUTE_PIPELINE_STATE_DESC desc = {0}; desc.CS = shader->byteCode; desc.pRootSignature = layout->handle; - if (s_D3D.debugLayer) { - desc.Flags = D3D12_PIPELINE_STATE_FLAG_DEBUG; - } HRESULT result = d3dDevice->handle->lpVtbl->CreateComputePipelineState( d3dDevice->handle, @@ -7189,6 +7382,8 @@ PalResult PAL_CALL createComputePipelineD3D12( pipeline->shaders = nullptr; pipeline->scratchBuffer = nullptr; pipeline->hasFsr = false; + pipeline->layout = layout; + *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -7335,6 +7530,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( pipeline->hasFsr = false; pipeline->shaders = shaders; pipeline->scratchBuffer = scratchBuffer; + pipeline->layout = layout; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index e58b377a..c5b6222c 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -123,6 +123,14 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter); +bool PAL_CALL isShaderTargetSupportedVk( + PalAdapter* adapter, + PalShaderTarget target); + +PalShaderTarget PAL_CALL getHighestSupportedShaderTargetVk( + PalAdapter* adapter, + PalShaderFormats shaderFormat); + // ================================================== // Device // ================================================== @@ -587,13 +595,11 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set); PalResult PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -780,6 +786,8 @@ static PalGraphicsBackend s_VkBackend = { .getAdapterInfo = getAdapterInfoVk, .getAdapterCapabilities = getAdapterCapabilitiesVk, .getAdapterFeatures = getAdapterFeaturesVk, + .isShaderTargetSupported = isShaderTargetSupportedVk, + .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetVk, // device .createDevice = createDeviceVk, @@ -982,6 +990,14 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); +bool PAL_CALL isShaderTargetSupportedD3D12( + PalAdapter* adapter, + PalShaderTarget target); + +PalShaderTarget PAL_CALL getHighestSupportedShaderTargetD3D12( + PalAdapter* adapter, + PalShaderFormats shaderFormat); + // ================================================== // Device // ================================================== @@ -1446,13 +1462,11 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set); PalResult PAL_CALL cmdPushConstantsD3D12( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -1639,6 +1653,8 @@ static PalGraphicsBackend s_D3D12Backend = { .getAdapterInfo = getAdapterInfoD3D12, .getAdapterCapabilities = getAdapterCapabilitiesD3D12, .getAdapterFeatures = getAdapterFeaturesD3D12, + .isShaderTargetSupported = isShaderTargetSupportedD3D12, + .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetD3D12, // device .createDevice = createDeviceD3D12, @@ -1844,6 +1860,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->getAdapterInfo || !backend->getAdapterCapabilities || !backend->getAdapterFeatures || + !backend->isShaderTargetSupported || + !backend->getHighestSupportedShaderTarget || // device !backend->createDevice || @@ -2042,6 +2060,7 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN + // TODO: uncomment // result = initGraphicsVk(debugger, allocator); // if (result != PAL_RESULT_SUCCESS) { // return result; @@ -2050,7 +2069,7 @@ PalResult PAL_CALL palInitGraphics( // attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; // attachedBackend->base = &s_VkBackend; // attachedBackend->startIndex = 0; - // attachedBackend->count = 0; // TODO: uncomment + // attachedBackend->count = 0; #endif // PAL_HAS_VULKAN // D3D12 @@ -2097,7 +2116,8 @@ void PAL_CALL palShutdownGraphics() #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - shutdownGraphicsVk(); + // TODO: uncomment block + // shutdownGraphicsVk(); #endif // PAL_HAS_VULKAN // D3D12 @@ -2221,6 +2241,26 @@ PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) return adapter->backend->getAdapterFeatures(adapter); } +bool PAL_CALL palIsShaderTargetSupported( + PalAdapter* adapter, + PalShaderTarget target) +{ + if (!s_Graphics.initialized || !adapter) { + return false; + } + return adapter->backend->isShaderTargetSupported(adapter, target); +} + +PalShaderTarget PAL_CALL palGetHighestSupportedShaderTarget( + PalAdapter* adapter, + PalShaderFormats shaderFormat) +{ + if (!s_Graphics.initialized || !adapter) { + return PAL_SHADER_TARGET_UNKNOWN; + } + return adapter->backend->getHighestSupportedShaderTarget(adapter, shaderFormat); +} + // ================================================== // Device // ================================================== @@ -3734,7 +3774,6 @@ PalResult PAL_CALL palCmdTraceRaysIndirect( PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set) { @@ -3742,20 +3781,18 @@ PalResult PAL_CALL palCmdBindDescriptorSet( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !layout || !set) { + if (!cmdBuffer || !set) { return PAL_RESULT_NULL_POINTER; } return cmdBuffer->backend->cmdBindDescriptorSet( cmdBuffer, - layout, setIndex, set); } PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint32 offset, @@ -3766,14 +3803,13 @@ PalResult PAL_CALL palCmdPushConstants( return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; } - if (!cmdBuffer || !layout || !shaderStages || !value) { + if (!cmdBuffer || !shaderStages || !value) { return PAL_RESULT_NULL_POINTER; } // clang-format off return cmdBuffer->backend->cmdPushConstants( cmdBuffer, - layout, shaderStageCount, shaderStages, offset, diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 40a381e8..9d3fa001 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -504,9 +504,9 @@ typedef struct { const PalGraphicsBackend* backend; bool primary; - VkPipelineBindPoint bindPoint; Device* device; CommandPool* pool; + void* pipeline; VkCommandBuffer handle; } CommandBuffer; @@ -587,6 +587,7 @@ typedef struct { VkPipelineBindPoint bindPoint; Device* device; VkPipeline handle; + PipelineLayout* layout; } Pipeline; typedef struct { @@ -3301,7 +3302,6 @@ PalResult PAL_CALL getAdapterInfoVk( info->apiType = PAL_ADAPTER_API_TYPE_VULKAN; info->shaderFormats = PAL_SHADER_FORMAT_SPIRV; - info->version = props.driverVersion; info->deviceId = props.deviceID; info->vendorId = props.vendorID; strcpy(info->name, props.deviceName); @@ -3345,15 +3345,6 @@ PalResult PAL_CALL getAdapterInfoVk( } } - // version string - snprintf( - info->versionString, - PAL_ADAPTER_VERSION_SIZE, - "%d.%d.%d", - VK_VERSION_MAJOR(props.apiVersion), - VK_VERSION_MINOR(props.apiVersion), - VK_VERSION_PATCH(props.apiVersion)); - return PAL_RESULT_SUCCESS; } @@ -3791,6 +3782,72 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) return adapterFeatures; } +bool PAL_CALL isShaderTargetSupportedVk( + PalAdapter* adapter, + PalShaderTarget target) +{ + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDeviceProperties props = {0}; + s_Vk.getPhysicalDeviceProperties(vkAdapter->handle, &props); + + switch (target) { + case PAL_SHADER_TARGET_SPIRV_1_0: + case PAL_SHADER_TARGET_SPIRV_1_1: + case PAL_SHADER_TARGET_SPIRV_1_2: { + return true; + } + + case PAL_SHADER_TARGET_SPIRV_1_3: + case PAL_SHADER_TARGET_SPIRV_1_4: { + if (props.apiVersion >= VK_API_VERSION_1_1) { + return true; + } + } + + case PAL_SHADER_TARGET_SPIRV_1_5: { + if (props.apiVersion >= VK_API_VERSION_1_2) { + return true; + } + } + + case PAL_SHADER_TARGET_SPIRV_1_6: { + if (props.apiVersion >= VK_API_VERSION_1_3) { + return true; + } + } + } + + return false; +} + +PalShaderTarget PAL_CALL getHighestSupportedShaderTargetVk( + PalAdapter* adapter, + PalShaderFormats shaderFormat) +{ + if (shaderFormat != PAL_SHADER_FORMAT_SPIRV) { + return PAL_SHADER_TARGET_UNKNOWN; + } + + Adapter* vkAdapter = (Adapter*)adapter; + VkPhysicalDeviceProperties props = {0}; + s_Vk.getPhysicalDeviceProperties(vkAdapter->handle, &props); + + if (props.apiVersion >= VK_API_VERSION_1_3) { + return PAL_SHADER_TARGET_SPIRV_1_6; + + } else if (props.apiVersion >= VK_API_VERSION_1_2) { + return PAL_SHADER_TARGET_SPIRV_1_5; + + } else if (props.apiVersion >= VK_API_VERSION_1_1) { + return PAL_SHADER_TARGET_SPIRV_1_4; + + } else if (props.apiVersion >= VK_API_VERSION_1_0) { + return PAL_SHADER_TARGET_SPIRV_1_2; + } + + return PAL_SHADER_TARGET_UNKNOWN; +} + // ================================================== // Device // ================================================== @@ -6975,7 +7032,7 @@ PalResult PAL_CALL cmdBindPipelineVk( Pipeline* vkPipeline = (Pipeline*)pipeline; s_Vk.cmdBindPipeline(vkCmdBuffer->handle, vkPipeline->bindPoint, vkPipeline->handle); - vkCmdBuffer->bindPoint = vkPipeline->bindPoint; + vkCmdBuffer->pipeline = vkPipeline; return PAL_RESULT_SUCCESS; } @@ -7472,18 +7529,17 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 setIndex, PalDescriptorSet* set) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - PipelineLayout* vkLayout = (PipelineLayout*)layout; + Pipeline* pipeline = vkCmdBuffer->pipeline; DescriptorSet* vkSet = (DescriptorSet*)set; s_Vk.cmdBindDescriptorSets( vkCmdBuffer->handle, - vkCmdBuffer->bindPoint, - vkLayout->handle, + pipeline->bindPoint, + pipeline->layout->handle, setIndex, 1, &vkSet->handle, @@ -7495,7 +7551,6 @@ PalResult PAL_CALL cmdBindDescriptorSetVk( PalResult PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, - PalPipelineLayout* layout, Uint32 shaderStageCount, PalShaderStage* shaderStages, Uint64 offset, @@ -7503,7 +7558,7 @@ PalResult PAL_CALL cmdPushConstantsVk( const void* value) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - PipelineLayout* vkLayout = (PipelineLayout*)layout; + Pipeline* pipeline = vkCmdBuffer->pipeline; VkShaderStageFlags stages = 0; for (int i = 0; i < shaderStageCount; i++) { @@ -7511,7 +7566,14 @@ PalResult PAL_CALL cmdPushConstantsVk( stages |= bit; } - s_Vk.cmdPushConstants(vkCmdBuffer->handle, vkLayout->handle, stages, offset, size, value); + s_Vk.cmdPushConstants( + vkCmdBuffer->handle, + pipeline->layout->handle, + stages, + offset, + size, + value); + return PAL_RESULT_SUCCESS; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index ee4d8d0d..a4c4e774 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -83,7 +83,9 @@ bool computeTest() PalAdapterCapabilities caps; PalAdapterFeatures adapterFeatures = 0; + PalAdapterInfo adapterInfo = {0}; bool hasComputeQueue = false; + bool hasComputeShader = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -101,27 +103,45 @@ bool computeTest() hasComputeQueue = true; adapterFeatures = palGetAdapterFeatures(adapter); if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { - break; + hasComputeShader = true; + } + } + + if (hasComputeShader) { + // We want an adapter that supports spirv 1.0 or dxil 6.0 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + break; + } } } } palFree(nullptr, adapters); if (!adapter) { - if (hasComputeQueue) { + if (!hasComputeQueue) { palLog(nullptr, "Failed to find an adapter that supports compute queue"); - } else { + } else if (!hasComputeShader) { palLog(nullptr, "Failed to find an adapter that supports compute shader"); - } - return false; - } - PalAdapterInfo adapterInfo = {0}; - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } return false; } @@ -420,7 +440,6 @@ bool computeTest() result = palCmdPushConstants( cmdBuffer, - pipelineLayout, 1, shaderStages, 0, @@ -433,7 +452,7 @@ bool computeTest() return false; } - result = palCmdBindDescriptorSet(cmdBuffer, pipelineLayout, 0, descriptorSet); + result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); @@ -585,7 +604,7 @@ bool computeTest() } // write to a ppm output file - FILE* file = fopen("graphics/compute_output.ppm", "wb"); + FILE* file = fopen("compute_output.ppm", "wb"); fprintf(file, "P6\n%d %d\n255\n", BUFFER_SIZE, BUFFER_SIZE); float* pixels = (float*)ptr; for (int y = 0; y < BUFFER_SIZE; y++) { diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 6dbdd8e5..d98a5ca4 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -2,6 +2,60 @@ #include "pal/pal_graphics.h" #include "tests.h" +const char* shaderTargetToString(PalShaderTarget target) +{ + switch (target) { + case PAL_SHADER_TARGET_SPIRV_1_0: + return "1.0"; + + case PAL_SHADER_TARGET_SPIRV_1_1: + return "1.1"; + + case PAL_SHADER_TARGET_SPIRV_1_2: + return "1.2"; + + case PAL_SHADER_TARGET_SPIRV_1_3: + return "1.3"; + + case PAL_SHADER_TARGET_SPIRV_1_4: + return "1.4"; + + case PAL_SHADER_TARGET_SPIRV_1_5: + return "1.5"; + + case PAL_SHADER_TARGET_SPIRV_1_6: + return "1.6"; + + case PAL_SHADER_TARGET_DXIL_5_1: + return "5.1"; + + case PAL_SHADER_TARGET_DXIL_6_0: + return "6.0"; + + case PAL_SHADER_TARGET_DXIL_6_1: + return "6.1"; + + case PAL_SHADER_TARGET_DXIL_6_2: + return "6.2"; + + case PAL_SHADER_TARGET_DXIL_6_3: + return "6.3"; + + case PAL_SHADER_TARGET_DXIL_6_4: + return "6.4"; + + case PAL_SHADER_TARGET_DXIL_6_5: + return "6.5"; + + case PAL_SHADER_TARGET_DXIL_6_6: + return "6.6"; + + case PAL_SHADER_TARGET_DXIL_6_7: + return "6.7"; + } + return nullptr; +} + bool graphicsTest() { // initialize the graphics system @@ -66,7 +120,6 @@ bool graphicsTest() palLog(nullptr, " Device Id: %d", info.deviceId); palLog(nullptr, " Vram %dMB", vramMb); palLog(nullptr, " Shared Memory %dMB", sharedMemMb); - palLog(nullptr, " API Version: %s", info.versionString); const char* typeString; switch (info.type) { @@ -108,59 +161,25 @@ bool graphicsTest() apiTypeString = "Metal"; break; } - - case PAL_ADAPTER_API_TYPE_OPENGL: { - apiTypeString = "OpenGL"; - break; - } - - case PAL_ADAPTER_API_TYPE_GLES: { - apiTypeString = "GLes"; - break; - } - - case PAL_ADAPTER_API_TYPE_D3D11: { - apiTypeString = "D3D11"; - break; - } - - case PAL_ADAPTER_API_TYPE_D3D9: { - apiTypeString = "D3D9"; - break; - } - - case PAL_ADAPTER_API_TYPE_PPM: { - apiTypeString = "PPM"; - break; - } } palLog(nullptr, " API Type: %s", apiTypeString); // shader formats + PalShaderTarget target; palLog(nullptr, ""); palLog(nullptr, " Supported Shader Formats:"); if (info.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { palLog(nullptr, " SPIRV"); + + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + palLog(nullptr, " Highest Spirv Target %s:", shaderTargetToString(target)); } if (info.shaderFormats & PAL_SHADER_FORMAT_DXIL) { palLog(nullptr, " DXIL"); - } - - if (info.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - palLog(nullptr, " DXBC"); - } - - if (info.shaderFormats & PAL_SHADER_FORMAT_GLSL) { - palLog(nullptr, " GLSL"); - } - - if (info.shaderFormats & PAL_SHADER_FORMAT_MSL) { - palLog(nullptr, " MSL"); - } - if (info.shaderFormats & PAL_SHADER_FORMAT_PPM) { - palLog(nullptr, " PPM"); + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + palLog(nullptr, " Highest Dxil Target %s:", shaderTargetToString(target)); } // features diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 601e8fae..32466d61 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -869,7 +869,7 @@ bool rayTracingTest() return false; } - result = palCmdBindDescriptorSet(cmdBuffer, pipelineLayout, 0, descriptorSet); + result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 72e7c593..09c2e481 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -1226,12 +1226,7 @@ bool textureTest() return false; } - result = palCmdBindDescriptorSet( - cmdBuffers[currentFrame], - pipelineLayout, - 0, - descriptorSet); - + result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); From 8d21bc7a82d342b2c55e2ea690a97d188a61df1c Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 24 Apr 2026 20:09:41 +0000 Subject: [PATCH 179/372] add a todo for ray tracing test for d3d12 --- tests/graphics/compute_test.c | 3 +- tests/graphics/ray_tracing_test.c | 60 +++++++++++++++++++++++-------- tests/tests_main.c | 4 +-- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index a4c4e774..41611cb2 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -81,7 +81,7 @@ bool computeTest() return false; } - PalAdapterCapabilities caps; + PalAdapterCapabilities caps = {0}; PalAdapterFeatures adapterFeatures = 0; PalAdapterInfo adapterInfo = {0}; bool hasComputeQueue = false; @@ -129,6 +129,7 @@ bool computeTest() } } } + adapter = nullptr; } palFree(nullptr, adapters); diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 32466d61..2c05e9c9 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -52,11 +52,11 @@ bool rayTracingTest() PalAccelerationStructure* blas = nullptr; PalAccelerationStructure* tlas = nullptr; - PalGraphicsDebugger debugger; + PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -92,9 +92,11 @@ bool rayTracingTest() return false; } - PalAdapterCapabilities caps; + PalAdapterCapabilities caps = {0}; + PalAdapterInfo adapterInfo = {0}; PalAdapterFeatures adapterFeatures = 0; bool hasGraphicsQueue = false; + bool hasTracing = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -113,27 +115,46 @@ bool rayTracingTest() hasGraphicsQueue = true; adapterFeatures = palGetAdapterFeatures(adapter); if (adapterFeatures & PAL_ADAPTER_FEATURE_RAY_TRACING) { - break; + hasTracing = true; + } + } + + if (hasTracing) { + // We want an adapter that supports spirv 1.0 or dxil 6.0 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + break; + } } } + adapter = nullptr; } palFree(nullptr, adapters); if (!adapter) { - if (hasGraphicsQueue) { + if (!hasGraphicsQueue) { palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - } else { + } else if (!hasTracing) { palLog(nullptr, "Failed to find an adapter that supports ray tracing"); - } - return false; - } - PalAdapterInfo adapterInfo = {0}; - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } return false; } @@ -180,6 +201,9 @@ bool rayTracingTest() const char* shaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { shaderPath = "graphics/shaders/raygen_shader.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + shaderPath = "graphics/shaders/raygen_shader.dxil"; } if (!readFile(shaderPath, nullptr, &bytecodeSize)) { @@ -211,6 +235,9 @@ bool rayTracingTest() bytecode = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { shaderPath = "graphics/shaders/miss_shader.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + shaderPath = "graphics/shaders/miss_shader.dxil"; } if (!readFile(shaderPath, nullptr, &bytecodeSize)) { @@ -242,6 +269,9 @@ bool rayTracingTest() bytecode = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { shaderPath = "graphics/shaders/closest_hit_shader.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + shaderPath = "graphics/shaders/closest_hit_shader.dxil"; } if (!readFile(shaderPath, nullptr, &bytecodeSize)) { @@ -1029,7 +1059,7 @@ bool rayTracingTest() } // write to a ppm output file - FILE* file = fopen("graphics/ray_tracing_output.ppm", "wb"); + FILE* file = fopen("ray_tracing_output.ppm", "wb"); fprintf(file, "P6\n%d %d\n255\n", BUFFER_SIZE, BUFFER_SIZE); float* pixels = (float*)ptr; for (int y = 0; y < BUFFER_SIZE; y++) { diff --git a/tests/tests_main.c b/tests/tests_main.c index b0359452..c086f4e9 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,8 +58,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(computeTest, "Compute Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From d250da3d67b0ab31c8066a85b56c6930eb3fc116 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 24 Apr 2026 21:59:14 +0000 Subject: [PATCH 180/372] clear color test working on d3d12 --- src/graphics/pal_d3d12.c | 95 ++++++++++++++++++++----------- src/graphics/pal_vulkan.c | 6 +- tests/graphics/clear_color_test.c | 44 ++++++++++++-- tests/graphics/compute_test.c | 3 + tests/graphics/ray_tracing_test.c | 5 +- tests/tests_main.c | 4 +- 6 files changed, 111 insertions(+), 46 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index dc4216b1..424bfbe3 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2705,19 +2705,19 @@ PalResult PAL_CALL createDeviceD3D12( } for (int i = 0; i < MAX_RTV; i++) { - device->rtvAllocator.freeList[i] = i; + device->rtvAllocator.freeList[i] = i + 1; } for (int i = 0; i < MAX_DSV; i++) { - device->dsvAllocator.freeList[i] = i; + device->dsvAllocator.freeList[i] = i + 1; } - device->rtvAllocator.freeTop = MAX_RTV; + device->rtvAllocator.freeTop = 0; device->rtvAllocator.incrementSize = device->handle->lpVtbl->GetDescriptorHandleIncrementSize( device->handle, D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - device->dsvAllocator.freeTop = MAX_DSV; + device->dsvAllocator.freeTop = 0; device->dsvAllocator.incrementSize = device->handle->lpVtbl->GetDescriptorHandleIncrementSize( device->handle, D3D12_DESCRIPTOR_HEAP_TYPE_DSV); @@ -3486,7 +3486,9 @@ PalResult PAL_CALL createImageViewD3D12( imageView->format = formatToD3D12(info->format); if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR) { RTVHeapAllocator* allocator = &d3dDevice->rtvAllocator; - Uint32 index = allocator->freeList[--allocator->freeTop]; + Uint32 index = allocator->freeTop; + allocator->freeTop = allocator->freeList[index]; + D3D12_CPU_DESCRIPTOR_HANDLE dst; dst.ptr = getDescriptorHandleD3D12(index, allocator->incrementSize, allocator->baseOffset); @@ -3503,7 +3505,9 @@ PalResult PAL_CALL createImageViewD3D12( } else { DSVHeapAllocator* allocator = &d3dDevice->dsvAllocator; - Uint32 index = allocator->freeList[--allocator->freeTop]; + Uint32 index = allocator->freeTop; + allocator->freeTop = allocator->freeList[index]; + D3D12_CPU_DESCRIPTOR_HANDLE dst; dst.ptr = getDescriptorHandleD3D12(index, allocator->incrementSize, allocator->baseOffset); @@ -3522,6 +3526,8 @@ PalResult PAL_CALL createImageViewD3D12( imageView->range = info->subresourceRange; imageView->type = info->type; imageView->image = d3dImage; + + imageView->device = d3dDevice; *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; } @@ -3530,13 +3536,18 @@ void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) { ImageView* d3dImageView = (ImageView*)imageView; Device* device = d3dImageView->device; + RTVHeapAllocator* allocator = nullptr; + if (d3dImageView->range.aspect == PAL_IMAGE_ASPECT_COLOR) { - device->rtvAllocator.freeList[device->rtvAllocator.freeTop++] = d3dImageView->heapIndex; + RTVHeapAllocator* allocator = &device->rtvAllocator; + allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; + allocator->freeTop = d3dImageView->heapIndex; } else { - device->dsvAllocator.freeList[device->dsvAllocator.freeTop++] = d3dImageView->heapIndex; + DSVHeapAllocator* allocator = &device->dsvAllocator; + allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; + allocator->freeTop = d3dImageView->heapIndex; } - palFree(s_D3D.allocator, d3dImageView); } @@ -3643,12 +3654,14 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( } DXGI_SWAP_CHAIN_DESC1 desc = {0}; - desc.Width = 1; - desc.Height = 1; + desc.Width = 8; + desc.Height = 8; desc.SampleDesc.Count = 1; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.BufferCount = 1; + desc.BufferCount = 2; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; result = s_D3D.factory->lpVtbl->CreateSwapChainForHwnd( s_D3D.factory, @@ -4388,14 +4401,17 @@ PalResult PAL_CALL createCommandPoolD3D12( switch (d3dQueue->type) { case PAL_QUEUE_TYPE_COMPUTE: { pool->type = D3D12_COMMAND_LIST_TYPE_COMPUTE; + break; } case PAL_QUEUE_TYPE_GRAPHICS: { pool->type = D3D12_COMMAND_LIST_TYPE_DIRECT; + break; } case PAL_QUEUE_TYPE_COPY: { pool->type = D3D12_COMMAND_LIST_TYPE_COPY; + break; } } @@ -4570,6 +4586,7 @@ PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) d3dCmdBuffer->allocator, nullptr); + d3dCmdBuffer->handle->lpVtbl->Close(d3dCmdBuffer->handle); d3dCmdBuffer->pipeline = nullptr; return PAL_RESULT_SUCCESS; } @@ -4624,7 +4641,23 @@ PalResult PAL_CALL cmdBeginD3D12( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) { - return resetCommandBufferD3D12(cmdBuffer); + HRESULT result; + CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; + result = d3dCmdBuffer->allocator->lpVtbl->Reset(d3dCmdBuffer->allocator); + if (FAILED(result)) { + pollMessagesD3D12(d3dCmdBuffer->device); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_COMMAND_BUFFER; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + d3dCmdBuffer->handle->lpVtbl->Reset( + d3dCmdBuffer->handle, + d3dCmdBuffer->allocator, + nullptr); + + return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer) @@ -4815,41 +4848,35 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; D3D12_CPU_DESCRIPTOR_HANDLE colorAttachments[MAX_ATTACHMENTS]; D3D12_CPU_DESCRIPTOR_HANDLE depthStencilAttachment; + D3D12_CPU_DESCRIPTOR_HANDLE* depthStencil = nullptr; D3D12_CPU_DESCRIPTOR_HANDLE fsrAttachment; + for (int i = 0; i < info->colorAttachentCount; i++) { ImageView* tmp = (ImageView*)info->colorAttachments[i].imageView; RTVHeapAllocator* allocator = &tmp->device->rtvAllocator; Uint32 size = allocator->incrementSize; - Uint32 base = allocator->baseOffset; + Uint64 base = allocator->baseOffset; colorAttachments[i].ptr = getDescriptorHandleD3D12(tmp->heapIndex, size, base); } - ImageView* tmp = (ImageView*)info->depthStencilAttachment->imageView; - if (tmp) { + if (info->depthStencilAttachment) { + ImageView* tmp = (ImageView*)info->depthStencilAttachment->imageView; DSVHeapAllocator* allocator = &tmp->device->dsvAllocator; Uint32 size = allocator->incrementSize; - Uint32 base = allocator->baseOffset; + Uint64 base = allocator->baseOffset; depthStencilAttachment.ptr = getDescriptorHandleD3D12(tmp->heapIndex, size, base); - - d3dCmdBuffer->handle->lpVtbl->OMSetRenderTargets( - d3dCmdBuffer->handle, - info->colorAttachentCount, - colorAttachments, - FALSE, - &depthStencilAttachment); - - } else { - d3dCmdBuffer->handle->lpVtbl->OMSetRenderTargets( - d3dCmdBuffer->handle, - info->colorAttachentCount, - colorAttachments, - FALSE, - nullptr); + depthStencil = &depthStencilAttachment; } + d3dCmdBuffer->handle->lpVtbl->OMSetRenderTargets( + d3dCmdBuffer->handle, + info->colorAttachentCount, + colorAttachments, + FALSE, + depthStencil); + for (int i = 0; i < info->colorAttachentCount; i++) { - ImageView* tmp = (ImageView*)info->colorAttachments[i].imageView; float color[4]; color[0] = info->colorAttachments[i].clearValue.color[0]; color[1] = info->colorAttachments[i].clearValue.color[1]; @@ -4861,7 +4888,7 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( colorAttachments[i], color, 0, nullptr); } - if (tmp) { + if (info->depthStencilAttachment) { D3D12_CLEAR_FLAGS clearFlags = 0; UINT8 stencil = 0; float depth = 0; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 9d3fa001..4795f18e 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -2244,7 +2244,7 @@ static inline Uint32 minVk( return (a < b) ? a : b; } -static void fillVkBuildInfoVk( +static void fillBuildInfoVk( Uint32 count, PalAccelerationStructureBuildInfo* info, Uint32* maxPrimities, @@ -6646,7 +6646,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * geometryCount); } - fillVkBuildInfoVk( + fillBuildInfoVk( geometryCount, info, nullptr, @@ -7847,7 +7847,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( memset(maxPrimities, 0, sizeof(Uint32) * geometryCount); } - fillVkBuildInfoVk( + fillBuildInfoVk( geometryCount, info, maxPrimities, diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index 346bb19b..812c135e 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -100,11 +100,11 @@ bool clearColorTest() gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; } - PalGraphicsDebugger debugger; + PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -140,7 +140,9 @@ bool clearColorTest() return false; } - PalAdapterCapabilities caps; + PalAdapterCapabilities caps = {0}; + PalAdapterInfo adapterInfo = {0}; + bool hasGraphicsQueue = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -152,15 +154,46 @@ bool clearColorTest() } if (caps.maxGraphicsQueues == 0) { + hasGraphicsQueue = false; continue; + } else { - break; + hasGraphicsQueue = true; + } + + if (hasGraphicsQueue) { + // We want an adapter that supports spirv 1.0 or dxil 6.0 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + break; + } + } } + adapter = nullptr; } palFree(nullptr, adapters); if (!adapter) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); + if (!hasGraphicsQueue) { + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); + + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } return false; } @@ -214,7 +247,6 @@ bool clearColorTest() // create a swapchain with the graphics queue PalSurfaceCapabilities surfaceCaps = {0}; result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); - if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get surface capabilities: %s", error); diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 41611cb2..c8e0dd60 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -97,6 +97,7 @@ bool computeTest() } if (caps.maxComputeQueues == 0) { + hasComputeQueue = false; continue; } else { @@ -104,6 +105,8 @@ bool computeTest() adapterFeatures = palGetAdapterFeatures(adapter); if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { hasComputeShader = true; + } else { + hasComputeShader = false; } } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 2c05e9c9..b5d8312b 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -109,6 +109,7 @@ bool rayTracingTest() // Ray tracing is generally implemented on the graphics queue if (caps.maxGraphicsQueues == 0) { + hasGraphicsQueue = false; continue; } else { @@ -116,6 +117,8 @@ bool rayTracingTest() adapterFeatures = palGetAdapterFeatures(adapter); if (adapterFeatures & PAL_ADAPTER_FEATURE_RAY_TRACING) { hasTracing = true; + } else { + hasTracing = false; } } @@ -130,7 +133,7 @@ bool rayTracingTest() // we prefer spirv first if an adapter supports multiple shader formats if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_3)) { break; } } diff --git a/tests/tests_main.c b/tests/tests_main.c index c086f4e9..309b0630 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,11 +59,11 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders + // registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest(clearColorTest, "Clear Color Test"); + registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); From 4c6d0a77af3bf528469b6f348097bc7f3acf17c5 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 27 Apr 2026 21:04:15 +0000 Subject: [PATCH 181/372] triangle test working on d3d12 --- include/pal/pal_graphics.h | 3 +- src/graphics/pal_d3d12.c | 358 +++++++++++------- tests/graphics/clear_color_test.c | 2 +- tests/graphics/compute_test.c | 4 +- .../shaders/triangle_frag_shader.dxil | Bin 0 -> 2948 bytes .../shaders/triangle_frag_shader.hlsl | 11 + .../shaders/triangle_vert_shader.dxil | Bin 0 -> 3128 bytes .../shaders/triangle_vert_shader.hlsl | 20 + tests/graphics/texture_test.c | 2 + tests/graphics/triangle_test.c | 53 ++- tests/tests_main.c | 4 +- 11 files changed, 298 insertions(+), 159 deletions(-) create mode 100644 tests/graphics/shaders/triangle_frag_shader.dxil create mode 100644 tests/graphics/shaders/triangle_frag_shader.hlsl create mode 100644 tests/graphics/shaders/triangle_vert_shader.dxil create mode 100644 tests/graphics/shaders/triangle_vert_shader.hlsl diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 352e69ff..a00a70bd 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1959,7 +1959,8 @@ typedef struct { PalVertexType type; /**< (eg. PAL_VERTEX_TYPE_FLOAT).*/ /** Must not include the index (eg. "position" or "myown"). Set to nullptr to use the default - * that will be derived from `semanticID`.*/ + * that will be derived from `semanticID` which are + * (`POSITION`, `COLOR`, `TEXCOORD`, `NORMAL` and `TANGENT`).*/ const char* semanticName; } PalVertexAttribute; diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 424bfbe3..3fe95f1b 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -55,6 +55,14 @@ freely, subject to the following restrictions: #define COMPUTE_PIPELINE 1221 #define RAY_TRACING_PIPELINE 1222 +#if defined(_MSC_VER) + #define ALIGN_STREAM __declspec(align(sizeof(void*))) +#elif defined(__GNUC__) || defined(__clang__) + #define ALIGN_STREAM __attribute__((aligned(sizeof(void*)))) +#else + #define ALIGN_STREAM +#endif // _MSC_VER + // clang-format off // IIDS const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; @@ -375,79 +383,86 @@ typedef struct { DescriptorSet* sets; } DescriptorPool; -typedef struct { +typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; ID3D12RootSignature* root; } RootSignatureStream; -typedef struct { +typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; D3D12_INPUT_LAYOUT_DESC desc; } InputLayoutStream; -typedef struct { +typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE ibType; D3D12_PRIMITIVE_TOPOLOGY_TYPE topology; - D3D12_INDEX_BUFFER_STRIP_CUT_VALUE IBStripCutValue; -} InputAssemblyStream; +} TopologyStream; -typedef struct { +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE value; +} IBStripCutStream; + +typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; D3D12_RASTERIZER_DESC desc; } RasterizerStream; -typedef struct { - UINT sampleMask; - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE maskType; +typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; DXGI_SAMPLE_DESC desc; -} MultisampleStream; +} SampleDescStream; -typedef struct { +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + UINT mask; +} SampleMaskStream; + +typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; D3D12_DEPTH_STENCIL_DESC desc; } DepthStencilStream; -typedef struct { +typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; D3D12_BLEND_DESC desc; -} ColorBlendStream; +} BlendStream; -typedef struct { +typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE dsvType; - UINT NumRenderTargets; - DXGI_FORMAT DSVFormat; - DXGI_FORMAT RTVFormats[8]; -} RenderingLayoutStream; + struct D3D12_RT_FORMAT_ARRAY data; +} RTVStream; -typedef struct { +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + DXGI_FORMAT format; +} DSVStream; + +typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; D3D12_SHADER_BYTECODE desc; } ShaderStream; -typedef struct { +typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; D3D12_VIEW_INSTANCING_DESC desc; } ViewInstancingStream; -typedef struct { +typedef struct { RootSignatureStream layout; InputLayoutStream inputLayout; - InputAssemblyStream inputAssembly; + TopologyStream topology; + IBStripCutStream ibStripCut; RasterizerStream rasterizer; - MultisampleStream multisample; + SampleDescStream sampleDesc; + SampleMaskStream sampleMask; DepthStencilStream depthStencil; - ColorBlendStream colorBlend; - RenderingLayoutStream renderingLayout; + BlendStream blend; + RTVStream RTV; + DSVStream DSV; ViewInstancingStream viewInstancing; -} FixedPipelineHeader; - -typedef struct { - FixedPipelineHeader header; ShaderStream shaders[7]; // 7 shader types for graphics pipeline -} GraphicsPipelineeStreamDesc; +} GraphicsPipelineStreamDesc; static D3D12 s_D3D = {0}; @@ -1895,6 +1910,27 @@ static void pollMessagesD3D12(Device* device) queue->lpVtbl->ClearStoredMessages(queue); } +static const char* semanticIDToStringD3D12(PalVertexSemanticID id) +{ + switch (id) { + case PAL_VERTEX_SEMANTIC_ID_POSITION: + return "POSITION"; + + case PAL_VERTEX_SEMANTIC_ID_COLOR: + return "COLOR"; + + case PAL_VERTEX_SEMANTIC_ID_TEXCOORD: + return "TEXCOORD"; + + case PAL_VERTEX_SEMANTIC_ID_NORMAL: + return "NORMAL"; + + case PAL_VERTEX_SEMANTIC_ID_TANGENT: + return "TANGENT"; + } + return nullptr; +} + // ================================================== // Adapter // ================================================== @@ -4025,6 +4061,7 @@ PalResult PAL_CALL presentSwapchainD3D12( return PAL_RESULT_PLATFORM_FAILURE; } + pollMessagesD3D12(d3dSwapchain->device); return PAL_RESULT_SUCCESS; } @@ -4877,15 +4914,17 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( depthStencil); for (int i = 0; i < info->colorAttachentCount; i++) { - float color[4]; - color[0] = info->colorAttachments[i].clearValue.color[0]; - color[1] = info->colorAttachments[i].clearValue.color[1]; - color[2] = info->colorAttachments[i].clearValue.color[2]; - color[3] = info->colorAttachments[i].clearValue.color[3]; - - d3dCmdBuffer->handle->lpVtbl->ClearRenderTargetView( - d3dCmdBuffer->handle, - colorAttachments[i], color, 0, nullptr); + if (info->colorAttachments[i].loadOp == PAL_LOAD_OP_CLEAR) { + float color[4]; + color[0] = info->colorAttachments[i].clearValue.color[0]; + color[1] = info->colorAttachments[i].clearValue.color[1]; + color[2] = info->colorAttachments[i].clearValue.color[2]; + color[3] = info->colorAttachments[i].clearValue.color[3]; + + d3dCmdBuffer->handle->lpVtbl->ClearRenderTargetView( + d3dCmdBuffer->handle, + colorAttachments[i], color, 0, nullptr); + } } if (info->depthStencilAttachment) { @@ -6045,7 +6084,7 @@ PalResult PAL_CALL createBufferD3D12( } memset(buffer, 0, sizeof(Buffer)); - buffer->desc.Width = (UINT64)info->size; + buffer->desc.Width = info->size; buffer->desc.Height = 1; buffer->desc.DepthOrArraySize = 1; buffer->desc.MipLevels = 1; @@ -6070,6 +6109,7 @@ PalResult PAL_CALL createBufferD3D12( } buffer->device = d3dDevice; + buffer->size = info->size; *outBuffer = (PalBuffer*)buffer; return PAL_RESULT_SUCCESS; } @@ -6949,30 +6989,17 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( Device* d3dDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - GraphicsPipelineeStreamDesc desc = {0}; - memset(&desc, 0, sizeof(GraphicsPipelineeStreamDesc)); - - desc.header.layout.root = layout->handle; - desc.header.layout.type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE; - - ShaderStream shaderStreams[7]; // 7 shader types for graphics pipeline D3D12_INPUT_ELEMENT_DESC* elementDescs = nullptr; D3D12_VIEW_INSTANCE_LOCATION* viewLocations = nullptr; - D3D12_VIEW_INSTANCE_LOCATION cachedViewLocation = {0}; - InputLayoutStream* inputLayoutDesc = &desc.header.inputLayout; - InputAssemblyStream* inputAssemblyDesc = &desc.header.inputAssembly; - RasterizerStream* rasterizerDesc = &desc.header.rasterizer; - MultisampleStream* multisampleDesc = &desc.header.multisample; - DepthStencilStream* depthStencilDesc = &desc.header.depthStencil; - ColorBlendStream* colorBlendDesc = &desc.header.colorBlend; - RenderingLayoutStream* renderingLayoutDesc = &desc.header.renderingLayout; - ViewInstancingStream* viewInstancingDesc = &desc.header.viewInstancing; + GraphicsPipelineStreamDesc graphicsStreamDesc = {0}; + memset(&graphicsStreamDesc, 0, sizeof(GraphicsPipelineStreamDesc)); pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); if (!pipeline) { return PAL_RESULT_OUT_OF_MEMORY; } + memset(pipeline, 0, sizeof(Pipeline)); if (info->renderingLayout->viewCount > 1) { viewLocations = palAllocate( @@ -6983,16 +7010,22 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( if (!viewLocations) { return PAL_RESULT_OUT_OF_MEMORY; } - - } else { - viewLocations = &cachedViewLocation; } - totalSize = sizeof(FixedPipelineHeader) + (sizeof(ShaderStream) * info->shaderCount); + // Root signature + RootSignatureStream* rootSignatureStream = &graphicsStreamDesc.layout; + totalSize += sizeof(RootSignatureStream); + rootSignatureStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE; + rootSignatureStream->root = layout->handle; + // shaders for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; - if (tmp->patchControlPoints) { + ShaderStream* shaderStream = &graphicsStreamDesc.shaders[i]; + totalSize += sizeof(ShaderStream); + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + + if (tmp->patchControlPoints) { patchControlPoints = tmp->patchControlPoints; if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { palFree(s_D3D.allocator, pipeline); @@ -7001,34 +7034,30 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( } if (tmp->stage == PAL_SHADER_STAGE_VERTEX) { - shaderStreams[i].desc = tmp->byteCode; - shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS; + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS; } else if (tmp->stage == PAL_SHADER_STAGE_FRAGMENT) { - shaderStreams[i].desc = tmp->byteCode; - shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS; + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS; } else if (tmp->stage == PAL_SHADER_STAGE_GEOMETRY) { - shaderStreams[i].desc = tmp->byteCode; - shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS; + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS; } else if (tmp->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { - shaderStreams[i].desc = tmp->byteCode; - shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS; + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS; } else if (tmp->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { - shaderStreams[i].desc = tmp->byteCode; - shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS; + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS; } else if (tmp->stage == PAL_SHADER_STAGE_TASK) { - shaderStreams[i].desc = tmp->byteCode; - shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS; + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS; } else { // mesh shader - shaderStreams[i].desc = tmp->byteCode; - shaderStreams[i].type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS; + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS; } + + shaderStream->type = type; + shaderStream->desc = tmp->byteCode; } // Vertex input state @@ -7040,10 +7069,13 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( vertexCount += layout->attributeCount; } - inputLayoutDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT; + InputLayoutStream* inputLayoutStream = &graphicsStreamDesc.inputLayout; + totalSize += sizeof(InputLayoutStream); + inputLayoutStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT; + pipeline->strides = nullptr; if (vertexCount) { - pipeline->strides = palAllocate(s_D3D.allocator, sizeof(Uint32) * vertexLayoutCount, 0); + pipeline->strides = palAllocate(s_D3D.allocator, sizeof(Uint32) * 8, 0); if (!pipeline->strides) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7077,6 +7109,8 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( elementDesc->InputSlot = layout->binding; if (vertexAttrib->semanticName) { elementDesc->SemanticName = vertexAttrib->semanticName; + } else { + elementDesc->SemanticName = semanticIDToStringD3D12(vertexAttrib->semanticID); } if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_POSITION) { @@ -7115,11 +7149,11 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( pipeline->strides[i] = stride; } - inputLayoutDesc->desc.NumElements = vertexCount; - inputLayoutDesc->desc.pInputElementDescs = elementDescs; + inputLayoutStream->desc.NumElements = vertexCount; + inputLayoutStream->desc.pInputElementDescs = elementDescs; } - // Input assembly + // Primitive Topology D3D12_PRIMITIVE_TOPOLOGY_TYPE topologyType = 0; D3D_PRIMITIVE_TOPOLOGY topology = 0; switch (info->topology) { @@ -7160,81 +7194,105 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( } } - inputAssemblyDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY; - inputAssemblyDesc->ibType = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE; - inputAssemblyDesc->topology = topologyType; + TopologyStream* topologyStream = &graphicsStreamDesc.topology; + totalSize += sizeof(TopologyStream); + topologyStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY; + topologyStream->topology = topologyType; + + // IB Strip Cut + IBStripCutStream* inStripCutStream = &graphicsStreamDesc.ibStripCut; + totalSize += sizeof(IBStripCutStream); + inStripCutStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE; if (info->primitiveRestartEnable == false) { - inputAssemblyDesc->IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + inStripCutStream->value = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; } else { if (info->indexType == PAL_INDEX_TYPE_UINT16) { - inputAssemblyDesc->IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; + inStripCutStream->value = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; } else { - inputAssemblyDesc->IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF; + inStripCutStream->value = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF; } } // Rasterizer - rasterizerDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER; - rasterizerDesc->desc.FrontCounterClockwise = FALSE; + RasterizerStream* rasterizerStream = &graphicsStreamDesc.rasterizer; + totalSize += sizeof(RasterizerStream); + rasterizerStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER; + + rasterizerStream->desc.CullMode = D3D12_CULL_MODE_NONE; + rasterizerStream->desc.FillMode = D3D12_FILL_MODE_SOLID; + rasterizerStream->desc.FrontCounterClockwise = FALSE; + rasterizerStream->desc.DepthClipEnable = TRUE; + if (info->rasterizerState) { PalRasterizerState* state = info->rasterizerState; if (state->cullMode == PAL_CULL_MODE_NONE) { - rasterizerDesc->desc.CullMode = D3D12_CULL_MODE_NONE; + rasterizerStream->desc.CullMode = D3D12_CULL_MODE_NONE; } else if (state->cullMode == PAL_CULL_MODE_BACK) { - rasterizerDesc->desc.CullMode = D3D12_CULL_MODE_BACK; + rasterizerStream->desc.CullMode = D3D12_CULL_MODE_BACK; } else if (state->cullMode == PAL_CULL_MODE_FRONT) { - rasterizerDesc->desc.CullMode = D3D12_CULL_MODE_FRONT; + rasterizerStream->desc.CullMode = D3D12_CULL_MODE_FRONT; } if (state->polygonMode == PAL_POLYGON_MODE_FILL) { - rasterizerDesc->desc.FillMode = D3D12_FILL_MODE_SOLID; + rasterizerStream->desc.FillMode = D3D12_FILL_MODE_SOLID; } else { - rasterizerDesc->desc.FillMode = D3D12_FILL_MODE_WIREFRAME; + rasterizerStream->desc.FillMode = D3D12_FILL_MODE_WIREFRAME; } if (state->frontFace == PAL_FRONT_FACE_CLOCKWISE) { - rasterizerDesc->desc.FrontCounterClockwise = FALSE; + rasterizerStream->desc.FrontCounterClockwise = FALSE; } else { - rasterizerDesc->desc.FrontCounterClockwise = TRUE; + rasterizerStream->desc.FrontCounterClockwise = TRUE; } - rasterizerDesc->desc.DepthClipEnable = !state->enableDepthClamp; - rasterizerDesc->desc.DepthBias = (INT)state->depthBiasConstant; - rasterizerDesc->desc.SlopeScaledDepthBias = state->depthBiasSlope; - rasterizerDesc->desc.DepthBiasClamp = state->depthBiasClamp; + rasterizerStream->desc.DepthClipEnable = !state->enableDepthClamp; + rasterizerStream->desc.DepthBias = (INT)state->depthBiasConstant; + rasterizerStream->desc.SlopeScaledDepthBias = state->depthBiasSlope; + rasterizerStream->desc.DepthBiasClamp = state->depthBiasClamp; } - // Multisample - multisampleDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC; - multisampleDesc->maskType = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK; - multisampleDesc->desc.Quality = 0; - multisampleDesc->desc.Count = 1; + // Sample Desc + SampleDescStream* sampleDescStream = &graphicsStreamDesc.sampleDesc; + totalSize += sizeof(SampleDescStream); + sampleDescStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC; + sampleDescStream->desc.Quality = 0; + sampleDescStream->desc.Count = 1; + + // Sample Mask + SampleMaskStream* sampleMaskStream = &graphicsStreamDesc.sampleMask; + totalSize += sizeof(SampleMaskStream); + sampleMaskStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK; + sampleMaskStream->mask = UINT_MAX; + if (info->multisampleState) { PalMultisampleState* state = info->multisampleState; if (state->sampleMask) { - multisampleDesc->sampleMask = (UINT)state->sampleMask; - } else { - multisampleDesc->sampleMask = UINT32_MAX; + sampleMaskStream->mask = (UINT)state->sampleMask; } - multisampleDesc->desc.Count = samplesToD3D12(state->sampleCount); + sampleDescStream->desc.Count = samplesToD3D12(state->sampleCount); alphaToCoverageEnable = state->enableAlphaToCoverage; } // Depth stencil - depthStencilDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL; + DepthStencilStream* depthStencilStream = &graphicsStreamDesc.depthStencil; + totalSize += sizeof(DepthStencilStream); + depthStencilStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL; + depthStencilStream->desc.DepthEnable = FALSE; + depthStencilStream->desc.StencilEnable = FALSE; + if (info->depthStencilState) { PalDepthStencilState* state = info->depthStencilState; PalStencilOpState* back = &state->backStencilOpState; PalStencilOpState* front = &state->frontStencilOpState; - D3D12_DEPTH_STENCILOP_DESC* d3dBack = &depthStencilDesc->desc.BackFace; - D3D12_DEPTH_STENCILOP_DESC* d3dFront = &depthStencilDesc->desc.FrontFace; + D3D12_DEPTH_STENCILOP_DESC* d3dBack = &depthStencilStream->desc.BackFace; + D3D12_DEPTH_STENCILOP_DESC* d3dFront = &depthStencilStream->desc.FrontFace; d3dBack->StencilFunc = compareOpToD3D12(back->compareOp); d3dBack->StencilDepthFailOp = stencilOpToD3D12(back->depthFailOp); @@ -7246,23 +7304,26 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( d3dFront->StencilFailOp = stencilOpToD3D12(front->failOp); d3dFront->StencilPassOp = stencilOpToD3D12(front->passOp); - depthStencilDesc->desc.DepthFunc = compareOpToD3D12(state->compareOp); - depthStencilDesc->desc.DepthEnable = state->enableDepthTest; - depthStencilDesc->desc.StencilEnable = state->enableStencilTest; + depthStencilStream->desc.DepthFunc = compareOpToD3D12(state->compareOp); + depthStencilStream->desc.DepthEnable = state->enableDepthTest; + depthStencilStream->desc.StencilEnable = state->enableStencilTest; if (state->enableDepthWrite) { - depthStencilDesc->desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + depthStencilStream->desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; } else { - depthStencilDesc->desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + depthStencilStream->desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; } } - // Color blend - colorBlendDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND; - colorBlendDesc->desc.IndependentBlendEnable = TRUE; - colorBlendDesc->desc.AlphaToCoverageEnable = alphaToCoverageEnable; + // Blend + BlendStream* blendStream = &graphicsStreamDesc.blend; + totalSize += sizeof(BlendStream); + blendStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND; + blendStream->desc.IndependentBlendEnable = TRUE; + blendStream->desc.AlphaToCoverageEnable = alphaToCoverageEnable; + if (info->colorBlendAttachmentCount) { for (int i = 0; i < info->colorBlendAttachmentCount; i++) { - D3D12_RENDER_TARGET_BLEND_DESC* tmp = colorBlendDesc[i].desc.RenderTarget; + D3D12_RENDER_TARGET_BLEND_DESC* tmp = &blendStream->desc.RenderTarget[i]; PalColorBlendAttachment* desc = &info->colorBlendAttachments[i]; tmp->BlendEnable = desc->enableBlend; @@ -7305,34 +7366,43 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( } } - // Rendering Layout - renderingLayoutDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS; - renderingLayoutDesc->dsvType = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT; - DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; - PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; + // RTV Formats + RTVStream* rtvStream = &graphicsStreamDesc.RTV; + totalSize += sizeof(RTVStream); + rtvStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS; - // color attachments - renderingLayoutDesc->NumRenderTargets = renderingLayout->colorAttachentCount; - for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { - format = formatToD3D12(renderingLayout->colorAttachmentsFormat[i]); - renderingLayoutDesc->RTVFormats[i] = format; + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + rtvStream->data.NumRenderTargets = info->renderingLayout->colorAttachentCount; + for (int i = 0; i < info->renderingLayout->colorAttachentCount; i++) { + format = formatToD3D12(info->renderingLayout->colorAttachmentsFormat[i]); + rtvStream->data.RTFormats[i] = format; } - // depth stencil attachment - format = formatToD3D12(renderingLayout->depthStencilAttachmentFormat); - renderingLayoutDesc->DSVFormat = format; + // DSV Format + DSVStream* dsvStream = &graphicsStreamDesc.DSV; + totalSize += sizeof(DSVStream); + dsvStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT; + dsvStream->format = formatToD3D12(info->renderingLayout->depthStencilAttachmentFormat); // View Instancing - viewInstancingDesc->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING; - viewInstancingDesc->desc.ViewInstanceCount = info->renderingLayout->viewCount; - viewInstancingDesc->desc.pViewInstanceLocations = viewLocations; - for (int i = 0; i < info->renderingLayout->viewCount; i++) { - viewLocations[i].RenderTargetArrayIndex = i; - viewLocations[i].RenderTargetArrayIndex = i; + ViewInstancingStream* viewInstacingStream = &graphicsStreamDesc.viewInstancing; + totalSize += sizeof(ViewInstancingStream); + viewInstacingStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING; + + viewInstacingStream->desc.ViewInstanceCount = 0; + viewInstacingStream->desc.pViewInstanceLocations = nullptr; + if (info->renderingLayout->viewCount > 1) { + for (int i = 0; i < info->renderingLayout->viewCount; i++) { + viewLocations[i].RenderTargetArrayIndex = i; + viewLocations[i].ViewportArrayIndex = i; + } + + viewInstacingStream->desc.ViewInstanceCount = info->renderingLayout->viewCount; + viewInstacingStream->desc.pViewInstanceLocations = viewLocations; } D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {0}; - streamDesc.pPipelineStateSubobjectStream = &desc; + streamDesc.pPipelineStateSubobjectStream = &graphicsStreamDesc; streamDesc.SizeInBytes = totalSize; result = d3dDevice->handle->lpVtbl->CreatePipelineState( @@ -7569,6 +7639,7 @@ void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) if (d3dPipeline->type == RAY_TRACING_PIPELINE) { ID3D12StateObject* handle = d3dPipeline->handle; handle->lpVtbl->Release(handle); + } else { ID3D12PipelineState* handle = d3dPipeline->handle; handle->lpVtbl->Release(handle); @@ -7585,6 +7656,7 @@ void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) if (d3dPipeline->scratchBuffer) { palFree(s_D3D.allocator, d3dPipeline->scratchBuffer); } + palFree(s_D3D.allocator, d3dPipeline); } diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index 812c135e..c520448f 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -104,7 +104,7 @@ bool clearColorTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(&debugger, nullptr); + result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index c8e0dd60..cc5f376a 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -45,7 +45,7 @@ bool computeTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -220,6 +220,8 @@ bool computeTest() return false; } + palFree(nullptr, bytecode); + // create a storage buffer Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader PalBufferCreateInfo bufferCreateInfo = {0}; diff --git a/tests/graphics/shaders/triangle_frag_shader.dxil b/tests/graphics/shaders/triangle_frag_shader.dxil new file mode 100644 index 0000000000000000000000000000000000000000..b4323e6e0362596f17c3159361db257cd2e9c202 GIT binary patch literal 2948 zcmeHJeN0=|6@T`7yk~;_cwj3r;X}_5n48elm_k4p4S(PoFp7!Y)T>~zNu0onjlr&m zNjp7kgPqh-9YPX!Y!N1D)TY&zFLkBqCK4M;657#}Oi5u8EYxWy+M+C}x@p>WuQ63t zRr_O__E(R5&pG#;-~D*!-uHV}85PQ(t&C~r3SQbuL0&Tn7j8`oFJ#u@07d-EFAw` z@=qWz&St^izYDAd6fRV&o3WbPZHfKD5Cv6IScnQmvDIgRAr?!8ps*-O0eNa|pKCE_ z;hGQzh9>H#H^>dspko64Qjk;`>$DIA*SZMe3g!465!ldX5KHsWiLrc;Bl-#s%crn9 zoRU@!vV7da6i!wi_EIZD)v^_XX$l`D6;yD94eO+efF>lMmFmE&NS0Kwq#;8Y`7xcm zsV}(b{p27fQsYfR1OZ2lWCs^ud59YJYdqfybWs}aw+`gtp7|b=f(G^gQ1JMq`J7aG zPd~=bKjj1Jt}hZ2WNHJ!G@nmPNeYlcf-<&tsP0@*i0?&#}u~|I$ z%z0r!R)#hdOf7n95>t+53R&U-srcnVF?ME9>{WoShaJgnkb{fM)X<45;|BHnF&MiM z)rQn;zUpOe=kn)`+)a~(@6}G?>dC@5j@1?oXz}-!)$t;WlG0KEv!{m2_VwMODJxS;|TAva`f@y_YYkky18L?u6bk2$HQ}2L|4R_ zI4`1$I4Pxa@y~f_qDF&-x4w&2Ja8g>;#3i*zf?{KQ`ub|RJkoG-Sg4Y?cTEHKjN&v zgtb3Hur!zM?+V|~pIJ3E>73h;1v`pjO+|l8(Zf)OVu{rggk#$)oUTS$|z8UOrh-p&{ z+-u!1x%Zi(ZH3}LhZe`CBmIYuUM>6W;iKmoQ$zK8dbT>vWnSJvj89((`faS zvO0)XPxl0!c49w=aBKW_JJD-LT|Is~?a!LdAeTerq9olWNx!>7uIR{8Dwcaklyggz zd&Qi$S8|~0U2oNlvhpG-d)F)Tp;gl>0+)%{-$ra}^LGQy`0XLT-9)&=gzM`RFzrtn z|1OTdOX%+o``zKb;xAUnFBZs$J>&v}n#{UpfR!%7^ z!wLO%v|>nE5kRYkqECQD|L&=pMXSz6xiJy(f*tJ@`(2Db>q8~^^#Z;`llKN%`R>Djg@`V{?`xgHXPw+h|8)I5d=eN z_XGT{H3?~-Q& z%zxxN_#ON%zB|w=_TC@ad_XGpWia_->f>_)AAoW&@I{61ng(?K3$6>()C6vph{xY= zq&T~y%%&J-c9&z|<6Vo;G^wxiDToM;o$_Jod&DXCz}6r0=9E7CVdq z^8TiuggNzd)C<`-$z^!8cYQ3xVBUSkNg!MGEj##A7mPRhTFm zkh2+DC^U#_*(I$Zgy!ICi+0D3pl}ny@${K`0aK?z&mc&-!^f7tUgk%*Su;^y< QSK+MIEWsxj_#*)1U))Av2LJ#7 literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/triangle_frag_shader.hlsl b/tests/graphics/shaders/triangle_frag_shader.hlsl new file mode 100644 index 00000000..756feece --- /dev/null +++ b/tests/graphics/shaders/triangle_frag_shader.hlsl @@ -0,0 +1,11 @@ + +struct PSInput +{ + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +float4 main(PSInput input) : SV_Target +{ + return input.color; +} \ No newline at end of file diff --git a/tests/graphics/shaders/triangle_vert_shader.dxil b/tests/graphics/shaders/triangle_vert_shader.dxil new file mode 100644 index 0000000000000000000000000000000000000000..0cf4d49856ec0be9b0d65aafa41f637150d04915 GIT binary patch literal 3128 zcmeHJeN0=|6~Fc~e$QZ=2YAGeo#>HZ$ zR(%^Nt8`WS0H}iX>!JTe^{Ko>*;FbyE;We`v{anJCE|v9?1EHqz{e?g&Y(CO6gtCATXiYWWF#m63@&D_!+TLT5bp;EOdp#ep7eaW#QpwX1i zpC=YqAqXRu6CKl30D%jLt|gvB8LB1$RR)z3Lyf#<4d$63vIK%vMy-xYqHv4QuTW0k z&4Oo5LSKrDi0*9$jG@l$1M+!>mWfMC25BC)I0+MMWgKg8;Ctwb!4!oDm-31+enqlW z(XR>c2&KAz90;U}H4QhAwk@oeS3CWy?gvL1S!!lA9{~8e0HOaLwSB0JKEd&9P+f$8 z(*iAwQ+t`=GARgXkHCgHBk4AbMKty?GPa%Zz~;VZG{8&O_4`vi9vx0@2V!tk;3%P! z!R@l6yHz!+IyN!3dDiLB!Tb!KZQ9pm@)cTqJr)G^IX~BP+m^V!um!2TBx*a2b`oe? zfZLJibSF9;CX@m!G5`1_m|ceUn$WH#W&}s=F{FtLE5wiy7&?tYOxry!tP`&g^(aT4 zUj_iYWlWsf{;05fa00+Hh{`;j#(^E_)*w%irVIF4Ij_z!lw;|9n#3!W`2H&S;XVm= zb`TC-QVHX;^MeSB0UXnS2S5+pzebq58PNsQ^bFOH*oW31SF*F`#Gme&W2)!G5hi0# zj#tP0bX^_EX;R`kyx;7S;X;pdg}@m}zn)^zt6TY8PmsW-nWm5|_p;aVJCeOOPi`FJ z%qYiR&b@LRTfR|~UVHuB8;ns?4z}l)Sws%jmnSFuoY}Y9j9AOqj_;krk`L~F5`L0h zAeW4==pC*2&i0Vhl2Kb7D%9U$W_|IYZvQ*-i&w_4jbEIq#FH&986oskunTh;eBJBc zVk-IgGQZWxY#ZD0Cgyf-c5~>0p&9RL9%53Cs=fPZwc$$E$Sbf)Q+t=KM}MfLy{psU%6p{nK9oMId#HXbr>ID5g=9mW3&ovzm_rm^ z6*co{<^9THPsp!upgrAaXRw1E0jZC1?h^+$kFD4`JG15LsHmAtio)E&MWlRQS?)*5 z7rXskR`hKQ?a}zGRmJ!Y5cv@kAGu4HlqHi$*+=d&4^q0g!Lystw=HOq#b<-9!)FcntR~bhLG6D_f@Kdod~aaB z4!+M8^z{Utxu0)vKflL)I?Y`tk%swE(b}kJG1}fXi!Nn}!p<$1%*@{glqK`Zl3=v` zFjPFGEbd22heEsHr2lZ0E+eJqLjL(I^!rxChWk3L2=y!`pLO1McmnMWI?L7^sqM1V z2TR-yxL+LvOnk>4&QmjG-Zgk7u5oV6L$pvBAHoBX0*(x8% z=iJ4eGt4Y@*c6&RPCGYh5lMk#M{BFSZD&g(p%PPts#d6l1{^> zxn{^YVv=I1#nHZj;e~>W1H6=>Gu#+nFrjGMQ>Z z*)M<6FQ+>QK0i}l>D%2900hRItF7U6`uW)ab2*)Y+6P1&-so$3X(0wD_S+5w$QWGn xUj5DV7@RgJzWG!XgF6}*-YS_(z+DIQ@#>oQOg9zJ;VVzs2{_AM!i<0P{u_dWkY)e? literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/triangle_vert_shader.hlsl b/tests/graphics/shaders/triangle_vert_shader.hlsl new file mode 100644 index 00000000..965d2fcc --- /dev/null +++ b/tests/graphics/shaders/triangle_vert_shader.hlsl @@ -0,0 +1,20 @@ + +struct VSInput +{ + float2 pos : POSITION; + float3 color : COLOR; +}; + +struct VSOutput +{ + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +VSOutput main(VSInput input) +{ + VSOutput output; + output.pos = float4(input.pos, 0.0, 1.0); + output.color = float4(input.color, 1.0); + return output; +} \ No newline at end of file diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 09c2e481..336cde65 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -1004,10 +1004,12 @@ bool textureTest() // position vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; + vertexAttributes[0].semanticName = nullptr; // use default vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; // texture coordinates vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_TEXCOORD; + vertexAttributes[1].semanticName = nullptr; // use default vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT2; vertexLayout.attributeCount = 2; diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 9ec62d03..52f673b1 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -110,7 +110,7 @@ bool triangleTest() gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; } - PalGraphicsDebugger debugger; + PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; @@ -150,7 +150,9 @@ bool triangleTest() return false; } - PalAdapterCapabilities caps; + PalAdapterCapabilities caps = {0}; + PalAdapterInfo adapterInfo = {0}; + bool hasGraphicsQueue = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -162,23 +164,46 @@ bool triangleTest() } if (caps.maxGraphicsQueues == 0) { + hasGraphicsQueue = false; continue; + } else { - break; + hasGraphicsQueue = true; } + + if (hasGraphicsQueue) { + // We want an adapter that supports spirv 1.0 or dxil 6.0 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + break; + } + } + } + adapter = nullptr; } palFree(nullptr, adapters); if (!adapter) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - return false; - } + if (!hasGraphicsQueue) { + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - PalAdapterInfo adapterInfo = {0}; - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } return false; } @@ -533,6 +558,10 @@ bool triangleTest() if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { vertexShaderPath = "graphics/shaders/triangle_vert_shader.spv"; fragShaderPath = "graphics/shaders/triangle_frag_shader.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + vertexShaderPath = "graphics/shaders/triangle_vert_shader.dxil"; + fragShaderPath = "graphics/shaders/triangle_frag_shader.dxil"; } if (!readFile(vertexShaderPath, nullptr, &bytecodeSize)) { @@ -610,10 +639,12 @@ bool triangleTest() // position vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; + vertexAttributes[0].semanticName = nullptr; // use default vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; // color vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_COLOR; + vertexAttributes[1].semanticName = nullptr; // use default vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT3; vertexLayout.attributeCount = 2; diff --git a/tests/tests_main.c b/tests/tests_main.c index 309b0630..4050d4c0 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -63,8 +63,8 @@ int main(int argc, char** argv) #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest(clearColorTest, "Clear Color Test"); - // registerTest(triangleTest, "Triangle Test"); + // registerTest(clearColorTest, "Clear Color Test"); + registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); #endif // From bc18b34db3870da79883a2e0066c19da33b1ce05 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 28 Apr 2026 11:33:29 +0000 Subject: [PATCH 182/372] fix submit command buffer bug d3d12 --- src/graphics/pal_d3d12.c | 6 +++--- tests/graphics/triangle_test.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 3fe95f1b..01a5629e 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -3111,8 +3111,6 @@ PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) { Queue* d3dQueue = (Queue*)queue; ID3D12Fence* fence = d3dQueue->fence; - d3dQueue->fenceValue++; - fence->lpVtbl->Signal(fence, d3dQueue->fenceValue); // wait on the fence if the submited work is not done if (fence->lpVtbl->GetCompletedValue(fence) < d3dQueue->fenceValue) { @@ -4061,7 +4059,6 @@ PalResult PAL_CALL presentSwapchainD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - pollMessagesD3D12(d3dSwapchain->device); return PAL_RESULT_SUCCESS; } @@ -4651,6 +4648,9 @@ PalResult PAL_CALL submitCommandBufferD3D12( ID3D12CommandList* tmp = (ID3D12CommandList*)d3dCmdBuffer->handle; queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, &tmp); + d3dQueue->fenceValue++; + queueHandle->lpVtbl->Signal(queueHandle, d3dQueue->fence, d3dQueue->fenceValue); + if (info->fence) { Fence* fence = (Fence*)info->fence; fence->value++; diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 52f673b1..5d39077c 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -114,7 +114,7 @@ bool triangleTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); From 11c698c6489272d26a9cc69681c9cb07a1b377b3 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 28 Apr 2026 12:01:48 +0000 Subject: [PATCH 183/372] add a todo for mesh shader test for d3d12 --- tests/graphics/mesh_test.c | 57 ++++++++++++++++++++++++---------- tests/graphics/triangle_test.c | 2 +- tests/tests_main.c | 4 +-- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 98d82112..a5ee0d4d 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -105,7 +105,7 @@ bool meshTest() gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; } - PalGraphicsDebugger debugger; + PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; @@ -145,9 +145,11 @@ bool meshTest() return false; } - PalAdapterCapabilities caps; - PalAdapterFeatures adapterFeatures; - bool hasGfxQueue = false; + PalAdapterCapabilities caps = {0}; + PalAdapterFeatures adapterFeatures = 0; + PalAdapterInfo adapterInfo = {0}; + bool hasGraphicsQueue = false; + bool hasMeshShader = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -159,32 +161,55 @@ bool meshTest() } if (caps.maxGraphicsQueues == 0) { + hasGraphicsQueue = false; continue; + } else { - hasGfxQueue = true; + hasGraphicsQueue = true; adapterFeatures = palGetAdapterFeatures(adapter); if (adapterFeatures & PAL_ADAPTER_FEATURE_MESH_SHADER) { - break; + hasMeshShader = true; + } else { + hasMeshShader = false; } } + + if (hasMeshShader) { + // We want an adapter that supports spirv 1.0 or dxil 6.0 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + break; + } + } + } + adapter = nullptr; } palFree(nullptr, adapters); if (!adapter) { - if (hasGfxQueue) { + if (!hasGraphicsQueue) { palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - } else { + } else if (!hasMeshShader) { palLog(nullptr, "Failed to find an adapter that supports mesh shader"); - } - return false; - } - PalAdapterInfo adapterInfo = {0}; - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } return false; } diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 5d39077c..52f673b1 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -114,7 +114,7 @@ bool triangleTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(&debugger, nullptr); + result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/tests_main.c b/tests/tests_main.c index 4050d4c0..c144ead6 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -64,8 +64,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); - registerTest(triangleTest, "Triangle Test"); - // registerTest(meshTest, "Mesh Test"); + // registerTest(triangleTest, "Triangle Test"); + registerTest(meshTest, "Mesh Test"); // TODO: add dxil shaders // registerTest(textureTest, "Texture Test"); #endif // From da85c745ed7e1c81ff3e5bf6f4ac1ae6062cdfb2 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 28 Apr 2026 16:46:01 +0000 Subject: [PATCH 184/372] texture test working on d3d12 --- include/pal/pal_graphics.h | 20 +- src/graphics/pal_d3d12.c | 180 +++++++++++------- src/graphics/pal_vulkan.c | 47 ++--- tests/graphics/compute_test.c | 1 - tests/graphics/ray_tracing_test.c | 2 - .../graphics/shaders/texture_frag_shader.dxil | Bin 0 -> 3812 bytes .../graphics/shaders/texture_frag_shader.hlsl | 14 ++ .../graphics/shaders/texture_vert_shader.dxil | Bin 0 -> 3100 bytes .../graphics/shaders/texture_vert_shader.hlsl | 20 ++ tests/graphics/texture_test.c | 59 ++++-- tests/tests_main.c | 4 +- 11 files changed, 233 insertions(+), 114 deletions(-) create mode 100644 tests/graphics/shaders/texture_frag_shader.dxil create mode 100644 tests/graphics/shaders/texture_frag_shader.hlsl create mode 100644 tests/graphics/shaders/texture_vert_shader.dxil create mode 100644 tests/graphics/shaders/texture_vert_shader.hlsl diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index a00a70bd..8e383de5 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -186,6 +186,12 @@ typedef struct PalCommandBuffer PalCommandBuffer; /** * @struct PalDescriptorSetLayout * @brief Opaque handle to a descriptor set layout. + * + * This defines the layout, ordering and the number of descriptors a descriptor set uses. + * + * The layouts should reflect the exact layout of the shaders. Eg. + * descriptorBindings[2] = { sampler, sampled image } is different from + * descriptorBindings[2] = { sampled image, sampler }. The ordering must be correct. * * @since 1.4 * @ingroup pal_graphics @@ -1967,11 +1973,12 @@ typedef struct { /** * @struct PalVertexLayout * @brief Vertex layout. + * * This defines the layout, ordering and the number of vertex attributes the layout uses. * - * This layouts should reflect the exact layout of the shaders. Eg. attributes[0] = position - * attribute and attributes[1] = color attribute is not the same as attributes[0] = color attribute - * and attributes[1] = position attribute. The ordering must be correct. + * The layouts should reflect the exact layout of the shaders. Eg. + * attributes[2] = { position, color } is different from + * attributes[2] = { color, position }. The ordering must be correct. * * Uninitialized fields may result in undefined behavior. * @@ -2226,7 +2233,6 @@ typedef struct { */ typedef struct { bool readOnly; /**< For PAL_DESCRIPTOR_TYPE_STORAGE.*/ - Uint32 binding; Uint32 descriptorCount; Uint32 shaderStageCount; PalShaderStage* shaderStages; /**< Array of shader stages that can access the descriptor.*/ @@ -6988,6 +6994,12 @@ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); * Enable `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` when creating the device for descriptor * indexing (bindless resources). The feature must be supported by the device if not, * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * This defines the layout, ordering and the number of descriptors a descriptor set uses. + * + * The layouts should reflect the exact layout of the shaders. Eg. + * descriptorBindings[2] = { sampler, sampled image } is different from + * descriptorBindings[2] = { sampled image, sampler }. The ordering must be correct. * * @param[in] device Device that creates the descriptor set layout. * @param[in] info Pointer to a PalDescriptorSetLayoutCreateInfo struct that specifies parameters. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 01a5629e..ed44224d 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -3441,28 +3441,16 @@ PalResult PAL_CALL bindImageMemoryD3D12( return PAL_RESULT_INVALID_OPERATION; } - D3D12_RESOURCE_STATES state = 0; ID3D12Heap* mem = (ID3D12Heap*)memory; - D3D12_HEAP_DESC __ret = {0}; - D3D12_HEAP_DESC heapProps = {0}; - heapProps = *mem->lpVtbl->GetDesc(mem, &__ret); - - if (heapProps.Properties.Type == D3D12_HEAP_TYPE_UPLOAD) { - state = D3D12_RESOURCE_STATE_GENERIC_READ; - - } else if (heapProps.Properties.Type == D3D12_HEAP_TYPE_READBACK) { - state = D3D12_RESOURCE_STATE_COPY_DEST; - } - result = device->lpVtbl->CreatePlacedResource( device, mem, offset, &d3dImage->desc, - state, + 0, nullptr, &IID_Resource, - (void**)d3dImage->handle); + (void**)&d3dImage->handle); if (FAILED(result)) { pollMessagesD3D12(d3dImage->device); @@ -3517,8 +3505,12 @@ PalResult PAL_CALL createImageViewD3D12( return PAL_RESULT_OUT_OF_MEMORY; } + imageView->heapIndex = UINT32_MAX; + bool hasRTV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); + bool hasDSV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); + imageView->format = formatToD3D12(info->format); - if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR) { + if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR && hasRTV) { RTVHeapAllocator* allocator = &d3dDevice->rtvAllocator; Uint32 index = allocator->freeTop; allocator->freeTop = allocator->freeList[index]; @@ -3528,16 +3520,22 @@ PalResult PAL_CALL createImageViewD3D12( D3D12_RENDER_TARGET_VIEW_DESC desc = {0}; desc.Format = imageView->format; - fillSubresourceD3D12(info->type, &info->subresourceRange, &desc, nullptr, nullptr, nullptr); - imageView->heapIndex = index; + fillSubresourceD3D12( + info->type, + &info->subresourceRange, + &desc, + nullptr, + nullptr, + nullptr); + imageView->heapIndex = index; d3dDevice->handle->lpVtbl->CreateRenderTargetView( d3dDevice->handle, d3dImage->handle, &desc, dst); - } else { + } else if (info->subresourceRange.aspect != PAL_IMAGE_ASPECT_COLOR && hasDSV) { DSVHeapAllocator* allocator = &d3dDevice->dsvAllocator; Uint32 index = allocator->freeTop; allocator->freeTop = allocator->freeList[index]; @@ -3547,9 +3545,15 @@ PalResult PAL_CALL createImageViewD3D12( D3D12_DEPTH_STENCIL_VIEW_DESC desc = {0}; desc.Format = imageView->format; - fillSubresourceD3D12(info->type, &info->subresourceRange, nullptr, &desc, nullptr, nullptr); - imageView->heapIndex = index; + fillSubresourceD3D12( + info->type, + &info->subresourceRange, + nullptr, + &desc, + nullptr, + nullptr); + imageView->heapIndex = index; d3dDevice->handle->lpVtbl->CreateDepthStencilView( d3dDevice->handle, d3dImage->handle, @@ -3572,15 +3576,17 @@ void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) Device* device = d3dImageView->device; RTVHeapAllocator* allocator = nullptr; - if (d3dImageView->range.aspect == PAL_IMAGE_ASPECT_COLOR) { - RTVHeapAllocator* allocator = &device->rtvAllocator; - allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; - allocator->freeTop = d3dImageView->heapIndex; + if (d3dImageView->heapIndex != UINT32_MAX) { + if (d3dImageView->range.aspect == PAL_IMAGE_ASPECT_COLOR) { + RTVHeapAllocator* allocator = &device->rtvAllocator; + allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; + allocator->freeTop = d3dImageView->heapIndex; - } else { - DSVHeapAllocator* allocator = &device->dsvAllocator; - allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; - allocator->freeTop = d3dImageView->heapIndex; + } else { + DSVHeapAllocator* allocator = &device->dsvAllocator; + allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; + allocator->freeTop = d3dImageView->heapIndex; + } } palFree(s_D3D.allocator, d3dImageView); } @@ -6168,18 +6174,18 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( Uint64* outSize) { Uint32 imageFormatSize = getFormatSizeD3D12(imageFormat); - Uint32 height = 0; - Uint64 rowPitch = alignD3D12((Uint64)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); - height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; + Uint32 rowPitch = alignD3D12((Uint64)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + Uint32 bufferImageHeight = 0; - *outBufferRowLength = rowPitch; - if (height == copyInfo->imageHeight) { - *outBufferImageHeight = 0; + if (copyInfo->bufferImageHeight) { + bufferImageHeight = copyInfo->bufferImageHeight; } else { - *outBufferImageHeight = height; + bufferImageHeight = copyInfo->imageHeight; } - *outSize = rowPitch * height * copyInfo->imageDepth; + *outBufferRowLength = rowPitch; + *outBufferImageHeight = bufferImageHeight; + *outSize = (Uint64)rowPitch * bufferImageHeight * copyInfo->imageDepth; return PAL_RESULT_SUCCESS; } @@ -6213,23 +6219,21 @@ PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( PalBufferImageCopyInfo* copyInfo) { Uint32 imageFormatSize = getFormatSizeD3D12(imageFormat); - Uint32 length, height; - length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; - height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; + Uint32 srcRowPitch = copyInfo->imageWidth * imageFormatSize; + const Uint32 dstSlicePitch = copyInfo->bufferRowLength * copyInfo->bufferImageHeight; + const Uint32 srcSlicePitch = srcRowPitch * copyInfo->imageHeight; // manually offset the buffer with the provided offset Uint8* dst = (Uint8*)ptr + copyInfo->bufferOffset; const Uint8* src = (const Uint8*)srcData; - Uint64 tmpSizeDest = length * height * imageFormatSize; - Uint64 tmpSizeSrc = copyInfo->imageWidth * copyInfo->imageHeight * imageFormatSize; // write to destination pointer for (Uint32 z = 0; z < copyInfo->imageDepth; z++) { for (Uint32 y = 0; y < copyInfo->imageHeight; y++) { memcpy( - dst + z * tmpSizeDest + y * (length * imageFormatSize), - src + z * tmpSizeSrc + y * (copyInfo->imageWidth * imageFormatSize), - copyInfo->imageWidth * imageFormatSize); + dst + z * dstSlicePitch + y * copyInfo->bufferRowLength, + src + z * srcSlicePitch + y * srcRowPitch, + srcRowPitch); } } @@ -6339,49 +6343,71 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - Uint32 offset = 0; + Uint32 resourceOffset = 0; + Uint32 samplerOffset = 0; Uint32 samplerCount = 0; + + Uint32 sampledASIndex = 0; + Uint32 uniformIndex = 0; + Uint32 storageIndex = 0; + for (int i = 0; i < count; i++) { DescriptorSetBinding* binding = &bindings[i]; binding->type = info->bindings[i].descriptorType; binding->range.NumDescriptors = info->bindings[i].descriptorCount; - binding->range.BaseShaderRegister = info->bindings[i].binding; binding->range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; - binding->range.RegisterSpace = 0; - binding->range.OffsetInDescriptorsFromTableStart = offset; - offset += info->bindings[i].descriptorCount; switch (info->bindings[i].descriptorType) { case PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE: case PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + binding->range.BaseShaderRegister = sampledASIndex++; + + binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; + resourceOffset += info->bindings[i].descriptorCount; break; } case PAL_DESCRIPTOR_TYPE_SAMPLER: { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - samplerCount++; + binding->range.BaseShaderRegister = samplerCount++; + + binding->range.OffsetInDescriptorsFromTableStart = samplerOffset; + samplerOffset += info->bindings[i].descriptorCount; break; } case PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER: { if (info->bindings[i].readOnly) { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + binding->range.BaseShaderRegister = sampledASIndex++; } else { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + binding->range.BaseShaderRegister = storageIndex++; } + + binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; + resourceOffset += info->bindings[i].descriptorCount; break; } case PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE: { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + binding->range.BaseShaderRegister = storageIndex++; + + binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; + resourceOffset += info->bindings[i].descriptorCount; break; } case PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; + binding->range.BaseShaderRegister = uniformIndex++; + + binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; + resourceOffset += info->bindings[i].descriptorCount; break; } } @@ -6664,14 +6690,13 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( Uint32 totalDescriptors = asCount + storageBufferCount + uniformBufferCount; totalDescriptors += sampledImageCount + storageImageCount; d3dPool->resourceHeap.nextOffset += totalDescriptors; - d3dPool->samplerHeap.nextOffset += totalDescriptors; + d3dPool->samplerHeap.nextOffset += samplerCount; limits->usedAs += asCount; limits->usedSampledImages += sampledImageCount; limits->usedSamplers += samplerCount; limits->usedStorageBuffers += storageBufferCount; limits->usedUniformBuffers += uniformBufferCount; - d3dPool->usedSets++; *outSet = (PalDescriptorSet*)set; return PAL_RESULT_SUCCESS; @@ -6692,18 +6717,18 @@ PalResult PAL_CALL updateDescriptorSetD3D12( DescriptorHeap* heap = nullptr; Uint32 index = 0; - Uint32 bindingOffsetffset = binding->range.OffsetInDescriptorsFromTableStart; + Uint32 bindingOffset = binding->range.OffsetInDescriptorsFromTableStart; if (info->arrayElement + binding->range.NumDescriptors > layout->bindingCount) { return PAL_RESULT_INVALID_ARGUMENT; } if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { heap = &pool->samplerHeap; - index = set->samplerOffset + bindingOffsetffset + info->arrayElement; + index = set->samplerOffset + bindingOffset + info->arrayElement; } else { heap = &pool->resourceHeap; - index = set->resourceOffset + bindingOffsetffset + info->arrayElement; + index = set->resourceOffset + bindingOffset + info->arrayElement; } for (int y = 0; y < binding->range.NumDescriptors; y++) { @@ -6717,6 +6742,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { AccelerationStructure* tlas = (AccelerationStructure*)info->tlasInfo->tlas; D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; + desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; desc.RaytracingAccelerationStructure.Location = tlas->address; desc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; @@ -6729,7 +6755,9 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { ImageView* imageView = (ImageView*)info->imageViewInfo->imageView; D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; + desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; desc.Format = imageView->format; + fillSubresourceD3D12( imageView->type, &imageView->range, @@ -6748,6 +6776,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( ImageView* imageView = (ImageView*)info->imageViewInfo->imageView; D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; desc.Format = imageView->format; + fillSubresourceD3D12( imageView->type, &imageView->range, @@ -6782,6 +6811,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( Buffer* buffer = (Buffer*)info->bufferInfo->buffer; if (info->bufferInfo->readOnly) { D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; + desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + Uint32 stride = 4; if (info->bufferInfo->stride) { stride = info->bufferInfo->stride; @@ -6843,6 +6874,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( Uint32 resourceCount = 0; Uint32 samplerCount = 0; Uint32 pushConstantSize = 0; + Uint32 sizeInBytes = sizeof(D3D12_DESCRIPTOR_RANGE1); D3D12_DESCRIPTOR_RANGE1* ranges = nullptr; D3D12_DESCRIPTOR_RANGE1* samplerRanges = nullptr; @@ -6861,24 +6893,37 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } } - Uint32 sizeInBytes = sizeof(D3D12_DESCRIPTOR_RANGE1); layout = palAllocate(s_D3D.allocator, sizeof(PipelineLayout), 0); - ranges = palAllocate(s_D3D.allocator, sizeInBytes * resourceCount, 0); - samplerRanges = palAllocate(s_D3D.allocator, sizeInBytes * samplerCount, 0); - if (!layout || !ranges || !samplerRanges) { + if (!layout) { return PAL_RESULT_OUT_OF_MEMORY; } memset(layout, 0, sizeof(PipelineLayout)); + if (resourceCount) { + ranges = palAllocate(s_D3D.allocator, sizeInBytes * resourceCount, 0); + if (!ranges) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } + + if (samplerCount) { + samplerRanges = palAllocate(s_D3D.allocator, sizeInBytes * samplerCount, 0); + if (!samplerRanges) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } + + Uint32 tmpResourceIndex = 0; + Uint32 tmpSamplerIndex = 0; for (int i = 0; i < info->descriptorSetLayoutCount; i++) { DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; // seperate the samplers from the remaining descriptors for (int i = 0; i < tmp->bindingCount; i++) { DescriptorSetBinding* binding = &tmp->bindings[i]; if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { - samplerRanges[i] = binding->range; + samplerRanges[tmpResourceIndex++] = binding->range; } else { - ranges[i] = binding->range; + ranges[tmpSamplerIndex++] = binding->range; } } } @@ -6931,7 +6976,8 @@ PalResult PAL_CALL createPipelineLayoutD3D12( rootDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; ID3DBlob* blob = nullptr; - HRESULT result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); + ID3DBlob* errBlob = nullptr; + HRESULT result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, &errBlob); if (FAILED(result)) { pollMessagesD3D12(d3dDevice); if (result == E_INVALIDARG) { @@ -6958,9 +7004,15 @@ PalResult PAL_CALL createPipelineLayoutD3D12( return PAL_RESULT_PLATFORM_FAILURE; } + if (resourceCount) { + palFree(s_D3D.allocator, ranges); + } + + if (samplerCount) { + palFree(s_D3D.allocator, samplerRanges); + } + blob->lpVtbl->Release(blob); - palFree(s_D3D.allocator, ranges); - palFree(s_D3D.allocator, samplerRanges); *outLayout = (PalPipelineLayout*)layout; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 4795f18e..3a228d0e 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -7978,24 +7978,25 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( Uint32* outBufferImageHeight, Uint64* outSize) { - Uint32 length, height; - length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; - height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; - Uint32 rowPitch = length * getFormatSizeVk(imageFormat); + Uint32 imageFormatSize = getFormatSizeVk(imageFormat); + Uint32 rowPitch = 0; + Uint32 bufferImageHeight = 0; - if (length == copyInfo->imageWidth) { - *outBufferRowLength = 0; + if (copyInfo->bufferRowLength) { + rowPitch = copyInfo->bufferRowLength; } else { - *outBufferRowLength = length; + rowPitch = copyInfo->imageWidth * imageFormatSize; } - if (height == copyInfo->imageHeight) { - *outBufferImageHeight = 0; + if (copyInfo->bufferImageHeight) { + bufferImageHeight = copyInfo->bufferImageHeight; } else { - *outBufferImageHeight = height; + bufferImageHeight = copyInfo->imageHeight; } - *outSize = rowPitch * height * copyInfo->imageDepth; + *outBufferRowLength = rowPitch; + *outBufferImageHeight = bufferImageHeight; + *outSize = (Uint64)rowPitch * bufferImageHeight * copyInfo->imageDepth; return PAL_RESULT_SUCCESS; } @@ -8029,30 +8030,21 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( PalBufferImageCopyInfo* copyInfo) { Uint32 imageFormatSize = getFormatSizeVk(imageFormat); - if (copyInfo->bufferRowLength == 0 && copyInfo->bufferImageHeight == 0) { - Uint64 size = copyInfo->imageWidth * copyInfo->imageHeight * copyInfo->imageDepth; - // normal path. Simple memcpy works - memcpy(ptr, srcData, size * imageFormatSize); - return PAL_RESULT_SUCCESS; - } - - Uint32 length, height; - length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; - height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; + Uint32 srcRowPitch = copyInfo->imageWidth * imageFormatSize; + const Uint32 dstSlicePitch = copyInfo->bufferRowLength * copyInfo->bufferImageHeight; + const Uint32 srcSlicePitch = srcRowPitch * copyInfo->imageHeight; // manually offset the buffer with the provided offset Uint8* dst = (Uint8*)ptr + copyInfo->bufferOffset; const Uint8* src = (const Uint8*)srcData; - Uint64 tmpSizeDest = length * height * imageFormatSize; - Uint64 tmpSizeSrc = copyInfo->imageWidth * copyInfo->imageHeight * imageFormatSize; // write to destination pointer for (Uint32 z = 0; z < copyInfo->imageDepth; z++) { for (Uint32 y = 0; y < copyInfo->imageHeight; y++) { memcpy( - dst + z * tmpSizeDest + y * (length * imageFormatSize), - src + z * tmpSizeSrc + y * (copyInfo->imageWidth * imageFormatSize), - copyInfo->imageWidth * imageFormatSize); + dst + z * dstSlicePitch + y * copyInfo->bufferRowLength, + src + z * srcSlicePitch + y * srcRowPitch, + srcRowPitch); } } @@ -8153,9 +8145,10 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( createInfo.bindingCount = count; createInfo.pBindings = bindings; + Uint32 bindingIndex = 0; for (int i = 0; i < count; i++) { VkDescriptorSetLayoutBinding* binding = &bindings[i]; - binding->binding = info->bindings[i].binding; + binding->binding = bindingIndex++; binding->descriptorCount = info->bindings[i].descriptorCount; binding->descriptorType = descriptortypeToVk(info->bindings[i].descriptorType); diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index cc5f376a..f61fb6e0 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -310,7 +310,6 @@ bool computeTest() PalDescriptorSetLayoutBinding descriptorBinding = {0}; PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_COMPUTE }; - descriptorBinding.binding = 0; descriptorBinding.descriptorCount = 1; // not an array descriptorBinding.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; descriptorBinding.shaderStageCount = 1; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index b5d8312b..58daaec5 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -720,14 +720,12 @@ bool rayTracingTest() PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_RAYGEN }; // storage buffer to write to - descriptorBindings[0].binding = 0; descriptorBindings[0].descriptorCount = 1; // not an array descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; descriptorBindings[0].shaderStageCount = 1; descriptorBindings[0].shaderStages = shaderStages; // acceleration buffer - descriptorBindings[1].binding = 1; descriptorBindings[1].descriptorCount = 1; // not an array descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE; descriptorBindings[1].shaderStageCount = 1; diff --git a/tests/graphics/shaders/texture_frag_shader.dxil b/tests/graphics/shaders/texture_frag_shader.dxil new file mode 100644 index 0000000000000000000000000000000000000000..3df641a1963568bec8201b22802521c01e951672 GIT binary patch literal 3812 zcmeHKeNa=`6~D=Qy!Qg(nIS&Dyo=QrYmeuuj5!?DINHSqCH~KW<%fhF!#H(wdKe zkT~^Z25H|D>CvikO}6pId+(#m(y&~(QSAE>+s4>!#g*KnftDFoMVNAF6RW%dct=4d zjANfkXx6EjYyz$hfZYrL8Ytr;GkDC_UFg2ZE(;tcEKa*4Nfv5yb z5iZ?t!Lk9yB2s@y8>w}ev!m(qAG)pfXKnU^qK7TF)B5Qx)belm`+uevNS;c(`~Z`A zJ-vn&Z{e#49kO&v)VN1I7?ngxZAyOpC%sACnxrAO;tb~}t;lMxCS_2QJjhu#V@hdt zCwblSLFA2gM1D?_=Qk>gUqqcQB1 zmYh`zzGejX7`)4cKhcsCO2Gq0@ScvGo*~DTf-->BjN!U5Jfpq!%bcsC+`h?^;L*xd z&)cq4htZpZa)D4(<+9f3tg=#TeJKLnCx*Rx+DIX(Yp7{(ui{{Xa3l2b&0;68s z2Yx-p0C;|VL_bVW0(i)LB%L%FeOHH_F##}!J+E;Q?V^yNY`cvYlRkiIBBP~TEq{%6 zQL#3nKbOe=`C-1l9(54@mT5j14*{39NHBO}XV|s`>fyPmhcXn&wx@B0o>;~$)|mEX zoebz)k;U0v*;{F#r z4*TzuujuSxMAuMLA&m55;^3md)iR^cXp#JK8r;^4Zkhw1TO$ z#AxD}eY|J1?cx>oA$ZL(TkC#Wt1qi9uF5kXCPNNg4*Mm&;lRdg;te6UTfs6-)BVU_ z$i6A~abkfiG1{?w&v=jbUT>RUPtW<`UF<$w$>E)Ni_NjU_}$E{c{Tc);ym+5Fj3Y4 z@dq0tuK((w`13oh40#q-wVfa78HSZ}co2Blcg^BZJYfv;jE9woI4RAVB#YaoHsbYl zcy)Uve+mfxL6MJ*WISIT(bpUPsWYrZ>gNk<6b~Wr4yV|Vl%YCXjRD_D;Pn|+g8^?a zAhmT?17i&t3L>ZN>}{=(3MOXA87&!4dBX2X!bT2CSCM!8p$d)TB$znUSx8Y91U zk<(J7XwVrp=?ok4jd%26mn2~xQ}`u4cEb*PjV8I>H=c1PwQ7=@5qYcoO<44qS$-Xn zcf0u>3I3h|X;^BlHCjW4HRS9VHp!6p$FL_9`4ILTyWoLV@EGn_B?G`BDASn0{SOou zs32FWMH#=+;+O5dC;#1Fl3a{TuEdWKBK$r+phAJ;ZG^c`w>5(tqjwpThsP^0R;J<$~!s3i=9(Oul!kwB0xO4C| z?!3mGSHYe6a|gvM;|}{8XTRU~cHh z>de|%4bfl-b(YFd59&0;5dA0hlDP7Tv(6}mkysye!+UL?Xc%=GV+hL$6@|o(cJp

A;;<*HH)wan|6p zf|$=9rxgsyqBAbR);`#F<^0IS-?YKr{^5VY!LgU&zzF-!>;C`$(f{=f0L$U|7ow__ z?0*SA$dA)Nb88=8dGSZ;@!Vyc(0FKz!g#=}1I4?lHw`wcxJHIn9t_eK#ueECLtstY zN<%C*dI=!RrhkTa6fB9t1TfrNhsP4C+_H{!wiwh^YNl*4{Jv6d>|7*AjZw6*cg^=^ RaSLar=!G*?Fas9?=|AZGp`-u+ literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/texture_frag_shader.hlsl b/tests/graphics/shaders/texture_frag_shader.hlsl new file mode 100644 index 00000000..dca9f232 --- /dev/null +++ b/tests/graphics/shaders/texture_frag_shader.hlsl @@ -0,0 +1,14 @@ + +Texture2D tex : register(t0); +SamplerState samp : register(s0); + +struct PSInput +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD; +}; + +float4 main(PSInput input) : SV_Target +{ + return tex.Sample(samp, input.uv); +} \ No newline at end of file diff --git a/tests/graphics/shaders/texture_vert_shader.dxil b/tests/graphics/shaders/texture_vert_shader.dxil new file mode 100644 index 0000000000000000000000000000000000000000..9ab0b1ccc04cd235c76fcfd460d4ebadf4608e31 GIT binary patch literal 3100 zcmeHJe^3+o72nM+*$pINfp8Z{U^XCJJSm1q1C-FoFOZm6A_*SXk-5Nuhc^%tq6m01 z%`Zs6&_)DFjpG1%9$IUGqvzS)A3|s+hp4HC9jMmP%5m2jw2UL2cG_wC-Gtmw+dn#; zY5%%6`F`K~zW4dQmwn&e&#tOgp}gOc8GLr<@{6UN&j$y7dh{j?K@gt_K^V|dFtlJy zfWZZUbubp`K!c&LP>XQjkBM5pyWjv=(7=fKD`P>Rkxd(k8DPEdr8reP7S~nj)dqFd zcOXM~t+J}BS_NWNpoS6Xe^(>27sMz@jH<|N*kV(qBRFtf2D#w@*k=UDA^=v^sy3Fnjh%c?eb03315)>|*A`;c1!Zi3S@{PE!mdC|rb?Q;c&p@nVIi z(#Ii{6`uE@G_hi(lI=^%n$yYm*}adQpZB4H3i>`S1cBQJ;&~rYZNy}>ah7YHG7%D# zh14KU^)$s{RFFXTf{8j$aTd-X8@thztP3tMJ#mftILTU%H^Jr75~6G<2kJ|+mC!`~ zY*}A{%AnfMB*)Tc?KTzIpTcRo;XYz?OPbxC%?PkrKhd#U!|X0FLy27?tZf9dl31&c zZHXBjF~efSC_tG0`z^3`8P;XQj)du}1lAr!8rdL26uAmQBN)K6K4ODBn;9Y=<+-mO z4hZUz(g~{l5n*-`Bm~YNA|V<~-J;@5KPN3o>+>>lcmEPqjwN$pVUJk&gDD|;c>vfB zu@L>uBoV|>$aVwZJ3;T>209(l`YLECa|L9Or?j8ae3)>4hX(Go%vkJ}(aB48SU&ox z-~?mGO@>pwOrR-fgP$bk==G!oN98jnlS9Vg^&o;=oHhY3iHMt10;7cKysITnzoT6D zH797S*|d$qA=S`}l|s32kfE4t!95JcjF!OPcAD#WuPDxp_oe4KW<9#pdRAGPI;pjm z-a7XByA$;I`(z_;c>9lbj$gZ8__OJvYYfG&v_$+n4jG^4N?=OzR7IWlirzz0>AchO z!1#Rn75l6NZxGRW^zSomtnTC?7@DZG2F?cpB!Tx|pZ;*CWQsvM8TM;R|8nO1edAd; z{enIH3S8aYf9vY4oc=2d{iZ#HK@hY~?l=|D9JdCNiM^rq18cKOYx64?(eezjbhu<% zG$p=%v1m&C(RR4HmwBf1DAP}#jc=N zVZ%B*Fst9fT!j*!66_Z?_AaI(b9N@<_9*|LC@unX@)nS?kh08+lr404kC?IJIM!L| zHk+|7Gt%DSHk0nOg(UWxkNsGbXc8qpS!b{7*t>|ijE4gLk|1NYKJ%ccxAYTdX;@h@ zjYvOnN?l0l!aAqjh#hanikjVRV79r+ENb*c&(4Ya*l}G|FEY$5%Jr3;O`DZEow;}k z&bm<2cdXb6e@5}$wzw$&slkJ{mH(K)ALBpS*ZlXtunG^pO3uW zn`FxpIu#=s2?bsm_~MAX(JB7h3ljg={FjTXCgogae7iLTom~=S=NkLPC&`j z3tKgE?&84sz`3)zc)1ub9}6y!3r{m>mKH+zZcriBZ7UC|RH;dqv#yMO@Y?n<)=jhg zB!~4GQNu$Mo`{<^;x;716~ljAmB@wu2=n2MPT5gFm`+JAuQ=!B85`fesP63+|N1vKez{*d?EL2_Kt^F_lOxkXf_9P*6s@%5$d$>pI>_cFZS zYV63jHrF>cwe3CJ*wmtTTwtf2J5l%D<+|i$P93*ydC+)C+4Dv9YQ<~A*v9GAilU+% z0{NP!{+~QmPeM>GxKC41c^>uc1*iuySa)zHB-Jau|&|C+8c# z@W^R4lFLmkP`e8nd=QD#dup_LtCzbC!X0)?8fS=%!fgjCYszM$aPrmanmwW@Jk)I% c(nsNNo1o?%HwO3Al+DH94K?#NP#DNR03S|!jsO4v literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/texture_vert_shader.hlsl b/tests/graphics/shaders/texture_vert_shader.hlsl new file mode 100644 index 00000000..ff9ef8cc --- /dev/null +++ b/tests/graphics/shaders/texture_vert_shader.hlsl @@ -0,0 +1,20 @@ + +struct VSInput +{ + float2 pos : POSITION; + float2 uv : TEXCOORD; +}; + +struct VSOutput +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD; +}; + +VSOutput main(VSInput input) +{ + VSOutput output; + output.pos = float4(input.pos, 0.0, 1.0); + output.uv = input.uv; + return output; +} \ No newline at end of file diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 336cde65..d6bcf694 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -144,11 +144,11 @@ bool textureTest() gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; } - PalGraphicsDebugger debugger; + PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -184,7 +184,9 @@ bool textureTest() return false; } - PalAdapterCapabilities caps; + PalAdapterCapabilities caps = {0}; + PalAdapterInfo adapterInfo = {0}; + bool hasGraphicsQueue = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -196,23 +198,46 @@ bool textureTest() } if (caps.maxGraphicsQueues == 0) { + hasGraphicsQueue = false; continue; + } else { - break; + hasGraphicsQueue = true; + } + + if (hasGraphicsQueue) { + // We want an adapter that supports spirv 1.0 or dxil 6.0 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + break; + } + } } + adapter = nullptr; } palFree(nullptr, adapters); if (!adapter) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - return false; - } + if (!hasGraphicsQueue) { + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - PalAdapterInfo adapterInfo = {0}; - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } return false; } @@ -587,6 +612,10 @@ bool textureTest() return false; } + // update our copy with the required buffer row length and buffer image height + bufferImageCopyInfo.bufferRowLength = bufferRowLength; + bufferImageCopyInfo.bufferImageHeight = bufferImageHeight; + // create staging buffer to transfer the data to the image PalBuffer* imageStagingBuffer = nullptr; PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; @@ -827,6 +856,10 @@ bool textureTest() if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { vertexShaderPath = "graphics/shaders/texture_vert_shader.spv"; fragShaderPath = "graphics/shaders/texture_frag_shader.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + vertexShaderPath = "graphics/shaders/texture_vert_shader.dxil"; + fragShaderPath = "graphics/shaders/texture_frag_shader.dxil"; } if (!readFile(vertexShaderPath, nullptr, &bytecodeSize)) { @@ -886,13 +919,11 @@ bool textureTest() PalDescriptorSetLayoutBinding descriptorBindings[2]; PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; - descriptorBindings[0].binding = 0; descriptorBindings[0].descriptorCount = 1; // not an array descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; descriptorBindings[0].shaderStageCount = 1; descriptorBindings[0].shaderStages = shaderStages; - descriptorBindings[1].binding = 1; descriptorBindings[1].descriptorCount = 1; // not an array descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; descriptorBindings[1].shaderStageCount = 1; diff --git a/tests/tests_main.c b/tests/tests_main.c index c144ead6..1c5706ee 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -65,8 +65,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); - registerTest(meshTest, "Mesh Test"); // TODO: add dxil shaders - // registerTest(textureTest, "Texture Test"); + // registerTest(meshTest, "Mesh Test"); // TODO: add dxil shaders + registerTest(textureTest, "Texture Test"); #endif // runTests(); From de14afa9c8330c49c2c436bb39aaef6f2a561f4f Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 28 Apr 2026 21:47:33 +0000 Subject: [PATCH 185/372] fix staging image write function vulkan --- src/graphics/pal_vulkan.c | 41 ++++++++++++++----------------- tests/graphics/ray_tracing_test.c | 2 +- tests/graphics/texture_test.c | 2 +- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 3a228d0e..8554b76d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -587,7 +587,7 @@ typedef struct { VkPipelineBindPoint bindPoint; Device* device; VkPipeline handle; - PipelineLayout* layout; + VkPipelineLayout layout; } Pipeline; typedef struct { @@ -7539,7 +7539,7 @@ PalResult PAL_CALL cmdBindDescriptorSetVk( s_Vk.cmdBindDescriptorSets( vkCmdBuffer->handle, pipeline->bindPoint, - pipeline->layout->handle, + pipeline->layout, setIndex, 1, &vkSet->handle, @@ -7568,7 +7568,7 @@ PalResult PAL_CALL cmdPushConstantsVk( s_Vk.cmdPushConstants( vkCmdBuffer->handle, - pipeline->layout->handle, + pipeline->layout, stages, offset, size, @@ -7979,24 +7979,15 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( Uint64* outSize) { Uint32 imageFormatSize = getFormatSizeVk(imageFormat); - Uint32 rowPitch = 0; - Uint32 bufferImageHeight = 0; - - if (copyInfo->bufferRowLength) { - rowPitch = copyInfo->bufferRowLength; - } else { - rowPitch = copyInfo->imageWidth * imageFormatSize; - } - - if (copyInfo->bufferImageHeight) { - bufferImageHeight = copyInfo->bufferImageHeight; - } else { - bufferImageHeight = copyInfo->imageHeight; - } - - *outBufferRowLength = rowPitch; - *outBufferImageHeight = bufferImageHeight; - *outSize = (Uint64)rowPitch * bufferImageHeight * copyInfo->imageDepth; + Uint32 length = 0; + Uint32 height = 0; + length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; + height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; + Uint32 rowPitch = length * imageFormatSize; + + *outBufferRowLength = length; + *outBufferImageHeight = height; + *outSize = (Uint64)rowPitch * length * copyInfo->imageDepth; return PAL_RESULT_SUCCESS; } @@ -8030,8 +8021,9 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( PalBufferImageCopyInfo* copyInfo) { Uint32 imageFormatSize = getFormatSizeVk(imageFormat); + Uint32 dstRowPitch = copyInfo->bufferRowLength * imageFormatSize; Uint32 srcRowPitch = copyInfo->imageWidth * imageFormatSize; - const Uint32 dstSlicePitch = copyInfo->bufferRowLength * copyInfo->bufferImageHeight; + const Uint32 dstSlicePitch = dstRowPitch * copyInfo->bufferImageHeight; const Uint32 srcSlicePitch = srcRowPitch * copyInfo->imageHeight; // manually offset the buffer with the provided offset @@ -8042,7 +8034,7 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( for (Uint32 z = 0; z < copyInfo->imageDepth; z++) { for (Uint32 y = 0; y < copyInfo->imageHeight; y++) { memcpy( - dst + z * dstSlicePitch + y * copyInfo->bufferRowLength, + dst + z * dstSlicePitch + y * dstRowPitch, src + z * srcSlicePitch + y * srcRowPitch, srcRowPitch); } @@ -8923,6 +8915,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; pipeline->device = vkDevice; + pipeline->layout = layout->handle; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -8962,6 +8955,7 @@ PalResult PAL_CALL createComputePipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; pipeline->device = vkDevice; + pipeline->layout = layout->handle; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -9046,6 +9040,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; pipeline->device = vkDevice; + pipeline->layout = layout->handle; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 58daaec5..4a84227e 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -56,7 +56,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index d6bcf694..755d340c 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -148,7 +148,7 @@ bool textureTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(&debugger, nullptr); + result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); From 23d18ad6817224ac8db44ca7acb4e8c6f1e0b61e Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 29 Apr 2026 09:46:16 +0000 Subject: [PATCH 186/372] compute test: remove shader files dependency and embed shader sources and bytecode into source file --- tests/graphics/compute_test.c | 477 ++++++++++++++++++++- tests/graphics/shaders/compute_shader.dxil | Bin 3416 -> 0 bytes tests/graphics/shaders/compute_shader.glsl | 27 -- tests/graphics/shaders/compute_shader.hlsl | 22 - tests/graphics/shaders/compute_shader.spv | Bin 1704 -> 0 bytes tests/tests_main.c | 4 +- 6 files changed, 462 insertions(+), 68 deletions(-) delete mode 100644 tests/graphics/shaders/compute_shader.dxil delete mode 100644 tests/graphics/shaders/compute_shader.glsl delete mode 100644 tests/graphics/shaders/compute_shader.hlsl delete mode 100644 tests/graphics/shaders/compute_shader.spv diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index f61fb6e0..dd772391 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -4,6 +4,462 @@ #define BUFFER_SIZE 400 +// clang-format off + +// Compute Shader Source Code GLSL +// #version 450 + +// layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +// layout(set = 0, binding = 0) buffer OutputBuffer +// { +// vec4 pixels[]; +// } outBuffer; + +// layout(push_constant) uniform PushConstants +// { +// uint width; +// uint height; +// vec4 color; +// } pc; + +// void main() +// { +// uvec2 id = gl_GlobalInvocationID.xy; +// if (id.x >= pc.width || id.y >= pc.height) { +// return; +// } + +// uint index = id.y * pc.width + id.x; +// outBuffer.pixels[index] = pc.color; +// } + +// Compute Shader Source Code HLSL +// struct PushConstants +// { +// uint width; +// uint height; +// float4 color; +// }; + +// We used raw Buffer but structured buffer can be used as well. +// PalDescriptorBufferInfo::stride must be set to 16 + +// RWByteAddressBuffer outBuffer : register(u0); +// ConstantBuffer pc : register(b0); + +// [numThreads(16, 16, 1)] +// void main(uint3 id : SV_DispatchThreadID) +// { +// if (id.x >= pc.width || id.y >= pc.height) { +// return; +// } + +// uint index = id.y * pc.width + id.x; +// uint offset = index * 16; // sizeof(float4) +// outBuffer.Store4(offset, asuint(pc.color)); +// } + +static const Uint32 s_ComputeShaderSpv[] = { + 0x07230203, 0x00010000, 0x0008000b, 0x00000043, + 0x00000000, 0x00020011, 0x00000001, 0x0006000b, + 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, + 0x0006000f, 0x00000005, 0x00000004, 0x6e69616d, + 0x00000000, 0x0000000c, 0x00060010, 0x00000004, + 0x00000011, 0x00000010, 0x00000010, 0x00000001, + 0x00030003, 0x00000002, 0x000001c2, 0x00040005, + 0x00000004, 0x6e69616d, 0x00000000, 0x00030005, + 0x00000009, 0x00006469, 0x00080005, 0x0000000c, + 0x475f6c67, 0x61626f6c, 0x766e496c, 0x7461636f, + 0x496e6f69, 0x00000044, 0x00060005, 0x00000016, + 0x68737550, 0x736e6f43, 0x746e6174, 0x00000073, + 0x00050006, 0x00000016, 0x00000000, 0x74646977, + 0x00000068, 0x00050006, 0x00000016, 0x00000001, + 0x67696568, 0x00007468, 0x00050006, 0x00000016, + 0x00000002, 0x6f6c6f63, 0x00000072, 0x00030005, + 0x00000018, 0x00006370, 0x00040005, 0x0000002d, + 0x65646e69, 0x00000078, 0x00060005, 0x00000037, + 0x7074754f, 0x75427475, 0x72656666, 0x00000000, + 0x00050006, 0x00000037, 0x00000000, 0x65786970, + 0x0000736c, 0x00050005, 0x00000039, 0x4274756f, + 0x65666675, 0x00000072, 0x00040047, 0x0000000c, + 0x0000000b, 0x0000001c, 0x00030047, 0x00000016, + 0x00000002, 0x00050048, 0x00000016, 0x00000000, + 0x00000023, 0x00000000, 0x00050048, 0x00000016, + 0x00000001, 0x00000023, 0x00000004, 0x00050048, + 0x00000016, 0x00000002, 0x00000023, 0x00000010, + 0x00040047, 0x00000036, 0x00000006, 0x00000010, + 0x00030047, 0x00000037, 0x00000003, 0x00050048, + 0x00000037, 0x00000000, 0x00000023, 0x00000000, + 0x00040047, 0x00000039, 0x00000021, 0x00000000, + 0x00040047, 0x00000039, 0x00000022, 0x00000000, + 0x00040047, 0x00000042, 0x0000000b, 0x00000019, + 0x00020013, 0x00000002, 0x00030021, 0x00000003, + 0x00000002, 0x00040015, 0x00000006, 0x00000020, + 0x00000000, 0x00040017, 0x00000007, 0x00000006, + 0x00000002, 0x00040020, 0x00000008, 0x00000007, + 0x00000007, 0x00040017, 0x0000000a, 0x00000006, + 0x00000003, 0x00040020, 0x0000000b, 0x00000001, + 0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c, + 0x00000001, 0x00020014, 0x0000000f, 0x0004002b, + 0x00000006, 0x00000010, 0x00000000, 0x00040020, + 0x00000011, 0x00000007, 0x00000006, 0x00030016, + 0x00000014, 0x00000020, 0x00040017, 0x00000015, + 0x00000014, 0x00000004, 0x0005001e, 0x00000016, + 0x00000006, 0x00000006, 0x00000015, 0x00040020, + 0x00000017, 0x00000009, 0x00000016, 0x0004003b, + 0x00000017, 0x00000018, 0x00000009, 0x00040015, + 0x00000019, 0x00000020, 0x00000001, 0x0004002b, + 0x00000019, 0x0000001a, 0x00000000, 0x00040020, + 0x0000001b, 0x00000009, 0x00000006, 0x0004002b, + 0x00000006, 0x00000022, 0x00000001, 0x0004002b, + 0x00000019, 0x00000025, 0x00000001, 0x0003001d, + 0x00000036, 0x00000015, 0x0003001e, 0x00000037, + 0x00000036, 0x00040020, 0x00000038, 0x00000002, + 0x00000037, 0x0004003b, 0x00000038, 0x00000039, + 0x00000002, 0x0004002b, 0x00000019, 0x0000003b, + 0x00000002, 0x00040020, 0x0000003c, 0x00000009, + 0x00000015, 0x00040020, 0x0000003f, 0x00000002, + 0x00000015, 0x0004002b, 0x00000006, 0x00000041, + 0x00000010, 0x0006002c, 0x0000000a, 0x00000042, + 0x00000041, 0x00000041, 0x00000022, 0x00050036, + 0x00000002, 0x00000004, 0x00000000, 0x00000003, + 0x000200f8, 0x00000005, 0x0004003b, 0x00000008, + 0x00000009, 0x00000007, 0x0004003b, 0x00000011, + 0x0000002d, 0x00000007, 0x0004003d, 0x0000000a, + 0x0000000d, 0x0000000c, 0x0007004f, 0x00000007, + 0x0000000e, 0x0000000d, 0x0000000d, 0x00000000, + 0x00000001, 0x0003003e, 0x00000009, 0x0000000e, + 0x00050041, 0x00000011, 0x00000012, 0x00000009, + 0x00000010, 0x0004003d, 0x00000006, 0x00000013, + 0x00000012, 0x00050041, 0x0000001b, 0x0000001c, + 0x00000018, 0x0000001a, 0x0004003d, 0x00000006, + 0x0000001d, 0x0000001c, 0x000500ae, 0x0000000f, + 0x0000001e, 0x00000013, 0x0000001d, 0x000400a8, + 0x0000000f, 0x0000001f, 0x0000001e, 0x000300f7, + 0x00000021, 0x00000000, 0x000400fa, 0x0000001f, + 0x00000020, 0x00000021, 0x000200f8, 0x00000020, + 0x00050041, 0x00000011, 0x00000023, 0x00000009, + 0x00000022, 0x0004003d, 0x00000006, 0x00000024, + 0x00000023, 0x00050041, 0x0000001b, 0x00000026, + 0x00000018, 0x00000025, 0x0004003d, 0x00000006, + 0x00000027, 0x00000026, 0x000500ae, 0x0000000f, + 0x00000028, 0x00000024, 0x00000027, 0x000200f9, + 0x00000021, 0x000200f8, 0x00000021, 0x000700f5, + 0x0000000f, 0x00000029, 0x0000001e, 0x00000005, + 0x00000028, 0x00000020, 0x000300f7, 0x0000002b, + 0x00000000, 0x000400fa, 0x00000029, 0x0000002a, + 0x0000002b, 0x000200f8, 0x0000002a, 0x000100fd, + 0x000200f8, 0x0000002b, 0x00050041, 0x00000011, + 0x0000002e, 0x00000009, 0x00000022, 0x0004003d, + 0x00000006, 0x0000002f, 0x0000002e, 0x00050041, + 0x0000001b, 0x00000030, 0x00000018, 0x0000001a, + 0x0004003d, 0x00000006, 0x00000031, 0x00000030, + 0x00050084, 0x00000006, 0x00000032, 0x0000002f, + 0x00000031, 0x00050041, 0x00000011, 0x00000033, + 0x00000009, 0x00000010, 0x0004003d, 0x00000006, + 0x00000034, 0x00000033, 0x00050080, 0x00000006, + 0x00000035, 0x00000032, 0x00000034, 0x0003003e, + 0x0000002d, 0x00000035, 0x0004003d, 0x00000006, + 0x0000003a, 0x0000002d, 0x00050041, 0x0000003c, + 0x0000003d, 0x00000018, 0x0000003b, 0x0004003d, + 0x00000015, 0x0000003e, 0x0000003d, 0x00060041, + 0x0000003f, 0x00000040, 0x00000039, 0x0000001a, + 0x0000003a, 0x0003003e, 0x00000040, 0x0000003e, + 0x000100fd, 0x00010038 +}; + +static const Uint8 s_ComputeShaderDxil[] = { + 0x44, 0x58, 0x42, 0x43, 0x3c, 0x03, 0x02, 0xb3, 0x0e, 0x59, 0xfb, 0x9b, + 0xc1, 0xd2, 0x75, 0x12, 0xb3, 0x0d, 0x3c, 0xd0, 0x01, 0x00, 0x00, 0x00, + 0x58, 0x0d, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0xf4, 0x00, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00, 0x4c, 0x07, 0x00, 0x00, + 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x50, 0x53, 0x56, 0x30, 0x80, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0x34, 0x06, 0x00, 0x00, + 0x60, 0x00, 0x05, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, + 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x01, 0xd5, 0x06, 0x62, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x90, 0x00, 0x49, 0x18, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, + 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, + 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x74, 0x23, 0x00, 0x25, 0x00, 0x14, 0xe6, + 0x08, 0xc0, 0xa0, 0x0c, 0x63, 0x0c, 0x22, 0x33, 0x00, 0x47, 0x0d, 0x97, + 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0xdc, 0x46, 0x15, 0x2b, 0x31, 0xf9, 0xc5, + 0x6d, 0x23, 0xc2, 0x18, 0x63, 0xe6, 0x08, 0x10, 0x42, 0xf7, 0x0c, 0x97, + 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, 0x0c, 0x0b, 0x81, 0x82, 0x54, + 0x88, 0x33, 0xd4, 0xa0, 0x75, 0xd4, 0x70, 0xf9, 0x13, 0xf6, 0x10, 0x92, + 0xcf, 0x6d, 0x54, 0xb1, 0x12, 0x93, 0x8f, 0xdc, 0x36, 0x22, 0xc6, 0x18, + 0xa3, 0x10, 0x6d, 0xa8, 0x41, 0x6e, 0x8e, 0x20, 0x28, 0x86, 0x1a, 0x68, + 0x0c, 0x48, 0xb1, 0x28, 0x60, 0xa8, 0x31, 0xc6, 0x18, 0x03, 0xd1, 0x1c, + 0x08, 0x38, 0x4d, 0x9a, 0x22, 0x4a, 0x98, 0xfc, 0x15, 0xde, 0xb0, 0x89, + 0xd0, 0x86, 0x21, 0x22, 0x24, 0x69, 0xa3, 0x8a, 0x82, 0x88, 0x50, 0x30, + 0xc8, 0x0e, 0x23, 0x10, 0xc6, 0x51, 0xd2, 0x14, 0x51, 0xc2, 0xe4, 0xa7, + 0x94, 0x74, 0x70, 0x4e, 0x23, 0x4d, 0x40, 0x33, 0x49, 0x68, 0x18, 0x03, + 0x9f, 0xf0, 0x08, 0x28, 0xc8, 0xa4, 0xe7, 0x08, 0x40, 0x01, 0x00, 0x00, + 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, + 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, + 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, + 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, + 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, + 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, + 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x04, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, + 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, + 0x89, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0xc8, 0x33, 0x01, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x16, 0x08, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, + 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, + 0x25, 0x30, 0x02, 0x50, 0x0c, 0x65, 0x51, 0x40, 0x65, 0x50, 0x0e, 0xa5, + 0x50, 0x08, 0x05, 0x52, 0x12, 0xa5, 0x51, 0x34, 0x45, 0x40, 0x70, 0x04, + 0x80, 0x78, 0x81, 0x50, 0x9e, 0x01, 0x20, 0x3d, 0x03, 0x40, 0x7b, 0x06, + 0x80, 0xee, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, + 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, + 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb1, 0xa9, 0x81, + 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, 0xcb, 0x09, 0x83, 0x49, + 0xd9, 0x10, 0x04, 0x13, 0x84, 0xc1, 0x98, 0x20, 0x0c, 0xc7, 0x06, 0x61, + 0x20, 0x36, 0x08, 0x04, 0x41, 0x61, 0x6c, 0x6e, 0x82, 0x30, 0x20, 0x1b, + 0x86, 0x03, 0x21, 0x26, 0x08, 0x57, 0xc6, 0xe4, 0xad, 0x8e, 0x4e, 0xa8, + 0xce, 0xcc, 0xac, 0x4c, 0x6e, 0x82, 0x30, 0x24, 0x13, 0x04, 0x88, 0xda, + 0xb0, 0x10, 0xca, 0x42, 0x10, 0x03, 0xd3, 0x34, 0x0d, 0xb0, 0x21, 0x70, + 0x26, 0x08, 0x1b, 0x46, 0x01, 0x6e, 0x6c, 0x82, 0x30, 0x28, 0x1b, 0x10, + 0x02, 0x8a, 0x08, 0x62, 0x90, 0x80, 0x0d, 0xc1, 0xb4, 0x81, 0x00, 0x1e, + 0x0a, 0x98, 0x20, 0x64, 0x16, 0x8b, 0xbb, 0x34, 0x32, 0x3a, 0xb4, 0x09, + 0xc2, 0xb0, 0x4c, 0x10, 0x06, 0x66, 0x82, 0x30, 0x34, 0x1b, 0x0c, 0xe4, + 0xc2, 0x88, 0x4c, 0xa3, 0x81, 0x56, 0x96, 0x76, 0x86, 0x46, 0x37, 0x41, + 0x18, 0x9c, 0x0d, 0x06, 0xc2, 0x61, 0x5d, 0xa6, 0xb1, 0x18, 0x7b, 0x63, + 0x7b, 0x93, 0x9b, 0x20, 0x0c, 0xcf, 0x04, 0x61, 0x80, 0x26, 0x08, 0x43, + 0xb4, 0x01, 0x41, 0x3e, 0x0c, 0x0c, 0xb2, 0x30, 0x10, 0x83, 0x6e, 0x03, + 0x21, 0x6d, 0xde, 0x18, 0x4c, 0x10, 0xb4, 0x6b, 0x03, 0x81, 0x44, 0x18, + 0xb1, 0x41, 0x90, 0xcc, 0x60, 0x43, 0x41, 0x58, 0x64, 0x50, 0x06, 0x67, + 0x30, 0x41, 0x10, 0x80, 0x0d, 0xc0, 0x86, 0x81, 0x50, 0x03, 0x35, 0xd8, + 0x10, 0xac, 0xc1, 0x86, 0x61, 0x48, 0x03, 0x36, 0x20, 0xd1, 0x16, 0x96, + 0xe6, 0x36, 0x41, 0xe0, 0xaa, 0x0d, 0x03, 0x18, 0x80, 0xc1, 0xb0, 0x81, + 0x20, 0xde, 0xa0, 0x83, 0x83, 0x0d, 0x45, 0x1a, 0xb8, 0x01, 0x50, 0xc5, + 0x01, 0x11, 0x31, 0xb9, 0x30, 0xb7, 0x31, 0xb4, 0xb2, 0x39, 0x16, 0x69, + 0x6e, 0x73, 0x74, 0x73, 0x13, 0x84, 0x41, 0x22, 0x91, 0xe6, 0x46, 0x37, + 0xc7, 0x84, 0xae, 0x0c, 0xef, 0x6b, 0x8e, 0xee, 0x4d, 0xae, 0x8c, 0x45, + 0x5d, 0x9a, 0x1b, 0xdd, 0xdc, 0x04, 0x61, 0x98, 0x36, 0x28, 0x73, 0x30, + 0xd0, 0x41, 0x1d, 0xd8, 0x41, 0x77, 0x07, 0x03, 0x1e, 0xe4, 0x41, 0x15, + 0x36, 0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37, 0xba, 0x29, 0x41, + 0x50, 0x85, 0x0c, 0xcf, 0xc5, 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, 0x6d, + 0x4a, 0x40, 0x34, 0x21, 0xc3, 0x73, 0xb1, 0x0b, 0x63, 0xb3, 0x2b, 0x93, + 0x9b, 0x12, 0x14, 0x75, 0xc8, 0xf0, 0x5c, 0xe6, 0xd0, 0xc2, 0xc8, 0xca, + 0xe4, 0x9a, 0xde, 0xc8, 0xca, 0xd8, 0xa6, 0x04, 0x48, 0x19, 0x32, 0x3c, + 0x17, 0xb9, 0xb2, 0xb9, 0xb7, 0x3a, 0xb9, 0xb1, 0xb2, 0xb9, 0x29, 0x01, + 0x55, 0x89, 0x0c, 0xcf, 0x85, 0x2e, 0x0f, 0xae, 0x2c, 0xc8, 0xcd, 0xed, + 0x8d, 0x2e, 0x8c, 0x2e, 0xed, 0xcd, 0x6d, 0x6e, 0x8a, 0x70, 0x06, 0x6c, + 0x50, 0x87, 0x0c, 0xcf, 0xa5, 0xcc, 0x8d, 0x4e, 0x2e, 0x0f, 0xea, 0x2d, + 0xcd, 0x8d, 0x6e, 0x6e, 0x4a, 0x10, 0x07, 0x5d, 0xc8, 0xf0, 0x5c, 0xc6, + 0xde, 0xea, 0xdc, 0xe8, 0xca, 0xe4, 0xe6, 0xa6, 0x04, 0x79, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, + 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, + 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, + 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, + 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, + 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, + 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, + 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, + 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, + 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, + 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, + 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, + 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, + 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, + 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, + 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, + 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, + 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, + 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, + 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, + 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, + 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, + 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, + 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, + 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, + 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x30, 0x83, 0x81, + 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, 0x1c, 0xc2, 0x61, 0x1d, + 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x56, 0x50, 0x0d, 0x97, 0xef, 0x3c, 0x7e, 0x40, + 0x15, 0x05, 0x11, 0xb1, 0x93, 0x13, 0x11, 0x3e, 0x72, 0xdb, 0x26, 0xb0, + 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, + 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x03, 0xdb, 0x70, + 0xf9, 0xce, 0xe3, 0x0b, 0x01, 0x55, 0x14, 0x44, 0x54, 0x3a, 0xc0, 0x50, + 0x12, 0x06, 0x20, 0x60, 0x3e, 0x72, 0xdb, 0x46, 0x20, 0x0d, 0x97, 0xef, + 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, 0x33, 0x2c, 0x84, 0x05, + 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x1d, 0x11, 0x01, 0x0c, 0xe2, 0xe0, + 0x23, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6f, 0xb0, 0x69, 0x56, 0x40, 0x84, 0x26, 0xed, + 0x85, 0x8e, 0xc5, 0x2c, 0x46, 0xd0, 0xbf, 0x12, 0x44, 0x58, 0x49, 0x4c, + 0x04, 0x06, 0x00, 0x00, 0x60, 0x00, 0x05, 0x00, 0x81, 0x01, 0x00, 0x00, + 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xec, 0x05, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, + 0x78, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, + 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, + 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, + 0xa4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, + 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, + 0xe4, 0x48, 0x0e, 0x90, 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, + 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, + 0x40, 0x02, 0xa8, 0x0d, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, + 0x01, 0xd5, 0x06, 0x62, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x90, 0x00, + 0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, + 0x20, 0x4c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, + 0x31, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, + 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, + 0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x78, 0x23, 0x00, + 0x25, 0x00, 0x14, 0xe6, 0x08, 0xc0, 0xa0, 0x0c, 0x63, 0x0c, 0x22, 0x33, + 0x00, 0x47, 0x0d, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0xdc, 0x46, 0x15, + 0x2b, 0x31, 0xf9, 0xc5, 0x6d, 0x23, 0xc2, 0x18, 0x63, 0xe6, 0x08, 0x10, + 0x42, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, 0x0c, + 0x0b, 0x81, 0x82, 0x54, 0x88, 0x33, 0xd4, 0xa0, 0x75, 0xd4, 0x70, 0xf9, + 0x13, 0xf6, 0x10, 0x92, 0xcf, 0x6d, 0x54, 0xb1, 0x12, 0x93, 0x8f, 0xdc, + 0x36, 0x22, 0xc6, 0x18, 0xa3, 0x10, 0x6d, 0xa8, 0x41, 0x6e, 0x8e, 0x20, + 0x28, 0x86, 0x1a, 0x68, 0x0c, 0x48, 0xb1, 0x28, 0x60, 0xa8, 0x31, 0xc6, + 0x18, 0x03, 0xd1, 0x1c, 0x08, 0x38, 0x4d, 0x9a, 0x22, 0x4a, 0x98, 0xfc, + 0x15, 0xde, 0xb0, 0x89, 0xd0, 0x86, 0x21, 0x22, 0x24, 0x69, 0xa3, 0x8a, + 0x82, 0x88, 0x50, 0x30, 0xc8, 0x0e, 0x23, 0x10, 0xc6, 0x51, 0xd2, 0x14, + 0x51, 0xc2, 0xe4, 0xa7, 0x94, 0x74, 0x70, 0x4e, 0x23, 0x4d, 0x40, 0x33, + 0x49, 0x68, 0x18, 0x03, 0x9f, 0xf0, 0x08, 0x28, 0xc8, 0xa4, 0xe7, 0x08, + 0x40, 0x61, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, + 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, + 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, + 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, + 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, + 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, + 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, + 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, + 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, + 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, + 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x86, 0x3c, 0x04, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x89, 0x80, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc8, 0x33, 0x01, 0x01, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x16, 0x08, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, + 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, 0x25, 0x30, 0x02, 0x50, + 0x12, 0xc5, 0x50, 0x16, 0x05, 0x54, 0x08, 0x05, 0x42, 0x70, 0x04, 0x80, + 0x78, 0x81, 0xd0, 0x9e, 0x01, 0xa0, 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, + 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, + 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, + 0xa1, 0xb1, 0xa9, 0x81, 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, + 0xcb, 0x09, 0x83, 0x49, 0xd9, 0x10, 0x04, 0x13, 0x84, 0xc1, 0x98, 0x20, + 0x0c, 0xc7, 0x06, 0x61, 0x20, 0x26, 0x08, 0x03, 0xb2, 0x41, 0x18, 0x0c, + 0x0a, 0x63, 0x73, 0x13, 0x84, 0x21, 0xd9, 0x30, 0x20, 0x09, 0x31, 0x41, + 0xb8, 0x22, 0x02, 0x13, 0x84, 0x41, 0x99, 0x20, 0x40, 0xce, 0x86, 0x85, + 0x58, 0x18, 0x82, 0x18, 0x1a, 0xc7, 0x71, 0x80, 0x0d, 0xc1, 0x33, 0x41, + 0xd8, 0xa0, 0x09, 0xc2, 0xb0, 0x6c, 0x40, 0x88, 0x88, 0x21, 0x88, 0x41, + 0x02, 0x36, 0x04, 0xd3, 0x06, 0x02, 0x80, 0x28, 0x60, 0x82, 0x20, 0x00, + 0x24, 0xda, 0xc2, 0xd2, 0xdc, 0x26, 0x08, 0xdc, 0x33, 0x41, 0x18, 0x98, + 0x09, 0xc2, 0xd0, 0x6c, 0x18, 0x34, 0x6d, 0xd8, 0x40, 0x10, 0x58, 0xb6, + 0x6d, 0x28, 0xac, 0x0b, 0xa8, 0xb8, 0x2a, 0x6c, 0x6c, 0x76, 0x6d, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, 0x9e, 0x8b, + 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, 0x42, 0x86, + 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26, 0x37, 0x25, 0x30, 0xea, 0x90, + 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, 0x91, 0x95, + 0xb1, 0x4d, 0x09, 0x92, 0x32, 0x64, 0x78, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x53, 0x02, 0xaa, 0x0e, 0x19, 0x9e, 0x4b, + 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, + 0x80, 0x03, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, + 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, + 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, + 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, + 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, + 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, + 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, + 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, + 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, + 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, + 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, + 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, + 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, + 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, + 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, + 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, + 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, + 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, + 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, + 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, + 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, + 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, + 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, + 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, + 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, + 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, + 0xf4, 0x30, 0x83, 0x81, 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, + 0x1c, 0xc2, 0x61, 0x1d, 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, + 0x71, 0x20, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x56, 0x50, 0x0d, 0x97, + 0xef, 0x3c, 0x7e, 0x40, 0x15, 0x05, 0x11, 0xb1, 0x93, 0x13, 0x11, 0x3e, + 0x72, 0xdb, 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, + 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, + 0x6d, 0x03, 0xdb, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x01, 0x55, 0x14, 0x44, + 0x54, 0x3a, 0xc0, 0x50, 0x12, 0x06, 0x20, 0x60, 0x3e, 0x72, 0xdb, 0x46, + 0x20, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, + 0x33, 0x2c, 0x84, 0x05, 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x1d, 0x11, + 0x01, 0x0c, 0xe2, 0xe0, 0x23, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, + 0x13, 0x04, 0x43, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x34, 0x4a, 0xae, 0x74, 0x03, 0xca, 0xae, 0x14, 0x03, 0x66, 0x00, 0x08, + 0x95, 0x40, 0x11, 0x94, 0x07, 0x00, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, + 0x82, 0x60, 0x10, 0x59, 0xc8, 0x30, 0x4d, 0xcc, 0x88, 0x41, 0x02, 0x80, + 0x20, 0x18, 0x44, 0x57, 0x32, 0x50, 0x54, 0x33, 0x62, 0x60, 0x00, 0x20, + 0x08, 0x06, 0xc4, 0x96, 0x54, 0x23, 0x06, 0x06, 0x00, 0x82, 0x60, 0x40, + 0x70, 0xca, 0x35, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0xa6, 0x0c, + 0xd7, 0x68, 0x42, 0x00, 0x0c, 0x37, 0x10, 0x01, 0x19, 0x8c, 0x26, 0x0c, + 0xc1, 0x70, 0x43, 0x11, 0x90, 0x41, 0x0d, 0x81, 0xce, 0x32, 0x04, 0x42, + 0x50, 0xc5, 0x21, 0x15, 0x24, 0x50, 0x81, 0x76, 0x23, 0x06, 0x07, 0x00, + 0x82, 0x60, 0xb0, 0x94, 0xc1, 0xc4, 0x84, 0xc1, 0x68, 0x42, 0x00, 0x8c, + 0x26, 0x08, 0xc1, 0x68, 0xc2, 0x20, 0x8c, 0x26, 0x10, 0xc3, 0x11, 0x63, + 0x8f, 0x18, 0x7b, 0xc4, 0xd8, 0x23, 0xc6, 0x8e, 0x18, 0x34, 0x00, 0x08, + 0x82, 0xc1, 0xb4, 0x06, 0x9b, 0xa5, 0x68, 0xc4, 0x20, 0x04, 0xd7, 0x2c, + 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// clang-format on + // layout must match shader typedef struct { Uint32 width; @@ -189,26 +645,15 @@ bool computeTest() Uint64 bytecodeSize = 0; void* bytecode = nullptr; PalShaderCreateInfo shaderCreateInfo = {0}; - const char* shaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - shaderPath = "graphics/shaders/compute_shader.spv"; + bytecode = (void*)s_ComputeShaderSpv; + bytecodeSize = sizeof(s_ComputeShaderSpv); } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - shaderPath = "graphics/shaders/compute_shader.dxil"; + bytecode = (void*)s_ComputeShaderDxil; + bytecodeSize = sizeof(s_ComputeShaderDxil); } - if (!readFile(shaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader file"); - return false; - } - - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - readFile(shaderPath, bytecode, &bytecodeSize); shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; shaderCreateInfo.stage = PAL_SHADER_STAGE_COMPUTE; @@ -220,8 +665,6 @@ bool computeTest() return false; } - palFree(nullptr, bytecode); - // create a storage buffer Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader PalBufferCreateInfo bufferCreateInfo = {0}; diff --git a/tests/graphics/shaders/compute_shader.dxil b/tests/graphics/shaders/compute_shader.dxil deleted file mode 100644 index 44f34dff066ebbb468a778ed97e34c7295aff6cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3416 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 UJVWT2-ik2>`6R_^0m%URC&A1;5C8xG diff --git a/tests/graphics/shaders/compute_shader.glsl b/tests/graphics/shaders/compute_shader.glsl deleted file mode 100644 index 2b633bcb..00000000 --- a/tests/graphics/shaders/compute_shader.glsl +++ /dev/null @@ -1,27 +0,0 @@ - -#version 450 - -layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout(set = 0, binding = 0) buffer OutputBuffer -{ - vec4 pixels[]; -} outBuffer; - -layout(push_constant) uniform PushConstants -{ - uint width; - uint height; - vec4 color; -} pc; - -void main() -{ - uvec2 id = gl_GlobalInvocationID.xy; - if (id.x >= pc.width || id.y >= pc.height) { - return; - } - - uint index = id.y * pc.width + id.x; - outBuffer.pixels[index] = pc.color; -} \ No newline at end of file diff --git a/tests/graphics/shaders/compute_shader.hlsl b/tests/graphics/shaders/compute_shader.hlsl deleted file mode 100644 index f02e313b..00000000 --- a/tests/graphics/shaders/compute_shader.hlsl +++ /dev/null @@ -1,22 +0,0 @@ - -struct PushConstants -{ - uint width; - uint height; - float4 color; -}; - -RWByteAddressBuffer outBuffer : register(u0); -ConstantBuffer pc : register(b0); - -[numThreads(16, 16, 1)] -void main(uint3 id : SV_DispatchThreadID) -{ - if (id.x >= pc.width || id.y >= pc.height) { - return; - } - - uint index = id.y * pc.width + id.x; - uint offset = index * 16; // sizeof(float4) - outBuffer.Store4(offset, asuint(pc.color)); -} \ No newline at end of file diff --git a/tests/graphics/shaders/compute_shader.spv b/tests/graphics/shaders/compute_shader.spv deleted file mode 100644 index 6b369782f113f376998164b299dda8f88aaa839a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1704 zcmZ9L+fGwa5QaC@Rul!1lP9o%XB1HZQ3N@dR1y+Qd;n8vp*yK9vAfEp7e0(vK7{XN zJR~N5-|k-8u$sxt{B!#Etkqoa%*iO~iTb0yXe;WRp{N%m0xP7twDWpru9Z~g78d8t z7>IIdqB(=)z?nWK9YeZ$F<(Os7(c8XYBG1iy%IjFxW z)thh2_3g%o=3Y68n~m)k#J8o2}M`^4OJx1@glf!nh+1}r;T9Wn__Z-GY)jA~d{GQ-9 zyAn%$se9>1t{^35$wHgP))?JJQoJ)`6kFe2O=df_UNPp}akOvD-8)y`I~Vi2{N^Ge z59jM&LOj-AMw@HTz;7D6JO6s-Pr%Q+arPv(ccE{eWwg5zlZU?dA{OSZWWM>&usa+( z_0O}Iy#tR8Y~RFP*tyqDL`;$65<9WK`|)@eKSBKe%E3ExhWpib*Zv3eSMlw67V(~T zLB$6$Ox)9htkKy%#y03~pYw>A{Oslah7oad+^hc!@4|hDoQVwoN{(-060uJF3w^|{ zBH}-oJB9ZACMI4)#QaX}z{mfCeB4Wzbq!lQ@VS94AMZ2d+{6|Sd~RV|C;p2WVV3$k z8gA-BW!zj-_ZiT_@}IH5!+gE@7ebu7WVTLTg;xm*;Pa?zGZWKuWPAoP9gFguOq&F Q@7;R)uBW=QgJt&c7bi+&tpET3 diff --git a/tests/tests_main.c b/tests/tests_main.c index 1c5706ee..8d4bafd8 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,7 +58,7 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - // registerTest(computeTest, "Compute Test"); + registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders #endif // PAL_HAS_GRAPHICS @@ -66,7 +66,7 @@ int main(int argc, char** argv) // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); // TODO: add dxil shaders - registerTest(textureTest, "Texture Test"); + // registerTest(textureTest, "Texture Test"); #endif // runTests(); From 1e5e849653b0b6d12ac14768745dee3f1962de08 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 29 Apr 2026 13:44:11 +0000 Subject: [PATCH 187/372] ray tracing test: remove shader files dependency and embed shader sources and bytecode into source file --- tests/graphics/ray_tracing_test.c | 410 ++++++++++++++---- .../graphics/shaders/closest_hit_shader.glsl | 10 - tests/graphics/shaders/closest_hit_shader.spv | Bin 372 -> 0 bytes tests/graphics/shaders/miss_shader.glsl | 10 - tests/graphics/shaders/miss_shader.spv | Bin 356 -> 0 bytes tests/graphics/shaders/raygen_shader.glsl | 44 -- tests/graphics/shaders/raygen_shader.spv | Bin 2620 -> 0 bytes tests/tests_main.c | 4 +- 8 files changed, 332 insertions(+), 146 deletions(-) delete mode 100644 tests/graphics/shaders/closest_hit_shader.glsl delete mode 100644 tests/graphics/shaders/closest_hit_shader.spv delete mode 100644 tests/graphics/shaders/miss_shader.glsl delete mode 100644 tests/graphics/shaders/miss_shader.spv delete mode 100644 tests/graphics/shaders/raygen_shader.glsl delete mode 100644 tests/graphics/shaders/raygen_shader.spv diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 4a84227e..66d91cc5 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -4,6 +4,301 @@ #define BUFFER_SIZE 400 +// clang-format off + +// Ray Tracing Shaders Source Code GLSL + +// Raygen +// #version 460 +// #extension GL_EXT_ray_tracing : require + +// layout(set = 0, binding = 0) buffer OutputBuffer +// { +// vec4 pixels[]; +// } outBuffer; + +// layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; +// layout(location = 0) rayPayloadEXT vec3 payloadColor; + +// void main() +// { +// uvec2 pixel = gl_LaunchIDEXT.xy; +// uvec2 size = gl_LaunchSizeEXT.xy; +// payloadColor = vec3(0.0); + +// vec2 uv = (vec2(pixel) + 0.5) / vec2(size); +// vec2 ndcUv = uv * 2.0 - 1.0; +// vec3 origin = vec3(0.0, 0.0, -3.0); +// vec3 direction = normalize(vec3(ndcUv.x, ndcUv.y, 1.0)); + +// traceRayEXT( +// tlas, +// gl_RayFlagsOpaqueEXT, +// 0xFF, +// 0, +// 0, +// 0, +// origin, +// 0.001, +// direction, +// 1000.0, +// 0 +// ); + +// if (pixel.x >= size.x || pixel.y >= size.y) { +// return; +// } + +// uint index = pixel.y * size.x + pixel.x; +// outBuffer.pixels[index] = vec4(payloadColor, 1.0); +// } + +// Closest Hit +// #version 460 +// #extension GL_EXT_ray_tracing : require + +// layout(location = 0) rayPayloadInEXT vec3 payloadColor; + +// void main() +// { +// payloadColor = vec3(0.0, 1.0, 0.0); +// } + +// Miss +// #version 460 +// #extension GL_EXT_ray_tracing : require + +// layout(location = 0) rayPayloadInEXT vec3 payloadColor; + +// void main() +// { +// payloadColor = vec3(0.0); +// } + +// Ray Tracing Shaders Source Code HLSL + +static const Uint32 s_RaygenShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x0000006d, + 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, + 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, + 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, + 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, + 0x00000000, 0x00000001, 0x000a000f, 0x000014c1, + 0x00000004, 0x6e69616d, 0x00000000, 0x0000000c, + 0x00000010, 0x00000016, 0x0000003b, 0x00000064, + 0x00030003, 0x00000002, 0x000001cc, 0x00060004, + 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, + 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, + 0x00000000, 0x00040005, 0x00000009, 0x65786970, + 0x0000006c, 0x00060005, 0x0000000c, 0x4c5f6c67, + 0x636e7561, 0x45444968, 0x00005458, 0x00040005, + 0x0000000f, 0x657a6973, 0x00000000, 0x00070005, + 0x00000010, 0x4c5f6c67, 0x636e7561, 0x7a695368, + 0x54584565, 0x00000000, 0x00060005, 0x00000016, + 0x6c796170, 0x4364616f, 0x726f6c6f, 0x00000000, + 0x00030005, 0x0000001b, 0x00007675, 0x00040005, + 0x00000024, 0x5563646e, 0x00000076, 0x00040005, + 0x0000002c, 0x6769726f, 0x00006e69, 0x00050005, + 0x0000002f, 0x65726964, 0x6f697463, 0x0000006e, + 0x00040005, 0x0000003b, 0x73616c74, 0x00000000, + 0x00040005, 0x00000057, 0x65646e69, 0x00000078, + 0x00060005, 0x00000062, 0x7074754f, 0x75427475, + 0x72656666, 0x00000000, 0x00050006, 0x00000062, + 0x00000000, 0x65786970, 0x0000736c, 0x00050005, + 0x00000064, 0x4274756f, 0x65666675, 0x00000072, + 0x00040047, 0x0000000c, 0x0000000b, 0x000014c7, + 0x00040047, 0x00000010, 0x0000000b, 0x000014c8, + 0x00040047, 0x0000003b, 0x00000021, 0x00000001, + 0x00040047, 0x0000003b, 0x00000022, 0x00000000, + 0x00040047, 0x00000061, 0x00000006, 0x00000010, + 0x00030047, 0x00000062, 0x00000002, 0x00050048, + 0x00000062, 0x00000000, 0x00000023, 0x00000000, + 0x00040047, 0x00000064, 0x00000021, 0x00000000, + 0x00040047, 0x00000064, 0x00000022, 0x00000000, + 0x00020013, 0x00000002, 0x00030021, 0x00000003, + 0x00000002, 0x00040015, 0x00000006, 0x00000020, + 0x00000000, 0x00040017, 0x00000007, 0x00000006, + 0x00000002, 0x00040020, 0x00000008, 0x00000007, + 0x00000007, 0x00040017, 0x0000000a, 0x00000006, + 0x00000003, 0x00040020, 0x0000000b, 0x00000001, + 0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c, + 0x00000001, 0x0004003b, 0x0000000b, 0x00000010, + 0x00000001, 0x00030016, 0x00000013, 0x00000020, + 0x00040017, 0x00000014, 0x00000013, 0x00000003, + 0x00040020, 0x00000015, 0x000014da, 0x00000014, + 0x0004003b, 0x00000015, 0x00000016, 0x000014da, + 0x0004002b, 0x00000013, 0x00000017, 0x00000000, + 0x0006002c, 0x00000014, 0x00000018, 0x00000017, + 0x00000017, 0x00000017, 0x00040017, 0x00000019, + 0x00000013, 0x00000002, 0x00040020, 0x0000001a, + 0x00000007, 0x00000019, 0x0004002b, 0x00000013, + 0x0000001e, 0x3f000000, 0x0004002b, 0x00000013, + 0x00000026, 0x40000000, 0x0004002b, 0x00000013, + 0x00000028, 0x3f800000, 0x00040020, 0x0000002b, + 0x00000007, 0x00000014, 0x0004002b, 0x00000013, + 0x0000002d, 0xc0400000, 0x0006002c, 0x00000014, + 0x0000002e, 0x00000017, 0x00000017, 0x0000002d, + 0x0004002b, 0x00000006, 0x00000030, 0x00000000, + 0x00040020, 0x00000031, 0x00000007, 0x00000013, + 0x0004002b, 0x00000006, 0x00000034, 0x00000001, + 0x000214dd, 0x00000039, 0x00040020, 0x0000003a, + 0x00000000, 0x00000039, 0x0004003b, 0x0000003a, + 0x0000003b, 0x00000000, 0x0004002b, 0x00000006, + 0x0000003d, 0x000000ff, 0x0004002b, 0x00000013, + 0x0000003f, 0x3a83126f, 0x0004002b, 0x00000013, + 0x00000041, 0x447a0000, 0x00040015, 0x00000042, + 0x00000020, 0x00000001, 0x0004002b, 0x00000042, + 0x00000043, 0x00000000, 0x00020014, 0x00000044, + 0x00040020, 0x00000045, 0x00000007, 0x00000006, + 0x00040017, 0x00000060, 0x00000013, 0x00000004, + 0x0003001d, 0x00000061, 0x00000060, 0x0003001e, + 0x00000062, 0x00000061, 0x00040020, 0x00000063, + 0x0000000c, 0x00000062, 0x0004003b, 0x00000063, + 0x00000064, 0x0000000c, 0x00040020, 0x0000006b, + 0x0000000c, 0x00000060, 0x00050036, 0x00000002, + 0x00000004, 0x00000000, 0x00000003, 0x000200f8, + 0x00000005, 0x0004003b, 0x00000008, 0x00000009, + 0x00000007, 0x0004003b, 0x00000008, 0x0000000f, + 0x00000007, 0x0004003b, 0x0000001a, 0x0000001b, + 0x00000007, 0x0004003b, 0x0000001a, 0x00000024, + 0x00000007, 0x0004003b, 0x0000002b, 0x0000002c, + 0x00000007, 0x0004003b, 0x0000002b, 0x0000002f, + 0x00000007, 0x0004003b, 0x00000045, 0x00000057, + 0x00000007, 0x0004003d, 0x0000000a, 0x0000000d, + 0x0000000c, 0x0007004f, 0x00000007, 0x0000000e, + 0x0000000d, 0x0000000d, 0x00000000, 0x00000001, + 0x0003003e, 0x00000009, 0x0000000e, 0x0004003d, + 0x0000000a, 0x00000011, 0x00000010, 0x0007004f, + 0x00000007, 0x00000012, 0x00000011, 0x00000011, + 0x00000000, 0x00000001, 0x0003003e, 0x0000000f, + 0x00000012, 0x0003003e, 0x00000016, 0x00000018, + 0x0004003d, 0x00000007, 0x0000001c, 0x00000009, + 0x00040070, 0x00000019, 0x0000001d, 0x0000001c, + 0x00050050, 0x00000019, 0x0000001f, 0x0000001e, + 0x0000001e, 0x00050081, 0x00000019, 0x00000020, + 0x0000001d, 0x0000001f, 0x0004003d, 0x00000007, + 0x00000021, 0x0000000f, 0x00040070, 0x00000019, + 0x00000022, 0x00000021, 0x00050088, 0x00000019, + 0x00000023, 0x00000020, 0x00000022, 0x0003003e, + 0x0000001b, 0x00000023, 0x0004003d, 0x00000019, + 0x00000025, 0x0000001b, 0x0005008e, 0x00000019, + 0x00000027, 0x00000025, 0x00000026, 0x00050050, + 0x00000019, 0x00000029, 0x00000028, 0x00000028, + 0x00050083, 0x00000019, 0x0000002a, 0x00000027, + 0x00000029, 0x0003003e, 0x00000024, 0x0000002a, + 0x0003003e, 0x0000002c, 0x0000002e, 0x00050041, + 0x00000031, 0x00000032, 0x00000024, 0x00000030, + 0x0004003d, 0x00000013, 0x00000033, 0x00000032, + 0x00050041, 0x00000031, 0x00000035, 0x00000024, + 0x00000034, 0x0004003d, 0x00000013, 0x00000036, + 0x00000035, 0x00060050, 0x00000014, 0x00000037, + 0x00000033, 0x00000036, 0x00000028, 0x0006000c, + 0x00000014, 0x00000038, 0x00000001, 0x00000045, + 0x00000037, 0x0003003e, 0x0000002f, 0x00000038, + 0x0004003d, 0x00000039, 0x0000003c, 0x0000003b, + 0x0004003d, 0x00000014, 0x0000003e, 0x0000002c, + 0x0004003d, 0x00000014, 0x00000040, 0x0000002f, + 0x000c115d, 0x0000003c, 0x00000034, 0x0000003d, + 0x00000030, 0x00000030, 0x00000030, 0x0000003e, + 0x0000003f, 0x00000040, 0x00000041, 0x00000016, + 0x00050041, 0x00000045, 0x00000046, 0x00000009, + 0x00000030, 0x0004003d, 0x00000006, 0x00000047, + 0x00000046, 0x00050041, 0x00000045, 0x00000048, + 0x0000000f, 0x00000030, 0x0004003d, 0x00000006, + 0x00000049, 0x00000048, 0x000500ae, 0x00000044, + 0x0000004a, 0x00000047, 0x00000049, 0x000400a8, + 0x00000044, 0x0000004b, 0x0000004a, 0x000300f7, + 0x0000004d, 0x00000000, 0x000400fa, 0x0000004b, + 0x0000004c, 0x0000004d, 0x000200f8, 0x0000004c, + 0x00050041, 0x00000045, 0x0000004e, 0x00000009, + 0x00000034, 0x0004003d, 0x00000006, 0x0000004f, + 0x0000004e, 0x00050041, 0x00000045, 0x00000050, + 0x0000000f, 0x00000034, 0x0004003d, 0x00000006, + 0x00000051, 0x00000050, 0x000500ae, 0x00000044, + 0x00000052, 0x0000004f, 0x00000051, 0x000200f9, + 0x0000004d, 0x000200f8, 0x0000004d, 0x000700f5, + 0x00000044, 0x00000053, 0x0000004a, 0x00000005, + 0x00000052, 0x0000004c, 0x000300f7, 0x00000055, + 0x00000000, 0x000400fa, 0x00000053, 0x00000054, + 0x00000055, 0x000200f8, 0x00000054, 0x000100fd, + 0x000200f8, 0x00000055, 0x00050041, 0x00000045, + 0x00000058, 0x00000009, 0x00000034, 0x0004003d, + 0x00000006, 0x00000059, 0x00000058, 0x00050041, + 0x00000045, 0x0000005a, 0x0000000f, 0x00000030, + 0x0004003d, 0x00000006, 0x0000005b, 0x0000005a, + 0x00050084, 0x00000006, 0x0000005c, 0x00000059, + 0x0000005b, 0x00050041, 0x00000045, 0x0000005d, + 0x00000009, 0x00000030, 0x0004003d, 0x00000006, + 0x0000005e, 0x0000005d, 0x00050080, 0x00000006, + 0x0000005f, 0x0000005c, 0x0000005e, 0x0003003e, + 0x00000057, 0x0000005f, 0x0004003d, 0x00000006, + 0x00000065, 0x00000057, 0x0004003d, 0x00000014, + 0x00000066, 0x00000016, 0x00050051, 0x00000013, + 0x00000067, 0x00000066, 0x00000000, 0x00050051, + 0x00000013, 0x00000068, 0x00000066, 0x00000001, + 0x00050051, 0x00000013, 0x00000069, 0x00000066, + 0x00000002, 0x00070050, 0x00000060, 0x0000006a, + 0x00000067, 0x00000068, 0x00000069, 0x00000028, + 0x00060041, 0x0000006b, 0x0000006c, 0x00000064, + 0x00000043, 0x00000065, 0x0003003e, 0x0000006c, + 0x0000006a, 0x000100fd, 0x00010038 +}; + +static const uint32_t s_ClosestHitShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x0000000d, + 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, + 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, + 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, + 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, + 0x00000000, 0x00000001, 0x0006000f, 0x000014c4, + 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, + 0x00030003, 0x00000002, 0x000001cc, 0x00060004, + 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, + 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, + 0x00000000, 0x00060005, 0x00000009, 0x6c796170, + 0x4364616f, 0x726f6c6f, 0x00000000, 0x00020013, + 0x00000002, 0x00030021, 0x00000003, 0x00000002, + 0x00030016, 0x00000006, 0x00000020, 0x00040017, + 0x00000007, 0x00000006, 0x00000003, 0x00040020, + 0x00000008, 0x000014de, 0x00000007, 0x0004003b, + 0x00000008, 0x00000009, 0x000014de, 0x0004002b, + 0x00000006, 0x0000000a, 0x00000000, 0x0004002b, + 0x00000006, 0x0000000b, 0x3f800000, 0x0006002c, + 0x00000007, 0x0000000c, 0x0000000a, 0x0000000b, + 0x0000000a, 0x00050036, 0x00000002, 0x00000004, + 0x00000000, 0x00000003, 0x000200f8, 0x00000005, + 0x0003003e, 0x00000009, 0x0000000c, 0x000100fd, + 0x00010038 +}; + +static const uint32_t s_MissShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x0000000c, + 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, + 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, + 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, + 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, + 0x00000000, 0x00000001, 0x0006000f, 0x000014c5, + 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, + 0x00030003, 0x00000002, 0x000001cc, 0x00060004, + 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, + 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, + 0x00000000, 0x00060005, 0x00000009, 0x6c796170, + 0x4364616f, 0x726f6c6f, 0x00000000, 0x00020013, + 0x00000002, 0x00030021, 0x00000003, 0x00000002, + 0x00030016, 0x00000006, 0x00000020, 0x00040017, + 0x00000007, 0x00000006, 0x00000003, 0x00040020, + 0x00000008, 0x000014de, 0x00000007, 0x0004003b, + 0x00000008, 0x00000009, 0x000014de, 0x0004002b, + 0x00000006, 0x0000000a, 0x00000000, 0x0006002c, + 0x00000007, 0x0000000b, 0x0000000a, 0x0000000a, + 0x0000000a, 0x00050036, 0x00000002, 0x00000004, + 0x00000000, 0x00000003, 0x000200f8, 0x00000005, + 0x0003003e, 0x00000009, 0x0000000b, 0x000100fd, + 0x00010038 +}; + +// clang-format on + static void PAL_CALL onGraphicsDebug( void* userData, PalDebugMessageSeverity severity, @@ -197,109 +492,64 @@ bool rayTracingTest() return false; } - // create a raygen shader - Uint64 bytecodeSize = 0; - void* bytecode = nullptr; - PalShaderCreateInfo shaderCreateInfo = {0}; - const char* shaderPath = nullptr; + // create ray tracing shaders + Uint64 raygenBytecodeSize = 0; + Uint64 closestHitBytecodeSize = 0; + Uint64 missBytecodeSize = 0; + void* raygenBytecode = 0; + void* closestHitBytecode = 0; + void* missBytecode = 0; + + PalShaderCreateInfo raygenShaderCreateInfo = {0}; + PalShaderCreateInfo closestHitShaderCreateInfo = {0}; + PalShaderCreateInfo missShaderCreateInfo = {0}; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - shaderPath = "graphics/shaders/raygen_shader.spv"; + raygenBytecodeSize = sizeof(s_RaygenShaderSpv); + closestHitBytecodeSize = sizeof(s_ClosestHitShaderSpv); + missBytecodeSize = sizeof(s_MissShaderSpv); - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - shaderPath = "graphics/shaders/raygen_shader.dxil"; - } + raygenBytecode = (void*)s_RaygenShaderSpv; + closestHitBytecode = (void*)s_ClosestHitShaderSpv; + missBytecode = (void*)s_MissShaderSpv; - if (!readFile(shaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader file"); + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + palLog(nullptr, "Dxil not tested yet"); return false; } - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } + raygenShaderCreateInfo.bytecode = raygenBytecode; + raygenShaderCreateInfo.bytecodeSize = raygenBytecodeSize; + raygenShaderCreateInfo.stage = PAL_SHADER_STAGE_RAYGEN; + + closestHitShaderCreateInfo.bytecode = closestHitBytecode; + closestHitShaderCreateInfo.bytecodeSize = closestHitBytecodeSize; + closestHitShaderCreateInfo.stage = PAL_SHADER_STAGE_CLOSEST_HIT; - readFile(shaderPath, bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_RAYGEN; + missShaderCreateInfo.bytecode = missBytecode; + missShaderCreateInfo.bytecodeSize = missBytecodeSize; + missShaderCreateInfo.stage = PAL_SHADER_STAGE_MISS; - result = palCreateShader(device, &shaderCreateInfo, &raygenShader); + result = palCreateShader(device, &raygenShaderCreateInfo, &raygenShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create raygen shader: %s", error); return false; } - palFree(nullptr, bytecode); - // create a miss shader - bytecodeSize = 0; - bytecode = nullptr; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - shaderPath = "graphics/shaders/miss_shader.spv"; - - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - shaderPath = "graphics/shaders/miss_shader.dxil"; - } - - if (!readFile(shaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader file"); - return false; - } - - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - readFile(shaderPath, bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_MISS; - - result = palCreateShader(device, &shaderCreateInfo, &missShader); + result = palCreateShader(device, &closestHitShaderCreateInfo, &closestHitShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create miss shader: %s", error); - return false; - } - palFree(nullptr, bytecode); - - // create a closest hit shader - bytecodeSize = 0; - bytecode = nullptr; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - shaderPath = "graphics/shaders/closest_hit_shader.spv"; - - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - shaderPath = "graphics/shaders/closest_hit_shader.dxil"; - } - - if (!readFile(shaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader file"); - return false; - } - - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); + palLog(nullptr, "Failed to create closest hit shader: %s", error); return false; } - readFile(shaderPath, bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_CLOSEST_HIT; - - result = palCreateShader(device, &shaderCreateInfo, &closestHitShader); + result = palCreateShader(device, &missShaderCreateInfo, &missShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create closest hit shader: %s", error); + palLog(nullptr, "Failed to create miss shader: %s", error); return false; } - palFree(nullptr, bytecode); Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader PalBufferCreateInfo bufferCreateInfo = {0}; diff --git a/tests/graphics/shaders/closest_hit_shader.glsl b/tests/graphics/shaders/closest_hit_shader.glsl deleted file mode 100644 index 626fb050..00000000 --- a/tests/graphics/shaders/closest_hit_shader.glsl +++ /dev/null @@ -1,10 +0,0 @@ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 0) rayPayloadInEXT vec3 payloadColor; - -void main() -{ - payloadColor = vec3(0.0, 1.0, 0.0); -} \ No newline at end of file diff --git a/tests/graphics/shaders/closest_hit_shader.spv b/tests/graphics/shaders/closest_hit_shader.spv deleted file mode 100644 index 2ee524ac28481cce7ff123a25392b46219e34994..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmY*V!D_-#5F8VeSgkFh)T`oA5f8NpLOqBmm_yN0yoHB?2-ZmS;>mtokNpO}!;9cd zs-XK=W@mSHvc$G39^3>nNFj^=$ic!s2c+R*{P7hG2csY|yI>oc>0&jf)y5S;wSR4SpO*NDeT@L-Ej@FJyxIfxPQ7CsD=LQEv>rKdifH=n`h=%wIH ztf2cb?9T4&WQk*+2ktfZK*F`<2)`vyuEX%WW zxhm7E(WN%~a5@9cj;Q%K23*!}W>IT!KsbCh^Cv|vHM6XkzC8W2hsVj^J&!u=zMFN` znDVx%nwAs;I?3y-b46F5u=d$Yh*P=*%;LH%ArG0qc$fN&LUBPRU5`-j b7h_(i@9IW{ytnLl%r|86)6R~6>6-Wk9DyTJ diff --git a/tests/graphics/shaders/raygen_shader.glsl b/tests/graphics/shaders/raygen_shader.glsl deleted file mode 100644 index 4af8153e..00000000 --- a/tests/graphics/shaders/raygen_shader.glsl +++ /dev/null @@ -1,44 +0,0 @@ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(set = 0, binding = 0) buffer OutputBuffer -{ - vec4 pixels[]; -} outBuffer; - -layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; -layout(location = 0) rayPayloadEXT vec3 payloadColor; - -void main() -{ - uvec2 pixel = gl_LaunchIDEXT.xy; - uvec2 size = gl_LaunchSizeEXT.xy; - payloadColor = vec3(0.0); - - vec2 uv = (vec2(pixel) + 0.5) / vec2(size); - vec2 ndcUv = uv * 2.0 - 1.0; - vec3 origin = vec3(0.0, 0.0, -3.0); - vec3 direction = normalize(vec3(ndcUv.x, ndcUv.y, 1.0)); - - traceRayEXT( - tlas, - gl_RayFlagsOpaqueEXT, - 0xFF, - 0, - 0, - 0, - origin, - 0.001, - direction, - 1000.0, - 0 - ); - - if (pixel.x >= size.x || pixel.y >= size.y) { - return; - } - - uint index = pixel.y * size.x + pixel.x; - outBuffer.pixels[index] = vec4(payloadColor, 1.0); -} \ No newline at end of file diff --git a/tests/graphics/shaders/raygen_shader.spv b/tests/graphics/shaders/raygen_shader.spv deleted file mode 100644 index 4d24a2da959a30ad33e80765d34c6e92a06ba219..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2620 zcmZ9MTXU0D6oz-xBt@uTX#r1QN>Nd2MFm6<+R|c*L>njw9xx3_TB4!pq^Sekh=Uhi z@jJZoH|UjK@C%&rXE+{a9DSZI-`3cjd1tNn-D|DAzJ17GW@0Gh2f~i9E!+;hF%mN2 z%aIVahkRHne^9x&aJkZ{-mP>y)mn3HmDqe3AhcLoDot&4>r=;$A2oAl7)%N{w~Oo_ z#zM&A->x>-oEQdAfW6=}sDnX%8SEpHveYe>D(A0X`QLIO$4q}6`D5g)H}5oB*c^G* zUTsxM)y=iqtqb$iP|wmw2pi3N4GerJS^wX-B_@){UJd(NuikC7tM$2dtKI4442EZL zHoxfAJA}VhuU&;E^(V3IPIJ{S%<+2_UT=09wQjTRN85wn+HF-gFbThgZLZZDcM_ft zH?fPG-Sy4xxy_Z8MzU_6NOec@on%|zJ!|&`7OC&I?*Kot-*Wd@{!_|be;g!dmiBWH z?l8WJ%>(m_oQLaXz(QXS6L5#|_Fz3n180yx%hb)K90}?^cW4{^fhg8pRfXwb+J)$69;fKO?G}EBEZxj=;^`2ON`h zVce5I?LTD0Q*dMBH$07R|LU>M0er@E&5w3lKGkMV;@uS z*n@M%xlc!vIKMd?UcXtXM7H?09?m;`5bVJu}kw<*FBH5Kl}E4ma*2(g8iIb6}t=$;NQf`&8uNO zb2a;wdl%K5|2*}Vu_w5@8LTxOgWz|R9M)X#oBtv95xM^rk$aZD`+k0?k9$^=TexpO z#`}%eQhtW@ytj`7dtD^TxSgq{?ic`P>D0cQi+TJNCvP+6?S`ufN6fQ-=d9s<_RdKb9`?zU>10$_V2py0M9diqi?C0>M>>k?pgK6T!5>8N1b`>yTCm4Z|PO- zB2fR0?|KjG_>(#H5>WFk>BqI+$G4xjpZ2o|)MHE;-+uaIF2U7fKbP^%Q~!fC;#%5Y zxykmo1ne&djJFSay^3|%t1(xAn!W1(#i{A5#h$L?Z|(a-H1!zs5&qVF{1{FBYr61T zKLO^c$GjW(*6!c`PvPqK)4U44x$52{|1;FQC)RBMwRmq<@Vy6@$REY70yRg}ZsDtW qN2AtEHUAUK?Bg=_Ghn{)&L0M|tm^-03)I0Jum^inGsk^A3H||(*S-M& diff --git a/tests/tests_main.c b/tests/tests_main.c index 8d4bafd8..9dce3360 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,8 +58,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders + // registerTest(computeTest, "Compute Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From d91c05948a58d4d6a35753e55c754f355166db0e Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 29 Apr 2026 15:52:20 +0000 Subject: [PATCH 188/372] triangle test: remove shader files dependency and embed shader sources and bytecode into source file --- tests/graphics/compute_test.c | 457 +----- tests/graphics/ray_tracing_test.c | 296 +--- tests/graphics/shaders.h | 1444 +++++++++++++++++ .../shaders/triangle_frag_shader.dxil | Bin 2948 -> 0 bytes .../shaders/triangle_frag_shader.glsl | 11 - .../shaders/triangle_frag_shader.hlsl | 11 - .../graphics/shaders/triangle_frag_shader.spv | Bin 372 -> 0 bytes .../shaders/triangle_vert_shader.dxil | Bin 3128 -> 0 bytes .../shaders/triangle_vert_shader.glsl | 13 - .../shaders/triangle_vert_shader.hlsl | 20 - .../graphics/shaders/triangle_vert_shader.spv | Bin 1140 -> 0 bytes tests/graphics/triangle_test.c | 72 +- tests/tests.h | 28 - tests/tests_main.c | 4 +- 14 files changed, 1473 insertions(+), 883 deletions(-) create mode 100644 tests/graphics/shaders.h delete mode 100644 tests/graphics/shaders/triangle_frag_shader.dxil delete mode 100644 tests/graphics/shaders/triangle_frag_shader.glsl delete mode 100644 tests/graphics/shaders/triangle_frag_shader.hlsl delete mode 100644 tests/graphics/shaders/triangle_frag_shader.spv delete mode 100644 tests/graphics/shaders/triangle_vert_shader.dxil delete mode 100644 tests/graphics/shaders/triangle_vert_shader.glsl delete mode 100644 tests/graphics/shaders/triangle_vert_shader.hlsl delete mode 100644 tests/graphics/shaders/triangle_vert_shader.spv diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index dd772391..0ee01395 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -1,465 +1,10 @@ #include "pal/pal_graphics.h" #include "tests.h" +#include "shaders.h" #define BUFFER_SIZE 400 -// clang-format off - -// Compute Shader Source Code GLSL -// #version 450 - -// layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -// layout(set = 0, binding = 0) buffer OutputBuffer -// { -// vec4 pixels[]; -// } outBuffer; - -// layout(push_constant) uniform PushConstants -// { -// uint width; -// uint height; -// vec4 color; -// } pc; - -// void main() -// { -// uvec2 id = gl_GlobalInvocationID.xy; -// if (id.x >= pc.width || id.y >= pc.height) { -// return; -// } - -// uint index = id.y * pc.width + id.x; -// outBuffer.pixels[index] = pc.color; -// } - -// Compute Shader Source Code HLSL -// struct PushConstants -// { -// uint width; -// uint height; -// float4 color; -// }; - -// We used raw Buffer but structured buffer can be used as well. -// PalDescriptorBufferInfo::stride must be set to 16 - -// RWByteAddressBuffer outBuffer : register(u0); -// ConstantBuffer pc : register(b0); - -// [numThreads(16, 16, 1)] -// void main(uint3 id : SV_DispatchThreadID) -// { -// if (id.x >= pc.width || id.y >= pc.height) { -// return; -// } - -// uint index = id.y * pc.width + id.x; -// uint offset = index * 16; // sizeof(float4) -// outBuffer.Store4(offset, asuint(pc.color)); -// } - -static const Uint32 s_ComputeShaderSpv[] = { - 0x07230203, 0x00010000, 0x0008000b, 0x00000043, - 0x00000000, 0x00020011, 0x00000001, 0x0006000b, - 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, - 0x00000000, 0x0003000e, 0x00000000, 0x00000001, - 0x0006000f, 0x00000005, 0x00000004, 0x6e69616d, - 0x00000000, 0x0000000c, 0x00060010, 0x00000004, - 0x00000011, 0x00000010, 0x00000010, 0x00000001, - 0x00030003, 0x00000002, 0x000001c2, 0x00040005, - 0x00000004, 0x6e69616d, 0x00000000, 0x00030005, - 0x00000009, 0x00006469, 0x00080005, 0x0000000c, - 0x475f6c67, 0x61626f6c, 0x766e496c, 0x7461636f, - 0x496e6f69, 0x00000044, 0x00060005, 0x00000016, - 0x68737550, 0x736e6f43, 0x746e6174, 0x00000073, - 0x00050006, 0x00000016, 0x00000000, 0x74646977, - 0x00000068, 0x00050006, 0x00000016, 0x00000001, - 0x67696568, 0x00007468, 0x00050006, 0x00000016, - 0x00000002, 0x6f6c6f63, 0x00000072, 0x00030005, - 0x00000018, 0x00006370, 0x00040005, 0x0000002d, - 0x65646e69, 0x00000078, 0x00060005, 0x00000037, - 0x7074754f, 0x75427475, 0x72656666, 0x00000000, - 0x00050006, 0x00000037, 0x00000000, 0x65786970, - 0x0000736c, 0x00050005, 0x00000039, 0x4274756f, - 0x65666675, 0x00000072, 0x00040047, 0x0000000c, - 0x0000000b, 0x0000001c, 0x00030047, 0x00000016, - 0x00000002, 0x00050048, 0x00000016, 0x00000000, - 0x00000023, 0x00000000, 0x00050048, 0x00000016, - 0x00000001, 0x00000023, 0x00000004, 0x00050048, - 0x00000016, 0x00000002, 0x00000023, 0x00000010, - 0x00040047, 0x00000036, 0x00000006, 0x00000010, - 0x00030047, 0x00000037, 0x00000003, 0x00050048, - 0x00000037, 0x00000000, 0x00000023, 0x00000000, - 0x00040047, 0x00000039, 0x00000021, 0x00000000, - 0x00040047, 0x00000039, 0x00000022, 0x00000000, - 0x00040047, 0x00000042, 0x0000000b, 0x00000019, - 0x00020013, 0x00000002, 0x00030021, 0x00000003, - 0x00000002, 0x00040015, 0x00000006, 0x00000020, - 0x00000000, 0x00040017, 0x00000007, 0x00000006, - 0x00000002, 0x00040020, 0x00000008, 0x00000007, - 0x00000007, 0x00040017, 0x0000000a, 0x00000006, - 0x00000003, 0x00040020, 0x0000000b, 0x00000001, - 0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c, - 0x00000001, 0x00020014, 0x0000000f, 0x0004002b, - 0x00000006, 0x00000010, 0x00000000, 0x00040020, - 0x00000011, 0x00000007, 0x00000006, 0x00030016, - 0x00000014, 0x00000020, 0x00040017, 0x00000015, - 0x00000014, 0x00000004, 0x0005001e, 0x00000016, - 0x00000006, 0x00000006, 0x00000015, 0x00040020, - 0x00000017, 0x00000009, 0x00000016, 0x0004003b, - 0x00000017, 0x00000018, 0x00000009, 0x00040015, - 0x00000019, 0x00000020, 0x00000001, 0x0004002b, - 0x00000019, 0x0000001a, 0x00000000, 0x00040020, - 0x0000001b, 0x00000009, 0x00000006, 0x0004002b, - 0x00000006, 0x00000022, 0x00000001, 0x0004002b, - 0x00000019, 0x00000025, 0x00000001, 0x0003001d, - 0x00000036, 0x00000015, 0x0003001e, 0x00000037, - 0x00000036, 0x00040020, 0x00000038, 0x00000002, - 0x00000037, 0x0004003b, 0x00000038, 0x00000039, - 0x00000002, 0x0004002b, 0x00000019, 0x0000003b, - 0x00000002, 0x00040020, 0x0000003c, 0x00000009, - 0x00000015, 0x00040020, 0x0000003f, 0x00000002, - 0x00000015, 0x0004002b, 0x00000006, 0x00000041, - 0x00000010, 0x0006002c, 0x0000000a, 0x00000042, - 0x00000041, 0x00000041, 0x00000022, 0x00050036, - 0x00000002, 0x00000004, 0x00000000, 0x00000003, - 0x000200f8, 0x00000005, 0x0004003b, 0x00000008, - 0x00000009, 0x00000007, 0x0004003b, 0x00000011, - 0x0000002d, 0x00000007, 0x0004003d, 0x0000000a, - 0x0000000d, 0x0000000c, 0x0007004f, 0x00000007, - 0x0000000e, 0x0000000d, 0x0000000d, 0x00000000, - 0x00000001, 0x0003003e, 0x00000009, 0x0000000e, - 0x00050041, 0x00000011, 0x00000012, 0x00000009, - 0x00000010, 0x0004003d, 0x00000006, 0x00000013, - 0x00000012, 0x00050041, 0x0000001b, 0x0000001c, - 0x00000018, 0x0000001a, 0x0004003d, 0x00000006, - 0x0000001d, 0x0000001c, 0x000500ae, 0x0000000f, - 0x0000001e, 0x00000013, 0x0000001d, 0x000400a8, - 0x0000000f, 0x0000001f, 0x0000001e, 0x000300f7, - 0x00000021, 0x00000000, 0x000400fa, 0x0000001f, - 0x00000020, 0x00000021, 0x000200f8, 0x00000020, - 0x00050041, 0x00000011, 0x00000023, 0x00000009, - 0x00000022, 0x0004003d, 0x00000006, 0x00000024, - 0x00000023, 0x00050041, 0x0000001b, 0x00000026, - 0x00000018, 0x00000025, 0x0004003d, 0x00000006, - 0x00000027, 0x00000026, 0x000500ae, 0x0000000f, - 0x00000028, 0x00000024, 0x00000027, 0x000200f9, - 0x00000021, 0x000200f8, 0x00000021, 0x000700f5, - 0x0000000f, 0x00000029, 0x0000001e, 0x00000005, - 0x00000028, 0x00000020, 0x000300f7, 0x0000002b, - 0x00000000, 0x000400fa, 0x00000029, 0x0000002a, - 0x0000002b, 0x000200f8, 0x0000002a, 0x000100fd, - 0x000200f8, 0x0000002b, 0x00050041, 0x00000011, - 0x0000002e, 0x00000009, 0x00000022, 0x0004003d, - 0x00000006, 0x0000002f, 0x0000002e, 0x00050041, - 0x0000001b, 0x00000030, 0x00000018, 0x0000001a, - 0x0004003d, 0x00000006, 0x00000031, 0x00000030, - 0x00050084, 0x00000006, 0x00000032, 0x0000002f, - 0x00000031, 0x00050041, 0x00000011, 0x00000033, - 0x00000009, 0x00000010, 0x0004003d, 0x00000006, - 0x00000034, 0x00000033, 0x00050080, 0x00000006, - 0x00000035, 0x00000032, 0x00000034, 0x0003003e, - 0x0000002d, 0x00000035, 0x0004003d, 0x00000006, - 0x0000003a, 0x0000002d, 0x00050041, 0x0000003c, - 0x0000003d, 0x00000018, 0x0000003b, 0x0004003d, - 0x00000015, 0x0000003e, 0x0000003d, 0x00060041, - 0x0000003f, 0x00000040, 0x00000039, 0x0000001a, - 0x0000003a, 0x0003003e, 0x00000040, 0x0000003e, - 0x000100fd, 0x00010038 -}; - -static const Uint8 s_ComputeShaderDxil[] = { - 0x44, 0x58, 0x42, 0x43, 0x3c, 0x03, 0x02, 0xb3, 0x0e, 0x59, 0xfb, 0x9b, - 0xc1, 0xd2, 0x75, 0x12, 0xb3, 0x0d, 0x3c, 0xd0, 0x01, 0x00, 0x00, 0x00, - 0x58, 0x0d, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0xf4, 0x00, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00, 0x4c, 0x07, 0x00, 0x00, - 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x50, 0x53, 0x56, 0x30, 0x80, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0x34, 0x06, 0x00, 0x00, - 0x60, 0x00, 0x05, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, - 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x01, 0xd5, 0x06, 0x62, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x90, 0x00, 0x49, 0x18, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, - 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, - 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x74, 0x23, 0x00, 0x25, 0x00, 0x14, 0xe6, - 0x08, 0xc0, 0xa0, 0x0c, 0x63, 0x0c, 0x22, 0x33, 0x00, 0x47, 0x0d, 0x97, - 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0xdc, 0x46, 0x15, 0x2b, 0x31, 0xf9, 0xc5, - 0x6d, 0x23, 0xc2, 0x18, 0x63, 0xe6, 0x08, 0x10, 0x42, 0xf7, 0x0c, 0x97, - 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, 0x0c, 0x0b, 0x81, 0x82, 0x54, - 0x88, 0x33, 0xd4, 0xa0, 0x75, 0xd4, 0x70, 0xf9, 0x13, 0xf6, 0x10, 0x92, - 0xcf, 0x6d, 0x54, 0xb1, 0x12, 0x93, 0x8f, 0xdc, 0x36, 0x22, 0xc6, 0x18, - 0xa3, 0x10, 0x6d, 0xa8, 0x41, 0x6e, 0x8e, 0x20, 0x28, 0x86, 0x1a, 0x68, - 0x0c, 0x48, 0xb1, 0x28, 0x60, 0xa8, 0x31, 0xc6, 0x18, 0x03, 0xd1, 0x1c, - 0x08, 0x38, 0x4d, 0x9a, 0x22, 0x4a, 0x98, 0xfc, 0x15, 0xde, 0xb0, 0x89, - 0xd0, 0x86, 0x21, 0x22, 0x24, 0x69, 0xa3, 0x8a, 0x82, 0x88, 0x50, 0x30, - 0xc8, 0x0e, 0x23, 0x10, 0xc6, 0x51, 0xd2, 0x14, 0x51, 0xc2, 0xe4, 0xa7, - 0x94, 0x74, 0x70, 0x4e, 0x23, 0x4d, 0x40, 0x33, 0x49, 0x68, 0x18, 0x03, - 0x9f, 0xf0, 0x08, 0x28, 0xc8, 0xa4, 0xe7, 0x08, 0x40, 0x01, 0x00, 0x00, - 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, - 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, - 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, - 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, - 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, - 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, - 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x04, 0x10, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, - 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, - 0x89, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, - 0xc8, 0x33, 0x01, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x16, 0x08, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, - 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, - 0x25, 0x30, 0x02, 0x50, 0x0c, 0x65, 0x51, 0x40, 0x65, 0x50, 0x0e, 0xa5, - 0x50, 0x08, 0x05, 0x52, 0x12, 0xa5, 0x51, 0x34, 0x45, 0x40, 0x70, 0x04, - 0x80, 0x78, 0x81, 0x50, 0x9e, 0x01, 0x20, 0x3d, 0x03, 0x40, 0x7b, 0x06, - 0x80, 0xee, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x74, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, - 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, - 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb1, 0xa9, 0x81, - 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, 0xcb, 0x09, 0x83, 0x49, - 0xd9, 0x10, 0x04, 0x13, 0x84, 0xc1, 0x98, 0x20, 0x0c, 0xc7, 0x06, 0x61, - 0x20, 0x36, 0x08, 0x04, 0x41, 0x61, 0x6c, 0x6e, 0x82, 0x30, 0x20, 0x1b, - 0x86, 0x03, 0x21, 0x26, 0x08, 0x57, 0xc6, 0xe4, 0xad, 0x8e, 0x4e, 0xa8, - 0xce, 0xcc, 0xac, 0x4c, 0x6e, 0x82, 0x30, 0x24, 0x13, 0x04, 0x88, 0xda, - 0xb0, 0x10, 0xca, 0x42, 0x10, 0x03, 0xd3, 0x34, 0x0d, 0xb0, 0x21, 0x70, - 0x26, 0x08, 0x1b, 0x46, 0x01, 0x6e, 0x6c, 0x82, 0x30, 0x28, 0x1b, 0x10, - 0x02, 0x8a, 0x08, 0x62, 0x90, 0x80, 0x0d, 0xc1, 0xb4, 0x81, 0x00, 0x1e, - 0x0a, 0x98, 0x20, 0x64, 0x16, 0x8b, 0xbb, 0x34, 0x32, 0x3a, 0xb4, 0x09, - 0xc2, 0xb0, 0x4c, 0x10, 0x06, 0x66, 0x82, 0x30, 0x34, 0x1b, 0x0c, 0xe4, - 0xc2, 0x88, 0x4c, 0xa3, 0x81, 0x56, 0x96, 0x76, 0x86, 0x46, 0x37, 0x41, - 0x18, 0x9c, 0x0d, 0x06, 0xc2, 0x61, 0x5d, 0xa6, 0xb1, 0x18, 0x7b, 0x63, - 0x7b, 0x93, 0x9b, 0x20, 0x0c, 0xcf, 0x04, 0x61, 0x80, 0x26, 0x08, 0x43, - 0xb4, 0x01, 0x41, 0x3e, 0x0c, 0x0c, 0xb2, 0x30, 0x10, 0x83, 0x6e, 0x03, - 0x21, 0x6d, 0xde, 0x18, 0x4c, 0x10, 0xb4, 0x6b, 0x03, 0x81, 0x44, 0x18, - 0xb1, 0x41, 0x90, 0xcc, 0x60, 0x43, 0x41, 0x58, 0x64, 0x50, 0x06, 0x67, - 0x30, 0x41, 0x10, 0x80, 0x0d, 0xc0, 0x86, 0x81, 0x50, 0x03, 0x35, 0xd8, - 0x10, 0xac, 0xc1, 0x86, 0x61, 0x48, 0x03, 0x36, 0x20, 0xd1, 0x16, 0x96, - 0xe6, 0x36, 0x41, 0xe0, 0xaa, 0x0d, 0x03, 0x18, 0x80, 0xc1, 0xb0, 0x81, - 0x20, 0xde, 0xa0, 0x83, 0x83, 0x0d, 0x45, 0x1a, 0xb8, 0x01, 0x50, 0xc5, - 0x01, 0x11, 0x31, 0xb9, 0x30, 0xb7, 0x31, 0xb4, 0xb2, 0x39, 0x16, 0x69, - 0x6e, 0x73, 0x74, 0x73, 0x13, 0x84, 0x41, 0x22, 0x91, 0xe6, 0x46, 0x37, - 0xc7, 0x84, 0xae, 0x0c, 0xef, 0x6b, 0x8e, 0xee, 0x4d, 0xae, 0x8c, 0x45, - 0x5d, 0x9a, 0x1b, 0xdd, 0xdc, 0x04, 0x61, 0x98, 0x36, 0x28, 0x73, 0x30, - 0xd0, 0x41, 0x1d, 0xd8, 0x41, 0x77, 0x07, 0x03, 0x1e, 0xe4, 0x41, 0x15, - 0x36, 0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37, 0xba, 0x29, 0x41, - 0x50, 0x85, 0x0c, 0xcf, 0xc5, 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, 0x6d, - 0x4a, 0x40, 0x34, 0x21, 0xc3, 0x73, 0xb1, 0x0b, 0x63, 0xb3, 0x2b, 0x93, - 0x9b, 0x12, 0x14, 0x75, 0xc8, 0xf0, 0x5c, 0xe6, 0xd0, 0xc2, 0xc8, 0xca, - 0xe4, 0x9a, 0xde, 0xc8, 0xca, 0xd8, 0xa6, 0x04, 0x48, 0x19, 0x32, 0x3c, - 0x17, 0xb9, 0xb2, 0xb9, 0xb7, 0x3a, 0xb9, 0xb1, 0xb2, 0xb9, 0x29, 0x01, - 0x55, 0x89, 0x0c, 0xcf, 0x85, 0x2e, 0x0f, 0xae, 0x2c, 0xc8, 0xcd, 0xed, - 0x8d, 0x2e, 0x8c, 0x2e, 0xed, 0xcd, 0x6d, 0x6e, 0x8a, 0x70, 0x06, 0x6c, - 0x50, 0x87, 0x0c, 0xcf, 0xa5, 0xcc, 0x8d, 0x4e, 0x2e, 0x0f, 0xea, 0x2d, - 0xcd, 0x8d, 0x6e, 0x6e, 0x4a, 0x10, 0x07, 0x5d, 0xc8, 0xf0, 0x5c, 0xc6, - 0xde, 0xea, 0xdc, 0xe8, 0xca, 0xe4, 0xe6, 0xa6, 0x04, 0x79, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, - 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, - 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, - 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, - 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, - 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, - 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, - 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, - 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, - 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, - 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, - 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, - 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, - 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, - 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, - 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, - 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, - 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, - 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, - 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, - 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, - 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, - 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, - 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, - 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, - 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x30, 0x83, 0x81, - 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, 0x1c, 0xc2, 0x61, 0x1d, - 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x56, 0x50, 0x0d, 0x97, 0xef, 0x3c, 0x7e, 0x40, - 0x15, 0x05, 0x11, 0xb1, 0x93, 0x13, 0x11, 0x3e, 0x72, 0xdb, 0x26, 0xb0, - 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, - 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x03, 0xdb, 0x70, - 0xf9, 0xce, 0xe3, 0x0b, 0x01, 0x55, 0x14, 0x44, 0x54, 0x3a, 0xc0, 0x50, - 0x12, 0x06, 0x20, 0x60, 0x3e, 0x72, 0xdb, 0x46, 0x20, 0x0d, 0x97, 0xef, - 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, 0x33, 0x2c, 0x84, 0x05, - 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x1d, 0x11, 0x01, 0x0c, 0xe2, 0xe0, - 0x23, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x6f, 0xb0, 0x69, 0x56, 0x40, 0x84, 0x26, 0xed, - 0x85, 0x8e, 0xc5, 0x2c, 0x46, 0xd0, 0xbf, 0x12, 0x44, 0x58, 0x49, 0x4c, - 0x04, 0x06, 0x00, 0x00, 0x60, 0x00, 0x05, 0x00, 0x81, 0x01, 0x00, 0x00, - 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0xec, 0x05, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, - 0x78, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, - 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, - 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, - 0xa4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, - 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, - 0xe4, 0x48, 0x0e, 0x90, 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, - 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, - 0x40, 0x02, 0xa8, 0x0d, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, - 0x01, 0xd5, 0x06, 0x62, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x90, 0x00, - 0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, - 0x20, 0x4c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, - 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, - 0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x78, 0x23, 0x00, - 0x25, 0x00, 0x14, 0xe6, 0x08, 0xc0, 0xa0, 0x0c, 0x63, 0x0c, 0x22, 0x33, - 0x00, 0x47, 0x0d, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0xdc, 0x46, 0x15, - 0x2b, 0x31, 0xf9, 0xc5, 0x6d, 0x23, 0xc2, 0x18, 0x63, 0xe6, 0x08, 0x10, - 0x42, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, 0x0c, - 0x0b, 0x81, 0x82, 0x54, 0x88, 0x33, 0xd4, 0xa0, 0x75, 0xd4, 0x70, 0xf9, - 0x13, 0xf6, 0x10, 0x92, 0xcf, 0x6d, 0x54, 0xb1, 0x12, 0x93, 0x8f, 0xdc, - 0x36, 0x22, 0xc6, 0x18, 0xa3, 0x10, 0x6d, 0xa8, 0x41, 0x6e, 0x8e, 0x20, - 0x28, 0x86, 0x1a, 0x68, 0x0c, 0x48, 0xb1, 0x28, 0x60, 0xa8, 0x31, 0xc6, - 0x18, 0x03, 0xd1, 0x1c, 0x08, 0x38, 0x4d, 0x9a, 0x22, 0x4a, 0x98, 0xfc, - 0x15, 0xde, 0xb0, 0x89, 0xd0, 0x86, 0x21, 0x22, 0x24, 0x69, 0xa3, 0x8a, - 0x82, 0x88, 0x50, 0x30, 0xc8, 0x0e, 0x23, 0x10, 0xc6, 0x51, 0xd2, 0x14, - 0x51, 0xc2, 0xe4, 0xa7, 0x94, 0x74, 0x70, 0x4e, 0x23, 0x4d, 0x40, 0x33, - 0x49, 0x68, 0x18, 0x03, 0x9f, 0xf0, 0x08, 0x28, 0xc8, 0xa4, 0xe7, 0x08, - 0x40, 0x61, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, - 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, - 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, - 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, - 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, - 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, - 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, - 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, - 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, - 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, - 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x86, 0x3c, 0x04, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x89, 0x80, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc8, 0x33, 0x01, 0x01, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x16, 0x08, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, - 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, 0x25, 0x30, 0x02, 0x50, - 0x12, 0xc5, 0x50, 0x16, 0x05, 0x54, 0x08, 0x05, 0x42, 0x70, 0x04, 0x80, - 0x78, 0x81, 0xd0, 0x9e, 0x01, 0xa0, 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, - 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, - 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, - 0xa1, 0xb1, 0xa9, 0x81, 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, - 0xcb, 0x09, 0x83, 0x49, 0xd9, 0x10, 0x04, 0x13, 0x84, 0xc1, 0x98, 0x20, - 0x0c, 0xc7, 0x06, 0x61, 0x20, 0x26, 0x08, 0x03, 0xb2, 0x41, 0x18, 0x0c, - 0x0a, 0x63, 0x73, 0x13, 0x84, 0x21, 0xd9, 0x30, 0x20, 0x09, 0x31, 0x41, - 0xb8, 0x22, 0x02, 0x13, 0x84, 0x41, 0x99, 0x20, 0x40, 0xce, 0x86, 0x85, - 0x58, 0x18, 0x82, 0x18, 0x1a, 0xc7, 0x71, 0x80, 0x0d, 0xc1, 0x33, 0x41, - 0xd8, 0xa0, 0x09, 0xc2, 0xb0, 0x6c, 0x40, 0x88, 0x88, 0x21, 0x88, 0x41, - 0x02, 0x36, 0x04, 0xd3, 0x06, 0x02, 0x80, 0x28, 0x60, 0x82, 0x20, 0x00, - 0x24, 0xda, 0xc2, 0xd2, 0xdc, 0x26, 0x08, 0xdc, 0x33, 0x41, 0x18, 0x98, - 0x09, 0xc2, 0xd0, 0x6c, 0x18, 0x34, 0x6d, 0xd8, 0x40, 0x10, 0x58, 0xb6, - 0x6d, 0x28, 0xac, 0x0b, 0xa8, 0xb8, 0x2a, 0x6c, 0x6c, 0x76, 0x6d, 0x2e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, 0x9e, 0x8b, - 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, 0x42, 0x86, - 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26, 0x37, 0x25, 0x30, 0xea, 0x90, - 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, 0x91, 0x95, - 0xb1, 0x4d, 0x09, 0x92, 0x32, 0x64, 0x78, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x53, 0x02, 0xaa, 0x0e, 0x19, 0x9e, 0x4b, - 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, - 0x80, 0x03, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, - 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, - 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, - 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, - 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, - 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, - 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, - 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, - 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, - 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, - 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, - 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, - 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, - 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, - 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, - 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, - 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, - 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, - 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, - 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, - 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, - 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, - 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, - 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, - 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, - 0xf4, 0x30, 0x83, 0x81, 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, - 0x1c, 0xc2, 0x61, 0x1d, 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, - 0x71, 0x20, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x56, 0x50, 0x0d, 0x97, - 0xef, 0x3c, 0x7e, 0x40, 0x15, 0x05, 0x11, 0xb1, 0x93, 0x13, 0x11, 0x3e, - 0x72, 0xdb, 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, - 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, - 0x6d, 0x03, 0xdb, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x01, 0x55, 0x14, 0x44, - 0x54, 0x3a, 0xc0, 0x50, 0x12, 0x06, 0x20, 0x60, 0x3e, 0x72, 0xdb, 0x46, - 0x20, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, - 0x33, 0x2c, 0x84, 0x05, 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x1d, 0x11, - 0x01, 0x0c, 0xe2, 0xe0, 0x23, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x13, 0x04, 0x43, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x34, 0x4a, 0xae, 0x74, 0x03, 0xca, 0xae, 0x14, 0x03, 0x66, 0x00, 0x08, - 0x95, 0x40, 0x11, 0x94, 0x07, 0x00, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, - 0x82, 0x60, 0x10, 0x59, 0xc8, 0x30, 0x4d, 0xcc, 0x88, 0x41, 0x02, 0x80, - 0x20, 0x18, 0x44, 0x57, 0x32, 0x50, 0x54, 0x33, 0x62, 0x60, 0x00, 0x20, - 0x08, 0x06, 0xc4, 0x96, 0x54, 0x23, 0x06, 0x06, 0x00, 0x82, 0x60, 0x40, - 0x70, 0xca, 0x35, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0xa6, 0x0c, - 0xd7, 0x68, 0x42, 0x00, 0x0c, 0x37, 0x10, 0x01, 0x19, 0x8c, 0x26, 0x0c, - 0xc1, 0x70, 0x43, 0x11, 0x90, 0x41, 0x0d, 0x81, 0xce, 0x32, 0x04, 0x42, - 0x50, 0xc5, 0x21, 0x15, 0x24, 0x50, 0x81, 0x76, 0x23, 0x06, 0x07, 0x00, - 0x82, 0x60, 0xb0, 0x94, 0xc1, 0xc4, 0x84, 0xc1, 0x68, 0x42, 0x00, 0x8c, - 0x26, 0x08, 0xc1, 0x68, 0xc2, 0x20, 0x8c, 0x26, 0x10, 0xc3, 0x11, 0x63, - 0x8f, 0x18, 0x7b, 0xc4, 0xd8, 0x23, 0xc6, 0x8e, 0x18, 0x34, 0x00, 0x08, - 0x82, 0xc1, 0xb4, 0x06, 0x9b, 0xa5, 0x68, 0xc4, 0x20, 0x04, 0xd7, 0x2c, - 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -// clang-format on - // layout must match shader typedef struct { Uint32 width; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 66d91cc5..d167b2fb 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -1,304 +1,10 @@ #include "pal/pal_graphics.h" #include "tests.h" +#include "shaders.h" #define BUFFER_SIZE 400 -// clang-format off - -// Ray Tracing Shaders Source Code GLSL - -// Raygen -// #version 460 -// #extension GL_EXT_ray_tracing : require - -// layout(set = 0, binding = 0) buffer OutputBuffer -// { -// vec4 pixels[]; -// } outBuffer; - -// layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; -// layout(location = 0) rayPayloadEXT vec3 payloadColor; - -// void main() -// { -// uvec2 pixel = gl_LaunchIDEXT.xy; -// uvec2 size = gl_LaunchSizeEXT.xy; -// payloadColor = vec3(0.0); - -// vec2 uv = (vec2(pixel) + 0.5) / vec2(size); -// vec2 ndcUv = uv * 2.0 - 1.0; -// vec3 origin = vec3(0.0, 0.0, -3.0); -// vec3 direction = normalize(vec3(ndcUv.x, ndcUv.y, 1.0)); - -// traceRayEXT( -// tlas, -// gl_RayFlagsOpaqueEXT, -// 0xFF, -// 0, -// 0, -// 0, -// origin, -// 0.001, -// direction, -// 1000.0, -// 0 -// ); - -// if (pixel.x >= size.x || pixel.y >= size.y) { -// return; -// } - -// uint index = pixel.y * size.x + pixel.x; -// outBuffer.pixels[index] = vec4(payloadColor, 1.0); -// } - -// Closest Hit -// #version 460 -// #extension GL_EXT_ray_tracing : require - -// layout(location = 0) rayPayloadInEXT vec3 payloadColor; - -// void main() -// { -// payloadColor = vec3(0.0, 1.0, 0.0); -// } - -// Miss -// #version 460 -// #extension GL_EXT_ray_tracing : require - -// layout(location = 0) rayPayloadInEXT vec3 payloadColor; - -// void main() -// { -// payloadColor = vec3(0.0); -// } - -// Ray Tracing Shaders Source Code HLSL - -static const Uint32 s_RaygenShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x0000006d, - 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, - 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, - 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, - 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, - 0x00000000, 0x00000001, 0x000a000f, 0x000014c1, - 0x00000004, 0x6e69616d, 0x00000000, 0x0000000c, - 0x00000010, 0x00000016, 0x0000003b, 0x00000064, - 0x00030003, 0x00000002, 0x000001cc, 0x00060004, - 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, - 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, - 0x00000000, 0x00040005, 0x00000009, 0x65786970, - 0x0000006c, 0x00060005, 0x0000000c, 0x4c5f6c67, - 0x636e7561, 0x45444968, 0x00005458, 0x00040005, - 0x0000000f, 0x657a6973, 0x00000000, 0x00070005, - 0x00000010, 0x4c5f6c67, 0x636e7561, 0x7a695368, - 0x54584565, 0x00000000, 0x00060005, 0x00000016, - 0x6c796170, 0x4364616f, 0x726f6c6f, 0x00000000, - 0x00030005, 0x0000001b, 0x00007675, 0x00040005, - 0x00000024, 0x5563646e, 0x00000076, 0x00040005, - 0x0000002c, 0x6769726f, 0x00006e69, 0x00050005, - 0x0000002f, 0x65726964, 0x6f697463, 0x0000006e, - 0x00040005, 0x0000003b, 0x73616c74, 0x00000000, - 0x00040005, 0x00000057, 0x65646e69, 0x00000078, - 0x00060005, 0x00000062, 0x7074754f, 0x75427475, - 0x72656666, 0x00000000, 0x00050006, 0x00000062, - 0x00000000, 0x65786970, 0x0000736c, 0x00050005, - 0x00000064, 0x4274756f, 0x65666675, 0x00000072, - 0x00040047, 0x0000000c, 0x0000000b, 0x000014c7, - 0x00040047, 0x00000010, 0x0000000b, 0x000014c8, - 0x00040047, 0x0000003b, 0x00000021, 0x00000001, - 0x00040047, 0x0000003b, 0x00000022, 0x00000000, - 0x00040047, 0x00000061, 0x00000006, 0x00000010, - 0x00030047, 0x00000062, 0x00000002, 0x00050048, - 0x00000062, 0x00000000, 0x00000023, 0x00000000, - 0x00040047, 0x00000064, 0x00000021, 0x00000000, - 0x00040047, 0x00000064, 0x00000022, 0x00000000, - 0x00020013, 0x00000002, 0x00030021, 0x00000003, - 0x00000002, 0x00040015, 0x00000006, 0x00000020, - 0x00000000, 0x00040017, 0x00000007, 0x00000006, - 0x00000002, 0x00040020, 0x00000008, 0x00000007, - 0x00000007, 0x00040017, 0x0000000a, 0x00000006, - 0x00000003, 0x00040020, 0x0000000b, 0x00000001, - 0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c, - 0x00000001, 0x0004003b, 0x0000000b, 0x00000010, - 0x00000001, 0x00030016, 0x00000013, 0x00000020, - 0x00040017, 0x00000014, 0x00000013, 0x00000003, - 0x00040020, 0x00000015, 0x000014da, 0x00000014, - 0x0004003b, 0x00000015, 0x00000016, 0x000014da, - 0x0004002b, 0x00000013, 0x00000017, 0x00000000, - 0x0006002c, 0x00000014, 0x00000018, 0x00000017, - 0x00000017, 0x00000017, 0x00040017, 0x00000019, - 0x00000013, 0x00000002, 0x00040020, 0x0000001a, - 0x00000007, 0x00000019, 0x0004002b, 0x00000013, - 0x0000001e, 0x3f000000, 0x0004002b, 0x00000013, - 0x00000026, 0x40000000, 0x0004002b, 0x00000013, - 0x00000028, 0x3f800000, 0x00040020, 0x0000002b, - 0x00000007, 0x00000014, 0x0004002b, 0x00000013, - 0x0000002d, 0xc0400000, 0x0006002c, 0x00000014, - 0x0000002e, 0x00000017, 0x00000017, 0x0000002d, - 0x0004002b, 0x00000006, 0x00000030, 0x00000000, - 0x00040020, 0x00000031, 0x00000007, 0x00000013, - 0x0004002b, 0x00000006, 0x00000034, 0x00000001, - 0x000214dd, 0x00000039, 0x00040020, 0x0000003a, - 0x00000000, 0x00000039, 0x0004003b, 0x0000003a, - 0x0000003b, 0x00000000, 0x0004002b, 0x00000006, - 0x0000003d, 0x000000ff, 0x0004002b, 0x00000013, - 0x0000003f, 0x3a83126f, 0x0004002b, 0x00000013, - 0x00000041, 0x447a0000, 0x00040015, 0x00000042, - 0x00000020, 0x00000001, 0x0004002b, 0x00000042, - 0x00000043, 0x00000000, 0x00020014, 0x00000044, - 0x00040020, 0x00000045, 0x00000007, 0x00000006, - 0x00040017, 0x00000060, 0x00000013, 0x00000004, - 0x0003001d, 0x00000061, 0x00000060, 0x0003001e, - 0x00000062, 0x00000061, 0x00040020, 0x00000063, - 0x0000000c, 0x00000062, 0x0004003b, 0x00000063, - 0x00000064, 0x0000000c, 0x00040020, 0x0000006b, - 0x0000000c, 0x00000060, 0x00050036, 0x00000002, - 0x00000004, 0x00000000, 0x00000003, 0x000200f8, - 0x00000005, 0x0004003b, 0x00000008, 0x00000009, - 0x00000007, 0x0004003b, 0x00000008, 0x0000000f, - 0x00000007, 0x0004003b, 0x0000001a, 0x0000001b, - 0x00000007, 0x0004003b, 0x0000001a, 0x00000024, - 0x00000007, 0x0004003b, 0x0000002b, 0x0000002c, - 0x00000007, 0x0004003b, 0x0000002b, 0x0000002f, - 0x00000007, 0x0004003b, 0x00000045, 0x00000057, - 0x00000007, 0x0004003d, 0x0000000a, 0x0000000d, - 0x0000000c, 0x0007004f, 0x00000007, 0x0000000e, - 0x0000000d, 0x0000000d, 0x00000000, 0x00000001, - 0x0003003e, 0x00000009, 0x0000000e, 0x0004003d, - 0x0000000a, 0x00000011, 0x00000010, 0x0007004f, - 0x00000007, 0x00000012, 0x00000011, 0x00000011, - 0x00000000, 0x00000001, 0x0003003e, 0x0000000f, - 0x00000012, 0x0003003e, 0x00000016, 0x00000018, - 0x0004003d, 0x00000007, 0x0000001c, 0x00000009, - 0x00040070, 0x00000019, 0x0000001d, 0x0000001c, - 0x00050050, 0x00000019, 0x0000001f, 0x0000001e, - 0x0000001e, 0x00050081, 0x00000019, 0x00000020, - 0x0000001d, 0x0000001f, 0x0004003d, 0x00000007, - 0x00000021, 0x0000000f, 0x00040070, 0x00000019, - 0x00000022, 0x00000021, 0x00050088, 0x00000019, - 0x00000023, 0x00000020, 0x00000022, 0x0003003e, - 0x0000001b, 0x00000023, 0x0004003d, 0x00000019, - 0x00000025, 0x0000001b, 0x0005008e, 0x00000019, - 0x00000027, 0x00000025, 0x00000026, 0x00050050, - 0x00000019, 0x00000029, 0x00000028, 0x00000028, - 0x00050083, 0x00000019, 0x0000002a, 0x00000027, - 0x00000029, 0x0003003e, 0x00000024, 0x0000002a, - 0x0003003e, 0x0000002c, 0x0000002e, 0x00050041, - 0x00000031, 0x00000032, 0x00000024, 0x00000030, - 0x0004003d, 0x00000013, 0x00000033, 0x00000032, - 0x00050041, 0x00000031, 0x00000035, 0x00000024, - 0x00000034, 0x0004003d, 0x00000013, 0x00000036, - 0x00000035, 0x00060050, 0x00000014, 0x00000037, - 0x00000033, 0x00000036, 0x00000028, 0x0006000c, - 0x00000014, 0x00000038, 0x00000001, 0x00000045, - 0x00000037, 0x0003003e, 0x0000002f, 0x00000038, - 0x0004003d, 0x00000039, 0x0000003c, 0x0000003b, - 0x0004003d, 0x00000014, 0x0000003e, 0x0000002c, - 0x0004003d, 0x00000014, 0x00000040, 0x0000002f, - 0x000c115d, 0x0000003c, 0x00000034, 0x0000003d, - 0x00000030, 0x00000030, 0x00000030, 0x0000003e, - 0x0000003f, 0x00000040, 0x00000041, 0x00000016, - 0x00050041, 0x00000045, 0x00000046, 0x00000009, - 0x00000030, 0x0004003d, 0x00000006, 0x00000047, - 0x00000046, 0x00050041, 0x00000045, 0x00000048, - 0x0000000f, 0x00000030, 0x0004003d, 0x00000006, - 0x00000049, 0x00000048, 0x000500ae, 0x00000044, - 0x0000004a, 0x00000047, 0x00000049, 0x000400a8, - 0x00000044, 0x0000004b, 0x0000004a, 0x000300f7, - 0x0000004d, 0x00000000, 0x000400fa, 0x0000004b, - 0x0000004c, 0x0000004d, 0x000200f8, 0x0000004c, - 0x00050041, 0x00000045, 0x0000004e, 0x00000009, - 0x00000034, 0x0004003d, 0x00000006, 0x0000004f, - 0x0000004e, 0x00050041, 0x00000045, 0x00000050, - 0x0000000f, 0x00000034, 0x0004003d, 0x00000006, - 0x00000051, 0x00000050, 0x000500ae, 0x00000044, - 0x00000052, 0x0000004f, 0x00000051, 0x000200f9, - 0x0000004d, 0x000200f8, 0x0000004d, 0x000700f5, - 0x00000044, 0x00000053, 0x0000004a, 0x00000005, - 0x00000052, 0x0000004c, 0x000300f7, 0x00000055, - 0x00000000, 0x000400fa, 0x00000053, 0x00000054, - 0x00000055, 0x000200f8, 0x00000054, 0x000100fd, - 0x000200f8, 0x00000055, 0x00050041, 0x00000045, - 0x00000058, 0x00000009, 0x00000034, 0x0004003d, - 0x00000006, 0x00000059, 0x00000058, 0x00050041, - 0x00000045, 0x0000005a, 0x0000000f, 0x00000030, - 0x0004003d, 0x00000006, 0x0000005b, 0x0000005a, - 0x00050084, 0x00000006, 0x0000005c, 0x00000059, - 0x0000005b, 0x00050041, 0x00000045, 0x0000005d, - 0x00000009, 0x00000030, 0x0004003d, 0x00000006, - 0x0000005e, 0x0000005d, 0x00050080, 0x00000006, - 0x0000005f, 0x0000005c, 0x0000005e, 0x0003003e, - 0x00000057, 0x0000005f, 0x0004003d, 0x00000006, - 0x00000065, 0x00000057, 0x0004003d, 0x00000014, - 0x00000066, 0x00000016, 0x00050051, 0x00000013, - 0x00000067, 0x00000066, 0x00000000, 0x00050051, - 0x00000013, 0x00000068, 0x00000066, 0x00000001, - 0x00050051, 0x00000013, 0x00000069, 0x00000066, - 0x00000002, 0x00070050, 0x00000060, 0x0000006a, - 0x00000067, 0x00000068, 0x00000069, 0x00000028, - 0x00060041, 0x0000006b, 0x0000006c, 0x00000064, - 0x00000043, 0x00000065, 0x0003003e, 0x0000006c, - 0x0000006a, 0x000100fd, 0x00010038 -}; - -static const uint32_t s_ClosestHitShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x0000000d, - 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, - 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, - 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, - 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, - 0x00000000, 0x00000001, 0x0006000f, 0x000014c4, - 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, - 0x00030003, 0x00000002, 0x000001cc, 0x00060004, - 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, - 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, - 0x00000000, 0x00060005, 0x00000009, 0x6c796170, - 0x4364616f, 0x726f6c6f, 0x00000000, 0x00020013, - 0x00000002, 0x00030021, 0x00000003, 0x00000002, - 0x00030016, 0x00000006, 0x00000020, 0x00040017, - 0x00000007, 0x00000006, 0x00000003, 0x00040020, - 0x00000008, 0x000014de, 0x00000007, 0x0004003b, - 0x00000008, 0x00000009, 0x000014de, 0x0004002b, - 0x00000006, 0x0000000a, 0x00000000, 0x0004002b, - 0x00000006, 0x0000000b, 0x3f800000, 0x0006002c, - 0x00000007, 0x0000000c, 0x0000000a, 0x0000000b, - 0x0000000a, 0x00050036, 0x00000002, 0x00000004, - 0x00000000, 0x00000003, 0x000200f8, 0x00000005, - 0x0003003e, 0x00000009, 0x0000000c, 0x000100fd, - 0x00010038 -}; - -static const uint32_t s_MissShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x0000000c, - 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, - 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, - 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, - 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, - 0x00000000, 0x00000001, 0x0006000f, 0x000014c5, - 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, - 0x00030003, 0x00000002, 0x000001cc, 0x00060004, - 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, - 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, - 0x00000000, 0x00060005, 0x00000009, 0x6c796170, - 0x4364616f, 0x726f6c6f, 0x00000000, 0x00020013, - 0x00000002, 0x00030021, 0x00000003, 0x00000002, - 0x00030016, 0x00000006, 0x00000020, 0x00040017, - 0x00000007, 0x00000006, 0x00000003, 0x00040020, - 0x00000008, 0x000014de, 0x00000007, 0x0004003b, - 0x00000008, 0x00000009, 0x000014de, 0x0004002b, - 0x00000006, 0x0000000a, 0x00000000, 0x0006002c, - 0x00000007, 0x0000000b, 0x0000000a, 0x0000000a, - 0x0000000a, 0x00050036, 0x00000002, 0x00000004, - 0x00000000, 0x00000003, 0x000200f8, 0x00000005, - 0x0003003e, 0x00000009, 0x0000000b, 0x000100fd, - 0x00010038 -}; - -// clang-format on - static void PAL_CALL onGraphicsDebug( void* userData, PalDebugMessageSeverity severity, diff --git a/tests/graphics/shaders.h b/tests/graphics/shaders.h new file mode 100644 index 00000000..4d944373 --- /dev/null +++ b/tests/graphics/shaders.h @@ -0,0 +1,1444 @@ + +#include + +// clang-format off + +// ================================================== +// Compute +// ================================================== + +// GLSL +// #version 450 + +// layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +// layout(set = 0, binding = 0) buffer OutputBuffer +// { +// vec4 pixels[]; +// } outBuffer; + +// layout(push_constant) uniform PushConstants +// { +// uint width; +// uint height; +// vec4 color; +// } pc; + +// void main() +// { +// uvec2 id = gl_GlobalInvocationID.xy; +// if (id.x >= pc.width || id.y >= pc.height) { +// return; +// } + +// uint index = id.y * pc.width + id.x; +// outBuffer.pixels[index] = pc.color; +// } + +// HLSL +// struct PushConstants +// { +// uint width; +// uint height; +// float4 color; +// }; + +// We used raw Buffer but structured buffer can be used as well. +// PalDescriptorBufferInfo::stride must be set to 16 + +// RWByteAddressBuffer outBuffer : register(u0); +// ConstantBuffer pc : register(b0); + +// [numThreads(16, 16, 1)] +// void main(uint3 id : SV_DispatchThreadID) +// { +// if (id.x >= pc.width || id.y >= pc.height) { +// return; +// } + +// uint index = id.y * pc.width + id.x; +// uint offset = index * 16; // sizeof(float4) +// outBuffer.Store4(offset, asuint(pc.color)); +// } + +static const uint32_t s_ComputeShaderSpv[] = { + 0x07230203, 0x00010000, 0x0008000b, 0x00000043, + 0x00000000, 0x00020011, 0x00000001, 0x0006000b, + 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, + 0x0006000f, 0x00000005, 0x00000004, 0x6e69616d, + 0x00000000, 0x0000000c, 0x00060010, 0x00000004, + 0x00000011, 0x00000010, 0x00000010, 0x00000001, + 0x00030003, 0x00000002, 0x000001c2, 0x00040005, + 0x00000004, 0x6e69616d, 0x00000000, 0x00030005, + 0x00000009, 0x00006469, 0x00080005, 0x0000000c, + 0x475f6c67, 0x61626f6c, 0x766e496c, 0x7461636f, + 0x496e6f69, 0x00000044, 0x00060005, 0x00000016, + 0x68737550, 0x736e6f43, 0x746e6174, 0x00000073, + 0x00050006, 0x00000016, 0x00000000, 0x74646977, + 0x00000068, 0x00050006, 0x00000016, 0x00000001, + 0x67696568, 0x00007468, 0x00050006, 0x00000016, + 0x00000002, 0x6f6c6f63, 0x00000072, 0x00030005, + 0x00000018, 0x00006370, 0x00040005, 0x0000002d, + 0x65646e69, 0x00000078, 0x00060005, 0x00000037, + 0x7074754f, 0x75427475, 0x72656666, 0x00000000, + 0x00050006, 0x00000037, 0x00000000, 0x65786970, + 0x0000736c, 0x00050005, 0x00000039, 0x4274756f, + 0x65666675, 0x00000072, 0x00040047, 0x0000000c, + 0x0000000b, 0x0000001c, 0x00030047, 0x00000016, + 0x00000002, 0x00050048, 0x00000016, 0x00000000, + 0x00000023, 0x00000000, 0x00050048, 0x00000016, + 0x00000001, 0x00000023, 0x00000004, 0x00050048, + 0x00000016, 0x00000002, 0x00000023, 0x00000010, + 0x00040047, 0x00000036, 0x00000006, 0x00000010, + 0x00030047, 0x00000037, 0x00000003, 0x00050048, + 0x00000037, 0x00000000, 0x00000023, 0x00000000, + 0x00040047, 0x00000039, 0x00000021, 0x00000000, + 0x00040047, 0x00000039, 0x00000022, 0x00000000, + 0x00040047, 0x00000042, 0x0000000b, 0x00000019, + 0x00020013, 0x00000002, 0x00030021, 0x00000003, + 0x00000002, 0x00040015, 0x00000006, 0x00000020, + 0x00000000, 0x00040017, 0x00000007, 0x00000006, + 0x00000002, 0x00040020, 0x00000008, 0x00000007, + 0x00000007, 0x00040017, 0x0000000a, 0x00000006, + 0x00000003, 0x00040020, 0x0000000b, 0x00000001, + 0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c, + 0x00000001, 0x00020014, 0x0000000f, 0x0004002b, + 0x00000006, 0x00000010, 0x00000000, 0x00040020, + 0x00000011, 0x00000007, 0x00000006, 0x00030016, + 0x00000014, 0x00000020, 0x00040017, 0x00000015, + 0x00000014, 0x00000004, 0x0005001e, 0x00000016, + 0x00000006, 0x00000006, 0x00000015, 0x00040020, + 0x00000017, 0x00000009, 0x00000016, 0x0004003b, + 0x00000017, 0x00000018, 0x00000009, 0x00040015, + 0x00000019, 0x00000020, 0x00000001, 0x0004002b, + 0x00000019, 0x0000001a, 0x00000000, 0x00040020, + 0x0000001b, 0x00000009, 0x00000006, 0x0004002b, + 0x00000006, 0x00000022, 0x00000001, 0x0004002b, + 0x00000019, 0x00000025, 0x00000001, 0x0003001d, + 0x00000036, 0x00000015, 0x0003001e, 0x00000037, + 0x00000036, 0x00040020, 0x00000038, 0x00000002, + 0x00000037, 0x0004003b, 0x00000038, 0x00000039, + 0x00000002, 0x0004002b, 0x00000019, 0x0000003b, + 0x00000002, 0x00040020, 0x0000003c, 0x00000009, + 0x00000015, 0x00040020, 0x0000003f, 0x00000002, + 0x00000015, 0x0004002b, 0x00000006, 0x00000041, + 0x00000010, 0x0006002c, 0x0000000a, 0x00000042, + 0x00000041, 0x00000041, 0x00000022, 0x00050036, + 0x00000002, 0x00000004, 0x00000000, 0x00000003, + 0x000200f8, 0x00000005, 0x0004003b, 0x00000008, + 0x00000009, 0x00000007, 0x0004003b, 0x00000011, + 0x0000002d, 0x00000007, 0x0004003d, 0x0000000a, + 0x0000000d, 0x0000000c, 0x0007004f, 0x00000007, + 0x0000000e, 0x0000000d, 0x0000000d, 0x00000000, + 0x00000001, 0x0003003e, 0x00000009, 0x0000000e, + 0x00050041, 0x00000011, 0x00000012, 0x00000009, + 0x00000010, 0x0004003d, 0x00000006, 0x00000013, + 0x00000012, 0x00050041, 0x0000001b, 0x0000001c, + 0x00000018, 0x0000001a, 0x0004003d, 0x00000006, + 0x0000001d, 0x0000001c, 0x000500ae, 0x0000000f, + 0x0000001e, 0x00000013, 0x0000001d, 0x000400a8, + 0x0000000f, 0x0000001f, 0x0000001e, 0x000300f7, + 0x00000021, 0x00000000, 0x000400fa, 0x0000001f, + 0x00000020, 0x00000021, 0x000200f8, 0x00000020, + 0x00050041, 0x00000011, 0x00000023, 0x00000009, + 0x00000022, 0x0004003d, 0x00000006, 0x00000024, + 0x00000023, 0x00050041, 0x0000001b, 0x00000026, + 0x00000018, 0x00000025, 0x0004003d, 0x00000006, + 0x00000027, 0x00000026, 0x000500ae, 0x0000000f, + 0x00000028, 0x00000024, 0x00000027, 0x000200f9, + 0x00000021, 0x000200f8, 0x00000021, 0x000700f5, + 0x0000000f, 0x00000029, 0x0000001e, 0x00000005, + 0x00000028, 0x00000020, 0x000300f7, 0x0000002b, + 0x00000000, 0x000400fa, 0x00000029, 0x0000002a, + 0x0000002b, 0x000200f8, 0x0000002a, 0x000100fd, + 0x000200f8, 0x0000002b, 0x00050041, 0x00000011, + 0x0000002e, 0x00000009, 0x00000022, 0x0004003d, + 0x00000006, 0x0000002f, 0x0000002e, 0x00050041, + 0x0000001b, 0x00000030, 0x00000018, 0x0000001a, + 0x0004003d, 0x00000006, 0x00000031, 0x00000030, + 0x00050084, 0x00000006, 0x00000032, 0x0000002f, + 0x00000031, 0x00050041, 0x00000011, 0x00000033, + 0x00000009, 0x00000010, 0x0004003d, 0x00000006, + 0x00000034, 0x00000033, 0x00050080, 0x00000006, + 0x00000035, 0x00000032, 0x00000034, 0x0003003e, + 0x0000002d, 0x00000035, 0x0004003d, 0x00000006, + 0x0000003a, 0x0000002d, 0x00050041, 0x0000003c, + 0x0000003d, 0x00000018, 0x0000003b, 0x0004003d, + 0x00000015, 0x0000003e, 0x0000003d, 0x00060041, + 0x0000003f, 0x00000040, 0x00000039, 0x0000001a, + 0x0000003a, 0x0003003e, 0x00000040, 0x0000003e, + 0x000100fd, 0x00010038 +}; + +static const uint8_t s_ComputeShaderDxil[] = { + 0x44, 0x58, 0x42, 0x43, 0x3c, 0x03, 0x02, 0xb3, 0x0e, 0x59, 0xfb, 0x9b, + 0xc1, 0xd2, 0x75, 0x12, 0xb3, 0x0d, 0x3c, 0xd0, 0x01, 0x00, 0x00, 0x00, + 0x58, 0x0d, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0xf4, 0x00, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00, 0x4c, 0x07, 0x00, 0x00, + 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x50, 0x53, 0x56, 0x30, 0x80, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0x34, 0x06, 0x00, 0x00, + 0x60, 0x00, 0x05, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, + 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x01, 0xd5, 0x06, 0x62, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x90, 0x00, 0x49, 0x18, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, + 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, + 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x74, 0x23, 0x00, 0x25, 0x00, 0x14, 0xe6, + 0x08, 0xc0, 0xa0, 0x0c, 0x63, 0x0c, 0x22, 0x33, 0x00, 0x47, 0x0d, 0x97, + 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0xdc, 0x46, 0x15, 0x2b, 0x31, 0xf9, 0xc5, + 0x6d, 0x23, 0xc2, 0x18, 0x63, 0xe6, 0x08, 0x10, 0x42, 0xf7, 0x0c, 0x97, + 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, 0x0c, 0x0b, 0x81, 0x82, 0x54, + 0x88, 0x33, 0xd4, 0xa0, 0x75, 0xd4, 0x70, 0xf9, 0x13, 0xf6, 0x10, 0x92, + 0xcf, 0x6d, 0x54, 0xb1, 0x12, 0x93, 0x8f, 0xdc, 0x36, 0x22, 0xc6, 0x18, + 0xa3, 0x10, 0x6d, 0xa8, 0x41, 0x6e, 0x8e, 0x20, 0x28, 0x86, 0x1a, 0x68, + 0x0c, 0x48, 0xb1, 0x28, 0x60, 0xa8, 0x31, 0xc6, 0x18, 0x03, 0xd1, 0x1c, + 0x08, 0x38, 0x4d, 0x9a, 0x22, 0x4a, 0x98, 0xfc, 0x15, 0xde, 0xb0, 0x89, + 0xd0, 0x86, 0x21, 0x22, 0x24, 0x69, 0xa3, 0x8a, 0x82, 0x88, 0x50, 0x30, + 0xc8, 0x0e, 0x23, 0x10, 0xc6, 0x51, 0xd2, 0x14, 0x51, 0xc2, 0xe4, 0xa7, + 0x94, 0x74, 0x70, 0x4e, 0x23, 0x4d, 0x40, 0x33, 0x49, 0x68, 0x18, 0x03, + 0x9f, 0xf0, 0x08, 0x28, 0xc8, 0xa4, 0xe7, 0x08, 0x40, 0x01, 0x00, 0x00, + 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, + 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, + 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, + 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, + 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, + 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, + 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x04, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, + 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, + 0x89, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, + 0xc8, 0x33, 0x01, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x16, 0x08, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, + 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, + 0x25, 0x30, 0x02, 0x50, 0x0c, 0x65, 0x51, 0x40, 0x65, 0x50, 0x0e, 0xa5, + 0x50, 0x08, 0x05, 0x52, 0x12, 0xa5, 0x51, 0x34, 0x45, 0x40, 0x70, 0x04, + 0x80, 0x78, 0x81, 0x50, 0x9e, 0x01, 0x20, 0x3d, 0x03, 0x40, 0x7b, 0x06, + 0x80, 0xee, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, + 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, + 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb1, 0xa9, 0x81, + 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, 0xcb, 0x09, 0x83, 0x49, + 0xd9, 0x10, 0x04, 0x13, 0x84, 0xc1, 0x98, 0x20, 0x0c, 0xc7, 0x06, 0x61, + 0x20, 0x36, 0x08, 0x04, 0x41, 0x61, 0x6c, 0x6e, 0x82, 0x30, 0x20, 0x1b, + 0x86, 0x03, 0x21, 0x26, 0x08, 0x57, 0xc6, 0xe4, 0xad, 0x8e, 0x4e, 0xa8, + 0xce, 0xcc, 0xac, 0x4c, 0x6e, 0x82, 0x30, 0x24, 0x13, 0x04, 0x88, 0xda, + 0xb0, 0x10, 0xca, 0x42, 0x10, 0x03, 0xd3, 0x34, 0x0d, 0xb0, 0x21, 0x70, + 0x26, 0x08, 0x1b, 0x46, 0x01, 0x6e, 0x6c, 0x82, 0x30, 0x28, 0x1b, 0x10, + 0x02, 0x8a, 0x08, 0x62, 0x90, 0x80, 0x0d, 0xc1, 0xb4, 0x81, 0x00, 0x1e, + 0x0a, 0x98, 0x20, 0x64, 0x16, 0x8b, 0xbb, 0x34, 0x32, 0x3a, 0xb4, 0x09, + 0xc2, 0xb0, 0x4c, 0x10, 0x06, 0x66, 0x82, 0x30, 0x34, 0x1b, 0x0c, 0xe4, + 0xc2, 0x88, 0x4c, 0xa3, 0x81, 0x56, 0x96, 0x76, 0x86, 0x46, 0x37, 0x41, + 0x18, 0x9c, 0x0d, 0x06, 0xc2, 0x61, 0x5d, 0xa6, 0xb1, 0x18, 0x7b, 0x63, + 0x7b, 0x93, 0x9b, 0x20, 0x0c, 0xcf, 0x04, 0x61, 0x80, 0x26, 0x08, 0x43, + 0xb4, 0x01, 0x41, 0x3e, 0x0c, 0x0c, 0xb2, 0x30, 0x10, 0x83, 0x6e, 0x03, + 0x21, 0x6d, 0xde, 0x18, 0x4c, 0x10, 0xb4, 0x6b, 0x03, 0x81, 0x44, 0x18, + 0xb1, 0x41, 0x90, 0xcc, 0x60, 0x43, 0x41, 0x58, 0x64, 0x50, 0x06, 0x67, + 0x30, 0x41, 0x10, 0x80, 0x0d, 0xc0, 0x86, 0x81, 0x50, 0x03, 0x35, 0xd8, + 0x10, 0xac, 0xc1, 0x86, 0x61, 0x48, 0x03, 0x36, 0x20, 0xd1, 0x16, 0x96, + 0xe6, 0x36, 0x41, 0xe0, 0xaa, 0x0d, 0x03, 0x18, 0x80, 0xc1, 0xb0, 0x81, + 0x20, 0xde, 0xa0, 0x83, 0x83, 0x0d, 0x45, 0x1a, 0xb8, 0x01, 0x50, 0xc5, + 0x01, 0x11, 0x31, 0xb9, 0x30, 0xb7, 0x31, 0xb4, 0xb2, 0x39, 0x16, 0x69, + 0x6e, 0x73, 0x74, 0x73, 0x13, 0x84, 0x41, 0x22, 0x91, 0xe6, 0x46, 0x37, + 0xc7, 0x84, 0xae, 0x0c, 0xef, 0x6b, 0x8e, 0xee, 0x4d, 0xae, 0x8c, 0x45, + 0x5d, 0x9a, 0x1b, 0xdd, 0xdc, 0x04, 0x61, 0x98, 0x36, 0x28, 0x73, 0x30, + 0xd0, 0x41, 0x1d, 0xd8, 0x41, 0x77, 0x07, 0x03, 0x1e, 0xe4, 0x41, 0x15, + 0x36, 0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37, 0xba, 0x29, 0x41, + 0x50, 0x85, 0x0c, 0xcf, 0xc5, 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, 0x6d, + 0x4a, 0x40, 0x34, 0x21, 0xc3, 0x73, 0xb1, 0x0b, 0x63, 0xb3, 0x2b, 0x93, + 0x9b, 0x12, 0x14, 0x75, 0xc8, 0xf0, 0x5c, 0xe6, 0xd0, 0xc2, 0xc8, 0xca, + 0xe4, 0x9a, 0xde, 0xc8, 0xca, 0xd8, 0xa6, 0x04, 0x48, 0x19, 0x32, 0x3c, + 0x17, 0xb9, 0xb2, 0xb9, 0xb7, 0x3a, 0xb9, 0xb1, 0xb2, 0xb9, 0x29, 0x01, + 0x55, 0x89, 0x0c, 0xcf, 0x85, 0x2e, 0x0f, 0xae, 0x2c, 0xc8, 0xcd, 0xed, + 0x8d, 0x2e, 0x8c, 0x2e, 0xed, 0xcd, 0x6d, 0x6e, 0x8a, 0x70, 0x06, 0x6c, + 0x50, 0x87, 0x0c, 0xcf, 0xa5, 0xcc, 0x8d, 0x4e, 0x2e, 0x0f, 0xea, 0x2d, + 0xcd, 0x8d, 0x6e, 0x6e, 0x4a, 0x10, 0x07, 0x5d, 0xc8, 0xf0, 0x5c, 0xc6, + 0xde, 0xea, 0xdc, 0xe8, 0xca, 0xe4, 0xe6, 0xa6, 0x04, 0x79, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, + 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, + 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, + 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, + 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, + 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, + 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, + 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, + 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, + 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, + 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, + 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, + 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, + 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, + 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, + 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, + 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, + 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, + 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, + 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, + 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, + 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, + 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, + 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, + 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, + 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x30, 0x83, 0x81, + 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, 0x1c, 0xc2, 0x61, 0x1d, + 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x56, 0x50, 0x0d, 0x97, 0xef, 0x3c, 0x7e, 0x40, + 0x15, 0x05, 0x11, 0xb1, 0x93, 0x13, 0x11, 0x3e, 0x72, 0xdb, 0x26, 0xb0, + 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, + 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x03, 0xdb, 0x70, + 0xf9, 0xce, 0xe3, 0x0b, 0x01, 0x55, 0x14, 0x44, 0x54, 0x3a, 0xc0, 0x50, + 0x12, 0x06, 0x20, 0x60, 0x3e, 0x72, 0xdb, 0x46, 0x20, 0x0d, 0x97, 0xef, + 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, 0x33, 0x2c, 0x84, 0x05, + 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x1d, 0x11, 0x01, 0x0c, 0xe2, 0xe0, + 0x23, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6f, 0xb0, 0x69, 0x56, 0x40, 0x84, 0x26, 0xed, + 0x85, 0x8e, 0xc5, 0x2c, 0x46, 0xd0, 0xbf, 0x12, 0x44, 0x58, 0x49, 0x4c, + 0x04, 0x06, 0x00, 0x00, 0x60, 0x00, 0x05, 0x00, 0x81, 0x01, 0x00, 0x00, + 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xec, 0x05, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, + 0x78, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, + 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, + 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, + 0xa4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, + 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, + 0xe4, 0x48, 0x0e, 0x90, 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, + 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, + 0x40, 0x02, 0xa8, 0x0d, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, + 0x01, 0xd5, 0x06, 0x62, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x90, 0x00, + 0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, + 0x20, 0x4c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, + 0x31, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, + 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, + 0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x78, 0x23, 0x00, + 0x25, 0x00, 0x14, 0xe6, 0x08, 0xc0, 0xa0, 0x0c, 0x63, 0x0c, 0x22, 0x33, + 0x00, 0x47, 0x0d, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0xdc, 0x46, 0x15, + 0x2b, 0x31, 0xf9, 0xc5, 0x6d, 0x23, 0xc2, 0x18, 0x63, 0xe6, 0x08, 0x10, + 0x42, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, 0x0c, + 0x0b, 0x81, 0x82, 0x54, 0x88, 0x33, 0xd4, 0xa0, 0x75, 0xd4, 0x70, 0xf9, + 0x13, 0xf6, 0x10, 0x92, 0xcf, 0x6d, 0x54, 0xb1, 0x12, 0x93, 0x8f, 0xdc, + 0x36, 0x22, 0xc6, 0x18, 0xa3, 0x10, 0x6d, 0xa8, 0x41, 0x6e, 0x8e, 0x20, + 0x28, 0x86, 0x1a, 0x68, 0x0c, 0x48, 0xb1, 0x28, 0x60, 0xa8, 0x31, 0xc6, + 0x18, 0x03, 0xd1, 0x1c, 0x08, 0x38, 0x4d, 0x9a, 0x22, 0x4a, 0x98, 0xfc, + 0x15, 0xde, 0xb0, 0x89, 0xd0, 0x86, 0x21, 0x22, 0x24, 0x69, 0xa3, 0x8a, + 0x82, 0x88, 0x50, 0x30, 0xc8, 0x0e, 0x23, 0x10, 0xc6, 0x51, 0xd2, 0x14, + 0x51, 0xc2, 0xe4, 0xa7, 0x94, 0x74, 0x70, 0x4e, 0x23, 0x4d, 0x40, 0x33, + 0x49, 0x68, 0x18, 0x03, 0x9f, 0xf0, 0x08, 0x28, 0xc8, 0xa4, 0xe7, 0x08, + 0x40, 0x61, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, + 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, + 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, + 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, + 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, + 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, + 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, + 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, + 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, + 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, + 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x86, 0x3c, 0x04, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x89, 0x80, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc8, 0x33, 0x01, 0x01, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x16, 0x08, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, + 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, 0x25, 0x30, 0x02, 0x50, + 0x12, 0xc5, 0x50, 0x16, 0x05, 0x54, 0x08, 0x05, 0x42, 0x70, 0x04, 0x80, + 0x78, 0x81, 0xd0, 0x9e, 0x01, 0xa0, 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, + 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, + 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, + 0xa1, 0xb1, 0xa9, 0x81, 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, + 0xcb, 0x09, 0x83, 0x49, 0xd9, 0x10, 0x04, 0x13, 0x84, 0xc1, 0x98, 0x20, + 0x0c, 0xc7, 0x06, 0x61, 0x20, 0x26, 0x08, 0x03, 0xb2, 0x41, 0x18, 0x0c, + 0x0a, 0x63, 0x73, 0x13, 0x84, 0x21, 0xd9, 0x30, 0x20, 0x09, 0x31, 0x41, + 0xb8, 0x22, 0x02, 0x13, 0x84, 0x41, 0x99, 0x20, 0x40, 0xce, 0x86, 0x85, + 0x58, 0x18, 0x82, 0x18, 0x1a, 0xc7, 0x71, 0x80, 0x0d, 0xc1, 0x33, 0x41, + 0xd8, 0xa0, 0x09, 0xc2, 0xb0, 0x6c, 0x40, 0x88, 0x88, 0x21, 0x88, 0x41, + 0x02, 0x36, 0x04, 0xd3, 0x06, 0x02, 0x80, 0x28, 0x60, 0x82, 0x20, 0x00, + 0x24, 0xda, 0xc2, 0xd2, 0xdc, 0x26, 0x08, 0xdc, 0x33, 0x41, 0x18, 0x98, + 0x09, 0xc2, 0xd0, 0x6c, 0x18, 0x34, 0x6d, 0xd8, 0x40, 0x10, 0x58, 0xb6, + 0x6d, 0x28, 0xac, 0x0b, 0xa8, 0xb8, 0x2a, 0x6c, 0x6c, 0x76, 0x6d, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, 0x9e, 0x8b, + 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, 0x42, 0x86, + 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26, 0x37, 0x25, 0x30, 0xea, 0x90, + 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, 0x91, 0x95, + 0xb1, 0x4d, 0x09, 0x92, 0x32, 0x64, 0x78, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x53, 0x02, 0xaa, 0x0e, 0x19, 0x9e, 0x4b, + 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, + 0x80, 0x03, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, + 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, + 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, + 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, + 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, + 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, + 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, + 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, + 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, + 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, + 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, + 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, + 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, + 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, + 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, + 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, + 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, + 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, + 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, + 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, + 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, + 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, + 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, + 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, + 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, + 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, + 0xf4, 0x30, 0x83, 0x81, 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, + 0x1c, 0xc2, 0x61, 0x1d, 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, + 0x71, 0x20, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x56, 0x50, 0x0d, 0x97, + 0xef, 0x3c, 0x7e, 0x40, 0x15, 0x05, 0x11, 0xb1, 0x93, 0x13, 0x11, 0x3e, + 0x72, 0xdb, 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, + 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, + 0x6d, 0x03, 0xdb, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x01, 0x55, 0x14, 0x44, + 0x54, 0x3a, 0xc0, 0x50, 0x12, 0x06, 0x20, 0x60, 0x3e, 0x72, 0xdb, 0x46, + 0x20, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, + 0x33, 0x2c, 0x84, 0x05, 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x1d, 0x11, + 0x01, 0x0c, 0xe2, 0xe0, 0x23, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, + 0x13, 0x04, 0x43, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x34, 0x4a, 0xae, 0x74, 0x03, 0xca, 0xae, 0x14, 0x03, 0x66, 0x00, 0x08, + 0x95, 0x40, 0x11, 0x94, 0x07, 0x00, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, + 0x82, 0x60, 0x10, 0x59, 0xc8, 0x30, 0x4d, 0xcc, 0x88, 0x41, 0x02, 0x80, + 0x20, 0x18, 0x44, 0x57, 0x32, 0x50, 0x54, 0x33, 0x62, 0x60, 0x00, 0x20, + 0x08, 0x06, 0xc4, 0x96, 0x54, 0x23, 0x06, 0x06, 0x00, 0x82, 0x60, 0x40, + 0x70, 0xca, 0x35, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0xa6, 0x0c, + 0xd7, 0x68, 0x42, 0x00, 0x0c, 0x37, 0x10, 0x01, 0x19, 0x8c, 0x26, 0x0c, + 0xc1, 0x70, 0x43, 0x11, 0x90, 0x41, 0x0d, 0x81, 0xce, 0x32, 0x04, 0x42, + 0x50, 0xc5, 0x21, 0x15, 0x24, 0x50, 0x81, 0x76, 0x23, 0x06, 0x07, 0x00, + 0x82, 0x60, 0xb0, 0x94, 0xc1, 0xc4, 0x84, 0xc1, 0x68, 0x42, 0x00, 0x8c, + 0x26, 0x08, 0xc1, 0x68, 0xc2, 0x20, 0x8c, 0x26, 0x10, 0xc3, 0x11, 0x63, + 0x8f, 0x18, 0x7b, 0xc4, 0xd8, 0x23, 0xc6, 0x8e, 0x18, 0x34, 0x00, 0x08, + 0x82, 0xc1, 0xb4, 0x06, 0x9b, 0xa5, 0x68, 0xc4, 0x20, 0x04, 0xd7, 0x2c, + 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// ================================================== +// Ray Tracing +// ================================================== + +// GLSL +// Raygen +// #version 460 +// #extension GL_EXT_ray_tracing : require + +// layout(set = 0, binding = 0) buffer OutputBuffer +// { +// vec4 pixels[]; +// } outBuffer; + +// layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; +// layout(location = 0) rayPayloadEXT vec3 payloadColor; + +// void main() +// { +// uvec2 pixel = gl_LaunchIDEXT.xy; +// uvec2 size = gl_LaunchSizeEXT.xy; +// payloadColor = vec3(0.0); + +// vec2 uv = (vec2(pixel) + 0.5) / vec2(size); +// vec2 ndcUv = uv * 2.0 - 1.0; +// vec3 origin = vec3(0.0, 0.0, -3.0); +// vec3 direction = normalize(vec3(ndcUv.x, ndcUv.y, 1.0)); + +// traceRayEXT( +// tlas, +// gl_RayFlagsOpaqueEXT, +// 0xFF, +// 0, +// 0, +// 0, +// origin, +// 0.001, +// direction, +// 1000.0, +// 0 +// ); + +// if (pixel.x >= size.x || pixel.y >= size.y) { +// return; +// } + +// uint index = pixel.y * size.x + pixel.x; +// outBuffer.pixels[index] = vec4(payloadColor, 1.0); +// } + +// Closest Hit +// #version 460 +// #extension GL_EXT_ray_tracing : require + +// layout(location = 0) rayPayloadInEXT vec3 payloadColor; + +// void main() +// { +// payloadColor = vec3(0.0, 1.0, 0.0); +// } + +// Miss +// #version 460 +// #extension GL_EXT_ray_tracing : require + +// layout(location = 0) rayPayloadInEXT vec3 payloadColor; + +// void main() +// { +// payloadColor = vec3(0.0); +// } + +// HLSL + +static const Uint32 s_RaygenShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x0000006d, + 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, + 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, + 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, + 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, + 0x00000000, 0x00000001, 0x000a000f, 0x000014c1, + 0x00000004, 0x6e69616d, 0x00000000, 0x0000000c, + 0x00000010, 0x00000016, 0x0000003b, 0x00000064, + 0x00030003, 0x00000002, 0x000001cc, 0x00060004, + 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, + 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, + 0x00000000, 0x00040005, 0x00000009, 0x65786970, + 0x0000006c, 0x00060005, 0x0000000c, 0x4c5f6c67, + 0x636e7561, 0x45444968, 0x00005458, 0x00040005, + 0x0000000f, 0x657a6973, 0x00000000, 0x00070005, + 0x00000010, 0x4c5f6c67, 0x636e7561, 0x7a695368, + 0x54584565, 0x00000000, 0x00060005, 0x00000016, + 0x6c796170, 0x4364616f, 0x726f6c6f, 0x00000000, + 0x00030005, 0x0000001b, 0x00007675, 0x00040005, + 0x00000024, 0x5563646e, 0x00000076, 0x00040005, + 0x0000002c, 0x6769726f, 0x00006e69, 0x00050005, + 0x0000002f, 0x65726964, 0x6f697463, 0x0000006e, + 0x00040005, 0x0000003b, 0x73616c74, 0x00000000, + 0x00040005, 0x00000057, 0x65646e69, 0x00000078, + 0x00060005, 0x00000062, 0x7074754f, 0x75427475, + 0x72656666, 0x00000000, 0x00050006, 0x00000062, + 0x00000000, 0x65786970, 0x0000736c, 0x00050005, + 0x00000064, 0x4274756f, 0x65666675, 0x00000072, + 0x00040047, 0x0000000c, 0x0000000b, 0x000014c7, + 0x00040047, 0x00000010, 0x0000000b, 0x000014c8, + 0x00040047, 0x0000003b, 0x00000021, 0x00000001, + 0x00040047, 0x0000003b, 0x00000022, 0x00000000, + 0x00040047, 0x00000061, 0x00000006, 0x00000010, + 0x00030047, 0x00000062, 0x00000002, 0x00050048, + 0x00000062, 0x00000000, 0x00000023, 0x00000000, + 0x00040047, 0x00000064, 0x00000021, 0x00000000, + 0x00040047, 0x00000064, 0x00000022, 0x00000000, + 0x00020013, 0x00000002, 0x00030021, 0x00000003, + 0x00000002, 0x00040015, 0x00000006, 0x00000020, + 0x00000000, 0x00040017, 0x00000007, 0x00000006, + 0x00000002, 0x00040020, 0x00000008, 0x00000007, + 0x00000007, 0x00040017, 0x0000000a, 0x00000006, + 0x00000003, 0x00040020, 0x0000000b, 0x00000001, + 0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c, + 0x00000001, 0x0004003b, 0x0000000b, 0x00000010, + 0x00000001, 0x00030016, 0x00000013, 0x00000020, + 0x00040017, 0x00000014, 0x00000013, 0x00000003, + 0x00040020, 0x00000015, 0x000014da, 0x00000014, + 0x0004003b, 0x00000015, 0x00000016, 0x000014da, + 0x0004002b, 0x00000013, 0x00000017, 0x00000000, + 0x0006002c, 0x00000014, 0x00000018, 0x00000017, + 0x00000017, 0x00000017, 0x00040017, 0x00000019, + 0x00000013, 0x00000002, 0x00040020, 0x0000001a, + 0x00000007, 0x00000019, 0x0004002b, 0x00000013, + 0x0000001e, 0x3f000000, 0x0004002b, 0x00000013, + 0x00000026, 0x40000000, 0x0004002b, 0x00000013, + 0x00000028, 0x3f800000, 0x00040020, 0x0000002b, + 0x00000007, 0x00000014, 0x0004002b, 0x00000013, + 0x0000002d, 0xc0400000, 0x0006002c, 0x00000014, + 0x0000002e, 0x00000017, 0x00000017, 0x0000002d, + 0x0004002b, 0x00000006, 0x00000030, 0x00000000, + 0x00040020, 0x00000031, 0x00000007, 0x00000013, + 0x0004002b, 0x00000006, 0x00000034, 0x00000001, + 0x000214dd, 0x00000039, 0x00040020, 0x0000003a, + 0x00000000, 0x00000039, 0x0004003b, 0x0000003a, + 0x0000003b, 0x00000000, 0x0004002b, 0x00000006, + 0x0000003d, 0x000000ff, 0x0004002b, 0x00000013, + 0x0000003f, 0x3a83126f, 0x0004002b, 0x00000013, + 0x00000041, 0x447a0000, 0x00040015, 0x00000042, + 0x00000020, 0x00000001, 0x0004002b, 0x00000042, + 0x00000043, 0x00000000, 0x00020014, 0x00000044, + 0x00040020, 0x00000045, 0x00000007, 0x00000006, + 0x00040017, 0x00000060, 0x00000013, 0x00000004, + 0x0003001d, 0x00000061, 0x00000060, 0x0003001e, + 0x00000062, 0x00000061, 0x00040020, 0x00000063, + 0x0000000c, 0x00000062, 0x0004003b, 0x00000063, + 0x00000064, 0x0000000c, 0x00040020, 0x0000006b, + 0x0000000c, 0x00000060, 0x00050036, 0x00000002, + 0x00000004, 0x00000000, 0x00000003, 0x000200f8, + 0x00000005, 0x0004003b, 0x00000008, 0x00000009, + 0x00000007, 0x0004003b, 0x00000008, 0x0000000f, + 0x00000007, 0x0004003b, 0x0000001a, 0x0000001b, + 0x00000007, 0x0004003b, 0x0000001a, 0x00000024, + 0x00000007, 0x0004003b, 0x0000002b, 0x0000002c, + 0x00000007, 0x0004003b, 0x0000002b, 0x0000002f, + 0x00000007, 0x0004003b, 0x00000045, 0x00000057, + 0x00000007, 0x0004003d, 0x0000000a, 0x0000000d, + 0x0000000c, 0x0007004f, 0x00000007, 0x0000000e, + 0x0000000d, 0x0000000d, 0x00000000, 0x00000001, + 0x0003003e, 0x00000009, 0x0000000e, 0x0004003d, + 0x0000000a, 0x00000011, 0x00000010, 0x0007004f, + 0x00000007, 0x00000012, 0x00000011, 0x00000011, + 0x00000000, 0x00000001, 0x0003003e, 0x0000000f, + 0x00000012, 0x0003003e, 0x00000016, 0x00000018, + 0x0004003d, 0x00000007, 0x0000001c, 0x00000009, + 0x00040070, 0x00000019, 0x0000001d, 0x0000001c, + 0x00050050, 0x00000019, 0x0000001f, 0x0000001e, + 0x0000001e, 0x00050081, 0x00000019, 0x00000020, + 0x0000001d, 0x0000001f, 0x0004003d, 0x00000007, + 0x00000021, 0x0000000f, 0x00040070, 0x00000019, + 0x00000022, 0x00000021, 0x00050088, 0x00000019, + 0x00000023, 0x00000020, 0x00000022, 0x0003003e, + 0x0000001b, 0x00000023, 0x0004003d, 0x00000019, + 0x00000025, 0x0000001b, 0x0005008e, 0x00000019, + 0x00000027, 0x00000025, 0x00000026, 0x00050050, + 0x00000019, 0x00000029, 0x00000028, 0x00000028, + 0x00050083, 0x00000019, 0x0000002a, 0x00000027, + 0x00000029, 0x0003003e, 0x00000024, 0x0000002a, + 0x0003003e, 0x0000002c, 0x0000002e, 0x00050041, + 0x00000031, 0x00000032, 0x00000024, 0x00000030, + 0x0004003d, 0x00000013, 0x00000033, 0x00000032, + 0x00050041, 0x00000031, 0x00000035, 0x00000024, + 0x00000034, 0x0004003d, 0x00000013, 0x00000036, + 0x00000035, 0x00060050, 0x00000014, 0x00000037, + 0x00000033, 0x00000036, 0x00000028, 0x0006000c, + 0x00000014, 0x00000038, 0x00000001, 0x00000045, + 0x00000037, 0x0003003e, 0x0000002f, 0x00000038, + 0x0004003d, 0x00000039, 0x0000003c, 0x0000003b, + 0x0004003d, 0x00000014, 0x0000003e, 0x0000002c, + 0x0004003d, 0x00000014, 0x00000040, 0x0000002f, + 0x000c115d, 0x0000003c, 0x00000034, 0x0000003d, + 0x00000030, 0x00000030, 0x00000030, 0x0000003e, + 0x0000003f, 0x00000040, 0x00000041, 0x00000016, + 0x00050041, 0x00000045, 0x00000046, 0x00000009, + 0x00000030, 0x0004003d, 0x00000006, 0x00000047, + 0x00000046, 0x00050041, 0x00000045, 0x00000048, + 0x0000000f, 0x00000030, 0x0004003d, 0x00000006, + 0x00000049, 0x00000048, 0x000500ae, 0x00000044, + 0x0000004a, 0x00000047, 0x00000049, 0x000400a8, + 0x00000044, 0x0000004b, 0x0000004a, 0x000300f7, + 0x0000004d, 0x00000000, 0x000400fa, 0x0000004b, + 0x0000004c, 0x0000004d, 0x000200f8, 0x0000004c, + 0x00050041, 0x00000045, 0x0000004e, 0x00000009, + 0x00000034, 0x0004003d, 0x00000006, 0x0000004f, + 0x0000004e, 0x00050041, 0x00000045, 0x00000050, + 0x0000000f, 0x00000034, 0x0004003d, 0x00000006, + 0x00000051, 0x00000050, 0x000500ae, 0x00000044, + 0x00000052, 0x0000004f, 0x00000051, 0x000200f9, + 0x0000004d, 0x000200f8, 0x0000004d, 0x000700f5, + 0x00000044, 0x00000053, 0x0000004a, 0x00000005, + 0x00000052, 0x0000004c, 0x000300f7, 0x00000055, + 0x00000000, 0x000400fa, 0x00000053, 0x00000054, + 0x00000055, 0x000200f8, 0x00000054, 0x000100fd, + 0x000200f8, 0x00000055, 0x00050041, 0x00000045, + 0x00000058, 0x00000009, 0x00000034, 0x0004003d, + 0x00000006, 0x00000059, 0x00000058, 0x00050041, + 0x00000045, 0x0000005a, 0x0000000f, 0x00000030, + 0x0004003d, 0x00000006, 0x0000005b, 0x0000005a, + 0x00050084, 0x00000006, 0x0000005c, 0x00000059, + 0x0000005b, 0x00050041, 0x00000045, 0x0000005d, + 0x00000009, 0x00000030, 0x0004003d, 0x00000006, + 0x0000005e, 0x0000005d, 0x00050080, 0x00000006, + 0x0000005f, 0x0000005c, 0x0000005e, 0x0003003e, + 0x00000057, 0x0000005f, 0x0004003d, 0x00000006, + 0x00000065, 0x00000057, 0x0004003d, 0x00000014, + 0x00000066, 0x00000016, 0x00050051, 0x00000013, + 0x00000067, 0x00000066, 0x00000000, 0x00050051, + 0x00000013, 0x00000068, 0x00000066, 0x00000001, + 0x00050051, 0x00000013, 0x00000069, 0x00000066, + 0x00000002, 0x00070050, 0x00000060, 0x0000006a, + 0x00000067, 0x00000068, 0x00000069, 0x00000028, + 0x00060041, 0x0000006b, 0x0000006c, 0x00000064, + 0x00000043, 0x00000065, 0x0003003e, 0x0000006c, + 0x0000006a, 0x000100fd, 0x00010038 +}; + +static const uint32_t s_ClosestHitShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x0000000d, + 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, + 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, + 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, + 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, + 0x00000000, 0x00000001, 0x0006000f, 0x000014c4, + 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, + 0x00030003, 0x00000002, 0x000001cc, 0x00060004, + 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, + 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, + 0x00000000, 0x00060005, 0x00000009, 0x6c796170, + 0x4364616f, 0x726f6c6f, 0x00000000, 0x00020013, + 0x00000002, 0x00030021, 0x00000003, 0x00000002, + 0x00030016, 0x00000006, 0x00000020, 0x00040017, + 0x00000007, 0x00000006, 0x00000003, 0x00040020, + 0x00000008, 0x000014de, 0x00000007, 0x0004003b, + 0x00000008, 0x00000009, 0x000014de, 0x0004002b, + 0x00000006, 0x0000000a, 0x00000000, 0x0004002b, + 0x00000006, 0x0000000b, 0x3f800000, 0x0006002c, + 0x00000007, 0x0000000c, 0x0000000a, 0x0000000b, + 0x0000000a, 0x00050036, 0x00000002, 0x00000004, + 0x00000000, 0x00000003, 0x000200f8, 0x00000005, + 0x0003003e, 0x00000009, 0x0000000c, 0x000100fd, + 0x00010038 +}; + +static const uint32_t s_MissShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x0000000c, + 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, + 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, + 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, + 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, + 0x00000000, 0x00000001, 0x0006000f, 0x000014c5, + 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, + 0x00030003, 0x00000002, 0x000001cc, 0x00060004, + 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, + 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, + 0x00000000, 0x00060005, 0x00000009, 0x6c796170, + 0x4364616f, 0x726f6c6f, 0x00000000, 0x00020013, + 0x00000002, 0x00030021, 0x00000003, 0x00000002, + 0x00030016, 0x00000006, 0x00000020, 0x00040017, + 0x00000007, 0x00000006, 0x00000003, 0x00040020, + 0x00000008, 0x000014de, 0x00000007, 0x0004003b, + 0x00000008, 0x00000009, 0x000014de, 0x0004002b, + 0x00000006, 0x0000000a, 0x00000000, 0x0006002c, + 0x00000007, 0x0000000b, 0x0000000a, 0x0000000a, + 0x0000000a, 0x00050036, 0x00000002, 0x00000004, + 0x00000000, 0x00000003, 0x000200f8, 0x00000005, + 0x0003003e, 0x00000009, 0x0000000b, 0x000100fd, + 0x00010038 +}; + +// ================================================== +// Triangle +// ================================================== + +// GLSL +// Vertex +// #version 450 + +// layout(location = 0) in vec2 aPosition; +// layout(location = 1) in vec3 aColor; + +// layout(location = 0) out vec4 vColor; + +// void main() +// { +// gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); +// vColor = vec4(aColor, 1.0); +// } + +// Fragment +// #version 450 + +// layout(location = 0) in vec4 aColor; + +// layout(location = 0) out vec4 color; + +// void main() +// { +// color = aColor; +// } + +// HLSL +// Vertex +// struct VSInput +// { +// float2 pos : POSITION; +// float3 color : COLOR; +// }; + +// struct VSOutput +// { +// float4 pos : SV_POSITION; +// float4 color : COLOR; +// }; + +// VSOutput main(VSInput input) +// { +// VSOutput output; +// output.pos = float4(input.pos, 0.0, 1.0); +// output.color = float4(input.color, 1.0); +// return output; +// } + +// Fragment +// struct PSInput +// { +// float4 pos : SV_POSITION; +// float4 color : COLOR; +// }; + +// float4 main(PSInput input) : SV_Target +// { +// return input.color; +// } + +static const Uint32 s_TriangleVertShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x00000028, + 0x00000000, 0x00020011, 0x00000001, 0x0006000b, + 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, + 0x0009000f, 0x00000000, 0x00000004, 0x6e69616d, + 0x00000000, 0x0000000d, 0x00000012, 0x0000001f, + 0x00000022, 0x00030003, 0x00000002, 0x000001c2, + 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, + 0x00060005, 0x0000000b, 0x505f6c67, 0x65567265, + 0x78657472, 0x00000000, 0x00060006, 0x0000000b, + 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69, + 0x00070006, 0x0000000b, 0x00000001, 0x505f6c67, + 0x746e696f, 0x657a6953, 0x00000000, 0x00070006, + 0x0000000b, 0x00000002, 0x435f6c67, 0x4470696c, + 0x61747369, 0x0065636e, 0x00070006, 0x0000000b, + 0x00000003, 0x435f6c67, 0x446c6c75, 0x61747369, + 0x0065636e, 0x00030005, 0x0000000d, 0x00000000, + 0x00050005, 0x00000012, 0x736f5061, 0x6f697469, + 0x0000006e, 0x00040005, 0x0000001f, 0x6c6f4376, + 0x0000726f, 0x00040005, 0x00000022, 0x6c6f4361, + 0x0000726f, 0x00030047, 0x0000000b, 0x00000002, + 0x00050048, 0x0000000b, 0x00000000, 0x0000000b, + 0x00000000, 0x00050048, 0x0000000b, 0x00000001, + 0x0000000b, 0x00000001, 0x00050048, 0x0000000b, + 0x00000002, 0x0000000b, 0x00000003, 0x00050048, + 0x0000000b, 0x00000003, 0x0000000b, 0x00000004, + 0x00040047, 0x00000012, 0x0000001e, 0x00000000, + 0x00040047, 0x0000001f, 0x0000001e, 0x00000000, + 0x00040047, 0x00000022, 0x0000001e, 0x00000001, + 0x00020013, 0x00000002, 0x00030021, 0x00000003, + 0x00000002, 0x00030016, 0x00000006, 0x00000020, + 0x00040017, 0x00000007, 0x00000006, 0x00000004, + 0x00040015, 0x00000008, 0x00000020, 0x00000000, + 0x0004002b, 0x00000008, 0x00000009, 0x00000001, + 0x0004001c, 0x0000000a, 0x00000006, 0x00000009, + 0x0006001e, 0x0000000b, 0x00000007, 0x00000006, + 0x0000000a, 0x0000000a, 0x00040020, 0x0000000c, + 0x00000003, 0x0000000b, 0x0004003b, 0x0000000c, + 0x0000000d, 0x00000003, 0x00040015, 0x0000000e, + 0x00000020, 0x00000001, 0x0004002b, 0x0000000e, + 0x0000000f, 0x00000000, 0x00040017, 0x00000010, + 0x00000006, 0x00000002, 0x00040020, 0x00000011, + 0x00000001, 0x00000010, 0x0004003b, 0x00000011, + 0x00000012, 0x00000001, 0x0004002b, 0x00000008, + 0x00000013, 0x00000000, 0x00040020, 0x00000014, + 0x00000001, 0x00000006, 0x0004002b, 0x00000006, + 0x0000001a, 0x00000000, 0x0004002b, 0x00000006, + 0x0000001b, 0x3f800000, 0x00040020, 0x0000001d, + 0x00000003, 0x00000007, 0x0004003b, 0x0000001d, + 0x0000001f, 0x00000003, 0x00040017, 0x00000020, + 0x00000006, 0x00000003, 0x00040020, 0x00000021, + 0x00000001, 0x00000020, 0x0004003b, 0x00000021, + 0x00000022, 0x00000001, 0x00050036, 0x00000002, + 0x00000004, 0x00000000, 0x00000003, 0x000200f8, + 0x00000005, 0x00050041, 0x00000014, 0x00000015, + 0x00000012, 0x00000013, 0x0004003d, 0x00000006, + 0x00000016, 0x00000015, 0x00050041, 0x00000014, + 0x00000017, 0x00000012, 0x00000009, 0x0004003d, + 0x00000006, 0x00000018, 0x00000017, 0x0004007f, + 0x00000006, 0x00000019, 0x00000018, 0x00070050, + 0x00000007, 0x0000001c, 0x00000016, 0x00000019, + 0x0000001a, 0x0000001b, 0x00050041, 0x0000001d, + 0x0000001e, 0x0000000d, 0x0000000f, 0x0003003e, + 0x0000001e, 0x0000001c, 0x0004003d, 0x00000020, + 0x00000023, 0x00000022, 0x00050051, 0x00000006, + 0x00000024, 0x00000023, 0x00000000, 0x00050051, + 0x00000006, 0x00000025, 0x00000023, 0x00000001, + 0x00050051, 0x00000006, 0x00000026, 0x00000023, + 0x00000002, 0x00070050, 0x00000007, 0x00000027, + 0x00000024, 0x00000025, 0x00000026, 0x0000001b, + 0x0003003e, 0x0000001f, 0x00000027, 0x000100fd, + 0x00010038 +}; + +static const Uint32 s_TriangleFragShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x0000000d, + 0x00000000, 0x00020011, 0x00000001, 0x0006000b, + 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, + 0x0007000f, 0x00000004, 0x00000004, 0x6e69616d, + 0x00000000, 0x00000009, 0x0000000b, 0x00030010, + 0x00000004, 0x00000007, 0x00030003, 0x00000002, + 0x000001c2, 0x00040005, 0x00000004, 0x6e69616d, + 0x00000000, 0x00040005, 0x00000009, 0x6f6c6f63, + 0x00000072, 0x00040005, 0x0000000b, 0x6c6f4361, + 0x0000726f, 0x00040047, 0x00000009, 0x0000001e, + 0x00000000, 0x00040047, 0x0000000b, 0x0000001e, + 0x00000000, 0x00020013, 0x00000002, 0x00030021, + 0x00000003, 0x00000002, 0x00030016, 0x00000006, + 0x00000020, 0x00040017, 0x00000007, 0x00000006, + 0x00000004, 0x00040020, 0x00000008, 0x00000003, + 0x00000007, 0x0004003b, 0x00000008, 0x00000009, + 0x00000003, 0x00040020, 0x0000000a, 0x00000001, + 0x00000007, 0x0004003b, 0x0000000a, 0x0000000b, + 0x00000001, 0x00050036, 0x00000002, 0x00000004, + 0x00000000, 0x00000003, 0x000200f8, 0x00000005, + 0x0004003d, 0x00000007, 0x0000000c, 0x0000000b, + 0x0003003e, 0x00000009, 0x0000000c, 0x000100fd, + 0x00010038 +}; + +static const Uint32 s_TriangleVertShaderDxil[] = { + 0x44, 0x58, 0x42, 0x43, 0x43, 0xaa, 0x4b, 0xdf, 0x49, 0x8b, 0x4b, 0xbe, + 0xc3, 0x3a, 0x72, 0x00, 0x02, 0xed, 0x6c, 0x73, 0x01, 0x00, 0x00, 0x00, + 0x38, 0x0c, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, + 0xe0, 0x01, 0x00, 0x00, 0xcc, 0x06, 0x00, 0x00, 0xe8, 0x06, 0x00, 0x00, + 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x58, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x43, 0x4f, 0x4c, + 0x4f, 0x52, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x5c, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, + 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, + 0xc8, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4f, 0x53, + 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, + 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x42, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x43, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x44, 0x00, + 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x54, 0x41, 0x54, 0xe4, 0x04, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, + 0x39, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xcc, 0x04, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, + 0x21, 0x0c, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, + 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, + 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, + 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, + 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, + 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, + 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, + 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, + 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, + 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, + 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, + 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x19, 0x80, 0x39, 0x02, 0x30, + 0x98, 0x23, 0x40, 0x8a, 0x31, 0x44, 0x54, 0x44, 0x56, 0x0c, 0x20, 0xa2, + 0x1a, 0xc2, 0x81, 0x80, 0x4c, 0x20, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, + 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, + 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, + 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, + 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, + 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, + 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, + 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, + 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, + 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, + 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, 0x0d, 0x00, 0x00, 0x00, + 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, + 0xc6, 0x04, 0x43, 0xa2, 0x12, 0x18, 0x01, 0x28, 0x86, 0x32, 0x28, 0x87, + 0xf2, 0x28, 0x8e, 0x52, 0x28, 0x08, 0xaa, 0x92, 0x18, 0x01, 0x28, 0x82, + 0x32, 0x28, 0x04, 0xda, 0xb1, 0x92, 0x03, 0x09, 0x04, 0x00, 0x80, 0xc0, + 0x00, 0x14, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, + 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, + 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, + 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x88, 0x61, 0x82, 0x40, 0x10, + 0x1b, 0x84, 0x81, 0xd8, 0x20, 0x10, 0x04, 0x05, 0xbb, 0xb9, 0x09, 0x02, + 0x51, 0x6c, 0x18, 0x0e, 0x84, 0x98, 0x20, 0x08, 0xc0, 0x06, 0x60, 0xc3, + 0x40, 0x2c, 0xcb, 0x86, 0x80, 0xd9, 0x30, 0x0c, 0x4a, 0x33, 0x41, 0x58, + 0xa2, 0x0d, 0xc1, 0x43, 0xa2, 0x2d, 0x2c, 0xcd, 0x8d, 0x08, 0xd4, 0xd3, + 0x54, 0x12, 0x55, 0xd2, 0x93, 0xd3, 0x04, 0xa1, 0x60, 0x26, 0x08, 0x45, + 0xb3, 0x21, 0x20, 0x26, 0x08, 0x85, 0x33, 0x41, 0x20, 0x8c, 0x0d, 0xc2, + 0x75, 0x6d, 0x58, 0x08, 0x69, 0xa2, 0x2a, 0x6a, 0xb0, 0x08, 0x0a, 0x63, + 0x31, 0xf4, 0xc4, 0xf4, 0x24, 0x35, 0x41, 0x28, 0x9e, 0x09, 0x02, 0x71, + 0x6c, 0x10, 0x2e, 0x6e, 0xc3, 0x32, 0x68, 0x13, 0x55, 0x51, 0xc3, 0x36, + 0x50, 0xdd, 0x06, 0x21, 0xf3, 0xb8, 0x4c, 0x59, 0x7d, 0x41, 0xbd, 0xcd, + 0xa5, 0xd1, 0xa5, 0xbd, 0xb9, 0x4d, 0x10, 0x0a, 0x68, 0x82, 0x40, 0x20, + 0x1b, 0x84, 0x4b, 0x0c, 0x36, 0x2c, 0x04, 0x18, 0x4c, 0x5b, 0x15, 0x06, + 0x43, 0x18, 0x10, 0xd4, 0x18, 0x6c, 0x58, 0x06, 0x6d, 0xa2, 0x2a, 0x6b, + 0x08, 0x83, 0x81, 0x1a, 0x83, 0x0d, 0x02, 0x19, 0x94, 0xc1, 0x86, 0xe1, + 0x33, 0x03, 0x60, 0x43, 0xa1, 0x44, 0x67, 0x00, 0x00, 0x2c, 0xd2, 0xdc, + 0xe6, 0xe8, 0xe6, 0x26, 0x08, 0x44, 0x42, 0x63, 0x2e, 0xed, 0xec, 0x8b, + 0x8d, 0x6c, 0x82, 0x40, 0x28, 0x34, 0xe6, 0xd2, 0xce, 0xbe, 0xe6, 0xe8, + 0x26, 0x08, 0xc4, 0xb2, 0xc1, 0x48, 0x03, 0x35, 0x58, 0x03, 0x36, 0x68, + 0x03, 0x37, 0xa8, 0xc2, 0xc6, 0x66, 0xd7, 0xe6, 0x92, 0x46, 0x56, 0xe6, + 0x46, 0x37, 0x25, 0x08, 0xaa, 0x90, 0xe1, 0xb9, 0xd8, 0x95, 0xc9, 0xcd, + 0xa5, 0xbd, 0xb9, 0x4d, 0x09, 0x88, 0x26, 0x64, 0x78, 0x2e, 0x76, 0x61, + 0x6c, 0x76, 0x65, 0x72, 0x53, 0x82, 0xa2, 0x0e, 0x19, 0x9e, 0xcb, 0x1c, + 0x5a, 0x18, 0x59, 0x99, 0x5c, 0xd3, 0x1b, 0x59, 0x19, 0xdb, 0x94, 0x00, + 0xa9, 0x44, 0x86, 0xe7, 0x42, 0x97, 0x07, 0x57, 0x16, 0xe4, 0xe6, 0xf6, + 0x46, 0x17, 0x46, 0x97, 0xf6, 0xe6, 0x36, 0x37, 0x25, 0x68, 0xea, 0x90, + 0xe1, 0xb9, 0xd8, 0xa5, 0x95, 0xdd, 0x25, 0x91, 0x4d, 0xd1, 0x85, 0xd1, + 0x95, 0x4d, 0x09, 0x9e, 0x3a, 0x64, 0x78, 0x2e, 0x65, 0x6e, 0x74, 0x72, + 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x53, 0x82, 0x33, 0xe8, 0x42, + 0x86, 0xe7, 0x32, 0xf6, 0x56, 0xe7, 0x46, 0x57, 0x26, 0x37, 0x37, 0x25, + 0x70, 0x03, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, + 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, + 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, + 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, + 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, + 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, + 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, + 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, + 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, + 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, + 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, + 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, + 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, + 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, + 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, + 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, + 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, + 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, + 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, + 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, + 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, + 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, + 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, + 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, + 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, + 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x16, 0x30, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, + 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, + 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, + 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1a, 0x12, 0xec, 0x35, 0xb4, 0xdb, 0x6b, 0x4a, 0x7a, 0xae, 0xf3, 0xf6, + 0xa5, 0x3d, 0xb4, 0x25, 0x44, 0x58, 0x49, 0x4c, 0x48, 0x05, 0x00, 0x00, + 0x60, 0x00, 0x01, 0x00, 0x52, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x05, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, + 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, + 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, + 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, + 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, + 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x19, + 0x80, 0x39, 0x02, 0x30, 0x98, 0x23, 0x40, 0x8a, 0x31, 0x44, 0x54, 0x44, + 0x56, 0x0c, 0x20, 0xa2, 0x1a, 0xc2, 0x81, 0x80, 0x4c, 0x20, 0x00, 0x00, + 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, + 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, + 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, + 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, + 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, + 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, + 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, + 0x0c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, + 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xa2, 0x12, 0x18, 0x01, 0x28, + 0x89, 0x62, 0x28, 0x83, 0x72, 0x28, 0x0f, 0xaa, 0x92, 0x18, 0x01, 0x28, + 0x82, 0x32, 0x28, 0x04, 0xda, 0xb1, 0x92, 0x03, 0x09, 0x04, 0x00, 0x80, + 0xc0, 0x00, 0x14, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, + 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, + 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, + 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, + 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x88, 0x61, 0x82, 0x40, 0x10, + 0x1b, 0x84, 0x81, 0x98, 0x20, 0x10, 0xc5, 0x06, 0x61, 0x30, 0x28, 0xd8, + 0xcd, 0x4d, 0x10, 0x08, 0x63, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x61, 0x79, + 0x36, 0x04, 0xcb, 0x04, 0x41, 0x00, 0x48, 0xb4, 0x85, 0xa5, 0xb9, 0x11, + 0x81, 0x7a, 0x9a, 0x4a, 0xa2, 0x4a, 0x7a, 0x72, 0x9a, 0x20, 0x14, 0xca, + 0x04, 0xa1, 0x58, 0x36, 0x04, 0xc4, 0x04, 0xa1, 0x60, 0x26, 0x08, 0xc4, + 0xb1, 0x41, 0xa0, 0xa8, 0x0d, 0x0b, 0xf1, 0x40, 0x91, 0x14, 0x0d, 0x13, + 0x11, 0x55, 0x2c, 0x86, 0x9e, 0x98, 0x9e, 0xa4, 0x26, 0x08, 0x45, 0x33, + 0x41, 0x20, 0x90, 0x0d, 0x02, 0x95, 0x6d, 0x58, 0x86, 0x0b, 0x8a, 0xa4, + 0x68, 0xc0, 0x86, 0x48, 0xdb, 0x20, 0x58, 0x1b, 0x97, 0x29, 0xab, 0x2f, + 0xa8, 0xb7, 0xb9, 0x34, 0xba, 0xb4, 0x37, 0xb7, 0x09, 0x42, 0xe1, 0x4c, + 0x10, 0x88, 0x64, 0x83, 0x40, 0x7d, 0x1b, 0x16, 0xa2, 0x83, 0x30, 0xc9, + 0x1b, 0x3c, 0x22, 0x02, 0x83, 0x0d, 0xcb, 0x70, 0x41, 0x91, 0x34, 0x0d, + 0xde, 0x10, 0x81, 0xc1, 0x06, 0x21, 0x0c, 0xc4, 0x60, 0xc3, 0xc0, 0x8d, + 0x01, 0xb0, 0xa1, 0x68, 0x1c, 0x32, 0x00, 0x80, 0x2a, 0x6c, 0x6c, 0x76, + 0x6d, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, + 0x9e, 0x8b, 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, + 0x42, 0x86, 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26, 0x37, 0x25, 0x30, + 0xea, 0x90, 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, + 0x91, 0x95, 0xb1, 0x4d, 0x09, 0x92, 0x3a, 0x64, 0x78, 0x2e, 0x76, 0x69, + 0x65, 0x77, 0x49, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x82, 0xa5, + 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, + 0x1b, 0xdd, 0xdc, 0x94, 0x80, 0x0c, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, + 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, + 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, + 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, + 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, + 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, + 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, + 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, + 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, + 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, + 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, + 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, + 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, + 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, + 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, + 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, + 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, + 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, + 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, + 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, + 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, + 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, + 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, + 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, + 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, + 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x16, 0x30, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0xe2, + 0x00, 0x83, 0xd8, 0x3c, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, + 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, + 0x17, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x61, 0x20, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, + 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x54, 0x25, 0x40, 0x34, + 0x03, 0x50, 0x0a, 0x85, 0x40, 0x33, 0x02, 0x30, 0x46, 0x00, 0x82, 0x20, + 0x88, 0x7f, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x60, 0x54, + 0xc3, 0x24, 0x2d, 0xc5, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x16, + 0x41, 0x4d, 0x87, 0x31, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0xc6, 0x55, + 0x54, 0x14, 0x73, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0x81, 0x19, + 0x55, 0xe5, 0x20, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x60, 0x64, 0x87, + 0x65, 0x29, 0xc9, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x59, 0x72, + 0x5d, 0x90, 0x30, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x96, 0x5c, + 0xd7, 0x12, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x25, 0xd7, + 0xf5, 0x1c, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x64, 0xc9, 0x75, + 0x39, 0xc6, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x59, 0x82, 0x5d, + 0x50, 0x31, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x96, 0x60, 0xd7, + 0x42, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x25, 0xd8, 0xf5, + 0x0c, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x64, 0x09, 0x76, 0x39, + 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const Uint32 s_TriangleFragShaderDxil[] = { + 0x44, 0x58, 0x42, 0x43, 0x7e, 0x0a, 0x30, 0x58, 0x0c, 0x74, 0x45, 0xb2, + 0x7d, 0x54, 0xd2, 0x32, 0xbe, 0xaa, 0xdb, 0x3f, 0x01, 0x00, 0x00, 0x00, + 0x84, 0x0b, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, + 0x9c, 0x01, 0x00, 0x00, 0x70, 0x06, 0x00, 0x00, 0x8c, 0x06, 0x00, 0x00, + 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x5c, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, + 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, + 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, + 0xa8, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x43, 0x4f, 0x4c, + 0x4f, 0x52, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x44, 0x00, + 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x44, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xcc, 0x04, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xb4, 0x04, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, + 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, + 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, + 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, + 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, + 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x19, + 0x80, 0x39, 0x02, 0x30, 0x98, 0x23, 0x40, 0x8a, 0x31, 0x44, 0x54, 0x44, + 0x56, 0x0c, 0x20, 0xa2, 0x1a, 0xc2, 0x81, 0x80, 0x54, 0x20, 0x00, 0x00, + 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, + 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, + 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, + 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, + 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, + 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, + 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, + 0x0d, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, + 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xa2, 0x12, 0x18, 0x01, 0x28, + 0x86, 0x32, 0x28, 0x8f, 0x92, 0x28, 0x04, 0xaa, 0x92, 0x28, 0x83, 0x42, + 0x18, 0x01, 0x28, 0x82, 0x02, 0xa1, 0x1d, 0x4b, 0x41, 0x08, 0x00, 0x00, + 0x80, 0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x5e, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, + 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, + 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, + 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x88, + 0x61, 0x82, 0x40, 0x10, 0x1b, 0x84, 0x81, 0xd8, 0x20, 0x10, 0x04, 0x05, + 0xb8, 0xb9, 0x09, 0x02, 0x51, 0x6c, 0x18, 0x0e, 0x84, 0x98, 0x20, 0x08, + 0xc0, 0x06, 0x60, 0xc3, 0x40, 0x2c, 0xcb, 0x86, 0x80, 0xd9, 0x30, 0x0c, + 0x4a, 0x33, 0x41, 0x58, 0xa0, 0x0d, 0xc1, 0x43, 0xa2, 0x2d, 0x2c, 0xcd, + 0x8d, 0xcb, 0x94, 0xd5, 0x17, 0xd4, 0xdb, 0x5c, 0x1a, 0x5d, 0xda, 0x9b, + 0xdb, 0x04, 0xa1, 0x50, 0x26, 0x08, 0xc5, 0xb2, 0x21, 0x20, 0x26, 0x08, + 0x05, 0x33, 0x41, 0x28, 0x9a, 0x0d, 0x0b, 0x21, 0x4d, 0x54, 0x65, 0x0d, + 0x16, 0x71, 0x01, 0x2c, 0x86, 0x9e, 0x98, 0x9e, 0xa4, 0x26, 0x08, 0x85, + 0x33, 0x41, 0x20, 0x8c, 0x09, 0x02, 0x71, 0x6c, 0x10, 0x36, 0x6e, 0xc3, + 0x32, 0x64, 0xd3, 0x55, 0x69, 0x83, 0x35, 0x5c, 0xdd, 0x06, 0x01, 0xf3, + 0x98, 0x4c, 0x59, 0x7d, 0x51, 0x85, 0xc9, 0x9d, 0x95, 0xd1, 0x4d, 0x10, + 0x8a, 0x67, 0xc3, 0x42, 0x80, 0xc1, 0x14, 0x06, 0xd5, 0x35, 0x58, 0xc4, + 0xd5, 0x6d, 0x08, 0xc4, 0x60, 0xc3, 0xf0, 0x8d, 0x01, 0xb0, 0xa1, 0x50, + 0x22, 0x32, 0x00, 0x00, 0x16, 0x69, 0x6e, 0x73, 0x74, 0x73, 0x13, 0x04, + 0x02, 0xa1, 0x31, 0x97, 0x76, 0xf6, 0xc5, 0x46, 0x36, 0x41, 0x20, 0x12, + 0x1a, 0x73, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x1b, 0x0c, 0x33, 0x38, 0x03, + 0x34, 0x48, 0x03, 0x35, 0x48, 0x83, 0x2a, 0x6c, 0x6c, 0x76, 0x6d, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, 0x9e, 0x8b, + 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, 0x42, 0x86, + 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26, 0x37, 0x25, 0x28, 0xea, 0x90, + 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, 0x91, 0x95, + 0xb1, 0x4d, 0x09, 0x90, 0x4a, 0x64, 0x78, 0x2e, 0x74, 0x79, 0x70, 0x65, + 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, + 0x82, 0xa6, 0x0e, 0x19, 0x9e, 0x8b, 0x5d, 0x5a, 0xd9, 0x5d, 0x12, 0xd9, + 0x14, 0x5d, 0x18, 0x5d, 0xd9, 0x94, 0xe0, 0xa9, 0x43, 0x86, 0xe7, 0x52, + 0xe6, 0x46, 0x27, 0x97, 0x07, 0xf5, 0x96, 0xe6, 0x46, 0x37, 0x37, 0x25, + 0x20, 0x83, 0x2e, 0x64, 0x78, 0x2e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, + 0x72, 0x73, 0x53, 0x02, 0x35, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, + 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, + 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, + 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, + 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, + 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, + 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, + 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, + 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, + 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, + 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, + 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, + 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, + 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, + 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, + 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, + 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, + 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, + 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, + 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, + 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, + 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, + 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, + 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20, + 0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, + 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x16, 0x30, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0xe2, + 0x00, 0x83, 0xd8, 0x3c, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, + 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, + 0x17, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x43, 0x04, 0x79, 0x2c, 0x87, 0xd0, 0x04, + 0xaa, 0xf4, 0x85, 0xf5, 0x84, 0xb6, 0x2b, 0x16, 0x44, 0x58, 0x49, 0x4c, + 0xf0, 0x04, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, + 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xd8, 0x04, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, + 0x33, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, + 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, + 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, + 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, + 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, + 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, + 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, + 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, + 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, + 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, + 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, + 0x25, 0x00, 0x8a, 0x19, 0x80, 0x39, 0x02, 0x30, 0x98, 0x23, 0x40, 0x8a, + 0x31, 0x44, 0x54, 0x44, 0x56, 0x0c, 0x20, 0xa2, 0x1a, 0xc2, 0x81, 0x80, + 0x54, 0x20, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, + 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, + 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, + 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, + 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, + 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, + 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, + 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, + 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, + 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, + 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xc8, 0x02, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, + 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xa2, + 0x12, 0x18, 0x01, 0x28, 0x89, 0x62, 0x28, 0x83, 0xf2, 0xa0, 0x2a, 0x89, + 0x32, 0x28, 0x84, 0x11, 0x80, 0x22, 0x28, 0x10, 0xda, 0xb1, 0x14, 0x84, + 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x01, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, + 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, + 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, + 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x88, + 0x61, 0x82, 0x40, 0x10, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x10, 0xc5, 0x06, + 0x61, 0x30, 0x28, 0xc0, 0xcd, 0x4d, 0x10, 0x08, 0x63, 0xc3, 0x80, 0x24, + 0xc4, 0x04, 0x61, 0x79, 0x36, 0x04, 0xcb, 0x04, 0x41, 0x00, 0x48, 0xb4, + 0x85, 0xa5, 0xb9, 0x71, 0x99, 0xb2, 0xfa, 0x82, 0x7a, 0x9b, 0x4b, 0xa3, + 0x4b, 0x7b, 0x73, 0x9b, 0x20, 0x14, 0xc9, 0x04, 0xa1, 0x50, 0x36, 0x04, + 0xc4, 0x04, 0xa1, 0x58, 0x26, 0x08, 0x05, 0xb3, 0x61, 0x21, 0x1e, 0x28, + 0x92, 0xa6, 0x61, 0x22, 0x28, 0x80, 0xc5, 0xd0, 0x13, 0xd3, 0x93, 0xd4, + 0x04, 0xa1, 0x68, 0x26, 0x08, 0xc4, 0x31, 0x41, 0x20, 0x90, 0x0d, 0x02, + 0x96, 0x6d, 0x58, 0x06, 0x0b, 0xa2, 0xa4, 0x6b, 0x98, 0x06, 0x4a, 0xdb, + 0x20, 0x54, 0x1b, 0x93, 0x29, 0xab, 0x2f, 0xaa, 0x30, 0xb9, 0xb3, 0x32, + 0xba, 0x09, 0x42, 0xe1, 0x6c, 0x58, 0x88, 0x0e, 0xf2, 0x24, 0x6a, 0x98, + 0x08, 0x4a, 0xdb, 0x10, 0x7c, 0x1b, 0x06, 0x0e, 0x0c, 0x80, 0x0d, 0x45, + 0xe3, 0x84, 0x01, 0x00, 0x54, 0x61, 0x63, 0xb3, 0x6b, 0x73, 0x49, 0x23, + 0x2b, 0x73, 0xa3, 0x9b, 0x12, 0x04, 0x55, 0xc8, 0xf0, 0x5c, 0xec, 0xca, + 0xe4, 0xe6, 0xd2, 0xde, 0xdc, 0xa6, 0x04, 0x44, 0x13, 0x32, 0x3c, 0x17, + 0xbb, 0x30, 0x36, 0xbb, 0x32, 0xb9, 0x29, 0x81, 0x51, 0x87, 0x0c, 0xcf, + 0x65, 0x0e, 0x2d, 0x8c, 0xac, 0x4c, 0xae, 0xe9, 0x8d, 0xac, 0x8c, 0x6d, + 0x4a, 0x90, 0xd4, 0x21, 0xc3, 0x73, 0xb1, 0x4b, 0x2b, 0xbb, 0x4b, 0x22, + 0x9b, 0xa2, 0x0b, 0xa3, 0x2b, 0x9b, 0x12, 0x2c, 0x75, 0xc8, 0xf0, 0x5c, + 0xca, 0xdc, 0xe8, 0xe4, 0xf2, 0xa0, 0xde, 0xd2, 0xdc, 0xe8, 0xe6, 0xa6, + 0x04, 0x61, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, + 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, + 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, + 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, + 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, + 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, + 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, + 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, + 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, + 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, + 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, + 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, + 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, + 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, + 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, + 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, + 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, + 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, + 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, + 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, + 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, + 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, + 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, + 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, + 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, + 0xf4, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x16, 0x30, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, + 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, + 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, + 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x44, 0x85, 0x30, 0x03, 0x50, 0x0a, 0x54, 0x25, + 0x00, 0x00, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x60, 0x4c, + 0x44, 0x04, 0x21, 0xc3, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x54, + 0x21, 0x45, 0x02, 0x31, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x46, 0x65, + 0x4c, 0x52, 0x52, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0x61, 0x1d, + 0xd4, 0xd4, 0x18, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x58, 0x06, + 0x45, 0x31, 0xc4, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x96, 0x41, + 0x51, 0xc5, 0x30, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x88, 0x65, 0x50, + 0xd4, 0x22, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x62, 0x19, 0x14, + 0xe5, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// ================================================== +// Mesh +// ================================================== + +// ================================================== +// Texture +// ================================================== + +// clang-format on \ No newline at end of file diff --git a/tests/graphics/shaders/triangle_frag_shader.dxil b/tests/graphics/shaders/triangle_frag_shader.dxil deleted file mode 100644 index b4323e6e0362596f17c3159361db257cd2e9c202..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2948 zcmeHJeN0=|6@T`7yk~;_cwj3r;X}_5n48elm_k4p4S(PoFp7!Y)T>~zNu0onjlr&m zNjp7kgPqh-9YPX!Y!N1D)TY&zFLkBqCK4M;657#}Oi5u8EYxWy+M+C}x@p>WuQ63t zRr_O__E(R5&pG#;-~D*!-uHV}85PQ(t&C~r3SQbuL0&Tn7j8`oFJ#u@07d-EFAw` z@=qWz&St^izYDAd6fRV&o3WbPZHfKD5Cv6IScnQmvDIgRAr?!8ps*-O0eNa|pKCE_ z;hGQzh9>H#H^>dspko64Qjk;`>$DIA*SZMe3g!465!ldX5KHsWiLrc;Bl-#s%crn9 zoRU@!vV7da6i!wi_EIZD)v^_XX$l`D6;yD94eO+efF>lMmFmE&NS0Kwq#;8Y`7xcm zsV}(b{p27fQsYfR1OZ2lWCs^ud59YJYdqfybWs}aw+`gtp7|b=f(G^gQ1JMq`J7aG zPd~=bKjj1Jt}hZ2WNHJ!G@nmPNeYlcf-<&tsP0@*i0?&#}u~|I$ z%z0r!R)#hdOf7n95>t+53R&U-srcnVF?ME9>{WoShaJgnkb{fM)X<45;|BHnF&MiM z)rQn;zUpOe=kn)`+)a~(@6}G?>dC@5j@1?oXz}-!)$t;WlG0KEv!{m2_VwMODJxS;|TAva`f@y_YYkky18L?u6bk2$HQ}2L|4R_ zI4`1$I4Pxa@y~f_qDF&-x4w&2Ja8g>;#3i*zf?{KQ`ub|RJkoG-Sg4Y?cTEHKjN&v zgtb3Hur!zM?+V|~pIJ3E>73h;1v`pjO+|l8(Zf)OVu{rggk#$)oUTS$|z8UOrh-p&{ z+-u!1x%Zi(ZH3}LhZe`CBmIYuUM>6W;iKmoQ$zK8dbT>vWnSJvj89((`faS zvO0)XPxl0!c49w=aBKW_JJD-LT|Is~?a!LdAeTerq9olWNx!>7uIR{8Dwcaklyggz zd&Qi$S8|~0U2oNlvhpG-d)F)Tp;gl>0+)%{-$ra}^LGQy`0XLT-9)&=gzM`RFzrtn z|1OTdOX%+o``zKb;xAUnFBZs$J>&v}n#{UpfR!%7^ z!wLO%v|>nE5kRYkqECQD|L&=pMXSz6xiJy(f*tJ@`(2Db>q8~^^#Z;`llKN%`R>Djg@`V{?`xgHXPw+h|8)I5d=eN z_XGT{H3?~-Q& z%zxxN_#ON%zB|w=_TC@ad_XGpWia_->f>_)AAoW&@I{61ng(?K3$6>()C6vph{xY= zq&T~y%%&J-c9&z|<6Vo;G^wxiDToM;o$_Jod&DXCz}6r0=9E7CVdq z^8TiuggNzd)C<`-$z^!8cYQ3xVBUSkNg!MGEj##A7mPRhTFm zkh2+DC^U#_*(I$Zgy!ICi+0D3pl}ny@${K`0aK?z&mc&-!^f7tUgk%*Su;^y< QSK+MIEWsxj_#*)1U))Av2LJ#7 diff --git a/tests/graphics/shaders/triangle_frag_shader.glsl b/tests/graphics/shaders/triangle_frag_shader.glsl deleted file mode 100644 index 384d9720..00000000 --- a/tests/graphics/shaders/triangle_frag_shader.glsl +++ /dev/null @@ -1,11 +0,0 @@ - -#version 450 - -layout(location = 0) in vec4 aColor; - -layout(location = 0) out vec4 color; - -void main() -{ - color = aColor; -} \ No newline at end of file diff --git a/tests/graphics/shaders/triangle_frag_shader.hlsl b/tests/graphics/shaders/triangle_frag_shader.hlsl deleted file mode 100644 index 756feece..00000000 --- a/tests/graphics/shaders/triangle_frag_shader.hlsl +++ /dev/null @@ -1,11 +0,0 @@ - -struct PSInput -{ - float4 pos : SV_POSITION; - float4 color : COLOR; -}; - -float4 main(PSInput input) : SV_Target -{ - return input.color; -} \ No newline at end of file diff --git a/tests/graphics/shaders/triangle_frag_shader.spv b/tests/graphics/shaders/triangle_frag_shader.spv deleted file mode 100644 index 2faee3a9764b9c5565146fcb371fb4138aac027a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmYk1y9&Zk5JWeLCeipr&`u)u!9qn4Z7kBH^9zDDf*Mf2(66!)oD&~-!`!_yJNt;| zjsx=@i!8LJy-(L%bM%bNFJqc*v*dc)C)3#kN6Wm@h^K9VRTRM~Kb%R_gh=SfhaL!? zK3DOsqN>z?Kb)FfaV##1aO(5TTS!0op)?Mh{FnFCnckyvik0ua-oCV07|72KaOTFk xLq+}qefi<+fJVNqs8xS?I5W}a+K_ql;!yLDQdL|@rDsFHzgCvM@TaO5!VAoI66^o~ diff --git a/tests/graphics/shaders/triangle_vert_shader.dxil b/tests/graphics/shaders/triangle_vert_shader.dxil deleted file mode 100644 index 0cf4d49856ec0be9b0d65aafa41f637150d04915..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3128 zcmeHJeN0=|6~Fc~e$QZ=2YAGeo#>HZ$ zR(%^Nt8`WS0H}iX>!JTe^{Ko>*;FbyE;We`v{anJCE|v9?1EHqz{e?g&Y(CO6gtCATXiYWWF#m63@&D_!+TLT5bp;EOdp#ep7eaW#QpwX1i zpC=YqAqXRu6CKl30D%jLt|gvB8LB1$RR)z3Lyf#<4d$63vIK%vMy-xYqHv4QuTW0k z&4Oo5LSKrDi0*9$jG@l$1M+!>mWfMC25BC)I0+MMWgKg8;Ctwb!4!oDm-31+enqlW z(XR>c2&KAz90;U}H4QhAwk@oeS3CWy?gvL1S!!lA9{~8e0HOaLwSB0JKEd&9P+f$8 z(*iAwQ+t`=GARgXkHCgHBk4AbMKty?GPa%Zz~;VZG{8&O_4`vi9vx0@2V!tk;3%P! z!R@l6yHz!+IyN!3dDiLB!Tb!KZQ9pm@)cTqJr)G^IX~BP+m^V!um!2TBx*a2b`oe? zfZLJibSF9;CX@m!G5`1_m|ceUn$WH#W&}s=F{FtLE5wiy7&?tYOxry!tP`&g^(aT4 zUj_iYWlWsf{;05fa00+Hh{`;j#(^E_)*w%irVIF4Ij_z!lw;|9n#3!W`2H&S;XVm= zb`TC-QVHX;^MeSB0UXnS2S5+pzebq58PNsQ^bFOH*oW31SF*F`#Gme&W2)!G5hi0# zj#tP0bX^_EX;R`kyx;7S;X;pdg}@m}zn)^zt6TY8PmsW-nWm5|_p;aVJCeOOPi`FJ z%qYiR&b@LRTfR|~UVHuB8;ns?4z}l)Sws%jmnSFuoY}Y9j9AOqj_;krk`L~F5`L0h zAeW4==pC*2&i0Vhl2Kb7D%9U$W_|IYZvQ*-i&w_4jbEIq#FH&986oskunTh;eBJBc zVk-IgGQZWxY#ZD0Cgyf-c5~>0p&9RL9%53Cs=fPZwc$$E$Sbf)Q+t=KM}MfLy{psU%6p{nK9oMId#HXbr>ID5g=9mW3&ovzm_rm^ z6*co{<^9THPsp!upgrAaXRw1E0jZC1?h^+$kFD4`JG15LsHmAtio)E&MWlRQS?)*5 z7rXskR`hKQ?a}zGRmJ!Y5cv@kAGu4HlqHi$*+=d&4^q0g!Lystw=HOq#b<-9!)FcntR~bhLG6D_f@Kdod~aaB z4!+M8^z{Utxu0)vKflL)I?Y`tk%swE(b}kJG1}fXi!Nn}!p<$1%*@{glqK`Zl3=v` zFjPFGEbd22heEsHr2lZ0E+eJqLjL(I^!rxChWk3L2=y!`pLO1McmnMWI?L7^sqM1V z2TR-yxL+LvOnk>4&QmjG-Zgk7u5oV6L$pvBAHoBX0*(x8% z=iJ4eGt4Y@*c6&RPCGYh5lMk#M{BFSZD&g(p%PPts#d6l1{^> zxn{^YVv=I1#nHZj;e~>W1H6=>Gu#+nFrjGMQ>Z z*)M<6FQ+>QK0i}l>D%2900hRItF7U6`uW)ab2*)Y+6P1&-so$3X(0wD_S+5w$QWGn xUj5DV7@RgJzWG!XgF6}*-YS_(z+DIQ@#>oQOg9zJ;VVzs2{_AM!i<0P{u_dWkY)e? diff --git a/tests/graphics/shaders/triangle_vert_shader.glsl b/tests/graphics/shaders/triangle_vert_shader.glsl deleted file mode 100644 index 55b9831a..00000000 --- a/tests/graphics/shaders/triangle_vert_shader.glsl +++ /dev/null @@ -1,13 +0,0 @@ - -#version 450 - -layout(location = 0) in vec2 aPosition; -layout(location = 1) in vec3 aColor; - -layout(location = 0) out vec4 vColor; - -void main() -{ - gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); - vColor = vec4(aColor, 1.0); -} \ No newline at end of file diff --git a/tests/graphics/shaders/triangle_vert_shader.hlsl b/tests/graphics/shaders/triangle_vert_shader.hlsl deleted file mode 100644 index 965d2fcc..00000000 --- a/tests/graphics/shaders/triangle_vert_shader.hlsl +++ /dev/null @@ -1,20 +0,0 @@ - -struct VSInput -{ - float2 pos : POSITION; - float3 color : COLOR; -}; - -struct VSOutput -{ - float4 pos : SV_POSITION; - float4 color : COLOR; -}; - -VSOutput main(VSInput input) -{ - VSOutput output; - output.pos = float4(input.pos, 0.0, 1.0); - output.color = float4(input.color, 1.0); - return output; -} \ No newline at end of file diff --git a/tests/graphics/shaders/triangle_vert_shader.spv b/tests/graphics/shaders/triangle_vert_shader.spv deleted file mode 100644 index b98a577bd42c6c2154f51b8219e26e2f992998ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1140 zcmYk4U2D`(5Qa~8o88vcet-B;YihL>gyMyYASzN}z34@y;H@k+ltA1qyJ;!CslUx% z<&EI;Bsr@mOlIbt_sn_EB<eiG02A|cd!-g5%w5s^R)24*pP%-o`2kgGkWA_#kb>Z{52bw*%c{h zjT>7VP4Y4y4MDpV-?J+`AC@QibtW&?Jd4_4k)MCcC*@%HJ)724ZtbEdrnLlpYIY?& zY9CBbtTlU=%fnGI8rQk^8Z>#I{ocWIKeON16@A3&nTBen5p$0`bw$ir%sKUWt7jW? znXBdhTrKAIUqyvIcj#yz;|-z?KE*cK-^H8Tf1URnKE+(mo7}Hzzb*1xc==-6L~4sY ztZ6B{+xV#cZIe4!G0$13cy(XTF<-=7>RQ5kj+*Vaj8}uW{mh+(Sk$>n?2^BRw`LFP z`umtG<`1gu=Lh)@iPh#^>~HRD#nhAH?O`r|2XFrrlW*?q#a{E>)$L4O?)eRp;6L(K z+d8IxHNS&t?+r{mayE(OIP1u{ODulV?72rQc8qehZ(;Tk_rBiIe%{Cb!f)W5-=oT0 wzP(fYF6JG+z*o(!~g&Q diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 52f673b1..4f167b01 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -3,6 +3,7 @@ #include "pal/pal_video.h" #include "pal/pal_system.h" #include "tests.h" +#include "shaders.h" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 @@ -549,74 +550,51 @@ bool triangleTest() } // create shaders - Uint64 bytecodeSize = 0; - void* bytecode = nullptr; - PalShaderCreateInfo shaderCreateInfo = {0}; + Uint64 vertBytecodeSize = 0; + Uint64 fragBytecodeSize = 0; + void* vertBytecode = nullptr; + void* fragBytecode = nullptr; + + PalShaderCreateInfo vertShaderCreateInfo = {0}; + PalShaderCreateInfo fragShaderCreateInfo = {0}; - const char* vertexShaderPath = nullptr; - const char* fragShaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - vertexShaderPath = "graphics/shaders/triangle_vert_shader.spv"; - fragShaderPath = "graphics/shaders/triangle_frag_shader.spv"; + vertBytecodeSize = sizeof(s_TriangleVertShaderSpv); + fragBytecodeSize = sizeof(s_TriangleFragShaderSpv); + + vertBytecode = (void*)s_TriangleVertShaderSpv; + fragBytecode = (void*)s_TriangleFragShaderSpv; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - vertexShaderPath = "graphics/shaders/triangle_vert_shader.dxil"; - fragShaderPath = "graphics/shaders/triangle_frag_shader.dxil"; - } + vertBytecodeSize = sizeof(s_TriangleVertShaderDxil); + fragBytecodeSize = sizeof(s_TriangleFragShaderDxil); - if (!readFile(vertexShaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader file"); - return false; + vertBytecode = (void*)s_TriangleVertShaderDxil; + fragBytecode = (void*)s_TriangleFragShaderDxil; } - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } + vertShaderCreateInfo.bytecode = vertBytecode; + vertShaderCreateInfo.bytecodeSize = vertBytecodeSize; + vertShaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; - readFile(vertexShaderPath, bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; + fragShaderCreateInfo.bytecode = fragBytecode; + fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; + fragShaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; - result = palCreateShader(device, &shaderCreateInfo, &vertexShader); + result = palCreateShader(device, &vertShaderCreateInfo, &vertexShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create vertex shader: %s", error); return false; } - // fragment shader - bytecodeSize = 0; - palFree(nullptr, bytecode); - bytecode = nullptr; - - if (!readFile(fragShaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader file"); - return false; - } - - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - readFile(fragShaderPath, bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; - - result = palCreateShader(device, &shaderCreateInfo, &fragmentShader); + result = palCreateShader(device, &fragShaderCreateInfo, &fragmentShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fragment shader: %s", error); return false; } - palFree(nullptr, bytecode); - // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); diff --git a/tests/tests.h b/tests/tests.h index 20890798..d0a92c02 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -5,39 +5,11 @@ #include "pal/pal_core.h" #include - typedef bool (*TestFn)(); void registerTest(TestFn func, const char* name); void runTests(); -static bool readFile( - const char* filename, - void* buffer, - Uint64* size) -{ - FILE* file = fopen(filename, "rb"); - if (!file) { - return false; - } - - fseek(file, 0, SEEK_END); - Uint64 tmpSize = ftell(file); - fseek(file, 0, SEEK_SET); - - if (buffer) { - tmpSize = *size; - size_t read = fread(buffer, 1, tmpSize, file); - if (read != tmpSize) { - return false; - } - } - - fclose(file); - *size = tmpSize; - return true; -} - // core tests bool loggerTest(); bool timeTest(); diff --git a/tests/tests_main.c b/tests/tests_main.c index 9dce3360..ee6768b3 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,12 +59,12 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders + // registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); - // registerTest(triangleTest, "Triangle Test"); + registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); // TODO: add dxil shaders // registerTest(textureTest, "Texture Test"); #endif // From 8790688a7cf837aadd2f068ae0d2c467f862988b Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 29 Apr 2026 16:04:17 +0000 Subject: [PATCH 189/372] mesh test: remove shader files dependency and embed shader sources and bytecode into source file --- tests/graphics/mesh_test.c | 67 ++++------- tests/graphics/shaders.h | 143 ++++++++++++++++++++++++ tests/graphics/shaders/mesh_shader.glsl | 27 ----- tests/graphics/shaders/mesh_shader.spv | Bin 1756 -> 0 bytes tests/tests_main.c | 4 +- 5 files changed, 168 insertions(+), 73 deletions(-) delete mode 100644 tests/graphics/shaders/mesh_shader.glsl delete mode 100644 tests/graphics/shaders/mesh_shader.spv diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index a5ee0d4d..67a819b6 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -3,6 +3,7 @@ #include "pal/pal_video.h" #include "pal/pal_system.h" #include "tests.h" +#include "shaders.h" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 @@ -393,70 +394,48 @@ bool meshTest() } // create shaders - Uint64 bytecodeSize = 0; - void* bytecode = nullptr; - PalShaderCreateInfo shaderCreateInfo = {0}; + Uint64 meshBytecodeSize = 0; + Uint64 fragBytecodeSize = 0; + void* meshBytecode = nullptr; + void* fragBytecode = nullptr; + + PalShaderCreateInfo meshShaderCreateInfo = {0}; + PalShaderCreateInfo fragShaderCreateInfo = {0}; - const char* meshShaderPath = nullptr; - const char* fragShaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - meshShaderPath = "graphics/shaders/mesh_shader.spv"; - fragShaderPath = "graphics/shaders/triangle_frag_shader.spv"; - } + meshBytecodeSize = sizeof(s_MeshShaderSpv); + fragBytecodeSize = sizeof(s_TriangleFragShaderSpv); - if (!readFile(meshShaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader file"); - return false; - } + meshBytecode = (void*)s_MeshShaderSpv; + fragBytecode = (void*)s_TriangleFragShaderSpv; - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + palLog(nullptr, "Dxil not tested yet"); return false; } - readFile(meshShaderPath, bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_MESH; + meshShaderCreateInfo.bytecode = meshBytecode; + meshShaderCreateInfo.bytecodeSize = meshBytecodeSize; + meshShaderCreateInfo.stage = PAL_SHADER_STAGE_MESH; + + fragShaderCreateInfo.bytecode = fragBytecode; + fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; + fragShaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; - result = palCreateShader(device, &shaderCreateInfo, &meshShader); + result = palCreateShader(device, &meshShaderCreateInfo, &meshShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create mesh shader: %s", error); return false; } - // fragment shader - bytecodeSize = 0; - palFree(nullptr, bytecode); - bytecode = nullptr; - - if (!readFile(fragShaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader file"); - return false; - } - - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - readFile(fragShaderPath, bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; - - result = palCreateShader(device, &shaderCreateInfo, &fragmentShader); + result = palCreateShader(device, &fragShaderCreateInfo, &fragmentShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fragment shader: %s", error); return false; } - palFree(nullptr, bytecode); - // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); diff --git a/tests/graphics/shaders.h b/tests/graphics/shaders.h index 4d944373..3dfea5e1 100644 --- a/tests/graphics/shaders.h +++ b/tests/graphics/shaders.h @@ -1437,6 +1437,149 @@ static const Uint32 s_TriangleFragShaderDxil[] = { // Mesh // ================================================== +// GLSL +// #version 460 +// #extension GL_EXT_mesh_shader : require + +// layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; +// layout(max_vertices = 4, max_primitives = 2) out; +// layout(triangles) out; + +// layout(location = 0) out vec4 vColors[]; + +// void main() +// { +// SetMeshOutputsEXT(4, 2); +// gl_MeshVerticesEXT[0].gl_Position = vec4(-0.5, 0.5, 0.0, 1.0); +// gl_MeshVerticesEXT[1].gl_Position = vec4( 0.5, 0.5, 0.0, 1.0); +// gl_MeshVerticesEXT[2].gl_Position = vec4( 0.5,-0.5, 0.0, 1.0); +// gl_MeshVerticesEXT[3].gl_Position = vec4(-0.5,-0.5, 0.0, 1.0); + +// // colors +// vColors[0] = vec4(1.0, 0.0, 0.0, 1.0); +// vColors[1] = vec4(0.0, 1.0, 0.0, 1.0); +// vColors[2] = vec4(0.0, 0.0, 1.0, 1.0); +// vColors[3] = vec4(1.0, 0.0, 0.0, 1.0); + +// gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); +// gl_PrimitiveTriangleIndicesEXT[1] = uvec3(0, 2, 3); +// } + +// HLSL + +static const uint32_t s_MeshShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x00000039, + 0x00000000, 0x00020011, 0x000014a3, 0x0006000a, + 0x5f565053, 0x5f545845, 0x6873656d, 0x6168735f, + 0x00726564, 0x0006000b, 0x00000001, 0x4c534c47, + 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, + 0x00000000, 0x00000001, 0x0008000f, 0x000014f5, + 0x00000004, 0x6e69616d, 0x00000000, 0x00000010, + 0x00000025, 0x00000030, 0x0006014b, 0x00000004, + 0x00000026, 0x00000007, 0x00000007, 0x00000007, + 0x00040010, 0x00000004, 0x0000001a, 0x00000004, + 0x00040010, 0x00000004, 0x00001496, 0x00000002, + 0x00030010, 0x00000004, 0x000014b2, 0x00030003, + 0x00000002, 0x000001cc, 0x00060004, 0x455f4c47, + 0x6d5f5458, 0x5f687365, 0x64616873, 0x00007265, + 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, + 0x00070005, 0x0000000d, 0x4d5f6c67, 0x50687365, + 0x65567265, 0x78657472, 0x00545845, 0x00060006, + 0x0000000d, 0x00000000, 0x505f6c67, 0x7469736f, + 0x006e6f69, 0x00070006, 0x0000000d, 0x00000001, + 0x505f6c67, 0x746e696f, 0x657a6953, 0x00000000, + 0x00070006, 0x0000000d, 0x00000002, 0x435f6c67, + 0x4470696c, 0x61747369, 0x0065636e, 0x00070006, + 0x0000000d, 0x00000003, 0x435f6c67, 0x446c6c75, + 0x61747369, 0x0065636e, 0x00070005, 0x00000010, + 0x4d5f6c67, 0x56687365, 0x69747265, 0x45736563, + 0x00005458, 0x00040005, 0x00000025, 0x6c6f4376, + 0x0073726f, 0x000a0005, 0x00000030, 0x505f6c67, + 0x696d6972, 0x65766974, 0x61697254, 0x656c676e, + 0x69646e49, 0x45736563, 0x00005458, 0x00030047, + 0x0000000d, 0x00000002, 0x00050048, 0x0000000d, + 0x00000000, 0x0000000b, 0x00000000, 0x00050048, + 0x0000000d, 0x00000001, 0x0000000b, 0x00000001, + 0x00050048, 0x0000000d, 0x00000002, 0x0000000b, + 0x00000003, 0x00050048, 0x0000000d, 0x00000003, + 0x0000000b, 0x00000004, 0x00040047, 0x00000025, + 0x0000001e, 0x00000000, 0x00040047, 0x00000030, + 0x0000000b, 0x000014b0, 0x00020013, 0x00000002, + 0x00030021, 0x00000003, 0x00000002, 0x00040015, + 0x00000006, 0x00000020, 0x00000000, 0x0004002b, + 0x00000006, 0x00000007, 0x00000001, 0x0004002b, + 0x00000006, 0x00000008, 0x00000004, 0x0004002b, + 0x00000006, 0x00000009, 0x00000002, 0x00030016, + 0x0000000a, 0x00000020, 0x00040017, 0x0000000b, + 0x0000000a, 0x00000004, 0x0004001c, 0x0000000c, + 0x0000000a, 0x00000007, 0x0006001e, 0x0000000d, + 0x0000000b, 0x0000000a, 0x0000000c, 0x0000000c, + 0x0004001c, 0x0000000e, 0x0000000d, 0x00000008, + 0x00040020, 0x0000000f, 0x00000003, 0x0000000e, + 0x0004003b, 0x0000000f, 0x00000010, 0x00000003, + 0x00040015, 0x00000011, 0x00000020, 0x00000001, + 0x0004002b, 0x00000011, 0x00000012, 0x00000000, + 0x0004002b, 0x0000000a, 0x00000013, 0xbf000000, + 0x0004002b, 0x0000000a, 0x00000014, 0x3f000000, + 0x0004002b, 0x0000000a, 0x00000015, 0x00000000, + 0x0004002b, 0x0000000a, 0x00000016, 0x3f800000, + 0x0007002c, 0x0000000b, 0x00000017, 0x00000013, + 0x00000014, 0x00000015, 0x00000016, 0x00040020, + 0x00000018, 0x00000003, 0x0000000b, 0x0004002b, + 0x00000011, 0x0000001a, 0x00000001, 0x0007002c, + 0x0000000b, 0x0000001b, 0x00000014, 0x00000014, + 0x00000015, 0x00000016, 0x0004002b, 0x00000011, + 0x0000001d, 0x00000002, 0x0007002c, 0x0000000b, + 0x0000001e, 0x00000014, 0x00000013, 0x00000015, + 0x00000016, 0x0004002b, 0x00000011, 0x00000020, + 0x00000003, 0x0007002c, 0x0000000b, 0x00000021, + 0x00000013, 0x00000013, 0x00000015, 0x00000016, + 0x0004001c, 0x00000023, 0x0000000b, 0x00000008, + 0x00040020, 0x00000024, 0x00000003, 0x00000023, + 0x0004003b, 0x00000024, 0x00000025, 0x00000003, + 0x0007002c, 0x0000000b, 0x00000026, 0x00000016, + 0x00000015, 0x00000015, 0x00000016, 0x0007002c, + 0x0000000b, 0x00000028, 0x00000015, 0x00000016, + 0x00000015, 0x00000016, 0x0007002c, 0x0000000b, + 0x0000002a, 0x00000015, 0x00000015, 0x00000016, + 0x00000016, 0x00040017, 0x0000002d, 0x00000006, + 0x00000003, 0x0004001c, 0x0000002e, 0x0000002d, + 0x00000009, 0x00040020, 0x0000002f, 0x00000003, + 0x0000002e, 0x0004003b, 0x0000002f, 0x00000030, + 0x00000003, 0x0004002b, 0x00000006, 0x00000031, + 0x00000000, 0x0006002c, 0x0000002d, 0x00000032, + 0x00000031, 0x00000007, 0x00000009, 0x00040020, + 0x00000033, 0x00000003, 0x0000002d, 0x0004002b, + 0x00000006, 0x00000035, 0x00000003, 0x0006002c, + 0x0000002d, 0x00000036, 0x00000031, 0x00000009, + 0x00000035, 0x0006002c, 0x0000002d, 0x00000038, + 0x00000007, 0x00000007, 0x00000007, 0x00050036, + 0x00000002, 0x00000004, 0x00000000, 0x00000003, + 0x000200f8, 0x00000005, 0x000314af, 0x00000008, + 0x00000009, 0x00060041, 0x00000018, 0x00000019, + 0x00000010, 0x00000012, 0x00000012, 0x0003003e, + 0x00000019, 0x00000017, 0x00060041, 0x00000018, + 0x0000001c, 0x00000010, 0x0000001a, 0x00000012, + 0x0003003e, 0x0000001c, 0x0000001b, 0x00060041, + 0x00000018, 0x0000001f, 0x00000010, 0x0000001d, + 0x00000012, 0x0003003e, 0x0000001f, 0x0000001e, + 0x00060041, 0x00000018, 0x00000022, 0x00000010, + 0x00000020, 0x00000012, 0x0003003e, 0x00000022, + 0x00000021, 0x00050041, 0x00000018, 0x00000027, + 0x00000025, 0x00000012, 0x0003003e, 0x00000027, + 0x00000026, 0x00050041, 0x00000018, 0x00000029, + 0x00000025, 0x0000001a, 0x0003003e, 0x00000029, + 0x00000028, 0x00050041, 0x00000018, 0x0000002b, + 0x00000025, 0x0000001d, 0x0003003e, 0x0000002b, + 0x0000002a, 0x00050041, 0x00000018, 0x0000002c, + 0x00000025, 0x00000020, 0x0003003e, 0x0000002c, + 0x00000026, 0x00050041, 0x00000033, 0x00000034, + 0x00000030, 0x00000012, 0x0003003e, 0x00000034, + 0x00000032, 0x00050041, 0x00000033, 0x00000037, + 0x00000030, 0x0000001a, 0x0003003e, 0x00000037, + 0x00000036, 0x000100fd, 0x00010038 +}; + // ================================================== // Texture // ================================================== diff --git a/tests/graphics/shaders/mesh_shader.glsl b/tests/graphics/shaders/mesh_shader.glsl deleted file mode 100644 index a0fbe477..00000000 --- a/tests/graphics/shaders/mesh_shader.glsl +++ /dev/null @@ -1,27 +0,0 @@ - -#version 460 -#extension GL_EXT_mesh_shader : require - -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; -layout(max_vertices = 4, max_primitives = 2) out; -layout(triangles) out; - -layout(location = 0) out vec4 vColors[]; - -void main() -{ - SetMeshOutputsEXT(4, 2); - gl_MeshVerticesEXT[0].gl_Position = vec4(-0.5, 0.5, 0.0, 1.0); - gl_MeshVerticesEXT[1].gl_Position = vec4( 0.5, 0.5, 0.0, 1.0); - gl_MeshVerticesEXT[2].gl_Position = vec4( 0.5,-0.5, 0.0, 1.0); - gl_MeshVerticesEXT[3].gl_Position = vec4(-0.5,-0.5, 0.0, 1.0); - - // colors - vColors[0] = vec4(1.0, 0.0, 0.0, 1.0); - vColors[1] = vec4(0.0, 1.0, 0.0, 1.0); - vColors[2] = vec4(0.0, 0.0, 1.0, 1.0); - vColors[3] = vec4(1.0, 0.0, 0.0, 1.0); - - gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); - gl_PrimitiveTriangleIndicesEXT[1] = uvec3(0, 2, 3); -} \ No newline at end of file diff --git a/tests/graphics/shaders/mesh_shader.spv b/tests/graphics/shaders/mesh_shader.spv deleted file mode 100644 index 1aef01631fc058035295b825bd69d944d1b1bc89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1756 zcmZXU+fEZv6oz*xEm)L;oID^7;+a|z0Wl^Lf~Fd4(xilV*EDnjleAMaQ;G4)r|<=Q z0F5u;3-~%F-kA7*(^<^~H(A|#{r@`cwf2x7Ssio5oSSgt?x`EB88_m-&N)|dMc1ew zHebFwXmpu$%rxu|^U-pWr{F=k*8nO9@9+Q?>SAsjeUX(|9B`kF22>)HPm{nF{tRzzz z)G#lbqA*XwT1$22O>Wc2btZ@D=X564f?}1ldy++2kP98#CHb~66ZbV6I0U;% z?QrDrq)%z*Zs5;SomqfU^Ne;+Vl|>)l(49g8fFvC{WM)IVC|YdKhTHv3yJ=Dx2(BS zW*~m-RKJWZb-m*KNjb)&iKHa-&Ts5-?nu8@PRXYN9XMSvTc2X%!2pI zBJLj{1?}JF@<~65v8Q^N`(+95khg|Bmj@Vc#cY;z#)daxHekF7v$?J_HoOJ10pl&0 z%?+Kg@g!yg#v9mEh17FL!d#6H)kG>(nAO491-twa}o4@*6b|n7*<-m6t diff --git a/tests/tests_main.c b/tests/tests_main.c index ee6768b3..c144ead6 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -64,8 +64,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); - registerTest(triangleTest, "Triangle Test"); - // registerTest(meshTest, "Mesh Test"); // TODO: add dxil shaders + // registerTest(triangleTest, "Triangle Test"); + registerTest(meshTest, "Mesh Test"); // TODO: add dxil shaders // registerTest(textureTest, "Texture Test"); #endif // From 103608bca1915da245164b5e454cdc32324d4baf Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 29 Apr 2026 16:25:35 +0000 Subject: [PATCH 190/372] texture test: remove shader files dependency and embed shader sources and bytecode into source file --- tests/graphics/shaders.h | 777 +++++++++++++++++- .../graphics/shaders/texture_frag_shader.dxil | Bin 3812 -> 0 bytes .../graphics/shaders/texture_frag_shader.glsl | 14 - .../graphics/shaders/texture_frag_shader.hlsl | 14 - .../graphics/shaders/texture_frag_shader.spv | Bin 684 -> 0 bytes .../graphics/shaders/texture_vert_shader.dxil | Bin 3100 -> 0 bytes .../graphics/shaders/texture_vert_shader.glsl | 13 - .../graphics/shaders/texture_vert_shader.hlsl | 20 - .../graphics/shaders/texture_vert_shader.spv | Bin 1044 -> 0 bytes tests/graphics/texture_test.c | 72 +- tests/tests_main.c | 4 +- 11 files changed, 797 insertions(+), 117 deletions(-) delete mode 100644 tests/graphics/shaders/texture_frag_shader.dxil delete mode 100644 tests/graphics/shaders/texture_frag_shader.glsl delete mode 100644 tests/graphics/shaders/texture_frag_shader.hlsl delete mode 100644 tests/graphics/shaders/texture_frag_shader.spv delete mode 100644 tests/graphics/shaders/texture_vert_shader.dxil delete mode 100644 tests/graphics/shaders/texture_vert_shader.glsl delete mode 100644 tests/graphics/shaders/texture_vert_shader.hlsl delete mode 100644 tests/graphics/shaders/texture_vert_shader.spv diff --git a/tests/graphics/shaders.h b/tests/graphics/shaders.h index 3dfea5e1..39c4b9d0 100644 --- a/tests/graphics/shaders.h +++ b/tests/graphics/shaders.h @@ -1,5 +1,5 @@ -#include +#include "pal/pal_core.h" // clang-format off @@ -61,7 +61,7 @@ // outBuffer.Store4(offset, asuint(pc.color)); // } -static const uint32_t s_ComputeShaderSpv[] = { +static const Uint32 s_ComputeShaderSpv[] = { 0x07230203, 0x00010000, 0x0008000b, 0x00000043, 0x00000000, 0x00020011, 0x00000001, 0x0006000b, 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, @@ -171,7 +171,7 @@ static const uint32_t s_ComputeShaderSpv[] = { 0x000100fd, 0x00010038 }; -static const uint8_t s_ComputeShaderDxil[] = { +static const Uint8 s_ComputeShaderDxil[] = { 0x44, 0x58, 0x42, 0x43, 0x3c, 0x03, 0x02, 0xb3, 0x0e, 0x59, 0xfb, 0x9b, 0xc1, 0xd2, 0x75, 0x12, 0xb3, 0x0d, 0x3c, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x58, 0x0d, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, @@ -700,7 +700,7 @@ static const Uint32 s_RaygenShaderSpv[] = { 0x0000006a, 0x000100fd, 0x00010038 }; -static const uint32_t s_ClosestHitShaderSpv[] = { +static const Uint32 s_ClosestHitShaderSpv[] = { 0x07230203, 0x00010600, 0x0008000b, 0x0000000d, 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, @@ -727,7 +727,7 @@ static const uint32_t s_ClosestHitShaderSpv[] = { 0x00010038 }; -static const uint32_t s_MissShaderSpv[] = { +static const Uint32 s_MissShaderSpv[] = { 0x07230203, 0x00010600, 0x0008000b, 0x0000000c, 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, @@ -1467,7 +1467,7 @@ static const Uint32 s_TriangleFragShaderDxil[] = { // HLSL -static const uint32_t s_MeshShaderSpv[] = { +static const Uint32 s_MeshShaderSpv[] = { 0x07230203, 0x00010600, 0x0008000b, 0x00000039, 0x00000000, 0x00020011, 0x000014a3, 0x0006000a, 0x5f565053, 0x5f545845, 0x6873656d, 0x6168735f, @@ -1584,4 +1584,769 @@ static const uint32_t s_MeshShaderSpv[] = { // Texture // ================================================== +// GLSL +// Vertex +// #version 450 + +// layout(location = 0) in vec2 aPosition; +// layout(location = 1) in vec2 aTexCoord; + +// layout(location = 0) out vec2 vTexCoord; + +// void main() +// { +// gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); +// vTexCoord = aTexCoord; +// } + +// Fragment +// #version 450 + +// layout(set = 0, binding = 0) uniform texture2D tex; +// layout(set = 0, binding = 0) uniform sampler samp; + +// layout(location = 0) in vec2 aTexCoord; + +// layout(location = 0) out vec4 color; + +// void main() +// { +// color = texture(sampler2D(tex, samp), aTexCoord); +// } + +// HLSL +// Vertex +// struct VSInput +// { +// float2 pos : POSITION; +// float2 uv : TEXCOORD; +// }; + +// struct VSOutput +// { +// float4 pos : SV_POSITION; +// float2 uv : TEXCOORD; +// }; + +// VSOutput main(VSInput input) +// { +// VSOutput output; +// output.pos = float4(input.pos, 0.0, 1.0); +// output.uv = input.uv; +// return output; +// } + +// Fragment +// Texture2D tex : register(t0); +// SamplerState samp : register(s0); + +// struct PSInput +// { +// float4 pos : SV_POSITION; +// float2 uv : TEXCOORD; +// }; + +// float4 main(PSInput input) : SV_Target +// { +// return tex.Sample(samp, input.uv); +// } + +static const Uint32 s_TextureVertShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x00000023, + 0x00000000, 0x00020011, 0x00000001, 0x0006000b, + 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, + 0x0009000f, 0x00000000, 0x00000004, 0x6e69616d, + 0x00000000, 0x0000000d, 0x00000012, 0x00000020, + 0x00000021, 0x00030003, 0x00000002, 0x000001c2, + 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, + 0x00060005, 0x0000000b, 0x505f6c67, 0x65567265, + 0x78657472, 0x00000000, 0x00060006, 0x0000000b, + 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69, + 0x00070006, 0x0000000b, 0x00000001, 0x505f6c67, + 0x746e696f, 0x657a6953, 0x00000000, 0x00070006, + 0x0000000b, 0x00000002, 0x435f6c67, 0x4470696c, + 0x61747369, 0x0065636e, 0x00070006, 0x0000000b, + 0x00000003, 0x435f6c67, 0x446c6c75, 0x61747369, + 0x0065636e, 0x00030005, 0x0000000d, 0x00000000, + 0x00050005, 0x00000012, 0x736f5061, 0x6f697469, + 0x0000006e, 0x00050005, 0x00000020, 0x78655476, + 0x726f6f43, 0x00000064, 0x00050005, 0x00000021, + 0x78655461, 0x726f6f43, 0x00000064, 0x00030047, + 0x0000000b, 0x00000002, 0x00050048, 0x0000000b, + 0x00000000, 0x0000000b, 0x00000000, 0x00050048, + 0x0000000b, 0x00000001, 0x0000000b, 0x00000001, + 0x00050048, 0x0000000b, 0x00000002, 0x0000000b, + 0x00000003, 0x00050048, 0x0000000b, 0x00000003, + 0x0000000b, 0x00000004, 0x00040047, 0x00000012, + 0x0000001e, 0x00000000, 0x00040047, 0x00000020, + 0x0000001e, 0x00000000, 0x00040047, 0x00000021, + 0x0000001e, 0x00000001, 0x00020013, 0x00000002, + 0x00030021, 0x00000003, 0x00000002, 0x00030016, + 0x00000006, 0x00000020, 0x00040017, 0x00000007, + 0x00000006, 0x00000004, 0x00040015, 0x00000008, + 0x00000020, 0x00000000, 0x0004002b, 0x00000008, + 0x00000009, 0x00000001, 0x0004001c, 0x0000000a, + 0x00000006, 0x00000009, 0x0006001e, 0x0000000b, + 0x00000007, 0x00000006, 0x0000000a, 0x0000000a, + 0x00040020, 0x0000000c, 0x00000003, 0x0000000b, + 0x0004003b, 0x0000000c, 0x0000000d, 0x00000003, + 0x00040015, 0x0000000e, 0x00000020, 0x00000001, + 0x0004002b, 0x0000000e, 0x0000000f, 0x00000000, + 0x00040017, 0x00000010, 0x00000006, 0x00000002, + 0x00040020, 0x00000011, 0x00000001, 0x00000010, + 0x0004003b, 0x00000011, 0x00000012, 0x00000001, + 0x0004002b, 0x00000008, 0x00000013, 0x00000000, + 0x00040020, 0x00000014, 0x00000001, 0x00000006, + 0x0004002b, 0x00000006, 0x0000001a, 0x00000000, + 0x0004002b, 0x00000006, 0x0000001b, 0x3f800000, + 0x00040020, 0x0000001d, 0x00000003, 0x00000007, + 0x00040020, 0x0000001f, 0x00000003, 0x00000010, + 0x0004003b, 0x0000001f, 0x00000020, 0x00000003, + 0x0004003b, 0x00000011, 0x00000021, 0x00000001, + 0x00050036, 0x00000002, 0x00000004, 0x00000000, + 0x00000003, 0x000200f8, 0x00000005, 0x00050041, + 0x00000014, 0x00000015, 0x00000012, 0x00000013, + 0x0004003d, 0x00000006, 0x00000016, 0x00000015, + 0x00050041, 0x00000014, 0x00000017, 0x00000012, + 0x00000009, 0x0004003d, 0x00000006, 0x00000018, + 0x00000017, 0x0004007f, 0x00000006, 0x00000019, + 0x00000018, 0x00070050, 0x00000007, 0x0000001c, + 0x00000016, 0x00000019, 0x0000001a, 0x0000001b, + 0x00050041, 0x0000001d, 0x0000001e, 0x0000000d, + 0x0000000f, 0x0003003e, 0x0000001e, 0x0000001c, + 0x0004003d, 0x00000010, 0x00000022, 0x00000021, + 0x0003003e, 0x00000020, 0x00000022, 0x000100fd, + 0x00010038 +}; + +static const Uint32 s_TextureFragShaderSpv[] = { + 0x07230203, 0x00010600, 0x0008000b, 0x00000019, + 0x00000000, 0x00020011, 0x00000001, 0x0006000b, + 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, + 0x00000000, 0x0003000e, 0x00000000, 0x00000001, + 0x0009000f, 0x00000004, 0x00000004, 0x6e69616d, + 0x00000000, 0x00000009, 0x0000000c, 0x00000010, + 0x00000016, 0x00030010, 0x00000004, 0x00000007, + 0x00030003, 0x00000002, 0x000001c2, 0x00040005, + 0x00000004, 0x6e69616d, 0x00000000, 0x00040005, + 0x00000009, 0x6f6c6f63, 0x00000072, 0x00030005, + 0x0000000c, 0x00786574, 0x00040005, 0x00000010, + 0x706d6173, 0x00000000, 0x00050005, 0x00000016, + 0x78655461, 0x726f6f43, 0x00000064, 0x00040047, + 0x00000009, 0x0000001e, 0x00000000, 0x00040047, + 0x0000000c, 0x00000021, 0x00000000, 0x00040047, + 0x0000000c, 0x00000022, 0x00000000, 0x00040047, + 0x00000010, 0x00000021, 0x00000000, 0x00040047, + 0x00000010, 0x00000022, 0x00000000, 0x00040047, + 0x00000016, 0x0000001e, 0x00000000, 0x00020013, + 0x00000002, 0x00030021, 0x00000003, 0x00000002, + 0x00030016, 0x00000006, 0x00000020, 0x00040017, + 0x00000007, 0x00000006, 0x00000004, 0x00040020, + 0x00000008, 0x00000003, 0x00000007, 0x0004003b, + 0x00000008, 0x00000009, 0x00000003, 0x00090019, + 0x0000000a, 0x00000006, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000001, 0x00000000, + 0x00040020, 0x0000000b, 0x00000000, 0x0000000a, + 0x0004003b, 0x0000000b, 0x0000000c, 0x00000000, + 0x0002001a, 0x0000000e, 0x00040020, 0x0000000f, + 0x00000000, 0x0000000e, 0x0004003b, 0x0000000f, + 0x00000010, 0x00000000, 0x0003001b, 0x00000012, + 0x0000000a, 0x00040017, 0x00000014, 0x00000006, + 0x00000002, 0x00040020, 0x00000015, 0x00000001, + 0x00000014, 0x0004003b, 0x00000015, 0x00000016, + 0x00000001, 0x00050036, 0x00000002, 0x00000004, + 0x00000000, 0x00000003, 0x000200f8, 0x00000005, + 0x0004003d, 0x0000000a, 0x0000000d, 0x0000000c, + 0x0004003d, 0x0000000e, 0x00000011, 0x00000010, + 0x00050056, 0x00000012, 0x00000013, 0x0000000d, + 0x00000011, 0x0004003d, 0x00000014, 0x00000017, + 0x00000016, 0x00050057, 0x00000007, 0x00000018, + 0x00000013, 0x00000017, 0x0003003e, 0x00000009, + 0x00000018, 0x000100fd, 0x00010038 +}; + +static const Uint8 s_TextureVertShaderDxil[] = { + 0x44, 0x58, 0x42, 0x43, 0xdb, 0x6c, 0x1e, 0xc3, 0xee, 0xcf, 0xaa, 0xf4, + 0xd8, 0x2f, 0xf2, 0x94, 0x92, 0xb5, 0x75, 0xcb, 0x01, 0x00, 0x00, 0x00, + 0x1c, 0x0c, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, + 0xf0, 0x01, 0x00, 0x00, 0xd4, 0x06, 0x00, 0x00, 0xf0, 0x06, 0x00, 0x00, + 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x5c, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x54, 0x45, 0x58, + 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, + 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, + 0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0xd0, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, + 0x4e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x54, + 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x6d, 0x61, 0x69, 0x6e, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x42, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x42, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, + 0x03, 0x04, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x42, 0x00, 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xdc, 0x04, 0x00, 0x00, + 0x60, 0x00, 0x01, 0x00, 0x37, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xc4, 0x04, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, + 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, + 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, + 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, + 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, + 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x19, + 0x80, 0x39, 0x02, 0x30, 0x98, 0x23, 0x40, 0x8a, 0x31, 0x44, 0x54, 0x44, + 0x56, 0x0c, 0x20, 0xa2, 0x1a, 0xc2, 0x81, 0x80, 0x44, 0x20, 0x00, 0x00, + 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, + 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, + 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, + 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, + 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, + 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, + 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, + 0x0c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, + 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xa2, 0x12, 0x18, 0x01, 0x28, + 0x86, 0x32, 0x28, 0x8f, 0xb2, 0x28, 0x04, 0xaa, 0x92, 0x18, 0x01, 0x28, + 0x82, 0x32, 0x28, 0x04, 0xda, 0xb1, 0x10, 0xc3, 0x08, 0x04, 0x00, 0x80, + 0xc0, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, + 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, + 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, + 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb1, 0xa9, 0x81, 0x01, 0x41, 0xa1, 0xc9, + 0x21, 0x8b, 0x09, 0x2b, 0xcb, 0x09, 0x83, 0x49, 0xd9, 0x10, 0x04, 0x13, + 0x04, 0x62, 0x98, 0x20, 0x10, 0xc4, 0x06, 0x61, 0x20, 0x36, 0x08, 0x04, + 0x41, 0xc1, 0x6e, 0x6e, 0x82, 0x40, 0x14, 0x1b, 0x86, 0x03, 0x21, 0x26, + 0x08, 0x02, 0xb0, 0x01, 0xd8, 0x30, 0x10, 0xcb, 0xb2, 0x21, 0x60, 0x36, + 0x0c, 0x83, 0xd2, 0x4c, 0x10, 0x96, 0x67, 0x43, 0xf0, 0x90, 0x68, 0x0b, + 0x4b, 0x73, 0x23, 0x02, 0xf5, 0x34, 0x95, 0x44, 0x95, 0xf4, 0xe4, 0x34, + 0x41, 0x28, 0x94, 0x09, 0x42, 0xb1, 0x6c, 0x08, 0x88, 0x09, 0x42, 0xc1, + 0x4c, 0x10, 0x08, 0x63, 0x83, 0x70, 0x5d, 0x1b, 0x16, 0x42, 0x9a, 0xa8, + 0x8a, 0x1a, 0x2c, 0x82, 0xc2, 0x88, 0x50, 0x15, 0x61, 0x0d, 0x3d, 0x3d, + 0x49, 0x11, 0x6d, 0x58, 0x06, 0x6d, 0xa2, 0x2a, 0x6a, 0xb0, 0x06, 0x0a, + 0xdb, 0x20, 0x64, 0x1b, 0x97, 0x29, 0xab, 0x2f, 0xa8, 0xb7, 0xb9, 0x34, + 0xba, 0xb4, 0x37, 0xb7, 0x09, 0x42, 0xd1, 0x4c, 0x10, 0x0a, 0x67, 0x82, + 0x40, 0x1c, 0x1b, 0x84, 0x0b, 0x0c, 0x36, 0x2c, 0x44, 0x37, 0x79, 0xd5, + 0x37, 0x7c, 0x04, 0x15, 0x06, 0x1b, 0x96, 0x41, 0x9b, 0xa8, 0xca, 0x1a, + 0xac, 0x81, 0xc2, 0x36, 0x08, 0x62, 0x30, 0x06, 0x1b, 0x06, 0x8e, 0x0c, + 0x80, 0x0d, 0x85, 0x12, 0x95, 0x01, 0x00, 0xb0, 0x48, 0x73, 0x9b, 0xa3, + 0x9b, 0x9b, 0x20, 0x10, 0x08, 0x8d, 0xb9, 0xb4, 0xb3, 0x2f, 0x36, 0xb2, + 0x09, 0x02, 0x91, 0xd0, 0x98, 0x4b, 0x3b, 0xfb, 0x9a, 0xa3, 0xdb, 0x60, + 0x9c, 0x01, 0x1a, 0xa4, 0x81, 0x1a, 0xac, 0x01, 0x52, 0x85, 0x8d, 0xcd, + 0xae, 0xcd, 0x25, 0x8d, 0xac, 0xcc, 0x8d, 0x6e, 0x4a, 0x10, 0x54, 0x21, + 0xc3, 0x73, 0xb1, 0x2b, 0x93, 0x9b, 0x4b, 0x7b, 0x73, 0x9b, 0x12, 0x10, + 0x4d, 0xc8, 0xf0, 0x5c, 0xec, 0xc2, 0xd8, 0xec, 0xca, 0xe4, 0xa6, 0x04, + 0x45, 0x1d, 0x32, 0x3c, 0x97, 0x39, 0xb4, 0x30, 0xb2, 0x32, 0xb9, 0xa6, + 0x37, 0xb2, 0x32, 0xb6, 0x29, 0x01, 0x52, 0x89, 0x0c, 0xcf, 0x85, 0x2e, + 0x0f, 0xae, 0x2c, 0xc8, 0xcd, 0xed, 0x8d, 0x2e, 0x8c, 0x2e, 0xed, 0xcd, + 0x6d, 0x6e, 0x4a, 0xd0, 0xd4, 0x21, 0xc3, 0x73, 0xb1, 0x4b, 0x2b, 0xbb, + 0x4b, 0x22, 0x9b, 0xa2, 0x0b, 0xa3, 0x2b, 0x9b, 0x12, 0x3c, 0x75, 0xc8, + 0xf0, 0x5c, 0xca, 0xdc, 0xe8, 0xe4, 0xf2, 0xa0, 0xde, 0xd2, 0xdc, 0xe8, + 0xe6, 0xa6, 0x04, 0x65, 0xd0, 0x85, 0x0c, 0xcf, 0x65, 0xec, 0xad, 0xce, + 0x8d, 0xae, 0x4c, 0x6e, 0x6e, 0x4a, 0xb0, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, + 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, + 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, + 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, + 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, + 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, + 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, + 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, + 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, + 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, + 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, + 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, + 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, + 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, + 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, + 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, + 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, + 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, + 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, + 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, + 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, + 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, + 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, + 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, + 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, + 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00, + 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x16, 0x30, 0x0d, 0x97, + 0xef, 0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, 0xd4, 0xe4, 0x17, 0xb7, + 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, + 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x15, 0xb4, 0x1e, + 0xd4, 0xa9, 0x01, 0x22, 0xa4, 0x39, 0x8a, 0x77, 0x38, 0x83, 0x01, 0xd3, + 0x44, 0x58, 0x49, 0x4c, 0x24, 0x05, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, + 0x49, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0c, 0x05, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, + 0x21, 0x0c, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, + 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, + 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, + 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, + 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, + 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, + 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, + 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, + 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, + 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, + 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, + 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x19, 0x80, 0x39, 0x02, 0x30, + 0x98, 0x23, 0x40, 0x8a, 0x31, 0x44, 0x54, 0x44, 0x56, 0x0c, 0x20, 0xa2, + 0x1a, 0xc2, 0x81, 0x80, 0x44, 0x20, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, + 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, + 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, + 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, + 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, + 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, + 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, + 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, + 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, + 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, + 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, 0x0c, 0x00, 0x00, 0x00, + 0x32, 0x1e, 0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, + 0xc6, 0x04, 0x43, 0xa2, 0x12, 0x18, 0x01, 0x28, 0x89, 0x62, 0x28, 0x83, + 0xf2, 0xa0, 0x2a, 0x89, 0x11, 0x80, 0x22, 0x28, 0x83, 0x42, 0xa0, 0x1d, + 0x0b, 0x31, 0x8c, 0x40, 0x00, 0x00, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, + 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, + 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, + 0xa1, 0xb1, 0xa9, 0x81, 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, + 0xcb, 0x09, 0x83, 0x49, 0xd9, 0x10, 0x04, 0x13, 0x04, 0x62, 0x98, 0x20, + 0x10, 0xc4, 0x06, 0x61, 0x20, 0x26, 0x08, 0x44, 0xb1, 0x41, 0x18, 0x0c, + 0x0a, 0x76, 0x73, 0x13, 0x04, 0xc2, 0xd8, 0x30, 0x20, 0x09, 0x31, 0x41, + 0x58, 0x9c, 0x0d, 0xc1, 0x32, 0x41, 0x10, 0x00, 0x12, 0x6d, 0x61, 0x69, + 0x6e, 0x44, 0xa0, 0x9e, 0xa6, 0x92, 0xa8, 0x92, 0x9e, 0x9c, 0x26, 0x08, + 0x45, 0x32, 0x41, 0x28, 0x94, 0x0d, 0x01, 0x31, 0x41, 0x28, 0x96, 0x09, + 0x02, 0x71, 0x6c, 0x10, 0x28, 0x6a, 0xc3, 0x42, 0x3c, 0x50, 0x24, 0x45, + 0xc3, 0x44, 0x44, 0x15, 0x11, 0xaa, 0x22, 0xac, 0xa1, 0xa7, 0x27, 0x29, + 0xa2, 0x0d, 0xcb, 0x70, 0x41, 0x91, 0x14, 0x0d, 0xd3, 0x10, 0x55, 0x1b, + 0x04, 0x0b, 0xe3, 0x32, 0x65, 0xf5, 0x05, 0xf5, 0x36, 0x97, 0x46, 0x97, + 0xf6, 0xe6, 0x36, 0x41, 0x28, 0x98, 0x09, 0x42, 0xd1, 0x4c, 0x10, 0x08, + 0x64, 0x83, 0x40, 0x75, 0x1b, 0x16, 0x42, 0x83, 0x36, 0x89, 0x1b, 0x38, + 0x22, 0xf2, 0x36, 0x2c, 0xc3, 0x05, 0x45, 0xd2, 0x34, 0x4c, 0x43, 0x54, + 0x6d, 0x10, 0x3e, 0x30, 0xd8, 0x30, 0x64, 0x61, 0x00, 0x6c, 0x28, 0x1a, + 0x47, 0x0c, 0x00, 0xa0, 0x0a, 0x1b, 0x9b, 0x5d, 0x9b, 0x4b, 0x1a, 0x59, + 0x99, 0x1b, 0xdd, 0x94, 0x20, 0xa8, 0x42, 0x86, 0xe7, 0x62, 0x57, 0x26, + 0x37, 0x97, 0xf6, 0xe6, 0x36, 0x25, 0x20, 0x9a, 0x90, 0xe1, 0xb9, 0xd8, + 0x85, 0xb1, 0xd9, 0x95, 0xc9, 0x4d, 0x09, 0x8c, 0x3a, 0x64, 0x78, 0x2e, + 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, + 0x82, 0xa4, 0x0e, 0x19, 0x9e, 0x8b, 0x5d, 0x5a, 0xd9, 0x5d, 0x12, 0xd9, + 0x14, 0x5d, 0x18, 0x5d, 0xd9, 0x94, 0x60, 0xa9, 0x43, 0x86, 0xe7, 0x52, + 0xe6, 0x46, 0x27, 0x97, 0x07, 0xf5, 0x96, 0xe6, 0x46, 0x37, 0x37, 0x25, + 0x10, 0x03, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, + 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, + 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, + 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, + 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, + 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, + 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, + 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, + 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, + 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, + 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, + 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, + 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, + 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, + 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, + 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, + 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, + 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, + 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, + 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, + 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, + 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, + 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, + 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, + 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, + 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x16, 0x30, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, + 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, + 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, + 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, + 0x26, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x54, 0x25, 0x40, 0x34, 0x03, 0x50, 0x0a, 0x85, + 0x40, 0x33, 0x46, 0x00, 0x82, 0x20, 0x88, 0x7f, 0x23, 0x00, 0x00, 0x00, + 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x60, 0x50, 0x83, 0x14, 0x2d, 0xc5, + 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x15, 0x31, 0x49, 0x87, 0x31, + 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x86, 0x55, 0x4c, 0x53, 0x73, 0x8c, + 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0x71, 0x19, 0x14, 0x95, 0x20, 0x23, + 0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x5c, 0x48, 0x55, 0x3d, 0xc2, 0x88, + 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x17, 0x52, 0x55, 0x4a, 0x30, 0x62, + 0x90, 0x00, 0x20, 0x08, 0x06, 0xc8, 0x85, 0x54, 0x95, 0x53, 0x8c, 0x18, + 0x24, 0x00, 0x08, 0x82, 0x01, 0x72, 0x21, 0x55, 0xd5, 0x18, 0x23, 0x06, + 0x09, 0x00, 0x82, 0x60, 0x80, 0x5c, 0x88, 0x55, 0x3d, 0xc4, 0x88, 0x41, + 0x02, 0x80, 0x20, 0x18, 0x20, 0x17, 0x62, 0x55, 0xca, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +static const Uint8 s_TextureFragShaderDxil[] = { + 0x44, 0x58, 0x42, 0x43, 0xb9, 0x47, 0xea, 0x75, 0x37, 0x83, 0x8c, 0xf3, + 0xbe, 0xa0, 0x73, 0xc4, 0x09, 0x85, 0x21, 0xae, 0x01, 0x00, 0x00, 0x00, + 0xe4, 0x0e, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, + 0xd8, 0x01, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00, 0x50, 0x08, 0x00, 0x00, + 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x60, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, + 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x00, 0x00, 0x00, + 0x4f, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0x00, 0x00, + 0x50, 0x53, 0x56, 0x30, 0xe0, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, + 0x44, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x42, 0x00, + 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x44, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0x54, 0x06, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x95, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x06, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, + 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff, + 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, + 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, + 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x68, 0x23, 0x00, 0x25, 0x00, 0x14, 0x66, + 0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x20, 0x84, 0x14, + 0x42, 0xa6, 0x18, 0x80, 0x10, 0x52, 0x06, 0xa1, 0x9b, 0x86, 0xcb, 0x9f, + 0xb0, 0x87, 0x90, 0xfc, 0x95, 0x90, 0x56, 0x62, 0xf2, 0x8b, 0xdb, 0x46, + 0xc5, 0x18, 0x63, 0x10, 0x2a, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, + 0xf9, 0x21, 0xd0, 0x0c, 0x0b, 0x81, 0x82, 0x55, 0x18, 0x45, 0x18, 0x1b, + 0x63, 0x0c, 0x42, 0xc8, 0xa0, 0x36, 0x47, 0x10, 0x14, 0x83, 0x91, 0x42, + 0xc8, 0x23, 0x38, 0x10, 0x30, 0x8c, 0x40, 0x0c, 0x33, 0xb5, 0xc1, 0x38, + 0xb0, 0x43, 0x38, 0xcc, 0xc3, 0x3c, 0xb8, 0x01, 0x2d, 0x94, 0x03, 0x3e, + 0xd0, 0x43, 0x3d, 0xc8, 0x43, 0x39, 0xc8, 0x01, 0x29, 0xf0, 0x81, 0x3d, + 0x94, 0xc3, 0x38, 0xd0, 0xc3, 0x3b, 0xc8, 0x03, 0x1f, 0x98, 0x03, 0x3b, + 0xbc, 0x43, 0x38, 0xd0, 0x03, 0x1b, 0x80, 0x01, 0x1d, 0xf8, 0x01, 0x18, + 0xf8, 0x81, 0x1e, 0xe8, 0x41, 0x3b, 0xa4, 0x03, 0x3c, 0xcc, 0xc3, 0x2f, + 0xd0, 0x43, 0x3e, 0xc0, 0x43, 0x39, 0xa0, 0x80, 0xcc, 0x24, 0x06, 0xe3, + 0xc0, 0x0e, 0xe1, 0x30, 0x0f, 0xf3, 0xe0, 0x06, 0xb4, 0x50, 0x0e, 0xf8, + 0x40, 0x0f, 0xf5, 0x20, 0x0f, 0xe5, 0x20, 0x07, 0xa4, 0xc0, 0x07, 0xf6, + 0x50, 0x0e, 0xe3, 0x40, 0x0f, 0xef, 0x20, 0x0f, 0x7c, 0x60, 0x0e, 0xec, + 0xf0, 0x0e, 0xe1, 0x40, 0x0f, 0x6c, 0x00, 0x06, 0x74, 0xe0, 0x07, 0x60, + 0xe0, 0x07, 0x48, 0x98, 0x94, 0xea, 0x4d, 0xd2, 0x14, 0x51, 0xc2, 0xe4, + 0xb3, 0x00, 0xf3, 0x2c, 0x44, 0xc4, 0x4e, 0xc0, 0x44, 0xa0, 0x80, 0xd0, + 0x4d, 0x04, 0x02, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, + 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, + 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, + 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, + 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, + 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, + 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, + 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, + 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, + 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, + 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0xf2, 0x34, 0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0xe4, 0x81, 0x80, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x0b, 0x04, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, + 0xc6, 0x04, 0x43, 0x22, 0x25, 0x30, 0x02, 0x50, 0x0c, 0x45, 0x50, 0x12, + 0x65, 0x50, 0x1e, 0xc5, 0x51, 0x08, 0x54, 0x4a, 0xa2, 0x0c, 0x0a, 0x61, + 0x04, 0xa0, 0x08, 0x0a, 0x84, 0xec, 0x0c, 0x00, 0xe1, 0x19, 0x00, 0xca, + 0x63, 0x21, 0x06, 0x01, 0x00, 0x00, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, + 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, + 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, + 0xa1, 0xb1, 0xa9, 0x81, 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, + 0xcb, 0x09, 0x83, 0x49, 0xd9, 0x10, 0x04, 0x13, 0x04, 0xa2, 0x98, 0x20, + 0x10, 0xc6, 0x06, 0x61, 0x20, 0x36, 0x08, 0x04, 0x41, 0x01, 0x6e, 0x6e, + 0x82, 0x40, 0x1c, 0x1b, 0x86, 0x03, 0x21, 0x26, 0x08, 0x16, 0xc5, 0x81, + 0xae, 0x0c, 0x6f, 0x82, 0x40, 0x20, 0x13, 0x04, 0x22, 0xd9, 0x20, 0x10, + 0xcd, 0x86, 0x84, 0x50, 0x16, 0x82, 0x18, 0x18, 0xc2, 0xd9, 0x10, 0x3c, + 0x13, 0x04, 0xac, 0x22, 0x31, 0x17, 0xd6, 0x06, 0xb7, 0x01, 0x21, 0x22, + 0x89, 0x20, 0x06, 0x02, 0xd8, 0x10, 0x4c, 0x1b, 0x08, 0x08, 0x00, 0xa8, + 0x09, 0x82, 0x00, 0x6c, 0x00, 0x36, 0x0c, 0xc4, 0x75, 0x6d, 0x08, 0xb0, + 0x0d, 0xc3, 0x60, 0x65, 0x13, 0x84, 0xcc, 0xda, 0x10, 0x6c, 0x24, 0xda, + 0xc2, 0xd2, 0xdc, 0xb8, 0x4c, 0x59, 0x7d, 0x41, 0xbd, 0xcd, 0xa5, 0xd1, + 0xa5, 0xbd, 0xb9, 0x4d, 0x10, 0x0a, 0x67, 0x82, 0x50, 0x3c, 0x1b, 0x02, + 0x62, 0x82, 0x50, 0x40, 0x13, 0x84, 0x22, 0xda, 0xb0, 0x10, 0xde, 0x07, + 0x06, 0x61, 0x20, 0x06, 0x83, 0x18, 0x10, 0x63, 0x00, 0x10, 0xa1, 0x2a, + 0xc2, 0x1a, 0x7a, 0x7a, 0x92, 0x22, 0x9a, 0x20, 0x14, 0xd2, 0x04, 0x81, + 0x50, 0x36, 0x08, 0x67, 0x70, 0x06, 0x1b, 0x96, 0xa1, 0x0c, 0xbe, 0x31, + 0x08, 0x03, 0x33, 0x18, 0xcc, 0x60, 0x18, 0x03, 0x34, 0xd8, 0x20, 0x90, + 0x41, 0x1a, 0x30, 0x99, 0xb2, 0xfa, 0xa2, 0x0a, 0x93, 0x3b, 0x2b, 0xa3, + 0x9b, 0x20, 0x14, 0xd3, 0x04, 0x81, 0x58, 0x36, 0x08, 0x67, 0xd0, 0x06, + 0x1b, 0x16, 0x62, 0x0d, 0x3e, 0x36, 0x08, 0x83, 0x31, 0x18, 0xc4, 0x80, + 0x18, 0x03, 0x37, 0xd8, 0x10, 0xbc, 0xc1, 0x86, 0x41, 0x0d, 0xe0, 0x00, + 0xd8, 0x50, 0x58, 0x5d, 0x1c, 0x54, 0x00, 0x8b, 0x34, 0xb7, 0x39, 0xba, + 0xb9, 0x09, 0x02, 0xc1, 0xd0, 0x98, 0x4b, 0x3b, 0xfb, 0x62, 0x23, 0xa3, + 0x31, 0x97, 0x76, 0xf6, 0x35, 0x47, 0x37, 0x41, 0x20, 0x1a, 0x22, 0x74, + 0x65, 0x78, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x1b, 0x90, 0x39, 0xa0, 0x83, + 0x3a, 0x60, 0xec, 0xe0, 0x0e, 0xf0, 0x60, 0xa8, 0xc2, 0xc6, 0x66, 0xd7, + 0xe6, 0x92, 0x46, 0x56, 0xe6, 0x46, 0x37, 0x25, 0x08, 0xaa, 0x90, 0xe1, + 0xb9, 0xd8, 0x95, 0xc9, 0xcd, 0xa5, 0xbd, 0xb9, 0x4d, 0x09, 0x88, 0x26, + 0x64, 0x78, 0x2e, 0x76, 0x61, 0x6c, 0x76, 0x65, 0x72, 0x53, 0x82, 0xa2, + 0x0e, 0x19, 0x9e, 0xcb, 0x1c, 0x5a, 0x18, 0x59, 0x99, 0x5c, 0xd3, 0x1b, + 0x59, 0x19, 0xdb, 0x94, 0x00, 0x29, 0x43, 0x86, 0xe7, 0x22, 0x57, 0x36, + 0xf7, 0x56, 0x27, 0x37, 0x56, 0x36, 0x37, 0x25, 0xa0, 0x2a, 0x91, 0xe1, + 0xb9, 0xd0, 0xe5, 0xc1, 0x95, 0x05, 0xb9, 0xb9, 0xbd, 0xd1, 0x85, 0xd1, + 0xa5, 0xbd, 0xb9, 0xcd, 0x4d, 0x09, 0xb2, 0x3a, 0x64, 0x78, 0x2e, 0x76, + 0x69, 0x65, 0x77, 0x49, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x82, + 0xad, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, + 0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0x20, 0x0e, 0xba, 0x90, 0xe1, 0xb9, 0x8c, + 0xbd, 0xd5, 0xb9, 0xd1, 0x95, 0xc9, 0xcd, 0x4d, 0x09, 0xf0, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, + 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, + 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, + 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, + 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, + 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, + 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, + 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, + 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, + 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, + 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, + 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, + 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, + 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, + 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, + 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, + 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, + 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, + 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, + 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, + 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, + 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, + 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, + 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, + 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, + 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, + 0x71, 0x20, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x46, 0x20, 0x0d, 0x97, + 0xef, 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, 0x33, 0x2c, 0x84, + 0x05, 0x4c, 0xc3, 0xe5, 0x3b, 0x8f, 0xbf, 0x38, 0xc0, 0x20, 0x36, 0x0f, + 0x35, 0xf9, 0xc5, 0x6d, 0xdb, 0x00, 0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x12, + 0xc0, 0x3c, 0x0b, 0xe1, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, + 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, + 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7a, 0xec, 0xd5, 0xe9, 0x4e, 0x1e, 0x68, 0xfc, 0xf3, 0x76, 0xff, 0x47, + 0x16, 0xeb, 0xad, 0xd5, 0x44, 0x58, 0x49, 0x4c, 0x8c, 0x06, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x74, 0x06, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, + 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff, + 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, + 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, + 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x68, 0x23, 0x00, 0x25, 0x00, 0x14, 0x66, + 0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x20, 0x84, 0x14, + 0x42, 0xa6, 0x18, 0x80, 0x10, 0x52, 0x06, 0xa1, 0x9b, 0x86, 0xcb, 0x9f, + 0xb0, 0x87, 0x90, 0xfc, 0x95, 0x90, 0x56, 0x62, 0xf2, 0x8b, 0xdb, 0x46, + 0xc5, 0x18, 0x63, 0x10, 0x2a, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, + 0xf9, 0x21, 0xd0, 0x0c, 0x0b, 0x81, 0x82, 0x55, 0x18, 0x45, 0x18, 0x1b, + 0x63, 0x0c, 0x42, 0xc8, 0xa0, 0x36, 0x47, 0x10, 0x14, 0x83, 0x91, 0x42, + 0xc8, 0x23, 0x38, 0x10, 0x30, 0x8c, 0x40, 0x0c, 0x33, 0xb5, 0xc1, 0x38, + 0xb0, 0x43, 0x38, 0xcc, 0xc3, 0x3c, 0xb8, 0x01, 0x2d, 0x94, 0x03, 0x3e, + 0xd0, 0x43, 0x3d, 0xc8, 0x43, 0x39, 0xc8, 0x01, 0x29, 0xf0, 0x81, 0x3d, + 0x94, 0xc3, 0x38, 0xd0, 0xc3, 0x3b, 0xc8, 0x03, 0x1f, 0x98, 0x03, 0x3b, + 0xbc, 0x43, 0x38, 0xd0, 0x03, 0x1b, 0x80, 0x01, 0x1d, 0xf8, 0x01, 0x18, + 0xf8, 0x81, 0x1e, 0xe8, 0x41, 0x3b, 0xa4, 0x03, 0x3c, 0xcc, 0xc3, 0x2f, + 0xd0, 0x43, 0x3e, 0xc0, 0x43, 0x39, 0xa0, 0x80, 0xcc, 0x24, 0x06, 0xe3, + 0xc0, 0x0e, 0xe1, 0x30, 0x0f, 0xf3, 0xe0, 0x06, 0xb4, 0x50, 0x0e, 0xf8, + 0x40, 0x0f, 0xf5, 0x20, 0x0f, 0xe5, 0x20, 0x07, 0xa4, 0xc0, 0x07, 0xf6, + 0x50, 0x0e, 0xe3, 0x40, 0x0f, 0xef, 0x20, 0x0f, 0x7c, 0x60, 0x0e, 0xec, + 0xf0, 0x0e, 0xe1, 0x40, 0x0f, 0x6c, 0x00, 0x06, 0x74, 0xe0, 0x07, 0x60, + 0xe0, 0x07, 0x48, 0x98, 0x94, 0xea, 0x4d, 0xd2, 0x14, 0x51, 0xc2, 0xe4, + 0xb3, 0x00, 0xf3, 0x2c, 0x44, 0xc4, 0x4e, 0xc0, 0x44, 0xa0, 0x80, 0xd0, + 0x4d, 0x04, 0x02, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, + 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, + 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, + 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, + 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, + 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, + 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, + 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, + 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, + 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, + 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0xf2, 0x34, 0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0xe4, 0x81, 0x80, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x0b, 0x04, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, + 0xc6, 0x04, 0x43, 0x22, 0x25, 0x30, 0x02, 0x50, 0x12, 0xc5, 0x50, 0x04, + 0x65, 0x50, 0x1e, 0x54, 0x4a, 0xa2, 0x0c, 0x0a, 0x61, 0x04, 0xa0, 0x08, + 0x0a, 0x84, 0xec, 0x0c, 0x00, 0xe1, 0x19, 0x00, 0xca, 0x63, 0x21, 0x06, + 0x01, 0x00, 0x00, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x5c, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, + 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, + 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb1, 0xa9, 0x81, + 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, 0xcb, 0x09, 0x83, 0x49, + 0xd9, 0x10, 0x04, 0x13, 0x04, 0xa2, 0x98, 0x20, 0x10, 0xc6, 0x06, 0x61, + 0x20, 0x26, 0x08, 0xc4, 0xb1, 0x41, 0x18, 0x0c, 0x0a, 0x70, 0x73, 0x13, + 0x04, 0x02, 0xd9, 0x30, 0x20, 0x09, 0x31, 0x41, 0xb0, 0x24, 0x02, 0x13, + 0x04, 0x22, 0xd9, 0x20, 0x10, 0xc6, 0x86, 0x84, 0x58, 0x18, 0x82, 0x18, + 0x1a, 0xc2, 0xd9, 0x10, 0x3c, 0x13, 0x04, 0x6c, 0xda, 0x80, 0x10, 0x11, + 0x43, 0x10, 0x03, 0x01, 0x6c, 0x08, 0xa4, 0x0d, 0x04, 0x04, 0x00, 0xd3, + 0x04, 0x21, 0xa3, 0x36, 0x04, 0xd5, 0x04, 0x41, 0x00, 0x48, 0xb4, 0x85, + 0xa5, 0xb9, 0x71, 0x99, 0xb2, 0xfa, 0x82, 0x7a, 0x9b, 0x4b, 0xa3, 0x4b, + 0x7b, 0x73, 0x9b, 0x20, 0x14, 0xcc, 0x04, 0xa1, 0x68, 0x36, 0x04, 0xc4, + 0x04, 0xa1, 0x70, 0x26, 0x08, 0xc5, 0xb3, 0x61, 0x21, 0x32, 0x6d, 0xe3, + 0xba, 0xa1, 0x23, 0x3c, 0x80, 0x08, 0x55, 0x11, 0xd6, 0xd0, 0xd3, 0x93, + 0x14, 0xd1, 0x04, 0xa1, 0x80, 0x26, 0x08, 0x84, 0xb2, 0x41, 0x10, 0x03, + 0x31, 0xd8, 0xb0, 0x0c, 0x60, 0xa0, 0x79, 0x5c, 0x18, 0x0c, 0x61, 0x30, + 0x78, 0x63, 0xb0, 0x41, 0xf8, 0xc8, 0x80, 0xc9, 0x94, 0xd5, 0x17, 0x55, + 0x98, 0xdc, 0x59, 0x19, 0xdd, 0x04, 0xa1, 0x88, 0x26, 0x08, 0xc4, 0xb2, + 0x41, 0x10, 0x03, 0x34, 0xd8, 0xb0, 0x10, 0x66, 0xa0, 0x9d, 0x01, 0xe7, + 0x0d, 0x1d, 0xe1, 0xa5, 0xc1, 0x86, 0x40, 0x0d, 0x36, 0x0c, 0x65, 0xb0, + 0x06, 0xc0, 0x86, 0xe2, 0xc2, 0xd8, 0x80, 0x02, 0xaa, 0xb0, 0xb1, 0xd9, + 0xb5, 0xb9, 0xa4, 0x91, 0x95, 0xb9, 0xd1, 0x4d, 0x09, 0x82, 0x2a, 0x64, + 0x78, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x02, 0xa2, + 0x09, 0x19, 0x9e, 0x8b, 0x5d, 0x18, 0x9b, 0x5d, 0x99, 0xdc, 0x94, 0xc0, + 0xa8, 0x43, 0x86, 0xe7, 0x32, 0x87, 0x16, 0x46, 0x56, 0x26, 0xd7, 0xf4, + 0x46, 0x56, 0xc6, 0x36, 0x25, 0x48, 0xca, 0x90, 0xe1, 0xb9, 0xc8, 0x95, + 0xcd, 0xbd, 0xd5, 0xc9, 0x8d, 0x95, 0xcd, 0x4d, 0x09, 0xa6, 0x3a, 0x64, + 0x78, 0x2e, 0x76, 0x69, 0x65, 0x77, 0x49, 0x64, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x53, 0x82, 0xaa, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, + 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0x80, 0x0d, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, + 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, + 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, + 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, + 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, + 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, + 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, + 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, + 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, + 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, + 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, + 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, + 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, + 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, + 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, + 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, + 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, + 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, + 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, + 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, + 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, + 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, + 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, + 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, + 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, + 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, + 0x71, 0x20, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x46, 0x20, 0x0d, 0x97, + 0xef, 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, 0x33, 0x2c, 0x84, + 0x05, 0x4c, 0xc3, 0xe5, 0x3b, 0x8f, 0xbf, 0x38, 0xc0, 0x20, 0x36, 0x0f, + 0x35, 0xf9, 0xc5, 0x6d, 0xdb, 0x00, 0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x12, + 0xc0, 0x3c, 0x0b, 0xe1, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, + 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, + 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0xf4, 0x46, 0x00, 0x88, 0x94, 0xc2, 0x0c, 0x40, + 0xc9, 0x15, 0x42, 0xe1, 0x51, 0x29, 0x01, 0x1a, 0x33, 0x00, 0x00, 0x00, + 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x00, 0x65, 0x85, 0x73, 0x5d, 0xc8, + 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x40, 0x9a, 0x11, 0x61, 0x58, 0x32, + 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x86, 0x67, 0x68, 0x19, 0x84, 0x8c, + 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0xf1, 0x1d, 0x9b, 0x56, 0x24, 0x23, + 0x06, 0x0f, 0x00, 0x82, 0x60, 0xd0, 0x78, 0x07, 0x31, 0x08, 0x41, 0x51, + 0x6c, 0x9b, 0x52, 0x8c, 0x26, 0x04, 0xc0, 0x68, 0x82, 0x10, 0x8c, 0x26, + 0x0c, 0xc2, 0x68, 0x02, 0x31, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, + 0x42, 0x06, 0x10, 0x18, 0x80, 0xc1, 0x45, 0x8c, 0x18, 0x24, 0x00, 0x08, + 0x82, 0x01, 0x42, 0x06, 0x10, 0x18, 0x80, 0xc1, 0x32, 0x8c, 0x18, 0x24, + 0x00, 0x08, 0x82, 0x01, 0x42, 0x06, 0x10, 0x18, 0x80, 0x81, 0x25, 0x8c, + 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x42, 0x06, 0x10, 0x18, 0x80, 0x41, + 0x16, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + // clang-format on \ No newline at end of file diff --git a/tests/graphics/shaders/texture_frag_shader.dxil b/tests/graphics/shaders/texture_frag_shader.dxil deleted file mode 100644 index 3df641a1963568bec8201b22802521c01e951672..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3812 zcmeHKeNa=`6~D=Qy!Qg(nIS&Dyo=QrYmeuuj5!?DINHSqCH~KW<%fhF!#H(wdKe zkT~^Z25H|D>CvikO}6pId+(#m(y&~(QSAE>+s4>!#g*KnftDFoMVNAF6RW%dct=4d zjANfkXx6EjYyz$hfZYrL8Ytr;GkDC_UFg2ZE(;tcEKa*4Nfv5yb z5iZ?t!Lk9yB2s@y8>w}ev!m(qAG)pfXKnU^qK7TF)B5Qx)belm`+uevNS;c(`~Z`A zJ-vn&Z{e#49kO&v)VN1I7?ngxZAyOpC%sACnxrAO;tb~}t;lMxCS_2QJjhu#V@hdt zCwblSLFA2gM1D?_=Qk>gUqqcQB1 zmYh`zzGejX7`)4cKhcsCO2Gq0@ScvGo*~DTf-->BjN!U5Jfpq!%bcsC+`h?^;L*xd z&)cq4htZpZa)D4(<+9f3tg=#TeJKLnCx*Rx+DIX(Yp7{(ui{{Xa3l2b&0;68s z2Yx-p0C;|VL_bVW0(i)LB%L%FeOHH_F##}!J+E;Q?V^yNY`cvYlRkiIBBP~TEq{%6 zQL#3nKbOe=`C-1l9(54@mT5j14*{39NHBO}XV|s`>fyPmhcXn&wx@B0o>;~$)|mEX zoebz)k;U0v*;{F#r z4*TzuujuSxMAuMLA&m55;^3md)iR^cXp#JK8r;^4Zkhw1TO$ z#AxD}eY|J1?cx>oA$ZL(TkC#Wt1qi9uF5kXCPNNg4*Mm&;lRdg;te6UTfs6-)BVU_ z$i6A~abkfiG1{?w&v=jbUT>RUPtW<`UF<$w$>E)Ni_NjU_}$E{c{Tc);ym+5Fj3Y4 z@dq0tuK((w`13oh40#q-wVfa78HSZ}co2Blcg^BZJYfv;jE9woI4RAVB#YaoHsbYl zcy)Uve+mfxL6MJ*WISIT(bpUPsWYrZ>gNk<6b~Wr4yV|Vl%YCXjRD_D;Pn|+g8^?a zAhmT?17i&t3L>ZN>}{=(3MOXA87&!4dBX2X!bT2CSCM!8p$d)TB$znUSx8Y91U zk<(J7XwVrp=?ok4jd%26mn2~xQ}`u4cEb*PjV8I>H=c1PwQ7=@5qYcoO<44qS$-Xn zcf0u>3I3h|X;^BlHCjW4HRS9VHp!6p$FL_9`4ILTyWoLV@EGn_B?G`BDASn0{SOou zs32FWMH#=+;+O5dC;#1Fl3a{TuEdWKBK$r+phAJ;ZG^c`w>5(tqjwpThsP^0R;J<$~!s3i=9(Oul!kwB0xO4C| z?!3mGSHYe6a|gvM;|}{8XTRU~cHh z>de|%4bfl-b(YFd59&0;5dA0hlDP7Tv(6}mkysye!+UL?Xc%=GV+hL$6@|o(cJp

A;;<*HH)wan|6p zf|$=9rxgsyqBAbR);`#F<^0IS-?YKr{^5VY!LgU&zzF-!>;C`$(f{=f0L$U|7ow__ z?0*SA$dA)Nb88=8dGSZ;@!Vyc(0FKz!g#=}1I4?lHw`wcxJHIn9t_eK#ueECLtstY zN<%C*dI=!RrhkTa6fB9t1TfrNhsP4C+_H{!wiwh^YNl*4{Jv6d>|7*AjZw6*cg^=^ RaSLar=!G*?Fas9?=|AZGp`-u+ diff --git a/tests/graphics/shaders/texture_frag_shader.glsl b/tests/graphics/shaders/texture_frag_shader.glsl deleted file mode 100644 index 457b1f86..00000000 --- a/tests/graphics/shaders/texture_frag_shader.glsl +++ /dev/null @@ -1,14 +0,0 @@ - -#version 450 - -layout(set = 0, binding = 0) uniform texture2D tex; -layout(set = 0, binding = 0) uniform sampler samp; - -layout(location = 0) in vec2 aTexCoord; - -layout(location = 0) out vec4 color; - -void main() -{ - color = texture(sampler2D(tex, samp), aTexCoord); -} \ No newline at end of file diff --git a/tests/graphics/shaders/texture_frag_shader.hlsl b/tests/graphics/shaders/texture_frag_shader.hlsl deleted file mode 100644 index dca9f232..00000000 --- a/tests/graphics/shaders/texture_frag_shader.hlsl +++ /dev/null @@ -1,14 +0,0 @@ - -Texture2D tex : register(t0); -SamplerState samp : register(s0); - -struct PSInput -{ - float4 pos : SV_POSITION; - float2 uv : TEXCOORD; -}; - -float4 main(PSInput input) : SV_Target -{ - return tex.Sample(samp, input.uv); -} \ No newline at end of file diff --git a/tests/graphics/shaders/texture_frag_shader.spv b/tests/graphics/shaders/texture_frag_shader.spv deleted file mode 100644 index f6aeea6cec9ae85dd4c21ae9277ce490eb7cfcd2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 684 zcmYk3y-or_7)1xxEL?}$eH9*1h`BXM0o-;t)As=_{ zojc#pY*M@^hf*QbLM3#@jn2z2* zJ*W~p#2(R#n8fok`-EQ+{N{3sn!hLa?pyYe&A=3|c@~pp^qOxzntlQBH0B;XPnM5a zHXEZ2*7wgeu;kwFMfT6nbKIQyb9w&U{x|uWbZ+mxI7Nv27W)!fmuOSZ8RgE^<-Y>@ zTIzRe?u=?3rrieh7l{1YaC6kw2YSsRcP`fnUDQE+ji~s2RzA7&xK62f0Gh)-4?*iX zk9UtiYpPpA?(AweytO`Oa@qS2N($binsb-1C%N_a32VRLvTl>mqprs~ZNeI_czmB@ RLZA8rReUG4U%I#@{s5gk9qRx9 diff --git a/tests/graphics/shaders/texture_vert_shader.dxil b/tests/graphics/shaders/texture_vert_shader.dxil deleted file mode 100644 index 9ab0b1ccc04cd235c76fcfd460d4ebadf4608e31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3100 zcmeHJe^3+o72nM+*$pINfp8Z{U^XCJJSm1q1C-FoFOZm6A_*SXk-5Nuhc^%tq6m01 z%`Zs6&_)DFjpG1%9$IUGqvzS)A3|s+hp4HC9jMmP%5m2jw2UL2cG_wC-Gtmw+dn#; zY5%%6`F`K~zW4dQmwn&e&#tOgp}gOc8GLr<@{6UN&j$y7dh{j?K@gt_K^V|dFtlJy zfWZZUbubp`K!c&LP>XQjkBM5pyWjv=(7=fKD`P>Rkxd(k8DPEdr8reP7S~nj)dqFd zcOXM~t+J}BS_NWNpoS6Xe^(>27sMz@jH<|N*kV(qBRFtf2D#w@*k=UDA^=v^sy3Fnjh%c?eb03315)>|*A`;c1!Zi3S@{PE!mdC|rb?Q;c&p@nVIi z(#Ii{6`uE@G_hi(lI=^%n$yYm*}adQpZB4H3i>`S1cBQJ;&~rYZNy}>ah7YHG7%D# zh14KU^)$s{RFFXTf{8j$aTd-X8@thztP3tMJ#mftILTU%H^Jr75~6G<2kJ|+mC!`~ zY*}A{%AnfMB*)Tc?KTzIpTcRo;XYz?OPbxC%?PkrKhd#U!|X0FLy27?tZf9dl31&c zZHXBjF~efSC_tG0`z^3`8P;XQj)du}1lAr!8rdL26uAmQBN)K6K4ODBn;9Y=<+-mO z4hZUz(g~{l5n*-`Bm~YNA|V<~-J;@5KPN3o>+>>lcmEPqjwN$pVUJk&gDD|;c>vfB zu@L>uBoV|>$aVwZJ3;T>209(l`YLECa|L9Or?j8ae3)>4hX(Go%vkJ}(aB48SU&ox z-~?mGO@>pwOrR-fgP$bk==G!oN98jnlS9Vg^&o;=oHhY3iHMt10;7cKysITnzoT6D zH797S*|d$qA=S`}l|s32kfE4t!95JcjF!OPcAD#WuPDxp_oe4KW<9#pdRAGPI;pjm z-a7XByA$;I`(z_;c>9lbj$gZ8__OJvYYfG&v_$+n4jG^4N?=OzR7IWlirzz0>AchO z!1#Rn75l6NZxGRW^zSomtnTC?7@DZG2F?cpB!Tx|pZ;*CWQsvM8TM;R|8nO1edAd; z{enIH3S8aYf9vY4oc=2d{iZ#HK@hY~?l=|D9JdCNiM^rq18cKOYx64?(eezjbhu<% zG$p=%v1m&C(RR4HmwBf1DAP}#jc=N zVZ%B*Fst9fT!j*!66_Z?_AaI(b9N@<_9*|LC@unX@)nS?kh08+lr404kC?IJIM!L| zHk+|7Gt%DSHk0nOg(UWxkNsGbXc8qpS!b{7*t>|ijE4gLk|1NYKJ%ccxAYTdX;@h@ zjYvOnN?l0l!aAqjh#hanikjVRV79r+ENb*c&(4Ya*l}G|FEY$5%Jr3;O`DZEow;}k z&bm<2cdXb6e@5}$wzw$&slkJ{mH(K)ALBpS*ZlXtunG^pO3uW zn`FxpIu#=s2?bsm_~MAX(JB7h3ljg={FjTXCgogae7iLTom~=S=NkLPC&`j z3tKgE?&84sz`3)zc)1ub9}6y!3r{m>mKH+zZcriBZ7UC|RH;dqv#yMO@Y?n<)=jhg zB!~4GQNu$Mo`{<^;x;716~ljAmB@wu2=n2MPT5gFm`+JAuQ=!B85`fesP63+|N1vKez{*d?EL2_Kt^F_lOxkXf_9P*6s@%5$d$>pI>_cFZS zYV63jHrF>cwe3CJ*wmtTTwtf2J5l%D<+|i$P93*ydC+)C+4Dv9YQ<~A*v9GAilU+% z0{NP!{+~QmPeM>GxKC41c^>uc1*iuySa)zHB-Jau|&|C+8c# z@W^R4lFLmkP`e8nd=QD#dup_LtCzbC!X0)?8fS=%!fgjCYszM$aPrmanmwW@Jk)I% c(nsNNo1o?%HwO3Al+DH94K?#NP#DNR03S|!jsO4v diff --git a/tests/graphics/shaders/texture_vert_shader.glsl b/tests/graphics/shaders/texture_vert_shader.glsl deleted file mode 100644 index ac9a01d3..00000000 --- a/tests/graphics/shaders/texture_vert_shader.glsl +++ /dev/null @@ -1,13 +0,0 @@ - -#version 450 - -layout(location = 0) in vec2 aPosition; -layout(location = 1) in vec2 aTexCoord; - -layout(location = 0) out vec2 vTexCoord; - -void main() -{ - gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); - vTexCoord = aTexCoord; -} \ No newline at end of file diff --git a/tests/graphics/shaders/texture_vert_shader.hlsl b/tests/graphics/shaders/texture_vert_shader.hlsl deleted file mode 100644 index ff9ef8cc..00000000 --- a/tests/graphics/shaders/texture_vert_shader.hlsl +++ /dev/null @@ -1,20 +0,0 @@ - -struct VSInput -{ - float2 pos : POSITION; - float2 uv : TEXCOORD; -}; - -struct VSOutput -{ - float4 pos : SV_POSITION; - float2 uv : TEXCOORD; -}; - -VSOutput main(VSInput input) -{ - VSOutput output; - output.pos = float4(input.pos, 0.0, 1.0); - output.uv = input.uv; - return output; -} \ No newline at end of file diff --git a/tests/graphics/shaders/texture_vert_shader.spv b/tests/graphics/shaders/texture_vert_shader.spv deleted file mode 100644 index 77d1b67794c35bbda578f3cf9595649dbbd94a9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1044 zcmYk4UrPc}5XG+AiXbYYz#e)Cie5u_~nRBn^vaN#2XH3ZyP0OTKFFJe+niwlv8_)qDjq@J~U&V9<+BS8&l2~ z_kJIYF9(BR&-QV)?iAP29L~c2Yt13YTyz}T;fRjo8#weijvS8r>gbKGZ8-+^6{j(J zz|5^m1v8tP$Q<%jWqCzkUf1^pMKJSgdKVRaIksmpzb^9{!gGrB!)+@=o0~xm_tiJA z=(L|$%>BZ#XEEtZ=duS}mSgBzQe+RBnO9Ln13dG<+y$J|SyhhFzoJNu8Ptgza?Ih) z1bv;;zoi^)oCUmNvD*jsE$8+(h1qeW-x;0UA;z2^F`nXu-e{@G(Tm1Yt7p~nuBUE$ zxLen=rX2p$ezUF|?p8|C+K@8`p7U`g=5ZeW2i!ULdL~t1`kBqScIBLbns4#1PIN5) E1K@H&od5s; diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 755d340c..04c41d90 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -3,6 +3,7 @@ #include "pal/pal_video.h" #include "pal/pal_system.h" #include "tests.h" +#include "shaders.h" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 @@ -847,74 +848,49 @@ bool textureTest() } // create shaders - Uint64 bytecodeSize = 0; - void* bytecode = nullptr; - PalShaderCreateInfo shaderCreateInfo = {0}; + Uint64 vertBytecodeSize = 0; + Uint64 fragBytecodeSize = 0; + void* vertBytecode = nullptr; + void* fragBytecode = nullptr; + + PalShaderCreateInfo vertShaderCreateInfo = {0}; + PalShaderCreateInfo fragShaderCreateInfo = {0}; - const char* vertexShaderPath = nullptr; - const char* fragShaderPath = nullptr; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - vertexShaderPath = "graphics/shaders/texture_vert_shader.spv"; - fragShaderPath = "graphics/shaders/texture_frag_shader.spv"; + vertBytecodeSize = sizeof(s_TextureVertShaderSpv); + fragBytecodeSize = sizeof(s_TextureFragShaderSpv); + vertBytecode = (void*)s_TextureVertShaderSpv; + fragBytecode = (void*)s_TextureFragShaderSpv; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - vertexShaderPath = "graphics/shaders/texture_vert_shader.dxil"; - fragShaderPath = "graphics/shaders/texture_frag_shader.dxil"; + vertBytecodeSize = sizeof(s_TextureVertShaderDxil); + fragBytecodeSize = sizeof(s_TextureFragShaderDxil); + vertBytecode = (void*)s_TextureVertShaderDxil; + fragBytecode = (void*)s_TextureFragShaderDxil; } - if (!readFile(vertexShaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader file"); - return false; - } + vertShaderCreateInfo.bytecode = vertBytecode; + vertShaderCreateInfo.bytecodeSize = vertBytecodeSize; + vertShaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - readFile(vertexShaderPath, bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; + fragShaderCreateInfo.bytecode = fragBytecode; + fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; + fragShaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; - result = palCreateShader(device, &shaderCreateInfo, &vertexShader); + result = palCreateShader(device, &vertShaderCreateInfo, &vertexShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create vertex shader: %s", error); return false; } - // fragment shader - bytecodeSize = 0; - palFree(nullptr, bytecode); - bytecode = nullptr; - - if (!readFile(fragShaderPath, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to find shader file"); - return false; - } - - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - readFile(fragShaderPath, bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; - - result = palCreateShader(device, &shaderCreateInfo, &fragmentShader); + result = palCreateShader(device, &fragShaderCreateInfo, &fragmentShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fragment shader: %s", error); return false; } - palFree(nullptr, bytecode); - // create descriptor set layout PalDescriptorSetLayoutBinding descriptorBindings[2]; PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; diff --git a/tests/tests_main.c b/tests/tests_main.c index c144ead6..1c5706ee 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -65,8 +65,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); - registerTest(meshTest, "Mesh Test"); // TODO: add dxil shaders - // registerTest(textureTest, "Texture Test"); + // registerTest(meshTest, "Mesh Test"); // TODO: add dxil shaders + registerTest(textureTest, "Texture Test"); #endif // runTests(); From f7ae87ad36d5ba55b6f0f263162f200d614fee55 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 29 Apr 2026 19:29:04 +0000 Subject: [PATCH 191/372] add mesh shader dxil --- tests/graphics/mesh_test.c | 9 +- tests/graphics/shaders.h | 301 +++++++++++++++++++++++++++++++++++++ tests/tests_main.c | 2 +- 3 files changed, 308 insertions(+), 4 deletions(-) diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 67a819b6..ef4326bc 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -192,7 +192,7 @@ bool meshTest() } if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_5)) { break; } } @@ -410,8 +410,11 @@ bool meshTest() fragBytecode = (void*)s_TriangleFragShaderSpv; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - palLog(nullptr, "Dxil not tested yet"); - return false; + meshBytecodeSize = sizeof(s_MeshShaderDxil); + fragBytecodeSize = sizeof(s_TriangleFragShaderDxil); + + meshBytecode = (void*)s_MeshShaderDxil; + fragBytecode = (void*)s_TriangleFragShaderDxil; } meshShaderCreateInfo.bytecode = meshBytecode; diff --git a/tests/graphics/shaders.h b/tests/graphics/shaders.h index 39c4b9d0..66c78813 100644 --- a/tests/graphics/shaders.h +++ b/tests/graphics/shaders.h @@ -1466,6 +1466,32 @@ static const Uint32 s_TriangleFragShaderDxil[] = { // } // HLSL +// struct MSOutput +// { +// float4 position : SV_POSITION; +// float4 color : COLOR; +// }; + +// [outputtopology("triangle")] +// [numthreads(1, 1, 1)] +// void main( +// out vertices MSOutput meshVertices[4], +// out indices uint3 triangleIndices[2]) +// { +// SetMeshOutputCounts(4, 2); +// meshVertices[0].position = float4(-0.5, 0.5, 0.0, 1.0); +// meshVertices[1].position = float4( 0.5, 0.5, 0.0, 1.0); +// meshVertices[2].position = float4( 0.5,-0.5, 0.0, 1.0); +// meshVertices[3].position = float4(-0.5,-0.5, 0.0, 1.0); + +// meshVertices[0].color = float4(1.0, 0.0, 0.0, 1.0); +// meshVertices[1].color = float4(0.0, 1.0, 0.0, 1.0); +// meshVertices[2].color = float4(0.0, 0.0, 1.0, 1.0); +// meshVertices[3].color = float4(1.0, 0.0, 0.0, 1.0); + +// triangleIndices[0] = uint3(0, 1, 2); +// triangleIndices[1] = uint3(0, 2, 3); +// } static const Uint32 s_MeshShaderSpv[] = { 0x07230203, 0x00010600, 0x0008000b, 0x00000039, @@ -1580,6 +1606,281 @@ static const Uint32 s_MeshShaderSpv[] = { 0x00000036, 0x000100fd, 0x00010038 }; +static const Uint8 s_MeshShaderDxil[] = { + 0x44, 0x58, 0x42, 0x43, 0xcb, 0xfe, 0x8e, 0x94, 0x80, 0xad, 0x7f, 0xe3, + 0xef, 0xa4, 0xa8, 0x66, 0x70, 0x03, 0x1a, 0xab, 0x01, 0x00, 0x00, 0x00, + 0xc0, 0x0c, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x40, 0x01, 0x00, 0x00, 0x24, 0x06, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, + 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, + 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x00, 0x00, + 0x50, 0x53, 0x56, 0x30, 0x78, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x0d, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, + 0x03, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x44, 0x00, 0x03, 0x02, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, + 0xdc, 0x04, 0x00, 0x00, 0x65, 0x00, 0x0d, 0x00, 0x37, 0x01, 0x00, 0x00, + 0x44, 0x58, 0x49, 0x4c, 0x05, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xc4, 0x04, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, + 0x2e, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, + 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, + 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, + 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, + 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, + 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, + 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, + 0x40, 0x02, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x13, 0x82, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, + 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, + 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x38, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x39, + 0x02, 0x30, 0x28, 0x06, 0xcc, 0xcc, 0x0c, 0xd1, 0x1c, 0x01, 0x32, 0x03, + 0x50, 0x0e, 0x98, 0x19, 0xbb, 0x21, 0x2c, 0x04, 0xcc, 0x0c, 0xe9, 0x40, + 0x40, 0x0e, 0x0c, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, + 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, + 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, + 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, + 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, + 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, + 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, + 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, + 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, + 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, + 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, + 0x3c, 0x04, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x79, 0x10, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0xf2, 0x28, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x90, 0x05, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, + 0xc6, 0x04, 0x43, 0x9a, 0x12, 0x28, 0x85, 0x11, 0x80, 0x62, 0x28, 0x83, + 0xf2, 0x28, 0x89, 0x42, 0x28, 0x82, 0x42, 0x2a, 0x20, 0xb2, 0x92, 0x28, + 0x83, 0x42, 0x18, 0x01, 0x28, 0x02, 0xea, 0xb1, 0x06, 0x00, 0x01, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, + 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, + 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, + 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, + 0x10, 0x4c, 0x10, 0x06, 0x62, 0x82, 0x30, 0x14, 0x1b, 0x84, 0x81, 0x98, + 0x20, 0x0c, 0xc6, 0x06, 0xc1, 0x30, 0x28, 0xb4, 0xcd, 0x4d, 0x10, 0x86, + 0x63, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x41, 0x00, 0x36, 0x00, 0x1b, 0x06, + 0x83, 0x61, 0x36, 0x04, 0xcd, 0x86, 0x61, 0x58, 0x9c, 0x09, 0x42, 0x43, + 0x6d, 0x08, 0x20, 0x12, 0x6d, 0x61, 0x69, 0x6e, 0x5c, 0xa6, 0xac, 0xbe, + 0xa0, 0xde, 0xe6, 0xd2, 0xe8, 0xd2, 0xde, 0xdc, 0x26, 0x08, 0xc6, 0x33, + 0x41, 0x30, 0xa0, 0x0d, 0x81, 0x31, 0x41, 0x30, 0xa2, 0x09, 0x82, 0x21, + 0x4d, 0x10, 0x06, 0x64, 0x82, 0x30, 0x24, 0x1b, 0x84, 0x4c, 0xdb, 0xb0, + 0x18, 0x13, 0x55, 0x59, 0xd7, 0x70, 0x19, 0xd8, 0xc6, 0x62, 0xe8, 0x89, + 0xe9, 0x49, 0x6a, 0x82, 0x60, 0x4c, 0x1b, 0x96, 0xa1, 0xa3, 0x30, 0xcb, + 0x1b, 0xae, 0x01, 0xdb, 0x36, 0x08, 0xdc, 0xb7, 0x61, 0x00, 0xc0, 0x00, + 0x98, 0x20, 0x0c, 0xca, 0x86, 0x61, 0x18, 0x86, 0x09, 0xc2, 0xb0, 0x4c, + 0x10, 0x06, 0x66, 0x43, 0x31, 0x06, 0x64, 0x50, 0x06, 0x65, 0x60, 0x6c, + 0x10, 0xc4, 0xc0, 0x0c, 0x36, 0x14, 0x8b, 0x14, 0x06, 0xc0, 0x19, 0xb0, + 0x48, 0x73, 0x9b, 0xa3, 0x9b, 0x9b, 0x20, 0x0c, 0x0d, 0x8d, 0xb9, 0xb4, + 0xb3, 0xaf, 0x39, 0xba, 0x09, 0xc2, 0xe0, 0x6c, 0x20, 0xd2, 0x40, 0x0d, + 0xd6, 0x80, 0x0d, 0xaa, 0xb0, 0xb1, 0xd9, 0xb5, 0xb9, 0xa4, 0x91, 0x95, + 0xb9, 0xd1, 0x4d, 0x09, 0x82, 0x2a, 0x64, 0x78, 0x2e, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x02, 0xa2, 0x09, 0x19, 0x9e, 0x8b, 0x5d, + 0x18, 0x9b, 0x5d, 0x99, 0xdc, 0x94, 0xc0, 0xa8, 0x43, 0x86, 0xe7, 0x32, + 0x87, 0x16, 0x46, 0x56, 0x26, 0xd7, 0xf4, 0x46, 0x56, 0xc6, 0x36, 0x25, + 0x48, 0x2a, 0x91, 0xe1, 0xb9, 0xd0, 0xe5, 0xc1, 0x95, 0x05, 0xb9, 0xb9, + 0xbd, 0xd1, 0x85, 0xd1, 0xa5, 0xbd, 0xb9, 0xcd, 0x4d, 0x09, 0x9c, 0x3a, + 0x64, 0x78, 0x2e, 0x76, 0x69, 0x65, 0x77, 0x49, 0x64, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x53, 0x02, 0xa8, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, + 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0xe0, 0x0c, 0xba, + 0x90, 0xe1, 0xb9, 0x8c, 0xbd, 0xd5, 0xb9, 0xd1, 0x95, 0xc9, 0xcd, 0x4d, + 0x09, 0xd8, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, + 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, + 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, + 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, + 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, + 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, + 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, + 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, + 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, + 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, + 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, + 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, + 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, + 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, + 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, + 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, + 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, + 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, + 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, + 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, + 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, + 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, + 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, + 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, + 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, + 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x16, 0x10, 0x0d, 0x97, 0xef, 0x3c, 0x3e, 0xc1, 0x20, 0x93, 0xd8, 0x0c, + 0x88, 0x40, 0x48, 0x36, 0x90, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x44, 0x4c, + 0x26, 0x21, 0x1d, 0x28, 0x35, 0x3d, 0xd4, 0xc4, 0x39, 0x54, 0x33, 0x49, + 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x34, 0x39, 0x11, 0xf1, 0x12, + 0xd1, 0x44, 0x5c, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, + 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xdc, 0x4d, 0x54, 0xec, 0x84, 0x03, 0xa5, 0xfb, 0x85, 0xf8, 0x53, 0x5a, + 0x52, 0x72, 0x23, 0x6a, 0x44, 0x58, 0x49, 0x4c, 0x78, 0x06, 0x00, 0x00, + 0x65, 0x00, 0x0d, 0x00, 0x9e, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x05, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x95, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0x00, 0x00, + 0x49, 0x18, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x82, 0x00, 0x00, + 0x89, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, + 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, + 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, + 0x10, 0x38, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x39, 0x02, 0x30, 0x28, 0x06, + 0xcc, 0xcc, 0x0c, 0xd1, 0x1c, 0x01, 0x32, 0x03, 0x50, 0x0e, 0x98, 0x19, + 0xbb, 0x21, 0x2c, 0x04, 0xcc, 0x0c, 0xe9, 0x40, 0x40, 0x0e, 0x0c, 0x00, + 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, + 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, + 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, + 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, + 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, + 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, + 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x04, 0x10, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x28, + 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x05, + 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, + 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x9a, + 0x12, 0x28, 0x85, 0x92, 0x28, 0x86, 0x11, 0x80, 0x32, 0x28, 0x8f, 0x42, + 0x28, 0x02, 0xb2, 0x92, 0x28, 0x83, 0x42, 0x18, 0x01, 0x28, 0x02, 0xea, + 0xb1, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, + 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, + 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, + 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x06, + 0x62, 0x82, 0x30, 0x14, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x0c, 0xc6, 0x06, + 0x61, 0x30, 0x28, 0xb4, 0xcd, 0x4d, 0x10, 0x86, 0x63, 0xc3, 0x80, 0x24, + 0xc4, 0x04, 0xa1, 0x91, 0x36, 0x04, 0xcb, 0x04, 0x41, 0x00, 0x48, 0xb4, + 0x85, 0xa5, 0xb9, 0x4d, 0x10, 0x06, 0x84, 0xcb, 0x94, 0xd5, 0x17, 0xd4, + 0xdb, 0x5c, 0x1a, 0x5d, 0xda, 0x9b, 0xdb, 0x04, 0xc1, 0x68, 0x26, 0x08, + 0x86, 0xb3, 0x21, 0x78, 0x26, 0x08, 0xc6, 0x33, 0x41, 0x30, 0xa0, 0x09, + 0xc2, 0x90, 0x4c, 0x10, 0x06, 0x65, 0x83, 0x60, 0x5d, 0x1b, 0x96, 0x07, + 0x8a, 0xa4, 0x89, 0x1a, 0xa8, 0xa7, 0xc2, 0x58, 0x0c, 0x3d, 0x31, 0x3d, + 0x49, 0x4d, 0x10, 0x8c, 0x68, 0xc3, 0x32, 0x68, 0x51, 0x35, 0x6d, 0x03, + 0x35, 0x54, 0xd8, 0x06, 0x21, 0xe3, 0x36, 0x0c, 0x40, 0x07, 0x6c, 0x18, + 0x86, 0x61, 0x98, 0x20, 0x0c, 0xcb, 0x04, 0x61, 0x60, 0x36, 0x14, 0x1f, + 0x18, 0x84, 0x41, 0x18, 0x3c, 0x1b, 0x04, 0x43, 0x0c, 0x36, 0x14, 0x8d, + 0xe3, 0x01, 0x63, 0x50, 0x85, 0x8d, 0xcd, 0xae, 0xcd, 0x25, 0x8d, 0xac, + 0xcc, 0x8d, 0x6e, 0x4a, 0x10, 0x54, 0x21, 0xc3, 0x73, 0xb1, 0x2b, 0x93, + 0x9b, 0x4b, 0x7b, 0x73, 0x9b, 0x12, 0x10, 0x4d, 0xc8, 0xf0, 0x5c, 0xec, + 0xc2, 0xd8, 0xec, 0xca, 0xe4, 0xa6, 0x04, 0x46, 0x1d, 0x32, 0x3c, 0x97, + 0x39, 0xb4, 0x30, 0xb2, 0x32, 0xb9, 0xa6, 0x37, 0xb2, 0x32, 0xb6, 0x29, + 0x41, 0x52, 0x87, 0x0c, 0xcf, 0xc5, 0x2e, 0xad, 0xec, 0x2e, 0x89, 0x6c, + 0x8a, 0x2e, 0x8c, 0xae, 0x6c, 0x4a, 0xb0, 0xd4, 0x21, 0xc3, 0x73, 0x29, + 0x73, 0xa3, 0x93, 0xcb, 0x83, 0x7a, 0x4b, 0x73, 0xa3, 0x9b, 0x9b, 0x12, + 0x8c, 0x01, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, + 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, + 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, + 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, + 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, + 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, + 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, + 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, + 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, + 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, + 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, + 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, + 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, + 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, + 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, + 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, + 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, + 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, + 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, + 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, + 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, + 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, + 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, + 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, + 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, + 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x16, 0x10, 0x0d, 0x97, 0xef, 0x3c, 0x3e, 0xc1, 0x20, 0x93, 0xd8, 0x0c, + 0x88, 0x40, 0x48, 0x36, 0x90, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x44, 0x4c, + 0x26, 0x21, 0x1d, 0x28, 0x35, 0x3d, 0xd4, 0xc4, 0x39, 0x54, 0x33, 0x49, + 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x34, 0x39, 0x11, 0xf1, 0x12, + 0xd1, 0x44, 0x5c, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, + 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, + 0x79, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x34, 0x65, 0x2d, 0x50, 0xd2, 0x02, 0x05, 0x2d, + 0x40, 0x56, 0x02, 0x74, 0x23, 0x00, 0x63, 0x04, 0x20, 0x08, 0x82, 0xf8, + 0x37, 0x46, 0x00, 0x82, 0x20, 0x08, 0xff, 0xc2, 0x18, 0x01, 0x08, 0x82, + 0x20, 0xfc, 0x01, 0x00, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xa0, 0x60, + 0x06, 0xf4, 0x8c, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd3, + 0xb4, 0x08, 0xd3, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x32, + 0x4d, 0x45, 0x30, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, + 0xd3, 0xa4, 0x10, 0xd3, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, + 0x32, 0x4d, 0xcd, 0x30, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, + 0x21, 0xd3, 0xb4, 0x04, 0xd7, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, + 0x19, 0x32, 0x4d, 0x45, 0x70, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, + 0x92, 0x21, 0xd3, 0xa4, 0x10, 0xd7, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, + 0x20, 0x19, 0x32, 0x4d, 0xcd, 0x70, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, + 0x01, 0x92, 0x21, 0xd3, 0xb4, 0x04, 0xcf, 0x88, 0x81, 0x02, 0x80, 0x20, + 0x18, 0x20, 0x19, 0x32, 0x4d, 0x85, 0xf0, 0x8c, 0x18, 0x28, 0x00, 0x08, + 0x82, 0x01, 0x92, 0x21, 0xd3, 0xa4, 0x10, 0xcf, 0x88, 0x81, 0x02, 0x80, + 0x20, 0x18, 0x20, 0x19, 0x32, 0x4d, 0xcd, 0xf0, 0x8c, 0x18, 0x28, 0x00, + 0x08, 0x82, 0x01, 0x92, 0x21, 0xd3, 0xb4, 0x08, 0xd2, 0x88, 0x81, 0x02, + 0x80, 0x20, 0x18, 0x20, 0x19, 0x32, 0x4d, 0x85, 0x20, 0x8d, 0x18, 0x28, + 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd3, 0xa4, 0x10, 0xd2, 0x88, 0x81, + 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x32, 0x4d, 0xcd, 0x20, 0x8d, 0x18, + 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd7, 0xb4, 0x0c, 0xd3, 0x88, + 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x72, 0x4d, 0x05, 0x31, 0x8d, + 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd7, 0xa4, 0x10, 0xd3, + 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x72, 0x4d, 0xcd, 0x30, + 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd7, 0xb4, 0x10, + 0xd7, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x72, 0x4d, 0xc5, + 0x70, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd7, 0xa4, + 0x10, 0xd7, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x72, 0x4d, + 0xcd, 0x70, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd7, + 0xb4, 0x10, 0xcf, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x72, + 0x4d, 0x05, 0xf1, 0x8c, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, + 0xd7, 0xa4, 0x0c, 0xcf, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, + 0x72, 0x4d, 0xcd, 0xf0, 0x8c, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, + 0x21, 0xd7, 0xb4, 0x0c, 0xd2, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, + 0x19, 0x72, 0x4d, 0x05, 0x21, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, + 0x92, 0x21, 0xd7, 0xa4, 0x10, 0xd2, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, + 0x20, 0x19, 0x72, 0x4d, 0xcd, 0x20, 0x8d, 0x18, 0x24, 0x00, 0x08, 0x82, + 0x01, 0xa1, 0x1d, 0xd3, 0x74, 0x3d, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, + 0x40, 0x68, 0xc7, 0x35, 0x3d, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + // ================================================== // Texture // ================================================== diff --git a/tests/tests_main.c b/tests/tests_main.c index 1c5706ee..2b0203a9 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -65,7 +65,7 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); - // registerTest(meshTest, "Mesh Test"); // TODO: add dxil shaders + // registerTest(meshTest, "Mesh Test"); registerTest(textureTest, "Texture Test"); #endif // From 589d9ac830ec7c79f56c29b7c3c7966e04ad0f8b Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 30 Apr 2026 16:21:03 +0000 Subject: [PATCH 192/372] start shader API limit removal --- include/pal/pal_core.h | 1 + include/pal/pal_graphics.h | 36 ++++- src/graphics/pal_d3d12.c | 289 +++++++++++++++++++------------------ src/graphics/pal_vulkan.c | 210 ++++++++++++++++++++------- src/pal_core.c | 3 + tests/tests.lua | 12 +- tests/tests_main.c | 4 +- 7 files changed, 350 insertions(+), 205 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 620ab0e3..f8dd6bf2 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -259,6 +259,7 @@ typedef enum { PAL_RESULT_INVALID_IMAGE_VIEW, PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED, PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_INVALID_SHADER, PAL_RESULT_INVALID_SHADER_TYPE, PAL_RESULT_INVALID_COMMAND_POOL, PAL_RESULT_INVALID_COMMAND_BUFFER, diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 8e383de5..8b321dda 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -47,6 +47,13 @@ freely, subject to the following restrictions: */ #define PAL_ADAPTER_NAME_SIZE 128 +/** + * @brief The maximum name size of a shader entry. + * @since 1.4 + * @ingroup pal_graphics + */ +#define PAL_SHADER_ENTRY_NAME_SIZE 32 + #define PAL_MAX_RESOLVE_MODES 8 #define PAL_MAX_COMBINER_OPS 8 @@ -2431,6 +2438,21 @@ typedef struct { PalImageAspect aspect; } PalImageCopyInfo; +/** + * @struct PalShaderEntry + * @brief Information for a single shader entry point in a shader bytecode. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ + PalShaderStage stage; + const char* entryName; +} PalShaderEntry; + /** * @struct PalImageCreateInfo * @brief Creation parameters for an image. @@ -2522,11 +2544,10 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ - PalShaderStage stage; + Uint32 entryCount; void* bytecode; Uint64 bytecodeSize; - const char* exportName; /**< Set to nullptr if shader does not have an export name.*/ + PalShaderEntry* entries; } PalShaderCreateInfo; /** @@ -2660,7 +2681,11 @@ typedef struct { Uint32 closestHitShaderIndex; /**< Index of closest hit shader from shader array.*/ Uint32 generalShaderIndex; /**< Index of general hit shader from shader array.*/ Uint32 intersectionShaderIndex; /**< Index of intersection hit shader from shader array.*/ - const char* exportName; /**< Set to nullptr if shader group does not have an export name.*/ + Uint32 anyHitEntryIndex; /**< Index of any hit Entry from `anyHitShaderIndex`.*/ + Uint32 closestHitEntryIndex; /**< Index of any hit Entry from `anyHitShaderIndex`.*/ + Uint32 generalEntryIndex; /**< Index of any hit Entry from `anyHitShaderIndex`.*/ + Uint32 intersectionEntryIndex; /**< Index of any hit Entry from `anyHitShaderIndex`.*/ + const char* exportName; } PalRayTracingShaderGroupCreateInfo; /** @@ -5123,8 +5148,7 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @note All shader stages must use `main` as the entry point. Pal does not support custom - * entry points. + * @note Each shader entry name must not be greater than `PAL_SHADER_ENTRY_NAME_SIZE (32)`. * * @since 1.4 * @ingroup pal_graphics diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index ed44224d..a70988a9 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -230,11 +230,17 @@ typedef struct { } Fence, Semaphore; typedef struct { - const PalGraphicsBackend* backend; - + Uint32 tmpIndex; Uint32 patchControlPoints; PalShaderStage stage; - const char* exportName; + wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; +} ShaderEntry; + +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 entryCount; + ShaderEntry* entries; D3D12_SHADER_BYTECODE byteCode; } Shader; @@ -282,12 +288,6 @@ typedef struct { ID3D12Resource* handle; } AccelerationStructure; -typedef struct { - PalShaderStage stage; - D3D12_EXPORT_DESC exports; - D3D12_DXIL_LIBRARY_DESC dxil; -} RayTracingShader; - typedef struct { const PalGraphicsBackend* backend; @@ -298,6 +298,16 @@ typedef struct { D3D12_ROOT_PARAMETER1 params[3]; } PipelineLayout; +typedef struct { + PalShaderStage stage; + wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; +} ShaderExport; + +typedef struct { + wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; + D3D12_HIT_GROUP_DESC desc; +} RayHitGroup; + typedef struct { const PalGraphicsBackend* backend; @@ -307,8 +317,7 @@ typedef struct { D3D_PRIMITIVE_TOPOLOGY topology; Uint32* strides; void* handle; - wchar_t* scratchBuffer; - RayTracingShader* shaders; + ShaderExport* shaderExports; PipelineLayout* layout; D3D12_SHADING_RATE_COMBINER combinerOps[2]; } Pipeline; @@ -1798,47 +1807,15 @@ static Uint32 getVertexTypeSizeD3D12(PalVertexType type) return 0; } -static wchar_t* convertToWcharD3D12( - wchar_t* buffer, - Uint32* offset, - const char* name) +static void convertToWcharD3D12( + const char* src, + wchar_t dst[PAL_SHADER_ENTRY_NAME_SIZE]) { - if (!name) { - return nullptr; - } - size_t srcLen = strlen(name); - int dstLen = MultiByteToWideChar( - CP_UTF8, - 0, - name, - srcLen, - nullptr, - 0); - - if (!dstLen) { - return nullptr; + int i = 0; + for (; i < PAL_SHADER_ENTRY_NAME_SIZE - 1 && src[i]; i++) { + dst[i] = (wchar_t)src[i]; } - - if (*offset + dstLen + 1 > MAX_SCRATCH_BUFFER_SIZE) { - return nullptr; - } - - wchar_t* dst = buffer + *offset; - int written = MultiByteToWideChar( - CP_UTF8, - 0, - name, - srcLen, - dst, - dstLen); - - if (!written) { - return nullptr; - } - - dst[written] = L'\0'; - *offset += written; - return dst; + dst[i] = L'\0'; } static void pollMessagesD3D12(Device* device) @@ -4127,44 +4104,52 @@ PalResult PAL_CALL createShaderD3D12( const PalShaderCreateInfo* info, PalShader** outShader) { - Device* d3dDevice = (Device*)device; Shader* shader = nullptr; + Device* d3dDevice = (Device*)device; void* bytecode = nullptr; - if (info->stage == PAL_SHADER_STAGE_MESH || info->stage == PAL_SHADER_STAGE_TASK) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - // clang-format off - } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || - info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || - info->stage == PAL_SHADER_STAGE_ANY_HIT || - info->stage == PAL_SHADER_STAGE_MISS || - info->stage == PAL_SHADER_STAGE_INTERSECTION || - info->stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!info->exportName) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - // clang-format on - shader = palAllocate(s_D3D.allocator, sizeof(Shader), 0); bytecode = palAllocate(s_D3D.allocator, info->bytecodeSize, 0); if (!shader || !bytecode) { return PAL_RESULT_OUT_OF_MEMORY; } + shader->entries = palAllocate(s_D3D.allocator, sizeof(ShaderEntry) * info->entryCount, 0); + if (!shader->entries) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + for (int i = 0; i < info->entryCount; i++) { + ShaderEntry* entry = &shader->entries[i]; + convertToWcharD3D12(info->entries[i].entryName, entry->entryName); + entry->patchControlPoints = info->entries[i].patchControlPoints; + entry->stage = info->entries[i].stage; + + if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || + info->entries[i].stage == PAL_SHADER_STAGE_TASK) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + // clang-format off + } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || + info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_MISS || + info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || + info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + // clang-format on + } + memcpy(bytecode, info->bytecode, info->bytecodeSize); shader->byteCode.pShaderBytecode = bytecode; shader->byteCode.BytecodeLength = info->bytecodeSize; - shader->stage = info->stage; - shader->patchControlPoints = info->patchControlPoints; - shader->exportName = info->exportName; + + shader->entryCount = info->entryCount; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } @@ -4173,6 +4158,7 @@ void PAL_CALL destroyShaderD3D12(PalShader* shader) { Shader* d3dShader = (Shader*)shader; palFree(s_D3D.allocator, (void*)d3dShader->byteCode.pShaderBytecode); + palFree(s_D3D.allocator, d3dShader->entries); palFree(s_D3D.allocator, d3dShader); } @@ -7077,30 +7063,36 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( totalSize += sizeof(ShaderStream); D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - if (tmp->patchControlPoints) { - patchControlPoints = tmp->patchControlPoints; + // D3D12 only supports a single entry for graphics pipeline shaders + if (tmp->entryCount != 1) { + return PAL_RESULT_INVALID_SHADER; + } + + ShaderEntry* entry = &tmp->entries[0]; + if (entry->patchControlPoints) { + patchControlPoints = entry->patchControlPoints; if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { palFree(s_D3D.allocator, pipeline); return PAL_RESULT_INVALID_OPERATION; } } - if (tmp->stage == PAL_SHADER_STAGE_VERTEX) { + if (entry->stage == PAL_SHADER_STAGE_VERTEX) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS; - } else if (tmp->stage == PAL_SHADER_STAGE_FRAGMENT) { + } else if (entry->stage == PAL_SHADER_STAGE_FRAGMENT) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS; - } else if (tmp->stage == PAL_SHADER_STAGE_GEOMETRY) { + } else if (entry->stage == PAL_SHADER_STAGE_GEOMETRY) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS; - } else if (tmp->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { + } else if (entry->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS; - } else if (tmp->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + } else if (entry->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS; - } else if (tmp->stage == PAL_SHADER_STAGE_TASK) { + } else if (entry->stage == PAL_SHADER_STAGE_TASK) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS; } else { @@ -7483,8 +7475,6 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( pipeline->topology = topology; pipeline->type = GRAPHICS_PIPELINE; - pipeline->shaders = nullptr; - pipeline->scratchBuffer = nullptr; pipeline->layout = layout; *outPipeline = (PalPipeline*)pipeline; @@ -7528,8 +7518,6 @@ PalResult PAL_CALL createComputePipelineD3D12( pipeline->type = COMPUTE_PIPELINE; pipeline->strides = nullptr; - pipeline->shaders = nullptr; - pipeline->scratchBuffer = nullptr; pipeline->hasFsr = false; pipeline->layout = layout; @@ -7543,62 +7531,86 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( PalPipeline** outPipeline) { HRESULT result; + Uint32 exportOffset = 0; + Uint32 exportCount = 0; Device* d3dDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; Pipeline* pipeline = nullptr; - Uint32 offset = 0; - D3D12_HIT_GROUP_DESC* groups = nullptr; + D3D12_DXIL_LIBRARY_DESC* libraries = nullptr; + D3D12_EXPORT_DESC* exports = nullptr; + RayHitGroup* groups = nullptr; D3D12_STATE_SUBOBJECT* subObjects = nullptr; - RayTracingShader* shaders = nullptr; - wchar_t* scratchBuffer = nullptr; - Uint32 groupSize = sizeof(D3D12_HIT_GROUP_DESC) * info->shaderGroupCount; - Uint32 shaderSize = sizeof(RayTracingShader) * info->shaderCount; - Uint32 subObjectCount = info->shaderCount + info->shaderGroupCount + 3; Uint32 subObjectIndex = 0; + Uint32 subObjectCount = info->shaderCount + info->shaderGroupCount + 2; if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + // Every entry is a shader export + for (int i = 0; i < info->shaderCount; i++) { + Shader* tmp = (Shader*)info->shaders[i]; + exportCount += tmp->entryCount; + } + pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); - groups = palAllocate(s_D3D.allocator, groupSize, 0); - shaders = palAllocate(s_D3D.allocator, shaderSize, 0); + if (!pipeline) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + pipeline->shaderExports = palAllocate(s_D3D.allocator, sizeof(ShaderExport) * exportCount, 0); subObjects = palAllocate(s_D3D.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); - scratchBuffer = palAllocate(s_D3D.allocator, MAX_SCRATCH_BUFFER_SIZE, 0); - if (!pipeline || !groups || !shaders || !subObjects || !scratchBuffer) { + exports = palAllocate(s_D3D.allocator, sizeof(D3D12_EXPORT_DESC) * exportCount, 0); + groups = palAllocate(s_D3D.allocator, sizeof(RayHitGroup) * info->shaderGroupCount, 0); + + libraries = palAllocate( + s_D3D.allocator, + sizeof(D3D12_DXIL_LIBRARY_DESC) * info->shaderCount, + 0); + + if (!pipeline->shaderExports|| !groups || !exports || !subObjects || !libraries) { return PAL_RESULT_OUT_OF_MEMORY; } // shaders - memset(groups, 0, sizeof(D3D12_HIT_GROUP_DESC) * info->shaderGroupCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; - shaders[i].stage = tmp->stage; - shaders[i].exports.Name = convertToWcharD3D12(scratchBuffer, &offset, tmp->exportName); + D3D12_DXIL_LIBRARY_DESC* library = &libraries[i]; - shaders[i].exports.ExportToRename = nullptr; - shaders[i].exports.Flags = D3D12_EXPORT_FLAG_NONE; + for (int j = 0; j < tmp->entryCount; i++) { + ShaderEntry* entry = &tmp->entries[j]; + ShaderExport* shaderExport = &pipeline->shaderExports[exportOffset + j]; + shaderExport->stage = entry->stage; + wcscpy(shaderExport->entryName, entry->entryName); - shaders[i].dxil.pExports = &shaders[i].exports; - shaders[i].dxil.NumExports = 1; - shaders[i].dxil.DXILLibrary = tmp->byteCode; + D3D12_EXPORT_DESC* export = &exports[exportOffset + j]; + export->Flags = D3D12_EXPORT_FLAG_NONE; + export->ExportToRename = nullptr; + export->Name = shaderExport->entryName; // reference + } + + library->DXILLibrary = tmp->byteCode; + library->NumExports = tmp->entryCount; + libraries->pExports = &exports[exportOffset]; + exportOffset += tmp->entryCount; subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; - subObjects[subObjectIndex].pDesc = &shaders[i].dxil; + subObjects[subObjectIndex].pDesc = library; subObjectIndex++; } // hit groups for (int i = 0; i < info->shaderGroupCount; i++) { PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; - D3D12_HIT_GROUP_DESC* group = &groups[i]; + D3D12_HIT_GROUP_DESC* group = &groups[i].desc; + convertToWcharD3D12(tmp->exportName, groups[i].entryName); group->AnyHitShaderImport = nullptr; group->ClosestHitShaderImport = nullptr; group->IntersectionShaderImport = nullptr; - group->HitGroupExport = convertToWcharD3D12(scratchBuffer, &offset, tmp->exportName); + group->HitGroupExport = groups[i].entryName; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { group->Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; @@ -7607,28 +7619,31 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( group->Type = D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE; } - // any hit shader + // Any hit shader if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - RayTracingShader* shader = &shaders[tmp->anyHitShaderIndex]; - if (shader) { - group->AnyHitShaderImport = shader->exports.Name; - } + Shader* shader = (Shader*)info->shaders[tmp->anyHitShaderIndex]; + group->AnyHitShaderImport = shader->entries[tmp->anyHitEntryIndex].entryName; + + } else { + group->AnyHitShaderImport = nullptr; } - // closest hit shader + // Closest hit shader if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - RayTracingShader* shader = &shaders[tmp->closestHitShaderIndex]; - if (shader) { - group->ClosestHitShaderImport = shader->exports.Name; - } + Shader* shader = (Shader*)info->shaders[tmp->closestHitShaderIndex]; + group->ClosestHitShaderImport = shader->entries[tmp->closestHitEntryIndex].entryName; + + } else { + group->ClosestHitShaderImport = nullptr; } - // intersection shader + // IntersectionShader shader if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { - RayTracingShader* shader = &shaders[tmp->intersectionShaderIndex]; - if (shader) { - group->IntersectionShaderImport = shader->exports.Name; - } + Shader* shader = (Shader*)info->shaders[tmp->intersectionShaderIndex]; + group->IntersectionShaderImport = shader->entries[tmp->intersectionEntryIndex].entryName; + + } else { + group->IntersectionShaderImport = nullptr; } subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP; @@ -7673,12 +7688,12 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( palFree(s_D3D.allocator, groups); palFree(s_D3D.allocator, subObjects); + palFree(s_D3D.allocator, libraries); + palFree(s_D3D.allocator, exports); pipeline->type = RAY_TRACING_PIPELINE; pipeline->strides = nullptr; pipeline->hasFsr = false; - pipeline->shaders = shaders; - pipeline->scratchBuffer = scratchBuffer; pipeline->layout = layout; *outPipeline = (PalPipeline*)pipeline; @@ -7701,12 +7716,8 @@ void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) palFree(s_D3D.allocator, d3dPipeline->strides); } - if (d3dPipeline->shaders) { - palFree(s_D3D.allocator, d3dPipeline->shaders); - } - - if (d3dPipeline->scratchBuffer) { - palFree(s_D3D.allocator, d3dPipeline->scratchBuffer); + if (d3dPipeline->shaderExports) { + palFree(s_D3D.allocator, d3dPipeline->shaderExports); } palFree(s_D3D.allocator, d3dPipeline); @@ -7815,25 +7826,27 @@ PalResult PAL_CALL createShaderBindingTableD3D12( } // get shader group handles + Uint32 index = 0; Uint32 totalGroups = info->raygenGroupCount + info->hitGroupCount; totalGroups += info->missGroupCount + info->callableGroupCount; + for (int i = 0; i < totalGroups; i++) { - RayTracingShader* tmp = &pipeline->shaders[i]; + ShaderExport* tmp = &pipeline->shaderExports[i]; PalShaderStage stage = tmp->stage; if (stage == PAL_SHADER_STAGE_RAYGEN) { - raygenHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->exports.Name); + raygenHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); } else if (stage == PAL_SHADER_STAGE_MISS) { - missHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->exports.Name); + missHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); } else if (stage == PAL_SHADER_STAGE_ANY_HIT || stage == PAL_SHADER_STAGE_CLOSEST_HIT || stage == PAL_SHADER_STAGE_INTERSECTION) { - hitHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->exports.Name); + hitHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); } else if (stage == PAL_SHADER_STAGE_CALLABLE) { - callableHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->exports.Name); + callableHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); } } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 8554b76d..cb216659 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -470,13 +470,20 @@ typedef struct { Image* images; } Swapchain; +typedef struct { + Uint32 tmpIndex; + Uint32 patchControlPoints; + VkShaderStageFlags stage; + char entryName[PAL_SHADER_ENTRY_NAME_SIZE]; +} ShaderEntry; + typedef struct { const PalGraphicsBackend* backend; - Uint32 patchControlPoints; + Uint32 entryCount; + ShaderEntry* entries; Device* device; VkShaderModule handle; - VkPipelineShaderStageCreateInfo info; } Shader; typedef struct { @@ -5963,33 +5970,44 @@ PalResult PAL_CALL createShaderVk( { VkResult result; Shader* shader = nullptr; - VkShaderStageFlags stage = 0; Device* vkDevice = (Device*)device; - stage = shaderStageToVK(info->stage); - if (info->stage == PAL_SHADER_STAGE_MESH || info->stage == PAL_SHADER_STAGE_TASK) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - // clang-format off - } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || - info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || - info->stage == PAL_SHADER_STAGE_ANY_HIT || - info->stage == PAL_SHADER_STAGE_MISS || - info->stage == PAL_SHADER_STAGE_INTERSECTION || - info->stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - // clang-format on - shader = palAllocate(s_Vk.allocator, sizeof(Shader), 0); if (!shader) { return PAL_RESULT_OUT_OF_MEMORY; } - memset(shader, 0, sizeof(Shader)); + + shader->entries = palAllocate(s_Vk.allocator, sizeof(ShaderEntry) * info->entryCount, 0); + if (!shader->entries) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + for (int i = 0; i < info->entryCount; i++) { + ShaderEntry* entry = &shader->entries[i]; + strncpy(entry->entryName, info->entries[i].entryName, PAL_SHADER_ENTRY_NAME_SIZE); + entry->entryName[PAL_SHADER_ENTRY_NAME_SIZE - 1] = '\0'; + entry->patchControlPoints = info->entries[i].patchControlPoints; + entry->stage = shaderStageToVK(info->entries[i].stage); + + if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || + info->entries[i].stage == PAL_SHADER_STAGE_TASK) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + // clang-format off + } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || + info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_MISS || + info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || + info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + // clang-format on + } VkShaderModuleCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; @@ -5998,17 +6016,13 @@ PalResult PAL_CALL createShaderVk( result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, shader->entries); palFree(s_Vk.allocator, shader); return resultFromVk(result); } shader->device = vkDevice; - shader->patchControlPoints = info->patchControlPoints; - shader->info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shader->info.module = shader->handle; - shader->info.pName = "main"; - shader->info.stage = stage; - + shader->entryCount = info->entryCount; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } @@ -6018,6 +6032,7 @@ void PAL_CALL destroyShaderVk(PalShader* shader) Shader* vkShader = (Shader*)shader; s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkShader->entries); palFree(s_Vk.allocator, vkShader); } @@ -8506,7 +8521,8 @@ PalResult PAL_CALL createGraphicsPipelineVk( Device* vkDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - VkPipelineShaderStageCreateInfo shaderStages[7]; // 7 shader types for graphics pipeline + Uint32 stagesCount = 0; + VkPipelineShaderStageCreateInfo* shaderStages = nullptr; VkDynamicState dynamicStates[16]; VkVertexInputBindingDescription* bindingDescs = nullptr; VkVertexInputAttributeDescription* attribDescs = nullptr; @@ -8550,27 +8566,50 @@ PalResult PAL_CALL createGraphicsPipelineVk( createInfo.renderPass = VK_NULL_HANDLE; createInfo.layout = layout->handle; + // Every entry is a shader stage + for (int i = 0; i < info->shaderCount; i++) { + Shader* tmp = (Shader*)info->shaders[i]; + stagesCount += tmp->entryCount; + } + pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); + shaderStages = palAllocate( + s_Vk.allocator, + sizeof(VkPipelineShaderStageCreateInfo) * stagesCount, + 0); + if (!pipeline) { return PAL_RESULT_OUT_OF_MEMORY; } // shaders + Uint32 stageIndex = 0; + memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stagesCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; - shaderStages[i] = tmp->info; - - if (tmp->patchControlPoints) { - tessellationState.patchControlPoints = tmp->patchControlPoints; - createInfo.pTessellationState = &tessellationState; - - if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { - palFree(s_Vk.allocator, pipeline); - return PAL_RESULT_INVALID_OPERATION; + for (int j = 0; j < tmp->entryCount; j++) { + ShaderEntry* entry = &tmp->entries[j]; + VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex]; + + stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageInfo->module = tmp->handle; + stageInfo->pName = entry->entryName; + stageInfo->stage = entry->stage; + stageIndex++; + + if (entry->patchControlPoints) { + tessellationState.patchControlPoints = entry->patchControlPoints; + createInfo.pTessellationState = &tessellationState; + + if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { + palFree(s_Vk.allocator, pipeline); + return PAL_RESULT_INVALID_OPERATION; + } } } } - createInfo.stageCount = info->shaderCount; + + createInfo.stageCount = stagesCount; createInfo.pStages = shaderStages; // Vertex input state @@ -8904,6 +8943,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( return resultFromVk(result); } + palFree(s_Vk.allocator, shaderStages); if (info->vertexLayoutCount) { palFree(s_Vk.allocator, bindingDescs); palFree(s_Vk.allocator, attribDescs); @@ -8938,7 +8978,11 @@ PalResult PAL_CALL createComputePipelineVk( VkComputePipelineCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; createInfo.layout = layout->handle; - createInfo.stage = shader->info; + + createInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + createInfo.stage.module = shader->handle; + createInfo.stage.stage = shader->entries[0].stage; + createInfo.stage.pName = shader->entries[1].entryName; VkResult result = s_Vk.createComputePipeline( vkDevice->handle, @@ -8969,50 +9013,110 @@ PalResult PAL_CALL createRayTracingPipelineVk( Device* vkDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; Pipeline* pipeline = nullptr; + Uint32 stagesCount = 0; VkPipelineShaderStageCreateInfo* shaderStages = nullptr; VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; - Uint32 groupSize = sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount; - Uint32 shaderSize = sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + // Every entry is a shader stage + for (int i = 0; i < info->shaderCount; i++) { + Shader* tmp = (Shader*)info->shaders[i]; + stagesCount += tmp->entryCount; + } + VkRayTracingPipelineCreateInfoKHR createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); - groups = palAllocate(s_Vk.allocator, groupSize, 0); - shaderStages = palAllocate(s_Vk.allocator, shaderSize, 0); + groups = palAllocate( + s_Vk.allocator, + sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount, + 0); + + shaderStages = palAllocate( + s_Vk.allocator, + sizeof(VkPipelineShaderStageCreateInfo) * stagesCount, + 0); + + if (!pipeline || !groups || !shaderStages) { return PAL_RESULT_OUT_OF_MEMORY; } // shaders - memset(groups, 0, sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount); + Uint32 stageIndex = 0; + memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stagesCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; - shaderStages[i] = tmp->info; + for (int j = 0; j < tmp->entryCount; i++) { + ShaderEntry* entry = &tmp->entries[j]; + VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex]; + + stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageInfo->module = tmp->handle; + stageInfo->pName = entry->entryName; + stageInfo->stage = entry->stage; + entry->tmpIndex = stageIndex++; + } } + createInfo.stageCount = stagesCount; + createInfo.pStages = shaderStages; + // shader groups for (int i = 0; i < info->shaderGroupCount; i++) { VkRayTracingShaderGroupCreateInfoKHR* group = &groups[i]; + PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; + group->sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - if (info->shaderGroups[i].type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - } else if (info->shaderGroups[i].type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { + } else if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; } else { group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; } - group->anyHitShader = info->shaderGroups[i].anyHitShaderIndex; - group->closestHitShader = info->shaderGroups[i].closestHitShaderIndex; - group->generalShader = info->shaderGroups[i].generalShaderIndex; - group->intersectionShader = info->shaderGroups[i].intersectionShaderIndex; + // Any hit shader + if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { + Shader* shader = (Shader*)info->shaders[tmp->anyHitShaderIndex]; + group->anyHitShader = shader->entries[tmp->anyHitEntryIndex].tmpIndex; + + } else { + group->anyHitShader = VK_SHADER_UNUSED_KHR; + } + + // Closest hit shader + if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { + Shader* shader = (Shader*)info->shaders[tmp->closestHitShaderIndex]; + group->closestHitShader = shader->entries[tmp->closestHitEntryIndex].tmpIndex; + + } else { + group->closestHitShader = VK_SHADER_UNUSED_KHR; + } + + // General shader + if (tmp->generalShaderIndex != PAL_UNUSED_SHADER_INDEX) { + Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; + group->generalShader = shader->entries[tmp->generalEntryIndex].tmpIndex; + + } else { + group->generalShader = VK_SHADER_UNUSED_KHR; + } + + // IntersectionShader shader + if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { + Shader* shader = (Shader*)info->shaders[tmp->intersectionShaderIndex]; + group->intersectionShader = shader->entries[tmp->intersectionEntryIndex].tmpIndex; + + } else { + group->intersectionShader = VK_SHADER_UNUSED_KHR; + } } createInfo.stageCount = info->shaderCount; diff --git a/src/pal_core.c b/src/pal_core.c index 8ff8c816..ffa0cfc1 100644 --- a/src/pal_core.c +++ b/src/pal_core.c @@ -419,6 +419,9 @@ const char* PAL_CALL palFormatResult(PalResult result) case PAL_RESULT_INVALID_OPERATION: return "Invalid operation"; + case PAL_RESULT_INVALID_SHADER: + return "Invalid shader"; + case PAL_RESULT_INVALID_SHADER_TYPE: return "Invalid shader type"; diff --git a/tests/tests.lua b/tests/tests.lua index c84fe701..4fb6adda 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -70,17 +70,17 @@ project "tests" if (PAL_BUILD_GRAPHICS) then files { "graphics/graphics_test.c", - "graphics/compute_test.c", - "graphics/ray_tracing_test.c" + -- "graphics/compute_test.c", + -- "graphics/ray_tracing_test.c" } end if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { - "graphics/clear_color_test.c", - "graphics/triangle_test.c", - "graphics/mesh_test.c", - "graphics/texture_test.c" + -- "graphics/clear_color_test.c", + -- "graphics/triangle_test.c", + -- "graphics/mesh_test.c", + -- "graphics/texture_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 2b0203a9..310f92dd 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,7 +57,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest, "Graphics Test"); + registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders #endif // PAL_HAS_GRAPHICS @@ -66,7 +66,7 @@ int main(int argc, char** argv) // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); - registerTest(textureTest, "Texture Test"); + // registerTest(textureTest, "Texture Test"); #endif // runTests(); From 1edabd7b597361f77a83b4c6489846f5c025982d Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 1 May 2026 11:29:40 +0000 Subject: [PATCH 193/372] fix graphics tests with new shader API vulkan --- include/pal/pal_graphics.h | 3 +++ src/graphics/pal_vulkan.c | 24 +++++++++++++----------- tests/graphics/compute_test.c | 9 ++++++++- tests/graphics/mesh_test.c | 16 ++++++++++++++-- tests/graphics/ray_tracing_test.c | 23 ++++++++++++++++++++--- tests/graphics/texture_test.c | 16 ++++++++++++++-- tests/graphics/triangle_test.c | 16 ++++++++++++++-- tests/tests.lua | 12 ++++++------ tests/tests_main.c | 2 +- 9 files changed, 93 insertions(+), 28 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 8b321dda..ccec451a 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -5137,6 +5137,9 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * `PAL_SHADER_STAGE_RAYGEN` or `PAL_SHADER_STAGE_CLOSEST_HIT` or `PAL_SHADER_STAGE_ANY_HIT` or * `PAL_SHADER_STAGE_MISS` or `PAL_SHADER_STAGE_INTERSECTION` or `PAL_SHADER_STAGE_CALLABLE` will * be used. + * + * If the pipeline only takes a single shader (eg. Compute Pipeline), only the first entry in + * the entries array will be used. * * @param[in] device Device that creates the shader. * @param[in] info Pointer to a PalShaderCreateInfo struct that specifies parameters. diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index cb216659..0aba7826 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -8587,6 +8587,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stagesCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; + for (int j = 0; j < tmp->entryCount; j++) { ShaderEntry* entry = &tmp->entries[j]; VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex]; @@ -8792,17 +8793,17 @@ PalResult PAL_CALL createGraphicsPipelineVk( // clang-format off if (state->sampleMask) { - if (info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_1 || - info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_2 || - info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_4 || - info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_8 || - info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_16 || - info->multisampleState->sampleCount == PAL_SAMPLE_COUNT_32) { - sampleMask[0] = (Uint32)(info->multisampleState->sampleMask & 0xFFFFFFFFULL); + if (state->sampleCount == PAL_SAMPLE_COUNT_1 || + state->sampleCount == PAL_SAMPLE_COUNT_2 || + state->sampleCount == PAL_SAMPLE_COUNT_4 || + state->sampleCount == PAL_SAMPLE_COUNT_8 || + state->sampleCount == PAL_SAMPLE_COUNT_16 || + state->sampleCount == PAL_SAMPLE_COUNT_32) { + sampleMask[0] = (Uint32)(state->sampleMask & 0xFFFFFFFFULL); } else { - sampleMask[0] = (Uint32)(info->multisampleState->sampleMask & 0xFFFFFFFFULL); - sampleMask[1] = (Uint32)((info->multisampleState->sampleMask >> 32) & 0xFFFFFFFFULL); + sampleMask[0] = (Uint32)(state->sampleMask & 0xFFFFFFFFULL); + sampleMask[1] = (Uint32)((state->sampleMask >> 32) & 0xFFFFFFFFULL); } multisampleState.pSampleMask = sampleMask; @@ -8982,7 +8983,7 @@ PalResult PAL_CALL createComputePipelineVk( createInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; createInfo.stage.module = shader->handle; createInfo.stage.stage = shader->entries[0].stage; - createInfo.stage.pName = shader->entries[1].entryName; + createInfo.stage.pName = shader->entries[0].entryName; VkResult result = s_Vk.createComputePipeline( vkDevice->handle, @@ -9051,7 +9052,8 @@ PalResult PAL_CALL createRayTracingPipelineVk( memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stagesCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; - for (int j = 0; j < tmp->entryCount; i++) { + + for (int j = 0; j < tmp->entryCount; j++) { ShaderEntry* entry = &tmp->entries[j]; VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex]; diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 0ee01395..55b3dfc7 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -199,9 +199,16 @@ bool computeTest() bytecodeSize = sizeof(s_ComputeShaderDxil); } + // describe how many entries are in the shader bytecode + // We only have one entry for the compute shader. + PalShaderEntry computeEntry = {0}; + computeEntry.entryName = "main"; + computeEntry.stage = PAL_SHADER_STAGE_COMPUTE; + shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.stage = PAL_SHADER_STAGE_COMPUTE; + shaderCreateInfo.entryCount = 1; + shaderCreateInfo.entries = &computeEntry; result = palCreateShader(device, &shaderCreateInfo, &shader); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index ef4326bc..f8d2a028 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -417,13 +417,25 @@ bool meshTest() fragBytecode = (void*)s_TriangleFragShaderDxil; } + // describe how many entries are in the shader bytecode + // For simplicity, we dont use one shader bytecode for all the shaders + PalShaderEntry meshEntry = {0}; + meshEntry.entryName = "main"; + meshEntry.stage = PAL_SHADER_STAGE_MESH; + + PalShaderEntry fragmentEntry = {0}; + fragmentEntry.entryName = "main"; + fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; + meshShaderCreateInfo.bytecode = meshBytecode; meshShaderCreateInfo.bytecodeSize = meshBytecodeSize; - meshShaderCreateInfo.stage = PAL_SHADER_STAGE_MESH; + meshShaderCreateInfo.entries = &meshEntry; + meshShaderCreateInfo.entryCount = 1; fragShaderCreateInfo.bytecode = fragBytecode; fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; - fragShaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; + fragShaderCreateInfo.entries = &fragmentEntry; + fragShaderCreateInfo.entryCount = 1; result = palCreateShader(device, &meshShaderCreateInfo, &meshShader); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index d167b2fb..48f6b5a3 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -224,17 +224,34 @@ bool rayTracingTest() return false; } + // describe how many entries are in the shader bytecode + // For simplicity, we dont use one shader bytecode for all the shaders + PalShaderEntry raygenEntry = {0}; + raygenEntry.entryName = "main"; + raygenEntry.stage = PAL_SHADER_STAGE_RAYGEN; + + PalShaderEntry closestHitEntry = {0}; + closestHitEntry.entryName = "main"; + closestHitEntry.stage = PAL_SHADER_STAGE_CLOSEST_HIT; + + PalShaderEntry missEntry = {0}; + missEntry.entryName = "main"; + missEntry.stage = PAL_SHADER_STAGE_MISS; + raygenShaderCreateInfo.bytecode = raygenBytecode; raygenShaderCreateInfo.bytecodeSize = raygenBytecodeSize; - raygenShaderCreateInfo.stage = PAL_SHADER_STAGE_RAYGEN; + raygenShaderCreateInfo.entries = &raygenEntry; + raygenShaderCreateInfo.entryCount = 1; closestHitShaderCreateInfo.bytecode = closestHitBytecode; closestHitShaderCreateInfo.bytecodeSize = closestHitBytecodeSize; - closestHitShaderCreateInfo.stage = PAL_SHADER_STAGE_CLOSEST_HIT; + closestHitShaderCreateInfo.entries = &closestHitEntry; + closestHitShaderCreateInfo.entryCount = 1; missShaderCreateInfo.bytecode = missBytecode; missShaderCreateInfo.bytecodeSize = missBytecodeSize; - missShaderCreateInfo.stage = PAL_SHADER_STAGE_MISS; + missShaderCreateInfo.entries = &missEntry; + missShaderCreateInfo.entryCount = 1; result = palCreateShader(device, &raygenShaderCreateInfo, &raygenShader); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 04c41d90..9806bf6d 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -869,13 +869,25 @@ bool textureTest() fragBytecode = (void*)s_TextureFragShaderDxil; } + // describe how many entries are in the shader bytecode + // For simplicity, we dont use one shader bytecode for all the shaders + PalShaderEntry vertEntry = {0}; + vertEntry.entryName = "main"; + vertEntry.stage = PAL_SHADER_STAGE_VERTEX; + + PalShaderEntry fragmentEntry = {0}; + fragmentEntry.entryName = "main"; + fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; + vertShaderCreateInfo.bytecode = vertBytecode; vertShaderCreateInfo.bytecodeSize = vertBytecodeSize; - vertShaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; + vertShaderCreateInfo.entries = &vertEntry; + vertShaderCreateInfo.entryCount = 1; fragShaderCreateInfo.bytecode = fragBytecode; fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; - fragShaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; + fragShaderCreateInfo.entries = &fragmentEntry; + fragShaderCreateInfo.entryCount = 1; result = palCreateShader(device, &vertShaderCreateInfo, &vertexShader); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 4f167b01..60efbac7 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -573,13 +573,25 @@ bool triangleTest() fragBytecode = (void*)s_TriangleFragShaderDxil; } + // describe how many entries are in the shader bytecode + // For simplicity, we dont use one shader bytecode for all the shaders + PalShaderEntry vertexEntry = {0}; + vertexEntry.entryName = "main"; + vertexEntry.stage = PAL_SHADER_STAGE_VERTEX; + + PalShaderEntry fragmentEntry = {0}; + fragmentEntry.entryName = "main"; + fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; + vertShaderCreateInfo.bytecode = vertBytecode; vertShaderCreateInfo.bytecodeSize = vertBytecodeSize; - vertShaderCreateInfo.stage = PAL_SHADER_STAGE_VERTEX; + vertShaderCreateInfo.entries = &vertexEntry; + vertShaderCreateInfo.entryCount = 1; fragShaderCreateInfo.bytecode = fragBytecode; fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; - fragShaderCreateInfo.stage = PAL_SHADER_STAGE_FRAGMENT; + fragShaderCreateInfo.entries = &fragmentEntry; + fragShaderCreateInfo.entryCount = 1; result = palCreateShader(device, &vertShaderCreateInfo, &vertexShader); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/tests.lua b/tests/tests.lua index 4fb6adda..c84fe701 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -70,17 +70,17 @@ project "tests" if (PAL_BUILD_GRAPHICS) then files { "graphics/graphics_test.c", - -- "graphics/compute_test.c", - -- "graphics/ray_tracing_test.c" + "graphics/compute_test.c", + "graphics/ray_tracing_test.c" } end if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then files { - -- "graphics/clear_color_test.c", - -- "graphics/triangle_test.c", - -- "graphics/mesh_test.c", - -- "graphics/texture_test.c" + "graphics/clear_color_test.c", + "graphics/triangle_test.c", + "graphics/mesh_test.c", + "graphics/texture_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 310f92dd..8307a47c 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,7 +57,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest, "Graphics Test"); + // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders #endif // PAL_HAS_GRAPHICS From a68f2d3aa7935a0c2f465fcec9b310c639a4d561 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 1 May 2026 16:20:22 +0000 Subject: [PATCH 194/372] fix graphics tests with new shader API d3d12 --- include/pal/pal_graphics.h | 10 +- src/graphics/pal_d3d12.c | 78 ++- tests/graphics/mesh_test.c | 4 +- tests/graphics/ray_tracing_test.c | 18 +- tests/graphics/shaders.h | 889 +++++++++++++++++++++++++++++- tests/graphics/texture_test.c | 2 + tests/tests_main.c | 4 +- 7 files changed, 964 insertions(+), 41 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index ccec451a..e2f8b0ba 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2682,10 +2682,9 @@ typedef struct { Uint32 generalShaderIndex; /**< Index of general hit shader from shader array.*/ Uint32 intersectionShaderIndex; /**< Index of intersection hit shader from shader array.*/ Uint32 anyHitEntryIndex; /**< Index of any hit Entry from `anyHitShaderIndex`.*/ - Uint32 closestHitEntryIndex; /**< Index of any hit Entry from `anyHitShaderIndex`.*/ - Uint32 generalEntryIndex; /**< Index of any hit Entry from `anyHitShaderIndex`.*/ - Uint32 intersectionEntryIndex; /**< Index of any hit Entry from `anyHitShaderIndex`.*/ - const char* exportName; + Uint32 closestHitEntryIndex; /**< Index of any hit Entry from `closestHitShaderIndex`.*/ + Uint32 generalEntryIndex; /**< Index of any hit Entry from `generalShaderIndex`.*/ + Uint32 intersectionEntryIndex; /**< Index of any hit Entry from `intersectionShaderIndex`.*/ } PalRayTracingShaderGroupCreateInfo; /** @@ -7290,6 +7289,9 @@ PAL_API PalResult PAL_CALL palCreateComputePipeline( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. + * + * @note The shader group index will be based on the order of + * PalRayTracingPipelineCreateInfo::shaderGroups. * * @since 1.4 * @ingroup pal_graphics diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index a70988a9..b66f61f6 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -1818,6 +1818,14 @@ static void convertToWcharD3D12( dst[i] = L'\0'; } +static void getHitGroupNameD3D12( + Uint32 index, + wchar_t dst[PAL_SHADER_ENTRY_NAME_SIZE]) +{ + wcscpy(dst, L"HitGroup"); + _itow(index, dst + 8, 10); +} + static void pollMessagesD3D12(Device* device) { ID3D12InfoQueue* queue = device->infoQueue; @@ -7063,11 +7071,6 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( totalSize += sizeof(ShaderStream); D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - // D3D12 only supports a single entry for graphics pipeline shaders - if (tmp->entryCount != 1) { - return PAL_RESULT_INVALID_SHADER; - } - ShaderEntry* entry = &tmp->entries[0]; if (entry->patchControlPoints) { patchControlPoints = entry->patchControlPoints; @@ -7476,6 +7479,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( pipeline->topology = topology; pipeline->type = GRAPHICS_PIPELINE; pipeline->layout = layout; + pipeline->shaderExports = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -7520,6 +7524,7 @@ PalResult PAL_CALL createComputePipelineD3D12( pipeline->strides = nullptr; pipeline->hasFsr = false; pipeline->layout = layout; + pipeline->shaderExports = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -7533,17 +7538,22 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( HRESULT result; Uint32 exportOffset = 0; Uint32 exportCount = 0; + Uint32 hitGroupIndex = 0; + Uint32 hitGroupCount = 0; + Uint32 subObjectIndex = 0; + + // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG + // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG + Uint32 subObjectCount = info->shaderCount + 2; + Device* d3dDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; Pipeline* pipeline = nullptr; D3D12_DXIL_LIBRARY_DESC* libraries = nullptr; - D3D12_EXPORT_DESC* exports = nullptr; RayHitGroup* groups = nullptr; D3D12_STATE_SUBOBJECT* subObjects = nullptr; - - Uint32 subObjectIndex = 0; - Uint32 subObjectCount = info->shaderCount + info->shaderGroupCount + 2; + D3D12_EXPORT_DESC* exportDesc = nullptr; if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -7555,22 +7565,31 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( exportCount += tmp->entryCount; } + for (int i = 0; i < info->shaderGroupCount; i++) { + PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { + continue; + } + hitGroupCount++; + subObjectCount++; + } + pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); if (!pipeline) { return PAL_RESULT_OUT_OF_MEMORY; } pipeline->shaderExports = palAllocate(s_D3D.allocator, sizeof(ShaderExport) * exportCount, 0); + exportDesc = palAllocate(s_D3D.allocator, sizeof(D3D12_EXPORT_DESC) * exportCount, 0); subObjects = palAllocate(s_D3D.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); - exports = palAllocate(s_D3D.allocator, sizeof(D3D12_EXPORT_DESC) * exportCount, 0); - groups = palAllocate(s_D3D.allocator, sizeof(RayHitGroup) * info->shaderGroupCount, 0); + groups = palAllocate(s_D3D.allocator, sizeof(RayHitGroup) * hitGroupCount, 0); libraries = palAllocate( s_D3D.allocator, sizeof(D3D12_DXIL_LIBRARY_DESC) * info->shaderCount, 0); - if (!pipeline->shaderExports|| !groups || !exports || !subObjects || !libraries) { + if (!pipeline->shaderExports || !exportDesc || !groups || !subObjects || !libraries) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7579,21 +7598,20 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( Shader* tmp = (Shader*)info->shaders[i]; D3D12_DXIL_LIBRARY_DESC* library = &libraries[i]; - for (int j = 0; j < tmp->entryCount; i++) { + for (int j = 0; j < tmp->entryCount; j++) { ShaderEntry* entry = &tmp->entries[j]; ShaderExport* shaderExport = &pipeline->shaderExports[exportOffset + j]; shaderExport->stage = entry->stage; wcscpy(shaderExport->entryName, entry->entryName); - D3D12_EXPORT_DESC* export = &exports[exportOffset + j]; - export->Flags = D3D12_EXPORT_FLAG_NONE; - export->ExportToRename = nullptr; - export->Name = shaderExport->entryName; // reference + exportDesc[exportOffset + j].Flags = D3D12_EXPORT_FLAG_NONE; + exportDesc[exportOffset + j].ExportToRename = nullptr; + exportDesc[exportOffset + j].Name = shaderExport->entryName; // reference } library->DXILLibrary = tmp->byteCode; library->NumExports = tmp->entryCount; - libraries->pExports = &exports[exportOffset]; + libraries->pExports = &exportDesc[exportOffset]; exportOffset += tmp->entryCount; subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; @@ -7604,25 +7622,30 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // hit groups for (int i = 0; i < info->shaderGroupCount; i++) { PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; - D3D12_HIT_GROUP_DESC* group = &groups[i].desc; - convertToWcharD3D12(tmp->exportName, groups[i].entryName); + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { + continue; + } + + D3D12_HIT_GROUP_DESC* group = &groups[hitGroupIndex].desc; + getHitGroupNameD3D12(hitGroupIndex, groups[hitGroupIndex].entryName); group->AnyHitShaderImport = nullptr; group->ClosestHitShaderImport = nullptr; group->IntersectionShaderImport = nullptr; - group->HitGroupExport = groups[i].entryName; + group->HitGroupExport = groups[hitGroupIndex].entryName; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { group->Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; - } else { + } else if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT) { group->Type = D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE; } // Any hit shader if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->anyHitShaderIndex]; - group->AnyHitShaderImport = shader->entries[tmp->anyHitEntryIndex].entryName; + ShaderEntry* entry = &shader->entries[tmp->anyHitEntryIndex]; + group->AnyHitShaderImport = entry->entryName; } else { group->AnyHitShaderImport = nullptr; @@ -7631,7 +7654,8 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // Closest hit shader if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->closestHitShaderIndex]; - group->ClosestHitShaderImport = shader->entries[tmp->closestHitEntryIndex].entryName; + ShaderEntry* entry = &shader->entries[tmp->closestHitEntryIndex]; + group->AnyHitShaderImport = entry->entryName; } else { group->ClosestHitShaderImport = nullptr; @@ -7640,7 +7664,8 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // IntersectionShader shader if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->intersectionShaderIndex]; - group->IntersectionShaderImport = shader->entries[tmp->intersectionEntryIndex].entryName; + ShaderEntry* entry = &shader->entries[tmp->intersectionEntryIndex]; + group->AnyHitShaderImport = entry->entryName; } else { group->IntersectionShaderImport = nullptr; @@ -7649,6 +7674,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP; subObjects[subObjectIndex].pDesc = group; subObjectIndex++; + hitGroupIndex++; } // ray tracing config @@ -7689,7 +7715,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( palFree(s_D3D.allocator, groups); palFree(s_D3D.allocator, subObjects); palFree(s_D3D.allocator, libraries); - palFree(s_D3D.allocator, exports); + palFree(s_D3D.allocator, exportDesc); pipeline->type = RAY_TRACING_PIPELINE; pipeline->strides = nullptr; diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index f8d2a028..d576a5ac 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -176,7 +176,7 @@ bool meshTest() } if (hasMeshShader) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 + // We want an adapter that supports spirv 1.5 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -186,7 +186,7 @@ bool meshTest() // we prefer spirv first if an adapter supports multiple shader formats if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_5)) { break; } } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 48f6b5a3..786b7101 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -124,7 +124,7 @@ bool rayTracingTest() } if (hasTracing) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 + // We want an adapter that supports spirv 1.4 or dxil 6.3 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -134,13 +134,13 @@ bool rayTracingTest() // we prefer spirv first if an adapter supports multiple shader formats if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_3)) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_4)) { break; } } if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_3)) { break; } } @@ -220,8 +220,13 @@ bool rayTracingTest() missBytecode = (void*)s_MissShaderSpv; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - palLog(nullptr, "Dxil not tested yet"); - return false; + raygenBytecodeSize = sizeof(s_RaygenShaderDxil); + closestHitBytecodeSize = sizeof(s_ClosestHitShaderDxil); + missBytecodeSize = sizeof(s_MissShaderDxil); + + raygenBytecode = (void*)s_RaygenShaderDxil; + closestHitBytecode = (void*)s_ClosestHitShaderDxil; + missBytecode = (void*)s_MissShaderDxil; } // describe how many entries are in the shader bytecode @@ -807,18 +812,21 @@ bool rayTracingTest() shaderGroupCreateInfos[0].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[0].generalEntryIndex = 0; // First shader entry shaderGroupCreateInfos[1].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; shaderGroupCreateInfos[1].generalShaderIndex = 1; // must match miss index shaderGroupCreateInfos[1].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[1].generalEntryIndex = 0; // First shader entry shaderGroupCreateInfos[2].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT; shaderGroupCreateInfos[2].closestHitShaderIndex = 2; // must match closest hit index shaderGroupCreateInfos[2].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[2].generalShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[2].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[2].closestHitEntryIndex = 0; // First shader entry // create a ray tracing pipeline PalRayTracingPipelineCreateInfo pipelineCreateInfo = {0}; diff --git a/tests/graphics/shaders.h b/tests/graphics/shaders.h index 66c78813..93899c8c 100644 --- a/tests/graphics/shaders.h +++ b/tests/graphics/shaders.h @@ -532,6 +532,73 @@ static const Uint8 s_ComputeShaderDxil[] = { // } // HLSL +// Raygen +// struct RayPayload +// { +// float3 color; +// }; + +// RWByteAddressBuffer outBuffer : register(u0); +// RaytracingAccelerationStructure tlas : register(t0); + +// [shader("raygeneration")] +// void main() +// { +// uint2 pixel = DispatchRaysIndex().xy; +// uint2 size = DispatchRaysDimensions().xy; +// RayPayload payload; +// payload.color = float3(0.0, 0.0, 0.0); + +// float2 uv = (float2(pixel) + 0.5) / float2(size); +// float2 ndcUv = uv * 2.0 - 1.0; + +// RayDesc desc; +// desc.Origin = float3(0.0, 0.0, -3.0);; +// desc.Direction = normalize(float3(ndcUv.x, ndcUv.y, 1.0));; +// desc.TMin = 0.001; +// desc.TMax = 1000.0; +// TraceRay(tlas, RAY_FLAG_NONE, 0xFF, 0, 0, 0, desc, payload); + +// if (pixel.x >= size.x || pixel.y >= size.y) { +// return; +// } + +// uint index = pixel.y * size.x + pixel.x; +// uint offset = index * 16; // sizeof(float4) +// float4 color = float4(payload.color, 1.0); +// outBuffer.Store4(offset, asuint(color)); +// } + +// Closest Hit +// struct RayPayload +// { +// float3 color; +// }; + +// struct HitAttributes +// { +// float2 unused; +// }; + +// [shader("closesthit")] +// void main( +// inout RayPayload payload, +// in HitAttributes attr) +// { +// payload.color = float3(0.0, 1.0, 0.0); +// } + +// Miss +// struct RayPayload +// { +// float3 color; +// }; + +// [shader("miss")] +// void main(inout RayPayload payload) +// { +// payload.color = float3(0.0, 0.0, 0.0); +// } static const Uint32 s_RaygenShaderSpv[] = { 0x07230203, 0x00010600, 0x0008000b, 0x0000006d, @@ -753,6 +820,824 @@ static const Uint32 s_MissShaderSpv[] = { 0x00010038 }; +static const Uint8 s_RaygenShaderDxil[] = { + 0x44, 0x58, 0x42, 0x43, 0xac, 0x98, 0x93, 0xce, 0x61, 0x31, 0x12, 0x64, + 0x6a, 0xbd, 0x43, 0xc2, 0x54, 0xba, 0xb4, 0x35, 0x01, 0x00, 0x00, 0x00, + 0xf8, 0x10, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, + 0xa4, 0x08, 0x00, 0x00, 0xc0, 0x08, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x45, 0x52, 0x53, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x14, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x32, 0x31, 0x64, 0x32, 0x38, 0x66, 0x37, 0x32, 0x00, 0x31, 0x2e, 0x39, + 0x2e, 0x32, 0x36, 0x30, 0x32, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x52, 0x44, 0x41, 0x54, 0xec, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x94, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x74, 0x6c, 0x61, 0x73, 0x00, 0x6f, 0x75, + 0x74, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x00, 0x01, 0x3f, 0x6d, 0x61, + 0x69, 0x6e, 0x40, 0x40, 0x59, 0x41, 0x58, 0x58, 0x5a, 0x00, 0x6d, 0x61, + 0x69, 0x6e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x63, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0x30, 0x07, 0x00, 0x00, + 0x63, 0x00, 0x06, 0x00, 0xcc, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x07, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0xc3, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xc4, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x62, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x11, 0x23, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x31, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0xda, 0x60, 0x08, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x12, 0x40, 0x6d, 0x30, 0x86, 0xff, + 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x88, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x23, 0xa4, 0x84, + 0x04, 0x13, 0x23, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8c, 0x8c, + 0x0b, 0x84, 0xc4, 0x4c, 0x10, 0x80, 0xc1, 0x1c, 0x01, 0x18, 0x9c, 0x26, + 0x4d, 0x11, 0x25, 0x4c, 0xfe, 0x0a, 0x6f, 0xd8, 0x44, 0x68, 0xc3, 0x10, + 0x11, 0x92, 0xb4, 0x51, 0x45, 0x41, 0x44, 0x28, 0x00, 0x28, 0x38, 0x33, + 0x90, 0xa6, 0x88, 0x12, 0x26, 0x7f, 0x05, 0xb0, 0x29, 0x02, 0x04, 0xa4, + 0x31, 0x34, 0x41, 0x20, 0x16, 0x22, 0x02, 0x26, 0xc4, 0x69, 0xd8, 0x29, + 0xa2, 0x84, 0x89, 0x8a, 0x08, 0x14, 0x00, 0x34, 0x8c, 0x00, 0x94, 0xa0, + 0x20, 0x63, 0x8e, 0x00, 0x29, 0x03, 0x00, 0x20, 0x94, 0xcc, 0x00, 0x14, + 0x64, 0x01, 0x96, 0x65, 0x59, 0x96, 0x85, 0x98, 0x32, 0x2c, 0xc0, 0x42, + 0x0e, 0x21, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, + 0x0c, 0x0b, 0x81, 0x02, 0xa8, 0x2c, 0x05, 0x10, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x90, 0x34, 0x8c, 0x30, 0x2c, 0x17, 0x49, 0x53, 0x44, 0x09, + 0x93, 0xbf, 0x02, 0x58, 0x0a, 0x60, 0x8b, 0x03, 0x0c, 0x28, 0xa0, 0xa8, + 0x2a, 0x51, 0x01, 0x44, 0x00, 0x00, 0x00, 0xc0, 0xb2, 0x2c, 0xcb, 0xb2, + 0x2c, 0x8b, 0x45, 0x57, 0x19, 0x22, 0x60, 0xa0, 0xac, 0x0c, 0x11, 0x10, + 0xd0, 0x36, 0x10, 0x30, 0x47, 0x10, 0xcc, 0x11, 0x80, 0x02, 0x00, 0x00, + 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, + 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, + 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, + 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, + 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, + 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, + 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x3a, 0x0f, 0x44, 0x90, 0x21, 0x23, + 0x45, 0x44, 0x00, 0x36, 0x00, 0x60, 0x3e, 0x00, 0xe0, 0x21, 0x8f, 0x01, + 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x9e, + 0x04, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, + 0x3c, 0x09, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x79, 0x18, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x30, 0xe4, 0x91, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0xc8, 0x73, 0x01, 0x01, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x90, 0x27, 0x03, 0x02, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x21, 0xcf, 0x06, 0x04, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x20, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, + 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x02, 0x4a, 0xa0, 0x0c, 0x46, + 0x00, 0x8a, 0xa1, 0x40, 0x0a, 0xa1, 0x2c, 0x0a, 0xa3, 0x1c, 0x4a, 0xa2, + 0x34, 0x0a, 0xa2, 0x14, 0x4a, 0xab, 0x08, 0xe8, 0x2b, 0x10, 0xf2, 0x46, + 0x00, 0xa8, 0x9a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x71, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, + 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, + 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, + 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x80, + 0x65, 0x82, 0x00, 0x30, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x00, 0xcd, 0x06, + 0xc1, 0x30, 0x38, 0xb0, 0xa5, 0x89, 0x4d, 0x10, 0x00, 0x67, 0xc3, 0x80, + 0x24, 0xc4, 0x04, 0x81, 0x08, 0x48, 0xd0, 0xb1, 0x85, 0xcd, 0x4d, 0x10, + 0x80, 0x67, 0x82, 0x00, 0x40, 0x1b, 0x04, 0xc3, 0xd9, 0x90, 0x18, 0x0b, + 0x63, 0x18, 0x43, 0x63, 0x3c, 0x1b, 0x02, 0x68, 0x82, 0x20, 0x00, 0x4c, + 0xde, 0xea, 0xe8, 0x84, 0xea, 0xcc, 0xcc, 0xca, 0xe4, 0x26, 0x08, 0x40, + 0x34, 0x41, 0xf0, 0xb6, 0x0d, 0x8b, 0x21, 0x4d, 0x86, 0x31, 0x50, 0x55, + 0x55, 0x01, 0x1b, 0x02, 0x6b, 0x03, 0x11, 0x5d, 0x00, 0x30, 0x41, 0xa8, + 0xb8, 0x09, 0x02, 0x20, 0xb1, 0x18, 0x7b, 0x63, 0x7b, 0x93, 0x9b, 0x20, + 0x00, 0xd3, 0x04, 0x01, 0xa0, 0x26, 0x08, 0x40, 0xb5, 0x01, 0x49, 0x36, + 0xc2, 0xe0, 0x3a, 0x8f, 0xd8, 0x20, 0x68, 0xdf, 0x86, 0xc1, 0xc8, 0xc0, + 0x60, 0x82, 0x70, 0x08, 0x1b, 0x80, 0x0d, 0xc3, 0x30, 0x06, 0x63, 0xb0, + 0x21, 0x20, 0x83, 0x0d, 0xc3, 0x20, 0x06, 0x65, 0x40, 0x60, 0x82, 0xf0, + 0x69, 0x1b, 0x04, 0x03, 0x0d, 0x36, 0x14, 0xc0, 0x19, 0x00, 0x58, 0x1a, + 0xb0, 0x09, 0xf8, 0x69, 0x0b, 0x4b, 0x73, 0x03, 0x02, 0xca, 0x0a, 0xc2, + 0xc2, 0xd2, 0x9a, 0x20, 0x00, 0xd6, 0x04, 0x01, 0xb8, 0x36, 0x04, 0xc6, + 0x06, 0x82, 0x0d, 0xb8, 0x36, 0x70, 0x83, 0x0d, 0x85, 0x18, 0xac, 0x01, + 0x00, 0xbc, 0x01, 0x11, 0x31, 0xb9, 0x30, 0xb7, 0x31, 0xb4, 0xb2, 0x39, + 0x1a, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x73, 0x2c, 0xd2, 0xdc, 0xe6, 0xe8, + 0xe6, 0x26, 0x08, 0x00, 0x46, 0x22, 0xcd, 0x8d, 0x6e, 0x8e, 0x09, 0x5d, + 0x19, 0xde, 0xd7, 0x1c, 0xdd, 0x9b, 0x5c, 0x19, 0x8b, 0xba, 0x34, 0x37, + 0xba, 0xb9, 0x09, 0x02, 0x90, 0x6d, 0x60, 0xe2, 0x60, 0x90, 0x83, 0x66, + 0x0e, 0xe8, 0xa0, 0x0e, 0x1c, 0x3b, 0x18, 0xee, 0x00, 0x0f, 0xaa, 0xb0, + 0xb1, 0xd9, 0xb5, 0xb9, 0xa4, 0x91, 0x95, 0xb9, 0xd1, 0x4d, 0x09, 0x82, + 0x2a, 0x64, 0x78, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, + 0x02, 0xa2, 0x09, 0x19, 0x9e, 0x8b, 0x5d, 0x18, 0x9b, 0x5d, 0x99, 0xdc, + 0x94, 0xc0, 0xa8, 0x43, 0x86, 0xe7, 0x32, 0x87, 0x16, 0x46, 0x56, 0x26, + 0xd7, 0xf4, 0x46, 0x56, 0xc6, 0x36, 0x25, 0x48, 0xca, 0x90, 0xe1, 0xb9, + 0xc8, 0x95, 0xcd, 0xbd, 0xd5, 0xc9, 0x8d, 0x95, 0xcd, 0x4d, 0x09, 0xae, + 0x4a, 0x64, 0x78, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x41, 0x6e, 0x6e, 0x6f, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x04, 0x30, 0x28, 0x83, + 0x3a, 0x64, 0x78, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, + 0x6e, 0x74, 0x73, 0x53, 0x84, 0x34, 0x78, 0x83, 0x2e, 0x64, 0x78, 0x2e, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x53, 0x02, 0x3c, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, + 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, + 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, + 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, + 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, + 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, + 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, + 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, + 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, + 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, + 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, + 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, + 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, + 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, + 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, + 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, + 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, + 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, + 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, + 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, + 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, + 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, + 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, + 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, + 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, + 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x30, 0x83, 0x81, + 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, 0x1c, 0xc2, 0x61, 0x1d, + 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, + 0x4d, 0x00, 0x00, 0x00, 0x25, 0xd0, 0x04, 0x7e, 0xed, 0x70, 0xda, 0x0d, + 0x04, 0x66, 0x83, 0x58, 0xac, 0xb6, 0x00, 0xca, 0x20, 0xf0, 0x7b, 0xd7, + 0xe9, 0xc2, 0xba, 0xd9, 0x5c, 0x96, 0x03, 0x81, 0xb3, 0xaa, 0xf4, 0x2a, + 0xcc, 0xd3, 0xcb, 0x41, 0x32, 0x59, 0x5e, 0x9e, 0xcf, 0x85, 0x75, 0xb3, + 0xb9, 0x2c, 0x07, 0x02, 0x83, 0x15, 0xc0, 0x06, 0x81, 0x1f, 0x9d, 0x1d, + 0x9e, 0x03, 0x81, 0xb3, 0xaa, 0x34, 0x9c, 0xa7, 0xcb, 0xc3, 0xe3, 0xb4, + 0xfb, 0x1c, 0x1c, 0x8f, 0xcb, 0xec, 0xb2, 0x3c, 0x4c, 0x4f, 0xbf, 0xdd, + 0x53, 0xba, 0xbc, 0x3e, 0xa6, 0xd7, 0xe5, 0x65, 0x20, 0x30, 0x68, 0x0a, + 0x73, 0x30, 0x5c, 0xbe, 0xf3, 0xf8, 0x42, 0x44, 0x00, 0x13, 0x11, 0x02, + 0xcd, 0xb0, 0x10, 0x9f, 0x13, 0x95, 0x48, 0xe0, 0x4b, 0x53, 0x44, 0x09, + 0x93, 0xbf, 0xc2, 0x1b, 0x36, 0x11, 0xda, 0x30, 0x44, 0x84, 0x24, 0x6d, + 0x54, 0x51, 0x10, 0x91, 0x25, 0xfc, 0xc1, 0x70, 0xf9, 0xce, 0xe3, 0x0b, + 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0x7c, 0x4e, 0x54, 0x22, + 0x81, 0x2f, 0x4d, 0x11, 0x25, 0x4c, 0xfe, 0x0a, 0x60, 0x53, 0x04, 0x08, + 0x48, 0x63, 0x68, 0x82, 0x40, 0x2c, 0x44, 0x04, 0x4c, 0x88, 0xd3, 0xb0, + 0x53, 0x44, 0x09, 0x13, 0x15, 0x11, 0x36, 0x00, 0x06, 0xc3, 0xe5, 0x3b, + 0x8f, 0x3f, 0x20, 0xd2, 0x03, 0x4c, 0xc2, 0xb1, 0x02, 0x98, 0xd4, 0x21, + 0x0c, 0xd1, 0x48, 0x88, 0xd3, 0x48, 0x3e, 0x72, 0xdb, 0x46, 0xb0, 0x0d, + 0x97, 0xef, 0x3c, 0xfe, 0x80, 0x48, 0x0f, 0x30, 0x09, 0xc7, 0x0a, 0x60, + 0x92, 0xd8, 0x0c, 0xc4, 0xe5, 0x23, 0xb7, 0x6d, 0x05, 0xce, 0x70, 0xf9, + 0xce, 0xe3, 0x0f, 0xce, 0x74, 0xfb, 0xc5, 0x6d, 0xdb, 0x01, 0x36, 0x5c, + 0xbe, 0xf3, 0xf8, 0x11, 0x60, 0x6d, 0x54, 0x51, 0x10, 0x11, 0x3b, 0x39, + 0x11, 0xe1, 0x23, 0xb7, 0x6d, 0x08, 0x60, 0x30, 0x5c, 0xbe, 0xf3, 0xf8, + 0x53, 0x04, 0x08, 0xc4, 0x0a, 0x60, 0xbe, 0x34, 0x45, 0x94, 0x30, 0xf9, + 0x2b, 0x80, 0xa5, 0x00, 0xb6, 0x38, 0xc0, 0x60, 0x06, 0xcf, 0x70, 0xf9, + 0xce, 0xe3, 0x53, 0x0d, 0x10, 0x61, 0x7e, 0x71, 0xdb, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x84, 0x49, 0x03, 0xad, 0x36, 0xa1, 0xb0, 0x22, + 0x48, 0xe9, 0x9b, 0x09, 0xc0, 0x25, 0x58, 0xf0, 0x44, 0x58, 0x49, 0x4c, + 0x30, 0x08, 0x00, 0x00, 0x63, 0x00, 0x06, 0x00, 0x0c, 0x02, 0x00, 0x00, + 0x44, 0x58, 0x49, 0x4c, 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x18, 0x08, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, + 0x03, 0x02, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, + 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, + 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, + 0xc4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x62, 0x88, + 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, + 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x23, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, + 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x31, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, + 0x40, 0xda, 0x60, 0x08, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x12, 0x40, + 0x6d, 0x30, 0x86, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x36, + 0x10, 0x04, 0x04, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x86, + 0x09, 0x01, 0x01, 0x00, 0x89, 0x20, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x88, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x23, 0xa4, 0x84, + 0x04, 0x13, 0x23, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8c, 0x8c, + 0x0b, 0x84, 0xc4, 0x4c, 0x10, 0x88, 0xc1, 0x1c, 0x01, 0x18, 0x9c, 0x26, + 0x4d, 0x11, 0x25, 0x4c, 0xfe, 0x0a, 0x6f, 0xd8, 0x44, 0x68, 0xc3, 0x10, + 0x11, 0x92, 0xb4, 0x51, 0x45, 0x41, 0x44, 0x28, 0x00, 0x28, 0x38, 0x33, + 0x90, 0xa6, 0x88, 0x12, 0x26, 0x7f, 0x05, 0xb0, 0x29, 0x02, 0x04, 0xa4, + 0x31, 0x34, 0x41, 0x20, 0x16, 0x22, 0x02, 0x26, 0xc4, 0x69, 0xd8, 0x29, + 0xa2, 0x84, 0x89, 0x8a, 0x08, 0x14, 0x00, 0x34, 0x8c, 0x00, 0x94, 0xa0, + 0x20, 0x63, 0x8e, 0x00, 0x29, 0x03, 0x00, 0x20, 0x94, 0xcc, 0x00, 0x14, + 0x64, 0x01, 0x96, 0x65, 0x59, 0x96, 0x85, 0x98, 0x32, 0x2c, 0xc0, 0x42, + 0x0e, 0x21, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, + 0x0c, 0x0b, 0x81, 0x02, 0xa8, 0x2c, 0x05, 0x10, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x90, 0x34, 0x8c, 0x30, 0x2c, 0x17, 0x49, 0x53, 0x44, 0x09, + 0x93, 0xbf, 0x02, 0x58, 0x0a, 0x60, 0x8b, 0x03, 0x0c, 0x28, 0xa0, 0xa8, + 0x2a, 0x51, 0x01, 0x44, 0x00, 0x00, 0x00, 0xc0, 0xb2, 0x2c, 0xcb, 0xb2, + 0x2c, 0x8b, 0x45, 0x57, 0x19, 0x22, 0x60, 0xa0, 0xac, 0x0c, 0x11, 0x10, + 0xd0, 0x36, 0x10, 0x30, 0x47, 0x10, 0xcc, 0x11, 0x80, 0x02, 0x51, 0x53, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, + 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, + 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, + 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, + 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, + 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, + 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, + 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, + 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, + 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x3a, 0x0f, + 0x44, 0x90, 0x21, 0x23, 0x45, 0x44, 0x00, 0x36, 0x00, 0x60, 0x3e, 0x00, + 0xe0, 0x21, 0x8f, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x43, 0x9e, 0x04, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x86, 0x3c, 0x09, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x18, 0x20, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x91, 0x80, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc8, 0x73, 0x01, 0x01, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x90, 0x27, 0x03, + 0x02, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x21, 0xcf, + 0x06, 0x04, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, + 0x20, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, + 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x02, + 0x4a, 0xa0, 0x0c, 0x4a, 0xa2, 0x18, 0x46, 0x00, 0x0a, 0xa4, 0x10, 0xca, + 0xa2, 0x20, 0xca, 0xa1, 0x14, 0xc8, 0x1b, 0x01, 0xa0, 0xaf, 0x40, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, + 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, + 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, + 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, + 0x10, 0x4c, 0x10, 0x80, 0x65, 0x82, 0x00, 0x30, 0x1b, 0x84, 0x81, 0x98, + 0x20, 0x00, 0xcd, 0x06, 0x61, 0x30, 0x38, 0xb0, 0xa5, 0x89, 0x4d, 0x10, + 0x00, 0x67, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x01, 0x78, 0x26, 0x08, 0x44, + 0x40, 0x82, 0x8e, 0x2d, 0x6c, 0x6e, 0x82, 0x00, 0x40, 0x13, 0x04, 0x20, + 0xda, 0x20, 0x2c, 0xcf, 0x86, 0x64, 0x61, 0x9a, 0x65, 0x19, 0x9c, 0x05, + 0xda, 0x10, 0x44, 0x13, 0x04, 0x01, 0x60, 0xf2, 0x56, 0x47, 0x27, 0x54, + 0x67, 0x66, 0x56, 0x26, 0x37, 0x41, 0x00, 0xa4, 0x09, 0x82, 0x67, 0x6d, + 0x58, 0x96, 0x89, 0x5a, 0x96, 0xa1, 0xb2, 0x2c, 0x0b, 0xd8, 0x10, 0x5c, + 0x1b, 0x08, 0x09, 0x03, 0x80, 0x09, 0xc2, 0x21, 0x6c, 0x00, 0x36, 0x0c, + 0xc3, 0xb6, 0x6d, 0x08, 0xb8, 0x0d, 0xc3, 0xa0, 0x75, 0x04, 0x26, 0x08, + 0xdf, 0xb5, 0x41, 0x58, 0xc0, 0x60, 0x43, 0x01, 0x7c, 0x40, 0x16, 0x06, + 0x6c, 0x02, 0x7e, 0xda, 0xc2, 0xd2, 0xdc, 0x80, 0x80, 0xb2, 0x82, 0xb0, + 0xb0, 0xb4, 0x26, 0x08, 0xc0, 0x34, 0x41, 0x00, 0xa8, 0x09, 0x02, 0x50, + 0x6d, 0x08, 0x96, 0x0d, 0x04, 0x19, 0x94, 0x81, 0x19, 0x9c, 0xc1, 0x86, + 0x42, 0x1b, 0x03, 0x00, 0x40, 0x83, 0x2a, 0x6c, 0x6c, 0x76, 0x6d, 0x2e, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, 0x9e, 0x8b, + 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, 0x42, 0x86, + 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26, 0x37, 0x25, 0x30, 0xea, 0x90, + 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, 0x91, 0x95, + 0xb1, 0x4d, 0x09, 0x92, 0x32, 0x64, 0x78, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x53, 0x02, 0xac, 0x12, 0x19, 0x9e, 0x0b, + 0x5d, 0x1e, 0x5c, 0x59, 0x90, 0x9b, 0xdb, 0x1b, 0x5d, 0x18, 0x5d, 0xda, + 0x9b, 0xdb, 0xdc, 0x94, 0xa0, 0xab, 0x43, 0x86, 0xe7, 0x52, 0xe6, 0x46, + 0x27, 0x97, 0x07, 0xf5, 0x96, 0xe6, 0x46, 0x37, 0x37, 0x45, 0x08, 0x03, + 0x34, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, + 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, + 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, + 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, + 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, + 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, + 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, + 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, + 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, + 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, + 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, + 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, + 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, + 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, + 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, + 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, + 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, + 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, + 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, + 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, + 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, + 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, + 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, + 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, + 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, + 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, + 0xf0, 0x30, 0x83, 0x81, 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, + 0x1c, 0xc2, 0x61, 0x1d, 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, + 0x71, 0x20, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x25, 0xd0, 0x04, 0x7e, + 0xed, 0x70, 0xda, 0x0d, 0x04, 0x66, 0x83, 0x58, 0xac, 0xb6, 0x00, 0xca, + 0x20, 0xf0, 0x7b, 0xd7, 0xe9, 0xc2, 0xba, 0xd9, 0x5c, 0x96, 0x03, 0x81, + 0xb3, 0xaa, 0xf4, 0x2a, 0xcc, 0xd3, 0xcb, 0x41, 0x32, 0x59, 0x5e, 0x9e, + 0xcf, 0x85, 0x75, 0xb3, 0xb9, 0x2c, 0x07, 0x02, 0x83, 0x15, 0xc0, 0x06, + 0x81, 0x1f, 0x9d, 0x1d, 0x9e, 0x03, 0x81, 0xb3, 0xaa, 0x34, 0x9c, 0xa7, + 0xcb, 0xc3, 0xe3, 0xb4, 0xfb, 0x1c, 0x1c, 0x8f, 0xcb, 0xec, 0xb2, 0x3c, + 0x4c, 0x4f, 0xbf, 0xdd, 0x53, 0xba, 0xbc, 0x3e, 0xa6, 0xd7, 0xe5, 0x65, + 0x20, 0x30, 0x68, 0x0a, 0x73, 0x30, 0x5c, 0xbe, 0xf3, 0xf8, 0x42, 0x44, + 0x00, 0x13, 0x11, 0x02, 0xcd, 0xb0, 0x10, 0x9f, 0x13, 0x95, 0x48, 0xe0, + 0x4b, 0x53, 0x44, 0x09, 0x93, 0xbf, 0xc2, 0x1b, 0x36, 0x11, 0xda, 0x30, + 0x44, 0x84, 0x24, 0x6d, 0x54, 0x51, 0x10, 0x91, 0x25, 0xfc, 0xc1, 0x70, + 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, + 0x7c, 0x4e, 0x54, 0x22, 0x81, 0x2f, 0x4d, 0x11, 0x25, 0x4c, 0xfe, 0x0a, + 0x60, 0x53, 0x04, 0x08, 0x48, 0x63, 0x68, 0x82, 0x40, 0x2c, 0x44, 0x04, + 0x4c, 0x88, 0xd3, 0xb0, 0x53, 0x44, 0x09, 0x13, 0x15, 0x11, 0x36, 0x00, + 0x06, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x20, 0xd2, 0x03, 0x4c, 0xc2, 0xb1, + 0x02, 0x98, 0xd4, 0x21, 0x0c, 0xd1, 0x48, 0x88, 0xd3, 0x48, 0x3e, 0x72, + 0xdb, 0x46, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0x80, 0x48, 0x0f, 0x30, + 0x09, 0xc7, 0x0a, 0x60, 0x92, 0xd8, 0x0c, 0xc4, 0xe5, 0x23, 0xb7, 0x6d, + 0x05, 0xce, 0x70, 0xf9, 0xce, 0xe3, 0x0f, 0xce, 0x74, 0xfb, 0xc5, 0x6d, + 0xdb, 0x01, 0x36, 0x5c, 0xbe, 0xf3, 0xf8, 0x11, 0x60, 0x6d, 0x54, 0x51, + 0x10, 0x11, 0x3b, 0x39, 0x11, 0xe1, 0x23, 0xb7, 0x6d, 0x08, 0x60, 0x30, + 0x5c, 0xbe, 0xf3, 0xf8, 0x53, 0x04, 0x08, 0xc4, 0x0a, 0x60, 0xbe, 0x34, + 0x45, 0x94, 0x30, 0xf9, 0x2b, 0x80, 0xa5, 0x00, 0xb6, 0x38, 0xc0, 0x60, + 0x06, 0xcf, 0x70, 0xf9, 0xce, 0xe3, 0x53, 0x0d, 0x10, 0x61, 0x7e, 0x71, + 0xdb, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x13, 0x04, 0x43, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x94, 0xa8, 0x40, 0x91, 0x0a, 0x14, 0xb0, 0x40, 0xb9, 0x95, 0x4c, + 0xe9, 0x0a, 0x94, 0xff, 0x40, 0x61, 0x0a, 0xcc, 0x00, 0x14, 0x20, 0x20, + 0x20, 0xfe, 0x01, 0x21, 0x23, 0x00, 0x25, 0x50, 0x1e, 0xf4, 0x15, 0x41, + 0x09, 0x8c, 0x00, 0xd0, 0x32, 0x46, 0x00, 0x82, 0x20, 0x88, 0x7f, 0x23, + 0x00, 0x63, 0x04, 0x20, 0x08, 0x82, 0x24, 0x38, 0x8c, 0x11, 0xbc, 0x33, + 0x69, 0xa2, 0xdd, 0x18, 0x01, 0x08, 0x82, 0xf4, 0x29, 0x06, 0x44, 0x8d, + 0x00, 0xd0, 0x32, 0x46, 0x00, 0x82, 0x20, 0x88, 0xff, 0xc2, 0x18, 0x01, + 0x08, 0x82, 0x20, 0x08, 0x06, 0x63, 0x04, 0x20, 0x08, 0x82, 0xf0, 0x07, + 0x04, 0x07, 0xc3, 0x20, 0x39, 0x08, 0xc6, 0x4c, 0x44, 0x05, 0x2c, 0xa4, + 0x30, 0x62, 0x60, 0x00, 0x20, 0x08, 0x06, 0x09, 0x1c, 0x70, 0xd2, 0x88, + 0x81, 0x01, 0x80, 0x20, 0x18, 0x24, 0x71, 0xd0, 0x49, 0x23, 0x06, 0x06, + 0x00, 0x82, 0x60, 0x90, 0xcc, 0x41, 0x47, 0x8d, 0x18, 0x18, 0x00, 0x08, + 0x82, 0x41, 0x42, 0x07, 0x1e, 0x75, 0xc4, 0x52, 0x47, 0x2c, 0x65, 0x82, + 0x02, 0x1f, 0x13, 0x16, 0xf8, 0x9c, 0xb1, 0xd4, 0x19, 0x4b, 0x19, 0x21, + 0xd0, 0xc7, 0x08, 0x81, 0x3e, 0x26, 0x44, 0xf2, 0x31, 0x41, 0x92, 0x8f, + 0x09, 0x14, 0x7c, 0x4c, 0xa8, 0xe0, 0x33, 0x62, 0xb0, 0x00, 0x20, 0x08, + 0x06, 0xcc, 0x1f, 0xa4, 0x81, 0x10, 0x70, 0x42, 0xc0, 0x8d, 0x18, 0x18, + 0x00, 0x08, 0x82, 0x81, 0xf3, 0x07, 0x69, 0x10, 0x58, 0x40, 0xc8, 0xc7, + 0x08, 0x41, 0x3e, 0x23, 0x06, 0x06, 0x00, 0x82, 0x60, 0x90, 0xfd, 0x81, + 0x1b, 0x5c, 0xbb, 0x1a, 0x2c, 0x3d, 0xd0, 0x83, 0x61, 0x03, 0x22, 0xe8, + 0x08, 0x60, 0xc4, 0x80, 0x22, 0x40, 0x10, 0x0c, 0x2e, 0x51, 0x68, 0x03, + 0x61, 0x0f, 0xd8, 0x60, 0x0f, 0xf6, 0x60, 0x0f, 0xc2, 0x20, 0x0c, 0xc0, + 0xe0, 0x23, 0x86, 0xc2, 0xbb, 0x28, 0xa0, 0xc8, 0x70, 0xc3, 0x55, 0x8d, + 0xc1, 0x70, 0xc3, 0x55, 0x8d, 0x41, 0x09, 0xc1, 0xce, 0x32, 0x08, 0x41, + 0x50, 0x58, 0x26, 0x15, 0x6c, 0x50, 0xc1, 0x1f, 0xdc, 0x18, 0xc2, 0xa1, + 0x06, 0x63, 0x08, 0x08, 0x1b, 0x8c, 0x21, 0x24, 0x6e, 0x70, 0x03, 0xb0, + 0x37, 0x00, 0x7b, 0x03, 0xb0, 0x23, 0x06, 0x06, 0x00, 0x82, 0x60, 0xb0, + 0xb5, 0x42, 0x1f, 0x94, 0xc1, 0x88, 0x81, 0x03, 0x80, 0x20, 0x18, 0x48, + 0xb1, 0x90, 0x07, 0x01, 0x82, 0x07, 0xc4, 0x20, 0xdc, 0x01, 0x1d, 0x9c, + 0xc2, 0x2c, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const Uint8 s_ClosestHitShaderDxil[] = { + 0x44, 0x58, 0x42, 0x43, 0xe2, 0x63, 0x0f, 0x70, 0x86, 0x07, 0xe7, 0xc8, + 0xbc, 0xcb, 0x54, 0xe0, 0x73, 0x66, 0x13, 0x7b, 0x01, 0x00, 0x00, 0x00, + 0xe8, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, + 0xdc, 0x05, 0x00, 0x00, 0xf8, 0x05, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x45, 0x52, 0x53, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x14, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x32, 0x31, 0x64, 0x32, 0x38, 0x66, 0x37, 0x32, 0x00, 0x31, 0x2e, 0x39, + 0x2e, 0x32, 0x36, 0x30, 0x32, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x52, 0x44, 0x41, 0x54, 0x90, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x6d, + 0x61, 0x69, 0x6e, 0x40, 0x40, 0x59, 0x41, 0x58, 0x55, 0x52, 0x61, 0x79, + 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x40, 0x40, 0x55, 0x48, 0x69, + 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x40, + 0x40, 0x40, 0x5a, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x63, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x53, 0x54, 0x41, 0x54, + 0xc4, 0x04, 0x00, 0x00, 0x63, 0x00, 0x06, 0x00, 0x31, 0x01, 0x00, 0x00, + 0x44, 0x58, 0x49, 0x4c, 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xac, 0x04, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, + 0x28, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, + 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, + 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, + 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, + 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, + 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, + 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0x20, 0x00, 0x12, 0x60, 0xd9, 0x60, + 0x08, 0x02, 0xb0, 0x00, 0xd4, 0x06, 0x62, 0xf8, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x90, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x13, 0x86, 0x40, 0x18, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, + 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, + 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, + 0x33, 0x00, 0xc3, 0x08, 0x43, 0x70, 0x91, 0x34, 0x45, 0x94, 0x30, 0xf9, + 0x2b, 0x80, 0xa5, 0x00, 0xb6, 0x38, 0xc0, 0x80, 0x02, 0xa1, 0x19, 0x46, + 0x10, 0x82, 0xa3, 0xa4, 0x29, 0xa2, 0x84, 0xc9, 0x0f, 0x91, 0x49, 0x9b, + 0xa6, 0x08, 0x09, 0xa8, 0x89, 0x90, 0x50, 0x50, 0x64, 0x65, 0x00, 0x3a, + 0xc2, 0x81, 0x80, 0x39, 0x02, 0x30, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, + 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, + 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, + 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, + 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, + 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, + 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, + 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, + 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, + 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, + 0x40, 0x07, 0x43, 0x1e, 0x04, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb2, 0x40, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x32, 0x1e, 0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, + 0xc6, 0x04, 0x43, 0xda, 0x52, 0x28, 0x8a, 0x12, 0x28, 0x83, 0x11, 0x80, + 0x62, 0x28, 0x8c, 0x72, 0x28, 0x89, 0xd2, 0x28, 0x88, 0x22, 0x20, 0x9b, + 0x01, 0xa0, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x5d, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, + 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, + 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, + 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x96, + 0x61, 0x82, 0xb0, 0x10, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x2c, 0xc5, 0x06, + 0xc1, 0x30, 0x38, 0xb0, 0xa5, 0x89, 0x4d, 0x10, 0x16, 0x63, 0xc3, 0x80, + 0x24, 0xc4, 0x04, 0x61, 0x70, 0x26, 0x08, 0xcb, 0xc1, 0x62, 0xec, 0x8d, + 0xed, 0x4d, 0x6e, 0x82, 0xb0, 0x20, 0x13, 0x84, 0x25, 0x99, 0x20, 0x2c, + 0xca, 0x06, 0x24, 0x69, 0x08, 0xc3, 0x79, 0x20, 0x62, 0x83, 0xc0, 0x44, + 0x13, 0x04, 0xa3, 0x99, 0x20, 0x2c, 0x0b, 0x8d, 0x3a, 0xb7, 0xba, 0xb9, + 0x32, 0xb2, 0x09, 0xc2, 0xc2, 0x6c, 0x40, 0x92, 0x8a, 0x30, 0x9c, 0x07, + 0xb2, 0x36, 0x08, 0xd4, 0xb5, 0xa1, 0x30, 0x16, 0x69, 0xc2, 0x26, 0x08, + 0x09, 0xb0, 0x01, 0xd8, 0x30, 0x0c, 0xdb, 0xb6, 0x61, 0xb0, 0xb6, 0x6d, + 0xc3, 0x60, 0x6c, 0xdb, 0x86, 0x81, 0xeb, 0xbc, 0x0d, 0xc3, 0xa0, 0x7d, + 0x04, 0x36, 0x14, 0x40, 0x18, 0x00, 0x00, 0x40, 0x35, 0x08, 0xf8, 0x69, + 0x0b, 0x4b, 0x73, 0x03, 0x02, 0xca, 0x0a, 0xc2, 0xaa, 0x92, 0x0a, 0xcb, + 0x83, 0x0a, 0xcb, 0x63, 0x7b, 0x0b, 0x23, 0x03, 0x02, 0xaa, 0x42, 0x4a, + 0xa3, 0x0b, 0xa2, 0xa3, 0x93, 0x4b, 0x13, 0xab, 0xa3, 0x2b, 0x9b, 0x03, + 0x02, 0x02, 0xd2, 0x9a, 0x20, 0x2c, 0xc2, 0x04, 0x61, 0x09, 0x36, 0x04, + 0xc6, 0x06, 0x84, 0x22, 0x83, 0x84, 0x71, 0xa8, 0x32, 0x30, 0x83, 0x0d, + 0x85, 0x36, 0x06, 0x00, 0x70, 0x06, 0x2c, 0xd2, 0xdc, 0xe6, 0xe8, 0xe6, + 0x36, 0x08, 0x69, 0x40, 0x54, 0x61, 0x63, 0xb3, 0x6b, 0x73, 0x49, 0x23, + 0x2b, 0x73, 0xa3, 0x9b, 0x12, 0x04, 0x55, 0xc8, 0xf0, 0x5c, 0xec, 0xca, + 0xe4, 0xe6, 0xd2, 0xde, 0xdc, 0xa6, 0x04, 0x44, 0x13, 0x32, 0x3c, 0x17, + 0xbb, 0x30, 0x36, 0xbb, 0x32, 0xb9, 0x29, 0x81, 0x51, 0x87, 0x0c, 0xcf, + 0x65, 0x0e, 0x2d, 0x8c, 0xac, 0x4c, 0xae, 0xe9, 0x8d, 0xac, 0x8c, 0x6d, + 0x4a, 0x90, 0x54, 0x22, 0xc3, 0x73, 0xa1, 0xcb, 0x83, 0x2b, 0x0b, 0x72, + 0x73, 0x7b, 0xa3, 0x0b, 0xa3, 0x4b, 0x7b, 0x73, 0x9b, 0x9b, 0x22, 0x60, + 0x5f, 0x1d, 0x32, 0x3c, 0x97, 0x32, 0x37, 0x3a, 0xb9, 0x3c, 0xa8, 0xb7, + 0x34, 0x37, 0xba, 0xb9, 0x29, 0x42, 0x18, 0x9c, 0x41, 0x17, 0x32, 0x3c, + 0x97, 0xb1, 0xb7, 0x3a, 0x37, 0xba, 0x32, 0xb9, 0xb9, 0x29, 0x41, 0x1a, + 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, + 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, + 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, + 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, + 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, + 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, + 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, + 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, + 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, + 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, + 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, + 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, + 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, + 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, + 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, + 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, + 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, + 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, + 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, + 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, + 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, + 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, + 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, + 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, + 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, + 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x05, 0xa0, 0x06, 0x81, 0x5f, 0x3b, 0x9c, 0x76, 0x03, 0x81, 0xd9, 0x20, + 0xb6, 0x2a, 0x0d, 0xe7, 0xa1, 0xe1, 0x3c, 0xfb, 0x1d, 0x26, 0x03, 0x81, + 0x55, 0x64, 0x9a, 0x1e, 0xa4, 0xd3, 0xe5, 0x69, 0x71, 0x9d, 0x5e, 0x9e, + 0x03, 0x81, 0x40, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x61, 0xd0, 0x02, 0xc8, 0xf2, 0x7a, 0x7b, 0xb7, 0xe0, 0xb0, 0x51, 0xd6, + 0x21, 0x9d, 0x7e, 0x16, 0x44, 0x58, 0x49, 0x4c, 0xe8, 0x04, 0x00, 0x00, + 0x63, 0x00, 0x06, 0x00, 0x3a, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xd0, 0x04, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x1b, 0x8c, 0x20, 0x00, 0x12, 0x60, 0xd9, 0x60, 0x08, 0x02, 0xb0, 0x00, + 0xd4, 0x06, 0x62, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x90, 0x00, 0x00, + 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x86, 0x40, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, + 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, + 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x34, 0x23, 0x00, 0x33, 0x00, 0xc3, 0x08, + 0x43, 0x70, 0x91, 0x34, 0x45, 0x94, 0x30, 0xf9, 0x2b, 0x80, 0xa5, 0x00, + 0xb6, 0x38, 0xc0, 0x80, 0x02, 0xa1, 0x19, 0x46, 0x10, 0x82, 0xa3, 0xa4, + 0x29, 0xa2, 0x84, 0xc9, 0x0f, 0x91, 0x49, 0x9b, 0xa6, 0x08, 0x09, 0xa8, + 0x89, 0x90, 0x50, 0x50, 0x64, 0x65, 0x00, 0x3a, 0xc2, 0x81, 0x80, 0x39, + 0x02, 0x30, 0x20, 0x01, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, + 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, + 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, + 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, + 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, + 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, + 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, + 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, + 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, + 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, + 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x1e, + 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, + 0x40, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x10, + 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xda, + 0x52, 0x28, 0x8a, 0x12, 0x28, 0x83, 0x92, 0x28, 0x86, 0x11, 0x80, 0xc2, + 0x28, 0x87, 0x82, 0x28, 0x02, 0xb2, 0x19, 0x00, 0x9a, 0x19, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, + 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, + 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, + 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, + 0x10, 0x4c, 0x10, 0x96, 0x61, 0x82, 0xb0, 0x10, 0x1b, 0x84, 0x81, 0x98, + 0x20, 0x2c, 0xc5, 0x06, 0x61, 0x30, 0x38, 0xb0, 0xa5, 0x89, 0x4d, 0x10, + 0x16, 0x63, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x61, 0x39, 0x26, 0x08, 0x43, + 0x33, 0x41, 0x58, 0x10, 0x16, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x13, 0x84, + 0x25, 0xd9, 0x60, 0x24, 0x0e, 0xb1, 0x3c, 0xc6, 0x06, 0xa1, 0x81, 0x26, + 0x08, 0x06, 0x33, 0x41, 0x58, 0x14, 0x1a, 0x75, 0x6e, 0x75, 0x73, 0x65, + 0x64, 0x1b, 0x8c, 0x84, 0x22, 0x96, 0xc7, 0xd8, 0x20, 0x4c, 0xd5, 0x86, + 0x62, 0x61, 0x22, 0xc9, 0x9a, 0x20, 0x24, 0xc0, 0x06, 0x60, 0xc3, 0x30, + 0x64, 0xd9, 0x04, 0x61, 0x59, 0x36, 0x0c, 0x5b, 0x96, 0x6d, 0x18, 0x96, + 0x2c, 0xdb, 0x30, 0x68, 0x5c, 0xb7, 0x61, 0x18, 0x30, 0x8f, 0xc0, 0x86, + 0x02, 0x00, 0x03, 0x00, 0x00, 0xa8, 0x06, 0x01, 0x3f, 0x6d, 0x61, 0x69, + 0x6e, 0x40, 0x40, 0x59, 0x41, 0x58, 0x55, 0x52, 0x61, 0x79, 0x50, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x40, 0x40, 0x55, 0x48, 0x69, 0x74, 0x41, + 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x40, 0x40, 0x40, + 0x5a, 0x13, 0x84, 0x45, 0x98, 0x20, 0x2c, 0xc1, 0x86, 0x60, 0xd9, 0x80, + 0x4c, 0x63, 0x90, 0x34, 0xcf, 0x44, 0x06, 0x65, 0xb0, 0xa1, 0xc0, 0xc4, + 0x00, 0x00, 0xcc, 0xa0, 0x0a, 0x1b, 0x9b, 0x5d, 0x9b, 0x4b, 0x1a, 0x59, + 0x99, 0x1b, 0xdd, 0x94, 0x20, 0xa8, 0x42, 0x86, 0xe7, 0x62, 0x57, 0x26, + 0x37, 0x97, 0xf6, 0xe6, 0x36, 0x25, 0x20, 0x9a, 0x90, 0xe1, 0xb9, 0xd8, + 0x85, 0xb1, 0xd9, 0x95, 0xc9, 0x4d, 0x09, 0x8c, 0x3a, 0x64, 0x78, 0x2e, + 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, + 0x82, 0xa4, 0x12, 0x19, 0x9e, 0x0b, 0x5d, 0x1e, 0x5c, 0x59, 0x90, 0x9b, + 0xdb, 0x1b, 0x5d, 0x18, 0x5d, 0xda, 0x9b, 0xdb, 0xdc, 0x14, 0xc1, 0xf2, + 0xea, 0x90, 0xe1, 0xb9, 0x94, 0xb9, 0xd1, 0xc9, 0xe5, 0x41, 0xbd, 0xa5, + 0xb9, 0xd1, 0xcd, 0x4d, 0x11, 0xc0, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, + 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, + 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, + 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, + 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, + 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, + 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, + 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, + 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, + 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, + 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, + 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, + 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, + 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, + 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, + 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, + 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, + 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, + 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, + 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, + 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, + 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, + 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, + 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, + 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, + 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00, + 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0xa0, 0x06, 0x81, + 0x5f, 0x3b, 0x9c, 0x76, 0x03, 0x81, 0xd9, 0x20, 0xb6, 0x2a, 0x0d, 0xe7, + 0xa1, 0xe1, 0x3c, 0xfb, 0x1d, 0x26, 0x03, 0x81, 0x55, 0x64, 0x9a, 0x1e, + 0xa4, 0xd3, 0xe5, 0x69, 0x71, 0x9d, 0x5e, 0x9e, 0x03, 0x81, 0x40, 0x2d, + 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x24, 0x63, 0x0d, 0x00, 0x08, 0x82, 0x20, 0xfe, 0x01, 0x00, 0x00, 0x00, + 0x7b, 0x86, 0x41, 0x51, 0x86, 0x0d, 0x88, 0x40, 0x18, 0x00, 0x0c, 0x07, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf6, 0x40, 0x00, 0xd3, + 0x14, 0x99, 0xc3, 0xf1, 0x00, 0xd8, 0xe2, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const Uint8 s_MissShaderDxil[] = { + 0x44, 0x58, 0x42, 0x43, 0xb8, 0x8e, 0xad, 0xc7, 0x67, 0x2c, 0xbe, 0x74, + 0x0c, 0x8d, 0xff, 0x5a, 0x17, 0xce, 0x2f, 0xfa, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x64, 0x05, 0x00, 0x00, 0x80, 0x05, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x45, 0x52, 0x53, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x14, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x32, 0x31, 0x64, 0x32, 0x38, 0x66, 0x37, 0x32, 0x00, 0x31, 0x2e, 0x39, + 0x2e, 0x32, 0x36, 0x30, 0x32, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00, 0x00, + 0x52, 0x44, 0x41, 0x54, 0x80, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x6d, + 0x61, 0x69, 0x6e, 0x40, 0x40, 0x59, 0x41, 0x58, 0x55, 0x52, 0x61, 0x79, + 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x40, 0x40, 0x40, 0x5a, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x63, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x53, 0x54, 0x41, 0x54, 0x5c, 0x04, 0x00, 0x00, + 0x63, 0x00, 0x06, 0x00, 0x17, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x44, 0x04, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x1b, 0x8c, 0x20, 0x00, 0x12, 0x60, 0xd9, 0x40, 0x08, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x13, 0x84, 0x40, 0x00, 0x89, 0x20, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, + 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, + 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x24, 0x23, 0x00, + 0x33, 0x00, 0xc3, 0x08, 0x43, 0x70, 0x91, 0x34, 0x45, 0x94, 0x30, 0xf9, + 0x2b, 0x80, 0xa5, 0x00, 0xb6, 0x38, 0xc0, 0x80, 0x02, 0xa1, 0x29, 0x02, + 0x10, 0xd5, 0x40, 0xc0, 0x1c, 0x01, 0x18, 0x00, 0x13, 0x14, 0x72, 0xc0, + 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, + 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, + 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, + 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, + 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, + 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, + 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, + 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, + 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, + 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, + 0x40, 0x07, 0x43, 0x9e, 0x02, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb2, 0x40, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x32, 0x1e, 0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, + 0xc6, 0x04, 0x43, 0xc2, 0x52, 0x28, 0x81, 0x32, 0x18, 0x01, 0x28, 0x86, + 0xc2, 0x28, 0x87, 0x92, 0x28, 0x8d, 0x22, 0x28, 0x88, 0xb2, 0xa0, 0x99, + 0x01, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, + 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, + 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, + 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x10, 0x61, 0x82, 0x80, 0x0c, + 0x1b, 0x84, 0x81, 0x98, 0x20, 0x20, 0xc4, 0x06, 0xc1, 0x30, 0x38, 0xb0, + 0xa5, 0x89, 0x4d, 0x10, 0x90, 0x62, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x61, + 0x68, 0x26, 0x08, 0x88, 0xc1, 0x62, 0xec, 0x8d, 0xed, 0x4d, 0x6e, 0x82, + 0x80, 0x1c, 0x13, 0x04, 0x04, 0x99, 0x20, 0x20, 0xc9, 0x06, 0x24, 0x69, + 0x08, 0xc3, 0x79, 0x20, 0x62, 0x83, 0xc0, 0x44, 0x1b, 0x06, 0x63, 0x91, + 0x26, 0x08, 0x06, 0xb0, 0x01, 0xd8, 0x30, 0x0c, 0x55, 0x35, 0x41, 0x40, + 0x94, 0x0d, 0xc3, 0x55, 0x55, 0x1b, 0x04, 0x0b, 0xdb, 0x30, 0x0c, 0x54, + 0x46, 0x60, 0x43, 0x01, 0x6c, 0x00, 0x00, 0x50, 0x0b, 0xf8, 0x69, 0x0b, + 0x4b, 0x73, 0x03, 0x02, 0xca, 0x0a, 0xc2, 0xaa, 0x92, 0x0a, 0xcb, 0x83, + 0x0a, 0xcb, 0x63, 0x7b, 0x0b, 0x23, 0x03, 0x02, 0x02, 0xd2, 0x9a, 0x20, + 0x20, 0xcb, 0x04, 0x01, 0x61, 0x26, 0x08, 0x48, 0xb0, 0x21, 0x30, 0x36, + 0x18, 0xde, 0x97, 0x30, 0x60, 0x10, 0x06, 0x1b, 0x0a, 0xaa, 0x03, 0x00, + 0x31, 0x60, 0x91, 0xe6, 0x36, 0x47, 0x37, 0xb7, 0x41, 0x20, 0x03, 0xa2, + 0x0a, 0x1b, 0x9b, 0x5d, 0x9b, 0x4b, 0x1a, 0x59, 0x99, 0x1b, 0xdd, 0x94, + 0x20, 0xa8, 0x42, 0x86, 0xe7, 0x62, 0x57, 0x26, 0x37, 0x97, 0xf6, 0xe6, + 0x36, 0x25, 0x20, 0x9a, 0x90, 0xe1, 0xb9, 0xd8, 0x85, 0xb1, 0xd9, 0x95, + 0xc9, 0x4d, 0x09, 0x8c, 0x3a, 0x64, 0x78, 0x2e, 0x73, 0x68, 0x61, 0x64, + 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x82, 0xa4, 0x12, 0x19, + 0x9e, 0x0b, 0x5d, 0x1e, 0x5c, 0x59, 0x90, 0x9b, 0xdb, 0x1b, 0x5d, 0x18, + 0x5d, 0xda, 0x9b, 0xdb, 0xdc, 0x14, 0x41, 0xca, 0xea, 0x90, 0xe1, 0xb9, + 0x94, 0xb9, 0xd1, 0xc9, 0xe5, 0x41, 0xbd, 0xa5, 0xb9, 0xd1, 0xcd, 0x4d, + 0x11, 0x36, 0x31, 0xe8, 0x42, 0x86, 0xe7, 0x32, 0xf6, 0x56, 0xe7, 0x46, + 0x57, 0x26, 0x37, 0x37, 0x25, 0x20, 0x03, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, + 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, + 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, + 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, + 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, + 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, + 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, + 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, + 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, + 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, + 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, + 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, + 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, + 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, + 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, + 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, + 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, + 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, + 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, + 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, + 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, + 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, + 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, + 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, + 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, + 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x05, 0xa0, 0x05, 0x7e, 0xed, 0x70, 0xda, 0x0d, + 0x04, 0x66, 0x83, 0xd8, 0xaa, 0x34, 0x9c, 0x87, 0x86, 0xf3, 0xec, 0x77, + 0x98, 0x0c, 0x04, 0x02, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x98, 0x7d, 0xbf, 0x81, 0x6e, 0xe5, 0x34, 0x58, 0x9f, 0x60, 0x8b, 0xd9, + 0x81, 0xf5, 0xe6, 0xff, 0x44, 0x58, 0x49, 0x4c, 0x78, 0x04, 0x00, 0x00, + 0x63, 0x00, 0x06, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, + 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, + 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, + 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, + 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, + 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, + 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, + 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, + 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x1b, 0x8c, 0x20, 0x00, 0x12, 0x60, 0xd9, 0x40, 0x08, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x13, 0x84, 0x40, 0x00, 0x89, 0x20, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, + 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, + 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x28, 0x23, 0x00, + 0x33, 0x00, 0xc3, 0x08, 0x43, 0x70, 0x91, 0x34, 0x45, 0x94, 0x30, 0xf9, + 0x2b, 0x80, 0xa5, 0x00, 0xb6, 0x38, 0xc0, 0x80, 0x02, 0xa1, 0x29, 0x02, + 0x10, 0xd5, 0x40, 0xc0, 0x1c, 0x01, 0x18, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, + 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, + 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, + 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, + 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, + 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, + 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, + 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, + 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x02, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x40, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, + 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xc2, 0x52, 0x28, 0x81, 0x32, + 0x28, 0x89, 0x62, 0x18, 0x01, 0x28, 0x8c, 0x72, 0x28, 0x82, 0x82, 0x28, + 0x0b, 0x9a, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, + 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, + 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, + 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x10, + 0x61, 0x82, 0x80, 0x0c, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x20, 0xc4, 0x06, + 0x61, 0x30, 0x38, 0xb0, 0xa5, 0x89, 0x4d, 0x10, 0x90, 0x62, 0xc3, 0x80, + 0x24, 0xc4, 0x04, 0x01, 0x31, 0x26, 0x08, 0x03, 0x33, 0x41, 0x40, 0x0e, + 0x16, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x13, 0x04, 0x04, 0xd9, 0x60, 0x24, + 0x0e, 0xb1, 0x3c, 0xc6, 0x06, 0xa1, 0x81, 0x36, 0x0c, 0x0b, 0x13, 0x4d, + 0x10, 0x0c, 0x60, 0x03, 0xb0, 0x61, 0x18, 0x28, 0x6a, 0x82, 0x80, 0x24, + 0x1b, 0x06, 0x8b, 0xa2, 0x36, 0x08, 0xd5, 0xb5, 0x61, 0x18, 0x26, 0x8c, + 0xc0, 0x86, 0x02, 0xd0, 0x00, 0x00, 0xa0, 0x16, 0xf0, 0xd3, 0x16, 0x96, + 0xe6, 0x06, 0x04, 0x94, 0x15, 0x84, 0x55, 0x25, 0x15, 0x96, 0x07, 0x15, + 0x96, 0xc7, 0xf6, 0x16, 0x46, 0x06, 0x04, 0x04, 0xa4, 0x35, 0x41, 0x40, + 0x94, 0x09, 0x02, 0xb2, 0x4c, 0x10, 0x90, 0x60, 0x43, 0xb0, 0x6c, 0x30, + 0x3a, 0x2f, 0x69, 0x3e, 0x30, 0xd8, 0x50, 0x4c, 0x1c, 0x00, 0x84, 0x41, + 0x15, 0x36, 0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37, 0xba, 0x29, + 0x41, 0x50, 0x85, 0x0c, 0xcf, 0xc5, 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, + 0x6d, 0x4a, 0x40, 0x34, 0x21, 0xc3, 0x73, 0xb1, 0x0b, 0x63, 0xb3, 0x2b, + 0x93, 0x9b, 0x12, 0x18, 0x75, 0xc8, 0xf0, 0x5c, 0xe6, 0xd0, 0xc2, 0xc8, + 0xca, 0xe4, 0x9a, 0xde, 0xc8, 0xca, 0xd8, 0xa6, 0x04, 0x49, 0x25, 0x32, + 0x3c, 0x17, 0xba, 0x3c, 0xb8, 0xb2, 0x20, 0x37, 0xb7, 0x37, 0xba, 0x30, + 0xba, 0xb4, 0x37, 0xb7, 0xb9, 0x29, 0x42, 0x84, 0xd5, 0x21, 0xc3, 0x73, + 0x29, 0x73, 0xa3, 0x93, 0xcb, 0x83, 0x7a, 0x4b, 0x73, 0xa3, 0x9b, 0x9b, + 0x22, 0x68, 0x61, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, + 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, + 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, + 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, + 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, + 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, + 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, + 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, + 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, + 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, + 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, + 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, + 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, + 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, + 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, + 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, + 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, + 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, + 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, + 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, + 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, + 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, + 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, + 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, + 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, + 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x05, 0xa0, 0x05, 0x7e, 0xed, 0x70, 0xda, 0x0d, 0x04, 0x66, 0x83, 0xd8, + 0xaa, 0x34, 0x9c, 0x87, 0x86, 0xf3, 0xec, 0x77, 0x98, 0x0c, 0x04, 0x02, + 0xb5, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x24, 0x23, 0x00, 0x00, 0x7b, 0x06, 0x21, 0x49, 0x86, 0x0d, 0x88, 0x40, + 0x18, 0x00, 0x0c, 0x07, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xd6, 0x70, 0x3c, 0x00, 0xb6, 0x38, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + // ================================================== // Triangle // ================================================== @@ -920,7 +1805,7 @@ static const Uint32 s_TriangleFragShaderSpv[] = { 0x00010038 }; -static const Uint32 s_TriangleVertShaderDxil[] = { +static const Uint8 s_TriangleVertShaderDxil[] = { 0x44, 0x58, 0x42, 0x43, 0x43, 0xaa, 0x4b, 0xdf, 0x49, 0x8b, 0x4b, 0xbe, 0xc3, 0x3a, 0x72, 0x00, 0x02, 0xed, 0x6c, 0x73, 0x01, 0x00, 0x00, 0x00, 0x38, 0x0c, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, @@ -1184,7 +2069,7 @@ static const Uint32 s_TriangleVertShaderDxil[] = { 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static const Uint32 s_TriangleFragShaderDxil[] = { +static const Uint8 s_TriangleFragShaderDxil[] = { 0x44, 0x58, 0x42, 0x43, 0x7e, 0x0a, 0x30, 0x58, 0x0c, 0x74, 0x45, 0xb2, 0x7d, 0x54, 0xd2, 0x32, 0xbe, 0xaa, 0xdb, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x84, 0x0b, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 9806bf6d..74111fd8 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -859,12 +859,14 @@ bool textureTest() if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { vertBytecodeSize = sizeof(s_TextureVertShaderSpv); fragBytecodeSize = sizeof(s_TextureFragShaderSpv); + vertBytecode = (void*)s_TextureVertShaderSpv; fragBytecode = (void*)s_TextureFragShaderSpv; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { vertBytecodeSize = sizeof(s_TextureVertShaderDxil); fragBytecodeSize = sizeof(s_TextureFragShaderDxil); + vertBytecode = (void*)s_TextureVertShaderDxil; fragBytecode = (void*)s_TextureFragShaderDxil; } diff --git a/tests/tests_main.c b/tests/tests_main.c index 8307a47c..f62e99aa 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,14 +59,14 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: add dxil shaders + // registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); - // registerTest(textureTest, "Texture Test"); + registerTest(textureTest, "Texture Test"); #endif // runTests(); From 4006f76051450059e5e863046d72c4c7e2698b3c Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 2 May 2026 05:52:35 +0000 Subject: [PATCH 195/372] start descriptor indexing test --- src/graphics/pal_d3d12.c | 4 +- src/graphics/pal_vulkan.c | 92 +- tests/graphics/descriptor_indexing_test.c | 1514 +++++++++++++++++++++ tests/graphics/triangle_test.c | 3 +- tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 3 +- 7 files changed, 1573 insertions(+), 47 deletions(-) create mode 100644 tests/graphics/descriptor_indexing_test.c diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index b66f61f6..5a61ecd4 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -6725,9 +6725,9 @@ PalResult PAL_CALL updateDescriptorSetD3D12( index = set->resourceOffset + bindingOffset + info->arrayElement; } - for (int y = 0; y < binding->range.NumDescriptors; y++) { + for (int j = 0; j < binding->range.NumDescriptors; j++) { D3D12_CPU_DESCRIPTOR_HANDLE dst; - dst.ptr = getDescriptorHandleD3D12(index + y, heap->incrementSize, heap->cpuBase); + dst.ptr = getDescriptorHandleD3D12(index + j, heap->incrementSize, heap->cpuBase); if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { Sampler* sampler = (Sampler*)info->samplerInfo->sampler; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 0aba7826..f6404664 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -8316,23 +8316,29 @@ PalResult PAL_CALL updateDescriptorSetVk( VkDescriptorImageInfo* imageInfos = nullptr; VkWriteDescriptorSetAccelerationStructureKHR* tlasInfos = nullptr; + // TODO: loop over descriptor count Uint32 bufferCount = 0; - Uint32 imageCount = 0; - Uint32 tlasCount = 0; Uint32 bufferIndex = 0; + Uint32 bufferOffset = 0; + + Uint32 imageCount = 0; Uint32 imageIndex = 0; + Uint32 imageOffset = 0; + + Uint32 tlasCount = 0; Uint32 tlasIndex = 0; + Uint32 tlasOffset = 0; for (int i = 0; i < count; i++) { if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - bufferCount++; + bufferCount += infos[i].descriptorCount; } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - tlasCount++; + tlasCount += infos[i].descriptorCount; } else { - imageCount++; + imageCount += infos[i].descriptorCount; } } @@ -8372,50 +8378,52 @@ PalResult PAL_CALL updateDescriptorSetVk( DescriptorSet* set = (DescriptorSet*)infos[i].descriptorSet; write->dstSet = set->handle; + for (int j = 0; j < write->descriptorCount; j++) { + if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || + infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + VkDescriptorBufferInfo* bufferInfo = &bufferInfos[bufferIndex++]; + Buffer* vkBuffer = (Buffer*)infos[j].bufferInfo->buffer; + + bufferInfo->buffer = vkBuffer->handle; + bufferInfo->offset = infos[i].bufferInfo->offset; + bufferInfo->range = infos[i].bufferInfo->size; + write->pBufferInfo = bufferInfo; + + } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + VkWriteDescriptorSetAccelerationStructureKHR* tlasInfo = &tlasInfos[tlasIndex++]; + AccelerationStructure* ac = (AccelerationStructure*)infos[i].tlasInfo->tlas; + + tlasInfo->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; + tlasInfo->accelerationStructureCount = 1; + tlasInfo->pAccelerationStructures = &ac->handle; + tlasInfo->pNext = nullptr; + write->pNext = tlasInfo; - if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || - infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - VkDescriptorBufferInfo* bufferInfo = &bufferInfos[bufferIndex++]; - Buffer* vkBuffer = (Buffer*)infos[i].bufferInfo->buffer; - bufferInfo->buffer = vkBuffer->handle; - bufferInfo->offset = infos[i].bufferInfo->offset; - bufferInfo->range = infos[i].bufferInfo->size; - write->pBufferInfo = bufferInfo; - - } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - VkWriteDescriptorSetAccelerationStructureKHR* tlasInfo = &tlasInfos[tlasIndex++]; - AccelerationStructure* ac = (AccelerationStructure*)infos[i].tlasInfo->tlas; - - tlasInfo->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; - tlasInfo->accelerationStructureCount = 1; - tlasInfo->pAccelerationStructures = &ac->handle; - tlasInfo->pNext = nullptr; - write->pNext = tlasInfo; - - } else { - VkDescriptorImageInfo* imageInfo = &imageInfos[imageIndex++]; - if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { - Sampler* vkSampler = (Sampler*)infos[i].samplerInfo->sampler; + } else { + VkDescriptorImageInfo* imageInfo = &imageInfos[imageIndex++]; + if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { + Sampler* vkSampler = (Sampler*)infos[i].samplerInfo->sampler; - imageInfo->sampler = vkSampler->handle; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo->imageView = nullptr; + imageInfo->sampler = vkSampler->handle; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo->imageView = nullptr; - } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; + } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { + ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; - imageInfo->sampler = nullptr; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo->imageView = vkImageView->handle; + imageInfo->sampler = nullptr; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageInfo->imageView = vkImageView->handle; - } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; + } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; - imageInfo->sampler = nullptr; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo->imageView = vkImageView->handle; + imageInfo->sampler = nullptr; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageInfo->imageView = vkImageView->handle; + } + write->pImageInfo = imageInfo; } - write->pImageInfo = imageInfo; } } diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c new file mode 100644 index 00000000..3f425122 --- /dev/null +++ b/tests/graphics/descriptor_indexing_test.c @@ -0,0 +1,1514 @@ + +#include "pal/pal_graphics.h" +#include "pal/pal_video.h" +#include "pal/pal_system.h" +#include "tests.h" +#include "shaders.h" + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +#define MAX_FRAMES_IN_FLIGHT 2 +#define TEXTURE_WIDTH 128 +#define TEXTURE_HEIGHT 128 +#define CHECKER_SIZE 16 + +static Uint32 align(Uint32 value, Uint32 alignment) +{ + return (value + alignment - 1) & ~(alignment - 1); +} + +static void createCheckerboardTexture( + Uint32* texture, + Uint32 width, + Uint32 height, + Uint32 checkerSize) +{ + Uint8* pixels = (Uint8*)texture; + for (Int32 y = 0; y < height; ++y) { + for (Int32 x = 0; x < width; ++x) { + Int32 i = (y * width + x) * 4; + int checker = ((x / checkerSize) ^ (y / checkerSize)) & 1; + if (checker) { + pixels[i + 0] = 255; // Red bit + pixels[i + 1] = 0; // Green bit + pixels[i + 2] = 0; // Blue bit + pixels[i + 3] = 255; // Alpha bit + + } else { + pixels[i + 0] = 0; // Red bit + pixels[i + 1] = 255; // Green bit + pixels[i + 2] = 0; // Blue bit + pixels[i + 3] = 255; // Alpha bit + } + } + } +} + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) +{ + palLog(nullptr, msg); +} + +bool descriptorIndexingTest() +{ + PalResult result; + PalWindow* window = nullptr; + PalEventDriver* eventDriver = nullptr; + PalGraphicsWindow gfxWindow; + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalSurface* surface = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + + PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalFence** inFlightImages; // count of swapchain images + + PalPipelineLayout* pipelineLayout = nullptr; + PalPipeline* pipeline = nullptr; + PalShader* vertexShader = nullptr; + PalShader* fragmentShader = nullptr; + + PalBuffer* vertexBuffer = nullptr; + PalBuffer* indexBuffer = nullptr; + PalBuffer* stagingBuffer = nullptr; + PalMemory* vertexBufferMemory = nullptr; + PalMemory* indexBufferMemory = nullptr; + PalMemory* stagingBufferMemory = nullptr; + + PalDescriptorSetLayout* descriptorSetLayout = nullptr; + PalDescriptorPool* descriptorPool = nullptr; + PalDescriptorSet* descriptorSet = nullptr; + + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create event driver: %s", error); + return false; + } + + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + + result = palInitVideo(nullptr, eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize video: %s", error); + return false; + } + + PalWindowCreateInfo windowCreateInfo = {0}; + windowCreateInfo.height = WINDOW_HEIGHT; + windowCreateInfo.width = WINDOW_WIDTH; + windowCreateInfo.show = true; + windowCreateInfo.title = "Triangle Window"; + + PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); + if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&windowCreateInfo, &window); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create window: %s", error); + return false; + } + + PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); + gfxWindow.display = winHandle.nativeDisplay; + gfxWindow.window = winHandle.nativeWindow; + + // using pal_system.h will be easy to know the underlying windowing API + // or use typedefs. We will use the pal_system module. This is needed + // for systems which multiple windowing APIs (linux). + PalPlatformInfo platformInfo = {0}; + result = palGetPlatformInfo(&platformInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get platform information: %s", error); + return false; + } + + if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + + } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + + } else { + // automatically this is xcb + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } + + PalGraphicsDebugger debugger = {0}; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; + + result = palInitGraphics(&debugger, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (adapterCount == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", adapterCount); + + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&adapterCount, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + PalAdapterCapabilities caps = {0}; + PalAdapterInfo adapterInfo = {0}; + PalAdapterFeatures adapterFeatures = 0; + bool hasGraphicsQueue = false; + bool hasDescriptorIndexing = false; + for (Int32 i = 0; i < adapterCount; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (caps.maxGraphicsQueues == 0) { + hasGraphicsQueue = false; + continue; + + } else { + hasGraphicsQueue = true; + adapterFeatures = palGetAdapterFeatures(adapter); + if (adapterFeatures & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + hasDescriptorIndexing = true; + } else { + hasDescriptorIndexing = false; + } + } + + if (hasDescriptorIndexing) { + // We want an adapter that supports spirv 1.0 or dxil 6.0 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + break; + } + } + } + adapter = nullptr; + } + + palFree(nullptr, adapters); + if (!adapter) { + if (!hasGraphicsQueue) { + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); + + } else if (!hasDescriptorIndexing) { + palLog(nullptr, "Failed to find an adapter that supports descriptor indexing"); + + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } + return false; + } + + // create a device + PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + features |= PAL_ADAPTER_FEATURE_FENCE_RESET; + } + + result = palCreateDevice(adapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create surface + result = palCreateSurface(device, &gfxWindow, &surface); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create surface: %s", error); + return false; + } + + // create a graphics command queue and check if its supports presenting to the surface + bool foundQueue = false; + for (int i = 0; i < caps.maxGraphicsQueues; i++) { + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palDestroyQueue(queue); + queue = nullptr; + } else { + // found a queue + foundQueue = true; + break; + } + } + + if (!foundQueue) { + palLog(nullptr, "Failed to find a queue that can present to the surface"); + return false; + } + + // create a swapchain with the graphics queue + PalSurfaceCapabilities surfaceCaps = {0}; + result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get surface capabilities: %s", error); + return false; + } + + PalSwapchainCreateInfo swapchainCreateInfo = {0}; + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; + swapchainCreateInfo.height = WINDOW_HEIGHT; + swapchainCreateInfo.width = WINDOW_WIDTH; + swapchainCreateInfo.imageArrayLayerCount = 1; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR; + + // rare but possible on andriod + if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { + swapchainCreateInfo.width = surfaceCaps.maxImageWidth / 2; + } + + if (WINDOW_HEIGHT > surfaceCaps.maxImageHeight) { + swapchainCreateInfo.height = surfaceCaps.maxImageHeight / 2; + } + + // check if the minimal image count is not good for you + // and increase it but not pass the max count + swapchainCreateInfo.imageCount = surfaceCaps.minImageCount; + if (swapchainCreateInfo.imageCount == 1) { + swapchainCreateInfo.imageCount++; + if (surfaceCaps.maxImageCount < 2) { + palLog(nullptr, "Surface does not support double buffers"); + return false; + } + } + + result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create swapchain: %s", error); + return false; + } + + // get all swapchain images and create image views for them + Uint32 imageCount = swapchainCreateInfo.imageCount; + imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); + inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); + if (!imageViews || !inFlightImages) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + PalImageInfo imageInfo; + result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } + + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.subresourceRange.layerArrayCount = 1; + imageViewCreateInfo.subresourceRange.mipLevelCount = 1; + imageViewCreateInfo.subresourceRange.startArrayLayer = 0; + imageViewCreateInfo.subresourceRange.startMipLevel = 0; + imageViewCreateInfo.format = imageInfo.format; + + for (int i = 0; i < imageCount; i++) { + // get swapchain image + // this is fast since the images are cache by PAL + PalImage* image = palGetSwapchainImage(swapchain, i); + if (!image) { + palLog(nullptr, "Failed to get swapchain image"); + } + + result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + + inFlightImages[i] = nullptr; + } + + result = palCreateCommandPool(device, queue, &cmdPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + // create synchronization objects and command buffers + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateFence(device, true, &inFlightFences[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + result = palAllocateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffers[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate command buffer: %s", error); + return false; + } + } + + // create vertex and staging buffer + // clang-format off + // vertices format[x, y, u, v, index] + float vertices[] = { + // Quad 1 + -0.9f, 0.9f, 0.0f, 0.0f, 0.0f, + -0.9f, 0.1f, 0.0f, 1.0f, 0.0f, + -0.3f, 0.1f, 1.0f, 1.0f, 0.0f, + -0.3f, 0.9f, 1.0f, 0.0f, 0.0f, + + // Quad 2 + -0.2f, 0.9f, 0.0f, 0.0f, 1.0f, + -0.2f, 0.1f, 0.0f, 1.0f, 1.0f, + 0.4f, 0.1f, 1.0f, 1.0f, 1.0f, + 0.4f, 0.9f, 1.0f, 0.0f, 1.0f, + + // Quad 3 + 0.5f, 0.9f, 0.0f, 0.0f, 2.0f, + 0.5f, 0.1f, 0.0f, 1.0f, 2.0f, + 1.1f, 0.1f, 1.0f, 1.0f, 2.0f, + 1.1f, 0.9f, 1.0f, 0.0f, 2.0f + }; + + Uint32 indices[] = { + // Quad 1 + 0, 1, 2, + 0, 2, 3, + + // Quad 2 + 4, 5, 6, + 4, 6, 7, + + // Quad 3 + 8, 9, 10, + 8, 10, 11 + }; + // clang-format on + + // we will use one staging buffer for both vertices and indices thus we need to align + // the data. We use 256 as a safe default + Uint32 verticesSize = sizeof(vertices); + Uint32 indicesSize = sizeof(indices); + Uint32 indicesOffset = align(verticesSize, 256); + Uint32 stagingBufferSize = indicesOffset + indicesSize; + + // create vertex buffer + PalBufferCreateInfo bufferCreateInfo = {0}; + bufferCreateInfo.size = verticesSize; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create vertex buffer: %s", error); + return false; + } + + // create index buffer + bufferCreateInfo.size = indicesSize; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_INDEX; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + result = palCreateBuffer(device, &bufferCreateInfo, &indexBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create index buffer: %s", error); + return false; + } + + // create staging buffer + bufferCreateInfo.size = stagingBufferSize; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send + result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create staging buffer: %s", error); + return false; + } + + // get buffer memory requirement and allocate memory + PalMemoryRequirements vertexBufferMemReq = {0}; + PalMemoryRequirements indexBufferMemReq = {0}; + PalMemoryRequirements stagingBufferMemReq = {0}; + + result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get vertex buffer memory requirement: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(indexBuffer, &indexBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get index buffer memory requirement: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get staging buffer memory requirement: %s", error); + return false; + } + + // we need to check if the memory type we want are supported + // but almost every GPU supports a GPU only memory + // and CPU writable memory + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + vertexBufferMemReq.memoryMask, + vertexBufferMemReq.size, + &vertexBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for vertetx buffer: %s", error); + return false; + } + + // allocate memory for index buffer + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + indexBufferMemReq.memoryMask, + indexBufferMemReq.size, + &indexBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for index buffer: %s", error); + return false; + } + + // allocate memory for staging buffer + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + stagingBufferMemReq.memoryMask, + stagingBufferMemReq.size, + &stagingBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for staging buffer: %s", error); + return false; + } + + // bind memory for vertex buffer + result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory for vertex buffer: %s", error); + return false; + } + + // bind memory for index buffer + result = palBindBufferMemory(indexBuffer, indexBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory for index buffer: %s", error); + return false; + } + + // bind memory for index buffer + result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory for staging buffer: %s", error); + return false; + } + + // map the staging buffer and upload the vertices and indices + void* ptr = nullptr; + result = palMapBufferMemory(stagingBuffer, 0, stagingBufferSize, &ptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map buffer memory: %s", error); + return false; + } + + memcpy(ptr, vertices, verticesSize); // copy vertices + memcpy(ptr + indicesOffset, indices, indicesSize); // copy indices + palUnmapBufferMemory(stagingBuffer); + + PalFence* fence = nullptr; + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + // we dont want to load the texture from disk so we will create a + // checkerboard texture and use that rather + Uint32 texture[TEXTURE_WIDTH * TEXTURE_HEIGHT]; + memset(texture, 0, TEXTURE_WIDTH * TEXTURE_HEIGHT); + createCheckerboardTexture(texture, TEXTURE_WIDTH, TEXTURE_HEIGHT, CHECKER_SIZE); + + // create image for the texture + PalImage* checkerboard = nullptr; + PalImageCreateInfo imageCreateInfo = {0}; + imageCreateInfo.depthOrArraySize = 1; + imageCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; + imageCreateInfo.mipLevelCount = 1; // simple + imageCreateInfo.sampleCount = PAL_SAMPLE_COUNT_1; // simple + imageCreateInfo.type = PAL_IMAGE_TYPE_2D; + imageCreateInfo.usages = PAL_IMAGE_USAGE_TRANSFER_DST | PAL_IMAGE_USAGE_SAMPLED; + imageCreateInfo.width = TEXTURE_WIDTH; + imageCreateInfo.height = TEXTURE_HEIGHT; + + result = palCreateImage(device, &imageCreateInfo, &checkerboard); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image: %s", error); + return false; + } + + // allocate memory for the image + PalMemoryRequirements imageMemReq = {0}; + result = palGetImageMemoryRequirements(checkerboard, &imageMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image memory requirement: %s", error); + return false; + } + + PalMemory* checkerboardMemory = nullptr; + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + imageMemReq.memoryMask, + imageMemReq.size, + &checkerboardMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory: %s", error); + return false; + } + + result = palBindImageMemory(checkerboard, checkerboardMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind image memory: %s", error); + return false; + } + + // create staging buffer to transfer the data to the image + PalBufferImageCopyInfo bufferImageCopyInfo = {0}; + bufferImageCopyInfo.ImageArrayLayerCount = 1; + bufferImageCopyInfo.imageWidth = TEXTURE_WIDTH; + bufferImageCopyInfo.imageHeight = TEXTURE_HEIGHT; + bufferImageCopyInfo.imageDepth = 1; // 2D image + + Uint64 imageCopyStagingBufferSize = 0; + Uint32 bufferRowLength = 0; + Uint32 bufferImageHeight = 0; + + result = palComputeImageCopyStagingBufferRequirements( + device, + imageCreateInfo.format, + &bufferImageCopyInfo, + &bufferRowLength, + &bufferImageHeight, + &imageCopyStagingBufferSize); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to compute image copy staging buffer info: %s", error); + return false; + } + + // update our copy with the required buffer row length and buffer image height + bufferImageCopyInfo.bufferRowLength = bufferRowLength; + bufferImageCopyInfo.bufferImageHeight = bufferImageHeight; + + // create staging buffer to transfer the data to the image + PalBuffer* imageStagingBuffer = nullptr; + PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; + imageStagingBufferCreateInfo.size = imageCopyStagingBufferSize; + imageStagingBufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; + + result = palCreateBuffer(device, &imageStagingBufferCreateInfo, &imageStagingBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image staging buffer: %s", error); + return false; + } + + PalMemoryRequirements imageStagingBufferMemReq = {0}; + result = palGetBufferMemoryRequirements(imageStagingBuffer, &imageStagingBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image staging buffer memory requirement: %s", error); + return false; + } + + PalMemory* imageStagingBufferMemory = nullptr; + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + imageStagingBufferMemReq.memoryMask, + imageStagingBufferMemReq.size, + &imageStagingBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory: %s", error); + return false; + } + + result = palBindBufferMemory(imageStagingBuffer, imageStagingBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind image staging buffer memory: %s", error); + return false; + } + + // copy data + void* data = nullptr; + result = palMapBufferMemory( + imageStagingBuffer, + 0, + imageStagingBufferCreateInfo.size, + &data); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map buffer memory: %s", error); + return false; + } + + // write data to the mapped image copy staging buffer + result = palWriteToImageCopyStagingBuffer( + device, + data, + texture, + imageCreateInfo.format, + &bufferImageCopyInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to write to image copy staging buffer: %s", error); + return false; + } + + palUnmapBufferMemory(imageStagingBuffer); + + // use the first command buffer to upload the copy + // and reset it when done + // set a fence and check at the last line before the main loop + // to see if we have to wait for the copy to be executed + result = palCmdBegin(cmdBuffers[0], nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + PalBufferCopyInfo verticesCopyInfo = {0}; + verticesCopyInfo.size = verticesSize; + + PalBufferCopyInfo indicesCopyInfo = {0}; + indicesCopyInfo.size = indicesSize; + indicesCopyInfo.srcOffset = indicesOffset; + + // copy vertices to the vertex buffer + result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, &verticesCopyInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy vertices to vertex buffer: %s", error); + return false; + } + + // copy vertices to the vertex buffer + result = palCmdCopyBuffer(cmdBuffers[0], indexBuffer, stagingBuffer, &indicesCopyInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy indices to index buffer: %s", error); + return false; + } + + PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; + PalUsageStateInfo oldUsageStateInfo = {0}; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.shaderStageCount = 1; + newUsageStateInfo.shaderStages = vertexShaderStage; + newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; + + result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // copy image staging buffer to the checkerboard image + // first the image must be in the correct layout + PalUsageStateInfo oldImageUsageState = {0}; + PalUsageStateInfo newImageUsageState = {0}; + newImageUsageState.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + + // set a barrier on the image to transition it into transfer dst state + PalImageSubresourceRange checkerboardRange = {0}; + checkerboardRange.startMipLevel = 0; + checkerboardRange.startArrayLayer = 0; + checkerboardRange.mipLevelCount = 1; + checkerboardRange.layerArrayCount = 1; + + result = palCmdImageBarrier( + cmdBuffers[0], + checkerboard, + &checkerboardRange, + &oldImageUsageState, + &newImageUsageState); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image barrier: %s", error); + return false; + } + + result = palCmdCopyBufferToImage( + cmdBuffers[0], + checkerboard, + imageStagingBuffer, + &bufferImageCopyInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer to image: %s", error); + return false; + } + + // we should transition the image into a shader read state so we dont do that + // in the main loop + PalShaderStage fragmentShaderStage[] = { PAL_SHADER_STAGE_FRAGMENT }; + oldImageUsageState = newImageUsageState; + newImageUsageState.usageState = PAL_USAGE_STATE_SHADER_READ; + newImageUsageState.shaderStageCount = 1; + newImageUsageState.shaderStages = fragmentShaderStage; // fragment shader will read + + result = palCmdImageBarrier( + cmdBuffers[0], + checkerboard, + &checkerboardRange, + &oldImageUsageState, + &newImageUsageState); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image barrier: %s", error); + return false; + } + + result = palCmdEnd(cmdBuffers[0]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffers[0]; + submitInfo.fence = fence; + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // now we have the checkerboard texture data in the image + // we need an image view and a sampler + PalImageView* checkerboardImageView = nullptr; + PalImageViewCreateInfo checkerboardImageViewCreateInfo = {0}; + checkerboardImageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + checkerboardImageViewCreateInfo.subresourceRange = checkerboardRange; + checkerboardImageViewCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; + + result = palCreateImageView( + device, + checkerboard, + &checkerboardImageViewCreateInfo, + &checkerboardImageView); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create checkerboard image view: %s", error); + return false; + } + + PalSampler* sampler = nullptr; + PalSamplerCreateInfo samplerCreateInfo = {0}; + samplerCreateInfo.addressModeU = PAL_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.addressModeV = PAL_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.addressModeW = PAL_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.borderColor = PAL_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerCreateInfo.compareOp = PAL_COMPARE_OP_NEVER; // will not be used if its not enabled + + samplerCreateInfo.enableAnisotropy = false; + samplerCreateInfo.enableCompare = false; + samplerCreateInfo.magFilterMode = PAL_FILTER_MODE_LINEAR; + samplerCreateInfo.minFilterMode = PAL_FILTER_MODE_LINEAR; + samplerCreateInfo.maxAnisotropy = 1.0f; + + result = palCreateSampler( + device, + &samplerCreateInfo, + &sampler); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create sampler: %s", error); + return false; + } + + // create shaders + Uint64 vertBytecodeSize = 0; + Uint64 fragBytecodeSize = 0; + void* vertBytecode = nullptr; + void* fragBytecode = nullptr; + + PalShaderCreateInfo vertShaderCreateInfo = {0}; + PalShaderCreateInfo fragShaderCreateInfo = {0}; + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + vertBytecodeSize = sizeof(s_TextureVertShaderSpv); + fragBytecodeSize = sizeof(s_TextureFragShaderSpv); + + vertBytecode = (void*)s_TextureVertShaderSpv; + fragBytecode = (void*)s_TextureFragShaderSpv; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + vertBytecodeSize = sizeof(s_TextureVertShaderDxil); + fragBytecodeSize = sizeof(s_TextureFragShaderDxil); + + vertBytecode = (void*)s_TextureVertShaderDxil; + fragBytecode = (void*)s_TextureFragShaderDxil; + } + + // describe how many entries are in the shader bytecode + // For simplicity, we dont use one shader bytecode for all the shaders + PalShaderEntry vertEntry = {0}; + vertEntry.entryName = "main"; + vertEntry.stage = PAL_SHADER_STAGE_VERTEX; + + PalShaderEntry fragmentEntry = {0}; + fragmentEntry.entryName = "main"; + fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; + + vertShaderCreateInfo.bytecode = vertBytecode; + vertShaderCreateInfo.bytecodeSize = vertBytecodeSize; + vertShaderCreateInfo.entries = &vertEntry; + vertShaderCreateInfo.entryCount = 1; + + fragShaderCreateInfo.bytecode = fragBytecode; + fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; + fragShaderCreateInfo.entries = &fragmentEntry; + fragShaderCreateInfo.entryCount = 1; + + result = palCreateShader(device, &vertShaderCreateInfo, &vertexShader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create vertex shader: %s", error); + return false; + } + + result = palCreateShader(device, &fragShaderCreateInfo, &fragmentShader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fragment shader: %s", error); + return false; + } + + // create descriptor set layout + PalDescriptorSetLayoutBinding descriptorBindings[2]; + PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; + + descriptorBindings[0].descriptorCount = 3; + descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + descriptorBindings[0].shaderStageCount = 1; + descriptorBindings[0].shaderStages = shaderStages; + + descriptorBindings[1].descriptorCount = 1; // not an array + descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; + descriptorBindings[1].shaderStageCount = 1; + descriptorBindings[1].shaderStages = shaderStages; + + PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; + descriptorSetLayoutcreateInfo.bindingCount = 2; + descriptorSetLayoutcreateInfo.bindings = descriptorBindings; + + result = palCreateDescriptorSetLayout( + device, + &descriptorSetLayoutcreateInfo, + &descriptorSetLayout); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor set layout: %s", error); + return false; + } + + // create descriptor pool + PalDescriptorPoolBindingSize storageBufferBindingsizes[2]; + storageBufferBindingsizes[0].bindingCount = 3; + storageBufferBindingsizes[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + + storageBufferBindingsizes[1].bindingCount = 1; + storageBufferBindingsizes[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; + + PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; + descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set + descriptorPoolCreateInfo.maxDescriptorBindingSizes = 2; + descriptorPoolCreateInfo.bindingSizes = storageBufferBindingsizes; + + result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor pool: %s", error); + return false; + } + + // allocate a single descriptor set from the descriptor pool + // using the layout we created above + result = palAllocateDescriptorSet(device, descriptorPool, descriptorSetLayout, &descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate descriptor set: %s", error); + return false; + } + + // write the inital data to the descriptor set since its created empty + PalDescriptorImageViewInfo descriptorImageInfo = {0}; + descriptorImageInfo.imageView = checkerboardImageView; + + PalDescriptorSamplerInfo descriptorSamplerInfo = {0}; + descriptorSamplerInfo.sampler = sampler; + + PalDescriptorSetWriteInfo writeInfos[2]; + writeInfos[0].binding = 0; + writeInfos[0].imageViewInfo = &descriptorImageInfo; + writeInfos[0].descriptorSet = descriptorSet; + writeInfos[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + writeInfos[0].descriptorCount = 3; + + writeInfos[0].arrayElement = 0; + writeInfos[0].bufferInfo = nullptr; + writeInfos[0].samplerInfo = nullptr; + writeInfos[0].tlasInfo = nullptr; + + writeInfos[1].binding = 1; + writeInfos[1].samplerInfo = &descriptorSamplerInfo; + writeInfos[1].descriptorSet = descriptorSet; + writeInfos[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; + writeInfos[1].descriptorCount = 1; + + writeInfos[1].arrayElement = 0; + writeInfos[1].imageViewInfo = nullptr; + writeInfos[1].tlasInfo = nullptr; + writeInfos[1].bufferInfo = nullptr; + + result = palUpdateDescriptorSet(device, 2, writeInfos); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to update descriptor set: %s", error); + return false; + } + + // create pipeline layout + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + pipelineLayoutCreateInfo.descriptorSetLayoutCount = 1; + pipelineLayoutCreateInfo.descriptorSetLayouts = &descriptorSetLayout; + + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline layout: %s", error); + return false; + } + + PalRenderingLayoutInfo renderingLayoutInfo = {0}; + renderingLayoutInfo.colorAttachentCount = 1; + renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; + renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.viewCount = 1; + + // create graphics pipeline + PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; + PalVertexLayout vertexLayout = {0}; + PalVertexAttribute vertexAttributes[2]; + + // position + vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; + vertexAttributes[0].semanticName = nullptr; // use default + vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; + + // texture coordinates + vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_TEXCOORD; + vertexAttributes[1].semanticName = nullptr; // use default + vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT2; + + vertexLayout.attributeCount = 2; + vertexLayout.attributes = vertexAttributes; + vertexLayout.binding = 0; // first vertex buffer binding slot + vertexLayout.type = PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX; + + pipelineCreateInfo.vertexLayoutCount = 1; + pipelineCreateInfo.vertexLayouts = &vertexLayout; + + // color blend attachment + PalColorBlendAttachment blendAttachment = {0}; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; + + pipelineCreateInfo.colorBlendAttachments = &blendAttachment; + pipelineCreateInfo.colorBlendAttachmentCount = 1; + + // shaders + PalShader* shaders[2]; + shaders[0] = vertexShader; + shaders[1] = fragmentShader; + pipelineCreateInfo.shaderCount = 2; + pipelineCreateInfo.shaders = shaders; + + pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + pipelineCreateInfo.pipelineLayout = pipelineLayout; + pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; + + result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create graphics pipeline: %s", error); + return false; + } + + palDestroyShader(vertexShader); + palDestroyShader(fragmentShader); + + // wait for the vertices copy to be done + result = palWaitFence(fence, PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } + + // the vertices have been copied + palDestroyFence(fence); + palDestroyBuffer(stagingBuffer); + palFreeMemory(device, stagingBufferMemory); + + // we can destroy the image staging buffer + palDestroyBuffer(imageStagingBuffer); + palFreeMemory(device, imageStagingBufferMemory); + + // main loop + Uint32 currentFrame = 0; + bool running = true; + + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + + PalRect2D scissor = {0}; + scissor.height = WINDOW_HEIGHT; + scissor.width = WINDOW_WIDTH; + + while (running) { + // update the video system to push video events + palUpdateVideo(); + + PalEvent event; + while (palPollEvent(eventDriver, &event)) { + switch (event.type) { + case PAL_EVENT_WINDOW_CLOSE: { + running = false; + break; + } + + case PAL_EVENT_KEYDOWN: { + PalKeycode keycode = 0; + palUnpackUint32(event.data, &keycode, nullptr); + if (keycode == PAL_KEYCODE_ESCAPE) { + running = false; + } + break; + } + } + } + + result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; + nextImageInfo.timeout = PAL_INFINITE; + + Uint32 imageIndex = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + if (inFlightImages[imageIndex] != nullptr) { + result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + inFlightImages[imageIndex] = inFlightFences[currentFrame]; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + result = palResetFence(inFlightFences[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + } else { + // recreate since we dont support fence resetting + palDestroyFence(inFlightFences[currentFrame]); + + result = palCreateFence(device, false, &inFlightFences[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + // reset the command buffer + result = palResetCommandBuffer(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to reset command buffer: %s", error); + return false; + } + + result = palCmdBegin(cmdBuffers[currentFrame], nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + // change the state of the image view to make it renderable + PalUsageStateInfo oldUsageStateInfo = {0}; + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + + PalImageSubresourceRange imageRange = {0}; + imageRange.layerArrayCount = 1; + imageRange.mipLevelCount = 1; + imageRange.startArrayLayer = 0; + imageRange.startMipLevel = 0; + + PalImage* image = palGetSwapchainImage(swapchain, imageIndex); + result = palCmdImageBarrier( + cmdBuffers[currentFrame], + image, + &imageRange, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + PalClearValue clearValue; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; + + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.clearValue = clearValue; + colorAttachment.imageView = imageViews[imageIndex]; + + PalRenderingInfo renderingInfo = {0}; + renderingInfo.viewCount = 1; + renderingInfo.colorAttachentCount = 1; + renderingInfo.colorAttachments = &colorAttachment; + + result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin rendering: %s", error); + return false; + } + + // bind pipeline + result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind descriptor set: %s", error); + return false; + } + + // set viewport and scissors + result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set viewport: %s", error); + return false; + } + + result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set scissors: %s", error); + return false; + } + + // bind vertex buffer + Uint64 offset[] = {0}; + result = palCmdBindVertexBuffers( + cmdBuffers[currentFrame], + 0, + 1, + &vertexBuffer, + offset); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind vertex buffer: %s", error); + return false; + } + + result = palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to issue draw command: %s", error); + return false; + } + + result = palCmdEndRendering(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end rendering: %s", error); + return false; + } + + // change the state of the image view to make it presentable + oldUsageStateInfo = newUsageStateInfo; + newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + result = palCmdImageBarrier( + cmdBuffers[currentFrame], + image, + &imageRange, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + result = palCmdEnd(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // submit command buffer + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffers[currentFrame]; + submitInfo.fence = inFlightFences[currentFrame]; + submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; + + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // present + PalSwapchainPresentInfo presentInfo = {0}; + presentInfo.imageIndex = imageIndex; + presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; + result = palPresentSwapchain(swapchain, &presentInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to present swapchain: %s", error); + return false; + } + + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + } + + result = palWaitQueue(queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for queue: %s", error); + return false; + } + + palDestroyPipeline(pipeline); + palDestroyPipelineLayout(pipelineLayout); + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + palDestroySemaphore(imageAvailableSemaphores[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); + palDestroyFence(inFlightFences[i]); + palFreeCommandBuffer(cmdBuffers[i]); + } + + for (int i = 0; i < imageCount; i++) { + palDestroyImageView(imageViews[i]); + } + + palDestroyDescriptorPool(descriptorPool); + palDestroyDescriptorSetLayout(descriptorSetLayout); + + palDestroySampler(sampler); + palDestroyImageView(checkerboardImageView); + palDestroyImage(checkerboard); + palFreeMemory(device, checkerboardMemory); + + palDestroyBuffer(vertexBuffer); + palFreeMemory(device, vertexBufferMemory); + + palDestroyBuffer(indexBuffer); + palFreeMemory(device, indexBufferMemory); + + palDestroyCommandPool(cmdPool); + palDestroySwapchain(swapchain); + palDestroySurface(surface); + palDestroyQueue(queue); + palDestroyDevice(device); + palShutdownGraphics(); + palFree(nullptr, imageViews); + + palDestroyWindow(window); + palShutdownVideo(); + palDestroyEventDriver(eventDriver); + return true; + +} \ No newline at end of file diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 60efbac7..07ffc976 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -391,7 +391,8 @@ bool triangleTest() float vertices[] = { 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, - -0.5f, -0.5f, 0.0f, 0.0f, 1.0f}; + -0.5f, -0.5f, 0.0f, 0.0f, 1.0f + }; // clang-format on PalBufferCreateInfo bufferCreateInfo = {0}; diff --git a/tests/tests.h b/tests/tests.h index d0a92c02..71c07f88 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -61,5 +61,6 @@ bool clearColorTest(); bool triangleTest(); bool meshTest(); bool textureTest(); +bool descriptorIndexingTest(); #endif // _TESTS_H diff --git a/tests/tests.lua b/tests/tests.lua index c84fe701..d9db65a6 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -80,7 +80,8 @@ project "tests" "graphics/clear_color_test.c", "graphics/triangle_test.c", "graphics/mesh_test.c", - "graphics/texture_test.c" + "graphics/texture_test.c", + "graphics/descriptor_indexing_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index f62e99aa..adbf959e 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -66,7 +66,8 @@ int main(int argc, char** argv) // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); - registerTest(textureTest, "Texture Test"); + // registerTest(textureTest, "Texture Test"); + registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From 0ad8ca7bf08b00a6df845df2c2122cff3c510b99 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 6 May 2026 22:09:02 +0000 Subject: [PATCH 196/372] start API cleanup vulkan --- include/pal/pal_graphics.h | 139 +- src/graphics/pal_graphics.c | 51 + src/graphics/pal_vulkan.c | 144 +- tests/graphics/compute_test.c | 15 +- tests/graphics/descriptor_indexing_test.c | 1514 --------------------- tests/graphics/graphics_test.c | 342 ++++- tests/tests.h | 1 - tests/tests.lua | 3 +- tests/tests_main.c | 3 +- 9 files changed, 606 insertions(+), 1606 deletions(-) delete mode 100644 tests/graphics/descriptor_indexing_test.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index e2f8b0ba..4676dc56 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -591,13 +591,13 @@ typedef enum { * @ingroup pal_graphics */ typedef enum { - PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY = PAL_BIT64(0), - PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING = PAL_BIT64(1), - PAL_ADAPTER_FEATURE_MULTI_VIEWPORT = PAL_BIT64(2), - PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(3), - PAL_ADAPTER_FEATURE_TESSELLATION_SHADER = PAL_BIT64(4), - PAL_ADAPTER_FEATURE_GEOMETRY_SHADER = PAL_BIT64(5), - PAL_ADAPTER_FEATURE_COMPUTE_SHADER = PAL_BIT64(6), + PAL_ADAPTER_FEATURE_NONE = 0, + PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY = PAL_BIT64(1), + PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING = PAL_BIT64(2), + PAL_ADAPTER_FEATURE_MULTI_VIEWPORT = PAL_BIT64(3), + PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(4), + PAL_ADAPTER_FEATURE_TESSELLATION_SHADER = PAL_BIT64(5), + PAL_ADAPTER_FEATURE_GEOMETRY_SHADER = PAL_BIT64(6), PAL_ADAPTER_FEATURE_SHADER_FLOAT16 = PAL_BIT64(7), PAL_ADAPTER_FEATURE_SHADER_FLOAT64 = PAL_BIT64(8), PAL_ADAPTER_FEATURE_SHADER_INT16 = PAL_BIT64(9), @@ -1477,15 +1477,23 @@ typedef struct { Uint32 maxImageArrayLayers; Uint32 maxImageMipLevels; Uint32 maxColorAttachments; - Uint32 maxMultiViews; - Uint32 maxViewports; - Uint32 maxSamplers; Uint32 maxUniformBufferSize; Uint32 maxStorageBufferSize; Uint32 maxPushConstantSize; Uint32 maxVertexLayouts; Uint32 maxVertexAttributes; Uint32 maxTessellationPatchPoint; + Uint32 maxPerStageDescriptorSampledImages; + Uint32 maxDescriptorSetSampledImages; + Uint32 maxPerStageDescriptorStorageImages; + Uint32 maxDescriptorSetStorageImages; + Uint32 maxPerStageDescriptorSamplers; + Uint32 maxDescriptorSetSamplers; + Uint32 maxPerStageDescriptorStorageBuffers; + Uint32 maxDescriptorSetStorageBuffers; + Uint32 maxPerStageDescriptorUniformBuffers; + Uint32 maxDescriptorSetUniformBuffers; + Uint32 maxBoundDescriptorSets; Uint32 maxComputeWorkGroupInvocations; /**< Max compute threads per workgroup across all axis.*/ Uint32 maxComputeWorkGroupCount[3]; /**< Max compute workgroups per axis.*/ Uint32 maxComputeWorkGroupSize[3]; /**< Max compute threads per workgroup per axis.*/ @@ -1505,6 +1513,28 @@ typedef struct { Uint32 maxAnisotropy; } PalSamplerAnisotropyCapabilities; +/** + * @struct PalMultiViewCapabilities + * @brief Multi view capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 maxMultiViews; +} PalMultiViewCapabilities; + +/** + * @struct PalMultiViewportCapabilities + * @brief Multi viewport capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 maxViewports; +} PalMultiViewportCapabilities; + /** * @struct PalDepthStencilCapabilities * @brief Depth stencil capabilities of an adapter (GPU). @@ -1588,7 +1618,7 @@ typedef struct { Uint32 maxPrimitiveCount; Uint32 maxGeometryCount; Uint32 maxPayloadSize; /**< Max memory per ray.*/ - Uint32 maxDispatchInvocations; /**< Max ray threads per dispatch.*/ + Uint32 maxDispatchInvocations; } PalRayTracingCapabilities; /** @@ -1602,18 +1632,21 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + bool bindlessSampledImages; /**< If true, bindless sampled images are supported.*/ + bool bindlessStorageImages; /**< If true, bindless storage images are supported.*/ bool bindlessSamplers; /**< If true, bindless samplers are supported.*/ bool bindlessStorageBuffers; /**< If true, bindless storage buffers are supported.*/ bool bindlessUniformBuffers; /**< If true, bindless uniform buffers are supported.*/ - Uint32 maxImagesPerShaderStage; - Uint32 maxImagesPerDescriptorSet; - Uint32 maxSamplersPerShaderStage; - Uint32 maxSamplersPerDescriptorSet; - Uint32 maxStorageBuffersPerShaderStage; - Uint32 maxStorageBuffersPerDescriptorSet; - Uint32 maxUniformBuffersPerShaderStage; - Uint32 maxUniformBuffersPerDescriptorSet; - Uint32 maxDescriptors; + Uint32 maxPerStageBindlessDescriptorSampledImages; + Uint32 maxDescriptorSetBindlessSampledImages; + Uint32 maxPerStageBindlessDescriptorStorageImages; + Uint32 maxDescriptorSetBindlessStorageImages; + Uint32 maxPerStageBindlessDescriptorSamplers; + Uint32 maxDescriptorSetBindlessSamplers; + Uint32 maxPerStageBindlessDescriptorStorageBuffers; + Uint32 maxDescriptorSetBindlessStorageBuffers; + Uint32 maxPerStageBindlessDescriptorUniformBuffers; + Uint32 maxDescriptorSetBindlessUniformBuffers; } PalDescriptorIndexingCapabilities; /** @@ -2834,6 +2867,26 @@ typedef struct { PalDevice* device, PalSamplerAnisotropyCapabilities* caps); + /** + * Backend implementation of ::palQueryMultiViewCapabilities. + * + * Must obey the rules and semantics documented in + * palQueryMultiViewCapabilities(). + */ + PalResult PAL_CALL (*queryMultiViewCapabilities)( + PalDevice* device, + PalMultiViewCapabilities* caps); + + /** + * Backend implementation of ::palQueryMultiViewportCapabilities. + * + * Must obey the rules and semantics documented in + * palQueryMultiViewportCapabilities(). + */ + PalResult PAL_CALL (*queryMultiViewportCapabilities)( + PalDevice* device, + PalMultiViewportCapabilities* caps); + /** * Backend implementation of ::palQueryDepthStencilCapabilities. * @@ -4328,6 +4381,52 @@ PAL_API PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( PalDevice* device, PalSamplerAnisotropyCapabilities* caps); +/** + * @brief Get multi view feature capabilites or limits about a device. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to query multi view feature capabilities on. + * @param[out] caps Pointer to a PalMultiViewCapabilities to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `caps` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palQueryMultiViewCapabilities( + PalDevice* device, + PalMultiViewCapabilities* caps); + +/** + * @brief Get multi viewport feature capabilites or limits about a device. + * + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_MULTI_VIEWPORT` must be supported and enabled when creating the + * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * @param[in] device Device to query multi viewport feature capabilities on. + * @param[out] caps Pointer to a PalMultiViewportCapabilities to fill. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `caps` is per thread. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palQueryMultiViewportCapabilities( + PalDevice* device, + PalMultiViewportCapabilities* caps); + /** * @brief Get depth stencil feature capabilites or limits about a device. * diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index c5b6222c..15ce4e0d 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -167,6 +167,14 @@ PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk( PalDevice* device, PalSamplerAnisotropyCapabilities* caps); +PalResult PAL_CALL queryMultiViewCapabilitiesVk( + PalDevice* device, + PalMultiViewCapabilities* caps); + +PalResult PAL_CALL queryMultiViewportCapabilitiesVk( + PalDevice* device, + PalMultiViewportCapabilities* caps); + PalResult PAL_CALL queryDepthStencilCapabilitiesVk( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -799,6 +807,8 @@ static PalGraphicsBackend s_VkBackend = { // extended adapter features .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesVk, + .queryMultiViewCapabilities = queryMultiViewCapabilitiesVk, + .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesVk, .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesVk, .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesVk, .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesVk, @@ -1034,6 +1044,15 @@ PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( PalDevice* device, PalSamplerAnisotropyCapabilities* caps); +// TODO: +PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( + PalDevice* device, + PalMultiViewCapabilities* caps); + +PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( + PalDevice* device, + PalMultiViewportCapabilities* caps); + PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -1873,6 +1892,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) // extended adapter features !backend->querySamplerAnisotropyCapabilities || + !backend->queryMultiViewCapabilities || + !backend->queryMultiViewportCapabilities || !backend->queryDepthStencilCapabilities || !backend->queryFragmentShadingRateCapabilities || !backend->queryMeshShaderCapabilities || @@ -2343,6 +2364,36 @@ PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( return device->backend->querySamplerAnisotropyCapabilities(device, caps); } +PalResult PAL_CALL palQueryMultiViewCapabilities( + PalDevice* device, + PalMultiViewCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->queryMultiViewCapabilities(device, caps); +} + +PalResult PAL_CALL palQueryMultiViewportCapabilities( + PalDevice* device, + PalMultiViewportCapabilities* caps) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!device || !caps) { + return PAL_RESULT_NULL_POINTER; + } + + return device->backend->queryMultiViewportCapabilities(device, caps); +} + PalResult PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index f6404664..0ee86e80 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3364,31 +3364,18 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; VkPhysicalDeviceProperties props = {0}; - VkPhysicalDeviceMultiviewPropertiesKHR multiViewProps = {0}; - VkPhysicalDeviceProperties2 properties2 = {0}; - multiViewProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; - s_Vk.getPhysicalDeviceProperties(phyDevice, &props); - properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - properties2.pNext = &multiViewProps; - s_Vk.getPhysicalDeviceProperties2(phyDevice, &properties2); + VkPhysicalDeviceLimits* limits = &props.limits; - caps->maxColorAttachments = props.limits.maxColorAttachments; - caps->maxImageWidth = props.limits.maxImageDimension2D; - caps->maxImageHeight = props.limits.maxImageDimension2D; - caps->maxImageDepth = props.limits.maxImageDimension3D; - caps->maxImageArrayLayers = props.limits.maxImageArrayLayers; + caps->maxColorAttachments = limits->maxColorAttachments; + caps->maxImageWidth = limits->maxImageDimension2D; + caps->maxImageHeight = limits->maxImageDimension2D; + caps->maxImageDepth = limits->maxImageDimension3D; + caps->maxImageArrayLayers = limits->maxImageArrayLayers; - caps->maxViewports = props.limits.maxViewports; - caps->maxSamplers = props.limits.maxSamplerAllocationCount; - caps->maxUniformBufferSize = props.limits.maxUniformBufferRange; - caps->maxStorageBufferSize = props.limits.maxStorageBufferRange; - caps->maxPushConstantSize = props.limits.maxPushConstantsSize; - - caps->maxMultiViews = multiViewProps.maxMultiviewViewCount; - if (caps->maxMultiViews == 0) { - caps->maxMultiViews = 1; - } + caps->maxUniformBufferSize = limits->maxUniformBufferRange; + caps->maxStorageBufferSize = limits->maxStorageBufferRange; + caps->maxPushConstantSize = limits->maxPushConstantsSize; // vulkan does not give this but we calculate from the max width and width Uint32 a = caps->maxImageWidth; @@ -3431,17 +3418,31 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( } } - caps->maxVertexLayouts = props.limits.maxVertexInputBindings; - caps->maxVertexAttributes = props.limits.maxVertexInputAttributes; - caps->maxTessellationPatchPoint = props.limits.maxTessellationPatchSize; + caps->maxVertexLayouts = limits->maxVertexInputBindings; + caps->maxVertexAttributes = limits->maxVertexInputAttributes; + caps->maxTessellationPatchPoint = limits->maxTessellationPatchSize; + + caps->maxPerStageDescriptorSampledImages = limits->maxPerStageDescriptorSampledImages; + caps->maxDescriptorSetSampledImages = limits->maxDescriptorSetSampledImages; + caps->maxPerStageDescriptorStorageImages = limits->maxPerStageDescriptorStorageImages; + caps->maxDescriptorSetStorageImages = limits->maxDescriptorSetStorageImages; + + caps->maxPerStageDescriptorSamplers = limits->maxPerStageDescriptorSamplers; + caps->maxDescriptorSetSamplers = limits->maxDescriptorSetSamplers; + caps->maxPerStageDescriptorStorageBuffers = limits->maxPerStageDescriptorStorageBuffers; + caps->maxDescriptorSetStorageBuffers = limits->maxDescriptorSetStorageBuffers; + + caps->maxPerStageDescriptorUniformBuffers = limits->maxPerStageDescriptorUniformBuffers; + caps->maxDescriptorSetUniformBuffers = limits->maxDescriptorSetUniformBuffers; + caps->maxBoundDescriptorSets = limits->maxBoundDescriptorSets; - caps->maxComputeWorkGroupInvocations = props.limits.maxComputeWorkGroupInvocations; - caps->maxComputeWorkGroupCount[0] = props.limits.maxComputeWorkGroupCount[0]; - caps->maxComputeWorkGroupCount[1] = props.limits.maxComputeWorkGroupCount[1]; - caps->maxComputeWorkGroupCount[2] = props.limits.maxComputeWorkGroupCount[2]; - caps->maxComputeWorkGroupSize[0] = props.limits.maxComputeWorkGroupSize[0]; - caps->maxComputeWorkGroupSize[1] = props.limits.maxComputeWorkGroupSize[1]; - caps->maxComputeWorkGroupSize[2] = props.limits.maxComputeWorkGroupSize[2]; + caps->maxComputeWorkGroupInvocations = limits->maxComputeWorkGroupInvocations; + caps->maxComputeWorkGroupCount[0] = limits->maxComputeWorkGroupCount[0]; + caps->maxComputeWorkGroupCount[1] = limits->maxComputeWorkGroupCount[1]; + caps->maxComputeWorkGroupCount[2] = limits->maxComputeWorkGroupCount[2]; + caps->maxComputeWorkGroupSize[0] = limits->maxComputeWorkGroupSize[0]; + caps->maxComputeWorkGroupSize[1] = limits->maxComputeWorkGroupSize[1]; + caps->maxComputeWorkGroupSize[2] = limits->maxComputeWorkGroupSize[2]; palFree(s_Vk.allocator, queueProps); return PAL_RESULT_SUCCESS; @@ -3781,7 +3782,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) // this features are supported on vulkan adapterFeatures |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; - adapterFeatures |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; @@ -4687,6 +4687,47 @@ PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL queryMultiViewCapabilitiesVk( + PalDevice* device, + PalMultiViewCapabilities* caps) +{ + Device* vkDevice = (Device*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceMultiviewPropertiesKHR props = {0}; + VkPhysicalDeviceProperties2 properties2 = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; + + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + + caps->maxMultiViews = props.maxMultiviewViewCount; + if (caps->maxMultiViews == 0) { + caps->maxMultiViews = 1; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryMultiViewportCapabilitiesVk( + PalDevice* device, + PalMultiViewportCapabilities* caps) +{ + Device* vkDevice = (Device*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceProperties props = {0}; + s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); + + caps->maxViewports = props.limits.maxViewports; + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL queryDepthStencilCapabilitiesVk( PalDevice* device, PalDepthStencilCapabilities* caps) @@ -4851,7 +4892,7 @@ PalResult PAL_CALL queryRayTracingCapabilitiesVk( caps->maxPrimitiveCount = accProps.maxPrimitiveCount; caps->maxGeometryCount = accProps.maxGeometryCount; - caps->maxPayloadSize = INT32_MAX; // depends on memory + caps->maxPayloadSize = 64; // safe caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; return PAL_RESULT_SUCCESS; @@ -4866,6 +4907,7 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + caps->bindlessSampledImages = true; caps->bindlessSamplers = true; VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; @@ -4896,21 +4938,29 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( caps->bindlessUniformBuffers = true; } - caps->maxImagesPerShaderStage = props.maxPerStageDescriptorUpdateAfterBindSampledImages; - caps->maxImagesPerDescriptorSet = props.maxDescriptorSetUpdateAfterBindSampledImages; + // check for bindless storage images + if (desc.shaderStorageImageArrayNonUniformIndexing && + desc.descriptorBindingStorageImageUpdateAfterBind) { + caps->bindlessStorageImages = true; + } - caps->maxSamplersPerShaderStage = props.maxPerStageDescriptorUpdateAfterBindSamplers; - caps->maxSamplersPerDescriptorSet = props.maxDescriptorSetUpdateAfterBindSamplers; + // clang-format off + caps->maxPerStageBindlessDescriptorSampledImages = props.maxPerStageDescriptorUpdateAfterBindSampledImages; + caps->maxDescriptorSetBindlessSampledImages = props.maxDescriptorSetUpdateAfterBindSampledImages; - caps->maxStorageBuffersPerShaderStage = - props.maxPerStageDescriptorUpdateAfterBindStorageBuffers; - caps->maxStorageBuffersPerDescriptorSet = props.maxDescriptorSetUpdateAfterBindStorageBuffers; + caps->maxPerStageBindlessDescriptorStorageImages = props.maxPerStageDescriptorUpdateAfterBindStorageImages; + caps->maxDescriptorSetBindlessStorageImages = props.maxDescriptorSetUpdateAfterBindStorageImages; - caps->maxUniformBuffersPerShaderStage = - props.maxPerStageDescriptorUpdateAfterBindUniformBuffers; - caps->maxUniformBuffersPerDescriptorSet = props.maxDescriptorSetUpdateAfterBindUniformBuffers; + caps->maxPerStageBindlessDescriptorSamplers = props.maxPerStageDescriptorUpdateAfterBindSamplers; + caps->maxDescriptorSetBindlessSamplers = props.maxDescriptorSetUpdateAfterBindSamplers; + + caps->maxPerStageBindlessDescriptorStorageBuffers = props.maxPerStageDescriptorUpdateAfterBindStorageBuffers; + caps->maxDescriptorSetBindlessStorageBuffers = props.maxDescriptorSetUpdateAfterBindStorageBuffers; + + caps->maxPerStageBindlessDescriptorUniformBuffers = props.maxPerStageDescriptorUpdateAfterBindUniformBuffers; + caps->maxDescriptorSetBindlessUniformBuffers = props.maxDescriptorSetUpdateAfterBindUniformBuffers; + // clang-format on - caps->maxDescriptors = props.maxUpdateAfterBindDescriptorsInAllPools; return PAL_RESULT_SUCCESS; } @@ -7457,10 +7507,6 @@ PalResult PAL_CALL cmdDispatchIndirectVk( PalBuffer* buffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 55b3dfc7..c2dbc66f 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -86,7 +86,6 @@ bool computeTest() PalAdapterFeatures adapterFeatures = 0; PalAdapterInfo adapterInfo = {0}; bool hasComputeQueue = false; - bool hasComputeShader = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -103,15 +102,9 @@ bool computeTest() } else { hasComputeQueue = true; - adapterFeatures = palGetAdapterFeatures(adapter); - if (adapterFeatures & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { - hasComputeShader = true; - } else { - hasComputeShader = false; - } } - if (hasComputeShader) { + if (hasComputeQueue) { // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { @@ -141,9 +134,6 @@ bool computeTest() if (!hasComputeQueue) { palLog(nullptr, "Failed to find an adapter that supports compute queue"); - } else if (!hasComputeShader) { - palLog(nullptr, "Failed to find an adapter that supports compute shader"); - } else { palLog(nullptr, "Failed to find an adapter that supports required shader target"); } @@ -151,8 +141,7 @@ bool computeTest() } // create a device - PalAdapterFeatures features = PAL_ADAPTER_FEATURE_COMPUTE_SHADER; - result = palCreateDevice(adapter, features, &device); + result = palCreateDevice(adapter, 0, &device); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c deleted file mode 100644 index 3f425122..00000000 --- a/tests/graphics/descriptor_indexing_test.c +++ /dev/null @@ -1,1514 +0,0 @@ - -#include "pal/pal_graphics.h" -#include "pal/pal_video.h" -#include "pal/pal_system.h" -#include "tests.h" -#include "shaders.h" - -#define WINDOW_WIDTH 640 -#define WINDOW_HEIGHT 480 -#define MAX_FRAMES_IN_FLIGHT 2 -#define TEXTURE_WIDTH 128 -#define TEXTURE_HEIGHT 128 -#define CHECKER_SIZE 16 - -static Uint32 align(Uint32 value, Uint32 alignment) -{ - return (value + alignment - 1) & ~(alignment - 1); -} - -static void createCheckerboardTexture( - Uint32* texture, - Uint32 width, - Uint32 height, - Uint32 checkerSize) -{ - Uint8* pixels = (Uint8*)texture; - for (Int32 y = 0; y < height; ++y) { - for (Int32 x = 0; x < width; ++x) { - Int32 i = (y * width + x) * 4; - int checker = ((x / checkerSize) ^ (y / checkerSize)) & 1; - if (checker) { - pixels[i + 0] = 255; // Red bit - pixels[i + 1] = 0; // Green bit - pixels[i + 2] = 0; // Blue bit - pixels[i + 3] = 255; // Alpha bit - - } else { - pixels[i + 0] = 0; // Red bit - pixels[i + 1] = 255; // Green bit - pixels[i + 2] = 0; // Blue bit - pixels[i + 3] = 255; // Alpha bit - } - } - } -} - -static void PAL_CALL onGraphicsDebug( - void* userData, - PalDebugMessageSeverity severity, - PalDebugMessageType type, - const char* msg) -{ - palLog(nullptr, msg); -} - -bool descriptorIndexingTest() -{ - PalResult result; - PalWindow* window = nullptr; - PalEventDriver* eventDriver = nullptr; - PalGraphicsWindow gfxWindow; - - PalAdapter* adapter = nullptr; - PalDevice* device = nullptr; - PalSurface* surface = nullptr; - PalQueue* queue = nullptr; - PalSwapchain* swapchain = nullptr; - PalCommandPool* cmdPool = nullptr; - PalImageView** imageViews = nullptr; - - PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; - PalFence** inFlightImages; // count of swapchain images - - PalPipelineLayout* pipelineLayout = nullptr; - PalPipeline* pipeline = nullptr; - PalShader* vertexShader = nullptr; - PalShader* fragmentShader = nullptr; - - PalBuffer* vertexBuffer = nullptr; - PalBuffer* indexBuffer = nullptr; - PalBuffer* stagingBuffer = nullptr; - PalMemory* vertexBufferMemory = nullptr; - PalMemory* indexBufferMemory = nullptr; - PalMemory* stagingBufferMemory = nullptr; - - PalDescriptorSetLayout* descriptorSetLayout = nullptr; - PalDescriptorPool* descriptorPool = nullptr; - PalDescriptorSet* descriptorSet = nullptr; - - PalEventDriverCreateInfo eventDriverCreateInfo = {0}; - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; - } - - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - - result = palInitVideo(nullptr, eventDriver); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; - } - - PalWindowCreateInfo windowCreateInfo = {0}; - windowCreateInfo.height = WINDOW_HEIGHT; - windowCreateInfo.width = WINDOW_WIDTH; - windowCreateInfo.show = true; - windowCreateInfo.title = "Triangle Window"; - - PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); - if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { - windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; - } - - result = palCreateWindow(&windowCreateInfo, &window); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; - } - - PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); - gfxWindow.display = winHandle.nativeDisplay; - gfxWindow.window = winHandle.nativeWindow; - - // using pal_system.h will be easy to know the underlying windowing API - // or use typedefs. We will use the pal_system module. This is needed - // for systems which multiple windowing APIs (linux). - PalPlatformInfo platformInfo = {0}; - result = palGetPlatformInfo(&platformInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get platform information: %s", error); - return false; - } - - if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; - - } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; - - } else { - // automatically this is xcb - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; - } - - PalGraphicsDebugger debugger = {0}; - debugger.callback = onGraphicsDebug; - debugger.userData = nullptr; - - result = palInitGraphics(&debugger, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; - } - - // enumerate all available adapters - Int32 adapterCount = 0; - result = palEnumerateAdapters(&adapterCount, nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - if (adapterCount == 0) { - palLog(nullptr, "No adapters found"); - return false; - } - palLog(nullptr, "Adapter count: %d", adapterCount); - - PalAdapter** adapters = nullptr; - adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); - if (!adapters) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - result = palEnumerateAdapters(&adapterCount, adapters); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); - return false; - } - - PalAdapterCapabilities caps = {0}; - PalAdapterInfo adapterInfo = {0}; - PalAdapterFeatures adapterFeatures = 0; - bool hasGraphicsQueue = false; - bool hasDescriptorIndexing = false; - for (Int32 i = 0; i < adapterCount; i++) { - adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); - palFree(nullptr, adapters); - return false; - } - - if (caps.maxGraphicsQueues == 0) { - hasGraphicsQueue = false; - continue; - - } else { - hasGraphicsQueue = true; - adapterFeatures = palGetAdapterFeatures(adapter); - if (adapterFeatures & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - hasDescriptorIndexing = true; - } else { - hasDescriptorIndexing = false; - } - } - - if (hasDescriptorIndexing) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } - - // we prefer spirv first if an adapter supports multiple shader formats - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { - break; - } - } - - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { - break; - } - } - } - adapter = nullptr; - } - - palFree(nullptr, adapters); - if (!adapter) { - if (!hasGraphicsQueue) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - - } else if (!hasDescriptorIndexing) { - palLog(nullptr, "Failed to find an adapter that supports descriptor indexing"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } - return false; - } - - // create a device - PalAdapterFeatures adapterFeatures = palGetAdapterFeatures(adapter); - PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; - features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { - features |= PAL_ADAPTER_FEATURE_FENCE_RESET; - } - - result = palCreateDevice(adapter, features, &device); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); - return false; - } - - // create surface - result = palCreateSurface(device, &gfxWindow, &surface); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create surface: %s", error); - return false; - } - - // create a graphics command queue and check if its supports presenting to the surface - bool foundQueue = false; - for (int i = 0; i < caps.maxGraphicsQueues; i++) { - result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); - return false; - } - - if (!palCanQueuePresent(queue, surface)) { - palDestroyQueue(queue); - queue = nullptr; - } else { - // found a queue - foundQueue = true; - break; - } - } - - if (!foundQueue) { - palLog(nullptr, "Failed to find a queue that can present to the surface"); - return false; - } - - // create a swapchain with the graphics queue - PalSurfaceCapabilities surfaceCaps = {0}; - result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get surface capabilities: %s", error); - return false; - } - - PalSwapchainCreateInfo swapchainCreateInfo = {0}; - swapchainCreateInfo.clipped = true; - swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; - swapchainCreateInfo.height = WINDOW_HEIGHT; - swapchainCreateInfo.width = WINDOW_WIDTH; - swapchainCreateInfo.imageArrayLayerCount = 1; - swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; - swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR; - - // rare but possible on andriod - if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { - swapchainCreateInfo.width = surfaceCaps.maxImageWidth / 2; - } - - if (WINDOW_HEIGHT > surfaceCaps.maxImageHeight) { - swapchainCreateInfo.height = surfaceCaps.maxImageHeight / 2; - } - - // check if the minimal image count is not good for you - // and increase it but not pass the max count - swapchainCreateInfo.imageCount = surfaceCaps.minImageCount; - if (swapchainCreateInfo.imageCount == 1) { - swapchainCreateInfo.imageCount++; - if (surfaceCaps.maxImageCount < 2) { - palLog(nullptr, "Surface does not support double buffers"); - return false; - } - } - - result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create swapchain: %s", error); - return false; - } - - // get all swapchain images and create image views for them - Uint32 imageCount = swapchainCreateInfo.imageCount; - imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); - inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); - if (!imageViews || !inFlightImages) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - PalImageInfo imageInfo; - result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); - return false; - } - - PalImageViewCreateInfo imageViewCreateInfo = {0}; - imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.subresourceRange.layerArrayCount = 1; - imageViewCreateInfo.subresourceRange.mipLevelCount = 1; - imageViewCreateInfo.subresourceRange.startArrayLayer = 0; - imageViewCreateInfo.subresourceRange.startMipLevel = 0; - imageViewCreateInfo.format = imageInfo.format; - - for (int i = 0; i < imageCount; i++) { - // get swapchain image - // this is fast since the images are cache by PAL - PalImage* image = palGetSwapchainImage(swapchain, i); - if (!image) { - palLog(nullptr, "Failed to get swapchain image"); - } - - result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); - return false; - } - - inFlightImages[i] = nullptr; - } - - result = palCreateCommandPool(device, queue, &cmdPool); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); - return false; - } - - // create synchronization objects and command buffers - for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - - result = palCreateFence(device, true, &inFlightFences[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); - return false; - } - - result = palAllocateCommandBuffer( - device, - cmdPool, - PAL_COMMAND_BUFFER_TYPE_PRIMARY, - &cmdBuffers[i]); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; - } - } - - // create vertex and staging buffer - // clang-format off - // vertices format[x, y, u, v, index] - float vertices[] = { - // Quad 1 - -0.9f, 0.9f, 0.0f, 0.0f, 0.0f, - -0.9f, 0.1f, 0.0f, 1.0f, 0.0f, - -0.3f, 0.1f, 1.0f, 1.0f, 0.0f, - -0.3f, 0.9f, 1.0f, 0.0f, 0.0f, - - // Quad 2 - -0.2f, 0.9f, 0.0f, 0.0f, 1.0f, - -0.2f, 0.1f, 0.0f, 1.0f, 1.0f, - 0.4f, 0.1f, 1.0f, 1.0f, 1.0f, - 0.4f, 0.9f, 1.0f, 0.0f, 1.0f, - - // Quad 3 - 0.5f, 0.9f, 0.0f, 0.0f, 2.0f, - 0.5f, 0.1f, 0.0f, 1.0f, 2.0f, - 1.1f, 0.1f, 1.0f, 1.0f, 2.0f, - 1.1f, 0.9f, 1.0f, 0.0f, 2.0f - }; - - Uint32 indices[] = { - // Quad 1 - 0, 1, 2, - 0, 2, 3, - - // Quad 2 - 4, 5, 6, - 4, 6, 7, - - // Quad 3 - 8, 9, 10, - 8, 10, 11 - }; - // clang-format on - - // we will use one staging buffer for both vertices and indices thus we need to align - // the data. We use 256 as a safe default - Uint32 verticesSize = sizeof(vertices); - Uint32 indicesSize = sizeof(indices); - Uint32 indicesOffset = align(verticesSize, 256); - Uint32 stagingBufferSize = indicesOffset + indicesSize; - - // create vertex buffer - PalBufferCreateInfo bufferCreateInfo = {0}; - bufferCreateInfo.size = verticesSize; - bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; - bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve - result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create vertex buffer: %s", error); - return false; - } - - // create index buffer - bufferCreateInfo.size = indicesSize; - bufferCreateInfo.usages = PAL_BUFFER_USAGE_INDEX; - bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve - result = palCreateBuffer(device, &bufferCreateInfo, &indexBuffer); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create index buffer: %s", error); - return false; - } - - // create staging buffer - bufferCreateInfo.size = stagingBufferSize; - bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send - result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create staging buffer: %s", error); - return false; - } - - // get buffer memory requirement and allocate memory - PalMemoryRequirements vertexBufferMemReq = {0}; - PalMemoryRequirements indexBufferMemReq = {0}; - PalMemoryRequirements stagingBufferMemReq = {0}; - - result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get vertex buffer memory requirement: %s", error); - return false; - } - - result = palGetBufferMemoryRequirements(indexBuffer, &indexBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get index buffer memory requirement: %s", error); - return false; - } - - result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get staging buffer memory requirement: %s", error); - return false; - } - - // we need to check if the memory type we want are supported - // but almost every GPU supports a GPU only memory - // and CPU writable memory - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - vertexBufferMemReq.memoryMask, - vertexBufferMemReq.size, - &vertexBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for vertetx buffer: %s", error); - return false; - } - - // allocate memory for index buffer - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - indexBufferMemReq.memoryMask, - indexBufferMemReq.size, - &indexBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for index buffer: %s", error); - return false; - } - - // allocate memory for staging buffer - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - stagingBufferMemReq.memoryMask, - stagingBufferMemReq.size, - &stagingBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for staging buffer: %s", error); - return false; - } - - // bind memory for vertex buffer - result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory for vertex buffer: %s", error); - return false; - } - - // bind memory for index buffer - result = palBindBufferMemory(indexBuffer, indexBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory for index buffer: %s", error); - return false; - } - - // bind memory for index buffer - result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory for staging buffer: %s", error); - return false; - } - - // map the staging buffer and upload the vertices and indices - void* ptr = nullptr; - result = palMapBufferMemory(stagingBuffer, 0, stagingBufferSize, &ptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; - } - - memcpy(ptr, vertices, verticesSize); // copy vertices - memcpy(ptr + indicesOffset, indices, indicesSize); // copy indices - palUnmapBufferMemory(stagingBuffer); - - PalFence* fence = nullptr; - result = palCreateFence(device, false, &fence); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); - return false; - } - - // we dont want to load the texture from disk so we will create a - // checkerboard texture and use that rather - Uint32 texture[TEXTURE_WIDTH * TEXTURE_HEIGHT]; - memset(texture, 0, TEXTURE_WIDTH * TEXTURE_HEIGHT); - createCheckerboardTexture(texture, TEXTURE_WIDTH, TEXTURE_HEIGHT, CHECKER_SIZE); - - // create image for the texture - PalImage* checkerboard = nullptr; - PalImageCreateInfo imageCreateInfo = {0}; - imageCreateInfo.depthOrArraySize = 1; - imageCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; - imageCreateInfo.mipLevelCount = 1; // simple - imageCreateInfo.sampleCount = PAL_SAMPLE_COUNT_1; // simple - imageCreateInfo.type = PAL_IMAGE_TYPE_2D; - imageCreateInfo.usages = PAL_IMAGE_USAGE_TRANSFER_DST | PAL_IMAGE_USAGE_SAMPLED; - imageCreateInfo.width = TEXTURE_WIDTH; - imageCreateInfo.height = TEXTURE_HEIGHT; - - result = palCreateImage(device, &imageCreateInfo, &checkerboard); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image: %s", error); - return false; - } - - // allocate memory for the image - PalMemoryRequirements imageMemReq = {0}; - result = palGetImageMemoryRequirements(checkerboard, &imageMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image memory requirement: %s", error); - return false; - } - - PalMemory* checkerboardMemory = nullptr; - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - imageMemReq.memoryMask, - imageMemReq.size, - &checkerboardMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory: %s", error); - return false; - } - - result = palBindImageMemory(checkerboard, checkerboardMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind image memory: %s", error); - return false; - } - - // create staging buffer to transfer the data to the image - PalBufferImageCopyInfo bufferImageCopyInfo = {0}; - bufferImageCopyInfo.ImageArrayLayerCount = 1; - bufferImageCopyInfo.imageWidth = TEXTURE_WIDTH; - bufferImageCopyInfo.imageHeight = TEXTURE_HEIGHT; - bufferImageCopyInfo.imageDepth = 1; // 2D image - - Uint64 imageCopyStagingBufferSize = 0; - Uint32 bufferRowLength = 0; - Uint32 bufferImageHeight = 0; - - result = palComputeImageCopyStagingBufferRequirements( - device, - imageCreateInfo.format, - &bufferImageCopyInfo, - &bufferRowLength, - &bufferImageHeight, - &imageCopyStagingBufferSize); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to compute image copy staging buffer info: %s", error); - return false; - } - - // update our copy with the required buffer row length and buffer image height - bufferImageCopyInfo.bufferRowLength = bufferRowLength; - bufferImageCopyInfo.bufferImageHeight = bufferImageHeight; - - // create staging buffer to transfer the data to the image - PalBuffer* imageStagingBuffer = nullptr; - PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; - imageStagingBufferCreateInfo.size = imageCopyStagingBufferSize; - imageStagingBufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; - - result = palCreateBuffer(device, &imageStagingBufferCreateInfo, &imageStagingBuffer); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image staging buffer: %s", error); - return false; - } - - PalMemoryRequirements imageStagingBufferMemReq = {0}; - result = palGetBufferMemoryRequirements(imageStagingBuffer, &imageStagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image staging buffer memory requirement: %s", error); - return false; - } - - PalMemory* imageStagingBufferMemory = nullptr; - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - imageStagingBufferMemReq.memoryMask, - imageStagingBufferMemReq.size, - &imageStagingBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory: %s", error); - return false; - } - - result = palBindBufferMemory(imageStagingBuffer, imageStagingBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind image staging buffer memory: %s", error); - return false; - } - - // copy data - void* data = nullptr; - result = palMapBufferMemory( - imageStagingBuffer, - 0, - imageStagingBufferCreateInfo.size, - &data); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; - } - - // write data to the mapped image copy staging buffer - result = palWriteToImageCopyStagingBuffer( - device, - data, - texture, - imageCreateInfo.format, - &bufferImageCopyInfo); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to write to image copy staging buffer: %s", error); - return false; - } - - palUnmapBufferMemory(imageStagingBuffer); - - // use the first command buffer to upload the copy - // and reset it when done - // set a fence and check at the last line before the main loop - // to see if we have to wait for the copy to be executed - result = palCmdBegin(cmdBuffers[0], nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; - } - - PalBufferCopyInfo verticesCopyInfo = {0}; - verticesCopyInfo.size = verticesSize; - - PalBufferCopyInfo indicesCopyInfo = {0}; - indicesCopyInfo.size = indicesSize; - indicesCopyInfo.srcOffset = indicesOffset; - - // copy vertices to the vertex buffer - result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, &verticesCopyInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy vertices to vertex buffer: %s", error); - return false; - } - - // copy vertices to the vertex buffer - result = palCmdCopyBuffer(cmdBuffers[0], indexBuffer, stagingBuffer, &indicesCopyInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy indices to index buffer: %s", error); - return false; - } - - PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; - PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStageCount = 1; - newUsageStateInfo.shaderStages = vertexShaderStage; - newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; - - result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; - } - - // copy image staging buffer to the checkerboard image - // first the image must be in the correct layout - PalUsageStateInfo oldImageUsageState = {0}; - PalUsageStateInfo newImageUsageState = {0}; - newImageUsageState.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - - // set a barrier on the image to transition it into transfer dst state - PalImageSubresourceRange checkerboardRange = {0}; - checkerboardRange.startMipLevel = 0; - checkerboardRange.startArrayLayer = 0; - checkerboardRange.mipLevelCount = 1; - checkerboardRange.layerArrayCount = 1; - - result = palCmdImageBarrier( - cmdBuffers[0], - checkerboard, - &checkerboardRange, - &oldImageUsageState, - &newImageUsageState); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image barrier: %s", error); - return false; - } - - result = palCmdCopyBufferToImage( - cmdBuffers[0], - checkerboard, - imageStagingBuffer, - &bufferImageCopyInfo); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer to image: %s", error); - return false; - } - - // we should transition the image into a shader read state so we dont do that - // in the main loop - PalShaderStage fragmentShaderStage[] = { PAL_SHADER_STAGE_FRAGMENT }; - oldImageUsageState = newImageUsageState; - newImageUsageState.usageState = PAL_USAGE_STATE_SHADER_READ; - newImageUsageState.shaderStageCount = 1; - newImageUsageState.shaderStages = fragmentShaderStage; // fragment shader will read - - result = palCmdImageBarrier( - cmdBuffers[0], - checkerboard, - &checkerboardRange, - &oldImageUsageState, - &newImageUsageState); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image barrier: %s", error); - return false; - } - - result = palCmdEnd(cmdBuffers[0]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); - return false; - } - - PalCommandBufferSubmitInfo submitInfo = {0}; - submitInfo.cmdBuffer = cmdBuffers[0]; - submitInfo.fence = fence; - result = palSubmitCommandBuffer(queue, &submitInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; - } - - // now we have the checkerboard texture data in the image - // we need an image view and a sampler - PalImageView* checkerboardImageView = nullptr; - PalImageViewCreateInfo checkerboardImageViewCreateInfo = {0}; - checkerboardImageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; - checkerboardImageViewCreateInfo.subresourceRange = checkerboardRange; - checkerboardImageViewCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; - - result = palCreateImageView( - device, - checkerboard, - &checkerboardImageViewCreateInfo, - &checkerboardImageView); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create checkerboard image view: %s", error); - return false; - } - - PalSampler* sampler = nullptr; - PalSamplerCreateInfo samplerCreateInfo = {0}; - samplerCreateInfo.addressModeU = PAL_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.addressModeV = PAL_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.addressModeW = PAL_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.borderColor = PAL_BORDER_COLOR_INT_OPAQUE_BLACK; - samplerCreateInfo.compareOp = PAL_COMPARE_OP_NEVER; // will not be used if its not enabled - - samplerCreateInfo.enableAnisotropy = false; - samplerCreateInfo.enableCompare = false; - samplerCreateInfo.magFilterMode = PAL_FILTER_MODE_LINEAR; - samplerCreateInfo.minFilterMode = PAL_FILTER_MODE_LINEAR; - samplerCreateInfo.maxAnisotropy = 1.0f; - - result = palCreateSampler( - device, - &samplerCreateInfo, - &sampler); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create sampler: %s", error); - return false; - } - - // create shaders - Uint64 vertBytecodeSize = 0; - Uint64 fragBytecodeSize = 0; - void* vertBytecode = nullptr; - void* fragBytecode = nullptr; - - PalShaderCreateInfo vertShaderCreateInfo = {0}; - PalShaderCreateInfo fragShaderCreateInfo = {0}; - - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - vertBytecodeSize = sizeof(s_TextureVertShaderSpv); - fragBytecodeSize = sizeof(s_TextureFragShaderSpv); - - vertBytecode = (void*)s_TextureVertShaderSpv; - fragBytecode = (void*)s_TextureFragShaderSpv; - - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - vertBytecodeSize = sizeof(s_TextureVertShaderDxil); - fragBytecodeSize = sizeof(s_TextureFragShaderDxil); - - vertBytecode = (void*)s_TextureVertShaderDxil; - fragBytecode = (void*)s_TextureFragShaderDxil; - } - - // describe how many entries are in the shader bytecode - // For simplicity, we dont use one shader bytecode for all the shaders - PalShaderEntry vertEntry = {0}; - vertEntry.entryName = "main"; - vertEntry.stage = PAL_SHADER_STAGE_VERTEX; - - PalShaderEntry fragmentEntry = {0}; - fragmentEntry.entryName = "main"; - fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; - - vertShaderCreateInfo.bytecode = vertBytecode; - vertShaderCreateInfo.bytecodeSize = vertBytecodeSize; - vertShaderCreateInfo.entries = &vertEntry; - vertShaderCreateInfo.entryCount = 1; - - fragShaderCreateInfo.bytecode = fragBytecode; - fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; - fragShaderCreateInfo.entries = &fragmentEntry; - fragShaderCreateInfo.entryCount = 1; - - result = palCreateShader(device, &vertShaderCreateInfo, &vertexShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create vertex shader: %s", error); - return false; - } - - result = palCreateShader(device, &fragShaderCreateInfo, &fragmentShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fragment shader: %s", error); - return false; - } - - // create descriptor set layout - PalDescriptorSetLayoutBinding descriptorBindings[2]; - PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; - - descriptorBindings[0].descriptorCount = 3; - descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - descriptorBindings[0].shaderStageCount = 1; - descriptorBindings[0].shaderStages = shaderStages; - - descriptorBindings[1].descriptorCount = 1; // not an array - descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; - descriptorBindings[1].shaderStageCount = 1; - descriptorBindings[1].shaderStages = shaderStages; - - PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; - descriptorSetLayoutcreateInfo.bindingCount = 2; - descriptorSetLayoutcreateInfo.bindings = descriptorBindings; - - result = palCreateDescriptorSetLayout( - device, - &descriptorSetLayoutcreateInfo, - &descriptorSetLayout); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor set layout: %s", error); - return false; - } - - // create descriptor pool - PalDescriptorPoolBindingSize storageBufferBindingsizes[2]; - storageBufferBindingsizes[0].bindingCount = 3; - storageBufferBindingsizes[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - - storageBufferBindingsizes[1].bindingCount = 1; - storageBufferBindingsizes[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; - - PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; - descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set - descriptorPoolCreateInfo.maxDescriptorBindingSizes = 2; - descriptorPoolCreateInfo.bindingSizes = storageBufferBindingsizes; - - result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor pool: %s", error); - return false; - } - - // allocate a single descriptor set from the descriptor pool - // using the layout we created above - result = palAllocateDescriptorSet(device, descriptorPool, descriptorSetLayout, &descriptorSet); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate descriptor set: %s", error); - return false; - } - - // write the inital data to the descriptor set since its created empty - PalDescriptorImageViewInfo descriptorImageInfo = {0}; - descriptorImageInfo.imageView = checkerboardImageView; - - PalDescriptorSamplerInfo descriptorSamplerInfo = {0}; - descriptorSamplerInfo.sampler = sampler; - - PalDescriptorSetWriteInfo writeInfos[2]; - writeInfos[0].binding = 0; - writeInfos[0].imageViewInfo = &descriptorImageInfo; - writeInfos[0].descriptorSet = descriptorSet; - writeInfos[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - writeInfos[0].descriptorCount = 3; - - writeInfos[0].arrayElement = 0; - writeInfos[0].bufferInfo = nullptr; - writeInfos[0].samplerInfo = nullptr; - writeInfos[0].tlasInfo = nullptr; - - writeInfos[1].binding = 1; - writeInfos[1].samplerInfo = &descriptorSamplerInfo; - writeInfos[1].descriptorSet = descriptorSet; - writeInfos[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; - writeInfos[1].descriptorCount = 1; - - writeInfos[1].arrayElement = 0; - writeInfos[1].imageViewInfo = nullptr; - writeInfos[1].tlasInfo = nullptr; - writeInfos[1].bufferInfo = nullptr; - - result = palUpdateDescriptorSet(device, 2, writeInfos); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to update descriptor set: %s", error); - return false; - } - - // create pipeline layout - PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; - pipelineLayoutCreateInfo.descriptorSetLayoutCount = 1; - pipelineLayoutCreateInfo.descriptorSetLayouts = &descriptorSetLayout; - - result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); - return false; - } - - PalRenderingLayoutInfo renderingLayoutInfo = {0}; - renderingLayoutInfo.colorAttachentCount = 1; - renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; - renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; - renderingLayoutInfo.viewCount = 1; - - // create graphics pipeline - PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; - PalVertexLayout vertexLayout = {0}; - PalVertexAttribute vertexAttributes[2]; - - // position - vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; - vertexAttributes[0].semanticName = nullptr; // use default - vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; - - // texture coordinates - vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_TEXCOORD; - vertexAttributes[1].semanticName = nullptr; // use default - vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT2; - - vertexLayout.attributeCount = 2; - vertexLayout.attributes = vertexAttributes; - vertexLayout.binding = 0; // first vertex buffer binding slot - vertexLayout.type = PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX; - - pipelineCreateInfo.vertexLayoutCount = 1; - pipelineCreateInfo.vertexLayouts = &vertexLayout; - - // color blend attachment - PalColorBlendAttachment blendAttachment = {0}; - blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; - blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; - blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; - blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; - - pipelineCreateInfo.colorBlendAttachments = &blendAttachment; - pipelineCreateInfo.colorBlendAttachmentCount = 1; - - // shaders - PalShader* shaders[2]; - shaders[0] = vertexShader; - shaders[1] = fragmentShader; - pipelineCreateInfo.shaderCount = 2; - pipelineCreateInfo.shaders = shaders; - - pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - pipelineCreateInfo.pipelineLayout = pipelineLayout; - pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; - - result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create graphics pipeline: %s", error); - return false; - } - - palDestroyShader(vertexShader); - palDestroyShader(fragmentShader); - - // wait for the vertices copy to be done - result = palWaitFence(fence, PAL_INFINITE); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); - return false; - } - - // the vertices have been copied - palDestroyFence(fence); - palDestroyBuffer(stagingBuffer); - palFreeMemory(device, stagingBufferMemory); - - // we can destroy the image staging buffer - palDestroyBuffer(imageStagingBuffer); - palFreeMemory(device, imageStagingBufferMemory); - - // main loop - Uint32 currentFrame = 0; - bool running = true; - - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; - - PalRect2D scissor = {0}; - scissor.height = WINDOW_HEIGHT; - scissor.width = WINDOW_WIDTH; - - while (running) { - // update the video system to push video events - palUpdateVideo(); - - PalEvent event; - while (palPollEvent(eventDriver, &event)) { - switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { - running = false; - break; - } - - case PAL_EVENT_KEYDOWN: { - PalKeycode keycode = 0; - palUnpackUint32(event.data, &keycode, nullptr); - if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; - } - break; - } - } - } - - result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); - return false; - } - - // get next swapchain image - PalSwapchainNextImageInfo nextImageInfo = {0}; - nextImageInfo.fence = nullptr; - nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; - nextImageInfo.timeout = PAL_INFINITE; - - Uint32 imageIndex = 0; - result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; - } - - if (inFlightImages[imageIndex] != nullptr) { - result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); - return false; - } - } - - inFlightImages[imageIndex] = inFlightFences[currentFrame]; - if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { - result = palResetFence(inFlightFences[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); - return false; - } - - } else { - // recreate since we dont support fence resetting - palDestroyFence(inFlightFences[currentFrame]); - - result = palCreateFence(device, false, &inFlightFences[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); - return false; - } - } - - // reset the command buffer - result = palResetCommandBuffer(cmdBuffers[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to reset command buffer: %s", error); - return false; - } - - result = palCmdBegin(cmdBuffers[currentFrame], nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; - } - - // change the state of the image view to make it renderable - PalUsageStateInfo oldUsageStateInfo = {0}; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; - - PalImageSubresourceRange imageRange = {0}; - imageRange.layerArrayCount = 1; - imageRange.mipLevelCount = 1; - imageRange.startArrayLayer = 0; - imageRange.startMipLevel = 0; - - PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - result = palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; - } - - PalClearValue clearValue; - clearValue.color[0] = 0.2f; - clearValue.color[1] = 0.2f; - clearValue.color[2] = 0.2f; - clearValue.color[3] = 1.0f; - - PalAttachmentDesc colorAttachment = {0}; - colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; - colorAttachment.storeOp = PAL_STORE_OP_STORE; - colorAttachment.clearValue = clearValue; - colorAttachment.imageView = imageViews[imageIndex]; - - PalRenderingInfo renderingInfo = {0}; - renderingInfo.viewCount = 1; - renderingInfo.colorAttachentCount = 1; - renderingInfo.colorAttachments = &colorAttachment; - - result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin rendering: %s", error); - return false; - } - - // bind pipeline - result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; - } - - result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind descriptor set: %s", error); - return false; - } - - // set viewport and scissors - result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set viewport: %s", error); - return false; - } - - result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set scissors: %s", error); - return false; - } - - // bind vertex buffer - Uint64 offset[] = {0}; - result = palCmdBindVertexBuffers( - cmdBuffers[currentFrame], - 0, - 1, - &vertexBuffer, - offset); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind vertex buffer: %s", error); - return false; - } - - result = palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to issue draw command: %s", error); - return false; - } - - result = palCmdEndRendering(cmdBuffers[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end rendering: %s", error); - return false; - } - - // change the state of the image view to make it presentable - oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; - } - - result = palCmdEnd(cmdBuffers[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); - return false; - } - - // submit command buffer - PalCommandBufferSubmitInfo submitInfo = {0}; - submitInfo.cmdBuffer = cmdBuffers[currentFrame]; - submitInfo.fence = inFlightFences[currentFrame]; - submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; - submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; - - result = palSubmitCommandBuffer(queue, &submitInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; - } - - // present - PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; - result = palPresentSwapchain(swapchain, &presentInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to present swapchain: %s", error); - return false; - } - - currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; - } - - result = palWaitQueue(queue); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for queue: %s", error); - return false; - } - - palDestroyPipeline(pipeline); - palDestroyPipelineLayout(pipelineLayout); - - for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - palDestroySemaphore(imageAvailableSemaphores[i]); - palDestroySemaphore(renderFinishedSemaphores[i]); - palDestroyFence(inFlightFences[i]); - palFreeCommandBuffer(cmdBuffers[i]); - } - - for (int i = 0; i < imageCount; i++) { - palDestroyImageView(imageViews[i]); - } - - palDestroyDescriptorPool(descriptorPool); - palDestroyDescriptorSetLayout(descriptorSetLayout); - - palDestroySampler(sampler); - palDestroyImageView(checkerboardImageView); - palDestroyImage(checkerboard); - palFreeMemory(device, checkerboardMemory); - - palDestroyBuffer(vertexBuffer); - palFreeMemory(device, vertexBufferMemory); - - palDestroyBuffer(indexBuffer); - palFreeMemory(device, indexBufferMemory); - - palDestroyCommandPool(cmdPool); - palDestroySwapchain(swapchain); - palDestroySurface(surface); - palDestroyQueue(queue); - palDestroyDevice(device); - palShutdownGraphics(); - palFree(nullptr, imageViews); - - palDestroyWindow(window); - palShutdownVideo(); - palDestroyEventDriver(eventDriver); - return true; - -} \ No newline at end of file diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index d98a5ca4..06541186 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -99,18 +99,62 @@ bool graphicsTest() // get information about all the adapters PalAdapterInfo info; + PalAdapterCapabilities caps; PalAdapterFeatures features = 0; for (Int32 i = 0; i < count; i++) { PalAdapter* adapter = adapters[i]; result = palGetAdapterInfo(adapter, &info); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + palLog(nullptr, "Failed to get adapter information: %s", error); palFree(nullptr, adapters); return false; } + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + // create a device features = palGetAdapterFeatures(adapter); + PalDevice* device = nullptr; + PalAdapterFeatures deviceFeatures = 0; + if (features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { + deviceFeatures |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; + } + + if (features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE) { + deviceFeatures |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; + } + + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { + deviceFeatures |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE; + } + + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + deviceFeatures |= PAL_ADAPTER_FEATURE_MESH_SHADER; + } + + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + deviceFeatures |= PAL_ADAPTER_FEATURE_RAY_TRACING; + } + + if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + deviceFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + } + + result = palCreateDevice(adapter, deviceFeatures, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + palFree(nullptr, adapters); + return false; + } + Uint32 vramMb = info.vram / (1024.0 * 1024.0); Uint32 sharedMemMb = info.sharedMemory / (1024.0 * 1024.0); @@ -164,6 +208,51 @@ bool graphicsTest() } palLog(nullptr, " API Type: %s", apiTypeString); + palLog(nullptr, ""); + palLog(nullptr, " Capabilities:"); + palLog(nullptr, " Max compute queue: %d", caps.maxComputeQueues); + palLog(nullptr, " Max graphics queue: %d", caps.maxGraphicsQueues); + palLog(nullptr, " Max copy queue: %d", caps.maxCopyQueues); + + palLog(nullptr, " Max image width: %d", caps.maxImageWidth); + palLog(nullptr, " Max image height: %d", caps.maxImageHeight); + palLog(nullptr, " Max image depth: %d", caps.maxImageDepth); + palLog(nullptr, " Max image array layers: %d", caps.maxImageArrayLayers); + palLog(nullptr, " Max image mip levels: %d", caps.maxImageMipLevels); + + palLog(nullptr, " Max color attachments: %d", caps.maxColorAttachments); + palLog(nullptr, " Max uniform buffer size: %d Bytes", caps.maxUniformBufferSize); + palLog(nullptr, " Max storage buffer size: %d Bytes", caps.maxStorageBufferSize); + palLog(nullptr, " Max push constant size: %d Bytes", caps.maxPushConstantSize); + + palLog(nullptr, " Max vertex layouts: %d", caps.maxVertexLayouts); + palLog(nullptr, " Max vertex attributes: %d", caps.maxVertexAttributes); + palLog(nullptr, " Max tessellation patch point: %d", caps.maxTessellationPatchPoint); + + // clang-format off + palLog(nullptr, " Max per stage descriptor sampled images: %d", caps.maxPerStageDescriptorSampledImages); + palLog(nullptr, " Max descriptor set sampled images: %d", caps.maxDescriptorSetSampledImages); + palLog(nullptr, " Max per stage descriptor storage images: %d", caps.maxPerStageDescriptorStorageImages); + palLog(nullptr, " Max descriptor set storage images: %d", caps.maxDescriptorSetStorageImages); + + palLog(nullptr, " Max per stage descriptor samplers: %d", caps.maxPerStageDescriptorSamplers); + palLog(nullptr, " Max descriptor set samplers: %d", caps.maxDescriptorSetSamplers); + palLog(nullptr, " Max per stage descriptor storage buffers: %d", caps.maxPerStageDescriptorStorageBuffers); + palLog(nullptr, " Max descriptor set storage buffers: %d", caps.maxDescriptorSetStorageBuffers); + + palLog(nullptr, " Max per stage descriptor uniform buffers: %d", caps.maxPerStageDescriptorUniformBuffers); + palLog(nullptr, " Max descriptor set uniform buffers: %d", caps.maxDescriptorSetUniformBuffers); + palLog(nullptr, " Max bound descriptor sets: %d", caps.maxBoundDescriptorSets); + // clang-format on + + palLog(nullptr, " Max compute invocations: %d", caps.maxComputeWorkGroupInvocations); + palLog(nullptr, " Max compute work group count[0]: %d", caps.maxComputeWorkGroupCount[0]); + palLog(nullptr, " Max compute work group count[1]: %d", caps.maxComputeWorkGroupCount[1]); + palLog(nullptr, " Max compute work group count[2]: %d", caps.maxComputeWorkGroupCount[2]); + palLog(nullptr, " Max compute work group size[0]: %d", caps.maxComputeWorkGroupSize[0]); + palLog(nullptr, " Max compute work group size[1]: %d", caps.maxComputeWorkGroupSize[1]); + palLog(nullptr, " Max compute work group size[2]: %d", caps.maxComputeWorkGroupSize[2]); + // shader formats PalShaderTarget target; palLog(nullptr, ""); @@ -187,6 +276,18 @@ bool graphicsTest() palLog(nullptr, " Supported Features:"); if (features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { palLog(nullptr, " Sampler Anisotropy"); + + PalSamplerAnisotropyCapabilities tmp; + result = palQuerySamplerAnisotropyCapabilities(device, &tmp); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get sampler anisotropy capabilities: %s", error); + return false; + } + + palLog(nullptr, " Max anisotropy: %d", tmp.maxAnisotropy); + + palLog(nullptr, ""); } if (features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { @@ -195,6 +296,18 @@ bool graphicsTest() if (features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { palLog(nullptr, " Multi viewport"); + + PalMultiViewportCapabilities tmp; + result = palQueryMultiViewportCapabilities(device, &tmp); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get multi viewport capabilities: %s", error); + return false; + } + + palLog(nullptr, " Max viewports: %d", tmp.maxViewports); + + palLog(nullptr, ""); } if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { @@ -209,10 +322,6 @@ bool graphicsTest() palLog(nullptr, " Geometry shader"); } - if (features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER) { - palLog(nullptr, " Compute shader"); - } - if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { palLog(nullptr, " Shader float16"); } @@ -231,18 +340,179 @@ bool graphicsTest() if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { palLog(nullptr, " Ray tracing"); + + PalRayTracingCapabilities tmp; + result = palQueryRayTracingCapabilities(device, &tmp); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get ray tracing capabilities: %s", error); + return false; + } + + palLog(nullptr, " Max recursion depth: %d", tmp.maxRecursionDepth); + palLog(nullptr, " Max hit attribute size: %d Bytes", tmp.maxHitAttributeSize); + palLog(nullptr, " Max instance count: %d", tmp.maxInstanceCount); + palLog(nullptr, " Max primitive count: %d", tmp.maxPrimitiveCount); + palLog(nullptr, " Max geometry count: %d", tmp.maxGeometryCount); + palLog(nullptr, " Max payload size: %d Bytes", tmp.maxPayloadSize); + palLog(nullptr, " Max dispatch invocations: %d", tmp.maxDispatchInvocations); + + palLog(nullptr, ""); } if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { palLog(nullptr, " Mesh and task shader"); + + PalMeshShaderCapabilities tmp; + result = palQueryMeshShaderCapabilities(device, &tmp); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get mesh shader capabilities: %s", error); + return false; + } + + palLog(nullptr, " Max mesh output primitives: %d", tmp.maxMeshOutputPrimitives); + palLog(nullptr, " Max mesh output vertices: %d", tmp.maxMeshOutputVertices); + palLog(nullptr, " Max mesh invocations: %d", tmp.maxMeshWorkGroupInvocations); + palLog(nullptr, " Max task invocations: %d", tmp.maxTaskWorkGroupInvocations); + + palLog(nullptr, " Max mesh work group count[0]: %d", tmp.maxMeshWorkGroupCount[0]); + palLog(nullptr, " Max mesh work group count[1]: %d", tmp.maxMeshWorkGroupCount[1]); + palLog(nullptr, " Max mesh work group count[2]: %d", tmp.maxMeshWorkGroupCount[2]); + palLog(nullptr, " Max task work group count[0]: %d", tmp.maxTaskWorkGroupCount[0]); + palLog(nullptr, " Max task work group count[1]: %d", tmp.maxTaskWorkGroupCount[1]); + palLog(nullptr, " Max task work group count[2]: %d", tmp.maxTaskWorkGroupCount[2]); + + palLog(nullptr, ""); } if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { palLog(nullptr, " Fragment shading rate"); + + PalFragmentShadingRateCapabilities tmp; + result = palQueryFragmentShadingRateCapabilities(device, &tmp); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get FSR capabilities: %s", error); + return false; + } + + palLog(nullptr, " Min texel width: %d", tmp.minTexelWidth); + palLog(nullptr, " Min texel height: %d", tmp.maxTexelWidth); + palLog(nullptr, " Max texel width: %d", tmp.minTexelHeight); + palLog(nullptr, " Max texel height: %d", tmp.maxTexelHeight); + + palLog(nullptr, " Support Shading Rates:"); + if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_1X1]) { + palLog(nullptr, " 1 X 1"); + } + + if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_1X2]) { + palLog(nullptr, " 1 X 2"); + } + + if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_2X1]) { + palLog(nullptr, " 2 X 1"); + } + + if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_2X2]) { + palLog(nullptr, " 2 X 2"); + } + + if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_2X4]) { + palLog(nullptr, " 2 X 4"); + } + + if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_4X2]) { + palLog(nullptr, " 4 X 2"); + + } + + if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_4X4]) { + palLog(nullptr, " 4 X 4"); + } + + palLog(nullptr, " Support Combiner operations:"); + if (tmp.combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP]) { + palLog(nullptr, " Keep"); + } + + if (tmp.combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE]) { + palLog(nullptr, " Replace"); + } + + if (tmp.combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN]) { + palLog(nullptr, " Min"); + } + + if (tmp.combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX]) { + palLog(nullptr, " Max"); + } + + if (tmp.combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL]) { + palLog(nullptr, " Mul"); + } + + palLog(nullptr, ""); } if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { palLog(nullptr, " Descriptor indexing"); + + PalDescriptorIndexingCapabilities tmp; + result = palQueryDescriptorIndexingCapabilities(device, &tmp); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get descriptor indexing capabilities: %s", error); + return false; + } + + if (tmp.bindlessSampledImages) { + palLog(nullptr, " Bindless sampled images: True"); + } else { + palLog(nullptr, " Bindless sampled images: False"); + } + + if (tmp.bindlessStorageImages) { + palLog(nullptr, " Bindless storage images: True"); + } else { + palLog(nullptr, " Bindless storage images: False"); + } + + if (tmp.bindlessSamplers) { + palLog(nullptr, " Bindless samplers: True"); + } else { + palLog(nullptr, " Bindless samplers: False"); + } + + if (tmp.bindlessStorageBuffers) { + palLog(nullptr, " Bindless storage buffers: True"); + } else { + palLog(nullptr, " Bindless storage buffers: False"); + } + + if (tmp.bindlessUniformBuffers) { + palLog(nullptr, " Bindless uniform buffers: True"); + } else { + palLog(nullptr, " Bindless uniform buffers: False"); + } + + // clang-format off + palLog(nullptr, " Max per stage bindless descriptor sampled images: %d", tmp.maxPerStageBindlessDescriptorSampledImages); + palLog(nullptr, " Max descriptor set bindless sampled images: %d", tmp.maxDescriptorSetBindlessSampledImages); + palLog(nullptr, " Max per stage binding descriptor storage images: %d", tmp.maxPerStageBindlessDescriptorStorageImages); + palLog(nullptr, " Max descriptor set bindless storage images: %d", tmp.maxDescriptorSetBindlessStorageImages); + + palLog(nullptr, " Max per stage binding descriptor samplers: %d", tmp.maxPerStageBindlessDescriptorSamplers); + palLog(nullptr, " Max descriptor set bindless samplers: %d", tmp.maxDescriptorSetBindlessSamplers); + palLog(nullptr, " Max per stage binding descriptor storage buffers: %d", tmp.maxPerStageBindlessDescriptorStorageBuffers); + palLog(nullptr, " Max descriptor set bindless storage buffers: %d", tmp.maxDescriptorSetBindlessStorageBuffers); + + palLog(nullptr, " Max per stage binding descriptor uniform buffers: %d", tmp.maxPerStageBindlessDescriptorUniformBuffers); + palLog(nullptr, " Max descriptor set bindless uniform buffers: %d", tmp.maxDescriptorSetBindlessUniformBuffers); + // clang-format on + + palLog(nullptr, ""); } if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { @@ -251,6 +521,17 @@ bool graphicsTest() if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { palLog(nullptr, " Multiview"); + + PalMultiViewCapabilities tmp; + result = palQueryMultiViewCapabilities(device, &tmp); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get multi view capabilities: %s", error); + return false; + } + + palLog(nullptr, " Max multi views: %d", tmp.maxMultiViews); + palLog(nullptr, ""); } if (features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY) { @@ -291,6 +572,56 @@ bool graphicsTest() if (features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE) { palLog(nullptr, " Depth stencil resolve"); + + PalDepthStencilCapabilities tmp; + result = palQueryDepthStencilCapabilities(device, &tmp); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get depth stencil capabilities: %s", error); + return false; + } + + if (tmp.independentDepthStencilResolve) { + palLog(nullptr, " Independent depth stencil resource: True"); + } else { + palLog(nullptr, " Independent depth stencil resource: False"); + } + + palLog(nullptr, " Supported Depth Resolve Modes:"); + if (tmp.depthResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO]) { + palLog(nullptr, " Zero"); + } + + if (tmp.depthResolveModes[PAL_RESOLVE_MODE_AVERAGE]) { + palLog(nullptr, " Average"); + } + + if (tmp.depthResolveModes[PAL_RESOLVE_MODE_MIN]) { + palLog(nullptr, " Min"); + } + + if (tmp.depthResolveModes[PAL_RESOLVE_MODE_MAX]) { + palLog(nullptr, " Max"); + } + + palLog(nullptr, " Supported Stencil Resolve Modes:"); + if (tmp.stencilResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO]) { + palLog(nullptr, " Zero"); + } + + if (tmp.stencilResolveModes[PAL_RESOLVE_MODE_AVERAGE]) { + palLog(nullptr, " Average"); + } + + if (tmp.stencilResolveModes[PAL_RESOLVE_MODE_MIN]) { + palLog(nullptr, " Min"); + } + + if (tmp.stencilResolveModes[PAL_RESOLVE_MODE_MAX]) { + palLog(nullptr, " Max"); + } + + palLog(nullptr, ""); } if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { @@ -322,6 +653,7 @@ bool graphicsTest() } palLog(nullptr, ""); + palDestroyDevice(device); } // shutdown the graphics system diff --git a/tests/tests.h b/tests/tests.h index 71c07f88..d0a92c02 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -61,6 +61,5 @@ bool clearColorTest(); bool triangleTest(); bool meshTest(); bool textureTest(); -bool descriptorIndexingTest(); #endif // _TESTS_H diff --git a/tests/tests.lua b/tests/tests.lua index d9db65a6..c84fe701 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -80,8 +80,7 @@ project "tests" "graphics/clear_color_test.c", "graphics/triangle_test.c", "graphics/mesh_test.c", - "graphics/texture_test.c", - "graphics/descriptor_indexing_test.c" + "graphics/texture_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index adbf959e..836bf2de 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,7 +57,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest, "Graphics Test"); + registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS @@ -67,7 +67,6 @@ int main(int argc, char** argv) // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); - registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From c4b57cfcd8dd94e88f09ecc8c2d3d4c6c1748c6e Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 7 May 2026 13:04:37 +0000 Subject: [PATCH 197/372] remove PAL_LIMIT_UNKNOWN sentinel --- include/pal/pal_graphics.h | 58 +-------- src/graphics/pal_d3d12.c | 213 ++++++++++++++++++++------------- src/graphics/pal_graphics.c | 25 ++-- src/graphics/pal_vulkan.c | 8 +- tests/graphics/graphics_test.c | 148 ++++++++++++----------- 5 files changed, 223 insertions(+), 229 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 4676dc56..867bf500 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -33,13 +33,6 @@ freely, subject to the following restrictions: #include "pal_core.h" -/** - * @brief Value for indicating an unknown limit. - * @since 1.4 - * @ingroup pal_graphics - */ -#define PAL_LIMIT_UNKNOWN UINT32_MAX - /** * @brief The maximum name size of an adapter (GPU). * @since 1.4 @@ -1460,9 +1453,6 @@ typedef struct { /** * @struct PalAdapterCapabilities * @brief Capabilities of an adapter (GPU). - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * @since 1.4 * @ingroup pal_graphics @@ -1502,9 +1492,6 @@ typedef struct { /** * @struct PalSamplerAnisotropyCapabilities * @brief Sampler anisotropy capabilities of an adapter (GPU). - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * @since 1.4 * @ingroup pal_graphics @@ -1539,9 +1526,6 @@ typedef struct { * @struct PalDepthStencilCapabilities * @brief Depth stencil capabilities of an adapter (GPU). * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. - * * @since 1.4 * @ingroup pal_graphics */ @@ -1561,9 +1545,6 @@ typedef struct { /** * @struct PalFragmentShadingRateCapabilities * @brief Fragment shading rate capabilities of an adapter (GPU). - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * @since 1.4 * @ingroup pal_graphics @@ -1585,9 +1566,6 @@ typedef struct { /** * @struct PalMeshShaderCapabilities * @brief Mesh shader capabilities of an adapter (GPU). - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * @since 1.4 * @ingroup pal_graphics @@ -1604,9 +1582,6 @@ typedef struct { /** * @struct PalRayTracingCapabilities * @brief Ray tracing capabilities of an adapter (GPU). - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * @since 1.4 * @ingroup pal_graphics @@ -1619,14 +1594,13 @@ typedef struct { Uint32 maxGeometryCount; Uint32 maxPayloadSize; /**< Max memory per ray.*/ Uint32 maxDispatchInvocations; + Uint32 maxDescriptorSetAccelerationStructures; + Uint32 maxDescriptorSetBindlessAccelerationStructures; } PalRayTracingCapabilities; /** * @struct PalDescriptorIndexingCapabilities * @brief Descriptor indexing capabilities of an adapter (GPU). - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. Bindless images are always supported if Descriptor indexing is supported. * * @since 1.4 * @ingroup pal_graphics @@ -1652,9 +1626,6 @@ typedef struct { /** * @struct PalSurfaceCapabilities * @brief surface capabilities of an adapter (GPU). - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * @since 1.4 * @ingroup pal_graphics @@ -2304,7 +2275,6 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool readOnly; /**< For PAL_DESCRIPTOR_TYPE_STORAGE.*/ Uint32 size; Uint32 stride; /**< For structured buffers. Will be ignored if not supported. 0 for default.*/ Uint64 offset; /**< Offset in bytes. If structured, will be divided by `stride`.*/ @@ -4181,9 +4151,6 @@ PAL_API PalResult PAL_CALL palGetAdapterInfo( * @brief Get capabilites or limits about an adapter (GPU). * * The graphics system must be initialized before this call. - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * @param[in] adapter Adapter to query capabilities on. * @param[out] caps Pointer to a PalAdapterCapabilities to fill. @@ -4359,9 +4326,6 @@ PAL_API void PAL_CALL palFreeMemory( * @brief Get sampler anisotropy feature capabilites or limits about a device. * * The graphics system must be initialized before this call. - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * `PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4431,9 +4395,6 @@ PAL_API PalResult PAL_CALL palQueryMultiViewportCapabilities( * @brief Get depth stencil feature capabilites or limits about a device. * * The graphics system must be initialized before this call. - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * `PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4457,9 +4418,6 @@ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( * @brief Get fragment shading rate feature capabilites or limits about a device. * * The graphics system must be initialized before this call. - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4483,9 +4441,6 @@ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( * @brief Get mesh shader feature capabilites or limits about a device. * * The graphics system must be initialized before this call. - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4509,9 +4464,6 @@ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( * @brief Get ray tracing feature capabilites or limits about a device. * * The graphics system must be initialized before this call. - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -4535,9 +4487,6 @@ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( * @brief Get descriptor indexing feature capabilites or limits about a device. * * The graphics system must be initialized before this call. - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. @@ -5050,9 +4999,6 @@ PAL_API void PAL_CALL palDestroySurface(PalSurface* surface); * @brief Get surface capabilites about a device. * * The graphics system must be initialized before this call. - * - * If a limit is not defined or exposed by a backend, `PAL_LIMIT_UNKNOWN` value will be set as the - * value. * * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 5a61ecd4..af9fe5fc 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2174,9 +2174,21 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapter* adapter, PalAdapterCapabilities* caps) { - caps->maxComputeQueues = PAL_LIMIT_UNKNOWN; - caps->maxGraphicsQueues = PAL_LIMIT_UNKNOWN; - caps->maxCopyQueues = PAL_LIMIT_UNKNOWN; + Adapter* d3dAdapter = (Adapter*)adapter; + IDXGIAdapter4* adapterHandle = d3dAdapter->handle; + ID3D12Device* device = d3dAdapter->tmpDevice; + D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; + options.ResourceBindingTier = D3D12_RESOURCE_BINDING_TIER_1; // If call fails + + device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS, + &options, + sizeof(options)); + + caps->maxComputeQueues = 2; // safe default + caps->maxGraphicsQueues = 2; // safe default + caps->maxCopyQueues = 2; // safe default caps->maxImageWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; caps->maxImageHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; @@ -2199,21 +2211,49 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( caps->maxImageMipLevels = levels; caps->maxColorAttachments = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; - caps->maxViewports = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - caps->maxSamplers = D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE; - - caps->maxMultiViews = D3D12_MAX_VIEW_INSTANCE_COUNT; - if (caps->maxMultiViews == 0) { - caps->maxMultiViews = 1; - } - caps->maxUniformBufferSize = D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT * 16; - caps->maxStorageBufferSize = PAL_LIMIT_UNKNOWN; - caps->maxPushConstantSize = (D3D12_MAX_ROOT_COST - 2) * 4; - caps->maxVertexLayouts = PAL_LIMIT_UNKNOWN; - caps->maxVertexAttributes = PAL_LIMIT_UNKNOWN; + caps->maxStorageBufferSize = 2147483648; // 2 GIB + caps->maxPushConstantSize = 256; + + caps->maxVertexLayouts = 32; // safe + caps->maxVertexAttributes = 32; // safe caps->maxTessellationPatchPoint = 32; + caps->maxBoundDescriptorSets = 4; + if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) { + // safe defaults + // Reserve 4 slots per set for TLAS from SRV + caps->maxPerStageDescriptorSampledImages = 112; + caps->maxDescriptorSetSampledImages = 28; + caps->maxPerStageDescriptorStorageImages = 4; + caps->maxDescriptorSetStorageImages = 1; + + caps->maxPerStageDescriptorSamplers = 16; + caps->maxDescriptorSetSamplers = 4; + caps->maxPerStageDescriptorStorageBuffers = 4; + caps->maxDescriptorSetStorageBuffers = 1; + + caps->maxPerStageDescriptorUniformBuffers = 12; + caps->maxDescriptorSetUniformBuffers = 3; + caps->maxBoundDescriptorSets = 4; + + } else { + // safe defaults + // Reserve 16 slots per set for TLAS from SRV + caps->maxPerStageDescriptorSampledImages = 960; + caps->maxDescriptorSetSampledImages = 240; + caps->maxPerStageDescriptorStorageImages = 32; + caps->maxDescriptorSetStorageImages = 8; + + caps->maxPerStageDescriptorSamplers = 2048; + caps->maxDescriptorSetSamplers = 512; + caps->maxPerStageDescriptorStorageBuffers = 32; + caps->maxDescriptorSetStorageBuffers = 8; + + caps->maxPerStageDescriptorUniformBuffers = 12; + caps->maxDescriptorSetUniformBuffers = 3; + } + caps->maxComputeWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; caps->maxComputeWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; caps->maxComputeWorkGroupCount[1] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; @@ -2332,7 +2372,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) // this features are supported on d3d12 features |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; - features |= PAL_ADAPTER_FEATURE_COMPUTE_SHADER; features |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; features |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; @@ -2864,6 +2903,32 @@ PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( + PalDevice* device, + PalMultiViewCapabilities* caps) +{ + Device* d3dDevice = (Device*)device; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + caps->maxMultiViews = D3D12_MAX_VIEW_INSTANCE_COUNT; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( + PalDevice* device, + PalMultiViewportCapabilities* caps) +{ + Device* d3dDevice = (Device*)device; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + caps->maxViewports = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + return PAL_RESULT_SUCCESS; +} + PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( PalDevice* device, PalDepthStencilCapabilities* caps) @@ -2970,15 +3035,17 @@ PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // these are only limited by memory. D3d12 does not expose them - caps->maxRecursionDepth = 32; // 32 - 1; - caps->maxHitAttributeSize = PAL_LIMIT_UNKNOWN; - caps->maxInstanceCount = PAL_LIMIT_UNKNOWN; - caps->maxPrimitiveCount = PAL_LIMIT_UNKNOWN; - caps->maxGeometryCount = PAL_LIMIT_UNKNOWN; - caps->maxPayloadSize = PAL_LIMIT_UNKNOWN; - caps->maxDispatchInvocations = PAL_LIMIT_UNKNOWN; + // these are safe defaults. D3d12 does not expose them. + caps->maxRecursionDepth = 31; + caps->maxHitAttributeSize = 32; + caps->maxInstanceCount = 1000000; + caps->maxPrimitiveCount = 10000000; + caps->maxGeometryCount = 100000; + caps->maxPayloadSize = 64; + caps->maxDispatchInvocations = 16000000; + caps->maxDescriptorSetAccelerationStructures = 4; + caps->maxDescriptorSetBindlessAccelerationStructures = 16; return PAL_RESULT_SUCCESS; } @@ -2992,20 +3059,26 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( } // these are supported if descriptor indexing is + caps->bindlessSampledImages = true; + caps->bindlessStorageImages = true; + caps->bindlessSamplers = true; caps->bindlessStorageBuffers = true; caps->bindlessUniformBuffers = true; - caps->bindlessSamplers = true; - // these are not exposed by d3d12. We use the offical resource binding spec - caps->maxImagesPerShaderStage = PAL_LIMIT_UNKNOWN; - caps->maxImagesPerDescriptorSet = PAL_LIMIT_UNKNOWN; - caps->maxSamplersPerShaderStage = 2048; - caps->maxSamplersPerDescriptorSet = PAL_LIMIT_UNKNOWN; - caps->maxStorageBuffersPerShaderStage = PAL_LIMIT_UNKNOWN; - caps->maxUniformBuffersPerShaderStage = PAL_LIMIT_UNKNOWN; - caps->maxStorageBuffersPerDescriptorSet = PAL_LIMIT_UNKNOWN; - caps->maxUniformBuffersPerDescriptorSet = PAL_LIMIT_UNKNOWN; - caps->maxDescriptors = PAL_LIMIT_UNKNOWN; + // safe defaults + // Reserve 16 slots per set for TLAS from SRV + caps->maxPerStageBindlessDescriptorSampledImages = 960; + caps->maxDescriptorSetBindlessSampledImages = 240; + caps->maxPerStageBindlessDescriptorStorageImages = 32; + caps->maxDescriptorSetBindlessStorageImages = 8; + + caps->maxPerStageBindlessDescriptorSamplers = 2048; + caps->maxDescriptorSetBindlessSamplers = 512; + caps->maxPerStageBindlessDescriptorStorageBuffers = 32; + caps->maxDescriptorSetBindlessStorageBuffers = 8; + + caps->maxPerStageBindlessDescriptorUniformBuffers = 12; + caps->maxDescriptorSetBindlessUniformBuffers = 3; return PAL_RESULT_SUCCESS; } @@ -3742,11 +3815,11 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = false; caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = false; - caps->maxImageCount = PAL_LIMIT_UNKNOWN; + caps->maxImageCount = 8; // safe default caps->minImageWidth = 1; caps->minImageHeight = 1; - caps->maxImageWidth = PAL_LIMIT_UNKNOWN; - caps->maxImageHeight = PAL_LIMIT_UNKNOWN; + caps->maxImageWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + caps->maxImageHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; caps->maxImageArrayLayers = 1; // check support for the base format @@ -5704,10 +5777,6 @@ PalResult PAL_CALL cmdDispatchIndirectD3D12( { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_COMPUTE_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6803,51 +6872,27 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } else { // storage buffer Buffer* buffer = (Buffer*)info->bufferInfo->buffer; - if (info->bufferInfo->readOnly) { - D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; - desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - - Uint32 stride = 4; - if (info->bufferInfo->stride) { - stride = info->bufferInfo->stride; - desc.Buffer.StructureByteStride = info->bufferInfo->stride; - } else { - desc.Format = DXGI_FORMAT_R32_TYPELESS; - desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; - } - - desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - desc.Buffer.FirstElement = info->bufferInfo->offset / stride; - desc.Buffer.NumElements = info->bufferInfo->size / stride; - - d3dDevice->handle->lpVtbl->CreateShaderResourceView( - d3dDevice->handle, - buffer->handle, - &desc, - dst); - + + D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; + Uint32 stride = 4; + if (info->bufferInfo->stride) { + stride = info->bufferInfo->stride; + desc.Buffer.StructureByteStride = info->bufferInfo->stride; } else { - D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; - Uint32 stride = 4; - if (info->bufferInfo->stride) { - stride = info->bufferInfo->stride; - desc.Buffer.StructureByteStride = info->bufferInfo->stride; - } else { - desc.Format = DXGI_FORMAT_R32_TYPELESS; - desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; - } + desc.Format = DXGI_FORMAT_R32_TYPELESS; + desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; + } - desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - desc.Buffer.FirstElement = info->bufferInfo->offset / stride; - desc.Buffer.NumElements = info->bufferInfo->size / stride; + desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + desc.Buffer.FirstElement = info->bufferInfo->offset / stride; + desc.Buffer.NumElements = info->bufferInfo->size / stride; - d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( - d3dDevice->handle, - buffer->handle, - nullptr, - &desc, - dst); - } + d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( + d3dDevice->handle, + buffer->handle, + nullptr, + &desc, + dst); } } } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 15ce4e0d..0a4c9acf 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -1044,7 +1044,6 @@ PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( PalDevice* device, PalSamplerAnisotropyCapabilities* caps); -// TODO: PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( PalDevice* device, PalMultiViewCapabilities* caps); @@ -1685,6 +1684,8 @@ static PalGraphicsBackend s_D3D12Backend = { // extended adapter features .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesD3D12, + .queryMultiViewCapabilities = queryMultiViewCapabilitiesD3D12, + .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesD3D12, .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesD3D12, .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesD3D12, .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesD3D12, @@ -2081,16 +2082,15 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - // TODO: uncomment - // result = initGraphicsVk(debugger, allocator); - // if (result != PAL_RESULT_SUCCESS) { - // return result; - // } - - // attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - // attachedBackend->base = &s_VkBackend; - // attachedBackend->startIndex = 0; - // attachedBackend->count = 0; + result = initGraphicsVk(debugger, allocator); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + attachedBackend->base = &s_VkBackend; + attachedBackend->startIndex = 0; + attachedBackend->count = 0; #endif // PAL_HAS_VULKAN // D3D12 @@ -2137,8 +2137,7 @@ void PAL_CALL palShutdownGraphics() #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - // TODO: uncomment block - // shutdownGraphicsVk(); + shutdownGraphicsVk(); #endif // PAL_HAS_VULKAN // D3D12 diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 0ee86e80..6852ac5d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -4895,6 +4895,10 @@ PalResult PAL_CALL queryRayTracingCapabilitiesVk( caps->maxPayloadSize = 64; // safe caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; + caps->maxDescriptorSetAccelerationStructures = accProps.maxDescriptorSetAccelerationStructures; + caps->maxDescriptorSetBindlessAccelerationStructures = + accProps.maxDescriptorSetUpdateAfterBindAccelerationStructures; + return PAL_RESULT_SUCCESS; } @@ -4947,13 +4951,11 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( // clang-format off caps->maxPerStageBindlessDescriptorSampledImages = props.maxPerStageDescriptorUpdateAfterBindSampledImages; caps->maxDescriptorSetBindlessSampledImages = props.maxDescriptorSetUpdateAfterBindSampledImages; - caps->maxPerStageBindlessDescriptorStorageImages = props.maxPerStageDescriptorUpdateAfterBindStorageImages; caps->maxDescriptorSetBindlessStorageImages = props.maxDescriptorSetUpdateAfterBindStorageImages; caps->maxPerStageBindlessDescriptorSamplers = props.maxPerStageDescriptorUpdateAfterBindSamplers; caps->maxDescriptorSetBindlessSamplers = props.maxDescriptorSetUpdateAfterBindSamplers; - caps->maxPerStageBindlessDescriptorStorageBuffers = props.maxPerStageDescriptorUpdateAfterBindStorageBuffers; caps->maxDescriptorSetBindlessStorageBuffers = props.maxDescriptorSetUpdateAfterBindStorageBuffers; @@ -5653,7 +5655,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesVk( caps->maxImageArrayLayers = surfaceCaps.maxImageArrayLayers; if (caps->maxImageCount == 0) { - caps->maxImageCount = INT32_MAX; + caps->maxImageCount = 8; // safe } // get supported composite alphas diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 06541186..fdd344c0 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -79,7 +79,7 @@ bool graphicsTest() palLog(nullptr, "No adapters found"); return false; } - palLog(nullptr, "Adapter count: %d", count); + palLog(nullptr, "Adapter count: %u", count); // allocate an array of adapters or use a fixed array // Example: PalAdapter* adapters[12]; @@ -160,10 +160,10 @@ bool graphicsTest() palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Backend Name: %s", info.backendName); - palLog(nullptr, " Vendor Id: %d", info.vendorId); - palLog(nullptr, " Device Id: %d", info.deviceId); - palLog(nullptr, " Vram %dMB", vramMb); - palLog(nullptr, " Shared Memory %dMB", sharedMemMb); + palLog(nullptr, " Vendor Id: %u", info.vendorId); + palLog(nullptr, " Device Id: %u", info.deviceId); + palLog(nullptr, " Vram %u MB", vramMb); + palLog(nullptr, " Shared Memory %u MB", sharedMemMb); const char* typeString; switch (info.type) { @@ -210,48 +210,48 @@ bool graphicsTest() palLog(nullptr, ""); palLog(nullptr, " Capabilities:"); - palLog(nullptr, " Max compute queue: %d", caps.maxComputeQueues); - palLog(nullptr, " Max graphics queue: %d", caps.maxGraphicsQueues); - palLog(nullptr, " Max copy queue: %d", caps.maxCopyQueues); + palLog(nullptr, " Max compute queue: %u", caps.maxComputeQueues); + palLog(nullptr, " Max graphics queue: %u", caps.maxGraphicsQueues); + palLog(nullptr, " Max copy queue: %u", caps.maxCopyQueues); - palLog(nullptr, " Max image width: %d", caps.maxImageWidth); - palLog(nullptr, " Max image height: %d", caps.maxImageHeight); - palLog(nullptr, " Max image depth: %d", caps.maxImageDepth); - palLog(nullptr, " Max image array layers: %d", caps.maxImageArrayLayers); - palLog(nullptr, " Max image mip levels: %d", caps.maxImageMipLevels); + palLog(nullptr, " Max image width: %u", caps.maxImageWidth); + palLog(nullptr, " Max image height: %u", caps.maxImageHeight); + palLog(nullptr, " Max image depth: %u", caps.maxImageDepth); + palLog(nullptr, " Max image array layers: %u", caps.maxImageArrayLayers); + palLog(nullptr, " Max image mip levels: %u", caps.maxImageMipLevels); - palLog(nullptr, " Max color attachments: %d", caps.maxColorAttachments); - palLog(nullptr, " Max uniform buffer size: %d Bytes", caps.maxUniformBufferSize); - palLog(nullptr, " Max storage buffer size: %d Bytes", caps.maxStorageBufferSize); - palLog(nullptr, " Max push constant size: %d Bytes", caps.maxPushConstantSize); + palLog(nullptr, " Max color attachments: %u", caps.maxColorAttachments); + palLog(nullptr, " Max uniform buffer size: %u Bytes", caps.maxUniformBufferSize); + palLog(nullptr, " Max storage buffer size: %u Bytes", caps.maxStorageBufferSize); + palLog(nullptr, " Max push constant size: %u Bytes", caps.maxPushConstantSize); - palLog(nullptr, " Max vertex layouts: %d", caps.maxVertexLayouts); - palLog(nullptr, " Max vertex attributes: %d", caps.maxVertexAttributes); - palLog(nullptr, " Max tessellation patch point: %d", caps.maxTessellationPatchPoint); + palLog(nullptr, " Max vertex layouts: %u", caps.maxVertexLayouts); + palLog(nullptr, " Max vertex attributes: %u", caps.maxVertexAttributes); + palLog(nullptr, " Max tessellation patch point: %u", caps.maxTessellationPatchPoint); // clang-format off - palLog(nullptr, " Max per stage descriptor sampled images: %d", caps.maxPerStageDescriptorSampledImages); - palLog(nullptr, " Max descriptor set sampled images: %d", caps.maxDescriptorSetSampledImages); - palLog(nullptr, " Max per stage descriptor storage images: %d", caps.maxPerStageDescriptorStorageImages); - palLog(nullptr, " Max descriptor set storage images: %d", caps.maxDescriptorSetStorageImages); + palLog(nullptr, " Max per stage descriptor sampled images: %u", caps.maxPerStageDescriptorSampledImages); + palLog(nullptr, " Max descriptor set sampled images: %u", caps.maxDescriptorSetSampledImages); + palLog(nullptr, " Max per stage descriptor storage images: %u", caps.maxPerStageDescriptorStorageImages); + palLog(nullptr, " Max descriptor set storage images: %u", caps.maxDescriptorSetStorageImages); - palLog(nullptr, " Max per stage descriptor samplers: %d", caps.maxPerStageDescriptorSamplers); - palLog(nullptr, " Max descriptor set samplers: %d", caps.maxDescriptorSetSamplers); - palLog(nullptr, " Max per stage descriptor storage buffers: %d", caps.maxPerStageDescriptorStorageBuffers); - palLog(nullptr, " Max descriptor set storage buffers: %d", caps.maxDescriptorSetStorageBuffers); - - palLog(nullptr, " Max per stage descriptor uniform buffers: %d", caps.maxPerStageDescriptorUniformBuffers); - palLog(nullptr, " Max descriptor set uniform buffers: %d", caps.maxDescriptorSetUniformBuffers); - palLog(nullptr, " Max bound descriptor sets: %d", caps.maxBoundDescriptorSets); + palLog(nullptr, " Max per stage descriptor samplers: %u", caps.maxPerStageDescriptorSamplers); + palLog(nullptr, " Max descriptor set samplers: %u", caps.maxDescriptorSetSamplers); + palLog(nullptr, " Max per stage descriptor storage buffers: %u", caps.maxPerStageDescriptorStorageBuffers); + palLog(nullptr, " Max descriptor set storage buffers: %u", caps.maxDescriptorSetStorageBuffers); + + palLog(nullptr, " Max per stage descriptor uniform buffers: %u", caps.maxPerStageDescriptorUniformBuffers); + palLog(nullptr, " Max descriptor set uniform buffers: %u", caps.maxDescriptorSetUniformBuffers); + palLog(nullptr, " Max bound descriptor sets: %u", caps.maxBoundDescriptorSets); // clang-format on - palLog(nullptr, " Max compute invocations: %d", caps.maxComputeWorkGroupInvocations); - palLog(nullptr, " Max compute work group count[0]: %d", caps.maxComputeWorkGroupCount[0]); - palLog(nullptr, " Max compute work group count[1]: %d", caps.maxComputeWorkGroupCount[1]); - palLog(nullptr, " Max compute work group count[2]: %d", caps.maxComputeWorkGroupCount[2]); - palLog(nullptr, " Max compute work group size[0]: %d", caps.maxComputeWorkGroupSize[0]); - palLog(nullptr, " Max compute work group size[1]: %d", caps.maxComputeWorkGroupSize[1]); - palLog(nullptr, " Max compute work group size[2]: %d", caps.maxComputeWorkGroupSize[2]); + palLog(nullptr, " Max compute invocations: %u", caps.maxComputeWorkGroupInvocations); + palLog(nullptr, " Max compute work group count[0]: %u", caps.maxComputeWorkGroupCount[0]); + palLog(nullptr, " Max compute work group count[1]: %u", caps.maxComputeWorkGroupCount[1]); + palLog(nullptr, " Max compute work group count[2]: %u", caps.maxComputeWorkGroupCount[2]); + palLog(nullptr, " Max compute work group size[0]: %u", caps.maxComputeWorkGroupSize[0]); + palLog(nullptr, " Max compute work group size[1]: %u", caps.maxComputeWorkGroupSize[1]); + palLog(nullptr, " Max compute work group size[2]: %u", caps.maxComputeWorkGroupSize[2]); // shader formats PalShaderTarget target; @@ -285,7 +285,7 @@ bool graphicsTest() return false; } - palLog(nullptr, " Max anisotropy: %d", tmp.maxAnisotropy); + palLog(nullptr, " Max anisotropy: %u", tmp.maxAnisotropy); palLog(nullptr, ""); } @@ -305,7 +305,7 @@ bool graphicsTest() return false; } - palLog(nullptr, " Max viewports: %d", tmp.maxViewports); + palLog(nullptr, " Max viewports: %u", tmp.maxViewports); palLog(nullptr, ""); } @@ -349,13 +349,15 @@ bool graphicsTest() return false; } - palLog(nullptr, " Max recursion depth: %d", tmp.maxRecursionDepth); - palLog(nullptr, " Max hit attribute size: %d Bytes", tmp.maxHitAttributeSize); - palLog(nullptr, " Max instance count: %d", tmp.maxInstanceCount); - palLog(nullptr, " Max primitive count: %d", tmp.maxPrimitiveCount); - palLog(nullptr, " Max geometry count: %d", tmp.maxGeometryCount); - palLog(nullptr, " Max payload size: %d Bytes", tmp.maxPayloadSize); - palLog(nullptr, " Max dispatch invocations: %d", tmp.maxDispatchInvocations); + palLog(nullptr, " Max recursion depth: %u", tmp.maxRecursionDepth); + palLog(nullptr, " Max hit attribute size: %u Bytes", tmp.maxHitAttributeSize); + palLog(nullptr, " Max instance count: %u", tmp.maxInstanceCount); + palLog(nullptr, " Max primitive count: %u", tmp.maxPrimitiveCount); + palLog(nullptr, " Max geometry count: %u", tmp.maxGeometryCount); + palLog(nullptr, " Max payload size: %u Bytes", tmp.maxPayloadSize); + palLog(nullptr, " Max dispatch invocations: %u", tmp.maxDispatchInvocations); + palLog(nullptr, " Max descriptor set acceleration structures: %u", tmp.maxDescriptorSetAccelerationStructures); + palLog(nullptr, " Max descriptor set bindless acceleration structure: %u", tmp.maxDescriptorSetBindlessAccelerationStructures); palLog(nullptr, ""); } @@ -371,17 +373,17 @@ bool graphicsTest() return false; } - palLog(nullptr, " Max mesh output primitives: %d", tmp.maxMeshOutputPrimitives); - palLog(nullptr, " Max mesh output vertices: %d", tmp.maxMeshOutputVertices); - palLog(nullptr, " Max mesh invocations: %d", tmp.maxMeshWorkGroupInvocations); - palLog(nullptr, " Max task invocations: %d", tmp.maxTaskWorkGroupInvocations); + palLog(nullptr, " Max mesh output primitives: %u", tmp.maxMeshOutputPrimitives); + palLog(nullptr, " Max mesh output vertices: %u", tmp.maxMeshOutputVertices); + palLog(nullptr, " Max mesh invocations: %u", tmp.maxMeshWorkGroupInvocations); + palLog(nullptr, " Max task invocations: %u", tmp.maxTaskWorkGroupInvocations); - palLog(nullptr, " Max mesh work group count[0]: %d", tmp.maxMeshWorkGroupCount[0]); - palLog(nullptr, " Max mesh work group count[1]: %d", tmp.maxMeshWorkGroupCount[1]); - palLog(nullptr, " Max mesh work group count[2]: %d", tmp.maxMeshWorkGroupCount[2]); - palLog(nullptr, " Max task work group count[0]: %d", tmp.maxTaskWorkGroupCount[0]); - palLog(nullptr, " Max task work group count[1]: %d", tmp.maxTaskWorkGroupCount[1]); - palLog(nullptr, " Max task work group count[2]: %d", tmp.maxTaskWorkGroupCount[2]); + palLog(nullptr, " Max mesh work group count[0]: %u", tmp.maxMeshWorkGroupCount[0]); + palLog(nullptr, " Max mesh work group count[1]: %u", tmp.maxMeshWorkGroupCount[1]); + palLog(nullptr, " Max mesh work group count[2]: %u", tmp.maxMeshWorkGroupCount[2]); + palLog(nullptr, " Max task work group count[0]: %u", tmp.maxTaskWorkGroupCount[0]); + palLog(nullptr, " Max task work group count[1]: %u", tmp.maxTaskWorkGroupCount[1]); + palLog(nullptr, " Max task work group count[2]: %u", tmp.maxTaskWorkGroupCount[2]); palLog(nullptr, ""); } @@ -397,10 +399,10 @@ bool graphicsTest() return false; } - palLog(nullptr, " Min texel width: %d", tmp.minTexelWidth); - palLog(nullptr, " Min texel height: %d", tmp.maxTexelWidth); - palLog(nullptr, " Max texel width: %d", tmp.minTexelHeight); - palLog(nullptr, " Max texel height: %d", tmp.maxTexelHeight); + palLog(nullptr, " Min texel width: %u", tmp.minTexelWidth); + palLog(nullptr, " Min texel height: %u", tmp.maxTexelWidth); + palLog(nullptr, " Max texel width: %u", tmp.minTexelHeight); + palLog(nullptr, " Max texel height: %u", tmp.maxTexelHeight); palLog(nullptr, " Support Shading Rates:"); if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_1X1]) { @@ -498,18 +500,18 @@ bool graphicsTest() } // clang-format off - palLog(nullptr, " Max per stage bindless descriptor sampled images: %d", tmp.maxPerStageBindlessDescriptorSampledImages); - palLog(nullptr, " Max descriptor set bindless sampled images: %d", tmp.maxDescriptorSetBindlessSampledImages); - palLog(nullptr, " Max per stage binding descriptor storage images: %d", tmp.maxPerStageBindlessDescriptorStorageImages); - palLog(nullptr, " Max descriptor set bindless storage images: %d", tmp.maxDescriptorSetBindlessStorageImages); + palLog(nullptr, " Max per stage bindless descriptor sampled images: %u", tmp.maxPerStageBindlessDescriptorSampledImages); + palLog(nullptr, " Max descriptor set bindless sampled images: %u", tmp.maxDescriptorSetBindlessSampledImages); + palLog(nullptr, " Max per stage binding descriptor storage images: %u", tmp.maxPerStageBindlessDescriptorStorageImages); + palLog(nullptr, " Max descriptor set bindless storage images: %u", tmp.maxDescriptorSetBindlessStorageImages); - palLog(nullptr, " Max per stage binding descriptor samplers: %d", tmp.maxPerStageBindlessDescriptorSamplers); - palLog(nullptr, " Max descriptor set bindless samplers: %d", tmp.maxDescriptorSetBindlessSamplers); - palLog(nullptr, " Max per stage binding descriptor storage buffers: %d", tmp.maxPerStageBindlessDescriptorStorageBuffers); - palLog(nullptr, " Max descriptor set bindless storage buffers: %d", tmp.maxDescriptorSetBindlessStorageBuffers); + palLog(nullptr, " Max per stage binding descriptor samplers: %u", tmp.maxPerStageBindlessDescriptorSamplers); + palLog(nullptr, " Max descriptor set bindless samplers: %u", tmp.maxDescriptorSetBindlessSamplers); + palLog(nullptr, " Max per stage binding descriptor storage buffers: %u", tmp.maxPerStageBindlessDescriptorStorageBuffers); + palLog(nullptr, " Max descriptor set bindless storage buffers: %u", tmp.maxDescriptorSetBindlessStorageBuffers); - palLog(nullptr, " Max per stage binding descriptor uniform buffers: %d", tmp.maxPerStageBindlessDescriptorUniformBuffers); - palLog(nullptr, " Max descriptor set bindless uniform buffers: %d", tmp.maxDescriptorSetBindlessUniformBuffers); + palLog(nullptr, " Max per stage binding descriptor uniform buffers: %u", tmp.maxPerStageBindlessDescriptorUniformBuffers); + palLog(nullptr, " Max descriptor set bindless uniform buffers: %u", tmp.maxDescriptorSetBindlessUniformBuffers); // clang-format on palLog(nullptr, ""); @@ -530,7 +532,7 @@ bool graphicsTest() return false; } - palLog(nullptr, " Max multi views: %d", tmp.maxMultiViews); + palLog(nullptr, " Max multi views: %u", tmp.maxMultiViews); palLog(nullptr, ""); } From 8de2d9efd4b1974110ec2e694edaa6cdbd1e1b04 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 7 May 2026 18:24:30 +0000 Subject: [PATCH 198/372] remove descriptor API limits vulkan --- include/pal/pal_graphics.h | 18 +++----- src/graphics/pal_vulkan.c | 76 +++++++++++++++++++------------ tests/graphics/compute_test.c | 4 +- tests/graphics/ray_tracing_test.c | 16 +++---- tests/graphics/texture_test.c | 20 ++++---- 5 files changed, 75 insertions(+), 59 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 867bf500..77e0bdce 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2243,7 +2243,6 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool readOnly; /**< For PAL_DESCRIPTOR_TYPE_STORAGE.*/ Uint32 descriptorCount; Uint32 shaderStageCount; PalShaderStage* shaderStages; /**< Array of shader stages that can access the descriptor.*/ @@ -2330,15 +2329,15 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 binding; - Uint32 arrayElement; /**< 0 If not using PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING.*/ - Uint32 descriptorCount; /**< 1 If not using PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING.*/ + Uint32 layoutBindingIndex; /**< Index into the descriptor set layout bindings.*/ + Uint32 arrayElement; + Uint32 descriptorCount; PalDescriptorType descriptorType; PalDescriptorSet* descriptorSet; - PalDescriptorBufferInfo* bufferInfo; /**< If PAL_DESCRIPTOR_TYPE* uniform or storage buffer.*/ - PalDescriptorImageViewInfo* imageViewInfo; /**< If PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE*/ - PalDescriptorSamplerInfo* samplerInfo; /**< If PAL_DESCRIPTOR_TYPE_SAMPLER.*/ - PalDescriptorTLASInfo* tlasInfo; /**< If PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE.*/ + PalDescriptorBufferInfo* bufferInfos; /**< If PAL_DESCRIPTOR_TYPE* uniform or storage buffer.*/ + PalDescriptorImageViewInfo* imageViewInfos; /**< If PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE*/ + PalDescriptorSamplerInfo* samplerInfos; /**< If PAL_DESCRIPTOR_TYPE_SAMPLER.*/ + PalDescriptorTLASInfo* tlasInfos; /**< If PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE.*/ } PalDescriptorSetWriteInfo; /** @@ -7203,9 +7202,6 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( * * The graphics system must be initialized before this call. * - * PalDescriptorSetWriteInfo::descriptorCount must be `1` if not using - * `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` feature for all descriptors. - * * @param[in] device The Device. Must match the one used to allocate descriptor set. * @param[in] count Capacity of the PalDescriptorSetWriteInfo array. * @param[in] infos Array of PalDescriptorSetWriteInfo to write. diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 6852ac5d..e1769ed9 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -8364,17 +8364,11 @@ PalResult PAL_CALL updateDescriptorSetVk( VkDescriptorImageInfo* imageInfos = nullptr; VkWriteDescriptorSetAccelerationStructureKHR* tlasInfos = nullptr; - // TODO: loop over descriptor count Uint32 bufferCount = 0; - Uint32 bufferIndex = 0; Uint32 bufferOffset = 0; - Uint32 imageCount = 0; - Uint32 imageIndex = 0; Uint32 imageOffset = 0; - Uint32 tlasCount = 0; - Uint32 tlasIndex = 0; Uint32 tlasOffset = 0; for (int i = 0; i < count; i++) { @@ -8413,66 +8407,92 @@ PalResult PAL_CALL updateDescriptorSetVk( for (int i = 0; i < count; i++) { VkWriteDescriptorSet* write = &writes[i]; + PalDescriptorSetWriteInfo* info = &info[i]; + write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write->pBufferInfo = nullptr; write->pImageInfo = nullptr; write->pTexelBufferView = nullptr; write->pNext = nullptr; - write->dstArrayElement = infos[i].arrayElement; - write->dstBinding = infos[i].binding; - write->descriptorCount = infos[i].descriptorCount; - write->descriptorType = descriptortypeToVk(infos[i].descriptorType); + write->dstArrayElement = info->arrayElement; + write->dstBinding = info->layoutBindingIndex; + write->descriptorCount = info->descriptorCount; + write->descriptorType = descriptortypeToVk(info->descriptorType); - DescriptorSet* set = (DescriptorSet*)infos[i].descriptorSet; + DescriptorSet* set = (DescriptorSet*)info->descriptorSet; write->dstSet = set->handle; + bool isImage = false; + bool isTlas = false; + bool isBuffer = false; + for (int j = 0; j < write->descriptorCount; j++) { - if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || - infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - VkDescriptorBufferInfo* bufferInfo = &bufferInfos[bufferIndex++]; - Buffer* vkBuffer = (Buffer*)infos[j].bufferInfo->buffer; + if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || + info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + VkDescriptorBufferInfo* bufferInfo = &bufferInfos[bufferOffset + j]; + PalDescriptorBufferInfo* tmp = &info->bufferInfos[j]; + Buffer* vkBuffer = (Buffer*)tmp->buffer; bufferInfo->buffer = vkBuffer->handle; - bufferInfo->offset = infos[i].bufferInfo->offset; - bufferInfo->range = infos[i].bufferInfo->size; - write->pBufferInfo = bufferInfo; + bufferInfo->offset = tmp->offset; + bufferInfo->range = tmp->size; + isBuffer = true; } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - VkWriteDescriptorSetAccelerationStructureKHR* tlasInfo = &tlasInfos[tlasIndex++]; - AccelerationStructure* ac = (AccelerationStructure*)infos[i].tlasInfo->tlas; + VkWriteDescriptorSetAccelerationStructureKHR* tlasInfo = nullptr; + tlasInfo = &tlasInfos[tlasOffset + j]; + PalDescriptorTLASInfo* tmp = &info->tlasInfos[j]; + AccelerationStructure* as = (AccelerationStructure*)tmp->tlas; tlasInfo->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; tlasInfo->accelerationStructureCount = 1; - tlasInfo->pAccelerationStructures = &ac->handle; + tlasInfo->pAccelerationStructures = &as->handle; tlasInfo->pNext = nullptr; - write->pNext = tlasInfo; + isTlas = true; } else { - VkDescriptorImageInfo* imageInfo = &imageInfos[imageIndex++]; + VkDescriptorImageInfo* imageInfo = &imageInfos[imageOffset + j]; + isImage = true; + if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { - Sampler* vkSampler = (Sampler*)infos[i].samplerInfo->sampler; + PalDescriptorSamplerInfo* tmp = &info->samplerInfos[j]; + Sampler* vkSampler = (Sampler*)tmp->sampler; imageInfo->sampler = vkSampler->handle; imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; imageInfo->imageView = nullptr; } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; + PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; + ImageView* vkImageView = (ImageView*)tmp->imageView; imageInfo->sampler = nullptr; imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; imageInfo->imageView = vkImageView->handle; } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - ImageView* vkImageView = (ImageView*)infos[i].imageViewInfo->imageView; + PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; + ImageView* vkImageView = (ImageView*)tmp->imageView; imageInfo->sampler = nullptr; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo->imageView = vkImageView->handle; } - write->pImageInfo = imageInfo; } } + + if (isImage) { + write->pImageInfo = &imageInfos[imageOffset]; + imageOffset += write->descriptorCount; + + } else if (isTlas) { + write->pNext = &tlasInfos[tlasOffset]; + tlasOffset += write->descriptorCount; + + } else if (isBuffer) { + write->pBufferInfo = &bufferInfos[bufferOffset]; + bufferOffset += write->descriptorCount; + } } s_Vk.updateDescriptorSet(vkDevice->handle, count, writes, 0, nullptr); diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index c2dbc66f..d4fb61bb 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -347,8 +347,8 @@ bool computeTest() descriptorBufferInfo.size = bufferBytes; PalDescriptorSetWriteInfo writeInfo = {0}; - writeInfo.binding = 0; - writeInfo.bufferInfo = &descriptorBufferInfo; + writeInfo.layoutBindingIndex = 0; + writeInfo.bufferInfos = &descriptorBufferInfo; writeInfo.descriptorSet = descriptorSet; writeInfo.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; writeInfo.descriptorCount = 1; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 786b7101..254ae80b 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -763,23 +763,23 @@ bool rayTracingTest() descriptorTlasInfo.tlas = tlas; PalDescriptorSetWriteInfo writeInfos[2]; - writeInfos[0].binding = 0; - writeInfos[0].bufferInfo = &descriptorStorageBufferInfo; + writeInfos[0].layoutBindingIndex = 0; + writeInfos[0].bufferInfos = &descriptorStorageBufferInfo; writeInfos[0].descriptorSet = descriptorSet; writeInfos[0].descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; writeInfos[0].descriptorCount = 1; writeInfos[0].arrayElement = 0; - writeInfos[0].imageViewInfo = nullptr; - writeInfos[0].tlasInfo = nullptr; + writeInfos[0].imageViewInfos = nullptr; + writeInfos[0].tlasInfos = nullptr; - writeInfos[1].binding = 1; - writeInfos[1].tlasInfo = &descriptorTlasInfo; + writeInfos[1].layoutBindingIndex = 1; + writeInfos[1].tlasInfos = &descriptorTlasInfo; writeInfos[1].descriptorSet = descriptorSet; writeInfos[1].descriptorType = PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE; writeInfos[1].descriptorCount = 1; writeInfos[1].arrayElement = 0; - writeInfos[1].imageViewInfo = nullptr; - writeInfos[1].bufferInfo = nullptr; + writeInfos[1].imageViewInfos = nullptr; + writeInfos[1].bufferInfos = nullptr; result = palUpdateDescriptorSet(device, 2, writeInfos); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 74111fd8..8cd877e9 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -971,27 +971,27 @@ bool textureTest() descriptorSamplerInfo.sampler = sampler; PalDescriptorSetWriteInfo writeInfos[2]; - writeInfos[0].binding = 0; - writeInfos[0].imageViewInfo = &descriptorImageInfo; + writeInfos[0].layoutBindingIndex = 0; + writeInfos[0].imageViewInfos = &descriptorImageInfo; writeInfos[0].descriptorSet = descriptorSet; writeInfos[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; writeInfos[0].descriptorCount = 1; writeInfos[0].arrayElement = 0; - writeInfos[0].bufferInfo = nullptr; - writeInfos[0].samplerInfo = nullptr; - writeInfos[0].tlasInfo = nullptr; + writeInfos[0].bufferInfos = nullptr; + writeInfos[0].samplerInfos = nullptr; + writeInfos[0].tlasInfos = nullptr; - writeInfos[1].binding = 1; - writeInfos[1].samplerInfo = &descriptorSamplerInfo; + writeInfos[1].layoutBindingIndex = 1; + writeInfos[1].samplerInfos = &descriptorSamplerInfo; writeInfos[1].descriptorSet = descriptorSet; writeInfos[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; writeInfos[1].descriptorCount = 1; writeInfos[1].arrayElement = 0; - writeInfos[1].imageViewInfo = nullptr; - writeInfos[1].tlasInfo = nullptr; - writeInfos[1].bufferInfo = nullptr; + writeInfos[1].imageViewInfos = nullptr; + writeInfos[1].tlasInfos = nullptr; + writeInfos[1].bufferInfos = nullptr; result = palUpdateDescriptorSet(device, 2, writeInfos); if (result != PAL_RESULT_SUCCESS) { From 5fe5fb6f5841d04299afce329cc6a54039e95a04 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 7 May 2026 18:54:57 +0000 Subject: [PATCH 199/372] remove descriptor API limits d3d12 --- src/graphics/pal_d3d12.c | 117 ++++++++++++++------------------------- 1 file changed, 41 insertions(+), 76 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index af9fe5fc..15c5a803 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2174,18 +2174,6 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapter* adapter, PalAdapterCapabilities* caps) { - Adapter* d3dAdapter = (Adapter*)adapter; - IDXGIAdapter4* adapterHandle = d3dAdapter->handle; - ID3D12Device* device = d3dAdapter->tmpDevice; - D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; - options.ResourceBindingTier = D3D12_RESOURCE_BINDING_TIER_1; // If call fails - - device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS, - &options, - sizeof(options)); - caps->maxComputeQueues = 2; // safe default caps->maxGraphicsQueues = 2; // safe default caps->maxCopyQueues = 2; // safe default @@ -2219,40 +2207,20 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( caps->maxVertexAttributes = 32; // safe caps->maxTessellationPatchPoint = 32; - caps->maxBoundDescriptorSets = 4; - if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) { - // safe defaults - // Reserve 4 slots per set for TLAS from SRV - caps->maxPerStageDescriptorSampledImages = 112; - caps->maxDescriptorSetSampledImages = 28; - caps->maxPerStageDescriptorStorageImages = 4; - caps->maxDescriptorSetStorageImages = 1; - - caps->maxPerStageDescriptorSamplers = 16; - caps->maxDescriptorSetSamplers = 4; - caps->maxPerStageDescriptorStorageBuffers = 4; - caps->maxDescriptorSetStorageBuffers = 1; - - caps->maxPerStageDescriptorUniformBuffers = 12; - caps->maxDescriptorSetUniformBuffers = 3; - caps->maxBoundDescriptorSets = 4; - - } else { - // safe defaults - // Reserve 16 slots per set for TLAS from SRV - caps->maxPerStageDescriptorSampledImages = 960; - caps->maxDescriptorSetSampledImages = 240; - caps->maxPerStageDescriptorStorageImages = 32; - caps->maxDescriptorSetStorageImages = 8; + // safe defaults + caps->maxPerStageDescriptorSampledImages = 1024; + caps->maxDescriptorSetSampledImages = 1024; + caps->maxPerStageDescriptorStorageImages = 512; + caps->maxDescriptorSetStorageImages = 512; - caps->maxPerStageDescriptorSamplers = 2048; - caps->maxDescriptorSetSamplers = 512; - caps->maxPerStageDescriptorStorageBuffers = 32; - caps->maxDescriptorSetStorageBuffers = 8; + caps->maxPerStageDescriptorSamplers = 256; + caps->maxDescriptorSetSamplers = 256; + caps->maxPerStageDescriptorStorageBuffers = 512; + caps->maxDescriptorSetStorageBuffers = 512; - caps->maxPerStageDescriptorUniformBuffers = 12; - caps->maxDescriptorSetUniformBuffers = 3; - } + caps->maxPerStageDescriptorUniformBuffers = 256; + caps->maxDescriptorSetUniformBuffers = 256; + caps->maxBoundDescriptorSets = 30; caps->maxComputeWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; caps->maxComputeWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; @@ -3045,7 +3013,7 @@ PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( caps->maxDispatchInvocations = 16000000; caps->maxDescriptorSetAccelerationStructures = 4; - caps->maxDescriptorSetBindlessAccelerationStructures = 16; + caps->maxDescriptorSetBindlessAccelerationStructures = 4; return PAL_RESULT_SUCCESS; } @@ -3066,19 +3034,18 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( caps->bindlessUniformBuffers = true; // safe defaults - // Reserve 16 slots per set for TLAS from SRV - caps->maxPerStageBindlessDescriptorSampledImages = 960; - caps->maxDescriptorSetBindlessSampledImages = 240; - caps->maxPerStageBindlessDescriptorStorageImages = 32; - caps->maxDescriptorSetBindlessStorageImages = 8; + caps->maxPerStageBindlessDescriptorSampledImages = 4096; + caps->maxDescriptorSetBindlessSampledImages = 4096; + caps->maxPerStageBindlessDescriptorStorageImages = 1024; + caps->maxDescriptorSetBindlessStorageImages = 1024; - caps->maxPerStageBindlessDescriptorSamplers = 2048; + caps->maxPerStageBindlessDescriptorSamplers = 512; caps->maxDescriptorSetBindlessSamplers = 512; - caps->maxPerStageBindlessDescriptorStorageBuffers = 32; - caps->maxDescriptorSetBindlessStorageBuffers = 8; + caps->maxPerStageBindlessDescriptorStorageBuffers = 2048; + caps->maxDescriptorSetBindlessStorageBuffers = 2048; - caps->maxPerStageBindlessDescriptorUniformBuffers = 12; - caps->maxDescriptorSetBindlessUniformBuffers = 3; + caps->maxPerStageBindlessDescriptorUniformBuffers = 256; + caps->maxDescriptorSetBindlessUniformBuffers = 256; return PAL_RESULT_SUCCESS; } @@ -6443,13 +6410,8 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( } case PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER: { - if (info->bindings[i].readOnly) { - binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - binding->range.BaseShaderRegister = sampledASIndex++; - } else { - binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - binding->range.BaseShaderRegister = storageIndex++; - } + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + binding->range.BaseShaderRegister = storageIndex++; binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; resourceOffset += info->bindings[i].descriptorCount; @@ -6776,7 +6738,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( DescriptorSet* set = (DescriptorSet*)info->descriptorSet; DescriptorPool* pool = set->pool; DescriptorSetLayout* layout = set->layout; - DescriptorSetBinding* binding = &layout->bindings[info->binding]; + DescriptorSetBinding* binding = &layout->bindings[info->layoutBindingIndex]; DescriptorHeap* heap = nullptr; Uint32 index = 0; @@ -6799,11 +6761,11 @@ PalResult PAL_CALL updateDescriptorSetD3D12( dst.ptr = getDescriptorHandleD3D12(index + j, heap->incrementSize, heap->cpuBase); if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { - Sampler* sampler = (Sampler*)info->samplerInfo->sampler; + Sampler* sampler = (Sampler*)info->samplerInfos[j].sampler; d3dDevice->handle->lpVtbl->CreateSampler(d3dDevice->handle, &sampler->desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - AccelerationStructure* tlas = (AccelerationStructure*)info->tlasInfo->tlas; + AccelerationStructure* tlas = (AccelerationStructure*)info->tlasInfos[j].tlas; D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; desc.RaytracingAccelerationStructure.Location = tlas->address; @@ -6816,7 +6778,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - ImageView* imageView = (ImageView*)info->imageViewInfo->imageView; + ImageView* imageView = (ImageView*)info->imageViewInfos[j].imageView; D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; desc.Format = imageView->format; @@ -6836,7 +6798,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - ImageView* imageView = (ImageView*)info->imageViewInfo->imageView; + ImageView* imageView = (ImageView*)info->imageViewInfos[j].imageView; D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; desc.Format = imageView->format; @@ -6856,13 +6818,15 @@ PalResult PAL_CALL updateDescriptorSetD3D12( dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - Buffer* buffer = (Buffer*)info->bufferInfo->buffer; + PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; + Buffer* buffer = (Buffer*)bufferInfo->buffer; + D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {0}; - desc.SizeInBytes = info->bufferInfo->size; + desc.SizeInBytes = bufferInfo->size; D3D12_GPU_VIRTUAL_ADDRESS address = 0; address = buffer->handle->lpVtbl->GetGPUVirtualAddress(buffer->handle); - desc.BufferLocation = address + info->bufferInfo->offset; + desc.BufferLocation = address + bufferInfo->offset; d3dDevice->handle->lpVtbl->CreateConstantBufferView( d3dDevice->handle, @@ -6871,21 +6835,22 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } else { // storage buffer - Buffer* buffer = (Buffer*)info->bufferInfo->buffer; + PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; + Buffer* buffer = (Buffer*)bufferInfo->buffer; D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; Uint32 stride = 4; - if (info->bufferInfo->stride) { - stride = info->bufferInfo->stride; - desc.Buffer.StructureByteStride = info->bufferInfo->stride; + if (bufferInfo->stride) { + stride = bufferInfo->stride; + desc.Buffer.StructureByteStride = bufferInfo->stride; } else { desc.Format = DXGI_FORMAT_R32_TYPELESS; desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; } desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - desc.Buffer.FirstElement = info->bufferInfo->offset / stride; - desc.Buffer.NumElements = info->bufferInfo->size / stride; + desc.Buffer.FirstElement = bufferInfo->offset / stride; + desc.Buffer.NumElements = bufferInfo->size / stride; d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( d3dDevice->handle, From 7f90fea0365c57d62b95673531b539f2366498c1 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 8 May 2026 04:10:01 +0000 Subject: [PATCH 200/372] start descriptor API refinement --- src/graphics/pal_d3d12.c | 257 ++++++++++++++++++++++++++++++++++----- 1 file changed, 229 insertions(+), 28 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 15c5a803..396d44ce 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -144,6 +144,31 @@ typedef struct { Uint32 freeList[MAX_DSV]; } DSVHeapAllocator; +typedef struct { + Uint32 freeComputeQueues; + Uint32 freeGraphicsQueues; + Uint32 freeCopyQueues; + Uint32 maxVertexLayouts; + Uint32 maxVertexAttributes; + + Uint32 maxAnisotropy; + Uint32 maxPushConstantSize; + Uint32 maxTessellationPatchPoint; + + Uint32 maxDescriptorSampledImages; + Uint32 maxDescriptorStorageImages; + Uint32 maxDescriptorSamplers; + Uint32 maxDescriptorStorageBuffers; + Uint32 maxDescriptorUniformBuffers; + Uint32 maxBoundDescriptorSets; + + Uint32 maxRecursionDepth; + Uint32 maxHitAttributeSize; + Uint32 maxPayloadSize; + Uint32 maxDispatchInvocations; + Uint32 maxDescriptorAccelerationStructures; +} DeviceLimits; + typedef struct { const PalGraphicsBackend* backend; @@ -159,6 +184,7 @@ typedef struct { ID3D12Device5* handle; RTVHeapAllocator rtvAllocator; DSVHeapAllocator dsvAllocator; + DeviceLimits limits; } Device; typedef struct { @@ -1201,14 +1227,30 @@ static DXGI_FORMAT vertexTypeToD3D12(PalVertexType type) return DXGI_FORMAT_UNKNOWN; } -static void fillBuildInfoD3D12( +static bool fillBuildInfoD3D12( PalAccelerationStructureBuildInfo* info, D3D12_RAYTRACING_GEOMETRY_DESC* geometries, D3D12_GPU_VIRTUAL_ADDRESS srcAs, D3D12_GPU_VIRTUAL_ADDRESS dstAs, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC* buildInfo) { + static Uint32 maxInstanceCount = 1000000; + static Uint32 maxPrimitiveCount = 10000000; + static Uint32 maxGeometryCount = 100000; + + if (info->geometryCount > maxGeometryCount) { + return; + } + + if (info->instanceCount > maxInstanceCount) { + return; + } + for (int i = 0; i < info->geometryCount; i++) { + if (info->geometries[i].primitiveCount > maxPrimitiveCount) { + return; + } + D3D12_RAYTRACING_GEOMETRY_DESC* tmp = &geometries[i]; tmp->Flags = 0; if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_OPAQUE) { @@ -2534,6 +2576,13 @@ PalResult PAL_CALL createDeviceD3D12( Device* device = nullptr; Adapter* d3dAdapter = (Adapter*)adapter; + // check if any of the features are not supported + PalAdapterFeatures adapterFeatures = getAdapterFeaturesD3D12(adapter); + bool valid = (adapterFeatures & features) == features; + if (!valid) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + device = palAllocate(s_D3D.allocator, sizeof(Device), 0); if (!device) { return PAL_RESULT_OUT_OF_MEMORY; @@ -2541,6 +2590,7 @@ PalResult PAL_CALL createDeviceD3D12( ID3D12Device* tmpDevice = nullptr; memset(device, 0, sizeof(Device)); + DeviceLimits* limits = &device->limits; result = s_D3D.createDevice( (IUnknown*)d3dAdapter->handle, @@ -2764,6 +2814,42 @@ PalResult PAL_CALL createDeviceD3D12( ); device->dsvAllocator.baseOffset = dst.ptr; + // API enforced limits + limits->freeComputeQueues = 2; + limits->freeGraphicsQueues = 2; + limits->freeCopyQueues = 2; + limits->maxVertexLayouts = 30; + limits->maxVertexAttributes = 30; + + limits->maxAnisotropy = 16; + limits->maxPushConstantSize = 256; + limits->maxTessellationPatchPoint = 32; + limits->maxBoundDescriptorSets = 30; + + if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + limits->maxDescriptorSampledImages = 4096; + limits->maxDescriptorStorageImages = 1024; + limits->maxDescriptorSamplers = 512; + limits->maxDescriptorStorageBuffers = 2048; + limits->maxDescriptorUniformBuffers = 256; + + } else { + limits->maxDescriptorSampledImages = 1024; + limits->maxDescriptorStorageImages = 512; + limits->maxDescriptorSamplers = 256; + limits->maxDescriptorStorageBuffers = 512; + limits->maxDescriptorUniformBuffers = 256; + limits->maxBoundDescriptorSets = 30; + } + + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + limits->maxRecursionDepth = 31; + limits->maxHitAttributeSize = 32; + limits->maxPayloadSize = 64; + limits->maxDispatchInvocations = 16000000; + limits->maxDescriptorAccelerationStructures = 4; + } + device->adapter = d3dAdapter->handle; device->features = features; *outDevice = (PalDevice*)device; @@ -3067,16 +3153,31 @@ PalResult PAL_CALL createQueueD3D12( switch (type) { case PAL_QUEUE_TYPE_COMPUTE: { desc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; + + if (!d3dDevice->limits.freeComputeQueues) { + return PAL_RESULT_OUT_OF_QUEUE; + } + d3dDevice->limits.freeComputeQueues--; break; } case PAL_QUEUE_TYPE_GRAPHICS: { desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + + if (!d3dDevice->limits.freeGraphicsQueues) { + return PAL_RESULT_OUT_OF_QUEUE; + } + d3dDevice->limits.freeGraphicsQueues--; break; } case PAL_QUEUE_TYPE_COPY: { desc.Type = D3D12_COMMAND_LIST_TYPE_COPY; + + if (!d3dDevice->limits.freeCopyQueues) { + return PAL_RESULT_OUT_OF_QUEUE; + } + d3dDevice->limits.freeCopyQueues--; break; } } @@ -3625,6 +3726,11 @@ PalResult PAL_CALL createSamplerD3D12( const PalSamplerCreateInfo* info, PalSampler** outSampler) { + Device* d3dDevice = (Device*)device; + if (info->maxAnisotropy > d3dDevice->limits.maxAnisotropy) { + return PAL_RESULT_INVALID_ARGUMENT; + } + Sampler* sampler = nullptr; sampler = palAllocate(s_D3D.allocator, sizeof(Sampler), 0); if (!sampler) { @@ -3870,6 +3976,10 @@ PalResult PAL_CALL createSwapchainD3D12( return PAL_RESULT_INVALID_ARGUMENT; } + if (info->imageCount > 8) { + return PAL_RESULT_INVALID_ARGUMENT; + } + swapchain = palAllocate(s_D3D.allocator, sizeof(Swapchain), 0); if (!swapchain) { return PAL_RESULT_OUT_OF_MEMORY; @@ -4885,13 +4995,17 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( } memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); - fillBuildInfoD3D12( + bool success = fillBuildInfoD3D12( info, geometries, srcAsAddress, dstAs->address, &buildInfo); + if (!success) { + return PAL_RESULT_INVALID_ARGUMENT; + } + d3dCmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( d3dCmdBuffer->handle, &buildInfo, @@ -4901,13 +5015,17 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( palFree(s_D3D.allocator, geometries); } else { - fillBuildInfoD3D12( + bool success = fillBuildInfoD3D12( info, nullptr, srcAsAddress, dstAs->address, &buildInfo); + if (!success) { + return PAL_RESULT_INVALID_ARGUMENT; + } + d3dCmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( d3dCmdBuffer->handle, &buildInfo, @@ -5857,6 +5975,7 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( Uint32 setIndex, PalDescriptorSet* set) { + // TODO: CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* pipeline = d3dCmdBuffer->pipeline; DescriptorSet* d3dSet = (DescriptorSet*)set; @@ -5932,6 +6051,7 @@ PalResult PAL_CALL cmdPushConstantsD3D12( Uint32 size, const void* value) { + // TODO: CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* pipeline = d3dCmdBuffer->pipeline; @@ -6067,13 +6187,17 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( } memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); - fillBuildInfoD3D12( + bool success = fillBuildInfoD3D12( info, geometries, 0, 0, &buildInfo); + if (!success) { + return PAL_RESULT_INVALID_ARGUMENT; + } + d3dDevice->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( d3dDevice->handle, &buildInfo.Inputs, @@ -6082,13 +6206,17 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( palFree(s_D3D.allocator, geometries); } else { - fillBuildInfoD3D12( + bool success = fillBuildInfoD3D12( info, nullptr, 0, 0, &buildInfo); + if (!success) { + return PAL_RESULT_INVALID_ARGUMENT; + } + d3dDevice->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( d3dDevice->handle, &buildInfo.Inputs, @@ -6375,11 +6503,16 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( Uint32 resourceOffset = 0; Uint32 samplerOffset = 0; - Uint32 samplerCount = 0; + Uint32 SRVRegister = 0; + Uint32 UAVRegister = 0; + Uint32 CBVRegister = 0; - Uint32 sampledASIndex = 0; - Uint32 uniformIndex = 0; - Uint32 storageIndex = 0; + Uint32 sampledImageCount = 0; + Uint32 storageImageCount = 0; + Uint32 storageBufferCount = 0; + Uint32 uniformBufferCount = 0; + Uint32 tlasCount = 0; + Uint32 samplerCount = 0; for (int i = 0; i < count; i++) { DescriptorSetBinding* binding = &bindings[i]; @@ -6390,54 +6523,99 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( binding->range.RegisterSpace = 0; switch (info->bindings[i].descriptorType) { - case PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE: + case PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + binding->range.BaseShaderRegister = SRVRegister; + + binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; + resourceOffset += info->bindings[i].descriptorCount; + tlasCount += info->bindings[i].descriptorCount; + SRVRegister += info->bindings[i].descriptorCount; + + break; + } + case PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - binding->range.BaseShaderRegister = sampledASIndex++; + binding->range.BaseShaderRegister = SRVRegister; binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; resourceOffset += info->bindings[i].descriptorCount; + sampledImageCount += info->bindings[i].descriptorCount; + SRVRegister += info->bindings[i].descriptorCount; break; } case PAL_DESCRIPTOR_TYPE_SAMPLER: { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - binding->range.BaseShaderRegister = samplerCount++; + binding->range.BaseShaderRegister = samplerCount; binding->range.OffsetInDescriptorsFromTableStart = samplerOffset; samplerOffset += info->bindings[i].descriptorCount; + samplerCount += info->bindings[i].descriptorCount; break; } case PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER: { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - binding->range.BaseShaderRegister = storageIndex++; + binding->range.BaseShaderRegister = UAVRegister; binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; resourceOffset += info->bindings[i].descriptorCount; + storageBufferCount += info->bindings[i].descriptorCount; + UAVRegister += info->bindings[i].descriptorCount; break; } case PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE: { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - binding->range.BaseShaderRegister = storageIndex++; + binding->range.BaseShaderRegister = UAVRegister; binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; resourceOffset += info->bindings[i].descriptorCount; + storageImageCount += info->bindings[i].descriptorCount; + UAVRegister += info->bindings[i].descriptorCount; break; } case PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; - binding->range.BaseShaderRegister = uniformIndex++; + binding->range.BaseShaderRegister = CBVRegister; binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; resourceOffset += info->bindings[i].descriptorCount; + uniformBufferCount += info->bindings[i].descriptorCount; + CBVRegister += info->bindings[i].descriptorCount; break; } } } + // check limits + if (sampledImageCount > d3dDevice->limits.maxDescriptorSampledImages) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (storageImageCount > d3dDevice->limits.maxDescriptorStorageImages) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (storageBufferCount > d3dDevice->limits.maxDescriptorStorageBuffers) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (uniformBufferCount > d3dDevice->limits.maxDescriptorUniformBuffers) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (tlasCount > d3dDevice->limits.maxDescriptorAccelerationStructures) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (samplerCount > d3dDevice->limits.maxDescriptorSamplers) { + return PAL_RESULT_INVALID_ARGUMENT; + } + layout->bindingCount = info->bindingCount; layout->samplerCount = samplerCount; layout->bindings = bindings; @@ -6640,7 +6818,7 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( Uint32 storageBufferCount = 0; Uint32 uniformBufferCount = 0; Uint32 sampledImageCount = 0; - Uint32 asCount = 0; + Uint32 tlasCount = 0; // get requirements for the sets using the provided layout for (int i = 0; i < d3dLayout->bindingCount; i++) { @@ -6662,14 +6840,7 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( sampledImageCount += binding->range.NumDescriptors; } else if (binding->type == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - asCount += binding->range.NumDescriptors; - } - - // check if descriptor indexing is supported and enabled - if (binding->range.NumDescriptors > 1) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + tlasCount += binding->range.NumDescriptors; } } @@ -6681,7 +6852,7 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( // check descriptor limits DescriptorHeapLimits* limits = &d3dPool->limits; - if (limits->usedAs + asCount > limits->maxAs) { + if (limits->usedAs + tlasCount > limits->maxAs) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -6712,12 +6883,12 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( set->layout = d3dLayout; set->pool = d3dPool; - Uint32 totalDescriptors = asCount + storageBufferCount + uniformBufferCount; + Uint32 totalDescriptors = tlasCount + storageBufferCount + uniformBufferCount; totalDescriptors += sampledImageCount + storageImageCount; d3dPool->resourceHeap.nextOffset += totalDescriptors; d3dPool->samplerHeap.nextOffset += samplerCount; - limits->usedAs += asCount; + limits->usedAs += tlasCount; limits->usedSampledImages += sampledImageCount; limits->usedSamplers += samplerCount; limits->usedStorageBuffers += storageBufferCount; @@ -6738,8 +6909,12 @@ PalResult PAL_CALL updateDescriptorSetD3D12( DescriptorSet* set = (DescriptorSet*)info->descriptorSet; DescriptorPool* pool = set->pool; DescriptorSetLayout* layout = set->layout; - DescriptorSetBinding* binding = &layout->bindings[info->layoutBindingIndex]; + if (info->layoutBindingIndex > layout->bindingCount) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + DescriptorSetBinding* binding = &layout->bindings[info->layoutBindingIndex]; DescriptorHeap* heap = nullptr; Uint32 index = 0; Uint32 bindingOffset = binding->range.OffsetInDescriptorsFromTableStart; @@ -6882,6 +7057,8 @@ PalResult PAL_CALL createPipelineLayoutD3D12( D3D12_DESCRIPTOR_RANGE1* ranges = nullptr; D3D12_DESCRIPTOR_RANGE1* samplerRanges = nullptr; + // TODO: + // get the total resource and sampler ranges for all provided descriptor set layouts for (int i = 0; i < info->descriptorSetLayoutCount; i++) { DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; @@ -6897,6 +7074,10 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } } + if (pushConstantSize > d3dDevice->limits.maxPushConstantSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } + layout = palAllocate(s_D3D.allocator, sizeof(PipelineLayout), 0); if (!layout) { return PAL_RESULT_OUT_OF_MEMORY; @@ -7126,6 +7307,14 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( vertexCount += layout->attributeCount; } + if (info->vertexLayoutCount > d3dDevice->limits.maxVertexLayouts) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (vertexCount > d3dDevice->limits.maxVertexAttributes) { + return PAL_RESULT_INVALID_ARGUMENT; + } + InputLayoutStream* inputLayoutStream = &graphicsStreamDesc.inputLayout; totalSize += sizeof(InputLayoutStream); inputLayoutStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT; @@ -7569,6 +7758,18 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (info->maxAttributeSize > d3dDevice->limits.maxHitAttributeSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (info->maxPayloadSize > d3dDevice->limits.maxPayloadSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (info->maxRecursionDepth> d3dDevice->limits.maxRecursionDepth) { + return PAL_RESULT_INVALID_ARGUMENT; + } + // Every entry is a shader export for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; From 70f58fa649cdef40be1c4d2082dda48f4869d0fd Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 8 May 2026 10:05:20 +0000 Subject: [PATCH 201/372] descriptor API refinement vulkan --- src/graphics/pal_d3d12.c | 159 ++++++++++++++++++++------------- src/graphics/pal_vulkan.c | 14 +++ tests/graphics/graphics_test.c | 4 +- 3 files changed, 111 insertions(+), 66 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 396d44ce..5a3dcfa2 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -144,6 +144,7 @@ typedef struct { Uint32 freeList[MAX_DSV]; } DSVHeapAllocator; +// Limits we must enforce ourselves typedef struct { Uint32 freeComputeQueues; Uint32 freeGraphicsQueues; @@ -318,10 +319,7 @@ typedef struct { const PalGraphicsBackend* backend; Uint32 constantIndex; - Uint32 resourceIndex; - Uint32 samplerIndex; ID3D12RootSignature* handle; - D3D12_ROOT_PARAMETER1 params[3]; } PipelineLayout; typedef struct { @@ -1239,16 +1237,16 @@ static bool fillBuildInfoD3D12( static Uint32 maxGeometryCount = 100000; if (info->geometryCount > maxGeometryCount) { - return; + return false; } if (info->instanceCount > maxInstanceCount) { - return; + return false; } for (int i = 0; i < info->geometryCount; i++) { if (info->geometries[i].primitiveCount > maxPrimitiveCount) { - return; + return false; } D3D12_RAYTRACING_GEOMETRY_DESC* tmp = &geometries[i]; @@ -1325,6 +1323,8 @@ static bool fillBuildInfoD3D12( buildInfo->SourceAccelerationStructureData = srcAs; buildInfo->DestAccelerationStructureData = dstAs; buildInfo->ScratchAccelerationStructureData = info->scratchBufferAddress; + + return true; } static Uint32 getFormatSizeD3D12(PalFormat format) @@ -5975,7 +5975,6 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( Uint32 setIndex, PalDescriptorSet* set) { - // TODO: CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* pipeline = d3dCmdBuffer->pipeline; DescriptorSet* d3dSet = (DescriptorSet*)set; @@ -5993,9 +5992,11 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( } d3dCmdBuffer->handle->lpVtbl->SetDescriptorHeaps(d3dCmdBuffer->handle, heapCount, heaps); - // bind descriptor tables - if (pipeline->layout->resourceIndex != UINT32_MAX) { - // a valid index + // bind resource descriptor table + Uint32 resourceCount = d3dSet->layout->bindingCount - d3dSet->layout->samplerCount; + Uint32 baseIndex = setIndex; + + if (resourceCount) { D3D12_GPU_DESCRIPTOR_HANDLE base; base.ptr = getDescriptorHandleD3D12( d3dSet->resourceOffset, @@ -6005,20 +6006,22 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( if (pipeline->type == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( d3dCmdBuffer->handle, - pipeline->layout->resourceIndex, + baseIndex, // base set index is resource first before sampler base); } else { // ray tracing uses the compute path d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( d3dCmdBuffer->handle, - pipeline->layout->resourceIndex, + baseIndex, // base set index is resource first before sampler base); } + + baseIndex++; } - if (pipeline->layout->samplerIndex != UINT32_MAX) { - // a valid index + // bind sampler descriptor table + if (d3dSet->layout->samplerCount) { D3D12_GPU_DESCRIPTOR_HANDLE base; base.ptr = getDescriptorHandleD3D12( d3dSet->samplerOffset, @@ -6028,14 +6031,14 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( if (pipeline->type == GRAPHICS_PIPELINE) { d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( d3dCmdBuffer->handle, - pipeline->layout->samplerIndex, + baseIndex, base); } else { // ray tracing uses the compute path d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( d3dCmdBuffer->handle, - pipeline->layout->samplerIndex, + baseIndex, base); } } @@ -6051,7 +6054,6 @@ PalResult PAL_CALL cmdPushConstantsD3D12( Uint32 size, const void* value) { - // TODO: CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* pipeline = d3dCmdBuffer->pipeline; @@ -7054,10 +7056,18 @@ PalResult PAL_CALL createPipelineLayoutD3D12( Uint32 samplerCount = 0; Uint32 pushConstantSize = 0; Uint32 sizeInBytes = sizeof(D3D12_DESCRIPTOR_RANGE1); + + Uint32 rangesOffset = 0; + Uint32 samplerRangesOffset = 0; D3D12_DESCRIPTOR_RANGE1* ranges = nullptr; D3D12_DESCRIPTOR_RANGE1* samplerRanges = nullptr; - // TODO: + Uint32 parameterCount = info->descriptorSetLayoutCount; + D3D12_ROOT_PARAMETER1* parameters = nullptr; + + if (info->descriptorSetLayoutCount > d3dDevice->limits.maxBoundDescriptorSets) { + return PAL_RESULT_INVALID_ARGUMENT; + } // get the total resource and sampler ranges for all provided descriptor set layouts for (int i = 0; i < info->descriptorSetLayoutCount; i++) { @@ -7083,7 +7093,20 @@ PalResult PAL_CALL createPipelineLayoutD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - memset(layout, 0, sizeof(PipelineLayout)); + if (pushConstantSize) { + parameterCount++; + } + + if (parameterCount) { + Uint32 paramtersSize = sizeof(D3D12_ROOT_PARAMETER1) * parameterCount; + parameters = palAllocate(s_D3D.allocator, paramtersSize, 0); + if (!ranges) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(parameters, 0, paramtersSize); + } + if (resourceCount) { ranges = palAllocate(s_D3D.allocator, sizeInBytes * resourceCount, 0); if (!ranges) { @@ -7098,71 +7121,75 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } } - Uint32 tmpResourceIndex = 0; - Uint32 tmpSamplerIndex = 0; + // write root constant first if its provided + parameterCount = 0; // reset and reuse the same variable + layout->constantIndex = UINT32_MAX; + if (pushConstantSize) { + D3D12_ROOT_PARAMETER1* parameter = ¶meters[parameterCount]; + parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + parameter->Constants.Num32BitValues = pushConstantSize / 4; + parameter->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + layout->constantIndex = parameterCount; + parameterCount++; + } + + Uint32 registerSpace = 0; for (int i = 0; i < info->descriptorSetLayoutCount; i++) { DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; + D3D12_ROOT_PARAMETER1* parameter = ¶meters[parameterCount]; + + // reset and reuse same variable + resourceCount = tmp->bindingCount - tmp->samplerCount; + samplerCount = tmp->samplerCount; + // seperate the samplers from the remaining descriptors - for (int i = 0; i < tmp->bindingCount; i++) { - DescriptorSetBinding* binding = &tmp->bindings[i]; + for (int j = 0; j < tmp->bindingCount; j++) { + DescriptorSetBinding* binding = &tmp->bindings[j]; + D3D12_DESCRIPTOR_RANGE1* tmpRange = nullptr; + if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { - samplerRanges[tmpResourceIndex++] = binding->range; + tmpRange = &samplerRanges[samplerRangesOffset + j]; } else { - ranges[tmpSamplerIndex++] = binding->range; + tmpRange = &ranges[rangesOffset + j]; } + tmpRange->RegisterSpace = registerSpace; } - } - Uint32 paramCount = 0; - layout->constantIndex = UINT32_MAX; - layout->resourceIndex = UINT32_MAX; - layout->samplerIndex = UINT32_MAX; + // resource ranges + if (resourceCount) { + parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + parameter->DescriptorTable.NumDescriptorRanges = resourceCount; + parameter->DescriptorTable.pDescriptorRanges = &ranges[rangesOffset]; + parameter->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - // push constant parameter - if (pushConstantSize) { - D3D12_ROOT_PARAMETER1* tmp = &layout->params[paramCount]; - tmp->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; - tmp->Constants.Num32BitValues = pushConstantSize / 4; - tmp->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - - layout->constantIndex = paramCount; - paramCount++; - } - - // resource parameter - if (resourceCount) { - D3D12_ROOT_PARAMETER1* tmp = &layout->params[paramCount]; - tmp->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - tmp->DescriptorTable.NumDescriptorRanges = resourceCount; - tmp->DescriptorTable.pDescriptorRanges = ranges; - tmp->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + rangesOffset += resourceCount; + parameterCount++; + } - layout->resourceIndex = paramCount; - paramCount++; - } + // sampler ranges + if (resourceCount) { + parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + parameter->DescriptorTable.NumDescriptorRanges = samplerCount; + parameter->DescriptorTable.pDescriptorRanges = &samplerRanges[samplerRangesOffset]; + parameter->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - // sampler parameter - if (samplerCount) { - D3D12_ROOT_PARAMETER1* tmp = &layout->params[paramCount]; - tmp->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - tmp->DescriptorTable.NumDescriptorRanges = samplerCount; - tmp->DescriptorTable.pDescriptorRanges = samplerRanges; - tmp->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + samplerRangesOffset += samplerCount; + parameterCount++; + } - layout->samplerIndex = paramCount; - paramCount++; + registerSpace++; } // create root signature D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; rootDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; - rootDesc.Desc_1_1.NumParameters = paramCount; - rootDesc.Desc_1_1.pParameters = layout->params; + rootDesc.Desc_1_1.NumParameters = parameterCount; + rootDesc.Desc_1_1.pParameters = parameters; rootDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; ID3DBlob* blob = nullptr; - ID3DBlob* errBlob = nullptr; - HRESULT result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, &errBlob); + HRESULT result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { pollMessagesD3D12(d3dDevice); if (result == E_INVALIDARG) { @@ -7197,6 +7224,10 @@ PalResult PAL_CALL createPipelineLayoutD3D12( palFree(s_D3D.allocator, samplerRanges); } + if (parameterCount) { + palFree(s_D3D.allocator, parameters); + } + blob->lpVtbl->Release(blob); *outLayout = (PalPipelineLayout*)layout; return PAL_RESULT_SUCCESS; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e1769ed9..4e32b20c 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -355,6 +355,11 @@ typedef struct { VkQueueFlags usedUsages; } PhysicalQueue; +// Limits we must enforce ourselves +typedef struct { + Uint32 maxPayloadSize; +} DeviceLimits; + typedef struct { const PalGraphicsBackend* backend; @@ -419,6 +424,8 @@ typedef struct { PFN_vkCmdSetDepthTestEnable cmdSetDepthTestEnable; PFN_vkCmdSetDepthWriteEnable cmdSetDepthWriteEnable; PFN_vkCmdSetStencilOp cmdSetStencilOp; + + DeviceLimits limits; } Device; typedef struct { @@ -4332,7 +4339,10 @@ PalResult PAL_CALL createDeviceVk( } // ray tracing procs + device->limits.maxPayloadSize = 0; if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + device->limits.maxPayloadSize = 64; + device->createAccelerationStructure = (PFN_vkCreateAccelerationStructureKHR)s_Vk.getDeviceProcAddr( device->handle, @@ -9098,6 +9108,10 @@ PalResult PAL_CALL createRayTracingPipelineVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (info->maxPayloadSize > vkDevice->limits.maxPayloadSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } + // Every entry is a shader stage for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index fdd344c0..7d2ca9b6 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -261,14 +261,14 @@ bool graphicsTest() palLog(nullptr, " SPIRV"); target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - palLog(nullptr, " Highest Spirv Target %s:", shaderTargetToString(target)); + palLog(nullptr, " Highest Spirv Target %s:", shaderTargetToString(target)); } if (info.shaderFormats & PAL_SHADER_FORMAT_DXIL) { palLog(nullptr, " DXIL"); target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - palLog(nullptr, " Highest Dxil Target %s:", shaderTargetToString(target)); + palLog(nullptr, " Highest Dxil Target %s:", shaderTargetToString(target)); } // features From dd3f94be0875b0d553000346c57e8456a624da90 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 8 May 2026 11:43:48 +0000 Subject: [PATCH 202/372] compute test with refined descriptor API d3d12 and vulkan --- src/graphics/pal_d3d12.c | 26 ++++++++++++++++++++------ src/graphics/pal_vulkan.c | 28 ++++++++++++++++++---------- tests/graphics/compute_test.c | 2 +- tests/tests_main.c | 4 ++-- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 5a3dcfa2..6fe9001d 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -5995,6 +5995,11 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( // bind resource descriptor table Uint32 resourceCount = d3dSet->layout->bindingCount - d3dSet->layout->samplerCount; Uint32 baseIndex = setIndex; + if (pipeline->layout->constantIndex != UINT32_MAX) { + // If push constant was used to create the pipeline layout + // slot 0 will be reserve for it + baseIndex++; + } if (resourceCount) { D3D12_GPU_DESCRIPTOR_HANDLE base; @@ -6942,7 +6947,9 @@ PalResult PAL_CALL updateDescriptorSetD3D12( d3dDevice->handle->lpVtbl->CreateSampler(d3dDevice->handle, &sampler->desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - AccelerationStructure* tlas = (AccelerationStructure*)info->tlasInfos[j].tlas; + AccelerationStructure* tlas = nullptr; + tlas = (AccelerationStructure*)info->tlasInfos[j].tlas; + D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; desc.RaytracingAccelerationStructure.Location = tlas->address; @@ -7100,7 +7107,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( if (parameterCount) { Uint32 paramtersSize = sizeof(D3D12_ROOT_PARAMETER1) * parameterCount; parameters = palAllocate(s_D3D.allocator, paramtersSize, 0); - if (!ranges) { + if (!parameters) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7137,27 +7144,33 @@ PalResult PAL_CALL createPipelineLayoutD3D12( Uint32 registerSpace = 0; for (int i = 0; i < info->descriptorSetLayoutCount; i++) { DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; - D3D12_ROOT_PARAMETER1* parameter = ¶meters[parameterCount]; + D3D12_ROOT_PARAMETER1* parameter = nullptr; // reset and reuse same variable resourceCount = tmp->bindingCount - tmp->samplerCount; samplerCount = tmp->samplerCount; + Uint32 samplerIndex = samplerRangesOffset; + Uint32 rangeIndex = rangesOffset; + // seperate the samplers from the remaining descriptors for (int j = 0; j < tmp->bindingCount; j++) { DescriptorSetBinding* binding = &tmp->bindings[j]; D3D12_DESCRIPTOR_RANGE1* tmpRange = nullptr; if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { - tmpRange = &samplerRanges[samplerRangesOffset + j]; + tmpRange = &samplerRanges[samplerIndex++]; } else { - tmpRange = &ranges[rangesOffset + j]; + tmpRange = &ranges[rangeIndex++]; } + + *tmpRange = binding->range; tmpRange->RegisterSpace = registerSpace; } // resource ranges if (resourceCount) { + parameter = ¶meters[parameterCount]; parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter->DescriptorTable.NumDescriptorRanges = resourceCount; parameter->DescriptorTable.pDescriptorRanges = &ranges[rangesOffset]; @@ -7168,7 +7181,8 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } // sampler ranges - if (resourceCount) { + if (samplerCount) { + parameter = ¶meters[parameterCount]; parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter->DescriptorTable.NumDescriptorRanges = samplerCount; parameter->DescriptorTable.pDescriptorRanges = &samplerRanges[samplerRangesOffset]; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 4e32b20c..af458975 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -8399,25 +8399,32 @@ PalResult PAL_CALL updateDescriptorSetVk( return PAL_RESULT_OUT_OF_MEMORY; } - bufferInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBufferInfo) * bufferCount, 0); - if (!bufferInfos && bufferCount) { - return PAL_RESULT_OUT_OF_MEMORY; + if (bufferCount) { + bufferInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBufferInfo) * bufferCount, 0); + if (!bufferInfos) { + return PAL_RESULT_OUT_OF_MEMORY; + } } - imageInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorImageInfo) * imageCount, 0); - if (!imageInfos && imageCount) { - return PAL_RESULT_OUT_OF_MEMORY; + + if (imageCount) { + imageInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorImageInfo) * imageCount, 0); + if (!imageInfos) { + return PAL_RESULT_OUT_OF_MEMORY; + } } Uint32 tlasInfoSize = sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasCount; - tlasInfos = palAllocate(s_Vk.allocator, tlasInfoSize, 0); - if (!tlasInfos && tlasCount) { - return PAL_RESULT_OUT_OF_MEMORY; + if (tlasCount) { + tlasInfos = palAllocate(s_Vk.allocator, tlasInfoSize, 0); + if (!tlasInfos) { + return PAL_RESULT_OUT_OF_MEMORY; + } } for (int i = 0; i < count; i++) { VkWriteDescriptorSet* write = &writes[i]; - PalDescriptorSetWriteInfo* info = &info[i]; + PalDescriptorSetWriteInfo* info = &infos[i]; write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; write->pBufferInfo = nullptr; @@ -8432,6 +8439,7 @@ PalResult PAL_CALL updateDescriptorSetVk( DescriptorSet* set = (DescriptorSet*)info->descriptorSet; write->dstSet = set->handle; + bool isImage = false; bool isTlas = false; bool isBuffer = false; diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index d4fb61bb..73e75fd2 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -46,7 +46,7 @@ bool computeTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/tests_main.c b/tests/tests_main.c index 836bf2de..b0359452 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,8 +57,8 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest, "Graphics Test"); - // registerTest(computeTest, "Compute Test"); + // registerTest(graphicsTest, "Graphics Test"); + registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS From 6f25bfebb7f53e067bfee19fe45ff7b277e19505 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 8 May 2026 11:47:57 +0000 Subject: [PATCH 203/372] ray tracing with refined descriptor API d3d12 and vulkan --- tests/tests_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests_main.c b/tests/tests_main.c index b0359452..a58159ad 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,8 +58,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(computeTest, "Compute Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From 208ee55a67d2af6a631c44cd3fe6615b76d89cca Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 8 May 2026 11:52:32 +0000 Subject: [PATCH 204/372] triangle test with refind descriptor API d3d12 and vulkan --- tests/graphics/compute_test.c | 2 +- tests/tests_main.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 73e75fd2..d4fb61bb 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -46,7 +46,7 @@ bool computeTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/tests_main.c b/tests/tests_main.c index a58159ad..3c2d0110 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,12 +59,12 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); - // registerTest(triangleTest, "Triangle Test"); + registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); #endif // From 34db86286666ea462a73d947c0d6c4b8d3c9c6ad Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 8 May 2026 12:01:06 +0000 Subject: [PATCH 205/372] texture test with refined descriptor API d3d12 and vulkan --- tests/tests_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/tests_main.c b/tests/tests_main.c index 3c2d0110..f62e99aa 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -64,9 +64,9 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); - registerTest(triangleTest, "Triangle Test"); + // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); - // registerTest(textureTest, "Texture Test"); + registerTest(textureTest, "Texture Test"); #endif // runTests(); From e1b974166e5d01b8c2e52381649c1327ef1b4d91 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 8 May 2026 13:54:30 +0000 Subject: [PATCH 206/372] shader target API refinemenent --- include/pal/pal_graphics.h | 87 ++++++-------------- src/graphics/pal_d3d12.c | 132 +++++------------------------- src/graphics/pal_graphics.c | 29 +------ src/graphics/pal_vulkan.c | 52 ++---------- tests/graphics/clear_color_test.c | 33 +------- tests/graphics/compute_test.c | 7 +- tests/graphics/graphics_test.c | 83 ++++++------------- tests/graphics/mesh_test.c | 9 +- tests/graphics/ray_tracing_test.c | 7 +- tests/graphics/texture_test.c | 7 +- tests/graphics/triangle_test.c | 7 +- tests/tests_main.c | 4 +- 12 files changed, 112 insertions(+), 345 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 77e0bdce..27ed83e8 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -57,6 +57,27 @@ freely, subject to the following restrictions: */ #define PAL_UNUSED_SHADER_INDEX UINT32_MAX +/** + * @brief An encoding scheme for shader format target versions. + * @since 1.4 + * @ingroup pal_graphics + */ +#define PAL_MAKE_SHADER_TARGET(major, minor) ((Uint32)((major) << 8) | (minor)) + +/** + * @brief Get the major of an encoded shader target. + * @since 1.4 + * @ingroup pal_graphics + */ +#define PAL_SHADER_TARGET_MAJOR(target) ((Uint32)(target) >> 8); + +/** + * @brief Get the minor of an encoded shader target. + * @since 1.4 + * @ingroup pal_graphics + */ +#define PAL_SHADER_TARGET_MINOR(target) ((Uint32)(target) & 0xFF); + /** * @struct PalAdapter * @brief Opaque handle to an adapter (GPU). @@ -543,36 +564,6 @@ typedef enum { PAL_SHADER_FORMAT_PPM = PAL_BIT(5) } PalShaderFormats; -/** - * @enum PalShaderTarget - * @brief Shader targets. - * - * All shader targets follow the format `PAL_SHADER_TARGET_**` for - * consistency and API use. - * - * @since 1.4 - * @ingroup pal_graphics - */ -typedef enum { - PAL_SHADER_TARGET_UNKNOWN, - PAL_SHADER_TARGET_SPIRV_1_0, - PAL_SHADER_TARGET_SPIRV_1_1, - PAL_SHADER_TARGET_SPIRV_1_2, - PAL_SHADER_TARGET_SPIRV_1_3, - PAL_SHADER_TARGET_SPIRV_1_4, - PAL_SHADER_TARGET_SPIRV_1_5, - PAL_SHADER_TARGET_SPIRV_1_6, - PAL_SHADER_TARGET_DXIL_5_1, - PAL_SHADER_TARGET_DXIL_6_0, - PAL_SHADER_TARGET_DXIL_6_1, - PAL_SHADER_TARGET_DXIL_6_2, - PAL_SHADER_TARGET_DXIL_6_3, - PAL_SHADER_TARGET_DXIL_6_4, - PAL_SHADER_TARGET_DXIL_6_5, - PAL_SHADER_TARGET_DXIL_6_6, - PAL_SHADER_TARGET_DXIL_6_7 -} PalShaderTarget; - /** * @enum PalAdapterFeatures * @brief Adapter features. This is a bitmask. @@ -2770,21 +2761,12 @@ typedef struct { */ PalAdapterFeatures PAL_CALL (*getAdapterFeatures)(PalAdapter* adapter); - /** - * Backend implementation of ::palIsShaderTargetSupported. - * - * Must obey the rules and semantics documented in palIsShaderTargetSupported(). - */ - bool PAL_CALL (*isShaderTargetSupported)( - PalAdapter* adapter, - PalShaderTarget target); - /** * Backend implementation of ::palGetHighestSupportedShaderTarget. * * Must obey the rules and semantics documented in palGetHighestSupportedShaderTarget(). */ - PalShaderTarget PAL_CALL (*getHighestSupportedShaderTarget)( + Uint32 PAL_CALL (*getHighestSupportedShaderTarget)( PalAdapter* adapter, PalShaderFormats shaderFormat); @@ -4184,25 +4166,6 @@ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( */ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); -/** - * @brief Check if the provided shader target is supported by an adapter (GPU). - * - * The graphics system must be initialized before this call. - * - * @param[in] adapter Adapter to query. - * - * @return True if target is supported otherwise false. - * - * Thread safety: Thread safe. - * - * @since 1.4 - * @ingroup pal_graphics - * @sa palEnumerateAdapters - */ -PAL_API bool PAL_CALL palIsShaderTargetSupported( - PalAdapter* adapter, - PalShaderTarget target); - /** * @brief Get the highest supported shader target of an adapter (GPU). * @@ -4211,8 +4174,8 @@ PAL_API bool PAL_CALL palIsShaderTargetSupported( * @param[in] adapter Adapter to query. * @param[in] shaderFormat The shader format. Must have only a single bit set. * - * @return The highest supported shader target on success or `PAL_SHADER_TARGET_UNKNOWN` - * on failure. + * @return The highest supported shader target encoded with `PAL_MAKE_SHADER_TARGET` macro + * on success otherwise `0` on failure. * * Thread safety: Thread safe. * @@ -4220,7 +4183,7 @@ PAL_API bool PAL_CALL palIsShaderTargetSupported( * @ingroup pal_graphics * @sa palEnumerateAdapters */ -PAL_API PalShaderTarget PAL_CALL palGetHighestSupportedShaderTarget( +PAL_API Uint32 PAL_CALL palGetHighestSupportedShaderTarget( PalAdapter* adapter, PalShaderFormats shaderFormat); diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 6fe9001d..e8ce5e85 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2171,7 +2171,7 @@ PalResult PAL_CALL getAdapterInfoD3D12( info->vendorId = desc.VendorId; info->deviceId= desc.DeviceId; info->apiType = PAL_ADAPTER_API_TYPE_D3D12; - info->shaderFormats = PAL_SHADER_FORMAT_DXIL; + info->shaderFormats = PAL_SHADER_FORMAT_DXIL | PAL_SHADER_FORMAT_DXBC; info->sharedMemory = desc.SharedSystemMemory; strcpy(info->backendName, "PAL"); @@ -2399,10 +2399,15 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) return features; } -bool PAL_CALL isShaderTargetSupportedD3D12( +Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( PalAdapter* adapter, - PalShaderTarget target) + PalShaderFormats shaderFormat) { + bool isDxil = shaderFormat == PAL_SHADER_FORMAT_DXIL; + if (!isDxil && shaderFormat != PAL_SHADER_FORMAT_DXBC) { + return 0; + } + Adapter* d3dAdapter = (Adapter*)adapter; D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; @@ -2434,133 +2439,40 @@ bool PAL_CALL isShaderTargetSupportedD3D12( } } - switch (target) { - case PAL_SHADER_TARGET_DXIL_5_1: { - if (highestModel >= D3D_SHADER_MODEL_5_1) { - return true; - } - } - - case PAL_SHADER_TARGET_DXIL_6_0: { - if (highestModel >= D3D_SHADER_MODEL_6_0) { - return true; - } - } - - - case PAL_SHADER_TARGET_DXIL_6_1: { - if (highestModel >= D3D_SHADER_MODEL_6_1) { - return true; - } - } - - case PAL_SHADER_TARGET_DXIL_6_2: { - if (highestModel >= D3D_SHADER_MODEL_6_2) { - return true; - } - } - - case PAL_SHADER_TARGET_DXIL_6_3: { - if (highestModel >= D3D_SHADER_MODEL_6_3) { - return true; - } - } - - case PAL_SHADER_TARGET_DXIL_6_4: { - if (highestModel >= D3D_SHADER_MODEL_6_4) { - return true; - } - } - - case PAL_SHADER_TARGET_DXIL_6_5: { - if (highestModel >= D3D_SHADER_MODEL_6_5) { - return true; - } - } - case PAL_SHADER_TARGET_DXIL_6_6: { - if (highestModel >= D3D_SHADER_MODEL_6_6) { - return true; - } - } - - case PAL_SHADER_TARGET_DXIL_6_7: { - if (highestModel >= D3D_SHADER_MODEL_6_7) { - return true; - } - } - } - - return false; -} - -PalShaderTarget PAL_CALL getHighestSupportedShaderTargetD3D12( - PalAdapter* adapter, - PalShaderTarget shaderFormat) -{ - if (shaderFormat != PAL_SHADER_FORMAT_DXIL) { - return PAL_SHADER_TARGET_UNKNOWN; - } - - Adapter* d3dAdapter = (Adapter*)adapter; - D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; - - D3D_SHADER_MODEL models[8]; - models[0] = D3D_SHADER_MODEL_6_7; - models[1] = D3D_SHADER_MODEL_6_6; - models[2] = D3D_SHADER_MODEL_6_5; - models[3] = D3D_SHADER_MODEL_6_4; - models[4] = D3D_SHADER_MODEL_6_3; - models[5] = D3D_SHADER_MODEL_6_2; - models[6] = D3D_SHADER_MODEL_6_1; - models[7] = D3D_SHADER_MODEL_6_0; - models[8] = D3D_SHADER_MODEL_5_1; - - // find the highest supported shader model - HRESULT result = 0; - D3D_SHADER_MODEL highestModel = D3D_SHADER_MODEL_5_1; - for (int i = 0; i < 8; i++) { - shaderModel.HighestShaderModel = models[i]; - result = d3dAdapter->tmpDevice->lpVtbl->CheckFeatureSupport( - d3dAdapter->tmpDevice, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, - sizeof(shaderModel)); - - if (shaderModel.HighestShaderModel >= models[i] && result == S_OK) { - highestModel = models[i]; - break; + if (shaderFormat == PAL_SHADER_FORMAT_DXBC) { + if (highestModel >= D3D_SHADER_MODEL_5_1) { + return PAL_MAKE_SHADER_TARGET(5, 1); + } else { + return 0; } } if (highestModel >= D3D_SHADER_MODEL_6_7) { - return PAL_SHADER_TARGET_DXIL_6_7; + return PAL_MAKE_SHADER_TARGET(6, 7); } else if (highestModel >= D3D_SHADER_MODEL_6_6) { - return PAL_SHADER_TARGET_DXIL_6_6; + return PAL_MAKE_SHADER_TARGET(6, 6); } else if (highestModel >= D3D_SHADER_MODEL_6_5) { - return PAL_SHADER_TARGET_DXIL_6_5; + return PAL_MAKE_SHADER_TARGET(6, 5); } else if (highestModel >= D3D_SHADER_MODEL_6_4) { - return PAL_SHADER_TARGET_DXIL_6_4; + return PAL_MAKE_SHADER_TARGET(6, 4); } else if (highestModel >= D3D_SHADER_MODEL_6_3) { - return PAL_SHADER_TARGET_DXIL_6_3; + return PAL_MAKE_SHADER_TARGET(6, 3); } else if (highestModel >= D3D_SHADER_MODEL_6_2) { - return PAL_SHADER_TARGET_DXIL_6_2; + return PAL_MAKE_SHADER_TARGET(6, 2); } else if (highestModel >= D3D_SHADER_MODEL_6_1) { - return PAL_SHADER_TARGET_DXIL_6_1; + return PAL_MAKE_SHADER_TARGET(6, 1); } else if (highestModel >= D3D_SHADER_MODEL_6_0) { - return PAL_SHADER_TARGET_DXIL_6_0; - - } else if (highestModel >= D3D_SHADER_MODEL_5_1) { - return PAL_SHADER_TARGET_DXIL_5_1; + return PAL_MAKE_SHADER_TARGET(6, 0); } - return PAL_SHADER_TARGET_UNKNOWN; + return 0; } // ================================================== diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 0a4c9acf..52e95c80 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -123,11 +123,7 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter); -bool PAL_CALL isShaderTargetSupportedVk( - PalAdapter* adapter, - PalShaderTarget target); - -PalShaderTarget PAL_CALL getHighestSupportedShaderTargetVk( +Uint32 PAL_CALL getHighestSupportedShaderTargetVk( PalAdapter* adapter, PalShaderFormats shaderFormat); @@ -794,7 +790,6 @@ static PalGraphicsBackend s_VkBackend = { .getAdapterInfo = getAdapterInfoVk, .getAdapterCapabilities = getAdapterCapabilitiesVk, .getAdapterFeatures = getAdapterFeaturesVk, - .isShaderTargetSupported = isShaderTargetSupportedVk, .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetVk, // device @@ -1000,11 +995,7 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); -bool PAL_CALL isShaderTargetSupportedD3D12( - PalAdapter* adapter, - PalShaderTarget target); - -PalShaderTarget PAL_CALL getHighestSupportedShaderTargetD3D12( +Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( PalAdapter* adapter, PalShaderFormats shaderFormat); @@ -1671,7 +1662,6 @@ static PalGraphicsBackend s_D3D12Backend = { .getAdapterInfo = getAdapterInfoD3D12, .getAdapterCapabilities = getAdapterCapabilitiesD3D12, .getAdapterFeatures = getAdapterFeaturesD3D12, - .isShaderTargetSupported = isShaderTargetSupportedD3D12, .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetD3D12, // device @@ -1880,7 +1870,6 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) !backend->getAdapterInfo || !backend->getAdapterCapabilities || !backend->getAdapterFeatures || - !backend->isShaderTargetSupported || !backend->getHighestSupportedShaderTarget || // device @@ -2261,22 +2250,12 @@ PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) return adapter->backend->getAdapterFeatures(adapter); } -bool PAL_CALL palIsShaderTargetSupported( - PalAdapter* adapter, - PalShaderTarget target) -{ - if (!s_Graphics.initialized || !adapter) { - return false; - } - return adapter->backend->isShaderTargetSupported(adapter, target); -} - -PalShaderTarget PAL_CALL palGetHighestSupportedShaderTarget( +Uint32 PAL_CALL palGetHighestSupportedShaderTarget( PalAdapter* adapter, PalShaderFormats shaderFormat) { if (!s_Graphics.initialized || !adapter) { - return PAL_SHADER_TARGET_UNKNOWN; + return 0; } return adapter->backend->getHighestSupportedShaderTarget(adapter, shaderFormat); } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index af458975..bb9fa8c2 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3796,50 +3796,12 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) return adapterFeatures; } -bool PAL_CALL isShaderTargetSupportedVk( - PalAdapter* adapter, - PalShaderTarget target) -{ - Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDeviceProperties props = {0}; - s_Vk.getPhysicalDeviceProperties(vkAdapter->handle, &props); - - switch (target) { - case PAL_SHADER_TARGET_SPIRV_1_0: - case PAL_SHADER_TARGET_SPIRV_1_1: - case PAL_SHADER_TARGET_SPIRV_1_2: { - return true; - } - - case PAL_SHADER_TARGET_SPIRV_1_3: - case PAL_SHADER_TARGET_SPIRV_1_4: { - if (props.apiVersion >= VK_API_VERSION_1_1) { - return true; - } - } - - case PAL_SHADER_TARGET_SPIRV_1_5: { - if (props.apiVersion >= VK_API_VERSION_1_2) { - return true; - } - } - - case PAL_SHADER_TARGET_SPIRV_1_6: { - if (props.apiVersion >= VK_API_VERSION_1_3) { - return true; - } - } - } - - return false; -} - -PalShaderTarget PAL_CALL getHighestSupportedShaderTargetVk( +Uint32 PAL_CALL getHighestSupportedShaderTargetVk( PalAdapter* adapter, PalShaderFormats shaderFormat) { if (shaderFormat != PAL_SHADER_FORMAT_SPIRV) { - return PAL_SHADER_TARGET_UNKNOWN; + return 0; } Adapter* vkAdapter = (Adapter*)adapter; @@ -3847,19 +3809,19 @@ PalShaderTarget PAL_CALL getHighestSupportedShaderTargetVk( s_Vk.getPhysicalDeviceProperties(vkAdapter->handle, &props); if (props.apiVersion >= VK_API_VERSION_1_3) { - return PAL_SHADER_TARGET_SPIRV_1_6; + return PAL_MAKE_SHADER_TARGET(1, 6); } else if (props.apiVersion >= VK_API_VERSION_1_2) { - return PAL_SHADER_TARGET_SPIRV_1_5; + return PAL_MAKE_SHADER_TARGET(1, 5); } else if (props.apiVersion >= VK_API_VERSION_1_1) { - return PAL_SHADER_TARGET_SPIRV_1_4; + return PAL_MAKE_SHADER_TARGET(1, 4); } else if (props.apiVersion >= VK_API_VERSION_1_0) { - return PAL_SHADER_TARGET_SPIRV_1_2; + return PAL_MAKE_SHADER_TARGET(1, 2); } - return PAL_SHADER_TARGET_UNKNOWN; + return 0; } // ================================================== diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index c520448f..679508b1 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -142,7 +142,6 @@ bool clearColorTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; - bool hasGraphicsQueue = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -154,46 +153,18 @@ bool clearColorTest() } if (caps.maxGraphicsQueues == 0) { - hasGraphicsQueue = false; continue; } else { - hasGraphicsQueue = true; + break; } - if (hasGraphicsQueue) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } - - // we prefer spirv first if an adapter supports multiple shader formats - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { - break; - } - } - - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { - break; - } - } - } adapter = nullptr; } palFree(nullptr, adapters); if (!adapter) { - if (!hasGraphicsQueue) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); return false; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index d4fb61bb..205f581a 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -114,14 +114,17 @@ bool computeTest() } // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { break; } } if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 7d2ca9b6..88948f8d 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -2,60 +2,6 @@ #include "pal/pal_graphics.h" #include "tests.h" -const char* shaderTargetToString(PalShaderTarget target) -{ - switch (target) { - case PAL_SHADER_TARGET_SPIRV_1_0: - return "1.0"; - - case PAL_SHADER_TARGET_SPIRV_1_1: - return "1.1"; - - case PAL_SHADER_TARGET_SPIRV_1_2: - return "1.2"; - - case PAL_SHADER_TARGET_SPIRV_1_3: - return "1.3"; - - case PAL_SHADER_TARGET_SPIRV_1_4: - return "1.4"; - - case PAL_SHADER_TARGET_SPIRV_1_5: - return "1.5"; - - case PAL_SHADER_TARGET_SPIRV_1_6: - return "1.6"; - - case PAL_SHADER_TARGET_DXIL_5_1: - return "5.1"; - - case PAL_SHADER_TARGET_DXIL_6_0: - return "6.0"; - - case PAL_SHADER_TARGET_DXIL_6_1: - return "6.1"; - - case PAL_SHADER_TARGET_DXIL_6_2: - return "6.2"; - - case PAL_SHADER_TARGET_DXIL_6_3: - return "6.3"; - - case PAL_SHADER_TARGET_DXIL_6_4: - return "6.4"; - - case PAL_SHADER_TARGET_DXIL_6_5: - return "6.5"; - - case PAL_SHADER_TARGET_DXIL_6_6: - return "6.6"; - - case PAL_SHADER_TARGET_DXIL_6_7: - return "6.7"; - } - return nullptr; -} - bool graphicsTest() { // initialize the graphics system @@ -254,21 +200,40 @@ bool graphicsTest() palLog(nullptr, " Max compute work group size[2]: %u", caps.maxComputeWorkGroupSize[2]); // shader formats - PalShaderTarget target; + Uint32 target; + Uint32 targetMajor = 0; + Uint32 targetMinor = 0; + palLog(nullptr, ""); palLog(nullptr, " Supported Shader Formats:"); if (info.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { palLog(nullptr, " SPIRV"); - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - palLog(nullptr, " Highest Spirv Target %s:", shaderTargetToString(target)); + targetMajor = PAL_SHADER_TARGET_MAJOR(target); + targetMinor = PAL_SHADER_TARGET_MINOR(target); + + palLog(nullptr, " Highest Spirv Target: %u.%u", targetMajor, targetMinor); + palLog(nullptr, ""); } if (info.shaderFormats & PAL_SHADER_FORMAT_DXIL) { palLog(nullptr, " DXIL"); - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - palLog(nullptr, " Highest Dxil Target %s:", shaderTargetToString(target)); + targetMajor = PAL_SHADER_TARGET_MAJOR(target); + targetMinor = PAL_SHADER_TARGET_MINOR(target); + + palLog(nullptr, " Highest Dxil Target: %u.%u", targetMajor, targetMinor); + palLog(nullptr, ""); + } + + if (info.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + palLog(nullptr, " DXBC"); + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + targetMajor = PAL_SHADER_TARGET_MAJOR(target); + targetMinor = PAL_SHADER_TARGET_MINOR(target); + + palLog(nullptr, " Highest Dxbc Target: %u.%u", targetMajor, targetMinor); + palLog(nullptr, ""); } // features diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index d576a5ac..c719a8cf 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -176,7 +176,7 @@ bool meshTest() } if (hasMeshShader) { - // We want an adapter that supports spirv 1.5 or dxil 6.0 + // We want an adapter that supports spirv 1.5 or dxil 6.5 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -185,14 +185,17 @@ bool meshTest() } // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_5)) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 5)) { break; } } if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_5)) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 5)) { break; } } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 254ae80b..c1a54441 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -133,14 +133,17 @@ bool rayTracingTest() } // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_4)) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 4)) { break; } } if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_3)) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 3)) { break; } } diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 8cd877e9..b441bc26 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -216,14 +216,17 @@ bool textureTest() } // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { break; } } if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 07ffc976..a3ea62b9 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -182,14 +182,17 @@ bool triangleTest() } // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_SPIRV_1_0)) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { break; } } if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - if (palIsShaderTargetSupported(adapter, PAL_SHADER_TARGET_DXIL_6_0)) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } diff --git a/tests/tests_main.c b/tests/tests_main.c index f62e99aa..3c2d0110 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -64,9 +64,9 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); - // registerTest(triangleTest, "Triangle Test"); + registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); - registerTest(textureTest, "Texture Test"); + // registerTest(textureTest, "Texture Test"); #endif // runTests(); From 944e39355ac3384e5c4c03e626904477a4d43322 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 8 May 2026 14:32:38 +0000 Subject: [PATCH 207/372] add compute shader files --- tests/graphics/compute_test.c | 34 +- tests/graphics/shaders.h | 458 ----------------------- tests/graphics/shaders/dxbc/compute.cso | Bin 0 -> 1000 bytes tests/graphics/shaders/glsl/compute.glsl | 27 ++ tests/graphics/shaders/hlsl/compute.hlsl | 25 ++ tests/graphics/shaders/spirv/compute.spv | Bin 0 -> 1704 bytes tests/tests.h | 27 ++ tests/tests_main.c | 4 +- 8 files changed, 106 insertions(+), 469 deletions(-) create mode 100644 tests/graphics/shaders/dxbc/compute.cso create mode 100644 tests/graphics/shaders/glsl/compute.glsl create mode 100644 tests/graphics/shaders/hlsl/compute.hlsl create mode 100644 tests/graphics/shaders/spirv/compute.spv diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 205f581a..9730cdfa 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -105,7 +105,7 @@ bool computeTest() } if (hasComputeQueue) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 + // We want an adapter that supports spirv 1.0 or dxbc 5.1 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -122,9 +122,9 @@ bool computeTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { break; } } @@ -181,16 +181,30 @@ bool computeTest() // create a compute shader Uint64 bytecodeSize = 0; void* bytecode = nullptr; + const char* source = nullptr; + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - bytecode = (void*)s_ComputeShaderSpv; - bytecodeSize = sizeof(s_ComputeShaderSpv); + source = "graphics/shaders/spirv/compute.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + source = "graphics/shaders/dxbc/compute.cso"; + } + + // read file + if (!readFile(source, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - bytecode = (void*)s_ComputeShaderDxil; - bytecodeSize = sizeof(s_ComputeShaderDxil); + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; } + readFile(source, nullptr, &bytecodeSize); + // describe how many entries are in the shader bytecode // We only have one entry for the compute shader. PalShaderEntry computeEntry = {0}; @@ -209,6 +223,8 @@ bool computeTest() return false; } + palFree(nullptr, bytecode); + // create a storage buffer Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader PalBufferCreateInfo bufferCreateInfo = {0}; diff --git a/tests/graphics/shaders.h b/tests/graphics/shaders.h index 93899c8c..a35b107a 100644 --- a/tests/graphics/shaders.h +++ b/tests/graphics/shaders.h @@ -1,464 +1,6 @@ #include "pal/pal_core.h" -// clang-format off - -// ================================================== -// Compute -// ================================================== - -// GLSL -// #version 450 - -// layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -// layout(set = 0, binding = 0) buffer OutputBuffer -// { -// vec4 pixels[]; -// } outBuffer; - -// layout(push_constant) uniform PushConstants -// { -// uint width; -// uint height; -// vec4 color; -// } pc; - -// void main() -// { -// uvec2 id = gl_GlobalInvocationID.xy; -// if (id.x >= pc.width || id.y >= pc.height) { -// return; -// } - -// uint index = id.y * pc.width + id.x; -// outBuffer.pixels[index] = pc.color; -// } - -// HLSL -// struct PushConstants -// { -// uint width; -// uint height; -// float4 color; -// }; - -// We used raw Buffer but structured buffer can be used as well. -// PalDescriptorBufferInfo::stride must be set to 16 - -// RWByteAddressBuffer outBuffer : register(u0); -// ConstantBuffer pc : register(b0); - -// [numThreads(16, 16, 1)] -// void main(uint3 id : SV_DispatchThreadID) -// { -// if (id.x >= pc.width || id.y >= pc.height) { -// return; -// } - -// uint index = id.y * pc.width + id.x; -// uint offset = index * 16; // sizeof(float4) -// outBuffer.Store4(offset, asuint(pc.color)); -// } - -static const Uint32 s_ComputeShaderSpv[] = { - 0x07230203, 0x00010000, 0x0008000b, 0x00000043, - 0x00000000, 0x00020011, 0x00000001, 0x0006000b, - 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, - 0x00000000, 0x0003000e, 0x00000000, 0x00000001, - 0x0006000f, 0x00000005, 0x00000004, 0x6e69616d, - 0x00000000, 0x0000000c, 0x00060010, 0x00000004, - 0x00000011, 0x00000010, 0x00000010, 0x00000001, - 0x00030003, 0x00000002, 0x000001c2, 0x00040005, - 0x00000004, 0x6e69616d, 0x00000000, 0x00030005, - 0x00000009, 0x00006469, 0x00080005, 0x0000000c, - 0x475f6c67, 0x61626f6c, 0x766e496c, 0x7461636f, - 0x496e6f69, 0x00000044, 0x00060005, 0x00000016, - 0x68737550, 0x736e6f43, 0x746e6174, 0x00000073, - 0x00050006, 0x00000016, 0x00000000, 0x74646977, - 0x00000068, 0x00050006, 0x00000016, 0x00000001, - 0x67696568, 0x00007468, 0x00050006, 0x00000016, - 0x00000002, 0x6f6c6f63, 0x00000072, 0x00030005, - 0x00000018, 0x00006370, 0x00040005, 0x0000002d, - 0x65646e69, 0x00000078, 0x00060005, 0x00000037, - 0x7074754f, 0x75427475, 0x72656666, 0x00000000, - 0x00050006, 0x00000037, 0x00000000, 0x65786970, - 0x0000736c, 0x00050005, 0x00000039, 0x4274756f, - 0x65666675, 0x00000072, 0x00040047, 0x0000000c, - 0x0000000b, 0x0000001c, 0x00030047, 0x00000016, - 0x00000002, 0x00050048, 0x00000016, 0x00000000, - 0x00000023, 0x00000000, 0x00050048, 0x00000016, - 0x00000001, 0x00000023, 0x00000004, 0x00050048, - 0x00000016, 0x00000002, 0x00000023, 0x00000010, - 0x00040047, 0x00000036, 0x00000006, 0x00000010, - 0x00030047, 0x00000037, 0x00000003, 0x00050048, - 0x00000037, 0x00000000, 0x00000023, 0x00000000, - 0x00040047, 0x00000039, 0x00000021, 0x00000000, - 0x00040047, 0x00000039, 0x00000022, 0x00000000, - 0x00040047, 0x00000042, 0x0000000b, 0x00000019, - 0x00020013, 0x00000002, 0x00030021, 0x00000003, - 0x00000002, 0x00040015, 0x00000006, 0x00000020, - 0x00000000, 0x00040017, 0x00000007, 0x00000006, - 0x00000002, 0x00040020, 0x00000008, 0x00000007, - 0x00000007, 0x00040017, 0x0000000a, 0x00000006, - 0x00000003, 0x00040020, 0x0000000b, 0x00000001, - 0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c, - 0x00000001, 0x00020014, 0x0000000f, 0x0004002b, - 0x00000006, 0x00000010, 0x00000000, 0x00040020, - 0x00000011, 0x00000007, 0x00000006, 0x00030016, - 0x00000014, 0x00000020, 0x00040017, 0x00000015, - 0x00000014, 0x00000004, 0x0005001e, 0x00000016, - 0x00000006, 0x00000006, 0x00000015, 0x00040020, - 0x00000017, 0x00000009, 0x00000016, 0x0004003b, - 0x00000017, 0x00000018, 0x00000009, 0x00040015, - 0x00000019, 0x00000020, 0x00000001, 0x0004002b, - 0x00000019, 0x0000001a, 0x00000000, 0x00040020, - 0x0000001b, 0x00000009, 0x00000006, 0x0004002b, - 0x00000006, 0x00000022, 0x00000001, 0x0004002b, - 0x00000019, 0x00000025, 0x00000001, 0x0003001d, - 0x00000036, 0x00000015, 0x0003001e, 0x00000037, - 0x00000036, 0x00040020, 0x00000038, 0x00000002, - 0x00000037, 0x0004003b, 0x00000038, 0x00000039, - 0x00000002, 0x0004002b, 0x00000019, 0x0000003b, - 0x00000002, 0x00040020, 0x0000003c, 0x00000009, - 0x00000015, 0x00040020, 0x0000003f, 0x00000002, - 0x00000015, 0x0004002b, 0x00000006, 0x00000041, - 0x00000010, 0x0006002c, 0x0000000a, 0x00000042, - 0x00000041, 0x00000041, 0x00000022, 0x00050036, - 0x00000002, 0x00000004, 0x00000000, 0x00000003, - 0x000200f8, 0x00000005, 0x0004003b, 0x00000008, - 0x00000009, 0x00000007, 0x0004003b, 0x00000011, - 0x0000002d, 0x00000007, 0x0004003d, 0x0000000a, - 0x0000000d, 0x0000000c, 0x0007004f, 0x00000007, - 0x0000000e, 0x0000000d, 0x0000000d, 0x00000000, - 0x00000001, 0x0003003e, 0x00000009, 0x0000000e, - 0x00050041, 0x00000011, 0x00000012, 0x00000009, - 0x00000010, 0x0004003d, 0x00000006, 0x00000013, - 0x00000012, 0x00050041, 0x0000001b, 0x0000001c, - 0x00000018, 0x0000001a, 0x0004003d, 0x00000006, - 0x0000001d, 0x0000001c, 0x000500ae, 0x0000000f, - 0x0000001e, 0x00000013, 0x0000001d, 0x000400a8, - 0x0000000f, 0x0000001f, 0x0000001e, 0x000300f7, - 0x00000021, 0x00000000, 0x000400fa, 0x0000001f, - 0x00000020, 0x00000021, 0x000200f8, 0x00000020, - 0x00050041, 0x00000011, 0x00000023, 0x00000009, - 0x00000022, 0x0004003d, 0x00000006, 0x00000024, - 0x00000023, 0x00050041, 0x0000001b, 0x00000026, - 0x00000018, 0x00000025, 0x0004003d, 0x00000006, - 0x00000027, 0x00000026, 0x000500ae, 0x0000000f, - 0x00000028, 0x00000024, 0x00000027, 0x000200f9, - 0x00000021, 0x000200f8, 0x00000021, 0x000700f5, - 0x0000000f, 0x00000029, 0x0000001e, 0x00000005, - 0x00000028, 0x00000020, 0x000300f7, 0x0000002b, - 0x00000000, 0x000400fa, 0x00000029, 0x0000002a, - 0x0000002b, 0x000200f8, 0x0000002a, 0x000100fd, - 0x000200f8, 0x0000002b, 0x00050041, 0x00000011, - 0x0000002e, 0x00000009, 0x00000022, 0x0004003d, - 0x00000006, 0x0000002f, 0x0000002e, 0x00050041, - 0x0000001b, 0x00000030, 0x00000018, 0x0000001a, - 0x0004003d, 0x00000006, 0x00000031, 0x00000030, - 0x00050084, 0x00000006, 0x00000032, 0x0000002f, - 0x00000031, 0x00050041, 0x00000011, 0x00000033, - 0x00000009, 0x00000010, 0x0004003d, 0x00000006, - 0x00000034, 0x00000033, 0x00050080, 0x00000006, - 0x00000035, 0x00000032, 0x00000034, 0x0003003e, - 0x0000002d, 0x00000035, 0x0004003d, 0x00000006, - 0x0000003a, 0x0000002d, 0x00050041, 0x0000003c, - 0x0000003d, 0x00000018, 0x0000003b, 0x0004003d, - 0x00000015, 0x0000003e, 0x0000003d, 0x00060041, - 0x0000003f, 0x00000040, 0x00000039, 0x0000001a, - 0x0000003a, 0x0003003e, 0x00000040, 0x0000003e, - 0x000100fd, 0x00010038 -}; - -static const Uint8 s_ComputeShaderDxil[] = { - 0x44, 0x58, 0x42, 0x43, 0x3c, 0x03, 0x02, 0xb3, 0x0e, 0x59, 0xfb, 0x9b, - 0xc1, 0xd2, 0x75, 0x12, 0xb3, 0x0d, 0x3c, 0xd0, 0x01, 0x00, 0x00, 0x00, - 0x58, 0x0d, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0xf4, 0x00, 0x00, 0x00, 0x30, 0x07, 0x00, 0x00, 0x4c, 0x07, 0x00, 0x00, - 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x50, 0x53, 0x56, 0x30, 0x80, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0x34, 0x06, 0x00, 0x00, - 0x60, 0x00, 0x05, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, - 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x01, 0xd5, 0x06, 0x62, - 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x90, 0x00, 0x49, 0x18, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, - 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, - 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x74, 0x23, 0x00, 0x25, 0x00, 0x14, 0xe6, - 0x08, 0xc0, 0xa0, 0x0c, 0x63, 0x0c, 0x22, 0x33, 0x00, 0x47, 0x0d, 0x97, - 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0xdc, 0x46, 0x15, 0x2b, 0x31, 0xf9, 0xc5, - 0x6d, 0x23, 0xc2, 0x18, 0x63, 0xe6, 0x08, 0x10, 0x42, 0xf7, 0x0c, 0x97, - 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, 0x0c, 0x0b, 0x81, 0x82, 0x54, - 0x88, 0x33, 0xd4, 0xa0, 0x75, 0xd4, 0x70, 0xf9, 0x13, 0xf6, 0x10, 0x92, - 0xcf, 0x6d, 0x54, 0xb1, 0x12, 0x93, 0x8f, 0xdc, 0x36, 0x22, 0xc6, 0x18, - 0xa3, 0x10, 0x6d, 0xa8, 0x41, 0x6e, 0x8e, 0x20, 0x28, 0x86, 0x1a, 0x68, - 0x0c, 0x48, 0xb1, 0x28, 0x60, 0xa8, 0x31, 0xc6, 0x18, 0x03, 0xd1, 0x1c, - 0x08, 0x38, 0x4d, 0x9a, 0x22, 0x4a, 0x98, 0xfc, 0x15, 0xde, 0xb0, 0x89, - 0xd0, 0x86, 0x21, 0x22, 0x24, 0x69, 0xa3, 0x8a, 0x82, 0x88, 0x50, 0x30, - 0xc8, 0x0e, 0x23, 0x10, 0xc6, 0x51, 0xd2, 0x14, 0x51, 0xc2, 0xe4, 0xa7, - 0x94, 0x74, 0x70, 0x4e, 0x23, 0x4d, 0x40, 0x33, 0x49, 0x68, 0x18, 0x03, - 0x9f, 0xf0, 0x08, 0x28, 0xc8, 0xa4, 0xe7, 0x08, 0x40, 0x01, 0x00, 0x00, - 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, - 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, - 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, - 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, - 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, - 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, - 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x04, 0x10, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, - 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, - 0x89, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, - 0xc8, 0x33, 0x01, 0x01, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x16, 0x08, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, - 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, - 0x25, 0x30, 0x02, 0x50, 0x0c, 0x65, 0x51, 0x40, 0x65, 0x50, 0x0e, 0xa5, - 0x50, 0x08, 0x05, 0x52, 0x12, 0xa5, 0x51, 0x34, 0x45, 0x40, 0x70, 0x04, - 0x80, 0x78, 0x81, 0x50, 0x9e, 0x01, 0x20, 0x3d, 0x03, 0x40, 0x7b, 0x06, - 0x80, 0xee, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x74, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, - 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, - 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb1, 0xa9, 0x81, - 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, 0xcb, 0x09, 0x83, 0x49, - 0xd9, 0x10, 0x04, 0x13, 0x84, 0xc1, 0x98, 0x20, 0x0c, 0xc7, 0x06, 0x61, - 0x20, 0x36, 0x08, 0x04, 0x41, 0x61, 0x6c, 0x6e, 0x82, 0x30, 0x20, 0x1b, - 0x86, 0x03, 0x21, 0x26, 0x08, 0x57, 0xc6, 0xe4, 0xad, 0x8e, 0x4e, 0xa8, - 0xce, 0xcc, 0xac, 0x4c, 0x6e, 0x82, 0x30, 0x24, 0x13, 0x04, 0x88, 0xda, - 0xb0, 0x10, 0xca, 0x42, 0x10, 0x03, 0xd3, 0x34, 0x0d, 0xb0, 0x21, 0x70, - 0x26, 0x08, 0x1b, 0x46, 0x01, 0x6e, 0x6c, 0x82, 0x30, 0x28, 0x1b, 0x10, - 0x02, 0x8a, 0x08, 0x62, 0x90, 0x80, 0x0d, 0xc1, 0xb4, 0x81, 0x00, 0x1e, - 0x0a, 0x98, 0x20, 0x64, 0x16, 0x8b, 0xbb, 0x34, 0x32, 0x3a, 0xb4, 0x09, - 0xc2, 0xb0, 0x4c, 0x10, 0x06, 0x66, 0x82, 0x30, 0x34, 0x1b, 0x0c, 0xe4, - 0xc2, 0x88, 0x4c, 0xa3, 0x81, 0x56, 0x96, 0x76, 0x86, 0x46, 0x37, 0x41, - 0x18, 0x9c, 0x0d, 0x06, 0xc2, 0x61, 0x5d, 0xa6, 0xb1, 0x18, 0x7b, 0x63, - 0x7b, 0x93, 0x9b, 0x20, 0x0c, 0xcf, 0x04, 0x61, 0x80, 0x26, 0x08, 0x43, - 0xb4, 0x01, 0x41, 0x3e, 0x0c, 0x0c, 0xb2, 0x30, 0x10, 0x83, 0x6e, 0x03, - 0x21, 0x6d, 0xde, 0x18, 0x4c, 0x10, 0xb4, 0x6b, 0x03, 0x81, 0x44, 0x18, - 0xb1, 0x41, 0x90, 0xcc, 0x60, 0x43, 0x41, 0x58, 0x64, 0x50, 0x06, 0x67, - 0x30, 0x41, 0x10, 0x80, 0x0d, 0xc0, 0x86, 0x81, 0x50, 0x03, 0x35, 0xd8, - 0x10, 0xac, 0xc1, 0x86, 0x61, 0x48, 0x03, 0x36, 0x20, 0xd1, 0x16, 0x96, - 0xe6, 0x36, 0x41, 0xe0, 0xaa, 0x0d, 0x03, 0x18, 0x80, 0xc1, 0xb0, 0x81, - 0x20, 0xde, 0xa0, 0x83, 0x83, 0x0d, 0x45, 0x1a, 0xb8, 0x01, 0x50, 0xc5, - 0x01, 0x11, 0x31, 0xb9, 0x30, 0xb7, 0x31, 0xb4, 0xb2, 0x39, 0x16, 0x69, - 0x6e, 0x73, 0x74, 0x73, 0x13, 0x84, 0x41, 0x22, 0x91, 0xe6, 0x46, 0x37, - 0xc7, 0x84, 0xae, 0x0c, 0xef, 0x6b, 0x8e, 0xee, 0x4d, 0xae, 0x8c, 0x45, - 0x5d, 0x9a, 0x1b, 0xdd, 0xdc, 0x04, 0x61, 0x98, 0x36, 0x28, 0x73, 0x30, - 0xd0, 0x41, 0x1d, 0xd8, 0x41, 0x77, 0x07, 0x03, 0x1e, 0xe4, 0x41, 0x15, - 0x36, 0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37, 0xba, 0x29, 0x41, - 0x50, 0x85, 0x0c, 0xcf, 0xc5, 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, 0x6d, - 0x4a, 0x40, 0x34, 0x21, 0xc3, 0x73, 0xb1, 0x0b, 0x63, 0xb3, 0x2b, 0x93, - 0x9b, 0x12, 0x14, 0x75, 0xc8, 0xf0, 0x5c, 0xe6, 0xd0, 0xc2, 0xc8, 0xca, - 0xe4, 0x9a, 0xde, 0xc8, 0xca, 0xd8, 0xa6, 0x04, 0x48, 0x19, 0x32, 0x3c, - 0x17, 0xb9, 0xb2, 0xb9, 0xb7, 0x3a, 0xb9, 0xb1, 0xb2, 0xb9, 0x29, 0x01, - 0x55, 0x89, 0x0c, 0xcf, 0x85, 0x2e, 0x0f, 0xae, 0x2c, 0xc8, 0xcd, 0xed, - 0x8d, 0x2e, 0x8c, 0x2e, 0xed, 0xcd, 0x6d, 0x6e, 0x8a, 0x70, 0x06, 0x6c, - 0x50, 0x87, 0x0c, 0xcf, 0xa5, 0xcc, 0x8d, 0x4e, 0x2e, 0x0f, 0xea, 0x2d, - 0xcd, 0x8d, 0x6e, 0x6e, 0x4a, 0x10, 0x07, 0x5d, 0xc8, 0xf0, 0x5c, 0xc6, - 0xde, 0xea, 0xdc, 0xe8, 0xca, 0xe4, 0xe6, 0xa6, 0x04, 0x79, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, - 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, - 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, - 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, - 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, - 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, - 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, - 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, - 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, - 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, - 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, - 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, - 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, - 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, - 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, - 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, - 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, - 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, - 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, - 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, - 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, - 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, - 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, - 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, - 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, - 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x30, 0x83, 0x81, - 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, 0x1c, 0xc2, 0x61, 0x1d, - 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x56, 0x50, 0x0d, 0x97, 0xef, 0x3c, 0x7e, 0x40, - 0x15, 0x05, 0x11, 0xb1, 0x93, 0x13, 0x11, 0x3e, 0x72, 0xdb, 0x26, 0xb0, - 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, 0x41, 0x44, 0xa5, 0x03, - 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, 0x6d, 0x03, 0xdb, 0x70, - 0xf9, 0xce, 0xe3, 0x0b, 0x01, 0x55, 0x14, 0x44, 0x54, 0x3a, 0xc0, 0x50, - 0x12, 0x06, 0x20, 0x60, 0x3e, 0x72, 0xdb, 0x46, 0x20, 0x0d, 0x97, 0xef, - 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, 0x33, 0x2c, 0x84, 0x05, - 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x1d, 0x11, 0x01, 0x0c, 0xe2, 0xe0, - 0x23, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x6f, 0xb0, 0x69, 0x56, 0x40, 0x84, 0x26, 0xed, - 0x85, 0x8e, 0xc5, 0x2c, 0x46, 0xd0, 0xbf, 0x12, 0x44, 0x58, 0x49, 0x4c, - 0x04, 0x06, 0x00, 0x00, 0x60, 0x00, 0x05, 0x00, 0x81, 0x01, 0x00, 0x00, - 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0xec, 0x05, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, - 0x78, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, - 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, - 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, - 0xa4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, - 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, - 0xe4, 0x48, 0x0e, 0x90, 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, - 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, - 0x40, 0x02, 0xa8, 0x0d, 0x86, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, - 0x01, 0xd5, 0x06, 0x62, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x90, 0x00, - 0x49, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, - 0x20, 0x4c, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, - 0x93, 0x22, 0xa4, 0x84, 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, - 0x12, 0x4c, 0x8a, 0x8c, 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x78, 0x23, 0x00, - 0x25, 0x00, 0x14, 0xe6, 0x08, 0xc0, 0xa0, 0x0c, 0x63, 0x0c, 0x22, 0x33, - 0x00, 0x47, 0x0d, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0xdc, 0x46, 0x15, - 0x2b, 0x31, 0xf9, 0xc5, 0x6d, 0x23, 0xc2, 0x18, 0x63, 0xe6, 0x08, 0x10, - 0x42, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, 0x0c, - 0x0b, 0x81, 0x82, 0x54, 0x88, 0x33, 0xd4, 0xa0, 0x75, 0xd4, 0x70, 0xf9, - 0x13, 0xf6, 0x10, 0x92, 0xcf, 0x6d, 0x54, 0xb1, 0x12, 0x93, 0x8f, 0xdc, - 0x36, 0x22, 0xc6, 0x18, 0xa3, 0x10, 0x6d, 0xa8, 0x41, 0x6e, 0x8e, 0x20, - 0x28, 0x86, 0x1a, 0x68, 0x0c, 0x48, 0xb1, 0x28, 0x60, 0xa8, 0x31, 0xc6, - 0x18, 0x03, 0xd1, 0x1c, 0x08, 0x38, 0x4d, 0x9a, 0x22, 0x4a, 0x98, 0xfc, - 0x15, 0xde, 0xb0, 0x89, 0xd0, 0x86, 0x21, 0x22, 0x24, 0x69, 0xa3, 0x8a, - 0x82, 0x88, 0x50, 0x30, 0xc8, 0x0e, 0x23, 0x10, 0xc6, 0x51, 0xd2, 0x14, - 0x51, 0xc2, 0xe4, 0xa7, 0x94, 0x74, 0x70, 0x4e, 0x23, 0x4d, 0x40, 0x33, - 0x49, 0x68, 0x18, 0x03, 0x9f, 0xf0, 0x08, 0x28, 0xc8, 0xa4, 0xe7, 0x08, - 0x40, 0x61, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, - 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, - 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, - 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, - 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, - 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, - 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, - 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, - 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, - 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, - 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x86, 0x3c, 0x04, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x16, 0x20, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x89, 0x80, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc8, 0x33, 0x01, 0x01, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x16, 0x08, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, - 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x1a, 0x25, 0x30, 0x02, 0x50, - 0x12, 0xc5, 0x50, 0x16, 0x05, 0x54, 0x08, 0x05, 0x42, 0x70, 0x04, 0x80, - 0x78, 0x81, 0xd0, 0x9e, 0x01, 0xa0, 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, - 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, - 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, - 0xa1, 0xb1, 0xa9, 0x81, 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, - 0xcb, 0x09, 0x83, 0x49, 0xd9, 0x10, 0x04, 0x13, 0x84, 0xc1, 0x98, 0x20, - 0x0c, 0xc7, 0x06, 0x61, 0x20, 0x26, 0x08, 0x03, 0xb2, 0x41, 0x18, 0x0c, - 0x0a, 0x63, 0x73, 0x13, 0x84, 0x21, 0xd9, 0x30, 0x20, 0x09, 0x31, 0x41, - 0xb8, 0x22, 0x02, 0x13, 0x84, 0x41, 0x99, 0x20, 0x40, 0xce, 0x86, 0x85, - 0x58, 0x18, 0x82, 0x18, 0x1a, 0xc7, 0x71, 0x80, 0x0d, 0xc1, 0x33, 0x41, - 0xd8, 0xa0, 0x09, 0xc2, 0xb0, 0x6c, 0x40, 0x88, 0x88, 0x21, 0x88, 0x41, - 0x02, 0x36, 0x04, 0xd3, 0x06, 0x02, 0x80, 0x28, 0x60, 0x82, 0x20, 0x00, - 0x24, 0xda, 0xc2, 0xd2, 0xdc, 0x26, 0x08, 0xdc, 0x33, 0x41, 0x18, 0x98, - 0x09, 0xc2, 0xd0, 0x6c, 0x18, 0x34, 0x6d, 0xd8, 0x40, 0x10, 0x58, 0xb6, - 0x6d, 0x28, 0xac, 0x0b, 0xa8, 0xb8, 0x2a, 0x6c, 0x6c, 0x76, 0x6d, 0x2e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, 0x9e, 0x8b, - 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, 0x42, 0x86, - 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26, 0x37, 0x25, 0x30, 0xea, 0x90, - 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, 0x91, 0x95, - 0xb1, 0x4d, 0x09, 0x92, 0x32, 0x64, 0x78, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x53, 0x02, 0xaa, 0x0e, 0x19, 0x9e, 0x4b, - 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, - 0x80, 0x03, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, - 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, - 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, - 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, - 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, - 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, - 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, - 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, - 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, - 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, - 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, - 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, - 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, - 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, - 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, - 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, - 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, - 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, - 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, - 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, - 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, - 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, - 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, - 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, - 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, - 0xf4, 0x30, 0x83, 0x81, 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, - 0x1c, 0xc2, 0x61, 0x1d, 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, - 0x71, 0x20, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x56, 0x50, 0x0d, 0x97, - 0xef, 0x3c, 0x7e, 0x40, 0x15, 0x05, 0x11, 0xb1, 0x93, 0x13, 0x11, 0x3e, - 0x72, 0xdb, 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x50, 0x45, - 0x41, 0x44, 0xa5, 0x03, 0x0c, 0x25, 0x61, 0x00, 0x02, 0xe6, 0x17, 0xb7, - 0x6d, 0x03, 0xdb, 0x70, 0xf9, 0xce, 0xe3, 0x0b, 0x01, 0x55, 0x14, 0x44, - 0x54, 0x3a, 0xc0, 0x50, 0x12, 0x06, 0x20, 0x60, 0x3e, 0x72, 0xdb, 0x46, - 0x20, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, - 0x33, 0x2c, 0x84, 0x05, 0x48, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x1d, 0x11, - 0x01, 0x0c, 0xe2, 0xe0, 0x23, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x13, 0x04, 0x43, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x34, 0x4a, 0xae, 0x74, 0x03, 0xca, 0xae, 0x14, 0x03, 0x66, 0x00, 0x08, - 0x95, 0x40, 0x11, 0x94, 0x07, 0x00, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, - 0x82, 0x60, 0x10, 0x59, 0xc8, 0x30, 0x4d, 0xcc, 0x88, 0x41, 0x02, 0x80, - 0x20, 0x18, 0x44, 0x57, 0x32, 0x50, 0x54, 0x33, 0x62, 0x60, 0x00, 0x20, - 0x08, 0x06, 0xc4, 0x96, 0x54, 0x23, 0x06, 0x06, 0x00, 0x82, 0x60, 0x40, - 0x70, 0xca, 0x35, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0xa6, 0x0c, - 0xd7, 0x68, 0x42, 0x00, 0x0c, 0x37, 0x10, 0x01, 0x19, 0x8c, 0x26, 0x0c, - 0xc1, 0x70, 0x43, 0x11, 0x90, 0x41, 0x0d, 0x81, 0xce, 0x32, 0x04, 0x42, - 0x50, 0xc5, 0x21, 0x15, 0x24, 0x50, 0x81, 0x76, 0x23, 0x06, 0x07, 0x00, - 0x82, 0x60, 0xb0, 0x94, 0xc1, 0xc4, 0x84, 0xc1, 0x68, 0x42, 0x00, 0x8c, - 0x26, 0x08, 0xc1, 0x68, 0xc2, 0x20, 0x8c, 0x26, 0x10, 0xc3, 0x11, 0x63, - 0x8f, 0x18, 0x7b, 0xc4, 0xd8, 0x23, 0xc6, 0x8e, 0x18, 0x34, 0x00, 0x08, - 0x82, 0xc1, 0xb4, 0x06, 0x9b, 0xa5, 0x68, 0xc4, 0x20, 0x04, 0xd7, 0x2c, - 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - // ================================================== // Ray Tracing // ================================================== diff --git a/tests/graphics/shaders/dxbc/compute.cso b/tests/graphics/shaders/dxbc/compute.cso new file mode 100644 index 0000000000000000000000000000000000000000..1c567c58ed01d0e490d8b0b93ffc3732b663858c GIT binary patch literal 1000 zcmcgq%_{_97=Okt*5)7*Nf}wSQnK4B2MN1osr5MytCZG$nAPxVW;RzRrR0Q*l!ILM zAK))=@fUDWE>4PzBfn>NUe>sK>NmgVeZJr4okV&ne(OK%IJi^B9!^h39@Ei7g@|5! zMD^ep5U3;S1j0ZH_T|L1c8?&Ay98jSF+i!;pKYB$*hL8346qyl0iXfk zI#OzNww+0bhrMy4G)S!S|= pc.width || id.y >= pc.height) { + return; + } + + uint index = id.y * pc.width + id.x; + outBuffer.pixels[index] = pc.color; +} \ No newline at end of file diff --git a/tests/graphics/shaders/hlsl/compute.hlsl b/tests/graphics/shaders/hlsl/compute.hlsl new file mode 100644 index 00000000..d9e0fa41 --- /dev/null +++ b/tests/graphics/shaders/hlsl/compute.hlsl @@ -0,0 +1,25 @@ + +struct PushConstants +{ + uint width; + uint height; + float4 color; +}; + +PushConstants pc; + +// We used raw Buffer but structured buffer can be used as well. +// PalDescriptorBufferInfo::stride must be set to 16 +RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 + +[numthreads(16, 16, 1)] +void main(uint3 id : SV_DispatchThreadID) +{ + if (id.x >= pc.width || id.y >= pc.height) { + return; + } + + uint index = id.y * pc.width + id.x; + uint offset = index * 16; // sizeof(float4) + outBuffer.Store4(offset, asuint(pc.color)); +} \ No newline at end of file diff --git a/tests/graphics/shaders/spirv/compute.spv b/tests/graphics/shaders/spirv/compute.spv new file mode 100644 index 0000000000000000000000000000000000000000..092f9b3fa93a89131beb8fdebe782f44aaedde4a GIT binary patch literal 1704 zcmZ9L+fGwa5QaC@Rul!1lP9o%XB1HZQRHk=Nk}m90ZgTZ?xeQF?kbmF_%L4i5WbV~ zkeK*=yL-ik)l6pQpVPl*t>$`XPDfEs)F1Ul+fnBXMZF*qSRvJ=-8Z{)t)w!yusCnV zK$J@p%^4&ok3NOGFUJi7=a38FVneB|@05tj9NnYnJ5HXA?z%j&GsNPGvA(p=Vf}5X z-h5ZC?=(I(_sdD#Z0x)wCr|$|^y_x3w%u&Bl5!(y;mbzc^C_+*HFUt7U#rH4wd6l0 zm;GkF`2p?xOX#Eh4z~x`aidZ_PGg1WDSEG+9JQ0J_Q65blC-zD=O{j|)*+GS_YA+; zm003S-Ag}m4SChYa|YiNFnNl(n}Eqv%srOi={JhmcL`lUjF}(!gudpB$OMe;k+W^8OP@lrI_&|eji#)F@6?pjXjLpzXuUt$$a-C zHo}xa^elMzF5I-v_Y`K0(QPEfJ2OVH_1)WKwqNTNW6m8%`^Ma#bM?J*F~7@iE+X=9 zzWx=&WBpaMx%LeFrm?&8Z)W}k{Ja}yPhxuq`u15yyDKqy=zA|>VeU%ioBsm4!?9Dp zp2h4Pcx+<(2JXYoy>205iX4~NiT&M=$Gi9i;{R6;-kCGpufDtXKcK&gZ_o3H_p}Ep zK9FJJo*rb4&h|03Nq75PM8xE0FZVZ$h@0bH{a<(&?mOg6WcW97d=rz1b>d&?BX%7T z|H<4bwC4{o@ggGTcWMVdGuZNRFJaaVZ1KS77Pfr6&yaH)TRiZ&gKeGoZ)Sv9>K|-K zes>Z1xo7i>h+JpU9=V!x4-u2A_FuNCEf#psVV~sv5KKJqp2t49$46k|Utr+QRd>dp?9*~32}(qydw literal 0 HcmV?d00001 diff --git a/tests/tests.h b/tests/tests.h index d0a92c02..12565bc2 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -10,6 +10,33 @@ typedef bool (*TestFn)(); void registerTest(TestFn func, const char* name); void runTests(); +static bool readFile( + const char* filename, + void* buffer, + Uint64* size) +{ + FILE* file = fopen(filename, "rb"); + if (!file) { + return false; + } + + fseek(file, 0, SEEK_END); + Uint64 tmpSize = ftell(file); + fseek(file, 0, SEEK_SET); + + if (buffer) { + tmpSize = *size; + size_t read = fread(buffer, 1, tmpSize, file); + if (read != tmpSize) { + return false; + } + } + + fclose(file); + *size = tmpSize; + return true; +} + // core tests bool loggerTest(); bool timeTest(); diff --git a/tests/tests_main.c b/tests/tests_main.c index 3c2d0110..b0359452 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,13 +58,13 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - // registerTest(computeTest, "Compute Test"); + registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); - registerTest(triangleTest, "Triangle Test"); + // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); #endif // From d3e8cba7de0d1a71ac291ae247590b63c9565140 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 8 May 2026 19:45:39 +0000 Subject: [PATCH 208/372] add tests shader files --- .gitignore | 4 +- src/graphics/pal_d3d12.c | 24 +- tests/graphics/compute_test.c | 18 +- tests/graphics/graphics_test.c | 10 - tests/graphics/mesh_test.c | 48 +- tests/graphics/ray_tracing_test.c | 126 +- tests/graphics/shaders.h | 3075 ----------------- tests/graphics/shaders/bin/compute.dxil | Bin 0 -> 3464 bytes tests/graphics/shaders/bin/compute.spv | Bin 0 -> 1820 bytes tests/graphics/shaders/bin/mesh.dxil | Bin 0 -> 3264 bytes tests/graphics/shaders/bin/mesh.spv | Bin 0 -> 1464 bytes tests/graphics/shaders/bin/ray_tracing.dxil | Bin 0 -> 5424 bytes tests/graphics/shaders/bin/ray_tracing.spv | Bin 0 -> 2740 bytes tests/graphics/shaders/bin/texture_frag.dxil | Bin 0 -> 3824 bytes tests/graphics/shaders/bin/texture_frag.spv | Bin 0 -> 756 bytes tests/graphics/shaders/bin/texture_vert.dxil | Bin 0 -> 3112 bytes tests/graphics/shaders/bin/texture_vert.spv | Bin 0 -> 620 bytes tests/graphics/shaders/bin/triangle_frag.dxil | Bin 0 -> 2960 bytes tests/graphics/shaders/bin/triangle_frag.spv | Bin 0 -> 376 bytes tests/graphics/shaders/bin/triangle_vert.dxil | Bin 0 -> 3160 bytes tests/graphics/shaders/bin/triangle_vert.spv | Bin 0 -> 720 bytes tests/graphics/shaders/dxbc/compute.cso | Bin 1000 -> 0 bytes tests/graphics/shaders/glsl/compute.glsl | 27 - tests/graphics/shaders/hlsl/compute.hlsl | 25 - tests/graphics/shaders/spirv/compute.spv | Bin 1704 -> 0 bytes tests/graphics/shaders/src/compute.hlsl | 54 + tests/graphics/shaders/src/mesh.hlsl | 56 + tests/graphics/shaders/src/ray_tracing.hlsl | 124 + tests/graphics/shaders/src/texture_frag.hlsl | 30 + tests/graphics/shaders/src/texture_vert.hlsl | 35 + tests/graphics/shaders/src/triangle_frag.hlsl | 24 + tests/graphics/shaders/src/triangle_vert.hlsl | 35 + tests/graphics/texture_test.c | 70 +- tests/graphics/triangle_test.c | 62 +- tests/tests_main.c | 8 +- 35 files changed, 559 insertions(+), 3296 deletions(-) create mode 100644 tests/graphics/shaders/bin/compute.dxil create mode 100644 tests/graphics/shaders/bin/compute.spv create mode 100644 tests/graphics/shaders/bin/mesh.dxil create mode 100644 tests/graphics/shaders/bin/mesh.spv create mode 100644 tests/graphics/shaders/bin/ray_tracing.dxil create mode 100644 tests/graphics/shaders/bin/ray_tracing.spv create mode 100644 tests/graphics/shaders/bin/texture_frag.dxil create mode 100644 tests/graphics/shaders/bin/texture_frag.spv create mode 100644 tests/graphics/shaders/bin/texture_vert.dxil create mode 100644 tests/graphics/shaders/bin/texture_vert.spv create mode 100644 tests/graphics/shaders/bin/triangle_frag.dxil create mode 100644 tests/graphics/shaders/bin/triangle_frag.spv create mode 100644 tests/graphics/shaders/bin/triangle_vert.dxil create mode 100644 tests/graphics/shaders/bin/triangle_vert.spv delete mode 100644 tests/graphics/shaders/dxbc/compute.cso delete mode 100644 tests/graphics/shaders/glsl/compute.glsl delete mode 100644 tests/graphics/shaders/hlsl/compute.hlsl delete mode 100644 tests/graphics/shaders/spirv/compute.spv create mode 100644 tests/graphics/shaders/src/compute.hlsl create mode 100644 tests/graphics/shaders/src/mesh.hlsl create mode 100644 tests/graphics/shaders/src/ray_tracing.hlsl create mode 100644 tests/graphics/shaders/src/texture_frag.hlsl create mode 100644 tests/graphics/shaders/src/texture_vert.hlsl create mode 100644 tests/graphics/shaders/src/triangle_frag.hlsl create mode 100644 tests/graphics/shaders/src/triangle_vert.hlsl diff --git a/.gitignore b/.gitignore index 944ea572..25665d4f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,8 @@ **.vs # Binaries -**bin -**build +/bin/ +/build/ # MakeFiles Makefile diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index e8ce5e85..4d08860a 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2171,7 +2171,7 @@ PalResult PAL_CALL getAdapterInfoD3D12( info->vendorId = desc.VendorId; info->deviceId= desc.DeviceId; info->apiType = PAL_ADAPTER_API_TYPE_D3D12; - info->shaderFormats = PAL_SHADER_FORMAT_DXIL | PAL_SHADER_FORMAT_DXBC; + info->shaderFormats = PAL_SHADER_FORMAT_DXIL; info->sharedMemory = desc.SharedSystemMemory; strcpy(info->backendName, "PAL"); @@ -2403,8 +2403,7 @@ Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( PalAdapter* adapter, PalShaderFormats shaderFormat) { - bool isDxil = shaderFormat == PAL_SHADER_FORMAT_DXIL; - if (!isDxil && shaderFormat != PAL_SHADER_FORMAT_DXBC) { + if (shaderFormat != PAL_SHADER_FORMAT_DXIL) { return 0; } @@ -2420,7 +2419,6 @@ Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( models[5] = D3D_SHADER_MODEL_6_2; models[6] = D3D_SHADER_MODEL_6_1; models[7] = D3D_SHADER_MODEL_6_0; - models[8] = D3D_SHADER_MODEL_5_1; // find the highest supported shader model HRESULT result = 0; @@ -2439,12 +2437,8 @@ Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( } } - if (shaderFormat == PAL_SHADER_FORMAT_DXBC) { - if (highestModel >= D3D_SHADER_MODEL_5_1) { - return PAL_MAKE_SHADER_TARGET(5, 1); - } else { - return 0; - } + if (highestModel == D3D_SHADER_MODEL_5_1) { + return 0; } if (highestModel >= D3D_SHADER_MODEL_6_7) { @@ -6981,7 +6975,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( D3D12_DESCRIPTOR_RANGE1* ranges = nullptr; D3D12_DESCRIPTOR_RANGE1* samplerRanges = nullptr; - Uint32 parameterCount = info->descriptorSetLayoutCount; + Uint32 parameterCount = 0; D3D12_ROOT_PARAMETER1* parameters = nullptr; if (info->descriptorSetLayoutCount > d3dDevice->limits.maxBoundDescriptorSets) { @@ -6993,6 +6987,14 @@ PalResult PAL_CALL createPipelineLayoutD3D12( DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; resourceCount += tmp->bindingCount - tmp->samplerCount; samplerCount += tmp->samplerCount; + + if (tmp->bindingCount - tmp->samplerCount >= 1) { + parameterCount++; + } + + if (tmp->samplerCount >= 1) { + parameterCount++; + } } // get the total size needed for all provided push constant range diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 9730cdfa..c28ae9ce 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -105,7 +105,7 @@ bool computeTest() } if (hasComputeQueue) { - // We want an adapter that supports spirv 1.0 or dxbc 5.1 + // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -122,9 +122,9 @@ bool computeTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } @@ -185,10 +185,10 @@ bool computeTest() PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - source = "graphics/shaders/spirv/compute.spv"; + source = "graphics/shaders/bin/compute.spv"; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - source = "graphics/shaders/dxbc/compute.cso"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + source = "graphics/shaders/bin/compute.dxil"; } // read file @@ -203,12 +203,12 @@ bool computeTest() return false; } - readFile(source, nullptr, &bytecodeSize); + readFile(source, bytecode, &bytecodeSize); // describe how many entries are in the shader bytecode // We only have one entry for the compute shader. PalShaderEntry computeEntry = {0}; - computeEntry.entryName = "main"; + computeEntry.entryName = "computeMain"; computeEntry.stage = PAL_SHADER_STAGE_COMPUTE; shaderCreateInfo.bytecode = bytecode; diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 88948f8d..8b35b500 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -226,16 +226,6 @@ bool graphicsTest() palLog(nullptr, ""); } - if (info.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - palLog(nullptr, " DXBC"); - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - targetMajor = PAL_SHADER_TARGET_MAJOR(target); - targetMinor = PAL_SHADER_TARGET_MINOR(target); - - palLog(nullptr, " Highest Dxbc Target: %u.%u", targetMajor, targetMinor); - palLog(nullptr, ""); - } - // features palLog(nullptr, ""); palLog(nullptr, " Supported Features:"); diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index c719a8cf..914d6d43 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -401,33 +401,54 @@ bool meshTest() Uint64 fragBytecodeSize = 0; void* meshBytecode = nullptr; void* fragBytecode = nullptr; + const char* meshSource = nullptr; + const char* fragSource = nullptr; PalShaderCreateInfo meshShaderCreateInfo = {0}; PalShaderCreateInfo fragShaderCreateInfo = {0}; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - meshBytecodeSize = sizeof(s_MeshShaderSpv); - fragBytecodeSize = sizeof(s_TriangleFragShaderSpv); - - meshBytecode = (void*)s_MeshShaderSpv; - fragBytecode = (void*)s_TriangleFragShaderSpv; + meshSource = "graphics/shaders/bin/triangle_vert.spv"; + fragSource = "graphics/shaders/bin/triangle_frag.spv"; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - meshBytecodeSize = sizeof(s_MeshShaderDxil); - fragBytecodeSize = sizeof(s_TriangleFragShaderDxil); + meshSource = "graphics/shaders/bin/triangle_vert.dxil"; + fragSource = "graphics/shaders/bin/triangle_frag.dxil"; + } - meshBytecode = (void*)s_MeshShaderDxil; - fragBytecode = (void*)s_TriangleFragShaderDxil; + // read file + if (!readFile(meshSource, nullptr, &meshBytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; } + if (!readFile(fragSource, nullptr, &fragBytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } + + meshBytecode = palAllocate(nullptr, meshBytecodeSize, 0); + if (!meshBytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + fragBytecode = palAllocate(nullptr, fragBytecodeSize, 0); + if (!fragBytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(meshSource, meshBytecode, &meshBytecodeSize); + readFile(fragSource, fragBytecode, &fragBytecodeSize); + // describe how many entries are in the shader bytecode // For simplicity, we dont use one shader bytecode for all the shaders PalShaderEntry meshEntry = {0}; - meshEntry.entryName = "main"; + meshEntry.entryName = "meshMain"; meshEntry.stage = PAL_SHADER_STAGE_MESH; PalShaderEntry fragmentEntry = {0}; - fragmentEntry.entryName = "main"; + fragmentEntry.entryName = "fragMain"; fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; meshShaderCreateInfo.bytecode = meshBytecode; @@ -454,6 +475,9 @@ bool meshTest() return false; } + palFree(nullptr, meshBytecode); + palFree(nullptr, fragBytecode); + // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index c1a54441..22fba4b0 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -21,10 +21,7 @@ bool rayTracingTest() PalQueue* queue = nullptr; PalCommandPool* cmdPool = nullptr; PalCommandBuffer* cmdBuffer; - - PalShader* raygenShader = nullptr; - PalShader* missShader = nullptr; - PalShader* closestHitShader = nullptr; + PalShader* rayTracingShader = nullptr; PalBuffer* buffer = nullptr; PalBuffer* stagingBuffer = nullptr; @@ -201,86 +198,58 @@ bool rayTracingTest() return false; } - // create ray tracing shaders - Uint64 raygenBytecodeSize = 0; - Uint64 closestHitBytecodeSize = 0; - Uint64 missBytecodeSize = 0; - void* raygenBytecode = 0; - void* closestHitBytecode = 0; - void* missBytecode = 0; - - PalShaderCreateInfo raygenShaderCreateInfo = {0}; - PalShaderCreateInfo closestHitShaderCreateInfo = {0}; - PalShaderCreateInfo missShaderCreateInfo = {0}; + // create ray tracing shader + Uint64 bytecodeSize = 0; + void* bytecode = 0; + const char* source = nullptr; + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - raygenBytecodeSize = sizeof(s_RaygenShaderSpv); - closestHitBytecodeSize = sizeof(s_ClosestHitShaderSpv); - missBytecodeSize = sizeof(s_MissShaderSpv); - - raygenBytecode = (void*)s_RaygenShaderSpv; - closestHitBytecode = (void*)s_ClosestHitShaderSpv; - missBytecode = (void*)s_MissShaderSpv; + source = "graphics/shaders/bin/ray_tracing.spv"; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - raygenBytecodeSize = sizeof(s_RaygenShaderDxil); - closestHitBytecodeSize = sizeof(s_ClosestHitShaderDxil); - missBytecodeSize = sizeof(s_MissShaderDxil); - - raygenBytecode = (void*)s_RaygenShaderDxil; - closestHitBytecode = (void*)s_ClosestHitShaderDxil; - missBytecode = (void*)s_MissShaderDxil; + source = "graphics/shaders/bin/ray_tracing.dxil"; } - // describe how many entries are in the shader bytecode - // For simplicity, we dont use one shader bytecode for all the shaders - PalShaderEntry raygenEntry = {0}; - raygenEntry.entryName = "main"; - raygenEntry.stage = PAL_SHADER_STAGE_RAYGEN; + // read file + if (!readFile(source, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } - PalShaderEntry closestHitEntry = {0}; - closestHitEntry.entryName = "main"; - closestHitEntry.stage = PAL_SHADER_STAGE_CLOSEST_HIT; + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } - PalShaderEntry missEntry = {0}; - missEntry.entryName = "main"; - missEntry.stage = PAL_SHADER_STAGE_MISS; + readFile(source, bytecode, &bytecodeSize); - raygenShaderCreateInfo.bytecode = raygenBytecode; - raygenShaderCreateInfo.bytecodeSize = raygenBytecodeSize; - raygenShaderCreateInfo.entries = &raygenEntry; - raygenShaderCreateInfo.entryCount = 1; + // describe how many entries are in the shader bytecode + // For simplicity, we dont use one shader bytecode for all the shaders + PalShaderEntry shaderEntries[3]; + shaderEntries[0].entryName = "raygenMain"; + shaderEntries[0].stage = PAL_SHADER_STAGE_RAYGEN; - closestHitShaderCreateInfo.bytecode = closestHitBytecode; - closestHitShaderCreateInfo.bytecodeSize = closestHitBytecodeSize; - closestHitShaderCreateInfo.entries = &closestHitEntry; - closestHitShaderCreateInfo.entryCount = 1; + shaderEntries[1].entryName = "closestHitMain"; + shaderEntries[1].stage = PAL_SHADER_STAGE_CLOSEST_HIT; - missShaderCreateInfo.bytecode = missBytecode; - missShaderCreateInfo.bytecodeSize = missBytecodeSize; - missShaderCreateInfo.entries = &missEntry; - missShaderCreateInfo.entryCount = 1; + shaderEntries[2].entryName = "missMain"; + shaderEntries[2].stage = PAL_SHADER_STAGE_MISS; - result = palCreateShader(device, &raygenShaderCreateInfo, &raygenShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create raygen shader: %s", error); - return false; - } + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.entries = shaderEntries; + shaderCreateInfo.entryCount = 3; - result = palCreateShader(device, &closestHitShaderCreateInfo, &closestHitShader); + result = palCreateShader(device, &shaderCreateInfo, &rayTracingShader); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create closest hit shader: %s", error); + palLog(nullptr, "Failed to create ray tracing shader: %s", error); return false; } - result = palCreateShader(device, &missShaderCreateInfo, &missShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create miss shader: %s", error); - return false; - } + palFree(nullptr, bytecode); Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader PalBufferCreateInfo bufferCreateInfo = {0}; @@ -803,42 +772,36 @@ bool rayTracingTest() return false; } - // shader and shader groups - PalShader* shaders[3]; - shaders[0] = raygenShader; - shaders[1] = missShader; - shaders[2] = closestHitShader; - PalRayTracingShaderGroupCreateInfo shaderGroupCreateInfos[3] = {0}; shaderGroupCreateInfos[0].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; - shaderGroupCreateInfos[0].generalShaderIndex = 0; // must match raygen index + shaderGroupCreateInfos[0].generalShaderIndex = 0; // must match ray tracing shader index shaderGroupCreateInfos[0].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].generalEntryIndex = 0; // First shader entry shaderGroupCreateInfos[1].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; - shaderGroupCreateInfos[1].generalShaderIndex = 1; // must match miss index + shaderGroupCreateInfos[1].generalShaderIndex = 0; // must match ray tracing shader index shaderGroupCreateInfos[1].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; - shaderGroupCreateInfos[1].generalEntryIndex = 0; // First shader entry + shaderGroupCreateInfos[1].generalEntryIndex = 1; // Second shader entry shaderGroupCreateInfos[2].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT; - shaderGroupCreateInfos[2].closestHitShaderIndex = 2; // must match closest hit index + shaderGroupCreateInfos[2].closestHitShaderIndex = 0; // must match ray tracing shader index shaderGroupCreateInfos[2].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[2].generalShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[2].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; - shaderGroupCreateInfos[2].closestHitEntryIndex = 0; // First shader entry + shaderGroupCreateInfos[2].closestHitEntryIndex = 2; // Third shader entry // create a ray tracing pipeline PalRayTracingPipelineCreateInfo pipelineCreateInfo = {0}; pipelineCreateInfo.maxRecursionDepth = 1; pipelineCreateInfo.pipelineLayout = pipelineLayout; - pipelineCreateInfo.shaderCount = 3; + pipelineCreateInfo.shaderCount = 1; pipelineCreateInfo.shaderGroupCount = 3; pipelineCreateInfo.shaderGroups = shaderGroupCreateInfos; - pipelineCreateInfo.shaders = shaders; + pipelineCreateInfo.shaders = &rayTracingShader; result = palCreateRayTracingPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { @@ -1089,10 +1052,7 @@ bool rayTracingTest() palFreeMemory(device, tlasBufferMemory); palFreeMemory(device, scratchBufferMemory); - palDestroyShader(raygenShader); - palDestroyShader(missShader); - palDestroyShader(closestHitShader); - + palDestroyShader(rayTracingShader); palFreeCommandBuffer(cmdBuffer); palDestroyCommandPool(cmdPool); palDestroyQueue(queue); diff --git a/tests/graphics/shaders.h b/tests/graphics/shaders.h index a35b107a..3f2ff2d6 100644 --- a/tests/graphics/shaders.h +++ b/tests/graphics/shaders.h @@ -1,3080 +1,5 @@ -#include "pal/pal_core.h" -// ================================================== -// Ray Tracing -// ================================================== -// GLSL -// Raygen -// #version 460 -// #extension GL_EXT_ray_tracing : require -// layout(set = 0, binding = 0) buffer OutputBuffer -// { -// vec4 pixels[]; -// } outBuffer; -// layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; -// layout(location = 0) rayPayloadEXT vec3 payloadColor; - -// void main() -// { -// uvec2 pixel = gl_LaunchIDEXT.xy; -// uvec2 size = gl_LaunchSizeEXT.xy; -// payloadColor = vec3(0.0); - -// vec2 uv = (vec2(pixel) + 0.5) / vec2(size); -// vec2 ndcUv = uv * 2.0 - 1.0; -// vec3 origin = vec3(0.0, 0.0, -3.0); -// vec3 direction = normalize(vec3(ndcUv.x, ndcUv.y, 1.0)); - -// traceRayEXT( -// tlas, -// gl_RayFlagsOpaqueEXT, -// 0xFF, -// 0, -// 0, -// 0, -// origin, -// 0.001, -// direction, -// 1000.0, -// 0 -// ); - -// if (pixel.x >= size.x || pixel.y >= size.y) { -// return; -// } - -// uint index = pixel.y * size.x + pixel.x; -// outBuffer.pixels[index] = vec4(payloadColor, 1.0); -// } - -// Closest Hit -// #version 460 -// #extension GL_EXT_ray_tracing : require - -// layout(location = 0) rayPayloadInEXT vec3 payloadColor; - -// void main() -// { -// payloadColor = vec3(0.0, 1.0, 0.0); -// } - -// Miss -// #version 460 -// #extension GL_EXT_ray_tracing : require - -// layout(location = 0) rayPayloadInEXT vec3 payloadColor; - -// void main() -// { -// payloadColor = vec3(0.0); -// } - -// HLSL -// Raygen -// struct RayPayload -// { -// float3 color; -// }; - -// RWByteAddressBuffer outBuffer : register(u0); -// RaytracingAccelerationStructure tlas : register(t0); - -// [shader("raygeneration")] -// void main() -// { -// uint2 pixel = DispatchRaysIndex().xy; -// uint2 size = DispatchRaysDimensions().xy; -// RayPayload payload; -// payload.color = float3(0.0, 0.0, 0.0); - -// float2 uv = (float2(pixel) + 0.5) / float2(size); -// float2 ndcUv = uv * 2.0 - 1.0; - -// RayDesc desc; -// desc.Origin = float3(0.0, 0.0, -3.0);; -// desc.Direction = normalize(float3(ndcUv.x, ndcUv.y, 1.0));; -// desc.TMin = 0.001; -// desc.TMax = 1000.0; -// TraceRay(tlas, RAY_FLAG_NONE, 0xFF, 0, 0, 0, desc, payload); - -// if (pixel.x >= size.x || pixel.y >= size.y) { -// return; -// } - -// uint index = pixel.y * size.x + pixel.x; -// uint offset = index * 16; // sizeof(float4) -// float4 color = float4(payload.color, 1.0); -// outBuffer.Store4(offset, asuint(color)); -// } - -// Closest Hit -// struct RayPayload -// { -// float3 color; -// }; - -// struct HitAttributes -// { -// float2 unused; -// }; - -// [shader("closesthit")] -// void main( -// inout RayPayload payload, -// in HitAttributes attr) -// { -// payload.color = float3(0.0, 1.0, 0.0); -// } - -// Miss -// struct RayPayload -// { -// float3 color; -// }; - -// [shader("miss")] -// void main(inout RayPayload payload) -// { -// payload.color = float3(0.0, 0.0, 0.0); -// } - -static const Uint32 s_RaygenShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x0000006d, - 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, - 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, - 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, - 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, - 0x00000000, 0x00000001, 0x000a000f, 0x000014c1, - 0x00000004, 0x6e69616d, 0x00000000, 0x0000000c, - 0x00000010, 0x00000016, 0x0000003b, 0x00000064, - 0x00030003, 0x00000002, 0x000001cc, 0x00060004, - 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, - 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, - 0x00000000, 0x00040005, 0x00000009, 0x65786970, - 0x0000006c, 0x00060005, 0x0000000c, 0x4c5f6c67, - 0x636e7561, 0x45444968, 0x00005458, 0x00040005, - 0x0000000f, 0x657a6973, 0x00000000, 0x00070005, - 0x00000010, 0x4c5f6c67, 0x636e7561, 0x7a695368, - 0x54584565, 0x00000000, 0x00060005, 0x00000016, - 0x6c796170, 0x4364616f, 0x726f6c6f, 0x00000000, - 0x00030005, 0x0000001b, 0x00007675, 0x00040005, - 0x00000024, 0x5563646e, 0x00000076, 0x00040005, - 0x0000002c, 0x6769726f, 0x00006e69, 0x00050005, - 0x0000002f, 0x65726964, 0x6f697463, 0x0000006e, - 0x00040005, 0x0000003b, 0x73616c74, 0x00000000, - 0x00040005, 0x00000057, 0x65646e69, 0x00000078, - 0x00060005, 0x00000062, 0x7074754f, 0x75427475, - 0x72656666, 0x00000000, 0x00050006, 0x00000062, - 0x00000000, 0x65786970, 0x0000736c, 0x00050005, - 0x00000064, 0x4274756f, 0x65666675, 0x00000072, - 0x00040047, 0x0000000c, 0x0000000b, 0x000014c7, - 0x00040047, 0x00000010, 0x0000000b, 0x000014c8, - 0x00040047, 0x0000003b, 0x00000021, 0x00000001, - 0x00040047, 0x0000003b, 0x00000022, 0x00000000, - 0x00040047, 0x00000061, 0x00000006, 0x00000010, - 0x00030047, 0x00000062, 0x00000002, 0x00050048, - 0x00000062, 0x00000000, 0x00000023, 0x00000000, - 0x00040047, 0x00000064, 0x00000021, 0x00000000, - 0x00040047, 0x00000064, 0x00000022, 0x00000000, - 0x00020013, 0x00000002, 0x00030021, 0x00000003, - 0x00000002, 0x00040015, 0x00000006, 0x00000020, - 0x00000000, 0x00040017, 0x00000007, 0x00000006, - 0x00000002, 0x00040020, 0x00000008, 0x00000007, - 0x00000007, 0x00040017, 0x0000000a, 0x00000006, - 0x00000003, 0x00040020, 0x0000000b, 0x00000001, - 0x0000000a, 0x0004003b, 0x0000000b, 0x0000000c, - 0x00000001, 0x0004003b, 0x0000000b, 0x00000010, - 0x00000001, 0x00030016, 0x00000013, 0x00000020, - 0x00040017, 0x00000014, 0x00000013, 0x00000003, - 0x00040020, 0x00000015, 0x000014da, 0x00000014, - 0x0004003b, 0x00000015, 0x00000016, 0x000014da, - 0x0004002b, 0x00000013, 0x00000017, 0x00000000, - 0x0006002c, 0x00000014, 0x00000018, 0x00000017, - 0x00000017, 0x00000017, 0x00040017, 0x00000019, - 0x00000013, 0x00000002, 0x00040020, 0x0000001a, - 0x00000007, 0x00000019, 0x0004002b, 0x00000013, - 0x0000001e, 0x3f000000, 0x0004002b, 0x00000013, - 0x00000026, 0x40000000, 0x0004002b, 0x00000013, - 0x00000028, 0x3f800000, 0x00040020, 0x0000002b, - 0x00000007, 0x00000014, 0x0004002b, 0x00000013, - 0x0000002d, 0xc0400000, 0x0006002c, 0x00000014, - 0x0000002e, 0x00000017, 0x00000017, 0x0000002d, - 0x0004002b, 0x00000006, 0x00000030, 0x00000000, - 0x00040020, 0x00000031, 0x00000007, 0x00000013, - 0x0004002b, 0x00000006, 0x00000034, 0x00000001, - 0x000214dd, 0x00000039, 0x00040020, 0x0000003a, - 0x00000000, 0x00000039, 0x0004003b, 0x0000003a, - 0x0000003b, 0x00000000, 0x0004002b, 0x00000006, - 0x0000003d, 0x000000ff, 0x0004002b, 0x00000013, - 0x0000003f, 0x3a83126f, 0x0004002b, 0x00000013, - 0x00000041, 0x447a0000, 0x00040015, 0x00000042, - 0x00000020, 0x00000001, 0x0004002b, 0x00000042, - 0x00000043, 0x00000000, 0x00020014, 0x00000044, - 0x00040020, 0x00000045, 0x00000007, 0x00000006, - 0x00040017, 0x00000060, 0x00000013, 0x00000004, - 0x0003001d, 0x00000061, 0x00000060, 0x0003001e, - 0x00000062, 0x00000061, 0x00040020, 0x00000063, - 0x0000000c, 0x00000062, 0x0004003b, 0x00000063, - 0x00000064, 0x0000000c, 0x00040020, 0x0000006b, - 0x0000000c, 0x00000060, 0x00050036, 0x00000002, - 0x00000004, 0x00000000, 0x00000003, 0x000200f8, - 0x00000005, 0x0004003b, 0x00000008, 0x00000009, - 0x00000007, 0x0004003b, 0x00000008, 0x0000000f, - 0x00000007, 0x0004003b, 0x0000001a, 0x0000001b, - 0x00000007, 0x0004003b, 0x0000001a, 0x00000024, - 0x00000007, 0x0004003b, 0x0000002b, 0x0000002c, - 0x00000007, 0x0004003b, 0x0000002b, 0x0000002f, - 0x00000007, 0x0004003b, 0x00000045, 0x00000057, - 0x00000007, 0x0004003d, 0x0000000a, 0x0000000d, - 0x0000000c, 0x0007004f, 0x00000007, 0x0000000e, - 0x0000000d, 0x0000000d, 0x00000000, 0x00000001, - 0x0003003e, 0x00000009, 0x0000000e, 0x0004003d, - 0x0000000a, 0x00000011, 0x00000010, 0x0007004f, - 0x00000007, 0x00000012, 0x00000011, 0x00000011, - 0x00000000, 0x00000001, 0x0003003e, 0x0000000f, - 0x00000012, 0x0003003e, 0x00000016, 0x00000018, - 0x0004003d, 0x00000007, 0x0000001c, 0x00000009, - 0x00040070, 0x00000019, 0x0000001d, 0x0000001c, - 0x00050050, 0x00000019, 0x0000001f, 0x0000001e, - 0x0000001e, 0x00050081, 0x00000019, 0x00000020, - 0x0000001d, 0x0000001f, 0x0004003d, 0x00000007, - 0x00000021, 0x0000000f, 0x00040070, 0x00000019, - 0x00000022, 0x00000021, 0x00050088, 0x00000019, - 0x00000023, 0x00000020, 0x00000022, 0x0003003e, - 0x0000001b, 0x00000023, 0x0004003d, 0x00000019, - 0x00000025, 0x0000001b, 0x0005008e, 0x00000019, - 0x00000027, 0x00000025, 0x00000026, 0x00050050, - 0x00000019, 0x00000029, 0x00000028, 0x00000028, - 0x00050083, 0x00000019, 0x0000002a, 0x00000027, - 0x00000029, 0x0003003e, 0x00000024, 0x0000002a, - 0x0003003e, 0x0000002c, 0x0000002e, 0x00050041, - 0x00000031, 0x00000032, 0x00000024, 0x00000030, - 0x0004003d, 0x00000013, 0x00000033, 0x00000032, - 0x00050041, 0x00000031, 0x00000035, 0x00000024, - 0x00000034, 0x0004003d, 0x00000013, 0x00000036, - 0x00000035, 0x00060050, 0x00000014, 0x00000037, - 0x00000033, 0x00000036, 0x00000028, 0x0006000c, - 0x00000014, 0x00000038, 0x00000001, 0x00000045, - 0x00000037, 0x0003003e, 0x0000002f, 0x00000038, - 0x0004003d, 0x00000039, 0x0000003c, 0x0000003b, - 0x0004003d, 0x00000014, 0x0000003e, 0x0000002c, - 0x0004003d, 0x00000014, 0x00000040, 0x0000002f, - 0x000c115d, 0x0000003c, 0x00000034, 0x0000003d, - 0x00000030, 0x00000030, 0x00000030, 0x0000003e, - 0x0000003f, 0x00000040, 0x00000041, 0x00000016, - 0x00050041, 0x00000045, 0x00000046, 0x00000009, - 0x00000030, 0x0004003d, 0x00000006, 0x00000047, - 0x00000046, 0x00050041, 0x00000045, 0x00000048, - 0x0000000f, 0x00000030, 0x0004003d, 0x00000006, - 0x00000049, 0x00000048, 0x000500ae, 0x00000044, - 0x0000004a, 0x00000047, 0x00000049, 0x000400a8, - 0x00000044, 0x0000004b, 0x0000004a, 0x000300f7, - 0x0000004d, 0x00000000, 0x000400fa, 0x0000004b, - 0x0000004c, 0x0000004d, 0x000200f8, 0x0000004c, - 0x00050041, 0x00000045, 0x0000004e, 0x00000009, - 0x00000034, 0x0004003d, 0x00000006, 0x0000004f, - 0x0000004e, 0x00050041, 0x00000045, 0x00000050, - 0x0000000f, 0x00000034, 0x0004003d, 0x00000006, - 0x00000051, 0x00000050, 0x000500ae, 0x00000044, - 0x00000052, 0x0000004f, 0x00000051, 0x000200f9, - 0x0000004d, 0x000200f8, 0x0000004d, 0x000700f5, - 0x00000044, 0x00000053, 0x0000004a, 0x00000005, - 0x00000052, 0x0000004c, 0x000300f7, 0x00000055, - 0x00000000, 0x000400fa, 0x00000053, 0x00000054, - 0x00000055, 0x000200f8, 0x00000054, 0x000100fd, - 0x000200f8, 0x00000055, 0x00050041, 0x00000045, - 0x00000058, 0x00000009, 0x00000034, 0x0004003d, - 0x00000006, 0x00000059, 0x00000058, 0x00050041, - 0x00000045, 0x0000005a, 0x0000000f, 0x00000030, - 0x0004003d, 0x00000006, 0x0000005b, 0x0000005a, - 0x00050084, 0x00000006, 0x0000005c, 0x00000059, - 0x0000005b, 0x00050041, 0x00000045, 0x0000005d, - 0x00000009, 0x00000030, 0x0004003d, 0x00000006, - 0x0000005e, 0x0000005d, 0x00050080, 0x00000006, - 0x0000005f, 0x0000005c, 0x0000005e, 0x0003003e, - 0x00000057, 0x0000005f, 0x0004003d, 0x00000006, - 0x00000065, 0x00000057, 0x0004003d, 0x00000014, - 0x00000066, 0x00000016, 0x00050051, 0x00000013, - 0x00000067, 0x00000066, 0x00000000, 0x00050051, - 0x00000013, 0x00000068, 0x00000066, 0x00000001, - 0x00050051, 0x00000013, 0x00000069, 0x00000066, - 0x00000002, 0x00070050, 0x00000060, 0x0000006a, - 0x00000067, 0x00000068, 0x00000069, 0x00000028, - 0x00060041, 0x0000006b, 0x0000006c, 0x00000064, - 0x00000043, 0x00000065, 0x0003003e, 0x0000006c, - 0x0000006a, 0x000100fd, 0x00010038 -}; - -static const Uint32 s_ClosestHitShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x0000000d, - 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, - 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, - 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, - 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, - 0x00000000, 0x00000001, 0x0006000f, 0x000014c4, - 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, - 0x00030003, 0x00000002, 0x000001cc, 0x00060004, - 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, - 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, - 0x00000000, 0x00060005, 0x00000009, 0x6c796170, - 0x4364616f, 0x726f6c6f, 0x00000000, 0x00020013, - 0x00000002, 0x00030021, 0x00000003, 0x00000002, - 0x00030016, 0x00000006, 0x00000020, 0x00040017, - 0x00000007, 0x00000006, 0x00000003, 0x00040020, - 0x00000008, 0x000014de, 0x00000007, 0x0004003b, - 0x00000008, 0x00000009, 0x000014de, 0x0004002b, - 0x00000006, 0x0000000a, 0x00000000, 0x0004002b, - 0x00000006, 0x0000000b, 0x3f800000, 0x0006002c, - 0x00000007, 0x0000000c, 0x0000000a, 0x0000000b, - 0x0000000a, 0x00050036, 0x00000002, 0x00000004, - 0x00000000, 0x00000003, 0x000200f8, 0x00000005, - 0x0003003e, 0x00000009, 0x0000000c, 0x000100fd, - 0x00010038 -}; - -static const Uint32 s_MissShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x0000000c, - 0x00000000, 0x00020011, 0x0000117f, 0x0006000a, - 0x5f565053, 0x5f52484b, 0x5f796172, 0x63617274, - 0x00676e69, 0x0006000b, 0x00000001, 0x4c534c47, - 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, - 0x00000000, 0x00000001, 0x0006000f, 0x000014c5, - 0x00000004, 0x6e69616d, 0x00000000, 0x00000009, - 0x00030003, 0x00000002, 0x000001cc, 0x00060004, - 0x455f4c47, 0x725f5458, 0x745f7961, 0x69636172, - 0x0000676e, 0x00040005, 0x00000004, 0x6e69616d, - 0x00000000, 0x00060005, 0x00000009, 0x6c796170, - 0x4364616f, 0x726f6c6f, 0x00000000, 0x00020013, - 0x00000002, 0x00030021, 0x00000003, 0x00000002, - 0x00030016, 0x00000006, 0x00000020, 0x00040017, - 0x00000007, 0x00000006, 0x00000003, 0x00040020, - 0x00000008, 0x000014de, 0x00000007, 0x0004003b, - 0x00000008, 0x00000009, 0x000014de, 0x0004002b, - 0x00000006, 0x0000000a, 0x00000000, 0x0006002c, - 0x00000007, 0x0000000b, 0x0000000a, 0x0000000a, - 0x0000000a, 0x00050036, 0x00000002, 0x00000004, - 0x00000000, 0x00000003, 0x000200f8, 0x00000005, - 0x0003003e, 0x00000009, 0x0000000b, 0x000100fd, - 0x00010038 -}; - -static const Uint8 s_RaygenShaderDxil[] = { - 0x44, 0x58, 0x42, 0x43, 0xac, 0x98, 0x93, 0xce, 0x61, 0x31, 0x12, 0x64, - 0x6a, 0xbd, 0x43, 0xc2, 0x54, 0xba, 0xb4, 0x35, 0x01, 0x00, 0x00, 0x00, - 0xf8, 0x10, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, - 0xa4, 0x08, 0x00, 0x00, 0xc0, 0x08, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x56, 0x45, 0x52, 0x53, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x14, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x32, 0x31, 0x64, 0x32, 0x38, 0x66, 0x37, 0x32, 0x00, 0x31, 0x2e, 0x39, - 0x2e, 0x32, 0x36, 0x30, 0x32, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00, 0x00, - 0x52, 0x44, 0x41, 0x54, 0xec, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x94, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x74, 0x6c, 0x61, 0x73, 0x00, 0x6f, 0x75, - 0x74, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x00, 0x01, 0x3f, 0x6d, 0x61, - 0x69, 0x6e, 0x40, 0x40, 0x59, 0x41, 0x58, 0x58, 0x5a, 0x00, 0x6d, 0x61, - 0x69, 0x6e, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x63, 0x00, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0x30, 0x07, 0x00, 0x00, - 0x63, 0x00, 0x06, 0x00, 0xcc, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x07, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0xc3, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xc4, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x62, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x11, 0x23, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x31, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0xda, 0x60, 0x08, - 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x12, 0x40, 0x6d, 0x30, 0x86, 0xff, - 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x88, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x23, 0xa4, 0x84, - 0x04, 0x13, 0x23, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8c, 0x8c, - 0x0b, 0x84, 0xc4, 0x4c, 0x10, 0x80, 0xc1, 0x1c, 0x01, 0x18, 0x9c, 0x26, - 0x4d, 0x11, 0x25, 0x4c, 0xfe, 0x0a, 0x6f, 0xd8, 0x44, 0x68, 0xc3, 0x10, - 0x11, 0x92, 0xb4, 0x51, 0x45, 0x41, 0x44, 0x28, 0x00, 0x28, 0x38, 0x33, - 0x90, 0xa6, 0x88, 0x12, 0x26, 0x7f, 0x05, 0xb0, 0x29, 0x02, 0x04, 0xa4, - 0x31, 0x34, 0x41, 0x20, 0x16, 0x22, 0x02, 0x26, 0xc4, 0x69, 0xd8, 0x29, - 0xa2, 0x84, 0x89, 0x8a, 0x08, 0x14, 0x00, 0x34, 0x8c, 0x00, 0x94, 0xa0, - 0x20, 0x63, 0x8e, 0x00, 0x29, 0x03, 0x00, 0x20, 0x94, 0xcc, 0x00, 0x14, - 0x64, 0x01, 0x96, 0x65, 0x59, 0x96, 0x85, 0x98, 0x32, 0x2c, 0xc0, 0x42, - 0x0e, 0x21, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, - 0x0c, 0x0b, 0x81, 0x02, 0xa8, 0x2c, 0x05, 0x10, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x90, 0x34, 0x8c, 0x30, 0x2c, 0x17, 0x49, 0x53, 0x44, 0x09, - 0x93, 0xbf, 0x02, 0x58, 0x0a, 0x60, 0x8b, 0x03, 0x0c, 0x28, 0xa0, 0xa8, - 0x2a, 0x51, 0x01, 0x44, 0x00, 0x00, 0x00, 0xc0, 0xb2, 0x2c, 0xcb, 0xb2, - 0x2c, 0x8b, 0x45, 0x57, 0x19, 0x22, 0x60, 0xa0, 0xac, 0x0c, 0x11, 0x10, - 0xd0, 0x36, 0x10, 0x30, 0x47, 0x10, 0xcc, 0x11, 0x80, 0x02, 0x00, 0x00, - 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, - 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, - 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, - 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, - 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, - 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, - 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x3a, 0x0f, 0x44, 0x90, 0x21, 0x23, - 0x45, 0x44, 0x00, 0x36, 0x00, 0x60, 0x3e, 0x00, 0xe0, 0x21, 0x8f, 0x01, - 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x9e, - 0x04, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, - 0x3c, 0x09, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x79, 0x18, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x30, 0xe4, 0x91, 0x80, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x60, 0xc8, 0x73, 0x01, 0x01, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xc0, 0x90, 0x27, 0x03, 0x02, 0x60, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x21, 0xcf, 0x06, 0x04, 0xc0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x20, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, - 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x02, 0x4a, 0xa0, 0x0c, 0x46, - 0x00, 0x8a, 0xa1, 0x40, 0x0a, 0xa1, 0x2c, 0x0a, 0xa3, 0x1c, 0x4a, 0xa2, - 0x34, 0x0a, 0xa2, 0x14, 0x4a, 0xab, 0x08, 0xe8, 0x2b, 0x10, 0xf2, 0x46, - 0x00, 0xa8, 0x9a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, - 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, - 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, - 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x80, - 0x65, 0x82, 0x00, 0x30, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x00, 0xcd, 0x06, - 0xc1, 0x30, 0x38, 0xb0, 0xa5, 0x89, 0x4d, 0x10, 0x00, 0x67, 0xc3, 0x80, - 0x24, 0xc4, 0x04, 0x81, 0x08, 0x48, 0xd0, 0xb1, 0x85, 0xcd, 0x4d, 0x10, - 0x80, 0x67, 0x82, 0x00, 0x40, 0x1b, 0x04, 0xc3, 0xd9, 0x90, 0x18, 0x0b, - 0x63, 0x18, 0x43, 0x63, 0x3c, 0x1b, 0x02, 0x68, 0x82, 0x20, 0x00, 0x4c, - 0xde, 0xea, 0xe8, 0x84, 0xea, 0xcc, 0xcc, 0xca, 0xe4, 0x26, 0x08, 0x40, - 0x34, 0x41, 0xf0, 0xb6, 0x0d, 0x8b, 0x21, 0x4d, 0x86, 0x31, 0x50, 0x55, - 0x55, 0x01, 0x1b, 0x02, 0x6b, 0x03, 0x11, 0x5d, 0x00, 0x30, 0x41, 0xa8, - 0xb8, 0x09, 0x02, 0x20, 0xb1, 0x18, 0x7b, 0x63, 0x7b, 0x93, 0x9b, 0x20, - 0x00, 0xd3, 0x04, 0x01, 0xa0, 0x26, 0x08, 0x40, 0xb5, 0x01, 0x49, 0x36, - 0xc2, 0xe0, 0x3a, 0x8f, 0xd8, 0x20, 0x68, 0xdf, 0x86, 0xc1, 0xc8, 0xc0, - 0x60, 0x82, 0x70, 0x08, 0x1b, 0x80, 0x0d, 0xc3, 0x30, 0x06, 0x63, 0xb0, - 0x21, 0x20, 0x83, 0x0d, 0xc3, 0x20, 0x06, 0x65, 0x40, 0x60, 0x82, 0xf0, - 0x69, 0x1b, 0x04, 0x03, 0x0d, 0x36, 0x14, 0xc0, 0x19, 0x00, 0x58, 0x1a, - 0xb0, 0x09, 0xf8, 0x69, 0x0b, 0x4b, 0x73, 0x03, 0x02, 0xca, 0x0a, 0xc2, - 0xc2, 0xd2, 0x9a, 0x20, 0x00, 0xd6, 0x04, 0x01, 0xb8, 0x36, 0x04, 0xc6, - 0x06, 0x82, 0x0d, 0xb8, 0x36, 0x70, 0x83, 0x0d, 0x85, 0x18, 0xac, 0x01, - 0x00, 0xbc, 0x01, 0x11, 0x31, 0xb9, 0x30, 0xb7, 0x31, 0xb4, 0xb2, 0x39, - 0x1a, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x73, 0x2c, 0xd2, 0xdc, 0xe6, 0xe8, - 0xe6, 0x26, 0x08, 0x00, 0x46, 0x22, 0xcd, 0x8d, 0x6e, 0x8e, 0x09, 0x5d, - 0x19, 0xde, 0xd7, 0x1c, 0xdd, 0x9b, 0x5c, 0x19, 0x8b, 0xba, 0x34, 0x37, - 0xba, 0xb9, 0x09, 0x02, 0x90, 0x6d, 0x60, 0xe2, 0x60, 0x90, 0x83, 0x66, - 0x0e, 0xe8, 0xa0, 0x0e, 0x1c, 0x3b, 0x18, 0xee, 0x00, 0x0f, 0xaa, 0xb0, - 0xb1, 0xd9, 0xb5, 0xb9, 0xa4, 0x91, 0x95, 0xb9, 0xd1, 0x4d, 0x09, 0x82, - 0x2a, 0x64, 0x78, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, - 0x02, 0xa2, 0x09, 0x19, 0x9e, 0x8b, 0x5d, 0x18, 0x9b, 0x5d, 0x99, 0xdc, - 0x94, 0xc0, 0xa8, 0x43, 0x86, 0xe7, 0x32, 0x87, 0x16, 0x46, 0x56, 0x26, - 0xd7, 0xf4, 0x46, 0x56, 0xc6, 0x36, 0x25, 0x48, 0xca, 0x90, 0xe1, 0xb9, - 0xc8, 0x95, 0xcd, 0xbd, 0xd5, 0xc9, 0x8d, 0x95, 0xcd, 0x4d, 0x09, 0xae, - 0x4a, 0x64, 0x78, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x41, 0x6e, 0x6e, 0x6f, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, 0x04, 0x30, 0x28, 0x83, - 0x3a, 0x64, 0x78, 0x2e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x69, - 0x6e, 0x74, 0x73, 0x53, 0x84, 0x34, 0x78, 0x83, 0x2e, 0x64, 0x78, 0x2e, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x53, 0x02, 0x3c, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, - 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, - 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, - 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, - 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, - 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, - 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, - 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, - 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, - 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, - 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, - 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, - 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, - 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, - 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, - 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, - 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, - 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, - 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, - 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, - 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, - 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, - 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, - 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, - 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, - 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x30, 0x83, 0x81, - 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, 0x1c, 0xc2, 0x61, 0x1d, - 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x25, 0xd0, 0x04, 0x7e, 0xed, 0x70, 0xda, 0x0d, - 0x04, 0x66, 0x83, 0x58, 0xac, 0xb6, 0x00, 0xca, 0x20, 0xf0, 0x7b, 0xd7, - 0xe9, 0xc2, 0xba, 0xd9, 0x5c, 0x96, 0x03, 0x81, 0xb3, 0xaa, 0xf4, 0x2a, - 0xcc, 0xd3, 0xcb, 0x41, 0x32, 0x59, 0x5e, 0x9e, 0xcf, 0x85, 0x75, 0xb3, - 0xb9, 0x2c, 0x07, 0x02, 0x83, 0x15, 0xc0, 0x06, 0x81, 0x1f, 0x9d, 0x1d, - 0x9e, 0x03, 0x81, 0xb3, 0xaa, 0x34, 0x9c, 0xa7, 0xcb, 0xc3, 0xe3, 0xb4, - 0xfb, 0x1c, 0x1c, 0x8f, 0xcb, 0xec, 0xb2, 0x3c, 0x4c, 0x4f, 0xbf, 0xdd, - 0x53, 0xba, 0xbc, 0x3e, 0xa6, 0xd7, 0xe5, 0x65, 0x20, 0x30, 0x68, 0x0a, - 0x73, 0x30, 0x5c, 0xbe, 0xf3, 0xf8, 0x42, 0x44, 0x00, 0x13, 0x11, 0x02, - 0xcd, 0xb0, 0x10, 0x9f, 0x13, 0x95, 0x48, 0xe0, 0x4b, 0x53, 0x44, 0x09, - 0x93, 0xbf, 0xc2, 0x1b, 0x36, 0x11, 0xda, 0x30, 0x44, 0x84, 0x24, 0x6d, - 0x54, 0x51, 0x10, 0x91, 0x25, 0xfc, 0xc1, 0x70, 0xf9, 0xce, 0xe3, 0x0b, - 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, 0x7c, 0x4e, 0x54, 0x22, - 0x81, 0x2f, 0x4d, 0x11, 0x25, 0x4c, 0xfe, 0x0a, 0x60, 0x53, 0x04, 0x08, - 0x48, 0x63, 0x68, 0x82, 0x40, 0x2c, 0x44, 0x04, 0x4c, 0x88, 0xd3, 0xb0, - 0x53, 0x44, 0x09, 0x13, 0x15, 0x11, 0x36, 0x00, 0x06, 0xc3, 0xe5, 0x3b, - 0x8f, 0x3f, 0x20, 0xd2, 0x03, 0x4c, 0xc2, 0xb1, 0x02, 0x98, 0xd4, 0x21, - 0x0c, 0xd1, 0x48, 0x88, 0xd3, 0x48, 0x3e, 0x72, 0xdb, 0x46, 0xb0, 0x0d, - 0x97, 0xef, 0x3c, 0xfe, 0x80, 0x48, 0x0f, 0x30, 0x09, 0xc7, 0x0a, 0x60, - 0x92, 0xd8, 0x0c, 0xc4, 0xe5, 0x23, 0xb7, 0x6d, 0x05, 0xce, 0x70, 0xf9, - 0xce, 0xe3, 0x0f, 0xce, 0x74, 0xfb, 0xc5, 0x6d, 0xdb, 0x01, 0x36, 0x5c, - 0xbe, 0xf3, 0xf8, 0x11, 0x60, 0x6d, 0x54, 0x51, 0x10, 0x11, 0x3b, 0x39, - 0x11, 0xe1, 0x23, 0xb7, 0x6d, 0x08, 0x60, 0x30, 0x5c, 0xbe, 0xf3, 0xf8, - 0x53, 0x04, 0x08, 0xc4, 0x0a, 0x60, 0xbe, 0x34, 0x45, 0x94, 0x30, 0xf9, - 0x2b, 0x80, 0xa5, 0x00, 0xb6, 0x38, 0xc0, 0x60, 0x06, 0xcf, 0x70, 0xf9, - 0xce, 0xe3, 0x53, 0x0d, 0x10, 0x61, 0x7e, 0x71, 0xdb, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x84, 0x49, 0x03, 0xad, 0x36, 0xa1, 0xb0, 0x22, - 0x48, 0xe9, 0x9b, 0x09, 0xc0, 0x25, 0x58, 0xf0, 0x44, 0x58, 0x49, 0x4c, - 0x30, 0x08, 0x00, 0x00, 0x63, 0x00, 0x06, 0x00, 0x0c, 0x02, 0x00, 0x00, - 0x44, 0x58, 0x49, 0x4c, 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x18, 0x08, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, - 0x03, 0x02, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, - 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, - 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, - 0xc4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x62, 0x88, - 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, - 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x23, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, - 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x31, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, - 0x40, 0xda, 0x60, 0x08, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x12, 0x40, - 0x6d, 0x30, 0x86, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x36, - 0x10, 0x04, 0x04, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x86, - 0x09, 0x01, 0x01, 0x00, 0x89, 0x20, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x88, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x23, 0xa4, 0x84, - 0x04, 0x13, 0x23, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8c, 0x8c, - 0x0b, 0x84, 0xc4, 0x4c, 0x10, 0x88, 0xc1, 0x1c, 0x01, 0x18, 0x9c, 0x26, - 0x4d, 0x11, 0x25, 0x4c, 0xfe, 0x0a, 0x6f, 0xd8, 0x44, 0x68, 0xc3, 0x10, - 0x11, 0x92, 0xb4, 0x51, 0x45, 0x41, 0x44, 0x28, 0x00, 0x28, 0x38, 0x33, - 0x90, 0xa6, 0x88, 0x12, 0x26, 0x7f, 0x05, 0xb0, 0x29, 0x02, 0x04, 0xa4, - 0x31, 0x34, 0x41, 0x20, 0x16, 0x22, 0x02, 0x26, 0xc4, 0x69, 0xd8, 0x29, - 0xa2, 0x84, 0x89, 0x8a, 0x08, 0x14, 0x00, 0x34, 0x8c, 0x00, 0x94, 0xa0, - 0x20, 0x63, 0x8e, 0x00, 0x29, 0x03, 0x00, 0x20, 0x94, 0xcc, 0x00, 0x14, - 0x64, 0x01, 0x96, 0x65, 0x59, 0x96, 0x85, 0x98, 0x32, 0x2c, 0xc0, 0x42, - 0x0e, 0x21, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, 0xf9, 0x21, 0xd0, - 0x0c, 0x0b, 0x81, 0x02, 0xa8, 0x2c, 0x05, 0x10, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x90, 0x34, 0x8c, 0x30, 0x2c, 0x17, 0x49, 0x53, 0x44, 0x09, - 0x93, 0xbf, 0x02, 0x58, 0x0a, 0x60, 0x8b, 0x03, 0x0c, 0x28, 0xa0, 0xa8, - 0x2a, 0x51, 0x01, 0x44, 0x00, 0x00, 0x00, 0xc0, 0xb2, 0x2c, 0xcb, 0xb2, - 0x2c, 0x8b, 0x45, 0x57, 0x19, 0x22, 0x60, 0xa0, 0xac, 0x0c, 0x11, 0x10, - 0xd0, 0x36, 0x10, 0x30, 0x47, 0x10, 0xcc, 0x11, 0x80, 0x02, 0x51, 0x53, - 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, - 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, - 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, - 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, - 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, - 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, - 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, - 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, - 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, - 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x3a, 0x0f, - 0x44, 0x90, 0x21, 0x23, 0x45, 0x44, 0x00, 0x36, 0x00, 0x60, 0x3e, 0x00, - 0xe0, 0x21, 0x8f, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x43, 0x9e, 0x04, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x86, 0x3c, 0x09, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x18, 0x20, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x38, 0x40, 0x00, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0xe4, 0x91, 0x80, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xc8, 0x73, 0x01, 0x01, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x90, 0x27, 0x03, - 0x02, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x21, 0xcf, - 0x06, 0x04, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, - 0x20, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, - 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x02, - 0x4a, 0xa0, 0x0c, 0x4a, 0xa2, 0x18, 0x46, 0x00, 0x0a, 0xa4, 0x10, 0xca, - 0xa2, 0x20, 0xca, 0xa1, 0x14, 0xc8, 0x1b, 0x01, 0xa0, 0xaf, 0x40, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, - 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, - 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, - 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, - 0x10, 0x4c, 0x10, 0x80, 0x65, 0x82, 0x00, 0x30, 0x1b, 0x84, 0x81, 0x98, - 0x20, 0x00, 0xcd, 0x06, 0x61, 0x30, 0x38, 0xb0, 0xa5, 0x89, 0x4d, 0x10, - 0x00, 0x67, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x01, 0x78, 0x26, 0x08, 0x44, - 0x40, 0x82, 0x8e, 0x2d, 0x6c, 0x6e, 0x82, 0x00, 0x40, 0x13, 0x04, 0x20, - 0xda, 0x20, 0x2c, 0xcf, 0x86, 0x64, 0x61, 0x9a, 0x65, 0x19, 0x9c, 0x05, - 0xda, 0x10, 0x44, 0x13, 0x04, 0x01, 0x60, 0xf2, 0x56, 0x47, 0x27, 0x54, - 0x67, 0x66, 0x56, 0x26, 0x37, 0x41, 0x00, 0xa4, 0x09, 0x82, 0x67, 0x6d, - 0x58, 0x96, 0x89, 0x5a, 0x96, 0xa1, 0xb2, 0x2c, 0x0b, 0xd8, 0x10, 0x5c, - 0x1b, 0x08, 0x09, 0x03, 0x80, 0x09, 0xc2, 0x21, 0x6c, 0x00, 0x36, 0x0c, - 0xc3, 0xb6, 0x6d, 0x08, 0xb8, 0x0d, 0xc3, 0xa0, 0x75, 0x04, 0x26, 0x08, - 0xdf, 0xb5, 0x41, 0x58, 0xc0, 0x60, 0x43, 0x01, 0x7c, 0x40, 0x16, 0x06, - 0x6c, 0x02, 0x7e, 0xda, 0xc2, 0xd2, 0xdc, 0x80, 0x80, 0xb2, 0x82, 0xb0, - 0xb0, 0xb4, 0x26, 0x08, 0xc0, 0x34, 0x41, 0x00, 0xa8, 0x09, 0x02, 0x50, - 0x6d, 0x08, 0x96, 0x0d, 0x04, 0x19, 0x94, 0x81, 0x19, 0x9c, 0xc1, 0x86, - 0x42, 0x1b, 0x03, 0x00, 0x40, 0x83, 0x2a, 0x6c, 0x6c, 0x76, 0x6d, 0x2e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, 0x9e, 0x8b, - 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, 0x42, 0x86, - 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26, 0x37, 0x25, 0x30, 0xea, 0x90, - 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, 0x91, 0x95, - 0xb1, 0x4d, 0x09, 0x92, 0x32, 0x64, 0x78, 0x2e, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x53, 0x02, 0xac, 0x12, 0x19, 0x9e, 0x0b, - 0x5d, 0x1e, 0x5c, 0x59, 0x90, 0x9b, 0xdb, 0x1b, 0x5d, 0x18, 0x5d, 0xda, - 0x9b, 0xdb, 0xdc, 0x94, 0xa0, 0xab, 0x43, 0x86, 0xe7, 0x52, 0xe6, 0x46, - 0x27, 0x97, 0x07, 0xf5, 0x96, 0xe6, 0x46, 0x37, 0x37, 0x45, 0x08, 0x03, - 0x34, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, - 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, - 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, - 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, - 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, - 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, - 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, - 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, - 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, - 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, - 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, - 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, - 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, - 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, - 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, - 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, - 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, - 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, - 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, - 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, - 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, - 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, - 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, - 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, - 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, - 0xf0, 0x30, 0x83, 0x81, 0xc8, 0x01, 0x1f, 0xdc, 0x40, 0x1c, 0xe4, 0xa1, - 0x1c, 0xc2, 0x61, 0x1d, 0xdc, 0x40, 0x1c, 0xe4, 0x01, 0x00, 0x00, 0x00, - 0x71, 0x20, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x25, 0xd0, 0x04, 0x7e, - 0xed, 0x70, 0xda, 0x0d, 0x04, 0x66, 0x83, 0x58, 0xac, 0xb6, 0x00, 0xca, - 0x20, 0xf0, 0x7b, 0xd7, 0xe9, 0xc2, 0xba, 0xd9, 0x5c, 0x96, 0x03, 0x81, - 0xb3, 0xaa, 0xf4, 0x2a, 0xcc, 0xd3, 0xcb, 0x41, 0x32, 0x59, 0x5e, 0x9e, - 0xcf, 0x85, 0x75, 0xb3, 0xb9, 0x2c, 0x07, 0x02, 0x83, 0x15, 0xc0, 0x06, - 0x81, 0x1f, 0x9d, 0x1d, 0x9e, 0x03, 0x81, 0xb3, 0xaa, 0x34, 0x9c, 0xa7, - 0xcb, 0xc3, 0xe3, 0xb4, 0xfb, 0x1c, 0x1c, 0x8f, 0xcb, 0xec, 0xb2, 0x3c, - 0x4c, 0x4f, 0xbf, 0xdd, 0x53, 0xba, 0xbc, 0x3e, 0xa6, 0xd7, 0xe5, 0x65, - 0x20, 0x30, 0x68, 0x0a, 0x73, 0x30, 0x5c, 0xbe, 0xf3, 0xf8, 0x42, 0x44, - 0x00, 0x13, 0x11, 0x02, 0xcd, 0xb0, 0x10, 0x9f, 0x13, 0x95, 0x48, 0xe0, - 0x4b, 0x53, 0x44, 0x09, 0x93, 0xbf, 0xc2, 0x1b, 0x36, 0x11, 0xda, 0x30, - 0x44, 0x84, 0x24, 0x6d, 0x54, 0x51, 0x10, 0x91, 0x25, 0xfc, 0xc1, 0x70, - 0xf9, 0xce, 0xe3, 0x0b, 0x11, 0x01, 0x4c, 0x44, 0x08, 0x34, 0xc3, 0x42, - 0x7c, 0x4e, 0x54, 0x22, 0x81, 0x2f, 0x4d, 0x11, 0x25, 0x4c, 0xfe, 0x0a, - 0x60, 0x53, 0x04, 0x08, 0x48, 0x63, 0x68, 0x82, 0x40, 0x2c, 0x44, 0x04, - 0x4c, 0x88, 0xd3, 0xb0, 0x53, 0x44, 0x09, 0x13, 0x15, 0x11, 0x36, 0x00, - 0x06, 0xc3, 0xe5, 0x3b, 0x8f, 0x3f, 0x20, 0xd2, 0x03, 0x4c, 0xc2, 0xb1, - 0x02, 0x98, 0xd4, 0x21, 0x0c, 0xd1, 0x48, 0x88, 0xd3, 0x48, 0x3e, 0x72, - 0xdb, 0x46, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0x80, 0x48, 0x0f, 0x30, - 0x09, 0xc7, 0x0a, 0x60, 0x92, 0xd8, 0x0c, 0xc4, 0xe5, 0x23, 0xb7, 0x6d, - 0x05, 0xce, 0x70, 0xf9, 0xce, 0xe3, 0x0f, 0xce, 0x74, 0xfb, 0xc5, 0x6d, - 0xdb, 0x01, 0x36, 0x5c, 0xbe, 0xf3, 0xf8, 0x11, 0x60, 0x6d, 0x54, 0x51, - 0x10, 0x11, 0x3b, 0x39, 0x11, 0xe1, 0x23, 0xb7, 0x6d, 0x08, 0x60, 0x30, - 0x5c, 0xbe, 0xf3, 0xf8, 0x53, 0x04, 0x08, 0xc4, 0x0a, 0x60, 0xbe, 0x34, - 0x45, 0x94, 0x30, 0xf9, 0x2b, 0x80, 0xa5, 0x00, 0xb6, 0x38, 0xc0, 0x60, - 0x06, 0xcf, 0x70, 0xf9, 0xce, 0xe3, 0x53, 0x0d, 0x10, 0x61, 0x7e, 0x71, - 0xdb, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x13, 0x04, 0x43, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x04, 0x94, 0xa8, 0x40, 0x91, 0x0a, 0x14, 0xb0, 0x40, 0xb9, 0x95, 0x4c, - 0xe9, 0x0a, 0x94, 0xff, 0x40, 0x61, 0x0a, 0xcc, 0x00, 0x14, 0x20, 0x20, - 0x20, 0xfe, 0x01, 0x21, 0x23, 0x00, 0x25, 0x50, 0x1e, 0xf4, 0x15, 0x41, - 0x09, 0x8c, 0x00, 0xd0, 0x32, 0x46, 0x00, 0x82, 0x20, 0x88, 0x7f, 0x23, - 0x00, 0x63, 0x04, 0x20, 0x08, 0x82, 0x24, 0x38, 0x8c, 0x11, 0xbc, 0x33, - 0x69, 0xa2, 0xdd, 0x18, 0x01, 0x08, 0x82, 0xf4, 0x29, 0x06, 0x44, 0x8d, - 0x00, 0xd0, 0x32, 0x46, 0x00, 0x82, 0x20, 0x88, 0xff, 0xc2, 0x18, 0x01, - 0x08, 0x82, 0x20, 0x08, 0x06, 0x63, 0x04, 0x20, 0x08, 0x82, 0xf0, 0x07, - 0x04, 0x07, 0xc3, 0x20, 0x39, 0x08, 0xc6, 0x4c, 0x44, 0x05, 0x2c, 0xa4, - 0x30, 0x62, 0x60, 0x00, 0x20, 0x08, 0x06, 0x09, 0x1c, 0x70, 0xd2, 0x88, - 0x81, 0x01, 0x80, 0x20, 0x18, 0x24, 0x71, 0xd0, 0x49, 0x23, 0x06, 0x06, - 0x00, 0x82, 0x60, 0x90, 0xcc, 0x41, 0x47, 0x8d, 0x18, 0x18, 0x00, 0x08, - 0x82, 0x41, 0x42, 0x07, 0x1e, 0x75, 0xc4, 0x52, 0x47, 0x2c, 0x65, 0x82, - 0x02, 0x1f, 0x13, 0x16, 0xf8, 0x9c, 0xb1, 0xd4, 0x19, 0x4b, 0x19, 0x21, - 0xd0, 0xc7, 0x08, 0x81, 0x3e, 0x26, 0x44, 0xf2, 0x31, 0x41, 0x92, 0x8f, - 0x09, 0x14, 0x7c, 0x4c, 0xa8, 0xe0, 0x33, 0x62, 0xb0, 0x00, 0x20, 0x08, - 0x06, 0xcc, 0x1f, 0xa4, 0x81, 0x10, 0x70, 0x42, 0xc0, 0x8d, 0x18, 0x18, - 0x00, 0x08, 0x82, 0x81, 0xf3, 0x07, 0x69, 0x10, 0x58, 0x40, 0xc8, 0xc7, - 0x08, 0x41, 0x3e, 0x23, 0x06, 0x06, 0x00, 0x82, 0x60, 0x90, 0xfd, 0x81, - 0x1b, 0x5c, 0xbb, 0x1a, 0x2c, 0x3d, 0xd0, 0x83, 0x61, 0x03, 0x22, 0xe8, - 0x08, 0x60, 0xc4, 0x80, 0x22, 0x40, 0x10, 0x0c, 0x2e, 0x51, 0x68, 0x03, - 0x61, 0x0f, 0xd8, 0x60, 0x0f, 0xf6, 0x60, 0x0f, 0xc2, 0x20, 0x0c, 0xc0, - 0xe0, 0x23, 0x86, 0xc2, 0xbb, 0x28, 0xa0, 0xc8, 0x70, 0xc3, 0x55, 0x8d, - 0xc1, 0x70, 0xc3, 0x55, 0x8d, 0x41, 0x09, 0xc1, 0xce, 0x32, 0x08, 0x41, - 0x50, 0x58, 0x26, 0x15, 0x6c, 0x50, 0xc1, 0x1f, 0xdc, 0x18, 0xc2, 0xa1, - 0x06, 0x63, 0x08, 0x08, 0x1b, 0x8c, 0x21, 0x24, 0x6e, 0x70, 0x03, 0xb0, - 0x37, 0x00, 0x7b, 0x03, 0xb0, 0x23, 0x06, 0x06, 0x00, 0x82, 0x60, 0xb0, - 0xb5, 0x42, 0x1f, 0x94, 0xc1, 0x88, 0x81, 0x03, 0x80, 0x20, 0x18, 0x48, - 0xb1, 0x90, 0x07, 0x01, 0x82, 0x07, 0xc4, 0x20, 0xdc, 0x01, 0x1d, 0x9c, - 0xc2, 0x2c, 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -static const Uint8 s_ClosestHitShaderDxil[] = { - 0x44, 0x58, 0x42, 0x43, 0xe2, 0x63, 0x0f, 0x70, 0x86, 0x07, 0xe7, 0xc8, - 0xbc, 0xcb, 0x54, 0xe0, 0x73, 0x66, 0x13, 0x7b, 0x01, 0x00, 0x00, 0x00, - 0xe8, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, - 0xdc, 0x05, 0x00, 0x00, 0xf8, 0x05, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x56, 0x45, 0x52, 0x53, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x14, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x32, 0x31, 0x64, 0x32, 0x38, 0x66, 0x37, 0x32, 0x00, 0x31, 0x2e, 0x39, - 0x2e, 0x32, 0x36, 0x30, 0x32, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00, 0x00, - 0x52, 0x44, 0x41, 0x54, 0x90, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x6d, - 0x61, 0x69, 0x6e, 0x40, 0x40, 0x59, 0x41, 0x58, 0x55, 0x52, 0x61, 0x79, - 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x40, 0x40, 0x55, 0x48, 0x69, - 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x40, - 0x40, 0x40, 0x5a, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x63, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x53, 0x54, 0x41, 0x54, - 0xc4, 0x04, 0x00, 0x00, 0x63, 0x00, 0x06, 0x00, 0x31, 0x01, 0x00, 0x00, - 0x44, 0x58, 0x49, 0x4c, 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0xac, 0x04, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, - 0x28, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, - 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, - 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, - 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, - 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, - 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, - 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0x20, 0x00, 0x12, 0x60, 0xd9, 0x60, - 0x08, 0x02, 0xb0, 0x00, 0xd4, 0x06, 0x62, 0xf8, 0xff, 0xff, 0xff, 0xff, - 0x01, 0x90, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x13, 0x86, 0x40, 0x18, 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, - 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, - 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, - 0x33, 0x00, 0xc3, 0x08, 0x43, 0x70, 0x91, 0x34, 0x45, 0x94, 0x30, 0xf9, - 0x2b, 0x80, 0xa5, 0x00, 0xb6, 0x38, 0xc0, 0x80, 0x02, 0xa1, 0x19, 0x46, - 0x10, 0x82, 0xa3, 0xa4, 0x29, 0xa2, 0x84, 0xc9, 0x0f, 0x91, 0x49, 0x9b, - 0xa6, 0x08, 0x09, 0xa8, 0x89, 0x90, 0x50, 0x50, 0x64, 0x65, 0x00, 0x3a, - 0xc2, 0x81, 0x80, 0x39, 0x02, 0x30, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, - 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, - 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, - 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, - 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, - 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, - 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, - 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, - 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, - 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, - 0x40, 0x07, 0x43, 0x1e, 0x04, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb2, 0x40, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x32, 0x1e, 0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, - 0xc6, 0x04, 0x43, 0xda, 0x52, 0x28, 0x8a, 0x12, 0x28, 0x83, 0x11, 0x80, - 0x62, 0x28, 0x8c, 0x72, 0x28, 0x89, 0xd2, 0x28, 0x88, 0x22, 0x20, 0x9b, - 0x01, 0xa0, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, - 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, - 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, - 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x96, - 0x61, 0x82, 0xb0, 0x10, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x2c, 0xc5, 0x06, - 0xc1, 0x30, 0x38, 0xb0, 0xa5, 0x89, 0x4d, 0x10, 0x16, 0x63, 0xc3, 0x80, - 0x24, 0xc4, 0x04, 0x61, 0x70, 0x26, 0x08, 0xcb, 0xc1, 0x62, 0xec, 0x8d, - 0xed, 0x4d, 0x6e, 0x82, 0xb0, 0x20, 0x13, 0x84, 0x25, 0x99, 0x20, 0x2c, - 0xca, 0x06, 0x24, 0x69, 0x08, 0xc3, 0x79, 0x20, 0x62, 0x83, 0xc0, 0x44, - 0x13, 0x04, 0xa3, 0x99, 0x20, 0x2c, 0x0b, 0x8d, 0x3a, 0xb7, 0xba, 0xb9, - 0x32, 0xb2, 0x09, 0xc2, 0xc2, 0x6c, 0x40, 0x92, 0x8a, 0x30, 0x9c, 0x07, - 0xb2, 0x36, 0x08, 0xd4, 0xb5, 0xa1, 0x30, 0x16, 0x69, 0xc2, 0x26, 0x08, - 0x09, 0xb0, 0x01, 0xd8, 0x30, 0x0c, 0xdb, 0xb6, 0x61, 0xb0, 0xb6, 0x6d, - 0xc3, 0x60, 0x6c, 0xdb, 0x86, 0x81, 0xeb, 0xbc, 0x0d, 0xc3, 0xa0, 0x7d, - 0x04, 0x36, 0x14, 0x40, 0x18, 0x00, 0x00, 0x40, 0x35, 0x08, 0xf8, 0x69, - 0x0b, 0x4b, 0x73, 0x03, 0x02, 0xca, 0x0a, 0xc2, 0xaa, 0x92, 0x0a, 0xcb, - 0x83, 0x0a, 0xcb, 0x63, 0x7b, 0x0b, 0x23, 0x03, 0x02, 0xaa, 0x42, 0x4a, - 0xa3, 0x0b, 0xa2, 0xa3, 0x93, 0x4b, 0x13, 0xab, 0xa3, 0x2b, 0x9b, 0x03, - 0x02, 0x02, 0xd2, 0x9a, 0x20, 0x2c, 0xc2, 0x04, 0x61, 0x09, 0x36, 0x04, - 0xc6, 0x06, 0x84, 0x22, 0x83, 0x84, 0x71, 0xa8, 0x32, 0x30, 0x83, 0x0d, - 0x85, 0x36, 0x06, 0x00, 0x70, 0x06, 0x2c, 0xd2, 0xdc, 0xe6, 0xe8, 0xe6, - 0x36, 0x08, 0x69, 0x40, 0x54, 0x61, 0x63, 0xb3, 0x6b, 0x73, 0x49, 0x23, - 0x2b, 0x73, 0xa3, 0x9b, 0x12, 0x04, 0x55, 0xc8, 0xf0, 0x5c, 0xec, 0xca, - 0xe4, 0xe6, 0xd2, 0xde, 0xdc, 0xa6, 0x04, 0x44, 0x13, 0x32, 0x3c, 0x17, - 0xbb, 0x30, 0x36, 0xbb, 0x32, 0xb9, 0x29, 0x81, 0x51, 0x87, 0x0c, 0xcf, - 0x65, 0x0e, 0x2d, 0x8c, 0xac, 0x4c, 0xae, 0xe9, 0x8d, 0xac, 0x8c, 0x6d, - 0x4a, 0x90, 0x54, 0x22, 0xc3, 0x73, 0xa1, 0xcb, 0x83, 0x2b, 0x0b, 0x72, - 0x73, 0x7b, 0xa3, 0x0b, 0xa3, 0x4b, 0x7b, 0x73, 0x9b, 0x9b, 0x22, 0x60, - 0x5f, 0x1d, 0x32, 0x3c, 0x97, 0x32, 0x37, 0x3a, 0xb9, 0x3c, 0xa8, 0xb7, - 0x34, 0x37, 0xba, 0xb9, 0x29, 0x42, 0x18, 0x9c, 0x41, 0x17, 0x32, 0x3c, - 0x97, 0xb1, 0xb7, 0x3a, 0x37, 0xba, 0x32, 0xb9, 0xb9, 0x29, 0x41, 0x1a, - 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, - 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, - 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, - 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, - 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, - 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, - 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, - 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, - 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, - 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, - 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, - 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, - 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, - 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, - 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, - 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, - 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, - 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, - 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, - 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, - 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, - 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, - 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, - 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, - 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, - 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x05, 0xa0, 0x06, 0x81, 0x5f, 0x3b, 0x9c, 0x76, 0x03, 0x81, 0xd9, 0x20, - 0xb6, 0x2a, 0x0d, 0xe7, 0xa1, 0xe1, 0x3c, 0xfb, 0x1d, 0x26, 0x03, 0x81, - 0x55, 0x64, 0x9a, 0x1e, 0xa4, 0xd3, 0xe5, 0x69, 0x71, 0x9d, 0x5e, 0x9e, - 0x03, 0x81, 0x40, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x61, 0xd0, 0x02, 0xc8, 0xf2, 0x7a, 0x7b, 0xb7, 0xe0, 0xb0, 0x51, 0xd6, - 0x21, 0x9d, 0x7e, 0x16, 0x44, 0x58, 0x49, 0x4c, 0xe8, 0x04, 0x00, 0x00, - 0x63, 0x00, 0x06, 0x00, 0x3a, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xd0, 0x04, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x1b, 0x8c, 0x20, 0x00, 0x12, 0x60, 0xd9, 0x60, 0x08, 0x02, 0xb0, 0x00, - 0xd4, 0x06, 0x62, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x01, 0x90, 0x00, 0x00, - 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x86, 0x40, 0x18, - 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, - 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, - 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x34, 0x23, 0x00, 0x33, 0x00, 0xc3, 0x08, - 0x43, 0x70, 0x91, 0x34, 0x45, 0x94, 0x30, 0xf9, 0x2b, 0x80, 0xa5, 0x00, - 0xb6, 0x38, 0xc0, 0x80, 0x02, 0xa1, 0x19, 0x46, 0x10, 0x82, 0xa3, 0xa4, - 0x29, 0xa2, 0x84, 0xc9, 0x0f, 0x91, 0x49, 0x9b, 0xa6, 0x08, 0x09, 0xa8, - 0x89, 0x90, 0x50, 0x50, 0x64, 0x65, 0x00, 0x3a, 0xc2, 0x81, 0x80, 0x39, - 0x02, 0x30, 0x20, 0x01, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, - 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, - 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, - 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, - 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, - 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, - 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, - 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, - 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, - 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x1e, - 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, - 0x40, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x10, - 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xda, - 0x52, 0x28, 0x8a, 0x12, 0x28, 0x83, 0x92, 0x28, 0x86, 0x11, 0x80, 0xc2, - 0x28, 0x87, 0x82, 0x28, 0x02, 0xb2, 0x19, 0x00, 0x9a, 0x19, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, - 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, - 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, - 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, - 0x10, 0x4c, 0x10, 0x96, 0x61, 0x82, 0xb0, 0x10, 0x1b, 0x84, 0x81, 0x98, - 0x20, 0x2c, 0xc5, 0x06, 0x61, 0x30, 0x38, 0xb0, 0xa5, 0x89, 0x4d, 0x10, - 0x16, 0x63, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x61, 0x39, 0x26, 0x08, 0x43, - 0x33, 0x41, 0x58, 0x10, 0x16, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x13, 0x84, - 0x25, 0xd9, 0x60, 0x24, 0x0e, 0xb1, 0x3c, 0xc6, 0x06, 0xa1, 0x81, 0x26, - 0x08, 0x06, 0x33, 0x41, 0x58, 0x14, 0x1a, 0x75, 0x6e, 0x75, 0x73, 0x65, - 0x64, 0x1b, 0x8c, 0x84, 0x22, 0x96, 0xc7, 0xd8, 0x20, 0x4c, 0xd5, 0x86, - 0x62, 0x61, 0x22, 0xc9, 0x9a, 0x20, 0x24, 0xc0, 0x06, 0x60, 0xc3, 0x30, - 0x64, 0xd9, 0x04, 0x61, 0x59, 0x36, 0x0c, 0x5b, 0x96, 0x6d, 0x18, 0x96, - 0x2c, 0xdb, 0x30, 0x68, 0x5c, 0xb7, 0x61, 0x18, 0x30, 0x8f, 0xc0, 0x86, - 0x02, 0x00, 0x03, 0x00, 0x00, 0xa8, 0x06, 0x01, 0x3f, 0x6d, 0x61, 0x69, - 0x6e, 0x40, 0x40, 0x59, 0x41, 0x58, 0x55, 0x52, 0x61, 0x79, 0x50, 0x61, - 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x40, 0x40, 0x55, 0x48, 0x69, 0x74, 0x41, - 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x40, 0x40, 0x40, - 0x5a, 0x13, 0x84, 0x45, 0x98, 0x20, 0x2c, 0xc1, 0x86, 0x60, 0xd9, 0x80, - 0x4c, 0x63, 0x90, 0x34, 0xcf, 0x44, 0x06, 0x65, 0xb0, 0xa1, 0xc0, 0xc4, - 0x00, 0x00, 0xcc, 0xa0, 0x0a, 0x1b, 0x9b, 0x5d, 0x9b, 0x4b, 0x1a, 0x59, - 0x99, 0x1b, 0xdd, 0x94, 0x20, 0xa8, 0x42, 0x86, 0xe7, 0x62, 0x57, 0x26, - 0x37, 0x97, 0xf6, 0xe6, 0x36, 0x25, 0x20, 0x9a, 0x90, 0xe1, 0xb9, 0xd8, - 0x85, 0xb1, 0xd9, 0x95, 0xc9, 0x4d, 0x09, 0x8c, 0x3a, 0x64, 0x78, 0x2e, - 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, - 0x82, 0xa4, 0x12, 0x19, 0x9e, 0x0b, 0x5d, 0x1e, 0x5c, 0x59, 0x90, 0x9b, - 0xdb, 0x1b, 0x5d, 0x18, 0x5d, 0xda, 0x9b, 0xdb, 0xdc, 0x14, 0xc1, 0xf2, - 0xea, 0x90, 0xe1, 0xb9, 0x94, 0xb9, 0xd1, 0xc9, 0xe5, 0x41, 0xbd, 0xa5, - 0xb9, 0xd1, 0xcd, 0x4d, 0x11, 0xc0, 0xc0, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, - 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, - 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, - 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, - 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, - 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, - 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, - 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, - 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, - 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, - 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, - 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, - 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, - 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, - 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, - 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, - 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, - 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, - 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, - 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, - 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, - 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, - 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, - 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, - 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, - 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00, - 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x05, 0xa0, 0x06, 0x81, - 0x5f, 0x3b, 0x9c, 0x76, 0x03, 0x81, 0xd9, 0x20, 0xb6, 0x2a, 0x0d, 0xe7, - 0xa1, 0xe1, 0x3c, 0xfb, 0x1d, 0x26, 0x03, 0x81, 0x55, 0x64, 0x9a, 0x1e, - 0xa4, 0xd3, 0xe5, 0x69, 0x71, 0x9d, 0x5e, 0x9e, 0x03, 0x81, 0x40, 0x2d, - 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x24, 0x63, 0x0d, 0x00, 0x08, 0x82, 0x20, 0xfe, 0x01, 0x00, 0x00, 0x00, - 0x7b, 0x86, 0x41, 0x51, 0x86, 0x0d, 0x88, 0x40, 0x18, 0x00, 0x0c, 0x07, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf6, 0x40, 0x00, 0xd3, - 0x14, 0x99, 0xc3, 0xf1, 0x00, 0xd8, 0xe2, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -static const Uint8 s_MissShaderDxil[] = { - 0x44, 0x58, 0x42, 0x43, 0xb8, 0x8e, 0xad, 0xc7, 0x67, 0x2c, 0xbe, 0x74, - 0x0c, 0x8d, 0xff, 0x5a, 0x17, 0xce, 0x2f, 0xfa, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x0a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x64, 0x05, 0x00, 0x00, 0x80, 0x05, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x56, 0x45, 0x52, 0x53, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x14, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x32, 0x31, 0x64, 0x32, 0x38, 0x66, 0x37, 0x32, 0x00, 0x31, 0x2e, 0x39, - 0x2e, 0x32, 0x36, 0x30, 0x32, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00, 0x00, - 0x52, 0x44, 0x41, 0x54, 0x80, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3f, 0x6d, - 0x61, 0x69, 0x6e, 0x40, 0x40, 0x59, 0x41, 0x58, 0x55, 0x52, 0x61, 0x79, - 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x40, 0x40, 0x40, 0x5a, 0x00, - 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x00, 0x00, 0x63, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x53, 0x54, 0x41, 0x54, 0x5c, 0x04, 0x00, 0x00, - 0x63, 0x00, 0x06, 0x00, 0x17, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x44, 0x04, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x1b, 0x8c, 0x20, 0x00, 0x12, 0x60, 0xd9, 0x40, 0x08, 0xff, 0xff, 0xff, - 0xff, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x13, 0x84, 0x40, 0x00, 0x89, 0x20, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, - 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, - 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x24, 0x23, 0x00, - 0x33, 0x00, 0xc3, 0x08, 0x43, 0x70, 0x91, 0x34, 0x45, 0x94, 0x30, 0xf9, - 0x2b, 0x80, 0xa5, 0x00, 0xb6, 0x38, 0xc0, 0x80, 0x02, 0xa1, 0x29, 0x02, - 0x10, 0xd5, 0x40, 0xc0, 0x1c, 0x01, 0x18, 0x00, 0x13, 0x14, 0x72, 0xc0, - 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, - 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, - 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, - 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, - 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, - 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, - 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, - 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, - 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, - 0x40, 0x07, 0x43, 0x9e, 0x02, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb2, 0x40, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x32, 0x1e, 0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, - 0xc6, 0x04, 0x43, 0xc2, 0x52, 0x28, 0x81, 0x32, 0x18, 0x01, 0x28, 0x86, - 0xc2, 0x28, 0x87, 0x92, 0x28, 0x8d, 0x22, 0x28, 0x88, 0xb2, 0xa0, 0x99, - 0x01, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, - 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, - 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, - 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x10, 0x61, 0x82, 0x80, 0x0c, - 0x1b, 0x84, 0x81, 0x98, 0x20, 0x20, 0xc4, 0x06, 0xc1, 0x30, 0x38, 0xb0, - 0xa5, 0x89, 0x4d, 0x10, 0x90, 0x62, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x61, - 0x68, 0x26, 0x08, 0x88, 0xc1, 0x62, 0xec, 0x8d, 0xed, 0x4d, 0x6e, 0x82, - 0x80, 0x1c, 0x13, 0x04, 0x04, 0x99, 0x20, 0x20, 0xc9, 0x06, 0x24, 0x69, - 0x08, 0xc3, 0x79, 0x20, 0x62, 0x83, 0xc0, 0x44, 0x1b, 0x06, 0x63, 0x91, - 0x26, 0x08, 0x06, 0xb0, 0x01, 0xd8, 0x30, 0x0c, 0x55, 0x35, 0x41, 0x40, - 0x94, 0x0d, 0xc3, 0x55, 0x55, 0x1b, 0x04, 0x0b, 0xdb, 0x30, 0x0c, 0x54, - 0x46, 0x60, 0x43, 0x01, 0x6c, 0x00, 0x00, 0x50, 0x0b, 0xf8, 0x69, 0x0b, - 0x4b, 0x73, 0x03, 0x02, 0xca, 0x0a, 0xc2, 0xaa, 0x92, 0x0a, 0xcb, 0x83, - 0x0a, 0xcb, 0x63, 0x7b, 0x0b, 0x23, 0x03, 0x02, 0x02, 0xd2, 0x9a, 0x20, - 0x20, 0xcb, 0x04, 0x01, 0x61, 0x26, 0x08, 0x48, 0xb0, 0x21, 0x30, 0x36, - 0x18, 0xde, 0x97, 0x30, 0x60, 0x10, 0x06, 0x1b, 0x0a, 0xaa, 0x03, 0x00, - 0x31, 0x60, 0x91, 0xe6, 0x36, 0x47, 0x37, 0xb7, 0x41, 0x20, 0x03, 0xa2, - 0x0a, 0x1b, 0x9b, 0x5d, 0x9b, 0x4b, 0x1a, 0x59, 0x99, 0x1b, 0xdd, 0x94, - 0x20, 0xa8, 0x42, 0x86, 0xe7, 0x62, 0x57, 0x26, 0x37, 0x97, 0xf6, 0xe6, - 0x36, 0x25, 0x20, 0x9a, 0x90, 0xe1, 0xb9, 0xd8, 0x85, 0xb1, 0xd9, 0x95, - 0xc9, 0x4d, 0x09, 0x8c, 0x3a, 0x64, 0x78, 0x2e, 0x73, 0x68, 0x61, 0x64, - 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, 0x82, 0xa4, 0x12, 0x19, - 0x9e, 0x0b, 0x5d, 0x1e, 0x5c, 0x59, 0x90, 0x9b, 0xdb, 0x1b, 0x5d, 0x18, - 0x5d, 0xda, 0x9b, 0xdb, 0xdc, 0x14, 0x41, 0xca, 0xea, 0x90, 0xe1, 0xb9, - 0x94, 0xb9, 0xd1, 0xc9, 0xe5, 0x41, 0xbd, 0xa5, 0xb9, 0xd1, 0xcd, 0x4d, - 0x11, 0x36, 0x31, 0xe8, 0x42, 0x86, 0xe7, 0x32, 0xf6, 0x56, 0xe7, 0x46, - 0x57, 0x26, 0x37, 0x37, 0x25, 0x20, 0x03, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, - 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, - 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, - 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, - 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, - 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, - 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, - 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, - 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, - 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, - 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, - 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, - 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, - 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, - 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, - 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, - 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, - 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, - 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, - 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, - 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, - 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, - 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, - 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, - 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, - 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x05, 0xa0, 0x05, 0x7e, 0xed, 0x70, 0xda, 0x0d, - 0x04, 0x66, 0x83, 0xd8, 0xaa, 0x34, 0x9c, 0x87, 0x86, 0xf3, 0xec, 0x77, - 0x98, 0x0c, 0x04, 0x02, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x98, 0x7d, 0xbf, 0x81, 0x6e, 0xe5, 0x34, 0x58, 0x9f, 0x60, 0x8b, 0xd9, - 0x81, 0xf5, 0xe6, 0xff, 0x44, 0x58, 0x49, 0x4c, 0x78, 0x04, 0x00, 0x00, - 0x63, 0x00, 0x06, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x03, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x1b, 0x8c, 0x20, 0x00, 0x12, 0x60, 0xd9, 0x40, 0x08, 0xff, 0xff, 0xff, - 0xff, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x13, 0x84, 0x40, 0x00, 0x89, 0x20, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, - 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, - 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x28, 0x23, 0x00, - 0x33, 0x00, 0xc3, 0x08, 0x43, 0x70, 0x91, 0x34, 0x45, 0x94, 0x30, 0xf9, - 0x2b, 0x80, 0xa5, 0x00, 0xb6, 0x38, 0xc0, 0x80, 0x02, 0xa1, 0x29, 0x02, - 0x10, 0xd5, 0x40, 0xc0, 0x1c, 0x01, 0x18, 0x90, 0x00, 0x00, 0x00, 0x00, - 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, - 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, - 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, - 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, - 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, - 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, - 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x02, 0x00, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x40, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, - 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xc2, 0x52, 0x28, 0x81, 0x32, - 0x28, 0x89, 0x62, 0x18, 0x01, 0x28, 0x8c, 0x72, 0x28, 0x82, 0x82, 0x28, - 0x0b, 0x9a, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, - 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, - 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, - 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x10, - 0x61, 0x82, 0x80, 0x0c, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x20, 0xc4, 0x06, - 0x61, 0x30, 0x38, 0xb0, 0xa5, 0x89, 0x4d, 0x10, 0x90, 0x62, 0xc3, 0x80, - 0x24, 0xc4, 0x04, 0x01, 0x31, 0x26, 0x08, 0x03, 0x33, 0x41, 0x40, 0x0e, - 0x16, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x13, 0x04, 0x04, 0xd9, 0x60, 0x24, - 0x0e, 0xb1, 0x3c, 0xc6, 0x06, 0xa1, 0x81, 0x36, 0x0c, 0x0b, 0x13, 0x4d, - 0x10, 0x0c, 0x60, 0x03, 0xb0, 0x61, 0x18, 0x28, 0x6a, 0x82, 0x80, 0x24, - 0x1b, 0x06, 0x8b, 0xa2, 0x36, 0x08, 0xd5, 0xb5, 0x61, 0x18, 0x26, 0x8c, - 0xc0, 0x86, 0x02, 0xd0, 0x00, 0x00, 0xa0, 0x16, 0xf0, 0xd3, 0x16, 0x96, - 0xe6, 0x06, 0x04, 0x94, 0x15, 0x84, 0x55, 0x25, 0x15, 0x96, 0x07, 0x15, - 0x96, 0xc7, 0xf6, 0x16, 0x46, 0x06, 0x04, 0x04, 0xa4, 0x35, 0x41, 0x40, - 0x94, 0x09, 0x02, 0xb2, 0x4c, 0x10, 0x90, 0x60, 0x43, 0xb0, 0x6c, 0x30, - 0x3a, 0x2f, 0x69, 0x3e, 0x30, 0xd8, 0x50, 0x4c, 0x1c, 0x00, 0x84, 0x41, - 0x15, 0x36, 0x36, 0xbb, 0x36, 0x97, 0x34, 0xb2, 0x32, 0x37, 0xba, 0x29, - 0x41, 0x50, 0x85, 0x0c, 0xcf, 0xc5, 0xae, 0x4c, 0x6e, 0x2e, 0xed, 0xcd, - 0x6d, 0x4a, 0x40, 0x34, 0x21, 0xc3, 0x73, 0xb1, 0x0b, 0x63, 0xb3, 0x2b, - 0x93, 0x9b, 0x12, 0x18, 0x75, 0xc8, 0xf0, 0x5c, 0xe6, 0xd0, 0xc2, 0xc8, - 0xca, 0xe4, 0x9a, 0xde, 0xc8, 0xca, 0xd8, 0xa6, 0x04, 0x49, 0x25, 0x32, - 0x3c, 0x17, 0xba, 0x3c, 0xb8, 0xb2, 0x20, 0x37, 0xb7, 0x37, 0xba, 0x30, - 0xba, 0xb4, 0x37, 0xb7, 0xb9, 0x29, 0x42, 0x84, 0xd5, 0x21, 0xc3, 0x73, - 0x29, 0x73, 0xa3, 0x93, 0xcb, 0x83, 0x7a, 0x4b, 0x73, 0xa3, 0x9b, 0x9b, - 0x22, 0x68, 0x61, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, - 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, - 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, - 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, - 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, - 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, - 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, - 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, - 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, - 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, - 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, - 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, - 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, - 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, - 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, - 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, - 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, - 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, - 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, - 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, - 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, - 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, - 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, - 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, - 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, - 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x05, 0xa0, 0x05, 0x7e, 0xed, 0x70, 0xda, 0x0d, 0x04, 0x66, 0x83, 0xd8, - 0xaa, 0x34, 0x9c, 0x87, 0x86, 0xf3, 0xec, 0x77, 0x98, 0x0c, 0x04, 0x02, - 0xb5, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x24, 0x23, 0x00, 0x00, 0x7b, 0x06, 0x21, 0x49, 0x86, 0x0d, 0x88, 0x40, - 0x18, 0x00, 0x0c, 0x07, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xd6, 0x70, 0x3c, 0x00, 0xb6, 0x38, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; - -// ================================================== -// Triangle -// ================================================== - -// GLSL -// Vertex -// #version 450 - -// layout(location = 0) in vec2 aPosition; -// layout(location = 1) in vec3 aColor; - -// layout(location = 0) out vec4 vColor; - -// void main() -// { -// gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); -// vColor = vec4(aColor, 1.0); -// } - -// Fragment -// #version 450 - -// layout(location = 0) in vec4 aColor; - -// layout(location = 0) out vec4 color; - -// void main() -// { -// color = aColor; -// } - -// HLSL -// Vertex -// struct VSInput -// { -// float2 pos : POSITION; -// float3 color : COLOR; -// }; - -// struct VSOutput -// { -// float4 pos : SV_POSITION; -// float4 color : COLOR; -// }; - -// VSOutput main(VSInput input) -// { -// VSOutput output; -// output.pos = float4(input.pos, 0.0, 1.0); -// output.color = float4(input.color, 1.0); -// return output; -// } - -// Fragment -// struct PSInput -// { -// float4 pos : SV_POSITION; -// float4 color : COLOR; -// }; - -// float4 main(PSInput input) : SV_Target -// { -// return input.color; -// } - -static const Uint32 s_TriangleVertShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x00000028, - 0x00000000, 0x00020011, 0x00000001, 0x0006000b, - 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, - 0x00000000, 0x0003000e, 0x00000000, 0x00000001, - 0x0009000f, 0x00000000, 0x00000004, 0x6e69616d, - 0x00000000, 0x0000000d, 0x00000012, 0x0000001f, - 0x00000022, 0x00030003, 0x00000002, 0x000001c2, - 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, - 0x00060005, 0x0000000b, 0x505f6c67, 0x65567265, - 0x78657472, 0x00000000, 0x00060006, 0x0000000b, - 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69, - 0x00070006, 0x0000000b, 0x00000001, 0x505f6c67, - 0x746e696f, 0x657a6953, 0x00000000, 0x00070006, - 0x0000000b, 0x00000002, 0x435f6c67, 0x4470696c, - 0x61747369, 0x0065636e, 0x00070006, 0x0000000b, - 0x00000003, 0x435f6c67, 0x446c6c75, 0x61747369, - 0x0065636e, 0x00030005, 0x0000000d, 0x00000000, - 0x00050005, 0x00000012, 0x736f5061, 0x6f697469, - 0x0000006e, 0x00040005, 0x0000001f, 0x6c6f4376, - 0x0000726f, 0x00040005, 0x00000022, 0x6c6f4361, - 0x0000726f, 0x00030047, 0x0000000b, 0x00000002, - 0x00050048, 0x0000000b, 0x00000000, 0x0000000b, - 0x00000000, 0x00050048, 0x0000000b, 0x00000001, - 0x0000000b, 0x00000001, 0x00050048, 0x0000000b, - 0x00000002, 0x0000000b, 0x00000003, 0x00050048, - 0x0000000b, 0x00000003, 0x0000000b, 0x00000004, - 0x00040047, 0x00000012, 0x0000001e, 0x00000000, - 0x00040047, 0x0000001f, 0x0000001e, 0x00000000, - 0x00040047, 0x00000022, 0x0000001e, 0x00000001, - 0x00020013, 0x00000002, 0x00030021, 0x00000003, - 0x00000002, 0x00030016, 0x00000006, 0x00000020, - 0x00040017, 0x00000007, 0x00000006, 0x00000004, - 0x00040015, 0x00000008, 0x00000020, 0x00000000, - 0x0004002b, 0x00000008, 0x00000009, 0x00000001, - 0x0004001c, 0x0000000a, 0x00000006, 0x00000009, - 0x0006001e, 0x0000000b, 0x00000007, 0x00000006, - 0x0000000a, 0x0000000a, 0x00040020, 0x0000000c, - 0x00000003, 0x0000000b, 0x0004003b, 0x0000000c, - 0x0000000d, 0x00000003, 0x00040015, 0x0000000e, - 0x00000020, 0x00000001, 0x0004002b, 0x0000000e, - 0x0000000f, 0x00000000, 0x00040017, 0x00000010, - 0x00000006, 0x00000002, 0x00040020, 0x00000011, - 0x00000001, 0x00000010, 0x0004003b, 0x00000011, - 0x00000012, 0x00000001, 0x0004002b, 0x00000008, - 0x00000013, 0x00000000, 0x00040020, 0x00000014, - 0x00000001, 0x00000006, 0x0004002b, 0x00000006, - 0x0000001a, 0x00000000, 0x0004002b, 0x00000006, - 0x0000001b, 0x3f800000, 0x00040020, 0x0000001d, - 0x00000003, 0x00000007, 0x0004003b, 0x0000001d, - 0x0000001f, 0x00000003, 0x00040017, 0x00000020, - 0x00000006, 0x00000003, 0x00040020, 0x00000021, - 0x00000001, 0x00000020, 0x0004003b, 0x00000021, - 0x00000022, 0x00000001, 0x00050036, 0x00000002, - 0x00000004, 0x00000000, 0x00000003, 0x000200f8, - 0x00000005, 0x00050041, 0x00000014, 0x00000015, - 0x00000012, 0x00000013, 0x0004003d, 0x00000006, - 0x00000016, 0x00000015, 0x00050041, 0x00000014, - 0x00000017, 0x00000012, 0x00000009, 0x0004003d, - 0x00000006, 0x00000018, 0x00000017, 0x0004007f, - 0x00000006, 0x00000019, 0x00000018, 0x00070050, - 0x00000007, 0x0000001c, 0x00000016, 0x00000019, - 0x0000001a, 0x0000001b, 0x00050041, 0x0000001d, - 0x0000001e, 0x0000000d, 0x0000000f, 0x0003003e, - 0x0000001e, 0x0000001c, 0x0004003d, 0x00000020, - 0x00000023, 0x00000022, 0x00050051, 0x00000006, - 0x00000024, 0x00000023, 0x00000000, 0x00050051, - 0x00000006, 0x00000025, 0x00000023, 0x00000001, - 0x00050051, 0x00000006, 0x00000026, 0x00000023, - 0x00000002, 0x00070050, 0x00000007, 0x00000027, - 0x00000024, 0x00000025, 0x00000026, 0x0000001b, - 0x0003003e, 0x0000001f, 0x00000027, 0x000100fd, - 0x00010038 -}; - -static const Uint32 s_TriangleFragShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x0000000d, - 0x00000000, 0x00020011, 0x00000001, 0x0006000b, - 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, - 0x00000000, 0x0003000e, 0x00000000, 0x00000001, - 0x0007000f, 0x00000004, 0x00000004, 0x6e69616d, - 0x00000000, 0x00000009, 0x0000000b, 0x00030010, - 0x00000004, 0x00000007, 0x00030003, 0x00000002, - 0x000001c2, 0x00040005, 0x00000004, 0x6e69616d, - 0x00000000, 0x00040005, 0x00000009, 0x6f6c6f63, - 0x00000072, 0x00040005, 0x0000000b, 0x6c6f4361, - 0x0000726f, 0x00040047, 0x00000009, 0x0000001e, - 0x00000000, 0x00040047, 0x0000000b, 0x0000001e, - 0x00000000, 0x00020013, 0x00000002, 0x00030021, - 0x00000003, 0x00000002, 0x00030016, 0x00000006, - 0x00000020, 0x00040017, 0x00000007, 0x00000006, - 0x00000004, 0x00040020, 0x00000008, 0x00000003, - 0x00000007, 0x0004003b, 0x00000008, 0x00000009, - 0x00000003, 0x00040020, 0x0000000a, 0x00000001, - 0x00000007, 0x0004003b, 0x0000000a, 0x0000000b, - 0x00000001, 0x00050036, 0x00000002, 0x00000004, - 0x00000000, 0x00000003, 0x000200f8, 0x00000005, - 0x0004003d, 0x00000007, 0x0000000c, 0x0000000b, - 0x0003003e, 0x00000009, 0x0000000c, 0x000100fd, - 0x00010038 -}; - -static const Uint8 s_TriangleVertShaderDxil[] = { - 0x44, 0x58, 0x42, 0x43, 0x43, 0xaa, 0x4b, 0xdf, 0x49, 0x8b, 0x4b, 0xbe, - 0xc3, 0x3a, 0x72, 0x00, 0x02, 0xed, 0x6c, 0x73, 0x01, 0x00, 0x00, 0x00, - 0x38, 0x0c, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, - 0xe0, 0x01, 0x00, 0x00, 0xcc, 0x06, 0x00, 0x00, 0xe8, 0x06, 0x00, 0x00, - 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x58, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x43, 0x4f, 0x4c, - 0x4f, 0x52, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, 0x5c, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, - 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, - 0xc8, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4f, 0x53, - 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, - 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x42, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x43, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x44, 0x00, - 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x54, 0x41, 0x54, 0xe4, 0x04, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, - 0x39, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0xcc, 0x04, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, - 0x21, 0x0c, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, - 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, - 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, - 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, - 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, - 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, - 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, - 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, - 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, - 0xff, 0xff, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, - 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, - 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, - 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, - 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x19, 0x80, 0x39, 0x02, 0x30, - 0x98, 0x23, 0x40, 0x8a, 0x31, 0x44, 0x54, 0x44, 0x56, 0x0c, 0x20, 0xa2, - 0x1a, 0xc2, 0x81, 0x80, 0x4c, 0x20, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, - 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, - 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, - 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, - 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, - 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, - 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, - 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, - 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, - 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, - 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, 0x0d, 0x00, 0x00, 0x00, - 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, - 0xc6, 0x04, 0x43, 0xa2, 0x12, 0x18, 0x01, 0x28, 0x86, 0x32, 0x28, 0x87, - 0xf2, 0x28, 0x8e, 0x52, 0x28, 0x08, 0xaa, 0x92, 0x18, 0x01, 0x28, 0x82, - 0x32, 0x28, 0x04, 0xda, 0xb1, 0x92, 0x03, 0x09, 0x04, 0x00, 0x80, 0xc0, - 0x00, 0x14, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, - 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, - 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, - 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x88, 0x61, 0x82, 0x40, 0x10, - 0x1b, 0x84, 0x81, 0xd8, 0x20, 0x10, 0x04, 0x05, 0xbb, 0xb9, 0x09, 0x02, - 0x51, 0x6c, 0x18, 0x0e, 0x84, 0x98, 0x20, 0x08, 0xc0, 0x06, 0x60, 0xc3, - 0x40, 0x2c, 0xcb, 0x86, 0x80, 0xd9, 0x30, 0x0c, 0x4a, 0x33, 0x41, 0x58, - 0xa2, 0x0d, 0xc1, 0x43, 0xa2, 0x2d, 0x2c, 0xcd, 0x8d, 0x08, 0xd4, 0xd3, - 0x54, 0x12, 0x55, 0xd2, 0x93, 0xd3, 0x04, 0xa1, 0x60, 0x26, 0x08, 0x45, - 0xb3, 0x21, 0x20, 0x26, 0x08, 0x85, 0x33, 0x41, 0x20, 0x8c, 0x0d, 0xc2, - 0x75, 0x6d, 0x58, 0x08, 0x69, 0xa2, 0x2a, 0x6a, 0xb0, 0x08, 0x0a, 0x63, - 0x31, 0xf4, 0xc4, 0xf4, 0x24, 0x35, 0x41, 0x28, 0x9e, 0x09, 0x02, 0x71, - 0x6c, 0x10, 0x2e, 0x6e, 0xc3, 0x32, 0x68, 0x13, 0x55, 0x51, 0xc3, 0x36, - 0x50, 0xdd, 0x06, 0x21, 0xf3, 0xb8, 0x4c, 0x59, 0x7d, 0x41, 0xbd, 0xcd, - 0xa5, 0xd1, 0xa5, 0xbd, 0xb9, 0x4d, 0x10, 0x0a, 0x68, 0x82, 0x40, 0x20, - 0x1b, 0x84, 0x4b, 0x0c, 0x36, 0x2c, 0x04, 0x18, 0x4c, 0x5b, 0x15, 0x06, - 0x43, 0x18, 0x10, 0xd4, 0x18, 0x6c, 0x58, 0x06, 0x6d, 0xa2, 0x2a, 0x6b, - 0x08, 0x83, 0x81, 0x1a, 0x83, 0x0d, 0x02, 0x19, 0x94, 0xc1, 0x86, 0xe1, - 0x33, 0x03, 0x60, 0x43, 0xa1, 0x44, 0x67, 0x00, 0x00, 0x2c, 0xd2, 0xdc, - 0xe6, 0xe8, 0xe6, 0x26, 0x08, 0x44, 0x42, 0x63, 0x2e, 0xed, 0xec, 0x8b, - 0x8d, 0x6c, 0x82, 0x40, 0x28, 0x34, 0xe6, 0xd2, 0xce, 0xbe, 0xe6, 0xe8, - 0x26, 0x08, 0xc4, 0xb2, 0xc1, 0x48, 0x03, 0x35, 0x58, 0x03, 0x36, 0x68, - 0x03, 0x37, 0xa8, 0xc2, 0xc6, 0x66, 0xd7, 0xe6, 0x92, 0x46, 0x56, 0xe6, - 0x46, 0x37, 0x25, 0x08, 0xaa, 0x90, 0xe1, 0xb9, 0xd8, 0x95, 0xc9, 0xcd, - 0xa5, 0xbd, 0xb9, 0x4d, 0x09, 0x88, 0x26, 0x64, 0x78, 0x2e, 0x76, 0x61, - 0x6c, 0x76, 0x65, 0x72, 0x53, 0x82, 0xa2, 0x0e, 0x19, 0x9e, 0xcb, 0x1c, - 0x5a, 0x18, 0x59, 0x99, 0x5c, 0xd3, 0x1b, 0x59, 0x19, 0xdb, 0x94, 0x00, - 0xa9, 0x44, 0x86, 0xe7, 0x42, 0x97, 0x07, 0x57, 0x16, 0xe4, 0xe6, 0xf6, - 0x46, 0x17, 0x46, 0x97, 0xf6, 0xe6, 0x36, 0x37, 0x25, 0x68, 0xea, 0x90, - 0xe1, 0xb9, 0xd8, 0xa5, 0x95, 0xdd, 0x25, 0x91, 0x4d, 0xd1, 0x85, 0xd1, - 0x95, 0x4d, 0x09, 0x9e, 0x3a, 0x64, 0x78, 0x2e, 0x65, 0x6e, 0x74, 0x72, - 0x79, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x53, 0x82, 0x33, 0xe8, 0x42, - 0x86, 0xe7, 0x32, 0xf6, 0x56, 0xe7, 0x46, 0x57, 0x26, 0x37, 0x37, 0x25, - 0x70, 0x03, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, - 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, - 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, - 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, - 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, - 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, - 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, - 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, - 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, - 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, - 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, - 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, - 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, - 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, - 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, - 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, - 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, - 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, - 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, - 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, - 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, - 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, - 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, - 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, - 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, - 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x16, 0x30, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, - 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, - 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, - 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1a, 0x12, 0xec, 0x35, 0xb4, 0xdb, 0x6b, 0x4a, 0x7a, 0xae, 0xf3, 0xf6, - 0xa5, 0x3d, 0xb4, 0x25, 0x44, 0x58, 0x49, 0x4c, 0x48, 0x05, 0x00, 0x00, - 0x60, 0x00, 0x01, 0x00, 0x52, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x05, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, - 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, - 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, - 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, - 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, - 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x19, - 0x80, 0x39, 0x02, 0x30, 0x98, 0x23, 0x40, 0x8a, 0x31, 0x44, 0x54, 0x44, - 0x56, 0x0c, 0x20, 0xa2, 0x1a, 0xc2, 0x81, 0x80, 0x4c, 0x20, 0x00, 0x00, - 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, - 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, - 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, - 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, - 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, - 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, - 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, - 0x0c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, - 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xa2, 0x12, 0x18, 0x01, 0x28, - 0x89, 0x62, 0x28, 0x83, 0x72, 0x28, 0x0f, 0xaa, 0x92, 0x18, 0x01, 0x28, - 0x82, 0x32, 0x28, 0x04, 0xda, 0xb1, 0x92, 0x03, 0x09, 0x04, 0x00, 0x80, - 0xc0, 0x00, 0x14, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, - 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, - 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, - 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, - 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x88, 0x61, 0x82, 0x40, 0x10, - 0x1b, 0x84, 0x81, 0x98, 0x20, 0x10, 0xc5, 0x06, 0x61, 0x30, 0x28, 0xd8, - 0xcd, 0x4d, 0x10, 0x08, 0x63, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x61, 0x79, - 0x36, 0x04, 0xcb, 0x04, 0x41, 0x00, 0x48, 0xb4, 0x85, 0xa5, 0xb9, 0x11, - 0x81, 0x7a, 0x9a, 0x4a, 0xa2, 0x4a, 0x7a, 0x72, 0x9a, 0x20, 0x14, 0xca, - 0x04, 0xa1, 0x58, 0x36, 0x04, 0xc4, 0x04, 0xa1, 0x60, 0x26, 0x08, 0xc4, - 0xb1, 0x41, 0xa0, 0xa8, 0x0d, 0x0b, 0xf1, 0x40, 0x91, 0x14, 0x0d, 0x13, - 0x11, 0x55, 0x2c, 0x86, 0x9e, 0x98, 0x9e, 0xa4, 0x26, 0x08, 0x45, 0x33, - 0x41, 0x20, 0x90, 0x0d, 0x02, 0x95, 0x6d, 0x58, 0x86, 0x0b, 0x8a, 0xa4, - 0x68, 0xc0, 0x86, 0x48, 0xdb, 0x20, 0x58, 0x1b, 0x97, 0x29, 0xab, 0x2f, - 0xa8, 0xb7, 0xb9, 0x34, 0xba, 0xb4, 0x37, 0xb7, 0x09, 0x42, 0xe1, 0x4c, - 0x10, 0x88, 0x64, 0x83, 0x40, 0x7d, 0x1b, 0x16, 0xa2, 0x83, 0x30, 0xc9, - 0x1b, 0x3c, 0x22, 0x02, 0x83, 0x0d, 0xcb, 0x70, 0x41, 0x91, 0x34, 0x0d, - 0xde, 0x10, 0x81, 0xc1, 0x06, 0x21, 0x0c, 0xc4, 0x60, 0xc3, 0xc0, 0x8d, - 0x01, 0xb0, 0xa1, 0x68, 0x1c, 0x32, 0x00, 0x80, 0x2a, 0x6c, 0x6c, 0x76, - 0x6d, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, - 0x9e, 0x8b, 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, - 0x42, 0x86, 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26, 0x37, 0x25, 0x30, - 0xea, 0x90, 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, - 0x91, 0x95, 0xb1, 0x4d, 0x09, 0x92, 0x3a, 0x64, 0x78, 0x2e, 0x76, 0x69, - 0x65, 0x77, 0x49, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x82, 0xa5, - 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, - 0x1b, 0xdd, 0xdc, 0x94, 0x80, 0x0c, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, - 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, - 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, - 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, - 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, - 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, - 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, - 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, - 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, - 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, - 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, - 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, - 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, - 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, - 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, - 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, - 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, - 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, - 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, - 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, - 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, - 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, - 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, - 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, - 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, - 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x16, 0x30, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0xe2, - 0x00, 0x83, 0xd8, 0x3c, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, - 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, - 0x17, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, - 0x61, 0x20, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, - 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x54, 0x25, 0x40, 0x34, - 0x03, 0x50, 0x0a, 0x85, 0x40, 0x33, 0x02, 0x30, 0x46, 0x00, 0x82, 0x20, - 0x88, 0x7f, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x60, 0x54, - 0xc3, 0x24, 0x2d, 0xc5, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x16, - 0x41, 0x4d, 0x87, 0x31, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0xc6, 0x55, - 0x54, 0x14, 0x73, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0x81, 0x19, - 0x55, 0xe5, 0x20, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x60, 0x64, 0x87, - 0x65, 0x29, 0xc9, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x59, 0x72, - 0x5d, 0x90, 0x30, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x96, 0x5c, - 0xd7, 0x12, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x25, 0xd7, - 0xf5, 0x1c, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x64, 0xc9, 0x75, - 0x39, 0xc6, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x59, 0x82, 0x5d, - 0x50, 0x31, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x48, 0x96, 0x60, 0xd7, - 0x42, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x25, 0xd8, 0xf5, - 0x0c, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x64, 0x09, 0x76, 0x39, - 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const Uint8 s_TriangleFragShaderDxil[] = { - 0x44, 0x58, 0x42, 0x43, 0x7e, 0x0a, 0x30, 0x58, 0x0c, 0x74, 0x45, 0xb2, - 0x7d, 0x54, 0xd2, 0x32, 0xbe, 0xaa, 0xdb, 0x3f, 0x01, 0x00, 0x00, 0x00, - 0x84, 0x0b, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, - 0x9c, 0x01, 0x00, 0x00, 0x70, 0x06, 0x00, 0x00, 0x8c, 0x06, 0x00, 0x00, - 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x5c, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, - 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, - 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, - 0xa8, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x43, 0x4f, 0x4c, - 0x4f, 0x52, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x44, 0x00, - 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x44, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xcc, 0x04, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xb4, 0x04, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, - 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, - 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, - 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, - 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, - 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x19, - 0x80, 0x39, 0x02, 0x30, 0x98, 0x23, 0x40, 0x8a, 0x31, 0x44, 0x54, 0x44, - 0x56, 0x0c, 0x20, 0xa2, 0x1a, 0xc2, 0x81, 0x80, 0x54, 0x20, 0x00, 0x00, - 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, - 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, - 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, - 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, - 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, - 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, - 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, - 0x0d, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, - 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xa2, 0x12, 0x18, 0x01, 0x28, - 0x86, 0x32, 0x28, 0x8f, 0x92, 0x28, 0x04, 0xaa, 0x92, 0x28, 0x83, 0x42, - 0x18, 0x01, 0x28, 0x82, 0x02, 0xa1, 0x1d, 0x4b, 0x41, 0x08, 0x00, 0x00, - 0x80, 0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, - 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, - 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, - 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x88, - 0x61, 0x82, 0x40, 0x10, 0x1b, 0x84, 0x81, 0xd8, 0x20, 0x10, 0x04, 0x05, - 0xb8, 0xb9, 0x09, 0x02, 0x51, 0x6c, 0x18, 0x0e, 0x84, 0x98, 0x20, 0x08, - 0xc0, 0x06, 0x60, 0xc3, 0x40, 0x2c, 0xcb, 0x86, 0x80, 0xd9, 0x30, 0x0c, - 0x4a, 0x33, 0x41, 0x58, 0xa0, 0x0d, 0xc1, 0x43, 0xa2, 0x2d, 0x2c, 0xcd, - 0x8d, 0xcb, 0x94, 0xd5, 0x17, 0xd4, 0xdb, 0x5c, 0x1a, 0x5d, 0xda, 0x9b, - 0xdb, 0x04, 0xa1, 0x50, 0x26, 0x08, 0xc5, 0xb2, 0x21, 0x20, 0x26, 0x08, - 0x05, 0x33, 0x41, 0x28, 0x9a, 0x0d, 0x0b, 0x21, 0x4d, 0x54, 0x65, 0x0d, - 0x16, 0x71, 0x01, 0x2c, 0x86, 0x9e, 0x98, 0x9e, 0xa4, 0x26, 0x08, 0x85, - 0x33, 0x41, 0x20, 0x8c, 0x09, 0x02, 0x71, 0x6c, 0x10, 0x36, 0x6e, 0xc3, - 0x32, 0x64, 0xd3, 0x55, 0x69, 0x83, 0x35, 0x5c, 0xdd, 0x06, 0x01, 0xf3, - 0x98, 0x4c, 0x59, 0x7d, 0x51, 0x85, 0xc9, 0x9d, 0x95, 0xd1, 0x4d, 0x10, - 0x8a, 0x67, 0xc3, 0x42, 0x80, 0xc1, 0x14, 0x06, 0xd5, 0x35, 0x58, 0xc4, - 0xd5, 0x6d, 0x08, 0xc4, 0x60, 0xc3, 0xf0, 0x8d, 0x01, 0xb0, 0xa1, 0x50, - 0x22, 0x32, 0x00, 0x00, 0x16, 0x69, 0x6e, 0x73, 0x74, 0x73, 0x13, 0x04, - 0x02, 0xa1, 0x31, 0x97, 0x76, 0xf6, 0xc5, 0x46, 0x36, 0x41, 0x20, 0x12, - 0x1a, 0x73, 0x69, 0x67, 0x5f, 0x73, 0x74, 0x1b, 0x0c, 0x33, 0x38, 0x03, - 0x34, 0x48, 0x03, 0x35, 0x48, 0x83, 0x2a, 0x6c, 0x6c, 0x76, 0x6d, 0x2e, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x82, 0xa0, 0x0a, 0x19, 0x9e, 0x8b, - 0x5d, 0x99, 0xdc, 0x5c, 0xda, 0x9b, 0xdb, 0x94, 0x80, 0x68, 0x42, 0x86, - 0xe7, 0x62, 0x17, 0xc6, 0x66, 0x57, 0x26, 0x37, 0x25, 0x28, 0xea, 0x90, - 0xe1, 0xb9, 0xcc, 0xa1, 0x85, 0x91, 0x95, 0xc9, 0x35, 0xbd, 0x91, 0x95, - 0xb1, 0x4d, 0x09, 0x90, 0x4a, 0x64, 0x78, 0x2e, 0x74, 0x79, 0x70, 0x65, - 0x41, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x53, - 0x82, 0xa6, 0x0e, 0x19, 0x9e, 0x8b, 0x5d, 0x5a, 0xd9, 0x5d, 0x12, 0xd9, - 0x14, 0x5d, 0x18, 0x5d, 0xd9, 0x94, 0xe0, 0xa9, 0x43, 0x86, 0xe7, 0x52, - 0xe6, 0x46, 0x27, 0x97, 0x07, 0xf5, 0x96, 0xe6, 0x46, 0x37, 0x37, 0x25, - 0x20, 0x83, 0x2e, 0x64, 0x78, 0x2e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, - 0x72, 0x73, 0x53, 0x02, 0x35, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, - 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, - 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, - 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, - 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, - 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, - 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, - 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, - 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, - 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, - 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, - 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, - 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, - 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, - 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, - 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, - 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, - 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, - 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, - 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, - 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, - 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, - 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, - 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20, - 0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, - 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x16, 0x30, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0xe2, - 0x00, 0x83, 0xd8, 0x3c, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, - 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, - 0x17, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x3c, 0x43, 0x04, 0x79, 0x2c, 0x87, 0xd0, 0x04, - 0xaa, 0xf4, 0x85, 0xf5, 0x84, 0xb6, 0x2b, 0x16, 0x44, 0x58, 0x49, 0x4c, - 0xf0, 0x04, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, - 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0xd8, 0x04, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, - 0x33, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, - 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, - 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, - 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, - 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, - 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, - 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, - 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, - 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, - 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, - 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, - 0x25, 0x00, 0x8a, 0x19, 0x80, 0x39, 0x02, 0x30, 0x98, 0x23, 0x40, 0x8a, - 0x31, 0x44, 0x54, 0x44, 0x56, 0x0c, 0x20, 0xa2, 0x1a, 0xc2, 0x81, 0x80, - 0x54, 0x20, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, - 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, - 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, - 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, - 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, - 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, - 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, - 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, - 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, - 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, - 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0xc8, 0x02, 0x01, 0x0c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, - 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xa2, - 0x12, 0x18, 0x01, 0x28, 0x89, 0x62, 0x28, 0x83, 0xf2, 0xa0, 0x2a, 0x89, - 0x32, 0x28, 0x84, 0x11, 0x80, 0x22, 0x28, 0x10, 0xda, 0xb1, 0x14, 0x84, - 0x00, 0x00, 0x00, 0x08, 0x04, 0x02, 0x01, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, - 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, - 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, - 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x88, - 0x61, 0x82, 0x40, 0x10, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x10, 0xc5, 0x06, - 0x61, 0x30, 0x28, 0xc0, 0xcd, 0x4d, 0x10, 0x08, 0x63, 0xc3, 0x80, 0x24, - 0xc4, 0x04, 0x61, 0x79, 0x36, 0x04, 0xcb, 0x04, 0x41, 0x00, 0x48, 0xb4, - 0x85, 0xa5, 0xb9, 0x71, 0x99, 0xb2, 0xfa, 0x82, 0x7a, 0x9b, 0x4b, 0xa3, - 0x4b, 0x7b, 0x73, 0x9b, 0x20, 0x14, 0xc9, 0x04, 0xa1, 0x50, 0x36, 0x04, - 0xc4, 0x04, 0xa1, 0x58, 0x26, 0x08, 0x05, 0xb3, 0x61, 0x21, 0x1e, 0x28, - 0x92, 0xa6, 0x61, 0x22, 0x28, 0x80, 0xc5, 0xd0, 0x13, 0xd3, 0x93, 0xd4, - 0x04, 0xa1, 0x68, 0x26, 0x08, 0xc4, 0x31, 0x41, 0x20, 0x90, 0x0d, 0x02, - 0x96, 0x6d, 0x58, 0x06, 0x0b, 0xa2, 0xa4, 0x6b, 0x98, 0x06, 0x4a, 0xdb, - 0x20, 0x54, 0x1b, 0x93, 0x29, 0xab, 0x2f, 0xaa, 0x30, 0xb9, 0xb3, 0x32, - 0xba, 0x09, 0x42, 0xe1, 0x6c, 0x58, 0x88, 0x0e, 0xf2, 0x24, 0x6a, 0x98, - 0x08, 0x4a, 0xdb, 0x10, 0x7c, 0x1b, 0x06, 0x0e, 0x0c, 0x80, 0x0d, 0x45, - 0xe3, 0x84, 0x01, 0x00, 0x54, 0x61, 0x63, 0xb3, 0x6b, 0x73, 0x49, 0x23, - 0x2b, 0x73, 0xa3, 0x9b, 0x12, 0x04, 0x55, 0xc8, 0xf0, 0x5c, 0xec, 0xca, - 0xe4, 0xe6, 0xd2, 0xde, 0xdc, 0xa6, 0x04, 0x44, 0x13, 0x32, 0x3c, 0x17, - 0xbb, 0x30, 0x36, 0xbb, 0x32, 0xb9, 0x29, 0x81, 0x51, 0x87, 0x0c, 0xcf, - 0x65, 0x0e, 0x2d, 0x8c, 0xac, 0x4c, 0xae, 0xe9, 0x8d, 0xac, 0x8c, 0x6d, - 0x4a, 0x90, 0xd4, 0x21, 0xc3, 0x73, 0xb1, 0x4b, 0x2b, 0xbb, 0x4b, 0x22, - 0x9b, 0xa2, 0x0b, 0xa3, 0x2b, 0x9b, 0x12, 0x2c, 0x75, 0xc8, 0xf0, 0x5c, - 0xca, 0xdc, 0xe8, 0xe4, 0xf2, 0xa0, 0xde, 0xd2, 0xdc, 0xe8, 0xe6, 0xa6, - 0x04, 0x61, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, - 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, - 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, - 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, - 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, - 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, - 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, - 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, - 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, - 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, - 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, - 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, - 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, - 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, - 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, - 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, - 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, - 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, - 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, - 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, - 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, - 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, - 0x21, 0x07, 0x7c, 0x70, 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, - 0xd1, 0x43, 0x0e, 0xf8, 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, - 0xf6, 0x10, 0x0e, 0xf2, 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, - 0xf4, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x16, 0x30, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, - 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, - 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, - 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x44, 0x85, 0x30, 0x03, 0x50, 0x0a, 0x54, 0x25, - 0x00, 0x00, 0x00, 0x00, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x60, 0x4c, - 0x44, 0x04, 0x21, 0xc3, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x54, - 0x21, 0x45, 0x02, 0x31, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x46, 0x65, - 0x4c, 0x52, 0x52, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0x61, 0x1d, - 0xd4, 0xd4, 0x18, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x58, 0x06, - 0x45, 0x31, 0xc4, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x96, 0x41, - 0x51, 0xc5, 0x30, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x88, 0x65, 0x50, - 0xd4, 0x22, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x62, 0x19, 0x14, - 0xe5, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -// ================================================== -// Mesh -// ================================================== - -// GLSL -// #version 460 -// #extension GL_EXT_mesh_shader : require - -// layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; -// layout(max_vertices = 4, max_primitives = 2) out; -// layout(triangles) out; - -// layout(location = 0) out vec4 vColors[]; - -// void main() -// { -// SetMeshOutputsEXT(4, 2); -// gl_MeshVerticesEXT[0].gl_Position = vec4(-0.5, 0.5, 0.0, 1.0); -// gl_MeshVerticesEXT[1].gl_Position = vec4( 0.5, 0.5, 0.0, 1.0); -// gl_MeshVerticesEXT[2].gl_Position = vec4( 0.5,-0.5, 0.0, 1.0); -// gl_MeshVerticesEXT[3].gl_Position = vec4(-0.5,-0.5, 0.0, 1.0); - -// // colors -// vColors[0] = vec4(1.0, 0.0, 0.0, 1.0); -// vColors[1] = vec4(0.0, 1.0, 0.0, 1.0); -// vColors[2] = vec4(0.0, 0.0, 1.0, 1.0); -// vColors[3] = vec4(1.0, 0.0, 0.0, 1.0); - -// gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); -// gl_PrimitiveTriangleIndicesEXT[1] = uvec3(0, 2, 3); -// } - -// HLSL -// struct MSOutput -// { -// float4 position : SV_POSITION; -// float4 color : COLOR; -// }; - -// [outputtopology("triangle")] -// [numthreads(1, 1, 1)] -// void main( -// out vertices MSOutput meshVertices[4], -// out indices uint3 triangleIndices[2]) -// { -// SetMeshOutputCounts(4, 2); -// meshVertices[0].position = float4(-0.5, 0.5, 0.0, 1.0); -// meshVertices[1].position = float4( 0.5, 0.5, 0.0, 1.0); -// meshVertices[2].position = float4( 0.5,-0.5, 0.0, 1.0); -// meshVertices[3].position = float4(-0.5,-0.5, 0.0, 1.0); - -// meshVertices[0].color = float4(1.0, 0.0, 0.0, 1.0); -// meshVertices[1].color = float4(0.0, 1.0, 0.0, 1.0); -// meshVertices[2].color = float4(0.0, 0.0, 1.0, 1.0); -// meshVertices[3].color = float4(1.0, 0.0, 0.0, 1.0); - -// triangleIndices[0] = uint3(0, 1, 2); -// triangleIndices[1] = uint3(0, 2, 3); -// } - -static const Uint32 s_MeshShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x00000039, - 0x00000000, 0x00020011, 0x000014a3, 0x0006000a, - 0x5f565053, 0x5f545845, 0x6873656d, 0x6168735f, - 0x00726564, 0x0006000b, 0x00000001, 0x4c534c47, - 0x6474732e, 0x3035342e, 0x00000000, 0x0003000e, - 0x00000000, 0x00000001, 0x0008000f, 0x000014f5, - 0x00000004, 0x6e69616d, 0x00000000, 0x00000010, - 0x00000025, 0x00000030, 0x0006014b, 0x00000004, - 0x00000026, 0x00000007, 0x00000007, 0x00000007, - 0x00040010, 0x00000004, 0x0000001a, 0x00000004, - 0x00040010, 0x00000004, 0x00001496, 0x00000002, - 0x00030010, 0x00000004, 0x000014b2, 0x00030003, - 0x00000002, 0x000001cc, 0x00060004, 0x455f4c47, - 0x6d5f5458, 0x5f687365, 0x64616873, 0x00007265, - 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, - 0x00070005, 0x0000000d, 0x4d5f6c67, 0x50687365, - 0x65567265, 0x78657472, 0x00545845, 0x00060006, - 0x0000000d, 0x00000000, 0x505f6c67, 0x7469736f, - 0x006e6f69, 0x00070006, 0x0000000d, 0x00000001, - 0x505f6c67, 0x746e696f, 0x657a6953, 0x00000000, - 0x00070006, 0x0000000d, 0x00000002, 0x435f6c67, - 0x4470696c, 0x61747369, 0x0065636e, 0x00070006, - 0x0000000d, 0x00000003, 0x435f6c67, 0x446c6c75, - 0x61747369, 0x0065636e, 0x00070005, 0x00000010, - 0x4d5f6c67, 0x56687365, 0x69747265, 0x45736563, - 0x00005458, 0x00040005, 0x00000025, 0x6c6f4376, - 0x0073726f, 0x000a0005, 0x00000030, 0x505f6c67, - 0x696d6972, 0x65766974, 0x61697254, 0x656c676e, - 0x69646e49, 0x45736563, 0x00005458, 0x00030047, - 0x0000000d, 0x00000002, 0x00050048, 0x0000000d, - 0x00000000, 0x0000000b, 0x00000000, 0x00050048, - 0x0000000d, 0x00000001, 0x0000000b, 0x00000001, - 0x00050048, 0x0000000d, 0x00000002, 0x0000000b, - 0x00000003, 0x00050048, 0x0000000d, 0x00000003, - 0x0000000b, 0x00000004, 0x00040047, 0x00000025, - 0x0000001e, 0x00000000, 0x00040047, 0x00000030, - 0x0000000b, 0x000014b0, 0x00020013, 0x00000002, - 0x00030021, 0x00000003, 0x00000002, 0x00040015, - 0x00000006, 0x00000020, 0x00000000, 0x0004002b, - 0x00000006, 0x00000007, 0x00000001, 0x0004002b, - 0x00000006, 0x00000008, 0x00000004, 0x0004002b, - 0x00000006, 0x00000009, 0x00000002, 0x00030016, - 0x0000000a, 0x00000020, 0x00040017, 0x0000000b, - 0x0000000a, 0x00000004, 0x0004001c, 0x0000000c, - 0x0000000a, 0x00000007, 0x0006001e, 0x0000000d, - 0x0000000b, 0x0000000a, 0x0000000c, 0x0000000c, - 0x0004001c, 0x0000000e, 0x0000000d, 0x00000008, - 0x00040020, 0x0000000f, 0x00000003, 0x0000000e, - 0x0004003b, 0x0000000f, 0x00000010, 0x00000003, - 0x00040015, 0x00000011, 0x00000020, 0x00000001, - 0x0004002b, 0x00000011, 0x00000012, 0x00000000, - 0x0004002b, 0x0000000a, 0x00000013, 0xbf000000, - 0x0004002b, 0x0000000a, 0x00000014, 0x3f000000, - 0x0004002b, 0x0000000a, 0x00000015, 0x00000000, - 0x0004002b, 0x0000000a, 0x00000016, 0x3f800000, - 0x0007002c, 0x0000000b, 0x00000017, 0x00000013, - 0x00000014, 0x00000015, 0x00000016, 0x00040020, - 0x00000018, 0x00000003, 0x0000000b, 0x0004002b, - 0x00000011, 0x0000001a, 0x00000001, 0x0007002c, - 0x0000000b, 0x0000001b, 0x00000014, 0x00000014, - 0x00000015, 0x00000016, 0x0004002b, 0x00000011, - 0x0000001d, 0x00000002, 0x0007002c, 0x0000000b, - 0x0000001e, 0x00000014, 0x00000013, 0x00000015, - 0x00000016, 0x0004002b, 0x00000011, 0x00000020, - 0x00000003, 0x0007002c, 0x0000000b, 0x00000021, - 0x00000013, 0x00000013, 0x00000015, 0x00000016, - 0x0004001c, 0x00000023, 0x0000000b, 0x00000008, - 0x00040020, 0x00000024, 0x00000003, 0x00000023, - 0x0004003b, 0x00000024, 0x00000025, 0x00000003, - 0x0007002c, 0x0000000b, 0x00000026, 0x00000016, - 0x00000015, 0x00000015, 0x00000016, 0x0007002c, - 0x0000000b, 0x00000028, 0x00000015, 0x00000016, - 0x00000015, 0x00000016, 0x0007002c, 0x0000000b, - 0x0000002a, 0x00000015, 0x00000015, 0x00000016, - 0x00000016, 0x00040017, 0x0000002d, 0x00000006, - 0x00000003, 0x0004001c, 0x0000002e, 0x0000002d, - 0x00000009, 0x00040020, 0x0000002f, 0x00000003, - 0x0000002e, 0x0004003b, 0x0000002f, 0x00000030, - 0x00000003, 0x0004002b, 0x00000006, 0x00000031, - 0x00000000, 0x0006002c, 0x0000002d, 0x00000032, - 0x00000031, 0x00000007, 0x00000009, 0x00040020, - 0x00000033, 0x00000003, 0x0000002d, 0x0004002b, - 0x00000006, 0x00000035, 0x00000003, 0x0006002c, - 0x0000002d, 0x00000036, 0x00000031, 0x00000009, - 0x00000035, 0x0006002c, 0x0000002d, 0x00000038, - 0x00000007, 0x00000007, 0x00000007, 0x00050036, - 0x00000002, 0x00000004, 0x00000000, 0x00000003, - 0x000200f8, 0x00000005, 0x000314af, 0x00000008, - 0x00000009, 0x00060041, 0x00000018, 0x00000019, - 0x00000010, 0x00000012, 0x00000012, 0x0003003e, - 0x00000019, 0x00000017, 0x00060041, 0x00000018, - 0x0000001c, 0x00000010, 0x0000001a, 0x00000012, - 0x0003003e, 0x0000001c, 0x0000001b, 0x00060041, - 0x00000018, 0x0000001f, 0x00000010, 0x0000001d, - 0x00000012, 0x0003003e, 0x0000001f, 0x0000001e, - 0x00060041, 0x00000018, 0x00000022, 0x00000010, - 0x00000020, 0x00000012, 0x0003003e, 0x00000022, - 0x00000021, 0x00050041, 0x00000018, 0x00000027, - 0x00000025, 0x00000012, 0x0003003e, 0x00000027, - 0x00000026, 0x00050041, 0x00000018, 0x00000029, - 0x00000025, 0x0000001a, 0x0003003e, 0x00000029, - 0x00000028, 0x00050041, 0x00000018, 0x0000002b, - 0x00000025, 0x0000001d, 0x0003003e, 0x0000002b, - 0x0000002a, 0x00050041, 0x00000018, 0x0000002c, - 0x00000025, 0x00000020, 0x0003003e, 0x0000002c, - 0x00000026, 0x00050041, 0x00000033, 0x00000034, - 0x00000030, 0x00000012, 0x0003003e, 0x00000034, - 0x00000032, 0x00050041, 0x00000033, 0x00000037, - 0x00000030, 0x0000001a, 0x0003003e, 0x00000037, - 0x00000036, 0x000100fd, 0x00010038 -}; - -static const Uint8 s_MeshShaderDxil[] = { - 0x44, 0x58, 0x42, 0x43, 0xcb, 0xfe, 0x8e, 0x94, 0x80, 0xad, 0x7f, 0xe3, - 0xef, 0xa4, 0xa8, 0x66, 0x70, 0x03, 0x1a, 0xab, 0x01, 0x00, 0x00, 0x00, - 0xc0, 0x0c, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x40, 0x01, 0x00, 0x00, 0x24, 0x06, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, - 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, - 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x00, 0x00, - 0x50, 0x53, 0x56, 0x30, 0x78, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x0d, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x00, 0x43, 0x4f, 0x4c, 0x4f, 0x52, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, - 0x03, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x44, 0x00, 0x03, 0x02, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, - 0xdc, 0x04, 0x00, 0x00, 0x65, 0x00, 0x0d, 0x00, 0x37, 0x01, 0x00, 0x00, - 0x44, 0x58, 0x49, 0x4c, 0x05, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0xc4, 0x04, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, - 0x2e, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, - 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, - 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, - 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, - 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, - 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, - 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, - 0x40, 0x02, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x13, 0x82, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, - 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, - 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x38, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x39, - 0x02, 0x30, 0x28, 0x06, 0xcc, 0xcc, 0x0c, 0xd1, 0x1c, 0x01, 0x32, 0x03, - 0x50, 0x0e, 0x98, 0x19, 0xbb, 0x21, 0x2c, 0x04, 0xcc, 0x0c, 0xe9, 0x40, - 0x40, 0x0e, 0x0c, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, - 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, - 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, - 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, - 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, - 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, - 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, - 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, - 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, - 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, - 0x3c, 0x04, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x79, 0x10, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0xf2, 0x28, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x90, 0x05, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, - 0xc6, 0x04, 0x43, 0x9a, 0x12, 0x28, 0x85, 0x11, 0x80, 0x62, 0x28, 0x83, - 0xf2, 0x28, 0x89, 0x42, 0x28, 0x82, 0x42, 0x2a, 0x20, 0xb2, 0x92, 0x28, - 0x83, 0x42, 0x18, 0x01, 0x28, 0x02, 0xea, 0xb1, 0x06, 0x00, 0x01, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, - 0x46, 0x02, 0x13, 0x44, 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, - 0xc6, 0x25, 0xc7, 0x45, 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, - 0x45, 0x26, 0x86, 0x4c, 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, - 0x10, 0x4c, 0x10, 0x06, 0x62, 0x82, 0x30, 0x14, 0x1b, 0x84, 0x81, 0x98, - 0x20, 0x0c, 0xc6, 0x06, 0xc1, 0x30, 0x28, 0xb4, 0xcd, 0x4d, 0x10, 0x86, - 0x63, 0xc3, 0x80, 0x24, 0xc4, 0x04, 0x41, 0x00, 0x36, 0x00, 0x1b, 0x06, - 0x83, 0x61, 0x36, 0x04, 0xcd, 0x86, 0x61, 0x58, 0x9c, 0x09, 0x42, 0x43, - 0x6d, 0x08, 0x20, 0x12, 0x6d, 0x61, 0x69, 0x6e, 0x5c, 0xa6, 0xac, 0xbe, - 0xa0, 0xde, 0xe6, 0xd2, 0xe8, 0xd2, 0xde, 0xdc, 0x26, 0x08, 0xc6, 0x33, - 0x41, 0x30, 0xa0, 0x0d, 0x81, 0x31, 0x41, 0x30, 0xa2, 0x09, 0x82, 0x21, - 0x4d, 0x10, 0x06, 0x64, 0x82, 0x30, 0x24, 0x1b, 0x84, 0x4c, 0xdb, 0xb0, - 0x18, 0x13, 0x55, 0x59, 0xd7, 0x70, 0x19, 0xd8, 0xc6, 0x62, 0xe8, 0x89, - 0xe9, 0x49, 0x6a, 0x82, 0x60, 0x4c, 0x1b, 0x96, 0xa1, 0xa3, 0x30, 0xcb, - 0x1b, 0xae, 0x01, 0xdb, 0x36, 0x08, 0xdc, 0xb7, 0x61, 0x00, 0xc0, 0x00, - 0x98, 0x20, 0x0c, 0xca, 0x86, 0x61, 0x18, 0x86, 0x09, 0xc2, 0xb0, 0x4c, - 0x10, 0x06, 0x66, 0x43, 0x31, 0x06, 0x64, 0x50, 0x06, 0x65, 0x60, 0x6c, - 0x10, 0xc4, 0xc0, 0x0c, 0x36, 0x14, 0x8b, 0x14, 0x06, 0xc0, 0x19, 0xb0, - 0x48, 0x73, 0x9b, 0xa3, 0x9b, 0x9b, 0x20, 0x0c, 0x0d, 0x8d, 0xb9, 0xb4, - 0xb3, 0xaf, 0x39, 0xba, 0x09, 0xc2, 0xe0, 0x6c, 0x20, 0xd2, 0x40, 0x0d, - 0xd6, 0x80, 0x0d, 0xaa, 0xb0, 0xb1, 0xd9, 0xb5, 0xb9, 0xa4, 0x91, 0x95, - 0xb9, 0xd1, 0x4d, 0x09, 0x82, 0x2a, 0x64, 0x78, 0x2e, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x02, 0xa2, 0x09, 0x19, 0x9e, 0x8b, 0x5d, - 0x18, 0x9b, 0x5d, 0x99, 0xdc, 0x94, 0xc0, 0xa8, 0x43, 0x86, 0xe7, 0x32, - 0x87, 0x16, 0x46, 0x56, 0x26, 0xd7, 0xf4, 0x46, 0x56, 0xc6, 0x36, 0x25, - 0x48, 0x2a, 0x91, 0xe1, 0xb9, 0xd0, 0xe5, 0xc1, 0x95, 0x05, 0xb9, 0xb9, - 0xbd, 0xd1, 0x85, 0xd1, 0xa5, 0xbd, 0xb9, 0xcd, 0x4d, 0x09, 0x9c, 0x3a, - 0x64, 0x78, 0x2e, 0x76, 0x69, 0x65, 0x77, 0x49, 0x64, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x53, 0x02, 0xa8, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, - 0x5c, 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0xe0, 0x0c, 0xba, - 0x90, 0xe1, 0xb9, 0x8c, 0xbd, 0xd5, 0xb9, 0xd1, 0x95, 0xc9, 0xcd, 0x4d, - 0x09, 0xd8, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, - 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, - 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, - 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, - 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, - 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, - 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, - 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, - 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, - 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, - 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, - 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, - 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, - 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, - 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, - 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, - 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, - 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, - 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, - 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, - 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, - 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, - 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, - 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, - 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, - 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x16, 0x10, 0x0d, 0x97, 0xef, 0x3c, 0x3e, 0xc1, 0x20, 0x93, 0xd8, 0x0c, - 0x88, 0x40, 0x48, 0x36, 0x90, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x44, 0x4c, - 0x26, 0x21, 0x1d, 0x28, 0x35, 0x3d, 0xd4, 0xc4, 0x39, 0x54, 0x33, 0x49, - 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x34, 0x39, 0x11, 0xf1, 0x12, - 0xd1, 0x44, 0x5c, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, - 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xdc, 0x4d, 0x54, 0xec, 0x84, 0x03, 0xa5, 0xfb, 0x85, 0xf8, 0x53, 0x5a, - 0x52, 0x72, 0x23, 0x6a, 0x44, 0x58, 0x49, 0x4c, 0x78, 0x06, 0x00, 0x00, - 0x65, 0x00, 0x0d, 0x00, 0x9e, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x05, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x95, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x1b, 0x88, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0x00, 0x00, - 0x49, 0x18, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x13, 0x82, 0x00, 0x00, - 0x89, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, - 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, - 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, - 0x10, 0x38, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x39, 0x02, 0x30, 0x28, 0x06, - 0xcc, 0xcc, 0x0c, 0xd1, 0x1c, 0x01, 0x32, 0x03, 0x50, 0x0e, 0x98, 0x19, - 0xbb, 0x21, 0x2c, 0x04, 0xcc, 0x0c, 0xe9, 0x40, 0x40, 0x0e, 0x0c, 0x00, - 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, - 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, - 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, - 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, - 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, - 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, - 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x04, 0x10, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xf2, 0x28, - 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x05, - 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, - 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x9a, - 0x12, 0x28, 0x85, 0x92, 0x28, 0x86, 0x11, 0x80, 0x32, 0x28, 0x8f, 0x42, - 0x28, 0x02, 0xb2, 0x92, 0x28, 0x83, 0x42, 0x18, 0x01, 0x28, 0x02, 0xea, - 0xb1, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0x44, - 0x8f, 0x0c, 0x6f, 0xec, 0xed, 0x4d, 0x0c, 0x24, 0xc6, 0x25, 0xc7, 0x45, - 0xc6, 0x06, 0x46, 0xc6, 0x25, 0xe6, 0x06, 0x04, 0x45, 0x26, 0x86, 0x4c, - 0x06, 0xc7, 0xec, 0x46, 0xe6, 0x26, 0x65, 0x43, 0x10, 0x4c, 0x10, 0x06, - 0x62, 0x82, 0x30, 0x14, 0x1b, 0x84, 0x81, 0x98, 0x20, 0x0c, 0xc6, 0x06, - 0x61, 0x30, 0x28, 0xb4, 0xcd, 0x4d, 0x10, 0x86, 0x63, 0xc3, 0x80, 0x24, - 0xc4, 0x04, 0xa1, 0x91, 0x36, 0x04, 0xcb, 0x04, 0x41, 0x00, 0x48, 0xb4, - 0x85, 0xa5, 0xb9, 0x4d, 0x10, 0x06, 0x84, 0xcb, 0x94, 0xd5, 0x17, 0xd4, - 0xdb, 0x5c, 0x1a, 0x5d, 0xda, 0x9b, 0xdb, 0x04, 0xc1, 0x68, 0x26, 0x08, - 0x86, 0xb3, 0x21, 0x78, 0x26, 0x08, 0xc6, 0x33, 0x41, 0x30, 0xa0, 0x09, - 0xc2, 0x90, 0x4c, 0x10, 0x06, 0x65, 0x83, 0x60, 0x5d, 0x1b, 0x96, 0x07, - 0x8a, 0xa4, 0x89, 0x1a, 0xa8, 0xa7, 0xc2, 0x58, 0x0c, 0x3d, 0x31, 0x3d, - 0x49, 0x4d, 0x10, 0x8c, 0x68, 0xc3, 0x32, 0x68, 0x51, 0x35, 0x6d, 0x03, - 0x35, 0x54, 0xd8, 0x06, 0x21, 0xe3, 0x36, 0x0c, 0x40, 0x07, 0x6c, 0x18, - 0x86, 0x61, 0x98, 0x20, 0x0c, 0xcb, 0x04, 0x61, 0x60, 0x36, 0x14, 0x1f, - 0x18, 0x84, 0x41, 0x18, 0x3c, 0x1b, 0x04, 0x43, 0x0c, 0x36, 0x14, 0x8d, - 0xe3, 0x01, 0x63, 0x50, 0x85, 0x8d, 0xcd, 0xae, 0xcd, 0x25, 0x8d, 0xac, - 0xcc, 0x8d, 0x6e, 0x4a, 0x10, 0x54, 0x21, 0xc3, 0x73, 0xb1, 0x2b, 0x93, - 0x9b, 0x4b, 0x7b, 0x73, 0x9b, 0x12, 0x10, 0x4d, 0xc8, 0xf0, 0x5c, 0xec, - 0xc2, 0xd8, 0xec, 0xca, 0xe4, 0xa6, 0x04, 0x46, 0x1d, 0x32, 0x3c, 0x97, - 0x39, 0xb4, 0x30, 0xb2, 0x32, 0xb9, 0xa6, 0x37, 0xb2, 0x32, 0xb6, 0x29, - 0x41, 0x52, 0x87, 0x0c, 0xcf, 0xc5, 0x2e, 0xad, 0xec, 0x2e, 0x89, 0x6c, - 0x8a, 0x2e, 0x8c, 0xae, 0x6c, 0x4a, 0xb0, 0xd4, 0x21, 0xc3, 0x73, 0x29, - 0x73, 0xa3, 0x93, 0xcb, 0x83, 0x7a, 0x4b, 0x73, 0xa3, 0x9b, 0x9b, 0x12, - 0x8c, 0x01, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, - 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, - 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, - 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, - 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, - 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, - 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, - 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, - 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, - 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, - 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, - 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, - 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, - 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, - 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, - 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, - 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, - 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, - 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, - 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, - 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, - 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, - 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, - 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, - 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, - 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x16, 0x10, 0x0d, 0x97, 0xef, 0x3c, 0x3e, 0xc1, 0x20, 0x93, 0xd8, 0x0c, - 0x88, 0x40, 0x48, 0x36, 0x90, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x44, 0x4c, - 0x26, 0x21, 0x1d, 0x28, 0x35, 0x3d, 0xd4, 0xc4, 0x39, 0x54, 0x33, 0x49, - 0x26, 0xb0, 0x0d, 0x97, 0xef, 0x3c, 0xbe, 0x34, 0x39, 0x11, 0xf1, 0x12, - 0xd1, 0x44, 0x5c, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, - 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x34, 0x65, 0x2d, 0x50, 0xd2, 0x02, 0x05, 0x2d, - 0x40, 0x56, 0x02, 0x74, 0x23, 0x00, 0x63, 0x04, 0x20, 0x08, 0x82, 0xf8, - 0x37, 0x46, 0x00, 0x82, 0x20, 0x08, 0xff, 0xc2, 0x18, 0x01, 0x08, 0x82, - 0x20, 0xfc, 0x01, 0x00, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xa0, 0x60, - 0x06, 0xf4, 0x8c, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd3, - 0xb4, 0x08, 0xd3, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x32, - 0x4d, 0x45, 0x30, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, - 0xd3, 0xa4, 0x10, 0xd3, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, - 0x32, 0x4d, 0xcd, 0x30, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, - 0x21, 0xd3, 0xb4, 0x04, 0xd7, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, - 0x19, 0x32, 0x4d, 0x45, 0x70, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, - 0x92, 0x21, 0xd3, 0xa4, 0x10, 0xd7, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, - 0x20, 0x19, 0x32, 0x4d, 0xcd, 0x70, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, - 0x01, 0x92, 0x21, 0xd3, 0xb4, 0x04, 0xcf, 0x88, 0x81, 0x02, 0x80, 0x20, - 0x18, 0x20, 0x19, 0x32, 0x4d, 0x85, 0xf0, 0x8c, 0x18, 0x28, 0x00, 0x08, - 0x82, 0x01, 0x92, 0x21, 0xd3, 0xa4, 0x10, 0xcf, 0x88, 0x81, 0x02, 0x80, - 0x20, 0x18, 0x20, 0x19, 0x32, 0x4d, 0xcd, 0xf0, 0x8c, 0x18, 0x28, 0x00, - 0x08, 0x82, 0x01, 0x92, 0x21, 0xd3, 0xb4, 0x08, 0xd2, 0x88, 0x81, 0x02, - 0x80, 0x20, 0x18, 0x20, 0x19, 0x32, 0x4d, 0x85, 0x20, 0x8d, 0x18, 0x28, - 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd3, 0xa4, 0x10, 0xd2, 0x88, 0x81, - 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x32, 0x4d, 0xcd, 0x20, 0x8d, 0x18, - 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd7, 0xb4, 0x0c, 0xd3, 0x88, - 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x72, 0x4d, 0x05, 0x31, 0x8d, - 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd7, 0xa4, 0x10, 0xd3, - 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x72, 0x4d, 0xcd, 0x30, - 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd7, 0xb4, 0x10, - 0xd7, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x72, 0x4d, 0xc5, - 0x70, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd7, 0xa4, - 0x10, 0xd7, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x72, 0x4d, - 0xcd, 0x70, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, 0xd7, - 0xb4, 0x10, 0xcf, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, 0x72, - 0x4d, 0x05, 0xf1, 0x8c, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, 0x21, - 0xd7, 0xa4, 0x0c, 0xcf, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, 0x19, - 0x72, 0x4d, 0xcd, 0xf0, 0x8c, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, 0x92, - 0x21, 0xd7, 0xb4, 0x0c, 0xd2, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, 0x20, - 0x19, 0x72, 0x4d, 0x05, 0x21, 0x8d, 0x18, 0x28, 0x00, 0x08, 0x82, 0x01, - 0x92, 0x21, 0xd7, 0xa4, 0x10, 0xd2, 0x88, 0x81, 0x02, 0x80, 0x20, 0x18, - 0x20, 0x19, 0x72, 0x4d, 0xcd, 0x20, 0x8d, 0x18, 0x24, 0x00, 0x08, 0x82, - 0x01, 0xa1, 0x1d, 0xd3, 0x74, 0x3d, 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, - 0x40, 0x68, 0xc7, 0x35, 0x3d, 0x12, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -// ================================================== -// Texture -// ================================================== - -// GLSL -// Vertex -// #version 450 - -// layout(location = 0) in vec2 aPosition; -// layout(location = 1) in vec2 aTexCoord; - -// layout(location = 0) out vec2 vTexCoord; - -// void main() -// { -// gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); -// vTexCoord = aTexCoord; -// } - -// Fragment -// #version 450 - -// layout(set = 0, binding = 0) uniform texture2D tex; -// layout(set = 0, binding = 0) uniform sampler samp; - -// layout(location = 0) in vec2 aTexCoord; - -// layout(location = 0) out vec4 color; - -// void main() -// { -// color = texture(sampler2D(tex, samp), aTexCoord); -// } - -// HLSL -// Vertex -// struct VSInput -// { -// float2 pos : POSITION; -// float2 uv : TEXCOORD; -// }; - -// struct VSOutput -// { -// float4 pos : SV_POSITION; -// float2 uv : TEXCOORD; -// }; - -// VSOutput main(VSInput input) -// { -// VSOutput output; -// output.pos = float4(input.pos, 0.0, 1.0); -// output.uv = input.uv; -// return output; -// } - -// Fragment -// Texture2D tex : register(t0); -// SamplerState samp : register(s0); - -// struct PSInput -// { -// float4 pos : SV_POSITION; -// float2 uv : TEXCOORD; -// }; - -// float4 main(PSInput input) : SV_Target -// { -// return tex.Sample(samp, input.uv); -// } - -static const Uint32 s_TextureVertShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x00000023, - 0x00000000, 0x00020011, 0x00000001, 0x0006000b, - 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, - 0x00000000, 0x0003000e, 0x00000000, 0x00000001, - 0x0009000f, 0x00000000, 0x00000004, 0x6e69616d, - 0x00000000, 0x0000000d, 0x00000012, 0x00000020, - 0x00000021, 0x00030003, 0x00000002, 0x000001c2, - 0x00040005, 0x00000004, 0x6e69616d, 0x00000000, - 0x00060005, 0x0000000b, 0x505f6c67, 0x65567265, - 0x78657472, 0x00000000, 0x00060006, 0x0000000b, - 0x00000000, 0x505f6c67, 0x7469736f, 0x006e6f69, - 0x00070006, 0x0000000b, 0x00000001, 0x505f6c67, - 0x746e696f, 0x657a6953, 0x00000000, 0x00070006, - 0x0000000b, 0x00000002, 0x435f6c67, 0x4470696c, - 0x61747369, 0x0065636e, 0x00070006, 0x0000000b, - 0x00000003, 0x435f6c67, 0x446c6c75, 0x61747369, - 0x0065636e, 0x00030005, 0x0000000d, 0x00000000, - 0x00050005, 0x00000012, 0x736f5061, 0x6f697469, - 0x0000006e, 0x00050005, 0x00000020, 0x78655476, - 0x726f6f43, 0x00000064, 0x00050005, 0x00000021, - 0x78655461, 0x726f6f43, 0x00000064, 0x00030047, - 0x0000000b, 0x00000002, 0x00050048, 0x0000000b, - 0x00000000, 0x0000000b, 0x00000000, 0x00050048, - 0x0000000b, 0x00000001, 0x0000000b, 0x00000001, - 0x00050048, 0x0000000b, 0x00000002, 0x0000000b, - 0x00000003, 0x00050048, 0x0000000b, 0x00000003, - 0x0000000b, 0x00000004, 0x00040047, 0x00000012, - 0x0000001e, 0x00000000, 0x00040047, 0x00000020, - 0x0000001e, 0x00000000, 0x00040047, 0x00000021, - 0x0000001e, 0x00000001, 0x00020013, 0x00000002, - 0x00030021, 0x00000003, 0x00000002, 0x00030016, - 0x00000006, 0x00000020, 0x00040017, 0x00000007, - 0x00000006, 0x00000004, 0x00040015, 0x00000008, - 0x00000020, 0x00000000, 0x0004002b, 0x00000008, - 0x00000009, 0x00000001, 0x0004001c, 0x0000000a, - 0x00000006, 0x00000009, 0x0006001e, 0x0000000b, - 0x00000007, 0x00000006, 0x0000000a, 0x0000000a, - 0x00040020, 0x0000000c, 0x00000003, 0x0000000b, - 0x0004003b, 0x0000000c, 0x0000000d, 0x00000003, - 0x00040015, 0x0000000e, 0x00000020, 0x00000001, - 0x0004002b, 0x0000000e, 0x0000000f, 0x00000000, - 0x00040017, 0x00000010, 0x00000006, 0x00000002, - 0x00040020, 0x00000011, 0x00000001, 0x00000010, - 0x0004003b, 0x00000011, 0x00000012, 0x00000001, - 0x0004002b, 0x00000008, 0x00000013, 0x00000000, - 0x00040020, 0x00000014, 0x00000001, 0x00000006, - 0x0004002b, 0x00000006, 0x0000001a, 0x00000000, - 0x0004002b, 0x00000006, 0x0000001b, 0x3f800000, - 0x00040020, 0x0000001d, 0x00000003, 0x00000007, - 0x00040020, 0x0000001f, 0x00000003, 0x00000010, - 0x0004003b, 0x0000001f, 0x00000020, 0x00000003, - 0x0004003b, 0x00000011, 0x00000021, 0x00000001, - 0x00050036, 0x00000002, 0x00000004, 0x00000000, - 0x00000003, 0x000200f8, 0x00000005, 0x00050041, - 0x00000014, 0x00000015, 0x00000012, 0x00000013, - 0x0004003d, 0x00000006, 0x00000016, 0x00000015, - 0x00050041, 0x00000014, 0x00000017, 0x00000012, - 0x00000009, 0x0004003d, 0x00000006, 0x00000018, - 0x00000017, 0x0004007f, 0x00000006, 0x00000019, - 0x00000018, 0x00070050, 0x00000007, 0x0000001c, - 0x00000016, 0x00000019, 0x0000001a, 0x0000001b, - 0x00050041, 0x0000001d, 0x0000001e, 0x0000000d, - 0x0000000f, 0x0003003e, 0x0000001e, 0x0000001c, - 0x0004003d, 0x00000010, 0x00000022, 0x00000021, - 0x0003003e, 0x00000020, 0x00000022, 0x000100fd, - 0x00010038 -}; - -static const Uint32 s_TextureFragShaderSpv[] = { - 0x07230203, 0x00010600, 0x0008000b, 0x00000019, - 0x00000000, 0x00020011, 0x00000001, 0x0006000b, - 0x00000001, 0x4c534c47, 0x6474732e, 0x3035342e, - 0x00000000, 0x0003000e, 0x00000000, 0x00000001, - 0x0009000f, 0x00000004, 0x00000004, 0x6e69616d, - 0x00000000, 0x00000009, 0x0000000c, 0x00000010, - 0x00000016, 0x00030010, 0x00000004, 0x00000007, - 0x00030003, 0x00000002, 0x000001c2, 0x00040005, - 0x00000004, 0x6e69616d, 0x00000000, 0x00040005, - 0x00000009, 0x6f6c6f63, 0x00000072, 0x00030005, - 0x0000000c, 0x00786574, 0x00040005, 0x00000010, - 0x706d6173, 0x00000000, 0x00050005, 0x00000016, - 0x78655461, 0x726f6f43, 0x00000064, 0x00040047, - 0x00000009, 0x0000001e, 0x00000000, 0x00040047, - 0x0000000c, 0x00000021, 0x00000000, 0x00040047, - 0x0000000c, 0x00000022, 0x00000000, 0x00040047, - 0x00000010, 0x00000021, 0x00000000, 0x00040047, - 0x00000010, 0x00000022, 0x00000000, 0x00040047, - 0x00000016, 0x0000001e, 0x00000000, 0x00020013, - 0x00000002, 0x00030021, 0x00000003, 0x00000002, - 0x00030016, 0x00000006, 0x00000020, 0x00040017, - 0x00000007, 0x00000006, 0x00000004, 0x00040020, - 0x00000008, 0x00000003, 0x00000007, 0x0004003b, - 0x00000008, 0x00000009, 0x00000003, 0x00090019, - 0x0000000a, 0x00000006, 0x00000001, 0x00000000, - 0x00000000, 0x00000000, 0x00000001, 0x00000000, - 0x00040020, 0x0000000b, 0x00000000, 0x0000000a, - 0x0004003b, 0x0000000b, 0x0000000c, 0x00000000, - 0x0002001a, 0x0000000e, 0x00040020, 0x0000000f, - 0x00000000, 0x0000000e, 0x0004003b, 0x0000000f, - 0x00000010, 0x00000000, 0x0003001b, 0x00000012, - 0x0000000a, 0x00040017, 0x00000014, 0x00000006, - 0x00000002, 0x00040020, 0x00000015, 0x00000001, - 0x00000014, 0x0004003b, 0x00000015, 0x00000016, - 0x00000001, 0x00050036, 0x00000002, 0x00000004, - 0x00000000, 0x00000003, 0x000200f8, 0x00000005, - 0x0004003d, 0x0000000a, 0x0000000d, 0x0000000c, - 0x0004003d, 0x0000000e, 0x00000011, 0x00000010, - 0x00050056, 0x00000012, 0x00000013, 0x0000000d, - 0x00000011, 0x0004003d, 0x00000014, 0x00000017, - 0x00000016, 0x00050057, 0x00000007, 0x00000018, - 0x00000013, 0x00000017, 0x0003003e, 0x00000009, - 0x00000018, 0x000100fd, 0x00010038 -}; - -static const Uint8 s_TextureVertShaderDxil[] = { - 0x44, 0x58, 0x42, 0x43, 0xdb, 0x6c, 0x1e, 0xc3, 0xee, 0xcf, 0xaa, 0xf4, - 0xd8, 0x2f, 0xf2, 0x94, 0x92, 0xb5, 0x75, 0xcb, 0x01, 0x00, 0x00, 0x00, - 0x1c, 0x0c, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, - 0xf0, 0x01, 0x00, 0x00, 0xd4, 0x06, 0x00, 0x00, 0xf0, 0x06, 0x00, 0x00, - 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x5c, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x54, 0x45, 0x58, - 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x00, 0x00, 0x4f, 0x53, 0x47, 0x31, - 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x0c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, - 0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x56, 0x30, 0xd0, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4f, 0x53, 0x49, 0x54, 0x49, 0x4f, - 0x4e, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x54, - 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x6d, 0x61, 0x69, 0x6e, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x42, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x42, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, - 0x03, 0x04, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x42, 0x00, 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xdc, 0x04, 0x00, 0x00, - 0x60, 0x00, 0x01, 0x00, 0x37, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xc4, 0x04, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x10, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x11, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x21, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, - 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, - 0x49, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, - 0x20, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x08, 0x09, 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, - 0x04, 0x13, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, - 0x0b, 0x84, 0x84, 0x4c, 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x19, - 0x80, 0x39, 0x02, 0x30, 0x98, 0x23, 0x40, 0x8a, 0x31, 0x44, 0x54, 0x44, - 0x56, 0x0c, 0x20, 0xa2, 0x1a, 0xc2, 0x81, 0x80, 0x44, 0x20, 0x00, 0x00, - 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, - 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, - 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, - 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, - 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, - 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, - 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, - 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, - 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, 0x00, 0x08, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, - 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, - 0x0c, 0x00, 0x00, 0x00, 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, - 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0xa2, 0x12, 0x18, 0x01, 0x28, - 0x86, 0x32, 0x28, 0x8f, 0xb2, 0x28, 0x04, 0xaa, 0x92, 0x18, 0x01, 0x28, - 0x82, 0x32, 0x28, 0x04, 0xda, 0xb1, 0x10, 0xc3, 0x08, 0x04, 0x00, 0x80, - 0xc0, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, - 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, - 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb1, 0xa9, 0x81, 0x01, 0x41, 0xa1, 0xc9, - 0x21, 0x8b, 0x09, 0x2b, 0xcb, 0x09, 0x83, 0x49, 0xd9, 0x10, 0x04, 0x13, - 0x04, 0x62, 0x98, 0x20, 0x10, 0xc4, 0x06, 0x61, 0x20, 0x36, 0x08, 0x04, - 0x41, 0xc1, 0x6e, 0x6e, 0x82, 0x40, 0x14, 0x1b, 0x86, 0x03, 0x21, 0x26, - 0x08, 0x02, 0xb0, 0x01, 0xd8, 0x30, 0x10, 0xcb, 0xb2, 0x21, 0x60, 0x36, - 0x0c, 0x83, 0xd2, 0x4c, 0x10, 0x96, 0x67, 0x43, 0xf0, 0x90, 0x68, 0x0b, - 0x4b, 0x73, 0x23, 0x02, 0xf5, 0x34, 0x95, 0x44, 0x95, 0xf4, 0xe4, 0x34, - 0x41, 0x28, 0x94, 0x09, 0x42, 0xb1, 0x6c, 0x08, 0x88, 0x09, 0x42, 0xc1, - 0x4c, 0x10, 0x08, 0x63, 0x83, 0x70, 0x5d, 0x1b, 0x16, 0x42, 0x9a, 0xa8, - 0x8a, 0x1a, 0x2c, 0x82, 0xc2, 0x88, 0x50, 0x15, 0x61, 0x0d, 0x3d, 0x3d, - 0x49, 0x11, 0x6d, 0x58, 0x06, 0x6d, 0xa2, 0x2a, 0x6a, 0xb0, 0x06, 0x0a, - 0xdb, 0x20, 0x64, 0x1b, 0x97, 0x29, 0xab, 0x2f, 0xa8, 0xb7, 0xb9, 0x34, - 0xba, 0xb4, 0x37, 0xb7, 0x09, 0x42, 0xd1, 0x4c, 0x10, 0x0a, 0x67, 0x82, - 0x40, 0x1c, 0x1b, 0x84, 0x0b, 0x0c, 0x36, 0x2c, 0x44, 0x37, 0x79, 0xd5, - 0x37, 0x7c, 0x04, 0x15, 0x06, 0x1b, 0x96, 0x41, 0x9b, 0xa8, 0xca, 0x1a, - 0xac, 0x81, 0xc2, 0x36, 0x08, 0x62, 0x30, 0x06, 0x1b, 0x06, 0x8e, 0x0c, - 0x80, 0x0d, 0x85, 0x12, 0x95, 0x01, 0x00, 0xb0, 0x48, 0x73, 0x9b, 0xa3, - 0x9b, 0x9b, 0x20, 0x10, 0x08, 0x8d, 0xb9, 0xb4, 0xb3, 0x2f, 0x36, 0xb2, - 0x09, 0x02, 0x91, 0xd0, 0x98, 0x4b, 0x3b, 0xfb, 0x9a, 0xa3, 0xdb, 0x60, - 0x9c, 0x01, 0x1a, 0xa4, 0x81, 0x1a, 0xac, 0x01, 0x52, 0x85, 0x8d, 0xcd, - 0xae, 0xcd, 0x25, 0x8d, 0xac, 0xcc, 0x8d, 0x6e, 0x4a, 0x10, 0x54, 0x21, - 0xc3, 0x73, 0xb1, 0x2b, 0x93, 0x9b, 0x4b, 0x7b, 0x73, 0x9b, 0x12, 0x10, - 0x4d, 0xc8, 0xf0, 0x5c, 0xec, 0xc2, 0xd8, 0xec, 0xca, 0xe4, 0xa6, 0x04, - 0x45, 0x1d, 0x32, 0x3c, 0x97, 0x39, 0xb4, 0x30, 0xb2, 0x32, 0xb9, 0xa6, - 0x37, 0xb2, 0x32, 0xb6, 0x29, 0x01, 0x52, 0x89, 0x0c, 0xcf, 0x85, 0x2e, - 0x0f, 0xae, 0x2c, 0xc8, 0xcd, 0xed, 0x8d, 0x2e, 0x8c, 0x2e, 0xed, 0xcd, - 0x6d, 0x6e, 0x4a, 0xd0, 0xd4, 0x21, 0xc3, 0x73, 0xb1, 0x4b, 0x2b, 0xbb, - 0x4b, 0x22, 0x9b, 0xa2, 0x0b, 0xa3, 0x2b, 0x9b, 0x12, 0x3c, 0x75, 0xc8, - 0xf0, 0x5c, 0xca, 0xdc, 0xe8, 0xe4, 0xf2, 0xa0, 0xde, 0xd2, 0xdc, 0xe8, - 0xe6, 0xa6, 0x04, 0x65, 0xd0, 0x85, 0x0c, 0xcf, 0x65, 0xec, 0xad, 0xce, - 0x8d, 0xae, 0x4c, 0x6e, 0x6e, 0x4a, 0xb0, 0x06, 0x00, 0x00, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, - 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, - 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, - 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, - 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, - 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, - 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, - 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, - 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, - 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, - 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, - 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, - 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, - 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, - 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, - 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, - 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, - 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, - 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, - 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, - 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, - 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, - 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, 0x21, 0x07, 0x7c, 0x70, - 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, 0x08, 0x07, 0x79, 0x60, - 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, 0x98, 0x81, 0x3c, 0xe4, - 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, 0xf0, 0x00, 0x00, 0x00, - 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x16, 0x30, 0x0d, 0x97, - 0xef, 0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, 0xd4, 0xe4, 0x17, 0xb7, - 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, - 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, - 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x15, 0xb4, 0x1e, - 0xd4, 0xa9, 0x01, 0x22, 0xa4, 0x39, 0x8a, 0x77, 0x38, 0x83, 0x01, 0xd3, - 0x44, 0x58, 0x49, 0x4c, 0x24, 0x05, 0x00, 0x00, 0x60, 0x00, 0x01, 0x00, - 0x49, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x0c, 0x05, 0x00, 0x00, 0x42, 0x43, 0xc0, 0xde, - 0x21, 0x0c, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, - 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, - 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x10, 0x45, 0x02, - 0x42, 0x92, 0x0b, 0x42, 0x84, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, - 0x0a, 0x32, 0x42, 0x88, 0x48, 0x90, 0x14, 0x20, 0x43, 0x46, 0x88, 0xa5, - 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, 0x11, 0x22, 0xc4, 0x50, - 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, 0x04, 0x21, 0x46, 0x06, - 0x51, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x8c, 0xe0, 0xff, - 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, 0x84, 0xf0, 0xff, 0xff, - 0xff, 0xff, 0x03, 0x20, 0x01, 0x00, 0x00, 0x00, 0x49, 0x18, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x00, 0x00, 0x00, - 0x89, 0x20, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x32, 0x22, 0x08, 0x09, - 0x20, 0x64, 0x85, 0x04, 0x13, 0x22, 0xa4, 0x84, 0x04, 0x13, 0x22, 0xe3, - 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x88, 0x8c, 0x0b, 0x84, 0x84, 0x4c, - 0x10, 0x30, 0x23, 0x00, 0x25, 0x00, 0x8a, 0x19, 0x80, 0x39, 0x02, 0x30, - 0x98, 0x23, 0x40, 0x8a, 0x31, 0x44, 0x54, 0x44, 0x56, 0x0c, 0x20, 0xa2, - 0x1a, 0xc2, 0x81, 0x80, 0x44, 0x20, 0x00, 0x00, 0x13, 0x14, 0x72, 0xc0, - 0x87, 0x74, 0x60, 0x87, 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, - 0x87, 0x0d, 0xaf, 0x50, 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, - 0x00, 0x0f, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x90, 0x0e, 0x71, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, - 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, - 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, - 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, - 0xd0, 0x06, 0xe6, 0x10, 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, - 0x60, 0x0e, 0x73, 0x20, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, - 0x60, 0x07, 0x74, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, - 0xa0, 0x07, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, - 0x40, 0x07, 0x43, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x86, 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x02, 0x01, 0x0c, 0x00, 0x00, 0x00, - 0x32, 0x1e, 0x98, 0x10, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, - 0xc6, 0x04, 0x43, 0xa2, 0x12, 0x18, 0x01, 0x28, 0x89, 0x62, 0x28, 0x83, - 0xf2, 0xa0, 0x2a, 0x89, 0x11, 0x80, 0x22, 0x28, 0x83, 0x42, 0xa0, 0x1d, - 0x0b, 0x31, 0x8c, 0x40, 0x00, 0x00, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, - 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, - 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, - 0xa1, 0xb1, 0xa9, 0x81, 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, - 0xcb, 0x09, 0x83, 0x49, 0xd9, 0x10, 0x04, 0x13, 0x04, 0x62, 0x98, 0x20, - 0x10, 0xc4, 0x06, 0x61, 0x20, 0x26, 0x08, 0x44, 0xb1, 0x41, 0x18, 0x0c, - 0x0a, 0x76, 0x73, 0x13, 0x04, 0xc2, 0xd8, 0x30, 0x20, 0x09, 0x31, 0x41, - 0x58, 0x9c, 0x0d, 0xc1, 0x32, 0x41, 0x10, 0x00, 0x12, 0x6d, 0x61, 0x69, - 0x6e, 0x44, 0xa0, 0x9e, 0xa6, 0x92, 0xa8, 0x92, 0x9e, 0x9c, 0x26, 0x08, - 0x45, 0x32, 0x41, 0x28, 0x94, 0x0d, 0x01, 0x31, 0x41, 0x28, 0x96, 0x09, - 0x02, 0x71, 0x6c, 0x10, 0x28, 0x6a, 0xc3, 0x42, 0x3c, 0x50, 0x24, 0x45, - 0xc3, 0x44, 0x44, 0x15, 0x11, 0xaa, 0x22, 0xac, 0xa1, 0xa7, 0x27, 0x29, - 0xa2, 0x0d, 0xcb, 0x70, 0x41, 0x91, 0x14, 0x0d, 0xd3, 0x10, 0x55, 0x1b, - 0x04, 0x0b, 0xe3, 0x32, 0x65, 0xf5, 0x05, 0xf5, 0x36, 0x97, 0x46, 0x97, - 0xf6, 0xe6, 0x36, 0x41, 0x28, 0x98, 0x09, 0x42, 0xd1, 0x4c, 0x10, 0x08, - 0x64, 0x83, 0x40, 0x75, 0x1b, 0x16, 0x42, 0x83, 0x36, 0x89, 0x1b, 0x38, - 0x22, 0xf2, 0x36, 0x2c, 0xc3, 0x05, 0x45, 0xd2, 0x34, 0x4c, 0x43, 0x54, - 0x6d, 0x10, 0x3e, 0x30, 0xd8, 0x30, 0x64, 0x61, 0x00, 0x6c, 0x28, 0x1a, - 0x47, 0x0c, 0x00, 0xa0, 0x0a, 0x1b, 0x9b, 0x5d, 0x9b, 0x4b, 0x1a, 0x59, - 0x99, 0x1b, 0xdd, 0x94, 0x20, 0xa8, 0x42, 0x86, 0xe7, 0x62, 0x57, 0x26, - 0x37, 0x97, 0xf6, 0xe6, 0x36, 0x25, 0x20, 0x9a, 0x90, 0xe1, 0xb9, 0xd8, - 0x85, 0xb1, 0xd9, 0x95, 0xc9, 0x4d, 0x09, 0x8c, 0x3a, 0x64, 0x78, 0x2e, - 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x53, - 0x82, 0xa4, 0x0e, 0x19, 0x9e, 0x8b, 0x5d, 0x5a, 0xd9, 0x5d, 0x12, 0xd9, - 0x14, 0x5d, 0x18, 0x5d, 0xd9, 0x94, 0x60, 0xa9, 0x43, 0x86, 0xe7, 0x52, - 0xe6, 0x46, 0x27, 0x97, 0x07, 0xf5, 0x96, 0xe6, 0x46, 0x37, 0x37, 0x25, - 0x10, 0x03, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x33, 0x08, 0x80, 0x1c, 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, - 0x43, 0x38, 0x84, 0xc3, 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, - 0x98, 0x71, 0x0c, 0xe6, 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, - 0x33, 0x0c, 0x42, 0x1e, 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, - 0x05, 0x3d, 0x88, 0x43, 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, - 0x43, 0x3d, 0x8c, 0x03, 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, - 0x08, 0x07, 0x79, 0x48, 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, - 0x78, 0x87, 0x70, 0x20, 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, - 0xe1, 0x30, 0x0f, 0x6e, 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, - 0x33, 0x10, 0xc4, 0x1d, 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, - 0x1e, 0x66, 0x30, 0x89, 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, - 0x03, 0x3c, 0xbc, 0x83, 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, - 0x60, 0x07, 0x7b, 0x68, 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, - 0x80, 0x87, 0x70, 0x90, 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, - 0xf8, 0x05, 0x76, 0x78, 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, - 0x18, 0x87, 0x72, 0x98, 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, - 0xee, 0xe0, 0x0e, 0xf5, 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, - 0x1c, 0xe4, 0xa1, 0x1c, 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, - 0x1c, 0xca, 0x21, 0x1c, 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, - 0x43, 0x39, 0xc8, 0x43, 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, - 0xc3, 0x38, 0x94, 0x43, 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, - 0x83, 0x3c, 0xfc, 0x82, 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x8c, 0xc8, - 0x21, 0x07, 0x7c, 0x70, 0x03, 0x72, 0x10, 0x87, 0x73, 0x70, 0x03, 0x7b, - 0x08, 0x07, 0x79, 0x60, 0x87, 0x70, 0xc8, 0x87, 0x77, 0xa8, 0x07, 0x7a, - 0x98, 0x81, 0x3c, 0xe4, 0x80, 0x0f, 0x6e, 0x40, 0x0f, 0xe5, 0xd0, 0x0e, - 0xf0, 0x00, 0x00, 0x00, 0x71, 0x20, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x16, 0x30, 0x0d, 0x97, 0xef, 0x3c, 0xfe, 0xe2, 0x00, 0x83, 0xd8, 0x3c, - 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, - 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x00, - 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x54, 0x25, 0x40, 0x34, 0x03, 0x50, 0x0a, 0x85, - 0x40, 0x33, 0x46, 0x00, 0x82, 0x20, 0x88, 0x7f, 0x23, 0x00, 0x00, 0x00, - 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x60, 0x50, 0x83, 0x14, 0x2d, 0xc5, - 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x18, 0x15, 0x31, 0x49, 0x87, 0x31, - 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x86, 0x55, 0x4c, 0x53, 0x73, 0x8c, - 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0x71, 0x19, 0x14, 0x95, 0x20, 0x23, - 0x06, 0x09, 0x00, 0x82, 0x60, 0x80, 0x5c, 0x48, 0x55, 0x3d, 0xc2, 0x88, - 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0x17, 0x52, 0x55, 0x4a, 0x30, 0x62, - 0x90, 0x00, 0x20, 0x08, 0x06, 0xc8, 0x85, 0x54, 0x95, 0x53, 0x8c, 0x18, - 0x24, 0x00, 0x08, 0x82, 0x01, 0x72, 0x21, 0x55, 0xd5, 0x18, 0x23, 0x06, - 0x09, 0x00, 0x82, 0x60, 0x80, 0x5c, 0x88, 0x55, 0x3d, 0xc4, 0x88, 0x41, - 0x02, 0x80, 0x20, 0x18, 0x20, 0x17, 0x62, 0x55, 0xca, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - -static const Uint8 s_TextureFragShaderDxil[] = { - 0x44, 0x58, 0x42, 0x43, 0xb9, 0x47, 0xea, 0x75, 0x37, 0x83, 0x8c, 0xf3, - 0xbe, 0xa0, 0x73, 0xc4, 0x09, 0x85, 0x21, 0xae, 0x01, 0x00, 0x00, 0x00, - 0xe4, 0x0e, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, - 0xd8, 0x01, 0x00, 0x00, 0x34, 0x08, 0x00, 0x00, 0x50, 0x08, 0x00, 0x00, - 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, 0x60, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x56, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x00, - 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x00, 0x00, 0x00, 0x00, - 0x4f, 0x53, 0x47, 0x31, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x00, 0x00, 0x00, - 0x50, 0x53, 0x56, 0x30, 0xe0, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, - 0x44, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x03, 0x03, 0x04, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x42, 0x00, - 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x44, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0x54, 0x06, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x95, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x06, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, - 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff, - 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, - 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, - 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x68, 0x23, 0x00, 0x25, 0x00, 0x14, 0x66, - 0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x20, 0x84, 0x14, - 0x42, 0xa6, 0x18, 0x80, 0x10, 0x52, 0x06, 0xa1, 0x9b, 0x86, 0xcb, 0x9f, - 0xb0, 0x87, 0x90, 0xfc, 0x95, 0x90, 0x56, 0x62, 0xf2, 0x8b, 0xdb, 0x46, - 0xc5, 0x18, 0x63, 0x10, 0x2a, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, - 0xf9, 0x21, 0xd0, 0x0c, 0x0b, 0x81, 0x82, 0x55, 0x18, 0x45, 0x18, 0x1b, - 0x63, 0x0c, 0x42, 0xc8, 0xa0, 0x36, 0x47, 0x10, 0x14, 0x83, 0x91, 0x42, - 0xc8, 0x23, 0x38, 0x10, 0x30, 0x8c, 0x40, 0x0c, 0x33, 0xb5, 0xc1, 0x38, - 0xb0, 0x43, 0x38, 0xcc, 0xc3, 0x3c, 0xb8, 0x01, 0x2d, 0x94, 0x03, 0x3e, - 0xd0, 0x43, 0x3d, 0xc8, 0x43, 0x39, 0xc8, 0x01, 0x29, 0xf0, 0x81, 0x3d, - 0x94, 0xc3, 0x38, 0xd0, 0xc3, 0x3b, 0xc8, 0x03, 0x1f, 0x98, 0x03, 0x3b, - 0xbc, 0x43, 0x38, 0xd0, 0x03, 0x1b, 0x80, 0x01, 0x1d, 0xf8, 0x01, 0x18, - 0xf8, 0x81, 0x1e, 0xe8, 0x41, 0x3b, 0xa4, 0x03, 0x3c, 0xcc, 0xc3, 0x2f, - 0xd0, 0x43, 0x3e, 0xc0, 0x43, 0x39, 0xa0, 0x80, 0xcc, 0x24, 0x06, 0xe3, - 0xc0, 0x0e, 0xe1, 0x30, 0x0f, 0xf3, 0xe0, 0x06, 0xb4, 0x50, 0x0e, 0xf8, - 0x40, 0x0f, 0xf5, 0x20, 0x0f, 0xe5, 0x20, 0x07, 0xa4, 0xc0, 0x07, 0xf6, - 0x50, 0x0e, 0xe3, 0x40, 0x0f, 0xef, 0x20, 0x0f, 0x7c, 0x60, 0x0e, 0xec, - 0xf0, 0x0e, 0xe1, 0x40, 0x0f, 0x6c, 0x00, 0x06, 0x74, 0xe0, 0x07, 0x60, - 0xe0, 0x07, 0x48, 0x98, 0x94, 0xea, 0x4d, 0xd2, 0x14, 0x51, 0xc2, 0xe4, - 0xb3, 0x00, 0xf3, 0x2c, 0x44, 0xc4, 0x4e, 0xc0, 0x44, 0xa0, 0x80, 0xd0, - 0x4d, 0x04, 0x02, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, - 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, - 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, - 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, - 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, - 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, - 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, - 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, - 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, - 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, - 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, - 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0xf2, 0x34, 0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x30, 0xe4, 0x81, 0x80, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x0b, 0x04, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, - 0xc6, 0x04, 0x43, 0x22, 0x25, 0x30, 0x02, 0x50, 0x0c, 0x45, 0x50, 0x12, - 0x65, 0x50, 0x1e, 0xc5, 0x51, 0x08, 0x54, 0x4a, 0xa2, 0x0c, 0x0a, 0x61, - 0x04, 0xa0, 0x08, 0x0a, 0x84, 0xec, 0x0c, 0x00, 0xe1, 0x19, 0x00, 0xca, - 0x63, 0x21, 0x06, 0x01, 0x00, 0x00, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, - 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, - 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, - 0xa1, 0xb1, 0xa9, 0x81, 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, - 0xcb, 0x09, 0x83, 0x49, 0xd9, 0x10, 0x04, 0x13, 0x04, 0xa2, 0x98, 0x20, - 0x10, 0xc6, 0x06, 0x61, 0x20, 0x36, 0x08, 0x04, 0x41, 0x01, 0x6e, 0x6e, - 0x82, 0x40, 0x1c, 0x1b, 0x86, 0x03, 0x21, 0x26, 0x08, 0x16, 0xc5, 0x81, - 0xae, 0x0c, 0x6f, 0x82, 0x40, 0x20, 0x13, 0x04, 0x22, 0xd9, 0x20, 0x10, - 0xcd, 0x86, 0x84, 0x50, 0x16, 0x82, 0x18, 0x18, 0xc2, 0xd9, 0x10, 0x3c, - 0x13, 0x04, 0xac, 0x22, 0x31, 0x17, 0xd6, 0x06, 0xb7, 0x01, 0x21, 0x22, - 0x89, 0x20, 0x06, 0x02, 0xd8, 0x10, 0x4c, 0x1b, 0x08, 0x08, 0x00, 0xa8, - 0x09, 0x82, 0x00, 0x6c, 0x00, 0x36, 0x0c, 0xc4, 0x75, 0x6d, 0x08, 0xb0, - 0x0d, 0xc3, 0x60, 0x65, 0x13, 0x84, 0xcc, 0xda, 0x10, 0x6c, 0x24, 0xda, - 0xc2, 0xd2, 0xdc, 0xb8, 0x4c, 0x59, 0x7d, 0x41, 0xbd, 0xcd, 0xa5, 0xd1, - 0xa5, 0xbd, 0xb9, 0x4d, 0x10, 0x0a, 0x67, 0x82, 0x50, 0x3c, 0x1b, 0x02, - 0x62, 0x82, 0x50, 0x40, 0x13, 0x84, 0x22, 0xda, 0xb0, 0x10, 0xde, 0x07, - 0x06, 0x61, 0x20, 0x06, 0x83, 0x18, 0x10, 0x63, 0x00, 0x10, 0xa1, 0x2a, - 0xc2, 0x1a, 0x7a, 0x7a, 0x92, 0x22, 0x9a, 0x20, 0x14, 0xd2, 0x04, 0x81, - 0x50, 0x36, 0x08, 0x67, 0x70, 0x06, 0x1b, 0x96, 0xa1, 0x0c, 0xbe, 0x31, - 0x08, 0x03, 0x33, 0x18, 0xcc, 0x60, 0x18, 0x03, 0x34, 0xd8, 0x20, 0x90, - 0x41, 0x1a, 0x30, 0x99, 0xb2, 0xfa, 0xa2, 0x0a, 0x93, 0x3b, 0x2b, 0xa3, - 0x9b, 0x20, 0x14, 0xd3, 0x04, 0x81, 0x58, 0x36, 0x08, 0x67, 0xd0, 0x06, - 0x1b, 0x16, 0x62, 0x0d, 0x3e, 0x36, 0x08, 0x83, 0x31, 0x18, 0xc4, 0x80, - 0x18, 0x03, 0x37, 0xd8, 0x10, 0xbc, 0xc1, 0x86, 0x41, 0x0d, 0xe0, 0x00, - 0xd8, 0x50, 0x58, 0x5d, 0x1c, 0x54, 0x00, 0x8b, 0x34, 0xb7, 0x39, 0xba, - 0xb9, 0x09, 0x02, 0xc1, 0xd0, 0x98, 0x4b, 0x3b, 0xfb, 0x62, 0x23, 0xa3, - 0x31, 0x97, 0x76, 0xf6, 0x35, 0x47, 0x37, 0x41, 0x20, 0x1a, 0x22, 0x74, - 0x65, 0x78, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x1b, 0x90, 0x39, 0xa0, 0x83, - 0x3a, 0x60, 0xec, 0xe0, 0x0e, 0xf0, 0x60, 0xa8, 0xc2, 0xc6, 0x66, 0xd7, - 0xe6, 0x92, 0x46, 0x56, 0xe6, 0x46, 0x37, 0x25, 0x08, 0xaa, 0x90, 0xe1, - 0xb9, 0xd8, 0x95, 0xc9, 0xcd, 0xa5, 0xbd, 0xb9, 0x4d, 0x09, 0x88, 0x26, - 0x64, 0x78, 0x2e, 0x76, 0x61, 0x6c, 0x76, 0x65, 0x72, 0x53, 0x82, 0xa2, - 0x0e, 0x19, 0x9e, 0xcb, 0x1c, 0x5a, 0x18, 0x59, 0x99, 0x5c, 0xd3, 0x1b, - 0x59, 0x19, 0xdb, 0x94, 0x00, 0x29, 0x43, 0x86, 0xe7, 0x22, 0x57, 0x36, - 0xf7, 0x56, 0x27, 0x37, 0x56, 0x36, 0x37, 0x25, 0xa0, 0x2a, 0x91, 0xe1, - 0xb9, 0xd0, 0xe5, 0xc1, 0x95, 0x05, 0xb9, 0xb9, 0xbd, 0xd1, 0x85, 0xd1, - 0xa5, 0xbd, 0xb9, 0xcd, 0x4d, 0x09, 0xb2, 0x3a, 0x64, 0x78, 0x2e, 0x76, - 0x69, 0x65, 0x77, 0x49, 0x64, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x82, - 0xad, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, 0x1e, 0xd4, 0x5b, - 0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0x20, 0x0e, 0xba, 0x90, 0xe1, 0xb9, 0x8c, - 0xbd, 0xd5, 0xb9, 0xd1, 0x95, 0xc9, 0xcd, 0x4d, 0x09, 0xf0, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, - 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, - 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, - 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, - 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, - 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, - 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, - 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, - 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, - 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, - 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, - 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, - 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, - 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, - 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, - 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, - 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, - 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, - 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, - 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, - 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, - 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, - 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, - 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, - 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, - 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, - 0x71, 0x20, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x46, 0x20, 0x0d, 0x97, - 0xef, 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, 0x33, 0x2c, 0x84, - 0x05, 0x4c, 0xc3, 0xe5, 0x3b, 0x8f, 0xbf, 0x38, 0xc0, 0x20, 0x36, 0x0f, - 0x35, 0xf9, 0xc5, 0x6d, 0xdb, 0x00, 0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x12, - 0xc0, 0x3c, 0x0b, 0xe1, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, - 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, - 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7a, 0xec, 0xd5, 0xe9, 0x4e, 0x1e, 0x68, 0xfc, 0xf3, 0x76, 0xff, 0x47, - 0x16, 0xeb, 0xad, 0xd5, 0x44, 0x58, 0x49, 0x4c, 0x8c, 0x06, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x00, 0x44, 0x58, 0x49, 0x4c, - 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x74, 0x06, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00, - 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, - 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, - 0x80, 0x14, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xa4, 0x10, 0x32, 0x14, - 0x38, 0x08, 0x18, 0x4b, 0x0a, 0x32, 0x52, 0x88, 0x48, 0x90, 0x14, 0x20, - 0x43, 0x46, 0x88, 0xa5, 0x00, 0x19, 0x32, 0x42, 0xe4, 0x48, 0x0e, 0x90, - 0x91, 0x22, 0xc4, 0x50, 0x41, 0x51, 0x81, 0x8c, 0xe1, 0x83, 0xe5, 0x8a, - 0x04, 0x29, 0x46, 0x06, 0x51, 0x18, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x1b, 0x8c, 0xe0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x40, 0x02, 0xa8, 0x0d, - 0x84, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x03, 0x20, 0x6d, 0x30, 0x86, 0xff, - 0xff, 0xff, 0xff, 0x1f, 0x00, 0x09, 0xa8, 0x00, 0x49, 0x18, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x13, 0x82, 0x60, 0x42, 0x20, 0x4c, 0x08, 0x06, - 0x00, 0x00, 0x00, 0x00, 0x89, 0x20, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, - 0x32, 0x22, 0x48, 0x09, 0x20, 0x64, 0x85, 0x04, 0x93, 0x22, 0xa4, 0x84, - 0x04, 0x93, 0x22, 0xe3, 0x84, 0xa1, 0x90, 0x14, 0x12, 0x4c, 0x8a, 0x8c, - 0x0b, 0x84, 0xa4, 0x4c, 0x10, 0x68, 0x23, 0x00, 0x25, 0x00, 0x14, 0x66, - 0x00, 0xe6, 0x08, 0xc0, 0x60, 0x8e, 0x00, 0x29, 0xc6, 0x20, 0x84, 0x14, - 0x42, 0xa6, 0x18, 0x80, 0x10, 0x52, 0x06, 0xa1, 0x9b, 0x86, 0xcb, 0x9f, - 0xb0, 0x87, 0x90, 0xfc, 0x95, 0x90, 0x56, 0x62, 0xf2, 0x8b, 0xdb, 0x46, - 0xc5, 0x18, 0x63, 0x10, 0x2a, 0xf7, 0x0c, 0x97, 0x3f, 0x61, 0x0f, 0x21, - 0xf9, 0x21, 0xd0, 0x0c, 0x0b, 0x81, 0x82, 0x55, 0x18, 0x45, 0x18, 0x1b, - 0x63, 0x0c, 0x42, 0xc8, 0xa0, 0x36, 0x47, 0x10, 0x14, 0x83, 0x91, 0x42, - 0xc8, 0x23, 0x38, 0x10, 0x30, 0x8c, 0x40, 0x0c, 0x33, 0xb5, 0xc1, 0x38, - 0xb0, 0x43, 0x38, 0xcc, 0xc3, 0x3c, 0xb8, 0x01, 0x2d, 0x94, 0x03, 0x3e, - 0xd0, 0x43, 0x3d, 0xc8, 0x43, 0x39, 0xc8, 0x01, 0x29, 0xf0, 0x81, 0x3d, - 0x94, 0xc3, 0x38, 0xd0, 0xc3, 0x3b, 0xc8, 0x03, 0x1f, 0x98, 0x03, 0x3b, - 0xbc, 0x43, 0x38, 0xd0, 0x03, 0x1b, 0x80, 0x01, 0x1d, 0xf8, 0x01, 0x18, - 0xf8, 0x81, 0x1e, 0xe8, 0x41, 0x3b, 0xa4, 0x03, 0x3c, 0xcc, 0xc3, 0x2f, - 0xd0, 0x43, 0x3e, 0xc0, 0x43, 0x39, 0xa0, 0x80, 0xcc, 0x24, 0x06, 0xe3, - 0xc0, 0x0e, 0xe1, 0x30, 0x0f, 0xf3, 0xe0, 0x06, 0xb4, 0x50, 0x0e, 0xf8, - 0x40, 0x0f, 0xf5, 0x20, 0x0f, 0xe5, 0x20, 0x07, 0xa4, 0xc0, 0x07, 0xf6, - 0x50, 0x0e, 0xe3, 0x40, 0x0f, 0xef, 0x20, 0x0f, 0x7c, 0x60, 0x0e, 0xec, - 0xf0, 0x0e, 0xe1, 0x40, 0x0f, 0x6c, 0x00, 0x06, 0x74, 0xe0, 0x07, 0x60, - 0xe0, 0x07, 0x48, 0x98, 0x94, 0xea, 0x4d, 0xd2, 0x14, 0x51, 0xc2, 0xe4, - 0xb3, 0x00, 0xf3, 0x2c, 0x44, 0xc4, 0x4e, 0xc0, 0x44, 0xa0, 0x80, 0xd0, - 0x4d, 0x04, 0x02, 0x00, 0x13, 0x14, 0x72, 0xc0, 0x87, 0x74, 0x60, 0x87, - 0x36, 0x68, 0x87, 0x79, 0x68, 0x03, 0x72, 0xc0, 0x87, 0x0d, 0xaf, 0x50, - 0x0e, 0x6d, 0xd0, 0x0e, 0x7a, 0x50, 0x0e, 0x6d, 0x00, 0x0f, 0x7a, 0x30, - 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x71, 0xa0, - 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, 0x0e, 0x78, 0xa0, 0x07, 0x73, 0x20, - 0x07, 0x6d, 0x90, 0x0e, 0x71, 0x60, 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, - 0x06, 0xe9, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x90, - 0x0e, 0x76, 0x40, 0x07, 0x7a, 0x60, 0x07, 0x74, 0xd0, 0x06, 0xe6, 0x10, - 0x07, 0x76, 0xa0, 0x07, 0x73, 0x20, 0x07, 0x6d, 0x60, 0x0e, 0x73, 0x20, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xd0, 0x06, 0xe6, 0x60, 0x07, 0x74, 0xa0, - 0x07, 0x76, 0x40, 0x07, 0x6d, 0xe0, 0x0e, 0x78, 0xa0, 0x07, 0x71, 0x60, - 0x07, 0x7a, 0x30, 0x07, 0x72, 0xa0, 0x07, 0x76, 0x40, 0x07, 0x43, 0x9e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, - 0x3c, 0x06, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x79, 0x10, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x18, 0xf2, 0x34, 0x40, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x30, 0xe4, 0x81, 0x80, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x20, 0x0b, 0x04, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x32, 0x1e, 0x98, 0x14, 0x19, 0x11, 0x4c, 0x90, 0x8c, 0x09, 0x26, 0x47, - 0xc6, 0x04, 0x43, 0x22, 0x25, 0x30, 0x02, 0x50, 0x12, 0xc5, 0x50, 0x04, - 0x65, 0x50, 0x1e, 0x54, 0x4a, 0xa2, 0x0c, 0x0a, 0x61, 0x04, 0xa0, 0x08, - 0x0a, 0x84, 0xec, 0x0c, 0x00, 0xe1, 0x19, 0x00, 0xca, 0x63, 0x21, 0x06, - 0x01, 0x00, 0x00, 0xf0, 0x3c, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, - 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, - 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb1, 0xa9, 0x81, - 0x01, 0x41, 0xa1, 0xc9, 0x21, 0x8b, 0x09, 0x2b, 0xcb, 0x09, 0x83, 0x49, - 0xd9, 0x10, 0x04, 0x13, 0x04, 0xa2, 0x98, 0x20, 0x10, 0xc6, 0x06, 0x61, - 0x20, 0x26, 0x08, 0xc4, 0xb1, 0x41, 0x18, 0x0c, 0x0a, 0x70, 0x73, 0x13, - 0x04, 0x02, 0xd9, 0x30, 0x20, 0x09, 0x31, 0x41, 0xb0, 0x24, 0x02, 0x13, - 0x04, 0x22, 0xd9, 0x20, 0x10, 0xc6, 0x86, 0x84, 0x58, 0x18, 0x82, 0x18, - 0x1a, 0xc2, 0xd9, 0x10, 0x3c, 0x13, 0x04, 0x6c, 0xda, 0x80, 0x10, 0x11, - 0x43, 0x10, 0x03, 0x01, 0x6c, 0x08, 0xa4, 0x0d, 0x04, 0x04, 0x00, 0xd3, - 0x04, 0x21, 0xa3, 0x36, 0x04, 0xd5, 0x04, 0x41, 0x00, 0x48, 0xb4, 0x85, - 0xa5, 0xb9, 0x71, 0x99, 0xb2, 0xfa, 0x82, 0x7a, 0x9b, 0x4b, 0xa3, 0x4b, - 0x7b, 0x73, 0x9b, 0x20, 0x14, 0xcc, 0x04, 0xa1, 0x68, 0x36, 0x04, 0xc4, - 0x04, 0xa1, 0x70, 0x26, 0x08, 0xc5, 0xb3, 0x61, 0x21, 0x32, 0x6d, 0xe3, - 0xba, 0xa1, 0x23, 0x3c, 0x80, 0x08, 0x55, 0x11, 0xd6, 0xd0, 0xd3, 0x93, - 0x14, 0xd1, 0x04, 0xa1, 0x80, 0x26, 0x08, 0x84, 0xb2, 0x41, 0x10, 0x03, - 0x31, 0xd8, 0xb0, 0x0c, 0x60, 0xa0, 0x79, 0x5c, 0x18, 0x0c, 0x61, 0x30, - 0x78, 0x63, 0xb0, 0x41, 0xf8, 0xc8, 0x80, 0xc9, 0x94, 0xd5, 0x17, 0x55, - 0x98, 0xdc, 0x59, 0x19, 0xdd, 0x04, 0xa1, 0x88, 0x26, 0x08, 0xc4, 0xb2, - 0x41, 0x10, 0x03, 0x34, 0xd8, 0xb0, 0x10, 0x66, 0xa0, 0x9d, 0x01, 0xe7, - 0x0d, 0x1d, 0xe1, 0xa5, 0xc1, 0x86, 0x40, 0x0d, 0x36, 0x0c, 0x65, 0xb0, - 0x06, 0xc0, 0x86, 0xe2, 0xc2, 0xd8, 0x80, 0x02, 0xaa, 0xb0, 0xb1, 0xd9, - 0xb5, 0xb9, 0xa4, 0x91, 0x95, 0xb9, 0xd1, 0x4d, 0x09, 0x82, 0x2a, 0x64, - 0x78, 0x2e, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x53, 0x02, 0xa2, - 0x09, 0x19, 0x9e, 0x8b, 0x5d, 0x18, 0x9b, 0x5d, 0x99, 0xdc, 0x94, 0xc0, - 0xa8, 0x43, 0x86, 0xe7, 0x32, 0x87, 0x16, 0x46, 0x56, 0x26, 0xd7, 0xf4, - 0x46, 0x56, 0xc6, 0x36, 0x25, 0x48, 0xca, 0x90, 0xe1, 0xb9, 0xc8, 0x95, - 0xcd, 0xbd, 0xd5, 0xc9, 0x8d, 0x95, 0xcd, 0x4d, 0x09, 0xa6, 0x3a, 0x64, - 0x78, 0x2e, 0x76, 0x69, 0x65, 0x77, 0x49, 0x64, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x53, 0x82, 0xaa, 0x0e, 0x19, 0x9e, 0x4b, 0x99, 0x1b, 0x9d, 0x5c, - 0x1e, 0xd4, 0x5b, 0x9a, 0x1b, 0xdd, 0xdc, 0x94, 0x80, 0x0d, 0x00, 0x00, - 0x79, 0x18, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x33, 0x08, 0x80, 0x1c, - 0xc4, 0xe1, 0x1c, 0x66, 0x14, 0x01, 0x3d, 0x88, 0x43, 0x38, 0x84, 0xc3, - 0x8c, 0x42, 0x80, 0x07, 0x79, 0x78, 0x07, 0x73, 0x98, 0x71, 0x0c, 0xe6, - 0x00, 0x0f, 0xed, 0x10, 0x0e, 0xf4, 0x80, 0x0e, 0x33, 0x0c, 0x42, 0x1e, - 0xc2, 0xc1, 0x1d, 0xce, 0xa1, 0x1c, 0x66, 0x30, 0x05, 0x3d, 0x88, 0x43, - 0x38, 0x84, 0x83, 0x1b, 0xcc, 0x03, 0x3d, 0xc8, 0x43, 0x3d, 0x8c, 0x03, - 0x3d, 0xcc, 0x78, 0x8c, 0x74, 0x70, 0x07, 0x7b, 0x08, 0x07, 0x79, 0x48, - 0x87, 0x70, 0x70, 0x07, 0x7a, 0x70, 0x03, 0x76, 0x78, 0x87, 0x70, 0x20, - 0x87, 0x19, 0xcc, 0x11, 0x0e, 0xec, 0x90, 0x0e, 0xe1, 0x30, 0x0f, 0x6e, - 0x30, 0x0f, 0xe3, 0xf0, 0x0e, 0xf0, 0x50, 0x0e, 0x33, 0x10, 0xc4, 0x1d, - 0xde, 0x21, 0x1c, 0xd8, 0x21, 0x1d, 0xc2, 0x61, 0x1e, 0x66, 0x30, 0x89, - 0x3b, 0xbc, 0x83, 0x3b, 0xd0, 0x43, 0x39, 0xb4, 0x03, 0x3c, 0xbc, 0x83, - 0x3c, 0x84, 0x03, 0x3b, 0xcc, 0xf0, 0x14, 0x76, 0x60, 0x07, 0x7b, 0x68, - 0x07, 0x37, 0x68, 0x87, 0x72, 0x68, 0x07, 0x37, 0x80, 0x87, 0x70, 0x90, - 0x87, 0x70, 0x60, 0x07, 0x76, 0x28, 0x07, 0x76, 0xf8, 0x05, 0x76, 0x78, - 0x87, 0x77, 0x80, 0x87, 0x5f, 0x08, 0x87, 0x71, 0x18, 0x87, 0x72, 0x98, - 0x87, 0x79, 0x98, 0x81, 0x2c, 0xee, 0xf0, 0x0e, 0xee, 0xe0, 0x0e, 0xf5, - 0xc0, 0x0e, 0xec, 0x30, 0x03, 0x62, 0xc8, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, - 0xcc, 0xa1, 0x1c, 0xe4, 0xa1, 0x1c, 0xdc, 0x61, 0x1c, 0xca, 0x21, 0x1c, - 0xc4, 0x81, 0x1d, 0xca, 0x61, 0x06, 0xd6, 0x90, 0x43, 0x39, 0xc8, 0x43, - 0x39, 0x98, 0x43, 0x39, 0xc8, 0x43, 0x39, 0xb8, 0xc3, 0x38, 0x94, 0x43, - 0x38, 0x88, 0x03, 0x3b, 0x94, 0xc3, 0x2f, 0xbc, 0x83, 0x3c, 0xfc, 0x82, - 0x3b, 0xd4, 0x03, 0x3b, 0xb0, 0xc3, 0x0c, 0xc4, 0x21, 0x07, 0x7c, 0x70, - 0x03, 0x7a, 0x28, 0x87, 0x76, 0x80, 0x87, 0x19, 0xd1, 0x43, 0x0e, 0xf8, - 0xe0, 0x06, 0xe4, 0x20, 0x0e, 0xe7, 0xe0, 0x06, 0xf6, 0x10, 0x0e, 0xf2, - 0xc0, 0x0e, 0xe1, 0x90, 0x0f, 0xef, 0x50, 0x0f, 0xf4, 0x00, 0x00, 0x00, - 0x71, 0x20, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x46, 0x20, 0x0d, 0x97, - 0xef, 0x3c, 0xbe, 0x10, 0x11, 0xc0, 0x44, 0x84, 0x40, 0x33, 0x2c, 0x84, - 0x05, 0x4c, 0xc3, 0xe5, 0x3b, 0x8f, 0xbf, 0x38, 0xc0, 0x20, 0x36, 0x0f, - 0x35, 0xf9, 0xc5, 0x6d, 0xdb, 0x00, 0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x12, - 0xc0, 0x3c, 0x0b, 0xe1, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, - 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, - 0x6d, 0x00, 0x04, 0x03, 0x20, 0x0d, 0x00, 0x00, 0x61, 0x20, 0x00, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x13, 0x04, 0x41, 0x2c, 0x10, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0xf4, 0x46, 0x00, 0x88, 0x94, 0xc2, 0x0c, 0x40, - 0xc9, 0x15, 0x42, 0xe1, 0x51, 0x29, 0x01, 0x1a, 0x33, 0x00, 0x00, 0x00, - 0x23, 0x06, 0x09, 0x00, 0x82, 0x60, 0x00, 0x65, 0x85, 0x73, 0x5d, 0xc8, - 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x40, 0x9a, 0x11, 0x61, 0x58, 0x32, - 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0x86, 0x67, 0x68, 0x19, 0x84, 0x8c, - 0x18, 0x24, 0x00, 0x08, 0x82, 0x81, 0xf1, 0x1d, 0x9b, 0x56, 0x24, 0x23, - 0x06, 0x0f, 0x00, 0x82, 0x60, 0xd0, 0x78, 0x07, 0x31, 0x08, 0x41, 0x51, - 0x6c, 0x9b, 0x52, 0x8c, 0x26, 0x04, 0xc0, 0x68, 0x82, 0x10, 0x8c, 0x26, - 0x0c, 0xc2, 0x68, 0x02, 0x31, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, - 0x42, 0x06, 0x10, 0x18, 0x80, 0xc1, 0x45, 0x8c, 0x18, 0x24, 0x00, 0x08, - 0x82, 0x01, 0x42, 0x06, 0x10, 0x18, 0x80, 0xc1, 0x32, 0x8c, 0x18, 0x24, - 0x00, 0x08, 0x82, 0x01, 0x42, 0x06, 0x10, 0x18, 0x80, 0x81, 0x25, 0x8c, - 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x42, 0x06, 0x10, 0x18, 0x80, 0x41, - 0x16, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -// clang-format on \ No newline at end of file diff --git a/tests/graphics/shaders/bin/compute.dxil b/tests/graphics/shaders/bin/compute.dxil new file mode 100644 index 0000000000000000000000000000000000000000..afe9aae521c3bc002c59efd11760e27ba16d22dd GIT binary patch literal 3464 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 Kn+=o}=)VAd%@Py< literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/ray_tracing.spv b/tests/graphics/shaders/bin/ray_tracing.spv new file mode 100644 index 0000000000000000000000000000000000000000..e2158940853ac5759595d04c3f9dbbb95e2a32ac GIT binary patch literal 2740 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 O8ozX;dWnJ)f$|@#1*o0? literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/texture_frag.spv b/tests/graphics/shaders/bin/texture_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..83aab1e4025792323f27ad9ce766832f15996d46 GIT binary patch literal 756 zcmZXQOH0F05QWF4N$aZ*tE~@^w(hfVA%f^e#g!Da)b1o;3;|n9jH3VCjo|riQzCQql1oW?HwZl~p-EXHjw+rBj9_C9HaiIQI^EH)A0Y@8Gco>CBMIm-N=)j4wVEL?PbhveTE9=;GRQs z%o{Av!HaoYYOBIs<(^KwDVVpzcM)KsE5_RV=(zi0@mBQLi$1s`yrGH~n&8a>qYJ;L ziY|R{U6tMVuO;1vYEPY}D(3^8c_;MF^yMDxN`UcaHv)`4UU+~P`gok^Pc)ekczlb! xrFt$dcWNp5AB^X=5)da4{(M76Ft5xlTm66;iDMMUr_9rVPZQ&8dYr)5VY8_ff69q zW^98E^-?DRg(MpS+El3863EgK=!XCUb%11ykclOf!9v-GNXMp3%A{%AeFk?d+aJ@U z?XMpB-gE9bzkAMm=f3yzQ&h<01uvWxl#MOSu3ZwVMBgbpO#=W3m;hiQ0*vmH`^= z3E>KiXTw3^pO?Quq5O0@_4{Yx?JotC{@0uM@@|@|8=9(HN{w~qf7Br0mS8;^kOg`c zwx5qi+gtB1Ax^*hhM2Qlj{0lTEGc^Q{J&e3nWh08{vJ2rdCn4hG;oM_k zBAL6y%OT~(?rR`cB-<)sdn1!(G}7{R&!*$^ZX~f7E$0FNA0ZI$*`Qj9N$A5Y=PqS3 zNLUsqVVvq~wA~;hq3(hcb*7>uJd`}ufkY?0>x9!|=b)DprFMJ5olZ3&Oa`f-JJyy@ z7xpDfx-%6z#R(=k6gS;&Q^5VvoQ6qPlfji!>uRlKK$~?#!!|9k+u#f$+Jsoc0MG+Kg&)qqieCG@ukV9gS&&44v6q1y!3yoWTfVTL{AHVh455M$b4!#w*L0v>t) zmoEqaonn-r+8+>RD?tKy1_ANYY1CsXI^4&JjZ}L*q5PNU5cyCPmnP^G3EsXbK;FLq zZM#T-JRBu_I09^w5Z?-WcM|G2hT2<9k5;_RJiYUzl$kP@`f1S|T0ED!jUq+-PBr@J zPVqLsT2815x6v*k;+^fQB!Pr{I37wbujjIzeI!1K8hn!Ug-+WqgiKYIw4$FiC7->n zK6jmYBQ5>z_wbebx+wkf#rw#hhL6wQOeFbuNS2iJu%_QIRp50)M_wDj!;)os=h3H6 zQ;KdGV{di6KRgvDsCRfxmGAxVlY#Z^<=-r?ukrDsEUDo8p>%6Kks(|iAwJvE|8h4{ z$E~kGO+!asA3?(&k?tvOJvUDTayTj-3MP~8n$DTcb_toiy?pPJRX-nB$WCTF*?Ik( z*B+JZIqS()1);t9ciYGY?HWrwGy67CK1YJ?#Hm?M6XQRtT!dKiU^EuJO| zb{5B4OI#KU)@ETex40~%D|RuGz2jwX3M0(Ih{wC^T@5>nm`PYqs8!k<+>XB zT&;cW>0j)!zt~{^X_CDoWK{VFd0T_L#lXB~pU0nwy=h@I5UxfGgSr=k%i?#P8OGZB+QnP82(u*O^Ck8! z?3a}UfO-eMCS+auz4))c0*+Pj%2v#niT=Ry=X;NjU5t(t94!oZfT~ClZM_VZAv_=@ zQf&!m-#-404|GcO%|kUm`S`}|rM5zf^8_J#9H@dX-$4!}pg+ig(yuu1f5(CQX9LxL z!hyu|9N1MQaQt!LNLQpSN#KwTB!p*rB=F0FdRzkUTPf841qb$##4KtQ3Rdry68K4< zEoBBVT62&EL<)vid++?Lck^h+weiUIwkxV3Ra?Uql5+>LUk);Z3|8>*nNjJ$Ff05I zlJgu^bfjJ}+&$9S-~X;VC*2oPbUa%v*O`cP&qB|Gn3YGBaj!hQ`Un{`1lW)Cvgi*W zX|f)sm^a-1MU6FAjE`@4a*MpXLg;}?hZX>zeLzzlfW|bF^INGUKYa2b>6oA{? zt+AY5au05+EYTNE@4?BK<9d~F5AN^K^=kLvw1!0e18xxR))&qM;Z^#18!Qav@4m5; Az5oCK literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/texture_vert.spv b/tests/graphics/shaders/bin/texture_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..1a053ec4e0e6d4e3aa4d27f619e310ded6ede396 GIT binary patch literal 620 zcmYk2yH7%448;qV%S+`U4>yBhG+`trMj6x)2EBj`tPBh+m=GY2{@E-fo?p2i;Y)hk z)6<^zHp+GjW*IZ9SX*CS-Lh#WatvFw@;TlwH{0d!=VG-sRhm(ilf@oK?&l(6%R9eX z_x6iTZ=8IOW~1cG^Yolpq5E;{-f+=(wKriK|EVJ?C$d3g4KXD9e;dFGP`-=vuO zhEyu@52~oj6F;j4P4v+X7>$6@M4ucyny0&)^%bE*Ef3v;)N1lCs%36nhJL`eiqV>= pm)#pOYIq^nR7?)tu`a~_v}Dx6aWn4pDkXMEfGd={6s(H@8`1d;TWJ7*JS1g&=7B|HOQj3Ls2j5(4w&#$GpK zjAqtlU~p)xhI)hCFb^FQ^moIg%2=aiK+Ha_z_>y=bzj5D6ssB{ke(aS z$s79pEAEeuq9QfcAOHX!H^}raGbO^S*uPBmtTQG;G5f87d1lW%mq|fEJp?=E2xYmP zWa`iW%F8|Pf!za7D8SFq`ur&#kCv3?fqZaONSCpt!Mv)Yg(`z;KbJbY^?E;Tfa7`m z?kTUsF>PW`Qp=$I$^U=PyzqNlN16yYLmU}}sc{@)I+h7IPhy5xL^<}&Wd>ld0wZH*1pgl3_L5ZWpcrSC z%}RwzmJ{R))3pJAviR8*BgB(Drh&^Lx9ZUuB*>`-={99~|!ii%yQURb{a zaO_q@8&I=(s#mz3Yme%=+h+3LuAafvGx<>rtribzvA5UMQL#lyYDu5jRYhic`tMLA znsj9{ncdJXAUr{eGliMLRRy;O>AO;HZIRqKo_b9g(e7Nku)W}&W4A^Yw=CRi+}iZv z=sh%~6LY5D6j5SMQjuKpT55`@-e5`H+{G#w91D(}7jp)R|-PKN(Si`bIx1Vcs z7dQSHWBo0t{qfHm25y`=`F=fl^l(@~U*lto#m2~D2Pa|*uODMw4C!)Z0Bmlv+8uTt z$_^Etc78FfE|F6iTkUO!57-@<+@exsw+1QJxSwfncXsS-J7lps^sezu!m*c|UR`R0 zI~<`~6@w3(x6HKsNW3Rs^4Gx1{HjQhjou_E67GN3YEyw^}de5GG%DoegJlOf7)nVzj>)FMy z_RJYDJXge_vmz^5Eqqp`Pg&{-`xP|a+k@MKUEC;0dqfgXXrhR#$hm$k``u7hi!><) zb7#&Wm9xr9KTZ?M1M({C&FSdUa8dcc9)ZO+Ect#XtW7+;=J#R=51VgS}|``@0Y7PVmwt z#g(xL(4?~llPTsY0YD?yYxpq>0Ch%aU@Y^i^gQFxqlrbSlHs@~3C^qh7UwNJ#d!=L ze$ROc7W`jxUgB(^`j4CkUp?Q+c|*+-_v7(rhGY^?I-M&aKfJ{EKqv==Z&v16tAWmc z!FNH5oW{&j$<#abB8v|#G2VS4-diBkJxcWxx&ea{Uk5c>_ zkm*X$2pTd%rn_tw6>}nmaw?F@KGk8wQqG=#A&Ax9qYRlR zw*Pw98`8A1~2zL3-Lq$1?_J>Id;L{Q5#qgh3%K>c3iE? z9X*?JZpUaw!HaP8&83f5ACKSvVCm!N1Zw`Cm;Rr;WTpVff%lS!$_tnmGxL3>8jvEo zO@@4Ef;=o4xJ)Lk3KfNYayCr~1O`zxyRbO`C=RB!X!q^&3$_7{tKXcxupo%TX(Lu$ e7>UEFQ}TvsX&mme=oWJ0a8|RB{}CGhn*A3Us%d%v literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/triangle_frag.spv b/tests/graphics/shaders/bin/triangle_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..3cf2393e2358a0647a03c2d8ca528ccb28deae0c GIT binary patch literal 376 zcmZXPy9>f#48&s}zVU&en<(y%B8V;yE{dQcZqh+ZmkLGw+g${I_f;o9NR!Lua;fi) zN@fK!YgnDHUfaBH$9Gt4)5;c*RbR6x-b6_%(jzq0;wz42RKA7e6J%&bHz3?i&z2D)|fNy?`t7+tnY? z&F|D5W*s({$wPKj$f{?|NFz`Em+(&`-w8_1iPMwr#dMWCXI6V_g!BvcN+bM6F(p0{ CK^K_- literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/triangle_vert.dxil b/tests/graphics/shaders/bin/triangle_vert.dxil new file mode 100644 index 0000000000000000000000000000000000000000..f458f68ddb428ea755a7a4dcdcdffeebbfe3757c GIT binary patch literal 3160 zcmeHJeN0=|6~Fc~e$QZ=N9++hcF-fi$cb3un6EI*}KRvZcsVb@K`~LpZAI$w~V0hN@`6nMz001T?04SVgP<2q> zfr`VxL#TJ@0DKA6ped1H&>xo)!wb7ia6yF{_iN)pI3qC|i5qZT@r^jSH%e{{MPF_x zF_x770I14!<$D1rhxMzW|9SPvym;AUGC3y3xB+J}PU7NmL)FXrgRKp14F{X!TL8VG zO0obkIWa7pz9#>ILe`*C$=}x{HMYzk=Wjgx`YSl<>}_@JWtN6!5<=D?1&129DL@&0 z&ctX0`YEbs??t*OK#d@@^_=LMq6P?jkmxhTa>$9SNkElDCBik=GoAfMG{50Cp8Yf;%RrV$+ zy||RS8{?HGN|oK(AeT^Sx<>$Cs$9{sgDG34^oj~sVA*s32rXShuiyay|29AnxJ$MX zl~YGq-Zj!h2)HdMfpM~@9Jg6X!1*v7$g`4e!5Bns7mc&!lot;7yhB0m23>a`$?MhO zlC3}lj_{oYR7q&7{Kzh~QC-C(hBr;RoI04#;o8UjZDxO-)!$)7pv`($&u&^^cft`Q zcS=zENwk$fn}Y0?xX~UrTFfX3SfKyuD=>!~?KGop3-kz%I@Xb9HmtCYjKI)I6k?k0 zvSFQAg{Vh0`0P>u;FHmDvi(tEcHjhnXAqScDuo3NX|Z_1-Gu0Z8Y)NqbLPR-M`g^6Y0<~U z({#&2y!PgG+K@RDEBD~JGV^3^62 z)-b&NCugw41G^qiJb69HSR91xZ^tb8he><<+_qyW3<&mo+7skr) zM5|j)2)w1tyet||_tJOhDjvSbYc$cDhPS_hd0d-3EGoZm!nd4_m{mjS9|Mqe?N;Pr zBok9B5A1lfdh}SMTQ1ItT)XnS$iqx*>b(gql50ZptVsUoWJ-r<#qL zfv1tYe3A9fWQCFb+oGPbt6f+7%NT>-gH`I9+w2|sgAL7Xtp<1YL#6M5^l8-t&5N1& z`63%hJ<;@NGsID1us)XWSCSB8Z1(eai=cqv^t z<=TA7LjNSFDwt6fgrej5@a{g>5tVn)*%PIEfAo(o+ZV4`c<-GjInbD}&WV-q zGJcg4WzZkzMBTTX_`l=C*xA78KXM{@{?FsY!!=@$U7Y+}LL~XH9OnHOd>A6|i*$=b zymYw?#}0&@8B;V%M;>jCrU0XmJg)XH=XQ;ZrMNmz>>1wEX+J@5FVTifd9$p#QlQ0Pew*6-3=((|+58lr| z$51XqPOkOHUl*hfdnB_0*%qpYHD^=wqiIJ& zE#w}9`(z@2@aX>Ix2iw=#mzpa6%tU*#_4*;KGI76O2sutofm WZ<%i>pTU=&FynBBqkta!DE>FM9in3Z literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/triangle_vert.spv b/tests/graphics/shaders/bin/triangle_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..8841490f23661cfe2cb857d3885f1f833c898b0d GIT binary patch literal 720 zcmYk3O-q7N5QQgA`_|0TJ|K*ify)S@TC@nEdhKJ;)`bf<24d2(pWPrz znR{m5Yq@l~60sB!wK(F}(}>c7DJQI2kM+NLHk?d{pAUo4IOvS9YniB|x}5SGLM5t6 zAC0@S!KB+SUV5*+;xX~wS@5^Teen!TydLi#({v#V6%=>)KlhG_&fFk8Vs|-CXpWsB z_O80#S#Pm*72F}t(5!igbTVE|=4PzBfn>NUe>sK>NmgVeZJr4okV&ne(OK%IJi^B9!^h39@Ei7g@|5! zMD^ep5U3;S1j0ZH_T|L1c8?&Ay98jSF+i!;pKYB$*hL8346qyl0iXfk zI#OzNww+0bhrMy4G)S!S|= pc.width || id.y >= pc.height) { - return; - } - - uint index = id.y * pc.width + id.x; - outBuffer.pixels[index] = pc.color; -} \ No newline at end of file diff --git a/tests/graphics/shaders/hlsl/compute.hlsl b/tests/graphics/shaders/hlsl/compute.hlsl deleted file mode 100644 index d9e0fa41..00000000 --- a/tests/graphics/shaders/hlsl/compute.hlsl +++ /dev/null @@ -1,25 +0,0 @@ - -struct PushConstants -{ - uint width; - uint height; - float4 color; -}; - -PushConstants pc; - -// We used raw Buffer but structured buffer can be used as well. -// PalDescriptorBufferInfo::stride must be set to 16 -RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 - -[numthreads(16, 16, 1)] -void main(uint3 id : SV_DispatchThreadID) -{ - if (id.x >= pc.width || id.y >= pc.height) { - return; - } - - uint index = id.y * pc.width + id.x; - uint offset = index * 16; // sizeof(float4) - outBuffer.Store4(offset, asuint(pc.color)); -} \ No newline at end of file diff --git a/tests/graphics/shaders/spirv/compute.spv b/tests/graphics/shaders/spirv/compute.spv deleted file mode 100644 index 092f9b3fa93a89131beb8fdebe782f44aaedde4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1704 zcmZ9L+fGwa5QaC@Rul!1lP9o%XB1HZQRHk=Nk}m90ZgTZ?xeQF?kbmF_%L4i5WbV~ zkeK*=yL-ik)l6pQpVPl*t>$`XPDfEs)F1Ul+fnBXMZF*qSRvJ=-8Z{)t)w!yusCnV zK$J@p%^4&ok3NOGFUJi7=a38FVneB|@05tj9NnYnJ5HXA?z%j&GsNPGvA(p=Vf}5X z-h5ZC?=(I(_sdD#Z0x)wCr|$|^y_x3w%u&Bl5!(y;mbzc^C_+*HFUt7U#rH4wd6l0 zm;GkF`2p?xOX#Eh4z~x`aidZ_PGg1WDSEG+9JQ0J_Q65blC-zD=O{j|)*+GS_YA+; zm003S-Ag}m4SChYa|YiNFnNl(n}Eqv%srOi={JhmcL`lUjF}(!gudpB$OMe;k+W^8OP@lrI_&|eji#)F@6?pjXjLpzXuUt$$a-C zHo}xa^elMzF5I-v_Y`K0(QPEfJ2OVH_1)WKwqNTNW6m8%`^Ma#bM?J*F~7@iE+X=9 zzWx=&WBpaMx%LeFrm?&8Z)W}k{Ja}yPhxuq`u15yyDKqy=zA|>VeU%ioBsm4!?9Dp zp2h4Pcx+<(2JXYoy>205iX4~NiT&M=$Gi9i;{R6;-kCGpufDtXKcK&gZ_o3H_p}Ep zK9FJJo*rb4&h|03Nq75PM8xE0FZVZ$h@0bH{a<(&?mOg6WcW97d=rz1b>d&?BX%7T z|H<4bwC4{o@ggGTcWMVdGuZNRFJaaVZ1KS77Pfr6&yaH)TRiZ&gKeGoZ)Sv9>K|-K zes>Z1xo7i>h+JpU9=V!x4-u2A_FuNCEf#psVV~sv5KKJqp2t49$46k|Utr+QRd>dp?9*~32}(qydw diff --git a/tests/graphics/shaders/src/compute.hlsl b/tests/graphics/shaders/src/compute.hlsl new file mode 100644 index 00000000..512d1d3d --- /dev/null +++ b/tests/graphics/shaders/src/compute.hlsl @@ -0,0 +1,54 @@ + +struct PushConstants +{ + uint width; + uint height; + float4 color; +}; + +PushConstants pc; + +// We used raw Buffer but structured buffer can be used as well. +// PalDescriptorBufferInfo::stride must be set to 16 +RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 + +[numthreads(16, 16, 1)] +void computeMain(uint3 id : SV_DispatchThreadID) +{ + if (id.x >= pc.width || id.y >= pc.height) { + return; + } + + uint index = id.y * pc.width + id.x; + uint offset = index * 16; // sizeof(float4) + outBuffer.Store4(offset, asuint(pc.color)); +} + +// GLSL equivalent + +// #version 450 + +// layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +// layout(set = 0, binding = 0) buffer OutputBuffer +// { +// vec4 pixels[]; +// } outBuffer; + +// layout(push_constant) uniform PushConstants +// { +// uint width; +// uint height; +// vec4 color; +// } pc; + +// void main() +// { +// uvec2 id = gl_GlobalInvocationID.xy; +// if (id.x >= pc.width || id.y >= pc.height) { +// return; +// } + +// uint index = id.y * pc.width + id.x; +// outBuffer.pixels[index] = pc.color; +// } diff --git a/tests/graphics/shaders/src/mesh.hlsl b/tests/graphics/shaders/src/mesh.hlsl new file mode 100644 index 00000000..23a8a579 --- /dev/null +++ b/tests/graphics/shaders/src/mesh.hlsl @@ -0,0 +1,56 @@ + +struct MSOutput +{ + float4 position : SV_POSITION; + float4 color : COLOR; +}; + +[outputtopology("triangle")] +[numthreads(1, 1, 1)] +void meshMain( + out vertices MSOutput meshVertices[4], + out indices uint3 triangleIndices[2]) +{ + SetMeshOutputCounts(4, 2); + meshVertices[0].position = float4(-0.5, 0.5, 0.0, 1.0); + meshVertices[1].position = float4( 0.5, 0.5, 0.0, 1.0); + meshVertices[2].position = float4( 0.5,-0.5, 0.0, 1.0); + meshVertices[3].position = float4(-0.5,-0.5, 0.0, 1.0); + + meshVertices[0].color = float4(1.0, 0.0, 0.0, 1.0); + meshVertices[1].color = float4(0.0, 1.0, 0.0, 1.0); + meshVertices[2].color = float4(0.0, 0.0, 1.0, 1.0); + meshVertices[3].color = float4(1.0, 0.0, 0.0, 1.0); + + triangleIndices[0] = uint3(0, 1, 2); + triangleIndices[1] = uint3(0, 2, 3); +} + +// GLSL equivalent + +// #version 460 +// #extension GL_EXT_mesh_shader : require + +// layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; +// layout(max_vertices = 4, max_primitives = 2) out; +// layout(triangles) out; + +// layout(location = 0) out vec4 vColors[]; + +// void main() +// { +// SetMeshOutputsEXT(4, 2); +// gl_MeshVerticesEXT[0].gl_Position = vec4(-0.5, 0.5, 0.0, 1.0); +// gl_MeshVerticesEXT[1].gl_Position = vec4( 0.5, 0.5, 0.0, 1.0); +// gl_MeshVerticesEXT[2].gl_Position = vec4( 0.5,-0.5, 0.0, 1.0); +// gl_MeshVerticesEXT[3].gl_Position = vec4(-0.5,-0.5, 0.0, 1.0); + +// // colors +// vColors[0] = vec4(1.0, 0.0, 0.0, 1.0); +// vColors[1] = vec4(0.0, 1.0, 0.0, 1.0); +// vColors[2] = vec4(0.0, 0.0, 1.0, 1.0); +// vColors[3] = vec4(1.0, 0.0, 0.0, 1.0); + +// gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); +// gl_PrimitiveTriangleIndicesEXT[1] = uvec3(0, 2, 3); +// } \ No newline at end of file diff --git a/tests/graphics/shaders/src/ray_tracing.hlsl b/tests/graphics/shaders/src/ray_tracing.hlsl new file mode 100644 index 00000000..46ea26ea --- /dev/null +++ b/tests/graphics/shaders/src/ray_tracing.hlsl @@ -0,0 +1,124 @@ + +struct RayPayload +{ + float3 color; +}; + +struct HitAttributes +{ + float2 unused; +}; + +RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 +RaytracingAccelerationStructure tlas : register(t0, space0); // set 0 + +[shader("raygeneration")] +void raygenMain() +{ + uint2 pixel = DispatchRaysIndex().xy; + uint2 size = DispatchRaysDimensions().xy; + RayPayload payload; + payload.color = float3(0.0, 0.0, 0.0); + + float2 uv = (float2(pixel) + 0.5) / float2(size); + float2 ndcUv = uv * 2.0 - 1.0; + + RayDesc desc; + desc.Origin = float3(0.0, 0.0, -3.0);; + desc.Direction = normalize(float3(ndcUv.x, ndcUv.y, 1.0));; + desc.TMin = 0.001; + desc.TMax = 1000.0; + TraceRay(tlas, RAY_FLAG_NONE, 0xFF, 0, 0, 0, desc, payload); + + if (pixel.x >= size.x || pixel.y >= size.y) { + return; + } + + uint index = pixel.y * size.x + pixel.x; + uint offset = index * 16; // sizeof(float4) + float4 color = float4(payload.color, 1.0); + outBuffer.Store4(offset, asuint(color)); +} + +[shader("closesthit")] +void closestHitMain( + inout RayPayload payload, + in HitAttributes attr) +{ + payload.color = float3(0.0, 1.0, 0.0); +} + +[shader("miss")] +void missMain(inout RayPayload payload) +{ + payload.color = float3(0.0, 0.0, 0.0); +} + +// GLSL equivalent + +// // Raygen +// #version 460 +// #extension GL_EXT_ray_tracing : require + +// layout(set = 0, binding = 0) buffer OutputBuffer +// { +// vec4 pixels[]; +// } outBuffer; + +// layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; +// layout(location = 0) rayPayloadEXT vec3 payloadColor; + +// void main() +// { +// uvec2 pixel = gl_LaunchIDEXT.xy; +// uvec2 size = gl_LaunchSizeEXT.xy; +// payloadColor = vec3(0.0); + +// vec2 uv = (vec2(pixel) + 0.5) / vec2(size); +// vec2 ndcUv = uv * 2.0 - 1.0; +// vec3 origin = vec3(0.0, 0.0, -3.0); +// vec3 direction = normalize(vec3(ndcUv.x, ndcUv.y, 1.0)); + +// traceRayEXT( +// tlas, +// gl_RayFlagsOpaqueEXT, +// 0xFF, +// 0, +// 0, +// 0, +// origin, +// 0.001, +// direction, +// 1000.0, +// 0 +// ); + +// if (pixel.x >= size.x || pixel.y >= size.y) { +// return; +// } + +// uint index = pixel.y * size.x + pixel.x; +// outBuffer.pixels[index] = vec4(payloadColor, 1.0); +// } + +// // Closest Hit +// #version 460 +// #extension GL_EXT_ray_tracing : require + +// layout(location = 0) rayPayloadInEXT vec3 payloadColor; + +// void main() +// { +// payloadColor = vec3(0.0, 1.0, 0.0); +// } + +// // Miss +// #version 460 +// #extension GL_EXT_ray_tracing : require + +// layout(location = 0) rayPayloadInEXT vec3 payloadColor; + +// void main() +// { +// payloadColor = vec3(0.0); +// } \ No newline at end of file diff --git a/tests/graphics/shaders/src/texture_frag.hlsl b/tests/graphics/shaders/src/texture_frag.hlsl new file mode 100644 index 00000000..2c769605 --- /dev/null +++ b/tests/graphics/shaders/src/texture_frag.hlsl @@ -0,0 +1,30 @@ + +Texture2D tex : register(t0, space0); // set 0 +SamplerState samp : register(s0, space0); // set 0 + +struct PSInput +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD; +}; + +float4 fragMain(PSInput input) : SV_Target +{ + return tex.Sample(samp, input.uv); +} + +// GLSL equivalent + +// #version 450 + +// layout(set = 0, binding = 0) uniform texture2D tex; +// layout(set = 0, binding = 1) uniform sampler samp; + +// layout(location = 0) in vec2 aTexCoord; + +// layout(location = 0) out vec4 color; + +// void main() +// { +// color = texture(sampler2D(tex, samp), aTexCoord); +// } \ No newline at end of file diff --git a/tests/graphics/shaders/src/texture_vert.hlsl b/tests/graphics/shaders/src/texture_vert.hlsl new file mode 100644 index 00000000..bd630089 --- /dev/null +++ b/tests/graphics/shaders/src/texture_vert.hlsl @@ -0,0 +1,35 @@ + +struct VSInput +{ + float2 pos : POSITION; + float2 uv : TEXCOORD; +}; + +struct VSOutput +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD; +}; + +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + output.pos = float4(input.pos, 0.0, 1.0); + output.uv = input.uv; + return output; +} + +// GLSL equivalent + +// #version 450 + +// layout(location = 0) in vec2 aPosition; +// layout(location = 1) in vec2 aTexCoord; + +// layout(location = 0) out vec2 vTexCoord; + +// void main() +// { +// gl_Position = vec4(aPosition, 0.0, 1.0); +// vTexCoord = aTexCoord; +// } \ No newline at end of file diff --git a/tests/graphics/shaders/src/triangle_frag.hlsl b/tests/graphics/shaders/src/triangle_frag.hlsl new file mode 100644 index 00000000..72d47ecd --- /dev/null +++ b/tests/graphics/shaders/src/triangle_frag.hlsl @@ -0,0 +1,24 @@ + +struct PSInput +{ + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +float4 fragMain(PSInput input) : SV_Target +{ + return input.color; +} + +// GLSL equivalent + +// #version 450 + +// layout(location = 0) in vec4 aColor; + +// layout(location = 0) out vec4 color; + +// void main() +// { +// color = aColor; +// } \ No newline at end of file diff --git a/tests/graphics/shaders/src/triangle_vert.hlsl b/tests/graphics/shaders/src/triangle_vert.hlsl new file mode 100644 index 00000000..3a7cc3f8 --- /dev/null +++ b/tests/graphics/shaders/src/triangle_vert.hlsl @@ -0,0 +1,35 @@ + +struct VSInput +{ + float2 pos : POSITION; + float3 color : COLOR; +}; + +struct VSOutput +{ + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +VSOutput vertexMain(VSInput input) +{ + VSOutput output; + output.pos = float4(input.pos, 0.0, 1.0); + output.color = float4(input.color, 1.0); + return output; +} + +// GLSL equivalent + +// #version 450 + +// layout(location = 0) in vec2 aPosition; +// layout(location = 1) in vec3 aColor; + +// layout(location = 0) out vec4 vColor; + +// void main() +// { +// gl_Position = vec4(aPosition, 0.0, 1.0); +// vColor = vec4(aColor, 1.0); +// } diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index b441bc26..5a7efec1 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -855,38 +855,69 @@ bool textureTest() Uint64 fragBytecodeSize = 0; void* vertBytecode = nullptr; void* fragBytecode = nullptr; + const char* vertSource = nullptr; + const char* fragSource = nullptr; + + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; PalShaderCreateInfo vertShaderCreateInfo = {0}; PalShaderCreateInfo fragShaderCreateInfo = {0}; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - vertBytecodeSize = sizeof(s_TextureVertShaderSpv); - fragBytecodeSize = sizeof(s_TextureFragShaderSpv); + vertSource = "graphics/shaders/bin/texture_vert.spv"; + fragSource = "graphics/shaders/bin/texture_frag.spv"; - vertBytecode = (void*)s_TextureVertShaderSpv; - fragBytecode = (void*)s_TextureFragShaderSpv; + // flip for spirv since we use a single shader source + viewport.y = (float)WINDOW_HEIGHT; + viewport.height = -(float)WINDOW_HEIGHT; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - vertBytecodeSize = sizeof(s_TextureVertShaderDxil); - fragBytecodeSize = sizeof(s_TextureFragShaderDxil); - - vertBytecode = (void*)s_TextureVertShaderDxil; - fragBytecode = (void*)s_TextureFragShaderDxil; + vertSource = "graphics/shaders/bin/texture_vert.dxil"; + fragSource = "graphics/shaders/bin/texture_frag.dxil"; } + // read file + if (!readFile(vertSource, nullptr, &vertBytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } + + if (!readFile(fragSource, nullptr, &fragBytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } + + vertBytecode = palAllocate(nullptr, vertBytecodeSize, 0); + if (!vertBytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + fragBytecode = palAllocate(nullptr, fragBytecodeSize, 0); + if (!fragBytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(vertSource, vertBytecode, &vertBytecodeSize); + readFile(fragSource, fragBytecode, &fragBytecodeSize); + // describe how many entries are in the shader bytecode // For simplicity, we dont use one shader bytecode for all the shaders - PalShaderEntry vertEntry = {0}; - vertEntry.entryName = "main"; - vertEntry.stage = PAL_SHADER_STAGE_VERTEX; + PalShaderEntry vertexEntry = {0}; + vertexEntry.entryName = "vertexMain"; + vertexEntry.stage = PAL_SHADER_STAGE_VERTEX; PalShaderEntry fragmentEntry = {0}; - fragmentEntry.entryName = "main"; + fragmentEntry.entryName = "fragMain"; fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; vertShaderCreateInfo.bytecode = vertBytecode; vertShaderCreateInfo.bytecodeSize = vertBytecodeSize; - vertShaderCreateInfo.entries = &vertEntry; + vertShaderCreateInfo.entries = &vertexEntry; vertShaderCreateInfo.entryCount = 1; fragShaderCreateInfo.bytecode = fragBytecode; @@ -908,6 +939,9 @@ bool textureTest() return false; } + palFree(nullptr, vertBytecode); + palFree(nullptr, fragBytecode); + // create descriptor set layout PalDescriptorSetLayoutBinding descriptorBindings[2]; PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; @@ -1096,12 +1130,6 @@ bool textureTest() Uint32 currentFrame = 0; bool running = true; - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; - PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index a3ea62b9..ae536b23 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -558,33 +558,64 @@ bool triangleTest() Uint64 fragBytecodeSize = 0; void* vertBytecode = nullptr; void* fragBytecode = nullptr; + const char* vertSource = nullptr; + const char* fragSource = nullptr; + + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; PalShaderCreateInfo vertShaderCreateInfo = {0}; PalShaderCreateInfo fragShaderCreateInfo = {0}; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - vertBytecodeSize = sizeof(s_TriangleVertShaderSpv); - fragBytecodeSize = sizeof(s_TriangleFragShaderSpv); + vertSource = "graphics/shaders/bin/triangle_vert.spv"; + fragSource = "graphics/shaders/bin/triangle_frag.spv"; - vertBytecode = (void*)s_TriangleVertShaderSpv; - fragBytecode = (void*)s_TriangleFragShaderSpv; + // flip for spirv since we use a single shader source + viewport.y = (float)WINDOW_HEIGHT; + viewport.height = -(float)WINDOW_HEIGHT; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - vertBytecodeSize = sizeof(s_TriangleVertShaderDxil); - fragBytecodeSize = sizeof(s_TriangleFragShaderDxil); + vertSource = "graphics/shaders/bin/triangle_vert.dxil"; + fragSource = "graphics/shaders/bin/triangle_frag.dxil"; + } + + // read file + if (!readFile(vertSource, nullptr, &vertBytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } + + if (!readFile(fragSource, nullptr, &fragBytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } - vertBytecode = (void*)s_TriangleVertShaderDxil; - fragBytecode = (void*)s_TriangleFragShaderDxil; + vertBytecode = palAllocate(nullptr, vertBytecodeSize, 0); + if (!vertBytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; } + fragBytecode = palAllocate(nullptr, fragBytecodeSize, 0); + if (!fragBytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(vertSource, vertBytecode, &vertBytecodeSize); + readFile(fragSource, fragBytecode, &fragBytecodeSize); + // describe how many entries are in the shader bytecode // For simplicity, we dont use one shader bytecode for all the shaders PalShaderEntry vertexEntry = {0}; - vertexEntry.entryName = "main"; + vertexEntry.entryName = "vertexMain"; vertexEntry.stage = PAL_SHADER_STAGE_VERTEX; PalShaderEntry fragmentEntry = {0}; - fragmentEntry.entryName = "main"; + fragmentEntry.entryName = "fragMain"; fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; vertShaderCreateInfo.bytecode = vertBytecode; @@ -611,6 +642,9 @@ bool triangleTest() return false; } + palFree(nullptr, vertBytecode); + palFree(nullptr, fragBytecode); + // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); @@ -697,12 +731,6 @@ bool triangleTest() Uint32 currentFrame = 0; bool running = true; - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; - PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; diff --git a/tests/tests_main.c b/tests/tests_main.c index b0359452..960ba8bd 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,14 +58,14 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(computeTest, "Compute Test"); // TODO: test + // registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: test #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest(clearColorTest, "Clear Color Test"); + registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); - // registerTest(meshTest, "Mesh Test"); + // registerTest(meshTest, "Mesh Test"); // TODO: test // registerTest(textureTest, "Texture Test"); #endif // From b278a81b580eab3305f263cd6b139ac494540f81 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 9 May 2026 00:24:08 +0000 Subject: [PATCH 209/372] add more glsl shaders and simplyfy shader API --- include/pal/pal_graphics.h | 31 +--- src/graphics/pal_vulkan.c | 153 ++++++------------ tests/graphics/compute_test.c | 15 +- tests/graphics/mesh_test.c | 115 +++++-------- tests/graphics/ray_tracing_test.c | 99 ++++++------ tests/graphics/shaders.h | 5 - tests/graphics/shaders/bin/compute.dxil | Bin 3464 -> 0 bytes tests/graphics/shaders/bin/compute.spv | Bin 1820 -> 0 bytes .../shaders/bin/dxil/closest_hit.dxil | Bin 0 -> 2796 bytes tests/graphics/shaders/bin/dxil/compute.dxil | Bin 0 -> 3452 bytes tests/graphics/shaders/bin/dxil/mesh.dxil | Bin 0 -> 3276 bytes tests/graphics/shaders/bin/dxil/miss.dxil | Bin 0 -> 2576 bytes tests/graphics/shaders/bin/dxil/raygen.dxil | Bin 0 -> 4384 bytes .../shaders/bin/dxil/texture_frag.dxil | Bin 0 -> 3820 bytes .../shaders/bin/dxil/texture_vert.dxil | Bin 0 -> 3104 bytes .../shaders/bin/dxil/triangle_frag.dxil | Bin 0 -> 2964 bytes .../shaders/bin/dxil/triangle_vert.dxil | Bin 0 -> 3144 bytes tests/graphics/shaders/bin/mesh.dxil | Bin 3264 -> 0 bytes tests/graphics/shaders/bin/mesh.spv | Bin 1464 -> 0 bytes tests/graphics/shaders/bin/ray_tracing.dxil | Bin 5424 -> 0 bytes tests/graphics/shaders/bin/ray_tracing.spv | Bin 2740 -> 0 bytes .../shaders/bin/spirv/closest_hit.spv | Bin 0 -> 372 bytes tests/graphics/shaders/bin/spirv/compute.spv | Bin 0 -> 1704 bytes tests/graphics/shaders/bin/spirv/mesh.spv | Bin 0 -> 1772 bytes tests/graphics/shaders/bin/spirv/miss.spv | Bin 0 -> 356 bytes tests/graphics/shaders/bin/spirv/raygen.spv | Bin 0 -> 2620 bytes .../shaders/bin/spirv/texture_frag.spv | Bin 0 -> 676 bytes .../shaders/bin/spirv/texture_vert.spv | Bin 0 -> 1044 bytes .../shaders/bin/spirv/triangle_frag.spv | Bin 0 -> 372 bytes .../shaders/bin/spirv/triangle_vert.spv | Bin 0 -> 1140 bytes tests/graphics/shaders/bin/texture_frag.dxil | Bin 3824 -> 0 bytes tests/graphics/shaders/bin/texture_frag.spv | Bin 756 -> 0 bytes tests/graphics/shaders/bin/texture_vert.dxil | Bin 3112 -> 0 bytes tests/graphics/shaders/bin/texture_vert.spv | Bin 620 -> 0 bytes tests/graphics/shaders/bin/triangle_frag.dxil | Bin 2960 -> 0 bytes tests/graphics/shaders/bin/triangle_frag.spv | Bin 376 -> 0 bytes tests/graphics/shaders/bin/triangle_vert.dxil | Bin 3160 -> 0 bytes tests/graphics/shaders/bin/triangle_vert.spv | Bin 720 -> 0 bytes tests/graphics/shaders/src/compute.hlsl | 54 ------- .../shaders/src/glsl/closest_hit.glsl | 10 ++ tests/graphics/shaders/src/glsl/compute.glsl | 27 ++++ tests/graphics/shaders/src/glsl/mesh.glsl | 27 ++++ tests/graphics/shaders/src/glsl/miss.glsl | 10 ++ tests/graphics/shaders/src/glsl/raygen.glsl | 44 +++++ .../shaders/src/glsl/texture_frag.glsl | 14 ++ .../shaders/src/glsl/texture_vert.glsl | 14 ++ .../shaders/src/glsl/triangle_frag.glsl | 11 ++ .../shaders/src/glsl/triangle_vert.glsl | 13 ++ .../shaders/src/hlsl/closest_hit.hlsl | 18 +++ tests/graphics/shaders/src/hlsl/compute.hlsl | 25 +++ tests/graphics/shaders/src/hlsl/mesh.hlsl | 27 ++++ tests/graphics/shaders/src/hlsl/miss.hlsl | 11 ++ tests/graphics/shaders/src/hlsl/raygen.hlsl | 36 +++++ .../shaders/src/hlsl/texture_frag.hlsl | 14 ++ .../shaders/src/hlsl/texture_vert.hlsl | 20 +++ .../shaders/src/hlsl/triangle_frag.hlsl | 11 ++ .../shaders/src/hlsl/triangle_vert.hlsl | 20 +++ tests/graphics/shaders/src/mesh.hlsl | 56 ------- tests/graphics/shaders/src/ray_tracing.hlsl | 124 -------------- tests/graphics/shaders/src/texture_frag.hlsl | 30 ---- tests/graphics/shaders/src/texture_vert.hlsl | 35 ---- tests/graphics/shaders/src/triangle_frag.hlsl | 24 --- tests/graphics/shaders/src/triangle_vert.hlsl | 35 ---- tests/graphics/texture_test.c | 129 +++++---------- tests/graphics/triangle_test.c | 129 +++++---------- tests/tests_main.c | 8 +- 66 files changed, 593 insertions(+), 801 deletions(-) delete mode 100644 tests/graphics/shaders.h delete mode 100644 tests/graphics/shaders/bin/compute.dxil delete mode 100644 tests/graphics/shaders/bin/compute.spv create mode 100644 tests/graphics/shaders/bin/dxil/closest_hit.dxil create mode 100644 tests/graphics/shaders/bin/dxil/compute.dxil create mode 100644 tests/graphics/shaders/bin/dxil/mesh.dxil create mode 100644 tests/graphics/shaders/bin/dxil/miss.dxil create mode 100644 tests/graphics/shaders/bin/dxil/raygen.dxil create mode 100644 tests/graphics/shaders/bin/dxil/texture_frag.dxil create mode 100644 tests/graphics/shaders/bin/dxil/texture_vert.dxil create mode 100644 tests/graphics/shaders/bin/dxil/triangle_frag.dxil create mode 100644 tests/graphics/shaders/bin/dxil/triangle_vert.dxil delete mode 100644 tests/graphics/shaders/bin/mesh.dxil delete mode 100644 tests/graphics/shaders/bin/mesh.spv delete mode 100644 tests/graphics/shaders/bin/ray_tracing.dxil delete mode 100644 tests/graphics/shaders/bin/ray_tracing.spv create mode 100644 tests/graphics/shaders/bin/spirv/closest_hit.spv create mode 100644 tests/graphics/shaders/bin/spirv/compute.spv create mode 100644 tests/graphics/shaders/bin/spirv/mesh.spv create mode 100644 tests/graphics/shaders/bin/spirv/miss.spv create mode 100644 tests/graphics/shaders/bin/spirv/raygen.spv create mode 100644 tests/graphics/shaders/bin/spirv/texture_frag.spv create mode 100644 tests/graphics/shaders/bin/spirv/texture_vert.spv create mode 100644 tests/graphics/shaders/bin/spirv/triangle_frag.spv create mode 100644 tests/graphics/shaders/bin/spirv/triangle_vert.spv delete mode 100644 tests/graphics/shaders/bin/texture_frag.dxil delete mode 100644 tests/graphics/shaders/bin/texture_frag.spv delete mode 100644 tests/graphics/shaders/bin/texture_vert.dxil delete mode 100644 tests/graphics/shaders/bin/texture_vert.spv delete mode 100644 tests/graphics/shaders/bin/triangle_frag.dxil delete mode 100644 tests/graphics/shaders/bin/triangle_frag.spv delete mode 100644 tests/graphics/shaders/bin/triangle_vert.dxil delete mode 100644 tests/graphics/shaders/bin/triangle_vert.spv delete mode 100644 tests/graphics/shaders/src/compute.hlsl create mode 100644 tests/graphics/shaders/src/glsl/closest_hit.glsl create mode 100644 tests/graphics/shaders/src/glsl/compute.glsl create mode 100644 tests/graphics/shaders/src/glsl/mesh.glsl create mode 100644 tests/graphics/shaders/src/glsl/miss.glsl create mode 100644 tests/graphics/shaders/src/glsl/raygen.glsl create mode 100644 tests/graphics/shaders/src/glsl/texture_frag.glsl create mode 100644 tests/graphics/shaders/src/glsl/texture_vert.glsl create mode 100644 tests/graphics/shaders/src/glsl/triangle_frag.glsl create mode 100644 tests/graphics/shaders/src/glsl/triangle_vert.glsl create mode 100644 tests/graphics/shaders/src/hlsl/closest_hit.hlsl create mode 100644 tests/graphics/shaders/src/hlsl/compute.hlsl create mode 100644 tests/graphics/shaders/src/hlsl/mesh.hlsl create mode 100644 tests/graphics/shaders/src/hlsl/miss.hlsl create mode 100644 tests/graphics/shaders/src/hlsl/raygen.hlsl create mode 100644 tests/graphics/shaders/src/hlsl/texture_frag.hlsl create mode 100644 tests/graphics/shaders/src/hlsl/texture_vert.hlsl create mode 100644 tests/graphics/shaders/src/hlsl/triangle_frag.hlsl create mode 100644 tests/graphics/shaders/src/hlsl/triangle_vert.hlsl delete mode 100644 tests/graphics/shaders/src/mesh.hlsl delete mode 100644 tests/graphics/shaders/src/ray_tracing.hlsl delete mode 100644 tests/graphics/shaders/src/texture_frag.hlsl delete mode 100644 tests/graphics/shaders/src/texture_vert.hlsl delete mode 100644 tests/graphics/shaders/src/triangle_frag.hlsl delete mode 100644 tests/graphics/shaders/src/triangle_vert.hlsl diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 27ed83e8..398a5149 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2431,21 +2431,6 @@ typedef struct { PalImageAspect aspect; } PalImageCopyInfo; -/** - * @struct PalShaderEntry - * @brief Information for a single shader entry point in a shader bytecode. - * - * Uninitialized fields may result in undefined behavior. - * - * @since 1.4 - * @ingroup pal_graphics - */ -typedef struct { - Uint32 patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ - PalShaderStage stage; - const char* entryName; -} PalShaderEntry; - /** * @struct PalImageCreateInfo * @brief Creation parameters for an image. @@ -2537,10 +2522,11 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 entryCount; - void* bytecode; + Uint32 patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ + PalShaderStage stage; Uint64 bytecodeSize; - PalShaderEntry* entries; + void* bytecode; + const char* entryName; } PalShaderCreateInfo; /** @@ -2674,10 +2660,6 @@ typedef struct { Uint32 closestHitShaderIndex; /**< Index of closest hit shader from shader array.*/ Uint32 generalShaderIndex; /**< Index of general hit shader from shader array.*/ Uint32 intersectionShaderIndex; /**< Index of intersection hit shader from shader array.*/ - Uint32 anyHitEntryIndex; /**< Index of any hit Entry from `anyHitShaderIndex`.*/ - Uint32 closestHitEntryIndex; /**< Index of any hit Entry from `closestHitShaderIndex`.*/ - Uint32 generalEntryIndex; /**< Index of any hit Entry from `generalShaderIndex`.*/ - Uint32 intersectionEntryIndex; /**< Index of any hit Entry from `intersectionShaderIndex`.*/ } PalRayTracingShaderGroupCreateInfo; /** @@ -5143,9 +5125,6 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * `PAL_SHADER_STAGE_RAYGEN` or `PAL_SHADER_STAGE_CLOSEST_HIT` or `PAL_SHADER_STAGE_ANY_HIT` or * `PAL_SHADER_STAGE_MISS` or `PAL_SHADER_STAGE_INTERSECTION` or `PAL_SHADER_STAGE_CALLABLE` will * be used. - * - * If the pipeline only takes a single shader (eg. Compute Pipeline), only the first entry in - * the entries array will be used. * * @param[in] device Device that creates the shader. * @param[in] info Pointer to a PalShaderCreateInfo struct that specifies parameters. @@ -5157,7 +5136,7 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @note Each shader entry name must not be greater than `PAL_SHADER_ENTRY_NAME_SIZE (32)`. + * @note The shader entry name must not be greater than `PAL_SHADER_ENTRY_NAME_SIZE (32)`. * * @since 1.4 * @ingroup pal_graphics diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index bb9fa8c2..5181e912 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -477,20 +477,14 @@ typedef struct { Image* images; } Swapchain; -typedef struct { - Uint32 tmpIndex; - Uint32 patchControlPoints; - VkShaderStageFlags stage; - char entryName[PAL_SHADER_ENTRY_NAME_SIZE]; -} ShaderEntry; - typedef struct { const PalGraphicsBackend* backend; - Uint32 entryCount; - ShaderEntry* entries; + Uint32 patchControlPoints; + VkShaderStageFlagBits stage; Device* device; VkShaderModule handle; + char entryName[PAL_SHADER_ENTRY_NAME_SIZE]; } Shader; typedef struct { @@ -6001,37 +5995,24 @@ PalResult PAL_CALL createShaderVk( return PAL_RESULT_OUT_OF_MEMORY; } - shader->entries = palAllocate(s_Vk.allocator, sizeof(ShaderEntry) * info->entryCount, 0); - if (!shader->entries) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - for (int i = 0; i < info->entryCount; i++) { - ShaderEntry* entry = &shader->entries[i]; - strncpy(entry->entryName, info->entries[i].entryName, PAL_SHADER_ENTRY_NAME_SIZE); - entry->entryName[PAL_SHADER_ENTRY_NAME_SIZE - 1] = '\0'; - entry->patchControlPoints = info->entries[i].patchControlPoints; - entry->stage = shaderStageToVK(info->entries[i].stage); - - if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || - info->entries[i].stage == PAL_SHADER_STAGE_TASK) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + if (info->stage == PAL_SHADER_STAGE_MESH || + info->stage == PAL_SHADER_STAGE_TASK) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } - // clang-format off - } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || - info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_MISS || - info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || - info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + // clang-format off + } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || + info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || + info->stage == PAL_SHADER_STAGE_ANY_HIT || + info->stage == PAL_SHADER_STAGE_MISS || + info->stage == PAL_SHADER_STAGE_INTERSECTION || + info->stage == PAL_SHADER_STAGE_CALLABLE) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // clang-format on } + // clang-format on VkShaderModuleCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; @@ -6040,13 +6021,16 @@ PalResult PAL_CALL createShaderVk( result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, shader->entries); palFree(s_Vk.allocator, shader); return resultFromVk(result); } + strncpy(shader->entryName, info->entryName, PAL_SHADER_ENTRY_NAME_SIZE); + shader->entryName[PAL_SHADER_ENTRY_NAME_SIZE - 1] = '\0'; + shader->patchControlPoints = info->patchControlPoints; + shader->stage = shaderStageToVK(info->stage); + shader->device = vkDevice; - shader->entryCount = info->entryCount; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } @@ -6056,7 +6040,6 @@ void PAL_CALL destroyShaderVk(PalShader* shader) Shader* vkShader = (Shader*)shader; s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkShader->entries); palFree(s_Vk.allocator, vkShader); } @@ -8577,7 +8560,6 @@ PalResult PAL_CALL createGraphicsPipelineVk( Device* vkDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - Uint32 stagesCount = 0; VkPipelineShaderStageCreateInfo* shaderStages = nullptr; VkDynamicState dynamicStates[16]; VkVertexInputBindingDescription* bindingDescs = nullptr; @@ -8622,16 +8604,10 @@ PalResult PAL_CALL createGraphicsPipelineVk( createInfo.renderPass = VK_NULL_HANDLE; createInfo.layout = layout->handle; - // Every entry is a shader stage - for (int i = 0; i < info->shaderCount; i++) { - Shader* tmp = (Shader*)info->shaders[i]; - stagesCount += tmp->entryCount; - } - pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); shaderStages = palAllocate( s_Vk.allocator, - sizeof(VkPipelineShaderStageCreateInfo) * stagesCount, + sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount, 0); if (!pipeline) { @@ -8639,34 +8615,28 @@ PalResult PAL_CALL createGraphicsPipelineVk( } // shaders - Uint32 stageIndex = 0; - memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stagesCount); + memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; + VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[i]; - for (int j = 0; j < tmp->entryCount; j++) { - ShaderEntry* entry = &tmp->entries[j]; - VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex]; + if (tmp->patchControlPoints) { + tessellationState.patchControlPoints = tmp->patchControlPoints; + createInfo.pTessellationState = &tessellationState; - stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo->module = tmp->handle; - stageInfo->pName = entry->entryName; - stageInfo->stage = entry->stage; - stageIndex++; - - if (entry->patchControlPoints) { - tessellationState.patchControlPoints = entry->patchControlPoints; - createInfo.pTessellationState = &tessellationState; - - if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { - palFree(s_Vk.allocator, pipeline); - return PAL_RESULT_INVALID_OPERATION; - } + if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { + palFree(s_Vk.allocator, pipeline); + return PAL_RESULT_INVALID_OPERATION; } } + + stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageInfo->module = tmp->handle; + stageInfo->pName = tmp->entryName; + stageInfo->stage = tmp->stage; } - createInfo.stageCount = stagesCount; + createInfo.stageCount = info->shaderCount; createInfo.pStages = shaderStages; // Vertex input state @@ -9038,8 +9008,8 @@ PalResult PAL_CALL createComputePipelineVk( createInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; createInfo.stage.module = shader->handle; - createInfo.stage.stage = shader->entries[0].stage; - createInfo.stage.pName = shader->entries[0].entryName; + createInfo.stage.stage = shader->stage; + createInfo.stage.pName = shader->entryName; VkResult result = s_Vk.createComputePipeline( vkDevice->handle, @@ -9070,7 +9040,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( Device* vkDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; Pipeline* pipeline = nullptr; - Uint32 stagesCount = 0; VkPipelineShaderStageCreateInfo* shaderStages = nullptr; VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; @@ -9082,12 +9051,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( return PAL_RESULT_INVALID_ARGUMENT; } - // Every entry is a shader stage - for (int i = 0; i < info->shaderCount; i++) { - Shader* tmp = (Shader*)info->shaders[i]; - stagesCount += tmp->entryCount; - } - VkRayTracingPipelineCreateInfoKHR createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; @@ -9099,7 +9062,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( shaderStages = palAllocate( s_Vk.allocator, - sizeof(VkPipelineShaderStageCreateInfo) * stagesCount, + sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount, 0); @@ -9108,24 +9071,18 @@ PalResult PAL_CALL createRayTracingPipelineVk( } // shaders - Uint32 stageIndex = 0; - memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stagesCount); + memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; + VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[i]; - for (int j = 0; j < tmp->entryCount; j++) { - ShaderEntry* entry = &tmp->entries[j]; - VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex]; - - stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo->module = tmp->handle; - stageInfo->pName = entry->entryName; - stageInfo->stage = entry->stage; - entry->tmpIndex = stageIndex++; - } + stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageInfo->module = tmp->handle; + stageInfo->pName = tmp->entryName; + stageInfo->stage = tmp->stage; } - createInfo.stageCount = stagesCount; + createInfo.stageCount = info->shaderCount; createInfo.pStages = shaderStages; // shader groups @@ -9146,8 +9103,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( // Any hit shader if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - Shader* shader = (Shader*)info->shaders[tmp->anyHitShaderIndex]; - group->anyHitShader = shader->entries[tmp->anyHitEntryIndex].tmpIndex; + group->anyHitShader = tmp->anyHitShaderIndex; } else { group->anyHitShader = VK_SHADER_UNUSED_KHR; @@ -9155,8 +9111,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( // Closest hit shader if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - Shader* shader = (Shader*)info->shaders[tmp->closestHitShaderIndex]; - group->closestHitShader = shader->entries[tmp->closestHitEntryIndex].tmpIndex; + group->closestHitShader = tmp->closestHitShaderIndex; } else { group->closestHitShader = VK_SHADER_UNUSED_KHR; @@ -9164,8 +9119,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( // General shader if (tmp->generalShaderIndex != PAL_UNUSED_SHADER_INDEX) { - Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; - group->generalShader = shader->entries[tmp->generalEntryIndex].tmpIndex; + group->generalShader = tmp->generalShaderIndex; } else { group->generalShader = VK_SHADER_UNUSED_KHR; @@ -9173,16 +9127,13 @@ PalResult PAL_CALL createRayTracingPipelineVk( // IntersectionShader shader if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { - Shader* shader = (Shader*)info->shaders[tmp->intersectionShaderIndex]; - group->intersectionShader = shader->entries[tmp->intersectionEntryIndex].tmpIndex; + group->intersectionShader = tmp->intersectionShaderIndex; } else { group->intersectionShader = VK_SHADER_UNUSED_KHR; } } - createInfo.stageCount = info->shaderCount; - createInfo.pStages = shaderStages; createInfo.pGroups = groups; createInfo.groupCount = info->shaderGroupCount; createInfo.maxPipelineRayRecursionDepth = info->maxRecursionDepth; diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index c28ae9ce..90dcf2c9 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -1,7 +1,6 @@ #include "pal/pal_graphics.h" #include "tests.h" -#include "shaders.h" #define BUFFER_SIZE 400 @@ -185,10 +184,10 @@ bool computeTest() PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - source = "graphics/shaders/bin/compute.spv"; + source = "graphics/shaders/bin/spirv/compute.spv"; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - source = "graphics/shaders/bin/compute.dxil"; + source = "graphics/shaders/bin/dxil/compute.dxil"; } // read file @@ -205,16 +204,10 @@ bool computeTest() readFile(source, bytecode, &bytecodeSize); - // describe how many entries are in the shader bytecode - // We only have one entry for the compute shader. - PalShaderEntry computeEntry = {0}; - computeEntry.entryName = "computeMain"; - computeEntry.stage = PAL_SHADER_STAGE_COMPUTE; - shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.entryCount = 1; - shaderCreateInfo.entries = &computeEntry; + shaderCreateInfo.entryName = "main"; + shaderCreateInfo.stage = PAL_SHADER_STAGE_COMPUTE; result = palCreateShader(device, &shaderCreateInfo, &shader); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 914d6d43..210a631e 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -3,7 +3,6 @@ #include "pal/pal_video.h" #include "pal/pal_system.h" #include "tests.h" -#include "shaders.h" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 @@ -41,8 +40,7 @@ bool meshTest() PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; - PalShader* meshShader = nullptr; - PalShader* fragmentShader = nullptr; + PalShader* shaders[2]; PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); @@ -397,87 +395,54 @@ bool meshTest() } // create shaders - Uint64 meshBytecodeSize = 0; - Uint64 fragBytecodeSize = 0; - void* meshBytecode = nullptr; - void* fragBytecode = nullptr; - const char* meshSource = nullptr; - const char* fragSource = nullptr; - - PalShaderCreateInfo meshShaderCreateInfo = {0}; - PalShaderCreateInfo fragShaderCreateInfo = {0}; + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + const char* sources[2]; + PalShaderStage tmpShaderStages[2]; + + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - meshSource = "graphics/shaders/bin/triangle_vert.spv"; - fragSource = "graphics/shaders/bin/triangle_frag.spv"; + sources[0] = "graphics/shaders/bin/spirv/mesh.spv"; + sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - meshSource = "graphics/shaders/bin/triangle_vert.dxil"; - fragSource = "graphics/shaders/bin/triangle_frag.dxil"; + sources[0] = "graphics/shaders/bin/dxil/mesh.dxil"; + sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; } - // read file - if (!readFile(meshSource, nullptr, &meshBytecodeSize)) { - palLog(nullptr, "Failed to read shader file"); - return false; - } + tmpShaderStages[0] = PAL_SHADER_STAGE_MESH; + tmpShaderStages[1] = PAL_SHADER_STAGE_FRAGMENT; - if (!readFile(fragSource, nullptr, &fragBytecodeSize)) { - palLog(nullptr, "Failed to read shader file"); - return false; - } - - meshBytecode = palAllocate(nullptr, meshBytecodeSize, 0); - if (!meshBytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - fragBytecode = palAllocate(nullptr, fragBytecodeSize, 0); - if (!fragBytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - readFile(meshSource, meshBytecode, &meshBytecodeSize); - readFile(fragSource, fragBytecode, &fragBytecodeSize); - - // describe how many entries are in the shader bytecode - // For simplicity, we dont use one shader bytecode for all the shaders - PalShaderEntry meshEntry = {0}; - meshEntry.entryName = "meshMain"; - meshEntry.stage = PAL_SHADER_STAGE_MESH; + for (int i = 0; i < 2; i++) { + // read file + if (!readFile(sources[i], nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } - PalShaderEntry fragmentEntry = {0}; - fragmentEntry.entryName = "fragMain"; - fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } - meshShaderCreateInfo.bytecode = meshBytecode; - meshShaderCreateInfo.bytecodeSize = meshBytecodeSize; - meshShaderCreateInfo.entries = &meshEntry; - meshShaderCreateInfo.entryCount = 1; + readFile(sources[i], bytecode, &bytecodeSize); - fragShaderCreateInfo.bytecode = fragBytecode; - fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; - fragShaderCreateInfo.entries = &fragmentEntry; - fragShaderCreateInfo.entryCount = 1; + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.entryName = "main"; + shaderCreateInfo.stage = tmpShaderStages[i]; - result = palCreateShader(device, &meshShaderCreateInfo, &meshShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create mesh shader: %s", error); - return false; - } + result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create shader: %s", error); + return false; + } - result = palCreateShader(device, &fragShaderCreateInfo, &fragmentShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fragment shader: %s", error); - return false; + palFree(nullptr, bytecode); } - palFree(nullptr, meshBytecode); - palFree(nullptr, fragBytecode); - // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); @@ -507,9 +472,6 @@ bool meshTest() pipelineCreateInfo.colorBlendAttachmentCount = 1; // shaders - PalShader* shaders[2]; - shaders[0] = meshShader; - shaders[1] = fragmentShader; pipelineCreateInfo.shaderCount = 2; pipelineCreateInfo.shaders = shaders; @@ -524,8 +486,9 @@ bool meshTest() return false; } - palDestroyShader(meshShader); - palDestroyShader(fragmentShader); + for (int i = 0; i < 2; i++) { + palDestroyShader(shaders[i]); + } // main loop Uint32 currentFrame = 0; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 22fba4b0..a0f44d7a 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -1,7 +1,6 @@ #include "pal/pal_graphics.h" #include "tests.h" -#include "shaders.h" #define BUFFER_SIZE 400 @@ -21,7 +20,8 @@ bool rayTracingTest() PalQueue* queue = nullptr; PalCommandPool* cmdPool = nullptr; PalCommandBuffer* cmdBuffer; - PalShader* rayTracingShader = nullptr; + + PalShader* shaders[3]; PalBuffer* buffer = nullptr; PalBuffer* stagingBuffer = nullptr; @@ -54,7 +54,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -198,58 +198,57 @@ bool rayTracingTest() return false; } - // create ray tracing shader + // create ray tracing shaders Uint64 bytecodeSize = 0; - void* bytecode = 0; - const char* source = nullptr; + void* bytecode = nullptr; + const char* sources[3]; + PalShaderStage tmpShaderStages[3]; PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - source = "graphics/shaders/bin/ray_tracing.spv"; + sources[0] = "graphics/shaders/bin/spirv/raygen.spv"; + sources[1] = "graphics/shaders/bin/spirv/miss.spv"; + sources[2] = "graphics/shaders/bin/spirv/closest_hit.spv"; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - source = "graphics/shaders/bin/ray_tracing.dxil"; + sources[0] = "graphics/shaders/bin/dxil/raygen.dxil"; + sources[1] = "graphics/shaders/bin/dxil/miss.dxil"; + sources[2] = "graphics/shaders/bin/dxil/closest_hit.dxil"; } - // read file - if (!readFile(source, nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to read shader file"); - return false; - } + tmpShaderStages[0] = PAL_SHADER_STAGE_RAYGEN; + tmpShaderStages[1] = PAL_SHADER_STAGE_MISS; + tmpShaderStages[2] = PAL_SHADER_STAGE_CLOSEST_HIT; - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - readFile(source, bytecode, &bytecodeSize); - - // describe how many entries are in the shader bytecode - // For simplicity, we dont use one shader bytecode for all the shaders - PalShaderEntry shaderEntries[3]; - shaderEntries[0].entryName = "raygenMain"; - shaderEntries[0].stage = PAL_SHADER_STAGE_RAYGEN; + for (int i = 0; i < 3; i++) { + // read file + if (!readFile(sources[i], nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } - shaderEntries[1].entryName = "closestHitMain"; - shaderEntries[1].stage = PAL_SHADER_STAGE_CLOSEST_HIT; + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } - shaderEntries[2].entryName = "missMain"; - shaderEntries[2].stage = PAL_SHADER_STAGE_MISS; + readFile(sources[i], bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.entries = shaderEntries; - shaderCreateInfo.entryCount = 3; + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.entryName = "main"; + shaderCreateInfo.stage = tmpShaderStages[i]; - result = palCreateShader(device, &shaderCreateInfo, &rayTracingShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create ray tracing shader: %s", error); - return false; - } + result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create shader: %s", error); + return false; + } - palFree(nullptr, bytecode); + palFree(nullptr, bytecode); + } Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader PalBufferCreateInfo bufferCreateInfo = {0}; @@ -774,34 +773,31 @@ bool rayTracingTest() PalRayTracingShaderGroupCreateInfo shaderGroupCreateInfos[3] = {0}; shaderGroupCreateInfos[0].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; - shaderGroupCreateInfos[0].generalShaderIndex = 0; // must match ray tracing shader index + shaderGroupCreateInfos[0].generalShaderIndex = 0; shaderGroupCreateInfos[0].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; - shaderGroupCreateInfos[0].generalEntryIndex = 0; // First shader entry shaderGroupCreateInfos[1].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; - shaderGroupCreateInfos[1].generalShaderIndex = 0; // must match ray tracing shader index + shaderGroupCreateInfos[1].generalShaderIndex = 1; shaderGroupCreateInfos[1].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; - shaderGroupCreateInfos[1].generalEntryIndex = 1; // Second shader entry shaderGroupCreateInfos[2].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT; - shaderGroupCreateInfos[2].closestHitShaderIndex = 0; // must match ray tracing shader index + shaderGroupCreateInfos[2].closestHitShaderIndex = 2; shaderGroupCreateInfos[2].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[2].generalShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[2].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; - shaderGroupCreateInfos[2].closestHitEntryIndex = 2; // Third shader entry // create a ray tracing pipeline PalRayTracingPipelineCreateInfo pipelineCreateInfo = {0}; pipelineCreateInfo.maxRecursionDepth = 1; pipelineCreateInfo.pipelineLayout = pipelineLayout; - pipelineCreateInfo.shaderCount = 1; + pipelineCreateInfo.shaderCount = 3; pipelineCreateInfo.shaderGroupCount = 3; pipelineCreateInfo.shaderGroups = shaderGroupCreateInfos; - pipelineCreateInfo.shaders = &rayTracingShader; + pipelineCreateInfo.shaders = shaders; result = palCreateRayTracingPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { @@ -810,6 +806,10 @@ bool rayTracingTest() return false; } + for (int i = 0; i < 3; i++) { + palDestroyShader(shaders[i]); + } + // create shader binding table PalShaderBindingTableCreateInfo sbtCreateInfo = {0}; sbtCreateInfo.rayTracingPipeline = pipeline; @@ -1052,7 +1052,6 @@ bool rayTracingTest() palFreeMemory(device, tlasBufferMemory); palFreeMemory(device, scratchBufferMemory); - palDestroyShader(rayTracingShader); palFreeCommandBuffer(cmdBuffer); palDestroyCommandPool(cmdPool); palDestroyQueue(queue); diff --git a/tests/graphics/shaders.h b/tests/graphics/shaders.h deleted file mode 100644 index 3f2ff2d6..00000000 --- a/tests/graphics/shaders.h +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/tests/graphics/shaders/bin/compute.dxil b/tests/graphics/shaders/bin/compute.dxil deleted file mode 100644 index afe9aae521c3bc002c59efd11760e27ba16d22dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3464 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 X6bQ3;#*qF?`U#rzX_DClk^%HDv)oNP literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/mesh.dxil b/tests/graphics/shaders/bin/dxil/mesh.dxil new file mode 100644 index 0000000000000000000000000000000000000000..089e25fc2d0d5c1c56d70aa3fed2d6aa1142af49 GIT binary patch literal 3276 zcmeHJeM}qY8Gr3N?o2r!2lj#q2A!cnMi6>2)RfSThoc8bf z$NuOmJ@3c!d!FZgp7*``-5Flf>3_Xk{Q0TB{lotGxKn!MmG)oq006TD05}}gP|Q&F zK^cc)fM5{@fDuYMkCvwnOialLWFnB4=}n5S-x>`=#&jZ%p_ zBigC;Lx!~j$y2!oz)Og=U=sTbuy?J<35he)%)vl%{;ofw`m^cs&NQb&{+n*OH&=dv zpIhix$h~RK+`gP6v3qQXXZZ{0w-qr5tN5a+9dtNL?>b$5HRXI^HP7Gt=Vn*)CI5tr zr!DBcbgADz@$Qi6E`^G`t`JR3V>UWp;2F{~#0!m%EX)g6{6XFlBe^{+vnmPCf|)wo zppORYQ>q;g6o;NAJyZ5n^?bXg)H1(Kc0V~P2qe3CKcfQmZbmBd^6t{syPea){11n* z+c!$L#NGuFs{dk;SZ;mw?^a>YN7|)ZLL|x)d1ZGQBFtzdXObrekIJX4M8ru1ggVKY ziB6q=95Be1h9*a=1LoPkqo?iLmv@zEC1-``)(ft!m$g4pD#w&PrNfG{(E_dI1o7$g z6?0SZS96WKHKnq!V<_do)xy)g>5?}i(S2+4laZO#vn!FAr2*8qO`*;hRo@t<%dVG= zGNaeZuHP)s*7{(C;@>|m_8&c29Jq3HcXSa(DR7)WecRJf?Kt1tn;z0;DAYYe*MC|z zs~zRcM)@^O&7&!jdn zsSl!L)Iyd}Q`svr>5?pa(w1|W@mJjPRLtwkuOaGN9<>*#n2n0ttoYmYcv-!#1@=y# zJ?OJr@isZ$_B;uOeaq>4UEph$_*z1~_K>US>nQp4J@VN&`ItfWNBX6!{nFW3zigAv z$fQ%Q>=_&Om!Q5pqAw4{`Ws=@8NI3tsW=mU32yqGyJ8Wk7z_s@GW@t5X`y@$JHpmt z_1Po7w?4o-LN4{HGqp*R`sF+sh3C~w1CR#CEtIh5U+PyT=+jF?m&T|JvdfPR=6qSU z{N>8Usq(rKQ~qE~Sz4agkPK32b)alH|s2o33Ty&1K&M)Ag6o&DV0KL77_w<(&D zc_=){a^7+HO<+0jcmKtK2cbUBf$#mufj=w<#xLiG;lOhep4{_P?$^or!`*U^4leos z9KzPAm3AZhO&OBc!%{1D8MUTUlFpxUjOEFQ_Vk>?d@= z{{0yHVF%sJi&@^8F9ubqV$&U_d~tgJL;oYwuiREc)_XFK+>|xo8dVCGKC%Io)y>GW zI&G4CL0F-cgoM*LW}~oAunCbzm~^LgTvBH{aP^48lvfCOCmnqiGT7sp)it>B0BR6H z_8Mc9V~U#vt{O;Mhsf=L%jPSOPF)T(?sl@IHB?4zho5x}4>|ndOJ8Py1FD zmLIMSpa*{Btp5YfveEF{0iRb9sx4yw#gd_v9@=hM;3sX@?B%!SfdeQla6d1r0&ZIH z{iK8^aMR!MKputzx3$lTeG`z#fxyk{mWf9Mi(M|hla|n#x|*GuQwiWA#R29xzzF(R zj)$G=!2#wtzzF*3rpJls=H?eE4lu_7Mg(^_9t?L64luU~WQ-7rbX#hYv(uI3GNz{>Xk>CKFI$&0bbfL!%ZdM$Ct>Z=ZKKir8 WZ&v1E$?%pm^?%w~DPsTX0Qe8`2GjKb literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/miss.dxil b/tests/graphics/shaders/bin/dxil/miss.dxil new file mode 100644 index 0000000000000000000000000000000000000000..ff11be7122e3a52d8778327bea46f70e1a4e84db GIT binary patch literal 2576 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 literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/texture_frag.dxil b/tests/graphics/shaders/bin/dxil/texture_frag.dxil new file mode 100644 index 0000000000000000000000000000000000000000..8f83ca909778347761a106c79f518a6e8f56f742 GIT binary patch literal 3820 zcmeHKYgAL&6+X!g_ufEqb0HbM5MXY2ReaR&kcWhsJOE*U8ib+R;xa)&SOpA^VF0IV zF4_Mn|Wp)IvpcT2!izgPmEcJvXAmxaOC?`oq1l z&)#Q$JA0qI?>T2D2`iPVlue0MnGZg$CW6*QoH=u!W&r>u2>>uCWsuV#AAvjtc?5zn zH~?9YGm}!JP`sp+%w=I3IAcS8VNaexnV86oE|`&w$eN`yxXW+GF*AFOdP8|(Md5}L zkd?SnwS4)C1jcdb8EIFvDve~SJKiLtX; z%;(4CJ~L&WkAnOv4ol{u7x`zVu6i&!$qX+aq*z;6@{ z8G<N>l&nOTagEEE6@v~P!tO<0+d#w?o2C4+XQs{59N2Y?mYJdCt!okECV zhQJ2J04D_{!(+Fx%)DSX+}oeCC08#>WGlCMDBH)0S>hy!(bgV-Pz0uO+qtZp_q3hwvIBT#pLV`zIlpK5xQ7f%P4OHZU;z#e#|oo zjT$ALhQrkXP)`G(f-*cHnM<$R#Ays@H^bq!xz#4}O51GpFt?|X1%V(Ki1NV%-mUo^ z2t7-iMaun@o?L;pw$z^gxYJ_$e!DF@_tBP{N&VDXa{jlxo$qP|l4lYp&%zC;P^#% zf?e-S=dgiLRMu^&&{(1hEY$@F)cJo_6U9!V297{bBgM+>SUHUq+lbN^O4SRcRD&@N zPW0i%7mPQ0bz5$LXWW|0rfP>9wyVoI1W0vMo@lJl9CQoP{x$5vP|P%!h6qo-(OLycIA92UgdqW352R@?*{xb z>f7v}MQ2Av2ixa2jCDEh^lW$Q>N<6K6H|u^>DGHIF2l^}T-bb=cg^&o2wd;$81u~+vEu7gG3Gw2Qjb+v zVdc%Gya^zgIAYiH8t)hU2YB{7{v(LWga{vFc=tPKVX# zkjg5Hj<$FYc@mR0=Cqbb1-GY&DK!y6I{a=)e1|1|y;}c#X?@&DQ=C&3djyf4G|9|J z+|ZP$QiE+Qz@iH*WpLD6bT*4lgH_JMDyQ9G*bnuVHMpgevXnJjs+$c9A50MsMu~5_ ziAgDvJJ9Mo-s(H#8b`FggA!kd!EaEDer1DqjViX;H6HJaX;Q`1A#qK8i(%65jd53z zxXwPFLxO#zLu%$(D)koc%PL}e6dk9DyQAn+l6VB~9Gl>wTJQwctCR-73(6##zw@E& zH0jx$V3tQLG`pqs-HH4CnV4=mO0eWvfALKanREK_v{$#xV{GoRV)ixNvx~P=8-Dt_@H*WADJe8k53Ubr047TZaa=D+_JQ55C5h- zC2&D`TZU{c$e~sMb?99pMAacptblt zTa%=(ykSAh#!nl?3tC#d)E_Y4y)yV<+ra*Nz4r$9bF%%yWjn*8mv+fIjzvbF=n7Sc z-}He0mmZ*{0hkZZfRLkD$Q%nd$WM|$T~jYle(o*hSVkzzCj#06Q7$lQK;b5ncA!qd z*3*={#WQbJc&-i5IC^${k&oF*1p(Y>V4>Ktx6ak|AkZiB?+Tt$E%N=NsEx~#?xs0y iT$6OSocBDMzKJD5wK~t)v(6u38t!b&=EnR30pNe?exyYJ literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/texture_vert.dxil b/tests/graphics/shaders/bin/dxil/texture_vert.dxil new file mode 100644 index 0000000000000000000000000000000000000000..fff537a1e2b8f0689f5a4ca00e56003087bca66e GIT binary patch literal 3104 zcmeHJeNa=`6@STl_3C;@$8&`@U(gaG<$rngWTp|gUwlbTr;G$z?bAI=nymR0Cy{D~LYj`ie!)>-vSl@p9`+dUAqvaF`f(Ql#p+L*QFn}=* z1{VaLfw4dX8VpmFPK*J6N_3`OCHujG3P#FboeBaCuiJ3S0PDTa#mU;KxUt5hGwW(z zhRl`qnwpwgEr`{C8Wy1cU5&(E5F;fssS>k!gH4uB;K22fV%qnL@rdi-(St|q8_PgO z(?0PX5HACR#6K^82SWO(RPy)FBG|CpO4|Q=AzxgP&3e#ILQ*yG4K@W*Cwi7n0)S8` z$#rr??$N?90zvF`MMeDd>LLM(QC2>>d8N$iX%E2E-CM)_!$Lh7;g*mR-+rQq^kQf)P7vTDZ{w>bcs4x z9p(_4s^B{iPoiF`W`(ozW{j%6p3poDpfP+OSg zOd0Jd!)ZZDz&!0Y8(?ipw9|qfou@71Xj>9#VSx-un$4w%x+S9TOp1_q`+@D1 zh>%}S;4ut=+}8oV1N81ypmShDxQfc2DIsEfjpwBP{fu+l^^_jx4X4L>v1iIdQEiJ} zyg1S`bz(xdh$C#IF+$)oG%F#+5Y?33?p1R5-LS9_qmEM+#Q2AkLW`8)yKTTvy{1_W zw`AyD`P8-2LG9qPrBan>fUcf6j0NfHDFcqZ>T@*kUr?VO>&+?hP6v&ftW1SMmu0J` z*+ySFG)_zZglOUqZTtR?v8&fge|$xDm9GA|0Z)I;s}%7484PKWR@QM>b{yG6s@jda?{VUT8E3-=%kjh+%e5m}2 zcv5ohf^1Uq!)=t>9>zyq#hI6j;y0i46^DwS+_c$u&)*?4=(qnwpBEhk?Tlv2Uk6!c z?|ruPbol=5d!H>|K$_>f7#}sSymzbbvcYcOJx<={i8CR2bSLH(%sdnv;7}AnO_@Iy zQoGTPcGMMdGM1stCphbwo3)dn-ZDLvduv2+K%AC<`S^3NBCb({V8vW}=%@odhM^tR z0fz(abii%x0S6J_&1JDx!mNklOuIPq(JE`z$l8g|3TAh}5e_&kXqyOa`(qkN`-VI43Knp31FexjN5oU~ z`6}!42duU0tQ9fb7#|TVjR@uv^F6CzRw$V9>6Pz#C&|XT&34a%b9=nUCjLtDs*_0&oz} zFNm2#zmxy%*N|^PerIX(RU7rL<4?C9=})q=L|;`TJP-mCOaM(twaQe@S+{w|j=y)P zVR&Nnx1AsV)%xZQlJB;rCHYSW9=whG#{m8m|0%!ZzyBTot)C50{|W!$&+}hzqsaGk z_@$mKcb>?n9?s1u2`Rx>N8+tc^4}hi_`l}ALQFfM;xf|PTx?`|K}^s~RP|?=QxX*p zWs@&#?eN(P{bT)S&lF;n62N>+N{LEzicWPN#zlu>YPoT1WlXExl=W`jrIGKwxNVgA zp+j|o!~7Vp<0Bc5B+YASYto^rp+783Ria3O`LHIR@^wI%K4}lXEbpnbD3(@vyVRgD z+wiZ87sO3g=&&ef7Xunj=SLf&`kZfmm;b8)VocrrY2!BvWn`uT;&k}owS}&U#lahU z=%KGQwHLcutWC|WdyX_UA2xZct^+?bLFW zOjdxyU-H!dlc%f%1Qmk&l#Qs0$Zsz|J&?ITSqdA|yOcYtATJSoGavZ!X>`bIu^4@v zulzKqqPht#cT?Oef*Q=Gwa5;v_uY eWgavo;gnWk-Cb@99;{Q$q~MKpvu;or$UgvQ#eGHq literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/triangle_frag.dxil b/tests/graphics/shaders/bin/dxil/triangle_frag.dxil new file mode 100644 index 0000000000000000000000000000000000000000..6759c8c822c623dac3d0d1b35e9856eb5bc7d48c GIT binary patch literal 2964 zcmeHJeN0=|6~Fd-@q5Ph1~h#0w;-4AKOJD(Ya1l(K$^uS5=|8CY}!LNX``B^66iM5;`h*4<~DD66Xd zF=_j&M?UwQd(Q8kd*3RfI+E-Y=Arf zc@1(8bT)FJA97)Kt^$X)P0B5NBc&8h*pN5vIbkOg6A9~)VabT17j(wY;3C6-!r~(Z zC+m*aA3s?Gbo&hZ4nW^NxW}F_ZgUSgoHL|>{QW&(j3QI*&noMoub{A4aSh5e$Uj8i zL1OG|7W4aeVsf!bd`1Z!sM>VACU|DXL^4B|SU`^;Xy|zu6N{w>2$PsFK|i^9)=e8D znSB`;TpG+_VG&(41t&&0-vgccl3W7=V)ptF+O@jj`!aZ-ozTX!Q^B=D=)-J@XK6p0 z%OREN?JOrhX$u|`kDe*Fl38qRJ5TE*m7+9UoEM?gx^uiDN|)`v0%DZf2RVc{Dq*~U z-f#0PIUcs5vTV+NF#xdKK;l_sQiN&PR|U>>Mnx#*yt&ZNoLOi$YAGmN;lPwonSgVt ziqoht;j$AB%g$b}DB9rm@SIKqsYnD#pe@Fl&Q^3LYT8otMfzesbt!h#W-Ws2g`(PF zSH01ts&X||Ay60mu7IeXBAVd{BAXRhZ4XvQVbxy3vZ*v~Di$Ng0H!#PUVt@dux2Ax zKgC%gv4#-RNWcgoRv3)NkU7PI6nO8Kwb<>>qEa)%a9?d;yTJQ}{dRt*(=Wtw3Aj=;6C zh{2o97LKP-V-lV1T;3me@9oTEwOVdlY?l7k5gUu%(beDI+d6V~Fn5kbg=l#vMUHb! zlnO^_R!xmvBa*ZrvSge+z?xN%pZ#8DRPh}F1G%+Ix9+Xt<<%`KE1zz8s_Mw@_;y7_ z%Y9t!;0fH#)s7g*wqs-39O1#kj;vB}ruXH(m;1TeB?E~cwQHmj=dbP#@aO6e&Km`X zZqUQ(|}oMRrX6>Dn5>N+j_6%hG1lGv~kyZPGq(UG`2z0zZfEkT$=GKpmR zb(tO{bF$G>Z^qunv8EiC*^D)tk%mT>nR3NUMiFaXVo4EMqljEyC)Nvy-Q;-OeVKGt z7B^~&Kc;BS_}Gy#rAxn#s6Te7ok+&yx~Rd3yah3Z&fMD}B%_oeYi(Ch3GsI&O=bFme9u)usD& z>7Bvx!?84%~m-1C0&y`H!DLeJa#W6%5F^}KLx zp!knHkGTtfsOPnn%NyckR=j`zwLf!2N|}JWB~Xoq&}>%g@73ccR3NwOu~m ziANYyHpVx$@1^AzxoivUbQKP3rR4mGUH&Mx&lXVOU)-vg`1;H%hR4@DHTHru$<|8_ zb!%+0J)lDW+G0Zxqi#CQ1i-=B*|qu7fPZ3PwGX9VQmVIoq#PQ$o_b>kYud^G)6G{s zpMPMedDA!}8>_pZ<0bAq_w(k&okzQ(x1aK_m#zgS9=H4ZR!3JS`p~>MrMg3z`udRi z>Ww|Ae;nFD!%Tr6d(;21H<>5^;$hB(D7}lhoDs@q9_TfAd$lbcB9dtM`dGf znr)@T;v!iVJEhzUD4dgBX*h7eBi;^hyUi3gGb0YcttFhSl<^RpI#2JvsR+T{l?5{i PAvmi%M)VL3{iFRCNvU(F literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/triangle_vert.dxil b/tests/graphics/shaders/bin/dxil/triangle_vert.dxil new file mode 100644 index 0000000000000000000000000000000000000000..31548d572a0e4c0e5b3770d5f8beb4942f4f4c3d GIT binary patch literal 3144 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 Kn+=o}=)VAd%@Py< diff --git a/tests/graphics/shaders/bin/ray_tracing.spv b/tests/graphics/shaders/bin/ray_tracing.spv deleted file mode 100644 index e2158940853ac5759595d04c3f9dbbb95e2a32ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2740 zcmZvcYj2cQ5XT?7Y;V-oLIH1JO94e{MFm6=Ji5Psr zD_{9Jj2}UbMn8jzehcF*Mt{F&pOH=VG}D>+&z%1=Gv}Pmb&dBV`E5y(3?>!+yM~jl z7FTM8*2??MQmsYaR=iOw6w4dy$qw>moSk2qpR6}lCy$>v zChuU9Q>C#Xvc4Wk_)?O>pRh2Im9^Lyr{@2vHI z$b9SBkGPCGivy{5#~2r^DZu?)&h&sxSAH7lO5cb0 z5qy{L#o0fCcE8^-eiUsDZ9JF03D42k1o}q~#CM|qDEjBj-$f^r_+v0VhSrw<7+QY& z)PEf947_jpPoRzK%lRbQn#IoG+lO~tOyBywuP%M-wRUR`U#{@2**9a|#;w^mY~A7e zzVs)E+uL!(dmH`rZU&$0@|P`Yhbe^l8L;uTYh< zIh|qRF6)lmGuZYLxzAvWDK2w2$?(0LMdbPGy)T1_+vm*;yM`@p|B?3!w)i+ApLgO_ z#2LE+dktGG`Zw?O4C_KK(3`&rZy@eB-?(?>o9z47vHjjb?^oR*m7BW zaIIknmvOno+#g))*mC8N;CdTduER)hm9c}%xLjiH?>u+U|1Y{cg~abzFPJNS$KJtq Ze;?Z4ysi2DV6Mo27u)y5S-?(wW*b0(QCw`5R6mQ|ffE3z9(q4M159hJZ;B$Bp zoJlR%{a9vacXqPGwl3>%Yw*#)F?JEa!X^Nk@GyCtrsL65TAFpbD$VOGf1}nzjnX)o zB++t}Mcv+wHruc(1IxG%+8XPfgK8v`e$e|`q(&5YVfjwMK{_nZeY4_c% z=Y`1z#k?pND0Jdm;0jE_I@~E(^&U#4p~Z{@ov!w|ZCP(l(ijJ@+g2 l@o>$l_F7D7)ED-7vF^~#3VrLF9hZ1dCV%bx@UPu6e*tQfBvSwY literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/spirv/compute.spv b/tests/graphics/shaders/bin/spirv/compute.spv new file mode 100644 index 0000000000000000000000000000000000000000..6b369782f113f376998164b299dda8f88aaa839a GIT binary patch literal 1704 zcmZ9L+fGwa5QaC@Rul!1lP9o%XB1HZQ3N@dR1y+Qd;n8vp*yK9vAfEp7e0(vK7{XN zJR~N5-|k-8u$sxt{B!#Etkqoa%*iO~iTb0yXe;WRp{N%m0xP7twDWpru9Z~g78d8t z7>IIdqB(=)z?nWK9YeZ$F<(Os7(c8XYBG1iy%IjFxW z)thh2_3g%o=3Y68n~m)k#J8o2}M`^4OJx1@glf!nh+1}r;T9Wn__Z-GY)jA~d{GQ-9 zyAn%$se9>1t{^35$wHgP))?JJQoJ)`6kFe2O=df_UNPp}akOvD-8)y`I~Vi2{N^Ge z59jM&LOj-AMw@HTz;7D6JO6s-Pr%Q+arPv(ccE{eWwg5zlZU?dA{OSZWWM>&usa+( z_0O}Iy#tR8Y~RFP*tyqDL`;$65<9WK`|)@eKSBKe%E3ExhWpib*Zv3eSMlw67V(~T zLB$6$Ox)9htkKy%#y03~pYw>A{Oslah7oad+^hc!@4|hDoQVwoN{(-060uJF3w^|{ zBH}-oJB9ZACMI4)#QaX}z{mfCeB4Wzbq!lQ@VS94AMZ2d+{6|Sd~RV|C;p2WVV3$k z8gA-BW!zj-_ZiT_@}IH5!+gE@7ebu7WVTLTg;xm*;Pa?zGZWKuWPAoP9gFguOq&F Q@7;R)uBW=QgJt&c7bi+&tpET3 literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/spirv/mesh.spv b/tests/graphics/shaders/bin/spirv/mesh.spv new file mode 100644 index 0000000000000000000000000000000000000000..311c2b399fe6af1b1f8c32016bf33a20e2948af6 GIT binary patch literal 1772 zcmZXT?M@Rx6o#jiwpbL3eEEU6h#x4mA_8JeBm_-0sY#O(;=iV$8`xyqnrne)EqoOx&FY<6t5;Bpx^=_cGWHykr=%zd46uITcv zQ9o+FdUx3D_|a)II&HQ6zGCw(qtI%tQL99Qc4cdOgUl(HjSIj{tKM(b7}vVf3c3&_ z*&P|dCDnkNkr8iJ5(<7z#%%r<)f$WaY>fYqpVbfSmy*X-uUh+0s>_KWr$8k2%rs^9&`td;FC|Bap(|t5C-pG2GO9^ zJ@!W&w*vPe3`ZO~xDVmzKtyotN63gZb5Cany|CAh@k*G8OuphL#C!znQ z+aBdrbswA!Ew7cunlU+?Mi}P+W41VQz|d+KYcTGws(&;s%NY2)Bm8&01^#a0U)4M- z71UgbUumdmUNL!Lo{X`c_yw)m!~6-Y$z4$H16D`D)JKR@(G@e8s4 zd9N%LXk3(0gFIs4(RM{MI*75o`8LpEx!1KOFP&?#H-vMS7R&n)$6mIN#d^Zn%VJlw zCN3Sz{jCZ^kKNyGt;qxD{_yFQbgjGcITL%@zP8U=3Omm|IF~~Wdf}mFdWk*IRM8AZ z?{IIAG{b?T37>uiBF(^2mWR+`b3uVLSRJ zc?a+<%*W#jv##=i9M?tDk|A-#sZPzD&iVlhiv6GKl}3>ZCOF*mg)hF-83 zFnYmaZfQ-7C$ktZdSG7)(Q{A6yBd$ryBdE#;n9Lt{IwLnp77{^$LD=5znt)%W_Wz7 e&pT|%He|Lx{-%t4_@^>>+aI5|`KzyGSN0EV9Cug% literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/spirv/miss.spv b/tests/graphics/shaders/bin/spirv/miss.spv new file mode 100644 index 0000000000000000000000000000000000000000..ead00b0a2c55011f0f31a9c344ccd577ab437df1 GIT binary patch literal 356 zcmY*V&1%A65FGPonn;VZ=+)ArC3t8{LGU8QLURyP#9R1KkU(lm>cvx^&YRERb9fP) zi7mAIG3?In>|}{;-PPgN5W+_T=V-#hcM}NUAsJ88x7SHpnoYVc%{*Hzsr68!bQC9X z^tE0@505=kw_a)S1O~S%=(b-t#W?`#)UX>UGJb4G6_OnRFqc c-Y=ebp}wmd74kl?<1!D(Nd2MFm6<+R|c*R2wJ=9xx3_TB0H8q^Sekh=Uhi z@jJZoH|UjK@C%&rXE+{a9DSZI-`3cjd1tNn-D|DAzJ17GW@0Gh2EvZ8E!+;hF%mN2 z%aIVahkRHreNeu*aJk&6+%0!Im1?84Mr=L|5L#SZUYy$K)~1dfKWgUAFqjl@ZWq}< zjD?WJzg=mxoEQdAfW6=}sDVL#8SEpHveYdumd{_m^1tOmj+y>C^2f+oZ``Rju{rXr zz1A!*RyJGJTNmc3p`N9W5H=e3>KOP?vi`qu%S}d$67(@>p+_OmoMRlkL^nLyq+ez_AZLgjF-P0N;jH z6V7kPI`55g-tQRz>ZeogcdJEi|MIF)?_2T?1$^6Xsv5zTu z?7=zX+^3^SoZp-cui;zA-s1c*eD~&;u}pXiYuqWUL+(Dvy(^BGcLx9Olv{5aw0A!^ z75kfohj4G+Gd_n`0IuV_d=5Cq*rj=_>z>EjpM85iD_Co1!G6xJf?WXz@NZ(}=2fwt zxtjgTy^Ctjf1dg)*c05{4Az>CLGU|D4r{LW&HoVlh}{2*$URHneLp|c$33gbE!?*s zfVOX-_`6W=^_dl^pkllbnrXKai;c=qbn@;$u`d`oiQ^I2e@k)F1AIli|UFbh0W`*+=Ufae*%(YI7g^%%1N_pJJ3F2L2lqs~0`U0|O2xAdxZ z5vc#hcfE&o{K=g9B2e=!>BqI+$G4xjpZ2o^)MHEu-+uaIF2U7fKbP^%Q~!fC;#%5Y zxykmo4D2rljJFSay^3|%t1(xAn!W1(#i{A5#h$L?Z|(a-H1!zs5&qVF{1{FBYr61T zKLO^c$GjW(*6!c`PvPqK)4Vdix$52{|1;FQC)TY4wRmq<@x2F^$REY70X0X|ZsDtW qN2AtAHUAS!?BfddGhn{)&L0M|tm^-06V$*Qum^inGsk^A3H||vpuPYA literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/spirv/texture_frag.spv b/tests/graphics/shaders/bin/spirv/texture_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..86381da9219568f6bbc1d046a4c5da0ca06054f1 GIT binary patch literal 676 zcmYk3J5K^Z6op6D1r+5W3ZjVt?TLjN6Qhj<4V^}7A`~X#8ld3!`KxS9{JsI=-sJ9` zbLQOFY*M%=g|HPWp&UA4WsOjP32?<22g9dff4&&^udXjuR6`PlYHFbrwu$<5^#19^ z4&K7+=;Ud@DWPfz-z255dA-=2x9lUE5mU5##KmM8wRO(((e#S|PGjxS^JMv$WwSBd zV4Z)a027NT0%*?Vz|5YH{nMYt~BCf^;!?$za6Ci+V9 zcWdm9aviqaC91c7-Zt18mGy;MYlz)TJ7J0{QC%%E{+E?b>^|Bl9S?}saLz-beci|0 zBceU!?ICt|xf|YEojYmH{sWT|?_sUEk2{mt{tevTFR1L>#MQ{Fu}>Sf$157&=NMNf O|3DYtN$!^^Zt*`FnjOdh literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/spirv/texture_vert.spv b/tests/graphics/shaders/bin/spirv/texture_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..e7d4e13b49a853e608276a90f5cd86367aae3873 GIT binary patch literal 1044 zcmYk4PfNo<5XINFY1OK=*0%nsn%bjKJg5kwA{FYP2SM>FMS}!lD{U09+{ z4#XCcdS)klIEZh;kAOOtW0rEAD15mL$8mq~5KM9?C-)jflbk1gXl8kO(B7X+OgUfN z+imdP84gE}wvMy)r?{^Aa2DoYsSh#BdB>q04(~Yjz@g7^#BkhKS8sG}%UEDvej1|( zOy7!B(6gzI^dYV(%FFw*y7ueCCz$?K;aPcK#@e%(uS>s%@Vq?x;kFf_&GjIM`Knux zciK-Z=6>Orvy{}OeVGF;$yn%GmS+x{=~tFV13dk}+y$J|Sy9ZQepQ|vJ;>uXWGsg_ z6ZCaX{gz_1aTf57#cm$hx15{b6lTVezB4+xLl%90#CY--dZVQ(LoXUnt)80YT}|EA zaJQ~zO)>nZ-LtM3?pjLG+K|x)p7U`g`f(oq1MZxAJ(DUh_4MXkyE4u|&bRniCpwn> E0mv9ZmjD0& literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/spirv/triangle_frag.spv b/tests/graphics/shaders/bin/spirv/triangle_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..4900c89b5811ef41686d1e343b2e1df161f79889 GIT binary patch literal 372 zcmYk1%MQU%5QaxfmAXd4PAc|dfk=dng-v&!pkX6H6Fi}(vXS_|(-J3{&it3T)c3|! zvyw#?TGR5^HBXF*3tZkM`($!|94E8+6i3T^XT;OCs+EF$Rv0@-UH-On2>l-Tb u7x1eBa|0ZDU0J98bTB*N7P^pq%;M4W5>ruLi)Cg*fqx^Fx!||Dmx>R=-4f;i literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/spirv/triangle_vert.spv b/tests/graphics/shaders/bin/spirv/triangle_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..15b7f9086461b6f401fe12f2e70c4619db37209b GIT binary patch literal 1140 zcmYk4T~E|d5QdMtln+5Z1q1;LD4LKEFVvVAB?OZ7f(r}@w`L;^X;OB{ZZ*am{B8a! zZ%lZewrBA))0uhaJ#*eOZM(HQ5yFEo9VWx8P_Kp10tsN_mG7LMpB@a$%Y!#>U(1*c z?TRR8E=*PN81L(D-ZOcGEn?5G9jwjM!vA4I62^G$xd~@XlV25I&$7WqHYl^7q@Xo! zY^^`c%e>zMov8SpUEz7JJkNh+@?y=is2vyi%}G8iyS;DOsHSpj--}{YOVFogSHh$A z?&!o?vv>J%+%NirI`>}PChxG{J9zGA_8YsRk61lZr+v?Jk34lnp0Sv7>hM<27UnWn z%m2Ar%R`&I3?LH-c$ez7egwZ$IR zv=rV9K5GBa=P;ML=JB4RX8SGR)gW#^b7vtIbuJORtnD>mly$18nQO8SS_sh4g4$pL^*8VZ6_t+iDB0|0Z literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/texture_frag.dxil b/tests/graphics/shaders/bin/texture_frag.dxil deleted file mode 100644 index b427ebef651b944fc8598b14b3a3cd2f3dfe39d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3824 zcmeHKeNa=`6~D;~?w`KDgBg4PilF9ea%Hf4BDwh+)*9f53w6<-vk+x-A`7-~p=Y~-B{mxm;1+=Sg>UM2 z)|J(#!kqU6-zHeu1i>2nE0Z{qMmEXBFjY*@?5Yl+drHJzqxS0PKUl z5E~Vks|dz0YwUj25HA-cK;-qPUlND2Fo`)bKGKz z);N!WaJhOqhj8zY8PKcptggxC>n*%h8Z-|s7Wl75vo#VXN{FW za2(`99Q#Znn?X%!`EYgsyiEZ>!(JYfBcMw5@D9fGFtC|oy4~V1ZHp^}>CuwrSP&1y zWx&t(7~TP^1}R3Y{++}^ZbrL1?H7O3>u`VD<}Nhd-FsDYPO^<${SDs!no$`2DB6dI zSZzO%WJ{#maP?4E>IPEWyk9*On@-AHN<8^gUwSW{KH|+d&G}I)@~V%{9HQ3`aaPS) zGh4msKCfa3S=oUo&eG{VL~7wg&T}O5)~K5*MGulO;(ggizv`jacUeZ_&?yfwDHGnC zKu_w4d8P0HCA>~yJs#|#o|sY!?@+?s24Z%Om{bZY09rqR878otj@B97C*r*R=|6&d zNm&Cw_GEQgd^#Q%h{UxXN4>$3YIZc45oj;_gPy4L5xZaugu7%|Z5LKYVU=#8X3=O| zG-?bO3-F;|ErB&Cv0VnN-iP{0tl=@zK)?)-k$xEJ!XTz{f`EAzG6X#I(IF~J0`19F=sAe$UkMgn;>{|5vtj3>EN|RdBX|gFLQpP$;k-VVOX9V1u3JJkbjt`$N`nw9IMVd|}XlYzgTp3{=OEd#|x(s7h=#@Qr%11+nhDA1L_=k{_&W#pAp z(VkSixlKpPchJ3|YY&Dfb_8#%o06A42zrp(u4#YhPgNxz5vaee;5!9sj*e_Gd)19A zC5%;qo0Kk&k~zWOar3L(7PC#CBjTyYs3U#h6-9RW{2+yo7-Y>x+-GQ3qUD~F;hDXw zwYPuos

|BAy8%Rnm$gXUhC2g%27?#DtF<=s8r1rdSXIZTv-zo|E*+xc{a#ziAt;LYn${t z%d6_^@@?riVO9CV!W$Y`IW6A9-VN-#X1OStZ;2R~j3^UxGM#if<8`SmSW_cb*HMG} zf$$bd+_w@7all;fzb#&%UB4ULX! z$`L*iO3b?1(^@4HPR$W>dLo$|i2O1-Vl+Ck-xyUUds}g~S>dDCpF}dwHfJ!1Vq{L- zV8GroV`*kbEo?20YPX}>fHfpy4f8=T?Jq5kH~EeliKDi|(bQp0x;;nSo**80h*=q8 z8tRUi?v5A7_nh@#c|GA#P7P4O9`==I_Q z(b(>4WLKi2!Qu$NOcV1H=rl##m_Q$r#9esjxP^E0!uxQ&YAATG!d^oyYrm865gF>q zVwA~AOpw-lUGeT;(>+wGFy+y?%Bx^q@kjUO!#o)wlgs~H$^CovqmQRH9u$QpreuCL z4Lu+ylw%iA%U~{6a#Z;_0bYZ4)p-4DlG`O)cE>Wtq-&A8S*~#}a8D0BtxLJ5aS8Wy zzTlo0-19u#6WD=)=DE3t{bu_7i58m$DvFK%Nsryzvmw; z9i9o9sa&&f&8gBBuWkCH|Xz&(O(z|Fpj|2VxdKJw*)nFhvfdDty4; zm0PU-8l#Nqo7mTfPR1e$Prj5zObmowgfO4MtM0Hiphwc`nRZmlO&OK7_N@TYmXK{o z@bUh^vMc@rnnJ%OEuMdZz1G_xbnge)RTFuI4hE&FBTO5n*o&Wse5C{sp48FiSlr$u}E%m1B#E@x0}Nm zmn07GZPu?NI}77tQ6Yr;8nLx}RbEBsW>*5wW44j51iatOUHcfxQKO{9(wF_6k$maM O8ozX;dWnJ)f$|@#1*o0? diff --git a/tests/graphics/shaders/bin/texture_frag.spv b/tests/graphics/shaders/bin/texture_frag.spv deleted file mode 100644 index 83aab1e4025792323f27ad9ce766832f15996d46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 756 zcmZXQOH0F05QWF4N$aZ*tE~@^w(hfVA%f^e#g!Da)b1o;3;|n9jH3VCjo|riQzCQql1oW?HwZl~p-EXHjw+rBj9_C9HaiIQI^EH)A0Y@8Gco>CBMIm-N=)j4wVEL?PbhveTE9=;GRQs z%o{Av!HaoYYOBIs<(^KwDVVpzcM)KsE5_RV=(zi0@mBQLi$1s`yrGH~n&8a>qYJ;L ziY|R{U6tMVuO;1vYEPY}D(3^8c_;MF^yMDxN`UcaHv)`4UU+~P`gok^Pc)ekczlb! xrFt$dcWNp5AB^X=5)da4{(M76Ft5xlTm66;iDMMUr_9rVPZQ&8dYr)5VY8_ff69q zW^98E^-?DRg(MpS+El3863EgK=!XCUb%11ykclOf!9v-GNXMp3%A{%AeFk?d+aJ@U z?XMpB-gE9bzkAMm=f3yzQ&h<01uvWxl#MOSu3ZwVMBgbpO#=W3m;hiQ0*vmH`^= z3E>KiXTw3^pO?Quq5O0@_4{Yx?JotC{@0uM@@|@|8=9(HN{w~qf7Br0mS8;^kOg`c zwx5qi+gtB1Ax^*hhM2Qlj{0lTEGc^Q{J&e3nWh08{vJ2rdCn4hG;oM_k zBAL6y%OT~(?rR`cB-<)sdn1!(G}7{R&!*$^ZX~f7E$0FNA0ZI$*`Qj9N$A5Y=PqS3 zNLUsqVVvq~wA~;hq3(hcb*7>uJd`}ufkY?0>x9!|=b)DprFMJ5olZ3&Oa`f-JJyy@ z7xpDfx-%6z#R(=k6gS;&Q^5VvoQ6qPlfji!>uRlKK$~?#!!|9k+u#f$+Jsoc0MG+Kg&)qqieCG@ukV9gS&&44v6q1y!3yoWTfVTL{AHVh455M$b4!#w*L0v>t) zmoEqaonn-r+8+>RD?tKy1_ANYY1CsXI^4&JjZ}L*q5PNU5cyCPmnP^G3EsXbK;FLq zZM#T-JRBu_I09^w5Z?-WcM|G2hT2<9k5;_RJiYUzl$kP@`f1S|T0ED!jUq+-PBr@J zPVqLsT2815x6v*k;+^fQB!Pr{I37wbujjIzeI!1K8hn!Ug-+WqgiKYIw4$FiC7->n zK6jmYBQ5>z_wbebx+wkf#rw#hhL6wQOeFbuNS2iJu%_QIRp50)M_wDj!;)os=h3H6 zQ;KdGV{di6KRgvDsCRfxmGAxVlY#Z^<=-r?ukrDsEUDo8p>%6Kks(|iAwJvE|8h4{ z$E~kGO+!asA3?(&k?tvOJvUDTayTj-3MP~8n$DTcb_toiy?pPJRX-nB$WCTF*?Ik( z*B+JZIqS()1);t9ciYGY?HWrwGy67CK1YJ?#Hm?M6XQRtT!dKiU^EuJO| zb{5B4OI#KU)@ETex40~%D|RuGz2jwX3M0(Ih{wC^T@5>nm`PYqs8!k<+>XB zT&;cW>0j)!zt~{^X_CDoWK{VFd0T_L#lXB~pU0nwy=h@I5UxfGgSr=k%i?#P8OGZB+QnP82(u*O^Ck8! z?3a}UfO-eMCS+auz4))c0*+Pj%2v#niT=Ry=X;NjU5t(t94!oZfT~ClZM_VZAv_=@ zQf&!m-#-404|GcO%|kUm`S`}|rM5zf^8_J#9H@dX-$4!}pg+ig(yuu1f5(CQX9LxL z!hyu|9N1MQaQt!LNLQpSN#KwTB!p*rB=F0FdRzkUTPf841qb$##4KtQ3Rdry68K4< zEoBBVT62&EL<)vid++?Lck^h+weiUIwkxV3Ra?Uql5+>LUk);Z3|8>*nNjJ$Ff05I zlJgu^bfjJ}+&$9S-~X;VC*2oPbUa%v*O`cP&qB|Gn3YGBaj!hQ`Un{`1lW)Cvgi*W zX|f)sm^a-1MU6FAjE`@4a*MpXLg;}?hZX>zeLzzlfW|bF^INGUKYa2b>6oA{? zt+AY5au05+EYTNE@4?BK<9d~F5AN^K^=kLvw1!0e18xxR))&qM;Z^#18!Qav@4m5; Az5oCK diff --git a/tests/graphics/shaders/bin/texture_vert.spv b/tests/graphics/shaders/bin/texture_vert.spv deleted file mode 100644 index 1a053ec4e0e6d4e3aa4d27f619e310ded6ede396..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 620 zcmYk2yH7%448;qV%S+`U4>yBhG+`trMj6x)2EBj`tPBh+m=GY2{@E-fo?p2i;Y)hk z)6<^zHp+GjW*IZ9SX*CS-Lh#WatvFw@;TlwH{0d!=VG-sRhm(ilf@oK?&l(6%R9eX z_x6iTZ=8IOW~1cG^Yolpq5E;{-f+=(wKriK|EVJ?C$d3g4KXD9e;dFGP`-=vuO zhEyu@52~oj6F;j4P4v+X7>$6@M4ucyny0&)^%bE*Ef3v;)N1lCs%36nhJL`eiqV>= pm)#pOYIq^nR7?)tu`a~_v}Dx6aWn4pDkXMEfGd={6s(H@8`1d;TWJ7*JS1g&=7B|HOQj3Ls2j5(4w&#$GpK zjAqtlU~p)xhI)hCFb^FQ^moIg%2=aiK+Ha_z_>y=bzj5D6ssB{ke(aS z$s79pEAEeuq9QfcAOHX!H^}raGbO^S*uPBmtTQG;G5f87d1lW%mq|fEJp?=E2xYmP zWa`iW%F8|Pf!za7D8SFq`ur&#kCv3?fqZaONSCpt!Mv)Yg(`z;KbJbY^?E;Tfa7`m z?kTUsF>PW`Qp=$I$^U=PyzqNlN16yYLmU}}sc{@)I+h7IPhy5xL^<}&Wd>ld0wZH*1pgl3_L5ZWpcrSC z%}RwzmJ{R))3pJAviR8*BgB(Drh&^Lx9ZUuB*>`-={99~|!ii%yQURb{a zaO_q@8&I=(s#mz3Yme%=+h+3LuAafvGx<>rtribzvA5UMQL#lyYDu5jRYhic`tMLA znsj9{ncdJXAUr{eGliMLRRy;O>AO;HZIRqKo_b9g(e7Nku)W}&W4A^Yw=CRi+}iZv z=sh%~6LY5D6j5SMQjuKpT55`@-e5`H+{G#w91D(}7jp)R|-PKN(Si`bIx1Vcs z7dQSHWBo0t{qfHm25y`=`F=fl^l(@~U*lto#m2~D2Pa|*uODMw4C!)Z0Bmlv+8uTt z$_^Etc78FfE|F6iTkUO!57-@<+@exsw+1QJxSwfncXsS-J7lps^sezu!m*c|UR`R0 zI~<`~6@w3(x6HKsNW3Rs^4Gx1{HjQhjou_E67GN3YEyw^}de5GG%DoegJlOf7)nVzj>)FMy z_RJYDJXge_vmz^5Eqqp`Pg&{-`xP|a+k@MKUEC;0dqfgXXrhR#$hm$k``u7hi!><) zb7#&Wm9xr9KTZ?M1M({C&FSdUa8dcc9)ZO+Ect#XtW7+;=J#R=51VgS}|``@0Y7PVmwt z#g(xL(4?~llPTsY0YD?yYxpq>0Ch%aU@Y^i^gQFxqlrbSlHs@~3C^qh7UwNJ#d!=L ze$ROc7W`jxUgB(^`j4CkUp?Q+c|*+-_v7(rhGY^?I-M&aKfJ{EKqv==Z&v16tAWmc z!FNH5oW{&j$<#abB8v|#G2VS4-diBkJxcWxx&ea{Uk5c>_ zkm*X$2pTd%rn_tw6>}nmaw?F@KGk8wQqG=#A&Ax9qYRlR zw*Pw98`8A1~2zL3-Lq$1?_J>Id;L{Q5#qgh3%K>c3iE? z9X*?JZpUaw!HaP8&83f5ACKSvVCm!N1Zw`Cm;Rr;WTpVff%lS!$_tnmGxL3>8jvEo zO@@4Ef;=o4xJ)Lk3KfNYayCr~1O`zxyRbO`C=RB!X!q^&3$_7{tKXcxupo%TX(Lu$ e7>UEFQ}TvsX&mme=oWJ0a8|RB{}CGhn*A3Us%d%v diff --git a/tests/graphics/shaders/bin/triangle_frag.spv b/tests/graphics/shaders/bin/triangle_frag.spv deleted file mode 100644 index 3cf2393e2358a0647a03c2d8ca528ccb28deae0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 376 zcmZXPy9>f#48&s}zVU&en<(y%B8V;yE{dQcZqh+ZmkLGw+g${I_f;o9NR!Lua;fi) zN@fK!YgnDHUfaBH$9Gt4)5;c*RbR6x-b6_%(jzq0;wz42RKA7e6J%&bHz3?i&z2D)|fNy?`t7+tnY? z&F|D5W*s({$wPKj$f{?|NFz`Em+(&`-w8_1iPMwr#dMWCXI6V_g!BvcN+bM6F(p0{ CK^K_- diff --git a/tests/graphics/shaders/bin/triangle_vert.dxil b/tests/graphics/shaders/bin/triangle_vert.dxil deleted file mode 100644 index f458f68ddb428ea755a7a4dcdcdffeebbfe3757c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3160 zcmeHJeN0=|6~Fc~e$QZ=N9++hcF-fi$cb3un6EI*}KRvZcsVb@K`~LpZAI$w~V0hN@`6nMz001T?04SVgP<2q> zfr`VxL#TJ@0DKA6ped1H&>xo)!wb7ia6yF{_iN)pI3qC|i5qZT@r^jSH%e{{MPF_x zF_x770I14!<$D1rhxMzW|9SPvym;AUGC3y3xB+J}PU7NmL)FXrgRKp14F{X!TL8VG zO0obkIWa7pz9#>ILe`*C$=}x{HMYzk=Wjgx`YSl<>}_@JWtN6!5<=D?1&129DL@&0 z&ctX0`YEbs??t*OK#d@@^_=LMq6P?jkmxhTa>$9SNkElDCBik=GoAfMG{50Cp8Yf;%RrV$+ zy||RS8{?HGN|oK(AeT^Sx<>$Cs$9{sgDG34^oj~sVA*s32rXShuiyay|29AnxJ$MX zl~YGq-Zj!h2)HdMfpM~@9Jg6X!1*v7$g`4e!5Bns7mc&!lot;7yhB0m23>a`$?MhO zlC3}lj_{oYR7q&7{Kzh~QC-C(hBr;RoI04#;o8UjZDxO-)!$)7pv`($&u&^^cft`Q zcS=zENwk$fn}Y0?xX~UrTFfX3SfKyuD=>!~?KGop3-kz%I@Xb9HmtCYjKI)I6k?k0 zvSFQAg{Vh0`0P>u;FHmDvi(tEcHjhnXAqScDuo3NX|Z_1-Gu0Z8Y)NqbLPR-M`g^6Y0<~U z({#&2y!PgG+K@RDEBD~JGV^3^62 z)-b&NCugw41G^qiJb69HSR91xZ^tb8he><<+_qyW3<&mo+7skr) zM5|j)2)w1tyet||_tJOhDjvSbYc$cDhPS_hd0d-3EGoZm!nd4_m{mjS9|Mqe?N;Pr zBok9B5A1lfdh}SMTQ1ItT)XnS$iqx*>b(gql50ZptVsUoWJ-r<#qL zfv1tYe3A9fWQCFb+oGPbt6f+7%NT>-gH`I9+w2|sgAL7Xtp<1YL#6M5^l8-t&5N1& z`63%hJ<;@NGsID1us)XWSCSB8Z1(eai=cqv^t z<=TA7LjNSFDwt6fgrej5@a{g>5tVn)*%PIEfAo(o+ZV4`c<-GjInbD}&WV-q zGJcg4WzZkzMBTTX_`l=C*xA78KXM{@{?FsY!!=@$U7Y+}LL~XH9OnHOd>A6|i*$=b zymYw?#}0&@8B;V%M;>jCrU0XmJg)XH=XQ;ZrMNmz>>1wEX+J@5FVTifd9$p#QlQ0Pew*6-3=((|+58lr| z$51XqPOkOHUl*hfdnB_0*%qpYHD^=wqiIJ& zE#w}9`(z@2@aX>Ix2iw=#mzpa6%tU*#_4*;KGI76O2sutofm WZ<%i>pTU=&FynBBqkta!DE>FM9in3Z diff --git a/tests/graphics/shaders/bin/triangle_vert.spv b/tests/graphics/shaders/bin/triangle_vert.spv deleted file mode 100644 index 8841490f23661cfe2cb857d3885f1f833c898b0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 720 zcmYk3O-q7N5QQgA`_|0TJ|K*ify)S@TC@nEdhKJ;)`bf<24d2(pWPrz znR{m5Yq@l~60sB!wK(F}(}>c7DJQI2kM+NLHk?d{pAUo4IOvS9YniB|x}5SGLM5t6 zAC0@S!KB+SUV5*+;xX~wS@5^Teen!TydLi#({v#V6%=>)KlhG_&fFk8Vs|-CXpWsB z_O80#S#Pm*72F}t(5!igbTVE|== pc.width || id.y >= pc.height) { - return; - } - - uint index = id.y * pc.width + id.x; - uint offset = index * 16; // sizeof(float4) - outBuffer.Store4(offset, asuint(pc.color)); -} - -// GLSL equivalent - -// #version 450 - -// layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -// layout(set = 0, binding = 0) buffer OutputBuffer -// { -// vec4 pixels[]; -// } outBuffer; - -// layout(push_constant) uniform PushConstants -// { -// uint width; -// uint height; -// vec4 color; -// } pc; - -// void main() -// { -// uvec2 id = gl_GlobalInvocationID.xy; -// if (id.x >= pc.width || id.y >= pc.height) { -// return; -// } - -// uint index = id.y * pc.width + id.x; -// outBuffer.pixels[index] = pc.color; -// } diff --git a/tests/graphics/shaders/src/glsl/closest_hit.glsl b/tests/graphics/shaders/src/glsl/closest_hit.glsl new file mode 100644 index 00000000..626fb050 --- /dev/null +++ b/tests/graphics/shaders/src/glsl/closest_hit.glsl @@ -0,0 +1,10 @@ + +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(location = 0) rayPayloadInEXT vec3 payloadColor; + +void main() +{ + payloadColor = vec3(0.0, 1.0, 0.0); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/compute.glsl b/tests/graphics/shaders/src/glsl/compute.glsl new file mode 100644 index 00000000..2b633bcb --- /dev/null +++ b/tests/graphics/shaders/src/glsl/compute.glsl @@ -0,0 +1,27 @@ + +#version 450 + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(set = 0, binding = 0) buffer OutputBuffer +{ + vec4 pixels[]; +} outBuffer; + +layout(push_constant) uniform PushConstants +{ + uint width; + uint height; + vec4 color; +} pc; + +void main() +{ + uvec2 id = gl_GlobalInvocationID.xy; + if (id.x >= pc.width || id.y >= pc.height) { + return; + } + + uint index = id.y * pc.width + id.x; + outBuffer.pixels[index] = pc.color; +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/mesh.glsl b/tests/graphics/shaders/src/glsl/mesh.glsl new file mode 100644 index 00000000..a0fbe477 --- /dev/null +++ b/tests/graphics/shaders/src/glsl/mesh.glsl @@ -0,0 +1,27 @@ + +#version 460 +#extension GL_EXT_mesh_shader : require + +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; +layout(max_vertices = 4, max_primitives = 2) out; +layout(triangles) out; + +layout(location = 0) out vec4 vColors[]; + +void main() +{ + SetMeshOutputsEXT(4, 2); + gl_MeshVerticesEXT[0].gl_Position = vec4(-0.5, 0.5, 0.0, 1.0); + gl_MeshVerticesEXT[1].gl_Position = vec4( 0.5, 0.5, 0.0, 1.0); + gl_MeshVerticesEXT[2].gl_Position = vec4( 0.5,-0.5, 0.0, 1.0); + gl_MeshVerticesEXT[3].gl_Position = vec4(-0.5,-0.5, 0.0, 1.0); + + // colors + vColors[0] = vec4(1.0, 0.0, 0.0, 1.0); + vColors[1] = vec4(0.0, 1.0, 0.0, 1.0); + vColors[2] = vec4(0.0, 0.0, 1.0, 1.0); + vColors[3] = vec4(1.0, 0.0, 0.0, 1.0); + + gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); + gl_PrimitiveTriangleIndicesEXT[1] = uvec3(0, 2, 3); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/miss.glsl b/tests/graphics/shaders/src/glsl/miss.glsl new file mode 100644 index 00000000..5fcd6207 --- /dev/null +++ b/tests/graphics/shaders/src/glsl/miss.glsl @@ -0,0 +1,10 @@ + +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(location = 0) rayPayloadInEXT vec3 payloadColor; + +void main() +{ + payloadColor = vec3(0.0); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/raygen.glsl b/tests/graphics/shaders/src/glsl/raygen.glsl new file mode 100644 index 00000000..78f43b3d --- /dev/null +++ b/tests/graphics/shaders/src/glsl/raygen.glsl @@ -0,0 +1,44 @@ + +#version 460 +#extension GL_EXT_ray_tracing : require + +layout(set = 0, binding = 0) buffer OutputBuffer +{ + vec4 pixels[]; +} outBuffer; + +layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; +layout(location = 0) rayPayloadEXT vec3 payloadColor; + +void main() +{ + uvec2 pixel = gl_LaunchIDEXT.xy; + uvec2 size = gl_LaunchSizeEXT.xy; + payloadColor = vec3(0.0); + + vec2 uv = (vec2(pixel) + 0.5) / vec2(size); + vec2 ndcUv = uv * 2.0 - 1.0; + vec3 origin = vec3(0.0, 0.0, -3.0); + vec3 direction = normalize(vec3(ndcUv.x, ndcUv.y, 1.0)); + + traceRayEXT( + tlas, + gl_RayFlagsOpaqueEXT, + 0xFF, + 0, + 0, + 0, + origin, + 0.001, + direction, + 1000.0, + 0 + ); + + if (pixel.x >= size.x || pixel.y >= size.y) { + return; + } + + uint index = pixel.y * size.x + pixel.x; + outBuffer.pixels[index] = vec4(payloadColor, 1.0); +} diff --git a/tests/graphics/shaders/src/glsl/texture_frag.glsl b/tests/graphics/shaders/src/glsl/texture_frag.glsl new file mode 100644 index 00000000..fd330edc --- /dev/null +++ b/tests/graphics/shaders/src/glsl/texture_frag.glsl @@ -0,0 +1,14 @@ + +#version 450 + +layout(set = 0, binding = 0) uniform texture2D tex; +layout(set = 0, binding = 1) uniform sampler samp; + +layout(location = 0) in vec2 aTexCoord; + +layout(location = 0) out vec4 color; + +void main() +{ + color = texture(sampler2D(tex, samp), aTexCoord); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/texture_vert.glsl b/tests/graphics/shaders/src/glsl/texture_vert.glsl new file mode 100644 index 00000000..96ed6166 --- /dev/null +++ b/tests/graphics/shaders/src/glsl/texture_vert.glsl @@ -0,0 +1,14 @@ + + +#version 450 + +layout(location = 0) in vec2 aPosition; +layout(location = 1) in vec2 aTexCoord; + +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); + vTexCoord = aTexCoord; +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/triangle_frag.glsl b/tests/graphics/shaders/src/glsl/triangle_frag.glsl new file mode 100644 index 00000000..384d9720 --- /dev/null +++ b/tests/graphics/shaders/src/glsl/triangle_frag.glsl @@ -0,0 +1,11 @@ + +#version 450 + +layout(location = 0) in vec4 aColor; + +layout(location = 0) out vec4 color; + +void main() +{ + color = aColor; +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/triangle_vert.glsl b/tests/graphics/shaders/src/glsl/triangle_vert.glsl new file mode 100644 index 00000000..f396160c --- /dev/null +++ b/tests/graphics/shaders/src/glsl/triangle_vert.glsl @@ -0,0 +1,13 @@ + +#version 450 + +layout(location = 0) in vec2 aPosition; +layout(location = 1) in vec3 aColor; + +layout(location = 0) out vec4 vColor; + +void main() +{ + gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); + vColor = vec4(aColor, 1.0); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/closest_hit.hlsl b/tests/graphics/shaders/src/hlsl/closest_hit.hlsl new file mode 100644 index 00000000..e71bf6f6 --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/closest_hit.hlsl @@ -0,0 +1,18 @@ + +struct RayPayload +{ + float3 color; +}; + +struct HitAttributes +{ + float2 unused; +}; + +[shader("closesthit")] +void main( + inout RayPayload payload, + in HitAttributes attr) +{ + payload.color = float3(0.0, 1.0, 0.0); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/compute.hlsl b/tests/graphics/shaders/src/hlsl/compute.hlsl new file mode 100644 index 00000000..d7eebfe1 --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/compute.hlsl @@ -0,0 +1,25 @@ + +struct PushConstants +{ + uint width; + uint height; + float4 color; +}; + +PushConstants pc; + +// We used raw Buffer but structured buffer can be used as well. +// PalDescriptorBufferInfo::stride must be set to 16 +RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 + +[numthreads(16, 16, 1)] +void main(uint3 id : SV_DispatchThreadID) +{ + if (id.x >= pc.width || id.y >= pc.height) { + return; + } + + uint index = id.y * pc.width + id.x; + uint offset = index * 16; // sizeof(float4) + outBuffer.Store4(offset, asuint(pc.color)); +} diff --git a/tests/graphics/shaders/src/hlsl/mesh.hlsl b/tests/graphics/shaders/src/hlsl/mesh.hlsl new file mode 100644 index 00000000..5ca64819 --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/mesh.hlsl @@ -0,0 +1,27 @@ + +struct MSOutput +{ + float4 position : SV_POSITION; + float4 color : COLOR; +}; + +[outputtopology("triangle")] +[numthreads(1, 1, 1)] +void main( + out vertices MSOutput meshVertices[4], + out indices uint3 triangleIndices[2]) +{ + SetMeshOutputCounts(4, 2); + meshVertices[0].position = float4(-0.5, 0.5, 0.0, 1.0); + meshVertices[1].position = float4( 0.5, 0.5, 0.0, 1.0); + meshVertices[2].position = float4( 0.5,-0.5, 0.0, 1.0); + meshVertices[3].position = float4(-0.5,-0.5, 0.0, 1.0); + + meshVertices[0].color = float4(1.0, 0.0, 0.0, 1.0); + meshVertices[1].color = float4(0.0, 1.0, 0.0, 1.0); + meshVertices[2].color = float4(0.0, 0.0, 1.0, 1.0); + meshVertices[3].color = float4(1.0, 0.0, 0.0, 1.0); + + triangleIndices[0] = uint3(0, 1, 2); + triangleIndices[1] = uint3(0, 2, 3); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/miss.hlsl b/tests/graphics/shaders/src/hlsl/miss.hlsl new file mode 100644 index 00000000..2ec46cfc --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/miss.hlsl @@ -0,0 +1,11 @@ + +struct RayPayload +{ + float3 color; +}; + +[shader("miss")] +void main(inout RayPayload payload) +{ + payload.color = float3(0.0, 0.0, 0.0); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/raygen.hlsl b/tests/graphics/shaders/src/hlsl/raygen.hlsl new file mode 100644 index 00000000..d44ee13e --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/raygen.hlsl @@ -0,0 +1,36 @@ + +struct RayPayload +{ + float3 color; +}; + +RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 +RaytracingAccelerationStructure tlas : register(t0, space0); // set 0 + +[shader("raygeneration")] +void main() +{ + uint2 pixel = DispatchRaysIndex().xy; + uint2 size = DispatchRaysDimensions().xy; + RayPayload payload; + payload.color = float3(0.0, 0.0, 0.0); + + float2 uv = (float2(pixel) + 0.5) / float2(size); + float2 ndcUv = uv * 2.0 - 1.0; + + RayDesc desc; + desc.Origin = float3(0.0, 0.0, -3.0);; + desc.Direction = normalize(float3(ndcUv.x, ndcUv.y, 1.0));; + desc.TMin = 0.001; + desc.TMax = 1000.0; + TraceRay(tlas, RAY_FLAG_NONE, 0xFF, 0, 0, 0, desc, payload); + + if (pixel.x >= size.x || pixel.y >= size.y) { + return; + } + + uint index = pixel.y * size.x + pixel.x; + uint offset = index * 16; // sizeof(float4) + float4 color = float4(payload.color, 1.0); + outBuffer.Store4(offset, asuint(color)); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/texture_frag.hlsl b/tests/graphics/shaders/src/hlsl/texture_frag.hlsl new file mode 100644 index 00000000..5af1fc82 --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/texture_frag.hlsl @@ -0,0 +1,14 @@ + +Texture2D tex : register(t0, space0); // set 0 +SamplerState samp : register(s0, space0); // set 0 + +struct PSInput +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD; +}; + +float4 main(PSInput input) : SV_Target +{ + return tex.Sample(samp, input.uv); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/texture_vert.hlsl b/tests/graphics/shaders/src/hlsl/texture_vert.hlsl new file mode 100644 index 00000000..ff9ef8cc --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/texture_vert.hlsl @@ -0,0 +1,20 @@ + +struct VSInput +{ + float2 pos : POSITION; + float2 uv : TEXCOORD; +}; + +struct VSOutput +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD; +}; + +VSOutput main(VSInput input) +{ + VSOutput output; + output.pos = float4(input.pos, 0.0, 1.0); + output.uv = input.uv; + return output; +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/triangle_frag.hlsl b/tests/graphics/shaders/src/hlsl/triangle_frag.hlsl new file mode 100644 index 00000000..756feece --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/triangle_frag.hlsl @@ -0,0 +1,11 @@ + +struct PSInput +{ + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +float4 main(PSInput input) : SV_Target +{ + return input.color; +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/triangle_vert.hlsl b/tests/graphics/shaders/src/hlsl/triangle_vert.hlsl new file mode 100644 index 00000000..eb111619 --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/triangle_vert.hlsl @@ -0,0 +1,20 @@ + +struct VSInput +{ + float2 pos : POSITION; + float3 color : COLOR; +}; + +struct VSOutput +{ + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +VSOutput main(VSInput input) +{ + VSOutput output; + output.pos = float4(input.pos, 0.0, 1.0); + output.color = float4(input.color, 1.0); + return output; +} diff --git a/tests/graphics/shaders/src/mesh.hlsl b/tests/graphics/shaders/src/mesh.hlsl deleted file mode 100644 index 23a8a579..00000000 --- a/tests/graphics/shaders/src/mesh.hlsl +++ /dev/null @@ -1,56 +0,0 @@ - -struct MSOutput -{ - float4 position : SV_POSITION; - float4 color : COLOR; -}; - -[outputtopology("triangle")] -[numthreads(1, 1, 1)] -void meshMain( - out vertices MSOutput meshVertices[4], - out indices uint3 triangleIndices[2]) -{ - SetMeshOutputCounts(4, 2); - meshVertices[0].position = float4(-0.5, 0.5, 0.0, 1.0); - meshVertices[1].position = float4( 0.5, 0.5, 0.0, 1.0); - meshVertices[2].position = float4( 0.5,-0.5, 0.0, 1.0); - meshVertices[3].position = float4(-0.5,-0.5, 0.0, 1.0); - - meshVertices[0].color = float4(1.0, 0.0, 0.0, 1.0); - meshVertices[1].color = float4(0.0, 1.0, 0.0, 1.0); - meshVertices[2].color = float4(0.0, 0.0, 1.0, 1.0); - meshVertices[3].color = float4(1.0, 0.0, 0.0, 1.0); - - triangleIndices[0] = uint3(0, 1, 2); - triangleIndices[1] = uint3(0, 2, 3); -} - -// GLSL equivalent - -// #version 460 -// #extension GL_EXT_mesh_shader : require - -// layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; -// layout(max_vertices = 4, max_primitives = 2) out; -// layout(triangles) out; - -// layout(location = 0) out vec4 vColors[]; - -// void main() -// { -// SetMeshOutputsEXT(4, 2); -// gl_MeshVerticesEXT[0].gl_Position = vec4(-0.5, 0.5, 0.0, 1.0); -// gl_MeshVerticesEXT[1].gl_Position = vec4( 0.5, 0.5, 0.0, 1.0); -// gl_MeshVerticesEXT[2].gl_Position = vec4( 0.5,-0.5, 0.0, 1.0); -// gl_MeshVerticesEXT[3].gl_Position = vec4(-0.5,-0.5, 0.0, 1.0); - -// // colors -// vColors[0] = vec4(1.0, 0.0, 0.0, 1.0); -// vColors[1] = vec4(0.0, 1.0, 0.0, 1.0); -// vColors[2] = vec4(0.0, 0.0, 1.0, 1.0); -// vColors[3] = vec4(1.0, 0.0, 0.0, 1.0); - -// gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); -// gl_PrimitiveTriangleIndicesEXT[1] = uvec3(0, 2, 3); -// } \ No newline at end of file diff --git a/tests/graphics/shaders/src/ray_tracing.hlsl b/tests/graphics/shaders/src/ray_tracing.hlsl deleted file mode 100644 index 46ea26ea..00000000 --- a/tests/graphics/shaders/src/ray_tracing.hlsl +++ /dev/null @@ -1,124 +0,0 @@ - -struct RayPayload -{ - float3 color; -}; - -struct HitAttributes -{ - float2 unused; -}; - -RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 -RaytracingAccelerationStructure tlas : register(t0, space0); // set 0 - -[shader("raygeneration")] -void raygenMain() -{ - uint2 pixel = DispatchRaysIndex().xy; - uint2 size = DispatchRaysDimensions().xy; - RayPayload payload; - payload.color = float3(0.0, 0.0, 0.0); - - float2 uv = (float2(pixel) + 0.5) / float2(size); - float2 ndcUv = uv * 2.0 - 1.0; - - RayDesc desc; - desc.Origin = float3(0.0, 0.0, -3.0);; - desc.Direction = normalize(float3(ndcUv.x, ndcUv.y, 1.0));; - desc.TMin = 0.001; - desc.TMax = 1000.0; - TraceRay(tlas, RAY_FLAG_NONE, 0xFF, 0, 0, 0, desc, payload); - - if (pixel.x >= size.x || pixel.y >= size.y) { - return; - } - - uint index = pixel.y * size.x + pixel.x; - uint offset = index * 16; // sizeof(float4) - float4 color = float4(payload.color, 1.0); - outBuffer.Store4(offset, asuint(color)); -} - -[shader("closesthit")] -void closestHitMain( - inout RayPayload payload, - in HitAttributes attr) -{ - payload.color = float3(0.0, 1.0, 0.0); -} - -[shader("miss")] -void missMain(inout RayPayload payload) -{ - payload.color = float3(0.0, 0.0, 0.0); -} - -// GLSL equivalent - -// // Raygen -// #version 460 -// #extension GL_EXT_ray_tracing : require - -// layout(set = 0, binding = 0) buffer OutputBuffer -// { -// vec4 pixels[]; -// } outBuffer; - -// layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; -// layout(location = 0) rayPayloadEXT vec3 payloadColor; - -// void main() -// { -// uvec2 pixel = gl_LaunchIDEXT.xy; -// uvec2 size = gl_LaunchSizeEXT.xy; -// payloadColor = vec3(0.0); - -// vec2 uv = (vec2(pixel) + 0.5) / vec2(size); -// vec2 ndcUv = uv * 2.0 - 1.0; -// vec3 origin = vec3(0.0, 0.0, -3.0); -// vec3 direction = normalize(vec3(ndcUv.x, ndcUv.y, 1.0)); - -// traceRayEXT( -// tlas, -// gl_RayFlagsOpaqueEXT, -// 0xFF, -// 0, -// 0, -// 0, -// origin, -// 0.001, -// direction, -// 1000.0, -// 0 -// ); - -// if (pixel.x >= size.x || pixel.y >= size.y) { -// return; -// } - -// uint index = pixel.y * size.x + pixel.x; -// outBuffer.pixels[index] = vec4(payloadColor, 1.0); -// } - -// // Closest Hit -// #version 460 -// #extension GL_EXT_ray_tracing : require - -// layout(location = 0) rayPayloadInEXT vec3 payloadColor; - -// void main() -// { -// payloadColor = vec3(0.0, 1.0, 0.0); -// } - -// // Miss -// #version 460 -// #extension GL_EXT_ray_tracing : require - -// layout(location = 0) rayPayloadInEXT vec3 payloadColor; - -// void main() -// { -// payloadColor = vec3(0.0); -// } \ No newline at end of file diff --git a/tests/graphics/shaders/src/texture_frag.hlsl b/tests/graphics/shaders/src/texture_frag.hlsl deleted file mode 100644 index 2c769605..00000000 --- a/tests/graphics/shaders/src/texture_frag.hlsl +++ /dev/null @@ -1,30 +0,0 @@ - -Texture2D tex : register(t0, space0); // set 0 -SamplerState samp : register(s0, space0); // set 0 - -struct PSInput -{ - float4 pos : SV_POSITION; - float2 uv : TEXCOORD; -}; - -float4 fragMain(PSInput input) : SV_Target -{ - return tex.Sample(samp, input.uv); -} - -// GLSL equivalent - -// #version 450 - -// layout(set = 0, binding = 0) uniform texture2D tex; -// layout(set = 0, binding = 1) uniform sampler samp; - -// layout(location = 0) in vec2 aTexCoord; - -// layout(location = 0) out vec4 color; - -// void main() -// { -// color = texture(sampler2D(tex, samp), aTexCoord); -// } \ No newline at end of file diff --git a/tests/graphics/shaders/src/texture_vert.hlsl b/tests/graphics/shaders/src/texture_vert.hlsl deleted file mode 100644 index bd630089..00000000 --- a/tests/graphics/shaders/src/texture_vert.hlsl +++ /dev/null @@ -1,35 +0,0 @@ - -struct VSInput -{ - float2 pos : POSITION; - float2 uv : TEXCOORD; -}; - -struct VSOutput -{ - float4 pos : SV_POSITION; - float2 uv : TEXCOORD; -}; - -VSOutput vertexMain(VSInput input) -{ - VSOutput output; - output.pos = float4(input.pos, 0.0, 1.0); - output.uv = input.uv; - return output; -} - -// GLSL equivalent - -// #version 450 - -// layout(location = 0) in vec2 aPosition; -// layout(location = 1) in vec2 aTexCoord; - -// layout(location = 0) out vec2 vTexCoord; - -// void main() -// { -// gl_Position = vec4(aPosition, 0.0, 1.0); -// vTexCoord = aTexCoord; -// } \ No newline at end of file diff --git a/tests/graphics/shaders/src/triangle_frag.hlsl b/tests/graphics/shaders/src/triangle_frag.hlsl deleted file mode 100644 index 72d47ecd..00000000 --- a/tests/graphics/shaders/src/triangle_frag.hlsl +++ /dev/null @@ -1,24 +0,0 @@ - -struct PSInput -{ - float4 pos : SV_POSITION; - float4 color : COLOR; -}; - -float4 fragMain(PSInput input) : SV_Target -{ - return input.color; -} - -// GLSL equivalent - -// #version 450 - -// layout(location = 0) in vec4 aColor; - -// layout(location = 0) out vec4 color; - -// void main() -// { -// color = aColor; -// } \ No newline at end of file diff --git a/tests/graphics/shaders/src/triangle_vert.hlsl b/tests/graphics/shaders/src/triangle_vert.hlsl deleted file mode 100644 index 3a7cc3f8..00000000 --- a/tests/graphics/shaders/src/triangle_vert.hlsl +++ /dev/null @@ -1,35 +0,0 @@ - -struct VSInput -{ - float2 pos : POSITION; - float3 color : COLOR; -}; - -struct VSOutput -{ - float4 pos : SV_POSITION; - float4 color : COLOR; -}; - -VSOutput vertexMain(VSInput input) -{ - VSOutput output; - output.pos = float4(input.pos, 0.0, 1.0); - output.color = float4(input.color, 1.0); - return output; -} - -// GLSL equivalent - -// #version 450 - -// layout(location = 0) in vec2 aPosition; -// layout(location = 1) in vec3 aColor; - -// layout(location = 0) out vec4 vColor; - -// void main() -// { -// gl_Position = vec4(aPosition, 0.0, 1.0); -// vColor = vec4(aColor, 1.0); -// } diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 5a7efec1..34414ee6 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -3,7 +3,6 @@ #include "pal/pal_video.h" #include "pal/pal_system.h" #include "tests.h" -#include "shaders.h" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 @@ -71,8 +70,7 @@ bool textureTest() PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; - PalShader* vertexShader = nullptr; - PalShader* fragmentShader = nullptr; + PalShader* shaders[2]; PalBuffer* vertexBuffer = nullptr; PalBuffer* stagingBuffer = nullptr; @@ -851,97 +849,54 @@ bool textureTest() } // create shaders - Uint64 vertBytecodeSize = 0; - Uint64 fragBytecodeSize = 0; - void* vertBytecode = nullptr; - void* fragBytecode = nullptr; - const char* vertSource = nullptr; - const char* fragSource = nullptr; - - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + const char* sources[2]; + PalShaderStage tmpShaderStages[2]; - PalShaderCreateInfo vertShaderCreateInfo = {0}; - PalShaderCreateInfo fragShaderCreateInfo = {0}; + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - vertSource = "graphics/shaders/bin/texture_vert.spv"; - fragSource = "graphics/shaders/bin/texture_frag.spv"; - - // flip for spirv since we use a single shader source - viewport.y = (float)WINDOW_HEIGHT; - viewport.height = -(float)WINDOW_HEIGHT; + sources[0] = "graphics/shaders/bin/spirv/texture_vert.spv"; + sources[1] = "graphics/shaders/bin/spirv/texture_frag.spv"; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - vertSource = "graphics/shaders/bin/texture_vert.dxil"; - fragSource = "graphics/shaders/bin/texture_frag.dxil"; + sources[0] = "graphics/shaders/bin/dxil/texture_vert.dxil"; + sources[1] = "graphics/shaders/bin/dxil/texture_frag.dxil"; } - // read file - if (!readFile(vertSource, nullptr, &vertBytecodeSize)) { - palLog(nullptr, "Failed to read shader file"); - return false; - } + tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; + tmpShaderStages[1] = PAL_SHADER_STAGE_FRAGMENT; - if (!readFile(fragSource, nullptr, &fragBytecodeSize)) { - palLog(nullptr, "Failed to read shader file"); - return false; - } - - vertBytecode = palAllocate(nullptr, vertBytecodeSize, 0); - if (!vertBytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - fragBytecode = palAllocate(nullptr, fragBytecodeSize, 0); - if (!fragBytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - readFile(vertSource, vertBytecode, &vertBytecodeSize); - readFile(fragSource, fragBytecode, &fragBytecodeSize); - - // describe how many entries are in the shader bytecode - // For simplicity, we dont use one shader bytecode for all the shaders - PalShaderEntry vertexEntry = {0}; - vertexEntry.entryName = "vertexMain"; - vertexEntry.stage = PAL_SHADER_STAGE_VERTEX; + for (int i = 0; i < 2; i++) { + // read file + if (!readFile(sources[i], nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } - PalShaderEntry fragmentEntry = {0}; - fragmentEntry.entryName = "fragMain"; - fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } - vertShaderCreateInfo.bytecode = vertBytecode; - vertShaderCreateInfo.bytecodeSize = vertBytecodeSize; - vertShaderCreateInfo.entries = &vertexEntry; - vertShaderCreateInfo.entryCount = 1; + readFile(sources[i], bytecode, &bytecodeSize); - fragShaderCreateInfo.bytecode = fragBytecode; - fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; - fragShaderCreateInfo.entries = &fragmentEntry; - fragShaderCreateInfo.entryCount = 1; + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.entryName = "main"; + shaderCreateInfo.stage = tmpShaderStages[i]; - result = palCreateShader(device, &vertShaderCreateInfo, &vertexShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create vertex shader: %s", error); - return false; - } + result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create shader: %s", error); + return false; + } - result = palCreateShader(device, &fragShaderCreateInfo, &fragmentShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fragment shader: %s", error); - return false; + palFree(nullptr, bytecode); } - palFree(nullptr, vertBytecode); - palFree(nullptr, fragBytecode); - // create descriptor set layout PalDescriptorSetLayoutBinding descriptorBindings[2]; PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; @@ -1089,9 +1044,6 @@ bool textureTest() pipelineCreateInfo.colorBlendAttachmentCount = 1; // shaders - PalShader* shaders[2]; - shaders[0] = vertexShader; - shaders[1] = fragmentShader; pipelineCreateInfo.shaderCount = 2; pipelineCreateInfo.shaders = shaders; @@ -1106,8 +1058,9 @@ bool textureTest() return false; } - palDestroyShader(vertexShader); - palDestroyShader(fragmentShader); + for (int i = 0; i < 2; i++) { + palDestroyShader(shaders[i]); + } // wait for the vertices copy to be done result = palWaitFence(fence, PAL_INFINITE); @@ -1130,6 +1083,12 @@ bool textureTest() Uint32 currentFrame = 0; bool running = true; + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index ae536b23..ce22097c 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -3,7 +3,6 @@ #include "pal/pal_video.h" #include "pal/pal_system.h" #include "tests.h" -#include "shaders.h" #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 @@ -41,8 +40,7 @@ bool triangleTest() PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; - PalShader* vertexShader = nullptr; - PalShader* fragmentShader = nullptr; + PalShader* shaders[2]; PalBuffer* vertexBuffer = nullptr; PalBuffer* stagingBuffer = nullptr; @@ -554,97 +552,54 @@ bool triangleTest() } // create shaders - Uint64 vertBytecodeSize = 0; - Uint64 fragBytecodeSize = 0; - void* vertBytecode = nullptr; - void* fragBytecode = nullptr; - const char* vertSource = nullptr; - const char* fragSource = nullptr; - - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + const char* sources[2]; + PalShaderStage tmpShaderStages[2]; - PalShaderCreateInfo vertShaderCreateInfo = {0}; - PalShaderCreateInfo fragShaderCreateInfo = {0}; + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - vertSource = "graphics/shaders/bin/triangle_vert.spv"; - fragSource = "graphics/shaders/bin/triangle_frag.spv"; - - // flip for spirv since we use a single shader source - viewport.y = (float)WINDOW_HEIGHT; - viewport.height = -(float)WINDOW_HEIGHT; + sources[0] = "graphics/shaders/bin/spirv/triangle_vert.spv"; + sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - vertSource = "graphics/shaders/bin/triangle_vert.dxil"; - fragSource = "graphics/shaders/bin/triangle_frag.dxil"; + sources[0] = "graphics/shaders/bin/dxil/triangle_vert.dxil"; + sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; } - // read file - if (!readFile(vertSource, nullptr, &vertBytecodeSize)) { - palLog(nullptr, "Failed to read shader file"); - return false; - } + tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; + tmpShaderStages[1] = PAL_SHADER_STAGE_FRAGMENT; - if (!readFile(fragSource, nullptr, &fragBytecodeSize)) { - palLog(nullptr, "Failed to read shader file"); - return false; - } - - vertBytecode = palAllocate(nullptr, vertBytecodeSize, 0); - if (!vertBytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - fragBytecode = palAllocate(nullptr, fragBytecodeSize, 0); - if (!fragBytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } - - readFile(vertSource, vertBytecode, &vertBytecodeSize); - readFile(fragSource, fragBytecode, &fragBytecodeSize); - - // describe how many entries are in the shader bytecode - // For simplicity, we dont use one shader bytecode for all the shaders - PalShaderEntry vertexEntry = {0}; - vertexEntry.entryName = "vertexMain"; - vertexEntry.stage = PAL_SHADER_STAGE_VERTEX; + for (int i = 0; i < 2; i++) { + // read file + if (!readFile(sources[i], nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } - PalShaderEntry fragmentEntry = {0}; - fragmentEntry.entryName = "fragMain"; - fragmentEntry.stage = PAL_SHADER_STAGE_FRAGMENT; + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } - vertShaderCreateInfo.bytecode = vertBytecode; - vertShaderCreateInfo.bytecodeSize = vertBytecodeSize; - vertShaderCreateInfo.entries = &vertexEntry; - vertShaderCreateInfo.entryCount = 1; + readFile(sources[i], bytecode, &bytecodeSize); - fragShaderCreateInfo.bytecode = fragBytecode; - fragShaderCreateInfo.bytecodeSize = fragBytecodeSize; - fragShaderCreateInfo.entries = &fragmentEntry; - fragShaderCreateInfo.entryCount = 1; + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.entryName = "main"; + shaderCreateInfo.stage = tmpShaderStages[i]; - result = palCreateShader(device, &vertShaderCreateInfo, &vertexShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create vertex shader: %s", error); - return false; - } + result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create shader: %s", error); + return false; + } - result = palCreateShader(device, &fragShaderCreateInfo, &fragmentShader); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fragment shader: %s", error); - return false; + palFree(nullptr, bytecode); } - palFree(nullptr, vertBytecode); - palFree(nullptr, fragBytecode); - // create a pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); @@ -694,9 +649,6 @@ bool triangleTest() pipelineCreateInfo.colorBlendAttachmentCount = 1; // shaders - PalShader* shaders[2]; - shaders[0] = vertexShader; - shaders[1] = fragmentShader; pipelineCreateInfo.shaderCount = 2; pipelineCreateInfo.shaders = shaders; @@ -711,8 +663,9 @@ bool triangleTest() return false; } - palDestroyShader(vertexShader); - palDestroyShader(fragmentShader); + for (int i = 0; i < 2; i++) { + palDestroyShader(shaders[i]); + } // wait for the vertices copy to be done result = palWaitFence(tmpFence, PAL_INFINITE); @@ -731,6 +684,12 @@ bool triangleTest() Uint32 currentFrame = 0; bool running = true; + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; diff --git a/tests/tests_main.c b/tests/tests_main.c index 960ba8bd..a58159ad 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,14 +58,14 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - // registerTest(computeTest, "Compute Test"); // TODO: test - // registerTest(rayTracingTest, "Ray Tracing Test"); // TODO: test + // registerTest(computeTest, "Compute Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest(clearColorTest, "Clear Color Test"); + // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); - // registerTest(meshTest, "Mesh Test"); // TODO: test + // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); #endif // From d2b0b857305398d35af000f7aa0abd1a3f7e6182 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 9 May 2026 15:49:23 +0000 Subject: [PATCH 210/372] add more flexibility to ray tracing API --- include/pal/pal_graphics.h | 21 ++- src/graphics/pal_vulkan.c | 255 +++++++++++++++++++++++------- tests/graphics/ray_tracing_test.c | 33 +++- 3 files changed, 248 insertions(+), 61 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 398a5149..db0411bc 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2431,6 +2431,21 @@ typedef struct { PalImageAspect aspect; } PalImageCopyInfo; +/** + * @struct PalImageCopyInfo + * @brief Information for image to image copies. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 groupIndex; /**< Index into the shader groups used to create the ray tracing pipeline.*/ + Uint32 localDataSize; + void* localData; +} PalShaderBindingTableRecordInfo; + /** * @struct PalImageCreateInfo * @brief Creation parameters for an image. @@ -2692,10 +2707,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 raygenGroupCount; - Uint32 missGroupCount; - Uint32 hitGroupCount; - Uint32 callableGroupCount; + Uint32 recordCount; + PalShaderBindingTableRecordInfo* records; PalPipeline* rayTracingPipeline; } PalShaderBindingTableCreateInfo; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 5181e912..39cf77ba 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -589,6 +589,18 @@ typedef struct { VkPipelineLayout handle; } PipelineLayout; +typedef struct { + Uint32 raygenCount; + Uint32 missCount; + Uint32 hitCount; + Uint32 callableCount; +} ShaderBindingTableInfo; + +typedef struct { + PalShaderStage stage; // used to identify each group + Uint32 index; +} ShaderGroupMap; + typedef struct { const PalGraphicsBackend* backend; @@ -596,6 +608,8 @@ typedef struct { Device* device; VkPipeline handle; VkPipelineLayout layout; + ShaderGroupMap* groupMaps; + ShaderBindingTableInfo sbtInfo; } Pipeline; typedef struct { @@ -2245,6 +2259,13 @@ static inline Uint32 alignVk( return (value + alignment - 1) & ~(alignment - 1); } +static inline Uint32 maxVk( + Uint32 a, + Uint32 b) +{ + return (a > b) ? a : b; +} + static inline Uint32 minVk( Uint32 a, Uint32 b) @@ -8983,6 +9004,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; pipeline->device = vkDevice; pipeline->layout = layout->handle; + pipeline->groupMaps = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -9027,6 +9049,7 @@ PalResult PAL_CALL createComputePipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; pipeline->device = vkDevice; pipeline->layout = layout->handle; + pipeline->groupMaps = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -9042,6 +9065,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( Pipeline* pipeline = nullptr; VkPipelineShaderStageCreateInfo* shaderStages = nullptr; VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; + ShaderGroupMap* groupMaps = nullptr; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -9055,6 +9079,8 @@ PalResult PAL_CALL createRayTracingPipelineVk( createInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); + groupMaps = palAllocate(s_Vk.allocator, sizeof(ShaderGroupMap) * info->shaderGroupCount, 0); + groups = palAllocate( s_Vk.allocator, sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount, @@ -9065,8 +9091,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount, 0); - - if (!pipeline || !groups || !shaderStages) { + if (!pipeline || !groupMaps || !groups || !shaderStages) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -9085,53 +9110,115 @@ PalResult PAL_CALL createRayTracingPipelineVk( createInfo.stageCount = info->shaderCount; createInfo.pStages = shaderStages; - // shader groups + // we always arrange the groups in a specific order so sbt creation becomes simple and layout + // aware already. + // raygen + // miss + // hit + // callable + + ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; for (int i = 0; i < info->shaderGroupCount; i++) { - VkRayTracingShaderGroupCreateInfoKHR* group = &groups[i]; PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; - - group->sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { - group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + // check if its raygen, miss or callable + Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; + switch (shader->stage) { + case VK_SHADER_STAGE_RAYGEN_BIT_KHR: { + sbtInfo->raygenCount++; + break; + } - } else if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { - group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + case VK_SHADER_STAGE_MISS_BIT_KHR: { + sbtInfo->missCount++; + break; + } + + case VK_SHADER_STAGE_CALLABLE_BIT_KHR: { + sbtInfo->callableCount++; + break; + } + } } else { - group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; + sbtInfo->hitCount++; } + } - // Any hit shader - if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - group->anyHitShader = tmp->anyHitShaderIndex; + // we compute offsets + Uint32 raygenOffset = 0; // always first + Uint32 missOffset = sbtInfo->raygenCount; + Uint32 hitOffset = missOffset + sbtInfo->missCount; + Uint32 callableOffset = hitOffset + sbtInfo->hitCount; - } else { - group->anyHitShader = VK_SHADER_UNUSED_KHR; - } + // write into backend array with the correct offsets + for (int i = 0; i < info->shaderGroupCount; i++) { + VkRayTracingShaderGroupCreateInfoKHR* group = nullptr; + PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; - // Closest hit shader - if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - group->closestHitShader = tmp->closestHitShaderIndex; + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { + // check if its raygen, miss or callable + Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; + switch (shader->stage) { + case VK_SHADER_STAGE_RAYGEN_BIT_KHR: { + groupMaps[i].index = raygenOffset; + groupMaps[i].stage = PAL_SHADER_STAGE_RAYGEN; + group = &groups[raygenOffset++]; + break; + } - } else { - group->closestHitShader = VK_SHADER_UNUSED_KHR; - } + case VK_SHADER_STAGE_MISS_BIT_KHR: { + groupMaps[i].index = missOffset; + groupMaps[i].stage = PAL_SHADER_STAGE_MISS; + group = &groups[missOffset++]; + break; + } + + case VK_SHADER_STAGE_CALLABLE_BIT_KHR: { + groupMaps[i].index = callableOffset; + groupMaps[i].stage = PAL_SHADER_STAGE_CALLABLE; + group = &groups[callableOffset++]; + break; + } + } - // General shader - if (tmp->generalShaderIndex != PAL_UNUSED_SHADER_INDEX) { + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; group->generalShader = tmp->generalShaderIndex; + group->anyHitShader = VK_SHADER_UNUSED_KHR; + group->closestHitShader = VK_SHADER_UNUSED_KHR; + group->intersectionShader = VK_SHADER_UNUSED_KHR; } else { + groupMaps[i].index = hitOffset; + groupMaps[i].stage = PAL_SHADER_STAGE_CLOSEST_HIT; // just for identification + group = &groups[hitOffset++]; + group->generalShader = VK_SHADER_UNUSED_KHR; - } + if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { + group->anyHitShader = tmp->anyHitShaderIndex; - // IntersectionShader shader - if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { - group->intersectionShader = tmp->intersectionShaderIndex; + } else { + group->anyHitShader = VK_SHADER_UNUSED_KHR; + } - } else { - group->intersectionShader = VK_SHADER_UNUSED_KHR; + if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { + group->closestHitShader = tmp->closestHitShaderIndex; + + } else { + group->closestHitShader = VK_SHADER_UNUSED_KHR; + } + + if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; + group->intersectionShader = tmp->intersectionShaderIndex; + + } else { + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + group->intersectionShader = VK_SHADER_UNUSED_KHR; + } } + + group->sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; } createInfo.pGroups = groups; @@ -9158,6 +9245,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; pipeline->device = vkDevice; pipeline->layout = layout->handle; + pipeline->groupMaps = groupMaps; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -9167,6 +9255,9 @@ void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) Pipeline* vkPipeline = (Pipeline*)pipeline; s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); + if (vkPipeline->groupMaps) { + palFree(s_Vk.allocator, vkPipeline->groupMaps); + } palFree(s_Vk.allocator, pipeline); } @@ -9183,6 +9274,7 @@ PalResult PAL_CALL createShaderBindingTableVk( Device* vkDevice = (Device*)device; ShaderBindingTable* sbt = nullptr; Pipeline* pipeline = (Pipeline*)info->rayTracingPipeline; + ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -9205,27 +9297,78 @@ PalResult PAL_CALL createShaderBindingTableVk( Uint32 groupHandleSize = rayProps.shaderGroupHandleSize; Uint32 groupHandleAlignment = rayProps.shaderGroupHandleAlignment; Uint32 groupBaseAlignment = rayProps.shaderGroupBaseAlignment; - Uint32 stride = alignVk(groupHandleSize, groupHandleAlignment); - // get region size - Uint32 raygenRegionSize = stride * info->raygenGroupCount; - Uint32 missRegionSize = stride * info->missGroupCount; - Uint32 hitRegionSize = stride * info->hitGroupCount; - Uint32 callableRegionSize = stride * info->callableGroupCount; + Uint32 raygenDataSize = 0; + Uint32 missDataSize = 0; + Uint32 hitDataSize = 0; + Uint32 callableDataSize = 0; + + // get the max local data size + for (int i = 0; i < info->recordCount; i++) { + PalShaderBindingTableRecordInfo* record = &info->records[i]; + ShaderGroupMap* map = &pipeline->groupMaps[record->groupIndex]; + if (!map) { + return PAL_RESULT_INVALID_ARGUMENT; + } - // get aligned region size - Uint32 raygenAlignedRegionSize = alignVk(raygenRegionSize, groupBaseAlignment); - Uint32 missAlignedRegionSize = alignVk(missRegionSize, groupBaseAlignment); - Uint32 hitAlignedRegionSize = alignVk(hitRegionSize, groupBaseAlignment); - Uint32 callableAligneRegionSize = alignVk(callableRegionSize, groupBaseAlignment); + switch (map->stage) { + case PAL_SHADER_STAGE_RAYGEN: { + raygenDataSize = maxVk(raygenDataSize, record->localDataSize); + break; + } + + case PAL_SHADER_STAGE_MISS: { + missDataSize = maxVk(missDataSize, record->localDataSize); + break; + } + + case PAL_SHADER_STAGE_CALLABLE: { + callableDataSize = maxVk(callableDataSize, record->localDataSize); + break; + } + + case PAL_SHADER_STAGE_CLOSEST_HIT: { + hitDataSize = maxVk(hitDataSize, record->localDataSize); + break; + } + } + } + + // get strides + Uint32 raygenStride = alignVk(groupHandleSize + raygenDataSize, groupHandleAlignment); + Uint32 missStride = alignVk(groupHandleSize + missDataSize, groupHandleAlignment); + Uint32 hitStride = alignVk(groupHandleSize + hitDataSize, groupHandleAlignment); + Uint32 callableStride = alignVk(groupHandleSize + callableDataSize, groupHandleAlignment); + + // get region size + Uint32 raygenRegionSize = raygenStride * sbtInfo->raygenCount; + Uint32 missRegionSize = missStride * sbtInfo->missCount; + Uint32 hitRegionSize = hitStride * sbtInfo->hitCount; + Uint32 callableRegionSize = callableStride * sbtInfo->callableCount; // get offsets - Uint32 missOffset = raygenAlignedRegionSize; - Uint32 hitOffset = missOffset + missAlignedRegionSize; - Uint32 callableOffset = hitOffset + hitAlignedRegionSize; - Uint32 bufferSize = callableOffset + callableAligneRegionSize; + Uint32 offset = 0; + Uint32 raygenOffset = 0; + Uint32 missOffset = 0; + Uint32 hitOffset = 0; + Uint32 callableOffset = 0; + + raygenOffset = alignVk(offset, groupBaseAlignment); + offset = raygenOffset + raygenRegionSize; + + missOffset = alignVk(offset, groupBaseAlignment); + offset = missOffset + missRegionSize; + + hitOffset = alignVk(offset, groupBaseAlignment); + offset = hitOffset + hitRegionSize; + + callableOffset = alignVk(offset, groupBaseAlignment); + offset = callableOffset + callableRegionSize; + + Uint32 bufferSize = alignVk(offset, groupBaseAlignment); // create gpu buffer + // TODO: create both a GPU only and UPLOAD buffers VkBufferCreateInfo bufCreateInfo = {0}; bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufCreateInfo.size = bufferSize; @@ -9269,21 +9412,22 @@ PalResult PAL_CALL createShaderBindingTableVk( s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); // get shader group handles - Uint32 totalGroups = info->raygenGroupCount + info->hitGroupCount; - totalGroups += info->missGroupCount + info->callableGroupCount; - Uint32 sbtSize = totalGroups * groupHandleSize; - Uint8* handles = palAllocate(s_Vk.allocator, sbtSize, 0); + Uint32 totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; + totalGroups += sbtInfo->missCount + sbtInfo->callableCount; + Uint32 handlesSize = totalGroups * groupHandleSize; + Uint8* handles = palAllocate(s_Vk.allocator, handlesSize, 0); if (!handles) { palFree(s_Vk.allocator, sbt); return PAL_RESULT_OUT_OF_MEMORY; } + // handles already in our prefered format result = vkDevice->getRayTracingShaderGroupHandles( vkDevice->handle, pipeline->handle, 0, totalGroups, - sbtSize, + handlesSize, handles); if (result != VK_SUCCESS) { @@ -9299,12 +9443,15 @@ PalResult PAL_CALL createShaderBindingTableVk( return resultFromVk(result); } - Uint8* dstPtr = ptr; - Uint8* srcPtr = handles; + // TODO: finish implementation // raygen - for (int i = 0; i < info->raygenGroupCount; i++) { - memcpy(dstPtr + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); + for (int i = 0; i < sbtInfo->raygenCount; i++) { + Uint8* dstPtr = (Uint8*)ptr + (i * raygenStride); + Uint8* srcPtr = (Uint8*)handles + (i * groupHandleSize); + + memcpy(dstPtr, srcPtr, groupHandleSize); + memcpy(dstPtr + groupHandleSize, info->records[i].localData, info->records[i].localDataSize); } srcPtr += raygenRegionSize; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index a0f44d7a..6f84965c 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -4,6 +4,10 @@ #define BUFFER_SIZE 400 +typedef struct { + float color[3]; // closest hit color +} LocalData; + static void PAL_CALL onGraphicsDebug( void* userData, PalDebugMessageSeverity severity, @@ -811,11 +815,34 @@ bool rayTracingTest() } // create shader binding table + // we need 3 records, only closest hit (git group) only uses the local data + LocalData missLocalData; // black color for miss + missLocalData.color[0] = 0.0f; + missLocalData.color[1] = 0.0f; + missLocalData.color[2] = 0.0f; + + LocalData closestLocalData = {0}; // green color for miss + closestLocalData.color[0] = 0.0f; + closestLocalData.color[1] = 1.0f; + closestLocalData.color[2] = 0.0f; + + PalShaderBindingTableRecordInfo records[3]; + records[0].groupIndex = 0; // raygen group index + records[0].localDataSize = 0; + records[0].localData = nullptr; + + records[1].groupIndex = 1; // miss group index + records[1].localDataSize = sizeof(LocalData); + records[1].localData = &missLocalData; + + records[2].groupIndex = 2; // closest hit group index + records[2].localDataSize = sizeof(LocalData); + records[2].localData = &closestLocalData; + PalShaderBindingTableCreateInfo sbtCreateInfo = {0}; sbtCreateInfo.rayTracingPipeline = pipeline; - sbtCreateInfo.raygenGroupCount = 1; - sbtCreateInfo.missGroupCount = 1; - sbtCreateInfo.hitGroupCount = 1; + sbtCreateInfo.records = records; + sbtCreateInfo.recordCount = 3; result = palCreateShaderBindingTable(device, &sbtCreateInfo, &sbt); if (result != PAL_RESULT_SUCCESS) { From 51b21d8ce8ccb72a25ca64d03f3c4584d4d6ff09 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 10 May 2026 07:59:41 +0000 Subject: [PATCH 211/372] add shader binding table payload (local data) API vulkan --- include/pal/pal_graphics.h | 48 ++- src/graphics/pal_graphics.c | 46 ++- src/graphics/pal_vulkan.c | 318 ++++++++++-------- tests/graphics/ray_tracing_test.c | 188 ++++++++++- .../shaders/bin/spirv/closest_hit.spv | Bin 372 -> 540 bytes tests/graphics/shaders/bin/spirv/miss.spv | Bin 356 -> 540 bytes .../shaders/src/glsl/closest_hit.glsl | 7 +- tests/graphics/shaders/src/glsl/miss.glsl | 7 +- 8 files changed, 466 insertions(+), 148 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index db0411bc..acd6164a 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2436,6 +2436,8 @@ typedef struct { * @brief Information for image to image copies. * * Uninitialized fields may result in undefined behavior. + * + * The records array must be in this order [raygen][miss][hitgroup][callable]. * * @since 1.4 * @ingroup pal_graphics @@ -2665,6 +2667,8 @@ typedef struct { * @brief Creation parameters for a ray tracing pipeline shader group. * * Uninitialized fields may result in undefined behavior. + * + * The shader group array must be in this order [raygen][miss][hitgroup][callable]. * * @since 1.4 * @ingroup pal_graphics @@ -3988,6 +3992,16 @@ typedef struct { * Must obey the rules and semantics documented in palDestroyShaderBindingTable(). */ void PAL_CALL (*destroyShaderBindingTable)(PalShaderBindingTable* sbt); + + /** + * Backend implementation of ::palUpdateShaderBindingTable. + * + * Must obey the rules and semantics documented in palUpdateShaderBindingTable(). + */ + PalResult PAL_CALL (*updateShaderBindingTable)( + PalShaderBindingTable* sbt, + Uint32 count, + PalShaderBindingTableRecordInfo* infos); } PalGraphicsBackend; /** @@ -7286,8 +7300,7 @@ PAL_API PalResult PAL_CALL palCreateComputePipeline( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @note The shader group index will be based on the order of - * PalRayTracingPipelineCreateInfo::shaderGroups. + * @note The shader group array must be in this order [raygen][miss][hitgroup][callable]. * * @since 1.4 * @ingroup pal_graphics @@ -7325,6 +7338,9 @@ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * PalShaderBindingTableCreateInfo::recordCount must match the shader group count of + * PalShaderBindingTableCreateInfo::rayTracingPipeline. * * @param[in] device Device that creates the shader binding table. * @param[in] info Pointer to a PalShaderBindingTableCreateInfo struct that specifies parameters. @@ -7336,6 +7352,8 @@ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. + * + * @note The records array must be in this order [raygen][miss][hitgroup][callable]. * * @since 1.4 * @ingroup pal_graphics @@ -7364,6 +7382,32 @@ PAL_API PalResult PAL_CALL palCreateShaderBindingTable( */ PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); +/** + * @brief Update a shader binding table record payloads. + * + * The graphics system must be initialized before this call. + * + * This call does not update shader handles. It only updates the payload associated + * with the record. PalShaderBindingTableRecordInfo::groupIndex is the index into + * the shader groups used to create the ray tracing pipeline. + * + * @param[in] sbt The shader binding table to update. + * @param[in] count Capacity of the PalShaderBindingTableRecordInfo array. + * @param[in] infos Array of PalShaderBindingTableRecordInfo to update. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `sbt` is externally synchronized. + * + * @since 1.4 + * @ingroup pal_graphics + */ +PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( + PalShaderBindingTable* sbt, + Uint32 count, + PalShaderBindingTableRecordInfo* infos); + /** * @brief Build work group info(s) from work inputs specified in pixels, vertices etc. * diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 52e95c80..7f520b23 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -784,6 +784,11 @@ PalResult PAL_CALL createShaderBindingTableVk( void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt); +PalResult PAL_CALL updateShaderBindingTableVk( + PalShaderBindingTable* sbt, + Uint32 count, + PalShaderBindingTableRecordInfo* infos); + static PalGraphicsBackend s_VkBackend = { // adapter .enumerateAdapters = enumerateAdaptersVk, @@ -961,7 +966,8 @@ static PalGraphicsBackend s_VkBackend = { // shader binding table .createShaderBindingTable = createShaderBindingTableVk, - .destroyShaderBindingTable = destroyShaderBindingTableVk}; + .destroyShaderBindingTable = destroyShaderBindingTableVk, + .updateShaderBindingTable = updateShaderBindingTableVk}; #endif // PAL_HAS_VULKAN @@ -1656,6 +1662,12 @@ PalResult PAL_CALL createShaderBindingTableD3D12( void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); +// TODO: implement +PalResult PAL_CALL updateShaderBindingTableD3D12( + PalShaderBindingTable* sbt, + Uint32 count, + PalShaderBindingTableRecordInfo* infos); + static PalGraphicsBackend s_D3D12Backend = { // adapter .enumerateAdapters = enumerateAdaptersD3D12, @@ -1831,9 +1843,10 @@ static PalGraphicsBackend s_D3D12Backend = { .createRayTracingPipeline = createRayTracingPipelineD3D12, .destroyPipeline = destroyPipelineD3D12, - // shader binding table + // shader binding tables .createShaderBindingTable = createShaderBindingTableD3D12, - .destroyShaderBindingTable = destroyShaderBindingTableD3D12}; + .destroyShaderBindingTable = destroyShaderBindingTableD3D12; + .updateShaderBindingTable = updateShaderBindingTableD3D12}; #endif // PAL_HAS_D3D12 @@ -2041,7 +2054,8 @@ PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) // shader binding table !backend->createShaderBindingTable || - !backend->destroyShaderBindingTable) { + !backend->destroyShaderBindingTable || + !backend->updateShaderBindingTable) { return PAL_RESULT_INVALID_BACKEND; } // clang-format on @@ -4327,6 +4341,10 @@ PalResult PAL_CALL palUpdateDescriptorSet( return PAL_RESULT_NULL_POINTER; } + if (count == 0 && infos) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + return device->backend->updateDescriptorSet(device, count, infos); } @@ -4496,6 +4514,26 @@ void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt) } } +PalResult PAL_CALL palUpdateShaderBindingTable( + PalShaderBindingTable* sbt, + Uint32 count, + PalShaderBindingTableRecordInfo* infos) +{ + if (!s_Graphics.initialized) { + return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + } + + if (!sbt || !infos) { + return PAL_RESULT_NULL_POINTER; + } + + if (count == 0 && infos) { + return PAL_RESULT_INSUFFICIENT_BUFFER; + } + + return sbt->backend->updateShaderBindingTable(sbt, count, infos); +} + // ================================================== // Utils // ================================================== diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 39cf77ba..ddc60c0b 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -494,18 +494,26 @@ typedef struct { VkCommandPool handle; } CommandPool; +typedef struct { + Uint32 startIndex; + Uint32 offset; + VkStridedDeviceAddressRegionKHR region; +} AddressRegion; + typedef struct { const PalGraphicsBackend* backend; + Uint32 handleSize; Device* device; VkBuffer buffer; VkDeviceMemory bufferMemory; VkDeviceAddress baseAddress; + void* pipeline; - VkStridedDeviceAddressRegionKHR raygenAddress; - VkStridedDeviceAddressRegionKHR missAddress; - VkStridedDeviceAddressRegionKHR hitAddress; - VkStridedDeviceAddressRegionKHR callableAddress; + AddressRegion raygen; + AddressRegion miss; + AddressRegion hit; + AddressRegion callable; } ShaderBindingTable; typedef struct { @@ -596,11 +604,6 @@ typedef struct { Uint32 callableCount; } ShaderBindingTableInfo; -typedef struct { - PalShaderStage stage; // used to identify each group - Uint32 index; -} ShaderGroupMap; - typedef struct { const PalGraphicsBackend* backend; @@ -608,7 +611,6 @@ typedef struct { Device* device; VkPipeline handle; VkPipelineLayout layout; - ShaderGroupMap* groupMaps; ShaderBindingTableInfo sbtInfo; } Pipeline; @@ -7511,16 +7513,16 @@ PalResult PAL_CALL cmdTraceRaysVk( } VkStridedDeviceAddressRegionKHR raygenAddress = {0}; - raygenAddress.size = vkSbt->raygenAddress.size; - raygenAddress.stride = vkSbt->raygenAddress.stride; - raygenAddress.deviceAddress = vkSbt->baseAddress + raygenIndex * vkSbt->raygenAddress.stride; + raygenAddress.size = vkSbt->raygen.region.size; + raygenAddress.stride = vkSbt->raygen.region.stride; + raygenAddress.deviceAddress = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; vkCmdBuffer->device->cmdTraceRays( vkCmdBuffer->handle, &raygenAddress, - &vkSbt->missAddress, - &vkSbt->hitAddress, - &vkSbt->callableAddress, + &vkSbt->miss.region, + &vkSbt->hit.region, + &vkSbt->callable.region, width, height, depth); @@ -7546,8 +7548,8 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( return PAL_RESULT_MEMORY_MAP_FAILED; } - PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygenAddress.stride; - vkSbt->raygenAddress.deviceAddress = address; + PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; + vkSbt->raygen.region.deviceAddress = address; VkDeviceAddress bufferAddress = 0; VkBufferDeviceAddressInfoKHR bufferInfo = {0}; @@ -7557,10 +7559,10 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( vkCmdBuffer->device->cmdTraceRaysIndirect( vkCmdBuffer->handle, - &vkSbt->raygenAddress, - &vkSbt->missAddress, - &vkSbt->hitAddress, - &vkSbt->callableAddress, + &vkSbt->raygen.region, + &vkSbt->miss.region, + &vkSbt->hit.region, + &vkSbt->callable.region, bufferAddress); return PAL_RESULT_SUCCESS; @@ -9004,7 +9006,6 @@ PalResult PAL_CALL createGraphicsPipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; pipeline->device = vkDevice; pipeline->layout = layout->handle; - pipeline->groupMaps = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -9049,7 +9050,6 @@ PalResult PAL_CALL createComputePipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; pipeline->device = vkDevice; pipeline->layout = layout->handle; - pipeline->groupMaps = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -9065,7 +9065,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( Pipeline* pipeline = nullptr; VkPipelineShaderStageCreateInfo* shaderStages = nullptr; VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; - ShaderGroupMap* groupMaps = nullptr; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -9079,8 +9078,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( createInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); - groupMaps = palAllocate(s_Vk.allocator, sizeof(ShaderGroupMap) * info->shaderGroupCount, 0); - groups = palAllocate( s_Vk.allocator, sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount, @@ -9091,10 +9088,11 @@ PalResult PAL_CALL createRayTracingPipelineVk( sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount, 0); - if (!pipeline || !groupMaps || !groups || !shaderStages) { + if (!pipeline || !groups || !shaderStages) { return PAL_RESULT_OUT_OF_MEMORY; } + memset(pipeline, 0, sizeof(Pipeline)); // shaders memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount); for (int i = 0; i < info->shaderCount; i++) { @@ -9110,16 +9108,12 @@ PalResult PAL_CALL createRayTracingPipelineVk( createInfo.stageCount = info->shaderCount; createInfo.pStages = shaderStages; - // we always arrange the groups in a specific order so sbt creation becomes simple and layout - // aware already. - // raygen - // miss - // hit - // callable - ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; for (int i = 0; i < info->shaderGroupCount; i++) { + VkRayTracingShaderGroupCreateInfoKHR* group = &groups[i]; PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; + + group->sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { // check if its raygen, miss or callable Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; @@ -9140,48 +9134,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( } } - } else { - sbtInfo->hitCount++; - } - } - - // we compute offsets - Uint32 raygenOffset = 0; // always first - Uint32 missOffset = sbtInfo->raygenCount; - Uint32 hitOffset = missOffset + sbtInfo->missCount; - Uint32 callableOffset = hitOffset + sbtInfo->hitCount; - - // write into backend array with the correct offsets - for (int i = 0; i < info->shaderGroupCount; i++) { - VkRayTracingShaderGroupCreateInfoKHR* group = nullptr; - PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; - - if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { - // check if its raygen, miss or callable - Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; - switch (shader->stage) { - case VK_SHADER_STAGE_RAYGEN_BIT_KHR: { - groupMaps[i].index = raygenOffset; - groupMaps[i].stage = PAL_SHADER_STAGE_RAYGEN; - group = &groups[raygenOffset++]; - break; - } - - case VK_SHADER_STAGE_MISS_BIT_KHR: { - groupMaps[i].index = missOffset; - groupMaps[i].stage = PAL_SHADER_STAGE_MISS; - group = &groups[missOffset++]; - break; - } - - case VK_SHADER_STAGE_CALLABLE_BIT_KHR: { - groupMaps[i].index = callableOffset; - groupMaps[i].stage = PAL_SHADER_STAGE_CALLABLE; - group = &groups[callableOffset++]; - break; - } - } - group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; group->generalShader = tmp->generalShaderIndex; group->anyHitShader = VK_SHADER_UNUSED_KHR; @@ -9189,9 +9141,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( group->intersectionShader = VK_SHADER_UNUSED_KHR; } else { - groupMaps[i].index = hitOffset; - groupMaps[i].stage = PAL_SHADER_STAGE_CLOSEST_HIT; // just for identification - group = &groups[hitOffset++]; + sbtInfo->hitCount++; group->generalShader = VK_SHADER_UNUSED_KHR; if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { @@ -9217,8 +9167,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( group->intersectionShader = VK_SHADER_UNUSED_KHR; } } - - group->sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; } createInfo.pGroups = groups; @@ -9245,7 +9193,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; pipeline->device = vkDevice; pipeline->layout = layout->handle; - pipeline->groupMaps = groupMaps; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -9255,9 +9202,6 @@ void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) Pipeline* vkPipeline = (Pipeline*)pipeline; s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); - if (vkPipeline->groupMaps) { - palFree(s_Vk.allocator, vkPipeline->groupMaps); - } palFree(s_Vk.allocator, pipeline); } @@ -9280,6 +9224,12 @@ PalResult PAL_CALL createShaderBindingTableVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + Uint32 totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; + totalGroups += sbtInfo->missCount + sbtInfo->callableCount; + if (info->recordCount != totalGroups) { + return PAL_RESULT_INVALID_ARGUMENT; + } + sbt = palAllocate(s_Vk.allocator, sizeof(ShaderBindingTable), 0); if (!sbt) { return PAL_RESULT_OUT_OF_MEMORY; @@ -9306,31 +9256,23 @@ PalResult PAL_CALL createShaderBindingTableVk( // get the max local data size for (int i = 0; i < info->recordCount; i++) { PalShaderBindingTableRecordInfo* record = &info->records[i]; - ShaderGroupMap* map = &pipeline->groupMaps[record->groupIndex]; - if (!map) { - return PAL_RESULT_INVALID_ARGUMENT; - } + Uint32 index = record->groupIndex; - switch (map->stage) { - case PAL_SHADER_STAGE_RAYGEN: { - raygenDataSize = maxVk(raygenDataSize, record->localDataSize); - break; - } + if (index < sbtInfo->raygenCount) { + // raygen group + raygenDataSize = maxVk(raygenDataSize, record->localDataSize); - case PAL_SHADER_STAGE_MISS: { - missDataSize = maxVk(missDataSize, record->localDataSize); - break; - } + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { + // miss group + missDataSize = maxVk(missDataSize, record->localDataSize); - case PAL_SHADER_STAGE_CALLABLE: { - callableDataSize = maxVk(callableDataSize, record->localDataSize); - break; - } + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { + // hit group + hitDataSize = maxVk(hitDataSize, record->localDataSize); - case PAL_SHADER_STAGE_CLOSEST_HIT: { - hitDataSize = maxVk(hitDataSize, record->localDataSize); - break; - } + } else { + // callable group + callableDataSize = maxVk(callableDataSize, record->localDataSize); } } @@ -9412,8 +9354,6 @@ PalResult PAL_CALL createShaderBindingTableVk( s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); // get shader group handles - Uint32 totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; - totalGroups += sbtInfo->missCount + sbtInfo->callableCount; Uint32 handlesSize = totalGroups * groupHandleSize; Uint8* handles = palAllocate(s_Vk.allocator, handlesSize, 0); if (!handles) { @@ -9421,7 +9361,6 @@ PalResult PAL_CALL createShaderBindingTableVk( return PAL_RESULT_OUT_OF_MEMORY; } - // handles already in our prefered format result = vkDevice->getRayTracingShaderGroupHandles( vkDevice->handle, pipeline->handle, @@ -9443,66 +9382,107 @@ PalResult PAL_CALL createShaderBindingTableVk( return resultFromVk(result); } - // TODO: finish implementation + offset = 0; // reuse variable + Uint8* srcPtr = (Uint8*)handles; // raygen for (int i = 0; i < sbtInfo->raygenCount; i++) { Uint8* dstPtr = (Uint8*)ptr + (i * raygenStride); - Uint8* srcPtr = (Uint8*)handles + (i * groupHandleSize); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; - memcpy(dstPtr, srcPtr, groupHandleSize); - memcpy(dstPtr + groupHandleSize, info->records[i].localData, info->records[i].localDataSize); + memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } } - srcPtr += raygenRegionSize; + + offset += sbtInfo->raygenCount; + srcPtr += (groupHandleSize * sbtInfo->raygenCount); // miss - for (int i = 0; i < info->missGroupCount; i++) { - memcpy(dstPtr + missOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); + for (int i = 0; i < sbtInfo->missCount; i++) { + Uint8* dstPtr = (Uint8*)ptr + missOffset + (i * missStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } } - srcPtr += missRegionSize; + + offset += sbtInfo->missCount; + srcPtr += (groupHandleSize * sbtInfo->missCount); // hit - for (int i = 0; i < info->hitGroupCount; i++) { - memcpy(dstPtr + hitOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); + for (int i = 0; i < sbtInfo->hitCount; i++) { + Uint8* dstPtr = (Uint8*)ptr + hitOffset + (i * hitStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } } - srcPtr += hitRegionSize; + + offset += sbtInfo->hitCount; + srcPtr += (groupHandleSize * sbtInfo->hitCount); // callable - for (int i = 0; i < info->callableGroupCount; i++) { - memcpy(dstPtr + callableOffset + i * stride, srcPtr + i * groupHandleSize, groupHandleSize); + for (int i = 0; i < sbtInfo->callableCount; i++) { + Uint8* dstPtr = (Uint8*)ptr + callableOffset + (i * callableStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } } - srcPtr += callableRegionSize; s_Vk.unmapMemory(vkDevice->handle, sbt->bufferMemory); - // cache SBT fields and offsets address + //cache SBT fields and offsets address VkBufferDeviceAddressInfo bufferAddressInfo = {0}; bufferAddressInfo.buffer = sbt->buffer; bufferAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; sbt->baseAddress = s_Vk.getBufferDeviceAddress(vkDevice->handle, &bufferAddressInfo); // raygen - sbt->raygenAddress.deviceAddress = sbt->baseAddress; - sbt->raygenAddress.size = raygenAlignedRegionSize; - sbt->raygenAddress.stride = stride; + sbt->raygen.region.deviceAddress = sbt->baseAddress; + sbt->raygen.offset = 0; // always + sbt->raygen.startIndex = 0; // always + sbt->raygen.region.size = raygenRegionSize; + sbt->raygen.region.stride = raygenStride; // miss - sbt->missAddress.deviceAddress = sbt->baseAddress + missOffset; - sbt->missAddress.size = missAlignedRegionSize; - sbt->missAddress.stride = stride; + sbt->miss.offset = missOffset; + sbt->miss.startIndex = sbtInfo->raygenCount; + sbt->miss.region.deviceAddress = sbt->baseAddress + missOffset; + sbt->miss.region.size = missRegionSize; + sbt->miss.region.stride = missStride; // hit - sbt->hitAddress.deviceAddress = sbt->baseAddress + hitOffset; - sbt->hitAddress.size = hitAlignedRegionSize; - sbt->hitAddress.stride = stride; + sbt->hit.offset = hitOffset; + sbt->hit.startIndex = sbtInfo->raygenCount + sbtInfo->missCount; + sbt->hit.region.deviceAddress = sbt->baseAddress + hitOffset; + sbt->hit.region.size = hitRegionSize; + sbt->hit.region.stride = hitStride; // callable - sbt->callableAddress.deviceAddress = sbt->baseAddress + callableOffset; - sbt->callableAddress.size = callableAligneRegionSize; - sbt->callableAddress.stride = stride; + sbt->callable.offset = callableOffset; + sbt->callable.startIndex = sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount; + sbt->callable.region.deviceAddress = sbt->baseAddress + callableOffset; + sbt->callable.region.size = callableRegionSize; + sbt->callable.region.stride = callableStride; palFree(s_Vk.allocator, handles); sbt->device = vkDevice; + sbt->handleSize = groupHandleSize; + sbt->pipeline = pipeline; + *outSbt = (PalShaderBindingTable*)sbt; return PAL_RESULT_SUCCESS; } @@ -9517,4 +9497,68 @@ void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt) palFree(s_Vk.allocator, vkSbt); } +PalResult PAL_CALL updateShaderBindingTableVk( + PalShaderBindingTable* sbt, + Uint32 count, + PalShaderBindingTableRecordInfo* infos) +{ + VkResult result; + ShaderBindingTable* vkSbt = (ShaderBindingTable*)sbt; + Device* vkDevice = vkSbt->device; + Pipeline* pipeline = vkSbt->pipeline; + ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; + + void* data = nullptr; + result = s_Vk.mapMemory(vkDevice->handle, vkSbt->bufferMemory, 0, VK_WHOLE_SIZE, 0, &data); + if (result != VK_SUCCESS) { + return resultFromVk(result); + } + + Uint32 stride = 0; + Uint32 offset = 0; + Uint32 startIndex = 0; + + for (int i = 0; i < count; i++) { + PalShaderBindingTableRecordInfo* info = &infos[i]; + if (!info->localDataSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + // find the group the record belongs to + Uint32 index = info->groupIndex; + if (index < sbtInfo->raygenCount) { + // raygen group + offset = 0; + stride = vkSbt->raygen.region.stride; + startIndex = vkSbt->raygen.startIndex; + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { + // miss group + offset = vkSbt->miss.offset; + stride = vkSbt->miss.region.stride; + startIndex = vkSbt->miss.startIndex; + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { + // hit group + offset = vkSbt->hit.offset; + stride = vkSbt->hit.region.stride; + startIndex = vkSbt->hit.startIndex; + + } else { + // callable group + offset = vkSbt->callable.offset; + stride = vkSbt->callable.region.stride; + startIndex = vkSbt->callable.startIndex; + } + + // write payload + Uint32 localIndex = index - startIndex; + Uint8* dst = (Uint8*)data + offset + (localIndex * stride); + memcpy(dst + vkSbt->handleSize, info->localData, info->localDataSize); + } + + s_Vk.unmapMemory(vkDevice->handle, vkSbt->bufferMemory); + return PAL_RESULT_SUCCESS; +} + #endif // PAL_HAS_VULKAN diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 6f84965c..336fc82b 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -58,7 +58,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -481,6 +481,7 @@ bool rayTracingTest() asInstance.blas = blas; asInstance.instanceId = 0; asInstance.mask = 0xFF; + asInstance.hitGroupOffset = 0; // we only have 1 hitGroup float transform[12] = { 1.0f, 0.0f, 0.0f, 0.0f, @@ -775,19 +776,27 @@ bool rayTracingTest() return false; } + // the shader group array must respect the corect layout + // [raygen][miss][hitGroup][callable] + // [raygen][raygen][miss][hitGroup][hitGroup][callable] + PalRayTracingShaderGroupCreateInfo shaderGroupCreateInfos[3] = {0}; + + // raygen must be packed first always shaderGroupCreateInfos[0].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; shaderGroupCreateInfos[0].generalShaderIndex = 0; shaderGroupCreateInfos[0].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + // miss must be packed second always shaderGroupCreateInfos[1].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; shaderGroupCreateInfos[1].generalShaderIndex = 1; shaderGroupCreateInfos[1].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + // hitGroup must be packed third always shaderGroupCreateInfos[2].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT; shaderGroupCreateInfos[2].closestHitShaderIndex = 2; shaderGroupCreateInfos[2].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; @@ -797,6 +806,8 @@ bool rayTracingTest() // create a ray tracing pipeline PalRayTracingPipelineCreateInfo pipelineCreateInfo = {0}; pipelineCreateInfo.maxRecursionDepth = 1; + pipelineCreateInfo.maxPayloadSize = 16; + pipelineCreateInfo.maxAttributeSize = 8; pipelineCreateInfo.pipelineLayout = pipelineLayout; pipelineCreateInfo.shaderCount = 3; pipelineCreateInfo.shaderGroupCount = 3; @@ -821,11 +832,15 @@ bool rayTracingTest() missLocalData.color[1] = 0.0f; missLocalData.color[2] = 0.0f; - LocalData closestLocalData = {0}; // green color for miss + LocalData closestLocalData; // green color for miss closestLocalData.color[0] = 0.0f; closestLocalData.color[1] = 1.0f; closestLocalData.color[2] = 0.0f; + // the record array must respect the corect layout + // [raygen][miss][hitGroup][callable] + // [raygen][raygen][miss][hitGroup][hitGroup][callable] + PalShaderBindingTableRecordInfo records[3]; records[0].groupIndex = 0; // raygen group index records[0].localDataSize = 0; @@ -835,7 +850,7 @@ bool rayTracingTest() records[1].localDataSize = sizeof(LocalData); records[1].localData = &missLocalData; - records[2].groupIndex = 2; // closest hit group index + records[2].groupIndex = 2; // hit group index records[2].localDataSize = sizeof(LocalData); records[2].localData = &closestLocalData; @@ -1050,6 +1065,173 @@ bool rayTracingTest() } } + // update sbt and trace again + // since we still have the record array we used to create the pipeline + // we just change the underlying data and update the record + + // change miss from black to white + missLocalData.color[0] = 1.0f; + missLocalData.color[1] = 1.0f; + missLocalData.color[2] = 1.0f; + + // change closest hit from green to red + closestLocalData.color[0] = 1.0f; + closestLocalData.color[1] = 0.0f; + closestLocalData.color[2] = 0.0f; + + PalShaderBindingTableRecordInfo updateRecords[2]; + updateRecords[0] = records[1]; // miss + updateRecords[1] = records[2]; // closest hit + + // update records + result = palUpdateShaderBindingTable(sbt, 2, updateRecords); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to update shader binding table: %s", error); + return false; + } + + // we dont need to rebuild the blas or tlas + // we just delete and create the fence again for simplicity + palDestroyFence(fence); + fence = nullptr; + + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + // record commands + result = palCmdBegin(cmdBuffer, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + result = palCmdBindPipeline(cmdBuffer, pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind descriptor set: %s", error); + return false; + } + + // set a barrier on the buffer + newUsageStateInfo.shaderStageCount = 1; + newUsageStateInfo.shaderStages = shaderStages; + newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; + + result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to trace rays: %s", error); + return false; + } + + // set a barrier so we only read from the buffer after the shader has + // written to it + oldUsageStateInfo = newUsageStateInfo; + newUsageStateInfo.shaderStageCount = 0; + newUsageStateInfo.shaderStages = nullptr; + newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; + + result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // set a barrier on the staging buffer + oldUsageStateInfo.shaderStageCount = 0; + oldUsageStateInfo.shaderStages = nullptr; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; + newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + + result = palCmdBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // now we copy from the GPU buffer into the staging buffer + copyInfo.size = bufferBytes; + result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer: %s", error); + return false; + } + + result = palCmdEnd(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // submit the command buffer to the GPU + submitInfo.cmdBuffer = cmdBuffer; + submitInfo.fence = fence; + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // wait for the fence + result = palWaitFence(fence, PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } + + // now our staging buffer has the contents of the GPU buffer + // we map it and copy the contents to a ppm buffer and save it + ptr = nullptr; + result = palMapBufferMemory(stagingBuffer, 0, bufferBytes, &ptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map buffer memory: %s", error); + return false; + } + + // write to a ppm output file + file = fopen("ray_tracing_output2.ppm", "wb"); + fprintf(file, "P6\n%d %d\n255\n", BUFFER_SIZE, BUFFER_SIZE); + pixels = (float*)ptr; + for (int y = 0; y < BUFFER_SIZE; y++) { + int row = BUFFER_SIZE - 1 - y; // flip y + for (int x = 0; x < BUFFER_SIZE; x++) { + int index = row * BUFFER_SIZE + x; + Uint8 rgb[3]; + + rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; + rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; + rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255: 0; + fwrite(rgb, 1, 3, file); + } + } + fclose(file); palUnmapBufferMemory(stagingBuffer); diff --git a/tests/graphics/shaders/bin/spirv/closest_hit.spv b/tests/graphics/shaders/bin/spirv/closest_hit.spv index 3d28d92ecc41b7da990f89103fe9f8720a004094..e243c485a333c74efa07c798d054be03d4c14095 100644 GIT binary patch delta 291 zcmYjMI|{-;6rB8AHHkkII~7uTfq*EaGK~mgp`}E@fH4rfNU-%F9>9Be30uK=VG9=? z^JaG5o86E3uzkx66dVIC>gbjJYN+t)12%x{kX{LBu)H!`?;JR2lEmq4b4v2!$iAjE zwn*|zUJ%9S5zl|VC9G=Jq#pmx1mxv&yC3O$MLuD?OMLSok~h;_c8WG2_bVS@5T}~A o*vpamHc`Cl9vR~>VxlM=mTVE{oGwZ0vP56-1@cwlU+xWAKUQlSnE(I) delta 127 zcmbQk@`Z_)nMs+Qft8Vgn}LIYcOtK^FdM@W5e5bp1_p-Q#LPS(#lShS(0{TFV}PkP zP?!xUzy%To0vMkg%xkdM0m`xi**riDQUem_ntYT|Uc`=pnSm23^Ou2(gcl3?pWynyGh@fw2j!WJ$J zvokyIvmf(e`<59fI0jtQ(JTFEsPO6oHh}b$+(>8;UYTwW4jeQoqNFHxmpIGMKuvoR zjI(Q&lO^Yo)4$vrR#j`#-~81C)a7%39O-vOJ>htl{N^GuZ?3iU6mLN7S2@5SPql9G oE=TIyWXY=g%ov9&P86p@NEb;in38E-Li{B+kgtmVvTsQI00A8wXaE2J delta 111 zcmbQk@`Q<(nMs+Qft8Vgn}LIYXCkk!FdM^B5e5bp1_p-Q#LPS(#lShS(0{TFV}PnQ rP?!xUzy%To0v#Za9Y}KnF-Q!ICm&^$7qMetX5fU%{AFNdumEBJ@e~WD diff --git a/tests/graphics/shaders/src/glsl/closest_hit.glsl b/tests/graphics/shaders/src/glsl/closest_hit.glsl index 626fb050..c91f3f70 100644 --- a/tests/graphics/shaders/src/glsl/closest_hit.glsl +++ b/tests/graphics/shaders/src/glsl/closest_hit.glsl @@ -4,7 +4,12 @@ layout(location = 0) rayPayloadInEXT vec3 payloadColor; +layout(shaderRecordEXT) buffer HitRecord +{ + vec3 color; +} hitRecord; + void main() { - payloadColor = vec3(0.0, 1.0, 0.0); + payloadColor = hitRecord.color; } \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/miss.glsl b/tests/graphics/shaders/src/glsl/miss.glsl index 5fcd6207..e808a762 100644 --- a/tests/graphics/shaders/src/glsl/miss.glsl +++ b/tests/graphics/shaders/src/glsl/miss.glsl @@ -4,7 +4,12 @@ layout(location = 0) rayPayloadInEXT vec3 payloadColor; +layout(shaderRecordEXT) buffer MissRecord +{ + vec3 color; +} missRecord; + void main() { - payloadColor = vec3(0.0); + payloadColor = missRecord.color; } \ No newline at end of file From ec68e26b312c8ef7aac54e6a4849198d6ef19a8b Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 10 May 2026 10:32:24 +0000 Subject: [PATCH 212/372] remove ray shader binding table upload memory only limitation vulkan --- include/pal/pal_graphics.h | 98 +++++++++++++++++--------- src/graphics/pal_d3d12.c | 2 + src/graphics/pal_vulkan.c | 112 +++++++++++++++++++++++++++--- tests/graphics/compute_test.c | 42 ++--------- tests/graphics/ray_tracing_test.c | 73 +++++-------------- 5 files changed, 190 insertions(+), 137 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index acd6164a..d7f2ea99 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -6205,19 +6205,32 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( Uint32 maxDrawCount); /** - * @brief Insert an acceleration structure memory barrier into the command buffer. + * @brief Transition an acceleration structure from one usage state to another. * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * - * The graphics system must be initialized before this call. This functions makes memory invisible - * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. - * - * Example: To make sure an acceleration structure build is completed and memory is visible to the - * raygen shader before it executes, `oldUsageStateInfo.usageState` should be - * `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE` after the build function is called and - * `newUsageStateInfo.usageState` should be `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ` to make - * sure its in read state before its visible to the raygen shader. + * + * The graphics system must be initialized before this call. This function defines a + * dependency between `oldUsageStateInfo` and `newUsageStateInfo`. It ensures that all + * operations performed under `oldUsageStateInfo` are completed and visible before the acceleration + * structure is accessed under `newUsageStateInfo`. + * + * This function does not modify the acceleration structure, it only exforces execution ordering + * and acceleration structure memory visibility. + * + * A barrier is not needed between BLAS and TLAS if there dont shared any resource. If both + * builds use a different scratch buffer, no barrier is needed. + * + * Example: + * + * To make sure BLAS builds before TLAS access it and TLAS does not use scratch buffer + * whilst BLAS is buidling, + * we put a barrier to transition the BLAS to ensure it has finished building and the scratch + * buffer is not being used. This is expressed with oldUsageStateInfo.usageState being + * `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE`. + * + * newUsageStateInfo.usageState should be the new usage state we want after the BLAS + * has finished wbuilding which is `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] as Acceleration structure to set barrier on. @@ -6243,19 +6256,30 @@ PAL_API PalResult PAL_CALL palCmdAccelerationStructureBarrier( PalUsageStateInfo* newUsageStateInfo); /** - * @brief Insert an image memory barrier into the command buffer. + * @brief Transition an image from one usage state to another. * - * The graphics system must be initialized before this call. This functions makes memory invisible - * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. - * - * Example: To make sure an image has been rendered to fully and prepared for presenting, - * `oldUsageStateInfo.usageState` should be `PAL_USAGE_STATE_UNDEFINED` or `PAL_USAGE_STATE_PRESENT` - * depending on the previous state of the image. `newUsageStateInfo.usageState` should be - * `PAL_USAGE_STATE_PRESENT` to make sure its in present state. + * The graphics system must be initialized before this call. This function defines a + * dependency between `oldUsageStateInfo` and `newUsageStateInfo`. It ensures that all + * operations performed under `oldUsageStateInfo` are completed and visible before the image + * is accessed under `newUsageStateInfo`. + * + * This function does not modify the image, it only exforces execution ordering and image memory + * visibility. + * + * Example: + * + * To make sure the an image is ready for presenting after a render pass, + * we put a barrier to transition the image to ensure the render pass has finished writing + * to the image. This is expressed with oldUsageStateInfo.usageState being + * `PAL_USAGE_STATE_COLOR_ATTACHMENT` or `PAL_USAGE_STATE_COLOR_ATTACHMENT` or both set + * after each other. + * + * newUsageStateInfo.usageState should be the new usage state we want after the render pass + * has finished which is `PAL_USAGE_STATE_PRESENT`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] image Image to set barrier on. - * @param[in] subresourceRange Pointer to a PalImageSubresourceRange specifying the image. + * @param[in] subresourceRange Subresource range of the image. * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. * @@ -6266,7 +6290,7 @@ PAL_API PalResult PAL_CALL palCmdAccelerationStructureBarrier( * * @since 1.4 * @ingroup pal_graphics - * @sa palCmdMemoryBarrier + * @sa palCmdAccelerationStructureBarrier * @sa palCmdBufferBarrier */ PAL_API PalResult PAL_CALL palCmdImageBarrier( @@ -6277,16 +6301,26 @@ PAL_API PalResult PAL_CALL palCmdImageBarrier( PalUsageStateInfo* newUsageStateInfo); /** - * @brief Insert a buffer memory barrier into the command buffer. + * @brief Transition a buffer from one usage state to another. * - * The graphics system must be initialized before this call. This functions makes memory invisible - * and blocks access until the usage state specified by `oldUsageStateInfo` is completed. - * - * Example: To make sure a GPU memory buffer has been written to by the shader and ready to be - * copied to a CPU memory buffer, `oldUsageStateInfo.usageState` should be - * `PAL_USAGE_STATE_SHADER_WRITE` and optional `oldUsageStateInfo.shaderStage` set to indicate - * which shader stage will write to the buffer. `newUsageStateInfo.usageState` should be - * `PAL_USAGE_STATE_TRANSFER_READ` to make sure its in read state. + * The graphics system must be initialized before this call. This function defines a + * dependency between `oldUsageStateInfo` and `newUsageStateInfo`. It ensures that all + * operations performed under `oldUsageStateInfo` are completed and visible before the buffer + * is accessed under `newUsageStateInfo`. + * + * This function does not modify the buffer, it only exforces execution ordering and buffer memory + * visibility. + * + * Example: + * + * To read back data from a buffer that will be written to by a shader, + * we put a barrier to transition the buffer to ensurethe shader has finished writing to the + * buffer. This is expressed with oldUsageStateInfo.usageState being `PAL_USAGE_STATE_SHADER_WRITE` + * and optional oldUsageStateInfo.shaderStage set to the shader stage that we will be doing the + * writing. + * + * newUsageStateInfo.usageState should be the new usage state we want after the write + * has finished which is`PAL_USAGE_STATE_TRANSFER_READ`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer to set barrier on. @@ -6300,7 +6334,7 @@ PAL_API PalResult PAL_CALL palCmdImageBarrier( * * @since 1.4 * @ingroup pal_graphics - * @sa palCmdMemoryBarrier + * @sa palCmdAccelerationStructureBarrier * @sa palCmdImageBarrier */ PAL_API PalResult PAL_CALL palCmdBufferBarrier( @@ -6444,9 +6478,6 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * `PAL_ADAPTER_FEATURE_RAY_TRACING` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported * and enabled by the device if not, this function will fail and return * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * - * If buffer memory type is not `PAL_MEMORY_TYPE_CPU_UPLOAD`, this function will fail and return - * `PAL_RESULT_MEMORY_MAP_FAILED`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] raygenIndex Index of the raygen shader to execute. @@ -6458,7 +6489,6 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @note The memory associated with the buffer must be `PAL_MEMORY_TYPE_CPU_UPLOAD`. * @note A pipeline must be bound before this call. * * @since 1.4 diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 4d08860a..5cd7648a 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -5833,6 +5833,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + // TODO: remove upload memory requirement, check and copy according to buffer memory type // get width, height and depth from provided buffer void* ptr = nullptr; HRESULT result = d3dBuffer->handle->lpVtbl->Map(d3dBuffer->handle, 0, nullptr, &ptr); @@ -7937,6 +7938,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + // TODO: create both a GPU only and UPLOAD buffers void** raygenHandles = nullptr; void** missHandles = nullptr; void** hitHandles = nullptr; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index ddc60c0b..e4b1111d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -503,10 +503,14 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + bool isDirty; + Uint32 stagingBufferSize; Uint32 handleSize; Device* device; VkBuffer buffer; + VkBuffer stagingBuffer; VkDeviceMemory bufferMemory; + VkDeviceMemory stagingBufferMemory; VkDeviceAddress baseAddress; void* pipeline; @@ -2568,6 +2572,42 @@ static VkGeometryInstanceFlagsKHR instanceFlagsToVk(PalAccelerationStructureInst return instanceFlags; } +static void commitShaderbindingTableUpdate( + CommandBuffer* cmdBuffer, + ShaderBindingTable* sbt) +{ + if (!sbt->isDirty) { + return; + } + + // begin upload buffer copy to gpu buffer + VkBufferCopy copyRegion = {0}; + copyRegion.size = sbt->stagingBufferSize; + s_Vk.cmdCopyBuffer(cmdBuffer->handle, sbt->stagingBuffer, sbt->buffer, 1, ©Region); + + // put a memory barrier + VkBufferMemoryBarrier2KHR barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; + + barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR; + barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; + + barrier.dstStageMask = VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; + barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT_KHR; + + barrier.buffer = sbt->buffer; + barrier.offset = 0; + barrier.size = VK_WHOLE_SIZE; + + VkDependencyInfo dependencyInfo = {0}; + dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependencyInfo.bufferMemoryBarrierCount = 1; + dependencyInfo.pBufferMemoryBarriers = &barrier; + + cmdBuffer->device->cmdPipelineBarrier(cmdBuffer->handle, &dependencyInfo); + sbt->isDirty = false; +} + // ================================================== // Adapter // ================================================== @@ -7517,6 +7557,9 @@ PalResult PAL_CALL cmdTraceRaysVk( raygenAddress.stride = vkSbt->raygen.region.stride; raygenAddress.deviceAddress = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; + // we need to make sure the SBT is up to date + commitShaderbindingTableUpdate(vkCmdBuffer, vkSbt); + vkCmdBuffer->device->cmdTraceRays( vkCmdBuffer->handle, &raygenAddress, @@ -7544,10 +7587,6 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - if (vkBuffer->memory->type != PAL_MEMORY_TYPE_CPU_UPLOAD) { - return PAL_RESULT_MEMORY_MAP_FAILED; - } - PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; vkSbt->raygen.region.deviceAddress = address; @@ -7557,6 +7596,9 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; bufferAddress = vkBuffer->device->getBufferrAddress(vkBuffer->device->handle, &bufferInfo); + // we need to make sure the SBT is up to date + commitShaderbindingTableUpdate(vkCmdBuffer, vkSbt); + vkCmdBuffer->device->cmdTraceRaysIndirect( vkCmdBuffer->handle, &vkSbt->raygen.region, @@ -9310,12 +9352,12 @@ PalResult PAL_CALL createShaderBindingTableVk( Uint32 bufferSize = alignVk(offset, groupBaseAlignment); // create gpu buffer - // TODO: create both a GPU only and UPLOAD buffers VkBufferCreateInfo bufCreateInfo = {0}; bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufCreateInfo.size = bufferSize; bufCreateInfo.usage = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR; bufCreateInfo.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; + bufCreateInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); @@ -9324,6 +9366,20 @@ PalResult PAL_CALL createShaderBindingTableVk( return resultFromVk(result); } + // create staging buffer + bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + sbt->stagingBufferSize = bufferSize; + result = s_Vk.createBuffer( + vkDevice->handle, + &bufCreateInfo, + &s_Vk.vkAllocator, + &sbt->stagingBuffer); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, sbt); + return resultFromVk(result); + } + // allocate CPU upload memory and bind VkMemoryRequirements memReq = {0}; s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->buffer, &memReq); @@ -9332,7 +9388,7 @@ PalResult PAL_CALL createShaderBindingTableVk( allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memReq.size; - Uint32 mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] & memReq.memoryTypeBits; + Uint32 mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; Uint32 memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); allocateInfo.memoryTypeIndex = memoryIndex; @@ -9351,7 +9407,29 @@ PalResult PAL_CALL createShaderBindingTableVk( palFree(s_Vk.allocator, sbt); return resultFromVk(result); } + + // allocate memory for staging buffer + s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->stagingBuffer, &memReq); + allocateInfo.allocationSize = memReq.size; + + mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] & memReq.memoryTypeBits; + memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + allocateInfo.memoryTypeIndex = memoryIndex; + allocateInfo.pNext = nullptr; // we dont need the address + + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &sbt->stagingBufferMemory); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, sbt); + return resultFromVk(result); + } + s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); + s_Vk.bindBufferMemory(vkDevice->handle, sbt->stagingBuffer, sbt->stagingBufferMemory, 0); // get shader group handles Uint32 handlesSize = totalGroups * groupHandleSize; @@ -9376,7 +9454,7 @@ PalResult PAL_CALL createShaderBindingTableVk( // copy handles into the buffer void* ptr = nullptr; - result = s_Vk.mapMemory(vkDevice->handle, sbt->bufferMemory, 0, memReq.size, 0, &ptr); + result = s_Vk.mapMemory(vkDevice->handle, sbt->stagingBufferMemory, 0, VK_WHOLE_SIZE, 0, &ptr); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, sbt); return resultFromVk(result); @@ -9442,9 +9520,10 @@ PalResult PAL_CALL createShaderBindingTableVk( } } - s_Vk.unmapMemory(vkDevice->handle, sbt->bufferMemory); + s_Vk.unmapMemory(vkDevice->handle, sbt->stagingBufferMemory); - //cache SBT fields and offsets address + // cache SBT fields and offsets address + // we know the layout so we can prepare the strided address before we copy to the gpu buffer VkBufferDeviceAddressInfo bufferAddressInfo = {0}; bufferAddressInfo.buffer = sbt->buffer; bufferAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; @@ -9483,6 +9562,7 @@ PalResult PAL_CALL createShaderBindingTableVk( sbt->handleSize = groupHandleSize; sbt->pipeline = pipeline; + sbt->isDirty = true; // we need to copy from the staging to the gpu buffer *outSbt = (PalShaderBindingTable*)sbt; return PAL_RESULT_SUCCESS; } @@ -9493,7 +9573,9 @@ void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt) Device* device = vkSbt->device; s_Vk.destroyBuffer(device->handle, vkSbt->buffer, &s_Vk.vkAllocator); + s_Vk.destroyBuffer(device->handle, vkSbt->stagingBuffer, &s_Vk.vkAllocator); s_Vk.freeMemory(device->handle, vkSbt->bufferMemory, &s_Vk.vkAllocator); + s_Vk.freeMemory(device->handle, vkSbt->stagingBufferMemory, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkSbt); } @@ -9509,7 +9591,14 @@ PalResult PAL_CALL updateShaderBindingTableVk( ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; void* data = nullptr; - result = s_Vk.mapMemory(vkDevice->handle, vkSbt->bufferMemory, 0, VK_WHOLE_SIZE, 0, &data); + result = s_Vk.mapMemory( + vkDevice->handle, + vkSbt->stagingBufferMemory, + 0, + VK_WHOLE_SIZE, + 0, + &data); + if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -9557,7 +9646,8 @@ PalResult PAL_CALL updateShaderBindingTableVk( memcpy(dst + vkSbt->handleSize, info->localData, info->localDataSize); } - s_Vk.unmapMemory(vkDevice->handle, vkSbt->bufferMemory); + s_Vk.unmapMemory(vkDevice->handle, vkSbt->stagingBufferMemory); + vkSbt->isDirty = true; return PAL_RESULT_SUCCESS; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 90dcf2c9..b6ba372a 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -493,20 +493,6 @@ bool computeTest() palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, workGroupInfos); - // set a barrier on the buffer - PalUsageStateInfo oldUsageStateInfo = {0}; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStageCount = 1; - newUsageStateInfo.shaderStages = shaderStages; - newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; - - result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; - } - // dispatch with the work group info for (int i = 0; i < workGroupInfoCount; i++) { // palDispatchBase is not supported on all platforms so we dont use it for this example @@ -525,9 +511,13 @@ bool computeTest() } palFree(nullptr, workGroupInfos); - // set a barrier so we only read from the buffer after the shader has - // written to it - oldUsageStateInfo = newUsageStateInfo; + // set a barrier so we only read from the buffer after the shader has written to it + PalUsageStateInfo oldUsageStateInfo = {0}; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; + oldUsageStateInfo.shaderStageCount = 0; + oldUsageStateInfo.shaderStages = nullptr; + + PalUsageStateInfo newUsageStateInfo = {0}; newUsageStateInfo.shaderStageCount = 0; newUsageStateInfo.shaderStages = nullptr; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; @@ -539,19 +529,6 @@ bool computeTest() return false; } - // set a barrier on the staging buffer - oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - oldUsageStateInfo.shaderStageCount = 0; - oldUsageStateInfo.shaderStages = nullptr; - newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - - result = palCmdBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; - } - // now we copy from the GPU buffer into the staging buffer PalBufferCopyInfo copyInfo = {0}; copyInfo.size = bufferBytes; @@ -563,11 +540,6 @@ bool computeTest() return false; } - // if we want to copy to the ppm buffer in the command buffer - // we need a barrier to with the state PAL_USAGE_STATE_HOST_READ - // but we map and copy outside the command buffer since - // we wait for a fence (the command buffer has been executed). - result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 336fc82b..c483f360 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -58,7 +58,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -896,20 +896,6 @@ bool rayTracingTest() return false; } - // set a barrier on the buffer - PalUsageStateInfo oldUsageStateInfo = {0}; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStageCount = 1; - newUsageStateInfo.shaderStages = shaderStages; - newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; - - result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; - } - // build the blas and tlas infos PalDeviceAddress scratchBufferAddress = palGetBufferDeviceAddress(scratchBuffer); blasBuildInfo.dst = blas; @@ -925,7 +911,8 @@ bool rayTracingTest() return false; } - // make sure the BLAS builds before the TLAS + // make sure the BLAS builds before the TLAS. We need this barrier because + // BLAS and TLAS share the same scratch buffer PalUsageStateInfo oldAsUsageStateInfo = {0}; oldAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; @@ -974,9 +961,12 @@ bool rayTracingTest() return false; } - // set a barrier so we only read from the buffer after the shader has - // written to it - oldUsageStateInfo = newUsageStateInfo; + // set a barrier so we only read from the buffer after the shader has written to it + PalUsageStateInfo oldUsageStateInfo = {0}; + oldUsageStateInfo.shaderStageCount = 0; + oldUsageStateInfo.shaderStages = nullptr; + + PalUsageStateInfo newUsageStateInfo = {0}; newUsageStateInfo.shaderStageCount = 0; newUsageStateInfo.shaderStages = nullptr; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; @@ -988,19 +978,6 @@ bool rayTracingTest() return false; } - // set a barrier on the staging buffer - oldUsageStateInfo.shaderStageCount = 0; - oldUsageStateInfo.shaderStages = nullptr; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - - result = palCmdBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; - } - // now we copy from the GPU buffer into the staging buffer PalBufferCopyInfo copyInfo = {0}; copyInfo.size = bufferBytes; @@ -1125,7 +1102,12 @@ bool rayTracingTest() return false; } - // set a barrier on the buffer + // the previous trace transitioned the buffer to transfer read + // we need it back to shader write before transfer read + oldUsageStateInfo.shaderStageCount = 0; + oldUsageStateInfo.shaderStages = nullptr; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; + newUsageStateInfo.shaderStageCount = 1; newUsageStateInfo.shaderStages = shaderStages; newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; @@ -1144,7 +1126,7 @@ bool rayTracingTest() return false; } - // set a barrier so we only read from the buffer after the shader has + // set a barrier to transition to transfer read so we can read from it after shader has // written to it oldUsageStateInfo = newUsageStateInfo; newUsageStateInfo.shaderStageCount = 0; @@ -1158,19 +1140,6 @@ bool rayTracingTest() return false; } - // set a barrier on the staging buffer - oldUsageStateInfo.shaderStageCount = 0; - oldUsageStateInfo.shaderStages = nullptr; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_UNDEFINED; - newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - - result = palCmdBufferBarrier(cmdBuffer, stagingBuffer, &oldUsageStateInfo, &newUsageStateInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; - } - // now we copy from the GPU buffer into the staging buffer copyInfo.size = bufferBytes; result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); @@ -1205,16 +1174,6 @@ bool rayTracingTest() return false; } - // now our staging buffer has the contents of the GPU buffer - // we map it and copy the contents to a ppm buffer and save it - ptr = nullptr; - result = palMapBufferMemory(stagingBuffer, 0, bufferBytes, &ptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; - } - // write to a ppm output file file = fopen("ray_tracing_output2.ppm", "wb"); fprintf(file, "P6\n%d %d\n255\n", BUFFER_SIZE, BUFFER_SIZE); From bc92358d2674751f68da3cd7b9fdc7c1d7c2b6e8 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 11 May 2026 05:33:41 +0000 Subject: [PATCH 213/372] remove ray shader binding table upload memory only limitation d3d12 --- include/pal/pal_graphics.h | 8 +- src/graphics/pal_d3d12.c | 657 +++++++++++++++++++++--------- src/graphics/pal_graphics.c | 3 +- src/graphics/pal_vulkan.c | 155 +++++-- tests/graphics/mesh_test.c | 1 + tests/graphics/ray_tracing_test.c | 3 +- 6 files changed, 589 insertions(+), 238 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d7f2ea99..fa2ab204 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -6475,9 +6475,8 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported - * and enabled by the device if not, this function will fail and return - * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, + * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] raygenIndex Index of the raygen shader to execute. @@ -6489,6 +6488,9 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * + * @note The argument buffer memory must not be `PAL_MEMORY_TYPE_GPU_ONLY`. The implementation + * internally copies the data into a GPU buffer for execution. + * * @note A pipeline must be bound before this call. * * @since 1.4 diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 5cd7648a..f058bd37 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -256,19 +256,13 @@ typedef struct { ID3D12Fence* handle; } Fence, Semaphore; -typedef struct { - Uint32 tmpIndex; - Uint32 patchControlPoints; - PalShaderStage stage; - wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; -} ShaderEntry; - typedef struct { const PalGraphicsBackend* backend; - Uint32 entryCount; - ShaderEntry* entries; + Uint32 patchControlPoints; + PalShaderStage stage; D3D12_SHADER_BYTECODE byteCode; + wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; } Shader; typedef struct { @@ -277,7 +271,8 @@ typedef struct { bool primary; void* pool; // CommandPool Device* device; - ID3D12Resource* tmpBuffer; + ID3D12Resource* stagingBuffer; + ID3D12Resource* buffer; ID3D12CommandAllocator* allocator; void* pipeline; ID3D12GraphicsCommandList6* handle; @@ -332,6 +327,18 @@ typedef struct { D3D12_HIT_GROUP_DESC desc; } RayHitGroup; +typedef struct { + D3D12_EXPORT_DESC export; + D3D12_DXIL_LIBRARY_DESC library; +} RayShaderLibary; + +typedef struct { + Uint32 raygenCount; + Uint32 missCount; + Uint32 hitCount; + Uint32 callableCount; +} ShaderBindingTableInfo; + typedef struct { const PalGraphicsBackend* backend; @@ -344,17 +351,30 @@ typedef struct { ShaderExport* shaderExports; PipelineLayout* layout; D3D12_SHADING_RATE_COMBINER combinerOps[2]; + ShaderBindingTableInfo sbtInfo; } Pipeline; +typedef struct { + Uint32 startIndex; + Uint32 offset; + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE region; +} AddressRegion; + typedef struct { const PalGraphicsBackend* backend; + bool isDirty; + Uint32 stagingBufferSize; + Uint32 handleSize; ID3D12Resource* buffer; + ID3D12Resource* stagingBuffer; D3D12_GPU_VIRTUAL_ADDRESS baseAddress; - D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress; - D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE missAddress; - D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE hitAddress; - D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE callableAddress; + Pipeline* pipeline; + + AddressRegion raygen; + AddressRegion miss; + AddressRegion hit; + AddressRegion callable; } ShaderBindingTable; typedef struct { @@ -1958,6 +1978,35 @@ static const char* semanticIDToStringD3D12(PalVertexSemanticID id) return nullptr; } +static void commitShaderbindingTableUpdateD3D12( + CommandBuffer* cmdBuffer, + ShaderBindingTable* sbt) +{ + if (!sbt->isDirty) { + return; + } + + // begin upload buffer copy to gpu buffer + cmdBuffer->handle->lpVtbl->CopyBufferRegion( + cmdBuffer->handle, + sbt->buffer, + 0, + sbt->stagingBuffer, + 0, + sbt->stagingBufferSize); + + // put a memory barrier + D3D12_RESOURCE_BARRIER barrier = {0}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.pResource = sbt->buffer; + + cmdBuffer->handle->lpVtbl->ResourceBarrier(cmdBuffer->handle, 1, &barrier); + sbt->isDirty = false; +} + // ================================================== // Adapter // ================================================== @@ -4178,42 +4227,33 @@ PalResult PAL_CALL createShaderD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - shader->entries = palAllocate(s_D3D.allocator, sizeof(ShaderEntry) * info->entryCount, 0); - if (!shader->entries) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - for (int i = 0; i < info->entryCount; i++) { - ShaderEntry* entry = &shader->entries[i]; - convertToWcharD3D12(info->entries[i].entryName, entry->entryName); - entry->patchControlPoints = info->entries[i].patchControlPoints; - entry->stage = info->entries[i].stage; - - if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || - info->entries[i].stage == PAL_SHADER_STAGE_TASK) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + if (info->stage == PAL_SHADER_STAGE_MESH || + info->stage == PAL_SHADER_STAGE_TASK) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } - // clang-format off - } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || - info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_MISS || - info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || - info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + // clang-format off + } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || + info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || + info->stage == PAL_SHADER_STAGE_ANY_HIT || + info->stage == PAL_SHADER_STAGE_MISS || + info->stage == PAL_SHADER_STAGE_INTERSECTION || + info->stage == PAL_SHADER_STAGE_CALLABLE) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // clang-format on } + // clang-format on + + convertToWcharD3D12(info->entryName, shader->entryName); + shader->patchControlPoints = info->patchControlPoints; + shader->stage = info->stage; memcpy(bytecode, info->bytecode, info->bytecodeSize); shader->byteCode.pShaderBytecode = bytecode; shader->byteCode.BytecodeLength = info->bytecodeSize; - shader->entryCount = info->entryCount; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } @@ -4222,7 +4262,6 @@ void PAL_CALL destroyShaderD3D12(PalShader* shader) { Shader* d3dShader = (Shader*)shader; palFree(s_D3D.allocator, (void*)d3dShader->byteCode.pShaderBytecode); - palFree(s_D3D.allocator, d3dShader->entries); palFree(s_D3D.allocator, d3dShader); } @@ -4597,35 +4636,57 @@ PalResult PAL_CALL allocateCommandBufferD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - // we need a tmp upload buffer if ray tracing is enabled - D3D12_HEAP_PROPERTIES heapProps = {0}; - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - heapProps.VisibleNodeMask = 1; - heapProps.CreationNodeMask = 1; + // we need a tmp staging and gpu buffer if ray tracing is enabled + if (d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + D3D12_HEAP_PROPERTIES heapProps = {0}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.VisibleNodeMask = 1; + heapProps.CreationNodeMask = 1; - D3D12_RESOURCE_DESC bufferDesc = {0}; - bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - bufferDesc.Width = sizeof(D3D12_DISPATCH_RAYS_DESC); - bufferDesc.Height = 1; - bufferDesc.DepthOrArraySize = 1; - bufferDesc.MipLevels = 1; - bufferDesc.SampleDesc.Count = 1; - bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + D3D12_RESOURCE_DESC bufferDesc = {0}; + bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + bufferDesc.Width = sizeof(D3D12_DISPATCH_RAYS_DESC); + bufferDesc.Height = 1; + bufferDesc.DepthOrArraySize = 1; + bufferDesc.MipLevels = 1; + bufferDesc.SampleDesc.Count = 1; + bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - result = d3dDevice->handle->lpVtbl->CreateCommittedResource( - d3dDevice->handle, - &heapProps, - 0, - &bufferDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - &IID_Resource, (void**)&cmdBuffer->tmpBuffer); + result = d3dDevice->handle->lpVtbl->CreateCommittedResource( + d3dDevice->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + &IID_Resource, + (void**)&cmdBuffer->buffer); - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + // create staging buffer + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + result = d3dDevice->handle->lpVtbl->CreateCommittedResource( + d3dDevice->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + &IID_Resource, + (void**)&cmdBuffer->stagingBuffer); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; } - return PAL_RESULT_PLATFORM_FAILURE; } cmdList->lpVtbl->QueryInterface( @@ -4650,9 +4711,13 @@ void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) if (data) { d3dCmdBuffer->handle->lpVtbl->Release(d3dCmdBuffer->handle); d3dCmdBuffer->allocator->lpVtbl->Release(d3dCmdBuffer->allocator); - d3dCmdBuffer->tmpBuffer->lpVtbl->Release(d3dCmdBuffer->tmpBuffer); - palFree(s_D3D.allocator, cmdBuffer); + if (d3dCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + d3dCmdBuffer->buffer->lpVtbl->Release(d3dCmdBuffer->buffer); + d3dCmdBuffer->stagingBuffer->lpVtbl->Release(d3dCmdBuffer->stagingBuffer); + } + + palFree(s_D3D.allocator, cmdBuffer); data->cmdBuffer = nullptr; data->used = false; } @@ -5799,19 +5864,22 @@ PalResult PAL_CALL cmdTraceRaysD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Uint32 stride = d3dSbt->hitAddress.StrideInBytes; // same for raygen + Uint32 stride = d3dSbt->raygen.region.StrideInBytes; D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; - raygenAddress.SizeInBytes = d3dSbt->raygenAddress.SizeInBytes; + raygenAddress.SizeInBytes = d3dSbt->raygen.region.SizeInBytes; raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * stride; + // we need to make sure the SBT is up to date + commitShaderbindingTableUpdateD3D12(d3dCmdBuffer, d3dSbt); + D3D12_DISPATCH_RAYS_DESC desc = {0}; desc.Width = width; desc.Height = height; desc.Depth = depth; desc.RayGenerationShaderRecord = raygenAddress; - desc.HitGroupTable = d3dSbt->hitAddress; - desc.MissShaderTable = d3dSbt->missAddress; - desc.CallableShaderTable = d3dSbt->callableAddress; + desc.HitGroupTable = d3dSbt->hit.region; + desc.MissShaderTable = d3dSbt->miss.region; + desc.CallableShaderTable = d3dSbt->callable.region; d3dCmdBuffer->handle->lpVtbl->DispatchRays(d3dCmdBuffer->handle, &desc); return PAL_RESULT_SUCCESS; @@ -5823,6 +5891,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalShaderBindingTable* sbt, PalBuffer* buffer) { + HRESULT result; CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; Buffer* d3dBuffer = (Buffer*)buffer; @@ -5833,14 +5902,17 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // TODO: remove upload memory requirement, check and copy according to buffer memory type - // get width, height and depth from provided buffer + // we need to make sure the SBT is up to date + commitShaderbindingTableUpdateD3D12(d3dCmdBuffer, d3dSbt); + + // Buffer is mappable void* ptr = nullptr; - HRESULT result = d3dBuffer->handle->lpVtbl->Map(d3dBuffer->handle, 0, nullptr, &ptr); + result = d3dBuffer->handle->lpVtbl->Map(d3dBuffer->handle, 0, nullptr, &ptr); if (FAILED(result)) { return PAL_RESULT_MEMORY_MAP_FAILED; } + // copy indirect parameters from the buffer PalDispatchIndirectData data = {0}; memcpy(&data, ptr, sizeof(PalDispatchIndirectData)); d3dBuffer->handle->lpVtbl->Unmap(d3dBuffer->handle, 0, nullptr); @@ -5849,27 +5921,45 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( desc.Height = data.groupCountXOrHeight; desc.Depth = data.groupCountXOrDepth; - Uint32 stride = d3dSbt->hitAddress.StrideInBytes; // same for raygen + Uint32 stride = d3dSbt->raygen.region.StrideInBytes; D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; - raygenAddress.SizeInBytes = d3dSbt->raygenAddress.SizeInBytes; + raygenAddress.SizeInBytes = d3dSbt->raygen.region.SizeInBytes; raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * stride; desc.RayGenerationShaderRecord = raygenAddress; - desc.HitGroupTable = d3dSbt->hitAddress; - desc.MissShaderTable = d3dSbt->missAddress; - desc.CallableShaderTable = d3dSbt->callableAddress; + desc.HitGroupTable = d3dSbt->hit.region; + desc.MissShaderTable = d3dSbt->miss.region; + desc.CallableShaderTable = d3dSbt->callable.region; // fill the data into the tmp upload buffer of the command buffer ptr = nullptr; - d3dCmdBuffer->tmpBuffer->lpVtbl->Map(d3dCmdBuffer->tmpBuffer, 0, nullptr, &ptr); + d3dCmdBuffer->stagingBuffer->lpVtbl->Map(d3dCmdBuffer->stagingBuffer, 0, nullptr, &ptr); memcpy(ptr, &desc, sizeof(D3D12_DISPATCH_RAYS_DESC)); - d3dCmdBuffer->tmpBuffer->lpVtbl->Unmap(d3dCmdBuffer->tmpBuffer, 0, nullptr); + d3dCmdBuffer->stagingBuffer->lpVtbl->Unmap(d3dCmdBuffer->stagingBuffer, 0, nullptr); + + // copy to the gpu tmp buffer of the command buffer and execute with that + d3dCmdBuffer->handle->lpVtbl->CopyBufferRegion( + d3dCmdBuffer->handle, + d3dCmdBuffer->buffer, + 0, + d3dCmdBuffer->stagingBuffer, + 0, + sizeof(D3D12_DISPATCH_RAYS_DESC)); + + // put a memory barrier + D3D12_RESOURCE_BARRIER barrier = {0}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.pResource = d3dCmdBuffer->buffer; + d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( d3dCmdBuffer->handle, device->raySignature, 1, - d3dCmdBuffer->tmpBuffer, + d3dCmdBuffer->buffer, 0, nullptr, 0); @@ -7222,31 +7312,30 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( totalSize += sizeof(ShaderStream); D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - ShaderEntry* entry = &tmp->entries[0]; - if (entry->patchControlPoints) { - patchControlPoints = entry->patchControlPoints; + if (tmp->patchControlPoints) { + patchControlPoints = tmp->patchControlPoints; if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { palFree(s_D3D.allocator, pipeline); return PAL_RESULT_INVALID_OPERATION; } } - if (entry->stage == PAL_SHADER_STAGE_VERTEX) { + if (tmp->stage == PAL_SHADER_STAGE_VERTEX) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS; - } else if (entry->stage == PAL_SHADER_STAGE_FRAGMENT) { + } else if (tmp->stage == PAL_SHADER_STAGE_FRAGMENT) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS; - } else if (entry->stage == PAL_SHADER_STAGE_GEOMETRY) { + } else if (tmp->stage == PAL_SHADER_STAGE_GEOMETRY) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS; - } else if (entry->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { + } else if (tmp->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS; - } else if (entry->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + } else if (tmp->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS; - } else if (entry->stage == PAL_SHADER_STAGE_TASK) { + } else if (tmp->stage == PAL_SHADER_STAGE_TASK) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS; } else { @@ -7695,10 +7784,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( PalPipeline** outPipeline) { HRESULT result; - Uint32 exportOffset = 0; - Uint32 exportCount = 0; Uint32 hitGroupIndex = 0; - Uint32 hitGroupCount = 0; Uint32 subObjectIndex = 0; // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG @@ -7709,10 +7795,10 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; Pipeline* pipeline = nullptr; - D3D12_DXIL_LIBRARY_DESC* libraries = nullptr; + RayShaderLibary* libraries = nullptr; RayHitGroup* groups = nullptr; D3D12_STATE_SUBOBJECT* subObjects = nullptr; - D3D12_EXPORT_DESC* exportDesc = nullptr; + ShaderExport* exports = nullptr; if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -7730,18 +7816,31 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_INVALID_ARGUMENT; } - // Every entry is a shader export - for (int i = 0; i < info->shaderCount; i++) { - Shader* tmp = (Shader*)info->shaders[i]; - exportCount += tmp->entryCount; - } - + ShaderBindingTableInfo sbtInfo = {0}; for (int i = 0; i < info->shaderGroupCount; i++) { PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { - continue; + // check if its raygen, miss or callable + Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; + switch (shader->stage) { + case PAL_SHADER_STAGE_RAYGEN: { + sbtInfo.raygenCount++; + break; + } + + case PAL_SHADER_STAGE_MISS: { + sbtInfo.missCount++; + break; + } + + case PAL_SHADER_STAGE_CALLABLE: { + sbtInfo.callableCount++; + break; + } + } } - hitGroupCount++; + + sbtInfo.hitCount++; subObjectCount++; } @@ -7750,43 +7849,34 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - pipeline->shaderExports = palAllocate(s_D3D.allocator, sizeof(ShaderExport) * exportCount, 0); - exportDesc = palAllocate(s_D3D.allocator, sizeof(D3D12_EXPORT_DESC) * exportCount, 0); subObjects = palAllocate(s_D3D.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); - groups = palAllocate(s_D3D.allocator, sizeof(RayHitGroup) * hitGroupCount, 0); - - libraries = palAllocate( - s_D3D.allocator, - sizeof(D3D12_DXIL_LIBRARY_DESC) * info->shaderCount, - 0); + groups = palAllocate(s_D3D.allocator, sizeof(RayHitGroup) * sbtInfo.hitCount, 0); + libraries = palAllocate(s_D3D.allocator, sizeof(RayShaderLibary) * info->shaderCount, 0); + exports = palAllocate(s_D3D.allocator, sizeof(ShaderExport) * info->shaderCount, 0); - if (!pipeline->shaderExports || !exportDesc || !groups || !subObjects || !libraries) { + if (!exports || !groups || !subObjects || !libraries) { return PAL_RESULT_OUT_OF_MEMORY; } // shaders for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; - D3D12_DXIL_LIBRARY_DESC* library = &libraries[i]; + RayShaderLibary* shaderLibrary = &libraries[i]; + ShaderExport* export = &exports[i]; - for (int j = 0; j < tmp->entryCount; j++) { - ShaderEntry* entry = &tmp->entries[j]; - ShaderExport* shaderExport = &pipeline->shaderExports[exportOffset + j]; - shaderExport->stage = entry->stage; - wcscpy(shaderExport->entryName, entry->entryName); + export->stage = tmp->stage; + wcscpy(export->entryName, tmp->entryName); - exportDesc[exportOffset + j].Flags = D3D12_EXPORT_FLAG_NONE; - exportDesc[exportOffset + j].ExportToRename = nullptr; - exportDesc[exportOffset + j].Name = shaderExport->entryName; // reference - } + shaderLibrary->export.Flags = D3D12_EXPORT_FLAG_NONE; + shaderLibrary->export.ExportToRename = nullptr; + shaderLibrary->export.Name = export->entryName; // reference - library->DXILLibrary = tmp->byteCode; - library->NumExports = tmp->entryCount; - libraries->pExports = &exportDesc[exportOffset]; - exportOffset += tmp->entryCount; + shaderLibrary->library.DXILLibrary = tmp->byteCode; + shaderLibrary->library.NumExports = 1; + shaderLibrary->library.pExports = &shaderLibrary->export; subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; - subObjects[subObjectIndex].pDesc = library; + subObjects[subObjectIndex].pDesc = &shaderLibrary->library; subObjectIndex++; } @@ -7815,8 +7905,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // Any hit shader if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->anyHitShaderIndex]; - ShaderEntry* entry = &shader->entries[tmp->anyHitEntryIndex]; - group->AnyHitShaderImport = entry->entryName; + group->AnyHitShaderImport = shader->entryName; } else { group->AnyHitShaderImport = nullptr; @@ -7825,8 +7914,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // Closest hit shader if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->closestHitShaderIndex]; - ShaderEntry* entry = &shader->entries[tmp->closestHitEntryIndex]; - group->AnyHitShaderImport = entry->entryName; + group->AnyHitShaderImport = shader->entryName; } else { group->ClosestHitShaderImport = nullptr; @@ -7835,8 +7923,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // IntersectionShader shader if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->intersectionShaderIndex]; - ShaderEntry* entry = &shader->entries[tmp->intersectionEntryIndex]; - group->AnyHitShaderImport = entry->entryName; + group->AnyHitShaderImport = shader->entryName; } else { group->IntersectionShaderImport = nullptr; @@ -7886,13 +7973,14 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( palFree(s_D3D.allocator, groups); palFree(s_D3D.allocator, subObjects); palFree(s_D3D.allocator, libraries); - palFree(s_D3D.allocator, exportDesc); pipeline->type = RAY_TRACING_PIPELINE; pipeline->strides = nullptr; pipeline->hasFsr = false; pipeline->layout = layout; + pipeline->shaderExports = exports; + pipeline->sbtInfo = sbtInfo; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -7933,22 +8021,29 @@ PalResult PAL_CALL createShaderBindingTableD3D12( Device* d3dDevice = (Device*)device; ShaderBindingTable* sbt = nullptr; Pipeline* pipeline = (Pipeline*)info->rayTracingPipeline; + ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // TODO: create both a GPU only and UPLOAD buffers + Uint32 totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; + totalGroups += sbtInfo->missCount + sbtInfo->callableCount; + if (info->recordCount != totalGroups) { + return PAL_RESULT_INVALID_ARGUMENT; + } + void** raygenHandles = nullptr; void** missHandles = nullptr; void** hitHandles = nullptr; void** callableHandles = nullptr; sbt = palAllocate(s_D3D.allocator, sizeof(ShaderBindingTable), 0); - raygenHandles = palAllocate(s_D3D.allocator, sizeof(void*) * info->raygenGroupCount, 0); - missHandles = palAllocate(s_D3D.allocator, sizeof(void*) * info->missGroupCount, 0); - hitHandles = palAllocate(s_D3D.allocator, sizeof(void*) * info->hitGroupCount, 0); - callableHandles = palAllocate(s_D3D.allocator, sizeof(void*) * info->callableGroupCount, 0); + raygenHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->raygenCount, 0); + missHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->missCount, 0); + hitHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->hitCount, 0); + callableHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->callableCount, 0); + if (!sbt || !raygenHandles || !missHandles || !hitHandles || !callableHandles) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7970,31 +8065,73 @@ PalResult PAL_CALL createShaderBindingTableD3D12( } Uint32 groupHandleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; - Uint32 groupHandleAlignment = 32; // PAL does not allow local signatures + Uint32 groupHandleAlignment = D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT; Uint32 groupBaseAlignment = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; - Uint32 stride = alignD3D12(groupHandleSize, groupHandleAlignment); - // get region size - Uint32 raygenRegionSize = stride * info->raygenGroupCount; - Uint32 missRegionSize = stride * info->missGroupCount; - Uint32 hitRegionSize = stride * info->hitGroupCount; - Uint32 callableRegionSize = stride * info->callableGroupCount; + Uint32 raygenDataSize = 0; + Uint32 missDataSize = 0; + Uint32 hitDataSize = 0; + Uint32 callableDataSize = 0; + + // get the max local data size + for (int i = 0; i < info->recordCount; i++) { + PalShaderBindingTableRecordInfo* record = &info->records[i]; + Uint32 index = record->groupIndex; + + if (index < sbtInfo->raygenCount) { + // raygen group + raygenDataSize = max(raygenDataSize, record->localDataSize); + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { + // miss group + missDataSize = max(missDataSize, record->localDataSize); + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { + // hit group + hitDataSize = max(hitDataSize, record->localDataSize); + + } else { + // callable group + callableDataSize = max(callableDataSize, record->localDataSize); + } + } - // get aligned region size - Uint32 raygenAlignedRegionSize = alignD3D12(raygenRegionSize, groupBaseAlignment); - Uint32 missAlignedRegionSize = alignD3D12(missRegionSize, groupBaseAlignment); - Uint32 hitAlignedRegionSize = alignD3D12(hitRegionSize, groupBaseAlignment); - Uint32 callableAligneRegionSize = alignD3D12(callableRegionSize, groupBaseAlignment); + // get strides + Uint32 raygenStride = alignD3D12(groupHandleSize + raygenDataSize, groupHandleAlignment); + Uint32 missStride = alignD3D12(groupHandleSize + missDataSize, groupHandleAlignment); + Uint32 hitStride = alignD3D12(groupHandleSize + hitDataSize, groupHandleAlignment); + Uint32 callableStride = alignD3D12(groupHandleSize + callableDataSize, groupHandleAlignment); + + // get region size + Uint32 raygenRegionSize = raygenStride * sbtInfo->raygenCount; + Uint32 missRegionSize = missStride * sbtInfo->missCount; + Uint32 hitRegionSize = hitStride * sbtInfo->hitCount; + Uint32 callableRegionSize = callableStride * sbtInfo->callableCount; // get offsets - Uint32 missOffset = raygenAlignedRegionSize; - Uint32 hitOffset = missOffset + missAlignedRegionSize; - Uint32 callableOffset = hitOffset + hitAlignedRegionSize; - Uint32 bufferSize = callableOffset + callableAligneRegionSize; + Uint32 offset = 0; + Uint32 raygenOffset = 0; + Uint32 missOffset = 0; + Uint32 hitOffset = 0; + Uint32 callableOffset = 0; + + raygenOffset = alignD3D12(offset, groupBaseAlignment); + offset = raygenOffset + raygenRegionSize; + + missOffset = alignD3D12(offset, groupBaseAlignment); + offset = missOffset + missRegionSize; + + hitOffset = alignD3D12(offset, groupBaseAlignment); + offset = hitOffset + hitRegionSize; + + callableOffset = alignD3D12(offset, groupBaseAlignment); + offset = callableOffset + callableRegionSize; + + Uint32 bufferSize = alignD3D12(offset, groupBaseAlignment); // create gpu buffer D3D12_HEAP_PROPERTIES heapProps = {0}; - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; heapProps.VisibleNodeMask = 1; heapProps.CreationNodeMask = 1; @@ -8007,6 +8144,25 @@ PalResult PAL_CALL createShaderBindingTableD3D12( bufferDesc.SampleDesc.Count = 1; bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + result = d3dDevice->handle->lpVtbl->CreateCommittedResource( + d3dDevice->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + &IID_Resource, + (void**)&sbt->buffer); + + if (FAILED(result)) { + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + // create staging buffer + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; result = d3dDevice->handle->lpVtbl->CreateCommittedResource( d3dDevice->handle, &heapProps, @@ -8014,7 +8170,8 @@ PalResult PAL_CALL createShaderBindingTableD3D12( &bufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, - &IID_Resource, (void**)&sbt->buffer); + &IID_Resource, + (void**)&sbt->stagingBuffer); if (FAILED(result)) { if (result == E_OUTOFMEMORY) { @@ -8024,80 +8181,125 @@ PalResult PAL_CALL createShaderBindingTableD3D12( } // get shader group handles - Uint32 index = 0; - Uint32 totalGroups = info->raygenGroupCount + info->hitGroupCount; - totalGroups += info->missGroupCount + info->callableGroupCount; + Uint32 raygenIndex = 0; + Uint32 missIndex = 0; + Uint32 hitIndex = 0; + Uint32 callableIndex = 0; for (int i = 0; i < totalGroups; i++) { ShaderExport* tmp = &pipeline->shaderExports[i]; PalShaderStage stage = tmp->stage; + void* handle = nullptr; if (stage == PAL_SHADER_STAGE_RAYGEN) { - raygenHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); + handle = raygenHandles[raygenIndex++]; } else if (stage == PAL_SHADER_STAGE_MISS) { - missHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); + handle = missHandles[missIndex++]; } else if (stage == PAL_SHADER_STAGE_ANY_HIT || stage == PAL_SHADER_STAGE_CLOSEST_HIT || stage == PAL_SHADER_STAGE_INTERSECTION) { - hitHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); + handle = hitHandles[hitIndex++]; } else if (stage == PAL_SHADER_STAGE_CALLABLE) { - callableHandles[i] = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); + handle = callableHandles[callableIndex++]; } + + handle = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); } - // copy shader group handles into the buffer + // copy handles into the buffer + offset = 0; // reuse variable void* ptr = nullptr; - Uint8* dstPtr = ptr; - result = sbt->buffer->lpVtbl->Map(sbt->buffer, 0, nullptr, &ptr); + result = sbt->stagingBuffer->lpVtbl->Map(sbt->stagingBuffer, 0, nullptr, &ptr); if (FAILED(result)) { return PAL_RESULT_PLATFORM_FAILURE; } // raygen - for (int i = 0; i < info->raygenGroupCount; i++) { - memcpy(dstPtr + i * stride, raygenHandles[i], groupHandleSize); + for (int i = 0; i < sbtInfo->raygenCount; i++) { + Uint8* dstPtr = (Uint8*)ptr + (i * raygenStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, raygenHandles[i], groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } } + offset += sbtInfo->raygenCount; // miss - for (int i = 0; i < info->missGroupCount; i++) { - memcpy(dstPtr + missOffset + i * stride, missHandles[i], groupHandleSize); + for (int i = 0; i < sbtInfo->missCount; i++) { + Uint8* dstPtr = (Uint8*)ptr + missOffset + (i * missStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, missHandles[i], groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } } + offset += sbtInfo->missCount; // hit group - for (int i = 0; i < info->hitGroupCount; i++) { - memcpy(dstPtr + hitOffset + i * stride, hitHandles[i], groupHandleSize); + for (int i = 0; i < sbtInfo->hitCount; i++) { + Uint8* dstPtr = (Uint8*)ptr + hitOffset + (i * hitStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, hitHandles[i], groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } } + offset += sbtInfo->hitCount; + + // callable + for (int i = 0; i < sbtInfo->callableCount; i++) { + Uint8* dstPtr = (Uint8*)ptr + callableOffset + (i * callableStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; - // callable group - for (int i = 0; i < info->callableGroupCount; i++) { - memcpy(dstPtr + callableOffset + i * stride, callableHandles[i], groupHandleSize); + memcpy(dstPtr, callableHandles[i], groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } } + sbt->stagingBuffer->lpVtbl->Unmap(sbt->stagingBuffer, 0, nullptr); + // cache SBT fields and offsets address - sbt->buffer->lpVtbl->Unmap(sbt->buffer, 0, nullptr); sbt->baseAddress = sbt->buffer->lpVtbl->GetGPUVirtualAddress(sbt->buffer); // raygen - sbt->raygenAddress.StartAddress = sbt->baseAddress; - sbt->raygenAddress.SizeInBytes = raygenAlignedRegionSize; + sbt->raygen.region.StartAddress = sbt->baseAddress; + sbt->raygen.offset = 0; // always + sbt->raygen.startIndex = 0; // always + sbt->raygen.region.SizeInBytes = raygenRegionSize; + sbt->raygen.region.StrideInBytes = raygenStride; // miss - sbt->missAddress.StartAddress = sbt->baseAddress + missOffset; - sbt->missAddress.SizeInBytes = missAlignedRegionSize; - sbt->missAddress.StrideInBytes = stride; + sbt->miss.offset = missOffset; + sbt->miss.startIndex = sbtInfo->raygenCount; + sbt->miss.region.StartAddress = sbt->baseAddress + missOffset; + sbt->miss.region.SizeInBytes = missRegionSize; + sbt->miss.region.StrideInBytes = missStride; // hit - sbt->hitAddress.StartAddress = sbt->baseAddress + hitOffset; - sbt->hitAddress.SizeInBytes = hitAlignedRegionSize; - sbt->hitAddress.StrideInBytes = stride; + sbt->hit.offset = hitOffset; + sbt->hit.startIndex = sbtInfo->raygenCount + sbtInfo->missCount; + sbt->hit.region.StartAddress = sbt->baseAddress + hitOffset; + sbt->hit.region.SizeInBytes = hitRegionSize; + sbt->hit.region.StrideInBytes = hitStride; // callable - sbt->callableAddress.StartAddress = sbt->baseAddress + callableOffset; - sbt->callableAddress.SizeInBytes = callableAligneRegionSize; - sbt->callableAddress.StrideInBytes = stride; + sbt->callable.offset = callableOffset; + sbt->callable.startIndex = sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount; + sbt->callable.region.StartAddress = sbt->baseAddress + callableOffset; + sbt->callable.region.SizeInBytes = callableRegionSize; + sbt->callable.region.StrideInBytes = callableStride; props->lpVtbl->Release(props); palFree(s_D3D.allocator, raygenHandles); @@ -8105,6 +8307,10 @@ PalResult PAL_CALL createShaderBindingTableD3D12( palFree(s_D3D.allocator, hitHandles); palFree(s_D3D.allocator, callableHandles); + sbt->handleSize = groupHandleSize; + sbt->pipeline = pipeline; + + sbt->isDirty = true; // we need to copy from the staging to the gpu buffer *outSbt = (PalShaderBindingTable*)sbt; return PAL_RESULT_SUCCESS; } @@ -8113,9 +8319,74 @@ void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) { ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; d3dSbt->buffer->lpVtbl->Release(d3dSbt->buffer); + d3dSbt->stagingBuffer->lpVtbl->Release(d3dSbt->stagingBuffer); palFree(s_D3D.allocator, d3dSbt); } +PalResult PAL_CALL updateShaderBindingTableD3D12( + PalShaderBindingTable* sbt, + Uint32 count, + PalShaderBindingTableRecordInfo* infos) +{ + HRESULT result; + ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; + Pipeline* pipeline = d3dSbt->pipeline; + ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; + + void* data = nullptr; + result = d3dSbt->stagingBuffer->lpVtbl->Map(d3dSbt->stagingBuffer, 0, nullptr, &data); + if (FAILED(result)) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + Uint32 stride = 0; + Uint32 offset = 0; + Uint32 startIndex = 0; + + for (int i = 0; i < count; i++) { + PalShaderBindingTableRecordInfo* info = &infos[i]; + if (!info->localDataSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + // find the group the record belongs to + Uint32 index = info->groupIndex; + if (index < sbtInfo->raygenCount) { + // raygen group + offset = 0; + stride = d3dSbt->raygen.region.StrideInBytes; + startIndex = d3dSbt->raygen.startIndex; + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { + // miss group + offset = d3dSbt->miss.offset; + stride = d3dSbt->miss.region.StrideInBytes; + startIndex = d3dSbt->miss.startIndex; + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { + // hit group + offset = d3dSbt->hit.offset; + stride = d3dSbt->hit.region.StrideInBytes; + startIndex = d3dSbt->hit.startIndex; + + } else { + // callable group + offset = d3dSbt->callable.offset; + stride = d3dSbt->callable.region.StrideInBytes; + startIndex = d3dSbt->callable.startIndex; + } + + // write payload + Uint32 localIndex = index - startIndex; + Uint8* dst = (Uint8*)data + offset + (localIndex * stride); + memcpy(dst + d3dSbt->handleSize, info->localData, info->localDataSize); + } + + d3dSbt->stagingBuffer->lpVtbl->Unmap(d3dSbt->stagingBuffer, 0, nullptr); + d3dSbt->isDirty = true; + return PAL_RESULT_SUCCESS; +} + #endif // PAL_HAS_D3D12 #endif // __WIN32 \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 7f520b23..ad73a200 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -1662,7 +1662,6 @@ PalResult PAL_CALL createShaderBindingTableD3D12( void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); -// TODO: implement PalResult PAL_CALL updateShaderBindingTableD3D12( PalShaderBindingTable* sbt, Uint32 count, @@ -1845,7 +1844,7 @@ static PalGraphicsBackend s_D3D12Backend = { // shader binding tables .createShaderBindingTable = createShaderBindingTableD3D12, - .destroyShaderBindingTable = destroyShaderBindingTableD3D12; + .destroyShaderBindingTable = destroyShaderBindingTableD3D12, .updateShaderBindingTable = updateShaderBindingTableD3D12}; #endif // PAL_HAS_D3D12 diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e4b1111d..af5dbd70 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -494,32 +494,6 @@ typedef struct { VkCommandPool handle; } CommandPool; -typedef struct { - Uint32 startIndex; - Uint32 offset; - VkStridedDeviceAddressRegionKHR region; -} AddressRegion; - -typedef struct { - const PalGraphicsBackend* backend; - - bool isDirty; - Uint32 stagingBufferSize; - Uint32 handleSize; - Device* device; - VkBuffer buffer; - VkBuffer stagingBuffer; - VkDeviceMemory bufferMemory; - VkDeviceMemory stagingBufferMemory; - VkDeviceAddress baseAddress; - void* pipeline; - - AddressRegion raygen; - AddressRegion miss; - AddressRegion hit; - AddressRegion callable; -} ShaderBindingTable; - typedef struct { const PalGraphicsBackend* backend; @@ -527,6 +501,8 @@ typedef struct { Device* device; CommandPool* pool; void* pipeline; + VkBuffer buffer; + VkDeviceMemory bufferMemory; VkCommandBuffer handle; } CommandBuffer; @@ -618,6 +594,32 @@ typedef struct { ShaderBindingTableInfo sbtInfo; } Pipeline; +typedef struct { + Uint32 startIndex; + Uint32 offset; + VkStridedDeviceAddressRegionKHR region; +} AddressRegion; + +typedef struct { + const PalGraphicsBackend* backend; + + bool isDirty; + Uint32 stagingBufferSize; + Uint32 handleSize; + Device* device; + VkBuffer buffer; + VkBuffer stagingBuffer; + VkDeviceMemory bufferMemory; + VkDeviceMemory stagingBufferMemory; + VkDeviceAddress baseAddress; + Pipeline* pipeline; + + AddressRegion raygen; + AddressRegion miss; + AddressRegion hit; + AddressRegion callable; +} ShaderBindingTable; + typedef struct { VkPipelineStageFlags2 stages; VkPipelineStageFlags2 dstStages; @@ -2572,7 +2574,7 @@ static VkGeometryInstanceFlagsKHR instanceFlagsToVk(PalAccelerationStructureInst return instanceFlags; } -static void commitShaderbindingTableUpdate( +static void commitShaderbindingTableUpdateVk( CommandBuffer* cmdBuffer, ShaderBindingTable* sbt) { @@ -6423,9 +6425,51 @@ PalResult PAL_CALL allocateCommandBufferVk( return resultFromVk(result); } + // create a gpu buffer if ray tracing is enabled + if (vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + VkBufferCreateInfo bufCreateInfo = {0}; + bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufCreateInfo.size = sizeof(VkTraceRaysIndirectCommandKHR); + bufCreateInfo.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; + bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + result = s_Vk.createBuffer( + vkDevice->handle, + &bufCreateInfo, + &s_Vk.vkAllocator, + &cmdBuffer->buffer); + + if (result != VK_SUCCESS) { + return resultFromVk(result); + } + + // allocate CPU upload memory and bind + VkMemoryRequirements memReq = {0}; + s_Vk.getBufferMemoryRequirements(vkDevice->handle, cmdBuffer->buffer, &memReq); + + VkMemoryAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = memReq.size; + + Uint32 mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; + Uint32 memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + allocateInfo.memoryTypeIndex = memoryIndex; + + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &cmdBuffer->bufferMemory); + + if (result != VK_SUCCESS) { + return resultFromVk(result); + } + + s_Vk.bindBufferMemory(vkDevice->handle, cmdBuffer->buffer, cmdBuffer->bufferMemory, 0); + } + cmdBuffer->device = vkDevice; cmdBuffer->pool = vkPool; - *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; } @@ -6439,6 +6483,11 @@ void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer) 1, &vkCmdBuffer->handle); + if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + s_Vk.destroyBuffer(vkCmdBuffer->device->handle, vkCmdBuffer->buffer, &s_Vk.vkAllocator); + s_Vk.freeMemory(vkCmdBuffer->device->handle, vkCmdBuffer->bufferMemory, &s_Vk.vkAllocator); + } + palFree(s_Vk.allocator, vkCmdBuffer); } @@ -7558,7 +7607,7 @@ PalResult PAL_CALL cmdTraceRaysVk( raygenAddress.deviceAddress = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; // we need to make sure the SBT is up to date - commitShaderbindingTableUpdate(vkCmdBuffer, vkSbt); + commitShaderbindingTableUpdateVk(vkCmdBuffer, vkSbt); vkCmdBuffer->device->cmdTraceRays( vkCmdBuffer->handle, @@ -7589,15 +7638,38 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; vkSbt->raygen.region.deviceAddress = address; + + // we need to make sure the SBT is up to date + commitShaderbindingTableUpdateVk(vkCmdBuffer, vkSbt); + + // copy users buffer data into a tmp gpu buffer abd execute with it + VkBufferCopy copyRegion = {0}; + copyRegion.size = sizeof(VkTraceRaysIndirectCommandKHR); + s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, vkBuffer->handle, vkCmdBuffer->buffer, 1, ©Region); + + // put a memory barrier + VkBufferMemoryBarrier2KHR barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; + barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR; + barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; + barrier.dstStageMask = VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; + barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT_KHR; + + barrier.buffer = vkCmdBuffer->buffer; + barrier.offset = 0; + barrier.size = VK_WHOLE_SIZE; - VkDeviceAddress bufferAddress = 0; + VkDependencyInfo dependencyInfo = {0}; + dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependencyInfo.bufferMemoryBarrierCount = 1; + dependencyInfo.pBufferMemoryBarriers = &barrier; + vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); + + VkDeviceAddress bufAddress = 0; VkBufferDeviceAddressInfoKHR bufferInfo = {0}; - bufferInfo.buffer = vkBuffer->handle; + bufferInfo.buffer = vkCmdBuffer->buffer; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; - bufferAddress = vkBuffer->device->getBufferrAddress(vkBuffer->device->handle, &bufferInfo); - - // we need to make sure the SBT is up to date - commitShaderbindingTableUpdate(vkCmdBuffer, vkSbt); + bufAddress = vkCmdBuffer->device->getBufferrAddress(vkCmdBuffer->device->handle, &bufferInfo); vkCmdBuffer->device->cmdTraceRaysIndirect( vkCmdBuffer->handle, @@ -7605,7 +7677,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( &vkSbt->miss.region, &vkSbt->hit.region, &vkSbt->callable.region, - bufferAddress); + bufAddress); return PAL_RESULT_SUCCESS; } @@ -9200,14 +9272,19 @@ PalResult PAL_CALL createRayTracingPipelineVk( group->closestHitShader = VK_SHADER_UNUSED_KHR; } - if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { - group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; + if (tmp->intersectionShaderIndex!= PAL_UNUSED_SHADER_INDEX) { group->intersectionShader = tmp->intersectionShaderIndex; } else { - group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; group->intersectionShader = VK_SHADER_UNUSED_KHR; } + + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + + } else { + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; + } } } diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 210a631e..abef1fdf 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -19,6 +19,7 @@ static void PAL_CALL onGraphicsDebug( bool meshTest() { + // FIXME: Test properly on D3D12 PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index c483f360..c8a9147a 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -19,6 +19,7 @@ static void PAL_CALL onGraphicsDebug( bool rayTracingTest() { + // FIXME: Test properly on D3D12 PalAdapter* adapter = nullptr; PalDevice* device = nullptr; PalQueue* queue = nullptr; @@ -58,7 +59,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); From 1bfc22d7dbeef9856c500d5b4dca8e94470a8419 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 11 May 2026 18:29:56 +0000 Subject: [PATCH 214/372] make ray tracing pipeline more static --- include/pal/pal_graphics.h | 3 ++- src/graphics/pal_vulkan.c | 38 ++++++++++++++++++++----------- tests/graphics/ray_tracing_test.c | 3 +++ 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index fa2ab204..a1c31d1e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2444,7 +2444,7 @@ typedef struct { */ typedef struct { Uint32 groupIndex; /**< Index into the shader groups used to create the ray tracing pipeline.*/ - Uint32 localDataSize; + Uint32 localDataSize; /**< Must not be greater than the data size of the group.*/ void* localData; } PalShaderBindingTableRecordInfo; @@ -2679,6 +2679,7 @@ typedef struct { Uint32 closestHitShaderIndex; /**< Index of closest hit shader from shader array.*/ Uint32 generalShaderIndex; /**< Index of general hit shader from shader array.*/ Uint32 intersectionShaderIndex; /**< Index of intersection hit shader from shader array.*/ + Uint32 maxDataSize; /**< Size of extra data associated with the shader group.*/ } PalRayTracingShaderGroupCreateInfo; /** diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index af5dbd70..ce3a1ce9 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -579,9 +579,13 @@ typedef struct { typedef struct { Uint32 raygenCount; + Uint32 raygenDataSize; Uint32 missCount; + Uint32 missDataSize; Uint32 hitCount; + Uint32 hitDataSize; Uint32 callableCount; + Uint32 callableDataSize; } ShaderBindingTableInfo; typedef struct { @@ -9234,16 +9238,19 @@ PalResult PAL_CALL createRayTracingPipelineVk( switch (shader->stage) { case VK_SHADER_STAGE_RAYGEN_BIT_KHR: { sbtInfo->raygenCount++; + sbtInfo->raygenDataSize = maxVk(sbtInfo->raygenDataSize, tmp->maxDataSize); break; } case VK_SHADER_STAGE_MISS_BIT_KHR: { sbtInfo->missCount++; + sbtInfo->missDataSize = maxVk(sbtInfo->missDataSize, tmp->maxDataSize); break; } case VK_SHADER_STAGE_CALLABLE_BIT_KHR: { sbtInfo->callableCount++; + sbtInfo->callableDataSize = maxVk(sbtInfo->callableDataSize, tmp->maxDataSize); break; } } @@ -9256,6 +9263,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( } else { sbtInfo->hitCount++; + sbtInfo->hitDataSize = maxVk(sbtInfo->hitDataSize, tmp->maxDataSize); group->generalShader = VK_SHADER_UNUSED_KHR; if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { @@ -9367,11 +9375,6 @@ PalResult PAL_CALL createShaderBindingTableVk( Uint32 groupHandleAlignment = rayProps.shaderGroupHandleAlignment; Uint32 groupBaseAlignment = rayProps.shaderGroupBaseAlignment; - Uint32 raygenDataSize = 0; - Uint32 missDataSize = 0; - Uint32 hitDataSize = 0; - Uint32 callableDataSize = 0; - // get the max local data size for (int i = 0; i < info->recordCount; i++) { PalShaderBindingTableRecordInfo* record = &info->records[i]; @@ -9379,27 +9382,36 @@ PalResult PAL_CALL createShaderBindingTableVk( if (index < sbtInfo->raygenCount) { // raygen group - raygenDataSize = maxVk(raygenDataSize, record->localDataSize); + if (record->localDataSize > sbtInfo->raygenDataSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { // miss group - missDataSize = maxVk(missDataSize, record->localDataSize); + if (record->localDataSize > sbtInfo->missDataSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { // hit group - hitDataSize = maxVk(hitDataSize, record->localDataSize); + if (record->localDataSize > sbtInfo->hitDataSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } } else { // callable group - callableDataSize = maxVk(callableDataSize, record->localDataSize); + if (record->localDataSize > sbtInfo->callableDataSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } } } // get strides - Uint32 raygenStride = alignVk(groupHandleSize + raygenDataSize, groupHandleAlignment); - Uint32 missStride = alignVk(groupHandleSize + missDataSize, groupHandleAlignment); - Uint32 hitStride = alignVk(groupHandleSize + hitDataSize, groupHandleAlignment); - Uint32 callableStride = alignVk(groupHandleSize + callableDataSize, groupHandleAlignment); + Uint32 callableStride = 0; + Uint32 raygenStride = alignVk(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); + Uint32 missStride = alignVk(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); + Uint32 hitStride = alignVk(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); + callableStride = alignVk(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); // get region size Uint32 raygenRegionSize = raygenStride * sbtInfo->raygenCount; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index c8a9147a..bfbcf94d 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -789,6 +789,7 @@ bool rayTracingTest() shaderGroupCreateInfos[0].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[0].maxDataSize = 0; // no extra data // miss must be packed second always shaderGroupCreateInfos[1].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; @@ -796,6 +797,7 @@ bool rayTracingTest() shaderGroupCreateInfos[1].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[1].maxDataSize = sizeof(LocalData); // hitGroup must be packed third always shaderGroupCreateInfos[2].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT; @@ -803,6 +805,7 @@ bool rayTracingTest() shaderGroupCreateInfos[2].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[2].generalShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[2].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; + shaderGroupCreateInfos[2].maxDataSize = sizeof(LocalData); // create a ray tracing pipeline PalRayTracingPipelineCreateInfo pipelineCreateInfo = {0}; From 180bc074d565899b197503f0b01133aa9ee6cc4d Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 11 May 2026 21:57:39 +0000 Subject: [PATCH 215/372] make ray tracing pipeline more static d3d12 --- src/graphics/pal_d3d12.c | 143 ++++++++++++++++-- .../shaders/bin/dxil/closest_hit.dxil | Bin 2796 -> 3520 bytes tests/graphics/shaders/bin/dxil/compute.dxil | Bin 3452 -> 3384 bytes tests/graphics/shaders/bin/dxil/miss.dxil | Bin 2576 -> 3316 bytes .../shaders/src/hlsl/closest_hit.hlsl | 7 +- tests/graphics/shaders/src/hlsl/compute.hlsl | 10 +- tests/graphics/shaders/src/hlsl/miss.hlsl | 7 +- tests/tests_main.c | 4 +- 8 files changed, 146 insertions(+), 25 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index f058bd37..8c5233d0 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -319,6 +319,7 @@ typedef struct { typedef struct { PalShaderStage stage; + ID3D12RootSignature* localRoot; wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; } ShaderExport; @@ -334,9 +335,13 @@ typedef struct { typedef struct { Uint32 raygenCount; + Uint32 raygenDataSize; Uint32 missCount; + Uint32 missDataSize; Uint32 hitCount; + Uint32 hitDataSize; Uint32 callableCount; + Uint32 callableDataSize; } ShaderBindingTableInfo; typedef struct { @@ -350,6 +355,7 @@ typedef struct { void* handle; ShaderExport* shaderExports; PipelineLayout* layout; + ID3D12RootSignature* localRootSignature; D3D12_SHADING_RATE_COMBINER combinerOps[2]; ShaderBindingTableInfo sbtInfo; } Pipeline; @@ -7728,6 +7734,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( pipeline->type = GRAPHICS_PIPELINE; pipeline->layout = layout; pipeline->shaderExports = nullptr; + pipeline->localRootSignature = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -7773,6 +7780,7 @@ PalResult PAL_CALL createComputePipelineD3D12( pipeline->hasFsr = false; pipeline->layout = layout; pipeline->shaderExports = nullptr; + pipeline->localRootSignature = nullptr; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -7786,6 +7794,8 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( HRESULT result; Uint32 hitGroupIndex = 0; Uint32 subObjectIndex = 0; + Uint32 localExportCount = 0; + Uint32 localExportIndex = 0; // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG @@ -7799,7 +7809,8 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( RayHitGroup* groups = nullptr; D3D12_STATE_SUBOBJECT* subObjects = nullptr; ShaderExport* exports = nullptr; - + const wchar_t** localExports = nullptr; + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7816,6 +7827,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_INVALID_ARGUMENT; } + Uint32 localRootSize = 0; ShaderBindingTableInfo sbtInfo = {0}; for (int i = 0; i < info->shaderGroupCount; i++) { PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; @@ -7825,25 +7837,45 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( switch (shader->stage) { case PAL_SHADER_STAGE_RAYGEN: { sbtInfo.raygenCount++; + sbtInfo.raygenDataSize = max(sbtInfo.raygenDataSize, tmp->maxDataSize); break; } case PAL_SHADER_STAGE_MISS: { sbtInfo.missCount++; + sbtInfo.missDataSize = max(sbtInfo.missDataSize, tmp->maxDataSize); break; } case PAL_SHADER_STAGE_CALLABLE: { sbtInfo.callableCount++; + sbtInfo.callableDataSize = max(sbtInfo.callableDataSize, tmp->maxDataSize); break; } } } + sbtInfo.hitDataSize = max(sbtInfo.hitDataSize, tmp->maxDataSize); + if (tmp->maxDataSize) { + localExportCount++; + } + + // find the max data size across all shader groups + localRootSize = max(localRootSize, sbtInfo.raygenDataSize); + localRootSize = max(localRootSize, sbtInfo.missDataSize); + localRootSize = max(localRootSize, sbtInfo.hitDataSize); + localRootSize = max(localRootSize, sbtInfo.callableDataSize); + sbtInfo.hitCount++; subObjectCount++; } + if (localRootSize) { + // D3D12_LOCAL_ROOT_SIGNATURE + // D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION + subObjectCount += 2; + } + pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); if (!pipeline) { return PAL_RESULT_OUT_OF_MEMORY; @@ -7853,11 +7885,68 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( groups = palAllocate(s_D3D.allocator, sizeof(RayHitGroup) * sbtInfo.hitCount, 0); libraries = palAllocate(s_D3D.allocator, sizeof(RayShaderLibary) * info->shaderCount, 0); exports = palAllocate(s_D3D.allocator, sizeof(ShaderExport) * info->shaderCount, 0); + localExports = palAllocate(s_D3D.allocator, sizeof(wchar_t*) * localExportCount, 0); - if (!exports || !groups || !subObjects || !libraries) { + if (!exports || !groups || !subObjects || !libraries || !localExports) { return PAL_RESULT_OUT_OF_MEMORY; } + // check if we need a local root signature + D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION localExportAssociation = {0}; + if (localRootSize) { + D3D12_ROOT_PARAMETER1 parameter = {0}; + parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + parameter.Constants.Num32BitValues = alignD3D12(localRootSize, 4) / 4; + parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; + rootDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; + rootDesc.Desc_1_1.NumParameters = 1; + rootDesc.Desc_1_1.pParameters = ¶meter; + rootDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; + + ID3DBlob* blob = nullptr; + result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); + if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + result = d3dDevice->handle->lpVtbl->CreateRootSignature( + d3dDevice->handle, + 0, + blob->lpVtbl->GetBufferPointer(blob), + blob->lpVtbl->GetBufferSize(blob), + &IID_RootSignature, + (void**)&pipeline->localRootSignature); + + if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE; + subObjects[subObjectIndex].pDesc = pipeline->localRootSignature; + + localExportAssociation.pSubobjectToAssociate = &subObjects[subObjectIndex]; + localExportAssociation.pExports = localExports; + localExportAssociation.NumExports = localExportCount; + subObjectIndex++; + + D3D12_STATE_SUBOBJECT_TYPE t = D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION; + subObjects[subObjectIndex].Type = t; + subObjects[subObjectIndex].pDesc = &localExportAssociation; + subObjectIndex++; + } + // shaders for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; @@ -7882,8 +7971,14 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // hit groups for (int i = 0; i < info->shaderGroupCount; i++) { + const wchar_t* exportName = nullptr; PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { + if (tmp->maxDataSize) { + Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; + localExports[localExportIndex++] = shader->entryName; + } + continue; } @@ -7929,10 +8024,15 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( group->IntersectionShaderImport = nullptr; } + if (tmp->maxDataSize) { + localExports[localExportIndex] = group->HitGroupExport; + } + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP; subObjects[subObjectIndex].pDesc = group; subObjectIndex++; hitGroupIndex++; + localExportIndex++; } // ray tracing config @@ -7973,6 +8073,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( palFree(s_D3D.allocator, groups); palFree(s_D3D.allocator, subObjects); palFree(s_D3D.allocator, libraries); + palFree(s_D3D.allocator, localExports); pipeline->type = RAY_TRACING_PIPELINE; pipeline->strides = nullptr; @@ -7997,6 +8098,10 @@ void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) handle->lpVtbl->Release(handle); } + if (d3dPipeline->localRootSignature) { + d3dPipeline->localRootSignature->lpVtbl->Release(d3dPipeline->localRootSignature); + } + if (d3dPipeline->strides) { palFree(s_D3D.allocator, d3dPipeline->strides); } @@ -8068,11 +8173,6 @@ PalResult PAL_CALL createShaderBindingTableD3D12( Uint32 groupHandleAlignment = D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT; Uint32 groupBaseAlignment = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; - Uint32 raygenDataSize = 0; - Uint32 missDataSize = 0; - Uint32 hitDataSize = 0; - Uint32 callableDataSize = 0; - // get the max local data size for (int i = 0; i < info->recordCount; i++) { PalShaderBindingTableRecordInfo* record = &info->records[i]; @@ -8080,27 +8180,40 @@ PalResult PAL_CALL createShaderBindingTableD3D12( if (index < sbtInfo->raygenCount) { // raygen group - raygenDataSize = max(raygenDataSize, record->localDataSize); + if (record->localDataSize > sbtInfo->raygenDataSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { // miss group - missDataSize = max(missDataSize, record->localDataSize); + if (record->localDataSize > sbtInfo->missDataSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { // hit group - hitDataSize = max(hitDataSize, record->localDataSize); + if (record->localDataSize > sbtInfo->hitDataSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } } else { // callable group - callableDataSize = max(callableDataSize, record->localDataSize); + if (record->localDataSize > sbtInfo->callableDataSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } } } // get strides - Uint32 raygenStride = alignD3D12(groupHandleSize + raygenDataSize, groupHandleAlignment); - Uint32 missStride = alignD3D12(groupHandleSize + missDataSize, groupHandleAlignment); - Uint32 hitStride = alignD3D12(groupHandleSize + hitDataSize, groupHandleAlignment); - Uint32 callableStride = alignD3D12(groupHandleSize + callableDataSize, groupHandleAlignment); + Uint32 raygenStride = 0; + Uint32 missStride = 0; + Uint32 hitStride = 0; + Uint32 callableStride = 0; + + raygenStride = alignD3D12(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); + missStride = alignD3D12(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); + hitStride = alignD3D12(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); + callableStride = alignD3D12(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); // get region size Uint32 raygenRegionSize = raygenStride * sbtInfo->raygenCount; diff --git a/tests/graphics/shaders/bin/dxil/closest_hit.dxil b/tests/graphics/shaders/bin/dxil/closest_hit.dxil index 786f79610d5f49b57bb532b56a4f1790264a9473..e6c4924021ddd1d67d3ac49501c5c1361f860192 100644 GIT binary patch literal 3520 zcmeHKdr(u^89z5S+?zli7ZPh?0=)rY@Ud)&$TQX(5?Hbucf+e?E9@q`3KlRtWC5Kv z33-6V8Wg%wSA<<+*B#v=OI4_DK_~{q6?}AHMF(8KuESckkExw?rac$dj?>O`+W&TE z`px{#`R+O2`Of*ibLRZc)#N0r*F6q$Y*pRK59!<4-v1NSiU0rxxBy_Vj)zEtsDm)T zj(s=)9*E3Tt(*nhp2_!9GBP9K2LjkDO_UITHBeJT7b@b5;}jq|Dj`Y{D_2BC$I%8E z8dcUTtO*Dvga{%R!UZt_L9amx0n$oqGKvazR}}(ed%3Z+f}&nm-EO^vfai) zipqv2s+yXr()>L&Mb#8V{SeTG0HARA>Y4x`q0WGSVf~xXbJ0StgPxQAj)4e(h=ri# z?@;_<&4GA6ZhBAwpnFzr=sD>AXFfBtR9Qlp$YPjHJ8abCXmuE@>A0Wz0g$X7xG#fF z_rbORE4i{p0qnyqVJ#{jQ;QLbgu{r96Yj?nhcFN1n}sQi}PIB#nNGN>2*t7BnUE08(55Pa2v~iLdS%- zV@1QX!Z$OsB(4Xvic<_aZ9ogh(K!@2C{YA+*wz8{W)grGV66yEW0Qq;=8@1Y8!SGv zb-IN?y8W&ITbGU~sb;b)dmYzKc01iqi4upMQjyUNIVyL_g=@8$8upRjFmn722T)F= zyv7k|dk|T=KhpR|b>YoZ8VgK-5qm{Z0|@UOxh;hCRzNXnW3i7 zmq1uG;H)t?V@sU%B`DOnztr=}CwL981pEd$Ue$qDlX$tCSNTk-d!|$xaN1x3`}{ex zS_*G4;58H2B7xVgS{iuJ!>Z*X?CQXwP5CSj`uWu-d_w@CPXjFj zZk)lOXbp;4c7w?rSW#i2Zue*X^HlXv^f^|9c!c6Wo!iBZcxi;GZt&`b;d)LOu%}}S z`XFyQkwWdl%%5<;oEVIqr*{&7dYFhxSg%8M?o@_AbBMEh>5Cnl^&{a|Q%11Vk?=)~ znG)g9VON(@7bA+)gpO!0ur8Alo5e#aN3lV9e7Co`TtrwsWT8;d6_a?n=UiMu5Bth{ zWfZ3<+GRmvnb$D}kQ%I}w9O;;r|!>3ux=<+bsqMWTRI}-M`*ItNOn+zG`M5qV>r3s3Ci^C4K^nPEBroTo zeURD7js+5jh2t{}b+;hmG7(2XHgeTs&mhzt(G<#%_)}an-m#APwAb$KLy#grW46}5 zpt3KVyKHYkkZhTE(rFncAk*Hxn^1^-s)cJ;9hQFnWe*X(qbX9 ztw|kk8*(L^@%lQv+Ed9{1pF@u-k;69Eu7?#D}%wGbV`fmek*2;l5upKPrc2BZX2(2 z)tKQ!tSIGIFE%TQ3ye-6V@O_zdN)~*@7*Z^6 zPP){XG@(xDMU|Htl{PeKd|6m)!1tEmaV5?wSel(Cx6@?6Ya{X6Cw|cFTW05*EN7+2 zS>s?0PVZIKrbD zdQpm=NJ-~;sp;C)`y~_F{x4jSZ(SCxa>Z55_#9U#eN5S259yuMwjI1Y+5)frLiF9u zu6H@yZkZ{T0LwsNiZ9s_uuVsP+z_^@;CK*O zHVkGvIXArH2VafiKYHQ%!HSCgZu<52|2zBJd}kX;07Bs&3YeX2q6=k`tZVH*aJXsb9BA|kSuJ?&zWHu4y*=wsg`nyq=02bhGmwm#|Ti( zNj1A7ID^tgV)J`!yZkE2y!k!#ojpUChU5STN*@~fzvMeAa7!p2{t`?*Sb3Av{%QFK D`-fiz delta 1632 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 diff --git a/tests/graphics/shaders/bin/dxil/miss.dxil b/tests/graphics/shaders/bin/dxil/miss.dxil index ff11be7122e3a52d8778327bea46f70e1a4e84db..7119624c1f02254beb53a0fb711cefe459c4e411 100644 GIT binary patch literal 3316 zcmeHJeN0=|6~E8#@tzIO_5+*X1cU5QvqWX=VQ7Ft7JuPF>tyC@B2%V4gQ3u3Vm?NI zu*n#Mff&_%rA{&}P(GSX+2%$xDM{KmkbuV^rCC_^7T117uuf4H?#8ccfkh)@Pa0l7=TEqDU-~~w6atsNJ>mkRPLdbiAkw! zK%P!rumF1s0)vo17$BM(bQOZ z*ko3zRNn%u1E4T`a}02dQ0GAKA^uU=+^n$Q&4gf|Qy}1!!B-$y`74w#*t5336FBJ- zzaqWnM?NTP)M+J4V5FrDi2t z;O^OZ&8W_8aoufQ?ZS5J@myHUP?$5?B?A%6M=CBmnSJ0UUh;_55V!4>R`mv}!li{{ z%7O80?L-chhayEBc21qL%~~jTX7gm`Hmq;whyymCIELKf2t$`E%rRo14%K4ZmZR;z zIPG=1H>mRVHkDeI#Gz5zMT?_y@^!qvE1aTG<`_!uqU*X;)adYLY;)Cc*MMi^H|N81 zU))`bF~*MT*l_)l^$XEMs`pAnuQrR*qraimi8R^S%vs9b`GS|U^LkO_O;5)&KXKgA zp`m0U9Iv>>=d5F#d&-@S}}GQ#2(R6kJ~o+#A}!3Heg zzugj6uOgZlqHY0Sqlo&=NJaoNY(}m@*B}97EO!Jj&*Kb1%kx5=TOOxSf#(6^?*jB`|+!Ens>C*BBAUaS&?X9YTIY7$Tt-6Hi<;CTdc&C~y{rjnz5OE&6+*-)UcP!fyQq>4JfpXz5&uSt@5*zQY<#_7Oi{$vy$-998jInkju z(nbt!3;c51aX94uNJpU}@;DKBeCFXcJ&s`` Ro@;K;z%2TXmD(M@5&yDBbVzeKe zK)_k#SjvU;ixYfJbV1?b;`+yjZu)0$-y6f!k;=@dOUj9f@ze{ukq;c?`_~g)^FK9I zy~x~>Pt~5#hQ&SG_i9tzvn8h@WTpPVp_SRS<@+nsvuk760R?>bV&*&NWT_WYFVYub ziizEm@%VRP7)-wMhr#8Wx9_cuam`-*+t4<>eE;^n*%kPvL(XvSPXT+a|k%Zb!-XANv^POIB#Wr+G+ME#=>nD&Ux`5msaTH>tn zI2%1J37-Z8pWYGt(I;4^(PICQbY)077i@2vq_cAAwU(G!6aJxFo9@@9dxGsdQ)&I$ zv<@_*f9h-SqZ{^&TWE%N%H@|6%~rIAa@JZ=b}o$5>USPFLo|6>GFNQEDwS|`K@foT zs+K{{f_>y*$oC&uKjvd)t&2ZS`GK?jv-Kk$663s$4?h0?TlvPR)r{AKDc#A4D4a9z zrQ*H(*MFD!9%al@>qb#hVFH}Bs0$XXoIdp4XOA>Guo-q*G?0Bq`1(GRQ2vE{feZ`& zN7?H9YkX3cm0R~vAOJ*|Vi8nI z@SKw}dbYi#cZ5G#V3D-@cY22a4LD~)HpbgVClI7G#8jBmwyJJhee2z}9t1%uV6sxX zj}~ELA5puaUEOgfZ!8&gJ3#Y)jd;KD&xp6B&`G{OI@f(5QF#BW^W9ZdUAFJRa(!91 z|MTqA&$A}k=AB%GsT0`S5xei}j@gQkF!8#oqCe)>5fWrD)k!PNWzYlf%AHBY43Kg0 z-T^EQCxD#+rW}<^A_ZK#dRUG;caj3Nq~7L=C$CCdsf1x(8$Bb#Zhjqo+cJggWF%-u UAteXz*AK0k;Cz~oO&gTI0fsIm;s5{u delta 1537 zcmchXe@q*76u`fClyZfFSBiM0gdJ?_4k*}`A45YzuZ6Bin*fCYW<<)$++rC&MwStb zT-mL{?6UGJ1DX)XAi|a?Ka8d(B(x<68vZ~f!kCNb#*!s!vX~hYjlLTa(Ld%NCcfOe z_kG_V@B8lMbMGgGH?Fg=+F(rn2y?vH!|Cj4Gw(0`p!ya=2$7KpiNWT9nnBw@e+4}o zjt~!OGZkwH@b~3pQMv61I2eM1Ao+0!!GjvIa&oe@c{-%cd?{0tnWN3qpz=btf`c^@ zq3034H$eGdg^PtCy|f{) z<0wvW5csLg>A?sk)g=v)3Yo?0k*H2Ai;Tf?##IkB@aUMg`Ey2I_)+4P zcgMduxVkpE;I~S;RgO!U7wyiA4Xrl(W{hI=v&2`an&DGlC~Fkk18BO?{m^hDqALFW z?i14srW;RobB`B!=U#?G4d>fh+e@3yoo~BftfyZ{T2 zfQp9q{}x4AU?7N@wV4IJ1qplI^`j-eg$YZkt9$c3+c5z{{!c8E|AD3R0G8DMfu#%* zd={3+NakO$^g@h%G!X~RQ+Xzu%vBi|WG=TdJ%2~D1djekG^qnrvIuVewQ%hL77Jk3P9p>z n4#`EVT4;Mh3xGa@I>h!GcXYR&LedDK#R|IHoG&yS812a)fuOky diff --git a/tests/graphics/shaders/src/hlsl/closest_hit.hlsl b/tests/graphics/shaders/src/hlsl/closest_hit.hlsl index e71bf6f6..3ab56dd9 100644 --- a/tests/graphics/shaders/src/hlsl/closest_hit.hlsl +++ b/tests/graphics/shaders/src/hlsl/closest_hit.hlsl @@ -9,10 +9,15 @@ struct HitAttributes float2 unused; }; +cbuffer HitRecord : register(b0) +{ + float3 hitColor; +}; + [shader("closesthit")] void main( inout RayPayload payload, in HitAttributes attr) { - payload.color = float3(0.0, 1.0, 0.0); + payload.color = hitColor; } \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/compute.hlsl b/tests/graphics/shaders/src/hlsl/compute.hlsl index d7eebfe1..6e659772 100644 --- a/tests/graphics/shaders/src/hlsl/compute.hlsl +++ b/tests/graphics/shaders/src/hlsl/compute.hlsl @@ -1,13 +1,11 @@ -struct PushConstants +cbuffer PushConstants : register(b0) { uint width; uint height; float4 color; }; -PushConstants pc; - // We used raw Buffer but structured buffer can be used as well. // PalDescriptorBufferInfo::stride must be set to 16 RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 @@ -15,11 +13,11 @@ RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 [numthreads(16, 16, 1)] void main(uint3 id : SV_DispatchThreadID) { - if (id.x >= pc.width || id.y >= pc.height) { + if (id.x >= width || id.y >= height) { return; } - uint index = id.y * pc.width + id.x; + uint index = id.y * width + id.x; uint offset = index * 16; // sizeof(float4) - outBuffer.Store4(offset, asuint(pc.color)); + outBuffer.Store4(offset, asuint(color)); } diff --git a/tests/graphics/shaders/src/hlsl/miss.hlsl b/tests/graphics/shaders/src/hlsl/miss.hlsl index 2ec46cfc..8f4bdbda 100644 --- a/tests/graphics/shaders/src/hlsl/miss.hlsl +++ b/tests/graphics/shaders/src/hlsl/miss.hlsl @@ -4,8 +4,13 @@ struct RayPayload float3 color; }; +cbuffer MissRecord : register(b0) +{ + float3 missColor; +}; + [shader("miss")] void main(inout RayPayload payload) { - payload.color = float3(0.0, 0.0, 0.0); + payload.color = missColor; } \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index a58159ad..b0359452 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,8 +58,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - // registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); + registerTest(computeTest, "Compute Test"); + // registerTest(rayTracingTest, "Ray Tracing Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From fdc024bb9ab8fb980c173e38c1fe6d7a642aa3e8 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 13 May 2026 16:38:16 +0000 Subject: [PATCH 216/372] add multiple descriptor set test --- src/graphics/pal_d3d12.c | 7 +- src/graphics/pal_vulkan.c | 24 + tests/graphics/compute_test.c | 6 +- tests/graphics/multi_descriptor_set_test.c | 720 ++++++++++++++++++ .../shaders/bin/dxil/compute_multi.dxil | Bin 0 -> 3848 bytes .../shaders/bin/spirv/compute_multi.spv | Bin 0 -> 2264 bytes .../shaders/src/glsl/compute_multi.glsl | 36 + .../shaders/src/hlsl/compute_multi.hlsl | 30 + tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 3 +- 11 files changed, 819 insertions(+), 11 deletions(-) create mode 100644 tests/graphics/multi_descriptor_set_test.c create mode 100644 tests/graphics/shaders/bin/dxil/compute_multi.dxil create mode 100644 tests/graphics/shaders/bin/spirv/compute_multi.spv create mode 100644 tests/graphics/shaders/src/glsl/compute_multi.glsl create mode 100644 tests/graphics/shaders/src/hlsl/compute_multi.hlsl diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 8c5233d0..b9495046 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -6697,7 +6697,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - desc.NumDescriptors = resourceCount * info->maxDescriptorSets; + desc.NumDescriptors = resourceCount; result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( d3dDevice->handle, @@ -6741,7 +6741,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; - desc.NumDescriptors = limits->maxSamplers * info->maxDescriptorSets; + desc.NumDescriptors = limits->maxSamplers; result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( d3dDevice->handle, @@ -6928,9 +6928,6 @@ PalResult PAL_CALL updateDescriptorSetD3D12( DescriptorHeap* heap = nullptr; Uint32 index = 0; Uint32 bindingOffset = binding->range.OffsetInDescriptorsFromTableStart; - if (info->arrayElement + binding->range.NumDescriptors > layout->bindingCount) { - return PAL_RESULT_INVALID_ARGUMENT; - } if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { heap = &pool->samplerHeap; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index ce3a1ce9..0b8ebfb3 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1950,6 +1950,10 @@ static Barrier barrierToVk( for (int i = 0; i < stageCount; i++) { barrier.stages |= pipelineStageToVk(shaderStages[i]); } + + if (barrier.stages == 0) { + barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + } barrier.access = VK_ACCESS_2_UNIFORM_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -1961,6 +1965,10 @@ static Barrier barrierToVk( barrier.stages |= pipelineStageToVk(shaderStages[i]); } + if (barrier.stages == 0) { + barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + } + barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; return barrier; @@ -1971,6 +1979,10 @@ static Barrier barrierToVk( barrier.stages |= pipelineStageToVk(shaderStages[i]); } + if (barrier.stages == 0) { + barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + } + barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_GENERAL; return barrier; @@ -1981,6 +1993,10 @@ static Barrier barrierToVk( barrier.stages |= pipelineStageToVk(shaderStages[i]); } + if (barrier.stages == 0) { + barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + } + barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_GENERAL; return barrier; @@ -1991,6 +2007,10 @@ static Barrier barrierToVk( barrier.stages |= pipelineStageToVk(shaderStages[i]); } + if (barrier.stages == 0) { + barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + } + barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_GENERAL; return barrier; @@ -2027,6 +2047,10 @@ static Barrier barrierToVk( barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR; } + if (barrier.stages == 0) { + barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + } + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index b6ba372a..5223a798 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -231,9 +231,7 @@ bool computeTest() return false; } - bufferCreateInfo.size = bufferBytes; bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_DST; - result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -514,8 +512,8 @@ bool computeTest() // set a barrier so we only read from the buffer after the shader has written to it PalUsageStateInfo oldUsageStateInfo = {0}; oldUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; - oldUsageStateInfo.shaderStageCount = 0; - oldUsageStateInfo.shaderStages = nullptr; + oldUsageStateInfo.shaderStageCount = 1; + oldUsageStateInfo.shaderStages = shaderStages; PalUsageStateInfo newUsageStateInfo = {0}; newUsageStateInfo.shaderStageCount = 0; diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c new file mode 100644 index 00000000..2a822a21 --- /dev/null +++ b/tests/graphics/multi_descriptor_set_test.c @@ -0,0 +1,720 @@ + +#include "pal/pal_graphics.h" +#include "tests.h" + +#define BUFFER_SIZE 400 +#define BUFFER_COUNT 3 +#define DESCRIPTOR_SET_COUNT 2 + +// layout must match shader +typedef struct { + Uint32 width; + Uint32 height; + Uint32 _padding[2]; + float setColor1[4]; + float setColor2[4]; + float set1Color[4]; +} PushConstant; + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) +{ + palLog(nullptr, msg); +} + +bool multiDescriptorSetTest() +{ + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalQueue* queue = nullptr; + PalCommandPool* cmdPool = nullptr; + PalCommandBuffer* cmdBuffer; + PalShader* shader = nullptr; + + PalBuffer* buffers[BUFFER_COUNT]; + PalBuffer* stagingBuffers[BUFFER_COUNT]; + PalMemory* bufferMemories[BUFFER_COUNT]; + PalMemory* stagingBufferMemories[BUFFER_COUNT]; + + PalDescriptorPool* descriptorPool = nullptr; + PalDescriptorSetLayout* descriptorSetLayouts[DESCRIPTOR_SET_COUNT]; + PalDescriptorSet* descriptorSets[DESCRIPTOR_SET_COUNT]; + + PalPipelineLayout* pipelineLayout = nullptr; + PalPipeline* pipeline = nullptr; + PalFence* fence = nullptr; + + PalGraphicsDebugger debugger = {0}; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; + + PalResult result = palInitGraphics(nullptr, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (adapterCount == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", adapterCount); + + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&adapterCount, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + PalAdapterCapabilities caps = {0}; + PalAdapterFeatures adapterFeatures = 0; + PalAdapterInfo adapterInfo = {0}; + bool hasComputeQueue = false; + bool hasRequiredPushConstantSize = false; + bool hasRequiredBoundDescriptorSets = false; + for (Int32 i = 0; i < adapterCount; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (caps.maxComputeQueues == 0) { + hasComputeQueue = false; + continue; + + } else { + hasComputeQueue = true; + } + + // we want an adapter that supports the required bound descriptor sets (2) + if (caps.maxBoundDescriptorSets < 2) { + hasRequiredBoundDescriptorSets = false; + continue; + + } else { + hasRequiredBoundDescriptorSets = true; + } + + // we want an adapter that supports the required push constant size (64 bytes) + if (caps.maxPushConstantSize < 64) { + hasRequiredPushConstantSize = false; + continue; + + } else { + hasRequiredPushConstantSize = true; + } + + if (hasComputeQueue) { + // We want an adapter that supports spirv 1.0 or dxil 6.0 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { + break; + } + } + } + adapter = nullptr; + } + + palFree(nullptr, adapters); + if (!adapter) { + if (!hasComputeQueue) { + palLog(nullptr, "Failed to find an adapter that supports compute queue"); + + } else if (!hasRequiredBoundDescriptorSets) { + palLog( + nullptr, + "Failed to find an adapter that has the required bound descriptor sets"); + + } else if (!hasRequiredPushConstantSize) { + palLog(nullptr, "Failed to find an adapter that has the required push constant size"); + + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } + return false; + } + + // create a device + result = palCreateDevice(adapter, 0, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create a compute command queue + result = palCreateQueue(device, PAL_QUEUE_TYPE_COMPUTE, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + result = palCreateCommandPool(device, queue, &cmdPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + result = palAllocateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffer); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate command buffer: %s", error); + return false; + } + + // create a compute shader + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + const char* source = nullptr; + + PalShaderCreateInfo shaderCreateInfo = {0}; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + source = "graphics/shaders/bin/spirv/compute_multi.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + source = "graphics/shaders/bin/dxil/compute_multi.dxil"; + } + + // read file + if (!readFile(source, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(source, bytecode, &bytecodeSize); + + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.entryName = "main"; + shaderCreateInfo.stage = PAL_SHADER_STAGE_COMPUTE; + + result = palCreateShader(device, &shaderCreateInfo, &shader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create compute shader: %s", error); + return false; + } + + palFree(nullptr, bytecode); + + // create a storage buffer + Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader + PalBufferCreateInfo bufferCreateInfo = {0}; + bufferCreateInfo.size = bufferBytes; + + for (int i = 0; i < BUFFER_COUNT; i++) { + bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE | PAL_BUFFER_USAGE_TRANSFER_SRC; + + result = palCreateBuffer(device, &bufferCreateInfo, &buffers[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create buffer: %s", error); + return false; + } + + bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_DST; + result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffers[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create buffer: %s", error); + return false; + } + + // get buffer memory requirement and allocate memory + PalMemoryRequirements memReq = {0}; + PalMemoryRequirements stagingMemReq = {0}; + + result = palGetBufferMemoryRequirements(buffers[i], &memReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(stagingBuffers[i], &stagingMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + memReq.memoryMask, + memReq.size, + &bufferMemories[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_READBACK, + stagingMemReq.memoryMask, + stagingMemReq.size, + &stagingBufferMemories[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + // bind memory + result = palBindBufferMemory(buffers[i], bufferMemories[i], 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + result = palBindBufferMemory(stagingBuffers[i], stagingBufferMemories[i], 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + } + + // create descriptor set layout + PalDescriptorSetLayoutBinding descriptorBinding = {0}; + PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_COMPUTE }; + + descriptorBinding.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorBinding.shaderStageCount = 1; + descriptorBinding.shaderStages = shaderStages; + + PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; + descriptorSetLayoutcreateInfo.bindingCount = 1; + descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; + + descriptorBinding.descriptorCount = 2; // an array + result = palCreateDescriptorSetLayout( + device, + &descriptorSetLayoutcreateInfo, + &descriptorSetLayouts[0]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor set layout: %s", error); + return false; + } + + descriptorBinding.descriptorCount = 1; // not an array + result = palCreateDescriptorSetLayout( + device, + &descriptorSetLayoutcreateInfo, + &descriptorSetLayouts[1]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor set layout: %s", error); + return false; + } + + // create descriptor pool + PalDescriptorPoolBindingSize storageBufferBindingsize = {0}; + storageBufferBindingsize.bindingCount = 3; // across all sets + storageBufferBindingsize.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + + PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; + descriptorPoolCreateInfo.maxDescriptorSets = 2; // only one set + descriptorPoolCreateInfo.maxDescriptorBindingSizes = 1; // one binding type + descriptorPoolCreateInfo.bindingSizes = &storageBufferBindingsize; + + result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor pool: %s", error); + return false; + } + + // allocate the sets from the descriptor pool + for (int i = 0; i < DESCRIPTOR_SET_COUNT; i++) { + result = palAllocateDescriptorSet( + device, + descriptorPool, + descriptorSetLayouts[i], + &descriptorSets[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate descriptor set: %s", error); + return false; + } + } + + // write the inital data to the descriptor set since its created empty + Uint32 bindingCounts[DESCRIPTOR_SET_COUNT] = { 2, 1 }; + Uint32 bufferOffsets[DESCRIPTOR_SET_COUNT] = { 0, 2 }; + PalDescriptorSetWriteInfo writeInfos[DESCRIPTOR_SET_COUNT]; + PalDescriptorBufferInfo descriptorBufferInfos[BUFFER_COUNT]; + + for (int i = 0; i < BUFFER_COUNT; i++) { + descriptorBufferInfos[i].buffer = buffers[i]; + descriptorBufferInfos[i].offset = 0; + descriptorBufferInfos[i].size = bufferBytes; + descriptorBufferInfos[i].stride = 16; // sizeof(vec4) or float4. + } + + for (int i = 0; i < DESCRIPTOR_SET_COUNT; i++) { + writeInfos[i].layoutBindingIndex = 0; // single descriptor binding + writeInfos[i].bufferInfos = &descriptorBufferInfos[bufferOffsets[i]]; + writeInfos[i].descriptorSet = descriptorSets[i]; + writeInfos[i].descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; + writeInfos[i].descriptorCount = bindingCounts[i]; + + writeInfos[i].arrayElement = 0; + writeInfos[i].imageViewInfos = nullptr; + writeInfos[i].samplerInfos = nullptr; + writeInfos[i].tlasInfos = nullptr; + } + + result = palUpdateDescriptorSet(device, DESCRIPTOR_SET_COUNT, writeInfos); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to update descriptor set: %s", error); + return false; + } + + // push constants + // size must be less than the max size from the adapter capabilities struct + PalPushConstantRange pushConstantRange = {0}; + pushConstantRange.offset = 0; + pushConstantRange.size = sizeof(PushConstant); // must match shader + pushConstantRange.shaderStageCount = 1; + pushConstantRange.shaderStages = shaderStages; + + // create pipeline layout + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + pipelineLayoutCreateInfo.descriptorSetLayoutCount = DESCRIPTOR_SET_COUNT; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; + pipelineLayoutCreateInfo.descriptorSetLayouts = descriptorSetLayouts; + pipelineLayoutCreateInfo.pushConstantRanges = &pushConstantRange; + + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline layout: %s", error); + return false; + } + + // create a compute pipeline + PalComputePipelineCreateInfo pipelineCreateInfo = {0}; + pipelineCreateInfo.computeShader = shader; + pipelineCreateInfo.pipelineLayout = pipelineLayout; + + result = palCreateComputePipeline(device, &pipelineCreateInfo, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create compute pipeline: %s", error); + return false; + } + + palDestroyShader(shader); + + // create fence + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + // record commands + result = palCmdBegin(cmdBuffer, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + PushConstant pushConstant = {0}; + pushConstant.width = BUFFER_SIZE; + pushConstant.height = BUFFER_SIZE; + + // set 0 data + // red + pushConstant.setColor1[0] = 1.0f; + pushConstant.setColor1[1] = 0.0f; + pushConstant.setColor1[2] = 0.0f; + pushConstant.setColor1[3] = 1.0f; + + // green + pushConstant.setColor2[0] = 0.0f; + pushConstant.setColor2[1] = 1.0f; + pushConstant.setColor2[2] = 0.0f; + pushConstant.setColor2[3] = 1.0f; + + // set 1 data + // blue + pushConstant.set1Color[0] = 0.0f; + pushConstant.set1Color[1] = 0.0f; + pushConstant.set1Color[2] = 1.0f; + pushConstant.set1Color[3] = 1.0f; + + result = palCmdBindPipeline(cmdBuffer, pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + result = palCmdPushConstants( + cmdBuffer, + 1, + shaderStages, + 0, + sizeof(PushConstant), + &pushConstant); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to push constants: %s", error); + return false; + } + + result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSets[0]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind descriptor set: %s", error); + return false; + } + + // bind second descriptor set + result = palCmdBindDescriptorSet(cmdBuffer, 1, descriptorSets[1]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind descriptor set: %s", error); + return false; + } + + // we will use a helper function to calculate the number of group count + // we need on each axis. The workGroupSize on each axis must be less or equal + // to maxComputeWorkGroupInvocations from the adapter capabilities struct + PalWorkGroupBuildData buildData = {0}; + buildData.workCount[0] = BUFFER_SIZE; + buildData.workCount[1] = BUFFER_SIZE; + buildData.workCount[2] = 1; // no Z + + buildData.workGroupSize[0] = 16; // must match shader (local_size on glsl) + buildData.workGroupSize[1] = 16; // must match shader (local_size on glsl) + buildData.workGroupSize[2] = 1; // must match shader (local_size on glsl) + + // device limits + buildData.workGroupCount[0] = caps.maxComputeWorkGroupCount[0]; + buildData.workGroupCount[1] = caps.maxComputeWorkGroupCount[1]; + buildData.workGroupCount[2] = caps.maxComputeWorkGroupCount[2]; + + Uint32 workGroupInfoCount = 0; + PalWorkGroupInfo* workGroupInfos = nullptr; + bool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); + if (!ret) { + palLog(nullptr, "Failed to build work group info"); + return false; + } + + workGroupInfos = palAllocate(nullptr, sizeof(PalWorkGroupInfo) * workGroupInfoCount, 0); + if (!workGroupInfos) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, workGroupInfos); + + // dispatch with the work group info + for (int i = 0; i < workGroupInfoCount; i++) { + // palDispatchBase is not supported on all platforms so we dont use it for this example + // We cap the buffer size small so we only get a single dispatch + // but you can add fields in yout constants to send the base to the shader driectly + Uint32 groupCountX = workGroupInfos[i].workGroupCount[0]; + Uint32 groupCountY = workGroupInfos[i].workGroupCount[1]; + Uint32 groupCountZ = workGroupInfos[i].workGroupCount[2]; + + result = palCmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to dispatch: %s", error); + return false; + } + } + palFree(nullptr, workGroupInfos); + + // set a barrier so we only read from the buffer after the shader has written to it + PalUsageStateInfo oldUsageStateInfo = {0}; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; + oldUsageStateInfo.shaderStageCount = 1; + oldUsageStateInfo.shaderStages = shaderStages; + + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.shaderStageCount = 0; + newUsageStateInfo.shaderStages = nullptr; + newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; + + for (int i = 0; i < BUFFER_COUNT; i++) { + result = palCmdBufferBarrier( + cmdBuffer, + buffers[i], + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // now we copy from the GPU buffer into the staging buffer + PalBufferCopyInfo copyInfo = {0}; + copyInfo.size = bufferBytes; + + result = palCmdCopyBuffer(cmdBuffer, stagingBuffers[i], buffers[i], ©Info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer: %s", error); + return false; + } + } + + result = palCmdEnd(cmdBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // submit the command buffer to the GPU + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffer; + submitInfo.fence = fence; + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // wait for the fence + result = palWaitFence(fence, PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } + + const char* names[3] = { "compute_output1.ppm", "compute_output2.ppm", "compute_output3.ppm" }; + for (int i = 0; i < BUFFER_COUNT; i++) { + // now our staging buffer has the contents of the GPU buffer + // we map it and copy the contents to a ppm buffer and save it + void* ptr = nullptr; + result = palMapBufferMemory(stagingBuffers[i], 0, bufferBytes, &ptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map buffer memory: %s", error); + return false; + } + + // write to a ppm output file + FILE* file = fopen(names[i], "wb"); + fprintf(file, "P6\n%d %d\n255\n", BUFFER_SIZE, BUFFER_SIZE); + float* pixels = (float*)ptr; + for (int y = 0; y < BUFFER_SIZE; y++) { + int row = BUFFER_SIZE - 1 - y; // flip y + for (int x = 0; x < BUFFER_SIZE; x++) { + int index = row * BUFFER_SIZE + x; + Uint8 rgb[3]; + + rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; + rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; + rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255: 0; + fwrite(rgb, 1, 3, file); + } + } + + fclose(file); + palUnmapBufferMemory(stagingBuffers[i]); + } + + palDestroyPipeline(pipeline); + palDestroyPipelineLayout(pipelineLayout); + palFreeCommandBuffer(cmdBuffer); + palDestroyCommandPool(cmdPool); + + palDestroyDescriptorPool(descriptorPool); + for (int i = 0; i < DESCRIPTOR_SET_COUNT; i++) { + palDestroyDescriptorSetLayout(descriptorSetLayouts[i]); + } + + for (int i = 0; i < BUFFER_COUNT; i++) { + palDestroyBuffer(buffers[i]); + palFreeMemory(device, bufferMemories[i]); + + palDestroyBuffer(stagingBuffers[i]); + palFreeMemory(device, stagingBufferMemories[i]); + } + + palDestroyFence(fence); + palDestroyQueue(queue); + palDestroyDevice(device); + palShutdownGraphics(); + return true; +} diff --git a/tests/graphics/shaders/bin/dxil/compute_multi.dxil b/tests/graphics/shaders/bin/dxil/compute_multi.dxil new file mode 100644 index 0000000000000000000000000000000000000000..10c03bedae8f4ee1d16e14dbe6d9e99601dc18cb GIT binary patch literal 3848 zcmeHKeNYo;8sB6$n~iLeg+#hBfm=X0tJo%l318Y~2}V%p1xcyBD|ZPBjVHl?$btQs zgam>$*eKWnZ9SsWqn_vCN6%(XZxRwHT2MHx#S<-5q3T#=JkH{bGk5O>akx(B{zk|Y=XCi>k2(uqX z5FjKFHjw#+|F|=^_S_i$9s8W0`F6%OSLWLxvvE`Tvt>73MgYOIYHdct|{n`8x0oc&rjy&42fKqcG;-sCMBp#lv26To1Wn5+gFd z#b@m?LwK02PT#1!*s<-R<)P>SvFE&5e>9@`?NL>1A9;Wc>R0^v7(LZ45lGu--l^SVF#)0&c5gNr@I_~zvkX>1)N5?A`1RR*WZ z5zKa+6>KsD^_aD zR1=HrrpXg5$@g%P&7r@zbrQ(f( z=h7j&9J8wkyMl@9{N89Q+t^(EsdD@%DYfRW!^Gvm|th%JKpl-iFvhOq5Psx|tUb!HBS#qTX zdRo))b?i&3Zwr5%Qm9IaA6dG4+&eVk-^=lOPY>4*0~dpN;rD&Q+rVdwclgW%eY(>- zJebGRdcuIOk)M4aEovJbZBZ{|;+l!Ye9$T}t1LJ!D;2X=HfmBG0avD#TU*23+FF56 zLc(td!L(JN#51FN{88sTvQjxG1hY#A;FbNFl`eSYK#i-)!hH?n)@C~`7VdTnTwUX| zP)^A}xZsXkFfJFC%Z1mc1XDVJk_bj!ivbxZs>c{zD&LWD%APT#Njm|rIAveqfHMZB z#MK7wYbI`r$yo_%tJC6kS`6IkCEV&64siP`tMeC_vx0P1wmNHDZHafM1b4>-fAb0M z$l>CCkh(mf1m=;A8f9l=WIR}U7V7x#-dpjedLbwLXtOB%&5A1t-Hhc=gl-j`)d}PAMu-DBqibsyy<%C5W{ha z7kcpEQ0gw&OvdhLr%c0$(WIgry+qIgh_4K0=_PWSfFhW0RFQ)Zxb|Gbcx?k88Ls`Z zq4+w)#}9QMz5KEF;O@QN;XGd5QYN97RBqk0rM!T>pC{S3vxs~TB;gic7f9ww&PZ)x z!WYxp!ah}e_F0g&`}Yo>{`^eSUXZkprGvR8~Br^Xm%>P#Mnj?4CC_1X(vsN9iWi|7e3B{p2sLntX^-t*r8fmtbBD24io&D-`FQE>p#P~q`(l~or*;-w#zMpN@oA0k-{_}atoNprUv+ta5QlI@FX5V<*KHFvVTBB0kPJLa; zP4=a&*2Y%rVOlZz6?bjawySl(0>3-h&0L`8T>#7Ho8#HUUHSZ{*#Gj;%S_sP=|zqs z^W?>xMzLLiIVUmC7?^Vs^Bx21%&=k(Gsid|N|||B!(8i6v3DWC5$87EWxSZY#yf*k zh%4-owwc=V=y|@FL!M78_?(G+o=-mQJl`v9=W_%(K-cy?LbmzpgXCDRh`0`6^YNsZ z{vviayO^SXH@i7<=$F3(5x%YUs5J!J!4z-T7(~~0_QOOu zbMqB_A=W>H-GdloeQn>YnCJ8CMZ|vWL;EP=GXEI6v2sVBG1G`YgU|dE^y!^je;D1n z)sDPrbmw*)-dpVY#jJCiU7xspYWp66jO?A`m- z_OAW!(4N7Tb1&jMSppUB%P?`5^S%eOJo-wo%d;O5vp>1Kw*!c{G2W;D2fhLCIbu#^ z_*Y_llf#I4;$PqqJBf(@pza8}>o-2}A|mEF)uW$Lbo+5GQR_6ic=U4?-F|#W5pxb* zJo-70Zl3rrYD6vf?@Y-4E+F>joQ*Fc_BzJyvR7j+B4YNc{)cI*i$&k#=>PY91x!5p z_CN3cIbH)3|4bLoegZL1Jh&&(<<8&Hb!_oZS>6qFbH%-9--lSt=PtUKoPG=U5qt3) zF~+z401+=SpA!2+#Ba)bSLBde`~ec&v*>y5N7!=DWifI;M#O`=j4ro#D7PGPiyIr< ki|Bdo=h$*T%VOkSLc~i<(7s= pc.width || id.y >= pc.height) { + return; + } + + uint index = id.y * pc.width + id.x; + outBuffers[0].pixels[index] = pc.bufferColor1; + outBuffers[1].pixels[index] = pc.bufferColor2; + outBuffer.pixels[index] = pc.bufferColor3; +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/compute_multi.hlsl b/tests/graphics/shaders/src/hlsl/compute_multi.hlsl new file mode 100644 index 00000000..e074422a --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/compute_multi.hlsl @@ -0,0 +1,30 @@ + +cbuffer PushConstants : register(b0) +{ + uint width; + uint height; + float4 bufferColor1; + float4 bufferColor2; + float4 bufferColor3; +}; + +// we use structured buffer for this example. +// Some drivers do not map the registers well if we declare as an array +// some use index 0 and so use index 1. For portability, we make the registers explicit +RWStructuredBuffer outBuffer1 : register(u0, space0); // set 0 +RWStructuredBuffer outBuffer2 : register(u1, space0); // set 0 + +RWStructuredBuffer outBuffer3 : register(u0, space1); // set 1 + +[numthreads(16, 16, 1)] +void main(uint3 id : SV_DispatchThreadID) +{ + if (id.x >= width || id.y >= height) { + return; + } + + uint index = id.y * width + id.x; + outBuffer1[index] = bufferColor1; + outBuffer2[index] = bufferColor2; + outBuffer3[index] = bufferColor3; +} diff --git a/tests/tests.h b/tests/tests.h index 12565bc2..399941c4 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -82,6 +82,7 @@ bool multiThreadOpenGlTest(); bool graphicsTest(); bool computeTest(); bool rayTracingTest(); +bool multiDescriptorSetTest(); // graphics and video bool clearColorTest(); diff --git a/tests/tests.lua b/tests/tests.lua index c84fe701..7a21fce9 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -71,7 +71,8 @@ project "tests" files { "graphics/graphics_test.c", "graphics/compute_test.c", - "graphics/ray_tracing_test.c" + "graphics/ray_tracing_test.c", + "graphics/multi_descriptor_set_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index b0359452..2c0b34d4 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,8 +58,9 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); - registerTest(computeTest, "Compute Test"); + //registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); + registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO From dc8c75c4122c9fdccc8a0dfdbdccacf6569c7c5c Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 14 May 2026 12:06:51 +0000 Subject: [PATCH 217/372] add geometry test --- src/graphics/pal_d3d12.c | 13 +- src/graphics/pal_vulkan.c | 13 +- tests/graphics/geometry_test.c | 779 ++++++++++++++++++ tests/graphics/shaders/bin/dxil/geometry.dxil | Bin 0 -> 3824 bytes .../shaders/bin/dxil/geometry_vert.dxil | Bin 0 -> 3020 bytes tests/graphics/shaders/bin/spirv/geometry.spv | Bin 0 -> 2456 bytes .../shaders/bin/spirv/geometry_vert.spv | Bin 0 -> 1220 bytes tests/graphics/shaders/src/glsl/geometry.glsl | 33 + .../shaders/src/glsl/geometry_vert.glsl | 14 + .../shaders/src/glsl/triangle_vert.glsl | 2 +- tests/graphics/shaders/src/hlsl/geometry.hlsl | 41 + .../shaders/src/hlsl/geometry_vert.hlsl | 18 + tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 3 +- 15 files changed, 915 insertions(+), 5 deletions(-) create mode 100644 tests/graphics/geometry_test.c create mode 100644 tests/graphics/shaders/bin/dxil/geometry.dxil create mode 100644 tests/graphics/shaders/bin/dxil/geometry_vert.dxil create mode 100644 tests/graphics/shaders/bin/spirv/geometry.spv create mode 100644 tests/graphics/shaders/bin/spirv/geometry_vert.spv create mode 100644 tests/graphics/shaders/src/glsl/geometry.glsl create mode 100644 tests/graphics/shaders/src/glsl/geometry_vert.glsl create mode 100644 tests/graphics/shaders/src/hlsl/geometry.hlsl create mode 100644 tests/graphics/shaders/src/hlsl/geometry_vert.hlsl diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index b9495046..4225da43 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -4233,13 +4233,24 @@ PalResult PAL_CALL createShaderD3D12( return PAL_RESULT_OUT_OF_MEMORY; } + // clang-format off if (info->stage == PAL_SHADER_STAGE_MESH || info->stage == PAL_SHADER_STAGE_TASK) { if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // clang-format off + } else if (info->stage == PAL_SHADER_STAGE_GEOMETRY) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || + info->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || info->stage == PAL_SHADER_STAGE_ANY_HIT || diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 0b8ebfb3..e25e340d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -6088,13 +6088,24 @@ PalResult PAL_CALL createShaderVk( return PAL_RESULT_OUT_OF_MEMORY; } + // clang-format off if (info->stage == PAL_SHADER_STAGE_MESH || info->stage == PAL_SHADER_STAGE_TASK) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // clang-format off + } else if (info->stage == PAL_SHADER_STAGE_GEOMETRY) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || + info->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || info->stage == PAL_SHADER_STAGE_ANY_HIT || diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c new file mode 100644 index 00000000..69b16c79 --- /dev/null +++ b/tests/graphics/geometry_test.c @@ -0,0 +1,779 @@ + +#include "pal/pal_graphics.h" +#include "pal/pal_video.h" +#include "pal/pal_system.h" +#include "tests.h" + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +#define MAX_FRAMES_IN_FLIGHT 2 + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) +{ + palLog(nullptr, msg); +} + +bool geometryTest() +{ + PalResult result; + PalWindow* window = nullptr; + PalEventDriver* eventDriver = nullptr; + PalGraphicsWindow gfxWindow; + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalSurface* surface = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + + PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalFence** inFlightImages; // count of swapchain images + + PalPipelineLayout* pipelineLayout = nullptr; + PalPipeline* pipeline = nullptr; + PalShader* shaders[3]; + + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create event driver: %s", error); + return false; + } + + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + + result = palInitVideo(nullptr, eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize video: %s", error); + return false; + } + + PalWindowCreateInfo windowCreateInfo = {0}; + windowCreateInfo.height = WINDOW_HEIGHT; + windowCreateInfo.width = WINDOW_WIDTH; + windowCreateInfo.show = true; + windowCreateInfo.title = "Geometry Window"; + + PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); + if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&windowCreateInfo, &window); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create window: %s", error); + return false; + } + + PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); + gfxWindow.display = winHandle.nativeDisplay; + gfxWindow.window = winHandle.nativeWindow; + + // using pal_system.h will be easy to know the underlying windowing API + // or use typedefs. We will use the pal_system module. This is needed + // for systems which multiple windowing APIs (linux). + PalPlatformInfo platformInfo = {0}; + result = palGetPlatformInfo(&platformInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get platform information: %s", error); + return false; + } + + if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + + } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + + } else { + // automatically this is xcb + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } + + PalGraphicsDebugger debugger = {0}; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; + + result = palInitGraphics(nullptr, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (adapterCount == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", adapterCount); + + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&adapterCount, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + PalAdapterCapabilities caps = {0}; + PalAdapterInfo adapterInfo = {0}; + bool hasGraphicsQueue = false; + bool hasGeometryShader = false; + PalAdapterFeatures adapterFeatures; + + for (Int32 i = 0; i < adapterCount; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (caps.maxGraphicsQueues == 0) { + hasGraphicsQueue = false; + continue; + + } else { + hasGraphicsQueue = true; + } + + if (hasGraphicsQueue) { + adapterFeatures = palGetAdapterFeatures(adapter); + if (adapterFeatures & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { + hasGeometryShader = true; + + } else { + hasGeometryShader = false; + } + } + + if (hasGeometryShader) { + // We want an adapter that supports spirv 1.0 or dxil 6.0 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { + break; + } + } + } + adapter = nullptr; + } + + palFree(nullptr, adapters); + if (!adapter) { + if (!hasGraphicsQueue) { + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); + + } else if (!hasGeometryShader) { + palLog(nullptr, "Failed to find an adapter that supports geometry shader"); + + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } + return false; + } + + // create a device + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + features |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + features |= PAL_ADAPTER_FEATURE_FENCE_RESET; + } + + result = palCreateDevice(adapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create surface + result = palCreateSurface(device, &gfxWindow, &surface); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create surface: %s", error); + return false; + } + + // create a graphics command queue and check if its supports presenting to the surface + bool foundQueue = false; + for (int i = 0; i < caps.maxGraphicsQueues; i++) { + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palDestroyQueue(queue); + queue = nullptr; + } else { + // found a queue + foundQueue = true; + break; + } + } + + if (!foundQueue) { + palLog(nullptr, "Failed to find a queue that can present to the surface"); + return false; + } + + // create a swapchain with the graphics queue + PalSurfaceCapabilities surfaceCaps = {0}; + result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get surface capabilities: %s", error); + return false; + } + + PalSwapchainCreateInfo swapchainCreateInfo = {0}; + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; + swapchainCreateInfo.height = WINDOW_HEIGHT; + swapchainCreateInfo.width = WINDOW_WIDTH; + swapchainCreateInfo.imageArrayLayerCount = 1; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR; + + // rare but possible on andriod + if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { + swapchainCreateInfo.width = surfaceCaps.maxImageWidth / 2; + } + + if (WINDOW_HEIGHT > surfaceCaps.maxImageHeight) { + swapchainCreateInfo.height = surfaceCaps.maxImageHeight / 2; + } + + // check if the minimal image count is not good for you + // and increase it but not pass the max count + swapchainCreateInfo.imageCount = surfaceCaps.minImageCount; + if (swapchainCreateInfo.imageCount == 1) { + swapchainCreateInfo.imageCount++; + if (surfaceCaps.maxImageCount < 2) { + palLog(nullptr, "Surface does not support double buffers"); + return false; + } + } + + result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create swapchain: %s", error); + return false; + } + + // get all swapchain images and create image views for them + Uint32 imageCount = swapchainCreateInfo.imageCount; + imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); + inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); + if (!imageViews || !inFlightImages) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + PalImageInfo imageInfo; + result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } + + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.subresourceRange.layerArrayCount = 1; + imageViewCreateInfo.subresourceRange.mipLevelCount = 1; + imageViewCreateInfo.subresourceRange.startArrayLayer = 0; + imageViewCreateInfo.subresourceRange.startMipLevel = 0; + imageViewCreateInfo.format = imageInfo.format; + + for (int i = 0; i < imageCount; i++) { + // get swapchain image + // this is fast since the images are cache by PAL + PalImage* image = palGetSwapchainImage(swapchain, i); + if (!image) { + palLog(nullptr, "Failed to get swapchain image"); + } + + result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + + inFlightImages[i] = nullptr; + } + + result = palCreateCommandPool(device, queue, &cmdPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + // create synchronization objects and command buffers + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateFence(device, true, &inFlightFences[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + result = palAllocateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffers[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate command buffer: %s", error); + return false; + } + } + + // create shaders + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + const char* sources[3]; + PalShaderStage tmpShaderStages[3]; + + PalShaderCreateInfo shaderCreateInfo = {0}; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + sources[0] = "graphics/shaders/bin/spirv/geometry_vert.spv"; + sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; + sources[2] = "graphics/shaders/bin/spirv/geometry.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + sources[0] = "graphics/shaders/bin/dxil/geometry_vert.dxil"; + sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; + sources[2] = "graphics/shaders/bin/dxil/geometry.dxil"; + } + + tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; + tmpShaderStages[1] = PAL_SHADER_STAGE_FRAGMENT; + tmpShaderStages[2] = PAL_SHADER_STAGE_GEOMETRY; + + for (int i = 0; i < 3; i++) { + // read file + if (!readFile(sources[i], nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(sources[i], bytecode, &bytecodeSize); + + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.entryName = "main"; + shaderCreateInfo.stage = tmpShaderStages[i]; + + result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create shader: %s", error); + return false; + } + + palFree(nullptr, bytecode); + } + + // create a pipeline layout + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline layout: %s", error); + return false; + } + + PalRenderingLayoutInfo renderingLayoutInfo = {0}; + renderingLayoutInfo.colorAttachentCount = 1; + renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; + renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.viewCount = 1; + + // create graphics pipeline + PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; + + // color blend attachment + PalColorBlendAttachment blendAttachment = {0}; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; + + pipelineCreateInfo.colorBlendAttachments = &blendAttachment; + pipelineCreateInfo.colorBlendAttachmentCount = 1; + + // shaders + pipelineCreateInfo.shaderCount = 3; + pipelineCreateInfo.shaders = shaders; + + pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + pipelineCreateInfo.pipelineLayout = pipelineLayout; + pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; + + result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create graphics pipeline: %s", error); + return false; + } + + for (int i = 0; i < 3; i++) { + palDestroyShader(shaders[i]); + } + + // main loop + Uint32 currentFrame = 0; + bool running = true; + + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + + PalRect2D scissor = {0}; + scissor.height = WINDOW_HEIGHT; + scissor.width = WINDOW_WIDTH; + + while (running) { + // update the video system to push video events + palUpdateVideo(); + + PalEvent event; + while (palPollEvent(eventDriver, &event)) { + switch (event.type) { + case PAL_EVENT_WINDOW_CLOSE: { + running = false; + break; + } + + case PAL_EVENT_KEYDOWN: { + PalKeycode keycode = 0; + palUnpackUint32(event.data, &keycode, nullptr); + if (keycode == PAL_KEYCODE_ESCAPE) { + running = false; + } + break; + } + } + } + + result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; + nextImageInfo.timeout = PAL_INFINITE; + + Uint32 imageIndex = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + if (inFlightImages[imageIndex] != nullptr) { + result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + inFlightImages[imageIndex] = inFlightFences[currentFrame]; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + result = palResetFence(inFlightFences[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + } else { + // recreate since we dont support fence resetting + palDestroyFence(inFlightFences[currentFrame]); + + result = palCreateFence(device, false, &inFlightFences[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + // reset the command buffer + result = palResetCommandBuffer(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to reset command buffer: %s", error); + return false; + } + + result = palCmdBegin(cmdBuffers[currentFrame], nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + // change the state of the image view to make it renderable + PalUsageStateInfo oldUsageStateInfo = {0}; + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + + PalImageSubresourceRange imageRange = {0}; + imageRange.layerArrayCount = 1; + imageRange.mipLevelCount = 1; + imageRange.startArrayLayer = 0; + imageRange.startMipLevel = 0; + + PalImage* image = palGetSwapchainImage(swapchain, imageIndex); + result = palCmdImageBarrier( + cmdBuffers[currentFrame], + image, + &imageRange, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + PalClearValue clearValue; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; + + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.clearValue = clearValue; + colorAttachment.imageView = imageViews[imageIndex]; + + PalRenderingInfo renderingInfo = {0}; + renderingInfo.viewCount = 1; + renderingInfo.colorAttachentCount = 1; + renderingInfo.colorAttachments = &colorAttachment; + + result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin rendering: %s", error); + return false; + } + + // bind pipeline + result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + // set viewport and scissors + result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set viewport: %s", error); + return false; + } + + result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set scissors: %s", error); + return false; + } + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind vertex buffer: %s", error); + return false; + } + + result = palCmdDraw(cmdBuffers[currentFrame], 3, 1, 0, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to issue draw command: %s", error); + return false; + } + + result = palCmdEndRendering(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end rendering: %s", error); + return false; + } + + // change the state of the image view to make it presentable + oldUsageStateInfo = newUsageStateInfo; + newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + result = palCmdImageBarrier( + cmdBuffers[currentFrame], + image, + &imageRange, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + result = palCmdEnd(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // submit command buffer + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffers[currentFrame]; + submitInfo.fence = inFlightFences[currentFrame]; + submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; + + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // present + PalSwapchainPresentInfo presentInfo = {0}; + presentInfo.imageIndex = imageIndex; + presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; + result = palPresentSwapchain(swapchain, &presentInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to present swapchain: %s", error); + return false; + } + + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + } + + result = palWaitQueue(queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for queue: %s", error); + return false; + } + + palDestroyPipeline(pipeline); + palDestroyPipelineLayout(pipelineLayout); + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + palDestroySemaphore(imageAvailableSemaphores[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); + palDestroyFence(inFlightFences[i]); + palFreeCommandBuffer(cmdBuffers[i]); + } + + for (int i = 0; i < imageCount; i++) { + palDestroyImageView(imageViews[i]); + } + + palDestroyCommandPool(cmdPool); + palDestroySwapchain(swapchain); + palDestroySurface(surface); + palDestroyQueue(queue); + palDestroyDevice(device); + palShutdownGraphics(); + palFree(nullptr, imageViews); + + palDestroyWindow(window); + palShutdownVideo(); + palDestroyEventDriver(eventDriver); + return true; +} \ No newline at end of file diff --git a/tests/graphics/shaders/bin/dxil/geometry.dxil b/tests/graphics/shaders/bin/dxil/geometry.dxil new file mode 100644 index 0000000000000000000000000000000000000000..75fc054f24b488145cff4f8274ab80de8a1b46df GIT binary patch literal 3824 zcmeHKeNaMdY1dTzklMsr4L8CYhPIXK`6suq$6am{c z36Y>i8x>bX>w==|TBi$WUBQn{2)YzO1Enom)`Ftz?r1mD?e5g6)9$?xtexp}c6R^i z?ChD`d(J)Q+;i@`_vQZ1OV3Nwyl&dHWoXlx8@Izg;&cJg%Xk0)pBMlF@>JNgu+_o# z7&ZqqUWA4r*m5(nI1=inC@XhS;#@dD^QZLjek0Ne{Bm&cq>#IEt!|5HWBJA{C15F> zyBezbuuaX)^!tBru3v}PiWg)Q8~OP|gBN3KmTH$Shc;dAO0EHNv_|9~02`Wv8lrC@ z@qrNV_~`e2LVJOTLfvG*V#CIg=W}VK_Y)7K3k2BI2*sZqPvzn9(t!XbKx32#xuR#z zU7=nPg9D(4+MUpto|mOXPAE17^=TT{T^U?}8R~+p?8MwKXd^7q`_w&H7Ea5P_w#I2 zYycS^h3(EaOJ3!t?GH+8q2&@K$t(_(FR#mVN?1)s-ANEGPaDq^JNM1()~T0S9Ah;P zc44zJ@MR1DFcpwGM$vWBPleaW(8ga5YDiH4!G3D0YfVr-aHWp;S*G2QU7Y7u+gT zM75qM_u>y}qGHlhFNP5&Js(0-69IjSN5wFXKf;7&L2!&y79FcHM`}5n8!inVLu-u? z=im;YEvVq!J`oh*uB0^ReQ@<=_=C>n@ZC}Y;1b6%7om}b2il`SZjP;#Rh9yDLwCOgtCq%B#8AXnGc8 zM*V;^LFQDk=$)&APr4cM=>n}YgCEwN$aTW1 zb9;;WPQLS2+rEK@#VKDmo`5sG_#?{8io7aO?L20(r8Sk=q> z#yY$Y+y?_XI<5@tK-$O3S3c?(IQRjaGVVXOWsoP4=7{dGi1iZQ!a9x8=5eH%iKe@t07Ym~g9+_6ZjDXcjsI3;QY^hq`j1}mo?a{8Z5Iv_lZ9r75~E}e#{B-dzvH0 znEX>7QK3X#hDao!zicTBKs4lW zF7oER^!-b}wu501t=t`!^~)zS_`m1wT<$H2WMPm@nd0&r2t6++d!l8<3~I#{+mQ6cDLi zBBw(JaYXWiIFj8AaU}aV)7zB#-y_H*hAe{l{$mV@Bd?!VGgROPQy5lrhhv3_>dH=$ zTdt0$LQw^_`qbI0O?Mv-J{r6`5=Z_qNv%98;w7q;jlwRsmUg^u)#piVy?0vaU`f`8 zT*%P-GFKk8FmYiPgqcE*yoio1_RQ6Ng7fYxs8xiPriwJn!aegh(>OP*o4c2=si!Fv zmlTKQw#(;t&Qj}kP`9qVr!ATDq`x>@HCN^_wFMQNOE_>OlzF4axB8*CtEYFo@orD= z@F^@SQl9#=OXu4!#k9}rk1;BJf zw<@S%iE1ZX11-#~3;z!k0MHa%)l-zlp;QG`@j#Ffo9%TH5gf8aKdi z!iiW-XWfiV%{1{6C&Tqlcc`HvochjOr)G}2<bxZlIlSq^sQ`UnD2BeT5d8}+%8zFN literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/geometry_vert.dxil b/tests/graphics/shaders/bin/dxil/geometry_vert.dxil new file mode 100644 index 0000000000000000000000000000000000000000..04dd6611ed5f061c90c02bce48aaeaefcf10cd3b GIT binary patch literal 3020 zcmeHJeN0=|6~E>^{On+!AJ|(BHt3nJx*|=CNsTE+!ZtAwOzVa$p&ckT2^lQl7)%+E zP4Tx4F^fl7VKu8vk|DZfDUftDS+yC%DnfzMC~ZK^QV5J>6G=UqRP9!6yU&I+`)8B3 zKekCb(mCh8^Lg)m@BZE`tWc`fPh{{veem)2ryuQP|G1}AiE(? zLe@g3kq&?da=E%h%z(BnDk(3@+65n|{4Kj^(+R`FcIuHv1wbm_e{g?IQ*%vgNg;Ut zALLTuNH_xk_NIop+GD1==DK4Bpe^4ownO_?@6C`$>aUQf8nEwH>qoxLsYK@6pszDf zahqP^Q50oU{9P^$6e0-v)x5Ss%l9ev@uC6H!3;GlR9I1>p$dj;LAz2FxFuu(kPmG! zRuV+PL=I%klKKP16k0+jB)Q!*J1ae!k&uj@tTq$7qmbSTn*IV00BXPao+WDOSV7cKtUW{x5t3S43G|2i zT6IbiK6gMt%}xumtOwps*^W8cu?4fA+Alz`nX#+v+?iNqSbc;nWf zb!*V5!>E9H`tKhLYbn6mby)K}eT~3cB9S^AR)|EdL6;wcF%3&Ntg~4mYd`l`Ik{2VLnSc~f*fDP^FFaf89COXE8cVFtr7Oj{5W?~V#}QkLzShDiLj zD&(z=DK)J~Y97{nBctemv$t@ULe|d={;{6nW(H|x1gpkojOBk_`RdSgq9_=Yq6xiE z{cPvZ*yUYUF6E3dgK=d9e#mO%a?nGIWaY0Re%x(s`WeZmRT zNakr@>2Z@Uo+z6NRjvmY)~8no(cMWBd2j9|@u=kTV9u!I7f;dlcCg-a>|kHmJ~ex< zYlmmYz1arCp84xkh0@GlmZtd5z)kbT%U_07rf=R|-SFSKcJuDqAbM!t!FsP|{pWLC z7c>UL9xpr$)V@uIql0VbxX*OcV8CYAf%V@;fjYvzY%SgHsX5#R5FTN~h8^r9D z5FXOv*~DbhEummRm=x3}9}#!ty=}{zSLI$pn!vMZ6MyjU<1gisrnXtU67fcHU zla{1uJ^e$kDtAhi+ZUE^O~`swGB=XfGqDpk{nDCu9myM>U`-0K?;4SIk*me*N_by| zf4)RtCGk5;^v?)1j@!=$ZWMt51wIM4<@TMU$UO6>@Ix>VE#uE>IEpR2DB0K9~B%nVlJ#l z(MXE9VR>$_;MR?weh>E^xKClFY!f@5g9r3+>?9w<&fU=WKZTw0e}bJ5jQ=~aQ}Y#e zo`aiCMzAyd@+k3dU}s0Q$hP6nbWk|T>>P1YsCg8^=ZOIdEgd6tKc&Mk>Q6q(aKrB5 zGh77qzl@z34E3mj$J*9n;-IQUG0DtQ)DFguOB5nBp8EG!4xazj`RUcW)1hv62BRn& zqGl{DOCfuWX&tF2hV&Ckxi+m#RjB#E8MqDMHTt2nSKa&Bnp7e4GlO~!@%?J6PRvI; zKN=<~21`B~jw>G%hNP?;SiL9_V*&p*zOTwxn)u?6_`mHThm_7c)dwKatKQ|y z3yzV+A6_kEdY(Ppy2DhfKU~vPcI-RmmnoxN-7 zCwsAnudJzaa?&GLr2pgGe;()bB)ogU@05cowo~^i2wk9gcYzeqZgUif)xb)+PozRy zDxC?eI&-Bh?djii>V4L)O{ke^0h0EPTM=a@d7^JNRe8nLUO+PF)2~z>;CgszfMKV4Uwyd-qwaDP{SB0_s7U|- literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/spirv/geometry.spv b/tests/graphics/shaders/bin/spirv/geometry.spv new file mode 100644 index 0000000000000000000000000000000000000000..0c6aa7a3eb41c74cd00f302146f49d60f04ffc8f GIT binary patch literal 2456 zcmZ{l*KSim5QaA-cIX{K$D!BIdkGLAlu$#xLI?~pGBJvcgt&sofVbcYka!Gu4+Ka^ zeBYik!HQs`(aii)cV~{%J7Z&iN#nwcJ^;w(xt_)B0_EGdnSjgJkrJ5PrW9@?wN z{M0MUwgtqg^+7KmHzvdnL&u>T&_b-*mS?#y%ZNEPY-_u0tB_|wz5Ln37aFJ#)tz5` zF1FUQXYG2Yo$UkYPg>2^WLy8v?yDer*4$Z|Cugg=vRSD)E|>vr`c{=a^-{jVQw|L&(R&x$&Econ*GZmrjy5uXz=T>|snJaY;*h1rXk zJp78?De47gZT+0%D4m#3KkaeX?%Z+D?%Z)dG4n<2^xWY$N;U7Y4)QFaqBRGJHb!|l zQWai<2Jq)&$hx*==riFp$g{K5i~US#4f&?5LMG2}_$)>jE8?oT<`Q)C8L!e3c?5m(K%)?hQQ@%s7R{ub1rp3M95?Cee4-olPL zrEf)co=chNwi0)4`yumq=L2xxKx`e7`xoz`O>%yR;O5ePqSXCf#f)>erpKB8D7dzG z(__fi7B`Q&zlm|Llcj7f>kh+1-S>}HAp{abUMrW zRq`y)pu2Z9$UB_L{BPc~=)Q&i=inod?=EgmXLBABkDM2fBWKjT2qu1m2xCSeG0D>d zy{Cq@OOST+dY>!st5D>0KX2h%g^xk{d+c97v532d9C3b=5qBNgIO`gxpIE%-P2{+@ zJANB-$He1K<0Wpq--P;CGCE&p?TqA+^A55zdPnc>**!?i@5LP2#Jcy#S$`{Yy0_+( dN6!1m_8B=JAd5v#ZDQsegd6YP{wC*9=npYguR;I- literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/spirv/geometry_vert.spv b/tests/graphics/shaders/bin/spirv/geometry_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..443bffbf1223429a38b47406044929641be52d1f GIT binary patch literal 1220 zcmYk5-Afc<6vkh7n^m(kGqn%1G3`@Zx~K>uLkhNFFBGBMkQ`)S8^xUXeH?Z4So4*$R3}J%eye0v;1b1{e%**_+7!oJ+Tf`p>K5b{m zAG6~!`$h^{UtpdlzWWLfr_u7 zvBr3TsDn?jMfARax!gSY1U|()>rFmMZ2c1XMZ7g)DY?DO#nt<*%a|wT)5O1j^*1-T zyV@B{jd;{tAx3i&HM0#b9@A+hr7ff{CFdO zpU7U$7Ws$7@Tc;Rh~&M?3wG-pdS{RLACLrZZ{NxP8GCKQ8oRsKaL%`kIolQ$&XrS$C3BF foWdv~gfFpwh{jC@ literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/src/glsl/geometry.glsl b/tests/graphics/shaders/src/glsl/geometry.glsl new file mode 100644 index 00000000..9c116eb0 --- /dev/null +++ b/tests/graphics/shaders/src/glsl/geometry.glsl @@ -0,0 +1,33 @@ + +#version 450 + +layout(triangles) in; +layout(triangle_strip, max_vertices = 9) out; + +layout(location = 0) out vec4 outColor; + +void main() +{ + vec2 offsets[3] = { + vec2(-0.6, 0.0 ), + vec2( 0.0, 0.0 ), + vec2( 0.6, 0.0 ) + }; + + vec4 colors[3] = { + vec4( 1.0, 0.0, 0.0, 1.0 ), + vec4( 0.0, 1.0, 0.0, 1.0 ), + vec4( 0.0, 0.0, 1.0, 1.0 ) + }; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + gl_Position = gl_in[j].gl_Position; + gl_Position.xy += offsets[i]; + outColor = colors[i]; + + EmitVertex(); + } + EndPrimitive(); + } +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/geometry_vert.glsl b/tests/graphics/shaders/src/glsl/geometry_vert.glsl new file mode 100644 index 00000000..b2764cbf --- /dev/null +++ b/tests/graphics/shaders/src/glsl/geometry_vert.glsl @@ -0,0 +1,14 @@ + +#version 450 + +void main() +{ + vec2 positions[3] = { + vec2( 0.0, 0.2), + vec2( 0.2, -0.2 ), + vec2(-0.2, -0.2 ) + }; + + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + gl_Position.y *= -1.0; +} diff --git a/tests/graphics/shaders/src/glsl/triangle_vert.glsl b/tests/graphics/shaders/src/glsl/triangle_vert.glsl index f396160c..55b9831a 100644 --- a/tests/graphics/shaders/src/glsl/triangle_vert.glsl +++ b/tests/graphics/shaders/src/glsl/triangle_vert.glsl @@ -8,6 +8,6 @@ layout(location = 0) out vec4 vColor; void main() { - gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); + gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); vColor = vec4(aColor, 1.0); } \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/geometry.hlsl b/tests/graphics/shaders/src/hlsl/geometry.hlsl new file mode 100644 index 00000000..3889613e --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/geometry.hlsl @@ -0,0 +1,41 @@ + +struct PSInput +{ + float4 pos : SV_POSITION; +}; + +struct GSOutput +{ + float4 pos : SV_POSITION; + float4 color : COLOR; +}; + +[maxvertexcount(9)] +void main( + triangle PSInput inputs[3], + inout TriangleStream stream) +{ + float2 offsets[3] = { + float2(-0.6, 0.0 ), + float2( 0.0, 0.0 ), + float2( 0.6, 0.0 ) + }; + + float4 colors[3] = { + float4( 1.0, 0.0, 0.0, 1.0 ), + float4( 0.0, 1.0, 0.0, 1.0 ), + float4( 0.0, 0.0, 1.0, 1.0 ) + }; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + GSOutput output; + output.pos = inputs[j].pos; + output.pos.xy += offsets[i]; + output.color = colors[i]; + + stream.Append(output); + } + stream.RestartStrip(); + } +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/geometry_vert.hlsl b/tests/graphics/shaders/src/hlsl/geometry_vert.hlsl new file mode 100644 index 00000000..783bb59c --- /dev/null +++ b/tests/graphics/shaders/src/hlsl/geometry_vert.hlsl @@ -0,0 +1,18 @@ + +struct VSOutput +{ + float4 pos : SV_POSITION; +}; + +VSOutput main(uint vertexId : SV_VertexID) +{ + float2 positions[3] = { + float2( 0.0, 0.2), + float2( 0.2, -0.2 ), + float2(-0.2, -0.2 ) + }; + + VSOutput output; + output.pos = float4(positions[vertexId], 0.0, 1.0); + return output; +} diff --git a/tests/tests.h b/tests/tests.h index 399941c4..73b774d2 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -89,5 +89,6 @@ bool clearColorTest(); bool triangleTest(); bool meshTest(); bool textureTest(); +bool geometryTest(); #endif // _TESTS_H diff --git a/tests/tests.lua b/tests/tests.lua index 7a21fce9..1637e0be 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -81,7 +81,8 @@ project "tests" "graphics/clear_color_test.c", "graphics/triangle_test.c", "graphics/mesh_test.c", - "graphics/texture_test.c" + "graphics/texture_test.c", + "graphics/geometry_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 2c0b34d4..007e988a 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -60,7 +60,7 @@ int main(int argc, char** argv) // registerTest(graphicsTest, "Graphics Test"); //registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); - registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); + // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO @@ -68,6 +68,7 @@ int main(int argc, char** argv) // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); + registerTest(geometryTest, "Geometry Test"); #endif // runTests(); From 91c9821c03073cf5094f6c7ed04f726ebb5cd30d Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 17 May 2026 15:31:50 +0000 Subject: [PATCH 218/372] fix vlidation warnings --- tests/graphics/clear_color_test.c | 29 ++++++++------- tests/graphics/geometry_test.c | 31 +++++++++------- tests/graphics/mesh_test.c | 31 +++++++++------- tests/graphics/multi_descriptor_set_test.c | 42 +++++++++++----------- tests/graphics/texture_test.c | 31 +++++++++------- tests/graphics/triangle_test.c | 31 +++++++++------- tests/tests_main.c | 16 ++++----- 7 files changed, 117 insertions(+), 94 deletions(-) diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index 679508b1..12392246 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -34,8 +34,8 @@ bool clearColorTest() PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images PalFence** inFlightImages; // count of swapchain images PalEventDriverCreateInfo eventDriverCreateInfo = {0}; @@ -264,7 +264,8 @@ bool clearColorTest() Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); - if (!imageViews || !inFlightImages) { + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); + if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); return false; } @@ -300,6 +301,14 @@ bool clearColorTest() return false; } + // create render finished semaphores + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + inFlightImages[i] = nullptr; } @@ -319,13 +328,6 @@ bool clearColorTest() return false; } - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - result = palCreateFence(device, true, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -522,7 +524,7 @@ bool clearColorTest() submitInfo.cmdBuffer = cmdBuffers[currentFrame]; submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; - submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -534,7 +536,7 @@ bool clearColorTest() // present PalSwapchainPresentInfo presentInfo = {0}; presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; + presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -554,12 +556,12 @@ bool clearColorTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { palDestroySemaphore(imageAvailableSemaphores[i]); - palDestroySemaphore(renderFinishedSemaphores[i]); palDestroyFence(inFlightFences[i]); palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { + palDestroySemaphore(renderFinishedSemaphores[i]); palDestroyImageView(imageViews[i]); } @@ -569,7 +571,10 @@ bool clearColorTest() palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); + palFree(nullptr, imageViews); + palFree(nullptr, renderFinishedSemaphores); + palFree(nullptr, inFlightImages); palDestroyWindow(window); palShutdownVideo(); diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index 69b16c79..c0c6f0ef 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -34,8 +34,8 @@ bool geometryTest() PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; @@ -316,7 +316,8 @@ bool geometryTest() Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); - if (!imageViews || !inFlightImages) { + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); + if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); return false; } @@ -352,6 +353,14 @@ bool geometryTest() return false; } + // create render finished semaphores + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + inFlightImages[i] = nullptr; } @@ -371,13 +380,6 @@ bool geometryTest() return false; } - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - result = palCreateFence(device, true, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -720,7 +722,7 @@ bool geometryTest() submitInfo.cmdBuffer = cmdBuffers[currentFrame]; submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; - submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -732,7 +734,7 @@ bool geometryTest() // present PalSwapchainPresentInfo presentInfo = {0}; presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; + presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -755,13 +757,13 @@ bool geometryTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { palDestroySemaphore(imageAvailableSemaphores[i]); - palDestroySemaphore(renderFinishedSemaphores[i]); palDestroyFence(inFlightFences[i]); palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { - palDestroyImageView(imageViews[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); + palDestroyImageView(imageViews[i]); } palDestroyCommandPool(cmdPool); @@ -770,7 +772,10 @@ bool geometryTest() palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); + palFree(nullptr, imageViews); + palFree(nullptr, renderFinishedSemaphores); + palFree(nullptr, inFlightImages); palDestroyWindow(window); palShutdownVideo(); diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index abef1fdf..a0aa9cc7 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -35,8 +35,8 @@ bool meshTest() PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; @@ -313,7 +313,8 @@ bool meshTest() Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); - if (!imageViews || !inFlightImages) { + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); + if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); return false; } @@ -349,6 +350,14 @@ bool meshTest() return false; } + // create render finished semaphores + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + inFlightImages[i] = nullptr; } @@ -368,13 +377,6 @@ bool meshTest() return false; } - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - result = palCreateFence(device, true, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -712,7 +714,7 @@ bool meshTest() submitInfo.cmdBuffer = cmdBuffers[currentFrame]; submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; - submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -724,7 +726,7 @@ bool meshTest() // present PalSwapchainPresentInfo presentInfo = {0}; presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; + presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -747,13 +749,13 @@ bool meshTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { palDestroySemaphore(imageAvailableSemaphores[i]); - palDestroySemaphore(renderFinishedSemaphores[i]); palDestroyFence(inFlightFences[i]); palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { - palDestroyImageView(imageViews[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); + palDestroyImageView(imageViews[i]); } palDestroyCommandPool(cmdPool); @@ -762,7 +764,10 @@ bool meshTest() palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); + palFree(nullptr, imageViews); + palFree(nullptr, renderFinishedSemaphores); + palFree(nullptr, inFlightImages); palDestroyWindow(window); palShutdownVideo(); diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 2a822a21..9f04bb7a 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -3,8 +3,6 @@ #include "tests.h" #define BUFFER_SIZE 400 -#define BUFFER_COUNT 3 -#define DESCRIPTOR_SET_COUNT 2 // layout must match shader typedef struct { @@ -34,14 +32,14 @@ bool multiDescriptorSetTest() PalCommandBuffer* cmdBuffer; PalShader* shader = nullptr; - PalBuffer* buffers[BUFFER_COUNT]; - PalBuffer* stagingBuffers[BUFFER_COUNT]; - PalMemory* bufferMemories[BUFFER_COUNT]; - PalMemory* stagingBufferMemories[BUFFER_COUNT]; + PalBuffer* buffers[3]; + PalBuffer* stagingBuffers[3]; + PalMemory* bufferMemories[3]; + PalMemory* stagingBufferMemories[3]; PalDescriptorPool* descriptorPool = nullptr; - PalDescriptorSetLayout* descriptorSetLayouts[DESCRIPTOR_SET_COUNT]; - PalDescriptorSet* descriptorSets[DESCRIPTOR_SET_COUNT]; + PalDescriptorSetLayout* descriptorSetLayouts[2]; + PalDescriptorSet* descriptorSets[2]; PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -257,7 +255,7 @@ bool multiDescriptorSetTest() PalBufferCreateInfo bufferCreateInfo = {0}; bufferCreateInfo.size = bufferBytes; - for (int i = 0; i < BUFFER_COUNT; i++) { + for (int i = 0; i < 3; i++) { bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE | PAL_BUFFER_USAGE_TRANSFER_SRC; result = palCreateBuffer(device, &bufferCreateInfo, &buffers[i]); @@ -389,7 +387,7 @@ bool multiDescriptorSetTest() } // allocate the sets from the descriptor pool - for (int i = 0; i < DESCRIPTOR_SET_COUNT; i++) { + for (int i = 0; i < 2; i++) { result = palAllocateDescriptorSet( device, descriptorPool, @@ -404,19 +402,19 @@ bool multiDescriptorSetTest() } // write the inital data to the descriptor set since its created empty - Uint32 bindingCounts[DESCRIPTOR_SET_COUNT] = { 2, 1 }; - Uint32 bufferOffsets[DESCRIPTOR_SET_COUNT] = { 0, 2 }; - PalDescriptorSetWriteInfo writeInfos[DESCRIPTOR_SET_COUNT]; - PalDescriptorBufferInfo descriptorBufferInfos[BUFFER_COUNT]; + Uint32 bindingCounts[2] = { 2, 1 }; + Uint32 bufferOffsets[2] = { 0, 2 }; + PalDescriptorSetWriteInfo writeInfos[2]; + PalDescriptorBufferInfo descriptorBufferInfos[3]; - for (int i = 0; i < BUFFER_COUNT; i++) { + for (int i = 0; i < 3; i++) { descriptorBufferInfos[i].buffer = buffers[i]; descriptorBufferInfos[i].offset = 0; descriptorBufferInfos[i].size = bufferBytes; descriptorBufferInfos[i].stride = 16; // sizeof(vec4) or float4. } - for (int i = 0; i < DESCRIPTOR_SET_COUNT; i++) { + for (int i = 0; i < 2; i++) { writeInfos[i].layoutBindingIndex = 0; // single descriptor binding writeInfos[i].bufferInfos = &descriptorBufferInfos[bufferOffsets[i]]; writeInfos[i].descriptorSet = descriptorSets[i]; @@ -429,7 +427,7 @@ bool multiDescriptorSetTest() writeInfos[i].tlasInfos = nullptr; } - result = palUpdateDescriptorSet(device, DESCRIPTOR_SET_COUNT, writeInfos); + result = palUpdateDescriptorSet(device, 2, writeInfos); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); @@ -446,7 +444,7 @@ bool multiDescriptorSetTest() // create pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; - pipelineLayoutCreateInfo.descriptorSetLayoutCount = DESCRIPTOR_SET_COUNT; + pipelineLayoutCreateInfo.descriptorSetLayoutCount = 2; pipelineLayoutCreateInfo.pushConstantRangeCount = 1; pipelineLayoutCreateInfo.descriptorSetLayouts = descriptorSetLayouts; pipelineLayoutCreateInfo.pushConstantRanges = &pushConstantRange; @@ -610,7 +608,7 @@ bool multiDescriptorSetTest() newUsageStateInfo.shaderStages = nullptr; newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; - for (int i = 0; i < BUFFER_COUNT; i++) { + for (int i = 0; i < 3; i++) { result = palCmdBufferBarrier( cmdBuffer, buffers[i], @@ -662,7 +660,7 @@ bool multiDescriptorSetTest() } const char* names[3] = { "compute_output1.ppm", "compute_output2.ppm", "compute_output3.ppm" }; - for (int i = 0; i < BUFFER_COUNT; i++) { + for (int i = 0; i < 3; i++) { // now our staging buffer has the contents of the GPU buffer // we map it and copy the contents to a ppm buffer and save it void* ptr = nullptr; @@ -700,11 +698,11 @@ bool multiDescriptorSetTest() palDestroyCommandPool(cmdPool); palDestroyDescriptorPool(descriptorPool); - for (int i = 0; i < DESCRIPTOR_SET_COUNT; i++) { + for (int i = 0; i < 2; i++) { palDestroyDescriptorSetLayout(descriptorSetLayouts[i]); } - for (int i = 0; i < BUFFER_COUNT; i++) { + for (int i = 0; i < 3; i++) { palDestroyBuffer(buffers[i]); palFreeMemory(device, bufferMemories[i]); diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 34414ee6..d39d555e 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -64,8 +64,8 @@ bool textureTest() PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; @@ -339,7 +339,8 @@ bool textureTest() Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); - if (!imageViews || !inFlightImages) { + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); + if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); return false; } @@ -375,6 +376,14 @@ bool textureTest() return false; } + // create render finished semaphores + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + inFlightImages[i] = nullptr; } @@ -394,13 +403,6 @@ bool textureTest() return false; } - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - result = palCreateFence(device, true, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -1318,7 +1320,7 @@ bool textureTest() submitInfo.cmdBuffer = cmdBuffers[currentFrame]; submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; - submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -1330,7 +1332,7 @@ bool textureTest() // present PalSwapchainPresentInfo presentInfo = {0}; presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; + presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -1353,13 +1355,13 @@ bool textureTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { palDestroySemaphore(imageAvailableSemaphores[i]); - palDestroySemaphore(renderFinishedSemaphores[i]); palDestroyFence(inFlightFences[i]); palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { - palDestroyImageView(imageViews[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); + palDestroyImageView(imageViews[i]); } palDestroyDescriptorPool(descriptorPool); @@ -1379,7 +1381,10 @@ bool textureTest() palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); + palFree(nullptr, imageViews); + palFree(nullptr, renderFinishedSemaphores); + palFree(nullptr, inFlightImages); palDestroyWindow(window); palShutdownVideo(); diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index ce22097c..7deda986 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -34,8 +34,8 @@ bool triangleTest() PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; - PalSemaphore* renderFinishedSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; @@ -305,7 +305,8 @@ bool triangleTest() Uint32 imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); - if (!imageViews || !inFlightImages) { + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); + if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); return false; } @@ -341,6 +342,14 @@ bool triangleTest() return false; } + // create render finished semaphores + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + inFlightImages[i] = nullptr; } @@ -360,13 +369,6 @@ bool triangleTest() return false; } - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); - return false; - } - result = palCreateFence(device, true, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -912,7 +914,7 @@ bool triangleTest() submitInfo.cmdBuffer = cmdBuffers[currentFrame]; submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; - submitInfo.signalSemaphore = renderFinishedSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -924,7 +926,7 @@ bool triangleTest() // present PalSwapchainPresentInfo presentInfo = {0}; presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[currentFrame]; + presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; result = palPresentSwapchain(swapchain, &presentInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -947,13 +949,13 @@ bool triangleTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { palDestroySemaphore(imageAvailableSemaphores[i]); - palDestroySemaphore(renderFinishedSemaphores[i]); palDestroyFence(inFlightFences[i]); palFreeCommandBuffer(cmdBuffers[i]); } for (int i = 0; i < imageCount; i++) { - palDestroyImageView(imageViews[i]); + palDestroySemaphore(renderFinishedSemaphores[i]); + palDestroyImageView(imageViews[i]); } palDestroyBuffer(vertexBuffer); @@ -965,7 +967,10 @@ bool triangleTest() palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); + palFree(nullptr, imageViews); + palFree(nullptr, renderFinishedSemaphores); + palFree(nullptr, inFlightImages); palDestroyWindow(window); palShutdownVideo(); diff --git a/tests/tests_main.c b/tests/tests_main.c index 007e988a..ba65e313 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,17 +57,17 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest, "Graphics Test"); - //registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); - // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); + registerTest(graphicsTest, "Graphics Test"); + registerTest(computeTest, "Compute Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); + registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - // registerTest(clearColorTest, "Clear Color Test"); - // registerTest(triangleTest, "Triangle Test"); - // registerTest(meshTest, "Mesh Test"); - // registerTest(textureTest, "Texture Test"); + registerTest(clearColorTest, "Clear Color Test"); + registerTest(triangleTest, "Triangle Test"); + registerTest(meshTest, "Mesh Test"); + registerTest(textureTest, "Texture Test"); registerTest(geometryTest, "Geometry Test"); #endif // From 5bbdf18f55302fa16c381d0b2e663f1d3bd28c99 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 17 May 2026 17:03:16 +0000 Subject: [PATCH 219/372] add indirect draw test --- include/pal/pal_graphics.h | 12 +- src/graphics/pal_d3d12.c | 1 + src/graphics/pal_vulkan.c | 45 +- tests/graphics/indirect_draw_test.c | 1210 +++++++++++++++++++++++++++ tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 19 +- 7 files changed, 1279 insertions(+), 12 deletions(-) create mode 100644 tests/graphics/indirect_draw_test.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index a1c31d1e..1af30a9f 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1339,7 +1339,8 @@ typedef enum { PAL_BUFFER_USAGE_TRANSFER_SRC = PAL_BIT(4), PAL_BUFFER_USAGE_TRANSFER_DST = PAL_BIT(5), PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE = PAL_BIT(6), - PAL_BUFFER_USAGE_DEVICE_ADDRESS = PAL_BIT(7) + PAL_BUFFER_USAGE_DEVICE_ADDRESS = PAL_BIT(7), + PAL_BUFFER_USAGE_INDIRECT = PAL_BIT(8) } PalBufferUsages; enum PalDebugMessageSeverity { @@ -1377,6 +1378,7 @@ typedef enum { PAL_USAGE_STATE_TRANSFER_WRITE, PAL_USAGE_STATE_VERTEX_READ, PAL_USAGE_STATE_INDEX_READ, + PAL_USAGE_STATE_INDIRECT_READ, PAL_USAGE_STATE_UNIFORM_READ, PAL_USAGE_STATE_SHADER_READ, PAL_USAGE_STATE_SHADER_WRITE, @@ -5696,6 +5698,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. + * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 * @ingroup pal_graphics @@ -5727,6 +5730,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. + * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 * @ingroup pal_graphics @@ -6073,6 +6077,7 @@ PAL_API PalResult PAL_CALL palCmdDraw( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. + * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 * @ingroup pal_graphics @@ -6103,6 +6108,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirect( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. + * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 * @ingroup pal_graphics @@ -6164,6 +6170,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexed( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. + * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 * @ingroup pal_graphics @@ -6194,6 +6201,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. + * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 * @ingroup pal_graphics @@ -6429,6 +6437,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. + * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 * @ingroup pal_graphics @@ -6493,6 +6502,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * internally copies the data into a GPU buffer for execution. * * @note A pipeline must be bound before this call. + * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 * @ingroup pal_graphics diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 4225da43..e89fa632 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -27,6 +27,7 @@ freely, subject to the following restrictions: #include "pal/pal_graphics.h" +// TODO: Check flag for indirect buffers #if PAL_HAS_D3D12 #ifdef __WIN32 diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index e25e340d..0db072a4 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1502,6 +1502,10 @@ static VkBufferUsageFlags bufferUsageToVk(PalBufferUsages usages) flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; } + if (usages & PAL_BUFFER_USAGE_INDIRECT) { + flags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; + } + return flags; } @@ -1946,6 +1950,13 @@ static Barrier barrierToVk( return barrier; } + case PAL_USAGE_STATE_INDIRECT_READ: { + barrier.stages = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR; + barrier.access = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + case PAL_USAGE_STATE_UNIFORM_READ: { for (int i = 0; i < stageCount; i++) { barrier.stages |= pipelineStageToVk(shaderStages[i]); @@ -6730,6 +6741,10 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + Uint32 stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); device->cmdDrawMeshTaskIndirect( vkCmdBuffer->handle, @@ -6756,6 +6771,10 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + Uint32 stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); device->cmdDrawMeshTaskIndirectCount( vkCmdBuffer->handle, @@ -7350,6 +7369,10 @@ PalResult PAL_CALL cmdDrawIndirectVk( Buffer* vkBuffer = (Buffer*)buffer; Uint32 stride = sizeof(VkDrawIndirectCommand); + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + s_Vk.cmdDrawIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); return PAL_RESULT_SUCCESS; } @@ -7369,6 +7392,10 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + Uint32 stride = sizeof(VkDrawIndirectCommand); device->cmdDrawIndirectCount( vkCmdBuffer->handle, @@ -7411,6 +7438,10 @@ PalResult PAL_CALL cmdDrawIndexedIndirectVk( Buffer* vkBuffer = (Buffer*)buffer; Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + s_Vk.cmdDrawIndexedIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); return PAL_RESULT_SUCCESS; } @@ -7430,6 +7461,10 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); device->cmdDrawIndexedIndirectCount( vkCmdBuffer->handle, @@ -7615,11 +7650,15 @@ PalResult PAL_CALL cmdDispatchIndirectVk( PalBuffer* buffer) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; + Buffer* vkBuffer = (Buffer*)buffer; if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Buffer* vkBuffer = (Buffer*)buffer; + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + s_Vk.cmdDispatchIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0); return PAL_RESULT_SUCCESS; } @@ -7675,6 +7714,10 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; vkSbt->raygen.region.deviceAddress = address; diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c new file mode 100644 index 00000000..cc036efd --- /dev/null +++ b/tests/graphics/indirect_draw_test.c @@ -0,0 +1,1210 @@ + +#include "pal/pal_graphics.h" +#include "pal/pal_video.h" +#include "pal/pal_system.h" +#include "tests.h" + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +#define MAX_FRAMES_IN_FLIGHT 2 + +static inline Uint32 align( + Uint32 value, + Uint32 alignment) +{ + return (value + alignment - 1) & ~(alignment - 1); +} + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) +{ + palLog(nullptr, msg); +} + +bool indirectDrawTest() +{ + PalResult result; + PalWindow* window = nullptr; + PalEventDriver* eventDriver = nullptr; + PalGraphicsWindow gfxWindow; + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalSurface* surface = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + + PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images + PalFence** inFlightImages; // count of swapchain images + + PalPipelineLayout* pipelineLayout = nullptr; + PalPipeline* pipeline = nullptr; + PalShader* shaders[2]; + + PalBuffer* vertexBuffer = nullptr; + PalBuffer* indexBuffer = nullptr; + PalBuffer* indirectBuffer = nullptr; + PalBuffer* stagingBuffer = nullptr; + + PalMemory* vertexBufferMemory = nullptr; + PalMemory* indexBufferMemory = nullptr; + PalMemory* indirectBufferMemory = nullptr; + PalMemory* stagingBufferMemory = nullptr; + + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create event driver: %s", error); + return false; + } + + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + + result = palInitVideo(nullptr, eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize video: %s", error); + return false; + } + + PalWindowCreateInfo windowCreateInfo = {0}; + windowCreateInfo.height = WINDOW_HEIGHT; + windowCreateInfo.width = WINDOW_WIDTH; + windowCreateInfo.show = true; + windowCreateInfo.title = "Indirect Draw Window"; + + PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); + if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&windowCreateInfo, &window); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create window: %s", error); + return false; + } + + PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); + gfxWindow.display = winHandle.nativeDisplay; + gfxWindow.window = winHandle.nativeWindow; + + // using pal_system.h will be easy to know the underlying windowing API + // or use typedefs. We will use the pal_system module. This is needed + // for systems which multiple windowing APIs (linux). + PalPlatformInfo platformInfo = {0}; + result = palGetPlatformInfo(&platformInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get platform information: %s", error); + return false; + } + + if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + + } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + + } else { + // automatically this is xcb + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } + + PalGraphicsDebugger debugger = {0}; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; + + result = palInitGraphics(nullptr, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (adapterCount == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", adapterCount); + + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&adapterCount, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + PalAdapterCapabilities caps = {0}; + PalAdapterInfo adapterInfo = {0}; + PalAdapterFeatures adapterFeatures; + bool hasGraphicsQueue = false; + bool hasIndirect = false; + for (Int32 i = 0; i < adapterCount; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (caps.maxGraphicsQueues == 0) { + hasGraphicsQueue = false; + continue; + + } else { + hasGraphicsQueue = true; + } + + if (hasGraphicsQueue) { + adapterFeatures = palGetAdapterFeatures(adapter); + if (adapterFeatures & PAL_ADAPTER_FEATURE_INDIRECT_DRAW) { + hasIndirect = true; + } else { + hasIndirect = false; + } + } + + if (hasIndirect) { + // We want an adapter that supports spirv 1.0 or dxil 6.0 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { + break; + } + } + } + adapter = nullptr; + } + + palFree(nullptr, adapters); + if (!adapter) { + if (!hasGraphicsQueue) { + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); + + } else if (!hasIndirect) { + palLog(nullptr, "Failed to find an adapter that supports indirect draw"); + + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } + return false; + } + + // create a device + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + features |= PAL_ADAPTER_FEATURE_FENCE_RESET; + } + + result = palCreateDevice(adapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create surface + result = palCreateSurface(device, &gfxWindow, &surface); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create surface: %s", error); + return false; + } + + // create a graphics command queue and check if its supports presenting to the surface + bool foundQueue = false; + for (int i = 0; i < caps.maxGraphicsQueues; i++) { + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palDestroyQueue(queue); + queue = nullptr; + } else { + // found a queue + foundQueue = true; + break; + } + } + + if (!foundQueue) { + palLog(nullptr, "Failed to find a queue that can present to the surface"); + return false; + } + + // create a swapchain with the graphics queue + PalSurfaceCapabilities surfaceCaps = {0}; + result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get surface capabilities: %s", error); + return false; + } + + PalSwapchainCreateInfo swapchainCreateInfo = {0}; + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; + swapchainCreateInfo.height = WINDOW_HEIGHT; + swapchainCreateInfo.width = WINDOW_WIDTH; + swapchainCreateInfo.imageArrayLayerCount = 1; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR; + + // rare but possible on andriod + if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { + swapchainCreateInfo.width = surfaceCaps.maxImageWidth / 2; + } + + if (WINDOW_HEIGHT > surfaceCaps.maxImageHeight) { + swapchainCreateInfo.height = surfaceCaps.maxImageHeight / 2; + } + + // check if the minimal image count is not good for you + // and increase it but not pass the max count + swapchainCreateInfo.imageCount = surfaceCaps.minImageCount; + if (swapchainCreateInfo.imageCount == 1) { + swapchainCreateInfo.imageCount++; + if (surfaceCaps.maxImageCount < 2) { + palLog(nullptr, "Surface does not support double buffers"); + return false; + } + } + + result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create swapchain: %s", error); + return false; + } + + // get all swapchain images and create image views for them + Uint32 imageCount = swapchainCreateInfo.imageCount; + imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); + inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); + if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + PalImageInfo imageInfo; + result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } + + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.subresourceRange.layerArrayCount = 1; + imageViewCreateInfo.subresourceRange.mipLevelCount = 1; + imageViewCreateInfo.subresourceRange.startArrayLayer = 0; + imageViewCreateInfo.subresourceRange.startMipLevel = 0; + imageViewCreateInfo.format = imageInfo.format; + + for (int i = 0; i < imageCount; i++) { + // get swapchain image + // this is fast since the images are cache by PAL + PalImage* image = palGetSwapchainImage(swapchain, i); + if (!image) { + palLog(nullptr, "Failed to get swapchain image"); + } + + result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + + // create render finished semaphores + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + inFlightImages[i] = nullptr; + } + + result = palCreateCommandPool(device, queue, &cmdPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + // create synchronization objects and command buffers + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateFence(device, true, &inFlightFences[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + result = palAllocateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffers[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate command buffer: %s", error); + return false; + } + } + + // create vertex, index, indirect and staging buffer + // clang-format off + float vertices[] = { + -0.5, 0.5, 1.0f, 1.0f, 0.0f, + 0.5, 0.5, 1.0f, 1.0f, 0.0f, + 0.5,-0.5, 1.0f, 1.0f, 0.0f, + -0.5,-0.5, 1.0f, 1.0f, 0.0f + }; + // clang-format on + + Uint32 indices[6] = { 0, 1, 2, 2, 3, 0 }; + + // vertex buffer + PalBufferCreateInfo bufferCreateInfo = {0}; + bufferCreateInfo.size = sizeof(vertices); + bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create buffer: %s", error); + return false; + } + + // index buffer + bufferCreateInfo.size = sizeof(indices); + bufferCreateInfo.usages = PAL_BUFFER_USAGE_INDEX; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + result = palCreateBuffer(device, &bufferCreateInfo, &indexBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create buffer: %s", error); + return false; + } + + // indirect buffer + bufferCreateInfo.size = sizeof(PalDrawIndexedIndirectData); + bufferCreateInfo.usages = PAL_BUFFER_USAGE_INDIRECT; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + result = palCreateBuffer(device, &bufferCreateInfo, &indirectBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create buffer: %s", error); + return false; + } + + // staging buffer for vertex, index and indirect buffer + Uint32 offset = 0; + Uint32 indirectOffset = offset; + offset += sizeof(PalDrawIndexedIndirectData); + offset = align(offset, 16); + + Uint32 indexOffset = offset; + offset += sizeof(indices); + offset = align(offset, 16); + + Uint32 vertexOffset = offset; + offset += sizeof(vertices); + offset = align(offset, 16); + + Uint32 stagingBufferSize = offset; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send + bufferCreateInfo.size = offset; + result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create buffer: %s", error); + return false; + } + + // get buffer memory requirement and allocate memory + PalMemoryRequirements vertexBufferMemReq = {0}; + PalMemoryRequirements indexBufferMemReq = {0}; + PalMemoryRequirements indirectBufferMemReq = {0}; + PalMemoryRequirements stagingBufferMemReq = {0}; + + // get vertex buffer memory requirement + result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + // get index buffer memory requirement + result = palGetBufferMemoryRequirements(indexBuffer, &indexBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + // get indirect buffer memory requirement + result = palGetBufferMemoryRequirements(indirectBuffer, &indirectBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + // get staging buffer memory requirement + result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + // allocate memory for vertex buffer + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + vertexBufferMemReq.memoryMask, + vertexBufferMemReq.size, + &vertexBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + // allocate memory for index buffer + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + indexBufferMemReq.memoryMask, + indexBufferMemReq.size, + &indexBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + // allocate memory for indirect buffer + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + indirectBufferMemReq.memoryMask, + indirectBufferMemReq.size, + &indirectBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + stagingBufferMemReq.memoryMask, + stagingBufferMemReq.size, + &stagingBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + // bind memory for vertex buffer + result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + // bind memory for index buffer + result = palBindBufferMemory(indexBuffer, indexBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + // bind memory for indirect buffer + result = palBindBufferMemory(indirectBuffer, indirectBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + // bind memory for staging buffer + result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + // map the staging buffer and upload the data + void* ptr = nullptr; + result = palMapBufferMemory(stagingBuffer, 0, stagingBufferSize, &ptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map buffer memory: %s", error); + return false; + } + + // copy indirect data + PalDrawIndexedIndirectData indirectData = {0}; + indirectData.firstIndex = 0; + indirectData.firstInstance = 0; + indirectData.indexCount = 6; + indirectData.instanceCount = 1; + indirectData.vertexOffset = 0; + + Uint8* dst = (Uint8*)ptr; + memcpy(dst + indirectOffset, &indirectData, sizeof(PalDrawIndexedIndirectData)); + + // copy vertices + memcpy(dst + vertexOffset, vertices, sizeof(vertices)); + + // copy indices + memcpy(dst + indexOffset, indices, sizeof(indices)); + + palUnmapBufferMemory(stagingBuffer); + + PalFence* fence = nullptr; + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + // use the first command buffer to upload the copy + // and reset it when done + // set a fence and check at the last line before the main loop + // to see if we have to wait for the copy to be executed + result = palCmdBegin(cmdBuffers[0], nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + PalUsageStateInfo oldUsageStateInfo = {0}; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.shaderStageCount = 0; + newUsageStateInfo.shaderStages = nullptr; + newUsageStateInfo.usageState = PAL_USAGE_STATE_INDIRECT_READ; + + // copy to indirect buffer + PalBufferCopyInfo indirectCopyInfo = {0}; + indirectCopyInfo.dstOffset = 0; + indirectCopyInfo.size = sizeof(PalDrawIndexedIndirectData); + indirectCopyInfo.srcOffset = indirectOffset; + + result = palCmdCopyBuffer(cmdBuffers[0], indirectBuffer, stagingBuffer, &indirectCopyInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer: %s", error); + return false; + } + + result = palCmdBufferBarrier( + cmdBuffers[0], + indirectBuffer, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // copy to vertex buffer + PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; + + newUsageStateInfo.shaderStageCount = 1; + newUsageStateInfo.shaderStages = vertexShaderStage; + newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; + + PalBufferCopyInfo vertexCopyInfo = {0}; + vertexCopyInfo.dstOffset = 0; + vertexCopyInfo.size = sizeof(vertices); + vertexCopyInfo.srcOffset = vertexOffset; + + result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, &vertexCopyInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer: %s", error); + return false; + } + + result = palCmdBufferBarrier( + cmdBuffers[0], + vertexBuffer, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // copy to index buffer + newUsageStateInfo.shaderStageCount = 0; + newUsageStateInfo.shaderStages = nullptr; + newUsageStateInfo.usageState = PAL_USAGE_STATE_INDEX_READ; + + PalBufferCopyInfo indexCopyInfo = {0}; + indexCopyInfo.dstOffset = 0; + indexCopyInfo.size = sizeof(indices); + indexCopyInfo.srcOffset = indexOffset; + + result = palCmdCopyBuffer(cmdBuffers[0], indexBuffer, stagingBuffer, &indexCopyInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer: %s", error); + return false; + } + + result = palCmdBufferBarrier( + cmdBuffers[0], + indexBuffer, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + result = palCmdEnd(cmdBuffers[0]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffers[0]; + submitInfo.fence = fence; + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // create shaders + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + const char* sources[2]; + PalShaderStage tmpShaderStages[2]; + + PalShaderCreateInfo shaderCreateInfo = {0}; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + sources[0] = "graphics/shaders/bin/spirv/triangle_vert.spv"; + sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + sources[0] = "graphics/shaders/bin/dxil/triangle_vert.dxil"; + sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; + } + + tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; + tmpShaderStages[1] = PAL_SHADER_STAGE_FRAGMENT; + + for (int i = 0; i < 2; i++) { + // read file + if (!readFile(sources[i], nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(sources[i], bytecode, &bytecodeSize); + + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.entryName = "main"; + shaderCreateInfo.stage = tmpShaderStages[i]; + + result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create shader: %s", error); + return false; + } + + palFree(nullptr, bytecode); + } + + // create pipeline layout + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline layout: %s", error); + return false; + } + + PalRenderingLayoutInfo renderingLayoutInfo = {0}; + renderingLayoutInfo.colorAttachentCount = 1; + renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; + renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.viewCount = 1; + + // create graphics pipeline + PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; + PalVertexLayout vertexLayout = {0}; + PalVertexAttribute vertexAttributes[2]; + + // position + vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; + vertexAttributes[0].semanticName = nullptr; // use default + vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; + + // color coordinates + vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_COLOR; + vertexAttributes[1].semanticName = nullptr; // use default + vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT3; + + vertexLayout.attributeCount = 2; + vertexLayout.attributes = vertexAttributes; + vertexLayout.binding = 0; // first vertex buffer binding slot + vertexLayout.type = PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX; + + pipelineCreateInfo.vertexLayoutCount = 1; + pipelineCreateInfo.vertexLayouts = &vertexLayout; + + // color blend attachment + PalColorBlendAttachment blendAttachment = {0}; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; + + pipelineCreateInfo.colorBlendAttachments = &blendAttachment; + pipelineCreateInfo.colorBlendAttachmentCount = 1; + + // shaders + pipelineCreateInfo.shaderCount = 2; + pipelineCreateInfo.shaders = shaders; + + pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + pipelineCreateInfo.pipelineLayout = pipelineLayout; + pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; + + result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create graphics pipeline: %s", error); + return false; + } + + for (int i = 0; i < 2; i++) { + palDestroyShader(shaders[i]); + } + + // wait for the vertices copy to be done + result = palWaitFence(fence, PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } + + // the vertices have been copied + palDestroyFence(fence); + palDestroyBuffer(stagingBuffer); + palFreeMemory(device, stagingBufferMemory); + + // main loop + Uint32 currentFrame = 0; + bool running = true; + + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + + PalRect2D scissor = {0}; + scissor.height = WINDOW_HEIGHT; + scissor.width = WINDOW_WIDTH; + + while (running) { + // update the video system to push video events + palUpdateVideo(); + + PalEvent event; + while (palPollEvent(eventDriver, &event)) { + switch (event.type) { + case PAL_EVENT_WINDOW_CLOSE: { + running = false; + break; + } + + case PAL_EVENT_KEYDOWN: { + PalKeycode keycode = 0; + palUnpackUint32(event.data, &keycode, nullptr); + if (keycode == PAL_KEYCODE_ESCAPE) { + running = false; + } + break; + } + } + } + + result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; + nextImageInfo.timeout = PAL_INFINITE; + + Uint32 imageIndex = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + if (inFlightImages[imageIndex] != nullptr) { + result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + inFlightImages[imageIndex] = inFlightFences[currentFrame]; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + result = palResetFence(inFlightFences[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + } else { + // recreate since we dont support fence resetting + palDestroyFence(inFlightFences[currentFrame]); + + result = palCreateFence(device, false, &inFlightFences[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + // reset the command buffer + result = palResetCommandBuffer(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to reset command buffer: %s", error); + return false; + } + + result = palCmdBegin(cmdBuffers[currentFrame], nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + // change the state of the image view to make it renderable + PalUsageStateInfo oldUsageStateInfo = {0}; + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + + PalImageSubresourceRange imageRange = {0}; + imageRange.layerArrayCount = 1; + imageRange.mipLevelCount = 1; + imageRange.startArrayLayer = 0; + imageRange.startMipLevel = 0; + + PalImage* image = palGetSwapchainImage(swapchain, imageIndex); + result = palCmdImageBarrier( + cmdBuffers[currentFrame], + image, + &imageRange, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + PalClearValue clearValue; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; + + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.clearValue = clearValue; + colorAttachment.imageView = imageViews[imageIndex]; + + PalRenderingInfo renderingInfo = {0}; + renderingInfo.viewCount = 1; + renderingInfo.colorAttachentCount = 1; + renderingInfo.colorAttachments = &colorAttachment; + + result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin rendering: %s", error); + return false; + } + + // bind pipeline + result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + // set viewport and scissors + result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set viewport: %s", error); + return false; + } + + result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set scissors: %s", error); + return false; + } + + // bind vertex buffer + Uint64 offset[] = {0}; + result = palCmdBindVertexBuffers( + cmdBuffers[currentFrame], + 0, + 1, + &vertexBuffer, + offset); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind vertex buffer: %s", error); + return false; + } + + // bind index buffer + result = palCmdBindIndexBuffer( + cmdBuffers[currentFrame], + indexBuffer, + 0, + PAL_INDEX_TYPE_UINT32); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind index buffer: %s", error); + return false; + } + + result = palCmdDrawIndexedIndirect(cmdBuffers[currentFrame], indirectBuffer, 1); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to issue draw indirect command: %s", error); + return false; + } + + result = palCmdEndRendering(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end rendering: %s", error); + return false; + } + + // change the state of the image view to make it presentable + oldUsageStateInfo = newUsageStateInfo; + newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + result = palCmdImageBarrier( + cmdBuffers[currentFrame], + image, + &imageRange, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + result = palCmdEnd(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // submit command buffer + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffers[currentFrame]; + submitInfo.fence = inFlightFences[currentFrame]; + submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; + + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // present + PalSwapchainPresentInfo presentInfo = {0}; + presentInfo.imageIndex = imageIndex; + presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; + result = palPresentSwapchain(swapchain, &presentInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to present swapchain: %s", error); + return false; + } + + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + } + + result = palWaitQueue(queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for queue: %s", error); + return false; + } + + palDestroyPipeline(pipeline); + palDestroyPipelineLayout(pipelineLayout); + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + palDestroySemaphore(imageAvailableSemaphores[i]); + palDestroyFence(inFlightFences[i]); + palFreeCommandBuffer(cmdBuffers[i]); + } + + for (int i = 0; i < imageCount; i++) { + palDestroySemaphore(renderFinishedSemaphores[i]); + palDestroyImageView(imageViews[i]); + } + + palDestroyBuffer(indirectBuffer); + palDestroyBuffer(vertexBuffer); + palDestroyBuffer(indexBuffer); + + palFreeMemory(device, indirectBufferMemory); + palFreeMemory(device, vertexBufferMemory); + palFreeMemory(device, indexBufferMemory); + + palDestroyCommandPool(cmdPool); + palDestroySwapchain(swapchain); + palDestroySurface(surface); + palDestroyQueue(queue); + palDestroyDevice(device); + palShutdownGraphics(); + + palFree(nullptr, imageViews); + palFree(nullptr, renderFinishedSemaphores); + palFree(nullptr, inFlightImages); + + palDestroyWindow(window); + palShutdownVideo(); + palDestroyEventDriver(eventDriver); + return true; +} diff --git a/tests/tests.h b/tests/tests.h index 73b774d2..77b283c5 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -90,5 +90,6 @@ bool triangleTest(); bool meshTest(); bool textureTest(); bool geometryTest(); +bool indirectDrawTest(); #endif // _TESTS_H diff --git a/tests/tests.lua b/tests/tests.lua index 1637e0be..742dc776 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -82,7 +82,8 @@ project "tests" "graphics/triangle_test.c", "graphics/mesh_test.c", "graphics/texture_test.c", - "graphics/geometry_test.c" + "graphics/geometry_test.c", + "graphics/indirect_draw_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index ba65e313..d9757643 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,18 +57,19 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest, "Graphics Test"); - registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); - registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); + // registerTest(graphicsTest, "Graphics Test"); + // registerTest(computeTest, "Compute Test"); + // registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO - registerTest(clearColorTest, "Clear Color Test"); - registerTest(triangleTest, "Triangle Test"); - registerTest(meshTest, "Mesh Test"); - registerTest(textureTest, "Texture Test"); - registerTest(geometryTest, "Geometry Test"); + // registerTest(clearColorTest, "Clear Color Test"); + // registerTest(triangleTest, "Triangle Test"); + // registerTest(meshTest, "Mesh Test"); + // registerTest(textureTest, "Texture Test"); + // registerTest(geometryTest, "Geometry Test"); + registerTest(indirectDrawTest, "Indirect Draw Test"); #endif // runTests(); From c0b8aa592d77dc4cbcd69e6de9d286e15d720fae Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 17 May 2026 20:19:42 +0000 Subject: [PATCH 220/372] add more adapter capabilities --- include/pal/pal_graphics.h | 21 +- src/graphics/pal_d3d12.c | 2 + src/graphics/pal_vulkan.c | 119 +- tests/graphics/descriptor_indexing_test.c | 1418 +++++++++++++++++ tests/graphics/graphics_test.c | 84 +- tests/graphics/indirect_draw_test.c | 1 + .../shaders/src/glsl/descriptor_indexing.glsl | 16 + tests/tests.h | 1 + tests/tests.lua | 3 +- tests/tests_main.c | 5 +- 10 files changed, 1618 insertions(+), 52 deletions(-) create mode 100644 tests/graphics/descriptor_indexing_test.c create mode 100644 tests/graphics/shaders/src/glsl/descriptor_indexing.glsl diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 1af30a9f..f321c70b 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1451,6 +1451,10 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + bool sampledImageDynamicArrayIndexing; + bool storageImageDynamicArrayIndexing; + bool storageBufferDynamicArrayIndexing; + bool uniformBufferDynamicArrayIndexing; Uint32 maxComputeQueues; /**< Number of compute queues that can be created.*/ Uint32 maxGraphicsQueues; /**< Number of graphics queues that can be created.*/ Uint32 maxCopyQueues; /**< Number of copy queues that can be created.*/ @@ -1594,16 +1598,21 @@ typedef struct { /** * @struct PalDescriptorIndexingCapabilities * @brief Descriptor indexing capabilities of an adapter (GPU). + * + * PAL does not support partially bound descriptors or variable descriptor count. * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - bool bindlessSampledImages; /**< If true, bindless sampled images are supported.*/ - bool bindlessStorageImages; /**< If true, bindless storage images are supported.*/ - bool bindlessSamplers; /**< If true, bindless samplers are supported.*/ - bool bindlessStorageBuffers; /**< If true, bindless storage buffers are supported.*/ - bool bindlessUniformBuffers; /**< If true, bindless uniform buffers are supported.*/ + bool sampledImageNonUniformIndexing; + bool sampledImageUpdateAfterBind; + bool storageImageNonUniformIndexing; + bool storageImageUpdateAfterBind; + bool storageBufferNonUniformIndexing; + bool storageBufferUpdateAfterBind; + bool uniformBufferNonUniformIndexing; + bool uniformBufferUpdateAfterBind; Uint32 maxPerStageBindlessDescriptorSampledImages; Uint32 maxDescriptorSetBindlessSampledImages; Uint32 maxPerStageBindlessDescriptorStorageImages; @@ -4472,6 +4481,8 @@ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `caps` is per thread. + * + * @note PAL does not support partially bound descriptors or variable descriptor counts. * * @since 1.4 * @ingroup pal_graphics diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index e89fa632..16da7b2c 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -28,6 +28,8 @@ freely, subject to the following restrictions: #include "pal/pal_graphics.h" // TODO: Check flag for indirect buffers +// TODO: Add PAL_BUFFER_USAGE_INDIRECT bit +// TODO: add descriptor indexing shader #if PAL_HAS_D3D12 #ifdef __WIN32 diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 0db072a4..0306be7f 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3472,6 +3472,9 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( s_Vk.getPhysicalDeviceProperties(phyDevice, &props); VkPhysicalDeviceLimits* limits = &props.limits; + VkPhysicalDeviceFeatures features = {0}; + s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); + caps->maxColorAttachments = limits->maxColorAttachments; caps->maxImageWidth = limits->maxImageDimension2D; caps->maxImageHeight = limits->maxImageDimension2D; @@ -3549,6 +3552,11 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( caps->maxComputeWorkGroupSize[1] = limits->maxComputeWorkGroupSize[1]; caps->maxComputeWorkGroupSize[2] = limits->maxComputeWorkGroupSize[2]; + caps->sampledImageDynamicArrayIndexing = features.shaderSampledImageArrayDynamicIndexing; + caps->storageImageDynamicArrayIndexing = features.shaderStorageImageArrayDynamicIndexing; + caps->storageBufferDynamicArrayIndexing = features.shaderStorageBufferArrayDynamicIndexing; + caps->uniformBufferDynamicArrayIndexing = features.shaderUniformBufferArrayDynamicIndexing; + palFree(s_Vk.allocator, queueProps); return PAL_RESULT_SUCCESS; } @@ -3723,11 +3731,10 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) features.pNext = &desc; s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (desc.runtimeDescriptorArray && - desc.descriptorBindingPartiallyBound && - desc.descriptorBindingVariableDescriptorCount && - desc.shaderSampledImageArrayNonUniformIndexing && - desc.descriptorBindingSampledImageUpdateAfterBind) { + if (desc.shaderSampledImageArrayNonUniformIndexing || + desc.shaderStorageImageArrayNonUniformIndexing || + desc.shaderStorageBufferArrayNonUniformIndexing || + desc.shaderUniformBufferArrayNonUniformIndexing) { adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } } @@ -3977,6 +3984,9 @@ PalResult PAL_CALL createDeviceVk( } // build features and extensions capabilities + VkPhysicalDeviceFeatures phyDeviceFeatures = {0}; + s_Vk.getPhysicalDeviceFeatures(phyDevice, &phyDeviceFeatures); + VkPhysicalDeviceFeatures coreFeatures = {0}; if (features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { coreFeatures.samplerAnisotropy = true; @@ -4010,6 +4020,22 @@ PalResult PAL_CALL createDeviceVk( coreFeatures.shaderFloat64 = true; } + if (phyDeviceFeatures.shaderSampledImageArrayDynamicIndexing) { + coreFeatures.shaderSampledImageArrayDynamicIndexing = true; + } + + if (phyDeviceFeatures.shaderStorageImageArrayDynamicIndexing) { + coreFeatures.shaderStorageImageArrayDynamicIndexing = true; + } + + if (phyDeviceFeatures.shaderStorageBufferArrayDynamicIndexing) { + coreFeatures.shaderStorageBufferArrayDynamicIndexing = true; + } + + if (phyDeviceFeatures.shaderUniformBufferArrayDynamicIndexing) { + coreFeatures.shaderUniformBufferArrayDynamicIndexing = true; + } + // extensions and features2 void* next = nullptr; int extCount = 0; @@ -4168,14 +4194,9 @@ PalResult PAL_CALL createDeviceVk( extensions[extCount++] = "VK_EXT_descriptor_indexing"; } - descIndex.runtimeDescriptorArray = true; - descIndex.descriptorBindingPartiallyBound = true; - descIndex.shaderSampledImageArrayNonUniformIndexing = true; - descIndex.descriptorBindingSampledImageUpdateAfterBind = true; - descIndex.descriptorBindingVariableDescriptorCount = true; features12.descriptorIndexing = true; - // check support for bindless storage and uniform buffers + // check support for sub features VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; @@ -4184,15 +4205,39 @@ PalResult PAL_CALL createDeviceVk( features.pNext = &desc; s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (desc.shaderStorageBufferArrayNonUniformIndexing && - desc.descriptorBindingStorageBufferUpdateAfterBind) { + // check sub feature for sampled image + if (desc.shaderSampledImageArrayNonUniformIndexing) { + descIndex.shaderSampledImageArrayNonUniformIndexing = true; + } + + if (desc.descriptorBindingSampledImageUpdateAfterBind) { + descIndex.descriptorBindingSampledImageUpdateAfterBind = true; + } + + // check sub feature for storage image + if (desc.shaderStorageImageArrayNonUniformIndexing) { + descIndex.shaderStorageImageArrayNonUniformIndexing = true; + } + + if (desc.descriptorBindingStorageImageUpdateAfterBind) { + descIndex.descriptorBindingStorageImageUpdateAfterBind = true; + } + + // check sub feature for storage buffer + if (desc.shaderStorageBufferArrayNonUniformIndexing) { descIndex.shaderStorageBufferArrayNonUniformIndexing = true; + } + + if (desc.descriptorBindingStorageBufferUpdateAfterBind) { descIndex.descriptorBindingStorageBufferUpdateAfterBind = true; } - if (desc.shaderUniformBufferArrayNonUniformIndexing && - desc.descriptorBindingUniformBufferUpdateAfterBind) { + // check sub feature for uniform buffer + if (desc.shaderUniformBufferArrayNonUniformIndexing) { descIndex.shaderUniformBufferArrayNonUniformIndexing = true; + } + + if (desc.descriptorBindingUniformBufferUpdateAfterBind) { descIndex.descriptorBindingUniformBufferUpdateAfterBind = true; } @@ -4981,8 +5026,6 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - caps->bindlessSampledImages = true; - caps->bindlessSamplers = true; VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; @@ -5000,22 +5043,40 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( s_Vk.getPhysicalDeviceFeatures2(vkDevice->phyDevice, &features); s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - // check for bindless storage buffers - if (desc.shaderStorageBufferArrayNonUniformIndexing && - desc.descriptorBindingStorageBufferUpdateAfterBind) { - caps->bindlessStorageBuffers = true; + // check sub feature for sampled image + if (desc.shaderSampledImageArrayNonUniformIndexing) { + caps->sampledImageNonUniformIndexing = true; + } + + if (desc.descriptorBindingSampledImageUpdateAfterBind) { + caps->sampledImageUpdateAfterBind = true; + } + + // check sub feature for storage image + if (desc.shaderStorageImageArrayNonUniformIndexing) { + caps->storageImageNonUniformIndexing = true; + } + + if (desc.descriptorBindingStorageImageUpdateAfterBind) { + caps->storageImageUpdateAfterBind = true; + } + + // check sub feature for storage buffer + if (desc.shaderStorageBufferArrayNonUniformIndexing) { + caps->storageBufferNonUniformIndexing = true; + } + + if (desc.descriptorBindingStorageBufferUpdateAfterBind) { + caps->storageBufferUpdateAfterBind = true; } - // check for bindless uniform buffers - if (desc.shaderUniformBufferArrayNonUniformIndexing && - desc.descriptorBindingUniformBufferUpdateAfterBind) { - caps->bindlessUniformBuffers = true; + // check sub feature for uniform buffer + if (desc.shaderUniformBufferArrayNonUniformIndexing) { + caps->uniformBufferNonUniformIndexing = true; } - // check for bindless storage images - if (desc.shaderStorageImageArrayNonUniformIndexing && - desc.descriptorBindingStorageImageUpdateAfterBind) { - caps->bindlessStorageImages = true; + if (desc.descriptorBindingUniformBufferUpdateAfterBind) { + caps->uniformBufferUpdateAfterBind = true; } // clang-format off diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c new file mode 100644 index 00000000..4086b482 --- /dev/null +++ b/tests/graphics/descriptor_indexing_test.c @@ -0,0 +1,1418 @@ + +#include "pal/pal_graphics.h" +#include "pal/pal_video.h" +#include "pal/pal_system.h" +#include "tests.h" + +#define WINDOW_WIDTH 640 +#define WINDOW_HEIGHT 480 +#define MAX_FRAMES_IN_FLIGHT 2 +#define TEXTURE_WIDTH 128 +#define TEXTURE_HEIGHT 128 + +static void createFlatTexture( + Uint32* texture, + Uint32 width, + Uint32 height, + Uint8 r, + Uint8 g, + Uint8 b) +{ + Uint8* pixels = (Uint8*)texture; + for (Int32 y = 0; y < height; ++y) { + for (Int32 x = 0; x < width; ++x) { + Int32 i = (y * width + x) * 4; + pixels[i + 0] = r; + pixels[i + 1] = g; + pixels[i + 2] = b; + pixels[i + 3] = 255; + } + } +} + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) +{ + palLog(nullptr, msg); +} + +bool descriptorIndexingTest() +{ + PalResult result; + PalWindow* window = nullptr; + PalEventDriver* eventDriver = nullptr; + PalGraphicsWindow gfxWindow; + + PalAdapter* adapter = nullptr; + PalDevice* device = nullptr; + PalSurface* surface = nullptr; + PalQueue* queue = nullptr; + PalSwapchain* swapchain = nullptr; + PalCommandPool* cmdPool = nullptr; + PalImageView** imageViews = nullptr; + + PalCommandBuffer* cmdBuffers[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; + PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; + PalSemaphore** renderFinishedSemaphores; // count of swapchain images + PalFence** inFlightImages; // count of swapchain images + + PalPipelineLayout* pipelineLayout = nullptr; + PalPipeline* pipeline = nullptr; + PalShader* shaders[2]; + + PalBuffer* vertexBuffer = nullptr; + PalBuffer* stagingBuffer = nullptr; + PalMemory* vertexBufferMemory = nullptr; + PalMemory* stagingBufferMemory = nullptr; + + PalSampler* sampler = nullptr; + PalImage* textures[4]; + PalMemory* textureMemories[4]; + PalImageView* textureViews[4]; + + PalDescriptorSetLayout* descriptorSetLayout = nullptr; + PalDescriptorPool* descriptorPool = nullptr; + PalDescriptorSet* descriptorSet = nullptr; + + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create event driver: %s", error); + return false; + } + + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + + result = palInitVideo(nullptr, eventDriver); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize video: %s", error); + return false; + } + + PalWindowCreateInfo windowCreateInfo = {0}; + windowCreateInfo.height = WINDOW_HEIGHT; + windowCreateInfo.width = WINDOW_WIDTH; + windowCreateInfo.show = true; + windowCreateInfo.title = "Texture Window"; + + PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); + if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; + } + + result = palCreateWindow(&windowCreateInfo, &window); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create window: %s", error); + return false; + } + + PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); + gfxWindow.display = winHandle.nativeDisplay; + gfxWindow.window = winHandle.nativeWindow; + + // using pal_system.h will be easy to know the underlying windowing API + // or use typedefs. We will use the pal_system module. This is needed + // for systems which multiple windowing APIs (linux). + PalPlatformInfo platformInfo = {0}; + result = palGetPlatformInfo(&platformInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get platform information: %s", error); + return false; + } + + if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + + } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + + } else { + // automatically this is xcb + gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } + + PalGraphicsDebugger debugger = {0}; + debugger.callback = onGraphicsDebug; + debugger.userData = nullptr; + + result = palInitGraphics(nullptr, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to initialize graphics: %s", error); + return false; + } + + // enumerate all available adapters + Int32 adapterCount = 0; + result = palEnumerateAdapters(&adapterCount, nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + if (adapterCount == 0) { + palLog(nullptr, "No adapters found"); + return false; + } + palLog(nullptr, "Adapter count: %d", adapterCount); + + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + result = palEnumerateAdapters(&adapterCount, adapters); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get query adapters: %s", error); + return false; + } + + PalAdapterCapabilities caps = {0}; + PalAdapterInfo adapterInfo = {0}; + PalAdapterFeatures adapterFeatures; + bool hasGraphicsQueue = false; + bool hasDescriptorIndexing = false; + for (Int32 i = 0; i < adapterCount; i++) { + adapter = adapters[i]; + result = palGetAdapterCapabilities(adapter, &caps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter capabilities: %s", error); + palFree(nullptr, adapters); + return false; + } + + if (caps.maxGraphicsQueues == 0) { + hasGraphicsQueue = false; + continue; + + } else { + hasGraphicsQueue = true; + } + + if (hasGraphicsQueue) { + adapterFeatures = palGetAdapterFeatures(adapter); + if (adapterFeatures & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + hasDescriptorIndexing = true; + + } else { + hasDescriptorIndexing = false; + } + } + + if (hasDescriptorIndexing) { + // We want an adapter that supports spirv 1.4 or dxil 6.6 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 4)) { + break; + } + } + + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 6)) { + break; + } + } + } + adapter = nullptr; + } + + palFree(nullptr, adapters); + if (!adapter) { + if (!hasGraphicsQueue) { + palLog(nullptr, "Failed to find an adapter that supports graphics queue"); + + } else if (!hasDescriptorIndexing) { + palLog(nullptr, "Failed to find an adapter that supports descriptor indexing"); + + } else { + palLog(nullptr, "Failed to find an adapter that supports required shader target"); + } + return false; + } + + // create a device + PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + features |= PAL_ADAPTER_FEATURE_FENCE_RESET; + } + + result = palCreateDevice(adapter, features, &device); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create device: %s", error); + return false; + } + + // create surface + result = palCreateSurface(device, &gfxWindow, &surface); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create surface: %s", error); + return false; + } + + // create a graphics command queue and check if its supports presenting to the surface + bool foundQueue = false; + for (int i = 0; i < caps.maxGraphicsQueues; i++) { + result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create queue: %s", error); + return false; + } + + if (!palCanQueuePresent(queue, surface)) { + palDestroyQueue(queue); + queue = nullptr; + } else { + // found a queue + foundQueue = true; + break; + } + } + + if (!foundQueue) { + palLog(nullptr, "Failed to find a queue that can present to the surface"); + return false; + } + + // create a swapchain with the graphics queue + PalSurfaceCapabilities surfaceCaps = {0}; + result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get surface capabilities: %s", error); + return false; + } + + PalSwapchainCreateInfo swapchainCreateInfo = {0}; + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; + swapchainCreateInfo.height = WINDOW_HEIGHT; + swapchainCreateInfo.width = WINDOW_WIDTH; + swapchainCreateInfo.imageArrayLayerCount = 1; + swapchainCreateInfo.presentMode = PAL_PRESENT_MODE_FIFO; + swapchainCreateInfo.format = PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR; + + // rare but possible on andriod + if (WINDOW_WIDTH > surfaceCaps.maxImageWidth) { + swapchainCreateInfo.width = surfaceCaps.maxImageWidth / 2; + } + + if (WINDOW_HEIGHT > surfaceCaps.maxImageHeight) { + swapchainCreateInfo.height = surfaceCaps.maxImageHeight / 2; + } + + // check if the minimal image count is not good for you + // and increase it but not pass the max count + swapchainCreateInfo.imageCount = surfaceCaps.minImageCount; + if (swapchainCreateInfo.imageCount == 1) { + swapchainCreateInfo.imageCount++; + if (surfaceCaps.maxImageCount < 2) { + palLog(nullptr, "Surface does not support double buffers"); + return false; + } + } + + result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create swapchain: %s", error); + return false; + } + + // get all swapchain images and create image views for them + Uint32 imageCount = swapchainCreateInfo.imageCount; + imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); + inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); + renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); + if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + PalImageInfo imageInfo; + result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image info: %s", error); + return false; + } + + PalImageViewCreateInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.subresourceRange.layerArrayCount = 1; + imageViewCreateInfo.subresourceRange.mipLevelCount = 1; + imageViewCreateInfo.subresourceRange.startArrayLayer = 0; + imageViewCreateInfo.subresourceRange.startMipLevel = 0; + imageViewCreateInfo.format = imageInfo.format; + + for (int i = 0; i < imageCount; i++) { + // get swapchain image + // this is fast since the images are cache by PAL + PalImage* image = palGetSwapchainImage(swapchain, i); + if (!image) { + palLog(nullptr, "Failed to get swapchain image"); + } + + result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image view: %s", error); + return false; + } + + // create render finished semaphores + result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + inFlightImages[i] = nullptr; + } + + result = palCreateCommandPool(device, queue, &cmdPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create command pool: %s", error); + return false; + } + + // create synchronization objects and command buffers + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create semaphore: %s", error); + return false; + } + + result = palCreateFence(device, true, &inFlightFences[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + result = palAllocateCommandBuffer( + device, + cmdPool, + PAL_COMMAND_BUFFER_TYPE_PRIMARY, + &cmdBuffers[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate command buffer: %s", error); + return false; + } + } + + // create vertex and staging buffer + // clang-format off + float vertices[] = { + -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, 0.5f, 1.0f, 0.0f, + 0.5f, -0.5f, 1.0f, 1.0f, + + -0.5f, 0.5f, 0.0f, 0.0f, + 0.5f, -0.5f, 1.0f, 1.0f, + -0.5f, -0.5f, 0.0f, 1.0f}; + // clang-format on + + PalBufferCreateInfo bufferCreateInfo = {0}; + bufferCreateInfo.size = sizeof(vertices); + bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create vertex buffer: %s", error); + return false; + } + + bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send + result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create staging buffer: %s", error); + return false; + } + + // get buffer memory requirement and allocate memory + PalMemoryRequirements vertexBufferMemReq = {0}; + PalMemoryRequirements stagingBufferMemReq = {0}; + + result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get buffer memory requirement: %s", error); + return false; + } + + // we need to check if the memory type we want are supported + // but almost every GPU supports a GPU only memory + // and CPU writable memory + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + vertexBufferMemReq.memoryMask, + vertexBufferMemReq.size, + &vertexBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + stagingBufferMemReq.memoryMask, + stagingBufferMemReq.size, + &stagingBufferMemory); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory for buffer: %s", error); + return false; + } + + // bind memory + result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind memory: %s", error); + return false; + } + + // map the staging buffer and upload the vertices + void* ptr = nullptr; + result = palMapBufferMemory(stagingBuffer, 0, sizeof(vertices), &ptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map buffer memory: %s", error); + return false; + } + + memcpy(ptr, vertices, sizeof(vertices)); + palUnmapBufferMemory(stagingBuffer); + + PalFence* fence = nullptr; + result = palCreateFence(device, false, &fence); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create fence: %s", error); + return false; + } + + // create image for the textures + PalImageCreateInfo imageCreateInfo = {0}; + imageCreateInfo.depthOrArraySize = 1; + imageCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; + imageCreateInfo.mipLevelCount = 1; // simple + imageCreateInfo.sampleCount = PAL_SAMPLE_COUNT_1; // simple + imageCreateInfo.type = PAL_IMAGE_TYPE_2D; + imageCreateInfo.usages = PAL_IMAGE_USAGE_TRANSFER_DST | PAL_IMAGE_USAGE_SAMPLED; + imageCreateInfo.width = TEXTURE_WIDTH; + imageCreateInfo.height = TEXTURE_HEIGHT; + + for (int i = 0; i < 4; i++) { + result = palCreateImage(device, &imageCreateInfo, &textures[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image: %s", error); + return false; + } + + // allocate memory for the image + PalMemoryRequirements imageMemReq = {0}; + result = palGetImageMemoryRequirements(textures[i], &imageMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image memory requirement: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_GPU_ONLY, + imageMemReq.memoryMask, + imageMemReq.size, + &textureMemories[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory: %s", error); + return false; + } + + result = palBindImageMemory(textures[i], textureMemories[i], 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind image memory: %s", error); + return false; + } + } + + // create staging buffers to transfer the data to the images + PalBufferImageCopyInfo bufferImageCopyInfo = {0}; + bufferImageCopyInfo.ImageArrayLayerCount = 1; + bufferImageCopyInfo.imageWidth = TEXTURE_WIDTH; + bufferImageCopyInfo.imageHeight = TEXTURE_HEIGHT; + bufferImageCopyInfo.imageDepth = 1; // 2D image + + Uint64 imageCopyStagingBufferSize = 0; + Uint32 bufferRowLength = 0; + Uint32 bufferImageHeight = 0; + + result = palComputeImageCopyStagingBufferRequirements( + device, + imageCreateInfo.format, + &bufferImageCopyInfo, + &bufferRowLength, + &bufferImageHeight, + &imageCopyStagingBufferSize); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to compute image copy staging buffer info: %s", error); + return false; + } + + // update our copy with the required buffer row length and buffer image height + bufferImageCopyInfo.bufferRowLength = bufferRowLength; + bufferImageCopyInfo.bufferImageHeight = bufferImageHeight; + + // create staging buffers to transfer the data to the image + PalBuffer* imageStagingBuffers[4]; + PalMemory* imageStagingBufferMemories[4]; + + Uint32 textureDatas[4][TEXTURE_WIDTH * TEXTURE_HEIGHT]; + createFlatTexture(textureDatas[0], TEXTURE_WIDTH, TEXTURE_HEIGHT, 255, 0, 0); + createFlatTexture(textureDatas[1], TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, 255, 0); + createFlatTexture(textureDatas[2], TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, 0, 255); + createFlatTexture(textureDatas[3], TEXTURE_WIDTH, TEXTURE_HEIGHT, 255, 255, 0); + + PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; + imageStagingBufferCreateInfo.size = imageCopyStagingBufferSize; + imageStagingBufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; + + for (int i = 0; i < 4; i++) { + result = palCreateBuffer(device, &imageStagingBufferCreateInfo, &imageStagingBuffers[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create image staging buffer: %s", error); + return false; + } + + PalMemoryRequirements imageStagingBufferMemReq = {0}; + result = palGetBufferMemoryRequirements(imageStagingBuffers[i], &imageStagingBufferMemReq); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get image staging buffer memory requirement: %s", error); + return false; + } + + result = palAllocateMemory( + device, + PAL_MEMORY_TYPE_CPU_UPLOAD, + imageStagingBufferMemReq.memoryMask, + imageStagingBufferMemReq.size, + &imageStagingBufferMemories); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate memory: %s", error); + return false; + } + + result = palBindBufferMemory(imageStagingBuffers[i], imageStagingBufferMemories[i], 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind image staging buffer memory: %s", error); + return false; + } + + // copy data + void* data = nullptr; + result = palMapBufferMemory( + imageStagingBuffers[i], + 0, + imageCopyStagingBufferSize, + &data); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to map buffer memory: %s", error); + return false; + } + + // write data to the mapped image copy staging buffer + result = palWriteToImageCopyStagingBuffer( + device, + data, + textureDatas[i], + imageCreateInfo.format, + &bufferImageCopyInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to write to image copy staging buffer: %s", error); + return false; + } + + palUnmapBufferMemory(imageStagingBuffers[i]); + } + + // use the first command buffer to upload the copy + // and reset it when done + // set a fence and check at the last line before the main loop + // to see if we have to wait for the copy to be executed + result = palCmdBegin(cmdBuffers[0], nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + PalBufferCopyInfo copyInfo = {0}; + copyInfo.size = sizeof(vertices); + + result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer: %s", error); + return false; + } + + PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; + PalUsageStateInfo oldUsageStateInfo = {0}; + oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.shaderStageCount = 1; + newUsageStateInfo.shaderStages = vertexShaderStage; + newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; + + result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set buffer barrier: %s", error); + return false; + } + + // copy image staging buffers to the images + // first the image must be in the correct layout + PalUsageStateInfo oldImageUsageState = {0}; + PalUsageStateInfo newImageUsageState = {0}; + + // set a barrier on the image to transition it into transfer dst state + PalImageSubresourceRange textureRange = {0}; + textureRange.startMipLevel = 0; + textureRange.startArrayLayer = 0; + textureRange.mipLevelCount = 1; + textureRange.layerArrayCount = 1; + + for (int i = 0; i < 4; i++) { + newImageUsageState.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + result = palCmdImageBarrier( + cmdBuffers[0], + textures[i], + &textureRange, + &oldImageUsageState, + &newImageUsageState); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image barrier: %s", error); + return false; + } + + result = palCmdCopyBufferToImage( + cmdBuffers[0], + textures[i], + imageStagingBuffers[i], + &bufferImageCopyInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to copy buffer to image: %s", error); + return false; + } + + // we should transition the image into a shader read state so we dont do that + // in the main loop + PalShaderStage fragmentShaderStage[] = { PAL_SHADER_STAGE_FRAGMENT }; + oldImageUsageState = newImageUsageState; + newImageUsageState.usageState = PAL_USAGE_STATE_SHADER_READ; + newImageUsageState.shaderStageCount = 1; + newImageUsageState.shaderStages = fragmentShaderStage; // fragment shader will read + + result = palCmdImageBarrier( + cmdBuffers[0], + textures[i], + &textureRange, + &oldImageUsageState, + &newImageUsageState); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image barrier: %s", error); + return false; + } + } + + result = palCmdEnd(cmdBuffers[0]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffers[0]; + submitInfo.fence = fence; + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // now we have the checkerboard texture data in the image + // we need an image view and a sampler + PalImageViewCreateInfo checkerboardImageViewCreateInfo = {0}; + checkerboardImageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; + checkerboardImageViewCreateInfo.subresourceRange = textureRange; + checkerboardImageViewCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; + + for (int i = 0; i < 4; i++) { + result = palCreateImageView( + device, + textures[i], + &checkerboardImageViewCreateInfo, + &textureViews[i]); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create checkerboard image view: %s", error); + return false; + } + } + + // create sampler + PalSamplerCreateInfo samplerCreateInfo = {0}; + samplerCreateInfo.addressModeU = PAL_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.addressModeV = PAL_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.addressModeW = PAL_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.borderColor = PAL_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerCreateInfo.compareOp = PAL_COMPARE_OP_NEVER; // will not be used if its not enabled + + samplerCreateInfo.enableAnisotropy = false; + samplerCreateInfo.enableCompare = false; + samplerCreateInfo.magFilterMode = PAL_FILTER_MODE_LINEAR; + samplerCreateInfo.minFilterMode = PAL_FILTER_MODE_LINEAR; + samplerCreateInfo.maxAnisotropy = 1.0f; + + result = palCreateSampler( + device, + &samplerCreateInfo, + &sampler); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create sampler: %s", error); + return false; + } + + // create shaders + Uint64 bytecodeSize = 0; + void* bytecode = nullptr; + const char* sources[2]; + PalShaderStage tmpShaderStages[2]; + + PalShaderCreateInfo shaderCreateInfo = {0}; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + sources[0] = "graphics/shaders/bin/spirv/texture_vert.spv"; + sources[1] = "graphics/shaders/bin/spirv/descriptor_indexing.spv"; + + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + sources[0] = "graphics/shaders/bin/dxil/texture_vert.dxil"; + sources[1] = "graphics/shaders/bin/dxil/descriptor_indexing.dxil"; + } + + tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; + tmpShaderStages[1] = PAL_SHADER_STAGE_FRAGMENT; + + for (int i = 0; i < 2; i++) { + // read file + if (!readFile(sources[i], nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } + + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } + + readFile(sources[i], bytecode, &bytecodeSize); + + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.entryName = "main"; + shaderCreateInfo.stage = tmpShaderStages[i]; + + result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create shader: %s", error); + return false; + } + + palFree(nullptr, bytecode); + } + + // create descriptor set layout + PalDescriptorSetLayoutBinding descriptorBindings[2]; + PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; + + descriptorBindings[0].descriptorCount = 4; // an array + descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + descriptorBindings[0].shaderStageCount = 1; + descriptorBindings[0].shaderStages = shaderStages; + + descriptorBindings[1].descriptorCount = 1; // not an array + descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; + descriptorBindings[1].shaderStageCount = 1; + descriptorBindings[1].shaderStages = shaderStages; + + PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; + descriptorSetLayoutcreateInfo.bindingCount = 2; + descriptorSetLayoutcreateInfo.bindings = descriptorBindings; + + result = palCreateDescriptorSetLayout( + device, + &descriptorSetLayoutcreateInfo, + &descriptorSetLayout); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor set layout: %s", error); + return false; + } + + // create descriptor pool + PalDescriptorPoolBindingSize storageBufferBindingsizes[2]; + storageBufferBindingsizes[0].bindingCount = 4; + storageBufferBindingsizes[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + + storageBufferBindingsizes[1].bindingCount = 1; + storageBufferBindingsizes[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; + + PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; + descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set + descriptorPoolCreateInfo.maxDescriptorBindingSizes = 2; + descriptorPoolCreateInfo.bindingSizes = storageBufferBindingsizes; + + result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create descriptor pool: %s", error); + return false; + } + + // allocate a single descriptor set from the descriptor pool + // using the layout we created above + result = palAllocateDescriptorSet(device, descriptorPool, descriptorSetLayout, &descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to allocate descriptor set: %s", error); + return false; + } + + // write the inital data to the descriptor set since its created empty + PalDescriptorImageViewInfo descriptorImageInfos[4]; + descriptorImageInfos[0].imageView = textureViews[0]; + descriptorImageInfos[1].imageView = textureViews[1]; + descriptorImageInfos[2].imageView = textureViews[2]; + descriptorImageInfos[3].imageView = textureViews[3]; + + PalDescriptorSamplerInfo descriptorSamplerInfo = {0}; + descriptorSamplerInfo.sampler = sampler; + + PalDescriptorSetWriteInfo writeInfos[2]; + writeInfos[0].layoutBindingIndex = 0; + writeInfos[0].imageViewInfos = descriptorImageInfos; + writeInfos[0].descriptorSet = descriptorSet; + writeInfos[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + writeInfos[0].descriptorCount = 4; + + writeInfos[0].arrayElement = 0; + writeInfos[0].bufferInfos = nullptr; + writeInfos[0].samplerInfos = nullptr; + writeInfos[0].tlasInfos = nullptr; + + writeInfos[1].layoutBindingIndex = 1; + writeInfos[1].samplerInfos = &descriptorSamplerInfo; + writeInfos[1].descriptorSet = descriptorSet; + writeInfos[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; + writeInfos[1].descriptorCount = 1; + + writeInfos[1].arrayElement = 0; + writeInfos[1].imageViewInfos = nullptr; + writeInfos[1].tlasInfos = nullptr; + writeInfos[1].bufferInfos = nullptr; + + result = palUpdateDescriptorSet(device, 2, writeInfos); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to update descriptor set: %s", error); + return false; + } + + // create pipeline layout + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; + pipelineLayoutCreateInfo.descriptorSetLayoutCount = 1; + pipelineLayoutCreateInfo.descriptorSetLayouts = &descriptorSetLayout; + + result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create pipeline layout: %s", error); + return false; + } + + PalRenderingLayoutInfo renderingLayoutInfo = {0}; + renderingLayoutInfo.colorAttachentCount = 1; + renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; + renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.viewCount = 1; + + // create graphics pipeline + PalGraphicsPipelineCreateInfo pipelineCreateInfo = {0}; + PalVertexLayout vertexLayout = {0}; + PalVertexAttribute vertexAttributes[2]; + + // position + vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; + vertexAttributes[0].semanticName = nullptr; // use default + vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; + + // texture coordinates + vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_TEXCOORD; + vertexAttributes[1].semanticName = nullptr; // use default + vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT2; + + vertexLayout.attributeCount = 2; + vertexLayout.attributes = vertexAttributes; + vertexLayout.binding = 0; // first vertex buffer binding slot + vertexLayout.type = PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX; + + pipelineCreateInfo.vertexLayoutCount = 1; + pipelineCreateInfo.vertexLayouts = &vertexLayout; + + // color blend attachment + PalColorBlendAttachment blendAttachment = {0}; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_RED; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_GREEN; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_BLUE; + blendAttachment.colorWriteMask |= PAL_COLOR_MASK_ALPHA; + + pipelineCreateInfo.colorBlendAttachments = &blendAttachment; + pipelineCreateInfo.colorBlendAttachmentCount = 1; + + // shaders + pipelineCreateInfo.shaderCount = 2; + pipelineCreateInfo.shaders = shaders; + + pipelineCreateInfo.topology = PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + pipelineCreateInfo.pipelineLayout = pipelineLayout; + pipelineCreateInfo.renderingLayout = &renderingLayoutInfo; + + result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create graphics pipeline: %s", error); + return false; + } + + for (int i = 0; i < 2; i++) { + palDestroyShader(shaders[i]); + } + + // wait for the vertices copy to be done + result = palWaitFence(fence, PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for fence: %s", error); + return false; + } + + // the vertices have been copied + palDestroyFence(fence); + palDestroyBuffer(stagingBuffer); + palFreeMemory(device, stagingBufferMemory); + + // we can destroy the image staging buffer + for (int i = 0; i < 4; i++) { + palDestroyBuffer(imageStagingBuffers[i]); + palFreeMemory(device, imageStagingBufferMemories[i]); + } + + // main loop + Uint32 currentFrame = 0; + bool running = true; + + // we are not resizing for the viewport and scissor will not change + PalViewport viewport = {0}; + viewport.height = (float)WINDOW_HEIGHT; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + + PalRect2D scissor = {0}; + scissor.height = WINDOW_HEIGHT; + scissor.width = WINDOW_WIDTH; + + while (running) { + // update the video system to push video events + palUpdateVideo(); + + PalEvent event; + while (palPollEvent(eventDriver, &event)) { + switch (event.type) { + case PAL_EVENT_WINDOW_CLOSE: { + running = false; + break; + } + + case PAL_EVENT_KEYDOWN: { + PalKeycode keycode = 0; + palUnpackUint32(event.data, &keycode, nullptr); + if (keycode == PAL_KEYCODE_ESCAPE) { + running = false; + } + break; + } + } + } + + result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + // get next swapchain image + PalSwapchainNextImageInfo nextImageInfo = {0}; + nextImageInfo.fence = nullptr; + nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; + nextImageInfo.timeout = PAL_INFINITE; + + Uint32 imageIndex = 0; + result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get next swapchain image: %s", error); + return false; + } + + if (inFlightImages[imageIndex] != nullptr) { + result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + inFlightImages[imageIndex] = inFlightFences[currentFrame]; + if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { + result = palResetFence(inFlightFences[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + + } else { + // recreate since we dont support fence resetting + palDestroyFence(inFlightFences[currentFrame]); + + result = palCreateFence(device, false, &inFlightFences[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait fence: %s", error); + return false; + } + } + + // reset the command buffer + result = palResetCommandBuffer(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to reset command buffer: %s", error); + return false; + } + + result = palCmdBegin(cmdBuffers[currentFrame], nullptr); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin command buffer: %s", error); + return false; + } + + // change the state of the image view to make it renderable + PalUsageStateInfo oldUsageStateInfo = {0}; + PalUsageStateInfo newUsageStateInfo = {0}; + newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + + PalImageSubresourceRange imageRange = {0}; + imageRange.layerArrayCount = 1; + imageRange.mipLevelCount = 1; + imageRange.startArrayLayer = 0; + imageRange.startMipLevel = 0; + + PalImage* image = palGetSwapchainImage(swapchain, imageIndex); + result = palCmdImageBarrier( + cmdBuffers[currentFrame], + image, + &imageRange, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + PalClearValue clearValue; + clearValue.color[0] = 0.2f; + clearValue.color[1] = 0.2f; + clearValue.color[2] = 0.2f; + clearValue.color[3] = 1.0f; + + PalAttachmentDesc colorAttachment = {0}; + colorAttachment.loadOp = PAL_LOAD_OP_CLEAR; + colorAttachment.storeOp = PAL_STORE_OP_STORE; + colorAttachment.clearValue = clearValue; + colorAttachment.imageView = imageViews[imageIndex]; + + PalRenderingInfo renderingInfo = {0}; + renderingInfo.viewCount = 1; + renderingInfo.colorAttachentCount = 1; + renderingInfo.colorAttachments = &colorAttachment; + + result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to begin rendering: %s", error); + return false; + } + + // bind pipeline + result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind pipeline: %s", error); + return false; + } + + result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind descriptor set: %s", error); + return false; + } + + // set viewport and scissors + result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set viewport: %s", error); + return false; + } + + result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set scissors: %s", error); + return false; + } + + // bind vertex buffer + Uint64 offset[] = {0}; + result = palCmdBindVertexBuffers( + cmdBuffers[currentFrame], + 0, + 1, + &vertexBuffer, + offset); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind vertex buffer: %s", error); + return false; + } + + result = palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to issue draw command: %s", error); + return false; + } + + result = palCmdEndRendering(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end rendering: %s", error); + return false; + } + + // change the state of the image view to make it presentable + oldUsageStateInfo = newUsageStateInfo; + newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + result = palCmdImageBarrier( + cmdBuffers[currentFrame], + image, + &imageRange, + &oldUsageStateInfo, + &newUsageStateInfo); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to set image view barrier: %s", error); + return false; + } + + result = palCmdEnd(cmdBuffers[currentFrame]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to end command buffer: %s", error); + return false; + } + + // submit command buffer + PalCommandBufferSubmitInfo submitInfo = {0}; + submitInfo.cmdBuffer = cmdBuffers[currentFrame]; + submitInfo.fence = inFlightFences[currentFrame]; + submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; + submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; + + result = palSubmitCommandBuffer(queue, &submitInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to submit command buffer: %s", error); + return false; + } + + // present + PalSwapchainPresentInfo presentInfo = {0}; + presentInfo.imageIndex = imageIndex; + presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; + result = palPresentSwapchain(swapchain, &presentInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to present swapchain: %s", error); + return false; + } + + currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; + } + + result = palWaitQueue(queue); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to wait for queue: %s", error); + return false; + } + + palDestroyPipeline(pipeline); + palDestroyPipelineLayout(pipelineLayout); + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + palDestroySemaphore(imageAvailableSemaphores[i]); + palDestroyFence(inFlightFences[i]); + palFreeCommandBuffer(cmdBuffers[i]); + } + + for (int i = 0; i < imageCount; i++) { + palDestroySemaphore(renderFinishedSemaphores[i]); + palDestroyImageView(imageViews[i]); + } + + palDestroyDescriptorPool(descriptorPool); + palDestroyDescriptorSetLayout(descriptorSetLayout); + + palDestroySampler(sampler); + for (int i = 0; i < 4; i++) { + palDestroyImageView(textureViews[i]); + palDestroyImage(textures[i]); + palFreeMemory(device, textureMemories[i]); + } + + palDestroyBuffer(vertexBuffer); + palFreeMemory(device, vertexBufferMemory); + + palDestroyCommandPool(cmdPool); + palDestroySwapchain(swapchain); + palDestroySurface(surface); + palDestroyQueue(queue); + palDestroyDevice(device); + palShutdownGraphics(); + + palFree(nullptr, imageViews); + palFree(nullptr, renderFinishedSemaphores); + palFree(nullptr, inFlightImages); + + palDestroyWindow(window); + palShutdownVideo(); + palDestroyEventDriver(eventDriver); + return true; +} diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 8b35b500..7bd14b0e 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -156,6 +156,34 @@ bool graphicsTest() palLog(nullptr, ""); palLog(nullptr, " Capabilities:"); + if (caps.sampledImageDynamicArrayIndexing) { + palLog(nullptr, " Sampled image dynamic array indexing: True"); + + } else { + palLog(nullptr, " Sampled image dynamic array indexing: False"); + } + + if (caps.storageImageDynamicArrayIndexing) { + palLog(nullptr, " Storage image dynamic array indexing: True"); + + } else { + palLog(nullptr, " Storage image dynamic array indexing: False"); + } + + if (caps.storageBufferDynamicArrayIndexing) { + palLog(nullptr, " Storage buffer dynamic array indexing: True"); + + } else { + palLog(nullptr, " Storage buffer dynamic array indexing: False"); + } + + if (caps.uniformBufferDynamicArrayIndexing) { + palLog(nullptr, " Uniform buffer dynamic array indexing: True"); + + } else { + palLog(nullptr, " Uniform buffer dynamic array indexing: False"); + } + palLog(nullptr, " Max compute queue: %u", caps.maxComputeQueues); palLog(nullptr, " Max graphics queue: %u", caps.maxGraphicsQueues); palLog(nullptr, " Max copy queue: %u", caps.maxCopyQueues); @@ -424,34 +452,60 @@ bool graphicsTest() return false; } - if (tmp.bindlessSampledImages) { - palLog(nullptr, " Bindless sampled images: True"); + if (tmp.sampledImageNonUniformIndexing) { + palLog(nullptr, " Sampled image non uniform indexing: True"); + } else { - palLog(nullptr, " Bindless sampled images: False"); + palLog(nullptr, " Sampled image non uniform indexing: False"); } - if (tmp.bindlessStorageImages) { - palLog(nullptr, " Bindless storage images: True"); + if (tmp.sampledImageUpdateAfterBind) { + palLog(nullptr, " Sampled image update after bind: True"); + } else { - palLog(nullptr, " Bindless storage images: False"); + palLog(nullptr, " Sampled image update after bind: False"); } - if (tmp.bindlessSamplers) { - palLog(nullptr, " Bindless samplers: True"); + if (tmp.storageImageNonUniformIndexing) { + palLog(nullptr, " Storage image non uniform indexing: True"); + + } else { + palLog(nullptr, " Storage image non uniform indexing: False"); + } + + if (tmp.storageImageUpdateAfterBind) { + palLog(nullptr, " Storage image update after bind: True"); + + } else { + palLog(nullptr, " Storage image update after bind: False"); + } + + if (tmp.storageBufferNonUniformIndexing) { + palLog(nullptr, " Storage buffer non uniform indexing: True"); + + } else { + palLog(nullptr, " Storage buffer non uniform indexing: False"); + } + + if (tmp.storageBufferUpdateAfterBind) { + palLog(nullptr, " Storage buffer update after bind: True"); + } else { - palLog(nullptr, " Bindless samplers: False"); + palLog(nullptr, " Storage buffer update after bind: False"); } - if (tmp.bindlessStorageBuffers) { - palLog(nullptr, " Bindless storage buffers: True"); + if (tmp.uniformBufferNonUniformIndexing) { + palLog(nullptr, " Uniform buffer non uniform indexing: True"); + } else { - palLog(nullptr, " Bindless storage buffers: False"); + palLog(nullptr, " Uniform buffer non uniform indexing: False"); } - if (tmp.bindlessUniformBuffers) { - palLog(nullptr, " Bindless uniform buffers: True"); + if (tmp.uniformBufferUpdateAfterBind) { + palLog(nullptr, " Uniform buffer update after bind: True"); + } else { - palLog(nullptr, " Bindless uniform buffers: False"); + palLog(nullptr, " Uniform buffer update after bind: False"); } // clang-format off diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index cc036efd..a1df4201 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -188,6 +188,7 @@ bool indirectDrawTest() adapterFeatures = palGetAdapterFeatures(adapter); if (adapterFeatures & PAL_ADAPTER_FEATURE_INDIRECT_DRAW) { hasIndirect = true; + } else { hasIndirect = false; } diff --git a/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl b/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl new file mode 100644 index 00000000..72caa6f1 --- /dev/null +++ b/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl @@ -0,0 +1,16 @@ + +#version 450 + +layout(set = 0, binding = 0) uniform texture2D texs[4]; +layout(set = 0, binding = 1) uniform sampler samp; + +layout(location = 0) in vec2 aTexCoord; + +layout(location = 0) out vec4 color; + +void main() +{ + int index = int(gl_FragCoord.x) / 160; + index = index & 3; + color = texture(sampler2D(texs[index], samp), aTexCoord); +} \ No newline at end of file diff --git a/tests/tests.h b/tests/tests.h index 77b283c5..6a1a82dd 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -91,5 +91,6 @@ bool meshTest(); bool textureTest(); bool geometryTest(); bool indirectDrawTest(); +bool descriptorIndexingTest(); #endif // _TESTS_H diff --git a/tests/tests.lua b/tests/tests.lua index 742dc776..af056bb4 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -83,7 +83,8 @@ project "tests" "graphics/mesh_test.c", "graphics/texture_test.c", "graphics/geometry_test.c", - "graphics/indirect_draw_test.c" + "graphics/indirect_draw_test.c", + "graphics/descriptor_indexing_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index d9757643..16d6ef5b 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,7 +57,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest, "Graphics Test"); + registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); @@ -69,7 +69,8 @@ int main(int argc, char** argv) // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); - registerTest(indirectDrawTest, "Indirect Draw Test"); + // registerTest(indirectDrawTest, "Indirect Draw Test"); + // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From 9d3de753994a81c50b4fbf7116b2b57f2c89bae0 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 18 May 2026 12:43:01 +0000 Subject: [PATCH 221/372] add more adapter capabilities d3d12 --- include/pal/pal_graphics.h | 17 +- src/graphics/pal_d3d12.c | 203 +++++++++++++++++----- src/graphics/pal_vulkan.c | 84 ++++----- tests/graphics/descriptor_indexing_test.c | 2 +- tests/graphics/graphics_test.c | 21 +++ 5 files changed, 228 insertions(+), 99 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index f321c70b..a714fdac 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1598,13 +1598,24 @@ typedef struct { /** * @struct PalDescriptorIndexingCapabilities * @brief Descriptor indexing capabilities of an adapter (GPU). - * - * PAL does not support partially bound descriptors or variable descriptor count. * * @since 1.4 * @ingroup pal_graphics */ typedef struct { + /** Allows descriptor array whose size is not fixed at compiled time. + * The size will be provided at runtime.*/ + bool runtimeDescriptorArray; + + /** Allows a descriptor set to specify the number of descriptors in a descriptor set + * layout. This is only valid for one binding per descriptor set layout and it must be the + * last binding in the descriptor set layput.*/ + bool variableDescriptorCount; + + /** Allows a descriptor set to contain descriptors that are not initialized. Shader reading + * an uninitialized descriptor is still undefined behavior.*/ + bool partiallyBoundDescriptors; + bool sampledImageNonUniformIndexing; bool sampledImageUpdateAfterBind; bool storageImageNonUniformIndexing; @@ -4481,8 +4492,6 @@ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `caps` is per thread. - * - * @note PAL does not support partially bound descriptors or variable descriptor counts. * * @since 1.4 * @ingroup pal_graphics diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 16da7b2c..59751e54 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -27,9 +27,6 @@ freely, subject to the following restrictions: #include "pal/pal_graphics.h" -// TODO: Check flag for indirect buffers -// TODO: Add PAL_BUFFER_USAGE_INDIRECT bit -// TODO: add descriptor indexing shader #if PAL_HAS_D3D12 #ifdef __WIN32 @@ -299,6 +296,7 @@ typedef struct { bool supportsAddress; bool canChangeState; + bool hasIndirect; Uint64 size; ID3D12Resource* handle; Device* device; @@ -1521,6 +1519,10 @@ static D3D12_RESOURCE_STATES barrierToD3D12( return D3D12_RESOURCE_STATE_INDEX_BUFFER; } + case PAL_USAGE_STATE_INDIRECT_READ: { + return D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT; + } + case PAL_USAGE_STATE_UNIFORM_READ: { return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; } @@ -2016,6 +2018,95 @@ static void commitShaderbindingTableUpdateD3D12( sbt->isDirty = false; } +static void getDescriptorLimitsD3D12( + void* device, + PalAdapterCapabilities* caps, + PalDescriptorIndexingCapabilities* descCaps) +{ + D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; + if (caps) { + ID3D12Device* handle = device; + handle->lpVtbl->CheckFeatureSupport( + handle, + D3D12_FEATURE_D3D12_OPTIONS, + &options, + sizeof(options)); + + } else { + ID3D12Device5* handle = device; + handle->lpVtbl->CheckFeatureSupport( + handle, + D3D12_FEATURE_D3D12_OPTIONS, + &options, + sizeof(options)); + } + + if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) { + // safe defaults + if (caps) { + caps->maxPerStageDescriptorSampledImages = 1024; + caps->maxDescriptorSetSampledImages = 1024; + caps->maxPerStageDescriptorStorageImages = 512; + caps->maxDescriptorSetStorageImages = 512; + + caps->maxPerStageDescriptorSamplers = 256; + caps->maxDescriptorSetSamplers = 256; + caps->maxPerStageDescriptorStorageBuffers = 512; + caps->maxDescriptorSetStorageBuffers = 512; + + caps->maxPerStageDescriptorUniformBuffers = 256; + caps->maxDescriptorSetUniformBuffers = 256; + caps->maxBoundDescriptorSets = 30; + + } else { + descCaps->maxPerStageBindlessDescriptorSampledImages = 1024; + descCaps->maxDescriptorSetBindlessSampledImages = 1024; + descCaps->maxPerStageBindlessDescriptorStorageImages = 512; + descCaps->maxDescriptorSetBindlessStorageImages = 512; + + descCaps->maxPerStageBindlessDescriptorSamplers = 256; + descCaps->maxDescriptorSetBindlessSamplers = 256; + descCaps->maxPerStageBindlessDescriptorStorageBuffers = 512; + descCaps->maxDescriptorSetBindlessStorageBuffers = 512; + + descCaps->maxPerStageBindlessDescriptorUniformBuffers = 256; + descCaps->maxDescriptorSetBindlessUniformBuffers = 256; + } + + } else { + // safe defaults + if (caps) { + caps->maxPerStageDescriptorSampledImages = 4096; + caps->maxDescriptorSetSampledImages = 4096; + caps->maxPerStageDescriptorStorageImages = 1024; + caps->maxDescriptorSetStorageImages = 1024; + + caps->maxPerStageDescriptorSamplers = 512; + caps->maxDescriptorSetSamplers = 512; + caps->maxPerStageDescriptorStorageBuffers = 2048; + caps->maxDescriptorSetStorageBuffers = 2048; + + caps->maxPerStageDescriptorUniformBuffers = 256; + caps->maxDescriptorSetUniformBuffers = 256; + caps->maxBoundDescriptorSets = 30; + + } else { + descCaps->maxPerStageBindlessDescriptorSampledImages = 4096; + descCaps->maxDescriptorSetBindlessSampledImages = 4096; + descCaps->maxPerStageBindlessDescriptorStorageImages = 1024; + descCaps->maxDescriptorSetBindlessStorageImages = 1024; + + descCaps->maxPerStageBindlessDescriptorSamplers = 512; + descCaps->maxDescriptorSetBindlessSamplers = 512; + descCaps->maxPerStageBindlessDescriptorStorageBuffers = 2048; + descCaps->maxDescriptorSetBindlessStorageBuffers = 2048; + + descCaps->maxPerStageBindlessDescriptorUniformBuffers = 256; + descCaps->maxDescriptorSetBindlessUniformBuffers = 256; + } + } +} + // ================================================== // Adapter // ================================================== @@ -2274,6 +2365,12 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapter* adapter, PalAdapterCapabilities* caps) { + // always supported + caps->sampledImageDynamicArrayIndexing = true; + caps->storageImageDynamicArrayIndexing = true; + caps->storageBufferDynamicArrayIndexing = true; + caps->uniformBufferDynamicArrayIndexing = true; + caps->maxComputeQueues = 2; // safe default caps->maxGraphicsQueues = 2; // safe default caps->maxCopyQueues = 2; // safe default @@ -2307,21 +2404,6 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( caps->maxVertexAttributes = 32; // safe caps->maxTessellationPatchPoint = 32; - // safe defaults - caps->maxPerStageDescriptorSampledImages = 1024; - caps->maxDescriptorSetSampledImages = 1024; - caps->maxPerStageDescriptorStorageImages = 512; - caps->maxDescriptorSetStorageImages = 512; - - caps->maxPerStageDescriptorSamplers = 256; - caps->maxDescriptorSetSamplers = 256; - caps->maxPerStageDescriptorStorageBuffers = 512; - caps->maxDescriptorSetStorageBuffers = 512; - - caps->maxPerStageDescriptorUniformBuffers = 256; - caps->maxDescriptorSetUniformBuffers = 256; - caps->maxBoundDescriptorSets = 30; - caps->maxComputeWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; caps->maxComputeWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; caps->maxComputeWorkGroupCount[1] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; @@ -2331,6 +2413,8 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( caps->maxComputeWorkGroupSize[1] = D3D12_CS_THREAD_GROUP_MAX_Y; caps->maxComputeWorkGroupSize[2] = D3D12_CS_THREAD_GROUP_MAX_Z; + Adapter* d3dAdapter = (Adapter*)adapter; + getDescriptorLimitsD3D12(d3dAdapter->tmpDevice, caps, nullptr); return PAL_RESULT_SUCCESS; } @@ -2434,10 +2518,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT; } - if (!(options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1)) { - features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - } - // this features are supported on d3d12 features |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; features |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; @@ -2450,6 +2530,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; features |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; + features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; if (d3dAdapter->level >= D3D_FEATURE_LEVEL_12_0) { features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; @@ -3076,27 +3157,21 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // these are supported if descriptor indexing is - caps->bindlessSampledImages = true; - caps->bindlessStorageImages = true; - caps->bindlessSamplers = true; - caps->bindlessStorageBuffers = true; - caps->bindlessUniformBuffers = true; - - // safe defaults - caps->maxPerStageBindlessDescriptorSampledImages = 4096; - caps->maxDescriptorSetBindlessSampledImages = 4096; - caps->maxPerStageBindlessDescriptorStorageImages = 1024; - caps->maxDescriptorSetBindlessStorageImages = 1024; + caps->runtimeDescriptorArray = true; // always supported + caps->variableDescriptorCount = true; // manually + caps->partiallyBoundDescriptors = true; // always supported - caps->maxPerStageBindlessDescriptorSamplers = 512; - caps->maxDescriptorSetBindlessSamplers = 512; - caps->maxPerStageBindlessDescriptorStorageBuffers = 2048; - caps->maxDescriptorSetBindlessStorageBuffers = 2048; - - caps->maxPerStageBindlessDescriptorUniformBuffers = 256; - caps->maxDescriptorSetBindlessUniformBuffers = 256; + // always supported + caps->sampledImageNonUniformIndexing = true; + caps->sampledImageUpdateAfterBind = true; + caps->storageImageNonUniformIndexing = true; + caps->storageImageUpdateAfterBind = true; + caps->storageBufferNonUniformIndexing = true; + caps->storageBufferUpdateAfterBind = true; + caps->uniformBufferNonUniformIndexing = true; + caps->uniformBufferUpdateAfterBind = true; + getDescriptorLimitsD3D12(d3dDevice->handle, nullptr, caps); return PAL_RESULT_SUCCESS; } @@ -4912,11 +4987,15 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; + Buffer* d3dBuffer = (Buffer*)buffer; if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Buffer* d3dBuffer = (Buffer*)buffer; + if (!d3dBuffer->hasIndirect) { + return PAL_RESULT_INVALID_BUFFER; + } + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( d3dCmdBuffer->handle, device->meshSignature, @@ -4943,6 +5022,10 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( Buffer* d3dBuffer = (Buffer*)buffer; Buffer* d3dCountBuffer = (Buffer*)countBuffer; + if (!d3dBuffer->hasIndirect || !d3dCountBuffer->hasIndirect) { + return PAL_RESULT_INVALID_BUFFER; + } + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( d3dCmdBuffer->handle, device->meshSignature, @@ -5541,11 +5624,15 @@ PalResult PAL_CALL cmdDrawIndirectD3D12( { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; + Buffer* d3dBuffer = (Buffer*)buffer; if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Buffer* d3dBuffer = (Buffer*)buffer; + if (!d3dBuffer->hasIndirect) { + return PAL_RESULT_INVALID_BUFFER; + } + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( d3dCmdBuffer->handle, device->drawSignature, @@ -5572,6 +5659,10 @@ PalResult PAL_CALL cmdDrawIndirectCountD3D12( Buffer* d3dBuffer = (Buffer*)buffer; Buffer* d3dCountBuffer = (Buffer*)countBuffer; + if (!d3dBuffer->hasIndirect || !d3dCountBuffer->hasIndirect) { + return PAL_RESULT_INVALID_BUFFER; + } + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( d3dCmdBuffer->handle, device->drawSignature, @@ -5611,11 +5702,15 @@ PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; + Buffer* d3dBuffer = (Buffer*)buffer; if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Buffer* d3dBuffer = (Buffer*)buffer; + if (!d3dBuffer->hasIndirect) { + return PAL_RESULT_INVALID_BUFFER; + } + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( d3dCmdBuffer->handle, device->drawIndexedSignature, @@ -5642,6 +5737,10 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( Buffer* d3dBuffer = (Buffer*)buffer; Buffer* d3dCountBuffer = (Buffer*)countBuffer; + if (!d3dBuffer->hasIndirect || !d3dCountBuffer->hasIndirect) { + return PAL_RESULT_INVALID_BUFFER; + } + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( d3dCmdBuffer->handle, device->drawIndexedSignature, @@ -5853,11 +5952,15 @@ PalResult PAL_CALL cmdDispatchIndirectD3D12( { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; + Buffer* d3dBuffer = (Buffer*)buffer; if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Buffer* d3dBuffer = (Buffer*)buffer; + if (!d3dBuffer->hasIndirect) { + return PAL_RESULT_INVALID_BUFFER; + } + d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( d3dCmdBuffer->handle, device->dispatchSignature, @@ -5922,6 +6025,10 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } + if (!d3dBuffer->hasIndirect) { + return PAL_RESULT_INVALID_BUFFER; + } + // we need to make sure the SBT is up to date commitShaderbindingTableUpdateD3D12(d3dCmdBuffer, d3dSbt); @@ -6294,7 +6401,11 @@ PalResult PAL_CALL createBufferD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } buffer->supportsAddress = true; - } + } + + if (info->usages & PAL_BUFFER_USAGE_INDIRECT) { + buffer->hasIndirect = false; + } buffer->device = d3dDevice; buffer->size = info->size; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 0306be7f..49b58a19 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -4020,21 +4020,12 @@ PalResult PAL_CALL createDeviceVk( coreFeatures.shaderFloat64 = true; } - if (phyDeviceFeatures.shaderSampledImageArrayDynamicIndexing) { - coreFeatures.shaderSampledImageArrayDynamicIndexing = true; - } - - if (phyDeviceFeatures.shaderStorageImageArrayDynamicIndexing) { - coreFeatures.shaderStorageImageArrayDynamicIndexing = true; - } - - if (phyDeviceFeatures.shaderStorageBufferArrayDynamicIndexing) { - coreFeatures.shaderStorageBufferArrayDynamicIndexing = true; - } - - if (phyDeviceFeatures.shaderUniformBufferArrayDynamicIndexing) { - coreFeatures.shaderUniformBufferArrayDynamicIndexing = true; - } + // clang-format off + coreFeatures.shaderSampledImageArrayDynamicIndexing = phyDeviceFeatures.shaderSampledImageArrayDynamicIndexing; + coreFeatures.shaderStorageImageArrayDynamicIndexing = phyDeviceFeatures.shaderStorageImageArrayDynamicIndexing; + coreFeatures.shaderStorageBufferArrayDynamicIndexing = phyDeviceFeatures.shaderStorageBufferArrayDynamicIndexing; + coreFeatures.shaderUniformBufferArrayDynamicIndexing = phyDeviceFeatures.shaderUniformBufferArrayDynamicIndexing; + // clang-format on // extensions and features2 void* next = nullptr; @@ -4194,8 +4185,6 @@ PalResult PAL_CALL createDeviceVk( extensions[extCount++] = "VK_EXT_descriptor_indexing"; } - features12.descriptorIndexing = true; - // check support for sub features VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; @@ -4205,42 +4194,25 @@ PalResult PAL_CALL createDeviceVk( features.pNext = &desc; s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - // check sub feature for sampled image - if (desc.shaderSampledImageArrayNonUniformIndexing) { - descIndex.shaderSampledImageArrayNonUniformIndexing = true; - } - - if (desc.descriptorBindingSampledImageUpdateAfterBind) { - descIndex.descriptorBindingSampledImageUpdateAfterBind = true; - } - - // check sub feature for storage image - if (desc.shaderStorageImageArrayNonUniformIndexing) { - descIndex.shaderStorageImageArrayNonUniformIndexing = true; - } - - if (desc.descriptorBindingStorageImageUpdateAfterBind) { - descIndex.descriptorBindingStorageImageUpdateAfterBind = true; - } + // clang-format off + descIndex.runtimeDescriptorArray = desc.runtimeDescriptorArray; + descIndex.descriptorBindingVariableDescriptorCount = desc.descriptorBindingVariableDescriptorCount; + descIndex.descriptorBindingPartiallyBound = desc.descriptorBindingPartiallyBound; - // check sub feature for storage buffer - if (desc.shaderStorageBufferArrayNonUniformIndexing) { - descIndex.shaderStorageBufferArrayNonUniformIndexing = true; - } + descIndex.shaderSampledImageArrayNonUniformIndexing = desc.shaderSampledImageArrayNonUniformIndexing; + descIndex.descriptorBindingSampledImageUpdateAfterBind = desc.descriptorBindingSampledImageUpdateAfterBind; - if (desc.descriptorBindingStorageBufferUpdateAfterBind) { - descIndex.descriptorBindingStorageBufferUpdateAfterBind = true; - } + descIndex.shaderStorageImageArrayNonUniformIndexing = desc.shaderStorageImageArrayNonUniformIndexing; + descIndex.descriptorBindingStorageImageUpdateAfterBind = desc.descriptorBindingStorageImageUpdateAfterBind; - // check sub feature for uniform buffer - if (desc.shaderUniformBufferArrayNonUniformIndexing) { - descIndex.shaderUniformBufferArrayNonUniformIndexing = true; - } + descIndex.shaderStorageBufferArrayNonUniformIndexing = desc.shaderStorageBufferArrayNonUniformIndexing; + descIndex.descriptorBindingStorageBufferUpdateAfterBind = desc.descriptorBindingStorageBufferUpdateAfterBind; - if (desc.descriptorBindingUniformBufferUpdateAfterBind) { - descIndex.descriptorBindingUniformBufferUpdateAfterBind = true; - } + descIndex.shaderUniformBufferArrayNonUniformIndexing = desc.shaderUniformBufferArrayNonUniformIndexing; + descIndex.descriptorBindingUniformBufferUpdateAfterBind = desc.descriptorBindingUniformBufferUpdateAfterBind; + // clang-format on + features12.descriptorIndexing = true; descIndex.pNext = next; next = &descIndex; } @@ -5043,6 +5015,10 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( s_Vk.getPhysicalDeviceFeatures2(vkDevice->phyDevice, &features); s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + caps->runtimeDescriptorArray = desc.runtimeDescriptorArray; + caps->variableDescriptorCount = desc.descriptorBindingVariableDescriptorCount; + caps->partiallyBoundDescriptors = desc.descriptorBindingPartiallyBound; + // check sub feature for sampled image if (desc.shaderSampledImageArrayNonUniformIndexing) { caps->sampledImageNonUniformIndexing = true; @@ -6836,6 +6812,10 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( return PAL_RESULT_INVALID_BUFFER; } + if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + Uint32 stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); device->cmdDrawMeshTaskIndirectCount( vkCmdBuffer->handle, @@ -7457,6 +7437,10 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( return PAL_RESULT_INVALID_BUFFER; } + if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + Uint32 stride = sizeof(VkDrawIndirectCommand); device->cmdDrawIndirectCount( vkCmdBuffer->handle, @@ -7526,6 +7510,10 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( return PAL_RESULT_INVALID_BUFFER; } + if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_INVALID_BUFFER; + } + Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); device->cmdDrawIndexedIndirectCount( vkCmdBuffer->handle, diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 4086b482..ecfa74d1 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -661,7 +661,7 @@ bool descriptorIndexingTest() PAL_MEMORY_TYPE_CPU_UPLOAD, imageStagingBufferMemReq.memoryMask, imageStagingBufferMemReq.size, - &imageStagingBufferMemories); + &imageStagingBufferMemories[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 7bd14b0e..d4c4b486 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -452,6 +452,27 @@ bool graphicsTest() return false; } + if (tmp.runtimeDescriptorArray) { + palLog(nullptr, " Runtime descriptor arrays: True"); + + } else { + palLog(nullptr, " Runtime descriptor arrays: False"); + } + + if (tmp.variableDescriptorCount) { + palLog(nullptr, " Variable descriptor count: True"); + + } else { + palLog(nullptr, " Variable descriptor count: False"); + } + + if (tmp.partiallyBoundDescriptors) { + palLog(nullptr, " Partially bound descriptors: True"); + + } else { + palLog(nullptr, " Partially bound descriptors: False"); + } + if (tmp.sampledImageNonUniformIndexing) { palLog(nullptr, " Sampled image non uniform indexing: True"); From f2534da4579325cb1fac2b34c57601bc2c107d69 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 18 May 2026 17:19:05 +0000 Subject: [PATCH 222/372] make d3d12 adapters support dxbc 5.1 --- src/graphics/pal_d3d12.c | 23 +++++++++++++++--- src/graphics/pal_vulkan.c | 8 ++++++ tests/graphics/compute_test.c | 12 ++++----- tests/graphics/geometry_test.c | 16 ++++++------ tests/graphics/graphics_test.c | 10 ++++++++ tests/graphics/indirect_draw_test.c | 15 ++++++------ tests/graphics/multi_descriptor_set_test.c | 12 ++++----- tests/graphics/shaders/bin/dxbc/compute.dxbc | Bin 0 -> 992 bytes .../shaders/bin/dxbc/compute_multi.dxbc | Bin 0 -> 1456 bytes tests/graphics/shaders/bin/dxbc/geometry.dxbc | Bin 0 -> 1196 bytes .../shaders/bin/dxbc/geometry_vert.dxbc | Bin 0 -> 688 bytes .../shaders/bin/dxbc/texture_frag.dxbc | Bin 0 -> 692 bytes .../shaders/bin/dxbc/texture_vert.dxbc | Bin 0 -> 636 bytes .../shaders/bin/dxbc/triangle_frag.dxbc | Bin 0 -> 520 bytes .../shaders/bin/dxbc/triangle_vert.dxbc | Bin 0 -> 648 bytes tests/graphics/shaders/bin/dxil/compute.dxil | Bin 3384 -> 0 bytes .../shaders/bin/dxil/compute_multi.dxil | Bin 3848 -> 0 bytes tests/graphics/shaders/bin/dxil/geometry.dxil | Bin 3824 -> 0 bytes .../shaders/bin/dxil/geometry_vert.dxil | Bin 3020 -> 0 bytes .../shaders/bin/dxil/texture_frag.dxil | Bin 3820 -> 0 bytes .../shaders/bin/dxil/texture_vert.dxil | Bin 3104 -> 0 bytes .../shaders/bin/dxil/triangle_frag.dxil | Bin 2964 -> 0 bytes .../shaders/bin/dxil/triangle_vert.dxil | Bin 3144 -> 0 bytes .../shaders/src/hlsl/compute_multi.hlsl | 14 +++++------ tests/graphics/texture_test.c | 14 +++++------ tests/graphics/triangle_test.c | 14 +++++------ tests/tests_main.c | 4 +-- 27 files changed, 88 insertions(+), 54 deletions(-) create mode 100644 tests/graphics/shaders/bin/dxbc/compute.dxbc create mode 100644 tests/graphics/shaders/bin/dxbc/compute_multi.dxbc create mode 100644 tests/graphics/shaders/bin/dxbc/geometry.dxbc create mode 100644 tests/graphics/shaders/bin/dxbc/geometry_vert.dxbc create mode 100644 tests/graphics/shaders/bin/dxbc/texture_frag.dxbc create mode 100644 tests/graphics/shaders/bin/dxbc/texture_vert.dxbc create mode 100644 tests/graphics/shaders/bin/dxbc/triangle_frag.dxbc create mode 100644 tests/graphics/shaders/bin/dxbc/triangle_vert.dxbc delete mode 100644 tests/graphics/shaders/bin/dxil/compute.dxil delete mode 100644 tests/graphics/shaders/bin/dxil/compute_multi.dxil delete mode 100644 tests/graphics/shaders/bin/dxil/geometry.dxil delete mode 100644 tests/graphics/shaders/bin/dxil/geometry_vert.dxil delete mode 100644 tests/graphics/shaders/bin/dxil/texture_frag.dxil delete mode 100644 tests/graphics/shaders/bin/dxil/texture_vert.dxil delete mode 100644 tests/graphics/shaders/bin/dxil/triangle_frag.dxil delete mode 100644 tests/graphics/shaders/bin/dxil/triangle_vert.dxil diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 59751e54..4049d98b 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2312,15 +2312,28 @@ PalResult PAL_CALL getAdapterInfoD3D12( D3D12_FEATURE_DATA_ARCHITECTURE1 arch = {0}; ID3D12Device* device = d3dAdapter->tmpDevice; + D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; + shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; + HRESULT result = adapterHandle->lpVtbl->GetDesc3(adapterHandle, &desc); if (FAILED(result)) { return PAL_RESULT_INVALID_ADAPTER; } + result = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + info->shaderFormats = PAL_SHADER_FORMAT_DXBC; + if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0 && result == S_OK) { + info->shaderFormats |= PAL_SHADER_FORMAT_DXIL; + } + info->vendorId = desc.VendorId; info->deviceId= desc.DeviceId; info->apiType = PAL_ADAPTER_API_TYPE_D3D12; - info->shaderFormats = PAL_SHADER_FORMAT_DXIL; info->sharedMemory = desc.SharedSystemMemory; strcpy(info->backendName, "PAL"); @@ -2542,10 +2555,14 @@ Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( PalAdapter* adapter, PalShaderFormats shaderFormat) { - if (shaderFormat != PAL_SHADER_FORMAT_DXIL) { + if (shaderFormat != PAL_SHADER_FORMAT_DXIL && shaderFormat != PAL_SHADER_FORMAT_DXBC) { return 0; } + if (shaderFormat == PAL_SHADER_FORMAT_DXBC) { + return PAL_MAKE_SHADER_TARGET(5, 1); + } + Adapter* d3dAdapter = (Adapter*)adapter; D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; @@ -6404,7 +6421,7 @@ PalResult PAL_CALL createBufferD3D12( } if (info->usages & PAL_BUFFER_USAGE_INDIRECT) { - buffer->hasIndirect = false; + buffer->hasIndirect = true; } buffer->device = d3dDevice; diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 49b58a19..f3c9b052 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -7410,6 +7410,10 @@ PalResult PAL_CALL cmdDrawIndirectVk( Buffer* vkBuffer = (Buffer*)buffer; Uint32 stride = sizeof(VkDrawIndirectCommand); + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { return PAL_RESULT_INVALID_BUFFER; } @@ -7483,6 +7487,10 @@ PalResult PAL_CALL cmdDrawIndexedIndirectVk( Buffer* vkBuffer = (Buffer*)buffer; Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { return PAL_RESULT_INVALID_BUFFER; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 5223a798..f8f079f0 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -104,7 +104,7 @@ bool computeTest() } if (hasComputeQueue) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 + // We want an adapter that supports spirv 1.0 or dxbc 5.1 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -121,9 +121,9 @@ bool computeTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { break; } } @@ -186,8 +186,8 @@ bool computeTest() if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { source = "graphics/shaders/bin/spirv/compute.spv"; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - source = "graphics/shaders/bin/dxil/compute.dxil"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + source = "graphics/shaders/bin/dxbc/compute.dxbc"; } // read file diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index c0c6f0ef..e52e97b2 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -179,7 +179,7 @@ bool geometryTest() } if (hasGeometryShader) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 + // We want an adapter that supports spirv 1.0 or dxbc 5.1 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -196,9 +196,9 @@ bool geometryTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { break; } } @@ -412,10 +412,10 @@ bool geometryTest() sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; sources[2] = "graphics/shaders/bin/spirv/geometry.spv"; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - sources[0] = "graphics/shaders/bin/dxil/geometry_vert.dxil"; - sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; - sources[2] = "graphics/shaders/bin/dxil/geometry.dxil"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + sources[0] = "graphics/shaders/bin/dxbc/geometry_vert.dxbc"; + sources[1] = "graphics/shaders/bin/dxbc/triangle_frag.dxbc"; + sources[2] = "graphics/shaders/bin/dxbc/geometry.dxbc"; } tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index d4c4b486..a6c10c40 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -244,6 +244,16 @@ bool graphicsTest() palLog(nullptr, ""); } + if (info.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + palLog(nullptr, " DXBC"); + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + targetMajor = PAL_SHADER_TARGET_MAJOR(target); + targetMinor = PAL_SHADER_TARGET_MINOR(target); + + palLog(nullptr, " Highest Dxbc Target: %u.%u", targetMajor, targetMinor); + palLog(nullptr, ""); + } + if (info.shaderFormats & PAL_SHADER_FORMAT_DXIL) { palLog(nullptr, " DXIL"); target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index a1df4201..e691ad5a 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -195,7 +195,7 @@ bool indirectDrawTest() } if (hasIndirect) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 + // We want an adapter that supports spirv 1.0 or dxbc 5.1 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -212,9 +212,9 @@ bool indirectDrawTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { break; } } @@ -238,6 +238,7 @@ bool indirectDrawTest() // create a device PalAdapterFeatures features = PAL_ADAPTER_FEATURE_SWAPCHAIN; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { features |= PAL_ADAPTER_FEATURE_FENCE_RESET; } @@ -778,9 +779,9 @@ bool indirectDrawTest() sources[0] = "graphics/shaders/bin/spirv/triangle_vert.spv"; sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - sources[0] = "graphics/shaders/bin/dxil/triangle_vert.dxil"; - sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + sources[0] = "graphics/shaders/bin/dxbc/triangle_vert.dxbc"; + sources[1] = "graphics/shaders/bin/dxbc/triangle_frag.dxbc"; } tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 9f04bb7a..3dbfd11b 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -128,7 +128,7 @@ bool multiDescriptorSetTest() } if (hasComputeQueue) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 + // We want an adapter that supports spirv 1.0 or dxbc 5.1 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -145,9 +145,9 @@ bool multiDescriptorSetTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { break; } } @@ -218,8 +218,8 @@ bool multiDescriptorSetTest() if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { source = "graphics/shaders/bin/spirv/compute_multi.spv"; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - source = "graphics/shaders/bin/dxil/compute_multi.dxil"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + source = "graphics/shaders/bin/dxbc/compute_multi.dxbc"; } // read file diff --git a/tests/graphics/shaders/bin/dxbc/compute.dxbc b/tests/graphics/shaders/bin/dxbc/compute.dxbc new file mode 100644 index 0000000000000000000000000000000000000000..ebf10f3c1d5705ed3d43eec7d4d122b320a1f266 GIT binary patch literal 992 zcmcgqO)mpc6utdY8Vk`#L?lL#uxVQ9N@!?nkknVlfOr{nzr{J0BfYx z;b+ZXx?SkHpks2q!(ZxE3%X^HUKOSeRS-ScLhM>Gfsm0aY#SD3MNycPFN%y6MTQ6D z8~uy}l=+mFQZyr@=S(Fb_Vx=!EF$4hgch{9C4L76+vS$MHb1-G zk9w^+R3#+80R6e&muB_U!$sMJX)QYoeG5QHj}Vh0DMF|r+%u>(V= zP7Fv$jHpr;hAvFZ{0AKv7#LXSfEZX1d|&)tVp&z2iIYFyySwl1y?gK3mHLA9^5fLE zH(z$o++1FNzw`Ug4?{#gOp4%0m?owrNH^l0+g{>4c?zHI*P{}3N`VW#u1|9I^=hwg>JLy2B8dwveFGb z%kP9yqZ5VFV=eY>B6(gXLI+qJ>up2p^|E)ak^X~}|2v(K2>>DarR={D`n8@xkeriv zv#LJlX1y|B5M4*>I{YU5C-GeH3M25gT2ADNv*ia4*g5p78iAFTLxeoH^~{T8qrcCV z-}Zx|G~0e7DofA6Z87?trZZ#v8rGCZEG3N_!y^kH7uID@^{@NfSGL{>z3chl`e z((8>h|EP8Ex1I)m=ri&h(hV&QsG?%8*jGpb$c2PxZL ztk!q1Zx3PlJ0v(Xr$SF-H3du1yIy$AhN* z7FUij9bXa2lvJe}c(v^UqC>&=Jbg~ZFDji?dR8XJ_4qcXy8v7kIW^>uNj6n4i#hi2 zOZfTq(qIx@!J zgNut!#lfY{u7ZC-2M7O-&JKRxefP#|bn(Es=ht_>d+y;Swbg}c`t#`atA5aZ{pM)p ze7m+--$3lkJc1yv8*HLKHC4MvI}I&ay#RX>O1aa0 zl=k*|kDsYh`;uB}>6X&l>l>S?s`hrDc6Z>+MptL0sT<2zfagr(Pz9wh&KXZ+VnRgU zd$^M5W~Z4fOQIXsI;e$E_E2JT4)xhw%UT+8k{gtNa8{F6(w4(Ry|lRc1H^a1{sovP z;}Wc6RmVj&n1}t_xSm{H5o|2urNh|G&UkHFg14r8iZHofl3)v%V^uUUv74wfrvCuE z1=#B%qmz+>mq`$de0YE6tDh&Hd5WLsUM#+Xd?5u7v6L{zA^R1cPJ9e;VT{AbZ=8=I ze;DH!NQMI@e_rgn;;hKr!cZ>4c;`gM`Zj;rt8=G08OhzSIrNWBTK`0(%&r}twG=hZ zTrVrLcdwRr{BB47z3g#!u8l+GLH{V*f_t%RDgB}9-wzA6JOAN7`>6^`cn)w@_ zqGsj|GfR%X&1G}$SDt&{%Z#@te_nE&#vWe`Vco9X9?0piH{t5etMsmpC3*W6b{+e#ieKzX0KNSpon6 literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxbc/geometry_vert.dxbc b/tests/graphics/shaders/bin/dxbc/geometry_vert.dxbc new file mode 100644 index 0000000000000000000000000000000000000000..89ca9feb9a3726485a6cdeba69f173ced218eb4a GIT binary patch literal 688 zcma)2Jx{_=6um8AD>0FPgX0@CfrOYsjFS`SkHx?)GzJf<|TcreWWG|5k0Cz5yVaK z9()IN2rK9}%u>07+K+7%O62>8hd56p%yo{dVAA6n;u6T%@1Kl@SHsh>NH$WUQk7L9 zd&iybNEC+`m;G}j8Dk?umfWkQ;pdxlP=JgDkb4XTiEJIVx}$OT+A_)hV}|`9XM$)M z5i@mLT20HYk*t*3VHgguwE%6PlX659j>lro1iyEN`ct?y@9Gh$9Q)|AiFb3dMYNbT z1Tq(D-i>ds)g3pR_wWuiPsBPnMd`r52fv-vyyKY$JdrrLH$}Z$F{fp{JIjV}Zi{*z rX!^6K@xFOXayU?t%|i1If(G(!41V8_S)Y5e@Am7#JUAcJ|6Bh8ljcEo literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxbc/texture_frag.dxbc b/tests/graphics/shaders/bin/dxbc/texture_frag.dxbc new file mode 100644 index 0000000000000000000000000000000000000000..97d2a60ca65d24d4da246c146d53ac034d49afdd GIT binary patch literal 692 zcmZ>XaB@B|Z^@}|{!bsBwwvX$Ds7EDBLf4&7A6J;Rv>Kx#D9P|1Sr@6#1cU9AQxA+ z13)nt017eK05K!$|NkIOQ-N$@VHZ`9m;?}OK(Pvt<^f_5=mBD8FbkCc*^LY)0y!Y_ zL2h9I;{QMZq!>WzU}k~%#fiBE3?-=*48EDkMft_~X(b98L7EC4KEXZ;!5N7usYMFT z`MCv|IY5S?fu145>eZ_~gWdfCfO~3|a;-R4s=_COLW+MRsup3i>-uR>-0G4oNVBm(a t-JtSrbqa7Z84?g|JD?YXLmWe<0A)d80|UrxkQgW&Z~=UBxbzS!4gh_HNUi_? literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxbc/texture_vert.dxbc b/tests/graphics/shaders/bin/dxbc/texture_vert.dxbc new file mode 100644 index 0000000000000000000000000000000000000000..20feea50810febfcc59baf496d931d6c0bdf40f9 GIT binary patch literal 636 zcmZ>XaB{9vy(T|lvhI|Qyl)2aXDn+N85kI9m>3vXfwTz_F96~%KiFw-Ti!k>VeK--~eI^Acg^ED1#ZuaD)j0X^=R`4j8>`06!4BfLRa%ZYIzJ!C~>(j9ne< z;Tq8cR2~SlT^UGcaWF8(1D#II5%9D<55Ie=u4L4!R^4@f^q4~Vt{219U&W5^UBn*~WZG8-feQcDT|g#|SL06Nh< A7XSbN literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxbc/triangle_frag.dxbc b/tests/graphics/shaders/bin/dxbc/triangle_frag.dxbc new file mode 100644 index 0000000000000000000000000000000000000000..37f514deffbd9d98f7221145229eb1907969be07 GIT binary patch literal 520 zcmZ>XaB|kXqq*-ut;2do>EM;$I8w_Q85kHim>3vXfwTz_F96~%K&%0j$N}OY7gx6w zARign06C1T|NnzDf!M;rE~+3}0*E!BSOrM)05J&oW+oTq7w4yyC};#}DtPz=`zQow zB&MVmDLCin7G&lC8HNUWh76v;?tVT%^+4w^Z~(Cd5Q6~7jm%&c0|P&hc7d`%6i6H- z&kvLc4vP=)5B3c4^!Hi5?Vvv1V91M&}0u0Qb1O&i#r2?(}q#yt`#tayAFt(c RG8-fYayKb}RQ0&b1^~BIG_C*u literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxbc/triangle_vert.dxbc b/tests/graphics/shaders/bin/dxbc/triangle_vert.dxbc new file mode 100644 index 0000000000000000000000000000000000000000..a8f3f2c0d71094b374eb38cce14a56a9b83a51b2 GIT binary patch literal 648 zcmZ>XaB?nuvb0Qi)}cDyZC}JII72@(GB7Z7FflN&0%;QTUo0(jcU!0#-qM#9^so>!g?4uBz zk(iQNq~M&NTacLpWEdLg88UbVyZdVnlLAB>#7_mvf%qV{88FC=pmJ_d zy+ARJLr^g$2cRMp&|nYJQv}uTCWJ7j2`a|u0MgK4ZwCyL;1I`fw OcaQ?m^^>9(SuFqqXg$UN literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/compute.dxil b/tests/graphics/shaders/bin/dxil/compute.dxil deleted file mode 100644 index 2d6da3e38f9fcd684b383b5b37a412e7303d8482..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3384 zcmeHJeNa=`6~Ey<-g_*M$IFKpNN`{H8Z4~Fgyq}ad>{rl>^=%wJEPMCjE0tA1WfsG zI!TBG-KbHpi)F_J6^CiJ7OJhq-R^`BW6Ge$uZk-}Va3R{tjjpA)tQ}X?~AhI?DVfr z|Ja@BnK}2Id+xdCoHzHr^SecxHQL3JW4qrze{AIKb4>?pv;JY?0RVDi0KlOvgsg|W z1#%7K$BRp{_{B05E_^upb64+FYXN5`^GG=)0A6(YgrDk!Z~+S|Q3M#BaT# z_+h)wD`K?8?R_9#p_$WB-or^_th&tMnQgtlA6;3DmBA0;>XLY7xX;E_5&bc3i=2uu zyjxi1Q%>c1K?(Fjpr6ob&@g%eRtLa727pyiDw1?j%(lH~N75-59PYV#y&{2rzbD#t zN>5vpK`Ic12wx9bMJ6f1`k43LG{(xFO%*T8So7?nC3!?#6(VTOKgs8IS&)o&I4jzf zH+y#9v_2C)p^sd(R169_4ozhz`Nbz`OTW7IAd}vfU?z2g>4yF_elc=QO5~RQDrrO4 z*UP2{_66HyNh#GQ_dDBJd4Ni${jaY~O?>}`P8ie+68yf-2ZV|{Mj#Z``P>Z#cedHx zWJaJK^E;NZ1gT~?g4kv`Ue|-yGq}Y|?OIYAmy}%woO1|bpTFd0Q{l}9ydj8%Xx#SP z(?G!p&pktMsRxHXmKh4hc@ZIO(H;*U0#_6OZG|WuzGvKoY>Hz5%4v|qk8)MtILhbt z*~3?bTQLNbJf57>AgSUAKtZWk(ItxK>%E?+wDo>en~*AxU`bP%%EVHAtY9z8^p$0; zQ(4g-%)Feq9}li8LBkHXuL+)Y1C$Af-dh|YEILH)T==4tO!22)TIa`#{iz`gU6(7k>zXi9b?R5N&khsbGw)=T z8ZoL+i@Tymf-vC@C)g;V=SJG~cXJcWrs^H$2BB;Aj-6TY#Pq3uP~1}0($US3LDblu zovsrbD!mp-4)!-p^LL+}%qCqMF(JyE1T|tJOVt{qPN)&LDOp6o{hmVCvrfyFHg<8z_w(^IF>BB7#i`A72X zj}${I)n#t-s)>5d^P&FC=LbIYST@)@Wux_nGrC)T(;>;|?iR2|;okX2Gvm&wsps9J+@OyQnO-YIPprabh|tlN%CY{@A#ha~&t59YQam*%42KgvG*3KMV3<1V~Nu;>7*=i#JFO+ zd|$!Gtp!1C-Z`Z35wtC%G18z&lZBHX%*q__oKOx+^ z#O}H-cT<-m^Wh@(aEAKIM=i*a%0RDlu2(t{9;b}bahY_?kvML|{_54{1+;lx;qgzS zxt-eFcBG(lbTv%+wX@(RQZO(|j>+&nR-`%IZL_=MuW6~LGuRwMJ($6s(9|OzHS3N2 zl8t>VZ*>HCuTH7BL?gyTPT`uzE(ZP|P;O#l-utrf7pi5E{J{<(|Bbr4X#ea4c8?HlUi&Zbql+N}m{FeY;kxLyQG3c5I=i2M?cU@Bd6KwFBT;FVUgBk=S5b8<#Dm}S zWJzrd7BxxhB?LHOk8%R9Ir^>oZl>lcYBZz~+Ox*sIU}Mr-1%egz^b0lemyXF=MO`t z4j&!5RvP8}!M4U#Hd9@F_0HPzh!auq$KTy5?%sNAs?*o6ZF`__#}#i%yZyL$lRrCE zH}0Js3LL%s=Uaa{aP)F%RDV9)YpQLiYhrhDC{P|j{lC9{fBUPE0U!h3Ss|*;LnFeJ1j0o8dh@&cgCx@ZQSQKy?=pP5B?#Hwpjzn9GVyJNh61?TE15uKJyrZ-p+K`VKI>Y4Lq+q7ytkO diff --git a/tests/graphics/shaders/bin/dxil/compute_multi.dxil b/tests/graphics/shaders/bin/dxil/compute_multi.dxil deleted file mode 100644 index 10c03bedae8f4ee1d16e14dbe6d9e99601dc18cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3848 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 diff --git a/tests/graphics/shaders/bin/dxil/geometry_vert.dxil b/tests/graphics/shaders/bin/dxil/geometry_vert.dxil deleted file mode 100644 index 04dd6611ed5f061c90c02bce48aaeaefcf10cd3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3020 zcmeHJeN0=|6~E>^{On+!AJ|(BHt3nJx*|=CNsTE+!ZtAwOzVa$p&ckT2^lQl7)%+E zP4Tx4F^fl7VKu8vk|DZfDUftDS+yC%DnfzMC~ZK^QV5J>6G=UqRP9!6yU&I+`)8B3 zKekCb(mCh8^Lg)m@BZE`tWc`fPh{{veem)2ryuQP|G1}AiE(? zLe@g3kq&?da=E%h%z(BnDk(3@+65n|{4Kj^(+R`FcIuHv1wbm_e{g?IQ*%vgNg;Ut zALLTuNH_xk_NIop+GD1==DK4Bpe^4ownO_?@6C`$>aUQf8nEwH>qoxLsYK@6pszDf zahqP^Q50oU{9P^$6e0-v)x5Ss%l9ev@uC6H!3;GlR9I1>p$dj;LAz2FxFuu(kPmG! zRuV+PL=I%klKKP16k0+jB)Q!*J1ae!k&uj@tTq$7qmbSTn*IV00BXPao+WDOSV7cKtUW{x5t3S43G|2i zT6IbiK6gMt%}xumtOwps*^W8cu?4fA+Alz`nX#+v+?iNqSbc;nWf zb!*V5!>E9H`tKhLYbn6mby)K}eT~3cB9S^AR)|EdL6;wcF%3&Ntg~4mYd`l`Ik{2VLnSc~f*fDP^FFaf89COXE8cVFtr7Oj{5W?~V#}QkLzShDiLj zD&(z=DK)J~Y97{nBctemv$t@ULe|d={;{6nW(H|x1gpkojOBk_`RdSgq9_=Yq6xiE z{cPvZ*yUYUF6E3dgK=d9e#mO%a?nGIWaY0Re%x(s`WeZmRT zNakr@>2Z@Uo+z6NRjvmY)~8no(cMWBd2j9|@u=kTV9u!I7f;dlcCg-a>|kHmJ~ex< zYlmmYz1arCp84xkh0@GlmZtd5z)kbT%U_07rf=R|-SFSKcJuDqAbM!t!FsP|{pWLC z7c>UL9xpr$)V@uIql0VbxX*OcV8CYAf%V@;fjYvzY%SgHsX5#R5FTN~h8^r9D z5FXOv*~DbhEummRm=x3}9}#!ty=}{zSLI$pn!vMZ6MyjU<1gisrnXtU67fcHU zla{1uJ^e$kDtAhi+ZUE^O~`swGB=XfGqDpk{nDCu9myM>U`-0K?;4SIk*me*N_by| zf4)RtCGk5;^v?)1j@!=$ZWMt51wIM4<@TMU$UO6>@Ix>VE#uE>IEpR2DB0K9~B%nVlJ#l z(MXE9VR>$_;MR?weh>E^xKClFY!f@5g9r3+>?9w<&fU=WKZTw0e}bJ5jQ=~aQ}Y#e zo`aiCMzAyd@+k3dU}s0Q$hP6nbWk|T>>P1YsCg8^=ZOIdEgd6tKc&Mk>Q6q(aKrB5 zGh77qzl@z34E3mj$J*9n;-IQUG0DtQ)DFguOB5nBp8EG!4xazj`RUcW)1hv62BRn& zqGl{DOCfuWX&tF2hV&Ckxi+m#RjB#E8MqDMHTt2nSKa&Bnp7e4GlO~!@%?J6PRvI; zKN=<~21`B~jw>G%hNP?;SiL9_V*&p*zOTwxn)u?6_`mHThm_7c)dwKatKQ|y z3yzV+A6_kEdY(Ppy2DhfKU~vPcI-RmmnoxN-7 zCwsAnudJzaa?&GLr2pgGe;()bB)ogU@05cowo~^i2wk9gcYzeqZgUif)xb)+PozRy zDxC?eI&-Bh?djii>V4L)O{ke^0h0EPTM=a@d7^JNRe8nLUO+PF)2~z>;CgszfMKV4Uwyd-qwaDP{SB0_s7U|- diff --git a/tests/graphics/shaders/bin/dxil/texture_frag.dxil b/tests/graphics/shaders/bin/dxil/texture_frag.dxil deleted file mode 100644 index 8f83ca909778347761a106c79f518a6e8f56f742..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3820 zcmeHKYgAL&6+X!g_ufEqb0HbM5MXY2ReaR&kcWhsJOE*U8ib+R;xa)&SOpA^VF0IV zF4_Mn|Wp)IvpcT2!izgPmEcJvXAmxaOC?`oq1l z&)#Q$JA0qI?>T2D2`iPVlue0MnGZg$CW6*QoH=u!W&r>u2>>uCWsuV#AAvjtc?5zn zH~?9YGm}!JP`sp+%w=I3IAcS8VNaexnV86oE|`&w$eN`yxXW+GF*AFOdP8|(Md5}L zkd?SnwS4)C1jcdb8EIFvDve~SJKiLtX; z%;(4CJ~L&WkAnOv4ol{u7x`zVu6i&!$qX+aq*z;6@{ z8G<N>l&nOTagEEE6@v~P!tO<0+d#w?o2C4+XQs{59N2Y?mYJdCt!okECV zhQJ2J04D_{!(+Fx%)DSX+}oeCC08#>WGlCMDBH)0S>hy!(bgV-Pz0uO+qtZp_q3hwvIBT#pLV`zIlpK5xQ7f%P4OHZU;z#e#|oo zjT$ALhQrkXP)`G(f-*cHnM<$R#Ays@H^bq!xz#4}O51GpFt?|X1%V(Ki1NV%-mUo^ z2t7-iMaun@o?L;pw$z^gxYJ_$e!DF@_tBP{N&VDXa{jlxo$qP|l4lYp&%zC;P^#% zf?e-S=dgiLRMu^&&{(1hEY$@F)cJo_6U9!V297{bBgM+>SUHUq+lbN^O4SRcRD&@N zPW0i%7mPQ0bz5$LXWW|0rfP>9wyVoI1W0vMo@lJl9CQoP{x$5vP|P%!h6qo-(OLycIA92UgdqW352R@?*{xb z>f7v}MQ2Av2ixa2jCDEh^lW$Q>N<6K6H|u^>DGHIF2l^}T-bb=cg^&o2wd;$81u~+vEu7gG3Gw2Qjb+v zVdc%Gya^zgIAYiH8t)hU2YB{7{v(LWga{vFc=tPKVX# zkjg5Hj<$FYc@mR0=Cqbb1-GY&DK!y6I{a=)e1|1|y;}c#X?@&DQ=C&3djyf4G|9|J z+|ZP$QiE+Qz@iH*WpLD6bT*4lgH_JMDyQ9G*bnuVHMpgevXnJjs+$c9A50MsMu~5_ ziAgDvJJ9Mo-s(H#8b`FggA!kd!EaEDer1DqjViX;H6HJaX;Q`1A#qK8i(%65jd53z zxXwPFLxO#zLu%$(D)koc%PL}e6dk9DyQAn+l6VB~9Gl>wTJQwctCR-73(6##zw@E& zH0jx$V3tQLG`pqs-HH4CnV4=mO0eWvfALKanREK_v{$#xV{GoRV)ixNvx~P=8-Dt_@H*WADJe8k53Ubr047TZaa=D+_JQ55C5h- zC2&D`TZU{c$e~sMb?99pMAacptblt zTa%=(ykSAh#!nl?3tC#d)E_Y4y)yV<+ra*Nz4r$9bF%%yWjn*8mv+fIjzvbF=n7Sc z-}He0mmZ*{0hkZZfRLkD$Q%nd$WM|$T~jYle(o*hSVkzzCj#06Q7$lQK;b5ncA!qd z*3*={#WQbJc&-i5IC^${k&oF*1p(Y>V4>Ktx6ak|AkZiB?+Tt$E%N=NsEx~#?xs0y iT$6OSocBDMzKJD5wK~t)v(6u38t!b&=EnR30pNe?exyYJ diff --git a/tests/graphics/shaders/bin/dxil/texture_vert.dxil b/tests/graphics/shaders/bin/dxil/texture_vert.dxil deleted file mode 100644 index fff537a1e2b8f0689f5a4ca00e56003087bca66e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3104 zcmeHJeNa=`6@STl_3C;@$8&`@U(gaG<$rngWTp|gUwlbTr;G$z?bAI=nymR0Cy{D~LYj`ie!)>-vSl@p9`+dUAqvaF`f(Ql#p+L*QFn}=* z1{VaLfw4dX8VpmFPK*J6N_3`OCHujG3P#FboeBaCuiJ3S0PDTa#mU;KxUt5hGwW(z zhRl`qnwpwgEr`{C8Wy1cU5&(E5F;fssS>k!gH4uB;K22fV%qnL@rdi-(St|q8_PgO z(?0PX5HACR#6K^82SWO(RPy)FBG|CpO4|Q=AzxgP&3e#ILQ*yG4K@W*Cwi7n0)S8` z$#rr??$N?90zvF`MMeDd>LLM(QC2>>d8N$iX%E2E-CM)_!$Lh7;g*mR-+rQq^kQf)P7vTDZ{w>bcs4x z9p(_4s^B{iPoiF`W`(ozW{j%6p3poDpfP+OSg zOd0Jd!)ZZDz&!0Y8(?ipw9|qfou@71Xj>9#VSx-un$4w%x+S9TOp1_q`+@D1 zh>%}S;4ut=+}8oV1N81ypmShDxQfc2DIsEfjpwBP{fu+l^^_jx4X4L>v1iIdQEiJ} zyg1S`bz(xdh$C#IF+$)oG%F#+5Y?33?p1R5-LS9_qmEM+#Q2AkLW`8)yKTTvy{1_W zw`AyD`P8-2LG9qPrBan>fUcf6j0NfHDFcqZ>T@*kUr?VO>&+?hP6v&ftW1SMmu0J` z*+ySFG)_zZglOUqZTtR?v8&fge|$xDm9GA|0Z)I;s}%7484PKWR@QM>b{yG6s@jda?{VUT8E3-=%kjh+%e5m}2 zcv5ohf^1Uq!)=t>9>zyq#hI6j;y0i46^DwS+_c$u&)*?4=(qnwpBEhk?Tlv2Uk6!c z?|ruPbol=5d!H>|K$_>f7#}sSymzbbvcYcOJx<={i8CR2bSLH(%sdnv;7}AnO_@Iy zQoGTPcGMMdGM1stCphbwo3)dn-ZDLvduv2+K%AC<`S^3NBCb({V8vW}=%@odhM^tR z0fz(abii%x0S6J_&1JDx!mNklOuIPq(JE`z$l8g|3TAh}5e_&kXqyOa`(qkN`-VI43Knp31FexjN5oU~ z`6}!42duU0tQ9fb7#|TVjR@uv^F6CzRw$V9>6Pz#C&|XT&34a%b9=nUCjLtDs*_0&oz} zFNm2#zmxy%*N|^PerIX(RU7rL<4?C9=})q=L|;`TJP-mCOaM(twaQe@S+{w|j=y)P zVR&Nnx1AsV)%xZQlJB;rCHYSW9=whG#{m8m|0%!ZzyBTot)C50{|W!$&+}hzqsaGk z_@$mKcb>?n9?s1u2`Rx>N8+tc^4}hi_`l}ALQFfM;xf|PTx?`|K}^s~RP|?=QxX*p zWs@&#?eN(P{bT)S&lF;n62N>+N{LEzicWPN#zlu>YPoT1WlXExl=W`jrIGKwxNVgA zp+j|o!~7Vp<0Bc5B+YASYto^rp+783Ria3O`LHIR@^wI%K4}lXEbpnbD3(@vyVRgD z+wiZ87sO3g=&&ef7Xunj=SLf&`kZfmm;b8)VocrrY2!BvWn`uT;&k}owS}&U#lahU z=%KGQwHLcutWC|WdyX_UA2xZct^+?bLFW zOjdxyU-H!dlc%f%1Qmk&l#Qs0$Zsz|J&?ITSqdA|yOcYtATJSoGavZ!X>`bIu^4@v zulzKqqPht#cT?Oef*Q=Gwa5;v_uY eWgavo;gnWk-Cb@99;{Q$q~MKpvu;or$UgvQ#eGHq diff --git a/tests/graphics/shaders/bin/dxil/triangle_frag.dxil b/tests/graphics/shaders/bin/dxil/triangle_frag.dxil deleted file mode 100644 index 6759c8c822c623dac3d0d1b35e9856eb5bc7d48c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2964 zcmeHJeN0=|6~Fd-@q5Ph1~h#0w;-4AKOJD(Ya1l(K$^uS5=|8CY}!LNX``B^66iM5;`h*4<~DD66Xd zF=_j&M?UwQd(Q8kd*3RfI+E-Y=Arf zc@1(8bT)FJA97)Kt^$X)P0B5NBc&8h*pN5vIbkOg6A9~)VabT17j(wY;3C6-!r~(Z zC+m*aA3s?Gbo&hZ4nW^NxW}F_ZgUSgoHL|>{QW&(j3QI*&noMoub{A4aSh5e$Uj8i zL1OG|7W4aeVsf!bd`1Z!sM>VACU|DXL^4B|SU`^;Xy|zu6N{w>2$PsFK|i^9)=e8D znSB`;TpG+_VG&(41t&&0-vgccl3W7=V)ptF+O@jj`!aZ-ozTX!Q^B=D=)-J@XK6p0 z%OREN?JOrhX$u|`kDe*Fl38qRJ5TE*m7+9UoEM?gx^uiDN|)`v0%DZf2RVc{Dq*~U z-f#0PIUcs5vTV+NF#xdKK;l_sQiN&PR|U>>Mnx#*yt&ZNoLOi$YAGmN;lPwonSgVt ziqoht;j$AB%g$b}DB9rm@SIKqsYnD#pe@Fl&Q^3LYT8otMfzesbt!h#W-Ws2g`(PF zSH01ts&X||Ay60mu7IeXBAVd{BAXRhZ4XvQVbxy3vZ*v~Di$Ng0H!#PUVt@dux2Ax zKgC%gv4#-RNWcgoRv3)NkU7PI6nO8Kwb<>>qEa)%a9?d;yTJQ}{dRt*(=Wtw3Aj=;6C zh{2o97LKP-V-lV1T;3me@9oTEwOVdlY?l7k5gUu%(beDI+d6V~Fn5kbg=l#vMUHb! zlnO^_R!xmvBa*ZrvSge+z?xN%pZ#8DRPh}F1G%+Ix9+Xt<<%`KE1zz8s_Mw@_;y7_ z%Y9t!;0fH#)s7g*wqs-39O1#kj;vB}ruXH(m;1TeB?E~cwQHmj=dbP#@aO6e&Km`X zZqUQ(|}oMRrX6>Dn5>N+j_6%hG1lGv~kyZPGq(UG`2z0zZfEkT$=GKpmR zb(tO{bF$G>Z^qunv8EiC*^D)tk%mT>nR3NUMiFaXVo4EMqljEyC)Nvy-Q;-OeVKGt z7B^~&Kc;BS_}Gy#rAxn#s6Te7ok+&yx~Rd3yah3Z&fMD}B%_oeYi(Ch3GsI&O=bFme9u)usD& z>7Bvx!?84%~m-1C0&y`H!DLeJa#W6%5F^}KLx zp!knHkGTtfsOPnn%NyckR=j`zwLf!2N|}JWB~Xoq&}>%g@73ccR3NwOu~m ziANYyHpVx$@1^AzxoivUbQKP3rR4mGUH&Mx&lXVOU)-vg`1;H%hR4@DHTHru$<|8_ zb!%+0J)lDW+G0Zxqi#CQ1i-=B*|qu7fPZ3PwGX9VQmVIoq#PQ$o_b>kYud^G)6G{s zpMPMedDA!}8>_pZ<0bAq_w(k&okzQ(x1aK_m#zgS9=H4ZR!3JS`p~>MrMg3z`udRi z>Ww|Ae;nFD!%Tr6d(;21H<>5^;$hB(D7}lhoDs@q9_TfAd$lbcB9dtM`dGf znr)@T;v!iVJEhzUD4dgBX*h7eBi;^hyUi3gGb0YcttFhSl<^RpI#2JvsR+T{l?5{i PAvmi%M)VL3{iFRCNvU(F diff --git a/tests/graphics/shaders/bin/dxil/triangle_vert.dxil b/tests/graphics/shaders/bin/dxil/triangle_vert.dxil deleted file mode 100644 index 31548d572a0e4c0e5b3770d5f8beb4942f4f4c3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3144 zcmeHJeN0=|6~Fc~em2g6eOmSj|(JodE#VMJ9*uV(T zN%I#x18!$15C>KYS=vE0sjy~Boi!3)Lnfn@$!G!@>B2%tSG66g!qlnLw)<=xrB$>) zCT)N9$mia3@A;i`?>pD`_nxj&qrJTK+WqI!@Yh|x%~}5Hh~Ov%08qjL0EN90suAk1 zpkmOm33Y`Iz&2E~-XLYb`GgqEPs=LdfC@D+Uy^Xb9@({#gaOCLzTqd=M#+Vtn99ut zi=q4(pe;9+9|xcu=06GNAD5quOQcODgLlP}FknymNnFBju6W*brs;I^=`#(9C4k9X zAzgx)!d)!vz9#>ILgt`S$=}x{BH@yDpII^7W82MNKTlKDuX08MO<$?+ke zP_z%9Del)H2rV8H8&h-uft!f!XE%oI$ecJ-6;x8p7PaML7-xgXryy8YX)uyOBrXc) zHQMQq#PGaja4yAz$Lh<4KGdDltB%kNbWE=3qxe|4Nen?2t*6?B9i?jeQZznH&MRc_ zOOxdqe@T#sYxVv&fIzOIVromy~1sn35V_=U__x626QxxB_{qS;2|*Ai{D2(;O6n>h7RPCINtYP%F|97UUO zv_8mjCXCjE;k2P7AWHwsBd`_~+HOOeqx3BdZHXgo9GD@F+=8xA6k_V{aA2O@46zyQ z$ioW(K&O(9k>!sGs|~{eJcF1-s1!CdXplL6p^C^-}xrF#a^2%`u zixqL6JuR7y;FuYjK-x^hj473UWMl~XzH1U29Js->_o(Q4C*9hRf_%o*J4{f z%X{634c2P6gS9E8O*zz^!vng32b+i0k`Pm~T*vS;H5*2Z@q*W36=rCL#=A2QcxEeE z#j;{U8P@%xMn4TwUS`W6^8=K&bH&ZV#1tUFH{;>7@ zdjIISw)4K6$k12h-F%?0Sjf*+J<+=nj^3LYND7CqE_W=yaW(vY8FT0s6v_V$r;N&$TN0ji6Q$(JDf*_T9O{ zer=&2De9kl5-$1=PtgieG&vWDh|!-okVcGXav- z4eRB^As@j$L&`q)SLHwd47{t#mCf&7uBU$J`1=QUOJC)tNsbi9W&jPr$*U8S61BMm zUWu5jN4bXE7dyJoUMkCaG40B`B=?z;;#_Efm+(<8EQIq3E-d|)3;%aqxO+CR`;S}* zUrCSU!tQE`w^5S%SRy2OupGwy*F2cV&`qiNtmKv^E^T&IiZf;E$`SUAT#bQr^3|;y z9eJ~Fyl>>^d5jLZS~AF{$VeWfI_ogWkLEN=)83Li&23ydZUhpoerrN3+dt=#|8hf4Da}hFCkM+4VYx)|`%D1ld+a@6C9pBRLJBRKJZs`jO za&d$_8nTAp^40%`uc~kWo`f~$($ojY?=eV0z>=#vjF^%;REMZiJ@DZEp8}9WX9ADS zW|`aj{onc3R2R outBuffer1 : register(u0, space0); // set 0 -RWStructuredBuffer outBuffer2 : register(u1, space0); // set 0 - -RWStructuredBuffer outBuffer3 : register(u0, space1); // set 1 +// some use index 0 and so use index 1. +RWStructuredBuffer outBuffers[2] : register(u0, space0); // set 0 +RWStructuredBuffer outBuffer : register(u0, space1); // set 1 [numthreads(16, 16, 1)] void main(uint3 id : SV_DispatchThreadID) @@ -24,7 +22,7 @@ void main(uint3 id : SV_DispatchThreadID) } uint index = id.y * width + id.x; - outBuffer1[index] = bufferColor1; - outBuffer2[index] = bufferColor2; - outBuffer3[index] = bufferColor3; + outBuffers[0][index] = bufferColor1; + outBuffers[1][index] = bufferColor2; + outBuffer[index] = bufferColor3; } diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index d39d555e..792e48c6 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -205,7 +205,7 @@ bool textureTest() } if (hasGraphicsQueue) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 + // We want an adapter that supports spirv 1.0 or dxbc 5.1 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -222,9 +222,9 @@ bool textureTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { break; } } @@ -861,9 +861,9 @@ bool textureTest() sources[0] = "graphics/shaders/bin/spirv/texture_vert.spv"; sources[1] = "graphics/shaders/bin/spirv/texture_frag.spv"; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - sources[0] = "graphics/shaders/bin/dxil/texture_vert.dxil"; - sources[1] = "graphics/shaders/bin/dxil/texture_frag.dxil"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + sources[0] = "graphics/shaders/bin/dxbc/texture_vert.dxbc"; + sources[1] = "graphics/shaders/bin/dxbc/texture_frag.dxbc"; } tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 7deda986..6cbdfa9c 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -171,7 +171,7 @@ bool triangleTest() } if (hasGraphicsQueue) { - // We want an adapter that supports spirv 1.0 or dxil 6.0 + // We want an adapter that supports spirv 1.0 or dxbc 5.1 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -188,9 +188,9 @@ bool triangleTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { break; } } @@ -564,9 +564,9 @@ bool triangleTest() sources[0] = "graphics/shaders/bin/spirv/triangle_vert.spv"; sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - sources[0] = "graphics/shaders/bin/dxil/triangle_vert.dxil"; - sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + sources[0] = "graphics/shaders/bin/dxbc/triangle_vert.dxbc"; + sources[1] = "graphics/shaders/bin/dxbc/triangle_frag.dxbc"; } tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; diff --git a/tests/tests_main.c b/tests/tests_main.c index 16d6ef5b..231ff1a0 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,7 +57,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest, "Graphics Test"); + // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); @@ -69,7 +69,7 @@ int main(int argc, char** argv) // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); - // registerTest(indirectDrawTest, "Indirect Draw Test"); + registerTest(indirectDrawTest, "Indirect Draw Test"); // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // From 057c84bf0b101ddf4bbac44c9f9bcd3aff48a825 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 18 May 2026 17:30:30 +0000 Subject: [PATCH 223/372] make cmd disptach indirect feature bit explicit --- include/pal/pal_graphics.h | 28 ++++++------------- src/graphics/pal_d3d12.c | 28 ++++++++++--------- src/graphics/pal_vulkan.c | 3 +- tests/graphics/descriptor_indexing_test.c | 2 ++ .../shaders/src/glsl/descriptor_indexing.glsl | 1 + .../shaders/src/hlsl/descriptor_indexing.hlsl | 0 6 files changed, 29 insertions(+), 33 deletions(-) create mode 100644 tests/graphics/shaders/src/hlsl/descriptor_indexing.hlsl diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index a714fdac..353b0bc5 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -605,10 +605,11 @@ typedef enum { PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(27), PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(28), PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(29), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH = PAL_BIT64(31), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT = PAL_BIT64(32), - PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(33) + PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH = PAL_BIT64(30), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(31), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH = PAL_BIT64(32), + PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT = PAL_BIT64(33), + PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(34) } PalAdapterFeatures; /** @@ -5158,9 +5159,6 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if - * `PAL_SHADER_STAGE_COMPUTE` will be used. - * * `PAL_ADAPTER_FEATURE_GEOMETRY_SHADER` must be supported and enabled by the device if * `PAL_SHADER_STAGE_GEOMETRY` will be used. * @@ -6377,9 +6375,6 @@ PAL_API PalResult PAL_CALL palCmdBufferBarrier( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] groupCountX Number of compute shader groups to dispatch on the x axis. * @param[in] groupCountY Number of compute shader groups to dispatch on the y axis. @@ -6407,9 +6402,8 @@ PAL_API PalResult PAL_CALL palCmdDispatch( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` and `PAL_ADAPTER_FEATURE_DISPATCH_BASE` must be supported - * and enabled by the device if not, this function will fail and return - * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_DISPATCH_BASE` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] baseGroupX Base group offset on the x axis. @@ -6444,9 +6438,8 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported - * and enabled by the device if not, this function will fail and return - * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH` must be supported and enabled by the device if not, this + * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be nullptr. @@ -7323,9 +7316,6 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_COMPUTE_SHADER` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * * @param[in] device Device that creates the compute pipeline. * @param[in] info Pointer to a PalComputePipelineCreateInfo struct that specifies parameters. * Must not be nullptr. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 4049d98b..13d93a89 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2541,6 +2541,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE; features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; features |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; @@ -2756,16 +2757,16 @@ PalResult PAL_CALL createDeviceD3D12( } if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW) { - // disptach indexed - argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; - signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS); + // draw indexed + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; + signatureDesc.ByteStride = sizeof(D3D12_DRAW_INDEXED_ARGUMENTS); result = device->handle->lpVtbl->CreateCommandSignature( device->handle, &signatureDesc, nullptr, &IID_CommandSignature, - (void**)&device->dispatchSignature); + (void**)&device->drawIndexedSignature); if (FAILED(result)) { if (result == E_OUTOFMEMORY) { @@ -2774,16 +2775,16 @@ PalResult PAL_CALL createDeviceD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - // draw indexed - argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; - signatureDesc.ByteStride = sizeof(D3D12_DRAW_INDEXED_ARGUMENTS); + // draw + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; + signatureDesc.ByteStride = sizeof(D3D12_DRAW_ARGUMENTS); result = device->handle->lpVtbl->CreateCommandSignature( device->handle, &signatureDesc, nullptr, &IID_CommandSignature, - (void**)&device->drawIndexedSignature); + (void**)&device->drawSignature); if (FAILED(result)) { if (result == E_OUTOFMEMORY) { @@ -2791,17 +2792,18 @@ PalResult PAL_CALL createDeviceD3D12( } return PAL_RESULT_PLATFORM_FAILURE; } + } - // draw - argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; - signatureDesc.ByteStride = sizeof(D3D12_DRAW_ARGUMENTS); + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH) { + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; + signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS); result = device->handle->lpVtbl->CreateCommandSignature( device->handle, &signatureDesc, nullptr, &IID_CommandSignature, - (void**)&device->drawSignature); + (void**)&device->dispatchSignature); if (FAILED(result)) { if (result == E_OUTOFMEMORY) { @@ -5970,7 +5972,7 @@ PalResult PAL_CALL cmdDispatchIndirectD3D12( CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; Buffer* d3dBuffer = (Buffer*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index f3c9b052..07463b75 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3896,6 +3896,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH; palFree(s_Vk.allocator, extensionProps); return adapterFeatures; @@ -7708,7 +7709,7 @@ PalResult PAL_CALL cmdDispatchIndirectVk( { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index ecfa74d1..233e9f57 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -4,6 +4,8 @@ #include "pal/pal_system.h" #include "tests.h" +// TODO: test on vulkan first + #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define MAX_FRAMES_IN_FLIGHT 2 diff --git a/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl b/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl index 72caa6f1..caf8c59a 100644 --- a/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl +++ b/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl @@ -1,6 +1,7 @@ #version 450 +// texs[]; if runtime descriptor array is supported but for this example we wont use it layout(set = 0, binding = 0) uniform texture2D texs[4]; layout(set = 0, binding = 1) uniform sampler samp; diff --git a/tests/graphics/shaders/src/hlsl/descriptor_indexing.hlsl b/tests/graphics/shaders/src/hlsl/descriptor_indexing.hlsl new file mode 100644 index 00000000..e69de29b From c2dca91139f694cb209373f1350f5ad47067f8e3 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 20 May 2026 00:40:28 +0000 Subject: [PATCH 224/372] make API cleaner vulkan --- include/pal/pal_graphics.h | 185 ++++++++++------- src/graphics/pal_vulkan.c | 223 ++++++++++++--------- tests/graphics/compute_test.c | 6 +- tests/graphics/graphics_test.c | 205 +++++++++---------- tests/graphics/multi_descriptor_set_test.c | 8 +- tests/tests_main.c | 4 +- 6 files changed, 344 insertions(+), 287 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 353b0bc5..921fe6ba 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1445,8 +1445,23 @@ typedef struct { } PalAdapterInfo; /** - * @struct PalAdapterCapabilities - * @brief Capabilities of an adapter (GPU). + * @struct PalImageCapabilities + * @brief Image capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 maxWidth; + Uint32 maxHeight; + Uint32 maxDepth; + Uint32 maxArrayLayers; + Uint32 maxMipLevels; +} PalImageCapabilities; + +/** + * @struct PalResourceCapabilities + * @brief Resource capabilities of an adapter (GPU). * * @since 1.4 * @ingroup pal_graphics @@ -1456,14 +1471,59 @@ typedef struct { bool storageImageDynamicArrayIndexing; bool storageBufferDynamicArrayIndexing; bool uniformBufferDynamicArrayIndexing; - Uint32 maxComputeQueues; /**< Number of compute queues that can be created.*/ - Uint32 maxGraphicsQueues; /**< Number of graphics queues that can be created.*/ - Uint32 maxCopyQueues; /**< Number of copy queues that can be created.*/ - Uint32 maxImageWidth; - Uint32 maxImageHeight; - Uint32 maxImageDepth; - Uint32 maxImageArrayLayers; - Uint32 maxImageMipLevels; + Uint32 maxPerStageSampledImages; + Uint32 maxPerSetSampledImages; + Uint32 maxPerStageStorageImages; + Uint32 maxPerSetStorageImages; + Uint32 maxPerStageSamplers; + Uint32 maxPerSetSamplers; + Uint32 maxPerStageStorageBuffers; + Uint32 maxPerSetStorageBuffers; + Uint32 maxPerStageUniformBuffers; + Uint32 maxPerSetUniformBuffers; + Uint32 maxPerStageAccelerationStructure; + Uint32 maxPerSetAccelerationStructure; + Uint32 maxBoundSets; +} PalResourceCapabilities; + +/** + * @struct PalComputeCapabilities + * @brief Compute capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 maxWorkGroupInvocations; + Uint32 maxWorkGroupCount[3]; + Uint32 maxWorkGroupSize[3]; +} PalComputeCapabilities; + +/** + * @struct PalViewportCapabilities + * @brief Viewport capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 maxWidth; + Uint32 maxHeight; + float minBoundsRange; + float maxBoundsRange; +} PalViewportCapabilities; + +/** + * @struct PalAdapterCapabilities + * @brief Capabilities of an adapter (GPU). + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 maxComputeQueues; + Uint32 maxGraphicsQueues; + Uint32 maxCopyQueues; Uint32 maxColorAttachments; Uint32 maxUniformBufferSize; Uint32 maxStorageBufferSize; @@ -1471,20 +1531,10 @@ typedef struct { Uint32 maxVertexLayouts; Uint32 maxVertexAttributes; Uint32 maxTessellationPatchPoint; - Uint32 maxPerStageDescriptorSampledImages; - Uint32 maxDescriptorSetSampledImages; - Uint32 maxPerStageDescriptorStorageImages; - Uint32 maxDescriptorSetStorageImages; - Uint32 maxPerStageDescriptorSamplers; - Uint32 maxDescriptorSetSamplers; - Uint32 maxPerStageDescriptorStorageBuffers; - Uint32 maxDescriptorSetStorageBuffers; - Uint32 maxPerStageDescriptorUniformBuffers; - Uint32 maxDescriptorSetUniformBuffers; - Uint32 maxBoundDescriptorSets; - Uint32 maxComputeWorkGroupInvocations; /**< Max compute threads per workgroup across all axis.*/ - Uint32 maxComputeWorkGroupCount[3]; /**< Max compute workgroups per axis.*/ - Uint32 maxComputeWorkGroupSize[3]; /**< Max compute threads per workgroup per axis.*/ + PalViewportCapabilities viewportCaps; + PalImageCapabilities imageCaps; + PalResourceCapabilities resourceCaps; + PalComputeCapabilities computeCaps; } PalAdapterCapabilities; /** @@ -1506,7 +1556,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxMultiViews; + Uint32 maxViewCount; } PalMultiViewCapabilities; /** @@ -1517,7 +1567,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxViewports; + Uint32 maxCount; } PalMultiViewportCapabilities; /** @@ -1528,16 +1578,15 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - /** If false, depth and stencil resolve modes must be the same.*/ - bool independentDepthStencilResolve; + bool independentResolve; /**< If false, depth and stencil resolve modes must be the same.*/ /** Bool array of supported depth resolve modes. - * (eg. depthResolveModes[`PAL_RESOLVE_MODE_SAMPLE_ZERO`]).*/ - bool depthResolveModes[PAL_MAX_RESOLVE_MODES]; + * (eg. depthResolves[`PAL_RESOLVE_MODE_SAMPLE_ZERO`]).*/ + bool depthResolves[PAL_MAX_RESOLVE_MODES]; /** Bool array of supported stencil resolve modes. - * (eg. stencilResolveModes[`PAL_RESOLVE_MODE_SAMPLE_ZERO`]).*/ - bool stencilResolveModes[PAL_MAX_RESOLVE_MODES]; + * (eg. stencilResolves[`PAL_RESOLVE_MODE_SAMPLE_ZERO`]).*/ + bool stencilResolves[PAL_MAX_RESOLVE_MODES]; } PalDepthStencilCapabilities; /** @@ -1569,12 +1618,12 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxMeshOutputPrimitives; /**< Max mesh primitives per workgroup.*/ - Uint32 maxMeshOutputVertices; /**< Max mesh vertices per workgroup.*/ - Uint32 maxTaskWorkGroupInvocations; /**< Max task threads per workgroup.*/ - Uint32 maxMeshWorkGroupInvocations; /**< Max mesh threads per workgroup.*/ - Uint32 maxTaskWorkGroupCount[3]; /**< Max task workgroups per axis.*/ - Uint32 maxMeshWorkGroupCount[3]; /**< Max mesh workgroups per axis.*/ + Uint32 maxOutputPrimitives; + Uint32 maxOutputVertices; + Uint32 maxWorkGroupInvocations; + Uint32 maxTaskWorkGroupInvocations; + Uint32 maxWorkGroupCount[3]; + Uint32 maxTaskWorkGroupCount[3]; } PalMeshShaderCapabilities; /** @@ -1586,14 +1635,12 @@ typedef struct { */ typedef struct { Uint32 maxRecursionDepth; - Uint32 maxHitAttributeSize; /**< Max memory per intersection attributes.*/ + Uint32 maxHitAttributeSize; Uint32 maxInstanceCount; Uint32 maxPrimitiveCount; Uint32 maxGeometryCount; - Uint32 maxPayloadSize; /**< Max memory per ray.*/ + Uint32 maxPayloadSize; Uint32 maxDispatchInvocations; - Uint32 maxDescriptorSetAccelerationStructures; - Uint32 maxDescriptorSetBindlessAccelerationStructures; } PalRayTracingCapabilities; /** @@ -1604,19 +1651,6 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - /** Allows descriptor array whose size is not fixed at compiled time. - * The size will be provided at runtime.*/ - bool runtimeDescriptorArray; - - /** Allows a descriptor set to specify the number of descriptors in a descriptor set - * layout. This is only valid for one binding per descriptor set layout and it must be the - * last binding in the descriptor set layput.*/ - bool variableDescriptorCount; - - /** Allows a descriptor set to contain descriptors that are not initialized. Shader reading - * an uninitialized descriptor is still undefined behavior.*/ - bool partiallyBoundDescriptors; - bool sampledImageNonUniformIndexing; bool sampledImageUpdateAfterBind; bool storageImageNonUniformIndexing; @@ -1625,16 +1659,18 @@ typedef struct { bool storageBufferUpdateAfterBind; bool uniformBufferNonUniformIndexing; bool uniformBufferUpdateAfterBind; - Uint32 maxPerStageBindlessDescriptorSampledImages; - Uint32 maxDescriptorSetBindlessSampledImages; - Uint32 maxPerStageBindlessDescriptorStorageImages; - Uint32 maxDescriptorSetBindlessStorageImages; - Uint32 maxPerStageBindlessDescriptorSamplers; - Uint32 maxDescriptorSetBindlessSamplers; - Uint32 maxPerStageBindlessDescriptorStorageBuffers; - Uint32 maxDescriptorSetBindlessStorageBuffers; - Uint32 maxPerStageBindlessDescriptorUniformBuffers; - Uint32 maxDescriptorSetBindlessUniformBuffers; + Uint32 maxPerStageSampledImages; + Uint32 maxPerSetSampledImages; + Uint32 maxPerStageStorageImages; + Uint32 maxPerSetStorageImages; + Uint32 maxPerStageSamplers; + Uint32 maxPerSetSamplers; + Uint32 maxPerStageStorageBuffers; + Uint32 maxPerSetStorageBuffers; + Uint32 maxPerStageUniformBuffers; + Uint32 maxPerSetUniformBuffers; + Uint32 maxPerStageAccelerationStructure; + Uint32 maxPerSetAccelerationStructure; } PalDescriptorIndexingCapabilities; /** @@ -1683,16 +1719,16 @@ typedef struct { /** * @struct PalFormatInfo - * @brief Information about a format. This includes the supported image, image view usages and - * sample count from the provided format. + * @brief Information about a format. This includes the supported image usages and maximum sample + * count from the provided format. * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - PalFormat format; /**< The format.*/ - PalImageUsages usages; /**< Supported image usages of the format.*/ - PalSampleCount maxSampleCount; /**< Supported multisample count.*/ + PalFormat format; + PalImageUsages usages; + PalSampleCount sampleCount; /**< Maximum supported multisample count.*/ } PalFormatInfo; /** @@ -4596,9 +4632,9 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); * * The graphics system must be initialized before this call. * - * This function returns the supported format with the supported image and image view usages + * This function returns the supported format with the supported image usages * associated with the format. This is a handy way of selecting a format based on the image - * or image view usages. Use palIsFormatSupported() to check for a specific format. + * usages. Use palIsFormatSupported() to check for a specific format. * * Call this function first with PalFormatInfo array set to nullptr to get the number of formats. * Allocate memory for the PalFormatInfo array and passed in the count and the allocated array. If @@ -4631,9 +4667,8 @@ PAL_API PalResult PAL_CALL palEnumerateFormats( * The graphics system must be initialized before this call. * * This is much faster than enumerating all the formats to pick one. You directly check support - * for the format you want to use. Call palQueryFormatImageUsages() and - * palQueryFormatImageViewUsages() to check for supported image and image view usages respectively - * if format is supported. + * for the format you want to use. Call palQueryFormatImageUsages() to check for supported image + * usages if format is supported. * * @param[in] adapter Adapter to query format on. * @param[in] format Format to query support for. diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 07463b75..63962b95 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3472,33 +3472,21 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( s_Vk.getPhysicalDeviceProperties(phyDevice, &props); VkPhysicalDeviceLimits* limits = &props.limits; - VkPhysicalDeviceFeatures features = {0}; - s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); + VkPhysicalDeviceFeatures fts = {0}; + s_Vk.getPhysicalDeviceFeatures(phyDevice, &fts); - caps->maxColorAttachments = limits->maxColorAttachments; - caps->maxImageWidth = limits->maxImageDimension2D; - caps->maxImageHeight = limits->maxImageDimension2D; - caps->maxImageDepth = limits->maxImageDimension3D; - caps->maxImageArrayLayers = limits->maxImageArrayLayers; + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - caps->maxUniformBufferSize = limits->maxUniformBufferRange; - caps->maxStorageBufferSize = limits->maxStorageBufferRange; - caps->maxPushConstantSize = limits->maxPushConstantsSize; + VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; + accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; + properties2.pNext = &accProps; + s_Vk.getPhysicalDeviceProperties2(phyDevice, &properties2); - // vulkan does not give this but we calculate from the max width and width - Uint32 a = caps->maxImageWidth; - Uint32 b = caps->maxImageHeight; - Uint32 c = caps->maxImageDepth; - - Uint32 tmp = a > b ? a : b; - Uint32 size = tmp > c ? tmp : c; - Uint32 levels = 0; - while (size > 0) { - // divide by two - size = size / 2; - levels++; - } - caps->maxImageMipLevels = levels; + PalViewportCapabilities* viewportCaps = &caps->viewportCaps; + PalImageCapabilities* imageCaps = &caps->imageCaps; + PalResourceCapabilities* resourceCaps = &caps->resourceCaps; + PalComputeCapabilities* computeCaps = &caps->computeCaps; // get supported queue commands Uint32 count = 0; @@ -3526,36 +3514,74 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( } } + caps->maxColorAttachments = limits->maxColorAttachments; + caps->maxUniformBufferSize = limits->maxUniformBufferRange; + caps->maxStorageBufferSize = limits->maxStorageBufferRange; + caps->maxPushConstantSize = limits->maxPushConstantsSize; + caps->maxVertexLayouts = limits->maxVertexInputBindings; caps->maxVertexAttributes = limits->maxVertexInputAttributes; caps->maxTessellationPatchPoint = limits->maxTessellationPatchSize; - caps->maxPerStageDescriptorSampledImages = limits->maxPerStageDescriptorSampledImages; - caps->maxDescriptorSetSampledImages = limits->maxDescriptorSetSampledImages; - caps->maxPerStageDescriptorStorageImages = limits->maxPerStageDescriptorStorageImages; - caps->maxDescriptorSetStorageImages = limits->maxDescriptorSetStorageImages; - - caps->maxPerStageDescriptorSamplers = limits->maxPerStageDescriptorSamplers; - caps->maxDescriptorSetSamplers = limits->maxDescriptorSetSamplers; - caps->maxPerStageDescriptorStorageBuffers = limits->maxPerStageDescriptorStorageBuffers; - caps->maxDescriptorSetStorageBuffers = limits->maxDescriptorSetStorageBuffers; - - caps->maxPerStageDescriptorUniformBuffers = limits->maxPerStageDescriptorUniformBuffers; - caps->maxDescriptorSetUniformBuffers = limits->maxDescriptorSetUniformBuffers; - caps->maxBoundDescriptorSets = limits->maxBoundDescriptorSets; - - caps->maxComputeWorkGroupInvocations = limits->maxComputeWorkGroupInvocations; - caps->maxComputeWorkGroupCount[0] = limits->maxComputeWorkGroupCount[0]; - caps->maxComputeWorkGroupCount[1] = limits->maxComputeWorkGroupCount[1]; - caps->maxComputeWorkGroupCount[2] = limits->maxComputeWorkGroupCount[2]; - caps->maxComputeWorkGroupSize[0] = limits->maxComputeWorkGroupSize[0]; - caps->maxComputeWorkGroupSize[1] = limits->maxComputeWorkGroupSize[1]; - caps->maxComputeWorkGroupSize[2] = limits->maxComputeWorkGroupSize[2]; - - caps->sampledImageDynamicArrayIndexing = features.shaderSampledImageArrayDynamicIndexing; - caps->storageImageDynamicArrayIndexing = features.shaderStorageImageArrayDynamicIndexing; - caps->storageBufferDynamicArrayIndexing = features.shaderStorageBufferArrayDynamicIndexing; - caps->uniformBufferDynamicArrayIndexing = features.shaderUniformBufferArrayDynamicIndexing; + // viewport limits + viewportCaps->maxWidth = limits->maxViewportDimensions[0]; + viewportCaps->maxHeight = limits->maxViewportDimensions[1]; + viewportCaps->minBoundsRange = limits->viewportBoundsRange[0]; + viewportCaps->maxBoundsRange = limits->viewportBoundsRange[1]; + + // image limits + imageCaps->maxWidth = limits->maxImageDimension2D; + imageCaps->maxHeight = limits->maxImageDimension2D; + imageCaps->maxDepth = limits->maxImageDimension3D; + imageCaps->maxArrayLayers = limits->maxImageArrayLayers; + + // vulkan does not give this but we calculate from the max width and width + Uint32 a = imageCaps->maxWidth; + Uint32 b = imageCaps->maxHeight; + Uint32 c = imageCaps->maxDepth; + + Uint32 tmp = a > b ? a : b; + Uint32 size = tmp > c ? tmp : c; + Uint32 levels = 0; + while (size > 0) { + // divide by two + size = size / 2; + levels++; + } + imageCaps->maxMipLevels = levels; + + // resource limits + resourceCaps->sampledImageDynamicArrayIndexing = fts.shaderSampledImageArrayDynamicIndexing; + resourceCaps->storageImageDynamicArrayIndexing = fts.shaderStorageImageArrayDynamicIndexing; + resourceCaps->storageBufferDynamicArrayIndexing = fts.shaderStorageBufferArrayDynamicIndexing; + resourceCaps->uniformBufferDynamicArrayIndexing = fts.shaderUniformBufferArrayDynamicIndexing; + + resourceCaps->maxPerStageSampledImages = limits->maxPerStageDescriptorSampledImages; + resourceCaps->maxPerSetSampledImages = limits->maxDescriptorSetSampledImages; + resourceCaps->maxPerStageStorageImages = limits->maxPerStageDescriptorStorageImages; + resourceCaps->maxPerSetStorageImages = limits->maxDescriptorSetStorageImages; + + resourceCaps->maxPerStageSamplers = limits->maxPerStageDescriptorSamplers; + resourceCaps->maxPerSetSamplers = limits->maxDescriptorSetSamplers; + resourceCaps->maxPerStageStorageBuffers = limits->maxPerStageDescriptorStorageBuffers; + resourceCaps->maxPerSetStorageBuffers = limits->maxDescriptorSetStorageBuffers; + + resourceCaps->maxPerStageUniformBuffers = limits->maxPerStageDescriptorUniformBuffers; + resourceCaps->maxPerSetUniformBuffers = limits->maxDescriptorSetUniformBuffers; + + tmp = accProps.maxPerStageDescriptorAccelerationStructures; + resourceCaps->maxPerStageAccelerationStructure = tmp; + resourceCaps->maxPerSetAccelerationStructure = accProps.maxDescriptorSetAccelerationStructures; + resourceCaps->maxBoundSets = limits->maxBoundDescriptorSets; + + // compute limits + computeCaps->maxWorkGroupInvocations = limits->maxComputeWorkGroupInvocations; + computeCaps->maxWorkGroupCount[0] = limits->maxComputeWorkGroupCount[0]; + computeCaps->maxWorkGroupCount[1] = limits->maxComputeWorkGroupCount[1]; + computeCaps->maxWorkGroupCount[2] = limits->maxComputeWorkGroupCount[2]; + computeCaps->maxWorkGroupSize[0] = limits->maxComputeWorkGroupSize[0]; + computeCaps->maxWorkGroupSize[1] = limits->maxComputeWorkGroupSize[1]; + computeCaps->maxWorkGroupSize[2] = limits->maxComputeWorkGroupSize[2]; palFree(s_Vk.allocator, queueProps); return PAL_RESULT_SUCCESS; @@ -3731,10 +3757,10 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) features.pNext = &desc; s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (desc.shaderSampledImageArrayNonUniformIndexing || - desc.shaderStorageImageArrayNonUniformIndexing || - desc.shaderStorageBufferArrayNonUniformIndexing || - desc.shaderUniformBufferArrayNonUniformIndexing) { + // core features we need + if (desc.runtimeDescriptorArray || + desc.descriptorBindingPartiallyBound || + desc.descriptorBindingUpdateUnusedWhilePending) { adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } } @@ -4197,8 +4223,8 @@ PalResult PAL_CALL createDeviceVk( // clang-format off descIndex.runtimeDescriptorArray = desc.runtimeDescriptorArray; - descIndex.descriptorBindingVariableDescriptorCount = desc.descriptorBindingVariableDescriptorCount; descIndex.descriptorBindingPartiallyBound = desc.descriptorBindingPartiallyBound; + descIndex.descriptorBindingUpdateUnusedWhilePending = desc.descriptorBindingUpdateUnusedWhilePending; descIndex.shaderSampledImageArrayNonUniformIndexing = desc.shaderSampledImageArrayNonUniformIndexing; descIndex.descriptorBindingSampledImageUpdateAfterBind = desc.descriptorBindingSampledImageUpdateAfterBind; @@ -4792,9 +4818,9 @@ PalResult PAL_CALL queryMultiViewCapabilitiesVk( properties2.pNext = &props; s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - caps->maxMultiViews = props.maxMultiviewViewCount; - if (caps->maxMultiViews == 0) { - caps->maxMultiViews = 1; + caps->maxViewCount = props.maxMultiviewViewCount; + if (caps->maxViewCount == 0) { + caps->maxViewCount = 1; } return PAL_RESULT_SUCCESS; @@ -4812,7 +4838,7 @@ PalResult PAL_CALL queryMultiViewportCapabilitiesVk( VkPhysicalDeviceProperties props = {0}; s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); - caps->maxViewports = props.limits.maxViewports; + caps->maxCount = props.limits.maxViewports; return PAL_RESULT_SUCCESS; } @@ -4834,38 +4860,38 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesVk( properties2.pNext = &props; s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - caps->independentDepthStencilResolve = props.independentResolve; + caps->independentResolve = props.independentResolve; if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { - caps->depthResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; + caps->depthResolves[PAL_RESOLVE_MODE_AVERAGE] = true; } if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { - caps->depthResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; + caps->depthResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; } if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_MIN_BIT_KHR) { - caps->depthResolveModes[PAL_RESOLVE_MODE_MIN] = true; + caps->depthResolves[PAL_RESOLVE_MODE_MIN] = true; } if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { - caps->depthResolveModes[PAL_RESOLVE_MODE_MAX] = true; + caps->depthResolves[PAL_RESOLVE_MODE_MAX] = true; } // stencil if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { - caps->stencilResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_AVERAGE] = true; } if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { - caps->stencilResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; } if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MIN_BIT_KHR) { - caps->stencilResolveModes[PAL_RESOLVE_MODE_MIN] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_MIN] = true; } if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { - caps->stencilResolveModes[PAL_RESOLVE_MODE_MAX] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_MAX] = true; } return PAL_RESULT_SUCCESS; @@ -4936,18 +4962,18 @@ PalResult PAL_CALL queryMeshShaderCapabilitiesVk( properties2.pNext = &props; s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - caps->maxMeshOutputPrimitives = props.maxMeshOutputPrimitives; - caps->maxMeshOutputVertices = props.maxMeshOutputVertices; + caps->maxOutputPrimitives = props.maxMeshOutputPrimitives; + caps->maxOutputVertices = props.maxMeshOutputVertices; caps->maxTaskWorkGroupInvocations = props.maxTaskWorkGroupInvocations; - caps->maxMeshWorkGroupInvocations = props.maxMeshWorkGroupInvocations; + caps->maxWorkGroupInvocations = props.maxMeshWorkGroupInvocations; caps->maxTaskWorkGroupCount[0] = props.maxTaskWorkGroupCount[0]; caps->maxTaskWorkGroupCount[1] = props.maxTaskWorkGroupCount[1]; caps->maxTaskWorkGroupCount[2] = props.maxTaskWorkGroupCount[2]; - caps->maxMeshWorkGroupCount[0] = props.maxMeshWorkGroupCount[0]; - caps->maxMeshWorkGroupCount[1] = props.maxMeshWorkGroupCount[1]; - caps->maxMeshWorkGroupCount[2] = props.maxMeshWorkGroupCount[2]; + caps->maxWorkGroupCount[0] = props.maxMeshWorkGroupCount[0]; + caps->maxWorkGroupCount[1] = props.maxMeshWorkGroupCount[1]; + caps->maxWorkGroupCount[2] = props.maxMeshWorkGroupCount[2]; return PAL_RESULT_SUCCESS; } @@ -4983,10 +5009,6 @@ PalResult PAL_CALL queryRayTracingCapabilitiesVk( caps->maxPayloadSize = 64; // safe caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; - caps->maxDescriptorSetAccelerationStructures = accProps.maxDescriptorSetAccelerationStructures; - caps->maxDescriptorSetBindlessAccelerationStructures = - accProps.maxDescriptorSetUpdateAfterBindAccelerationStructures; - return PAL_RESULT_SUCCESS; } @@ -5010,16 +5032,16 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( VkPhysicalDeviceFeatures2 features; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + + VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; + accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; features.pNext = &desc; + props.pNext = &accProps; properties2.pNext = &props; s_Vk.getPhysicalDeviceFeatures2(vkDevice->phyDevice, &features); s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - caps->runtimeDescriptorArray = desc.runtimeDescriptorArray; - caps->variableDescriptorCount = desc.descriptorBindingVariableDescriptorCount; - caps->partiallyBoundDescriptors = desc.descriptorBindingPartiallyBound; - // check sub feature for sampled image if (desc.shaderSampledImageArrayNonUniformIndexing) { caps->sampledImageNonUniformIndexing = true; @@ -5056,20 +5078,23 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( caps->uniformBufferUpdateAfterBind = true; } - // clang-format off - caps->maxPerStageBindlessDescriptorSampledImages = props.maxPerStageDescriptorUpdateAfterBindSampledImages; - caps->maxDescriptorSetBindlessSampledImages = props.maxDescriptorSetUpdateAfterBindSampledImages; - caps->maxPerStageBindlessDescriptorStorageImages = props.maxPerStageDescriptorUpdateAfterBindStorageImages; - caps->maxDescriptorSetBindlessStorageImages = props.maxDescriptorSetUpdateAfterBindStorageImages; - - caps->maxPerStageBindlessDescriptorSamplers = props.maxPerStageDescriptorUpdateAfterBindSamplers; - caps->maxDescriptorSetBindlessSamplers = props.maxDescriptorSetUpdateAfterBindSamplers; - caps->maxPerStageBindlessDescriptorStorageBuffers = props.maxPerStageDescriptorUpdateAfterBindStorageBuffers; - caps->maxDescriptorSetBindlessStorageBuffers = props.maxDescriptorSetUpdateAfterBindStorageBuffers; - - caps->maxPerStageBindlessDescriptorUniformBuffers = props.maxPerStageDescriptorUpdateAfterBindUniformBuffers; - caps->maxDescriptorSetBindlessUniformBuffers = props.maxDescriptorSetUpdateAfterBindUniformBuffers; - // clang-format on + caps->maxPerStageSampledImages = props.maxPerStageDescriptorUpdateAfterBindSampledImages; + caps->maxPerSetSampledImages = props.maxDescriptorSetUpdateAfterBindSampledImages; + caps->maxPerStageStorageImages = props.maxPerStageDescriptorUpdateAfterBindStorageImages; + caps->maxPerSetStorageImages = props.maxDescriptorSetUpdateAfterBindStorageImages; + + caps->maxPerStageSamplers = props.maxPerStageDescriptorUpdateAfterBindSamplers; + caps->maxPerSetSamplers = props.maxDescriptorSetUpdateAfterBindSamplers; + caps->maxPerStageStorageBuffers = props.maxPerStageDescriptorUpdateAfterBindStorageBuffers; + caps->maxPerSetStorageBuffers = props.maxDescriptorSetUpdateAfterBindStorageBuffers; + + caps->maxPerStageUniformBuffers = props.maxPerStageDescriptorUpdateAfterBindUniformBuffers; + caps->maxPerSetUniformBuffers = props.maxDescriptorSetUpdateAfterBindUniformBuffers; + + Uint32 tmp = accProps.maxPerStageDescriptorUpdateAfterBindAccelerationStructures; + Uint32 tmp2 = accProps.maxDescriptorSetUpdateAfterBindAccelerationStructures; + caps->maxPerStageAccelerationStructure = tmp; + caps->maxPerSetAccelerationStructure = tmp2; return PAL_RESULT_SUCCESS; } @@ -8452,7 +8477,6 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( bindingFlags.bindingCount = count; VkDescriptorBindingFlags flags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; - flags |= VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT; flags |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; bindingFlags.pBindingFlags = &flags; createInfo.pNext = &bindingFlags; @@ -8515,7 +8539,10 @@ PalResult PAL_CALL createDescriptorPoolVk( createInfo.maxSets = info->maxDescriptorSets; createInfo.poolSizeCount = maxBindings; createInfo.pPoolSizes = poolSizes; - createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; + } result = s_Vk.createDescriptorPool( vkDevice->handle, diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index f8f079f0..7b92745f 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -471,9 +471,9 @@ bool computeTest() buildData.workGroupSize[2] = 1; // must match shader (local_size on glsl) // device limits - buildData.workGroupCount[0] = caps.maxComputeWorkGroupCount[0]; - buildData.workGroupCount[1] = caps.maxComputeWorkGroupCount[1]; - buildData.workGroupCount[2] = caps.maxComputeWorkGroupCount[2]; + buildData.workGroupCount[0] = caps.computeCaps.maxWorkGroupCount[0]; + buildData.workGroupCount[1] = caps.computeCaps.maxWorkGroupCount[1]; + buildData.workGroupCount[2] = caps.computeCaps.maxWorkGroupCount[2]; Uint32 workGroupInfoCount = 0; PalWorkGroupInfo* workGroupInfos = nullptr; diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index a6c10c40..e42aced7 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -156,76 +156,92 @@ bool graphicsTest() palLog(nullptr, ""); palLog(nullptr, " Capabilities:"); - if (caps.sampledImageDynamicArrayIndexing) { - palLog(nullptr, " Sampled image dynamic array indexing: True"); + palLog(nullptr, " Max compute queue: %u", caps.maxComputeQueues); + palLog(nullptr, " Max graphics queue: %u", caps.maxGraphicsQueues); + palLog(nullptr, " Max copy queue: %u", caps.maxCopyQueues); + palLog(nullptr, " Max color attachments: %u", caps.maxColorAttachments); + palLog(nullptr, " Max uniform buffer size: %u Bytes", caps.maxUniformBufferSize); - } else { - palLog(nullptr, " Sampled image dynamic array indexing: False"); - } + palLog(nullptr, " Max storage buffer size: %u Bytes", caps.maxStorageBufferSize); + palLog(nullptr, " Max push constant size: %u Bytes", caps.maxPushConstantSize); + palLog(nullptr, " Max vertex layouts: %u", caps.maxVertexLayouts); + palLog(nullptr, " Max vertex attributes: %u", caps.maxVertexAttributes); + palLog(nullptr, " Max tessellation patch point: %u", caps.maxTessellationPatchPoint); - if (caps.storageImageDynamicArrayIndexing) { - palLog(nullptr, " Storage image dynamic array indexing: True"); + palLog(nullptr, ""); + palLog(nullptr, " Viewport Capabilities:"); + palLog(nullptr, " Max width: %u", caps.viewportCaps.maxWidth); + palLog(nullptr, " Max height: %u", caps.viewportCaps.maxHeight); + palLog(nullptr, " Min bounds range: %.1f", caps.viewportCaps.minBoundsRange); + palLog(nullptr, " Max bounds range: %.1f", caps.viewportCaps.maxBoundsRange); - } else { - palLog(nullptr, " Storage image dynamic array indexing: False"); - } + palLog(nullptr, ""); + palLog(nullptr, " Image Capabilities:"); + palLog(nullptr, " Max width: %u", caps.imageCaps.maxWidth); + palLog(nullptr, " Max height: %u", caps.imageCaps.maxHeight); + palLog(nullptr, " Max depth: %u", caps.imageCaps.maxDepth); + palLog(nullptr, " Max array layers: %u", caps.imageCaps.maxArrayLayers); + palLog(nullptr, " Max mip levels: %u", caps.imageCaps.maxMipLevels); + + palLog(nullptr, ""); + palLog(nullptr, " Resource Capabilities:"); + PalResourceCapabilities* resourceCaps = &caps.resourceCaps; - if (caps.storageBufferDynamicArrayIndexing) { - palLog(nullptr, " Storage buffer dynamic array indexing: True"); + if (resourceCaps->sampledImageDynamicArrayIndexing) { + palLog(nullptr, " Sampled image dynamic array indexing: True"); } else { - palLog(nullptr, " Storage buffer dynamic array indexing: False"); + palLog(nullptr, " Sampled image dynamic array indexing: False"); } - if (caps.uniformBufferDynamicArrayIndexing) { - palLog(nullptr, " Uniform buffer dynamic array indexing: True"); + if (resourceCaps->storageImageDynamicArrayIndexing) { + palLog(nullptr, " Storage image dynamic array indexing: True"); } else { - palLog(nullptr, " Uniform buffer dynamic array indexing: False"); + palLog(nullptr, " Storage image dynamic array indexing: False"); } - palLog(nullptr, " Max compute queue: %u", caps.maxComputeQueues); - palLog(nullptr, " Max graphics queue: %u", caps.maxGraphicsQueues); - palLog(nullptr, " Max copy queue: %u", caps.maxCopyQueues); + if (resourceCaps->storageBufferDynamicArrayIndexing) { + palLog(nullptr, " Storage buffer dynamic array indexing: True"); - palLog(nullptr, " Max image width: %u", caps.maxImageWidth); - palLog(nullptr, " Max image height: %u", caps.maxImageHeight); - palLog(nullptr, " Max image depth: %u", caps.maxImageDepth); - palLog(nullptr, " Max image array layers: %u", caps.maxImageArrayLayers); - palLog(nullptr, " Max image mip levels: %u", caps.maxImageMipLevels); + } else { + palLog(nullptr, " Storage buffer dynamic array indexing: False"); + } - palLog(nullptr, " Max color attachments: %u", caps.maxColorAttachments); - palLog(nullptr, " Max uniform buffer size: %u Bytes", caps.maxUniformBufferSize); - palLog(nullptr, " Max storage buffer size: %u Bytes", caps.maxStorageBufferSize); - palLog(nullptr, " Max push constant size: %u Bytes", caps.maxPushConstantSize); + if (resourceCaps->uniformBufferDynamicArrayIndexing) { + palLog(nullptr, " Uniform buffer dynamic array indexing: True"); - palLog(nullptr, " Max vertex layouts: %u", caps.maxVertexLayouts); - palLog(nullptr, " Max vertex attributes: %u", caps.maxVertexAttributes); - palLog(nullptr, " Max tessellation patch point: %u", caps.maxTessellationPatchPoint); + } else { + palLog(nullptr, " Uniform buffer dynamic array indexing: False"); + } // clang-format off - palLog(nullptr, " Max per stage descriptor sampled images: %u", caps.maxPerStageDescriptorSampledImages); - palLog(nullptr, " Max descriptor set sampled images: %u", caps.maxDescriptorSetSampledImages); - palLog(nullptr, " Max per stage descriptor storage images: %u", caps.maxPerStageDescriptorStorageImages); - palLog(nullptr, " Max descriptor set storage images: %u", caps.maxDescriptorSetStorageImages); + palLog(nullptr, " Max per stage sampled images: %u", resourceCaps->maxPerStageSampledImages); + palLog(nullptr, " Max per set sampled images: %u", resourceCaps->maxPerSetSampledImages); + palLog(nullptr, " Max per stage storage images: %u", resourceCaps->maxPerStageStorageImages); + palLog(nullptr, " Max per set storage images: %u", resourceCaps->maxPerSetStorageImages); - palLog(nullptr, " Max per stage descriptor samplers: %u", caps.maxPerStageDescriptorSamplers); - palLog(nullptr, " Max descriptor set samplers: %u", caps.maxDescriptorSetSamplers); - palLog(nullptr, " Max per stage descriptor storage buffers: %u", caps.maxPerStageDescriptorStorageBuffers); - palLog(nullptr, " Max descriptor set storage buffers: %u", caps.maxDescriptorSetStorageBuffers); - - palLog(nullptr, " Max per stage descriptor uniform buffers: %u", caps.maxPerStageDescriptorUniformBuffers); - palLog(nullptr, " Max descriptor set uniform buffers: %u", caps.maxDescriptorSetUniformBuffers); - palLog(nullptr, " Max bound descriptor sets: %u", caps.maxBoundDescriptorSets); + palLog(nullptr, " Max per stage samplers: %u", resourceCaps->maxPerStageSamplers); + palLog(nullptr, " Max per set samplers: %u", resourceCaps->maxPerSetSamplers); + palLog(nullptr, " Max per stage storage buffers: %u", resourceCaps->maxPerStageStorageBuffers); + palLog(nullptr, " Max per set storage buffers: %u", resourceCaps->maxPerSetStorageBuffers); + + palLog(nullptr, " Max per stage uniform buffers: %u", resourceCaps->maxPerStageUniformBuffers); + palLog(nullptr, " Max per set uniform buffers: %u", resourceCaps->maxPerSetUniformBuffers); + palLog(nullptr, " Max per stage acceleration structures: %u", resourceCaps->maxPerStageAccelerationStructure); + palLog(nullptr, " Max per set acceleration structures: %u", resourceCaps->maxPerSetAccelerationStructure); + palLog(nullptr, " Max bound sets: %u", resourceCaps->maxBoundSets); // clang-format on - palLog(nullptr, " Max compute invocations: %u", caps.maxComputeWorkGroupInvocations); - palLog(nullptr, " Max compute work group count[0]: %u", caps.maxComputeWorkGroupCount[0]); - palLog(nullptr, " Max compute work group count[1]: %u", caps.maxComputeWorkGroupCount[1]); - palLog(nullptr, " Max compute work group count[2]: %u", caps.maxComputeWorkGroupCount[2]); - palLog(nullptr, " Max compute work group size[0]: %u", caps.maxComputeWorkGroupSize[0]); - palLog(nullptr, " Max compute work group size[1]: %u", caps.maxComputeWorkGroupSize[1]); - palLog(nullptr, " Max compute work group size[2]: %u", caps.maxComputeWorkGroupSize[2]); + palLog(nullptr, ""); + palLog(nullptr, " Compute Capabilities:"); + palLog(nullptr, " Max invocations: %u", caps.computeCaps.maxWorkGroupInvocations); + palLog(nullptr, " Max work group count[0]: %u", caps.computeCaps.maxWorkGroupCount[0]); + palLog(nullptr, " Max work group count[1]: %u", caps.computeCaps.maxWorkGroupCount[1]); + palLog(nullptr, " Max work group count[2]: %u", caps.computeCaps.maxWorkGroupCount[2]); + palLog(nullptr, " Max work group size[0]: %u", caps.computeCaps.maxWorkGroupSize[0]); + palLog(nullptr, " Max work group size[1]: %u", caps.computeCaps.maxWorkGroupSize[1]); + palLog(nullptr, " Max work group size[2]: %u", caps.computeCaps.maxWorkGroupSize[2]); // shader formats Uint32 target; @@ -298,7 +314,7 @@ bool graphicsTest() return false; } - palLog(nullptr, " Max viewports: %u", tmp.maxViewports); + palLog(nullptr, " Max count: %u", tmp.maxCount); palLog(nullptr, ""); } @@ -349,8 +365,6 @@ bool graphicsTest() palLog(nullptr, " Max geometry count: %u", tmp.maxGeometryCount); palLog(nullptr, " Max payload size: %u Bytes", tmp.maxPayloadSize); palLog(nullptr, " Max dispatch invocations: %u", tmp.maxDispatchInvocations); - palLog(nullptr, " Max descriptor set acceleration structures: %u", tmp.maxDescriptorSetAccelerationStructures); - palLog(nullptr, " Max descriptor set bindless acceleration structure: %u", tmp.maxDescriptorSetBindlessAccelerationStructures); palLog(nullptr, ""); } @@ -366,14 +380,14 @@ bool graphicsTest() return false; } - palLog(nullptr, " Max mesh output primitives: %u", tmp.maxMeshOutputPrimitives); - palLog(nullptr, " Max mesh output vertices: %u", tmp.maxMeshOutputVertices); - palLog(nullptr, " Max mesh invocations: %u", tmp.maxMeshWorkGroupInvocations); + palLog(nullptr, " Max output primitives: %u", tmp.maxOutputPrimitives); + palLog(nullptr, " Max output vertices: %u", tmp.maxOutputVertices); + palLog(nullptr, " Max invocations: %u", tmp.maxWorkGroupInvocations); palLog(nullptr, " Max task invocations: %u", tmp.maxTaskWorkGroupInvocations); - palLog(nullptr, " Max mesh work group count[0]: %u", tmp.maxMeshWorkGroupCount[0]); - palLog(nullptr, " Max mesh work group count[1]: %u", tmp.maxMeshWorkGroupCount[1]); - palLog(nullptr, " Max mesh work group count[2]: %u", tmp.maxMeshWorkGroupCount[2]); + palLog(nullptr, " Max work group count[0]: %u", tmp.maxWorkGroupCount[0]); + palLog(nullptr, " Max work group count[1]: %u", tmp.maxWorkGroupCount[1]); + palLog(nullptr, " Max work group count[2]: %u", tmp.maxWorkGroupCount[2]); palLog(nullptr, " Max task work group count[0]: %u", tmp.maxTaskWorkGroupCount[0]); palLog(nullptr, " Max task work group count[1]: %u", tmp.maxTaskWorkGroupCount[1]); palLog(nullptr, " Max task work group count[2]: %u", tmp.maxTaskWorkGroupCount[2]); @@ -462,27 +476,6 @@ bool graphicsTest() return false; } - if (tmp.runtimeDescriptorArray) { - palLog(nullptr, " Runtime descriptor arrays: True"); - - } else { - palLog(nullptr, " Runtime descriptor arrays: False"); - } - - if (tmp.variableDescriptorCount) { - palLog(nullptr, " Variable descriptor count: True"); - - } else { - palLog(nullptr, " Variable descriptor count: False"); - } - - if (tmp.partiallyBoundDescriptors) { - palLog(nullptr, " Partially bound descriptors: True"); - - } else { - palLog(nullptr, " Partially bound descriptors: False"); - } - if (tmp.sampledImageNonUniformIndexing) { palLog(nullptr, " Sampled image non uniform indexing: True"); @@ -540,18 +533,20 @@ bool graphicsTest() } // clang-format off - palLog(nullptr, " Max per stage bindless descriptor sampled images: %u", tmp.maxPerStageBindlessDescriptorSampledImages); - palLog(nullptr, " Max descriptor set bindless sampled images: %u", tmp.maxDescriptorSetBindlessSampledImages); - palLog(nullptr, " Max per stage binding descriptor storage images: %u", tmp.maxPerStageBindlessDescriptorStorageImages); - palLog(nullptr, " Max descriptor set bindless storage images: %u", tmp.maxDescriptorSetBindlessStorageImages); + palLog(nullptr, " Max per stage sampled images: %u", tmp.maxPerStageSampledImages); + palLog(nullptr, " Max per set sampled images: %u", tmp.maxPerSetSampledImages); + palLog(nullptr, " Max per stage storage images: %u", tmp.maxPerStageStorageImages); + palLog(nullptr, " Max per set storage images: %u", tmp.maxPerSetStorageImages); - palLog(nullptr, " Max per stage binding descriptor samplers: %u", tmp.maxPerStageBindlessDescriptorSamplers); - palLog(nullptr, " Max descriptor set bindless samplers: %u", tmp.maxDescriptorSetBindlessSamplers); - palLog(nullptr, " Max per stage binding descriptor storage buffers: %u", tmp.maxPerStageBindlessDescriptorStorageBuffers); - palLog(nullptr, " Max descriptor set bindless storage buffers: %u", tmp.maxDescriptorSetBindlessStorageBuffers); - - palLog(nullptr, " Max per stage binding descriptor uniform buffers: %u", tmp.maxPerStageBindlessDescriptorUniformBuffers); - palLog(nullptr, " Max descriptor set bindless uniform buffers: %u", tmp.maxDescriptorSetBindlessUniformBuffers); + palLog(nullptr, " Max per stage samplers: %u", tmp.maxPerStageSamplers); + palLog(nullptr, " Max per set samplers: %u", tmp.maxPerSetSamplers); + palLog(nullptr, " Max per stage storage buffers: %u", tmp.maxPerStageStorageBuffers); + palLog(nullptr, " Max per set storage buffers: %u", tmp.maxPerSetStorageBuffers); + + palLog(nullptr, " Max per stage uniform buffers: %u", tmp.maxPerStageUniformBuffers); + palLog(nullptr, " Max per set uniform buffers: %u", tmp.maxPerSetUniformBuffers); + palLog(nullptr, " Max per stage acceleration structures: %u", tmp.maxPerStageAccelerationStructure); + palLog(nullptr, " Max per set acceleration structures: %u", tmp.maxPerSetAccelerationStructure); // clang-format on palLog(nullptr, ""); @@ -572,7 +567,7 @@ bool graphicsTest() return false; } - palLog(nullptr, " Max multi views: %u", tmp.maxMultiViews); + palLog(nullptr, " Max view count: %u", tmp.maxViewCount); palLog(nullptr, ""); } @@ -623,43 +618,43 @@ bool graphicsTest() return false; } - if (tmp.independentDepthStencilResolve) { - palLog(nullptr, " Independent depth stencil resource: True"); + if (tmp.independentResolve) { + palLog(nullptr, " Independent resource: True"); } else { - palLog(nullptr, " Independent depth stencil resource: False"); + palLog(nullptr, " Independent resource: False"); } - palLog(nullptr, " Supported Depth Resolve Modes:"); - if (tmp.depthResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO]) { + palLog(nullptr, " Supported Depth Resolves:"); + if (tmp.depthResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO]) { palLog(nullptr, " Zero"); } - if (tmp.depthResolveModes[PAL_RESOLVE_MODE_AVERAGE]) { + if (tmp.depthResolves[PAL_RESOLVE_MODE_AVERAGE]) { palLog(nullptr, " Average"); } - if (tmp.depthResolveModes[PAL_RESOLVE_MODE_MIN]) { + if (tmp.depthResolves[PAL_RESOLVE_MODE_MIN]) { palLog(nullptr, " Min"); } - if (tmp.depthResolveModes[PAL_RESOLVE_MODE_MAX]) { + if (tmp.depthResolves[PAL_RESOLVE_MODE_MAX]) { palLog(nullptr, " Max"); } - palLog(nullptr, " Supported Stencil Resolve Modes:"); - if (tmp.stencilResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO]) { + palLog(nullptr, " Supported Stencil Resolves:"); + if (tmp.stencilResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO]) { palLog(nullptr, " Zero"); } - if (tmp.stencilResolveModes[PAL_RESOLVE_MODE_AVERAGE]) { + if (tmp.stencilResolves[PAL_RESOLVE_MODE_AVERAGE]) { palLog(nullptr, " Average"); } - if (tmp.stencilResolveModes[PAL_RESOLVE_MODE_MIN]) { + if (tmp.stencilResolves[PAL_RESOLVE_MODE_MIN]) { palLog(nullptr, " Min"); } - if (tmp.stencilResolveModes[PAL_RESOLVE_MODE_MAX]) { + if (tmp.stencilResolves[PAL_RESOLVE_MODE_MAX]) { palLog(nullptr, " Max"); } diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 3dbfd11b..e59d78a4 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -110,7 +110,7 @@ bool multiDescriptorSetTest() } // we want an adapter that supports the required bound descriptor sets (2) - if (caps.maxBoundDescriptorSets < 2) { + if (caps.resourceCaps.maxBoundSets < 2) { hasRequiredBoundDescriptorSets = false; continue; @@ -559,9 +559,9 @@ bool multiDescriptorSetTest() buildData.workGroupSize[2] = 1; // must match shader (local_size on glsl) // device limits - buildData.workGroupCount[0] = caps.maxComputeWorkGroupCount[0]; - buildData.workGroupCount[1] = caps.maxComputeWorkGroupCount[1]; - buildData.workGroupCount[2] = caps.maxComputeWorkGroupCount[2]; + buildData.workGroupCount[0] = caps.computeCaps.maxWorkGroupCount[0]; + buildData.workGroupCount[1] = caps.computeCaps.maxWorkGroupCount[1]; + buildData.workGroupCount[2] = caps.computeCaps.maxWorkGroupCount[2]; Uint32 workGroupInfoCount = 0; PalWorkGroupInfo* workGroupInfos = nullptr; diff --git a/tests/tests_main.c b/tests/tests_main.c index 231ff1a0..16d6ef5b 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,7 +57,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest, "Graphics Test"); + registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); @@ -69,7 +69,7 @@ int main(int argc, char** argv) // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); - registerTest(indirectDrawTest, "Indirect Draw Test"); + // registerTest(indirectDrawTest, "Indirect Draw Test"); // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // From 67a2ba3c5c49c671287603021da8359f79f845e9 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 20 May 2026 11:00:08 +0000 Subject: [PATCH 225/372] make API cleaner d3d12 --- src/graphics/pal_d3d12.c | 265 +++++++++++++++++++-------------------- 1 file changed, 131 insertions(+), 134 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 13d93a89..4a6c8998 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -48,7 +48,6 @@ freely, subject to the following restrictions: #define TEXTURE_PITCH 256 #define MAX_RTV 1024 #define MAX_DSV 512 -#define MAX_SCRATCH_BUFFER_SIZE 65536 * sizeof(wchar_t) #define MAX_MESSAGE_SIZE 4096 #define GRAPHICS_PIPELINE 1220 @@ -2018,92 +2017,76 @@ static void commitShaderbindingTableUpdateD3D12( sbt->isDirty = false; } -static void getDescriptorLimitsD3D12( +static void getDescriptorTierLimitsD3D12( void* device, - PalAdapterCapabilities* caps, + PalResourceCapabilities* caps, PalDescriptorIndexingCapabilities* descCaps) { D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; - if (caps) { - ID3D12Device* handle = device; - handle->lpVtbl->CheckFeatureSupport( - handle, - D3D12_FEATURE_D3D12_OPTIONS, - &options, - sizeof(options)); - - } else { - ID3D12Device5* handle = device; - handle->lpVtbl->CheckFeatureSupport( - handle, - D3D12_FEATURE_D3D12_OPTIONS, - &options, - sizeof(options)); - } + D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = {0}; + ID3D12Device* handle = device; + handle->lpVtbl->CheckFeatureSupport( + handle, + D3D12_FEATURE_D3D12_OPTIONS, + &options, + sizeof(options)); - if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) { - // safe defaults - if (caps) { - caps->maxPerStageDescriptorSampledImages = 1024; - caps->maxDescriptorSetSampledImages = 1024; - caps->maxPerStageDescriptorStorageImages = 512; - caps->maxDescriptorSetStorageImages = 512; - - caps->maxPerStageDescriptorSamplers = 256; - caps->maxDescriptorSetSamplers = 256; - caps->maxPerStageDescriptorStorageBuffers = 512; - caps->maxDescriptorSetStorageBuffers = 512; - - caps->maxPerStageDescriptorUniformBuffers = 256; - caps->maxDescriptorSetUniformBuffers = 256; - caps->maxBoundDescriptorSets = 30; + handle->lpVtbl->CheckFeatureSupport( + handle, + D3D12_FEATURE_D3D12_OPTIONS5, + &options5, + sizeof(options5)); + Uint32 perStage = 0; + if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED) { + // add buckets for acceleration structure + if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) { + perStage = 8; } else { - descCaps->maxPerStageBindlessDescriptorSampledImages = 1024; - descCaps->maxDescriptorSetBindlessSampledImages = 1024; - descCaps->maxPerStageBindlessDescriptorStorageImages = 512; - descCaps->maxDescriptorSetBindlessStorageImages = 512; - - descCaps->maxPerStageBindlessDescriptorSamplers = 256; - descCaps->maxDescriptorSetBindlessSamplers = 256; - descCaps->maxPerStageBindlessDescriptorStorageBuffers = 512; - descCaps->maxDescriptorSetBindlessStorageBuffers = 512; - - descCaps->maxPerStageBindlessDescriptorUniformBuffers = 256; - descCaps->maxDescriptorSetBindlessUniformBuffers = 256; + perStage = 5000; } + } + PalResourceCapabilities tmp = {0}; + if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) { + tmp.maxPerStageSampledImages = 128 - perStage; + tmp.maxPerStageStorageImages = 4; + tmp.maxPerStageSamplers = 16; + tmp.maxPerStageStorageBuffers = 4; + tmp.maxPerStageUniformBuffers = 14; + tmp.maxPerStageAccelerationStructure = perStage; + } else { - // safe defaults - if (caps) { - caps->maxPerStageDescriptorSampledImages = 4096; - caps->maxDescriptorSetSampledImages = 4096; - caps->maxPerStageDescriptorStorageImages = 1024; - caps->maxDescriptorSetStorageImages = 1024; - - caps->maxPerStageDescriptorSamplers = 512; - caps->maxDescriptorSetSamplers = 512; - caps->maxPerStageDescriptorStorageBuffers = 2048; - caps->maxDescriptorSetStorageBuffers = 2048; - - caps->maxPerStageDescriptorUniformBuffers = 256; - caps->maxDescriptorSetUniformBuffers = 256; - caps->maxBoundDescriptorSets = 30; - - } else { - descCaps->maxPerStageBindlessDescriptorSampledImages = 4096; - descCaps->maxDescriptorSetBindlessSampledImages = 4096; - descCaps->maxPerStageBindlessDescriptorStorageImages = 1024; - descCaps->maxDescriptorSetBindlessStorageImages = 1024; + tmp.maxPerStageSampledImages = 705000 - perStage; + tmp.maxPerStageStorageImages = 100000; + tmp.maxPerStageSamplers = 2048; + tmp.maxPerStageStorageBuffers = 100000; + tmp.maxPerStageUniformBuffers = 95000; + tmp.maxPerStageAccelerationStructure = perStage; + } - descCaps->maxPerStageBindlessDescriptorSamplers = 512; - descCaps->maxDescriptorSetBindlessSamplers = 512; - descCaps->maxPerStageBindlessDescriptorStorageBuffers = 2048; - descCaps->maxDescriptorSetBindlessStorageBuffers = 2048; + tmp.maxPerSetSampledImages = tmp.maxPerStageSampledImages; + tmp.maxPerSetStorageImages = tmp.maxPerStageStorageImages; + tmp.maxPerSetSamplers = tmp.maxPerStageSamplers; + tmp.maxPerSetStorageBuffers = tmp.maxPerStageStorageBuffers; + tmp.maxPerSetUniformBuffers = tmp.maxPerStageUniformBuffers; + tmp.maxPerSetAccelerationStructure = tmp.maxPerStageAccelerationStructure; - descCaps->maxPerStageBindlessDescriptorUniformBuffers = 256; - descCaps->maxDescriptorSetBindlessUniformBuffers = 256; - } + if (caps) { + *caps = tmp; + } else { + descCaps->maxPerStageSampledImages = tmp.maxPerStageSampledImages; + descCaps->maxPerSetSampledImages = tmp.maxPerSetSampledImages; + descCaps->maxPerStageStorageImages = tmp.maxPerStageStorageImages; + descCaps->maxPerSetStorageImages = tmp.maxPerSetStorageImages; + descCaps->maxPerStageSamplers = tmp.maxPerStageSamplers; + descCaps->maxPerSetSamplers = tmp.maxPerSetSamplers; + descCaps->maxPerStageStorageBuffers = tmp.maxPerStageStorageBuffers; + descCaps->maxPerSetStorageBuffers = tmp.maxPerSetStorageBuffers; + descCaps->maxPerStageUniformBuffers = tmp.maxPerStageUniformBuffers; + descCaps->maxPerSetUniformBuffers = tmp.maxPerSetUniformBuffers; + descCaps->maxPerStageAccelerationStructure = tmp.maxPerStageAccelerationStructure; + descCaps->maxPerSetAccelerationStructure = tmp.maxPerSetAccelerationStructure; } } @@ -2378,25 +2361,45 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapter* adapter, PalAdapterCapabilities* caps) { - // always supported - caps->sampledImageDynamicArrayIndexing = true; - caps->storageImageDynamicArrayIndexing = true; - caps->storageBufferDynamicArrayIndexing = true; - caps->uniformBufferDynamicArrayIndexing = true; + Adapter* d3dAdapter = (Adapter*)adapter; + if (!d3dAdapter->handle) { + return PAL_RESULT_INVALID_ADAPTER; + } + + PalViewportCapabilities* viewportCaps = &caps->viewportCaps; + PalImageCapabilities* imageCaps = &caps->imageCaps; + PalResourceCapabilities* resourceCaps = &caps->resourceCaps; + PalComputeCapabilities* computeCaps = &caps->computeCaps; caps->maxComputeQueues = 2; // safe default caps->maxGraphicsQueues = 2; // safe default caps->maxCopyQueues = 2; // safe default - caps->maxImageWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; - caps->maxImageHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; - caps->maxImageDepth = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - caps->maxImageArrayLayers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + caps->maxColorAttachments = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; + caps->maxUniformBufferSize = D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT * 16; + caps->maxStorageBufferSize = 2147483648; // 2 GIB + caps->maxPushConstantSize = 256; + + caps->maxVertexLayouts = 32; // safe + caps->maxVertexAttributes = 32; // safe + caps->maxTessellationPatchPoint = 32; + + // viewport limits + viewportCaps->maxWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + viewportCaps->maxHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + viewportCaps->minBoundsRange = (float)D3D12_VIEWPORT_BOUNDS_MIN; + viewportCaps->maxBoundsRange = (float)D3D12_VIEWPORT_BOUNDS_MAX; + + // image limits + imageCaps->maxWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + imageCaps->maxHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + imageCaps->maxDepth = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + imageCaps->maxArrayLayers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; // d3d12 does not give this but we calculate from the max width and width - Uint32 a = caps->maxImageWidth; - Uint32 b = caps->maxImageHeight; - Uint32 c = caps->maxImageDepth; + Uint32 a = imageCaps->maxWidth; + Uint32 b = imageCaps->maxHeight; + Uint32 c = imageCaps->maxDepth; Uint32 tmp = a > b ? a : b; Uint32 size = tmp > c ? tmp : c; @@ -2406,28 +2409,26 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( size = size / 2; levels++; } + imageCaps->maxMipLevels = levels; - caps->maxImageMipLevels = levels; - caps->maxColorAttachments = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; - caps->maxUniformBufferSize = D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT * 16; - caps->maxStorageBufferSize = 2147483648; // 2 GIB - caps->maxPushConstantSize = 256; - - caps->maxVertexLayouts = 32; // safe - caps->maxVertexAttributes = 32; // safe - caps->maxTessellationPatchPoint = 32; - - caps->maxComputeWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; - caps->maxComputeWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; - caps->maxComputeWorkGroupCount[1] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; - caps->maxComputeWorkGroupCount[2] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; - - caps->maxComputeWorkGroupSize[0] = D3D12_CS_THREAD_GROUP_MAX_X; - caps->maxComputeWorkGroupSize[1] = D3D12_CS_THREAD_GROUP_MAX_Y; - caps->maxComputeWorkGroupSize[2] = D3D12_CS_THREAD_GROUP_MAX_Z; + // resource limits + // always supported + getDescriptorTierLimitsD3D12(d3dAdapter->tmpDevice, resourceCaps, nullptr); + resourceCaps->maxBoundSets = 32; + resourceCaps->sampledImageDynamicArrayIndexing = true; + resourceCaps->storageImageDynamicArrayIndexing = true; + resourceCaps->storageBufferDynamicArrayIndexing = true; + resourceCaps->uniformBufferDynamicArrayIndexing = true; + + // compute limits + computeCaps->maxWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; + computeCaps->maxWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + computeCaps->maxWorkGroupCount[1] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + computeCaps->maxWorkGroupCount[2] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + computeCaps->maxWorkGroupSize[0] = D3D12_CS_THREAD_GROUP_MAX_X; + computeCaps->maxWorkGroupSize[1] = D3D12_CS_THREAD_GROUP_MAX_Y; + computeCaps->maxWorkGroupSize[2] = D3D12_CS_THREAD_GROUP_MAX_Z; - Adapter* d3dAdapter = (Adapter*)adapter; - getDescriptorLimitsD3D12(d3dAdapter->tmpDevice, caps, nullptr); return PAL_RESULT_SUCCESS; } @@ -2531,6 +2532,10 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT; } + if (!(options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1)) { + features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + } + // this features are supported on d3d12 features |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; features |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; @@ -2544,7 +2549,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; features |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; - features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; if (d3dAdapter->level >= D3D_FEATURE_LEVEL_12_0) { features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; @@ -3030,7 +3034,7 @@ PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - caps->maxMultiViews = D3D12_MAX_VIEW_INSTANCE_COUNT; + caps->maxViewCount = D3D12_MAX_VIEW_INSTANCE_COUNT; return PAL_RESULT_SUCCESS; } @@ -3043,7 +3047,7 @@ PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - caps->maxViewports = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + caps->maxCount = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; return PAL_RESULT_SUCCESS; } @@ -3056,17 +3060,17 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - caps->depthResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; - caps->depthResolveModes[PAL_RESOLVE_MODE_AVERAGE] = true; - caps->depthResolveModes[PAL_RESOLVE_MODE_MIN] = true; - caps->depthResolveModes[PAL_RESOLVE_MODE_MAX] = true; + caps->depthResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; + caps->depthResolves[PAL_RESOLVE_MODE_AVERAGE] = true; + caps->depthResolves[PAL_RESOLVE_MODE_MIN] = true; + caps->depthResolves[PAL_RESOLVE_MODE_MAX] = true; - caps->stencilResolveModes[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; - caps->stencilResolveModes[PAL_RESOLVE_MODE_AVERAGE] = false; - caps->stencilResolveModes[PAL_RESOLVE_MODE_MIN] = true; - caps->stencilResolveModes[PAL_RESOLVE_MODE_MAX] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_AVERAGE] = false; + caps->stencilResolves[PAL_RESOLVE_MODE_MIN] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_MAX] = true; - caps->independentDepthStencilResolve = true; + caps->independentResolve = true; return PAL_RESULT_SUCCESS; } @@ -3128,19 +3132,18 @@ PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( } // these are not exposed by d3d12. We use the offical mesh shader spec - caps->maxMeshOutputPrimitives = 256; - caps->maxMeshOutputVertices = 256; + caps->maxOutputPrimitives = 256; + caps->maxOutputVertices = 256; + caps->maxWorkGroupInvocations = 128; caps->maxTaskWorkGroupInvocations = 128; - caps->maxMeshWorkGroupInvocations = 128; + + caps->maxWorkGroupCount[0] = 65535; + caps->maxWorkGroupCount[1] = 65535; + caps->maxWorkGroupCount[2] = 65535; caps->maxTaskWorkGroupCount[0] = 65535; caps->maxTaskWorkGroupCount[1] = 65535; caps->maxTaskWorkGroupCount[2] = 65535; - - caps->maxMeshWorkGroupCount[0] = 65535; - caps->maxMeshWorkGroupCount[1] = 65535; - caps->maxMeshWorkGroupCount[2] = 65535; - return PAL_RESULT_SUCCESS; } @@ -3162,8 +3165,6 @@ PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( caps->maxPayloadSize = 64; caps->maxDispatchInvocations = 16000000; - caps->maxDescriptorSetAccelerationStructures = 4; - caps->maxDescriptorSetBindlessAccelerationStructures = 4; return PAL_RESULT_SUCCESS; } @@ -3176,10 +3177,6 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - caps->runtimeDescriptorArray = true; // always supported - caps->variableDescriptorCount = true; // manually - caps->partiallyBoundDescriptors = true; // always supported - // always supported caps->sampledImageNonUniformIndexing = true; caps->sampledImageUpdateAfterBind = true; @@ -3190,7 +3187,7 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( caps->uniformBufferNonUniformIndexing = true; caps->uniformBufferUpdateAfterBind = true; - getDescriptorLimitsD3D12(d3dDevice->handle, nullptr, caps); + getDescriptorTierLimitsD3D12(d3dDevice->handle, nullptr, caps); return PAL_RESULT_SUCCESS; } From 3ff85b6275610891c6d30b18800cc6bdac1adb5d Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 20 May 2026 16:13:05 +0000 Subject: [PATCH 226/372] descriptor indexing test working on vulkan' --- include/pal/pal_graphics.h | 37 +++--- src/graphics/pal_d3d12.c | 17 ++- src/graphics/pal_graphics.c | 5 +- src/graphics/pal_vulkan.c | 66 +++++++--- tests/graphics/clear_color_test.c | 4 +- tests/graphics/descriptor_indexing_test.c | 123 +++++++++++++----- tests/graphics/geometry_test.c | 4 +- tests/graphics/indirect_draw_test.c | 4 +- tests/graphics/mesh_test.c | 4 +- .../shaders/bin/spirv/descriptor_indexing.spv | Bin 0 -> 2356 bytes .../shaders/src/glsl/descriptor_indexing.glsl | 32 ++++- tests/graphics/texture_test.c | 4 +- tests/graphics/triangle_test.c | 4 +- tests/tests_main.c | 4 +- 14 files changed, 216 insertions(+), 92 deletions(-) create mode 100644 tests/graphics/shaders/bin/spirv/descriptor_indexing.spv diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 921fe6ba..d755053a 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1859,8 +1859,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint64 waitValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ - Uint64 signalValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ + Uint64 waitValue; + Uint64 signalValue; PalCommandBuffer* cmdBuffer; PalSemaphore* waitSemaphore; PalSemaphore* signalSemaphore; @@ -1878,7 +1878,7 @@ typedef struct { */ typedef struct { Uint64 timeout; /**< Timeout in milliseconds.*/ - Uint64 signalValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ + Uint64 signalValue; PalSemaphore* signalSemaphore; PalFence* fence; } PalSwapchainNextImageInfo; @@ -1894,7 +1894,7 @@ typedef struct { */ typedef struct { Uint32 imageIndex; /**< Image index to present. Must be 0 and less than max images.*/ - Uint64 waitValue; /**< Used if `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` is supported.*/ + Uint64 waitValue; PalSemaphore* waitSemaphore; } PalSwapchainPresentInfo; @@ -2645,6 +2645,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + /** If true `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled.*/ + bool enableDescriptorIndexing; Uint32 bindingCount; PalDescriptorSetLayoutBinding* bindings; } PalDescriptorSetLayoutCreateInfo; @@ -2659,6 +2661,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { + /** If true `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled.*/ + bool enableDescriptorIndexing; Uint32 maxDescriptorSets; Uint32 maxDescriptorBindingSizes; PalDescriptorPoolBindingSize* bindingSizes; @@ -3263,6 +3267,7 @@ typedef struct { */ PalResult PAL_CALL (*createSemaphore)( PalDevice* device, + bool enableTimeline, PalSemaphore** outSemaphore); /** @@ -5358,12 +5363,9 @@ PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); * * The graphics system must be initialized before this call. * - * A binary semaphore is created by default. To create a timeline - * semaphore, enable `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` when creating the device. - * The feature must be supported by the device if not, this function will fail and return - * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * * @param[in] device Device that creates the semaphore. + * @param[in] enableTimeline If true, `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported + * and enabled by the device creating the semaphore. * @param[out] outSemaphore Pointer to a PalSemaphore to recieve the created semaphore. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -5377,6 +5379,7 @@ PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); */ PAL_API PalResult PAL_CALL palCreateSemaphore( PalDevice* device, + bool enableTimeline, PalSemaphore** outSemaphore); /** @@ -5400,10 +5403,10 @@ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); /** * @brief Waits for a semaphore to reach the provided value. * - * The graphics system must be initialized before this call. - * - * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * The graphics system must be initialized before this call. + * + * The provided semaphore must be a timeline semaphore If not, this function fails and returns + * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] semaphore Semaphore to wait on. * @param[in] value Value to wait for. @@ -5429,8 +5432,8 @@ PAL_API PalResult PAL_CALL palWaitSemaphore( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * The provided semaphore must be a timeline semaphore If not, this function fails and returns + * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] semaphore Semaphore to signal. * @param[in] queue Queue used to signal the semaphore. @@ -5456,8 +5459,8 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * The provided semaphore must be a timeline semaphore If not, this function fails and returns + * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] semaphore Semaphore to get its value. * @param[out] outValue Pointer to a Uint64 to receive the semaphore value. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 4a6c8998..f85a6a83 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -4493,17 +4493,27 @@ bool PAL_CALL isFenceSignaledD3D12(PalFence* fence) PalResult PAL_CALL createSemaphoreD3D12( PalDevice* device, + bool enableTimeline, PalSemaphore** outSemaphore) { HRESULT result; Device* d3dDevice = (Device*)device; Semaphore* semaphore = nullptr; + bool hasTimeline = d3dDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; semaphore = palAllocate(s_D3D.allocator, sizeof(Semaphore), 0); if (!semaphore) { return PAL_RESULT_OUT_OF_MEMORY; } + if (enableTimeline && !hasTimeline) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + if (enableTimeline) { + semaphore->isTimeline = true; + } + result = d3dDevice->handle->lpVtbl->CreateFence( d3dDevice->handle, 0, @@ -4520,11 +4530,6 @@ PalResult PAL_CALL createSemaphoreD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - semaphore->isTimeline = false; - if (d3dDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - semaphore->isTimeline = true; - } - semaphore->canReset = false; semaphore->value = 0; *outSemaphore = (PalSemaphore*)semaphore; @@ -6635,6 +6640,8 @@ PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer) // Descriptor Pool, Set and Layout // ================================================== +// TODO: rewrite + PalResult PAL_CALL createDescriptorSetLayoutD3D12( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index ad73a200..6cc36d7d 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -367,6 +367,7 @@ bool PAL_CALL isFenceSignaledVk(PalFence* fence); PalResult PAL_CALL createSemaphoreVk( PalDevice* device, + bool enableTimeline, PalSemaphore** outSemaphore); void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore); @@ -1245,6 +1246,7 @@ bool PAL_CALL isFenceSignaledD3D12(PalFence* fence); PalResult PAL_CALL createSemaphoreD3D12( PalDevice* device, + bool enableTimeline, PalSemaphore** outSemaphore); void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); @@ -3023,6 +3025,7 @@ bool PAL_CALL palIsFenceSignaled(PalFence* fence) PalResult PAL_CALL palCreateSemaphore( PalDevice* device, + bool enableTimeline, PalSemaphore** outSemaphore) { if (!s_Graphics.initialized) { @@ -3035,7 +3038,7 @@ PalResult PAL_CALL palCreateSemaphore( PalSemaphore* semaphore = nullptr; PalResult result; - result = device->backend->createSemaphore(device, &semaphore); + result = device->backend->createSemaphore(device, enableTimeline, &semaphore); if (result != PAL_RESULT_SUCCESS) { return result; } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 63962b95..6fac6b48 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -6320,11 +6320,13 @@ bool PAL_CALL isFenceSignaledVk(PalFence* fence) PalResult PAL_CALL createSemaphoreVk( PalDevice* device, + bool enableTimeline, PalSemaphore** outSemaphore) { VkResult result; Semaphore* semaphore = nullptr; Device* vkDevice = (Device*)device; + bool hasTimeline = vkDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; semaphore = palAllocate(s_Vk.allocator, sizeof(Semaphore), 0); if (!semaphore) { @@ -6340,9 +6342,13 @@ PalResult PAL_CALL createSemaphoreVk( const void* next = nullptr; semaphore->isTimeline = false; - if (vkDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + if (enableTimeline && !hasTimeline) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + if (enableTimeline) { next = &timelineCreateInfo; - semaphore->isTimeline = true; + semaphore->isTimeline = true; } createInfo.pNext = next; @@ -6378,7 +6384,7 @@ PalResult PAL_CALL waitSemaphoreVk( VkResult result; Uint64 timeInNanoseconds = 0; Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { + if (!vkSemaphore->isTimeline) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6415,7 +6421,7 @@ PalResult PAL_CALL signalSemaphoreVk( { VkResult result; Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { + if (!vkSemaphore->isTimeline) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6437,7 +6443,7 @@ PalResult PAL_CALL getSemaphoreValueVk( Uint64* outValue) { Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!(vkSemaphore->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE)) { + if (!vkSemaphore->isTimeline) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -8442,9 +8448,15 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( VkResult result; Device* vkDevice = (Device*)device; VkDescriptorSetLayoutBinding* bindings = nullptr; - VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlags = {0}; + VkDescriptorBindingFlags* bindingFlags = nullptr; DescriptorSetLayout* layout = nullptr; Uint32 count = info->bindingCount; + VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsCreateInfo = {0}; + + bool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } layout = palAllocate(s_Vk.allocator, sizeof(DescriptorSetLayout), 0); bindings = palAllocate(s_Vk.allocator, sizeof(VkDescriptorSetLayoutBinding) * count, 0); @@ -8452,6 +8464,13 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( return PAL_RESULT_OUT_OF_MEMORY; } + if (info->enableDescriptorIndexing) { + bindingFlags = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBindingFlags) * count, 0); + if (!bindingFlags) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } + VkDescriptorSetLayoutCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; createInfo.bindingCount = count; @@ -8470,16 +8489,22 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( VkShaderStageFlagBits bit = shaderStageToVK(info->bindings[i].shaderStages[j]); binding->stageFlags |= bit; } + + if (bindingFlags) { + bindingFlags[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; + bindingFlags[i] |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; + bindingFlags[i] |= VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT; + } } - if (vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - bindingFlags.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; - bindingFlags.bindingCount = count; + if (info->enableDescriptorIndexing) { + bindingFlagsCreateInfo.sType = + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; - VkDescriptorBindingFlags flags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; - flags |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; - bindingFlags.pBindingFlags = &flags; - createInfo.pNext = &bindingFlags; + bindingFlagsCreateInfo.bindingCount = count; + bindingFlagsCreateInfo.pBindingFlags = bindingFlags; + createInfo.pNext = &bindingFlagsCreateInfo; + createInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; } result = s_Vk.createDescriptorSetLayout( @@ -8521,6 +8546,16 @@ PalResult PAL_CALL createDescriptorPoolVk( DescriptorPool* pool = nullptr; VkDescriptorPoolSize* poolSizes = nullptr; Uint32 maxBindings = info->maxDescriptorBindingSizes; + VkDescriptorPoolCreateInfo createInfo = {0}; + + bool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + if (info->enableDescriptorIndexing) { + createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; + } pool = palAllocate(s_Vk.allocator, sizeof(DescriptorPool), 0); poolSizes = palAllocate(s_Vk.allocator, sizeof(VkDescriptorPoolSize) * maxBindings, 0); @@ -8534,16 +8569,11 @@ PalResult PAL_CALL createDescriptorPoolVk( poolSize->type = descriptortypeToVk(info->bindingSizes[i].descriptorType); } - VkDescriptorPoolCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; createInfo.maxSets = info->maxDescriptorSets; createInfo.poolSizeCount = maxBindings; createInfo.pPoolSizes = poolSizes; - if (vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; - } - result = s_Vk.createDescriptorPool( vkDevice->handle, &createInfo, diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index 12392246..b57a0a79 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -302,7 +302,7 @@ bool clearColorTest() } // create render finished semaphores - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -321,7 +321,7 @@ bool clearColorTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 233e9f57..abc081d6 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -4,14 +4,22 @@ #include "pal/pal_system.h" #include "tests.h" -// TODO: test on vulkan first - #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define MAX_FRAMES_IN_FLIGHT 2 #define TEXTURE_WIDTH 128 #define TEXTURE_HEIGHT 128 +#define ARRAY_ELEMENT_0 17 +#define ARRAY_ELEMENT_1 47 +#define ARRAY_ELEMENT_2 55 +#define ARRAY_ELEMENT_3 78 + +// layout must match shader +typedef struct { + Uint32 textureIndices[4]; +} PushConstant; + static void createFlatTexture( Uint32* texture, Uint32 width, @@ -102,7 +110,7 @@ bool descriptorIndexingTest() windowCreateInfo.height = WINDOW_HEIGHT; windowCreateInfo.width = WINDOW_WIDTH; windowCreateInfo.show = true; - windowCreateInfo.title = "Texture Window"; + windowCreateInfo.title = "Descriptor Indexing Window"; PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { @@ -216,7 +224,7 @@ bool descriptorIndexingTest() } if (hasDescriptorIndexing) { - // We want an adapter that supports spirv 1.4 or dxil 6.6 + // We want an adapter that supports spirv 1.4 or dxbc 5.1 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -233,9 +241,9 @@ bool descriptorIndexingTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - if (target >= PAL_MAKE_SHADER_TARGET(6, 6)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { break; } } @@ -391,7 +399,7 @@ bool descriptorIndexingTest() } // create render finished semaphores - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -410,7 +418,7 @@ bool descriptorIndexingTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -759,7 +767,14 @@ bool descriptorIndexingTest() textureRange.layerArrayCount = 1; for (int i = 0; i < 4; i++) { + oldImageUsageState.shaderStageCount = 0; + oldImageUsageState.shaderStages = nullptr; + oldImageUsageState.usageState = PAL_USAGE_STATE_UNDEFINED; + + newImageUsageState.shaderStageCount = 0; + newImageUsageState.shaderStages = nullptr; newImageUsageState.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + result = palCmdImageBarrier( cmdBuffers[0], textures[i], @@ -881,9 +896,9 @@ bool descriptorIndexingTest() sources[0] = "graphics/shaders/bin/spirv/texture_vert.spv"; sources[1] = "graphics/shaders/bin/spirv/descriptor_indexing.spv"; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - sources[0] = "graphics/shaders/bin/dxil/texture_vert.dxil"; - sources[1] = "graphics/shaders/bin/dxil/descriptor_indexing.dxil"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + sources[0] = "graphics/shaders/bin/dxbc/texture_vert.dxbc"; + sources[1] = "graphics/shaders/bin/dxbc/descriptor_indexing.dxbc"; } tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; @@ -923,7 +938,8 @@ bool descriptorIndexingTest() PalDescriptorSetLayoutBinding descriptorBindings[2]; PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; - descriptorBindings[0].descriptorCount = 4; // an array + // We use descriptor count of 100 and only use 4 slots + descriptorBindings[0].descriptorCount = 100; descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; descriptorBindings[0].shaderStageCount = 1; descriptorBindings[0].shaderStages = shaderStages; @@ -937,6 +953,9 @@ bool descriptorIndexingTest() descriptorSetLayoutcreateInfo.bindingCount = 2; descriptorSetLayoutcreateInfo.bindings = descriptorBindings; + // we need to enable descriptor indexing for the descriptor set layout + descriptorSetLayoutcreateInfo.enableDescriptorIndexing = true; + result = palCreateDescriptorSetLayout( device, &descriptorSetLayoutcreateInfo, @@ -950,7 +969,7 @@ bool descriptorIndexingTest() // create descriptor pool PalDescriptorPoolBindingSize storageBufferBindingsizes[2]; - storageBufferBindingsizes[0].bindingCount = 4; + storageBufferBindingsizes[0].bindingCount = 100; storageBufferBindingsizes[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; storageBufferBindingsizes[1].bindingCount = 1; @@ -961,6 +980,9 @@ bool descriptorIndexingTest() descriptorPoolCreateInfo.maxDescriptorBindingSizes = 2; descriptorPoolCreateInfo.bindingSizes = storageBufferBindingsizes; + // we need to enable descriptor indexing for the descriptor pool + descriptorPoolCreateInfo.enableDescriptorIndexing = true; + result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -977,7 +999,9 @@ bool descriptorIndexingTest() return false; } - // write the inital data to the descriptor set since its created empty + // we only write 4 descriptors + Uint32 arrElements[] = { ARRAY_ELEMENT_0, ARRAY_ELEMENT_1, ARRAY_ELEMENT_2, ARRAY_ELEMENT_3 }; + PalDescriptorImageViewInfo descriptorImageInfos[4]; descriptorImageInfos[0].imageView = textureViews[0]; descriptorImageInfos[1].imageView = textureViews[1]; @@ -987,40 +1011,55 @@ bool descriptorIndexingTest() PalDescriptorSamplerInfo descriptorSamplerInfo = {0}; descriptorSamplerInfo.sampler = sampler; - PalDescriptorSetWriteInfo writeInfos[2]; - writeInfos[0].layoutBindingIndex = 0; - writeInfos[0].imageViewInfos = descriptorImageInfos; + PalDescriptorSetWriteInfo writeInfos[5]; + // sampler + writeInfos[0].layoutBindingIndex = 1; + writeInfos[0].samplerInfos = &descriptorSamplerInfo; writeInfos[0].descriptorSet = descriptorSet; - writeInfos[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - writeInfos[0].descriptorCount = 4; + writeInfos[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; + writeInfos[0].descriptorCount = 1; writeInfos[0].arrayElement = 0; - writeInfos[0].bufferInfos = nullptr; - writeInfos[0].samplerInfos = nullptr; + writeInfos[0].imageViewInfos = nullptr; writeInfos[0].tlasInfos = nullptr; + writeInfos[0].bufferInfos = nullptr; - writeInfos[1].layoutBindingIndex = 1; - writeInfos[1].samplerInfos = &descriptorSamplerInfo; - writeInfos[1].descriptorSet = descriptorSet; - writeInfos[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; - writeInfos[1].descriptorCount = 1; + // textures + for (int i = 0; i < 4; i++) { + writeInfos[i + 1].layoutBindingIndex = 0; + writeInfos[i + 1].imageViewInfos = &descriptorImageInfos[i]; + writeInfos[i + 1].descriptorSet = descriptorSet; + writeInfos[i + 1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + writeInfos[i + 1].descriptorCount = 1; - writeInfos[1].arrayElement = 0; - writeInfos[1].imageViewInfos = nullptr; - writeInfos[1].tlasInfos = nullptr; - writeInfos[1].bufferInfos = nullptr; + writeInfos[i + 1].arrayElement = arrElements[i]; + writeInfos[i + 1].bufferInfos = nullptr; + writeInfos[i + 1].samplerInfos = nullptr; + writeInfos[i + 1].tlasInfos = nullptr; + } - result = palUpdateDescriptorSet(device, 2, writeInfos); + result = palUpdateDescriptorSet(device, 5, writeInfos); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); return false; } + + // push constants + // size must be less than the max size from the adapter capabilities struct + PalPushConstantRange pushConstantRange = {0}; + pushConstantRange.offset = 0; + pushConstantRange.size = sizeof(PushConstant); // must match shader + pushConstantRange.shaderStageCount = 1; + pushConstantRange.shaderStages = shaderStages; + // create pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; pipelineLayoutCreateInfo.descriptorSetLayoutCount = 1; + pipelineLayoutCreateInfo.pushConstantRangeCount = 1; pipelineLayoutCreateInfo.descriptorSetLayouts = &descriptorSetLayout; + pipelineLayoutCreateInfo.pushConstantRanges = &pushConstantRange; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { @@ -1120,6 +1159,12 @@ bool descriptorIndexingTest() scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; + PushConstant pushConstant = {0}; + pushConstant.textureIndices[0] = ARRAY_ELEMENT_0; + pushConstant.textureIndices[1] = ARRAY_ELEMENT_1; + pushConstant.textureIndices[2] = ARRAY_ELEMENT_2; + pushConstant.textureIndices[3] = ARRAY_ELEMENT_3; + while (running) { // update the video system to push video events palUpdateVideo(); @@ -1266,6 +1311,20 @@ bool descriptorIndexingTest() return false; } + result = palCmdPushConstants( + cmdBuffers[currentFrame], + 1, + shaderStages, + 0, + sizeof(PushConstant), + &pushConstant); + + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to push constants: %s", error); + return false; + } + result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index e52e97b2..e98dc705 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -354,7 +354,7 @@ bool geometryTest() } // create render finished semaphores - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -373,7 +373,7 @@ bool geometryTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index e691ad5a..54c5b86d 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -370,7 +370,7 @@ bool indirectDrawTest() } // create render finished semaphores - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -389,7 +389,7 @@ bool indirectDrawTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index a0aa9cc7..5352a89c 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -351,7 +351,7 @@ bool meshTest() } // create render finished semaphores - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -370,7 +370,7 @@ bool meshTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); diff --git a/tests/graphics/shaders/bin/spirv/descriptor_indexing.spv b/tests/graphics/shaders/bin/spirv/descriptor_indexing.spv new file mode 100644 index 0000000000000000000000000000000000000000..53784e63aec33d8e093090011868ebbf4fbeeee5 GIT binary patch literal 2356 zcmZ9MX>U_U6o!Y`PFc!U_T3?+3rk8{pil~A0g|+a1`!#1!g-pSSGU;UW6(d}r&- z_34kc^m4H8{uQ-s2?K68LGgXDz@KR$X_V@JJ4MR$=ZoL zOa;%P3XTx-F;d&Ju*Pnr_2h3Bw&y43o}OV9xZFc~UuNa``_YZHrhX+y!TN0~#vjEp zCi+k44(plU-Yz6DBc&))yL_HCl|?En*Gcn>}S-W~79E#mFt0FeKS81Lhug7c2NrN$AY>wn_) z9R_mtp&n}=L$|hfDb_xYE+1>3M3?h^{YQSRqx_ey-TxGDA7?b)J?!HQ(q$jU_+P97 z`%v$n*V@MGGbZ*pf<8F^SvdK>i}^><<>LJ3&|U7U?^7UWZS`3DGxWjvKZlc#^M8RZ z7w3<4lyUwq(cPyCjCT*`zkqbvhcV~DC14-waen`+&TqUvV`7hE=!5fr1t%YSyo@dv z=l=%X<-Yp926EO`kF~!=ADsURoP0dntLSoZ{#ZvD=f8&TKK5_a`ye*@k5jn`*P^!ZNp`;6&7E6+?j-W{cP**9(q_!wSfQt literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl b/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl index caf8c59a..dc01d3b1 100644 --- a/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl +++ b/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl @@ -1,17 +1,39 @@ #version 450 +#extension GL_EXT_nonuniform_qualifier : require -// texs[]; if runtime descriptor array is supported but for this example we wont use it -layout(set = 0, binding = 0) uniform texture2D texs[4]; +layout(set = 0, binding = 0) uniform texture2D texs[]; layout(set = 0, binding = 1) uniform sampler samp; +layout(push_constant) uniform PushConstants +{ + uint textureIndices[4]; +} pc; + layout(location = 0) in vec2 aTexCoord; layout(location = 0) out vec4 color; void main() { - int index = int(gl_FragCoord.x) / 160; - index = index & 3; - color = texture(sampler2D(texs[index], samp), aTexCoord); + int quadrant = 0; // quad is centered + if (gl_FragCoord.x < 320.0 && gl_FragCoord.y < 240.0) { + // red texture + quadrant = 0; + + } else if (gl_FragCoord.x >= 320.0 && gl_FragCoord.y < 240.0) { + // green texture + quadrant = 1; + + } else if (gl_FragCoord.x < 320.0 && gl_FragCoord.y >= 240.0) { + // blue texture + quadrant = 2; + + } else { + // yellow texture + quadrant = 3; + } + + uint index = pc.textureIndices[quadrant]; + color = texture(sampler2D(texs[nonuniformEXT(index)], samp), aTexCoord); } \ No newline at end of file diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 792e48c6..3507bfce 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -377,7 +377,7 @@ bool textureTest() } // create render finished semaphores - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -396,7 +396,7 @@ bool textureTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 6cbdfa9c..9de72309 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -343,7 +343,7 @@ bool triangleTest() } // create render finished semaphores - result = palCreateSemaphore(device, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); @@ -362,7 +362,7 @@ bool triangleTest() // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); diff --git a/tests/tests_main.c b/tests/tests_main.c index 16d6ef5b..21fa4511 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,7 +57,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest, "Graphics Test"); + // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); @@ -70,7 +70,7 @@ int main(int argc, char** argv) // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); - // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); + registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From 7f716bea71af14ba0b6af9a428f64c5fc4ae0591 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 22 May 2026 18:01:03 +0000 Subject: [PATCH 227/372] make multi descriptor test use 3 sets rather than 2 --- tests/graphics/multi_descriptor_set_test.c | 119 ++++++++---------- .../shaders/bin/spirv/compute_multi.spv | Bin 2264 -> 2436 bytes .../shaders/src/glsl/compute_multi.glsl | 25 ++-- tests/tests_main.c | 4 +- 4 files changed, 70 insertions(+), 78 deletions(-) diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index e59d78a4..1a64ebcb 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -9,9 +9,9 @@ typedef struct { Uint32 width; Uint32 height; Uint32 _padding[2]; - float setColor1[4]; - float setColor2[4]; float set1Color[4]; + float set2Color[4]; + float set3Color[4]; } PushConstant; static void PAL_CALL onGraphicsDebug( @@ -38,8 +38,8 @@ bool multiDescriptorSetTest() PalMemory* stagingBufferMemories[3]; PalDescriptorPool* descriptorPool = nullptr; - PalDescriptorSetLayout* descriptorSetLayouts[2]; - PalDescriptorSet* descriptorSets[2]; + PalDescriptorSetLayout* descriptorSetLayout; + PalDescriptorSet* descriptorSets[3]; PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -109,8 +109,8 @@ bool multiDescriptorSetTest() hasComputeQueue = true; } - // we want an adapter that supports the required bound descriptor sets (2) - if (caps.resourceCaps.maxBoundSets < 2) { + // we want an adapter that supports the required bound descriptor sets (3) + if (caps.resourceCaps.maxBoundSets < 3) { hasRequiredBoundDescriptorSets = false; continue; @@ -340,28 +340,16 @@ bool multiDescriptorSetTest() descriptorBinding.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; descriptorBinding.shaderStageCount = 1; descriptorBinding.shaderStages = shaderStages; + descriptorBinding.descriptorCount = 1; // not an array PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; descriptorSetLayoutcreateInfo.bindingCount = 1; descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; - descriptorBinding.descriptorCount = 2; // an array result = palCreateDescriptorSetLayout( device, &descriptorSetLayoutcreateInfo, - &descriptorSetLayouts[0]); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor set layout: %s", error); - return false; - } - - descriptorBinding.descriptorCount = 1; // not an array - result = palCreateDescriptorSetLayout( - device, - &descriptorSetLayoutcreateInfo, - &descriptorSetLayouts[1]); + &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -375,7 +363,7 @@ bool multiDescriptorSetTest() storageBufferBindingsize.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; - descriptorPoolCreateInfo.maxDescriptorSets = 2; // only one set + descriptorPoolCreateInfo.maxDescriptorSets = 3; descriptorPoolCreateInfo.maxDescriptorBindingSizes = 1; // one binding type descriptorPoolCreateInfo.bindingSizes = &storageBufferBindingsize; @@ -387,11 +375,11 @@ bool multiDescriptorSetTest() } // allocate the sets from the descriptor pool - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 3; i++) { result = palAllocateDescriptorSet( device, descriptorPool, - descriptorSetLayouts[i], + descriptorSetLayout, &descriptorSets[i]); if (result != PAL_RESULT_SUCCESS) { @@ -402,11 +390,7 @@ bool multiDescriptorSetTest() } // write the inital data to the descriptor set since its created empty - Uint32 bindingCounts[2] = { 2, 1 }; - Uint32 bufferOffsets[2] = { 0, 2 }; - PalDescriptorSetWriteInfo writeInfos[2]; PalDescriptorBufferInfo descriptorBufferInfos[3]; - for (int i = 0; i < 3; i++) { descriptorBufferInfos[i].buffer = buffers[i]; descriptorBufferInfos[i].offset = 0; @@ -414,12 +398,13 @@ bool multiDescriptorSetTest() descriptorBufferInfos[i].stride = 16; // sizeof(vec4) or float4. } - for (int i = 0; i < 2; i++) { + PalDescriptorSetWriteInfo writeInfos[3]; + for (int i = 0; i < 3; i++) { writeInfos[i].layoutBindingIndex = 0; // single descriptor binding - writeInfos[i].bufferInfos = &descriptorBufferInfos[bufferOffsets[i]]; + writeInfos[i].bufferInfos = &descriptorBufferInfos[i]; writeInfos[i].descriptorSet = descriptorSets[i]; writeInfos[i].descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; - writeInfos[i].descriptorCount = bindingCounts[i]; + writeInfos[i].descriptorCount = 1; writeInfos[i].arrayElement = 0; writeInfos[i].imageViewInfos = nullptr; @@ -427,7 +412,7 @@ bool multiDescriptorSetTest() writeInfos[i].tlasInfos = nullptr; } - result = palUpdateDescriptorSet(device, 2, writeInfos); + result = palUpdateDescriptorSet(device, 3, writeInfos); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); @@ -443,8 +428,15 @@ bool multiDescriptorSetTest() pushConstantRange.shaderStages = shaderStages; // create pipeline layout + // even if the descriptor set layout is identical, pipeline layout creation needs + // a descriptor set layout per set (3) + PalDescriptorSetLayout* descriptorSetLayouts[3]; + descriptorSetLayouts[0] = descriptorSetLayout; + descriptorSetLayouts[1] = descriptorSetLayout; + descriptorSetLayouts[2] = descriptorSetLayout; + PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; - pipelineLayoutCreateInfo.descriptorSetLayoutCount = 2; + pipelineLayoutCreateInfo.descriptorSetLayoutCount = 3; pipelineLayoutCreateInfo.pushConstantRangeCount = 1; pipelineLayoutCreateInfo.descriptorSetLayouts = descriptorSetLayouts; pipelineLayoutCreateInfo.pushConstantRanges = &pushConstantRange; @@ -490,26 +482,24 @@ bool multiDescriptorSetTest() pushConstant.width = BUFFER_SIZE; pushConstant.height = BUFFER_SIZE; - // set 0 data - // red - pushConstant.setColor1[0] = 1.0f; - pushConstant.setColor1[1] = 0.0f; - pushConstant.setColor1[2] = 0.0f; - pushConstant.setColor1[3] = 1.0f; - - // green - pushConstant.setColor2[0] = 0.0f; - pushConstant.setColor2[1] = 1.0f; - pushConstant.setColor2[2] = 0.0f; - pushConstant.setColor2[3] = 1.0f; - - // set 1 data - // blue - pushConstant.set1Color[0] = 0.0f; + // set 1 data (red) + pushConstant.set1Color[0] = 1.0f; pushConstant.set1Color[1] = 0.0f; - pushConstant.set1Color[2] = 1.0f; + pushConstant.set1Color[2] = 0.0f; pushConstant.set1Color[3] = 1.0f; + // set 2 data(green) + pushConstant.set2Color[0] = 0.0f; + pushConstant.set2Color[1] = 1.0f; + pushConstant.set2Color[2] = 0.0f; + pushConstant.set2Color[3] = 1.0f; + + // set 3 data (blue) + pushConstant.set3Color[0] = 0.0f; + pushConstant.set3Color[1] = 0.0f; + pushConstant.set3Color[2] = 1.0f; + pushConstant.set3Color[3] = 1.0f; + result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -531,19 +521,14 @@ bool multiDescriptorSetTest() return false; } - result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSets[0]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind descriptor set: %s", error); - return false; - } - - // bind second descriptor set - result = palCmdBindDescriptorSet(cmdBuffer, 1, descriptorSets[1]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind descriptor set: %s", error); - return false; + // bind descriptor sets + for (int i = 0; i < 3; i++) { + result = palCmdBindDescriptorSet(cmdBuffer, i, descriptorSets[i]); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to bind descriptor set: %s", error); + return false; + } } // we will use a helper function to calculate the number of group count @@ -659,7 +644,11 @@ bool multiDescriptorSetTest() return false; } - const char* names[3] = { "compute_output1.ppm", "compute_output2.ppm", "compute_output3.ppm" }; + const char* names[3]; + names[0] = "set1_compute_output.ppm"; + names[1] = "set2_compute_output.ppm"; + names[2] = "set3_compute_output.ppm"; + for (int i = 0; i < 3; i++) { // now our staging buffer has the contents of the GPU buffer // we map it and copy the contents to a ppm buffer and save it @@ -698,9 +687,7 @@ bool multiDescriptorSetTest() palDestroyCommandPool(cmdPool); palDestroyDescriptorPool(descriptorPool); - for (int i = 0; i < 2; i++) { - palDestroyDescriptorSetLayout(descriptorSetLayouts[i]); - } + palDestroyDescriptorSetLayout(descriptorSetLayout); for (int i = 0; i < 3; i++) { palDestroyBuffer(buffers[i]); diff --git a/tests/graphics/shaders/bin/spirv/compute_multi.spv b/tests/graphics/shaders/bin/spirv/compute_multi.spv index 0943cd844703077bb226753e7670bc2ae11a22f2..7db5c33b7264b36656b6043220343805be3cc4a8 100644 GIT binary patch literal 2436 zcmZvc*-lhJ5QY!n0IsNjyEuS5iURJq0m_Jipy;(h7-W)hhBycH(hDEPD<8slGA@aU z-*@J;w!}^GDM* zb|r0DpfO#<6wq6c*GrX}8#|EQ;9`3+Ti+@PnQgEq$rqdg5piCDy{+t3R^02%cwSXs zl&bZYOVyd$+xqfSTB+A&?h#Xfe;;~bqp>zsuQk%8TH3(38*$gW%1XM14w&`V%9U4Z zsaP}LUK-_eWU5}RzsX{oxL*i9x*4}$@Uei~^8v8+<>vRC$F9^?%J0#Iq$9bCUW9*s zBVFG}CpT7C%a+M{a?iD1d0(#5yx(*k-+qYy6D-dpI6R~O<8jXw^Ee}TjQ@w{5jZ?! z|KoAb74yvD!(;p(o)V|#8E;39ASGtt%$?#VuYDv zoEOmgSJ3T_h($;xhj*+E}?mp99!&{E6H@N}t{#>-S-MXY}Q{hIVFR_Mz|n z5es$4bKm%z*v%fB`FHX?xvevS4s|B6_05|?%PD3ZeeY3RXByx0k;gj~c)UaU^30;m z5tB#X`xEob<9h~SE{oW{opVgf^Y(s;DFetA-jVs{xa{FOi2r(Pc$fTU&t2a;a6b2M z;mf%b@&3#cW!$bD6L+;Bw_%pYy$RUm*^7wTpIn}2HzIC~=j?ySyW#nVn4>xVnHcYC zA7Y;PCwRn;A>!Yt+mCkrWKX<^i20q`p`Sr)`*ALz)^Tj{(9cP1`|*B-m{Zu|p`X*( z=86BHMyRF!%7pCi3}S!I+4v%2uR~~;y&7{C5wlnAUrbY5Ec88$y}9oTVB(=~|EHVh zI07dAkuIG5C}N&?;2y)4J3gaJ_~IY(yvx|;ihIu953w+x8`xrU`i5>H_Tt+z#=Cwy zvyEv_d{=i7-=gPkzPxuc{g?MXe#~3KmvJw#sfOvGj1{Cni#~YY{QAvg%B<^P81j@{b@ z6;nnzV?4JP%!S5t`{L%bRN0gR=(Rz=JLnfZ*Jp53!k*6i-G`S}2VxlCEVvyg45RWK zn){*6B^mG&yl@F_yPNuwTi4qWW3+(#smI+fJ>eK$6AoRGkY~P51AG)uji|?~h)rMy zsA3q^Fa2L*c$)HKZ~AEf{m6rU&EdOouQ^*t(KZ9{ZI{6haq?ZLt$`omWR7~)=X?ul zyr0CG^EvDDh$n%0fZXzP Date: Fri, 22 May 2026 18:24:04 +0000 Subject: [PATCH 228/372] make multi descriptor test use 3 sets rather than 2 d3d12 --- .../shaders/bin/dxbc/compute_multi.dxbc | Bin 1456 -> 1584 bytes .../shaders/src/hlsl/compute_multi.hlsl | 19 +++++++++--------- tests/tests_main.c | 4 ++-- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/graphics/shaders/bin/dxbc/compute_multi.dxbc b/tests/graphics/shaders/bin/dxbc/compute_multi.dxbc index 006f77384a5570c4b7a822743ec41f20fe8d530d..85739f04d83619c3f265ee821330ba48df7267d7 100644 GIT binary patch literal 1584 zcmcgsJ#W)c6uoKs5h4aeiiB7&qDW;yN!keo)W%5&QcFwSp)8;XJJ^uM$bL~LBnC!c z>W0Js43#35&inv=LI;o-7!U(OOx@s|*e?lDNj-6;qx*Hf1N(P54nYsj|rYw_(Y~*se$|c6m z0`oEEpicsnPXJoz-}@e+rC zaOX7ZvHu&wxYjMi$vKV}g2%oDOFjEXy*N5cl^KxJBL|0?a@+3 zP1o@rxT^P9Ouyv^(roz+wTM$`fKwhVPjHq`FFFKkA+o+APSJD!jD5X7t>>yOXWMBj z>2|wGdL^x!l(*{L5B$(?Dr0`*vQb~LRt(E+*iK-W{`O<91*4F^QjnY0ja!*$B%xj# z@vVAw>m62n8y~2L{KJf-?ug9PUh-)TL~rsnb3Y1$1T5}~qI1Jfj5+!`7q64_{*LeA z6)WN`bD_z7h1Zkk^x1WhOfl|K1F!Zp&*Oc;|77NLoIe-qY^=}AWLn$Tag{T`MUfK& z{)A*l>SfVm55J^eUoP}}=o+b|C^Wnu-dXc$Q^xVR1I^d_7{|w_F1)+7xxBgCs~znW TX8-G8U)Cb@9bonTmhA)f^ejq->e;`1nC4jOZMMw%k(irOGp%#EF2N`HG z`5>dXU<8n<0OX;HrUFF`P(%}%oE6>yos^N9nVwO?kOU3}=lq=fB149>oczQR6Nc53 z4=^d%>HxJO$r>SZj1j?B9BmNGuma=`Bx|;SoHSX1Sw|FP3U=8A%s!kQK!*eZLpf>k iS7u{I#>tv2>XUO=&VYiQfpM}etM+6IR+Y&;tV;luk#eU1 diff --git a/tests/graphics/shaders/src/hlsl/compute_multi.hlsl b/tests/graphics/shaders/src/hlsl/compute_multi.hlsl index ad80ac82..30312f51 100644 --- a/tests/graphics/shaders/src/hlsl/compute_multi.hlsl +++ b/tests/graphics/shaders/src/hlsl/compute_multi.hlsl @@ -3,16 +3,15 @@ cbuffer PushConstants : register(b0) { uint width; uint height; - float4 bufferColor1; - float4 bufferColor2; - float4 bufferColor3; + float4 set1Color; + float4 set2Color; + float4 set3Color; }; // we use structured buffer for this example. -// Some drivers do not map the registers well if we declare as an array -// some use index 0 and so use index 1. -RWStructuredBuffer outBuffers[2] : register(u0, space0); // set 0 -RWStructuredBuffer outBuffer : register(u0, space1); // set 1 +RWStructuredBuffer set1OutBuffer : register(u0, space0); +RWStructuredBuffer set2OutBuffer : register(u0, space1); +RWStructuredBuffer set3OutBuffer : register(u0, space2); [numthreads(16, 16, 1)] void main(uint3 id : SV_DispatchThreadID) @@ -22,7 +21,7 @@ void main(uint3 id : SV_DispatchThreadID) } uint index = id.y * width + id.x; - outBuffers[0][index] = bufferColor1; - outBuffers[1][index] = bufferColor2; - outBuffer[index] = bufferColor3; + set1OutBuffer[index] = set1Color; + set2OutBuffer[index] = set2Color; + set3OutBuffer[index] = set3Color; } diff --git a/tests/tests_main.c b/tests/tests_main.c index 6a95ef2a..21fa4511 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -60,7 +60,7 @@ int main(int argc, char** argv) // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); - registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); + // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO @@ -70,7 +70,7 @@ int main(int argc, char** argv) // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); - // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); + registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From 0887f65ea944de720457a89c5acc32b9dd4afd7d Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 22 May 2026 19:29:55 +0000 Subject: [PATCH 229/372] disallow warp drivers: descriptor indexing test d3d12 --- src/graphics/pal_d3d12.c | 2 +- tests/graphics/clear_color_test.c | 5 +- tests/graphics/compute_test.c | 53 +++++------ tests/graphics/descriptor_indexing_test.c | 85 +++++++++--------- tests/graphics/geometry_test.c | 72 ++++++--------- tests/graphics/indirect_draw_test.c | 71 ++++++--------- tests/graphics/mesh_test.c | 67 ++++++-------- tests/graphics/multi_descriptor_set_test.c | 73 +++++---------- tests/graphics/ray_tracing_test.c | 69 ++++++-------- .../shaders/bin/dxbc/descriptor_indexing.dxbc | Bin 0 -> 1280 bytes .../shaders/src/hlsl/descriptor_indexing.hlsl | 38 ++++++++ tests/graphics/texture_test.c | 53 +++++------ tests/graphics/triangle_test.c | 53 +++++------ 13 files changed, 282 insertions(+), 359 deletions(-) create mode 100644 tests/graphics/shaders/bin/dxbc/descriptor_indexing.dxbc diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index f85a6a83..3b54bf94 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -7086,7 +7086,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( index = set->resourceOffset + bindingOffset + info->arrayElement; } - for (int j = 0; j < binding->range.NumDescriptors; j++) { + for (int j = 0; j < info->descriptorCount; j++) { D3D12_CPU_DESCRIPTOR_HANDLE dst; dst.ptr = getDescriptorHandleD3D12(index + j, heap->incrementSize, heap->cpuBase); diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index b57a0a79..d6dd9fd5 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -153,18 +153,17 @@ bool clearColorTest() } if (caps.maxGraphicsQueues == 0) { + adapter = nullptr; continue; } else { break; } - - adapter = nullptr; } palFree(nullptr, adapters); if (!adapter) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); + palLog(nullptr, "Failed to find a required adapter"); return false; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 7b92745f..f1f0e996 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -84,7 +84,6 @@ bool computeTest() PalAdapterCapabilities caps = {0}; PalAdapterFeatures adapterFeatures = 0; PalAdapterInfo adapterInfo = {0}; - bool hasComputeQueue = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -96,49 +95,41 @@ bool computeTest() } if (caps.maxComputeQueues == 0) { - hasComputeQueue = false; + adapter = nullptr; continue; - - } else { - hasComputeQueue = true; } - if (hasComputeQueue) { - // We want an adapter that supports spirv 1.0 or dxbc 5.1 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } + // We want an adapter that supports spirv 1.0 or dxbc 5.1 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } - // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { - break; - } + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { + break; } + } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { - break; - } + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + break; } } + adapter = nullptr; + continue; } palFree(nullptr, adapters); if (!adapter) { - if (!hasComputeQueue) { - palLog(nullptr, "Failed to find an adapter that supports compute queue"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } + palLog(nullptr, "Failed to find a required adapter"); return false; } diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index abc081d6..9d17deb3 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -193,10 +193,8 @@ bool descriptorIndexingTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; PalAdapterFeatures adapterFeatures; - bool hasGraphicsQueue = false; - bool hasDescriptorIndexing = false; for (Int32 i = 0; i < adapterCount; i++) { - adapter = adapters[i]; + adapter = adapters[2]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -206,62 +204,63 @@ bool descriptorIndexingTest() } if (caps.maxGraphicsQueues == 0) { - hasGraphicsQueue = false; + adapter = nullptr; continue; - - } else { - hasGraphicsQueue = true; } - if (hasGraphicsQueue) { - adapterFeatures = palGetAdapterFeatures(adapter); - if (adapterFeatures & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - hasDescriptorIndexing = true; + adapterFeatures = palGetAdapterFeatures(adapter); + if (!(adapterFeatures & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { + adapter = nullptr; + continue; + } - } else { - hasDescriptorIndexing = false; - } + // We want an adapter that supports spirv 1.4 or dxbc 5.1 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; } - if (hasDescriptorIndexing) { - // We want an adapter that supports spirv 1.4 or dxbc 5.1 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } + if (adapterInfo.apiType == PAL_ADAPTER_API_TYPE_D3D12 && + adapterInfo.type == PAL_ADAPTER_TYPE_CPU) { + // D3D12 WARP Adapter has a runtime limitation that causes dynamic indices to fold + // back to slot 0. This has been tested on multiple WARP drivers - // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - if (target >= PAL_MAKE_SHADER_TARGET(1, 4)) { - break; - } + // explicit registers work for this test but its not reliable for real usage + // Texture2D texs[] : register(t0, space0); // set 0 + // Texture2D tex17 : register(t17, space0); // set 0 + // Texture2D tex47 : register(t47, space0); // set 0 + // Texture2D tex55 : register(t55, space0); // set 0 + // Texture2D tex78 : register(t78, space0); // set 0 + + adapter = nullptr; + continue; + } + + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 4)) { + break; } + } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { - break; - } + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + break; } } + adapter = nullptr; + continue; } palFree(nullptr, adapters); if (!adapter) { - if (!hasGraphicsQueue) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - - } else if (!hasDescriptorIndexing) { - palLog(nullptr, "Failed to find an adapter that supports descriptor indexing"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } + palLog(nullptr, "Failed to find a required adapter"); return false; } diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index e98dc705..e797f488 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -146,10 +146,7 @@ bool geometryTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; - bool hasGraphicsQueue = false; - bool hasGeometryShader = false; PalAdapterFeatures adapterFeatures; - for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -161,62 +158,47 @@ bool geometryTest() } if (caps.maxGraphicsQueues == 0) { - hasGraphicsQueue = false; + adapter = nullptr; continue; - - } else { - hasGraphicsQueue = true; } - if (hasGraphicsQueue) { - adapterFeatures = palGetAdapterFeatures(adapter); - if (adapterFeatures & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { - hasGeometryShader = true; - - } else { - hasGeometryShader = false; - } + adapterFeatures = palGetAdapterFeatures(adapter); + if (!(adapterFeatures & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + adapter = nullptr; + continue; } - if (hasGeometryShader) { - // We want an adapter that supports spirv 1.0 or dxbc 5.1 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } - - // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { - break; - } + // We want an adapter that supports spirv 1.0 or dxbc 5.1 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { + break; } + } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { - break; - } + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + break; } } + adapter = nullptr; + continue; } palFree(nullptr, adapters); if (!adapter) { - if (!hasGraphicsQueue) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - - } else if (!hasGeometryShader) { - palLog(nullptr, "Failed to find an adapter that supports geometry shader"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } + palLog(nullptr, "Failed to find a required adapter"); return false; } diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 54c5b86d..1f63f4d1 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -164,8 +164,6 @@ bool indirectDrawTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; PalAdapterFeatures adapterFeatures; - bool hasGraphicsQueue = false; - bool hasIndirect = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -177,62 +175,47 @@ bool indirectDrawTest() } if (caps.maxGraphicsQueues == 0) { - hasGraphicsQueue = false; + adapter = nullptr; continue; - - } else { - hasGraphicsQueue = true; } - if (hasGraphicsQueue) { - adapterFeatures = palGetAdapterFeatures(adapter); - if (adapterFeatures & PAL_ADAPTER_FEATURE_INDIRECT_DRAW) { - hasIndirect = true; - - } else { - hasIndirect = false; - } + adapterFeatures = palGetAdapterFeatures(adapter); + if (!(adapterFeatures & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + adapter = nullptr; + continue; } - if (hasIndirect) { - // We want an adapter that supports spirv 1.0 or dxbc 5.1 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } - - // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { - break; - } + // We want an adapter that supports spirv 1.0 or dxbc 5.1 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } + + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { + break; } + } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { - break; - } + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + break; } } + adapter = nullptr; + continue; } palFree(nullptr, adapters); if (!adapter) { - if (!hasGraphicsQueue) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - - } else if (!hasIndirect) { - palLog(nullptr, "Failed to find an adapter that supports indirect draw"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } + palLog(nullptr, "Failed to find a required adapter"); return false; } diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 5352a89c..ca001c59 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -148,8 +148,6 @@ bool meshTest() PalAdapterCapabilities caps = {0}; PalAdapterFeatures adapterFeatures = 0; PalAdapterInfo adapterInfo = {0}; - bool hasGraphicsQueue = false; - bool hasMeshShader = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -161,58 +159,47 @@ bool meshTest() } if (caps.maxGraphicsQueues == 0) { - hasGraphicsQueue = false; + adapter = nullptr; continue; + } - } else { - hasGraphicsQueue = true; - adapterFeatures = palGetAdapterFeatures(adapter); - if (adapterFeatures & PAL_ADAPTER_FEATURE_MESH_SHADER) { - hasMeshShader = true; - } else { - hasMeshShader = false; - } + adapterFeatures = palGetAdapterFeatures(adapter); + if (!(adapterFeatures & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + adapter = nullptr; + continue; } - if (hasMeshShader) { - // We want an adapter that supports spirv 1.5 or dxil 6.5 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } + // We want an adapter that supports spirv 1.5 or dxil 6.5 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } - // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - if (target >= PAL_MAKE_SHADER_TARGET(1, 5)) { - break; - } + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 5)) { + break; } + } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - if (target >= PAL_MAKE_SHADER_TARGET(6, 5)) { - break; - } + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 5)) { + break; } } + adapter = nullptr; + continue; } palFree(nullptr, adapters); if (!adapter) { - if (!hasGraphicsQueue) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - - } else if (!hasMeshShader) { - palLog(nullptr, "Failed to find an adapter that supports mesh shader"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } + palLog(nullptr, "Failed to find a required adapter"); return false; } diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 1a64ebcb..06cb8a2f 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -88,9 +88,6 @@ bool multiDescriptorSetTest() PalAdapterCapabilities caps = {0}; PalAdapterFeatures adapterFeatures = 0; PalAdapterInfo adapterInfo = {0}; - bool hasComputeQueue = false; - bool hasRequiredPushConstantSize = false; - bool hasRequiredBoundDescriptorSets = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -102,75 +99,53 @@ bool multiDescriptorSetTest() } if (caps.maxComputeQueues == 0) { - hasComputeQueue = false; + adapter = nullptr; continue; - - } else { - hasComputeQueue = true; } // we want an adapter that supports the required bound descriptor sets (3) if (caps.resourceCaps.maxBoundSets < 3) { - hasRequiredBoundDescriptorSets = false; + adapter = nullptr; continue; - - } else { - hasRequiredBoundDescriptorSets = true; } // we want an adapter that supports the required push constant size (64 bytes) if (caps.maxPushConstantSize < 64) { - hasRequiredPushConstantSize = false; + adapter = nullptr; continue; - - } else { - hasRequiredPushConstantSize = true; } - if (hasComputeQueue) { - // We want an adapter that supports spirv 1.0 or dxbc 5.1 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } + // We want an adapter that supports spirv 1.0 or dxbc 5.1 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } - // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { - break; - } + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { + break; } + } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { - break; - } + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + break; } } + adapter = nullptr; + continue; } palFree(nullptr, adapters); if (!adapter) { - if (!hasComputeQueue) { - palLog(nullptr, "Failed to find an adapter that supports compute queue"); - - } else if (!hasRequiredBoundDescriptorSets) { - palLog( - nullptr, - "Failed to find an adapter that has the required bound descriptor sets"); - - } else if (!hasRequiredPushConstantSize) { - palLog(nullptr, "Failed to find an adapter that has the required push constant size"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } + palLog(nullptr, "Failed to find a required adapter"); return false; } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index bfbcf94d..190fe7ce 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -98,8 +98,6 @@ bool rayTracingTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; PalAdapterFeatures adapterFeatures = 0; - bool hasGraphicsQueue = false; - bool hasTracing = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -112,58 +110,47 @@ bool rayTracingTest() // Ray tracing is generally implemented on the graphics queue if (caps.maxGraphicsQueues == 0) { - hasGraphicsQueue = false; + adapter = nullptr; continue; - - } else { - hasGraphicsQueue = true; - adapterFeatures = palGetAdapterFeatures(adapter); - if (adapterFeatures & PAL_ADAPTER_FEATURE_RAY_TRACING) { - hasTracing = true; - } else { - hasTracing = false; - } } - if (hasTracing) { - // We want an adapter that supports spirv 1.4 or dxil 6.3 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } + adapterFeatures = palGetAdapterFeatures(adapter); + if (!(adapterFeatures & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + adapter = nullptr; + continue; + } + + // We want an adapter that supports spirv 1.4 or dxil 6.3 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; + } - // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - if (target >= PAL_MAKE_SHADER_TARGET(1, 4)) { - break; - } + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 4)) { + break; } + } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); - if (target >= PAL_MAKE_SHADER_TARGET(6, 3)) { - break; - } + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 3)) { + break; } } + adapter = nullptr; + continue; } palFree(nullptr, adapters); if (!adapter) { - if (!hasGraphicsQueue) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - - } else if (!hasTracing) { - palLog(nullptr, "Failed to find an adapter that supports ray tracing"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } + palLog(nullptr, "Failed to find a required adapter"); return false; } diff --git a/tests/graphics/shaders/bin/dxbc/descriptor_indexing.dxbc b/tests/graphics/shaders/bin/dxbc/descriptor_indexing.dxbc new file mode 100644 index 0000000000000000000000000000000000000000..a319f05e4d7ef98da0c8fe14b98d8d8a678b2000 GIT binary patch literal 1280 zcmb_cL2nXK5S}g25>g{+Q`6L_8-qzTrh&$o9*n^*tdP`#?AFj;6uaAku`FS?si)S1 z7cYA82lS3d6XV6J7k`HS0e^t_&D%G1i&rOn%)D>jd~bI4L8ZNJP4Db~K1sb_`F3)& zv^LZ8XGd#~ziq{foRGcLsUeds&x1NQ^sO90of@!1SE T_Iyud&0Nx?Cdu*t!T+#7nu&6J literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/src/hlsl/descriptor_indexing.hlsl b/tests/graphics/shaders/src/hlsl/descriptor_indexing.hlsl index e69de29b..c49fe33f 100644 --- a/tests/graphics/shaders/src/hlsl/descriptor_indexing.hlsl +++ b/tests/graphics/shaders/src/hlsl/descriptor_indexing.hlsl @@ -0,0 +1,38 @@ + +Texture2D texs[] : register(t0, space0); // set 0 +SamplerState samp : register(s0, space0); // set 0 + +cbuffer PushConstants : register(b0) +{ + uint textureIndices[4]; +}; + +struct PSInput +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD; +}; + +float4 main(PSInput input) : SV_Target +{ + int quadrant = 0; // quad is centered + if (input.pos.x < 320.0 && input.pos.y < 240.0) { + // red texture + quadrant = 0; + + } else if (input.pos.x >= 320.0 && input.pos.y < 240.0) { + // green texture + quadrant = 1; + + } else if (input.pos.x < 320.0 && input.pos.y >= 240.0) { + // blue texture + quadrant = 2; + + } else { + // yellow texture + quadrant = 3; + } + + uint index = textureIndices[quadrant]; + return texs[NonUniformResourceIndex(index)].Sample(samp, input.uv); +} \ No newline at end of file diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 3507bfce..24b89987 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -185,7 +185,6 @@ bool textureTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; - bool hasGraphicsQueue = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -197,49 +196,41 @@ bool textureTest() } if (caps.maxGraphicsQueues == 0) { - hasGraphicsQueue = false; + adapter = nullptr; continue; + } - } else { - hasGraphicsQueue = true; + // We want an adapter that supports spirv 1.0 or dxbc 5.1 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; } - if (hasGraphicsQueue) { - // We want an adapter that supports spirv 1.0 or dxbc 5.1 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } - - // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { - break; - } + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { + break; } + } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { - break; - } + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + break; } } + adapter = nullptr; + continue; } palFree(nullptr, adapters); if (!adapter) { - if (!hasGraphicsQueue) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } + palLog(nullptr, "Failed to find a required adapter"); return false; } diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 9de72309..30a8f5ac 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -151,7 +151,6 @@ bool triangleTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; - bool hasGraphicsQueue = false; for (Int32 i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); @@ -163,49 +162,41 @@ bool triangleTest() } if (caps.maxGraphicsQueues == 0) { - hasGraphicsQueue = false; + adapter = nullptr; continue; + } - } else { - hasGraphicsQueue = true; + // We want an adapter that supports spirv 1.0 or dxbc 5.1 + result = palGetAdapterInfo(adapter, &adapterInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to get adapter info: %s", error); + return false; } - if (hasGraphicsQueue) { - // We want an adapter that supports spirv 1.0 or dxbc 5.1 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); - return false; - } - - // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); - if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { - break; - } + // we prefer spirv first if an adapter supports multiple shader formats + Uint32 target = 0; + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); + if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { + break; } + } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { - break; - } + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); + if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + break; } } + adapter = nullptr; + continue; } palFree(nullptr, adapters); if (!adapter) { - if (!hasGraphicsQueue) { - palLog(nullptr, "Failed to find an adapter that supports graphics queue"); - - } else { - palLog(nullptr, "Failed to find an adapter that supports required shader target"); - } + palLog(nullptr, "Failed to find a required adapter"); return false; } From 0ef257eaf07b94600a2157a3ef389f147f599f27 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 25 May 2026 20:32:43 +0000 Subject: [PATCH 230/372] add multiple shader entry API --- include/pal/pal_graphics.h | 236 +++++++++--------- src/graphics/pal_vulkan.c | 194 +++++++++----- tests/graphics/compute_test.c | 16 +- tests/graphics/descriptor_indexing_test.c | 31 +-- tests/graphics/geometry_test.c | 20 +- tests/graphics/indirect_draw_test.c | 15 +- tests/graphics/mesh_test.c | 15 +- tests/graphics/multi_descriptor_set_test.c | 16 +- tests/graphics/ray_tracing_test.c | 104 ++++---- .../shaders/bin/dxil/ray_tracing.hlsl | 65 +++++ .../shaders/bin/spirv/ray_tracing.spv | Bin 0 -> 2996 bytes tests/graphics/texture_test.c | 27 +- tests/graphics/triangle_test.c | 15 +- tests/tests_main.c | 4 +- 14 files changed, 457 insertions(+), 301 deletions(-) create mode 100644 tests/graphics/shaders/bin/dxil/ray_tracing.hlsl create mode 100644 tests/graphics/shaders/bin/spirv/ray_tracing.spv diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d755053a..9c6d3838 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1578,14 +1578,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool independentResolve; /**< If false, depth and stencil resolve modes must be the same.*/ - - /** Bool array of supported depth resolve modes. - * (eg. depthResolves[`PAL_RESOLVE_MODE_SAMPLE_ZERO`]).*/ + bool independentResolve; bool depthResolves[PAL_MAX_RESOLVE_MODES]; - - /** Bool array of supported stencil resolve modes. - * (eg. stencilResolves[`PAL_RESOLVE_MODE_SAMPLE_ZERO`]).*/ bool stencilResolves[PAL_MAX_RESOLVE_MODES]; } PalDepthStencilCapabilities; @@ -1597,16 +1591,11 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - /** Bool array of supported fragment shading rates. - * (eg. shadingRates[`PAL_FRAGMENT_SHADING_RATE_2X1`]).*/ bool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; Uint32 minTexelWidth; Uint32 minTexelHeight; Uint32 maxTexelWidth; Uint32 maxTexelHeight; - - /** Bool array of supported fragment shading rate combiner operations. - * (eg. combinerOps[`PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP`]).*/ bool combinerOps[PAL_MAX_COMBINER_OPS]; } PalFragmentShadingRateCapabilities; @@ -1681,16 +1670,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - /** Bool array of supported present modes. - * (eg. presentModes[`PAL_PRESENT_MODE_FIFO`]).*/ bool presentModes[PAL_PRESENT_MODE_MAX]; - - /** Bool array of supported composite alphas. - * (eg. compositeAlphas[`PAL_COMPOSITE_ALPHA_OPAQUE`]).*/ bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; - - /** Bool array of supported swapchain formats. - * (eg. formats[`PAL_COMPOSITE_ALPHA_OPAQUE`]).*/ bool formats[PAL_SURFACE_FORMAT_MAX]; Uint32 minImageCount; Uint32 maxImageCount; @@ -1760,9 +1741,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - float color[4]; /**< Color for color attachments.*/ - float depth; /**< Depth for depth stencil attachments.*/ - Uint32 stencil; /**< Stencil for depth stencil attachments.*/ + float color[4]; /**< Color for color attachments only.*/ + float depth; + Uint32 stencil; } PalClearValue; /** @@ -1840,10 +1821,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - /** Bool array of supported memory types. - * (eg. memoryTypes[`PAL_MEMORY_TYPE_GPU_ONLY`]).*/ bool memoryTypes[PAL_MEMORY_TYPE_MAX]; - Uint64 memoryMask; Uint64 size; Uint32 alignment; @@ -1938,15 +1916,13 @@ typedef struct { * @struct PalWorkGroupBuildData * @brief Compute or Mesh(or Task) workgroup input data build helper. * - * Uninitialized fields may result in undefined behavior. + * Uninitialized fields may result in undefined behavior. `workCount` can be specified in pixels, + * vertices etc.Eg. an image of 800 x 600 will be [0] = 800, [1] = 600 and [2] = 1. * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - /** Workcount can be specified in pixels, vertices etc. - * eg. an image of 800 x 600 will have a workcount of workCount[0] = 800, - * workCount[1] = 600, workCount[2] = 1.*/ Uint32 workCount[3]; Uint32 workGroupSize[3]; /**< Threads per workgroup per axis of the adapter (GPU).*/ Uint32 workGroupCount[3]; /**< Workgroups per axis of the adapter (GPU).*/ @@ -1974,10 +1950,10 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 vertexCount; /**< Number of vertices to draw.*/ - Uint32 instanceCount; /**< Number of instances to draw. Set to 1 if not using instanced draw.*/ - Uint32 firstVertex; /**< First vertex. Set to 0 for default behavior.*/ - Uint32 firstInstance; /**< First instance. Set to 0 for default behavior.*/ + Uint32 vertexCount; + Uint32 instanceCount; + Uint32 firstVertex; + Uint32 firstInstance; } PalDrawIndirectData; /** @@ -1990,11 +1966,11 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 indexCount; /**< Number of indices to draw.*/ - Uint32 instanceCount; /**< Number of instances to draw. Set to 1 if not using instanced draw.*/ - Uint32 firstIndex; /**< First index. Set to 0 for default behavior.*/ - Int32 vertexOffset; /**< Vertex offset. Set to 0 for default behavior.*/ - Uint32 firstInstance; /**< First instance. Set to 0 for default behavior.*/ + Uint32 indexCount; + Uint32 instanceCount; + Uint32 firstIndex; + Int32 vertexOffset; + Uint32 firstInstance; } PalDrawIndexedIndirectData; /** @@ -2016,18 +1992,16 @@ typedef struct { * @struct PalVertexAttribute * @brief Vertex attribute. * - * Uninitialized fields may result in undefined behavior. + * Uninitialized fields may result in undefined behavior. `semanticName` Must not include the index + * (eg. "position" or "myown"). Set to nullptr to use the default that will be derived from ` + * semanticID` which are (`POSITION`, `COLOR`, `TEXCOORD`, `NORMAL` and `TANGENT`). * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - PalVertexSemanticID semanticID; /**< (eg. PAL_VERTEX_SEMANTIC_ID_POSITION).*/ - PalVertexType type; /**< (eg. PAL_VERTEX_TYPE_FLOAT).*/ - - /** Must not include the index (eg. "position" or "myown"). Set to nullptr to use the default - * that will be derived from `semanticID` which are - * (`POSITION`, `COLOR`, `TEXCOORD`, `NORMAL` and `TANGENT`).*/ + PalVertexSemanticID semanticID; + PalVertexType type; const char* semanticName; } PalVertexAttribute; @@ -2047,7 +2021,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - PalVertexLayoutType type; /**< (eg. PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX).*/ + PalVertexLayoutType type; Uint32 binding; Uint32 attributeCount; PalVertexAttribute* attributes; @@ -2063,9 +2037,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool denyGeneral; /**< Disable general messages.*/ - bool denyValidation; /**< Disable validation messages.*/ - bool denyPerformance; /**< Disable performance messages.*/ + bool denyGeneral; + bool denyValidation; + bool denyPerformance; bool denyInfoSeverity; bool denyWarningSeverity; bool denyErrorSeverity; @@ -2088,9 +2062,9 @@ typedef struct { float depthBiasConstant; float depthBiasSlope; float depthBiasClamp; - PalPolygonMode polygonMode; /**< (eg. PAL_POLYGON_MODE_FILL).*/ - PalCullMode cullMode; /**< (eg. PAL_CULL_MODE_BACK).*/ - PalFrontFace frontFace; /**< (eg. PAL_FRONT_FACE_CLOCKWISE).*/ + PalPolygonMode polygonMode; + PalCullMode cullMode; + PalFrontFace frontFace; } PalRasterizerState; /** @@ -2177,7 +2151,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - PalFragmentShadingRate rate; /**< (eg. PAL_FRAGMENT_SHADING_RATE_2X1).*/ + PalFragmentShadingRate rate; PalFragmentShadingRateCombinerOp combinerOps[2]; } PalFragmentShadingRateState; @@ -2191,11 +2165,11 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 instanceId; /**< User defined id.*/ + Uint32 instanceId; Uint32 mask; Uint32 hitGroupOffset; PalAccelerationStructureInstanceFlags flags; - PalAccelerationStructure* blas; /**< BLAS to use.*/ + PalAccelerationStructure* blas; float transform[12]; /**< row major (3x4).*/ } PalAccelerationStructureInstance; @@ -2207,9 +2181,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 accelerationStructureSize; /**< Required acceleration structure size.*/ - Uint32 scratchBufferSize; /**< Required scratch buffer size.*/ - Uint32 updateScratchBufferSize; /**< Required scratch buffer size for updates.*/ + Uint32 accelerationStructureSize; + Uint32 scratchBufferSize; + Uint32 updateScratchBufferSize; } PalAccelerationStructureBuildSize; /** @@ -2222,8 +2196,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - PalVertexType vertexType; /**< (eg. PAL_VERTEX_TYPE_FLOAT3).*/ - PalIndexType indexType; /**< (eg. PAL_INDEX_TYPE_UINT32). If indexBufferAddress is not 0.*/ + PalVertexType vertexType; + PalIndexType indexType; Uint32 vertexStride; Uint32 indexCount; Uint32 vertexCount; @@ -2257,7 +2231,7 @@ typedef struct { typedef struct { PalGeometryFlags flags; Uint32 primitiveCount; - PalGeometryType type; /**< (eg. PAL_GEOMETRY_TYPE_TRIANGLE).*/ + PalGeometryType type; void* data; /**< Pointer to geometry data. This will be casted based on the geometry type.*/ } PalGeometry; @@ -2271,7 +2245,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - PalAccelerationStructureType type; /**< (eg. PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL).*/ + PalAccelerationStructureType type; Uint32 geometryCount; Uint32 instanceCount; PalAccelerationStructureBuildHints buildHints; @@ -2294,9 +2268,7 @@ typedef struct { */ typedef struct { Uint32 descriptorCount; - Uint32 shaderStageCount; - PalShaderStage* shaderStages; /**< Array of shader stages that can access the descriptor.*/ - PalDescriptorType descriptorType; /**< (eg. PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER).*/ + PalDescriptorType descriptorType; } PalDescriptorSetLayoutBinding; /** @@ -2310,8 +2282,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 bindingCount; /**< Number of descriptors of `descriptorType` that will be used.*/ - PalDescriptorType descriptorType; /**< (eg. PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER).*/ + Uint32 bindingCount; + PalDescriptorType descriptorType; } PalDescriptorPoolBindingSize; /** @@ -2384,10 +2356,10 @@ typedef struct { Uint32 descriptorCount; PalDescriptorType descriptorType; PalDescriptorSet* descriptorSet; - PalDescriptorBufferInfo* bufferInfos; /**< If PAL_DESCRIPTOR_TYPE* uniform or storage buffer.*/ - PalDescriptorImageViewInfo* imageViewInfos; /**< If PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE*/ - PalDescriptorSamplerInfo* samplerInfos; /**< If PAL_DESCRIPTOR_TYPE_SAMPLER.*/ - PalDescriptorTLASInfo* tlasInfos; /**< If PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE.*/ + PalDescriptorBufferInfo* bufferInfos; + PalDescriptorImageViewInfo* imageViewInfos; + PalDescriptorSamplerInfo* samplerInfos; + PalDescriptorTLASInfo* tlasInfos; } PalDescriptorSetWriteInfo; /** @@ -2403,7 +2375,7 @@ typedef struct { Uint64 offset; Uint64 size; Uint32 shaderStageCount; - PalShaderStage* shaderStages; /**< Array of shader stages that can access the push constant.*/ + PalShaderStage* shaderStages; } PalPushConstantRange; /** @@ -2507,6 +2479,21 @@ typedef struct { void* localData; } PalShaderBindingTableRecordInfo; +/** + * @struct PalShaderEntryInfo + * @brief Entry information of a shader. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef struct { + Uint32 patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ + PalShaderStage stage; + const char* entryName; +} PalShaderEntryInfo; + /** * @struct PalImageCreateInfo * @brief Creation parameters for an image. @@ -2517,14 +2504,14 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 width; /**< Width of the image in pixels.*/ - Uint32 height; /**< Height of the image in pixels.*/ + Uint32 width; + Uint32 height; Uint32 depthOrArraySize; Uint32 mipLevelCount; PalSampleCount sampleCount; - PalImageType type; /**< (eg. PAL_IMAGE_TYPE_2D).*/ - PalFormat format; /**< Format of the image.*/ - PalImageUsages usages; /**< (eg. PAL_IMAGE_USAGE_COLOR_ATTACHEMENT).*/ + PalImageType type; + PalFormat format; + PalImageUsages usages; } PalImageCreateInfo; /** @@ -2538,7 +2525,7 @@ typedef struct { */ typedef struct { PalFormat format; /**< Must be compatible with the image format.*/ - PalImageViewType type; /**< (eg. PAL_IMAGE_VIEW_TYPE_2D).*/ + PalImageViewType type; PalImageSubresourceRange subresourceRange; } PalImageViewCreateInfo; @@ -2579,13 +2566,13 @@ typedef struct { */ typedef struct { bool clipped; - Uint32 width; /**< Width of the swapchain in pixels.*/ - Uint32 height; /**< Height of the swapchain in pixels.*/ - Uint32 imageCount; /**< Number of swapchain images.*/ - Uint32 imageArrayLayerCount; /**< Set to 1 for default.*/ - PalPresentMode presentMode; /**< (eg. PAL_PRESENT_MODE_FIFO).*/ - PalCompositeAplha compositeAlpha; /**< (eg. PAL_COMPOSITE_ALPHA_OPAQUE).*/ - PalSurfaceFormat format; /**< (eg. PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR).*/ + Uint32 width; + Uint32 height; + Uint32 imageCount; + Uint32 imageArrayLayerCount; + PalPresentMode presentMode; + PalCompositeAplha compositeAlpha; + PalSurfaceFormat format; } PalSwapchainCreateInfo; /** @@ -2598,11 +2585,10 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ - PalShaderStage stage; + Uint32 entryCount; Uint64 bytecodeSize; void* bytecode; - const char* entryName; + PalShaderEntryInfo* entries; } PalShaderCreateInfo; /** @@ -2615,7 +2601,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - PalBufferUsages usages; /**< (eg. PAL_BUFFER_USAGE_STORAGE).*/ + PalBufferUsages usages; Uint64 size; } PalBufferCreateInfo; @@ -2629,7 +2615,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - PalAccelerationStructureType type; /**< (eg. PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL).*/ + PalAccelerationStructureType type; PalBuffer* buffer; Uint64 offset; Uint64 size; @@ -2639,29 +2625,31 @@ typedef struct { * @struct PalDescriptorSetLayoutCreateInfo * @brief Creation parameters for a descriptor set layout. * - * Uninitialized fields may result in undefined behavior. + * Uninitialized fields may result in undefined behavior. Set `enableDescriptorIndexing` to + * true to enable descriptor indexing for the descriptor set layout. * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - /** If true `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled.*/ bool enableDescriptorIndexing; Uint32 bindingCount; + Uint32 shaderStageCount; + PalShaderStage* shaderStages; PalDescriptorSetLayoutBinding* bindings; } PalDescriptorSetLayoutCreateInfo; /** * @struct PalDescriptorPoolCreateInfo * @brief Creation parameters for a descriptor pool. - * - * Uninitialized fields may result in undefined behavior. + * + * Uninitialized fields may result in undefined behavior. Set `enableDescriptorIndexing` to + * true to enable descriptor indexing for the descriptor pool. * * @since 1.4 * @ingroup pal_graphics */ typedef struct { - /** If true `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled.*/ bool enableDescriptorIndexing; Uint32 maxDescriptorSets; Uint32 maxDescriptorBindingSizes; @@ -2694,7 +2682,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool primitiveRestartEnable; /**< False to disable.*/ + bool primitiveRestartEnable; Uint32 vertexLayoutCount; Uint32 colorBlendAttachmentCount; Uint32 shaderCount; @@ -2703,11 +2691,11 @@ typedef struct { PalPipelineLayout* pipelineLayout; PalShader** shaders; PalVertexLayout* vertexLayouts; - PalColorBlendAttachment* colorBlendAttachments; /**< Depth only: Can be nullptr.*/ - PalRasterizerState* rasterizerState; /**< Set to nullptr for default.*/ - PalMultisampleState* multisampleState; /**< Set to nullptr for default.*/ - PalDepthStencilState* depthStencilState; /**< Color only: Can be nullptr.*/ - PalFragmentShadingRateState* fragmentShadingRateState; /**< Set to nullptr for default.*/ + PalColorBlendAttachment* colorBlendAttachments; + PalRasterizerState* rasterizerState; + PalMultisampleState* multisampleState; + PalDepthStencilState* depthStencilState; + PalFragmentShadingRateState* fragmentShadingRateState; PalRenderingLayoutInfo* renderingLayout; } PalGraphicsPipelineCreateInfo; @@ -2737,11 +2725,15 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - PalRayTracingShaderGroupType type; /**< (eg. PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL).*/ - Uint32 anyHitShaderIndex; /**< Index of any hit shader from shader array.*/ - Uint32 closestHitShaderIndex; /**< Index of closest hit shader from shader array.*/ - Uint32 generalShaderIndex; /**< Index of general hit shader from shader array.*/ - Uint32 intersectionShaderIndex; /**< Index of intersection hit shader from shader array.*/ + PalRayTracingShaderGroupType type; + Uint32 anyHitShaderIndex; + Uint32 anyHitShaderEntryIndex; + Uint32 closestHitShaderIndex; + Uint32 closestHitShaderEntryIndex; + Uint32 generalShaderIndex; + Uint32 generalShaderEntryIndex; + Uint32 intersectionShaderIndex; + Uint32 intersectionShaderEntryIndex; Uint32 maxDataSize; /**< Size of extra data associated with the shader group.*/ } PalRayTracingShaderGroupCreateInfo; @@ -2761,8 +2753,8 @@ typedef struct { Uint32 maxAttributeSize; Uint32 maxPayloadSize; PalPipelineLayout* pipelineLayout; - PalRayTracingShaderGroupCreateInfo* shaderGroups; /**< Array of shader group create info.*/ - PalShader** shaders; /**< Array of shader stage. This is used by `shaderGroups`.*/ + PalRayTracingShaderGroupCreateInfo* shaderGroups; + PalShader** shaders; } PalRayTracingPipelineCreateInfo; /** @@ -7123,10 +7115,11 @@ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); * @brief Create a descriptor set layout that defines the bindings used by descriptor sets. * * The graphics system must be initialized before this call. - * - * Enable `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` when creating the device for descriptor - * indexing (bindless resources). The feature must be supported by the device if not, - * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * Set PalDescriptorSetLayoutCreateInfo::enableDescriptorIndexing to true to enable + * descriptor indexing on the descriptor set layout. `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` + * must be supported and enabled when creating the device if not, this function will fail and + * return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * This defines the layout, ordering and the number of descriptors a descriptor set uses. * @@ -7176,10 +7169,11 @@ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layo * @brief Create a descriptor pool to allocate descriptor sets. * * The graphics system must be initialized before this call. - * - * Enable `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` when creating the device for descriptor - * indexing (bindless resources). The feature must be supported by the device if not, - * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * Set PalDescriptorPoolCreateInfo::enableDescriptorIndexing to true to enable + * descriptor indexing on the descriptor pool. `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` + * must be supported and enabled when creating the device if not, this function will fail and + * return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device that creates the descriptor pool. * @param[in] info Pointer to a PalDescriptorPoolCreateInfo struct that specifies parameters. @@ -7239,7 +7233,11 @@ PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); * @brief Allocate a descriptor set from the provided descriptor pool. * * The graphics system must be initialized before this call. The descriptor set will be - * allocated uninitialized therefore update it before use. + * allocated uninitialized therefore update it before use except the case where descriptor + * indexing is enabled. + * + * `pool` and `layout` must either be created with descriptor indexing enabled or not. Any other + * pair will fail and return `PAL_RESULT_INVALID_OPERATION`. * * @param[in] device Device to allocate descriptor set on. * @param[in] pool Descriptor pool to allocate descriptor set from. @@ -7363,6 +7361,8 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. + * + * @note The first entry of the compute shader will be used. * * @since 1.4 * @ingroup pal_graphics diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 6fac6b48..5bbe4ea3 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -478,13 +478,18 @@ typedef struct { } Swapchain; typedef struct { - const PalGraphicsBackend* backend; - Uint32 patchControlPoints; VkShaderStageFlagBits stage; + char entryName[PAL_SHADER_ENTRY_NAME_SIZE]; +} ShaderEntry; + +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 entryCount; + ShaderEntry* entries; Device* device; VkShaderModule handle; - char entryName[PAL_SHADER_ENTRY_NAME_SIZE]; } Shader; typedef struct { @@ -544,6 +549,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + bool hasDescriptorIndexing; Device* device; VkDescriptorSetLayout handle; } DescriptorSetLayout; @@ -551,6 +557,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + bool hasDescriptorIndexing; Device* device; VkDescriptorPool handle; } DescriptorPool; @@ -6162,35 +6169,50 @@ PalResult PAL_CALL createShaderVk( return PAL_RESULT_OUT_OF_MEMORY; } - // clang-format off - if (info->stage == PAL_SHADER_STAGE_MESH || - info->stage == PAL_SHADER_STAGE_TASK) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + // allocate entries array + shader->entries = palAllocate(s_Vk.allocator, sizeof(ShaderEntry) * info->entryCount, 0); + if (!shader->entries) { + return PAL_RESULT_OUT_OF_MEMORY; + } - } else if (info->stage == PAL_SHADER_STAGE_GEOMETRY) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + for (int i = 0; i < info->entryCount; i++) { + ShaderEntry* entry = &shader->entries[i]; - } else if (info->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || - info->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + // clang-format off + if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || + info->entries[i].stage == PAL_SHADER_STAGE_TASK) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } - } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || - info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || - info->stage == PAL_SHADER_STAGE_ANY_HIT || - info->stage == PAL_SHADER_STAGE_MISS || - info->stage == PAL_SHADER_STAGE_INTERSECTION || - info->stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } else if (info->entries[i].stage == PAL_SHADER_STAGE_GEOMETRY) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || + info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || + info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_MISS || + info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || + info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } } + // clang-format on + + strncpy(entry->entryName, info->entries[i].entryName, PAL_SHADER_ENTRY_NAME_SIZE); + entry->entryName[PAL_SHADER_ENTRY_NAME_SIZE - 1] = '\0'; + entry->patchControlPoints = info->entries[i].patchControlPoints; + entry->stage = shaderStageToVK(info->entries[i].stage); } - // clang-format on VkShaderModuleCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; @@ -6203,12 +6225,8 @@ PalResult PAL_CALL createShaderVk( return resultFromVk(result); } - strncpy(shader->entryName, info->entryName, PAL_SHADER_ENTRY_NAME_SIZE); - shader->entryName[PAL_SHADER_ENTRY_NAME_SIZE - 1] = '\0'; - shader->patchControlPoints = info->patchControlPoints; - shader->stage = shaderStageToVK(info->stage); - shader->device = vkDevice; + shader->entryCount = info->entryCount; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } @@ -6218,6 +6236,7 @@ void PAL_CALL destroyShaderVk(PalShader* shader) Shader* vkShader = (Shader*)shader; s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkShader->entries); palFree(s_Vk.allocator, vkShader); } @@ -8476,6 +8495,12 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( createInfo.bindingCount = count; createInfo.pBindings = bindings; + VkShaderStageFlags stageFlags = 0; + for (int i = 0; i < info->shaderStageCount; i++) { + VkShaderStageFlagBits bit = shaderStageToVK(info->shaderStages[i]); + stageFlags |= bit; + } + Uint32 bindingIndex = 0; for (int i = 0; i < count; i++) { VkDescriptorSetLayoutBinding* binding = &bindings[i]; @@ -8484,12 +8509,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( binding->descriptorType = descriptortypeToVk(info->bindings[i].descriptorType); binding->pImmutableSamplers = nullptr; - binding->stageFlags = 0; - for (int j = 0; j < info->bindings[i].shaderStageCount; j++) { - VkShaderStageFlagBits bit = shaderStageToVK(info->bindings[i].shaderStages[j]); - binding->stageFlags |= bit; - } - + binding->stageFlags = stageFlags; if (bindingFlags) { bindingFlags[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; bindingFlags[i] |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; @@ -8520,6 +8540,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( } layout->device = vkDevice; + layout->hasDescriptorIndexing = info->enableDescriptorIndexing; palFree(s_Vk.allocator, bindings); *outLayout = (PalDescriptorSetLayout*)layout; return PAL_RESULT_SUCCESS; @@ -8587,6 +8608,7 @@ PalResult PAL_CALL createDescriptorPoolVk( } pool->device = vkDevice; + pool->hasDescriptorIndexing = info->enableDescriptorIndexing; palFree(s_Vk.allocator, poolSizes); *outPool = (PalDescriptorPool*)pool; return PAL_RESULT_SUCCESS; @@ -8618,6 +8640,10 @@ PalResult PAL_CALL allocateDescriptorSetVk( DescriptorSetLayout* vkLayout = (DescriptorSetLayout*)layout; DescriptorSet* set = nullptr; + if (vkPool->hasDescriptorIndexing != vkLayout->hasDescriptorIndexing) { + return PAL_RESULT_INVALID_OPERATION; + } + set = palAllocate(s_Vk.allocator, sizeof(DescriptorSet), 0); if (!set) { return PAL_RESULT_OUT_OF_MEMORY; @@ -8938,39 +8964,51 @@ PalResult PAL_CALL createGraphicsPipelineVk( createInfo.renderPass = VK_NULL_HANDLE; createInfo.layout = layout->handle; + // find the total number of shader stages + Uint32 stageCount = 0; + for (int i = 0; i < info->shaderCount; i++) { + Shader* shader = (Shader*)info->shaders[i]; + stageCount += shader->entryCount; + } + pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); shaderStages = palAllocate( s_Vk.allocator, - sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount, + sizeof(VkPipelineShaderStageCreateInfo) * stageCount, 0); - if (!pipeline) { + if (!pipeline || !shaderStages) { return PAL_RESULT_OUT_OF_MEMORY; } // shaders - memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount); + Uint32 stageIndex = 0; + memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stageCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; - VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[i]; - if (tmp->patchControlPoints) { - tessellationState.patchControlPoints = tmp->patchControlPoints; - createInfo.pTessellationState = &tessellationState; + for (int j = 0; j < tmp->entryCount; j++) { + ShaderEntry* entry = &tmp->entries[j]; + VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex++]; + + if (entry->patchControlPoints) { + tessellationState.patchControlPoints = entry->patchControlPoints; + createInfo.pTessellationState = &tessellationState; - if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { - palFree(s_Vk.allocator, pipeline); - return PAL_RESULT_INVALID_OPERATION; + if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { + palFree(s_Vk.allocator, pipeline); + return PAL_RESULT_INVALID_OPERATION; + } } - } - stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo->module = tmp->handle; - stageInfo->pName = tmp->entryName; - stageInfo->stage = tmp->stage; + stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageInfo->module = tmp->handle; + stageInfo->pName = entry->entryName; + stageInfo->stage = entry->stage; + } } - createInfo.stageCount = info->shaderCount; + createInfo.stageCount = stageCount; createInfo.pStages = shaderStages; // Vertex input state @@ -9342,8 +9380,8 @@ PalResult PAL_CALL createComputePipelineVk( createInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; createInfo.stage.module = shader->handle; - createInfo.stage.stage = shader->stage; - createInfo.stage.pName = shader->entryName; + createInfo.stage.stage = shader->entries[0].stage; + createInfo.stage.pName = shader->entries[0].entryName; VkResult result = s_Vk.createComputePipeline( vkDevice->handle, @@ -9388,6 +9426,13 @@ PalResult PAL_CALL createRayTracingPipelineVk( VkRayTracingPipelineCreateInfoKHR createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; + // find the total number of shader stages + Uint32 stageCount = 0; + for (int i = 0; i < info->shaderCount; i++) { + Shader* shader = (Shader*)info->shaders[i]; + stageCount += shader->entryCount; + } + pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); groups = palAllocate( s_Vk.allocator, @@ -9396,7 +9441,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( shaderStages = palAllocate( s_Vk.allocator, - sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount, + sizeof(VkPipelineShaderStageCreateInfo) * stageCount, 0); if (!pipeline || !groups || !shaderStages) { @@ -9404,19 +9449,25 @@ PalResult PAL_CALL createRayTracingPipelineVk( } memset(pipeline, 0, sizeof(Pipeline)); + // shaders - memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * info->shaderCount); + Uint32 stageIndex = 0; + memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stageCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; - VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[i]; - stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo->module = tmp->handle; - stageInfo->pName = tmp->entryName; - stageInfo->stage = tmp->stage; + for (int j = 0; j < tmp->entryCount; j++) { + ShaderEntry* entry = &tmp->entries[j]; + VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex++]; + + stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageInfo->module = tmp->handle; + stageInfo->pName = entry->entryName; + stageInfo->stage = entry->stage; + } } - createInfo.stageCount = info->shaderCount; + createInfo.stageCount = stageCount; createInfo.pStages = shaderStages; ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; @@ -9425,10 +9476,15 @@ PalResult PAL_CALL createRayTracingPipelineVk( PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; group->sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + group->pShaderGroupCaptureReplayHandle = nullptr; + group->pNext = nullptr; + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { // check if its raygen, miss or callable Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; - switch (shader->stage) { + ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; + + switch (entry->stage) { case VK_SHADER_STAGE_RAYGEN_BIT_KHR: { sbtInfo->raygenCount++; sbtInfo->raygenDataSize = maxVk(sbtInfo->raygenDataSize, tmp->maxDataSize); @@ -9449,7 +9505,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( } group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group->generalShader = tmp->generalShaderIndex; + group->generalShader = tmp->generalShaderEntryIndex; group->anyHitShader = VK_SHADER_UNUSED_KHR; group->closestHitShader = VK_SHADER_UNUSED_KHR; group->intersectionShader = VK_SHADER_UNUSED_KHR; @@ -9460,21 +9516,21 @@ PalResult PAL_CALL createRayTracingPipelineVk( group->generalShader = VK_SHADER_UNUSED_KHR; if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - group->anyHitShader = tmp->anyHitShaderIndex; + group->anyHitShader = tmp->anyHitShaderEntryIndex; } else { group->anyHitShader = VK_SHADER_UNUSED_KHR; } if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - group->closestHitShader = tmp->closestHitShaderIndex; + group->closestHitShader = tmp->closestHitShaderEntryIndex; } else { group->closestHitShader = VK_SHADER_UNUSED_KHR; } if (tmp->intersectionShaderIndex!= PAL_UNUSED_SHADER_INDEX) { - group->intersectionShader = tmp->intersectionShaderIndex; + group->intersectionShader = tmp->intersectionShaderEntryIndex; } else { group->intersectionShader = VK_SHADER_UNUSED_KHR; diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index f1f0e996..6c36ae74 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -195,10 +195,14 @@ bool computeTest() readFile(source, bytecode, &bytecodeSize); + PalShaderEntryInfo computeEntry = {0}; + computeEntry.entryName = "main"; + computeEntry.stage = PAL_SHADER_STAGE_COMPUTE; + shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.entryName = "main"; - shaderCreateInfo.stage = PAL_SHADER_STAGE_COMPUTE; + shaderCreateInfo.entries = &computeEntry; + shaderCreateInfo.entryCount = 1; result = palCreateShader(device, &shaderCreateInfo, &shader); if (result != PAL_RESULT_SUCCESS) { @@ -293,17 +297,17 @@ bool computeTest() // create descriptor set layout PalDescriptorSetLayoutBinding descriptorBinding = {0}; - PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_COMPUTE }; - descriptorBinding.descriptorCount = 1; // not an array descriptorBinding.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorBinding.shaderStageCount = 1; - descriptorBinding.shaderStages = shaderStages; PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; descriptorSetLayoutcreateInfo.bindingCount = 1; descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; + PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_COMPUTE }; + descriptorSetLayoutcreateInfo.shaderStageCount = 1; + descriptorSetLayoutcreateInfo.shaderStages = shaderStages; + result = palCreateDescriptorSetLayout( device, &descriptorSetLayoutcreateInfo, diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 9d17deb3..2cd53d98 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -194,7 +194,7 @@ bool descriptorIndexingTest() PalAdapterInfo adapterInfo = {0}; PalAdapterFeatures adapterFeatures; for (Int32 i = 0; i < adapterCount; i++) { - adapter = adapters[2]; + adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -888,7 +888,7 @@ bool descriptorIndexingTest() Uint64 bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; - PalShaderStage tmpShaderStages[2]; + PalShaderEntryInfo entries[2]; PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { @@ -900,8 +900,13 @@ bool descriptorIndexingTest() sources[1] = "graphics/shaders/bin/dxbc/descriptor_indexing.dxbc"; } - tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; - tmpShaderStages[1] = PAL_SHADER_STAGE_FRAGMENT; + entries[0].stage = PAL_SHADER_STAGE_VERTEX; + entries[0].entryName = "main"; + entries[0].patchControlPoints = 0; + + entries[1].stage = PAL_SHADER_STAGE_FRAGMENT; + entries[1].entryName = "main"; + entries[1].patchControlPoints = 0; for (int i = 0; i < 2; i++) { // read file @@ -920,8 +925,8 @@ bool descriptorIndexingTest() shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.entryName = "main"; - shaderCreateInfo.stage = tmpShaderStages[i]; + shaderCreateInfo.entries = &entries[i]; + shaderCreateInfo.entryCount = 1; result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); if (result != PAL_RESULT_SUCCESS) { @@ -934,24 +939,22 @@ bool descriptorIndexingTest() } // create descriptor set layout - PalDescriptorSetLayoutBinding descriptorBindings[2]; - PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; - // We use descriptor count of 100 and only use 4 slots + PalDescriptorSetLayoutBinding descriptorBindings[2]; descriptorBindings[0].descriptorCount = 100; descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - descriptorBindings[0].shaderStageCount = 1; - descriptorBindings[0].shaderStages = shaderStages; - + descriptorBindings[1].descriptorCount = 1; // not an array descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; - descriptorBindings[1].shaderStageCount = 1; - descriptorBindings[1].shaderStages = shaderStages; PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; descriptorSetLayoutcreateInfo.bindingCount = 2; descriptorSetLayoutcreateInfo.bindings = descriptorBindings; + PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; + descriptorSetLayoutcreateInfo.shaderStageCount = 1; + descriptorSetLayoutcreateInfo.shaderStages = shaderStages; + // we need to enable descriptor indexing for the descriptor set layout descriptorSetLayoutcreateInfo.enableDescriptorIndexing = true; diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index e797f488..7e2309c3 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -386,7 +386,7 @@ bool geometryTest() Uint64 bytecodeSize = 0; void* bytecode = nullptr; const char* sources[3]; - PalShaderStage tmpShaderStages[3]; + PalShaderEntryInfo entries[3]; PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { @@ -400,9 +400,17 @@ bool geometryTest() sources[2] = "graphics/shaders/bin/dxbc/geometry.dxbc"; } - tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; - tmpShaderStages[1] = PAL_SHADER_STAGE_FRAGMENT; - tmpShaderStages[2] = PAL_SHADER_STAGE_GEOMETRY; + entries[0].stage = PAL_SHADER_STAGE_VERTEX; + entries[0].entryName = "main"; + entries[0].patchControlPoints = 0; + + entries[1].stage = PAL_SHADER_STAGE_FRAGMENT; + entries[1].entryName = "main"; + entries[1].patchControlPoints = 0; + + entries[2].stage = PAL_SHADER_STAGE_GEOMETRY; + entries[2].entryName = "main"; + entries[2].patchControlPoints = 0; for (int i = 0; i < 3; i++) { // read file @@ -421,8 +429,8 @@ bool geometryTest() shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.entryName = "main"; - shaderCreateInfo.stage = tmpShaderStages[i]; + shaderCreateInfo.entries = &entries[i]; + shaderCreateInfo.entryCount = 1; result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 1f63f4d1..1d7486de 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -755,7 +755,7 @@ bool indirectDrawTest() Uint64 bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; - PalShaderStage tmpShaderStages[2]; + PalShaderEntryInfo entries[2]; PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { @@ -767,8 +767,13 @@ bool indirectDrawTest() sources[1] = "graphics/shaders/bin/dxbc/triangle_frag.dxbc"; } - tmpShaderStages[0] = PAL_SHADER_STAGE_VERTEX; - tmpShaderStages[1] = PAL_SHADER_STAGE_FRAGMENT; + entries[0].stage = PAL_SHADER_STAGE_VERTEX; + entries[0].entryName = "main"; + entries[0].patchControlPoints = 0; + + entries[1].stage = PAL_SHADER_STAGE_FRAGMENT; + entries[1].entryName = "main"; + entries[1].patchControlPoints = 0; for (int i = 0; i < 2; i++) { // read file @@ -787,8 +792,8 @@ bool indirectDrawTest() shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.entryName = "main"; - shaderCreateInfo.stage = tmpShaderStages[i]; + shaderCreateInfo.entries = &entries[i]; + shaderCreateInfo.entryCount = 1; result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index ca001c59..01dc8b6b 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -388,7 +388,7 @@ bool meshTest() Uint64 bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; - PalShaderStage tmpShaderStages[2]; + PalShaderEntryInfo entries[2]; PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { @@ -400,8 +400,13 @@ bool meshTest() sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; } - tmpShaderStages[0] = PAL_SHADER_STAGE_MESH; - tmpShaderStages[1] = PAL_SHADER_STAGE_FRAGMENT; + entries[0].stage = PAL_SHADER_STAGE_MESH; + entries[0].entryName = "main"; + entries[0].patchControlPoints = 0; + + entries[1].stage = PAL_SHADER_STAGE_FRAGMENT; + entries[1].entryName = "main"; + entries[1].patchControlPoints = 0; for (int i = 0; i < 2; i++) { // read file @@ -420,8 +425,8 @@ bool meshTest() shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.entryName = "main"; - shaderCreateInfo.stage = tmpShaderStages[i]; + shaderCreateInfo.entries = &entries[i]; + shaderCreateInfo.entryCount = 1; result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 06cb8a2f..db6b3ef6 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -211,10 +211,14 @@ bool multiDescriptorSetTest() readFile(source, bytecode, &bytecodeSize); + PalShaderEntryInfo computeEntry = {0}; + computeEntry.entryName = "main"; + computeEntry.stage = PAL_SHADER_STAGE_COMPUTE; + shaderCreateInfo.bytecode = bytecode; shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.entryName = "main"; - shaderCreateInfo.stage = PAL_SHADER_STAGE_COMPUTE; + shaderCreateInfo.entries = &computeEntry; + shaderCreateInfo.entryCount = 1; result = palCreateShader(device, &shaderCreateInfo, &shader); if (result != PAL_RESULT_SUCCESS) { @@ -310,17 +314,17 @@ bool multiDescriptorSetTest() // create descriptor set layout PalDescriptorSetLayoutBinding descriptorBinding = {0}; - PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_COMPUTE }; - descriptorBinding.descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorBinding.shaderStageCount = 1; - descriptorBinding.shaderStages = shaderStages; descriptorBinding.descriptorCount = 1; // not an array PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; descriptorSetLayoutcreateInfo.bindingCount = 1; descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; + PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_COMPUTE }; + descriptorSetLayoutcreateInfo.shaderStageCount = 1; + descriptorSetLayoutcreateInfo.shaderStages = shaderStages; + result = palCreateDescriptorSetLayout( device, &descriptorSetLayoutcreateInfo, diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 190fe7ce..49a9b8d4 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -26,7 +26,7 @@ bool rayTracingTest() PalCommandPool* cmdPool = nullptr; PalCommandBuffer* cmdBuffer; - PalShader* shaders[3]; + PalShader* rayTracingShader = nullptr; PalBuffer* buffer = nullptr; PalBuffer* stagingBuffer = nullptr; @@ -59,7 +59,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -193,54 +193,56 @@ bool rayTracingTest() // create ray tracing shaders Uint64 bytecodeSize = 0; void* bytecode = nullptr; - const char* sources[3]; - PalShaderStage tmpShaderStages[3]; + const char* source = nullptr; + PalShaderEntryInfo entries[3]; PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { - sources[0] = "graphics/shaders/bin/spirv/raygen.spv"; - sources[1] = "graphics/shaders/bin/spirv/miss.spv"; - sources[2] = "graphics/shaders/bin/spirv/closest_hit.spv"; + source = "graphics/shaders/bin/spirv/ray_tracing.spv"; } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { - sources[0] = "graphics/shaders/bin/dxil/raygen.dxil"; - sources[1] = "graphics/shaders/bin/dxil/miss.dxil"; - sources[2] = "graphics/shaders/bin/dxil/closest_hit.dxil"; + source = "graphics/shaders/bin/dxil/ray_tracing.dxil"; } - tmpShaderStages[0] = PAL_SHADER_STAGE_RAYGEN; - tmpShaderStages[1] = PAL_SHADER_STAGE_MISS; - tmpShaderStages[2] = PAL_SHADER_STAGE_CLOSEST_HIT; + entries[0].stage = PAL_SHADER_STAGE_RAYGEN; + entries[0].entryName = "raygenMain"; + entries[0].patchControlPoints = 0; - for (int i = 0; i < 3; i++) { - // read file - if (!readFile(sources[i], nullptr, &bytecodeSize)) { - palLog(nullptr, "Failed to read shader file"); - return false; - } + entries[1].stage = PAL_SHADER_STAGE_MISS; + entries[1].entryName = "missMain"; + entries[1].patchControlPoints = 0; - bytecode = palAllocate(nullptr, bytecodeSize, 0); - if (!bytecode) { - palLog(nullptr, "Failed to allocate memory"); - return false; - } + entries[2].stage = PAL_SHADER_STAGE_CLOSEST_HIT; + entries[2].entryName = "closestHitMain"; + entries[2].patchControlPoints = 0; - readFile(sources[i], bytecode, &bytecodeSize); + // read file + if (!readFile(source, nullptr, &bytecodeSize)) { + palLog(nullptr, "Failed to read shader file"); + return false; + } - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; - shaderCreateInfo.entryName = "main"; - shaderCreateInfo.stage = tmpShaderStages[i]; + bytecode = palAllocate(nullptr, bytecodeSize, 0); + if (!bytecode) { + palLog(nullptr, "Failed to allocate memory"); + return false; + } - result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create shader: %s", error); - return false; - } + readFile(source, bytecode, &bytecodeSize); - palFree(nullptr, bytecode); - } + shaderCreateInfo.bytecode = bytecode; + shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.entries = entries; + shaderCreateInfo.entryCount = 3; + + result = palCreateShader(device, &shaderCreateInfo, &rayTracingShader); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to create shader: %s", error); + return false; + } + + palFree(nullptr, bytecode); Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader PalBufferCreateInfo bufferCreateInfo = {0}; @@ -659,24 +661,20 @@ bool rayTracingTest() // create descriptor set layout PalDescriptorSetLayoutBinding descriptorBindings[2]; - PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_RAYGEN }; - - // storage buffer to write to descriptorBindings[0].descriptorCount = 1; // not an array descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorBindings[0].shaderStageCount = 1; - descriptorBindings[0].shaderStages = shaderStages; - // acceleration buffer descriptorBindings[1].descriptorCount = 1; // not an array descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE; - descriptorBindings[1].shaderStageCount = 1; - descriptorBindings[1].shaderStages = shaderStages; PalDescriptorSetLayoutCreateInfo descriptorSetLayoutcreateInfo = {0}; descriptorSetLayoutcreateInfo.bindingCount = 2; descriptorSetLayoutcreateInfo.bindings = descriptorBindings; + PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_RAYGEN }; + descriptorSetLayoutcreateInfo.shaderStageCount = 1; + descriptorSetLayoutcreateInfo.shaderStages = shaderStages; + result = palCreateDescriptorSetLayout( device, &descriptorSetLayoutcreateInfo, @@ -767,12 +765,12 @@ bool rayTracingTest() // the shader group array must respect the corect layout // [raygen][miss][hitGroup][callable] // [raygen][raygen][miss][hitGroup][hitGroup][callable] - PalRayTracingShaderGroupCreateInfo shaderGroupCreateInfos[3] = {0}; // raygen must be packed first always shaderGroupCreateInfos[0].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; shaderGroupCreateInfos[0].generalShaderIndex = 0; + shaderGroupCreateInfos[0].generalShaderEntryIndex = 0; shaderGroupCreateInfos[0].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[0].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; @@ -780,7 +778,8 @@ bool rayTracingTest() // miss must be packed second always shaderGroupCreateInfos[1].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL; - shaderGroupCreateInfos[1].generalShaderIndex = 1; + shaderGroupCreateInfos[1].generalShaderIndex = 0; + shaderGroupCreateInfos[1].generalShaderEntryIndex = 1; shaderGroupCreateInfos[1].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].closestHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[1].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; @@ -788,7 +787,8 @@ bool rayTracingTest() // hitGroup must be packed third always shaderGroupCreateInfos[2].type = PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT; - shaderGroupCreateInfos[2].closestHitShaderIndex = 2; + shaderGroupCreateInfos[2].closestHitShaderIndex = 0; + shaderGroupCreateInfos[2].closestHitShaderEntryIndex = 2; shaderGroupCreateInfos[2].anyHitShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[2].generalShaderIndex = PAL_UNUSED_SHADER_INDEX; shaderGroupCreateInfos[2].intersectionShaderIndex = PAL_UNUSED_SHADER_INDEX; @@ -800,10 +800,10 @@ bool rayTracingTest() pipelineCreateInfo.maxPayloadSize = 16; pipelineCreateInfo.maxAttributeSize = 8; pipelineCreateInfo.pipelineLayout = pipelineLayout; - pipelineCreateInfo.shaderCount = 3; + pipelineCreateInfo.shaderCount = 1; pipelineCreateInfo.shaderGroupCount = 3; pipelineCreateInfo.shaderGroups = shaderGroupCreateInfos; - pipelineCreateInfo.shaders = shaders; + pipelineCreateInfo.shaders = &rayTracingShader; result = palCreateRayTracingPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { @@ -812,9 +812,7 @@ bool rayTracingTest() return false; } - for (int i = 0; i < 3; i++) { - palDestroyShader(shaders[i]); - } + palDestroyShader(rayTracingShader); // create shader binding table // we need 3 records, only closest hit (git group) only uses the local data diff --git a/tests/graphics/shaders/bin/dxil/ray_tracing.hlsl b/tests/graphics/shaders/bin/dxil/ray_tracing.hlsl new file mode 100644 index 00000000..4c51fdaa --- /dev/null +++ b/tests/graphics/shaders/bin/dxil/ray_tracing.hlsl @@ -0,0 +1,65 @@ + + +struct RayPayload +{ + float3 color; +}; + +struct HitAttributes +{ + float2 unused; +}; + +[[vk::shader_record_ext]] +cbuffer RecordData : register(b0) +{ + float3 colorRecord; +}; + +// binding 0 set 0 +[[vk::binding(0, 0)]] +RWByteAddressBuffer outBuffer : register(u0, space0); + +// binding 1 set 0 +[[vk::binding(1, 0)]] +RaytracingAccelerationStructure tlas : register(t0, space0); + +[shader("raygeneration")] +void raygenMain() +{ + uint2 pixel = DispatchRaysIndex().xy; + uint2 size = DispatchRaysDimensions().xy; + RayPayload payload; + payload.color = float3(0.0, 0.0, 0.0); + + float2 uv = (float2(pixel) + 0.5) / float2(size); + float2 ndcUv = uv * 2.0 - 1.0; + + RayDesc desc; + desc.Origin = float3(0.0, 0.0, -3.0);; + desc.Direction = normalize(float3(ndcUv.x, ndcUv.y, 1.0));; + desc.TMin = 0.001; + desc.TMax = 1000.0; + TraceRay(tlas, RAY_FLAG_NONE, 0xFF, 0, 0, 0, desc, payload); + + if (pixel.x >= size.x || pixel.y >= size.y) { + return; + } + + uint index = pixel.y * size.x + pixel.x; + uint offset = index * 16; // sizeof(float4) + float4 color = float4(payload.color, 1.0); + outBuffer.Store4(offset, asuint(color)); +} + +[shader("miss")] +void missMain(inout RayPayload payload) +{ + payload.color = colorRecord; +} + +[shader("closesthit")] +void closestHitMain(inout RayPayload payload, in HitAttributes attr) +{ + payload.color = colorRecord; +} \ No newline at end of file diff --git a/tests/graphics/shaders/bin/spirv/ray_tracing.spv b/tests/graphics/shaders/bin/spirv/ray_tracing.spv new file mode 100644 index 0000000000000000000000000000000000000000..f40b2c0bd46e915d616f6f5033d946d31ea757f5 GIT binary patch literal 2996 zcmZvc+j3M@5Qdit69^y?2;d1wI4KY#DjQh*r%F^%Kvs+T=nsmDVzkBuSUWeV;v3G5%+>=t;l-}pRV{__A zA8k%)edd#9W1knxFYxTrO}nVK2obS>#bHhxjCF?UybGbU$R1XJ#bmIT3@I) zvwXg>IFmP*tNC)Xetwo2Yl{8I7qV95xDR7GTbasM78+U2Ix9)eQPhcco_#NsL1Oo8 zHFkgQ;L3l_#Cq@E`wFZ5-+qsi-&5B29cLo;JjLIa*m`y$4*l-Mo&w#${j0F|V6|VY z-#a!zZE-ex!H#h%kn?VtpQ~Ezopl)R`8Za`%Nf6&xm(bE$YJJcZ$%tCz_d_s_BcRR z@ixSmkZr_m2lpY?Xddwn#1VP#Z^I$;K7j37)-XVg;s+69l$i4nHe)#O!v(xK6mxch z<&=nN@AdGPQSWYiQLDa)>%(qrxpgvdKRBfi#_Y%a?-Mfgi(~%+?}Pgr>7|SP=!5K~ z`T!C!k6?R813!vw&w&qO$DX;yA;i7jRi3H)-N*We(LVz`=biXGW8;nUEXBqRpuOL6 zKlXMMZ%qC%u){a!{tu#^?^^mFM_Y%yIjuR?K7#!NK+f1F&_9)UE8RQ^?q|+ZXl?T! zMVr5)#K+K{w|7$iakPH1IiE&bx19I{+J5; z*9vS;zDxVkZ%=+F>?^Rj#RK^5{Tal&f1H{2X>Shu{ta{z{VS`Ul4Sge?VWiR(XT#D zF8BB}Vtp6r;wbt|$;mscGh&CZtvzCgvE>wpu}ehwhDH!`eO$h&(US9RMa*;9!^rJ2 zW(?an`As5+0bAZTcM;C>97p6G!A)SxS=Utg&3F;pSbe_LjV1pQwsGb) z<_x>yxwzN%?|nUsc(#`}Z!B#0bRVJ)*^S+Yn6Do(hx0wR$r4*1$C=KR9IB{!5BfY3 zdvBcF1tj+P3%LE@Da2TPp7lkv;}6!-H;u@7-fg>`YX;8z_8R$L#x}p)=Vks^u#MIC zJ2@hk`WNnsHOwLh5bu-mu465i&<<-c=2b+_TC~mQ-4x459j{?WZJ(6AzYZsFpEpbH z4QzS)kGMCn<^9f?&pUA$agQCry@f3o{Tnw|avkU?dh;7`1#!Od`n@Y(m+NQPuID%O zLwfWZ@-}h>iC(HDhvF@C72lN_w%-cxiaESva>mBII<~p2FZ#WTZM@&;$aM`na_Kjh zobw~sb!>ClSLB+Byufao9hq~xo%)bF8$_`bN=dc z_x%5&%M(a^$JW6);ybp8J;I**4Q?Ra$PUE! Date: Mon, 25 May 2026 21:30:57 +0000 Subject: [PATCH 231/372] use only HLSL shader source for both dxil and spirv --- tests/graphics/descriptor_indexing_test.c | 15 +++--- tests/graphics/geometry_test.c | 15 +++--- tests/graphics/indirect_draw_test.c | 15 +++--- tests/graphics/mesh_test.c | 15 +++--- tests/graphics/ray_tracing_test.c | 2 +- tests/graphics/shaders/bin/dxbc/compute.dxbc | Bin 992 -> 0 bytes .../shaders/bin/dxbc/compute_multi.dxbc | Bin 1584 -> 0 bytes .../shaders/bin/dxbc/descriptor_indexing.dxbc | Bin 1280 -> 0 bytes tests/graphics/shaders/bin/dxbc/geometry.dxbc | Bin 1196 -> 0 bytes .../shaders/bin/dxbc/geometry_vert.dxbc | Bin 688 -> 0 bytes .../shaders/bin/dxbc/texture_frag.dxbc | Bin 692 -> 0 bytes .../shaders/bin/dxbc/texture_vert.dxbc | Bin 636 -> 0 bytes .../shaders/bin/dxbc/triangle_frag.dxbc | Bin 520 -> 0 bytes .../shaders/bin/dxbc/triangle_vert.dxbc | Bin 648 -> 0 bytes .../shaders/bin/dxil/closest_hit.dxil | Bin 3520 -> 0 bytes tests/graphics/shaders/bin/dxil/compute.dxil | Bin 0 -> 3400 bytes .../shaders/bin/dxil/compute_multi.dxil | Bin 0 -> 3852 bytes .../shaders/bin/dxil/descriptor_indexing.dxil | Bin 0 -> 4452 bytes tests/graphics/shaders/bin/dxil/geometry.dxil | Bin 0 -> 3832 bytes .../shaders/bin/dxil/geometry_vert.dxil | Bin 0 -> 3024 bytes tests/graphics/shaders/bin/dxil/miss.dxil | Bin 3316 -> 0 bytes .../shaders/bin/dxil/ray_tracing.dxil | Bin 0 -> 5936 bytes tests/graphics/shaders/bin/dxil/raygen.dxil | Bin 4384 -> 0 bytes .../shaders/bin/dxil/texture_frag.dxil | Bin 0 -> 3820 bytes .../shaders/bin/dxil/texture_vert.dxil | Bin 0 -> 3104 bytes .../shaders/bin/dxil/triangle_frag.dxil | Bin 0 -> 2964 bytes .../shaders/bin/dxil/triangle_vert.dxil | Bin 0 -> 3144 bytes .../shaders/bin/spirv/closest_hit.spv | Bin 540 -> 0 bytes tests/graphics/shaders/bin/spirv/compute.spv | Bin 1704 -> 1720 bytes .../shaders/bin/spirv/compute_multi.spv | Bin 2436 -> 1764 bytes .../shaders/bin/spirv/descriptor_indexing.spv | Bin 2356 -> 2032 bytes tests/graphics/shaders/bin/spirv/geometry.spv | Bin 2456 -> 1724 bytes .../shaders/bin/spirv/geometry_vert.spv | Bin 1220 -> 680 bytes tests/graphics/shaders/bin/spirv/mesh.spv | Bin 1772 -> 1324 bytes tests/graphics/shaders/bin/spirv/miss.spv | Bin 540 -> 0 bytes tests/graphics/shaders/bin/spirv/raygen.spv | Bin 2620 -> 0 bytes .../shaders/bin/spirv/texture_frag.spv | Bin 676 -> 748 bytes .../shaders/bin/spirv/texture_vert.spv | Bin 1044 -> 612 bytes .../shaders/bin/spirv/triangle_frag.spv | Bin 372 -> 368 bytes .../shaders/bin/spirv/triangle_vert.spv | Bin 1140 -> 712 bytes .../shaders/src/{hlsl => }/compute.hlsl | 17 +++++-- .../shaders/src/{hlsl => }/compute_multi.hlsl | 25 +++++++--- .../src/{hlsl => }/descriptor_indexing.hlsl | 17 +++++-- .../shaders/src/{hlsl => }/geometry.hlsl | 0 .../shaders/src/{hlsl => }/geometry_vert.hlsl | 0 .../shaders/src/glsl/closest_hit.glsl | 15 ------ tests/graphics/shaders/src/glsl/compute.glsl | 27 ----------- .../shaders/src/glsl/compute_multi.glsl | 41 ---------------- .../shaders/src/glsl/descriptor_indexing.glsl | 39 ---------------- tests/graphics/shaders/src/glsl/geometry.glsl | 33 ------------- .../shaders/src/glsl/geometry_vert.glsl | 14 ------ tests/graphics/shaders/src/glsl/mesh.glsl | 27 ----------- tests/graphics/shaders/src/glsl/miss.glsl | 15 ------ tests/graphics/shaders/src/glsl/raygen.glsl | 44 ------------------ .../shaders/src/glsl/texture_frag.glsl | 14 ------ .../shaders/src/glsl/texture_vert.glsl | 14 ------ .../shaders/src/glsl/triangle_frag.glsl | 11 ----- .../shaders/src/glsl/triangle_vert.glsl | 13 ------ .../shaders/src/hlsl/closest_hit.hlsl | 23 --------- tests/graphics/shaders/src/hlsl/miss.hlsl | 16 ------- tests/graphics/shaders/src/hlsl/raygen.hlsl | 36 -------------- .../shaders/src/hlsl/texture_frag.hlsl | 14 ------ .../graphics/shaders/src/{hlsl => }/mesh.hlsl | 0 .../{bin/dxil => src}/ray_tracing.hlsl | 0 tests/graphics/shaders/src/texture_frag.hlsl | 19 ++++++++ .../shaders/src/{hlsl => }/texture_vert.hlsl | 0 .../shaders/src/{hlsl => }/triangle_frag.hlsl | 0 .../shaders/src/{hlsl => }/triangle_vert.hlsl | 0 tests/graphics/texture_test.c | 15 +++--- tests/graphics/triangle_test.c | 15 +++--- tests/tests_main.c | 4 +- 71 files changed, 120 insertions(+), 450 deletions(-) delete mode 100644 tests/graphics/shaders/bin/dxbc/compute.dxbc delete mode 100644 tests/graphics/shaders/bin/dxbc/compute_multi.dxbc delete mode 100644 tests/graphics/shaders/bin/dxbc/descriptor_indexing.dxbc delete mode 100644 tests/graphics/shaders/bin/dxbc/geometry.dxbc delete mode 100644 tests/graphics/shaders/bin/dxbc/geometry_vert.dxbc delete mode 100644 tests/graphics/shaders/bin/dxbc/texture_frag.dxbc delete mode 100644 tests/graphics/shaders/bin/dxbc/texture_vert.dxbc delete mode 100644 tests/graphics/shaders/bin/dxbc/triangle_frag.dxbc delete mode 100644 tests/graphics/shaders/bin/dxbc/triangle_vert.dxbc delete mode 100644 tests/graphics/shaders/bin/dxil/closest_hit.dxil create mode 100644 tests/graphics/shaders/bin/dxil/compute.dxil create mode 100644 tests/graphics/shaders/bin/dxil/compute_multi.dxil create mode 100644 tests/graphics/shaders/bin/dxil/descriptor_indexing.dxil create mode 100644 tests/graphics/shaders/bin/dxil/geometry.dxil create mode 100644 tests/graphics/shaders/bin/dxil/geometry_vert.dxil delete mode 100644 tests/graphics/shaders/bin/dxil/miss.dxil create mode 100644 tests/graphics/shaders/bin/dxil/ray_tracing.dxil delete mode 100644 tests/graphics/shaders/bin/dxil/raygen.dxil create mode 100644 tests/graphics/shaders/bin/dxil/texture_frag.dxil create mode 100644 tests/graphics/shaders/bin/dxil/texture_vert.dxil create mode 100644 tests/graphics/shaders/bin/dxil/triangle_frag.dxil create mode 100644 tests/graphics/shaders/bin/dxil/triangle_vert.dxil delete mode 100644 tests/graphics/shaders/bin/spirv/closest_hit.spv delete mode 100644 tests/graphics/shaders/bin/spirv/miss.spv delete mode 100644 tests/graphics/shaders/bin/spirv/raygen.spv rename tests/graphics/shaders/src/{hlsl => }/compute.hlsl (50%) rename tests/graphics/shaders/src/{hlsl => }/compute_multi.hlsl (51%) rename tests/graphics/shaders/src/{hlsl => }/descriptor_indexing.hlsl (68%) rename tests/graphics/shaders/src/{hlsl => }/geometry.hlsl (100%) rename tests/graphics/shaders/src/{hlsl => }/geometry_vert.hlsl (100%) delete mode 100644 tests/graphics/shaders/src/glsl/closest_hit.glsl delete mode 100644 tests/graphics/shaders/src/glsl/compute.glsl delete mode 100644 tests/graphics/shaders/src/glsl/compute_multi.glsl delete mode 100644 tests/graphics/shaders/src/glsl/descriptor_indexing.glsl delete mode 100644 tests/graphics/shaders/src/glsl/geometry.glsl delete mode 100644 tests/graphics/shaders/src/glsl/geometry_vert.glsl delete mode 100644 tests/graphics/shaders/src/glsl/mesh.glsl delete mode 100644 tests/graphics/shaders/src/glsl/miss.glsl delete mode 100644 tests/graphics/shaders/src/glsl/raygen.glsl delete mode 100644 tests/graphics/shaders/src/glsl/texture_frag.glsl delete mode 100644 tests/graphics/shaders/src/glsl/texture_vert.glsl delete mode 100644 tests/graphics/shaders/src/glsl/triangle_frag.glsl delete mode 100644 tests/graphics/shaders/src/glsl/triangle_vert.glsl delete mode 100644 tests/graphics/shaders/src/hlsl/closest_hit.hlsl delete mode 100644 tests/graphics/shaders/src/hlsl/miss.hlsl delete mode 100644 tests/graphics/shaders/src/hlsl/raygen.hlsl delete mode 100644 tests/graphics/shaders/src/hlsl/texture_frag.hlsl rename tests/graphics/shaders/src/{hlsl => }/mesh.hlsl (100%) rename tests/graphics/shaders/{bin/dxil => src}/ray_tracing.hlsl (100%) create mode 100644 tests/graphics/shaders/src/texture_frag.hlsl rename tests/graphics/shaders/src/{hlsl => }/texture_vert.hlsl (100%) rename tests/graphics/shaders/src/{hlsl => }/triangle_frag.hlsl (100%) rename tests/graphics/shaders/src/{hlsl => }/triangle_vert.hlsl (100%) diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 2cd53d98..57208e3a 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -890,14 +890,23 @@ bool descriptorIndexingTest() const char* sources[2]; PalShaderEntryInfo entries[2]; + PalViewport viewport = {0}; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { sources[0] = "graphics/shaders/bin/spirv/texture_vert.spv"; sources[1] = "graphics/shaders/bin/spirv/descriptor_indexing.spv"; + viewport.height = -(float)WINDOW_HEIGHT; + viewport.y = (float)WINDOW_HEIGHT; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { sources[0] = "graphics/shaders/bin/dxbc/texture_vert.dxbc"; sources[1] = "graphics/shaders/bin/dxbc/descriptor_indexing.dxbc"; + + viewport.height = (float)WINDOW_HEIGHT; } entries[0].stage = PAL_SHADER_STAGE_VERTEX; @@ -1151,12 +1160,6 @@ bool descriptorIndexingTest() Uint32 currentFrame = 0; bool running = true; - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; - PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index 7e2309c3..03955f2c 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -388,16 +388,25 @@ bool geometryTest() const char* sources[3]; PalShaderEntryInfo entries[3]; + PalViewport viewport = {0}; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { sources[0] = "graphics/shaders/bin/spirv/geometry_vert.spv"; sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; sources[2] = "graphics/shaders/bin/spirv/geometry.spv"; + viewport.height = -(float)WINDOW_HEIGHT; + viewport.y = (float)WINDOW_HEIGHT; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { sources[0] = "graphics/shaders/bin/dxbc/geometry_vert.dxbc"; sources[1] = "graphics/shaders/bin/dxbc/triangle_frag.dxbc"; sources[2] = "graphics/shaders/bin/dxbc/geometry.dxbc"; + + viewport.height = (float)WINDOW_HEIGHT; } entries[0].stage = PAL_SHADER_STAGE_VERTEX; @@ -493,12 +502,6 @@ bool geometryTest() Uint32 currentFrame = 0; bool running = true; - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; - PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 1d7486de..d3e5de47 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -757,14 +757,23 @@ bool indirectDrawTest() const char* sources[2]; PalShaderEntryInfo entries[2]; + PalViewport viewport = {0}; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { sources[0] = "graphics/shaders/bin/spirv/triangle_vert.spv"; sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; + viewport.height = -(float)WINDOW_HEIGHT; + viewport.y = (float)WINDOW_HEIGHT; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { sources[0] = "graphics/shaders/bin/dxbc/triangle_vert.dxbc"; sources[1] = "graphics/shaders/bin/dxbc/triangle_frag.dxbc"; + + viewport.height = (float)WINDOW_HEIGHT; } entries[0].stage = PAL_SHADER_STAGE_VERTEX; @@ -889,12 +898,6 @@ bool indirectDrawTest() Uint32 currentFrame = 0; bool running = true; - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; - PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 01dc8b6b..1d20fb78 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -390,14 +390,23 @@ bool meshTest() const char* sources[2]; PalShaderEntryInfo entries[2]; + PalViewport viewport = {0}; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { sources[0] = "graphics/shaders/bin/spirv/mesh.spv"; sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; + viewport.height = -(float)WINDOW_HEIGHT; + viewport.y = (float)WINDOW_HEIGHT; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { sources[0] = "graphics/shaders/bin/dxil/mesh.dxil"; sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; + + viewport.height = (float)WINDOW_HEIGHT; } entries[0].stage = PAL_SHADER_STAGE_MESH; @@ -489,12 +498,6 @@ bool meshTest() Uint32 currentFrame = 0; bool running = true; - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; - PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 49a9b8d4..512b034a 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -59,7 +59,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/graphics/shaders/bin/dxbc/compute.dxbc b/tests/graphics/shaders/bin/dxbc/compute.dxbc deleted file mode 100644 index ebf10f3c1d5705ed3d43eec7d4d122b320a1f266..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 992 zcmcgqO)mpc6utdY8Vk`#L?lL#uxVQ9N@!?nkknVlfOr{nzr{J0BfYx z;b+ZXx?SkHpks2q!(ZxE3%X^HUKOSeRS-ScLhM>Gfsm0aY#SD3MNycPFN%y6MTQ6D z8~uy}l=+mFQZyr@=S(Fb_Vx=!EF$4hgch{9C4L76+vS$MHb1-G zk9w^+R3#+W0Js43#35&inv=LI;o-7!U(OOx@s|*e?lDNj-6;qx*Hf1N(P54nYsj|rYw_(Y~*se$|c6m z0`oEEpicsnPXJoz-}@e+rC zaOX7ZvHu&wxYjMi$vKV}g2%oDOFjEXy*N5cl^KxJBL|0?a@+3 zP1o@rxT^P9Ouyv^(roz+wTM$`fKwhVPjHq`FFFKkA+o+APSJD!jD5X7t>>yOXWMBj z>2|wGdL^x!l(*{L5B$(?Dr0`*vQb~LRt(E+*iK-W{`O<91*4F^QjnY0ja!*$B%xj# z@vVAw>m62n8y~2L{KJf-?ug9PUh-)TL~rsnb3Y1$1T5}~qI1Jfj5+!`7q64_{*LeA z6)WN`bD_z7h1Zkk^x1WhOfl|K1F!Zp&*Oc;|77NLoIe-qY^=}AWLn$Tag{T`MUfK& z{)A*l>SfVm55J^eUoP}}=o+b|C^Wnu-dXc$Q^xVR1I^d_7{|w_F1)+7xxBgCs~znW TX8-G8U)Cb@9bog{+Q`6L_8-qzTrh&$o9*n^*tdP`#?AFj;6uaAku`FS?si)S1 z7cYA82lS3d6XV6J7k`HS0e^t_&D%G1i&rOn%)D>jd~bI4L8ZNJP4Db~K1sb_`F3)& zv^LZ8XGd#~ziq{foRGcLsUeds&x1NQ^sO90of@!1SE T_Iyud&0Nx?Cdu*t!T+#7nu&6J diff --git a/tests/graphics/shaders/bin/dxbc/geometry.dxbc b/tests/graphics/shaders/bin/dxbc/geometry.dxbc deleted file mode 100644 index 48a737eb3d42ae753dd7a235b1bf5703dd72f3ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1196 zcmb7EziU%b6h7~zX&Vt5TaY?fuA&e{J zgNut!#lfY{u7ZC-2M7O-&JKRxefP#|bn(Es=ht_>d+y;Swbg}c`t#`atA5aZ{pM)p ze7m+--$3lkJc1yv8*HLKHC4MvI}I&ay#RX>O1aa0 zl=k*|kDsYh`;uB}>6X&l>l>S?s`hrDc6Z>+MptL0sT<2zfagr(Pz9wh&KXZ+VnRgU zd$^M5W~Z4fOQIXsI;e$E_E2JT4)xhw%UT+8k{gtNa8{F6(w4(Ry|lRc1H^a1{sovP z;}Wc6RmVj&n1}t_xSm{H5o|2urNh|G&UkHFg14r8iZHofl3)v%V^uUUv74wfrvCuE z1=#B%qmz+>mq`$de0YE6tDh&Hd5WLsUM#+Xd?5u7v6L{zA^R1cPJ9e;VT{AbZ=8=I ze;DH!NQMI@e_rgn;;hKr!cZ>4c;`gM`Zj;rt8=G08OhzSIrNWBTK`0(%&r}twG=hZ zTrVrLcdwRr{BB47z3g#!u8l+GLH{V*f_t%RDgB}9-wzA6JOAN7`>6^`cn)w@_ zqGsj|GfR%X&1G}$SDt&{%Z#@te_nE&#vWe`Vco9X9?0piH{t5etMsmpC3*W6b{+e#ieKzX0KNSpon6 diff --git a/tests/graphics/shaders/bin/dxbc/geometry_vert.dxbc b/tests/graphics/shaders/bin/dxbc/geometry_vert.dxbc deleted file mode 100644 index 89ca9feb9a3726485a6cdeba69f173ced218eb4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 688 zcma)2Jx{_=6um8AD>0FPgX0@CfrOYsjFS`SkHx?)GzJf<|TcreWWG|5k0Cz5yVaK z9()IN2rK9}%u>07+K+7%O62>8hd56p%yo{dVAA6n;u6T%@1Kl@SHsh>NH$WUQk7L9 zd&iybNEC+`m;G}j8Dk?umfWkQ;pdxlP=JgDkb4XTiEJIVx}$OT+A_)hV}|`9XM$)M z5i@mLT20HYk*t*3VHgguwE%6PlX659j>lro1iyEN`ct?y@9Gh$9Q)|AiFb3dMYNbT z1Tq(D-i>ds)g3pR_wWuiPsBPnMd`r52fv-vyyKY$JdrrLH$}Z$F{fp{JIjV}Zi{*z rX!^6K@xFOXayU?t%|i1If(G(!41V8_S)Y5e@Am7#JUAcJ|6Bh8ljcEo diff --git a/tests/graphics/shaders/bin/dxbc/texture_frag.dxbc b/tests/graphics/shaders/bin/dxbc/texture_frag.dxbc deleted file mode 100644 index 97d2a60ca65d24d4da246c146d53ac034d49afdd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 692 zcmZ>XaB@B|Z^@}|{!bsBwwvX$Ds7EDBLf4&7A6J;Rv>Kx#D9P|1Sr@6#1cU9AQxA+ z13)nt017eK05K!$|NkIOQ-N$@VHZ`9m;?}OK(Pvt<^f_5=mBD8FbkCc*^LY)0y!Y_ zL2h9I;{QMZq!>WzU}k~%#fiBE3?-=*48EDkMft_~X(b98L7EC4KEXZ;!5N7usYMFT z`MCv|IY5S?fu145>eZ_~gWdfCfO~3|a;-R4s=_COLW+MRsup3i>-uR>-0G4oNVBm(a t-JtSrbqa7Z84?g|JD?YXLmWe<0A)d80|UrxkQgW&Z~=UBxbzS!4gh_HNUi_? diff --git a/tests/graphics/shaders/bin/dxbc/texture_vert.dxbc b/tests/graphics/shaders/bin/dxbc/texture_vert.dxbc deleted file mode 100644 index 20feea50810febfcc59baf496d931d6c0bdf40f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 636 zcmZ>XaB{9vy(T|lvhI|Qyl)2aXDn+N85kI9m>3vXfwTz_F96~%KiFw-Ti!k>VeK--~eI^Acg^ED1#ZuaD)j0X^=R`4j8>`06!4BfLRa%ZYIzJ!C~>(j9ne< z;Tq8cR2~SlT^UGcaWF8(1D#II5%9D<55Ie=u4L4!R^4@f^q4~Vt{219U&W5^UBn*~WZG8-feQcDT|g#|SL06Nh< A7XSbN diff --git a/tests/graphics/shaders/bin/dxbc/triangle_frag.dxbc b/tests/graphics/shaders/bin/dxbc/triangle_frag.dxbc deleted file mode 100644 index 37f514deffbd9d98f7221145229eb1907969be07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 520 zcmZ>XaB|kXqq*-ut;2do>EM;$I8w_Q85kHim>3vXfwTz_F96~%K&%0j$N}OY7gx6w zARign06C1T|NnzDf!M;rE~+3}0*E!BSOrM)05J&oW+oTq7w4yyC};#}DtPz=`zQow zB&MVmDLCin7G&lC8HNUWh76v;?tVT%^+4w^Z~(Cd5Q6~7jm%&c0|P&hc7d`%6i6H- z&kvLc4vP=)5B3c4^!Hi5?Vvv1V91M&}0u0Qb1O&i#r2?(}q#yt`#tayAFt(c RG8-fYayKb}RQ0&b1^~BIG_C*u diff --git a/tests/graphics/shaders/bin/dxbc/triangle_vert.dxbc b/tests/graphics/shaders/bin/dxbc/triangle_vert.dxbc deleted file mode 100644 index a8f3f2c0d71094b374eb38cce14a56a9b83a51b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 648 zcmZ>XaB?nuvb0Qi)}cDyZC}JII72@(GB7Z7FflN&0%;QTUo0(jcU!0#-qM#9^so>!g?4uBz zk(iQNq~M&NTacLpWEdLg88UbVyZdVnlLAB>#7_mvf%qV{88FC=pmJ_d zy+ARJLr^g$2cRMp&|nYJQv}uTCWJ7j2`a|u0MgK4ZwCyL;1I`fw OcaQ?m^^>9(SuFqqXg$UN diff --git a/tests/graphics/shaders/bin/dxil/closest_hit.dxil b/tests/graphics/shaders/bin/dxil/closest_hit.dxil deleted file mode 100644 index e6c4924021ddd1d67d3ac49501c5c1361f860192..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3520 zcmeHKdr(u^89z5S+?zli7ZPh?0=)rY@Ud)&$TQX(5?Hbucf+e?E9@q`3KlRtWC5Kv z33-6V8Wg%wSA<<+*B#v=OI4_DK_~{q6?}AHMF(8KuESckkExw?rac$dj?>O`+W&TE z`px{#`R+O2`Of*ibLRZc)#N0r*F6q$Y*pRK59!<4-v1NSiU0rxxBy_Vj)zEtsDm)T zj(s=)9*E3Tt(*nhp2_!9GBP9K2LjkDO_UITHBeJT7b@b5;}jq|Dj`Y{D_2BC$I%8E z8dcUTtO*Dvga{%R!UZt_L9amx0n$oqGKvazR}}(ed%3Z+f}&nm-EO^vfai) zipqv2s+yXr()>L&Mb#8V{SeTG0HARA>Y4x`q0WGSVf~xXbJ0StgPxQAj)4e(h=ri# z?@;_<&4GA6ZhBAwpnFzr=sD>AXFfBtR9Qlp$YPjHJ8abCXmuE@>A0Wz0g$X7xG#fF z_rbORE4i{p0qnyqVJ#{jQ;QLbgu{r96Yj?nhcFN1n}sQi}PIB#nNGN>2*t7BnUE08(55Pa2v~iLdS%- zV@1QX!Z$OsB(4Xvic<_aZ9ogh(K!@2C{YA+*wz8{W)grGV66yEW0Qq;=8@1Y8!SGv zb-IN?y8W&ITbGU~sb;b)dmYzKc01iqi4upMQjyUNIVyL_g=@8$8upRjFmn722T)F= zyv7k|dk|T=KhpR|b>YoZ8VgK-5qm{Z0|@UOxh;hCRzNXnW3i7 zmq1uG;H)t?V@sU%B`DOnztr=}CwL981pEd$Ue$qDlX$tCSNTk-d!|$xaN1x3`}{ex zS_*G4;58H2B7xVgS{iuJ!>Z*X?CQXwP5CSj`uWu-d_w@CPXjFj zZk)lOXbp;4c7w?rSW#i2Zue*X^HlXv^f^|9c!c6Wo!iBZcxi;GZt&`b;d)LOu%}}S z`XFyQkwWdl%%5<;oEVIqr*{&7dYFhxSg%8M?o@_AbBMEh>5Cnl^&{a|Q%11Vk?=)~ znG)g9VON(@7bA+)gpO!0ur8Alo5e#aN3lV9e7Co`TtrwsWT8;d6_a?n=UiMu5Bth{ zWfZ3<+GRmvnb$D}kQ%I}w9O;;r|!>3ux=<+bsqMWTRI}-M`*ItNOn+zG`M5qV>r3s3Ci^C4K^nPEBroTo zeURD7js+5jh2t{}b+;hmG7(2XHgeTs&mhzt(G<#%_)}an-m#APwAb$KLy#grW46}5 zpt3KVyKHYkkZhTE(rFncAk*Hxn^1^-s)cJ;9hQFnWe*X(qbX9 ztw|kk8*(L^@%lQv+Ed9{1pF@u-k;69Eu7?#D}%wGbV`fmek*2;l5upKPrc2BZX2(2 z)tKQ!tSIGIFE%TQ3ye-6V@O_zdN)~*@7*Z^6 zPP){XG@(xDMU|Htl{PeKd|6m)!1tEmaV5?wSel(Cx6@?6Ya{X6Cw|cFTW05*EN7+2 zS>s?0PVZIKrbD zdQpm=NJ-~;sp;C)`y~_F{x4jSZ(SCxa>Z55_#9U#eN5S259yuMwjI1Y+5)frLiF9u zu6H@yZkZ{T0LwsNiZ9s_uuVsP+z_^@;CK*O zHVkGvIXArH2VafiKYHQ%!HSCgZu<52|2zBJd}kX;07Bs&3YeX2q6=k`tZVH*aJXsb9BA|kSuJ?&zWHu4y*=wsg`nyq=02bhGmwm#|Ti( zNj1A7ID^tgV)J`!yZkE2y!k!#ojpUChU5STN*@~fzvMeAa7!p2{t`?*Sb3Av{%QFK D`-fiz diff --git a/tests/graphics/shaders/bin/dxil/compute.dxil b/tests/graphics/shaders/bin/dxil/compute.dxil new file mode 100644 index 0000000000000000000000000000000000000000..f64b59bc308c35da4656783507a18d50ef4db8d3 GIT binary patch literal 3400 zcmeHKeNaw{ zcJ_~Urf25dbMCpnckg-c-kje}VVPRf^8A*E($>&p+3HI7q4@F58~}ip2LKLj0aP8- z-B4?wK7yJB2eeR2ii%|f?5{|1$<}o%ebzqzjlRC*MVS-E^Hv`ChW$5`h-YFn^jT%| zVU-mwRN+(0_E!X^8x}U_XC?Y+C!CkrxTp4Mzob-EnuP&i01@CIoV>8CSjR5Ht|x$T zwPtuuOakD5v1kVqUY8HYaJ%HFY78yLX!(X?94DC;L5Nb&gXK2C7OwhOwE8S97vvGb z?NRcdxV2sZqbYKq10uP4QA>G`ruy}&op#Sc>%9YLMiI6Xz6hIFqGz6cbzI5qV$)RhjD^UpGregcVB!t^OzZBrXn;(RN3v zTQSwMcgpgZ|0R9wrn&S|T*r}6PHI4ShBo)9Y7aB%Z3!k)dnw(}w=N(=ZY2?UJ5Hr; z>-uWdTz`A8O`N)B&zS=bw_Y|zN$9}(jI`w6-qG@dy10bEaOZtO8Qx01pnllZXmI72 zT+Jo~`n)&wlsQPXz!t=`$ng3eyn(^ZUaD@zXw-X2D~wdEz!93 z3DQ8p8J-}Q;7|_^G3I#+&hvDJa71%Dyb0__1)!|}rN2IFWbb#yv>DBpfWtE;fr;ppOXU^@+ z-lDXiJ(ww;xF-U)6`=7|_*^sG>%Gt>AUbamm+xQ4j3#RA9oyfEK9jkf(_Z&poxSct zyU)&1WprP-(A(}ida3wB8s$5ET@3jyW@K^*RAsEGb;y{+Hbg8Xb_Evyc=*SClM`>~ zU~ml|b1{+<^Vhjj@nX9I_P19tC58Pm!`jK_Vb3gm!9jLQoeG+r#RZGoJ!6~0_{ zY8ExVl|z;@*eK>Owch0A2wok=lwV+l{>70{AUM8Mc6RW_ts6UNtiAA5;zvpRA^Ej8 zHw@(t%2)5*Q`^|UcN%AU{5}S6P~xv7lU57VcP9kj2!>V(uxw5o1cVtUdo)Ykp9(;R;f4t+l|3S1ehS-dWb0k@{( z)<+R=+F#mSuMn;}p{u^j)!b#z`gEE4be{TRn0g>X%Ex+>7JHK>!fnWyG%il^+mpwQ z*k8Pw4P%-OUE%iXXkMo#&yD1Fj{XQP`jsPp3d!#uCH-RjR~Dot-DS18M7K25qj_wR zq3+LPU((dWVQRq}^O-*8b6Kl>jPrw#l3i%Tn9MqC0jXo)Zv@&G^}G|G6}+Zg6%l)> zgCF}`{j9W~jr^I`Z&4MVL&!8E;4Z}vn2}k_dV+pM+0HxcR^E344e6Z+s%Su3sHd zN<^qFsLg8kp62xAv)6=hop}!0|CvKz)xN9}l2H|~l8Qf+F_G(3S5vusrwW$*$+rDv zLWeNn-8x7Q3RSQNazc&L?H0RL+#K`{#!^n(vHYu^2(;Q^;HeO*jryw)lkBHof4hielqcQyHloKhD;FZw81aH za_IMU_PbeUjSK*p@a*zYO%{6>Xa5gmZ@butj9(NW)qpszjO}Fa_!2A zlS)WNkjS<$U<0l_V8F$0#>KC3=)@ffWP&MRh#dzP;y?|Uc>G{e>PIJ?_O37<+R5}s zr$5q8@65UP>^a{(_w3%g=i5!lR;tvQQH8BuX}jM!y&$`k*!F}0K@jc@L2NL_0nq?? z8%QCLFyM^CASfG1dQyrM3@=+sdUC|dH9fxhPuJS?Ea^pHk9j%cAC

##&_}fKCgY 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 C-_?-- literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/descriptor_indexing.dxil b/tests/graphics/shaders/bin/dxil/descriptor_indexing.dxil new file mode 100644 index 0000000000000000000000000000000000000000..8aa4e4ff3382d6f369dbb485b58f48f9fd079a6f GIT binary patch literal 4452 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 CWq+ms literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/geometry.dxil b/tests/graphics/shaders/bin/dxil/geometry.dxil new file mode 100644 index 0000000000000000000000000000000000000000..8afc0732d1459a65ba407e6d413175b0c108609f GIT binary patch literal 3832 zcmeHKe^3is|t^kNRh7D1gu!D`~PP>mHw%-w+m37Ui0hES@YXl#b0Oqz6bl8Jrq05xr=)9GKC zPQP>SeZTMf^X+@P@AEDtH(7iA$>trKMtrvI9J|)y_u&o~1^{>@1%QM+5jGuc^{`FD zW{1Wr&@c*HPHH+Qg1UK1&v`|;5)M%Oygq8qh;+g^+24Ow$XUNRdq>6A%B?#}!D<-0 z5vm2S&BvzA`F}5VPKVgK=VX){`OT#U&*#>z)~#L(ZP_{Nxnq#4U_<^su%Q^#5Iun; z0Ahd%(C_<%)?%J0B+Mo)(Qhq%8c)wVK#qYFp%8zjm>3FM2^gWy&&+ybgP@Hxg*R#j@N|NXjz5IeQcHY9 z!D0A;JfrMoLGmHLu7ZhhzC(N(8SY6!+|AU(9SrS3aTxS${)ho2e~0d9Bmh)vLHxS z?zC3&*0^Hp?qVU7CBMm*mUyH!um}D%99ixlD_F9`E-jlEs^^6=obT&)XE4Q@lHMNDvT z1<(>yajqE&6yd5QH1jiX_D1-F&Xw@}QUlr9*|_o80W-thK0*Wwi= z+RiSfCa>mD3mfu5UE#yi?|ezTcIkq|{kIZE#eqmsU95)twZtcq=w&E*t%-`0WylD1 zFdcB%uR^X}*4oN4j3nmb@3_nH3%68k&fi&?c=N&4!LgBtx$WIIhHqriHd{)I{7>V! z%Tqkmar}+0#^L77gl}3-!AKABkn*q+k6Ka}%ZxfC;}epJ3CUfx^zF{BPu}frZ#>dH zoFz6dEvQ~mRajmD&$t}HNpbLr1DlxEO-IL@9A~t3pGI3>NL?TK@mHzq`{S0Vmo`pz zd+xiA_;h#o4DUnBa3f3HvI=F`TDU8{Ag5AaS(sz~l{EN7=27|ajbXQbhGy5~pf1}d zyKOzc?;bvK9fnNJ?b{m2V?@S~zR8dx8J1M9Rn_*|l8xl!{)qycS`O_(%PZL2hpdqm{!G^@ct))<6U)m8&*4IT=RPTQrE zoPR0je{V)QlP!&*`$BIkLPiy#Zhcr0*N||zwRA$k_xY8bHYIz!epn-Zst{-tXF`yS~GXE6<6i^kQckXs*$1oX+4u>gca9_bX_ zyqj`p^*2^93c^(fg3^Ef`62<2+a{L(G~)5ay&~fR&U{|gICbYc1^C4b^~=8`UR7sJ z%K|{YugCEC=Di>)x+^CI*g|!^_Y>ZFPvvCe{9_+qE0HJ1ZoK-}MRtPv^xDbeH?DF(gvde?h}gzFR7SaLX9Sij|t`D-u_X-ymYE&&^w@XLcwwd`{dF|j>C+#mw|A-5?^{&F1 zOC>3j(jm+g_C^=eOGZ_@bly==jF5);~5Gi<9d<&HGV*(W{X!E#W?chw)I`zQ!ZhV|yBpbY+PT z{nHWN@sCHi8r>-o*8cy@{@*>b^(;D%;hBV|E=PAO^q-9`&n+$3N&4hb4R24PJnmBasKFjJwGQCfWS`oH2RqQf*G|BJ1LUIt?FkSrAVR?cWhP6lW2)#x zcfCenWEpmg({PNz!wE4k^G1i}qn&mx&kjFYB5k4S#H&Q_oZGgU*Y7ZNYRHUovFXEE zUDS3pk;f9ntc{6)AG^s-6tF~Iw$E%XM<*6sZ(`aphJmH9Q$*0hQ6;=#mx`Q#DhehPjFJO1E<7z+9?Nx5 zJU33)W6V&rETz+JB#YQ=(C@1ab6^^bSw_`32*QUy$4z5$R%YySJIPXq*I|(p(_+kd JeEyH!-vM}vj}HI< literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/geometry_vert.dxil b/tests/graphics/shaders/bin/dxil/geometry_vert.dxil new file mode 100644 index 0000000000000000000000000000000000000000..931cb657f0cb90870cfed8270b668ea44b0481e6 GIT binary patch literal 3024 zcmeHJeN0=|6~E>^{On+!pRu`5CF`9K9*I+rGztKvY_O=AwM? z+&{^s;7B9`0QS0vxrSqwnx>j#^}tYaKuXO|0d>9fIx6b^28D{laW{tkvj0hZWX^S_ zntBSmjv&57QZdy(jd|AOqh)&3|yJ${US}Y?m1%0W~M(mDJcg3llgp8+P@O7JHYHy*R zM{2a*pMpf0dZ`fib2g6~RD12dg|^>ypdu}OFCPGE&jr4DYWY}R%s{+zm1-g+wYDPI z9~swSRFm+z9U5wWvds)8dDw+=H=lPxv*_&e^Ahx4U!2paClr|=8}P&+jej;fM%pXR z>o6U$YD;|?myug`n@|e#xxB`Zr^)D%S9@Bj5!jA@(}35_;H}UCcB>R?3}O}%tMlUx z8;$0TMuQQf05kO8KLNAmVXa22X@yrmS2v6tt!_~vJ8YeW=kwhir$7nGy7!jN3WDIJHwgGsajGm1wrI(k; z(ffVO^n&+L%{8?I8BXBSByO4Hv2_LcN2{l^x4iqoY0KJEFIa9|uizgA zlz;Q-`=`H%{lk#k2KT)MY8f0L3DNttG2HPCa!jDHpVD29JGV_oYj3#TU~jn4K5D0_ zwgxU-=xZN+d8lZPK)L8*FUg;vn@BkWRgKoyJB+CUHzG=BxCUvnQsP&`BBPwuc1uqr z{Xnzoua47M7G+hBtG<(7aM0b8ze}Y!%?$ssmf>ZFX~hJqs?8iP_@?@`fypFEI4nmK zd$zv5b717^u4`AaMwnqvF@Ya)n0Z|E&>UIzTeoZW?MrL)lY=3nhM)`R#VlLAE1{DH z1`92LbAbTKXLVk^a(Sm*mSm~(ng3D2%fF7>0klV!@D>?_h?+1386VcE~N()P8pZn}1`FKwTg ze%QIgx8vb-UHzV!+f)VJwx8=Z2hPGx3nVCCgjFW*JXl%_-o16_!E!%(XvW35S+(-U zjm}H@`uaT-Us3x`aaktACLCW79^uh)y&8pc%%`?tEzOvvw}G_`*bfQ(kqysesZ+wE z$v66hN2IY4Sesx9$(_*T`jFhIW?z#TJI=sb3O!~s)@nwq%^ox9Nu1)~D}H=I%C48P z7gzCB1D;8YC*KtbXGO_jQ_2x(d(Jy;IWwB{pKvN-@0f&> zBH_3_dD2Axz^}=k&}8>U?Av3CZjHi=Nmm_&P_x93LBXuz-LUz)WC&eP}yO-=r z7p~5_hUQ+mUd;48bGUhjrP_43sc~UKKklqtw z7!%W(z+tqNwWWURmmQ{n;~QgIW@?C}z2{ZM*hs$QyN%_3X{8^K4Ep4&We0gaekx!% X?89jvzQvE`25YasScOq{IZFNx*S4i- literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/miss.dxil b/tests/graphics/shaders/bin/dxil/miss.dxil deleted file mode 100644 index 7119624c1f02254beb53a0fb711cefe459c4e411..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3316 zcmeHJeN0=|6~E8#@tzIO_5+*X1cU5QvqWX=VQ7Ft7JuPF>tyC@B2%V4gQ3u3Vm?NI zu*n#Mff&_%rA{&}P(GSX+2%$xDM{KmkbuV^rCC_^7T117uuf4H?#8ccfkh)@Pa0l7=TEqDU-~~w6atsNJ>mkRPLdbiAkw! zK%P!rumF1s0)vo17$BM(bQOZ z*ko3zRNn%u1E4T`a}02dQ0GAKA^uU=+^n$Q&4gf|Qy}1!!B-$y`74w#*t5336FBJ- zzaqWnM?NTP)M+J4V5FrDi2t z;O^OZ&8W_8aoufQ?ZS5J@myHUP?$5?B?A%6M=CBmnSJ0UUh;_55V!4>R`mv}!li{{ z%7O80?L-chhayEBc21qL%~~jTX7gm`Hmq;whyymCIELKf2t$`E%rRo14%K4ZmZR;z zIPG=1H>mRVHkDeI#Gz5zMT?_y@^!qvE1aTG<`_!uqU*X;)adYLY;)Cc*MMi^H|N81 zU))`bF~*MT*l_)l^$XEMs`pAnuQrR*qraimi8R^S%vs9b`GS|U^LkO_O;5)&KXKgA zp`m0U9Iv>>=d5F#d&-@S}}GQ#2(R6kJ~o+#A}!3Heg zzugj6uOgZlqHY0Sqlo&=NJaoNY(}m@*B}97EO!Jj&*Kb1%kx5=TOOxSf#(6^?*jB`|+!Ens>C*BBAUaS&?X9YTIY7$Tt-6Hi<;CTdc&C~y{rjnz5OE&6+*-)UcP!fyQq>4JfpXz5&uSt@5*zQY<#_7Oi{$vy$-998jInkju z(nbt!3;c51aX94uNJpU}@;DKBeCFXcJ&s`` Ro@;K;z%2TXmD(M@5&yDBbVzeKe zK)_k#SjvU;ixYfJbV1?b;`+yjZu)0$-y6f!k;=@dOUj9f@ze{ukq;c?`_~g)^FK9I zy~x~>Pt~5#hQ&SG_i9tzvn8h@WTpPVp_SRS<@+nsvuk760R?>bV&*&NWT_WYFVYub ziizEm@%VRP7)-wMhr#8Wx9_cuam`-*+t4<>eE;^n*%kPvL(XvSPXT+a|k%Zb!-XANv^POIB#Wr+G+ME#=>nD&Ux`5msaTH>tn zI2%1J37-Z8pWYGt(I;4^(PICQbY)077i@2vq_cAAwU(G!6aJxFo9@@9dxGsdQ)&I$ zv<@_*f9h-SqZ{^&TWE%N%H@|6%~rIAa@JZ=b}o$5>USPFLo|6>GFNQEDwS|`K@foT zs+K{{f_>y*$oC&uKjvd)t&2ZS`GK?jv-Kk$663s$4?h0?TlvPR)r{AKDc#A4D4a9z zrQ*H(*MFD!9%al@>qb#hVFH}Bs0$XXoIdp4XOA>Guo-q*G?0Bq`1(GRQ2vE{feZ`& zN7?H9YkX3cm0R~vAOJ*|Vi8nI z@SKw}dbYi#cZ5G#V3D-@cY22a4LD~)HpbgVClI7G#8jBmwyJJhee2z}9t1%uV6sxX zj}~ELA5puaUEOgfZ!8&gJ3#Y)jd;KD&xp6B&`G{OI@f(5QF#BW^W9ZdUAFJRa(!91 z|MTqA&$A}k=AB%GsT0`S5xei}j@gQkF!8#oqCe)>5fWrD)k!PNWzYlf%AHBY43Kg0 z-T^EQCxD#+rW}<^A_ZK#dRUG;caj3Nq~7L=C$CCdsf1x(8$Bb#Zhjqo+cJggWF%-u UAteXz*AK0k;Cz~oO&gTI0fsIm;s5{u diff --git a/tests/graphics/shaders/bin/dxil/ray_tracing.dxil b/tests/graphics/shaders/bin/dxil/ray_tracing.dxil new file mode 100644 index 0000000000000000000000000000000000000000..1a78cb5981038730ab1793451629e78881726939 GIT binary patch literal 5936 zcmeHL4OCOtmOeN4n%smWTujtp0^Wd95o&J&LQrh)O(F(C4fr$GI_(XJ$`lj`rJ^0* z&5s5x)f9M2#c{yDs?XPl7R8@VUkFhn{uI&rQuSF{DWc1^jD0gpXZ5|#xdGZfU)Rif zvu4)Jn$^9s&)H}1ea_zJ=jML*n3ot$AGx0GjGx@3$l2k{`EAp--y;A3Y8(JUSQ{W) zAXh?uLjXW90)Rfq3$n5)9O_1B@vQs>6JY}ZlCUaM2>|?oqLgXVQgsGB&`r&lN===n zGf*Jk%q#?OECSjw$STM|$Oag=4>BMBAY_nVRJf*Mx!G1}1C=Eb65hL^~ELmeO zvR7J)D}UO15wtLsl@-MWuT>V=!@d8!3rrJ*ylS{6VGXASWRRaGeqJNQ&;4nV4l8&+ zxWs=!QNtR3&Gtd&y z4K5tcg!d_c+8vNb`tUo=_knId5KOLc_zduU__g5A0bld;8mXZO7A#~In#BODfF~^v z8q75Un@%S>)cR_<)tkbJTw3`eF;F%M#|n!^h7- zUDL~_E23|*IN}8tg@pt+syR&+;I)w)W>wdIKI9;n0^LD2?8one!pS;GOd+)430T10 z3^tPh;jtZuvS`g2;80 zsG?b9Cq<=RdHIO2c0?#=MZ80|@cxh7s%X(VR#e$7>?cH3L!PW0jxgle4^7P?=u_G& zhvN*75Y|kOG<&u2v&>*RV8cI7J0HPlxSwG%?H+}PPch%xlt~cbM}cohs}soYp99sS zTsnM+c?;Edhyx@qL1Ke;1fjzs06yrtR?PO~ZtNcIt3d#J8v&73`{l0EpA zJ<2(HZr&{|mwyZ4c144wD?!ci7;N%8e28jzuG?Wf9?kV;2^0Yx*{L=;>T}+Y*qfAt zY%af0?kGRBxx;}liA{$NwQTNq`)Kwj1g5|ecaoMKp^Z$yd)gREDlaK6Pz&9#xsni0 z90>XQ6Y$Z~81G@3^Jclk;@AyrtBPiSj$r%+i1tcv*a67W@D*O6 z!aa>drxva$SyM6e?oks?+4HE>PfI_P8E**H^1bmcz120X%q4c}NJLYUXywCrr+5aeX#~JQ(Qe=Qyq{0k4B= z^`Xph6w#qpQcqDXE3r{_Hs)Id)C&HI`^OV)r%oMcO-(18kB~>E9BR!x*qV8wozjye z`D@vx=v?zy$)47hW>-G^8}3yO#*f?n`r`f@%I*C^tYM6My{%dC+&RtN#G@(j?gTbmqxpWO{r0Y3ei_ z;#8tj-N(e}Gk56Ir=Q9^*bXx~m1v$&>rC8d90%1$+oz|WhT#&K{s&H;A~nYPJ7TW1XjV|8!fr10C3I%cG_w|+ zd1-BJWtnI_E~>V8%F0CR%FwE{o-)!CeJM)*&@2Cpid;=a-W`+=TIDH3Am)x%6Vk@` zZLuq;%`-l5&FD5|w4s?FxH8@7j7x*cDps_9l_-6crvjFor_AdqV?|YyMOBYS!C_zL zJg?xMa+Rl|(No>%Nd9V2{#CF1Uwrb16j~5$(e$-wE``h6HcgjS6L7?I*@QQ|ri`E| zqcL2b>@+l(3^nMChR)|;&~KeHuA?(rJ8Oel(HmuG1>v!mq5ND}Pg&6O`a#jUMn`5J z7rB~_{GwYvNVyzAWWsHl59GJS@B;sTQBDHz3al5=BFCqVf84#}Ugh$gcckzBo@Uc( zem$qNdX?d$4W0`$JLa7OqWhKAOP9U7;~q^~U&3DQ{oTBe?p-dsDZ^H{LWfg#c{Y9X z@byM1COAIIDs+5$X5P3Pm-~-t@Lh}c|BY?;%ksJlj~=}-^+?m@q6|WH#F02y@A>B5 zu`|*0&NzG}#G4;425M|WWz||acI9wS+3u;4+pc|OFUy?z{>4Ys%s*DmzyIjp8eiVA z!{KWdPfpSru682|R(8GY$(6h4+`G9xvztyyc0XIv`NfQF&tVJmh`js2l&#{pCud8W z(DBk8UuS+uL=CwG?wKcze*B~NcO#r|6efZ5| zG;XGEq9%#UE=VDEY`c9zYv2RDV7T_>xb{*>h)-iScRX(vV}96Yc0&gp*TF02N0CGl z_oN5DS^ItiwhKa^1J|TXzVG~Lv>WEeqcMn)m<1LdXYq7$`>FGvDz5nNzjfop<9deU zag`YYJRWCVeHv#${Rqwq{tx3U9uxl+IP0*?jUX#wA0BIsg7s5atC4_u9&hDB+kc3+ zd_Uu@AMlpLo5-)_|82|#XqaP|Am$qSa^PDKa}9ld@Qwdf%q52jJcYScV!mu&MfYKuO#>wPVkfERb`s(-ataX2LQ$#t7(3?Bv7_l3`aRU?RQ+*ezk)X#?wIrD{&rIr#T#0o6!S z0Un1*3tZ zPNIEp{YBTh9Q)p;CSz-dCd9-JpO2sM$efIhE6aOWQqg@xGHxjR>- zX8|W^adzT9UQPZf%HW~0?RYVHRmWRuzVnCmICLj*=ODcH3W)sV3&goxbKJ~*Q~?V} zT(}_C$_|V5u?t5;#e{_gBMuXm6qE(>W^0O^f(eSTk9U<{kDeW^?LLn?o=-48(lK@0 z#L72v5B8=MwDJRvnZh}UBjg+kzDDd7QD_`8}8gdL9}$h&=YLD9sirn@4?9%G9#Ohwy{j$VGGl0pg=|C>D~uP4V01!wk`*E9 zT9pAN$DE7UKur9Fl|UzZoynI*HB+g1O-E)K}S1FQ?;O9RSTl$s+<`@?UF2o z#I}{e_x*#kK~>YyibUZk_Zbbxg3uEPD>C`}E+`G<5)bSDESI9;TpE7JW$^o4fV7TN z=?pMKbhXsWspsNchA^JaQfy*j65Fr3jg5tbp!gZnG+`lCLSufw8X&;n@AbwS!8K)c O@Sg$1+bEyVF#S6f3Xlr` literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/raygen.dxil b/tests/graphics/shaders/bin/dxil/raygen.dxil deleted file mode 100644 index 6211b34a10f7751cc1511c9219a5b53d0c1e3f9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4384 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 diff --git a/tests/graphics/shaders/bin/dxil/texture_frag.dxil b/tests/graphics/shaders/bin/dxil/texture_frag.dxil new file mode 100644 index 0000000000000000000000000000000000000000..8f83ca909778347761a106c79f518a6e8f56f742 GIT binary patch literal 3820 zcmeHKYgAL&6+X!g_ufEqb0HbM5MXY2ReaR&kcWhsJOE*U8ib+R;xa)&SOpA^VF0IV zF4_Mn|Wp)IvpcT2!izgPmEcJvXAmxaOC?`oq1l z&)#Q$JA0qI?>T2D2`iPVlue0MnGZg$CW6*QoH=u!W&r>u2>>uCWsuV#AAvjtc?5zn zH~?9YGm}!JP`sp+%w=I3IAcS8VNaexnV86oE|`&w$eN`yxXW+GF*AFOdP8|(Md5}L zkd?SnwS4)C1jcdb8EIFvDve~SJKiLtX; z%;(4CJ~L&WkAnOv4ol{u7x`zVu6i&!$qX+aq*z;6@{ z8G<N>l&nOTagEEE6@v~P!tO<0+d#w?o2C4+XQs{59N2Y?mYJdCt!okECV zhQJ2J04D_{!(+Fx%)DSX+}oeCC08#>WGlCMDBH)0S>hy!(bgV-Pz0uO+qtZp_q3hwvIBT#pLV`zIlpK5xQ7f%P4OHZU;z#e#|oo zjT$ALhQrkXP)`G(f-*cHnM<$R#Ays@H^bq!xz#4}O51GpFt?|X1%V(Ki1NV%-mUo^ z2t7-iMaun@o?L;pw$z^gxYJ_$e!DF@_tBP{N&VDXa{jlxo$qP|l4lYp&%zC;P^#% zf?e-S=dgiLRMu^&&{(1hEY$@F)cJo_6U9!V297{bBgM+>SUHUq+lbN^O4SRcRD&@N zPW0i%7mPQ0bz5$LXWW|0rfP>9wyVoI1W0vMo@lJl9CQoP{x$5vP|P%!h6qo-(OLycIA92UgdqW352R@?*{xb z>f7v}MQ2Av2ixa2jCDEh^lW$Q>N<6K6H|u^>DGHIF2l^}T-bb=cg^&o2wd;$81u~+vEu7gG3Gw2Qjb+v zVdc%Gya^zgIAYiH8t)hU2YB{7{v(LWga{vFc=tPKVX# zkjg5Hj<$FYc@mR0=Cqbb1-GY&DK!y6I{a=)e1|1|y;}c#X?@&DQ=C&3djyf4G|9|J z+|ZP$QiE+Qz@iH*WpLD6bT*4lgH_JMDyQ9G*bnuVHMpgevXnJjs+$c9A50MsMu~5_ ziAgDvJJ9Mo-s(H#8b`FggA!kd!EaEDer1DqjViX;H6HJaX;Q`1A#qK8i(%65jd53z zxXwPFLxO#zLu%$(D)koc%PL}e6dk9DyQAn+l6VB~9Gl>wTJQwctCR-73(6##zw@E& zH0jx$V3tQLG`pqs-HH4CnV4=mO0eWvfALKanREK_v{$#xV{GoRV)ixNvx~P=8-Dt_@H*WADJe8k53Ubr047TZaa=D+_JQ55C5h- zC2&D`TZU{c$e~sMb?99pMAacptblt zTa%=(ykSAh#!nl?3tC#d)E_Y4y)yV<+ra*Nz4r$9bF%%yWjn*8mv+fIjzvbF=n7Sc z-}He0mmZ*{0hkZZfRLkD$Q%nd$WM|$T~jYle(o*hSVkzzCj#06Q7$lQK;b5ncA!qd z*3*={#WQbJc&-i5IC^${k&oF*1p(Y>V4>Ktx6ak|AkZiB?+Tt$E%N=NsEx~#?xs0y iT$6OSocBDMzKJD5wK~t)v(6u38t!b&=EnR30pNe?exyYJ literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/texture_vert.dxil b/tests/graphics/shaders/bin/dxil/texture_vert.dxil new file mode 100644 index 0000000000000000000000000000000000000000..fff537a1e2b8f0689f5a4ca00e56003087bca66e GIT binary patch literal 3104 zcmeHJeNa=`6@STl_3C;@$8&`@U(gaG<$rngWTp|gUwlbTr;G$z?bAI=nymR0Cy{D~LYj`ie!)>-vSl@p9`+dUAqvaF`f(Ql#p+L*QFn}=* z1{VaLfw4dX8VpmFPK*J6N_3`OCHujG3P#FboeBaCuiJ3S0PDTa#mU;KxUt5hGwW(z zhRl`qnwpwgEr`{C8Wy1cU5&(E5F;fssS>k!gH4uB;K22fV%qnL@rdi-(St|q8_PgO z(?0PX5HACR#6K^82SWO(RPy)FBG|CpO4|Q=AzxgP&3e#ILQ*yG4K@W*Cwi7n0)S8` z$#rr??$N?90zvF`MMeDd>LLM(QC2>>d8N$iX%E2E-CM)_!$Lh7;g*mR-+rQq^kQf)P7vTDZ{w>bcs4x z9p(_4s^B{iPoiF`W`(ozW{j%6p3poDpfP+OSg zOd0Jd!)ZZDz&!0Y8(?ipw9|qfou@71Xj>9#VSx-un$4w%x+S9TOp1_q`+@D1 zh>%}S;4ut=+}8oV1N81ypmShDxQfc2DIsEfjpwBP{fu+l^^_jx4X4L>v1iIdQEiJ} zyg1S`bz(xdh$C#IF+$)oG%F#+5Y?33?p1R5-LS9_qmEM+#Q2AkLW`8)yKTTvy{1_W zw`AyD`P8-2LG9qPrBan>fUcf6j0NfHDFcqZ>T@*kUr?VO>&+?hP6v&ftW1SMmu0J` z*+ySFG)_zZglOUqZTtR?v8&fge|$xDm9GA|0Z)I;s}%7484PKWR@QM>b{yG6s@jda?{VUT8E3-=%kjh+%e5m}2 zcv5ohf^1Uq!)=t>9>zyq#hI6j;y0i46^DwS+_c$u&)*?4=(qnwpBEhk?Tlv2Uk6!c z?|ruPbol=5d!H>|K$_>f7#}sSymzbbvcYcOJx<={i8CR2bSLH(%sdnv;7}AnO_@Iy zQoGTPcGMMdGM1stCphbwo3)dn-ZDLvduv2+K%AC<`S^3NBCb({V8vW}=%@odhM^tR z0fz(abii%x0S6J_&1JDx!mNklOuIPq(JE`z$l8g|3TAh}5e_&kXqyOa`(qkN`-VI43Knp31FexjN5oU~ z`6}!42duU0tQ9fb7#|TVjR@uv^F6CzRw$V9>6Pz#C&|XT&34a%b9=nUCjLtDs*_0&oz} zFNm2#zmxy%*N|^PerIX(RU7rL<4?C9=})q=L|;`TJP-mCOaM(twaQe@S+{w|j=y)P zVR&Nnx1AsV)%xZQlJB;rCHYSW9=whG#{m8m|0%!ZzyBTot)C50{|W!$&+}hzqsaGk z_@$mKcb>?n9?s1u2`Rx>N8+tc^4}hi_`l}ALQFfM;xf|PTx?`|K}^s~RP|?=QxX*p zWs@&#?eN(P{bT)S&lF;n62N>+N{LEzicWPN#zlu>YPoT1WlXExl=W`jrIGKwxNVgA zp+j|o!~7Vp<0Bc5B+YASYto^rp+783Ria3O`LHIR@^wI%K4}lXEbpnbD3(@vyVRgD z+wiZ87sO3g=&&ef7Xunj=SLf&`kZfmm;b8)VocrrY2!BvWn`uT;&k}owS}&U#lahU z=%KGQwHLcutWC|WdyX_UA2xZct^+?bLFW zOjdxyU-H!dlc%f%1Qmk&l#Qs0$Zsz|J&?ITSqdA|yOcYtATJSoGavZ!X>`bIu^4@v zulzKqqPht#cT?Oef*Q=Gwa5;v_uY eWgavo;gnWk-Cb@99;{Q$q~MKpvu;or$UgvQ#eGHq literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/triangle_frag.dxil b/tests/graphics/shaders/bin/dxil/triangle_frag.dxil new file mode 100644 index 0000000000000000000000000000000000000000..6759c8c822c623dac3d0d1b35e9856eb5bc7d48c GIT binary patch literal 2964 zcmeHJeN0=|6~Fd-@q5Ph1~h#0w;-4AKOJD(Ya1l(K$^uS5=|8CY}!LNX``B^66iM5;`h*4<~DD66Xd zF=_j&M?UwQd(Q8kd*3RfI+E-Y=Arf zc@1(8bT)FJA97)Kt^$X)P0B5NBc&8h*pN5vIbkOg6A9~)VabT17j(wY;3C6-!r~(Z zC+m*aA3s?Gbo&hZ4nW^NxW}F_ZgUSgoHL|>{QW&(j3QI*&noMoub{A4aSh5e$Uj8i zL1OG|7W4aeVsf!bd`1Z!sM>VACU|DXL^4B|SU`^;Xy|zu6N{w>2$PsFK|i^9)=e8D znSB`;TpG+_VG&(41t&&0-vgccl3W7=V)ptF+O@jj`!aZ-ozTX!Q^B=D=)-J@XK6p0 z%OREN?JOrhX$u|`kDe*Fl38qRJ5TE*m7+9UoEM?gx^uiDN|)`v0%DZf2RVc{Dq*~U z-f#0PIUcs5vTV+NF#xdKK;l_sQiN&PR|U>>Mnx#*yt&ZNoLOi$YAGmN;lPwonSgVt ziqoht;j$AB%g$b}DB9rm@SIKqsYnD#pe@Fl&Q^3LYT8otMfzesbt!h#W-Ws2g`(PF zSH01ts&X||Ay60mu7IeXBAVd{BAXRhZ4XvQVbxy3vZ*v~Di$Ng0H!#PUVt@dux2Ax zKgC%gv4#-RNWcgoRv3)NkU7PI6nO8Kwb<>>qEa)%a9?d;yTJQ}{dRt*(=Wtw3Aj=;6C zh{2o97LKP-V-lV1T;3me@9oTEwOVdlY?l7k5gUu%(beDI+d6V~Fn5kbg=l#vMUHb! zlnO^_R!xmvBa*ZrvSge+z?xN%pZ#8DRPh}F1G%+Ix9+Xt<<%`KE1zz8s_Mw@_;y7_ z%Y9t!;0fH#)s7g*wqs-39O1#kj;vB}ruXH(m;1TeB?E~cwQHmj=dbP#@aO6e&Km`X zZqUQ(|}oMRrX6>Dn5>N+j_6%hG1lGv~kyZPGq(UG`2z0zZfEkT$=GKpmR zb(tO{bF$G>Z^qunv8EiC*^D)tk%mT>nR3NUMiFaXVo4EMqljEyC)Nvy-Q;-OeVKGt z7B^~&Kc;BS_}Gy#rAxn#s6Te7ok+&yx~Rd3yah3Z&fMD}B%_oeYi(Ch3GsI&O=bFme9u)usD& z>7Bvx!?84%~m-1C0&y`H!DLeJa#W6%5F^}KLx zp!knHkGTtfsOPnn%NyckR=j`zwLf!2N|}JWB~Xoq&}>%g@73ccR3NwOu~m ziANYyHpVx$@1^AzxoivUbQKP3rR4mGUH&Mx&lXVOU)-vg`1;H%hR4@DHTHru$<|8_ zb!%+0J)lDW+G0Zxqi#CQ1i-=B*|qu7fPZ3PwGX9VQmVIoq#PQ$o_b>kYud^G)6G{s zpMPMedDA!}8>_pZ<0bAq_w(k&okzQ(x1aK_m#zgS9=H4ZR!3JS`p~>MrMg3z`udRi z>Ww|Ae;nFD!%Tr6d(;21H<>5^;$hB(D7}lhoDs@q9_TfAd$lbcB9dtM`dGf znr)@T;v!iVJEhzUD4dgBX*h7eBi;^hyUi3gGb0YcttFhSl<^RpI#2JvsR+T{l?5{i PAvmi%M)VL3{iFRCNvU(F literal 0 HcmV?d00001 diff --git a/tests/graphics/shaders/bin/dxil/triangle_vert.dxil b/tests/graphics/shaders/bin/dxil/triangle_vert.dxil new file mode 100644 index 0000000000000000000000000000000000000000..31548d572a0e4c0e5b3770d5f8beb4942f4f4c3d GIT binary patch literal 3144 zcmeHJeN0=|6~Fc~em2g6eOmSj|(JodE#VMJ9*uV(T zN%I#x18!$15C>KYS=vE0sjy~Boi!3)Lnfn@$!G!@>B2%tSG66g!qlnLw)<=xrB$>) zCT)N9$mia3@A;i`?>pD`_nxj&qrJTK+WqI!@Yh|x%~}5Hh~Ov%08qjL0EN90suAk1 zpkmOm33Y`Iz&2E~-XLYb`GgqEPs=LdfC@D+Uy^Xb9@({#gaOCLzTqd=M#+Vtn99ut zi=q4(pe;9+9|xcu=06GNAD5quOQcODgLlP}FknymNnFBju6W*brs;I^=`#(9C4k9X zAzgx)!d)!vz9#>ILgt`S$=}x{BH@yDpII^7W82MNKTlKDuX08MO<$?+ke zP_z%9Del)H2rV8H8&h-uft!f!XE%oI$ecJ-6;x8p7PaML7-xgXryy8YX)uyOBrXc) zHQMQq#PGaja4yAz$Lh<4KGdDltB%kNbWE=3qxe|4Nen?2t*6?B9i?jeQZznH&MRc_ zOOxdqe@T#sYxVv&fIzOIVromy~1sn35V_=U__x626QxxB_{qS;2|*Ai{D2(;O6n>h7RPCINtYP%F|97UUO zv_8mjCXCjE;k2P7AWHwsBd`_~+HOOeqx3BdZHXgo9GD@F+=8xA6k_V{aA2O@46zyQ z$ioW(K&O(9k>!sGs|~{eJcF1-s1!CdXplL6p^C^-}xrF#a^2%`u zixqL6JuR7y;FuYjK-x^hj473UWMl~XzH1U29Js->_o(Q4C*9hRf_%o*J4{f z%X{634c2P6gS9E8O*zz^!vng32b+i0k`Pm~T*vS;H5*2Z@q*W36=rCL#=A2QcxEeE z#j;{U8P@%xMn4TwUS`W6^8=K&bH&ZV#1tUFH{;>7@ zdjIISw)4K6$k12h-F%?0Sjf*+J<+=nj^3LYND7CqE_W=yaW(vY8FT0s6v_V$r;N&$TN0ji6Q$(JDf*_T9O{ zer=&2De9kl5-$1=PtgieG&vWDh|!-okVcGXav- z4eRB^As@j$L&`q)SLHwd47{t#mCf&7uBU$J`1=QUOJC)tNsbi9W&jPr$*U8S61BMm zUWu5jN4bXE7dyJoUMkCaG40B`B=?z;;#_Efm+(<8EQIq3E-d|)3;%aqxO+CR`;S}* zUrCSU!tQE`w^5S%SRy2OupGwy*F2cV&`qiNtmKv^E^T&IiZf;E$`SUAT#bQr^3|;y z9eJ~Fyl>>^d5jLZS~AF{$VeWfI_ogWkLEN=)83Li&23ydZUhpoerrN3+dt=#|8hf4Da}hFCkM+4VYx)|`%D1ld+a@6C9pBRLJBRKJZs`jO za&d$_8nTAp^40%`uc~kWo`f~$($ojY?=eV0z>=#vjF^%;REMZiJ@DZEp8}9WX9ADS zW|`aj{onc3R2Ri5QQgclT@p%^>-(gE`{QviXaLi(tuq^E8;GMR2G@vR+*|dt0!z1Q`^9AN z8+Y)-0yoHInr{-t)xHz-ORK(_OnQE(c*INI;%?yDuN~(wHOFtx>laK&r|>T)p5lMW Cb~0-K diff --git a/tests/graphics/shaders/bin/spirv/compute.spv b/tests/graphics/shaders/bin/spirv/compute.spv index 6b369782f113f376998164b299dda8f88aaa839a..824647328be5a611e87a523fe82565eb8e22003a 100644 GIT binary patch literal 1720 zcmZ9M+fGzL5Jek?K|uwPn>TO(Z;0X@Q3PZl!AJE)Unej)B+3xx5JTdF4}OpF8~i8Z zEhesY=2S#GDXMB$^{(B0dMI^H9Z9JprPP)LY~JoErBdGiil%bvB}*wg*sag5Hg{TCZ6~YlZ*A50W}of18f&$zMme9*o|w|R z?ai!l2y;fGzWut9{q1x9M)OT`4_{_N7k+ocxF?^T&wKH*dXUvuHaGX`tyX&|ZPd%m zOR2eED9N#|f6liKqce_S=P`5lOk%FcC)#Ox3TNn_`VUjTm>Q!`ZZYp{ot^F#lb4T@ z&x(HU-W9y|i@9f*{-gK`=A4-#?;&;#!P<+Trd#iMqUSiVd*nEQuV60g=6#s@BJU?w zW8~Ic!RI?TTt7t~n&cbA)I7r9A$$cJW!5m>-1CkX_h`RntwLo4@0r{`#$WHq`Z%$7 zVQ$|jUJYV$pT^tgKI>=j9hmqaooDeARL|j!?eTj%%YEi!MXnY($BUYJtzW=9)BXi= zwOW(ITur_md(72ftd2R9I@j2xj_*_}_(givIf2>#4V{yC*Dqr4e+si-{~RtgT*Tbt zS^@Jsm$1+zuYH#b{4+hijVqXY#hrB(@A^r_u$VVP>^$FC%)3r3 z{;8OEgV?>|Ki~{*{a3!Inr1QItmm`exoW$Kcd5;uTbP*IjOFvL%*8|NZQ{`SvAC~0 zVB((pLxJ5T7WY1)?;f$Zzl$$L-+f|ne;c0Nw=#!$c7G3^-FNc<6Ms+c`8VnIgkAT=W=7R literal 1704 zcmZ9L+fGwa5QaC@Rul!1lP9o%XB1HZQ3N@dR1y+Qd;n8vp*yK9vAfEp7e0(vK7{XN zJR~N5-|k-8u$sxt{B!#Etkqoa%*iO~iTb0yXe;WRp{N%m0xP7twDWpru9Z~g78d8t z7>IIdqB(=)z?nWK9YeZ$F<(Os7(c8XYBG1iy%IjFxW z)thh2_3g%o=3Y68n~m)k#J8o2}M`^4OJx1@glf!nh+1}r;T9Wn__Z-GY)jA~d{GQ-9 zyAn%$se9>1t{^35$wHgP))?JJQoJ)`6kFe2O=df_UNPp}akOvD-8)y`I~Vi2{N^Ge z59jM&LOj-AMw@HTz;7D6JO6s-Pr%Q+arPv(ccE{eWwg5zlZU?dA{OSZWWM>&usa+( z_0O}Iy#tR8Y~RFP*tyqDL`;$65<9WK`|)@eKSBKe%E3ExhWpib*Zv3eSMlw67V(~T zLB$6$Ox)9htkKy%#y03~pYw>A{Oslah7oad+^hc!@4|hDoQVwoN{(-060uJF3w^|{ zBH}-oJB9ZACMI4)#QaX}z{mfCeB4Wzbq!lQ@VS94AMZ2d+{6|Sd~RV|C;p2WVV3$k z8gA-BW!zj-_ZiT_@}IH5!+gE@7ebu7WVTLTg;xm*;Pa?zGZWKuWPAoP9gFguOq&F Q@7;R)uBW=QgJt&c7bi+&tpET3 diff --git a/tests/graphics/shaders/bin/spirv/compute_multi.spv b/tests/graphics/shaders/bin/spirv/compute_multi.spv index 7db5c33b7264b36656b6043220343805be3cc4a8..7890a6ade154ecca4b8ee08371191b8746d431b8 100644 GIT binary patch literal 1764 zcmZ9MSx*#E5JoS|0E!ACn;Y1G8=@$Sh@vKd3BI{K=<5V#91>*6(4+Cq2Y-+8&l$Iv zcusfUq~Rt-Rekl{+U7Qu?wP(2xF0y`{AO$aFs<#U8=Xd@-kyKiIcz?wr8UA?g}h=2pLTcB zW(l)Kv%dSjnab&0|o-S;*_FC(J7|D7iW=K-Q)O)9A7$$SC8y+i%y*96ml8Sx6U-; ziT+gXX1?`|yBp*B<+yc?o7cF0j6bL2xa%2kPsGe8=58Wp4l#ef_TPY4WkoeoY)9jU+yH^Hivx0Sd;|DD8BQ`nc%Os@kwlF)R#Agwl^_r zjHAuxJ>%!mU5NNF%nRr#q8HKHaxS6Gm-k-H-cPJ&e1e!YtiOhDZ_Xe`-yZy3zr*oOTt~bsZmk<=&mZ{4ZX#mV(~k9Ku@j^ViS=$_ThF%@ z>&;<{e=F+U#`doGZ*s=m>L0upd%A=8R-I42b?t2)?XfpGcM&mr(>9;G(ie}t`kf_+ zy?!nBwSX<|++PZ85nJ4SIFtWlmJnz1`*0@T$1)1%Y=K;2O%(IH!hm`Y($%}a&Vw=bBG3I%MEgti%Vfz-#dBo(EcjT`Av6WTiKRohu AkpKVy literal 2436 zcmZvc*-lhJ5QY!n0IsNjyEuS5iURJq0m_Jipy;(h7-W)hhBycH(hDEPD<8slGA@aU z-*@J;w!}^GDM* zb|r0DpfO#<6wq6c*GrX}8#|EQ;9`3+Ti+@PnQgEq$rqdg5piCDy{+t3R^02%cwSXs zl&bZYOVyd$+xqfSTB+A&?h#Xfe;;~bqp>zsuQk%8TH3(38*$gW%1XM14w&`V%9U4Z zsaP}LUK-_eWU5}RzsX{oxL*i9x*4}$@Uei~^8v8+<>vRC$F9^?%J0#Iq$9bCUW9*s zBVFG}CpT7C%a+M{a?iD1d0(#5yx(*k-+qYy6D-dpI6R~O<8jXw^Ee}TjQ@w{5jZ?! z|KoAb74yvD!(;p(o)V|#8E;39ASGtt%$?#VuYDv zoEOmgSJ3T_h($;xhj*+E}?mp99!&{E6H@N}t{#>-S-MXY}Q{hIVFR_Mz|n z5es$4bKm%z*v%fB`FHX?xvevS4s|B6_05|?%PD3ZeeY3RXByx0k;gj~c)UaU^30;m z5tB#X`xEob<9h~SE{oW{opVgf^Y(s;DFetA-jVs{xa{FOi2r(Pc$fTU&t2a;a6b2M z;mf%b@&3#cW!$bD6L+;Bw_%pYy$RUm*^7wTpIn}2HzIC~=j?ySyW#nVn4>xVnHcYC zA7Y;PCwRn;A>!Yt+mCkrWKX<^i20q`p`Sr)`*ALz)^Tj{(9cP1`|*B-m{Zu|p`X*( z=86BHMyRF!%7pCi3}S!I+4v%2uR~~;y&7{C5wlnAUrbY5Ec88$y}9oTVB(=~|EHVh zI07dAkuIG5C}N&?;2y)4J3gaJ_~IY(yvx|;ihIu953w+x8`xrU`i5>H_Tt+z#=Cwy zvyEv_d{=i7-=gPkzPxuc{g?MXe#~3KmvJw#sfa5+me!NqVrhd;nQ9-qc97eGRNpKVO9q-@GxT?&83P1bCbS|~NN8n> zdiriV$>q07m9$Vwr*~exO3JxsJC)Zng|t98?4i;;DNT0MopLf?S}(386?cL zb(}T`8P^`HS~Xkzjd5+`Vlw|A(*3gUBhbcu9m1C8>gOXa^+U*y+z0jc23@?--&xm> z(6tLa3p;P5ZXZUMdg;-P%)-XhX$`&4_plR3(1yuT_QJ8g4?Xs?<|xdG=VSaBmUyFm z9Nm2s&k1A}mW*rn!>+%dulo^wC#iBj^ks<+AiXF0j-h$CoG%vVMbefAsQ0YQv;LG$ zNZ)ZP?4>`8l(hS>2a)y_lX1_l3D$4ivoY>W<7be@^=qF+x?c0U$vRinGvPc^-JAb*iA7R zlf?Lw>S5$KS%b(C*nZls@e*w9b86j(%dk1p7ku8A9IW5_^n>gxNa;5{j9rEGIZHkE zx`u8q@x)%E==!~9zsQeu%J1xw^RC0*QE{7ZPv_o1O3pRsCVUHauDboq(boU1j{i1# zBmO(sl6{Qbh4opd9`WBp{~!MtKK&7YtW!q(_tC{K2J`JH{&A$_TyrMi2e5P1#cz(b zerqO?Qrzn)^hwwp^@w#EJz|aP&g0V`u}-2}r;J!<(8cOJ^X>V88|uGi7B=obz<1w> zPn`BJ?;-4e#5Gtm2{)dFXA*Pg(EVq5Ue?)Xig~`FN3d_hxOv`D-_$&8Y_V?p-_$q7 z`TExUclw6(TjN{nfc0zp)*i#Yt7U51kp5TA(f^XEgUBbae&2*N!T$TU^#9=&-+})E Dg8-j{ literal 2356 zcmZ9MX>U_U6o!Y`PFc!U_T3?+3rk8{pil~A0g|+a1`!#1!g-pSSGU;UW6(d}r&- z_34kc^m4H8{uQ-s2?K68LGgXDz@KR$X_V@JJ4MR$=ZoL zOa;%P3XTx-F;d&Ju*Pnr_2h3Bw&y43o}OV9xZFc~UuNa``_YZHrhX+y!TN0~#vjEp zCi+k44(plU-Yz6DBc&))yL_HCl|?En*Gcn>}S-W~79E#mFt0FeKS81Lhug7c2NrN$AY>wn_) z9R_mtp&n}=L$|hfDb_xYE+1>3M3?h^{YQSRqx_ey-TxGDA7?b)J?!HQ(q$jU_+P97 z`%v$n*V@MGGbZ*pf<8F^SvdK>i}^><<>LJ3&|U7U?^7UWZS`3DGxWjvKZlc#^M8RZ z7w3<4lyUwq(cPyCjCT*`zkqbvhcV~DC14-waen`+&TqUvV`7hE=!5fr1t%YSyo@dv z=l=%X<-Yp926EO`kF~!=ADsURoP0dntLSoZ{#ZvD=f8&TKK5_a`ye*@k5jn`*P^!ZNp`;6&7E6+?j-W{cP**9(q_!wSfQt diff --git a/tests/graphics/shaders/bin/spirv/geometry.spv b/tests/graphics/shaders/bin/spirv/geometry.spv index 0c6aa7a3eb41c74cd00f302146f49d60f04ffc8f..60153d5eab8e00b298ab00053b28491ef487034c 100644 GIT binary patch literal 1724 zcmZ9M*-leY6oxmg6`Y{RB#KbPnObK=5!#B17?W1L@wS&-FoeNtd<=aHpTPIf=g_E$ ziQjiTD>-pDfA{*=xYu60Etlr{Q|e184W^fTyM|MVkD7AEwGO3$j45ySHnueAqsI|Y z%b;p&P$L-3Rio7So#StZbA7g}a*iIL8|Jz1#Tj-4&Bl9SG4LCc`DIWu_;Lg-L3_gLZzwu|-Yrv&lJ_+=n zg8N=Px4Ihq9J{gVNCQv`etU)I3ML{WM{A4d^7Cw$X7%5j?`cI29CbvD^$aQR~i;s8M z0P4f%CbDs!BYbWls}G;s$dNmI?x0iOeXHM_j7J+u(=MQ>%$gbV>8?OBkP;Xvk>n!EmJ?cD0wvIl_ zUop6i{DzUEOjhqkX& oJ|y1xcvtr3e?swYTkvoAsdFaYi+jX5OKV14%-&i3A#M@;1zgNsjQ{`u literal 2456 zcmZ{l*KSim5QaA-cIX{K$D!BIdkGLAlu$#xLI?~pGBJvcgt&sofVbcYka!Gu4+Ka^ zeBYik!HQs`(aii)cV~{%J7Z&iN#nwcJ^;w(xt_)B0_EGdnSjgJkrJ5PrW9@?wN z{M0MUwgtqg^+7KmHzvdnL&u>T&_b-*mS?#y%ZNEPY-_u0tB_|wz5Ln37aFJ#)tz5` zF1FUQXYG2Yo$UkYPg>2^WLy8v?yDer*4$Z|Cugg=vRSD)E|>vr`c{=a^-{jVQw|L&(R&x$&Econ*GZmrjy5uXz=T>|snJaY;*h1rXk zJp78?De47gZT+0%D4m#3KkaeX?%Z+D?%Z)dG4n<2^xWY$N;U7Y4)QFaqBRGJHb!|l zQWai<2Jq)&$hx*==riFp$g{K5i~US#4f&?5LMG2}_$)>jE8?oT<`Q)C8L!e3c?5m(K%)?hQQ@%s7R{ub1rp3M95?Cee4-olPL zrEf)co=chNwi0)4`yumq=L2xxKx`e7`xoz`O>%yR;O5ePqSXCf#f)>erpKB8D7dzG z(__fi7B`Q&zlm|Llcj7f>kh+1-S>}HAp{abUMrW zRq`y)pu2Z9$UB_L{BPc~=)Q&i=inod?=EgmXLBABkDM2fBWKjT2qu1m2xCSeG0D>d zy{Cq@OOST+dY>!st5D>0KX2h%g^xk{d+c97v532d9C3b=5qBNgIO`gxpIE%-P2{+@ zJANB-$He1K<0Wpq--P;CGCE&p?TqA+^A55zdPnc>**!?i@5LP2#Jcy#S$`{Yy0_+( dN6!1m_8B=JAd5v#ZDQsegd6YP{wC*9=npYguR;I- diff --git a/tests/graphics/shaders/bin/spirv/geometry_vert.spv b/tests/graphics/shaders/bin/spirv/geometry_vert.spv index 443bffbf1223429a38b47406044929641be52d1f..5c7edbe9c6fbe52c60d9024a3eb6b56cd01e691e 100644 GIT binary patch literal 680 zcmY+B%T5A85Jk(GLB$6T5%7UJhMlrDBt!@+HZFAM)};&m2EWWN(Eo8`;yKc7Vw0lk z-oEwfDU0z|#70E4qUPVzjUqASFZQ+_$T-F?PtUK$1*W3p*T6qQG@|;aS%KB-O=N5>PsW?XpC5PgA-7JU#+nn9;%&?vbvdU=OwN1O?4*17%sGQt%Xxdm z5pRn=UG|A;A*Tkn@a`|~EN#5Atmm(yL+ozyJtpkpFJTVw#`Z9`hp8KZ5Ap6GXODiu z^5Q|lYGz<(aCher=bqM^@B-!yG2g_U-SLLkvA;PU=lP<_5#Ad1JjU#C3wFj6%sz7_ z_0F10>Nw9SCZ|Tdc_U2z0gdl*mN?uWcb+)sxF^eZy1>+W=Qs5I?dd+=eKYkG`vLoX B7(M_1 literal 1220 zcmYk5-Afc<6vkh7n^m(kGqn%1G3`@Zx~K>uLkhNFFBGBMkQ`)S8^xUXeH?Z4So4*$R3}J%eye0v;1b1{e%**_+7!oJ+Tf`p>K5b{m zAG6~!`$h^{UtpdlzWWLfr_u7 zvBr3TsDn?jMfARax!gSY1U|()>rFmMZ2c1XMZ7g)DY?DO#nt<*%a|wT)5O1j^*1-T zyV@B{jd;{tAx3i&HM0#b9@A+hr7ff{CFdO zpU7U$7Ws$7@Tc;Rh~&M?3wG-pdS{RLACLrZZ{NxP8GCKQ8oRsKaL%`kIolQ$&XrS$C3BF foWdv~gfFpwh{jC@ diff --git a/tests/graphics/shaders/bin/spirv/mesh.spv b/tests/graphics/shaders/bin/spirv/mesh.spv index 311c2b399fe6af1b1f8c32016bf33a20e2948af6..0d24f9e40c8eca736d8f970c3c81d1fed2d98e45 100644 GIT binary patch literal 1324 zcmZvaT}xC^6o$7m&Wu{=m|uOE9h)q_8m%CLAc=@>0>vV_8wL{W!URpP{Sne1=m#kN z0e_X?P2lsKa~2HZhIRIO&-<=-?X%CSR$7fz>q{vOr`J4Pqp6bqji)q}>gnso_s*vu z-#R;6``exU?e5R5J(Sg4XVpj=NEc|$ce=lROH>FI{X`QFxlzJBqKU%%jM^qj^9Mvx zQ{caFg;zDz;En+`{Pf;E_|rb@?zKOze_7uI*Gi8#!)LIyw+NS5Z}BO@bb-_H4?wJGZFkn5rMa%$vwm|RbN ztX1zhN7ysMJJUGq6rOsZ_C$wBu{{5ky0IR!6JIQ|ZE4enmgyX)NjYc+a!9{-Os;tKqb+;8y?r`gpMXQ=1+5!f1a{>!NIzxV1MgVm{# zo5n9=_rLhhGw>|CH5noQB;Sh~`4(8-_ha1JQ}$Wj%(0uRdB(0rU-9!2d-iu=dpK`u z0-FbJkvk*eH+-$WeT2(CmsHQQpNv=YbNf9X(Ajr^(A!ygkAv753x1JY-uaLhJ4eAU zk;^+1@?vKv_+@f==RjWUyafM(+;c~Nu`?2UyX2$4*f|M)rR1Z(*jWjFwdA9}IQ+fm amxOm0{l(6Q_42O>`RFfpF8*`FZ;2~GC^dfo literal 1772 zcmZXT?M@Rx6o#jiwpbL3eEEU6h#x4mA_8JeBm_-0sY#O(;=iV$8`xyqnrne)EqoOx&FY<6t5;Bpx^=_cGWHykr=%zd46uITcv zQ9o+FdUx3D_|a)II&HQ6zGCw(qtI%tQL99Qc4cdOgUl(HjSIj{tKM(b7}vVf3c3&_ z*&P|dCDnkNkr8iJ5(<7z#%%r<)f$WaY>fYqpVbfSmy*X-uUh+0s>_KWr$8k2%rs^9&`td;FC|Bap(|t5C-pG2GO9^ zJ@!W&w*vPe3`ZO~xDVmzKtyotN63gZb5Cany|CAh@k*G8OuphL#C!znQ z+aBdrbswA!Ew7cunlU+?Mi}P+W41VQz|d+KYcTGws(&;s%NY2)Bm8&01^#a0U)4M- z71UgbUumdmUNL!Lo{X`c_yw)m!~6-Y$z4$H16D`D)JKR@(G@e8s4 zd9N%LXk3(0gFIs4(RM{MI*75o`8LpEx!1KOFP&?#H-vMS7R&n)$6mIN#d^Zn%VJlw zCN3Sz{jCZ^kKNyGt;qxD{_yFQbgjGcITL%@zP8U=3Omm|IF~~Wdf}mFdWk*IRM8AZ z?{IIAG{b?T37>uiBF(^2mWR+`b3uVLSRJ zc?a+<%*W#jv##=i9M?tDk|A-#sZPzD&iVlhiv6GKl}3>ZCOF*mg)hF-83 zFnYmaZfQ-7C$ktZdSG7)(Q{A6yBd$ryBdE#;n9Lt{IwLnp77{^$LD=5znt)%W_Wz7 e&pT|%He|Lx{-%t4_@^>>+aI5|`KzyGSN0EV9Cug% diff --git a/tests/graphics/shaders/bin/spirv/miss.spv b/tests/graphics/shaders/bin/spirv/miss.spv deleted file mode 100644 index 85c5e50973740ef1960984620e76bf55c4626ccb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 540 zcmY*W%}T>y5S%1UQmwYu-zJ1tUl+;w^+kB+xb`>7^&1&YRDmui-^- zCdnag*z7mEv%B*pmN{@?8|a{oZB*8WiT6IR4hNIR=kR_s4)bUgF7qf(=WpaXFi7=- zNiZyy$?){-M4eq&0E_1`Uc(NV={h{*y1cd2=88={;hz`O0(A{ zPyLH%HO->rHk)QSA$c}+0uO0Xj9=p{Pe5jsQ$4PU;%WD+!Sks@z0xvj^bCk)JFKX7 zR4T4``#d|$dGrG+bQy(pbC0;q_{DoGe_3PcR_?Igr<%AO#&71OL0n;JRBn%WlV^`^ z(2r}}Nd2MFm6<+R|c*R2wJ=9xx3_TB0H8q^Sekh=Uhi z@jJZoH|UjK@C%&rXE+{a9DSZI-`3cjd1tNn-D|DAzJ17GW@0Gh2EvZ8E!+;hF%mN2 z%aIVahkRHreNeu*aJk&6+%0!Im1?84Mr=L|5L#SZUYy$K)~1dfKWgUAFqjl@ZWq}< zjD?WJzg=mxoEQdAfW6=}sDVL#8SEpHveYdumd{_m^1tOmj+y>C^2f+oZ``Rju{rXr zz1A!*RyJGJTNmc3p`N9W5H=e3>KOP?vi`qu%S}d$67(@>p+_OmoMRlkL^nLyq+ez_AZLgjF-P0N;jH z6V7kPI`55g-tQRz>ZeogcdJEi|MIF)?_2T?1$^6Xsv5zTu z?7=zX+^3^SoZp-cui;zA-s1c*eD~&;u}pXiYuqWUL+(Dvy(^BGcLx9Olv{5aw0A!^ z75kfohj4G+Gd_n`0IuV_d=5Cq*rj=_>z>EjpM85iD_Co1!G6xJf?WXz@NZ(}=2fwt zxtjgTy^Ctjf1dg)*c05{4Az>CLGU|D4r{LW&HoVlh}{2*$URHneLp|c$33gbE!?*s zfVOX-_`6W=^_dl^pkllbnrXKai;c=qbn@;$u`d`oiQ^I2e@k)F1AIli|UFbh0W`*+=Ufae*%(YI7g^%%1N_pJJ3F2L2lqs~0`U0|O2xAdxZ z5vc#hcfE&o{K=g9B2e=!>BqI+$G4xjpZ2o^)MHEu-+uaIF2U7fKbP^%Q~!fC;#%5Y zxykmo4D2rljJFSay^3|%t1(xAn!W1(#i{A5#h$L?Z|(a-H1!zs5&qVF{1{FBYr61T zKLO^c$GjW(*6!c`PvPqK)4Vdix$52{|1;FQC)TY4wRmq<@x2F^$REY70X0X|ZsDtW qN2AtAHUAS!?BfddGhn{)&L0M|tm^-06V$*Qum^inGsk^A3H||vpuPYA diff --git a/tests/graphics/shaders/bin/spirv/texture_frag.spv b/tests/graphics/shaders/bin/spirv/texture_frag.spv index 86381da9219568f6bbc1d046a4c5da0ca06054f1..05fc4aa922683e2338f735db8940564cd02650e3 100644 GIT binary patch literal 748 zcmYk2OH0F05QWF4O?>uYwe?n#bxjN=+VrIgKyQY2KrB`5I?};_J>2s=&URmn_21C<`Zdvzzhw;a0jp zZf0*ExobR5pC?f^kMq)_`d+l_;w!WMA9b&J>~o?d!1z`%dyQx+=!1t26`1|2eK39A z(39JS>Ogs@6aNxSkGZP=69XwWi=)#XNyUGH-zs@Rr_7v*W&!c~h~xtEWT*|0D%_^p)^<5!c#*`S8D*exdvW|FNT0%*?Vz|5YH{nMYt~BCf^;!?$za6Ci+V9 zcWdm9aviqaC91c7-Zt18mGy;MYlz)TJ7J0{QC%%E{+E?b>^|Bl9S?}saLz-beci|0 zBceU!?ICt|xf|YEojYmH{sWT|?_sUEk2{mt{tevTFR1L>#MQ{Fu}>Sf$157&=NMNf O|3DYtN$!^^Zt*`FnjOdh diff --git a/tests/graphics/shaders/bin/spirv/texture_vert.spv b/tests/graphics/shaders/bin/spirv/texture_vert.spv index e7d4e13b49a853e608276a90f5cd86367aae3873..d4c5400af52ad4542541589592d279cb43640812 100644 GIT binary patch literal 612 zcmX|-J!?W?429Es{b;S#cQjBtD}PoqR#&8E`^>a-q%2Ga&nTB z+&7N8d9w#ID_cuntY%SKi5=m=lpixzif{EMY5c& zX35;^%%t_zbUjXzpNZ;upFNyUK5!>oJLC6+yFMS}!lD{U09+{ z4#XCcdS)klIEZh;kAOOtW0rEAD15mL$8mq~5KM9?C-)jflbk1gXl8kO(B7X+OgUfN z+imdP84gE}wvMy)r?{^Aa2DoYsSh#BdB>q04(~Yjz@g7^#BkhKS8sG}%UEDvej1|( zOy7!B(6gzI^dYV(%FFw*y7ueCCz$?K;aPcK#@e%(uS>s%@Vq?x;kFf_&GjIM`Knux zciK-Z=6>Orvy{}OeVGF;$yn%GmS+x{=~tFV13dk}+y$J|Sy9ZQepQ|vJ;>uXWGsg_ z6ZCaX{gz_1aTf57#cm$hx15{b6lTVezB4+xLl%90#CY--dZVQ(LoXUnt)80YT}|EA zaJQ~zO)>nZ-LtM3?pjLG+K|x)p7U`g`f(oq1MZxAJ(DUh_4MXkyE4u|&bRniCpwn> E0mv9ZmjD0& diff --git a/tests/graphics/shaders/bin/spirv/triangle_frag.spv b/tests/graphics/shaders/bin/spirv/triangle_frag.spv index 4900c89b5811ef41686d1e343b2e1df161f79889..4f44a9d72b3c3e470d77af391afb396d48410601 100644 GIT binary patch literal 368 zcmY+9y9>f#48&s}))zhybQ8tBqX?plgNsm55jW`|;-G?5|8^I_-+i@%AEe3Ua=Fy^ z#*tac%$nBVtJg8_*YO<|+p@?4vg&Jkxry)yO||I(WjEPaNY~JAir7tA>I5& z-C)*bbA>!&N0qF4#*8%b)ISLq8u?C8YEGPF$Rv0@-UH-On2>l-Tb u7x1eBa|0ZDU0J98bTB*N7P^pq%;M4W5>ruLi)Cg*fqx^Fx!||Dmx>R=-4f;i diff --git a/tests/graphics/shaders/bin/spirv/triangle_vert.spv b/tests/graphics/shaders/bin/spirv/triangle_vert.spv index 15b7f9086461b6f401fe12f2e70c4619db37209b..9c114ffc5a0973fc63d4b7734efe4b5cd01049e2 100644 GIT binary patch literal 712 zcmX|;J4-`B5QWEkO?)TDXyOATl2S-1f~bXs1jHL3g>A|dMi903XWIyV-{!6hlbLhQ z?3uZnvKX#JEJZ{sj`;O-qNtfNVbyl5{nxM4*<4T%b}SQ(RF^5gAT*+x^x1s$HGLmV zs;BYuxVlfgcWVBox~m?6iPz)p^CMlzLIZc_=b5))=WP%kv3ndRw7~j{y{E2k)_ZK+ z1P_Q)G;1Cpos3r#`o8X?`_=Y1V*p+!>npGB9_r3i-z2Nct8bCj-C4awwpYH3Ynyxm zvrV?XpvM``(?_hQcQV#PKRI>r;{7AesPwVdqwf!H9r7i;?!80kFLuu^q1QwD7b144 z?eS!8k6KRO2`}dUJ;Gi!-_Uo<{e5bEJ(=65meV712Q}wD+4qpz`}V8rd&P!+voo#z LUi*G=J171C5U(1*c z?TRR8E=*PN81L(D-ZOcGEn?5G9jwjM!vA4I62^G$xd~@XlV25I&$7WqHYl^7q@Xo! zY^^`c%e>zMov8SpUEz7JJkNh+@?y=is2vyi%}G8iyS;DOsHSpj--}{YOVFogSHh$A z?&!o?vv>J%+%NirI`>}PChxG{J9zGA_8YsRk61lZr+v?Jk34lnp0Sv7>hM<27UnWn z%m2Ar%R`&I3?LH-c$ez7egwZ$IR zv=rV9K5GBa=P;ML=JB4RX8SGR)gW#^b7vtIbuJORtnD>mly$18nQO8SS_sh4g4$pL^*8VZ6_t+iDB0|0Z diff --git a/tests/graphics/shaders/src/hlsl/compute.hlsl b/tests/graphics/shaders/src/compute.hlsl similarity index 50% rename from tests/graphics/shaders/src/hlsl/compute.hlsl rename to tests/graphics/shaders/src/compute.hlsl index 6e659772..cebd6389 100644 --- a/tests/graphics/shaders/src/hlsl/compute.hlsl +++ b/tests/graphics/shaders/src/compute.hlsl @@ -1,23 +1,30 @@ -cbuffer PushConstants : register(b0) + +struct PushData { uint width; uint height; float4 color; }; +[[vk::push_constant]] +ConstantBuffer pc : register(b0); + // We used raw Buffer but structured buffer can be used as well. // PalDescriptorBufferInfo::stride must be set to 16 -RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 + +// binding 0 set 0 +[[vk::binding(0, 0)]] +RWByteAddressBuffer outBuffer : register(u0, space0); [numthreads(16, 16, 1)] void main(uint3 id : SV_DispatchThreadID) { - if (id.x >= width || id.y >= height) { + if (id.x >= pc.width || id.y >= pc.height) { return; } - uint index = id.y * width + id.x; + uint index = id.y * pc.width + id.x; uint offset = index * 16; // sizeof(float4) - outBuffer.Store4(offset, asuint(color)); + outBuffer.Store4(offset, asuint(pc.color)); } diff --git a/tests/graphics/shaders/src/hlsl/compute_multi.hlsl b/tests/graphics/shaders/src/compute_multi.hlsl similarity index 51% rename from tests/graphics/shaders/src/hlsl/compute_multi.hlsl rename to tests/graphics/shaders/src/compute_multi.hlsl index 30312f51..ad50b3eb 100644 --- a/tests/graphics/shaders/src/hlsl/compute_multi.hlsl +++ b/tests/graphics/shaders/src/compute_multi.hlsl @@ -1,5 +1,6 @@ -cbuffer PushConstants : register(b0) + +struct PushData { uint width; uint height; @@ -8,20 +9,32 @@ cbuffer PushConstants : register(b0) float4 set3Color; }; +[[vk::push_constant]] +ConstantBuffer pc : register(b0); + // we use structured buffer for this example. + +// binding 0 set 0 +[[vk::binding(0, 0)]] RWStructuredBuffer set1OutBuffer : register(u0, space0); + +// binding 0 set 1 +[[vk::binding(0, 1)]] RWStructuredBuffer set2OutBuffer : register(u0, space1); + +// binding 0 set 2 +[[vk::binding(0, 2)]] RWStructuredBuffer set3OutBuffer : register(u0, space2); [numthreads(16, 16, 1)] void main(uint3 id : SV_DispatchThreadID) { - if (id.x >= width || id.y >= height) { + if (id.x >= pc.width || id.y >= pc.height) { return; } - uint index = id.y * width + id.x; - set1OutBuffer[index] = set1Color; - set2OutBuffer[index] = set2Color; - set3OutBuffer[index] = set3Color; + uint index = id.y * pc.width + id.x; + set1OutBuffer[index] = pc.set1Color; + set2OutBuffer[index] = pc.set2Color; + set3OutBuffer[index] = pc.set3Color; } diff --git a/tests/graphics/shaders/src/hlsl/descriptor_indexing.hlsl b/tests/graphics/shaders/src/descriptor_indexing.hlsl similarity index 68% rename from tests/graphics/shaders/src/hlsl/descriptor_indexing.hlsl rename to tests/graphics/shaders/src/descriptor_indexing.hlsl index c49fe33f..bfbe2526 100644 --- a/tests/graphics/shaders/src/hlsl/descriptor_indexing.hlsl +++ b/tests/graphics/shaders/src/descriptor_indexing.hlsl @@ -1,12 +1,21 @@ -Texture2D texs[] : register(t0, space0); // set 0 -SamplerState samp : register(s0, space0); // set 0 -cbuffer PushConstants : register(b0) +struct PushData { uint textureIndices[4]; }; +[[vk::push_constant]] +ConstantBuffer pc : register(b0); + +// binding 0 set 0 +[[vk::binding(0, 0)]] +Texture2D texs[] : register(t0, space0); + +// binding 1 set 0 +[[vk::binding(1, 0)]] +SamplerState samp : register(s0, space0); + struct PSInput { float4 pos : SV_POSITION; @@ -33,6 +42,6 @@ float4 main(PSInput input) : SV_Target quadrant = 3; } - uint index = textureIndices[quadrant]; + uint index = pc.textureIndices[quadrant]; return texs[NonUniformResourceIndex(index)].Sample(samp, input.uv); } \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/geometry.hlsl b/tests/graphics/shaders/src/geometry.hlsl similarity index 100% rename from tests/graphics/shaders/src/hlsl/geometry.hlsl rename to tests/graphics/shaders/src/geometry.hlsl diff --git a/tests/graphics/shaders/src/hlsl/geometry_vert.hlsl b/tests/graphics/shaders/src/geometry_vert.hlsl similarity index 100% rename from tests/graphics/shaders/src/hlsl/geometry_vert.hlsl rename to tests/graphics/shaders/src/geometry_vert.hlsl diff --git a/tests/graphics/shaders/src/glsl/closest_hit.glsl b/tests/graphics/shaders/src/glsl/closest_hit.glsl deleted file mode 100644 index c91f3f70..00000000 --- a/tests/graphics/shaders/src/glsl/closest_hit.glsl +++ /dev/null @@ -1,15 +0,0 @@ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 0) rayPayloadInEXT vec3 payloadColor; - -layout(shaderRecordEXT) buffer HitRecord -{ - vec3 color; -} hitRecord; - -void main() -{ - payloadColor = hitRecord.color; -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/compute.glsl b/tests/graphics/shaders/src/glsl/compute.glsl deleted file mode 100644 index 2b633bcb..00000000 --- a/tests/graphics/shaders/src/glsl/compute.glsl +++ /dev/null @@ -1,27 +0,0 @@ - -#version 450 - -layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout(set = 0, binding = 0) buffer OutputBuffer -{ - vec4 pixels[]; -} outBuffer; - -layout(push_constant) uniform PushConstants -{ - uint width; - uint height; - vec4 color; -} pc; - -void main() -{ - uvec2 id = gl_GlobalInvocationID.xy; - if (id.x >= pc.width || id.y >= pc.height) { - return; - } - - uint index = id.y * pc.width + id.x; - outBuffer.pixels[index] = pc.color; -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/compute_multi.glsl b/tests/graphics/shaders/src/glsl/compute_multi.glsl deleted file mode 100644 index d8780b07..00000000 --- a/tests/graphics/shaders/src/glsl/compute_multi.glsl +++ /dev/null @@ -1,41 +0,0 @@ - -#version 450 - -layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; - -layout(set = 0, binding = 0) buffer Set1OutputBuffer -{ - vec4 pixels[]; -} set1OutBuffer; - -layout(set = 1, binding = 0) buffer Set2OutputBuffer -{ - vec4 pixels[]; -} set2OutBuffer; - -layout(set = 2, binding = 0) buffer Set3OutputBuffer -{ - vec4 pixels[]; -} set3OutBuffer; - -layout(push_constant) uniform PushConstants -{ - uint width; - uint height; - vec4 set1Color; - vec4 set2Color; - vec4 set3Color; -} pc; - -void main() -{ - uvec2 id = gl_GlobalInvocationID.xy; - if (id.x >= pc.width || id.y >= pc.height) { - return; - } - - uint index = id.y * pc.width + id.x; - set1OutBuffer.pixels[index] = pc.set1Color; - set2OutBuffer.pixels[index] = pc.set2Color; - set3OutBuffer.pixels[index] = pc.set3Color; -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl b/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl deleted file mode 100644 index dc01d3b1..00000000 --- a/tests/graphics/shaders/src/glsl/descriptor_indexing.glsl +++ /dev/null @@ -1,39 +0,0 @@ - -#version 450 -#extension GL_EXT_nonuniform_qualifier : require - -layout(set = 0, binding = 0) uniform texture2D texs[]; -layout(set = 0, binding = 1) uniform sampler samp; - -layout(push_constant) uniform PushConstants -{ - uint textureIndices[4]; -} pc; - -layout(location = 0) in vec2 aTexCoord; - -layout(location = 0) out vec4 color; - -void main() -{ - int quadrant = 0; // quad is centered - if (gl_FragCoord.x < 320.0 && gl_FragCoord.y < 240.0) { - // red texture - quadrant = 0; - - } else if (gl_FragCoord.x >= 320.0 && gl_FragCoord.y < 240.0) { - // green texture - quadrant = 1; - - } else if (gl_FragCoord.x < 320.0 && gl_FragCoord.y >= 240.0) { - // blue texture - quadrant = 2; - - } else { - // yellow texture - quadrant = 3; - } - - uint index = pc.textureIndices[quadrant]; - color = texture(sampler2D(texs[nonuniformEXT(index)], samp), aTexCoord); -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/geometry.glsl b/tests/graphics/shaders/src/glsl/geometry.glsl deleted file mode 100644 index 9c116eb0..00000000 --- a/tests/graphics/shaders/src/glsl/geometry.glsl +++ /dev/null @@ -1,33 +0,0 @@ - -#version 450 - -layout(triangles) in; -layout(triangle_strip, max_vertices = 9) out; - -layout(location = 0) out vec4 outColor; - -void main() -{ - vec2 offsets[3] = { - vec2(-0.6, 0.0 ), - vec2( 0.0, 0.0 ), - vec2( 0.6, 0.0 ) - }; - - vec4 colors[3] = { - vec4( 1.0, 0.0, 0.0, 1.0 ), - vec4( 0.0, 1.0, 0.0, 1.0 ), - vec4( 0.0, 0.0, 1.0, 1.0 ) - }; - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - gl_Position = gl_in[j].gl_Position; - gl_Position.xy += offsets[i]; - outColor = colors[i]; - - EmitVertex(); - } - EndPrimitive(); - } -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/geometry_vert.glsl b/tests/graphics/shaders/src/glsl/geometry_vert.glsl deleted file mode 100644 index b2764cbf..00000000 --- a/tests/graphics/shaders/src/glsl/geometry_vert.glsl +++ /dev/null @@ -1,14 +0,0 @@ - -#version 450 - -void main() -{ - vec2 positions[3] = { - vec2( 0.0, 0.2), - vec2( 0.2, -0.2 ), - vec2(-0.2, -0.2 ) - }; - - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); - gl_Position.y *= -1.0; -} diff --git a/tests/graphics/shaders/src/glsl/mesh.glsl b/tests/graphics/shaders/src/glsl/mesh.glsl deleted file mode 100644 index a0fbe477..00000000 --- a/tests/graphics/shaders/src/glsl/mesh.glsl +++ /dev/null @@ -1,27 +0,0 @@ - -#version 460 -#extension GL_EXT_mesh_shader : require - -layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; -layout(max_vertices = 4, max_primitives = 2) out; -layout(triangles) out; - -layout(location = 0) out vec4 vColors[]; - -void main() -{ - SetMeshOutputsEXT(4, 2); - gl_MeshVerticesEXT[0].gl_Position = vec4(-0.5, 0.5, 0.0, 1.0); - gl_MeshVerticesEXT[1].gl_Position = vec4( 0.5, 0.5, 0.0, 1.0); - gl_MeshVerticesEXT[2].gl_Position = vec4( 0.5,-0.5, 0.0, 1.0); - gl_MeshVerticesEXT[3].gl_Position = vec4(-0.5,-0.5, 0.0, 1.0); - - // colors - vColors[0] = vec4(1.0, 0.0, 0.0, 1.0); - vColors[1] = vec4(0.0, 1.0, 0.0, 1.0); - vColors[2] = vec4(0.0, 0.0, 1.0, 1.0); - vColors[3] = vec4(1.0, 0.0, 0.0, 1.0); - - gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2); - gl_PrimitiveTriangleIndicesEXT[1] = uvec3(0, 2, 3); -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/miss.glsl b/tests/graphics/shaders/src/glsl/miss.glsl deleted file mode 100644 index e808a762..00000000 --- a/tests/graphics/shaders/src/glsl/miss.glsl +++ /dev/null @@ -1,15 +0,0 @@ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(location = 0) rayPayloadInEXT vec3 payloadColor; - -layout(shaderRecordEXT) buffer MissRecord -{ - vec3 color; -} missRecord; - -void main() -{ - payloadColor = missRecord.color; -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/raygen.glsl b/tests/graphics/shaders/src/glsl/raygen.glsl deleted file mode 100644 index 78f43b3d..00000000 --- a/tests/graphics/shaders/src/glsl/raygen.glsl +++ /dev/null @@ -1,44 +0,0 @@ - -#version 460 -#extension GL_EXT_ray_tracing : require - -layout(set = 0, binding = 0) buffer OutputBuffer -{ - vec4 pixels[]; -} outBuffer; - -layout(set = 0, binding = 1) uniform accelerationStructureEXT tlas; -layout(location = 0) rayPayloadEXT vec3 payloadColor; - -void main() -{ - uvec2 pixel = gl_LaunchIDEXT.xy; - uvec2 size = gl_LaunchSizeEXT.xy; - payloadColor = vec3(0.0); - - vec2 uv = (vec2(pixel) + 0.5) / vec2(size); - vec2 ndcUv = uv * 2.0 - 1.0; - vec3 origin = vec3(0.0, 0.0, -3.0); - vec3 direction = normalize(vec3(ndcUv.x, ndcUv.y, 1.0)); - - traceRayEXT( - tlas, - gl_RayFlagsOpaqueEXT, - 0xFF, - 0, - 0, - 0, - origin, - 0.001, - direction, - 1000.0, - 0 - ); - - if (pixel.x >= size.x || pixel.y >= size.y) { - return; - } - - uint index = pixel.y * size.x + pixel.x; - outBuffer.pixels[index] = vec4(payloadColor, 1.0); -} diff --git a/tests/graphics/shaders/src/glsl/texture_frag.glsl b/tests/graphics/shaders/src/glsl/texture_frag.glsl deleted file mode 100644 index fd330edc..00000000 --- a/tests/graphics/shaders/src/glsl/texture_frag.glsl +++ /dev/null @@ -1,14 +0,0 @@ - -#version 450 - -layout(set = 0, binding = 0) uniform texture2D tex; -layout(set = 0, binding = 1) uniform sampler samp; - -layout(location = 0) in vec2 aTexCoord; - -layout(location = 0) out vec4 color; - -void main() -{ - color = texture(sampler2D(tex, samp), aTexCoord); -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/texture_vert.glsl b/tests/graphics/shaders/src/glsl/texture_vert.glsl deleted file mode 100644 index 96ed6166..00000000 --- a/tests/graphics/shaders/src/glsl/texture_vert.glsl +++ /dev/null @@ -1,14 +0,0 @@ - - -#version 450 - -layout(location = 0) in vec2 aPosition; -layout(location = 1) in vec2 aTexCoord; - -layout(location = 0) out vec2 vTexCoord; - -void main() -{ - gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); - vTexCoord = aTexCoord; -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/triangle_frag.glsl b/tests/graphics/shaders/src/glsl/triangle_frag.glsl deleted file mode 100644 index 384d9720..00000000 --- a/tests/graphics/shaders/src/glsl/triangle_frag.glsl +++ /dev/null @@ -1,11 +0,0 @@ - -#version 450 - -layout(location = 0) in vec4 aColor; - -layout(location = 0) out vec4 color; - -void main() -{ - color = aColor; -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/glsl/triangle_vert.glsl b/tests/graphics/shaders/src/glsl/triangle_vert.glsl deleted file mode 100644 index 55b9831a..00000000 --- a/tests/graphics/shaders/src/glsl/triangle_vert.glsl +++ /dev/null @@ -1,13 +0,0 @@ - -#version 450 - -layout(location = 0) in vec2 aPosition; -layout(location = 1) in vec3 aColor; - -layout(location = 0) out vec4 vColor; - -void main() -{ - gl_Position = vec4(aPosition.x, -aPosition.y, 0.0, 1.0); - vColor = vec4(aColor, 1.0); -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/closest_hit.hlsl b/tests/graphics/shaders/src/hlsl/closest_hit.hlsl deleted file mode 100644 index 3ab56dd9..00000000 --- a/tests/graphics/shaders/src/hlsl/closest_hit.hlsl +++ /dev/null @@ -1,23 +0,0 @@ - -struct RayPayload -{ - float3 color; -}; - -struct HitAttributes -{ - float2 unused; -}; - -cbuffer HitRecord : register(b0) -{ - float3 hitColor; -}; - -[shader("closesthit")] -void main( - inout RayPayload payload, - in HitAttributes attr) -{ - payload.color = hitColor; -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/miss.hlsl b/tests/graphics/shaders/src/hlsl/miss.hlsl deleted file mode 100644 index 8f4bdbda..00000000 --- a/tests/graphics/shaders/src/hlsl/miss.hlsl +++ /dev/null @@ -1,16 +0,0 @@ - -struct RayPayload -{ - float3 color; -}; - -cbuffer MissRecord : register(b0) -{ - float3 missColor; -}; - -[shader("miss")] -void main(inout RayPayload payload) -{ - payload.color = missColor; -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/raygen.hlsl b/tests/graphics/shaders/src/hlsl/raygen.hlsl deleted file mode 100644 index d44ee13e..00000000 --- a/tests/graphics/shaders/src/hlsl/raygen.hlsl +++ /dev/null @@ -1,36 +0,0 @@ - -struct RayPayload -{ - float3 color; -}; - -RWByteAddressBuffer outBuffer : register(u0, space0); // set 0 -RaytracingAccelerationStructure tlas : register(t0, space0); // set 0 - -[shader("raygeneration")] -void main() -{ - uint2 pixel = DispatchRaysIndex().xy; - uint2 size = DispatchRaysDimensions().xy; - RayPayload payload; - payload.color = float3(0.0, 0.0, 0.0); - - float2 uv = (float2(pixel) + 0.5) / float2(size); - float2 ndcUv = uv * 2.0 - 1.0; - - RayDesc desc; - desc.Origin = float3(0.0, 0.0, -3.0);; - desc.Direction = normalize(float3(ndcUv.x, ndcUv.y, 1.0));; - desc.TMin = 0.001; - desc.TMax = 1000.0; - TraceRay(tlas, RAY_FLAG_NONE, 0xFF, 0, 0, 0, desc, payload); - - if (pixel.x >= size.x || pixel.y >= size.y) { - return; - } - - uint index = pixel.y * size.x + pixel.x; - uint offset = index * 16; // sizeof(float4) - float4 color = float4(payload.color, 1.0); - outBuffer.Store4(offset, asuint(color)); -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/texture_frag.hlsl b/tests/graphics/shaders/src/hlsl/texture_frag.hlsl deleted file mode 100644 index 5af1fc82..00000000 --- a/tests/graphics/shaders/src/hlsl/texture_frag.hlsl +++ /dev/null @@ -1,14 +0,0 @@ - -Texture2D tex : register(t0, space0); // set 0 -SamplerState samp : register(s0, space0); // set 0 - -struct PSInput -{ - float4 pos : SV_POSITION; - float2 uv : TEXCOORD; -}; - -float4 main(PSInput input) : SV_Target -{ - return tex.Sample(samp, input.uv); -} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/mesh.hlsl b/tests/graphics/shaders/src/mesh.hlsl similarity index 100% rename from tests/graphics/shaders/src/hlsl/mesh.hlsl rename to tests/graphics/shaders/src/mesh.hlsl diff --git a/tests/graphics/shaders/bin/dxil/ray_tracing.hlsl b/tests/graphics/shaders/src/ray_tracing.hlsl similarity index 100% rename from tests/graphics/shaders/bin/dxil/ray_tracing.hlsl rename to tests/graphics/shaders/src/ray_tracing.hlsl diff --git a/tests/graphics/shaders/src/texture_frag.hlsl b/tests/graphics/shaders/src/texture_frag.hlsl new file mode 100644 index 00000000..ad0ef885 --- /dev/null +++ b/tests/graphics/shaders/src/texture_frag.hlsl @@ -0,0 +1,19 @@ + +// binding 0 set 0 +[[vk::binding(0, 0)]] +Texture2D tex : register(t0, space0); + +// binding 1 set 0 +[[vk::binding(1, 0)]] +SamplerState samp : register(s0, space0); + +struct PSInput +{ + float4 pos : SV_POSITION; + float2 uv : TEXCOORD; +}; + +float4 main(PSInput input) : SV_Target +{ + return tex.Sample(samp, input.uv); +} \ No newline at end of file diff --git a/tests/graphics/shaders/src/hlsl/texture_vert.hlsl b/tests/graphics/shaders/src/texture_vert.hlsl similarity index 100% rename from tests/graphics/shaders/src/hlsl/texture_vert.hlsl rename to tests/graphics/shaders/src/texture_vert.hlsl diff --git a/tests/graphics/shaders/src/hlsl/triangle_frag.hlsl b/tests/graphics/shaders/src/triangle_frag.hlsl similarity index 100% rename from tests/graphics/shaders/src/hlsl/triangle_frag.hlsl rename to tests/graphics/shaders/src/triangle_frag.hlsl diff --git a/tests/graphics/shaders/src/hlsl/triangle_vert.hlsl b/tests/graphics/shaders/src/triangle_vert.hlsl similarity index 100% rename from tests/graphics/shaders/src/hlsl/triangle_vert.hlsl rename to tests/graphics/shaders/src/triangle_vert.hlsl diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 5133d17e..5dbbbedb 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -847,14 +847,23 @@ bool textureTest() const char* sources[2]; PalShaderEntryInfo entries[2]; + PalViewport viewport = {0}; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { sources[0] = "graphics/shaders/bin/spirv/texture_vert.spv"; sources[1] = "graphics/shaders/bin/spirv/texture_frag.spv"; + viewport.height = -(float)WINDOW_HEIGHT; + viewport.y = (float)WINDOW_HEIGHT; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { sources[0] = "graphics/shaders/bin/dxbc/texture_vert.dxbc"; sources[1] = "graphics/shaders/bin/dxbc/texture_frag.dxbc"; + + viewport.height = (float)WINDOW_HEIGHT; } entries[0].stage = PAL_SHADER_STAGE_VERTEX; @@ -1079,12 +1088,6 @@ bool textureTest() Uint32 currentFrame = 0; bool running = true; - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; - PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index fe0892a2..3a2b2aef 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -550,14 +550,23 @@ bool triangleTest() const char* sources[2]; PalShaderEntryInfo entries[2]; + PalViewport viewport = {0}; + viewport.width = (float)WINDOW_WIDTH; + viewport.maxDepth = 1.0f; + PalShaderCreateInfo shaderCreateInfo = {0}; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { sources[0] = "graphics/shaders/bin/spirv/triangle_vert.spv"; sources[1] = "graphics/shaders/bin/spirv/triangle_frag.spv"; + viewport.height = -(float)WINDOW_HEIGHT; + viewport.y = (float)WINDOW_HEIGHT; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { sources[0] = "graphics/shaders/bin/dxbc/triangle_vert.dxbc"; sources[1] = "graphics/shaders/bin/dxbc/triangle_frag.dxbc"; + + viewport.height = (float)WINDOW_HEIGHT; } entries[0].stage = PAL_SHADER_STAGE_VERTEX; @@ -682,12 +691,6 @@ bool triangleTest() Uint32 currentFrame = 0; bool running = true; - // we are not resizing for the viewport and scissor will not change - PalViewport viewport = {0}; - viewport.height = (float)WINDOW_HEIGHT; - viewport.width = (float)WINDOW_WIDTH; - viewport.maxDepth = 1.0f; - PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; scissor.width = WINDOW_WIDTH; diff --git a/tests/tests_main.c b/tests/tests_main.c index c3c21a72..21fa4511 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,7 +59,7 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS @@ -70,7 +70,7 @@ int main(int argc, char** argv) // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); - // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); + registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From c586cbf38028e04fd0475a56f34c912d32c74b8d Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 26 May 2026 00:55:33 -0700 Subject: [PATCH 232/372] remove test properly fixme from mesh test d3d12 --- src/graphics/pal_d3d12.c | 369 +++++++++++++++------ tests/graphics/compute_test.c | 12 +- tests/graphics/descriptor_indexing_test.c | 17 +- tests/graphics/geometry_test.c | 16 +- tests/graphics/indirect_draw_test.c | 14 +- tests/graphics/mesh_test.c | 1 - tests/graphics/multi_descriptor_set_test.c | 12 +- tests/graphics/shaders/bin/dxil/mesh.dxil | Bin 3276 -> 3264 bytes tests/graphics/texture_test.c | 14 +- tests/graphics/triangle_test.c | 14 +- tests/tests_main.c | 4 +- 11 files changed, 318 insertions(+), 155 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 3b54bf94..2b09cf0d 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -39,6 +39,19 @@ freely, subject to the following restrictions: // Typedefs, enums and structs // ================================================== +// From Agility SDK +#ifndef D3D_SHADER_MODEL_6_8 +#define D3D_SHADER_MODEL_6_8 0x68 +#endif // D3D_SHADER_MODEL_6_8 + +#ifndef D3D_SHADER_MODEL_6_9 +#define D3D_SHADER_MODEL_6_9 0x69 +#endif // D3D_SHADER_MODEL_6_9 + +#ifndef D3D_SHADER_MODEL_6_10 +#define D3D_SHADER_MODEL_6_10 0x6a +#endif // D3D_SHADER_MODEL_6_10 + // on older SDKs, D3D_FEATURE_LEVEL_12_2 is not defined #ifndef D3D_FEATURE_LEVEL_12_2 #define D3D_FEATURE_LEVEL_12_2 0xc200 @@ -172,6 +185,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + Uint32 shaderModel; PalAdapterFeatures features; IDXGIAdapter4* adapter; ID3D12CommandSignature* meshSignature; @@ -260,8 +274,15 @@ typedef struct { Uint32 patchControlPoints; PalShaderStage stage; - D3D12_SHADER_BYTECODE byteCode; wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; +} ShaderEntry; + +typedef struct { + const PalGraphicsBackend* backend; + + Uint32 entryCount; + D3D12_SHADER_BYTECODE byteCode; + ShaderEntry* entries; } Shader; typedef struct { @@ -319,7 +340,6 @@ typedef struct { typedef struct { PalShaderStage stage; - ID3D12RootSignature* localRoot; wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; } ShaderExport; @@ -328,11 +348,6 @@ typedef struct { D3D12_HIT_GROUP_DESC desc; } RayHitGroup; -typedef struct { - D3D12_EXPORT_DESC export; - D3D12_DXIL_LIBRARY_DESC library; -} RayShaderLibary; - typedef struct { Uint32 raygenCount; Uint32 raygenDataSize; @@ -391,8 +406,10 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + bool hasDescriptorIndexing; Uint32 bindingCount; Uint32 samplerCount; + D3D12_SHADER_VISIBILITY visibility; DescriptorSetBinding* bindings; } DescriptorSetLayout; @@ -432,6 +449,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; + bool hasDescriptorIndexing; bool hasResourceHeap; bool hasSamplerHeap; Uint32 maxSets; @@ -2571,15 +2589,18 @@ Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( Adapter* d3dAdapter = (Adapter*)adapter; D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; - D3D_SHADER_MODEL models[8]; - models[0] = D3D_SHADER_MODEL_6_7; - models[1] = D3D_SHADER_MODEL_6_6; - models[2] = D3D_SHADER_MODEL_6_5; - models[3] = D3D_SHADER_MODEL_6_4; - models[4] = D3D_SHADER_MODEL_6_3; - models[5] = D3D_SHADER_MODEL_6_2; - models[6] = D3D_SHADER_MODEL_6_1; - models[7] = D3D_SHADER_MODEL_6_0; + D3D_SHADER_MODEL models[11]; + models[0] = D3D_SHADER_MODEL_6_10; + models[1] = D3D_SHADER_MODEL_6_9; + models[2] = D3D_SHADER_MODEL_6_8; + models[3] = D3D_SHADER_MODEL_6_7; + models[4] = D3D_SHADER_MODEL_6_6; + models[5] = D3D_SHADER_MODEL_6_5; + models[6] = D3D_SHADER_MODEL_6_4; + models[7] = D3D_SHADER_MODEL_6_3; + models[8] = D3D_SHADER_MODEL_6_2; + models[9] = D3D_SHADER_MODEL_6_1; + models[10] = D3D_SHADER_MODEL_6_0; // find the highest supported shader model HRESULT result = 0; @@ -2602,8 +2623,14 @@ Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( return 0; } - if (highestModel >= D3D_SHADER_MODEL_6_7) { - return PAL_MAKE_SHADER_TARGET(6, 7); + if (highestModel >= D3D_SHADER_MODEL_6_10) { + return PAL_MAKE_SHADER_TARGET(6, 10); + + } else if (highestModel >= D3D_SHADER_MODEL_6_9) { + return PAL_MAKE_SHADER_TARGET(6, 9); + + } else if (highestModel >= D3D_SHADER_MODEL_6_8) { + return PAL_MAKE_SHADER_TARGET(6, 8); } else if (highestModel >= D3D_SHADER_MODEL_6_6) { return PAL_MAKE_SHADER_TARGET(6, 6); @@ -2659,6 +2686,9 @@ PalResult PAL_CALL createDeviceD3D12( memset(device, 0, sizeof(Device)); DeviceLimits* limits = &device->limits; + // get and cache highest shader model + device->shaderModel = getHighestSupportedShaderTargetD3D12(adapter, PAL_SHADER_FORMAT_DXIL); + result = s_D3D.createDevice( (IUnknown*)d3dAdapter->handle, d3dAdapter->level, @@ -4327,44 +4357,55 @@ PalResult PAL_CALL createShaderD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - // clang-format off - if (info->stage == PAL_SHADER_STAGE_MESH || - info->stage == PAL_SHADER_STAGE_TASK) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + // allocate entries array + shader->entries = palAllocate(s_D3D.allocator, sizeof(ShaderEntry) * info->entryCount, 0); + if (!shader->entries) { + return PAL_RESULT_OUT_OF_MEMORY; + } - } else if (info->stage == PAL_SHADER_STAGE_GEOMETRY) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + for (int i = 0; i < info->entryCount; i++) { + ShaderEntry* entry = &shader->entries[i]; - } else if (info->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || - info->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + // clang-format off + if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || + info->entries[i].stage == PAL_SHADER_STAGE_TASK) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } - } else if (info->stage == PAL_SHADER_STAGE_RAYGEN || - info->stage == PAL_SHADER_STAGE_CLOSEST_HIT || - info->stage == PAL_SHADER_STAGE_ANY_HIT || - info->stage == PAL_SHADER_STAGE_MISS || - info->stage == PAL_SHADER_STAGE_INTERSECTION || - info->stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } else if (info->entries[i].stage == PAL_SHADER_STAGE_GEOMETRY) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || + info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || + info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_MISS || + info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || + info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } } - } - // clang-format on + // clang-format on - convertToWcharD3D12(info->entryName, shader->entryName); - shader->patchControlPoints = info->patchControlPoints; - shader->stage = info->stage; + convertToWcharD3D12(info->entries[i].entryName, entry->entryName); + entry->patchControlPoints = info->entries[i].patchControlPoints; + entry->stage = info->entries[i].stage; + } memcpy(bytecode, info->bytecode, info->bytecodeSize); shader->byteCode.pShaderBytecode = bytecode; shader->byteCode.BytecodeLength = info->bytecodeSize; - + + shader->entryCount = info->entryCount; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } @@ -4373,6 +4414,7 @@ void PAL_CALL destroyShaderD3D12(PalShader* shader) { Shader* d3dShader = (Shader*)shader; palFree(s_D3D.allocator, (void*)d3dShader->byteCode.pShaderBytecode); + palFree(s_D3D.allocator, d3dShader->entries); palFree(s_D3D.allocator, d3dShader); } @@ -6640,8 +6682,6 @@ PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer) // Descriptor Pool, Set and Layout // ================================================== -// TODO: rewrite - PalResult PAL_CALL createDescriptorSetLayoutD3D12( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, @@ -6653,12 +6693,77 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( DescriptorSetBinding* bindings = nullptr; Uint32 count = info->bindingCount; + bool hasDescriptorIndexing = d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + layout = palAllocate(s_D3D.allocator, sizeof(DescriptorSetLayout), 0); bindings = palAllocate(s_D3D.allocator, sizeof(DescriptorSetBinding) * count, 0); if (!layout || !bindings) { return PAL_RESULT_OUT_OF_MEMORY; } + layout->visibility = 0; + if (info->shaderStageCount > 1) { + layout->visibility = D3D12_SHADER_VISIBILITY_ALL; + + } else { + switch (info->shaderStages[0]) { + case PAL_SHADER_STAGE_VERTEX: { + layout->visibility = D3D12_SHADER_VISIBILITY_VERTEX; + break; + } + + case PAL_SHADER_STAGE_FRAGMENT: { + layout->visibility = D3D12_SHADER_VISIBILITY_PIXEL; + break; + } + + case PAL_SHADER_STAGE_GEOMETRY: { + layout->visibility = D3D12_SHADER_VISIBILITY_GEOMETRY; + break; + } + + case PAL_SHADER_STAGE_MESH: { + layout->visibility = D3D12_SHADER_VISIBILITY_MESH; + break; + } + + case PAL_SHADER_STAGE_TASK: { + layout->visibility = D3D12_SHADER_VISIBILITY_AMPLIFICATION; + break; + } + + case PAL_SHADER_STAGE_TESSELLATION_CONTROL: { + layout->visibility = D3D12_SHADER_VISIBILITY_HULL; + break; + } + + case PAL_SHADER_STAGE_TESSELLATION_EVALUATION: { + layout->visibility = D3D12_SHADER_VISIBILITY_DOMAIN; + break; + } + + case PAL_SHADER_STAGE_COMPUTE: + case PAL_SHADER_STAGE_RAYGEN: + case PAL_SHADER_STAGE_CLOSEST_HIT: + case PAL_SHADER_STAGE_ANY_HIT: + case PAL_SHADER_STAGE_MISS: + case PAL_SHADER_STAGE_INTERSECTION: + case PAL_SHADER_STAGE_CALLABLE: { + layout->visibility = D3D12_SHADER_VISIBILITY_ALL; + break; + } + + } + } + + D3D12_DESCRIPTOR_RANGE_FLAGS rangeFlags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; + if (info->enableDescriptorIndexing) { + rangeFlags = D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE; + } + Uint32 resourceOffset = 0; Uint32 samplerOffset = 0; Uint32 SRVRegister = 0; @@ -6677,7 +6782,7 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( binding->type = info->bindings[i].descriptorType; binding->range.NumDescriptors = info->bindings[i].descriptorCount; - binding->range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; + binding->range.Flags = rangeFlags; binding->range.RegisterSpace = 0; switch (info->bindings[i].descriptorType) { @@ -6774,6 +6879,7 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( return PAL_RESULT_INVALID_ARGUMENT; } + layout->hasDescriptorIndexing = info->enableDescriptorIndexing; layout->bindingCount = info->bindingCount; layout->samplerCount = samplerCount; layout->bindings = bindings; @@ -6796,6 +6902,12 @@ PalResult PAL_CALL createDescriptorPoolD3D12( HRESULT result; Device* d3dDevice = (Device*)device; DescriptorPool* pool = nullptr; + + bool hasDescriptorIndexing = d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + pool = palAllocate(s_D3D.allocator, sizeof(DescriptorPool), 0); if (!pool) { return PAL_RESULT_OUT_OF_MEMORY; @@ -6924,6 +7036,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( pool->hasSamplerHeap = true; } + pool->hasDescriptorIndexing = info->enableDescriptorIndexing; pool->maxSets = info->maxDescriptorSets; *outPool = (PalDescriptorPool*)pool; return PAL_RESULT_SUCCESS; @@ -6978,6 +7091,10 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( Uint32 sampledImageCount = 0; Uint32 tlasCount = 0; + if (d3dPool->hasDescriptorIndexing != d3dLayout->hasDescriptorIndexing) { + return PAL_RESULT_INVALID_OPERATION; + } + // get requirements for the sets using the provided layout for (int i = 0; i < d3dLayout->bindingCount; i++) { DescriptorSetBinding* binding = &d3dLayout->bindings[i]; @@ -7219,11 +7336,18 @@ PalResult PAL_CALL createPipelineLayoutD3D12( Uint32 parameterCount = 0; D3D12_ROOT_PARAMETER1* parameters = nullptr; + D3D12_ROOT_SIGNATURE_FLAGS rootFlags = 0; + rootFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; if (info->descriptorSetLayoutCount > d3dDevice->limits.maxBoundDescriptorSets) { return PAL_RESULT_INVALID_ARGUMENT; } + if (d3dDevice->shaderModel >= PAL_MAKE_SHADER_TARGET(6, 6)) { + rootFlags |= D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED; + rootFlags |= D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED; + } + // get the total resource and sampler ranges for all provided descriptor set layouts for (int i = 0; i < info->descriptorSetLayoutCount; i++) { DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; @@ -7330,7 +7454,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter->DescriptorTable.NumDescriptorRanges = resourceCount; parameter->DescriptorTable.pDescriptorRanges = &ranges[rangesOffset]; - parameter->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + parameter->ShaderVisibility = tmp->visibility; rangesOffset += resourceCount; parameterCount++; @@ -7342,7 +7466,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter->DescriptorTable.NumDescriptorRanges = samplerCount; parameter->DescriptorTable.pDescriptorRanges = &samplerRanges[samplerRangesOffset]; - parameter->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + parameter->ShaderVisibility = tmp->visibility; samplerRangesOffset += samplerCount; parameterCount++; @@ -7356,7 +7480,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( rootDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; rootDesc.Desc_1_1.NumParameters = parameterCount; rootDesc.Desc_1_1.pParameters = parameters; - rootDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + rootDesc.Desc_1_1.Flags = rootFlags; ID3DBlob* blob = nullptr; HRESULT result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); @@ -7463,30 +7587,31 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( totalSize += sizeof(ShaderStream); D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - if (tmp->patchControlPoints) { - patchControlPoints = tmp->patchControlPoints; + ShaderEntry* entry = &tmp->entries[0]; + if (entry->patchControlPoints) { + patchControlPoints = entry->patchControlPoints; if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { palFree(s_D3D.allocator, pipeline); return PAL_RESULT_INVALID_OPERATION; } } - if (tmp->stage == PAL_SHADER_STAGE_VERTEX) { + if (entry->stage == PAL_SHADER_STAGE_VERTEX) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS; - } else if (tmp->stage == PAL_SHADER_STAGE_FRAGMENT) { + } else if (entry->stage == PAL_SHADER_STAGE_FRAGMENT) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS; - } else if (tmp->stage == PAL_SHADER_STAGE_GEOMETRY) { + } else if (entry->stage == PAL_SHADER_STAGE_GEOMETRY) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS; - } else if (tmp->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { + } else if (entry->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS; - } else if (tmp->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + } else if (entry->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS; - } else if (tmp->stage == PAL_SHADER_STAGE_TASK) { + } else if (entry->stage == PAL_SHADER_STAGE_TASK) { type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS; } else { @@ -7937,25 +8062,10 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( PalPipeline** outPipeline) { HRESULT result; - Uint32 hitGroupIndex = 0; - Uint32 subObjectIndex = 0; - Uint32 localExportCount = 0; - Uint32 localExportIndex = 0; - - // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG - // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG - Uint32 subObjectCount = info->shaderCount + 2; - Device* d3dDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; Pipeline* pipeline = nullptr; - RayShaderLibary* libraries = nullptr; - RayHitGroup* groups = nullptr; - D3D12_STATE_SUBOBJECT* subObjects = nullptr; - ShaderExport* exports = nullptr; - const wchar_t** localExports = nullptr; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7972,14 +8082,31 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_INVALID_ARGUMENT; } + D3D12_EXPORT_DESC* exportDescs = nullptr; + D3D12_DXIL_LIBRARY_DESC* libraryDescs = nullptr; + RayHitGroup* hitGroups = nullptr; + D3D12_STATE_SUBOBJECT* subObjects = nullptr; + const wchar_t** localExports = nullptr; + + // find the total number of exports + Uint32 exportCount = 0; + for (int i = 0; i < info->shaderCount; i++) { + Shader* shader = (Shader*)info->shaders[i]; + exportCount += shader->entryCount; + } + Uint32 localRootSize = 0; + Uint32 subObjectCount = 0; + Uint32 localExportCount = 0; ShaderBindingTableInfo sbtInfo = {0}; + for (int i = 0; i < info->shaderGroupCount; i++) { PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { // check if its raygen, miss or callable Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; - switch (shader->stage) { + ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; + switch (entry->stage) { case PAL_SHADER_STAGE_RAYGEN: { sbtInfo.raygenCount++; sbtInfo.raygenDataSize = max(sbtInfo.raygenDataSize, tmp->maxDataSize); @@ -8015,6 +8142,9 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( subObjectCount++; } + // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG + // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG + subObjectCount += info->shaderCount + 2; if (localRootSize) { // D3D12_LOCAL_ROOT_SIGNATURE // D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION @@ -8027,16 +8157,37 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( } subObjects = palAllocate(s_D3D.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); - groups = palAllocate(s_D3D.allocator, sizeof(RayHitGroup) * sbtInfo.hitCount, 0); - libraries = palAllocate(s_D3D.allocator, sizeof(RayShaderLibary) * info->shaderCount, 0); - exports = palAllocate(s_D3D.allocator, sizeof(ShaderExport) * info->shaderCount, 0); - localExports = palAllocate(s_D3D.allocator, sizeof(wchar_t*) * localExportCount, 0); + hitGroups = palAllocate(s_D3D.allocator, sizeof(RayHitGroup) * sbtInfo.hitCount, 0); + if (!subObjects || !hitGroups) { + return PAL_RESULT_OUT_OF_MEMORY; + } - if (!exports || !groups || !subObjects || !libraries || !localExports) { + libraryDescs = palAllocate( + s_D3D.allocator, + sizeof(D3D12_DXIL_LIBRARY_DESC) * info->shaderCount, + 0); + + exportDescs = palAllocate( + s_D3D.allocator, + sizeof(D3D12_EXPORT_DESC) * exportCount, + 0); + + pipeline->shaderExports = palAllocate( + s_D3D.allocator, + sizeof(ShaderExport) * exportCount, + 0); + + localExports = palAllocate( + s_D3D.allocator, + sizeof(wchar_t*) * localExportCount, + 0); + + if (!libraryDescs || !exportDescs || !pipeline->shaderExports || !localExports) { return PAL_RESULT_OUT_OF_MEMORY; } // check if we need a local root signature + Uint32 subObjectIndex = 0; D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION localExportAssociation = {0}; if (localRootSize) { D3D12_ROOT_PARAMETER1 parameter = {0}; @@ -8093,47 +8244,56 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( } // shaders + Uint32 exportsOffset = 0; for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; - RayShaderLibary* shaderLibrary = &libraries[i]; - ShaderExport* export = &exports[i]; + D3D12_DXIL_LIBRARY_DESC* libraryDesc = &libraryDescs[i]; + libraryDesc->DXILLibrary = tmp->byteCode; + + for (int j = 0; j < tmp->entryCount; j++) { + D3D12_EXPORT_DESC* exportDesc = &exportDescs[exportsOffset + j]; + ShaderExport* shaderExport = &pipeline->shaderExports[exportsOffset + j]; + ShaderEntry* entry = &tmp->entries[j]; - export->stage = tmp->stage; - wcscpy(export->entryName, tmp->entryName); + shaderExport->stage = entry->stage; + wcscpy(shaderExport->entryName, entry->entryName); - shaderLibrary->export.Flags = D3D12_EXPORT_FLAG_NONE; - shaderLibrary->export.ExportToRename = nullptr; - shaderLibrary->export.Name = export->entryName; // reference + exportDesc->ExportToRename = nullptr; + exportDesc->Flags = D3D12_EXPORT_FLAG_NONE; + exportDesc->Name = shaderExport->entryName; + } - shaderLibrary->library.DXILLibrary = tmp->byteCode; - shaderLibrary->library.NumExports = 1; - shaderLibrary->library.pExports = &shaderLibrary->export; + libraryDesc->pExports = &exportDescs[exportsOffset]; + libraryDesc->NumExports = tmp->entryCount; subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; - subObjects[subObjectIndex].pDesc = &shaderLibrary->library; + subObjects[subObjectIndex].pDesc = libraryDesc; subObjectIndex++; } // hit groups + Uint32 localExportIndex = 0; + Uint32 hitGroupIndex = 0; for (int i = 0; i < info->shaderGroupCount; i++) { const wchar_t* exportName = nullptr; PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { if (tmp->maxDataSize) { Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; - localExports[localExportIndex++] = shader->entryName; + ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; + localExports[localExportIndex++] = entry->entryName; } continue; } - D3D12_HIT_GROUP_DESC* group = &groups[hitGroupIndex].desc; - getHitGroupNameD3D12(hitGroupIndex, groups[hitGroupIndex].entryName); + D3D12_HIT_GROUP_DESC* group = &hitGroups[hitGroupIndex].desc; + getHitGroupNameD3D12(hitGroupIndex, hitGroups[hitGroupIndex].entryName); group->AnyHitShaderImport = nullptr; group->ClosestHitShaderImport = nullptr; group->IntersectionShaderImport = nullptr; - group->HitGroupExport = groups[hitGroupIndex].entryName; + group->HitGroupExport = hitGroups[hitGroupIndex].entryName; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { group->Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; @@ -8145,7 +8305,8 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // Any hit shader if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->anyHitShaderIndex]; - group->AnyHitShaderImport = shader->entryName; + ShaderEntry* entry = &shader->entries[tmp->anyHitShaderEntryIndex]; + group->AnyHitShaderImport = entry->entryName; } else { group->AnyHitShaderImport = nullptr; @@ -8154,7 +8315,8 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // Closest hit shader if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->closestHitShaderIndex]; - group->AnyHitShaderImport = shader->entryName; + ShaderEntry* entry = &shader->entries[tmp->closestHitShaderEntryIndex]; + group->AnyHitShaderImport = entry->entryName; } else { group->ClosestHitShaderImport = nullptr; @@ -8163,7 +8325,8 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // IntersectionShader shader if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->intersectionShaderIndex]; - group->AnyHitShaderImport = shader->entryName; + ShaderEntry* entry = &shader->entries[tmp->intersectionShaderEntryIndex]; + group->AnyHitShaderImport = entry->entryName; } else { group->IntersectionShaderImport = nullptr; @@ -8215,9 +8378,10 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - palFree(s_D3D.allocator, groups); + palFree(s_D3D.allocator, hitGroups); palFree(s_D3D.allocator, subObjects); - palFree(s_D3D.allocator, libraries); + palFree(s_D3D.allocator, libraryDescs); + palFree(s_D3D.allocator, exportDescs); palFree(s_D3D.allocator, localExports); pipeline->type = RAY_TRACING_PIPELINE; @@ -8225,7 +8389,6 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( pipeline->hasFsr = false; pipeline->layout = layout; - pipeline->shaderExports = exports; pipeline->sbtInfo = sbtInfo; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 6c36ae74..d4ee1ade 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -99,7 +99,7 @@ bool computeTest() continue; } - // We want an adapter that supports spirv 1.0 or dxbc 5.1 + // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -116,9 +116,9 @@ bool computeTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } @@ -177,8 +177,8 @@ bool computeTest() if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { source = "graphics/shaders/bin/spirv/compute.spv"; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - source = "graphics/shaders/bin/dxbc/compute.dxbc"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + source = "graphics/shaders/bin/dxil/compute.dxil"; } // read file diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 57208e3a..2f1507bb 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -51,6 +51,7 @@ static void PAL_CALL onGraphicsDebug( bool descriptorIndexingTest() { + // FIXME: Test properly on D3D12 PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; @@ -214,7 +215,7 @@ bool descriptorIndexingTest() continue; } - // We want an adapter that supports spirv 1.4 or dxbc 5.1 + // We want an adapter that supports spirv 1.4 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -225,7 +226,7 @@ bool descriptorIndexingTest() if (adapterInfo.apiType == PAL_ADAPTER_API_TYPE_D3D12 && adapterInfo.type == PAL_ADAPTER_TYPE_CPU) { // D3D12 WARP Adapter has a runtime limitation that causes dynamic indices to fold - // back to slot 0. This has been tested on multiple WARP drivers + // back to slot 0. // explicit registers work for this test but its not reliable for real usage // Texture2D texs[] : register(t0, space0); // set 0 @@ -247,9 +248,9 @@ bool descriptorIndexingTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } @@ -902,9 +903,9 @@ bool descriptorIndexingTest() viewport.height = -(float)WINDOW_HEIGHT; viewport.y = (float)WINDOW_HEIGHT; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - sources[0] = "graphics/shaders/bin/dxbc/texture_vert.dxbc"; - sources[1] = "graphics/shaders/bin/dxbc/descriptor_indexing.dxbc"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + sources[0] = "graphics/shaders/bin/dxil/texture_vert.dxil"; + sources[1] = "graphics/shaders/bin/dxil/descriptor_indexing.dxil"; viewport.height = (float)WINDOW_HEIGHT; } diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index 03955f2c..7f95c135 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -168,7 +168,7 @@ bool geometryTest() continue; } - // We want an adapter that supports spirv 1.0 or dxbc 5.1 + // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -185,9 +185,9 @@ bool geometryTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } @@ -401,10 +401,10 @@ bool geometryTest() viewport.height = -(float)WINDOW_HEIGHT; viewport.y = (float)WINDOW_HEIGHT; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - sources[0] = "graphics/shaders/bin/dxbc/geometry_vert.dxbc"; - sources[1] = "graphics/shaders/bin/dxbc/triangle_frag.dxbc"; - sources[2] = "graphics/shaders/bin/dxbc/geometry.dxbc"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + sources[0] = "graphics/shaders/bin/dxil/geometry_vert.dxil"; + sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; + sources[2] = "graphics/shaders/bin/dxil/geometry.dxil"; viewport.height = (float)WINDOW_HEIGHT; } diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index d3e5de47..5aeacbf7 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -185,7 +185,7 @@ bool indirectDrawTest() continue; } - // We want an adapter that supports spirv 1.0 or dxbc 5.1 + // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -202,9 +202,9 @@ bool indirectDrawTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } @@ -769,9 +769,9 @@ bool indirectDrawTest() viewport.height = -(float)WINDOW_HEIGHT; viewport.y = (float)WINDOW_HEIGHT; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - sources[0] = "graphics/shaders/bin/dxbc/triangle_vert.dxbc"; - sources[1] = "graphics/shaders/bin/dxbc/triangle_frag.dxbc"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + sources[0] = "graphics/shaders/bin/dxil/triangle_vert.dxil"; + sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; viewport.height = (float)WINDOW_HEIGHT; } diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 1d20fb78..651f3e9c 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -19,7 +19,6 @@ static void PAL_CALL onGraphicsDebug( bool meshTest() { - // FIXME: Test properly on D3D12 PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index db6b3ef6..42221097 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -115,7 +115,7 @@ bool multiDescriptorSetTest() continue; } - // We want an adapter that supports spirv 1.0 or dxbc 5.1 + // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -132,9 +132,9 @@ bool multiDescriptorSetTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } @@ -193,8 +193,8 @@ bool multiDescriptorSetTest() if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { source = "graphics/shaders/bin/spirv/compute_multi.spv"; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - source = "graphics/shaders/bin/dxbc/compute_multi.dxbc"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + source = "graphics/shaders/bin/dxil/compute_multi.dxil"; } // read file diff --git a/tests/graphics/shaders/bin/dxil/mesh.dxil b/tests/graphics/shaders/bin/dxil/mesh.dxil index 089e25fc2d0d5c1c56d70aa3fed2d6aa1142af49..3fbf1231631e4d362e173b50d585bd9b93d64957 100644 GIT binary patch delta 1364 zcmbV~eM}o=9LMjbk%yOA+oB)VaNQ*%o&rLf}GH5)IpD3xqMahe*Z@edOdTGH{IGn9@0LG(apu zK^#!`<#vO_vjf+jAL7FrX%c}TD#g@+b+ zw8Oi{*+jX2r+RgiOIIwO8>HMi5~g@R&!P|vy+uAKS(sz&H}LjWoW@V2exdQAsC1<= ziW;KQT@Iox(Hn|i9B2Ui;Vmyj2DkvsS6TYKM&Z1>R3#lLx>b9tm zxX;pX4%6w|9eiS{9r$no`h`A&*fi}AoMIw)J zD@5*n>6JvMa5LI;ulJ|w<1VvNbY^T^5fjb8TPl9?3k%o|sC?aLA$?dR1ll>KFF~7Y zQLDL)SPtW=g1!PYEDTlIgX6)V7g}Fk*G>qRXlK)z4gQ5 zNG{7Rta?``7uYzBoqI0*LaX)7>gKvGOP95dH~pA!wC1enyy?je^0f~|-zA6d;8*(Z zvi^nJ?CQuh;Ms)cU&g%f5QP%zBwe5Kv9V<; zZ2UI3g)Fwn_`Z2b_rHL#NI&3Xb(^cGHk6luWAOUkQh!r!u_Y9YW|F~nk46+A_Hv}BnG(F3A^9r$RiHxQqRO9Pi~1Ue28^^zs~?9)TR zns@9k1oH{{tNW%@WHWXB`zge*Pg(Z9no-Ot*{Oqb%FhpI51+(uUX@=?$$Q&Q$^A2J zhe8{`e!xCH6m!2_V+Y?P-w&sG+=3nJ41fLI9-dQ7iiJwLQV}32i0^_2CF>IeM~HI- z21#%nom>Y;h;sx6xtVo%@B6bg90W&+a}^z-!~~uh1URyTfVMLI0*8d#77(Zhn+Fy! dNl|+9WBb;-%J-ufGK delta 1342 zcmX>gc}CLGCBn(M_Kx1w-rLU$t{!NR$+oMEV`N}pIK#uhzz(EsfY=9!V}SSo5W4^+ zb=VjfJSJLpv(^9wEGC|`p2X;)`hbOjA&r5T!2+njCBoB(4M+`otzKcQv@2Q zzd4g}E@OS0V1toH|0InTC5a4>mG7YR+D{a$)Dei5op{3a|*bG|o`qIm(u(pvKX> z(b0g1E4Nshtp&(q+Q4|jK;rZ!#RM~+=1V>T^|LaaKTOEr_AY*Gl=_wRtJ!q7>EE82 zIU3C2Z2FkP(Zkuq=qu2Z(PSVa+`@QMA>n4*(Ftm+HnE-FVIt=2@8cgN%;J1&1J9k3 z(7Oq|)3-U^*u%^Gfl;_c@umUKVFO2rDV&Ek)XZ$R*>salM&`RT9Rpf<&L3Uplc)Fg zY_6AsiQ?hnjoitbwI|OOk|;g#A?DeILnlr>nRV~PsT<2!JXDQr#CO^3*rZ^--F%n9 zt}W)aEcJ}uo`HFn zGT&vibEoD(DF%kkvsk7vTH46|@Tt7;yRymigSces;SHeptN}(kD1PUo#cv8w92URR zHfOTUW#nvIB*CcB{7Iv8GCzl8y(h(SDS?Q~-Ytp&z!-H{q^ol_7Z^h^%hv2$aPQfr z7nkncQR8qk21X)pBaoa2jzqSUCWCqv>6TNsHdyeBcwRQJymB<@MdwS;tfmAP>1m41 z8lKY28h4p-+}M`LV3E*dpdsCsD51u2*vL_02JcaJwnPE8b8H8Nn|WC;mmH7?Nlf0H zUF@l>4GcXYmQY|sygBvc8PMisEH1*pNZ4&)w%cf@W@8{Q>{I!4d)D}@d)ceGrYF~{ z0TlQfy|s6HE6rX6Ovkf@G(hoq>duQNpBCJ^bmzshWh}{?y*V#1){AWAxYE(c)Sw`t zAn6q7>d-5p!NAePI7v}tsQ{A1StNzBk~oVbv6baKLPzU|9)unB0!T7v zkz}@VTt?DjfNTkp#94%d_*Ndcdy4{D9pO5}kvviqh~yFRtpeBUVU`pH9z{49s0Hp5 zpcW*FtqAu5E%^xdiTF|;xJQ6G5FP= PAL_MAKE_SHADER_TARGET(5, 1)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } @@ -859,9 +859,9 @@ bool textureTest() viewport.height = -(float)WINDOW_HEIGHT; viewport.y = (float)WINDOW_HEIGHT; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - sources[0] = "graphics/shaders/bin/dxbc/texture_vert.dxbc"; - sources[1] = "graphics/shaders/bin/dxbc/texture_frag.dxbc"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + sources[0] = "graphics/shaders/bin/dxil/texture_vert.dxil"; + sources[1] = "graphics/shaders/bin/dxil/texture_frag.dxil"; viewport.height = (float)WINDOW_HEIGHT; } diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 3a2b2aef..dca53bcc 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -166,7 +166,7 @@ bool triangleTest() continue; } - // We want an adapter that supports spirv 1.0 or dxbc 5.1 + // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -183,9 +183,9 @@ bool triangleTest() } } - if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXBC); - if (target >= PAL_MAKE_SHADER_TARGET(5, 1)) { + if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_DXIL); + if (target >= PAL_MAKE_SHADER_TARGET(6, 0)) { break; } } @@ -562,9 +562,9 @@ bool triangleTest() viewport.height = -(float)WINDOW_HEIGHT; viewport.y = (float)WINDOW_HEIGHT; - } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXBC) { - sources[0] = "graphics/shaders/bin/dxbc/triangle_vert.dxbc"; - sources[1] = "graphics/shaders/bin/dxbc/triangle_frag.dxbc"; + } else if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + sources[0] = "graphics/shaders/bin/dxil/triangle_vert.dxil"; + sources[1] = "graphics/shaders/bin/dxil/triangle_frag.dxil"; viewport.height = (float)WINDOW_HEIGHT; } diff --git a/tests/tests_main.c b/tests/tests_main.c index 21fa4511..a836fa81 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -66,11 +66,11 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); - // registerTest(meshTest, "Mesh Test"); + registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); - registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); + // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From 8f5ca9765a7dee7ecff1a3935eef935c1e3a1eee Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 26 May 2026 17:09:21 +0000 Subject: [PATCH 233/372] add more buffer usages --- include/pal/pal_graphics.h | 22 ++-- src/graphics/pal_d3d12.c | 179 +++++++++++++++++------------- src/graphics/pal_graphics.c | 20 ++-- src/graphics/pal_vulkan.c | 53 +++------ tests/graphics/ray_tracing_test.c | 16 ++- tests/tests_main.c | 4 +- 6 files changed, 161 insertions(+), 133 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 9c6d3838..1883e294 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1340,8 +1340,10 @@ typedef enum { PAL_BUFFER_USAGE_TRANSFER_SRC = PAL_BIT(4), PAL_BUFFER_USAGE_TRANSFER_DST = PAL_BIT(5), PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE = PAL_BIT(6), - PAL_BUFFER_USAGE_DEVICE_ADDRESS = PAL_BIT(7), - PAL_BUFFER_USAGE_INDIRECT = PAL_BIT(8) + PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH = PAL_BIT(7), + PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT = PAL_BIT(8), + PAL_BUFFER_USAGE_DEVICE_ADDRESS = PAL_BIT(9), + PAL_BUFFER_USAGE_INDIRECT = PAL_BIT(10) } PalBufferUsages; enum PalDebugMessageSeverity { @@ -6838,12 +6840,16 @@ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` or `PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS` must be - * supported and enabled by the device if `PAL_BUFFER_USAGE_DEVICE_ADDRESS` will be used. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if - * `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE` will be used. - * + * `PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS` must be supported and enabled by the device if + * `PAL_BUFFER_USAGE_DEVICE_ADDRESS` will be used. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if + * `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE` or `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH` + * or `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT` will be used. + * + * `PAL_BUFFER_USAGE_INDIRECT` must be supported and enabled by the device if the buffer will be + * used as an indirect buffer. + * * @param[in] device Device that creates the buffer. * @param[in] info Pointer to a PalBufferCreateInfo struct that specifies parameters. * Must not be nullptr. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 2b09cf0d..147b19d8 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -270,8 +270,6 @@ typedef struct { } Fence, Semaphore; typedef struct { - const PalGraphicsBackend* backend; - Uint32 patchControlPoints; PalShaderStage stage; wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; @@ -1315,9 +1313,14 @@ static bool fillBuildInfoD3D12( tmp->Triangles.IndexBuffer = tmpData->indexBufferAddress; tmp->Triangles.IndexCount = tmpData->indexCount; if (tmpData->indexType == PAL_INDEX_TYPE_UINT16) { - tmp->Triangles.IndexFormat = DXGI_FORMAT_R16_FLOAT; + if (tmp->Triangles.IndexBuffer) { + tmp->Triangles.IndexFormat = DXGI_FORMAT_R16_FLOAT; + } + } else { - tmp->Triangles.IndexFormat = DXGI_FORMAT_R32_FLOAT; + if (tmp->Triangles.IndexBuffer) { + tmp->Triangles.IndexFormat = DXGI_FORMAT_R32_FLOAT; + } } } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { @@ -6436,6 +6439,17 @@ PalResult PAL_CALL createBufferD3D12( Buffer* buffer = nullptr; Device* d3dDevice = (Device*)device; + if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + buffer = palAllocate(s_D3D.allocator, sizeof(Buffer), 0); if (!buffer) { return PAL_RESULT_OUT_OF_MEMORY; @@ -6456,13 +6470,14 @@ PalResult PAL_CALL createBufferD3D12( } if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - buffer->desc.Flags |= D3D12_RESOURCE_FLAG_RAYTRACING_ACCELERATION_STRUCTURE; + buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + } + + if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { + buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } buffer->supportsAddress = true; } @@ -8095,7 +8110,6 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( exportCount += shader->entryCount; } - Uint32 localRootSize = 0; Uint32 subObjectCount = 0; Uint32 localExportCount = 0; ShaderBindingTableInfo sbtInfo = {0}; @@ -8125,28 +8139,32 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( break; } } + + } else { + sbtInfo.hitDataSize = max(sbtInfo.hitDataSize, tmp->maxDataSize); + sbtInfo.hitCount++; } - sbtInfo.hitDataSize = max(sbtInfo.hitDataSize, tmp->maxDataSize); if (tmp->maxDataSize) { localExportCount++; } - - // find the max data size across all shader groups - localRootSize = max(localRootSize, sbtInfo.raygenDataSize); - localRootSize = max(localRootSize, sbtInfo.missDataSize); - localRootSize = max(localRootSize, sbtInfo.hitDataSize); - localRootSize = max(localRootSize, sbtInfo.callableDataSize); - - sbtInfo.hitCount++; - subObjectCount++; } + // find the max data size across all shader groups + Uint32 localRootSize = 0; + localRootSize = max(localRootSize, sbtInfo.raygenDataSize); + localRootSize = max(localRootSize, sbtInfo.missDataSize); + localRootSize = max(localRootSize, sbtInfo.hitDataSize); + localRootSize = max(localRootSize, sbtInfo.callableDataSize); + + // // D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG - subObjectCount += info->shaderCount + 2; + subObjectCount += info->shaderCount + 3; + + subObjectCount += sbtInfo.hitCount; if (localRootSize) { - // D3D12_LOCAL_ROOT_SIGNATURE + // D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE // D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION subObjectCount += 2; } @@ -8186,62 +8204,14 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - // check if we need a local root signature + // global root signature Uint32 subObjectIndex = 0; - D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION localExportAssociation = {0}; - if (localRootSize) { - D3D12_ROOT_PARAMETER1 parameter = {0}; - parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; - parameter.Constants.Num32BitValues = alignD3D12(localRootSize, 4) / 4; - parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + D3D12_GLOBAL_ROOT_SIGNATURE globalRootSignature = {0}; + globalRootSignature.pGlobalRootSignature = layout->handle; - D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; - rootDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; - rootDesc.Desc_1_1.NumParameters = 1; - rootDesc.Desc_1_1.pParameters = ¶meter; - rootDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; - - ID3DBlob* blob = nullptr; - result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); - if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - result = d3dDevice->handle->lpVtbl->CreateRootSignature( - d3dDevice->handle, - 0, - blob->lpVtbl->GetBufferPointer(blob), - blob->lpVtbl->GetBufferSize(blob), - &IID_RootSignature, - (void**)&pipeline->localRootSignature); - - if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE; - subObjects[subObjectIndex].pDesc = pipeline->localRootSignature; - - localExportAssociation.pSubobjectToAssociate = &subObjects[subObjectIndex]; - localExportAssociation.pExports = localExports; - localExportAssociation.NumExports = localExportCount; - subObjectIndex++; - - D3D12_STATE_SUBOBJECT_TYPE t = D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION; - subObjects[subObjectIndex].Type = t; - subObjects[subObjectIndex].pDesc = &localExportAssociation; - subObjectIndex++; - } + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE; + subObjects[subObjectIndex].pDesc = &globalRootSignature; + subObjectIndex++; // shaders Uint32 exportsOffset = 0; @@ -8343,6 +8313,65 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( localExportIndex++; } + // check if we need a local root signature + D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION localExportAssociation = {0}; + D3D12_LOCAL_ROOT_SIGNATURE localRootSignature = {0}; + + if (localRootSize) { + D3D12_ROOT_PARAMETER1 parameter = {0}; + parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + parameter.Constants.Num32BitValues = alignD3D12(localRootSize, 4) / 4; + parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; + rootDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; + rootDesc.Desc_1_1.NumParameters = 1; + rootDesc.Desc_1_1.pParameters = ¶meter; + rootDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; + + ID3DBlob* blob = nullptr; + result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); + if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + result = d3dDevice->handle->lpVtbl->CreateRootSignature( + d3dDevice->handle, + 0, + blob->lpVtbl->GetBufferPointer(blob), + blob->lpVtbl->GetBufferSize(blob), + &IID_RootSignature, + (void**)&pipeline->localRootSignature); + + if (FAILED(result)) { + pollMessagesD3D12(d3dDevice); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + localRootSignature.pLocalRootSignature = pipeline->localRootSignature; + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE; + subObjects[subObjectIndex].pDesc = pipeline->localRootSignature; + + localExportAssociation.pSubobjectToAssociate = &subObjects[subObjectIndex]; + localExportAssociation.pExports = localExports; + localExportAssociation.NumExports = localExportCount; + subObjectIndex++; + + D3D12_STATE_SUBOBJECT_TYPE t = D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION; + subObjects[subObjectIndex].Type = t; + subObjects[subObjectIndex].pDesc = &localExportAssociation; + subObjectIndex++; + } + // ray tracing config D3D12_RAYTRACING_SHADER_CONFIG shaderConfig = {0}; shaderConfig.MaxAttributeSizeInBytes = info->maxAttributeSize; diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 6cc36d7d..74cc876d 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -2086,15 +2086,15 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - result = initGraphicsVk(debugger, allocator); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - - attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base = &s_VkBackend; - attachedBackend->startIndex = 0; - attachedBackend->count = 0; + // result = initGraphicsVk(debugger, allocator); + // if (result != PAL_RESULT_SUCCESS) { + // return result; + // } + + // attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + // attachedBackend->base = &s_VkBackend; + // attachedBackend->startIndex = 0; + // attachedBackend->count = 0; // TODO: uncomment #endif // PAL_HAS_VULKAN // D3D12 @@ -2141,7 +2141,7 @@ void PAL_CALL palShutdownGraphics() #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - shutdownGraphicsVk(); + //shutdownGraphicsVk(); // TODO: uncomment #endif // PAL_HAS_VULKAN // D3D12 diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 5bbe4ea3..8870890c 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1500,11 +1500,17 @@ static VkBufferUsageFlags bufferUsageToVk(PalBufferUsages usages) } if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR; } + if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { + flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR; + } + + if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT) { + flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + } + if (usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; } @@ -3835,22 +3841,17 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } // buffer device address is part of core 1.2 - // if ray tracing is supported, buffer device address will be supported as well - if (adapterFeatures & PAL_ADAPTER_FEATURE_RAY_TRACING) { - adapterFeatures |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; - } else { - if (props.apiVersion >= VK_API_VERSION_1_2 || bufferDeviceAddress) { - VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; - bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; + if (props.apiVersion >= VK_API_VERSION_1_2 || bufferDeviceAddress) { + VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; + bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &bufferAddress; + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &bufferAddress; - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (bufferAddress.bufferDeviceAddress) { - adapterFeatures |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; - } + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (bufferAddress.bufferDeviceAddress) { + adapterFeatures |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; } } @@ -4498,19 +4499,6 @@ PalResult PAL_CALL createDeviceVk( (PFN_vkGetRayTracingShaderGroupHandlesKHR)s_Vk.getDeviceProcAddr( device->handle, "vkGetRayTracingShaderGroupHandlesKHR"); - - device->getBufferrAddress = - (PFN_vkGetBufferDeviceAddress)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetBufferDeviceAddress"); - - if (!device->getBufferrAddress) { - device->getBufferrAddress = - (PFN_vkGetBufferDeviceAddressKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetBufferDeviceAddressKHR"); - } - device->features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; } // buffer address procs @@ -8240,7 +8228,6 @@ PalResult PAL_CALL createBufferVk( if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - // buffer device address feature is supported if ray tracing is } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { @@ -8266,10 +8253,6 @@ PalResult PAL_CALL createBufferVk( } buffer->usages = info->usages; - if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - buffer->usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; - } - buffer->device = vkDevice; buffer->memory = nullptr; *outBuffer = (PalBuffer*)buffer; @@ -8445,7 +8428,7 @@ void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer) PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer) { Buffer* vkBuffer = (Buffer*)buffer; - if (!(vkBuffer->device->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS)) { return 0; } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 512b034a..ede8d8e6 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -119,6 +119,11 @@ bool rayTracingTest() adapter = nullptr; continue; } + + if (!(adapterFeatures & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { + adapter = nullptr; + continue; + } // We want an adapter that supports spirv 1.4 or dxil 6.3 result = palGetAdapterInfo(adapter, &adapterInfo); @@ -156,6 +161,7 @@ bool rayTracingTest() // create a device PalAdapterFeatures features = PAL_ADAPTER_FEATURE_RAY_TRACING; + features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -335,7 +341,8 @@ bool rayTracingTest() -1.0f, -1.0f}; bufferCreateInfo.size = sizeof(vertices); - bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); if (result != PAL_RESULT_SUCCESS) { @@ -419,6 +426,7 @@ bool rayTracingTest() // create the blas buffer and blas bufferCreateInfo.size = buildSizes.accelerationStructureSize; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; result = palCreateBuffer(device, &bufferCreateInfo, &blasBuffer); if (result != PAL_RESULT_SUCCESS) { @@ -493,7 +501,8 @@ bool rayTracingTest() } bufferCreateInfo.size = instanceBufferSize; - bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; result = palCreateBuffer(device, &bufferCreateInfo, &instanceBuffer); if (result != PAL_RESULT_SUCCESS) { @@ -574,6 +583,7 @@ bool rayTracingTest() // create the tlas buffer and tlas bufferCreateInfo.size = buildSizes.accelerationStructureSize; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; + bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; result = palCreateBuffer(device, &bufferCreateInfo, &tlasBuffer); if (result != PAL_RESULT_SUCCESS) { @@ -622,7 +632,7 @@ bool rayTracingTest() // create scratch buffer bufferCreateInfo.size = buildSizes.scratchBufferSize + blasScratchSize;; - bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE; + bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; result = palCreateBuffer(device, &bufferCreateInfo, &scratchBuffer); diff --git a/tests/tests_main.c b/tests/tests_main.c index a836fa81..c3c21a72 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,14 +59,14 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS #if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); - registerTest(meshTest, "Mesh Test"); + // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); From 61dfb142e4b8425ce1f497b57f4816c17f71f2b5 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 26 May 2026 20:02:34 -0700 Subject: [PATCH 234/372] update premake binaries --- premake/premake5 | Bin 2667824 -> 2725168 bytes premake/premake5.exe | Bin 1568256 -> 1567744 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/premake/premake5 b/premake/premake5 index 1b601b0ae3bb7d86522ab766db7f0ba935a380d9..b5354b58c56f56421fa97e313918df72b0f09076 100755 GIT binary patch delta 350998 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

7do5&qWoIea~BEKi~{GnGlMpfHRuuy^>A&8 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 z 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 #77C`wpMv}3--b8IUx2sBJ8(Ckz?S&h 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 z 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≈HNT*;jC{S@(?h3sqUh&?OWv-l*u;$|mq;ct*$6NyLM!g#17 zdTt}n>`RQn!_Y{)7v6*>;KiA@(+|8j{tjXuFXo{Dz5vce`dtq(eHHOfxp)Dp#QWj! zJMH}?eu|nY7t`x2K;$K%YPJ9xMdYHY67k~8#>*XG5 z@pSw!yf_DW@!}K6hZnORwadll(KO2Au<$W*CSE+Jfqj7&Q=5n@yc=G*mS+ZM-~eo0 z$5<$j!V_CrFTA+dlk{2j;q~k3Gd>9GH_+C8)Q4w0O+WDkupEuXi!CS@FAmyByy3;; zP%&OS9hKt?;7!jm&-f5r{TzFW_d3M)V#GYcNYT z{eii~iw(#}%vPjlndtiqdx1LQWvB%2 zhbtxGM?CdC#zna}ABFJ&ScUZ7zUWIZF0})vqYkwL+tC)h*zXgb*Ld+jWcD9wac7dT z;FIvPFNyQFh_|nJ*7Onol*i%wNN0Yr59LxWF8GeMz>8&QE?&F=mEeQ$!tWUi-Vd)r zA-s6`F4hPyZj|sb_`q&E&cks29`-Wj;=w<%$MNDVs249jgxrIfbNC|C8C#ra`WX-9 z;%qblFSa^f>~g&LvE#*ld)f8H5snvqju-uo7lV!$!;TkYju$_1yx4DVr+w&kym*e| z#m5{kwmV*Y&GF(Vju%r>>^8+=ju($}ym+qT#rcjGgN_#;a=iG2Ni!VD~eBbfn_l_55rrGxumpfj(+wo$f`}MQi6h}B-ye++-$tQk7@Q*0K^G@7@3Mm&yxcZr5ycb@O!J3f|{V+STpLIU; z!pTT~n?<}1l~G^Zgevf20!8rRYyF8~@=^jGG=MfK7mN2HcJX2mCGcX3yPrwo-S8`< zX9t5aXAJ6R<+lR(EK+$4Ci%?Q0YljPaLHie1}`ogLR{j-8&Ezz2s000ym;{pRD>7L zL1lPx)zE$>gco~I1TTJ%RLAfc(nFE*fOs@&r(App#qr{^XeVCmK)dj9IP4(qtM>!N z!|DG4={NxWEwcHzZ8Blpmu z7R@oX7l%7u^q`T{5ev`+ytoSa@M0~Rh8NePV!U|zc;W^xo{cK-;`yi+FU~@3ct1Sy zSo+3$I9_-mpZ%@)3Bzp@SsUsk;Kg~2OZDOPXENq2&TsIU{C;LIUVI5<?CKT}D$8~zbl?-j!&($A}i zGcLkYM_ho~)FzxeU2%qoXJ2f$QvkCIiAl=6umS1&CgSU8JLO`(8U0KjUL56kvB2@7 z9}PH=alvw=I0?a1F0uEx4`$D@W7`XFyVTAhA-ML}#68zW;U|}IE$4@TpY~>RU%VSO zJ3b0~=Mo##7r&U#UcifKMf3^phJK`V6iXNIHRVB=eWl$WFYIu99Da_=azuOitRCa;NgpyXXw`pRAx= z%6-9pX7q3D`d&EcCdN*A0rajU#tx!=_$Kn;#eO%lFYw|Fl#lnrPmq-xZz1-O)*=Y+ zxRv}y9dRQH;Khr|$qBj^{thYsiY<-n=#7E&Rf8yTc@DO|+bx|&ELEG@+n{n0= zFOGeU&+{I}d(rS@G#KxLK{OICmcPzg;KfH#0X_`3AU|F_d%tIm@L~87nuQnl|AG2=@kCUH7vI`NKk=e#cRv%wiyqX07f(%1H(T)jv~)Ah zm2Q%FFU;OI-3&Ms4{HxdHzV;;c;V1=1HQhtVL!xeSkN5(~TP+giXiLSG;)N zc>0DHUpzM5OvA_FffLfLJm!T@A?2|coXp=BK#9(Y2!>A{QV9aGN_+^;nv`xmgZyyeonH=FwP!u#&p&d?}rsL(#=$S82V7r_gzvdjIj4C#F>F?VUYaUIV0Bj9x8!HY#G2QMy1Q}IDqRl;23#UWQy z4==7pEAe6Y+fv4k55XO%4KF@=UApPOi<7Qr{_zE{VFlyGN8wp3(@pA#p%y>CIo%Ay ziz9AHH(vZmcq!7e&kq}so+-`ngj;Q&1LMd?eX-Xm7Y`}7>v-TLj-LgWA+=cokGjpS zGaBY1m5UcSz7TG?ow3utxC5z954>$vx`|L8hM(Ta`r-TFnre_!xZo0oFTZsOf?yK1jP< z>w`;>=B)yLk94nHaA2j~jvF5C_>pj|<9)CIc}B7?VDcgM2)=SP<3d*d;cJfH0`Gg+ zj{gey4pN&aM^kLsU$gJ@DkPU7icCKx(rHb~)wZ{Z;AK&w*6Jx2x@W z?uPHwq?0V-o7a+>$|%meb#pCD{P`S>V&3l-oKaMTOT8$KJZNBX{4 zJA4;ueiD$+MKONrl*2!uz$l&t;vbwoz!9B1r+B|^Bpme;^QAW7(OtG54adD|`!JmR zCvr5e<9u=U2$C;(jrDn*JWTuM4RSTo`;%fJ3e%=IAGP6&;MYjM)7=N}dfRS41l{l0 zUVLyHd6M&aB^>@2+k4=}ACP0!CY-T@HR8VA@W_wp59Oob9;EYt`Gm6pl5dCSe`?Q< zAHIdON4nv%opy|sz@eYfH`>gC+mYUf5nZ1%ceF3g_=5Sxm%<0Xv}2|jrhjF(?|~ap zGwq0v^pd;rVVFRDcyZ#_#5vvvyO3f)eDoWhHIzr-zTetocf%z}`zrv?>Z3fHXAQgt zsk{_!KxLG-!{fiBUCMLd7F0sH_~8$%4Za87wu>0UuY#LV6yF64cH7sAU+-ZZDer^6 zAIT?2(r360<>RyXB+5xheV7WbLtCi71`bJa8JFt7t$YO1Hp;ibc$&-fQ7(?@$F+Db z{2kJ|Y=qO&UDlk4Q(P_+rOs5i5Ggjw;Bgr)lXKKilLPn4bQwQ>7<>S&!B@hG{at1i z-Uqvp=2i?0u)R2cAD4+yrwBfXtk{DcNaGUu3?j?-!IKBtJ`Wb|>oPrD8-Sl7&(ZY9 z?J_Hn_G1uMJH8fnAgfKd-SJ}H{*0Mx#o0)Gm!{8dk(#Dc$Ui)b8R6!^I(^?-}B)IhqEp}5Zmy%Bkb}RJpNbqoaexgkz!*f zd~B5M!|?oU+fRe(N7~*6f9Lp(aMDpO)6RXT!VM^aZ-=hY_F9N@#<)zF^0{!wSeGfo z`^FI`NNcnmmU(S24n4+YQb!X@@JFQFYsS0GCrEjFCtP`~U0)nN!S-Hw?{O~U<=O-s zcf39SUidE3&yy!$@C4S9I^yIUm-V;q#fwj5ekd0UPNqIy{0eQu_riN7(k8wF_MF1F z@Zxnb0h5hpFHFd$v zNwyyhzd@;E*r)KODYS`S2_KotxZdM6DI9Sw^FaAX*l?chBk;fi=f3a@q+HYsH=l3& zF4%N|Jn*b8&NoOmhJtp-=(&9!>1e{gIE08 zE)T#1F0;J{zU=reIMHv}%Q-2ZZghyWv)(&x{a1s$ySIM@-bXOdDQ2w$^TE0<3d<1SU}S zIO@Q)b>t3wGrX#vf8*K`SdX+{B5*TOf4bnw4dg@W1YiqN`9}C1DyE%X@PQ`sExr~Z!oek42vDOaz76P{#@>>Y7ro4t185~O|x zU^~(r#$ftWJPT>Z1@ktr-gt2bn(8Ho!2Z8e9wh(6I;5N*fjg1nT#P<#my3g+Vcw`O zuG+}D)28?rq&_5I$|ie^sqiSrkA_Fa$eCO_8kQjSvkcZD&0z#Si_}ghyzY6%OZ_s~ z{{{A{`Uxk!NI#At9^jBp;(_N#7JLlp+Av(cnf9q4gqzR=>c?QiOZI&u@ZFcmfjrj| za8H*#Uh@j=Nz@k)jNA2x!9(A$^O6S++QPh1#{;iNYw)7Go7lsPV^KHW3;jrA6d!SX z7(Vl7=9W4eVR$QhXFO*)IP@LzCq4^Ck)B!NRoj?<%1hvYckOcV&q(vR4Q9P(_fxzA zX&sB;Vke`CLSE`UgBa=;t)J8m*$v8hH9&?R=64KXLp{_~56^ z?Xko;JmWLs3ZDmSKc{`Xcu0~s;XLnw4>^7fe6yFnQl}ff^)>s1dv(JbzG2?*K{)DL z+h@bAeY8XQHu&`Sl=E{n8{xh`*kdn&C+)U?SV4~+3nAQFFC#ozO#RZb(Y%(za5-meJ`UAo;W1Kv~z7PJm>)G;D^Dt zkm8{meu>ndUN~^5?cH#SU^+&?XP#@)f_%Iqaff$2R526pe zCK8JewtX3V4kf7H1HHpCOgBCc&PVD`5iE7QxE^UvV$d97dvPXG{Q#_UeBPlM=4Pa^ zm%~3HtxFt!ja1(?Jj0ysq5L@R3!gw)_%`@1nu|}s#fN3^J~7V)_z_Yr?SWSwZu?SL zkM#N_0w<5K=XNT5Vx+wmZSasI>^^(oUy%BcfR`SXVe)C;5C4FQ@SSkM(ew>p45yFD zu+HIyuxDI`Swp!v;aKJfFOEAd!}Q|4@EWA&ODWvzc-DnJr-~>+9r4x^?DBH>1?r-F z7aWyi_st70K`WUDK0DRChBWpq@ZOV%`{Rj!c*(>Jvr~28b*E&QT6`JYd^&T2?}DeD zP5e_o51y4z`}lk~dy?(v!Yz|C_*qe2Z^Gg!#5}o6ylpDuq})jkEj=KrZEQ+>mq)FG>1Fku@~8M zG64pV-n$lGMe0LeVTL(!hV4hg*^ZwJ?{|D9e8ur`IR8@GKY?=socn9`39m=QGyU|H z@_cy6Y}&+o;MJGgd#4n>G>7_>cfk+lW?1=iJKQ{i;hILb1I^I^bT5h%2s5g=e60d>;G_>cy{wn^7~q3m&~V!^H8U;ddyA-vx&) zvFA$MFFX;=Wh2uPJxK0;Kzv!@aJd4&|vZR%+*7G3#2p4`RUaVjI$Z#qf31VT|Ib z*Jqe%wBv`KGM+oUZW3FOVkrvUH`w3Jchtg!o#3U5JbryQ09 z?fZ(aA&q4VJoGnqeGj}8sh@s$m*Ye5li%9qJK?@JWmsnbH#{F{&ZohCD_LvC;)0Wr z%BR8#$4B8uj!(Tg!`zM9s2_rd-9kLzN5X?|B@Xe!U?oyJ;+%4OjC0{;r1CC!@NIVA zhQR^1Q_kFugd^`DfAT#M@jA4VHY?#xt7zv>{JbLc+{ra3vPa-X$BW0`WzSCzeC+NF z>orjrJ{KZaP(KErxtHtl8{yph>>MIqSYh{bJ6v%;xr;hM*ori_Q8?@Y){JwzIPyW( zhC1TumDIuK!OxJ^E(vdc$liAqaO`T^=fJTK({Jhr;8VzoZTRsT=8*E8@SaEPb3z5& zjuPBgT=gjZKZ$1+T=tk9^K0PNF!RQ>+u#FL_Sh@oKGk;nZg@s5IfQGc!sST!ErlI* zCf8bE_fi)wZov-@s;px$9Kc@=bZZR;Fujt!{E#p$Ro5l z3l8eAV`(rv8L7=S_*chohx`A*E*}ifaC{y-r8C3ib6+q4vk0W?JV@vGJfx6QjHhzIkw_NvIC2KZLQL${83Q zacHLXw?49A4Cy%~Hh5@Db>Pqunfz^XUJJuG8ip6WBkg{QQynj6jLPKqg2*Ru1=1KR zV0E_L=UV7H(w!rX1smh0WgfLXEEG? z)c+(Ld#vrfa6XFCP7$0t!LBdfhcwR>@Y|CZ8+H2N-nq;VKTnkkho43aQ0{@Nkj|6h zvb;>|`_v_{9_hXjxZ`ZQeh*CMXPUu2{Y)d*PO|SSuAFSw?|>Ih%`_valYrCDwdW)V zHz3_B0n5*``zd~drc%ETURq$c~=c_%>31x?$h~+l%L2L_erg08g5pX`1o5 z@LQy~?Sq$JOq@_Y7w$%Sz0WV7nWdM|7Ud;y)=c_v8hHR7Im>Q;H2l5eJ7E9IGL4%$ z1K?mkv4Woq2hFzcH5mTU@tyGO%QLOlp84>_xtXSydv(J8^B5O@i)H|9xgygP(@qqA zidN!x!j1Foc@w*e5Nj%4a=q4!{+F@Wkji`D9XHtbS_LQF$XGakPJ?HzU{0tXfI-xb z?}9Bs_6FYdn@ltDxAX_!23;#NO}EP7o?95_>D=p9Vyv7Ppj_OA^!iA=`*wRiLvS-v z>}`QXci8({T!B;`gv0M-FVLn3K71GRk6#1lh8V9rTz)Tcf-i+HA_Juzf%W&1 zr#Qz(VE+m`FAadB9WSm#IwOf&obvGfnP$qv%meKg!OxM-dr5fT8oQkexZClrN7&Pa}Tj=55Ocq1y*yL*}B6MGmRgJajyKHdvoUB{U5aX2k% zd-0+T#3AK=xOF4@5ubo>##mQ;=y~qh!QA2l@Zrtm#60E=9+P0-;eD{_L*@AM8e2uLK#Tv(pn;b8`<#_R1$BXV= ztP9`E7LP=_mpIMwVlh%3aivo(KI(Y!DWp1L+$k4#J6=3sx81&YDpGy%Vy9eO>Ui-E z$BQ+N7dJUx+~RogZ%A#5u08g>#3LOq`jF~~Gn{g9spG{*9WQQhyg2Sh*85Zb&N-Zf zG*{x~ju&r4YF}LKc(DzszW9pc#lJdU+~s&a$<=s}>i_@${^w`l(TDiiKlDfRAgV=e zr~_4?E)+ot6h~ncMKKgYJ?Q8EweWLc74?+E;czutfdVK=*`4qrbQX&9^&IF$E)?bK zt0VmU44REDL}#L7&><)Tech05>KoI|W9S}q6IzaDqjS)S=m@m;+H~_nQ@Z&Ky@y^y zFQE0P0X>BN|9}5D1N_Z#iads2yMZ|n{OmtI8opW6!ltOeWh8Jv`d z_#*7h;_uu1y+ZWZEPaIIPye}7Cg7)=3(aNx|4efMZjw3AoXgjf`2SgW{kJLgb3T1o z7xFu=)_*onb-v=Snppqpd}$%TpETc#_DalBv%oAi^J#5?DK_(Hd9k^|ETPs^tB#ky z)#NoNq6zdtJt{W8;@UH)vxvXRJ)8R1(wo_QHP32$GJYBVx|rE4plm6B!CUuO#@DJn z7nYbJ{zd=36fUBC;ZI*LF<0W}P>0V~HoOP$Q{VC^U&gVKK)j|H2Pnb zc}zB?M>3}IwCLskV=On`97EZ^a!yV+`_RAhoc?HL)yscdKYeAdM1UH9pIeP~o+(B8 zZ@e|HnzbdY$8u}7f4+wQY(8_X`TXTI|2V7v(VXUSPd?R^zAgQ!r+<$$J{z1EW-p#QyLidsc@sxnJ8#*jQ%~6^Gk5l~W%CwYUVN>G1{N=yIBNOQ#V0MBQ#5bU z>}6vXEts=($+9I^l#H3PWYI~pmn|B5^)aJ7i)JrgaK*f3CDVU?H=6Qza!ZyjUsf_{ z@fAy))(-z~w07*_)^%LDY~GyZOBa+}>wHbg(s@@c=PvW+7A#$G^@8Gg^XD!5=^uao z&u5l$X$ixgI`8Uv#hzmQf8waw%O)+pddb3hOGkN@FF0+^oO#O_+ZD5mm(3gH8TV5= zx#RxhyX21hMW1rV{WLf(&mH$~^Trnnn*Z1SbN4syy^M*~b=Jk}y6X~k$vRiPyFRPl zQ=eV$tx=3G_2K$xeXKrSpQumPn+A7-r@`CcYba>&Hv}4j4WWi`L$o2* z5N}8{BpXb`9q~lG5nrSr;*SI(!AK|)jzlA|NIa5=BqOHL-RNobHu@S18vTud#$aQp zG29q!j5Wp^6OGA6)8uaQGZCZcIemO(= z^#wo8QfYm#zPvtEU&(w$n6Y-|tdm*mX5M<3xjyF3#q4DwvV}WF}qpJZ#FZW!yM-`%Z1Ey5i?!NT$eN3mCSb} z!VlA$X{@ie%2!oTRaoV(Dyj-pl~x6-%Bw1?!c~!~XjOYvtg5prUe#08SLLd9S7%jw zsUec`b)vebI$7OUZE9RK?wYI`Pfd1>wd0nWkvMyW~ zsf*UN*TsH{!5*T}p8J14&weWwOaJAwoM`GHuKI{97qOK^bY&A?IYd}KF;+;F6%l8p zM4Bn+Z=GEVn~IuBo64Iin<7o^O`T2Mw9wb&;@WJk%jcRR>X)yrTpL;2zP591_u8Jd zeQRCKS#z) z!?AEYoCqhwrpjIAsj?%%PZR{JLPS86)sI&ts|+jesrFX;stc<9)q(0@b*MUQMM0bh zNV58FR^D6Vt0}1IS=YDD)soec-ICLi-%{98)Kc0~-cs2TX=!iiZ0T<4Y3XZmwPv+u zx8}6ww-&Y*wU)M)w^p`BTH9MYTf19(TKih*Z=kfz(PB=eY7%mEzhReg1 z;YheW+!^i;_k{bxuBxo6?5doqeB!r=*j404h}zDoZYO55h}WFz{OZE$qUzG>^6JX! zNOe2W+fC&5RlA7UY~nS)rm&`{rnIKKrm`kd(_YhA(_Pb3(^uoF%_5R>*zbiza4FGS zSsSTsukEbuuI;Jqt922>*~D)?v0FskmJ_oP;C# zGO5ZF|CeR#=(^ayY8UZ>q`&F@pWH`@|IVG{uL;xyYeF^QnrKa|CSH@MN!FNJcddua z>Z>gvrv}KUq1te5v^G{7uT9h@$*XR1s+W9PKrRiCM?>V$DETvPJ--c4ClAkVA5SHJ zJp+pJj0Zt-QHX40V*NR{8&K>vQQ3rD4$GJNG>WO8tgk5B) zEOJyfSt^GtRY;yHB2$%;tIEk%mE@}k8LOR~)k)UsCU5nSx%$XmF0xk^`74_Ymc!F5 z|KB~&LjUfG)?Jk#LnL{wnd-kk*}UWm<+vhpMUX64Nw$buPdh#9l2*o0uFEE8DBBg1 zHMC0Qm;W9;?vfD@YXPM9;A zGEbaSnsSffoTlvK<)o(k*UtS6EeZst&eAD{L;ZPH^STmDU-qy}8pm#q~7zS?9Q{b=lTQE`MDi zXSs4ta+UU3&O5*iChUHGvM{j$yn-{Pn^UBT+y5T1#uQ^z+7tt!dUg%*Z2NrGi`rf*Y|KEbP8KIT6CcRyI-YTiD9aj?mr<$z-JC;vIEgZb zOD9^YUPr0}i zcRg0*nMTE4mKA+k0Uu92MWEk`!BQ&V!Z From cc49197e228b34d7f61db3973774971da1664447 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 27 May 2026 06:23:35 -0700 Subject: [PATCH 235/372] make bitmask base cross compiler --- .gitignore | 1 + include/pal/pal_graphics.h | 366 ++++++++++++++--------------- include/pal/pal_video.h | 106 ++++----- premake5.lua | 8 +- src/graphics/pal_d3d12.c | 4 +- src/graphics/pal_vulkan.c | 10 +- src/video/pal_video_linux.c | 4 + src/video/pal_video_win32.c | 4 + tests/graphics/graphics_test.c | 4 +- tests/tests_main.c | 4 +- tests/video/native_instance_test.c | 6 +- 11 files changed, 265 insertions(+), 252 deletions(-) diff --git a/.gitignore b/.gitignore index 25665d4f..a10e46a7 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ Makefile # Visual studio files **.sln +**.slnx **.filters **.user **.vcxproj diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 1883e294..5975bf69 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -78,6 +78,54 @@ freely, subject to the following restrictions: */ #define PAL_SHADER_TARGET_MINOR(target) ((Uint32)(target) & 0xFF); +/** + * @enum PalAdapterFeatures + * @brief Adapter features. This is a bitmask. + * + * All adapter features follow the format `PAL_ADAPTER_FEATURE_**` for + * consistency and API use. + * + * @since 1.4 + * @ingroup pal_graphics + */ +typedef Uint64 PalAdapterFeatures; + +#define PAL_ADAPTER_FEATURE_NONE 0; +#define PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY PAL_BIT64(1) +#define PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING PAL_BIT64(2) +#define PAL_ADAPTER_FEATURE_MULTI_VIEWPORT PAL_BIT64(3) +#define PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE PAL_BIT64(4) +#define PAL_ADAPTER_FEATURE_TESSELLATION_SHADER PAL_BIT64(5) +#define PAL_ADAPTER_FEATURE_GEOMETRY_SHADER PAL_BIT64(6) +#define PAL_ADAPTER_FEATURE_SHADER_FLOAT16 PAL_BIT64(7) +#define PAL_ADAPTER_FEATURE_SHADER_FLOAT64 PAL_BIT64(8) +#define PAL_ADAPTER_FEATURE_SHADER_INT16 PAL_BIT64(9) +#define PAL_ADAPTER_FEATURE_SHADER_INT64 PAL_BIT64(10) +#define PAL_ADAPTER_FEATURE_RAY_TRACING PAL_BIT64(11) +#define PAL_ADAPTER_FEATURE_MESH_SHADER PAL_BIT64(12) +#define PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE PAL_BIT64(13) +#define PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING PAL_BIT64(14) +#define PAL_ADAPTER_FEATURE_SWAPCHAIN PAL_BIT64(15) +#define PAL_ADAPTER_FEATURE_MULTI_VIEW PAL_BIT64(16) +#define PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY PAL_BIT64(17) +#define PAL_ADAPTER_FEATURE_FENCE_RESET PAL_BIT64(18) +#define PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE PAL_BIT64(19) +#define PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE PAL_BIT64(20) +#define PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE PAL_BIT64(21) +#define PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY PAL_BIT64(22) +#define PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE PAL_BIT64(23) +#define PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE PAL_BIT64(24) +#define PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP PAL_BIT64(25) +#define PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE PAL_BIT64(26) +#define PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT PAL_BIT64(27) +#define PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS PAL_BIT64(28) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW PAL_BIT64(29) +#define PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH PAL_BIT64(30) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT PAL_BIT64(31) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH PAL_BIT64(32) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT PAL_BIT64(33) +#define PAL_ADAPTER_FEATURE_DISPATCH_BASE PAL_BIT64(34) + /** * @struct PalAdapter * @brief Opaque handle to an adapter (GPU). @@ -564,54 +612,6 @@ typedef enum { PAL_SHADER_FORMAT_PPM = PAL_BIT(5) } PalShaderFormats; -/** - * @enum PalAdapterFeatures - * @brief Adapter features. This is a bitmask. - * - * All adapter features follow the format `PAL_ADAPTER_FEATURE_**` for - * consistency and API use. - * - * @since 1.4 - * @ingroup pal_graphics - */ -typedef enum { - PAL_ADAPTER_FEATURE_NONE = 0, - PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY = PAL_BIT64(1), - PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING = PAL_BIT64(2), - PAL_ADAPTER_FEATURE_MULTI_VIEWPORT = PAL_BIT64(3), - PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE = PAL_BIT64(4), - PAL_ADAPTER_FEATURE_TESSELLATION_SHADER = PAL_BIT64(5), - PAL_ADAPTER_FEATURE_GEOMETRY_SHADER = PAL_BIT64(6), - PAL_ADAPTER_FEATURE_SHADER_FLOAT16 = PAL_BIT64(7), - PAL_ADAPTER_FEATURE_SHADER_FLOAT64 = PAL_BIT64(8), - PAL_ADAPTER_FEATURE_SHADER_INT16 = PAL_BIT64(9), - PAL_ADAPTER_FEATURE_SHADER_INT64 = PAL_BIT64(10), - PAL_ADAPTER_FEATURE_RAY_TRACING = PAL_BIT64(11), - PAL_ADAPTER_FEATURE_MESH_SHADER = PAL_BIT64(12), - PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE = PAL_BIT64(13), - PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING = PAL_BIT64(14), - PAL_ADAPTER_FEATURE_SWAPCHAIN = PAL_BIT64(15), - PAL_ADAPTER_FEATURE_MULTI_VIEW = PAL_BIT64(16), - PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY = PAL_BIT64(17), - PAL_ADAPTER_FEATURE_FENCE_RESET = PAL_BIT64(18), - PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE = PAL_BIT64(19), - PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE = PAL_BIT64(20), - PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE = PAL_BIT64(21), - PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY = PAL_BIT64(22), - PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE = PAL_BIT64(23), - PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE = PAL_BIT64(24), - PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP = PAL_BIT64(25), - PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE = PAL_BIT64(26), - PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT = PAL_BIT64(27), - PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS = PAL_BIT64(28), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW = PAL_BIT64(29), - PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH = PAL_BIT64(30), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT = PAL_BIT64(31), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH = PAL_BIT64(32), - PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT = PAL_BIT64(33), - PAL_ADAPTER_FEATURE_DISPATCH_BASE = PAL_BIT64(34) -} PalAdapterFeatures; - /** * @enum PalLoadOp * @brief Load operation type. @@ -2789,7 +2789,7 @@ typedef struct { * * Must obey the rules and semantics documented in palEnumerateAdapters(). */ - PalResult PAL_CALL (*enumerateAdapters)( + PalResult (PAL_CALL *enumerateAdapters)( Int32* count, PalAdapter** outAdapters); @@ -2798,7 +2798,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetAdapterInfo(). */ - PalResult PAL_CALL (*getAdapterInfo)( + PalResult (PAL_CALL *getAdapterInfo)( PalAdapter* adapter, PalAdapterInfo* info); @@ -2807,7 +2807,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetAdapterCapabilities(). */ - PalResult PAL_CALL (*getAdapterCapabilities)( + PalResult (PAL_CALL *getAdapterCapabilities)( PalAdapter* adapter, PalAdapterCapabilities* caps); @@ -2816,14 +2816,14 @@ typedef struct { * * Must obey the rules and semantics documented in palGetAdapterFeatures(). */ - PalAdapterFeatures PAL_CALL (*getAdapterFeatures)(PalAdapter* adapter); + PalAdapterFeatures (PAL_CALL *getAdapterFeatures)(PalAdapter* adapter); /** * Backend implementation of ::palGetHighestSupportedShaderTarget. * * Must obey the rules and semantics documented in palGetHighestSupportedShaderTarget(). */ - Uint32 PAL_CALL (*getHighestSupportedShaderTarget)( + Uint32 (PAL_CALL *getHighestSupportedShaderTarget)( PalAdapter* adapter, PalShaderFormats shaderFormat); @@ -2832,7 +2832,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateDevice(). */ - PalResult PAL_CALL (*createDevice)( + PalResult (PAL_CALL *createDevice)( PalAdapter* adapter, PalAdapterFeatures features, PalDevice** outDevice); @@ -2842,14 +2842,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyDevice(). */ - void PAL_CALL (*destroyDevice)(PalDevice* device); + void (PAL_CALL *destroyDevice)(PalDevice* device); /** * Backend implementation of ::palAllocateMemory. * * Must obey the rules and semantics documented in palAllocateMemory(). */ - PalResult PAL_CALL (*allocateMemory)( + PalResult (PAL_CALL *allocateMemory)( PalDevice* device, PalMemoryType type, Uint64 memoryMask, @@ -2861,7 +2861,7 @@ typedef struct { * * Must obey the rules and semantics documented in palFreeMemory(). */ - void PAL_CALL (*freeMemory)( + void (PAL_CALL *freeMemory)( PalDevice* device, PalMemory* memory); @@ -2871,7 +2871,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQuerySamplerAnisotropyCapabilities(). */ - PalResult PAL_CALL (*querySamplerAnisotropyCapabilities)( + PalResult (PAL_CALL *querySamplerAnisotropyCapabilities)( PalDevice* device, PalSamplerAnisotropyCapabilities* caps); @@ -2881,7 +2881,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryMultiViewCapabilities(). */ - PalResult PAL_CALL (*queryMultiViewCapabilities)( + PalResult (PAL_CALL *queryMultiViewCapabilities)( PalDevice* device, PalMultiViewCapabilities* caps); @@ -2891,7 +2891,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryMultiViewportCapabilities(). */ - PalResult PAL_CALL (*queryMultiViewportCapabilities)( + PalResult (PAL_CALL *queryMultiViewportCapabilities)( PalDevice* device, PalMultiViewportCapabilities* caps); @@ -2901,7 +2901,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryDepthStencilCapabilities(). */ - PalResult PAL_CALL (*queryDepthStencilCapabilities)( + PalResult (PAL_CALL *queryDepthStencilCapabilities)( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -2911,7 +2911,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryFragmentShadingRateCapabilities(). */ - PalResult PAL_CALL (*queryFragmentShadingRateCapabilities)( + PalResult (PAL_CALL *queryFragmentShadingRateCapabilities)( PalDevice* device, PalFragmentShadingRateCapabilities* caps); @@ -2921,7 +2921,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryMeshShaderCapabilities(). */ - PalResult PAL_CALL (*queryMeshShaderCapabilities)( + PalResult (PAL_CALL *queryMeshShaderCapabilities)( PalDevice* device, PalMeshShaderCapabilities* caps); @@ -2931,7 +2931,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryRayTracingCapabilities(). */ - PalResult PAL_CALL (*queryRayTracingCapabilities)( + PalResult (PAL_CALL *queryRayTracingCapabilities)( PalDevice* device, PalRayTracingCapabilities* caps); @@ -2941,7 +2941,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryDescriptorIndexingCapabilities(). */ - PalResult PAL_CALL (*queryDescriptorIndexingCapabilities)( + PalResult (PAL_CALL *queryDescriptorIndexingCapabilities)( PalDevice* device, PalDescriptorIndexingCapabilities* caps); @@ -2950,7 +2950,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateQueue(). */ - PalResult PAL_CALL (*createQueue)( + PalResult (PAL_CALL *createQueue)( PalDevice* device, PalQueueType type, PalQueue** outQueue); @@ -2960,14 +2960,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyQueue(). */ - void PAL_CALL (*destroyQueue)(PalQueue* queue); + void (PAL_CALL *destroyQueue)(PalQueue* queue); /** * Backend implementation of ::palCanQueuePresent. * * Must obey the rules and semantics documented in palCanQueuePresent(). */ - bool PAL_CALL (*canQueuePresent)( + bool (PAL_CALL *canQueuePresent)( PalQueue* queue, PalSurface* surface); @@ -2976,14 +2976,14 @@ typedef struct { * * Must obey the rules and semantics documented in palWaitQueue(). */ - PalResult PAL_CALL (*waitQueue)(PalQueue* queue); + PalResult (PAL_CALL *waitQueue)(PalQueue* queue); /** * Backend implementation of ::palEnumerateFormats. * * Must obey the rules and semantics documented in palEnumerateFormats(). */ - PalResult PAL_CALL (*enumerateFormats)( + PalResult (PAL_CALL *enumerateFormats)( PalAdapter* adapter, Int32* count, PalFormatInfo* outFormats); @@ -2993,7 +2993,7 @@ typedef struct { * * Must obey the rules and semantics documented in palIsFormatSupported(). */ - bool PAL_CALL (*isFormatSupported)( + bool (PAL_CALL *isFormatSupported)( PalAdapter* adapter, PalFormat format); @@ -3002,7 +3002,7 @@ typedef struct { * * Must obey the rules and semantics documented in palQueryFormatImageUsages(). */ - PalImageUsages PAL_CALL (*queryFormatImageUsages)( + PalImageUsages (PAL_CALL *queryFormatImageUsages)( PalAdapter* adapter, PalFormat format); @@ -3011,7 +3011,7 @@ typedef struct { * * Must obey the rules and semantics documented in palQueryFormatSampleCount(). */ - PalSampleCount PAL_CALL (*queryFormatSampleCount)( + PalSampleCount (PAL_CALL *queryFormatSampleCount)( PalAdapter* adapter, PalFormat format); @@ -3020,7 +3020,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateImage(). */ - PalResult PAL_CALL (*createImage)( + PalResult (PAL_CALL *createImage)( PalDevice* device, const PalImageCreateInfo* info, PalImage** outImage); @@ -3030,14 +3030,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyImage(). */ - void PAL_CALL (*destroyImage)(PalImage* image); + void (PAL_CALL *destroyImage)(PalImage* image); /** * Backend implementation of ::palGetImageInfo. * * Must obey the rules and semantics documented in palGetImageInfo(). */ - PalResult PAL_CALL (*getImageInfo)( + PalResult (PAL_CALL *getImageInfo)( PalImage* image, PalImageInfo* info); @@ -3046,7 +3046,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetImageMemoryRequirements(). */ - PalResult PAL_CALL (*getImageMemoryRequirements)( + PalResult (PAL_CALL *getImageMemoryRequirements)( PalImage* image, PalMemoryRequirements* requirements); @@ -3055,7 +3055,7 @@ typedef struct { * * Must obey the rules and semantics documented in palBindImageMemory(). */ - PalResult PAL_CALL (*bindImageMemory)( + PalResult (PAL_CALL *bindImageMemory)( PalImage* image, PalMemory* memory, Uint64 offset); @@ -3065,7 +3065,7 @@ typedef struct { * * Must obey the rules and semantics documented in palMapImageMemory(). */ - PalResult PAL_CALL (*mapImageMemory)( + PalResult (PAL_CALL *mapImageMemory)( PalImage* image, Uint64 offset, Uint64 size, @@ -3076,14 +3076,14 @@ typedef struct { * * Must obey the rules and semantics documented in palUnmapImageMemory(). */ - void PAL_CALL (*unmapImageMemory)(PalImage* image); + void (PAL_CALL *unmapImageMemory)(PalImage* image); /** * Backend implementation of ::palCreateImageView. * * Must obey the rules and semantics documented in palCreateImageView(). */ - PalResult PAL_CALL (*createImageView)( + PalResult (PAL_CALL *createImageView)( PalDevice* device, PalImage* image, const PalImageViewCreateInfo* info, @@ -3094,14 +3094,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyImageView(). */ - void PAL_CALL (*destroyImageView)(PalImageView* imageView); + void (PAL_CALL *destroyImageView)(PalImageView* imageView); /** * Backend implementation of ::palCreateSampler. * * Must obey the rules and semantics documented in palCreateSampler(). */ - PalResult PAL_CALL (*createSampler)( + PalResult (PAL_CALL *createSampler)( PalDevice* device, const PalSamplerCreateInfo* info, PalSampler** outSampler); @@ -3111,14 +3111,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroySampler(). */ - void PAL_CALL (*destroySampler)(PalSampler* sampler); + void (PAL_CALL *destroySampler)(PalSampler* sampler); /** * Backend implementation of ::palCreateSurface. * * Must obey the rules and semantics documented in palCreateSurface(). */ - PalResult PAL_CALL (*createSurface)( + PalResult (PAL_CALL *createSurface)( PalDevice* device, PalGraphicsWindow* window, PalSurface** outSurface); @@ -3128,14 +3128,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroySurface(). */ - void PAL_CALL (*destroySurface)(PalSurface* surface); + void (PAL_CALL *destroySurface)(PalSurface* surface); /** * Backend implementation of ::palGetSurfaceCapabilities. * * Must obey the rules and semantics documented in palGetSurfaceCapabilities(). */ - PalResult PAL_CALL (*getSurfaceCapabilities)( + PalResult (PAL_CALL *getSurfaceCapabilities)( PalDevice* device, PalSurface* surface, PalSurfaceCapabilities* caps); @@ -3145,7 +3145,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateSwapchain(). */ - PalResult PAL_CALL (*createSwapchain)( + PalResult (PAL_CALL *createSwapchain)( PalDevice* device, PalQueue* queue, PalSurface* surface, @@ -3157,14 +3157,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroySwapchain(). */ - void PAL_CALL (*destroySwapchain)(PalSwapchain* swapchain); + void (PAL_CALL *destroySwapchain)(PalSwapchain* swapchain); /** * Backend implementation of ::palGetSwapchainImage. * * Must obey the rules and semantics documented in palGetSwapchainImage(). */ - PalImage* PAL_CALL (*getSwapchainImage)( + PalImage* (PAL_CALL *getSwapchainImage)( PalSwapchain* swapchain, Int32 index); @@ -3173,7 +3173,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetNextSwapchainImage(). */ - PalResult PAL_CALL (*getNextSwapchainImage)( + PalResult (PAL_CALL *getNextSwapchainImage)( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, Uint32* outIndex); @@ -3183,7 +3183,7 @@ typedef struct { * * Must obey the rules and semantics documented in palPresentSwapchain(). */ - PalResult PAL_CALL (*presentSwapchain)( + PalResult (PAL_CALL *presentSwapchain)( PalSwapchain* swapchain, PalSwapchainPresentInfo* info); @@ -3192,7 +3192,7 @@ typedef struct { * * Must obey the rules and semantics documented in palResizeSwapchain(). */ - PalResult PAL_CALL (*resizeSwapchain)( + PalResult (PAL_CALL *resizeSwapchain)( PalSwapchain* swapchain, Uint32 newWidth, Uint32 newHeight); @@ -3202,7 +3202,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateShader(). */ - PalResult PAL_CALL (*createShader)( + PalResult (PAL_CALL *createShader)( PalDevice* device, const PalShaderCreateInfo* info, PalShader** outShader); @@ -3212,14 +3212,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyShader(). */ - void PAL_CALL (*destroyShader)(PalShader* shader); + void (PAL_CALL *destroyShader)(PalShader* shader); /** * Backend implementation of ::palCreateFence. * * Must obey the rules and semantics documented in palCreateFence(). */ - PalResult PAL_CALL (*createFence)( + PalResult (PAL_CALL *createFence)( PalDevice* device, bool signaled, PalFence** outFence); @@ -3229,14 +3229,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyFence(). */ - void PAL_CALL (*destroyFence)(PalFence* fence); + void (PAL_CALL *destroyFence)(PalFence* fence); /** * Backend implementation of ::palWaitFence. * * Must obey the rules and semantics documented in palWaitFence(). */ - PalResult PAL_CALL (*waitFence)( + PalResult (PAL_CALL *waitFence)( PalFence* fence, Uint64 timeout); @@ -3245,21 +3245,21 @@ typedef struct { * * Must obey the rules and semantics documented in palResetFence(). */ - PalResult PAL_CALL (*resetFence)(PalFence* fence); + PalResult (PAL_CALL *resetFence)(PalFence* fence); /** * Backend implementation of ::palIsFenceSignaled. * * Must obey the rules and semantics documented in palIsFenceSignaled(). */ - bool PAL_CALL (*isFenceSignaled)(PalFence* fence); + bool (PAL_CALL *isFenceSignaled)(PalFence* fence); /** * Backend implementation of ::palCreateSemaphore. * * Must obey the rules and semantics documented in palCreateSemaphore(). */ - PalResult PAL_CALL (*createSemaphore)( + PalResult (PAL_CALL *createSemaphore)( PalDevice* device, bool enableTimeline, PalSemaphore** outSemaphore); @@ -3269,14 +3269,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroySemaphore(). */ - void PAL_CALL (*destroySemaphore)(PalSemaphore* semaphore); + void (PAL_CALL *destroySemaphore)(PalSemaphore* semaphore); /** * Backend implementation of ::palWaitSemaphore. * * Must obey the rules and semantics documented in palWaitSemaphore(). */ - PalResult PAL_CALL (*waitSemaphore)( + PalResult (PAL_CALL *waitSemaphore)( PalSemaphore* semaphore, Uint64 value, Uint64 timeout); @@ -3286,7 +3286,7 @@ typedef struct { * * Must obey the rules and semantics documented in palSignalSemaphore(). */ - PalResult PAL_CALL (*signalSemaphore)( + PalResult (PAL_CALL *signalSemaphore)( PalSemaphore* semaphore, PalQueue* queue, Uint64 value); @@ -3296,7 +3296,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetSemaphoreValue(). */ - PalResult PAL_CALL (*getSemaphoreValue)( + PalResult (PAL_CALL *getSemaphoreValue)( PalSemaphore* semaphore, Uint64* outValue); @@ -3305,7 +3305,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateCommandPool(). */ - PalResult PAL_CALL (*createCommandPool)( + PalResult (PAL_CALL *createCommandPool)( PalDevice* device, PalQueue* queue, PalCommandPool** outPool); @@ -3315,21 +3315,21 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyCommandPool(). */ - void PAL_CALL (*destroyCommandPool)(PalCommandPool* pool); + void (PAL_CALL *destroyCommandPool)(PalCommandPool* pool); /** * Backend implementation of ::palResetCommandPool. * * Must obey the rules and semantics documented in palResetCommandPool(). */ - PalResult PAL_CALL (*resetCommandPool)(PalCommandPool* pool); + PalResult (PAL_CALL *resetCommandPool)(PalCommandPool* pool); /** * Backend implementation of ::palAllocateCommandBuffer. * * Must obey the rules and semantics documented in palAllocateCommandBuffer(). */ - PalResult PAL_CALL (*allocateCommandBuffer)( + PalResult (PAL_CALL *allocateCommandBuffer)( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, @@ -3340,21 +3340,21 @@ typedef struct { * * Must obey the rules and semantics documented in palFreeCommandBuffer(). */ - void PAL_CALL (*freeCommandBuffer)(PalCommandBuffer* cmdBuffer); + void (PAL_CALL *freeCommandBuffer)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palResetCommandBuffer. * * Must obey the rules and semantics documented in palResetCommandBuffer(). */ - PalResult PAL_CALL (*resetCommandBuffer)(PalCommandBuffer* cmdBuffer); + PalResult (PAL_CALL *resetCommandBuffer)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palSubmitCommandBuffer. * * Must obey the rules and semantics documented in palSubmitCommandBuffer(). */ - PalResult PAL_CALL (*submitCommandBuffer)( + PalResult (PAL_CALL *submitCommandBuffer)( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -3363,7 +3363,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBegin(). */ - PalResult PAL_CALL (*cmdBegin)( + PalResult (PAL_CALL *cmdBegin)( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); @@ -3372,14 +3372,14 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdEnd(). */ - PalResult PAL_CALL (*cmdEnd)(PalCommandBuffer* cmdBuffer); + PalResult (PAL_CALL *cmdEnd)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palCmdExecuteCommandBuffer. * * Must obey the rules and semantics documented in palCmdExecuteCommandBuffer(). */ - PalResult PAL_CALL (*cmdExecuteCommandBuffer)( + PalResult (PAL_CALL *cmdExecuteCommandBuffer)( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -3388,7 +3388,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetFragmentShadingRate(). */ - PalResult PAL_CALL (*cmdSetFragmentShadingRate)( + PalResult (PAL_CALL *cmdSetFragmentShadingRate)( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state); @@ -3397,7 +3397,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawMeshTasks(). */ - PalResult PAL_CALL (*cmdDrawMeshTasks)( + PalResult (PAL_CALL *cmdDrawMeshTasks)( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, @@ -3408,7 +3408,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawMeshTasksIndirect(). */ - PalResult PAL_CALL (*cmdDrawMeshTasksIndirect)( + PalResult (PAL_CALL *cmdDrawMeshTasksIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint32 drawCount); @@ -3418,7 +3418,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawMeshTasksIndirectCount(). */ - PalResult PAL_CALL (*cmdDrawMeshTasksIndirectCount)( + PalResult (PAL_CALL *cmdDrawMeshTasksIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -3429,7 +3429,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBuildAccelerationStructure(). */ - PalResult PAL_CALL (*cmdBuildAccelerationStructure)( + PalResult (PAL_CALL *cmdBuildAccelerationStructure)( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); @@ -3438,7 +3438,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBeginRendering(). */ - PalResult PAL_CALL (*cmdBeginRendering)( + PalResult (PAL_CALL *cmdBeginRendering)( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info); @@ -3447,14 +3447,14 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdEndRendering(). */ - PalResult PAL_CALL (*cmdEndRendering)(PalCommandBuffer* cmdBuffer); + PalResult (PAL_CALL *cmdEndRendering)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palCmdCopyBuffer. * * Must obey the rules and semantics documented in palCmdCopyBuffer(). */ - PalResult PAL_CALL (*cmdCopyBuffer)( + PalResult (PAL_CALL *cmdCopyBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -3465,7 +3465,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdCopyBufferToImage(). */ - PalResult PAL_CALL (*cmdCopyBufferToImage)( + PalResult (PAL_CALL *cmdCopyBufferToImage)( PalCommandBuffer* cmdBuffer, PalImage* dstImage, PalBuffer* srcBuffer, @@ -3476,7 +3476,7 @@ typedef struct { * * Must obey the rules and semantics documented in cmdCopyImage(). */ - PalResult PAL_CALL (*cmdCopyImage)( + PalResult (PAL_CALL *cmdCopyImage)( PalCommandBuffer* cmdBuffer, PalImage* dst, PalImage* src, @@ -3487,7 +3487,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdCopyImageToBuffer(). */ - PalResult PAL_CALL (*cmdCopyImageToBuffer)( + PalResult (PAL_CALL *cmdCopyImageToBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, @@ -3498,7 +3498,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindPipeline(). */ - PalResult PAL_CALL (*cmdBindPipeline)( + PalResult (PAL_CALL *cmdBindPipeline)( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline); @@ -3507,7 +3507,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetViewport(). */ - PalResult PAL_CALL (*cmdSetViewport)( + PalResult (PAL_CALL *cmdSetViewport)( PalCommandBuffer* cmdBuffer, Uint32 count, PalViewport* viewports); @@ -3517,7 +3517,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetScissors(). */ - PalResult PAL_CALL (*cmdSetScissors)( + PalResult (PAL_CALL *cmdSetScissors)( PalCommandBuffer* cmdBuffer, Uint32 count, PalRect2D* scissors); @@ -3527,7 +3527,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindVertexBuffers(). */ - PalResult PAL_CALL (*cmdBindVertexBuffers)( + PalResult (PAL_CALL *cmdBindVertexBuffers)( PalCommandBuffer* cmdBuffer, Uint32 firstSlot, Uint32 count, @@ -3539,7 +3539,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindIndexBuffer(). */ - PalResult PAL_CALL (*cmdBindIndexBuffer)( + PalResult (PAL_CALL *cmdBindIndexBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint64 offset, @@ -3550,7 +3550,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDraw(). */ - PalResult PAL_CALL (*cmdDraw)( + PalResult (PAL_CALL *cmdDraw)( PalCommandBuffer* cmdBuffer, Uint32 vertexCount, Uint32 instanceCount, @@ -3562,7 +3562,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndirect(). */ - PalResult PAL_CALL (*cmdDrawIndirect)( + PalResult (PAL_CALL *cmdDrawIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint32 count); @@ -3572,7 +3572,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndirectCount(). */ - PalResult PAL_CALL (*cmdDrawIndirectCount)( + PalResult (PAL_CALL *cmdDrawIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -3583,7 +3583,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndexed(). */ - PalResult PAL_CALL (*cmdDrawIndexed)( + PalResult (PAL_CALL *cmdDrawIndexed)( PalCommandBuffer* cmdBuffer, Uint32 indexCount, Uint32 instanceCount, @@ -3596,7 +3596,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndexedIndirect(). */ - PalResult PAL_CALL (*cmdDrawIndexedIndirect)( + PalResult (PAL_CALL *cmdDrawIndexedIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, Uint32 count); @@ -3606,7 +3606,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndexedIndirectCount(). */ - PalResult PAL_CALL (*cmdDrawIndexedIndirectCount)( + PalResult (PAL_CALL *cmdDrawIndexedIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -3617,7 +3617,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdAccelerationStructureBarrier(). */ - PalResult PAL_CALL (*cmdAccelerationStructureBarrier)( + PalResult (PAL_CALL *cmdAccelerationStructureBarrier)( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, PalUsageStateInfo* oldUsageStateInfo, @@ -3628,7 +3628,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdImageBarrier(). */ - PalResult PAL_CALL (*cmdImageBarrier)( + PalResult (PAL_CALL *cmdImageBarrier)( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, @@ -3640,7 +3640,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBufferBarrier(). */ - PalResult PAL_CALL (*cmdBufferBarrier)( + PalResult (PAL_CALL *cmdBufferBarrier)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageStateInfo* oldUsageStateInfo, @@ -3651,7 +3651,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDispatch(). */ - PalResult PAL_CALL (*cmdDispatch)( + PalResult (PAL_CALL *cmdDispatch)( PalCommandBuffer* cmdBuffer, Uint32 groupCountX, Uint32 groupCountY, @@ -3662,7 +3662,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDispatchBase(). */ - PalResult PAL_CALL (*cmdDispatchBase)( + PalResult (PAL_CALL *cmdDispatchBase)( PalCommandBuffer* cmdBuffer, Uint32 baseGroupX, Uint32 baseGroupY, @@ -3676,7 +3676,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDispatchIndirect(). */ - PalResult PAL_CALL (*cmdDispatchIndirect)( + PalResult (PAL_CALL *cmdDispatchIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer); @@ -3685,7 +3685,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdTraceRays(). */ - PalResult PAL_CALL (*cmdTraceRays)( + PalResult (PAL_CALL *cmdTraceRays)( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, Uint32 raygenIndex, @@ -3698,7 +3698,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdTraceRaysIndirect(). */ - PalResult PAL_CALL (*cmdTraceRaysIndirect)( + PalResult (PAL_CALL *cmdTraceRaysIndirect)( PalCommandBuffer* cmdBuffer, Uint32 raygenIndex, PalShaderBindingTable* sbt, @@ -3709,7 +3709,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindDescriptorSet(). */ - PalResult PAL_CALL (*cmdBindDescriptorSet)( + PalResult (PAL_CALL *cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, Uint32 setIndex, PalDescriptorSet* set); @@ -3719,7 +3719,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdPushConstants(). */ - PalResult PAL_CALL (*cmdPushConstants)( + PalResult (PAL_CALL *cmdPushConstants)( PalCommandBuffer* cmdBuffer, Uint32 shaderStageCount, PalShaderStage* shaderStages, @@ -3732,7 +3732,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetCullMode(). */ - PalResult PAL_CALL (*cmdSetCullMode)( + PalResult (PAL_CALL *cmdSetCullMode)( PalCommandBuffer* cmdBuffer, PalCullMode cullMode); @@ -3741,7 +3741,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetFrontFace(). */ - PalResult PAL_CALL (*cmdSetFrontFace)( + PalResult (PAL_CALL *cmdSetFrontFace)( PalCommandBuffer* cmdBuffer, PalFrontFace frontFace); @@ -3750,7 +3750,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetPrimitiveTopology(). */ - PalResult PAL_CALL (*cmdSetPrimitiveTopology)( + PalResult (PAL_CALL *cmdSetPrimitiveTopology)( PalCommandBuffer* cmdBuffer, PalPrimitiveTopology topology); @@ -3759,7 +3759,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetDepthTestEnable(). */ - PalResult PAL_CALL (*cmdSetDepthTestEnable)( + PalResult (PAL_CALL *cmdSetDepthTestEnable)( PalCommandBuffer* cmdBuffer, bool enable); @@ -3768,7 +3768,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetDepthWriteEnable(). */ - PalResult PAL_CALL (*cmdSetDepthWriteEnable)( + PalResult (PAL_CALL *cmdSetDepthWriteEnable)( PalCommandBuffer* cmdBuffer, bool enable); @@ -3777,7 +3777,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetStencilOp(). */ - PalResult PAL_CALL (*cmdSetStencilOp)( + PalResult (PAL_CALL *cmdSetStencilOp)( PalCommandBuffer* cmdBuffer, PalStencilFaceFlags faceMask, PalStencilOp failOp, @@ -3790,7 +3790,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateAccelerationstructure(). */ - PalResult PAL_CALL (*createAccelerationstructure)( + PalResult (PAL_CALL *createAccelerationstructure)( PalDevice* device, const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs); @@ -3800,14 +3800,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyAccelerationstructure(). */ - void PAL_CALL (*destroyAccelerationstructure)(PalAccelerationStructure* as); + void (PAL_CALL *destroyAccelerationstructure)(PalAccelerationStructure* as); /** * Backend implementation of ::palGetAccelerationStructureBuildSize. * * Must obey the rules and semantics documented in palGetAccelerationStructureBuildSize(). */ - PalResult PAL_CALL (*getAccelerationStructureBuildSize)( + PalResult (PAL_CALL *getAccelerationStructureBuildSize)( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); @@ -3817,7 +3817,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateBuffer(). */ - PalResult PAL_CALL (*createBuffer)( + PalResult (PAL_CALL *createBuffer)( PalDevice* device, const PalBufferCreateInfo* info, PalBuffer** outBuffer); @@ -3827,14 +3827,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyBuffer(). */ - void PAL_CALL (*destroyBuffer)(PalBuffer* buffer); + void (PAL_CALL *destroyBuffer)(PalBuffer* buffer); /** * Backend implementation of ::palGetBufferMemoryRequirements. * * Must obey the rules and semantics documented in palGetBufferMemoryRequirements(). */ - PalResult PAL_CALL (*getBufferMemoryRequirements)( + PalResult (PAL_CALL *getBufferMemoryRequirements)( PalBuffer* buffer, PalMemoryRequirements* requirements); @@ -3843,7 +3843,7 @@ typedef struct { * * Must obey the rules and semantics documented in palComputeInstanceBufferRequirements(). */ - PalResult PAL_CALL (*computeInstanceBufferRequirements)( + PalResult (PAL_CALL *computeInstanceBufferRequirements)( PalDevice* device, Uint32 instanceCount, Uint64* outSize); @@ -3853,7 +3853,7 @@ typedef struct { * * Must obey the rules and semantics documented in palComputeImageCopyStagingBufferRequirements(). */ - PalResult PAL_CALL (*computeImageCopyStagingBufferRequirements)( + PalResult (PAL_CALL *computeImageCopyStagingBufferRequirements)( PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, @@ -3866,7 +3866,7 @@ typedef struct { * * Must obey the rules and semantics documented in palWriteToInstanceBuffer(). */ - PalResult PAL_CALL (*writeToInstanceBuffer)( + PalResult (PAL_CALL *writeToInstanceBuffer)( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, @@ -3877,7 +3877,7 @@ typedef struct { * * Must obey the rules and semantics documented in palWriteToImageCopyStagingBuffer(). */ - PalResult PAL_CALL (*writeToImageCopyStagingBuffer)( + PalResult (PAL_CALL *writeToImageCopyStagingBuffer)( PalDevice* device, void* ptr, void* srcData, @@ -3889,7 +3889,7 @@ typedef struct { * * Must obey the rules and semantics documented in palBindBufferMemory(). */ - PalResult PAL_CALL (*bindBufferMemory)( + PalResult (PAL_CALL *bindBufferMemory)( PalBuffer* buffer, PalMemory* memory, Uint64 offset); @@ -3899,7 +3899,7 @@ typedef struct { * * Must obey the rules and semantics documented in palMapBufferMemory(). */ - PalResult PAL_CALL (*mapBufferMemory)( + PalResult (PAL_CALL *mapBufferMemory)( PalBuffer* buffer, Uint64 offset, Uint64 size, @@ -3910,21 +3910,21 @@ typedef struct { * * Must obey the rules and semantics documented in palUnmapBufferMemory(). */ - void PAL_CALL (*unmapBufferMemory)(PalBuffer* buffer); + void (PAL_CALL *unmapBufferMemory)(PalBuffer* buffer); /** * Backend implementation of ::palGetBufferDeviceAddress. * * Must obey the rules and semantics documented in palGetBufferDeviceAddress(). */ - PalDeviceAddress PAL_CALL (*getBufferDeviceAddress)(PalBuffer* buffer); + PalDeviceAddress (PAL_CALL *getBufferDeviceAddress)(PalBuffer* buffer); /** * Backend implementation of ::palCreateDescriptorSetLayout. * * Must obey the rules and semantics documented in palCreateDescriptorSetLayout(). */ - PalResult PAL_CALL (*createDescriptorSetLayout)( + PalResult (PAL_CALL *createDescriptorSetLayout)( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout); @@ -3934,14 +3934,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyDescriptorSetLayout(). */ - void PAL_CALL (*destroyDescriptorSetLayout)(PalDescriptorSetLayout* layout); + void (PAL_CALL *destroyDescriptorSetLayout)(PalDescriptorSetLayout* layout); /** * Backend implementation of ::palCreateDescriptorPool. * * Must obey the rules and semantics documented in palCreateDescriptorPool(). */ - PalResult PAL_CALL (*createDescriptorPool)( + PalResult (PAL_CALL *createDescriptorPool)( PalDevice* device, const PalDescriptorPoolCreateInfo* info, PalDescriptorPool** outPool); @@ -3951,21 +3951,21 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyDescriptorPool(). */ - void PAL_CALL (*destroyDescriptorPool)(PalDescriptorPool* pool); + void (PAL_CALL *destroyDescriptorPool)(PalDescriptorPool* pool); /** * Backend implementation of ::palResetDescriptorPool. * * Must obey the rules and semantics documented in palResetDescriptorPool(). */ - PalResult PAL_CALL (*resetDescriptorPool)(PalDescriptorPool* pool); + PalResult (PAL_CALL *resetDescriptorPool)(PalDescriptorPool* pool); /** * Backend implementation of ::palAllocateDescriptorSet. * * Must obey the rules and semantics documented in palAllocateDescriptorSet(). */ - PalResult PAL_CALL (*allocateDescriptorSet)( + PalResult (PAL_CALL *allocateDescriptorSet)( PalDevice* device, PalDescriptorPool* pool, PalDescriptorSetLayout* layout, @@ -3976,7 +3976,7 @@ typedef struct { * * Must obey the rules and semantics documented in palUpdateDescriptorSet(). */ - PalResult PAL_CALL (*updateDescriptorSet)( + PalResult (PAL_CALL *updateDescriptorSet)( PalDevice* device, Uint32 count, PalDescriptorSetWriteInfo* infos); @@ -3986,7 +3986,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreatePipelineLayout(). */ - PalResult PAL_CALL (*createPipelineLayout)( + PalResult (PAL_CALL *createPipelineLayout)( PalDevice* device, const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout); @@ -3996,14 +3996,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyPipelineLayout(). */ - void PAL_CALL (*destroyPipelineLayout)(PalPipelineLayout* layout); + void (PAL_CALL *destroyPipelineLayout)(PalPipelineLayout* layout); /** * Backend implementation of ::palCreateGraphicsPipeline. * * Must obey the rules and semantics documented in palCreateGraphicsPipeline(). */ - PalResult PAL_CALL (*createGraphicsPipeline)( + PalResult (PAL_CALL *createGraphicsPipeline)( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline); @@ -4013,7 +4013,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateComputePipeline(). */ - PalResult PAL_CALL (*createComputePipeline)( + PalResult (PAL_CALL *createComputePipeline)( PalDevice* device, const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline); @@ -4023,7 +4023,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateRayTracingPipeline(). */ - PalResult PAL_CALL (*createRayTracingPipeline)( + PalResult (PAL_CALL *createRayTracingPipeline)( PalDevice* device, const PalRayTracingPipelineCreateInfo* info, PalPipeline** outPipeline); @@ -4033,14 +4033,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyPipeline(). */ - void PAL_CALL (*destroyPipeline)(PalPipeline* pipeline); + void (PAL_CALL *destroyPipeline)(PalPipeline* pipeline); /** * Backend implementation of ::palCreateShaderBindingTable. * * Must obey the rules and semantics documented in palCreateShaderBindingTable(). */ - PalResult PAL_CALL (*createShaderBindingTable)( + PalResult (PAL_CALL *createShaderBindingTable)( PalDevice* device, const PalShaderBindingTableCreateInfo* info, PalShaderBindingTable** outSbt); @@ -4050,14 +4050,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyShaderBindingTable(). */ - void PAL_CALL (*destroyShaderBindingTable)(PalShaderBindingTable* sbt); + void (PAL_CALL *destroyShaderBindingTable)(PalShaderBindingTable* sbt); /** * Backend implementation of ::palUpdateShaderBindingTable. * * Must obey the rules and semantics documented in palUpdateShaderBindingTable(). */ - PalResult PAL_CALL (*updateShaderBindingTable)( + PalResult (PAL_CALL *updateShaderBindingTable)( PalShaderBindingTable* sbt, Uint32 count, PalShaderBindingTableRecordInfo* infos); diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index de81785f..48c5ab77 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -33,6 +33,59 @@ freely, subject to the following restrictions: #include "pal_event.h" +/** + * @enum PalVideoFeatures64 + * @brief Extended Video system features. + * + * All extended video features follow the format `PAL_VIDEO_FEATURE64_**` for + * consistency and API use. + * + * @since 1.3 + * @ingroup pal_video + */ +typedef Uint64 PalVideoFeatures64; + +#define PAL_VIDEO_FEATURE64_HIGH_DPI PAL_BIT64(0) +#define PAL_VIDEO_FEATURE64_MONITOR_SET_ORIENTATION PAL_BIT64(1) +#define PAL_VIDEO_FEATURE64_MONITOR_GET_ORIENTATION PAL_BIT64(2) +#define PAL_VIDEO_FEATURE64_BORDERLESS_WINDOW PAL_BIT64(3) +#define PAL_VIDEO_FEATURE64_TRANSPARENT_WINDOW PAL_BIT64(4) +#define PAL_VIDEO_FEATURE64_TOOL_WINDOW PAL_BIT64(5) +#define PAL_VIDEO_FEATURE64_MONITOR_SET_MODE PAL_BIT64(6) +#define PAL_VIDEO_FEATURE64_MONITOR_GET_MODE PAL_BIT64(7) +#define PAL_VIDEO_FEATURE64_MULTI_MONITORS PAL_BIT64(8) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_SIZE PAL_BIT64(9) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_SIZE PAL_BIT64(10) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_POS PAL_BIT64(11) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_POS PAL_BIT64(12) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_STATE PAL_BIT64(13) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_STATE PAL_BIT64(14) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_VISIBILITY PAL_BIT64(15) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_VISIBILITY PAL_BIT64(16) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_TITLE PAL_BIT64(17) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_TITLE PAL_BIT64(18) +#define PAL_VIDEO_FEATURE64_NO_MAXIMIZEBOX PAL_BIT64(19) +#define PAL_VIDEO_FEATURE64_NO_MINIMIZEBOX PAL_BIT64(20) +#define PAL_VIDEO_FEATURE64_CLIP_CURSOR PAL_BIT64(21) +#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_CAPTION PAL_BIT64(22) +#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_TRAY PAL_BIT64(23) +#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_INTERVAL PAL_BIT64(24) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_INPUT_FOCUS PAL_BIT64(25) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_INPUT_FOCUS PAL_BIT64(26) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_STYLE PAL_BIT64(27) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_STYLE PAL_BIT64(28) +#define PAL_VIDEO_FEATURE64_CURSOR_SET_POS PAL_BIT64(29) +#define PAL_VIDEO_FEATURE64_CURSOR_GET_POS PAL_BIT64(30) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_ICON PAL_BIT64(31) +#define PAL_VIDEO_FEATURE64_TOPMOST_WINDOW PAL_BIT64(32) +#define PAL_VIDEO_FEATURE64_DECORATED_WINDOW PAL_BIT64(33) +#define PAL_VIDEO_FEATURE64_CURSOR_SET_VISIBILITY PAL_BIT64(34) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_MONITOR PAL_BIT64(35) +#define PAL_VIDEO_FEATURE64_MONITOR_GET_PRIMARY PAL_BIT64(36) +#define PAL_VIDEO_FEATURE64_FOREIGN_WINDOWS PAL_BIT64(37) +#define PAL_VIDEO_FEATURE64_MONITOR_VALIDATE_MODE PAL_BIT64(38) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR PAL_BIT64(39) + /** * @struct PalMonitor * @brief Opaque handle to a monitor. @@ -114,59 +167,6 @@ typedef enum { PAL_VIDEO_FEATURE_WINDOW_SET_ICON = PAL_BIT(31) } PalVideoFeatures; -/** - * @enum PalVideoFeatures64 - * @brief Extended Video system features. - * - * All extended video features follow the format `PAL_VIDEO_FEATURE64_**` for - * consistency and API use. - * - * @since 1.3 - * @ingroup pal_video - */ -typedef enum { - PAL_VIDEO_FEATURE64_HIGH_DPI = PAL_BIT64(0), - PAL_VIDEO_FEATURE64_MONITOR_SET_ORIENTATION = PAL_BIT64(1), - PAL_VIDEO_FEATURE64_MONITOR_GET_ORIENTATION = PAL_BIT64(2), - PAL_VIDEO_FEATURE64_BORDERLESS_WINDOW = PAL_BIT64(3), - PAL_VIDEO_FEATURE64_TRANSPARENT_WINDOW = PAL_BIT64(4), - PAL_VIDEO_FEATURE64_TOOL_WINDOW = PAL_BIT64(5), - PAL_VIDEO_FEATURE64_MONITOR_SET_MODE = PAL_BIT64(6), - PAL_VIDEO_FEATURE64_MONITOR_GET_MODE = PAL_BIT64(7), - PAL_VIDEO_FEATURE64_MULTI_MONITORS = PAL_BIT64(8), - PAL_VIDEO_FEATURE64_WINDOW_SET_SIZE = PAL_BIT64(9), - PAL_VIDEO_FEATURE64_WINDOW_GET_SIZE = PAL_BIT64(10), - PAL_VIDEO_FEATURE64_WINDOW_SET_POS = PAL_BIT64(11), - PAL_VIDEO_FEATURE64_WINDOW_GET_POS = PAL_BIT64(12), - PAL_VIDEO_FEATURE64_WINDOW_SET_STATE = PAL_BIT64(13), - PAL_VIDEO_FEATURE64_WINDOW_GET_STATE = PAL_BIT64(14), - PAL_VIDEO_FEATURE64_WINDOW_SET_VISIBILITY = PAL_BIT64(15), - PAL_VIDEO_FEATURE64_WINDOW_GET_VISIBILITY = PAL_BIT64(16), - PAL_VIDEO_FEATURE64_WINDOW_SET_TITLE = PAL_BIT64(17), - PAL_VIDEO_FEATURE64_WINDOW_GET_TITLE = PAL_BIT64(18), - PAL_VIDEO_FEATURE64_NO_MAXIMIZEBOX = PAL_BIT64(19), - PAL_VIDEO_FEATURE64_NO_MINIMIZEBOX = PAL_BIT64(20), - PAL_VIDEO_FEATURE64_CLIP_CURSOR = PAL_BIT64(21), - PAL_VIDEO_FEATURE64_WINDOW_FLASH_CAPTION = PAL_BIT64(22), - PAL_VIDEO_FEATURE64_WINDOW_FLASH_TRAY = PAL_BIT64(23), - PAL_VIDEO_FEATURE64_WINDOW_FLASH_INTERVAL = PAL_BIT64(24), - PAL_VIDEO_FEATURE64_WINDOW_SET_INPUT_FOCUS = PAL_BIT64(25), - PAL_VIDEO_FEATURE64_WINDOW_GET_INPUT_FOCUS = PAL_BIT64(26), - PAL_VIDEO_FEATURE64_WINDOW_SET_STYLE = PAL_BIT64(27), - PAL_VIDEO_FEATURE64_WINDOW_GET_STYLE = PAL_BIT64(28), - PAL_VIDEO_FEATURE64_CURSOR_SET_POS = PAL_BIT64(29), - PAL_VIDEO_FEATURE64_CURSOR_GET_POS = PAL_BIT64(30), - PAL_VIDEO_FEATURE64_WINDOW_SET_ICON = PAL_BIT64(31), - PAL_VIDEO_FEATURE64_TOPMOST_WINDOW = PAL_BIT64(32), - PAL_VIDEO_FEATURE64_DECORATED_WINDOW = PAL_BIT64(33), - PAL_VIDEO_FEATURE64_CURSOR_SET_VISIBILITY = PAL_BIT64(34), - PAL_VIDEO_FEATURE64_WINDOW_GET_MONITOR = PAL_BIT64(35), - PAL_VIDEO_FEATURE64_MONITOR_GET_PRIMARY = PAL_BIT64(36), - PAL_VIDEO_FEATURE64_FOREIGN_WINDOWS = PAL_BIT64(37), - PAL_VIDEO_FEATURE64_MONITOR_VALIDATE_MODE = PAL_BIT64(38), - PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR = PAL_BIT64(39) -} PalVideoFeatures64; - /** * @enum PalOrientation * @brief Orientation types for a monitor. diff --git a/premake5.lua b/premake5.lua index 38ce9f91..e0123acd 100644 --- a/premake5.lua +++ b/premake5.lua @@ -27,8 +27,8 @@ workspace "PAL_workspace" staticruntime "off" end + multiprocessorcompile "On" configurations { "Debug", "Release" } - flags { "MultiProcessorCompile" } filter {"system:windows", "configurations:*"} architecture "x64" @@ -73,7 +73,7 @@ workspace "PAL_workspace" end end - if (_ACTION == "vs2022") then + if (_ACTION == "vs2022") or (_ACTION == "vs2026") then if (_OPTIONS["compiler"] == "clang") then toolset("clang") end @@ -82,7 +82,9 @@ workspace "PAL_workspace" "_CRT_SECURE_NO_WARNINGS" } disablewarnings { - "6387" + "6387", + "4018", + "4133" } end diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 147b19d8..93b4209f 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -29,7 +29,7 @@ freely, subject to the following restrictions: #if PAL_HAS_D3D12 -#ifdef __WIN32 +#ifdef _WIN32 #include #include #include @@ -8839,4 +8839,4 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( #endif // PAL_HAS_D3D12 -#endif // __WIN32 \ No newline at end of file +#endif // _WIN32 \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 8870890c..236274f0 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -646,7 +646,7 @@ static Vulkan s_Vk = {0}; static void* loadLibrary(const char* name) { -#ifdef __WIN32 +#ifdef _WIN32 return LoadLibraryA(name); #elif defined (__linux__) return dlopen(name, RTLD_LAZY); @@ -655,7 +655,7 @@ static void* loadLibrary(const char* name) static void freeLibrary(void* lib) { -#ifdef __WIN32 +#ifdef _WIN32 FreeLibrary((HMODULE)lib); #elif defined (__linux__) dlclose(lib); @@ -664,7 +664,7 @@ static void freeLibrary(void* lib) static void* loadProc(void* lib, const char* name) { -#ifdef __WIN32 +#ifdef _WIN32 return GetProcAddress((HMODULE)lib, name); #elif defined (__linux__) return dlsym(lib, name); @@ -5642,7 +5642,7 @@ PalResult PAL_CALL createSurfaceVk( return PAL_RESULT_OUT_OF_MEMORY; } -#ifdef __WIN32 +#ifdef _WIN32 if (!s_Vk.createWin32Surface) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -5729,7 +5729,7 @@ PalResult PAL_CALL createSurfaceVk( return PAL_RESULT_SUCCESS; } -#endif // __WIN32 +#endif // _WIN32 } void PAL_CALL destroySurfaceVk(PalSurface* surface) diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index 3a004ce5..5f82d9f0 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -25,6 +25,8 @@ freely, subject to the following restrictions: // Includes // ================================================== +#ifdef __linux__ + #define _GNU_SOURCE #define _POSIX_C_SOURCE 200112L #include "pal/pal_video.h" @@ -8276,3 +8278,5 @@ void PAL_CALL palSetPreferredInstance(void* instance) s_Video.platformInstance = instance; } } + +#endif // __linux__ diff --git a/src/video/pal_video_win32.c b/src/video/pal_video_win32.c index 9b491d10..9e7dafb1 100644 --- a/src/video/pal_video_win32.c +++ b/src/video/pal_video_win32.c @@ -25,6 +25,8 @@ freely, subject to the following restrictions: // Includes // ================================================== +#ifdef _WIN32 + #include "pal/pal_video.h" #ifndef WIN32_LEAN_AND_MEAN @@ -3050,3 +3052,5 @@ void PAL_CALL palSetPreferredInstance(void* instance) s_Video.instance = instance; } } + +#endif // _WIN32 \ No newline at end of file diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index e42aced7..517d75e3 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -101,8 +101,8 @@ bool graphicsTest() return false; } - Uint32 vramMb = info.vram / (1024.0 * 1024.0); - Uint32 sharedMemMb = info.sharedMemory / (1024.0 * 1024.0); + Uint32 vramMb = (Uint32)(info.vram / 1024 * 1024); + Uint32 sharedMemMb = (Uint32)(info.sharedMemory / 1024 * 1024); palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Backend Name: %s", info.backendName); diff --git a/tests/tests_main.c b/tests/tests_main.c index c3c21a72..16d6ef5b 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,9 +57,9 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest, "Graphics Test"); + registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS diff --git a/tests/video/native_instance_test.c b/tests/video/native_instance_test.c index 6819b0b9..fab13b5e 100644 --- a/tests/video/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -186,6 +186,7 @@ void* openDisplayX11() return s_XOpenDisplay(nullptr); #endif // __linux__ + return nullptr; } void closeDisplayX11(void* instance) @@ -245,6 +246,7 @@ void* openDisplayWayland() return display; #endif // __linux__ + return nullptr; } void closeDisplayWayland(void* instance) @@ -258,9 +260,9 @@ void closeDisplayWayland(void* instance) void* openDisplayWin32() { -#ifdef __WIN32 +#ifdef _WIN32 return GetModuleHandleW(nullptr); -#endif // __WIN32 +#endif // _WIN32 } void closeDisplayWin32(void* instance) From 428914b0eeb8ca1edf8b3b4feaa96245dcc728ef Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 28 May 2026 20:35:08 -0700 Subject: [PATCH 236/372] fix errors and warnings visual studio --- include/pal/pal_graphics.h | 2 +- pal.lua | 17 +++++-- premake5.lua | 3 +- src/graphics/pal_d3d12.c | 93 ++++++++++++++++++---------------- src/graphics/pal_graphics.c | 20 ++++---- tests/graphics/graphics_test.c | 4 +- 6 files changed, 77 insertions(+), 62 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 5975bf69..02adbf6f 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1826,7 +1826,7 @@ typedef struct { bool memoryTypes[PAL_MEMORY_TYPE_MAX]; Uint64 memoryMask; Uint64 size; - Uint32 alignment; + Uint64 alignment; } PalMemoryRequirements; /** diff --git a/pal.lua b/pal.lua index 8a40ee92..7b7adbf5 100644 --- a/pal.lua +++ b/pal.lua @@ -170,11 +170,18 @@ project "PAL" hasD3D12 = true else - if (_ACTION == "vs2022") then - local sdkDir = os.getenv("WindowsSdkDir") - local sdkVer = os.getenv("WindowsSDKVersion") - if (sdkDir and sdkVer) then - d3d12_include = path.join(sdkDir, "Include", sdkVer, "um") + if (_ACTION == "vs2022") or (_ACTION == "vs2026") then + d3d12_include = "" + local base = "C:/Program Files (x86)/Windows Kits/10/Include" + local versions = os.matchdirs(base .. "/*") + table.sort(versions) + + for i = #versions, 1, -1 do + local v = versions[i] + d3d12_include = path.join(v, "um") + if (os.isdir(d3d12_include)) then + break + end end else d3d12_include = path.join(ucrt, "include") diff --git a/premake5.lua b/premake5.lua index e0123acd..c168b6cf 100644 --- a/premake5.lua +++ b/premake5.lua @@ -84,7 +84,8 @@ workspace "PAL_workspace" disablewarnings { "6387", "4018", - "4133" + "4133", + "4101" } end diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 93b4209f..ef56c65b 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -67,10 +67,16 @@ freely, subject to the following restrictions: #define COMPUTE_PIPELINE 1221 #define RAY_TRACING_PIPELINE 1222 +#if INTPTR_MAX == INT64_MAX +#define PTR_SIZE 8 +#else +#define PTR_SIZE 4 +#endif // INTPTR_MAX + #if defined(_MSC_VER) - #define ALIGN_STREAM __declspec(align(sizeof(void*))) +#define ALIGN_STREAM __declspec(align(PTR_SIZE)) #elif defined(__GNUC__) || defined(__clang__) - #define ALIGN_STREAM __attribute__((aligned(sizeof(void*)))) +#define ALIGN_STREAM __attribute__((aligned(PTR_SIZE))) #else #define ALIGN_STREAM #endif // _MSC_VER @@ -1589,29 +1595,29 @@ static void fillSubresourceD3D12( if (rtvDesc) { if (type == PAL_IMAGE_VIEW_TYPE_1D) { rtvDesc->Texture1D.MipSlice = range->startMipLevel; - rtvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; + rtvDesc->ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D; } else if (type == PAL_IMAGE_VIEW_TYPE_1D_ARRAY) { rtvDesc->Texture1DArray.MipSlice = range->startMipLevel; rtvDesc->Texture1DArray.FirstArraySlice = range->startArrayLayer; rtvDesc->Texture1DArray.ArraySize = range->layerArrayCount; - rtvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + rtvDesc->ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY; } else if (type == PAL_IMAGE_VIEW_TYPE_2D) { rtvDesc->Texture2D.MipSlice = range->startMipLevel; - rtvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + rtvDesc->ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; } else if (type == PAL_IMAGE_VIEW_TYPE_2D_ARRAY) { rtvDesc->Texture2DArray.MipSlice = range->startMipLevel; rtvDesc->Texture2DArray.FirstArraySlice = range->startArrayLayer; rtvDesc->Texture2DArray.ArraySize = range->layerArrayCount; - rtvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + rtvDesc->ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; } else if (type == PAL_IMAGE_VIEW_TYPE_3D) { rtvDesc->Texture3D.MipSlice = range->startMipLevel; rtvDesc->Texture3D.FirstWSlice = range->startArrayLayer; rtvDesc->Texture3D.WSize = range->layerArrayCount; - rtvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; + rtvDesc->ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; } return; @@ -1624,23 +1630,23 @@ static void fillSubresourceD3D12( if (type == PAL_IMAGE_VIEW_TYPE_1D) { dsvDesc->Texture1D.MipSlice = range->startMipLevel; - dsvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; + dsvDesc->ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1D; } else if (type == PAL_IMAGE_VIEW_TYPE_1D_ARRAY) { dsvDesc->Texture1DArray.MipSlice = range->startMipLevel; dsvDesc->Texture1DArray.FirstArraySlice = range->startArrayLayer; dsvDesc->Texture1DArray.ArraySize = range->layerArrayCount; - dsvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + dsvDesc->ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1DARRAY; } else if (type == PAL_IMAGE_VIEW_TYPE_2D) { dsvDesc->Texture2D.MipSlice = range->startMipLevel; - dsvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + dsvDesc->ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; } else if (type == PAL_IMAGE_VIEW_TYPE_2D_ARRAY) { dsvDesc->Texture2DArray.MipSlice = range->startMipLevel; dsvDesc->Texture2DArray.FirstArraySlice = range->startArrayLayer; dsvDesc->Texture2DArray.ArraySize = range->layerArrayCount; - dsvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + dsvDesc->ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY; } return; @@ -1691,29 +1697,29 @@ static void fillSubresourceD3D12( } else if (uavDesc) { if (type == PAL_IMAGE_VIEW_TYPE_1D) { uavDesc->Texture1D.MipSlice = range->startMipLevel; - uavDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1D; + uavDesc->ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1D; } else if (type == PAL_IMAGE_VIEW_TYPE_1D_ARRAY) { uavDesc->Texture1DArray.MipSlice = range->startMipLevel; uavDesc->Texture1DArray.FirstArraySlice = range->startArrayLayer; uavDesc->Texture1DArray.ArraySize = range->layerArrayCount; - uavDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + uavDesc->ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1DARRAY; } else if (type == PAL_IMAGE_VIEW_TYPE_2D) { uavDesc->Texture2D.MipSlice = range->startMipLevel; - uavDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + uavDesc->ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; } else if (type == PAL_IMAGE_VIEW_TYPE_2D_ARRAY) { uavDesc->Texture2DArray.MipSlice = range->startMipLevel; uavDesc->Texture2DArray.FirstArraySlice = range->startArrayLayer; uavDesc->Texture2DArray.ArraySize = range->layerArrayCount; - uavDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; + uavDesc->ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY; } else if (type == PAL_IMAGE_VIEW_TYPE_3D) { uavDesc->Texture3D.MipSlice = range->startMipLevel; uavDesc->Texture3D.FirstWSlice = range->startArrayLayer; uavDesc->Texture3D.WSize = range->layerArrayCount; - uavDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; + uavDesc->ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D; } return; } @@ -1926,19 +1932,20 @@ static void pollMessagesD3D12(Device* device) return; } - Uint8* tmpBuffer[MAX_MESSAGE_SIZE]; UINT64 messageCount = queue->lpVtbl->GetNumStoredMessages(queue); for (int i = 0; i < messageCount; i++) { SIZE_T size = 0; - queue->lpVtbl->GetMessageA(queue, i, nullptr, &size); - if (size > sizeof(tmpBuffer)) { - size = sizeof(tmpBuffer); + queue->lpVtbl->GetMessage(queue, i, nullptr, &size); + + Uint8* buffer = palAllocate(s_D3D.allocator, size, 0); + if (!buffer) { + return; } - queue->lpVtbl->GetMessageA(queue, i, (D3D12_MESSAGE*)tmpBuffer, &size); - const char* message = ((D3D12_MESSAGE*)tmpBuffer)->pDescription; - D3D12_MESSAGE_CATEGORY category = ((D3D12_MESSAGE*)tmpBuffer)->Category; - D3D12_MESSAGE_SEVERITY severity = ((D3D12_MESSAGE*)tmpBuffer)->Severity; + queue->lpVtbl->GetMessage(queue, i, (D3D12_MESSAGE*)buffer, &size); + const char* message = ((D3D12_MESSAGE*)buffer)->pDescription; + D3D12_MESSAGE_CATEGORY category = ((D3D12_MESSAGE*)buffer)->Category; + D3D12_MESSAGE_SEVERITY severity = ((D3D12_MESSAGE*)buffer)->Severity; PalDebugMessageSeverity msgSeverity = 0; PalDebugMessageType msgType = 0; @@ -1984,6 +1991,7 @@ static void pollMessagesD3D12(Device* device) } s_D3D.debugCallback(s_D3D.debugUserData, msgSeverity, msgType, message); + palFree(s_D3D.allocator, buffer); } queue->lpVtbl->ClearStoredMessages(queue); } @@ -3832,7 +3840,7 @@ PalResult PAL_CALL createSamplerD3D12( sampler->desc.MaxAnisotropy = 1; if (info->enableAnisotropy) { - sampler->desc.MaxAnisotropy = info->maxAnisotropy; + sampler->desc.MaxAnisotropy = (UINT)info->maxAnisotropy; } sampler->desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; @@ -4273,10 +4281,9 @@ PalResult PAL_CALL presentSwapchainD3D12( // check if swapchain needs to be resize RECT windowRect; - Uint32 w, h; bool ret = GetClientRect((HWND)d3dSwapchain->surface->handle, &windowRect); - w = windowRect.right - windowRect.left; - w = windowRect.bottom - windowRect.top; + Uint32 w = windowRect.right - windowRect.left; + Uint32 h = windowRect.bottom - windowRect.top; if (!ret) { return PAL_RESULT_SURFACE_LOST; @@ -4499,7 +4506,7 @@ PalResult PAL_CALL waitFenceD3D12( if (timeout == PAL_INFINITE) { ret = WaitForSingleObject(event, INFINITE); } else { - ret = WaitForSingleObject(event, timeout); + ret = WaitForSingleObject(event, (DWORD)timeout); } CloseHandle(event); } @@ -4617,7 +4624,7 @@ PalResult PAL_CALL waitSemaphoreD3D12( if (timeout == PAL_INFINITE) { ret = WaitForSingleObject(event, INFINITE); } else { - ret = WaitForSingleObject(event, timeout); + ret = WaitForSingleObject(event, (DWORD)timeout); } CloseHandle(event); } @@ -5626,7 +5633,7 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( Buffer* tmp = (Buffer*)buffers[i]; views[i].BufferLocation = tmp->handle->lpVtbl->GetGPUVirtualAddress(tmp->handle); views[i].BufferLocation = views[i].BufferLocation + offsets[i]; - views[i].SizeInBytes = tmp->size; + views[i].SizeInBytes = (UINT)tmp->size; views[i].StrideInBytes = pipeline->strides[i]; } @@ -5654,7 +5661,7 @@ PalResult PAL_CALL cmdBindIndexBufferD3D12( view.BufferLocation = indexBuffer->handle->lpVtbl->GetGPUVirtualAddress(indexBuffer->handle); view.BufferLocation = view.BufferLocation + offset; - view.SizeInBytes = indexBuffer->size; + view.SizeInBytes = (UINT)indexBuffer->size; if (type == PAL_INDEX_TYPE_UINT16) { view.Format = DXGI_FORMAT_R16_UINT; } else { @@ -6053,7 +6060,7 @@ PalResult PAL_CALL cmdTraceRaysD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Uint32 stride = d3dSbt->raygen.region.StrideInBytes; + Uint64 stride = d3dSbt->raygen.region.StrideInBytes; D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; raygenAddress.SizeInBytes = d3dSbt->raygen.region.SizeInBytes; raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * stride; @@ -6114,7 +6121,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( desc.Height = data.groupCountXOrHeight; desc.Depth = data.groupCountXOrDepth; - Uint32 stride = d3dSbt->raygen.region.StrideInBytes; + Uint64 stride = d3dSbt->raygen.region.StrideInBytes; D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; raygenAddress.SizeInBytes = d3dSbt->raygen.region.SizeInBytes; raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * stride; @@ -6420,9 +6427,9 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( &sizeInfo); } - size->accelerationStructureSize = sizeInfo.ResultDataMaxSizeInBytes; - size->scratchBufferSize = sizeInfo.ScratchDataSizeInBytes; - size->updateScratchBufferSize = sizeInfo.UpdateScratchDataSizeInBytes; + size->accelerationStructureSize = (UINT)sizeInfo.ResultDataMaxSizeInBytes; + size->scratchBufferSize = (UINT)sizeInfo.ScratchDataSizeInBytes; + size->updateScratchBufferSize = (UINT)sizeInfo.UpdateScratchDataSizeInBytes; return PAL_RESULT_SUCCESS; } @@ -6673,7 +6680,7 @@ PalResult PAL_CALL mapBufferMemoryD3D12( return PAL_RESULT_MEMORY_MAP_FAILED; } - *outPtr = ptr + offset; + *outPtr = (Uint8*)ptr + offset; return PAL_RESULT_SUCCESS; } @@ -7341,7 +7348,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( PipelineLayout* layout = nullptr; Uint32 resourceCount = 0; Uint32 samplerCount = 0; - Uint32 pushConstantSize = 0; + Uint64 pushConstantSize = 0; Uint32 sizeInBytes = sizeof(D3D12_DESCRIPTOR_RANGE1); Uint32 rangesOffset = 0; @@ -7429,7 +7436,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( if (pushConstantSize) { D3D12_ROOT_PARAMETER1* parameter = ¶meters[parameterCount]; parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; - parameter->Constants.Num32BitValues = pushConstantSize / 4; + parameter->Constants.Num32BitValues = (UINT)pushConstantSize / 4; parameter->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; layout->constantIndex = parameterCount; @@ -8789,8 +8796,8 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - Uint32 stride = 0; - Uint32 offset = 0; + Uint64 stride = 0; + Uint64 offset = 0; Uint32 startIndex = 0; for (int i = 0; i < count; i++) { @@ -8839,4 +8846,4 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( #endif // PAL_HAS_D3D12 -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 74cc876d..6cc36d7d 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -2086,15 +2086,15 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - // result = initGraphicsVk(debugger, allocator); - // if (result != PAL_RESULT_SUCCESS) { - // return result; - // } - - // attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - // attachedBackend->base = &s_VkBackend; - // attachedBackend->startIndex = 0; - // attachedBackend->count = 0; // TODO: uncomment + result = initGraphicsVk(debugger, allocator); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + attachedBackend->base = &s_VkBackend; + attachedBackend->startIndex = 0; + attachedBackend->count = 0; #endif // PAL_HAS_VULKAN // D3D12 @@ -2141,7 +2141,7 @@ void PAL_CALL palShutdownGraphics() #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - //shutdownGraphicsVk(); // TODO: uncomment + shutdownGraphicsVk(); #endif // PAL_HAS_VULKAN // D3D12 diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 517d75e3..18d828cb 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -101,8 +101,8 @@ bool graphicsTest() return false; } - Uint32 vramMb = (Uint32)(info.vram / 1024 * 1024); - Uint32 sharedMemMb = (Uint32)(info.sharedMemory / 1024 * 1024); + Uint32 vramMb = (Uint32)info.vram / (1024 * 1024); + Uint32 sharedMemMb = (Uint32)info.sharedMemory /(1024 * 1024); palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Backend Name: %s", info.backendName); From 712c9acd12383910bf24bbdbc15f76a84453f034 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 29 May 2026 14:25:54 +0000 Subject: [PATCH 237/372] start ray tracing test fix d3d12 --- src/graphics/pal_d3d12.c | 126 ++++++++++++------ src/graphics/pal_graphics.c | 20 +-- tests/graphics/ray_tracing_test.c | 2 +- .../shaders/bin/dxil/ray_tracing.dxil | Bin 5936 -> 6040 bytes tests/tests_main.c | 4 +- 5 files changed, 96 insertions(+), 56 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index ef56c65b..fd6c62e4 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -343,6 +343,7 @@ typedef struct { } PipelineLayout; typedef struct { + bool isHitGroup; PalShaderStage stage; wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; } ShaderExport; @@ -368,6 +369,7 @@ typedef struct { bool hasFsr; Uint32 type; + Uint32 shaderExportCount; D3D12_SHADING_RATE shadingRate; D3D_PRIMITIVE_TOPOLOGY topology; Uint32* strides; @@ -5501,6 +5503,10 @@ PalResult PAL_CALL cmdBindPipelineD3D12( d3dCmdBuffer->handle, d3dPipeline->handle); + d3dCmdBuffer->handle->lpVtbl->SetComputeRootSignature( + d3dCmdBuffer->handle, + d3dPipeline->layout->handle); + } else { d3dCmdBuffer->handle->lpVtbl->SetPipelineState( d3dCmdBuffer->handle, @@ -5521,11 +5527,6 @@ PalResult PAL_CALL cmdBindPipelineD3D12( d3dPipeline->shadingRate, d3dPipeline->combinerOps); } - - } else if (d3dPipeline->type == COMPUTE_PIPELINE) { - d3dCmdBuffer->handle->lpVtbl->SetComputeRootSignature( - d3dCmdBuffer->handle, - d3dPipeline->layout->handle); } } @@ -6077,6 +6078,7 @@ PalResult PAL_CALL cmdTraceRaysD3D12( desc.MissShaderTable = d3dSbt->miss.region; desc.CallableShaderTable = d3dSbt->callable.region; + // TODO: Fix unknown signal d3dCmdBuffer->handle->lpVtbl->DispatchRays(d3dCmdBuffer->handle, &desc); return PAL_RESULT_SUCCESS; } @@ -8181,6 +8183,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_OUT_OF_MEMORY; } + pipeline->shaderExportCount = exportCount + sbtInfo.hitCount; subObjects = palAllocate(s_D3D.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); hitGroups = palAllocate(s_D3D.allocator, sizeof(RayHitGroup) * sbtInfo.hitCount, 0); if (!subObjects || !hitGroups) { @@ -8199,7 +8202,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( pipeline->shaderExports = palAllocate( s_D3D.allocator, - sizeof(ShaderExport) * exportCount, + sizeof(ShaderExport) * pipeline->shaderExportCount, 0); localExports = palAllocate( @@ -8220,6 +8223,20 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( subObjects[subObjectIndex].pDesc = &globalRootSignature; subObjectIndex++; + // ray tracing config + D3D12_RAYTRACING_SHADER_CONFIG shaderConfig = {0}; + shaderConfig.MaxAttributeSizeInBytes = info->maxAttributeSize; + shaderConfig.MaxPayloadSizeInBytes = info->maxPayloadSize; + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG; + subObjects[subObjectIndex].pDesc = &shaderConfig; + subObjectIndex++; + + D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = {0}; + pipelineConfig.MaxTraceRecursionDepth = info->maxRecursionDepth; + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG; + subObjects[subObjectIndex].pDesc = &pipelineConfig; + subObjectIndex++; + // shaders Uint32 exportsOffset = 0; for (int i = 0; i < info->shaderCount; i++) { @@ -8232,6 +8249,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( ShaderExport* shaderExport = &pipeline->shaderExports[exportsOffset + j]; ShaderEntry* entry = &tmp->entries[j]; + shaderExport->isHitGroup = false; shaderExport->stage = entry->stage; wcscpy(shaderExport->entryName, entry->entryName); @@ -8246,6 +8264,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; subObjects[subObjectIndex].pDesc = libraryDesc; subObjectIndex++; + exportsOffset += tmp->entryCount; } // hit groups @@ -8267,6 +8286,11 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( D3D12_HIT_GROUP_DESC* group = &hitGroups[hitGroupIndex].desc; getHitGroupNameD3D12(hitGroupIndex, hitGroups[hitGroupIndex].entryName); + ShaderExport* hitGroupExport = &pipeline->shaderExports[exportCount++]; + wcscpy(hitGroupExport->entryName, hitGroups[hitGroupIndex].entryName); + hitGroupExport->isHitGroup = true; + hitGroupExport->stage = PAL_SHADER_STAGE_CLOSEST_HIT; // to identify + group->AnyHitShaderImport = nullptr; group->ClosestHitShaderImport = nullptr; group->IntersectionShaderImport = nullptr; @@ -8293,7 +8317,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->closestHitShaderIndex]; ShaderEntry* entry = &shader->entries[tmp->closestHitShaderEntryIndex]; - group->AnyHitShaderImport = entry->entryName; + group->ClosestHitShaderImport = entry->entryName; } else { group->ClosestHitShaderImport = nullptr; @@ -8303,7 +8327,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { Shader* shader = (Shader*)info->shaders[tmp->intersectionShaderIndex]; ShaderEntry* entry = &shader->entries[tmp->intersectionShaderEntryIndex]; - group->AnyHitShaderImport = entry->entryName; + group->IntersectionShaderImport = entry->entryName; } else { group->IntersectionShaderImport = nullptr; @@ -8323,7 +8347,6 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // check if we need a local root signature D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION localExportAssociation = {0}; D3D12_LOCAL_ROOT_SIGNATURE localRootSignature = {0}; - if (localRootSize) { D3D12_ROOT_PARAMETER1 parameter = {0}; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; @@ -8366,7 +8389,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( localRootSignature.pLocalRootSignature = pipeline->localRootSignature; subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE; - subObjects[subObjectIndex].pDesc = pipeline->localRootSignature; + subObjects[subObjectIndex].pDesc = &localRootSignature; localExportAssociation.pSubobjectToAssociate = &subObjects[subObjectIndex]; localExportAssociation.pExports = localExports; @@ -8379,20 +8402,6 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( subObjectIndex++; } - // ray tracing config - D3D12_RAYTRACING_SHADER_CONFIG shaderConfig = {0}; - shaderConfig.MaxAttributeSizeInBytes = info->maxAttributeSize; - shaderConfig.MaxPayloadSizeInBytes = info->maxPayloadSize; - subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG; - subObjects[subObjectIndex].pDesc = &shaderConfig; - subObjectIndex++; - - D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = {0}; - pipelineConfig.MaxTraceRecursionDepth = info->maxRecursionDepth; - subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG; - subObjects[subObjectIndex].pDesc = &pipelineConfig; - subObjectIndex++; - D3D12_STATE_OBJECT_DESC desc = {0}; desc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; desc.NumSubobjects = subObjectCount; @@ -8488,15 +8497,38 @@ PalResult PAL_CALL createShaderBindingTableD3D12( void** callableHandles = nullptr; sbt = palAllocate(s_D3D.allocator, sizeof(ShaderBindingTable), 0); - raygenHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->raygenCount, 0); - missHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->missCount, 0); - hitHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->hitCount, 0); - callableHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->callableCount, 0); - - if (!sbt || !raygenHandles || !missHandles || !hitHandles || !callableHandles) { + if (!sbt) { return PAL_RESULT_OUT_OF_MEMORY; } + if (sbtInfo->raygenCount) { + raygenHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->raygenCount, 0); + if (!raygenHandles) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } + + if (sbtInfo->missCount) { + missHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->missCount, 0); + if (!missHandles) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } + + if (sbtInfo->hitCount) { + hitHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->hitCount, 0); + if (!hitHandles) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } + + if (sbtInfo->callableCount) { + callableHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->callableCount, 0); + if (!callableHandles) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } + // create SBT buffer ID3D12StateObject* pipelineHandle = pipeline->handle; ID3D12StateObjectProperties* props = NULL; @@ -8589,8 +8621,6 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // create gpu buffer D3D12_HEAP_PROPERTIES heapProps = {0}; heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.VisibleNodeMask = 1; - heapProps.CreationNodeMask = 1; D3D12_RESOURCE_DESC bufferDesc = {0}; bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; @@ -8643,27 +8673,36 @@ PalResult PAL_CALL createShaderBindingTableD3D12( Uint32 hitIndex = 0; Uint32 callableIndex = 0; - for (int i = 0; i < totalGroups; i++) { + for (int i = 0; i < pipeline->shaderExportCount; i++) { ShaderExport* tmp = &pipeline->shaderExports[i]; PalShaderStage stage = tmp->stage; - void* handle = nullptr; + // skip any hit, closest hit, intersection shaders without isHitGroup bool + bool isHitGroup = false; + if (stage == PAL_SHADER_STAGE_ANY_HIT || + stage == PAL_SHADER_STAGE_CLOSEST_HIT || + stage == PAL_SHADER_STAGE_INTERSECTION) { + if (tmp->isHitGroup) { + isHitGroup = true; + + } else { + continue; + } + } + + void* handle = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); if (stage == PAL_SHADER_STAGE_RAYGEN) { - handle = raygenHandles[raygenIndex++]; + raygenHandles[raygenIndex++] = handle; } else if (stage == PAL_SHADER_STAGE_MISS) { - handle = missHandles[missIndex++]; + missHandles[missIndex++] = handle; - } else if (stage == PAL_SHADER_STAGE_ANY_HIT || - stage == PAL_SHADER_STAGE_CLOSEST_HIT || - stage == PAL_SHADER_STAGE_INTERSECTION) { - handle = hitHandles[hitIndex++]; + } else if (isHitGroup) { + hitHandles[hitIndex++] = handle; } else if (stage == PAL_SHADER_STAGE_CALLABLE) { - handle = callableHandles[callableIndex++]; + callableHandles[callableIndex++] = handle; } - - handle = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); } // copy handles into the buffer @@ -8765,6 +8804,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( palFree(s_D3D.allocator, callableHandles); sbt->handleSize = groupHandleSize; + sbt->stagingBufferSize = bufferSize; sbt->pipeline = pipeline; sbt->isDirty = true; // we need to copy from the staging to the gpu buffer diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 6cc36d7d..895364cf 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -2086,15 +2086,15 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - result = initGraphicsVk(debugger, allocator); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - - attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base = &s_VkBackend; - attachedBackend->startIndex = 0; - attachedBackend->count = 0; + // result = initGraphicsVk(debugger, allocator); + // if (result != PAL_RESULT_SUCCESS) { + // return result; + // } + + // attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + // attachedBackend->base = &s_VkBackend; + // attachedBackend->startIndex = 0; + // attachedBackend->count = 0; #endif // PAL_HAS_VULKAN // D3D12 @@ -2141,7 +2141,7 @@ void PAL_CALL palShutdownGraphics() #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN - shutdownGraphicsVk(); + // shutdownGraphicsVk(); #endif // PAL_HAS_VULKAN // D3D12 diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index ede8d8e6..2bda8c8e 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -59,7 +59,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/graphics/shaders/bin/dxil/ray_tracing.dxil b/tests/graphics/shaders/bin/dxil/ray_tracing.dxil index 1a78cb5981038730ab1793451629e78881726939..0dbd5ac705efa182824f5e2e01c8a4986be95693 100644 GIT binary patch literal 6040 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 delta 3470 zcmdUy4^ULc9mn_m$-8%tJ9xl}hj-vRz*7*-yW`IthM4z`0}nwx5FHY2JwT!~pdx8n zlhk|nM}ijREfq)ll6^T8?q%;zOju~y*>F7)*=^kL3$)wZi zOlR8eyxsln@3*)6eYV5rAXS0CZXrbb(O}z_W0+0_Zaq=jIbo0E~fT=r?3}K2k}b1~)I+$n@FqB?_Xw!7 zF^;B|^pn2ors;r6TX9vULejz`sChg6+@dhP2Dg}rTy$&FuqtM#S}9sru0Q5@`wZR4 z)~IGZW{Q&qcIm5^X6RN=WGG1Z1+PX(q8P`=( zN9Nu*(ayxlOwLQ;_%BX7$BkK{d_d99d`fbNdpo}0YILdMvyEUGuuMOKY7K&O)9Vh4 ztT!Gb;Xcfy+Dw`T*la_xOU-~syC(lUpPOFhV33_SDF9}+n`O8LLAcq5$F&ecA4LRJ zmufA5HjETzZBUz80`RZr&3Z!v(AL?QkR0632$;38&GP8*d{@0#yKN^BXZ@|pmF=liJGrl2wo)ss9#aX0V~B7h8a%TF)SZpN7rll65dgd7 z0CcpLq<&#v(e*%!GTK@o|6Ty+`_h@gJ<)?MM1fXe$kPgzH(eCY2NYv1 zH*wylCJWPfSC`n{RmG9_Qap@gV0?_(T*mS{1}%1`I`z)YJCpul*sU8;T^gV60Ho>U zvo0dinZ{sC%eGf;-&t5*wteSj1#Oou$0R;Z@}AUijVMus9*uWs&5pDk4zXQR3DPB5 z$^maJ7pf*Doh6(@U+0k8m7`udrV$W&u^l=T#>?Nd_|BLjD){F8zpbg9WkxHj)eZJme)Gc#J2 zb(rZr((^H2AfO)ojqvkxUA?`>J5qH_>uKh6(#ej@6CIi7x>+s5Fu#=6M&}!&sP>Mw zR!1R($++x({Mfi`n)UuMr4M%S(DWBa;v-Mxu+#RMOt%{;8t zE$huZ(G5rMO*GE0w%qR^7_? z7@b^7vU5pg|0hp0JdPI?&;_?aR<2wS9-gmi!REPDA(7T^u&Wu7OAg=5{8BK5vEm`h zQuqpMj90CWe>hw<=1t%D-d`SIaZh>@l#7Mj(iHk|!_9LleQ@Zf^jANd+g(Kkf)lS0 z&K6|z#=8?nC+wgRyg}!haE4wiJRFe~_$Gb@4xxdMfnz~t@VA9)(l{rSGXn<`zt$Aw zbujfD>K*!HGI)n{BQ{cNO07U33QA^vc2l(m8la&Ll`@@ION5P^jozbPjTPUn$g7}EzhFYS^3G;Y;C zt$E!#2;S%H9wK(m$uph042!m%?duTRH&=18E0MCAkjy>wPp7qWc?n=Wx<2DNzX~`X9xwwNreMaljz`= zsn$qb3}sx$`H^(oPfSQ928Tmehh+rJ%{B$_C@+URsK{$+d5+4f!B9WtJJm?N@1Wi< zdnqIyL(!2NmUoftt<{W3L1|84paWZtJhiiA*Ou~at4b=iaop29su>a=Nad$)blI7pV*~ag}88UBF)nAiXbJYF5}(HMY%!*ML(W@5y*~nPouAX#oeZw zPH+b)SqJA0ZQ5{w)}q{y93kz0O(e?jd-<<#)#U&?W3u;?o}iogGF<-(n_ELxFjq9e zNZnUHIpThCPN;Q2JNo9B@vOV52u1T>Is6K-#@~ zC<|T84G)q0@^~vj0K0`Hj$4R7)Oitskvoy3X8!VLn|n+)S*^6LRYF<@1T9BP-d$(G z+GICcWh>icK6v}ENGKnJ)uT>{&T>sYT{O{mlN~hvYDFO;nsdyzU!~l|)(UsMa>Iy7 zXL`xer87M-^NwYfkQXdOJYf~V>1m?JB0?1Pay^vC4~Fcf6Rc($Tja7QUyLAwm(3Ce zfFLF!aejJ(;Oz~JMj^S6C7V02Hw#`EJ>(&Qt%lre3D*V>BPZdLYgjA#$07;`D*XZ-1Mr@nJB`8*rLIx4ffUC0T;Xea-5@SI{v+3_Il2qXU diff --git a/tests/tests_main.c b/tests/tests_main.c index 16d6ef5b..c3c21a72 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,9 +57,9 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - registerTest(graphicsTest, "Graphics Test"); + // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS From 27ff5a3e33b383be5964dba339e083429f8b928d Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 4 Jun 2026 18:16:22 -0700 Subject: [PATCH 238/372] remove test properly fixme from ray tracing test d3d12 --- include/pal/pal_graphics.h | 5 +- src/graphics/pal_d3d12.c | 103 ++++++++++++++++-------------- tests/graphics/ray_tracing_test.c | 5 +- 3 files changed, 60 insertions(+), 53 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 02adbf6f..8113b7bc 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -5501,8 +5501,9 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( * * The graphics system must be initialized before this call. * If the provided command pool is invalid or nullptr, this function returns - * silently. All command buffers allocated from the command pool must be freed before this - * function. + * silently. + * + * Destroying a command pool frees all command buffers automatically. * * @param[in] pool Command pool to destroy. * diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index fd6c62e4..a3cdec70 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -321,6 +321,8 @@ typedef struct { bool supportsAddress; bool canChangeState; bool hasIndirect; + bool isAccelerationStructure; + bool isScratch; Uint64 size; ID3D12Resource* handle; Device* device; @@ -1300,13 +1302,9 @@ static bool fillBuildInfoD3D12( } D3D12_RAYTRACING_GEOMETRY_DESC* tmp = &geometries[i]; - tmp->Flags = 0; - if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_OPAQUE) { - tmp->Flags |= D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; - } - + tmp->Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT) { - tmp->Flags |= D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION; + tmp->Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION; } if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { @@ -5838,22 +5836,10 @@ PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - AccelerationStructure* d3dAS = (AccelerationStructure*)as; - D3D12_RESOURCE_STATES old, new; - - old = barrierToD3D12( - oldUsageStateInfo->shaderStageCount, - oldUsageStateInfo->usageState, - oldUsageStateInfo->shaderStages); - - new = barrierToD3D12( - newUsageStateInfo->shaderStageCount, - newUsageStateInfo->usageState, - newUsageStateInfo->shaderStages); - + AccelerationStructure* d3dAs = (AccelerationStructure*)as; D3D12_RESOURCE_BARRIER barrier = {0}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrier.UAV.pResource = d3dAS->handle; + barrier.UAV.pResource = d3dAs->handle; d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); return PAL_RESULT_SUCCESS; @@ -6078,7 +6064,6 @@ PalResult PAL_CALL cmdTraceRaysD3D12( desc.MissShaderTable = d3dSbt->miss.region; desc.CallableShaderTable = d3dSbt->callable.region; - // TODO: Fix unknown signal d3dCmdBuffer->handle->lpVtbl->DispatchRays(d3dCmdBuffer->handle, &desc); return PAL_RESULT_SUCCESS; } @@ -6480,10 +6465,12 @@ PalResult PAL_CALL createBufferD3D12( if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + buffer->isAccelerationStructure = true; } if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + buffer->isScratch = true; } if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { @@ -6645,6 +6632,14 @@ PalResult PAL_CALL bindBufferMemoryD3D12( d3dBuffer->canChangeState = false; } + if (d3dBuffer->isAccelerationStructure) { + d3dBuffer->canChangeState = false; + state = D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; + + } else if (d3dBuffer->isScratch) { + state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + } + result = device->lpVtbl->CreatePlacedResource( device, mem, @@ -8501,6 +8496,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( return PAL_RESULT_OUT_OF_MEMORY; } + memset(sbt, 0, sizeof(ShaderBindingTable)); if (sbtInfo->raygenCount) { raygenHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->raygenCount, 0); if (!raygenHandles) { @@ -8636,7 +8632,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( &heapProps, 0, &bufferDesc, - D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_COPY_DEST, nullptr, &IID_Resource, (void**)&sbt->buffer); @@ -8767,42 +8763,53 @@ PalResult PAL_CALL createShaderBindingTableD3D12( sbt->stagingBuffer->lpVtbl->Unmap(sbt->stagingBuffer, 0, nullptr); // cache SBT fields and offsets address - sbt->baseAddress = sbt->buffer->lpVtbl->GetGPUVirtualAddress(sbt->buffer); + sbt->baseAddress = sbt->buffer->lpVtbl->GetGPUVirtualAddress(sbt->stagingBuffer); // raygen - sbt->raygen.region.StartAddress = sbt->baseAddress; - sbt->raygen.offset = 0; // always - sbt->raygen.startIndex = 0; // always - sbt->raygen.region.SizeInBytes = raygenRegionSize; - sbt->raygen.region.StrideInBytes = raygenStride; + if (sbtInfo->raygenCount) { + sbt->raygen.region.StartAddress = sbt->baseAddress; + sbt->raygen.offset = 0; // always + sbt->raygen.startIndex = 0; // always + sbt->raygen.region.SizeInBytes = raygenRegionSize; + sbt->raygen.region.StrideInBytes = raygenStride; + palFree(s_D3D.allocator, raygenHandles); + } + // miss - sbt->miss.offset = missOffset; - sbt->miss.startIndex = sbtInfo->raygenCount; - sbt->miss.region.StartAddress = sbt->baseAddress + missOffset; - sbt->miss.region.SizeInBytes = missRegionSize; - sbt->miss.region.StrideInBytes = missStride; + if (sbtInfo->missCount) { + sbt->miss.offset = missOffset; + sbt->miss.startIndex = sbtInfo->raygenCount; + sbt->miss.region.StartAddress = sbt->baseAddress + missOffset; + sbt->miss.region.SizeInBytes = missRegionSize; + sbt->miss.region.StrideInBytes = missStride; + + palFree(s_D3D.allocator, missHandles); + } // hit - sbt->hit.offset = hitOffset; - sbt->hit.startIndex = sbtInfo->raygenCount + sbtInfo->missCount; - sbt->hit.region.StartAddress = sbt->baseAddress + hitOffset; - sbt->hit.region.SizeInBytes = hitRegionSize; - sbt->hit.region.StrideInBytes = hitStride; + if (sbtInfo->hitCount) { + sbt->hit.offset = hitOffset; + sbt->hit.startIndex = sbtInfo->raygenCount + sbtInfo->missCount; + sbt->hit.region.StartAddress = sbt->baseAddress + hitOffset; + sbt->hit.region.SizeInBytes = hitRegionSize; + sbt->hit.region.StrideInBytes = hitStride; + + palFree(s_D3D.allocator, hitHandles); + } // callable - sbt->callable.offset = callableOffset; - sbt->callable.startIndex = sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount; - sbt->callable.region.StartAddress = sbt->baseAddress + callableOffset; - sbt->callable.region.SizeInBytes = callableRegionSize; - sbt->callable.region.StrideInBytes = callableStride; + if (sbtInfo->callableCount) { + sbt->callable.offset = callableOffset; + sbt->callable.startIndex = sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount; + sbt->callable.region.StartAddress = sbt->baseAddress + callableOffset; + sbt->callable.region.SizeInBytes = callableRegionSize; + sbt->callable.region.StrideInBytes = callableStride; + palFree(s_D3D.allocator, callableHandles); + } + props->lpVtbl->Release(props); - palFree(s_D3D.allocator, raygenHandles); - palFree(s_D3D.allocator, missHandles); - palFree(s_D3D.allocator, hitHandles); - palFree(s_D3D.allocator, callableHandles); - sbt->handleSize = groupHandleSize; sbt->stagingBufferSize = bufferSize; sbt->pipeline = pipeline; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 2bda8c8e..bb2afac1 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -5,7 +5,7 @@ #define BUFFER_SIZE 400 typedef struct { - float color[3]; // closest hit color + float color[3]; // closest hit and miss color } LocalData; static void PAL_CALL onGraphicsDebug( @@ -19,7 +19,6 @@ static void PAL_CALL onGraphicsDebug( bool rayTracingTest() { - // FIXME: Test properly on D3D12 PalAdapter* adapter = nullptr; PalDevice* device = nullptr; PalQueue* queue = nullptr; @@ -59,7 +58,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); From 3d1b96ddf375398d77a2272cda0861836643e86d Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 4 Jun 2026 20:04:25 -0700 Subject: [PATCH 239/372] remove test properly fixme from descriptor indexing test d3d12 --- include/pal/pal_graphics.h | 11 ++ src/graphics/pal_d3d12.c | 161 ++++++++++++++++------ src/graphics/pal_vulkan.c | 9 +- tests/graphics/descriptor_indexing_test.c | 78 ++++++++--- tests/graphics/graphics_test.c | 8 ++ tests/tests_main.c | 4 +- 6 files changed, 211 insertions(+), 60 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 8113b7bc..5ee52c12 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -125,6 +125,8 @@ typedef Uint64 PalAdapterFeatures; #define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH PAL_BIT64(32) #define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT PAL_BIT64(33) #define PAL_ADAPTER_FEATURE_DISPATCH_BASE PAL_BIT64(34) +#define PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS PAL_BIT64(35) +#define PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS PAL_BIT64(36) /** * @struct PalAdapter @@ -7269,6 +7271,15 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( * @brief Update a descriptor set with descriptors (resources). * * The graphics system must be initialized before this call. + * + * If the write info has no valid resource handle, then `PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS` + * must be supported and enabled when creating the device if not, this function will fail and + * return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * + * Set PalDescriptorPoolCreateInfo::enableDescriptorIndexing to true to enable + * descriptor indexing on the descriptor pool. `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` + * must be supported and enabled when creating the device if not, this function will fail and + * return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device The Device. Must match the one used to allocate descriptor set. * @param[in] count Capacity of the PalDescriptorSetWriteInfo array. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index a3cdec70..b0acf04b 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2578,6 +2578,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH; features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; features |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; + features |= PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS; if (d3dAdapter->level >= D3D_FEATURE_LEVEL_12_0) { features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; @@ -7227,18 +7228,43 @@ PalResult PAL_CALL updateDescriptorSetD3D12( dst.ptr = getDescriptorHandleD3D12(index + j, heap->incrementSize, heap->cpuBase); if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { - Sampler* sampler = (Sampler*)info->samplerInfos[j].sampler; - d3dDevice->handle->lpVtbl->CreateSampler(d3dDevice->handle, &sampler->desc, dst); + if (info->samplerInfos) { + Sampler* sampler = (Sampler*)info->samplerInfos[j].sampler; + d3dDevice->handle->lpVtbl->CreateSampler(d3dDevice->handle, &sampler->desc, dst); - } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - AccelerationStructure* tlas = nullptr; - tlas = (AccelerationStructure*)info->tlasInfos[j].tlas; + } else { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + D3D12_SAMPLER_DESC desc = {0}; + desc.MaxAnisotropy = 1; + desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; + desc.BorderColor[3] = 1.0f; + + desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; + d3dDevice->handle->lpVtbl->CreateSampler(d3dDevice->handle, &desc, dst); + } + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - desc.RaytracingAccelerationStructure.Location = tlas->address; desc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; + if (info->tlasInfos) { + AccelerationStructure* tlas = nullptr; + tlas = (AccelerationStructure*)info->tlasInfos[j].tlas; + desc.RaytracingAccelerationStructure.Location = tlas->address; + + } else { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + d3dDevice->handle->lpVtbl->CreateShaderResourceView( d3dDevice->handle, nullptr, @@ -7246,14 +7272,35 @@ PalResult PAL_CALL updateDescriptorSetD3D12( dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - ImageView* imageView = (ImageView*)info->imageViewInfos[j].imageView; D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - desc.Format = imageView->format; + + PalImageSubresourceRange range = {0}; + PalImageViewType type; + ID3D12Resource* handle = nullptr; + + if (info->imageViewInfos) { + ImageView* imageView = (ImageView*)info->imageViewInfos[j].imageView; + desc.Format = imageView->format; + type = imageView->type; + range = imageView->range; + handle = imageView->image->handle; + + } else { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + type = PAL_IMAGE_VIEW_TYPE_2D; + range.mipLevelCount = 1; + range.layerArrayCount = 1; + range.aspect = PAL_IMAGE_ASPECT_COLOR; + } fillSubresourceD3D12( - imageView->type, - &imageView->range, + type, + &range, nullptr, nullptr, &desc, @@ -7261,18 +7308,38 @@ PalResult PAL_CALL updateDescriptorSetD3D12( d3dDevice->handle->lpVtbl->CreateShaderResourceView( d3dDevice->handle, - imageView->image->handle, + handle, &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - ImageView* imageView = (ImageView*)info->imageViewInfos[j].imageView; D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; - desc.Format = imageView->format; + PalImageSubresourceRange range = {0}; + PalImageViewType type; + ID3D12Resource* handle = nullptr; + + if (info->imageViewInfos) { + ImageView* imageView = (ImageView*)info->imageViewInfos[j].imageView; + desc.Format = imageView->format; + type = imageView->type; + range = imageView->range; + handle = imageView->image->handle; + + } else { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + type = PAL_IMAGE_VIEW_TYPE_2D; + range.mipLevelCount = 1; + range.layerArrayCount = 1; + range.aspect = PAL_IMAGE_ASPECT_COLOR; + } fillSubresourceD3D12( - imageView->type, - &imageView->range, + type, + &range, nullptr, nullptr, nullptr, @@ -7280,21 +7347,27 @@ PalResult PAL_CALL updateDescriptorSetD3D12( d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( d3dDevice->handle, - imageView->image->handle, + handle, nullptr, &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; - Buffer* buffer = (Buffer*)bufferInfo->buffer; - D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {0}; - desc.SizeInBytes = bufferInfo->size; - D3D12_GPU_VIRTUAL_ADDRESS address = 0; - address = buffer->handle->lpVtbl->GetGPUVirtualAddress(buffer->handle); - desc.BufferLocation = address + bufferInfo->offset; + + if (info->bufferInfos) { + PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; + Buffer* buffer = (Buffer*)bufferInfo->buffer; + desc.SizeInBytes = bufferInfo->size; + address = buffer->handle->lpVtbl->GetGPUVirtualAddress(buffer->handle); + desc.BufferLocation = address + bufferInfo->offset; + + } else { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } d3dDevice->handle->lpVtbl->CreateConstantBufferView( d3dDevice->handle, @@ -7303,26 +7376,36 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } else { // storage buffer - PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; - Buffer* buffer = (Buffer*)bufferInfo->buffer; - D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; - Uint32 stride = 4; - if (bufferInfo->stride) { - stride = bufferInfo->stride; - desc.Buffer.StructureByteStride = bufferInfo->stride; - } else { - desc.Format = DXGI_FORMAT_R32_TYPELESS; - desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; - } - desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - desc.Buffer.FirstElement = bufferInfo->offset / stride; - desc.Buffer.NumElements = bufferInfo->size / stride; + + ID3D12Resource* handle = nullptr; + if (info->bufferInfos) { + PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; + Buffer* buffer = (Buffer*)bufferInfo->buffer; + + Uint32 stride = 4; + if (bufferInfo->stride) { + stride = bufferInfo->stride; + desc.Buffer.StructureByteStride = bufferInfo->stride; + } else { + desc.Format = DXGI_FORMAT_R32_TYPELESS; + desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; + } + + handle = buffer->handle; + desc.Buffer.FirstElement = bufferInfo->offset / stride; + desc.Buffer.NumElements = bufferInfo->size / stride; + + } else { + if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( d3dDevice->handle, - buffer->handle, + handle, nullptr, &desc, dst); @@ -8763,7 +8846,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( sbt->stagingBuffer->lpVtbl->Unmap(sbt->stagingBuffer, 0, nullptr); // cache SBT fields and offsets address - sbt->baseAddress = sbt->buffer->lpVtbl->GetGPUVirtualAddress(sbt->stagingBuffer); + sbt->baseAddress = sbt->buffer->lpVtbl->GetGPUVirtualAddress(sbt->buffer); // raygen if (sbtInfo->raygenCount) { diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 236274f0..d1f3f80b 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3771,11 +3771,15 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); // core features we need - if (desc.runtimeDescriptorArray || - desc.descriptorBindingPartiallyBound || + if (desc.runtimeDescriptorArray || desc.descriptorBindingUpdateUnusedWhilePending) { adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } + + // TODO: add PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS + if (desc.descriptorBindingPartiallyBound) { + adapterFeatures |= PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; + } } // timeline semaphore is part of core 1.2 @@ -8655,6 +8659,7 @@ PalResult PAL_CALL updateDescriptorSetVk( Uint32 count, PalDescriptorSetWriteInfo* infos) { + // TODO: add null descriptors VkResult result; Device* vkDevice = (Device*)device; VkWriteDescriptorSet* writes = nullptr; diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 2f1507bb..e27f0c32 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -51,7 +51,6 @@ static void PAL_CALL onGraphicsDebug( bool descriptorIndexingTest() { - // FIXME: Test properly on D3D12 PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; @@ -223,22 +222,6 @@ bool descriptorIndexingTest() return false; } - if (adapterInfo.apiType == PAL_ADAPTER_API_TYPE_D3D12 && - adapterInfo.type == PAL_ADAPTER_TYPE_CPU) { - // D3D12 WARP Adapter has a runtime limitation that causes dynamic indices to fold - // back to slot 0. - - // explicit registers work for this test but its not reliable for real usage - // Texture2D texs[] : register(t0, space0); // set 0 - // Texture2D tex17 : register(t17, space0); // set 0 - // Texture2D tex47 : register(t47, space0); // set 0 - // Texture2D tex55 : register(t55, space0); // set 0 - // Texture2D tex78 : register(t78, space0); // set 0 - - adapter = nullptr; - continue; - } - // we prefer spirv first if an adapter supports multiple shader formats Uint32 target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { @@ -272,6 +255,15 @@ bool descriptorIndexingTest() features |= PAL_ADAPTER_FEATURE_FENCE_RESET; } + // check if null descriptors or partially bound is supported + if (adapterFeatures & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS) { + features |= PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; + } + + if (adapterFeatures & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS) { + features |= PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS; + } + result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -1011,6 +1003,58 @@ bool descriptorIndexingTest() return false; } + // check if null descriptors was enabled and partially bound was not supported + bool hasPartiallyBound = adapterFeatures & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; + if (adapterFeatures & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS && !hasPartiallyBound) { + // write null descriptors into the slots + PalDescriptorSetWriteInfo writeInfo = {0}; + writeInfo.layoutBindingIndex = 0; + writeInfo.descriptorSet = descriptorSet; + writeInfo.descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + writeInfo.descriptorCount = 100; + + writeInfo.arrayElement = 0; + writeInfo.samplerInfos = nullptr; + writeInfo.imageViewInfos = nullptr; + writeInfo.tlasInfos = nullptr; + writeInfo.bufferInfos = nullptr; + + result = palUpdateDescriptorSet(device, 1, &writeInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to update descriptor set: %s", error); + return false; + } + + } else { + // both null descriptors and partially bound are not supported + // we write the first texture to all slots + PalDescriptorImageViewInfo imageViewInfos[100]; + for (int i = 0; i < 100; i++) { + imageViewInfos[i].imageView = textureViews[0]; + } + + PalDescriptorSetWriteInfo writeInfo = {0}; + writeInfo.layoutBindingIndex = 0; + writeInfo.descriptorSet = descriptorSet; + writeInfo.descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + writeInfo.descriptorCount = 100; + + writeInfo.arrayElement = 0; + writeInfo.samplerInfos = nullptr; + writeInfo.imageViewInfos = imageViewInfos; + writeInfo.tlasInfos = nullptr; + writeInfo.bufferInfos = nullptr; + + result = palUpdateDescriptorSet(device, 1, &writeInfo); + if (result != PAL_RESULT_SUCCESS) { + const char* error = palFormatResult(result); + palLog(nullptr, "Failed to update descriptor set: %s", error); + return false; + } + } + + // we only write 4 descriptors Uint32 arrElements[] = { ARRAY_ELEMENT_0, ARRAY_ELEMENT_1, ARRAY_ELEMENT_2, ARRAY_ELEMENT_3 }; diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 18d828cb..e2210a14 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -93,6 +93,10 @@ bool graphicsTest() deviceFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } + if (features & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS) { + deviceFeatures |= PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; + } + result = palCreateDevice(adapter, deviceFeatures, &device); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -689,6 +693,10 @@ bool graphicsTest() palLog(nullptr, " Dispatch base"); } + if (features & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS) { + palLog(nullptr, " Partially bound descriptors"); + } + palLog(nullptr, ""); palDestroyDevice(device); } diff --git a/tests/tests_main.c b/tests/tests_main.c index c3c21a72..21fa4511 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,7 +59,7 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS @@ -70,7 +70,7 @@ int main(int argc, char** argv) // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); - // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); + registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From 71dd98351516f4650557879c7c7dc433f2754374 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 4 Jun 2026 20:32:36 -0700 Subject: [PATCH 240/372] rewrite debug message types d3d12 --- src/graphics/pal_d3d12.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index b0acf04b..670d07a8 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2173,21 +2173,20 @@ PalResult PAL_CALL initGraphicsD3D12( // message types if (!debugger->denyGeneral) { + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED; s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_INITIALIZATION; - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_CLEANUP; - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_COMPILATION; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_SETTING; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION; } if (!debugger->denyPerformance) { - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_CREATION; s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_EXECUTION; - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_SHADER; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_SETTING; } if (!debugger->denyValidation) { - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_CREATION; - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_GETTING; - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_SETTING; + s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_SHADER; } // message severities From e4581e5228fab146d0a8e8f2619b41908fc0a3f2 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 4 Jun 2026 23:03:49 +0000 Subject: [PATCH 241/372] add null descriptors feature --- src/graphics/pal_vulkan.c | 167 ++++++++++++++++++++++-------- tests/graphics/graphics_test.c | 4 + tests/graphics/ray_tracing_test.c | 2 +- tests/tests_main.c | 4 +- 4 files changed, 132 insertions(+), 45 deletions(-) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index d1f3f80b..0b91269c 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3636,6 +3636,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) bool dynamicstate = false; bool bufferDeviceAddress = false; bool shaderParameters = false; + bool nullDescriptors = false; s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, extensionProps); // clang-format off @@ -3701,6 +3702,9 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } else if (strcmp(props->extensionName, "VK_KHR_shader_draw_parameters") == 0) { shaderParameters = true; + + } else if (strcmp(props->extensionName, "VK_EXT_robustness2") == 0) { + nullDescriptors = true; } } @@ -3776,7 +3780,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } - // TODO: add PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS if (desc.descriptorBindingPartiallyBound) { adapterFeatures |= PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; } @@ -3888,6 +3891,20 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_DISPATCH_BASE; } } + + if (nullDescriptors) { + VkPhysicalDeviceRobustness2FeaturesEXT nullDescriptors = {0}; + nullDescriptors.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &nullDescriptors; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (nullDescriptors.nullDescriptor) { + adapterFeatures |= PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS; + } + } // clang-format on VkPhysicalDeviceFeatures features; @@ -4115,6 +4132,9 @@ PalResult PAL_CALL createDeviceVk( VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {0}; drawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; + VkPhysicalDeviceRobustness2FeaturesEXT nullDescriptors = {0}; + nullDescriptors.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; + if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_KHR_dynamic_rendering"; extensions[extCount++] = "VK_KHR_synchronization2"; @@ -4235,7 +4255,6 @@ PalResult PAL_CALL createDeviceVk( // clang-format off descIndex.runtimeDescriptorArray = desc.runtimeDescriptorArray; - descIndex.descriptorBindingPartiallyBound = desc.descriptorBindingPartiallyBound; descIndex.descriptorBindingUpdateUnusedWhilePending = desc.descriptorBindingUpdateUnusedWhilePending; descIndex.shaderSampledImageArrayNonUniformIndexing = desc.shaderSampledImageArrayNonUniformIndexing; @@ -4256,6 +4275,20 @@ PalResult PAL_CALL createDeviceVk( next = &descIndex; } + if (features & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS) { + if (!(features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_EXT_descriptor_indexing"; + } + + features12.descriptorIndexing = true; + descIndex.pNext = next; + next = &descIndex; + } + + descIndex.descriptorBindingPartiallyBound = true; + } + if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_multiview"; @@ -4309,6 +4342,14 @@ PalResult PAL_CALL createDeviceVk( next = &drawParameters; } + if (features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS) { + extensions[extCount++] = "VK_EXT_robustness2"; + nullDescriptors.nullDescriptor = true; + + nullDescriptors.pNext = next; + next = &nullDescriptors; + } + VkDeviceCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pEnabledFeatures = &coreFeatures; @@ -8659,12 +8700,12 @@ PalResult PAL_CALL updateDescriptorSetVk( Uint32 count, PalDescriptorSetWriteInfo* infos) { - // TODO: add null descriptors VkResult result; Device* vkDevice = (Device*)device; VkWriteDescriptorSet* writes = nullptr; VkDescriptorBufferInfo* bufferInfos = nullptr; VkDescriptorImageInfo* imageInfos = nullptr; + VkAccelerationStructureKHR* tlas = nullptr; VkWriteDescriptorSetAccelerationStructureKHR* tlasInfos = nullptr; Uint32 bufferCount = 0; @@ -8673,6 +8714,7 @@ PalResult PAL_CALL updateDescriptorSetVk( Uint32 imageOffset = 0; Uint32 tlasCount = 0; Uint32 tlasOffset = 0; + Uint32 tlasInfoCount = 0; for (int i = 0; i < count; i++) { if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || @@ -8681,6 +8723,7 @@ PalResult PAL_CALL updateDescriptorSetVk( } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { tlasCount += infos[i].descriptorCount; + tlasInfoCount++; } else { imageCount += infos[i].descriptorCount; @@ -8691,12 +8734,15 @@ PalResult PAL_CALL updateDescriptorSetVk( if (!writes) { return PAL_RESULT_OUT_OF_MEMORY; } + memset(writes, 0, sizeof(VkWriteDescriptorSet) * count); if (bufferCount) { bufferInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBufferInfo) * bufferCount, 0); if (!bufferInfos) { return PAL_RESULT_OUT_OF_MEMORY; } + + memset(bufferInfos, 0, sizeof(VkDescriptorBufferInfo) * bufferCount); } @@ -8705,14 +8751,20 @@ PalResult PAL_CALL updateDescriptorSetVk( if (!imageInfos) { return PAL_RESULT_OUT_OF_MEMORY; } + + memset(imageInfos, 0, sizeof(VkDescriptorImageInfo) * imageCount); } - Uint32 tlasInfoSize = sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasCount; if (tlasCount) { + Uint32 tlasInfoSize = sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasInfoCount; tlasInfos = palAllocate(s_Vk.allocator, tlasInfoSize, 0); - if (!tlasInfos) { + tlas = palAllocate(s_Vk.allocator, sizeof(VkAccelerationStructureKHR) * count, 0); + if (!tlasInfos || !tlas) { return PAL_RESULT_OUT_OF_MEMORY; } + + memset(tlasInfos, 0, tlasInfoSize); + memset(tlas, 0, sizeof(VkAccelerationStructureKHR) * tlasCount); } for (int i = 0; i < count; i++) { @@ -8720,11 +8772,6 @@ PalResult PAL_CALL updateDescriptorSetVk( PalDescriptorSetWriteInfo* info = &infos[i]; write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write->pBufferInfo = nullptr; - write->pImageInfo = nullptr; - write->pTexelBufferView = nullptr; - write->pNext = nullptr; - write->dstArrayElement = info->arrayElement; write->dstBinding = info->layoutBindingIndex; write->descriptorCount = info->descriptorCount; @@ -8741,24 +8788,35 @@ PalResult PAL_CALL updateDescriptorSetVk( if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { VkDescriptorBufferInfo* bufferInfo = &bufferInfos[bufferOffset + j]; - PalDescriptorBufferInfo* tmp = &info->bufferInfos[j]; - Buffer* vkBuffer = (Buffer*)tmp->buffer; - bufferInfo->buffer = vkBuffer->handle; - bufferInfo->offset = tmp->offset; - bufferInfo->range = tmp->size; + if (info->bufferInfos) { + PalDescriptorBufferInfo* tmp = &info->bufferInfos[j]; + Buffer* vkBuffer = (Buffer*)tmp->buffer; + + bufferInfo->buffer = vkBuffer->handle; + bufferInfo->offset = tmp->offset; + bufferInfo->range = tmp->size; + + } else { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + isBuffer = true; } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - VkWriteDescriptorSetAccelerationStructureKHR* tlasInfo = nullptr; - tlasInfo = &tlasInfos[tlasOffset + j]; - PalDescriptorTLASInfo* tmp = &info->tlasInfos[j]; - AccelerationStructure* as = (AccelerationStructure*)tmp->tlas; - - tlasInfo->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; - tlasInfo->accelerationStructureCount = 1; - tlasInfo->pAccelerationStructures = &as->handle; - tlasInfo->pNext = nullptr; + if (info->tlasInfos) { + PalDescriptorTLASInfo* tmp = &info->tlasInfos[j]; + AccelerationStructure* as = (AccelerationStructure*)tmp->tlas; + tlas[tlasOffset + j] = as->handle; + + } else { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + isTlas = true; } else { @@ -8766,28 +8824,47 @@ PalResult PAL_CALL updateDescriptorSetVk( isImage = true; if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { - PalDescriptorSamplerInfo* tmp = &info->samplerInfos[j]; - Sampler* vkSampler = (Sampler*)tmp->sampler; - - imageInfo->sampler = vkSampler->handle; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo->imageView = nullptr; + if (info->samplerInfos) { + PalDescriptorSamplerInfo* tmp = &info->samplerInfos[j]; + Sampler* vkSampler = (Sampler*)tmp->sampler; + imageInfo->sampler = vkSampler->handle; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + } else { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; - ImageView* vkImageView = (ImageView*)tmp->imageView; + if (info->imageViewInfos) { + PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; + ImageView* vkImageView = (ImageView*)tmp->imageView; - imageInfo->sampler = nullptr; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo->imageView = vkImageView->handle; + imageInfo->sampler = nullptr; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageInfo->imageView = vkImageView->handle; - } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; - ImageView* vkImageView = (ImageView*)tmp->imageView; + } else { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } - imageInfo->sampler = nullptr; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo->imageView = vkImageView->handle; + } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + if (info->imageViewInfos) { + PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; + ImageView* vkImageView = (ImageView*)tmp->imageView; + + imageInfo->sampler = nullptr; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo->imageView = vkImageView->handle; + + } else { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } } } } @@ -8797,7 +8874,11 @@ PalResult PAL_CALL updateDescriptorSetVk( imageOffset += write->descriptorCount; } else if (isTlas) { - write->pNext = &tlasInfos[tlasOffset]; + tlasInfos[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; + tlasInfos[i].accelerationStructureCount = info->descriptorCount; + tlasInfos[i].pAccelerationStructures = &tlas[tlasOffset]; + + write->pNext = &tlasInfos[i]; tlasOffset += write->descriptorCount; } else if (isBuffer) { @@ -8811,6 +8892,8 @@ PalResult PAL_CALL updateDescriptorSetVk( palFree(s_Vk.allocator, bufferInfos); palFree(s_Vk.allocator, imageInfos); palFree(s_Vk.allocator, tlasInfos); + palFree(s_Vk.allocator, tlas); + return PAL_RESULT_SUCCESS; } diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index e2210a14..9f7b238c 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -697,6 +697,10 @@ bool graphicsTest() palLog(nullptr, " Partially bound descriptors"); } + if (features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS) { + palLog(nullptr, " Null descriptors"); + } + palLog(nullptr, ""); palDestroyDevice(device); } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index bb2afac1..203713af 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -58,7 +58,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); diff --git a/tests/tests_main.c b/tests/tests_main.c index 21fa4511..c3c21a72 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -59,7 +59,7 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS @@ -70,7 +70,7 @@ int main(int argc, char** argv) // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); - registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); + // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From f83e7b8a00ffa0aeedfb4c803ce607356a719d0e Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 9 Jun 2026 19:23:25 +0000 Subject: [PATCH 242/372] fix ray tracing test bug --- src/graphics/pal_vulkan.c | 85 ++++++++------------- tests/graphics/ray_tracing_test.c | 11 ++- tests/graphics/shaders/src/ray_tracing.hlsl | 4 +- 3 files changed, 41 insertions(+), 59 deletions(-) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 0b91269c..0588b971 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1504,7 +1504,7 @@ static VkBufferUsageFlags bufferUsageToVk(PalBufferUsages usages) } if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { - flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR; + flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; } if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT) { @@ -4086,7 +4086,7 @@ PalResult PAL_CALL createDeviceVk( // extensions and features2 void* next = nullptr; int extCount = 0; - const char* extensions[16] = {0}; + const char* extensions[32] = {0}; VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline = {0}; timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; @@ -4126,9 +4126,6 @@ PalResult PAL_CALL createDeviceVk( VkPhysicalDeviceSynchronization2FeaturesKHR sync2 = {0}; sync2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR; - VkPhysicalDeviceVulkan12Features features12 = {0}; - features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; - VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {0}; drawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; @@ -4160,7 +4157,6 @@ PalResult PAL_CALL createDeviceVk( extensions[extCount++] = "VK_KHR_timeline_semaphore"; } timeline.timelineSemaphore = true; - features12.timelineSemaphore = true; timeline.pNext = next; next = &timeline; @@ -4171,8 +4167,6 @@ PalResult PAL_CALL createDeviceVk( extensions[extCount++] = "VK_KHR_shader_float16_int8"; } shader16.shaderFloat16 = true; - features12.shaderFloat16 = true; - features12.shaderInt8 = true; shader16.pNext = next; next = &shader16; @@ -4185,17 +4179,9 @@ PalResult PAL_CALL createDeviceVk( ray.rayTracingPipeline = true; acc.accelerationStructure = true; - // ray tracing needs buffer address feature enabled - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_KHR_buffer_device_address"; - } - bufferAddress.bufferDeviceAddress = true; - features12.bufferDeviceAddress = true; - ray.pNext = next; acc.pNext = &ray; - bufferAddress.pNext = &acc; - next = &bufferAddress; + next = &acc; } if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { @@ -4219,10 +4205,6 @@ PalResult PAL_CALL createDeviceVk( if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_draw_indirect_count"; } - features12.drawIndirectCount = true; - - features12.pNext = next; - next = &features12; } if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || @@ -4270,7 +4252,6 @@ PalResult PAL_CALL createDeviceVk( descIndex.descriptorBindingUniformBufferUpdateAfterBind = desc.descriptorBindingUniformBufferUpdateAfterBind; // clang-format on - features12.descriptorIndexing = true; descIndex.pNext = next; next = &descIndex; } @@ -4281,7 +4262,6 @@ PalResult PAL_CALL createDeviceVk( extensions[extCount++] = "VK_EXT_descriptor_indexing"; } - features12.descriptorIndexing = true; descIndex.pNext = next; next = &descIndex; } @@ -4326,7 +4306,6 @@ PalResult PAL_CALL createDeviceVk( extensions[extCount++] = "VK_KHR_buffer_device_address"; } bufferAddress.bufferDeviceAddress = true; - features12.bufferDeviceAddress = true; bufferAddress.pNext = next; next = &bufferAddress; @@ -8709,11 +8688,8 @@ PalResult PAL_CALL updateDescriptorSetVk( VkWriteDescriptorSetAccelerationStructureKHR* tlasInfos = nullptr; Uint32 bufferCount = 0; - Uint32 bufferOffset = 0; Uint32 imageCount = 0; - Uint32 imageOffset = 0; Uint32 tlasCount = 0; - Uint32 tlasOffset = 0; Uint32 tlasInfoCount = 0; for (int i = 0; i < count; i++) { @@ -8767,6 +8743,12 @@ PalResult PAL_CALL updateDescriptorSetVk( memset(tlas, 0, sizeof(VkAccelerationStructureKHR) * tlasCount); } + // reset and reuse + bufferCount = 0; + imageCount = 0; + tlasCount = 0; + tlasInfoCount = 0; + for (int i = 0; i < count; i++) { VkWriteDescriptorSet* write = &writes[i]; PalDescriptorSetWriteInfo* info = &infos[i]; @@ -8780,14 +8762,10 @@ PalResult PAL_CALL updateDescriptorSetVk( DescriptorSet* set = (DescriptorSet*)info->descriptorSet; write->dstSet = set->handle; - bool isImage = false; - bool isTlas = false; - bool isBuffer = false; - for (int j = 0; j < write->descriptorCount; j++) { if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - VkDescriptorBufferInfo* bufferInfo = &bufferInfos[bufferOffset + j]; + VkDescriptorBufferInfo* bufferInfo = &bufferInfos[bufferCount + j]; if (info->bufferInfos) { PalDescriptorBufferInfo* tmp = &info->bufferInfos[j]; @@ -8803,27 +8781,22 @@ PalResult PAL_CALL updateDescriptorSetVk( } } - isBuffer = true; - - } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { if (info->tlasInfos) { PalDescriptorTLASInfo* tmp = &info->tlasInfos[j]; AccelerationStructure* as = (AccelerationStructure*)tmp->tlas; - tlas[tlasOffset + j] = as->handle; + tlas[tlasCount + j] = as->handle; } else { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } - - isTlas = true; } else { - VkDescriptorImageInfo* imageInfo = &imageInfos[imageOffset + j]; - isImage = true; + VkDescriptorImageInfo* imageInfo = &imageInfos[imageCount + j]; - if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { + if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { if (info->samplerInfos) { PalDescriptorSamplerInfo* tmp = &info->samplerInfos[j]; Sampler* vkSampler = (Sampler*)tmp->sampler; @@ -8836,7 +8809,7 @@ PalResult PAL_CALL updateDescriptorSetVk( } } - } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { if (info->imageViewInfos) { PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; ImageView* vkImageView = (ImageView*)tmp->imageView; @@ -8851,7 +8824,7 @@ PalResult PAL_CALL updateDescriptorSetVk( } } - } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { if (info->imageViewInfos) { PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; ImageView* vkImageView = (ImageView*)tmp->imageView; @@ -8869,21 +8842,23 @@ PalResult PAL_CALL updateDescriptorSetVk( } } - if (isImage) { - write->pImageInfo = &imageInfos[imageOffset]; - imageOffset += write->descriptorCount; + if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || + info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + write->pBufferInfo = &bufferInfos[bufferCount]; + bufferCount += write->descriptorCount; - } else if (isTlas) { - tlasInfos[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; - tlasInfos[i].accelerationStructureCount = info->descriptorCount; - tlasInfos[i].pAccelerationStructures = &tlas[tlasOffset]; + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + VkWriteDescriptorSetAccelerationStructureKHR* tlasInfo = &tlasInfos[tlasInfoCount]; + tlasInfo->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; + tlasInfo->accelerationStructureCount = info->descriptorCount; + tlasInfo->pAccelerationStructures = &tlas[tlasCount]; - write->pNext = &tlasInfos[i]; - tlasOffset += write->descriptorCount; + write->pNext = &tlasInfos[tlasInfoCount++]; + tlasCount += write->descriptorCount; - } else if (isBuffer) { - write->pBufferInfo = &bufferInfos[bufferOffset]; - bufferOffset += write->descriptorCount; + } else { + write->pImageInfo = &imageInfos[imageCount]; + imageCount += write->descriptorCount; } } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 203713af..1baa0af1 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -17,6 +17,13 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } +static inline Uint32 _max( + Uint32 a, + Uint32 b) +{ + return (a > b) ? a : b; +} + bool rayTracingTest() { PalAdapter* adapter = nullptr; @@ -58,7 +65,7 @@ bool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); @@ -630,7 +637,7 @@ bool rayTracingTest() } // create scratch buffer - bufferCreateInfo.size = buildSizes.scratchBufferSize + blasScratchSize;; + bufferCreateInfo.size = _max(buildSizes.scratchBufferSize, blasScratchSize); bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; diff --git a/tests/graphics/shaders/src/ray_tracing.hlsl b/tests/graphics/shaders/src/ray_tracing.hlsl index 4c51fdaa..f695d03a 100644 --- a/tests/graphics/shaders/src/ray_tracing.hlsl +++ b/tests/graphics/shaders/src/ray_tracing.hlsl @@ -36,8 +36,8 @@ void raygenMain() float2 ndcUv = uv * 2.0 - 1.0; RayDesc desc; - desc.Origin = float3(0.0, 0.0, -3.0);; - desc.Direction = normalize(float3(ndcUv.x, ndcUv.y, 1.0));; + desc.Origin = float3(0.0, 0.0, -3.0); + desc.Direction = normalize(float3(ndcUv.x, ndcUv.y, 1.0)); desc.TMin = 0.001; desc.TMax = 1000.0; TraceRay(tlas, RAY_FLAG_NONE, 0xFF, 0, 0, 0, desc, payload); From ac4a66c9d9697dc959466f10779bdaa09ca269f2 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 10 Jun 2026 03:10:55 +0000 Subject: [PATCH 243/372] add ray query adapter feature bit --- include/pal/pal_graphics.h | 54 ++++++++++++++++++---------------- src/graphics/pal_d3d12.c | 7 ++++- src/graphics/pal_vulkan.c | 44 +++++++++++++++------------ tests/graphics/graphics_test.c | 8 +++++ tests/tests_main.c | 4 +-- 5 files changed, 70 insertions(+), 47 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 5ee52c12..0b399c42 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -102,31 +102,33 @@ typedef Uint64 PalAdapterFeatures; #define PAL_ADAPTER_FEATURE_SHADER_INT16 PAL_BIT64(9) #define PAL_ADAPTER_FEATURE_SHADER_INT64 PAL_BIT64(10) #define PAL_ADAPTER_FEATURE_RAY_TRACING PAL_BIT64(11) -#define PAL_ADAPTER_FEATURE_MESH_SHADER PAL_BIT64(12) -#define PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE PAL_BIT64(13) -#define PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING PAL_BIT64(14) -#define PAL_ADAPTER_FEATURE_SWAPCHAIN PAL_BIT64(15) -#define PAL_ADAPTER_FEATURE_MULTI_VIEW PAL_BIT64(16) -#define PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY PAL_BIT64(17) -#define PAL_ADAPTER_FEATURE_FENCE_RESET PAL_BIT64(18) -#define PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE PAL_BIT64(19) -#define PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE PAL_BIT64(20) -#define PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE PAL_BIT64(21) -#define PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY PAL_BIT64(22) -#define PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE PAL_BIT64(23) -#define PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE PAL_BIT64(24) -#define PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP PAL_BIT64(25) -#define PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE PAL_BIT64(26) -#define PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT PAL_BIT64(27) -#define PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS PAL_BIT64(28) -#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW PAL_BIT64(29) -#define PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH PAL_BIT64(30) -#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT PAL_BIT64(31) -#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH PAL_BIT64(32) -#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT PAL_BIT64(33) -#define PAL_ADAPTER_FEATURE_DISPATCH_BASE PAL_BIT64(34) -#define PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS PAL_BIT64(35) -#define PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS PAL_BIT64(36) +#define PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING PAL_BIT64(12) +#define PAL_ADAPTER_FEATURE_MESH_SHADER PAL_BIT64(13) +#define PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE PAL_BIT64(14) +#define PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING PAL_BIT64(15) +#define PAL_ADAPTER_FEATURE_SWAPCHAIN PAL_BIT64(16) +#define PAL_ADAPTER_FEATURE_MULTI_VIEW PAL_BIT64(17) +#define PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY PAL_BIT64(18) +#define PAL_ADAPTER_FEATURE_FENCE_RESET PAL_BIT64(19) +#define PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE PAL_BIT64(20) +#define PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE PAL_BIT64(21) +#define PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE PAL_BIT64(22) +#define PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY PAL_BIT64(23) +#define PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE PAL_BIT64(24) +#define PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE PAL_BIT64(25) +#define PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP PAL_BIT64(26) +#define PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE PAL_BIT64(27) +#define PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT PAL_BIT64(28) +#define PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS PAL_BIT64(29) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW PAL_BIT64(30) +#define PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH PAL_BIT64(31) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT PAL_BIT64(32) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH PAL_BIT64(33) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT PAL_BIT64(34) +#define PAL_ADAPTER_FEATURE_DISPATCH_BASE PAL_BIT64(35) +#define PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS PAL_BIT64(36) +#define PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS PAL_BIT64(37) +#define PAL_ADAPTER_FEATURE_RAY_QUERY PAL_BIT64(38) /** * @struct PalAdapter @@ -6533,7 +6535,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, + * `PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING` must be supported and enabled by the device if not, * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 670d07a8..f1aa8691 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2547,6 +2547,11 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED) { features |= PAL_ADAPTER_FEATURE_RAY_TRACING; + features |= PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING; + } + + if (options5.RaytracingTier >= D3D12_RAYTRACING_TIER_1_1) { + features |= PAL_ADAPTER_FEATURE_RAY_QUERY; } if (options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED) { @@ -6081,7 +6086,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( Device* device = (Device*)d3dCmdBuffer->device; D3D12_DISPATCH_RAYS_DESC desc = {0}; - if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 0588b971..4d41ac10 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -3625,8 +3625,8 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } // check extensions - bool rayTracingFound = false; - bool accelerateFound = false; + bool rayTracing = false; + bool accelerationStructure = false; bool meshShader = false; bool fragmentRateShading = false; bool timelineSemaphore = false; @@ -3637,6 +3637,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) bool bufferDeviceAddress = false; bool shaderParameters = false; bool nullDescriptors = false; + bool rayQuery = false; s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, extensionProps); // clang-format off @@ -3644,10 +3645,10 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) for (int i = 0; i < extensionCount; i++) { VkExtensionProperties* props = &extensionProps[i]; if (strcmp(props->extensionName, "VK_KHR_ray_tracing_pipeline") == 0) { - rayTracingFound = true; + rayTracing = true; } else if (strcmp(props->extensionName, "VK_KHR_acceleration_structure") == 0) { - accelerateFound = true; + accelerationStructure = true; } else if (strcmp(props->extensionName, "VK_EXT_mesh_shader") == 0) { meshShader = true; @@ -3708,9 +3709,8 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } } - // features that require core and extension support - // ray tracing is not part of core - if (rayTracingFound && accelerateFound) { + // features that require additional checks + if (rayTracing && accelerationStructure) { VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; @@ -3726,9 +3726,12 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) if (ray.rayTracingPipeline && acc.accelerationStructure) { adapterFeatures |= PAL_ADAPTER_FEATURE_RAY_TRACING; } + + if (ray.rayTracingPipelineTraceRaysIndirect) { + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING; + } } - // mesh shader is not part of core if (meshShader) { VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; @@ -3744,7 +3747,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } } - // fragment shading rate is not part of core if (fragmentRateShading) { VkPhysicalDeviceFragmentShadingRateFeaturesKHR frag = {0}; frag.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; @@ -3764,7 +3766,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } } - // descriptor indexing is part of core 1.2 if (props.apiVersion >= VK_API_VERSION_1_2 || descriptorIndexing) { VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; @@ -3785,7 +3786,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } } - // timeline semaphore is part of core 1.2 if (props.apiVersion >= VK_API_VERSION_1_2 || timelineSemaphore) { VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline = {0}; timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; @@ -3800,7 +3800,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } } - // shader float 16 is part of core 1.2 if (props.apiVersion >= VK_API_VERSION_1_2 || shaderFloat16) { VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; @@ -3815,7 +3814,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } } - // multi view is part of core 1.1 if (props.apiVersion >= VK_API_VERSION_1_1 || multiiView) { VkPhysicalDeviceMultiviewFeaturesKHR multiView = {0}; multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR; @@ -3830,7 +3828,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } } - // dynamic state is part of core 1.3 if (props.apiVersion >= VK_API_VERSION_1_3 || dynamicstate) { VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynState = {0}; dynState.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; @@ -3847,7 +3844,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } } - // buffer device address is part of core 1.2 if (props.apiVersion >= VK_API_VERSION_1_2 || bufferDeviceAddress) { VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; @@ -3862,7 +3858,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } } - // indirect draw count is part of core 1.2 if (props.apiVersion >= VK_API_VERSION_1_2) { VkPhysicalDeviceVulkan12Features features12 = {0}; features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; @@ -3877,7 +3872,6 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } } - // shader draw parameters is part of core 1.2 if (props.apiVersion >= VK_API_VERSION_1_2 || shaderParameters) { VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {0}; drawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; @@ -3905,6 +3899,20 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS; } } + + if (rayQuery) { + VkPhysicalDeviceRayQueryFeaturesKHR query = {0}; + query.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &query; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (query.rayQuery) { + adapterFeatures |= PAL_ADAPTER_FEATURE_RAY_QUERY; + } + } // clang-format on VkPhysicalDeviceFeatures features; @@ -7830,7 +7838,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( ShaderBindingTable* vkSbt = (ShaderBindingTable*)sbt; Buffer* vkBuffer = (Buffer*)buffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 9f7b238c..14f85217 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -701,6 +701,14 @@ bool graphicsTest() palLog(nullptr, " Null descriptors"); } + if (features & PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING) { + palLog(nullptr, " Indirect ray tracing"); + } + + if (features & PAL_ADAPTER_FEATURE_RAY_QUERY) { + palLog(nullptr, " Ray query"); + } + palLog(nullptr, ""); palDestroyDevice(device); } diff --git a/tests/tests_main.c b/tests/tests_main.c index c3c21a72..16d6ef5b 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,9 +57,9 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS - // registerTest(graphicsTest, "Graphics Test"); + registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS From b03492c26196ecc4d1924f5d7640691c19df072d Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Jun 2026 08:24:40 +0000 Subject: [PATCH 244/372] fix highest shader target API bug d3d12 --- src/graphics/pal_d3d12.c | 15 +++- tests/graphics/graphics_test.c | 144 ++++++++++++++++----------------- 2 files changed, 83 insertions(+), 76 deletions(-) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index f1aa8691..5d72cb8c 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -2621,7 +2621,7 @@ Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( // find the highest supported shader model HRESULT result = 0; D3D_SHADER_MODEL highestModel = D3D_SHADER_MODEL_5_1; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 11; i++) { shaderModel.HighestShaderModel = models[i]; result = d3dAdapter->tmpDevice->lpVtbl->CheckFeatureSupport( d3dAdapter->tmpDevice, @@ -4768,7 +4768,9 @@ PalResult PAL_CALL allocateCommandBufferD3D12( return PAL_RESULT_OUT_OF_MEMORY; } + memset(cmdBuffer, 0, sizeof(CommandBuffer)); cmdBuffer->primary = true; + D3D12_COMMAND_LIST_TYPE cmdBufferType = cmdPool->type; if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { cmdBufferType = D3D12_COMMAND_LIST_TYPE_BUNDLE; @@ -4862,11 +4864,15 @@ PalResult PAL_CALL allocateCommandBufferD3D12( } } - cmdList->lpVtbl->QueryInterface( + result = cmdList->lpVtbl->QueryInterface( cmdList, &IID_CommandList6, (void**)&cmdBuffer->handle); + if (FAILED(result)) { + return PAL_RESULT_PLATFORM_FAILURE; + } + cmdList->lpVtbl->Release(cmdList); cmdBuffer->handle->lpVtbl->Close(cmdBuffer->handle); @@ -4940,8 +4946,9 @@ PalResult PAL_CALL submitCommandBufferD3D12( } } - ID3D12CommandList* tmp = (ID3D12CommandList*)d3dCmdBuffer->handle; - queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, &tmp); + + ID3D12CommandList* cmdLists[1] = { (ID3D12CommandList*)d3dCmdBuffer->handle }; + queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, cmdLists); d3dQueue->fenceValue++; queueHandle->lpVtbl->Signal(queueHandle, d3dQueue->fence, d3dQueue->fenceValue); diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 14f85217..fd514ac5 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -303,10 +303,6 @@ bool graphicsTest() palLog(nullptr, ""); } - if (features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { - palLog(nullptr, " Sample rate shading"); - } - if (features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { palLog(nullptr, " Multi viewport"); @@ -323,34 +319,6 @@ bool graphicsTest() palLog(nullptr, ""); } - if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - palLog(nullptr, " Timeline Semaphore"); - } - - if (features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { - palLog(nullptr, " Tesselation Shader"); - } - - if (features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { - palLog(nullptr, " Geometry shader"); - } - - if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { - palLog(nullptr, " Shader float16"); - } - - if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT64) { - palLog(nullptr, " Shader float64"); - } - - if (features & PAL_ADAPTER_FEATURE_SHADER_INT16) { - palLog(nullptr, " Shader int16"); - } - - if (features & PAL_ADAPTER_FEATURE_SHADER_INT64) { - palLog(nullptr, " Shader int64"); - } - if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { palLog(nullptr, " Ray tracing"); @@ -556,10 +524,6 @@ bool graphicsTest() palLog(nullptr, ""); } - if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { - palLog(nullptr, " Swapchain"); - } - if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { palLog(nullptr, " Multiview"); @@ -575,42 +539,6 @@ bool graphicsTest() palLog(nullptr, ""); } - if (features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY) { - palLog(nullptr, " Image view type Cube array"); - } - - if (features & PAL_ADAPTER_FEATURE_FENCE_RESET) { - palLog(nullptr, " Resetting fence"); - } - - if (features & PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE) { - palLog(nullptr, " Polygon mode line"); - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { - palLog(nullptr, " Dynamic cull mode"); - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { - palLog(nullptr, " Dynamic front face"); - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { - palLog(nullptr, " Dynamic primitive topology"); - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { - palLog(nullptr, " Dynamic depth test enable"); - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { - palLog(nullptr, " Dynamic depth write enable"); - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { - palLog(nullptr, " Dynamic stencil op"); - } - if (features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE) { palLog(nullptr, " Depth stencil resolve"); @@ -665,6 +593,78 @@ bool graphicsTest() palLog(nullptr, ""); } + if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { + palLog(nullptr, " Swapchain"); + } + + if (features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { + palLog(nullptr, " Sample rate shading"); + } + + if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + palLog(nullptr, " Timeline Semaphore"); + } + + if (features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { + palLog(nullptr, " Tesselation Shader"); + } + + if (features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { + palLog(nullptr, " Geometry shader"); + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { + palLog(nullptr, " Shader float16"); + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT64) { + palLog(nullptr, " Shader float64"); + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_INT16) { + palLog(nullptr, " Shader int16"); + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_INT64) { + palLog(nullptr, " Shader int64"); + } + + if (features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY) { + palLog(nullptr, " Image view type Cube array"); + } + + if (features & PAL_ADAPTER_FEATURE_FENCE_RESET) { + palLog(nullptr, " Resetting fence"); + } + + if (features & PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE) { + palLog(nullptr, " Polygon mode line"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { + palLog(nullptr, " Dynamic cull mode"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { + palLog(nullptr, " Dynamic front face"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { + palLog(nullptr, " Dynamic primitive topology"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { + palLog(nullptr, " Dynamic depth test enable"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { + palLog(nullptr, " Dynamic depth write enable"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { + palLog(nullptr, " Dynamic stencil op"); + } + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { palLog(nullptr, " Fragment shading rate attachment"); } From 94df64cf55f00fee11999f50256ddc2bc8e446a3 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Jun 2026 08:32:40 +0000 Subject: [PATCH 245/372] Stop tracking pal_config.h file --- .gitignore | 3 +++ include/pal/pal_config.h | 9 --------- 2 files changed, 3 insertions(+), 9 deletions(-) delete mode 100644 include/pal/pal_config.h diff --git a/.gitignore b/.gitignore index a10e46a7..69fcd88c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,9 @@ /bin/ /build/ +# build reflection +include/pal/pal_config.h + # MakeFiles Makefile **.make diff --git a/include/pal/pal_config.h b/include/pal/pal_config.h deleted file mode 100644 index b066298b..00000000 --- a/include/pal/pal_config.h +++ /dev/null @@ -1,9 +0,0 @@ - -// Auto Generated Config Header From pal_config.lua -// Must not be edited manually - -#define PAL_HAS_SYSTEM 1 -#define PAL_HAS_THREAD 0 -#define PAL_HAS_VIDEO 1 -#define PAL_HAS_OPENGL 0 -#define PAL_HAS_GRAPHICS 1 From 8e289b548a3cba031ed395d4b1b90228d1e5c56c Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Jun 2026 13:55:11 +0000 Subject: [PATCH 246/372] begin build system restructure --- README.md | 9 +- pal.lua | 99 ++++++++----------- premake5.lua | 187 +++++++++++++++++++++++++++++++----- src/graphics/pal_d3d12.c | 4 +- src/graphics/pal_graphics.c | 32 +++--- src/graphics/pal_vulkan.c | 4 +- tests/tests.lua | 4 +- tests/tests_main.c | 25 +++-- 8 files changed, 242 insertions(+), 122 deletions(-) diff --git a/README.md b/README.md index 713b5074..743dde6d 100644 --- a/README.md +++ b/README.md @@ -119,10 +119,15 @@ For more detailed examples, see the [tests folder](./tests) tests folder, which PAL is written in **C99** and uses Premake as its build system. Configure modules via [pal_config.lua](./pal_config.lua). See [pal_config.h](./include/pal/pal_config.h) to see the reflection of modules that will be built. +// TODO: docs +os.getenv("D3D12_INCLUDE") +const char* resName = getenv("RESOURCE_NAME"); +const char* resClass = getenv("RESOURCE_CLASS"); + **Windows** ```bash -premake\premake5.exe gmake2 # generate Makefiles (default: GCC) -premake\premake5.exe gmake2 --compiler=clang +premake\premake5.exe gmake # generate Makefiles (default: GCC) +premake\premake5.exe gmake --compiler=clang premake\premake5.exe vs2022 # generate Visual Studio project (default: MSVC) premake\premake5.exe vs2022 --compiler=clang diff --git a/pal.lua b/pal.lua index 7b7adbf5..0acc5b5c 100644 --- a/pal.lua +++ b/pal.lua @@ -1,44 +1,6 @@ dofile("pal_config.lua") -function writeConfig(path) - local file = io.open(path, "w") - file:write("\n// Auto Generated Config Header From pal_config.lua\n") - file:write("// Must not be edited manually\n\n") - - if (PAL_BUILD_SYSTEM) then - file:write("#define PAL_HAS_SYSTEM 1\n") - else - file:write("#define PAL_HAS_SYSTEM 0\n") - end - - if (PAL_BUILD_THREAD) then - file:write("#define PAL_HAS_THREAD 1\n") - else - file:write("#define PAL_HAS_THREAD 0\n") - end - - if (PAL_BUILD_VIDEO) then - file:write("#define PAL_HAS_VIDEO 1\n") - else - file:write("#define PAL_HAS_VIDEO 0\n") - end - - if (PAL_BUILD_OPENGL) then - file:write("#define PAL_HAS_OPENGL 1\n") - else - file:write("#define PAL_HAS_OPENGL 0\n") - end - - if (PAL_BUILD_GRAPHICS) then - file:write("#define PAL_HAS_GRAPHICS 1\n") - else - file:write("#define PAL_HAS_GRAPHICS 0\n") - end - - file:close() -end - project "PAL" language "C" @@ -52,8 +14,8 @@ project "PAL" } end - targetdir(target_dir) - objdir(obj_dir) + targetdir(targetDir) + objdir(objDir) includedirs { "include", @@ -71,7 +33,11 @@ project "PAL" filter {"system:linux", "configurations:*"} files { "src/system/pal_system_linux.c" } + filter {} + defines { "PAL_HAS_SYSTEM_MODULE = 1" } + else + defines { "PAL_HAS_SYSTEM_MODULE = 0" } end if (PAL_BUILD_THREAD) then @@ -82,6 +48,9 @@ project "PAL" files { "src/thread/pal_thread_linux.c" } filter {} + defines { "PAL_HAS_THREAD_MODULE = 1" } + else + defines { "PAL_HAS_THREAD_MODULE = 0" } end if (PAL_BUILD_VIDEO) then @@ -108,9 +77,9 @@ project "PAL" end if found then - defines { "PAL_HAS_WAYLAND=1" } + defines { "PAL_HAS_WAYLAND_BACKEND = 1" } else - defines { "PAL_HAS_WAYLAND=0" } + defines { "PAL_HAS_WAYLAND_BACKEND = 0" } end -- check for X11 support. This is cross compiler @@ -130,12 +99,15 @@ project "PAL" end if found then - defines { "PAL_HAS_X11=1" } + defines { "PAL_HAS_X11_BACKEND = 1" } else - defines { "PAL_HAS_X11=0" } + defines { "PAL_HAS_X11_BACKEND = 0" } end filter {} + defines { "PAL_HAS_VIDEO_MODULE = 1" } + else + defines { "PAL_HAS_VIDEO_MODULE = 0" } end if (PAL_BUILD_OPENGL) then @@ -144,50 +116,54 @@ project "PAL" filter {"system:linux", "configurations:*"} files { "src/opengl/pal_opengl_linux.c" } + filter {} + defines { "PAL_HAS_OPENGL_MODULE = 1" } + else + defines { "PAL_HAS_OPENGL_MODULE = 0" } end if (PAL_BUILD_GRAPHICS) then -- check for vulkan support. This is cross compiler - local vulkan_sdk = os.getenv("VULKAN_SDK") + local vulkanSdk = os.getenv("VULKAN_SDK") local hasVulkan = false - if (vulkan_sdk) then + if (vulkanSdk) then hasVulkan = true -- add to include path if compiler does not see it includedirs { - path.join(vulkan_sdk, "include") + path.join(vulkanSdk, "include") } - defines { "PAL_HAS_VULKAN=1" } + defines { "PAL_HAS_VULKAN_BACKEND = 1" } else - defines { "PAL_HAS_VULKAN=0" } + defines { "PAL_HAS_VULKAN_BACKEND = 0" } end -- check for d3d12 support. This is cross compiler local hasD3D12 = false - local d3d12_include = os.getenv("D3D12_INCLUDE") - if (os.isfile(path.join(d3d12_include, "d3d12.h"))) then + local d3d12Include = os.getenv("D3D12_INCLUDE") + if (os.isfile(path.join(d3d12Include, "d3d12.h"))) then hasD3D12 = true else if (_ACTION == "vs2022") or (_ACTION == "vs2026") then - d3d12_include = "" + d3d12Include = "" local base = "C:/Program Files (x86)/Windows Kits/10/Include" local versions = os.matchdirs(base .. "/*") table.sort(versions) for i = #versions, 1, -1 do local v = versions[i] - d3d12_include = path.join(v, "um") - if (os.isdir(d3d12_include)) then + d3d12Include = path.join(v, "um") + if (os.isdir(d3d12Include)) then break end end else - d3d12_include = path.join(ucrt, "include") + d3d12Include = path.join(ucrt, "include") end - if (os.isfile(path.join(d3d12_include, "d3d12.h"))) then + if (os.isfile(path.join(d3d12Include, "d3d12.h"))) then hasD3D12 = true end end @@ -195,12 +171,12 @@ project "PAL" if (hasD3D12) then -- add to include path if compiler does not see it includedirs { - d3d12_include + d3d12Include } - defines { "PAL_HAS_D3D12=1" } + defines { "PAL_HAS_D3D12_BACKEND = 1" } else - defines { "PAL_HAS_D3D12=0" } + defines { "PAL_HAS_D3D12_BACKEND = 0" } end -- base graphics file @@ -221,6 +197,7 @@ project "PAL" end filter {} + defines { "PAL_HAS_GRAPHICS_MODULE = 1" } + else + defines { "PAL_HAS_GRAPHICS_MODULE = 0" } end - - writeConfig("include/pal/pal_config.h") diff --git a/premake5.lua b/premake5.lua index c168b6cf..26b9d5aa 100644 --- a/premake5.lua +++ b/premake5.lua @@ -1,9 +1,114 @@ dofile("pal_config.lua") -target_dir = "%{wks.location}/bin/%{cfg.buildcfg}" -obj_dir = "%{wks.location}/build" -ucrt = os.getenv("UCRT64") or "C:/msys64/ucrt64" +targetDir = "%{wks.location}/bin/%{cfg.buildcfg}" +objDir = "%{wks.location}/build" + +workspaceName = "PALWorkspace" +compilerPath = "" +intellisenseMode = "" +problemMatcher = "" + +local function getCommandOutput(cmd) + local result, exitCode = os.outputof(cmd) + if result then + result = result:gsub("[\r\n%s]+$", "") + + if (result ~= "") then + result = result:gsub("\\", "/") + return result + else + return nil + end + end + return nil +end + +local function generateVscodeProperties() + print("\n=======================================================") + print("Generating .vscode/c_cpp_properties.json") + + local prjDefines = {} + local prjIncludes = {} + local workspace = premake.global.getWorkspace(workspaceName) + + for prj in premake.workspace.eachproject(workspace) do + for _, path in ipairs(prj.includedirs or {}) do + table.insert(prjIncludes, path) + end + + for _, define in ipairs(prj.defines or {}) do + table.insert(prjDefines, define) + end + end + + -- write to file + os.execute("mkdir .vscode 2>nul") -- ensure .vscode directory exists + local file = io.open(".vscode/c_cpp_properties.json", "w") + if file then + file:write('{\n') + file:write(' "configurations": [\n') + file:write(' {\n') + file:write(string.format(' "name": "%s",\n', workspaceName)) + + -- includes + file:write(' "includePath": [\n') + for i, dir in ipairs(prjIncludes) do + file:write(string.format(' "%s"%s\n', dir, i < #prjIncludes and "," or "")) + end + file:write(' ],\n') + + -- defines + file:write(" \"defines\": [\n") + for i, define in ipairs(prjDefines) do + file:write(string.format(' "%s"%s\n', define, i < #prjDefines and "," or "")) + end + file:write(' ],\n') + + file:write(string.format(' "compilerPath": "%s",\n', compilerPath)) + file:write(string.format(' "intelliSenseMode": "%s",\n', intellisenseMode)) + file:write(' "cStandard": "c99"\n') + + file:write(' }\n') + file:write(' ],\n') + file:write(' "version": 4\n') + file:write('}\n') + + file:close() + else + print("Error: Could not write to .vscode/c_cpp_properties.json.") + end +end + +local function generateTasksJson() + print("\n=======================================================") + print("Generating .vscode/tasks.json") + + local file = io.open(".vscode/tasks.json", "w") + if file then + file:write('{\n') + file:write(' "tasks": [\n') + file:write(" {\n") + file:write(' "type": "shell",\n') + file:write(' "label": "shell",\n') + + file:write(" }\n") + file:write(" ],\n") + file:write(' "version": "2.0.0"\n') + file:write("}\n") + + file:close() + else + print("Error: Could not write to .vscode/c_cpp_properties.json.") + end +end + +-- generate vscode properties +premake.override(premake.action, "call", function(base, action) + base(action) + generateVscodeProperties() + generateTasksJson() +end) newoption { trigger = "compiler", @@ -16,7 +121,7 @@ newoption { } } -workspace "PAL_workspace" +workspace(workspaceName) if PAL_BUILD_TESTS then startproject("tests") end @@ -50,37 +155,70 @@ workspace "PAL_workspace" filter {} - if (_ACTION == "gmake2") then - if (_OPTIONS["compiler"] == "clang") then - toolset("clang") - - buildoptions { - "-target x86_64-w64-windows-gnu", - "-I" .. ucrt .. "/include", - "-I" .. ucrt .. "/ucrt/include", - "-I" .. ucrt .. "/mingw/include", - - -- warnings - "-Wno-switch", -- for switch statements - "-Wno-switch-enum" -- for switch statements - } - - linkoptions { - "-target x86_64-w64-windows-gnu", - "-L" .. ucrt .. "/lib", - "-L" .. ucrt .. "/mingw/lib" - } + if (_ACTION == "gmake") then + if os.target() == "windows" then + local gccPath = getCommandOutput("where gcc.exe 2>nul") + local gccBinPath = path.getdirectory(gccPath) + local gccBasePath = path.getdirectory(gccBinPath) + + if (_OPTIONS["compiler"] == "clang") then + toolset("clang") + + buildoptions { + "-target x86_64-w64-windows-gnu", + "-I" .. gccBasePath .. "/include", + "-I" .. gccBasePath .. "/ucrt/include", + "-I" .. gccBasePath .. "/mingw/include", + + -- warnings + "-Wno-switch", -- for switch statements + "-Wno-switch-enum" -- for switch statements + } + + linkoptions { + "-target x86_64-w64-windows-gnu", + "-L" .. gccBasePath .. "/lib", + "-L" .. gccBasePath .. "/mingw/lib" + } + + intellisenseMode = "windows-clang-x64" + compilerPath = getCommandOutput("where clang.exe 2>nul") + else + -- GCC + intellisenseMode = "gcc-x64" + compilerPath = gccPath + end + else + -- linux + if (_OPTIONS["compiler"] == "clang") then + toolset("clang") + + intellisenseMode = "linux-clang-x64" + compilerPath = "/usr/bin/clang" + else + -- GCC + intellisenseMode = "linux-gcc-x64" + compilerPath = "/usr/bin/gcc" + end end end if (_ACTION == "vs2022") or (_ACTION == "vs2026") then if (_OPTIONS["compiler"] == "clang") then toolset("clang") + + intellisenseMode = "windows-clang-x64" + compilerPath = getCommandOutput("where clang.exe 2>nul") + else + -- MSVC + intellisenseMode = "windows-msvc-x64" + compilerPath = getCommandOutput("where cl.exe 2>nul") end defines { "_CRT_SECURE_NO_WARNINGS" } + disablewarnings { "6387", "4018", @@ -94,3 +232,4 @@ workspace "PAL_workspace" end include "pal.lua" + \ No newline at end of file diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 5d72cb8c..c7a5f593 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -27,7 +27,7 @@ freely, subject to the following restrictions: #include "pal/pal_graphics.h" -#if PAL_HAS_D3D12 +#if PAL_HAS_D3D12_BACKEND #ifdef _WIN32 #include @@ -8985,6 +8985,6 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( return PAL_RESULT_SUCCESS; } -#endif // PAL_HAS_D3D12 +#endif // PAL_HAS_D3D12_BACKEND #endif // _WIN32 diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 895364cf..8e9662cb 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -97,7 +97,7 @@ static inline Uint32 _min( // Vulkan API // ================================================== -#if PAL_HAS_VULKAN +#if PAL_HAS_VULKAN_BACKEND // ================================================== // Adapter @@ -970,13 +970,13 @@ static PalGraphicsBackend s_VkBackend = { .destroyShaderBindingTable = destroyShaderBindingTableVk, .updateShaderBindingTable = updateShaderBindingTableVk}; -#endif // PAL_HAS_VULKAN +#endif // PAL_HAS_VULKAN_BACKEND // ================================================== // D3D12 API // ================================================== -#if PAL_HAS_D3D12 +#if PAL_HAS_D3D12_BACKEND // ================================================== // Adapter @@ -1849,7 +1849,7 @@ static PalGraphicsBackend s_D3D12Backend = { .destroyShaderBindingTable = destroyShaderBindingTableD3D12, .updateShaderBindingTable = updateShaderBindingTableD3D12}; -#endif // PAL_HAS_D3D12 +#endif // PAL_HAS_D3D12_BACKEND // ================================================== // Metal API @@ -2085,7 +2085,7 @@ PalResult PAL_CALL palInitGraphics( BackendData* attachedBackend = nullptr; #ifdef _WIN32 // vulkan -#if PAL_HAS_VULKAN +#if PAL_HAS_VULKAN_BACKEND // result = initGraphicsVk(debugger, allocator); // if (result != PAL_RESULT_SUCCESS) { // return result; @@ -2095,10 +2095,10 @@ PalResult PAL_CALL palInitGraphics( // attachedBackend->base = &s_VkBackend; // attachedBackend->startIndex = 0; // attachedBackend->count = 0; -#endif // PAL_HAS_VULKAN +#endif // PAL_HAS_VULKAN_BACKEND // D3D12 -#if PAL_HAS_D3D12 +#if PAL_HAS_D3D12_BACKEND result = initGraphicsD3D12(debugger, allocator); if (result != PAL_RESULT_SUCCESS) { return result; @@ -2108,11 +2108,11 @@ PalResult PAL_CALL palInitGraphics( attachedBackend->base = &s_D3D12Backend; attachedBackend->startIndex = 0; attachedBackend->count = 0; -#endif // PAL_HAS_D3D12 +#endif // PAL_HAS_D3D12_BACKEND #elif defined(__linux__) // vulkan -#if PAL_HAS_VULKAN +#if PAL_HAS_VULKAN_BACKEND result = initGraphicsVk(debugger, allocator); if (result != PAL_RESULT_SUCCESS) { return result; @@ -2122,7 +2122,7 @@ PalResult PAL_CALL palInitGraphics( attachedBackend->base = &s_VkBackend; attachedBackend->startIndex = 0; attachedBackend->count = 0; -#endif // PAL_HAS_VULKAN +#endif // PAL_HAS_VULKAN_BACKEND #else // metal or andriod #endif // _WIN32 @@ -2140,20 +2140,20 @@ void PAL_CALL palShutdownGraphics() #ifdef _WIN32 // vulkan -#if PAL_HAS_VULKAN +#if PAL_HAS_VULKAN_BACKEND // shutdownGraphicsVk(); -#endif // PAL_HAS_VULKAN +#endif // PAL_HAS_VULKAN_BACKEND // D3D12 -#if PAL_HAS_D3D12 +#if PAL_HAS_D3D12_BACKEND shutdownGraphicsD3D12(); -#endif // PAL_HAS_D3D12 +#endif // PAL_HAS_D3D12_BACKEND #elif defined(__linux__) // vulkan -#if PAL_HAS_VULKAN +#if PAL_HAS_VULKAN_BACKEND shutdownGraphicsVk(); -#endif // PAL_HAS_VULKAN +#endif // PAL_HAS_VULKAN_BACKEND #else // metal or andriod diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 4d41ac10..bc4d6d02 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -31,7 +31,7 @@ freely, subject to the following restrictions: #include "pal/pal_graphics.h" -#if PAL_HAS_VULKAN +#if PAL_HAS_VULKAN_BACKEND #include // HACK: Needed to determine display type if on linux @@ -10043,4 +10043,4 @@ PalResult PAL_CALL updateShaderBindingTableVk( return PAL_RESULT_SUCCESS; } -#endif // PAL_HAS_VULKAN +#endif // PAL_HAS_VULKAN_BACKEND diff --git a/tests/tests.lua b/tests/tests.lua index af056bb4..e545a36f 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -3,8 +3,8 @@ project "tests" language "C" kind "ConsoleApp" - targetdir(target_dir) - objdir(obj_dir) + targetdir(targetDir) + objdir(objDir) files { "tests_main.c", diff --git a/tests/tests_main.c b/tests/tests_main.c index 16d6ef5b..17d1a810 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -1,5 +1,4 @@ -#include "pal/pal_config.h" // for systems reflection #include "tests.h" // clang-format off @@ -16,18 +15,18 @@ int main(int argc, char** argv) // registerTest(eventTest, "Event test"); // registerTest(userEventTest, "User Event Test"); -#if PAL_HAS_SYSTEM +#if PAL_HAS_SYSTEM_MODULE // registerTest(systemTest, "System Test"); -#endif // PAL_HAS_SYSTEM +#endif // PAL_HAS_SYSTEM_MODULE -#if PAL_HAS_THREAD +#if PAL_HAS_THREAD_MODULE // registerTest(threadTest, "Thread Test"); // registerTest(tlsTest, "TLS Test"); // registerTest(mutexTest, "Mutex Test"); // registerTest(condvarTest, "Condvar Test"); -#endif // PAL_HAS_THREAD +#endif // PAL_HAS_THREAD_MODULE -#if PAL_HAS_VIDEO +#if PAL_HAS_VIDEO_MODULE // registerTest(videoTest, "Video Test"); // registerTest(monitorTest, "Monitor Test"); // registerTest(monitorModeTest, "Monitor Mode Test"); @@ -41,29 +40,29 @@ int main(int argc, char** argv) // registerTest(nativeIntegrationTest, "Native Integration Test"); // registerTest(nativeInstanceTest, "Native Instance Test"); // registerTest(customDecorationTest, "Custom Decoration Test"); -#endif // PAL_HAS_VIDEO +#endif // PAL_HAS_VIDEO_MODULE // This test can run without video system so long as your have a valid // window -#if PAL_HAS_OPENGL && PAL_HAS_VIDEO +#if PAL_HAS_OPENGL_MODULE && PAL_HAS_VIDEO_MODULE // registerTest(openglTest, "Opengl Test"); // registerTest(openglFBConfigTest, "Opengl FBConfig Test"); // registerTest(openglContextTest, "Context Test"); // registerTest(openglMultiContextTest, "Opengl Multi Context Test"); -#endif // PAL_HAS_OPENGL +#endif // PAL_HAS_OPENGL_MODULE -#if PAL_HAS_OPENGL && PAL_HAS_VIDEO && PAL_HAS_THREAD +#if PAL_HAS_OPENGL_MODULE && PAL_HAS_VIDEO_MODULE && PAL_HAS_THREAD_MODULE // registerTest(multiThreadOpenGlTest, "Multi Thread Opengl Test"); #endif -#if PAL_HAS_GRAPHICS +#if PAL_HAS_GRAPHICS_MODULE registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); -#endif // PAL_HAS_GRAPHICS +#endif // PAL_HAS_GRAPHICS_MODULE -#if PAL_HAS_GRAPHICS && PAL_HAS_VIDEO +#if PAL_HAS_GRAPHICS_MODULE && PAL_HAS_VIDEO_MODULE // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); From 37e95f1f9be0f9214d78eabcdf920cca3856fdf7 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Jun 2026 16:16:06 +0000 Subject: [PATCH 247/372] add dynamic tasks.json file generating --- premake5.lua | 108 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 100 insertions(+), 8 deletions(-) diff --git a/premake5.lua b/premake5.lua index 26b9d5aa..c44c2fa6 100644 --- a/premake5.lua +++ b/premake5.lua @@ -8,6 +8,11 @@ workspaceName = "PALWorkspace" compilerPath = "" intellisenseMode = "" problemMatcher = "" +buildCommand = "" +cleanCommand = "" + +debugConfiguration = "" +releaseConfiguration = "" local function getCommandOutput(cmd) local result, exitCode = os.outputof(cmd) @@ -59,7 +64,7 @@ local function generateVscodeProperties() file:write(' ],\n') -- defines - file:write(" \"defines\": [\n") + file:write(' "defines": [\n') for i, define in ipairs(prjDefines) do file:write(string.format(' "%s"%s\n', define, i < #prjDefines and "," or "")) end @@ -75,11 +80,56 @@ local function generateVscodeProperties() file:write('}\n') file:close() - else - print("Error: Could not write to .vscode/c_cpp_properties.json.") end end +local function writeTasksConfiguration(file, actionType) + local name = "" + local configuration = "" + local isDefault = "false" + local command = "" + + if actionType == "buildDebug" then + name = "build debug" + configuration = debugConfiguration + command = buildCommand + isDefault = "true" + + elseif actionType == "buildRelease" then + name = "build release" + configuration = releaseConfiguration + command = buildCommand + + elseif actionType == "cleanDebug" then + name = "clean debug" + configuration = debugConfiguration + command = cleanCommand + + elseif actionType == "cleanRelease" then + name = "clean release" + configuration = releaseConfiguration + command = cleanCommand + end + + file:write(" {\n") + file:write(' "type": "shell",\n') + file:write(string.format(' "label": "%s %s",\n', workspaceName, name)) + file:write(string.format(' "command": "%s %s",\n', command, configuration)) + + file:write(' "options": {\n') + file:write(' "cwd": "${workspaceFolder}"\n') + file:write(' },\n') + + file:write(' "problemMatcher": [\n') + file:write(string.format(' "$%s",\n', problemMatcher)) + file:write(' ],\n') + + file:write(' "group": {\n') + file:write(' "kind": "build",\n') + file:write(string.format(' "isDefault": %s\n', isDefault)) + file:write(' }\n') +end + local function generateTasksJson() print("\n=======================================================") print("Generating .vscode/tasks.json") @@ -88,18 +138,45 @@ local function generateTasksJson() if file then file:write('{\n') file:write(' "tasks": [\n') - file:write(" {\n") - file:write(' "type": "shell",\n') - file:write(' "label": "shell",\n') + + writeTasksConfiguration(file, "buildDebug") + file:write(" },\n") + file:write('\n') + writeTasksConfiguration(file, "buildRelease") + file:write(" },\n") + file:write('\n') + + -- clean configurations + writeTasksConfiguration(file, "cleanDebug") + file:write(" },\n") + file:write('\n') + + writeTasksConfiguration(file, "cleanRelease") file:write(" }\n") + file:write(" ],\n") file:write(' "version": "2.0.0"\n') file:write("}\n") file:close() - else - print("Error: Could not write to .vscode/c_cpp_properties.json.") + end +end + +local function writeLaunchConfiguration(file, isDebug) + +end + +local function generateLaunchJson() + print("\n=======================================================") + print("Generating .vscode/launch.json") + + local file = io.open(".vscode/launch.json", "w") + if file then + writeLaunchConfiguration(file, true) + file:write('\n') + writeLaunchConfiguration(file, false) + file:close() end end @@ -156,6 +233,14 @@ workspace(workspaceName) filter {} if (_ACTION == "gmake") then + problemMatcher = "gcc" + command = "make all" + buildCommand = "make all" + cleanCommand = "make clean" + + debugConfiguration = "config=debug" + releaseConfiguration = "config=release" + if os.target() == "windows" then local gccPath = getCommandOutput("where gcc.exe 2>nul") local gccBinPath = path.getdirectory(gccPath) @@ -204,6 +289,13 @@ workspace(workspaceName) end if (_ACTION == "vs2022") or (_ACTION == "vs2026") then + problemMatcher = "msCompile" + command = "msbuild" + cleanCommand = "msbuild /t:clean" + + debugConfiguration = "p:Configuration=Debug" + releaseConfiguration = "p:Configuration=Release" + if (_OPTIONS["compiler"] == "clang") then toolset("clang") From 284996bd142eb1445ff60281f0783e57ca5b08e3 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Jun 2026 16:59:04 +0000 Subject: [PATCH 248/372] add dynamic launch.json file --- premake5.lua | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/premake5.lua b/premake5.lua index c44c2fa6..545afa87 100644 --- a/premake5.lua +++ b/premake5.lua @@ -13,6 +13,7 @@ cleanCommand = "" debugConfiguration = "" releaseConfiguration = "" +debuggerPath = "" local function getCommandOutput(cmd) local result, exitCode = os.outputof(cmd) @@ -164,7 +165,70 @@ local function generateTasksJson() end local function writeLaunchConfiguration(file, isDebug) - + local name = "" + local launchType = "" + local preLaunchTask = "" + + if isDebug then + name = "launch debug" + launchType = "cppdbg" + preLaunchTask = "build debug" + + else + name = "launch release" + launchType = "cppvsdbg" + preLaunchTask = "build release" + end + + file:write(" {\n") + file:write(string.format(' "name": "%s %s",\n', workspaceName, name)) + file:write(string.format(' "type": "%s",\n', launchType)) + file:write(' "request": "launch",\n') + file:write(' "stopAtEntry": false,\n') + file:write(' "cwd": "${workspaceFolder}/tests",\n') + + file:write(' "environment": [],\n') + file:write(' "externalConsole": false,\n') + file:write(string.format(' "preLaunchTask": "%s %s",\n', workspaceName, preLaunchTask)) + + if isDebug then + if os.target() == "windows" then + file:write(' "program": "${workspaceFolder}/bin/Debug/tests.exe",\n') + else + file:write(' "program": "${workspaceFolder}/bin/Debug/tests",\n') + end + + else + if os.target() == "windows" then + file:write(' "program": "${workspaceFolder}/bin/Release/tests.exe",\n') + else + file:write(' "program": "${workspaceFolder}/bin/Release/tests",\n') + end + end + + if launchType == "cppdbg" then + file:write(' "MIMode": "gdb",\n') + file:write(string.format(' "miDebuggerPath": "%s",\n', debuggerPath)) + end + + if isDebug then + file:write(' "setupCommands": [\n') + + file:write(' {\n') + file:write(' "description": "Enable pretty printing for gdb",\n') + file:write(' "text": "-enable-pretty-printing",\n') + file:write(' "ignoreFailures": false,\n') + file:write(' },\n') + + file:write(' {\n') + file:write(' "description": "Set disassembly flavor to intel",\n') + file:write(' "text": "-gdb-set disassembly-flavor intel",\n') + file:write(' "ignoreFailures": false,\n') + file:write(' }\n') + + file:write(' ]\n') + end + end local function generateLaunchJson() @@ -173,9 +237,19 @@ local function generateLaunchJson() local file = io.open(".vscode/launch.json", "w") if file then + file:write('{\n') + file:write(' "configurations": [\n') + writeLaunchConfiguration(file, true) + file:write(" },\n") file:write('\n') + writeLaunchConfiguration(file, false) + file:write(" }\n") + + file:write(" ],\n") + file:write(' "version": "0.2.0"\n') + file:write("}\n") file:close() end end @@ -185,6 +259,7 @@ premake.override(premake.action, "call", function(base, action) base(action) generateVscodeProperties() generateTasksJson() + generateLaunchJson() end) newoption { @@ -245,6 +320,7 @@ workspace(workspaceName) local gccPath = getCommandOutput("where gcc.exe 2>nul") local gccBinPath = path.getdirectory(gccPath) local gccBasePath = path.getdirectory(gccBinPath) + debuggerPath = getCommandOutput("where gdb.exe 2>nul") if (_OPTIONS["compiler"] == "clang") then toolset("clang") From 83a967d11b752dd7f4ba479f0da3f88ecdc31098 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Jun 2026 21:43:09 +0000 Subject: [PATCH 249/372] updated build system working linux --- pal.lua | 31 ++++++++----------------------- premake5.lua | 45 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/pal.lua b/pal.lua index 0acc5b5c..ab6c04e6 100644 --- a/pal.lua +++ b/pal.lua @@ -35,9 +35,6 @@ project "PAL" files { "src/system/pal_system_linux.c" } filter {} - defines { "PAL_HAS_SYSTEM_MODULE = 1" } - else - defines { "PAL_HAS_SYSTEM_MODULE = 0" } end if (PAL_BUILD_THREAD) then @@ -48,9 +45,6 @@ project "PAL" files { "src/thread/pal_thread_linux.c" } filter {} - defines { "PAL_HAS_THREAD_MODULE = 1" } - else - defines { "PAL_HAS_THREAD_MODULE = 0" } end if (PAL_BUILD_VIDEO) then @@ -77,9 +71,9 @@ project "PAL" end if found then - defines { "PAL_HAS_WAYLAND_BACKEND = 1" } + defines { "PAL_HAS_WAYLAND_BACKEND=1" } else - defines { "PAL_HAS_WAYLAND_BACKEND = 0" } + defines { "PAL_HAS_WAYLAND_BACKEND=0" } end -- check for X11 support. This is cross compiler @@ -99,15 +93,12 @@ project "PAL" end if found then - defines { "PAL_HAS_X11_BACKEND = 1" } + defines { "PAL_HAS_X11_BACKEND=1" } else - defines { "PAL_HAS_X11_BACKEND = 0" } + defines { "PAL_HAS_X11_BACKEND=0" } end filter {} - defines { "PAL_HAS_VIDEO_MODULE = 1" } - else - defines { "PAL_HAS_VIDEO_MODULE = 0" } end if (PAL_BUILD_OPENGL) then @@ -118,9 +109,6 @@ project "PAL" files { "src/opengl/pal_opengl_linux.c" } filter {} - defines { "PAL_HAS_OPENGL_MODULE = 1" } - else - defines { "PAL_HAS_OPENGL_MODULE = 0" } end if (PAL_BUILD_GRAPHICS) then @@ -134,9 +122,9 @@ project "PAL" path.join(vulkanSdk, "include") } - defines { "PAL_HAS_VULKAN_BACKEND = 1" } + defines { "PAL_HAS_VULKAN_BACKEND=1" } else - defines { "PAL_HAS_VULKAN_BACKEND = 0" } + defines { "PAL_HAS_VULKAN_BACKEND=0" } end -- check for d3d12 support. This is cross compiler @@ -174,9 +162,9 @@ project "PAL" d3d12Include } - defines { "PAL_HAS_D3D12_BACKEND = 1" } + defines { "PAL_HAS_D3D12_BACKEND=1" } else - defines { "PAL_HAS_D3D12_BACKEND = 0" } + defines { "PAL_HAS_D3D12_BACKEND=0" } end -- base graphics file @@ -197,7 +185,4 @@ project "PAL" end filter {} - defines { "PAL_HAS_GRAPHICS_MODULE = 1" } - else - defines { "PAL_HAS_GRAPHICS_MODULE = 0" } end diff --git a/premake5.lua b/premake5.lua index 545afa87..b56d5279 100644 --- a/premake5.lua +++ b/premake5.lua @@ -49,7 +49,7 @@ local function generateVscodeProperties() end -- write to file - os.execute("mkdir .vscode 2>nul") -- ensure .vscode directory exists + os.execute("mkdir -p .vscode") -- ensure .vscode directory exists local file = io.open(".vscode/c_cpp_properties.json", "w") if file then file:write('{\n') @@ -171,15 +171,19 @@ local function writeLaunchConfiguration(file, isDebug) if isDebug then name = "launch debug" - launchType = "cppdbg" preLaunchTask = "build debug" else name = "launch release" - launchType = "cppvsdbg" preLaunchTask = "build release" end + if os.target() == "windows" then + launchType = "cppvsdbg" + else + launchType = "cppdbg" + end + file:write(" {\n") file:write(string.format(' "name": "%s %s",\n', workspaceName, name)) file:write(string.format(' "type": "%s",\n', launchType)) @@ -361,6 +365,8 @@ workspace(workspaceName) intellisenseMode = "linux-gcc-x64" compilerPath = "/usr/bin/gcc" end + + debuggerPath = "/usr/bin/gdb" end end @@ -395,9 +401,38 @@ workspace(workspaceName) } end + if (PAL_BUILD_SYSTEM) then + defines { "PAL_HAS_SYSTEM_MODULE=1" } + else + defines { "PAL_HAS_SYSTEM_MODULE=0" } + end + + if (PAL_BUILD_THREAD) then + defines { "PAL_HAS_THREAD_MODULE=1" } + else + defines { "PAL_HAS_THREAD_MODULE=0" } + end + + if (PAL_BUILD_VIDEO) then + defines { "PAL_HAS_VIDEO_MODULE=1" } + else + defines { "PAL_HAS_VIDEO_MODULE=0" } + end + + if (PAL_BUILD_OPENGL) then + defines { "PAL_HAS_OPENGL_MODULE=1" } + else + defines { "PAL_HAS_OPENGL_MODULE=0" } + end + + if (PAL_BUILD_GRAPHICS) then + defines { "PAL_HAS_GRAPHICS_MODULE=1" } + else + defines { "PAL_HAS_GRAPHICS_MODULE=0" } + end + if (PAL_BUILD_TESTS) then include "tests/tests.lua" end - include "pal.lua" - \ No newline at end of file + include "pal.lua" \ No newline at end of file From 5c0a26543f7a7e071a65ed63f55098865a833fa5 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 11 Jun 2026 23:50:43 -0700 Subject: [PATCH 250/372] updated build system working windows --- pal.lua | 3 +- premake5.lua | 80 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/pal.lua b/pal.lua index ab6c04e6..cc978ad0 100644 --- a/pal.lua +++ b/pal.lua @@ -148,7 +148,8 @@ project "PAL" end end else - d3d12Include = path.join(ucrt, "include") + -- gccBasePath will be set if we are on gcc + d3d12Include = path.join(gccBasePath, "include") end if (os.isfile(path.join(d3d12Include, "d3d12.h"))) then diff --git a/premake5.lua b/premake5.lua index b56d5279..b2722a8d 100644 --- a/premake5.lua +++ b/premake5.lua @@ -14,6 +14,7 @@ cleanCommand = "" debugConfiguration = "" releaseConfiguration = "" debuggerPath = "" +gccBasePath = "" local function getCommandOutput(cmd) local result, exitCode = os.outputof(cmd) @@ -30,6 +31,20 @@ local function getCommandOutput(cmd) return nil end +local function removeDuplicates(list) + local seen = {} + local out = {} + + for _, v in ipairs(list) do + if not seen[v] then + seen[v] = true + table.insert(out, v) + end + end + + return out +end + local function generateVscodeProperties() print("\n=======================================================") print("Generating .vscode/c_cpp_properties.json") @@ -48,8 +63,12 @@ local function generateVscodeProperties() end end + -- remove duplicates + prjIncludes = removeDuplicates(prjIncludes) + prjDefines = removeDuplicates(prjDefines) + -- write to file - os.execute("mkdir -p .vscode") -- ensure .vscode directory exists + os.mkdir(".vscode") -- ensure .vscode directory exists local file = io.open(".vscode/c_cpp_properties.json", "w") if file then file:write('{\n') @@ -178,10 +197,10 @@ local function writeLaunchConfiguration(file, isDebug) preLaunchTask = "build release" end - if os.target() == "windows" then - launchType = "cppvsdbg" - else + if (_ACTION == "gmake") then launchType = "cppdbg" + else + launchType = "cppvsdbg" end file:write(" {\n") @@ -192,7 +211,12 @@ local function writeLaunchConfiguration(file, isDebug) file:write(' "cwd": "${workspaceFolder}/tests",\n') file:write(' "environment": [],\n') - file:write(' "externalConsole": false,\n') + if launchType == "cppvsdbg" then + file:write(' "console": "internalConsole",\n') + else + file:write(' "externalConsole": false,\n') + end + file:write(string.format(' "preLaunchTask": "%s %s",\n', workspaceName, preLaunchTask)) if isDebug then @@ -213,26 +237,25 @@ local function writeLaunchConfiguration(file, isDebug) if launchType == "cppdbg" then file:write(' "MIMode": "gdb",\n') file:write(string.format(' "miDebuggerPath": "%s",\n', debuggerPath)) - end - if isDebug then - file:write(' "setupCommands": [\n') + if isDebug then + file:write(' "setupCommands": [\n') - file:write(' {\n') - file:write(' "description": "Enable pretty printing for gdb",\n') - file:write(' "text": "-enable-pretty-printing",\n') - file:write(' "ignoreFailures": false,\n') - file:write(' },\n') + file:write(' {\n') + file:write(' "description": "Enable pretty printing for gdb",\n') + file:write(' "text": "-enable-pretty-printing",\n') + file:write(' "ignoreFailures": false,\n') + file:write(' },\n') - file:write(' {\n') - file:write(' "description": "Set disassembly flavor to intel",\n') - file:write(' "text": "-gdb-set disassembly-flavor intel",\n') - file:write(' "ignoreFailures": false,\n') - file:write(' }\n') + file:write(' {\n') + file:write(' "description": "Set disassembly flavor to intel",\n') + file:write(' "text": "-gdb-set disassembly-flavor intel",\n') + file:write(' "ignoreFailures": false,\n') + file:write(' }\n') - file:write(' ]\n') + file:write(' ]\n') + end end - end local function generateLaunchJson() @@ -323,7 +346,7 @@ workspace(workspaceName) if os.target() == "windows" then local gccPath = getCommandOutput("where gcc.exe 2>nul") local gccBinPath = path.getdirectory(gccPath) - local gccBasePath = path.getdirectory(gccBinPath) + gccBasePath = path.getdirectory(gccBinPath) debuggerPath = getCommandOutput("where gdb.exe 2>nul") if (_OPTIONS["compiler"] == "clang") then @@ -381,12 +404,23 @@ workspace(workspaceName) if (_OPTIONS["compiler"] == "clang") then toolset("clang") - intellisenseMode = "windows-clang-x64" + intellisenseMode = "windows-clang-x64"; compilerPath = getCommandOutput("where clang.exe 2>nul") else -- MSVC intellisenseMode = "windows-msvc-x64" - compilerPath = getCommandOutput("where cl.exe 2>nul") + local base = "C:/Program Files/Microsoft Visual Studio/18/Community/VC/Tools/MSVC" + local versions = os.matchdirs(base .. "/*") + table.sort(versions) + + for i = #versions, 1, -1 do + local v = versions[i] + local tmp = path.join(v, "bin") + if (os.isdir(tmp)) then + compilerPath = path.join(tmp, "Hostx64/x64/cl.exe") + break + end + end end defines { From 2dd99036975c8e2d5a941a27e32b10d3cdbc4cd6 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 12 Jun 2026 11:34:47 +0000 Subject: [PATCH 251/372] finalize build system --- README.md | 1 - pal.lua | 40 +++++++-------- premake5.lua | 134 ++++++++++++++------------------------------------- 3 files changed, 54 insertions(+), 121 deletions(-) diff --git a/README.md b/README.md index 743dde6d..5dd412ad 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,6 @@ PAL is written in **C99** and uses Premake as its build system. Configure module See [pal_config.h](./include/pal/pal_config.h) to see the reflection of modules that will be built. // TODO: docs -os.getenv("D3D12_INCLUDE") const char* resName = getenv("RESOURCE_NAME"); const char* resClass = getenv("RESOURCE_CLASS"); diff --git a/pal.lua b/pal.lua index cc978ad0..661ee975 100644 --- a/pal.lua +++ b/pal.lua @@ -129,32 +129,26 @@ project "PAL" -- check for d3d12 support. This is cross compiler local hasD3D12 = false - local d3d12Include = os.getenv("D3D12_INCLUDE") - if (os.isfile(path.join(d3d12Include, "d3d12.h"))) then - hasD3D12 = true - - else - if (_ACTION == "vs2022") or (_ACTION == "vs2026") then - d3d12Include = "" - local base = "C:/Program Files (x86)/Windows Kits/10/Include" - local versions = os.matchdirs(base .. "/*") - table.sort(versions) - - for i = #versions, 1, -1 do - local v = versions[i] - d3d12Include = path.join(v, "um") - if (os.isdir(d3d12Include)) then - break - end + local d3d12Include = "" + if (_ACTION == "vs2022") or (_ACTION == "vs2026") then + local base = "C:/Program Files (x86)/Windows Kits/10/Include" + local versions = os.matchdirs(base .. "/*") + table.sort(versions) + + for i = #versions, 1, -1 do + local v = versions[i] + d3d12Include = path.join(v, "um") + if (os.isdir(d3d12Include)) then + break end - else - -- gccBasePath will be set if we are on gcc - d3d12Include = path.join(gccBasePath, "include") end + else + -- gccBasePath will be set if we are on gcc + d3d12Include = path.join(gccBasePath, "include") + end - if (os.isfile(path.join(d3d12Include, "d3d12.h"))) then - hasD3D12 = true - end + if (os.isfile(path.join(d3d12Include, "d3d12.h"))) then + hasD3D12 = true end if (hasD3D12) then diff --git a/premake5.lua b/premake5.lua index b2722a8d..ef3ec835 100644 --- a/premake5.lua +++ b/premake5.lua @@ -7,12 +7,6 @@ objDir = "%{wks.location}/build" workspaceName = "PALWorkspace" compilerPath = "" intellisenseMode = "" -problemMatcher = "" -buildCommand = "" -cleanCommand = "" - -debugConfiguration = "" -releaseConfiguration = "" debuggerPath = "" gccBasePath = "" @@ -105,43 +99,38 @@ end local function writeTasksConfiguration(file, actionType) local name = "" - local configuration = "" local isDefault = "false" local command = "" if actionType == "buildDebug" then name = "build debug" - configuration = debugConfiguration - command = buildCommand + command = "make all config=debug" isDefault = "true" elseif actionType == "buildRelease" then name = "build release" - configuration = releaseConfiguration - command = buildCommand + command = "make all config=release" elseif actionType == "cleanDebug" then name = "clean debug" - configuration = debugConfiguration - command = cleanCommand + command = "make clean config=debug" elseif actionType == "cleanRelease" then name = "clean release" - configuration = releaseConfiguration - command = cleanCommand + command = "make clean config=release" end file:write(" {\n") file:write(' "type": "shell",\n') file:write(string.format(' "label": "%s %s",\n', workspaceName, name)) - file:write(string.format(' "command": "%s %s",\n', command, configuration)) + file:write(string.format(' "command": "%s",\n', command)) file:write(' "options": {\n') file:write(' "cwd": "${workspaceFolder}"\n') file:write(' },\n') file:write(' "problemMatcher": [\n') - file:write(string.format(' "$%s",\n', problemMatcher)) + file:write(' "$gcc",\n') file:write(' ],\n') file:write(' "group": {\n') @@ -185,76 +174,56 @@ end local function writeLaunchConfiguration(file, isDebug) local name = "" - local launchType = "" local preLaunchTask = "" + local dir = "" if isDebug then name = "launch debug" preLaunchTask = "build debug" + dir = "Debug" else name = "launch release" preLaunchTask = "build release" + dir = "Release" end - if (_ACTION == "gmake") then - launchType = "cppdbg" + if os.target() == "windows" then + program = "tests.exe" else - launchType = "cppvsdbg" + program = "tests" end file:write(" {\n") file:write(string.format(' "name": "%s %s",\n', workspaceName, name)) - file:write(string.format(' "type": "%s",\n', launchType)) + file:write(' "type": "cppdbg",\n') file:write(' "request": "launch",\n') file:write(' "stopAtEntry": false,\n') file:write(' "cwd": "${workspaceFolder}/tests",\n') file:write(' "environment": [],\n') - if launchType == "cppvsdbg" then - file:write(' "console": "internalConsole",\n') - else - file:write(' "externalConsole": false,\n') - end - + file:write(' "externalConsole": false,\n') file:write(string.format(' "preLaunchTask": "%s %s",\n', workspaceName, preLaunchTask)) + file:write(string.format(' "program": "${workspaceFolder}/bin/%s/%s",\n', dir, program)) + file:write(' "MIMode": "gdb",\n') + file:write(string.format(' "miDebuggerPath": "%s",\n', debuggerPath)) if isDebug then - if os.target() == "windows" then - file:write(' "program": "${workspaceFolder}/bin/Debug/tests.exe",\n') - else - file:write(' "program": "${workspaceFolder}/bin/Debug/tests",\n') - end - - else - if os.target() == "windows" then - file:write(' "program": "${workspaceFolder}/bin/Release/tests.exe",\n') - else - file:write(' "program": "${workspaceFolder}/bin/Release/tests",\n') - end - end + file:write(' "setupCommands": [\n') - if launchType == "cppdbg" then - file:write(' "MIMode": "gdb",\n') - file:write(string.format(' "miDebuggerPath": "%s",\n', debuggerPath)) + file:write(' {\n') + file:write(' "description": "Enable pretty printing for gdb",\n') + file:write(' "text": "-enable-pretty-printing",\n') + file:write(' "ignoreFailures": false,\n') + file:write(' },\n') - if isDebug then - file:write(' "setupCommands": [\n') + file:write(' {\n') + file:write(' "description": "Set disassembly flavor to intel",\n') + file:write(' "text": "-gdb-set disassembly-flavor intel",\n') + file:write(' "ignoreFailures": false,\n') + file:write(' }\n') - file:write(' {\n') - file:write(' "description": "Enable pretty printing for gdb",\n') - file:write(' "text": "-enable-pretty-printing",\n') - file:write(' "ignoreFailures": false,\n') - file:write(' },\n') - - file:write(' {\n') - file:write(' "description": "Set disassembly flavor to intel",\n') - file:write(' "text": "-gdb-set disassembly-flavor intel",\n') - file:write(' "ignoreFailures": false,\n') - file:write(' }\n') - - file:write(' ]\n') - end + file:write(' ]\n') end end @@ -281,12 +250,16 @@ local function generateLaunchJson() end end --- generate vscode properties +-- generate vscode properties if using gmake premake.override(premake.action, "call", function(base, action) base(action) - generateVscodeProperties() - generateTasksJson() - generateLaunchJson() + + if action == "gmake" then + generateVscodeProperties() + generateTasksJson() + generateLaunchJson() + end + end) newoption { @@ -335,14 +308,6 @@ workspace(workspaceName) filter {} if (_ACTION == "gmake") then - problemMatcher = "gcc" - command = "make all" - buildCommand = "make all" - cleanCommand = "make clean" - - debugConfiguration = "config=debug" - releaseConfiguration = "config=release" - if os.target() == "windows" then local gccPath = getCommandOutput("where gcc.exe 2>nul") local gccBinPath = path.getdirectory(gccPath) @@ -394,33 +359,8 @@ workspace(workspaceName) end if (_ACTION == "vs2022") or (_ACTION == "vs2026") then - problemMatcher = "msCompile" - command = "msbuild" - cleanCommand = "msbuild /t:clean" - - debugConfiguration = "p:Configuration=Debug" - releaseConfiguration = "p:Configuration=Release" - if (_OPTIONS["compiler"] == "clang") then toolset("clang") - - intellisenseMode = "windows-clang-x64"; - compilerPath = getCommandOutput("where clang.exe 2>nul") - else - -- MSVC - intellisenseMode = "windows-msvc-x64" - local base = "C:/Program Files/Microsoft Visual Studio/18/Community/VC/Tools/MSVC" - local versions = os.matchdirs(base .. "/*") - table.sort(versions) - - for i = #versions, 1, -1 do - local v = versions[i] - local tmp = path.join(v, "bin") - if (os.isdir(tmp)) then - compilerPath = path.join(tmp, "Hostx64/x64/cl.exe") - break - end - end end defines { From 1ab540e3231dcf49d6d0dd19aebce3143189874e Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 12 Jun 2026 15:37:39 +0000 Subject: [PATCH 252/372] expand core system to multiple files --- README.md | 2 +- include/pal/core/defines.h | 131 ++++++++ include/pal/core/log.h | 67 ++++ include/pal/core/memory.h | 106 +++++++ include/pal/core/pack.h | 202 ++++++++++++ include/pal/core/result.h | 101 ++++++ include/pal/core/time.h | 46 +++ include/pal/core/version.h | 57 ++++ include/pal/pal_core.h | 633 +------------------------------------ pal.lua | 20 +- pal_config.lua | 14 +- premake5.lua | 16 +- src/core/pal_log.c | 193 +++++++++++ src/core/pal_memory.c | 66 ++++ src/core/pal_result.c | 187 +++++++++++ src/core/pal_time.c | 51 +++ src/core/pal_version.c | 27 ++ src/pal_core.c | 552 -------------------------------- tests/tests.lua | 18 +- tests/tests_main.c | 6 +- 20 files changed, 1286 insertions(+), 1209 deletions(-) create mode 100644 include/pal/core/defines.h create mode 100644 include/pal/core/log.h create mode 100644 include/pal/core/memory.h create mode 100644 include/pal/core/pack.h create mode 100644 include/pal/core/result.h create mode 100644 include/pal/core/time.h create mode 100644 include/pal/core/version.h create mode 100644 src/core/pal_log.c create mode 100644 src/core/pal_memory.c create mode 100644 src/core/pal_result.c create mode 100644 src/core/pal_time.c create mode 100644 src/core/pal_version.c delete mode 100644 src/pal_core.c diff --git a/README.md b/README.md index 5dd412ad..f9afe225 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ premake\premake5.exe vs2022 --compiler=clang ./premake/premake5 gmake # generate Makefiles (default: GCC) ``` -Enable tests in `pal_config.lua` by setting `PAL_BUILD_TESTS = true`. +Enable tests in `pal_config.lua` by setting `PAL_BUILD_TEST_APPLICATION = true`. --- diff --git a/include/pal/core/defines.h b/include/pal/core/defines.h new file mode 100644 index 00000000..c40961ae --- /dev/null +++ b/include/pal/core/defines.h @@ -0,0 +1,131 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup defines Base defines + * @ingroup pal_core + * @{ + */ + +#ifndef _CORE_DEFINES_H +#define _CORE_DEFINES_H + +#include + +#ifdef __cplusplus +#define PAL_EXTERN_C extern "C" +#else +#define PAL_EXTERN_C +#define nullptr ((void*)0) +#define true 1 +#define false 0 + +/** + * @brief A bool + * @since 1.0 + */ +typedef _Bool bool; +#endif // __cplusplus + +// Set up shared library dependencies +#ifdef _WIN32 +#define PAL_CALL __stdcall +#ifdef _PAL_EXPORT +#define PAL_DECLSPEC PAL_EXTERN_C __declspec(dllexport) +#else +#define PAL_DECLSPEC PAL_EXTERN_C __declspec(dllimport) +#endif // PAL_EXPORT +#else +// other plafforms +#define PAL_CALL +#ifdef _PAL_EXPORT +#define PAL_DECLSPEC PAL_EXTERN_C __attribute__((visibility("default"))) +#else +#define PAL_DECLSPEC PAL_EXTERN_C +#endif // PAL_EXPORT +#endif // _WIN32 + +#ifdef _PAL_BUILD_DLL +#define PAL_API PAL_EXTERN_C PAL_DECLSPEC +#else +// static library +#define PAL_API PAL_EXTERN_C +#endif // _PAL_BUILD_DLL + +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define PAL_BIG_ENDIAN 1 +#else +#define PAL_BIG_ENDIAN 0 +#endif // __ORDER_BIG_ENDIAN__ + +#define PAL_BIT(x) 1 << x +#define PAL_BIT64(x) 1ULL << x +#define PAL_INFINITE UINT32_MAX + +/** + * @brief A signed 8-bit integer + * @since 1.0 + */ +typedef int8_t Int8; + +/** + * @brief A signed 16-bit integer + * @since 1.0 + */ +typedef int16_t Int16; + +/** + * @brief A signed 32-bit integer + * @since 1.0 + */ +typedef int32_t Int32; + +/** + * @brief A signed 64-bit integer + * @since 1.0 + */ +typedef int64_t Int64; + +/** + * @brief A signed 64-bit integer pointer + * @since 1.0 + */ +typedef intptr_t IntPtr; + +/** + * @brief An unsigned 8-bit integer + * @since 1.0 + */ +typedef uint8_t Uint8; + +/** + * @brief An unsigned 16-bit integer + * @since 1.0 + */ +typedef uint16_t Uint16; + +/** + * @brief An unsigned 32-bit integer + * @since 1.0 + */ +typedef uint32_t Uint32; + +/** + * @brief An unsigned 64-bit integer + * @since 1.0 + */ +typedef uint64_t Uint64; + +/** + * @brief An unsigned 64-bit integer pointer + * @since 1.0 + */ +typedef uintptr_t UintPtr; + +#endif // _CORE_DEFINES_H + +/** @} */ \ No newline at end of file diff --git a/include/pal/core/log.h b/include/pal/core/log.h new file mode 100644 index 00000000..892a8797 --- /dev/null +++ b/include/pal/core/log.h @@ -0,0 +1,67 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup log Log System + * @ingroup pal_core + * @{ + */ + +#ifndef _CORE_LOG_H +#define _CORE_LOG_H + +#include "defines.h" + +/** + * @typedef PalLogCallback + * @brief Function pointer type used for log callbacks. + * + * @param userData Optional pointer to user data passed from ::PalLogger. Can be nullptr. + * @param msg Null-terminated UTF-8 log message. + * + * @since 1.0 + * @sa palLog + */ +typedef void(PAL_CALL* PalLogCallback)( + void* userData, + const char* msg); + +/** + * @struct PalLogger + * @brief Logging configuration. + * + * Provides a callback and user data for handling log messages. + * + * @since 1.0 + */ +typedef struct { + PalLogCallback callback; + void* userData; /** Optional user-provided data. Can be nullptr.*/ +} PalLogger; + +/** + * Log a formatted message. + * + * @param logger Logger instance. Set to nullptr to use default logger. + * @param fmt printf-style format string. + * @param ... Arguments for the format string. + * + * Thread safety: Thread safe, but log output and + * callbacks may be invoked concurrently. The user must ensure the callback + * implementation is thread safe. + * + * @since 1.0 + * @sa palFormatResult + */ +PAL_API void PAL_CALL palLog( + const PalLogger* logger, + const char* fmt, + ...); + +#endif // _CORE_LOG_H + +/** @} */ \ No newline at end of file diff --git a/include/pal/core/memory.h b/include/pal/core/memory.h new file mode 100644 index 00000000..7b4c0425 --- /dev/null +++ b/include/pal/core/memory.h @@ -0,0 +1,106 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup memory Memory System + * @ingroup pal_core + * @{ + */ + +#ifndef _CORE_MEMORY_H +#define _CORE_MEMORY_H + +#include "defines.h" + +/** + * @typedef PalAllocateFn + * @brief Function pointer type used for memory allocations. + * + * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. + * @param[in] size Number of bytes to allocate. Must not be 0. + * @param[in] alignment Must be power of two. Set to 0 to use default (16). + * + * @return Pointer to the allocated memory on success or nullptr on failure. + * + * @since 1.0 + * @sa PalFreeFn + */ +typedef void*(PAL_CALL* PalAllocateFn)( + void* userData, + Uint64 size, + Uint64 alignment); + +/** + * @typedef PalFreeFn + * @brief Function pointer type used for memory deallocations. + * + * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. + * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must return safely if + * pointer is nullptr. + * + * @since 1.0 + * @sa PalAllocateFn + */ +typedef void(PAL_CALL* PalFreeFn)( + void* userData, + void* ptr); + +/** + * @struct PalAllocator + * @brief Custom memory allocator. + * + * Provides user-defined memory allocation and free functions. + * + * @since 1.0 + */ +typedef struct { + PalAllocateFn allocate; + PalFreeFn free; + void* userData; /**< Optional user-provided data. Can be nullptr.*/ +} PalAllocator; + +/** + * Allocate memory using the provided allocator. + * + * @param allocator The allocator to use. Set to nullptr to use default. + * @param size Number of bytes to allocate. + * @param alignment Alignment in bytes. Must be a power of two. + * + * @return Pointer to allocated memory on success, or nullptr on failure. + * + * Thread safety: Thread safe only if the provided allocator is thread safe. The default allocator + * is thread safe. + * + * @since 1.0 + * @sa palFree + */ +PAL_API void* PAL_CALL palAllocate( + const PalAllocator* allocator, + Uint64 size, + Uint64 alignment); + +/** + * Free memory allocated by palAllocate. + * + * @param allocator The allocator used to allocate the memory. Set to nullptr to + * use default. + * @param ptr Pointer to memory to free. If nullptr, the function returns + * silently. + * + * Thread safety: Thread safe only if the provided allocator is thread + * safe. The default allocator is thread safe. + * + * @since 1.0 + * @sa palAllocate + */ +PAL_API void PAL_CALL palFree( + const PalAllocator* allocator, + void* ptr); + +#endif // _CORE_MEMORY_H + +/** @} */ \ No newline at end of file diff --git a/include/pal/core/pack.h b/include/pal/core/pack.h new file mode 100644 index 00000000..ee8aa73f --- /dev/null +++ b/include/pal/core/pack.h @@ -0,0 +1,202 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup pack Packing and unpacking helpers + * @ingroup pal_core + * @{ + */ + +#ifndef _CORE_PACK_H +#define _CORE_PACK_H + +#include "defines.h" +#include + +/** + * @brief Combine two 32-bit unsigned integers into a single 64-bit signed + * integer. + * + * @return The combined 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palUnpackUint32 + */ +static inline Int64 PAL_CALL palPackUint32( + Uint32 low, + Uint32 high) +{ + return (Int64)(((Uint64)high << 32) | (Uint64)low); +} + +/** + * @brief Combine two 32-bit signed integers into a single 64-bit signed + * integer. + * + * @return The combined 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palUnpackInt32 + */ +static inline Int64 PAL_CALL palPackInt32( + Int32 low, + Int32 high) +{ + return ((Int64)(Uint32)high << 32) | (Uint32)low; +} + +/** + * @brief Pack a pointer into a 64-bit signed integer. + * + * @return The packed 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palUnpackPointer + */ +static inline Int64 PAL_CALL palPackPointer(void* ptr) +{ + return (Int64)(UintPtr)ptr; +} + +/** + * @brief Combine two floats into a single 64-bit signed integer. + * + * @return The combined 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.3 + * @sa palUnpackFloat + */ +static inline Int64 PAL_CALL palPackFloat( + float low, + float high) +{ + Int64 combined = 0; +#if PAL_BIG_ENDIAN + memcpy(&((Uint32*)&combined)[0], &high, sizeof(float)); + memcpy(&((Uint32*)&combined)[1], &low, sizeof(float)); +#else + memcpy(&((Uint32*)&combined)[0], &low, sizeof(float)); + memcpy(&((Uint32*)&combined)[1], &high, sizeof(float)); +#endif // PAL_BIG_ENDIAN + + return combined; +} + +/** + * @brief Retrieve two 32-bit unsigned integers from a 64-bit signed integer. + * + * @param[out] outLow Low value of the 64-bit signed integer. + * @param[out] outHigh High value of the 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palPackUint32 + */ +static inline void PAL_CALL palUnpackUint32( + Int64 data, + Uint32* outLow, + Uint32* outHigh) +{ + if (outLow) { + *outLow = (Uint32)(data & 0xFFFFFFFF); + } + + if (outHigh) { + *outHigh = (Uint32)((Uint64)data >> 32); + } +} + +/** + * @brief Retrieve two 32-bit signed integers from a 64-bit signed integer. + * + * @param[out] outLow Low value of the 64-bit signed integer. + * @param[out] outHigh High value of the 64-bit signed integer. + * + * Thread safety: Thread-safe if `outLow` and `outHigh` are + * thread local. + * + * @since 1.0 + * @sa palPackInt32 + */ +static inline void PAL_CALL palUnpackInt32( + Int64 data, + Int32* outLow, + Int32* outHigh) +{ + if (outLow) { + *outLow = (Int32)(data & 0xFFFFFFFF); + } + + if (outHigh) { + *outHigh = (Int32)((Uint64)data >> 32); + } +} + +/** + * @brief Unpack a pointer from a 64-bit signed integer. + * + * @return The pointer from the 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palPackPointer + */ +static inline void* PAL_CALL palUnpackPointer(Int64 data) +{ + return (void*)(UintPtr)data; +} + +/** + * @brief Retrieve two floats from a 64-bit signed integer. + * + * @param[out] outLow Low value of the 64-bit signed integer. + * @param[out] outHigh High value of the 64-bit signed integer. + * + * Thread safety: Thread-safe if `outLow` and `outHigh` are + * thread local. + * + * @since 1.3 + * @sa palPackFloat + */ +static inline void PAL_CALL palUnpackFloat( + Int64 data, + float* low, + float* high) +{ +#if PAL_BIG_ENDIAN + if (low) { + memcpy(low, &((Uint32*)&data)[1], sizeof(float)); + } + + if (high) { + memcpy(high, &((Uint32*)&data)[0], sizeof(float)); + } +#else + if (low) { + memcpy(low, &((Uint32*)&data)[0], sizeof(float)); + } + + if (high) { + memcpy(high, &((Uint32*)&data)[1], sizeof(float)); + } + +#endif // PAL_BIG_ENDIAN +} + +#endif // _CORE_PACK_H + +/** @} */ \ No newline at end of file diff --git a/include/pal/core/result.h b/include/pal/core/result.h new file mode 100644 index 00000000..8bf8e6cc --- /dev/null +++ b/include/pal/core/result.h @@ -0,0 +1,101 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup result Result codes + * @ingroup pal_core + * @{ + */ + +#ifndef _CORE_RESULT_H +#define _CORE_RESULT_H + +#include "defines.h" + +/** + * @enum PalResult + * @brief Codes returned by most PAL functions. This is not a bitmask. + * + * All result codes follow the format `PAL_RESULT_**` for consistency and API use. + * + * @since 1.0 + */ +typedef enum { + PAL_RESULT_SUCCESS, + PAL_RESULT_NULL_POINTER, + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_INVALID_ALLOCATOR, + PAL_RESULT_ACCESS_DENIED, + PAL_RESULT_TIMEOUT, + PAL_RESULT_INSUFFICIENT_BUFFER, + PAL_RESULT_INVALID_THREAD, + PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED, + PAL_RESULT_VIDEO_NOT_INITIALIZED, + PAL_RESULT_INVALID_MONITOR, + PAL_RESULT_INVALID_MONITOR_MODE, + PAL_RESULT_INVALID_WINDOW, + PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED, + PAL_RESULT_INVALID_KEYCODE, + PAL_RESULT_INVALID_SCANCODE, + PAL_RESULT_INVALID_MOUSE_BUTTON, + PAL_RESULT_INVALID_ORIENTATION, + PAL_RESULT_GL_NOT_INITIALIZED, + PAL_RESULT_INVALID_GL_WINDOW, + PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED, + PAL_RESULT_INVALID_GL_FBCONFIG, + PAL_RESULT_INVALID_GL_VERSION, + PAL_RESULT_INVALID_GL_PROFILE, + PAL_RESULT_INVALID_GL_CONTEXT, + PAL_RESULT_INVALID_FBCONFIG_BACKEND, + PAL_RESULT_GRAPHICS_NOT_INITIALIZED, + PAL_RESULT_INVALID_ADAPTER, + PAL_RESULT_INVALID_BACKEND, + PAL_RESULT_QUEUE_NOT_SUPPORTED, + PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED, + PAL_RESULT_INVALID_DRIVER, + PAL_RESULT_INVALID_DEVICE, + PAL_RESULT_INVALID_QUEUE, + PAL_RESULT_OUT_OF_QUEUE, + PAL_RESULT_INVALID_GRAPHICS_WINDOW, + PAL_RESULT_INVALID_SWAPCHAIN, + PAL_RESULT_INVALID_IMAGE, + PAL_RESULT_INVALID_IMAGE_VIEW, + PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED, + PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_INVALID_SHADER, + PAL_RESULT_INVALID_SHADER_TYPE, + PAL_RESULT_INVALID_COMMAND_POOL, + PAL_RESULT_INVALID_COMMAND_BUFFER, + PAL_RESULT_INVALID_FENCE, + PAL_RESULT_INVALID_SEMAPHORE, + PAL_RESULT_INVALID_BUFFER, + PAL_RESULT_INVALID_ACCELERATION_STRUCTURE, + PAL_RESULT_INVALID_PIPELINE, + PAL_RESULT_MEMORY_MAP_FAILED, + PAL_RESULT_DEVICE_LOST, + PAL_RESULT_SURFACE_LOST, + PAL_RESULT_SWAPCHAIN_OUT_OF_DATE +} PalResult; + +/** + * Convert a result code to a human-readable string. + * + * @param result The PalResult code to format. + * + * @return Null-terminated static string describing the result. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API const char* PAL_CALL palFormatResult(PalResult result); + +#endif // _CORE_RESULT_H + +/** @} */ \ No newline at end of file diff --git a/include/pal/core/time.h b/include/pal/core/time.h new file mode 100644 index 00000000..e10f97c7 --- /dev/null +++ b/include/pal/core/time.h @@ -0,0 +1,46 @@ + + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup time Time System + * @ingroup pal_core + * @{ + */ + +#ifndef _CORE_TIME_H +#define _CORE_TIME_H + +#include "defines.h" + +/** + * Query a high-resolution performance counter value. + * + * @return Current performance counter value. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palGetPerformanceFrequency + */ +PAL_API Uint64 PAL_CALL palGetPerformanceCounter(); + +/** + * Query the frequency of the high-resolution performance counter. + * + * @return Performance counter frequency, in counts per second. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palGetPerformanceCounter + */ +PAL_API Uint64 PAL_CALL palGetPerformanceFrequency(); + +#endif // _CORE_TIME_H + +/** @} */ \ No newline at end of file diff --git a/include/pal/core/version.h b/include/pal/core/version.h new file mode 100644 index 00000000..2324f0d9 --- /dev/null +++ b/include/pal/core/version.h @@ -0,0 +1,57 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup version Versioning + * @ingroup pal_core + * @{ + */ + +#ifndef _CORE_VERSION_H +#define _CORE_VERSION_H + +#include "defines.h" + +/** + * @struct PalVersion + * @brief Describes the version of PAL. + * + * @since 1.0 + */ +typedef struct { + Uint32 major; /**< Major version (breaking changes).*/ + Uint32 minor; /**< Minor version (adding features).*/ + Uint32 build; /**< Build version (bug fixes).*/ +} PalVersion; + +/** + * Retrieve the PAL version number. + * + * @return PAL version (major, minor, build). + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palGetVersionString + */ +PAL_API PalVersion PAL_CALL palGetVersion(); + +/** + * Retrieve the PAL version string. + * + * @return Null-terminated string containing the PAL version. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palGetVersion + */ +PAL_API const char* PAL_CALL palGetVersionString(); + +#endif // _CORE_VERSION_H + +/** @} */ \ No newline at end of file diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index f8dd6bf2..5d44a809 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -1,635 +1,26 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ /** - * @defgroup pal_core Core - * Core PAL functionality such as versioning, memory allocation, logging, and - * timing. - * + * @defgroup pal_core Core System * @{ */ #ifndef _PAL_CORE_H #define _PAL_CORE_H -#include -#include - -#ifdef __cplusplus -#define PAL_EXTERN_C extern "C" -#else -#define PAL_EXTERN_C -#define nullptr ((void*)0) -#define true 1 -#define false 0 - -/** - * @brief A bool - * @since 1.0 - * @ingroup pal_core - */ -typedef _Bool bool; -#endif // __cplusplus - -// Set up shared library dependencies -#ifdef _WIN32 -#define PAL_CALL __stdcall -#ifdef _PAL_EXPORT -#define PAL_DECLSPEC PAL_EXTERN_C __declspec(dllexport) -#else -#define PAL_DECLSPEC PAL_EXTERN_C __declspec(dllimport) -#endif // PAL_EXPORT -#else -// other plafforms -#define PAL_CALL -#ifdef _PAL_EXPORT -#define PAL_DECLSPEC PAL_EXTERN_C __attribute__((visibility("default"))) -#else -#define PAL_DECLSPEC PAL_EXTERN_C -#endif // PAL_EXPORT -#endif // _WIN32 - -#ifdef _PAL_BUILD_DLL -#define PAL_API PAL_EXTERN_C PAL_DECLSPEC -#else -// static library -#define PAL_API PAL_EXTERN_C -#endif // _PAL_BUILD_DLL - -#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define PAL_BIG_ENDIAN 1 -#else -#define PAL_BIG_ENDIAN 0 -#endif // __ORDER_BIG_ENDIAN__ - -#define PAL_BIT(x) 1 << x -#define PAL_BIT64(x) 1ULL << x -#define PAL_INFINITE UINT32_MAX - -/** - * @brief A signed 8-bit integer - * @since 1.0 - * @ingroup pal_core - */ -typedef int8_t Int8; - -/** - * @brief A signed 16-bit integer - * @since 1.0 - * @ingroup pal_core - */ -typedef int16_t Int16; - -/** - * @brief A signed 32-bit integer - * @since 1.0 - * @ingroup pal_core - */ -typedef int32_t Int32; - -/** - * @brief A signed 64-bit integer - * @since 1.0 - * @ingroup pal_core - */ -typedef int64_t Int64; - -/** - * @brief A signed 64-bit integer pointer - * @since 1.0 - * @ingroup pal_core - */ -typedef intptr_t IntPtr; - -/** - * @brief An unsigned 8-bit integer - * @since 1.0 - * @ingroup pal_core - */ -typedef uint8_t Uint8; - -/** - * @brief An unsigned 16-bit integer - * @since 1.0 - * @ingroup pal_core - */ -typedef uint16_t Uint16; - -/** - * @brief An unsigned 32-bit integer - * @since 1.0 - * @ingroup pal_core - */ -typedef uint32_t Uint32; - -/** - * @brief An unsigned 64-bit integer - * @since 1.0 - * @ingroup pal_core - */ -typedef uint64_t Uint64; - -/** - * @brief An unsigned 64-bit integer pointer - * @since 1.0 - * @ingroup pal_core - */ -typedef uintptr_t UintPtr; - -/** - * @typedef PalAllocateFn - * @brief Function pointer type used for memory allocations. - * - * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. - * @param[in] size Number of bytes to allocate. Must not be 0. - * @param[in] alignment Must be power of two. Set to 0 to use default (16). - * - * @return Pointer to the allocated memory on success or nullptr on failure. - * - * @since 1.0 - * @ingroup pal_core - * @sa PalFreeFn - */ -typedef void*(PAL_CALL* PalAllocateFn)( - void* userData, - Uint64 size, - Uint64 alignment); - -/** - * @typedef PalFreeFn - * @brief Function pointer type used for memory deallocations. - * - * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. - * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must return safely if - * pointer is nullptr. - * - * @since 1.0 - * @ingroup pal_core - * @sa PalAllocateFn - */ -typedef void(PAL_CALL* PalFreeFn)( - void* userData, - void* ptr); - -/** - * @typedef PalLogCallback - * @brief Function pointer type used for log callbacks. - * - * @param userData Optional pointer to user data passed from ::PalLogger. Can be nullptr. - * @param msg Null-terminated UTF-8 log message. - * - * @since 1.0 - * @ingroup pal_core - * @sa palLog - */ -typedef void(PAL_CALL* PalLogCallback)( - void* userData, - const char* msg); - -/** - * @enum PalResult - * @brief Codes returned by most PAL functions. This is not a bitmask. - * - * All result codes follow the format `PAL_RESULT_**` for consistency and API use. - * - * @since 1.0 - * @ingroup pal_core - */ -typedef enum { - PAL_RESULT_SUCCESS, - PAL_RESULT_NULL_POINTER, - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_INVALID_ALLOCATOR, - PAL_RESULT_ACCESS_DENIED, - PAL_RESULT_TIMEOUT, - PAL_RESULT_INSUFFICIENT_BUFFER, - PAL_RESULT_INVALID_THREAD, - PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED, - PAL_RESULT_VIDEO_NOT_INITIALIZED, - PAL_RESULT_INVALID_MONITOR, - PAL_RESULT_INVALID_MONITOR_MODE, - PAL_RESULT_INVALID_WINDOW, - PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED, - PAL_RESULT_INVALID_KEYCODE, - PAL_RESULT_INVALID_SCANCODE, - PAL_RESULT_INVALID_MOUSE_BUTTON, - PAL_RESULT_INVALID_ORIENTATION, - PAL_RESULT_GL_NOT_INITIALIZED, - PAL_RESULT_INVALID_GL_WINDOW, - PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED, - PAL_RESULT_INVALID_GL_FBCONFIG, - PAL_RESULT_INVALID_GL_VERSION, - PAL_RESULT_INVALID_GL_PROFILE, - PAL_RESULT_INVALID_GL_CONTEXT, - PAL_RESULT_INVALID_FBCONFIG_BACKEND, - PAL_RESULT_GRAPHICS_NOT_INITIALIZED, - PAL_RESULT_INVALID_ADAPTER, - PAL_RESULT_INVALID_BACKEND, - PAL_RESULT_QUEUE_NOT_SUPPORTED, - PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED, - PAL_RESULT_INVALID_DRIVER, - PAL_RESULT_INVALID_DEVICE, - PAL_RESULT_INVALID_QUEUE, - PAL_RESULT_OUT_OF_QUEUE, - PAL_RESULT_INVALID_GRAPHICS_WINDOW, - PAL_RESULT_INVALID_SWAPCHAIN, - PAL_RESULT_INVALID_IMAGE, - PAL_RESULT_INVALID_IMAGE_VIEW, - PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED, - PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_INVALID_SHADER, - PAL_RESULT_INVALID_SHADER_TYPE, - PAL_RESULT_INVALID_COMMAND_POOL, - PAL_RESULT_INVALID_COMMAND_BUFFER, - PAL_RESULT_INVALID_FENCE, - PAL_RESULT_INVALID_SEMAPHORE, - PAL_RESULT_INVALID_BUFFER, - PAL_RESULT_INVALID_ACCELERATION_STRUCTURE, - PAL_RESULT_INVALID_PIPELINE, - PAL_RESULT_MEMORY_MAP_FAILED, - PAL_RESULT_DEVICE_LOST, - PAL_RESULT_SURFACE_LOST, - PAL_RESULT_SWAPCHAIN_OUT_OF_DATE -} PalResult; - -/** - * @struct PalVersion - * @brief Describes the version of PAL. - * - * @since 1.0 - * @ingroup pal_core - */ -typedef struct { - Uint32 major; /**< Major version (breaking changes).*/ - Uint32 minor; /**< Minor version (adding features).*/ - Uint32 build; /**< Build version (bug fixes).*/ -} PalVersion; - -/** - * @struct PalAllocator - * @brief Custom memory allocator. - * - * Provides user-defined memory allocation and free functions. - * - * @since 1.0 - * @ingroup pal_core - */ -typedef struct { - PalAllocateFn allocate; - PalFreeFn free; - void* userData; /**< Optional user-provided data. Can be nullptr.*/ -} PalAllocator; - -/** - * @struct PalLogger - * @brief Logging configuration. - * - * Provides a callback and user data for handling log messages. - * - * @since 1.0 - * @ingroup pal_core - */ -typedef struct { - PalLogCallback callback; - void* userData; /** Optional user-provided data. Can be nullptr.*/ -} PalLogger; - -/** - * Retrieve the PAL version number. - * - * @return PAL version (major, minor, build). - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palGetVersionString - */ -PAL_API PalVersion PAL_CALL palGetVersion(); - -/** - * Retrieve the PAL version string. - * - * @return Null-terminated string containing the PAL version. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palGetVersion - */ -PAL_API const char* PAL_CALL palGetVersionString(); - -/** - * Convert a result code to a human-readable string. - * - * @param result The PalResult code to format. - * - * @return Null-terminated static string describing the result. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_core - */ -PAL_API const char* PAL_CALL palFormatResult(PalResult result); - -/** - * Allocate memory using the provided allocator. - * - * @param allocator The allocator to use. Set to nullptr to use default. - * @param size Number of bytes to allocate. - * @param alignment Alignment in bytes. Must be a power of two. - * - * @return Pointer to allocated memory on success, or nullptr on failure. - * - * Thread safety: Thread safe only if the provided allocator is thread safe. The default allocator - * is thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palFree - */ -PAL_API void* PAL_CALL palAllocate( - const PalAllocator* allocator, - Uint64 size, - Uint64 alignment); - -/** - * Free memory allocated by palAllocate. - * - * @param allocator The allocator used to allocate the memory. Set to nullptr to - * use default. - * @param ptr Pointer to memory to free. If nullptr, the function returns - * silently. - * - * Thread safety: Thread safe only if the provided allocator is thread - * safe. The default allocator is thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palAllocate - */ -PAL_API void PAL_CALL palFree( - const PalAllocator* allocator, - void* ptr); - -/** - * Log a formatted message. - * - * @param logger Logger instance. Set to nullptr to use default logger. - * @param fmt printf-style format string. - * @param ... Arguments for the format string. - * - * Thread safety: Thread safe, but log output and - * callbacks may be invoked concurrently. The user must ensure the callback - * implementation is thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palFormatResult - */ -PAL_API void PAL_CALL palLog( - const PalLogger* logger, - const char* fmt, - ...); - -/** - * Query a high-resolution performance counter value. - * - * @return Current performance counter value. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palGetPerformanceFrequency - */ -PAL_API Uint64 PAL_CALL palGetPerformanceCounter(); - -/** - * Query the frequency of the high-resolution performance counter. - * - * @return Performance counter frequency, in counts per second. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palGetPerformanceCounter - */ -PAL_API Uint64 PAL_CALL palGetPerformanceFrequency(); - -/** - * @brief Combine two 32-bit unsigned integers into a single 64-bit signed - * integer. - * - * @return The combined 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palUnpackUint32 - */ -static inline Int64 PAL_CALL palPackUint32( - Uint32 low, - Uint32 high) -{ - return (Int64)(((Uint64)high << 32) | (Uint64)low); -} - -/** - * @brief Combine two 32-bit signed integers into a single 64-bit signed - * integer. - * - * @return The combined 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palUnpackInt32 - */ -static inline Int64 PAL_CALL palPackInt32( - Int32 low, - Int32 high) -{ - return ((Int64)(Uint32)high << 32) | (Uint32)low; -} - -/** - * @brief Pack a pointer into a 64-bit signed integer. - * - * @return The packed 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palUnpackPointer - */ -static inline Int64 PAL_CALL palPackPointer(void* ptr) -{ - return (Int64)(UintPtr)ptr; -} - -/** - * @brief Combine two floats into a single 64-bit signed integer. - * - * @return The combined 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.3 - * @ingroup pal_core - * @sa palUnpackFloat - */ -static inline Int64 PAL_CALL palPackFloat( - float low, - float high) -{ - Int64 combined = 0; -#if PAL_BIG_ENDIAN - memcpy(&((Uint32*)&combined)[0], &high, sizeof(float)); - memcpy(&((Uint32*)&combined)[1], &low, sizeof(float)); -#else - memcpy(&((Uint32*)&combined)[0], &low, sizeof(float)); - memcpy(&((Uint32*)&combined)[1], &high, sizeof(float)); -#endif // PAL_BIG_ENDIAN - - return combined; -} - -/** - * @brief Retrieve two 32-bit unsigned integers from a 64-bit signed integer. - * - * @param[out] outLow Low value of the 64-bit signed integer. - * @param[out] outHigh High value of the 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palPackUint32 - */ -static inline void PAL_CALL palUnpackUint32( - Int64 data, - Uint32* outLow, - Uint32* outHigh) -{ - if (outLow) { - *outLow = (Uint32)(data & 0xFFFFFFFF); - } - - if (outHigh) { - *outHigh = (Uint32)((Uint64)data >> 32); - } -} - -/** - * @brief Retrieve two 32-bit signed integers from a 64-bit signed integer. - * - * @param[out] outLow Low value of the 64-bit signed integer. - * @param[out] outHigh High value of the 64-bit signed integer. - * - * Thread safety: Thread-safe if `outLow` and `outHigh` are - * thread local. - * - * @since 1.0 - * @ingroup pal_core - * @sa palPackInt32 - */ -static inline void PAL_CALL palUnpackInt32( - Int64 data, - Int32* outLow, - Int32* outHigh) -{ - if (outLow) { - *outLow = (Int32)(data & 0xFFFFFFFF); - } - - if (outHigh) { - *outHigh = (Int32)((Uint64)data >> 32); - } -} - -/** - * @brief Unpack a pointer from a 64-bit signed integer. - * - * @return The pointer from the 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_core - * @sa palPackPointer - */ -static inline void* PAL_CALL palUnpackPointer(Int64 data) -{ - return (void*)(UintPtr)data; -} - -/** - * @brief Retrieve two floats from a 64-bit signed integer. - * - * @param[out] outLow Low value of the 64-bit signed integer. - * @param[out] outHigh High value of the 64-bit signed integer. - * - * Thread safety: Thread-safe if `outLow` and `outHigh` are - * thread local. - * - * @since 1.3 - * @ingroup pal_core - * @sa palPackFloat - */ -static inline void PAL_CALL palUnpackFloat( - Int64 data, - float* low, - float* high) -{ -#if PAL_BIG_ENDIAN - if (low) { - memcpy(low, &((Uint32*)&data)[1], sizeof(float)); - } - - if (high) { - memcpy(high, &((Uint32*)&data)[0], sizeof(float)); - } -#else - if (low) { - memcpy(low, &((Uint32*)&data)[0], sizeof(float)); - } - - if (high) { - memcpy(high, &((Uint32*)&data)[1], sizeof(float)); - } - -#endif // PAL_BIG_ENDIAN -} +#include "core/defines.h" +#include "core/log.h" +#include "core/memory.h" +#include "core/pack.h" +#include "core/result.h" +#include "core/time.h" +#include "core/version.h" -/** @} */ // end of pal_core group +/** @} */ #endif // _PAL_CORE_H diff --git a/pal.lua b/pal.lua index 661ee975..88549702 100644 --- a/pal.lua +++ b/pal.lua @@ -4,7 +4,7 @@ dofile("pal_config.lua") project "PAL" language "C" - if PAL_BUILD_STATIC then + if PAL_BUILD_STATIC_LIBRARY then kind "StaticLib" else kind "SharedLib" @@ -23,11 +23,15 @@ project "PAL" } files { - "src/pal_core.c", - "src/pal_event.c" + -- core + "src/core/pal_log.c", + "src/core/pal_memory.c", + "src/core/pal_result.c", + "src/core/pal_time.c", + "src/core/pal_version.c" } - if (PAL_BUILD_SYSTEM) then + if (PAL_BUILD_SYSTEM_MODULE) then filter {"system:windows", "configurations:*"} files { "src/system/pal_system_win32.c" } @@ -37,7 +41,7 @@ project "PAL" filter {} end - if (PAL_BUILD_THREAD) then + if (PAL_BUILD_THREAD_MODULE) then filter {"system:windows", "configurations:*"} files { "src/thread/pal_thread_win32.c" } @@ -47,7 +51,7 @@ project "PAL" filter {} end - if (PAL_BUILD_VIDEO) then + if (PAL_BUILD_VIDEO_MODULE) then filter {"system:windows", "configurations:*"} files { "src/video/pal_video_win32.c" } @@ -101,7 +105,7 @@ project "PAL" filter {} end - if (PAL_BUILD_OPENGL) then + if (PAL_BUILD_OPENGL_MODULE) then filter {"system:windows", "configurations:*"} files { "src/opengl/pal_opengl_win32.c" } @@ -111,7 +115,7 @@ project "PAL" filter {} end - if (PAL_BUILD_GRAPHICS) then + if (PAL_BUILD_GRAPHICS_MODULE) then -- check for vulkan support. This is cross compiler local vulkanSdk = os.getenv("VULKAN_SDK") local hasVulkan = false diff --git a/pal_config.lua b/pal_config.lua index 36970328..04037df9 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -1,21 +1,21 @@ -- build PAL as a static library -PAL_BUILD_STATIC = false +PAL_BUILD_STATIC_LIBRARY = false -- build PAL tests as a single application -PAL_BUILD_TESTS = true +PAL_BUILD_TEST_APPLICATION = true -- build system module -PAL_BUILD_SYSTEM = true +PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD = false +PAL_BUILD_THREAD_MODULE = false -- build video module -PAL_BUILD_VIDEO = true +PAL_BUILD_VIDEO_MODULE = false -- build opengl module -PAL_BUILD_OPENGL = false +PAL_BUILD_OPENGL_MODULE = false -- build graphics module -PAL_BUILD_GRAPHICS = true +PAL_BUILD_GRAPHICS_MODULE = false diff --git a/premake5.lua b/premake5.lua index ef3ec835..7e6cd6ed 100644 --- a/premake5.lua +++ b/premake5.lua @@ -274,11 +274,11 @@ newoption { } workspace(workspaceName) - if PAL_BUILD_TESTS then + if PAL_BUILD_TEST_APPLICATION then startproject("tests") end - if PAL_BUILD_STATIC then + if PAL_BUILD_STATIC_LIBRARY then staticruntime "on" else staticruntime "off" @@ -375,37 +375,37 @@ workspace(workspaceName) } end - if (PAL_BUILD_SYSTEM) then + if (PAL_BUILD_SYSTEM_MODULE) then defines { "PAL_HAS_SYSTEM_MODULE=1" } else defines { "PAL_HAS_SYSTEM_MODULE=0" } end - if (PAL_BUILD_THREAD) then + if (PAL_BUILD_THREAD_MODULE) then defines { "PAL_HAS_THREAD_MODULE=1" } else defines { "PAL_HAS_THREAD_MODULE=0" } end - if (PAL_BUILD_VIDEO) then + if (PAL_BUILD_VIDEO_MODULE) then defines { "PAL_HAS_VIDEO_MODULE=1" } else defines { "PAL_HAS_VIDEO_MODULE=0" } end - if (PAL_BUILD_OPENGL) then + if (PAL_BUILD_OPENGL_MODULE) then defines { "PAL_HAS_OPENGL_MODULE=1" } else defines { "PAL_HAS_OPENGL_MODULE=0" } end - if (PAL_BUILD_GRAPHICS) then + if (PAL_BUILD_GRAPHICS_MODULE) then defines { "PAL_HAS_GRAPHICS_MODULE=1" } else defines { "PAL_HAS_GRAPHICS_MODULE=0" } end - if (PAL_BUILD_TESTS) then + if (PAL_BUILD_TEST_APPLICATION) then include "tests/tests.lua" end diff --git a/src/core/pal_log.c b/src/core/pal_log.c new file mode 100644 index 00000000..43709749 --- /dev/null +++ b/src/core/pal_log.c @@ -0,0 +1,193 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal/core/log.h" +#include +#include +#include + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE +#include + +static volatile LONG s_TlsID = 0; + +#else +#include + +pthread_key_t s_TLSID = 0; +static pthread_once_t s_TLSCreation = PTHREAD_ONCE_INIT; + +static void destroyTlsData(void* data); +void createTLSID() +{ + if (pthread_key_create(&s_TLSID, destroyTlsData) != 0) { + return; + } +} + +#endif // _WIN32 + +#define PAL_LOG_MSG_SIZE 4096 + +typedef struct { + char tmp[PAL_LOG_MSG_SIZE]; + char buffer[PAL_LOG_MSG_SIZE]; + wchar_t wideBuffer[PAL_LOG_MSG_SIZE]; + bool isLogging; +} LogTLSData; + +static void destroyTlsData(void* data) +{ + LogTLSData* tlsData = data; + if (tlsData) { + free(tlsData); + } +} + +static inline LogTLSData* getLogTlsData() +{ +#ifdef _WIN32 + LogTLSData* data = FlsGetValue((DWORD)s_TlsID); +#else + LogTLSData* data = pthread_getspecific(s_TLSID); +#endif // _WIN32 + + if (!data) { + data = malloc(sizeof(LogTLSData)); + memset(data, 0, sizeof(LogTLSData)); + // create TLS if it has not been created +#ifdef _WIN32 + if (s_TlsID == 0) { + DWORD TLSIndex = FlsAlloc(destroyTlsData); + if (TLSIndex == TLS_OUT_OF_INDEXES) { + // FIXME: Use a global log buffer with a mutex + return nullptr; + } else { + // update the TLS using atomic operations to avoid thread race + LONG prev = InterlockedCompareExchange((volatile LONG*)&s_TlsID, (LONG)TLSIndex, 0); + if (prev != 0) { + // Another thread has already set this, + // destroy the tls index + FlsFree(TLSIndex); + } + } + } + FlsSetValue(s_TlsID, data); +#else + pthread_once(&s_TLSCreation, createTLSID); + pthread_setspecific(s_TLSID, data); +#endif // _WIN32 + } + return data; +} + +static inline void updateLogTlsData(LogTLSData* data) +{ +#ifdef _WIN32 + FlsSetValue(s_TlsID, data); +#else + pthread_setspecific(s_TLSID, data); +#endif // _WIN32 +} + +static inline void formatArgs( + const char* fmt, + va_list argsList, + char* buffer) +{ + va_list argsListCopy; + va_copy(argsListCopy, argsList); + int len = vsnprintf(nullptr, 0, fmt, argsListCopy); + va_end(argsListCopy); + + va_copy(argsListCopy, argsList); + vsnprintf(buffer, len + 1, fmt, argsListCopy); + va_end(argsListCopy); + buffer[len] = 0; +} + +static inline void format( + char* buffer, + const char* fmt, + ...) +{ + va_list argPtr; + va_start(argPtr, fmt); + formatArgs(fmt, argPtr, buffer); + va_end(argPtr); +} + +static inline void writeToConsole(LogTLSData* data) +{ +#ifdef _WIN32 + HANDLE console = GetStdHandle(STD_ERROR_HANDLE); + int len = MultiByteToWideChar(CP_UTF8, 0, data->buffer, -1, nullptr, 0); + if (!len) { + return; + } + + MultiByteToWideChar(CP_UTF8, 0, data->buffer, -1, data->wideBuffer, len); + if (console) { + WriteConsoleW(console, data->wideBuffer, (DWORD)len - 1, NULL, 0); + } else { + OutputDebugStringW(data->wideBuffer); + } +#else + fprintf(stdout, "%s", data->buffer); + fflush(stdout); +#endif // _WIN32 +} + +void PAL_CALL palLog( + const PalLogger* logger, + const char* fmt, + ...) +{ + if (!fmt) { + return; + } + + LogTLSData* data = getLogTlsData(); + va_list argPtr; + va_start(argPtr, fmt); + formatArgs(fmt, argPtr, data->tmp); + va_end(argPtr); + + // check to see if a user supplied a logger + if (logger && logger->callback) { + if (data->isLogging) { + // block recursion + return; + } + + // update the tls to stop recursive calls + memcpy(data->buffer, data->tmp, PAL_LOG_MSG_SIZE); + data->isLogging = true; + updateLogTlsData(data); + logger->callback(logger->userData, data->buffer); + + } else { + // add newline character to the string + format(data->buffer, "%s\n", data->tmp); + writeToConsole(data); + } + + data->isLogging = false; + updateLogTlsData(data); +} \ No newline at end of file diff --git a/src/core/pal_memory.c b/src/core/pal_memory.c new file mode 100644 index 00000000..ffe666cc --- /dev/null +++ b/src/core/pal_memory.c @@ -0,0 +1,66 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#endif // _MSC_VER + +#include "pal/core/memory.h" + +#define PAL_DEFAULT_ALIGNMENT 16 + +static inline void* alignedAlloc( + Uint64 size, + Uint64 alignment) +{ +#if defined(_MSC_VER) || defined(__MINGW32__) + return _aligned_malloc(size, alignment); +#elif defined(_ISOC11_SOURCE) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + return aligned_alloc(alignment, size); +#else + void* ptr = nullptr; + posix_memalign(&ptr, alignment, size); + return ptr; +#endif // _MSC_VER +} + +static inline void alignedFree(void* ptr) +{ +#if defined(_MSC_VER) || defined(__MINGW32__) + _aligned_free(ptr); +#else + free(ptr); +#endif // _MSC_VER +} + +void* PAL_CALL palAllocate( + const PalAllocator* allocator, + Uint64 size, + Uint64 alignment) +{ + Uint64 align = alignment; + if (align == 0) { + align = PAL_DEFAULT_ALIGNMENT; + } + + if (allocator && allocator->allocate && size != 0) { + return allocator->allocate(allocator->userData, size, align); + } + return alignedAlloc(size, align); +} + +void PAL_CALL palFree( + const PalAllocator* allocator, + void* ptr) +{ + if (allocator && allocator->free && ptr) { + allocator->free(allocator->userData, ptr); + + } else { + alignedFree(ptr); + } +} \ No newline at end of file diff --git a/src/core/pal_result.c b/src/core/pal_result.c new file mode 100644 index 00000000..5b98a4d7 --- /dev/null +++ b/src/core/pal_result.c @@ -0,0 +1,187 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal/core/result.h" + +const char* PAL_CALL palFormatResult(PalResult result) +{ + switch (result) { + case PAL_RESULT_SUCCESS: + return "Success"; + + case PAL_RESULT_NULL_POINTER: + return "Null pointer"; + + case PAL_RESULT_INVALID_ARGUMENT: + return "Invalid argument"; + + case PAL_RESULT_OUT_OF_MEMORY: + return "Out of memory"; + + case PAL_RESULT_PLATFORM_FAILURE: { + return "Platform error"; + } + + case PAL_RESULT_INVALID_ALLOCATOR: + return "Invalif allocator"; + + case PAL_RESULT_ACCESS_DENIED: + return "Access denied"; + + case PAL_RESULT_TIMEOUT: + return "Timeout expired"; + + case PAL_RESULT_INSUFFICIENT_BUFFER: + return "Insufficient buffer"; + + // thread + case PAL_RESULT_INVALID_THREAD: + return "Invalid thread"; + + case PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED: + return "Unsupported thread feature"; + + // video + case PAL_RESULT_VIDEO_NOT_INITIALIZED: + return "Video system not initialized"; + + case PAL_RESULT_INVALID_MONITOR: + return "Invalid monitor"; + + case PAL_RESULT_INVALID_MONITOR_MODE: + return "Invalid monitor display mode"; + + case PAL_RESULT_INVALID_WINDOW: + return "Invalid window"; + + case PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED: + return "Unsupported video feature"; + + case PAL_RESULT_INVALID_KEYCODE: + return "Invalid keycode"; + + case PAL_RESULT_INVALID_SCANCODE: + return "Invalid scancode"; + + case PAL_RESULT_INVALID_MOUSE_BUTTON: + return "Invalid mouse button"; + + case PAL_RESULT_INVALID_ORIENTATION: + return "Invalid orientation"; + + // opengl + case PAL_RESULT_GL_NOT_INITIALIZED: + return "Opengl system not initialized"; + + case PAL_RESULT_INVALID_GL_WINDOW: + return "Invalid opengl window"; + + case PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED: + return "Unsupported opengl extension"; + + case PAL_RESULT_INVALID_GL_FBCONFIG: + return "Invalid opengl framebuffer"; + + case PAL_RESULT_INVALID_GL_VERSION: + return "Unsupported opengl version"; + + case PAL_RESULT_INVALID_GL_PROFILE: + return "Unsupported opengl profile"; + + case PAL_RESULT_INVALID_GL_CONTEXT: + return "Invalid opengl context"; + + case PAL_RESULT_INVALID_FBCONFIG_BACKEND: + return "Invalid FBConfg backend"; + + // graphics + case PAL_RESULT_GRAPHICS_NOT_INITIALIZED: + return "Graphics system not initialized"; + + case PAL_RESULT_INVALID_ADAPTER: + return "Invalid adapter"; + + case PAL_RESULT_INVALID_BACKEND: + return "Invalid backend"; + + case PAL_RESULT_QUEUE_NOT_SUPPORTED: + return "Queue not supported"; + + case PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED: + return "Unsupported adapter feature"; + + case PAL_RESULT_INVALID_DRIVER: + return "Incompatible driver"; + + case PAL_RESULT_INVALID_DEVICE: + return "Invalid device"; + + case PAL_RESULT_INVALID_QUEUE: + return "Invalid queue"; + + case PAL_RESULT_OUT_OF_QUEUE: + return "Out of queues"; + + case PAL_RESULT_INVALID_GRAPHICS_WINDOW: + return "Invalid graphics window"; + + case PAL_RESULT_INVALID_SWAPCHAIN: + return "Invalid swapchain"; + + case PAL_RESULT_INVALID_IMAGE: + return "Invalid image"; + + case PAL_RESULT_INVALID_IMAGE_VIEW: + return "Invalid image view"; + + case PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED: + return "memory type not supported"; + + case PAL_RESULT_INVALID_OPERATION: + return "Invalid operation"; + + case PAL_RESULT_INVALID_SHADER: + return "Invalid shader"; + + case PAL_RESULT_INVALID_SHADER_TYPE: + return "Invalid shader type"; + + case PAL_RESULT_INVALID_COMMAND_POOL: + return "Invalid command pool"; + + case PAL_RESULT_INVALID_COMMAND_BUFFER: + return "Invalid command buffer"; + + case PAL_RESULT_INVALID_FENCE: + return "Invalid fence"; + + case PAL_RESULT_INVALID_SEMAPHORE: + return "Invalid semaphore"; + + case PAL_RESULT_INVALID_BUFFER: + return "Invalid buffer"; + + case PAL_RESULT_INVALID_PIPELINE: + return "Invalid pipeline"; + + case PAL_RESULT_INVALID_ACCELERATION_STRUCTURE: + return "Invalid acceleration structure"; + + case PAL_RESULT_MEMORY_MAP_FAILED: + return "Memory map failed"; + + case PAL_RESULT_DEVICE_LOST: + return "Device lost"; + + case PAL_RESULT_SURFACE_LOST: + return "Surface lost"; + + case PAL_RESULT_SWAPCHAIN_OUT_OF_DATE: + return "Swapchain out of date"; + } + return "Unknown"; +} \ No newline at end of file diff --git a/src/core/pal_time.c b/src/core/pal_time.c new file mode 100644 index 00000000..305f1a6a --- /dev/null +++ b/src/core/pal_time.c @@ -0,0 +1,51 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal/core/time.h" + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE +#include + +#else +#include +#endif // _WIN32 + +Uint64 PAL_CALL palGetPerformanceCounter() +{ +#ifdef _WIN32 + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return (Uint64)counter.QuadPart; +#else + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (Uint64)ts.tv_sec * 1000000000LL + (Uint64)ts.tv_nsec; +#endif // _WIN32 +} + +Uint64 PAL_CALL palGetPerformanceFrequency() +{ +#ifdef _WIN32 + LARGE_INTEGER frequency; + QueryPerformanceFrequency(&frequency); + return (Uint64)frequency.QuadPart; +#else + return 1000000000LL; +#endif // _WIN32 +} \ No newline at end of file diff --git a/src/core/pal_version.c b/src/core/pal_version.c new file mode 100644 index 00000000..d14c3230 --- /dev/null +++ b/src/core/pal_version.c @@ -0,0 +1,27 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal/core/version.h" + +#define PAL_VERSION_MAJOR 1 +#define PAL_VERSION_MINOR 4 +#define PAL_VERSION_BUILD 0 +#define PAL_VERSION_STRING "1.4.0" + +PalVersion PAL_CALL palGetVersion() +{ + PalVersion version = {0}; + version.major = PAL_VERSION_MAJOR; + version.minor = PAL_VERSION_MINOR; + version.build = PAL_VERSION_BUILD; + return version; +} + +const char* PAL_CALL palGetVersionString() +{ + return PAL_VERSION_STRING; +} \ No newline at end of file diff --git a/src/pal_core.c b/src/pal_core.c deleted file mode 100644 index ffa0cfc1..00000000 --- a/src/pal_core.c +++ /dev/null @@ -1,552 +0,0 @@ - -/** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - - */ - -// ================================================== -// Includes -// ================================================== - -#ifdef __linux__ -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L -#include -#include -#include -#include -#include -#include -#endif // __linux__ - -#include "pal/pal_core.h" - -#ifdef _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN - -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -// set unicode -#ifndef UNICODE -#define UNICODE -#endif // UNICODE - -#include -#endif // _WIN32 - -#if defined(_MSC_VER) || defined(__MINGW32__) -#include -#endif // _MSC_VER - -#include -#include - -// ================================================== -// Typedefs, enums and structs -// ================================================== - -#define PAL_DEFAULT_ALIGNMENT 16 -#define PAL_VERSION_MAJOR 1 -#define PAL_VERSION_MINOR 4 -#define PAL_VERSION_BUILD 0 -#define PAL_VERSION_STRING "1.4.0" -#define PAL_LOG_MSG_SIZE 4096 - -#ifdef _WIN32 -static volatile LONG s_TlsID = 0; -#elif defined(__linux__) -pthread_key_t s_TLSID = 0; -static pthread_once_t s_TLSCreation = PTHREAD_ONCE_INIT; -#endif // _WIN32 - -typedef struct { - char tmp[PAL_LOG_MSG_SIZE]; - char buffer[PAL_LOG_MSG_SIZE]; - char platformResultDesc[PAL_LOG_MSG_SIZE]; - wchar_t wideBuffer[PAL_LOG_MSG_SIZE]; - bool isLogging; -} LogTLSData; - -// ================================================== -// Internal API -// ================================================== - -static void destroyTlsData(void* data); - -#ifdef __linux__ -void createTLSID() -{ - if (pthread_key_create(&s_TLSID, destroyTlsData) != 0) { - // FIXME: Use a global log buffer with a mutex - return; - } -} -#endif // __linux__ - -static inline void* alignedAlloc( - Uint64 size, - Uint64 alignment) -{ -#if defined(_MSC_VER) || defined(__MINGW32__) - return _aligned_malloc(size, alignment); -#elif defined(_ISOC11_SOURCE) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - return aligned_alloc(alignment, size); -#else - void* ptr = nullptr; - posix_memalign(&ptr, alignment, size); - return ptr; -#endif // _MSC_VER -} - -static inline void alignedFree(void* ptr) -{ -#if defined(_MSC_VER) || defined(__MINGW32__) - _aligned_free(ptr); -#else - free(ptr); -#endif // _MSC_VER -} - -static void destroyTlsData(void* data) -{ - LogTLSData* tlsData = data; - if (tlsData) { - palFree(nullptr, tlsData); - } -} - -static inline LogTLSData* getLogTlsData() -{ -#ifdef _WIN32 - LogTLSData* data = FlsGetValue((DWORD)s_TlsID); -#elif defined(__linux__) - LogTLSData* data = pthread_getspecific(s_TLSID); -#endif // _WIN32 - - if (!data) { - data = palAllocate(nullptr, sizeof(LogTLSData), 0); - memset(data, 0, sizeof(LogTLSData)); - // create TLS if it has not been created -#ifdef _WIN32 - if (s_TlsID == 0) { - DWORD TLSIndex = FlsAlloc(destroyTlsData); - if (TLSIndex == TLS_OUT_OF_INDEXES) { - // FIXME: Use a global log buffer with a mutex - return nullptr; - } else { - // update the TLS using atomic operations to avoid thread race - LONG prev = InterlockedCompareExchange((volatile LONG*)&s_TlsID, (LONG)TLSIndex, 0); - if (prev != 0) { - // Another thread has already set this, - // destroy the tls index - FlsFree(TLSIndex); - } - } - } - FlsSetValue(s_TlsID, data); -#elif defined(__linux__) - pthread_once(&s_TLSCreation, createTLSID); - pthread_setspecific(s_TLSID, data); -#endif // _WIN32 - } - return data; -} - -static inline void updateLogTlsData(LogTLSData* data) -{ -#ifdef _WIN32 - FlsSetValue(s_TlsID, data); -#elif defined(__linux__) - pthread_setspecific(s_TLSID, data); -#endif // _WIN32 -} - -static inline void formatArgs( - const char* fmt, - va_list argsList, - char* buffer) -{ - va_list argsListCopy; - va_copy(argsListCopy, argsList); - int len = vsnprintf(nullptr, 0, fmt, argsListCopy); - va_end(argsListCopy); - - va_copy(argsListCopy, argsList); - vsnprintf(buffer, len + 1, fmt, argsListCopy); - va_end(argsListCopy); - buffer[len] = 0; -} - -static inline void format( - char* buffer, - const char* fmt, - ...) -{ - va_list argPtr; - va_start(argPtr, fmt); - formatArgs(fmt, argPtr, buffer); - va_end(argPtr); -} - -static inline void writeToConsole(LogTLSData* data) -{ -#ifdef _WIN32 - HANDLE console = GetStdHandle(STD_ERROR_HANDLE); - int len = MultiByteToWideChar(CP_UTF8, 0, data->buffer, -1, nullptr, 0); - if (!len) { - return; - } - - MultiByteToWideChar(CP_UTF8, 0, data->buffer, -1, data->wideBuffer, len); - if (console) { - WriteConsoleW(console, data->wideBuffer, (DWORD)len - 1, NULL, 0); - } else { - OutputDebugStringW(data->wideBuffer); - } -#elif defined(__linux__) - fprintf(stdout, "%s", data->buffer); - fflush(stdout); -#endif // _WIN32 -} - -void palSetLastPlatformError(Uint32 e) -{ - LogTLSData* data = getLogTlsData(); - memset(data->platformResultDesc, 0, PAL_LOG_MSG_SIZE); - if (e == 0) { - return; - } - -#ifdef __linux__ -#if defined(__GLIBC__) - char* ret = strerror_r(e, data->platformResultDesc, PAL_LOG_MSG_SIZE); - if (ret != data->platformResultDesc) { - snprintf(data->platformResultDesc, PAL_LOG_MSG_SIZE, "%s", ret); - } -#else - strerror_r(e, data->platformResultDesc, PAL_LOG_MSG_SIZE); -#endif // __GLIBC__ -#else - FormatMessageA( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, - e, - 0, - data->platformResultDesc, - PAL_LOG_MSG_SIZE, - nullptr); -#endif // __linux__ -} - -// ================================================== -// Public API -// ================================================== - -PalVersion PAL_CALL palGetVersion() -{ - return (PalVersion){.major = PAL_VERSION_MAJOR, - .minor = PAL_VERSION_MINOR, - .build = PAL_VERSION_BUILD}; -} - -const char* PAL_CALL palGetVersionString() -{ - return PAL_VERSION_STRING; -} - -const char* PAL_CALL palFormatResult(PalResult result) -{ - switch (result) { - case PAL_RESULT_SUCCESS: - return "Success"; - - case PAL_RESULT_NULL_POINTER: - return "Null pointer"; - - case PAL_RESULT_INVALID_ARGUMENT: - return "Invalid argument"; - - case PAL_RESULT_OUT_OF_MEMORY: - return "Out of memory"; - - case PAL_RESULT_PLATFORM_FAILURE: { - LogTLSData* data = getLogTlsData(); - if (!data) { - return "Platform error"; - } else if (data && data->platformResultDesc[0] == 0) { - return "Platform error"; - } else { - return data->platformResultDesc; - } - } - - case PAL_RESULT_INVALID_ALLOCATOR: - return "Invalif allocator"; - - case PAL_RESULT_ACCESS_DENIED: - return "Access denied"; - - case PAL_RESULT_TIMEOUT: - return "Timeout expired"; - - case PAL_RESULT_INSUFFICIENT_BUFFER: - return "Insufficient buffer"; - - // thread - case PAL_RESULT_INVALID_THREAD: - return "Invalid thread"; - - case PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED: - return "Unsupported thread feature"; - - // video - case PAL_RESULT_VIDEO_NOT_INITIALIZED: - return "Video system not initialized"; - - case PAL_RESULT_INVALID_MONITOR: - return "Invalid monitor"; - - case PAL_RESULT_INVALID_MONITOR_MODE: - return "Invalid monitor display mode"; - - case PAL_RESULT_INVALID_WINDOW: - return "Invalid window"; - - case PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED: - return "Unsupported video feature"; - - case PAL_RESULT_INVALID_KEYCODE: - return "Invalid keycode"; - - case PAL_RESULT_INVALID_SCANCODE: - return "Invalid scancode"; - - case PAL_RESULT_INVALID_MOUSE_BUTTON: - return "Invalid mouse button"; - - case PAL_RESULT_INVALID_ORIENTATION: - return "Invalid orientation"; - - // opengl - case PAL_RESULT_GL_NOT_INITIALIZED: - return "Opengl system not initialized"; - - case PAL_RESULT_INVALID_GL_WINDOW: - return "Invalid opengl window"; - - case PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED: - return "Unsupported opengl extension"; - - case PAL_RESULT_INVALID_GL_FBCONFIG: - return "Invalid opengl framebuffer"; - - case PAL_RESULT_INVALID_GL_VERSION: - return "Unsupported opengl version"; - - case PAL_RESULT_INVALID_GL_PROFILE: - return "Unsupported opengl profile"; - - case PAL_RESULT_INVALID_GL_CONTEXT: - return "Invalid opengl context"; - - case PAL_RESULT_INVALID_FBCONFIG_BACKEND: - return "Invalid FBConfg backend"; - - // graphics - case PAL_RESULT_GRAPHICS_NOT_INITIALIZED: - return "Graphics system not initialized"; - - case PAL_RESULT_INVALID_ADAPTER: - return "Invalid adapter"; - - case PAL_RESULT_INVALID_BACKEND: - return "Invalid backend"; - - case PAL_RESULT_QUEUE_NOT_SUPPORTED: - return "Queue not supported"; - - case PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED: - return "Unsupported adapter feature"; - - case PAL_RESULT_INVALID_DRIVER: - return "Incompatible driver"; - - case PAL_RESULT_INVALID_DEVICE: - return "Invalid device"; - - case PAL_RESULT_INVALID_QUEUE: - return "Invalid queue"; - - case PAL_RESULT_OUT_OF_QUEUE: - return "Out of queues"; - - case PAL_RESULT_INVALID_GRAPHICS_WINDOW: - return "Invalid graphics window"; - - case PAL_RESULT_INVALID_SWAPCHAIN: - return "Invalid swapchain"; - - case PAL_RESULT_INVALID_IMAGE: - return "Invalid image"; - - case PAL_RESULT_INVALID_IMAGE_VIEW: - return "Invalid image view"; - - case PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED: - return "memory type not supported"; - - case PAL_RESULT_INVALID_OPERATION: - return "Invalid operation"; - - case PAL_RESULT_INVALID_SHADER: - return "Invalid shader"; - - case PAL_RESULT_INVALID_SHADER_TYPE: - return "Invalid shader type"; - - case PAL_RESULT_INVALID_COMMAND_POOL: - return "Invalid command pool"; - - case PAL_RESULT_INVALID_COMMAND_BUFFER: - return "Invalid command buffer"; - - case PAL_RESULT_INVALID_FENCE: - return "Invalid fence"; - - case PAL_RESULT_INVALID_SEMAPHORE: - return "Invalid semaphore"; - - case PAL_RESULT_INVALID_BUFFER: - return "Invalid buffer"; - - case PAL_RESULT_INVALID_PIPELINE: - return "Invalid pipeline"; - - case PAL_RESULT_INVALID_ACCELERATION_STRUCTURE: - return "Invalid acceleration structure"; - - case PAL_RESULT_MEMORY_MAP_FAILED: - return "Memory map failed"; - - case PAL_RESULT_DEVICE_LOST: - return "Device lost"; - - case PAL_RESULT_SURFACE_LOST: - return "Surface lost"; - - case PAL_RESULT_SWAPCHAIN_OUT_OF_DATE: - return "Swapchain out of date"; - } - return "Unknown"; -} - -void* PAL_CALL palAllocate( - const PalAllocator* allocator, - Uint64 size, - Uint64 alignment) -{ - Uint64 align = alignment; - if (align == 0) { - align = PAL_DEFAULT_ALIGNMENT; - } - - if (allocator && allocator->allocate && size != 0) { - return allocator->allocate(allocator->userData, size, align); - } - return alignedAlloc(size, align); -} - -void PAL_CALL palFree( - const PalAllocator* allocator, - void* ptr) -{ - if (allocator && allocator->free && ptr) { - allocator->free(allocator->userData, ptr); - - } else { - alignedFree(ptr); - } -} - -void PAL_CALL palLog( - const PalLogger* logger, - const char* fmt, - ...) -{ - if (!fmt) { - return; - } - - LogTLSData* data = getLogTlsData(); - va_list argPtr; - va_start(argPtr, fmt); - formatArgs(fmt, argPtr, data->tmp); - va_end(argPtr); - - // check to see if a user supplied a logger - if (logger && logger->callback) { - if (data->isLogging) { - // block recursion - return; - } - - // update the tls to stop recursive calls - memcpy(data->buffer, data->tmp, PAL_LOG_MSG_SIZE); - data->isLogging = true; - updateLogTlsData(data); - logger->callback(logger->userData, data->buffer); - - } else { - // add newline character to the string - format(data->buffer, "%s\n", data->tmp); - writeToConsole(data); - } - - data->isLogging = false; - updateLogTlsData(data); -} - -Uint64 PAL_CALL palGetPerformanceCounter() -{ -#ifdef _WIN32 - LARGE_INTEGER counter; - QueryPerformanceCounter(&counter); - return (Uint64)counter.QuadPart; -#elif defined(__linux__) - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (Uint64)ts.tv_sec * 1000000000LL + (Uint64)ts.tv_nsec; -#endif // _WIN32 -} - -Uint64 PAL_CALL palGetPerformanceFrequency() -{ -#ifdef _WIN32 - LARGE_INTEGER frequency; - QueryPerformanceFrequency(&frequency); - return (Uint64)frequency.QuadPart; -#elif defined(__linux__) - return 1000000000LL; -#endif // _WIN32 -} diff --git a/tests/tests.lua b/tests/tests.lua index e545a36f..a99e21a5 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -15,17 +15,17 @@ project "tests" "core/time_test.c", -- event - "event/user_event_test.c", - "event/event_test.c" + -- "event/user_event_test.c", + -- "event/event_test.c" } - if (PAL_BUILD_SYSTEM) then + if (PAL_BUILD_SYSTEM_MODULE) then files { "system/system_test.c" } end - if (PAL_BUILD_THREAD) then + if (PAL_BUILD_THREAD_MODULE) then files { "thread/thread_test.c", "thread/tls_test.c", @@ -34,7 +34,7 @@ project "tests" } end - if (PAL_BUILD_VIDEO) then + if (PAL_BUILD_VIDEO_MODULE) then files { "video/video_test.c", "video/monitor_test.c", @@ -52,7 +52,7 @@ project "tests" } end - if (PAL_BUILD_OPENGL and PAL_BUILD_VIDEO) then + if (PAL_BUILD_OPENGL_MODULE and PAL_BUILD_VIDEO_MODULE) then files { "opengl/opengl_test.c", "opengl/opengl_fbconfig_test.c", @@ -61,13 +61,13 @@ project "tests" } end - if (PAL_BUILD_OPENGL and PAL_BUILD_VIDEO and PAL_BUILD_THREAD) then + if (PAL_BUILD_OPENGL_MODULE and PAL_BUILD_VIDEO_MODULE and PAL_BUILD_THREAD_MODULE) then files { "opengl/multi_thread_opengl_test.c" } end - if (PAL_BUILD_GRAPHICS) then + if (PAL_BUILD_GRAPHICS_MODULE) then files { "graphics/graphics_test.c", "graphics/compute_test.c", @@ -76,7 +76,7 @@ project "tests" } end - if (PAL_BUILD_GRAPHICS and PAL_BUILD_VIDEO) then + if (PAL_BUILD_GRAPHICS_MODULE and PAL_BUILD_VIDEO_MODULE) then files { "graphics/clear_color_test.c", "graphics/triangle_test.c", diff --git a/tests/tests_main.c b/tests/tests_main.c index 17d1a810..09a3ca92 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -8,8 +8,8 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - // registerTest(loggerTest, "Logger Test"); - // registerTest(timeTest, "Time Test"); + registerTest(loggerTest, "Logger Test"); + registerTest(timeTest, "Time Test"); // event // registerTest(eventTest, "Event test"); @@ -56,7 +56,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS_MODULE - registerTest(graphicsTest, "Graphics Test"); + // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); From 961992a01096b01f251bf63d826e7344711e9d30 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 12 Jun 2026 15:45:47 +0000 Subject: [PATCH 253/372] recheck event system --- include/pal/pal_event.h | 48 +++++++---------------------------------- pal.lua | 5 ++++- src/pal_event.c | 38 +++----------------------------- tests/tests.lua | 4 ++-- tests/tests_main.c | 8 +++---- 5 files changed, 21 insertions(+), 82 deletions(-) diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index ad059f08..08fb8ad0 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -1,44 +1,27 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ /** - * @defgroup pal_event Event - * Event PAL functionality such as queues, event drivers, and event callbacks. - * + * @defgroup pal_event Event System + * @ingroup pal_event * @{ */ #ifndef _PAL_EVENT_H #define _PAL_EVENT_H -#include "pal_core.h" +#include "pal/core/memory.h" +#include "pal/core/result.h" /** * @struct PalEventDriver * @brief Opaque handle to an event driver. * * @since 1.0 - * @ingroup pal_event */ typedef struct PalEventDriver PalEventDriver; @@ -47,7 +30,6 @@ typedef struct PalEventDriver PalEventDriver; * @brief A single event. * * @since 1.0 - * @ingroup pal_event */ typedef struct PalEvent PalEvent; @@ -59,7 +41,6 @@ typedef struct PalEvent PalEvent; * @param[in] event Pointer to the event. * * @since 1.0 - * @ingroup pal_event * @sa PalPushFn */ typedef void(PAL_CALL* PalEventCallback)( @@ -74,7 +55,6 @@ typedef void(PAL_CALL* PalEventCallback)( * @param[in] event Pointer to the event to push. * * @since 1.0 - * @ingroup pal_event * @sa PalEventCallback */ typedef void(PAL_CALL* PalPushFn)( @@ -93,7 +73,6 @@ typedef void(PAL_CALL* PalPushFn)( * @param[out] event Pointer to the PalEvent to recieve the event. * * @since 1.0 - * @ingroup pal_event * @sa PalPushFn */ typedef bool(PAL_CALL* PalPollFn)( @@ -108,7 +87,6 @@ typedef bool(PAL_CALL* PalPollFn)( * consistency and API use. * * @since 1.3 - * @ingroup pal_event */ typedef enum { PAL_DECORATION_MODE_CLIENT_SIDE, @@ -123,7 +101,6 @@ typedef enum { * API use. * * @since 1.0 - * @ingroup pal_event */ typedef enum { /** @@ -386,7 +363,6 @@ typedef enum { * and API use. * * @since 1.0 - * @ingroup pal_event */ typedef enum { PAL_DISPATCH_NONE, /**< No dispatch.*/ @@ -409,7 +385,6 @@ struct PalEvent { * Provides user-defined event queue push and poll functions. * * @since 1.0 - * @ingroup pal_event */ typedef struct { PalPushFn push; @@ -424,7 +399,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.0 - * @ingroup pal_event */ typedef struct { const PalAllocator* allocator; /**< Set to nullptr to use default.*/ @@ -454,7 +428,6 @@ typedef struct { * thread safe. * * @since 1.0 - * @ingroup pal_event * @sa palDestroyEventDriver */ PAL_API PalResult PAL_CALL palCreateEventDriver( @@ -473,7 +446,6 @@ PAL_API PalResult PAL_CALL palCreateEventDriver( * the event driver is thread safe and `eventDriver` is per thread. * * @since 1.0 - * @ingroup pal_event * @sa palCreateEventDriver */ PAL_API void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver); @@ -499,7 +471,6 @@ PAL_API void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver); * simultaneously setting dispatch mode on the same `eventDriver`. * * @since 1.0 - * @ingroup pal_event * @sa palGetEventDispatchMode */ PAL_API void PAL_CALL palSetEventDispatchMode( @@ -520,7 +491,6 @@ PAL_API void PAL_CALL palSetEventDispatchMode( * simultaneously setting dispatch mode on the same `eventDriver`. * * @since 1.0 - * @ingroup pal_event * @sa palSetEventDispatchMode */ PAL_API PalDispatchMode PAL_CALL palGetEventDispatchMode( @@ -549,7 +519,6 @@ PAL_API PalDispatchMode PAL_CALL palGetEventDispatchMode( * not thread safe. * * @since 1.0 - * @ingroup pal_event * @sa palPollEvent */ PAL_API void PAL_CALL palPushEvent( @@ -576,13 +545,12 @@ PAL_API void PAL_CALL palPushEvent( * not thread safe. * * @since 1.0 - * @ingroup pal_event * @sa palPushEvent */ PAL_API bool PAL_CALL palPollEvent( PalEventDriver* eventDriver, PalEvent* outEvent); -/** @} */ // end of pal_event group +/** @} */ #endif // _PAL_EVENT_H diff --git a/pal.lua b/pal.lua index 88549702..8fd59ac1 100644 --- a/pal.lua +++ b/pal.lua @@ -28,7 +28,10 @@ project "PAL" "src/core/pal_memory.c", "src/core/pal_result.c", "src/core/pal_time.c", - "src/core/pal_version.c" + "src/core/pal_version.c", + + -- event + "src/pal_event.c" } if (PAL_BUILD_SYSTEM_MODULE) then diff --git a/src/pal_event.c b/src/pal_event.c index eed4454f..78f049d4 100644 --- a/src/pal_event.c +++ b/src/pal_event.c @@ -1,37 +1,13 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ -// ================================================== -// Includes -// ================================================== - #include "pal/pal_event.h" #include -// ================================================== -// Typedefs, enums and structs -// ================================================== - #define PAL_MAX_EVENTS 512 typedef struct { @@ -49,10 +25,6 @@ struct PalEventDriver { PalDispatchMode modes[PAL_MAX_EVENTS]; }; -// ================================================== -// Internal API -// ================================================== - static void PAL_CALL defaultPush( void* queue, PalEvent* event) @@ -76,10 +48,6 @@ static bool PAL_CALL defaultPoll( return true; } -// ================================================== -// Public API -// ================================================== - PalResult PAL_CALL palCreateEventDriver( const PalEventDriverCreateInfo* info, PalEventDriver** outEventDriver) diff --git a/tests/tests.lua b/tests/tests.lua index a99e21a5..13e1dc8c 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -15,8 +15,8 @@ project "tests" "core/time_test.c", -- event - -- "event/user_event_test.c", - -- "event/event_test.c" + "event/user_event_test.c", + "event/event_test.c" } if (PAL_BUILD_SYSTEM_MODULE) then diff --git a/tests/tests_main.c b/tests/tests_main.c index 09a3ca92..a998f82c 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -8,12 +8,12 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - registerTest(loggerTest, "Logger Test"); - registerTest(timeTest, "Time Test"); + // registerTest(loggerTest, "Logger Test"); + // registerTest(timeTest, "Time Test"); // event - // registerTest(eventTest, "Event test"); - // registerTest(userEventTest, "User Event Test"); + registerTest(eventTest, "Event test"); + registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE // registerTest(systemTest, "System Test"); From a89b83e3ce7a3940519e63ea3845fe552fe11b7f Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 12 Jun 2026 17:19:31 +0000 Subject: [PATCH 254/372] recheck system module --- include/pal/pal_system.h | 42 +++++++++-------------------------- pal_config.lua | 2 +- src/system/pal_system_linux.c | 35 +++++------------------------ src/system/pal_system_win32.c | 35 +++++------------------------ tests/tests_main.c | 6 ++--- 5 files changed, 26 insertions(+), 94 deletions(-) diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index 3b133e4c..2e6a1041 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -1,36 +1,22 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ /** - * @defgroup pal_system System - * System PAL functionality such as CPU info and Platform info. - * + * @defgroup pal_system CPU and platform + * @ingroup pal_system * @{ */ #ifndef _PAL_SYSTEM_H #define _PAL_SYSTEM_H -#include "pal_core.h" +#include "core/defines.h" +#include "core/result.h" +#include "core/version.h" +#include "core/memory.h" #define PAL_PLATFORM_NAME_SIZE 32 #define PAL_CPU_VENDOR_NAME_SIZE 16 @@ -47,7 +33,6 @@ freely, subject to the following restrictions: * consistency and API use. * * @since 1.0 - * @ingroup pal_system */ typedef enum { PAL_CPU_ARCH_UNKNOWN, @@ -65,7 +50,6 @@ typedef enum { * consistency and API use. * * @since 1.0 - * @ingroup pal_system */ typedef enum { PAL_CPU_FEATURE_SSE = PAL_BIT(0), @@ -93,7 +77,6 @@ typedef enum { * consistency and API use. * * @since 1.0 - * @ingroup pal_system */ typedef enum { PAL_PLATFORM_WINDOWS, @@ -114,7 +97,6 @@ typedef enum { * consistency and API use. * * @since 1.0 - * @ingroup pal_system */ typedef enum { PAL_PLATFORM_API_WIN32, @@ -131,7 +113,6 @@ typedef enum { * @brief Information about a platform (OS). * * @since 1.0 - * @ingroup pal_system */ typedef struct { PalPlatformType type; @@ -147,7 +128,6 @@ typedef struct { * @brief Information about a CPU. * * @since 1.0 - * @ingroup pal_system */ typedef struct { Uint32 numCores; @@ -172,7 +152,6 @@ typedef struct { * Thread safety: Thread-safe if `info` is per thread. * * @since 1.0 - * @ingroup pal_system */ PAL_API PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info); @@ -190,12 +169,11 @@ PAL_API PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info); * thread safe and `info` is per thread. The default allocator is thread safe. * * @since 1.0 - * @ingroup pal_system */ PAL_API PalResult PAL_CALL palGetCPUInfo( const PalAllocator* allocator, PalCPUInfo* info); -/** @} */ // end of pal_system group +/** @} */ #endif // _PAL_SYSTEM_H diff --git a/pal_config.lua b/pal_config.lua index 04037df9..642f4eb7 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -6,7 +6,7 @@ PAL_BUILD_STATIC_LIBRARY = false PAL_BUILD_TEST_APPLICATION = true -- build system module -PAL_BUILD_SYSTEM_MODULE = false +PAL_BUILD_SYSTEM_MODULE = true -- build thread module PAL_BUILD_THREAD_MODULE = false diff --git a/src/system/pal_system_linux.c b/src/system/pal_system_linux.c index 386afd42..dae82996 100644 --- a/src/system/pal_system_linux.c +++ b/src/system/pal_system_linux.c @@ -1,29 +1,10 @@ - /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ -// ================================================== -// Includes -// ================================================== +#ifdef __linux__ #define _GNU_SOURCE #define _POSIX_C_SOURCE 200112L @@ -68,8 +49,6 @@ static Uint32 parseCache(const char* path) return cacheSize; } -void palSetLastPlatformError(Uint32 e); - // ================================================== // Public API // ================================================== @@ -95,7 +74,6 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) FILE* file = fopen("/etc/os-release", "r"); if (!file) { - palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; } @@ -124,7 +102,6 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) struct statvfs stats; if (statvfs("/", &stats) != 0) { - palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; } @@ -148,7 +125,6 @@ PalResult PAL_CALL palGetCPUInfo( FILE* file = fopen("/proc/cpuinfo", "r"); if (!file) { - palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; } @@ -228,7 +204,6 @@ PalResult PAL_CALL palGetCPUInfo( // get architecture struct utsname arch; if (uname(&arch) != 0) { - palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; } @@ -254,3 +229,5 @@ PalResult PAL_CALL palGetCPUInfo( return PAL_RESULT_SUCCESS; } + +#endif // __linux__ \ No newline at end of file diff --git a/src/system/pal_system_win32.c b/src/system/pal_system_win32.c index 183ba674..a374eccc 100644 --- a/src/system/pal_system_win32.c +++ b/src/system/pal_system_win32.c @@ -1,32 +1,13 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ -// ================================================== -// Includes -// ================================================== - #include "pal/pal_system.h" +#ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif // WIN32_LEAN_AND_MEAN @@ -117,8 +98,6 @@ static inline bool isVersionWin32( return osVersion->build >= build; } -void palSetLastPlatformError(Uint32 e); - // ================================================== // Public API // ================================================== @@ -134,8 +113,6 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) // get windows build, version and combine them if (!getVersionWin32(&info->version)) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); return PAL_RESULT_PLATFORM_FAILURE; } @@ -272,8 +249,6 @@ PalResult PAL_CALL palGetCPUInfo( BOOL ret = GetLogicalProcessorInformationEx(RelationAll, buffer, &len); if (!ret) { palFree(allocator, buffer); - DWORD error = GetLastError(); - palSetLastPlatformError(error); return PAL_RESULT_PLATFORM_FAILURE; } @@ -364,3 +339,5 @@ PalResult PAL_CALL palGetCPUInfo( info->features = features; return PAL_RESULT_SUCCESS; } + +#endif // _WIN32 \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index a998f82c..7337289c 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -12,11 +12,11 @@ int main(int argc, char** argv) // registerTest(timeTest, "Time Test"); // event - registerTest(eventTest, "Event test"); - registerTest(userEventTest, "User Event Test"); + // registerTest(eventTest, "Event test"); + // registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE - // registerTest(systemTest, "System Test"); + registerTest(systemTest, "System Test"); #endif // PAL_HAS_SYSTEM_MODULE #if PAL_HAS_THREAD_MODULE From edea28c620972e693a00239f0bc036078c387383 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 12 Jun 2026 23:18:47 +0000 Subject: [PATCH 255/372] expand thread system to multiple files --- include/pal/core/defines.h | 2 +- include/pal/core/log.h | 2 +- include/pal/core/memory.h | 2 +- include/pal/core/pack.h | 2 +- include/pal/core/result.h | 2 +- include/pal/core/time.h | 2 +- include/pal/core/version.h | 2 +- include/pal/pal_thread.h | 656 +----------------- include/pal/thread/condvar.h | 136 ++++ include/pal/thread/mutex.h | 94 +++ include/pal/thread/thread.h | 343 +++++++++ include/pal/thread/tls.h | 101 +++ pal.lua | 14 +- pal_config.lua | 4 +- src/core/pal_log.c | 2 +- src/core/pal_memory.c | 3 + src/core/pal_time.c | 2 + src/system/pal_system_linux.c | 13 - src/system/pal_system_win32.c | 12 - src/thread/pal_condvar_posix.c | 113 +++ src/thread/pal_mutex_posix.c | 63 ++ ...{pal_thread_linux.c => pal_thread_posix.c} | 242 +------ src/thread/pal_tls_posix.c | 35 + tests/tests_main.c | 10 +- 24 files changed, 932 insertions(+), 925 deletions(-) create mode 100644 include/pal/thread/condvar.h create mode 100644 include/pal/thread/mutex.h create mode 100644 include/pal/thread/thread.h create mode 100644 include/pal/thread/tls.h create mode 100644 src/thread/pal_condvar_posix.c create mode 100644 src/thread/pal_mutex_posix.c rename src/thread/{pal_thread_linux.c => pal_thread_posix.c} (50%) create mode 100644 src/thread/pal_tls_posix.c diff --git a/include/pal/core/defines.h b/include/pal/core/defines.h index c40961ae..06d89c94 100644 --- a/include/pal/core/defines.h +++ b/include/pal/core/defines.h @@ -6,7 +6,7 @@ */ /** - * @defgroup defines Base defines + * @defgroup defines Defines section * @ingroup pal_core * @{ */ diff --git a/include/pal/core/log.h b/include/pal/core/log.h index 892a8797..fb4e1bff 100644 --- a/include/pal/core/log.h +++ b/include/pal/core/log.h @@ -6,7 +6,7 @@ */ /** - * @defgroup log Log System + * @defgroup log Log section * @ingroup pal_core * @{ */ diff --git a/include/pal/core/memory.h b/include/pal/core/memory.h index 7b4c0425..44a62c18 100644 --- a/include/pal/core/memory.h +++ b/include/pal/core/memory.h @@ -6,7 +6,7 @@ */ /** - * @defgroup memory Memory System + * @defgroup memory Memory section * @ingroup pal_core * @{ */ diff --git a/include/pal/core/pack.h b/include/pal/core/pack.h index ee8aa73f..3efd760f 100644 --- a/include/pal/core/pack.h +++ b/include/pal/core/pack.h @@ -6,7 +6,7 @@ */ /** - * @defgroup pack Packing and unpacking helpers + * @defgroup pack Packing and unpack helpers section * @ingroup pal_core * @{ */ diff --git a/include/pal/core/result.h b/include/pal/core/result.h index 8bf8e6cc..9bc393a1 100644 --- a/include/pal/core/result.h +++ b/include/pal/core/result.h @@ -6,7 +6,7 @@ */ /** - * @defgroup result Result codes + * @defgroup result Result codes section * @ingroup pal_core * @{ */ diff --git a/include/pal/core/time.h b/include/pal/core/time.h index e10f97c7..a26aec4e 100644 --- a/include/pal/core/time.h +++ b/include/pal/core/time.h @@ -7,7 +7,7 @@ */ /** - * @defgroup time Time System + * @defgroup time Time section * @ingroup pal_core * @{ */ diff --git a/include/pal/core/version.h b/include/pal/core/version.h index 2324f0d9..8b40ad7a 100644 --- a/include/pal/core/version.h +++ b/include/pal/core/version.h @@ -6,7 +6,7 @@ */ /** - * @defgroup version Versioning + * @defgroup version Version section * @ingroup pal_core * @{ */ diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index a50ec654..a8d0dd68 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -1,661 +1,23 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ /** - * @defgroup pal_thread Thread - * Thread PAL functionality such as Threads, mutxes, condition variables and - * TLS. - * + * @defgroup pal_thread Thread System * @{ */ #ifndef _PAL_THREAD_H #define _PAL_THREAD_H -#include "pal_core.h" - -/** - * @typedef PalTLSId - * @brief Opaque handle to a Thread Local Storage. - * - * @since 1.0 - * @ingroup pal_thread - */ -typedef Uint32 PalTLSId; - -/** - * @struct PalThread - * @brief Opaque handle to a thread. - * - * @since 1.0 - * @ingroup pal_thread - */ -typedef struct PalThread PalThread; - -/** - * @struct PalMutex - * @brief Opaque handle to a mutex. - * - * @since 1.0 - * @ingroup pal_thread - */ -typedef struct PalMutex PalMutex; - -/** - * @struct PalCondVar - * @brief Opaque handle to a condition variable. - * - * @since 1.0 - * @ingroup pal_thread - */ -typedef struct PalCondVar PalCondVar; - -/** - * @typedef PalThreadFn - * @brief Function pointer type used for thread entry function. - * - * @param[in] arg Optional pointer to user data. Can be nullptr. - * - * @return The return value of the thread as a pointer. - * - * @since 1.0 - * @ingroup pal_thread - */ -typedef void* (*PalThreadFn)(void* arg); - -/** - * @typedef PaTlsDestructorFn - * @brief Function pointer type used for TLS. - * - * This is called when the TLS is destroyed and its value is not nullptr. - * - * @param[in] userData Optional pointer to user data. Can be nullptr. - * - * @since 1.0 - * @ingroup pal_thread - */ -typedef void (*PaTlsDestructorFn)(void* userData); - -/** - * @enum PalThreadFeatures - * @brief Thread system features. - * - * All thread features follow the format `PAL_THREAD_FEATURE_**` for - * consistency and API use. - * - * @since 1.0 - * @ingroup pal_thread - */ -typedef enum { - PAL_THREAD_FEATURE_STACK_SIZE = PAL_BIT(0), - PAL_THREAD_FEATURE_PRIORITY = PAL_BIT(1), - PAL_THREAD_FEATURE_AFFINITY = PAL_BIT(2), - PAL_THREAD_FEATURE_NAME = PAL_BIT(3) -} PalThreadFeatures; - -/** - * @enum PalThreadPriority - * @brief Thread priority types. This is not a bitmask enum. - * - * All thread priority types follow the format `PAL_THREAD_PRIORITY_**` for - * consistency and API use. - * - * @since 1.0 - * @ingroup pal_thread - */ -typedef enum { - PAL_THREAD_PRIORITY_LOW, - PAL_THREAD_PRIORITY_NORMAL, - PAL_THREAD_PRIORITY_HIGH -} PalThreadPriority; - -/** - * @struct PalThreadCreateInfo - * @brief Creation parameters for a thread. - * - * Uninitialized fields may result in undefined behavior. - * - * @since 1.0 - * @ingroup pal_thread - */ -typedef struct { - Uint64 stackSize; /**< Set to 0 to use default*/ - const PalAllocator* allocator; /**< Set to nullptr to use default.*/ - PalThreadFn entry; /**< Thread entry function*/ - void* arg; /**< Optional user-provided data. Can be nullptr.*/ -} PalThreadCreateInfo; - -/** - * @brief Create a new thread. - * - * The allocator field in the provided PalThreadCreateInfo struct will not - * be copied, therefore the pointer must remain valid until the win is - * detached. Detach the thread with palDetachThread() when no - * longer needed. - * - * The created thread starts executing from the entry function. The thread runs - * until the entry function has finished executing or its detached. - * - * @param[in] info Pointer to a PalThreadCreateInfo struct that specifies - * parameters. Must not be nullptr. - * @param[out] outThread Pointer to a PalThread to recieve the created - * thread. Must not be nullptr. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if the provided allocator is - * thread safe and `outThread` is per thread. The default allocator is - * thread safe. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palDetachThread - */ -PAL_API PalResult PAL_CALL palCreateThread( - const PalThreadCreateInfo* info, - PalThread** outThread); - -/** - * @brief Wait for the provided thread to finish executing. - * - * After the thread is done executing, it is freed automatically and - * must not be used anymore nor detached. - * - * @param[in] thread Pointer to the thread. - * @param[out] retval Optionally pointer to get the threads exit value. - * Pass the address of the pointer. Internally it will be reinterpreted into a - * pointer-to-pointer. This is for ABI stability. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if `retval` is per thread. - * - * @since 1.0 - * @ingroup pal_thread - */ -PAL_API PalResult PAL_CALL palJoinThread( - PalThread* thread, - void* retval); - -/** - * @brief Release the thread's resources and destroy it. - * - * Must be called when the thread is done executing. - * After this call, the thread cannot be attached or used anymore. - * If the thread is invalid or nullptr, this function returns silently. - * - * This must not be called on a thread that has been attached. - * - * @param[in] thread Pointer to the thread to detach. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - */ -PAL_API void PAL_CALL palDetachThread(PalThread* thread); - -/** - * @brief Suspend the calling thread for the provided duration of milliseconds. - * - * @param[in] milliseconds Number of milliseconds to sleep. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - */ -PAL_API void PAL_CALL palSleep(Uint64 milliseconds); - -/** - * @brief Yield the remainder of the calling threads time sliced, - * allowing other threads of equal priority to run. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - */ -PAL_API void PAL_CALL palYield(); - -/** - * @brief Get the current executing thread. - * - * @return The current thread on success or nullptr on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - */ -PAL_API PalThread* PAL_CALL palGetCurrentThread(); - -/** - * @brief Get the supported features of PAL thread system. - * - * This is based on the platform (OS) features not a single created thread. - * - * @return The thread features on success or 0 on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - */ -PAL_API PalThreadFeatures PAL_CALL palGetThreadFeatures(); - -/** - * @brief Get the priority of the provided thread. - * - * `PAL_THREAD_FEATURE_PRIORITY` must be supported. - * - * @param[in] thread The thread to query priority for. - * - * @return The thread priority on success or 0 on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - */ -PAL_API PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread); - -/** - * @brief Get the affinity of the provided thread. - * - * `PAL_THREAD_FEATURE_AFFINITY` must be supported. Thread affinity is the - * number of CPU cores the thread is allowed to be executed on. - * - * @param[in] thread The thread to query affinity for. - * - * @return The thread affinity on success or 0 on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - */ -PAL_API Uint64 PAL_CALL palGetThreadAffinity(PalThread* thread); - -/** - * @brief Get the name of the provided thread. - * - * `PAL_THREAD_FEATURE_NAME` must be supported. - * fails. Set the buffer to nullptr to get the size of the thread name in bytes. - * - * If the size of the provided buffer is less than the actual size of thread - * name, PAL will write upto that limit. - * - * - * @param[in] thread The thread to query its name. - * @param[in] bufferSize Size of the provided buffer in bytes. - * @param[out] outSize The actual size of the thread name in bytes. - * @param[out] outBuffer Pointer to a user provided buffer to recieve the name. - * Can be nullptr. - * - * Thread safety: Thread safe. - * - * @note On Linux: Thread names are limited to 16 characters including the null - * terminator. - * - * @note On MacOS: Thread names are limited to 64 characters including the null - * terminator. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palSetThreadName - */ -PAL_API PalResult PAL_CALL palGetThreadName( - PalThread* thread, - Uint64 bufferSize, - Uint64* outSize, - char* outBuffer); - -/** - * @brief Set the priority of the provided thread. - * - * `PAL_THREAD_FEATURE_PRIORITY` must be supported. - * - * @param[in] thread The thread to set priority for. - * @param[in] priority The new thread priority. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * @return - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - */ -PAL_API PalResult PAL_CALL palSetThreadPriority( - PalThread* thread, - PalThreadPriority priority); - -/** - * @brief Set the affinity of the provided thread. - * - * `PAL_THREAD_FEATURE_AFFINITY` must be supported. - * Thread affinity is the number of CPU cores the thread is allowed to be - * executed on. - * - * To be safe, get the number of CPU cores and use that to build the CPU mask. - * Example: we set a thread to the first and second CPU core. - * - * @code - * Uint64 cpuMask = PAL_BIT(0) | PAL_BIT(1). - * @endcode - * - * @param[in] thread The thread to set affinity for. - * @param[in] mask The CPU core mask. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - */ -PAL_API PalResult PAL_CALL palSetThreadAffinity( - PalThread* thread, - Uint64 mask); - -/** - * @brief Set the name of the provided thread. - * - * `PAL_THREAD_FEATURE_NAME` must be supported. - * The thread name will be visible in debuggers and the Task Manager (Windows). - * - * @param[in] thread The thread - * @param[in] name UTF-8 null terminated string. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe. - * - * @note On Linux: Thread names are limited to 16 characters including the null - * terminator. - * - * @note On MacOS: Thread names are limited to 64 characters including the null - * terminator. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palGetThreadName - */ -PAL_API PalResult PAL_CALL palSetThreadName( - PalThread* thread, - const char* name); - -/** - * @brief Create a new TLS. - * - * The TLS handle can be used by multiple threads to associate thread local - * vaules. The destructor will be called if palDestroyTLS() is called and - * the TLS has a valid value. - * - * @param[in] destructor Pointer to the TLS destructor function. Can be - * nullptr. - * - * @return The TLS on success or 0 on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palDestroyTLS - */ -PAL_API PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor); - -/** - * @brief Destroy the provided TLS. - * - * @param[in] id The TLS to destroy. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palCreateTL - */ -PAL_API void PAL_CALL palDestroyTLS(PalTLSId id); - -/** - * @brief Get the value associated with the provided TLS on the calling thread. - * - * @param[in] id The TLS to query value. - * - * @return the value on success or nullptr on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palSetTLS - */ -PAL_API void* PAL_CALL palGetTLS(PalTLSId id); - -/** - * @brief Set a value associated with the provided TLS on the calling thread. - * - * @param[in] id The TLS to set value to. - * @param[in] data The value to set for the calling thread - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palGetTLS - */ -PAL_API void PAL_CALL palSetTLS( - PalTLSId id, - void* data); - -/** - * @brief Create a mutex. - * - * @param[in] allocator Optional user-provided allocator. Set to nullptr to use - * default. - * @param[out] outMutex Pointer to a PalMutex to recieve the created mutex. - * Must not be nullptr. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if the provided allocator is - * thread safe and `outMutex` is per thread. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palDestroyMutex - */ -PAL_API PalResult PAL_CALL palCreateMutex( - const PalAllocator* allocator, - PalMutex** outMutex); - -/** - * @brief Destroy a mutex - * - * If `mutex` is invalid, this function returns silently. - * The mutex must be unlocked before destroying if it was locked. - * - * @param[in] mutex Pointer to the mutex. - * - * Thread safety: Thread safe if the allocator used to create - * the mutex is thread safe and `mutex` is per thread. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palCreateMutex - */ -PAL_API void PAL_CALL palDestroyMutex(PalMutex* mutex); - -/** - * @brief Lock a mutex. Blocks if the mutex is already locked by another thread. - * - * @param[in] mutex Pointer to the mutex to lock. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palUnlockMutex - */ -PAL_API void PAL_CALL palLockMutex(PalMutex* mutex); - -/** - * @brief Unlock a mutex. - * - * The function must be called by the thread that first locked the mutex. - * - * @param[in] mutex Pointer to the mutex to unlock. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palLockMutex - */ -PAL_API void PAL_CALL palUnlockMutex(PalMutex* mutex); - -/** - * @brief Create a condition variable. - * - * @param[in] allocator Optional user-provided allocator. Set to nullptr to use - * default. - * @param[out] outCondVar Pointer to a PalCondVar to recieve the created - * condition variable. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if the provided allocator is - * thread safe and `outCondVar` is per thread. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palDestroyCondVar - */ -PAL_API PalResult PAL_CALL palCreateCondVar( - const PalAllocator* allocator, - PalCondVar** outCondVar); - -/** - * @brief Destroy a condition variable. - * - * If the condition variable is invalid, this function returns silently. - * Threads must not wait on the condition variable or undefined - * behaviour. - * - * @param[in] condVar Pointer to the condition to destroy - * - * Thread safety: Thread safe if the allocator used to create - * the condition varibale is thread safe and `condVar` is per thread. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palCreateCondVar - */ -PAL_API void PAL_CALL palDestroyCondVar(PalCondVar* condVar); - -/** - * @brief Unlock the provided mutex and wait on the condition variable. - * - * The mutex must be locked before this call. Spurious wakeups may occur, its - * best to use a loop. This waits until the condition varibale is signaled. - * - * Example: - * - * @code - * while (!ready) { palWaitCondVar(condition, mutex); } - * @endcode - * - * @param[in] condVar Pointer to the condition variable. - * @param[in] mutex Pointer to the mutex. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palWaitCondVarTimeout - */ -PAL_API PalResult PAL_CALL palWaitCondVar( - PalCondVar* condVar, - PalMutex* mutex); - -/** - * @brief Unlock the provided mutex and wait on the condition variable. - * - * The mutex must be locked before this call. Spurious wakeups may occur, its - * best to use a loop. If the condition variable is not signaled but the time to - * wait is up `PAL_RESULT_TIMEOUT` is returned. - * - * @param[in] condVar Pointer to the condition variable. - * @param[in] mutex Pointer to the mutex. - * @param[in] milliseconds Timeout in milliseconds. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palWaitCondVar - */ -PAL_API PalResult PAL_CALL palWaitCondVarTimeout( - PalCondVar* condVar, - PalMutex* mutex, - Uint64 milliseconds); - -/** - * @brief Wake a single thread waiting on the condition variable. - * - * @param[in] condVar Pointer to the condition variable. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @ingroup pal_thread - * @sa palBroadcastCondVar - */ -PAL_API void PAL_CALL palSignalCondVar(PalCondVar* condVar); - -/** - * @brief Wake all threads waiting on the condition variable. - * - * @param[in] condVar Pointer to the condition variable. - * - * Thread safety: Thread safe. - * - * @since 1.0. - * @ingroup pal_thread - * @sa palSignalCondVar - */ -PAL_API void PAL_CALL palBroadcastCondVar(PalCondVar* condVar); +#include "thread/condvar.h" +#include "thread/mutex.h" +#include "thread/thread.h" +#include "thread/tls.h" -/** @} */ // end of pal_thread group +/** @} */ #endif // _PAL_THREAD_H diff --git a/include/pal/thread/condvar.h b/include/pal/thread/condvar.h new file mode 100644 index 00000000..1a15a57a --- /dev/null +++ b/include/pal/thread/condvar.h @@ -0,0 +1,136 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup thread Condition variable section + * @ingroup pal_thread + * @{ + */ + +#ifndef _THREAD_CONDVAR_H +#define _THREAD_CONDVAR_H + +#include "mutex.h" + +/** + * @struct PalCondVar + * @brief Opaque handle to a condition variable. + * + * @since 1.0 + */ +typedef struct PalCondVar PalCondVar; + +/** + * @brief Create a condition variable. + * + * @param[in] allocator Optional user-provided allocator. Set to nullptr to use + * default. + * @param[out] outCondVar Pointer to a PalCondVar to recieve the created + * condition variable. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if the provided allocator is + * thread safe and `outCondVar` is per thread. + * + * @since 1.0 + * @sa palDestroyCondVar + */ +PAL_API PalResult PAL_CALL palCreateCondVar( + const PalAllocator* allocator, + PalCondVar** outCondVar); + +/** + * @brief Destroy a condition variable. + * + * If the condition variable is invalid, this function returns silently. + * Threads must not wait on the condition variable or undefined + * behaviour. + * + * @param[in] condVar Pointer to the condition to destroy + * + * Thread safety: Thread safe if the allocator used to create + * the condition varibale is thread safe and `condVar` is per thread. + * + * @since 1.0 + * @sa palCreateCondVar + */ +PAL_API void PAL_CALL palDestroyCondVar(PalCondVar* condVar); + +/** + * @brief Unlock the provided mutex and wait on the condition variable. + * + * The mutex must be locked before this call. Spurious wakeups may occur, its + * best to use a loop. This waits until the condition varibale is signaled. + * + * Example: + * + * @code + * while (!ready) { palWaitCondVar(condition, mutex); } + * @endcode + * + * @param[in] condVar Pointer to the condition variable. + * @param[in] mutex Pointer to the mutex. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palWaitCondVarTimeout + */ +PAL_API PalResult PAL_CALL palWaitCondVar( + PalCondVar* condVar, + PalMutex* mutex); + +/** + * @brief Unlock the provided mutex and wait on the condition variable. + * + * The mutex must be locked before this call. Spurious wakeups may occur, its + * best to use a loop. If the condition variable is not signaled but the time to + * wait is up `PAL_RESULT_TIMEOUT` is returned. + * + * @param[in] condVar Pointer to the condition variable. + * @param[in] mutex Pointer to the mutex. + * @param[in] milliseconds Timeout in milliseconds. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palWaitCondVar + */ +PAL_API PalResult PAL_CALL palWaitCondVarTimeout( + PalCondVar* condVar, + PalMutex* mutex, + Uint64 milliseconds); + +/** + * @brief Wake a single thread waiting on the condition variable. + * + * @param[in] condVar Pointer to the condition variable. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palBroadcastCondVar + */ +PAL_API void PAL_CALL palSignalCondVar(PalCondVar* condVar); + +/** + * @brief Wake all threads waiting on the condition variable. + * + * @param[in] condVar Pointer to the condition variable. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palSignalCondVar + */ +PAL_API void PAL_CALL palBroadcastCondVar(PalCondVar* condVar); + +#endif // _THREAD_CONDVAR_H + +/** @} */ \ No newline at end of file diff --git a/include/pal/thread/mutex.h b/include/pal/thread/mutex.h new file mode 100644 index 00000000..53c492be --- /dev/null +++ b/include/pal/thread/mutex.h @@ -0,0 +1,94 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup thread Mutex section + * @ingroup pal_thread + * @{ + */ + +#ifndef _THREAD_MUTEX_H +#define _THREAD_MUTEX_H + +#include "pal/core/defines.h" +#include "pal/core/result.h" +#include "pal/core/memory.h" + +/** + * @struct PalMutex + * @brief Opaque handle to a mutex. + * + * @since 1.0 + */ +typedef struct PalMutex PalMutex; + +/** + * @brief Create a mutex. + * + * @param[in] allocator Optional user-provided allocator. Set to nullptr to use + * default. + * @param[out] outMutex Pointer to a PalMutex to recieve the created mutex. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if the provided allocator is + * thread safe and `outMutex` is per thread. + * + * @since 1.0 + * @sa palDestroyMutex + */ +PAL_API PalResult PAL_CALL palCreateMutex( + const PalAllocator* allocator, + PalMutex** outMutex); + +/** + * @brief Destroy a mutex + * + * If `mutex` is invalid, this function returns silently. + * The mutex must be unlocked before destroying if it was locked. + * + * @param[in] mutex Pointer to the mutex. + * + * Thread safety: Thread safe if the allocator used to create + * the mutex is thread safe and `mutex` is per thread. + * + * @since 1.0 + * @sa palCreateMutex + */ +PAL_API void PAL_CALL palDestroyMutex(PalMutex* mutex); + +/** + * @brief Lock a mutex. Blocks if the mutex is already locked by another thread. + * + * @param[in] mutex Pointer to the mutex to lock. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palUnlockMutex + */ +PAL_API void PAL_CALL palLockMutex(PalMutex* mutex); + +/** + * @brief Unlock a mutex. + * + * The function must be called by the thread that first locked the mutex. + * + * @param[in] mutex Pointer to the mutex to unlock. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palLockMutex + */ +PAL_API void PAL_CALL palUnlockMutex(PalMutex* mutex); + +#endif // _THREAD_MUTEX_H + +/** @} */ \ No newline at end of file diff --git a/include/pal/thread/thread.h b/include/pal/thread/thread.h new file mode 100644 index 00000000..881e5dd5 --- /dev/null +++ b/include/pal/thread/thread.h @@ -0,0 +1,343 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup thread Thread section + * @ingroup pal_thread + * @{ + */ + +#ifndef _THREAD_THREAD_H +#define _THREAD_THREAD_H + +#include "pal/core/defines.h" +#include "pal/core/memory.h" +#include "pal/core/result.h" + +/** + * @struct PalThread + * @brief Opaque handle to a thread. + * + * @since 1.0 + */ +typedef struct PalThread PalThread; + +/** + * @typedef PalThreadFn + * @brief Function pointer type used for thread entry function. + * + * @param[in] arg Optional pointer to user data. Can be nullptr. + * + * @return The return value of the thread as a pointer. + * + * @since 1.0 + */ +typedef void* (*PalThreadFn)(void* arg); + +/** + * @enum PalThreadFeatures + * @brief Thread system features. + * + * All thread features follow the format `PAL_THREAD_FEATURE_**` for + * consistency and API use. + * + * @since 1.0 + */ +typedef enum { + PAL_THREAD_FEATURE_STACK_SIZE = PAL_BIT(0), + PAL_THREAD_FEATURE_PRIORITY = PAL_BIT(1), + PAL_THREAD_FEATURE_AFFINITY = PAL_BIT(2), + PAL_THREAD_FEATURE_NAME = PAL_BIT(3) +} PalThreadFeatures; + +/** + * @enum PalThreadPriority + * @brief Thread priority types. This is not a bitmask enum. + * + * All thread priority types follow the format `PAL_THREAD_PRIORITY_**` for + * consistency and API use. + * + * @since 1.0 + */ +typedef enum { + PAL_THREAD_PRIORITY_LOW, + PAL_THREAD_PRIORITY_NORMAL, + PAL_THREAD_PRIORITY_HIGH +} PalThreadPriority; + +/** + * @struct PalThreadCreateInfo + * @brief Creation parameters for a thread. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.0 + */ +typedef struct { + Uint64 stackSize; /**< Set to 0 to use default*/ + const PalAllocator* allocator; /**< Set to nullptr to use default.*/ + PalThreadFn entry; /**< Thread entry function*/ + void* arg; /**< Optional user-provided data. Can be nullptr.*/ +} PalThreadCreateInfo; + +/** + * @brief Create a new thread. + * + * The allocator field in the provided PalThreadCreateInfo struct will not + * be copied, therefore the pointer must remain valid until the win is + * detached. Detach the thread with palDetachThread() when no + * longer needed. + * + * The created thread starts executing from the entry function. The thread runs + * until the entry function has finished executing or its detached. + * + * @param[in] info Pointer to a PalThreadCreateInfo struct that specifies + * parameters. Must not be nullptr. + * @param[out] outThread Pointer to a PalThread to recieve the created + * thread. Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if the provided allocator is + * thread safe and `outThread` is per thread. The default allocator is + * thread safe. + * + * @since 1.0 + * @sa palDetachThread + */ +PAL_API PalResult PAL_CALL palCreateThread( + const PalThreadCreateInfo* info, + PalThread** outThread); + +/** + * @brief Wait for the provided thread to finish executing. + * + * After the thread is done executing, it is freed automatically and + * must not be used anymore nor detached. + * + * @param[in] thread Pointer to the thread. + * @param[out] retval Optionally pointer to get the threads exit value. + * Pass the address of the pointer. Internally it will be reinterpreted into a + * pointer-to-pointer. This is for ABI stability. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `retval` is per thread. + * + * @since 1.0 + */ +PAL_API PalResult PAL_CALL palJoinThread( + PalThread* thread, + void* retval); + +/** + * @brief Release the thread's resources and destroy it. + * + * Must be called when the thread is done executing. + * After this call, the thread cannot be attached or used anymore. + * If the thread is invalid or nullptr, this function returns silently. + * + * This must not be called on a thread that has been attached. + * + * @param[in] thread Pointer to the thread to detach. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API void PAL_CALL palDetachThread(PalThread* thread); + +/** + * @brief Suspend the calling thread for the provided duration of milliseconds. + * + * @param[in] milliseconds Number of milliseconds to sleep. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API void PAL_CALL palSleep(Uint64 milliseconds); + +/** + * @brief Yield the remainder of the calling threads time sliced, + * allowing other threads of equal priority to run. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API void PAL_CALL palYield(); + +/** + * @brief Get the current executing thread. + * + * @return The current thread on success or nullptr on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API PalThread* PAL_CALL palGetCurrentThread(); + +/** + * @brief Get the supported features of PAL thread system. + * + * This is based on the platform (OS) features not a single created thread. + * + * @return The thread features on success or 0 on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API PalThreadFeatures PAL_CALL palGetThreadFeatures(); + +/** + * @brief Get the priority of the provided thread. + * + * `PAL_THREAD_FEATURE_PRIORITY` must be supported. + * + * @param[in] thread The thread to query priority for. + * + * @return The thread priority on success or 0 on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread); + +/** + * @brief Get the affinity of the provided thread. + * + * `PAL_THREAD_FEATURE_AFFINITY` must be supported. Thread affinity is the + * number of CPU cores the thread is allowed to be executed on. + * + * @param[in] thread The thread to query affinity for. + * + * @return The thread affinity on success or 0 on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API Uint64 PAL_CALL palGetThreadAffinity(PalThread* thread); + +/** + * @brief Get the name of the provided thread. + * + * `PAL_THREAD_FEATURE_NAME` must be supported. + * fails. Set the buffer to nullptr to get the size of the thread name in bytes. + * + * If the size of the provided buffer is less than the actual size of thread + * name, PAL will write upto that limit. + * + * + * @param[in] thread The thread to query its name. + * @param[in] bufferSize Size of the provided buffer in bytes. + * @param[out] outSize The actual size of the thread name in bytes. + * @param[out] outBuffer Pointer to a user provided buffer to recieve the name. + * Can be nullptr. + * + * Thread safety: Thread safe. + * + * @note On Linux: Thread names are limited to 16 characters including the null + * terminator. + * + * @note On MacOS: Thread names are limited to 64 characters including the null + * terminator. + * + * @since 1.0 + * @sa palSetThreadName + */ +PAL_API PalResult PAL_CALL palGetThreadName( + PalThread* thread, + Uint64 bufferSize, + Uint64* outSize, + char* outBuffer); + +/** + * @brief Set the priority of the provided thread. + * + * `PAL_THREAD_FEATURE_PRIORITY` must be supported. + * + * @param[in] thread The thread to set priority for. + * @param[in] priority The new thread priority. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * @return + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API PalResult PAL_CALL palSetThreadPriority( + PalThread* thread, + PalThreadPriority priority); + +/** + * @brief Set the affinity of the provided thread. + * + * `PAL_THREAD_FEATURE_AFFINITY` must be supported. + * Thread affinity is the number of CPU cores the thread is allowed to be + * executed on. + * + * To be safe, get the number of CPU cores and use that to build the CPU mask. + * Example: we set a thread to the first and second CPU core. + * + * @code + * Uint64 cpuMask = PAL_BIT(0) | PAL_BIT(1). + * @endcode + * + * @param[in] thread The thread to set affinity for. + * @param[in] mask The CPU core mask. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API PalResult PAL_CALL palSetThreadAffinity( + PalThread* thread, + Uint64 mask); + +/** + * @brief Set the name of the provided thread. + * + * `PAL_THREAD_FEATURE_NAME` must be supported. + * The thread name will be visible in debuggers and the Task Manager (Windows). + * + * @param[in] thread The thread + * @param[in] name UTF-8 null terminated string. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe. + * + * @note On Linux: Thread names are limited to 16 characters including the null + * terminator. + * + * @note On MacOS: Thread names are limited to 64 characters including the null + * terminator. + * + * @since 1.0 + * @sa palGetThreadName + */ +PAL_API PalResult PAL_CALL palSetThreadName( + PalThread* thread, + const char* name); + +#endif // _THREAD_THREAD_H + +/** @} */ \ No newline at end of file diff --git a/include/pal/thread/tls.h b/include/pal/thread/tls.h new file mode 100644 index 00000000..3cb43f6a --- /dev/null +++ b/include/pal/thread/tls.h @@ -0,0 +1,101 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +/** + * @defgroup thread TLS section + * @ingroup pal_thread + * @{ + */ + +#ifndef _THREAD_TLS_H +#define _THREAD_TLS_H + +#include "pal/core/defines.h" + +/** + * @typedef PalTLSId + * @brief Opaque handle to a Thread Local Storage. + * + * @since 1.0 + */ +typedef Uint32 PalTLSId; + +/** + * @typedef PaTlsDestructorFn + * @brief Function pointer type used for TLS. + * + * This is called when the TLS is destroyed and its value is not nullptr. + * + * @param[in] userData Optional pointer to user data. Can be nullptr. + * + * @since 1.0 + */ +typedef void (*PaTlsDestructorFn)(void* userData); + +/** + * @brief Create a new TLS. + * + * The TLS handle can be used by multiple threads to associate thread local + * vaules. The destructor will be called if palDestroyTLS() is called and + * the TLS has a valid value. + * + * @param[in] destructor Pointer to the TLS destructor function. Can be + * nullptr. + * + * @return The TLS on success or 0 on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palDestroyTLS + */ +PAL_API PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor); + +/** + * @brief Destroy the provided TLS. + * + * @param[in] id The TLS to destroy. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palCreateTL + */ +PAL_API void PAL_CALL palDestroyTLS(PalTLSId id); + +/** + * @brief Get the value associated with the provided TLS on the calling thread. + * + * @param[in] id The TLS to query value. + * + * @return the value on success or nullptr on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palSetTLS + */ +PAL_API void* PAL_CALL palGetTLS(PalTLSId id); + +/** + * @brief Set a value associated with the provided TLS on the calling thread. + * + * @param[in] id The TLS to set value to. + * @param[in] data The value to set for the calling thread + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palGetTLS + */ +PAL_API void PAL_CALL palSetTLS( + PalTLSId id, + void* data); + +#endif // _THREAD_TLS_H + +/** @} */ \ No newline at end of file diff --git a/pal.lua b/pal.lua index 8fd59ac1..7e2e268b 100644 --- a/pal.lua +++ b/pal.lua @@ -46,10 +46,20 @@ project "PAL" if (PAL_BUILD_THREAD_MODULE) then filter {"system:windows", "configurations:*"} - files { "src/thread/pal_thread_win32.c" } + files { + "src/thread/pal_condvar_win32.c", + "src/thread/pal_mutex_win32.c", + "src/thread/pal_tls_win32.c", + "src/thread/pal_thread_win32.c" + } filter {"system:linux", "configurations:*"} - files { "src/thread/pal_thread_linux.c" } + files { + "src/thread/pal_condvar_posix.c", + "src/thread/pal_mutex_posix.c", + "src/thread/pal_tls_posix.c", + "src/thread/pal_thread_posix.c" + } filter {} end diff --git a/pal_config.lua b/pal_config.lua index 642f4eb7..cb56b04d 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -6,10 +6,10 @@ PAL_BUILD_STATIC_LIBRARY = false PAL_BUILD_TEST_APPLICATION = true -- build system module -PAL_BUILD_SYSTEM_MODULE = true +PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD_MODULE = false +PAL_BUILD_THREAD_MODULE = true -- build video module PAL_BUILD_VIDEO_MODULE = false diff --git a/src/core/pal_log.c b/src/core/pal_log.c index 43709749..511adc63 100644 --- a/src/core/pal_log.c +++ b/src/core/pal_log.c @@ -9,6 +9,7 @@ #include #include #include +#include #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN @@ -76,7 +77,6 @@ static inline LogTLSData* getLogTlsData() if (s_TlsID == 0) { DWORD TLSIndex = FlsAlloc(destroyTlsData); if (TLSIndex == TLS_OUT_OF_INDEXES) { - // FIXME: Use a global log buffer with a mutex return nullptr; } else { // update the TLS using atomic operations to avoid thread race diff --git a/src/core/pal_memory.c b/src/core/pal_memory.c index ffe666cc..e8609225 100644 --- a/src/core/pal_memory.c +++ b/src/core/pal_memory.c @@ -9,7 +9,10 @@ #include #endif // _MSC_VER +#define _GNU_SOURCE +#define _POSIX_C_SOURCE 200112L #include "pal/core/memory.h" +#include #define PAL_DEFAULT_ALIGNMENT 16 diff --git a/src/core/pal_time.c b/src/core/pal_time.c index 305f1a6a..22e39288 100644 --- a/src/core/pal_time.c +++ b/src/core/pal_time.c @@ -5,6 +5,8 @@ Licensed under the Zlib license. See LICENSE file in root. */ +#define _GNU_SOURCE +#define _POSIX_C_SOURCE 200112L #include "pal/core/time.h" #ifdef _WIN32 diff --git a/src/system/pal_system_linux.c b/src/system/pal_system_linux.c index dae82996..2ff0f1e3 100644 --- a/src/system/pal_system_linux.c +++ b/src/system/pal_system_linux.c @@ -5,7 +5,6 @@ */ #ifdef __linux__ - #define _GNU_SOURCE #define _POSIX_C_SOURCE 200112L #include "pal/pal_system.h" @@ -19,14 +18,6 @@ #include #include -// ================================================== -// Typedefs, enums and structs -// ================================================== - -// ================================================== -// Internal API -// ================================================== - static Uint32 parseCache(const char* path) { long cacheSize = 0; @@ -49,10 +40,6 @@ static Uint32 parseCache(const char* path) return cacheSize; } -// ================================================== -// Public API -// ================================================== - PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) { if (!info) { diff --git a/src/system/pal_system_win32.c b/src/system/pal_system_win32.c index a374eccc..b682f80d 100644 --- a/src/system/pal_system_win32.c +++ b/src/system/pal_system_win32.c @@ -28,16 +28,8 @@ #include #endif // _MSC_VER -// ================================================== -// Typedefs, enums and structs -// ================================================== - typedef LONG(WINAPI* RtlGetVersionFn)(PRTL_OSVERSIONINFOW); -// ================================================== -// Internal API -// ================================================== - static inline void cpuid( int regs[4], int leaf, @@ -98,10 +90,6 @@ static inline bool isVersionWin32( return osVersion->build >= build; } -// ================================================== -// Public API -// ================================================== - PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) { if (!info) { diff --git a/src/thread/pal_condvar_posix.c b/src/thread/pal_condvar_posix.c new file mode 100644 index 00000000..07987177 --- /dev/null +++ b/src/thread/pal_condvar_posix.c @@ -0,0 +1,113 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#define _GNU_SOURCE +#define _POSIX_C_SOURCE 200112L +#include "pal/thread/condvar.h" +#include +#include +#include + +struct PalCondVar { + const PalAllocator* allocator; + pthread_cond_t handle; +}; + +struct PalMutex { + const PalAllocator* allocator; + pthread_mutex_t handle; +}; + +PalResult PAL_CALL palCreateCondVar( + const PalAllocator* allocator, + PalCondVar** outCondVar) +{ + if (!outCondVar) { + return PAL_RESULT_NULL_POINTER; + } + + if (allocator) { + if (!allocator->allocate && !allocator->free) { + return PAL_RESULT_INVALID_ALLOCATOR; + } + } + + PalCondVar* condVar = palAllocate(allocator, sizeof(PalCondVar), 0); + if (!condVar) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + pthread_cond_init(&condVar->handle, nullptr); + condVar->allocator = allocator; + *outCondVar = condVar; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyCondVar(PalCondVar* condVar) +{ + if (condVar) { + pthread_cond_destroy(&condVar->handle); + palFree(condVar->allocator, condVar); + } +} + +PalResult PAL_CALL palWaitCondVar( + PalCondVar* condVar, + PalMutex* mutex) +{ + if (!condVar || !mutex) { + return PAL_RESULT_NULL_POINTER; + } + + int ret = pthread_cond_wait(&condVar->handle, &mutex->handle); + if (ret == 0) { + return PAL_RESULT_SUCCESS; + } else if (ret == ETIMEDOUT) { + return PAL_RESULT_TIMEOUT; + } else { + return PAL_RESULT_PLATFORM_FAILURE; + } +} + +PalResult PAL_CALL palWaitCondVarTimeout( + PalCondVar* condVar, + PalMutex* mutex, + Uint64 milliseconds) +{ + if (!condVar || !mutex) { + return PAL_RESULT_NULL_POINTER; + } + + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += milliseconds / 1000; + ts.tv_nsec += (milliseconds % 1000) * 1000000; + + if (ts.tv_nsec >= 1000000000) { + ts.tv_sec++; + ts.tv_nsec -= 1000000000; + } + + if (pthread_cond_timedwait(&condVar->handle, &mutex->handle, &ts) != 0) { + return PAL_RESULT_TIMEOUT; + } + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palSignalCondVar(PalCondVar* condVar) +{ + if (condVar) { + pthread_cond_signal(&condVar->handle); + } +} + +void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) +{ + if (condVar) { + pthread_cond_broadcast(&condVar->handle); + } +} \ No newline at end of file diff --git a/src/thread/pal_mutex_posix.c b/src/thread/pal_mutex_posix.c new file mode 100644 index 00000000..e8fbb9b8 --- /dev/null +++ b/src/thread/pal_mutex_posix.c @@ -0,0 +1,63 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#define _GNU_SOURCE +#define _POSIX_C_SOURCE 200112L +#include "pal/thread/mutex.h" +#include + +struct PalMutex { + const PalAllocator* allocator; + pthread_mutex_t handle; +}; + +PalResult PAL_CALL palCreateMutex( + const PalAllocator* allocator, + PalMutex** outMutex) +{ + if (!outMutex) { + return PAL_RESULT_NULL_POINTER; + } + + if (allocator) { + if (!allocator->allocate && !allocator->free) { + return PAL_RESULT_INVALID_ALLOCATOR; + } + } + + PalMutex* mutex = palAllocate(allocator, sizeof(PalMutex), 0); + if (!mutex) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + pthread_mutex_init(&mutex->handle, nullptr); + mutex->allocator = allocator; + *outMutex = mutex; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyMutex(PalMutex* mutex) +{ + if (mutex) { + pthread_mutex_destroy(&mutex->handle); + palFree(mutex->allocator, mutex); + } +} + +void PAL_CALL palLockMutex(PalMutex* mutex) +{ + if (mutex) { + pthread_mutex_lock(&mutex->handle); + } +} + +void PAL_CALL palUnlockMutex(PalMutex* mutex) +{ + if (mutex) { + pthread_mutex_unlock(&mutex->handle); + } +} \ No newline at end of file diff --git a/src/thread/pal_thread_linux.c b/src/thread/pal_thread_posix.c similarity index 50% rename from src/thread/pal_thread_linux.c rename to src/thread/pal_thread_posix.c index d2940177..842bc5bb 100644 --- a/src/thread/pal_thread_linux.c +++ b/src/thread/pal_thread_posix.c @@ -1,72 +1,21 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ -// ================================================== -// Includes -// ================================================== - #define _GNU_SOURCE #define _POSIX_C_SOURCE 200112L -#include +#include "pal/thread/thread.h" #include -#include +#include #include -#include #include -#include "pal/pal_thread.h" - -// ================================================== -// Typedefs, enums and structs -// ================================================== - #define TO_PAL_HANDLE(type, val) ((type*)(UintPtr)(val)) #define FROM_PAL_HANDLE(type, handle) ((type)(UintPtr)(handle)) -struct PalMutex { - const PalAllocator* allocator; - pthread_mutex_t handle; -}; - -struct PalCondVar { - const PalAllocator* allocator; - pthread_cond_t handle; -}; - -// ================================================== -// Internal API -// ================================================== - -void palSetLastPlatformError(Uint32 e); - -// ================================================== -// Public API -// ================================================== - -// ================================================== -// Thread -// ================================================== - PalResult PAL_CALL palCreateThread( const PalThreadCreateInfo* info, PalThread** outThread) @@ -84,7 +33,6 @@ PalResult PAL_CALL palCreateThread( pthread_t thread; if (info->stackSize == 0) { if (pthread_create(&thread, nullptr, info->entry, info->arg) != 0) { - palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; } @@ -94,7 +42,6 @@ PalResult PAL_CALL palCreateThread( pthread_attr_setstacksize(&attr, info->stackSize); if (pthread_create(&thread, nullptr, info->entry, info->arg) != 0) { - palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; } pthread_attr_destroy(&attr); @@ -127,7 +74,6 @@ PalResult PAL_CALL palJoinThread( if (ret == 0) { return PAL_RESULT_SUCCESS; } else { - palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; } } @@ -308,180 +254,4 @@ PalResult PAL_CALL palSetThreadName( } else { return PAL_RESULT_INVALID_THREAD; } -} - -// ================================================== -// TLS -// ================================================== - -PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor) -{ - pthread_key_t key; - if (pthread_key_create(&key, destructor) != 0) { - return 0; - } - return (PalTLSId)key; -} - -void PAL_CALL palDestroyTLS(PalTLSId id) -{ - pthread_key_delete((pthread_key_t)id); -} - -void* PAL_CALL palGetTLS(PalTLSId id) -{ - return pthread_getspecific((pthread_key_t)id); -} - -void PAL_CALL palSetTLS( - PalTLSId id, - void* data) -{ - pthread_setspecific((pthread_key_t)id, data); -} - -// ================================================== -// Mutex -// ================================================== - -PalResult PAL_CALL palCreateMutex( - const PalAllocator* allocator, - PalMutex** outMutex) -{ - if (!outMutex) { - return PAL_RESULT_NULL_POINTER; - } - - if (allocator) { - if (!allocator->allocate && !allocator->free) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - } - - PalMutex* mutex = palAllocate(allocator, sizeof(PalMutex), 0); - if (!mutex) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - pthread_mutex_init(&mutex->handle, nullptr); - mutex->allocator = allocator; - *outMutex = mutex; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyMutex(PalMutex* mutex) -{ - if (mutex) { - pthread_mutex_destroy(&mutex->handle); - palFree(mutex->allocator, mutex); - } -} - -void PAL_CALL palLockMutex(PalMutex* mutex) -{ - if (mutex) { - pthread_mutex_lock(&mutex->handle); - } -} - -void PAL_CALL palUnlockMutex(PalMutex* mutex) -{ - if (mutex) { - pthread_mutex_unlock(&mutex->handle); - } -} - -// ================================================== -// Condition Variable -// ================================================== - -PalResult PAL_CALL palCreateCondVar( - const PalAllocator* allocator, - PalCondVar** outCondVar) -{ - if (!outCondVar) { - return PAL_RESULT_NULL_POINTER; - } - - if (allocator) { - if (!allocator->allocate && !allocator->free) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - } - - PalCondVar* condVar = palAllocate(allocator, sizeof(PalCondVar), 0); - if (!condVar) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - pthread_cond_init(&condVar->handle, nullptr); - condVar->allocator = allocator; - *outCondVar = condVar; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyCondVar(PalCondVar* condVar) -{ - if (condVar) { - pthread_cond_destroy(&condVar->handle); - palFree(condVar->allocator, condVar); - } -} - -PalResult PAL_CALL palWaitCondVar( - PalCondVar* condVar, - PalMutex* mutex) -{ - if (!condVar || !mutex) { - return PAL_RESULT_NULL_POINTER; - } - - int ret = pthread_cond_wait(&condVar->handle, &mutex->handle); - if (ret == 0) { - return PAL_RESULT_SUCCESS; - } else if (ret == ETIMEDOUT) { - return PAL_RESULT_TIMEOUT; - } else { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } -} - -PalResult PAL_CALL palWaitCondVarTimeout( - PalCondVar* condVar, - PalMutex* mutex, - Uint64 milliseconds) -{ - if (!condVar || !mutex) { - return PAL_RESULT_NULL_POINTER; - } - - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += milliseconds / 1000; - ts.tv_nsec += (milliseconds % 1000) * 1000000; - - if (ts.tv_nsec >= 1000000000) { - ts.tv_sec++; - ts.tv_nsec -= 1000000000; - } - - if (pthread_cond_timedwait(&condVar->handle, &mutex->handle, &ts) != 0) { - return PAL_RESULT_TIMEOUT; - } - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palSignalCondVar(PalCondVar* condVar) -{ - if (condVar) { - pthread_cond_signal(&condVar->handle); - } -} - -void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) -{ - if (condVar) { - pthread_cond_broadcast(&condVar->handle); - } -} +} \ No newline at end of file diff --git a/src/thread/pal_tls_posix.c b/src/thread/pal_tls_posix.c new file mode 100644 index 00000000..7aad534e --- /dev/null +++ b/src/thread/pal_tls_posix.c @@ -0,0 +1,35 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal/thread/tls.h" +#include + +PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor) +{ + pthread_key_t key; + if (pthread_key_create(&key, destructor) != 0) { + return 0; + } + return (PalTLSId)key; +} + +void PAL_CALL palDestroyTLS(PalTLSId id) +{ + pthread_key_delete((pthread_key_t)id); +} + +void* PAL_CALL palGetTLS(PalTLSId id) +{ + return pthread_getspecific((pthread_key_t)id); +} + +void PAL_CALL palSetTLS( + PalTLSId id, + void* data) +{ + pthread_setspecific((pthread_key_t)id, data); +} \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index 7337289c..230769b5 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -16,14 +16,14 @@ int main(int argc, char** argv) // registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE - registerTest(systemTest, "System Test"); + // registerTest(systemTest, "System Test"); #endif // PAL_HAS_SYSTEM_MODULE #if PAL_HAS_THREAD_MODULE - // registerTest(threadTest, "Thread Test"); - // registerTest(tlsTest, "TLS Test"); - // registerTest(mutexTest, "Mutex Test"); - // registerTest(condvarTest, "Condvar Test"); + registerTest(threadTest, "Thread Test"); + registerTest(tlsTest, "TLS Test"); + registerTest(mutexTest, "Mutex Test"); + registerTest(condvarTest, "Condvar Test"); #endif // PAL_HAS_THREAD_MODULE #if PAL_HAS_VIDEO_MODULE From c9263ce6092f592673919f6c710712bb6358407c Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 14 Jun 2026 11:41:12 +0000 Subject: [PATCH 256/372] bump version to 2.0.0 and fix any ABI issues --- CHANGELOG.md | 13 ++++++++++--- src/core/pal_version.c | 6 +++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80d491c1..252186b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -121,7 +121,7 @@ void* retval; palJoinThread(thread, &retval); ``` -## [1.4.0] - 2026-01-00 +## [2.0.0] - 2026-01-00 ### Features @@ -153,6 +153,14 @@ palJoinThread(thread, &retval); - **Graphics:** Added **Graphics System To PAL**. +### Changed +- **All systems:** All enum types have been changed to defines and explicit width types. +- **Thread:** **palJoinThread()** now takes a void** for retval parameter. +- **Opengl:** **palEnumerateGLFBConfigs()** now does not take glWindow parameter anymore. + +### Removed +- **Core:** Removed **PAL_RESULT_DEVICE_LOST** define. + ### Tests - Added grapics example: see **graphics_test.c** @@ -170,5 +178,4 @@ palJoinThread(thread, &retval); - Added texture rendering example: see **texture_test.c** ### Notes -- No API or ABI changes - existing code remains compatible. -- Safe upgrade from **v1.3.0** - just rebuild your project after updating. +- API or ABI changes diff --git a/src/core/pal_version.c b/src/core/pal_version.c index d14c3230..1c1432ec 100644 --- a/src/core/pal_version.c +++ b/src/core/pal_version.c @@ -7,10 +7,10 @@ #include "pal/core/version.h" -#define PAL_VERSION_MAJOR 1 -#define PAL_VERSION_MINOR 4 +#define PAL_VERSION_MAJOR 2 +#define PAL_VERSION_MINOR 0 #define PAL_VERSION_BUILD 0 -#define PAL_VERSION_STRING "1.4.0" +#define PAL_VERSION_STRING "2.0.0" PalVersion PAL_CALL palGetVersion() { From 7f694e76ec47469482a3d83e83af730ca2fd5de3 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 14 Jun 2026 12:58:45 +0000 Subject: [PATCH 257/372] remove bit macros and base type aliases --- CHANGELOG.md | 4 +- include/pal/core/defines.h | 74 +- include/pal/core/memory.h | 8 +- include/pal/core/pack.h | 66 +- include/pal/core/time.h | 4 +- include/pal/core/version.h | 6 +- include/pal/pal_core.h | 2 +- include/pal/pal_event.h | 6 +- include/pal/pal_graphics.h | 946 ++++++++++----------- include/pal/pal_opengl.h | 50 +- include/pal/pal_system.h | 38 +- include/pal/pal_video.h | 250 +++--- include/pal/thread/condvar.h | 2 +- include/pal/thread/thread.h | 22 +- include/pal/thread/tls.h | 2 +- pal_config.lua | 4 +- src/core/pal_memory.c | 10 +- src/core/pal_time.c | 10 +- src/graphics/pal_d3d12.c | 694 +++++++-------- src/graphics/pal_graphics.c | 450 +++++----- src/graphics/pal_vulkan.c | 488 +++++------ src/opengl/pal_opengl_linux.c | 30 +- src/opengl/pal_opengl_win32.c | 40 +- src/pal_event.c | 4 +- src/system/pal_system_linux.c | 16 +- src/system/pal_system_win32.c | 10 +- src/thread/pal_condvar_posix.c | 2 +- src/thread/pal_thread_posix.c | 16 +- src/thread/pal_thread_win32.c | 14 +- src/video/pal_video_linux.c | 238 +++--- src/video/pal_video_win32.c | 162 ++-- tests/core/logger_test.c | 4 +- tests/core/time_test.c | 8 +- tests/event/event_test.c | 20 +- tests/event/user_event_test.c | 6 +- tests/graphics/clear_color_test.c | 10 +- tests/graphics/compute_test.c | 26 +- tests/graphics/descriptor_indexing_test.c | 48 +- tests/graphics/geometry_test.c | 14 +- tests/graphics/graphics_test.c | 14 +- tests/graphics/indirect_draw_test.c | 36 +- tests/graphics/mesh_test.c | 14 +- tests/graphics/multi_descriptor_set_test.c | 26 +- tests/graphics/ray_tracing_test.c | 24 +- tests/graphics/texture_test.c | 40 +- tests/graphics/triangle_test.c | 16 +- tests/opengl/multi_thread_opengl_test.c | 6 +- tests/opengl/opengl_context_test.c | 4 +- tests/opengl/opengl_fbconfig_test.c | 4 +- tests/opengl/opengl_multi_context_test.c | 4 +- tests/system/system_test.c | 4 +- tests/tests.c | 4 +- tests/tests.h | 4 +- tests/thread/condvar_test.c | 8 +- tests/thread/mutex_test.c | 8 +- tests/thread/thread_test.c | 8 +- tests/thread/tls_test.c | 2 +- tests/video/attach_window_test.c | 10 +- tests/video/char_event_test.c | 2 +- tests/video/cursor_test.c | 8 +- tests/video/custom_decoration_test.c | 20 +- tests/video/icon_test.c | 8 +- tests/video/input_window_test.c | 18 +- tests/video/monitor_mode_test.c | 8 +- tests/video/monitor_test.c | 4 +- tests/video/native_integration_test.c | 4 +- tests/video/window_test.c | 6 +- 67 files changed, 2027 insertions(+), 2091 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 252186b4..cdaed476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,8 +80,8 @@ reflecting its role as the primary explicit foundation for OS and graphics abstr - **Video:** Added **PAL_CONFIG_BACKEND_GLES** to `PalFBConfigBackend` enum. - **Video:** Added **palSetPreferredInstance()** to set the native instance or display PAL video should use rather than creating a new one. -- **Core:** Added **palPackFloat()** to combine two floats into a single Int64 integer. -- **Core:** Added **palUnpackFloat()** to retreive two floats from a single Int64 integer. +- **Core:** Added **palPackFloat()** to combine two floats into a single int64_t integer. +- **Core:** Added **palUnpackFloat()** to retreive two floats from a single int64_t integer. - **OpenGL:** Added **palGLSetInstance()** to set the native instance or display PAL opengl should use. This must be set before calling **palInitGL()**. - **OpenGL:** Added **palGLGetBackend()** to get the opengl backend. diff --git a/include/pal/core/defines.h b/include/pal/core/defines.h index 06d89c94..29e45421 100644 --- a/include/pal/core/defines.h +++ b/include/pal/core/defines.h @@ -15,20 +15,14 @@ #define _CORE_DEFINES_H #include +#include +#include #ifdef __cplusplus #define PAL_EXTERN_C extern "C" #else #define PAL_EXTERN_C #define nullptr ((void*)0) -#define true 1 -#define false 0 - -/** - * @brief A bool - * @since 1.0 - */ -typedef _Bool bool; #endif // __cplusplus // Set up shared library dependencies @@ -62,69 +56,11 @@ typedef _Bool bool; #define PAL_BIG_ENDIAN 0 #endif // __ORDER_BIG_ENDIAN__ -#define PAL_BIT(x) 1 << x -#define PAL_BIT64(x) 1ULL << x -#define PAL_INFINITE UINT32_MAX - -/** - * @brief A signed 8-bit integer - * @since 1.0 - */ -typedef int8_t Int8; - -/** - * @brief A signed 16-bit integer - * @since 1.0 - */ -typedef int16_t Int16; - -/** - * @brief A signed 32-bit integer - * @since 1.0 - */ -typedef int32_t Int32; - -/** - * @brief A signed 64-bit integer - * @since 1.0 - */ -typedef int64_t Int64; - /** - * @brief A signed 64-bit integer pointer - * @since 1.0 + * @brief Sentinel representing an infinite number or time. + * @since 2.0 */ -typedef intptr_t IntPtr; - -/** - * @brief An unsigned 8-bit integer - * @since 1.0 - */ -typedef uint8_t Uint8; - -/** - * @brief An unsigned 16-bit integer - * @since 1.0 - */ -typedef uint16_t Uint16; - -/** - * @brief An unsigned 32-bit integer - * @since 1.0 - */ -typedef uint32_t Uint32; - -/** - * @brief An unsigned 64-bit integer - * @since 1.0 - */ -typedef uint64_t Uint64; - -/** - * @brief An unsigned 64-bit integer pointer - * @since 1.0 - */ -typedef uintptr_t UintPtr; +#define PAL_INFINITE UINT32_MAX #endif // _CORE_DEFINES_H diff --git a/include/pal/core/memory.h b/include/pal/core/memory.h index 44a62c18..210ae37e 100644 --- a/include/pal/core/memory.h +++ b/include/pal/core/memory.h @@ -31,8 +31,8 @@ */ typedef void*(PAL_CALL* PalAllocateFn)( void* userData, - Uint64 size, - Uint64 alignment); + uint64_t size, + uint64_t alignment); /** * @typedef PalFreeFn @@ -80,8 +80,8 @@ typedef struct { */ PAL_API void* PAL_CALL palAllocate( const PalAllocator* allocator, - Uint64 size, - Uint64 alignment); + uint64_t size, + uint64_t alignment); /** * Free memory allocated by palAllocate. diff --git a/include/pal/core/pack.h b/include/pal/core/pack.h index 3efd760f..06e466eb 100644 --- a/include/pal/core/pack.h +++ b/include/pal/core/pack.h @@ -28,11 +28,11 @@ * @since 1.0 * @sa palUnpackUint32 */ -static inline Int64 PAL_CALL palPackUint32( - Uint32 low, - Uint32 high) +static inline int64_t PAL_CALL palPackUint32( + uint32_t low, + uint32_t high) { - return (Int64)(((Uint64)high << 32) | (Uint64)low); + return (int64_t)(((uint64_t)high << 32) | (uint64_t)low); } /** @@ -46,11 +46,11 @@ static inline Int64 PAL_CALL palPackUint32( * @since 1.0 * @sa palUnpackInt32 */ -static inline Int64 PAL_CALL palPackInt32( - Int32 low, - Int32 high) +static inline int64_t PAL_CALL palPackInt32( + int32_t low, + int32_t high) { - return ((Int64)(Uint32)high << 32) | (Uint32)low; + return ((int64_t)(uint32_t)high << 32) | (uint32_t)low; } /** @@ -63,9 +63,9 @@ static inline Int64 PAL_CALL palPackInt32( * @since 1.0 * @sa palUnpackPointer */ -static inline Int64 PAL_CALL palPackPointer(void* ptr) +static inline int64_t PAL_CALL palPackPointer(void* ptr) { - return (Int64)(UintPtr)ptr; + return (int64_t)(uintptr_t)ptr; } /** @@ -78,17 +78,17 @@ static inline Int64 PAL_CALL palPackPointer(void* ptr) * @since 1.3 * @sa palUnpackFloat */ -static inline Int64 PAL_CALL palPackFloat( +static inline int64_t PAL_CALL palPackFloat( float low, float high) { - Int64 combined = 0; + int64_t combined = 0; #if PAL_BIG_ENDIAN - memcpy(&((Uint32*)&combined)[0], &high, sizeof(float)); - memcpy(&((Uint32*)&combined)[1], &low, sizeof(float)); + memcpy(&((uint32_t*)&combined)[0], &high, sizeof(float)); + memcpy(&((uint32_t*)&combined)[1], &low, sizeof(float)); #else - memcpy(&((Uint32*)&combined)[0], &low, sizeof(float)); - memcpy(&((Uint32*)&combined)[1], &high, sizeof(float)); + memcpy(&((uint32_t*)&combined)[0], &low, sizeof(float)); + memcpy(&((uint32_t*)&combined)[1], &high, sizeof(float)); #endif // PAL_BIG_ENDIAN return combined; @@ -106,16 +106,16 @@ static inline Int64 PAL_CALL palPackFloat( * @sa palPackUint32 */ static inline void PAL_CALL palUnpackUint32( - Int64 data, - Uint32* outLow, - Uint32* outHigh) + int64_t data, + uint32_t* outLow, + uint32_t* outHigh) { if (outLow) { - *outLow = (Uint32)(data & 0xFFFFFFFF); + *outLow = (uint32_t)(data & 0xFFFFFFFF); } if (outHigh) { - *outHigh = (Uint32)((Uint64)data >> 32); + *outHigh = (uint32_t)((uint64_t)data >> 32); } } @@ -132,16 +132,16 @@ static inline void PAL_CALL palUnpackUint32( * @sa palPackInt32 */ static inline void PAL_CALL palUnpackInt32( - Int64 data, - Int32* outLow, - Int32* outHigh) + int64_t data, + int32_t* outLow, + int32_t* outHigh) { if (outLow) { - *outLow = (Int32)(data & 0xFFFFFFFF); + *outLow = (int32_t)(data & 0xFFFFFFFF); } if (outHigh) { - *outHigh = (Int32)((Uint64)data >> 32); + *outHigh = (int32_t)((uint64_t)data >> 32); } } @@ -155,9 +155,9 @@ static inline void PAL_CALL palUnpackInt32( * @since 1.0 * @sa palPackPointer */ -static inline void* PAL_CALL palUnpackPointer(Int64 data) +static inline void* PAL_CALL palUnpackPointer(int64_t data) { - return (void*)(UintPtr)data; + return (void*)(uintptr_t)data; } /** @@ -173,25 +173,25 @@ static inline void* PAL_CALL palUnpackPointer(Int64 data) * @sa palPackFloat */ static inline void PAL_CALL palUnpackFloat( - Int64 data, + int64_t data, float* low, float* high) { #if PAL_BIG_ENDIAN if (low) { - memcpy(low, &((Uint32*)&data)[1], sizeof(float)); + memcpy(low, &((uint32_t*)&data)[1], sizeof(float)); } if (high) { - memcpy(high, &((Uint32*)&data)[0], sizeof(float)); + memcpy(high, &((uint32_t*)&data)[0], sizeof(float)); } #else if (low) { - memcpy(low, &((Uint32*)&data)[0], sizeof(float)); + memcpy(low, &((uint32_t*)&data)[0], sizeof(float)); } if (high) { - memcpy(high, &((Uint32*)&data)[1], sizeof(float)); + memcpy(high, &((uint32_t*)&data)[1], sizeof(float)); } #endif // PAL_BIG_ENDIAN diff --git a/include/pal/core/time.h b/include/pal/core/time.h index a26aec4e..d4738fce 100644 --- a/include/pal/core/time.h +++ b/include/pal/core/time.h @@ -27,7 +27,7 @@ * @since 1.0 * @sa palGetPerformanceFrequency */ -PAL_API Uint64 PAL_CALL palGetPerformanceCounter(); +PAL_API uint64_t PAL_CALL palGetPerformanceCounter(); /** * Query the frequency of the high-resolution performance counter. @@ -39,7 +39,7 @@ PAL_API Uint64 PAL_CALL palGetPerformanceCounter(); * @since 1.0 * @sa palGetPerformanceCounter */ -PAL_API Uint64 PAL_CALL palGetPerformanceFrequency(); +PAL_API uint64_t PAL_CALL palGetPerformanceFrequency(); #endif // _CORE_TIME_H diff --git a/include/pal/core/version.h b/include/pal/core/version.h index 8b40ad7a..98a60ac4 100644 --- a/include/pal/core/version.h +++ b/include/pal/core/version.h @@ -23,9 +23,9 @@ * @since 1.0 */ typedef struct { - Uint32 major; /**< Major version (breaking changes).*/ - Uint32 minor; /**< Minor version (adding features).*/ - Uint32 build; /**< Build version (bug fixes).*/ + uint32_t major; /**< Major version (breaking changes).*/ + uint32_t minor; /**< Minor version (adding features).*/ + uint32_t build; /**< Build version (bug fixes).*/ } PalVersion; /** diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 5d44a809..15350e15 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -6,7 +6,7 @@ */ /** - * @defgroup pal_core Core System + * @defgroup pal_core Core * @{ */ diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 08fb8ad0..7ce7b7bf 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -373,9 +373,9 @@ typedef enum { struct PalEvent { PalEventType type; - Int64 data; /**< First data payload.*/ - Int64 data2; /**< Second data payload.*/ - Int64 userId; /**< You can have user events upto Int64 max.*/ + int64_t data; /**< First data payload.*/ + int64_t data2; /**< Second data payload.*/ + int64_t userId; /**< You can have user events upto int64_t max.*/ }; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 0b399c42..4e3ca4bc 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -62,21 +62,21 @@ freely, subject to the following restrictions: * @since 1.4 * @ingroup pal_graphics */ -#define PAL_MAKE_SHADER_TARGET(major, minor) ((Uint32)((major) << 8) | (minor)) +#define PAL_MAKE_SHADER_TARGET(major, minor) ((uint32_t)((major) << 8) | (minor)) /** * @brief Get the major of an encoded shader target. * @since 1.4 * @ingroup pal_graphics */ -#define PAL_SHADER_TARGET_MAJOR(target) ((Uint32)(target) >> 8); +#define PAL_SHADER_TARGET_MAJOR(target) ((uint32_t)(target) >> 8); /** * @brief Get the minor of an encoded shader target. * @since 1.4 * @ingroup pal_graphics */ -#define PAL_SHADER_TARGET_MINOR(target) ((Uint32)(target) & 0xFF); +#define PAL_SHADER_TARGET_MINOR(target) ((uint32_t)(target) & 0xFF); /** * @enum PalAdapterFeatures @@ -88,47 +88,47 @@ freely, subject to the following restrictions: * @since 1.4 * @ingroup pal_graphics */ -typedef Uint64 PalAdapterFeatures; +typedef uint64_t PalAdapterFeatures; #define PAL_ADAPTER_FEATURE_NONE 0; -#define PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY PAL_BIT64(1) -#define PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING PAL_BIT64(2) -#define PAL_ADAPTER_FEATURE_MULTI_VIEWPORT PAL_BIT64(3) -#define PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE PAL_BIT64(4) -#define PAL_ADAPTER_FEATURE_TESSELLATION_SHADER PAL_BIT64(5) -#define PAL_ADAPTER_FEATURE_GEOMETRY_SHADER PAL_BIT64(6) -#define PAL_ADAPTER_FEATURE_SHADER_FLOAT16 PAL_BIT64(7) -#define PAL_ADAPTER_FEATURE_SHADER_FLOAT64 PAL_BIT64(8) -#define PAL_ADAPTER_FEATURE_SHADER_INT16 PAL_BIT64(9) -#define PAL_ADAPTER_FEATURE_SHADER_INT64 PAL_BIT64(10) -#define PAL_ADAPTER_FEATURE_RAY_TRACING PAL_BIT64(11) -#define PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING PAL_BIT64(12) -#define PAL_ADAPTER_FEATURE_MESH_SHADER PAL_BIT64(13) -#define PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE PAL_BIT64(14) -#define PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING PAL_BIT64(15) -#define PAL_ADAPTER_FEATURE_SWAPCHAIN PAL_BIT64(16) -#define PAL_ADAPTER_FEATURE_MULTI_VIEW PAL_BIT64(17) -#define PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY PAL_BIT64(18) -#define PAL_ADAPTER_FEATURE_FENCE_RESET PAL_BIT64(19) -#define PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE PAL_BIT64(20) -#define PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE PAL_BIT64(21) -#define PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE PAL_BIT64(22) -#define PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY PAL_BIT64(23) -#define PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE PAL_BIT64(24) -#define PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE PAL_BIT64(25) -#define PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP PAL_BIT64(26) -#define PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE PAL_BIT64(27) -#define PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT PAL_BIT64(28) -#define PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS PAL_BIT64(29) -#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW PAL_BIT64(30) -#define PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH PAL_BIT64(31) -#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT PAL_BIT64(32) -#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH PAL_BIT64(33) -#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT PAL_BIT64(34) -#define PAL_ADAPTER_FEATURE_DISPATCH_BASE PAL_BIT64(35) -#define PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS PAL_BIT64(36) -#define PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS PAL_BIT64(37) -#define PAL_ADAPTER_FEATURE_RAY_QUERY PAL_BIT64(38) +#define PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY (1ULL << 1) +#define PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING (1ULL << 2) +#define PAL_ADAPTER_FEATURE_MULTI_VIEWPORT (1ULL << 3) +#define PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE (1ULL << 4) +#define PAL_ADAPTER_FEATURE_TESSELLATION_SHADER (1ULL << 5) +#define PAL_ADAPTER_FEATURE_GEOMETRY_SHADER (1ULL << 6) +#define PAL_ADAPTER_FEATURE_SHADER_FLOAT16 (1ULL << 7) +#define PAL_ADAPTER_FEATURE_SHADER_FLOAT64 (1ULL << 8) +#define PAL_ADAPTER_FEATURE_SHADER_INT16 (1ULL << 9) +#define PAL_ADAPTER_FEATURE_SHADER_INT64 (1ULL << 10) +#define PAL_ADAPTER_FEATURE_RAY_TRACING (1ULL << 11) +#define PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING (1ULL << 12) +#define PAL_ADAPTER_FEATURE_MESH_SHADER (1ULL << 13) +#define PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE (1ULL << 14) +#define PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING (1ULL << 15) +#define PAL_ADAPTER_FEATURE_SWAPCHAIN (1ULL << 16) +#define PAL_ADAPTER_FEATURE_MULTI_VIEW (1ULL << 17) +#define PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY (1ULL << 18) +#define PAL_ADAPTER_FEATURE_FENCE_RESET (1ULL << 19) +#define PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE (1ULL << 20) +#define PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE (1ULL << 21) +#define PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE (1ULL << 22) +#define PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY (1ULL << 23) +#define PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE (1ULL << 24) +#define PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE (1ULL << 25) +#define PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP (1ULL << 26) +#define PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE (1ULL << 27) +#define PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT (1ULL << 28) +#define PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS (1ULL << 29) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW (1ULL << 30) +#define PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH (1ULL << 31) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT (1ULL << 32) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH (1ULL << 33) +#define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT (1ULL << 34) +#define PAL_ADAPTER_FEATURE_DISPATCH_BASE (1ULL << 35) +#define PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS (1ULL << 36) +#define PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS (1ULL << 37) +#define PAL_ADAPTER_FEATURE_RAY_QUERY (1ULL << 38) /** * @struct PalAdapter @@ -360,7 +360,7 @@ typedef enum PalDebugMessageType PalDebugMessageType; * @since 1.4 * @ingroup pal_graphics */ -typedef Uint64 PalDeviceAddress; +typedef uint64_t PalDeviceAddress; /** * @typedef PalDebugCallback @@ -589,12 +589,12 @@ typedef enum { typedef enum { PAL_IMAGE_USAGE_UNDEFINED = 0, - PAL_IMAGE_USAGE_COLOR_ATTACHEMENT = PAL_BIT(0), - PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT = PAL_BIT(1), - PAL_IMAGE_USAGE_TRANSFER_SRC = PAL_BIT(2), - PAL_IMAGE_USAGE_TRANSFER_DST = PAL_BIT(3), - PAL_IMAGE_USAGE_STORAGE = PAL_BIT(4), - PAL_IMAGE_USAGE_SAMPLED = PAL_BIT(5) + PAL_IMAGE_USAGE_COLOR_ATTACHEMENT = (1ULL << 0), + PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT = (1ULL << 1), + PAL_IMAGE_USAGE_TRANSFER_SRC = (1ULL << 2), + PAL_IMAGE_USAGE_TRANSFER_DST = (1ULL << 3), + PAL_IMAGE_USAGE_STORAGE = (1ULL << 4), + PAL_IMAGE_USAGE_SAMPLED = (1ULL << 5) } PalImageUsages; /** @@ -608,12 +608,12 @@ typedef enum { * @ingroup pal_graphics */ typedef enum { - PAL_SHADER_FORMAT_SPIRV = PAL_BIT(0), - PAL_SHADER_FORMAT_DXIL = PAL_BIT(1), - PAL_SHADER_FORMAT_DXBC = PAL_BIT(2), - PAL_SHADER_FORMAT_GLSL = PAL_BIT(3), - PAL_SHADER_FORMAT_MSL = PAL_BIT(4), - PAL_SHADER_FORMAT_PPM = PAL_BIT(5) + PAL_SHADER_FORMAT_SPIRV = (1ULL << 0), + PAL_SHADER_FORMAT_DXIL = (1ULL << 1), + PAL_SHADER_FORMAT_DXBC = (1ULL << 2), + PAL_SHADER_FORMAT_GLSL = (1ULL << 3), + PAL_SHADER_FORMAT_MSL = (1ULL << 4), + PAL_SHADER_FORMAT_PPM = (1ULL << 5) } PalShaderFormats; /** @@ -945,8 +945,8 @@ typedef enum { * @ingroup pal_graphics */ typedef enum { - PAL_STENCIL_FACE_FRONT = PAL_BIT(0), - PAL_STENCIL_FACE_BACK = PAL_BIT(1), + PAL_STENCIL_FACE_FRONT = (1ULL << 0), + PAL_STENCIL_FACE_BACK = (1ULL << 1), PAL_STENCIL_FACE_BOTH = PAL_STENCIL_FACE_FRONT | PAL_STENCIL_FACE_BACK } PalStencilFaceFlags; @@ -963,35 +963,35 @@ typedef enum { typedef enum { PAL_VERTEX_TYPE_UNDEFINED, - PAL_VERTEX_TYPE_INT32, /**< Int32.*/ - PAL_VERTEX_TYPE_INT32_2, /**< Int32 vec2 or array[2].*/ - PAL_VERTEX_TYPE_INT32_3, /**< Int32 vec3 or array[3].*/ - PAL_VERTEX_TYPE_INT32_4, /**< Int32 vec4 or array[4].*/ + PAL_VERTEX_TYPE_INT32, /**< int32_t.*/ + PAL_VERTEX_TYPE_INT32_2, /**< int32_t vec2 or array[2].*/ + PAL_VERTEX_TYPE_INT32_3, /**< int32_t vec3 or array[3].*/ + PAL_VERTEX_TYPE_INT32_4, /**< int32_t vec4 or array[4].*/ - PAL_VERTEX_TYPE_UINT32, /**< Uint32.*/ - PAL_VERTEX_TYPE_UINT32_2, /**< Uint32 vec2 or array[2].*/ - PAL_VERTEX_TYPE_UINT32_3, /**< Uint32 vec3 or array[3].*/ - PAL_VERTEX_TYPE_UINT32_4, /**< Uint32 vec4 or array[4].*/ + PAL_VERTEX_TYPE_UINT32, /**< uint32_t.*/ + PAL_VERTEX_TYPE_UINT32_2, /**< uint32_t vec2 or array[2].*/ + PAL_VERTEX_TYPE_UINT32_3, /**< uint32_t vec3 or array[3].*/ + PAL_VERTEX_TYPE_UINT32_4, /**< uint32_t vec4 or array[4].*/ - PAL_VERTEX_TYPE_INT8_2, /**< Int8 vec2 or array[2].*/ - PAL_VERTEX_TYPE_INT8_4, /**< Int8 vec4 or array[4].*/ - PAL_VERTEX_TYPE_UINT8_2, /**< Uint8 vec2 or array[2].*/ - PAL_VERTEX_TYPE_UINT8_4, /**< Uint8 vec4 or array[4].*/ + PAL_VERTEX_TYPE_INT8_2, /**< int8_t vec2 or array[2].*/ + PAL_VERTEX_TYPE_INT8_4, /**< int8_t vec4 or array[4].*/ + PAL_VERTEX_TYPE_UINT8_2, /**< uint8_t vec2 or array[2].*/ + PAL_VERTEX_TYPE_UINT8_4, /**< uint8_t vec4 or array[4].*/ - PAL_VERTEX_TYPE_INT8_2NORM, /**< Int8 vec2 or array[2] normalized.*/ - PAL_VERTEX_TYPE_INT8_4NORM, /**< Int8 vec4 or array[4] normalized.*/ - PAL_VERTEX_TYPE_UINT8_2NORM, /**< Uint8 vec2 or array[2] normalized.*/ - PAL_VERTEX_TYPE_UINT8_4NORM, /**< Uint8 vec4 or array[4] normalized.*/ + PAL_VERTEX_TYPE_INT8_2NORM, /**< int8_t vec2 or array[2] normalized.*/ + PAL_VERTEX_TYPE_INT8_4NORM, /**< int8_t vec4 or array[4] normalized.*/ + PAL_VERTEX_TYPE_UINT8_2NORM, /**< uint8_t vec2 or array[2] normalized.*/ + PAL_VERTEX_TYPE_UINT8_4NORM, /**< uint8_t vec4 or array[4] normalized.*/ - PAL_VERTEX_TYPE_INT16_2, /**< Int16 vec2 or array[2].*/ - PAL_VERTEX_TYPE_INT16_4, /**< Int16 vec4 or array[4].*/ - PAL_VERTEX_TYPE_UINT16_2, /**< Uint16 vec2 or array[2].*/ - PAL_VERTEX_TYPE_UINT16_4, /**< Uint16 vec4 or array[4].*/ + PAL_VERTEX_TYPE_INT16_2, /**< int16_t vec2 or array[2].*/ + PAL_VERTEX_TYPE_INT16_4, /**< int16_t vec4 or array[4].*/ + PAL_VERTEX_TYPE_UINT16_2, /**< uint16_t vec2 or array[2].*/ + PAL_VERTEX_TYPE_UINT16_4, /**< uint16_t vec4 or array[4].*/ - PAL_VERTEX_TYPE_INT16_2NORM, /**< Int16 vec2 or array[2] normalized.*/ - PAL_VERTEX_TYPE_INT16_4NORM, /**< Int16 vec4 or array[4] normalized.*/ - PAL_VERTEX_TYPE_UINT16_2NORM, /**< Uint16 vec2 or array[2] normalized.*/ - PAL_VERTEX_TYPE_UINT16_4NORM, /**< Uint16 vec4 or array[4] normalized.*/ + PAL_VERTEX_TYPE_INT16_2NORM, /**< int16_t vec2 or array[2] normalized.*/ + PAL_VERTEX_TYPE_INT16_4NORM, /**< int16_t vec4 or array[4] normalized.*/ + PAL_VERTEX_TYPE_UINT16_2NORM, /**< uint16_t vec2 or array[2] normalized.*/ + PAL_VERTEX_TYPE_UINT16_4NORM, /**< uint16_t vec4 or array[4] normalized.*/ PAL_VERTEX_TYPE_FLOAT, /**< float*/ PAL_VERTEX_TYPE_FLOAT2, /**< float vec2 or array[2].*/ @@ -1153,10 +1153,10 @@ typedef enum { typedef enum { PAL_COLOR_MASK_NONE = 0, - PAL_COLOR_MASK_RED = PAL_BIT(0), - PAL_COLOR_MASK_GREEN = PAL_BIT(1), - PAL_COLOR_MASK_BLUE = PAL_BIT(2), - PAL_COLOR_MASK_ALPHA = PAL_BIT(3), + PAL_COLOR_MASK_RED = (1ULL << 0), + PAL_COLOR_MASK_GREEN = (1ULL << 1), + PAL_COLOR_MASK_BLUE = (1ULL << 2), + PAL_COLOR_MASK_ALPHA = (1ULL << 3), } PalColorMask; /** @@ -1260,9 +1260,9 @@ typedef enum { * @ingroup pal_graphics */ typedef enum { - PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD = PAL_BIT(0), - PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE = PAL_BIT(1), - PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY = PAL_BIT(2) + PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD = (1ULL << 0), + PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE = (1ULL << 1), + PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY = (1ULL << 2) } PalAccelerationStructureBuildHints; /** @@ -1277,10 +1277,10 @@ typedef enum { * @ingroup pal_graphics */ typedef enum { - PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE = PAL_BIT(0), - PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE = PAL_BIT(1), - PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE = PAL_BIT(2), - PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE = PAL_BIT(3) + PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE = (1ULL << 0), + PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE = (1ULL << 1), + PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE = (1ULL << 2), + PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE = (1ULL << 3) } PalAccelerationStructureInstanceFlags; /** @@ -1308,8 +1308,8 @@ typedef enum { * @ingroup pal_graphics */ typedef enum { - PAL_GEOMETRY_FLAG_OPAQUE = PAL_BIT(0), - PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT = PAL_BIT(1) + PAL_GEOMETRY_FLAG_OPAQUE = (1ULL << 0), + PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT = (1ULL << 1) } PalGeometryFlags; /** @@ -1337,17 +1337,17 @@ typedef enum { * @ingroup pal_graphics */ typedef enum { - PAL_BUFFER_USAGE_VERTEX = PAL_BIT(0), - PAL_BUFFER_USAGE_INDEX = PAL_BIT(1), - PAL_BUFFER_USAGE_UNIFORM = PAL_BIT(2), - PAL_BUFFER_USAGE_STORAGE = PAL_BIT(3), - PAL_BUFFER_USAGE_TRANSFER_SRC = PAL_BIT(4), - PAL_BUFFER_USAGE_TRANSFER_DST = PAL_BIT(5), - PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE = PAL_BIT(6), - PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH = PAL_BIT(7), - PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT = PAL_BIT(8), - PAL_BUFFER_USAGE_DEVICE_ADDRESS = PAL_BIT(9), - PAL_BUFFER_USAGE_INDIRECT = PAL_BIT(10) + PAL_BUFFER_USAGE_VERTEX = (1ULL << 0), + PAL_BUFFER_USAGE_INDEX = (1ULL << 1), + PAL_BUFFER_USAGE_UNIFORM = (1ULL << 2), + PAL_BUFFER_USAGE_STORAGE = (1ULL << 3), + PAL_BUFFER_USAGE_TRANSFER_SRC = (1ULL << 4), + PAL_BUFFER_USAGE_TRANSFER_DST = (1ULL << 5), + PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE = (1ULL << 6), + PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH = (1ULL << 7), + PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT = (1ULL << 8), + PAL_BUFFER_USAGE_DEVICE_ADDRESS = (1ULL << 9), + PAL_BUFFER_USAGE_INDIRECT = (1ULL << 10) } PalBufferUsages; enum PalDebugMessageSeverity { @@ -1439,13 +1439,13 @@ typedef enum { * @ingroup pal_graphics */ typedef struct { - Uint32 vendorId; - Uint32 deviceId; + uint32_t vendorId; + uint32_t deviceId; PalAdapterType type; /**< Discrete, Integrated, etc.*/ PalAdapterApiType apiType; /**< Vulkan, D3D12, etc.*/ PalShaderFormats shaderFormats; /**< Supported shader formats mask (eg. Spirv, DXIL, ect).*/ - Uint64 vram; - Uint64 sharedMemory; + uint64_t vram; + uint64_t sharedMemory; char name[PAL_ADAPTER_NAME_SIZE]; char backendName[PAL_ADAPTER_NAME_SIZE]; /**< Adapter backend name (eg. `PAL`, `Custom`).*/ } PalAdapterInfo; @@ -1458,11 +1458,11 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxWidth; - Uint32 maxHeight; - Uint32 maxDepth; - Uint32 maxArrayLayers; - Uint32 maxMipLevels; + uint32_t maxWidth; + uint32_t maxHeight; + uint32_t maxDepth; + uint32_t maxArrayLayers; + uint32_t maxMipLevels; } PalImageCapabilities; /** @@ -1477,19 +1477,19 @@ typedef struct { bool storageImageDynamicArrayIndexing; bool storageBufferDynamicArrayIndexing; bool uniformBufferDynamicArrayIndexing; - Uint32 maxPerStageSampledImages; - Uint32 maxPerSetSampledImages; - Uint32 maxPerStageStorageImages; - Uint32 maxPerSetStorageImages; - Uint32 maxPerStageSamplers; - Uint32 maxPerSetSamplers; - Uint32 maxPerStageStorageBuffers; - Uint32 maxPerSetStorageBuffers; - Uint32 maxPerStageUniformBuffers; - Uint32 maxPerSetUniformBuffers; - Uint32 maxPerStageAccelerationStructure; - Uint32 maxPerSetAccelerationStructure; - Uint32 maxBoundSets; + uint32_t maxPerStageSampledImages; + uint32_t maxPerSetSampledImages; + uint32_t maxPerStageStorageImages; + uint32_t maxPerSetStorageImages; + uint32_t maxPerStageSamplers; + uint32_t maxPerSetSamplers; + uint32_t maxPerStageStorageBuffers; + uint32_t maxPerSetStorageBuffers; + uint32_t maxPerStageUniformBuffers; + uint32_t maxPerSetUniformBuffers; + uint32_t maxPerStageAccelerationStructure; + uint32_t maxPerSetAccelerationStructure; + uint32_t maxBoundSets; } PalResourceCapabilities; /** @@ -1500,9 +1500,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxWorkGroupInvocations; - Uint32 maxWorkGroupCount[3]; - Uint32 maxWorkGroupSize[3]; + uint32_t maxWorkGroupInvocations; + uint32_t maxWorkGroupCount[3]; + uint32_t maxWorkGroupSize[3]; } PalComputeCapabilities; /** @@ -1513,8 +1513,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxWidth; - Uint32 maxHeight; + uint32_t maxWidth; + uint32_t maxHeight; float minBoundsRange; float maxBoundsRange; } PalViewportCapabilities; @@ -1527,16 +1527,16 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxComputeQueues; - Uint32 maxGraphicsQueues; - Uint32 maxCopyQueues; - Uint32 maxColorAttachments; - Uint32 maxUniformBufferSize; - Uint32 maxStorageBufferSize; - Uint32 maxPushConstantSize; - Uint32 maxVertexLayouts; - Uint32 maxVertexAttributes; - Uint32 maxTessellationPatchPoint; + uint32_t maxComputeQueues; + uint32_t maxGraphicsQueues; + uint32_t maxCopyQueues; + uint32_t maxColorAttachments; + uint32_t maxUniformBufferSize; + uint32_t maxStorageBufferSize; + uint32_t maxPushConstantSize; + uint32_t maxVertexLayouts; + uint32_t maxVertexAttributes; + uint32_t maxTessellationPatchPoint; PalViewportCapabilities viewportCaps; PalImageCapabilities imageCaps; PalResourceCapabilities resourceCaps; @@ -1551,7 +1551,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxAnisotropy; + uint32_t maxAnisotropy; } PalSamplerAnisotropyCapabilities; /** @@ -1562,7 +1562,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxViewCount; + uint32_t maxViewCount; } PalMultiViewCapabilities; /** @@ -1573,7 +1573,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxCount; + uint32_t maxCount; } PalMultiViewportCapabilities; /** @@ -1598,10 +1598,10 @@ typedef struct { */ typedef struct { bool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; - Uint32 minTexelWidth; - Uint32 minTexelHeight; - Uint32 maxTexelWidth; - Uint32 maxTexelHeight; + uint32_t minTexelWidth; + uint32_t minTexelHeight; + uint32_t maxTexelWidth; + uint32_t maxTexelHeight; bool combinerOps[PAL_MAX_COMBINER_OPS]; } PalFragmentShadingRateCapabilities; @@ -1613,12 +1613,12 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxOutputPrimitives; - Uint32 maxOutputVertices; - Uint32 maxWorkGroupInvocations; - Uint32 maxTaskWorkGroupInvocations; - Uint32 maxWorkGroupCount[3]; - Uint32 maxTaskWorkGroupCount[3]; + uint32_t maxOutputPrimitives; + uint32_t maxOutputVertices; + uint32_t maxWorkGroupInvocations; + uint32_t maxTaskWorkGroupInvocations; + uint32_t maxWorkGroupCount[3]; + uint32_t maxTaskWorkGroupCount[3]; } PalMeshShaderCapabilities; /** @@ -1629,13 +1629,13 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 maxRecursionDepth; - Uint32 maxHitAttributeSize; - Uint32 maxInstanceCount; - Uint32 maxPrimitiveCount; - Uint32 maxGeometryCount; - Uint32 maxPayloadSize; - Uint32 maxDispatchInvocations; + uint32_t maxRecursionDepth; + uint32_t maxHitAttributeSize; + uint32_t maxInstanceCount; + uint32_t maxPrimitiveCount; + uint32_t maxGeometryCount; + uint32_t maxPayloadSize; + uint32_t maxDispatchInvocations; } PalRayTracingCapabilities; /** @@ -1654,18 +1654,18 @@ typedef struct { bool storageBufferUpdateAfterBind; bool uniformBufferNonUniformIndexing; bool uniformBufferUpdateAfterBind; - Uint32 maxPerStageSampledImages; - Uint32 maxPerSetSampledImages; - Uint32 maxPerStageStorageImages; - Uint32 maxPerSetStorageImages; - Uint32 maxPerStageSamplers; - Uint32 maxPerSetSamplers; - Uint32 maxPerStageStorageBuffers; - Uint32 maxPerSetStorageBuffers; - Uint32 maxPerStageUniformBuffers; - Uint32 maxPerSetUniformBuffers; - Uint32 maxPerStageAccelerationStructure; - Uint32 maxPerSetAccelerationStructure; + uint32_t maxPerStageSampledImages; + uint32_t maxPerSetSampledImages; + uint32_t maxPerStageStorageImages; + uint32_t maxPerSetStorageImages; + uint32_t maxPerStageSamplers; + uint32_t maxPerSetSamplers; + uint32_t maxPerStageStorageBuffers; + uint32_t maxPerSetStorageBuffers; + uint32_t maxPerStageUniformBuffers; + uint32_t maxPerSetUniformBuffers; + uint32_t maxPerStageAccelerationStructure; + uint32_t maxPerSetAccelerationStructure; } PalDescriptorIndexingCapabilities; /** @@ -1679,13 +1679,13 @@ typedef struct { bool presentModes[PAL_PRESENT_MODE_MAX]; bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; bool formats[PAL_SURFACE_FORMAT_MAX]; - Uint32 minImageCount; - Uint32 maxImageCount; - Uint32 minImageWidth; - Uint32 minImageHeight; - Uint32 maxImageWidth; - Uint32 maxImageHeight; - Uint32 maxImageArrayLayers; + uint32_t minImageCount; + uint32_t maxImageCount; + uint32_t minImageWidth; + uint32_t minImageHeight; + uint32_t maxImageWidth; + uint32_t maxImageHeight; + uint32_t maxImageArrayLayers; } PalSurfaceCapabilities; /** @@ -1726,10 +1726,10 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 width; /**< Width of the image in pixels.*/ - Uint32 height; /**< Height of the image in pixels.*/ - Uint32 depthOrArraySize; /**< Depth for 3D image and array size for 2D image.*/ - Uint32 mipLevelCount; + uint32_t width; /**< Width of the image in pixels.*/ + uint32_t height; /**< Height of the image in pixels.*/ + uint32_t depthOrArraySize; /**< Depth for 3D image and array size for 2D image.*/ + uint32_t mipLevelCount; PalSampleCount sampleCount; PalImageType type; /**< 1D, 2D, 3D.*/ PalFormat format; @@ -1749,7 +1749,7 @@ typedef struct { typedef struct { float color[4]; /**< Color for color attachments only.*/ float depth; - Uint32 stencil; + uint32_t stencil; } PalClearValue; /** @@ -1767,8 +1767,8 @@ typedef struct { PalLoadOp stencilLoadOp; PalStoreOp stencilStoreOp; PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ - Uint32 texelWidth; /**< Texel width for fragment shading rate attachment.*/ - Uint32 texelHeight; /**< Texel height for fragment shading rate attachment.*/ + uint32_t texelWidth; /**< Texel width for fragment shading rate attachment.*/ + uint32_t texelHeight; /**< Texel height for fragment shading rate attachment.*/ PalImageView* imageView; /**< Image view. Must not be nullptr.*/ PalImageView* resolveImageView; /**< Optional resolve image view.*/ PalClearValue clearValue; @@ -1784,7 +1784,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 shaderStageCount; + uint32_t shaderStageCount; PalUsageState usageState; PalShaderStage* shaderStages; } PalUsageStateInfo; @@ -1813,10 +1813,10 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Int32 x; - Int32 y; - Uint32 width; - Uint32 height; + int32_t x; + int32_t y; + uint32_t width; + uint32_t height; } PalRect2D; /** @@ -1828,9 +1828,9 @@ typedef struct { */ typedef struct { bool memoryTypes[PAL_MEMORY_TYPE_MAX]; - Uint64 memoryMask; - Uint64 size; - Uint64 alignment; + uint64_t memoryMask; + uint64_t size; + uint64_t alignment; } PalMemoryRequirements; /** @@ -1843,8 +1843,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint64 waitValue; - Uint64 signalValue; + uint64_t waitValue; + uint64_t signalValue; PalCommandBuffer* cmdBuffer; PalSemaphore* waitSemaphore; PalSemaphore* signalSemaphore; @@ -1861,8 +1861,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint64 timeout; /**< Timeout in milliseconds.*/ - Uint64 signalValue; + uint64_t timeout; /**< Timeout in milliseconds.*/ + uint64_t signalValue; PalSemaphore* signalSemaphore; PalFence* fence; } PalSwapchainNextImageInfo; @@ -1877,8 +1877,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 imageIndex; /**< Image index to present. Must be 0 and less than max images.*/ - Uint64 waitValue; + uint32_t imageIndex; /**< Image index to present. Must be 0 and less than max images.*/ + uint64_t waitValue; PalSemaphore* waitSemaphore; } PalSwapchainPresentInfo; @@ -1892,8 +1892,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ - Uint32 colorAttachentCount; + uint32_t viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ + uint32_t colorAttachentCount; PalAttachmentDesc* colorAttachments; PalAttachmentDesc* depthStencilAttachment; PalAttachmentDesc* fragmentShadingRateAttachment; @@ -1910,8 +1910,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ - Uint32 colorAttachentCount; + uint32_t viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ + uint32_t colorAttachentCount; PalSampleCount multisampleCount; PalFormat depthStencilAttachmentFormat; PalFormat fragmentShadingRateAttachmentFormat; @@ -1929,9 +1929,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 workCount[3]; - Uint32 workGroupSize[3]; /**< Threads per workgroup per axis of the adapter (GPU).*/ - Uint32 workGroupCount[3]; /**< Workgroups per axis of the adapter (GPU).*/ + uint32_t workCount[3]; + uint32_t workGroupSize[3]; /**< Threads per workgroup per axis of the adapter (GPU).*/ + uint32_t workGroupCount[3]; /**< Workgroups per axis of the adapter (GPU).*/ } PalWorkGroupBuildData; /** @@ -1942,8 +1942,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 workGroupBase[3]; /**< Offset per axis of a dispatch tile.*/ - Uint32 workGroupCount[3]; /**< Workgroup count per axis of a dispatch tile.*/ + uint32_t workGroupBase[3]; /**< Offset per axis of a dispatch tile.*/ + uint32_t workGroupCount[3]; /**< Workgroup count per axis of a dispatch tile.*/ } PalWorkGroupInfo; /** @@ -1956,10 +1956,10 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 vertexCount; - Uint32 instanceCount; - Uint32 firstVertex; - Uint32 firstInstance; + uint32_t vertexCount; + uint32_t instanceCount; + uint32_t firstVertex; + uint32_t firstInstance; } PalDrawIndirectData; /** @@ -1972,11 +1972,11 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 indexCount; - Uint32 instanceCount; - Uint32 firstIndex; - Int32 vertexOffset; - Uint32 firstInstance; + uint32_t indexCount; + uint32_t instanceCount; + uint32_t firstIndex; + int32_t vertexOffset; + uint32_t firstInstance; } PalDrawIndexedIndirectData; /** @@ -1989,9 +1989,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 groupCountXOrWidth; /**< Number of groups on the x axis or width.*/ - Uint32 groupCountXOrHeight; /**< Number of groups on the y axis or height.*/ - Uint32 groupCountXOrDepth; /**< Number of groups on the z axis or depth.*/ + uint32_t groupCountXOrWidth; /**< Number of groups on the x axis or width.*/ + uint32_t groupCountXOrHeight; /**< Number of groups on the y axis or height.*/ + uint32_t groupCountXOrDepth; /**< Number of groups on the z axis or depth.*/ } PalDispatchIndirectData; /** @@ -2028,8 +2028,8 @@ typedef struct { */ typedef struct { PalVertexLayoutType type; - Uint32 binding; - Uint32 attributeCount; + uint32_t binding; + uint32_t attributeCount; PalVertexAttribute* attributes; } PalVertexLayout; @@ -2086,7 +2086,7 @@ typedef struct { bool enableSampleShading; bool enableAlphaToCoverage; PalSampleCount sampleCount; - Uint64 sampleMask; + uint64_t sampleMask; float minSampleShading; } PalMultisampleState; @@ -2171,9 +2171,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 instanceId; - Uint32 mask; - Uint32 hitGroupOffset; + uint32_t instanceId; + uint32_t mask; + uint32_t hitGroupOffset; PalAccelerationStructureInstanceFlags flags; PalAccelerationStructure* blas; float transform[12]; /**< row major (3x4).*/ @@ -2187,9 +2187,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 accelerationStructureSize; - Uint32 scratchBufferSize; - Uint32 updateScratchBufferSize; + uint32_t accelerationStructureSize; + uint32_t scratchBufferSize; + uint32_t updateScratchBufferSize; } PalAccelerationStructureBuildSize; /** @@ -2204,9 +2204,9 @@ typedef struct { typedef struct { PalVertexType vertexType; PalIndexType indexType; - Uint32 vertexStride; - Uint32 indexCount; - Uint32 vertexCount; + uint32_t vertexStride; + uint32_t indexCount; + uint32_t vertexCount; PalDeviceAddress vertexBufferAddress; PalDeviceAddress indexBufferAddress; } PalGeometryDataTriangle; @@ -2221,7 +2221,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 stride; + uint32_t stride; PalDeviceAddress bufferAddress; } PalGeometryDataAABBS; @@ -2236,7 +2236,7 @@ typedef struct { */ typedef struct { PalGeometryFlags flags; - Uint32 primitiveCount; + uint32_t primitiveCount; PalGeometryType type; void* data; /**< Pointer to geometry data. This will be casted based on the geometry type.*/ } PalGeometry; @@ -2252,8 +2252,8 @@ typedef struct { */ typedef struct { PalAccelerationStructureType type; - Uint32 geometryCount; - Uint32 instanceCount; + uint32_t geometryCount; + uint32_t instanceCount; PalAccelerationStructureBuildHints buildHints; PalAccelerationStructureBuildMode buildMode; PalDeviceAddress scratchBufferAddress; @@ -2273,7 +2273,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 descriptorCount; + uint32_t descriptorCount; PalDescriptorType descriptorType; } PalDescriptorSetLayoutBinding; @@ -2288,7 +2288,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 bindingCount; + uint32_t bindingCount; PalDescriptorType descriptorType; } PalDescriptorPoolBindingSize; @@ -2302,9 +2302,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 size; - Uint32 stride; /**< For structured buffers. Will be ignored if not supported. 0 for default.*/ - Uint64 offset; /**< Offset in bytes. If structured, will be divided by `stride`.*/ + uint32_t size; + uint32_t stride; /**< For structured buffers. Will be ignored if not supported. 0 for default.*/ + uint64_t offset; /**< Offset in bytes. If structured, will be divided by `stride`.*/ PalBuffer* buffer; } PalDescriptorBufferInfo; @@ -2357,9 +2357,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 layoutBindingIndex; /**< Index into the descriptor set layout bindings.*/ - Uint32 arrayElement; - Uint32 descriptorCount; + uint32_t layoutBindingIndex; /**< Index into the descriptor set layout bindings.*/ + uint32_t arrayElement; + uint32_t descriptorCount; PalDescriptorType descriptorType; PalDescriptorSet* descriptorSet; PalDescriptorBufferInfo* bufferInfos; @@ -2378,9 +2378,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint64 offset; - Uint64 size; - Uint32 shaderStageCount; + uint64_t offset; + uint64_t size; + uint32_t shaderStageCount; PalShaderStage* shaderStages; } PalPushConstantRange; @@ -2394,10 +2394,10 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 startMipLevel; - Uint32 mipLevelCount; - Uint32 startArrayLayer; - Uint32 layerArrayCount; + uint32_t startMipLevel; + uint32_t mipLevelCount; + uint32_t startArrayLayer; + uint32_t layerArrayCount; PalImageAspect aspect; /**< Must be compatible with the image format.*/ } PalImageSubresourceRange; @@ -2411,9 +2411,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 size; - Uint64 dstOffset; - Uint64 srcOffset; + uint32_t size; + uint64_t dstOffset; + uint64_t srcOffset; } PalBufferCopyInfo; /** @@ -2426,18 +2426,18 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint64 bufferOffset; - Uint32 bufferRowLength; - Uint32 bufferImageHeight; - Uint32 ImageMipLevel; - Uint32 ImageStartArrayLayer; - Uint32 ImageArrayLayerCount; - Int32 imageOffsetX; - Int32 imageOffsetY; - Int32 imageOffsetZ; - Uint32 imageWidth; - Uint32 imageHeight; - Uint32 imageDepth; + uint64_t bufferOffset; + uint32_t bufferRowLength; + uint32_t bufferImageHeight; + uint32_t ImageMipLevel; + uint32_t ImageStartArrayLayer; + uint32_t ImageArrayLayerCount; + int32_t imageOffsetX; + int32_t imageOffsetY; + int32_t imageOffsetZ; + uint32_t imageWidth; + uint32_t imageHeight; + uint32_t imageDepth; PalImageAspect imageAspect; } PalBufferImageCopyInfo; @@ -2451,20 +2451,20 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 dstMipLevel; - Uint32 srcMipLevel; - Uint32 dstStartArrayLayer; - Uint32 srcStartArrayLayer; - Uint32 arrayLayerCount; - Int32 dstOffsetX; - Int32 srcOffsetX; - Int32 dstOffsetY; - Int32 srcOffsetY; - Int32 dstOffsetZ; - Int32 srcOffsetZ; - Uint32 width; - Uint32 height; - Uint32 depth; + uint32_t dstMipLevel; + uint32_t srcMipLevel; + uint32_t dstStartArrayLayer; + uint32_t srcStartArrayLayer; + uint32_t arrayLayerCount; + int32_t dstOffsetX; + int32_t srcOffsetX; + int32_t dstOffsetY; + int32_t srcOffsetY; + int32_t dstOffsetZ; + int32_t srcOffsetZ; + uint32_t width; + uint32_t height; + uint32_t depth; PalImageAspect aspect; } PalImageCopyInfo; @@ -2480,8 +2480,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 groupIndex; /**< Index into the shader groups used to create the ray tracing pipeline.*/ - Uint32 localDataSize; /**< Must not be greater than the data size of the group.*/ + uint32_t groupIndex; /**< Index into the shader groups used to create the ray tracing pipeline.*/ + uint32_t localDataSize; /**< Must not be greater than the data size of the group.*/ void* localData; } PalShaderBindingTableRecordInfo; @@ -2495,7 +2495,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ + uint32_t patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ PalShaderStage stage; const char* entryName; } PalShaderEntryInfo; @@ -2510,10 +2510,10 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 width; - Uint32 height; - Uint32 depthOrArraySize; - Uint32 mipLevelCount; + uint32_t width; + uint32_t height; + uint32_t depthOrArraySize; + uint32_t mipLevelCount; PalSampleCount sampleCount; PalImageType type; PalFormat format; @@ -2572,10 +2572,10 @@ typedef struct { */ typedef struct { bool clipped; - Uint32 width; - Uint32 height; - Uint32 imageCount; - Uint32 imageArrayLayerCount; + uint32_t width; + uint32_t height; + uint32_t imageCount; + uint32_t imageArrayLayerCount; PalPresentMode presentMode; PalCompositeAplha compositeAlpha; PalSurfaceFormat format; @@ -2591,8 +2591,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 entryCount; - Uint64 bytecodeSize; + uint32_t entryCount; + uint64_t bytecodeSize; void* bytecode; PalShaderEntryInfo* entries; } PalShaderCreateInfo; @@ -2608,7 +2608,7 @@ typedef struct { */ typedef struct { PalBufferUsages usages; - Uint64 size; + uint64_t size; } PalBufferCreateInfo; /** @@ -2623,8 +2623,8 @@ typedef struct { typedef struct { PalAccelerationStructureType type; PalBuffer* buffer; - Uint64 offset; - Uint64 size; + uint64_t offset; + uint64_t size; } PalAccelerationStructureCreateInfo; /** @@ -2639,8 +2639,8 @@ typedef struct { */ typedef struct { bool enableDescriptorIndexing; - Uint32 bindingCount; - Uint32 shaderStageCount; + uint32_t bindingCount; + uint32_t shaderStageCount; PalShaderStage* shaderStages; PalDescriptorSetLayoutBinding* bindings; } PalDescriptorSetLayoutCreateInfo; @@ -2657,8 +2657,8 @@ typedef struct { */ typedef struct { bool enableDescriptorIndexing; - Uint32 maxDescriptorSets; - Uint32 maxDescriptorBindingSizes; + uint32_t maxDescriptorSets; + uint32_t maxDescriptorBindingSizes; PalDescriptorPoolBindingSize* bindingSizes; } PalDescriptorPoolCreateInfo; @@ -2672,8 +2672,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 descriptorSetLayoutCount; - Uint32 pushConstantRangeCount; + uint32_t descriptorSetLayoutCount; + uint32_t pushConstantRangeCount; PalDescriptorSetLayout** descriptorSetLayouts; PalPushConstantRange* pushConstantRanges; } PalPipelineLayoutCreateInfo; @@ -2689,9 +2689,9 @@ typedef struct { */ typedef struct { bool primitiveRestartEnable; - Uint32 vertexLayoutCount; - Uint32 colorBlendAttachmentCount; - Uint32 shaderCount; + uint32_t vertexLayoutCount; + uint32_t colorBlendAttachmentCount; + uint32_t shaderCount; PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is true.*/ PalPrimitiveTopology topology; PalPipelineLayout* pipelineLayout; @@ -2732,15 +2732,15 @@ typedef struct { */ typedef struct { PalRayTracingShaderGroupType type; - Uint32 anyHitShaderIndex; - Uint32 anyHitShaderEntryIndex; - Uint32 closestHitShaderIndex; - Uint32 closestHitShaderEntryIndex; - Uint32 generalShaderIndex; - Uint32 generalShaderEntryIndex; - Uint32 intersectionShaderIndex; - Uint32 intersectionShaderEntryIndex; - Uint32 maxDataSize; /**< Size of extra data associated with the shader group.*/ + uint32_t anyHitShaderIndex; + uint32_t anyHitShaderEntryIndex; + uint32_t closestHitShaderIndex; + uint32_t closestHitShaderEntryIndex; + uint32_t generalShaderIndex; + uint32_t generalShaderEntryIndex; + uint32_t intersectionShaderIndex; + uint32_t intersectionShaderEntryIndex; + uint32_t maxDataSize; /**< Size of extra data associated with the shader group.*/ } PalRayTracingShaderGroupCreateInfo; /** @@ -2753,11 +2753,11 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 shaderCount; - Uint32 shaderGroupCount; - Uint32 maxRecursionDepth; - Uint32 maxAttributeSize; - Uint32 maxPayloadSize; + uint32_t shaderCount; + uint32_t shaderGroupCount; + uint32_t maxRecursionDepth; + uint32_t maxAttributeSize; + uint32_t maxPayloadSize; PalPipelineLayout* pipelineLayout; PalRayTracingShaderGroupCreateInfo* shaderGroups; PalShader** shaders; @@ -2773,7 +2773,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - Uint32 recordCount; + uint32_t recordCount; PalShaderBindingTableRecordInfo* records; PalPipeline* rayTracingPipeline; } PalShaderBindingTableCreateInfo; @@ -2794,7 +2794,7 @@ typedef struct { * Must obey the rules and semantics documented in palEnumerateAdapters(). */ PalResult (PAL_CALL *enumerateAdapters)( - Int32* count, + int32_t* count, PalAdapter** outAdapters); /** @@ -2827,7 +2827,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetHighestSupportedShaderTarget(). */ - Uint32 (PAL_CALL *getHighestSupportedShaderTarget)( + uint32_t (PAL_CALL *getHighestSupportedShaderTarget)( PalAdapter* adapter, PalShaderFormats shaderFormat); @@ -2856,8 +2856,8 @@ typedef struct { PalResult (PAL_CALL *allocateMemory)( PalDevice* device, PalMemoryType type, - Uint64 memoryMask, - Uint64 size, + uint64_t memoryMask, + uint64_t size, PalMemory** outMemory); /** @@ -2989,7 +2989,7 @@ typedef struct { */ PalResult (PAL_CALL *enumerateFormats)( PalAdapter* adapter, - Int32* count, + int32_t* count, PalFormatInfo* outFormats); /** @@ -3062,7 +3062,7 @@ typedef struct { PalResult (PAL_CALL *bindImageMemory)( PalImage* image, PalMemory* memory, - Uint64 offset); + uint64_t offset); /** * Backend implementation of ::palMapImageMemory. @@ -3071,8 +3071,8 @@ typedef struct { */ PalResult (PAL_CALL *mapImageMemory)( PalImage* image, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr); /** @@ -3170,7 +3170,7 @@ typedef struct { */ PalImage* (PAL_CALL *getSwapchainImage)( PalSwapchain* swapchain, - Int32 index); + int32_t index); /** * Backend implementation of ::palGetNextSwapchainImage. @@ -3180,7 +3180,7 @@ typedef struct { PalResult (PAL_CALL *getNextSwapchainImage)( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32* outIndex); + uint32_t* outIndex); /** * Backend implementation of ::palPresentSwapchain. @@ -3198,8 +3198,8 @@ typedef struct { */ PalResult (PAL_CALL *resizeSwapchain)( PalSwapchain* swapchain, - Uint32 newWidth, - Uint32 newHeight); + uint32_t newWidth, + uint32_t newHeight); /** * Backend implementation of ::palCreateShader. @@ -3242,7 +3242,7 @@ typedef struct { */ PalResult (PAL_CALL *waitFence)( PalFence* fence, - Uint64 timeout); + uint64_t timeout); /** * Backend implementation of ::palResetFence. @@ -3282,8 +3282,8 @@ typedef struct { */ PalResult (PAL_CALL *waitSemaphore)( PalSemaphore* semaphore, - Uint64 value, - Uint64 timeout); + uint64_t value, + uint64_t timeout); /** * Backend implementation of ::palSignalSemaphore. @@ -3293,7 +3293,7 @@ typedef struct { PalResult (PAL_CALL *signalSemaphore)( PalSemaphore* semaphore, PalQueue* queue, - Uint64 value); + uint64_t value); /** * Backend implementation of ::palGetSemaphoreValue. @@ -3302,7 +3302,7 @@ typedef struct { */ PalResult (PAL_CALL *getSemaphoreValue)( PalSemaphore* semaphore, - Uint64* outValue); + uint64_t* outValue); /** * Backend implementation of ::palCreateCommandPool. @@ -3403,9 +3403,9 @@ typedef struct { */ PalResult (PAL_CALL *cmdDrawMeshTasks)( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); /** * Backend implementation of ::palCmdDrawMeshTasksIndirect. @@ -3415,7 +3415,7 @@ typedef struct { PalResult (PAL_CALL *cmdDrawMeshTasksIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 drawCount); + uint32_t drawCount); /** * Backend implementation of ::palCmdDrawMeshTasksIndirectCount. @@ -3426,7 +3426,7 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount); + uint32_t maxDrawCount); /** * Backend implementation of ::palCmdBuildAccelerationStructure. @@ -3513,7 +3513,7 @@ typedef struct { */ PalResult (PAL_CALL *cmdSetViewport)( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalViewport* viewports); /** @@ -3523,7 +3523,7 @@ typedef struct { */ PalResult (PAL_CALL *cmdSetScissors)( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalRect2D* scissors); /** @@ -3533,10 +3533,10 @@ typedef struct { */ PalResult (PAL_CALL *cmdBindVertexBuffers)( PalCommandBuffer* cmdBuffer, - Uint32 firstSlot, - Uint32 count, + uint32_t firstSlot, + uint32_t count, PalBuffer** buffers, - Uint64* offsets); + uint64_t* offsets); /** * Backend implementation of ::palCmdBindIndexBuffer. @@ -3546,7 +3546,7 @@ typedef struct { PalResult (PAL_CALL *cmdBindIndexBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, + uint64_t offset, PalIndexType type); /** @@ -3556,10 +3556,10 @@ typedef struct { */ PalResult (PAL_CALL *cmdDraw)( PalCommandBuffer* cmdBuffer, - Uint32 vertexCount, - Uint32 instanceCount, - Uint32 firstVertex, - Uint32 firstInstance); + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); /** * Backend implementation of ::palCmdDrawIndirect. @@ -3569,7 +3569,7 @@ typedef struct { PalResult (PAL_CALL *cmdDrawIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count); + uint32_t count); /** * Backend implementation of ::palCmdDrawIndirectCount. @@ -3580,7 +3580,7 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 count); + uint32_t count); /** * Backend implementation of ::palCmdDrawIndexed. @@ -3589,11 +3589,11 @@ typedef struct { */ PalResult (PAL_CALL *cmdDrawIndexed)( PalCommandBuffer* cmdBuffer, - Uint32 indexCount, - Uint32 instanceCount, - Uint32 firstIndex, - Int32 vertexOffset, - Uint32 firstInstance); + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); /** * Backend implementation of ::palCmdDrawIndexedIndirect. @@ -3603,7 +3603,7 @@ typedef struct { PalResult (PAL_CALL *cmdDrawIndexedIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count); + uint32_t count); /** * Backend implementation of ::palCmdDrawIndexedIndirectCount. @@ -3614,7 +3614,7 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 count); + uint32_t count); /** * Backend implementation of ::palCmdAccelerationStructureBarrier. @@ -3657,9 +3657,9 @@ typedef struct { */ PalResult (PAL_CALL *cmdDispatch)( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); /** * Backend implementation of ::palCmdDispatchBase. @@ -3668,12 +3668,12 @@ typedef struct { */ PalResult (PAL_CALL *cmdDispatchBase)( PalCommandBuffer* cmdBuffer, - Uint32 baseGroupX, - Uint32 baseGroupY, - Uint32 baseGroupZ, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); /** * Backend implementation of ::palCmdDispatchIndirect. @@ -3692,10 +3692,10 @@ typedef struct { PalResult (PAL_CALL *cmdTraceRays)( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, - Uint32 raygenIndex, - Uint32 width, - Uint32 height, - Uint32 depth); + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth); /** * Backend implementation of ::palCmdTraceRaysIndirect. @@ -3704,7 +3704,7 @@ typedef struct { */ PalResult (PAL_CALL *cmdTraceRaysIndirect)( PalCommandBuffer* cmdBuffer, - Uint32 raygenIndex, + uint32_t raygenIndex, PalShaderBindingTable* sbt, PalBuffer* buffer); @@ -3715,7 +3715,7 @@ typedef struct { */ PalResult (PAL_CALL *cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, - Uint32 setIndex, + uint32_t setIndex, PalDescriptorSet* set); /** @@ -3725,10 +3725,10 @@ typedef struct { */ PalResult (PAL_CALL *cmdPushConstants)( PalCommandBuffer* cmdBuffer, - Uint32 shaderStageCount, + uint32_t shaderStageCount, PalShaderStage* shaderStages, - Uint32 offset, - Uint32 size, + uint32_t offset, + uint32_t size, const void* value); /** @@ -3849,8 +3849,8 @@ typedef struct { */ PalResult (PAL_CALL *computeInstanceBufferRequirements)( PalDevice* device, - Uint32 instanceCount, - Uint64* outSize); + uint32_t instanceCount, + uint64_t* outSize); /** * Backend implementation of ::palComputeImageCopyStagingBufferRequirements. @@ -3861,9 +3861,9 @@ typedef struct { PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, - Uint32* outBufferRowLength, - Uint32* outBufferImageHeight, - Uint64* outSize); + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize); /** * Backend implementation of ::palWriteToInstanceBuffer. @@ -3874,7 +3874,7 @@ typedef struct { PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, - Uint32 instanceCount); + uint32_t instanceCount); /** * Backend implementation of ::palWriteToImageCopyStagingBuffer. @@ -3896,7 +3896,7 @@ typedef struct { PalResult (PAL_CALL *bindBufferMemory)( PalBuffer* buffer, PalMemory* memory, - Uint64 offset); + uint64_t offset); /** * Backend implementation of ::palMapBufferMemory. @@ -3905,8 +3905,8 @@ typedef struct { */ PalResult (PAL_CALL *mapBufferMemory)( PalBuffer* buffer, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr); /** @@ -3982,7 +3982,7 @@ typedef struct { */ PalResult (PAL_CALL *updateDescriptorSet)( PalDevice* device, - Uint32 count, + uint32_t count, PalDescriptorSetWriteInfo* infos); /** @@ -4063,7 +4063,7 @@ typedef struct { */ PalResult (PAL_CALL *updateShaderBindingTable)( PalShaderBindingTable* sbt, - Uint32 count, + uint32_t count, PalShaderBindingTableRecordInfo* infos); } PalGraphicsBackend; @@ -4176,7 +4176,7 @@ PAL_API void PAL_CALL palShutdownGraphics(); * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palEnumerateAdapters( - Int32* count, + int32_t* count, PalAdapter** outAdapters); /** @@ -4255,7 +4255,7 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); * @ingroup pal_graphics * @sa palEnumerateAdapters */ -PAL_API Uint32 PAL_CALL palGetHighestSupportedShaderTarget( +PAL_API uint32_t PAL_CALL palGetHighestSupportedShaderTarget( PalAdapter* adapter, PalShaderFormats shaderFormat); @@ -4332,8 +4332,8 @@ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); PAL_API PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, - Uint64 memoryMask, - Uint64 size, + uint64_t memoryMask, + uint64_t size, PalMemory** outMemory); /** @@ -4661,7 +4661,7 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); */ PAL_API PalResult PAL_CALL palEnumerateFormats( PalAdapter* adapter, - Int32* count, + int32_t* count, PalFormatInfo* outFormats); /** @@ -4838,7 +4838,7 @@ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( PAL_API PalResult PAL_CALL palBindImageMemory( PalImage* image, PalMemory* memory, - Uint64 offset); + uint64_t offset); /** * @brief Maps image to CPU visible address space. @@ -4869,8 +4869,8 @@ PAL_API PalResult PAL_CALL palBindImageMemory( */ PAL_API PalResult PAL_CALL palMapImageMemory( PalImage* image, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr); /** @@ -5120,7 +5120,7 @@ PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); */ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, - Int32 index); + int32_t index); /** * @brief Get the next available image from the swapchain image list. @@ -5130,7 +5130,7 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( * @param[in] swapchain Swapchain to get image index from. * @param[in] info Pointer to a PalSwapchainNextImageInfo struct that specifies parameters. * Must not be nullptr. - * @param[out] outIndex Pointer to a Uint32 to recieve the next image index. + * @param[out] outIndex Pointer to a uint32_t to recieve the next image index. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5144,7 +5144,7 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PAL_API PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32* outIndex); + uint32_t* outIndex); /** * @brief Present the swapchain. @@ -5189,8 +5189,8 @@ PAL_API PalResult PAL_CALL palPresentSwapchain( */ PAL_API PalResult PAL_CALL palResizeSwapchain( PalSwapchain* swapchain, - Uint32 newWidth, - Uint32 newHeight); + uint32_t newWidth, + uint32_t newHeight); /** * @brief Create a shader. @@ -5315,7 +5315,7 @@ PAL_API void PAL_CALL palDestroyFence(PalFence* fence); */ PAL_API PalResult PAL_CALL palWaitFence( PalFence* fence, - Uint64 timeout); + uint64_t timeout); /** * @brief Reset a fence to an unsignaled state. @@ -5422,8 +5422,8 @@ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); */ PAL_API PalResult PAL_CALL palWaitSemaphore( PalSemaphore* semaphore, - Uint64 value, - Uint64 timeout); + uint64_t value, + uint64_t timeout); /** * @brief Signals a semaphore from the provided value. @@ -5450,7 +5450,7 @@ PAL_API PalResult PAL_CALL palWaitSemaphore( PAL_API PalResult PAL_CALL palSignalSemaphore( PalSemaphore* semaphore, PalQueue* queue, - Uint64 value); + uint64_t value); /** * @brief Get the value of a semaphore. @@ -5461,7 +5461,7 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] semaphore Semaphore to get its value. - * @param[out] outValue Pointer to a Uint64 to receive the semaphore value. + * @param[out] outValue Pointer to a uint64_t to receive the semaphore value. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5475,7 +5475,7 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( */ PAL_API PalResult PAL_CALL palGetSemaphoreValue( PalSemaphore* semaphore, - Uint64* outValue); + uint64_t* outValue); /** * @brief Create a command pool from a device. @@ -5729,9 +5729,9 @@ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); /** * @brief Dispatch mesh shader workgroups using parameters from a buffer. @@ -5762,7 +5762,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 drawCount); + uint32_t drawCount); /** * @brief Dispatch mesh shader workgroups using parameters from buffers. @@ -5776,7 +5776,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. * Can be a single struct. - * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. + * @param[in] countBuffer Buffer containing a single `uint32_t` specifying the number of draws. * @param[in] maxDrawCount Maximum Number of draws to perform. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -5795,7 +5795,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount); + uint32_t maxDrawCount); /** * @brief Build or update an acceleration structure. @@ -6003,7 +6003,7 @@ PAL_API PalResult PAL_CALL palCmdBindPipeline( */ PAL_API PalResult PAL_CALL palCmdSetViewport( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalViewport* viewports); /** @@ -6026,7 +6026,7 @@ PAL_API PalResult PAL_CALL palCmdSetViewport( */ PAL_API PalResult PAL_CALL palCmdSetScissors( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalRect2D* scissors); /** @@ -6053,10 +6053,10 @@ PAL_API PalResult PAL_CALL palCmdSetScissors( */ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, - Uint32 firstSlot, - Uint32 count, + uint32_t firstSlot, + uint32_t count, PalBuffer** buffers, - Uint64* offsets); + uint64_t* offsets); /** * @brief Bind index buffer used in draw commands. @@ -6081,7 +6081,7 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, + uint64_t offset, PalIndexType type); /** @@ -6108,10 +6108,10 @@ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( */ PAL_API PalResult PAL_CALL palCmdDraw( PalCommandBuffer* cmdBuffer, - Uint32 vertexCount, - Uint32 instanceCount, - Uint32 firstVertex, - Uint32 firstInstance); + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); /** * @brief Issue a non-indexed draw command using buffers. @@ -6141,7 +6141,7 @@ PAL_API PalResult PAL_CALL palCmdDraw( PAL_API PalResult PAL_CALL palCmdDrawIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count); + uint32_t count); /** * @brief Issue a non-indexed draw command using buffers. @@ -6154,7 +6154,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirect( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. * Can be a single struct. - * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. + * @param[in] countBuffer Buffer containing a single `uint32_t` specifying the number of draws. * @param[in] maxDrawCount Maximum Number of draws to perform. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6173,7 +6173,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount); + uint32_t maxDrawCount); /** * @brief Issue an indexed draw command. @@ -6200,11 +6200,11 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( */ PAL_API PalResult PAL_CALL palCmdDrawIndexed( PalCommandBuffer* cmdBuffer, - Uint32 indexCount, - Uint32 instanceCount, - Uint32 firstIndex, - Int32 vertexOffset, - Uint32 firstInstance); + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); /** * @brief Issue an indexed draw command using buffers. @@ -6234,7 +6234,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexed( PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count); + uint32_t count); /** * @brief Issue an indexed draw command using buffers. @@ -6247,7 +6247,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. * Can be a single struct. - * @param[in] countBuffer Buffer containing a single `Uint32` specifying the number of draws. + * @param[in] countBuffer Buffer containing a single `uint32_t` specifying the number of draws. * @param[in] maxDrawCount Maximum Number of draws to perform. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6266,7 +6266,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount); + uint32_t maxDrawCount); /** * @brief Transition an acceleration structure from one usage state to another. @@ -6430,9 +6430,9 @@ PAL_API PalResult PAL_CALL palCmdBufferBarrier( */ PAL_API PalResult PAL_CALL palCmdDispatch( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); /** * @brief Dispatch compute shader workgroups with base offset. @@ -6463,12 +6463,12 @@ PAL_API PalResult PAL_CALL palCmdDispatch( */ PAL_API PalResult PAL_CALL palCmdDispatchBase( PalCommandBuffer* cmdBuffer, - Uint32 baseGroupX, - Uint32 baseGroupY, - Uint32 baseGroupZ, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); /** * @brief Dispatch compute shader workgroups using parameters from a buffer. @@ -6525,10 +6525,10 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( PAL_API PalResult PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, - Uint32 raygenIndex, - Uint32 width, - Uint32 height, - Uint32 depth); + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth); /** * @brief Dispatch rays using parameters from a buffer. @@ -6559,7 +6559,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( */ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, - Uint32 raygenIndex, + uint32_t raygenIndex, PalShaderBindingTable* sbt, PalBuffer* buffer); @@ -6584,7 +6584,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( */ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, - Uint32 setIndex, + uint32_t setIndex, PalDescriptorSet* set); /** @@ -6611,10 +6611,10 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( */ PAL_API PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, - Uint32 shaderStageCount, + uint32_t shaderStageCount, PalShaderStage* shaderStages, - Uint32 offset, - Uint32 size, + uint32_t offset, + uint32_t size, const void* value); /** @@ -6925,7 +6925,7 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( * * @param[in] device Device to compute instance buffer requirements with. * @param[in] instanceCount Number of instances the instance buffer will hold. - * @param[out] outSize Pointer to a Uint64 to recieve the required size. + * @param[out] outSize Pointer to a uint64_t to recieve the required size. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6937,8 +6937,8 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( */ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( PalDevice* device, - Uint32 instanceCount, - Uint64* outSize); + uint32_t instanceCount, + uint64_t* outSize); /** * @brief Compute size and alignment requirements for an image copy staging buffer. @@ -6959,9 +6959,9 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * @param[in] imageFormat Destination image format. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * Must not be nullptr. - * @param[out] outBufferRowLength Pointer to a Uint32 to recieve the required buffer row length. - * @param[out] outBufferImageHeight Pointer to a Uint32 to recieve the required buffer imag height. - * @param[out] outSize Pointer to a Uint64 to recieve the required size. + * @param[out] outBufferRowLength Pointer to a uint32_t to recieve the required buffer row length. + * @param[out] outBufferImageHeight Pointer to a uint32_t to recieve the required buffer imag height. + * @param[out] outSize Pointer to a uint64_t to recieve the required size. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6975,9 +6975,9 @@ PAL_API PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, - Uint32* outBufferRowLength, - Uint32* outBufferImageHeight, - Uint64* outSize); + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize); /** * @brief Update or write data to an instance buffer. @@ -7002,7 +7002,7 @@ PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, - Uint32 instanceCount); + uint32_t instanceCount); /** * @brief Update or write data to an image copy staging buffer. @@ -7054,7 +7054,7 @@ PAL_API PalResult PAL_CALL palWriteToImageCopyStagingBuffer( PAL_API PalResult PAL_CALL palBindBufferMemory( PalBuffer* buffer, PalMemory* memory, - Uint64 offset); + uint64_t offset); /** * @brief Maps buffer to CPU visible address space. @@ -7085,8 +7085,8 @@ PAL_API PalResult PAL_CALL palBindBufferMemory( */ PAL_API PalResult PAL_CALL palMapBufferMemory( PalBuffer* buffer, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr); /** @@ -7297,7 +7297,7 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( */ PAL_API PalResult PAL_CALL palUpdateDescriptorSet( PalDevice* device, - Uint32 count, + uint32_t count, PalDescriptorSetWriteInfo* infos); /** @@ -7516,7 +7516,7 @@ PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); */ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( PalShaderBindingTable* sbt, - Uint32 count, + uint32_t count, PalShaderBindingTableRecordInfo* infos); /** @@ -7552,7 +7552,7 @@ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( */ PAL_API bool PAL_CALL palBuildWorkGroupInfo( const PalWorkGroupBuildData* data, - Int32* count, + int32_t* count, PalWorkGroupInfo* info); /** @} */ // end of pal_graphics group diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 14f22c20..0421874b 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -60,16 +60,16 @@ typedef struct PalGLContext PalGLContext; * @ingroup pal_opengl */ typedef enum { - PAL_GL_EXTENSION_CREATE_CONTEXT = PAL_BIT(0), /**< Modern context.*/ - PAL_GL_EXTENSION_CONTEXT_PROFILE = PAL_BIT(1), - PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2 = PAL_BIT(2), - PAL_GL_EXTENSION_ROBUSTNESS = PAL_BIT(3), /**< Reset behaviour.*/ - PAL_GL_EXTENSION_NO_ERROR = PAL_BIT(4), /**< No errors*/ - PAL_GL_EXTENSION_PIXEL_FORMAT = PAL_BIT(5), /**< Modern PalGLFBConfig.*/ - PAL_GL_EXTENSION_MULTISAMPLE = PAL_BIT(6), /**< Multisample FBConfigs.*/ - PAL_GL_EXTENSION_SWAP_CONTROL = PAL_BIT(7), /**< Vsync.*/ - PAL_GL_EXTENSION_FLUSH_CONTROL = PAL_BIT(8), /**< Release behavior.*/ - PAL_GL_EXTENSION_COLORSPACE_SRGB = PAL_BIT(9) /**< Standard RGB.*/ + PAL_GL_EXTENSION_CREATE_CONTEXT = (1ULL << 0), /**< Modern context.*/ + PAL_GL_EXTENSION_CONTEXT_PROFILE = (1ULL << 1), + PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2 = (1ULL << 2), + PAL_GL_EXTENSION_ROBUSTNESS = (1ULL << 3), /**< Reset behaviour.*/ + PAL_GL_EXTENSION_NO_ERROR = (1ULL << 4), /**< No errors*/ + PAL_GL_EXTENSION_PIXEL_FORMAT = (1ULL << 5), /**< Modern PalGLFBConfig.*/ + PAL_GL_EXTENSION_MULTISAMPLE = (1ULL << 6), /**< Multisample FBConfigs.*/ + PAL_GL_EXTENSION_SWAP_CONTROL = (1ULL << 7), /**< Vsync.*/ + PAL_GL_EXTENSION_FLUSH_CONTROL = (1ULL << 8), /**< Release behavior.*/ + PAL_GL_EXTENSION_COLORSPACE_SRGB = (1ULL << 9) /**< Standard RGB.*/ } PalGLExtensions; /** @@ -129,8 +129,8 @@ typedef enum { */ typedef struct { PalGLExtensions extensions; - Uint32 major; /**< Version major.*/ - Uint32 minor; /**< Version minor.*/ + uint32_t major; /**< Version major.*/ + uint32_t minor; /**< Version minor.*/ char vendor[32]; /**< Graphics card vendor name (eg. Intel).*/ char graphicsCard[64]; /**< Graphics card name.*/ char version[64]; /**< Version string (major, minor, build).*/ @@ -147,14 +147,14 @@ typedef struct { bool doubleBuffer; bool stereo; bool sRGB; - Uint16 index; /**< Driver index. Must not be changed.*/ - Uint16 redBits; - Uint16 greenBits; - Uint16 blueBits; - Uint16 alphaBits; - Uint16 depthBits; - Uint16 stencilBits; - Uint16 samples; /**< PAL_GL_EXTENSION_MULTISAMPLE or 1.*/ + uint16_t index; /**< Driver index. Must not be changed.*/ + uint16_t redBits; + uint16_t greenBits; + uint16_t blueBits; + uint16_t alphaBits; + uint16_t depthBits; + uint16_t stencilBits; + uint16_t samples; /**< PAL_GL_EXTENSION_MULTISAMPLE or 1.*/ } PalGLFBConfig; /** @@ -185,8 +185,8 @@ typedef struct { bool forward; /**< Forward compatible context.*/ bool noError; /**< No error context.*/ bool debug; /**< Debug context. */ - Uint16 major; /** major version.*/ - Uint16 minor; /** minor version.*/ + uint16_t major; /** major version.*/ + uint16_t minor; /** minor version.*/ PalGLProfile profile; /**< see PalGLProfile.*/ PalGLContextReset reset; /**< see PalGLContextReset.*/ PalGLRelease release; /**< see PalGLRelease.*/ @@ -277,7 +277,7 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); */ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( PalGLWindow* glWindow, - Int32* count, + int32_t* count, PalGLFBConfig* configs); /** @@ -305,7 +305,7 @@ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( */ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( PalGLFBConfig* configs, - Int32 count, + int32_t count, const PalGLFBConfig* desired); /** @@ -447,7 +447,7 @@ PAL_API PalResult PAL_CALL palSwapBuffers( * @ingroup pal_opengl * @sa palMakeContextCurrent */ -PAL_API PalResult PAL_CALL palSetSwapInterval(Int32 interval); +PAL_API PalResult PAL_CALL palSetSwapInterval(int32_t interval); /** * @brief Set the native application instance or display for the opengl system. diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index 2e6a1041..b9ac664c 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -52,18 +52,18 @@ typedef enum { * @since 1.0 */ typedef enum { - PAL_CPU_FEATURE_SSE = PAL_BIT(0), - PAL_CPU_FEATURE_SSE2 = PAL_BIT(1), - PAL_CPU_FEATURE_SSE3 = PAL_BIT(2), - PAL_CPU_FEATURE_SSSE3 = PAL_BIT(3), - PAL_CPU_FEATURE_SSE41 = PAL_BIT(4), /**< SSE4.1.*/ - PAL_CPU_FEATURE_SSE42 = PAL_BIT(5), /**< SSE4.1.*/ - PAL_CPU_FEATURE_AVX = PAL_BIT(6), - PAL_CPU_FEATURE_AVX2 = PAL_BIT(7), - PAL_CPU_FEATURE_AVX512F = PAL_BIT(8), - PAL_CPU_FEATURE_FMA3 = PAL_BIT(9), - PAL_CPU_FEATURE_BMI1 = PAL_BIT(10), - PAL_CPU_FEATURE_BMI2 = PAL_BIT(11) + PAL_CPU_FEATURE_SSE = (1ULL << 0), + PAL_CPU_FEATURE_SSE2 = (1ULL << 1), + PAL_CPU_FEATURE_SSE3 = (1ULL << 2), + PAL_CPU_FEATURE_SSSE3 = (1ULL << 3), + PAL_CPU_FEATURE_SSE41 = (1ULL << 4), /**< SSE4.1.*/ + PAL_CPU_FEATURE_SSE42 = (1ULL << 5), /**< SSE4.1.*/ + PAL_CPU_FEATURE_AVX = (1ULL << 6), + PAL_CPU_FEATURE_AVX2 = (1ULL << 7), + PAL_CPU_FEATURE_AVX512F = (1ULL << 8), + PAL_CPU_FEATURE_FMA3 = (1ULL << 9), + PAL_CPU_FEATURE_BMI1 = (1ULL << 10), + PAL_CPU_FEATURE_BMI2 = (1ULL << 11) } PalCpuFeatures; /** @@ -117,8 +117,8 @@ typedef enum { typedef struct { PalPlatformType type; PalPlatformApiType apiType; - Uint32 totalMemory; /**< Total Disk space (memory) in GB.*/ - Uint32 totalRAM; /**< Total CPU RAM (memory) in MB.*/ + uint32_t totalMemory; /**< Total Disk space (memory) in GB.*/ + uint32_t totalRAM; /**< Total CPU RAM (memory) in MB.*/ PalVersion version; char name[PAL_PLATFORM_NAME_SIZE]; /**< (eg. Windows 11.22000).*/ } PalPlatformInfo; @@ -130,11 +130,11 @@ typedef struct { * @since 1.0 */ typedef struct { - Uint32 numCores; - Uint32 cacheL1; /**< L1 cache in KB.*/ - Uint32 cacheL2; /**< L2 cache in KB.*/ - Uint32 cacheL3; /**< L3 cache in KB.*/ - Uint32 numLogicalProcessors; /**< Number of CPUs.*/ + uint32_t numCores; + uint32_t cacheL1; /**< L1 cache in KB.*/ + uint32_t cacheL2; /**< L2 cache in KB.*/ + uint32_t cacheL3; /**< L3 cache in KB.*/ + uint32_t numLogicalProcessors; /**< Number of CPUs.*/ PalCpuArch architecture; PalCpuFeatures features; char vendor[PAL_CPU_VENDOR_NAME_SIZE]; /**< CPU vendor name.*/ diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 48c5ab77..718e797b 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -43,48 +43,48 @@ freely, subject to the following restrictions: * @since 1.3 * @ingroup pal_video */ -typedef Uint64 PalVideoFeatures64; - -#define PAL_VIDEO_FEATURE64_HIGH_DPI PAL_BIT64(0) -#define PAL_VIDEO_FEATURE64_MONITOR_SET_ORIENTATION PAL_BIT64(1) -#define PAL_VIDEO_FEATURE64_MONITOR_GET_ORIENTATION PAL_BIT64(2) -#define PAL_VIDEO_FEATURE64_BORDERLESS_WINDOW PAL_BIT64(3) -#define PAL_VIDEO_FEATURE64_TRANSPARENT_WINDOW PAL_BIT64(4) -#define PAL_VIDEO_FEATURE64_TOOL_WINDOW PAL_BIT64(5) -#define PAL_VIDEO_FEATURE64_MONITOR_SET_MODE PAL_BIT64(6) -#define PAL_VIDEO_FEATURE64_MONITOR_GET_MODE PAL_BIT64(7) -#define PAL_VIDEO_FEATURE64_MULTI_MONITORS PAL_BIT64(8) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_SIZE PAL_BIT64(9) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_SIZE PAL_BIT64(10) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_POS PAL_BIT64(11) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_POS PAL_BIT64(12) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_STATE PAL_BIT64(13) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_STATE PAL_BIT64(14) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_VISIBILITY PAL_BIT64(15) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_VISIBILITY PAL_BIT64(16) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_TITLE PAL_BIT64(17) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_TITLE PAL_BIT64(18) -#define PAL_VIDEO_FEATURE64_NO_MAXIMIZEBOX PAL_BIT64(19) -#define PAL_VIDEO_FEATURE64_NO_MINIMIZEBOX PAL_BIT64(20) -#define PAL_VIDEO_FEATURE64_CLIP_CURSOR PAL_BIT64(21) -#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_CAPTION PAL_BIT64(22) -#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_TRAY PAL_BIT64(23) -#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_INTERVAL PAL_BIT64(24) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_INPUT_FOCUS PAL_BIT64(25) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_INPUT_FOCUS PAL_BIT64(26) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_STYLE PAL_BIT64(27) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_STYLE PAL_BIT64(28) -#define PAL_VIDEO_FEATURE64_CURSOR_SET_POS PAL_BIT64(29) -#define PAL_VIDEO_FEATURE64_CURSOR_GET_POS PAL_BIT64(30) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_ICON PAL_BIT64(31) -#define PAL_VIDEO_FEATURE64_TOPMOST_WINDOW PAL_BIT64(32) -#define PAL_VIDEO_FEATURE64_DECORATED_WINDOW PAL_BIT64(33) -#define PAL_VIDEO_FEATURE64_CURSOR_SET_VISIBILITY PAL_BIT64(34) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_MONITOR PAL_BIT64(35) -#define PAL_VIDEO_FEATURE64_MONITOR_GET_PRIMARY PAL_BIT64(36) -#define PAL_VIDEO_FEATURE64_FOREIGN_WINDOWS PAL_BIT64(37) -#define PAL_VIDEO_FEATURE64_MONITOR_VALIDATE_MODE PAL_BIT64(38) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR PAL_BIT64(39) +typedef uint64_t PalVideoFeatures64; + +#define PAL_VIDEO_FEATURE64_HIGH_DPI (1ULL << 0) +#define PAL_VIDEO_FEATURE64_MONITOR_SET_ORIENTATION (1ULL << 1) +#define PAL_VIDEO_FEATURE64_MONITOR_GET_ORIENTATION (1ULL << 2) +#define PAL_VIDEO_FEATURE64_BORDERLESS_WINDOW (1ULL << 3) +#define PAL_VIDEO_FEATURE64_TRANSPARENT_WINDOW (1ULL << 4) +#define PAL_VIDEO_FEATURE64_TOOL_WINDOW (1ULL << 5) +#define PAL_VIDEO_FEATURE64_MONITOR_SET_MODE (1ULL << 6) +#define PAL_VIDEO_FEATURE64_MONITOR_GET_MODE (1ULL << 7) +#define PAL_VIDEO_FEATURE64_MULTI_MONITORS (1ULL << 8) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_SIZE (1ULL << 9) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_SIZE (1ULL << 10) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_POS (1ULL << 11) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_POS (1ULL << 12) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_STATE (1ULL << 13) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_STATE (1ULL << 14) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_VISIBILITY (1ULL << 15) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_VISIBILITY (1ULL << 16) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_TITLE (1ULL << 17) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_TITLE (1ULL << 18) +#define PAL_VIDEO_FEATURE64_NO_MAXIMIZEBOX (1ULL << 19) +#define PAL_VIDEO_FEATURE64_NO_MINIMIZEBOX (1ULL << 20) +#define PAL_VIDEO_FEATURE64_CLIP_CURSOR (1ULL << 21) +#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_CAPTION (1ULL << 22) +#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_TRAY (1ULL << 23) +#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_INTERVAL (1ULL << 24) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_INPUT_FOCUS (1ULL << 25) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_INPUT_FOCUS (1ULL << 26) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_STYLE (1ULL << 27) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_STYLE (1ULL << 28) +#define PAL_VIDEO_FEATURE64_CURSOR_SET_POS (1ULL << 29) +#define PAL_VIDEO_FEATURE64_CURSOR_GET_POS (1ULL << 30) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_ICON (1ULL << 31) +#define PAL_VIDEO_FEATURE64_TOPMOST_WINDOW (1ULL << 32) +#define PAL_VIDEO_FEATURE64_DECORATED_WINDOW (1ULL << 33) +#define PAL_VIDEO_FEATURE64_CURSOR_SET_VISIBILITY (1ULL << 34) +#define PAL_VIDEO_FEATURE64_WINDOW_GET_MONITOR (1ULL << 35) +#define PAL_VIDEO_FEATURE64_MONITOR_GET_PRIMARY (1ULL << 36) +#define PAL_VIDEO_FEATURE64_FOREIGN_WINDOWS (1ULL << 37) +#define PAL_VIDEO_FEATURE64_MONITOR_VALIDATE_MODE (1ULL << 38) +#define PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR (1ULL << 39) /** * @struct PalMonitor @@ -133,38 +133,38 @@ typedef struct PalCursor PalCursor; * @ingroup pal_video */ typedef enum { - PAL_VIDEO_FEATURE_HIGH_DPI = PAL_BIT(0), - PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION = PAL_BIT(1), - PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION = PAL_BIT(2), - PAL_VIDEO_FEATURE_BORDERLESS_WINDOW = PAL_BIT(3), - PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW = PAL_BIT(4), - PAL_VIDEO_FEATURE_TOOL_WINDOW = PAL_BIT(5), - PAL_VIDEO_FEATURE_MONITOR_SET_MODE = PAL_BIT(6), - PAL_VIDEO_FEATURE_MONITOR_GET_MODE = PAL_BIT(7), - PAL_VIDEO_FEATURE_MULTI_MONITORS = PAL_BIT(8), - PAL_VIDEO_FEATURE_WINDOW_SET_SIZE = PAL_BIT(9), - PAL_VIDEO_FEATURE_WINDOW_GET_SIZE = PAL_BIT(10), - PAL_VIDEO_FEATURE_WINDOW_SET_POS = PAL_BIT(11), - PAL_VIDEO_FEATURE_WINDOW_GET_POS = PAL_BIT(12), - PAL_VIDEO_FEATURE_WINDOW_SET_STATE = PAL_BIT(13), - PAL_VIDEO_FEATURE_WINDOW_GET_STATE = PAL_BIT(14), - PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY = PAL_BIT(15), - PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY = PAL_BIT(16), - PAL_VIDEO_FEATURE_WINDOW_SET_TITLE = PAL_BIT(17), - PAL_VIDEO_FEATURE_WINDOW_GET_TITLE = PAL_BIT(18), - PAL_VIDEO_FEATURE_NO_MAXIMIZEBOX = PAL_BIT(19), - PAL_VIDEO_FEATURE_NO_MINIMIZEBOX = PAL_BIT(20), - PAL_VIDEO_FEATURE_CLIP_CURSOR = PAL_BIT(21), - PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION = PAL_BIT(22), - PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY = PAL_BIT(23), - PAL_VIDEO_FEATURE_WINDOW_FLASH_INTERVAL = PAL_BIT(24), - PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS = PAL_BIT(25), - PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS = PAL_BIT(26), - PAL_VIDEO_FEATURE_WINDOW_SET_STYLE = PAL_BIT(27), - PAL_VIDEO_FEATURE_WINDOW_GET_STYLE = PAL_BIT(28), - PAL_VIDEO_FEATURE_CURSOR_SET_POS = PAL_BIT(29), - PAL_VIDEO_FEATURE_CURSOR_GET_POS = PAL_BIT(30), - PAL_VIDEO_FEATURE_WINDOW_SET_ICON = PAL_BIT(31) + PAL_VIDEO_FEATURE_HIGH_DPI = (1ULL << 0), + PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION = (1ULL << 1), + PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION = (1ULL << 2), + PAL_VIDEO_FEATURE_BORDERLESS_WINDOW = (1ULL << 3), + PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW = (1ULL << 4), + PAL_VIDEO_FEATURE_TOOL_WINDOW = (1ULL << 5), + PAL_VIDEO_FEATURE_MONITOR_SET_MODE = (1ULL << 6), + PAL_VIDEO_FEATURE_MONITOR_GET_MODE = (1ULL << 7), + PAL_VIDEO_FEATURE_MULTI_MONITORS = (1ULL << 8), + PAL_VIDEO_FEATURE_WINDOW_SET_SIZE = (1ULL << 9), + PAL_VIDEO_FEATURE_WINDOW_GET_SIZE = (1ULL << 10), + PAL_VIDEO_FEATURE_WINDOW_SET_POS = (1ULL << 11), + PAL_VIDEO_FEATURE_WINDOW_GET_POS = (1ULL << 12), + PAL_VIDEO_FEATURE_WINDOW_SET_STATE = (1ULL << 13), + PAL_VIDEO_FEATURE_WINDOW_GET_STATE = (1ULL << 14), + PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY = (1ULL << 15), + PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY = (1ULL << 16), + PAL_VIDEO_FEATURE_WINDOW_SET_TITLE = (1ULL << 17), + PAL_VIDEO_FEATURE_WINDOW_GET_TITLE = (1ULL << 18), + PAL_VIDEO_FEATURE_NO_MAXIMIZEBOX = (1ULL << 19), + PAL_VIDEO_FEATURE_NO_MINIMIZEBOX = (1ULL << 20), + PAL_VIDEO_FEATURE_CLIP_CURSOR = (1ULL << 21), + PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION = (1ULL << 22), + PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY = (1ULL << 23), + PAL_VIDEO_FEATURE_WINDOW_FLASH_INTERVAL = (1ULL << 24), + PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS = (1ULL << 25), + PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS = (1ULL << 26), + PAL_VIDEO_FEATURE_WINDOW_SET_STYLE = (1ULL << 27), + PAL_VIDEO_FEATURE_WINDOW_GET_STYLE = (1ULL << 28), + PAL_VIDEO_FEATURE_CURSOR_SET_POS = (1ULL << 29), + PAL_VIDEO_FEATURE_CURSOR_GET_POS = (1ULL << 30), + PAL_VIDEO_FEATURE_WINDOW_SET_ICON = (1ULL << 31) } PalVideoFeatures; /** @@ -196,13 +196,13 @@ typedef enum { * @ingroup pal_video */ typedef enum { - PAL_WINDOW_STYLE_RESIZABLE = PAL_BIT(0), - PAL_WINDOW_STYLE_TRANSPARENT = PAL_BIT(1), - PAL_WINDOW_STYLE_TOPMOST = PAL_BIT(2), - PAL_WINDOW_STYLE_NO_MINIMIZEBOX = PAL_BIT(3), - PAL_WINDOW_STYLE_NO_MAXIMIZEBOX = PAL_BIT(4), - PAL_WINDOW_STYLE_TOOL = PAL_BIT(5), - PAL_WINDOW_STYLE_BORDERLESS = PAL_BIT(6) + PAL_WINDOW_STYLE_RESIZABLE = (1ULL << 0), + PAL_WINDOW_STYLE_TRANSPARENT = (1ULL << 1), + PAL_WINDOW_STYLE_TOPMOST = (1ULL << 2), + PAL_WINDOW_STYLE_NO_MINIMIZEBOX = (1ULL << 3), + PAL_WINDOW_STYLE_NO_MAXIMIZEBOX = (1ULL << 4), + PAL_WINDOW_STYLE_TOOL = (1ULL << 5), + PAL_WINDOW_STYLE_BORDERLESS = (1ULL << 6) } PalWindowStyle; /** @@ -236,8 +236,8 @@ typedef enum { */ typedef enum { PAL_FLASH_STOP = 0, /**< Stop flashing.*/ - PAL_FLASH_CAPTION = PAL_BIT(0), /**< Flash the titlebar of the window.*/ - PAL_FLASH_TRAY = PAL_BIT(1) /**< Flash the icon of the window.*/ + PAL_FLASH_CAPTION = (1ULL << 0), /**< Flash the titlebar of the window.*/ + PAL_FLASH_TRAY = (1ULL << 1) /**< Flash the icon of the window.*/ } PalFlashFlag; /** @@ -567,12 +567,12 @@ typedef enum { */ typedef struct { bool primary; /**< True if this is the primary monitor.*/ - Uint32 dpi; - Uint32 refreshRate; - Int32 x; /**< X position in pixels.*/ - Int32 y; /**< Y position in pixels.*/ - Uint32 width; /**< Width in pixels.*/ - Uint32 height; /**< Height in pixels.*/ + uint32_t dpi; + uint32_t refreshRate; + int32_t x; /**< X position in pixels.*/ + int32_t y; /**< Y position in pixels.*/ + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Height in pixels.*/ PalOrientation orientation; char name[32]; } PalMonitorInfo; @@ -585,10 +585,10 @@ typedef struct { * @ingroup pal_video */ typedef struct { - Uint32 bpp; /**< Bits per pixel.*/ - Uint32 refreshRate; - Uint32 width; /**< Width in pixels.*/ - Uint32 height; /**< Height in pixels.*/ + uint32_t bpp; /**< Bits per pixel.*/ + uint32_t refreshRate; + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Height in pixels.*/ } PalMonitorMode; /** @@ -601,9 +601,9 @@ typedef struct { * @ingroup pal_video */ typedef struct { - Uint32 interval; /**< In milliseconds. Set to 0 for default.*/ + uint32_t interval; /**< In milliseconds. Set to 0 for default.*/ PalFlashFlag flags; /**< See PalFlashFlag.*/ - Uint32 count; /**< Set to 0 to flash until focused or cancelled.*/ + uint32_t count; /**< Set to 0 to flash until focused or cancelled.*/ } PalFlashInfo; /** @@ -616,9 +616,9 @@ typedef struct { * @ingroup pal_video */ typedef struct { - Uint32 width; /**< Width in pixels.*/ - Uint32 height; /**< Height in pixels.*/ - const Uint8* pixels; /**< Pixels in `RGBA` format.*/ + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Height in pixels.*/ + const uint8_t* pixels; /**< Pixels in `RGBA` format.*/ } PalIconCreateInfo; /** @@ -631,11 +631,11 @@ typedef struct { * @ingroup pal_video */ typedef struct { - Uint32 width; /**< Width in pixels..*/ - Uint32 height; /**< Height in pixels.*/ - Int32 xHotspot; /**< X pixel for detecting clicks.*/ - Int32 yHotspot; /**< Y pixel for detecting clicks.*/ - const Uint8* pixels; /**< Pixels in `RGBA` format.*/ + uint32_t width; /**< Width in pixels..*/ + uint32_t height; /**< Height in pixels.*/ + int32_t xHotspot; /**< X pixel for detecting clicks.*/ + int32_t yHotspot; /**< Y pixel for detecting clicks.*/ + const uint8_t* pixels; /**< Pixels in `RGBA` format.*/ } PalCursorCreateInfo; /** @@ -679,8 +679,8 @@ typedef struct { bool maximized; /**< Maximize after creation.*/ bool minimized; /**< Minimze after creation.*/ bool center; /**< Center after creation.*/ - Uint32 width; /**< Width in pixels.*/ - Uint32 height; /**< Width in pixels.*/ + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Width in pixels.*/ PalWindowStyle style; /**< Window style.*/ const char* title; /**< Title in UTF-8 encoding.*/ PalMonitor* monitor; /**< Set to nullptr to use primary monitor.*/ @@ -842,7 +842,7 @@ PAL_API PalResult PAL_CALL palSetFBConfig( * @sa palGetPrimaryMonitor */ PAL_API PalResult PAL_CALL palEnumerateMonitors( - Int32* count, + int32_t* count, PalMonitor** outMonitors); /** @@ -921,7 +921,7 @@ PAL_API PalResult PAL_CALL palGetMonitorInfo( */ PAL_API PalResult PAL_CALL palEnumerateMonitorModes( PalMonitor* monitor, - Int32* count, + int32_t* count, PalMonitorMode* modes); /** @@ -1268,8 +1268,8 @@ PAL_API PalResult PAL_CALL palGetWindowMonitor( */ PAL_API PalResult PAL_CALL palGetWindowTitle( PalWindow* window, - Uint64 bufferSize, - Uint64* outSize, + uint64_t bufferSize, + uint64_t* outSize, char* outBuffer); /** @@ -1293,8 +1293,8 @@ PAL_API PalResult PAL_CALL palGetWindowTitle( */ PAL_API PalResult PAL_CALL palGetWindowPos( PalWindow* window, - Int32* x, - Int32* y); + int32_t* x, + int32_t* y); /** * @brief Get the size of the provided window in pixels. @@ -1317,8 +1317,8 @@ PAL_API PalResult PAL_CALL palGetWindowPos( */ PAL_API PalResult PAL_CALL palGetWindowSize( PalWindow* window, - Uint32* width, - Uint32* height); + uint32_t* width, + uint32_t* height); /** * @brief Get the state of the provided window. @@ -1415,8 +1415,8 @@ PAL_API const bool* PAL_CALL palGetMouseState(); * @ingroup pal_video */ PAL_API void PAL_CALL palGetMouseDelta( - Int32* dx, - Int32* dy); + int32_t* dx, + int32_t* dy); /** * @brief Get the wheel delta of the mouse. @@ -1434,8 +1434,8 @@ PAL_API void PAL_CALL palGetMouseDelta( * @ingroup pal_video */ PAL_API void PAL_CALL palGetMouseWheelDelta( - Int32* dx, - Int32* dy); + int32_t* dx, + int32_t* dy); /** * @brief Get the raw wheel delta of the mouse in floats. @@ -1616,8 +1616,8 @@ PAL_API PalResult PAL_CALL palSetWindowTitle( */ PAL_API PalResult PAL_CALL palSetWindowPos( PalWindow* window, - Int32 x, - Int32 y); + int32_t x, + int32_t y); /** * @brief Set the size of the provided window in pixels. @@ -1642,8 +1642,8 @@ PAL_API PalResult PAL_CALL palSetWindowPos( */ PAL_API PalResult PAL_CALL palSetWindowSize( PalWindow* window, - Uint32 width, - Uint32 height); + uint32_t width, + uint32_t height); /** * @brief Request input focus for the provided window. @@ -1856,8 +1856,8 @@ PAL_API PalResult PAL_CALL palClipCursor( */ PAL_API PalResult PAL_CALL palGetCursorPos( PalWindow* window, - Int32* x, - Int32* y); + int32_t* x, + int32_t* y); /** * @brief Set the position of the cursor relative to the provided window in @@ -1880,8 +1880,8 @@ PAL_API PalResult PAL_CALL palGetCursorPos( */ PAL_API PalResult PAL_CALL palSetCursorPos( PalWindow* window, - Int32 x, - Int32 y); + int32_t x, + int32_t y); /** * @brief Set the cursor for the provided window. diff --git a/include/pal/thread/condvar.h b/include/pal/thread/condvar.h index 1a15a57a..34ccef12 100644 --- a/include/pal/thread/condvar.h +++ b/include/pal/thread/condvar.h @@ -105,7 +105,7 @@ PAL_API PalResult PAL_CALL palWaitCondVar( PAL_API PalResult PAL_CALL palWaitCondVarTimeout( PalCondVar* condVar, PalMutex* mutex, - Uint64 milliseconds); + uint64_t milliseconds); /** * @brief Wake a single thread waiting on the condition variable. diff --git a/include/pal/thread/thread.h b/include/pal/thread/thread.h index 881e5dd5..575896c2 100644 --- a/include/pal/thread/thread.h +++ b/include/pal/thread/thread.h @@ -48,10 +48,10 @@ typedef void* (*PalThreadFn)(void* arg); * @since 1.0 */ typedef enum { - PAL_THREAD_FEATURE_STACK_SIZE = PAL_BIT(0), - PAL_THREAD_FEATURE_PRIORITY = PAL_BIT(1), - PAL_THREAD_FEATURE_AFFINITY = PAL_BIT(2), - PAL_THREAD_FEATURE_NAME = PAL_BIT(3) + PAL_THREAD_FEATURE_STACK_SIZE = (1ULL << 0), + PAL_THREAD_FEATURE_PRIORITY = (1ULL << 1), + PAL_THREAD_FEATURE_AFFINITY = (1ULL << 2), + PAL_THREAD_FEATURE_NAME = (1ULL << 3) } PalThreadFeatures; /** @@ -78,7 +78,7 @@ typedef enum { * @since 1.0 */ typedef struct { - Uint64 stackSize; /**< Set to 0 to use default*/ + uint64_t stackSize; /**< Set to 0 to use default*/ const PalAllocator* allocator; /**< Set to nullptr to use default.*/ PalThreadFn entry; /**< Thread entry function*/ void* arg; /**< Optional user-provided data. Can be nullptr.*/ @@ -162,7 +162,7 @@ PAL_API void PAL_CALL palDetachThread(PalThread* thread); * * @since 1.0 */ -PAL_API void PAL_CALL palSleep(Uint64 milliseconds); +PAL_API void PAL_CALL palSleep(uint64_t milliseconds); /** * @brief Yield the remainder of the calling threads time sliced, @@ -227,7 +227,7 @@ PAL_API PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread); * * @since 1.0 */ -PAL_API Uint64 PAL_CALL palGetThreadAffinity(PalThread* thread); +PAL_API uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread); /** * @brief Get the name of the provided thread. @@ -258,8 +258,8 @@ PAL_API Uint64 PAL_CALL palGetThreadAffinity(PalThread* thread); */ PAL_API PalResult PAL_CALL palGetThreadName( PalThread* thread, - Uint64 bufferSize, - Uint64* outSize, + uint64_t bufferSize, + uint64_t* outSize, char* outBuffer); /** @@ -294,7 +294,7 @@ PAL_API PalResult PAL_CALL palSetThreadPriority( * Example: we set a thread to the first and second CPU core. * * @code - * Uint64 cpuMask = PAL_BIT(0) | PAL_BIT(1). + * uint64_t cpuMask = (1ULL << 0) | (1ULL << 1). * @endcode * * @param[in] thread The thread to set affinity for. @@ -309,7 +309,7 @@ PAL_API PalResult PAL_CALL palSetThreadPriority( */ PAL_API PalResult PAL_CALL palSetThreadAffinity( PalThread* thread, - Uint64 mask); + uint64_t mask); /** * @brief Set the name of the provided thread. diff --git a/include/pal/thread/tls.h b/include/pal/thread/tls.h index 3cb43f6a..9627a1ed 100644 --- a/include/pal/thread/tls.h +++ b/include/pal/thread/tls.h @@ -22,7 +22,7 @@ * * @since 1.0 */ -typedef Uint32 PalTLSId; +typedef uint32_t PalTLSId; /** * @typedef PaTlsDestructorFn diff --git a/pal_config.lua b/pal_config.lua index cb56b04d..a68efa61 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -3,13 +3,13 @@ PAL_BUILD_STATIC_LIBRARY = false -- build PAL tests as a single application -PAL_BUILD_TEST_APPLICATION = true +PAL_BUILD_TEST_APPLICATION = false -- build system module PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD_MODULE = true +PAL_BUILD_THREAD_MODULE = false -- build video module PAL_BUILD_VIDEO_MODULE = false diff --git a/src/core/pal_memory.c b/src/core/pal_memory.c index e8609225..f50145e9 100644 --- a/src/core/pal_memory.c +++ b/src/core/pal_memory.c @@ -17,8 +17,8 @@ #define PAL_DEFAULT_ALIGNMENT 16 static inline void* alignedAlloc( - Uint64 size, - Uint64 alignment) + uint64_t size, + uint64_t alignment) { #if defined(_MSC_VER) || defined(__MINGW32__) return _aligned_malloc(size, alignment); @@ -42,10 +42,10 @@ static inline void alignedFree(void* ptr) void* PAL_CALL palAllocate( const PalAllocator* allocator, - Uint64 size, - Uint64 alignment) + uint64_t size, + uint64_t alignment) { - Uint64 align = alignment; + uint64_t align = alignment; if (align == 0) { align = PAL_DEFAULT_ALIGNMENT; } diff --git a/src/core/pal_time.c b/src/core/pal_time.c index 22e39288..3934d2c5 100644 --- a/src/core/pal_time.c +++ b/src/core/pal_time.c @@ -28,25 +28,25 @@ #include #endif // _WIN32 -Uint64 PAL_CALL palGetPerformanceCounter() +uint64_t PAL_CALL palGetPerformanceCounter() { #ifdef _WIN32 LARGE_INTEGER counter; QueryPerformanceCounter(&counter); - return (Uint64)counter.QuadPart; + return (uint64_t)counter.QuadPart; #else struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - return (Uint64)ts.tv_sec * 1000000000LL + (Uint64)ts.tv_nsec; + return (uint64_t)ts.tv_sec * 1000000000LL + (uint64_t)ts.tv_nsec; #endif // _WIN32 } -Uint64 PAL_CALL palGetPerformanceFrequency() +uint64_t PAL_CALL palGetPerformanceFrequency() { #ifdef _WIN32 LARGE_INTEGER frequency; QueryPerformanceFrequency(&frequency); - return (Uint64)frequency.QuadPart; + return (uint64_t)frequency.QuadPart; #else return 1000000000LL; #endif // _WIN32 diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index c7a5f593..4839a76b 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -126,9 +126,9 @@ typedef struct { typedef struct { bool debugLayer; - Uint32 adapterCount; - Uint32 severityCount; - Uint32 categoryCount; + uint32_t adapterCount; + uint32_t severityCount; + uint32_t categoryCount; HMODULE handle; HMODULE dxgi; Adapter* adapters; @@ -147,51 +147,51 @@ typedef struct { } D3D12; typedef struct { - Uint32 incrementSize; - Uint32 freeTop; - Uint64 baseOffset; + uint32_t incrementSize; + uint32_t freeTop; + uint64_t baseOffset; ID3D12DescriptorHeap* heap; - Uint32 freeList[MAX_RTV]; + uint32_t freeList[MAX_RTV]; } RTVHeapAllocator; typedef struct { - Uint32 incrementSize; - Uint32 freeTop; - Uint64 baseOffset; + uint32_t incrementSize; + uint32_t freeTop; + uint64_t baseOffset; ID3D12DescriptorHeap* heap; - Uint32 freeList[MAX_DSV]; + uint32_t freeList[MAX_DSV]; } DSVHeapAllocator; // Limits we must enforce ourselves typedef struct { - Uint32 freeComputeQueues; - Uint32 freeGraphicsQueues; - Uint32 freeCopyQueues; - Uint32 maxVertexLayouts; - Uint32 maxVertexAttributes; - - Uint32 maxAnisotropy; - Uint32 maxPushConstantSize; - Uint32 maxTessellationPatchPoint; - - Uint32 maxDescriptorSampledImages; - Uint32 maxDescriptorStorageImages; - Uint32 maxDescriptorSamplers; - Uint32 maxDescriptorStorageBuffers; - Uint32 maxDescriptorUniformBuffers; - Uint32 maxBoundDescriptorSets; - - Uint32 maxRecursionDepth; - Uint32 maxHitAttributeSize; - Uint32 maxPayloadSize; - Uint32 maxDispatchInvocations; - Uint32 maxDescriptorAccelerationStructures; + uint32_t freeComputeQueues; + uint32_t freeGraphicsQueues; + uint32_t freeCopyQueues; + uint32_t maxVertexLayouts; + uint32_t maxVertexAttributes; + + uint32_t maxAnisotropy; + uint32_t maxPushConstantSize; + uint32_t maxTessellationPatchPoint; + + uint32_t maxDescriptorSampledImages; + uint32_t maxDescriptorStorageImages; + uint32_t maxDescriptorSamplers; + uint32_t maxDescriptorStorageBuffers; + uint32_t maxDescriptorUniformBuffers; + uint32_t maxBoundDescriptorSets; + + uint32_t maxRecursionDepth; + uint32_t maxHitAttributeSize; + uint32_t maxPayloadSize; + uint32_t maxDispatchInvocations; + uint32_t maxDescriptorAccelerationStructures; } DeviceLimits; typedef struct { const PalGraphicsBackend* backend; - Uint32 shaderModel; + uint32_t shaderModel; PalAdapterFeatures features; IDXGIAdapter4* adapter; ID3D12CommandSignature* meshSignature; @@ -210,7 +210,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 fenceValue; + uint32_t fenceValue; PalQueueType type; ID3D12Fence* fence; ID3D12CommandQueue* handle; @@ -235,7 +235,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 heapIndex; + uint32_t heapIndex; PalImageViewType type; DXGI_FORMAT format; Image* image; @@ -252,11 +252,11 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 imageCount; - Uint32 syncInterval; - Uint32 windowWidth; - Uint32 windowHeight; - Uint32 flags; + uint32_t imageCount; + uint32_t syncInterval; + uint32_t windowWidth; + uint32_t windowHeight; + uint32_t flags; DXGI_FORMAT format; DXGI_FEATURE presentFlags; Surface* surface; @@ -276,7 +276,7 @@ typedef struct { } Fence, Semaphore; typedef struct { - Uint32 patchControlPoints; + uint32_t patchControlPoints; PalShaderStage stage; wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; } ShaderEntry; @@ -284,7 +284,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 entryCount; + uint32_t entryCount; D3D12_SHADER_BYTECODE byteCode; ShaderEntry* entries; } Shader; @@ -310,7 +310,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 size; + uint32_t size; D3D12_COMMAND_LIST_TYPE type; CommandBufferData* cmdBuffersData; } CommandPool; @@ -323,7 +323,7 @@ typedef struct { bool hasIndirect; bool isAccelerationStructure; bool isScratch; - Uint64 size; + uint64_t size; ID3D12Resource* handle; Device* device; D3D12_RESOURCE_DESC desc; @@ -340,7 +340,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 constantIndex; + uint32_t constantIndex; ID3D12RootSignature* handle; } PipelineLayout; @@ -356,25 +356,25 @@ typedef struct { } RayHitGroup; typedef struct { - Uint32 raygenCount; - Uint32 raygenDataSize; - Uint32 missCount; - Uint32 missDataSize; - Uint32 hitCount; - Uint32 hitDataSize; - Uint32 callableCount; - Uint32 callableDataSize; + uint32_t raygenCount; + uint32_t raygenDataSize; + uint32_t missCount; + uint32_t missDataSize; + uint32_t hitCount; + uint32_t hitDataSize; + uint32_t callableCount; + uint32_t callableDataSize; } ShaderBindingTableInfo; typedef struct { const PalGraphicsBackend* backend; bool hasFsr; - Uint32 type; - Uint32 shaderExportCount; + uint32_t type; + uint32_t shaderExportCount; D3D12_SHADING_RATE shadingRate; D3D_PRIMITIVE_TOPOLOGY topology; - Uint32* strides; + uint32_t* strides; void* handle; ShaderExport* shaderExports; PipelineLayout* layout; @@ -384,8 +384,8 @@ typedef struct { } Pipeline; typedef struct { - Uint32 startIndex; - Uint32 offset; + uint32_t startIndex; + uint32_t offset; D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE region; } AddressRegion; @@ -393,8 +393,8 @@ typedef struct { const PalGraphicsBackend* backend; bool isDirty; - Uint32 stagingBufferSize; - Uint32 handleSize; + uint32_t stagingBufferSize; + uint32_t handleSize; ID3D12Resource* buffer; ID3D12Resource* stagingBuffer; D3D12_GPU_VIRTUAL_ADDRESS baseAddress; @@ -415,41 +415,41 @@ typedef struct { const PalGraphicsBackend* backend; bool hasDescriptorIndexing; - Uint32 bindingCount; - Uint32 samplerCount; + uint32_t bindingCount; + uint32_t samplerCount; D3D12_SHADER_VISIBILITY visibility; DescriptorSetBinding* bindings; } DescriptorSetLayout; typedef struct { - Uint32 incrementSize; - Uint32 nextOffset; - Uint64 cpuBase; - Uint64 gpuBase; + uint32_t incrementSize; + uint32_t nextOffset; + uint64_t cpuBase; + uint64_t gpuBase; ID3D12DescriptorHeap* handle; } DescriptorHeap; typedef struct { - Uint32 maxUniformBuffers; - Uint32 maxSampledImages; - Uint32 maxStorageBuffers; - Uint32 maxSamplers; - Uint32 maxStorageImages; - Uint32 maxAs; - - Uint32 usedUniformBuffers; - Uint32 usedSampledImages; - Uint32 usedStorageBuffers; - Uint32 usedSamplers; - Uint32 usedStorageImages; - Uint32 usedAs; + uint32_t maxUniformBuffers; + uint32_t maxSampledImages; + uint32_t maxStorageBuffers; + uint32_t maxSamplers; + uint32_t maxStorageImages; + uint32_t maxAs; + + uint32_t usedUniformBuffers; + uint32_t usedSampledImages; + uint32_t usedStorageBuffers; + uint32_t usedSamplers; + uint32_t usedStorageImages; + uint32_t usedAs; } DescriptorHeapLimits; typedef struct { const PalGraphicsBackend* backend; - Uint32 resourceOffset; - Uint32 samplerOffset; + uint32_t resourceOffset; + uint32_t samplerOffset; DescriptorSetLayout* layout; void* pool; // DescriptorPool } DescriptorSet; @@ -460,8 +460,8 @@ typedef struct { bool hasDescriptorIndexing; bool hasResourceHeap; bool hasSamplerHeap; - Uint32 maxSets; - Uint32 usedSets; + uint32_t maxSets; + uint32_t usedSets; DescriptorHeapLimits limits; DescriptorHeap resourceHeap; DescriptorHeap samplerHeap; @@ -822,7 +822,7 @@ static PalImageUsages ImageUsageFromD3D12(D3D12_FORMAT_SUPPORT1 flags) return usages; } -static Uint32 samplesToD3D12(PalSampleCount count) +static uint32_t samplesToD3D12(PalSampleCount count) { switch (count) { case PAL_SAMPLE_COUNT_2: @@ -1284,9 +1284,9 @@ static bool fillBuildInfoD3D12( D3D12_GPU_VIRTUAL_ADDRESS dstAs, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC* buildInfo) { - static Uint32 maxInstanceCount = 1000000; - static Uint32 maxPrimitiveCount = 10000000; - static Uint32 maxGeometryCount = 100000; + static uint32_t maxInstanceCount = 1000000; + static uint32_t maxPrimitiveCount = 10000000; + static uint32_t maxGeometryCount = 100000; if (info->geometryCount > maxGeometryCount) { return false; @@ -1380,7 +1380,7 @@ static bool fillBuildInfoD3D12( return true; } -static Uint32 getFormatSizeD3D12(PalFormat format) +static uint32_t getFormatSizeD3D12(PalFormat format) { switch (format) { case PAL_FORMAT_R8_UNORM: @@ -1489,15 +1489,15 @@ static Uint32 getFormatSizeD3D12(PalFormat format) return 0; } -static inline Uint32 alignD3D12( - Uint32 value, - Uint32 alignment) +static inline uint32_t alignD3D12( + uint32_t value, + uint32_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } static D3D12_RESOURCE_STATES barrierToD3D12( - Uint32 stageCount, + uint32_t stageCount, PalUsageState state, PalShaderStage* shaderStages) { @@ -1725,10 +1725,10 @@ static void fillSubresourceD3D12( } } -static inline Uint64 getDescriptorHandleD3D12( - Uint32 index, - Uint32 size, - Uint64 baseOffset) +static inline uint64_t getDescriptorHandleD3D12( + uint32_t index, + uint32_t size, + uint64_t baseOffset) { return baseOffset + index * size; } @@ -1756,7 +1756,7 @@ static D3D12_RAYTRACING_INSTANCE_FLAGS instanceFlagsToD3D12( return instanceFlags; } -static D3D_PRIMITIVE_TOPOLOGY getPatchTopology(Uint32 patch) +static D3D_PRIMITIVE_TOPOLOGY getPatchTopology(uint32_t patch) { switch (patch) { case 1: @@ -1853,7 +1853,7 @@ static D3D_PRIMITIVE_TOPOLOGY getPatchTopology(Uint32 patch) return D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST; } -static Uint32 getVertexTypeSizeD3D12(PalVertexType type) +static uint32_t getVertexTypeSizeD3D12(PalVertexType type) { // count x sizeof type returned as size switch (type) { @@ -1918,7 +1918,7 @@ static void convertToWcharD3D12( } static void getHitGroupNameD3D12( - Uint32 index, + uint32_t index, wchar_t dst[PAL_SHADER_ENTRY_NAME_SIZE]) { wcscpy(dst, L"HitGroup"); @@ -1937,7 +1937,7 @@ static void pollMessagesD3D12(Device* device) SIZE_T size = 0; queue->lpVtbl->GetMessage(queue, i, nullptr, &size); - Uint8* buffer = palAllocate(s_D3D.allocator, size, 0); + uint8_t* buffer = palAllocate(s_D3D.allocator, size, 0); if (!buffer) { return; } @@ -2066,7 +2066,7 @@ static void getDescriptorTierLimitsD3D12( &options5, sizeof(options5)); - Uint32 perStage = 0; + uint32_t perStage = 0; if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED) { // add buckets for acceleration structure if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) { @@ -2238,10 +2238,10 @@ void PAL_CALL shutdownGraphicsD3D12() } PalResult PAL_CALL enumerateAdaptersD3D12( - Int32* count, + int32_t* count, PalAdapter** outAdapters) { - Uint32 adapterCount = 0; + uint32_t adapterCount = 0; IDXGIAdapter* adapter = nullptr; IDXGIAdapter4* dxAdapters[32]; // should be more than enough ID3D12Device* devices[32]; // should be more than enough @@ -2425,13 +2425,13 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( imageCaps->maxArrayLayers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; // d3d12 does not give this but we calculate from the max width and width - Uint32 a = imageCaps->maxWidth; - Uint32 b = imageCaps->maxHeight; - Uint32 c = imageCaps->maxDepth; + uint32_t a = imageCaps->maxWidth; + uint32_t b = imageCaps->maxHeight; + uint32_t c = imageCaps->maxDepth; - Uint32 tmp = a > b ? a : b; - Uint32 size = tmp > c ? tmp : c; - Uint32 levels = 0; + uint32_t tmp = a > b ? a : b; + uint32_t size = tmp > c ? tmp : c; + uint32_t levels = 0; while (size > 0) { // divide by two size = size / 2; @@ -2590,7 +2590,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) return features; } -Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( +uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( PalAdapter* adapter, PalShaderFormats shaderFormat) { @@ -3012,8 +3012,8 @@ void PAL_CALL destroyDeviceD3D12(PalDevice* device) PalResult PAL_CALL allocateMemoryD3D12( PalDevice* device, PalMemoryType type, - Uint64 memoryMask, - Uint64 size, + uint64_t memoryMask, + uint64_t size, PalMemory** outMemory) { HRESULT result; @@ -3366,10 +3366,10 @@ bool PAL_CALL canQueuePresentD3D12( PalResult PAL_CALL enumerateFormatsD3D12( PalAdapter* adapter, - Int32* count, + int32_t* count, PalFormatInfo* outFormats) { - Int32 fmtCount = 0; + int32_t fmtCount = 0; HRESULT result; Adapter* d3dAdapter = (Adapter*)adapter; ID3D12Device* device = d3dAdapter->tmpDevice; @@ -3514,7 +3514,7 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS samples = {0}; samples.Format = fmt; - Uint32 tmp = 0; + uint32_t tmp = 0; for (int i = 0; i < 6; i++) { samples.SampleCount = sampleCounts[i]; result = device->lpVtbl->CheckFeatureSupport( @@ -3659,7 +3659,7 @@ PalResult PAL_CALL getImageMemoryRequirementsD3D12( PalResult PAL_CALL bindImageMemoryD3D12( PalImage* image, PalMemory* memory, - Uint64 offset) + uint64_t offset) { HRESULT result; Image* d3dImage = (Image*)image; @@ -3694,8 +3694,8 @@ PalResult PAL_CALL bindImageMemoryD3D12( PalResult PAL_CALL mapImageMemoryD3D12( PalImage* image, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr) { return PAL_RESULT_MEMORY_MAP_FAILED; @@ -3739,7 +3739,7 @@ PalResult PAL_CALL createImageViewD3D12( imageView->format = formatToD3D12(info->format); if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR && hasRTV) { RTVHeapAllocator* allocator = &d3dDevice->rtvAllocator; - Uint32 index = allocator->freeTop; + uint32_t index = allocator->freeTop; allocator->freeTop = allocator->freeList[index]; D3D12_CPU_DESCRIPTOR_HANDLE dst; @@ -3764,7 +3764,7 @@ PalResult PAL_CALL createImageViewD3D12( } else if (info->subresourceRange.aspect != PAL_IMAGE_ASPECT_COLOR && hasDSV) { DSVHeapAllocator* allocator = &d3dDevice->dsvAllocator; - Uint32 index = allocator->freeTop; + uint32_t index = allocator->freeTop; allocator->freeTop = allocator->freeList[index]; D3D12_CPU_DESCRIPTOR_HANDLE dst; @@ -4215,7 +4215,7 @@ void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) PalImage* PAL_CALL getSwapchainImageD3D12( PalSwapchain* swapchain, - Int32 index) + int32_t index) { Swapchain* d3dSwapchain = (Swapchain*)swapchain; if (index > d3dSwapchain->imageCount) { @@ -4227,9 +4227,9 @@ PalImage* PAL_CALL getSwapchainImageD3D12( PalResult PAL_CALL getNextSwapchainImageD3D12( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32* outIndex) + uint32_t* outIndex) { - Uint32 index = 0; + uint32_t index = 0; Swapchain* d3dSwapchain = (Swapchain*)swapchain; ID3D12CommandQueue* queue = d3dSwapchain->queue; @@ -4287,8 +4287,8 @@ PalResult PAL_CALL presentSwapchainD3D12( // check if swapchain needs to be resize RECT windowRect; bool ret = GetClientRect((HWND)d3dSwapchain->surface->handle, &windowRect); - Uint32 w = windowRect.right - windowRect.left; - Uint32 h = windowRect.bottom - windowRect.top; + uint32_t w = windowRect.right - windowRect.left; + uint32_t h = windowRect.bottom - windowRect.top; if (!ret) { return PAL_RESULT_SURFACE_LOST; @@ -4305,8 +4305,8 @@ PalResult PAL_CALL presentSwapchainD3D12( PalResult PAL_CALL resizeSwapchainD3D12( PalSwapchain* swapchain, - Uint32 newWidth, - Uint32 newHeight) + uint32_t newWidth, + uint32_t newHeight) { HRESULT result; Swapchain* d3dSwapchain = (Swapchain*)swapchain; @@ -4487,12 +4487,12 @@ void PAL_CALL destroyFenceD3D12(PalFence* fence) PalResult PAL_CALL waitFenceD3D12( PalFence* fence, - Uint64 timeout) + uint64_t timeout) { HRESULT result; Fence* d3dFence = (Fence*)fence; DWORD ret = 0; - Uint64 value = d3dFence->value; + uint64_t value = d3dFence->value; if (d3dFence->handle->lpVtbl->GetCompletedValue(d3dFence->handle) < value) { HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); @@ -4602,8 +4602,8 @@ void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore) PalResult PAL_CALL waitSemaphoreD3D12( PalSemaphore* semaphore, - Uint64 value, - Uint64 timeout) + uint64_t value, + uint64_t timeout) { HRESULT result; DWORD ret = 0; @@ -4643,7 +4643,7 @@ PalResult PAL_CALL waitSemaphoreD3D12( PalResult PAL_CALL signalSemaphoreD3D12( PalSemaphore* semaphore, PalQueue* queue, - Uint64 value) + uint64_t value) { Semaphore* d3dSemaphore = (Semaphore*)semaphore; if (!d3dSemaphore->isTimeline) { @@ -4662,7 +4662,7 @@ PalResult PAL_CALL signalSemaphoreD3D12( PalResult PAL_CALL getSemaphoreValueD3D12( PalSemaphore* semaphore, - Uint64* outValue) + uint64_t* outValue) { Semaphore* d3dSemaphore = (Semaphore*)semaphore; if (!d3dSemaphore->isTimeline) { @@ -4694,7 +4694,7 @@ PalResult PAL_CALL createCommandPoolD3D12( pool->size = 8; pool->cmdBuffersData = nullptr; - Uint32 size = sizeof(CommandBufferData) * pool->size; + uint32_t size = sizeof(CommandBufferData) * pool->size; pool->cmdBuffersData = palAllocate(s_D3D.allocator, size, 0); if (!pool->cmdBuffersData) { return PAL_RESULT_OUT_OF_MEMORY; @@ -5046,9 +5046,9 @@ PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( PalResult PAL_CALL cmdDrawMeshTasksD3D12( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ) + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; @@ -5068,7 +5068,7 @@ PalResult PAL_CALL cmdDrawMeshTasksD3D12( PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 drawCount) + uint32_t drawCount) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; @@ -5097,7 +5097,7 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount) + uint32_t maxDrawCount) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; @@ -5209,16 +5209,16 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( ImageView* tmp = (ImageView*)info->colorAttachments[i].imageView; RTVHeapAllocator* allocator = &tmp->device->rtvAllocator; - Uint32 size = allocator->incrementSize; - Uint64 base = allocator->baseOffset; + uint32_t size = allocator->incrementSize; + uint64_t base = allocator->baseOffset; colorAttachments[i].ptr = getDescriptorHandleD3D12(tmp->heapIndex, size, base); } if (info->depthStencilAttachment) { ImageView* tmp = (ImageView*)info->depthStencilAttachment->imageView; DSVHeapAllocator* allocator = &tmp->device->dsvAllocator; - Uint32 size = allocator->incrementSize; - Uint64 base = allocator->baseOffset; + uint32_t size = allocator->incrementSize; + uint64_t base = allocator->baseOffset; depthStencilAttachment.ptr = getDescriptorHandleD3D12(tmp->heapIndex, size, base); depthStencil = &depthStencilAttachment; } @@ -5330,11 +5330,11 @@ PalResult PAL_CALL cmdCopyBufferToImageD3D12( footPrint->Footprint.Depth = copyInfo->imageDepth; footPrint->Footprint.Format = formatToD3D12(dst->info.format); - Uint32 imageFormatSize = getFormatSizeD3D12(dst->info.format); - Uint64 rowPitch = alignD3D12((Uint64)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + uint32_t imageFormatSize = getFormatSizeD3D12(dst->info.format); + uint64_t rowPitch = alignD3D12((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); footPrint->Footprint.RowPitch = (UINT)rowPitch; - Uint32 planeCount = 1; + uint32_t planeCount = 1; if (copyInfo->imageAspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { planeCount = 2; } @@ -5344,15 +5344,15 @@ PalResult PAL_CALL cmdCopyBufferToImageD3D12( box.bottom = copyInfo->imageHeight; box.back = copyInfo->imageDepth; - Uint32 level = copyInfo->ImageMipLevel; - Uint32 startLayer = copyInfo->ImageStartArrayLayer; - Uint32 layerCount = copyInfo->ImageArrayLayerCount; - Uint32 maxLayers = dst->info.depthOrArraySize; - Uint32 maxLevels = dst->info.mipLevelCount; + uint32_t level = copyInfo->ImageMipLevel; + uint32_t startLayer = copyInfo->ImageStartArrayLayer; + uint32_t layerCount = copyInfo->ImageArrayLayerCount; + uint32_t maxLayers = dst->info.depthOrArraySize; + uint32_t maxLevels = dst->info.mipLevelCount; - for (Uint32 plane = 0; plane < planeCount; plane++) { - for (Uint32 layer = startLayer; layer < startLayer + layerCount; layer++) { - Uint32 index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); + for (uint32_t plane = 0; plane < planeCount; plane++) { + for (uint32_t layer = startLayer; layer < startLayer + layerCount; layer++) { + uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); dstLocation.SubresourceIndex = index; d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( @@ -5395,27 +5395,27 @@ PalResult PAL_CALL cmdCopyImageD3D12( box.bottom = copyInfo->srcOffsetY + copyInfo->height; box.back = copyInfo->srcOffsetZ + copyInfo->depth; - Uint32 planeCount = 1; - Uint32 layerCount = copyInfo->arrayLayerCount; + uint32_t planeCount = 1; + uint32_t layerCount = copyInfo->arrayLayerCount; if (copyInfo->aspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { planeCount = 2; } - Uint32 dstLevel = copyInfo->dstMipLevel; - Uint32 dstStartLayer = copyInfo->dstStartArrayLayer; - Uint32 dstMaxLayers = dstImage->info.depthOrArraySize; - Uint32 dstMaxLevels = dstImage->info.mipLevelCount; + uint32_t dstLevel = copyInfo->dstMipLevel; + uint32_t dstStartLayer = copyInfo->dstStartArrayLayer; + uint32_t dstMaxLayers = dstImage->info.depthOrArraySize; + uint32_t dstMaxLevels = dstImage->info.mipLevelCount; - Uint32 srcLevel = copyInfo->srcMipLevel; - Uint32 srcStartLayer = copyInfo->srcStartArrayLayer; - Uint32 srcMaxLayers = srcImage->info.depthOrArraySize; - Uint32 srcMaxLevels = srcImage->info.mipLevelCount; + uint32_t srcLevel = copyInfo->srcMipLevel; + uint32_t srcStartLayer = copyInfo->srcStartArrayLayer; + uint32_t srcMaxLayers = srcImage->info.depthOrArraySize; + uint32_t srcMaxLevels = srcImage->info.mipLevelCount; - for (Uint32 plane = 0; plane < planeCount; plane++) { - for (Uint32 layer = 0; layer + layerCount; layer++) { + for (uint32_t plane = 0; plane < planeCount; plane++) { + for (uint32_t layer = 0; layer + layerCount; layer++) { // clang-format off - Uint32 dstIndex = dstLevel + (dstStartLayer + layer * dstMaxLevels) + (plane * dstMaxLevels * dstMaxLayers); - Uint32 srcIndex = srcLevel + (srcStartLayer + layer * srcMaxLevels) + (plane * srcMaxLevels * srcMaxLayers); + uint32_t dstIndex = dstLevel + (dstStartLayer + layer * dstMaxLevels) + (plane * dstMaxLevels * dstMaxLayers); + uint32_t srcIndex = srcLevel + (srcStartLayer + layer * srcMaxLevels) + (plane * srcMaxLevels * srcMaxLayers); // clang-format on dstLocation.SubresourceIndex = dstIndex; @@ -5459,8 +5459,8 @@ PalResult PAL_CALL cmdCopyImageToBufferD3D12( srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; srcLocation.pResource = src->handle; - Uint32 imageFormatSize = getFormatSizeD3D12(src->info.format); - Uint64 rowPitch = alignD3D12((Uint64)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + uint32_t imageFormatSize = getFormatSizeD3D12(src->info.format); + uint64_t rowPitch = alignD3D12((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); footPrint->Footprint.RowPitch = (UINT)rowPitch; D3D12_BOX box = {0}; @@ -5471,20 +5471,20 @@ PalResult PAL_CALL cmdCopyImageToBufferD3D12( box.bottom = copyInfo->imageOffsetY + copyInfo->imageHeight; box.back = copyInfo->imageOffsetX + copyInfo->imageDepth; - Uint32 planeCount = 1; + uint32_t planeCount = 1; if (copyInfo->imageAspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { planeCount = 2; } - Uint32 level = copyInfo->ImageMipLevel; - Uint32 startLayer = copyInfo->ImageStartArrayLayer; - Uint32 layerCount = copyInfo->ImageArrayLayerCount; - Uint32 maxLayers = src->info.depthOrArraySize; - Uint32 maxLevels = src->info.mipLevelCount; + uint32_t level = copyInfo->ImageMipLevel; + uint32_t startLayer = copyInfo->ImageStartArrayLayer; + uint32_t layerCount = copyInfo->ImageArrayLayerCount; + uint32_t maxLayers = src->info.depthOrArraySize; + uint32_t maxLevels = src->info.mipLevelCount; - for (Uint32 plane = 0; plane < planeCount; plane++) { - for (Uint32 layer = startLayer; layer < startLayer + layerCount; layer++) { - Uint32 index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); + for (uint32_t plane = 0; plane < planeCount; plane++) { + for (uint32_t layer = startLayer; layer < startLayer + layerCount; layer++) { + uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); srcLocation.SubresourceIndex = index; d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( @@ -5546,7 +5546,7 @@ PalResult PAL_CALL cmdBindPipelineD3D12( PalResult PAL_CALL cmdSetViewportD3D12( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalViewport* viewports) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -5582,7 +5582,7 @@ PalResult PAL_CALL cmdSetViewportD3D12( PalResult PAL_CALL cmdSetScissorsD3D12( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalRect2D* scissors) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -5616,10 +5616,10 @@ PalResult PAL_CALL cmdSetScissorsD3D12( PalResult PAL_CALL cmdBindVertexBuffersD3D12( PalCommandBuffer* cmdBuffer, - Uint32 firstSlot, - Uint32 count, + uint32_t firstSlot, + uint32_t count, PalBuffer** buffers, - Uint64* offsets) + uint64_t* offsets) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Pipeline* pipeline = d3dCmdBuffer->pipeline; @@ -5663,7 +5663,7 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( PalResult PAL_CALL cmdBindIndexBufferD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, + uint64_t offset, PalIndexType type) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -5685,10 +5685,10 @@ PalResult PAL_CALL cmdBindIndexBufferD3D12( PalResult PAL_CALL cmdDrawD3D12( PalCommandBuffer* cmdBuffer, - Uint32 vertexCount, - Uint32 instanceCount, - Uint32 firstVertex, - Uint32 firstInstance) + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; d3dCmdBuffer->handle->lpVtbl->DrawInstanced( @@ -5704,7 +5704,7 @@ PalResult PAL_CALL cmdDrawD3D12( PalResult PAL_CALL cmdDrawIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count) + uint32_t count) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; @@ -5733,7 +5733,7 @@ PalResult PAL_CALL cmdDrawIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount) + uint32_t maxDrawCount) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; @@ -5761,11 +5761,11 @@ PalResult PAL_CALL cmdDrawIndirectCountD3D12( PalResult PAL_CALL cmdDrawIndexedD3D12( PalCommandBuffer* cmdBuffer, - Uint32 indexCount, - Uint32 instanceCount, - Uint32 firstIndex, - Int32 vertexOffset, - Uint32 firstInstance) + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; d3dCmdBuffer->handle->lpVtbl->DrawIndexedInstanced( @@ -5782,7 +5782,7 @@ PalResult PAL_CALL cmdDrawIndexedD3D12( PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count) + uint32_t count) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; @@ -5811,7 +5811,7 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount) + uint32_t maxDrawCount) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = d3dCmdBuffer->device; @@ -5887,20 +5887,20 @@ PalResult PAL_CALL cmdImageBarrierD3D12( return PAL_RESULT_SUCCESS; } - Uint32 planeCount = 1; // for color or depth + uint32_t planeCount = 1; // for color or depth if (subresourceRange->aspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { planeCount = 2; } D3D12_RESOURCE_BARRIER* barriers = nullptr; - Uint32 levelCount = subresourceRange->mipLevelCount; - Uint32 layerCount = subresourceRange->layerArrayCount; + uint32_t levelCount = subresourceRange->mipLevelCount; + uint32_t layerCount = subresourceRange->layerArrayCount; - Uint32 startLevel = subresourceRange->startMipLevel; - Uint32 startLayer = subresourceRange->startArrayLayer; - Uint32 maxLevels = d3dImage->info.mipLevelCount; - Uint32 maxLayers = d3dImage->info.depthOrArraySize; - Uint32 barrierCount = layerCount * levelCount * planeCount; + uint32_t startLevel = subresourceRange->startMipLevel; + uint32_t startLayer = subresourceRange->startArrayLayer; + uint32_t maxLevels = d3dImage->info.mipLevelCount; + uint32_t maxLayers = d3dImage->info.depthOrArraySize; + uint32_t barrierCount = layerCount * levelCount * planeCount; if (startLevel == 0 && levelCount == maxLevels && startLayer == 0 && layerCount == maxLayers) { // full resource @@ -5931,11 +5931,11 @@ PalResult PAL_CALL cmdImageBarrierD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - Uint32 count = 0; - for (Uint32 plane = 0; plane < planeCount; plane++) { - for (Uint32 layer = startLayer; layer < startLayer + layerCount; layer++) { - for (Uint32 level = startLevel; level < startLevel + levelCount; level++) { - Uint32 index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); + uint32_t count = 0; + for (uint32_t plane = 0; plane < planeCount; plane++) { + for (uint32_t layer = startLayer; layer < startLayer + layerCount; layer++) { + for (uint32_t level = startLevel; level < startLevel + levelCount; level++) { + uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); D3D12_RESOURCE_BARRIER* tmp = &barriers[count++]; tmp->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; @@ -5992,9 +5992,9 @@ PalResult PAL_CALL cmdBufferBarrierD3D12( PalResult PAL_CALL cmdDispatchD3D12( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ) + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; d3dCmdBuffer->handle->lpVtbl->Dispatch( @@ -6008,12 +6008,12 @@ PalResult PAL_CALL cmdDispatchD3D12( PalResult PAL_CALL cmdDispatchBaseD3D12( PalCommandBuffer* cmdBuffer, - Uint32 baseGroupX, - Uint32 baseGroupY, - Uint32 baseGroupZ, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ) + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6048,10 +6048,10 @@ PalResult PAL_CALL cmdDispatchIndirectD3D12( PalResult PAL_CALL cmdTraceRaysD3D12( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, - Uint32 raygenIndex, - Uint32 width, - Uint32 height, - Uint32 depth) + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; @@ -6059,7 +6059,7 @@ PalResult PAL_CALL cmdTraceRaysD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Uint64 stride = d3dSbt->raygen.region.StrideInBytes; + uint64_t stride = d3dSbt->raygen.region.StrideInBytes; D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; raygenAddress.SizeInBytes = d3dSbt->raygen.region.SizeInBytes; raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * stride; @@ -6082,7 +6082,7 @@ PalResult PAL_CALL cmdTraceRaysD3D12( PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalCommandBuffer* cmdBuffer, - Uint32 raygenIndex, + uint32_t raygenIndex, PalShaderBindingTable* sbt, PalBuffer* buffer) { @@ -6120,7 +6120,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( desc.Height = data.groupCountXOrHeight; desc.Depth = data.groupCountXOrDepth; - Uint64 stride = d3dSbt->raygen.region.StrideInBytes; + uint64_t stride = d3dSbt->raygen.region.StrideInBytes; D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; raygenAddress.SizeInBytes = d3dSbt->raygen.region.SizeInBytes; raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * stride; @@ -6168,7 +6168,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, - Uint32 setIndex, + uint32_t setIndex, PalDescriptorSet* set) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -6177,7 +6177,7 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( DescriptorPool* pool = d3dSet->pool; // bind heaps - Uint32 heapCount = 0; + uint32_t heapCount = 0; ID3D12DescriptorHeap* heaps[2]; if (pool->hasResourceHeap) { heaps[heapCount++] = pool->resourceHeap.handle; @@ -6189,8 +6189,8 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( d3dCmdBuffer->handle->lpVtbl->SetDescriptorHeaps(d3dCmdBuffer->handle, heapCount, heaps); // bind resource descriptor table - Uint32 resourceCount = d3dSet->layout->bindingCount - d3dSet->layout->samplerCount; - Uint32 baseIndex = setIndex; + uint32_t resourceCount = d3dSet->layout->bindingCount - d3dSet->layout->samplerCount; + uint32_t baseIndex = setIndex; if (pipeline->layout->constantIndex != UINT32_MAX) { // If push constant was used to create the pipeline layout // slot 0 will be reserve for it @@ -6249,10 +6249,10 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalResult PAL_CALL cmdPushConstantsD3D12( PalCommandBuffer* cmdBuffer, - Uint32 shaderStageCount, + uint32_t shaderStageCount, PalShaderStage* shaderStages, - Uint32 offset, - Uint32 size, + uint32_t offset, + uint32_t size, const void* value) { CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -6537,8 +6537,8 @@ PalResult PAL_CALL getBufferMemoryRequirementsD3D12( PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( PalDevice* device, - Uint32 instanceCount, - Uint64* outSize) + uint32_t instanceCount, + uint64_t* outSize) { *outSize = sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * instanceCount; return PAL_RESULT_SUCCESS; @@ -6548,13 +6548,13 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, - Uint32* outBufferRowLength, - Uint32* outBufferImageHeight, - Uint64* outSize) + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize) { - Uint32 imageFormatSize = getFormatSizeD3D12(imageFormat); - Uint32 rowPitch = alignD3D12((Uint64)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); - Uint32 bufferImageHeight = 0; + uint32_t imageFormatSize = getFormatSizeD3D12(imageFormat); + uint32_t rowPitch = alignD3D12((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + uint32_t bufferImageHeight = 0; if (copyInfo->bufferImageHeight) { bufferImageHeight = copyInfo->bufferImageHeight; @@ -6564,7 +6564,7 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( *outBufferRowLength = rowPitch; *outBufferImageHeight = bufferImageHeight; - *outSize = (Uint64)rowPitch * bufferImageHeight * copyInfo->imageDepth; + *outSize = (uint64_t)rowPitch * bufferImageHeight * copyInfo->imageDepth; return PAL_RESULT_SUCCESS; } @@ -6572,7 +6572,7 @@ PalResult PAL_CALL writeToInstanceBufferD3D12( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, - Uint32 instanceCount) + uint32_t instanceCount) { D3D12_RAYTRACING_INSTANCE_DESC* data = ptr; for (int i = 0; i < instanceCount; i++) { @@ -6597,18 +6597,18 @@ PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo) { - Uint32 imageFormatSize = getFormatSizeD3D12(imageFormat); - Uint32 srcRowPitch = copyInfo->imageWidth * imageFormatSize; - const Uint32 dstSlicePitch = copyInfo->bufferRowLength * copyInfo->bufferImageHeight; - const Uint32 srcSlicePitch = srcRowPitch * copyInfo->imageHeight; + uint32_t imageFormatSize = getFormatSizeD3D12(imageFormat); + uint32_t srcRowPitch = copyInfo->imageWidth * imageFormatSize; + const uint32_t dstSlicePitch = copyInfo->bufferRowLength * copyInfo->bufferImageHeight; + const uint32_t srcSlicePitch = srcRowPitch * copyInfo->imageHeight; // manually offset the buffer with the provided offset - Uint8* dst = (Uint8*)ptr + copyInfo->bufferOffset; - const Uint8* src = (const Uint8*)srcData; + uint8_t* dst = (uint8_t*)ptr + copyInfo->bufferOffset; + const uint8_t* src = (const uint8_t*)srcData; // write to destination pointer - for (Uint32 z = 0; z < copyInfo->imageDepth; z++) { - for (Uint32 y = 0; y < copyInfo->imageHeight; y++) { + for (uint32_t z = 0; z < copyInfo->imageDepth; z++) { + for (uint32_t y = 0; y < copyInfo->imageHeight; y++) { memcpy( dst + z * dstSlicePitch + y * copyInfo->bufferRowLength, src + z * srcSlicePitch + y * srcRowPitch, @@ -6622,7 +6622,7 @@ PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( PalResult PAL_CALL bindBufferMemoryD3D12( PalBuffer* buffer, PalMemory* memory, - Uint64 offset) + uint64_t offset) { HRESULT result; Buffer* d3dBuffer = (Buffer*)buffer; @@ -6677,8 +6677,8 @@ PalResult PAL_CALL bindBufferMemoryD3D12( PalResult PAL_CALL mapBufferMemoryD3D12( PalBuffer* buffer, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr) { void* ptr = nullptr; @@ -6689,7 +6689,7 @@ PalResult PAL_CALL mapBufferMemoryD3D12( return PAL_RESULT_MEMORY_MAP_FAILED; } - *outPtr = (Uint8*)ptr + offset; + *outPtr = (uint8_t*)ptr + offset; return PAL_RESULT_SUCCESS; } @@ -6722,7 +6722,7 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( Device* d3dDevice = (Device*)device; DescriptorSetLayout* layout = nullptr; DescriptorSetBinding* bindings = nullptr; - Uint32 count = info->bindingCount; + uint32_t count = info->bindingCount; bool hasDescriptorIndexing = d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { @@ -6795,18 +6795,18 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( rangeFlags = D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE; } - Uint32 resourceOffset = 0; - Uint32 samplerOffset = 0; - Uint32 SRVRegister = 0; - Uint32 UAVRegister = 0; - Uint32 CBVRegister = 0; + uint32_t resourceOffset = 0; + uint32_t samplerOffset = 0; + uint32_t SRVRegister = 0; + uint32_t UAVRegister = 0; + uint32_t CBVRegister = 0; - Uint32 sampledImageCount = 0; - Uint32 storageImageCount = 0; - Uint32 storageBufferCount = 0; - Uint32 uniformBufferCount = 0; - Uint32 tlasCount = 0; - Uint32 samplerCount = 0; + uint32_t sampledImageCount = 0; + uint32_t storageImageCount = 0; + uint32_t storageBufferCount = 0; + uint32_t uniformBufferCount = 0; + uint32_t tlasCount = 0; + uint32_t samplerCount = 0; for (int i = 0; i < count; i++) { DescriptorSetBinding* binding = &bindings[i]; @@ -6950,7 +6950,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - Uint32 resourceCount = 0; + uint32_t resourceCount = 0; DescriptorHeapLimits* limits = &pool->limits; for (int i = 0; i < info->maxDescriptorBindingSizes; i++) { PalDescriptorPoolBindingSize* bindingSize = &info->bindingSizes[i]; @@ -7115,12 +7115,12 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; DescriptorSet* set = nullptr; - Uint32 storageImageCount = 0; - Uint32 samplerCount = 0; - Uint32 storageBufferCount = 0; - Uint32 uniformBufferCount = 0; - Uint32 sampledImageCount = 0; - Uint32 tlasCount = 0; + uint32_t storageImageCount = 0; + uint32_t samplerCount = 0; + uint32_t storageBufferCount = 0; + uint32_t uniformBufferCount = 0; + uint32_t sampledImageCount = 0; + uint32_t tlasCount = 0; if (d3dPool->hasDescriptorIndexing != d3dLayout->hasDescriptorIndexing) { return PAL_RESULT_INVALID_OPERATION; @@ -7189,7 +7189,7 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( set->layout = d3dLayout; set->pool = d3dPool; - Uint32 totalDescriptors = tlasCount + storageBufferCount + uniformBufferCount; + uint32_t totalDescriptors = tlasCount + storageBufferCount + uniformBufferCount; totalDescriptors += sampledImageCount + storageImageCount; d3dPool->resourceHeap.nextOffset += totalDescriptors; d3dPool->samplerHeap.nextOffset += samplerCount; @@ -7206,7 +7206,7 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( PalResult PAL_CALL updateDescriptorSetD3D12( PalDevice* device, - Uint32 count, + uint32_t count, PalDescriptorSetWriteInfo* infos) { Device* d3dDevice = (Device*)device; @@ -7222,8 +7222,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( DescriptorSetBinding* binding = &layout->bindings[info->layoutBindingIndex]; DescriptorHeap* heap = nullptr; - Uint32 index = 0; - Uint32 bindingOffset = binding->range.OffsetInDescriptorsFromTableStart; + uint32_t index = 0; + uint32_t bindingOffset = binding->range.OffsetInDescriptorsFromTableStart; if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { heap = &pool->samplerHeap; @@ -7395,7 +7395,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; Buffer* buffer = (Buffer*)bufferInfo->buffer; - Uint32 stride = 4; + uint32_t stride = 4; if (bufferInfo->stride) { stride = bufferInfo->stride; desc.Buffer.StructureByteStride = bufferInfo->stride; @@ -7437,17 +7437,17 @@ PalResult PAL_CALL createPipelineLayoutD3D12( { Device* d3dDevice = (Device*)device; PipelineLayout* layout = nullptr; - Uint32 resourceCount = 0; - Uint32 samplerCount = 0; - Uint64 pushConstantSize = 0; - Uint32 sizeInBytes = sizeof(D3D12_DESCRIPTOR_RANGE1); + uint32_t resourceCount = 0; + uint32_t samplerCount = 0; + uint64_t pushConstantSize = 0; + uint32_t sizeInBytes = sizeof(D3D12_DESCRIPTOR_RANGE1); - Uint32 rangesOffset = 0; - Uint32 samplerRangesOffset = 0; + uint32_t rangesOffset = 0; + uint32_t samplerRangesOffset = 0; D3D12_DESCRIPTOR_RANGE1* ranges = nullptr; D3D12_DESCRIPTOR_RANGE1* samplerRanges = nullptr; - Uint32 parameterCount = 0; + uint32_t parameterCount = 0; D3D12_ROOT_PARAMETER1* parameters = nullptr; D3D12_ROOT_SIGNATURE_FLAGS rootFlags = 0; rootFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; @@ -7498,7 +7498,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } if (parameterCount) { - Uint32 paramtersSize = sizeof(D3D12_ROOT_PARAMETER1) * parameterCount; + uint32_t paramtersSize = sizeof(D3D12_ROOT_PARAMETER1) * parameterCount; parameters = palAllocate(s_D3D.allocator, paramtersSize, 0); if (!parameters) { return PAL_RESULT_OUT_OF_MEMORY; @@ -7534,7 +7534,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( parameterCount++; } - Uint32 registerSpace = 0; + uint32_t registerSpace = 0; for (int i = 0; i < info->descriptorSetLayoutCount; i++) { DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; D3D12_ROOT_PARAMETER1* parameter = nullptr; @@ -7543,8 +7543,8 @@ PalResult PAL_CALL createPipelineLayoutD3D12( resourceCount = tmp->bindingCount - tmp->samplerCount; samplerCount = tmp->samplerCount; - Uint32 samplerIndex = samplerRangesOffset; - Uint32 rangeIndex = rangesOffset; + uint32_t samplerIndex = samplerRangesOffset; + uint32_t rangeIndex = rangesOffset; // seperate the samplers from the remaining descriptors for (int j = 0; j < tmp->bindingCount; j++) { @@ -7657,8 +7657,8 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( PalPipeline** outPipeline) { HRESULT result; - Uint32 patchControlPoints = 0; - Uint32 totalSize = 0; + uint32_t patchControlPoints = 0; + uint32_t totalSize = 0; bool alphaToCoverageEnable = false; Pipeline* pipeline = nullptr; Device* d3dDevice = (Device*)device; @@ -7738,8 +7738,8 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( // Vertex input state // get the max size of vertex attributes in all layouts - Uint32 vertexCount = 0; - Uint32 vertexLayoutCount = info->vertexLayoutCount; + uint32_t vertexCount = 0; + uint32_t vertexLayoutCount = info->vertexLayoutCount; for (int i = 0; i < vertexLayoutCount; i++) { PalVertexLayout* layout = &info->vertexLayouts[i]; vertexCount += layout->attributeCount; @@ -7759,7 +7759,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( pipeline->strides = nullptr; if (vertexCount) { - pipeline->strides = palAllocate(s_D3D.allocator, sizeof(Uint32) * 8, 0); + pipeline->strides = palAllocate(s_D3D.allocator, sizeof(uint32_t) * 8, 0); if (!pipeline->strides) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7774,16 +7774,16 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( return PAL_RESULT_OUT_OF_MEMORY; } - Uint32 positionIndex = 0; - Uint32 colorIndex = 0; - Uint32 texCoordIndex = 0; - Uint32 normalIndex = 0; - Uint32 tangentIndex = 0; + uint32_t positionIndex = 0; + uint32_t colorIndex = 0; + uint32_t texCoordIndex = 0; + uint32_t normalIndex = 0; + uint32_t tangentIndex = 0; for (int i = 0; i < info->vertexLayoutCount; i++) { PalVertexLayout* layout = &info->vertexLayouts[i]; - Uint32 stride = 0; - Uint32 offset = 0; + uint32_t stride = 0; + uint32_t offset = 0; for (int j = 0; j < layout->attributeCount; j++) { PalVertexAttribute* vertexAttrib = &layout->attributes[j]; @@ -7823,7 +7823,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( } // build offsets and stride - Uint32 size = getVertexTypeSizeD3D12(vertexAttrib->type); + uint32_t size = getVertexTypeSizeD3D12(vertexAttrib->type); elementDesc->AlignedByteOffset = offset; offset += size; stride += size; @@ -8202,14 +8202,14 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( const wchar_t** localExports = nullptr; // find the total number of exports - Uint32 exportCount = 0; + uint32_t exportCount = 0; for (int i = 0; i < info->shaderCount; i++) { Shader* shader = (Shader*)info->shaders[i]; exportCount += shader->entryCount; } - Uint32 subObjectCount = 0; - Uint32 localExportCount = 0; + uint32_t subObjectCount = 0; + uint32_t localExportCount = 0; ShaderBindingTableInfo sbtInfo = {0}; for (int i = 0; i < info->shaderGroupCount; i++) { @@ -8249,7 +8249,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( } // find the max data size across all shader groups - Uint32 localRootSize = 0; + uint32_t localRootSize = 0; localRootSize = max(localRootSize, sbtInfo.raygenDataSize); localRootSize = max(localRootSize, sbtInfo.missDataSize); localRootSize = max(localRootSize, sbtInfo.hitDataSize); @@ -8304,7 +8304,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( } // global root signature - Uint32 subObjectIndex = 0; + uint32_t subObjectIndex = 0; D3D12_GLOBAL_ROOT_SIGNATURE globalRootSignature = {0}; globalRootSignature.pGlobalRootSignature = layout->handle; @@ -8327,7 +8327,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( subObjectIndex++; // shaders - Uint32 exportsOffset = 0; + uint32_t exportsOffset = 0; for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; D3D12_DXIL_LIBRARY_DESC* libraryDesc = &libraryDescs[i]; @@ -8357,8 +8357,8 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( } // hit groups - Uint32 localExportIndex = 0; - Uint32 hitGroupIndex = 0; + uint32_t localExportIndex = 0; + uint32_t hitGroupIndex = 0; for (int i = 0; i < info->shaderGroupCount; i++) { const wchar_t* exportName = nullptr; PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; @@ -8574,7 +8574,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Uint32 totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; + uint32_t totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; totalGroups += sbtInfo->missCount + sbtInfo->callableCount; if (info->recordCount != totalGroups) { return PAL_RESULT_INVALID_ARGUMENT; @@ -8635,14 +8635,14 @@ PalResult PAL_CALL createShaderBindingTableD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - Uint32 groupHandleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; - Uint32 groupHandleAlignment = D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT; - Uint32 groupBaseAlignment = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; + uint32_t groupHandleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + uint32_t groupHandleAlignment = D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT; + uint32_t groupBaseAlignment = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; // get the max local data size for (int i = 0; i < info->recordCount; i++) { PalShaderBindingTableRecordInfo* record = &info->records[i]; - Uint32 index = record->groupIndex; + uint32_t index = record->groupIndex; if (index < sbtInfo->raygenCount) { // raygen group @@ -8671,10 +8671,10 @@ PalResult PAL_CALL createShaderBindingTableD3D12( } // get strides - Uint32 raygenStride = 0; - Uint32 missStride = 0; - Uint32 hitStride = 0; - Uint32 callableStride = 0; + uint32_t raygenStride = 0; + uint32_t missStride = 0; + uint32_t hitStride = 0; + uint32_t callableStride = 0; raygenStride = alignD3D12(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); missStride = alignD3D12(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); @@ -8682,17 +8682,17 @@ PalResult PAL_CALL createShaderBindingTableD3D12( callableStride = alignD3D12(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); // get region size - Uint32 raygenRegionSize = raygenStride * sbtInfo->raygenCount; - Uint32 missRegionSize = missStride * sbtInfo->missCount; - Uint32 hitRegionSize = hitStride * sbtInfo->hitCount; - Uint32 callableRegionSize = callableStride * sbtInfo->callableCount; + uint32_t raygenRegionSize = raygenStride * sbtInfo->raygenCount; + uint32_t missRegionSize = missStride * sbtInfo->missCount; + uint32_t hitRegionSize = hitStride * sbtInfo->hitCount; + uint32_t callableRegionSize = callableStride * sbtInfo->callableCount; // get offsets - Uint32 offset = 0; - Uint32 raygenOffset = 0; - Uint32 missOffset = 0; - Uint32 hitOffset = 0; - Uint32 callableOffset = 0; + uint32_t offset = 0; + uint32_t raygenOffset = 0; + uint32_t missOffset = 0; + uint32_t hitOffset = 0; + uint32_t callableOffset = 0; raygenOffset = alignD3D12(offset, groupBaseAlignment); offset = raygenOffset + raygenRegionSize; @@ -8706,7 +8706,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( callableOffset = alignD3D12(offset, groupBaseAlignment); offset = callableOffset + callableRegionSize; - Uint32 bufferSize = alignD3D12(offset, groupBaseAlignment); + uint32_t bufferSize = alignD3D12(offset, groupBaseAlignment); // create gpu buffer D3D12_HEAP_PROPERTIES heapProps = {0}; @@ -8758,10 +8758,10 @@ PalResult PAL_CALL createShaderBindingTableD3D12( } // get shader group handles - Uint32 raygenIndex = 0; - Uint32 missIndex = 0; - Uint32 hitIndex = 0; - Uint32 callableIndex = 0; + uint32_t raygenIndex = 0; + uint32_t missIndex = 0; + uint32_t hitIndex = 0; + uint32_t callableIndex = 0; for (int i = 0; i < pipeline->shaderExportCount; i++) { ShaderExport* tmp = &pipeline->shaderExports[i]; @@ -8805,7 +8805,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // raygen for (int i = 0; i < sbtInfo->raygenCount; i++) { - Uint8* dstPtr = (Uint8*)ptr + (i * raygenStride); + uint8_t* dstPtr = (uint8_t*)ptr + (i * raygenStride); PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; memcpy(dstPtr, raygenHandles[i], groupHandleSize); @@ -8818,7 +8818,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // miss for (int i = 0; i < sbtInfo->missCount; i++) { - Uint8* dstPtr = (Uint8*)ptr + missOffset + (i * missStride); + uint8_t* dstPtr = (uint8_t*)ptr + missOffset + (i * missStride); PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; memcpy(dstPtr, missHandles[i], groupHandleSize); @@ -8831,7 +8831,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // hit group for (int i = 0; i < sbtInfo->hitCount; i++) { - Uint8* dstPtr = (Uint8*)ptr + hitOffset + (i * hitStride); + uint8_t* dstPtr = (uint8_t*)ptr + hitOffset + (i * hitStride); PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; memcpy(dstPtr, hitHandles[i], groupHandleSize); @@ -8844,7 +8844,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // callable for (int i = 0; i < sbtInfo->callableCount; i++) { - Uint8* dstPtr = (Uint8*)ptr + callableOffset + (i * callableStride); + uint8_t* dstPtr = (uint8_t*)ptr + callableOffset + (i * callableStride); PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; memcpy(dstPtr, callableHandles[i], groupHandleSize); @@ -8923,7 +8923,7 @@ void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) PalResult PAL_CALL updateShaderBindingTableD3D12( PalShaderBindingTable* sbt, - Uint32 count, + uint32_t count, PalShaderBindingTableRecordInfo* infos) { HRESULT result; @@ -8937,9 +8937,9 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - Uint64 stride = 0; - Uint64 offset = 0; - Uint32 startIndex = 0; + uint64_t stride = 0; + uint64_t offset = 0; + uint32_t startIndex = 0; for (int i = 0; i < count; i++) { PalShaderBindingTableRecordInfo* info = &infos[i]; @@ -8948,7 +8948,7 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( } // find the group the record belongs to - Uint32 index = info->groupIndex; + uint32_t index = info->groupIndex; if (index < sbtInfo->raygenCount) { // raygen group offset = 0; @@ -8975,8 +8975,8 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( } // write payload - Uint32 localIndex = index - startIndex; - Uint8* dst = (Uint8*)data + offset + (localIndex * stride); + uint32_t localIndex = index - startIndex; + uint8_t* dst = (uint8_t*)data + offset + (localIndex * stride); memcpy(dst + d3dSbt->handleSize, info->localData, info->localDataSize); } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 8e9662cb..55c5cabe 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -61,14 +61,14 @@ PAL_HANDLE(PalSurface) PAL_HANDLE(PalShaderBindingTable) typedef struct { - Int32 count; - Int32 startIndex; + int32_t count; + int32_t startIndex; const PalGraphicsBackend* base; } BackendData; typedef struct { bool initialized; - Int32 backendCount; + int32_t backendCount; const PalAllocator* allocator; BackendData backends[MAX_BACKENDS]; } GraphicsLinux; @@ -79,16 +79,16 @@ static GraphicsLinux s_Graphics = {0}; // Internal API // ================================================== -static inline Uint32 _ceil( - Uint32 a, - Uint32 b) +static inline uint32_t _ceil( + uint32_t a, + uint32_t b) { return (a + b - 1) / b; } -static inline Uint32 _min( - Uint32 a, - Uint32 b) +static inline uint32_t _min( + uint32_t a, + uint32_t b) { return (a < b) ? a : b; } @@ -110,7 +110,7 @@ PalResult PAL_CALL initGraphicsVk( void PAL_CALL shutdownGraphicsVk(); PalResult PAL_CALL enumerateAdaptersVk( - Int32* count, + int32_t* count, PalAdapter** outAdapters); PalResult PAL_CALL getAdapterInfoVk( @@ -123,7 +123,7 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter); -Uint32 PAL_CALL getHighestSupportedShaderTargetVk( +uint32_t PAL_CALL getHighestSupportedShaderTargetVk( PalAdapter* adapter, PalShaderFormats shaderFormat); @@ -147,8 +147,8 @@ PalResult PAL_CALL waitDeviceVk(PalDevice* device); PalResult PAL_CALL allocateMemoryVk( PalDevice* device, PalMemoryType type, - Uint64 memoryMask, - Uint64 size, + uint64_t memoryMask, + uint64_t size, PalMemory** outMemory); void PAL_CALL freeMemoryVk( @@ -214,7 +214,7 @@ bool PAL_CALL canQueuePresentVk( PalResult PAL_CALL enumerateFormatsVk( PalAdapter* adapter, - Int32* count, + int32_t* count, PalFormatInfo* outFormats); bool PAL_CALL isFormatSupportedVk( @@ -251,12 +251,12 @@ PalResult PAL_CALL getImageMemoryRequirementsVk( PalResult PAL_CALL bindImageMemoryVk( PalImage* image, PalMemory* memory, - Uint64 offset); + uint64_t offset); PalResult PAL_CALL mapImageMemoryVk( PalImage* image, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr); void PAL_CALL unmapImageMemoryVk(PalImage* image); @@ -315,12 +315,12 @@ void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain); PalImage* PAL_CALL getSwapchainImageVk( PalSwapchain* swapchain, - Int32 index); + int32_t index); PalResult PAL_CALL getNextSwapchainImageVk( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32* outIndex); + uint32_t* outIndex); PalResult PAL_CALL presentSwapchainVk( PalSwapchain* swapchain, @@ -328,8 +328,8 @@ PalResult PAL_CALL presentSwapchainVk( PalResult PAL_CALL resizeSwapchainVk( PalSwapchain* swapchain, - Uint32 newWidth, - Uint32 newHeight); + uint32_t newWidth, + uint32_t newHeight); // ================================================== // Shader @@ -355,7 +355,7 @@ void PAL_CALL destroyFenceVk(PalFence* fence); PalResult PAL_CALL waitFenceVk( PalFence* fence, - Uint64 timeout); + uint64_t timeout); PalResult PAL_CALL resetFenceVk(PalFence* fence); @@ -374,17 +374,17 @@ void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore); PalResult PAL_CALL waitSemaphoreVk( PalSemaphore* semaphore, - Uint64 value, - Uint64 timeout); + uint64_t value, + uint64_t timeout); PalResult PAL_CALL signalSemaphoreVk( PalSemaphore* semaphore, PalQueue* queue, - Uint64 value); + uint64_t value); PalResult PAL_CALL getSemaphoreValueVk( PalSemaphore* semaphore, - Uint64* outValue); + uint64_t* outValue); // ================================================== // Command Pool And Buffer @@ -433,20 +433,20 @@ PalResult PAL_CALL cmdSetFragmentShadingRateVk( PalResult PAL_CALL cmdDrawMeshTasksVk( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 drawCount); + uint32_t drawCount); PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount); + uint32_t maxDrawCount); PalResult PAL_CALL cmdBuildAccelerationStructureVk( PalCommandBuffer* cmdBuffer, @@ -488,63 +488,63 @@ PalResult PAL_CALL cmdBindPipelineVk( PalResult PAL_CALL cmdSetViewportVk( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalViewport* viewports); PalResult PAL_CALL cmdSetScissorsVk( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalRect2D* scissors); PalResult PAL_CALL cmdBindVertexBuffersVk( PalCommandBuffer* cmdBuffer, - Uint32 firstSlot, - Uint32 count, + uint32_t firstSlot, + uint32_t count, PalBuffer** buffers, - Uint64* offsets); + uint64_t* offsets); PalResult PAL_CALL cmdBindIndexBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, + uint64_t offset, PalIndexType type); PalResult PAL_CALL cmdDrawVk( PalCommandBuffer* cmdBuffer, - Uint32 vertexCount, - Uint32 instanceCount, - Uint32 firstVertex, - Uint32 firstInstance); + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); PalResult PAL_CALL cmdDrawIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count); + uint32_t count); PalResult PAL_CALL cmdDrawIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount); + uint32_t maxDrawCount); PalResult PAL_CALL cmdDrawIndexedVk( PalCommandBuffer* cmdBuffer, - Uint32 indexCount, - Uint32 instanceCount, - Uint32 firstIndex, - Int32 vertexOffset, - Uint32 firstInstance); + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); PalResult PAL_CALL cmdDrawIndexedIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count); + uint32_t count); PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount); + uint32_t maxDrawCount); PalResult PAL_CALL cmdAccelerationStructureBarrierVk( PalCommandBuffer* cmdBuffer, @@ -567,18 +567,18 @@ PalResult PAL_CALL cmdBufferBarrierVk( PalResult PAL_CALL cmdDispatchVk( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); PalResult PAL_CALL cmdDispatchBaseVk( PalCommandBuffer* cmdBuffer, - Uint32 baseGroupX, - Uint32 baseGroupY, - Uint32 baseGroupZ, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); PalResult PAL_CALL cmdDispatchIndirectVk( PalCommandBuffer* cmdBuffer, @@ -587,28 +587,28 @@ PalResult PAL_CALL cmdDispatchIndirectVk( PalResult PAL_CALL cmdTraceRaysVk( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, - Uint32 raygenIndex, - Uint32 width, - Uint32 height, - Uint32 depth); + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth); PalResult PAL_CALL cmdTraceRaysIndirectVk( PalCommandBuffer* cmdBuffer, - Uint32 raygenIndex, + uint32_t raygenIndex, PalShaderBindingTable* sbt, PalBuffer* buffer); PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, - Uint32 setIndex, + uint32_t setIndex, PalDescriptorSet* set); PalResult PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, - Uint32 shaderStageCount, + uint32_t shaderStageCount, PalShaderStage* shaderStages, - Uint32 offset, - Uint32 size, + uint32_t offset, + uint32_t size, const void* value); PalResult PAL_CALL cmdSetCullModeVk( @@ -672,22 +672,22 @@ PalResult PAL_CALL getBufferMemoryRequirementsVk( PalResult PAL_CALL computeInstanceBufferRequirementsVk( PalDevice* device, - Uint32 instanceCount, - Uint64* outSize); + uint32_t instanceCount, + uint64_t* outSize); PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, - Uint32* outBufferRowLength, - Uint32* outBufferImageHeight, - Uint64* outSize); + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize); PalResult PAL_CALL writeToInstanceBufferVk( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, - Uint32 instanceCount); + uint32_t instanceCount); PalResult PAL_CALL writeToImageCopyStagingBufferVk( PalDevice* device, @@ -699,12 +699,12 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( PalResult PAL_CALL bindBufferMemoryVk( PalBuffer* buffer, PalMemory* memory, - Uint64 offset); + uint64_t offset); PalResult PAL_CALL mapBufferMemoryVk( PalBuffer* buffer, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr); void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer); @@ -739,7 +739,7 @@ PalResult PAL_CALL allocateDescriptorSetVk( PalResult PAL_CALL updateDescriptorSetVk( PalDevice* device, - Uint32 count, + uint32_t count, PalDescriptorSetWriteInfo* infos); // ================================================== @@ -787,7 +787,7 @@ void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt); PalResult PAL_CALL updateShaderBindingTableVk( PalShaderBindingTable* sbt, - Uint32 count, + uint32_t count, PalShaderBindingTableRecordInfo* infos); static PalGraphicsBackend s_VkBackend = { @@ -989,7 +989,7 @@ PalResult PAL_CALL initGraphicsD3D12( void PAL_CALL shutdownGraphicsD3D12(); PalResult PAL_CALL enumerateAdaptersD3D12( - Int32* count, + int32_t* count, PalAdapter** outAdapters); PalResult PAL_CALL getAdapterInfoD3D12( @@ -1002,7 +1002,7 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); -Uint32 PAL_CALL getHighestSupportedShaderTargetD3D12( +uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( PalAdapter* adapter, PalShaderFormats shaderFormat); @@ -1026,8 +1026,8 @@ PalResult PAL_CALL waitDeviceD3D12(PalDevice* device); PalResult PAL_CALL allocateMemoryD3D12( PalDevice* device, PalMemoryType type, - Uint64 memoryMask, - Uint64 size, + uint64_t memoryMask, + uint64_t size, PalMemory** outMemory); void PAL_CALL freeMemoryD3D12( @@ -1093,7 +1093,7 @@ bool PAL_CALL canQueuePresentD3D12( PalResult PAL_CALL enumerateFormatsD3D12( PalAdapter* adapter, - Int32* count, + int32_t* count, PalFormatInfo* outFormats); bool PAL_CALL isFormatSupportedD3D12( @@ -1130,12 +1130,12 @@ PalResult PAL_CALL getImageMemoryRequirementsD3D12( PalResult PAL_CALL bindImageMemoryD3D12( PalImage* image, PalMemory* memory, - Uint64 offset); + uint64_t offset); PalResult PAL_CALL mapImageMemoryD3D12( PalImage* image, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr); void PAL_CALL unmapImageMemoryD3D12(PalImage* image); @@ -1194,12 +1194,12 @@ void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain); PalImage* PAL_CALL getSwapchainImageD3D12( PalSwapchain* swapchain, - Int32 index); + int32_t index); PalResult PAL_CALL getNextSwapchainImageD3D12( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32* outIndex); + uint32_t* outIndex); PalResult PAL_CALL presentSwapchainD3D12( PalSwapchain* swapchain, @@ -1207,8 +1207,8 @@ PalResult PAL_CALL presentSwapchainD3D12( PalResult PAL_CALL resizeSwapchainD3D12( PalSwapchain* swapchain, - Uint32 newWidth, - Uint32 newHeight); + uint32_t newWidth, + uint32_t newHeight); // ================================================== // Shader @@ -1234,7 +1234,7 @@ void PAL_CALL destroyFenceD3D12(PalFence* fence); PalResult PAL_CALL waitFenceD3D12( PalFence* fence, - Uint64 timeout); + uint64_t timeout); PalResult PAL_CALL resetFenceD3D12(PalFence* fence); @@ -1253,17 +1253,17 @@ void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); PalResult PAL_CALL waitSemaphoreD3D12( PalSemaphore* semaphore, - Uint64 value, - Uint64 timeout); + uint64_t value, + uint64_t timeout); PalResult PAL_CALL signalSemaphoreD3D12( PalSemaphore* semaphore, PalQueue* queue, - Uint64 value); + uint64_t value); PalResult PAL_CALL getSemaphoreValueD3D12( PalSemaphore* semaphore, - Uint64* outValue); + uint64_t* outValue); // ================================================== // Command Pool And Buffer @@ -1312,20 +1312,20 @@ PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( PalResult PAL_CALL cmdDrawMeshTasksD3D12( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 drawCount); + uint32_t drawCount); PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount); + uint32_t maxDrawCount); PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( PalCommandBuffer* cmdBuffer, @@ -1367,63 +1367,63 @@ PalResult PAL_CALL cmdBindPipelineD3D12( PalResult PAL_CALL cmdSetViewportD3D12( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalViewport* viewports); PalResult PAL_CALL cmdSetScissorsD3D12( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalRect2D* scissors); PalResult PAL_CALL cmdBindVertexBuffersD3D12( PalCommandBuffer* cmdBuffer, - Uint32 firstSlot, - Uint32 count, + uint32_t firstSlot, + uint32_t count, PalBuffer** buffers, - Uint64* offsets); + uint64_t* offsets); PalResult PAL_CALL cmdBindIndexBufferD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, + uint64_t offset, PalIndexType type); PalResult PAL_CALL cmdDrawD3D12( PalCommandBuffer* cmdBuffer, - Uint32 vertexCount, - Uint32 instanceCount, - Uint32 firstVertex, - Uint32 firstInstance); + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); PalResult PAL_CALL cmdDrawIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count); + uint32_t count); PalResult PAL_CALL cmdDrawIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount); + uint32_t maxDrawCount); PalResult PAL_CALL cmdDrawIndexedD3D12( PalCommandBuffer* cmdBuffer, - Uint32 indexCount, - Uint32 instanceCount, - Uint32 firstIndex, - Int32 vertexOffset, - Uint32 firstInstance); + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count); + uint32_t count); PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount); + uint32_t maxDrawCount); PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( PalCommandBuffer* cmdBuffer, @@ -1446,18 +1446,18 @@ PalResult PAL_CALL cmdBufferBarrierD3D12( PalResult PAL_CALL cmdDispatchD3D12( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); PalResult PAL_CALL cmdDispatchBaseD3D12( PalCommandBuffer* cmdBuffer, - Uint32 baseGroupX, - Uint32 baseGroupY, - Uint32 baseGroupZ, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ); + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); PalResult PAL_CALL cmdDispatchIndirectD3D12( PalCommandBuffer* cmdBuffer, @@ -1466,28 +1466,28 @@ PalResult PAL_CALL cmdDispatchIndirectD3D12( PalResult PAL_CALL cmdTraceRaysD3D12( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, - Uint32 raygenIndex, - Uint32 width, - Uint32 height, - Uint32 depth); + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth); PalResult PAL_CALL cmdTraceRaysIndirectD3D12( PalCommandBuffer* cmdBuffer, - Uint32 raygenIndex, + uint32_t raygenIndex, PalShaderBindingTable* sbt, PalBuffer* buffer); PalResult PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, - Uint32 setIndex, + uint32_t setIndex, PalDescriptorSet* set); PalResult PAL_CALL cmdPushConstantsD3D12( PalCommandBuffer* cmdBuffer, - Uint32 shaderStageCount, + uint32_t shaderStageCount, PalShaderStage* shaderStages, - Uint32 offset, - Uint32 size, + uint32_t offset, + uint32_t size, const void* value); PalResult PAL_CALL cmdSetCullModeD3D12( @@ -1551,22 +1551,22 @@ PalResult PAL_CALL getBufferMemoryRequirementsD3D12( PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( PalDevice* device, - Uint32 instanceCount, - Uint64* outSize); + uint32_t instanceCount, + uint64_t* outSize); PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, - Uint32* outBufferRowLength, - Uint32* outBufferImageHeight, - Uint64* outSize); + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize); PalResult PAL_CALL writeToInstanceBufferD3D12( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, - Uint32 instanceCount); + uint32_t instanceCount); PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( PalDevice* device, @@ -1578,12 +1578,12 @@ PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( PalResult PAL_CALL bindBufferMemoryD3D12( PalBuffer* buffer, PalMemory* memory, - Uint64 offset); + uint64_t offset); PalResult PAL_CALL mapBufferMemoryD3D12( PalBuffer* buffer, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr); void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer); @@ -1618,7 +1618,7 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( PalResult PAL_CALL updateDescriptorSetD3D12( PalDevice* device, - Uint32 count, + uint32_t count, PalDescriptorSetWriteInfo* infos); // ================================================== @@ -1666,7 +1666,7 @@ void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); PalResult PAL_CALL updateShaderBindingTableD3D12( PalShaderBindingTable* sbt, - Uint32 count, + uint32_t count, PalShaderBindingTableRecordInfo* infos); static PalGraphicsBackend s_D3D12Backend = { @@ -2168,7 +2168,7 @@ void PAL_CALL palShutdownGraphics() // ================================================== PalResult PAL_CALL palEnumerateAdapters( - Int32* count, + int32_t* count, PalAdapter** outAdapters) { // enumerate all adapters for both custom and PAL backends @@ -2265,7 +2265,7 @@ PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) return adapter->backend->getAdapterFeatures(adapter); } -Uint32 PAL_CALL palGetHighestSupportedShaderTarget( +uint32_t PAL_CALL palGetHighestSupportedShaderTarget( PalAdapter* adapter, PalShaderFormats shaderFormat) { @@ -2314,8 +2314,8 @@ void PAL_CALL palDestroyDevice(PalDevice* device) PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, - Uint64 memoryMask, - Uint64 size, + uint64_t memoryMask, + uint64_t size, PalMemory** outMemory) { if (!s_Graphics.initialized) { @@ -2527,7 +2527,7 @@ PalResult PAL_CALL palWaitQueue(PalQueue* queue) PalResult PAL_CALL palEnumerateFormats( PalAdapter* adapter, - Int32* count, + int32_t* count, PalFormatInfo* outFormats) { if (!s_Graphics.initialized) { @@ -2647,7 +2647,7 @@ PalResult PAL_CALL palGetImageMemoryRequirements( PalResult PAL_CALL palBindImageMemory( PalImage* image, PalMemory* memory, - Uint64 offset) + uint64_t offset) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2662,8 +2662,8 @@ PalResult PAL_CALL palBindImageMemory( PalResult PAL_CALL palMapImageMemory( PalImage* image, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr) { if (!s_Graphics.initialized) { @@ -2855,7 +2855,7 @@ void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, - Int32 index) + int32_t index) { if (!s_Graphics.initialized || !swapchain || index < 0) { return nullptr; @@ -2867,7 +2867,7 @@ PalImage* PAL_CALL palGetSwapchainImage( PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32* outIndex) + uint32_t* outIndex) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2897,8 +2897,8 @@ PalResult PAL_CALL palPresentSwapchain( PalResult PAL_CALL palResizeSwapchain( PalSwapchain* swapchain, - Uint32 newWidth, - Uint32 newHeight) + uint32_t newWidth, + uint32_t newHeight) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -2985,7 +2985,7 @@ void PAL_CALL palDestroyFence(PalFence* fence) PalResult PAL_CALL palWaitFence( PalFence* fence, - Uint64 timeout) + uint64_t timeout) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3057,8 +3057,8 @@ void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore) PalResult PAL_CALL palWaitSemaphore( PalSemaphore* semaphore, - Uint64 value, - Uint64 timeout) + uint64_t value, + uint64_t timeout) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3074,7 +3074,7 @@ PalResult PAL_CALL palWaitSemaphore( PalResult PAL_CALL palSignalSemaphore( PalSemaphore* semaphore, PalQueue* queue, - Uint64 value) + uint64_t value) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3089,7 +3089,7 @@ PalResult PAL_CALL palSignalSemaphore( PalResult PAL_CALL palGetSemaphoreValue( PalSemaphore* semaphore, - Uint64* outValue) + uint64_t* outValue) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3276,9 +3276,9 @@ PalResult PAL_CALL palCmdSetFragmentShadingRate( PalResult PAL_CALL palCmdDrawMeshTasks( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ) + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3294,7 +3294,7 @@ PalResult PAL_CALL palCmdDrawMeshTasks( PalResult PAL_CALL palCmdDrawMeshTasksIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 drawCount) + uint32_t drawCount) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3311,7 +3311,7 @@ PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount) + uint32_t maxDrawCount) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3472,7 +3472,7 @@ PalResult PAL_CALL palCmdBindPipeline( PalResult PAL_CALL palCmdSetViewport( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalViewport* viewports) { if (!s_Graphics.initialized) { @@ -3488,7 +3488,7 @@ PalResult PAL_CALL palCmdSetViewport( PalResult PAL_CALL palCmdSetScissors( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalRect2D* scissors) { if (!s_Graphics.initialized) { @@ -3504,10 +3504,10 @@ PalResult PAL_CALL palCmdSetScissors( PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, - Uint32 firstSlot, - Uint32 count, + uint32_t firstSlot, + uint32_t count, PalBuffer** buffers, - Uint64* offsets) + uint64_t* offsets) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3528,7 +3528,7 @@ PalResult PAL_CALL palCmdBindVertexBuffers( PalResult PAL_CALL palCmdBindIndexBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, + uint64_t offset, PalIndexType type) { if (!s_Graphics.initialized) { @@ -3544,10 +3544,10 @@ PalResult PAL_CALL palCmdBindIndexBuffer( PalResult PAL_CALL palCmdDraw( PalCommandBuffer* cmdBuffer, - Uint32 vertexCount, - Uint32 instanceCount, - Uint32 firstVertex, - Uint32 firstInstance) + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3564,7 +3564,7 @@ PalResult PAL_CALL palCmdDraw( PalResult PAL_CALL palCmdDrawIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count) + uint32_t count) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3581,7 +3581,7 @@ PalResult PAL_CALL palCmdDrawIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount) + uint32_t maxDrawCount) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3600,11 +3600,11 @@ PalResult PAL_CALL palCmdDrawIndirectCount( PalResult PAL_CALL palCmdDrawIndexed( PalCommandBuffer* cmdBuffer, - Uint32 indexCount, - Uint32 instanceCount, - Uint32 firstIndex, - Int32 vertexOffset, - Uint32 firstInstance) + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3626,7 +3626,7 @@ PalResult PAL_CALL palCmdDrawIndexed( PalResult PAL_CALL palCmdDrawIndexedIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count) + uint32_t count) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3643,7 +3643,7 @@ PalResult PAL_CALL palCmdDrawIndexedIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount) + uint32_t maxDrawCount) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3724,9 +3724,9 @@ PalResult PAL_CALL palCmdBufferBarrier( PalResult PAL_CALL palCmdDispatch( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ) + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3741,12 +3741,12 @@ PalResult PAL_CALL palCmdDispatch( PalResult PAL_CALL palCmdDispatchBase( PalCommandBuffer* cmdBuffer, - Uint32 baseGroupX, - Uint32 baseGroupY, - Uint32 baseGroupZ, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ) + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3784,10 +3784,10 @@ PalResult PAL_CALL palCmdDispatchIndirect( PalResult PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, - Uint32 raygenIndex, - Uint32 width, - Uint32 height, - Uint32 depth) + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3802,7 +3802,7 @@ PalResult PAL_CALL palCmdTraceRays( PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, - Uint32 raygenIndex, + uint32_t raygenIndex, PalShaderBindingTable* sbt, PalBuffer* buffer) { @@ -3819,7 +3819,7 @@ PalResult PAL_CALL palCmdTraceRaysIndirect( PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, - Uint32 setIndex, + uint32_t setIndex, PalDescriptorSet* set) { if (!s_Graphics.initialized) { @@ -3838,10 +3838,10 @@ PalResult PAL_CALL palCmdBindDescriptorSet( PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, - Uint32 shaderStageCount, + uint32_t shaderStageCount, PalShaderStage* shaderStages, - Uint32 offset, - Uint32 size, + uint32_t offset, + uint32_t size, const void* value) { if (!s_Graphics.initialized) { @@ -4072,8 +4072,8 @@ PalResult PAL_CALL palGetBufferMemoryRequirements( PalResult PAL_CALL palComputeInstanceBufferRequirements( PalDevice* device, - Uint32 instanceCount, - Uint64* outSize) + uint32_t instanceCount, + uint64_t* outSize) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -4093,9 +4093,9 @@ PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, - Uint32* outBufferRowLength, - Uint32* outBufferImageHeight, - Uint64* outSize) + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -4126,7 +4126,7 @@ PalResult PAL_CALL palWriteToInstanceBuffer( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, - Uint32 instanceCount) + uint32_t instanceCount) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -4174,7 +4174,7 @@ PalResult PAL_CALL palWriteToImageCopyStagingBuffer( PalResult PAL_CALL palBindBufferMemory( PalBuffer* buffer, PalMemory* memory, - Uint64 offset) + uint64_t offset) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -4189,8 +4189,8 @@ PalResult PAL_CALL palBindBufferMemory( PalResult PAL_CALL palMapBufferMemory( PalBuffer* buffer, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr) { if (!s_Graphics.initialized) { @@ -4332,7 +4332,7 @@ PalResult PAL_CALL palAllocateDescriptorSet( PalResult PAL_CALL palUpdateDescriptorSet( PalDevice* device, - Uint32 count, + uint32_t count, PalDescriptorSetWriteInfo* infos) { if (!s_Graphics.initialized) { @@ -4518,7 +4518,7 @@ void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt) PalResult PAL_CALL palUpdateShaderBindingTable( PalShaderBindingTable* sbt, - Uint32 count, + uint32_t count, PalShaderBindingTableRecordInfo* infos) { if (!s_Graphics.initialized) { @@ -4542,7 +4542,7 @@ PalResult PAL_CALL palUpdateShaderBindingTable( bool PAL_CALL palBuildWorkGroupInfo( const PalWorkGroupBuildData* data, - Int32* count, + int32_t* count, PalWorkGroupInfo* infos) { if (!data) { @@ -4553,10 +4553,10 @@ bool PAL_CALL palBuildWorkGroupInfo( return false; } - Uint32 workGroupCount[3]; - Uint32 groupInfoCount[3]; + uint32_t workGroupCount[3]; + uint32_t groupInfoCount[3]; for (int i = 0; i < 3; i++) { - Uint32 tmp = _ceil(data->workCount[i], data->workGroupSize[i]); + uint32_t tmp = _ceil(data->workCount[i], data->workGroupSize[i]); workGroupCount[i] = tmp; groupInfoCount[i] = _ceil(tmp, data->workGroupCount[i]); } @@ -4571,7 +4571,7 @@ bool PAL_CALL palBuildWorkGroupInfo( for (int i = 0; i < *count; i++) { PalWorkGroupInfo* buildInfo = &infos[i]; // find index - Uint32 index[3]; + uint32_t index[3]; index[0] = i % groupInfoCount[0]; index[1] = (i / groupInfoCount[0]) % groupInfoCount[1]; index[2] = i / (groupInfoCount[0] * groupInfoCount[1]); @@ -4582,7 +4582,7 @@ bool PAL_CALL palBuildWorkGroupInfo( buildInfo->workGroupBase[j] = index[j] * data->workGroupCount[j]; buildInfo->workGroupBase[j] = index[j] * data->workGroupCount[j]; - Uint32 tmp = workGroupCount[j] - buildInfo->workGroupBase[j]; + uint32_t tmp = workGroupCount[j] - buildInfo->workGroupBase[j]; buildInfo->workGroupCount[j] = _min(data->workGroupCount[j], tmp); } } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index bc4d6d02..de27977f 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -348,7 +348,7 @@ typedef struct { } Vulkan; typedef struct { - Int32 familyIndex; + int32_t familyIndex; VkPhysicalDevice phyDevice; VkQueue handle; VkQueueFlags usages; @@ -357,17 +357,17 @@ typedef struct { // Limits we must enforce ourselves typedef struct { - Uint32 maxPayloadSize; + uint32_t maxPayloadSize; } DeviceLimits; typedef struct { const PalGraphicsBackend* backend; PalAdapterFeatures features; - Int32 phyQueueCount; - Int32 phyQueueIndex; - Int32 queueFamilyCount; - Uint32 memoryClassMask[3]; + int32_t phyQueueCount; + int32_t phyQueueIndex; + int32_t queueFamilyCount; + uint32_t memoryClassMask[3]; VkPhysicalDevice phyDevice; VkDevice handle; PhysicalQueue* phyQueues; @@ -454,7 +454,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 layerCount; + uint32_t layerCount; Device* device; Image* image; VkImageView handle; @@ -470,7 +470,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 imageCount; + uint32_t imageCount; Device* device; Queue* queue; VkSwapchainKHR handle; @@ -478,7 +478,7 @@ typedef struct { } Swapchain; typedef struct { - Uint32 patchControlPoints; + uint32_t patchControlPoints; VkShaderStageFlagBits stage; char entryName[PAL_SHADER_ENTRY_NAME_SIZE]; } ShaderEntry; @@ -486,7 +486,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - Uint32 entryCount; + uint32_t entryCount; ShaderEntry* entries; Device* device; VkShaderModule handle; @@ -585,14 +585,14 @@ typedef struct { } PipelineLayout; typedef struct { - Uint32 raygenCount; - Uint32 raygenDataSize; - Uint32 missCount; - Uint32 missDataSize; - Uint32 hitCount; - Uint32 hitDataSize; - Uint32 callableCount; - Uint32 callableDataSize; + uint32_t raygenCount; + uint32_t raygenDataSize; + uint32_t missCount; + uint32_t missDataSize; + uint32_t hitCount; + uint32_t hitDataSize; + uint32_t callableCount; + uint32_t callableDataSize; } ShaderBindingTableInfo; typedef struct { @@ -606,8 +606,8 @@ typedef struct { } Pipeline; typedef struct { - Uint32 startIndex; - Uint32 offset; + uint32_t startIndex; + uint32_t offset; VkStridedDeviceAddressRegionKHR region; } AddressRegion; @@ -615,8 +615,8 @@ typedef struct { const PalGraphicsBackend* backend; bool isDirty; - Uint32 stagingBufferSize; - Uint32 handleSize; + uint32_t stagingBufferSize; + uint32_t handleSize; Device* device; VkBuffer buffer; VkBuffer stagingBuffer; @@ -1522,7 +1522,7 @@ static VkBufferUsageFlags bufferUsageToVk(PalBufferUsages usages) return flags; } -static Uint32 getVertexTypeSizeVk(PalVertexType type) +static uint32_t getVertexTypeSizeVk(PalVertexType type) { // count x sizeof type returned as size switch (type) { @@ -1869,7 +1869,7 @@ static VkBorderColor borderColorToVk(PalBorderColor color) } static Barrier barrierToVk( - Uint32 stageCount, + uint32_t stageCount, PalUsageState state, PalShaderStage* shaderStages) { @@ -2169,8 +2169,8 @@ static VkShaderStageFlags shaderStageToVK(PalShaderStage stage) static inline void* alignedRealloc( void* memory, - Uint64 size, - Uint64 alignment) + uint64_t size, + uint64_t alignment) { #if defined(_MSC_VER) || defined(__MINGW32__) return _aligned_realloc(memory, size, alignment); @@ -2269,12 +2269,12 @@ VkBool32 VKAPI_CALL debugCallbackVk( return VK_FALSE; } -static Uint32 findBestMemoryIndexVk( +static uint32_t findBestMemoryIndexVk( VkPhysicalDevice phyDevice, - Uint32 memoryMask) + uint32_t memoryMask) { int bestScore = -1; - Uint32 bestIndex = UINT32_MAX; + uint32_t bestIndex = UINT32_MAX; VkPhysicalDeviceMemoryProperties memProps = {0}; s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); @@ -2312,31 +2312,31 @@ static Uint32 findBestMemoryIndexVk( return bestIndex; } -static inline Uint32 alignVk( - Uint32 value, - Uint32 alignment) +static inline uint32_t alignVk( + uint32_t value, + uint32_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } -static inline Uint32 maxVk( - Uint32 a, - Uint32 b) +static inline uint32_t maxVk( + uint32_t a, + uint32_t b) { return (a > b) ? a : b; } -static inline Uint32 minVk( - Uint32 a, - Uint32 b) +static inline uint32_t minVk( + uint32_t a, + uint32_t b) { return (a < b) ? a : b; } static void fillBuildInfoVk( - Uint32 count, + uint32_t count, PalAccelerationStructureBuildInfo* info, - Uint32* maxPrimities, + uint32_t* maxPrimities, VkAccelerationStructureGeometryKHR* geometries, VkAccelerationStructureKHR srcAs, VkAccelerationStructureKHR dstAs, @@ -2476,7 +2476,7 @@ static void fillBuildInfoVk( buildInfo->scratchData = scratchData; } -static Uint32 getFormatSizeVk(PalFormat format) +static uint32_t getFormatSizeVk(PalFormat format) { switch (format) { case PAL_FORMAT_R8_UNORM: @@ -3024,7 +3024,7 @@ PalResult PAL_CALL initGraphicsVk( // get version bool versionFallback = false; - Uint32 version = 0; + uint32_t version = 0; if (s_Vk.enumerateInstanceVersion) { s_Vk.enumerateInstanceVersion(&version); if (version <= VK_API_VERSION_1_0) { @@ -3033,7 +3033,7 @@ PalResult PAL_CALL initGraphicsVk( } VkResult result; - Uint32 layerCount = 0; + uint32_t layerCount = 0; bool hasValidationLayer = false; s_Vk.messenger = nullptr; s_Vk.allocator = allocator; @@ -3093,7 +3093,7 @@ PalResult PAL_CALL initGraphicsVk( } // extensions - Uint32 extCount = 0; + uint32_t extCount = 0; const char* extensions[8]; result = s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, nullptr); if (result != VK_SUCCESS) { @@ -3328,7 +3328,7 @@ void PAL_CALL shutdownGraphicsVk() } PalResult PAL_CALL enumerateAdaptersVk( - Int32* count, + int32_t* count, PalAdapter** outAdapters) { int deviceCount = 0; @@ -3502,7 +3502,7 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( PalComputeCapabilities* computeCaps = &caps->computeCaps; // get supported queue commands - Uint32 count = 0; + uint32_t count = 0; s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &count, nullptr); VkQueueFamilyProperties* queueProps = nullptr; @@ -3549,13 +3549,13 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( imageCaps->maxArrayLayers = limits->maxImageArrayLayers; // vulkan does not give this but we calculate from the max width and width - Uint32 a = imageCaps->maxWidth; - Uint32 b = imageCaps->maxHeight; - Uint32 c = imageCaps->maxDepth; + uint32_t a = imageCaps->maxWidth; + uint32_t b = imageCaps->maxHeight; + uint32_t c = imageCaps->maxDepth; - Uint32 tmp = a > b ? a : b; - Uint32 size = tmp > c ? tmp : c; - Uint32 levels = 0; + uint32_t tmp = a > b ? a : b; + uint32_t size = tmp > c ? tmp : c; + uint32_t levels = 0; while (size > 0) { // divide by two size = size / 2; @@ -3604,7 +3604,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) { VkResult result; PalAdapterFeatures adapterFeatures = 0; - Uint32 extensionCount = 0; + uint32_t extensionCount = 0; VkPhysicalDeviceProperties props = {0}; Adapter* vkAdapter = (Adapter*)adapter; @@ -3965,7 +3965,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) return adapterFeatures; } -Uint32 PAL_CALL getHighestSupportedShaderTargetVk( +uint32_t PAL_CALL getHighestSupportedShaderTargetVk( PalAdapter* adapter, PalShaderFormats shaderFormat) { @@ -4003,8 +4003,8 @@ PalResult PAL_CALL createDeviceVk( PalDevice** outDevice) { float priority = 1.0f; - Uint32 phyQueueCount = 0; - Uint32 queueFamilyCount = 0; + uint32_t phyQueueCount = 0; + uint32_t queueFamilyCount = 0; VkResult result = VK_SUCCESS; Device* device = nullptr; VkPhysicalDeviceProperties props = {0}; @@ -4017,8 +4017,8 @@ PalResult PAL_CALL createDeviceVk( VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueFamilyCount, nullptr); - Uint32 queueFamilySize = sizeof(VkQueueFamilyProperties) * queueFamilyCount; - Uint32 queueCreateInfosSize = sizeof(VkDeviceQueueCreateInfo) * queueFamilyCount; + uint32_t queueFamilySize = sizeof(VkQueueFamilyProperties) * queueFamilyCount; + uint32_t queueCreateInfosSize = sizeof(VkDeviceQueueCreateInfo) * queueFamilyCount; queueFamilyProps = palAllocate(s_Vk.allocator, queueFamilySize, 0); queueCreateInfos = palAllocate(s_Vk.allocator, queueCreateInfosSize, 0); @@ -4377,11 +4377,11 @@ PalResult PAL_CALL createDeviceVk( VkPhysicalDeviceMemoryProperties memProps = {0}; s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); - memset(device->memoryClassMask, 0, sizeof(Uint32) * 3); + memset(device->memoryClassMask, 0, sizeof(uint32_t) * 3); for (int i = 0; i < memProps.memoryTypeCount; i++) { VkMemoryPropertyFlags flags = memProps.memoryTypes[i].propertyFlags; - Uint32 bit = (1u << i); + uint32_t bit = (1u << i); if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) && !(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] |= bit; @@ -4740,8 +4740,8 @@ void PAL_CALL destroyDeviceVk(PalDevice* device) PalResult PAL_CALL allocateMemoryVk( PalDevice* device, PalMemoryType type, - Uint64 memoryMask, - Uint64 size, + uint64_t memoryMask, + uint64_t size, PalMemory** outMemory) { VkResult result; @@ -4757,16 +4757,16 @@ PalResult PAL_CALL allocateMemoryVk( return PAL_RESULT_NULL_POINTER; } - Uint32 memoryTypeMask = 0; - Uint32 usages = 0; + uint32_t memoryTypeMask = 0; + uint32_t usages = 0; palUnpackUint32(memoryMask, &memoryTypeMask, &usages); - Uint32 memoryClassMask = vkDevice->memoryClassMask[type] & memoryTypeMask; + uint32_t memoryClassMask = vkDevice->memoryClassMask[type] & memoryTypeMask; if (memoryClassMask == 0) { return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; } // pick an index using the scoring system - Uint32 memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, memoryClassMask); + uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, memoryClassMask); if (memoryIndex == UINT32_MAX) { return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; } @@ -5118,8 +5118,8 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( caps->maxPerStageUniformBuffers = props.maxPerStageDescriptorUpdateAfterBindUniformBuffers; caps->maxPerSetUniformBuffers = props.maxDescriptorSetUpdateAfterBindUniformBuffers; - Uint32 tmp = accProps.maxPerStageDescriptorUpdateAfterBindAccelerationStructures; - Uint32 tmp2 = accProps.maxDescriptorSetUpdateAfterBindAccelerationStructures; + uint32_t tmp = accProps.maxPerStageDescriptorUpdateAfterBindAccelerationStructures; + uint32_t tmp2 = accProps.maxDescriptorSetUpdateAfterBindAccelerationStructures; caps->maxPerStageAccelerationStructure = tmp; caps->maxPerSetAccelerationStructure = tmp2; @@ -5266,10 +5266,10 @@ bool PAL_CALL canQueuePresentVk( PalResult PAL_CALL enumerateFormatsVk( PalAdapter* adapter, - Int32* count, + int32_t* count, PalFormatInfo* outFormats) { - Int32 fmtCount = 0; + int32_t fmtCount = 0; Adapter* vkAdapter = (Adapter*)adapter; VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; VkFormatProperties props = {0}; @@ -5467,8 +5467,8 @@ PalResult PAL_CALL getImageMemoryRequirementsVk( Device* device = vkImage->device; VkMemoryRequirements memReq = {0}; s_Vk.getImageMemoryRequirements(device->handle, vkImage->handle, &memReq); - requirements->alignment = (Uint64)memReq.alignment; - requirements->size = (Uint64)memReq.size; + requirements->alignment = (uint64_t)memReq.alignment; + requirements->size = (uint64_t)memReq.size; requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, 0); requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; @@ -5485,7 +5485,7 @@ PalResult PAL_CALL getImageMemoryRequirementsVk( PalResult PAL_CALL bindImageMemoryVk( PalImage* image, PalMemory* memory, - Uint64 offset) + uint64_t offset) { Image* vkImage = (Image*)image; if (vkImage->belongsToSwapchain) { @@ -5504,8 +5504,8 @@ PalResult PAL_CALL bindImageMemoryVk( PalResult PAL_CALL mapImageMemoryVk( PalImage* image, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr) { VkResult result; @@ -5726,7 +5726,7 @@ PalResult PAL_CALL createSurfaceVk( VkXlibSurfaceCreateInfoKHR cInfo = {0}; cInfo.dpy = window->display; - cInfo.window = (Window)(UintPtr)(window->window); + cInfo.window = (Window)(uintptr_t)(window->window); cInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; VkSurfaceKHR tmp = nullptr; @@ -5777,8 +5777,8 @@ PalResult PAL_CALL getSurfaceCapabilitiesVk( PalSurface* surface, PalSurfaceCapabilities* caps) { - Int32 formatCount = 0; - Int32 modeCount = 0; + int32_t formatCount = 0; + int32_t modeCount = 0; Surface* vkSurface = (Surface*)surface; VkSurfaceFormatKHR* formats = nullptr; VkPresentModeKHR* modes = nullptr; @@ -5986,7 +5986,7 @@ PalResult PAL_CALL createSwapchainVk( } // get and cache all images - Int32 count = 0; + int32_t count = 0; result = vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, nullptr); swapchain->images = palAllocate(s_Vk.allocator, sizeof(Image) * count, 0); @@ -6038,7 +6038,7 @@ void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain) PalImage* PAL_CALL getSwapchainImageVk( PalSwapchain* swapchain, - Int32 index) + int32_t index) { Swapchain* vkSwapchain = (Swapchain*)swapchain; if (index > vkSwapchain->imageCount) { @@ -6050,11 +6050,11 @@ PalImage* PAL_CALL getSwapchainImageVk( PalResult PAL_CALL getNextSwapchainImageVk( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, - Uint32* outIndex) + uint32_t* outIndex) { VkResult result; - Uint32 index = 0; - Uint64 timeInNanoseconds = 0; + uint32_t index = 0; + uint64_t timeInNanoseconds = 0; VkFence fenceHandle = nullptr; VkSemaphore semaphoreHandle = nullptr; Swapchain* vkSwapchain = (Swapchain*)swapchain; @@ -6098,7 +6098,7 @@ PalResult PAL_CALL presentSwapchainVk( PalSwapchainPresentInfo* info) { Swapchain* vkSwapchain = (Swapchain*)swapchain; - Int32 semaphoreCount = 0; + int32_t semaphoreCount = 0; VkSemaphore semaphoreHandle = nullptr; if (info->waitSemaphore) { Semaphore* vkSemaphore = (Semaphore*)info->waitSemaphore; @@ -6125,8 +6125,8 @@ PalResult PAL_CALL presentSwapchainVk( PalResult PAL_CALL resizeSwapchainVk( PalSwapchain* swapchain, - Uint32 newWidth, - Uint32 newHeight) + uint32_t newWidth, + uint32_t newHeight) { VkResult result; Swapchain* vkSwapchain = (Swapchain*)swapchain; @@ -6150,7 +6150,7 @@ PalResult PAL_CALL resizeSwapchainVk( return resultFromVk(result); } - Uint32 count = vkSwapchain->imageCount; + uint32_t count = vkSwapchain->imageCount; images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); if (!images) { return PAL_RESULT_OUT_OF_MEMORY; @@ -6237,7 +6237,7 @@ PalResult PAL_CALL createShaderVk( VkShaderModuleCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = info->bytecodeSize; - createInfo.pCode = (const Uint32*)info->bytecode; + createInfo.pCode = (const uint32_t*)info->bytecode; result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); if (result != VK_SUCCESS) { @@ -6305,11 +6305,11 @@ void PAL_CALL destroyFenceVk(PalFence* fence) PalResult PAL_CALL waitFenceVk( PalFence* fence, - Uint64 timeout) + uint64_t timeout) { Fence* vkFence = (Fence*)fence; VkResult result; - Uint64 timeInNanoseconds = 0; + uint64_t timeInNanoseconds = 0; if (timeout) { if (timeout == PAL_INFINITE) { @@ -6417,11 +6417,11 @@ void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore) PalResult PAL_CALL waitSemaphoreVk( PalSemaphore* semaphore, - Uint64 value, - Uint64 timeout) + uint64_t value, + uint64_t timeout) { VkResult result; - Uint64 timeInNanoseconds = 0; + uint64_t timeInNanoseconds = 0; Semaphore* vkSemaphore = (Semaphore*)semaphore; if (!vkSemaphore->isTimeline) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -6456,7 +6456,7 @@ PalResult PAL_CALL waitSemaphoreVk( PalResult PAL_CALL signalSemaphoreVk( PalSemaphore* semaphore, PalQueue* queue, - Uint64 value) + uint64_t value) { VkResult result; Semaphore* vkSemaphore = (Semaphore*)semaphore; @@ -6479,7 +6479,7 @@ PalResult PAL_CALL signalSemaphoreVk( PalResult PAL_CALL getSemaphoreValueVk( PalSemaphore* semaphore, - Uint64* outValue) + uint64_t* outValue) { Semaphore* vkSemaphore = (Semaphore*)semaphore; if (!vkSemaphore->isTimeline) { @@ -6609,8 +6609,8 @@ PalResult PAL_CALL allocateCommandBufferVk( allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memReq.size; - Uint32 mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; - Uint32 memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + uint32_t mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); allocateInfo.memoryTypeIndex = memoryIndex; result = s_Vk.allocateMemory( @@ -6661,8 +6661,8 @@ PalResult PAL_CALL submitCommandBufferVk( PalCommandBufferSubmitInfo* info) { VkResult result; - Int32 waitSemaphoreCount = 0; - Int32 signalSemaphoreCount = 0; + int32_t waitSemaphoreCount = 0; + int32_t signalSemaphoreCount = 0; VkFence fenceHandle = nullptr; VkSemaphore waitSemaphoreHandle = nullptr; VkSemaphore signalSemaphoreHandle = nullptr; @@ -6821,9 +6821,9 @@ PalResult PAL_CALL cmdSetFragmentShadingRateVk( PalResult PAL_CALL cmdDrawMeshTasksVk( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ) + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = vkCmdBuffer->device; @@ -6839,7 +6839,7 @@ PalResult PAL_CALL cmdDrawMeshTasksVk( PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 drawCount) + uint32_t drawCount) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = vkCmdBuffer->device; @@ -6853,7 +6853,7 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( return PAL_RESULT_INVALID_BUFFER; } - Uint32 stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); + uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); device->cmdDrawMeshTaskIndirect( vkCmdBuffer->handle, vkBuffer->handle, @@ -6868,7 +6868,7 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount) + uint32_t maxDrawCount) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = vkCmdBuffer->device; @@ -6887,7 +6887,7 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( return PAL_RESULT_INVALID_BUFFER; } - Uint32 stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); + uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); device->cmdDrawMeshTaskIndirectCount( vkCmdBuffer->handle, vkBuffer->handle, @@ -6920,7 +6920,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( // cache these for top level as VkAccelerationStructureBuildRangeInfoKHR cachedRangeInfo = {0}; VkAccelerationStructureGeometryKHR cachedGeometries = {0}; - Uint32 geometryCount = info->geometryCount; + uint32_t geometryCount = info->geometryCount; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { geometryCount = 1; rangeInfos = &cachedRangeInfo; @@ -6992,9 +6992,9 @@ PalResult PAL_CALL cmdBeginRenderingVk( VkRenderingFragmentShadingRateAttachmentInfoKHR fsrInfo = {0}; fsrInfo.sType = VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; - Uint32 layerCount = UINT32_MAX; - Uint32 renderWidth = UINT32_MAX; - Uint32 renderHeight = UINT32_MAX; + uint32_t layerCount = UINT32_MAX; + uint32_t renderWidth = UINT32_MAX; + uint32_t renderHeight = UINT32_MAX; for (int i = 0; i < info->colorAttachentCount; i++) { attachment = &colorAttachments[i]; desc = &info->colorAttachments[i]; @@ -7342,7 +7342,7 @@ PalResult PAL_CALL cmdBindPipelineVk( PalResult PAL_CALL cmdSetViewportVk( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalViewport* viewports) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -7378,7 +7378,7 @@ PalResult PAL_CALL cmdSetViewportVk( PalResult PAL_CALL cmdSetScissorsVk( PalCommandBuffer* cmdBuffer, - Uint32 count, + uint32_t count, PalRect2D* scissors) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -7412,10 +7412,10 @@ PalResult PAL_CALL cmdSetScissorsVk( PalResult PAL_CALL cmdBindVertexBuffersVk( PalCommandBuffer* cmdBuffer, - Uint32 firstSlot, - Uint32 count, + uint32_t firstSlot, + uint32_t count, PalBuffer** buffers, - Uint64* offsets) + uint64_t* offsets) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; VkBuffer cachedbuffer = nullptr; @@ -7446,7 +7446,7 @@ PalResult PAL_CALL cmdBindVertexBuffersVk( PalResult PAL_CALL cmdBindIndexBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint64 offset, + uint64_t offset, PalIndexType type) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -7462,10 +7462,10 @@ PalResult PAL_CALL cmdBindIndexBufferVk( PalResult PAL_CALL cmdDrawVk( PalCommandBuffer* cmdBuffer, - Uint32 vertexCount, - Uint32 instanceCount, - Uint32 firstVertex, - Uint32 firstInstance) + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.cmdDraw(vkCmdBuffer->handle, vertexCount, instanceCount, firstVertex, firstInstance); @@ -7475,11 +7475,11 @@ PalResult PAL_CALL cmdDrawVk( PalResult PAL_CALL cmdDrawIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count) + uint32_t count) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; - Uint32 stride = sizeof(VkDrawIndirectCommand); + uint32_t stride = sizeof(VkDrawIndirectCommand); if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -7497,7 +7497,7 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount) + uint32_t maxDrawCount) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; @@ -7516,7 +7516,7 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( return PAL_RESULT_INVALID_BUFFER; } - Uint32 stride = sizeof(VkDrawIndirectCommand); + uint32_t stride = sizeof(VkDrawIndirectCommand); device->cmdDrawIndirectCount( vkCmdBuffer->handle, vkBuffer->handle, @@ -7531,11 +7531,11 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( PalResult PAL_CALL cmdDrawIndexedVk( PalCommandBuffer* cmdBuffer, - Uint32 indexCount, - Uint32 instanceCount, - Uint32 firstIndex, - Int32 vertexOffset, - Uint32 firstInstance) + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.cmdDrawIndexed( @@ -7552,11 +7552,11 @@ PalResult PAL_CALL cmdDrawIndexedVk( PalResult PAL_CALL cmdDrawIndexedIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - Uint32 count) + uint32_t count) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; - Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); + uint32_t stride = sizeof(VkDrawIndexedIndirectCommand); if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -7574,7 +7574,7 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, - Uint32 maxDrawCount) + uint32_t maxDrawCount) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Buffer* vkBuffer = (Buffer*)buffer; @@ -7593,7 +7593,7 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( return PAL_RESULT_INVALID_BUFFER; } - Uint32 stride = sizeof(VkDrawIndexedIndirectCommand); + uint32_t stride = sizeof(VkDrawIndexedIndirectCommand); device->cmdDrawIndexedIndirectCount( vkCmdBuffer->handle, vkBuffer->handle, @@ -7736,9 +7736,9 @@ PalResult PAL_CALL cmdBufferBarrierVk( PalResult PAL_CALL cmdDispatchVk( PalCommandBuffer* cmdBuffer, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ) + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; s_Vk.cmdDispatch(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); @@ -7747,12 +7747,12 @@ PalResult PAL_CALL cmdDispatchVk( PalResult PAL_CALL cmdDispatchBaseVk( PalCommandBuffer* cmdBuffer, - Uint32 baseGroupX, - Uint32 baseGroupY, - Uint32 baseGroupZ, - Uint32 groupCountX, - Uint32 groupCountY, - Uint32 groupCountZ) + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = vkCmdBuffer->device; @@ -7794,10 +7794,10 @@ PalResult PAL_CALL cmdDispatchIndirectVk( PalResult PAL_CALL cmdTraceRaysVk( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, - Uint32 raygenIndex, - Uint32 width, - Uint32 height, - Uint32 depth) + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = vkCmdBuffer->device; @@ -7830,7 +7830,7 @@ PalResult PAL_CALL cmdTraceRaysVk( PalResult PAL_CALL cmdTraceRaysIndirectVk( PalCommandBuffer* cmdBuffer, - Uint32 raygenIndex, + uint32_t raygenIndex, PalShaderBindingTable* sbt, PalBuffer* buffer) { @@ -7894,7 +7894,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( PalResult PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, - Uint32 setIndex, + uint32_t setIndex, PalDescriptorSet* set) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -7916,10 +7916,10 @@ PalResult PAL_CALL cmdBindDescriptorSetVk( PalResult PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, - Uint32 shaderStageCount, + uint32_t shaderStageCount, PalShaderStage* shaderStages, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, const void* value) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; @@ -8178,7 +8178,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { - Uint32* maxPrimities = nullptr; + uint32_t* maxPrimities = nullptr; VkAccelerationStructureGeometryKHR* geometries = nullptr; Device* vkDevice = (Device*)device; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; @@ -8189,8 +8189,8 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( // cache these for top level as VkAccelerationStructureGeometryKHR cachedGeometries = {0}; - Uint32 cachedPrimitives = 0; - Uint32 geometryCount = info->geometryCount; + uint32_t cachedPrimitives = 0; + uint32_t geometryCount = info->geometryCount; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { geometryCount = 1; geometries = &cachedGeometries; @@ -8203,13 +8203,13 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( sizeof(VkAccelerationStructureGeometryKHR) * geometryCount, 0); - maxPrimities = palAllocate(s_Vk.allocator, sizeof(Uint32) * geometryCount, 0); + maxPrimities = palAllocate(s_Vk.allocator, sizeof(uint32_t) * geometryCount, 0); if (!maxPrimities || !geometries) { return PAL_RESULT_OUT_OF_MEMORY; } memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * geometryCount); - memset(maxPrimities, 0, sizeof(Uint32) * geometryCount); + memset(maxPrimities, 0, sizeof(uint32_t) * geometryCount); } fillBuildInfoVk( @@ -8307,8 +8307,8 @@ PalResult PAL_CALL getBufferMemoryRequirementsVk( VkMemoryRequirements memReq = {0}; s_Vk.getBufferMemoryRequirements(device->handle, vkBuffer->handle, &memReq); - requirements->alignment = (Uint64)memReq.alignment; - requirements->size = (Uint64)memReq.size; + requirements->alignment = (uint64_t)memReq.alignment; + requirements->size = (uint64_t)memReq.size; requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, vkBuffer->usages); requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; @@ -8323,8 +8323,8 @@ PalResult PAL_CALL getBufferMemoryRequirementsVk( PalResult PAL_CALL computeInstanceBufferRequirementsVk( PalDevice* device, - Uint32 instanceCount, - Uint64* outSize) + uint32_t instanceCount, + uint64_t* outSize) { *outSize = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; return PAL_RESULT_SUCCESS; @@ -8334,20 +8334,20 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, - Uint32* outBufferRowLength, - Uint32* outBufferImageHeight, - Uint64* outSize) + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize) { - Uint32 imageFormatSize = getFormatSizeVk(imageFormat); - Uint32 length = 0; - Uint32 height = 0; + uint32_t imageFormatSize = getFormatSizeVk(imageFormat); + uint32_t length = 0; + uint32_t height = 0; length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; - Uint32 rowPitch = length * imageFormatSize; + uint32_t rowPitch = length * imageFormatSize; *outBufferRowLength = length; *outBufferImageHeight = height; - *outSize = (Uint64)rowPitch * length * copyInfo->imageDepth; + *outSize = (uint64_t)rowPitch * length * copyInfo->imageDepth; return PAL_RESULT_SUCCESS; } @@ -8355,7 +8355,7 @@ PalResult PAL_CALL writeToInstanceBufferVk( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, - Uint32 instanceCount) + uint32_t instanceCount) { VkAccelerationStructureInstanceKHR* data = ptr; for (int i = 0; i < instanceCount; i++) { @@ -8380,19 +8380,19 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo) { - Uint32 imageFormatSize = getFormatSizeVk(imageFormat); - Uint32 dstRowPitch = copyInfo->bufferRowLength * imageFormatSize; - Uint32 srcRowPitch = copyInfo->imageWidth * imageFormatSize; - const Uint32 dstSlicePitch = dstRowPitch * copyInfo->bufferImageHeight; - const Uint32 srcSlicePitch = srcRowPitch * copyInfo->imageHeight; + uint32_t imageFormatSize = getFormatSizeVk(imageFormat); + uint32_t dstRowPitch = copyInfo->bufferRowLength * imageFormatSize; + uint32_t srcRowPitch = copyInfo->imageWidth * imageFormatSize; + const uint32_t dstSlicePitch = dstRowPitch * copyInfo->bufferImageHeight; + const uint32_t srcSlicePitch = srcRowPitch * copyInfo->imageHeight; // manually offset the buffer with the provided offset - Uint8* dst = (Uint8*)ptr + copyInfo->bufferOffset; - const Uint8* src = (const Uint8*)srcData; + uint8_t* dst = (uint8_t*)ptr + copyInfo->bufferOffset; + const uint8_t* src = (const uint8_t*)srcData; // write to destination pointer - for (Uint32 z = 0; z < copyInfo->imageDepth; z++) { - for (Uint32 y = 0; y < copyInfo->imageHeight; y++) { + for (uint32_t z = 0; z < copyInfo->imageDepth; z++) { + for (uint32_t y = 0; y < copyInfo->imageHeight; y++) { memcpy( dst + z * dstSlicePitch + y * dstRowPitch, src + z * srcSlicePitch + y * srcRowPitch, @@ -8406,7 +8406,7 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( PalResult PAL_CALL bindBufferMemoryVk( PalBuffer* buffer, PalMemory* memory, - Uint64 offset) + uint64_t offset) { VkResult result; Memory* vkMemory = (Memory*)memory; @@ -8432,8 +8432,8 @@ PalResult PAL_CALL bindBufferMemoryVk( PalResult PAL_CALL mapBufferMemoryVk( PalBuffer* buffer, - Uint64 offset, - Uint64 size, + uint64_t offset, + uint64_t size, void** outPtr) { VkResult result; @@ -8484,7 +8484,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( VkDescriptorSetLayoutBinding* bindings = nullptr; VkDescriptorBindingFlags* bindingFlags = nullptr; DescriptorSetLayout* layout = nullptr; - Uint32 count = info->bindingCount; + uint32_t count = info->bindingCount; VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsCreateInfo = {0}; bool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; @@ -8516,7 +8516,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( stageFlags |= bit; } - Uint32 bindingIndex = 0; + uint32_t bindingIndex = 0; for (int i = 0; i < count; i++) { VkDescriptorSetLayoutBinding* binding = &bindings[i]; binding->binding = bindingIndex++; @@ -8581,7 +8581,7 @@ PalResult PAL_CALL createDescriptorPoolVk( Device* vkDevice = (Device*)device; DescriptorPool* pool = nullptr; VkDescriptorPoolSize* poolSizes = nullptr; - Uint32 maxBindings = info->maxDescriptorBindingSizes; + uint32_t maxBindings = info->maxDescriptorBindingSizes; VkDescriptorPoolCreateInfo createInfo = {0}; bool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; @@ -8684,7 +8684,7 @@ PalResult PAL_CALL allocateDescriptorSetVk( PalResult PAL_CALL updateDescriptorSetVk( PalDevice* device, - Uint32 count, + uint32_t count, PalDescriptorSetWriteInfo* infos) { VkResult result; @@ -8695,10 +8695,10 @@ PalResult PAL_CALL updateDescriptorSetVk( VkAccelerationStructureKHR* tlas = nullptr; VkWriteDescriptorSetAccelerationStructureKHR* tlasInfos = nullptr; - Uint32 bufferCount = 0; - Uint32 imageCount = 0; - Uint32 tlasCount = 0; - Uint32 tlasInfoCount = 0; + uint32_t bufferCount = 0; + uint32_t imageCount = 0; + uint32_t tlasCount = 0; + uint32_t tlasInfoCount = 0; for (int i = 0; i < count; i++) { if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || @@ -8740,7 +8740,7 @@ PalResult PAL_CALL updateDescriptorSetVk( } if (tlasCount) { - Uint32 tlasInfoSize = sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasInfoCount; + uint32_t tlasInfoSize = sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasInfoCount; tlasInfos = palAllocate(s_Vk.allocator, tlasInfoSize, 0); tlas = palAllocate(s_Vk.allocator, sizeof(VkAccelerationStructureKHR) * count, 0); if (!tlasInfos || !tlas) { @@ -8894,8 +8894,8 @@ PalResult PAL_CALL createPipelineLayoutVk( PipelineLayout* layout = nullptr; VkPushConstantRange* pushConstants = nullptr; VkDescriptorSetLayout* descriptorLayouts = nullptr; - Uint32 pushConstantSize = sizeof(VkPushConstantRange) * info->pushConstantRangeCount; - Uint32 setLayoutSize = sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount; + uint32_t pushConstantSize = sizeof(VkPushConstantRange) * info->pushConstantRangeCount; + uint32_t setLayoutSize = sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount; layout = palAllocate(s_Vk.allocator, sizeof(PipelineLayout), 0); pushConstants = palAllocate(s_Vk.allocator, pushConstantSize, 0); @@ -9019,7 +9019,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( createInfo.layout = layout->handle; // find the total number of shader stages - Uint32 stageCount = 0; + uint32_t stageCount = 0; for (int i = 0; i < info->shaderCount; i++) { Shader* shader = (Shader*)info->shaders[i]; stageCount += shader->entryCount; @@ -9036,7 +9036,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( } // shaders - Uint32 stageIndex = 0; + uint32_t stageIndex = 0; memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stageCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; @@ -9067,15 +9067,15 @@ PalResult PAL_CALL createGraphicsPipelineVk( // Vertex input state // get the max size of vertex attributes in all layouts - Uint32 vertexCount = 0; + uint32_t vertexCount = 0; for (int i = 0; i < info->vertexLayoutCount; i++) { PalVertexLayout* layout = &info->vertexLayouts[i]; vertexCount += layout->attributeCount; } if (vertexCount) { - Uint32 tmpBindingSize = sizeof(VkVertexInputBindingDescription) * info->vertexLayoutCount; - Uint32 tmpAttribSize = sizeof(VkVertexInputAttributeDescription) * vertexCount; + uint32_t tmpBindingSize = sizeof(VkVertexInputBindingDescription) * info->vertexLayoutCount; + uint32_t tmpAttribSize = sizeof(VkVertexInputAttributeDescription) * vertexCount; bindingDescs = palAllocate(s_Vk.allocator, tmpBindingSize, 0); attribDescs = palAllocate(s_Vk.allocator, tmpAttribSize, 0); if (!bindingDescs || !attribDescs) { @@ -9083,7 +9083,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( return PAL_RESULT_OUT_OF_MEMORY; } - Uint32 location = 0; + uint32_t location = 0; for (int i = 0; i < info->vertexLayoutCount; i++) { PalVertexLayout* layout = &info->vertexLayouts[i]; VkVertexInputBindingDescription* bindingDesc = &bindingDescs[i]; @@ -9097,7 +9097,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( // find the stride and offset of the layout bindingDesc->stride = 0; - Uint32 offset = 0; + uint32_t offset = 0; for (int j = 0; j < layout->attributeCount; j++) { PalVertexAttribute* vertexAttrib = &layout->attributes[j]; VkVertexInputAttributeDescription* attribDesc = &attribDescs[j]; @@ -9107,7 +9107,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( attribDesc->location = location++; // build offsets and stride - Uint32 size = getVertexTypeSizeVk(vertexAttrib->type); + uint32_t size = getVertexTypeSizeVk(vertexAttrib->type); attribDesc->offset = offset; offset += size; bindingDesc->stride += size; @@ -9154,7 +9154,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( createInfo.pInputAssemblyState = &inputAssemblyState; // Dynamic states - Uint32 dynCount = 0; + uint32_t dynCount = 0; dynamicStates[dynCount++] = VK_DYNAMIC_STATE_VIEWPORT; dynamicStates[dynCount++] = VK_DYNAMIC_STATE_SCISSOR; dynamicStates[dynCount++] = VK_DYNAMIC_STATE_LINE_WIDTH; @@ -9233,7 +9233,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( createInfo.pRasterizationState = &rasterizerState; // Multisample state - Uint32 sampleMask[2] = {0}; // PAL supports upto 64 samples + uint32_t sampleMask[2] = {0}; // PAL supports upto 64 samples multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; multisampleState.pSampleMask = nullptr; if (info->multisampleState) { @@ -9251,11 +9251,11 @@ PalResult PAL_CALL createGraphicsPipelineVk( state->sampleCount == PAL_SAMPLE_COUNT_8 || state->sampleCount == PAL_SAMPLE_COUNT_16 || state->sampleCount == PAL_SAMPLE_COUNT_32) { - sampleMask[0] = (Uint32)(state->sampleMask & 0xFFFFFFFFULL); + sampleMask[0] = (uint32_t)(state->sampleMask & 0xFFFFFFFFULL); } else { - sampleMask[0] = (Uint32)(state->sampleMask & 0xFFFFFFFFULL); - sampleMask[1] = (Uint32)((state->sampleMask >> 32) & 0xFFFFFFFFULL); + sampleMask[0] = (uint32_t)(state->sampleMask & 0xFFFFFFFFULL); + sampleMask[1] = (uint32_t)((state->sampleMask >> 32) & 0xFFFFFFFFULL); } multisampleState.pSampleMask = sampleMask; @@ -9294,8 +9294,8 @@ PalResult PAL_CALL createGraphicsPipelineVk( // Color blend state if (info->colorBlendAttachmentCount) { - Uint32 count = info->colorBlendAttachmentCount; - Uint32 size = sizeof(VkPipelineColorBlendAttachmentState) * count; + uint32_t count = info->colorBlendAttachmentCount; + uint32_t size = sizeof(VkPipelineColorBlendAttachmentState) * count; blendattachments = palAllocate(s_Vk.allocator, size, 0); if (!blendattachments) { return PAL_RESULT_OUT_OF_MEMORY; @@ -9481,7 +9481,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( createInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; // find the total number of shader stages - Uint32 stageCount = 0; + uint32_t stageCount = 0; for (int i = 0; i < info->shaderCount; i++) { Shader* shader = (Shader*)info->shaders[i]; stageCount += shader->entryCount; @@ -9505,7 +9505,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( memset(pipeline, 0, sizeof(Pipeline)); // shaders - Uint32 stageIndex = 0; + uint32_t stageIndex = 0; memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stageCount); for (int i = 0; i < info->shaderCount; i++) { Shader* tmp = (Shader*)info->shaders[i]; @@ -9654,7 +9654,7 @@ PalResult PAL_CALL createShaderBindingTableVk( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - Uint32 totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; + uint32_t totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; totalGroups += sbtInfo->missCount + sbtInfo->callableCount; if (info->recordCount != totalGroups) { return PAL_RESULT_INVALID_ARGUMENT; @@ -9674,14 +9674,14 @@ PalResult PAL_CALL createShaderBindingTableVk( props.pNext = &rayProps; s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &props); - Uint32 groupHandleSize = rayProps.shaderGroupHandleSize; - Uint32 groupHandleAlignment = rayProps.shaderGroupHandleAlignment; - Uint32 groupBaseAlignment = rayProps.shaderGroupBaseAlignment; + uint32_t groupHandleSize = rayProps.shaderGroupHandleSize; + uint32_t groupHandleAlignment = rayProps.shaderGroupHandleAlignment; + uint32_t groupBaseAlignment = rayProps.shaderGroupBaseAlignment; // get the max local data size for (int i = 0; i < info->recordCount; i++) { PalShaderBindingTableRecordInfo* record = &info->records[i]; - Uint32 index = record->groupIndex; + uint32_t index = record->groupIndex; if (index < sbtInfo->raygenCount) { // raygen group @@ -9710,24 +9710,24 @@ PalResult PAL_CALL createShaderBindingTableVk( } // get strides - Uint32 callableStride = 0; - Uint32 raygenStride = alignVk(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); - Uint32 missStride = alignVk(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); - Uint32 hitStride = alignVk(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); + uint32_t callableStride = 0; + uint32_t raygenStride = alignVk(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); + uint32_t missStride = alignVk(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); + uint32_t hitStride = alignVk(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); callableStride = alignVk(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); // get region size - Uint32 raygenRegionSize = raygenStride * sbtInfo->raygenCount; - Uint32 missRegionSize = missStride * sbtInfo->missCount; - Uint32 hitRegionSize = hitStride * sbtInfo->hitCount; - Uint32 callableRegionSize = callableStride * sbtInfo->callableCount; + uint32_t raygenRegionSize = raygenStride * sbtInfo->raygenCount; + uint32_t missRegionSize = missStride * sbtInfo->missCount; + uint32_t hitRegionSize = hitStride * sbtInfo->hitCount; + uint32_t callableRegionSize = callableStride * sbtInfo->callableCount; // get offsets - Uint32 offset = 0; - Uint32 raygenOffset = 0; - Uint32 missOffset = 0; - Uint32 hitOffset = 0; - Uint32 callableOffset = 0; + uint32_t offset = 0; + uint32_t raygenOffset = 0; + uint32_t missOffset = 0; + uint32_t hitOffset = 0; + uint32_t callableOffset = 0; raygenOffset = alignVk(offset, groupBaseAlignment); offset = raygenOffset + raygenRegionSize; @@ -9741,7 +9741,7 @@ PalResult PAL_CALL createShaderBindingTableVk( callableOffset = alignVk(offset, groupBaseAlignment); offset = callableOffset + callableRegionSize; - Uint32 bufferSize = alignVk(offset, groupBaseAlignment); + uint32_t bufferSize = alignVk(offset, groupBaseAlignment); // create gpu buffer VkBufferCreateInfo bufCreateInfo = {0}; @@ -9780,8 +9780,8 @@ PalResult PAL_CALL createShaderBindingTableVk( allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memReq.size; - Uint32 mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; - Uint32 memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + uint32_t mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); allocateInfo.memoryTypeIndex = memoryIndex; VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; @@ -9824,8 +9824,8 @@ PalResult PAL_CALL createShaderBindingTableVk( s_Vk.bindBufferMemory(vkDevice->handle, sbt->stagingBuffer, sbt->stagingBufferMemory, 0); // get shader group handles - Uint32 handlesSize = totalGroups * groupHandleSize; - Uint8* handles = palAllocate(s_Vk.allocator, handlesSize, 0); + uint32_t handlesSize = totalGroups * groupHandleSize; + uint8_t* handles = palAllocate(s_Vk.allocator, handlesSize, 0); if (!handles) { palFree(s_Vk.allocator, sbt); return PAL_RESULT_OUT_OF_MEMORY; @@ -9853,11 +9853,11 @@ PalResult PAL_CALL createShaderBindingTableVk( } offset = 0; // reuse variable - Uint8* srcPtr = (Uint8*)handles; + uint8_t* srcPtr = (uint8_t*)handles; // raygen for (int i = 0; i < sbtInfo->raygenCount; i++) { - Uint8* dstPtr = (Uint8*)ptr + (i * raygenStride); + uint8_t* dstPtr = (uint8_t*)ptr + (i * raygenStride); PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); @@ -9872,7 +9872,7 @@ PalResult PAL_CALL createShaderBindingTableVk( // miss for (int i = 0; i < sbtInfo->missCount; i++) { - Uint8* dstPtr = (Uint8*)ptr + missOffset + (i * missStride); + uint8_t* dstPtr = (uint8_t*)ptr + missOffset + (i * missStride); PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); @@ -9887,7 +9887,7 @@ PalResult PAL_CALL createShaderBindingTableVk( // hit for (int i = 0; i < sbtInfo->hitCount; i++) { - Uint8* dstPtr = (Uint8*)ptr + hitOffset + (i * hitStride); + uint8_t* dstPtr = (uint8_t*)ptr + hitOffset + (i * hitStride); PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); @@ -9902,7 +9902,7 @@ PalResult PAL_CALL createShaderBindingTableVk( // callable for (int i = 0; i < sbtInfo->callableCount; i++) { - Uint8* dstPtr = (Uint8*)ptr + callableOffset + (i * callableStride); + uint8_t* dstPtr = (uint8_t*)ptr + callableOffset + (i * callableStride); PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); @@ -9973,7 +9973,7 @@ void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt) PalResult PAL_CALL updateShaderBindingTableVk( PalShaderBindingTable* sbt, - Uint32 count, + uint32_t count, PalShaderBindingTableRecordInfo* infos) { VkResult result; @@ -9995,9 +9995,9 @@ PalResult PAL_CALL updateShaderBindingTableVk( return resultFromVk(result); } - Uint32 stride = 0; - Uint32 offset = 0; - Uint32 startIndex = 0; + uint32_t stride = 0; + uint32_t offset = 0; + uint32_t startIndex = 0; for (int i = 0; i < count; i++) { PalShaderBindingTableRecordInfo* info = &infos[i]; @@ -10006,7 +10006,7 @@ PalResult PAL_CALL updateShaderBindingTableVk( } // find the group the record belongs to - Uint32 index = info->groupIndex; + uint32_t index = info->groupIndex; if (index < sbtInfo->raygenCount) { // raygen group offset = 0; @@ -10033,8 +10033,8 @@ PalResult PAL_CALL updateShaderBindingTableVk( } // write payload - Uint32 localIndex = index - startIndex; - Uint8* dst = (Uint8*)data + offset + (localIndex * stride); + uint32_t localIndex = index - startIndex; + uint8_t* dst = (uint8_t*)data + offset + (localIndex * stride); memcpy(dst + vkSbt->handleSize, info->localData, info->localDataSize); } diff --git a/src/opengl/pal_opengl_linux.c b/src/opengl/pal_opengl_linux.c index b1f2bd2f..6b615be4 100644 --- a/src/opengl/pal_opengl_linux.c +++ b/src/opengl/pal_opengl_linux.c @@ -206,7 +206,7 @@ typedef EGLSurface (*eglCreateWindowSurfaceFn)( const EGLint*); typedef const GLubyte* (*glGetStringFn)(GLenum); -typedef void(PAL_GL_APIENTRY* glClearFn)(Uint32); +typedef void(PAL_GL_APIENTRY* glClearFn)(uint32_t); typedef void(PAL_GL_APIENTRY* glClearColorFn)( float, @@ -222,7 +222,7 @@ typedef struct { typedef struct { bool initialized; - Int32 maxContextData; + int32_t maxContextData; EGLenum apiType; int apiTypeBit; const PalAllocator* allocator; @@ -338,7 +338,7 @@ static void freeContextData(PalGLContext* context) } } -void palSetLastPlatformError(Uint32 e); +void palSetLastPlatformError(uint32_t e); // ================================================== // Public API @@ -676,7 +676,7 @@ const PalGLInfo* PAL_CALL palGetGLInfo() PalResult PAL_CALL palEnumerateGLFBConfigs( PalGLWindow* glWindow, - Int32* count, + int32_t* count, PalGLFBConfig* configs) { if (!s_GL.initialized) { @@ -691,8 +691,8 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( return PAL_RESULT_INSUFFICIENT_BUFFER; } - Int32 configCount = 0; - Int32 maxConfigCount = 0; + int32_t configCount = 0; + int32_t maxConfigCount = 0; if (configs) { maxConfigCount = *count; @@ -802,7 +802,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( PalGLFBConfig* configs, - Int32 count, + int32_t count, const PalGLFBConfig* desired) { if (!s_GL.initialized) { @@ -817,10 +817,10 @@ const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( return nullptr; } - Int32 score = 0; - Int32 bestScore = 0x7FFFFFFF; + int32_t score = 0; + int32_t bestScore = 0x7FFFFFFF; PalGLFBConfig* best = nullptr; - for (Int32 i = 0; i < count; i++) { + for (int32_t i = 0; i < count; i++) { PalGLFBConfig* tmp = &configs[i]; // filter out hard constraints @@ -953,10 +953,10 @@ PalResult PAL_CALL palCreateGLContext( share = EGL_NO_CONTEXT; } - Int32 attribs[40]; - Int32 index = 0; - Int32 profile = 0; - Int32 flags = 0; + int32_t attribs[40]; + int32_t index = 0; + int32_t profile = 0; + int32_t flags = 0; // set context attributes // the first element is the key and the second is the value @@ -1194,7 +1194,7 @@ PalResult PAL_CALL palSwapBuffers( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palSetSwapInterval(Int32 interval) +PalResult PAL_CALL palSetSwapInterval(int32_t interval) { if (!s_GL.initialized) { return PAL_RESULT_GL_NOT_INITIALIZED; diff --git a/src/opengl/pal_opengl_win32.c b/src/opengl/pal_opengl_win32.c index d7791292..eadc1f11 100644 --- a/src/opengl/pal_opengl_win32.c +++ b/src/opengl/pal_opengl_win32.c @@ -239,7 +239,7 @@ static inline bool checkExtension( } } -void palSetLastPlatformError(Uint32 e); +void palSetLastPlatformError(uint32_t e); // ================================================== // Public API @@ -376,7 +376,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) pfd.cDepthBits = 24; pfd.cStencilBits = 8; - Int32 pixelFormat = s_Gdi.choosePixelFormat(s_Wgl.hdc, &pfd); + int32_t pixelFormat = s_Gdi.choosePixelFormat(s_Wgl.hdc, &pfd); s_Gdi.setPixelFormat(s_Wgl.hdc, pixelFormat, &pfd); s_Wgl.context = s_Wgl.wglCreateContext(s_Wgl.hdc); @@ -539,7 +539,7 @@ const PalGLInfo* PAL_CALL palGetGLInfo() PalResult PAL_CALL palEnumerateGLFBConfigs( PalGLWindow* glWindow, - Int32* count, + int32_t* count, PalGLFBConfig* configs) { if (!s_Wgl.initialized) { @@ -554,10 +554,10 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( return PAL_RESULT_INSUFFICIENT_BUFFER; } - Int32 configCount = 0; - Int32 maxConfigCount = 0; - Int32 nativeCount = 0; - const Int32 configAttrib = WGL_NUMBER_PIXEL_FORMATS_ARB; + int32_t configCount = 0; + int32_t maxConfigCount = 0; + int32_t nativeCount = 0; + const int32_t configAttrib = WGL_NUMBER_PIXEL_FORMATS_ARB; if (configs) { maxConfigCount = *count; @@ -573,7 +573,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( } // attributes we care about - Int32 attributes[] = { + int32_t attributes[] = { WGL_SUPPORT_OPENGL_ARB, WGL_DRAW_TO_WINDOW_ARB, WGL_PIXEL_TYPE_ARB, @@ -589,8 +589,8 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( WGL_DOUBLE_BUFFER_ARB, WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB}; - Int32 values[sizeof(attributes) / sizeof(attributes[0])]; - for (Int32 i = 1; i <= nativeCount; i++) { + int32_t values[sizeof(attributes) / sizeof(attributes[0])]; + for (int32_t i = 1; i <= nativeCount; i++) { if (!s_Wgl.wglGetPixelFormatAttribivARB( s_Wgl.hdc, i, @@ -650,7 +650,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( // get pixel format with legacy pixel descriptor nativeCount = s_Gdi.describePixelFormat(s_Wgl.hdc, 1, 0, nullptr); - for (Int32 i = 1; i <= nativeCount; i++) { + for (int32_t i = 1; i <= nativeCount; i++) { PIXELFORMATDESCRIPTOR pfd; if (!s_Gdi.describePixelFormat(s_Wgl.hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { continue; @@ -697,7 +697,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( PalGLFBConfig* configs, - Int32 count, + int32_t count, const PalGLFBConfig* desired) { if (!s_Wgl.initialized) { @@ -712,10 +712,10 @@ const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( return nullptr; } - Int32 score = 0; - Int32 bestScore = 0x7FFFFFFF; + int32_t score = 0; + int32_t bestScore = 0x7FFFFFFF; PalGLFBConfig* best = nullptr; - for (Int32 i = 0; i < count; i++) { + for (int32_t i = 0; i < count; i++) { PalGLFBConfig* tmp = &configs[i]; // filter out hard constraints @@ -830,10 +830,10 @@ PalResult PAL_CALL palCreateGLContext( HGLRC context = nullptr; if (s_Wgl.wglCreateContextAttribsARB) { // create context with modern wgl functions - Int32 attribs[40]; - Int32 index = 0; - Int32 profile = 0; - Int32 flags = 0; + int32_t attribs[40]; + int32_t index = 0; + int32_t profile = 0; + int32_t flags = 0; // set context attributes // the first element is the key and the second is the value @@ -1028,7 +1028,7 @@ PalResult PAL_CALL palSwapBuffers( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palSetSwapInterval(Int32 interval) +PalResult PAL_CALL palSetSwapInterval(int32_t interval) { if (!s_Wgl.initialized) { return PAL_RESULT_GL_NOT_INITIALIZED; diff --git a/src/pal_event.c b/src/pal_event.c index 78f049d4..87026bd4 100644 --- a/src/pal_event.c +++ b/src/pal_event.c @@ -11,8 +11,8 @@ #define PAL_MAX_EVENTS 512 typedef struct { - Uint8 head; - Uint8 tail; + uint8_t head; + uint8_t tail; PalEvent data[PAL_MAX_EVENTS]; } QueueData; diff --git a/src/system/pal_system_linux.c b/src/system/pal_system_linux.c index 2ff0f1e3..d3e37595 100644 --- a/src/system/pal_system_linux.c +++ b/src/system/pal_system_linux.c @@ -18,7 +18,7 @@ #include #include -static Uint32 parseCache(const char* path) +static uint32_t parseCache(const char* path) { long cacheSize = 0; FILE* file = fopen(path, "r"); @@ -85,15 +85,15 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) // get total memory and disk space for the root drive struct sysinfo sysInfo; sysinfo(&sysInfo); - info->totalRAM = (Uint32)(sysInfo.totalram / (1024 * 1024)); + info->totalRAM = (uint32_t)(sysInfo.totalram / (1024 * 1024)); struct statvfs stats; if (statvfs("/", &stats) != 0) { return PAL_RESULT_PLATFORM_FAILURE; } - Uint64 size = (stats.f_blocks * stats.f_frsize) / (1024 * 1024 * 1024); - info->totalMemory = (Uint32)size; + uint64_t size = (stats.f_blocks * stats.f_frsize) / (1024 * 1024 * 1024); + info->totalMemory = (uint32_t)size; return PAL_RESULT_SUCCESS; } @@ -179,11 +179,11 @@ PalResult PAL_CALL palGetCPUInfo( } fclose(file); - Uint32 l1 = parseCache("/sys/devices/system/cpu/cpu0/cache/index0/size"); - Uint32 l2 = parseCache("/sys/devices/system/cpu/cpu0/cache/index2/size"); - Uint32 l3 = parseCache("/sys/devices/system/cpu/cpu0/cache/index3/size"); + uint32_t l1 = parseCache("/sys/devices/system/cpu/cpu0/cache/index0/size"); + uint32_t l2 = parseCache("/sys/devices/system/cpu/cpu0/cache/index2/size"); + uint32_t l3 = parseCache("/sys/devices/system/cpu/cpu0/cache/index3/size"); - info->numLogicalProcessors = (Uint32)sysconf(_SC_NPROCESSORS_ONLN); + info->numLogicalProcessors = (uint32_t)sysconf(_SC_NPROCESSORS_ONLN); info->cacheL1 = l1; info->cacheL2 = l2; info->cacheL3 = l3; diff --git a/src/system/pal_system_win32.c b/src/system/pal_system_win32.c index b682f80d..14986757 100644 --- a/src/system/pal_system_win32.c +++ b/src/system/pal_system_win32.c @@ -67,9 +67,9 @@ static inline bool getVersionWin32(PalVersion* version) static inline bool isVersionWin32( PalVersion* osVersion, - Uint16 major, - Uint16 minor, - Uint16 build) + uint16_t major, + uint16_t minor, + uint16_t build) { if (osVersion->major > major) { return true; @@ -145,14 +145,14 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) // get total disk memory (size) in GB ULARGE_INTEGER free, total, available; if (GetDiskFreeSpaceExW(L"C:\\", &available, &total, &free)) { - info->totalMemory = (Uint32)(total.QuadPart / (1024 * 1024 * 1024)); + info->totalMemory = (uint32_t)(total.QuadPart / (1024 * 1024 * 1024)); } // get ram (size) in MB MEMORYSTATUSEX status = {0}; status.dwLength = sizeof(MEMORYSTATUSEX); if (GlobalMemoryStatusEx(&status)) { - info->totalRAM = (Uint32)(status.ullTotalPhys / (1024 * 1024)); + info->totalRAM = (uint32_t)(status.ullTotalPhys / (1024 * 1024)); } return PAL_RESULT_SUCCESS; diff --git a/src/thread/pal_condvar_posix.c b/src/thread/pal_condvar_posix.c index 07987177..5a2abd15 100644 --- a/src/thread/pal_condvar_posix.c +++ b/src/thread/pal_condvar_posix.c @@ -76,7 +76,7 @@ PalResult PAL_CALL palWaitCondVar( PalResult PAL_CALL palWaitCondVarTimeout( PalCondVar* condVar, PalMutex* mutex, - Uint64 milliseconds) + uint64_t milliseconds) { if (!condVar || !mutex) { return PAL_RESULT_NULL_POINTER; diff --git a/src/thread/pal_thread_posix.c b/src/thread/pal_thread_posix.c index 842bc5bb..80a69a60 100644 --- a/src/thread/pal_thread_posix.c +++ b/src/thread/pal_thread_posix.c @@ -13,8 +13,8 @@ #include #include -#define TO_PAL_HANDLE(type, val) ((type*)(UintPtr)(val)) -#define FROM_PAL_HANDLE(type, handle) ((type)(UintPtr)(handle)) +#define TO_PAL_HANDLE(type, val) ((type*)(uintptr_t)(val)) +#define FROM_PAL_HANDLE(type, handle) ((type)(uintptr_t)(handle)) PalResult PAL_CALL palCreateThread( const PalThreadCreateInfo* info, @@ -85,7 +85,7 @@ void PAL_CALL palDetachThread(PalThread* thread) } } -void PAL_CALL palSleep(Uint64 milliseconds) +void PAL_CALL palSleep(uint64_t milliseconds) { usleep(milliseconds * 1000); } @@ -137,7 +137,7 @@ PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread) } } -Uint64 PAL_CALL palGetThreadAffinity(PalThread* thread) +uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) { if (!thread) { return 0; @@ -150,7 +150,7 @@ Uint64 PAL_CALL palGetThreadAffinity(PalThread* thread) return 0; } - Uint64 mask = 0; + uint64_t mask = 0; for (int i = 0; i < 64; ++i) { if (CPU_ISSET(i, &cpuset)) { mask |= (1ULL << 1); @@ -161,8 +161,8 @@ Uint64 PAL_CALL palGetThreadAffinity(PalThread* thread) PalResult PAL_CALL palGetThreadName( PalThread* thread, - Uint64 bufferSize, - Uint64* outSize, + uint64_t bufferSize, + uint64_t* outSize, char* outBuffer) { if (!thread) { @@ -215,7 +215,7 @@ PalResult PAL_CALL palSetThreadPriority( PalResult PAL_CALL palSetThreadAffinity( PalThread* thread, - Uint64 mask) + uint64_t mask) { if (!thread) { return PAL_RESULT_NULL_POINTER; diff --git a/src/thread/pal_thread_win32.c b/src/thread/pal_thread_win32.c index b1e2c5b1..381aa3dd 100644 --- a/src/thread/pal_thread_win32.c +++ b/src/thread/pal_thread_win32.c @@ -82,7 +82,7 @@ static DWORD WINAPI threadEntryToWin32(LPVOID arg) return (DWORD)(uintptr_t)ret; } -void palSetLastPlatformError(Uint32 e); +void palSetLastPlatformError(uint32_t e); // ================================================== // Public API @@ -172,7 +172,7 @@ void PAL_CALL palDetachThread(PalThread* thread) } } -void PAL_CALL palSleep(Uint64 milliseconds) +void PAL_CALL palSleep(uint64_t milliseconds) { Sleep((DWORD)milliseconds); } @@ -230,7 +230,7 @@ PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread) return 0; } -Uint64 PAL_CALL palGetThreadAffinity(PalThread* thread) +uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) { if (!thread) { return 0; @@ -247,8 +247,8 @@ Uint64 PAL_CALL palGetThreadAffinity(PalThread* thread) PalResult PAL_CALL palGetThreadName( PalThread* thread, - Uint64 bufferSize, - Uint64* outSize, + uint64_t bufferSize, + uint64_t* outSize, char* outBuffer) { if (!thread) { @@ -332,7 +332,7 @@ PalResult PAL_CALL palSetThreadPriority( PalResult PAL_CALL palSetThreadAffinity( PalThread* thread, - Uint64 mask) + uint64_t mask) { if (!thread) { return PAL_RESULT_NULL_POINTER; @@ -541,7 +541,7 @@ PalResult PAL_CALL palWaitCondVar( PalResult PAL_CALL palWaitCondVarTimeout( PalCondVar* condVar, PalMutex* mutex, - Uint64 milliseconds) + uint64_t milliseconds) { if (!condVar || !mutex) { return PAL_RESULT_NULL_POINTER; diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index 5f82d9f0..af955414 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -72,8 +72,8 @@ freely, subject to the following restrictions: // Typedefs, enums and structs // ================================================== -#define TO_PAL_HANDLE(type, val) ((type*)(UintPtr)(val)) -#define FROM_PAL_HANDLE(type, handle) ((type)(UintPtr)(handle)) +#define TO_PAL_HANDLE(type, val) ((type*)(uintptr_t)(val)) +#define FROM_PAL_HANDLE(type, handle) ((type)(uintptr_t)(handle)) #define MAX_SPAN_MONITORS 4 #define NULL_BUTTON_SERIAL 0xffffffffU @@ -151,10 +151,10 @@ typedef struct { bool pushStateEvent; int x; int y; - Uint32 w; + uint32_t w; int dpi; int monitorCount; - Uint32 h; + uint32_t h; PalWindowState state; PalWindow* window; @@ -177,10 +177,10 @@ typedef struct { int dpi; int x; int y; - Uint32 w; - Uint32 h; - Uint32 refreshRate; - Uint32 wlName; + uint32_t w; + uint32_t h; + uint32_t refreshRate; + uint32_t wlName; PalOrientation orientation; PalMonitor* monitor; PalMonitorMode mode; // wayland only sends current @@ -189,12 +189,12 @@ typedef struct { typedef struct { bool pendingScroll; - Int32 lastX; - Int32 lastY; - Int32 dx; - Int32 dy; - Int32 WheelX; - Int32 WheelY; + int32_t lastX; + int32_t lastY; + int32_t dx; + int32_t dy; + int32_t WheelX; + int32_t WheelY; float WheelXf; float WheelYf; bool state[PAL_MOUSE_BUTTON_MAX]; @@ -213,8 +213,8 @@ typedef struct { int repeatScancode; int scancodes[512]; int keycodes[256]; - Uint64 timer; - Uint64 frequency; + uint64_t timer; + uint64_t frequency; } Keyboard; typedef struct { @@ -234,10 +234,10 @@ typedef struct { void (*shutdownVideo)(); void (*updateVideo)(); PalResult (*setFBConfig)(const int, PalFBConfigBackend); - PalResult (*enumerateMonitors)(Int32*, PalMonitor**); + PalResult (*enumerateMonitors)(int32_t*, PalMonitor**); PalResult (*getPrimaryMonitor)(PalMonitor**); PalResult (*getMonitorInfo)(PalMonitor*, PalMonitorInfo*); - PalResult (*enumerateMonitorModes)(PalMonitor*, Int32*, PalMonitorMode*); + PalResult (*enumerateMonitorModes)(PalMonitor*, int32_t*, PalMonitorMode*); PalResult (*getCurrentMonitorMode)(PalMonitor*, PalMonitorMode*); PalResult (*setMonitorMode)(PalMonitor*, PalMonitorMode*); PalResult (*validateMonitorMode)(PalMonitor*, PalMonitorMode*); @@ -253,9 +253,9 @@ typedef struct { PalResult (*flashWindow)(PalWindow*, const PalFlashInfo*); PalResult (*getWindowStyle)(PalWindow*, PalWindowStyle*); PalResult (*getWindowMonitor)(PalWindow*, PalMonitor**); - PalResult (*getWindowTitle)(PalWindow*, Uint64, Uint64*, char*); - PalResult (*getWindowPos)(PalWindow*, Int32*, Int32*); - PalResult (*getWindowSize)(PalWindow*, Uint32*, Uint32*); + PalResult (*getWindowTitle)(PalWindow*, uint64_t, uint64_t*, char*); + PalResult (*getWindowPos)(PalWindow*, int32_t*, int32_t*); + PalResult (*getWindowSize)(PalWindow*, uint32_t*, uint32_t*); PalResult (*getWindowState)(PalWindow*, PalWindowState*); bool (*isWindowVisible)(PalWindow*); PalWindow* (*getFocusWindow)(); @@ -264,8 +264,8 @@ typedef struct { PalResult (*setWindowOpacity)(PalWindow*, float); PalResult (*setWindowStyle)(PalWindow*, PalWindowStyle); PalResult (*setWindowTitle)(PalWindow*, const char*); - PalResult (*setWindowPos)(PalWindow*, Int32, Int32); - PalResult (*setWindowSize)(PalWindow*, Uint32, Uint32); + PalResult (*setWindowPos)(PalWindow*, int32_t, int32_t); + PalResult (*setWindowSize)(PalWindow*, uint32_t, uint32_t); PalResult (*setFocusWindow)(PalWindow*); PalResult (*createIcon)(const PalIconCreateInfo*, PalIcon**); @@ -277,8 +277,8 @@ typedef struct { void (*destroyCursor)(PalCursor*); void (*showCursor)(bool); PalResult (*clipCursor)(PalWindow*, bool); - PalResult (*getCursorPos)(PalWindow*, Int32*, Int32*); - PalResult (*setCursorPos)(PalWindow*, Int32, Int32); + PalResult (*getCursorPos)(PalWindow*, int32_t*, int32_t*); + PalResult (*setCursorPos)(PalWindow*, int32_t, int32_t); PalResult (*setWindowCursor)(PalWindow*, PalCursor*); PalResult (*attachWindow)(void*, PalWindow**); @@ -288,9 +288,9 @@ typedef struct { typedef struct { bool initialized; - Int32 maxWindowData; - Int32 maxMonitorData; - Int32 pixelFormat; + int32_t maxWindowData; + int32_t maxMonitorData; + int32_t pixelFormat; PalVideoFeatures features; PalVideoFeatures64 features64; const PalAllocator* allocator; @@ -1059,9 +1059,9 @@ static Wayland s_Wl = {0}; static WindowData* findWindowData(PalWindow* window); static MonitorData* findMonitorData(PalMonitor* monitor); -static inline Uint64 getTime() +static inline uint64_t getTime() { - Uint64 now = palGetPerformanceCounter(); + uint64_t now = palGetPerformanceCounter(); return (now * 1000) / s_Keyboard.frequency; } @@ -1856,13 +1856,13 @@ static void keyboardHandleKey( // Since PalKeycode and PalScancode have the same integers // we can make a direct cast without a table // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) - keycode = (PalKeycode)(Uint32)scancode; + keycode = (PalKeycode)(uint32_t)scancode; } // If we got a keySym but its not mapped into our keycode array // we do a direct cast as well if (keycode == PAL_KEYCODE_UNKNOWN) { - keycode = (PalKeycode)(Uint32)scancode; + keycode = (PalKeycode)(uint32_t)scancode; } s_Keyboard.scancodeState[scancode] = pressed; @@ -1906,7 +1906,7 @@ static void keyboardHandleKey( return; } - Uint32 codepoint = s_Wl.xkbKeysymToUtf32(keySym); + uint32_t codepoint = s_Wl.xkbKeysymToUtf32(keySym); if (codepoint <= 0) { return; } @@ -2011,7 +2011,7 @@ struct xdg_toplevel; static struct wl_buffer* createShmBuffer( int width, int height, - const Uint8* pixels, + const uint8_t* pixels, bool cursor); const struct wl_interface xdg_popup_interface; @@ -2954,7 +2954,7 @@ static void createScancodeTable() s_Keyboard.scancodes[0x07E] = PAL_SCANCODE_RSUPER; } -void palSetLastPlatformError(Uint32 e); +void palSetLastPlatformError(uint32_t e); // ================================================== // X11 API @@ -3054,7 +3054,7 @@ static RRMode xFindMode( // compare with width, height and refresh rate if (info->width == mode->width && info->height == mode->height && - (Uint32)(rate + 0.5) == mode->refreshRate) { + (uint32_t)(rate + 0.5) == mode->refreshRate) { return info->id; } } @@ -3278,7 +3278,7 @@ static void xCacheMonitors() } } - data->dpi = (Uint32)(closest * 96.0f); + data->dpi = (uint32_t)(closest * 96.0f); data->w = crtc->width; data->h = crtc->height; data->x = crtc->x; @@ -4191,13 +4191,13 @@ static void xUpdateVideo() // Since PalKeycode and PalScancode have the same integers // we can make a direct cast without a table // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) - keycode = (PalKeycode)(Uint32)scancode; + keycode = (PalKeycode)(uint32_t)scancode; } // If we got a keySym but its not mapped into our keycode array // we do a direct cast as well if (keycode == PAL_KEYCODE_UNKNOWN) { - keycode = (PalKeycode)(Uint32)scancode; + keycode = (PalKeycode)(uint32_t)scancode; } // update our keyboard and mouse state to handle key repeat @@ -4244,7 +4244,7 @@ static void xUpdateVideo() &keySym, &status); - Uint32 codepoint = 0; + uint32_t codepoint = 0; if (status == XLookupChars || status == XLookupBoth) { // decode to Unicode codepoint unsigned char ch = buffer[0]; @@ -4290,7 +4290,7 @@ static void xUpdateVideo() } static PalResult xEnumerateMonitors( - Int32* count, + int32_t* count, PalMonitor** outMonitors) { int _count = 0; @@ -4420,7 +4420,7 @@ static PalResult xGetMonitorInfo( } } - info->dpi = (Uint32)(closest * 96.0f); + info->dpi = (uint32_t)(closest * 96.0f); s_X11.freeCrtcInfo(crtc); s_X11.freeOutputInfo(outputInfo); @@ -4431,10 +4431,10 @@ static PalResult xGetMonitorInfo( static PalResult xEnumerateMonitorModes( PalMonitor* monitor, - Int32* count, + int32_t* count, PalMonitorMode* modes) { - Int32 modeCount = 0; + int32_t modeCount = 0; int maxModeCount = modes ? *count : 0; XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); @@ -4733,8 +4733,8 @@ static PalResult xCreateWindow( // get monitor int monitorX = 0; int monitorY = 0; - Uint32 monitorW = 0; - Uint32 monitorH = 0; + uint32_t monitorW = 0; + uint32_t monitorH = 0; int dpi = 0; if (info->monitor) { monitor = info->monitor; @@ -4793,7 +4793,7 @@ static PalResult xCreateWindow( } } - dpi = (Uint32)(closest * 96.0f); + dpi = (uint32_t)(closest * 96.0f); s_X11.freeCrtcInfo(crtc); s_X11.freeOutputInfo(outputInfo); @@ -4802,7 +4802,7 @@ static PalResult xCreateWindow( s_X11.freeScreenResources(resources); } - Int32 x, y = 0; + int32_t x, y = 0; // the position and size must be scaled with the dpi before this call if (info->center) { x = monitorX + (monitorW - info->width) / 2; @@ -5252,8 +5252,8 @@ PalResult xGetWindowMonitor( PalResult xGetWindowTitle( PalWindow* window, - Uint64 bufferSize, - Uint64* outSize, + uint64_t bufferSize, + uint64_t* outSize, char* outBuffer) { Window xWin = FROM_PAL_HANDLE(Window, window); @@ -5313,8 +5313,8 @@ PalResult xGetWindowTitle( PalResult xGetWindowPos( PalWindow* window, - Int32* x, - Int32* y) + int32_t* x, + int32_t* y) { Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; @@ -5335,8 +5335,8 @@ PalResult xGetWindowPos( PalResult xGetWindowSize( PalWindow* window, - Uint32* width, - Uint32* height) + uint32_t* width, + uint32_t* height) { Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; @@ -5509,8 +5509,8 @@ PalResult xSetWindowTitle( PalResult xSetWindowPos( PalWindow* window, - Int32 x, - Int32 y) + int32_t x, + int32_t y) { Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; @@ -5525,8 +5525,8 @@ PalResult xSetWindowPos( PalResult xSetWindowSize( PalWindow* window, - Uint32 width, - Uint32 height) + uint32_t width, + uint32_t height) { Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; @@ -5585,8 +5585,8 @@ PalResult xCreateIcon( const PalIconCreateInfo* info, PalIcon** outIcon) { - Uint64 totalPixels = 2 + (Uint64)(info->width * info->height); - Uint64 totalBytes = sizeof(unsigned long) * totalPixels; + uint64_t totalPixels = 2 + (uint64_t)(info->width * info->height); + uint64_t totalBytes = sizeof(unsigned long) * totalPixels; unsigned long* icon = palAllocate(s_Video.allocator, totalBytes, 0); if (!icon) { @@ -5600,10 +5600,10 @@ PalResult xCreateIcon( // convert from RGBA8 to ARGB32 for (int i = 0; i < info->width * info->height; i++) { - Uint8 r = info->pixels[i * 4 + 0]; // Red - Uint8 g = info->pixels[i * 4 + 1]; // Green - Uint8 b = info->pixels[i * 4 + 2]; // Blue - Uint8 a = info->pixels[i * 4 + 3]; // Alpha + uint8_t r = info->pixels[i * 4 + 0]; // Red + uint8_t g = info->pixels[i * 4 + 1]; // Green + uint8_t b = info->pixels[i * 4 + 2]; // Blue + uint8_t a = info->pixels[i * 4 + 3]; // Alpha // clang-format off icon[2 + i] = ((unsigned long)a << 24) | @@ -5636,7 +5636,7 @@ PalResult xSetWindowIcon( } unsigned long* iconData = FROM_PAL_HANDLE(unsigned long*, icon); - Uint64 totalPixels = 2 + iconData[0] * iconData[1]; + uint64_t totalPixels = 2 + iconData[0] * iconData[1]; s_X11.changeProperty( s_X11.display, xWin, @@ -5661,10 +5661,10 @@ PalResult xCreateCursor( // convert from RGBA8 to ARGB32 for (int i = 0; i < info->width * info->height; i++) { - Uint8 r = info->pixels[i * 4 + 0]; // Red - Uint8 g = info->pixels[i * 4 + 1]; // Green - Uint8 b = info->pixels[i * 4 + 2]; // Blue - Uint8 a = info->pixels[i * 4 + 3]; // Alpha + uint8_t r = info->pixels[i * 4 + 0]; // Red + uint8_t g = info->pixels[i * 4 + 1]; // Green + uint8_t b = info->pixels[i * 4 + 2]; // Blue + uint8_t a = info->pixels[i * 4 + 3]; // Alpha // clang-format off image->pixels[i] = ((unsigned long)a << 24) | @@ -5769,8 +5769,8 @@ PalResult xClipCursor( PalResult xGetCursorPos( PalWindow* window, - Int32* x, - Int32* y) + int32_t* x, + int32_t* y) { Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; @@ -5796,8 +5796,8 @@ PalResult xGetCursorPos( PalResult xSetCursorPos( PalWindow* window, - Int32 x, - Int32 y) + int32_t x, + int32_t y) { Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; @@ -6068,7 +6068,7 @@ static void wlCreateKeycodeTable() s_Keyboard.keycodes[XKB_KEY_bracketright] = PAL_KEYCODE_RBRACKET; } -static int createShmFile(Uint64 size) +static int createShmFile(uint64_t size) { char template[] = "/tmp/pal-shm-XXXXXX"; int fd = mkstemp(template); @@ -6087,11 +6087,11 @@ static int createShmFile(Uint64 size) static struct wl_buffer* createShmBuffer( int width, int height, - const Uint8* pixels, + const uint8_t* pixels, bool cursor) { int stride = width * 4; - Uint64 size = stride * height; + uint64_t size = stride * height; struct wl_buffer* buffer = nullptr; struct wl_shm_pool* pool = nullptr; void* data = nullptr; @@ -6109,14 +6109,14 @@ static struct wl_buffer* createShmBuffer( enum wl_shm_format format = WL_SHM_FORMAT_XRGB8888; if (cursor) { format = WL_SHM_FORMAT_ARGB8888; - Uint32* dataPixels = (Uint32*)data; + uint32_t* dataPixels = (uint32_t*)data; // convert from RGBA8 to ARGB32 for (int i = 0; i < width * height; i++) { - Uint8 r = pixels[i * 4 + 0]; // Red - Uint8 g = pixels[i * 4 + 1]; // Green - Uint8 b = pixels[i * 4 + 2]; // Blue - Uint8 a = pixels[i * 4 + 3]; // Alpha + uint8_t r = pixels[i * 4 + 0]; // Red + uint8_t g = pixels[i * 4 + 1]; // Green + uint8_t b = pixels[i * 4 + 2]; // Blue + uint8_t a = pixels[i * 4 + 3]; // Alpha // clang-format off dataPixels[i] = ((unsigned long)a << 24) | @@ -6220,7 +6220,7 @@ static void wlOutputScale( { MonitorData* monitorData = data; float dpi = (float)scale * 96.0f; - monitorData->dpi = (Uint32)dpi; + monitorData->dpi = (uint32_t)dpi; } static void wlOutputDone( @@ -6607,7 +6607,7 @@ void wlUpdateVideo() mode = palGetEventDispatchMode(driver, PAL_EVENT_KEYREPEAT); if (mode != PAL_DISPATCH_NONE) { // get now time and check with the key repeat time - Uint64 now = getTime(); + uint64_t now = getTime(); if (now >= s_Keyboard.timer) { PalWindow* window = (PalWindow*)s_Wl.keyboardSurface; PalKeycode key = s_Keyboard.repeatKey; @@ -6643,7 +6643,7 @@ void wlUpdateVideo() } PalResult wlEnumerateMonitors( - Int32* count, + int32_t* count, PalMonitor** outMonitors) { if (outMonitors) { @@ -6695,7 +6695,7 @@ PalResult wlGetMonitorInfo( PalResult wlEnumerateMonitorModes( PalMonitor* monitor, - Int32* count, + int32_t* count, PalMonitorMode* modes) { MonitorData* monitorData = findMonitorData(monitor); @@ -7020,8 +7020,8 @@ PalResult wlGetWindowMonitor( PalResult wlGetWindowTitle( PalWindow* window, - Uint64 bufferSize, - Uint64* outSize, + uint64_t bufferSize, + uint64_t* outSize, char* outBuffer) { return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; @@ -7029,16 +7029,16 @@ PalResult wlGetWindowTitle( PalResult wlGetWindowPos( PalWindow* window, - Int32* x, - Int32* y) + int32_t* x, + int32_t* y) { return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; } PalResult wlGetWindowSize( PalWindow* window, - Uint32* width, - Uint32* height) + uint32_t* width, + uint32_t* height) { return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; } @@ -7114,16 +7114,16 @@ PalResult wlSetWindowTitle( PalResult wlSetWindowPos( PalWindow* window, - Int32 x, - Int32 y) + int32_t x, + int32_t y) { return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; } PalResult wlSetWindowSize( PalWindow* window, - Uint32 width, - Uint32 height) + uint32_t width, + uint32_t height) { WindowData* data = findWindowData(window); if (!data) { @@ -7279,16 +7279,16 @@ PalResult wlClipCursor( PalResult wlGetCursorPos( PalWindow* window, - Int32* x, - Int32* y) + int32_t* x, + int32_t* y) { return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; } PalResult wlSetCursorPos( PalWindow* window, - Int32 x, - Int32 y) + int32_t x, + int32_t y) { return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; } @@ -7529,7 +7529,7 @@ PalResult PAL_CALL palSetFBConfig( } PalResult PAL_CALL palEnumerateMonitors( - Int32* count, + int32_t* count, PalMonitor** outMonitors) { if (!s_Video.initialized) { @@ -7577,7 +7577,7 @@ PalResult PAL_CALL palGetMonitorInfo( PalResult PAL_CALL palEnumerateMonitorModes( PalMonitor* monitor, - Int32* count, + int32_t* count, PalMonitorMode* modes) { if (!s_Video.initialized) { @@ -7807,8 +7807,8 @@ PalResult PAL_CALL palGetWindowMonitor( PalResult PAL_CALL palGetWindowTitle( PalWindow* window, - Uint64 bufferSize, - Uint64* outSize, + uint64_t bufferSize, + uint64_t* outSize, char* outBuffer) { if (!s_Video.initialized) { @@ -7824,8 +7824,8 @@ PalResult PAL_CALL palGetWindowTitle( PalResult PAL_CALL palGetWindowPos( PalWindow* window, - Int32* x, - Int32* y) + int32_t* x, + int32_t* y) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -7840,8 +7840,8 @@ PalResult PAL_CALL palGetWindowPos( PalResult PAL_CALL palGetWindowSize( PalWindow* window, - Uint32* width, - Uint32* height) + uint32_t* width, + uint32_t* height) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -7894,8 +7894,8 @@ const bool* PAL_CALL palGetMouseState() } void PAL_CALL palGetMouseDelta( - Int32* dx, - Int32* dy) + int32_t* dx, + int32_t* dy) { if (!s_Video.initialized) { return; @@ -7911,8 +7911,8 @@ void PAL_CALL palGetMouseDelta( } void PAL_CALL palGetMouseWheelDelta( - Int32* dx, - Int32* dy) + int32_t* dx, + int32_t* dy) { if (!s_Video.initialized) { return; @@ -8039,8 +8039,8 @@ PalResult PAL_CALL palSetWindowTitle( PalResult PAL_CALL palSetWindowPos( PalWindow* window, - Int32 x, - Int32 y) + int32_t x, + int32_t y) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -8055,8 +8055,8 @@ PalResult PAL_CALL palSetWindowPos( PalResult PAL_CALL palSetWindowSize( PalWindow* window, - Uint32 width, - Uint32 height) + uint32_t width, + uint32_t height) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -8188,8 +8188,8 @@ PalResult PAL_CALL palClipCursor( PalResult PAL_CALL palGetCursorPos( PalWindow* window, - Int32* x, - Int32* y) + int32_t* x, + int32_t* y) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -8204,8 +8204,8 @@ PalResult PAL_CALL palGetCursorPos( PalResult PAL_CALL palSetCursorPos( PalWindow* window, - Int32 x, - Int32 y) + int32_t x, + int32_t y) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; diff --git a/src/video/pal_video_win32.c b/src/video/pal_video_win32.c index 9e7dafb1..421f3c1f 100644 --- a/src/video/pal_video_win32.c +++ b/src/video/pal_video_win32.c @@ -60,11 +60,11 @@ freely, subject to the following restrictions: typedef HRESULT(WINAPI* GetDpiForMonitorFn)( HMONITOR, - Int32, + int32_t, UINT*, UINT*); -typedef HRESULT(WINAPI* SetProcessAwarenessFn)(Int32); +typedef HRESULT(WINAPI* SetProcessAwarenessFn)(int32_t); typedef HBITMAP(WINAPI* CreateDIBSectionFn)( HDC, @@ -104,8 +104,8 @@ typedef struct { typedef struct { bool initialized; - Int32 pixelFormat; - Int32 maxWindowData; + int32_t pixelFormat; + int32_t maxWindowData; PalVideoFeatures features; PalVideoFeatures64 features64; const PalAllocator* allocator; @@ -128,8 +128,8 @@ typedef struct { } VideoWin32; typedef struct { - Int32 count; - Int32 maxCount; + int32_t count; + int32_t maxCount; PalMonitor** monitors; } MonitorData; @@ -137,16 +137,16 @@ typedef struct { bool pendingResize; bool pendingMove; bool pendingState; - Uint32 width; - Uint32 height; - Int32 x; - Int32 y; + uint32_t width; + uint32_t height; + int32_t x; + int32_t y; PalWindowState state; PalWindow* window; } PendingEvent; typedef struct { - Int32 pendingHighSurrogate; + int32_t pendingHighSurrogate; bool scancodeState[PAL_SCANCODE_MAX]; bool keycodeState[PAL_KEYCODE_MAX]; int scancodes[512]; @@ -155,10 +155,10 @@ typedef struct { typedef struct { bool push; - Int32 dx; - Int32 dy; - Int32 WheelX; - Int32 WheelY; + int32_t dx; + int32_t dy; + int32_t WheelX; + int32_t WheelY; bool state[PAL_MOUSE_BUTTON_MAX]; } Mouse; @@ -173,7 +173,7 @@ static Keyboard s_Keyboard = {0}; // Internal API // ================================================== -void palSetLastPlatformError(Uint32 e); +void palSetLastPlatformError(uint32_t e); LRESULT CALLBACK videoProc( HWND hwnd, @@ -208,8 +208,8 @@ LRESULT CALLBACK videoProc( if (s_Video.eventDriver) { PalEventDriver* driver = s_Video.eventDriver; mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_SIZE); - Uint32 width = (Uint32)LOWORD(lParam); - Uint32 height = (Uint32)HIWORD(lParam); + uint32_t width = (uint32_t)LOWORD(lParam); + uint32_t height = (uint32_t)HIWORD(lParam); if (mode == PAL_DISPATCH_CALLBACK) { PalEvent event = {0}; @@ -270,8 +270,8 @@ LRESULT CALLBACK videoProc( if (s_Video.eventDriver) { PalEventDriver* driver = s_Video.eventDriver; mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_MOVE); - Int32 x = GET_X_LPARAM(lParam); - Int32 y = GET_Y_LPARAM(lParam); + int32_t x = GET_X_LPARAM(lParam); + int32_t y = GET_Y_LPARAM(lParam); if (mode == PAL_DISPATCH_CALLBACK) { PalEvent event = {0}; @@ -406,7 +406,7 @@ LRESULT CALLBACK videoProc( } case WM_MOUSEHWHEEL: { - Int32 delta = GET_WHEEL_DELTA_WPARAM(wParam); + int32_t delta = GET_WHEEL_DELTA_WPARAM(wParam); s_Mouse.WheelX = delta / WHEEL_DELTA; if (s_Video.eventDriver) { @@ -424,7 +424,7 @@ LRESULT CALLBACK videoProc( } case WM_MOUSEWHEEL: { - Int32 delta = GET_WHEEL_DELTA_WPARAM(wParam); + int32_t delta = GET_WHEEL_DELTA_WPARAM(wParam); s_Mouse.WheelY = delta / WHEEL_DELTA; if (s_Video.eventDriver) { @@ -442,8 +442,8 @@ LRESULT CALLBACK videoProc( } case WM_MOUSEMOVE: { - const Int32 x = GET_X_LPARAM(lParam); - const Int32 y = GET_Y_LPARAM(lParam); + const int32_t x = GET_X_LPARAM(lParam); + const int32_t y = GET_Y_LPARAM(lParam); if (s_Video.eventDriver) { PalEventDriver* driver = s_Video.eventDriver; @@ -571,8 +571,8 @@ LRESULT CALLBACK videoProc( PalKeycode keycode = PAL_KEYCODE_UNKNOWN; PalScancode scancode = PAL_SCANCODE_UNKNOWN; PalEventType type; - Int32 win32Keycode; - Int32 win32Scancode; + int32_t win32Keycode; + int32_t win32Scancode; bool pressed = false; bool extended = false; @@ -586,7 +586,7 @@ LRESULT CALLBACK videoProc( scancode = PAL_SCANCODE_NUMLOCK; } else { - Uint16 index = win32Scancode | (extended << 8); + uint16_t index = win32Scancode | (extended << 8); scancode = s_Keyboard.scancodes[index]; } @@ -597,7 +597,7 @@ LRESULT CALLBACK videoProc( // Since PalKeycode and PalScancode have the same integers // we can make a direct cast without a table // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) - keycode = (PalKeycode)(Uint32)scancode; + keycode = (PalKeycode)(uint32_t)scancode; } if (win32Keycode == VK_SNAPSHOT) { @@ -668,7 +668,7 @@ LRESULT CALLBACK videoProc( case WM_CHAR: { PalEventType type = PAL_EVENT_KEYCHAR; - Uint32 codepoint = 0; + uint32_t codepoint = 0; if (s_Video.eventDriver) { PalEventDriver* driver = s_Video.eventDriver; mode = palGetEventDispatchMode(driver, type); @@ -678,15 +678,15 @@ LRESULT CALLBACK videoProc( } // Most characters comes as two WM_CHAR messags or event // we store the first one and combine with the second if we got any - Uint16 character = (Uint16)wParam; + uint16_t character = (uint16_t)wParam; if (character >= 0xD800 && character <= 0xDBFF) { // high surrogate s_Keyboard.pendingHighSurrogate = character; } else if (character >= 0xDC00 && character <= 0xDFFF) { if (s_Keyboard.pendingHighSurrogate) { // low surrogate we combine both - Uint32 high = s_Keyboard.pendingHighSurrogate - 0xD800; - Uint32 low = character - 0xDC00; + uint32_t high = s_Keyboard.pendingHighSurrogate - 0xD800; + uint32_t low = character - 0xDC00; codepoint = 0x10000 + ((high << 10) | low); s_Keyboard.pendingHighSurrogate = 0; } @@ -824,10 +824,10 @@ static inline bool compareMonitorMode( static inline void addMonitorMode( PalMonitorMode* modes, const PalMonitorMode* mode, - Int32* count) + int32_t* count) { // check if we have a duplicate mode - for (Int32 i = 0; i < *count; i++) { + for (int32_t i = 0; i < *count; i++) { PalMonitorMode* oldMode = &modes[i]; if (compareMonitorMode(oldMode, mode)) { return; // discard it @@ -1364,7 +1364,7 @@ PalResult PAL_CALL palSetFBConfig( // ================================================== PalResult PAL_CALL palEnumerateMonitors( - Int32* count, + int32_t* count, PalMonitor** outMonitors) { if (!s_Video.initialized) { @@ -1478,7 +1478,7 @@ PalResult PAL_CALL palGetMonitorInfo( PalResult PAL_CALL palEnumerateMonitorModes( PalMonitor* monitor, - Int32* count, + int32_t* count, PalMonitorMode* modes) { if (!s_Video.initialized) { @@ -1493,8 +1493,8 @@ PalResult PAL_CALL palEnumerateMonitorModes( return PAL_RESULT_INSUFFICIENT_BUFFER; } - Int32 modeCount = 0; - Int32 maxModes = 0; + int32_t modeCount = 0; + int32_t maxModes = 0; PalMonitorMode* monitorModes = nullptr; MONITORINFOEXW mi = {0}; @@ -1528,7 +1528,7 @@ PalResult PAL_CALL palEnumerateMonitorModes( DEVMODEW dm = {0}; dm.dmSize = sizeof(DEVMODE); - for (Int32 i = 0; EnumDisplaySettingsW(mi.szDevice, i, &dm); i++) { + for (int32_t i = 0; EnumDisplaySettingsW(mi.szDevice, i, &dm); i++) { // Pal support up to 128 modes if (modeCount > maxModes) { break; @@ -1695,8 +1695,8 @@ PalResult PAL_CALL palCreateWindow( PalMonitor* monitor = nullptr; PalMonitorInfo monitorInfo; - Uint32 style = WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED; - Uint32 exStyle = 0; + uint32_t style = WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED; + uint32_t exStyle = 0; // no minimize box if (!(info->style & PAL_WINDOW_STYLE_NO_MINIMIZEBOX)) { @@ -1753,7 +1753,7 @@ PalResult PAL_CALL palCreateWindow( } // compose position. - Int32 x, y = 0; + int32_t x, y = 0; // the position and size must be scaled with the dpi before this call if (info->center) { x = monitorInfo.x + (monitorInfo.width - info->width) / 2; @@ -1815,7 +1815,7 @@ PalResult PAL_CALL palCreateWindow( } // show, maximize and minimize - Int32 showFlag = SW_HIDE; + int32_t showFlag = SW_HIDE; // maximize if (info->maximized) { showFlag = SW_MAXIMIZE; @@ -2107,8 +2107,8 @@ PalResult PAL_CALL palGetWindowMonitor( PalResult PAL_CALL palGetWindowTitle( PalWindow* window, - Uint64 bufferSize, - Uint64* outSize, + uint64_t bufferSize, + uint64_t* outSize, char* outBuffer) { if (!s_Video.initialized) { @@ -2141,8 +2141,8 @@ PalResult PAL_CALL palGetWindowTitle( PalResult PAL_CALL palGetWindowPos( PalWindow* window, - Int32* x, - Int32* y) + int32_t* x, + int32_t* y) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -2169,8 +2169,8 @@ PalResult PAL_CALL palGetWindowPos( PalResult PAL_CALL palGetWindowSize( PalWindow* window, - Uint32* width, - Uint32* height) + uint32_t* width, + uint32_t* height) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -2250,8 +2250,8 @@ const bool* PAL_CALL palGetMouseState() } void PAL_CALL palGetMouseDelta( - Int32* dx, - Int32* dy) + int32_t* dx, + int32_t* dy) { if (!s_Video.initialized) { return; @@ -2267,8 +2267,8 @@ void PAL_CALL palGetMouseDelta( } void PAL_CALL palGetMouseWheelDelta( - Int32* dx, - Int32* dy) + int32_t* dx, + int32_t* dy) { if (!s_Video.initialized) { return; @@ -2487,8 +2487,8 @@ PalResult PAL_CALL palSetWindowTitle( PalResult PAL_CALL palSetWindowPos( PalWindow* window, - Int32 x, - Int32 y) + int32_t x, + int32_t y) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -2516,8 +2516,8 @@ PalResult PAL_CALL palSetWindowPos( PalResult PAL_CALL palSetWindowSize( PalWindow* window, - Uint32 width, - Uint32 height) + uint32_t width, + uint32_t height) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -2598,7 +2598,7 @@ PalResult PAL_CALL palCreateIcon( BITMAPV5HEADER bitInfo = {0}; bitInfo.bV5Size = sizeof(BITMAPV5HEADER); bitInfo.bV5Width = info->width; - bitInfo.bV5Height = -(Int32)info->height; // this is topdown by default + bitInfo.bV5Height = -(int32_t)info->height; // this is topdown by default // default parameters bitInfo.bV5Planes = 1; @@ -2627,20 +2627,20 @@ PalResult PAL_CALL palCreateIcon( ReleaseDC(nullptr, hdc); // convert RGBA to BGRA - Uint8* pixels = (Uint8*)dibPixels; - for (Uint32 i = 0; i < info->width * info->height; i++) { - Uint8 r = info->pixels[i * 4 + 0]; // Red - Uint8 g = info->pixels[i * 4 + 1]; // Green - Uint8 b = info->pixels[i * 4 + 2]; // Blue - Uint8 a = info->pixels[i * 4 + 3]; // Alpha + uint8_t* pixels = (uint8_t*)dibPixels; + for (uint32_t i = 0; i < info->width * info->height; i++) { + uint8_t r = info->pixels[i * 4 + 0]; // Red + uint8_t g = info->pixels[i * 4 + 1]; // Green + uint8_t b = info->pixels[i * 4 + 2]; // Blue + uint8_t a = info->pixels[i * 4 + 3]; // Alpha // premultiply only if alpha is not 0 if (a == 0) { r = g = b = 0; } else { - r = (Uint8)((r * a) / 255); - g = (Uint8)((g * a) / 255); - b = (Uint8)((b * a) / 255); + r = (uint8_t)((r * a) / 255); + g = (uint8_t)((g * a) / 255); + b = (uint8_t)((b * a) / 255); } pixels[i * 4 + 0] = b; @@ -2716,7 +2716,7 @@ PalResult PAL_CALL palCreateCursor( BITMAPV5HEADER bitInfo = {0}; bitInfo.bV5Size = sizeof(BITMAPV5HEADER); bitInfo.bV5Width = info->width; - bitInfo.bV5Height = -(Int32)info->height; // this is topdown by default + bitInfo.bV5Height = -(int32_t)info->height; // this is topdown by default // default parameters bitInfo.bV5Planes = 1; @@ -2745,20 +2745,20 @@ PalResult PAL_CALL palCreateCursor( ReleaseDC(nullptr, hdc); // convert RGBA to BGRA - Uint8* pixels = (Uint8*)dibPixels; - for (Uint32 i = 0; i < info->width * info->height; i++) { - Uint8 r = info->pixels[i * 4 + 0]; // Red - Uint8 g = info->pixels[i * 4 + 1]; // Green - Uint8 b = info->pixels[i * 4 + 2]; // Blue - Uint8 a = info->pixels[i * 4 + 3]; // Alpha + uint8_t* pixels = (uint8_t*)dibPixels; + for (uint32_t i = 0; i < info->width * info->height; i++) { + uint8_t r = info->pixels[i * 4 + 0]; // Red + uint8_t g = info->pixels[i * 4 + 1]; // Green + uint8_t b = info->pixels[i * 4 + 2]; // Blue + uint8_t a = info->pixels[i * 4 + 3]; // Alpha // premultiply only if alpha is not 0 if (a == 0) { r = g = b = 0; } else { - r = (Uint8)((r * a) / 255); - g = (Uint8)((g * a) / 255); - b = (Uint8)((b * a) / 255); + r = (uint8_t)((r * a) / 255); + g = (uint8_t)((g * a) / 255); + b = (uint8_t)((b * a) / 255); } pixels[i * 4 + 0] = b; @@ -2892,8 +2892,8 @@ PalResult PAL_CALL palClipCursor( PalResult PAL_CALL palGetCursorPos( PalWindow* window, - Int32* x, - Int32* y) + int32_t* x, + int32_t* y) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -2923,8 +2923,8 @@ PalResult PAL_CALL palGetCursorPos( PalResult PAL_CALL palSetCursorPos( PalWindow* window, - Int32 x, - Int32 y) + int32_t x, + int32_t y) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; diff --git a/tests/core/logger_test.c b/tests/core/logger_test.c index 3dcabbb6..f022cce0 100644 --- a/tests/core/logger_test.c +++ b/tests/core/logger_test.c @@ -28,12 +28,12 @@ static void PAL_CALL onLogger( bool loggerTest() { PalLogger loggers[LOGGER_COUNT]; - for (Int32 i = 0; i < LOGGER_COUNT; i++) { + for (int32_t i = 0; i < LOGGER_COUNT; i++) { loggers[i].callback = onLogger; loggers[i].userData = (void*)g_LoggerNames[i]; } - for (Int32 i = 0; i < LOGGER_COUNT; i++) { + for (int32_t i = 0; i < LOGGER_COUNT; i++) { // push a log message to all loggers palLog(&loggers[i], "This is directed to a logger"); } diff --git a/tests/core/time_test.c b/tests/core/time_test.c index 1515a281..65b87009 100644 --- a/tests/core/time_test.c +++ b/tests/core/time_test.c @@ -3,14 +3,14 @@ // a simple timer object to hold frequency and start time typedef struct { - Uint64 frequency; - Uint64 startTime; + uint64_t frequency; + uint64_t startTime; } MyTimer; // get the time in seconds static inline double getTime(MyTimer* timer) { - Uint64 now = palGetPerformanceCounter(); + uint64_t now = palGetPerformanceCounter(); return (double)(now - timer->startTime) / (double)timer->frequency; } @@ -25,7 +25,7 @@ bool timeTest() double lastTime = getTime(&timer); double totalTime = 0.0; - Int32 frameCount = 0; + int32_t frameCount = 0; // run the loop for 5 seconds while (totalTime < 5.0) { diff --git a/tests/event/event_test.c b/tests/event/event_test.c index 37b41e7b..5115f37b 100644 --- a/tests/event/event_test.c +++ b/tests/event/event_test.c @@ -5,18 +5,18 @@ #define MAX_ITERATIONS 10 #define MAX_EVENTS 100000 -static Uint32 s_CallbackCounter = 0; -static Uint32 s_PollCounter = 0; +static uint32_t s_CallbackCounter = 0; +static uint32_t s_PollCounter = 0; typedef struct { - Uint64 frequency; - Uint64 startTime; + uint64_t frequency; + uint64_t startTime; } MyTimer; // get the time in seconds static inline double getTime(MyTimer* timer) { - Uint64 now = palGetPerformanceCounter(); + uint64_t now = palGetPerformanceCounter(); return (double)(now - timer->startTime) / (double)timer->frequency; } @@ -48,14 +48,14 @@ static inline void eventDispatchTest(bool poll) mode = PAL_DISPATCH_POLL; } - for (Uint32 e = 0; e < PAL_EVENT_MAX; e++) { + for (uint32_t e = 0; e < PAL_EVENT_MAX; e++) { palSetEventDispatchMode(driver, e, mode); } - Int32 counter = 0; + int32_t counter = 0; while (counter < MAX_EVENTS) { // push all types of event up to max - for (Int32 i = 0; i < MAX_EVENTS; i++) { + for (int32_t i = 0; i < MAX_EVENTS; i++) { PalEventType type = i % PAL_EVENT_MAX; PalEvent event = {0}; event.type = type; @@ -86,7 +86,7 @@ bool eventTest() // get start time double startTime = getTime(&timer); - for (Int32 i = 0; i < MAX_ITERATIONS; i++) { + for (int32_t i = 0; i < MAX_ITERATIONS; i++) { eventDispatchTest(false); // callback mode first } @@ -106,7 +106,7 @@ bool eventTest() // get start time startTime = getTime(&timer); - for (Int32 i = 0; i < MAX_ITERATIONS; i++) { + for (int32_t i = 0; i < MAX_ITERATIONS; i++) { eventDispatchTest(true); // poll mode first } diff --git a/tests/event/user_event_test.c b/tests/event/user_event_test.c index c7d50353..51c2c712 100644 --- a/tests/event/user_event_test.c +++ b/tests/event/user_event_test.c @@ -7,14 +7,14 @@ // a simple timer object to hold frequency and start time typedef struct { - Uint64 frequency; - Uint64 startTime; + uint64_t frequency; + uint64_t startTime; } MyTimer; // get the time in seconds static inline double getTime(MyTimer* timer) { - Uint64 now = palGetPerformanceCounter(); + uint64_t now = palGetPerformanceCounter(); return (double)(now - timer->startTime) / (double)timer->frequency; } diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index d6dd9fd5..33c0afb4 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -112,7 +112,7 @@ bool clearColorTest() } // enumerate all available adapters - Int32 adapterCount = 0; + int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -142,7 +142,7 @@ bool clearColorTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; - for (Int32 i = 0; i < adapterCount; i++) { + for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -260,7 +260,7 @@ bool clearColorTest() } // get all swapchain images and create image views for them - Uint32 imageCount = swapchainCreateInfo.imageCount; + uint32_t imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); @@ -348,7 +348,7 @@ bool clearColorTest() } // main loop - Uint32 currentFrame = 0; + uint32_t currentFrame = 0; bool running = true; while (running) { // update the video system to push video events @@ -386,7 +386,7 @@ bool clearColorTest() nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; nextImageInfo.timeout = PAL_INFINITE; - Uint32 imageIndex = 0; + uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index d4ee1ade..5acafda0 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -6,9 +6,9 @@ // layout must match shader typedef struct { - Uint32 width; - Uint32 height; - Uint32 _padding[2]; + uint32_t width; + uint32_t height; + uint32_t _padding[2]; float color[4]; } PushConstant; @@ -53,7 +53,7 @@ bool computeTest() } // enumerate all available adapters - Int32 adapterCount = 0; + int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -84,7 +84,7 @@ bool computeTest() PalAdapterCapabilities caps = {0}; PalAdapterFeatures adapterFeatures = 0; PalAdapterInfo adapterInfo = {0}; - for (Int32 i = 0; i < adapterCount; i++) { + for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -108,7 +108,7 @@ bool computeTest() } // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; + uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { @@ -169,7 +169,7 @@ bool computeTest() } // create a compute shader - Uint64 bytecodeSize = 0; + uint64_t bytecodeSize = 0; void* bytecode = nullptr; const char* source = nullptr; @@ -214,7 +214,7 @@ bool computeTest() palFree(nullptr, bytecode); // create a storage buffer - Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader + uint32_t bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader PalBufferCreateInfo bufferCreateInfo = {0}; bufferCreateInfo.size = bufferBytes; bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE | PAL_BUFFER_USAGE_TRANSFER_SRC; @@ -470,7 +470,7 @@ bool computeTest() buildData.workGroupCount[1] = caps.computeCaps.maxWorkGroupCount[1]; buildData.workGroupCount[2] = caps.computeCaps.maxWorkGroupCount[2]; - Uint32 workGroupInfoCount = 0; + uint32_t workGroupInfoCount = 0; PalWorkGroupInfo* workGroupInfos = nullptr; bool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); if (!ret) { @@ -491,9 +491,9 @@ bool computeTest() // palDispatchBase is not supported on all platforms so we dont use it for this example // We cap the buffer size small so we only get a single dispatch // but you can add fields in yout constants to send the base to the shader driectly - Uint32 groupCountX = workGroupInfos[i].workGroupCount[0]; - Uint32 groupCountY = workGroupInfos[i].workGroupCount[1]; - Uint32 groupCountZ = workGroupInfos[i].workGroupCount[2]; + uint32_t groupCountX = workGroupInfos[i].workGroupCount[0]; + uint32_t groupCountY = workGroupInfos[i].workGroupCount[1]; + uint32_t groupCountZ = workGroupInfos[i].workGroupCount[2]; result = palCmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); if (result != PAL_RESULT_SUCCESS) { @@ -577,7 +577,7 @@ bool computeTest() int row = BUFFER_SIZE - 1 - y; // flip y for (int x = 0; x < BUFFER_SIZE; x++) { int index = row * BUFFER_SIZE + x; - Uint8 rgb[3]; + uint8_t rgb[3]; rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index e27f0c32..efa7521d 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -17,21 +17,21 @@ // layout must match shader typedef struct { - Uint32 textureIndices[4]; + uint32_t textureIndices[4]; } PushConstant; static void createFlatTexture( - Uint32* texture, - Uint32 width, - Uint32 height, - Uint8 r, - Uint8 g, - Uint8 b) + uint32_t* texture, + uint32_t width, + uint32_t height, + uint8_t r, + uint8_t g, + uint8_t b) { - Uint8* pixels = (Uint8*)texture; - for (Int32 y = 0; y < height; ++y) { - for (Int32 x = 0; x < width; ++x) { - Int32 i = (y * width + x) * 4; + uint8_t* pixels = (uint8_t*)texture; + for (int32_t y = 0; y < height; ++y) { + for (int32_t x = 0; x < width; ++x) { + int32_t i = (y * width + x) * 4; pixels[i + 0] = r; pixels[i + 1] = g; pixels[i + 2] = b; @@ -162,7 +162,7 @@ bool descriptorIndexingTest() } // enumerate all available adapters - Int32 adapterCount = 0; + int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -193,7 +193,7 @@ bool descriptorIndexingTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; PalAdapterFeatures adapterFeatures; - for (Int32 i = 0; i < adapterCount; i++) { + for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -223,7 +223,7 @@ bool descriptorIndexingTest() } // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; + uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); if (target >= PAL_MAKE_SHADER_TARGET(1, 4)) { @@ -350,7 +350,7 @@ bool descriptorIndexingTest() } // get all swapchain images and create image views for them - Uint32 imageCount = swapchainCreateInfo.imageCount; + uint32_t imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); @@ -606,9 +606,9 @@ bool descriptorIndexingTest() bufferImageCopyInfo.imageHeight = TEXTURE_HEIGHT; bufferImageCopyInfo.imageDepth = 1; // 2D image - Uint64 imageCopyStagingBufferSize = 0; - Uint32 bufferRowLength = 0; - Uint32 bufferImageHeight = 0; + uint64_t imageCopyStagingBufferSize = 0; + uint32_t bufferRowLength = 0; + uint32_t bufferImageHeight = 0; result = palComputeImageCopyStagingBufferRequirements( device, @@ -632,7 +632,7 @@ bool descriptorIndexingTest() PalBuffer* imageStagingBuffers[4]; PalMemory* imageStagingBufferMemories[4]; - Uint32 textureDatas[4][TEXTURE_WIDTH * TEXTURE_HEIGHT]; + uint32_t textureDatas[4][TEXTURE_WIDTH * TEXTURE_HEIGHT]; createFlatTexture(textureDatas[0], TEXTURE_WIDTH, TEXTURE_HEIGHT, 255, 0, 0); createFlatTexture(textureDatas[1], TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, 255, 0); createFlatTexture(textureDatas[2], TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, 0, 255); @@ -878,7 +878,7 @@ bool descriptorIndexingTest() } // create shaders - Uint64 bytecodeSize = 0; + uint64_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; PalShaderEntryInfo entries[2]; @@ -1056,7 +1056,7 @@ bool descriptorIndexingTest() // we only write 4 descriptors - Uint32 arrElements[] = { ARRAY_ELEMENT_0, ARRAY_ELEMENT_1, ARRAY_ELEMENT_2, ARRAY_ELEMENT_3 }; + uint32_t arrElements[] = { ARRAY_ELEMENT_0, ARRAY_ELEMENT_1, ARRAY_ELEMENT_2, ARRAY_ELEMENT_3 }; PalDescriptorImageViewInfo descriptorImageInfos[4]; descriptorImageInfos[0].imageView = textureViews[0]; @@ -1202,7 +1202,7 @@ bool descriptorIndexingTest() } // main loop - Uint32 currentFrame = 0; + uint32_t currentFrame = 0; bool running = true; PalRect2D scissor = {0}; @@ -1251,7 +1251,7 @@ bool descriptorIndexingTest() nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; nextImageInfo.timeout = PAL_INFINITE; - Uint32 imageIndex = 0; + uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -1398,7 +1398,7 @@ bool descriptorIndexingTest() } // bind vertex buffer - Uint64 offset[] = {0}; + uint64_t offset[] = {0}; result = palCmdBindVertexBuffers( cmdBuffers[currentFrame], 0, diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index 7f95c135..8e2f3532 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -116,7 +116,7 @@ bool geometryTest() } // enumerate all available adapters - Int32 adapterCount = 0; + int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -147,7 +147,7 @@ bool geometryTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; PalAdapterFeatures adapterFeatures; - for (Int32 i = 0; i < adapterCount; i++) { + for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -177,7 +177,7 @@ bool geometryTest() } // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; + uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { @@ -295,7 +295,7 @@ bool geometryTest() } // get all swapchain images and create image views for them - Uint32 imageCount = swapchainCreateInfo.imageCount; + uint32_t imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); @@ -383,7 +383,7 @@ bool geometryTest() } // create shaders - Uint64 bytecodeSize = 0; + uint64_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[3]; PalShaderEntryInfo entries[3]; @@ -499,7 +499,7 @@ bool geometryTest() } // main loop - Uint32 currentFrame = 0; + uint32_t currentFrame = 0; bool running = true; PalRect2D scissor = {0}; @@ -542,7 +542,7 @@ bool geometryTest() nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; nextImageInfo.timeout = PAL_INFINITE; - Uint32 imageIndex = 0; + uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index fd514ac5..7e33ad7e 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -13,7 +13,7 @@ bool graphicsTest() } // enumerate all available adapters - Int32 count = 0; + int32_t count = 0; result = palEnumerateAdapters(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -47,7 +47,7 @@ bool graphicsTest() PalAdapterInfo info; PalAdapterCapabilities caps; PalAdapterFeatures features = 0; - for (Int32 i = 0; i < count; i++) { + for (int32_t i = 0; i < count; i++) { PalAdapter* adapter = adapters[i]; result = palGetAdapterInfo(adapter, &info); if (result != PAL_RESULT_SUCCESS) { @@ -105,8 +105,8 @@ bool graphicsTest() return false; } - Uint32 vramMb = (Uint32)info.vram / (1024 * 1024); - Uint32 sharedMemMb = (Uint32)info.sharedMemory /(1024 * 1024); + uint32_t vramMb = (uint32_t)info.vram / (1024 * 1024); + uint32_t sharedMemMb = (uint32_t)info.sharedMemory /(1024 * 1024); palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Backend Name: %s", info.backendName); @@ -248,9 +248,9 @@ bool graphicsTest() palLog(nullptr, " Max work group size[2]: %u", caps.computeCaps.maxWorkGroupSize[2]); // shader formats - Uint32 target; - Uint32 targetMajor = 0; - Uint32 targetMinor = 0; + uint32_t target; + uint32_t targetMajor = 0; + uint32_t targetMinor = 0; palLog(nullptr, ""); palLog(nullptr, " Supported Shader Formats:"); diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 5aeacbf7..f18ecaac 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -8,9 +8,9 @@ #define WINDOW_HEIGHT 480 #define MAX_FRAMES_IN_FLIGHT 2 -static inline Uint32 align( - Uint32 value, - Uint32 alignment) +static inline uint32_t align( + uint32_t value, + uint32_t alignment) { return (value + alignment - 1) & ~(alignment - 1); } @@ -133,7 +133,7 @@ bool indirectDrawTest() } // enumerate all available adapters - Int32 adapterCount = 0; + int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -164,7 +164,7 @@ bool indirectDrawTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; PalAdapterFeatures adapterFeatures; - for (Int32 i = 0; i < adapterCount; i++) { + for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -194,7 +194,7 @@ bool indirectDrawTest() } // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; + uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { @@ -312,7 +312,7 @@ bool indirectDrawTest() } // get all swapchain images and create image views for them - Uint32 imageCount = swapchainCreateInfo.imageCount; + uint32_t imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); @@ -409,7 +409,7 @@ bool indirectDrawTest() }; // clang-format on - Uint32 indices[6] = { 0, 1, 2, 2, 3, 0 }; + uint32_t indices[6] = { 0, 1, 2, 2, 3, 0 }; // vertex buffer PalBufferCreateInfo bufferCreateInfo = {0}; @@ -446,20 +446,20 @@ bool indirectDrawTest() } // staging buffer for vertex, index and indirect buffer - Uint32 offset = 0; - Uint32 indirectOffset = offset; + uint32_t offset = 0; + uint32_t indirectOffset = offset; offset += sizeof(PalDrawIndexedIndirectData); offset = align(offset, 16); - Uint32 indexOffset = offset; + uint32_t indexOffset = offset; offset += sizeof(indices); offset = align(offset, 16); - Uint32 vertexOffset = offset; + uint32_t vertexOffset = offset; offset += sizeof(vertices); offset = align(offset, 16); - Uint32 stagingBufferSize = offset; + uint32_t stagingBufferSize = offset; bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send bufferCreateInfo.size = offset; result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); @@ -611,7 +611,7 @@ bool indirectDrawTest() indirectData.instanceCount = 1; indirectData.vertexOffset = 0; - Uint8* dst = (Uint8*)ptr; + uint8_t* dst = (uint8_t*)ptr; memcpy(dst + indirectOffset, &indirectData, sizeof(PalDrawIndexedIndirectData)); // copy vertices @@ -752,7 +752,7 @@ bool indirectDrawTest() } // create shaders - Uint64 bytecodeSize = 0; + uint64_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; PalShaderEntryInfo entries[2]; @@ -895,7 +895,7 @@ bool indirectDrawTest() palFreeMemory(device, stagingBufferMemory); // main loop - Uint32 currentFrame = 0; + uint32_t currentFrame = 0; bool running = true; PalRect2D scissor = {0}; @@ -938,7 +938,7 @@ bool indirectDrawTest() nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; nextImageInfo.timeout = PAL_INFINITE; - Uint32 imageIndex = 0; + uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -1064,7 +1064,7 @@ bool indirectDrawTest() } // bind vertex buffer - Uint64 offset[] = {0}; + uint64_t offset[] = {0}; result = palCmdBindVertexBuffers( cmdBuffers[currentFrame], 0, diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 651f3e9c..27613231 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -116,7 +116,7 @@ bool meshTest() } // enumerate all available adapters - Int32 adapterCount = 0; + int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -147,7 +147,7 @@ bool meshTest() PalAdapterCapabilities caps = {0}; PalAdapterFeatures adapterFeatures = 0; PalAdapterInfo adapterInfo = {0}; - for (Int32 i = 0; i < adapterCount; i++) { + for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -177,7 +177,7 @@ bool meshTest() } // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; + uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); if (target >= PAL_MAKE_SHADER_TARGET(1, 5)) { @@ -296,7 +296,7 @@ bool meshTest() } // get all swapchain images and create image views for them - Uint32 imageCount = swapchainCreateInfo.imageCount; + uint32_t imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); @@ -384,7 +384,7 @@ bool meshTest() } // create shaders - Uint64 bytecodeSize = 0; + uint64_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; PalShaderEntryInfo entries[2]; @@ -494,7 +494,7 @@ bool meshTest() } // main loop - Uint32 currentFrame = 0; + uint32_t currentFrame = 0; bool running = true; PalRect2D scissor = {0}; @@ -537,7 +537,7 @@ bool meshTest() nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; nextImageInfo.timeout = PAL_INFINITE; - Uint32 imageIndex = 0; + uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 42221097..e9092f20 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -6,9 +6,9 @@ // layout must match shader typedef struct { - Uint32 width; - Uint32 height; - Uint32 _padding[2]; + uint32_t width; + uint32_t height; + uint32_t _padding[2]; float set1Color[4]; float set2Color[4]; float set3Color[4]; @@ -57,7 +57,7 @@ bool multiDescriptorSetTest() } // enumerate all available adapters - Int32 adapterCount = 0; + int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -88,7 +88,7 @@ bool multiDescriptorSetTest() PalAdapterCapabilities caps = {0}; PalAdapterFeatures adapterFeatures = 0; PalAdapterInfo adapterInfo = {0}; - for (Int32 i = 0; i < adapterCount; i++) { + for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -124,7 +124,7 @@ bool multiDescriptorSetTest() } // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; + uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { @@ -185,7 +185,7 @@ bool multiDescriptorSetTest() } // create a compute shader - Uint64 bytecodeSize = 0; + uint64_t bytecodeSize = 0; void* bytecode = nullptr; const char* source = nullptr; @@ -230,7 +230,7 @@ bool multiDescriptorSetTest() palFree(nullptr, bytecode); // create a storage buffer - Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader + uint32_t bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader PalBufferCreateInfo bufferCreateInfo = {0}; bufferCreateInfo.size = bufferBytes; @@ -527,7 +527,7 @@ bool multiDescriptorSetTest() buildData.workGroupCount[1] = caps.computeCaps.maxWorkGroupCount[1]; buildData.workGroupCount[2] = caps.computeCaps.maxWorkGroupCount[2]; - Uint32 workGroupInfoCount = 0; + uint32_t workGroupInfoCount = 0; PalWorkGroupInfo* workGroupInfos = nullptr; bool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); if (!ret) { @@ -548,9 +548,9 @@ bool multiDescriptorSetTest() // palDispatchBase is not supported on all platforms so we dont use it for this example // We cap the buffer size small so we only get a single dispatch // but you can add fields in yout constants to send the base to the shader driectly - Uint32 groupCountX = workGroupInfos[i].workGroupCount[0]; - Uint32 groupCountY = workGroupInfos[i].workGroupCount[1]; - Uint32 groupCountZ = workGroupInfos[i].workGroupCount[2]; + uint32_t groupCountX = workGroupInfos[i].workGroupCount[0]; + uint32_t groupCountY = workGroupInfos[i].workGroupCount[1]; + uint32_t groupCountZ = workGroupInfos[i].workGroupCount[2]; result = palCmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); if (result != PAL_RESULT_SUCCESS) { @@ -647,7 +647,7 @@ bool multiDescriptorSetTest() int row = BUFFER_SIZE - 1 - y; // flip y for (int x = 0; x < BUFFER_SIZE; x++) { int index = row * BUFFER_SIZE + x; - Uint8 rgb[3]; + uint8_t rgb[3]; rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 1baa0af1..5407254f 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -17,9 +17,9 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -static inline Uint32 _max( - Uint32 a, - Uint32 b) +static inline uint32_t _max( + uint32_t a, + uint32_t b) { return (a > b) ? a : b; } @@ -73,7 +73,7 @@ bool rayTracingTest() } // enumerate all available adapters - Int32 adapterCount = 0; + int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -104,7 +104,7 @@ bool rayTracingTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; PalAdapterFeatures adapterFeatures = 0; - for (Int32 i = 0; i < adapterCount; i++) { + for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -140,7 +140,7 @@ bool rayTracingTest() } // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; + uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); if (target >= PAL_MAKE_SHADER_TARGET(1, 4)) { @@ -203,7 +203,7 @@ bool rayTracingTest() } // create ray tracing shaders - Uint64 bytecodeSize = 0; + uint64_t bytecodeSize = 0; void* bytecode = nullptr; const char* source = nullptr; PalShaderEntryInfo entries[3]; @@ -256,7 +256,7 @@ bool rayTracingTest() palFree(nullptr, bytecode); - Uint32 bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader + uint32_t bufferBytes = BUFFER_SIZE * BUFFER_SIZE * sizeof(float) * 4; // must match shader PalBufferCreateInfo bufferCreateInfo = {0}; bufferCreateInfo.size = bufferBytes; bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE | PAL_BUFFER_USAGE_TRANSFER_SRC; @@ -494,7 +494,7 @@ bool rayTracingTest() }; memcpy(asInstance.transform, transform, sizeof(float) * 12); - Uint64 instanceBufferSize = 0; + uint64_t instanceBufferSize = 0; result = palComputeInstanceBufferRequirements( device, 1, @@ -578,7 +578,7 @@ bool rayTracingTest() tlasBuildInfo.buildMode = PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD; // get the build sizes for tlas - Uint32 blasScratchSize = buildSizes.scratchBufferSize; + uint32_t blasScratchSize = buildSizes.scratchBufferSize; result = palGetAccelerationStructureBuildSize(device, &tlasBuildInfo, &buildSizes); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -1038,7 +1038,7 @@ bool rayTracingTest() int row = BUFFER_SIZE - 1 - y; // flip y for (int x = 0; x < BUFFER_SIZE; x++) { int index = row * BUFFER_SIZE + x; - Uint8 rgb[3]; + uint8_t rgb[3]; rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; @@ -1187,7 +1187,7 @@ bool rayTracingTest() int row = BUFFER_SIZE - 1 - y; // flip y for (int x = 0; x < BUFFER_SIZE; x++) { int index = row * BUFFER_SIZE + x; - Uint8 rgb[3]; + uint8_t rgb[3]; rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 659c98b3..a98be67f 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -12,15 +12,15 @@ #define CHECKER_SIZE 16 static void createCheckerboardTexture( - Uint32* texture, - Uint32 width, - Uint32 height, - Uint32 checkerSize) + uint32_t* texture, + uint32_t width, + uint32_t height, + uint32_t checkerSize) { - Uint8* pixels = (Uint8*)texture; - for (Int32 y = 0; y < height; ++y) { - for (Int32 x = 0; x < width; ++x) { - Int32 i = (y * width + x) * 4; + uint8_t* pixels = (uint8_t*)texture; + for (int32_t y = 0; y < height; ++y) { + for (int32_t x = 0; x < width; ++x) { + int32_t i = (y * width + x) * 4; int checker = ((x / checkerSize) ^ (y / checkerSize)) & 1; if (checker) { pixels[i + 0] = 255; // Red bit @@ -155,7 +155,7 @@ bool textureTest() } // enumerate all available adapters - Int32 adapterCount = 0; + int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -185,7 +185,7 @@ bool textureTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; - for (Int32 i = 0; i < adapterCount; i++) { + for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -209,7 +209,7 @@ bool textureTest() } // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; + uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { @@ -327,7 +327,7 @@ bool textureTest() } // get all swapchain images and create image views for them - Uint32 imageCount = swapchainCreateInfo.imageCount; + uint32_t imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); @@ -529,7 +529,7 @@ bool textureTest() // we dont want to load the texture from disk so we will create a // checkerboard texture and use that rather - Uint32 texture[TEXTURE_WIDTH * TEXTURE_HEIGHT]; + uint32_t texture[TEXTURE_WIDTH * TEXTURE_HEIGHT]; memset(texture, 0, TEXTURE_WIDTH * TEXTURE_HEIGHT); createCheckerboardTexture(texture, TEXTURE_WIDTH, TEXTURE_HEIGHT, CHECKER_SIZE); @@ -589,9 +589,9 @@ bool textureTest() bufferImageCopyInfo.imageHeight = TEXTURE_HEIGHT; bufferImageCopyInfo.imageDepth = 1; // 2D image - Uint64 imageCopyStagingBufferSize = 0; - Uint32 bufferRowLength = 0; - Uint32 bufferImageHeight = 0; + uint64_t imageCopyStagingBufferSize = 0; + uint32_t bufferRowLength = 0; + uint32_t bufferImageHeight = 0; result = palComputeImageCopyStagingBufferRequirements( device, @@ -842,7 +842,7 @@ bool textureTest() } // create shaders - Uint64 bytecodeSize = 0; + uint64_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; PalShaderEntryInfo entries[2]; @@ -1085,7 +1085,7 @@ bool textureTest() palFreeMemory(device, imageStagingBufferMemory); // main loop - Uint32 currentFrame = 0; + uint32_t currentFrame = 0; bool running = true; PalRect2D scissor = {0}; @@ -1128,7 +1128,7 @@ bool textureTest() nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; nextImageInfo.timeout = PAL_INFINITE; - Uint32 imageIndex = 0; + uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -1261,7 +1261,7 @@ bool textureTest() } // bind vertex buffer - Uint64 offset[] = {0}; + uint64_t offset[] = {0}; result = palCmdBindVertexBuffers( cmdBuffers[currentFrame], 0, diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index dca53bcc..56f053a4 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -121,7 +121,7 @@ bool triangleTest() } // enumerate all available adapters - Int32 adapterCount = 0; + int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -151,7 +151,7 @@ bool triangleTest() PalAdapterCapabilities caps = {0}; PalAdapterInfo adapterInfo = {0}; - for (Int32 i = 0; i < adapterCount; i++) { + for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { @@ -175,7 +175,7 @@ bool triangleTest() } // we prefer spirv first if an adapter supports multiple shader formats - Uint32 target = 0; + uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { target = palGetHighestSupportedShaderTarget(adapter, PAL_SHADER_FORMAT_SPIRV); if (target >= PAL_MAKE_SHADER_TARGET(1, 0)) { @@ -293,7 +293,7 @@ bool triangleTest() } // get all swapchain images and create image views for them - Uint32 imageCount = swapchainCreateInfo.imageCount; + uint32_t imageCount = swapchainCreateInfo.imageCount; imageViews = palAllocate(nullptr, sizeof(PalImageView*) * imageCount, 0); inFlightImages = palAllocate(nullptr, sizeof(PalFence*) * imageCount, 0); renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); @@ -545,7 +545,7 @@ bool triangleTest() } // create shaders - Uint64 bytecodeSize = 0; + uint64_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; PalShaderEntryInfo entries[2]; @@ -688,7 +688,7 @@ bool triangleTest() palFreeMemory(device, stagingBufferMemory); // main loop - Uint32 currentFrame = 0; + uint32_t currentFrame = 0; bool running = true; PalRect2D scissor = {0}; @@ -731,7 +731,7 @@ bool triangleTest() nextImageInfo.signalSemaphore = imageAvailableSemaphores[currentFrame]; nextImageInfo.timeout = PAL_INFINITE; - Uint32 imageIndex = 0; + uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -857,7 +857,7 @@ bool triangleTest() } // bind vertex buffer - Uint64 offset[] = {0}; + uint64_t offset[] = {0}; result = palCmdBindVertexBuffers( cmdBuffers[currentFrame], 0, diff --git a/tests/opengl/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c index d747edbd..0c7db0d3 100644 --- a/tests/opengl/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -11,7 +11,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARCOLORPROC)( float blue, float alpha); -typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(Uint32 mask); // use GL typedefs if needed +typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(uint32_t mask); // use GL typedefs if needed typedef void (*glFlushFn)(); typedef void (*glBeginFn)(unsigned int); @@ -130,7 +130,7 @@ static void* PAL_CALL rendererWorkder(void* arg) while (palPollEvent(shared->openglEventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_SIZE: { - Uint32 width, height; + uint32_t width, height; palUnpackUint32(event.data, &width, &height); palLog(nullptr, "Video driver sent a resize event (%d, %d)", width, height); @@ -231,7 +231,7 @@ bool multiThreadOpenGlTest() } // get all FBConfigs and select one - Int32 fbCount = 0; + int32_t fbCount = 0; result = palEnumerateGLFBConfigs(nullptr, &fbCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); diff --git a/tests/opengl/opengl_context_test.c b/tests/opengl/opengl_context_test.c index cd9b7cab..7f9d5dc6 100644 --- a/tests/opengl/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -12,7 +12,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARCOLORPROC)( float blue, float alpha); -typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(Uint32 mask); // use GL typedefs if needed +typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(uint32_t mask); // use GL typedefs if needed bool openglContextTest() { @@ -61,7 +61,7 @@ bool openglContextTest() PalGLContext* context = nullptr; PalWindowCreateInfo createInfo = {0}; PalGLContextCreateInfo contextCreateInfo = {0}; - Int32 fbCount = 0; + int32_t fbCount = 0; bool running = false; // enumerate supported opengl framebuffer configs diff --git a/tests/opengl/opengl_fbconfig_test.c b/tests/opengl/opengl_fbconfig_test.c index c4f15ada..a00baa96 100644 --- a/tests/opengl/opengl_fbconfig_test.c +++ b/tests/opengl/opengl_fbconfig_test.c @@ -28,7 +28,7 @@ bool openglFBConfigTest() } // enumerate supported opengl framebuffer configs - Int32 fbCount = 0; + int32_t fbCount = 0; result = palEnumerateGLFBConfigs(nullptr, &fbCount, nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); @@ -60,7 +60,7 @@ bool openglFBConfigTest() // log configs palLog(nullptr, ""); - for (Int32 i = 0; i < fbCount; i++) { + for (int32_t i = 0; i < fbCount; i++) { // log pixel formate PalGLFBConfig* config = &fbConfigs[i]; palLog(nullptr, "FB Config Index: %d", config->index); diff --git a/tests/opengl/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c index 2923922c..9d3d7c18 100644 --- a/tests/opengl/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -12,7 +12,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARCOLORPROC)( float blue, float alpha); -typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(Uint32 mask); // use GL typedefs if needed +typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(uint32_t mask); // use GL typedefs if needed bool openglMultiContextTest() { @@ -61,7 +61,7 @@ bool openglMultiContextTest() PalGLContext* context = nullptr; PalWindowCreateInfo createInfo = {0}; PalGLContextCreateInfo contextCreateInfo = {0}; - Int32 fbCount = 0; + int32_t fbCount = 0; bool running = false; // enumerate supported opengl framebuffer configs diff --git a/tests/system/system_test.c b/tests/system/system_test.c index 0580d971..6f3c77e1 100644 --- a/tests/system/system_test.c +++ b/tests/system/system_test.c @@ -91,7 +91,7 @@ bool systemTest() palLog(nullptr, " Total RAM: %llu MB", platformInfo.totalRAM); palLog(nullptr, " Total Memory: %llu GB", platformInfo.totalMemory); - Uint16 major, minor, build; + uint16_t major, minor, build; major = platformInfo.version.major; minor = platformInfo.version.minor; build = platformInfo.version.build; @@ -99,7 +99,7 @@ bool systemTest() // log cpu information const char* archString = cpuArchToString(cpuInfo.architecture); - Int32 processors = cpuInfo.numLogicalProcessors; + int32_t processors = cpuInfo.numLogicalProcessors; palLog(nullptr, " Cpu: %s", cpuInfo.model); palLog(nullptr, " Vendor: %s", cpuInfo.vendor); diff --git a/tests/tests.c b/tests/tests.c index 04c0e382..547c6c93 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -8,7 +8,7 @@ typedef struct { const char* name; } TestEntry; -static Uint32 s_Count = 0; +static uint32_t s_Count = 0; static TestEntry s_Test[MAX_TESTS]; static const char* s_FailedString = "FAILED"; static const char* s_PassedString = "PASSED"; @@ -23,7 +23,7 @@ void runTests() { bool status = false; const char* statusString = nullptr; - for (Int32 i = 0; i < s_Count; i++) { + for (int32_t i = 0; i < s_Count; i++) { palLog(nullptr, ""); palLog(nullptr, "==========================================="); palLog(nullptr, s_Test[i].name); diff --git a/tests/tests.h b/tests/tests.h index 6a1a82dd..fa8d3e3c 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -13,7 +13,7 @@ void runTests(); static bool readFile( const char* filename, void* buffer, - Uint64* size) + uint64_t* size) { FILE* file = fopen(filename, "rb"); if (!file) { @@ -21,7 +21,7 @@ static bool readFile( } fseek(file, 0, SEEK_END); - Uint64 tmpSize = ftell(file); + uint64_t tmpSize = ftell(file); fseek(file, 0, SEEK_SET); if (buffer) { diff --git a/tests/thread/condvar_test.c b/tests/thread/condvar_test.c index dfbf3300..adef63b3 100644 --- a/tests/thread/condvar_test.c +++ b/tests/thread/condvar_test.c @@ -10,7 +10,7 @@ static PalCondVar* g_Condition; typedef struct { bool ready; - Uint32 id; + uint32_t id; } ThreadData; static void* PAL_CALL worker(void* arg) @@ -61,7 +61,7 @@ bool condvarTest() createInfo.entry = worker; // will be the same for all threads createInfo.stackSize = 0; // same for all threads createInfo.allocator = nullptr; // default - for (Int32 i = 0; i < THREAD_COUNT; i++) { + for (int32_t i = 0; i < THREAD_COUNT; i++) { ThreadData* threadData = &data[i]; threadData->id = i + 1; threadData->ready = false; @@ -97,7 +97,7 @@ bool condvarTest() // broadcast to all remaining threads palLockMutex(g_Mutex); - for (Int32 i = 1; i < THREAD_COUNT; i++) { + for (int32_t i = 1; i < THREAD_COUNT; i++) { data[i].ready = true; } @@ -106,7 +106,7 @@ bool condvarTest() // wait for the remaining threads // joint threads does not need to be detached - for (Int32 i = 0; i < THREAD_COUNT; i++) { + for (int32_t i = 0; i < THREAD_COUNT; i++) { palJoinThread(threads[i], nullptr); palLog(nullptr, "Thread %d finished successfully", data[i].id); } diff --git a/tests/thread/mutex_test.c b/tests/thread/mutex_test.c index 3a158697..7ba7a2bb 100644 --- a/tests/thread/mutex_test.c +++ b/tests/thread/mutex_test.c @@ -7,7 +7,7 @@ typedef struct { PalMutex* mutex; - Int32 counter; + int32_t counter; } SharedData; static void* PAL_CALL worker(void* arg) @@ -16,7 +16,7 @@ static void* PAL_CALL worker(void* arg) // this is only needed when two or more threads are writing to the same // variable - for (Int32 i = 0; i < MAX_COUNTER; i++) { + for (int32_t i = 0; i < MAX_COUNTER; i++) { palLockMutex(data->mutex); data->counter++; // a shared variable. we need lock and unlocks palLog(nullptr, "Counter: %d", data->counter); @@ -53,7 +53,7 @@ bool mutexTest() createInfo.entry = worker; // will be the same for all threads createInfo.stackSize = 0; // same for all threads createInfo.allocator = nullptr; // default - for (Int32 i = 0; i < THREAD_COUNT; i++) { + for (int32_t i = 0; i < THREAD_COUNT; i++) { createInfo.arg = (void*)data; // create thread @@ -67,7 +67,7 @@ bool mutexTest() // join the threads to main thread // joint threads does not need to be detached - for (Int32 i = 0; i < THREAD_COUNT; i++) { + for (int32_t i = 0; i < THREAD_COUNT; i++) { palJoinThread(threads[i], nullptr); } diff --git a/tests/thread/thread_test.c b/tests/thread/thread_test.c index 84d6db64..6b9f6415 100644 --- a/tests/thread/thread_test.c +++ b/tests/thread/thread_test.c @@ -8,7 +8,7 @@ static void* PAL_CALL worker(void* arg) { // palLog is thread safe so there should'nt be any race conditions - Int32 id = (Int32)(IntPtr)arg; + int32_t id = (int32_t)(intptr_t)arg; palLog(nullptr, "Thread %d: started", id); palSleep(THREAD_TIME * id); @@ -26,8 +26,8 @@ bool threadTest() createInfo.entry = worker; // will be the same for all threads createInfo.stackSize = 0; // same for all threads createInfo.allocator = nullptr; // default - for (Int32 i = 0; i < THREAD_COUNT; i++) { - createInfo.arg = (void*)((IntPtr)i + 1); + for (int32_t i = 0; i < THREAD_COUNT; i++) { + createInfo.arg = (void*)((intptr_t)i + 1); // create thread result = palCreateThread(&createInfo, &threads[i]); @@ -39,7 +39,7 @@ bool threadTest() } // join threads - for (Int32 i = 0; i < THREAD_COUNT; i++) { + for (int32_t i = 0; i < THREAD_COUNT; i++) { // we dont need the return value // joint threads does not need to be detached result = palJoinThread(threads[i], nullptr); diff --git a/tests/thread/tls_test.c b/tests/thread/tls_test.c index 53498c15..51619774 100644 --- a/tests/thread/tls_test.c +++ b/tests/thread/tls_test.c @@ -5,7 +5,7 @@ // data every thread will have its own copy of typedef struct { const char* name; - Uint32 number; + uint32_t number; } TlsData; // thread data diff --git a/tests/video/attach_window_test.c b/tests/video/attach_window_test.c index d4b48a7f..ee55fd2d 100644 --- a/tests/video/attach_window_test.c +++ b/tests/video/attach_window_test.c @@ -121,7 +121,7 @@ static void* createX11Window() s_XMapRaised(display, window); s_XSync(display, False); - return (void*)(UintPtr)window; + return (void*)(uintptr_t)window; #endif // __linux__ return nullptr; } @@ -182,7 +182,7 @@ static void destroyX11Window(void* windowHandle) { #ifdef __linux__ Display* display = palGetInstance(); - s_XDestroyWindow(display, (Window)(UintPtr)windowHandle); + s_XDestroyWindow(display, (Window)(uintptr_t)windowHandle); dlclose(s_LibX); // we loaded dynamically #endif } @@ -285,7 +285,7 @@ bool attachWindowTest() bool running = true; bool detached = false; - Int32 counter = 0; + int32_t counter = 0; while (running) { // update the video system to push video events palUpdateVideo(); @@ -304,7 +304,7 @@ bool attachWindowTest() case PAL_EVENT_WINDOW_MOVE: { // this will be triggered for our attached window - Int32 x, y; // x == low, y == high + int32_t x, y; // x == low, y == high palUnpackInt32(event.data, &x, &y); palLog(nullptr, "Window Moved: (%d, %d)", x, y); break; @@ -324,7 +324,7 @@ bool attachWindowTest() // since if the window is detached, // we wont recieve the key up event // keycode == low, scancode == high - Uint32 keycode; + uint32_t keycode; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_D) { palDetachWindow(myWindow, nullptr); diff --git a/tests/video/char_event_test.c b/tests/video/char_event_test.c index e99da998..35622527 100644 --- a/tests/video/char_event_test.c +++ b/tests/video/char_event_test.c @@ -74,7 +74,7 @@ bool charEventTest() } case PAL_EVENT_KEYCHAR: { - Uint32 codepoint = (Uint32)event.data; + uint32_t codepoint = (uint32_t)event.data; PalWindow* window = palUnpackPointer(event.data2); // we log the codepoint diff --git a/tests/video/cursor_test.c b/tests/video/cursor_test.c index 0f157d0d..bdaac0b3 100644 --- a/tests/video/cursor_test.c +++ b/tests/video/cursor_test.c @@ -52,10 +52,10 @@ bool cursorTest() // simple checkerboard RGBA pixel buffer // every block contains 64 pixels - Uint8 pixels[32 * 32 * 4]; // size is 32 and we have 4 channles - for (Int32 y = 0; y < 32; ++y) { - for (Int32 x = 0; x < 32; ++x) { - Int32 i = (y * 32 + x) * 4; + uint8_t pixels[32 * 32 * 4]; // size is 32 and we have 4 channles + for (int32_t y = 0; y < 32; ++y) { + for (int32_t x = 0; x < 32; ++x) { + int32_t i = (y * 32 + x) * 4; int checker = ((x / 8) ^ (y / 8)) & 1; if (checker) { pixels[i + 0] = 255; // Red bit diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index 00d3c27a..d22f9910 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -42,9 +42,9 @@ typedef struct { struct wl_buffer* buffer; struct wl_surface* surface; struct wl_subsurface* subsurface; - Uint32* pixels; + uint32_t* pixels; PalEventDriver* driver; // a pointer to the event driver - Uint64 size; + uint64_t size; } WaylandDecoration; static struct wl_display* s_Display = nullptr; @@ -506,7 +506,7 @@ static void closeDisplayWayland() dlclose(s_LibWayland); } -static int createShmFile(Uint64 size) +static int createShmFile(uint64_t size) { char template[] = "/tmp/pal-shm-XXXXXX"; int fd = mkstemp(template); @@ -526,11 +526,11 @@ static struct wl_buffer* createShmBuffer( int width, int height, int* outFd, - Uint64* outSize, - Uint32** outPixels) + uint64_t* outSize, + uint32_t** outPixels) { int stride = width * 4; - Uint64 size = stride * height; + uint64_t size = stride * height; struct wl_buffer* buffer = nullptr; struct wl_shm_pool* pool = nullptr; void* data = nullptr; @@ -557,7 +557,7 @@ static struct wl_buffer* createShmBuffer( wlShmPoolDestroy(pool); - *outPixels = (Uint32*)data; + *outPixels = (uint32_t*)data; *outFd = fd; *outSize = size; return buffer; @@ -582,7 +582,7 @@ void fillRect( // a simple 8x8 bitmap font // exchange with your font // Each byte = one row of 8 pixels, MSB = leftmost pixel -static const Uint8 s_FontBasic[128][8] = { +static const uint8_t s_FontBasic[128][8] = { ['A'] = {0x18, 0x24, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42}, ['B'] = {0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x42, 0x7C}, ['C'] = {0x3C, 0x42, 0x40, 0x40, 0x40, 0x40, 0x42, 0x3C}, @@ -788,7 +788,7 @@ static void PAL_CALL onEvent( const PalEvent* event) { if (event->type == PAL_EVENT_MOUSE_BUTTONDOWN) { - Uint32 button, serial; + uint32_t button, serial; palUnpackUint32(event->data, &button, &serial); if (button == PAL_MOUSE_BUTTON_LEFT) { @@ -823,7 +823,7 @@ static void PAL_CALL onEvent( } } else if (event->type == PAL_EVENT_MOUSE_MOVE) { - Int32 x, y; + int32_t x, y; palUnpackInt32(event->data, &x, &y); s_Decoration.mouseX = x; s_Decoration.mouseY = y; diff --git a/tests/video/icon_test.c b/tests/video/icon_test.c index fba46c6f..93ac094d 100644 --- a/tests/video/icon_test.c +++ b/tests/video/icon_test.c @@ -52,10 +52,10 @@ bool iconTest() // simple checkerboard RGBA pixel buffer // every block contains 64 pixels - Uint8 pixels[32 * 32 * 4]; // size is 32 and we have 4 channles - for (Int32 y = 0; y < 32; ++y) { - for (Int32 x = 0; x < 32; ++x) { - Int32 i = (y * 32 + x) * 4; + uint8_t pixels[32 * 32 * 4]; // size is 32 and we have 4 channles + for (int32_t y = 0; y < 32; ++y) { + for (int32_t x = 0; x < 32; ++x) { + int32_t i = (y * 32 + x) * 4; int checker = ((x / 8) ^ (y / 8)) & 1; if (checker) { pixels[i + 0] = 255; // Red bit diff --git a/tests/video/input_window_test.c b/tests/video/input_window_test.c index 164427a3..d84c171a 100644 --- a/tests/video/input_window_test.c +++ b/tests/video/input_window_test.c @@ -277,7 +277,7 @@ static bool s_Running = false; // inline helpers static inline void onKeydown(const PalEvent* event) { - Uint32 keycode, scancode; // keycode == low, scancode == high + uint32_t keycode, scancode; // keycode == low, scancode == high palUnpackUint32(event->data, &keycode, &scancode); PalWindow* window = palUnpackPointer(event->data2); @@ -293,7 +293,7 @@ static inline void onKeydown(const PalEvent* event) static inline void onKeyrepeat(const PalEvent* event) { - Uint32 keycode, scancode; // keycode == low, scancode == high + uint32_t keycode, scancode; // keycode == low, scancode == high palUnpackUint32(event->data, &keycode, &scancode); PalWindow* window = palUnpackPointer(event->data2); @@ -305,7 +305,7 @@ static inline void onKeyrepeat(const PalEvent* event) static inline void onKeyup(const PalEvent* event) { - Uint32 keycode, scancode; // keycode == low, scancode == high + uint32_t keycode, scancode; // keycode == low, scancode == high palUnpackUint32(event->data, &keycode, &scancode); PalWindow* window = palUnpackPointer(event->data2); @@ -317,7 +317,7 @@ static inline void onKeyup(const PalEvent* event) static inline void onMouseButtondown(const PalEvent* event) { - Uint32 button, serial; // button == low, serial == high + uint32_t button, serial; // button == low, serial == high palUnpackUint32(event->data, &button, &serial); PalWindow* window = palUnpackPointer(event->data2); @@ -328,7 +328,7 @@ static inline void onMouseButtondown(const PalEvent* event) static inline void onMouseButtonup(const PalEvent* event) { - Uint32 button, serial; // button == low, serial == high + uint32_t button, serial; // button == low, serial == high palUnpackUint32(event->data, &button, &serial); PalWindow* window = palUnpackPointer(event->data2); @@ -339,7 +339,7 @@ static inline void onMouseButtonup(const PalEvent* event) static inline void onMouseMove(const PalEvent* event) { - Int32 x, y; // x == low, y == high + int32_t x, y; // x == low, y == high palUnpackInt32(event->data, &x, &y); PalWindow* window = palUnpackPointer(event->data2); palLog(nullptr, "%s: Mouse Moved: (%d, %d)", dispatchString, x, y); @@ -347,7 +347,7 @@ static inline void onMouseMove(const PalEvent* event) static inline void onMouseDelta(const PalEvent* event) { - Int32 dx, dy; // dx == low, dy == high + int32_t dx, dy; // dx == low, dy == high palUnpackInt32(event->data, &dx, &dy); PalWindow* window = palUnpackPointer(event->data2); palLog(nullptr, "%s: Mouse Delta: (%d, %d)", dispatchString, dx, dy); @@ -355,7 +355,7 @@ static inline void onMouseDelta(const PalEvent* event) static inline void onMouseWheel(const PalEvent* event) { - Int32 dx, dy; // dx == low, dy == high + int32_t dx, dy; // dx == low, dy == high palUnpackInt32(event->data, &dx, &dy); // get the raw wheel delta (float) @@ -469,7 +469,7 @@ bool inputWindowTest() #endif // DISPATCH_MODE_POLL // set dispatch mode for all events. - for (Uint32 e = PAL_EVENT_KEYDOWN; e < PAL_EVENT_USER; e++) { + for (uint32_t e = PAL_EVENT_KEYDOWN; e < PAL_EVENT_USER; e++) { palSetEventDispatchMode(eventDriver, e, dispatchMode); } diff --git a/tests/video/monitor_mode_test.c b/tests/video/monitor_mode_test.c index 18e9db48..b853f5b2 100644 --- a/tests/video/monitor_mode_test.c +++ b/tests/video/monitor_mode_test.c @@ -5,8 +5,8 @@ bool monitorModeTest() { PalMonitorInfo info; - Int32 count = 0; - Int32 modeCount = 0; + int32_t count = 0; + int32_t modeCount = 0; // initialize the video system PalResult result = palInitVideo(nullptr, nullptr); @@ -49,7 +49,7 @@ bool monitorModeTest() } // get monitor info for every monitor and log the information - for (Int32 i = 0; i < count; i++) { + for (int32_t i = 0; i < count; i++) { PalMonitor* monitor = monitors[i]; result = palGetMonitorInfo(monitor, &info); if (result != PAL_RESULT_SUCCESS) { @@ -89,7 +89,7 @@ bool monitorModeTest() return false; } - for (Int32 i = 0; i < modeCount; i++) { + for (int32_t i = 0; i < modeCount; i++) { // log monitor mode PalMonitorMode* mode = &modes[i]; palLog(nullptr, " Mode Index: %d", i); diff --git a/tests/video/monitor_test.c b/tests/video/monitor_test.c index 33c11978..8542f311 100644 --- a/tests/video/monitor_test.c +++ b/tests/video/monitor_test.c @@ -5,7 +5,7 @@ bool monitorTest() { PalMonitorInfo info; - Int32 count = 0; + int32_t count = 0; // initialize the video system PalResult result = palInitVideo(nullptr, nullptr); @@ -48,7 +48,7 @@ bool monitorTest() } // get monitor info for every monitor and log the information - for (Int32 i = 0; i < count; i++) { + for (int32_t i = 0; i < count; i++) { PalMonitor* monitor = monitors[i]; result = palGetMonitorInfo(monitor, &info); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/video/native_integration_test.c b/tests/video/native_integration_test.c index 89777ce4..a62b58fd 100644 --- a/tests/video/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -161,7 +161,7 @@ void setWindowTitleX11(PalWindowHandleInfoEx* windowInfo) // clang-format on Display* display = (Display*)windowInfo->nativeDisplay; - Window window = (Window)(UintPtr)windowInfo->nativeWindow; + Window window = (Window)(uintptr_t)windowInfo->nativeWindow; s_NET_WM_NAME = s_XInternAtom(display, "_NET_WM_NAME", False); s_UTF8_STRING = s_XInternAtom(display, "UTF8_STRING", False); @@ -190,7 +190,7 @@ void getWindowTitleX11(PalWindowHandleInfoEx* windowInfo) { #ifdef __linux__ Display* display = (Display*)windowInfo->nativeDisplay; - Window window = (Window)(UintPtr)windowInfo->nativeWindow; + Window window = (Window)(uintptr_t)windowInfo->nativeWindow; if (s_NET_WM_NAME) { Atom type; diff --git a/tests/video/window_test.c b/tests/video/window_test.c index 3b65142b..8d350330 100644 --- a/tests/video/window_test.c +++ b/tests/video/window_test.c @@ -30,7 +30,7 @@ static const char* dispatchString = "Callback Mode"; // inline helpers static inline void onWindowResize(const PalEvent* event) { - Uint32 width, height; // width == low, height == high + uint32_t width, height; // width == low, height == high palUnpackUint32(event->data, &width, &height); PalWindow* window = palUnpackPointer(event->data2); palLog(nullptr, "%s: Window Resized: (%d, %d)", dispatchString, width, height); @@ -38,7 +38,7 @@ static inline void onWindowResize(const PalEvent* event) static inline void onWindowMove(const PalEvent* event) { - Int32 x, y; // x == low, y == high + int32_t x, y; // x == low, y == high palUnpackInt32(event->data, &x, &y); PalWindow* window = palUnpackPointer(event->data2); palLog(nullptr, "%s: Window Moved: (%d, %d)", dispatchString, x, y); @@ -177,7 +177,7 @@ bool windowTest() #endif // DISPATCH_MODE_POLL // set dispatch mode for all events. - for (Uint32 e = 0; e < PAL_EVENT_KEYDOWN; e++) { + for (uint32_t e = 0; e < PAL_EVENT_KEYDOWN; e++) { palSetEventDispatchMode(eventDriver, e, dispatchMode); } From 3f615fc8ad2e40038bc135526d3f80eda446713a Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 14 Jun 2026 14:23:47 +0000 Subject: [PATCH 258/372] fold core system includes into pal_core.h --- CHANGELOG.md | 74 ++-- include/pal/core/defines.h | 67 --- include/pal/core/log.h | 67 --- include/pal/core/memory.h | 106 ----- include/pal/core/pack.h | 202 --------- include/pal/core/result.h | 101 ----- include/pal/core/time.h | 46 -- include/pal/core/version.h | 57 --- include/pal/pal_core.h | 464 ++++++++++++++++++++- include/pal/pal_event.h | 4 +- include/pal/pal_graphics.h | 112 ++--- include/pal/pal_opengl.h | 12 +- include/pal/pal_video.h | 39 +- src/core/pal_log.c | 2 +- src/graphics/pal_d3d12.c | 84 ++-- src/graphics/pal_graphics.c | 46 +- src/graphics/pal_vulkan.c | 80 ++-- src/opengl/pal_opengl_linux.c | 8 +- src/opengl/pal_opengl_win32.c | 6 +- src/pal_event.c | 6 +- src/system/pal_system_win32.c | 4 +- src/video/pal_video_linux.c | 90 ++-- src/video/pal_video_win32.c | 60 +-- tests/core/logger_test.c | 2 +- tests/core/time_test.c | 2 +- tests/event/event_test.c | 4 +- tests/event/user_event_test.c | 4 +- tests/graphics/clear_color_test.c | 6 +- tests/graphics/compute_test.c | 4 +- tests/graphics/descriptor_indexing_test.c | 8 +- tests/graphics/geometry_test.c | 6 +- tests/graphics/graphics_test.c | 2 +- tests/graphics/indirect_draw_test.c | 6 +- tests/graphics/mesh_test.c | 6 +- tests/graphics/multi_descriptor_set_test.c | 4 +- tests/graphics/ray_tracing_test.c | 2 +- tests/graphics/texture_test.c | 6 +- tests/graphics/triangle_test.c | 6 +- tests/opengl/multi_thread_opengl_test.c | 8 +- tests/opengl/opengl_context_test.c | 4 +- tests/opengl/opengl_fbconfig_test.c | 2 +- tests/opengl/opengl_multi_context_test.c | 4 +- tests/opengl/opengl_test.c | 2 +- tests/system/system_test.c | 2 +- tests/tests.c | 2 +- tests/tests.h | 80 ++-- tests/thread/condvar_test.c | 4 +- tests/thread/mutex_test.c | 2 +- tests/thread/thread_test.c | 2 +- tests/thread/tls_test.c | 2 +- tests/video/attach_window_test.c | 6 +- tests/video/char_event_test.c | 4 +- tests/video/cursor_test.c | 4 +- tests/video/custom_decoration_test.c | 8 +- tests/video/icon_test.c | 4 +- tests/video/input_window_test.c | 6 +- tests/video/monitor_mode_test.c | 2 +- tests/video/monitor_test.c | 2 +- tests/video/native_instance_test.c | 8 +- tests/video/native_integration_test.c | 6 +- tests/video/system_cursor_test.c | 4 +- tests/video/video_test.c | 2 +- tests/video/window_test.c | 4 +- 63 files changed, 887 insertions(+), 1092 deletions(-) delete mode 100644 include/pal/core/defines.h delete mode 100644 include/pal/core/log.h delete mode 100644 include/pal/core/memory.h delete mode 100644 include/pal/core/pack.h delete mode 100644 include/pal/core/result.h delete mode 100644 include/pal/core/time.h delete mode 100644 include/pal/core/version.h diff --git a/CHANGELOG.md b/CHANGELOG.md index cdaed476..759857ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -124,57 +124,65 @@ palJoinThread(thread, &retval); ## [2.0.0] - 2026-01-00 ### Features - -- **Core:** Added **PAL_RESULT_GRAPHICS_NOT_INITIALIZED** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_ADAPTER** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_BACKEND** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_QUEUE_NOT_SUPPORTED** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_DRIVER** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_DEVICE** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_QUEUE** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_OUT_OF_QUEUE** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_GRAPHICS_WINDOW** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_SWAPCHAIN** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_IMAGE** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_IMAGE_VIEW** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_OPERATION** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_SHADER_TYPE** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_COMMAND_POOL** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_COMMAND_BUFFER** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_FENCE** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_SEMAPHORE** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_RENDER_PASS** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_BUFFER** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_INVALID_ACCELERATION_STRUCTURE** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_MEMORY_MAP_FAILED** to `PalResult` enum. -- **Core:** Added **PAL_RESULT_DEVICE_LOST** to `PalResult` enum. +- **Core:** Added **PAL_RESULT_INVALID_HANDLE** result code. +- **Core:** Added **PAL_RESULT_FEATURE_NOT_SUPPORTED** result code. +- **Core:** Added **PAL_RESULT_NOT_INITIALIZED** result code. +- **Core:** Added **PAL_RESULT_DEVICE_LOST** result code. +- **Core:** Added **PAL_RESULT_OUT_OF_DATE** result code. - **Graphics:** Added **Graphics System To PAL**. ### Changed - **All systems:** All enum types have been changed to defines and explicit width types. + +- **Core:** Rename **Int8** to **int8_t**. +- **Core:** Rename **Int16** to **int16_t**. +- **Core:** Rename **Int32** to **int32_t**. +- **Core:** Rename **Int64** to **int64_t**. +- **Core:** Rename **IntPtr** to **intptr_t**. +- **Core:** Rename **Uint8** to **uint8_t**. +- **Core:** Rename **Uint16** to **uint16_t**. +- **Core:** Rename **Uint32** to **uint32_t**. +- **Core:** Rename **Uint64** to **uint64_t**. +- **Core:** Rename **UintPtr** to **uintptr_t**. + - **Thread:** **palJoinThread()** now takes a void** for retval parameter. + - **Opengl:** **palEnumerateGLFBConfigs()** now does not take glWindow parameter anymore. ### Removed -- **Core:** Removed **PAL_RESULT_DEVICE_LOST** define. +- **Core:** Removed **PAL_RESULT_NULL_POINTER** result code. +- **Core:** Removed **PAL_RESULT_INVALID_ALLOCATOR** result code. +- **Core:** Removed **PAL_RESULT_ACCESS_DENIED** result code. +- **Core:** Removed **PAL_RESULT_INSUFFICIENT_BUFFER** result code. +- **Core:** Removed **PAL_RESULT_INVALID_THREAD** result code. +- **Core:** Removed **PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED** result code. +- **Core:** Removed **PAL_RESULT_VIDEO_NOT_INITIALIZED** result code. +- **Core:** Removed **PAL_RESULT_INVALID_MONITOR** result code. +- **Core:** Removed **PAL_RESULT_INVALID_MONITOR_MODE** result code. +- **Core:** Removed **PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED** result code. +- **Core:** Removed **PAL_RESULT_INVALID_KEYCODE** result code. +- **Core:** Removed **PAL_RESULT_INVALID_SCANCODE** result code. +- **Core:** Removed **PAL_RESULT_INVALID_MOUSE_BUTTON** result code. +- **Core:** Removed **PAL_RESULT_GL_NOT_INITIALIZED** result code. +- **Core:** Removed **PAL_RESULT_INVALID_GL_WINDOW** result code. +- **Core:** Removed **PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED** result code. +- **Core:** Removed **PAL_RESULT_INVALID_GL_FBCONFIG** result code. +- **Core:** Removed **PAL_RESULT_INVALID_GL_VERSION** result code. +- **Core:** Removed **PAL_RESULT_INVALID_GL_PROFILE** result code. +- **Core:** Removed **PAL_RESULT_INVALID_GL_CONTEXT** result code. +- **Core:** Removed **PAL_RESULT_INVALID_FBCONFIG_BACKEND** result code. + +- **Video:** Removed **palGetVideoFeaturesEx** functions. ### Tests - Added grapics example: see **graphics_test.c** - - Added clear color example: see **clear_color_test.c** - - Added vertex shader/buffer triangle example: see **triangle_test.c** - - Added mesh example: see **mesh_test.c** - - Added compute example: see **compute_test.c** - - Added ray tracing example: see **ray_tracing_test.c** - - Added texture rendering example: see **texture_test.c** ### Notes diff --git a/include/pal/core/defines.h b/include/pal/core/defines.h deleted file mode 100644 index 29e45421..00000000 --- a/include/pal/core/defines.h +++ /dev/null @@ -1,67 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup defines Defines section - * @ingroup pal_core - * @{ - */ - -#ifndef _CORE_DEFINES_H -#define _CORE_DEFINES_H - -#include -#include -#include - -#ifdef __cplusplus -#define PAL_EXTERN_C extern "C" -#else -#define PAL_EXTERN_C -#define nullptr ((void*)0) -#endif // __cplusplus - -// Set up shared library dependencies -#ifdef _WIN32 -#define PAL_CALL __stdcall -#ifdef _PAL_EXPORT -#define PAL_DECLSPEC PAL_EXTERN_C __declspec(dllexport) -#else -#define PAL_DECLSPEC PAL_EXTERN_C __declspec(dllimport) -#endif // PAL_EXPORT -#else -// other plafforms -#define PAL_CALL -#ifdef _PAL_EXPORT -#define PAL_DECLSPEC PAL_EXTERN_C __attribute__((visibility("default"))) -#else -#define PAL_DECLSPEC PAL_EXTERN_C -#endif // PAL_EXPORT -#endif // _WIN32 - -#ifdef _PAL_BUILD_DLL -#define PAL_API PAL_EXTERN_C PAL_DECLSPEC -#else -// static library -#define PAL_API PAL_EXTERN_C -#endif // _PAL_BUILD_DLL - -#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#define PAL_BIG_ENDIAN 1 -#else -#define PAL_BIG_ENDIAN 0 -#endif // __ORDER_BIG_ENDIAN__ - -/** - * @brief Sentinel representing an infinite number or time. - * @since 2.0 - */ -#define PAL_INFINITE UINT32_MAX - -#endif // _CORE_DEFINES_H - -/** @} */ \ No newline at end of file diff --git a/include/pal/core/log.h b/include/pal/core/log.h deleted file mode 100644 index fb4e1bff..00000000 --- a/include/pal/core/log.h +++ /dev/null @@ -1,67 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup log Log section - * @ingroup pal_core - * @{ - */ - -#ifndef _CORE_LOG_H -#define _CORE_LOG_H - -#include "defines.h" - -/** - * @typedef PalLogCallback - * @brief Function pointer type used for log callbacks. - * - * @param userData Optional pointer to user data passed from ::PalLogger. Can be nullptr. - * @param msg Null-terminated UTF-8 log message. - * - * @since 1.0 - * @sa palLog - */ -typedef void(PAL_CALL* PalLogCallback)( - void* userData, - const char* msg); - -/** - * @struct PalLogger - * @brief Logging configuration. - * - * Provides a callback and user data for handling log messages. - * - * @since 1.0 - */ -typedef struct { - PalLogCallback callback; - void* userData; /** Optional user-provided data. Can be nullptr.*/ -} PalLogger; - -/** - * Log a formatted message. - * - * @param logger Logger instance. Set to nullptr to use default logger. - * @param fmt printf-style format string. - * @param ... Arguments for the format string. - * - * Thread safety: Thread safe, but log output and - * callbacks may be invoked concurrently. The user must ensure the callback - * implementation is thread safe. - * - * @since 1.0 - * @sa palFormatResult - */ -PAL_API void PAL_CALL palLog( - const PalLogger* logger, - const char* fmt, - ...); - -#endif // _CORE_LOG_H - -/** @} */ \ No newline at end of file diff --git a/include/pal/core/memory.h b/include/pal/core/memory.h deleted file mode 100644 index 210ae37e..00000000 --- a/include/pal/core/memory.h +++ /dev/null @@ -1,106 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup memory Memory section - * @ingroup pal_core - * @{ - */ - -#ifndef _CORE_MEMORY_H -#define _CORE_MEMORY_H - -#include "defines.h" - -/** - * @typedef PalAllocateFn - * @brief Function pointer type used for memory allocations. - * - * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. - * @param[in] size Number of bytes to allocate. Must not be 0. - * @param[in] alignment Must be power of two. Set to 0 to use default (16). - * - * @return Pointer to the allocated memory on success or nullptr on failure. - * - * @since 1.0 - * @sa PalFreeFn - */ -typedef void*(PAL_CALL* PalAllocateFn)( - void* userData, - uint64_t size, - uint64_t alignment); - -/** - * @typedef PalFreeFn - * @brief Function pointer type used for memory deallocations. - * - * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. - * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must return safely if - * pointer is nullptr. - * - * @since 1.0 - * @sa PalAllocateFn - */ -typedef void(PAL_CALL* PalFreeFn)( - void* userData, - void* ptr); - -/** - * @struct PalAllocator - * @brief Custom memory allocator. - * - * Provides user-defined memory allocation and free functions. - * - * @since 1.0 - */ -typedef struct { - PalAllocateFn allocate; - PalFreeFn free; - void* userData; /**< Optional user-provided data. Can be nullptr.*/ -} PalAllocator; - -/** - * Allocate memory using the provided allocator. - * - * @param allocator The allocator to use. Set to nullptr to use default. - * @param size Number of bytes to allocate. - * @param alignment Alignment in bytes. Must be a power of two. - * - * @return Pointer to allocated memory on success, or nullptr on failure. - * - * Thread safety: Thread safe only if the provided allocator is thread safe. The default allocator - * is thread safe. - * - * @since 1.0 - * @sa palFree - */ -PAL_API void* PAL_CALL palAllocate( - const PalAllocator* allocator, - uint64_t size, - uint64_t alignment); - -/** - * Free memory allocated by palAllocate. - * - * @param allocator The allocator used to allocate the memory. Set to nullptr to - * use default. - * @param ptr Pointer to memory to free. If nullptr, the function returns - * silently. - * - * Thread safety: Thread safe only if the provided allocator is thread - * safe. The default allocator is thread safe. - * - * @since 1.0 - * @sa palAllocate - */ -PAL_API void PAL_CALL palFree( - const PalAllocator* allocator, - void* ptr); - -#endif // _CORE_MEMORY_H - -/** @} */ \ No newline at end of file diff --git a/include/pal/core/pack.h b/include/pal/core/pack.h deleted file mode 100644 index 06e466eb..00000000 --- a/include/pal/core/pack.h +++ /dev/null @@ -1,202 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup pack Packing and unpack helpers section - * @ingroup pal_core - * @{ - */ - -#ifndef _CORE_PACK_H -#define _CORE_PACK_H - -#include "defines.h" -#include - -/** - * @brief Combine two 32-bit unsigned integers into a single 64-bit signed - * integer. - * - * @return The combined 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palUnpackUint32 - */ -static inline int64_t PAL_CALL palPackUint32( - uint32_t low, - uint32_t high) -{ - return (int64_t)(((uint64_t)high << 32) | (uint64_t)low); -} - -/** - * @brief Combine two 32-bit signed integers into a single 64-bit signed - * integer. - * - * @return The combined 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palUnpackInt32 - */ -static inline int64_t PAL_CALL palPackInt32( - int32_t low, - int32_t high) -{ - return ((int64_t)(uint32_t)high << 32) | (uint32_t)low; -} - -/** - * @brief Pack a pointer into a 64-bit signed integer. - * - * @return The packed 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palUnpackPointer - */ -static inline int64_t PAL_CALL palPackPointer(void* ptr) -{ - return (int64_t)(uintptr_t)ptr; -} - -/** - * @brief Combine two floats into a single 64-bit signed integer. - * - * @return The combined 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.3 - * @sa palUnpackFloat - */ -static inline int64_t PAL_CALL palPackFloat( - float low, - float high) -{ - int64_t combined = 0; -#if PAL_BIG_ENDIAN - memcpy(&((uint32_t*)&combined)[0], &high, sizeof(float)); - memcpy(&((uint32_t*)&combined)[1], &low, sizeof(float)); -#else - memcpy(&((uint32_t*)&combined)[0], &low, sizeof(float)); - memcpy(&((uint32_t*)&combined)[1], &high, sizeof(float)); -#endif // PAL_BIG_ENDIAN - - return combined; -} - -/** - * @brief Retrieve two 32-bit unsigned integers from a 64-bit signed integer. - * - * @param[out] outLow Low value of the 64-bit signed integer. - * @param[out] outHigh High value of the 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palPackUint32 - */ -static inline void PAL_CALL palUnpackUint32( - int64_t data, - uint32_t* outLow, - uint32_t* outHigh) -{ - if (outLow) { - *outLow = (uint32_t)(data & 0xFFFFFFFF); - } - - if (outHigh) { - *outHigh = (uint32_t)((uint64_t)data >> 32); - } -} - -/** - * @brief Retrieve two 32-bit signed integers from a 64-bit signed integer. - * - * @param[out] outLow Low value of the 64-bit signed integer. - * @param[out] outHigh High value of the 64-bit signed integer. - * - * Thread safety: Thread-safe if `outLow` and `outHigh` are - * thread local. - * - * @since 1.0 - * @sa palPackInt32 - */ -static inline void PAL_CALL palUnpackInt32( - int64_t data, - int32_t* outLow, - int32_t* outHigh) -{ - if (outLow) { - *outLow = (int32_t)(data & 0xFFFFFFFF); - } - - if (outHigh) { - *outHigh = (int32_t)((uint64_t)data >> 32); - } -} - -/** - * @brief Unpack a pointer from a 64-bit signed integer. - * - * @return The pointer from the 64-bit signed integer. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palPackPointer - */ -static inline void* PAL_CALL palUnpackPointer(int64_t data) -{ - return (void*)(uintptr_t)data; -} - -/** - * @brief Retrieve two floats from a 64-bit signed integer. - * - * @param[out] outLow Low value of the 64-bit signed integer. - * @param[out] outHigh High value of the 64-bit signed integer. - * - * Thread safety: Thread-safe if `outLow` and `outHigh` are - * thread local. - * - * @since 1.3 - * @sa palPackFloat - */ -static inline void PAL_CALL palUnpackFloat( - int64_t data, - float* low, - float* high) -{ -#if PAL_BIG_ENDIAN - if (low) { - memcpy(low, &((uint32_t*)&data)[1], sizeof(float)); - } - - if (high) { - memcpy(high, &((uint32_t*)&data)[0], sizeof(float)); - } -#else - if (low) { - memcpy(low, &((uint32_t*)&data)[0], sizeof(float)); - } - - if (high) { - memcpy(high, &((uint32_t*)&data)[1], sizeof(float)); - } - -#endif // PAL_BIG_ENDIAN -} - -#endif // _CORE_PACK_H - -/** @} */ \ No newline at end of file diff --git a/include/pal/core/result.h b/include/pal/core/result.h deleted file mode 100644 index 9bc393a1..00000000 --- a/include/pal/core/result.h +++ /dev/null @@ -1,101 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup result Result codes section - * @ingroup pal_core - * @{ - */ - -#ifndef _CORE_RESULT_H -#define _CORE_RESULT_H - -#include "defines.h" - -/** - * @enum PalResult - * @brief Codes returned by most PAL functions. This is not a bitmask. - * - * All result codes follow the format `PAL_RESULT_**` for consistency and API use. - * - * @since 1.0 - */ -typedef enum { - PAL_RESULT_SUCCESS, - PAL_RESULT_NULL_POINTER, - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_INVALID_ALLOCATOR, - PAL_RESULT_ACCESS_DENIED, - PAL_RESULT_TIMEOUT, - PAL_RESULT_INSUFFICIENT_BUFFER, - PAL_RESULT_INVALID_THREAD, - PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED, - PAL_RESULT_VIDEO_NOT_INITIALIZED, - PAL_RESULT_INVALID_MONITOR, - PAL_RESULT_INVALID_MONITOR_MODE, - PAL_RESULT_INVALID_WINDOW, - PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED, - PAL_RESULT_INVALID_KEYCODE, - PAL_RESULT_INVALID_SCANCODE, - PAL_RESULT_INVALID_MOUSE_BUTTON, - PAL_RESULT_INVALID_ORIENTATION, - PAL_RESULT_GL_NOT_INITIALIZED, - PAL_RESULT_INVALID_GL_WINDOW, - PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED, - PAL_RESULT_INVALID_GL_FBCONFIG, - PAL_RESULT_INVALID_GL_VERSION, - PAL_RESULT_INVALID_GL_PROFILE, - PAL_RESULT_INVALID_GL_CONTEXT, - PAL_RESULT_INVALID_FBCONFIG_BACKEND, - PAL_RESULT_GRAPHICS_NOT_INITIALIZED, - PAL_RESULT_INVALID_ADAPTER, - PAL_RESULT_INVALID_BACKEND, - PAL_RESULT_QUEUE_NOT_SUPPORTED, - PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED, - PAL_RESULT_INVALID_DRIVER, - PAL_RESULT_INVALID_DEVICE, - PAL_RESULT_INVALID_QUEUE, - PAL_RESULT_OUT_OF_QUEUE, - PAL_RESULT_INVALID_GRAPHICS_WINDOW, - PAL_RESULT_INVALID_SWAPCHAIN, - PAL_RESULT_INVALID_IMAGE, - PAL_RESULT_INVALID_IMAGE_VIEW, - PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED, - PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_INVALID_SHADER, - PAL_RESULT_INVALID_SHADER_TYPE, - PAL_RESULT_INVALID_COMMAND_POOL, - PAL_RESULT_INVALID_COMMAND_BUFFER, - PAL_RESULT_INVALID_FENCE, - PAL_RESULT_INVALID_SEMAPHORE, - PAL_RESULT_INVALID_BUFFER, - PAL_RESULT_INVALID_ACCELERATION_STRUCTURE, - PAL_RESULT_INVALID_PIPELINE, - PAL_RESULT_MEMORY_MAP_FAILED, - PAL_RESULT_DEVICE_LOST, - PAL_RESULT_SURFACE_LOST, - PAL_RESULT_SWAPCHAIN_OUT_OF_DATE -} PalResult; - -/** - * Convert a result code to a human-readable string. - * - * @param result The PalResult code to format. - * - * @return Null-terminated static string describing the result. - * - * Thread safety: Thread safe. - * - * @since 1.0 - */ -PAL_API const char* PAL_CALL palFormatResult(PalResult result); - -#endif // _CORE_RESULT_H - -/** @} */ \ No newline at end of file diff --git a/include/pal/core/time.h b/include/pal/core/time.h deleted file mode 100644 index d4738fce..00000000 --- a/include/pal/core/time.h +++ /dev/null @@ -1,46 +0,0 @@ - - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup time Time section - * @ingroup pal_core - * @{ - */ - -#ifndef _CORE_TIME_H -#define _CORE_TIME_H - -#include "defines.h" - -/** - * Query a high-resolution performance counter value. - * - * @return Current performance counter value. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palGetPerformanceFrequency - */ -PAL_API uint64_t PAL_CALL palGetPerformanceCounter(); - -/** - * Query the frequency of the high-resolution performance counter. - * - * @return Performance counter frequency, in counts per second. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palGetPerformanceCounter - */ -PAL_API uint64_t PAL_CALL palGetPerformanceFrequency(); - -#endif // _CORE_TIME_H - -/** @} */ \ No newline at end of file diff --git a/include/pal/core/version.h b/include/pal/core/version.h deleted file mode 100644 index 98a60ac4..00000000 --- a/include/pal/core/version.h +++ /dev/null @@ -1,57 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup version Version section - * @ingroup pal_core - * @{ - */ - -#ifndef _CORE_VERSION_H -#define _CORE_VERSION_H - -#include "defines.h" - -/** - * @struct PalVersion - * @brief Describes the version of PAL. - * - * @since 1.0 - */ -typedef struct { - uint32_t major; /**< Major version (breaking changes).*/ - uint32_t minor; /**< Minor version (adding features).*/ - uint32_t build; /**< Build version (bug fixes).*/ -} PalVersion; - -/** - * Retrieve the PAL version number. - * - * @return PAL version (major, minor, build). - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palGetVersionString - */ -PAL_API PalVersion PAL_CALL palGetVersion(); - -/** - * Retrieve the PAL version string. - * - * @return Null-terminated string containing the PAL version. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palGetVersion - */ -PAL_API const char* PAL_CALL palGetVersionString(); - -#endif // _CORE_VERSION_H - -/** @} */ \ No newline at end of file diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 15350e15..8b94a1dc 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -13,13 +13,463 @@ #ifndef _PAL_CORE_H #define _PAL_CORE_H -#include "core/defines.h" -#include "core/log.h" -#include "core/memory.h" -#include "core/pack.h" -#include "core/result.h" -#include "core/time.h" -#include "core/version.h" +#include + +#ifdef __cplusplus +#define PAL_EXTERN_C extern "C" +#else +#define PAL_EXTERN_C +#define nullptr ((void*)0) +#endif // __cplusplus + +// Set up shared library dependencies +#ifdef _WIN32 +#define PAL_CALL __stdcall +#ifdef _PAL_EXPORT +#define PAL_DECLSPEC PAL_EXTERN_C __declspec(dllexport) +#else +#define PAL_DECLSPEC PAL_EXTERN_C __declspec(dllimport) +#endif // PAL_EXPORT +#else +// other plafforms +#define PAL_CALL +#ifdef _PAL_EXPORT +#define PAL_DECLSPEC PAL_EXTERN_C __attribute__((visibility("default"))) +#else +#define PAL_DECLSPEC PAL_EXTERN_C +#endif // PAL_EXPORT +#endif // _WIN32 + +#ifdef _PAL_BUILD_DLL +#define PAL_API PAL_EXTERN_C PAL_DECLSPEC +#else +// static library +#define PAL_API PAL_EXTERN_C +#endif // _PAL_BUILD_DLL + +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define PAL_BIG_ENDIAN 1 +#else +#define PAL_BIG_ENDIAN 0 +#endif // __ORDER_BIG_ENDIAN__ + +#define PAL_TRUE 1 +#define PAL_FALSE 0 +#define PAL_INFINITE UINT32_MAX + +#define PAL_RESULT_SUCCESS 0 +#define PAL_RESULT_INVALID_ARGUMENT 1 +#define PAL_RESULT_OUT_OF_MEMORY 2 +#define PAL_RESULT_PLATFORM_FAILURE 3 +#define PAL_RESULT_TIMEOUT 4 +#define PAL_RESULT_INVALID_HANDLE 5 +#define PAL_RESULT_FEATURE_NOT_SUPPORTED 6 +#define PAL_RESULT_NOT_INITIALIZED 7 +#define PAL_RESULT_INVALID_OPERATION 8 +#define PAL_RESULT_DEVICE_LOST 9 +#define PAL_RESULT_OUT_OF_DATE 10 + +/** + * @typedef PalBool + * @brief Must be @c PAL_TRUE or @c PAL_FALSE. + * + * @since 2.0 + */ +typedef uint32_t PalBool; + +/** + * @typedef PalResult + * @brief Codes returned by most PAL functions. This is not a bitmask. + * + * All result codes follow the format `PAL_RESULT_**` for consistency and API use. + * + * @since 2.0 + */ +typedef uint64_t PalResult; + +/** + * @typedef PalAllocateFn + * @brief Function pointer type used for memory allocations. + * + * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. + * @param[in] size Number of bytes to allocate. Must not be 0. + * @param[in] alignment Must be power of two. Set to 0 to use default (16). + * + * @return Pointer to the allocated memory on success or nullptr on failure. + * + * @since 1.0 + * @sa PalFreeFn + */ +typedef void*(PAL_CALL* PalAllocateFn)( + void* userData, + uint64_t size, + uint64_t alignment); + +/** + * @typedef PalFreeFn + * @brief Function pointer type used for memory deallocations. + * + * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. + * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must return safely if + * pointer is nullptr. + * + * @since 1.0 + * @sa PalAllocateFn + */ +typedef void(PAL_CALL* PalFreeFn)( + void* userData, + void* ptr); + +/** + * @typedef PalLogCallback + * @brief Function pointer type used for log callbacks. + * + * @param userData Optional pointer to user data passed from ::PalLogger. Can be nullptr. + * @param msg Null-terminated UTF-8 log message. + * + * @since 1.0 + * @sa palLog + */ +typedef void(PAL_CALL* PalLogCallback)( + void* userData, + const char* msg); + +/** + * @struct PalVersion + * @brief Describes the version of PAL. + * + * @since 1.0 + */ +typedef struct { + uint32_t major; /**< Major version (breaking changes).*/ + uint32_t minor; /**< Minor version (adding features).*/ + uint32_t build; /**< Build version (bug fixes).*/ +} PalVersion; + +/** + * @struct PalAllocator + * @brief Custom memory allocator. + * + * Provides user-defined memory allocation and free functions. + * + * @since 1.0 + */ +typedef struct { + PalAllocateFn allocate; + PalFreeFn free; + void* userData; /**< Optional user-provided data. Can be nullptr.*/ +} PalAllocator; + +/** + * @struct PalLogger + * @brief Logging configuration. + * + * Provides a callback and user data for handling log messages. + * + * @since 1.0 + */ +typedef struct { + PalLogCallback callback; + void* userData; /** Optional user-provided data. Can be nullptr.*/ +} PalLogger; + +/** + * Convert a result code to a human-readable string. + * + * @param result The PalResult code to format. + * + * @return Null-terminated static string describing the result. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API const char* PAL_CALL palFormatResult(PalResult result); + +/** + * Retrieve the PAL version number. + * + * @return PAL version (major, minor, build). + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palGetVersionString + */ +PAL_API PalVersion PAL_CALL palGetVersion(); + +/** + * Retrieve the PAL version string. + * + * @return Null-terminated string containing the PAL version. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palGetVersion + */ +PAL_API const char* PAL_CALL palGetVersionString(); + +/** + * Allocate memory using the provided allocator. + * + * @param allocator The allocator to use. Set to nullptr to use default. + * @param size Number of bytes to allocate. + * @param alignment Alignment in bytes. Must be a power of two. + * + * @return Pointer to allocated memory on success, or nullptr on failure. + * + * Thread safety: Thread safe only if the provided allocator is thread safe. The default allocator + * is thread safe. + * + * @since 1.0 + * @sa palFree + */ +PAL_API void* PAL_CALL palAllocate( + const PalAllocator* allocator, + uint64_t size, + uint64_t alignment); + +/** + * Free memory allocated by palAllocate. + * + * @param allocator The allocator used to allocate the memory. Set to nullptr to + * use default. + * @param ptr Pointer to memory to free. If nullptr, the function returns + * silently. + * + * Thread safety: Thread safe only if the provided allocator is thread + * safe. The default allocator is thread safe. + * + * @since 1.0 + * @sa palAllocate + */ +PAL_API void PAL_CALL palFree( + const PalAllocator* allocator, + void* ptr); + +/** + * Log a formatted message. + * + * @param logger Logger instance. Set to nullptr to use default logger. + * @param fmt printf-style format string. + * @param ... Arguments for the format string. + * + * Thread safety: Thread safe, but log output and + * callbacks may be invoked concurrently. The user must ensure the callback + * implementation is thread safe. + * + * @since 1.0 + * @sa palFormatResult + */ +PAL_API void PAL_CALL palLog( + const PalLogger* logger, + const char* fmt, + ...); + +/** + * Query a high-resolution performance counter value. + * + * @return Current performance counter value. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palGetPerformanceFrequency + */ +PAL_API uint64_t PAL_CALL palGetPerformanceCounter(); + +/** + * Query the frequency of the high-resolution performance counter. + * + * @return Performance counter frequency, in counts per second. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palGetPerformanceCounter + */ +PAL_API uint64_t PAL_CALL palGetPerformanceFrequency(); + +/** + * @brief Combine two 32-bit unsigned integers into a single 64-bit signed + * integer. + * + * @return The combined 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palUnpackUint32 + */ +static inline int64_t PAL_CALL palPackUint32( + uint32_t low, + uint32_t high) +{ + return (int64_t)(((uint64_t)high << 32) | (uint64_t)low); +} + +/** + * @brief Combine two 32-bit signed integers into a single 64-bit signed + * integer. + * + * @return The combined 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palUnpackInt32 + */ +static inline int64_t PAL_CALL palPackInt32( + int32_t low, + int32_t high) +{ + return ((int64_t)(uint32_t)high << 32) | (uint32_t)low; +} + +/** + * @brief Pack a pointer into a 64-bit signed integer. + * + * @return The packed 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palUnpackPointer + */ +static inline int64_t PAL_CALL palPackPointer(void* ptr) +{ + return (int64_t)(uintptr_t)ptr; +} + +/** + * @brief Combine two floats into a single 64-bit signed integer. + * + * @return The combined 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.3 + * @sa palUnpackFloat + */ +static inline int64_t PAL_CALL palPackFloat( + float low, + float high) +{ + int64_t combined = 0; +#if PAL_BIG_ENDIAN + memcpy(&((uint32_t*)&combined)[0], &high, sizeof(float)); + memcpy(&((uint32_t*)&combined)[1], &low, sizeof(float)); +#else + memcpy(&((uint32_t*)&combined)[0], &low, sizeof(float)); + memcpy(&((uint32_t*)&combined)[1], &high, sizeof(float)); +#endif // PAL_BIG_ENDIAN + + return combined; +} + +/** + * @brief Retrieve two 32-bit unsigned integers from a 64-bit signed integer. + * + * @param[out] outLow Low value of the 64-bit signed integer. + * @param[out] outHigh High value of the 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palPackUint32 + */ +static inline void PAL_CALL palUnpackUint32( + int64_t data, + uint32_t* outLow, + uint32_t* outHigh) +{ + if (outLow) { + *outLow = (uint32_t)(data & 0xFFFFFFFF); + } + + if (outHigh) { + *outHigh = (uint32_t)((uint64_t)data >> 32); + } +} + +/** + * @brief Retrieve two 32-bit signed integers from a 64-bit signed integer. + * + * @param[out] outLow Low value of the 64-bit signed integer. + * @param[out] outHigh High value of the 64-bit signed integer. + * + * Thread safety: Thread-safe if `outLow` and `outHigh` are + * thread local. + * + * @since 1.0 + * @sa palPackInt32 + */ +static inline void PAL_CALL palUnpackInt32( + int64_t data, + int32_t* outLow, + int32_t* outHigh) +{ + if (outLow) { + *outLow = (int32_t)(data & 0xFFFFFFFF); + } + + if (outHigh) { + *outHigh = (int32_t)((uint64_t)data >> 32); + } +} + +/** + * @brief Unpack a pointer from a 64-bit signed integer. + * + * @return The pointer from the 64-bit signed integer. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palPackPointer + */ +static inline void* PAL_CALL palUnpackPointer(int64_t data) +{ + return (void*)(uintptr_t)data; +} + +/** + * @brief Retrieve two floats from a 64-bit signed integer. + * + * @param[out] outLow Low value of the 64-bit signed integer. + * @param[out] outHigh High value of the 64-bit signed integer. + * + * Thread safety: Thread-safe if `outLow` and `outHigh` are + * thread local. + * + * @since 1.3 + * @sa palPackFloat + */ +static inline void PAL_CALL palUnpackFloat( + int64_t data, + float* low, + float* high) +{ +#if PAL_BIG_ENDIAN + if (low) { + memcpy(low, &((uint32_t*)&data)[1], sizeof(float)); + } + + if (high) { + memcpy(high, &((uint32_t*)&data)[0], sizeof(float)); + } +#else + if (low) { + memcpy(low, &((uint32_t*)&data)[0], sizeof(float)); + } + + if (high) { + memcpy(high, &((uint32_t*)&data)[1], sizeof(float)); + } + +#endif // PAL_BIG_ENDIAN +} /** @} */ diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 7ce7b7bf..001607dc 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -75,7 +75,7 @@ typedef void(PAL_CALL* PalPushFn)( * @since 1.0 * @sa PalPushFn */ -typedef bool(PAL_CALL* PalPollFn)( +typedef PalBool(PAL_CALL* PalPollFn)( void* userData, PalEvent* outEvent); @@ -547,7 +547,7 @@ PAL_API void PAL_CALL palPushEvent( * @since 1.0 * @sa palPushEvent */ -PAL_API bool PAL_CALL palPollEvent( +PAL_API PalBool PAL_CALL palPollEvent( PalEventDriver* eventDriver, PalEvent* outEvent); diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 4e3ca4bc..25f033c4 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1473,10 +1473,10 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool sampledImageDynamicArrayIndexing; - bool storageImageDynamicArrayIndexing; - bool storageBufferDynamicArrayIndexing; - bool uniformBufferDynamicArrayIndexing; + PalBool sampledImageDynamicArrayIndexing; + PalBool storageImageDynamicArrayIndexing; + PalBool storageBufferDynamicArrayIndexing; + PalBool uniformBufferDynamicArrayIndexing; uint32_t maxPerStageSampledImages; uint32_t maxPerSetSampledImages; uint32_t maxPerStageStorageImages; @@ -1584,9 +1584,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool independentResolve; - bool depthResolves[PAL_MAX_RESOLVE_MODES]; - bool stencilResolves[PAL_MAX_RESOLVE_MODES]; + PalBool independentResolve; + PalBool depthResolves[PAL_MAX_RESOLVE_MODES]; + PalBool stencilResolves[PAL_MAX_RESOLVE_MODES]; } PalDepthStencilCapabilities; /** @@ -1597,12 +1597,12 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; + PalBool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; uint32_t minTexelWidth; uint32_t minTexelHeight; uint32_t maxTexelWidth; uint32_t maxTexelHeight; - bool combinerOps[PAL_MAX_COMBINER_OPS]; + PalBool combinerOps[PAL_MAX_COMBINER_OPS]; } PalFragmentShadingRateCapabilities; /** @@ -1646,14 +1646,14 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool sampledImageNonUniformIndexing; - bool sampledImageUpdateAfterBind; - bool storageImageNonUniformIndexing; - bool storageImageUpdateAfterBind; - bool storageBufferNonUniformIndexing; - bool storageBufferUpdateAfterBind; - bool uniformBufferNonUniformIndexing; - bool uniformBufferUpdateAfterBind; + PalBool sampledImageNonUniformIndexing; + PalBool sampledImageUpdateAfterBind; + PalBool storageImageNonUniformIndexing; + PalBool storageImageUpdateAfterBind; + PalBool storageBufferNonUniformIndexing; + PalBool storageBufferUpdateAfterBind; + PalBool uniformBufferNonUniformIndexing; + PalBool uniformBufferUpdateAfterBind; uint32_t maxPerStageSampledImages; uint32_t maxPerSetSampledImages; uint32_t maxPerStageStorageImages; @@ -1676,9 +1676,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool presentModes[PAL_PRESENT_MODE_MAX]; - bool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; - bool formats[PAL_SURFACE_FORMAT_MAX]; + PalBool presentModes[PAL_PRESENT_MODE_MAX]; + PalBool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; + PalBool formats[PAL_SURFACE_FORMAT_MAX]; uint32_t minImageCount; uint32_t maxImageCount; uint32_t minImageWidth; @@ -1827,7 +1827,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool memoryTypes[PAL_MEMORY_TYPE_MAX]; + PalBool memoryTypes[PAL_MEMORY_TYPE_MAX]; uint64_t memoryMask; uint64_t size; uint64_t alignment; @@ -2043,12 +2043,12 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool denyGeneral; - bool denyValidation; - bool denyPerformance; - bool denyInfoSeverity; - bool denyWarningSeverity; - bool denyErrorSeverity; + PalBool denyGeneral; + PalBool denyValidation; + PalBool denyPerformance; + PalBool denyInfoSeverity; + PalBool denyWarningSeverity; + PalBool denyErrorSeverity; void* userData; PalDebugCallback callback; } PalGraphicsDebugger; @@ -2063,8 +2063,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool enableDepthClamp; - bool enableDepthBias; + PalBool enableDepthClamp; + PalBool enableDepthBias; float depthBiasConstant; float depthBiasSlope; float depthBiasClamp; @@ -2083,8 +2083,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool enableSampleShading; - bool enableAlphaToCoverage; + PalBool enableSampleShading; + PalBool enableAlphaToCoverage; PalSampleCount sampleCount; uint64_t sampleMask; float minSampleShading; @@ -2116,9 +2116,9 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool enableDepthTest; - bool enableDepthWrite; - bool enableStencilTest; + PalBool enableDepthTest; + PalBool enableDepthWrite; + PalBool enableStencilTest; PalCompareOp compareOp; PalStencilOpState frontStencilOpState; PalStencilOpState backStencilOpState; @@ -2137,7 +2137,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool enableBlend; + PalBool enableBlend; PalColorMask colorWriteMask; PalBlendFactor srcColorBlendFactor; PalBlendFactor dstColorBlendFactor; @@ -2545,8 +2545,8 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool enableCompare; - bool enableAnisotropy; /**< `PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY` must be supported.*/ + PalBool enableCompare; + PalBool enableAnisotropy; /**< `PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY` must be supported.*/ float mipLodBias; float minLod; float maxLod; @@ -2571,7 +2571,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool clipped; + PalBool clipped; uint32_t width; uint32_t height; uint32_t imageCount; @@ -2638,7 +2638,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool enableDescriptorIndexing; + PalBool enableDescriptorIndexing; uint32_t bindingCount; uint32_t shaderStageCount; PalShaderStage* shaderStages; @@ -2656,7 +2656,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool enableDescriptorIndexing; + PalBool enableDescriptorIndexing; uint32_t maxDescriptorSets; uint32_t maxDescriptorBindingSizes; PalDescriptorPoolBindingSize* bindingSizes; @@ -2688,7 +2688,7 @@ typedef struct { * @ingroup pal_graphics */ typedef struct { - bool primitiveRestartEnable; + PalBool primitiveRestartEnable; uint32_t vertexLayoutCount; uint32_t colorBlendAttachmentCount; uint32_t shaderCount; @@ -2971,7 +2971,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCanQueuePresent(). */ - bool (PAL_CALL *canQueuePresent)( + PalBool (PAL_CALL *canQueuePresent)( PalQueue* queue, PalSurface* surface); @@ -2997,7 +2997,7 @@ typedef struct { * * Must obey the rules and semantics documented in palIsFormatSupported(). */ - bool (PAL_CALL *isFormatSupported)( + PalBool (PAL_CALL *isFormatSupported)( PalAdapter* adapter, PalFormat format); @@ -3225,7 +3225,7 @@ typedef struct { */ PalResult (PAL_CALL *createFence)( PalDevice* device, - bool signaled, + PalBool signaled, PalFence** outFence); /** @@ -3256,7 +3256,7 @@ typedef struct { * * Must obey the rules and semantics documented in palIsFenceSignaled(). */ - bool (PAL_CALL *isFenceSignaled)(PalFence* fence); + PalBool (PAL_CALL *isFenceSignaled)(PalFence* fence); /** * Backend implementation of ::palCreateSemaphore. @@ -3265,7 +3265,7 @@ typedef struct { */ PalResult (PAL_CALL *createSemaphore)( PalDevice* device, - bool enableTimeline, + PalBool enableTimeline, PalSemaphore** outSemaphore); /** @@ -3765,7 +3765,7 @@ typedef struct { */ PalResult (PAL_CALL *cmdSetDepthTestEnable)( PalCommandBuffer* cmdBuffer, - bool enable); + PalBool enable); /** * Backend implementation of ::palCmdSetDepthWriteEnable. @@ -3774,7 +3774,7 @@ typedef struct { */ PalResult (PAL_CALL *cmdSetDepthWriteEnable)( PalCommandBuffer* cmdBuffer, - bool enable); + PalBool enable); /** * Backend implementation of ::palCmdSetStencilOp. @@ -4606,7 +4606,7 @@ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); * @ingroup pal_graphics * @sa palCreateQueue */ -PAL_API bool PAL_CALL palCanQueuePresent( +PAL_API PalBool PAL_CALL palCanQueuePresent( PalQueue* queue, PalSurface* surface); @@ -4685,7 +4685,7 @@ PAL_API PalResult PAL_CALL palEnumerateFormats( * @sa palQueryFormatImageUsages * @sa palQueryFormatImageViewUsages */ -PAL_API bool PAL_CALL palIsFormatSupported( +PAL_API PalBool PAL_CALL palIsFormatSupported( PalAdapter* adapter, PalFormat format); @@ -5272,7 +5272,7 @@ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); */ PAL_API PalResult PAL_CALL palCreateFence( PalDevice* device, - bool signaled, + PalBool signaled, PalFence** outFence); /** @@ -5354,7 +5354,7 @@ PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); * @sa palResetFence * @sa palWaitFence */ -PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); +PAL_API PalBool PAL_CALL palIsFenceSignaled(PalFence* fence); /** * @brief Create a semaphore. @@ -5377,7 +5377,7 @@ PAL_API bool PAL_CALL palIsFenceSignaled(PalFence* fence); */ PAL_API PalResult PAL_CALL palCreateSemaphore( PalDevice* device, - bool enableTimeline, + PalBool enableTimeline, PalSemaphore** outSemaphore); /** @@ -6707,7 +6707,7 @@ PAL_API PalResult PAL_CALL palCmdSetPrimitiveTopology( */ PAL_API PalResult PAL_CALL palCmdSetDepthTestEnable( PalCommandBuffer* cmdBuffer, - bool enable); + PalBool enable); /** * @brief Set depth write enable for the provided command buffer. @@ -6730,7 +6730,7 @@ PAL_API PalResult PAL_CALL palCmdSetDepthTestEnable( */ PAL_API PalResult PAL_CALL palCmdSetDepthWriteEnable( PalCommandBuffer* cmdBuffer, - bool enable); + PalBool enable); /** * @brief Set depth stencil operation for the provided command buffer. @@ -7550,7 +7550,7 @@ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( * @sa palCmdDispatch * @sa palCmdDispatchBase */ -PAL_API bool PAL_CALL palBuildWorkGroupInfo( +PAL_API PalBool PAL_CALL palBuildWorkGroupInfo( const PalWorkGroupBuildData* data, int32_t* count, PalWorkGroupInfo* info); diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 0421874b..6dc80666 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -144,9 +144,9 @@ typedef struct { * @ingroup pal_opengl */ typedef struct { - bool doubleBuffer; - bool stereo; - bool sRGB; + PalBool doubleBuffer; + PalBool stereo; + PalBool sRGB; uint16_t index; /**< Driver index. Must not be changed.*/ uint16_t redBits; uint16_t greenBits; @@ -182,9 +182,9 @@ typedef struct { * @ingroup pal_opengl */ typedef struct { - bool forward; /**< Forward compatible context.*/ - bool noError; /**< No error context.*/ - bool debug; /**< Debug context. */ + PalBool forward; /**< Forward compatible context.*/ + PalBool noError; /**< No error context.*/ + PalBool debug; /**< Debug context. */ uint16_t major; /** major version.*/ uint16_t minor; /** minor version.*/ PalGLProfile profile; /**< see PalGLProfile.*/ diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 718e797b..73bf885b 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -566,7 +566,7 @@ typedef enum { * @ingroup pal_video */ typedef struct { - bool primary; /**< True if this is the primary monitor.*/ + PalBool primary; /**< True if this is the primary monitor.*/ uint32_t dpi; uint32_t refreshRate; int32_t x; /**< X position in pixels.*/ @@ -675,10 +675,10 @@ typedef struct { * @ingroup pal_video */ typedef struct { - bool show; /**< Show after creation.*/ - bool maximized; /**< Maximize after creation.*/ - bool minimized; /**< Minimze after creation.*/ - bool center; /**< Center after creation.*/ + PalBool show; /**< Show after creation.*/ + PalBool maximized; /**< Maximize after creation.*/ + PalBool minimized; /**< Minimze after creation.*/ + PalBool center; /**< Center after creation.*/ uint32_t width; /**< Width in pixels.*/ uint32_t height; /**< Width in pixels.*/ PalWindowStyle style; /**< Window style.*/ @@ -759,23 +759,6 @@ PAL_API void PAL_CALL palUpdateVideo(); */ PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures(); -/** - * @brief Get the supported features of the video system. - * - * The video system must be initialized before this call. - * This returns the supported features from palGetVideoFeatures() - * and adds additionally supported features. - * - * @return video features on success or `0` on failure. - * - * Thread safety: Thread safe. - * - * @since 1.3 - * @ingroup pal_video - * @sa palInitVideo - */ -PAL_API PalVideoFeatures64 PAL_CALL palGetVideoFeaturesEx(); - /** * @brief Set the FBConfig for the video system. * @@ -1358,7 +1341,7 @@ PAL_API PalResult PAL_CALL palGetWindowState( * @since 1.0 * @ingroup pal_video */ -PAL_API const bool* PAL_CALL palGetKeycodeState(); +PAL_API const PalBool* PAL_CALL palGetKeycodeState(); /** * @brief Get the state of the scancodes (layout independent keys) of @@ -1377,7 +1360,7 @@ PAL_API const bool* PAL_CALL palGetKeycodeState(); * @since 1.0 * @ingroup pal_video */ -PAL_API const bool* PAL_CALL palGetScancodeState(); +PAL_API const PalBool* PAL_CALL palGetScancodeState(); /** * @brief Get the state of the buttons of the mouse. @@ -1395,7 +1378,7 @@ PAL_API const bool* PAL_CALL palGetScancodeState(); * @since 1.0 * @ingroup pal_video */ -PAL_API const bool* PAL_CALL palGetMouseState(); +PAL_API const PalBool* PAL_CALL palGetMouseState(); /** * @brief Get the relative movement of the mouse in desktop pixels. @@ -1473,7 +1456,7 @@ PAL_API void PAL_CALL palGetRawMouseWheelDelta( * @since 1.0 * @ingroup pal_video */ -PAL_API bool PAL_CALL palIsWindowVisible(PalWindow* window); +PAL_API PalBool PAL_CALL palIsWindowVisible(PalWindow* window); /** * @brief Get the current input-focused window per application. @@ -1806,7 +1789,7 @@ PAL_API void PAL_CALL palDestroyCursor(PalCursor* cursor); * @since 1.0 * @ingroup pal_video */ -PAL_API void PAL_CALL palShowCursor(bool show); +PAL_API void PAL_CALL palShowCursor(PalBool show); /** * @brief Clip the cursor to the provided window. @@ -1831,7 +1814,7 @@ PAL_API void PAL_CALL palShowCursor(bool show); */ PAL_API PalResult PAL_CALL palClipCursor( PalWindow* window, - bool clip); + PalBool clip); /** * @brief Get the position of the cursor relative to the provided window in diff --git a/src/core/pal_log.c b/src/core/pal_log.c index 511adc63..7618f778 100644 --- a/src/core/pal_log.c +++ b/src/core/pal_log.c @@ -50,7 +50,7 @@ typedef struct { char tmp[PAL_LOG_MSG_SIZE]; char buffer[PAL_LOG_MSG_SIZE]; wchar_t wideBuffer[PAL_LOG_MSG_SIZE]; - bool isLogging; + PalBool isLogging; } LogTLSData; static void destroyTlsData(void* data) diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 4839a76b..36f516a8 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -125,7 +125,7 @@ typedef struct { } Adapter; typedef struct { - bool debugLayer; + PalBool debugLayer; uint32_t adapterCount; uint32_t severityCount; uint32_t categoryCount; @@ -225,7 +225,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool belongsToSwapchain; + PalBool belongsToSwapchain; Device* device; ID3D12Resource* handle; PalImageInfo info; @@ -269,8 +269,8 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool isTimeline; - bool canReset; + PalBool isTimeline; + PalBool canReset; UINT64 value; ID3D12Fence* handle; } Fence, Semaphore; @@ -292,7 +292,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool primary; + PalBool primary; void* pool; // CommandPool Device* device; ID3D12Resource* stagingBuffer; @@ -303,7 +303,7 @@ typedef struct { } CommandBuffer; typedef struct { - bool used; + PalBool used; CommandBuffer* cmdBuffer; } CommandBufferData; @@ -318,11 +318,11 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool supportsAddress; - bool canChangeState; - bool hasIndirect; - bool isAccelerationStructure; - bool isScratch; + PalBool supportsAddress; + PalBool canChangeState; + PalBool hasIndirect; + PalBool isAccelerationStructure; + PalBool isScratch; uint64_t size; ID3D12Resource* handle; Device* device; @@ -345,7 +345,7 @@ typedef struct { } PipelineLayout; typedef struct { - bool isHitGroup; + PalBool isHitGroup; PalShaderStage stage; wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; } ShaderExport; @@ -369,7 +369,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool hasFsr; + PalBool hasFsr; uint32_t type; uint32_t shaderExportCount; D3D12_SHADING_RATE shadingRate; @@ -392,7 +392,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool isDirty; + PalBool isDirty; uint32_t stagingBufferSize; uint32_t handleSize; ID3D12Resource* buffer; @@ -414,7 +414,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool hasDescriptorIndexing; + PalBool hasDescriptorIndexing; uint32_t bindingCount; uint32_t samplerCount; D3D12_SHADER_VISIBILITY visibility; @@ -457,9 +457,9 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool hasDescriptorIndexing; - bool hasResourceHeap; - bool hasSamplerHeap; + PalBool hasDescriptorIndexing; + PalBool hasResourceHeap; + PalBool hasSamplerHeap; uint32_t maxSets; uint32_t usedSets; DescriptorHeapLimits limits; @@ -1277,7 +1277,7 @@ static DXGI_FORMAT vertexTypeToD3D12(PalVertexType type) return DXGI_FORMAT_UNKNOWN; } -static bool fillBuildInfoD3D12( +static PalBool fillBuildInfoD3D12( PalAccelerationStructureBuildInfo* info, D3D12_RAYTRACING_GEOMETRY_DESC* geometries, D3D12_GPU_VIRTUAL_ADDRESS srcAs, @@ -2688,7 +2688,7 @@ PalResult PAL_CALL createDeviceD3D12( // check if any of the features are not supported PalAdapterFeatures adapterFeatures = getAdapterFeaturesD3D12(adapter); - bool valid = (adapterFeatures & features) == features; + PalBool valid = (adapterFeatures & features) == features; if (!valid) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3349,7 +3349,7 @@ PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) return PAL_RESULT_SUCCESS; } -bool PAL_CALL canQueuePresentD3D12( +PalBool PAL_CALL canQueuePresentD3D12( PalQueue* queue, PalSurface* surface) { @@ -3412,7 +3412,7 @@ PalResult PAL_CALL enumerateFormatsD3D12( return PAL_RESULT_SUCCESS; } -bool PAL_CALL isFormatSupportedD3D12( +PalBool PAL_CALL isFormatSupportedD3D12( PalAdapter* adapter, PalFormat format) { @@ -3733,8 +3733,8 @@ PalResult PAL_CALL createImageViewD3D12( } imageView->heapIndex = UINT32_MAX; - bool hasRTV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); - bool hasDSV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); + PalBool hasRTV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); + PalBool hasDSV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); imageView->format = formatToD3D12(info->format); if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR && hasRTV) { @@ -3917,7 +3917,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( HRESULT result; Surface* d3dSurface = (Surface*)surface; Device* d3dDevice = (Device*)device; - bool supportHDR10 = false; + PalBool supportHDR10 = false; IDXGISwapChain1* swapchain1 = nullptr; IDXGISwapChain3* swapchain3 = nullptr; @@ -4059,7 +4059,7 @@ PalResult PAL_CALL createSwapchainD3D12( Device* d3dDevice = (Device*)device; Queue* d3dQueue = (Queue*)queue; Swapchain* swapchain = nullptr; - bool isHDRColorspace = false; + PalBool isHDRColorspace = false; if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -4286,7 +4286,7 @@ PalResult PAL_CALL presentSwapchainD3D12( // check if swapchain needs to be resize RECT windowRect; - bool ret = GetClientRect((HWND)d3dSwapchain->surface->handle, &windowRect); + PalBool ret = GetClientRect((HWND)d3dSwapchain->surface->handle, &windowRect); uint32_t w = windowRect.right - windowRect.left; uint32_t h = windowRect.bottom - windowRect.top; @@ -4439,7 +4439,7 @@ void PAL_CALL destroyShaderD3D12(PalShader* shader) PalResult PAL_CALL createFenceD3D12( PalDevice* device, - bool signaled, + PalBool signaled, PalFence** outFence) { HRESULT result; @@ -4535,7 +4535,7 @@ PalResult PAL_CALL resetFenceD3D12(PalFence* fence) return PAL_RESULT_SUCCESS; } -bool PAL_CALL isFenceSignaledD3D12(PalFence* fence) +PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence) { Fence* d3dFence = (Fence*)fence; if (d3dFence->handle->lpVtbl->GetCompletedValue(d3dFence->handle) == 0) { @@ -4550,13 +4550,13 @@ bool PAL_CALL isFenceSignaledD3D12(PalFence* fence) PalResult PAL_CALL createSemaphoreD3D12( PalDevice* device, - bool enableTimeline, + PalBool enableTimeline, PalSemaphore** outSemaphore) { HRESULT result; Device* d3dDevice = (Device*)device; Semaphore* semaphore = nullptr; - bool hasTimeline = d3dDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; + PalBool hasTimeline = d3dDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; semaphore = palAllocate(s_D3D.allocator, sizeof(Semaphore), 0); if (!semaphore) { @@ -5154,7 +5154,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( } memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); - bool success = fillBuildInfoD3D12( + PalBool success = fillBuildInfoD3D12( info, geometries, srcAsAddress, @@ -5174,7 +5174,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( palFree(s_D3D.allocator, geometries); } else { - bool success = fillBuildInfoD3D12( + PalBool success = fillBuildInfoD3D12( info, nullptr, srcAsAddress, @@ -6304,14 +6304,14 @@ PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( PalResult PAL_CALL cmdSetDepthTestEnableD3D12( PalCommandBuffer* cmdBuffer, - bool enable) + PalBool enable) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( PalCommandBuffer* cmdBuffer, - bool enable) + PalBool enable) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6390,7 +6390,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( } memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); - bool success = fillBuildInfoD3D12( + PalBool success = fillBuildInfoD3D12( info, geometries, 0, @@ -6409,7 +6409,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( palFree(s_D3D.allocator, geometries); } else { - bool success = fillBuildInfoD3D12( + PalBool success = fillBuildInfoD3D12( info, nullptr, 0, @@ -6724,7 +6724,7 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( DescriptorSetBinding* bindings = nullptr; uint32_t count = info->bindingCount; - bool hasDescriptorIndexing = d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + PalBool hasDescriptorIndexing = d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -6934,7 +6934,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( Device* d3dDevice = (Device*)device; DescriptorPool* pool = nullptr; - bool hasDescriptorIndexing = d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + PalBool hasDescriptorIndexing = d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7659,7 +7659,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( HRESULT result; uint32_t patchControlPoints = 0; uint32_t totalSize = 0; - bool alphaToCoverageEnable = false; + PalBool alphaToCoverageEnable = false; Pipeline* pipeline = nullptr; Device* d3dDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; @@ -8767,8 +8767,8 @@ PalResult PAL_CALL createShaderBindingTableD3D12( ShaderExport* tmp = &pipeline->shaderExports[i]; PalShaderStage stage = tmp->stage; - // skip any hit, closest hit, intersection shaders without isHitGroup bool - bool isHitGroup = false; + // skip any hit, closest hit, intersection shaders without isHitGroup PalBool + PalBool isHitGroup = false; if (stage == PAL_SHADER_STAGE_ANY_HIT || stage == PAL_SHADER_STAGE_CLOSEST_HIT || stage == PAL_SHADER_STAGE_INTERSECTION) { diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 55c5cabe..54ff9115 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -67,7 +67,7 @@ typedef struct { } BackendData; typedef struct { - bool initialized; + PalBool initialized; int32_t backendCount; const PalAllocator* allocator; BackendData backends[MAX_BACKENDS]; @@ -204,7 +204,7 @@ void PAL_CALL destroyQueueVk(PalQueue* queue); PalResult PAL_CALL waitQueueVk(PalQueue* queue); -bool PAL_CALL canQueuePresentVk( +PalBool PAL_CALL canQueuePresentVk( PalQueue* queue, PalSurface* surface); @@ -217,7 +217,7 @@ PalResult PAL_CALL enumerateFormatsVk( int32_t* count, PalFormatInfo* outFormats); -bool PAL_CALL isFormatSupportedVk( +PalBool PAL_CALL isFormatSupportedVk( PalAdapter* adapter, PalFormat format); @@ -348,7 +348,7 @@ void PAL_CALL destroyShaderVk(PalShader* shader); PalResult PAL_CALL createFenceVk( PalDevice* device, - bool signaled, + PalBool signaled, PalFence** outFence); void PAL_CALL destroyFenceVk(PalFence* fence); @@ -359,7 +359,7 @@ PalResult PAL_CALL waitFenceVk( PalResult PAL_CALL resetFenceVk(PalFence* fence); -bool PAL_CALL isFenceSignaledVk(PalFence* fence); +PalBool PAL_CALL isFenceSignaledVk(PalFence* fence); // ================================================== // Semaphore @@ -367,7 +367,7 @@ bool PAL_CALL isFenceSignaledVk(PalFence* fence); PalResult PAL_CALL createSemaphoreVk( PalDevice* device, - bool enableTimeline, + PalBool enableTimeline, PalSemaphore** outSemaphore); void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore); @@ -625,11 +625,11 @@ PalResult PAL_CALL cmdSetPrimitiveTopologyVk( PalResult PAL_CALL cmdSetDepthTestEnableVk( PalCommandBuffer* cmdBuffer, - bool enable); + PalBool enable); PalResult PAL_CALL cmdSetDepthWriteEnableVk( PalCommandBuffer* cmdBuffer, - bool enable); + PalBool enable); PalResult PAL_CALL cmdSetStencilOpVk( PalCommandBuffer* cmdBuffer, @@ -1083,7 +1083,7 @@ void PAL_CALL destroyQueueD3D12(PalQueue* queue); PalResult PAL_CALL waitQueueD3D12(PalQueue* queue); -bool PAL_CALL canQueuePresentD3D12( +PalBool PAL_CALL canQueuePresentD3D12( PalQueue* queue, PalSurface* surface); @@ -1096,7 +1096,7 @@ PalResult PAL_CALL enumerateFormatsD3D12( int32_t* count, PalFormatInfo* outFormats); -bool PAL_CALL isFormatSupportedD3D12( +PalBool PAL_CALL isFormatSupportedD3D12( PalAdapter* adapter, PalFormat format); @@ -1227,7 +1227,7 @@ void PAL_CALL destroyShaderD3D12(PalShader* shader); PalResult PAL_CALL createFenceD3D12( PalDevice* device, - bool signaled, + PalBool signaled, PalFence** outFence); void PAL_CALL destroyFenceD3D12(PalFence* fence); @@ -1238,7 +1238,7 @@ PalResult PAL_CALL waitFenceD3D12( PalResult PAL_CALL resetFenceD3D12(PalFence* fence); -bool PAL_CALL isFenceSignaledD3D12(PalFence* fence); +PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence); // ================================================== // Semaphore @@ -1246,7 +1246,7 @@ bool PAL_CALL isFenceSignaledD3D12(PalFence* fence); PalResult PAL_CALL createSemaphoreD3D12( PalDevice* device, - bool enableTimeline, + PalBool enableTimeline, PalSemaphore** outSemaphore); void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); @@ -1504,11 +1504,11 @@ PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( PalResult PAL_CALL cmdSetDepthTestEnableD3D12( PalCommandBuffer* cmdBuffer, - bool enable); + PalBool enable); PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( PalCommandBuffer* cmdBuffer, - bool enable); + PalBool enable); PalResult PAL_CALL cmdSetStencilOpD3D12( PalCommandBuffer* cmdBuffer, @@ -2498,7 +2498,7 @@ void PAL_CALL palDestroyQueue(PalQueue* queue) } } -bool PAL_CALL palCanQueuePresent( +PalBool PAL_CALL palCanQueuePresent( PalQueue* queue, PalSurface* surface) { @@ -2545,7 +2545,7 @@ PalResult PAL_CALL palEnumerateFormats( return adapter->backend->enumerateFormats(adapter, count, outFormats); } -bool PAL_CALL palIsFormatSupported( +PalBool PAL_CALL palIsFormatSupported( PalAdapter* adapter, PalFormat format) { @@ -2953,7 +2953,7 @@ void PAL_CALL palDestroyShader(PalShader* shader) PalResult PAL_CALL palCreateFence( PalDevice* device, - bool signaled, + PalBool signaled, PalFence** outFence) { if (!s_Graphics.initialized) { @@ -3011,7 +3011,7 @@ PalResult PAL_CALL palResetFence(PalFence* fence) return fence->backend->resetFence(fence); } -bool PAL_CALL palIsFenceSignaled(PalFence* fence) +PalBool PAL_CALL palIsFenceSignaled(PalFence* fence) { if (s_Graphics.initialized && fence) { return fence->backend->isFenceSignaled(fence); @@ -3025,7 +3025,7 @@ bool PAL_CALL palIsFenceSignaled(PalFence* fence) PalResult PAL_CALL palCreateSemaphore( PalDevice* device, - bool enableTimeline, + PalBool enableTimeline, PalSemaphore** outSemaphore) { if (!s_Graphics.initialized) { @@ -3910,7 +3910,7 @@ PalResult PAL_CALL palCmdSetPrimitiveTopology( PalResult PAL_CALL palCmdSetDepthTestEnable( PalCommandBuffer* cmdBuffer, - bool enable) + PalBool enable) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -3925,7 +3925,7 @@ PalResult PAL_CALL palCmdSetDepthTestEnable( PalResult PAL_CALL palCmdSetDepthWriteEnable( PalCommandBuffer* cmdBuffer, - bool enable) + PalBool enable) { if (!s_Graphics.initialized) { return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; @@ -4540,7 +4540,7 @@ PalResult PAL_CALL palUpdateShaderBindingTable( // Utils // ================================================== -bool PAL_CALL palBuildWorkGroupInfo( +PalBool PAL_CALL palBuildWorkGroupInfo( const PalWorkGroupBuildData* data, int32_t* count, PalWorkGroupInfo* infos) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index de27977f..cfe24888 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -222,7 +222,7 @@ typedef struct { } Adapter; typedef struct { - bool useCache; + PalBool useCache; void* handle; Adapter* adapters; VkInstance instance; @@ -444,7 +444,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool belongsToSwapchain; + PalBool belongsToSwapchain; Device* device; Memory* memory; VkImage handle; @@ -502,7 +502,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool primary; + PalBool primary; Device* device; CommandPool* pool; void* pipeline; @@ -521,7 +521,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool isTimeline; + PalBool isTimeline; Device* device; VkSemaphore handle; } Semaphore; @@ -549,7 +549,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool hasDescriptorIndexing; + PalBool hasDescriptorIndexing; Device* device; VkDescriptorSetLayout handle; } DescriptorSetLayout; @@ -557,7 +557,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool hasDescriptorIndexing; + PalBool hasDescriptorIndexing; Device* device; VkDescriptorPool handle; } DescriptorPool; @@ -614,7 +614,7 @@ typedef struct { typedef struct { const PalGraphicsBackend* backend; - bool isDirty; + PalBool isDirty; uint32_t stagingBufferSize; uint32_t handleSize; Device* device; @@ -3023,7 +3023,7 @@ PalResult PAL_CALL initGraphicsVk( // clang-format on // get version - bool versionFallback = false; + PalBool versionFallback = false; uint32_t version = 0; if (s_Vk.enumerateInstanceVersion) { s_Vk.enumerateInstanceVersion(&version); @@ -3034,7 +3034,7 @@ PalResult PAL_CALL initGraphicsVk( VkResult result; uint32_t layerCount = 0; - bool hasValidationLayer = false; + PalBool hasValidationLayer = false; s_Vk.messenger = nullptr; s_Vk.allocator = allocator; VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {0}; @@ -3106,12 +3106,12 @@ PalResult PAL_CALL initGraphicsVk( return PAL_RESULT_SUCCESS; } - bool hasXlib = false; - bool hasXcb = false; - bool hasWayland = false; - bool hasWin32 = false; - bool hasSurface = false; - bool hasExtDebug = false; + PalBool hasXlib = false; + PalBool hasXcb = false; + PalBool hasWayland = false; + PalBool hasWin32 = false; + PalBool hasSurface = false; + PalBool hasExtDebug = false; s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, extensionProps); for (int i = 0; i < extCount; i++) { @@ -3366,7 +3366,7 @@ PalResult PAL_CALL enumerateAdaptersVk( return PAL_RESULT_OUT_OF_MEMORY; } - bool found = false; + PalBool found = false; s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extCount, exts); for (int i = 0; i < extCount; i++) { @@ -3625,19 +3625,19 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } // check extensions - bool rayTracing = false; - bool accelerationStructure = false; - bool meshShader = false; - bool fragmentRateShading = false; - bool timelineSemaphore = false; - bool descriptorIndexing = false; - bool shaderFloat16 = false; - bool multiiView = false; - bool dynamicstate = false; - bool bufferDeviceAddress = false; - bool shaderParameters = false; - bool nullDescriptors = false; - bool rayQuery = false; + PalBool rayTracing = false; + PalBool accelerationStructure = false; + PalBool meshShader = false; + PalBool fragmentRateShading = false; + PalBool timelineSemaphore = false; + PalBool descriptorIndexing = false; + PalBool shaderFloat16 = false; + PalBool multiiView = false; + PalBool dynamicstate = false; + PalBool bufferDeviceAddress = false; + PalBool shaderParameters = false; + PalBool nullDescriptors = false; + PalBool rayQuery = false; s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, extensionProps); // clang-format off @@ -5231,7 +5231,7 @@ PalResult PAL_CALL waitQueueVk(PalQueue* queue) return PAL_RESULT_SUCCESS; } -bool PAL_CALL canQueuePresentVk( +PalBool PAL_CALL canQueuePresentVk( PalQueue* queue, PalSurface* surface) { @@ -5297,7 +5297,7 @@ PalResult PAL_CALL enumerateFormatsVk( return PAL_RESULT_SUCCESS; } -bool PAL_CALL isFormatSupportedVk( +PalBool PAL_CALL isFormatSupportedVk( PalAdapter* adapter, PalFormat format) { @@ -5347,7 +5347,7 @@ PalSampleCount PAL_CALL queryFormatSampleCountVk( VkImageUsageFlags vkImageUsage = 0; PalImageUsages imageUsages = ImageUsageFromVk(props.optimalTilingFeatures); - bool isDepth = (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) != 0; + PalBool isDepth = (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) != 0; if (isDepth) { vkImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } else { @@ -6266,7 +6266,7 @@ void PAL_CALL destroyShaderVk(PalShader* shader) PalResult PAL_CALL createFenceVk( PalDevice* device, - bool signaled, + PalBool signaled, PalFence** outFence) { VkResult result; @@ -6342,7 +6342,7 @@ PalResult PAL_CALL resetFenceVk(PalFence* fence) return PAL_RESULT_SUCCESS; } -bool PAL_CALL isFenceSignaledVk(PalFence* fence) +PalBool PAL_CALL isFenceSignaledVk(PalFence* fence) { Fence* vkFence = (Fence*)fence; VkResult result = s_Vk.isFenceSignaled(vkFence->device->handle, vkFence->handle); @@ -6359,13 +6359,13 @@ bool PAL_CALL isFenceSignaledVk(PalFence* fence) PalResult PAL_CALL createSemaphoreVk( PalDevice* device, - bool enableTimeline, + PalBool enableTimeline, PalSemaphore** outSemaphore) { VkResult result; Semaphore* semaphore = nullptr; Device* vkDevice = (Device*)device; - bool hasTimeline = vkDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; + PalBool hasTimeline = vkDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; semaphore = palAllocate(s_Vk.allocator, sizeof(Semaphore), 0); if (!semaphore) { @@ -8038,7 +8038,7 @@ PalResult PAL_CALL cmdSetPrimitiveTopologyVk( PalResult PAL_CALL cmdSetDepthTestEnableVk( PalCommandBuffer* cmdBuffer, - bool enable) + PalBool enable) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = vkCmdBuffer->device; @@ -8053,7 +8053,7 @@ PalResult PAL_CALL cmdSetDepthTestEnableVk( PalResult PAL_CALL cmdSetDepthWriteEnableVk( PalCommandBuffer* cmdBuffer, - bool enable) + PalBool enable) { CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; Device* device = vkCmdBuffer->device; @@ -8487,7 +8487,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( uint32_t count = info->bindingCount; VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsCreateInfo = {0}; - bool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -8584,7 +8584,7 @@ PalResult PAL_CALL createDescriptorPoolVk( uint32_t maxBindings = info->maxDescriptorBindingSizes; VkDescriptorPoolCreateInfo createInfo = {0}; - bool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } diff --git a/src/opengl/pal_opengl_linux.c b/src/opengl/pal_opengl_linux.c index 6b615be4..8f9ff859 100644 --- a/src/opengl/pal_opengl_linux.c +++ b/src/opengl/pal_opengl_linux.c @@ -215,13 +215,13 @@ typedef void(PAL_GL_APIENTRY* glClearColorFn)( float); typedef struct { - bool used; + PalBool used; EGLSurface surface; PalGLContext* context; } ContextData; typedef struct { - bool initialized; + PalBool initialized; int32_t maxContextData; EGLenum apiType; int apiTypeBit; @@ -263,7 +263,7 @@ static GLLinux s_GL = {0}; // Internal API // ================================================== -static inline bool checkExtension( +static inline PalBool checkExtension( const char* extension, const char* extensions) { @@ -918,7 +918,7 @@ PalResult PAL_CALL palCreateGLContext( } // check version - bool valid = info->major < s_GL.info.major || + PalBool valid = info->major < s_GL.info.major || (info->major == s_GL.info.major && info->minor <= s_GL.info.minor); if (!valid) { diff --git a/src/opengl/pal_opengl_win32.c b/src/opengl/pal_opengl_win32.c index eadc1f11..d8837fd3 100644 --- a/src/opengl/pal_opengl_win32.c +++ b/src/opengl/pal_opengl_win32.c @@ -179,7 +179,7 @@ typedef struct { } Gdi; typedef struct { - bool initialized; + PalBool initialized; wglGetProcAddressFn wglGetProcAddress; wglCreateContextFn wglCreateContext; wglDeleteContextFn wglDeleteContext; @@ -210,7 +210,7 @@ static Wgl s_Wgl = {0}; // Internal API // ================================================== -static inline bool checkExtension( +static inline PalBool checkExtension( const char* extension, const char* extensions) { @@ -804,7 +804,7 @@ PalResult PAL_CALL palCreateGLContext( // clang-format off // check version - bool valid = info->major < s_Wgl.info.major || + PalBool valid = info->major < s_Wgl.info.major || (info->major == s_Wgl.info.major && info->minor <= s_Wgl.info.minor); // clang-format on diff --git a/src/pal_event.c b/src/pal_event.c index 87026bd4..0701cfce 100644 --- a/src/pal_event.c +++ b/src/pal_event.c @@ -17,7 +17,7 @@ typedef struct { } QueueData; struct PalEventDriver { - bool freeQueue; + PalBool freeQueue; PalEventQueue* queue; const PalAllocator* allocator; PalEventCallback callback; @@ -34,7 +34,7 @@ static void PAL_CALL defaultPush( data->data[data->tail++ % PAL_MAX_EVENTS] = *event; } -static bool PAL_CALL defaultPoll( +static PalBool PAL_CALL defaultPoll( void* queue, PalEvent* outEvent) { @@ -167,7 +167,7 @@ void PAL_CALL palPushEvent( } } -bool PAL_CALL palPollEvent( +PalBool PAL_CALL palPollEvent( PalEventDriver* eventDriver, PalEvent* outEvent) { diff --git a/src/system/pal_system_win32.c b/src/system/pal_system_win32.c index 14986757..6e4fbc1d 100644 --- a/src/system/pal_system_win32.c +++ b/src/system/pal_system_win32.c @@ -45,7 +45,7 @@ static inline void cpuid( #endif // _MSC_VER } -static inline bool getVersionWin32(PalVersion* version) +static inline PalBool getVersionWin32(PalVersion* version) { OSVERSIONINFOEXW ver = {0}; ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); @@ -65,7 +65,7 @@ static inline bool getVersionWin32(PalVersion* version) return true; } -static inline bool isVersionWin32( +static inline PalBool isVersionWin32( PalVersion* osVersion, uint16_t major, uint16_t minor, diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index af955414..9e9a2b85 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -141,14 +141,14 @@ typedef struct { } SpanMonitor; typedef struct { - bool skipConfigure; - bool skipState; - bool used; - bool isAttached; - bool skipIfAttached; - bool focused; - bool pushConfigureEvent; - bool pushStateEvent; + PalBool skipConfigure; + PalBool skipState; + PalBool used; + PalBool isAttached; + PalBool skipIfAttached; + PalBool focused; + PalBool pushConfigureEvent; + PalBool pushStateEvent; int x; int y; uint32_t w; @@ -173,7 +173,7 @@ typedef struct { } WindowData; typedef struct { - bool used; + PalBool used; int dpi; int x; int y; @@ -188,7 +188,7 @@ typedef struct { } MonitorData; typedef struct { - bool pendingScroll; + PalBool pendingScroll; int32_t lastX; int32_t lastY; int32_t dx; @@ -197,7 +197,7 @@ typedef struct { int32_t WheelY; float WheelXf; float WheelYf; - bool state[PAL_MOUSE_BUTTON_MAX]; + PalBool state[PAL_MOUSE_BUTTON_MAX]; double tmpScrollX; double tmpScrollY; double accumScrollX; @@ -205,8 +205,8 @@ typedef struct { } Mouse; typedef struct { - bool scancodeState[PAL_SCANCODE_MAX]; - bool keycodeState[PAL_KEYCODE_MAX]; + PalBool scancodeState[PAL_SCANCODE_MAX]; + PalBool keycodeState[PAL_KEYCODE_MAX]; int repeatRate; int repeatDelay; int repeatKey; @@ -257,7 +257,7 @@ typedef struct { PalResult (*getWindowPos)(PalWindow*, int32_t*, int32_t*); PalResult (*getWindowSize)(PalWindow*, uint32_t*, uint32_t*); PalResult (*getWindowState)(PalWindow*, PalWindowState*); - bool (*isWindowVisible)(PalWindow*); + PalBool (*isWindowVisible)(PalWindow*); PalWindow* (*getFocusWindow)(); PalWindowHandleInfo (*getWindowHandleInfo)(PalWindow*); PalWindowHandleInfoEx (*getWindowHandleInfoEx)(PalWindow*); @@ -275,8 +275,8 @@ typedef struct { PalResult (*createCursor)(const PalCursorCreateInfo*, PalCursor**); PalResult (*createCursorFrom)(PalCursorType, PalCursor**); void (*destroyCursor)(PalCursor*); - void (*showCursor)(bool); - PalResult (*clipCursor)(PalWindow*, bool); + void (*showCursor)(PalBool); + PalResult (*clipCursor)(PalWindow*, PalBool); PalResult (*getCursorPos)(PalWindow*, int32_t*, int32_t*); PalResult (*setCursorPos)(PalWindow*, int32_t, int32_t); PalResult (*setWindowCursor)(PalWindow*, PalCursor*); @@ -287,7 +287,7 @@ typedef struct { } Backend; typedef struct { - bool initialized; + PalBool initialized; int32_t maxWindowData; int32_t maxMonitorData; int32_t pixelFormat; @@ -721,7 +721,7 @@ typedef int (*Xutf8LookupStringFn)( int*); typedef struct { - bool unicodeTitle; + PalBool unicodeTitle; Atom WM_DELETE_WINDOW; Atom _NET_SUPPORTED; @@ -746,8 +746,8 @@ typedef struct { } X11Atoms; typedef struct { - bool error; - bool skipScreenEvent; + PalBool error; + PalBool skipScreenEvent; int bpp; int screen; int depth; @@ -966,7 +966,7 @@ typedef void (*wl_egl_window_resize_fn)( int); typedef struct { - bool checkFeatures; + PalBool checkFeatures; int monitorCount; void* handle; @@ -1596,7 +1596,7 @@ static void pointerHandleButton( return; } - bool pressed = state == WL_POINTER_BUTTON_STATE_PRESSED; + PalBool pressed = state == WL_POINTER_BUTTON_STATE_PRESSED; PalMouseButton _button = 0; PalEventType type = PAL_EVENT_MOUSE_BUTTONUP; @@ -1824,7 +1824,7 @@ static void keyboardHandleKey( PalScancode scancode = 0; PalKeycode keycode = 0; - bool pressed = (state == WL_KEYBOARD_KEY_STATE_PRESSED); + PalBool pressed = (state == WL_KEYBOARD_KEY_STATE_PRESSED); PalEventType type = PAL_EVENT_KEYUP; PalDispatchMode mode = PAL_DISPATCH_NONE; xkb_keysym_t keySym = s_Wl.xkbStateKeyGetOneSym(s_Wl.state, key + 8); @@ -2012,7 +2012,7 @@ static struct wl_buffer* createShmBuffer( int width, int height, const uint8_t* pixels, - bool cursor); + PalBool cursor); const struct wl_interface xdg_popup_interface; const struct wl_interface xdg_positioner_interface; @@ -2202,7 +2202,7 @@ static void xdgToplevelHandleConfigure( { WindowData* winData = (WindowData*)data; uint32_t* state; - bool activated = false; + PalBool activated = false; wl_array_for_each(state, states) { // we need only maximized @@ -3321,7 +3321,7 @@ static void xSendWMEvent( long b, long c, long d, - bool add) + PalBool add) { XEvent e = {0}; e.xclient.type = ClientMessage; @@ -4093,7 +4093,7 @@ static void xUpdateVideo() case ButtonPress: case ButtonRelease: { int xButton = event.xbutton.button; - bool pressed = (event.xbutton.type == ButtonPress); + PalBool pressed = (event.xbutton.type == ButtonPress); PalMouseButton button = 0; PalEventType type; @@ -4159,7 +4159,7 @@ static void xUpdateVideo() case KeyPress: case KeyRelease: { int xScancode = event.xkey.keycode; - bool pressed = (event.xbutton.type == KeyPress); + PalBool pressed = (event.xbutton.type == KeyPress); PalScancode scancode = PAL_SCANCODE_UNKNOWN; PalKeycode keycode = PAL_KEYCODE_UNKNOWN; PalEventType type; @@ -4201,7 +4201,7 @@ static void xUpdateVideo() } // update our keyboard and mouse state to handle key repeat - bool repeat = s_Keyboard.keycodeState[keycode]; + PalBool repeat = s_Keyboard.keycodeState[keycode]; s_Keyboard.scancodeState[scancode] = pressed; s_Keyboard.keycodeState[keycode] = pressed; @@ -4985,7 +4985,7 @@ static PalResult xCreateWindow( // we use this to minimize or maximize XWindowAttributes attr; s_X11.getWindowAttributes(s_X11.display, window, &attr); - bool windowMapped = attr.map_state = IsViewable; + PalBool windowMapped = attr.map_state = IsViewable; // maximize if (info->maximized) { @@ -5197,7 +5197,7 @@ PalResult xFlashWindow( return PAL_RESULT_INVALID_WINDOW; } - bool add = false; + PalBool add = false; if (info->flags & PAL_FLASH_TRAY) { add = true; } @@ -5403,7 +5403,7 @@ PalResult xGetWindowState( return PAL_RESULT_SUCCESS; } -bool xIsWindowVisible(PalWindow* window) +PalBool xIsWindowVisible(PalWindow* window) { Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; @@ -5732,7 +5732,7 @@ void xDestroyCursor(PalCursor* cursor) s_X11.freeCursor(s_X11.display, FROM_PAL_HANDLE(Cursor, cursor)); } -void xShowCursor(bool show) +void xShowCursor(PalBool show) { // x11 does not support Hiding and showing cursor return; @@ -5740,7 +5740,7 @@ void xShowCursor(bool show) PalResult xClipCursor( PalWindow* window, - bool clip) + PalBool clip) { Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; @@ -6088,7 +6088,7 @@ static struct wl_buffer* createShmBuffer( int width, int height, const uint8_t* pixels, - bool cursor) + PalBool cursor) { int stride = width * 4; uint64_t size = stride * height; @@ -7050,7 +7050,7 @@ PalResult wlGetWindowState( return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; } -bool wlIsWindowVisible(PalWindow* window) +PalBool wlIsWindowVisible(PalWindow* window) { return false; } @@ -7260,7 +7260,7 @@ void wlDestroyCursor(PalCursor* cursor) palFree(s_Video.allocator, waylandCursor); } -void wlShowCursor(bool show) +void wlShowCursor(PalBool show) { // not supported return; @@ -7268,7 +7268,7 @@ void wlShowCursor(bool show) PalResult wlClipCursor( PalWindow* window, - bool clip) + PalBool clip) { if (!(s_Video.features & PAL_VIDEO_FEATURE_CLIP_CURSOR)) { return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; @@ -7399,7 +7399,7 @@ PalResult PAL_CALL palInitVideo( } // get backend type - bool x11 = true; + PalBool x11 = true; const char* session = getenv("XDG_SESSION_TYPE"); if (session) { if (strcmp(session, "wayland") == 0) { @@ -7869,7 +7869,7 @@ PalResult PAL_CALL palGetWindowState( return s_Video.backend->getWindowState(window, outState); } -const bool* PAL_CALL palGetKeycodeState() +const PalBool* PAL_CALL palGetKeycodeState() { if (!s_Video.initialized) { return nullptr; @@ -7877,7 +7877,7 @@ const bool* PAL_CALL palGetKeycodeState() return s_Keyboard.keycodeState; } -const bool* PAL_CALL palGetScancodeState() +const PalBool* PAL_CALL palGetScancodeState() { if (!s_Video.initialized) { return nullptr; @@ -7885,7 +7885,7 @@ const bool* PAL_CALL palGetScancodeState() return s_Keyboard.scancodeState; } -const bool* PAL_CALL palGetMouseState() +const PalBool* PAL_CALL palGetMouseState() { if (!s_Video.initialized) { return nullptr; @@ -7944,7 +7944,7 @@ void PAL_CALL palGetRawMouseWheelDelta( } } -bool PAL_CALL palIsWindowVisible(PalWindow* window) +PalBool PAL_CALL palIsWindowVisible(PalWindow* window) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; @@ -8164,7 +8164,7 @@ void PAL_CALL palDestroyCursor(PalCursor* cursor) } } -void PAL_CALL palShowCursor(bool show) +void PAL_CALL palShowCursor(PalBool show) { if (s_Video.initialized) { s_Video.backend->showCursor(show); @@ -8173,7 +8173,7 @@ void PAL_CALL palShowCursor(bool show) PalResult PAL_CALL palClipCursor( PalWindow* window, - bool clip) + PalBool clip) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; diff --git a/src/video/pal_video_win32.c b/src/video/pal_video_win32.c index 421f3c1f..09a9d0e6 100644 --- a/src/video/pal_video_win32.c +++ b/src/video/pal_video_win32.c @@ -95,15 +95,15 @@ typedef BOOL(WINAPI* SetPixelFormatFn)( CONST PIXELFORMATDESCRIPTOR*); typedef struct { - bool used; - bool isAttached; + PalBool used; + PalBool isAttached; PalWindowState state; HCURSOR cursor; LONG_PTR wndProc; } WindowData; typedef struct { - bool initialized; + PalBool initialized; int32_t pixelFormat; int32_t maxWindowData; PalVideoFeatures features; @@ -134,9 +134,9 @@ typedef struct { } MonitorData; typedef struct { - bool pendingResize; - bool pendingMove; - bool pendingState; + PalBool pendingResize; + PalBool pendingMove; + PalBool pendingState; uint32_t width; uint32_t height; int32_t x; @@ -147,19 +147,19 @@ typedef struct { typedef struct { int32_t pendingHighSurrogate; - bool scancodeState[PAL_SCANCODE_MAX]; - bool keycodeState[PAL_KEYCODE_MAX]; + PalBool scancodeState[PAL_SCANCODE_MAX]; + PalBool keycodeState[PAL_KEYCODE_MAX]; int scancodes[512]; int keycodes[256]; } Keyboard; typedef struct { - bool push; + PalBool push; int32_t dx; int32_t dy; int32_t WheelX; int32_t WheelY; - bool state[PAL_MOUSE_BUTTON_MAX]; + PalBool state[PAL_MOUSE_BUTTON_MAX]; } Mouse; static PendingEvent s_Event; @@ -299,7 +299,7 @@ LRESULT CALLBACK videoProc( if (mode != PAL_DISPATCH_NONE) { PalEvent event = {0}; event.type = type; - event.data = (bool)wParam; + event.data = (PalBool)wParam; event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); } @@ -504,7 +504,7 @@ LRESULT CALLBACK videoProc( case WM_XBUTTONUP: { PalMouseButton button = PAL_MOUSE_BUTTON_UNKNOWN; PalEventType type; - bool pressed = false; + PalBool pressed = false; if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) { button = PAL_MOUSE_BUTTON_LEFT; @@ -573,8 +573,8 @@ LRESULT CALLBACK videoProc( PalEventType type; int32_t win32Keycode; int32_t win32Scancode; - bool pressed = false; - bool extended = false; + PalBool pressed = false; + PalBool extended = false; pressed = (HIWORD(lParam) & KF_UP) ? false : true; extended = (lParam >> 24) & 1; // we use this for special keys @@ -619,7 +619,7 @@ LRESULT CALLBACK videoProc( } // check before updating state - bool repeat = s_Keyboard.keycodeState[keycode]; + PalBool repeat = s_Keyboard.keycodeState[keycode]; if (pressed) { s_Keyboard.keycodeState[keycode] = true; s_Keyboard.scancodeState[scancode] = true; @@ -764,7 +764,7 @@ static inline DWORD orientationToin32(PalOrientation orientation) static inline PalResult setMonitorMode( PalMonitor* monitor, PalMonitorMode* mode, - bool test) + PalBool test) { if (!monitor || !mode) { return PAL_RESULT_NULL_POINTER; @@ -808,7 +808,7 @@ static inline PalResult setMonitorMode( } } -static inline bool compareMonitorMode( +static inline PalBool compareMonitorMode( const PalMonitorMode* a, const PalMonitorMode* b) { @@ -1645,10 +1645,10 @@ PalResult PAL_CALL palSetMonitorOrientation( // clang-format off // only swap size if switching between landscape and portrait - bool isMonitorLandscape = (monitorOrientation == DMDO_DEFAULT || + PalBool isMonitorLandscape = (monitorOrientation == DMDO_DEFAULT || monitorOrientation == DMDO_180); - bool isLandscape = (win32Orientation == DMDO_DEFAULT || + PalBool isLandscape = (win32Orientation == DMDO_DEFAULT || win32Orientation == DMDO_180); // clang-format on @@ -1996,7 +1996,7 @@ PalResult PAL_CALL palFlashWindow( flashInfo.hwnd = (HWND)window; flashInfo.uCount = info->count; - bool success = FlashWindowEx(&flashInfo); + PalBool success = FlashWindowEx(&flashInfo); if (!success) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { @@ -2225,7 +2225,7 @@ PalResult PAL_CALL palGetWindowState( return PAL_RESULT_SUCCESS; } -const bool* PAL_CALL palGetKeycodeState() +const PalBool* PAL_CALL palGetKeycodeState() { if (!s_Video.initialized) { return nullptr; @@ -2233,7 +2233,7 @@ const bool* PAL_CALL palGetKeycodeState() return s_Keyboard.keycodeState; } -const bool* PAL_CALL palGetScancodeState() +const PalBool* PAL_CALL palGetScancodeState() { if (!s_Video.initialized) { return nullptr; @@ -2241,7 +2241,7 @@ const bool* PAL_CALL palGetScancodeState() return s_Keyboard.scancodeState; } -const bool* PAL_CALL palGetMouseState() +const PalBool* PAL_CALL palGetMouseState() { if (!s_Video.initialized) { return nullptr; @@ -2300,7 +2300,7 @@ void PAL_CALL palGetRawMouseWheelDelta( } } -bool PAL_CALL palIsWindowVisible(PalWindow* window) +PalBool PAL_CALL palIsWindowVisible(PalWindow* window) { if (!s_Video.initialized) { return false; @@ -2361,7 +2361,7 @@ PalResult PAL_CALL palSetWindowOpacity( opacity = 1.0f; } - bool ret = SetLayeredWindowAttributes((HWND)window, 0, (BYTE)(opacity * 255), LWA_ALPHA); + PalBool ret = SetLayeredWindowAttributes((HWND)window, 0, (BYTE)(opacity * 255), LWA_ALPHA); if (!ret) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { @@ -2439,7 +2439,7 @@ PalResult PAL_CALL palSetWindowStyle( SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle); // force a frame update - bool success = SetWindowPos( + PalBool success = SetWindowPos( hwnd, nullptr, 0, @@ -2498,7 +2498,7 @@ PalResult PAL_CALL palSetWindowPos( return PAL_RESULT_NULL_POINTER; } - bool success = + PalBool success = SetWindowPos((HWND)window, nullptr, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); if (!success) { @@ -2527,7 +2527,7 @@ PalResult PAL_CALL palSetWindowSize( return PAL_RESULT_NULL_POINTER; } - bool success = SetWindowPos( + PalBool success = SetWindowPos( (HWND)window, HWND_TOP, 0, @@ -2849,7 +2849,7 @@ void PAL_CALL palDestroyCursor(PalCursor* cursor) } } -void PAL_CALL palShowCursor(bool show) +void PAL_CALL palShowCursor(PalBool show) { if (s_Video.initialized) { ShowCursor(show); @@ -2858,7 +2858,7 @@ void PAL_CALL palShowCursor(bool show) PalResult PAL_CALL palClipCursor( PalWindow* window, - bool clip) + PalBool clip) { if (!s_Video.initialized) { return PAL_RESULT_VIDEO_NOT_INITIALIZED; diff --git a/tests/core/logger_test.c b/tests/core/logger_test.c index f022cce0..debef306 100644 --- a/tests/core/logger_test.c +++ b/tests/core/logger_test.c @@ -25,7 +25,7 @@ static void PAL_CALL onLogger( palLog(nullptr, "%s: %s", name, msg); } -bool loggerTest() +PalBool loggerTest() { PalLogger loggers[LOGGER_COUNT]; for (int32_t i = 0; i < LOGGER_COUNT; i++) { diff --git a/tests/core/time_test.c b/tests/core/time_test.c index 65b87009..c454eaa4 100644 --- a/tests/core/time_test.c +++ b/tests/core/time_test.c @@ -14,7 +14,7 @@ static inline double getTime(MyTimer* timer) return (double)(now - timer->startTime) / (double)timer->frequency; } -bool timeTest() +PalBool timeTest() { // create and set the frequency and start time for time related calculations MyTimer timer; diff --git a/tests/event/event_test.c b/tests/event/event_test.c index 5115f37b..8425fd6e 100644 --- a/tests/event/event_test.c +++ b/tests/event/event_test.c @@ -28,7 +28,7 @@ static void PAL_CALL onEvent( s_CallbackCounter++; } -static inline void eventDispatchTest(bool poll) +static inline void eventDispatchTest(PalBool poll) { PalResult result; PalEventDriver* driver = nullptr; @@ -76,7 +76,7 @@ static inline void eventDispatchTest(bool poll) palDestroyEventDriver(driver); } -bool eventTest() +PalBool eventTest() { MyTimer timer; timer.frequency = palGetPerformanceFrequency(); diff --git a/tests/event/user_event_test.c b/tests/event/user_event_test.c index 51c2c712..a15fb7e7 100644 --- a/tests/event/user_event_test.c +++ b/tests/event/user_event_test.c @@ -18,12 +18,12 @@ static inline double getTime(MyTimer* timer) return (double)(now - timer->startTime) / (double)timer->frequency; } -bool userEventTest() +PalBool userEventTest() { PalResult result; PalEventDriver* eventDriver = nullptr; PalEventDriverCreateInfo createInfo; - bool running, logged = false; + PalBool running, logged = false; // fill the event driver create info createInfo.allocator = nullptr; // default allocator diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index 33c0afb4..ef2d6d23 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -17,7 +17,7 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -bool clearColorTest() +PalBool clearColorTest() { PalResult result; PalWindow* window = nullptr; @@ -190,7 +190,7 @@ bool clearColorTest() } // create a graphics command queue and check if its supports presenting to the surface - bool foundQueue = false; + PalBool foundQueue = false; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { @@ -349,7 +349,7 @@ bool clearColorTest() // main loop uint32_t currentFrame = 0; - bool running = true; + PalBool running = true; while (running) { // update the video system to push video events palUpdateVideo(); diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 5acafda0..3c6901af 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -21,7 +21,7 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -bool computeTest() +PalBool computeTest() { PalAdapter* adapter = nullptr; PalDevice* device = nullptr; @@ -472,7 +472,7 @@ bool computeTest() uint32_t workGroupInfoCount = 0; PalWorkGroupInfo* workGroupInfos = nullptr; - bool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); + PalBool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); if (!ret) { palLog(nullptr, "Failed to build work group info"); return false; diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index efa7521d..69285b4e 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -49,7 +49,7 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -bool descriptorIndexingTest() +PalBool descriptorIndexingTest() { PalResult result; PalWindow* window = nullptr; @@ -280,7 +280,7 @@ bool descriptorIndexingTest() } // create a graphics command queue and check if its supports presenting to the surface - bool foundQueue = false; + PalBool foundQueue = false; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { @@ -1004,7 +1004,7 @@ bool descriptorIndexingTest() } // check if null descriptors was enabled and partially bound was not supported - bool hasPartiallyBound = adapterFeatures & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; + PalBool hasPartiallyBound = adapterFeatures & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; if (adapterFeatures & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS && !hasPartiallyBound) { // write null descriptors into the slots PalDescriptorSetWriteInfo writeInfo = {0}; @@ -1203,7 +1203,7 @@ bool descriptorIndexingTest() // main loop uint32_t currentFrame = 0; - bool running = true; + PalBool running = true; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index 8e2f3532..e173914f 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -17,7 +17,7 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -bool geometryTest() +PalBool geometryTest() { PalResult result; PalWindow* window = nullptr; @@ -225,7 +225,7 @@ bool geometryTest() } // create a graphics command queue and check if its supports presenting to the surface - bool foundQueue = false; + PalBool foundQueue = false; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { @@ -500,7 +500,7 @@ bool geometryTest() // main loop uint32_t currentFrame = 0; - bool running = true; + PalBool running = true; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 7e33ad7e..0776b1ec 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -2,7 +2,7 @@ #include "pal/pal_graphics.h" #include "tests.h" -bool graphicsTest() +PalBool graphicsTest() { // initialize the graphics system PalResult result = palInitGraphics(nullptr, nullptr); diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index f18ecaac..c3710c3f 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -24,7 +24,7 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -bool indirectDrawTest() +PalBool indirectDrawTest() { PalResult result; PalWindow* window = nullptr; @@ -242,7 +242,7 @@ bool indirectDrawTest() } // create a graphics command queue and check if its supports presenting to the surface - bool foundQueue = false; + PalBool foundQueue = false; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { @@ -896,7 +896,7 @@ bool indirectDrawTest() // main loop uint32_t currentFrame = 0; - bool running = true; + PalBool running = true; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 27613231..e730c1ae 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -17,7 +17,7 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -bool meshTest() +PalBool meshTest() { PalResult result; PalWindow* window = nullptr; @@ -225,7 +225,7 @@ bool meshTest() } // create a graphics command queue and check if its supports presenting to the surface - bool foundQueue = false; + PalBool foundQueue = false; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { @@ -495,7 +495,7 @@ bool meshTest() // main loop uint32_t currentFrame = 0; - bool running = true; + PalBool running = true; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index e9092f20..b248b7a1 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -23,7 +23,7 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -bool multiDescriptorSetTest() +PalBool multiDescriptorSetTest() { PalAdapter* adapter = nullptr; PalDevice* device = nullptr; @@ -529,7 +529,7 @@ bool multiDescriptorSetTest() uint32_t workGroupInfoCount = 0; PalWorkGroupInfo* workGroupInfos = nullptr; - bool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); + PalBool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); if (!ret) { palLog(nullptr, "Failed to build work group info"); return false; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 5407254f..d08f7337 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -24,7 +24,7 @@ static inline uint32_t _max( return (a > b) ? a : b; } -bool rayTracingTest() +PalBool rayTracingTest() { PalAdapter* adapter = nullptr; PalDevice* device = nullptr; diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index a98be67f..a5cfb4ca 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -47,7 +47,7 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -bool textureTest() +PalBool textureTest() { PalResult result; PalWindow* window = nullptr; @@ -257,7 +257,7 @@ bool textureTest() } // create a graphics command queue and check if its supports presenting to the surface - bool foundQueue = false; + PalBool foundQueue = false; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { @@ -1086,7 +1086,7 @@ bool textureTest() // main loop uint32_t currentFrame = 0; - bool running = true; + PalBool running = true; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 56f053a4..25efffda 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -17,7 +17,7 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -bool triangleTest() +PalBool triangleTest() { PalResult result; PalWindow* window = nullptr; @@ -223,7 +223,7 @@ bool triangleTest() } // create a graphics command queue and check if its supports presenting to the surface - bool foundQueue = false; + PalBool foundQueue = false; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { @@ -689,7 +689,7 @@ bool triangleTest() // main loop uint32_t currentFrame = 0; - bool running = true; + PalBool running = true; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; diff --git a/tests/opengl/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c index 0c7db0d3..6f2885e2 100644 --- a/tests/opengl/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -34,9 +34,9 @@ typedef void (*glViewportFn)( int); typedef struct { - bool driverCreated; - bool running; - bool fixedPipeline; + PalBool driverCreated; + PalBool running; + PalBool fixedPipeline; PalEventDriver* videoEventDriver; PalEventDriver* openglEventDriver; PalGLContext* context; @@ -173,7 +173,7 @@ static void* PAL_CALL rendererWorkder(void* arg) return nullptr; } -bool multiThreadOpenGlTest() +PalBool multiThreadOpenGlTest() { palLog(nullptr, "Press Escape or click close button to close Test"); PalResult result; diff --git a/tests/opengl/opengl_context_test.c b/tests/opengl/opengl_context_test.c index 7f9d5dc6..585b0e13 100644 --- a/tests/opengl/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -14,7 +14,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARCOLORPROC)( typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(uint32_t mask); // use GL typedefs if needed -bool openglContextTest() +PalBool openglContextTest() { palLog(nullptr, "Press Escape or click close button to close Test"); PalResult result; @@ -62,7 +62,7 @@ bool openglContextTest() PalWindowCreateInfo createInfo = {0}; PalGLContextCreateInfo contextCreateInfo = {0}; int32_t fbCount = 0; - bool running = false; + PalBool running = false; // enumerate supported opengl framebuffer configs // glWindow must be nullptr diff --git a/tests/opengl/opengl_fbconfig_test.c b/tests/opengl/opengl_fbconfig_test.c index a00baa96..27f4b0eb 100644 --- a/tests/opengl/opengl_fbconfig_test.c +++ b/tests/opengl/opengl_fbconfig_test.c @@ -5,7 +5,7 @@ static const char* g_BoolsToSting[2] = {"False", "True"}; -bool openglFBConfigTest() +PalBool openglFBConfigTest() { // initialize the video system and create a window PalResult result = palInitVideo(nullptr, nullptr); diff --git a/tests/opengl/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c index 9d3d7c18..fa244f24 100644 --- a/tests/opengl/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -14,7 +14,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARCOLORPROC)( typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(uint32_t mask); // use GL typedefs if needed -bool openglMultiContextTest() +PalBool openglMultiContextTest() { palLog(nullptr, "Press Escape or click close button to close Test"); PalResult result; @@ -62,7 +62,7 @@ bool openglMultiContextTest() PalWindowCreateInfo createInfo = {0}; PalGLContextCreateInfo contextCreateInfo = {0}; int32_t fbCount = 0; - bool running = false; + PalBool running = false; // enumerate supported opengl framebuffer configs // glWindow must be nullptr diff --git a/tests/opengl/opengl_test.c b/tests/opengl/opengl_test.c index d0e70e14..fc3a5755 100644 --- a/tests/opengl/opengl_test.c +++ b/tests/opengl/opengl_test.c @@ -3,7 +3,7 @@ #include "pal/pal_video.h" #include "tests.h" -bool openglTest() +PalBool openglTest() { // initialize the video system and create a window PalResult result = palInitVideo(nullptr, nullptr); diff --git a/tests/system/system_test.c b/tests/system/system_test.c index 6f3c77e1..38a73e86 100644 --- a/tests/system/system_test.c +++ b/tests/system/system_test.c @@ -61,7 +61,7 @@ static inline const char* cpuArchToString(PalCpuArch arch) return nullptr; } -bool systemTest() +PalBool systemTest() { PalResult result; PalCPUInfo cpuInfo; diff --git a/tests/tests.c b/tests/tests.c index 547c6c93..6b4bdc25 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -21,7 +21,7 @@ void registerTest(TestFn func, const char* name) void runTests() { - bool status = false; + PalBool status = false; const char* statusString = nullptr; for (int32_t i = 0; i < s_Count; i++) { palLog(nullptr, ""); diff --git a/tests/tests.h b/tests/tests.h index fa8d3e3c..0bcd7f29 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -5,12 +5,12 @@ #include "pal/pal_core.h" #include -typedef bool (*TestFn)(); +typedef PalBool (*TestFn)(); void registerTest(TestFn func, const char* name); void runTests(); -static bool readFile( +static PalBool readFile( const char* filename, void* buffer, uint64_t* size) @@ -38,59 +38,59 @@ static bool readFile( } // core tests -bool loggerTest(); -bool timeTest(); -bool userEventTest(); -bool eventTest(); +PalBool loggerTest(); +PalBool timeTest(); +PalBool userEventTest(); +PalBool eventTest(); // system tests -bool systemTest(); +PalBool systemTest(); // system tests -bool threadTest(); -bool tlsTest(); -bool mutexTest(); -bool condvarTest(); +PalBool threadTest(); +PalBool tlsTest(); +PalBool mutexTest(); +PalBool condvarTest(); // video test -bool videoTest(); -bool monitorTest(); -bool monitorModeTest(); -bool windowTest(); -bool iconTest(); -bool cursorTest(); -bool inputWindowTest(); -bool systemCursorTest(); -bool attachWindowTest(); -bool charEventTest(); -bool nativeIntegrationTest(); -bool nativeInstanceTest(); -bool customDecorationTest(); +PalBool videoTest(); +PalBool monitorTest(); +PalBool monitorModeTest(); +PalBool windowTest(); +PalBool iconTest(); +PalBool cursorTest(); +PalBool inputWindowTest(); +PalBool systemCursorTest(); +PalBool attachWindowTest(); +PalBool charEventTest(); +PalBool nativeIntegrationTest(); +PalBool nativeInstanceTest(); +PalBool customDecorationTest(); // opengl test -bool openglTest(); +PalBool openglTest(); // opengl and video test -bool openglFBConfigTest(); -bool openglContextTest(); -bool openglMultiContextTest(); +PalBool openglFBConfigTest(); +PalBool openglContextTest(); +PalBool openglMultiContextTest(); // opengl, video and thread -bool multiThreadOpenGlTest(); +PalBool multiThreadOpenGlTest(); // graphics -bool graphicsTest(); -bool computeTest(); -bool rayTracingTest(); -bool multiDescriptorSetTest(); +PalBool graphicsTest(); +PalBool computeTest(); +PalBool rayTracingTest(); +PalBool multiDescriptorSetTest(); // graphics and video -bool clearColorTest(); -bool triangleTest(); -bool meshTest(); -bool textureTest(); -bool geometryTest(); -bool indirectDrawTest(); -bool descriptorIndexingTest(); +PalBool clearColorTest(); +PalBool triangleTest(); +PalBool meshTest(); +PalBool textureTest(); +PalBool geometryTest(); +PalBool indirectDrawTest(); +PalBool descriptorIndexingTest(); #endif // _TESTS_H diff --git a/tests/thread/condvar_test.c b/tests/thread/condvar_test.c index adef63b3..b0c47d85 100644 --- a/tests/thread/condvar_test.c +++ b/tests/thread/condvar_test.c @@ -9,7 +9,7 @@ static PalMutex* g_Mutex; static PalCondVar* g_Condition; typedef struct { - bool ready; + PalBool ready; uint32_t id; } ThreadData; @@ -28,7 +28,7 @@ static void* PAL_CALL worker(void* arg) return nullptr; } -bool condvarTest() +PalBool condvarTest() { PalResult result; PalThread* threads[THREAD_COUNT]; diff --git a/tests/thread/mutex_test.c b/tests/thread/mutex_test.c index 7ba7a2bb..959f9eec 100644 --- a/tests/thread/mutex_test.c +++ b/tests/thread/mutex_test.c @@ -25,7 +25,7 @@ static void* PAL_CALL worker(void* arg) return nullptr; } -bool mutexTest() +PalBool mutexTest() { PalResult result; PalThread* threads[THREAD_COUNT]; diff --git a/tests/thread/thread_test.c b/tests/thread/thread_test.c index 6b9f6415..ccf0eb0b 100644 --- a/tests/thread/thread_test.c +++ b/tests/thread/thread_test.c @@ -16,7 +16,7 @@ static void* PAL_CALL worker(void* arg) return nullptr; } -bool threadTest() +PalBool threadTest() { PalResult result; PalThread* threads[THREAD_COUNT]; diff --git a/tests/thread/tls_test.c b/tests/thread/tls_test.c index 51619774..2b62bb5f 100644 --- a/tests/thread/tls_test.c +++ b/tests/thread/tls_test.c @@ -49,7 +49,7 @@ static void* PAL_CALL worker(void* arg) return nullptr; } -bool tlsTest() +PalBool tlsTest() { PalThread* thread = nullptr; diff --git a/tests/video/attach_window_test.c b/tests/video/attach_window_test.c index ee55fd2d..0a586773 100644 --- a/tests/video/attach_window_test.c +++ b/tests/video/attach_window_test.c @@ -205,7 +205,7 @@ static void destroyPlatformWindow(void* windowHandle) #endif // _WIN32 } -bool attachWindowTest() +PalBool attachWindowTest() { palLog(nullptr, "Press A to attach and D to detach window"); palLog(nullptr, "Press Escape or click close button to close Test"); @@ -283,8 +283,8 @@ bool attachWindowTest() return false; } - bool running = true; - bool detached = false; + PalBool running = true; + PalBool detached = false; int32_t counter = 0; while (running) { // update the video system to push video events diff --git a/tests/video/char_event_test.c b/tests/video/char_event_test.c index 35622527..5c1d023b 100644 --- a/tests/video/char_event_test.c +++ b/tests/video/char_event_test.c @@ -2,7 +2,7 @@ #include "pal/pal_video.h" #include "tests.h" -bool charEventTest() +PalBool charEventTest() { palLog(nullptr, "Press Escape or click close button to close Test"); @@ -60,7 +60,7 @@ bool charEventTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYCHAR, PAL_DISPATCH_POLL); - bool running = true; + PalBool running = true; while (running) { // update the video system to push video events palUpdateVideo(); diff --git a/tests/video/cursor_test.c b/tests/video/cursor_test.c index bdaac0b3..cce0f4e3 100644 --- a/tests/video/cursor_test.c +++ b/tests/video/cursor_test.c @@ -2,7 +2,7 @@ #include "pal/pal_video.h" #include "tests.h" -bool cursorTest() +PalBool cursorTest() { palLog(nullptr, "Press Escape or click close button to close Test"); @@ -11,7 +11,7 @@ bool cursorTest() PalCursor* cursor = nullptr; PalWindowCreateInfo createInfo = {0}; PalCursorCreateInfo cursorCreateInfo = {0}; - bool running = false; + PalBool running = false; // event driver PalEventDriver* eventDriver = nullptr; diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index d22f9910..0fb41381 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -803,7 +803,7 @@ static void PAL_CALL onEvent( xdgToplevelMove(s_WinHandle.nativeHandle2, s_Seat, serial); // Optionally check for another click and maximize the window - // maybe set a bool or query mouse button state + // maybe set a PalBool or query mouse button state // we will skip it for this example } @@ -833,7 +833,7 @@ static void PAL_CALL onEvent( } } -bool customDecorationTest() +PalBool customDecorationTest() { palLog(nullptr, "Press Escape or click close button to close Test"); palLog(nullptr, "This only implements close and window movement for simplicity"); @@ -903,7 +903,7 @@ bool customDecorationTest() s_Decoration.driver = eventDriver; createDecoration(); - bool running = true; + PalBool running = true; while (running) { // update the video system to push video events palUpdateVideo(); @@ -957,7 +957,7 @@ bool customDecorationTest() #else #include "tests.h" -bool customDecorationTest() +PalBool customDecorationTest() { return false; } diff --git a/tests/video/icon_test.c b/tests/video/icon_test.c index 93ac094d..45a1eb50 100644 --- a/tests/video/icon_test.c +++ b/tests/video/icon_test.c @@ -2,7 +2,7 @@ #include "pal/pal_video.h" #include "tests.h" -bool iconTest() +PalBool iconTest() { palLog(nullptr, "Press Escape or click close button to close Test"); @@ -11,7 +11,7 @@ bool iconTest() PalIcon* icon = nullptr; PalWindowCreateInfo createInfo = {0}; PalIconCreateInfo iconCreateInfo = {0}; - bool running = false; + PalBool running = false; // event driver PalEventDriver* eventDriver = nullptr; diff --git a/tests/video/input_window_test.c b/tests/video/input_window_test.c index d84c171a..56862714 100644 --- a/tests/video/input_window_test.c +++ b/tests/video/input_window_test.c @@ -272,7 +272,7 @@ static const char* dispatchString = "Poll Mode"; static const char* dispatchString = "Callback Mode"; #endif // DISPATCH_MODE_POLL -static bool s_Running = false; +static PalBool s_Running = false; // inline helpers static inline void onKeydown(const PalEvent* event) @@ -397,14 +397,14 @@ static void PAL_CALL onEvent( } } -bool inputWindowTest() +PalBool inputWindowTest() { palLog(nullptr, "Press Escape or click close button to close Test"); PalResult result; PalWindow* window = nullptr; PalWindowCreateInfo createInfo = {0}; - bool running = false; + PalBool running = false; // event driver PalEventDriver* eventDriver = nullptr; diff --git a/tests/video/monitor_mode_test.c b/tests/video/monitor_mode_test.c index b853f5b2..872e85da 100644 --- a/tests/video/monitor_mode_test.c +++ b/tests/video/monitor_mode_test.c @@ -2,7 +2,7 @@ #include "pal/pal_video.h" #include "tests.h" -bool monitorModeTest() +PalBool monitorModeTest() { PalMonitorInfo info; int32_t count = 0; diff --git a/tests/video/monitor_test.c b/tests/video/monitor_test.c index 8542f311..55e00e8e 100644 --- a/tests/video/monitor_test.c +++ b/tests/video/monitor_test.c @@ -2,7 +2,7 @@ #include "pal/pal_video.h" #include "tests.h" -bool monitorTest() +PalBool monitorTest() { PalMonitorInfo info; int32_t count = 0; diff --git a/tests/video/native_instance_test.c b/tests/video/native_instance_test.c index fab13b5e..e188289a 100644 --- a/tests/video/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -132,7 +132,7 @@ static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_dis return (struct wl_registry*)registry; } -static bool s_Logged = false; +static PalBool s_Logged = false; static void globalHandle( void* data, struct wl_registry* registry, @@ -161,7 +161,7 @@ static const struct wl_registry_listener s_RegistryListener = { .global = globalHandle, .global_remove = globalRemove}; -static bool s_OnWayland = false; +static PalBool s_OnWayland = false; #endif // _WIN32 @@ -306,7 +306,7 @@ void closeInstance(void* instance) #endif // _WIN32 } -bool nativeInstanceTest() +PalBool nativeInstanceTest() { palLog(nullptr, "Press Escape or click close button to close Test"); @@ -374,7 +374,7 @@ bool nativeInstanceTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - bool running = true; + PalBool running = true; while (running) { // update the video system to push video events palUpdateVideo(); diff --git a/tests/video/native_integration_test.c b/tests/video/native_integration_test.c index a62b58fd..67c10649 100644 --- a/tests/video/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -112,7 +112,7 @@ static XFreeFn s_XFree; static Atom s_NET_WM_NAME; static Atom s_UTF8_STRING; -static bool s_OnWayland = false; +static PalBool s_OnWayland = false; static void* s_X11Lib; static void* s_WaylandLib; @@ -312,7 +312,7 @@ void getWindowTitle(PalWindowHandleInfoEx* windowInfo) #endif // _WIN32 } -bool nativeIntegrationTest() +PalBool nativeIntegrationTest() { palLog(nullptr, "Press Escape or click close button to close Test"); @@ -391,7 +391,7 @@ bool nativeIntegrationTest() // using native API like wl_proxy_set_user_data, XContext and // SetWindowLongPtr(GWLP_USERDATA) can be used freely - bool running = true; + PalBool running = true; while (running) { // update the video system to push video events palUpdateVideo(); diff --git a/tests/video/system_cursor_test.c b/tests/video/system_cursor_test.c index a492cbe8..089eef65 100644 --- a/tests/video/system_cursor_test.c +++ b/tests/video/system_cursor_test.c @@ -2,7 +2,7 @@ #include "pal/pal_video.h" #include "tests.h" -bool systemCursorTest() +PalBool systemCursorTest() { palLog(nullptr, "Press Escape or click close button to close Test"); @@ -10,7 +10,7 @@ bool systemCursorTest() PalWindow* window = nullptr; PalCursor* cursor = nullptr; PalWindowCreateInfo createInfo = {0}; - bool running = false; + PalBool running = false; // event driver PalEventDriver* eventDriver = nullptr; diff --git a/tests/video/video_test.c b/tests/video/video_test.c index 916da27f..62c56101 100644 --- a/tests/video/video_test.c +++ b/tests/video/video_test.c @@ -2,7 +2,7 @@ #include "pal/pal_video.h" #include "tests.h" -bool videoTest() +PalBool videoTest() { palLog(nullptr, "Press Escape or click close button to close Test"); diff --git a/tests/video/window_test.c b/tests/video/window_test.c index 8d350330..5611737e 100644 --- a/tests/video/window_test.c +++ b/tests/video/window_test.c @@ -142,14 +142,14 @@ static void PAL_CALL onEvent( } } -bool windowTest() +PalBool windowTest() { palLog(nullptr, "Press Escape or click close button to close Test"); PalResult result; PalWindow* window = nullptr; PalWindowCreateInfo createInfo = {0}; - bool running = false; + PalBool running = false; // event driver PalEventDriver* eventDriver = nullptr; From 93f755eb64e04d4e80cd34b32c713782f9eaf202 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 14 Jun 2026 20:01:00 +0000 Subject: [PATCH 259/372] test re write of core system linux --- CHANGELOG.md | 1 + include/pal/pal_core.h | 52 ++++- include/pal/pal_event.h | 3 +- pal.lua | 24 ++- pal_config.lua | 2 +- src/core/linux/pal_log_linux.c | 89 ++++++++ src/core/linux/pal_memory_linux.c | 48 +++++ src/core/linux/pal_result_linux.c | 30 +++ src/core/linux/pal_time_linux.c | 25 +++ src/core/pal_format.h | 42 ++++ src/core/pal_log.c | 193 ------------------ src/core/pal_memory.c | 69 ------- src/core/pal_result.c | 187 ----------------- src/core/pal_result_common.h | 110 ++++++++++ src/core/pal_version.c | 2 +- src/core/win32/pal_log_win32.c | 114 +++++++++++ src/core/win32/pal_memory_win32.c | 48 +++++ src/core/win32/pal_result_win32.c | 45 ++++ .../{pal_time.c => win32/pal_time_win32.c} | 22 +- tests/core/logger_test.c | 2 +- tests/core/time_test.c | 2 +- tests/tests.c | 2 +- tests/tests.h | 6 +- tests/tests.lua | 4 +- tests/tests_main.c | 12 +- 25 files changed, 634 insertions(+), 500 deletions(-) create mode 100644 src/core/linux/pal_log_linux.c create mode 100644 src/core/linux/pal_memory_linux.c create mode 100644 src/core/linux/pal_result_linux.c create mode 100644 src/core/linux/pal_time_linux.c create mode 100644 src/core/pal_format.h delete mode 100644 src/core/pal_log.c delete mode 100644 src/core/pal_memory.c delete mode 100644 src/core/pal_result.c create mode 100644 src/core/pal_result_common.h create mode 100644 src/core/win32/pal_log_win32.c create mode 100644 src/core/win32/pal_memory_win32.c create mode 100644 src/core/win32/pal_result_win32.c rename src/core/{pal_time.c => win32/pal_time_win32.c} (65%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 759857ff..4cbd1bd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -145,6 +145,7 @@ palJoinThread(thread, &retval); - **Core:** Rename **Uint32** to **uint32_t**. - **Core:** Rename **Uint64** to **uint64_t**. - **Core:** Rename **UintPtr** to **uintptr_t**. +- **Core:** **palFormatResult()** now takes two additional parameters. - **Thread:** **palJoinThread()** now takes a void** for retval parameter. diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 8b94a1dc..c051852a 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -14,6 +14,7 @@ #define _PAL_CORE_H #include +#include #ifdef __cplusplus #define PAL_EXTERN_C extern "C" @@ -71,7 +72,7 @@ /** * @typedef PalBool - * @brief Must be @c PAL_TRUE or @c PAL_FALSE. + * @brief Must be `PAL_TRUE` or `PAL_FALSE`. * * @since 2.0 */ @@ -79,7 +80,17 @@ typedef uint32_t PalBool; /** * @typedef PalResult - * @brief Codes returned by most PAL functions. This is not a bitmask. + * @brief Value returned by most PAL functions. + * + * Non-success results (eg. `PAL_RESULT_INVALID_HANDLE`) may contain + * additional information for debugging and logging purposes. For checking specific + * result codes, call `palGetResultCode()` to get the code from the result value. + * + * Example: + * + * uint16_t resultCode = palGetResultCode(result); + * + * if (resultCode == `PAL_RESULT_INVALID_DEVICE_LOST`) {}. * * All result codes follow the format `PAL_RESULT_**` for consistency and API use. * @@ -174,17 +185,38 @@ typedef struct { } PalLogger; /** - * Convert a result code to a human-readable string. - * - * @param result The PalResult code to format. + * Get the result code from the result value. + * + * `PAL_RESULT_SUCCESS` code can be compared with the result value without comparing the + * result code. + * + * @param result The result value. * - * @return Null-terminated static string describing the result. + * @return The result code from the result value. * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 + */ +PAL_API uint16_t PAL_CALL palGetResultCode(PalResult result); + +/** + * Convert a result value to a human-readable string. + * + * This returns a null-terminated string. The string is truncated if `bufferSize` is insufficient. + * + * @param result The PalResult value to format. + * @param bufferSize The size of the buffer. + * @param buffer The buffer. + * + * Thread safety: Thread safe if the provided buffer is per thread. + * + * @since 2.0 */ -PAL_API const char* PAL_CALL palFormatResult(PalResult result); +PAL_API void PAL_CALL palFormatResult( + PalResult result, + uint64_t bufferSize, + char* buffer); /** * Retrieve the PAL version number. @@ -399,7 +431,7 @@ static inline void PAL_CALL palUnpackUint32( * @param[out] outLow Low value of the 64-bit signed integer. * @param[out] outHigh High value of the 64-bit signed integer. * - * Thread safety: Thread-safe if `outLow` and `outHigh` are + * Thread safety: Thread-safe if @c outLow and @c outHigh are * thread local. * * @since 1.0 @@ -440,7 +472,7 @@ static inline void* PAL_CALL palUnpackPointer(int64_t data) * @param[out] outLow Low value of the 64-bit signed integer. * @param[out] outHigh High value of the 64-bit signed integer. * - * Thread safety: Thread-safe if `outLow` and `outHigh` are + * Thread safety: Thread-safe if @c outLow and @c outHigh are * thread local. * * @since 1.3 diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 001607dc..92976113 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -14,8 +14,7 @@ #ifndef _PAL_EVENT_H #define _PAL_EVENT_H -#include "pal/core/memory.h" -#include "pal/core/result.h" +#include "pal/pal_core.h" /** * @struct PalEventDriver diff --git a/pal.lua b/pal.lua index 7e2e268b..d5826fe1 100644 --- a/pal.lua +++ b/pal.lua @@ -24,16 +24,30 @@ project "PAL" files { -- core - "src/core/pal_log.c", - "src/core/pal_memory.c", - "src/core/pal_result.c", - "src/core/pal_time.c", "src/core/pal_version.c", -- event - "src/pal_event.c" + -- "src/pal_event.c" } + filter {"system:windows", "configurations:*"} + files { + "src/core/win32/pal_log_win32.c", + "src/core/win32/pal_memory_win32.c", + "src/core/win32/pal_result_win32.c", + "src/core/win32/pal_time_win32.c" + } + + filter {"system:linux", "configurations:*"} + files { + "src/core/linux/pal_log_linux.c", + "src/core/linux/pal_memory_linux.c", + "src/core/linux/pal_result_linux.c", + "src/core/linux/pal_time_linux.c" + } + + filter {} + if (PAL_BUILD_SYSTEM_MODULE) then filter {"system:windows", "configurations:*"} files { "src/system/pal_system_win32.c" } diff --git a/pal_config.lua b/pal_config.lua index a68efa61..04037df9 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -3,7 +3,7 @@ PAL_BUILD_STATIC_LIBRARY = false -- build PAL tests as a single application -PAL_BUILD_TEST_APPLICATION = false +PAL_BUILD_TEST_APPLICATION = true -- build system module PAL_BUILD_SYSTEM_MODULE = false diff --git a/src/core/linux/pal_log_linux.c b/src/core/linux/pal_log_linux.c new file mode 100644 index 00000000..77a9b097 --- /dev/null +++ b/src/core/linux/pal_log_linux.c @@ -0,0 +1,89 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#include "core/pal_format.h" +#include +#include + +#define MSG_SIZE 4096 + +typedef struct { + char tmp[MSG_SIZE]; + char buffer[MSG_SIZE]; + PalBool isLogging; +} LogTLSData; + +pthread_key_t s_TLSID = 0; +static pthread_once_t s_TLSCreation = PTHREAD_ONCE_INIT; + +static void destroyTlsData(void* data) +{ + LogTLSData* tlsData = data; + if (tlsData) { + palFree(nullptr, tlsData); + } +} + +void createTLSID() +{ + if (pthread_key_create(&s_TLSID, destroyTlsData) != 0) { + return; + } +} + +void PAL_CALL palLog( + const PalLogger* logger, + const char* fmt, + ...) +{ + if (!fmt) { + return; + } + + LogTLSData* data = pthread_getspecific(s_TLSID); + if (!data) { + data = palAllocate(nullptr, sizeof(LogTLSData), 0); + memset(data, 0, sizeof(LogTLSData)); + + // create TLS if it has not been created + pthread_once(&s_TLSCreation, createTLSID); + pthread_setspecific(s_TLSID, data); + } + + va_list argPtr; + va_start(argPtr, fmt); + formatArgs(fmt, argPtr, data->tmp); + va_end(argPtr); + + // check to see if a user supplied a logger + if (logger && logger->callback) { + if (data->isLogging) { + // block recursion + return; + } + + // update the tls to stop recursive calls + memcpy(data->buffer, data->tmp, MSG_SIZE); + data->isLogging = PAL_TRUE; + pthread_setspecific(s_TLSID, data); + logger->callback(logger->userData, data->buffer); + + } else { + // add newline character to the string + format(data->buffer, "%s\n", data->tmp); + + // write to console + fprintf(stdout, "%s", data->buffer); + fflush(stdout); + } + + data->isLogging = PAL_FALSE; + pthread_setspecific(s_TLSID, data); +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/core/linux/pal_memory_linux.c b/src/core/linux/pal_memory_linux.c new file mode 100644 index 00000000..75ad4d26 --- /dev/null +++ b/src/core/linux/pal_memory_linux.c @@ -0,0 +1,48 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#define _POSIX_C_SOURCE 200112L +#include "pal/pal_core.h" +#include + +void* PAL_CALL palAllocate( + const PalAllocator* allocator, + uint64_t size, + uint64_t alignment) +{ + if (size == 0) { + return nullptr; + } + + uint64_t align = alignment; + if (align == 0) { + align = 16; // default + } + + if (allocator && allocator->allocate) { + return allocator->allocate(allocator->userData, size, align); + } + + void* ptr = nullptr; + posix_memalign(&ptr, align, size); + return ptr; +} + +void PAL_CALL palFree( + const PalAllocator* allocator, + void* ptr) +{ + if (allocator && allocator->free && ptr) { + allocator->free(allocator->userData, ptr); + + } else { + free(ptr); + } +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/core/linux/pal_result_linux.c b/src/core/linux/pal_result_linux.c new file mode 100644 index 00000000..fc388126 --- /dev/null +++ b/src/core/linux/pal_result_linux.c @@ -0,0 +1,30 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#define _POSIX_C_SOURCE 200112L +#include "pal/pal_core.h" +#include "core/pal_result_common.h" +#include + +uint16_t PAL_CALL palGetResultCode(PalResult result) +{ + getResultCode(result); +} + +void PAL_CALL palFormatResult( + PalResult result, + uint64_t bufferSize, + char* buffer) +{ + const char* baseString = resultCodeToString(result); + const char* sourceString = resultSourceToString(result); + uint32_t nativeCode = getResultNativeCode(result); + strerror_r(nativeCode, buffer, bufferSize); +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/core/linux/pal_time_linux.c b/src/core/linux/pal_time_linux.c new file mode 100644 index 00000000..a241e9eb --- /dev/null +++ b/src/core/linux/pal_time_linux.c @@ -0,0 +1,25 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#define _POSIX_C_SOURCE 200112L +#include "pal/pal_core.h" +#include + +uint64_t PAL_CALL palGetPerformanceCounter() +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000000LL + (uint64_t)ts.tv_nsec; +} + +uint64_t PAL_CALL palGetPerformanceFrequency() +{ + return 1000000000LL; +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/core/pal_format.h b/src/core/pal_format.h new file mode 100644 index 00000000..de11eb59 --- /dev/null +++ b/src/core/pal_format.h @@ -0,0 +1,42 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_FORMAT_H +#define _PAL_FORMAT_H + +#include "pal/pal_core.h" +#include +#include + +static inline void formatArgs( + const char* fmt, + va_list argsList, + char* buffer) +{ + va_list argsListCopy; + va_copy(argsListCopy, argsList); + int len = vsnprintf(nullptr, 0, fmt, argsListCopy); + va_end(argsListCopy); + + va_copy(argsListCopy, argsList); + vsnprintf(buffer, len + 1, fmt, argsListCopy); + va_end(argsListCopy); + buffer[len] = 0; +} + +static inline void format( + char* buffer, + const char* fmt, + ...) +{ + va_list argPtr; + va_start(argPtr, fmt); + formatArgs(fmt, argPtr, buffer); + va_end(argPtr); +} + +#endif // _PAL_FORMAT_H \ No newline at end of file diff --git a/src/core/pal_log.c b/src/core/pal_log.c deleted file mode 100644 index 7618f778..00000000 --- a/src/core/pal_log.c +++ /dev/null @@ -1,193 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#include "pal/core/log.h" -#include -#include -#include -#include - -#ifdef _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN - -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -// set unicode -#ifndef UNICODE -#define UNICODE -#endif // UNICODE -#include - -static volatile LONG s_TlsID = 0; - -#else -#include - -pthread_key_t s_TLSID = 0; -static pthread_once_t s_TLSCreation = PTHREAD_ONCE_INIT; - -static void destroyTlsData(void* data); -void createTLSID() -{ - if (pthread_key_create(&s_TLSID, destroyTlsData) != 0) { - return; - } -} - -#endif // _WIN32 - -#define PAL_LOG_MSG_SIZE 4096 - -typedef struct { - char tmp[PAL_LOG_MSG_SIZE]; - char buffer[PAL_LOG_MSG_SIZE]; - wchar_t wideBuffer[PAL_LOG_MSG_SIZE]; - PalBool isLogging; -} LogTLSData; - -static void destroyTlsData(void* data) -{ - LogTLSData* tlsData = data; - if (tlsData) { - free(tlsData); - } -} - -static inline LogTLSData* getLogTlsData() -{ -#ifdef _WIN32 - LogTLSData* data = FlsGetValue((DWORD)s_TlsID); -#else - LogTLSData* data = pthread_getspecific(s_TLSID); -#endif // _WIN32 - - if (!data) { - data = malloc(sizeof(LogTLSData)); - memset(data, 0, sizeof(LogTLSData)); - // create TLS if it has not been created -#ifdef _WIN32 - if (s_TlsID == 0) { - DWORD TLSIndex = FlsAlloc(destroyTlsData); - if (TLSIndex == TLS_OUT_OF_INDEXES) { - return nullptr; - } else { - // update the TLS using atomic operations to avoid thread race - LONG prev = InterlockedCompareExchange((volatile LONG*)&s_TlsID, (LONG)TLSIndex, 0); - if (prev != 0) { - // Another thread has already set this, - // destroy the tls index - FlsFree(TLSIndex); - } - } - } - FlsSetValue(s_TlsID, data); -#else - pthread_once(&s_TLSCreation, createTLSID); - pthread_setspecific(s_TLSID, data); -#endif // _WIN32 - } - return data; -} - -static inline void updateLogTlsData(LogTLSData* data) -{ -#ifdef _WIN32 - FlsSetValue(s_TlsID, data); -#else - pthread_setspecific(s_TLSID, data); -#endif // _WIN32 -} - -static inline void formatArgs( - const char* fmt, - va_list argsList, - char* buffer) -{ - va_list argsListCopy; - va_copy(argsListCopy, argsList); - int len = vsnprintf(nullptr, 0, fmt, argsListCopy); - va_end(argsListCopy); - - va_copy(argsListCopy, argsList); - vsnprintf(buffer, len + 1, fmt, argsListCopy); - va_end(argsListCopy); - buffer[len] = 0; -} - -static inline void format( - char* buffer, - const char* fmt, - ...) -{ - va_list argPtr; - va_start(argPtr, fmt); - formatArgs(fmt, argPtr, buffer); - va_end(argPtr); -} - -static inline void writeToConsole(LogTLSData* data) -{ -#ifdef _WIN32 - HANDLE console = GetStdHandle(STD_ERROR_HANDLE); - int len = MultiByteToWideChar(CP_UTF8, 0, data->buffer, -1, nullptr, 0); - if (!len) { - return; - } - - MultiByteToWideChar(CP_UTF8, 0, data->buffer, -1, data->wideBuffer, len); - if (console) { - WriteConsoleW(console, data->wideBuffer, (DWORD)len - 1, NULL, 0); - } else { - OutputDebugStringW(data->wideBuffer); - } -#else - fprintf(stdout, "%s", data->buffer); - fflush(stdout); -#endif // _WIN32 -} - -void PAL_CALL palLog( - const PalLogger* logger, - const char* fmt, - ...) -{ - if (!fmt) { - return; - } - - LogTLSData* data = getLogTlsData(); - va_list argPtr; - va_start(argPtr, fmt); - formatArgs(fmt, argPtr, data->tmp); - va_end(argPtr); - - // check to see if a user supplied a logger - if (logger && logger->callback) { - if (data->isLogging) { - // block recursion - return; - } - - // update the tls to stop recursive calls - memcpy(data->buffer, data->tmp, PAL_LOG_MSG_SIZE); - data->isLogging = true; - updateLogTlsData(data); - logger->callback(logger->userData, data->buffer); - - } else { - // add newline character to the string - format(data->buffer, "%s\n", data->tmp); - writeToConsole(data); - } - - data->isLogging = false; - updateLogTlsData(data); -} \ No newline at end of file diff --git a/src/core/pal_memory.c b/src/core/pal_memory.c deleted file mode 100644 index f50145e9..00000000 --- a/src/core/pal_memory.c +++ /dev/null @@ -1,69 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#if defined(_MSC_VER) || defined(__MINGW32__) -#include -#endif // _MSC_VER - -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L -#include "pal/core/memory.h" -#include - -#define PAL_DEFAULT_ALIGNMENT 16 - -static inline void* alignedAlloc( - uint64_t size, - uint64_t alignment) -{ -#if defined(_MSC_VER) || defined(__MINGW32__) - return _aligned_malloc(size, alignment); -#elif defined(_ISOC11_SOURCE) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L - return aligned_alloc(alignment, size); -#else - void* ptr = nullptr; - posix_memalign(&ptr, alignment, size); - return ptr; -#endif // _MSC_VER -} - -static inline void alignedFree(void* ptr) -{ -#if defined(_MSC_VER) || defined(__MINGW32__) - _aligned_free(ptr); -#else - free(ptr); -#endif // _MSC_VER -} - -void* PAL_CALL palAllocate( - const PalAllocator* allocator, - uint64_t size, - uint64_t alignment) -{ - uint64_t align = alignment; - if (align == 0) { - align = PAL_DEFAULT_ALIGNMENT; - } - - if (allocator && allocator->allocate && size != 0) { - return allocator->allocate(allocator->userData, size, align); - } - return alignedAlloc(size, align); -} - -void PAL_CALL palFree( - const PalAllocator* allocator, - void* ptr) -{ - if (allocator && allocator->free && ptr) { - allocator->free(allocator->userData, ptr); - - } else { - alignedFree(ptr); - } -} \ No newline at end of file diff --git a/src/core/pal_result.c b/src/core/pal_result.c deleted file mode 100644 index 5b98a4d7..00000000 --- a/src/core/pal_result.c +++ /dev/null @@ -1,187 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#include "pal/core/result.h" - -const char* PAL_CALL palFormatResult(PalResult result) -{ - switch (result) { - case PAL_RESULT_SUCCESS: - return "Success"; - - case PAL_RESULT_NULL_POINTER: - return "Null pointer"; - - case PAL_RESULT_INVALID_ARGUMENT: - return "Invalid argument"; - - case PAL_RESULT_OUT_OF_MEMORY: - return "Out of memory"; - - case PAL_RESULT_PLATFORM_FAILURE: { - return "Platform error"; - } - - case PAL_RESULT_INVALID_ALLOCATOR: - return "Invalif allocator"; - - case PAL_RESULT_ACCESS_DENIED: - return "Access denied"; - - case PAL_RESULT_TIMEOUT: - return "Timeout expired"; - - case PAL_RESULT_INSUFFICIENT_BUFFER: - return "Insufficient buffer"; - - // thread - case PAL_RESULT_INVALID_THREAD: - return "Invalid thread"; - - case PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED: - return "Unsupported thread feature"; - - // video - case PAL_RESULT_VIDEO_NOT_INITIALIZED: - return "Video system not initialized"; - - case PAL_RESULT_INVALID_MONITOR: - return "Invalid monitor"; - - case PAL_RESULT_INVALID_MONITOR_MODE: - return "Invalid monitor display mode"; - - case PAL_RESULT_INVALID_WINDOW: - return "Invalid window"; - - case PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED: - return "Unsupported video feature"; - - case PAL_RESULT_INVALID_KEYCODE: - return "Invalid keycode"; - - case PAL_RESULT_INVALID_SCANCODE: - return "Invalid scancode"; - - case PAL_RESULT_INVALID_MOUSE_BUTTON: - return "Invalid mouse button"; - - case PAL_RESULT_INVALID_ORIENTATION: - return "Invalid orientation"; - - // opengl - case PAL_RESULT_GL_NOT_INITIALIZED: - return "Opengl system not initialized"; - - case PAL_RESULT_INVALID_GL_WINDOW: - return "Invalid opengl window"; - - case PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED: - return "Unsupported opengl extension"; - - case PAL_RESULT_INVALID_GL_FBCONFIG: - return "Invalid opengl framebuffer"; - - case PAL_RESULT_INVALID_GL_VERSION: - return "Unsupported opengl version"; - - case PAL_RESULT_INVALID_GL_PROFILE: - return "Unsupported opengl profile"; - - case PAL_RESULT_INVALID_GL_CONTEXT: - return "Invalid opengl context"; - - case PAL_RESULT_INVALID_FBCONFIG_BACKEND: - return "Invalid FBConfg backend"; - - // graphics - case PAL_RESULT_GRAPHICS_NOT_INITIALIZED: - return "Graphics system not initialized"; - - case PAL_RESULT_INVALID_ADAPTER: - return "Invalid adapter"; - - case PAL_RESULT_INVALID_BACKEND: - return "Invalid backend"; - - case PAL_RESULT_QUEUE_NOT_SUPPORTED: - return "Queue not supported"; - - case PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED: - return "Unsupported adapter feature"; - - case PAL_RESULT_INVALID_DRIVER: - return "Incompatible driver"; - - case PAL_RESULT_INVALID_DEVICE: - return "Invalid device"; - - case PAL_RESULT_INVALID_QUEUE: - return "Invalid queue"; - - case PAL_RESULT_OUT_OF_QUEUE: - return "Out of queues"; - - case PAL_RESULT_INVALID_GRAPHICS_WINDOW: - return "Invalid graphics window"; - - case PAL_RESULT_INVALID_SWAPCHAIN: - return "Invalid swapchain"; - - case PAL_RESULT_INVALID_IMAGE: - return "Invalid image"; - - case PAL_RESULT_INVALID_IMAGE_VIEW: - return "Invalid image view"; - - case PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED: - return "memory type not supported"; - - case PAL_RESULT_INVALID_OPERATION: - return "Invalid operation"; - - case PAL_RESULT_INVALID_SHADER: - return "Invalid shader"; - - case PAL_RESULT_INVALID_SHADER_TYPE: - return "Invalid shader type"; - - case PAL_RESULT_INVALID_COMMAND_POOL: - return "Invalid command pool"; - - case PAL_RESULT_INVALID_COMMAND_BUFFER: - return "Invalid command buffer"; - - case PAL_RESULT_INVALID_FENCE: - return "Invalid fence"; - - case PAL_RESULT_INVALID_SEMAPHORE: - return "Invalid semaphore"; - - case PAL_RESULT_INVALID_BUFFER: - return "Invalid buffer"; - - case PAL_RESULT_INVALID_PIPELINE: - return "Invalid pipeline"; - - case PAL_RESULT_INVALID_ACCELERATION_STRUCTURE: - return "Invalid acceleration structure"; - - case PAL_RESULT_MEMORY_MAP_FAILED: - return "Memory map failed"; - - case PAL_RESULT_DEVICE_LOST: - return "Device lost"; - - case PAL_RESULT_SURFACE_LOST: - return "Surface lost"; - - case PAL_RESULT_SWAPCHAIN_OUT_OF_DATE: - return "Swapchain out of date"; - } - return "Unknown"; -} \ No newline at end of file diff --git a/src/core/pal_result_common.h b/src/core/pal_result_common.h new file mode 100644 index 00000000..88ac061a --- /dev/null +++ b/src/core/pal_result_common.h @@ -0,0 +1,110 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_RESULT_COMMON_H +#define _PAL_RESULT_COMMON_H + +#include "pal/pal_core.h" + +#define PAL_RESULT_SOURCE_WINDOWS 100 +#define PAL_RESULT_SOURCE_LINUX 101 +#define PAL_RESULT_SOURCE_MACOS 102 +#define PAL_RESULT_SOURCE_VULKAN 103 +#define PAL_RESULT_SOURCE_D3D12 104 +#define PAL_RESULT_SOURCE_METAL 105 + +static inline PalResult makeResult( + uint16_t code, + uint16_t source, + uint32_t nativeCode) +{ + return ((uint64_t)nativeCode << 32) | ((uint64_t)source << 16) | (uint64_t)code; +} + +static inline uint16_t getResultCode(PalResult result) +{ + return (uint16_t)(result & 0xFFFFU); +} + +static inline uint16_t getResultSource(PalResult result) +{ + return (uint16_t)((result >> 16) & 0xFFFFu); +} + +static inline uint32_t getResultNativeCode(PalResult result) +{ + return (uint32_t)(result >> 32); +} + +static const char* PAL_CALL resultCodeToString(PalResult result) +{ + uint16_t code = getResultCode(result); + switch (code) { + case PAL_RESULT_SUCCESS: + return "Success"; + + case PAL_RESULT_INVALID_ARGUMENT: + return "Invalid argument"; + + case PAL_RESULT_OUT_OF_MEMORY: + return "Out of memory"; + + case PAL_RESULT_PLATFORM_FAILURE: + return "Platform failure"; + + case PAL_RESULT_TIMEOUT: + return "Timeout"; + + case PAL_RESULT_INVALID_HANDLE: + return "Invalid handle"; + + case PAL_RESULT_FEATURE_NOT_SUPPORTED: + return "Feature not supported"; + + case PAL_RESULT_NOT_INITIALIZED: + return "Not initialized"; + + case PAL_RESULT_INVALID_OPERATION: + return "Invalid operation"; + + case PAL_RESULT_DEVICE_LOST: + return "Device lost"; + + case PAL_RESULT_OUT_OF_DATE: + return "Out of date"; + } + + return nullptr; +} + +static const char* PAL_CALL resultSourceToString(PalResult result) +{ + uint16_t source = getResultSource(result); + switch (source) { + case PAL_RESULT_SOURCE_WINDOWS: + return "Windows"; + + case PAL_RESULT_SOURCE_LINUX: + return "Linux"; + + case PAL_RESULT_SOURCE_MACOS: + return "MacOS"; + + case PAL_RESULT_SOURCE_VULKAN: + return "Vulkan"; + + case PAL_RESULT_SOURCE_D3D12: + return "D3D12"; + + case PAL_RESULT_SOURCE_METAL: + return "Metal"; + } + + return nullptr; +} + +#endif // _PAL_RESULT_COMMON_H \ No newline at end of file diff --git a/src/core/pal_version.c b/src/core/pal_version.c index 1c1432ec..b4057858 100644 --- a/src/core/pal_version.c +++ b/src/core/pal_version.c @@ -5,7 +5,7 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal/core/version.h" +#include "pal/pal_core.h" #define PAL_VERSION_MAJOR 2 #define PAL_VERSION_MINOR 0 diff --git a/src/core/win32/pal_log_win32.c b/src/core/win32/pal_log_win32.c new file mode 100644 index 00000000..7525d7ca --- /dev/null +++ b/src/core/win32/pal_log_win32.c @@ -0,0 +1,114 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE + +#include "core/pal_format.h" +#include +#include + +#define MSG_SIZE 4096 + +typedef struct { + char tmp[MSG_SIZE]; + char buffer[MSG_SIZE]; + wchar_t wideBuffer[MSG_SIZE]; + PalBool isLogging; +} LogTLSData; + +static volatile LONG s_TlsID = 0; + +static void destroyTlsData(void* data) +{ + LogTLSData* tlsData = data; + if (tlsData) { + palFree(nullptr, tlsData); + } +} + +void PAL_CALL palLog( + const PalLogger* logger, + const char* fmt, + ...) +{ + if (!fmt) { + return; + } + + LogTLSData* data = FlsGetValue((DWORD)s_TlsID); + if (!data) { + data = palAllocate(nullptr, sizeof(LogTLSData),0); + memset(data, 0, sizeof(LogTLSData)); + + // create TLS if it has not been created + if (s_TlsID == 0) { + DWORD TLSIndex = FlsAlloc(destroyTlsData); + // update the TLS using atomic operations to avoid thread race + LONG prev = InterlockedCompareExchange((volatile LONG*)&s_TlsID, (LONG)TLSIndex, 0); + if (prev != 0) { + // Another thread has already set this, + // destroy the tls index + FlsFree(TLSIndex); + } + } + FlsSetValue(s_TlsID, data); + } + + va_list argPtr; + va_start(argPtr, fmt); + formatArgs(fmt, argPtr, data->tmp); + va_end(argPtr); + + // check to see if a user supplied a logger + if (logger && logger->callback) { + if (data->isLogging) { + // block recursion + return; + } + + // update the tls to stop recursive calls + memcpy(data->buffer, data->tmp, PAL_LOG_MSG_SIZE); + data->isLogging = true; + FlsSetValue(s_TlsID, data); + logger->callback(logger->userData, data->buffer); + + } else { + // add newline character to the string + format(data->buffer, "%s\n", data->tmp); + + // write to console + HANDLE console = GetStdHandle(STD_ERROR_HANDLE); + int len = MultiByteToWideChar(CP_UTF8, 0, data->buffer, -1, nullptr, 0); + if (!len) { + return; + } + + MultiByteToWideChar(CP_UTF8, 0, data->buffer, -1, data->wideBuffer, len); + if (console) { + WriteConsoleW(console, data->wideBuffer, (DWORD)len - 1, NULL, 0); + } else { + OutputDebugStringW(data->wideBuffer); + } + } + + data->isLogging = false; + FlsSetValue(s_TlsID, data); +} + +#endif // _WIN32 diff --git a/src/core/win32/pal_memory_win32.c b/src/core/win32/pal_memory_win32.c new file mode 100644 index 00000000..995fc05d --- /dev/null +++ b/src/core/win32/pal_memory_win32.c @@ -0,0 +1,48 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal/pal_core.h" + +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#endif // _MSC_VER + +void* PAL_CALL palAllocate( + const PalAllocator* allocator, + uint64_t size, + uint64_t alignment) +{ + if (size == 0) { + return nullptr; + } + + uint64_t align = alignment; + if (align == 0) { + align = 16; // default + } + + if (allocator && allocator->allocate) { + return allocator->allocate(allocator->userData, size, align); + } + + return _aligned_malloc(size, alignment); +} + +void PAL_CALL palFree( + const PalAllocator* allocator, + void* ptr) +{ + if (allocator && allocator->free && ptr) { + allocator->free(allocator->userData, ptr); + + } else { + _aligned_free(ptr); + } +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/core/win32/pal_result_win32.c b/src/core/win32/pal_result_win32.c new file mode 100644 index 00000000..336d0d47 --- /dev/null +++ b/src/core/win32/pal_result_win32.c @@ -0,0 +1,45 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_format.h" +#include "core/pal_result_common.h" +#include + +uint16_t PAL_CALL palGetResultCode(PalResult result) +{ + getResultCode(result); +} + +void PAL_CALL palFormatResult( + PalResult result, + uint64_t bufferSize, + char* buffer) +{ + const char* baseString = resultCodeToString(result); + const char* sourceString = resultSourceToString(result); + + uint32_t nativeCode = getResultNativeCode(result); + if (nativeCode != 0) { + char tmpBuffer[256]; + FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + nativeCode, + 0, + tmpBuffer, + 256, + nullptr); + + format(buffer, "%s (0x%08x) - %s: %s", sourceString, nativeCode, baseString, tmpBuffer); + + } else { + format(buffer, "%s (0x%08x) - %s", sourceString, nativeCode, baseString); + } +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/core/pal_time.c b/src/core/win32/pal_time_win32.c similarity index 65% rename from src/core/pal_time.c rename to src/core/win32/pal_time_win32.c index 3934d2c5..ce5c65cd 100644 --- a/src/core/pal_time.c +++ b/src/core/win32/pal_time_win32.c @@ -5,9 +5,7 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L -#include "pal/core/time.h" +#include "pal/pal_core.h" #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN @@ -24,30 +22,18 @@ #endif // UNICODE #include -#else -#include -#endif // _WIN32 - uint64_t PAL_CALL palGetPerformanceCounter() { -#ifdef _WIN32 LARGE_INTEGER counter; QueryPerformanceCounter(&counter); return (uint64_t)counter.QuadPart; -#else - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (uint64_t)ts.tv_sec * 1000000000LL + (uint64_t)ts.tv_nsec; -#endif // _WIN32 } uint64_t PAL_CALL palGetPerformanceFrequency() { -#ifdef _WIN32 LARGE_INTEGER frequency; QueryPerformanceFrequency(&frequency); return (uint64_t)frequency.QuadPart; -#else - return 1000000000LL; -#endif // _WIN32 -} \ No newline at end of file +} + +#endif // _WIN32 \ No newline at end of file diff --git a/tests/core/logger_test.c b/tests/core/logger_test.c index debef306..e60bd52c 100644 --- a/tests/core/logger_test.c +++ b/tests/core/logger_test.c @@ -38,5 +38,5 @@ PalBool loggerTest() palLog(&loggers[i], "This is directed to a logger"); } - return true; + return PAL_TRUE; } diff --git a/tests/core/time_test.c b/tests/core/time_test.c index c454eaa4..9f355392 100644 --- a/tests/core/time_test.c +++ b/tests/core/time_test.c @@ -39,5 +39,5 @@ PalBool timeTest() palLog(nullptr, "Loop finished after %f seconds and %d frames", totalTime, frameCount); - return true; + return PAL_TRUE; } diff --git a/tests/tests.c b/tests/tests.c index 6b4bdc25..ac78f63d 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -21,7 +21,7 @@ void registerTest(TestFn func, const char* name) void runTests() { - PalBool status = false; + PalBool status = PAL_FALSE; const char* statusString = nullptr; for (int32_t i = 0; i < s_Count; i++) { palLog(nullptr, ""); diff --git a/tests/tests.h b/tests/tests.h index 0bcd7f29..04de34a3 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -17,7 +17,7 @@ static PalBool readFile( { FILE* file = fopen(filename, "rb"); if (!file) { - return false; + return PAL_FALSE; } fseek(file, 0, SEEK_END); @@ -28,13 +28,13 @@ static PalBool readFile( tmpSize = *size; size_t read = fread(buffer, 1, tmpSize, file); if (read != tmpSize) { - return false; + return PAL_FALSE; } } fclose(file); *size = tmpSize; - return true; + return PAL_TRUE; } // core tests diff --git a/tests/tests.lua b/tests/tests.lua index 13e1dc8c..a99e21a5 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -15,8 +15,8 @@ project "tests" "core/time_test.c", -- event - "event/user_event_test.c", - "event/event_test.c" + -- "event/user_event_test.c", + -- "event/event_test.c" } if (PAL_BUILD_SYSTEM_MODULE) then diff --git a/tests/tests_main.c b/tests/tests_main.c index 230769b5..09a3ca92 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -8,8 +8,8 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - // registerTest(loggerTest, "Logger Test"); - // registerTest(timeTest, "Time Test"); + registerTest(loggerTest, "Logger Test"); + registerTest(timeTest, "Time Test"); // event // registerTest(eventTest, "Event test"); @@ -20,10 +20,10 @@ int main(int argc, char** argv) #endif // PAL_HAS_SYSTEM_MODULE #if PAL_HAS_THREAD_MODULE - registerTest(threadTest, "Thread Test"); - registerTest(tlsTest, "TLS Test"); - registerTest(mutexTest, "Mutex Test"); - registerTest(condvarTest, "Condvar Test"); + // registerTest(threadTest, "Thread Test"); + // registerTest(tlsTest, "TLS Test"); + // registerTest(mutexTest, "Mutex Test"); + // registerTest(condvarTest, "Condvar Test"); #endif // PAL_HAS_THREAD_MODULE #if PAL_HAS_VIDEO_MODULE From 07b42c0dcc82f81652914670b9d72b3b48833519 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Jun 2026 01:14:23 +0000 Subject: [PATCH 260/372] test event system rewrite --- CHANGELOG.md | 2 + include/pal/pal_core.h | 12 +- include/pal/pal_event.h | 552 ++++++++++++++---------------- include/pal/pal_graphics.h | 106 +++--- include/pal/pal_opengl.h | 8 +- include/pal/pal_system.h | 8 +- include/pal/pal_video.h | 22 +- include/pal/thread/thread.h | 4 +- pal.lua | 3 +- src/core/linux/pal_result_linux.c | 13 +- src/core/pal_result_common.h | 86 +++-- src/core/pal_version.c | 12 +- src/core/win32/pal_result_win32.c | 9 +- src/event/pal_default_queue.c | 69 ++++ src/event/pal_default_queue.h | 21 ++ src/{ => event}/pal_event.c | 97 +++--- src/pal_shared.h | 26 ++ tests/event/event_test.c | 20 +- tests/event/user_event_test.c | 15 +- tests/tests.h | 7 + tests/tests.lua | 4 +- tests/tests_main.c | 8 +- 22 files changed, 613 insertions(+), 491 deletions(-) create mode 100644 src/event/pal_default_queue.c create mode 100644 src/event/pal_default_queue.h rename src/{ => event}/pal_event.c (61%) create mode 100644 src/pal_shared.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cbd1bd8..dfc404a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -129,6 +129,7 @@ palJoinThread(thread, &retval); - **Core:** Added **PAL_RESULT_NOT_INITIALIZED** result code. - **Core:** Added **PAL_RESULT_DEVICE_LOST** result code. - **Core:** Added **PAL_RESULT_OUT_OF_DATE** result code. +- **Core:** Added **palGetResultCode()**. - **Graphics:** Added **Graphics System To PAL**. @@ -146,6 +147,7 @@ palJoinThread(thread, &retval); - **Core:** Rename **Uint64** to **uint64_t**. - **Core:** Rename **UintPtr** to **uintptr_t**. - **Core:** **palFormatResult()** now takes two additional parameters. +- **Core:** **palGetVersion()** now takes a parameter and returns nothing. - **Thread:** **palJoinThread()** now takes a void** for retval parameter. diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index c051852a..ea1d9e7e 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -209,7 +209,7 @@ PAL_API uint16_t PAL_CALL palGetResultCode(PalResult result); * @param bufferSize The size of the buffer. * @param buffer The buffer. * - * Thread safety: Thread safe if the provided buffer is per thread. + * Thread safety: Thread safe if buffer is per thread. * * @since 2.0 */ @@ -220,15 +220,15 @@ PAL_API void PAL_CALL palFormatResult( /** * Retrieve the PAL version number. + * + * @param version Pointer to PalVersion struct to fill. * - * @return PAL version (major, minor, build). - * - * Thread safety: Thread safe. + * Thread safety: Thread safe if version is per thread. * - * @since 1.0 + * @since 2.0 * @sa palGetVersionString */ -PAL_API PalVersion PAL_CALL palGetVersion(); +PAL_API void PAL_CALL palGetVersion(PalVersion* version); /** * Retrieve the PAL version string. diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 92976113..15e046c7 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -6,7 +6,7 @@ */ /** - * @defgroup pal_event Event System + * @defgroup pal_event Event * @ingroup pal_event * @{ */ @@ -16,6 +16,227 @@ #include "pal/pal_core.h" +#define PAL_DECORATION_MODE_CLIENT_SIDE 0 +#define PAL_DECORATION_MODE_SERVER_SIDE 1 + +/** + * event.data2 : window + * + * Use inline helpers: + * - palUnpackPointer() + */ +#define PAL_EVENT_WINDOW_CLOSE 0 + +/** + * event.data : lower 32 bits = width, upper 32 bits = height + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackUint32() + * - palUnpackPointer() + */ +#define PAL_EVENT_WINDOW_SIZE 1 + +/** + * event.data : lower 32 bits = x, upper 32 bits = y + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackInt32() + * - palUnpackPointer() + */ +#define PAL_EVENT_WINDOW_MOVE 2 + +/** + * event.data : state(minimized, maximized, restored). + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackPointer() + */ +#define PAL_EVENT_WINDOW_STATE 3 + +/** + * event.data : `true` for focus gained or `false` for focus lost. + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackPointer() + */ +#define PAL_EVENT_WINDOW_FOCUS 4 + +/** + * event.data : `true` for visible or `false` for hidden. + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackPointer() + */ +#define PAL_EVENT_WINDOW_VISIBILITY 5 + +/** + * event.data2 : window + */ +#define PAL_EVENT_WINDOW_MODAL_BEGIN 6 + +/** + * event.data2 : window + */ +#define PAL_EVENT_WINDOW_MODAL_END 7 + +/** + * event.data2 : window + */ +#define PAL_EVENT_MONITOR_DPI_CHANGED 8 + +/** + * event.data2 : window + */ +#define PAL_EVENT_MONITOR_LIST_CHANGED 9 + +/** + * event.data : lower 32 bits = keycode, upper 32 bits = scancode + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackUint32() + * - palUnpackPointer() + */ +#define PAL_EVENT_KEYDOWN 10 + +/** + * event.data : lower 32 bits = keycode, upper 32 bits = scancode + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackUint32() + * - palUnpackPointer() + */ +#define PAL_EVENT_KEYREPEAT 11 + +/** + * event.data : lower 32 bits = keycode, upper 32 bits = scancode + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackUint32() + * - palUnpackPointer() + */ +#define PAL_EVENT_KEYUP 12 + +/** + * event.data : lower 32 bits = button, upper 32 bits = serial + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackPointer() + */ +#define PAL_EVENT_MOUSE_BUTTONDOWN 13 + +/** + * event.data : lower 32 bits = button, upper 32 bits = serial + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackPointer() + */ +#define PAL_EVENT_MOUSE_BUTTONUP 14 + +/** + * event.data : lower 32 bits = x, upper 32 bits = y + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackInt32() + * - palUnpackPointer() + */ +#define PAL_EVENT_MOUSE_MOVE 15 + +/** + * event.data : lower 32 bits = dx, upper 32 bits = dy + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackInt32() + * - palUnpackPointer() + */ +#define PAL_EVENT_MOUSE_DELTA 16 + +/** + * event.data : lower 32 bits = dx, upper 32 bits = dy + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackInt32() + * - palUnpackPointer() + */ +#define PAL_EVENT_MOUSE_WHEEL 17 + +/** + * event.userId : User event ID or type. + * + * Use inline helpers: + * - palPackInt32() + * - palPackUint32() + * - palPackPointer() + * - palUnpackInt32() + * - palUnpackUint32() + * - palUnpackPointer() + */ +#define PAL_EVENT_USER 18 + +/** + * event.data : codepoint + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackPointer() + */ +#define PAL_EVENT_KEYCHAR 19 + +/** + * event.data : negotiated decorations mode + * + * event.data2 : window + * + * Use inline helpers: + * - palUnpackPointer() + */ +#define PAL_EVENT_WINDOW_DECORATION_MODE 20 + +#define PAL_EVENT_MAX 21 + +/** + * No dispatch. + */ +#define PAL_DISPATCH_NONE 0 + +/** + * Dispatch to event callback. + */ +#define PAL_DISPATCH_CALLBACK 1 + +/** + * Dispatch to event queue. + */ +#define PAL_DISPATCH_POLL 2 + +#define PAL_DISPATCH_MAX + /** * @struct PalEventDriver * @brief Opaque handle to an event driver. @@ -32,6 +253,39 @@ typedef struct PalEventDriver PalEventDriver; */ typedef struct PalEvent PalEvent; +/** + * @typedef PalDecorationMode + * @brief Decoration types. This is not a bitmask enum. + * + * All decoration types follow the format `PAL_DECORATION_MODE_**` for + * consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalDecorationMode; + +/** + * @typedef PalEventType + * @brief Event types. This is not a bitmask enum. + * + * All event types follow the format `PAL_EVENT_**` for consistency and + * API use. + * + * @since 2.0 + */ +typedef uint32_t PalEventType; + +/** + * @typedef PalDispatchMode + * @brief Dispatch types for an event. This is not a bitmask enum. + * + * All dispatch modes follow the format `PAL_DISPATCH_**` for consistency + * and API use. + * + * @since 2.0 + */ +typedef uint32_t PalDispatchMode; + /** * @typedef PalEventCallback * @brief Function pointer type used for event callbacks. @@ -78,303 +332,11 @@ typedef PalBool(PAL_CALL* PalPollFn)( void* userData, PalEvent* outEvent); -/** - * @enum PalDecorationMode - * @brief Decoration types. This is not a bitmask enum. - * - * All decoration types follow the format `PAL_DECORATION_MODE_**` for - * consistency and API use. - * - * @since 1.3 - */ -typedef enum { - PAL_DECORATION_MODE_CLIENT_SIDE, - PAL_DECORATION_MODE_SERVER_SIDE -} PalDecorationMode; - -/** - * @enum PalEventType - * @brief Event types. This is not a bitmask enum. - * - * All event types follow the format `PAL_EVENT_**` for consistency and - * API use. - * - * @since 1.0 - */ -typedef enum { - /** - * PAL_EVENT_WINDOW_CLOSE - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() - */ - PAL_EVENT_WINDOW_CLOSE, - - /** - * PAL_EVENT_WINDOW_SIZE - * - * event.data : lower 32 bits = width, upper 32 bits = height - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackUint32() - * - palUnpackPointer() - */ - PAL_EVENT_WINDOW_SIZE, - - /** - * PAL_EVENT_WINDOW_MOVE - * - * event.data : lower 32 bits = x, upper 32 bits = y - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackInt32() - * - palUnpackPointer() - */ - PAL_EVENT_WINDOW_MOVE, - - /** - * PAL_EVENT_WINDOW_STATE - * - * event.data : state(minimized, maximized, restored). - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() - */ - PAL_EVENT_WINDOW_STATE, - - /** - * PAL_EVENT_WINDOW_FOCUS - * - * event.data : `true` for focus gained or `false` for focus lost. - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() - */ - PAL_EVENT_WINDOW_FOCUS, - - /** - * PAL_EVENT_WINDOW_VISIBILITY - * - * event.data : `true` for visible or `false` for hidden. - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() - */ - PAL_EVENT_WINDOW_VISIBILITY, - - /** - * @brief WM_ENTERSIZEMOVE (Windows Only). - * - * PAL_EVENT_WINDOW_MODAL_BEGIN - * - * event.data2 : window - */ - PAL_EVENT_WINDOW_MODAL_BEGIN, - - /** - * @brief WM_EXITSIZEMOVE (Windows Only). - * - * PAL_EVENT_WINDOW_MODAL_END - * - * event.data2 : window - */ - PAL_EVENT_WINDOW_MODAL_END, - - /** - * PAL_EVENT_MONITOR_DPI_CHANGED - * - * event.data2 : window - */ - PAL_EVENT_MONITOR_DPI_CHANGED, - - /** - * @brief Monitor list changed - * - * PAL_EVENT_MONITOR_LIST_CHANGED - * - * event.data2 : window - */ - PAL_EVENT_MONITOR_LIST_CHANGED, - - /** - * PAL_EVENT_KEYDOWN - * - * event.data : lower 32 bits = keycode, upper 32 bits = scancode - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackUint32() - * - palUnpackPointer() - */ - PAL_EVENT_KEYDOWN, - - /** - * PAL_EVENT_KEYREPEAT - * - * event.data : lower 32 bits = keycode, upper 32 bits = scancode - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackUint32() - * - palUnpackPointer() - */ - PAL_EVENT_KEYREPEAT, - - /** - * PAL_EVENT_KEYUP - * - * event.data : lower 32 bits = keycode, upper 32 bits = scancode - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackUint32() - * - palUnpackPointer() - */ - PAL_EVENT_KEYUP, - - /** - * PAL_EVENT_MOUSE_BUTTONDOWN - * - * event.data : lower 32 bits = button, upper 32 bits = serial - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() - */ - PAL_EVENT_MOUSE_BUTTONDOWN, - - /** - * PAL_EVENT_MOUSE_BUTTONUP - * - * event.data : lower 32 bits = button, upper 32 bits = serial - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() - */ - PAL_EVENT_MOUSE_BUTTONUP, - - /** - * PAL_EVENT_MOUSE_MOVE - * - * event.data : lower 32 bits = x, upper 32 bits = y - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackInt32() - * - palUnpackPointer() - */ - PAL_EVENT_MOUSE_MOVE, - - /** - * @brief Mouse movement delta. - * - * PAL_EVENT_MOUSE_DELTA - * - * event.data : lower 32 bits = dx, upper 32 bits = dy - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackInt32() - * - palUnpackPointer() - */ - PAL_EVENT_MOUSE_DELTA, - - /** - * PAL_EVENT_MOUSE_WHEEL - * - * event.data : lower 32 bits = dx, upper 32 bits = dy - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackInt32() - * - palUnpackPointer() - */ - PAL_EVENT_MOUSE_WHEEL, - - /** - * PAL_EVENT_USER - * - * event.userId : User event ID or type. - * - * Use inline helpers: - * - palPackInt32() - * - palPackUint32() - * - palPackPointer() - * - palUnpackInt32() - * - palUnpackUint32() - * - palUnpackPointer() - */ - PAL_EVENT_USER, - - /** - * PAL_EVENT_USER - * - * event.data : codepoint - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() - */ - PAL_EVENT_KEYCHAR, - - /** - * PAL_EVENT_WINDOW_DECORATION_MODE - * - * event.data : negotiated decorations mode - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() - */ - PAL_EVENT_WINDOW_DECORATION_MODE, - - PAL_EVENT_MAX -} PalEventType; - -/** - * @enum PalDispatchMode - * @brief Dispatch types for an event. This is not a bitmask enum. - * - * All dispatch modes follow the format `PAL_DISPATCH_**` for consistency - * and API use. - * - * @since 1.0 - */ -typedef enum { - PAL_DISPATCH_NONE, /**< No dispatch.*/ - PAL_DISPATCH_CALLBACK, /**< Dispatch to event callback.*/ - PAL_DISPATCH_POLL, /**< Dispatch to the event queue.*/ - PAL_DISPATCH_MAX -} PalDispatchMode; - struct PalEvent { - PalEventType type; + int64_t userId; /**< You can have user events upto int64_t max.*/ int64_t data; /**< First data payload.*/ int64_t data2; /**< Second data payload.*/ - int64_t userId; /**< You can have user events upto int64_t max.*/ + PalEventType type; }; /** diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 25f033c4..c4615829 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -79,7 +79,7 @@ freely, subject to the following restrictions: #define PAL_SHADER_TARGET_MINOR(target) ((uint32_t)(target) & 0xFF); /** - * @enum PalAdapterFeatures + * @typedef PalAdapterFeatures * @brief Adapter features. This is a bitmask. * * All adapter features follow the format `PAL_ADAPTER_FEATURE_**` for @@ -336,7 +336,7 @@ typedef struct PalShaderBindingTable PalShaderBindingTable; typedef struct PalAccelerationStructure PalAccelerationStructure; /** - * @enum PalDebugMessageSeverity + * @typedef PalDebugMessageSeverity * @brief Debugger messages severity types used to filter incoming messages. * * @since 1.4 @@ -345,7 +345,7 @@ typedef struct PalAccelerationStructure PalAccelerationStructure; typedef enum PalDebugMessageSeverity PalDebugMessageSeverity; /** - * @enum PalDebugMessageType + * @typedef PalDebugMessageType * @brief Debugger messages types used to filter incoming messages. * * @since 1.4 @@ -384,7 +384,7 @@ typedef void(PAL_CALL* PalDebugCallback)( const char* msg); /** - * @enum PalAdapterType + * @typedef PalAdapterType * @brief Adapter (GPU) types. * * All adapter types follow the format `PAL_ADAPTER_TYPE_**` for @@ -402,7 +402,7 @@ typedef enum { } PalAdapterType; /** - * @enum PalAdapterApiType + * @typedef PalAdapterApiType * @brief Adapter API types. * * All adapter api types follow the format `PAL_ADAPTER_API_TYPE_**` for @@ -427,7 +427,7 @@ typedef enum { } PalAdapterApiType; /** - * @enum PalQueueType + * @typedef PalQueueType * @brief Queue types. * * All queue types follow the format `PAL_QUEUE_TYPE_**` for @@ -443,7 +443,7 @@ typedef enum { } PalQueueType; /** - * @enum PalPresentMode + * @typedef PalPresentMode * @brief Present modes * * All present modes follow the format `PAL_PRESENT_MODE_**` for @@ -461,7 +461,7 @@ typedef enum { } PalPresentMode; /** - * @enum PalCompositeAplha + * @typedef PalCompositeAplha * @brief Composite alphas * * All composite alphas follow the format `PAL_COMPOSITE_ALPHA_**` for @@ -479,7 +479,7 @@ typedef enum { } PalCompositeAplha; /** - * @enum PalFormat + * @typedef PalFormat * @brief Format types. * * All format types follow the format `PAL_FORMAT_**` for @@ -576,7 +576,7 @@ typedef enum { } PalFormat; /** - * @enum PalImageUsages + * @typedef PalImageUsages * @brief Image usages. Multiple image usages can be OR'ed together using bitwise * OR operator (`|`). * @@ -598,7 +598,7 @@ typedef enum { } PalImageUsages; /** - * @enum PalShaderFormats + * @typedef PalShaderFormats * @brief Shader formats. This is a bitmask. * * All shader formats follow the format `PAL_SHADER_FORMAT_**` for @@ -617,7 +617,7 @@ typedef enum { } PalShaderFormats; /** - * @enum PalLoadOp + * @typedef PalLoadOp * @brief Load operation type. * * All load operation type follow the format `PAL_LOAD_OP_**` for @@ -633,7 +633,7 @@ typedef enum { } PalLoadOp; /** - * @enum PalStoreOp + * @typedef PalStoreOp * @brief Store operation type. * * All store operation type follow the format `PAL_STORE_OP_**` for @@ -648,7 +648,7 @@ typedef enum { } PalStoreOp; /** - * @enum PalMemoryType + * @typedef PalMemoryType * @brief Memory types. * * All memory types follow the format `PAL_MEMORY_TYPE_**` for @@ -666,7 +666,7 @@ typedef enum { } PalMemoryType; /** - * @enum PalImageType + * @typedef PalImageType * @brief Image types. * * All image types follow the format `PAL_IMAGE_TYPE_**` for @@ -682,7 +682,7 @@ typedef enum { } PalImageType; /** - * @enum PalImageAspect + * @typedef PalImageAspect * @brief Image aspects. * * All image aspect follow the format `PAL_IMAGE_ASPECT_**` for @@ -699,7 +699,7 @@ typedef enum { } PalImageAspect; /** - * @enum PalImageViewType + * @typedef PalImageViewType * @brief Image view types. * * All image view types follow the format `PAL_IMAGE_VIEW_TYPE_**` for @@ -719,7 +719,7 @@ typedef enum { } PalImageViewType; /** - * @enum PalFilterMode + * @typedef PalFilterMode * @brief Filter modes. * * All filter modes follow the format `PAL_FILTER_MODE_**` for @@ -734,7 +734,7 @@ typedef enum { } PalFilterMode; /** - * @enum PalSamplerMipmapMode + * @typedef PalSamplerMipmapMode * @brief Sampler mipmap modes. * * All sampler mipmap modes follow the format `PAL_SAMPLER_MIPMAP_MODE_**` for @@ -749,7 +749,7 @@ typedef enum { } PalSamplerMipmapMode; /** - * @enum PalSamplerAddressMode + * @typedef PalSamplerAddressMode * @brief Sampler address modes. * * All sampler address modes follow the format `PAL_SAMPLER_ADDRESS_MODE_**` for @@ -766,7 +766,7 @@ typedef enum { } PalSamplerAddressMode; /** - * @enum PalBorderColor + * @typedef PalBorderColor * @brief Border color. * * All border colors follow the format `PAL_BORDER_COLOR_**` for @@ -785,7 +785,7 @@ typedef enum { } PalBorderColor; /** - * @enum PalSurfaceFormat + * @typedef PalSurfaceFormat * @brief Surface format types. * * All surface format types follow the format `PAL_SURFACE_FORMAT_**` for @@ -804,7 +804,7 @@ typedef enum { } PalSurfaceFormat; /** - * @enum PalGraphicsWindowDisplayType + * @typedef PalGraphicsWindowDisplayType * @brief Display types for a graphics window. * * All graphics window display types follow the format `PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_**` for @@ -820,7 +820,7 @@ typedef enum { } PalGraphicsWindowDisplayType; /** - * @enum PalShaderStage + * @typedef PalShaderStage * @brief shader stage types. * * All shader stage types follow the format `PAL_SHADER_STAGE_**` for @@ -849,7 +849,7 @@ typedef enum { } PalShaderStage; /** - * @enum PalSampleCount + * @typedef PalSampleCount * @brief sample count. * * All sample count follow the format `PAL_SAMPLE_COUNT_**` for @@ -869,7 +869,7 @@ typedef enum { } PalSampleCount; /** - * @enum PalPrimitiveTopology + * @typedef PalPrimitiveTopology * @brief Primitve topology types. * * All primitve topology types follow the format `PAL_PRIMITIVE_TOPOLOGY_**` for @@ -888,7 +888,7 @@ typedef enum { } PalPrimitiveTopology; /** - * @enum PalCullMode + * @typedef PalCullMode * @brief Cull modes. * * All cull modes follow the format `PAL_CULL_MODE_**` for @@ -904,7 +904,7 @@ typedef enum { } PalCullMode; /** - * @enum PalFrontFace + * @typedef PalFrontFace * @brief Front face modes. * * All front face modes follow the format `PAL_FRONT_FACE_**` for @@ -919,7 +919,7 @@ typedef enum { } PalFrontFace; /** - * @enum PalPolygonMode + * @typedef PalPolygonMode * @brief Polygon modes. * * All polygon modes follow the format `PAL_POLYGON_MODE_**` for @@ -934,7 +934,7 @@ typedef enum { } PalPolygonMode; /** - * @enum PalStencilFaceFlags + * @typedef PalStencilFaceFlags * @brief Stencil face flags. Multiple stencil face flags can be OR'ed together using bitwise * OR operator (`|`). * @@ -951,7 +951,7 @@ typedef enum { } PalStencilFaceFlags; /** - * @enum PalVertexType + * @typedef PalVertexType * @brief Vertex attribute types. * * All vertex attribute types follow the format `PAL_VERTEX_TYPE_**` for @@ -1003,7 +1003,7 @@ typedef enum { } PalVertexType; /** - * @enum PalVertexSemanticID + * @typedef PalVertexSemanticID * @brief Vertex semantic id types. * * All vertex semantic id types follow the format `PAL_VERTEX_SEMANTIC_ID_**` for @@ -1021,7 +1021,7 @@ typedef enum { } PalVertexSemanticID; /** - * @enum PalCommandBufferType + * @typedef PalCommandBufferType * @brief Command buffer types. * * All command buffer types follow the format `PAL_COMMAND_BUFFER_TYPE_**` for @@ -1036,7 +1036,7 @@ typedef enum { } PalCommandBufferType; /** - * @enum PalVertexLayoutType + * @typedef PalVertexLayoutType * @brief Vertex layout types. * * All vertex layout types follow the format `PAL_VERTEX_LAYOUT_TYPE_**` for @@ -1051,7 +1051,7 @@ typedef enum { } PalVertexLayoutType; /** - * @enum PalCompareOp + * @typedef PalCompareOp * @brief Compare operation modes. * * All compare operation modes follow the format `PAL_COMPARE_OP_**` for @@ -1072,7 +1072,7 @@ typedef enum { } PalCompareOp; /** - * @enum PalStencilOp + * @typedef PalStencilOp * @brief Stencil operation modes. * * All stencil operation modes follow the format `PAL_STENCIL_OP_**` for @@ -1093,7 +1093,7 @@ typedef enum { } PalStencilOp; /** - * @enum PalBlendOp + * @typedef PalBlendOp * @brief Blend operation modes. * * All blend operation modes follow the format `PAL_BLEND_OP_**` for @@ -1111,7 +1111,7 @@ typedef enum { } PalBlendOp; /** - * @enum PalBlendOp + * @typedef PalBlendOp * @brief Blend factor modes. * * All blend factor modes follow the format `PAL_BLEND_FACTOR_**` for @@ -1138,7 +1138,7 @@ typedef enum { } PalBlendFactor; /** - * @enum PalColorMask + * @typedef PalColorMask * @brief Color mask flags. Multiple color mask flags can be OR'ed together using bitwise * OR operator (`|`). * @@ -1160,7 +1160,7 @@ typedef enum { } PalColorMask; /** - * @enum PalResolveMode + * @typedef PalResolveMode * @brief Resolve modes. * * All resolve modes follow the format `PAL_RESOLVE_MODE_**` for @@ -1179,7 +1179,7 @@ typedef enum { } PalResolveMode; /** - * @enum PalFragmentShadingRate + * @typedef PalFragmentShadingRate * @brief Fragment shading rates. * * All fragment shading rates follow the format `PAL_FRAGMENT_SHADING_RATE_**` for @@ -1201,7 +1201,7 @@ typedef enum { } PalFragmentShadingRate; /** - * @enum PalFragmentShadingRateCombinerOp + * @typedef PalFragmentShadingRateCombinerOp * @brief Fragment shading rate combiner operaton modes. * * All fragment shading rate combiner operation modes follow the format @@ -1219,7 +1219,7 @@ typedef enum { } PalFragmentShadingRateCombinerOp; /** - * @enum PalAccelerationStructureType + * @typedef PalAccelerationStructureType * @brief Acceleration structure types. * * All acceleration structure types follow the format `PAL_ACCELERATION_STRUCTURE_TYPE_**` @@ -1234,7 +1234,7 @@ typedef enum { } PalAccelerationStructureType; /** - * @enum PalAccelerationStructureBuildMode + * @typedef PalAccelerationStructureBuildMode * @brief Acceleration structure build modes. * * All acceleration structure build modes follow the format @@ -1249,7 +1249,7 @@ typedef enum { } PalAccelerationStructureBuildMode; /** - * @enum PalAccelerationStructureBuildHints + * @typedef PalAccelerationStructureBuildHints * @brief Acceleration structure build hints. Multiple hints can be OR'ed together using * bitwise OR operator (`|`). Hints can be ignored by the driver. * @@ -1266,7 +1266,7 @@ typedef enum { } PalAccelerationStructureBuildHints; /** - * @enum PalAccelerationStructureInstanceFlags + * @typedef PalAccelerationStructureInstanceFlags * @brief Acceleration structure instance flags. Multiple flags can be OR'ed together using * bitwise OR operator (`|`). Not all combinations are valid. * @@ -1284,7 +1284,7 @@ typedef enum { } PalAccelerationStructureInstanceFlags; /** - * @enum PalGeometryType + * @typedef PalGeometryType * @brief Geometry types. * * All geometry types follow the format `PAL_GEOMETRY_TYPE_**` for consistency and API use. @@ -1298,7 +1298,7 @@ typedef enum { } PalGeometryType; /** - * @enum PalGeometryFlags + * @typedef PalGeometryFlags * @brief Geometry flags. Multiple flags can be OR'ed together using * bitwise OR operator (`|`). Not all combinations are valid. * @@ -1313,7 +1313,7 @@ typedef enum { } PalGeometryFlags; /** - * @enum PalIndexType + * @typedef PalIndexType * @brief Index types. * * All index types follow the format `PAL_INDEX_TYPE_**` for consistency and API use. @@ -1327,7 +1327,7 @@ typedef enum { } PalIndexType; /** - * @enum PalBufferUsages + * @typedef PalBufferUsages * @brief Buffer usages. Multiple buffer usages can be OR'ed together using bitwise * OR operator (`|`). * @@ -1363,7 +1363,7 @@ enum PalDebugMessageType { }; /** - * @enum PalUsageState + * @typedef PalUsageState * @brief Usage states. * * All usage states follow the format `PAL_USAGE_STATE_**` for consistency and API use. @@ -1398,7 +1398,7 @@ typedef enum { } PalUsageState; /** - * @enum PalDescriptorType + * @typedef PalDescriptorType * @brief Descriptor types. * * All descriptor types follow the format `PAL_DESCRIPTOR_TYPE_**` for consistency and API use. @@ -1416,7 +1416,7 @@ typedef enum { } PalDescriptorType; /** - * @enum PalRayTracingShaderGroupType + * @typedef PalRayTracingShaderGroupType * @brief Ray tracing shader group types. * * All ray tracing shader group types follow the format `PAL_RAY_TRACING_SHADER_GROUP_TYPE_**` diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 6dc80666..e61f0469 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -50,7 +50,7 @@ freely, subject to the following restrictions: typedef struct PalGLContext PalGLContext; /** - * @enum PalGLExtensions + * @typedef PalGLExtensions * @brief Opengl system extensions. * * All opengl extensions follow the format `PAL_GL_EXTENSION_**` for @@ -73,7 +73,7 @@ typedef enum { } PalGLExtensions; /** - * @enum PalGLProfile + * @typedef PalGLProfile * @brief Opengl context creation profiles. This is not a bitmask. * * All opengl profiles follow the format `PAL_GL_PROFILE_**` for @@ -90,7 +90,7 @@ typedef enum { } PalGLProfile; /** - * @enum PalGLContextReset + * @typedef PalGLContextReset * @brief Opengl context reset behavior. This is not a bitmask. * * All context reset behavior follow the format `PAL_GL_CONTEXT_RESET_**` @@ -106,7 +106,7 @@ typedef enum { } PalGLContextReset; /** - * @enum PalGLRelease + * @typedef PalGLRelease * @brief Opengl context release behavior. This is not a bitmask. * * All opengl context release behavior follow the format diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index b9ac664c..c5dfaf5d 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -23,7 +23,7 @@ #define PAL_CPU_MODEL_NAME_SIZE 64 /** - * @enum PalCpuArch + * @typedef PalCpuArch * @brief CPU achitecture. This is not a bitmask. * * This is a build time achitecture. Example: Generating your project with x64 @@ -43,7 +43,7 @@ typedef enum { } PalCpuArch; /** - * @enum PalCpuFeatures + * @typedef PalCpuFeatures * @brief CPU features (instruction sets). * * All CPU features sets follow the format `PAL_CPU_FEATURE_**` for @@ -67,7 +67,7 @@ typedef enum { } PalCpuFeatures; /** - * @enum PalPlatformType + * @typedef PalPlatformType * @brief Platform types. This is not a bitmask. * * This is the family name (eg. This does not show if its Windows 7 or Windows 8 @@ -87,7 +87,7 @@ typedef enum { } PalPlatformType; /** - * @enum PalPlatformApiType + * @typedef PalPlatformApiType * @brief Platform API types. This is not a bitmask. * * This is the API the playform uses. Most platforms support only one (eg. diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 73bf885b..85d1cc73 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -34,7 +34,7 @@ freely, subject to the following restrictions: #include "pal_event.h" /** - * @enum PalVideoFeatures64 + * @typedef PalVideoFeatures64 * @brief Extended Video system features. * * All extended video features follow the format `PAL_VIDEO_FEATURE64_**` for @@ -123,7 +123,7 @@ typedef struct PalIcon PalIcon; typedef struct PalCursor PalCursor; /** - * @enum PalVideoFeatures + * @typedef PalVideoFeatures * @brief Video system features. * * All video features follow the format `PAL_VIDEO_FEATURE_**` for @@ -168,7 +168,7 @@ typedef enum { } PalVideoFeatures; /** - * @enum PalOrientation + * @typedef PalOrientation * @brief Orientation types for a monitor. * * All orientation types follow the format `PAL_ORIENTATION_**` for consistency @@ -185,7 +185,7 @@ typedef enum { } PalOrientation; /** - * @enum PalWindowStyle + * @typedef PalWindowStyle * @brief Window styles. Multiple styles can be OR'ed together using bitwise * OR operator (`|`). * @@ -206,7 +206,7 @@ typedef enum { } PalWindowStyle; /** - * @enum PalWindowState + * @typedef PalWindowState * @brief Represents the current state of a window. * * All window states follow the format `PAL_WINDOW_STATE_**` for consistency and @@ -222,7 +222,7 @@ typedef enum { } PalWindowState; /** - * @enum PalFlashFlag + * @typedef PalFlashFlag * @brief Flash flags. Multiple flash flags can be OR'ed together using bitwise * OR operator (`|`). * @@ -241,7 +241,7 @@ typedef enum { } PalFlashFlag; /** - * @enum PalFBConfigBackend + * @typedef PalFBConfigBackend * @brief Represents the backend of a FBConfig. * * All FBConfig backends follow the format `PAL_CONFIG_BACKEND**` for @@ -259,7 +259,7 @@ typedef enum { } PalFBConfigBackend; /** - * @enum PalScancode + * @typedef PalScancode * @brief scancodes (layout independent keys) of a keyboard. * * All scancodes follow the format `PAL_SCANCODE_**` for consistency and @@ -388,7 +388,7 @@ typedef enum { } PalScancode; /** - * @enum PalKeycode + * @typedef PalKeycode * @brief Keycodes (layout aware keys) of a keyboard. * * All keycodes follow the format `PAL_KEYCODE_**` for consistency and API @@ -517,7 +517,7 @@ typedef enum { } PalKeycode; /** - * @enum PalMouseButton + * @typedef PalMouseButton * @brief Buttons of a mouse. * * All mouse buttons follow the format `PAL_MOUSE_BUTTON_**` for @@ -539,7 +539,7 @@ typedef enum { } PalMouseButton; /** - * @enum PalCursorType + * @typedef PalCursorType * @brief System cursor types. * * All cursor types follow the format `PAL_CURSOR_**` for diff --git a/include/pal/thread/thread.h b/include/pal/thread/thread.h index 575896c2..942bf1a1 100644 --- a/include/pal/thread/thread.h +++ b/include/pal/thread/thread.h @@ -39,7 +39,7 @@ typedef struct PalThread PalThread; typedef void* (*PalThreadFn)(void* arg); /** - * @enum PalThreadFeatures + * @typedef PalThreadFeatures * @brief Thread system features. * * All thread features follow the format `PAL_THREAD_FEATURE_**` for @@ -55,7 +55,7 @@ typedef enum { } PalThreadFeatures; /** - * @enum PalThreadPriority + * @typedef PalThreadPriority * @brief Thread priority types. This is not a bitmask enum. * * All thread priority types follow the format `PAL_THREAD_PRIORITY_**` for diff --git a/pal.lua b/pal.lua index d5826fe1..3ea17e36 100644 --- a/pal.lua +++ b/pal.lua @@ -27,7 +27,8 @@ project "PAL" "src/core/pal_version.c", -- event - -- "src/pal_event.c" + "src/event/pal_default_queue.c", + "src/event/pal_event.c" } filter {"system:windows", "configurations:*"} diff --git a/src/core/linux/pal_result_linux.c b/src/core/linux/pal_result_linux.c index fc388126..860126a0 100644 --- a/src/core/linux/pal_result_linux.c +++ b/src/core/linux/pal_result_linux.c @@ -7,7 +7,7 @@ #ifdef __linux__ #define _POSIX_C_SOURCE 200112L -#include "pal/pal_core.h" +#include "core/pal_format.h" #include "core/pal_result_common.h" #include @@ -21,10 +21,15 @@ void PAL_CALL palFormatResult( uint64_t bufferSize, char* buffer) { - const char* baseString = resultCodeToString(result); - const char* sourceString = resultSourceToString(result); + char tmpBuffer[256]; uint32_t nativeCode = getResultNativeCode(result); - strerror_r(nativeCode, buffer, bufferSize); + if (nativeCode != 0) { + strerror_r(nativeCode, tmpBuffer, 256); + formatResultMsg(result, buffer, tmpBuffer); + + } else { + formatResultMsg(result, buffer, nullptr); + } } #endif // __linux__ \ No newline at end of file diff --git a/src/core/pal_result_common.h b/src/core/pal_result_common.h index 88ac061a..d0d9d6cc 100644 --- a/src/core/pal_result_common.h +++ b/src/core/pal_result_common.h @@ -8,22 +8,7 @@ #ifndef _PAL_RESULT_COMMON_H #define _PAL_RESULT_COMMON_H -#include "pal/pal_core.h" - -#define PAL_RESULT_SOURCE_WINDOWS 100 -#define PAL_RESULT_SOURCE_LINUX 101 -#define PAL_RESULT_SOURCE_MACOS 102 -#define PAL_RESULT_SOURCE_VULKAN 103 -#define PAL_RESULT_SOURCE_D3D12 104 -#define PAL_RESULT_SOURCE_METAL 105 - -static inline PalResult makeResult( - uint16_t code, - uint16_t source, - uint32_t nativeCode) -{ - return ((uint64_t)nativeCode << 32) | ((uint64_t)source << 16) | (uint64_t)code; -} +#include "pal_shared.h" static inline uint16_t getResultCode(PalResult result) { @@ -41,6 +26,47 @@ static inline uint32_t getResultNativeCode(PalResult result) } static const char* PAL_CALL resultCodeToString(PalResult result) +{ + uint16_t code = getResultCode(result); + switch (code) { + case PAL_RESULT_SUCCESS: + return "PAL_RESULT_SUCCESS"; + + case PAL_RESULT_INVALID_ARGUMENT: + return "PAL_RESULT_INVALID_ARGUMENT"; + + case PAL_RESULT_OUT_OF_MEMORY: + return "PAL_RESULT_OUT_OF_MEMORY"; + + case PAL_RESULT_PLATFORM_FAILURE: + return "PAL_RESULT_PLATFORM_FAILURE"; + + case PAL_RESULT_TIMEOUT: + return "PAL_RESULT_TIMEOUT"; + + case PAL_RESULT_INVALID_HANDLE: + return "PAL_RESULT_INVALID_HANDLE"; + + case PAL_RESULT_FEATURE_NOT_SUPPORTED: + return "PAL_RESULT_FEATURE_NOT_SUPPORTED"; + + case PAL_RESULT_NOT_INITIALIZED: + return "PAL_RESULT_NOT_INITIALIZED"; + + case PAL_RESULT_INVALID_OPERATION: + return "PAL_RESULT_INVALID_OPERATION"; + + case PAL_RESULT_DEVICE_LOST: + return "PAL_RESULT_DEVICE_LOST"; + + case PAL_RESULT_OUT_OF_DATE: + return "PAL_RESULT_OUT_OF_DATE"; + } + + return nullptr; +} + +static const char* PAL_CALL resultCodeToDescription(PalResult result) { uint16_t code = getResultCode(result); switch (code) { @@ -91,20 +117,36 @@ static const char* PAL_CALL resultSourceToString(PalResult result) case PAL_RESULT_SOURCE_LINUX: return "Linux"; - case PAL_RESULT_SOURCE_MACOS: - return "MacOS"; - case PAL_RESULT_SOURCE_VULKAN: return "Vulkan"; case PAL_RESULT_SOURCE_D3D12: return "D3D12"; - - case PAL_RESULT_SOURCE_METAL: - return "Metal"; } return nullptr; } +static void formatResultMsg(PalResult result, char* buffer, char* msg) +{ + const char* baseString = resultCodeToString(result); + const char* sourceString = resultSourceToString(result); + const char* baseDescription = resultCodeToDescription(result); + uint32_t nativeCode = getResultNativeCode(result); + + const char* description = ""; + if (msg) { + description = msg; + } + + format( + buffer, + "Source: %s\n PAL Code: %s\n Native Code: 0x%08x\n PAL Description: %s\n Native Description: %s", + sourceString, + baseString, + nativeCode, + baseDescription, + description); +} + #endif // _PAL_RESULT_COMMON_H \ No newline at end of file diff --git a/src/core/pal_version.c b/src/core/pal_version.c index b4057858..591d81a3 100644 --- a/src/core/pal_version.c +++ b/src/core/pal_version.c @@ -12,13 +12,13 @@ #define PAL_VERSION_BUILD 0 #define PAL_VERSION_STRING "2.0.0" -PalVersion PAL_CALL palGetVersion() +void PAL_CALL palGetVersion(PalVersion* version) { - PalVersion version = {0}; - version.major = PAL_VERSION_MAJOR; - version.minor = PAL_VERSION_MINOR; - version.build = PAL_VERSION_BUILD; - return version; + if (version) { + version->major = PAL_VERSION_MAJOR; + version->minor = PAL_VERSION_MINOR; + version->build = PAL_VERSION_BUILD; + } } const char* PAL_CALL palGetVersionString() diff --git a/src/core/win32/pal_result_win32.c b/src/core/win32/pal_result_win32.c index 336d0d47..3977c20e 100644 --- a/src/core/win32/pal_result_win32.c +++ b/src/core/win32/pal_result_win32.c @@ -20,12 +20,9 @@ void PAL_CALL palFormatResult( uint64_t bufferSize, char* buffer) { - const char* baseString = resultCodeToString(result); - const char* sourceString = resultSourceToString(result); - + char tmpBuffer[256]; uint32_t nativeCode = getResultNativeCode(result); if (nativeCode != 0) { - char tmpBuffer[256]; FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, @@ -35,10 +32,10 @@ void PAL_CALL palFormatResult( 256, nullptr); - format(buffer, "%s (0x%08x) - %s: %s", sourceString, nativeCode, baseString, tmpBuffer); + formatResultMsg(result, buffer, tmpBuffer); } else { - format(buffer, "%s (0x%08x) - %s", sourceString, nativeCode, baseString); + formatResultMsg(result, buffer, nullptr); } } diff --git a/src/event/pal_default_queue.c b/src/event/pal_default_queue.c new file mode 100644 index 00000000..18a64022 --- /dev/null +++ b/src/event/pal_default_queue.c @@ -0,0 +1,69 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal_default_queue.h" + +typedef struct { + uint8_t head; + uint8_t tail; + PalEvent data[MAX_EVENTS]; +} QueueData; + +static void PAL_CALL eventPush( + void* queue, + PalEvent* event) +{ + PalEventQueue* eventQueue = queue; + QueueData* data = eventQueue->userData; + data->data[data->tail++ % MAX_EVENTS] = *event; +} + +static PalBool PAL_CALL eventPoll( + void* queue, + PalEvent* outEvent) +{ + PalEventQueue* eventQueue = queue; + QueueData* data = eventQueue->userData; + if (data->head == data->tail) { + return PAL_FALSE; + } + + *outEvent = data->data[data->head++ % MAX_EVENTS]; + return PAL_TRUE; +} + +PalEventQueue* createDefaultEventQueue(const PalAllocator* allocator) +{ + PalEventQueue* queue = nullptr; + queue = palAllocate(allocator, sizeof(PalEventQueue), 0); + if (!queue) { + return nullptr; + } + + // we create a default event queue data + QueueData* queueData = nullptr; + queueData = palAllocate(allocator, sizeof(QueueData), 0); + if (!queueData) { + palFree(allocator, queue); + return nullptr; + } + + memset(queueData, 0, sizeof(QueueData)); + queue->userData = queueData; + queue->poll = eventPoll; + queue->push = eventPush; + + return queue; +} + +void destroyDefaultEventQueue( + const PalAllocator* allocator, + PalEventQueue* queue) +{ + palFree(allocator, queue->userData); + palFree(allocator, queue); +} \ No newline at end of file diff --git a/src/event/pal_default_queue.h b/src/event/pal_default_queue.h new file mode 100644 index 00000000..a755d908 --- /dev/null +++ b/src/event/pal_default_queue.h @@ -0,0 +1,21 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_DEFAULT_QUEUE_H +#define _PAL_DEFAULT_QUEUE_H + +#include "pal/pal_event.h" + +#define MAX_EVENTS 512 + +PalEventQueue* createDefaultEventQueue(const PalAllocator* allocator); + +void destroyDefaultEventQueue( + const PalAllocator* allocator, + PalEventQueue* queue); + +#endif // _PAL_DEFAULT_QUEUE_H \ No newline at end of file diff --git a/src/pal_event.c b/src/event/pal_event.c similarity index 61% rename from src/pal_event.c rename to src/event/pal_event.c index 0701cfce..1c78e6eb 100644 --- a/src/pal_event.c +++ b/src/event/pal_event.c @@ -5,16 +5,28 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal/pal_event.h" +#include "pal_default_queue.h" +#include "pal_shared.h" #include -#define PAL_MAX_EVENTS 512 +#ifdef _WIN32 +#define PLATFORM_SOURCE PAL_RESULT_SOURCE_WINDOWS -typedef struct { - uint8_t head; - uint8_t tail; - PalEvent data[PAL_MAX_EVENTS]; -} QueueData; +uint32_t __stdcall GetLastError(); + +#elif defined(__linux__) +#include +#define PLATFORM_SOURCE PAL_RESULT_SOURCE_LINUX +#endif // _WIN32 + +static inline uint32_t getLastErrorCode() +{ +#ifdef _WIN32 + return GetLastError(); +#elif defined(__linux__) + return (uint32_t)errno; +#endif // _WIN32 +} struct PalEventDriver { PalBool freeQueue; @@ -22,50 +34,36 @@ struct PalEventDriver { const PalAllocator* allocator; PalEventCallback callback; void* userData; - PalDispatchMode modes[PAL_MAX_EVENTS]; + PalDispatchMode modes[MAX_EVENTS]; }; -static void PAL_CALL defaultPush( - void* queue, - PalEvent* event) -{ - PalEventQueue* eventQueue = queue; - QueueData* data = eventQueue->userData; - data->data[data->tail++ % PAL_MAX_EVENTS] = *event; -} - -static PalBool PAL_CALL defaultPoll( - void* queue, - PalEvent* outEvent) -{ - PalEventQueue* eventQueue = queue; - QueueData* data = eventQueue->userData; - if (data->head == data->tail) { - return false; - } - - *outEvent = data->data[data->head++ % PAL_MAX_EVENTS]; - return true; -} - PalResult PAL_CALL palCreateEventDriver( const PalEventDriverCreateInfo* info, PalEventDriver** outEventDriver) { if (!info || !outEventDriver) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PLATFORM_SOURCE, + getLastErrorCode()); } if (info->allocator) { if (!info->allocator->allocate && !info->allocator->free) { - return PAL_RESULT_INVALID_ALLOCATOR; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PLATFORM_SOURCE, + getLastErrorCode()); } } PalEventDriver* driver = nullptr; driver = palAllocate(info->allocator, sizeof(PalEventDriver), 0); if (!driver) { - return PAL_RESULT_OUT_OF_MEMORY; + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PLATFORM_SOURCE, + getLastErrorCode()); } memset(driver, 0, sizeof(PalEventDriver)); @@ -76,33 +74,21 @@ PalResult PAL_CALL palCreateEventDriver( if (info->queue) { // user supplied an event queue driver->queue = info->queue; - driver->freeQueue = false; + driver->freeQueue = PAL_FALSE; } else { // we create a default event queue - PalEventQueue* queue = nullptr; - queue = palAllocate(info->allocator, sizeof(PalEventQueue), 0); + PalEventQueue* queue = createDefaultEventQueue(info->allocator); if (!queue) { palFree(info->allocator, driver); - return PAL_RESULT_OUT_OF_MEMORY; + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PLATFORM_SOURCE, + getLastErrorCode()); } - // we create a default event queue data - QueueData* queueData = nullptr; - queueData = palAllocate(info->allocator, sizeof(QueueData), 0); - if (!queueData) { - palFree(info->allocator, queue); - palFree(info->allocator, driver); - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(queueData, 0, sizeof(QueueData)); - queue->userData = queueData; - queue->poll = defaultPoll; - queue->push = defaultPush; - driver->queue = queue; - driver->freeQueue = true; + driver->freeQueue = PAL_TRUE; } driver->callback = info->callback; @@ -119,8 +105,7 @@ void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver) const PalAllocator* allocator = eventDriver->allocator; if (eventDriver->freeQueue) { - palFree(allocator, eventDriver->queue->userData); - palFree(allocator, eventDriver->queue); + destroyDefaultEventQueue(allocator, eventDriver->queue); } palFree(allocator, eventDriver); } @@ -172,7 +157,7 @@ PalBool PAL_CALL palPollEvent( PalEvent* outEvent) { if (!eventDriver || !outEvent) { - return false; + return PAL_FALSE; } return eventDriver->queue->poll(eventDriver->queue, outEvent); diff --git a/src/pal_shared.h b/src/pal_shared.h new file mode 100644 index 00000000..6ada50c2 --- /dev/null +++ b/src/pal_shared.h @@ -0,0 +1,26 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_SHARED_H +#define _PAL_SHARED_H + +#include "pal/pal_core.h" + +#define PAL_RESULT_SOURCE_WINDOWS 100 +#define PAL_RESULT_SOURCE_LINUX 101 +#define PAL_RESULT_SOURCE_VULKAN 102 +#define PAL_RESULT_SOURCE_D3D12 103 + +static inline PalResult palMakeResult( + uint16_t code, + uint16_t source, + uint32_t nativeCode) +{ + return ((uint64_t)nativeCode << 32) | ((uint64_t)source << 16) | (uint64_t)code; +} + +#endif // _PAL_SHARED_H \ No newline at end of file diff --git a/tests/event/event_test.c b/tests/event/event_test.c index 8425fd6e..75b82597 100644 --- a/tests/event/event_test.c +++ b/tests/event/event_test.c @@ -28,7 +28,7 @@ static void PAL_CALL onEvent( s_CallbackCounter++; } -static inline void eventDispatchTest(PalBool poll) +static inline PalBool eventDispatchTest(PalBool poll) { PalResult result; PalEventDriver* driver = nullptr; @@ -37,9 +37,8 @@ static inline void eventDispatchTest(PalBool poll) result = palCreateEventDriver(&createInfo, &driver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // set dispatch mode @@ -74,6 +73,7 @@ static inline void eventDispatchTest(PalBool poll) } palDestroyEventDriver(driver); + return PAL_TRUE; } PalBool eventTest() @@ -87,7 +87,10 @@ PalBool eventTest() double startTime = getTime(&timer); for (int32_t i = 0; i < MAX_ITERATIONS; i++) { - eventDispatchTest(false); // callback mode first + PalBool success = eventDispatchTest(PAL_FALSE); // callback mode + if (success == PAL_FALSE) { + return PAL_FALSE; + } } // get end time @@ -107,7 +110,10 @@ PalBool eventTest() startTime = getTime(&timer); for (int32_t i = 0; i < MAX_ITERATIONS; i++) { - eventDispatchTest(true); // poll mode first + PalBool success = eventDispatchTest(PAL_TRUE); // poll mode + if (success == PAL_FALSE) { + return PAL_FALSE; + } } // get end time @@ -128,5 +134,5 @@ PalBool eventTest() // how many times poll event was called palLog(nullptr, "Poll counter: %d", s_PollCounter); - return true; + return PAL_TRUE; } diff --git a/tests/event/user_event_test.c b/tests/event/user_event_test.c index a15fb7e7..c03f80bd 100644 --- a/tests/event/user_event_test.c +++ b/tests/event/user_event_test.c @@ -23,7 +23,7 @@ PalBool userEventTest() PalResult result; PalEventDriver* eventDriver = nullptr; PalEventDriverCreateInfo createInfo; - PalBool running, logged = false; + PalBool running, logged = PAL_FALSE; // fill the event driver create info createInfo.allocator = nullptr; // default allocator @@ -34,9 +34,8 @@ PalBool userEventTest() // create the event driver result = palCreateEventDriver(&createInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } palSetEventDispatchMode(eventDriver, PAL_EVENT_USER, PAL_DISPATCH_POLL); @@ -49,7 +48,7 @@ PalBool userEventTest() // get the start time normalize by timer.startTime double lastTime = getTime(&timer); - running = true; + running = PAL_TRUE; while (running) { PalEvent event; while (palPollEvent(eventDriver, &event)) { @@ -62,14 +61,14 @@ PalBool userEventTest() // log a message if (!logged) { palLog(nullptr, "5 seconds have passed"); - logged = true; + logged = PAL_TRUE; } break; } case USER_CLOSE_EVENT_ID: { palLog(nullptr, "10 seconds have passed"); - running = false; + running = PAL_FALSE; break; } } @@ -101,5 +100,5 @@ PalBool userEventTest() // destroy the event driver palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/tests.h b/tests/tests.h index 04de34a3..03e79cc4 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -37,6 +37,13 @@ static PalBool readFile( return PAL_TRUE; } +static inline void logResult(PalResult result, const char* msg) +{ + char buffer[256]; + palFormatResult(result, 256, buffer); + palLog(nullptr, "%s \n %s", msg, buffer); +} + // core tests PalBool loggerTest(); PalBool timeTest(); diff --git a/tests/tests.lua b/tests/tests.lua index a99e21a5..13e1dc8c 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -15,8 +15,8 @@ project "tests" "core/time_test.c", -- event - -- "event/user_event_test.c", - -- "event/event_test.c" + "event/user_event_test.c", + "event/event_test.c" } if (PAL_BUILD_SYSTEM_MODULE) then diff --git a/tests/tests_main.c b/tests/tests_main.c index 09a3ca92..a998f82c 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -8,12 +8,12 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - registerTest(loggerTest, "Logger Test"); - registerTest(timeTest, "Time Test"); + // registerTest(loggerTest, "Logger Test"); + // registerTest(timeTest, "Time Test"); // event - // registerTest(eventTest, "Event test"); - // registerTest(userEventTest, "User Event Test"); + registerTest(eventTest, "Event test"); + registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE // registerTest(systemTest, "System Test"); From d44d37a1e8c9a61926344784c4fcf63a271fcbc2 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Jun 2026 09:44:24 +0000 Subject: [PATCH 261/372] test core and event system rewrite win32 --- src/core/win32/pal_log_win32.c | 8 ++++---- src/core/win32/pal_memory_win32.c | 2 +- src/core/win32/pal_result_win32.c | 16 +++++++++++++++- src/core/win32/pal_time_win32.c | 4 ++-- src/event/pal_event.c | 17 ++++++++++++++--- tests/tests_main.c | 4 ++-- 6 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/core/win32/pal_log_win32.c b/src/core/win32/pal_log_win32.c index 7525d7ca..1ffa322b 100644 --- a/src/core/win32/pal_log_win32.c +++ b/src/core/win32/pal_log_win32.c @@ -53,7 +53,7 @@ void PAL_CALL palLog( LogTLSData* data = FlsGetValue((DWORD)s_TlsID); if (!data) { - data = palAllocate(nullptr, sizeof(LogTLSData),0); + data = palAllocate(nullptr, sizeof(LogTLSData), 0); memset(data, 0, sizeof(LogTLSData)); // create TLS if it has not been created @@ -83,8 +83,8 @@ void PAL_CALL palLog( } // update the tls to stop recursive calls - memcpy(data->buffer, data->tmp, PAL_LOG_MSG_SIZE); - data->isLogging = true; + memcpy(data->buffer, data->tmp, MSG_SIZE); + data->isLogging = PAL_TRUE; FlsSetValue(s_TlsID, data); logger->callback(logger->userData, data->buffer); @@ -107,7 +107,7 @@ void PAL_CALL palLog( } } - data->isLogging = false; + data->isLogging = PAL_FALSE; FlsSetValue(s_TlsID, data); } diff --git a/src/core/win32/pal_memory_win32.c b/src/core/win32/pal_memory_win32.c index 995fc05d..363274fa 100644 --- a/src/core/win32/pal_memory_win32.c +++ b/src/core/win32/pal_memory_win32.c @@ -30,7 +30,7 @@ void* PAL_CALL palAllocate( return allocator->allocate(allocator->userData, size, align); } - return _aligned_malloc(size, alignment); + return _aligned_malloc(size, align); } void PAL_CALL palFree( diff --git a/src/core/win32/pal_result_win32.c b/src/core/win32/pal_result_win32.c index 3977c20e..5935d148 100644 --- a/src/core/win32/pal_result_win32.c +++ b/src/core/win32/pal_result_win32.c @@ -6,9 +6,23 @@ */ #ifdef _WIN32 -#include "pal_format.h" +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE + +#include "core/pal_format.h" #include "core/pal_result_common.h" #include +#include uint16_t PAL_CALL palGetResultCode(PalResult result) { diff --git a/src/core/win32/pal_time_win32.c b/src/core/win32/pal_time_win32.c index ce5c65cd..c6a5a1ce 100644 --- a/src/core/win32/pal_time_win32.c +++ b/src/core/win32/pal_time_win32.c @@ -5,8 +5,6 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal/pal_core.h" - #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN @@ -20,6 +18,8 @@ #ifndef UNICODE #define UNICODE #endif // UNICODE + +#include "pal/pal_core.h" #include uint64_t PAL_CALL palGetPerformanceCounter() diff --git a/src/event/pal_event.c b/src/event/pal_event.c index 1c78e6eb..84afd588 100644 --- a/src/event/pal_event.c +++ b/src/event/pal_event.c @@ -10,10 +10,21 @@ #include #ifdef _WIN32 -#define PLATFORM_SOURCE PAL_RESULT_SOURCE_WINDOWS +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX -uint32_t __stdcall GetLastError(); +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE +#include +#define PLATFORM_SOURCE PAL_RESULT_SOURCE_WINDOWS #elif defined(__linux__) #include #define PLATFORM_SOURCE PAL_RESULT_SOURCE_LINUX @@ -22,7 +33,7 @@ uint32_t __stdcall GetLastError(); static inline uint32_t getLastErrorCode() { #ifdef _WIN32 - return GetLastError(); + return (uint32_t)GetLastError(); #elif defined(__linux__) return (uint32_t)errno; #endif // _WIN32 diff --git a/tests/tests_main.c b/tests/tests_main.c index a998f82c..10f0e69b 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -8,8 +8,8 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - // registerTest(loggerTest, "Logger Test"); - // registerTest(timeTest, "Time Test"); + registerTest(loggerTest, "Logger Test"); + registerTest(timeTest, "Time Test"); // event registerTest(eventTest, "Event test"); From dc32ba913eaa7eb019317dc79668ce8a51b71dda Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Jun 2026 12:40:42 +0000 Subject: [PATCH 262/372] add abi dump tool for abi inspection --- pal.lua | 2 -- pal_config.lua | 3 +++ premake5.lua | 16 ++++++----- tests/tests.lua | 2 +- tools/abi_dump/abi_dump.lua | 18 +++++++++++++ tools/abi_dump/abi_dump_main.c | 49 ++++++++++++++++++++++++++++++++++ tools/abi_dump/core_abi_dump.c | 36 +++++++++++++++++++++++++ tools/abi_dump/dumps.h | 15 +++++++++++ 8 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 tools/abi_dump/abi_dump.lua create mode 100644 tools/abi_dump/abi_dump_main.c create mode 100644 tools/abi_dump/core_abi_dump.c create mode 100644 tools/abi_dump/dumps.h diff --git a/pal.lua b/pal.lua index 3ea17e36..f6a4af0e 100644 --- a/pal.lua +++ b/pal.lua @@ -2,8 +2,6 @@ dofile("pal_config.lua") project "PAL" - language "C" - if PAL_BUILD_STATIC_LIBRARY then kind "StaticLib" else diff --git a/pal_config.lua b/pal_config.lua index 04037df9..78d521da 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -5,6 +5,9 @@ PAL_BUILD_STATIC_LIBRARY = false -- build PAL tests as a single application PAL_BUILD_TEST_APPLICATION = true +-- build PAL abi dump +PAL_BUILD_ABI_DUMP = true + -- build system module PAL_BUILD_SYSTEM_MODULE = false diff --git a/premake5.lua b/premake5.lua index 7e6cd6ed..73732541 100644 --- a/premake5.lua +++ b/premake5.lua @@ -276,6 +276,8 @@ newoption { workspace(workspaceName) if PAL_BUILD_TEST_APPLICATION then startproject("tests") + else + startproject("pal-abi-dump") end if PAL_BUILD_STATIC_LIBRARY then @@ -285,16 +287,14 @@ workspace(workspaceName) end multiprocessorcompile "On" + cdialect "C99" + architecture "x64" + language "C" + configurations { "Debug", "Release" } filter {"system:windows", "configurations:*"} - architecture "x64" systemversion "latest" - cdialect "C99" - - filter {"system:linux", "configurations:*"} - architecture "x86_64" - cdialect "C99" filter "configurations:Debug" symbols "on" @@ -409,4 +409,8 @@ workspace(workspaceName) include "tests/tests.lua" end + if (PAL_BUILD_ABI_DUMP) then + include "tools/abi_dump/abi_dump.lua" + end + include "pal.lua" \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index 13e1dc8c..789d54dd 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -1,6 +1,5 @@ project "tests" - language "C" kind "ConsoleApp" targetdir(targetDir) @@ -92,4 +91,5 @@ project "tests" "%{wks.location}/include", "%{wks.location}/tests" } + links { "PAL" } diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua new file mode 100644 index 00000000..5beb61e0 --- /dev/null +++ b/tools/abi_dump/abi_dump.lua @@ -0,0 +1,18 @@ + +project "pal-abi-dump" + kind "ConsoleApp" + + targetdir(targetDir) + objdir(objDir) + + files { + "core_abi_dump.c", + "abi_dump_main.c" + } + + includedirs { + "%{wks.location}/include", + "%{wks.location}/tools/abi_dump" + } + + links { "PAL" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c new file mode 100644 index 00000000..156387d1 --- /dev/null +++ b/tools/abi_dump/abi_dump_main.c @@ -0,0 +1,49 @@ + +#include "dumps.h" + +#define VERSION "1.0" + +#ifdef _WIN32 +#define EXE_NAME "pal-abi-dump.exe" +#else +#define EXE_NAME "pal-abi-dump" +#endif // _WIN32 + +// clang-format off +int main(int argc, char** argv) +{ + // clang-format on + PalBool dumpCore = PAL_FALSE; + PalBool dumpVersion = PAL_FALSE; + PalBool dumpHelp = PAL_FALSE; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--core") == 0) { + dumpCore = PAL_TRUE; + + } else if (strcmp(argv[i], "--version") == 0) { + dumpVersion = PAL_TRUE; + + } else if (strcmp(argv[i], "--help") == 0) { + dumpHelp = PAL_TRUE; + } + } + + if (dumpCore) { + dumpCoreABI(); + } + + if (dumpVersion) { + palLog(nullptr, "PAL ABI dump %s", VERSION); + } + + if (dumpHelp) { + palLog(nullptr, "USAGE: %s [options]", EXE_NAME); + palLog(nullptr, "Options:"); // 10 spaces + palLog(nullptr, " --help Display available options"); + palLog(nullptr, " --version Display ABI dump version information"); + palLog(nullptr, " --core Display PAL core system structs ABI information"); + } + + return 0; +} diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c new file mode 100644 index 00000000..ac569fba --- /dev/null +++ b/tools/abi_dump/core_abi_dump.c @@ -0,0 +1,36 @@ + +#include "dumps.h" + +static void palVersionDump() +{ + uint32_t size = sizeof(PalVersion); + uint32_t alignof = PAL_ALIGNOF(PalVersion); + uint32_t majorOffset = offsetof(PalVersion, major); + uint32_t minorOffset = offsetof(PalVersion, minor); + uint32_t buildOffset = offsetof(PalVersion, build); + + palLog(nullptr, "PalVersion"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "sizeof %u %u", 12, size); + palLog(nullptr, "alignof %u %u", 4, alignof); + palLog(nullptr, "major@ %u %u", 0, majorOffset); + palLog(nullptr, "minor@ %u %u", 4, minorOffset); + palLog(nullptr, "build@ %u %u", 8, buildOffset); + palLog(nullptr, ""); +} + +void dumpCoreABI() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Core System ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + palVersionDump(); + // PalAllocator + // PalLogger +} \ No newline at end of file diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h new file mode 100644 index 00000000..ceb86acb --- /dev/null +++ b/tools/abi_dump/dumps.h @@ -0,0 +1,15 @@ + +#ifndef _DUMPS_H +#define _DUMPS_H + +#include "pal/pal_core.h" + +#ifdef _MSC_VER +#define PAL_ALIGNOF(type) __alignof(type) +#else +#define PAL_ALIGNOF(type) __alignof__(type) +#endif // _MSC_VER + +void dumpCoreABI(); + +#endif // _DUMPS_H \ No newline at end of file From 6a229e432af020cd0ce971d7be6837bebcbb991c Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Jun 2026 17:45:15 +0000 Subject: [PATCH 263/372] add allocator and logger to core abi dump --- tools/abi_dump/core_abi_dump.c | 114 ++++++++++++++++++++++++++++++--- tools/abi_dump/dumps.h | 4 ++ 2 files changed, 110 insertions(+), 8 deletions(-) diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c index ac569fba..b2d4d311 100644 --- a/tools/abi_dump/core_abi_dump.c +++ b/tools/abi_dump/core_abi_dump.c @@ -3,22 +3,120 @@ static void palVersionDump() { + uint32_t expectedSize = 12; + uint32_t expectedAlignof = 4; + uint32_t expectedMajorOffset = 0; + uint32_t expectedMinorOffset = 4; + uint32_t expectedBuildOffset = 8; + uint32_t size = sizeof(PalVersion); uint32_t alignof = PAL_ALIGNOF(PalVersion); uint32_t majorOffset = offsetof(PalVersion, major); uint32_t minorOffset = offsetof(PalVersion, minor); uint32_t buildOffset = offsetof(PalVersion, build); + const char* result = s_FailedString; + // clang-format off + if (expectedSize == size && + expectedAlignof == alignof && + expectedMajorOffset == majorOffset && + expectedMinorOffset == minorOffset && + expectedBuildOffset == buildOffset) { + result = s_PassedString; + } + // clang-format on + palLog(nullptr, "PalVersion"); palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "sizeof %u %u", expectedSize, size); + palLog(nullptr, "alignof %u %u", expectedAlignof, alignof); + palLog(nullptr, "major @ %u %u", expectedMajorOffset, majorOffset); + palLog(nullptr, "minor @ %u %u", expectedMinorOffset, minorOffset); + palLog(nullptr, "build @ %u %u", expectedBuildOffset, buildOffset); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void palAllocatorDump() +{ + uint32_t expectedSize = 24; + uint32_t expectedAlignof = 8; + uint32_t expectedAllocateOffset = 0; + uint32_t expectedFreeOffset = 8; + uint32_t expectedUserDataOffset = 16; + + uint32_t size = sizeof(PalAllocator); + uint32_t alignof = PAL_ALIGNOF(PalAllocator); + uint32_t allocateOffset = offsetof(PalAllocator, allocate); + uint32_t freeOffset = offsetof(PalAllocator, free); + uint32_t userDataOffset = offsetof(PalAllocator, userData); + + const char* result = s_FailedString; + // clang-format off + if (expectedSize == size && + expectedAlignof == alignof && + expectedAllocateOffset == allocateOffset && + expectedFreeOffset == freeOffset && + expectedUserDataOffset == userDataOffset) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalAllocator"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "sizeof %u %u", expectedSize, size); + palLog(nullptr, "alignof %u %u", expectedAlignof, alignof); + palLog(nullptr, "allocate @ %u %u", expectedAllocateOffset, allocateOffset); + palLog(nullptr, "free @ %u %u", expectedFreeOffset, freeOffset); + palLog(nullptr, "userData @ %u %u", expectedUserDataOffset, userDataOffset); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void palLoggerDump() +{ + uint32_t expectedSize = 16; + uint32_t expectedAlignof = 8; + uint32_t expectedCallbackOffset = 0; + uint32_t expectedUserDataOffset = 8; + + uint32_t size = sizeof(PalLogger); + uint32_t alignof = PAL_ALIGNOF(PalLogger); + uint32_t callbackOffset = offsetof(PalLogger, callback); + uint32_t userDataOffset = offsetof(PalLogger, userData); + + const char* result = s_FailedString; + // clang-format off + if (expectedSize == size && + expectedAlignof == alignof && + expectedCallbackOffset == callbackOffset && + expectedUserDataOffset == userDataOffset) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalLogger"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "sizeof %u %u", expectedSize, size); + palLog(nullptr, "alignof %u %u", expectedAlignof, alignof); + palLog(nullptr, "allocate @ %u %u", expectedCallbackOffset, callbackOffset); + palLog(nullptr, "userData @ %u %u", expectedUserDataOffset, userDataOffset); palLog(nullptr, "==========================================="); - palLog(nullptr, "sizeof %u %u", 12, size); - palLog(nullptr, "alignof %u %u", 4, alignof); - palLog(nullptr, "major@ %u %u", 0, majorOffset); - palLog(nullptr, "minor@ %u %u", 4, minorOffset); - palLog(nullptr, "build@ %u %u", 8, buildOffset); + palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } @@ -31,6 +129,6 @@ void dumpCoreABI() palLog(nullptr, ""); palVersionDump(); - // PalAllocator - // PalLogger + palAllocatorDump(); + palLoggerDump(); } \ No newline at end of file diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index ceb86acb..062d477d 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -3,6 +3,10 @@ #define _DUMPS_H #include "pal/pal_core.h" +#include + +static const char* s_FailedString = "FAILED"; +static const char* s_PassedString = "PASSED"; #ifdef _MSC_VER #define PAL_ALIGNOF(type) __alignof(type) From 2b2259ae321a84b5b2e7697d0e4a1a9146747a0f Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Jun 2026 18:45:25 +0000 Subject: [PATCH 264/372] add event system abi dump --- include/pal/pal_event.h | 4 +- tools/abi_dump/abi_dump.lua | 1 + tools/abi_dump/abi_dump_main.c | 28 ++++++ tools/abi_dump/core_abi_dump.c | 128 +++++++++++++-------------- tools/abi_dump/dumps.h | 1 + tools/abi_dump/event_abi_dump.c | 147 ++++++++++++++++++++++++++++++++ 6 files changed, 243 insertions(+), 66 deletions(-) create mode 100644 tools/abi_dump/event_abi_dump.c diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 15e046c7..5b35927e 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -273,7 +273,7 @@ typedef uint32_t PalDecorationMode; * * @since 2.0 */ -typedef uint32_t PalEventType; +typedef uint64_t PalEventType; /** * @typedef PalDispatchMode @@ -284,7 +284,7 @@ typedef uint32_t PalEventType; * * @since 2.0 */ -typedef uint32_t PalDispatchMode; +typedef uint64_t PalDispatchMode; /** * @typedef PalEventCallback diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index 5beb61e0..8debf70a 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -7,6 +7,7 @@ project "pal-abi-dump" files { "core_abi_dump.c", + "event_abi_dump.c", "abi_dump_main.c" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 156387d1..6f5a1241 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -14,6 +14,12 @@ int main(int argc, char** argv) { // clang-format on PalBool dumpCore = PAL_FALSE; + PalBool dumpEvent = PAL_FALSE; + PalBool dumpThread = PAL_FALSE; + PalBool dumpOpengl = PAL_FALSE; + PalBool dumpGraphics = PAL_FALSE; + PalBool dumpSystem = PAL_FALSE; + PalBool dumpVideo = PAL_FALSE; PalBool dumpVersion = PAL_FALSE; PalBool dumpHelp = PAL_FALSE; @@ -21,6 +27,24 @@ int main(int argc, char** argv) if (strcmp(argv[i], "--core") == 0) { dumpCore = PAL_TRUE; + } else if (strcmp(argv[i], "--event") == 0) { + dumpEvent = PAL_TRUE; + + } else if (strcmp(argv[i], "--graphics") == 0) { + dumpGraphics = PAL_TRUE; + + } else if (strcmp(argv[i], "--opengl") == 0) { + dumpOpengl = PAL_TRUE; + + } else if (strcmp(argv[i], "--system") == 0) { + dumpSystem = PAL_TRUE; + + } else if (strcmp(argv[i], "--thread") == 0) { + dumpThread = PAL_TRUE; + + } else if (strcmp(argv[i], "--video") == 0) { + dumpVideo = PAL_TRUE; + } else if (strcmp(argv[i], "--version") == 0) { dumpVersion = PAL_TRUE; @@ -33,6 +57,10 @@ int main(int argc, char** argv) dumpCoreABI(); } + if (dumpEvent) { + dumpEventABI(); + } + if (dumpVersion) { palLog(nullptr, "PAL ABI dump %s", VERSION); } diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c index b2d4d311..9288e93d 100644 --- a/tools/abi_dump/core_abi_dump.c +++ b/tools/abi_dump/core_abi_dump.c @@ -1,27 +1,27 @@ #include "dumps.h" -static void palVersionDump() +static void versionDump() { - uint32_t expectedSize = 12; - uint32_t expectedAlignof = 4; - uint32_t expectedMajorOffset = 0; - uint32_t expectedMinorOffset = 4; - uint32_t expectedBuildOffset = 8; - - uint32_t size = sizeof(PalVersion); - uint32_t alignof = PAL_ALIGNOF(PalVersion); - uint32_t majorOffset = offsetof(PalVersion, major); - uint32_t minorOffset = offsetof(PalVersion, minor); - uint32_t buildOffset = offsetof(PalVersion, build); + uint32_t xSize = 12; + uint32_t xAlign = 4; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 4; + uint32_t xOffset3 = 8; + + uint32_t ySize = sizeof(PalVersion); + uint32_t yAlign = PAL_ALIGNOF(PalVersion); + uint32_t yOffset1 = offsetof(PalVersion, major); + uint32_t yOffset2 = offsetof(PalVersion, minor); + uint32_t yOffset3 = offsetof(PalVersion, build); const char* result = s_FailedString; // clang-format off - if (expectedSize == size && - expectedAlignof == alignof && - expectedMajorOffset == majorOffset && - expectedMinorOffset == minorOffset && - expectedBuildOffset == buildOffset) { + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3) { result = s_PassedString; } // clang-format on @@ -31,38 +31,38 @@ static void palVersionDump() palLog(nullptr, "Field Expected Actual"); palLog(nullptr, "==========================================="); - palLog(nullptr, "sizeof %u %u", expectedSize, size); - palLog(nullptr, "alignof %u %u", expectedAlignof, alignof); - palLog(nullptr, "major @ %u %u", expectedMajorOffset, majorOffset); - palLog(nullptr, "minor @ %u %u", expectedMinorOffset, minorOffset); - palLog(nullptr, "build @ %u %u", expectedBuildOffset, buildOffset); + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "major @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "minor @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "build @ %u %u", xOffset3, yOffset3); palLog(nullptr, "==========================================="); palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void palAllocatorDump() +static void allocatorDump() { - uint32_t expectedSize = 24; - uint32_t expectedAlignof = 8; - uint32_t expectedAllocateOffset = 0; - uint32_t expectedFreeOffset = 8; - uint32_t expectedUserDataOffset = 16; - - uint32_t size = sizeof(PalAllocator); - uint32_t alignof = PAL_ALIGNOF(PalAllocator); - uint32_t allocateOffset = offsetof(PalAllocator, allocate); - uint32_t freeOffset = offsetof(PalAllocator, free); - uint32_t userDataOffset = offsetof(PalAllocator, userData); + uint32_t xSize = 24; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 16; + + uint32_t ySize = sizeof(PalAllocator); + uint32_t yAlign = PAL_ALIGNOF(PalAllocator); + uint32_t yOffset1 = offsetof(PalAllocator, allocate); + uint32_t yOffset2 = offsetof(PalAllocator, free); + uint32_t yOffset3 = offsetof(PalAllocator, userData); const char* result = s_FailedString; // clang-format off - if (expectedSize == size && - expectedAlignof == alignof && - expectedAllocateOffset == allocateOffset && - expectedFreeOffset == freeOffset && - expectedUserDataOffset == userDataOffset) { + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3) { result = s_PassedString; } // clang-format on @@ -72,35 +72,35 @@ static void palAllocatorDump() palLog(nullptr, "Field Expected Actual"); palLog(nullptr, "==========================================="); - palLog(nullptr, "sizeof %u %u", expectedSize, size); - palLog(nullptr, "alignof %u %u", expectedAlignof, alignof); - palLog(nullptr, "allocate @ %u %u", expectedAllocateOffset, allocateOffset); - palLog(nullptr, "free @ %u %u", expectedFreeOffset, freeOffset); - palLog(nullptr, "userData @ %u %u", expectedUserDataOffset, userDataOffset); + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "allocate @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "free @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "userData @ %u %u", xOffset3, yOffset3); palLog(nullptr, "==========================================="); palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void palLoggerDump() +static void loggerDump() { - uint32_t expectedSize = 16; - uint32_t expectedAlignof = 8; - uint32_t expectedCallbackOffset = 0; - uint32_t expectedUserDataOffset = 8; + uint32_t xSize = 16; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; - uint32_t size = sizeof(PalLogger); - uint32_t alignof = PAL_ALIGNOF(PalLogger); - uint32_t callbackOffset = offsetof(PalLogger, callback); - uint32_t userDataOffset = offsetof(PalLogger, userData); + uint32_t ySize = sizeof(PalLogger); + uint32_t yAlign = PAL_ALIGNOF(PalLogger); + uint32_t yOffset1 = offsetof(PalLogger, callback); + uint32_t yOffset2 = offsetof(PalLogger, userData); const char* result = s_FailedString; // clang-format off - if (expectedSize == size && - expectedAlignof == alignof && - expectedCallbackOffset == callbackOffset && - expectedUserDataOffset == userDataOffset) { + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2) { result = s_PassedString; } // clang-format on @@ -110,10 +110,10 @@ static void palLoggerDump() palLog(nullptr, "Field Expected Actual"); palLog(nullptr, "==========================================="); - palLog(nullptr, "sizeof %u %u", expectedSize, size); - palLog(nullptr, "alignof %u %u", expectedAlignof, alignof); - palLog(nullptr, "allocate @ %u %u", expectedCallbackOffset, callbackOffset); - palLog(nullptr, "userData @ %u %u", expectedUserDataOffset, userDataOffset); + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "allocate @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "userData @ %u %u", xOffset2, yOffset2); palLog(nullptr, "==========================================="); palLog(nullptr, "Status: %s", result); @@ -128,7 +128,7 @@ void dumpCoreABI() palLog(nullptr, "==========================================="); palLog(nullptr, ""); - palVersionDump(); - palAllocatorDump(); - palLoggerDump(); + versionDump(); + allocatorDump(); + loggerDump(); } \ No newline at end of file diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 062d477d..db8bfea0 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -15,5 +15,6 @@ static const char* s_PassedString = "PASSED"; #endif // _MSC_VER void dumpCoreABI(); +void dumpEventABI(); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c new file mode 100644 index 00000000..340ac561 --- /dev/null +++ b/tools/abi_dump/event_abi_dump.c @@ -0,0 +1,147 @@ + +#include "dumps.h" +#include "pal/pal_event.h" + +static void eventDump() +{ + uint32_t xSize = 32; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 16; + uint32_t xOffset4 = 24; + + uint32_t ySize = sizeof(PalEvent); + uint32_t yAlign = PAL_ALIGNOF(PalEvent); + uint32_t yOffset1 = offsetof(PalEvent, userId); + uint32_t yOffset2 = offsetof(PalEvent, data); + uint32_t yOffset3 = offsetof(PalEvent, data2); + uint32_t yOffset4 = offsetof(PalEvent, type); + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalEvent"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "userId @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "data @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "data2 @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "type @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void eventQueueDump() +{ + uint32_t xSize = 24; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 16; + + uint32_t ySize = sizeof(PalEventQueue); + uint32_t yAlign = PAL_ALIGNOF(PalEventQueue); + uint32_t yOffset1 = offsetof(PalEventQueue, push); + uint32_t yOffset2 = offsetof(PalEventQueue, poll); + uint32_t yOffset3 = offsetof(PalEventQueue, userData); + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalEventQueue"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "push @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "poll @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "userData @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void eventCreateInfoDump() +{ + uint32_t xSize = 32; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 16; + uint32_t xOffset4 = 24; + + uint32_t ySize = sizeof(PalEventDriverCreateInfo); + uint32_t yAlign = PAL_ALIGNOF(PalEventDriverCreateInfo); + uint32_t yOffset1 = offsetof(PalEventDriverCreateInfo, allocator); + uint32_t yOffset2 = offsetof(PalEventDriverCreateInfo, queue); + uint32_t yOffset3 = offsetof(PalEventDriverCreateInfo, callback); + uint32_t yOffset4 = offsetof(PalEventDriverCreateInfo, userData); + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalEventDriverCreateInfo"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "allocator @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "queue @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "callback @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "userData @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +void dumpEventABI() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Event System ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + eventDump(); + eventQueueDump(); + eventCreateInfoDump(); +} \ No newline at end of file From 6a1034f504b14083fa1ad705315cc569720cf237 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Jun 2026 20:16:23 +0000 Subject: [PATCH 265/372] test thread system rewrite linux --- include/pal/pal_core.h | 1 + include/pal/pal_thread.h | 592 +++++++++++++++++- include/pal/thread/condvar.h | 136 ---- include/pal/thread/mutex.h | 94 --- include/pal/thread/thread.h | 343 ---------- include/pal/thread/tls.h | 101 --- pal.lua | 16 +- pal_config.lua | 2 +- .../pal_condvar_linux.c} | 66 +- .../pal_mutex_linux.c} | 31 +- src/thread/linux/pal_thread_common_linux.h | 29 + .../pal_thread_linux.c} | 93 ++- .../pal_tls_linux.c} | 7 +- src/thread/pal_thread_win32.c | 575 ----------------- src/thread/win32/pal_condvar_win32.c | 128 ++++ src/thread/win32/pal_mutex_win32.c | 68 ++ src/thread/win32/pal_thread_common_win32.h | 39 ++ src/thread/win32/pal_thread_win32.c | 417 ++++++++++++ src/thread/win32/pal_tls_win32.c | 51 ++ tests/tests_main.c | 16 +- tests/thread/condvar_test.c | 27 +- tests/thread/mutex_test.c | 16 +- tests/thread/thread_test.c | 14 +- tests/thread/tls_test.c | 13 +- 24 files changed, 1500 insertions(+), 1375 deletions(-) delete mode 100644 include/pal/thread/condvar.h delete mode 100644 include/pal/thread/mutex.h delete mode 100644 include/pal/thread/thread.h delete mode 100644 include/pal/thread/tls.h rename src/thread/{pal_condvar_posix.c => linux/pal_condvar_linux.c} (62%) rename src/thread/{pal_mutex_posix.c => linux/pal_mutex_linux.c} (65%) create mode 100644 src/thread/linux/pal_thread_common_linux.h rename src/thread/{pal_thread_posix.c => linux/pal_thread_linux.c} (71%) rename src/thread/{pal_tls_posix.c => linux/pal_tls_linux.c} (90%) delete mode 100644 src/thread/pal_thread_win32.c create mode 100644 src/thread/win32/pal_condvar_win32.c create mode 100644 src/thread/win32/pal_mutex_win32.c create mode 100644 src/thread/win32/pal_thread_common_win32.h create mode 100644 src/thread/win32/pal_thread_win32.c create mode 100644 src/thread/win32/pal_tls_win32.c diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index ea1d9e7e..76cd875d 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -7,6 +7,7 @@ /** * @defgroup pal_core Core + * @ingroup pal_core * @{ */ diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index a8d0dd68..c011f5ce 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -6,17 +6,599 @@ */ /** - * @defgroup pal_thread Thread System + * @defgroup pal_thread Thread + * @ingroup pal_thread * @{ */ #ifndef _PAL_THREAD_H #define _PAL_THREAD_H -#include "thread/condvar.h" -#include "thread/mutex.h" -#include "thread/thread.h" -#include "thread/tls.h" +#include "pal_core.h" + +#define PAL_THREAD_FEATURE_STACK_SIZE (1ULL << 0) +#define PAL_THREAD_FEATURE_PRIORITY (1ULL << 1) +#define PAL_THREAD_FEATURE_AFFINITY (1ULL << 2) +#define PAL_THREAD_FEATURE_NAME (1ULL << 3) + +#define PAL_THREAD_PRIORITY_LOW 0 +#define PAL_THREAD_PRIORITY_NORMAL 1 +#define PAL_THREAD_PRIORITY_HIGH 2 + +/** + * @struct PalThread + * @brief Opaque handle to a thread. + * + * @since 1.0 + */ +typedef struct PalThread PalThread; + +/** + * @typedef PalTLSId + * @brief Opaque handle to a Thread Local Storage. + * + * @since 1.0 + */ +typedef uint32_t PalTLSId; + +/** + * @struct PalMutex + * @brief Opaque handle to a mutex. + * + * @since 1.0 + */ +typedef struct PalMutex PalMutex; + +/** + * @struct PalCondVar + * @brief Opaque handle to a condition variable. + * + * @since 1.0 + */ +typedef struct PalCondVar PalCondVar; + +/** + * @typedef PalThreadFeatures + * @brief Thread system features. + * + * All thread features follow the format `PAL_THREAD_FEATURE_**` for + * consistency and API use. + * + * @since 2.0 + */ +typedef uint64_t PalThreadFeatures; + +/** + * @typedef PalThreadPriority + * @brief Thread priority types. This is not a bitmask enum. + * + * All thread priority types follow the format `PAL_THREAD_PRIORITY_**` for + * consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalThreadPriority; + +/** + * @typedef PalThreadFn + * @brief Function pointer type used for thread entry function. + * + * @param[in] arg Optional pointer to user data. Can be nullptr. + * + * @return The return value of the thread as a pointer. + * + * @since 1.0 + */ +typedef void* (*PalThreadFn)(void* arg); + +/** + * @typedef PaTlsDestructorFn + * @brief Function pointer type used for TLS. + * + * This is called when the TLS is destroyed and its value is not nullptr. + * + * @param[in] userData Optional pointer to user data. Can be nullptr. + * + * @since 1.0 + */ +typedef void (*PaTlsDestructorFn)(void* userData); + +/** + * @struct PalThreadCreateInfo + * @brief Creation parameters for a thread. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 1.0 + */ +typedef struct { + uint64_t stackSize; /**< Set to 0 to use default*/ + const PalAllocator* allocator; /**< Set to nullptr to use default.*/ + PalThreadFn entry; /**< Thread entry function*/ + void* arg; /**< Optional user-provided data. Can be nullptr.*/ +} PalThreadCreateInfo; + +/** + * @brief Create a new thread. + * + * The allocator field in the provided PalThreadCreateInfo struct will not + * be copied, therefore the pointer must remain valid until the win is + * detached. Detach the thread with palDetachThread() when no + * longer needed. + * + * The created thread starts executing from the entry function. The thread runs + * until the entry function has finished executing or its detached. + * + * @param[in] info Pointer to a PalThreadCreateInfo struct that specifies + * parameters. Must not be nullptr. + * @param[out] outThread Pointer to a PalThread to recieve the created + * thread. Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if the provided allocator is + * thread safe and `outThread` is per thread. The default allocator is + * thread safe. + * + * @since 1.0 + * @sa palDetachThread + */ +PAL_API PalResult PAL_CALL palCreateThread( + const PalThreadCreateInfo* info, + PalThread** outThread); + +/** + * @brief Wait for the provided thread to finish executing. + * + * After the thread is done executing, it is freed automatically and + * must not be used anymore nor detached. + * + * @param[in] thread Pointer to the thread. + * @param[out] retval Optionally pointer to get the threads exit value. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if `retval` is per thread. + * + * @since 2.0 + */ +PAL_API PalResult PAL_CALL palJoinThread( + PalThread* thread, + void** retval); + +/** + * @brief Release the thread's resources and destroy it. + * + * Must be called when the thread is done executing. + * After this call, the thread cannot be attached or used anymore. + * If the thread is invalid or nullptr, this function returns silently. + * + * This must not be called on a thread that has been attached. + * + * @param[in] thread Pointer to the thread to detach. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API void PAL_CALL palDetachThread(PalThread* thread); + +/** + * @brief Suspend the calling thread for the provided duration of milliseconds. + * + * @param[in] milliseconds Number of milliseconds to sleep. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API void PAL_CALL palSleep(uint64_t milliseconds); + +/** + * @brief Yield the remainder of the calling threads time sliced, + * allowing other threads of equal priority to run. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API void PAL_CALL palYield(); + +/** + * @brief Get the current executing thread. + * + * @return The current thread on success or nullptr on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API PalThread* PAL_CALL palGetCurrentThread(); + +/** + * @brief Get the supported features of PAL thread system. + * + * This is based on the platform (OS) features not a single created thread. + * + * @return The thread features on success or 0 on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API PalThreadFeatures PAL_CALL palGetThreadFeatures(); + +/** + * @brief Get the priority of the provided thread. + * + * `PAL_THREAD_FEATURE_PRIORITY` must be supported. + * + * @param[in] thread The thread to query priority for. + * + * @return The thread priority on success or 0 on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread); + +/** + * @brief Get the affinity of the provided thread. + * + * `PAL_THREAD_FEATURE_AFFINITY` must be supported. Thread affinity is the + * number of CPU cores the thread is allowed to be executed on. + * + * @param[in] thread The thread to query affinity for. + * + * @return The thread affinity on success or 0 on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread); + +/** + * @brief Get the name of the provided thread. + * + * `PAL_THREAD_FEATURE_NAME` must be supported. + * fails. Set the buffer to nullptr to get the size of the thread name in bytes. + * + * If the size of the provided buffer is less than the actual size of thread + * name, PAL will write upto that limit. + * + * + * @param[in] thread The thread to query its name. + * @param[in] bufferSize Size of the provided buffer in bytes. + * @param[out] outSize The actual size of the thread name in bytes. + * @param[out] outBuffer Pointer to a user provided buffer to recieve the name. + * Can be nullptr. + * + * Thread safety: Thread safe. + * + * @note On Linux: Thread names are limited to 16 characters including the null + * terminator. + * + * @note On MacOS: Thread names are limited to 64 characters including the null + * terminator. + * + * @since 1.0 + * @sa palSetThreadName + */ +PAL_API PalResult PAL_CALL palGetThreadName( + PalThread* thread, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer); + +/** + * @brief Set the priority of the provided thread. + * + * `PAL_THREAD_FEATURE_PRIORITY` must be supported. + * + * @param[in] thread The thread to set priority for. + * @param[in] priority The new thread priority. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * @return + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API PalResult PAL_CALL palSetThreadPriority( + PalThread* thread, + PalThreadPriority priority); + +/** + * @brief Set the affinity of the provided thread. + * + * `PAL_THREAD_FEATURE_AFFINITY` must be supported. + * Thread affinity is the number of CPU cores the thread is allowed to be + * executed on. + * + * To be safe, get the number of CPU cores and use that to build the CPU mask. + * Example: we set a thread to the first and second CPU core. + * + * @code + * uint64_t cpuMask = (1ULL << 0) | (1ULL << 1). + * @endcode + * + * @param[in] thread The thread to set affinity for. + * @param[in] mask The CPU core mask. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe. + * + * @since 1.0 + */ +PAL_API PalResult PAL_CALL palSetThreadAffinity( + PalThread* thread, + uint64_t mask); + +/** + * @brief Set the name of the provided thread. + * + * `PAL_THREAD_FEATURE_NAME` must be supported. + * The thread name will be visible in debuggers and the Task Manager (Windows). + * + * @param[in] thread The thread + * @param[in] name UTF-8 null terminated string. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe. + * + * @note On Linux: Thread names are limited to 16 characters including the null + * terminator. + * + * @note On MacOS: Thread names are limited to 64 characters including the null + * terminator. + * + * @since 1.0 + * @sa palGetThreadName + */ +PAL_API PalResult PAL_CALL palSetThreadName( + PalThread* thread, + const char* name); + +/** + * @brief Create a new TLS. + * + * The TLS handle can be used by multiple threads to associate thread local + * vaules. The destructor will be called if palDestroyTLS() is called and + * the TLS has a valid value. + * + * @param[in] destructor Pointer to the TLS destructor function. Can be + * nullptr. + * + * @return The TLS on success or 0 on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palDestroyTLS + */ +PAL_API PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor); + +/** + * @brief Destroy the provided TLS. + * + * @param[in] id The TLS to destroy. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palCreateTL + */ +PAL_API void PAL_CALL palDestroyTLS(PalTLSId id); + +/** + * @brief Get the value associated with the provided TLS on the calling thread. + * + * @param[in] id The TLS to query value. + * + * @return the value on success or nullptr on failure. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palSetTLS + */ +PAL_API void* PAL_CALL palGetTLS(PalTLSId id); + +/** + * @brief Set a value associated with the provided TLS on the calling thread. + * + * @param[in] id The TLS to set value to. + * @param[in] data The value to set for the calling thread + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palGetTLS + */ +PAL_API void PAL_CALL palSetTLS( + PalTLSId id, + void* data); + +/** + * @brief Create a mutex. + * + * @param[in] allocator Optional user-provided allocator. Set to nullptr to use + * default. + * @param[out] outMutex Pointer to a PalMutex to recieve the created mutex. + * Must not be nullptr. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if the provided allocator is + * thread safe and `outMutex` is per thread. + * + * @since 1.0 + * @sa palDestroyMutex + */ +PAL_API PalResult PAL_CALL palCreateMutex( + const PalAllocator* allocator, + PalMutex** outMutex); + +/** + * @brief Destroy a mutex + * + * If `mutex` is invalid, this function returns silently. + * The mutex must be unlocked before destroying if it was locked. + * + * @param[in] mutex Pointer to the mutex. + * + * Thread safety: Thread safe if the allocator used to create + * the mutex is thread safe and `mutex` is per thread. + * + * @since 1.0 + * @sa palCreateMutex + */ +PAL_API void PAL_CALL palDestroyMutex(PalMutex* mutex); + +/** + * @brief Lock a mutex. Blocks if the mutex is already locked by another thread. + * + * @param[in] mutex Pointer to the mutex to lock. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palUnlockMutex + */ +PAL_API void PAL_CALL palLockMutex(PalMutex* mutex); + +/** + * @brief Unlock a mutex. + * + * The function must be called by the thread that first locked the mutex. + * + * @param[in] mutex Pointer to the mutex to unlock. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palLockMutex + */ +PAL_API void PAL_CALL palUnlockMutex(PalMutex* mutex); + +/** + * @brief Create a condition variable. + * + * @param[in] allocator Optional user-provided allocator. Set to nullptr to use + * default. + * @param[out] outCondVar Pointer to a PalCondVar to recieve the created + * condition variable. + * + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. + * + * Thread safety: Thread safe if the provided allocator is + * thread safe and `outCondVar` is per thread. + * + * @since 1.0 + * @sa palDestroyCondVar + */ +PAL_API PalResult PAL_CALL palCreateCondVar( + const PalAllocator* allocator, + PalCondVar** outCondVar); + +/** + * @brief Destroy a condition variable. + * + * If the condition variable is invalid, this function returns silently. + * Threads must not wait on the condition variable or undefined + * behaviour. + * + * @param[in] condVar Pointer to the condition to destroy + * + * Thread safety: Thread safe if the allocator used to create + * the condition varibale is thread safe and `condVar` is per thread. + * + * @since 1.0 + * @sa palCreateCondVar + */ +PAL_API void PAL_CALL palDestroyCondVar(PalCondVar* condVar); + +/** + * @brief Unlock the provided mutex and wait on the condition variable. + * + * The mutex must be locked before this call. Spurious wakeups may occur, its + * best to use a loop. This waits until the condition varibale is signaled. + * + * Example: + * + * @code + * while (!ready) { palWaitCondVar(condition, mutex); } + * @endcode + * + * @param[in] condVar Pointer to the condition variable. + * @param[in] mutex Pointer to the mutex. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palWaitCondVarTimeout + */ +PAL_API PalResult PAL_CALL palWaitCondVar( + PalCondVar* condVar, + PalMutex* mutex); + +/** + * @brief Unlock the provided mutex and wait on the condition variable. + * + * The mutex must be locked before this call. Spurious wakeups may occur, its + * best to use a loop. If the condition variable is not signaled but the time to + * wait is up `PAL_RESULT_TIMEOUT` is returned. + * + * @param[in] condVar Pointer to the condition variable. + * @param[in] mutex Pointer to the mutex. + * @param[in] milliseconds Timeout in milliseconds. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palWaitCondVar + */ +PAL_API PalResult PAL_CALL palWaitCondVarTimeout( + PalCondVar* condVar, + PalMutex* mutex, + uint64_t milliseconds); + +/** + * @brief Wake a single thread waiting on the condition variable. + * + * @param[in] condVar Pointer to the condition variable. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palBroadcastCondVar + */ +PAL_API void PAL_CALL palSignalCondVar(PalCondVar* condVar); + +/** + * @brief Wake all threads waiting on the condition variable. + * + * @param[in] condVar Pointer to the condition variable. + * + * Thread safety: Thread safe. + * + * @since 1.0 + * @sa palSignalCondVar + */ +PAL_API void PAL_CALL palBroadcastCondVar(PalCondVar* condVar); /** @} */ diff --git a/include/pal/thread/condvar.h b/include/pal/thread/condvar.h deleted file mode 100644 index 34ccef12..00000000 --- a/include/pal/thread/condvar.h +++ /dev/null @@ -1,136 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup thread Condition variable section - * @ingroup pal_thread - * @{ - */ - -#ifndef _THREAD_CONDVAR_H -#define _THREAD_CONDVAR_H - -#include "mutex.h" - -/** - * @struct PalCondVar - * @brief Opaque handle to a condition variable. - * - * @since 1.0 - */ -typedef struct PalCondVar PalCondVar; - -/** - * @brief Create a condition variable. - * - * @param[in] allocator Optional user-provided allocator. Set to nullptr to use - * default. - * @param[out] outCondVar Pointer to a PalCondVar to recieve the created - * condition variable. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if the provided allocator is - * thread safe and `outCondVar` is per thread. - * - * @since 1.0 - * @sa palDestroyCondVar - */ -PAL_API PalResult PAL_CALL palCreateCondVar( - const PalAllocator* allocator, - PalCondVar** outCondVar); - -/** - * @brief Destroy a condition variable. - * - * If the condition variable is invalid, this function returns silently. - * Threads must not wait on the condition variable or undefined - * behaviour. - * - * @param[in] condVar Pointer to the condition to destroy - * - * Thread safety: Thread safe if the allocator used to create - * the condition varibale is thread safe and `condVar` is per thread. - * - * @since 1.0 - * @sa palCreateCondVar - */ -PAL_API void PAL_CALL palDestroyCondVar(PalCondVar* condVar); - -/** - * @brief Unlock the provided mutex and wait on the condition variable. - * - * The mutex must be locked before this call. Spurious wakeups may occur, its - * best to use a loop. This waits until the condition varibale is signaled. - * - * Example: - * - * @code - * while (!ready) { palWaitCondVar(condition, mutex); } - * @endcode - * - * @param[in] condVar Pointer to the condition variable. - * @param[in] mutex Pointer to the mutex. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palWaitCondVarTimeout - */ -PAL_API PalResult PAL_CALL palWaitCondVar( - PalCondVar* condVar, - PalMutex* mutex); - -/** - * @brief Unlock the provided mutex and wait on the condition variable. - * - * The mutex must be locked before this call. Spurious wakeups may occur, its - * best to use a loop. If the condition variable is not signaled but the time to - * wait is up `PAL_RESULT_TIMEOUT` is returned. - * - * @param[in] condVar Pointer to the condition variable. - * @param[in] mutex Pointer to the mutex. - * @param[in] milliseconds Timeout in milliseconds. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palWaitCondVar - */ -PAL_API PalResult PAL_CALL palWaitCondVarTimeout( - PalCondVar* condVar, - PalMutex* mutex, - uint64_t milliseconds); - -/** - * @brief Wake a single thread waiting on the condition variable. - * - * @param[in] condVar Pointer to the condition variable. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palBroadcastCondVar - */ -PAL_API void PAL_CALL palSignalCondVar(PalCondVar* condVar); - -/** - * @brief Wake all threads waiting on the condition variable. - * - * @param[in] condVar Pointer to the condition variable. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palSignalCondVar - */ -PAL_API void PAL_CALL palBroadcastCondVar(PalCondVar* condVar); - -#endif // _THREAD_CONDVAR_H - -/** @} */ \ No newline at end of file diff --git a/include/pal/thread/mutex.h b/include/pal/thread/mutex.h deleted file mode 100644 index 53c492be..00000000 --- a/include/pal/thread/mutex.h +++ /dev/null @@ -1,94 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup thread Mutex section - * @ingroup pal_thread - * @{ - */ - -#ifndef _THREAD_MUTEX_H -#define _THREAD_MUTEX_H - -#include "pal/core/defines.h" -#include "pal/core/result.h" -#include "pal/core/memory.h" - -/** - * @struct PalMutex - * @brief Opaque handle to a mutex. - * - * @since 1.0 - */ -typedef struct PalMutex PalMutex; - -/** - * @brief Create a mutex. - * - * @param[in] allocator Optional user-provided allocator. Set to nullptr to use - * default. - * @param[out] outMutex Pointer to a PalMutex to recieve the created mutex. - * Must not be nullptr. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if the provided allocator is - * thread safe and `outMutex` is per thread. - * - * @since 1.0 - * @sa palDestroyMutex - */ -PAL_API PalResult PAL_CALL palCreateMutex( - const PalAllocator* allocator, - PalMutex** outMutex); - -/** - * @brief Destroy a mutex - * - * If `mutex` is invalid, this function returns silently. - * The mutex must be unlocked before destroying if it was locked. - * - * @param[in] mutex Pointer to the mutex. - * - * Thread safety: Thread safe if the allocator used to create - * the mutex is thread safe and `mutex` is per thread. - * - * @since 1.0 - * @sa palCreateMutex - */ -PAL_API void PAL_CALL palDestroyMutex(PalMutex* mutex); - -/** - * @brief Lock a mutex. Blocks if the mutex is already locked by another thread. - * - * @param[in] mutex Pointer to the mutex to lock. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palUnlockMutex - */ -PAL_API void PAL_CALL palLockMutex(PalMutex* mutex); - -/** - * @brief Unlock a mutex. - * - * The function must be called by the thread that first locked the mutex. - * - * @param[in] mutex Pointer to the mutex to unlock. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palLockMutex - */ -PAL_API void PAL_CALL palUnlockMutex(PalMutex* mutex); - -#endif // _THREAD_MUTEX_H - -/** @} */ \ No newline at end of file diff --git a/include/pal/thread/thread.h b/include/pal/thread/thread.h deleted file mode 100644 index 942bf1a1..00000000 --- a/include/pal/thread/thread.h +++ /dev/null @@ -1,343 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup thread Thread section - * @ingroup pal_thread - * @{ - */ - -#ifndef _THREAD_THREAD_H -#define _THREAD_THREAD_H - -#include "pal/core/defines.h" -#include "pal/core/memory.h" -#include "pal/core/result.h" - -/** - * @struct PalThread - * @brief Opaque handle to a thread. - * - * @since 1.0 - */ -typedef struct PalThread PalThread; - -/** - * @typedef PalThreadFn - * @brief Function pointer type used for thread entry function. - * - * @param[in] arg Optional pointer to user data. Can be nullptr. - * - * @return The return value of the thread as a pointer. - * - * @since 1.0 - */ -typedef void* (*PalThreadFn)(void* arg); - -/** - * @typedef PalThreadFeatures - * @brief Thread system features. - * - * All thread features follow the format `PAL_THREAD_FEATURE_**` for - * consistency and API use. - * - * @since 1.0 - */ -typedef enum { - PAL_THREAD_FEATURE_STACK_SIZE = (1ULL << 0), - PAL_THREAD_FEATURE_PRIORITY = (1ULL << 1), - PAL_THREAD_FEATURE_AFFINITY = (1ULL << 2), - PAL_THREAD_FEATURE_NAME = (1ULL << 3) -} PalThreadFeatures; - -/** - * @typedef PalThreadPriority - * @brief Thread priority types. This is not a bitmask enum. - * - * All thread priority types follow the format `PAL_THREAD_PRIORITY_**` for - * consistency and API use. - * - * @since 1.0 - */ -typedef enum { - PAL_THREAD_PRIORITY_LOW, - PAL_THREAD_PRIORITY_NORMAL, - PAL_THREAD_PRIORITY_HIGH -} PalThreadPriority; - -/** - * @struct PalThreadCreateInfo - * @brief Creation parameters for a thread. - * - * Uninitialized fields may result in undefined behavior. - * - * @since 1.0 - */ -typedef struct { - uint64_t stackSize; /**< Set to 0 to use default*/ - const PalAllocator* allocator; /**< Set to nullptr to use default.*/ - PalThreadFn entry; /**< Thread entry function*/ - void* arg; /**< Optional user-provided data. Can be nullptr.*/ -} PalThreadCreateInfo; - -/** - * @brief Create a new thread. - * - * The allocator field in the provided PalThreadCreateInfo struct will not - * be copied, therefore the pointer must remain valid until the win is - * detached. Detach the thread with palDetachThread() when no - * longer needed. - * - * The created thread starts executing from the entry function. The thread runs - * until the entry function has finished executing or its detached. - * - * @param[in] info Pointer to a PalThreadCreateInfo struct that specifies - * parameters. Must not be nullptr. - * @param[out] outThread Pointer to a PalThread to recieve the created - * thread. Must not be nullptr. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if the provided allocator is - * thread safe and `outThread` is per thread. The default allocator is - * thread safe. - * - * @since 1.0 - * @sa palDetachThread - */ -PAL_API PalResult PAL_CALL palCreateThread( - const PalThreadCreateInfo* info, - PalThread** outThread); - -/** - * @brief Wait for the provided thread to finish executing. - * - * After the thread is done executing, it is freed automatically and - * must not be used anymore nor detached. - * - * @param[in] thread Pointer to the thread. - * @param[out] retval Optionally pointer to get the threads exit value. - * Pass the address of the pointer. Internally it will be reinterpreted into a - * pointer-to-pointer. This is for ABI stability. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if `retval` is per thread. - * - * @since 1.0 - */ -PAL_API PalResult PAL_CALL palJoinThread( - PalThread* thread, - void* retval); - -/** - * @brief Release the thread's resources and destroy it. - * - * Must be called when the thread is done executing. - * After this call, the thread cannot be attached or used anymore. - * If the thread is invalid or nullptr, this function returns silently. - * - * This must not be called on a thread that has been attached. - * - * @param[in] thread Pointer to the thread to detach. - * - * Thread safety: Thread safe. - * - * @since 1.0 - */ -PAL_API void PAL_CALL palDetachThread(PalThread* thread); - -/** - * @brief Suspend the calling thread for the provided duration of milliseconds. - * - * @param[in] milliseconds Number of milliseconds to sleep. - * - * Thread safety: Thread safe. - * - * @since 1.0 - */ -PAL_API void PAL_CALL palSleep(uint64_t milliseconds); - -/** - * @brief Yield the remainder of the calling threads time sliced, - * allowing other threads of equal priority to run. - * - * Thread safety: Thread safe. - * - * @since 1.0 - */ -PAL_API void PAL_CALL palYield(); - -/** - * @brief Get the current executing thread. - * - * @return The current thread on success or nullptr on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - */ -PAL_API PalThread* PAL_CALL palGetCurrentThread(); - -/** - * @brief Get the supported features of PAL thread system. - * - * This is based on the platform (OS) features not a single created thread. - * - * @return The thread features on success or 0 on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - */ -PAL_API PalThreadFeatures PAL_CALL palGetThreadFeatures(); - -/** - * @brief Get the priority of the provided thread. - * - * `PAL_THREAD_FEATURE_PRIORITY` must be supported. - * - * @param[in] thread The thread to query priority for. - * - * @return The thread priority on success or 0 on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - */ -PAL_API PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread); - -/** - * @brief Get the affinity of the provided thread. - * - * `PAL_THREAD_FEATURE_AFFINITY` must be supported. Thread affinity is the - * number of CPU cores the thread is allowed to be executed on. - * - * @param[in] thread The thread to query affinity for. - * - * @return The thread affinity on success or 0 on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - */ -PAL_API uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread); - -/** - * @brief Get the name of the provided thread. - * - * `PAL_THREAD_FEATURE_NAME` must be supported. - * fails. Set the buffer to nullptr to get the size of the thread name in bytes. - * - * If the size of the provided buffer is less than the actual size of thread - * name, PAL will write upto that limit. - * - * - * @param[in] thread The thread to query its name. - * @param[in] bufferSize Size of the provided buffer in bytes. - * @param[out] outSize The actual size of the thread name in bytes. - * @param[out] outBuffer Pointer to a user provided buffer to recieve the name. - * Can be nullptr. - * - * Thread safety: Thread safe. - * - * @note On Linux: Thread names are limited to 16 characters including the null - * terminator. - * - * @note On MacOS: Thread names are limited to 64 characters including the null - * terminator. - * - * @since 1.0 - * @sa palSetThreadName - */ -PAL_API PalResult PAL_CALL palGetThreadName( - PalThread* thread, - uint64_t bufferSize, - uint64_t* outSize, - char* outBuffer); - -/** - * @brief Set the priority of the provided thread. - * - * `PAL_THREAD_FEATURE_PRIORITY` must be supported. - * - * @param[in] thread The thread to set priority for. - * @param[in] priority The new thread priority. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * @return - * - * Thread safety: Thread safe. - * - * @since 1.0 - */ -PAL_API PalResult PAL_CALL palSetThreadPriority( - PalThread* thread, - PalThreadPriority priority); - -/** - * @brief Set the affinity of the provided thread. - * - * `PAL_THREAD_FEATURE_AFFINITY` must be supported. - * Thread affinity is the number of CPU cores the thread is allowed to be - * executed on. - * - * To be safe, get the number of CPU cores and use that to build the CPU mask. - * Example: we set a thread to the first and second CPU core. - * - * @code - * uint64_t cpuMask = (1ULL << 0) | (1ULL << 1). - * @endcode - * - * @param[in] thread The thread to set affinity for. - * @param[in] mask The CPU core mask. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe. - * - * @since 1.0 - */ -PAL_API PalResult PAL_CALL palSetThreadAffinity( - PalThread* thread, - uint64_t mask); - -/** - * @brief Set the name of the provided thread. - * - * `PAL_THREAD_FEATURE_NAME` must be supported. - * The thread name will be visible in debuggers and the Task Manager (Windows). - * - * @param[in] thread The thread - * @param[in] name UTF-8 null terminated string. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe. - * - * @note On Linux: Thread names are limited to 16 characters including the null - * terminator. - * - * @note On MacOS: Thread names are limited to 64 characters including the null - * terminator. - * - * @since 1.0 - * @sa palGetThreadName - */ -PAL_API PalResult PAL_CALL palSetThreadName( - PalThread* thread, - const char* name); - -#endif // _THREAD_THREAD_H - -/** @} */ \ No newline at end of file diff --git a/include/pal/thread/tls.h b/include/pal/thread/tls.h deleted file mode 100644 index 9627a1ed..00000000 --- a/include/pal/thread/tls.h +++ /dev/null @@ -1,101 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -/** - * @defgroup thread TLS section - * @ingroup pal_thread - * @{ - */ - -#ifndef _THREAD_TLS_H -#define _THREAD_TLS_H - -#include "pal/core/defines.h" - -/** - * @typedef PalTLSId - * @brief Opaque handle to a Thread Local Storage. - * - * @since 1.0 - */ -typedef uint32_t PalTLSId; - -/** - * @typedef PaTlsDestructorFn - * @brief Function pointer type used for TLS. - * - * This is called when the TLS is destroyed and its value is not nullptr. - * - * @param[in] userData Optional pointer to user data. Can be nullptr. - * - * @since 1.0 - */ -typedef void (*PaTlsDestructorFn)(void* userData); - -/** - * @brief Create a new TLS. - * - * The TLS handle can be used by multiple threads to associate thread local - * vaules. The destructor will be called if palDestroyTLS() is called and - * the TLS has a valid value. - * - * @param[in] destructor Pointer to the TLS destructor function. Can be - * nullptr. - * - * @return The TLS on success or 0 on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palDestroyTLS - */ -PAL_API PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor); - -/** - * @brief Destroy the provided TLS. - * - * @param[in] id The TLS to destroy. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palCreateTL - */ -PAL_API void PAL_CALL palDestroyTLS(PalTLSId id); - -/** - * @brief Get the value associated with the provided TLS on the calling thread. - * - * @param[in] id The TLS to query value. - * - * @return the value on success or nullptr on failure. - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palSetTLS - */ -PAL_API void* PAL_CALL palGetTLS(PalTLSId id); - -/** - * @brief Set a value associated with the provided TLS on the calling thread. - * - * @param[in] id The TLS to set value to. - * @param[in] data The value to set for the calling thread - * - * Thread safety: Thread safe. - * - * @since 1.0 - * @sa palGetTLS - */ -PAL_API void PAL_CALL palSetTLS( - PalTLSId id, - void* data); - -#endif // _THREAD_TLS_H - -/** @} */ \ No newline at end of file diff --git a/pal.lua b/pal.lua index f6a4af0e..696f2e59 100644 --- a/pal.lua +++ b/pal.lua @@ -60,18 +60,18 @@ project "PAL" if (PAL_BUILD_THREAD_MODULE) then filter {"system:windows", "configurations:*"} files { - "src/thread/pal_condvar_win32.c", - "src/thread/pal_mutex_win32.c", - "src/thread/pal_tls_win32.c", - "src/thread/pal_thread_win32.c" + "src/thread/win32/pal_condvar_win32.c", + "src/thread/win32/pal_mutex_win32.c", + "src/thread/win32/pal_tls_win32.c", + "src/thread/win32/pal_thread_win32.c" } filter {"system:linux", "configurations:*"} files { - "src/thread/pal_condvar_posix.c", - "src/thread/pal_mutex_posix.c", - "src/thread/pal_tls_posix.c", - "src/thread/pal_thread_posix.c" + "src/thread/linux/pal_condvar_linux.c", + "src/thread/linux/pal_mutex_linux.c", + "src/thread/linux/pal_tls_linux.c", + "src/thread/linux/pal_thread_linux.c" } filter {} diff --git a/pal_config.lua b/pal_config.lua index 78d521da..3ab92dff 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -12,7 +12,7 @@ PAL_BUILD_ABI_DUMP = true PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD_MODULE = false +PAL_BUILD_THREAD_MODULE = true -- build video module PAL_BUILD_VIDEO_MODULE = false diff --git a/src/thread/pal_condvar_posix.c b/src/thread/linux/pal_condvar_linux.c similarity index 62% rename from src/thread/pal_condvar_posix.c rename to src/thread/linux/pal_condvar_linux.c index 5a2abd15..6ea0a1f1 100644 --- a/src/thread/pal_condvar_posix.c +++ b/src/thread/linux/pal_condvar_linux.c @@ -5,40 +5,36 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L -#include "pal/thread/condvar.h" -#include -#include -#include - -struct PalCondVar { - const PalAllocator* allocator; - pthread_cond_t handle; -}; - -struct PalMutex { - const PalAllocator* allocator; - pthread_mutex_t handle; -}; +#ifdef __linux__ +#include "pal_thread_common_linux.h" +#include "pal_shared.h" PalResult PAL_CALL palCreateCondVar( const PalAllocator* allocator, PalCondVar** outCondVar) { if (!outCondVar) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } if (allocator) { if (!allocator->allocate && !allocator->free) { - return PAL_RESULT_INVALID_ALLOCATOR; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } } PalCondVar* condVar = palAllocate(allocator, sizeof(PalCondVar), 0); if (!condVar) { - return PAL_RESULT_OUT_OF_MEMORY; + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); } pthread_cond_init(&condVar->handle, nullptr); @@ -60,16 +56,27 @@ PalResult PAL_CALL palWaitCondVar( PalMutex* mutex) { if (!condVar || !mutex) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } int ret = pthread_cond_wait(&condVar->handle, &mutex->handle); if (ret == 0) { return PAL_RESULT_SUCCESS; + } else if (ret == ETIMEDOUT) { - return PAL_RESULT_TIMEOUT; + return palMakeResult( + PAL_RESULT_TIMEOUT, + PAL_RESULT_SOURCE_LINUX, + errno); + } else { - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } } @@ -79,7 +86,10 @@ PalResult PAL_CALL palWaitCondVarTimeout( uint64_t milliseconds) { if (!condVar || !mutex) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } struct timespec ts; @@ -93,8 +103,12 @@ PalResult PAL_CALL palWaitCondVarTimeout( } if (pthread_cond_timedwait(&condVar->handle, &mutex->handle, &ts) != 0) { - return PAL_RESULT_TIMEOUT; + return palMakeResult( + PAL_RESULT_TIMEOUT, + PAL_RESULT_SOURCE_LINUX, + errno); } + return PAL_RESULT_SUCCESS; } @@ -110,4 +124,6 @@ void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) if (condVar) { pthread_cond_broadcast(&condVar->handle); } -} \ No newline at end of file +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/thread/pal_mutex_posix.c b/src/thread/linux/pal_mutex_linux.c similarity index 65% rename from src/thread/pal_mutex_posix.c rename to src/thread/linux/pal_mutex_linux.c index e8fbb9b8..8af71165 100644 --- a/src/thread/pal_mutex_posix.c +++ b/src/thread/linux/pal_mutex_linux.c @@ -5,33 +5,36 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L -#include "pal/thread/mutex.h" -#include - -struct PalMutex { - const PalAllocator* allocator; - pthread_mutex_t handle; -}; +#ifdef __linux__ +#include "pal_thread_common_linux.h" +#include "pal_shared.h" PalResult PAL_CALL palCreateMutex( const PalAllocator* allocator, PalMutex** outMutex) { if (!outMutex) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } if (allocator) { if (!allocator->allocate && !allocator->free) { - return PAL_RESULT_INVALID_ALLOCATOR; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } } PalMutex* mutex = palAllocate(allocator, sizeof(PalMutex), 0); if (!mutex) { - return PAL_RESULT_OUT_OF_MEMORY; + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); } pthread_mutex_init(&mutex->handle, nullptr); @@ -60,4 +63,6 @@ void PAL_CALL palUnlockMutex(PalMutex* mutex) if (mutex) { pthread_mutex_unlock(&mutex->handle); } -} \ No newline at end of file +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/thread/linux/pal_thread_common_linux.h b/src/thread/linux/pal_thread_common_linux.h new file mode 100644 index 00000000..64fd517a --- /dev/null +++ b/src/thread/linux/pal_thread_common_linux.h @@ -0,0 +1,29 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#ifndef _PAL_THREAD_COMMON_LINUX_H +#define _PAL_THREAD_COMMON_LINUX_H + +#define _POSIX_C_SOURCE 200112L +#include "pal/pal_thread.h" +#include +#include +#include + +struct PalCondVar { + const PalAllocator* allocator; + pthread_cond_t handle; +}; + +struct PalMutex { + const PalAllocator* allocator; + pthread_mutex_t handle; +}; + +#endif // _PAL_THREAD_COMMON_LINUX_H +#endif // __linux__ \ No newline at end of file diff --git a/src/thread/pal_thread_posix.c b/src/thread/linux/pal_thread_linux.c similarity index 71% rename from src/thread/pal_thread_posix.c rename to src/thread/linux/pal_thread_linux.c index 80a69a60..6b9d32dd 100644 --- a/src/thread/pal_thread_posix.c +++ b/src/thread/linux/pal_thread_linux.c @@ -5,13 +5,13 @@ Licensed under the Zlib license. See LICENSE file in root. */ +#ifdef __linux__ #define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L -#include "pal/thread/thread.h" -#include -#include +#include "pal_thread_common_linux.h" +#include "pal_shared.h" #include #include +#include #define TO_PAL_HANDLE(type, val) ((type*)(uintptr_t)(val)) #define FROM_PAL_HANDLE(type, handle) ((type)(uintptr_t)(handle)) @@ -21,19 +21,28 @@ PalResult PAL_CALL palCreateThread( PalThread** outThread) { if (!info || !outThread) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } if (info->allocator) { if (!info->allocator->allocate && !info->allocator->free) { - return PAL_RESULT_INVALID_ALLOCATOR; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } } pthread_t thread; if (info->stackSize == 0) { if (pthread_create(&thread, nullptr, info->entry, info->arg) != 0) { - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } } else { @@ -42,7 +51,10 @@ PalResult PAL_CALL palCreateThread( pthread_attr_setstacksize(&attr, info->stackSize); if (pthread_create(&thread, nullptr, info->entry, info->arg) != 0) { - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } pthread_attr_destroy(&attr); } @@ -53,28 +65,31 @@ PalResult PAL_CALL palCreateThread( PalResult PAL_CALL palJoinThread( PalThread* thread, - void* retval) + void** retval) { if (!thread) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } int ret = 0; - void* value = nullptr; pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); if (retval) { - ret = pthread_join(_thread, &value); - void** out = (void**)retval; - *out = value; - + ret = pthread_join(_thread, retval); } else { ret = pthread_join(_thread, nullptr); } if (ret == 0) { return PAL_RESULT_SUCCESS; + } else { - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } } @@ -166,14 +181,20 @@ PalResult PAL_CALL palGetThreadName( char* outBuffer) { if (!thread) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } // see if user provided a buffer and write to it if (outBuffer && bufferSize > 0) { pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); if (pthread_getname_np(_thread, outBuffer, bufferSize) != 0) { - return PAL_RESULT_INVALID_THREAD; + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); } } @@ -185,7 +206,10 @@ PalResult PAL_CALL palSetThreadPriority( PalThreadPriority priority) { if (!thread) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } switch (priority) { @@ -205,7 +229,10 @@ PalResult PAL_CALL palSetThreadPriority( pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); int ret = pthread_setschedparam(_thread, SCHED_FIFO, ¶m); if (ret == EPERM) { - return PAL_RESULT_ACCESS_DENIED; + return palMakeResult( + PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_SOURCE_LINUX, + errno); } } } @@ -218,7 +245,10 @@ PalResult PAL_CALL palSetThreadAffinity( uint64_t mask) { if (!thread) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } cpu_set_t cpuset; @@ -234,8 +264,12 @@ PalResult PAL_CALL palSetThreadAffinity( int ret = pthread_setaffinity_np(_thread, sizeof(cpuset), &cpuset); if (ret == 0) { return PAL_RESULT_SUCCESS; + } else { - return PAL_RESULT_INVALID_THREAD; + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); } } @@ -244,14 +278,23 @@ PalResult PAL_CALL palSetThreadName( const char* name) { if (!thread || !name) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); int ret = pthread_setname_np(_thread, name); if (ret == 0) { return PAL_RESULT_SUCCESS; + } else { - return PAL_RESULT_INVALID_THREAD; + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); } -} \ No newline at end of file +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/thread/pal_tls_posix.c b/src/thread/linux/pal_tls_linux.c similarity index 90% rename from src/thread/pal_tls_posix.c rename to src/thread/linux/pal_tls_linux.c index 7aad534e..771b5177 100644 --- a/src/thread/pal_tls_posix.c +++ b/src/thread/linux/pal_tls_linux.c @@ -5,7 +5,8 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal/thread/tls.h" +#ifdef __linux__ +#include "pal/pal_thread.h" #include PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor) @@ -32,4 +33,6 @@ void PAL_CALL palSetTLS( void* data) { pthread_setspecific((pthread_key_t)id, data); -} \ No newline at end of file +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/thread/pal_thread_win32.c b/src/thread/pal_thread_win32.c deleted file mode 100644 index 381aa3dd..00000000 --- a/src/thread/pal_thread_win32.c +++ /dev/null @@ -1,575 +0,0 @@ - -/** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - - */ - -// ================================================== -// Includes -// ================================================== - -#include "pal/pal_thread.h" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN - -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -// set unicode -#ifndef UNICODE -#define UNICODE -#endif // UNICODE - -#include - -// ================================================== -// Typedefs, enums and structs -// ================================================== - -typedef HRESULT(WINAPI* SetThreadDescriptionFn)( - HANDLE, - PCWSTR); - -typedef HRESULT(WINAPI* GetThreadDescriptionFn)( - HANDLE, - PWSTR*); - -typedef struct { - const PalAllocator* allocator; - PalThreadFn func; - void* arg; -} ThreadData; - -struct PalMutex { - const PalAllocator* allocator; - CRITICAL_SECTION sc; -}; - -struct PalCondVar { - const PalAllocator* allocator; - CONDITION_VARIABLE cv; -}; - -// ================================================== -// Internal API -// ================================================== - -static DWORD WINAPI threadEntryToWin32(LPVOID arg) -{ - ThreadData* data = arg; - void* ret = data->func(data->arg); - palFree(data->allocator, data); - return (DWORD)(uintptr_t)ret; -} - -void palSetLastPlatformError(uint32_t e); - -// ================================================== -// Public API -// ================================================== - -// ================================================== -// Thread -// ================================================== - -PalResult PAL_CALL palCreateThread( - const PalThreadCreateInfo* info, - PalThread** outThread) -{ - if (!info || !outThread) { - return PAL_RESULT_NULL_POINTER; - } - - if (info->allocator) { - if (!info->allocator->allocate && !info->allocator->free) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - } - - // create thread - ThreadData* data = palAllocate(info->allocator, sizeof(ThreadData), 0); - if (!data) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - data->arg = info->arg; - data->func = info->entry; - data->allocator = info->allocator; - - HANDLE thread = CreateThread(nullptr, info->stackSize, threadEntryToWin32, data, 0, nullptr); - if (!thread) { - // error - DWORD error = GetLastError(); - if (error == ERROR_NOT_ENOUGH_MEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - - } else if (error == ERROR_INVALID_PARAMETER) { - return PAL_RESULT_OUT_OF_MEMORY; - - } else if (error == ERROR_ACCESS_DENIED) { - return PAL_RESULT_ACCESS_DENIED; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - *outThread = (PalThread*)thread; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palJoinThread( - PalThread* thread, - void* retval) -{ - if (!thread) { - return PAL_RESULT_NULL_POINTER; - } - - void* value = nullptr; - DWORD wait = WaitForSingleObject((HANDLE)thread, INFINITE); - if (wait == WAIT_OBJECT_0 && retval) { - uintptr_t ret; - GetExitCodeThread((HANDLE)thread, (LPDWORD)&ret); - void** out = (void**)retval; - *out = value; - - // thread is done destroy the HANDLE - CloseHandle((HANDLE)thread); - - } else if (wait == WAIT_FAILED) { - return PAL_RESULT_INVALID_THREAD; - } - - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDetachThread(PalThread* thread) -{ - if (thread) { - CloseHandle((HANDLE)thread); - } -} - -void PAL_CALL palSleep(uint64_t milliseconds) -{ - Sleep((DWORD)milliseconds); -} - -void PAL_CALL palYield() -{ - SwitchToThread(); -} - -PalThread* PAL_CALL palGetCurrentThread() -{ - return (PalThread*)GetCurrentThread(); -} - -PalThreadFeatures PAL_CALL palGetThreadFeatures() -{ - PalThreadFeatures features = 0; - features |= PAL_THREAD_FEATURE_STACK_SIZE; - features |= PAL_THREAD_FEATURE_PRIORITY; - features |= PAL_THREAD_FEATURE_AFFINITY; - - // check support for PAL_THREAD_FEATURE_NAME feature - HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); - if (kernel32) { - FARPROC setThreadDesc = GetProcAddress(kernel32, "SetThreadDescription"); - - if (setThreadDesc) { - features |= PAL_THREAD_FEATURE_NAME; - } - } - return features; -} - -PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread) -{ - if (!thread) { - return 0; - } - - int priority = GetThreadPriority((HANDLE)thread); - switch (priority) { - case THREAD_PRIORITY_LOWEST: - return PAL_THREAD_PRIORITY_LOW; - break; - - case THREAD_PRIORITY_NORMAL: - return PAL_THREAD_PRIORITY_NORMAL; - break; - - case THREAD_PRIORITY_HIGHEST: - return PAL_THREAD_PRIORITY_HIGH; - break; - } - - return 0; -} - -uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) -{ - if (!thread) { - return 0; - } - - DWORD_PTR mask = SetThreadAffinityMask((HANDLE)thread, ~0ull); - if (mask == 0) { - return 0; - } - - SetThreadAffinityMask((HANDLE)thread, mask); - return mask; -} - -PalResult PAL_CALL palGetThreadName( - PalThread* thread, - uint64_t bufferSize, - uint64_t* outSize, - char* outBuffer) -{ - if (!thread) { - return PAL_RESULT_NULL_POINTER; - } - - HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); - GetThreadDescriptionFn getThreadDescription = nullptr; - if (kernel32) { - getThreadDescription = - (GetThreadDescriptionFn)GetProcAddress(kernel32, "GetThreadDescription"); - } - - if (!getThreadDescription) { - // not supported - return PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED; - } - - wchar_t* buffer = nullptr; - HRESULT hr = getThreadDescription((HANDLE)thread, &buffer); - - if (!SUCCEEDED(hr)) { - return PAL_RESULT_INVALID_THREAD; - } - - int len = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, nullptr, 0, 0, 0); - if (outSize) { - *outSize = len - 1; - } - - // see if user provided a buffer and write to it - if (outBuffer && bufferSize > 0) { - int write = (int)bufferSize - 1; - WideCharToMultiByte(CP_UTF8, 0, buffer, -1, outBuffer, write + 1, 0, 0); - outBuffer[write < len - 1 ? write : len - 1] = '\0'; - LocalFree(buffer); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetThreadPriority( - PalThread* thread, - PalThreadPriority priority) -{ - if (!thread) { - return PAL_RESULT_NULL_POINTER; - } - - int _priority = 0; - switch (priority) { - case PAL_THREAD_PRIORITY_LOW: - _priority = THREAD_PRIORITY_LOWEST; - break; - - case PAL_THREAD_PRIORITY_NORMAL: - _priority = THREAD_PRIORITY_NORMAL; - break; - - case PAL_THREAD_PRIORITY_HIGH: - _priority = THREAD_PRIORITY_HIGHEST; - break; - } - - if (!SetThreadPriority((HANDLE)thread, _priority)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_THREAD; - - } else if (error == ERROR_ACCESS_DENIED) { - return PAL_RESULT_ACCESS_DENIED; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetThreadAffinity( - PalThread* thread, - uint64_t mask) -{ - if (!thread) { - return PAL_RESULT_NULL_POINTER; - } - - if (!SetThreadAffinityMask((HANDLE)thread, mask)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_THREAD; - - } else if (error == ERROR_INVALID_PARAMETER) { - return PAL_RESULT_INVALID_ARGUMENT; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetThreadName( - PalThread* thread, - const char* name) -{ - if (!thread || !name) { - return PAL_RESULT_NULL_POINTER; - } - - HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); - SetThreadDescriptionFn setThreadDescription = nullptr; - if (kernel32) { - setThreadDescription = - (SetThreadDescriptionFn)GetProcAddress(kernel32, "SetThreadDescription"); - } - - if (!setThreadDescription) { - // not supported - return PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED; - } - - wchar_t buffer[128] = {0}; - MultiByteToWideChar(CP_UTF8, 0, name, -1, buffer, 128); - HRESULT hr = setThreadDescription((HANDLE)thread, buffer); - - if (SUCCEEDED(hr)) { - return PAL_RESULT_SUCCESS; - - } else { - if (hr == E_INVALIDARG) { - return PAL_RESULT_INVALID_THREAD; - - } else if (hr == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - - } else if (hr == E_ACCESSDENIED) { - return PAL_RESULT_ACCESS_DENIED; - - } else { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } -} - -// ================================================== -// TLS -// ================================================== - -PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor) -{ - DWORD tlsid = FlsAlloc(destructor); - if (tlsid == FLS_OUT_OF_INDEXES) { - return 0; - } - return tlsid; -} - -void PAL_CALL palDestroyTLS(PalTLSId id) -{ - FlsFree((DWORD)id); -} - -void* PAL_CALL palGetTLS(PalTLSId id) -{ - return FlsGetValue((DWORD)id); -} - -void PAL_CALL palSetTLS( - PalTLSId id, - void* data) -{ - FlsSetValue((DWORD)id, data); -} - -// ================================================== -// Mutex -// ================================================== - -PalResult PAL_CALL palCreateMutex( - const PalAllocator* allocator, - PalMutex** outMutex) -{ - if (!outMutex) { - return PAL_RESULT_NULL_POINTER; - } - - if (allocator) { - if (!allocator->allocate && !allocator->free) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - } - - PalMutex* mutex = palAllocate(allocator, sizeof(PalMutex), 0); - if (!mutex) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - InitializeCriticalSection(&mutex->sc); - mutex->allocator = allocator; - *outMutex = mutex; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyMutex(PalMutex* mutex) -{ - if (mutex) { - DeleteCriticalSection(&mutex->sc); - palFree(mutex->allocator, mutex); - } -} - -void PAL_CALL palLockMutex(PalMutex* mutex) -{ - if (mutex) { - EnterCriticalSection(&mutex->sc); - } -} - -void PAL_CALL palUnlockMutex(PalMutex* mutex) -{ - if (mutex) { - LeaveCriticalSection(&mutex->sc); - } -} - -// ================================================== -// Condition Variable -// ================================================== - -PalResult PAL_CALL palCreateCondVar( - const PalAllocator* allocator, - PalCondVar** outCondVar) -{ - if (!outCondVar) { - return PAL_RESULT_NULL_POINTER; - } - - if (allocator) { - if (!allocator->allocate && !allocator->free) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - } - - PalCondVar* condVar = palAllocate(allocator, sizeof(PalCondVar), 0); - if (!condVar) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - InitializeConditionVariable(&condVar->cv); - condVar->allocator = allocator; - *outCondVar = condVar; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyCondVar(PalCondVar* condVar) -{ - if (condVar) { - palFree(condVar->allocator, condVar); - } -} - -PalResult PAL_CALL palWaitCondVar( - PalCondVar* condVar, - PalMutex* mutex) -{ - if (!condVar || !mutex) { - return PAL_RESULT_NULL_POINTER; - } - - BOOL ret = SleepConditionVariableCS(&condVar->cv, &mutex->sc, INFINITE); - if (!ret) { - DWORD error = GetLastError(); - if (error == ERROR_TIMEOUT) { - return PAL_RESULT_TIMEOUT; - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palWaitCondVarTimeout( - PalCondVar* condVar, - PalMutex* mutex, - uint64_t milliseconds) -{ - if (!condVar || !mutex) { - return PAL_RESULT_NULL_POINTER; - } - - BOOL ret = SleepConditionVariableCS(&condVar->cv, &mutex->sc, (DWORD)milliseconds); - if (!ret) { - DWORD error = GetLastError(); - if (error == ERROR_TIMEOUT) { - return PAL_RESULT_TIMEOUT; - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palSignalCondVar(PalCondVar* condVar) -{ - if (condVar) { - WakeConditionVariable(&condVar->cv); - } -} - -void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) -{ - if (condVar) { - WakeAllConditionVariable(&condVar->cv); - } -} diff --git a/src/thread/win32/pal_condvar_win32.c b/src/thread/win32/pal_condvar_win32.c new file mode 100644 index 00000000..2b497359 --- /dev/null +++ b/src/thread/win32/pal_condvar_win32.c @@ -0,0 +1,128 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_thread_common_win32.h" +#include "pal_shared.h" + +PalResult PAL_CALL palCreateCondVar( + const PalAllocator* allocator, + PalCondVar** outCondVar) +{ + if (!outCondVar) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (allocator) { + if (!allocator->allocate && !allocator->free) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + } + + PalCondVar* condVar = palAllocate(allocator, sizeof(PalCondVar), 0); + if (!condVar) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + InitializeConditionVariable(&condVar->cv); + condVar->allocator = allocator; + *outCondVar = condVar; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyCondVar(PalCondVar* condVar) +{ + if (condVar) { + palFree(condVar->allocator, condVar); + } +} + +PalResult PAL_CALL palWaitCondVar( + PalCondVar* condVar, + PalMutex* mutex) +{ + if (!condVar || !mutex) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + BOOL ret = SleepConditionVariableCS(&condVar->cv, &mutex->sc, INFINITE); + if (!ret) { + DWORD error = GetLastError(); + if (error == ERROR_TIMEOUT) { + return palMakeResult( + PAL_RESULT_TIMEOUT, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palWaitCondVarTimeout( + PalCondVar* condVar, + PalMutex* mutex, + uint64_t milliseconds) +{ + if (!condVar || !mutex) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + BOOL ret = SleepConditionVariableCS(&condVar->cv, &mutex->sc, (DWORD)milliseconds); + if (!ret) { + DWORD error = GetLastError(); + if (error == ERROR_TIMEOUT) { + return palMakeResult( + PAL_RESULT_TIMEOUT, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palSignalCondVar(PalCondVar* condVar) +{ + if (condVar) { + WakeConditionVariable(&condVar->cv); + } +} + +void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) +{ + if (condVar) { + WakeAllConditionVariable(&condVar->cv); + } +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/thread/win32/pal_mutex_win32.c b/src/thread/win32/pal_mutex_win32.c new file mode 100644 index 00000000..50542bae --- /dev/null +++ b/src/thread/win32/pal_mutex_win32.c @@ -0,0 +1,68 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_thread_common_win32.h" +#include "pal_shared.h" + +PalResult PAL_CALL palCreateMutex( + const PalAllocator* allocator, + PalMutex** outMutex) +{ + if (!outMutex) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (allocator) { + if (!allocator->allocate && !allocator->free) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + } + + PalMutex* mutex = palAllocate(allocator, sizeof(PalMutex), 0); + if (!mutex) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + InitializeCriticalSection(&mutex->sc); + mutex->allocator = allocator; + *outMutex = mutex; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyMutex(PalMutex* mutex) +{ + if (mutex) { + DeleteCriticalSection(&mutex->sc); + palFree(mutex->allocator, mutex); + } +} + +void PAL_CALL palLockMutex(PalMutex* mutex) +{ + if (mutex) { + EnterCriticalSection(&mutex->sc); + } +} + +void PAL_CALL palUnlockMutex(PalMutex* mutex) +{ + if (mutex) { + LeaveCriticalSection(&mutex->sc); + } +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/thread/win32/pal_thread_common_win32.h b/src/thread/win32/pal_thread_common_win32.h new file mode 100644 index 00000000..5ab001ae --- /dev/null +++ b/src/thread/win32/pal_thread_common_win32.h @@ -0,0 +1,39 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#ifndef _PAL_THREAD_COMMON_WIN32_H +#define _PAL_THREAD_COMMON_WIN32_H + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE + +#include "pal/pal_thread.h" +#include + +struct PalMutex { + const PalAllocator* allocator; + CRITICAL_SECTION sc; +}; + +struct PalCondVar { + const PalAllocator* allocator; + CONDITION_VARIABLE cv; +}; + +#endif // _PAL_THREAD_COMMON_WIN32_H +#endif // _WIN32 \ No newline at end of file diff --git a/src/thread/win32/pal_thread_win32.c b/src/thread/win32/pal_thread_win32.c new file mode 100644 index 00000000..6f37f55e --- /dev/null +++ b/src/thread/win32/pal_thread_win32.c @@ -0,0 +1,417 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_thread_common_win32.h" +#include "pal_shared.h" + +typedef HRESULT(WINAPI* SetThreadDescriptionFn)( + HANDLE, + PCWSTR); + +typedef HRESULT(WINAPI* GetThreadDescriptionFn)( + HANDLE, + PWSTR*); + +typedef struct { + const PalAllocator* allocator; + PalThreadFn func; + void* arg; +} ThreadData; + +static DWORD WINAPI threadEntryToWin32(LPVOID arg) +{ + ThreadData* data = arg; + void* ret = data->func(data->arg); + palFree(data->allocator, data); + return (DWORD)(uintptr_t)ret; +} + +PalResult PAL_CALL palCreateThread( + const PalThreadCreateInfo* info, + PalThread** outThread) +{ + if (!info || !outThread) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (info->allocator) { + if (!info->allocator->allocate && !info->allocator->free) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + } + + // create thread + ThreadData* data = palAllocate(info->allocator, sizeof(ThreadData), 0); + if (!data) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + data->arg = info->arg; + data->func = info->entry; + data->allocator = info->allocator; + + HANDLE thread = CreateThread(nullptr, info->stackSize, threadEntryToWin32, data, 0, nullptr); + if (!thread) { + // error + DWORD error = GetLastError(); + if (error == ERROR_NOT_ENOUGH_MEMORY) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else if (error == ERROR_INVALID_PARAMETER) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else if (error == ERROR_ACCESS_DENIED) { + return palMakeResult( + PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + *outThread = (PalThread*)thread; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palJoinThread( + PalThread* thread, + void** retval) +{ + if (!thread) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // TODO: test + void* value = nullptr; + DWORD wait = WaitForSingleObject((HANDLE)thread, INFINITE); + if (wait == WAIT_OBJECT_0 && retval) { + uintptr_t ret; + GetExitCodeThread((HANDLE)thread, (LPDWORD)&ret); + void** out = (void**)retval; + *retval = + *out = value; + + // thread is done destroy the HANDLE + CloseHandle((HANDLE)thread); + + } else if (wait == WAIT_FAILED) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDetachThread(PalThread* thread) +{ + if (thread) { + CloseHandle((HANDLE)thread); + } +} + +void PAL_CALL palSleep(uint64_t milliseconds) +{ + Sleep((DWORD)milliseconds); +} + +void PAL_CALL palYield() +{ + SwitchToThread(); +} + +PalThread* PAL_CALL palGetCurrentThread() +{ + return (PalThread*)GetCurrentThread(); +} + +PalThreadFeatures PAL_CALL palGetThreadFeatures() +{ + PalThreadFeatures features = 0; + features |= PAL_THREAD_FEATURE_STACK_SIZE; + features |= PAL_THREAD_FEATURE_PRIORITY; + features |= PAL_THREAD_FEATURE_AFFINITY; + + // check support for PAL_THREAD_FEATURE_NAME feature + HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); + if (kernel32) { + FARPROC setThreadDesc = GetProcAddress(kernel32, "SetThreadDescription"); + + if (setThreadDesc) { + features |= PAL_THREAD_FEATURE_NAME; + } + } + return features; +} + +PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread) +{ + if (!thread) { + return 0; + } + + int priority = GetThreadPriority((HANDLE)thread); + switch (priority) { + case THREAD_PRIORITY_LOWEST: + return PAL_THREAD_PRIORITY_LOW; + break; + + case THREAD_PRIORITY_NORMAL: + return PAL_THREAD_PRIORITY_NORMAL; + break; + + case THREAD_PRIORITY_HIGHEST: + return PAL_THREAD_PRIORITY_HIGH; + break; + } + + return 0; +} + +uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) +{ + if (!thread) { + return 0; + } + + DWORD_PTR mask = SetThreadAffinityMask((HANDLE)thread, ~0ull); + if (mask == 0) { + return 0; + } + + SetThreadAffinityMask((HANDLE)thread, mask); + return mask; +} + +PalResult PAL_CALL palGetThreadName( + PalThread* thread, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer) +{ + if (!thread) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); + GetThreadDescriptionFn getThreadDescription = nullptr; + if (kernel32) { + getThreadDescription = + (GetThreadDescriptionFn)GetProcAddress(kernel32, "GetThreadDescription"); + } + + if (!getThreadDescription) { + // not supported + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + wchar_t* buffer = nullptr; + HRESULT hr = getThreadDescription((HANDLE)thread, &buffer); + + if (!SUCCEEDED(hr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + hr); + } + + int len = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, nullptr, 0, 0, 0); + if (outSize) { + *outSize = len - 1; + } + + // see if user provided a buffer and write to it + if (outBuffer && bufferSize > 0) { + int write = (int)bufferSize - 1; + WideCharToMultiByte(CP_UTF8, 0, buffer, -1, outBuffer, write + 1, 0, 0); + outBuffer[write < len - 1 ? write : len - 1] = '\0'; + LocalFree(buffer); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetThreadPriority( + PalThread* thread, + PalThreadPriority priority) +{ + if (!thread) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + int _priority = 0; + switch (priority) { + case PAL_THREAD_PRIORITY_LOW: + _priority = THREAD_PRIORITY_LOWEST; + break; + + case PAL_THREAD_PRIORITY_NORMAL: + _priority = THREAD_PRIORITY_NORMAL; + break; + + case PAL_THREAD_PRIORITY_HIGH: + _priority = THREAD_PRIORITY_HIGHEST; + break; + } + + if (!SetThreadPriority((HANDLE)thread, _priority)) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else if (error == ERROR_ACCESS_DENIED) { + return palMakeResult( + PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetThreadAffinity( + PalThread* thread, + uint64_t mask) +{ + if (!thread) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!SetThreadAffinityMask((HANDLE)thread, mask)) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else if (error == ERROR_INVALID_PARAMETER) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetThreadName( + PalThread* thread, + const char* name) +{ + if (!thread || !name) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); + SetThreadDescriptionFn setThreadDescription = nullptr; + if (kernel32) { + setThreadDescription = + (SetThreadDescriptionFn)GetProcAddress(kernel32, "SetThreadDescription"); + } + + if (!setThreadDescription) { + // not supported + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + wchar_t buffer[128] = {0}; + MultiByteToWideChar(CP_UTF8, 0, name, -1, buffer, 128); + HRESULT hr = setThreadDescription((HANDLE)thread, buffer); + + if (SUCCEEDED(hr)) { + return PAL_RESULT_SUCCESS; + + } else { + if (hr == E_INVALIDARG) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + hr); + + } else if (hr == E_OUTOFMEMORY) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WINDOWS, + hr); + + } else if (hr == E_ACCESSDENIED) { + return palMakeResult( + PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_SOURCE_WINDOWS, + hr); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + hr); + } + } +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/thread/win32/pal_tls_win32.c b/src/thread/win32/pal_tls_win32.c new file mode 100644 index 00000000..04fc6492 --- /dev/null +++ b/src/thread/win32/pal_tls_win32.c @@ -0,0 +1,51 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE + +#include "pal/pal_thread.h" +#include + +PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor) +{ + DWORD tlsid = FlsAlloc(destructor); + if (tlsid == FLS_OUT_OF_INDEXES) { + return 0; + } + return tlsid; +} + +void PAL_CALL palDestroyTLS(PalTLSId id) +{ + FlsFree((DWORD)id); +} + +void* PAL_CALL palGetTLS(PalTLSId id) +{ + return FlsGetValue((DWORD)id); +} + +void PAL_CALL palSetTLS( + PalTLSId id, + void* data) +{ + FlsSetValue((DWORD)id, data); +} + +#endif // _WIN32 \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index 10f0e69b..230769b5 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -8,22 +8,22 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - registerTest(loggerTest, "Logger Test"); - registerTest(timeTest, "Time Test"); + // registerTest(loggerTest, "Logger Test"); + // registerTest(timeTest, "Time Test"); // event - registerTest(eventTest, "Event test"); - registerTest(userEventTest, "User Event Test"); + // registerTest(eventTest, "Event test"); + // registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE // registerTest(systemTest, "System Test"); #endif // PAL_HAS_SYSTEM_MODULE #if PAL_HAS_THREAD_MODULE - // registerTest(threadTest, "Thread Test"); - // registerTest(tlsTest, "TLS Test"); - // registerTest(mutexTest, "Mutex Test"); - // registerTest(condvarTest, "Condvar Test"); + registerTest(threadTest, "Thread Test"); + registerTest(tlsTest, "TLS Test"); + registerTest(mutexTest, "Mutex Test"); + registerTest(condvarTest, "Condvar Test"); #endif // PAL_HAS_THREAD_MODULE #if PAL_HAS_VIDEO_MODULE diff --git a/tests/thread/condvar_test.c b/tests/thread/condvar_test.c index b0c47d85..319e29ae 100644 --- a/tests/thread/condvar_test.c +++ b/tests/thread/condvar_test.c @@ -1,6 +1,6 @@ -#include "pal/pal_thread.h" #include "tests.h" +#include "pal/pal_thread.h" #define THREAD_COUNT 4 @@ -37,23 +37,21 @@ PalBool condvarTest() data = palAllocate(nullptr, sizeof(ThreadData) * THREAD_COUNT, 0); if (!data) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } // create mutex result = palCreateMutex(nullptr, &g_Mutex); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create mutex: %s", error); - return false; + logResult(result, "Failed to create mutex"); + return PAL_FALSE; } // create condition result = palCreateCondVar(nullptr, &g_Condition); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create cond var: %s", error); - return false; + logResult(result, "Failed to create condition variable"); + return PAL_FALSE; } // create threads @@ -64,14 +62,13 @@ PalBool condvarTest() for (int32_t i = 0; i < THREAD_COUNT; i++) { ThreadData* threadData = &data[i]; threadData->id = i + 1; - threadData->ready = false; + threadData->ready = PAL_FALSE; createInfo.arg = (void*)threadData; result = palCreateThread(&createInfo, &threads[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create thread: %s", error); - return false; + logResult(result, "Failed to create thread"); + return PAL_FALSE; } // since thread priority is not supported on all platforms @@ -87,7 +84,7 @@ PalBool condvarTest() // signal thread 1 palLockMutex(g_Mutex); - data[0].ready = true; + data[0].ready = PAL_TRUE; palSignalCondVar(g_Condition); palUnlockMutex(g_Mutex); @@ -98,7 +95,7 @@ PalBool condvarTest() // broadcast to all remaining threads palLockMutex(g_Mutex); for (int32_t i = 1; i < THREAD_COUNT; i++) { - data[i].ready = true; + data[i].ready = PAL_TRUE; } palBroadcastCondVar(g_Condition); @@ -112,5 +109,5 @@ PalBool condvarTest() } palFree(nullptr, data); - return true; + return PAL_TRUE; } diff --git a/tests/thread/mutex_test.c b/tests/thread/mutex_test.c index 959f9eec..e1b06b50 100644 --- a/tests/thread/mutex_test.c +++ b/tests/thread/mutex_test.c @@ -1,6 +1,6 @@ -#include "pal/pal_thread.h" #include "tests.h" +#include "pal/pal_thread.h" #define MAX_COUNTER 10000 #define THREAD_COUNT 2 @@ -34,15 +34,14 @@ PalBool mutexTest() SharedData* data = palAllocate(nullptr, sizeof(SharedData), 0); if (!data) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } // create mutex result = palCreateMutex(nullptr, &mutex); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create mutex: %s", error); - return false; + logResult(result, "Failed to create mutex"); + return PAL_FALSE; } data->counter = 0; @@ -59,9 +58,8 @@ PalBool mutexTest() // create thread result = palCreateThread(&createInfo, &threads[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create thread: %s", error); - return false; + logResult(result, "Failed to create thread"); + return PAL_FALSE; } } @@ -77,5 +75,5 @@ PalBool mutexTest() palLog(nullptr, "Final Counter: %d", data->counter); palFree(nullptr, data); - return true; + return PAL_TRUE; } diff --git a/tests/thread/thread_test.c b/tests/thread/thread_test.c index ccf0eb0b..1e14a35c 100644 --- a/tests/thread/thread_test.c +++ b/tests/thread/thread_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_core.h" +#include "tests.h" #include "pal/pal_thread.h" #define THREAD_TIME 1000 @@ -32,9 +32,8 @@ PalBool threadTest() // create thread result = palCreateThread(&createInfo, &threads[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create thread: %s", error); - return false; + logResult(result, "Failed to create thread"); + return PAL_FALSE; } } @@ -44,12 +43,11 @@ PalBool threadTest() // joint threads does not need to be detached result = palJoinThread(threads[i], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to join threads: %s", error); - return false; + logResult(result, "Failed to join threads"); + return PAL_FALSE; } } palLog(nullptr, "All threads finished successfully"); - return true; + return PAL_TRUE; } diff --git a/tests/thread/tls_test.c b/tests/thread/tls_test.c index 2b62bb5f..70921c22 100644 --- a/tests/thread/tls_test.c +++ b/tests/thread/tls_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_core.h" +#include "tests.h" #include "pal/pal_thread.h" // data every thread will have its own copy of @@ -57,14 +57,14 @@ PalBool tlsTest() PalTLSId tlsID = palCreateTLS(TlsDestructor); if (tlsID == 0) { palLog(nullptr, "Failed to create TLS"); - return false; + return PAL_FALSE; } // allocate thread data ThreadData* threadData = palAllocate(nullptr, sizeof(ThreadData), 0); if (!threadData) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } threadData->tlsId = tlsID; @@ -77,9 +77,8 @@ PalBool tlsTest() PalResult result = palCreateThread(&info, &thread); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create thread: %s", error); - return false; + logResult(result, "Failed to create thread"); + return PAL_FALSE; } // join thread @@ -90,5 +89,5 @@ PalBool tlsTest() palDestroyTLS(tlsID); palFree(nullptr, threadData); - return true; + return PAL_TRUE; } From 92b3f7639a5c14a41f46d14291c98e291c431dcd Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Jun 2026 20:30:05 +0000 Subject: [PATCH 266/372] add thread system abi dump --- tools/abi_dump/abi_dump.lua | 1 + tools/abi_dump/abi_dump_main.c | 20 +++++++++-- tools/abi_dump/core_abi_dump.c | 8 ++++- tools/abi_dump/dumps.h | 7 ++++ tools/abi_dump/event_abi_dump.c | 8 ++++- tools/abi_dump/thread_abi_dump.c | 60 ++++++++++++++++++++++++++++++++ 6 files changed, 100 insertions(+), 4 deletions(-) create mode 100644 tools/abi_dump/thread_abi_dump.c diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index 8debf70a..aadc22b2 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -8,6 +8,7 @@ project "pal-abi-dump" files { "core_abi_dump.c", "event_abi_dump.c", + "thread_abi_dump.c", "abi_dump_main.c" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 6f5a1241..0e58e6f7 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -1,4 +1,10 @@ +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + #include "dumps.h" #define VERSION "1.0" @@ -61,16 +67,26 @@ int main(int argc, char** argv) dumpEventABI(); } + if (dumpThread) { + dumpThreadABI(); + } + if (dumpVersion) { palLog(nullptr, "PAL ABI dump %s", VERSION); } if (dumpHelp) { palLog(nullptr, "USAGE: %s [options]", EXE_NAME); - palLog(nullptr, "Options:"); // 10 spaces + palLog(nullptr, "Options:"); palLog(nullptr, " --help Display available options"); palLog(nullptr, " --version Display ABI dump version information"); - palLog(nullptr, " --core Display PAL core system structs ABI information"); + palLog(nullptr, " --core Display PAL core structs ABI information"); + palLog(nullptr, " --event Display PAL event structs ABI information"); + palLog(nullptr, " --graphics Display PAL graphics structs ABI information"); + palLog(nullptr, " --opengl Display PAL opengl structs ABI information"); + palLog(nullptr, " --system Display PAL system structs ABI information"); + palLog(nullptr, " --thread Display PAL thread structs ABI information"); + palLog(nullptr, " --video Display PAL video structs ABI information"); } return 0; diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c index 9288e93d..7d3e6043 100644 --- a/tools/abi_dump/core_abi_dump.c +++ b/tools/abi_dump/core_abi_dump.c @@ -1,4 +1,10 @@ +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + #include "dumps.h" static void versionDump() @@ -124,7 +130,7 @@ void dumpCoreABI() { palLog(nullptr, ""); palLog(nullptr, "==========================================="); - palLog(nullptr, "Core System ABI Dump"); + palLog(nullptr, "Core ABI Dump"); palLog(nullptr, "==========================================="); palLog(nullptr, ""); diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index db8bfea0..f12238cc 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -1,4 +1,10 @@ +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + #ifndef _DUMPS_H #define _DUMPS_H @@ -16,5 +22,6 @@ static const char* s_PassedString = "PASSED"; void dumpCoreABI(); void dumpEventABI(); +void dumpThreadABI(); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index 340ac561..f99120e7 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -1,4 +1,10 @@ +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + #include "dumps.h" #include "pal/pal_event.h" @@ -137,7 +143,7 @@ void dumpEventABI() { palLog(nullptr, ""); palLog(nullptr, "==========================================="); - palLog(nullptr, "Event System ABI Dump"); + palLog(nullptr, "Event ABI Dump"); palLog(nullptr, "==========================================="); palLog(nullptr, ""); diff --git a/tools/abi_dump/thread_abi_dump.c b/tools/abi_dump/thread_abi_dump.c new file mode 100644 index 00000000..68871471 --- /dev/null +++ b/tools/abi_dump/thread_abi_dump.c @@ -0,0 +1,60 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "dumps.h" +#include "pal/pal_thread.h" + +void dumpThreadABI() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Thread ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + uint32_t xSize = 32; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 16; + uint32_t xOffset4 = 24; + + uint32_t ySize = sizeof(PalThreadCreateInfo); + uint32_t yAlign = PAL_ALIGNOF(PalThreadCreateInfo); + uint32_t yOffset1 = offsetof(PalThreadCreateInfo, stackSize); + uint32_t yOffset2 = offsetof(PalThreadCreateInfo, allocator); + uint32_t yOffset3 = offsetof(PalThreadCreateInfo, entry); + uint32_t yOffset4 = offsetof(PalThreadCreateInfo, arg); + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalThreadCreateInfo"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "stackSize @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "allocator @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "entry @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "arg @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} \ No newline at end of file From 285c216d06da270314c5bf0887e84a85cfe599b7 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 15 Jun 2026 22:50:20 +0000 Subject: [PATCH 267/372] test system rewrite linux --- include/pal/pal_system.h | 100 ++++++------ pal.lua | 10 +- pal_config.lua | 4 +- .../pal_cpu_linux.c} | 84 ++-------- src/system/linux/pal_platform_linux.c | 80 ++++++++++ .../pal_cpu_win32.c} | 139 +++------------- src/system/win32/pal_platform_win32.c | 148 ++++++++++++++++++ tests/system/{system_test.c => cpu_test.c} | 74 +-------- tests/system/platform_test.c | 66 ++++++++ tests/tests.h | 3 +- tests/tests.lua | 3 +- tests/tests_main.c | 3 +- tools/abi_dump/core_abi_dump.c | 18 ++- tools/abi_dump/event_abi_dump.c | 18 ++- 14 files changed, 428 insertions(+), 322 deletions(-) rename src/system/{pal_system_linux.c => linux/pal_cpu_linux.c} (70%) create mode 100644 src/system/linux/pal_platform_linux.c rename src/system/{pal_system_win32.c => win32/pal_cpu_win32.c} (61%) create mode 100644 src/system/win32/pal_platform_win32.c rename tests/system/{system_test.c => cpu_test.c} (58%) create mode 100644 tests/system/platform_test.c diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index c5dfaf5d..2deefa41 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -5,7 +5,7 @@ */ /** - * @defgroup pal_system CPU and platform + * @defgroup pal_system System * @ingroup pal_system * @{ */ @@ -13,34 +13,55 @@ #ifndef _PAL_SYSTEM_H #define _PAL_SYSTEM_H -#include "core/defines.h" -#include "core/result.h" -#include "core/version.h" -#include "core/memory.h" +#include "pal_core.h" #define PAL_PLATFORM_NAME_SIZE 32 #define PAL_CPU_VENDOR_NAME_SIZE 16 #define PAL_CPU_MODEL_NAME_SIZE 64 +#define PAL_CPU_ARCH_UNKNOWN 0 +#define PAL_CPU_ARCH_X86 1 +#define PAL_CPU_ARCH_X86_64 2 +#define PAL_CPU_ARCH_ARM 3 +#define PAL_CPU_ARCH_ARM64 4 + +#define PAL_CPU_FEATURE_SSE (1ULL << 0) +#define PAL_CPU_FEATURE_SSE2 (1ULL << 1) +#define PAL_CPU_FEATURE_SSE3 (1ULL << 2) +#define PAL_CPU_FEATURE_SSSE3 (1ULL << 3) +#define PAL_CPU_FEATURE_SSE41 (1ULL << 4) /**< SSE4.1.*/ +#define PAL_CPU_FEATURE_SSE42 (1ULL << 5) /**< SSE4.2.*/ +#define PAL_CPU_FEATURE_AVX (1ULL << 6) +#define PAL_CPU_FEATURE_AVX2 (1ULL << 7) +#define PAL_CPU_FEATURE_AVX512F (1ULL << 8) +#define PAL_CPU_FEATURE_FMA3 (1ULL << 9) +#define PAL_CPU_FEATURE_BMI1 (1ULL << 10) +#define PAL_CPU_FEATURE_BMI2 (1ULL << 11) + +#define PAL_PLATFORM_WINDOWS 0 +#define PAL_PLATFORM_LINUX 1 +#define PAL_PLATFORM_MACOS 2 +#define PAL_PLATFORM_ANDROID 3 +#define PAL_PLATFORM_IOS 4 + +#define PAL_PLATFORM_API_WIN32 0 +#define PAL_PLATFORM_API_WAYLAND 1 +#define PAL_PLATFORM_API_X11 2 +#define PAL_PLATFORM_API_COCOA 3 +#define PAL_PLATFORM_API_ANDRIOD 4 +#define PAL_PLATFORM_API_UIKIT 5 +#define PAL_PLATFORM_API_HEADLESS 6 + /** * @typedef PalCpuArch * @brief CPU achitecture. This is not a bitmask. * - * This is a build time achitecture. Example: Generating your project with x64 - * will reflect PAL_CPU_ARCH_X86_64. - * * All CPU achitectures follow the format `PAL_CPU_ARCH_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ -typedef enum { - PAL_CPU_ARCH_UNKNOWN, - PAL_CPU_ARCH_X86, - PAL_CPU_ARCH_X86_64, - PAL_CPU_ARCH_ARM, - PAL_CPU_ARCH_ARM64 -} PalCpuArch; +typedef uint32_t PalCpuArch; /** * @typedef PalCpuFeatures @@ -49,22 +70,9 @@ typedef enum { * All CPU features sets follow the format `PAL_CPU_FEATURE_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ -typedef enum { - PAL_CPU_FEATURE_SSE = (1ULL << 0), - PAL_CPU_FEATURE_SSE2 = (1ULL << 1), - PAL_CPU_FEATURE_SSE3 = (1ULL << 2), - PAL_CPU_FEATURE_SSSE3 = (1ULL << 3), - PAL_CPU_FEATURE_SSE41 = (1ULL << 4), /**< SSE4.1.*/ - PAL_CPU_FEATURE_SSE42 = (1ULL << 5), /**< SSE4.1.*/ - PAL_CPU_FEATURE_AVX = (1ULL << 6), - PAL_CPU_FEATURE_AVX2 = (1ULL << 7), - PAL_CPU_FEATURE_AVX512F = (1ULL << 8), - PAL_CPU_FEATURE_FMA3 = (1ULL << 9), - PAL_CPU_FEATURE_BMI1 = (1ULL << 10), - PAL_CPU_FEATURE_BMI2 = (1ULL << 11) -} PalCpuFeatures; +typedef uint64_t PalCpuFeatures; /** * @typedef PalPlatformType @@ -76,15 +84,9 @@ typedef enum { * All platform types follow the format `PAL_PLATFORM_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ -typedef enum { - PAL_PLATFORM_WINDOWS, - PAL_PLATFORM_LINUX, - PAL_PLATFORM_MACOS, - PAL_PLATFORM_ANDROID, - PAL_PLATFORM_IOS -} PalPlatformType; +typedef uint32_t PalPlatformType; /** * @typedef PalPlatformApiType @@ -96,23 +98,15 @@ typedef enum { * All platform API types follow the format `PAL_PLATFORM_API_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ -typedef enum { - PAL_PLATFORM_API_WIN32, - PAL_PLATFORM_API_WAYLAND, - PAL_PLATFORM_API_X11, - PAL_PLATFORM_API_COCOA, - PAL_PLATFORM_API_ANDRIOD, - PAL_PLATFORM_API_UIKIT, - PAL_PLATFORM_API_HEADLESS -} PalPlatformApiType; +typedef uint32_t PalPlatformApiType; /** * @struct PalPlatformInfo * @brief Information about a platform (OS). * - * @since 1.0 + * @since 2.0 */ typedef struct { PalPlatformType type; @@ -127,16 +121,16 @@ typedef struct { * @struct PalCPUInfo * @brief Information about a CPU. * - * @since 1.0 + * @since 2.0 */ typedef struct { + PalCpuFeatures features; + PalCpuArch architecture; uint32_t numCores; uint32_t cacheL1; /**< L1 cache in KB.*/ uint32_t cacheL2; /**< L2 cache in KB.*/ uint32_t cacheL3; /**< L3 cache in KB.*/ uint32_t numLogicalProcessors; /**< Number of CPUs.*/ - PalCpuArch architecture; - PalCpuFeatures features; char vendor[PAL_CPU_VENDOR_NAME_SIZE]; /**< CPU vendor name.*/ char model[PAL_CPU_MODEL_NAME_SIZE]; /**< CPU modal name.*/ } PalCPUInfo; diff --git a/pal.lua b/pal.lua index 696f2e59..2d6e1f83 100644 --- a/pal.lua +++ b/pal.lua @@ -49,10 +49,16 @@ project "PAL" if (PAL_BUILD_SYSTEM_MODULE) then filter {"system:windows", "configurations:*"} - files { "src/system/pal_system_win32.c" } + files { + "src/system/win32/pal_cpu_win32.c", + "src/system/win32/pal_platform_win32.c" + } filter {"system:linux", "configurations:*"} - files { "src/system/pal_system_linux.c" } + files { + "src/system/linux/pal_cpu_linux.c", + "src/system/linux/pal_platform_linux.c" + } filter {} end diff --git a/pal_config.lua b/pal_config.lua index 3ab92dff..095be764 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -9,10 +9,10 @@ PAL_BUILD_TEST_APPLICATION = true PAL_BUILD_ABI_DUMP = true -- build system module -PAL_BUILD_SYSTEM_MODULE = false +PAL_BUILD_SYSTEM_MODULE = true -- build thread module -PAL_BUILD_THREAD_MODULE = true +PAL_BUILD_THREAD_MODULE = false -- build video module PAL_BUILD_VIDEO_MODULE = false diff --git a/src/system/pal_system_linux.c b/src/system/linux/pal_cpu_linux.c similarity index 70% rename from src/system/pal_system_linux.c rename to src/system/linux/pal_cpu_linux.c index d3e37595..87857477 100644 --- a/src/system/pal_system_linux.c +++ b/src/system/linux/pal_cpu_linux.c @@ -5,16 +5,11 @@ */ #ifdef __linux__ -#define _GNU_SOURCE #define _POSIX_C_SOURCE 200112L +#include "pal_shared.h" #include "pal/pal_system.h" - #include #include -#include -#include -#include -#include #include #include @@ -40,79 +35,31 @@ static uint32_t parseCache(const char* path) return cacheSize; } -PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) -{ - if (!info) { - return PAL_RESULT_NULL_POINTER; - } - - info->type = PAL_PLATFORM_LINUX; - const char* session = getenv("XDG_SESSION_TYPE"); - if (session) { - if (strcmp(session, "wayland") == 0) { - info->apiType = PAL_PLATFORM_API_WAYLAND; - } else { - info->apiType = PAL_PLATFORM_API_X11; - } - } else { - // default - info->apiType = PAL_PLATFORM_API_X11; - } - - FILE* file = fopen("/etc/os-release", "r"); - if (!file) { - return PAL_RESULT_PLATFORM_FAILURE; - } - - char line[256]; - char name[15]; - char version[15]; - // parse version and name from the release file - while (fgets(line, sizeof(line), file)) { - if (strncmp(line, "NAME=", 5) == 0) { - sscanf(line, "NAME=\"%15[^\"]", name); - - } else if (strncmp(line, "VERSION_ID=", 11) == 0) { - sscanf(line, "VERSION_ID=\"%15[^\"]", version); - } - } - - // combine to get name - snprintf(info->name, PAL_PLATFORM_NAME_SIZE, "%s %s", name, version); - sscanf(version, "%d.%d", &info->version.major, &info->version.minor); - fclose(file); - - // get total memory and disk space for the root drive - struct sysinfo sysInfo; - sysinfo(&sysInfo); - info->totalRAM = (uint32_t)(sysInfo.totalram / (1024 * 1024)); - - struct statvfs stats; - if (statvfs("/", &stats) != 0) { - return PAL_RESULT_PLATFORM_FAILURE; - } - - uint64_t size = (stats.f_blocks * stats.f_frsize) / (1024 * 1024 * 1024); - info->totalMemory = (uint32_t)size; - return PAL_RESULT_SUCCESS; -} - PalResult PAL_CALL palGetCPUInfo( const PalAllocator* allocator, PalCPUInfo* info) { if (!info) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } // check invalid allocator if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_INVALID_ALLOCATOR; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); } FILE* file = fopen("/proc/cpuinfo", "r"); if (!file) { - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } char line[1024]; @@ -191,7 +138,10 @@ PalResult PAL_CALL palGetCPUInfo( // get architecture struct utsname arch; if (uname(&arch) != 0) { - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } if (strcmp(arch.machine, "x86_64") == 0) { diff --git a/src/system/linux/pal_platform_linux.c b/src/system/linux/pal_platform_linux.c new file mode 100644 index 00000000..80d786a0 --- /dev/null +++ b/src/system/linux/pal_platform_linux.c @@ -0,0 +1,80 @@ +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#define _POSIX_C_SOURCE 200112L +#include "pal_shared.h" +#include "pal/pal_system.h" +#include +#include +#include +#include +#include + +PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) +{ + if (!info) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + info->type = PAL_PLATFORM_LINUX; + const char* session = getenv("XDG_SESSION_TYPE"); + if (session) { + if (strcmp(session, "wayland") == 0) { + info->apiType = PAL_PLATFORM_API_WAYLAND; + } else { + info->apiType = PAL_PLATFORM_API_X11; + } + } else { + // default + info->apiType = PAL_PLATFORM_API_X11; + } + + FILE* file = fopen("/etc/os-release", "r"); + if (!file) { + return PAL_RESULT_PLATFORM_FAILURE; + } + + char line[256]; + char name[15]; + char version[15]; + // parse version and name from the release file + while (fgets(line, sizeof(line), file)) { + if (strncmp(line, "NAME=", 5) == 0) { + sscanf(line, "NAME=\"%15[^\"]", name); + + } else if (strncmp(line, "VERSION_ID=", 11) == 0) { + sscanf(line, "VERSION_ID=\"%15[^\"]", version); + } + } + + // combine to get name + snprintf(info->name, PAL_PLATFORM_NAME_SIZE, "%s %s", name, version); + sscanf(version, "%d.%d", &info->version.major, &info->version.minor); + fclose(file); + + // get total memory and disk space for the root drive + struct sysinfo sysInfo; + sysinfo(&sysInfo); + info->totalRAM = (uint32_t)(sysInfo.totalram / (1024 * 1024)); + + struct statvfs stats; + if (statvfs("/", &stats) != 0) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + uint64_t size = (stats.f_blocks * stats.f_frsize) / (1024 * 1024 * 1024); + info->totalMemory = (uint32_t)size; + return PAL_RESULT_SUCCESS; +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/system/pal_system_win32.c b/src/system/win32/pal_cpu_win32.c similarity index 61% rename from src/system/pal_system_win32.c rename to src/system/win32/pal_cpu_win32.c index 6e4fbc1d..5ae30d4a 100644 --- a/src/system/pal_system_win32.c +++ b/src/system/win32/pal_cpu_win32.c @@ -5,8 +5,6 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal/pal_system.h" - #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN @@ -21,6 +19,8 @@ #define UNICODE #endif // UNICODE +#include "pal/pal_system.h" +#include "pal_shared.h" #include #include @@ -28,8 +28,6 @@ #include #endif // _MSC_VER -typedef LONG(WINAPI* RtlGetVersionFn)(PRTL_OSVERSIONINFOW); - static inline void cpuid( int regs[4], int leaf, @@ -45,130 +43,23 @@ static inline void cpuid( #endif // _MSC_VER } -static inline PalBool getVersionWin32(PalVersion* version) -{ - OSVERSIONINFOEXW ver = {0}; - ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); - HINSTANCE ntdll = GetModuleHandleW(L"ntdll.dll"); - RtlGetVersionFn getVer = (RtlGetVersionFn)GetProcAddress(ntdll, "RtlGetVersion"); - if (!getVer) { - return false; - } - - if (getVer((PRTL_OSVERSIONINFOW)&ver)) { - return false; - } - - version->major = ver.dwMajorVersion; - version->minor = ver.dwMinorVersion; - version->build = ver.dwBuildNumber; - return true; -} - -static inline PalBool isVersionWin32( - PalVersion* osVersion, - uint16_t major, - uint16_t minor, - uint16_t build) -{ - if (osVersion->major > major) { - return true; - } - - if (osVersion->major < major) { - return false; - } - - if (osVersion->minor > minor) { - return true; - } - - if (osVersion->minor < minor) { - return false; - } - - return osVersion->build >= build; -} - -PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) -{ - if (!info) { - return PAL_RESULT_NULL_POINTER; - } - - info->apiType = PAL_PLATFORM_API_WIN32; - info->type = PAL_PLATFORM_WINDOWS; - - // get windows build, version and combine them - if (!getVersionWin32(&info->version)) { - return PAL_RESULT_PLATFORM_FAILURE; - } - - const char* name = nullptr; - const char* build = nullptr; - // check the versions and set the appropriate name - if (isVersionWin32(&info->version, 5, 1, 0)) { - name = "Windows XP"; - } - - if (isVersionWin32(&info->version, 6, 0, 0)) { - name = "Windows Vista"; - } - - if (isVersionWin32(&info->version, 6, 1, 0)) { - name = "Windows 7"; - } - - if (isVersionWin32(&info->version, 6, 2, 0)) { - name = "Windows 8"; - } - - if (isVersionWin32(&info->version, 6, 3, 0)) { - name = "Windows 8.1"; - } - - if (isVersionWin32(&info->version, 10, 0, 0)) { - name = "Windows 10"; - } - - if (isVersionWin32(&info->version, 10, 0, 22000)) { - name = "Windows 11"; - build = ".22000"; - } - - // combine them into a single string - strcpy(info->name, name); - if (build) { - strcat(info->name, build); - } - - // get total disk memory (size) in GB - ULARGE_INTEGER free, total, available; - if (GetDiskFreeSpaceExW(L"C:\\", &available, &total, &free)) { - info->totalMemory = (uint32_t)(total.QuadPart / (1024 * 1024 * 1024)); - } - - // get ram (size) in MB - MEMORYSTATUSEX status = {0}; - status.dwLength = sizeof(MEMORYSTATUSEX); - if (GlobalMemoryStatusEx(&status)) { - info->totalRAM = (uint32_t)(status.ullTotalPhys / (1024 * 1024)); - } - - return PAL_RESULT_SUCCESS; -} - PalResult PAL_CALL palGetCPUInfo( const PalAllocator* allocator, PalCPUInfo* info) { if (!info) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); } // check invalid allocator if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_INVALID_ALLOCATOR; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); } memset(info, 0, sizeof(PalCPUInfo)); @@ -231,13 +122,19 @@ PalResult PAL_CALL palGetCPUInfo( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* buffer = nullptr; buffer = palAllocate(allocator, len, 16); if (!buffer) { - return PAL_RESULT_OUT_OF_MEMORY; + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); } BOOL ret = GetLogicalProcessorInformationEx(RelationAll, buffer, &len); if (!ret) { palFree(allocator, buffer); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); } char* ptr = (char*)buffer; diff --git a/src/system/win32/pal_platform_win32.c b/src/system/win32/pal_platform_win32.c new file mode 100644 index 00000000..4101b8fc --- /dev/null +++ b/src/system/win32/pal_platform_win32.c @@ -0,0 +1,148 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE + +#include "pal/pal_system.h" +#include "pal_shared.h" +#include +#include + +typedef LONG(WINAPI* RtlGetVersionFn)(PRTL_OSVERSIONINFOW); + +static inline PalBool getVersionWin32(PalVersion* version) +{ + OSVERSIONINFOEXW ver = {0}; + ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); + HINSTANCE ntdll = GetModuleHandleW(L"ntdll.dll"); + RtlGetVersionFn getVer = (RtlGetVersionFn)GetProcAddress(ntdll, "RtlGetVersion"); + if (!getVer) { + return false; + } + + if (getVer((PRTL_OSVERSIONINFOW)&ver)) { + return false; + } + + version->major = ver.dwMajorVersion; + version->minor = ver.dwMinorVersion; + version->build = ver.dwBuildNumber; + return true; +} + +static inline PalBool isVersionWin32( + PalVersion* osVersion, + uint32_t major, + uint32_t minor, + uint32_t build) +{ + if (osVersion->major > major) { + return true; + } + + if (osVersion->major < major) { + return false; + } + + if (osVersion->minor > minor) { + return true; + } + + if (osVersion->minor < minor) { + return false; + } + + return osVersion->build >= build; +} + +PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) +{ + if (!info) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + info->apiType = PAL_PLATFORM_API_WIN32; + info->type = PAL_PLATFORM_WINDOWS; + + // get windows build, version and combine them + if (!getVersionWin32(&info->version)) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + const char* name = nullptr; + const char* build = nullptr; + // check the versions and set the appropriate name + if (isVersionWin32(&info->version, 5, 1, 0)) { + name = "Windows XP"; + } + + if (isVersionWin32(&info->version, 6, 0, 0)) { + name = "Windows Vista"; + } + + if (isVersionWin32(&info->version, 6, 1, 0)) { + name = "Windows 7"; + } + + if (isVersionWin32(&info->version, 6, 2, 0)) { + name = "Windows 8"; + } + + if (isVersionWin32(&info->version, 6, 3, 0)) { + name = "Windows 8.1"; + } + + if (isVersionWin32(&info->version, 10, 0, 0)) { + name = "Windows 10"; + } + + if (isVersionWin32(&info->version, 10, 0, 22000)) { + name = "Windows 11"; + build = ".22000"; + } + + // combine them into a single string + strcpy(info->name, name); + if (build) { + strcat(info->name, build); + } + + // get total disk memory (size) in GB + ULARGE_INTEGER free, total, available; + if (GetDiskFreeSpaceExW(L"C:\\", &available, &total, &free)) { + info->totalMemory = (uint32_t)(total.QuadPart / (1024 * 1024 * 1024)); + } + + // get ram (size) in MB + MEMORYSTATUSEX status = {0}; + status.dwLength = sizeof(MEMORYSTATUSEX); + if (GlobalMemoryStatusEx(&status)) { + info->totalRAM = (uint32_t)(status.ullTotalPhys / (1024 * 1024)); + } + + return PAL_RESULT_SUCCESS; +} + +#endif // _WIN32 \ No newline at end of file diff --git a/tests/system/system_test.c b/tests/system/cpu_test.c similarity index 58% rename from tests/system/system_test.c rename to tests/system/cpu_test.c index 38a73e86..04eacbaa 100644 --- a/tests/system/system_test.c +++ b/tests/system/cpu_test.c @@ -1,45 +1,8 @@ -#include "pal/pal_system.h" #include "tests.h" - +#include "pal/pal_system.h" #include // for strcat -static inline const char* platformToString(PalPlatformType type) -{ - switch (type) { - case PAL_PLATFORM_WINDOWS: - return "Windows"; - - case PAL_PLATFORM_LINUX: - return "Linux"; - - case PAL_PLATFORM_MACOS: - return "MacOs"; - - case PAL_PLATFORM_ANDROID: - return "Android"; - - case PAL_PLATFORM_IOS: - return "Ios"; - } - return nullptr; -} - -static inline const char* platformApiToString(PalPlatformApiType type) -{ - switch (type) { - case PAL_PLATFORM_API_WIN32: - return "Win32"; - - case PAL_PLATFORM_API_X11: - return "X11"; - - case PAL_PLATFORM_API_WAYLAND: - return "Wayland"; - } - return nullptr; -} - static inline const char* cpuArchToString(PalCpuArch arch) { switch (arch) { @@ -61,43 +24,18 @@ static inline const char* cpuArchToString(PalCpuArch arch) return nullptr; } -PalBool systemTest() +PalBool cpuTest() { PalResult result; PalCPUInfo cpuInfo; - PalPlatformInfo platformInfo; - - // get the platform info. Users must cache this - result = palGetPlatformInfo(&platformInfo); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get platform info: %s", error); - return false; - } - // user defined allocator, set to override the default one or nullptr for - // default + // user defined allocator, set to override the default one or nullptr for default result = palGetCPUInfo(nullptr, &cpuInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get Cpu info: %s", error); - return false; + logResult(result, "Failed to get cpu information"); + return PAL_FALSE; } - // log platform information - palLog(nullptr, "Platform: %s", platformToString(platformInfo.type)); - palLog(nullptr, " Name: %s", platformInfo.name); - palLog(nullptr, " API: %s", platformApiToString(platformInfo.apiType)); - palLog(nullptr, " Total RAM: %llu MB", platformInfo.totalRAM); - palLog(nullptr, " Total Memory: %llu GB", platformInfo.totalMemory); - - uint16_t major, minor, build; - major = platformInfo.version.major; - minor = platformInfo.version.minor; - build = platformInfo.version.build; - palLog(nullptr, " Version: (%d.%d.%d)", major, minor, build); - - // log cpu information const char* archString = cpuArchToString(cpuInfo.architecture); int32_t processors = cpuInfo.numLogicalProcessors; @@ -162,5 +100,5 @@ PalBool systemTest() palLog(nullptr, " Instructions Sets: %s", instructionSets); - return true; + return PAL_TRUE; } diff --git a/tests/system/platform_test.c b/tests/system/platform_test.c new file mode 100644 index 00000000..f964e4f6 --- /dev/null +++ b/tests/system/platform_test.c @@ -0,0 +1,66 @@ + +#include "tests.h" +#include "pal/pal_system.h" + +static inline const char* platformToString(PalPlatformType type) +{ + switch (type) { + case PAL_PLATFORM_WINDOWS: + return "Windows"; + + case PAL_PLATFORM_LINUX: + return "Linux"; + + case PAL_PLATFORM_MACOS: + return "MacOs"; + + case PAL_PLATFORM_ANDROID: + return "Android"; + + case PAL_PLATFORM_IOS: + return "Ios"; + } + return nullptr; +} + +static inline const char* platformApiToString(PalPlatformApiType type) +{ + switch (type) { + case PAL_PLATFORM_API_WIN32: + return "Win32"; + + case PAL_PLATFORM_API_X11: + return "X11"; + + case PAL_PLATFORM_API_WAYLAND: + return "Wayland"; + } + return nullptr; +} + +PalBool platformTest() +{ + PalResult result; + PalPlatformInfo platformInfo; + + // get the platform info. Users must cache this + result = palGetPlatformInfo(&platformInfo); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get platform information"); + return PAL_FALSE; + } + + palLog(nullptr, "Platform: %s", platformToString(platformInfo.type)); + palLog(nullptr, " Name: %s", platformInfo.name); + palLog(nullptr, " API: %s", platformApiToString(platformInfo.apiType)); + palLog(nullptr, " Total RAM: %llu MB", platformInfo.totalRAM); + palLog(nullptr, " Total Memory: %llu GB", platformInfo.totalMemory); + + uint16_t major, minor, build; + major = platformInfo.version.major; + minor = platformInfo.version.minor; + build = platformInfo.version.build; + palLog(nullptr, " Version: (%d.%d.%d)", major, minor, build); + + return PAL_TRUE; +} diff --git a/tests/tests.h b/tests/tests.h index 03e79cc4..7ea10268 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -51,7 +51,8 @@ PalBool userEventTest(); PalBool eventTest(); // system tests -PalBool systemTest(); +PalBool platformTest(); +PalBool cpuTest(); // system tests PalBool threadTest(); diff --git a/tests/tests.lua b/tests/tests.lua index 789d54dd..ca867607 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -20,7 +20,8 @@ project "tests" if (PAL_BUILD_SYSTEM_MODULE) then files { - "system/system_test.c" + "system/platform_test.c", + "system/cpu_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 230769b5..3009ab1a 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -16,7 +16,8 @@ int main(int argc, char** argv) // registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE - // registerTest(systemTest, "System Test"); + registerTest(platformTest, "Platform Test"); + registerTest(cpuTest, "CPU Test"); #endif // PAL_HAS_SYSTEM_MODULE #if PAL_HAS_THREAD_MODULE diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c index 7d3e6043..58d1b5cd 100644 --- a/tools/abi_dump/core_abi_dump.c +++ b/tools/abi_dump/core_abi_dump.c @@ -14,12 +14,14 @@ static void versionDump() uint32_t xOffset1 = 0; uint32_t xOffset2 = 4; uint32_t xOffset3 = 8; + uint32_t xPadding = 0; uint32_t ySize = sizeof(PalVersion); uint32_t yAlign = PAL_ALIGNOF(PalVersion); uint32_t yOffset1 = offsetof(PalVersion, major); uint32_t yOffset2 = offsetof(PalVersion, minor); uint32_t yOffset3 = offsetof(PalVersion, build); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; const char* result = s_FailedString; // clang-format off @@ -27,7 +29,8 @@ static void versionDump() xAlign == yAlign && xOffset1 == yOffset1 && xOffset2 == yOffset2 && - xOffset3 == yOffset3) { + xOffset3 == yOffset3 && + xPadding == yPadding) { result = s_PassedString; } // clang-format on @@ -39,6 +42,7 @@ static void versionDump() palLog(nullptr, "size %u %u", xSize, ySize); palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); palLog(nullptr, "major @ %u %u", xOffset1, yOffset1); palLog(nullptr, "minor @ %u %u", xOffset2, yOffset2); palLog(nullptr, "build @ %u %u", xOffset3, yOffset3); @@ -55,12 +59,14 @@ static void allocatorDump() uint32_t xOffset1 = 0; uint32_t xOffset2 = 8; uint32_t xOffset3 = 16; + uint32_t xPadding = 0; uint32_t ySize = sizeof(PalAllocator); uint32_t yAlign = PAL_ALIGNOF(PalAllocator); uint32_t yOffset1 = offsetof(PalAllocator, allocate); uint32_t yOffset2 = offsetof(PalAllocator, free); uint32_t yOffset3 = offsetof(PalAllocator, userData); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; const char* result = s_FailedString; // clang-format off @@ -68,7 +74,8 @@ static void allocatorDump() xAlign == yAlign && xOffset1 == yOffset1 && xOffset2 == yOffset2 && - xOffset3 == yOffset3) { + xOffset3 == yOffset3 && + xPadding == yPadding) { result = s_PassedString; } // clang-format on @@ -80,6 +87,7 @@ static void allocatorDump() palLog(nullptr, "size %u %u", xSize, ySize); palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); palLog(nullptr, "allocate @ %u %u", xOffset1, yOffset1); palLog(nullptr, "free @ %u %u", xOffset2, yOffset2); palLog(nullptr, "userData @ %u %u", xOffset3, yOffset3); @@ -95,18 +103,21 @@ static void loggerDump() uint32_t xAlign = 8; uint32_t xOffset1 = 0; uint32_t xOffset2 = 8; + uint32_t xPadding = 0; uint32_t ySize = sizeof(PalLogger); uint32_t yAlign = PAL_ALIGNOF(PalLogger); uint32_t yOffset1 = offsetof(PalLogger, callback); uint32_t yOffset2 = offsetof(PalLogger, userData); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; const char* result = s_FailedString; // clang-format off if (xSize == ySize && xAlign == yAlign && xOffset1 == yOffset1 && - xOffset2 == yOffset2) { + xOffset2 == yOffset2 && + xPadding == yPadding) { result = s_PassedString; } // clang-format on @@ -118,6 +129,7 @@ static void loggerDump() palLog(nullptr, "size %u %u", xSize, ySize); palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); palLog(nullptr, "allocate @ %u %u", xOffset1, yOffset1); palLog(nullptr, "userData @ %u %u", xOffset2, yOffset2); palLog(nullptr, "==========================================="); diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index f99120e7..c73e6e2c 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -16,6 +16,7 @@ static void eventDump() uint32_t xOffset2 = 8; uint32_t xOffset3 = 16; uint32_t xOffset4 = 24; + uint32_t xPadding = 0; uint32_t ySize = sizeof(PalEvent); uint32_t yAlign = PAL_ALIGNOF(PalEvent); @@ -23,6 +24,7 @@ static void eventDump() uint32_t yOffset2 = offsetof(PalEvent, data); uint32_t yOffset3 = offsetof(PalEvent, data2); uint32_t yOffset4 = offsetof(PalEvent, type); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; const char* result = s_FailedString; // clang-format off @@ -31,7 +33,8 @@ static void eventDump() xOffset1 == yOffset1 && xOffset2 == yOffset2 && xOffset3 == yOffset3 && - xOffset4 == yOffset4) { + xOffset4 == yOffset4 && + xPadding == yPadding) { result = s_PassedString; } // clang-format on @@ -43,6 +46,7 @@ static void eventDump() palLog(nullptr, "size %u %u", xSize, ySize); palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); palLog(nullptr, "userId @ %u %u", xOffset1, yOffset1); palLog(nullptr, "data @ %u %u", xOffset2, yOffset2); palLog(nullptr, "data2 @ %u %u", xOffset3, yOffset3); @@ -60,12 +64,14 @@ static void eventQueueDump() uint32_t xOffset1 = 0; uint32_t xOffset2 = 8; uint32_t xOffset3 = 16; + uint32_t xPadding = 0; uint32_t ySize = sizeof(PalEventQueue); uint32_t yAlign = PAL_ALIGNOF(PalEventQueue); uint32_t yOffset1 = offsetof(PalEventQueue, push); uint32_t yOffset2 = offsetof(PalEventQueue, poll); uint32_t yOffset3 = offsetof(PalEventQueue, userData); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; const char* result = s_FailedString; // clang-format off @@ -73,7 +79,8 @@ static void eventQueueDump() xAlign == yAlign && xOffset1 == yOffset1 && xOffset2 == yOffset2 && - xOffset3 == yOffset3) { + xOffset3 == yOffset3 && + xPadding == yPadding) { result = s_PassedString; } // clang-format on @@ -85,6 +92,7 @@ static void eventQueueDump() palLog(nullptr, "size %u %u", xSize, ySize); palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); palLog(nullptr, "push @ %u %u", xOffset1, yOffset1); palLog(nullptr, "poll @ %u %u", xOffset2, yOffset2); palLog(nullptr, "userData @ %u %u", xOffset3, yOffset3); @@ -102,6 +110,7 @@ static void eventCreateInfoDump() uint32_t xOffset2 = 8; uint32_t xOffset3 = 16; uint32_t xOffset4 = 24; + uint32_t xPadding = 0; uint32_t ySize = sizeof(PalEventDriverCreateInfo); uint32_t yAlign = PAL_ALIGNOF(PalEventDriverCreateInfo); @@ -109,6 +118,7 @@ static void eventCreateInfoDump() uint32_t yOffset2 = offsetof(PalEventDriverCreateInfo, queue); uint32_t yOffset3 = offsetof(PalEventDriverCreateInfo, callback); uint32_t yOffset4 = offsetof(PalEventDriverCreateInfo, userData); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; const char* result = s_FailedString; // clang-format off @@ -117,7 +127,8 @@ static void eventCreateInfoDump() xOffset1 == yOffset1 && xOffset2 == yOffset2 && xOffset3 == yOffset3 && - xOffset4 == yOffset4) { + xOffset4 == yOffset4 && + xPadding == yPadding) { result = s_PassedString; } // clang-format on @@ -129,6 +140,7 @@ static void eventCreateInfoDump() palLog(nullptr, "size %u %u", xSize, ySize); palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); palLog(nullptr, "allocator @ %u %u", xOffset1, yOffset1); palLog(nullptr, "queue @ %u %u", xOffset2, yOffset2); palLog(nullptr, "callback @ %u %u", xOffset3, yOffset3); From ad9313e37e96d0ecb99bfdf510131c3c02c4f6d7 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 16 Jun 2026 09:36:21 +0000 Subject: [PATCH 268/372] test thread and system rewrite win32 --- pal_config.lua | 2 +- src/system/win32/pal_platform_win32.c | 14 +++++++------- src/thread/win32/pal_thread_win32.c | 6 +----- tests/tests_main.c | 14 +++++++------- tools/abi_dump/abi_dump_main.c | 23 +++++++++++++++++++---- tools/abi_dump/core_abi_dump.c | 2 +- tools/abi_dump/dumps.h | 6 +++--- tools/abi_dump/event_abi_dump.c | 2 +- tools/abi_dump/thread_abi_dump.c | 2 +- 9 files changed, 41 insertions(+), 30 deletions(-) diff --git a/pal_config.lua b/pal_config.lua index 095be764..78d521da 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -9,7 +9,7 @@ PAL_BUILD_TEST_APPLICATION = true PAL_BUILD_ABI_DUMP = true -- build system module -PAL_BUILD_SYSTEM_MODULE = true +PAL_BUILD_SYSTEM_MODULE = false -- build thread module PAL_BUILD_THREAD_MODULE = false diff --git a/src/system/win32/pal_platform_win32.c b/src/system/win32/pal_platform_win32.c index 4101b8fc..8f1f0c5a 100644 --- a/src/system/win32/pal_platform_win32.c +++ b/src/system/win32/pal_platform_win32.c @@ -33,17 +33,17 @@ static inline PalBool getVersionWin32(PalVersion* version) HINSTANCE ntdll = GetModuleHandleW(L"ntdll.dll"); RtlGetVersionFn getVer = (RtlGetVersionFn)GetProcAddress(ntdll, "RtlGetVersion"); if (!getVer) { - return false; + return PAL_FALSE; } if (getVer((PRTL_OSVERSIONINFOW)&ver)) { - return false; + return PAL_FALSE; } version->major = ver.dwMajorVersion; version->minor = ver.dwMinorVersion; version->build = ver.dwBuildNumber; - return true; + return PAL_TRUE; } static inline PalBool isVersionWin32( @@ -53,19 +53,19 @@ static inline PalBool isVersionWin32( uint32_t build) { if (osVersion->major > major) { - return true; + return PAL_TRUE; } if (osVersion->major < major) { - return false; + return PAL_FALSE; } if (osVersion->minor > minor) { - return true; + return PAL_TRUE; } if (osVersion->minor < minor) { - return false; + return PAL_FALSE; } return osVersion->build >= build; diff --git a/src/thread/win32/pal_thread_win32.c b/src/thread/win32/pal_thread_win32.c index 6f37f55e..42f81f8a 100644 --- a/src/thread/win32/pal_thread_win32.c +++ b/src/thread/win32/pal_thread_win32.c @@ -109,15 +109,11 @@ PalResult PAL_CALL palJoinThread( GetLastError()); } - // TODO: test - void* value = nullptr; DWORD wait = WaitForSingleObject((HANDLE)thread, INFINITE); if (wait == WAIT_OBJECT_0 && retval) { uintptr_t ret; GetExitCodeThread((HANDLE)thread, (LPDWORD)&ret); - void** out = (void**)retval; - *retval = - *out = value; + *retval = (void*)ret; // thread is done destroy the HANDLE CloseHandle((HANDLE)thread); diff --git a/tests/tests_main.c b/tests/tests_main.c index 3009ab1a..7c4d14f2 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -15,19 +15,19 @@ int main(int argc, char** argv) // registerTest(eventTest, "Event test"); // registerTest(userEventTest, "User Event Test"); -#if PAL_HAS_SYSTEM_MODULE +#if PAL_HAS_SYSTEM_MODULE == 1 registerTest(platformTest, "Platform Test"); registerTest(cpuTest, "CPU Test"); #endif // PAL_HAS_SYSTEM_MODULE -#if PAL_HAS_THREAD_MODULE +#if PAL_HAS_THREAD_MODULE == 1 registerTest(threadTest, "Thread Test"); registerTest(tlsTest, "TLS Test"); registerTest(mutexTest, "Mutex Test"); registerTest(condvarTest, "Condvar Test"); #endif // PAL_HAS_THREAD_MODULE -#if PAL_HAS_VIDEO_MODULE +#if PAL_HAS_VIDEO_MODULE == 1 // registerTest(videoTest, "Video Test"); // registerTest(monitorTest, "Monitor Test"); // registerTest(monitorModeTest, "Monitor Mode Test"); @@ -45,25 +45,25 @@ int main(int argc, char** argv) // This test can run without video system so long as your have a valid // window -#if PAL_HAS_OPENGL_MODULE && PAL_HAS_VIDEO_MODULE +#if PAL_HAS_OPENGL_MODULE == 1&& PAL_HAS_VIDEO_MODULE == 1 // registerTest(openglTest, "Opengl Test"); // registerTest(openglFBConfigTest, "Opengl FBConfig Test"); // registerTest(openglContextTest, "Context Test"); // registerTest(openglMultiContextTest, "Opengl Multi Context Test"); #endif // PAL_HAS_OPENGL_MODULE -#if PAL_HAS_OPENGL_MODULE && PAL_HAS_VIDEO_MODULE && PAL_HAS_THREAD_MODULE +#if PAL_HAS_OPENGL_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 && PAL_HAS_THREAD_MODULE == 1 // registerTest(multiThreadOpenGlTest, "Multi Thread Opengl Test"); #endif -#if PAL_HAS_GRAPHICS_MODULE +#if PAL_HAS_GRAPHICS_MODULE == 1 // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS_MODULE -#if PAL_HAS_GRAPHICS_MODULE && PAL_HAS_VIDEO_MODULE +#if PAL_HAS_GRAPHICS_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 0e58e6f7..094e1fe1 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -19,6 +19,7 @@ int main(int argc, char** argv) { // clang-format on + PalBool dumpAll = PAL_FALSE; PalBool dumpCore = PAL_FALSE; PalBool dumpEvent = PAL_FALSE; PalBool dumpThread = PAL_FALSE; @@ -30,7 +31,10 @@ int main(int argc, char** argv) PalBool dumpHelp = PAL_FALSE; for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "--core") == 0) { + if (strcmp(argv[i], "--all") == 0) { + dumpAll = PAL_TRUE; + + } else if (strcmp(argv[i], "--core") == 0) { dumpCore = PAL_TRUE; } else if (strcmp(argv[i], "--event") == 0) { @@ -59,16 +63,26 @@ int main(int argc, char** argv) } } + if (dumpAll) { + dumpCore = PAL_TRUE; + dumpEvent = PAL_TRUE; + dumpThread = PAL_TRUE; + dumpOpengl = PAL_TRUE; + dumpGraphics = PAL_TRUE; + dumpSystem = PAL_TRUE; + dumpVideo = PAL_TRUE; + } + if (dumpCore) { - dumpCoreABI(); + coreABIDump(); } if (dumpEvent) { - dumpEventABI(); + eventABIDump(); } if (dumpThread) { - dumpThreadABI(); + threadABIDump(); } if (dumpVersion) { @@ -80,6 +94,7 @@ int main(int argc, char** argv) palLog(nullptr, "Options:"); palLog(nullptr, " --help Display available options"); palLog(nullptr, " --version Display ABI dump version information"); + palLog(nullptr, " --all Display all PAL structs ABI information"); palLog(nullptr, " --core Display PAL core structs ABI information"); palLog(nullptr, " --event Display PAL event structs ABI information"); palLog(nullptr, " --graphics Display PAL graphics structs ABI information"); diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c index 58d1b5cd..455cfb79 100644 --- a/tools/abi_dump/core_abi_dump.c +++ b/tools/abi_dump/core_abi_dump.c @@ -138,7 +138,7 @@ static void loggerDump() palLog(nullptr, ""); } -void dumpCoreABI() +void coreABIDump() { palLog(nullptr, ""); palLog(nullptr, "==========================================="); diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index f12238cc..48f8e2ee 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -20,8 +20,8 @@ static const char* s_PassedString = "PASSED"; #define PAL_ALIGNOF(type) __alignof__(type) #endif // _MSC_VER -void dumpCoreABI(); -void dumpEventABI(); -void dumpThreadABI(); +void coreABIDump(); +void eventABIDump(); +void threadABIDump(); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index c73e6e2c..3d5f69c2 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -151,7 +151,7 @@ static void eventCreateInfoDump() palLog(nullptr, ""); } -void dumpEventABI() +void eventABIDump() { palLog(nullptr, ""); palLog(nullptr, "==========================================="); diff --git a/tools/abi_dump/thread_abi_dump.c b/tools/abi_dump/thread_abi_dump.c index 68871471..6419378e 100644 --- a/tools/abi_dump/thread_abi_dump.c +++ b/tools/abi_dump/thread_abi_dump.c @@ -8,7 +8,7 @@ #include "dumps.h" #include "pal/pal_thread.h" -void dumpThreadABI() +void threadABIDump() { palLog(nullptr, ""); palLog(nullptr, "==========================================="); From 85855bddc7775805b77917b6d9045ec18abd6bae Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 16 Jun 2026 15:32:58 +0000 Subject: [PATCH 269/372] expand video to multiple src files win32 --- CHANGELOG.md | 10 +- README.md | 2 +- include/pal/pal_event.h | 14 +- include/pal/pal_graphics.h | 342 +-- include/pal/pal_opengl.h | 47 +- include/pal/pal_thread.h | 2 +- include/pal/pal_video.h | 945 +++--- pal.lua | 16 +- pal_config.lua | 2 +- src/graphics/pal_d3d12.c | 266 +- src/graphics/pal_graphics.c | 40 +- src/graphics/pal_vulkan.c | 290 +- src/opengl/pal_opengl_linux.c | 48 +- src/opengl/pal_opengl_win32.c | 38 +- src/system/linux/pal_platform_linux.c | 5 +- src/video/pal_video_linux.c | 234 +- src/video/pal_video_win32.c | 3056 -------------------- src/video/win32/pal_cursor_win32.c | 333 +++ src/video/win32/pal_icon_win32.c | 141 + src/video/win32/pal_monitor_win32.c | 536 ++++ src/video/win32/pal_video_common_win32.h | 109 + src/video/win32/pal_video_win32.c | 1120 +++++++ src/video/win32/pal_window_win32.c | 1150 ++++++++ tests/graphics/clear_color_test.c | 119 +- tests/graphics/compute_test.c | 90 +- tests/graphics/descriptor_indexing_test.c | 231 +- tests/graphics/geometry_test.c | 141 +- tests/graphics/graphics_test.c | 34 +- tests/graphics/indirect_draw_test.c | 201 +- tests/graphics/mesh_test.c | 139 +- tests/graphics/multi_descriptor_set_test.c | 90 +- tests/graphics/ray_tracing_test.c | 176 +- tests/graphics/texture_test.c | 221 +- tests/graphics/triangle_test.c | 175 +- tests/opengl/multi_thread_opengl_test.c | 73 +- tests/opengl/opengl_context_test.c | 69 +- tests/opengl/opengl_fbconfig_test.c | 23 +- tests/opengl/opengl_multi_context_test.c | 81 +- tests/opengl/opengl_test.c | 9 +- tests/video/attach_window_test.c | 47 +- tests/video/char_event_test.c | 29 +- tests/video/cursor_test.c | 40 +- tests/video/custom_decoration_test.c | 38 +- tests/video/icon_test.c | 43 +- tests/video/input_window_test.c | 51 +- tests/video/monitor_mode_test.c | 44 +- tests/video/monitor_test.c | 27 +- tests/video/native_instance_test.c | 43 +- tests/video/native_integration_test.c | 59 +- tests/video/system_cursor_test.c | 40 +- tests/video/video_test.c | 89 +- tests/video/window_test.c | 33 +- 52 files changed, 5421 insertions(+), 5780 deletions(-) delete mode 100644 src/video/pal_video_win32.c create mode 100644 src/video/win32/pal_cursor_win32.c create mode 100644 src/video/win32/pal_icon_win32.c create mode 100644 src/video/win32/pal_monitor_win32.c create mode 100644 src/video/win32/pal_video_common_win32.h create mode 100644 src/video/win32/pal_video_win32.c create mode 100644 src/video/win32/pal_window_win32.c diff --git a/CHANGELOG.md b/CHANGELOG.md index dfc404a2..fa761f49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -153,6 +153,10 @@ palJoinThread(thread, &retval); - **Opengl:** **palEnumerateGLFBConfigs()** now does not take glWindow parameter anymore. +- **Video:** **palGetWindowHandleInfo()** now takes an info parameter. +- **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. +- **Video:** **palGetMouseWheelDelta()** now takes floats instead of uint32_t. + ### Removed - **Core:** Removed **PAL_RESULT_NULL_POINTER** result code. - **Core:** Removed **PAL_RESULT_INVALID_ALLOCATOR** result code. @@ -176,7 +180,11 @@ palJoinThread(thread, &retval); - **Core:** Removed **PAL_RESULT_INVALID_GL_CONTEXT** result code. - **Core:** Removed **PAL_RESULT_INVALID_FBCONFIG_BACKEND** result code. -- **Video:** Removed **palGetVideoFeaturesEx** functions. +- **Video:** Removed **palGetVideoFeaturesEx** function. +- **Video:** Removed **palGetWindowHandleInfoEx** function. +- **Video:** Removed **palGetRawMouseWheelDelta** function. + + ### Tests diff --git a/README.md b/README.md index f9afe225..8ce33eef 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ int main() { w.width = 640; w.height = 480; w.title = "Hello PAL"; - w.show = true; + w.show = PAL_TRUE; palCreateWindow(&w, &window); while (1) { diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 5b35927e..38e2db42 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -60,7 +60,7 @@ #define PAL_EVENT_WINDOW_STATE 3 /** - * event.data : `true` for focus gained or `false` for focus lost. + * event.data : `PAL_TRUE` for focus gained or `PAL_FALSE` for focus lost. * * event.data2 : window * @@ -70,7 +70,7 @@ #define PAL_EVENT_WINDOW_FOCUS 4 /** - * event.data : `true` for visible or `false` for hidden. + * event.data : `PAL_TRUE` for visible or `PAL_FALSE` for hidden. * * event.data2 : window * @@ -169,7 +169,7 @@ * event.data2 : window * * Use inline helpers: - * - palUnpackInt32() + * - palUnpackFloat() * - palUnpackPointer() */ #define PAL_EVENT_MOUSE_DELTA 16 @@ -180,7 +180,7 @@ * event.data2 : window * * Use inline helpers: - * - palUnpackInt32() + * - palUnpackFloat() * - palUnpackPointer() */ #define PAL_EVENT_MOUSE_WHEEL 17 @@ -318,9 +318,9 @@ typedef void(PAL_CALL* PalPushFn)( * @typedef PalPollFn * @brief Function pointer type used for polling events from event queues. * - * This function should return false if the event queue is empty. + * This function should return `PAL_FALSE` if the event queue is empty. * If the queue is not empty and the event was retrieved, this should return - * true. + * `PAL_TRUE`. * * @param[in] userData Optional pointer to user data. Can be nullptr. * @param[out] event Pointer to the PalEvent to recieve the event. @@ -495,7 +495,7 @@ PAL_API void PAL_CALL palPushEvent( * * This function retrieves the next pending event from the queue of the * provided event driver without blocking. If no events are available, it - * returns false. + * returns `PAL_FALSE`. * * @param[in] eventDriver Pointer to the event driver. * @param[out] outEvent Pointer to a PalEvent to recieve the event. Must be diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index c4615829..7936f4ce 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1,30 +1,13 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ /** * @defgroup pal_graphics Graphics - * Graphics PAL functionality such as Adapters, Device, Swapchains and more. - * + * @ingroup pal_graphics * @{ */ @@ -36,14 +19,12 @@ freely, subject to the following restrictions: /** * @brief The maximum name size of an adapter (GPU). * @since 1.4 - * @ingroup pal_graphics */ #define PAL_ADAPTER_NAME_SIZE 128 /** * @brief The maximum name size of a shader entry. * @since 1.4 - * @ingroup pal_graphics */ #define PAL_SHADER_ENTRY_NAME_SIZE 32 @@ -53,28 +34,24 @@ freely, subject to the following restrictions: /** * @brief A Unused shader index. Used to make a shader index invalid. * @since 1.4 - * @ingroup pal_graphics */ #define PAL_UNUSED_SHADER_INDEX UINT32_MAX /** * @brief An encoding scheme for shader format target versions. * @since 1.4 - * @ingroup pal_graphics */ #define PAL_MAKE_SHADER_TARGET(major, minor) ((uint32_t)((major) << 8) | (minor)) /** * @brief Get the major of an encoded shader target. * @since 1.4 - * @ingroup pal_graphics */ #define PAL_SHADER_TARGET_MAJOR(target) ((uint32_t)(target) >> 8); /** * @brief Get the minor of an encoded shader target. * @since 1.4 - * @ingroup pal_graphics */ #define PAL_SHADER_TARGET_MINOR(target) ((uint32_t)(target) & 0xFF); @@ -86,7 +63,6 @@ freely, subject to the following restrictions: * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef uint64_t PalAdapterFeatures; @@ -135,7 +111,6 @@ typedef uint64_t PalAdapterFeatures; * @brief Opaque handle to an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalAdapter PalAdapter; @@ -144,7 +119,6 @@ typedef struct PalAdapter PalAdapter; * @brief Opaque handle to a device. Devices are created from an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalDevice PalDevice; @@ -153,7 +127,6 @@ typedef struct PalDevice PalDevice; * @brief Opaque handle to a device memory. This is not `CPU` memory. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalMemory PalMemory; @@ -162,7 +135,6 @@ typedef struct PalMemory PalMemory; * @brief Opaque handle to a queue. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalQueue PalQueue; @@ -171,7 +143,6 @@ typedef struct PalQueue PalQueue; * @brief Opaque handle to a surface. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalSurface PalSurface; @@ -180,7 +151,6 @@ typedef struct PalSurface PalSurface; * @brief Opaque handle to a swapchain. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalSwapchain PalSwapchain; @@ -189,7 +159,6 @@ typedef struct PalSwapchain PalSwapchain; * @brief Opaque handle to an image. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalImage PalImage; @@ -198,7 +167,6 @@ typedef struct PalImage PalImage; * @brief Opaque handle to an image view. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalImageView PalImageView; @@ -207,7 +175,6 @@ typedef struct PalImageView PalImageView; * @brief Opaque handle to a shader. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalShader PalShader; @@ -216,7 +183,6 @@ typedef struct PalShader PalShader; * @brief Opaque handle to a buffer. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalBuffer PalBuffer; @@ -225,7 +191,6 @@ typedef struct PalBuffer PalBuffer; * @brief Opaque handle to a fence. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalFence PalFence; @@ -234,7 +199,6 @@ typedef struct PalFence PalFence; * @brief Opaque handle to a semaphore. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalSemaphore PalSemaphore; @@ -243,7 +207,6 @@ typedef struct PalSemaphore PalSemaphore; * @brief Opaque handle to a command pool. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalCommandPool PalCommandPool; @@ -252,7 +215,6 @@ typedef struct PalCommandPool PalCommandPool; * @brief Opaque handle to a command buffer. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalCommandBuffer PalCommandBuffer; @@ -267,7 +229,6 @@ typedef struct PalCommandBuffer PalCommandBuffer; * descriptorBindings[2] = { sampled image, sampler }. The ordering must be correct. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalDescriptorSetLayout PalDescriptorSetLayout; @@ -276,7 +237,6 @@ typedef struct PalDescriptorSetLayout PalDescriptorSetLayout; * @brief Opaque handle to a descriptor pool. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalDescriptorPool PalDescriptorPool; @@ -285,7 +245,6 @@ typedef struct PalDescriptorPool PalDescriptorPool; * @brief Opaque handle to a descriptor set. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalDescriptorSet PalDescriptorSet; @@ -294,7 +253,6 @@ typedef struct PalDescriptorSet PalDescriptorSet; * @brief Opaque handle to a sampler. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalSampler PalSampler; @@ -303,7 +261,6 @@ typedef struct PalSampler PalSampler; * @brief Opaque handle to a pipeline layout. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalPipelineLayout PalPipelineLayout; @@ -313,7 +270,6 @@ typedef struct PalPipelineLayout PalPipelineLayout; * (Graphics, Compute and Ray tracing). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalPipeline PalPipeline; @@ -322,7 +278,6 @@ typedef struct PalPipeline PalPipeline; * @brief Opaque handle to a shader binding table. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalShaderBindingTable PalShaderBindingTable; @@ -331,7 +286,6 @@ typedef struct PalShaderBindingTable PalShaderBindingTable; * @brief Opaque handle to an acceleration structure. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct PalAccelerationStructure PalAccelerationStructure; @@ -340,7 +294,6 @@ typedef struct PalAccelerationStructure PalAccelerationStructure; * @brief Debugger messages severity types used to filter incoming messages. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum PalDebugMessageSeverity PalDebugMessageSeverity; @@ -349,7 +302,6 @@ typedef enum PalDebugMessageSeverity PalDebugMessageSeverity; * @brief Debugger messages types used to filter incoming messages. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum PalDebugMessageType PalDebugMessageType; @@ -358,7 +310,6 @@ typedef enum PalDebugMessageType PalDebugMessageType; * @brief Adapter address. Used to get adapter (GPU) address of mostly buffers. * * @since 1.4 - * @ingroup pal_graphics */ typedef uint64_t PalDeviceAddress; @@ -374,7 +325,6 @@ typedef uint64_t PalDeviceAddress; * @param msg Null-terminated UTF-8 debug message. * * @since 1.4 - * @ingroup pal_graphics * @sa palInitGraphics */ typedef void(PAL_CALL* PalDebugCallback)( @@ -391,7 +341,6 @@ typedef void(PAL_CALL* PalDebugCallback)( * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_ADAPTER_TYPE_UNKNOWN, @@ -413,7 +362,6 @@ typedef enum { * core graphics system. These are custom backends that can be use to extend the graphics systems. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_ADAPTER_API_TYPE_VULKAN, @@ -434,7 +382,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_QUEUE_TYPE_GRAPHICS, @@ -450,7 +397,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_PRESENT_MODE_FIFO, /**< V-Sync.*/ @@ -468,7 +414,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_COMPOSITE_ALPHA_OPAQUE, /**< Default behavior.*/ @@ -486,7 +431,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_FORMAT_UNDEFINED, @@ -584,7 +528,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_IMAGE_USAGE_UNDEFINED = 0, @@ -605,7 +548,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_SHADER_FORMAT_SPIRV = (1ULL << 0), @@ -624,7 +566,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_LOAD_OP_LOAD, @@ -640,7 +581,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_STORE_OP_STORE, @@ -655,7 +595,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_MEMORY_TYPE_GPU_ONLY, @@ -673,7 +612,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_IMAGE_TYPE_1D, @@ -689,7 +627,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_IMAGE_ASPECT_COLOR, @@ -706,7 +643,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_IMAGE_VIEW_TYPE_1D, @@ -726,7 +662,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_FILTER_MODE_NEAREST, @@ -741,7 +676,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_SAMPLER_MIPMAP_MODE_NEAREST, @@ -756,7 +690,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_SAMPLER_ADDRESS_MODE_REPEAT, @@ -773,7 +706,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, @@ -792,7 +724,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR, @@ -811,7 +742,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND, @@ -827,7 +757,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_SHADER_STAGE_UNDEFINED, @@ -856,7 +785,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_SAMPLE_COUNT_1, @@ -876,7 +804,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, @@ -895,7 +822,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_CULL_MODE_NONE, @@ -911,7 +837,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_FRONT_FACE_CLOCKWISE, @@ -926,7 +851,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_POLYGON_MODE_FILL, @@ -942,7 +866,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_STENCIL_FACE_FRONT = (1ULL << 0), @@ -958,7 +881,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_VERTEX_TYPE_UNDEFINED, @@ -1010,7 +932,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_VERTEX_SEMANTIC_ID_POSITION, @@ -1028,7 +949,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_COMMAND_BUFFER_TYPE_PRIMARY, @@ -1043,7 +963,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX, @@ -1058,7 +977,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_COMPARE_OP_NEVER, @@ -1079,7 +997,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_STENCIL_OP_KEEP, @@ -1100,7 +1017,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_BLEND_OP_ADD, @@ -1118,7 +1034,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_BLEND_FACTOR_ZERO, @@ -1148,7 +1063,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_COLOR_MASK_NONE = 0, @@ -1167,7 +1081,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_RESOLVE_MODE_NONE = 0, @@ -1186,7 +1099,6 @@ typedef enum { * consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_FRAGMENT_SHADING_RATE_1X1, @@ -1208,7 +1120,6 @@ typedef enum { * `PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_**` for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP, @@ -1226,7 +1137,6 @@ typedef enum { * for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL, @@ -1241,7 +1151,6 @@ typedef enum { * `PAL_ACCELERATION_STRUCTURE_BUILD_MODE_**` for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD, @@ -1257,7 +1166,6 @@ typedef enum { * `PAL_ACCELERATION_STRUCTURE_BUILD_HINT_**` for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD = (1ULL << 0), @@ -1274,7 +1182,6 @@ typedef enum { * `PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_**` for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE = (1ULL << 0), @@ -1290,7 +1197,6 @@ typedef enum { * All geometry types follow the format `PAL_GEOMETRY_TYPE_**` for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_GEOMETRY_TYPE_TRIANGLE, @@ -1305,7 +1211,6 @@ typedef enum { * All geometry flags follow the format `PAL_GEOMETRY_FLAG_**` for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_GEOMETRY_FLAG_OPAQUE = (1ULL << 0), @@ -1319,7 +1224,6 @@ typedef enum { * All index types follow the format `PAL_INDEX_TYPE_**` for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_INDEX_TYPE_UINT16, @@ -1334,7 +1238,6 @@ typedef enum { * All buffer usages follow the format `PAL_BUFFER_USAGE_**` for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_BUFFER_USAGE_VERTEX = (1ULL << 0), @@ -1369,7 +1272,6 @@ enum PalDebugMessageType { * All usage states follow the format `PAL_USAGE_STATE_**` for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_USAGE_STATE_UNDEFINED, @@ -1404,7 +1306,6 @@ typedef enum { * All descriptor types follow the format `PAL_DESCRIPTOR_TYPE_**` for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER, @@ -1423,7 +1324,6 @@ typedef enum { * for consistency and API use. * * @since 1.4 - * @ingroup pal_graphics */ typedef enum { PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL, @@ -1436,7 +1336,6 @@ typedef enum { * @brief Information about an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t vendorId; @@ -1455,7 +1354,6 @@ typedef struct { * @brief Image capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t maxWidth; @@ -1470,7 +1368,6 @@ typedef struct { * @brief Resource capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool sampledImageDynamicArrayIndexing; @@ -1497,7 +1394,6 @@ typedef struct { * @brief Compute capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t maxWorkGroupInvocations; @@ -1510,7 +1406,6 @@ typedef struct { * @brief Viewport capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t maxWidth; @@ -1524,7 +1419,6 @@ typedef struct { * @brief Capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t maxComputeQueues; @@ -1548,7 +1442,6 @@ typedef struct { * @brief Sampler anisotropy capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t maxAnisotropy; @@ -1559,7 +1452,6 @@ typedef struct { * @brief Multi view capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t maxViewCount; @@ -1570,7 +1462,6 @@ typedef struct { * @brief Multi viewport capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t maxCount; @@ -1581,7 +1472,6 @@ typedef struct { * @brief Depth stencil capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool independentResolve; @@ -1594,7 +1484,6 @@ typedef struct { * @brief Fragment shading rate capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; @@ -1610,7 +1499,6 @@ typedef struct { * @brief Mesh shader capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t maxOutputPrimitives; @@ -1626,7 +1514,6 @@ typedef struct { * @brief Ray tracing capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t maxRecursionDepth; @@ -1643,7 +1530,6 @@ typedef struct { * @brief Descriptor indexing capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool sampledImageNonUniformIndexing; @@ -1673,7 +1559,6 @@ typedef struct { * @brief surface capabilities of an adapter (GPU). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool presentModes[PAL_PRESENT_MODE_MAX]; @@ -1696,7 +1581,6 @@ typedef struct { * holding native handles. The handles will not be copied. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalGraphicsWindowDisplayType displayType; /**< Will be used only on linux platform.*/ @@ -1710,7 +1594,6 @@ typedef struct { * count from the provided format. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalFormat format; @@ -1723,7 +1606,6 @@ typedef struct { * @brief Information about an image. This can be a swapchain image. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t width; /**< Width of the image in pixels.*/ @@ -1744,7 +1626,6 @@ typedef struct { * will be used with depth stencil attachments. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { float color[4]; /**< Color for color attachments only.*/ @@ -1759,7 +1640,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalLoadOp loadOp; @@ -1781,7 +1661,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t shaderStageCount; @@ -1794,7 +1673,6 @@ typedef struct { * @brief A viewport in pixels (float). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { float x; @@ -1810,7 +1688,6 @@ typedef struct { * @brief A 2D rectangle in pixels. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { int32_t x; @@ -1824,7 +1701,6 @@ typedef struct { * @brief Memory requirements for a resource (image, buffer etc). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool memoryTypes[PAL_MEMORY_TYPE_MAX]; @@ -1840,7 +1716,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint64_t waitValue; @@ -1858,7 +1733,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint64_t timeout; /**< Timeout in milliseconds.*/ @@ -1874,7 +1748,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t imageIndex; /**< Image index to present. Must be 0 and less than max images.*/ @@ -1889,7 +1762,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ @@ -1907,7 +1779,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ @@ -1926,7 +1797,6 @@ typedef struct { * vertices etc.Eg. an image of 800 x 600 will be [0] = 800, [1] = 600 and [2] = 1. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t workCount[3]; @@ -1939,7 +1809,6 @@ typedef struct { * @brief Information about compute or mesh(or task) dispatch data or a dispatch tile. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t workGroupBase[3]; /**< Offset per axis of a dispatch tile.*/ @@ -1953,7 +1822,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t vertexCount; @@ -1969,7 +1837,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t indexCount; @@ -1986,7 +1853,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t groupCountXOrWidth; /**< Number of groups on the x axis or width.*/ @@ -2003,7 +1869,6 @@ typedef struct { * semanticID` which are (`POSITION`, `COLOR`, `TEXCOORD`, `NORMAL` and `TANGENT`). * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalVertexSemanticID semanticID; @@ -2024,7 +1889,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalVertexLayoutType type; @@ -2040,7 +1904,6 @@ typedef struct { * The debugger will not be initialized if PalGraphicsDebugger::callback is set and valid. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool denyGeneral; @@ -2060,7 +1923,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool enableDepthClamp; @@ -2080,7 +1942,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool enableSampleShading; @@ -2097,7 +1958,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalStencilOp failOp; @@ -2113,7 +1973,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool enableDepthTest; @@ -2134,7 +1993,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool enableBlend; @@ -2154,7 +2012,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalFragmentShadingRate rate; @@ -2168,7 +2025,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t instanceId; @@ -2184,7 +2040,6 @@ typedef struct { * @brief Acceleration structure build size. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t accelerationStructureSize; @@ -2199,7 +2054,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalVertexType vertexType; @@ -2218,7 +2072,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t stride; @@ -2232,7 +2085,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalGeometryFlags flags; @@ -2248,7 +2100,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalAccelerationStructureType type; @@ -2270,7 +2121,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t descriptorCount; @@ -2285,7 +2135,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t bindingCount; @@ -2299,7 +2148,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t size; @@ -2315,7 +2163,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalImageView* imageView; @@ -2328,7 +2175,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalSampler* sampler; @@ -2341,7 +2187,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalAccelerationStructure* tlas; @@ -2354,7 +2199,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t layoutBindingIndex; /**< Index into the descriptor set layout bindings.*/ @@ -2375,7 +2219,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint64_t offset; @@ -2391,7 +2234,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t startMipLevel; @@ -2408,7 +2250,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t size; @@ -2423,7 +2264,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint64_t bufferOffset; @@ -2448,7 +2288,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t dstMipLevel; @@ -2477,7 +2316,6 @@ typedef struct { * The records array must be in this order [raygen][miss][hitgroup][callable]. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t groupIndex; /**< Index into the shader groups used to create the ray tracing pipeline.*/ @@ -2492,7 +2330,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ @@ -2507,7 +2344,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t width; @@ -2527,7 +2363,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalFormat format; /**< Must be compatible with the image format.*/ @@ -2542,7 +2377,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool enableCompare; @@ -2568,7 +2402,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool clipped; @@ -2588,7 +2421,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t entryCount; @@ -2604,7 +2436,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBufferUsages usages; @@ -2618,7 +2449,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalAccelerationStructureType type; @@ -2632,10 +2462,9 @@ typedef struct { * @brief Creation parameters for a descriptor set layout. * * Uninitialized fields may result in undefined behavior. Set `enableDescriptorIndexing` to - * true to enable descriptor indexing for the descriptor set layout. + * `PAL_TRUE` to enable descriptor indexing for the descriptor set layout. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool enableDescriptorIndexing; @@ -2650,10 +2479,9 @@ typedef struct { * @brief Creation parameters for a descriptor pool. * * Uninitialized fields may result in undefined behavior. Set `enableDescriptorIndexing` to - * true to enable descriptor indexing for the descriptor pool. + * `PAL_TRUE` to enable descriptor indexing for the descriptor pool. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool enableDescriptorIndexing; @@ -2669,7 +2497,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t descriptorSetLayoutCount; @@ -2685,14 +2512,13 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalBool primitiveRestartEnable; uint32_t vertexLayoutCount; uint32_t colorBlendAttachmentCount; uint32_t shaderCount; - PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is true.*/ + PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is `PAL_TRUE`.*/ PalPrimitiveTopology topology; PalPipelineLayout* pipelineLayout; PalShader** shaders; @@ -2712,7 +2538,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalPipelineLayout* pipelineLayout; @@ -2728,7 +2553,6 @@ typedef struct { * The shader group array must be in this order [raygen][miss][hitgroup][callable]. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { PalRayTracingShaderGroupType type; @@ -2750,7 +2574,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t shaderCount; @@ -2770,7 +2593,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { uint32_t recordCount; @@ -2785,7 +2607,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.4 - * @ingroup pal_graphics */ typedef struct { /** @@ -4091,7 +3912,6 @@ typedef struct { * Thread safety: Must only be called from the main thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palInitGraphics * @sa palShutdownGraphics */ @@ -4121,7 +3941,6 @@ PAL_API PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backe * Thread safety: Must only be called from the main thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palAddGraphicsBackend * @sa palShutdownGraphics */ @@ -4138,7 +3957,6 @@ PAL_API PalResult PAL_CALL palInitGraphics( * Thread safety: Must only be called from the main thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palInitGraphics */ PAL_API void PAL_CALL palShutdownGraphics(); @@ -4173,7 +3991,6 @@ PAL_API void PAL_CALL palShutdownGraphics(); * Thread safety: Must only be called from the main thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palEnumerateAdapters( int32_t* count, @@ -4193,7 +4010,6 @@ PAL_API PalResult PAL_CALL palEnumerateAdapters( * Thread safety: Thread safe if `info` is per thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palEnumerateAdapters */ PAL_API PalResult PAL_CALL palGetAdapterInfo( @@ -4214,7 +4030,6 @@ PAL_API PalResult PAL_CALL palGetAdapterInfo( * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palEnumerateAdapters */ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( @@ -4233,7 +4048,6 @@ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( * Thread safety: Thread safe. * * @since 1.4 - * @ingroup pal_graphics * @sa palEnumerateAdapters */ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); @@ -4252,7 +4066,6 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); * Thread safety: Thread safe. * * @since 1.4 - * @ingroup pal_graphics * @sa palEnumerateAdapters */ PAL_API uint32_t PAL_CALL palGetHighestSupportedShaderTarget( @@ -4279,7 +4092,6 @@ PAL_API uint32_t PAL_CALL palGetHighestSupportedShaderTarget( * Thread safety: Thread safe if `adapter` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyDevice */ PAL_API PalResult PAL_CALL palCreateDevice( @@ -4300,7 +4112,6 @@ PAL_API PalResult PAL_CALL palCreateDevice( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateDevice */ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); @@ -4326,7 +4137,6 @@ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); * `outMemory` is per thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palFreeMemory */ PAL_API PalResult PAL_CALL palAllocateMemory( @@ -4349,7 +4159,6 @@ PAL_API PalResult PAL_CALL palAllocateMemory( * `outMemory` is per thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palAllocateMemory */ PAL_API void PAL_CALL palFreeMemory( @@ -4373,7 +4182,6 @@ PAL_API void PAL_CALL palFreeMemory( * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( PalDevice* device, @@ -4396,7 +4204,6 @@ PAL_API PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palQueryMultiViewCapabilities( PalDevice* device, @@ -4419,7 +4226,6 @@ PAL_API PalResult PAL_CALL palQueryMultiViewCapabilities( * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palQueryMultiViewportCapabilities( PalDevice* device, @@ -4442,7 +4248,6 @@ PAL_API PalResult PAL_CALL palQueryMultiViewportCapabilities( * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, @@ -4465,7 +4270,6 @@ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( PalDevice* device, @@ -4488,7 +4292,6 @@ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( PalDevice* device, @@ -4511,7 +4314,6 @@ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( PalDevice* device, @@ -4534,7 +4336,6 @@ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( PalDevice* device, @@ -4564,7 +4365,6 @@ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyQueue */ PAL_API PalResult PAL_CALL palCreateQueue( @@ -4585,7 +4385,6 @@ PAL_API PalResult PAL_CALL palCreateQueue( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateQueue */ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); @@ -4598,12 +4397,11 @@ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); * @param[in] queue Queue to query. * @param[in] surface Surface to check presentation support for. * - * @return True if queue can present otherwise false if queue can not present. + * @return True if queue can present otherwise `PAL_FALSE` if queue can not present. * * Thread safety: Must only be called from the main thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateQueue */ PAL_API PalBool PAL_CALL palCanQueuePresent( @@ -4626,7 +4424,6 @@ PAL_API PalBool PAL_CALL palCanQueuePresent( * Thread safety: Thread safe if `queue` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); @@ -4656,7 +4453,6 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); * Thread safety: Thread safe if `outFormats` is per thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palIsFormatSupported */ PAL_API PalResult PAL_CALL palEnumerateFormats( @@ -4676,12 +4472,11 @@ PAL_API PalResult PAL_CALL palEnumerateFormats( * @param[in] adapter Adapter to query format on. * @param[in] format Format to query support for. * - * @return True if format is supported otherwise false if not supported. + * @return True if format is supported otherwise `PAL_FALSE` if not supported. * * Thread safety: Thread safe. * * @since 1.4 - * @ingroup pal_graphics * @sa palQueryFormatImageUsages * @sa palQueryFormatImageViewUsages */ @@ -4702,7 +4497,6 @@ PAL_API PalBool PAL_CALL palIsFormatSupported( * Thread safety: Thread safe. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalImageUsages PAL_CALL palQueryFormatImageUsages( PalAdapter* adapter, @@ -4721,7 +4515,6 @@ PAL_API PalImageUsages PAL_CALL palQueryFormatImageUsages( * Thread safety: Thread safe. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalSampleCount PAL_CALL palQueryFormatSampleCount( PalAdapter* adapter, @@ -4747,7 +4540,6 @@ PAL_API PalSampleCount PAL_CALL palQueryFormatSampleCount( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyImage */ PAL_API PalResult PAL_CALL palCreateImage( @@ -4768,7 +4560,6 @@ PAL_API PalResult PAL_CALL palCreateImage( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateImage */ PAL_API void PAL_CALL palDestroyImage(PalImage* image); @@ -4788,7 +4579,6 @@ PAL_API void PAL_CALL palDestroyImage(PalImage* image); * Thread safety: Thread safe if `info` is per thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateImage */ PAL_API PalResult PAL_CALL palGetImageInfo( @@ -4809,7 +4599,6 @@ PAL_API PalResult PAL_CALL palGetImageInfo( * Thread safety: Thread safe if `requirements` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( PalImage* image, @@ -4832,7 +4621,6 @@ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( * Thread safety: Thread safe if `requirements` is per thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palGetImageMemoryRequirements */ PAL_API PalResult PAL_CALL palBindImageMemory( @@ -4864,7 +4652,6 @@ PAL_API PalResult PAL_CALL palBindImageMemory( * is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palUnmapImageMemory */ PAL_API PalResult PAL_CALL palMapImageMemory( @@ -4884,7 +4671,6 @@ PAL_API PalResult PAL_CALL palMapImageMemory( * Thread safety: Thread safe if `image` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palMapImageMemory */ PAL_API void PAL_CALL palUnmapImageMemory(PalImage* image); @@ -4913,7 +4699,6 @@ PAL_API void PAL_CALL palUnmapImageMemory(PalImage* image); * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyImageView */ PAL_API PalResult PAL_CALL palCreateImageView( @@ -4935,7 +4720,6 @@ PAL_API PalResult PAL_CALL palCreateImageView( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateImageView */ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); @@ -4958,7 +4742,6 @@ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroySampler */ PAL_API PalResult PAL_CALL palCreateSampler( @@ -4979,7 +4762,6 @@ PAL_API PalResult PAL_CALL palCreateSampler( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateSampler */ PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); @@ -5002,7 +4784,6 @@ PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroySurface */ PAL_API PalResult PAL_CALL palCreateSurface( @@ -5023,7 +4804,6 @@ PAL_API PalResult PAL_CALL palCreateSurface( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateSurface */ PAL_API void PAL_CALL palDestroySurface(PalSurface* surface); @@ -5046,7 +4826,6 @@ PAL_API void PAL_CALL palDestroySurface(PalSurface* surface); * Thread safety: Thread safe if `caps` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palGetSurfaceCapabilities( PalDevice* device, @@ -5074,7 +4853,6 @@ PAL_API PalResult PAL_CALL palGetSurfaceCapabilities( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroySwapchain */ PAL_API PalResult PAL_CALL palCreateSwapchain( @@ -5097,7 +4875,6 @@ PAL_API PalResult PAL_CALL palCreateSwapchain( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateSwapchain */ PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); @@ -5115,7 +4892,6 @@ PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); * Thread safety: Thread safe. * * @since 1.4 - * @ingroup pal_graphics * @sa palGetNextSwapchainImage */ PAL_API PalImage* PAL_CALL palGetSwapchainImage( @@ -5138,7 +4914,6 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( * Thread safety: Thread safe if `swapchain` externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palGetSwapchainImage */ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( @@ -5161,7 +4936,6 @@ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( * Thread safety: Must only be called from the main thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, @@ -5185,7 +4959,6 @@ PAL_API PalResult PAL_CALL palPresentSwapchain( * Thread safety: Thread safe if `swapchain` externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palResizeSwapchain( PalSwapchain* swapchain, @@ -5225,7 +4998,6 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * @note The shader entry name must not be greater than `PAL_SHADER_ENTRY_NAME_SIZE (32)`. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyShader */ PAL_API PalResult PAL_CALL palCreateShader( @@ -5246,7 +5018,6 @@ PAL_API PalResult PAL_CALL palCreateShader( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateShader */ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); @@ -5267,7 +5038,6 @@ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyFence */ PAL_API PalResult PAL_CALL palCreateFence( @@ -5288,7 +5058,6 @@ PAL_API PalResult PAL_CALL palCreateFence( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateFence */ PAL_API void PAL_CALL palDestroyFence(PalFence* fence); @@ -5310,7 +5079,6 @@ PAL_API void PAL_CALL palDestroyFence(PalFence* fence); * Thread safety: Thread safe if `fence` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palIsFenceSignaled */ PAL_API PalResult PAL_CALL palWaitFence( @@ -5333,7 +5101,6 @@ PAL_API PalResult PAL_CALL palWaitFence( * Thread safety: Thread safe if `fence` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palIsFenceSignaled */ PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); @@ -5345,12 +5112,11 @@ PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); * * @param[in] fence Fence to check. * - * @return True if signaled otherwise false. + * @return True if signaled otherwise `PAL_FALSE`. * * Thread safety: Thread safe. * * @since 1.4 - * @ingroup pal_graphics * @sa palResetFence * @sa palWaitFence */ @@ -5372,7 +5138,6 @@ PAL_API PalBool PAL_CALL palIsFenceSignaled(PalFence* fence); * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroySemaphore */ PAL_API PalResult PAL_CALL palCreateSemaphore( @@ -5393,7 +5158,6 @@ PAL_API PalResult PAL_CALL palCreateSemaphore( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateSemaphore */ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); @@ -5416,7 +5180,6 @@ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); * Thread safety: Thread safe if `semaphore` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palSignalSemaphore * @sa palGetSemaphoreValue */ @@ -5443,7 +5206,6 @@ PAL_API PalResult PAL_CALL palWaitSemaphore( * Thread safety: Thread safe if `queue` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palWaitSemaphore * @sa palGetSemaphoreValue */ @@ -5469,7 +5231,6 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * Thread safety: Thread safe if `semaphore` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palWaitSemaphore * @sa palSignalSemaphore */ @@ -5492,7 +5253,6 @@ PAL_API PalResult PAL_CALL palGetSemaphoreValue( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyCommandPool */ PAL_API PalResult PAL_CALL palCreateCommandPool( @@ -5515,7 +5275,6 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateCommandPool */ PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); @@ -5533,7 +5292,6 @@ PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); * Thread safety: Thread safe if `pool` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); @@ -5553,7 +5311,6 @@ PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); * Thread safety: Thread safe if `device` and `pool` are externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palFreeCommandBuffer */ PAL_API PalResult PAL_CALL palAllocateCommandBuffer( @@ -5575,7 +5332,6 @@ PAL_API PalResult PAL_CALL palAllocateCommandBuffer( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palAllocateCommandBuffer */ PAL_API void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -5593,7 +5349,6 @@ PAL_API void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer); * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -5613,7 +5368,6 @@ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); * Thread safety: Thread safe if `queue` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, @@ -5633,7 +5387,6 @@ PAL_API PalResult PAL_CALL palSubmitCommandBuffer( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCmdEnd */ PAL_API PalResult PAL_CALL palCmdBegin( @@ -5653,7 +5406,6 @@ PAL_API PalResult PAL_CALL palCmdBegin( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCmdBegin */ PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); @@ -5673,7 +5425,6 @@ PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); * Thread safety: Thread safe if `primaryCmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, @@ -5697,7 +5448,6 @@ PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( PalCommandBuffer* cmdBuffer, @@ -5724,7 +5474,6 @@ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( @@ -5756,7 +5505,6 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 - * @ingroup pal_graphics * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( @@ -5788,7 +5536,6 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 - * @ingroup pal_graphics * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( @@ -5815,7 +5562,6 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, @@ -5836,7 +5582,6 @@ PAL_API PalResult PAL_CALL palCmdBuildAccelerationStructure( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdBeginRendering( PalCommandBuffer* cmdBuffer, @@ -5855,7 +5600,6 @@ PAL_API PalResult PAL_CALL palCmdBeginRendering( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); @@ -5879,7 +5623,6 @@ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdCopyBuffer( PalCommandBuffer* cmdBuffer, @@ -5904,7 +5647,6 @@ PAL_API PalResult PAL_CALL palCmdCopyBuffer( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdCopyBufferToImage( PalCommandBuffer* cmdBuffer, @@ -5929,7 +5671,6 @@ PAL_API PalResult PAL_CALL palCmdCopyBufferToImage( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdCopyImage( PalCommandBuffer* cmdBuffer, @@ -5954,7 +5695,6 @@ PAL_API PalResult PAL_CALL palCmdCopyImage( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( PalCommandBuffer* cmdBuffer, @@ -5977,7 +5717,6 @@ PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, @@ -5999,7 +5738,6 @@ PAL_API PalResult PAL_CALL palCmdBindPipeline( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdSetViewport( PalCommandBuffer* cmdBuffer, @@ -6022,7 +5760,6 @@ PAL_API PalResult PAL_CALL palCmdSetViewport( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdSetScissors( PalCommandBuffer* cmdBuffer, @@ -6049,7 +5786,6 @@ PAL_API PalResult PAL_CALL palCmdSetScissors( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, @@ -6076,7 +5812,6 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( PalCommandBuffer* cmdBuffer, @@ -6103,7 +5838,6 @@ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics * @sa palDrawIndexed */ PAL_API PalResult PAL_CALL palCmdDraw( @@ -6135,7 +5869,6 @@ PAL_API PalResult PAL_CALL palCmdDraw( * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 - * @ingroup pal_graphics * @sa palDrawIndexedIndirect */ PAL_API PalResult PAL_CALL palCmdDrawIndirect( @@ -6166,7 +5899,6 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirect( * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 - * @ingroup pal_graphics * @sa palCmdDrawIndexedIndirectCount */ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( @@ -6195,7 +5927,6 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics * @sa palDraw */ PAL_API PalResult PAL_CALL palCmdDrawIndexed( @@ -6228,7 +5959,6 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexed( * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 - * @ingroup pal_graphics * @sa palDrawIndirect */ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( @@ -6259,7 +5989,6 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 - * @ingroup pal_graphics * @sa palCmdDrawIndirectCount */ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( @@ -6309,7 +6038,6 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics * @sa palCmdImageBarrier * @sa palCmdBufferBarrier */ @@ -6353,7 +6081,6 @@ PAL_API PalResult PAL_CALL palCmdAccelerationStructureBarrier( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCmdAccelerationStructureBarrier * @sa palCmdBufferBarrier */ @@ -6397,7 +6124,6 @@ PAL_API PalResult PAL_CALL palCmdImageBarrier( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCmdAccelerationStructureBarrier * @sa palCmdImageBarrier */ @@ -6425,7 +6151,6 @@ PAL_API PalResult PAL_CALL palCmdBufferBarrier( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDispatch( @@ -6458,7 +6183,6 @@ PAL_API PalResult PAL_CALL palCmdDispatch( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDispatchBase( @@ -6490,7 +6214,6 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 - * @ingroup pal_graphics * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( @@ -6520,7 +6243,6 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, @@ -6555,7 +6277,6 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, @@ -6580,7 +6301,6 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, @@ -6607,7 +6327,6 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( * @note A pipeline must be bound before this call. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, @@ -6634,7 +6353,6 @@ PAL_API PalResult PAL_CALL palCmdPushConstants( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdSetCullMode( PalCommandBuffer* cmdBuffer, @@ -6657,7 +6375,6 @@ PAL_API PalResult PAL_CALL palCmdSetCullMode( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdSetFrontFace( PalCommandBuffer* cmdBuffer, @@ -6680,7 +6397,6 @@ PAL_API PalResult PAL_CALL palCmdSetFrontFace( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdSetPrimitiveTopology( PalCommandBuffer* cmdBuffer, @@ -6703,7 +6419,6 @@ PAL_API PalResult PAL_CALL palCmdSetPrimitiveTopology( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdSetDepthTestEnable( PalCommandBuffer* cmdBuffer, @@ -6726,7 +6441,6 @@ PAL_API PalResult PAL_CALL palCmdSetDepthTestEnable( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdSetDepthWriteEnable( PalCommandBuffer* cmdBuffer, @@ -6753,7 +6467,6 @@ PAL_API PalResult PAL_CALL palCmdSetDepthWriteEnable( * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palCmdSetStencilOp( PalCommandBuffer* cmdBuffer, @@ -6786,7 +6499,6 @@ PAL_API PalResult PAL_CALL palCmdSetStencilOp( * `PAL_MEMORY_TYPE_GPU_ONLY`. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyAccelerationstructure */ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( @@ -6807,7 +6519,6 @@ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateAccelerationstructure */ PAL_API void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* as); @@ -6833,7 +6544,6 @@ PAL_API void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( PalDevice* device, @@ -6866,7 +6576,6 @@ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyBuffer */ PAL_API PalResult PAL_CALL palCreateBuffer( @@ -6887,7 +6596,6 @@ PAL_API PalResult PAL_CALL palCreateBuffer( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateBuffer */ PAL_API void PAL_CALL palDestroyBuffer(PalBuffer* buffer); @@ -6906,7 +6614,6 @@ PAL_API void PAL_CALL palDestroyBuffer(PalBuffer* buffer); * Thread safety: Thread safe if `requirements` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( PalBuffer* buffer, @@ -6933,7 +6640,6 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( PalDevice* device, @@ -6969,7 +6675,6 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( PalDevice* device, @@ -6996,7 +6701,6 @@ PAL_API PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( PalDevice* device, @@ -7022,7 +6726,6 @@ PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palWriteToImageCopyStagingBuffer( PalDevice* device, @@ -7048,7 +6751,6 @@ PAL_API PalResult PAL_CALL palWriteToImageCopyStagingBuffer( * Thread safety: Thread safe if `requirements` is per thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palGetBufferMemoryRequirements */ PAL_API PalResult PAL_CALL palBindBufferMemory( @@ -7080,7 +6782,6 @@ PAL_API PalResult PAL_CALL palBindBufferMemory( * is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palUnmapBufferMemory */ PAL_API PalResult PAL_CALL palMapBufferMemory( @@ -7100,7 +6801,6 @@ PAL_API PalResult PAL_CALL palMapBufferMemory( * Thread safety: Thread safe if `buffer` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palMapBufferMemory */ PAL_API void PAL_CALL palUnmapBufferMemory(PalBuffer* buffer); @@ -7118,7 +6818,6 @@ PAL_API void PAL_CALL palUnmapBufferMemory(PalBuffer* buffer); * Thread safety: Thread safe if `buffer` is per thread. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); @@ -7150,7 +6849,6 @@ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyDescriptorSetLayout */ PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( @@ -7171,7 +6869,6 @@ PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateDescriptorSetLayout */ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layout); @@ -7197,7 +6894,6 @@ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layo * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyDescriptorPool */ PAL_API PalResult PAL_CALL palCreateDescriptorPool( @@ -7218,7 +6914,6 @@ PAL_API PalResult PAL_CALL palCreateDescriptorPool( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateDescriptorPool */ PAL_API void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool); @@ -7236,7 +6931,6 @@ PAL_API void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool); * Thread safety: Thread safe if `pool` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); @@ -7261,7 +6955,6 @@ PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); * Thread safety: Thread safe if `device` and `pool` are externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( PalDevice* device, @@ -7293,7 +6986,6 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palUpdateDescriptorSet( PalDevice* device, @@ -7317,7 +7009,6 @@ PAL_API PalResult PAL_CALL palUpdateDescriptorSet( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyPipelineLayout */ PAL_API PalResult PAL_CALL palCreatePipelineLayout( @@ -7338,7 +7029,6 @@ PAL_API PalResult PAL_CALL palCreatePipelineLayout( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreatePipelineLayout */ PAL_API void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout); @@ -7359,7 +7049,6 @@ PAL_API void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout); * Thread safety: Thread safe if `device` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyPipeline */ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( @@ -7385,7 +7074,6 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( * @note The first entry of the compute shader will be used. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyPipeline */ PAL_API PalResult PAL_CALL palCreateComputePipeline( @@ -7414,7 +7102,6 @@ PAL_API PalResult PAL_CALL palCreateComputePipeline( * @note The shader group array must be in this order [raygen][miss][hitgroup][callable]. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyPipeline */ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( @@ -7435,7 +7122,6 @@ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateGraphicsPipeline * @sa palCreateComputePipeline * @sa palCreateRayTracingPipeline @@ -7467,7 +7153,6 @@ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); * @note The records array must be in this order [raygen][miss][hitgroup][callable]. * * @since 1.4 - * @ingroup pal_graphics * @sa palDestroyShaderBindingTable */ PAL_API PalResult PAL_CALL palCreateShaderBindingTable( @@ -7488,7 +7173,6 @@ PAL_API PalResult PAL_CALL palCreateShaderBindingTable( * externally synchronized. * * @since 1.4 - * @ingroup pal_graphics * @sa palCreateShaderBindingTable */ PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); @@ -7512,7 +7196,6 @@ PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); * Thread safety: Thread safe if `sbt` is externally synchronized. * * @since 1.4 - * @ingroup pal_graphics */ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( PalShaderBindingTable* sbt, @@ -7528,7 +7211,7 @@ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( * write upto that limit. * * If the count is 0 and the PalWorkGroupInfo array is nullptr, the function fails - * and returns `false`. + * and returns `PAL_FALSE`. * * This function works the maths for how many work groups to dispatch in each axis and how many * times it needs to be dispatch in order for the work to be done. It works well with @@ -7538,12 +7221,11 @@ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( * @param[in, out] count Capacity of the PalWorkGroupInfo array. * @param[out] infos Pointer to an Array of PalWorkGroupInfo. * - * @return True on success otherwise false. + * @return True on success otherwise `PAL_FALSE`. * * Thread safety: Must only be called from the main thread. * * @since 1.4 - * @ingroup pal_graphics * @sa palCmdDrawMeshTasks * @sa palCmdDrawMeshTasksIndirect * @sa palCmdDrawMeshTasksIndirectCount diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index e61f0469..bdeddd33 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -1,30 +1,13 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ /** * @defgroup pal_opengl Opengl - * Opengl PAL functionality such as FBConfigs and contexts. - * + * @ingroup pal_opengl * @{ */ @@ -45,7 +28,6 @@ freely, subject to the following restrictions: * @brief Opaque handle to an opengl context. * * @since 1.0 - * @ingroup pal_opengl */ typedef struct PalGLContext PalGLContext; @@ -57,7 +39,6 @@ typedef struct PalGLContext PalGLContext; * consistency and API use. * * @since 1.0 - * @ingroup pal_opengl */ typedef enum { PAL_GL_EXTENSION_CREATE_CONTEXT = (1ULL << 0), /**< Modern context.*/ @@ -80,7 +61,6 @@ typedef enum { * consistency and API use. * * @since 1.0 - * @ingroup pal_opengl */ typedef enum { PAL_GL_PROFILE_NONE, /**< Default profile.*/ @@ -97,7 +77,6 @@ typedef enum { * for consistency and API use. * * @since 1.0 - * @ingroup pal_opengl */ typedef enum { PAL_GL_CONTEXT_RESET_NONE, /**< Default reset behaviour.*/ @@ -113,7 +92,6 @@ typedef enum { * `PAL_GL_RELEASE_BEHAVIOR_**` for consistency and API use. * * @since 1.0 - * @ingroup pal_opengl */ typedef enum { PAL_GL_RELEASE_BEHAVIOR_NONE, /**< Default release behaviour..*/ @@ -125,7 +103,6 @@ typedef enum { * @brief Information about the opengl driver. * * @since 1.0 - * @ingroup pal_opengl */ typedef struct { PalGLExtensions extensions; @@ -141,7 +118,6 @@ typedef struct { * @brief Information about an opengl framebuffer. * * @since 1.0 - * @ingroup pal_opengl */ typedef struct { PalBool doubleBuffer; @@ -165,7 +141,6 @@ typedef struct { * holding native handles. The handles will not be copied. * * @since 1.0 - * @ingroup pal_opengl */ typedef struct { void* display; /**< Can be nullptr depending on platform (eg. Windows).*/ @@ -179,7 +154,6 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * @since 1.0 - * @ingroup pal_opengl */ typedef struct { PalBool forward; /**< Forward compatible context.*/ @@ -213,7 +187,6 @@ typedef struct { * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_opengl * @sa palShutdownGL * @sa palGLSetInstance */ @@ -228,7 +201,6 @@ PAL_API PalResult PAL_CALL palInitGL(const PalAllocator* allocator); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_opengl * @sa palInitGL */ PAL_API void PAL_CALL palShutdownGL(); @@ -244,7 +216,6 @@ PAL_API void PAL_CALL palShutdownGL(); * Thread safety: Thread-safe. * * @since 1.0 - * @ingroup pal_opengl */ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); @@ -272,7 +243,6 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_opengl * @sa palInitGL */ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( @@ -301,7 +271,6 @@ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( * Thread safety: Thread safe. * * @since 1.0 - * @ingroup pal_opengl */ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( PalGLFBConfig* configs, @@ -332,7 +301,6 @@ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_opengl * @sa palDestroyGLContext */ PAL_API PalResult PAL_CALL palCreateGLContext( @@ -352,7 +320,6 @@ PAL_API PalResult PAL_CALL palCreateGLContext( * Thread safety: Thread safe if the `context` is per thread. * * @since 1.0 - * @ingroup pal_opengl * @sa palCreateGLContext */ PAL_API void PAL_CALL palDestroyGLContext(PalGLContext* context); @@ -381,7 +348,6 @@ PAL_API void PAL_CALL palDestroyGLContext(PalGLContext* context); * current context at a time. * * @since 1.0 - * @ingroup pal_opengl */ PAL_API PalResult PAL_CALL palMakeContextCurrent( PalGLWindow* glWindow, @@ -399,7 +365,6 @@ PAL_API PalResult PAL_CALL palMakeContextCurrent( * Thread safety: Thread safe. * * @since 1.0 - * @ingroup pal_opengl * @sa palInitGL */ PAL_API void* PAL_CALL palGLGetProcAddress(const char* name); @@ -420,7 +385,6 @@ PAL_API void* PAL_CALL palGLGetProcAddress(const char* name); * bound context. * * @since 1.0 - * @ingroup pal_opengl * @sa palMakeContextCurrent */ PAL_API PalResult PAL_CALL palSwapBuffers( @@ -444,7 +408,6 @@ PAL_API PalResult PAL_CALL palSwapBuffers( * context. * * @since 1.0 - * @ingroup pal_opengl * @sa palMakeContextCurrent */ PAL_API PalResult PAL_CALL palSetSwapInterval(int32_t interval); @@ -465,7 +428,6 @@ PAL_API PalResult PAL_CALL palSetSwapInterval(int32_t interval); * @note The provided instance will not be freed by the opengl system. * * @since 1.3 - * @ingroup pal_opengl * @sa palInitGL */ PAL_API void PAL_CALL palGLSetInstance(void* instance); @@ -479,7 +441,6 @@ PAL_API void PAL_CALL palGLSetInstance(void* instance); * Thread safety: Thread safe. * * @since 1.3 - * @ingroup pal_opengl */ PAL_API const char* PAL_CALL palGLGetBackend(); diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index c011f5ce..581cb50c 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -70,7 +70,7 @@ typedef uint64_t PalThreadFeatures; /** * @typedef PalThreadPriority - * @brief Thread priority types. This is not a bitmask enum. + * @brief Thread priority types. This is not a bitmask. * * All thread priority types follow the format `PAL_THREAD_PRIORITY_**` for * consistency and API use. diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 85d1cc73..47882534 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -1,30 +1,13 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ /** * @defgroup pal_video Video - * Video PAL functionality such as windows, cursors, monitors and icons. - * + * @ingroup pal_video * @{ */ @@ -33,65 +16,330 @@ freely, subject to the following restrictions: #include "pal_event.h" -/** - * @typedef PalVideoFeatures64 - * @brief Extended Video system features. - * - * All extended video features follow the format `PAL_VIDEO_FEATURE64_**` for - * consistency and API use. - * - * @since 1.3 - * @ingroup pal_video - */ -typedef uint64_t PalVideoFeatures64; - -#define PAL_VIDEO_FEATURE64_HIGH_DPI (1ULL << 0) -#define PAL_VIDEO_FEATURE64_MONITOR_SET_ORIENTATION (1ULL << 1) -#define PAL_VIDEO_FEATURE64_MONITOR_GET_ORIENTATION (1ULL << 2) -#define PAL_VIDEO_FEATURE64_BORDERLESS_WINDOW (1ULL << 3) -#define PAL_VIDEO_FEATURE64_TRANSPARENT_WINDOW (1ULL << 4) -#define PAL_VIDEO_FEATURE64_TOOL_WINDOW (1ULL << 5) -#define PAL_VIDEO_FEATURE64_MONITOR_SET_MODE (1ULL << 6) -#define PAL_VIDEO_FEATURE64_MONITOR_GET_MODE (1ULL << 7) -#define PAL_VIDEO_FEATURE64_MULTI_MONITORS (1ULL << 8) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_SIZE (1ULL << 9) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_SIZE (1ULL << 10) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_POS (1ULL << 11) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_POS (1ULL << 12) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_STATE (1ULL << 13) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_STATE (1ULL << 14) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_VISIBILITY (1ULL << 15) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_VISIBILITY (1ULL << 16) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_TITLE (1ULL << 17) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_TITLE (1ULL << 18) -#define PAL_VIDEO_FEATURE64_NO_MAXIMIZEBOX (1ULL << 19) -#define PAL_VIDEO_FEATURE64_NO_MINIMIZEBOX (1ULL << 20) -#define PAL_VIDEO_FEATURE64_CLIP_CURSOR (1ULL << 21) -#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_CAPTION (1ULL << 22) -#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_TRAY (1ULL << 23) -#define PAL_VIDEO_FEATURE64_WINDOW_FLASH_INTERVAL (1ULL << 24) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_INPUT_FOCUS (1ULL << 25) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_INPUT_FOCUS (1ULL << 26) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_STYLE (1ULL << 27) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_STYLE (1ULL << 28) -#define PAL_VIDEO_FEATURE64_CURSOR_SET_POS (1ULL << 29) -#define PAL_VIDEO_FEATURE64_CURSOR_GET_POS (1ULL << 30) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_ICON (1ULL << 31) -#define PAL_VIDEO_FEATURE64_TOPMOST_WINDOW (1ULL << 32) -#define PAL_VIDEO_FEATURE64_DECORATED_WINDOW (1ULL << 33) -#define PAL_VIDEO_FEATURE64_CURSOR_SET_VISIBILITY (1ULL << 34) -#define PAL_VIDEO_FEATURE64_WINDOW_GET_MONITOR (1ULL << 35) -#define PAL_VIDEO_FEATURE64_MONITOR_GET_PRIMARY (1ULL << 36) -#define PAL_VIDEO_FEATURE64_FOREIGN_WINDOWS (1ULL << 37) -#define PAL_VIDEO_FEATURE64_MONITOR_VALIDATE_MODE (1ULL << 38) -#define PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR (1ULL << 39) +#define PAL_MONITOR_NAME_SIZE 32 + +#define PAL_VIDEO_FEATURE_HIGH_DPI (1ULL << 0) +#define PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION (1ULL << 1) +#define PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION (1ULL << 2) +#define PAL_VIDEO_FEATURE_BORDERLESS_WINDOW (1ULL << 3) +#define PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW (1ULL << 4) +#define PAL_VIDEO_FEATURE_TOOL_WINDOW (1ULL << 5) +#define PAL_VIDEO_FEATURE_MONITOR_SET_MODE (1ULL << 6) +#define PAL_VIDEO_FEATURE_MONITOR_GET_MODE (1ULL << 7) +#define PAL_VIDEO_FEATURE_MULTI_MONITORS (1ULL << 8) +#define PAL_VIDEO_FEATURE_WINDOW_SET_SIZE (1ULL << 9) +#define PAL_VIDEO_FEATURE_WINDOW_GET_SIZE (1ULL << 10) +#define PAL_VIDEO_FEATURE_WINDOW_SET_POS (1ULL << 11) +#define PAL_VIDEO_FEATURE_WINDOW_GET_POS (1ULL << 12) +#define PAL_VIDEO_FEATURE_WINDOW_SET_STATE (1ULL << 13) +#define PAL_VIDEO_FEATURE_WINDOW_GET_STATE (1ULL << 14) +#define PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY (1ULL << 15) +#define PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY (1ULL << 16) +#define PAL_VIDEO_FEATURE_WINDOW_SET_TITLE (1ULL << 17) +#define PAL_VIDEO_FEATURE_WINDOW_GET_TITLE (1ULL << 18) +#define PAL_VIDEO_FEATURE_NO_MAXIMIZEBOX (1ULL << 19) +#define PAL_VIDEO_FEATURE_NO_MINIMIZEBOX (1ULL << 20) +#define PAL_VIDEO_FEATURE_CLIP_CURSOR (1ULL << 21) +#define PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION (1ULL << 22) +#define PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY (1ULL << 23) +#define PAL_VIDEO_FEATURE_WINDOW_FLASH_INTERVAL (1ULL << 24) +#define PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS (1ULL << 25) +#define PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS (1ULL << 26) +#define PAL_VIDEO_FEATURE_WINDOW_SET_STYLE (1ULL << 27) +#define PAL_VIDEO_FEATURE_WINDOW_GET_STYLE (1ULL << 28) +#define PAL_VIDEO_FEATURE_CURSOR_SET_POS (1ULL << 29) +#define PAL_VIDEO_FEATURE_CURSOR_GET_POS (1ULL << 30) +#define PAL_VIDEO_FEATURE_WINDOW_SET_ICON (1ULL << 31) +#define PAL_VIDEO_FEATURE_TOPMOST_WINDOW (1ULL << 32) +#define PAL_VIDEO_FEATURE_DECORATED_WINDOW (1ULL << 33) +#define PAL_VIDEO_FEATURE_CURSOR_SET_VISIBILITY (1ULL << 34) +#define PAL_VIDEO_FEATURE_WINDOW_GET_MONITOR (1ULL << 35) +#define PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY (1ULL << 36) +#define PAL_VIDEO_FEATURE_FOREIGN_WINDOWS (1ULL << 37) +#define PAL_VIDEO_FEATURE_MONITOR_VALIDATE_MODE (1ULL << 38) +#define PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR (1ULL << 39) + +#define PAL_ORIENTATION_LANDSCAPE 0 +#define PAL_ORIENTATION_PORTRAIT 1 +#define PAL_ORIENTATION_LANDSCAPE_FLIPPED 2 +#define PAL_ORIENTATION_PORTRAIT_FLIPPED 3 + +#define PAL_WINDOW_STYLE_RESIZABLE (1ULL << 0) +#define PAL_WINDOW_STYLE_TRANSPARENT (1ULL << 1) +#define PAL_WINDOW_STYLE_TOPMOST (1ULL << 2) +#define PAL_WINDOW_STYLE_NO_MINIMIZEBOX (1ULL << 3) +#define PAL_WINDOW_STYLE_NO_MAXIMIZEBOX (1ULL << 4) +#define PAL_WINDOW_STYLE_TOOL (1ULL << 5) +#define PAL_WINDOW_STYLE_BORDERLESS (1ULL << 6) + +#define PAL_WINDOW_STATE_MAXIMIZED 0 +#define PAL_WINDOW_STATE_MINIMIZED 1 +#define PAL_WINDOW_STATE_RESTORED 2 + +#define PAL_FLASH_STOP 0 /**< Stop flashing.*/ +#define PAL_FLASH_CAPTION (1ULL << 0) /**< Flash the titlebar of the window.*/ +#define PAL_FLASH_TRAY (1ULL << 1) /**< Flash the icon of the window.*/ + +#define PAL_CONFIG_BACKEND_PAL_OPENGL 0 /**< Use PAL opengl module backend.*/ +#define PAL_CONFIG_BACKEND_EGL 1 +#define PAL_CONFIG_BACKEND_GLX 2 +#define PAL_CONFIG_BACKEND_WGL 3 +#define PAL_CONFIG_BACKEND_GLES 4 + +#define PAL_SCANCODE_UNKNOWN 0 +#define PAL_SCANCODE_A 1 +#define PAL_SCANCODE_B 2 +#define PAL_SCANCODE_C 3 +#define PAL_SCANCODE_D 4 +#define PAL_SCANCODE_E 5 +#define PAL_SCANCODE_F 6 +#define PAL_SCANCODE_G 7 +#define PAL_SCANCODE_H 8 +#define PAL_SCANCODE_I 9 +#define PAL_SCANCODE_J 10 +#define PAL_SCANCODE_K 11 +#define PAL_SCANCODE_L 12 +#define PAL_SCANCODE_M 13 +#define PAL_SCANCODE_N 14 +#define PAL_SCANCODE_O 15 +#define PAL_SCANCODE_P 16 +#define PAL_SCANCODE_Q 17 +#define PAL_SCANCODE_R 18 +#define PAL_SCANCODE_S 19 +#define PAL_SCANCODE_T 20 +#define PAL_SCANCODE_U 21 +#define PAL_SCANCODE_V 22 +#define PAL_SCANCODE_W 23 +#define PAL_SCANCODE_X 24 +#define PAL_SCANCODE_Y 25 +#define PAL_SCANCODE_Z 26 + +#define PAL_SCANCODE_0 27 +#define PAL_SCANCODE_1 28 +#define PAL_SCANCODE_2 29 +#define PAL_SCANCODE_3 30 +#define PAL_SCANCODE_4 31 +#define PAL_SCANCODE_5 32 +#define PAL_SCANCODE_6 33 +#define PAL_SCANCODE_7 34 +#define PAL_SCANCODE_8 35 +#define PAL_SCANCODE_9 36 + +#define PAL_SCANCODE_F1 37 +#define PAL_SCANCODE_F2 38 +#define PAL_SCANCODE_F3 39 +#define PAL_SCANCODE_F4 40 +#define PAL_SCANCODE_F5 41 +#define PAL_SCANCODE_F6 42 +#define PAL_SCANCODE_F7 43 +#define PAL_SCANCODE_F8 44 +#define PAL_SCANCODE_F9 45 +#define PAL_SCANCODE_F10 46 +#define PAL_SCANCODE_F11 47 +#define PAL_SCANCODE_F12 48 + +#define PAL_SCANCODE_ESCAPE 49 +#define PAL_SCANCODE_ENTER 50 +#define PAL_SCANCODE_TAB 51 +#define PAL_SCANCODE_BACKSPACE 52 +#define PAL_SCANCODE_SPACE 53 +#define PAL_SCANCODE_CAPSLOCK 54 +#define PAL_SCANCODE_NUMLOCK 55 +#define PAL_SCANCODE_SCROLLLOCK 56 +#define PAL_SCANCODE_LSHIFT 57 +#define PAL_SCANCODE_RSHIFT 58 +#define PAL_SCANCODE_LCTRL 59 +#define PAL_SCANCODE_RCTRL 60 +#define PAL_SCANCODE_LALT 61 +#define PAL_SCANCODE_RALT 62 + +#define PAL_SCANCODE_LEFT 63 +#define PAL_SCANCODE_RIGHT 64 +#define PAL_SCANCODE_UP 65 +#define PAL_SCANCODE_DOWN 66 + +#define PAL_SCANCODE_INSERT 67 +#define PAL_SCANCODE_DELETE 68 +#define PAL_SCANCODE_HOME 69 +#define PAL_SCANCODE_END 70 +#define PAL_SCANCODE_PAGEUP 71 +#define PAL_SCANCODE_PAGEDOWN 72 + +#define PAL_SCANCODE_KP_0 73 +#define PAL_SCANCODE_KP_1 74 +#define PAL_SCANCODE_KP_2 75 +#define PAL_SCANCODE_KP_3 76 +#define PAL_SCANCODE_KP_4 77 +#define PAL_SCANCODE_KP_5 78 +#define PAL_SCANCODE_KP_6 79 +#define PAL_SCANCODE_KP_7 80 +#define PAL_SCANCODE_KP_8 81 +#define PAL_SCANCODE_KP_9 82 +#define PAL_SCANCODE_KP_ENTER 83 +#define PAL_SCANCODE_KP_ADD 84 +#define PAL_SCANCODE_KP_SUBTRACT 85 +#define PAL_SCANCODE_KP_MULTIPLY 86 +#define PAL_SCANCODE_KP_DIVIDE 87 +#define PAL_SCANCODE_KP_DECIMAL 88 +#define PAL_SCANCODE_KP_EQUAL 89 + +#define PAL_SCANCODE_PRINTSCREEN 90 +#define PAL_SCANCODE_PAUSE 91 +#define PAL_SCANCODE_MENU 92 +#define PAL_SCANCODE_APOSTROPHE 93 +#define PAL_SCANCODE_BACKSLASH 94 +#define PAL_SCANCODE_COMMA 95 +#define PAL_SCANCODE_EQUAL 96 +#define PAL_SCANCODE_GRAVEACCENT 97 +#define PAL_SCANCODE_SUBTRACT 98 +#define PAL_SCANCODE_PERIOD 99 +#define PAL_SCANCODE_SEMICOLON 100 +#define PAL_SCANCODE_SLASH 101 +#define PAL_SCANCODE_LBRACKET 102 +#define PAL_SCANCODE_RBRACKET 103 +#define PAL_SCANCODE_LSUPER 104 +#define PAL_SCANCODE_RSUPER 105 + +#define PAL_SCANCODE_MAX 106 + +#define PAL_KEYCODE_UNKNOWN 0 +#define PAL_KEYCODE_A 1 +#define PAL_KEYCODE_B 2 +#define PAL_KEYCODE_C 3 +#define PAL_KEYCODE_D 4 +#define PAL_KEYCODE_E 5 +#define PAL_KEYCODE_F 6 +#define PAL_KEYCODE_G 7 +#define PAL_KEYCODE_H 8 +#define PAL_KEYCODE_I 9 +#define PAL_KEYCODE_J 10 +#define PAL_KEYCODE_K 11 +#define PAL_KEYCODE_L 12 +#define PAL_KEYCODE_M 13 +#define PAL_KEYCODE_N 14 +#define PAL_KEYCODE_O 15 +#define PAL_KEYCODE_P 16 +#define PAL_KEYCODE_Q 17 +#define PAL_KEYCODE_R 18 +#define PAL_KEYCODE_S 19 +#define PAL_KEYCODE_T 20 +#define PAL_KEYCODE_U 21 +#define PAL_KEYCODE_V 22 +#define PAL_KEYCODE_W 23 +#define PAL_KEYCODE_X 24 +#define PAL_KEYCODE_Y 25 +#define PAL_KEYCODE_Z 26 + +#define PAL_KEYCODE_0 27 +#define PAL_KEYCODE_1 28 +#define PAL_KEYCODE_2 29 +#define PAL_KEYCODE_3 30 +#define PAL_KEYCODE_4 31 +#define PAL_KEYCODE_5 32 +#define PAL_KEYCODE_6 33 +#define PAL_KEYCODE_7 34 +#define PAL_KEYCODE_8 35 +#define PAL_KEYCODE_9 36 + +#define PAL_KEYCODE_F1 37 +#define PAL_KEYCODE_F2 38 +#define PAL_KEYCODE_F3 39 +#define PAL_KEYCODE_F4 40 +#define PAL_KEYCODE_F5 41 +#define PAL_KEYCODE_F6 42 +#define PAL_KEYCODE_F7 43 +#define PAL_KEYCODE_F8 44 +#define PAL_KEYCODE_F9 45 +#define PAL_KEYCODE_F10 46 +#define PAL_KEYCODE_F11 47 +#define PAL_KEYCODE_F12 48 + +#define PAL_KEYCODE_ESCAPE 49 +#define PAL_KEYCODE_ENTER 50 +#define PAL_KEYCODE_TAB 51 +#define PAL_KEYCODE_BACKSPACE 52 +#define PAL_KEYCODE_SPACE 53 +#define PAL_KEYCODE_CAPSLOCK 54 +#define PAL_KEYCODE_NUMLOCK 55 +#define PAL_KEYCODE_SCROLLLOCK 56 +#define PAL_KEYCODE_LSHIFT 57 +#define PAL_KEYCODE_RSHIFT 58 +#define PAL_KEYCODE_LCTRL 59 +#define PAL_KEYCODE_RCTRL 60 +#define PAL_KEYCODE_LALT 61 +#define PAL_KEYCODE_RALT 62 + +#define PAL_KEYCODE_LEFT 63 +#define PAL_KEYCODE_RIGHT 64 +#define PAL_KEYCODE_UP 65 +#define PAL_KEYCODE_DOWN 66 + +#define PAL_KEYCODE_INSERT 67 +#define PAL_KEYCODE_DELETE 68 +#define PAL_KEYCODE_HOME 69 +#define PAL_KEYCODE_END 70 +#define PAL_KEYCODE_PAGEUP 71 +#define PAL_KEYCODE_PAGEDOWN 72 + +#define PAL_KEYCODE_KP_0 73 +#define PAL_KEYCODE_KP_1 74 +#define PAL_KEYCODE_KP_2 75 +#define PAL_KEYCODE_KP_3 76 +#define PAL_KEYCODE_KP_4 77 +#define PAL_KEYCODE_KP_5 78 +#define PAL_KEYCODE_KP_6 79 +#define PAL_KEYCODE_KP_7 80 +#define PAL_KEYCODE_KP_8 81 +#define PAL_KEYCODE_KP_9 82 +#define PAL_KEYCODE_KP_ENTER 83 +#define PAL_KEYCODE_KP_ADD 84 +#define PAL_KEYCODE_KP_SUBTRACT 85 +#define PAL_KEYCODE_KP_MULTIPLY 86 +#define PAL_KEYCODE_KP_DIVIDE 87 +#define PAL_KEYCODE_KP_DECIMAL 88 +#define PAL_KEYCODE_KP_EQUAL 89 + +#define PAL_KEYCODE_PRINTSCREEN 90 +#define PAL_KEYCODE_PAUSE 91 +#define PAL_KEYCODE_MENU 92 +#define PAL_KEYCODE_APOSTROPHE 93 +#define PAL_KEYCODE_BACKSLASH 94 +#define PAL_KEYCODE_COMMA 95 +#define PAL_KEYCODE_EQUAL 96 +#define PAL_KEYCODE_GRAVEACCENT 97 +#define PAL_KEYCODE_SUBTRACT 98 +#define PAL_KEYCODE_PERIOD 99 +#define PAL_KEYCODE_SEMICOLON 100 +#define PAL_KEYCODE_SLASH 101 +#define PAL_KEYCODE_LBRACKET 102 +#define PAL_KEYCODE_RBRACKET 103 +#define PAL_KEYCODE_LSUPER 104 +#define PAL_KEYCODE_RSUPER 105 + +#define PAL_KEYCODE_MAX 106 + +#define PAL_MOUSE_BUTTON_UNKNOWN 0 +#define PAL_MOUSE_BUTTON_LEFT 1 +#define PAL_MOUSE_BUTTON_RIGHT 2 +#define PAL_MOUSE_BUTTON_MIDDLE 3 +#define PAL_MOUSE_BUTTON_X1 4 +#define PAL_MOUSE_BUTTON_X2 5 + +#define PAL_MOUSE_BUTTON_MAX 6 + +#define PAL_CURSOR_ARROW 0 +#define PAL_CURSOR_HAND 1 +#define PAL_CURSOR_CROSS 2 +#define PAL_CURSOR_IBEAM 3 +#define PAL_CURSOR_WAIT 4 + +#define PAL_CURSOR_MAX 5 /** * @struct PalMonitor * @brief Opaque handle to a monitor. * * @since 1.0 - * @ingroup pal_video */ typedef struct PalMonitor PalMonitor; @@ -100,7 +348,6 @@ typedef struct PalMonitor PalMonitor; * @brief Opaque handle to a window. * * @since 1.0 - * @ingroup pal_video */ typedef struct PalWindow PalWindow; @@ -109,7 +356,6 @@ typedef struct PalWindow PalWindow; * @brief Opaque handle to an icon. * * @since 1.0 - * @ingroup pal_video */ typedef struct PalIcon PalIcon; @@ -118,7 +364,6 @@ typedef struct PalIcon PalIcon; * @brief Opaque handle to a cursor. * * @since 1.0 - * @ingroup pal_video */ typedef struct PalCursor PalCursor; @@ -129,43 +374,9 @@ typedef struct PalCursor PalCursor; * All video features follow the format `PAL_VIDEO_FEATURE_**` for * consistency and API use. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ -typedef enum { - PAL_VIDEO_FEATURE_HIGH_DPI = (1ULL << 0), - PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION = (1ULL << 1), - PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION = (1ULL << 2), - PAL_VIDEO_FEATURE_BORDERLESS_WINDOW = (1ULL << 3), - PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW = (1ULL << 4), - PAL_VIDEO_FEATURE_TOOL_WINDOW = (1ULL << 5), - PAL_VIDEO_FEATURE_MONITOR_SET_MODE = (1ULL << 6), - PAL_VIDEO_FEATURE_MONITOR_GET_MODE = (1ULL << 7), - PAL_VIDEO_FEATURE_MULTI_MONITORS = (1ULL << 8), - PAL_VIDEO_FEATURE_WINDOW_SET_SIZE = (1ULL << 9), - PAL_VIDEO_FEATURE_WINDOW_GET_SIZE = (1ULL << 10), - PAL_VIDEO_FEATURE_WINDOW_SET_POS = (1ULL << 11), - PAL_VIDEO_FEATURE_WINDOW_GET_POS = (1ULL << 12), - PAL_VIDEO_FEATURE_WINDOW_SET_STATE = (1ULL << 13), - PAL_VIDEO_FEATURE_WINDOW_GET_STATE = (1ULL << 14), - PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY = (1ULL << 15), - PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY = (1ULL << 16), - PAL_VIDEO_FEATURE_WINDOW_SET_TITLE = (1ULL << 17), - PAL_VIDEO_FEATURE_WINDOW_GET_TITLE = (1ULL << 18), - PAL_VIDEO_FEATURE_NO_MAXIMIZEBOX = (1ULL << 19), - PAL_VIDEO_FEATURE_NO_MINIMIZEBOX = (1ULL << 20), - PAL_VIDEO_FEATURE_CLIP_CURSOR = (1ULL << 21), - PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION = (1ULL << 22), - PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY = (1ULL << 23), - PAL_VIDEO_FEATURE_WINDOW_FLASH_INTERVAL = (1ULL << 24), - PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS = (1ULL << 25), - PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS = (1ULL << 26), - PAL_VIDEO_FEATURE_WINDOW_SET_STYLE = (1ULL << 27), - PAL_VIDEO_FEATURE_WINDOW_GET_STYLE = (1ULL << 28), - PAL_VIDEO_FEATURE_CURSOR_SET_POS = (1ULL << 29), - PAL_VIDEO_FEATURE_CURSOR_GET_POS = (1ULL << 30), - PAL_VIDEO_FEATURE_WINDOW_SET_ICON = (1ULL << 31) -} PalVideoFeatures; +typedef uint64_t PalVideoFeatures; /** * @typedef PalOrientation @@ -174,15 +385,9 @@ typedef enum { * All orientation types follow the format `PAL_ORIENTATION_**` for consistency * and API use. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ -typedef enum { - PAL_ORIENTATION_LANDSCAPE, - PAL_ORIENTATION_PORTRAIT, - PAL_ORIENTATION_LANDSCAPE_FLIPPED, - PAL_ORIENTATION_PORTRAIT_FLIPPED -} PalOrientation; +typedef uint32_t PalOrientation; /** * @typedef PalWindowStyle @@ -192,18 +397,9 @@ typedef enum { * All window flags follow the format `PAL_WINDOW_STYLE_**` for * consistency and API use. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ -typedef enum { - PAL_WINDOW_STYLE_RESIZABLE = (1ULL << 0), - PAL_WINDOW_STYLE_TRANSPARENT = (1ULL << 1), - PAL_WINDOW_STYLE_TOPMOST = (1ULL << 2), - PAL_WINDOW_STYLE_NO_MINIMIZEBOX = (1ULL << 3), - PAL_WINDOW_STYLE_NO_MAXIMIZEBOX = (1ULL << 4), - PAL_WINDOW_STYLE_TOOL = (1ULL << 5), - PAL_WINDOW_STYLE_BORDERLESS = (1ULL << 6) -} PalWindowStyle; +typedef uint64_t PalWindowStyle; /** * @typedef PalWindowState @@ -212,14 +408,9 @@ typedef enum { * All window states follow the format `PAL_WINDOW_STATE_**` for consistency and * API use. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ -typedef enum { - PAL_WINDOW_STATE_MAXIMIZED, - PAL_WINDOW_STATE_MINIMIZED, - PAL_WINDOW_STATE_RESTORED -} PalWindowState; +typedef uint32_t PalWindowState; /** * @typedef PalFlashFlag @@ -231,14 +422,9 @@ typedef enum { * All flash flags follow the format `PAL_FLASH_**` for consistency and * API use. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ -typedef enum { - PAL_FLASH_STOP = 0, /**< Stop flashing.*/ - PAL_FLASH_CAPTION = (1ULL << 0), /**< Flash the titlebar of the window.*/ - PAL_FLASH_TRAY = (1ULL << 1) /**< Flash the icon of the window.*/ -} PalFlashFlag; +typedef uint64_t PalFlashFlag; /** * @typedef PalFBConfigBackend @@ -247,16 +433,9 @@ typedef enum { * All FBConfig backends follow the format `PAL_CONFIG_BACKEND**` for * consistency and API use. * - * @since 1.1 - * @ingroup pal_video + * @since 2.0 */ -typedef enum { - PAL_CONFIG_BACKEND_EGL, - PAL_CONFIG_BACKEND_GLX, - PAL_CONFIG_BACKEND_WGL, - PAL_CONFIG_BACKEND_PAL_OPENGL, /**< Use PAL opengl module backend.*/ - PAL_CONFIG_BACKEND_GLES -} PalFBConfigBackend; +typedef uint32_t PalFBConfigBackend; /** * @typedef PalScancode @@ -265,127 +444,9 @@ typedef enum { * All scancodes follow the format `PAL_SCANCODE_**` for consistency and * API use. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ -typedef enum { - PAL_SCANCODE_UNKNOWN = 0, - - PAL_SCANCODE_A, - PAL_SCANCODE_B, - PAL_SCANCODE_C, - PAL_SCANCODE_D, - PAL_SCANCODE_E, - PAL_SCANCODE_F, - PAL_SCANCODE_G, - PAL_SCANCODE_H, - PAL_SCANCODE_I, - PAL_SCANCODE_J, - PAL_SCANCODE_K, - PAL_SCANCODE_L, - PAL_SCANCODE_M, - PAL_SCANCODE_N, - PAL_SCANCODE_O, - PAL_SCANCODE_P, - PAL_SCANCODE_Q, - PAL_SCANCODE_R, - PAL_SCANCODE_S, - PAL_SCANCODE_T, - PAL_SCANCODE_U, - PAL_SCANCODE_V, - PAL_SCANCODE_W, - PAL_SCANCODE_X, - PAL_SCANCODE_Y, - PAL_SCANCODE_Z, - - PAL_SCANCODE_0, - PAL_SCANCODE_1, - PAL_SCANCODE_2, - PAL_SCANCODE_3, - PAL_SCANCODE_4, - PAL_SCANCODE_5, - PAL_SCANCODE_6, - PAL_SCANCODE_7, - PAL_SCANCODE_8, - PAL_SCANCODE_9, - - PAL_SCANCODE_F1, - PAL_SCANCODE_F2, - PAL_SCANCODE_F3, - PAL_SCANCODE_F4, - PAL_SCANCODE_F5, - PAL_SCANCODE_F6, - PAL_SCANCODE_F7, - PAL_SCANCODE_F8, - PAL_SCANCODE_F9, - PAL_SCANCODE_F10, - PAL_SCANCODE_F11, - PAL_SCANCODE_F12, - - PAL_SCANCODE_ESCAPE, - PAL_SCANCODE_ENTER, - PAL_SCANCODE_TAB, - PAL_SCANCODE_BACKSPACE, - PAL_SCANCODE_SPACE, - PAL_SCANCODE_CAPSLOCK, - PAL_SCANCODE_NUMLOCK, - PAL_SCANCODE_SCROLLLOCK, - PAL_SCANCODE_LSHIFT, - PAL_SCANCODE_RSHIFT, - PAL_SCANCODE_LCTRL, - PAL_SCANCODE_RCTRL, - PAL_SCANCODE_LALT, - PAL_SCANCODE_RALT, - - PAL_SCANCODE_LEFT, - PAL_SCANCODE_RIGHT, - PAL_SCANCODE_UP, - PAL_SCANCODE_DOWN, - - PAL_SCANCODE_INSERT, - PAL_SCANCODE_DELETE, - PAL_SCANCODE_HOME, - PAL_SCANCODE_END, - PAL_SCANCODE_PAGEUP, - PAL_SCANCODE_PAGEDOWN, - - PAL_SCANCODE_KP_0, - PAL_SCANCODE_KP_1, - PAL_SCANCODE_KP_2, - PAL_SCANCODE_KP_3, - PAL_SCANCODE_KP_4, - PAL_SCANCODE_KP_5, - PAL_SCANCODE_KP_6, - PAL_SCANCODE_KP_7, - PAL_SCANCODE_KP_8, - PAL_SCANCODE_KP_9, - PAL_SCANCODE_KP_ENTER, - PAL_SCANCODE_KP_ADD, - PAL_SCANCODE_KP_SUBTRACT, - PAL_SCANCODE_KP_MULTIPLY, - PAL_SCANCODE_KP_DIVIDE, - PAL_SCANCODE_KP_DECIMAL, - PAL_SCANCODE_KP_EQUAL, - - PAL_SCANCODE_PRINTSCREEN, - PAL_SCANCODE_PAUSE, - PAL_SCANCODE_MENU, - PAL_SCANCODE_APOSTROPHE, - PAL_SCANCODE_BACKSLASH, - PAL_SCANCODE_COMMA, - PAL_SCANCODE_EQUAL, - PAL_SCANCODE_GRAVEACCENT, - PAL_SCANCODE_SUBTRACT, - PAL_SCANCODE_PERIOD, - PAL_SCANCODE_SEMICOLON, - PAL_SCANCODE_SLASH, - PAL_SCANCODE_LBRACKET, - PAL_SCANCODE_RBRACKET, - PAL_SCANCODE_LSUPER, - PAL_SCANCODE_RSUPER, - - PAL_SCANCODE_MAX -} PalScancode; +typedef uint32_t PalScancode; /** * @typedef PalKeycode @@ -394,127 +455,9 @@ typedef enum { * All keycodes follow the format `PAL_KEYCODE_**` for consistency and API * use. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ -typedef enum { - PAL_KEYCODE_UNKNOWN = 0, - - PAL_KEYCODE_A, - PAL_KEYCODE_B, - PAL_KEYCODE_C, - PAL_KEYCODE_D, - PAL_KEYCODE_E, - PAL_KEYCODE_F, - PAL_KEYCODE_G, - PAL_KEYCODE_H, - PAL_KEYCODE_I, - PAL_KEYCODE_J, - PAL_KEYCODE_K, - PAL_KEYCODE_L, - PAL_KEYCODE_M, - PAL_KEYCODE_N, - PAL_KEYCODE_O, - PAL_KEYCODE_P, - PAL_KEYCODE_Q, - PAL_KEYCODE_R, - PAL_KEYCODE_S, - PAL_KEYCODE_T, - PAL_KEYCODE_U, - PAL_KEYCODE_V, - PAL_KEYCODE_W, - PAL_KEYCODE_X, - PAL_KEYCODE_Y, - PAL_KEYCODE_Z, - - PAL_KEYCODE_0, - PAL_KEYCODE_1, - PAL_KEYCODE_2, - PAL_KEYCODE_3, - PAL_KEYCODE_4, - PAL_KEYCODE_5, - PAL_KEYCODE_6, - PAL_KEYCODE_7, - PAL_KEYCODE_8, - PAL_KEYCODE_9, - - PAL_KEYCODE_F1, - PAL_KEYCODE_F2, - PAL_KEYCODE_F3, - PAL_KEYCODE_F4, - PAL_KEYCODE_F5, - PAL_KEYCODE_F6, - PAL_KEYCODE_F7, - PAL_KEYCODE_F8, - PAL_KEYCODE_F9, - PAL_KEYCODE_F10, - PAL_KEYCODE_F11, - PAL_KEYCODE_F12, - - PAL_KEYCODE_ESCAPE, - PAL_KEYCODE_ENTER, - PAL_KEYCODE_TAB, - PAL_KEYCODE_BACKSPACE, - PAL_KEYCODE_SPACE, - PAL_KEYCODE_CAPSLOCK, - PAL_KEYCODE_NUMLOCK, - PAL_KEYCODE_SCROLLLOCK, - PAL_KEYCODE_LSHIFT, - PAL_KEYCODE_RSHIFT, - PAL_KEYCODE_LCTRL, - PAL_KEYCODE_RCTRL, - PAL_KEYCODE_LALT, - PAL_KEYCODE_RALT, - - PAL_KEYCODE_LEFT, - PAL_KEYCODE_RIGHT, - PAL_KEYCODE_UP, - PAL_KEYCODE_DOWN, - - PAL_KEYCODE_INSERT, - PAL_KEYCODE_DELETE, - PAL_KEYCODE_HOME, - PAL_KEYCODE_END, - PAL_KEYCODE_PAGEUP, - PAL_KEYCODE_PAGEDOWN, - - PAL_KEYCODE_KP_0, - PAL_KEYCODE_KP_1, - PAL_KEYCODE_KP_2, - PAL_KEYCODE_KP_3, - PAL_KEYCODE_KP_4, - PAL_KEYCODE_KP_5, - PAL_KEYCODE_KP_6, - PAL_KEYCODE_KP_7, - PAL_KEYCODE_KP_8, - PAL_KEYCODE_KP_9, - PAL_KEYCODE_KP_ENTER, - PAL_KEYCODE_KP_ADD, - PAL_KEYCODE_KP_SUBTRACT, - PAL_KEYCODE_KP_MULTIPLY, - PAL_KEYCODE_KP_DIVIDE, - PAL_KEYCODE_KP_DECIMAL, - PAL_KEYCODE_KP_EQUAL, - - PAL_KEYCODE_PRINTSCREEN, - PAL_KEYCODE_PAUSE, - PAL_KEYCODE_MENU, - PAL_KEYCODE_APOSTROPHE, - PAL_KEYCODE_BACKSLASH, - PAL_KEYCODE_COMMA, - PAL_KEYCODE_EQUAL, - PAL_KEYCODE_GRAVEACCENT, - PAL_KEYCODE_SUBTRACT, - PAL_KEYCODE_PERIOD, - PAL_KEYCODE_SEMICOLON, - PAL_KEYCODE_SLASH, - PAL_KEYCODE_LBRACKET, - PAL_KEYCODE_RBRACKET, - PAL_KEYCODE_LSUPER, - PAL_KEYCODE_RSUPER, - - PAL_KEYCODE_MAX -} PalKeycode; +typedef uint32_t PalKeycode; /** * @typedef PalMouseButton @@ -523,20 +466,9 @@ typedef enum { * All mouse buttons follow the format `PAL_MOUSE_BUTTON_**` for * consistency and API use. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ -typedef enum { - PAL_MOUSE_BUTTON_UNKNOWN = 0, - - PAL_MOUSE_BUTTON_LEFT, - PAL_MOUSE_BUTTON_RIGHT, - PAL_MOUSE_BUTTON_MIDDLE, - PAL_MOUSE_BUTTON_X1, - PAL_MOUSE_BUTTON_X2, - - PAL_MOUSE_BUTTON_MAX -} PalMouseButton; +typedef uint32_t PalMouseButton; /** * @typedef PalCursorType @@ -545,36 +477,26 @@ typedef enum { * All cursor types follow the format `PAL_CURSOR_**` for * consistency and API use. * - * @since 1.1 - * @ingroup pal_video + * @since 2.0 */ -typedef enum { - PAL_CURSOR_ARROW, - PAL_CURSOR_HAND, - PAL_CURSOR_CROSS, - PAL_CURSOR_IBEAM, - PAL_CURSOR_WAIT, - - PAL_CURSOR_MAX -} PalCursorType; +typedef uint32_t PalCursorType; /** * @struct PalMonitorInfo * @brief Information about a monitor. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ typedef struct { - PalBool primary; /**< True if this is the primary monitor.*/ - uint32_t dpi; - uint32_t refreshRate; int32_t x; /**< X position in pixels.*/ int32_t y; /**< Y position in pixels.*/ uint32_t width; /**< Width in pixels.*/ uint32_t height; /**< Height in pixels.*/ + uint32_t dpi; + uint32_t refreshRate; PalOrientation orientation; - char name[32]; + PalBool primary; /**< True if this is the primary monitor.*/ + char name[PAL_MONITOR_NAME_SIZE]; } PalMonitorInfo; /** @@ -582,7 +504,6 @@ typedef struct { * @brief information about a monitor display mode. * * @since 1.0 - * @ingroup pal_video */ typedef struct { uint32_t bpp; /**< Bits per pixel.*/ @@ -597,12 +518,11 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ typedef struct { + PalFlashFlag flags; /**< See PalFlashFlag.*/ uint32_t interval; /**< In milliseconds. Set to 0 for default.*/ - PalFlashFlag flags; /**< See PalFlashFlag.*/ uint32_t count; /**< Set to 0 to flash until focused or cancelled.*/ } PalFlashInfo; @@ -612,13 +532,12 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ typedef struct { + const uint8_t* pixels; /**< Pixels in `RGBA` format.*/ uint32_t width; /**< Width in pixels.*/ uint32_t height; /**< Height in pixels.*/ - const uint8_t* pixels; /**< Pixels in `RGBA` format.*/ } PalIconCreateInfo; /** @@ -627,43 +546,29 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ typedef struct { + const uint8_t* pixels; /**< Pixels in `RGBA` format.*/ uint32_t width; /**< Width in pixels..*/ uint32_t height; /**< Height in pixels.*/ int32_t xHotspot; /**< X pixel for detecting clicks.*/ int32_t yHotspot; /**< Y pixel for detecting clicks.*/ - const uint8_t* pixels; /**< Pixels in `RGBA` format.*/ } PalCursorCreateInfo; /** * @struct PalWindowHandleInfo * @brief Information about a window handle. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ typedef struct { - void* nativeDisplay; /**< The platform (OS) display.*/ - void* nativeWindow; /**< The window platform (OS) handle.*/ -} PalWindowHandleInfo; - -/** - * @struct PalWindowHandleInfoEx - * @brief Extended information about a window handle. - * - * @since 1.3 - * @ingroup pal_video - */ -typedef struct { - void* nativeDisplay; /**< The platform (OS) display.*/ + void* nativeDisplay; /**< The platform (OS) display or instance.*/ void* nativeWindow; /**< The window platform (OS) handle.*/ void* nativeHandle1; /**< Extra window handle (xdgSurface)*/ void* nativeHandle2; /**< Extra window handle (xdgToplevel)*/ void* nativeHandle3; /**< Extra window handle (wl_egl_window)*/ -} PalWindowHandleInfoEx; +} PalWindowHandleInfo; /** * @struct PalWindowCreateInfo @@ -671,19 +576,18 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ typedef struct { + PalWindowStyle style; /**< Window style.*/ + const char* title; /**< Title in UTF-8 encoding.*/ + PalMonitor* monitor; /**< Set to nullptr to use primary monitor.*/ + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Width in pixels.*/ PalBool show; /**< Show after creation.*/ PalBool maximized; /**< Maximize after creation.*/ PalBool minimized; /**< Minimze after creation.*/ PalBool center; /**< Center after creation.*/ - uint32_t width; /**< Width in pixels.*/ - uint32_t height; /**< Width in pixels.*/ - PalWindowStyle style; /**< Window style.*/ - const char* title; /**< Title in UTF-8 encoding.*/ - PalMonitor* monitor; /**< Set to nullptr to use primary monitor.*/ } PalWindowCreateInfo; /** @@ -707,7 +611,6 @@ typedef struct { * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palShutdownVideo * @sa palSetPreferredInstance */ @@ -724,7 +627,6 @@ PAL_API PalResult PAL_CALL palInitVideo( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palInitVideo */ PAL_API void PAL_CALL palShutdownVideo(); @@ -739,7 +641,6 @@ PAL_API void PAL_CALL palShutdownVideo(); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palInitVideo */ PAL_API void PAL_CALL palUpdateVideo(); @@ -754,7 +655,6 @@ PAL_API void PAL_CALL palUpdateVideo(); * Thread safety: Thread safe. * * @since 1.0 - * @ingroup pal_video * @sa palInitVideo */ PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures(); @@ -788,7 +688,6 @@ PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures(); * Thread safety: Must be called from the main thread. * * @since 1.1 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palSetFBConfig( const int index, @@ -821,7 +720,6 @@ PAL_API PalResult PAL_CALL palSetFBConfig( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palGetPrimaryMonitor */ PAL_API PalResult PAL_CALL palEnumerateMonitors( @@ -846,7 +744,6 @@ PAL_API PalResult PAL_CALL palEnumerateMonitors( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palEnumerateMonitors */ PAL_API PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor); @@ -869,7 +766,6 @@ PAL_API PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor); * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palGetMonitorInfo( PalMonitor* monitor, @@ -900,7 +796,6 @@ PAL_API PalResult PAL_CALL palGetMonitorInfo( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palEnumerateMonitorModes( PalMonitor* monitor, @@ -923,7 +818,6 @@ PAL_API PalResult PAL_CALL palEnumerateMonitorModes( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palSetMonitorMode */ PAL_API PalResult PAL_CALL palGetCurrentMonitorMode( @@ -953,7 +847,6 @@ PAL_API PalResult PAL_CALL palGetCurrentMonitorMode( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palGetCurrentMonitorMode */ PAL_API PalResult PAL_CALL palSetMonitorMode( @@ -975,7 +868,6 @@ PAL_API PalResult PAL_CALL palSetMonitorMode( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palValidateMonitorMode( PalMonitor* monitor, @@ -998,7 +890,6 @@ PAL_API PalResult PAL_CALL palValidateMonitorMode( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palSetMonitorOrientation( PalMonitor* monitor, @@ -1029,7 +920,6 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * - Creating hidden window is not supported. It will be ignored. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palCreateWindow( const PalWindowCreateInfo* info, @@ -1047,7 +937,6 @@ PAL_API PalResult PAL_CALL palCreateWindow( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palCreateWindow */ PAL_API void PAL_CALL palDestroyWindow(PalWindow* window); @@ -1067,7 +956,6 @@ PAL_API void PAL_CALL palDestroyWindow(PalWindow* window); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palMaximizeWindow * @sa palRestoreWindow */ @@ -1088,7 +976,6 @@ PAL_API PalResult PAL_CALL palMinimizeWindow(PalWindow* window); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palMinimizeWindow * @sa palRestoreWindow */ @@ -1111,7 +998,6 @@ PAL_API PalResult PAL_CALL palMaximizeWindow(PalWindow* window); * @note Wayland does not support restoring a minimized windows. * * @since 1.0 - * @ingroup pal_video * @sa palMinimizeWindow * @sa palMaximizeWindow */ @@ -1133,7 +1019,6 @@ PAL_API PalResult PAL_CALL palRestoreWindow(PalWindow* window); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palHideWindow */ PAL_API PalResult PAL_CALL palShowWindow(PalWindow* window); @@ -1153,7 +1038,6 @@ PAL_API PalResult PAL_CALL palShowWindow(PalWindow* window); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palShowWindow */ PAL_API PalResult PAL_CALL palHideWindow(PalWindow* window); @@ -1178,7 +1062,6 @@ PAL_API PalResult PAL_CALL palHideWindow(PalWindow* window); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palFlashWindow( PalWindow* window, @@ -1199,7 +1082,6 @@ PAL_API PalResult PAL_CALL palFlashWindow( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palSetWindowStyle */ PAL_API PalResult PAL_CALL palGetWindowStyle( @@ -1221,7 +1103,6 @@ PAL_API PalResult PAL_CALL palGetWindowStyle( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palGetWindowMonitor( PalWindow* window, @@ -1246,7 +1127,6 @@ PAL_API PalResult PAL_CALL palGetWindowMonitor( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palSetWindowTitle */ PAL_API PalResult PAL_CALL palGetWindowTitle( @@ -1271,7 +1151,6 @@ PAL_API PalResult PAL_CALL palGetWindowTitle( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palSetWindowPos */ PAL_API PalResult PAL_CALL palGetWindowPos( @@ -1295,7 +1174,6 @@ PAL_API PalResult PAL_CALL palGetWindowPos( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palSetWindowSize */ PAL_API PalResult PAL_CALL palGetWindowSize( @@ -1318,7 +1196,6 @@ PAL_API PalResult PAL_CALL palGetWindowSize( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palGetWindowState( PalWindow* window, @@ -1339,7 +1216,6 @@ PAL_API PalResult PAL_CALL palGetWindowState( * Thread safety: Thread-safe. * * @since 1.0 - * @ingroup pal_video */ PAL_API const PalBool* PAL_CALL palGetKeycodeState(); @@ -1358,7 +1234,6 @@ PAL_API const PalBool* PAL_CALL palGetKeycodeState(); * Thread safety: Thread-safe. * * @since 1.0 - * @ingroup pal_video */ PAL_API const PalBool* PAL_CALL palGetScancodeState(); @@ -1376,7 +1251,6 @@ PAL_API const PalBool* PAL_CALL palGetScancodeState(); * @Thread safety: Thread-safe. * * @since 1.0 - * @ingroup pal_video */ PAL_API const PalBool* PAL_CALL palGetMouseState(); @@ -1394,12 +1268,11 @@ PAL_API const PalBool* PAL_CALL palGetMouseState(); * Thread safety: Thread-safe if `dx` and `dy` are thread * local. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ PAL_API void PAL_CALL palGetMouseDelta( - int32_t* dx, - int32_t* dy); + float* dx, + float* dy); /** * @brief Get the wheel delta of the mouse. @@ -1413,31 +1286,9 @@ PAL_API void PAL_CALL palGetMouseDelta( * Thread safety: Thread-safe if `dx` and `dy` are thread * local. * - * @since 1.0 - * @ingroup pal_video + * @since 2.0 */ PAL_API void PAL_CALL palGetMouseWheelDelta( - int32_t* dx, - int32_t* dy); - -/** - * @brief Get the raw wheel delta of the mouse in floats. - * - * The video system must be initialized before this call. - * The wheel delta will be updated when palUpdateVideo() is called. - * - * @param[in] dx Pointer to recieve the mouse wheel delta x in floats. Can be - * nullptr. - * @param[in] dy Pointer to recieve the mouse wheel delta y in floats. Can be - * nullptr. - * - * Thread safety: Thread-safe if `dx` and `dy` are thread - * local. - * - * @since 1.3 - * @ingroup pal_video - */ -PAL_API void PAL_CALL palGetRawMouseWheelDelta( float* dx, float* dy); @@ -1449,12 +1300,11 @@ PAL_API void PAL_CALL palGetRawMouseWheelDelta( * * @param[in] window Pointer to the window. * - * @return `true` if the window is visible otherwise `false`. + * @return `true` if the window is visible otherwise `PAL_FALSE`. * * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalBool PAL_CALL palIsWindowVisible(PalWindow* window); @@ -1470,7 +1320,6 @@ PAL_API PalBool PAL_CALL palIsWindowVisible(PalWindow* window); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalWindow* PAL_CALL palGetFocusWindow(); @@ -1478,38 +1327,23 @@ PAL_API PalWindow* PAL_CALL palGetFocusWindow(); * @brief Get the native handle of the provided window. * * The video system must be initialized before this call. + * + * On Wayland: `::nativeHandle1`, `::nativeHandle2` and `::nativeHandle3` + * are `xdg_surface`, `xdg_toplevel` and `wl_egl_window` respectively if available. * * @param[in] window Pointer to the window. + * @param[out] info Pointer to a PalWindowHandleInfo to fill. * - * @return The native handle of the window on success or nullptr on failure. - * - * Thread safety: Thread-safe. - * - * @since 1.0 - * @ingroup pal_video - */ -PAL_API PalWindowHandleInfo PAL_CALL palGetWindowHandleInfo(PalWindow* window); - -/** - * @brief Get the native handles of the provided window. - * - * The video system must be initialized before this call. - * - * On Wayland: `PalWindowHandleInfoEx::nativeHandle1`, - * `PalWindowHandleInfoEx::nativeHandle2` and - * `PalWindowHandleInfoEx::nativeHandle3` are xdg_surface, xdg_toplevel - * and wl_egl_window respectively. - * - * @param[in] window Pointer to the window. - * - * @return The native handles of the window on success or nullptr on failure. + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. * * Thread safety: Thread-safe. * - * @since 1.3 - * @ingroup pal_video + * @since 2.0 */ -PAL_API PalWindowHandleInfoEx PAL_CALL palGetWindowHandleInfoEx(PalWindow* w); +PAL_API PalResult PAL_CALL palGetWindowHandleInfo( + PalWindow* window, + PalWindowHandleInfo* info); /** * @brief Set the opacity of the provided window. @@ -1527,7 +1361,6 @@ PAL_API PalWindowHandleInfoEx PAL_CALL palGetWindowHandleInfoEx(PalWindow* w); * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palSetWindowOpacity( PalWindow* window, @@ -1548,7 +1381,6 @@ PAL_API PalResult PAL_CALL palSetWindowOpacity( * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palGetWindowStyle */ PAL_API PalResult PAL_CALL palSetWindowStyle( @@ -1571,7 +1403,6 @@ PAL_API PalResult PAL_CALL palSetWindowStyle( * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palGetWindowTitle */ PAL_API PalResult PAL_CALL palSetWindowTitle( @@ -1594,7 +1425,6 @@ PAL_API PalResult PAL_CALL palSetWindowTitle( * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palGetWindowPos */ PAL_API PalResult PAL_CALL palSetWindowPos( @@ -1620,7 +1450,6 @@ PAL_API PalResult PAL_CALL palSetWindowPos( * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palGetWindowSize */ PAL_API PalResult PAL_CALL palSetWindowSize( @@ -1642,7 +1471,6 @@ PAL_API PalResult PAL_CALL palSetWindowSize( * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palGetFocusWindow */ PAL_API PalResult PAL_CALL palSetFocusWindow(PalWindow* window); @@ -1664,7 +1492,6 @@ PAL_API PalResult PAL_CALL palSetFocusWindow(PalWindow* window); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palDestroyIcon */ PAL_API PalResult PAL_CALL palCreateIcon( @@ -1684,7 +1511,6 @@ PAL_API PalResult PAL_CALL palCreateIcon( * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palCreateIcon */ PAL_API void PAL_CALL palDestroyIcon(PalIcon* icon); @@ -1704,7 +1530,6 @@ PAL_API void PAL_CALL palDestroyIcon(PalIcon* icon); * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palSetWindowIcon( PalWindow* window, @@ -1726,7 +1551,6 @@ PAL_API PalResult PAL_CALL palSetWindowIcon( * Thread safety: Must only be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palDestroyCursor */ PAL_API PalResult PAL_CALL palCreateCursor( @@ -1748,7 +1572,6 @@ PAL_API PalResult PAL_CALL palCreateCursor( * Thread safety: Must only be called from the main thread. * * @since 1.1 - * @ingroup pal_video * @sa palDestroyCursor */ PAL_API PalResult PAL_CALL palCreateCursorFrom( @@ -1768,7 +1591,6 @@ PAL_API PalResult PAL_CALL palCreateCursorFrom( * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video * @sa palCreateCursor */ PAL_API void PAL_CALL palDestroyCursor(PalCursor* cursor); @@ -1782,12 +1604,11 @@ PAL_API void PAL_CALL palDestroyCursor(PalCursor* cursor); * This affects all created cursors since the platform (OS) merges all cursors * into a single one on the screen. * - * @param[in] show True to make the cursor visible otherwise false. + * @param[in] show True to make the cursor visible otherwise `PAL_FALSE`. * * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API void PAL_CALL palShowCursor(PalBool show); @@ -1802,7 +1623,7 @@ PAL_API void PAL_CALL palShowCursor(PalBool show); * the window before destroying the window. * * @param[in] window Pointer to the window. - * @param[in] clip True to clip to window or false to unclip. + * @param[in] clip True to clip to window or `PAL_FALSE` to unclip. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1810,7 +1631,6 @@ PAL_API void PAL_CALL palShowCursor(PalBool show); * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palClipCursor( PalWindow* window, @@ -1835,7 +1655,6 @@ PAL_API PalResult PAL_CALL palClipCursor( * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palGetCursorPos( PalWindow* window, @@ -1859,7 +1678,6 @@ PAL_API PalResult PAL_CALL palGetCursorPos( * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palSetCursorPos( PalWindow* window, @@ -1880,7 +1698,6 @@ PAL_API PalResult PAL_CALL palSetCursorPos( * Thread safety: Must be called from the main thread. * * @since 1.0 - * @ingroup pal_video */ PAL_API PalResult PAL_CALL palSetWindowCursor( PalWindow* window, @@ -1905,7 +1722,6 @@ PAL_API PalResult PAL_CALL palSetWindowCursor( * @note The returned instance or display must not be freed. * * @since 1.2 - * @ingroup pal_video */ PAL_API void* PAL_CALL palGetInstance(); @@ -1941,7 +1757,6 @@ PAL_API void* PAL_CALL palGetInstance(); * Thread safety: Must be called from the main thread. * * @since 1.2 - * @ingroup pal_video * @sa palGetInstance * @sa palDestroyWindow * @sa palDetachWindow @@ -1978,7 +1793,6 @@ PAL_API PalResult PAL_CALL palAttachWindow( * Thread safety: Must be called from the main thread. * * @since 1.2 - * @ingroup pal_video * @sa palAttachWindow */ PAL_API PalResult PAL_CALL palDetachWindow( @@ -2001,7 +1815,6 @@ PAL_API PalResult PAL_CALL palDetachWindow( * @note The provided instance will not be freed by the video system. * * @since 1.3 - * @ingroup pal_video * @sa palInitVideo */ PAL_API void PAL_CALL palSetPreferredInstance(void* instance); diff --git a/pal.lua b/pal.lua index 2d6e1f83..1598df3e 100644 --- a/pal.lua +++ b/pal.lua @@ -85,10 +85,22 @@ project "PAL" if (PAL_BUILD_VIDEO_MODULE) then filter {"system:windows", "configurations:*"} - files { "src/video/pal_video_win32.c" } + files { + "src/video/win32/pal_cursor_win32.c", + "src/video/win32/pal_icon_win32.c", + "src/video/win32/pal_monitor_win32.c", + "src/video/win32/pal_window_win32.c", + "src/video/win32/pal_video_win32.c" + } filter {"system:linux", "configurations:*"} - files { "src/video/pal_video_linux.c" } + files { + "src/video/linux/pal_cursor_linux.c", + "src/video/linux/pal_icon_linux.c", + "src/video/linux/pal_monitor_linux.c", + "src/video/linux/pal_window_linux.c", + "src/video/linux/pal_video_linux.c" + } -- check for wayland support. This is cross compiler local waylandPaths = { diff --git a/pal_config.lua b/pal_config.lua index 78d521da..07bf5d26 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -15,7 +15,7 @@ PAL_BUILD_SYSTEM_MODULE = false PAL_BUILD_THREAD_MODULE = false -- build video module -PAL_BUILD_VIDEO_MODULE = false +PAL_BUILD_VIDEO_MODULE = true -- build opengl module PAL_BUILD_OPENGL_MODULE = false diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 36f516a8..0d6daaea 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -1,24 +1,8 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ // ================================================== @@ -1094,7 +1078,7 @@ static CommandBufferData* getFreeCmdBufferData(CommandPool* pool) { for (int i = 0; i < pool->size; ++i) { if (!pool->cmdBuffersData[i].used) { - pool->cmdBuffersData[i].used = true; + pool->cmdBuffersData[i].used = PAL_TRUE; return &pool->cmdBuffersData[i]; } } @@ -1112,7 +1096,7 @@ static CommandBufferData* getFreeCmdBufferData(CommandPool* pool) pool->cmdBuffersData = data; pool->size = count; - pool->cmdBuffersData[freeIndex].used = true; + pool->cmdBuffersData[freeIndex].used = PAL_TRUE; return &pool->cmdBuffersData[freeIndex]; } return nullptr; @@ -1289,16 +1273,16 @@ static PalBool fillBuildInfoD3D12( static uint32_t maxGeometryCount = 100000; if (info->geometryCount > maxGeometryCount) { - return false; + return PAL_FALSE; } if (info->instanceCount > maxInstanceCount) { - return false; + return PAL_FALSE; } for (int i = 0; i < info->geometryCount; i++) { if (info->geometries[i].primitiveCount > maxPrimitiveCount) { - return false; + return PAL_FALSE; } D3D12_RAYTRACING_GEOMETRY_DESC* tmp = &geometries[i]; @@ -1377,7 +1361,7 @@ static PalBool fillBuildInfoD3D12( buildInfo->DestAccelerationStructureData = dstAs; buildInfo->ScratchAccelerationStructureData = info->scratchBufferAddress; - return true; + return PAL_TRUE; } static uint32_t getFormatSizeD3D12(PalFormat format) @@ -2043,7 +2027,7 @@ static void commitShaderbindingTableUpdateD3D12( barrier.Transition.pResource = sbt->buffer; cmdBuffer->handle->lpVtbl->ResourceBarrier(cmdBuffer->handle, 1, &barrier); - sbt->isDirty = false; + sbt->isDirty = PAL_FALSE; } static void getDescriptorTierLimitsD3D12( @@ -2203,7 +2187,7 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D.severities[s_D3D.severityCount++] = D3D12_MESSAGE_SEVERITY_CORRUPTION; } } - s_D3D.debugLayer = true; + s_D3D.debugLayer = PAL_TRUE; s_D3D.debugCallback = debugger->callback; } } @@ -2364,7 +2348,7 @@ PalResult PAL_CALL getAdapterInfoD3D12( &arch, sizeof(arch)); - if (arch.UMA == true) { + if (arch.UMA == PAL_TRUE) { info->type = PAL_ADAPTER_TYPE_INTEGRATED; } else { @@ -2443,10 +2427,10 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( // always supported getDescriptorTierLimitsD3D12(d3dAdapter->tmpDevice, resourceCaps, nullptr); resourceCaps->maxBoundSets = 32; - resourceCaps->sampledImageDynamicArrayIndexing = true; - resourceCaps->storageImageDynamicArrayIndexing = true; - resourceCaps->storageBufferDynamicArrayIndexing = true; - resourceCaps->uniformBufferDynamicArrayIndexing = true; + resourceCaps->sampledImageDynamicArrayIndexing = PAL_TRUE; + resourceCaps->storageImageDynamicArrayIndexing = PAL_TRUE; + resourceCaps->storageBufferDynamicArrayIndexing = PAL_TRUE; + resourceCaps->uniformBufferDynamicArrayIndexing = PAL_TRUE; // compute limits computeCaps->maxWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; @@ -3106,17 +3090,17 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - caps->depthResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; - caps->depthResolves[PAL_RESOLVE_MODE_AVERAGE] = true; - caps->depthResolves[PAL_RESOLVE_MODE_MIN] = true; - caps->depthResolves[PAL_RESOLVE_MODE_MAX] = true; + caps->depthResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = PAL_TRUE; + caps->depthResolves[PAL_RESOLVE_MODE_AVERAGE] = PAL_TRUE; + caps->depthResolves[PAL_RESOLVE_MODE_MIN] = PAL_TRUE; + caps->depthResolves[PAL_RESOLVE_MODE_MAX] = PAL_TRUE; - caps->stencilResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; - caps->stencilResolves[PAL_RESOLVE_MODE_AVERAGE] = false; - caps->stencilResolves[PAL_RESOLVE_MODE_MIN] = true; - caps->stencilResolves[PAL_RESOLVE_MODE_MAX] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = PAL_TRUE; + caps->stencilResolves[PAL_RESOLVE_MODE_AVERAGE] = PAL_FALSE; + caps->stencilResolves[PAL_RESOLVE_MODE_MIN] = PAL_TRUE; + caps->stencilResolves[PAL_RESOLVE_MODE_MAX] = PAL_TRUE; - caps->independentResolve = true; + caps->independentResolve = PAL_TRUE; return PAL_RESULT_SUCCESS; } @@ -3130,10 +3114,10 @@ PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( } // these are supported if fragment shading rate feature is - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_1X1] = true; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_1X2] = true; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X1] = true; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X2] = true; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_1X1] = PAL_TRUE; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_1X2] = PAL_TRUE; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X1] = PAL_TRUE; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X2] = PAL_TRUE; D3D12_FEATURE_DATA_D3D12_OPTIONS6 options = {0}; d3dDevice->handle->lpVtbl->CheckFeatureSupport( @@ -3143,22 +3127,22 @@ PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( sizeof(options)); if (options.AdditionalShadingRatesSupported) { - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X4] = true; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X2] = true; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X4] = true; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X4] = PAL_TRUE; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X2] = PAL_TRUE; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X4] = PAL_TRUE; } else { - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X4] = false; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X2] = false; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X4] = false; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X4] = PAL_FALSE; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X2] = PAL_FALSE; + caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X4] = PAL_FALSE; } // there are supported if fragment shading rate feature is - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP] = true; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE] = true; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN] = true; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX] = true; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL] = true; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP] = PAL_TRUE; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE] = PAL_TRUE; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN] = PAL_TRUE; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX] = PAL_TRUE; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL] = PAL_TRUE; caps->minTexelWidth = 1; // safe default caps->minTexelHeight = 1; // safe default @@ -3224,14 +3208,14 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( } // always supported - caps->sampledImageNonUniformIndexing = true; - caps->sampledImageUpdateAfterBind = true; - caps->storageImageNonUniformIndexing = true; - caps->storageImageUpdateAfterBind = true; - caps->storageBufferNonUniformIndexing = true; - caps->storageBufferUpdateAfterBind = true; - caps->uniformBufferNonUniformIndexing = true; - caps->uniformBufferUpdateAfterBind = true; + caps->sampledImageNonUniformIndexing = PAL_TRUE; + caps->sampledImageUpdateAfterBind = PAL_TRUE; + caps->storageImageNonUniformIndexing = PAL_TRUE; + caps->storageImageUpdateAfterBind = PAL_TRUE; + caps->storageBufferNonUniformIndexing = PAL_TRUE; + caps->storageBufferUpdateAfterBind = PAL_TRUE; + caps->uniformBufferNonUniformIndexing = PAL_TRUE; + caps->uniformBufferUpdateAfterBind = PAL_TRUE; getDescriptorTierLimitsD3D12(d3dDevice->handle, nullptr, caps); return PAL_RESULT_SUCCESS; @@ -3341,7 +3325,7 @@ PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) // wait on the fence if the submited work is not done if (fence->lpVtbl->GetCompletedValue(fence) < d3dQueue->fenceValue) { - HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + HANDLE event = CreateEvent(nullptr, PAL_FALSE, PAL_FALSE, nullptr); fence->lpVtbl->SetEventOnCompletion(fence, d3dQueue->fenceValue, event); WaitForSingleObject(event, INFINITE); CloseHandle(event); @@ -3355,9 +3339,9 @@ PalBool PAL_CALL canQueuePresentD3D12( { Queue* d3dQueue = (Queue*)queue; if (d3dQueue->type == PAL_QUEUE_TYPE_GRAPHICS) { - return true; // all graphics queues support presentation + return PAL_TRUE; // all graphics queues support presentation } - return false; + return PAL_FALSE; } // ================================================== @@ -3423,7 +3407,7 @@ PalBool PAL_CALL isFormatSupportedD3D12( DXGI_FORMAT fmt = formatToD3D12(format); if (fmt == DXGI_FORMAT_UNKNOWN) { - return false; + return PAL_FALSE; } support.Format = fmt; @@ -3434,10 +3418,10 @@ PalBool PAL_CALL isFormatSupportedD3D12( sizeof(support)); if (FAILED(result) || (support.Support1 == 0 && support.Support2 == 0)) { - return false; + return PAL_FALSE; } - return true; + return PAL_TRUE; } PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( @@ -3490,7 +3474,7 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( DXGI_FORMAT fmt = formatToD3D12(format); if (fmt == DXGI_FORMAT_UNKNOWN) { - return false; + return PAL_FALSE; } support.Format = fmt; @@ -3501,12 +3485,12 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( sizeof(support)); if (FAILED(result)) { - return false; + return PAL_FALSE; } if (support.Support1 == 0 && support.Support2 == 0) { // format not supported - return false; + return PAL_FALSE; } // check sample count @@ -3593,7 +3577,7 @@ PalResult PAL_CALL createImageD3D12( image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } - image->belongsToSwapchain = false; + image->belongsToSwapchain = PAL_FALSE; image->info.depthOrArraySize = info->depthOrArraySize; image->info.type = info->type; image->info.format = info->format; @@ -3647,9 +3631,9 @@ PalResult PAL_CALL getImageMemoryRequirementsD3D12( &d3dImage->desc); // d3d12 allows images to be used with only GPU only heap - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = false; + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = PAL_TRUE; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = PAL_FALSE; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = PAL_FALSE; requirements->alignment = allocationInfo.Alignment; requirements->size = allocationInfo.SizeInBytes; @@ -3917,7 +3901,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( HRESULT result; Surface* d3dSurface = (Surface*)surface; Device* d3dDevice = (Device*)device; - PalBool supportHDR10 = false; + PalBool supportHDR10 = PAL_FALSE; IDXGISwapChain1* swapchain1 = nullptr; IDXGISwapChain3* swapchain3 = nullptr; @@ -3963,31 +3947,31 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( &flags); if (SUCCEEDED(result) && (flags & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) { - supportHDR10 = true; + supportHDR10 = PAL_TRUE; } - BOOL allowTearing = FALSE; + BOOL allowTearing = PAL_FALSE; s_D3D.factory->lpVtbl->CheckFeatureSupport( s_D3D.factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing)); - caps->presentModes[PAL_PRESENT_MODE_FIFO] = true; + caps->presentModes[PAL_PRESENT_MODE_FIFO] = PAL_TRUE; if (allowTearing) { caps->minImageCount = 3; - caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = true; - caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = true; + caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_TRUE; + caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_TRUE; } else { caps->minImageCount = 2; - caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = false; - caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = false; + caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_FALSE; + caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_FALSE; } - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = true; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = false; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = false; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = PAL_TRUE; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = PAL_FALSE; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = PAL_FALSE; caps->maxImageCount = 8; // safe default caps->minImageWidth = 1; @@ -4004,10 +3988,10 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( baseFormats[2] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; baseFormats[3] = DXGI_FORMAT_R16G16B16A16_FLOAT; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = false; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = false; - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = false; - caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = false; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_FALSE; + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; + caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_FALSE; for (int i = 0; i < PAL_SURFACE_FORMAT_MAX; i++) { formatSupport.Format = baseFormats[i]; @@ -4019,21 +4003,21 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( if (SUCCEEDED(result) && (formatSupport.Support1 != 0 || formatSupport.Support2 != 0)) { if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = true; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; } if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = true; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_TRUE; } if (baseFormats[i] == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) { - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = true; + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; } if (baseFormats[i] == DXGI_FORMAT_R16G16B16A16_FLOAT) { // check HDR10 color space if (supportHDR10) { - caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = true; + caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_TRUE; } } } @@ -4059,7 +4043,7 @@ PalResult PAL_CALL createSwapchainD3D12( Device* d3dDevice = (Device*)device; Queue* d3dQueue = (Queue*)queue; Swapchain* swapchain = nullptr; - PalBool isHDRColorspace = false; + PalBool isHDRColorspace = PAL_FALSE; if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; @@ -4093,7 +4077,7 @@ PalResult PAL_CALL createSwapchainD3D12( desc.SampleDesc.Count = 1; desc.BufferCount = info->imageCount; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.Stereo = false; + desc.Stereo = PAL_FALSE; desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; desc.Scaling = DXGI_SCALING_NONE; @@ -4129,7 +4113,7 @@ PalResult PAL_CALL createSwapchainD3D12( } else if (info->format == PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10) { desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; imageFormat = PAL_FORMAT_R16G16B16A16_SFLOAT; - isHDRColorspace = true; + isHDRColorspace = PAL_TRUE; } swapchain->format = desc.Format; @@ -4178,7 +4162,7 @@ PalResult PAL_CALL createSwapchainD3D12( swapchain->handle->lpVtbl->GetBuffer(swapchain->handle, i, &IID_Resource, (void**)&tmp); Image* image = &swapchain->images[i]; - image->belongsToSwapchain = true; + image->belongsToSwapchain = PAL_TRUE; image->device = d3dDevice; image->handle = tmp; @@ -4467,12 +4451,12 @@ PalResult PAL_CALL createFenceD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - fence->canReset = false; + fence->canReset = PAL_FALSE; if (d3dDevice->features & PAL_ADAPTER_FEATURE_FENCE_RESET) { - fence->canReset = true; + fence->canReset = PAL_TRUE; } - fence->isTimeline = false; // for sempaphores + fence->isTimeline = PAL_FALSE; // for sempaphores fence->value = 0; *outFence = (PalFence*)fence; return PAL_RESULT_SUCCESS; @@ -4495,7 +4479,7 @@ PalResult PAL_CALL waitFenceD3D12( uint64_t value = d3dFence->value; if (d3dFence->handle->lpVtbl->GetCompletedValue(d3dFence->handle) < value) { - HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + HANDLE event = CreateEvent(nullptr, PAL_FALSE, PAL_FALSE, nullptr); result = d3dFence->handle->lpVtbl->SetEventOnCompletion( d3dFence->handle, value, @@ -4539,9 +4523,9 @@ PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence) { Fence* d3dFence = (Fence*)fence; if (d3dFence->handle->lpVtbl->GetCompletedValue(d3dFence->handle) == 0) { - return false; + return PAL_FALSE; } - return true; + return PAL_TRUE; } // ================================================== @@ -4568,7 +4552,7 @@ PalResult PAL_CALL createSemaphoreD3D12( } if (enableTimeline) { - semaphore->isTimeline = true; + semaphore->isTimeline = PAL_TRUE; } result = d3dDevice->handle->lpVtbl->CreateFence( @@ -4587,7 +4571,7 @@ PalResult PAL_CALL createSemaphoreD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - semaphore->canReset = false; + semaphore->canReset = PAL_FALSE; semaphore->value = 0; *outSemaphore = (PalSemaphore*)semaphore; return PAL_RESULT_SUCCESS; @@ -4613,7 +4597,7 @@ PalResult PAL_CALL waitSemaphoreD3D12( } if (d3dSemaphore->handle->lpVtbl->GetCompletedValue(d3dSemaphore->handle) < value) { - HANDLE event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + HANDLE event = CreateEvent(nullptr, PAL_FALSE, PAL_FALSE, nullptr); result = d3dSemaphore->handle->lpVtbl->SetEventOnCompletion( d3dSemaphore->handle, value, @@ -4769,12 +4753,12 @@ PalResult PAL_CALL allocateCommandBufferD3D12( } memset(cmdBuffer, 0, sizeof(CommandBuffer)); - cmdBuffer->primary = true; + cmdBuffer->primary = PAL_TRUE; D3D12_COMMAND_LIST_TYPE cmdBufferType = cmdPool->type; if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { cmdBufferType = D3D12_COMMAND_LIST_TYPE_BUNDLE; - cmdBuffer->primary = false; + cmdBuffer->primary = PAL_FALSE; } // create an allocator @@ -4898,7 +4882,7 @@ void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) palFree(s_D3D.allocator, cmdBuffer); data->cmdBuffer = nullptr; - data->used = false; + data->used = PAL_FALSE; } } @@ -5227,7 +5211,7 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( d3dCmdBuffer->handle, info->colorAttachentCount, colorAttachments, - FALSE, + PAL_FALSE, depthStencil); for (int i = 0; i < info->colorAttachentCount; i++) { @@ -6477,20 +6461,20 @@ PalResult PAL_CALL createBufferD3D12( if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - buffer->isAccelerationStructure = true; + buffer->isAccelerationStructure = PAL_TRUE; } if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - buffer->isScratch = true; + buffer->isScratch = PAL_TRUE; } if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - buffer->supportsAddress = true; + buffer->supportsAddress = PAL_TRUE; } if (info->usages & PAL_BUFFER_USAGE_INDIRECT) { - buffer->hasIndirect = true; + buffer->hasIndirect = PAL_TRUE; } buffer->device = d3dDevice; @@ -6526,9 +6510,9 @@ PalResult PAL_CALL getBufferMemoryRequirementsD3D12( &d3dBuffer->desc); // d3d12 allows buffers to be used with all memory heap types - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = true; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = true; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = true; + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = PAL_TRUE; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = PAL_TRUE; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = PAL_TRUE; requirements->alignment = allocationInfo.Alignment; requirements->size = allocationInfo.SizeInBytes; @@ -6634,18 +6618,18 @@ PalResult PAL_CALL bindBufferMemoryD3D12( D3D12_HEAP_DESC heapProps = {0}; heapProps = *mem->lpVtbl->GetDesc(mem, &__ret); - d3dBuffer->canChangeState = true; + d3dBuffer->canChangeState = PAL_TRUE; if (heapProps.Properties.Type == D3D12_HEAP_TYPE_UPLOAD) { state = D3D12_RESOURCE_STATE_GENERIC_READ; - d3dBuffer->canChangeState = false; + d3dBuffer->canChangeState = PAL_FALSE; } else if (heapProps.Properties.Type == D3D12_HEAP_TYPE_READBACK) { state = D3D12_RESOURCE_STATE_COPY_DEST; - d3dBuffer->canChangeState = false; + d3dBuffer->canChangeState = PAL_FALSE; } if (d3dBuffer->isAccelerationStructure) { - d3dBuffer->canChangeState = false; + d3dBuffer->canChangeState = PAL_FALSE; state = D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; } else if (d3dBuffer->isScratch) { @@ -7020,7 +7004,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( &__gpuRet); heap->gpuBase = gpuHandle.ptr; - pool->hasResourceHeap = true; + pool->hasResourceHeap = PAL_TRUE; } // sampler heap @@ -7064,7 +7048,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( &__gpuRet); heap->gpuBase = gpuHandle.ptr; - pool->hasSamplerHeap = true; + pool->hasSamplerHeap = PAL_TRUE; } pool->hasDescriptorIndexing = info->enableDescriptorIndexing; @@ -7659,7 +7643,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( HRESULT result; uint32_t patchControlPoints = 0; uint32_t totalSize = 0; - PalBool alphaToCoverageEnable = false; + PalBool alphaToCoverageEnable = PAL_FALSE; Pipeline* pipeline = nullptr; Device* d3dDevice = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; @@ -7887,7 +7871,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( IBStripCutStream* inStripCutStream = &graphicsStreamDesc.ibStripCut; totalSize += sizeof(IBStripCutStream); inStripCutStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE; - if (info->primitiveRestartEnable == false) { + if (info->primitiveRestartEnable == PAL_FALSE) { inStripCutStream->value = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; } else { @@ -7905,7 +7889,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( rasterizerStream->desc.CullMode = D3D12_CULL_MODE_NONE; rasterizerStream->desc.FillMode = D3D12_FILL_MODE_SOLID; - rasterizerStream->desc.FrontCounterClockwise = FALSE; + rasterizerStream->desc.FrontCounterClockwise = PAL_FALSE; rasterizerStream->desc.DepthClipEnable = TRUE; if (info->rasterizerState) { @@ -7928,7 +7912,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( } if (state->frontFace == PAL_FRONT_FACE_CLOCKWISE) { - rasterizerStream->desc.FrontCounterClockwise = FALSE; + rasterizerStream->desc.FrontCounterClockwise = PAL_FALSE; } else { rasterizerStream->desc.FrontCounterClockwise = TRUE; @@ -7967,8 +7951,8 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( DepthStencilStream* depthStencilStream = &graphicsStreamDesc.depthStencil; totalSize += sizeof(DepthStencilStream); depthStencilStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL; - depthStencilStream->desc.DepthEnable = FALSE; - depthStencilStream->desc.StencilEnable = FALSE; + depthStencilStream->desc.DepthEnable = PAL_FALSE; + depthStencilStream->desc.StencilEnable = PAL_FALSE; if (info->depthStencilState) { PalDepthStencilState* state = info->depthStencilState; @@ -8041,7 +8025,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( } // Fragment shading rate - pipeline->hasFsr = false; + pipeline->hasFsr = PAL_FALSE; if (info->fragmentShadingRateState) { PalFragmentShadingRateState* state = info->fragmentShadingRateState; pipeline->shadingRate = shadingRateToD3D12(state->rate); @@ -8160,7 +8144,7 @@ PalResult PAL_CALL createComputePipelineD3D12( pipeline->type = COMPUTE_PIPELINE; pipeline->strides = nullptr; - pipeline->hasFsr = false; + pipeline->hasFsr = PAL_FALSE; pipeline->layout = layout; pipeline->shaderExports = nullptr; pipeline->localRootSignature = nullptr; @@ -8338,7 +8322,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( ShaderExport* shaderExport = &pipeline->shaderExports[exportsOffset + j]; ShaderEntry* entry = &tmp->entries[j]; - shaderExport->isHitGroup = false; + shaderExport->isHitGroup = PAL_FALSE; shaderExport->stage = entry->stage; wcscpy(shaderExport->entryName, entry->entryName); @@ -8377,7 +8361,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( ShaderExport* hitGroupExport = &pipeline->shaderExports[exportCount++]; wcscpy(hitGroupExport->entryName, hitGroups[hitGroupIndex].entryName); - hitGroupExport->isHitGroup = true; + hitGroupExport->isHitGroup = PAL_TRUE; hitGroupExport->stage = PAL_SHADER_STAGE_CLOSEST_HIT; // to identify group->AnyHitShaderImport = nullptr; @@ -8520,7 +8504,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( pipeline->type = RAY_TRACING_PIPELINE; pipeline->strides = nullptr; - pipeline->hasFsr = false; + pipeline->hasFsr = PAL_FALSE; pipeline->layout = layout; pipeline->sbtInfo = sbtInfo; @@ -8768,12 +8752,12 @@ PalResult PAL_CALL createShaderBindingTableD3D12( PalShaderStage stage = tmp->stage; // skip any hit, closest hit, intersection shaders without isHitGroup PalBool - PalBool isHitGroup = false; + PalBool isHitGroup = PAL_FALSE; if (stage == PAL_SHADER_STAGE_ANY_HIT || stage == PAL_SHADER_STAGE_CLOSEST_HIT || stage == PAL_SHADER_STAGE_INTERSECTION) { if (tmp->isHitGroup) { - isHitGroup = true; + isHitGroup = PAL_TRUE; } else { continue; @@ -8908,7 +8892,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( sbt->stagingBufferSize = bufferSize; sbt->pipeline = pipeline; - sbt->isDirty = true; // we need to copy from the staging to the gpu buffer + sbt->isDirty = PAL_TRUE; // we need to copy from the staging to the gpu buffer *outSbt = (PalShaderBindingTable*)sbt; return PAL_RESULT_SUCCESS; } @@ -8981,7 +8965,7 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( } d3dSbt->stagingBuffer->lpVtbl->Unmap(d3dSbt->stagingBuffer, 0, nullptr); - d3dSbt->isDirty = true; + d3dSbt->isDirty = PAL_TRUE; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 54ff9115..6222e728 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -1,24 +1,8 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ // ================================================== @@ -2128,7 +2112,7 @@ PalResult PAL_CALL palInitGraphics( #endif // _WIN32 s_Graphics.allocator = allocator; - s_Graphics.initialized = true; + s_Graphics.initialized = PAL_TRUE; return PAL_RESULT_SUCCESS; } @@ -2160,7 +2144,7 @@ void PAL_CALL palShutdownGraphics() #endif // _WIN32 memset(&s_Graphics, 0, sizeof(s_Graphics)); - s_Graphics.initialized = false; + s_Graphics.initialized = PAL_FALSE; } // ================================================== @@ -2505,7 +2489,7 @@ PalBool PAL_CALL palCanQueuePresent( if (s_Graphics.initialized && queue) { return queue->backend->canQueuePresent(queue, surface); } - return false; + return PAL_FALSE; } PalResult PAL_CALL palWaitQueue(PalQueue* queue) @@ -2550,7 +2534,7 @@ PalBool PAL_CALL palIsFormatSupported( PalFormat format) { if (!s_Graphics.initialized || !adapter) { - return false; + return PAL_FALSE; } return adapter->backend->isFormatSupported(adapter, format); @@ -3016,7 +3000,7 @@ PalBool PAL_CALL palIsFenceSignaled(PalFence* fence) if (s_Graphics.initialized && fence) { return fence->backend->isFenceSignaled(fence); } - return false; + return PAL_FALSE; } // ================================================== @@ -4546,11 +4530,11 @@ PalBool PAL_CALL palBuildWorkGroupInfo( PalWorkGroupInfo* infos) { if (!data) { - return false; + return PAL_FALSE; } if (*count == 0 && infos) { - return false; + return PAL_FALSE; } uint32_t workGroupCount[3]; @@ -4565,7 +4549,7 @@ PalBool PAL_CALL palBuildWorkGroupInfo( // total number of group build info on all axis *count = groupInfoCount[0] * groupInfoCount[1] * groupInfoCount[2]; ; - return true; + return PAL_TRUE; } for (int i = 0; i < *count; i++) { @@ -4587,5 +4571,5 @@ PalBool PAL_CALL palBuildWorkGroupInfo( } } - return true; + return PAL_TRUE; } diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index cfe24888..20270255 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -1,24 +1,8 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ // ================================================== @@ -2354,7 +2338,7 @@ static void fillBuildInfoVk( VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; data = &tmp->geometry.instances; data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; - data->arrayOfPointers = false; + data->arrayOfPointers = PAL_FALSE; VkDeviceOrHostAddressConstKHR address = {0}; address.deviceAddress = info->instanceBufferAddress; @@ -2659,7 +2643,7 @@ static void commitShaderbindingTableUpdateVk( dependencyInfo.pBufferMemoryBarriers = &barrier; cmdBuffer->device->cmdPipelineBarrier(cmdBuffer->handle, &dependencyInfo); - sbt->isDirty = false; + sbt->isDirty = PAL_FALSE; } // ================================================== @@ -3023,18 +3007,18 @@ PalResult PAL_CALL initGraphicsVk( // clang-format on // get version - PalBool versionFallback = false; + PalBool versionFallback = PAL_FALSE; uint32_t version = 0; if (s_Vk.enumerateInstanceVersion) { s_Vk.enumerateInstanceVersion(&version); if (version <= VK_API_VERSION_1_0) { - versionFallback = true; + versionFallback = PAL_TRUE; } } VkResult result; uint32_t layerCount = 0; - PalBool hasValidationLayer = false; + PalBool hasValidationLayer = PAL_FALSE; s_Vk.messenger = nullptr; s_Vk.allocator = allocator; VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {0}; @@ -3054,7 +3038,7 @@ PalResult PAL_CALL initGraphicsVk( for (int i = 0; i < layerCount; i++) { const char* name = props[i].layerName; if (strcmp(name, "VK_LAYER_KHRONOS_validation") == 0) { - hasValidationLayer = true; + hasValidationLayer = PAL_TRUE; break; } } @@ -3106,33 +3090,33 @@ PalResult PAL_CALL initGraphicsVk( return PAL_RESULT_SUCCESS; } - PalBool hasXlib = false; - PalBool hasXcb = false; - PalBool hasWayland = false; - PalBool hasWin32 = false; - PalBool hasSurface = false; - PalBool hasExtDebug = false; + PalBool hasXlib = PAL_FALSE; + PalBool hasXcb = PAL_FALSE; + PalBool hasWayland = PAL_FALSE; + PalBool hasWin32 = PAL_FALSE; + PalBool hasSurface = PAL_FALSE; + PalBool hasExtDebug = PAL_FALSE; s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, extensionProps); for (int i = 0; i < extCount; i++) { VkExtensionProperties* prop = &extensionProps[i]; if (strcmp(prop->extensionName, "VK_KHR_xlib_surface") == 0) { - hasXlib = true; + hasXlib = PAL_TRUE; } else if (strcmp(prop->extensionName, "VK_KHR_xcb_surface") == 0) { - hasXcb = true; + hasXcb = PAL_TRUE; } else if (strcmp(prop->extensionName, "VK_KHR_wayland_surface") == 0) { - hasWayland = true; + hasWayland = PAL_TRUE; } else if (strcmp(prop->extensionName, "VK_KHR_win32_surface") == 0) { - hasWin32 = true; + hasWin32 = PAL_TRUE; } else if (strcmp(prop->extensionName, "VK_KHR_surface") == 0) { - hasSurface = true; + hasSurface = PAL_TRUE; } else if (strcmp(prop->extensionName, "VK_EXT_debug_utils") == 0) { - hasExtDebug = true; + hasExtDebug = PAL_TRUE; } } palFree(s_Vk.allocator, extensionProps); @@ -3366,13 +3350,13 @@ PalResult PAL_CALL enumerateAdaptersVk( return PAL_RESULT_OUT_OF_MEMORY; } - PalBool found = false; + PalBool found = PAL_FALSE; s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extCount, exts); for (int i = 0; i < extCount; i++) { const char* ext = exts[i].extensionName; if (strcmp(ext, "VK_KHR_dynamic_rendering") == 0) { - found = true; + found = PAL_TRUE; break; } } @@ -3625,19 +3609,19 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } // check extensions - PalBool rayTracing = false; - PalBool accelerationStructure = false; - PalBool meshShader = false; - PalBool fragmentRateShading = false; - PalBool timelineSemaphore = false; - PalBool descriptorIndexing = false; - PalBool shaderFloat16 = false; - PalBool multiiView = false; - PalBool dynamicstate = false; - PalBool bufferDeviceAddress = false; - PalBool shaderParameters = false; - PalBool nullDescriptors = false; - PalBool rayQuery = false; + PalBool rayTracing = PAL_FALSE; + PalBool accelerationStructure = PAL_FALSE; + PalBool meshShader = PAL_FALSE; + PalBool fragmentRateShading = PAL_FALSE; + PalBool timelineSemaphore = PAL_FALSE; + PalBool descriptorIndexing = PAL_FALSE; + PalBool shaderFloat16 = PAL_FALSE; + PalBool multiiView = PAL_FALSE; + PalBool dynamicstate = PAL_FALSE; + PalBool bufferDeviceAddress = PAL_FALSE; + PalBool shaderParameters = PAL_FALSE; + PalBool nullDescriptors = PAL_FALSE; + PalBool rayQuery = PAL_FALSE; s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, extensionProps); // clang-format off @@ -3645,34 +3629,34 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) for (int i = 0; i < extensionCount; i++) { VkExtensionProperties* props = &extensionProps[i]; if (strcmp(props->extensionName, "VK_KHR_ray_tracing_pipeline") == 0) { - rayTracing = true; + rayTracing = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_KHR_acceleration_structure") == 0) { - accelerationStructure = true; + accelerationStructure = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_EXT_mesh_shader") == 0) { - meshShader = true; + meshShader = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_KHR_fragment_shading_rate") == 0) { - fragmentRateShading = true; + fragmentRateShading = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_EXT_descriptor_indexing") == 0) { - descriptorIndexing = true; + descriptorIndexing = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_KHR_swapchain") == 0) { adapterFeatures |= PAL_ADAPTER_FEATURE_SWAPCHAIN; } else if (strcmp(props->extensionName, "VK_KHR_shader_float16_int8") == 0) { - shaderFloat16 = true; + shaderFloat16 = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_KHR_timeline_semaphore") == 0) { - timelineSemaphore = true; + timelineSemaphore = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_KHR_multiview") == 0) { - multiiView = true; + multiiView = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_EXT_extended_dynamic_state") == 0) { - dynamicstate = true; + dynamicstate = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_EXT_extended_dynamic_state2") == 0) { VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynState2 = {0}; @@ -3699,13 +3683,13 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT; } else if (strcmp(props->extensionName, "VK_KHR_buffer_device_address") == 0) { - bufferDeviceAddress = true; + bufferDeviceAddress = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_KHR_shader_draw_parameters") == 0) { - shaderParameters = true; + shaderParameters = PAL_TRUE; } else if (strcmp(props->extensionName, "VK_EXT_robustness2") == 0) { - nullDescriptors = true; + nullDescriptors = PAL_TRUE; } } @@ -4053,35 +4037,35 @@ PalResult PAL_CALL createDeviceVk( VkPhysicalDeviceFeatures coreFeatures = {0}; if (features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { - coreFeatures.samplerAnisotropy = true; + coreFeatures.samplerAnisotropy = PAL_TRUE; } if (features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { - coreFeatures.sampleRateShading = true; + coreFeatures.sampleRateShading = PAL_TRUE; } if (features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { - coreFeatures.multiViewport = true; + coreFeatures.multiViewport = PAL_TRUE; } if (features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { - coreFeatures.tessellationShader = true; + coreFeatures.tessellationShader = PAL_TRUE; } if (features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { - coreFeatures.geometryShader = true; + coreFeatures.geometryShader = PAL_TRUE; } if (features & PAL_ADAPTER_FEATURE_SHADER_INT16) { - coreFeatures.shaderInt16 = true; + coreFeatures.shaderInt16 = PAL_TRUE; } if (features & PAL_ADAPTER_FEATURE_SHADER_INT64) { - coreFeatures.shaderInt64 = true; + coreFeatures.shaderInt64 = PAL_TRUE; } if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT64) { - coreFeatures.shaderFloat64 = true; + coreFeatures.shaderFloat64 = PAL_TRUE; } // clang-format off @@ -4145,8 +4129,8 @@ PalResult PAL_CALL createDeviceVk( extensions[extCount++] = "VK_KHR_synchronization2"; } - dynamicRendering.dynamicRendering = true; - sync2.synchronization2 = true; + dynamicRendering.dynamicRendering = PAL_TRUE; + sync2.synchronization2 = PAL_TRUE; dynamicRendering.pNext = next; sync2.pNext = &dynamicRendering; @@ -4164,7 +4148,7 @@ PalResult PAL_CALL createDeviceVk( if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_timeline_semaphore"; } - timeline.timelineSemaphore = true; + timeline.timelineSemaphore = PAL_TRUE; timeline.pNext = next; next = &timeline; @@ -4174,7 +4158,7 @@ PalResult PAL_CALL createDeviceVk( if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_shader_float16_int8"; } - shader16.shaderFloat16 = true; + shader16.shaderFloat16 = PAL_TRUE; shader16.pNext = next; next = &shader16; @@ -4184,8 +4168,8 @@ PalResult PAL_CALL createDeviceVk( extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; extensions[extCount++] = "VK_KHR_acceleration_structure"; extensions[extCount++] = "VK_KHR_deferred_host_operations"; - ray.rayTracingPipeline = true; - acc.accelerationStructure = true; + ray.rayTracingPipeline = PAL_TRUE; + acc.accelerationStructure = PAL_TRUE; ray.pNext = next; acc.pNext = &ray; @@ -4194,11 +4178,11 @@ PalResult PAL_CALL createDeviceVk( if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { extensions[extCount++] = "VK_EXT_mesh_shader"; - mesh.meshShader = true; - mesh.taskShader = true; + mesh.meshShader = PAL_TRUE; + mesh.taskShader = PAL_TRUE; // mesh shader needs geometry feature for primitives - coreFeatures.geometryShader = true; + coreFeatures.geometryShader = PAL_TRUE; // msh draw indirect count if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT) { @@ -4218,11 +4202,11 @@ PalResult PAL_CALL createDeviceVk( if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { extensions[extCount++] = "VK_KHR_fragment_shading_rate"; - fsr.pipelineFragmentShadingRate = true; + fsr.pipelineFragmentShadingRate = PAL_TRUE; // fragment shading rate attachment needs this if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { - fsr.attachmentFragmentShadingRate = true; + fsr.attachmentFragmentShadingRate = PAL_TRUE; } fsr.pNext = next; @@ -4274,14 +4258,14 @@ PalResult PAL_CALL createDeviceVk( next = &descIndex; } - descIndex.descriptorBindingPartiallyBound = true; + descIndex.descriptorBindingPartiallyBound = PAL_TRUE; } if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_multiview"; } - multiView.multiview = true; + multiView.multiview = PAL_TRUE; multiView.pNext = next; next = &multiView; @@ -4293,7 +4277,7 @@ PalResult PAL_CALL createDeviceVk( if (props.apiVersion < VK_API_VERSION_1_3) { extensions[extCount++] = "VK_EXT_extended_dynamic_state"; } - dynamicState.extendedDynamicState = true; + dynamicState.extendedDynamicState = PAL_TRUE; dynamicState.pNext = next; next = &dynamicState; @@ -4303,7 +4287,7 @@ PalResult PAL_CALL createDeviceVk( features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE || features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { extensions[extCount++] = "VK_EXT_extended_dynamic_state2"; - dynamicState2.extendedDynamicState2 = true; + dynamicState2.extendedDynamicState2 = PAL_TRUE; dynamicState2.pNext = next; next = &dynamicState2; @@ -4313,7 +4297,7 @@ PalResult PAL_CALL createDeviceVk( if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_buffer_device_address"; } - bufferAddress.bufferDeviceAddress = true; + bufferAddress.bufferDeviceAddress = PAL_TRUE; bufferAddress.pNext = next; next = &bufferAddress; @@ -4323,7 +4307,7 @@ PalResult PAL_CALL createDeviceVk( if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_shader_draw_parameters"; } - drawParameters.shaderDrawParameters = true; + drawParameters.shaderDrawParameters = PAL_TRUE; drawParameters.pNext = next; next = &drawParameters; @@ -4331,7 +4315,7 @@ PalResult PAL_CALL createDeviceVk( if (features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS) { extensions[extCount++] = "VK_EXT_robustness2"; - nullDescriptors.nullDescriptor = true; + nullDescriptors.nullDescriptor = PAL_TRUE; nullDescriptors.pNext = next; next = &nullDescriptors; @@ -4889,36 +4873,36 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesVk( caps->independentResolve = props.independentResolve; if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { - caps->depthResolves[PAL_RESOLVE_MODE_AVERAGE] = true; + caps->depthResolves[PAL_RESOLVE_MODE_AVERAGE] = PAL_TRUE; } if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { - caps->depthResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; + caps->depthResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = PAL_TRUE; } if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_MIN_BIT_KHR) { - caps->depthResolves[PAL_RESOLVE_MODE_MIN] = true; + caps->depthResolves[PAL_RESOLVE_MODE_MIN] = PAL_TRUE; } if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { - caps->depthResolves[PAL_RESOLVE_MODE_MAX] = true; + caps->depthResolves[PAL_RESOLVE_MODE_MAX] = PAL_TRUE; } // stencil if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { - caps->stencilResolves[PAL_RESOLVE_MODE_AVERAGE] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_AVERAGE] = PAL_TRUE; } if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { - caps->stencilResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = PAL_TRUE; } if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MIN_BIT_KHR) { - caps->stencilResolves[PAL_RESOLVE_MODE_MIN] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_MIN] = PAL_TRUE; } if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { - caps->stencilResolves[PAL_RESOLVE_MODE_MAX] = true; + caps->stencilResolves[PAL_RESOLVE_MODE_MAX] = PAL_TRUE; } return PAL_RESULT_SUCCESS; @@ -4949,16 +4933,16 @@ PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk( // check against the max size if (size.width <= props.maxFragmentSize.width || size.height <= props.maxFragmentSize.height) { - caps->shadingRates[i] = true; + caps->shadingRates[i] = PAL_TRUE; } } - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP] = true; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE] = true; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP] = PAL_TRUE; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE] = PAL_TRUE; if (props.fragmentShadingRateNonTrivialCombinerOps) { - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN] = true; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX] = true; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL] = true; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN] = PAL_TRUE; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX] = PAL_TRUE; + caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL] = PAL_TRUE; } VkExtent2D size = props.minFragmentShadingRateAttachmentTexelSize; @@ -5071,38 +5055,38 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( // check sub feature for sampled image if (desc.shaderSampledImageArrayNonUniformIndexing) { - caps->sampledImageNonUniformIndexing = true; + caps->sampledImageNonUniformIndexing = PAL_TRUE; } if (desc.descriptorBindingSampledImageUpdateAfterBind) { - caps->sampledImageUpdateAfterBind = true; + caps->sampledImageUpdateAfterBind = PAL_TRUE; } // check sub feature for storage image if (desc.shaderStorageImageArrayNonUniformIndexing) { - caps->storageImageNonUniformIndexing = true; + caps->storageImageNonUniformIndexing = PAL_TRUE; } if (desc.descriptorBindingStorageImageUpdateAfterBind) { - caps->storageImageUpdateAfterBind = true; + caps->storageImageUpdateAfterBind = PAL_TRUE; } // check sub feature for storage buffer if (desc.shaderStorageBufferArrayNonUniformIndexing) { - caps->storageBufferNonUniformIndexing = true; + caps->storageBufferNonUniformIndexing = PAL_TRUE; } if (desc.descriptorBindingStorageBufferUpdateAfterBind) { - caps->storageBufferUpdateAfterBind = true; + caps->storageBufferUpdateAfterBind = PAL_TRUE; } // check sub feature for uniform buffer if (desc.shaderUniformBufferArrayNonUniformIndexing) { - caps->uniformBufferNonUniformIndexing = true; + caps->uniformBufferNonUniformIndexing = PAL_TRUE; } if (desc.descriptorBindingUniformBufferUpdateAfterBind) { - caps->uniformBufferUpdateAfterBind = true; + caps->uniformBufferUpdateAfterBind = PAL_TRUE; } caps->maxPerStageSampledImages = props.maxPerStageDescriptorUpdateAfterBindSampledImages; @@ -5243,10 +5227,10 @@ PalBool PAL_CALL canQueuePresentVk( // check if the queue is a graphics queue before we check its family // index for presentation support. if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { - return false; + return PAL_FALSE; } - VkBool32 supported = false; + VkBool32 supported = PAL_FALSE; result = s_Vk.checkSurfaceSupport( phyQueue->phyDevice, phyQueue->familyIndex, @@ -5254,10 +5238,10 @@ PalBool PAL_CALL canQueuePresentVk( &supported); if (result == VK_SUCCESS && supported) { - return true; + return PAL_TRUE; } - return false; + return PAL_FALSE; } // ================================================== @@ -5308,9 +5292,9 @@ PalBool PAL_CALL isFormatSupportedVk( VkFormat fmt = formatToVk(format); s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); if (props.optimalTilingFeatures != 0) { - return true; + return PAL_TRUE; } - return false; + return PAL_FALSE; } PalImageUsages PAL_CALL queryFormatImageUsagesVk( @@ -5419,7 +5403,7 @@ PalResult PAL_CALL createImageVk( return resultFromVk(result); } - image->belongsToSwapchain = false; + image->belongsToSwapchain = PAL_FALSE; image->device = vkDevice; image->info.depthOrArraySize = info->depthOrArraySize; image->info.type = info->type; @@ -5471,9 +5455,9 @@ PalResult PAL_CALL getImageMemoryRequirementsVk( requirements->size = (uint64_t)memReq.size; requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, 0); - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = false; + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = PAL_FALSE; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = PAL_FALSE; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = PAL_FALSE; for (int i = 0; i < PAL_MEMORY_TYPE_MAX; i++) { requirements->memoryTypes[i] = (memReq.memoryTypeBits & device->memoryClassMask[i]) != 0; @@ -5820,63 +5804,63 @@ PalResult PAL_CALL getSurfaceCapabilitiesVk( // get supported composite alphas VkCompositeAlphaFlagsKHR alpha = surfaceCaps.supportedCompositeAlpha; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = true; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = false; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = false; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = PAL_TRUE; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = PAL_FALSE; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = PAL_FALSE; if (alpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = true; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = PAL_TRUE; } if (alpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = true; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = PAL_TRUE; } // present modes - caps->presentModes[PAL_PRESENT_MODE_FIFO] = true; - caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = false; - caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = false; + caps->presentModes[PAL_PRESENT_MODE_FIFO] = PAL_TRUE; + caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_FALSE; + caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_FALSE; for (int i = 0; i < modeCount; i++) { if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { - caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = true; + caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_TRUE; } if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { - caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = true; + caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_TRUE; } } // get format and colorspace - caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = false; - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = false; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = false; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = false; + caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_FALSE; + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_FALSE; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; for (int i = 0; i < formatCount; i++) { VkSurfaceFormatKHR* fmt = &formats[i]; if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = true; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; } } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = true; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_TRUE; } } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = true; + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; } } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { // find its supported colorspace if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { - caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = true; + caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_TRUE; } } } @@ -6001,7 +5985,7 @@ PalResult PAL_CALL createSwapchainVk( // fill all images with the creatio info for (int i = 0; i < count; i++) { Image* image = &swapchain->images[i]; - image->belongsToSwapchain = true; + image->belongsToSwapchain = PAL_TRUE; image->device = vkDevice; image->handle = images[i]; @@ -6319,7 +6303,7 @@ PalResult PAL_CALL waitFenceVk( } } - result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, true, timeInNanoseconds); + result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, PAL_TRUE, timeInNanoseconds); if (result != VK_SUCCESS) { return resultFromVk(result); } @@ -6347,9 +6331,9 @@ PalBool PAL_CALL isFenceSignaledVk(PalFence* fence) Fence* vkFence = (Fence*)fence; VkResult result = s_Vk.isFenceSignaled(vkFence->device->handle, vkFence->handle); if (result == VK_SUCCESS) { - return true; + return PAL_TRUE; } else { - return false; + return PAL_FALSE; } } @@ -6380,14 +6364,14 @@ PalResult PAL_CALL createSemaphoreVk( createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; const void* next = nullptr; - semaphore->isTimeline = false; + semaphore->isTimeline = PAL_FALSE; if (enableTimeline && !hasTimeline) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } if (enableTimeline) { next = &timelineCreateInfo; - semaphore->isTimeline = true; + semaphore->isTimeline = PAL_TRUE; } createInfo.pNext = next; @@ -6571,10 +6555,10 @@ PalResult PAL_CALL allocateCommandBufferVk( allocateInfo.commandPool = vkPool->handle; allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - cmdBuffer->primary = true; + cmdBuffer->primary = PAL_TRUE; if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; - cmdBuffer->primary = false; + cmdBuffer->primary = PAL_FALSE; } result = s_Vk.allocateCommandBuffer(vkDevice->handle, &allocateInfo, &cmdBuffer->handle); @@ -8311,9 +8295,9 @@ PalResult PAL_CALL getBufferMemoryRequirementsVk( requirements->size = (uint64_t)memReq.size; requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, vkBuffer->usages); - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = false; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = false; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = false; + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = PAL_FALSE; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = PAL_FALSE; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = PAL_FALSE; for (int i = 0; i < PAL_MEMORY_TYPE_MAX; i++) { requirements->memoryTypes[i] = (memReq.memoryTypeBits & device->memoryClassMask[i]) != 0; @@ -9954,7 +9938,7 @@ PalResult PAL_CALL createShaderBindingTableVk( sbt->handleSize = groupHandleSize; sbt->pipeline = pipeline; - sbt->isDirty = true; // we need to copy from the staging to the gpu buffer + sbt->isDirty = PAL_TRUE; // we need to copy from the staging to the gpu buffer *outSbt = (PalShaderBindingTable*)sbt; return PAL_RESULT_SUCCESS; } @@ -10039,7 +10023,7 @@ PalResult PAL_CALL updateShaderBindingTableVk( } s_Vk.unmapMemory(vkDevice->handle, vkSbt->stagingBufferMemory); - vkSbt->isDirty = true; + vkSbt->isDirty = PAL_TRUE; return PAL_RESULT_SUCCESS; } diff --git a/src/opengl/pal_opengl_linux.c b/src/opengl/pal_opengl_linux.c index 8f9ff859..b5d9ca97 100644 --- a/src/opengl/pal_opengl_linux.c +++ b/src/opengl/pal_opengl_linux.c @@ -1,24 +1,8 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ // ================================================== @@ -276,7 +260,7 @@ static inline PalBool checkExtension( where = strstr(start, extension); if (!where) { - return false; + return PAL_FALSE; } // the extension was found, we find the terminator by adding the sizeof @@ -284,7 +268,7 @@ static inline PalBool checkExtension( terminator = where + extensionLen; if (where == start || *(where - 1) == ' ') { if (*terminator == ' ' || *terminator == '\0') { - return true; + return PAL_TRUE; } } @@ -296,7 +280,7 @@ static ContextData* getFreeContextData() { for (int i = 0; i < s_GL.maxContextData; ++i) { if (!s_GL.contextData[i].used) { - s_GL.contextData[i].used = true; + s_GL.contextData[i].used = PAL_TRUE; return &s_GL.contextData[i]; } } @@ -314,7 +298,7 @@ static ContextData* getFreeContextData() s_GL.contextData = data; s_GL.maxContextData = count; - s_GL.contextData[freeIndex].used = true; + s_GL.contextData[freeIndex].used = PAL_TRUE; return &s_GL.contextData[freeIndex]; } return nullptr; @@ -333,7 +317,7 @@ static void freeContextData(PalGLContext* context) { for (int i = 0; i < s_GL.maxContextData; ++i) { if (s_GL.contextData[i].used && s_GL.contextData[i].context == context) { - s_GL.contextData[i].used = false; + s_GL.contextData[i].used = PAL_FALSE; } } } @@ -639,7 +623,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) s_GL.eglDestroySurface(tmpDisplay, surface); s_GL.allocator = allocator; - s_GL.initialized = true; + s_GL.initialized = PAL_TRUE; if (tmpDisplay != display) { // tmpDisplay is a seperate display @@ -663,7 +647,7 @@ void PAL_CALL palShutdownGL() } dlclose(s_GL.handle); - s_GL.initialized = false; + s_GL.initialized = PAL_FALSE; } const PalGLInfo* PAL_CALL palGetGLInfo() @@ -776,17 +760,17 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( fbConfig->samples = samples; // True for EGL_WINDOW_BIT - fbConfig->doubleBuffer = true; - fbConfig->stereo = false; + fbConfig->doubleBuffer = PAL_TRUE; + fbConfig->stereo = PAL_FALSE; if (s_GL.info.extensions & PAL_GL_EXTENSION_COLORSPACE_SRGB) { // since EGL does not have a bit to check SRGB support // we check if all the color bits are greater than or equal to 8 if (fbConfig->redBits >= 8 && fbConfig->greenBits >= 8 && fbConfig->blueBits >= 8) { - fbConfig->sRGB = true; + fbConfig->sRGB = PAL_TRUE; } } else { - fbConfig->sRGB = false; + fbConfig->sRGB = PAL_FALSE; } } configCount++; @@ -1013,7 +997,7 @@ PalResult PAL_CALL palCreateGLContext( // set no error if (info->noError) { attribs[index++] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR; - attribs[index++] = true; + attribs[index++] = PAL_TRUE; } // release @@ -1103,7 +1087,7 @@ void PAL_CALL palDestroyGLContext(PalGLContext* context) s_GL.eglDestroyContext(s_GL.display, (EGLContext)context); s_GL.eglDestroySurface(s_GL.display, data->surface); - data->used = false; + data->used = PAL_FALSE; } } } diff --git a/src/opengl/pal_opengl_win32.c b/src/opengl/pal_opengl_win32.c index d8837fd3..d444eb41 100644 --- a/src/opengl/pal_opengl_win32.c +++ b/src/opengl/pal_opengl_win32.c @@ -1,24 +1,8 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ // ================================================== @@ -223,7 +207,7 @@ static inline PalBool checkExtension( where = strstr(start, extension); if (!where) { - return false; + return PAL_FALSE; } // the extension was found, we find the terminator by adding the sizeof @@ -231,7 +215,7 @@ static inline PalBool checkExtension( terminator = where + extensionLen; if (where == start || *(where - 1) == ' ') { if (*terminator == ' ' || *terminator == '\0') { - return true; + return PAL_TRUE; } } @@ -506,7 +490,7 @@ PalResult PAL_CALL palInitGL(const PalAllocator* allocator) // pixel format } - s_Wgl.initialized = true; + s_Wgl.initialized = PAL_TRUE; return PAL_RESULT_SUCCESS; } @@ -526,7 +510,7 @@ void PAL_CALL palShutdownGL() FreeLibrary(s_Gdi.handle); memset(&s_Wgl, 0, sizeof(Wgl)); - s_Wgl.initialized = false; + s_Wgl.initialized = PAL_FALSE; } const PalGLInfo* PAL_CALL palGetGLInfo() @@ -681,9 +665,9 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( config->stencilBits = pfd.cStencilBits; config->samples = 1; - config->stereo = (pfd.dwFlags & PFD_STEREO) ? true : false; - config->sRGB = false; - config->doubleBuffer = (pfd.dwFlags & PFD_DOUBLEBUFFER) ? true : false; + config->stereo = (pfd.dwFlags & PFD_STEREO) ? PAL_TRUE : PAL_FALSE; + config->sRGB = PAL_FALSE; + config->doubleBuffer = (pfd.dwFlags & PFD_DOUBLEBUFFER) ? PAL_TRUE : PAL_FALSE; } configCount++; } @@ -884,7 +868,7 @@ PalResult PAL_CALL palCreateGLContext( // set no error if (info->noError) { attribs[index++] = WGL_CONTEXT_OPENGL_NO_ERROR_ARB; - attribs[index++] = true; + attribs[index++] = PAL_TRUE; } // release diff --git a/src/system/linux/pal_platform_linux.c b/src/system/linux/pal_platform_linux.c index 80d786a0..070ff79e 100644 --- a/src/system/linux/pal_platform_linux.c +++ b/src/system/linux/pal_platform_linux.c @@ -38,7 +38,10 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) FILE* file = fopen("/etc/os-release", "r"); if (!file) { - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } char line[256]; diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c index 9e9a2b85..06028ff9 100644 --- a/src/video/pal_video_linux.c +++ b/src/video/pal_video_linux.c @@ -1,24 +1,8 @@ /** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. */ // ================================================== @@ -26,7 +10,6 @@ freely, subject to the following restrictions: // ================================================== #ifdef __linux__ - #define _GNU_SOURCE #define _POSIX_C_SOURCE 200112L #include "pal/pal_video.h" @@ -1656,7 +1639,7 @@ static void pointerHandleAxis( s_Mouse.accumScrollY += delta; } - s_Mouse.pendingScroll = true; + s_Mouse.pendingScroll = PAL_TRUE; } static void pointerHandleAxisDiscrete( @@ -1674,7 +1657,7 @@ static void pointerHandleAxisDiscrete( s_Mouse.accumScrollY += discrete; } - s_Mouse.pendingScroll = true; + s_Mouse.pendingScroll = PAL_TRUE; } static void pointerHandleFrame( @@ -1715,7 +1698,7 @@ static void pointerHandleFrame( s_Mouse.WheelY = dy; s_Mouse.accumScrollX -= dx; s_Mouse.accumScrollY -= dy; - s_Mouse.pendingScroll = false; + s_Mouse.pendingScroll = PAL_FALSE; } static void pointerHandleAxisSource( @@ -2132,7 +2115,7 @@ static void xdgSurfaceHandleConfigure( } else { // create a new buffer with the new size struct wl_buffer* buffer = nullptr; - buffer = createShmBuffer(winData->w, winData->h, nullptr, false); + buffer = createShmBuffer(winData->w, winData->h, nullptr, PAL_FALSE); if (!buffer) { return; } @@ -2163,7 +2146,7 @@ static void xdgSurfaceHandleConfigure( } } - winData->pushConfigureEvent = false; + winData->pushConfigureEvent = PAL_FALSE; } } @@ -2189,7 +2172,7 @@ static void xdgSurfaceHandleConfigure( } } - winData->pushStateEvent = false; + winData->pushStateEvent = PAL_FALSE; } } @@ -2202,25 +2185,25 @@ static void xdgToplevelHandleConfigure( { WindowData* winData = (WindowData*)data; uint32_t* state; - PalBool activated = false; + PalBool activated = PAL_FALSE; wl_array_for_each(state, states) { // we need only maximized if (*state == 1) { // XDG_TOPLEVEL_STATE_MAXIMIZED if (winData->state != PAL_WINDOW_STATE_MAXIMIZED) { winData->state = PAL_WINDOW_STATE_MAXIMIZED; - winData->pushStateEvent = true; + winData->pushStateEvent = PAL_TRUE; } } else if (*state == 4) { // XDG_TOPLEVEL_STATE_ACTIVATED - activated = true; + activated = PAL_TRUE; } } if (width > 0 && height > 0) { if (width != winData->w || height != winData->h) { // size change - winData->pushConfigureEvent = true; + winData->pushConfigureEvent = PAL_TRUE; } winData->w = width; @@ -2229,11 +2212,11 @@ static void xdgToplevelHandleConfigure( if (activated && !winData->focused) { // focus gained - winData->focused = true; + winData->focused = PAL_TRUE; } else if (!activated && winData->focused) { // focus lost - winData->focused = false; + winData->focused = PAL_FALSE; } else { // discard double focus gained and double focus lost @@ -2744,7 +2727,7 @@ static WindowData* getFreeWindowData() { for (int i = 0; i < s_Video.maxWindowData; ++i) { if (!s_Video.windowData[i].used) { - s_Video.windowData[i].used = true; + s_Video.windowData[i].used = PAL_TRUE; return &s_Video.windowData[i]; } } @@ -2763,7 +2746,7 @@ static WindowData* getFreeWindowData() s_Video.windowData = data; s_Video.maxWindowData = count; - s_Video.windowData[freeIndex].used = true; + s_Video.windowData[freeIndex].used = PAL_TRUE; return &s_Video.windowData[freeIndex]; } return nullptr; @@ -2788,7 +2771,7 @@ static MonitorData* getFreeMonitorData() { for (int i = 0; i < s_Video.maxMonitorData; ++i) { if (!s_Video.monitorData[i].used) { - s_Video.monitorData[i].used = true; + s_Video.monitorData[i].used = PAL_TRUE; return &s_Video.monitorData[i]; } } @@ -2806,7 +2789,7 @@ static MonitorData* getFreeMonitorData() s_Video.monitorData = data; s_Video.maxWindowData = count; - s_Video.monitorData[freeIndex].used = true; + s_Video.monitorData[freeIndex].used = PAL_TRUE; return &s_Video.monitorData[freeIndex]; } return nullptr; @@ -2826,7 +2809,7 @@ static void freeMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Video.maxMonitorData; ++i) { if (s_Video.monitorData[i].used && s_Video.monitorData[i].monitor == monitor) { - s_Video.monitorData[i].used = false; + s_Video.monitorData[i].used = PAL_FALSE; } } } @@ -3126,7 +3109,7 @@ static void xCheckFeatures() } if (supportedAtoms[i] == s_X11Atoms._NET_WM_NAME) { - s_X11Atoms.unicodeTitle = true; + s_X11Atoms.unicodeTitle = PAL_TRUE; } if (supportedAtoms[i] == s_X11Atoms._NET_WM_WINDOW_TYPE_UTILITY) { @@ -3164,30 +3147,30 @@ static void xCheckFeatures() // extended features // old features - features64 |= PAL_VIDEO_FEATURE64_MULTI_MONITORS; - features64 |= PAL_VIDEO_FEATURE64_MONITOR_GET_ORIENTATION; - features64 |= PAL_VIDEO_FEATURE64_MONITOR_SET_MODE; - features64 |= PAL_VIDEO_FEATURE64_MONITOR_GET_MODE; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_SIZE; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_SIZE; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_VISIBILITY; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_VISIBILITY; - - features64 |= PAL_VIDEO_FEATURE64_CLIP_CURSOR; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_INPUT_FOCUS; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_INPUT_FOCUS; - features64 |= PAL_VIDEO_FEATURE64_CURSOR_SET_POS; - features64 |= PAL_VIDEO_FEATURE64_CURSOR_GET_POS; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_TITLE; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_TITLE; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_FLASH_TRAY; - - features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_ICON; - features64 |= PAL_VIDEO_FEATURE64_TOPMOST_WINDOW; - features64 |= PAL_VIDEO_FEATURE64_DECORATED_WINDOW; - features64 |= PAL_VIDEO_FEATURE64_MONITOR_GET_PRIMARY; - features64 |= PAL_VIDEO_FEATURE64_FOREIGN_WINDOWS; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR; + features64 |= PAL_VIDEO_FEATURE_MULTI_MONITORS; + features64 |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; + features64 |= PAL_VIDEO_FEATURE_MONITOR_SET_MODE; + features64 |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; + features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; + features64 |= PAL_VIDEO_FEATURE_WINDOW_GET_SIZE; + features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY; + features64 |= PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY; + + features64 |= PAL_VIDEO_FEATURE_CLIP_CURSOR; + features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS; + features64 |= PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS; + features64 |= PAL_VIDEO_FEATURE_CURSOR_SET_POS; + features64 |= PAL_VIDEO_FEATURE_CURSOR_GET_POS; + features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; + features64 |= PAL_VIDEO_FEATURE_WINDOW_GET_TITLE; + features64 |= PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY; + + features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_ICON; + features64 |= PAL_VIDEO_FEATURE_TOPMOST_WINDOW; + features64 |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; + features64 |= PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY; + features64 |= PAL_VIDEO_FEATURE_FOREIGN_WINDOWS; + features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; s_Video.features = features; s_Video.features64 = features64; @@ -3199,7 +3182,7 @@ static int xErrorHandler( XErrorEvent* e) { // this is use for simple success and failure - s_X11.error = true; + s_X11.error = PAL_TRUE; return 0; } @@ -3745,7 +3728,7 @@ static PalResult xInitVideo() int eventBase, errorBase = 0; s_X11.queryRRExtension(s_X11.display, &eventBase, &errorBase); s_X11.rrEventBase = eventBase; - s_X11.skipScreenEvent = true; + s_X11.skipScreenEvent = PAL_TRUE; s_X11.dataID = (XContext)s_X11.uniqueContext(); resetMonitorData(); @@ -3863,7 +3846,7 @@ static void xUpdateVideo() // skip the first configure event if (data->skipConfigure) { - data->skipConfigure = false; + data->skipConfigure = PAL_FALSE; data->w = event.xconfigure.width; data->h = event.xconfigure.height; data->x = event.xconfigure.x; @@ -3896,7 +3879,7 @@ static void xUpdateVideo() // skipConfgure an still send an initial move event if (data->isAttached) { if (data->skipIfAttached) { - data->skipIfAttached = false; + data->skipIfAttached = PAL_FALSE; break; } } @@ -3961,7 +3944,7 @@ static void xUpdateVideo() if (mode != PAL_DISPATCH_NONE) { PalEvent event = {0}; event.type = type; - event.data = true; + event.data = PAL_TRUE; event.data2 = palPackPointer(window); palPushEvent(driver, &event); } @@ -3984,7 +3967,7 @@ static void xUpdateVideo() if (mode != PAL_DISPATCH_NONE) { PalEvent event = {0}; event.type = type; - event.data = false; + event.data = PAL_FALSE; event.data2 = palPackPointer(window); palPushEvent(driver, &event); } @@ -4002,7 +3985,7 @@ static void xUpdateVideo() // skip the first state event if (data->skipState) { - data->skipState = false; + data->skipState = PAL_FALSE; break; } @@ -4026,7 +4009,7 @@ static void xUpdateVideo() case RANDR_SCREEN_CHANGE_EVENT: { // skip the first event if (s_X11.skipScreenEvent) { - s_X11.skipScreenEvent = false; + s_X11.skipScreenEvent = PAL_FALSE; break; } @@ -4354,9 +4337,9 @@ static PalResult xGetMonitorInfo( RROutput primary = s_X11.getOutputPrimary(s_X11.display, s_X11.root); if (monitor == TO_PAL_HANDLE(PalMonitor, primary)) { - info->primary = true; + info->primary = PAL_TRUE; } else { - info->primary = false; + info->primary = PAL_FALSE; } // get monitor pos and size @@ -5001,7 +4984,7 @@ static PalResult xCreateWindow( XEvent event; s_X11.nextEvent(s_X11.display, &event); if (event.type == MapNotify && event.xmap.window == window) { - windowMapped = true; + windowMapped = PAL_TRUE; break; } } @@ -5014,7 +4997,7 @@ static PalResult xCreateWindow( s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ, 1, 0, - true); // _NET_WM_STATE_ADD + PAL_TRUE); // _NET_WM_STATE_ADD } // minimize @@ -5031,7 +5014,7 @@ static PalResult xCreateWindow( XEvent event; s_X11.nextEvent(s_X11.display, &event); if (event.type == MapNotify && event.xmap.window == window) { - windowMapped = true; + windowMapped = PAL_TRUE; break; } } @@ -5043,9 +5026,9 @@ static PalResult xCreateWindow( s_X11.flush(s_X11.display); // attach the window data to the window - data->skipConfigure = true; - data->skipState = true; - data->isAttached = false; // true for attached windows + data->skipConfigure = PAL_TRUE; + data->skipState = PAL_TRUE; + data->isAttached = PAL_FALSE; // PAL_TRUE for attached windows data->dpi = dpi; // the current window monitor data->window = TO_PAL_HANDLE(PalWindow, window); s_X11.saveContext(s_X11.display, window, s_X11.dataID, (XPointer)data); @@ -5088,7 +5071,7 @@ static void xDestroyWindow(PalWindow* window) s_X11.freeColormap(s_X11.display, data->colormap); } - data->used = false; + data->used = PAL_FALSE; } PalResult xMinimizeWindow(PalWindow* window) @@ -5126,7 +5109,7 @@ PalResult xMaximizeWindow(PalWindow* window) s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ, 1, 0, - true); // _NET_WM_STATE_ADD + PAL_TRUE); // _NET_WM_STATE_ADD return PAL_RESULT_SUCCESS; } @@ -5152,7 +5135,7 @@ PalResult xRestoreWindow(PalWindow* window) s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ, 1, 0, - false); // _NET_WM_STATE_REMOVE + PAL_FALSE); // _NET_WM_STATE_REMOVE s_X11.mapRaised(s_X11.display, xWin); @@ -5197,9 +5180,9 @@ PalResult xFlashWindow( return PAL_RESULT_INVALID_WINDOW; } - PalBool add = false; + PalBool add = PAL_FALSE; if (info->flags & PAL_FLASH_TRAY) { - add = true; + add = PAL_TRUE; } // check if modern flashing is supported @@ -5408,7 +5391,7 @@ PalBool xIsWindowVisible(PalWindow* window) Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return false; + return PAL_FALSE; } return attr.map_state == IsViewable; @@ -5572,7 +5555,7 @@ PalResult xSetFocusWindow(PalWindow* window) if (s_X11Atoms._NET_ACTIVE_WINDOW) { xSendWMEvent(xWin, s_X11Atoms._NET_ACTIVE_WINDOW, CurrentTime, 0, 0, 0, - true); // 1 + PAL_TRUE); // 1 } else { s_X11.setInputFocus(s_X11.display, xWin, RevertToParent, CurrentTime); @@ -5853,14 +5836,14 @@ PalResult xAttachWindow( PalWindow* window = TO_PAL_HANDLE(PalWindow, xWin); // we assume the window was just created, since there is // no official way to get the DPI - data->isAttached = true; + data->isAttached = PAL_TRUE; data->dpi = 96; // if this is not the DPI, a dpi event will be triggered // If the window manager has not mapped the window yet, // we dont need the initial Size / Move events - data->skipConfigure = true; - data->skipState = true; - data->skipIfAttached = true; + data->skipConfigure = PAL_TRUE; + data->skipState = PAL_TRUE; + data->skipIfAttached = PAL_TRUE; data->window = window; data->w = attr.width; data->h = attr.height; @@ -5903,13 +5886,13 @@ PalResult xDetachWindow( return PAL_RESULT_INVALID_WINDOW; } - if (data->isAttached == false) { + if (data->isAttached == PAL_FALSE) { // window was created by PAL return PAL_RESULT_INVALID_WINDOW; } // detach the window - data->used = false; + data->used = PAL_FALSE; long mask = 0; s_X11.selectInput(s_X11.display, xWin, mask); s_X11.setWMProtocols(s_X11.display, xWin, nullptr, 0); @@ -6260,20 +6243,20 @@ static void globalHandle( features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; - features64 |= PAL_VIDEO_FEATURE64_HIGH_DPI; - features64 |= PAL_VIDEO_FEATURE64_MONITOR_GET_ORIENTATION; - features64 |= PAL_VIDEO_FEATURE64_MULTI_MONITORS; - features64 |= PAL_VIDEO_FEATURE64_MONITOR_GET_MODE; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_TITLE; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_SIZE; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_STATE; - features64 |= PAL_VIDEO_FEATURE64_BORDERLESS_WINDOW; + features64 |= PAL_VIDEO_FEATURE_HIGH_DPI; + features64 |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; + features64 |= PAL_VIDEO_FEATURE_MULTI_MONITORS; + features64 |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; + features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; + features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; + features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; + features64 |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; - features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR; + features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; s_Video.features = features; s_Video.features64 = features64; - s_Wl.checkFeatures = false; + s_Wl.checkFeatures = PAL_FALSE; } if (strcmp(interface, "wl_compositor") == 0) { @@ -6296,7 +6279,7 @@ static void globalHandle( s_Wl.decorationManager = wlRegistryBind(registry, name, &zxdg_decoration_manager_v1_interface, 1); - s_Video.features64 |= PAL_VIDEO_FEATURE64_DECORATED_WINDOW; + s_Video.features64 |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; } else if (strcmp(interface, "wl_output") == 0) { // wayland does not let use query monitors directly @@ -6325,7 +6308,7 @@ static void globalRemove( for (int i = 0; i < s_Video.maxMonitorData; ++i) { if (s_Video.monitorData[i].used && s_Video.monitorData[i].wlName == name) { MonitorData* data = &s_Video.monitorData[i]; - data->used = false; + data->used = PAL_FALSE; s_Wl.proxyDestroy((struct wl_proxy*)data->monitor); s_Wl.monitorCount--; } @@ -6500,7 +6483,7 @@ PalResult wlInitVideo() // clang-format on // initialize wayland - s_Wl.checkFeatures = true; + s_Wl.checkFeatures = PAL_TRUE; s_Wl.monitorCount = 0; setupXdgShellProtocol(); @@ -6687,7 +6670,7 @@ PalResult wlGetMonitorInfo( info->refreshRate = monitorData->refreshRate; info->orientation = monitorData->orientation; - info->primary = false; // no way to query + info->primary = PAL_FALSE; // no way to query strcpy(info->name, monitorData->name); return PAL_RESULT_SUCCESS; @@ -6790,8 +6773,8 @@ PalResult wlCreateWindow( } memset(data, 0, sizeof(WindowData)); - data->used = true; - data->focused = false; + data->used = PAL_TRUE; + data->focused = PAL_FALSE; // create surface surface = wlCompositorCreateSurface(s_Wl.compositor); @@ -6839,8 +6822,8 @@ PalResult wlCreateWindow( data->decoration = decoration; } - data->skipState = true; - data->skipConfigure = true; + data->skipState = PAL_TRUE; + data->skipConfigure = PAL_TRUE; wlSurfaceCommit(surface); s_Wl.displayRoundtrip(s_Wl.display); @@ -6861,7 +6844,7 @@ PalResult wlCreateWindow( data->xdgToplevel = xdgToplevel; data->window = (PalWindow*)surface; data->buffer = nullptr; - data->isAttached = false; + data->isAttached = PAL_FALSE; data->state = PAL_WINDOW_STATE_RESTORED; // minimize @@ -6882,7 +6865,7 @@ PalResult wlCreateWindow( } else { // create a white buffer for the surface struct wl_buffer* buffer = nullptr; - buffer = createShmBuffer(data->w, data->h, nullptr, false); + buffer = createShmBuffer(data->w, data->h, nullptr, PAL_FALSE); if (!buffer) { palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; @@ -6924,8 +6907,8 @@ PalResult wlCreateWindow( // but at the moment a linear search is fine // FIXME: Implement a window hash map - data->skipState = false; - data->skipConfigure = false; + data->skipState = PAL_FALSE; + data->skipConfigure = PAL_FALSE; *outWindow = data->window; return PAL_RESULT_SUCCESS; } @@ -6950,7 +6933,7 @@ void wlDestroyWindow(PalWindow* window) xdgToplevelDestroy(data->xdgToplevel); xdgSurfaceDestroy(data->xdgSurface); wlSurfaceDestroy((struct wl_surface*)window); - data->used = false; + data->used = PAL_FALSE; } PalResult wlMinimizeWindow(PalWindow* window) @@ -7052,7 +7035,7 @@ PalResult wlGetWindowState( PalBool wlIsWindowVisible(PalWindow* window) { - return false; + return PAL_FALSE; } PalWindow* wlGetFocusWindow() @@ -7176,7 +7159,7 @@ PalResult wlCreateCursor( return PAL_RESULT_PLATFORM_FAILURE; } - cursor->buffer = createShmBuffer(info->width, info->height, info->pixels, true); + cursor->buffer = createShmBuffer(info->width, info->height, info->pixels, PAL_TRUE); if (!cursor->buffer) { palSetLastPlatformError(errno); return PAL_RESULT_PLATFORM_FAILURE; @@ -7399,11 +7382,11 @@ PalResult PAL_CALL palInitVideo( } // get backend type - PalBool x11 = true; + PalBool x11 = PAL_TRUE; const char* session = getenv("XDG_SESSION_TYPE"); if (session) { if (strcmp(session, "wayland") == 0) { - x11 = false; + x11 = PAL_FALSE; } } @@ -7464,7 +7447,7 @@ PalResult PAL_CALL palInitVideo( s_Video.allocator = allocator; s_Video.eventDriver = eventDriver; - s_Video.initialized = true; + s_Video.initialized = PAL_TRUE; return PAL_RESULT_SUCCESS; } @@ -7483,7 +7466,7 @@ void PAL_CALL palShutdownVideo() s_Video.display = nullptr; memset(&s_Keyboard, 0, sizeof(Keyboard)); memset(&s_Mouse, 0, sizeof(Mouse)); - s_Video.initialized = false; + s_Video.initialized = PAL_FALSE; } } @@ -7966,20 +7949,15 @@ PalWindow* PAL_CALL palGetFocusWindow() return s_Video.backend->getFocusWindow(); } -PalWindowHandleInfo PAL_CALL palGetWindowHandleInfo(PalWindow* window) +PalResult PAL_CALL palGetWindowHandleInfo( + PalWindow* window, + PalWindowHandleInfo* info) { if (s_Video.initialized) { return s_Video.backend->getWindowHandleInfo(window); } } -PalWindowHandleInfoEx PAL_CALL palGetWindowHandleInfoEx(PalWindow* w) -{ - if (s_Video.initialized) { - return s_Video.backend->getWindowHandleInfoEx(w); - } -} - PalResult PAL_CALL palSetWindowOpacity( PalWindow* window, float opacity) diff --git a/src/video/pal_video_win32.c b/src/video/pal_video_win32.c deleted file mode 100644 index 09a9d0e6..00000000 --- a/src/video/pal_video_win32.c +++ /dev/null @@ -1,3056 +0,0 @@ - -/** - -Copyright (C) 2025-2026 Nicholas Agbo - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - - */ - -// ================================================== -// Includes -// ================================================== - -#ifdef _WIN32 - -#include "pal/pal_video.h" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN - -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -// set unicode -#ifndef UNICODE -#define UNICODE -#endif // UNICODE - -#include -#include - -// ================================================== -// Typedefs, enums and structs -// ================================================== - -#define PAL_VIDEO_CLASS L"PALVideoClass" -#define PAL_VIDEO_PROP L"PalVideoData" -#define WIN32_DPI 0 -#define WIN32_DPI_AWARE 2 -#define MAX_MODE_COUNT 128 -#define NULL_ORIENTATION 5 -#define WINDOW_NAME_SIZE 256 -#define NULL_BUTTON_SERIAL 0xffffffffU - -typedef HRESULT(WINAPI* GetDpiForMonitorFn)( - HMONITOR, - int32_t, - UINT*, - UINT*); - -typedef HRESULT(WINAPI* SetProcessAwarenessFn)(int32_t); - -typedef HBITMAP(WINAPI* CreateDIBSectionFn)( - HDC, - const BITMAPINFO*, - UINT, - VOID**, - HANDLE, - DWORD); - -typedef HBITMAP(WINAPI* CreateBitmapFn)( - int, - int, - UINT, - UINT, - CONST VOID*); - -typedef BOOL(WINAPI* DeleteObjectFn)(HGDIOBJ); - -typedef int(WINAPI* DescribePixelFormatFn)( - HDC, - int, - UINT, - LPPIXELFORMATDESCRIPTOR); - -typedef BOOL(WINAPI* SetPixelFormatFn)( - HDC, - int, - CONST PIXELFORMATDESCRIPTOR*); - -typedef struct { - PalBool used; - PalBool isAttached; - PalWindowState state; - HCURSOR cursor; - LONG_PTR wndProc; -} WindowData; - -typedef struct { - PalBool initialized; - int32_t pixelFormat; - int32_t maxWindowData; - PalVideoFeatures features; - PalVideoFeatures64 features64; - const PalAllocator* allocator; - PalEventDriver* eventDriver; - HINSTANCE shcore; - GetDpiForMonitorFn getDpiForMonitor; - SetProcessAwarenessFn setProcessAwareness; - - HINSTANCE gdi; - CreateDIBSectionFn createDIBSection; - CreateBitmapFn createBitmap; - DeleteObjectFn deleteObject; - DescribePixelFormatFn describePixelFormat; - SetPixelFormatFn setPixelFormat; - - HINSTANCE instance; - HWND hiddenWindow; - HCURSOR defaultCursor; - WindowData* windowData; -} VideoWin32; - -typedef struct { - int32_t count; - int32_t maxCount; - PalMonitor** monitors; -} MonitorData; - -typedef struct { - PalBool pendingResize; - PalBool pendingMove; - PalBool pendingState; - uint32_t width; - uint32_t height; - int32_t x; - int32_t y; - PalWindowState state; - PalWindow* window; -} PendingEvent; - -typedef struct { - int32_t pendingHighSurrogate; - PalBool scancodeState[PAL_SCANCODE_MAX]; - PalBool keycodeState[PAL_KEYCODE_MAX]; - int scancodes[512]; - int keycodes[256]; -} Keyboard; - -typedef struct { - PalBool push; - int32_t dx; - int32_t dy; - int32_t WheelX; - int32_t WheelY; - PalBool state[PAL_MOUSE_BUTTON_MAX]; -} Mouse; - -static PendingEvent s_Event; -static VideoWin32 s_Video = {0}; - -static BYTE s_RawBuffer[4096] = {0}; -static Mouse s_Mouse = {0}; -static Keyboard s_Keyboard = {0}; - -// ================================================== -// Internal API -// ================================================== - -void palSetLastPlatformError(uint32_t e); - -LRESULT CALLBACK videoProc( - HWND hwnd, - UINT msg, - WPARAM wParam, - LPARAM lParam) -{ - // check if the window has been created - WindowData* data = (WindowData*)GetPropW(hwnd, PAL_VIDEO_PROP); - if (!data) { - // window has not been created yet - return DefWindowProcW(hwnd, msg, wParam, lParam); - } - - PalDispatchMode mode = PAL_DISPATCH_NONE; - switch (msg) { - case WM_CLOSE: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_CLOSE); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_CLOSE; - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_SIZE: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_SIZE); - uint32_t width = (uint32_t)LOWORD(lParam); - uint32_t height = (uint32_t)HIWORD(lParam); - - if (mode == PAL_DISPATCH_CALLBACK) { - PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_SIZE; - event.data = palPackUint32(width, height); - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - - } else if (mode == PAL_DISPATCH_POLL) { - s_Event.pendingResize = true; - s_Event.width = width; - s_Event.height = height; - s_Event.window = (PalWindow*)hwnd; - } - - // trigger state event - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_STATE); - PalWindowState state = PAL_WINDOW_STATE_RESTORED; - if (mode == PAL_DISPATCH_NONE) { - return 0; - } - - switch (wParam) { - case SIZE_MINIMIZED: { - state = PAL_WINDOW_STATE_MINIMIZED; - break; - } - - case SIZE_MAXIMIZED: { - state = PAL_WINDOW_STATE_MAXIMIZED; - break; - } - } - - // if state has not changed, we discard the event - if (data->state == state) { - return 0; - } - - if (mode == PAL_DISPATCH_CALLBACK) { - PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_STATE; - event.data = state; - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - - } else if (mode == PAL_DISPATCH_POLL) { - s_Event.pendingState = true; - s_Event.state = state; - } - data->state = state; - } - - return 0; - } - - case WM_MOVE: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_MOVE); - int32_t x = GET_X_LPARAM(lParam); - int32_t y = GET_Y_LPARAM(lParam); - - if (mode == PAL_DISPATCH_CALLBACK) { - PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_MOVE; - event.data = palPackInt32(x, y); - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - - } else { - s_Event.pendingMove = true; - s_Event.x = x; - s_Event.y = y; - s_Event.window = (PalWindow*)hwnd; - } - } - - return 0; - } - - case WM_SHOWWINDOW: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_VISIBILITY; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = (PalBool)wParam; - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_SETFOCUS: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_FOCUS); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_FOCUS; - event.data = true; - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_KILLFOCUS: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_FOCUS); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_FOCUS; - event.data = false; - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_ENTERSIZEMOVE: { - s_Mouse.push = false; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_MODAL_BEGIN; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_EXITSIZEMOVE: { - s_Mouse.push = true; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_MODAL_END; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_DPICHANGED: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MONITOR_DPI_CHANGED; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = HIWORD(wParam); - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_DEVICECHANGE: { - // check if the monitors list has been changed - if (wParam != 0x0007) { - return 0; - } - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MONITOR_LIST_CHANGED; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_MOUSEHWHEEL: { - int32_t delta = GET_WHEEL_DELTA_WPARAM(wParam); - s_Mouse.WheelX = delta / WHEEL_DELTA; - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_WHEEL); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = PAL_EVENT_MOUSE_WHEEL; - event.data = palPackInt32(delta, 0); - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_MOUSEWHEEL: { - int32_t delta = GET_WHEEL_DELTA_WPARAM(wParam); - s_Mouse.WheelY = delta / WHEEL_DELTA; - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_WHEEL); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = PAL_EVENT_MOUSE_WHEEL; - event.data = palPackInt32(0, delta); - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_MOUSEMOVE: { - const int32_t x = GET_X_LPARAM(lParam); - const int32_t y = GET_Y_LPARAM(lParam); - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_MOVE); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = PAL_EVENT_MOUSE_MOVE; - event.data = palPackInt32(x, y); - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_INPUT: { - UINT size = sizeof(s_RawBuffer); - UINT result = GetRawInputData( - (HRAWINPUT)lParam, - RID_INPUT, - s_RawBuffer, - &size, - sizeof(RAWINPUTHEADER)); - - if (result == (UINT)-1) { - break; - } - - RAWINPUT* raw = (RAWINPUT*)s_RawBuffer; - RAWMOUSE* mouse = &raw->data.mouse; - // push only if we are not rresizing or moving with the mouse - if (s_Mouse.push && (mouse->lLastX || mouse->lLastY)) { - s_Mouse.dx += mouse->lLastX; - s_Mouse.dy += mouse->lLastY; - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MOUSE_DELTA; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackInt32(s_Mouse.dx, s_Mouse.dy); - palPushEvent(driver, &event); - } - } - } - break; - } - - case WM_LBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_XBUTTONDOWN: - case WM_LBUTTONUP: - case WM_RBUTTONUP: - case WM_MBUTTONUP: - case WM_XBUTTONUP: { - PalMouseButton button = PAL_MOUSE_BUTTON_UNKNOWN; - PalEventType type; - PalBool pressed = false; - - if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) { - button = PAL_MOUSE_BUTTON_LEFT; - - } else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONUP) { - button = PAL_MOUSE_BUTTON_RIGHT; - - } else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONUP) { - button = PAL_MOUSE_BUTTON_MIDDLE; - - } else if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP) { - // check which x buttton - WORD xButton = HIWORD(wParam); - if (xButton == XBUTTON1) { - button = PAL_MOUSE_BUTTON_X1; - - } else if (xButton == XBUTTON2) { - button = PAL_MOUSE_BUTTON_X2; - } - } - - // clang-format off - // check if we pressed or released the button - if (msg == WM_LBUTTONDOWN || - msg == WM_RBUTTONDOWN || - msg == WM_MBUTTONDOWN || - msg == WM_XBUTTONDOWN) { - pressed = true; - type = PAL_EVENT_MOUSE_BUTTONDOWN; - - } else { - pressed = false; - type = PAL_EVENT_MOUSE_BUTTONUP; - } - // clang-format on - - // set mouse capture - if (msg == WM_LBUTTONDOWN) { - SetCapture(hwnd); - - } else if (msg == WM_LBUTTONUP) { - ReleaseCapture(); - } - - s_Mouse.state[button] = pressed; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(button, NULL_BUTTON_SERIAL); - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - case WM_KEYUP: - case WM_SYSKEYUP: { - PalKeycode keycode = PAL_KEYCODE_UNKNOWN; - PalScancode scancode = PAL_SCANCODE_UNKNOWN; - PalEventType type; - int32_t win32Keycode; - int32_t win32Scancode; - PalBool pressed = false; - PalBool extended = false; - - pressed = (HIWORD(lParam) & KF_UP) ? false : true; - extended = (lParam >> 24) & 1; // we use this for special keys - win32Scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); - win32Keycode = (UINT)wParam; - - // spcecial scancode handling - if (!extended && win32Scancode == 0x045) { - scancode = PAL_SCANCODE_NUMLOCK; - - } else { - uint16_t index = win32Scancode | (extended << 8); - scancode = s_Keyboard.scancodes[index]; - } - - keycode = s_Keyboard.keycodes[win32Keycode]; - if (keycode == PAL_KEYCODE_UNKNOWN) { - // we didnt get any printable key - // we use the scancode - // Since PalKeycode and PalScancode have the same integers - // we can make a direct cast without a table - // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) - keycode = (PalKeycode)(uint32_t)scancode; - } - - if (win32Keycode == VK_SNAPSHOT) { - // printscreen since the platform does not get us a keydown, we - // do that ourselves - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_KEYDOWN); - keycode = PAL_KEYCODE_PRINTSCREEN; - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = PAL_EVENT_KEYDOWN; - event.data = palPackUint32(keycode, scancode); - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - s_Keyboard.keycodeState[keycode] = true; - } - } - - // check before updating state - PalBool repeat = s_Keyboard.keycodeState[keycode]; - if (pressed) { - s_Keyboard.keycodeState[keycode] = true; - s_Keyboard.scancodeState[scancode] = true; - - type = PAL_EVENT_KEYDOWN; - if (repeat) { - type = PAL_EVENT_KEYREPEAT; - } - - } else { - s_Keyboard.keycodeState[keycode] = false; - s_Keyboard.scancodeState[scancode] = false; - type = PAL_EVENT_KEYUP; - } - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(keycode, scancode); - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(driver, &event); - } - } - return 0; - } - - case WM_ERASEBKGND: { - return true; - } - - case WM_SETCURSOR: { - if (LOWORD(lParam) == HTCLIENT) { - if (data && data->cursor) { - SetCursor(data->cursor); - } else { - // no cursor, use default - SetCursor(s_Video.defaultCursor); - } - return TRUE; - } - break; - } - - case WM_CHAR: { - PalEventType type = PAL_EVENT_KEYCHAR; - uint32_t codepoint = 0; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, type); - if (mode == PAL_DISPATCH_NONE) { - break; - } - } - // Most characters comes as two WM_CHAR messags or event - // we store the first one and combine with the second if we got any - uint16_t character = (uint16_t)wParam; - if (character >= 0xD800 && character <= 0xDBFF) { - // high surrogate - s_Keyboard.pendingHighSurrogate = character; - } else if (character >= 0xDC00 && character <= 0xDFFF) { - if (s_Keyboard.pendingHighSurrogate) { - // low surrogate we combine both - uint32_t high = s_Keyboard.pendingHighSurrogate - 0xD800; - uint32_t low = character - 0xDC00; - codepoint = 0x10000 + ((high << 10) | low); - s_Keyboard.pendingHighSurrogate = 0; - } - - } else { - // normal character (A-Z) - codepoint = character; - } - - // push an event - PalEvent event = {0}; - event.type = type; - event.data = codepoint; - event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(s_Video.eventDriver, &event); - } - } - - return DefWindowProcW(hwnd, msg, wParam, lParam); -} - -BOOL CALLBACK enumMonitors( - HMONITOR monitor, - HDC hdc, - LPRECT lRect, - LPARAM lParam) -{ - MonitorData* data = (MonitorData*)lParam; - if (data->monitors) { - if (data->count < data->maxCount) { - data->monitors[data->count] = (PalMonitor*)monitor; - } - } - - data->count++; - return TRUE; -} - -static inline PalOrientation orientationFromWin32(DWORD orientation) -{ - switch (orientation) { - case DMDO_DEFAULT: - return PAL_ORIENTATION_LANDSCAPE; - - case DMDO_90: - return PAL_ORIENTATION_PORTRAIT; - - case DMDO_180: - return PAL_ORIENTATION_LANDSCAPE_FLIPPED; - - case DMDO_270: - return PAL_ORIENTATION_PORTRAIT_FLIPPED; - } - return PAL_ORIENTATION_LANDSCAPE; -} - -static inline DWORD orientationToin32(PalOrientation orientation) -{ - switch (orientation) { - case PAL_ORIENTATION_LANDSCAPE: - return DMDO_DEFAULT; - - case PAL_ORIENTATION_PORTRAIT: - return DMDO_90; - - case PAL_ORIENTATION_LANDSCAPE_FLIPPED: - return DMDO_180; - - case PAL_ORIENTATION_PORTRAIT_FLIPPED: - return DMDO_270; - } - return NULL_ORIENTATION; -} - -static inline PalResult setMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode, - PalBool test) -{ - if (!monitor || !mode) { - return PAL_RESULT_NULL_POINTER; - } - - MONITORINFOEXW mi = {0}; - mi.cbSize = sizeof(MONITORINFOEXW); - if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_MONITOR; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - DWORD flags = DM_PELSWIDTH | DM_PELSHEIGHT; - flags |= DM_DISPLAYFREQUENCY | DM_BITSPERPEL; - - DEVMODE devMode = {0}; - devMode.dmSize = sizeof(DEVMODE); - devMode.dmFields = flags; - - devMode.dmPelsWidth = mode->width; - devMode.dmPelsHeight = mode->height; - devMode.dmDisplayFrequency = mode->refreshRate; - devMode.dmBitsPerPel = mode->bpp; - - DWORD settingsFlag = CDS_FULLSCREEN; - if (test) { - settingsFlag = CDS_TEST; - } - - ULONG result = ChangeDisplaySettingsExW(mi.szDevice, &devMode, NULL, settingsFlag, NULL); - if (result == DISP_CHANGE_SUCCESSFUL) { - return PAL_RESULT_SUCCESS; - } else { - return PAL_RESULT_INVALID_MONITOR_MODE; - } -} - -static inline PalBool compareMonitorMode( - const PalMonitorMode* a, - const PalMonitorMode* b) -{ - - // clang-format off - return a->bpp == b->bpp && - a->width == b->width && - a->height == b->height && - a->refreshRate == b->refreshRate; - // clang-format on -} - -static inline void addMonitorMode( - PalMonitorMode* modes, - const PalMonitorMode* mode, - int32_t* count) -{ - // check if we have a duplicate mode - for (int32_t i = 0; i < *count; i++) { - PalMonitorMode* oldMode = &modes[i]; - if (compareMonitorMode(oldMode, mode)) { - return; // discard it - } - } - - // new mode - modes[*count] = *mode; - *count += 1; -} - -static void createKeycodeTable() -{ - // Tis is for only printable and text input keys - - // Letters - s_Keyboard.keycodes['A'] = PAL_KEYCODE_A; - s_Keyboard.keycodes['B'] = PAL_KEYCODE_B; - s_Keyboard.keycodes['C'] = PAL_KEYCODE_C; - s_Keyboard.keycodes['D'] = PAL_KEYCODE_D; - s_Keyboard.keycodes['E'] = PAL_KEYCODE_E; - s_Keyboard.keycodes['F'] = PAL_KEYCODE_F; - s_Keyboard.keycodes['G'] = PAL_KEYCODE_G; - s_Keyboard.keycodes['H'] = PAL_KEYCODE_H; - s_Keyboard.keycodes['I'] = PAL_KEYCODE_I; - s_Keyboard.keycodes['J'] = PAL_KEYCODE_J; - s_Keyboard.keycodes['K'] = PAL_KEYCODE_K; - s_Keyboard.keycodes['L'] = PAL_KEYCODE_L; - s_Keyboard.keycodes['M'] = PAL_KEYCODE_M; - s_Keyboard.keycodes['N'] = PAL_KEYCODE_N; - s_Keyboard.keycodes['O'] = PAL_KEYCODE_O; - s_Keyboard.keycodes['P'] = PAL_KEYCODE_P; - s_Keyboard.keycodes['Q'] = PAL_KEYCODE_Q; - s_Keyboard.keycodes['R'] = PAL_KEYCODE_R; - s_Keyboard.keycodes['S'] = PAL_KEYCODE_S; - s_Keyboard.keycodes['T'] = PAL_KEYCODE_T; - s_Keyboard.keycodes['U'] = PAL_KEYCODE_U; - s_Keyboard.keycodes['V'] = PAL_KEYCODE_V; - s_Keyboard.keycodes['W'] = PAL_KEYCODE_W; - s_Keyboard.keycodes['X'] = PAL_KEYCODE_X; - s_Keyboard.keycodes['Y'] = PAL_KEYCODE_Y; - s_Keyboard.keycodes['Z'] = PAL_KEYCODE_Z; - - // Control - s_Keyboard.keycodes[VK_SPACE] = PAL_KEYCODE_SPACE; - - // Misc - s_Keyboard.keycodes[VK_OEM_7] = PAL_KEYCODE_APOSTROPHE; - s_Keyboard.keycodes[VK_OEM_5] = PAL_KEYCODE_BACKSLASH; - s_Keyboard.keycodes[VK_OEM_COMMA] = PAL_KEYCODE_COMMA; - s_Keyboard.keycodes[VK_OEM_PLUS] = PAL_KEYCODE_EQUAL; - s_Keyboard.keycodes[VK_OEM_3] = PAL_KEYCODE_GRAVEACCENT; - s_Keyboard.keycodes[VK_OEM_MINUS] = PAL_KEYCODE_SUBTRACT; - s_Keyboard.keycodes[VK_OEM_PERIOD] = PAL_KEYCODE_PERIOD; - s_Keyboard.keycodes[VK_OEM_1] = PAL_KEYCODE_SEMICOLON; - s_Keyboard.keycodes[VK_OEM_2] = PAL_KEYCODE_SLASH; - s_Keyboard.keycodes[VK_OEM_4] = PAL_KEYCODE_LBRACKET; - s_Keyboard.keycodes[VK_OEM_6] = PAL_KEYCODE_RBRACKET; -} - -static void createScancodeTable() -{ - // Scancodes are made from OR'ed (scancode | extended) - // Letters - s_Keyboard.scancodes[0x01E] = PAL_SCANCODE_A; - s_Keyboard.scancodes[0x030] = PAL_SCANCODE_B; - s_Keyboard.scancodes[0x02E] = PAL_SCANCODE_C; - s_Keyboard.scancodes[0x020] = PAL_SCANCODE_D; - s_Keyboard.scancodes[0x012] = PAL_SCANCODE_E; - s_Keyboard.scancodes[0x021] = PAL_SCANCODE_F; - s_Keyboard.scancodes[0x022] = PAL_SCANCODE_G; - s_Keyboard.scancodes[0x023] = PAL_SCANCODE_H; - s_Keyboard.scancodes[0x017] = PAL_SCANCODE_I; - s_Keyboard.scancodes[0x024] = PAL_SCANCODE_J; - s_Keyboard.scancodes[0x025] = PAL_SCANCODE_K; - s_Keyboard.scancodes[0x026] = PAL_SCANCODE_L; - s_Keyboard.scancodes[0x032] = PAL_SCANCODE_M; - s_Keyboard.scancodes[0x031] = PAL_SCANCODE_N; - s_Keyboard.scancodes[0x018] = PAL_SCANCODE_O; - s_Keyboard.scancodes[0x019] = PAL_SCANCODE_P; - s_Keyboard.scancodes[0x010] = PAL_SCANCODE_Q; - s_Keyboard.scancodes[0x013] = PAL_SCANCODE_R; - s_Keyboard.scancodes[0x01F] = PAL_SCANCODE_S; - s_Keyboard.scancodes[0x014] = PAL_SCANCODE_T; - s_Keyboard.scancodes[0x016] = PAL_SCANCODE_U; - s_Keyboard.scancodes[0x02F] = PAL_SCANCODE_V; - s_Keyboard.scancodes[0x011] = PAL_SCANCODE_W; - s_Keyboard.scancodes[0x02D] = PAL_SCANCODE_X; - s_Keyboard.scancodes[0x015] = PAL_SCANCODE_Y; - s_Keyboard.scancodes[0x02C] = PAL_SCANCODE_Z; - - // Numbers (top row) - s_Keyboard.scancodes[0x00B] = PAL_SCANCODE_0; - s_Keyboard.scancodes[0x002] = PAL_SCANCODE_1; - s_Keyboard.scancodes[0x003] = PAL_SCANCODE_2; - s_Keyboard.scancodes[0x004] = PAL_SCANCODE_3; - s_Keyboard.scancodes[0x005] = PAL_SCANCODE_4; - s_Keyboard.scancodes[0x006] = PAL_SCANCODE_5; - s_Keyboard.scancodes[0x007] = PAL_SCANCODE_6; - s_Keyboard.scancodes[0x008] = PAL_SCANCODE_7; - s_Keyboard.scancodes[0x009] = PAL_SCANCODE_8; - s_Keyboard.scancodes[0x00A] = PAL_SCANCODE_9; - - // Function - s_Keyboard.scancodes[0x03B] = PAL_SCANCODE_F1; - s_Keyboard.scancodes[0x03C] = PAL_SCANCODE_F2; - s_Keyboard.scancodes[0x03D] = PAL_SCANCODE_F3; - s_Keyboard.scancodes[0x03E] = PAL_SCANCODE_F4; - s_Keyboard.scancodes[0x03F] = PAL_SCANCODE_F5; - s_Keyboard.scancodes[0x040] = PAL_SCANCODE_F6; - s_Keyboard.scancodes[0x041] = PAL_SCANCODE_F7; - s_Keyboard.scancodes[0x042] = PAL_SCANCODE_F8; - s_Keyboard.scancodes[0x043] = PAL_SCANCODE_F9; - s_Keyboard.scancodes[0x044] = PAL_SCANCODE_F10; - s_Keyboard.scancodes[0x057] = PAL_SCANCODE_F11; - s_Keyboard.scancodes[0x058] = PAL_SCANCODE_F12; - - // Control - s_Keyboard.scancodes[0x001] = PAL_SCANCODE_ESCAPE; - s_Keyboard.scancodes[0x01C] = PAL_SCANCODE_ENTER; - s_Keyboard.scancodes[0x00F] = PAL_SCANCODE_TAB; - s_Keyboard.scancodes[0x00E] = PAL_SCANCODE_BACKSPACE; - s_Keyboard.scancodes[0x039] = PAL_SCANCODE_SPACE; - s_Keyboard.scancodes[0x03A] = PAL_SCANCODE_CAPSLOCK; - s_Keyboard.scancodes[0x145] = PAL_SCANCODE_NUMLOCK; - s_Keyboard.scancodes[0x046] = PAL_SCANCODE_SCROLLLOCK; - s_Keyboard.scancodes[0x02A] = PAL_SCANCODE_LSHIFT; - s_Keyboard.scancodes[0x036] = PAL_SCANCODE_RSHIFT; - s_Keyboard.scancodes[0x01D] = PAL_SCANCODE_LCTRL; - s_Keyboard.scancodes[0x11D] = PAL_SCANCODE_RCTRL; - s_Keyboard.scancodes[0x038] = PAL_SCANCODE_LALT; - s_Keyboard.scancodes[0x138] = PAL_SCANCODE_RALT; - - // Arrows - s_Keyboard.scancodes[0x14B] = PAL_SCANCODE_LEFT; - s_Keyboard.scancodes[0x14D] = PAL_SCANCODE_RIGHT; - s_Keyboard.scancodes[0x148] = PAL_SCANCODE_UP; - s_Keyboard.scancodes[0x150] = PAL_SCANCODE_DOWN; - - // Navigation - s_Keyboard.scancodes[0x152] = PAL_SCANCODE_INSERT; - s_Keyboard.scancodes[0x153] = PAL_SCANCODE_DELETE; - s_Keyboard.scancodes[0x147] = PAL_SCANCODE_HOME; - s_Keyboard.scancodes[0x14F] = PAL_SCANCODE_END; - s_Keyboard.scancodes[0x149] = PAL_SCANCODE_PAGEUP; - s_Keyboard.scancodes[0x151] = PAL_SCANCODE_PAGEDOWN; - - // Keypad - s_Keyboard.scancodes[0x052] = PAL_SCANCODE_KP_0; - s_Keyboard.scancodes[0x04F] = PAL_SCANCODE_KP_1; - s_Keyboard.scancodes[0x050] = PAL_SCANCODE_KP_2; - s_Keyboard.scancodes[0x051] = PAL_SCANCODE_KP_3; - s_Keyboard.scancodes[0x04B] = PAL_SCANCODE_KP_4; - s_Keyboard.scancodes[0x04C] = PAL_SCANCODE_KP_5; - s_Keyboard.scancodes[0x04D] = PAL_SCANCODE_KP_6; - s_Keyboard.scancodes[0x047] = PAL_SCANCODE_KP_7; - s_Keyboard.scancodes[0x048] = PAL_SCANCODE_KP_8; - s_Keyboard.scancodes[0x049] = PAL_SCANCODE_KP_9; - s_Keyboard.scancodes[0x11C] = PAL_SCANCODE_KP_ENTER; - s_Keyboard.scancodes[0x04E] = PAL_SCANCODE_KP_ADD; - s_Keyboard.scancodes[0x04A] = PAL_SCANCODE_KP_SUBTRACT; - s_Keyboard.scancodes[0x037] = PAL_SCANCODE_KP_MULTIPLY; - s_Keyboard.scancodes[0x135] = PAL_SCANCODE_KP_DIVIDE; - s_Keyboard.scancodes[0x053] = PAL_SCANCODE_KP_DECIMAL; - s_Keyboard.scancodes[0x059] = PAL_SCANCODE_KP_EQUAL; - - // Misc - s_Keyboard.scancodes[0x137] = PAL_SCANCODE_PRINTSCREEN; - s_Keyboard.scancodes[0x146] = PAL_SCANCODE_PAUSE; - s_Keyboard.scancodes[0x045] = PAL_SCANCODE_PAUSE; - s_Keyboard.scancodes[0x15D] = PAL_SCANCODE_MENU; - s_Keyboard.scancodes[0x028] = PAL_SCANCODE_APOSTROPHE; - s_Keyboard.scancodes[0x02B] = PAL_SCANCODE_BACKSLASH; - s_Keyboard.scancodes[0x033] = PAL_SCANCODE_COMMA; - s_Keyboard.scancodes[0x00D] = PAL_SCANCODE_EQUAL; - s_Keyboard.scancodes[0x029] = PAL_SCANCODE_GRAVEACCENT; - s_Keyboard.scancodes[0x00C] = PAL_SCANCODE_SUBTRACT; - s_Keyboard.scancodes[0x034] = PAL_SCANCODE_PERIOD; - s_Keyboard.scancodes[0x027] = PAL_SCANCODE_SEMICOLON; - s_Keyboard.scancodes[0x035] = PAL_SCANCODE_SLASH; - s_Keyboard.scancodes[0x01A] = PAL_SCANCODE_LBRACKET; - s_Keyboard.scancodes[0x01B] = PAL_SCANCODE_RBRACKET; - s_Keyboard.scancodes[0x15B] = PAL_SCANCODE_LSUPER; - s_Keyboard.scancodes[0x15C] = PAL_SCANCODE_RSUPER; -} - -static WindowData* getFreeWindowData() -{ - for (int i = 0; i < s_Video.maxWindowData; ++i) { - if (!s_Video.windowData[i].used) { - s_Video.windowData[i].used = true; - return &s_Video.windowData[i]; - } - } - - // resize the data array - // It is rare for a user to create and manage - // 32 windows at the same time - WindowData* data = nullptr; - int count = s_Video.maxWindowData * 2; // double the size - int freeIndex = s_Video.maxWindowData + 1; - data = palAllocate(s_Video.allocator, sizeof(WindowData) * count, 0); - if (data) { - memcpy(data, s_Video.windowData, s_Video.maxWindowData * sizeof(WindowData)); - - palFree(s_Video.allocator, s_Video.windowData); - s_Video.windowData = data; - s_Video.maxWindowData = count; - - s_Video.windowData[freeIndex].used = true; - return &s_Video.windowData[freeIndex]; - } - return nullptr; -} - -// ================================================== -// Public API -// ================================================== - -PalResult PAL_CALL palInitVideo( - const PalAllocator* allocator, - PalEventDriver* eventDriver) -{ - if (s_Video.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - - s_Video.maxWindowData = 32; - s_Video.windowData = - palAllocate(s_Video.allocator, sizeof(WindowData) * s_Video.maxWindowData, 0); - - // get the instance - if (!s_Video.instance) { - s_Video.instance = GetModuleHandleW(nullptr); - } - - // load default cursor - s_Video.defaultCursor = LoadCursorW(NULL, IDC_ARROW); - - // register class - WNDCLASSEXW wc = {0}; - wc.cbSize = sizeof(WNDCLASSEXW); - wc.hCursor = s_Video.defaultCursor; - wc.hIcon = LoadIconW(NULL, IDI_APPLICATION); - wc.hIconSm = LoadIconW(NULL, IDI_APPLICATION); - wc.hInstance = s_Video.instance; - wc.lpfnWndProc = videoProc; - wc.lpszClassName = PAL_VIDEO_CLASS; - wc.style = CS_OWNDC; - - // since we check every input carefully, the only error we can get is access - // denied - if (!RegisterClassExW(&wc)) { - return PAL_RESULT_ACCESS_DENIED; - } - - // create hidden window - s_Video.hiddenWindow = CreateWindowExW( - 0, - PAL_VIDEO_CLASS, - L"HiddenWindow", - WS_OVERLAPPEDWINDOW, - 0, - 0, - 8, - 8, - nullptr, - nullptr, - s_Video.instance, - nullptr); - - if (!s_Video.hiddenWindow) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // set a flag to check if the window has been created - SetPropW(s_Video.hiddenWindow, PAL_VIDEO_PROP, &s_Event); - - // register raw input for mice to get delta - RAWINPUTDEVICE rid = {0}; - rid.dwFlags = RIDEV_INPUTSINK; - rid.hwndTarget = s_Video.hiddenWindow; - rid.usUsage = 0x02; - rid.usUsagePage = 0x01; - if (!RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE))) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // create mapping table - createKeycodeTable(); - createScancodeTable(); - - // load shared libraries - // shcore - s_Video.shcore = LoadLibraryA("shcore.dll"); - if (s_Video.shcore) { - s_Video.getDpiForMonitor = - (GetDpiForMonitorFn)GetProcAddress(s_Video.shcore, "GetDpiForMonitor"); - - s_Video.setProcessAwareness = - (SetProcessAwarenessFn)GetProcAddress(s_Video.shcore, "SetProcessDpiAwareness"); - } - - // clang-format off - // gdi functios - s_Video.gdi = LoadLibraryA("gdi32.dll"); - if (s_Video.gdi) { - s_Video.createDIBSection = (CreateDIBSectionFn)GetProcAddress( - s_Video.gdi, - "CreateDIBSection"); - - s_Video.createBitmap = (CreateBitmapFn)GetProcAddress( - s_Video.gdi, - "CreateBitmap"); - - s_Video.deleteObject = (DeleteObjectFn)GetProcAddress( - s_Video.gdi, - "DeleteObject"); - - s_Video.describePixelFormat = (DescribePixelFormatFn)GetProcAddress( - s_Video.gdi, - "DescribePixelFormat"); - - s_Video.setPixelFormat = (SetPixelFormatFn)GetProcAddress( - s_Video.gdi, - "SetPixelFormat"); - } - // clang-format on - - // set features - s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION; - s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; - s_Video.features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; - s_Video.features |= PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW; - s_Video.features |= PAL_VIDEO_FEATURE_TOOL_WINDOW; - s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_SET_MODE; - s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; - s_Video.features |= PAL_VIDEO_FEATURE_MULTI_MONITORS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_SIZE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_POS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_POS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_STATE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_TITLE; - s_Video.features |= PAL_VIDEO_FEATURE_NO_MAXIMIZEBOX; - s_Video.features |= PAL_VIDEO_FEATURE_NO_MINIMIZEBOX; - s_Video.features |= PAL_VIDEO_FEATURE_CLIP_CURSOR; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_INTERVAL; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_STYLE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_STYLE; - s_Video.features |= PAL_VIDEO_FEATURE_CURSOR_SET_POS; - s_Video.features |= PAL_VIDEO_FEATURE_CURSOR_GET_POS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_ICON; - - if (s_Video.getDpiForMonitor && s_Video.setProcessAwareness) { - s_Video.features |= PAL_VIDEO_FEATURE_HIGH_DPI; - s_Video.features64 |= PAL_VIDEO_FEATURE64_HIGH_DPI; - s_Video.setProcessAwareness(WIN32_DPI_AWARE); - } - - // extended features - s_Video.features64 |= PAL_VIDEO_FEATURE64_MONITOR_SET_ORIENTATION; - s_Video.features64 |= PAL_VIDEO_FEATURE64_MONITOR_GET_ORIENTATION; - s_Video.features64 |= PAL_VIDEO_FEATURE64_BORDERLESS_WINDOW; - s_Video.features64 |= PAL_VIDEO_FEATURE64_TRANSPARENT_WINDOW; - s_Video.features64 |= PAL_VIDEO_FEATURE64_TOOL_WINDOW; - s_Video.features64 |= PAL_VIDEO_FEATURE64_MONITOR_SET_MODE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_MONITOR_GET_MODE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_MULTI_MONITORS; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_SIZE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_SIZE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_POS; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_POS; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_STATE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_STATE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_VISIBILITY; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_VISIBILITY; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_TITLE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_TITLE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_NO_MAXIMIZEBOX; - s_Video.features64 |= PAL_VIDEO_FEATURE64_NO_MINIMIZEBOX; - s_Video.features64 |= PAL_VIDEO_FEATURE64_CLIP_CURSOR; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_FLASH_CAPTION; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_FLASH_TRAY; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_FLASH_INTERVAL; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_INPUT_FOCUS; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_INPUT_FOCUS; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_STYLE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_STYLE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_CURSOR_SET_POS; - s_Video.features64 |= PAL_VIDEO_FEATURE64_CURSOR_GET_POS; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_ICON; - - s_Video.features64 |= PAL_VIDEO_FEATURE64_TOPMOST_WINDOW; - s_Video.features64 |= PAL_VIDEO_FEATURE64_DECORATED_WINDOW; - s_Video.features64 |= PAL_VIDEO_FEATURE64_CURSOR_SET_VISIBILITY; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_GET_MONITOR; - s_Video.features64 |= PAL_VIDEO_FEATURE64_MONITOR_GET_PRIMARY; - s_Video.features64 |= PAL_VIDEO_FEATURE64_FOREIGN_WINDOWS; - s_Video.features64 |= PAL_VIDEO_FEATURE64_MONITOR_VALIDATE_MODE; - s_Video.features64 |= PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR; - - s_Video.initialized = true; - s_Video.allocator = allocator; - s_Video.eventDriver = eventDriver; - s_Video.pixelFormat = 0; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palShutdownVideo() -{ - if (!s_Video.initialized) { - return; - } - - if (s_Video.shcore) { - FreeLibrary(s_Video.shcore); - } - - FreeLibrary(s_Video.gdi); - DestroyWindow(s_Video.hiddenWindow); - UnregisterClassW(PAL_VIDEO_CLASS, s_Video.instance); - palFree(s_Video.allocator, s_Video.windowData); - - memset(&s_Video, 0, sizeof(VideoWin32)); - memset(&s_Keyboard, 0, sizeof(Keyboard)); - memset(&s_Mouse, 0, sizeof(Mouse)); - - s_Video.windowData = nullptr; - s_Video.initialized = false; -} - -void PAL_CALL palUpdateVideo() -{ - if (!s_Video.initialized) { - return; - } - - s_Mouse.dx = 0; - s_Mouse.dy = 0; - - MSG msg; - while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessageA(&msg); - } - - // push pending move and reszie events - if (s_Event.pendingResize) { - PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_SIZE; - event.data = palPackUint32(s_Event.width, s_Event.height); - event.data2 = palPackPointer(s_Event.window); - palPushEvent(s_Video.eventDriver, &event); - - if (s_Event.pendingState) { - PalEvent event = {0}; - event.data = s_Event.state; - event.data2 = palPackPointer(s_Event.window); - event.type = PAL_EVENT_WINDOW_STATE; - palPushEvent(s_Video.eventDriver, &event); - s_Event.pendingState = false; - } - - s_Event.pendingResize = false; - - } else if (s_Event.pendingMove) { - PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_MOVE; - event.data = palPackInt32(s_Event.x, s_Event.y); - event.data2 = palPackPointer(s_Event.window); - palPushEvent(s_Video.eventDriver, &event); - s_Event.pendingMove = false; - } -} - -PalVideoFeatures PAL_CALL palGetVideoFeatures() -{ - if (!s_Video.initialized) { - return 0; - } - - return s_Video.features; -} - -PalVideoFeatures64 PAL_CALL palGetVideoFeaturesEx() -{ - if (!s_Video.initialized) { - return 0; - } - - return s_Video.features64; -} - -PalResult PAL_CALL palSetFBConfig( - const int index, - PalFBConfigBackend backend) -{ - // Win32 uses only WGL and WGL index starts from 1 - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (backend == PAL_CONFIG_BACKEND_EGL || backend == PAL_CONFIG_BACKEND_GLES || - backend == PAL_CONFIG_BACKEND_GLX) { - return PAL_RESULT_INVALID_FBCONFIG_BACKEND; - } - - if (index >= 1) { - s_Video.pixelFormat = index; - return PAL_RESULT_SUCCESS; - } - return PAL_RESULT_INVALID_GL_FBCONFIG; -} - -// ================================================== -// Monitor -// ================================================== - -PalResult PAL_CALL palEnumerateMonitors( - int32_t* count, - PalMonitor** outMonitors) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!count) { - return PAL_RESULT_NULL_POINTER; - } - - if (*count == 0 && outMonitors) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - MonitorData data; - data.count = 0; - data.monitors = outMonitors; - data.maxCount = outMonitors ? *count : 0; - EnumDisplayMonitors(nullptr, nullptr, enumMonitors, (LPARAM)&data); - - if (!outMonitors) { - *count = data.count; - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!outMonitor) { - return PAL_RESULT_NULL_POINTER; - } - - HMONITOR monitor = nullptr; - monitor = MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); - if (!monitor) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - *outMonitor = (PalMonitor*)monitor; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetMonitorInfo( - PalMonitor* monitor, - PalMonitorInfo* info) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!monitor || !info) { - return PAL_RESULT_NULL_POINTER; - } - - MONITORINFOEXW mi = {0}; - mi.cbSize = sizeof(MONITORINFOEXW); - if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_MONITOR; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - info->x = mi.rcMonitor.left; - info->y = mi.rcMonitor.top; - info->width = mi.rcMonitor.right - mi.rcMonitor.left; - info->height = mi.rcMonitor.bottom - mi.rcWork.top; - - // get name - WideCharToMultiByte(CP_UTF8, 0, mi.szDevice, -1, info->name, 32, NULL, NULL); - - DEVMODE devMode = {0}; - devMode.dmSize = sizeof(DEVMODE); - EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &devMode); - info->refreshRate = devMode.dmDisplayFrequency; - info->orientation = orientationFromWin32(devMode.dmDisplayOrientation); - - // get dpi scale - UINT dpiX, dpiY; - if (s_Video.getDpiForMonitor) { - s_Video.getDpiForMonitor((HMONITOR)monitor, WIN32_DPI, &dpiX, &dpiY); - - } else { - dpiX = 96; - } - info->dpi = dpiX; - - // check for primary monitor - HMONITOR primary = nullptr; - primary = MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); - if (!primary) { - info->primary = false; - } - - if (primary == (HMONITOR)monitor) { - info->primary = true; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palEnumerateMonitorModes( - PalMonitor* monitor, - int32_t* count, - PalMonitorMode* modes) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!monitor || !count) { - return PAL_RESULT_NULL_POINTER; - } - - if (*count == 0 && modes) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - int32_t modeCount = 0; - int32_t maxModes = 0; - PalMonitorMode* monitorModes = nullptr; - - MONITORINFOEXW mi = {0}; - mi.cbSize = sizeof(MONITORINFOEXW); - if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_MONITOR; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - if (!modes) { - // allocate and store tmp monitor modesand check for the interested - // fields. - monitorModes = palAllocate(s_Video.allocator, sizeof(PalMonitorMode) * MAX_MODE_COUNT, 0); - if (!monitorModes) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(monitorModes, 0, sizeof(PalMonitorMode) * MAX_MODE_COUNT); - maxModes = MAX_MODE_COUNT; - - } else { - monitorModes = modes; - maxModes = *count; - } - - DEVMODEW dm = {0}; - dm.dmSize = sizeof(DEVMODE); - for (int32_t i = 0; EnumDisplaySettingsW(mi.szDevice, i, &dm); i++) { - // Pal support up to 128 modes - if (modeCount > maxModes) { - break; - } - - PalMonitorMode* mode = &monitorModes[modeCount]; - mode->refreshRate = dm.dmDisplayFrequency; - mode->width = dm.dmPelsWidth; - mode->height = dm.dmPelsHeight; - mode->bpp = dm.dmBitsPerPel; - addMonitorMode(monitorModes, mode, &modeCount); - } - - if (!modes) { - *count = modeCount; - palFree(s_Video.allocator, monitorModes); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetCurrentMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!monitor || !mode) { - return PAL_RESULT_NULL_POINTER; - } - - MONITORINFOEXW mi = {0}; - mi.cbSize = sizeof(MONITORINFOEXW); - if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_MONITOR; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - DEVMODE devMode = {0}; - devMode.dmSize = sizeof(DEVMODE); - EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &devMode); - mode->width = devMode.dmPelsWidth; - mode->height = devMode.dmPelsHeight; - mode->refreshRate = devMode.dmDisplayFrequency; - mode->bpp = devMode.dmBitsPerPel; - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - return setMonitorMode(monitor, mode, false); -} - -PalResult PAL_CALL palValidateMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - return setMonitorMode(monitor, mode, true); -} - -PalResult PAL_CALL palSetMonitorOrientation( - PalMonitor* monitor, - PalOrientation orientation) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!monitor) { - return PAL_RESULT_NULL_POINTER; - } - - DWORD win32Orientation = orientationToin32(orientation); - if (orientation == NULL_ORIENTATION) { - return PAL_RESULT_INVALID_ORIENTATION; - } - - MONITORINFOEXW mi = {0}; - mi.cbSize = sizeof(MONITORINFOEXW); - if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_MONITOR; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - DEVMODE devMode = {0}; - devMode.dmSize = sizeof(DEVMODE); - EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &devMode); - DWORD monitorOrientation = devMode.dmDisplayOrientation; - - // clang-format off - // only swap size if switching between landscape and portrait - PalBool isMonitorLandscape = (monitorOrientation == DMDO_DEFAULT || - monitorOrientation == DMDO_180); - - PalBool isLandscape = (win32Orientation == DMDO_DEFAULT || - win32Orientation == DMDO_180); - // clang-format on - - if (isMonitorLandscape != isLandscape) { - DWORD tmp = devMode.dmPelsWidth; - devMode.dmPelsWidth = devMode.dmPelsHeight; - devMode.dmPelsHeight = tmp; - } - - devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYORIENTATION; - devMode.dmDisplayOrientation = win32Orientation; - - ULONG result = ChangeDisplaySettingsExW(mi.szDevice, &devMode, NULL, CDS_RESET, NULL); - if (result == DISP_CHANGE_SUCCESSFUL) { - return PAL_RESULT_SUCCESS; - - } else { - return PAL_RESULT_INVALID_ORIENTATION; - } -} - -// ================================================== -// Window -// ================================================== - -PalResult PAL_CALL palCreateWindow( - const PalWindowCreateInfo* info, - PalWindow** outWindow) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!info || !outWindow) { - return PAL_RESULT_NULL_POINTER; - } - - WindowData* data = getFreeWindowData(); - if (!data) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - HWND handle = nullptr; - PalMonitor* monitor = nullptr; - PalMonitorInfo monitorInfo; - - uint32_t style = WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED; - uint32_t exStyle = 0; - - // no minimize box - if (!(info->style & PAL_WINDOW_STYLE_NO_MINIMIZEBOX)) { - style |= WS_MINIMIZEBOX; - } - - // no maximize box - if (!(info->style & PAL_WINDOW_STYLE_NO_MAXIMIZEBOX)) { - style |= WS_MAXIMIZEBOX; - } - - // resizable window - if (info->style & PAL_WINDOW_STYLE_RESIZABLE) { - style |= WS_THICKFRAME; - - } else { - // not resizable. We remove the maximizebox even if user requested - style &= ~WS_MAXIMIZEBOX; - } - - // transparent window - if (info->style & PAL_WINDOW_STYLE_TRANSPARENT) { - exStyle |= WS_EX_LAYERED; - } - - // tool window - if (info->style & PAL_WINDOW_STYLE_TOOL) { - exStyle |= WS_EX_TOOLWINDOW; - } - - // topmost window - if (info->style & PAL_WINDOW_STYLE_TOPMOST) { - exStyle |= WS_EX_TOPMOST; - } - - // get monitor - if (info->monitor) { - monitor = info->monitor; - - } else { - // get primary monitor - monitor = (PalMonitor*)MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); - if (!monitor) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - // get monitor info - PalResult result = palGetMonitorInfo(monitor, &monitorInfo); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - - // compose position. - int32_t x, y = 0; - // the position and size must be scaled with the dpi before this call - if (info->center) { - x = monitorInfo.x + (monitorInfo.width - info->width) / 2; - y = monitorInfo.y + (monitorInfo.height - info->height) / 2; - - } else { - // we set 100 for each axix - x = monitorInfo.x + 100; - y = monitorInfo.y + 100; - } - - // adjust the window size - RECT rect = {0, 0, 0, 0}; - rect.right = info->width; - rect.bottom = info->height; - AdjustWindowRectEx(&rect, style, 0, exStyle); - - wchar_t buffer[WINDOW_NAME_SIZE]; - MultiByteToWideChar(CP_UTF8, 0, info->title, -1, buffer, 256); - - // create the window - handle = CreateWindowExW( - exStyle, - PAL_VIDEO_CLASS, - buffer, - style, - x, - y, - rect.right - rect.left, - rect.bottom - rect.top, - nullptr, - nullptr, - s_Video.instance, - nullptr); - - if (!handle) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // set the pixel format is set - if (s_Video.pixelFormat) { - HDC hdc = GetDC(handle); - // since we have the pixel format already - // we ask the OS (platform) to fill the pfd struct for us from that - // index - PIXELFORMATDESCRIPTOR pfd; - if (!s_Video.describePixelFormat( - hdc, - s_Video.pixelFormat, - sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) { - return PAL_RESULT_INVALID_GL_FBCONFIG; - } - - s_Video.setPixelFormat(hdc, s_Video.pixelFormat, &pfd); - ReleaseDC(handle, hdc); - } - - // show, maximize and minimize - int32_t showFlag = SW_HIDE; - // maximize - if (info->maximized) { - showFlag = SW_MAXIMIZE; - data->state = PAL_WINDOW_STATE_MAXIMIZED; - } - - // minimized - if (info->minimized) { - showFlag = SW_MINIMIZE; - data->state = PAL_WINDOW_STATE_MINIMIZED; - } - - // shown - if (info->show) { - if (showFlag == SW_HIDE) { - // change only if maximize and minimize are not set - showFlag = SW_SHOW; - data->state = PAL_WINDOW_STATE_RESTORED; - } - } - - ShowWindow(handle, showFlag); - UpdateWindow(handle); - - if (info->style & PAL_WINDOW_STYLE_BORDERLESS) { - // revert changes - SetWindowLongPtrW(handle, GWL_STYLE, WS_POPUP); - SetWindowLongPtrW(handle, GWL_EXSTYLE, WS_EX_APPWINDOW); - - // force a frame update - SetWindowPos( - handle, - nullptr, - 0, - 0, - 0, - 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - } - - data->isAttached = false; - data->cursor = nullptr; - data->wndProc = (LONG_PTR)videoProc; - SetPropW(handle, PAL_VIDEO_PROP, data); - *outWindow = (PalWindow*)handle; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyWindow(PalWindow* window) -{ - if (s_Video.initialized && window) { - WindowData* data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); - // destroy only PAL created window - if (data->isAttached) { - return; - } - - DestroyWindow((HWND)window); - data->used = false; - } -} - -PalResult PAL_CALL palMinimizeWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - if (!ShowWindow((HWND)window, SW_MINIMIZE)) { - // technically, this will fail if the window handle is invalid - return PAL_RESULT_INVALID_WINDOW; - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palMaximizeWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - if (!ShowWindow((HWND)window, SW_MAXIMIZE)) { - // technically, this will fail if the window handle is invalid - return PAL_RESULT_INVALID_WINDOW; - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palRestoreWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - if (!ShowWindow((HWND)window, SW_RESTORE)) { - // technically, this will fail if the window handle is invalid - return PAL_RESULT_INVALID_WINDOW; - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palShowWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - if (!ShowWindow((HWND)window, SW_SHOW)) { - // technically, this will fail if the window handle is invalid - return PAL_RESULT_INVALID_WINDOW; - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palHideWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - if (!ShowWindow((HWND)window, SW_HIDE)) { - // technically, this will fail if the window handle is invalid - return PAL_RESULT_INVALID_WINDOW; - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palFlashWindow( - PalWindow* window, - const PalFlashInfo* info) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !info) { - return PAL_RESULT_NULL_POINTER; - } - - DWORD flags = 0; - if (info->flags == PAL_FLASH_STOP) { - flags = FLASHW_STOP; - - } else { - if (info->flags & PAL_FLASH_CAPTION) { - flags |= FLASHW_CAPTION; - } - if (info->flags & PAL_FLASH_TRAY) { - flags |= FLASHW_TRAY; - flags |= FLASHW_TIMERNOFG; - } - } - - FLASHWINFO flashInfo = {0}; - flashInfo.cbSize = sizeof(FLASHWINFO); - flashInfo.dwFlags = flags; - flashInfo.dwTimeout = info->interval; - flashInfo.hwnd = (HWND)window; - flashInfo.uCount = info->count; - - PalBool success = FlashWindowEx(&flashInfo); - if (!success) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_WINDOW; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetWindowStyle( - PalWindow* window, - PalWindowStyle* outStyle) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !outStyle) { - return PAL_RESULT_NULL_POINTER; - } - - PalWindowStyle windowStyle = 0; - DWORD style = (DWORD)GetWindowLongPtrW((HWND)window, GWL_STYLE); - DWORD exStyle = (DWORD)GetWindowLongPtrW((HWND)window, GWL_EXSTYLE); - - if (!style) { - // since there is no window without styles - // we assume if we dont get any, the window handle is invalid - return PAL_RESULT_INVALID_WINDOW; - } - - // check if we can resize - if (style & WS_THICKFRAME) { - windowStyle |= PAL_WINDOW_STYLE_RESIZABLE; - } - - // check if we are transparent - if (exStyle & WS_EX_LAYERED) { - windowStyle |= PAL_WINDOW_STYLE_TRANSPARENT; - } - - // check if we are a topmost window - if (exStyle & WS_EX_TOPMOST) { - windowStyle |= PAL_WINDOW_STYLE_TOPMOST; - } - - // check if we have a minimize box - if (!(style & WS_MINIMIZEBOX)) { - windowStyle |= PAL_WINDOW_STYLE_NO_MINIMIZEBOX; - } - - // check if we have a maximize box - if (!(style & WS_MAXIMIZEBOX)) { - windowStyle |= PAL_WINDOW_STYLE_NO_MAXIMIZEBOX; - } - - // check if its a tool window - if (exStyle & WS_EX_TOOLWINDOW) { - windowStyle |= PAL_WINDOW_STYLE_TOOL; - } - - // we check borderless last since it will overwrite other styles - if (style & WS_POPUP) { - windowStyle |= PAL_WINDOW_STYLE_BORDERLESS; - - // we remove minimize and maximize box if set - windowStyle &= ~PAL_WINDOW_STYLE_NO_MINIMIZEBOX; - windowStyle &= ~PAL_WINDOW_STYLE_NO_MAXIMIZEBOX; - } - - *outStyle = windowStyle; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetWindowMonitor( - PalWindow* window, - PalMonitor** outMonitor) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !outMonitor) { - return PAL_RESULT_NULL_POINTER; - } - - HMONITOR monitor = nullptr; - monitor = MonitorFromWindow((HWND)window, MONITOR_DEFAULTTONEAREST); - if (!monitor) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_WINDOW; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - *outMonitor = (PalMonitor*)monitor; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetWindowTitle( - PalWindow* window, - uint64_t bufferSize, - uint64_t* outSize, - char* outBuffer) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !outBuffer) { - return PAL_RESULT_NULL_POINTER; - } - - wchar_t buffer[WINDOW_NAME_SIZE]; - if (GetWindowTextW((HWND)window, buffer, WINDOW_NAME_SIZE) == 0) { - return PAL_RESULT_INVALID_WINDOW; - } - - int len = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, nullptr, 0, 0, 0); - if (outSize) { - *outSize = len - 1; - } - - // see if user provided a buffer and write to it - if (outBuffer && bufferSize > 0) { - int write = (int)bufferSize - 1; - WideCharToMultiByte(CP_UTF8, 0, buffer, -1, outBuffer, write + 1, 0, 0); - outBuffer[write < len - 1 ? write : len - 1] = '\0'; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetWindowPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - RECT rect; - if (!GetWindowRect((HWND)window, &rect)) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (x) { - *x = rect.left; - } - - if (y) { - *y = rect.top; - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetWindowSize( - PalWindow* window, - uint32_t* width, - uint32_t* height) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - RECT rect; - if (!GetWindowRect((HWND)window, &rect)) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (width) { - *width = rect.right - rect.left; - } - - if (height) { - *height = rect.bottom - rect.top; - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetWindowState( - PalWindow* window, - PalWindowState* outState) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !outState) { - return PAL_RESULT_NULL_POINTER; - } - - WINDOWPLACEMENT wp = {0}; - if (!GetWindowPlacement((HWND)window, &wp)) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (wp.showCmd == SW_MINIMIZE) { - *outState = PAL_WINDOW_STATE_MINIMIZED; - - } else if (wp.showCmd == SW_MAXIMIZE) { - *outState = PAL_WINDOW_STATE_MAXIMIZED; - - } else if (wp.showCmd == SW_RESTORE || wp.showCmd == SW_NORMAL) { - *outState = PAL_WINDOW_STATE_RESTORED; - } - - return PAL_RESULT_SUCCESS; -} - -const PalBool* PAL_CALL palGetKeycodeState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Keyboard.keycodeState; -} - -const PalBool* PAL_CALL palGetScancodeState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Keyboard.scancodeState; -} - -const PalBool* PAL_CALL palGetMouseState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Mouse.state; -} - -void PAL_CALL palGetMouseDelta( - int32_t* dx, - int32_t* dy) -{ - if (!s_Video.initialized) { - return; - } - - if (dx) { - *dx = s_Mouse.dx; - } - - if (dy) { - *dy = s_Mouse.dy; - } -} - -void PAL_CALL palGetMouseWheelDelta( - int32_t* dx, - int32_t* dy) -{ - if (!s_Video.initialized) { - return; - } - - if (dx) { - *dx = s_Mouse.WheelX; - } - - if (dy) { - *dy = s_Mouse.WheelY; - } -} - -void PAL_CALL palGetRawMouseWheelDelta( - float* dx, - float* dy) -{ - if (!s_Video.initialized) { - return; - } - - if (dx) { - *dx = (float)s_Mouse.WheelX; - } - - if (dy) { - *dy = (float)s_Mouse.WheelY; - } -} - -PalBool PAL_CALL palIsWindowVisible(PalWindow* window) -{ - if (!s_Video.initialized) { - return false; - } - - if (!window) { - return false; - } - - return IsWindowVisible((HWND)window); -} - -PalWindow* PAL_CALL palGetFocusWindow() -{ - if (!s_Video.initialized) { - return nullptr; - } - return (PalWindow*)GetFocus(); -} - -PalWindowHandleInfo PAL_CALL palGetWindowHandleInfo(PalWindow* window) -{ - PalWindowHandleInfo handle = {0}; - if (s_Video.initialized && window) { - handle.nativeDisplay = nullptr; - handle.nativeWindow = (void*)window; - } - return handle; -} - -PalWindowHandleInfoEx PAL_CALL palGetWindowHandleInfoEx(PalWindow* window) -{ - PalWindowHandleInfoEx handle = {0}; - if (s_Video.initialized && window) { - handle.nativeDisplay = nullptr; - handle.nativeWindow = (void*)window; - } - return handle; -} - -PalResult PAL_CALL palSetWindowOpacity( - PalWindow* window, - float opacity) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - if (opacity < 0.0f) { - opacity = 0.0f; - } - - if (opacity > 1.0f) { - opacity = 1.0f; - } - - PalBool ret = SetLayeredWindowAttributes((HWND)window, 0, (BYTE)(opacity * 255), LWA_ALPHA); - if (!ret) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_WINDOW; - - } else if (error == ERROR_INVALID_PARAMETER) { - return PAL_RESULT_INVALID_ARGUMENT; - - } else { - // FIXME: check for child windows - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetWindowStyle( - PalWindow* window, - PalWindowStyle style) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - // convert our style to win32 styles and exStyles - // all windows have this styles - DWORD win32Style = WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED; - DWORD exStyle = 0; - - // check for resizing - if (style & PAL_WINDOW_STYLE_RESIZABLE) { - win32Style |= WS_THICKFRAME; - } - - // check for transparent window - if (style & PAL_WINDOW_STYLE_TRANSPARENT) { - exStyle |= WS_EX_LAYERED; - } - - // check for topmost window - if (style & PAL_WINDOW_STYLE_TOPMOST) { - exStyle |= WS_EX_TOPMOST; - } - - // check for no minimize box - if (style & PAL_WINDOW_STYLE_NO_MINIMIZEBOX) { - win32Style &= ~WS_MINIMIZEBOX; - } - - // check for maximize box - if (style & PAL_WINDOW_STYLE_NO_MAXIMIZEBOX) { - win32Style &= ~WS_MAXIMIZEBOX; - } - - // check for tool window - if (style & PAL_WINDOW_STYLE_TOOL) { - exStyle |= WS_EX_TOOLWINDOW; - } - - // check for borderless window - if (style & PAL_WINDOW_STYLE_BORDERLESS) { - // revert the styles - win32Style = WS_POPUP; - exStyle = WS_EX_APPWINDOW; - } - - HWND hwnd = (HWND)window; - SetWindowLongPtrW(hwnd, GWL_STYLE, win32Style); - SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle); - - // force a frame update - PalBool success = SetWindowPos( - hwnd, - nullptr, - 0, - 0, - 0, - 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - - if (success) { - return PAL_RESULT_SUCCESS; - - } else { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_WINDOW; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } -} - -PalResult PAL_CALL palSetWindowTitle( - PalWindow* window, - const char* title) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !title) { - return PAL_RESULT_NULL_POINTER; - } - - wchar_t buffer[WINDOW_NAME_SIZE]; - MultiByteToWideChar(CP_UTF8, 0, title, -1, buffer, 256); - - if (!SetWindowTextW((HWND)window, buffer)) { - return PAL_RESULT_INVALID_WINDOW; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetWindowPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - PalBool success = - SetWindowPos((HWND)window, nullptr, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); - - if (!success) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_WINDOW; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetWindowSize( - PalWindow* window, - uint32_t width, - uint32_t height) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - PalBool success = SetWindowPos( - (HWND)window, - HWND_TOP, - 0, - 0, - width, - height, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); - - if (!success) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_WINDOW; - - } else if (error == ERROR_INVALID_PARAMETER) { - return PAL_RESULT_INVALID_ARGUMENT; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetFocusWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - if (!SetActiveWindow((HWND)window)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_WINDOW; - - } else if (error == ERROR_ACCESS_DENIED) { - return PAL_RESULT_ACCESS_DENIED; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Icon -// ================================================== - -PalResult PAL_CALL palCreateIcon( - const PalIconCreateInfo* info, - PalIcon** outIcon) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!info || !outIcon) { - return PAL_RESULT_NULL_POINTER; - } - - // describe the icon pixels - BITMAPV5HEADER bitInfo = {0}; - bitInfo.bV5Size = sizeof(BITMAPV5HEADER); - bitInfo.bV5Width = info->width; - bitInfo.bV5Height = -(int32_t)info->height; // this is topdown by default - - // default parameters - bitInfo.bV5Planes = 1; - bitInfo.bV5BitCount = 32; // PAL supports 32 bits - bitInfo.bV5Compression = BI_BITFIELDS; - bitInfo.bV5RedMask = 0x00FF0000; - bitInfo.bV5GreenMask = 0x0000FF00; - bitInfo.bV5BlueMask = 0x000000FF; - bitInfo.bV5AlphaMask = 0xFF000000; - - HDC hdc = GetDC(nullptr); - void* dibPixels = nullptr; - - // create dib section - HBITMAP bitmap = nullptr; - bitmap = - s_Video - .createDIBSection(hdc, (BITMAPINFO*)&bitInfo, DIB_RGB_COLORS, &dibPixels, nullptr, 0); - - if (!bitmap) { - ReleaseDC(nullptr, hdc); - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - ReleaseDC(nullptr, hdc); - - // convert RGBA to BGRA - uint8_t* pixels = (uint8_t*)dibPixels; - for (uint32_t i = 0; i < info->width * info->height; i++) { - uint8_t r = info->pixels[i * 4 + 0]; // Red - uint8_t g = info->pixels[i * 4 + 1]; // Green - uint8_t b = info->pixels[i * 4 + 2]; // Blue - uint8_t a = info->pixels[i * 4 + 3]; // Alpha - - // premultiply only if alpha is not 0 - if (a == 0) { - r = g = b = 0; - } else { - r = (uint8_t)((r * a) / 255); - g = (uint8_t)((g * a) / 255); - b = (uint8_t)((b * a) / 255); - } - - pixels[i * 4 + 0] = b; - pixels[i * 4 + 1] = g; - pixels[i * 4 + 2] = r; - pixels[i * 4 + 3] = a; - } - - ICONINFO iconInfo = {0}; - iconInfo.fIcon = TRUE; - iconInfo.hbmMask = bitmap; - iconInfo.hbmColor = bitmap; - - // create the icon with the icon info - HICON icon = CreateIconIndirect(&iconInfo); - if (!icon) { - s_Video.deleteObject(bitmap); - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - s_Video.deleteObject(bitmap); - *outIcon = (PalIcon*)icon; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyIcon(PalIcon* icon) -{ - if (s_Video.initialized && icon) { - DestroyIcon((HICON)icon); - } -} - -PalResult PAL_CALL palSetWindowIcon( - PalWindow* window, - PalIcon* icon) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - if (!IsWindow((HWND)window)) { - return PAL_RESULT_INVALID_WINDOW; - } - - SendMessageW((HWND)window, WM_SETICON, ICON_BIG, (LPARAM)icon); - SendMessageW((HWND)window, WM_SETICON, ICON_SMALL, (LPARAM)icon); - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Cursor -// ================================================== - -PalResult PAL_CALL palCreateCursor( - const PalCursorCreateInfo* info, - PalCursor** outCursor) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!info || !outCursor) { - return PAL_RESULT_NULL_POINTER; - } - - // describe the icon pixels - BITMAPV5HEADER bitInfo = {0}; - bitInfo.bV5Size = sizeof(BITMAPV5HEADER); - bitInfo.bV5Width = info->width; - bitInfo.bV5Height = -(int32_t)info->height; // this is topdown by default - - // default parameters - bitInfo.bV5Planes = 1; - bitInfo.bV5BitCount = 32; // PAL supports 32 bits - bitInfo.bV5Compression = BI_BITFIELDS; - bitInfo.bV5RedMask = 0x00FF0000; - bitInfo.bV5GreenMask = 0x0000FF00; - bitInfo.bV5BlueMask = 0x000000FF; - bitInfo.bV5AlphaMask = 0xFF000000; - - HDC hdc = GetDC(nullptr); - void* dibPixels = nullptr; - - // create dib section - HBITMAP bitmap = nullptr; - bitmap = - s_Video - .createDIBSection(hdc, (BITMAPINFO*)&bitInfo, DIB_RGB_COLORS, &dibPixels, nullptr, 0); - - if (!bitmap) { - ReleaseDC(nullptr, hdc); - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - ReleaseDC(nullptr, hdc); - - // convert RGBA to BGRA - uint8_t* pixels = (uint8_t*)dibPixels; - for (uint32_t i = 0; i < info->width * info->height; i++) { - uint8_t r = info->pixels[i * 4 + 0]; // Red - uint8_t g = info->pixels[i * 4 + 1]; // Green - uint8_t b = info->pixels[i * 4 + 2]; // Blue - uint8_t a = info->pixels[i * 4 + 3]; // Alpha - - // premultiply only if alpha is not 0 - if (a == 0) { - r = g = b = 0; - } else { - r = (uint8_t)((r * a) / 255); - g = (uint8_t)((g * a) / 255); - b = (uint8_t)((b * a) / 255); - } - - pixels[i * 4 + 0] = b; - pixels[i * 4 + 1] = g; - pixels[i * 4 + 2] = r; - pixels[i * 4 + 3] = a; - } - - ICONINFO iconInfo = {0}; - iconInfo.fIcon = false; - iconInfo.hbmColor = bitmap; - iconInfo.hbmMask = bitmap; - iconInfo.xHotspot = info->xHotspot; - iconInfo.xHotspot = info->yHotspot; - - // create the cursor with the iconinfo - HCURSOR cursor = CreateIconIndirect(&iconInfo); - if (!cursor) { - s_Video.deleteObject(bitmap); - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - s_Video.deleteObject(bitmap); - *outCursor = (PalCursor*)cursor; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palCreateCursorFrom( - PalCursorType type, - PalCursor** outCursor) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!outCursor) { - return PAL_RESULT_NULL_POINTER; - } - - HCURSOR cursor = nullptr; - switch (type) { - case PAL_CURSOR_ARROW: { - cursor = LoadCursorW(nullptr, IDC_ARROW); - break; - } - - case PAL_CURSOR_HAND: { - cursor = LoadCursorW(nullptr, IDC_HAND); - break; - } - - case PAL_CURSOR_CROSS: { - cursor = LoadCursorW(nullptr, IDC_CROSS); - break; - } - - case PAL_CURSOR_IBEAM: { - cursor = LoadCursorW(nullptr, IDC_IBEAM); - break; - } - - case PAL_CURSOR_WAIT: { - cursor = LoadCursorW(nullptr, IDC_WAIT); - break; - } - - default: { - return PAL_RESULT_INVALID_ARGUMENT; - } - } - - if (!cursor) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - *outCursor = (PalCursor*)cursor; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyCursor(PalCursor* cursor) -{ - if (s_Video.initialized && cursor) { - DestroyCursor((HCURSOR)cursor); - } -} - -void PAL_CALL palShowCursor(PalBool show) -{ - if (s_Video.initialized) { - ShowCursor(show); - } -} - -PalResult PAL_CALL palClipCursor( - PalWindow* window, - PalBool clip) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - if (clip) { - RECT rect; - if (!GetClientRect((HWND)window, &rect)) { - return PAL_RESULT_INVALID_WINDOW; - } - - POINT tmp = {rect.left, rect.top}; - POINT tmp2 = {rect.right, rect.bottom}; - - ClientToScreen((HWND)window, &tmp); - ClientToScreen((HWND)window, &tmp2); - - RECT clipRect = {tmp.x, tmp.y, tmp2.x, tmp2.y}; - ClipCursor(&clipRect); - - } else { - ClipCursor(nullptr); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palGetCursorPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - POINT pos; - GetCursorPos(&pos); - if (ScreenToClient((HWND)window, &pos)) { - if (x) { - *x = pos.x; - } - - if (y) { - *y = pos.y; - } - - return PAL_RESULT_SUCCESS; - - } else { - return PAL_RESULT_INVALID_WINDOW; - } -} - -PalResult PAL_CALL palSetCursorPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - POINT pos = {x, y}; - if (!ClientToScreen((HWND)window, &pos)) { - return PAL_RESULT_INVALID_WINDOW; - } - - SetCursorPos(pos.x, pos.y); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetWindowCursor( - PalWindow* window, - PalCursor* cursor) -{ - if (window) { - SetLastError(0); - WindowData* data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); - if (!data) { - return PAL_RESULT_INVALID_WINDOW; - } - - data->cursor = (HCURSOR)cursor; - DWORD error = GetLastError(); - if (error == 0) { - return PAL_RESULT_SUCCESS; - - } else if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_WINDOW; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - } else { - return PAL_RESULT_NULL_POINTER; - } -} - -void* PAL_CALL palGetInstance() -{ - if (!s_Video.initialized) { - return nullptr; - } - - return (void*)s_Video.instance; -} - -PalResult PAL_CALL palAttachWindow( - void* windowHandle, - PalWindow** outWindow) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!windowHandle || !outWindow) { - return PAL_RESULT_NULL_POINTER; - } - - WindowData* data = getFreeWindowData(); - if (!data) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - PalWindow* window = (PalWindow*)windowHandle; - data->isAttached = true; - data->wndProc = SetWindowLongPtrW((HWND)windowHandle, GWLP_WNDPROC, (LONG_PTR)videoProc); - - // use default PAL video cursor - // there is no way to get the cursor set on the native window - data->cursor = nullptr; - - // get state - palGetWindowState(window, &data->state); - SetPropW((HWND)window, PAL_VIDEO_PROP, data); - - *outWindow = window; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palDetachWindow( - PalWindow* window, - void** outWindowHandle) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - WindowData* data = nullptr; - data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); - if (!data) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (data->isAttached == false) { - // window is owned by PAL - return PAL_RESULT_INVALID_WINDOW; - } - - data->used = false; - SetWindowLongPtrW((HWND)window, GWLP_WNDPROC, data->wndProc); - if (outWindowHandle) { - *outWindowHandle = (void*)window; - } - - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palSetPreferredInstance(void* instance) -{ - if (!s_Video.initialized && instance) { - s_Video.instance = instance; - } -} - -#endif // _WIN32 \ No newline at end of file diff --git a/src/video/win32/pal_cursor_win32.c b/src/video/win32/pal_cursor_win32.c new file mode 100644 index 00000000..ee21285f --- /dev/null +++ b/src/video/win32/pal_cursor_win32.c @@ -0,0 +1,333 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_video_common_win32.h" +#include "pal_shared.h" + +PalResult PAL_CALL palCreateCursor( + const PalCursorCreateInfo* info, + PalCursor** outCursor) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!info || !outCursor) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // describe the icon pixels + BITMAPV5HEADER bitInfo = {0}; + bitInfo.bV5Size = sizeof(BITMAPV5HEADER); + bitInfo.bV5Width = info->width; + bitInfo.bV5Height = -(int32_t)info->height; // this is topdown by default + + // default parameters + bitInfo.bV5Planes = 1; + bitInfo.bV5BitCount = 32; // PAL supports 32 bits + bitInfo.bV5Compression = BI_BITFIELDS; + bitInfo.bV5RedMask = 0x00FF0000; + bitInfo.bV5GreenMask = 0x0000FF00; + bitInfo.bV5BlueMask = 0x000000FF; + bitInfo.bV5AlphaMask = 0xFF000000; + + HDC hdc = GetDC(nullptr); + void* dibPixels = nullptr; + + // create dib section + HBITMAP bitmap = nullptr; + bitmap = + s_Video + .createDIBSection(hdc, (BITMAPINFO*)&bitInfo, DIB_RGB_COLORS, &dibPixels, nullptr, 0); + + if (!bitmap) { + ReleaseDC(nullptr, hdc); + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + ReleaseDC(nullptr, hdc); + + // convert RGBA to BGRA + uint8_t* pixels = (uint8_t*)dibPixels; + for (uint32_t i = 0; i < info->width * info->height; i++) { + uint8_t r = info->pixels[i * 4 + 0]; // Red + uint8_t g = info->pixels[i * 4 + 1]; // Green + uint8_t b = info->pixels[i * 4 + 2]; // Blue + uint8_t a = info->pixels[i * 4 + 3]; // Alpha + + // premultiply only if alpha is not 0 + if (a == 0) { + r = g = b = 0; + } else { + r = (uint8_t)((r * a) / 255); + g = (uint8_t)((g * a) / 255); + b = (uint8_t)((b * a) / 255); + } + + pixels[i * 4 + 0] = b; + pixels[i * 4 + 1] = g; + pixels[i * 4 + 2] = r; + pixels[i * 4 + 3] = a; + } + + ICONINFO iconInfo = {0}; + iconInfo.fIcon = FALSE; + iconInfo.hbmColor = bitmap; + iconInfo.hbmMask = bitmap; + iconInfo.xHotspot = info->xHotspot; + iconInfo.xHotspot = info->yHotspot; + + // create the cursor with the iconinfo + HCURSOR cursor = CreateIconIndirect(&iconInfo); + if (!cursor) { + s_Video.deleteObject(bitmap); + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + s_Video.deleteObject(bitmap); + *outCursor = (PalCursor*)cursor; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palCreateCursorFrom( + PalCursorType type, + PalCursor** outCursor) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!outCursor) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + HCURSOR cursor = nullptr; + switch (type) { + case PAL_CURSOR_ARROW: { + cursor = LoadCursorW(nullptr, IDC_ARROW); + break; + } + + case PAL_CURSOR_HAND: { + cursor = LoadCursorW(nullptr, IDC_HAND); + break; + } + + case PAL_CURSOR_CROSS: { + cursor = LoadCursorW(nullptr, IDC_CROSS); + break; + } + + case PAL_CURSOR_IBEAM: { + cursor = LoadCursorW(nullptr, IDC_IBEAM); + break; + } + + case PAL_CURSOR_WAIT: { + cursor = LoadCursorW(nullptr, IDC_WAIT); + break; + } + } + + if (!cursor) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + *outCursor = (PalCursor*)cursor; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyCursor(PalCursor* cursor) +{ + if (s_Video.initialized && cursor) { + DestroyCursor((HCURSOR)cursor); + } +} + +void PAL_CALL palShowCursor(PalBool show) +{ + if (s_Video.initialized) { + ShowCursor(show); + } +} + +PalResult PAL_CALL palClipCursor( + PalWindow* window, + PalBool clip) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (clip) { + RECT rect; + if (!GetClientRect((HWND)window, &rect)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + POINT tmp = {rect.left, rect.top}; + POINT tmp2 = {rect.right, rect.bottom}; + + ClientToScreen((HWND)window, &tmp); + ClientToScreen((HWND)window, &tmp2); + + RECT clipRect = {tmp.x, tmp.y, tmp2.x, tmp2.y}; + ClipCursor(&clipRect); + + } else { + ClipCursor(nullptr); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetCursorPos( + PalWindow* window, + int32_t* x, + int32_t* y) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + POINT pos; + GetCursorPos(&pos); + if (ScreenToClient((HWND)window, &pos)) { + if (x) { + *x = pos.x; + } + + if (y) { + *y = pos.y; + } + + return PAL_RESULT_SUCCESS; + + } else { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } +} + +PalResult PAL_CALL palSetCursorPos( + PalWindow* window, + int32_t x, + int32_t y) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + POINT pos = {x, y}; + if (!ClientToScreen((HWND)window, &pos)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + SetCursorPos(pos.x, pos.y); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetWindowCursor( + PalWindow* window, + PalCursor* cursor) +{ + if (window) { + SetLastError(0); + WindowData* data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); + if (!data) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + data->cursor = (HCURSOR)cursor; + DWORD error = GetLastError(); + if (error == 0) { + return PAL_RESULT_SUCCESS; + + } else if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + + } else { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/video/win32/pal_icon_win32.c b/src/video/win32/pal_icon_win32.c new file mode 100644 index 00000000..adca2358 --- /dev/null +++ b/src/video/win32/pal_icon_win32.c @@ -0,0 +1,141 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_video_common_win32.h" +#include "pal_shared.h" + +PalResult PAL_CALL palCreateIcon( + const PalIconCreateInfo* info, + PalIcon** outIcon) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!info || !outIcon) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // describe the icon pixels + BITMAPV5HEADER bitInfo = {0}; + bitInfo.bV5Size = sizeof(BITMAPV5HEADER); + bitInfo.bV5Width = info->width; + bitInfo.bV5Height = -(int32_t)info->height; // this is topdown by default + + // default parameters + bitInfo.bV5Planes = 1; + bitInfo.bV5BitCount = 32; // PAL supports 32 bits + bitInfo.bV5Compression = BI_BITFIELDS; + bitInfo.bV5RedMask = 0x00FF0000; + bitInfo.bV5GreenMask = 0x0000FF00; + bitInfo.bV5BlueMask = 0x000000FF; + bitInfo.bV5AlphaMask = 0xFF000000; + + HDC hdc = GetDC(nullptr); + void* dibPixels = nullptr; + + // create dib section + HBITMAP bitmap = nullptr; + bitmap = s_Video.createDIBSection(hdc, (BITMAPINFO*)&bitInfo, DIB_RGB_COLORS, &dibPixels, nullptr, 0); + + if (!bitmap) { + ReleaseDC(nullptr, hdc); + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + ReleaseDC(nullptr, hdc); + + // convert RGBA to BGRA + uint8_t* pixels = (uint8_t*)dibPixels; + for (uint32_t i = 0; i < info->width * info->height; i++) { + uint8_t r = info->pixels[i * 4 + 0]; // Red + uint8_t g = info->pixels[i * 4 + 1]; // Green + uint8_t b = info->pixels[i * 4 + 2]; // Blue + uint8_t a = info->pixels[i * 4 + 3]; // Alpha + + // premultiply only if alpha is not 0 + if (a == 0) { + r = g = b = 0; + } else { + r = (uint8_t)((r * a) / 255); + g = (uint8_t)((g * a) / 255); + b = (uint8_t)((b * a) / 255); + } + + pixels[i * 4 + 0] = b; + pixels[i * 4 + 1] = g; + pixels[i * 4 + 2] = r; + pixels[i * 4 + 3] = a; + } + + ICONINFO iconInfo = {0}; + iconInfo.fIcon = TRUE; + iconInfo.hbmMask = bitmap; + iconInfo.hbmColor = bitmap; + + // create the icon with the icon info + HICON icon = CreateIconIndirect(&iconInfo); + if (!icon) { + s_Video.deleteObject(bitmap); + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + s_Video.deleteObject(bitmap); + *outIcon = (PalIcon*)icon; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyIcon(PalIcon* icon) +{ + if (s_Video.initialized && icon) { + DestroyIcon((HICON)icon); + } +} + +PalResult PAL_CALL palSetWindowIcon( + PalWindow* window, + PalIcon* icon) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!IsWindow((HWND)window)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + SendMessageW((HWND)window, WM_SETICON, ICON_BIG, (LPARAM)icon); + SendMessageW((HWND)window, WM_SETICON, ICON_SMALL, (LPARAM)icon); + return PAL_RESULT_SUCCESS; +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/video/win32/pal_monitor_win32.c b/src/video/win32/pal_monitor_win32.c new file mode 100644 index 00000000..a5dbe99b --- /dev/null +++ b/src/video/win32/pal_monitor_win32.c @@ -0,0 +1,536 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_video_common_win32.h" +#include "pal_shared.h" + +#define MONITOR_DPI 0 +#define MAX_MODE_COUNT 128 +#define NULL_ORIENTATION 5 + +typedef struct { + int32_t count; + int32_t maxCount; + PalMonitor** monitors; +} MonitorData; + +BOOL CALLBACK enumMonitors( + HMONITOR monitor, + HDC hdc, + LPRECT lRect, + LPARAM lParam) +{ + MonitorData* data = (MonitorData*)lParam; + if (data->monitors) { + if (data->count < data->maxCount) { + data->monitors[data->count] = (PalMonitor*)monitor; + } + } + + data->count++; + return PAL_TRUE; +} + +static inline PalOrientation orientationFromWin32(DWORD orientation) +{ + switch (orientation) { + case DMDO_DEFAULT: + return PAL_ORIENTATION_LANDSCAPE; + + case DMDO_90: + return PAL_ORIENTATION_PORTRAIT; + + case DMDO_180: + return PAL_ORIENTATION_LANDSCAPE_FLIPPED; + + case DMDO_270: + return PAL_ORIENTATION_PORTRAIT_FLIPPED; + } + return PAL_ORIENTATION_LANDSCAPE; +} + +static inline DWORD orientationToin32(PalOrientation orientation) +{ + switch (orientation) { + case PAL_ORIENTATION_LANDSCAPE: + return DMDO_DEFAULT; + + case PAL_ORIENTATION_PORTRAIT: + return DMDO_90; + + case PAL_ORIENTATION_LANDSCAPE_FLIPPED: + return DMDO_180; + + case PAL_ORIENTATION_PORTRAIT_FLIPPED: + return DMDO_270; + } + return NULL_ORIENTATION; +} + +static inline PalResult setMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode, + PalBool test) +{ + if (!monitor || !mode) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + MONITORINFOEXW mi = {0}; + mi.cbSize = sizeof(MONITORINFOEXW); + if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + DWORD flags = DM_PELSWIDTH | DM_PELSHEIGHT; + flags |= DM_DISPLAYFREQUENCY | DM_BITSPERPEL; + + DEVMODE devMode = {0}; + devMode.dmSize = sizeof(DEVMODE); + devMode.dmFields = flags; + + devMode.dmPelsWidth = mode->width; + devMode.dmPelsHeight = mode->height; + devMode.dmDisplayFrequency = mode->refreshRate; + devMode.dmBitsPerPel = mode->bpp; + + DWORD settingsFlag = CDS_FULLSCREEN; + if (test) { + settingsFlag = CDS_TEST; + } + + ULONG result = ChangeDisplaySettingsExW(mi.szDevice, &devMode, NULL, settingsFlag, NULL); + if (result == DISP_CHANGE_SUCCESSFUL) { + return PAL_RESULT_SUCCESS; + + } else { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } +} + +static inline PalBool compareMonitorMode( + const PalMonitorMode* a, + const PalMonitorMode* b) +{ + + // clang-format off + return a->bpp == b->bpp && + a->width == b->width && + a->height == b->height && + a->refreshRate == b->refreshRate; + // clang-format on +} + +static inline void addMonitorMode( + PalMonitorMode* modes, + const PalMonitorMode* mode, + int32_t* count) +{ + // check if we have a duplicate mode + for (int32_t i = 0; i < *count; i++) { + PalMonitorMode* oldMode = &modes[i]; + if (compareMonitorMode(oldMode, mode)) { + return; // discard it + } + } + + // new mode + modes[*count] = *mode; + *count += 1; +} + +PalResult PAL_CALL palEnumerateMonitors( + int32_t* count, + PalMonitor** outMonitors) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!count || *count == 0 && outMonitors) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + MonitorData data; + data.count = 0; + data.monitors = outMonitors; + data.maxCount = outMonitors ? *count : 0; + EnumDisplayMonitors(nullptr, nullptr, enumMonitors, (LPARAM)&data); + + if (!outMonitors) { + *count = data.count; + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!outMonitor) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + HMONITOR monitor = nullptr; + monitor = MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); + if (!monitor) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + *outMonitor = (PalMonitor*)monitor; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetMonitorInfo( + PalMonitor* monitor, + PalMonitorInfo* info) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!monitor || !info) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + MONITORINFOEXW mi = {0}; + mi.cbSize = sizeof(MONITORINFOEXW); + if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + info->x = mi.rcMonitor.left; + info->y = mi.rcMonitor.top; + info->width = mi.rcMonitor.right - mi.rcMonitor.left; + info->height = mi.rcMonitor.bottom - mi.rcWork.top; + + // get name + WideCharToMultiByte(CP_UTF8, 0, mi.szDevice, -1, info->name, 32, NULL, NULL); + + DEVMODE devMode = {0}; + devMode.dmSize = sizeof(DEVMODE); + EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &devMode); + info->refreshRate = devMode.dmDisplayFrequency; + info->orientation = orientationFromWin32(devMode.dmDisplayOrientation); + + // get dpi scale + UINT dpiX, dpiY; + if (s_Video.getDpiForMonitor) { + s_Video.getDpiForMonitor((HMONITOR)monitor, MONITOR_DPI, &dpiX, &dpiY); + + } else { + dpiX = 96; + } + info->dpi = dpiX; + + // check for primary monitor + HMONITOR primary = nullptr; + primary = MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); + if (!primary) { + info->primary = PAL_FALSE; + } + + if (primary == (HMONITOR)monitor) { + info->primary = PAL_TRUE; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palEnumerateMonitorModes( + PalMonitor* monitor, + int32_t* count, + PalMonitorMode* modes) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!monitor || !count || *count == 0 && modes) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + int32_t modeCount = 0; + int32_t maxModes = 0; + PalMonitorMode* monitorModes = nullptr; + + MONITORINFOEXW mi = {0}; + mi.cbSize = sizeof(MONITORINFOEXW); + if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + if (!modes) { + // allocate and store tmp monitor modesand check for the interested + // fields. + monitorModes = palAllocate(s_Video.allocator, sizeof(PalMonitorMode) * MAX_MODE_COUNT, 0); + if (!monitorModes) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + memset(monitorModes, 0, sizeof(PalMonitorMode) * MAX_MODE_COUNT); + maxModes = MAX_MODE_COUNT; + + } else { + monitorModes = modes; + maxModes = *count; + } + + DEVMODEW dm = {0}; + dm.dmSize = sizeof(DEVMODE); + for (int32_t i = 0; EnumDisplaySettingsW(mi.szDevice, i, &dm); i++) { + // Pal support up to 128 modes + if (modeCount > maxModes) { + break; + } + + PalMonitorMode* mode = &monitorModes[modeCount]; + mode->refreshRate = dm.dmDisplayFrequency; + mode->width = dm.dmPelsWidth; + mode->height = dm.dmPelsHeight; + mode->bpp = dm.dmBitsPerPel; + addMonitorMode(monitorModes, mode, &modeCount); + } + + if (!modes) { + *count = modeCount; + palFree(s_Video.allocator, monitorModes); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetCurrentMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!monitor || !mode) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + MONITORINFOEXW mi = {0}; + mi.cbSize = sizeof(MONITORINFOEXW); + if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + DEVMODE devMode = {0}; + devMode.dmSize = sizeof(DEVMODE); + EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &devMode); + mode->width = devMode.dmPelsWidth; + mode->height = devMode.dmPelsHeight; + mode->refreshRate = devMode.dmDisplayFrequency; + mode->bpp = devMode.dmBitsPerPel; + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + return setMonitorMode(monitor, mode, PAL_FALSE); +} + +PalResult PAL_CALL palValidateMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + return setMonitorMode(monitor, mode, PAL_TRUE); +} + +PalResult PAL_CALL palSetMonitorOrientation( + PalMonitor* monitor, + PalOrientation orientation) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!monitor) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + DWORD win32Orientation = orientationToin32(orientation); + if (orientation == NULL_ORIENTATION) { + return palMakeResult( + PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + MONITORINFOEXW mi = {0}; + mi.cbSize = sizeof(MONITORINFOEXW); + if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + DEVMODE devMode = {0}; + devMode.dmSize = sizeof(DEVMODE); + EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &devMode); + DWORD monitorOrientation = devMode.dmDisplayOrientation; + + // clang-format off + // only swap size if switching between landscape and portrait + PalBool isMonitorLandscape = (monitorOrientation == DMDO_DEFAULT || + monitorOrientation == DMDO_180); + + PalBool isLandscape = (win32Orientation == DMDO_DEFAULT || + win32Orientation == DMDO_180); + // clang-format on + + if (isMonitorLandscape != isLandscape) { + DWORD tmp = devMode.dmPelsWidth; + devMode.dmPelsWidth = devMode.dmPelsHeight; + devMode.dmPelsHeight = tmp; + } + + devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYORIENTATION; + devMode.dmDisplayOrientation = win32Orientation; + + ULONG result = ChangeDisplaySettingsExW(mi.szDevice, &devMode, NULL, CDS_RESET, NULL); + if (result == DISP_CHANGE_SUCCESSFUL) { + return PAL_RESULT_SUCCESS; + + } else { + return palMakeResult( + PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/video/win32/pal_video_common_win32.h b/src/video/win32/pal_video_common_win32.h new file mode 100644 index 00000000..962ccc9f --- /dev/null +++ b/src/video/win32/pal_video_common_win32.h @@ -0,0 +1,109 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#ifndef _PAL_VIDEO_COMMON_WIN32_H +#define _PAL_VIDEO_COMMON_WIN32_H + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE + +#include "pal/pal_video.h" +#include + +#define PAL_VIDEO_CLASS L"PALVideoClass" +#define PAL_VIDEO_PROP L"PalVideoData" +#define WINDOW_NAME_SIZE 256 + +LRESULT CALLBACK videoProc( + HWND hwnd, + UINT msg, + WPARAM wParam, + LPARAM lParam); + +typedef HRESULT(WINAPI* GetDpiForMonitorFn)( + HMONITOR, + int32_t, + UINT*, + UINT*); + +typedef HRESULT(WINAPI* SetProcessAwarenessFn)(int32_t); + +typedef HBITMAP(WINAPI* CreateDIBSectionFn)( + HDC, + const BITMAPINFO*, + UINT, + VOID**, + HANDLE, + DWORD); + +typedef HBITMAP(WINAPI* CreateBitmapFn)( + int, + int, + UINT, + UINT, + CONST VOID*); + +typedef BOOL(WINAPI* DeleteObjectFn)(HGDIOBJ); + +typedef int(WINAPI* DescribePixelFormatFn)( + HDC, + int, + UINT, + LPPIXELFORMATDESCRIPTOR); + +typedef BOOL(WINAPI* SetPixelFormatFn)( + HDC, + int, + CONST PIXELFORMATDESCRIPTOR*); + +typedef struct { + PalBool used; + PalBool isAttached; + PalWindowState state; + HCURSOR cursor; + LONG_PTR wndProc; +} WindowData; + +typedef struct { + PalBool initialized; + int32_t pixelFormat; + int32_t maxWindowData; + PalVideoFeatures features; + const PalAllocator* allocator; + PalEventDriver* eventDriver; + HINSTANCE shcore; + GetDpiForMonitorFn getDpiForMonitor; + SetProcessAwarenessFn setProcessAwareness; + + HINSTANCE gdi; + CreateDIBSectionFn createDIBSection; + CreateBitmapFn createBitmap; + DeleteObjectFn deleteObject; + DescribePixelFormatFn describePixelFormat; + SetPixelFormatFn setPixelFormat; + + HINSTANCE instance; + HWND hiddenWindow; + HCURSOR defaultCursor; + WindowData* windowData; +} VideoWin32; + +static VideoWin32 s_Video = {0}; + +#endif // _PAL_VIDEO_COMMON_WIN32_H +#endif // _WIN32 \ No newline at end of file diff --git a/src/video/win32/pal_video_win32.c b/src/video/win32/pal_video_win32.c new file mode 100644 index 00000000..6c635106 --- /dev/null +++ b/src/video/win32/pal_video_win32.c @@ -0,0 +1,1120 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_video_common_win32.h" +#include "pal_shared.h" +#include + +#define PROCESS_DPI_AWARE 2 +#define NULL_BUTTON_SERIAL 0xffffffffU + +typedef struct { + PalBool pendingResize; + PalBool pendingMove; + PalBool pendingState; + uint32_t width; + uint32_t height; + int32_t x; + int32_t y; + PalWindowState state; + PalWindow* window; +} PendingEvent; + +typedef struct { + int32_t pendingHighSurrogate; + PalBool scancodeState[PAL_SCANCODE_MAX]; + PalBool keycodeState[PAL_KEYCODE_MAX]; + int scancodes[512]; + int keycodes[256]; +} Keyboard; + +typedef struct { + PalBool push; + int32_t dx; + int32_t dy; + int32_t WheelX; + int32_t WheelY; + PalBool state[PAL_MOUSE_BUTTON_MAX]; +} Mouse; + +static PendingEvent s_Event; +static BYTE s_RawBuffer[4096] = {0}; +static Mouse s_Mouse = {0}; +static Keyboard s_Keyboard = {0}; + +LRESULT CALLBACK videoProc( + HWND hwnd, + UINT msg, + WPARAM wParam, + LPARAM lParam) +{ + // check if the window has been created + WindowData* data = (WindowData*)GetPropW(hwnd, PAL_VIDEO_PROP); + if (!data) { + // window has not been created yet + return DefWindowProcW(hwnd, msg, wParam, lParam); + } + + PalDispatchMode mode = PAL_DISPATCH_NONE; + switch (msg) { + case WM_CLOSE: { + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_CLOSE); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = PAL_EVENT_WINDOW_CLOSE; + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_SIZE: { + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_SIZE); + uint32_t width = (uint32_t)LOWORD(lParam); + uint32_t height = (uint32_t)HIWORD(lParam); + + if (mode == PAL_DISPATCH_CALLBACK) { + PalEvent event = {0}; + event.type = PAL_EVENT_WINDOW_SIZE; + event.data = palPackUint32(width, height); + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + + } else if (mode == PAL_DISPATCH_POLL) { + s_Event.pendingResize = PAL_TRUE; + s_Event.width = width; + s_Event.height = height; + s_Event.window = (PalWindow*)hwnd; + } + + // trigger state event + mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_STATE); + PalWindowState state = PAL_WINDOW_STATE_RESTORED; + if (mode == PAL_DISPATCH_NONE) { + return 0; + } + + switch (wParam) { + case SIZE_MINIMIZED: { + state = PAL_WINDOW_STATE_MINIMIZED; + break; + } + + case SIZE_MAXIMIZED: { + state = PAL_WINDOW_STATE_MAXIMIZED; + break; + } + } + + // if state has not changed, we discard the event + if (data->state == state) { + return 0; + } + + if (mode == PAL_DISPATCH_CALLBACK) { + PalEvent event = {0}; + event.type = PAL_EVENT_WINDOW_STATE; + event.data = state; + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + + } else if (mode == PAL_DISPATCH_POLL) { + s_Event.pendingState = PAL_TRUE; + s_Event.state = state; + } + data->state = state; + } + + return 0; + } + + case WM_MOVE: { + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_MOVE); + int32_t x = GET_X_LPARAM(lParam); + int32_t y = GET_Y_LPARAM(lParam); + + if (mode == PAL_DISPATCH_CALLBACK) { + PalEvent event = {0}; + event.type = PAL_EVENT_WINDOW_MOVE; + event.data = palPackInt32(x, y); + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + + } else { + s_Event.pendingMove = PAL_TRUE; + s_Event.x = x; + s_Event.y = y; + s_Event.window = (PalWindow*)hwnd; + } + } + + return 0; + } + + case WM_SHOWWINDOW: { + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_WINDOW_VISIBILITY; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = (PalBool)wParam; + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_SETFOCUS: { + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_FOCUS); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = PAL_EVENT_WINDOW_FOCUS; + event.data = PAL_TRUE; + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_KILLFOCUS: { + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_FOCUS); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = PAL_EVENT_WINDOW_FOCUS; + event.data = PAL_FALSE; + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_ENTERSIZEMOVE: { + s_Mouse.push = PAL_FALSE; + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_WINDOW_MODAL_BEGIN; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_EXITSIZEMOVE: { + s_Mouse.push = PAL_TRUE; + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_WINDOW_MODAL_END; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_DPICHANGED: { + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_MONITOR_DPI_CHANGED; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = HIWORD(wParam); + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_DEVICECHANGE: { + // check if the monitors list has been changed + if (wParam != 0x0007) { + return 0; + } + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_MONITOR_LIST_CHANGED; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_MOUSEHWHEEL: { + int32_t delta = GET_WHEEL_DELTA_WPARAM(wParam); + s_Mouse.WheelX = delta / WHEEL_DELTA; + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_WHEEL); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = PAL_EVENT_MOUSE_WHEEL; + event.data = palPackInt32(delta, 0); + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_MOUSEWHEEL: { + int32_t delta = GET_WHEEL_DELTA_WPARAM(wParam); + s_Mouse.WheelY = delta / WHEEL_DELTA; + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_WHEEL); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = PAL_EVENT_MOUSE_WHEEL; + event.data = palPackInt32(0, delta); + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_MOUSEMOVE: { + const int32_t x = GET_X_LPARAM(lParam); + const int32_t y = GET_Y_LPARAM(lParam); + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_MOVE); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = PAL_EVENT_MOUSE_MOVE; + event.data = palPackInt32(x, y); + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_INPUT: { + UINT size = sizeof(s_RawBuffer); + UINT result = GetRawInputData( + (HRAWINPUT)lParam, + RID_INPUT, + s_RawBuffer, + &size, + sizeof(RAWINPUTHEADER)); + + if (result == (UINT)-1) { + break; + } + + RAWINPUT* raw = (RAWINPUT*)s_RawBuffer; + RAWMOUSE* mouse = &raw->data.mouse; + // push only if we are not rresizing or moving with the mouse + if (s_Mouse.push && (mouse->lLastX || mouse->lLastY)) { + s_Mouse.dx += mouse->lLastX; + s_Mouse.dy += mouse->lLastY; + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_MOUSE_DELTA; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackInt32(s_Mouse.dx, s_Mouse.dy); + palPushEvent(driver, &event); + } + } + } + break; + } + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_XBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONUP: + case WM_MBUTTONUP: + case WM_XBUTTONUP: { + PalMouseButton button = PAL_MOUSE_BUTTON_UNKNOWN; + PalEventType type; + PalBool pressed = PAL_FALSE; + + if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) { + button = PAL_MOUSE_BUTTON_LEFT; + + } else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONUP) { + button = PAL_MOUSE_BUTTON_RIGHT; + + } else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONUP) { + button = PAL_MOUSE_BUTTON_MIDDLE; + + } else if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP) { + // check which x buttton + WORD xButton = HIWORD(wParam); + if (xButton == XBUTTON1) { + button = PAL_MOUSE_BUTTON_X1; + + } else if (xButton == XBUTTON2) { + button = PAL_MOUSE_BUTTON_X2; + } + } + + // clang-format off + // check if we pressed or released the button + if (msg == WM_LBUTTONDOWN || + msg == WM_RBUTTONDOWN || + msg == WM_MBUTTONDOWN || + msg == WM_XBUTTONDOWN) { + pressed = PAL_TRUE; + type = PAL_EVENT_MOUSE_BUTTONDOWN; + + } else { + pressed = PAL_FALSE; + type = PAL_EVENT_MOUSE_BUTTONUP; + } + // clang-format on + + // set mouse capture + if (msg == WM_LBUTTONDOWN) { + SetCapture(hwnd); + + } else if (msg == WM_LBUTTONUP) { + ReleaseCapture(); + } + + s_Mouse.state[button] = pressed; + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackUint32(button, NULL_BUTTON_SERIAL); + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: { + PalKeycode keycode = PAL_KEYCODE_UNKNOWN; + PalScancode scancode = PAL_SCANCODE_UNKNOWN; + PalEventType type; + int32_t win32Keycode; + int32_t win32Scancode; + PalBool pressed = PAL_FALSE; + PalBool extended = PAL_FALSE; + + pressed = (HIWORD(lParam) & KF_UP) ? PAL_FALSE : PAL_TRUE; + extended = (lParam >> 24) & 1; // we use this for special keys + win32Scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff)); + win32Keycode = (UINT)wParam; + + // spcecial scancode handling + if (!extended && win32Scancode == 0x045) { + scancode = PAL_SCANCODE_NUMLOCK; + + } else { + uint16_t index = win32Scancode | (extended << 8); + scancode = s_Keyboard.scancodes[index]; + } + + keycode = s_Keyboard.keycodes[win32Keycode]; + if (keycode == PAL_KEYCODE_UNKNOWN) { + // we didnt get any printable key + // we use the scancode + // Since PalKeycode and PalScancode have the same integers + // we can make a direct cast without a table + // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) + keycode = (PalKeycode)(uint32_t)scancode; + } + + if (win32Keycode == VK_SNAPSHOT) { + // printscreen since the platform does not get us a keydown, we + // do that ourselves + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_KEYDOWN); + keycode = PAL_KEYCODE_PRINTSCREEN; + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = PAL_EVENT_KEYDOWN; + event.data = palPackUint32(keycode, scancode); + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + s_Keyboard.keycodeState[keycode] = PAL_TRUE; + } + } + + // check before updating state + PalBool repeat = s_Keyboard.keycodeState[keycode]; + if (pressed) { + s_Keyboard.keycodeState[keycode] = PAL_TRUE; + s_Keyboard.scancodeState[scancode] = PAL_TRUE; + + type = PAL_EVENT_KEYDOWN; + if (repeat) { + type = PAL_EVENT_KEYREPEAT; + } + + } else { + s_Keyboard.keycodeState[keycode] = PAL_FALSE; + s_Keyboard.scancodeState[scancode] = PAL_FALSE; + type = PAL_EVENT_KEYUP; + } + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackUint32(keycode, scancode); + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(driver, &event); + } + } + return 0; + } + + case WM_ERASEBKGND: { + return PAL_TRUE; + } + + case WM_SETCURSOR: { + if (LOWORD(lParam) == HTCLIENT) { + if (data && data->cursor) { + SetCursor(data->cursor); + } else { + // no cursor, use default + SetCursor(s_Video.defaultCursor); + } + return PAL_TRUE; + } + break; + } + + case WM_CHAR: { + PalEventType type = PAL_EVENT_KEYCHAR; + uint32_t codepoint = 0; + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, type); + if (mode == PAL_DISPATCH_NONE) { + break; + } + } + // Most characters comes as two WM_CHAR messags or event + // we store the first one and combine with the second if we got any + uint16_t character = (uint16_t)wParam; + if (character >= 0xD800 && character <= 0xDBFF) { + // high surrogate + s_Keyboard.pendingHighSurrogate = character; + } else if (character >= 0xDC00 && character <= 0xDFFF) { + if (s_Keyboard.pendingHighSurrogate) { + // low surrogate we combine both + uint32_t high = s_Keyboard.pendingHighSurrogate - 0xD800; + uint32_t low = character - 0xDC00; + codepoint = 0x10000 + ((high << 10) | low); + s_Keyboard.pendingHighSurrogate = 0; + } + + } else { + // normal character (A-Z) + codepoint = character; + } + + // push an event + PalEvent event = {0}; + event.type = type; + event.data = codepoint; + event.data2 = palPackPointer((PalWindow*)hwnd); + palPushEvent(s_Video.eventDriver, &event); + } + } + + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +static void createKeycodeTable() +{ + // Tis is for only printable and text input keys + + // Letters + s_Keyboard.keycodes['A'] = PAL_KEYCODE_A; + s_Keyboard.keycodes['B'] = PAL_KEYCODE_B; + s_Keyboard.keycodes['C'] = PAL_KEYCODE_C; + s_Keyboard.keycodes['D'] = PAL_KEYCODE_D; + s_Keyboard.keycodes['E'] = PAL_KEYCODE_E; + s_Keyboard.keycodes['F'] = PAL_KEYCODE_F; + s_Keyboard.keycodes['G'] = PAL_KEYCODE_G; + s_Keyboard.keycodes['H'] = PAL_KEYCODE_H; + s_Keyboard.keycodes['I'] = PAL_KEYCODE_I; + s_Keyboard.keycodes['J'] = PAL_KEYCODE_J; + s_Keyboard.keycodes['K'] = PAL_KEYCODE_K; + s_Keyboard.keycodes['L'] = PAL_KEYCODE_L; + s_Keyboard.keycodes['M'] = PAL_KEYCODE_M; + s_Keyboard.keycodes['N'] = PAL_KEYCODE_N; + s_Keyboard.keycodes['O'] = PAL_KEYCODE_O; + s_Keyboard.keycodes['P'] = PAL_KEYCODE_P; + s_Keyboard.keycodes['Q'] = PAL_KEYCODE_Q; + s_Keyboard.keycodes['R'] = PAL_KEYCODE_R; + s_Keyboard.keycodes['S'] = PAL_KEYCODE_S; + s_Keyboard.keycodes['T'] = PAL_KEYCODE_T; + s_Keyboard.keycodes['U'] = PAL_KEYCODE_U; + s_Keyboard.keycodes['V'] = PAL_KEYCODE_V; + s_Keyboard.keycodes['W'] = PAL_KEYCODE_W; + s_Keyboard.keycodes['X'] = PAL_KEYCODE_X; + s_Keyboard.keycodes['Y'] = PAL_KEYCODE_Y; + s_Keyboard.keycodes['Z'] = PAL_KEYCODE_Z; + + // Control + s_Keyboard.keycodes[VK_SPACE] = PAL_KEYCODE_SPACE; + + // Misc + s_Keyboard.keycodes[VK_OEM_7] = PAL_KEYCODE_APOSTROPHE; + s_Keyboard.keycodes[VK_OEM_5] = PAL_KEYCODE_BACKSLASH; + s_Keyboard.keycodes[VK_OEM_COMMA] = PAL_KEYCODE_COMMA; + s_Keyboard.keycodes[VK_OEM_PLUS] = PAL_KEYCODE_EQUAL; + s_Keyboard.keycodes[VK_OEM_3] = PAL_KEYCODE_GRAVEACCENT; + s_Keyboard.keycodes[VK_OEM_MINUS] = PAL_KEYCODE_SUBTRACT; + s_Keyboard.keycodes[VK_OEM_PERIOD] = PAL_KEYCODE_PERIOD; + s_Keyboard.keycodes[VK_OEM_1] = PAL_KEYCODE_SEMICOLON; + s_Keyboard.keycodes[VK_OEM_2] = PAL_KEYCODE_SLASH; + s_Keyboard.keycodes[VK_OEM_4] = PAL_KEYCODE_LBRACKET; + s_Keyboard.keycodes[VK_OEM_6] = PAL_KEYCODE_RBRACKET; +} + +static void createScancodeTable() +{ + // Scancodes are made from OR'ed (scancode | extended) + // Letters + s_Keyboard.scancodes[0x01E] = PAL_SCANCODE_A; + s_Keyboard.scancodes[0x030] = PAL_SCANCODE_B; + s_Keyboard.scancodes[0x02E] = PAL_SCANCODE_C; + s_Keyboard.scancodes[0x020] = PAL_SCANCODE_D; + s_Keyboard.scancodes[0x012] = PAL_SCANCODE_E; + s_Keyboard.scancodes[0x021] = PAL_SCANCODE_F; + s_Keyboard.scancodes[0x022] = PAL_SCANCODE_G; + s_Keyboard.scancodes[0x023] = PAL_SCANCODE_H; + s_Keyboard.scancodes[0x017] = PAL_SCANCODE_I; + s_Keyboard.scancodes[0x024] = PAL_SCANCODE_J; + s_Keyboard.scancodes[0x025] = PAL_SCANCODE_K; + s_Keyboard.scancodes[0x026] = PAL_SCANCODE_L; + s_Keyboard.scancodes[0x032] = PAL_SCANCODE_M; + s_Keyboard.scancodes[0x031] = PAL_SCANCODE_N; + s_Keyboard.scancodes[0x018] = PAL_SCANCODE_O; + s_Keyboard.scancodes[0x019] = PAL_SCANCODE_P; + s_Keyboard.scancodes[0x010] = PAL_SCANCODE_Q; + s_Keyboard.scancodes[0x013] = PAL_SCANCODE_R; + s_Keyboard.scancodes[0x01F] = PAL_SCANCODE_S; + s_Keyboard.scancodes[0x014] = PAL_SCANCODE_T; + s_Keyboard.scancodes[0x016] = PAL_SCANCODE_U; + s_Keyboard.scancodes[0x02F] = PAL_SCANCODE_V; + s_Keyboard.scancodes[0x011] = PAL_SCANCODE_W; + s_Keyboard.scancodes[0x02D] = PAL_SCANCODE_X; + s_Keyboard.scancodes[0x015] = PAL_SCANCODE_Y; + s_Keyboard.scancodes[0x02C] = PAL_SCANCODE_Z; + + // Numbers (top row) + s_Keyboard.scancodes[0x00B] = PAL_SCANCODE_0; + s_Keyboard.scancodes[0x002] = PAL_SCANCODE_1; + s_Keyboard.scancodes[0x003] = PAL_SCANCODE_2; + s_Keyboard.scancodes[0x004] = PAL_SCANCODE_3; + s_Keyboard.scancodes[0x005] = PAL_SCANCODE_4; + s_Keyboard.scancodes[0x006] = PAL_SCANCODE_5; + s_Keyboard.scancodes[0x007] = PAL_SCANCODE_6; + s_Keyboard.scancodes[0x008] = PAL_SCANCODE_7; + s_Keyboard.scancodes[0x009] = PAL_SCANCODE_8; + s_Keyboard.scancodes[0x00A] = PAL_SCANCODE_9; + + // Function + s_Keyboard.scancodes[0x03B] = PAL_SCANCODE_F1; + s_Keyboard.scancodes[0x03C] = PAL_SCANCODE_F2; + s_Keyboard.scancodes[0x03D] = PAL_SCANCODE_F3; + s_Keyboard.scancodes[0x03E] = PAL_SCANCODE_F4; + s_Keyboard.scancodes[0x03F] = PAL_SCANCODE_F5; + s_Keyboard.scancodes[0x040] = PAL_SCANCODE_F6; + s_Keyboard.scancodes[0x041] = PAL_SCANCODE_F7; + s_Keyboard.scancodes[0x042] = PAL_SCANCODE_F8; + s_Keyboard.scancodes[0x043] = PAL_SCANCODE_F9; + s_Keyboard.scancodes[0x044] = PAL_SCANCODE_F10; + s_Keyboard.scancodes[0x057] = PAL_SCANCODE_F11; + s_Keyboard.scancodes[0x058] = PAL_SCANCODE_F12; + + // Control + s_Keyboard.scancodes[0x001] = PAL_SCANCODE_ESCAPE; + s_Keyboard.scancodes[0x01C] = PAL_SCANCODE_ENTER; + s_Keyboard.scancodes[0x00F] = PAL_SCANCODE_TAB; + s_Keyboard.scancodes[0x00E] = PAL_SCANCODE_BACKSPACE; + s_Keyboard.scancodes[0x039] = PAL_SCANCODE_SPACE; + s_Keyboard.scancodes[0x03A] = PAL_SCANCODE_CAPSLOCK; + s_Keyboard.scancodes[0x145] = PAL_SCANCODE_NUMLOCK; + s_Keyboard.scancodes[0x046] = PAL_SCANCODE_SCROLLLOCK; + s_Keyboard.scancodes[0x02A] = PAL_SCANCODE_LSHIFT; + s_Keyboard.scancodes[0x036] = PAL_SCANCODE_RSHIFT; + s_Keyboard.scancodes[0x01D] = PAL_SCANCODE_LCTRL; + s_Keyboard.scancodes[0x11D] = PAL_SCANCODE_RCTRL; + s_Keyboard.scancodes[0x038] = PAL_SCANCODE_LALT; + s_Keyboard.scancodes[0x138] = PAL_SCANCODE_RALT; + + // Arrows + s_Keyboard.scancodes[0x14B] = PAL_SCANCODE_LEFT; + s_Keyboard.scancodes[0x14D] = PAL_SCANCODE_RIGHT; + s_Keyboard.scancodes[0x148] = PAL_SCANCODE_UP; + s_Keyboard.scancodes[0x150] = PAL_SCANCODE_DOWN; + + // Navigation + s_Keyboard.scancodes[0x152] = PAL_SCANCODE_INSERT; + s_Keyboard.scancodes[0x153] = PAL_SCANCODE_DELETE; + s_Keyboard.scancodes[0x147] = PAL_SCANCODE_HOME; + s_Keyboard.scancodes[0x14F] = PAL_SCANCODE_END; + s_Keyboard.scancodes[0x149] = PAL_SCANCODE_PAGEUP; + s_Keyboard.scancodes[0x151] = PAL_SCANCODE_PAGEDOWN; + + // Keypad + s_Keyboard.scancodes[0x052] = PAL_SCANCODE_KP_0; + s_Keyboard.scancodes[0x04F] = PAL_SCANCODE_KP_1; + s_Keyboard.scancodes[0x050] = PAL_SCANCODE_KP_2; + s_Keyboard.scancodes[0x051] = PAL_SCANCODE_KP_3; + s_Keyboard.scancodes[0x04B] = PAL_SCANCODE_KP_4; + s_Keyboard.scancodes[0x04C] = PAL_SCANCODE_KP_5; + s_Keyboard.scancodes[0x04D] = PAL_SCANCODE_KP_6; + s_Keyboard.scancodes[0x047] = PAL_SCANCODE_KP_7; + s_Keyboard.scancodes[0x048] = PAL_SCANCODE_KP_8; + s_Keyboard.scancodes[0x049] = PAL_SCANCODE_KP_9; + s_Keyboard.scancodes[0x11C] = PAL_SCANCODE_KP_ENTER; + s_Keyboard.scancodes[0x04E] = PAL_SCANCODE_KP_ADD; + s_Keyboard.scancodes[0x04A] = PAL_SCANCODE_KP_SUBTRACT; + s_Keyboard.scancodes[0x037] = PAL_SCANCODE_KP_MULTIPLY; + s_Keyboard.scancodes[0x135] = PAL_SCANCODE_KP_DIVIDE; + s_Keyboard.scancodes[0x053] = PAL_SCANCODE_KP_DECIMAL; + s_Keyboard.scancodes[0x059] = PAL_SCANCODE_KP_EQUAL; + + // Misc + s_Keyboard.scancodes[0x137] = PAL_SCANCODE_PRINTSCREEN; + s_Keyboard.scancodes[0x146] = PAL_SCANCODE_PAUSE; + s_Keyboard.scancodes[0x045] = PAL_SCANCODE_PAUSE; + s_Keyboard.scancodes[0x15D] = PAL_SCANCODE_MENU; + s_Keyboard.scancodes[0x028] = PAL_SCANCODE_APOSTROPHE; + s_Keyboard.scancodes[0x02B] = PAL_SCANCODE_BACKSLASH; + s_Keyboard.scancodes[0x033] = PAL_SCANCODE_COMMA; + s_Keyboard.scancodes[0x00D] = PAL_SCANCODE_EQUAL; + s_Keyboard.scancodes[0x029] = PAL_SCANCODE_GRAVEACCENT; + s_Keyboard.scancodes[0x00C] = PAL_SCANCODE_SUBTRACT; + s_Keyboard.scancodes[0x034] = PAL_SCANCODE_PERIOD; + s_Keyboard.scancodes[0x027] = PAL_SCANCODE_SEMICOLON; + s_Keyboard.scancodes[0x035] = PAL_SCANCODE_SLASH; + s_Keyboard.scancodes[0x01A] = PAL_SCANCODE_LBRACKET; + s_Keyboard.scancodes[0x01B] = PAL_SCANCODE_RBRACKET; + s_Keyboard.scancodes[0x15B] = PAL_SCANCODE_LSUPER; + s_Keyboard.scancodes[0x15C] = PAL_SCANCODE_RSUPER; +} + +PalResult PAL_CALL palInitVideo( + const PalAllocator* allocator, + PalEventDriver* eventDriver) +{ + if (s_Video.initialized) { + return PAL_RESULT_SUCCESS; + } + + if (allocator && (!allocator->allocate || !allocator->free)) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + s_Video.maxWindowData = 32; + s_Video.windowData = + palAllocate(s_Video.allocator, sizeof(WindowData) * s_Video.maxWindowData, 0); + + // get the instance + if (!s_Video.instance) { + s_Video.instance = GetModuleHandleW(nullptr); + } + + // load default cursor + s_Video.defaultCursor = LoadCursorW(NULL, IDC_ARROW); + + // register class + WNDCLASSEXW wc = {0}; + wc.cbSize = sizeof(WNDCLASSEXW); + wc.hCursor = s_Video.defaultCursor; + wc.hIcon = LoadIconW(NULL, IDI_APPLICATION); + wc.hIconSm = LoadIconW(NULL, IDI_APPLICATION); + wc.hInstance = s_Video.instance; + wc.lpfnWndProc = videoProc; + wc.lpszClassName = PAL_VIDEO_CLASS; + wc.style = CS_OWNDC; + + if (!RegisterClassExW(&wc)) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // create hidden window + s_Video.hiddenWindow = CreateWindowExW( + 0, + PAL_VIDEO_CLASS, + L"HiddenWindow", + WS_OVERLAPPEDWINDOW, + 0, + 0, + 8, + 8, + nullptr, + nullptr, + s_Video.instance, + nullptr); + + if (!s_Video.hiddenWindow) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // set a flag to check if the window has been created + SetPropW(s_Video.hiddenWindow, PAL_VIDEO_PROP, &s_Event); + + // register raw input for mice to get delta + RAWINPUTDEVICE rid = {0}; + rid.dwFlags = RIDEV_INPUTSINK; + rid.hwndTarget = s_Video.hiddenWindow; + rid.usUsage = 0x02; + rid.usUsagePage = 0x01; + if (!RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE))) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // create mapping table + createKeycodeTable(); + createScancodeTable(); + + // load shared libraries + // shcore + s_Video.shcore = LoadLibraryA("shcore.dll"); + if (s_Video.shcore) { + s_Video.getDpiForMonitor = + (GetDpiForMonitorFn)GetProcAddress(s_Video.shcore, "GetDpiForMonitor"); + + s_Video.setProcessAwareness = + (SetProcessAwarenessFn)GetProcAddress(s_Video.shcore, "SetProcessDpiAwareness"); + } + + // clang-format off + // gdi functios + s_Video.gdi = LoadLibraryA("gdi32.dll"); + if (s_Video.gdi) { + s_Video.createDIBSection = (CreateDIBSectionFn)GetProcAddress( + s_Video.gdi, + "CreateDIBSection"); + + s_Video.createBitmap = (CreateBitmapFn)GetProcAddress( + s_Video.gdi, + "CreateBitmap"); + + s_Video.deleteObject = (DeleteObjectFn)GetProcAddress( + s_Video.gdi, + "DeleteObject"); + + s_Video.describePixelFormat = (DescribePixelFormatFn)GetProcAddress( + s_Video.gdi, + "DescribePixelFormat"); + + s_Video.setPixelFormat = (SetPixelFormatFn)GetProcAddress( + s_Video.gdi, + "SetPixelFormat"); + } + // clang-format on + + // set features + s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION; + s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; + s_Video.features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; + s_Video.features |= PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW; + s_Video.features |= PAL_VIDEO_FEATURE_TOOL_WINDOW; + s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_SET_MODE; + s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; + s_Video.features |= PAL_VIDEO_FEATURE_MULTI_MONITORS; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_SIZE; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_POS; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_POS; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_STATE; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_TITLE; + s_Video.features |= PAL_VIDEO_FEATURE_NO_MAXIMIZEBOX; + s_Video.features |= PAL_VIDEO_FEATURE_NO_MINIMIZEBOX; + s_Video.features |= PAL_VIDEO_FEATURE_CLIP_CURSOR; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_INTERVAL; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_STYLE; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_STYLE; + s_Video.features |= PAL_VIDEO_FEATURE_CURSOR_SET_POS; + s_Video.features |= PAL_VIDEO_FEATURE_CURSOR_GET_POS; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_ICON; + + s_Video.features |= PAL_VIDEO_FEATURE_TOPMOST_WINDOW; + s_Video.features |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; + s_Video.features |= PAL_VIDEO_FEATURE_CURSOR_SET_VISIBILITY; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_MONITOR; + s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY; + s_Video.features |= PAL_VIDEO_FEATURE_FOREIGN_WINDOWS; + s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_VALIDATE_MODE; + s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; + + if (s_Video.getDpiForMonitor && s_Video.setProcessAwareness) { + s_Video.features |= PAL_VIDEO_FEATURE_HIGH_DPI; + s_Video.setProcessAwareness(PROCESS_DPI_AWARE); + } + + s_Video.initialized = PAL_TRUE; + s_Video.allocator = allocator; + s_Video.eventDriver = eventDriver; + s_Video.pixelFormat = 0; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palShutdownVideo() +{ + if (!s_Video.initialized) { + return; + } + + if (s_Video.shcore) { + FreeLibrary(s_Video.shcore); + } + + FreeLibrary(s_Video.gdi); + DestroyWindow(s_Video.hiddenWindow); + UnregisterClassW(PAL_VIDEO_CLASS, s_Video.instance); + palFree(s_Video.allocator, s_Video.windowData); + + memset(&s_Video, 0, sizeof(VideoWin32)); + memset(&s_Keyboard, 0, sizeof(Keyboard)); + memset(&s_Mouse, 0, sizeof(Mouse)); + + s_Video.windowData = nullptr; + s_Video.initialized = PAL_FALSE; +} + +void PAL_CALL palUpdateVideo() +{ + if (!s_Video.initialized) { + return; + } + + s_Mouse.dx = 0; + s_Mouse.dy = 0; + + MSG msg; + while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + + // push pending move and reszie events + if (s_Event.pendingResize) { + PalEvent event = {0}; + event.type = PAL_EVENT_WINDOW_SIZE; + event.data = palPackUint32(s_Event.width, s_Event.height); + event.data2 = palPackPointer(s_Event.window); + palPushEvent(s_Video.eventDriver, &event); + + if (s_Event.pendingState) { + PalEvent event = {0}; + event.data = s_Event.state; + event.data2 = palPackPointer(s_Event.window); + event.type = PAL_EVENT_WINDOW_STATE; + palPushEvent(s_Video.eventDriver, &event); + s_Event.pendingState = PAL_FALSE; + } + + s_Event.pendingResize = PAL_FALSE; + + } else if (s_Event.pendingMove) { + PalEvent event = {0}; + event.type = PAL_EVENT_WINDOW_MOVE; + event.data = palPackInt32(s_Event.x, s_Event.y); + event.data2 = palPackPointer(s_Event.window); + palPushEvent(s_Video.eventDriver, &event); + s_Event.pendingMove = PAL_FALSE; + } +} + +PalVideoFeatures PAL_CALL palGetVideoFeatures() +{ + if (!s_Video.initialized) { + return 0; + } + + return s_Video.features; +} + +PalResult PAL_CALL palSetFBConfig( + const int index, + PalFBConfigBackend backend) +{ + // Win32 uses only WGL and WGL index starts from 1 + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // clang-format off + if (backend == PAL_CONFIG_BACKEND_EGL || + backend == PAL_CONFIG_BACKEND_GLES || + backend == PAL_CONFIG_BACKEND_GLX) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + // clang-format on + + if (index >= 1) { + s_Video.pixelFormat = index; + return PAL_RESULT_SUCCESS; + } + + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); +} + +const PalBool* PAL_CALL palGetKeycodeState() +{ + if (!s_Video.initialized) { + return nullptr; + } + return s_Keyboard.keycodeState; +} + +const PalBool* PAL_CALL palGetScancodeState() +{ + if (!s_Video.initialized) { + return nullptr; + } + return s_Keyboard.scancodeState; +} + +const PalBool* PAL_CALL palGetMouseState() +{ + if (!s_Video.initialized) { + return nullptr; + } + return s_Mouse.state; +} + +void PAL_CALL palGetMouseDelta( + float* dx, + float* dy) +{ + if (!s_Video.initialized) { + return; + } + + if (dx) { + *dx = (float)s_Mouse.dx; + } + + if (dy) { + *dy = (float)s_Mouse.dy; + } +} + +void PAL_CALL palGetMouseWheelDelta( + float* dx, + float* dy) +{ + if (!s_Video.initialized) { + return; + } + + if (dx) { + *dx = (float)s_Mouse.WheelX; + } + + if (dy) { + *dy = (float)s_Mouse.WheelY; + } +} + +void PAL_CALL palSetPreferredInstance(void* instance) +{ + if (!s_Video.initialized && instance) { + s_Video.instance = instance; + } +} + +void* PAL_CALL palGetInstance() +{ + if (!s_Video.initialized) { + return nullptr; + } + + return (void*)s_Video.instance; +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/video/win32/pal_window_win32.c b/src/video/win32/pal_window_win32.c new file mode 100644 index 00000000..27eaaac3 --- /dev/null +++ b/src/video/win32/pal_window_win32.c @@ -0,0 +1,1150 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_video_common_win32.h" +#include "pal_shared.h" + +static WindowData* getFreeWindowData() +{ + for (int i = 0; i < s_Video.maxWindowData; ++i) { + if (!s_Video.windowData[i].used) { + s_Video.windowData[i].used = PAL_TRUE; + return &s_Video.windowData[i]; + } + } + + // resize the data array + // It is rare for a user to create and manage + // 32 windows at the same time + WindowData* data = nullptr; + int count = s_Video.maxWindowData * 2; // double the size + int freeIndex = s_Video.maxWindowData + 1; + data = palAllocate(s_Video.allocator, sizeof(WindowData) * count, 0); + if (data) { + memcpy(data, s_Video.windowData, s_Video.maxWindowData * sizeof(WindowData)); + + palFree(s_Video.allocator, s_Video.windowData); + s_Video.windowData = data; + s_Video.maxWindowData = count; + + s_Video.windowData[freeIndex].used = PAL_TRUE; + return &s_Video.windowData[freeIndex]; + } + return nullptr; +} + +PalResult PAL_CALL palCreateWindow( + const PalWindowCreateInfo* info, + PalWindow** outWindow) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!info || !outWindow) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + WindowData* data = getFreeWindowData(); + if (!data) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + HWND handle = nullptr; + PalMonitor* monitor = nullptr; + PalMonitorInfo monitorInfo; + + uint32_t style = WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED; + uint32_t exStyle = 0; + + // no minimize box + if (!(info->style & PAL_WINDOW_STYLE_NO_MINIMIZEBOX)) { + style |= WS_MINIMIZEBOX; + } + + // no maximize box + if (!(info->style & PAL_WINDOW_STYLE_NO_MAXIMIZEBOX)) { + style |= WS_MAXIMIZEBOX; + } + + // resizable window + if (info->style & PAL_WINDOW_STYLE_RESIZABLE) { + style |= WS_THICKFRAME; + + } else { + // not resizable. We remove the maximizebox even if user requested + style &= ~WS_MAXIMIZEBOX; + } + + // transparent window + if (info->style & PAL_WINDOW_STYLE_TRANSPARENT) { + exStyle |= WS_EX_LAYERED; + } + + // tool window + if (info->style & PAL_WINDOW_STYLE_TOOL) { + exStyle |= WS_EX_TOOLWINDOW; + } + + // topmost window + if (info->style & PAL_WINDOW_STYLE_TOPMOST) { + exStyle |= WS_EX_TOPMOST; + } + + // get monitor + if (info->monitor) { + monitor = info->monitor; + + } else { + // get primary monitor + monitor = (PalMonitor*)MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); + if (!monitor) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + } + + // get monitor info + PalResult result = palGetMonitorInfo(monitor, &monitorInfo); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + // compose position. + int32_t x, y = 0; + // the position and size must be scaled with the dpi before this call + if (info->center) { + x = monitorInfo.x + (monitorInfo.width - info->width) / 2; + y = monitorInfo.y + (monitorInfo.height - info->height) / 2; + + } else { + // we set 100 for each axix + x = monitorInfo.x + 100; + y = monitorInfo.y + 100; + } + + // adjust the window size + RECT rect = {0, 0, 0, 0}; + rect.right = info->width; + rect.bottom = info->height; + AdjustWindowRectEx(&rect, style, 0, exStyle); + + wchar_t buffer[WINDOW_NAME_SIZE]; + MultiByteToWideChar(CP_UTF8, 0, info->title, -1, buffer, 256); + + // create the window + handle = CreateWindowExW( + exStyle, + PAL_VIDEO_CLASS, + buffer, + style, + x, + y, + rect.right - rect.left, + rect.bottom - rect.top, + nullptr, + nullptr, + s_Video.instance, + nullptr); + + if (!handle) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // set the pixel format is set + if (s_Video.pixelFormat) { + HDC hdc = GetDC(handle); + // since we have the pixel format already + // we ask the OS (platform) to fill the pfd struct for us from that + // index + PIXELFORMATDESCRIPTOR pfd; + if (!s_Video.describePixelFormat( + hdc, + s_Video.pixelFormat, + sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + s_Video.setPixelFormat(hdc, s_Video.pixelFormat, &pfd); + ReleaseDC(handle, hdc); + } + + // show, maximize and minimize + int32_t showFlag = SW_HIDE; + // maximize + if (info->maximized) { + showFlag = SW_MAXIMIZE; + data->state = PAL_WINDOW_STATE_MAXIMIZED; + } + + // minimized + if (info->minimized) { + showFlag = SW_MINIMIZE; + data->state = PAL_WINDOW_STATE_MINIMIZED; + } + + // shown + if (info->show) { + if (showFlag == SW_HIDE) { + // change only if maximize and minimize are not set + showFlag = SW_SHOW; + data->state = PAL_WINDOW_STATE_RESTORED; + } + } + + ShowWindow(handle, showFlag); + UpdateWindow(handle); + + if (info->style & PAL_WINDOW_STYLE_BORDERLESS) { + // revert changes + SetWindowLongPtrW(handle, GWL_STYLE, WS_POPUP); + SetWindowLongPtrW(handle, GWL_EXSTYLE, WS_EX_APPWINDOW); + + // force a frame update + SetWindowPos( + handle, + nullptr, + 0, + 0, + 0, + 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + } + + data->isAttached = PAL_FALSE; + data->cursor = nullptr; + data->wndProc = (LONG_PTR)videoProc; + SetPropW(handle, PAL_VIDEO_PROP, data); + *outWindow = (PalWindow*)handle; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyWindow(PalWindow* window) +{ + if (s_Video.initialized && window) { + WindowData* data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); + // destroy only PAL created window + if (data->isAttached) { + return; + } + + DestroyWindow((HWND)window); + data->used = PAL_FALSE; + } +} + +PalResult PAL_CALL palMinimizeWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!ShowWindow((HWND)window, SW_MINIMIZE)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palMaximizeWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!ShowWindow((HWND)window, SW_MAXIMIZE)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palRestoreWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!ShowWindow((HWND)window, SW_RESTORE)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palShowWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!ShowWindow((HWND)window, SW_SHOW)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palHideWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!ShowWindow((HWND)window, SW_HIDE)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palFlashWindow( + PalWindow* window, + const PalFlashInfo* info) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window || !info) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + DWORD flags = 0; + if (info->flags == PAL_FLASH_STOP) { + flags = FLASHW_STOP; + + } else { + if (info->flags & PAL_FLASH_CAPTION) { + flags |= FLASHW_CAPTION; + } + if (info->flags & PAL_FLASH_TRAY) { + flags |= FLASHW_TRAY; + flags |= FLASHW_TIMERNOFG; + } + } + + FLASHWINFO flashInfo = {0}; + flashInfo.cbSize = sizeof(FLASHWINFO); + flashInfo.dwFlags = flags; + flashInfo.dwTimeout = info->interval; + flashInfo.hwnd = (HWND)window; + flashInfo.uCount = info->count; + + PalBool success = FlashWindowEx(&flashInfo); + if (!success) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetWindowStyle( + PalWindow* window, + PalWindowStyle* outStyle) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window || !outStyle) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + PalWindowStyle windowStyle = 0; + DWORD style = (DWORD)GetWindowLongPtrW((HWND)window, GWL_STYLE); + DWORD exStyle = (DWORD)GetWindowLongPtrW((HWND)window, GWL_EXSTYLE); + + if (!style) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // check if we can resize + if (style & WS_THICKFRAME) { + windowStyle |= PAL_WINDOW_STYLE_RESIZABLE; + } + + // check if we are transparent + if (exStyle & WS_EX_LAYERED) { + windowStyle |= PAL_WINDOW_STYLE_TRANSPARENT; + } + + // check if we are a topmost window + if (exStyle & WS_EX_TOPMOST) { + windowStyle |= PAL_WINDOW_STYLE_TOPMOST; + } + + // check if we have a minimize box + if (!(style & WS_MINIMIZEBOX)) { + windowStyle |= PAL_WINDOW_STYLE_NO_MINIMIZEBOX; + } + + // check if we have a maximize box + if (!(style & WS_MAXIMIZEBOX)) { + windowStyle |= PAL_WINDOW_STYLE_NO_MAXIMIZEBOX; + } + + // check if its a tool window + if (exStyle & WS_EX_TOOLWINDOW) { + windowStyle |= PAL_WINDOW_STYLE_TOOL; + } + + // we check borderless last since it will overwrite other styles + if (style & WS_POPUP) { + windowStyle |= PAL_WINDOW_STYLE_BORDERLESS; + + // we remove minimize and maximize box if set + windowStyle &= ~PAL_WINDOW_STYLE_NO_MINIMIZEBOX; + windowStyle &= ~PAL_WINDOW_STYLE_NO_MAXIMIZEBOX; + } + + *outStyle = windowStyle; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetWindowMonitor( + PalWindow* window, + PalMonitor** outMonitor) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window || !outMonitor) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + HMONITOR monitor = nullptr; + monitor = MonitorFromWindow((HWND)window, MONITOR_DEFAULTTONEAREST); + if (!monitor) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + *outMonitor = (PalMonitor*)monitor; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetWindowTitle( + PalWindow* window, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window || !outBuffer) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + wchar_t buffer[WINDOW_NAME_SIZE]; + if (GetWindowTextW((HWND)window, buffer, WINDOW_NAME_SIZE) == 0) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + int len = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, nullptr, 0, 0, 0); + if (outSize) { + *outSize = len - 1; + } + + // see if user provided a buffer and write to it + if (outBuffer && bufferSize > 0) { + int write = (int)bufferSize - 1; + WideCharToMultiByte(CP_UTF8, 0, buffer, -1, outBuffer, write + 1, 0, 0); + outBuffer[write < len - 1 ? write : len - 1] = '\0'; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetWindowPos( + PalWindow* window, + int32_t* x, + int32_t* y) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + RECT rect; + if (!GetWindowRect((HWND)window, &rect)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (x) { + *x = rect.left; + } + + if (y) { + *y = rect.top; + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetWindowSize( + PalWindow* window, + uint32_t* width, + uint32_t* height) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + RECT rect; + if (!GetWindowRect((HWND)window, &rect)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (width) { + *width = rect.right - rect.left; + } + + if (height) { + *height = rect.bottom - rect.top; + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palGetWindowState( + PalWindow* window, + PalWindowState* outState) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window || !outState) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + WINDOWPLACEMENT wp = {0}; + if (!GetWindowPlacement((HWND)window, &wp)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (wp.showCmd == SW_MINIMIZE) { + *outState = PAL_WINDOW_STATE_MINIMIZED; + + } else if (wp.showCmd == SW_MAXIMIZE) { + *outState = PAL_WINDOW_STATE_MAXIMIZED; + + } else if (wp.showCmd == SW_RESTORE || wp.showCmd == SW_NORMAL) { + *outState = PAL_WINDOW_STATE_RESTORED; + } + + return PAL_RESULT_SUCCESS; +} + +PalBool PAL_CALL palIsWindowVisible(PalWindow* window) +{ + if (!s_Video.initialized || !window) { + return PAL_FALSE; + } + + return IsWindowVisible((HWND)window); +} + +PalWindow* PAL_CALL palGetFocusWindow() +{ + if (!s_Video.initialized) { + return nullptr; + } + return (PalWindow*)GetFocus(); +} + +PalResult PAL_CALL palGetWindowHandleInfo( + PalWindow* window, + PalWindowHandleInfo* info) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window || !info) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + info->nativeDisplay = (void*)s_Video.instance; + info->nativeWindow = (void*)window; + info->nativeHandle1 = nullptr; + info->nativeHandle2 = nullptr; + info->nativeHandle3 = nullptr; + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetWindowOpacity( + PalWindow* window, + float opacity) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (opacity < 0.0f) { + opacity = 0.0f; + } + + if (opacity > 1.0f) { + opacity = 1.0f; + } + + PalBool ret = SetLayeredWindowAttributes((HWND)window, 0, (BYTE)(opacity * 255), LWA_ALPHA); + if (!ret) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else if (error == ERROR_INVALID_PARAMETER) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetWindowStyle( + PalWindow* window, + PalWindowStyle style) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // convert our style to win32 styles and exStyles + // all windows have this styles + DWORD win32Style = WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED; + DWORD exStyle = 0; + + // check for resizing + if (style & PAL_WINDOW_STYLE_RESIZABLE) { + win32Style |= WS_THICKFRAME; + } + + // check for transparent window + if (style & PAL_WINDOW_STYLE_TRANSPARENT) { + exStyle |= WS_EX_LAYERED; + } + + // check for topmost window + if (style & PAL_WINDOW_STYLE_TOPMOST) { + exStyle |= WS_EX_TOPMOST; + } + + // check for no minimize box + if (style & PAL_WINDOW_STYLE_NO_MINIMIZEBOX) { + win32Style &= ~WS_MINIMIZEBOX; + } + + // check for maximize box + if (style & PAL_WINDOW_STYLE_NO_MAXIMIZEBOX) { + win32Style &= ~WS_MAXIMIZEBOX; + } + + // check for tool window + if (style & PAL_WINDOW_STYLE_TOOL) { + exStyle |= WS_EX_TOOLWINDOW; + } + + // check for borderless window + if (style & PAL_WINDOW_STYLE_BORDERLESS) { + // revert the styles + win32Style = WS_POPUP; + exStyle = WS_EX_APPWINDOW; + } + + HWND hwnd = (HWND)window; + SetWindowLongPtrW(hwnd, GWL_STYLE, win32Style); + SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle); + + // force a frame update + PalBool success = SetWindowPos( + hwnd, + nullptr, + 0, + 0, + 0, + 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); + + if (success) { + return PAL_RESULT_SUCCESS; + + } else { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } +} + +PalResult PAL_CALL palSetWindowTitle( + PalWindow* window, + const char* title) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window || !title) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + wchar_t buffer[WINDOW_NAME_SIZE]; + MultiByteToWideChar(CP_UTF8, 0, title, -1, buffer, 256); + + if (!SetWindowTextW((HWND)window, buffer)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetWindowPos( + PalWindow* window, + int32_t x, + int32_t y) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + PalBool success = + SetWindowPos((HWND)window, nullptr, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); + + if (!success) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetWindowSize( + PalWindow* window, + uint32_t width, + uint32_t height) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + PalBool success = SetWindowPos( + (HWND)window, + HWND_TOP, + 0, + 0, + width, + height, + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); + + if (!success) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else if (error == ERROR_INVALID_PARAMETER) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetFocusWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!SetActiveWindow((HWND)window)) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else if (error == ERROR_ACCESS_DENIED) { + return palMakeResult( + PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palAttachWindow( + void* windowHandle, + PalWindow** outWindow) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!windowHandle || !outWindow) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + WindowData* data = getFreeWindowData(); + if (!data) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + PalWindow* window = (PalWindow*)windowHandle; + data->isAttached = PAL_TRUE; + data->wndProc = SetWindowLongPtrW((HWND)windowHandle, GWLP_WNDPROC, (LONG_PTR)videoProc); + + // use default PAL video cursor + // there is no way to get the cursor set on the native window + data->cursor = nullptr; + + // get state + palGetWindowState(window, &data->state); + SetPropW((HWND)window, PAL_VIDEO_PROP, data); + + *outWindow = window; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palDetachWindow( + PalWindow* window, + void** outWindowHandle) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + WindowData* data = nullptr; + data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); + if (!data) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (data->isAttached == PAL_FALSE) { + // window is owned by PAL + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + data->used = PAL_FALSE; + SetWindowLongPtrW((HWND)window, GWLP_WNDPROC, data->wndProc); + if (outWindowHandle) { + *outWindowHandle = (void*)window; + } + + return PAL_RESULT_SUCCESS; +} + +#endif // _WIN32 \ No newline at end of file diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index ef2d6d23..d702d9dc 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -41,9 +41,8 @@ PalBool clearColorTest() PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); @@ -51,27 +50,25 @@ PalBool clearColorTest() result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } PalWindowCreateInfo windowCreateInfo = {0}; windowCreateInfo.height = WINDOW_HEIGHT; windowCreateInfo.width = WINDOW_WIDTH; - windowCreateInfo.show = true; + windowCreateInfo.show = PAL_TRUE; windowCreateInfo.title = "Clear Color Window"; - PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); - if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures videoFeatures = palGetVideoFeatures(); + if (!(videoFeatures & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } result = palCreateWindow(&windowCreateInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window");; + return PAL_FALSE; } PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); @@ -86,7 +83,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get platform information: %s", error); - return false; + return PAL_FALSE; } if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { @@ -108,7 +105,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -117,12 +114,12 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (adapterCount == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %d", adapterCount); @@ -130,14 +127,14 @@ PalBool clearColorTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } PalAdapterCapabilities caps = {0}; @@ -149,7 +146,7 @@ PalBool clearColorTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } if (caps.maxGraphicsQueues == 0) { @@ -164,7 +161,7 @@ PalBool clearColorTest() palFree(nullptr, adapters); if (!adapter) { palLog(nullptr, "Failed to find a required adapter"); - return false; + return PAL_FALSE; } // create a device @@ -178,7 +175,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); - return false; + return PAL_FALSE; } // create surface @@ -186,17 +183,17 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create surface: %s", error); - return false; + return PAL_FALSE; } // create a graphics command queue and check if its supports presenting to the surface - PalBool foundQueue = false; + PalBool foundQueue = PAL_FALSE; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create queue: %s", error); - return false; + return PAL_FALSE; } if (!palCanQueuePresent(queue, surface)) { @@ -204,14 +201,14 @@ PalBool clearColorTest() queue = nullptr; } else { // found a queue - foundQueue = true; + foundQueue = PAL_TRUE; break; } } if (!foundQueue) { palLog(nullptr, "Failed to find a queue that can present to the surface"); - return false; + return PAL_FALSE; } // create a swapchain with the graphics queue @@ -220,11 +217,11 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get surface capabilities: %s", error); - return false; + return PAL_FALSE; } PalSwapchainCreateInfo swapchainCreateInfo = {0}; - swapchainCreateInfo.clipped = true; + swapchainCreateInfo.clipped = PAL_TRUE; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; @@ -248,7 +245,7 @@ PalBool clearColorTest() swapchainCreateInfo.imageCount++; if (surfaceCaps.maxImageCount < 2) { palLog(nullptr, "Surface does not support double buffers"); - return false; + return PAL_FALSE; } } @@ -256,7 +253,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); - return false; + return PAL_FALSE; } // get all swapchain images and create image views for them @@ -266,7 +263,7 @@ PalBool clearColorTest() renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } PalImageInfo imageInfo; @@ -274,7 +271,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image info: %s", error); - return false; + return PAL_FALSE; } PalImageViewCreateInfo imageViewCreateInfo = {0}; @@ -297,15 +294,15 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); - return false; + return PAL_FALSE; } // create render finished semaphores - result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } inFlightImages[i] = nullptr; @@ -315,23 +312,23 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); - return false; + return PAL_FALSE; } // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } - result = palCreateFence(device, true, &inFlightFences[i]); + result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } result = palAllocateCommandBuffer( @@ -343,13 +340,13 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; + return PAL_FALSE; } } // main loop uint32_t currentFrame = 0; - PalBool running = true; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -358,7 +355,7 @@ PalBool clearColorTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -366,7 +363,7 @@ PalBool clearColorTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -377,7 +374,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } // get next swapchain image @@ -391,7 +388,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; + return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { @@ -399,7 +396,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -409,18 +406,18 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } else { // recreate since we dont support fence resetting palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &inFlightFences[currentFrame]); + result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -429,14 +426,14 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it renderable @@ -461,7 +458,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } PalClearValue clearValue; @@ -485,14 +482,14 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); - return false; + return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it presentable @@ -508,14 +505,14 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit command buffer @@ -529,7 +526,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // present @@ -540,7 +537,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to present swapchain: %s", error); - return false; + return PAL_FALSE; } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; @@ -550,7 +547,7 @@ PalBool clearColorTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for queue: %s", error); - return false; + return PAL_FALSE; } for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { @@ -578,5 +575,5 @@ PalBool clearColorTest() palDestroyWindow(window); palShutdownVideo(); palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 3c6901af..19eea564 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -49,7 +49,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -58,12 +58,12 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (adapterCount == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %d", adapterCount); @@ -71,14 +71,14 @@ PalBool computeTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } PalAdapterCapabilities caps = {0}; @@ -91,7 +91,7 @@ PalBool computeTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } if (caps.maxComputeQueues == 0) { @@ -104,7 +104,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - return false; + return PAL_FALSE; } // we prefer spirv first if an adapter supports multiple shader formats @@ -130,7 +130,7 @@ PalBool computeTest() palFree(nullptr, adapters); if (!adapter) { palLog(nullptr, "Failed to find a required adapter"); - return false; + return PAL_FALSE; } // create a device @@ -138,7 +138,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); - return false; + return PAL_FALSE; } // create a compute command queue @@ -146,14 +146,14 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create queue: %s", error); - return false; + return PAL_FALSE; } result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); - return false; + return PAL_FALSE; } result = palAllocateCommandBuffer( @@ -165,7 +165,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; + return PAL_FALSE; } // create a compute shader @@ -184,13 +184,13 @@ PalBool computeTest() // read file if (!readFile(source, nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to read shader file"); - return false; + return PAL_FALSE; } bytecode = palAllocate(nullptr, bytecodeSize, 0); if (!bytecode) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } readFile(source, bytecode, &bytecodeSize); @@ -208,7 +208,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create compute shader: %s", error); - return false; + return PAL_FALSE; } palFree(nullptr, bytecode); @@ -223,7 +223,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create buffer: %s", error); - return false; + return PAL_FALSE; } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_DST; @@ -231,7 +231,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create staging buffer: %s", error); - return false; + return PAL_FALSE; } // get buffer memory requirement and allocate memory @@ -241,14 +241,14 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } // we need to check if the memory type we want are supported @@ -264,7 +264,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -277,7 +277,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } // bind memory @@ -285,14 +285,14 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // create descriptor set layout @@ -316,7 +316,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create descriptor set layout: %s", error); - return false; + return PAL_FALSE; } // create descriptor pool @@ -333,7 +333,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create descriptor pool: %s", error); - return false; + return PAL_FALSE; } // allocate a single descriptor set from the descriptor pool @@ -342,7 +342,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate descriptor set: %s", error); - return false; + return PAL_FALSE; } // write the inital data to the descriptor set since its created empty @@ -362,7 +362,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); - return false; + return PAL_FALSE; } // push constants @@ -384,7 +384,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); - return false; + return PAL_FALSE; } // create a compute pipeline @@ -396,17 +396,17 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create compute pipeline: %s", error); - return false; + return PAL_FALSE; } palDestroyShader(shader); // create fence - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } // record commands @@ -414,7 +414,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } PushConstant pushConstant = {0}; @@ -429,7 +429,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; + return PAL_FALSE; } result = palCmdPushConstants( @@ -443,14 +443,14 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to push constants: %s", error); - return false; + return PAL_FALSE; } result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); - return false; + return PAL_FALSE; } // we will use a helper function to calculate the number of group count @@ -475,13 +475,13 @@ PalBool computeTest() PalBool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); if (!ret) { palLog(nullptr, "Failed to build work group info"); - return false; + return PAL_FALSE; } workGroupInfos = palAllocate(nullptr, sizeof(PalWorkGroupInfo) * workGroupInfoCount, 0); if (!workGroupInfos) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, workGroupInfos); @@ -499,7 +499,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to dispatch: %s", error); - return false; + return PAL_FALSE; } } palFree(nullptr, workGroupInfos); @@ -519,7 +519,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } // now we copy from the GPU buffer into the staging buffer @@ -530,14 +530,14 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit the command buffer to the GPU @@ -548,7 +548,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // wait for the fence @@ -556,7 +556,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); - return false; + return PAL_FALSE; } // now our staging buffer has the contents of the GPU buffer @@ -566,7 +566,7 @@ PalBool computeTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } // write to a ppm output file @@ -606,5 +606,5 @@ PalBool computeTest() palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); - return true; + return PAL_TRUE; } diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 69285b4e..b46c879d 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -91,9 +91,8 @@ PalBool descriptorIndexingTest() PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); @@ -101,27 +100,25 @@ PalBool descriptorIndexingTest() result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } PalWindowCreateInfo windowCreateInfo = {0}; windowCreateInfo.height = WINDOW_HEIGHT; windowCreateInfo.width = WINDOW_WIDTH; - windowCreateInfo.show = true; + windowCreateInfo.show = PAL_TRUE; windowCreateInfo.title = "Descriptor Indexing Window"; - PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); - if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures videoFeatures = palGetVideoFeatures(); + if (!(videoFeatures & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } result = palCreateWindow(&windowCreateInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); @@ -136,7 +133,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get platform information: %s", error); - return false; + return PAL_FALSE; } if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { @@ -158,7 +155,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -167,12 +164,12 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (adapterCount == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %d", adapterCount); @@ -180,14 +177,14 @@ PalBool descriptorIndexingTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } PalAdapterCapabilities caps = {0}; @@ -200,7 +197,7 @@ PalBool descriptorIndexingTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } if (caps.maxGraphicsQueues == 0) { @@ -219,7 +216,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - return false; + return PAL_FALSE; } // we prefer spirv first if an adapter supports multiple shader formats @@ -245,7 +242,7 @@ PalBool descriptorIndexingTest() palFree(nullptr, adapters); if (!adapter) { palLog(nullptr, "Failed to find a required adapter"); - return false; + return PAL_FALSE; } // create a device @@ -268,7 +265,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); - return false; + return PAL_FALSE; } // create surface @@ -276,17 +273,17 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create surface: %s", error); - return false; + return PAL_FALSE; } // create a graphics command queue and check if its supports presenting to the surface - PalBool foundQueue = false; + PalBool foundQueue = PAL_FALSE; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create queue: %s", error); - return false; + return PAL_FALSE; } if (!palCanQueuePresent(queue, surface)) { @@ -294,14 +291,14 @@ PalBool descriptorIndexingTest() queue = nullptr; } else { // found a queue - foundQueue = true; + foundQueue = PAL_TRUE; break; } } if (!foundQueue) { palLog(nullptr, "Failed to find a queue that can present to the surface"); - return false; + return PAL_FALSE; } // create a swapchain with the graphics queue @@ -310,11 +307,11 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get surface capabilities: %s", error); - return false; + return PAL_FALSE; } PalSwapchainCreateInfo swapchainCreateInfo = {0}; - swapchainCreateInfo.clipped = true; + swapchainCreateInfo.clipped = PAL_TRUE; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; @@ -338,7 +335,7 @@ PalBool descriptorIndexingTest() swapchainCreateInfo.imageCount++; if (surfaceCaps.maxImageCount < 2) { palLog(nullptr, "Surface does not support double buffers"); - return false; + return PAL_FALSE; } } @@ -346,7 +343,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); - return false; + return PAL_FALSE; } // get all swapchain images and create image views for them @@ -356,7 +353,7 @@ PalBool descriptorIndexingTest() renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } PalImageInfo imageInfo; @@ -364,7 +361,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image info: %s", error); - return false; + return PAL_FALSE; } PalImageViewCreateInfo imageViewCreateInfo = {0}; @@ -387,15 +384,15 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); - return false; + return PAL_FALSE; } // create render finished semaphores - result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } inFlightImages[i] = nullptr; @@ -405,23 +402,23 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); - return false; + return PAL_FALSE; } // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } - result = palCreateFence(device, true, &inFlightFences[i]); + result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } result = palAllocateCommandBuffer( @@ -433,7 +430,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; + return PAL_FALSE; } } @@ -457,7 +454,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create vertex buffer: %s", error); - return false; + return PAL_FALSE; } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send @@ -465,7 +462,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create staging buffer: %s", error); - return false; + return PAL_FALSE; } // get buffer memory requirement and allocate memory @@ -476,14 +473,14 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } // we need to check if the memory type we want are supported @@ -499,7 +496,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -512,7 +509,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } // bind memory @@ -520,14 +517,14 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // map the staging buffer and upload the vertices @@ -536,18 +533,18 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } memcpy(ptr, vertices, sizeof(vertices)); palUnmapBufferMemory(stagingBuffer); PalFence* fence = nullptr; - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } // create image for the textures @@ -566,7 +563,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image: %s", error); - return false; + return PAL_FALSE; } // allocate memory for the image @@ -575,7 +572,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -588,14 +585,14 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory: %s", error); - return false; + return PAL_FALSE; } result = palBindImageMemory(textures[i], textureMemories[i], 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind image memory: %s", error); - return false; + return PAL_FALSE; } } @@ -621,7 +618,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to compute image copy staging buffer info: %s", error); - return false; + return PAL_FALSE; } // update our copy with the required buffer row length and buffer image height @@ -647,7 +644,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image staging buffer: %s", error); - return false; + return PAL_FALSE; } PalMemoryRequirements imageStagingBufferMemReq = {0}; @@ -655,7 +652,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image staging buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -668,14 +665,14 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(imageStagingBuffers[i], imageStagingBufferMemories[i], 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind image staging buffer memory: %s", error); - return false; + return PAL_FALSE; } // copy data @@ -689,7 +686,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } // write data to the mapped image copy staging buffer @@ -703,7 +700,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to write to image copy staging buffer: %s", error); - return false; + return PAL_FALSE; } palUnmapBufferMemory(imageStagingBuffers[i]); @@ -717,7 +714,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } PalBufferCopyInfo copyInfo = {0}; @@ -727,7 +724,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); - return false; + return PAL_FALSE; } PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; @@ -743,7 +740,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } // copy image staging buffers to the images @@ -777,7 +774,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdCopyBufferToImage( @@ -789,7 +786,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer to image: %s", error); - return false; + return PAL_FALSE; } // we should transition the image into a shader read state so we dont do that @@ -810,7 +807,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image barrier: %s", error); - return false; + return PAL_FALSE; } } @@ -818,7 +815,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } PalCommandBufferSubmitInfo submitInfo = {0}; @@ -828,7 +825,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // now we have the checkerboard texture data in the image @@ -848,7 +845,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create checkerboard image view: %s", error); - return false; + return PAL_FALSE; } } @@ -860,8 +857,8 @@ PalBool descriptorIndexingTest() samplerCreateInfo.borderColor = PAL_BORDER_COLOR_INT_OPAQUE_BLACK; samplerCreateInfo.compareOp = PAL_COMPARE_OP_NEVER; // will not be used if its not enabled - samplerCreateInfo.enableAnisotropy = false; - samplerCreateInfo.enableCompare = false; + samplerCreateInfo.enableAnisotropy = PAL_FALSE; + samplerCreateInfo.enableCompare = PAL_FALSE; samplerCreateInfo.magFilterMode = PAL_FILTER_MODE_LINEAR; samplerCreateInfo.minFilterMode = PAL_FILTER_MODE_LINEAR; samplerCreateInfo.maxAnisotropy = 1.0f; @@ -874,7 +871,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create sampler: %s", error); - return false; + return PAL_FALSE; } // create shaders @@ -914,13 +911,13 @@ PalBool descriptorIndexingTest() // read file if (!readFile(sources[i], nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to read shader file"); - return false; + return PAL_FALSE; } bytecode = palAllocate(nullptr, bytecodeSize, 0); if (!bytecode) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } readFile(sources[i], bytecode, &bytecodeSize); @@ -934,7 +931,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create shader: %s", error); - return false; + return PAL_FALSE; } palFree(nullptr, bytecode); @@ -958,7 +955,7 @@ PalBool descriptorIndexingTest() descriptorSetLayoutcreateInfo.shaderStages = shaderStages; // we need to enable descriptor indexing for the descriptor set layout - descriptorSetLayoutcreateInfo.enableDescriptorIndexing = true; + descriptorSetLayoutcreateInfo.enableDescriptorIndexing = PAL_TRUE; result = palCreateDescriptorSetLayout( device, @@ -968,7 +965,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create descriptor set layout: %s", error); - return false; + return PAL_FALSE; } // create descriptor pool @@ -985,13 +982,13 @@ PalBool descriptorIndexingTest() descriptorPoolCreateInfo.bindingSizes = storageBufferBindingsizes; // we need to enable descriptor indexing for the descriptor pool - descriptorPoolCreateInfo.enableDescriptorIndexing = true; + descriptorPoolCreateInfo.enableDescriptorIndexing = PAL_TRUE; result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create descriptor pool: %s", error); - return false; + return PAL_FALSE; } // allocate a single descriptor set from the descriptor pool @@ -1000,7 +997,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate descriptor set: %s", error); - return false; + return PAL_FALSE; } // check if null descriptors was enabled and partially bound was not supported @@ -1023,7 +1020,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); - return false; + return PAL_FALSE; } } else { @@ -1050,7 +1047,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); - return false; + return PAL_FALSE; } } @@ -1098,7 +1095,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); - return false; + return PAL_FALSE; } @@ -1121,7 +1118,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); - return false; + return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; @@ -1175,7 +1172,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create graphics pipeline: %s", error); - return false; + return PAL_FALSE; } for (int i = 0; i < 2; i++) { @@ -1187,7 +1184,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); - return false; + return PAL_FALSE; } // the vertices have been copied @@ -1203,7 +1200,7 @@ PalBool descriptorIndexingTest() // main loop uint32_t currentFrame = 0; - PalBool running = true; + PalBool running = PAL_TRUE; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; @@ -1223,7 +1220,7 @@ PalBool descriptorIndexingTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -1231,7 +1228,7 @@ PalBool descriptorIndexingTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -1242,7 +1239,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } // get next swapchain image @@ -1256,7 +1253,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; + return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { @@ -1264,7 +1261,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -1274,18 +1271,18 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } else { // recreate since we dont support fence resetting palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &inFlightFences[currentFrame]); + result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -1294,14 +1291,14 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it renderable @@ -1326,7 +1323,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } PalClearValue clearValue; @@ -1350,7 +1347,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); - return false; + return PAL_FALSE; } // bind pipeline @@ -1358,7 +1355,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; + return PAL_FALSE; } result = palCmdPushConstants( @@ -1372,14 +1369,14 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to push constants: %s", error); - return false; + return PAL_FALSE; } result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); - return false; + return PAL_FALSE; } // set viewport and scissors @@ -1387,14 +1384,14 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); - return false; + return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); - return false; + return PAL_FALSE; } // bind vertex buffer @@ -1409,21 +1406,21 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind vertex buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); - return false; + return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it presentable @@ -1439,14 +1436,14 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit command buffer @@ -1460,7 +1457,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // present @@ -1471,7 +1468,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to present swapchain: %s", error); - return false; + return PAL_FALSE; } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; @@ -1481,7 +1478,7 @@ PalBool descriptorIndexingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for queue: %s", error); - return false; + return PAL_FALSE; } palDestroyPipeline(pipeline); @@ -1525,5 +1522,5 @@ PalBool descriptorIndexingTest() palDestroyWindow(window); palShutdownVideo(); palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index e173914f..0a21287d 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -45,9 +45,8 @@ PalBool geometryTest() PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); @@ -55,27 +54,25 @@ PalBool geometryTest() result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } PalWindowCreateInfo windowCreateInfo = {0}; windowCreateInfo.height = WINDOW_HEIGHT; windowCreateInfo.width = WINDOW_WIDTH; - windowCreateInfo.show = true; + windowCreateInfo.show = PAL_TRUE; windowCreateInfo.title = "Geometry Window"; - PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); - if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures videoFeatures = palGetVideoFeatures(); + if (!(videoFeatures & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } result = palCreateWindow(&windowCreateInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); @@ -90,7 +87,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get platform information: %s", error); - return false; + return PAL_FALSE; } if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { @@ -112,7 +109,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -121,12 +118,12 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (adapterCount == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %d", adapterCount); @@ -134,14 +131,14 @@ PalBool geometryTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } PalAdapterCapabilities caps = {0}; @@ -154,7 +151,7 @@ PalBool geometryTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } if (caps.maxGraphicsQueues == 0) { @@ -173,7 +170,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - return false; + return PAL_FALSE; } // we prefer spirv first if an adapter supports multiple shader formats @@ -199,7 +196,7 @@ PalBool geometryTest() palFree(nullptr, adapters); if (!adapter) { palLog(nullptr, "Failed to find a required adapter"); - return false; + return PAL_FALSE; } // create a device @@ -213,7 +210,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); - return false; + return PAL_FALSE; } // create surface @@ -221,17 +218,17 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create surface: %s", error); - return false; + return PAL_FALSE; } // create a graphics command queue and check if its supports presenting to the surface - PalBool foundQueue = false; + PalBool foundQueue = PAL_FALSE; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create queue: %s", error); - return false; + return PAL_FALSE; } if (!palCanQueuePresent(queue, surface)) { @@ -239,14 +236,14 @@ PalBool geometryTest() queue = nullptr; } else { // found a queue - foundQueue = true; + foundQueue = PAL_TRUE; break; } } if (!foundQueue) { palLog(nullptr, "Failed to find a queue that can present to the surface"); - return false; + return PAL_FALSE; } // create a swapchain with the graphics queue @@ -255,11 +252,11 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get surface capabilities: %s", error); - return false; + return PAL_FALSE; } PalSwapchainCreateInfo swapchainCreateInfo = {0}; - swapchainCreateInfo.clipped = true; + swapchainCreateInfo.clipped = PAL_TRUE; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; @@ -283,7 +280,7 @@ PalBool geometryTest() swapchainCreateInfo.imageCount++; if (surfaceCaps.maxImageCount < 2) { palLog(nullptr, "Surface does not support double buffers"); - return false; + return PAL_FALSE; } } @@ -291,7 +288,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); - return false; + return PAL_FALSE; } // get all swapchain images and create image views for them @@ -301,7 +298,7 @@ PalBool geometryTest() renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } PalImageInfo imageInfo; @@ -309,7 +306,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image info: %s", error); - return false; + return PAL_FALSE; } PalImageViewCreateInfo imageViewCreateInfo = {0}; @@ -332,15 +329,15 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); - return false; + return PAL_FALSE; } // create render finished semaphores - result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } inFlightImages[i] = nullptr; @@ -350,23 +347,23 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); - return false; + return PAL_FALSE; } // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } - result = palCreateFence(device, true, &inFlightFences[i]); + result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } result = palAllocateCommandBuffer( @@ -378,7 +375,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; + return PAL_FALSE; } } @@ -425,13 +422,13 @@ PalBool geometryTest() // read file if (!readFile(sources[i], nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to read shader file"); - return false; + return PAL_FALSE; } bytecode = palAllocate(nullptr, bytecodeSize, 0); if (!bytecode) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } readFile(sources[i], bytecode, &bytecodeSize); @@ -445,7 +442,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create shader: %s", error); - return false; + return PAL_FALSE; } palFree(nullptr, bytecode); @@ -457,7 +454,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); - return false; + return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; @@ -491,7 +488,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create graphics pipeline: %s", error); - return false; + return PAL_FALSE; } for (int i = 0; i < 3; i++) { @@ -500,7 +497,7 @@ PalBool geometryTest() // main loop uint32_t currentFrame = 0; - PalBool running = true; + PalBool running = PAL_TRUE; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; @@ -514,7 +511,7 @@ PalBool geometryTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -522,7 +519,7 @@ PalBool geometryTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -533,7 +530,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } // get next swapchain image @@ -547,7 +544,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; + return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { @@ -555,7 +552,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -565,18 +562,18 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } else { // recreate since we dont support fence resetting palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &inFlightFences[currentFrame]); + result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -585,14 +582,14 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it renderable @@ -617,7 +614,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } PalClearValue clearValue; @@ -641,7 +638,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); - return false; + return PAL_FALSE; } // bind pipeline @@ -649,7 +646,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; + return PAL_FALSE; } // set viewport and scissors @@ -657,34 +654,34 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); - return false; + return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); - return false; + return PAL_FALSE; } if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind vertex buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdDraw(cmdBuffers[currentFrame], 3, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); - return false; + return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it presentable @@ -700,14 +697,14 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit command buffer @@ -721,7 +718,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // present @@ -732,7 +729,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to present swapchain: %s", error); - return false; + return PAL_FALSE; } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; @@ -742,7 +739,7 @@ PalBool geometryTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for queue: %s", error); - return false; + return PAL_FALSE; } palDestroyPipeline(pipeline); @@ -773,5 +770,5 @@ PalBool geometryTest() palDestroyWindow(window); palShutdownVideo(); palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } \ No newline at end of file diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 0776b1ec..8d1f4f36 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -9,7 +9,7 @@ PalBool graphicsTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -18,12 +18,12 @@ PalBool graphicsTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (count == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %u", count); @@ -33,14 +33,14 @@ PalBool graphicsTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&count, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } // get information about all the adapters @@ -54,7 +54,7 @@ PalBool graphicsTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter information: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } result = palGetAdapterCapabilities(adapter, &caps); @@ -62,7 +62,7 @@ PalBool graphicsTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } // create a device @@ -102,7 +102,7 @@ PalBool graphicsTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } uint32_t vramMb = (uint32_t)info.vram / (1024 * 1024); @@ -295,7 +295,7 @@ PalBool graphicsTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get sampler anisotropy capabilities: %s", error); - return false; + return PAL_FALSE; } palLog(nullptr, " Max anisotropy: %u", tmp.maxAnisotropy); @@ -311,7 +311,7 @@ PalBool graphicsTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get multi viewport capabilities: %s", error); - return false; + return PAL_FALSE; } palLog(nullptr, " Max count: %u", tmp.maxCount); @@ -327,7 +327,7 @@ PalBool graphicsTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get ray tracing capabilities: %s", error); - return false; + return PAL_FALSE; } palLog(nullptr, " Max recursion depth: %u", tmp.maxRecursionDepth); @@ -349,7 +349,7 @@ PalBool graphicsTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get mesh shader capabilities: %s", error); - return false; + return PAL_FALSE; } palLog(nullptr, " Max output primitives: %u", tmp.maxOutputPrimitives); @@ -375,7 +375,7 @@ PalBool graphicsTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get FSR capabilities: %s", error); - return false; + return PAL_FALSE; } palLog(nullptr, " Min texel width: %u", tmp.minTexelWidth); @@ -445,7 +445,7 @@ PalBool graphicsTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get descriptor indexing capabilities: %s", error); - return false; + return PAL_FALSE; } if (tmp.sampledImageNonUniformIndexing) { @@ -532,7 +532,7 @@ PalBool graphicsTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get multi view capabilities: %s", error); - return false; + return PAL_FALSE; } palLog(nullptr, " Max view count: %u", tmp.maxViewCount); @@ -547,7 +547,7 @@ PalBool graphicsTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get depth stencil capabilities: %s", error); - return false; + return PAL_FALSE; } if (tmp.independentResolve) { @@ -718,5 +718,5 @@ PalBool graphicsTest() palFree(nullptr, adapters); - return true; + return PAL_TRUE; } diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index c3710c3f..98c3dd59 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -62,9 +62,8 @@ PalBool indirectDrawTest() PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); @@ -72,27 +71,25 @@ PalBool indirectDrawTest() result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } PalWindowCreateInfo windowCreateInfo = {0}; windowCreateInfo.height = WINDOW_HEIGHT; windowCreateInfo.width = WINDOW_WIDTH; - windowCreateInfo.show = true; + windowCreateInfo.show = PAL_TRUE; windowCreateInfo.title = "Indirect Draw Window"; - PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); - if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures videoFeatures = palGetVideoFeatures(); + if (!(videoFeatures & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } result = palCreateWindow(&windowCreateInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); @@ -107,7 +104,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get platform information: %s", error); - return false; + return PAL_FALSE; } if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { @@ -129,7 +126,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -138,12 +135,12 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (adapterCount == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %d", adapterCount); @@ -151,14 +148,14 @@ PalBool indirectDrawTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } PalAdapterCapabilities caps = {0}; @@ -171,7 +168,7 @@ PalBool indirectDrawTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } if (caps.maxGraphicsQueues == 0) { @@ -190,7 +187,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - return false; + return PAL_FALSE; } // we prefer spirv first if an adapter supports multiple shader formats @@ -216,7 +213,7 @@ PalBool indirectDrawTest() palFree(nullptr, adapters); if (!adapter) { palLog(nullptr, "Failed to find a required adapter"); - return false; + return PAL_FALSE; } // create a device @@ -230,7 +227,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); - return false; + return PAL_FALSE; } // create surface @@ -238,17 +235,17 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create surface: %s", error); - return false; + return PAL_FALSE; } // create a graphics command queue and check if its supports presenting to the surface - PalBool foundQueue = false; + PalBool foundQueue = PAL_FALSE; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create queue: %s", error); - return false; + return PAL_FALSE; } if (!palCanQueuePresent(queue, surface)) { @@ -256,14 +253,14 @@ PalBool indirectDrawTest() queue = nullptr; } else { // found a queue - foundQueue = true; + foundQueue = PAL_TRUE; break; } } if (!foundQueue) { palLog(nullptr, "Failed to find a queue that can present to the surface"); - return false; + return PAL_FALSE; } // create a swapchain with the graphics queue @@ -272,11 +269,11 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get surface capabilities: %s", error); - return false; + return PAL_FALSE; } PalSwapchainCreateInfo swapchainCreateInfo = {0}; - swapchainCreateInfo.clipped = true; + swapchainCreateInfo.clipped = PAL_TRUE; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; @@ -300,7 +297,7 @@ PalBool indirectDrawTest() swapchainCreateInfo.imageCount++; if (surfaceCaps.maxImageCount < 2) { palLog(nullptr, "Surface does not support double buffers"); - return false; + return PAL_FALSE; } } @@ -308,7 +305,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); - return false; + return PAL_FALSE; } // get all swapchain images and create image views for them @@ -318,7 +315,7 @@ PalBool indirectDrawTest() renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } PalImageInfo imageInfo; @@ -326,7 +323,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image info: %s", error); - return false; + return PAL_FALSE; } PalImageViewCreateInfo imageViewCreateInfo = {0}; @@ -349,15 +346,15 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); - return false; + return PAL_FALSE; } // create render finished semaphores - result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } inFlightImages[i] = nullptr; @@ -367,23 +364,23 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); - return false; + return PAL_FALSE; } // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } - result = palCreateFence(device, true, &inFlightFences[i]); + result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } result = palAllocateCommandBuffer( @@ -395,7 +392,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; + return PAL_FALSE; } } @@ -420,7 +417,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create buffer: %s", error); - return false; + return PAL_FALSE; } // index buffer @@ -431,7 +428,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create buffer: %s", error); - return false; + return PAL_FALSE; } // indirect buffer @@ -442,7 +439,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create buffer: %s", error); - return false; + return PAL_FALSE; } // staging buffer for vertex, index and indirect buffer @@ -466,7 +463,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create buffer: %s", error); - return false; + return PAL_FALSE; } // get buffer memory requirement and allocate memory @@ -480,7 +477,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } // get index buffer memory requirement @@ -488,7 +485,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } // get indirect buffer memory requirement @@ -496,7 +493,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } // get staging buffer memory requirement @@ -504,7 +501,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } // allocate memory for vertex buffer @@ -518,7 +515,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } // allocate memory for index buffer @@ -532,7 +529,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } // allocate memory for indirect buffer @@ -546,7 +543,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -559,7 +556,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } // bind memory for vertex buffer @@ -567,7 +564,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // bind memory for index buffer @@ -575,7 +572,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // bind memory for indirect buffer @@ -583,7 +580,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // bind memory for staging buffer @@ -591,7 +588,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // map the staging buffer and upload the data @@ -600,7 +597,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } // copy indirect data @@ -623,11 +620,11 @@ PalBool indirectDrawTest() palUnmapBufferMemory(stagingBuffer); PalFence* fence = nullptr; - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } // use the first command buffer to upload the copy @@ -638,7 +635,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } PalUsageStateInfo oldUsageStateInfo = {0}; @@ -659,7 +656,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBufferBarrier( @@ -671,7 +668,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } // copy to vertex buffer @@ -690,7 +687,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBufferBarrier( @@ -702,7 +699,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } // copy to index buffer @@ -719,7 +716,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBufferBarrier( @@ -731,14 +728,14 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } PalCommandBufferSubmitInfo submitInfo = {0}; @@ -748,7 +745,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // create shaders @@ -788,13 +785,13 @@ PalBool indirectDrawTest() // read file if (!readFile(sources[i], nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to read shader file"); - return false; + return PAL_FALSE; } bytecode = palAllocate(nullptr, bytecodeSize, 0); if (!bytecode) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } readFile(sources[i], bytecode, &bytecodeSize); @@ -808,7 +805,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create shader: %s", error); - return false; + return PAL_FALSE; } palFree(nullptr, bytecode); @@ -820,7 +817,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); - return false; + return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; @@ -874,7 +871,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create graphics pipeline: %s", error); - return false; + return PAL_FALSE; } for (int i = 0; i < 2; i++) { @@ -886,7 +883,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); - return false; + return PAL_FALSE; } // the vertices have been copied @@ -896,7 +893,7 @@ PalBool indirectDrawTest() // main loop uint32_t currentFrame = 0; - PalBool running = true; + PalBool running = PAL_TRUE; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; @@ -910,7 +907,7 @@ PalBool indirectDrawTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -918,7 +915,7 @@ PalBool indirectDrawTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -929,7 +926,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } // get next swapchain image @@ -943,7 +940,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; + return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { @@ -951,7 +948,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -961,18 +958,18 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } else { // recreate since we dont support fence resetting palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &inFlightFences[currentFrame]); + result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -981,14 +978,14 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it renderable @@ -1013,7 +1010,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } PalClearValue clearValue; @@ -1037,7 +1034,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); - return false; + return PAL_FALSE; } // bind pipeline @@ -1045,7 +1042,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; + return PAL_FALSE; } // set viewport and scissors @@ -1053,14 +1050,14 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); - return false; + return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); - return false; + return PAL_FALSE; } // bind vertex buffer @@ -1075,7 +1072,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind vertex buffer: %s", error); - return false; + return PAL_FALSE; } // bind index buffer @@ -1088,21 +1085,21 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind index buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdDrawIndexedIndirect(cmdBuffers[currentFrame], indirectBuffer, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw indirect command: %s", error); - return false; + return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it presentable @@ -1118,14 +1115,14 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit command buffer @@ -1139,7 +1136,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // present @@ -1150,7 +1147,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to present swapchain: %s", error); - return false; + return PAL_FALSE; } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; @@ -1160,7 +1157,7 @@ PalBool indirectDrawTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for queue: %s", error); - return false; + return PAL_FALSE; } palDestroyPipeline(pipeline); @@ -1199,5 +1196,5 @@ PalBool indirectDrawTest() palDestroyWindow(window); palShutdownVideo(); palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index e730c1ae..995cfa82 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -45,9 +45,8 @@ PalBool meshTest() PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); @@ -55,27 +54,25 @@ PalBool meshTest() result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } PalWindowCreateInfo windowCreateInfo = {0}; windowCreateInfo.height = WINDOW_HEIGHT; windowCreateInfo.width = WINDOW_WIDTH; - windowCreateInfo.show = true; + windowCreateInfo.show = PAL_TRUE; windowCreateInfo.title = "Mesh Window"; - PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); - if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures videoFeatures = palGetVideoFeatures(); + if (!(videoFeatures & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } result = palCreateWindow(&windowCreateInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); @@ -90,7 +87,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get platform information: %s", error); - return false; + return PAL_FALSE; } if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { @@ -112,7 +109,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -121,12 +118,12 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (adapterCount == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %d", adapterCount); @@ -134,14 +131,14 @@ PalBool meshTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } PalAdapterCapabilities caps = {0}; @@ -154,7 +151,7 @@ PalBool meshTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } if (caps.maxGraphicsQueues == 0) { @@ -173,7 +170,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - return false; + return PAL_FALSE; } // we prefer spirv first if an adapter supports multiple shader formats @@ -199,7 +196,7 @@ PalBool meshTest() palFree(nullptr, adapters); if (!adapter) { palLog(nullptr, "Failed to find a required adapter"); - return false; + return PAL_FALSE; } // create a device @@ -213,7 +210,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); - return false; + return PAL_FALSE; } // create surface @@ -221,17 +218,17 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create surface: %s", error); - return false; + return PAL_FALSE; } // create a graphics command queue and check if its supports presenting to the surface - PalBool foundQueue = false; + PalBool foundQueue = PAL_FALSE; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create queue: %s", error); - return false; + return PAL_FALSE; } if (!palCanQueuePresent(queue, surface)) { @@ -239,14 +236,14 @@ PalBool meshTest() queue = nullptr; } else { // found a queue - foundQueue = true; + foundQueue = PAL_TRUE; break; } } if (!foundQueue) { palLog(nullptr, "Failed to find a queue that can present to the surface"); - return false; + return PAL_FALSE; } // create a swapchain with the graphics queue @@ -256,11 +253,11 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get surface capabilities: %s", error); - return false; + return PAL_FALSE; } PalSwapchainCreateInfo swapchainCreateInfo = {0}; - swapchainCreateInfo.clipped = true; + swapchainCreateInfo.clipped = PAL_TRUE; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; @@ -284,7 +281,7 @@ PalBool meshTest() swapchainCreateInfo.imageCount++; if (surfaceCaps.maxImageCount < 2) { palLog(nullptr, "Surface does not support double buffers"); - return false; + return PAL_FALSE; } } @@ -292,7 +289,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); - return false; + return PAL_FALSE; } // get all swapchain images and create image views for them @@ -302,7 +299,7 @@ PalBool meshTest() renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } PalImageInfo imageInfo; @@ -310,7 +307,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image info: %s", error); - return false; + return PAL_FALSE; } PalImageViewCreateInfo imageViewCreateInfo = {0}; @@ -333,15 +330,15 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); - return false; + return PAL_FALSE; } // create render finished semaphores - result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } inFlightImages[i] = nullptr; @@ -351,23 +348,23 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); - return false; + return PAL_FALSE; } // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } - result = palCreateFence(device, true, &inFlightFences[i]); + result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } result = palAllocateCommandBuffer( @@ -379,7 +376,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; + return PAL_FALSE; } } @@ -420,13 +417,13 @@ PalBool meshTest() // read file if (!readFile(sources[i], nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to read shader file"); - return false; + return PAL_FALSE; } bytecode = palAllocate(nullptr, bytecodeSize, 0); if (!bytecode) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } readFile(sources[i], bytecode, &bytecodeSize); @@ -440,7 +437,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create shader: %s", error); - return false; + return PAL_FALSE; } palFree(nullptr, bytecode); @@ -452,7 +449,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); - return false; + return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; @@ -486,7 +483,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create graphics pipeline: %s", error); - return false; + return PAL_FALSE; } for (int i = 0; i < 2; i++) { @@ -495,7 +492,7 @@ PalBool meshTest() // main loop uint32_t currentFrame = 0; - PalBool running = true; + PalBool running = PAL_TRUE; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; @@ -509,7 +506,7 @@ PalBool meshTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -517,7 +514,7 @@ PalBool meshTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -528,7 +525,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } // get next swapchain image @@ -542,7 +539,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; + return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { @@ -550,7 +547,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -560,18 +557,18 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } else { // recreate since we dont support fence resetting palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &inFlightFences[currentFrame]); + result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -580,14 +577,14 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it renderable @@ -612,7 +609,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } PalClearValue clearValue; @@ -636,7 +633,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); - return false; + return PAL_FALSE; } // bind pipeline @@ -644,7 +641,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; + return PAL_FALSE; } // set viewport and scissors @@ -652,14 +649,14 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); - return false; + return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); - return false; + return PAL_FALSE; } // draw a single triangle with the mesh shader @@ -670,14 +667,14 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); - return false; + return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it presentable @@ -693,14 +690,14 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit command buffer @@ -714,7 +711,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // present @@ -725,7 +722,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to present swapchain: %s", error); - return false; + return PAL_FALSE; } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; @@ -735,7 +732,7 @@ PalBool meshTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for queue: %s", error); - return false; + return PAL_FALSE; } palDestroyPipeline(pipeline); @@ -766,5 +763,5 @@ PalBool meshTest() palDestroyWindow(window); palShutdownVideo(); palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index b248b7a1..e46b7e6c 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -53,7 +53,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -62,12 +62,12 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (adapterCount == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %d", adapterCount); @@ -75,14 +75,14 @@ PalBool multiDescriptorSetTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } PalAdapterCapabilities caps = {0}; @@ -95,7 +95,7 @@ PalBool multiDescriptorSetTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } if (caps.maxComputeQueues == 0) { @@ -120,7 +120,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - return false; + return PAL_FALSE; } // we prefer spirv first if an adapter supports multiple shader formats @@ -146,7 +146,7 @@ PalBool multiDescriptorSetTest() palFree(nullptr, adapters); if (!adapter) { palLog(nullptr, "Failed to find a required adapter"); - return false; + return PAL_FALSE; } // create a device @@ -154,7 +154,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); - return false; + return PAL_FALSE; } // create a compute command queue @@ -162,14 +162,14 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create queue: %s", error); - return false; + return PAL_FALSE; } result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); - return false; + return PAL_FALSE; } result = palAllocateCommandBuffer( @@ -181,7 +181,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; + return PAL_FALSE; } // create a compute shader @@ -200,13 +200,13 @@ PalBool multiDescriptorSetTest() // read file if (!readFile(source, nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to read shader file"); - return false; + return PAL_FALSE; } bytecode = palAllocate(nullptr, bytecodeSize, 0); if (!bytecode) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } readFile(source, bytecode, &bytecodeSize); @@ -224,7 +224,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create compute shader: %s", error); - return false; + return PAL_FALSE; } palFree(nullptr, bytecode); @@ -241,7 +241,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create buffer: %s", error); - return false; + return PAL_FALSE; } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_DST; @@ -249,7 +249,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create buffer: %s", error); - return false; + return PAL_FALSE; } // get buffer memory requirement and allocate memory @@ -260,14 +260,14 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palGetBufferMemoryRequirements(stagingBuffers[i], &stagingMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -280,7 +280,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -293,7 +293,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } // bind memory @@ -301,14 +301,14 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(stagingBuffers[i], stagingBufferMemories[i], 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } } @@ -333,7 +333,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create descriptor set layout: %s", error); - return false; + return PAL_FALSE; } // create descriptor pool @@ -350,7 +350,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create descriptor pool: %s", error); - return false; + return PAL_FALSE; } // allocate the sets from the descriptor pool @@ -364,7 +364,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate descriptor set: %s", error); - return false; + return PAL_FALSE; } } @@ -395,7 +395,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); - return false; + return PAL_FALSE; } // push constants @@ -424,7 +424,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); - return false; + return PAL_FALSE; } // create a compute pipeline @@ -436,17 +436,17 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create compute pipeline: %s", error); - return false; + return PAL_FALSE; } palDestroyShader(shader); // create fence - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } // record commands @@ -454,7 +454,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } PushConstant pushConstant = {0}; @@ -483,7 +483,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; + return PAL_FALSE; } result = palCmdPushConstants( @@ -497,7 +497,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to push constants: %s", error); - return false; + return PAL_FALSE; } // bind descriptor sets @@ -506,7 +506,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); - return false; + return PAL_FALSE; } } @@ -532,13 +532,13 @@ PalBool multiDescriptorSetTest() PalBool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); if (!ret) { palLog(nullptr, "Failed to build work group info"); - return false; + return PAL_FALSE; } workGroupInfos = palAllocate(nullptr, sizeof(PalWorkGroupInfo) * workGroupInfoCount, 0); if (!workGroupInfos) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, workGroupInfos); @@ -556,7 +556,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to dispatch: %s", error); - return false; + return PAL_FALSE; } } palFree(nullptr, workGroupInfos); @@ -582,7 +582,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } // now we copy from the GPU buffer into the staging buffer @@ -593,7 +593,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); - return false; + return PAL_FALSE; } } @@ -601,7 +601,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit the command buffer to the GPU @@ -612,7 +612,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // wait for the fence @@ -620,7 +620,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); - return false; + return PAL_FALSE; } const char* names[3]; @@ -636,7 +636,7 @@ PalBool multiDescriptorSetTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } // write to a ppm output file @@ -680,5 +680,5 @@ PalBool multiDescriptorSetTest() palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); - return true; + return PAL_TRUE; } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index d08f7337..c800c475 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -69,7 +69,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -78,12 +78,12 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (adapterCount == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %d", adapterCount); @@ -91,14 +91,14 @@ PalBool rayTracingTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } PalAdapterCapabilities caps = {0}; @@ -111,7 +111,7 @@ PalBool rayTracingTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } // Ray tracing is generally implemented on the graphics queue @@ -136,7 +136,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - return false; + return PAL_FALSE; } // we prefer spirv first if an adapter supports multiple shader formats @@ -162,7 +162,7 @@ PalBool rayTracingTest() palFree(nullptr, adapters); if (!adapter) { palLog(nullptr, "Failed to find a required adapter"); - return false; + return PAL_FALSE; } // create a device @@ -172,7 +172,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); - return false; + return PAL_FALSE; } // create a graphics command queue @@ -180,14 +180,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create queue: %s", error); - return false; + return PAL_FALSE; } result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); - return false; + return PAL_FALSE; } result = palAllocateCommandBuffer( @@ -199,7 +199,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; + return PAL_FALSE; } // create ray tracing shaders @@ -231,13 +231,13 @@ PalBool rayTracingTest() // read file if (!readFile(source, nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to read shader file"); - return false; + return PAL_FALSE; } bytecode = palAllocate(nullptr, bytecodeSize, 0); if (!bytecode) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } readFile(source, bytecode, &bytecodeSize); @@ -251,7 +251,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create shader: %s", error); - return false; + return PAL_FALSE; } palFree(nullptr, bytecode); @@ -265,7 +265,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create buffer: %s", error); - return false; + return PAL_FALSE; } bufferCreateInfo.size = bufferBytes; @@ -275,7 +275,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create staging buffer: %s", error); - return false; + return PAL_FALSE; } // get buffer memory requirement and allocate memory @@ -286,14 +286,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } // we need to check if the memory type we want are supported @@ -309,7 +309,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -322,7 +322,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } // bind memory @@ -330,14 +330,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // create a vertex buffer to store the vertices in @@ -354,7 +354,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create vertex buffer: %s", error); - return false; + return PAL_FALSE; } // we dont create a staging buffer to copy the vertices @@ -365,7 +365,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -378,14 +378,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // copy vertices @@ -394,7 +394,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } memcpy(data, vertices, sizeof(vertices)); @@ -426,7 +426,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get blas build sizes: %s", error); - return false; + return PAL_FALSE; } // create the blas buffer and blas @@ -438,14 +438,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create blas buffer: %s", error); - return false; + return PAL_FALSE; } result = palGetBufferMemoryRequirements(blasBuffer, &bufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -458,14 +458,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(blasBuffer, blasBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } PalAccelerationStructureCreateInfo asCreateInfo = {0}; @@ -477,7 +477,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create blas: %s", error); - return false; + return PAL_FALSE; } // create instance buffer @@ -503,7 +503,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to compute instance buffer requirement: %s", error); - return false; + return PAL_FALSE; } bufferCreateInfo.size = instanceBufferSize; @@ -514,14 +514,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create instance buffer: %s", error); - return false; + return PAL_FALSE; } result = palGetBufferMemoryRequirements(instanceBuffer, &bufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -534,14 +534,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(instanceBuffer, instanceBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // copy instance struct to the buffer @@ -555,7 +555,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } // we can not use a direct memcpy for instance buffers @@ -563,7 +563,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to write instances to instance buffer: %s", error); - return false; + return PAL_FALSE; } palUnmapBufferMemory(instanceBuffer); @@ -583,7 +583,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get tlas build sizes: %s", error); - return false; + return PAL_FALSE; } // create the tlas buffer and tlas @@ -595,14 +595,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create tlas buffer: %s", error); - return false; + return PAL_FALSE; } result = palGetBufferMemoryRequirements(tlasBuffer, &bufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -615,14 +615,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(tlasBuffer, tlasBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } asCreateInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; @@ -633,7 +633,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create tlas: %s", error); - return false; + return PAL_FALSE; } // create scratch buffer @@ -645,14 +645,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create scratch buffer: %s", error); - return false; + return PAL_FALSE; } result = palGetBufferMemoryRequirements(scratchBuffer, &bufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -665,14 +665,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(scratchBuffer, scratchBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // create descriptor set layout @@ -699,7 +699,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create descriptor set layout: %s", error); - return false; + return PAL_FALSE; } // create descriptor pool @@ -719,7 +719,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create descriptor pool: %s", error); - return false; + return PAL_FALSE; } // allocate a single descriptor set from the descriptor pool @@ -728,7 +728,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate descriptor set: %s", error); - return false; + return PAL_FALSE; } // write the inital data to the descriptor set since its created empty @@ -763,7 +763,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); - return false; + return PAL_FALSE; } // create pipeline layout @@ -775,7 +775,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); - return false; + return PAL_FALSE; } // the shader group array must respect the corect layout @@ -825,7 +825,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create ray tracing pipeline: %s", error); - return false; + return PAL_FALSE; } palDestroyShader(rayTracingShader); @@ -868,15 +868,15 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create shader binding table: %s", error); - return false; + return PAL_FALSE; } // create fence - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } // record commands @@ -884,21 +884,21 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; + return PAL_FALSE; } result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); - return false; + return PAL_FALSE; } // build the blas and tlas infos @@ -913,7 +913,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to build blas: %s", error); - return false; + return PAL_FALSE; } // make sure the BLAS builds before the TLAS. We need this barrier because @@ -933,14 +933,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set memory barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdBuildAccelerationStructure(cmdBuffer, &tlasBuildInfo); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to build tlas: %s", error); - return false; + return PAL_FALSE; } newAsUsageStateInfo.shaderStageCount = 1; @@ -956,14 +956,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set memory barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to trace rays: %s", error); - return false; + return PAL_FALSE; } // set a barrier so we only read from the buffer after the shader has written to it @@ -980,7 +980,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } // now we copy from the GPU buffer into the staging buffer @@ -991,14 +991,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit the command buffer to the GPU @@ -1009,7 +1009,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // wait for the fence @@ -1017,7 +1017,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); - return false; + return PAL_FALSE; } // now our staging buffer has the contents of the GPU buffer @@ -1027,7 +1027,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } // write to a ppm output file @@ -1070,7 +1070,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update shader binding table: %s", error); - return false; + return PAL_FALSE; } // we dont need to rebuild the blas or tlas @@ -1078,11 +1078,11 @@ PalBool rayTracingTest() palDestroyFence(fence); fence = nullptr; - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } // record commands @@ -1090,21 +1090,21 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; + return PAL_FALSE; } result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); - return false; + return PAL_FALSE; } // the previous trace transitioned the buffer to transfer read @@ -1121,14 +1121,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to trace rays: %s", error); - return false; + return PAL_FALSE; } // set a barrier to transition to transfer read so we can read from it after shader has @@ -1142,7 +1142,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } // now we copy from the GPU buffer into the staging buffer @@ -1151,14 +1151,14 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit the command buffer to the GPU @@ -1168,7 +1168,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // wait for the fence @@ -1176,7 +1176,7 @@ PalBool rayTracingTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); - return false; + return PAL_FALSE; } // write to a ppm output file @@ -1231,5 +1231,5 @@ PalBool rayTracingTest() palDestroyDevice(device); palShutdownGraphics(); - return true; + return PAL_TRUE; } diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index a5cfb4ca..3ecf9c13 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -84,9 +84,8 @@ PalBool textureTest() PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); @@ -94,27 +93,25 @@ PalBool textureTest() result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } PalWindowCreateInfo windowCreateInfo = {0}; windowCreateInfo.height = WINDOW_HEIGHT; windowCreateInfo.width = WINDOW_WIDTH; - windowCreateInfo.show = true; + windowCreateInfo.show = PAL_TRUE; windowCreateInfo.title = "Texture Window"; - PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); - if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures videoFeatures = palGetVideoFeatures(); + if (!(videoFeatures & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } result = palCreateWindow(&windowCreateInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); @@ -129,7 +126,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get platform information: %s", error); - return false; + return PAL_FALSE; } if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { @@ -151,7 +148,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -160,12 +157,12 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (adapterCount == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %d", adapterCount); @@ -173,14 +170,14 @@ PalBool textureTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } PalAdapterCapabilities caps = {0}; @@ -192,7 +189,7 @@ PalBool textureTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } if (caps.maxGraphicsQueues == 0) { @@ -205,7 +202,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - return false; + return PAL_FALSE; } // we prefer spirv first if an adapter supports multiple shader formats @@ -231,7 +228,7 @@ PalBool textureTest() palFree(nullptr, adapters); if (!adapter) { palLog(nullptr, "Failed to find a required adapter"); - return false; + return PAL_FALSE; } // create a device @@ -245,7 +242,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); - return false; + return PAL_FALSE; } // create surface @@ -253,17 +250,17 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create surface: %s", error); - return false; + return PAL_FALSE; } // create a graphics command queue and check if its supports presenting to the surface - PalBool foundQueue = false; + PalBool foundQueue = PAL_FALSE; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create queue: %s", error); - return false; + return PAL_FALSE; } if (!palCanQueuePresent(queue, surface)) { @@ -271,14 +268,14 @@ PalBool textureTest() queue = nullptr; } else { // found a queue - foundQueue = true; + foundQueue = PAL_TRUE; break; } } if (!foundQueue) { palLog(nullptr, "Failed to find a queue that can present to the surface"); - return false; + return PAL_FALSE; } // create a swapchain with the graphics queue @@ -287,11 +284,11 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get surface capabilities: %s", error); - return false; + return PAL_FALSE; } PalSwapchainCreateInfo swapchainCreateInfo = {0}; - swapchainCreateInfo.clipped = true; + swapchainCreateInfo.clipped = PAL_TRUE; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; @@ -315,7 +312,7 @@ PalBool textureTest() swapchainCreateInfo.imageCount++; if (surfaceCaps.maxImageCount < 2) { palLog(nullptr, "Surface does not support double buffers"); - return false; + return PAL_FALSE; } } @@ -323,7 +320,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); - return false; + return PAL_FALSE; } // get all swapchain images and create image views for them @@ -333,7 +330,7 @@ PalBool textureTest() renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } PalImageInfo imageInfo; @@ -341,7 +338,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image info: %s", error); - return false; + return PAL_FALSE; } PalImageViewCreateInfo imageViewCreateInfo = {0}; @@ -364,15 +361,15 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); - return false; + return PAL_FALSE; } // create render finished semaphores - result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } inFlightImages[i] = nullptr; @@ -382,23 +379,23 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); - return false; + return PAL_FALSE; } // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } - result = palCreateFence(device, true, &inFlightFences[i]); + result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } result = palAllocateCommandBuffer( @@ -410,7 +407,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; + return PAL_FALSE; } } @@ -434,7 +431,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create vertex buffer: %s", error); - return false; + return PAL_FALSE; } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send @@ -442,7 +439,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create staging buffer: %s", error); - return false; + return PAL_FALSE; } // get buffer memory requirement and allocate memory @@ -453,14 +450,14 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } // we need to check if the memory type we want are supported @@ -476,7 +473,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -489,7 +486,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } // bind memory @@ -497,14 +494,14 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // map the staging buffer and upload the vertices @@ -513,18 +510,18 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } memcpy(ptr, vertices, sizeof(vertices)); palUnmapBufferMemory(stagingBuffer); PalFence* fence = nullptr; - result = palCreateFence(device, false, &fence); + result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } // we dont want to load the texture from disk so we will create a @@ -549,7 +546,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image: %s", error); - return false; + return PAL_FALSE; } // allocate memory for the image @@ -558,7 +555,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image memory requirement: %s", error); - return false; + return PAL_FALSE; } PalMemory* checkerboardMemory = nullptr; @@ -572,14 +569,14 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory: %s", error); - return false; + return PAL_FALSE; } result = palBindImageMemory(checkerboard, checkerboardMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind image memory: %s", error); - return false; + return PAL_FALSE; } // create staging buffer to transfer the data to the image @@ -604,7 +601,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to compute image copy staging buffer info: %s", error); - return false; + return PAL_FALSE; } // update our copy with the required buffer row length and buffer image height @@ -621,7 +618,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image staging buffer: %s", error); - return false; + return PAL_FALSE; } PalMemoryRequirements imageStagingBufferMemReq = {0}; @@ -629,7 +626,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image staging buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } PalMemory* imageStagingBufferMemory = nullptr; @@ -643,14 +640,14 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(imageStagingBuffer, imageStagingBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind image staging buffer memory: %s", error); - return false; + return PAL_FALSE; } // copy data @@ -664,7 +661,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } // write data to the mapped image copy staging buffer @@ -678,7 +675,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to write to image copy staging buffer: %s", error); - return false; + return PAL_FALSE; } palUnmapBufferMemory(imageStagingBuffer); @@ -691,7 +688,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } PalBufferCopyInfo copyInfo = {0}; @@ -701,7 +698,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); - return false; + return PAL_FALSE; } PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; @@ -717,7 +714,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } // copy image staging buffer to the checkerboard image @@ -743,7 +740,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdCopyBufferToImage( @@ -755,7 +752,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer to image: %s", error); - return false; + return PAL_FALSE; } // we should transition the image into a shader read state so we dont do that @@ -776,14 +773,14 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } PalCommandBufferSubmitInfo submitInfo = {0}; @@ -793,7 +790,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // now we have the checkerboard texture data in the image @@ -813,7 +810,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create checkerboard image view: %s", error); - return false; + return PAL_FALSE; } PalSampler* sampler = nullptr; @@ -824,8 +821,8 @@ PalBool textureTest() samplerCreateInfo.borderColor = PAL_BORDER_COLOR_INT_OPAQUE_BLACK; samplerCreateInfo.compareOp = PAL_COMPARE_OP_NEVER; // will not be used if its not enabled - samplerCreateInfo.enableAnisotropy = false; - samplerCreateInfo.enableCompare = false; + samplerCreateInfo.enableAnisotropy = PAL_FALSE; + samplerCreateInfo.enableCompare = PAL_FALSE; samplerCreateInfo.magFilterMode = PAL_FILTER_MODE_LINEAR; samplerCreateInfo.minFilterMode = PAL_FILTER_MODE_LINEAR; samplerCreateInfo.maxAnisotropy = 1.0f; @@ -838,7 +835,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create sampler: %s", error); - return false; + return PAL_FALSE; } // create shaders @@ -878,13 +875,13 @@ PalBool textureTest() // read file if (!readFile(sources[i], nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to read shader file"); - return false; + return PAL_FALSE; } bytecode = palAllocate(nullptr, bytecodeSize, 0); if (!bytecode) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } readFile(sources[i], bytecode, &bytecodeSize); @@ -898,7 +895,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create shader: %s", error); - return false; + return PAL_FALSE; } palFree(nullptr, bytecode); @@ -928,7 +925,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create descriptor set layout: %s", error); - return false; + return PAL_FALSE; } // create descriptor pool @@ -948,7 +945,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create descriptor pool: %s", error); - return false; + return PAL_FALSE; } // allocate a single descriptor set from the descriptor pool @@ -957,7 +954,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate descriptor set: %s", error); - return false; + return PAL_FALSE; } // write the inital data to the descriptor set since its created empty @@ -994,7 +991,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to update descriptor set: %s", error); - return false; + return PAL_FALSE; } // create pipeline layout @@ -1006,7 +1003,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); - return false; + return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; @@ -1060,7 +1057,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create graphics pipeline: %s", error); - return false; + return PAL_FALSE; } for (int i = 0; i < 2; i++) { @@ -1072,7 +1069,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); - return false; + return PAL_FALSE; } // the vertices have been copied @@ -1086,7 +1083,7 @@ PalBool textureTest() // main loop uint32_t currentFrame = 0; - PalBool running = true; + PalBool running = PAL_TRUE; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; @@ -1100,7 +1097,7 @@ PalBool textureTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -1108,7 +1105,7 @@ PalBool textureTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -1119,7 +1116,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } // get next swapchain image @@ -1133,7 +1130,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; + return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { @@ -1141,7 +1138,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -1151,18 +1148,18 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } else { // recreate since we dont support fence resetting palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &inFlightFences[currentFrame]); + result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -1171,14 +1168,14 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it renderable @@ -1203,7 +1200,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } PalClearValue clearValue; @@ -1227,7 +1224,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); - return false; + return PAL_FALSE; } // bind pipeline @@ -1235,14 +1232,14 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; + return PAL_FALSE; } result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind descriptor set: %s", error); - return false; + return PAL_FALSE; } // set viewport and scissors @@ -1250,14 +1247,14 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); - return false; + return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); - return false; + return PAL_FALSE; } // bind vertex buffer @@ -1272,21 +1269,21 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind vertex buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); - return false; + return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it presentable @@ -1302,14 +1299,14 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit command buffer @@ -1323,7 +1320,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // present @@ -1334,7 +1331,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to present swapchain: %s", error); - return false; + return PAL_FALSE; } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; @@ -1344,7 +1341,7 @@ PalBool textureTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for queue: %s", error); - return false; + return PAL_FALSE; } palDestroyPipeline(pipeline); @@ -1386,5 +1383,5 @@ PalBool textureTest() palDestroyWindow(window); palShutdownVideo(); palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 25efffda..a670ef9c 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -50,9 +50,8 @@ PalBool triangleTest() PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); @@ -60,27 +59,25 @@ PalBool triangleTest() result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } PalWindowCreateInfo windowCreateInfo = {0}; windowCreateInfo.height = WINDOW_HEIGHT; windowCreateInfo.width = WINDOW_WIDTH; - windowCreateInfo.show = true; + windowCreateInfo.show = PAL_TRUE; windowCreateInfo.title = "Triangle Window"; - PalVideoFeatures64 videoFeatures = palGetVideoFeaturesEx(); - if (!(videoFeatures & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures videoFeatures = palGetVideoFeatures(); + if (!(videoFeatures & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } result = palCreateWindow(&windowCreateInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); @@ -95,7 +92,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get platform information: %s", error); - return false; + return PAL_FALSE; } if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { @@ -117,7 +114,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize graphics: %s", error); - return false; + return PAL_FALSE; } // enumerate all available adapters @@ -126,12 +123,12 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } if (adapterCount == 0) { palLog(nullptr, "No adapters found"); - return false; + return PAL_FALSE; } palLog(nullptr, "Adapter count: %d", adapterCount); @@ -139,14 +136,14 @@ PalBool triangleTest() adapters = palAllocate(nullptr, sizeof(PalAdapter*) * adapterCount, 0); if (!adapters) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get query adapters: %s", error); - return false; + return PAL_FALSE; } PalAdapterCapabilities caps = {0}; @@ -158,7 +155,7 @@ PalBool triangleTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter capabilities: %s", error); palFree(nullptr, adapters); - return false; + return PAL_FALSE; } if (caps.maxGraphicsQueues == 0) { @@ -171,7 +168,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get adapter info: %s", error); - return false; + return PAL_FALSE; } // we prefer spirv first if an adapter supports multiple shader formats @@ -197,7 +194,7 @@ PalBool triangleTest() palFree(nullptr, adapters); if (!adapter) { palLog(nullptr, "Failed to find a required adapter"); - return false; + return PAL_FALSE; } // create a device @@ -211,7 +208,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create device: %s", error); - return false; + return PAL_FALSE; } // create surface @@ -219,17 +216,17 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create surface: %s", error); - return false; + return PAL_FALSE; } // create a graphics command queue and check if its supports presenting to the surface - PalBool foundQueue = false; + PalBool foundQueue = PAL_FALSE; for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create queue: %s", error); - return false; + return PAL_FALSE; } if (!palCanQueuePresent(queue, surface)) { @@ -237,14 +234,14 @@ PalBool triangleTest() queue = nullptr; } else { // found a queue - foundQueue = true; + foundQueue = PAL_TRUE; break; } } if (!foundQueue) { palLog(nullptr, "Failed to find a queue that can present to the surface"); - return false; + return PAL_FALSE; } // create a swapchain with the graphics queue @@ -253,11 +250,11 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get surface capabilities: %s", error); - return false; + return PAL_FALSE; } PalSwapchainCreateInfo swapchainCreateInfo = {0}; - swapchainCreateInfo.clipped = true; + swapchainCreateInfo.clipped = PAL_TRUE; swapchainCreateInfo.compositeAlpha = PAL_COMPOSITE_ALPHA_OPAQUE; swapchainCreateInfo.height = WINDOW_HEIGHT; swapchainCreateInfo.width = WINDOW_WIDTH; @@ -281,7 +278,7 @@ PalBool triangleTest() swapchainCreateInfo.imageCount++; if (surfaceCaps.maxImageCount < 2) { palLog(nullptr, "Surface does not support double buffers"); - return false; + return PAL_FALSE; } } @@ -289,7 +286,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create swapchain: %s", error); - return false; + return PAL_FALSE; } // get all swapchain images and create image views for them @@ -299,7 +296,7 @@ PalBool triangleTest() renderFinishedSemaphores = palAllocate(nullptr, sizeof(PalSemaphore*) * imageCount, 0); if (!imageViews || !inFlightImages || !renderFinishedSemaphores) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } PalImageInfo imageInfo; @@ -307,7 +304,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get image info: %s", error); - return false; + return PAL_FALSE; } PalImageViewCreateInfo imageViewCreateInfo = {0}; @@ -330,15 +327,15 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create image view: %s", error); - return false; + return PAL_FALSE; } // create render finished semaphores - result = palCreateSemaphore(device, false, &renderFinishedSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } inFlightImages[i] = nullptr; @@ -348,23 +345,23 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create command pool: %s", error); - return false; + return PAL_FALSE; } // create synchronization objects and command buffers for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { - result = palCreateSemaphore(device, false, &imageAvailableSemaphores[i]); + result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create semaphore: %s", error); - return false; + return PAL_FALSE; } - result = palCreateFence(device, true, &inFlightFences[i]); + result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } result = palAllocateCommandBuffer( @@ -376,7 +373,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate command buffer: %s", error); - return false; + return PAL_FALSE; } } @@ -397,7 +394,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create vertex buffer: %s", error); - return false; + return PAL_FALSE; } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send @@ -405,7 +402,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create staging buffer: %s", error); - return false; + return PAL_FALSE; } // get buffer memory requirement and allocate memory @@ -416,14 +413,14 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return false; + return PAL_FALSE; } // we need to check if the memory type we want are supported @@ -439,7 +436,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } result = palAllocateMemory( @@ -452,7 +449,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return false; + return PAL_FALSE; } // bind memory @@ -460,14 +457,14 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind memory: %s", error); - return false; + return PAL_FALSE; } // map the staging buffer and upload the vertices @@ -476,18 +473,18 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to map buffer memory: %s", error); - return false; + return PAL_FALSE; } memcpy(ptr, vertices, sizeof(vertices)); palUnmapBufferMemory(stagingBuffer); PalFence* tmpFence = nullptr; - result = palCreateFence(device, false, &tmpFence); + result = palCreateFence(device, PAL_FALSE, &tmpFence); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create fence: %s", error); - return false; + return PAL_FALSE; } // use the first command buffer to upload the copy @@ -498,7 +495,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } PalBufferCopyInfo copyInfo = {0}; @@ -508,7 +505,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to copy buffer: %s", error); - return false; + return PAL_FALSE; } PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; @@ -524,14 +521,14 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set buffer barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } PalCommandBufferSubmitInfo submitInfo = {0}; @@ -541,7 +538,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // create shaders @@ -581,13 +578,13 @@ PalBool triangleTest() // read file if (!readFile(sources[i], nullptr, &bytecodeSize)) { palLog(nullptr, "Failed to read shader file"); - return false; + return PAL_FALSE; } bytecode = palAllocate(nullptr, bytecodeSize, 0); if (!bytecode) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } readFile(sources[i], bytecode, &bytecodeSize); @@ -601,7 +598,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create shader: %s", error); - return false; + return PAL_FALSE; } palFree(nullptr, bytecode); @@ -613,7 +610,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create pipeline layout: %s", error); - return false; + return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; @@ -667,7 +664,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create graphics pipeline: %s", error); - return false; + return PAL_FALSE; } for (int i = 0; i < 2; i++) { @@ -679,7 +676,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for fence: %s", error); - return false; + return PAL_FALSE; } // the vertices have been copied @@ -689,7 +686,7 @@ PalBool triangleTest() // main loop uint32_t currentFrame = 0; - PalBool running = true; + PalBool running = PAL_TRUE; PalRect2D scissor = {0}; scissor.height = WINDOW_HEIGHT; @@ -703,7 +700,7 @@ PalBool triangleTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -711,7 +708,7 @@ PalBool triangleTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -722,7 +719,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } // get next swapchain image @@ -736,7 +733,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to get next swapchain image: %s", error); - return false; + return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { @@ -744,7 +741,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -754,18 +751,18 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } else { // recreate since we dont support fence resetting palDestroyFence(inFlightFences[currentFrame]); - result = palCreateFence(device, false, &inFlightFences[currentFrame]); + result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait fence: %s", error); - return false; + return PAL_FALSE; } } @@ -774,14 +771,14 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to reset command buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin command buffer: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it renderable @@ -806,7 +803,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } PalClearValue clearValue; @@ -830,7 +827,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to begin rendering: %s", error); - return false; + return PAL_FALSE; } // bind pipeline @@ -838,7 +835,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind pipeline: %s", error); - return false; + return PAL_FALSE; } // set viewport and scissors @@ -846,14 +843,14 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set viewport: %s", error); - return false; + return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set scissors: %s", error); - return false; + return PAL_FALSE; } // bind vertex buffer @@ -868,21 +865,21 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to bind vertex buffer: %s", error); - return false; + return PAL_FALSE; } result = palCmdDraw(cmdBuffers[currentFrame], 3, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to issue draw command: %s", error); - return false; + return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end rendering: %s", error); - return false; + return PAL_FALSE; } // change the state of the image view to make it presentable @@ -898,14 +895,14 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set image view barrier: %s", error); - return false; + return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to end command buffer: %s", error); - return false; + return PAL_FALSE; } // submit command buffer @@ -919,7 +916,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to submit command buffer: %s", error); - return false; + return PAL_FALSE; } // present @@ -930,7 +927,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to present swapchain: %s", error); - return false; + return PAL_FALSE; } currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; @@ -940,7 +937,7 @@ PalBool triangleTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to wait for queue: %s", error); - return false; + return PAL_FALSE; } palDestroyPipeline(pipeline); @@ -974,5 +971,5 @@ PalBool triangleTest() palDestroyWindow(window); palShutdownVideo(); palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/opengl/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c index 6f2885e2..f8a1a92b 100644 --- a/tests/opengl/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -55,16 +55,14 @@ static void* PAL_CALL eventDriverWorker(void* arg) PalEventDriverCreateInfo createInfo = {0}; result = palCreateEventDriver(&createInfo, &shared->videoEventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); + logResult(result, "Failed to create event driver"); return nullptr; } // create the opengl driver as well result = palCreateEventDriver(&createInfo, &shared->openglEventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); + logResult(result, "Failed to create event driver"); return nullptr; } @@ -77,7 +75,7 @@ static void* PAL_CALL eventDriverWorker(void* arg) palSetEventDispatchMode(shared->videoEventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // we are done - shared->driverCreated = true; + shared->driverCreated = PAL_TRUE; return nullptr; } @@ -183,7 +181,7 @@ PalBool multiThreadOpenGlTest() shared = palAllocate(nullptr, sizeof(SharedState), 0); if (!shared) { palLog(nullptr, "Failed to allocate shared state"); - return false; + return PAL_FALSE; } // create a thread that creates two event drivers @@ -194,7 +192,7 @@ PalBool multiThreadOpenGlTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create thread: %s", error); - return false; + return PAL_FALSE; } // check to see if the event driver thread is done creating the drivers @@ -212,9 +210,8 @@ PalBool multiThreadOpenGlTest() // be valid till the video system is shutdown result = palInitVideo(nullptr, shared->videoEventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // get the instance or display handle and pass it to the opengl system @@ -227,7 +224,7 @@ PalBool multiThreadOpenGlTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize opengl: %s", error); - return false; + return PAL_FALSE; } // get all FBConfigs and select one @@ -236,19 +233,19 @@ PalBool multiThreadOpenGlTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to query GL FBConfigs: %s", error); - return false; + return PAL_FALSE; } if (fbCount == 0) { palLog(nullptr, "No supported FBConfig found"); - return false; + return PAL_FALSE; } PalGLFBConfig* fbConfigs = nullptr; fbConfigs = palAllocate(nullptr, sizeof(PalGLFBConfig) * fbCount, 0); if (!fbConfigs) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } result = palEnumerateGLFBConfigs(nullptr, &fbCount, fbConfigs); @@ -256,7 +253,7 @@ PalBool multiThreadOpenGlTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to query GL FBConfigs: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } // we get our desired FBConfig @@ -269,9 +266,9 @@ PalBool multiThreadOpenGlTest() desired.depthBits = 24; desired.stencilBits = 8; desired.samples = 2; - desired.stereo = false; // not widely supported - desired.sRGB = true; - desired.doubleBuffer = true; + desired.stereo = PAL_FALSE; // not widely supported + desired.sRGB = PAL_TRUE; + desired.doubleBuffer = PAL_TRUE; const PalGLFBConfig* closest = nullptr; closest = palGetClosestGLFBConfig(fbConfigs, fbCount, &desired); @@ -282,7 +279,7 @@ PalBool multiThreadOpenGlTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set FBConfig: %s", error); - return false; + return PAL_FALSE; } // if not using pal_opengl with pal_video @@ -309,13 +306,13 @@ PalBool multiThreadOpenGlTest() PalWindowCreateInfo windowCreateInfo = {0}; windowCreateInfo.width = 640; windowCreateInfo.height = 480; - windowCreateInfo.show = true; + windowCreateInfo.show = PAL_TRUE; windowCreateInfo.style = PAL_WINDOW_STYLE_RESIZABLE; windowCreateInfo.title = "Multi Thread OpenGL Window"; // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { // if we dont support, we need to create a borderless window // and create the decorations ourselves windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; @@ -323,20 +320,22 @@ PalBool multiThreadOpenGlTest() result = palCreateWindow(&windowCreateInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // GL context needs to be created on the main thread const PalGLInfo* glInfo = palGetGLInfo(); // get the native handles of our created window - PalWindowHandleInfoEx winHandle = {0}; - winHandle = palGetWindowHandleInfoEx(window); + PalWindowHandleInfo winHandle = {0}; + result = palGetWindowHandleInfo(window, &winHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } shared->window.display = winHandle.nativeDisplay; - // On Wayland the window is the wl_egl_window if (winHandle.nativeHandle3) { // the window has a valid wl_egl_window @@ -347,7 +346,7 @@ PalBool multiThreadOpenGlTest() } PalGLContextCreateInfo contextCreateInfo = {0}; - contextCreateInfo.debug = true; + contextCreateInfo.debug = PAL_TRUE; contextCreateInfo.fbConfig = closest; contextCreateInfo.major = glInfo->major; contextCreateInfo.minor = glInfo->minor; @@ -356,10 +355,10 @@ PalBool multiThreadOpenGlTest() // we dont want to get into GL pipeline for this example // so we request a Compatibility profile if supported // NOTE: is its not supported, no triangle would be displayed - shared->fixedPipeline = false; + shared->fixedPipeline = PAL_FALSE; if (glInfo->extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE) { contextCreateInfo.profile = PAL_GL_PROFILE_COMPATIBILITY; - shared->fixedPipeline = true; + shared->fixedPipeline = PAL_TRUE; } if (!shared->fixedPipeline) { @@ -371,10 +370,10 @@ PalBool multiThreadOpenGlTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to create opengl context: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } - shared->running = true; + shared->running = PAL_TRUE; // we create a renderer thread for opengl // we dont wait for the renderer thread since it has its own while loop @@ -387,7 +386,7 @@ PalBool multiThreadOpenGlTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to create thread: %s", error); - return false; + return PAL_FALSE; } // we run the video while loop here @@ -399,7 +398,7 @@ PalBool multiThreadOpenGlTest() while (palPollEvent(shared->videoEventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - shared->running = false; + shared->running = PAL_FALSE; break; } @@ -407,7 +406,7 @@ PalBool multiThreadOpenGlTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - shared->running = false; + shared->running = PAL_FALSE; } break; } @@ -439,5 +438,5 @@ PalBool multiThreadOpenGlTest() palDestroyEventDriver(shared->openglEventDriver); palFree(nullptr, fbConfigs); - return true; + return PAL_TRUE; } diff --git a/tests/opengl/opengl_context_test.c b/tests/opengl/opengl_context_test.c index 585b0e13..8247186c 100644 --- a/tests/opengl/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -30,9 +30,8 @@ PalBool openglContextTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // initialize the video system. We pass the event driver to recieve video @@ -40,9 +39,8 @@ PalBool openglContextTest() // be valid till the video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // get the instance or display handle and pass it to the opengl system @@ -54,7 +52,7 @@ PalBool openglContextTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize opengl: %s", error); - return false; + return PAL_FALSE; } PalWindow* window = nullptr; @@ -62,7 +60,7 @@ PalBool openglContextTest() PalWindowCreateInfo createInfo = {0}; PalGLContextCreateInfo contextCreateInfo = {0}; int32_t fbCount = 0; - PalBool running = false; + PalBool running = PAL_FALSE; // enumerate supported opengl framebuffer configs // glWindow must be nullptr @@ -70,20 +68,20 @@ PalBool openglContextTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to query GL FBConfigs: %s", error); - return false; + return PAL_FALSE; } palLog(nullptr, "GL FBConfig count: %d", fbCount); if (fbCount == 0) { palLog(nullptr, "No supported FBConfig found"); - return false; + return PAL_FALSE; } PalGLFBConfig* fbConfigs = nullptr; fbConfigs = palAllocate(nullptr, sizeof(PalGLFBConfig) * fbCount, 0); if (!fbConfigs) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } // enumerate supported opengl framebuffer configs @@ -93,7 +91,7 @@ PalBool openglContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to query GL FBConfigs: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } // we desire a FB config and see what is closest the driver will give us @@ -107,9 +105,9 @@ PalBool openglContextTest() desired.stencilBits = 8; desired.samples = 2; - desired.stereo = false; // not widely supported - desired.sRGB = true; - desired.doubleBuffer = true; + desired.stereo = PAL_FALSE; // not widely supported + desired.sRGB = PAL_TRUE; + desired.doubleBuffer = PAL_TRUE; // get the closest const PalGLFBConfig* closest = nullptr; @@ -143,7 +141,7 @@ PalBool openglContextTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set GL FBConfig: %s", error); - return false; + return PAL_FALSE; } // if not using pal_opengl with pal_video @@ -168,13 +166,13 @@ PalBool openglContextTest() createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.style = PAL_WINDOW_STYLE_RESIZABLE; createInfo.title = "Opengl Context Window"; // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { // if we dont support, we need to create a borderless window // and create the decorations ourselves createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; @@ -183,9 +181,8 @@ PalBool openglContextTest() // create the window with the create info struct result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // we set window close to poll @@ -195,8 +192,12 @@ PalBool openglContextTest() // get window handle. You can use any window from any library // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it - PalWindowHandleInfoEx winHandle = {0}; - winHandle = palGetWindowHandleInfoEx(window); + PalWindowHandleInfo winHandle = {0}; + result = palGetWindowHandleInfo(window, &winHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } // PalGLWindow is just a struct to hold native handles PalGLWindow glWindow = {0}; @@ -215,11 +216,11 @@ PalBool openglContextTest() const PalGLInfo* info = palGetGLInfo(); // fill the context create info with the closest FBConfig - contextCreateInfo.debug = true; // debug context + contextCreateInfo.debug = PAL_TRUE; // debug context contextCreateInfo.fbConfig = closest; // we use the closest to what we want contextCreateInfo.major = info->major; // context major contextCreateInfo.minor = info->minor; // context minor - contextCreateInfo.noError = false; // check PAL_GL_EXTENSION_NO_ERROR + contextCreateInfo.noError = PAL_FALSE; // check PAL_GL_EXTENSION_NO_ERROR // check PAL_GL_EXTENSION_FLUSH_CONTROL contextCreateInfo.release = PAL_GL_RELEASE_BEHAVIOR_NONE; @@ -231,7 +232,7 @@ PalBool openglContextTest() contextCreateInfo.window = &glWindow; if (info->extensions & PAL_GL_EXTENSION_CREATE_CONTEXT) { - contextCreateInfo.forward = true; + contextCreateInfo.forward = PAL_TRUE; } if (info->extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE) { @@ -244,7 +245,7 @@ PalBool openglContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to create opengl context: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } // make the context current and optionally set vsync if supported @@ -253,7 +254,7 @@ PalBool openglContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to make opengl context current: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } if (info->extensions & PAL_GL_EXTENSION_SWAP_CONTROL) { @@ -270,7 +271,7 @@ PalBool openglContextTest() // set clear color glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - running = true; + running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -279,7 +280,7 @@ PalBool openglContextTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -287,7 +288,7 @@ PalBool openglContextTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -303,7 +304,7 @@ PalBool openglContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to swap buffers: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } } @@ -325,5 +326,5 @@ PalBool openglContextTest() // free the framebuffer configs palFree(nullptr, fbConfigs); - return true; + return PAL_TRUE; } diff --git a/tests/opengl/opengl_fbconfig_test.c b/tests/opengl/opengl_fbconfig_test.c index 27f4b0eb..7076f7ad 100644 --- a/tests/opengl/opengl_fbconfig_test.c +++ b/tests/opengl/opengl_fbconfig_test.c @@ -10,9 +10,8 @@ PalBool openglFBConfigTest() // initialize the video system and create a window PalResult result = palInitVideo(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // get the instance or display handle and pass it to the opengl system @@ -24,7 +23,7 @@ PalBool openglFBConfigTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize opengl: %s", error); - return false; + return PAL_FALSE; } // enumerate supported opengl framebuffer configs @@ -33,20 +32,20 @@ PalBool openglFBConfigTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to query GL FBConfigs: %s", error); - return false; + return PAL_FALSE; } palLog(nullptr, "GL FBConfig count: %d", fbCount); if (fbCount == 0) { palLog(nullptr, "No supported FBConfig found"); - return false; + return PAL_FALSE; } PalGLFBConfig* fbConfigs = nullptr; fbConfigs = palAllocate(nullptr, sizeof(PalGLFBConfig) * fbCount, 0); if (!fbConfigs) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } // enumerate supported opengl framebuffer configs @@ -55,7 +54,7 @@ PalBool openglFBConfigTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to query GL FBConfigs: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } // log configs @@ -91,9 +90,9 @@ PalBool openglFBConfigTest() desired.stencilBits = 8; desired.samples = 2; - desired.stereo = false; // not widely supported - desired.sRGB = true; - desired.doubleBuffer = true; + desired.stereo = PAL_FALSE; // not widely supported + desired.sRGB = PAL_TRUE; + desired.doubleBuffer = PAL_TRUE; // get the closest const PalGLFBConfig* closest = nullptr; @@ -138,5 +137,5 @@ PalBool openglFBConfigTest() // free the framebuffer configs palFree(nullptr, fbConfigs); - return true; + return PAL_TRUE; } diff --git a/tests/opengl/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c index fa244f24..523d9e0e 100644 --- a/tests/opengl/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -30,9 +30,8 @@ PalBool openglMultiContextTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // initialize the video system. We pass the event driver to recieve video @@ -40,9 +39,8 @@ PalBool openglMultiContextTest() // be valid till the video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // get the instance or display handle and pass it to the opengl system @@ -54,7 +52,7 @@ PalBool openglMultiContextTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize opengl: %s", error); - return false; + return PAL_FALSE; } PalWindow* window = nullptr; @@ -62,7 +60,7 @@ PalBool openglMultiContextTest() PalWindowCreateInfo createInfo = {0}; PalGLContextCreateInfo contextCreateInfo = {0}; int32_t fbCount = 0; - PalBool running = false; + PalBool running = PAL_FALSE; // enumerate supported opengl framebuffer configs // glWindow must be nullptr @@ -70,20 +68,20 @@ PalBool openglMultiContextTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to query GL FBConfigs: %s", error); - return false; + return PAL_FALSE; } palLog(nullptr, "GL FBConfig count: %d", fbCount); if (fbCount == 0) { palLog(nullptr, "No supported FBConfig found"); - return false; + return PAL_FALSE; } PalGLFBConfig* fbConfigs = nullptr; fbConfigs = palAllocate(nullptr, sizeof(PalGLFBConfig) * fbCount, 0); if (!fbConfigs) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } // enumerate supported opengl framebuffer configs @@ -93,7 +91,7 @@ PalBool openglMultiContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to query GL FBConfigs: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } // we desire a FB config and see what is closest the driver will give us @@ -107,9 +105,9 @@ PalBool openglMultiContextTest() desired.stencilBits = 8; desired.samples = 2; - desired.stereo = false; // not widely supported - desired.sRGB = true; - desired.doubleBuffer = true; + desired.stereo = PAL_FALSE; // not widely supported + desired.sRGB = PAL_TRUE; + desired.doubleBuffer = PAL_TRUE; // get the closest const PalGLFBConfig* closest = nullptr; @@ -143,7 +141,7 @@ PalBool openglMultiContextTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set GL FBConfig: %s", error); - return false; + return PAL_FALSE; } // if not using pal_opengl with pal_video @@ -168,13 +166,13 @@ PalBool openglMultiContextTest() createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.style = PAL_WINDOW_STYLE_RESIZABLE; createInfo.title = "Opengl Multi Context Window"; // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { // if we dont support, we need to create a borderless window // and create the decorations ourselves createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; @@ -183,9 +181,8 @@ PalBool openglMultiContextTest() // create the window with the create info struct result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // we set window close to poll @@ -195,8 +192,12 @@ PalBool openglMultiContextTest() // get window handle. You can use any window from any library // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it - PalWindowHandleInfoEx winHandle = {0}; - winHandle = palGetWindowHandleInfoEx(window); + PalWindowHandleInfo winHandle = {0}; + result = palGetWindowHandleInfo(window, &winHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } // PalGLWindow is just a struct to hold native handles PalGLWindow glWindow = {0}; @@ -215,11 +216,11 @@ PalBool openglMultiContextTest() const PalGLInfo* info = palGetGLInfo(); // fill the context create info with the closest FBConfig - contextCreateInfo.debug = true; // debug context + contextCreateInfo.debug = PAL_TRUE; // debug context contextCreateInfo.fbConfig = closest; // we use the closest to what we want contextCreateInfo.major = info->major; // context major contextCreateInfo.minor = info->minor; // context minor - contextCreateInfo.noError = false; // check PAL_GL_EXTENSION_NO_ERROR + contextCreateInfo.noError = PAL_FALSE; // check PAL_GL_EXTENSION_NO_ERROR // check PAL_GL_EXTENSION_FLUSH_CONTROL contextCreateInfo.release = PAL_GL_RELEASE_BEHAVIOR_NONE; @@ -231,7 +232,7 @@ PalBool openglMultiContextTest() contextCreateInfo.window = &glWindow; if (info->extensions & PAL_GL_EXTENSION_CREATE_CONTEXT) { - contextCreateInfo.forward = true; + contextCreateInfo.forward = PAL_TRUE; } if (info->extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE) { @@ -244,7 +245,7 @@ PalBool openglMultiContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to create opengl context: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } // make the context current and optionally set vsync if supported @@ -253,7 +254,7 @@ PalBool openglMultiContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to make opengl context current: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } if (info->extensions & PAL_GL_EXTENSION_SWAP_CONTROL) { @@ -270,7 +271,7 @@ PalBool openglMultiContextTest() // set clear color glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - running = true; + running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -279,7 +280,7 @@ PalBool openglMultiContextTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -287,7 +288,7 @@ PalBool openglMultiContextTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -303,7 +304,7 @@ PalBool openglMultiContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to swap buffers: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } } @@ -318,7 +319,7 @@ PalBool openglMultiContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to create opengl context: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } // make the context current on this thread @@ -327,11 +328,11 @@ PalBool openglMultiContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to make opengl context current: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } glClearColor(.2f, .6f, .6f, 1.0f); - running = true; + running = PAL_TRUE; while (running) { palUpdateVideo(); @@ -339,7 +340,7 @@ PalBool openglMultiContextTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -347,7 +348,7 @@ PalBool openglMultiContextTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -360,7 +361,7 @@ PalBool openglMultiContextTest() const char* error = palFormatResult(result); palLog(nullptr, "Failed to swap buffers: %s", error); palFree(nullptr, fbConfigs); - return false; + return PAL_FALSE; } } @@ -382,5 +383,5 @@ PalBool openglMultiContextTest() // free the framebuffer configs palFree(nullptr, fbConfigs); - return true; + return PAL_TRUE; } diff --git a/tests/opengl/opengl_test.c b/tests/opengl/opengl_test.c index fc3a5755..2db36be6 100644 --- a/tests/opengl/opengl_test.c +++ b/tests/opengl/opengl_test.c @@ -8,9 +8,8 @@ PalBool openglTest() // initialize the video system and create a window PalResult result = palInitVideo(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // get the instance or display handle and pass it to the opengl system @@ -22,7 +21,7 @@ PalBool openglTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to initialize opengl: %s", error); - return false; + return PAL_FALSE; } // get the icd info. max version, graphics driver etc @@ -83,5 +82,5 @@ PalBool openglTest() // shutdown the video system palShutdownVideo(); - return true; + return PAL_TRUE; } diff --git a/tests/video/attach_window_test.c b/tests/video/attach_window_test.c index 0a586773..ff1ded7e 100644 --- a/tests/video/attach_window_test.c +++ b/tests/video/attach_window_test.c @@ -219,9 +219,8 @@ PalBool attachWindowTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // initialize the video system. We pass the event driver to recieve video @@ -229,18 +228,17 @@ PalBool attachWindowTest() // be valid till the video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // check for support - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_FOREIGN_WINDOWS)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_FOREIGN_WINDOWS)) { palLog(nullptr, "Attaching and detaching foreign windows feature not supported"); palDestroyEventDriver(eventDriver); palShutdownVideo(); - return false; + return PAL_FALSE; } // we are interested in move and close events @@ -259,7 +257,7 @@ PalBool attachWindowTest() void* platformWindow = createPlatformWindow(); if (!platformWindow) { palLog(nullptr, "Failed to create platform window"); - return false; + return PAL_FALSE; } // attach the created window to PAL video system @@ -269,22 +267,20 @@ PalBool attachWindowTest() PalWindow* myWindow = nullptr; result = palAttachWindow(platformWindow, &myWindow); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to attach window: %s", error); - return false; + logResult(result, "Failed to attach window"); + return PAL_FALSE; } // now that the window is attached, we can use PAL video API // to manager it result = palSetWindowTitle(myWindow, WINDOW_TITLE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to attach window: %s", error); - return false; + logResult(result, "Failed to set window title"); + return PAL_FALSE; } - PalBool running = true; - PalBool detached = false; + PalBool running = PAL_TRUE; + PalBool detached = PAL_FALSE; int32_t counter = 0; while (running) { // update the video system to push video events @@ -297,7 +293,7 @@ PalBool attachWindowTest() // we check if its really our attached window PalWindow* window = palUnpackPointer(event.data2); if (window == myWindow) { - running = false; + running = PAL_FALSE; } break; } @@ -314,7 +310,7 @@ PalBool attachWindowTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -330,7 +326,7 @@ PalBool attachWindowTest() palDetachWindow(myWindow, nullptr); palLog(nullptr, "window detached"); palLog(nullptr, "not recieving events anymore"); - detached = true; + detached = PAL_TRUE; counter = 0; } break; @@ -347,7 +343,7 @@ PalBool attachWindowTest() palLog(nullptr, "window attached"); palLog(nullptr, "recieving events"); counter = 0; // reset it - detached = false; + detached = PAL_FALSE; } } @@ -355,9 +351,8 @@ PalBool attachWindowTest() // myPlatformWindow will be equal our platformWindow result = palDetachWindow(myWindow, &myPlatformWindow); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to attach window: %s", error); - return false; + logResult(result, "Failed to detach window"); + return PAL_FALSE; } // We need to destroy the platform window before we shutdown @@ -368,5 +363,5 @@ PalBool attachWindowTest() palShutdownVideo(); palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/video/char_event_test.c b/tests/video/char_event_test.c index 5c1d023b..f99565e4 100644 --- a/tests/video/char_event_test.c +++ b/tests/video/char_event_test.c @@ -17,9 +17,8 @@ PalBool charEventTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // initialize the video system. We pass the event driver to recieve video @@ -27,21 +26,20 @@ PalBool charEventTest() // be valid till the video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // fill the create info struct createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.title = "Character Window"; // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { // if we dont support, we need to create a borderless window // and create the decorations ourselves createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; @@ -50,9 +48,8 @@ PalBool charEventTest() // create the window with the create info struct result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // we only neeed PAL_EVENT_KEYCHAR and PAL_EVENT_WINDOW_CLOSE @@ -60,7 +57,7 @@ PalBool charEventTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYCHAR, PAL_DISPATCH_POLL); - PalBool running = true; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -69,7 +66,7 @@ PalBool charEventTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -94,7 +91,7 @@ PalBool charEventTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -113,5 +110,5 @@ PalBool charEventTest() // destroy the event driver palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/video/cursor_test.c b/tests/video/cursor_test.c index cce0f4e3..fd64a29d 100644 --- a/tests/video/cursor_test.c +++ b/tests/video/cursor_test.c @@ -11,7 +11,7 @@ PalBool cursorTest() PalCursor* cursor = nullptr; PalWindowCreateInfo createInfo = {0}; PalCursorCreateInfo cursorCreateInfo = {0}; - PalBool running = false; + PalBool running = PAL_FALSE; // event driver PalEventDriver* eventDriver = nullptr; @@ -26,9 +26,8 @@ PalBool cursorTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // initialize the video system. We pass the event driver to recieve video @@ -36,18 +35,17 @@ PalBool cursorTest() // video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // check for support - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR)) { palLog(nullptr, "Seting cursors feature not supported"); palDestroyEventDriver(eventDriver); palShutdownVideo(); - return false; + return PAL_FALSE; } // simple checkerboard RGBA pixel buffer @@ -81,21 +79,20 @@ PalBool cursorTest() result = palCreateCursor(&cursorCreateInfo, &cursor); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window cursor: %s", error); - return false; + logResult(result, "Failed to create window cursor"); + return PAL_FALSE; } // fill the create info struct createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.style = PAL_WINDOW_STYLE_RESIZABLE; createInfo.title = "Cursor Window"; // check if we support decorated windows (title bar, close etc) - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + if (!(features & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { // if we dont support, we need to create a borderless window // and create the decorations ourselves createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; @@ -104,9 +101,8 @@ PalBool cursorTest() // create the window with the create info struct result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // set the dispatch mode for window close event to recieve it @@ -118,7 +114,7 @@ PalBool cursorTest() // set the cursor palSetWindowCursor(window, cursor); - running = true; + running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -127,7 +123,7 @@ PalBool cursorTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -135,7 +131,7 @@ PalBool cursorTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -155,5 +151,5 @@ PalBool cursorTest() // destroy the event driver palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index 0fb41381..2fbfeb88 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -679,7 +679,7 @@ void drawText( } } -static PalWindowHandleInfoEx s_WinHandle; +static PalWindowHandleInfo s_WinHandle; static void createDecoration() { @@ -842,7 +842,7 @@ PalBool customDecorationTest() if (!s_Display) { // not on wayland palLog(nullptr, "Not on wayland platform"); - return false; + return PAL_FALSE; } PalResult result; @@ -854,9 +854,8 @@ PalBool customDecorationTest() result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); @@ -878,32 +877,35 @@ PalBool customDecorationTest() // be valid till the video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } PalWindow* window = nullptr; PalWindowCreateInfo createInfo = {0}; createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.style = PAL_WINDOW_STYLE_BORDERLESS; createInfo.title = WINDOW_TITLE; result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // get native handles - s_WinHandle = palGetWindowHandleInfoEx(window); + result = palGetWindowHandleInfo(window, &s_WinHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } + s_Decoration.driver = eventDriver; createDecoration(); - PalBool running = true; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -912,7 +914,7 @@ PalBool customDecorationTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -920,7 +922,7 @@ PalBool customDecorationTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -952,14 +954,14 @@ PalBool customDecorationTest() closeDisplayWayland(); - return true; + return PAL_TRUE; } #else #include "tests.h" PalBool customDecorationTest() { - return false; + return PAL_FALSE; } #endif // __linux__ diff --git a/tests/video/icon_test.c b/tests/video/icon_test.c index 45a1eb50..911d1fe1 100644 --- a/tests/video/icon_test.c +++ b/tests/video/icon_test.c @@ -11,7 +11,7 @@ PalBool iconTest() PalIcon* icon = nullptr; PalWindowCreateInfo createInfo = {0}; PalIconCreateInfo iconCreateInfo = {0}; - PalBool running = false; + PalBool running = PAL_FALSE; // event driver PalEventDriver* eventDriver = nullptr; @@ -26,9 +26,8 @@ PalBool iconTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // initialize the video system. We pass the event driver to recieve video @@ -36,18 +35,17 @@ PalBool iconTest() // video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // check for support - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_WINDOW_SET_ICON)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_WINDOW_SET_ICON)) { palLog(nullptr, "Setting icons feature not supported"); palDestroyEventDriver(eventDriver); palShutdownVideo(); - return false; + return PAL_FALSE; } // simple checkerboard RGBA pixel buffer @@ -79,25 +77,23 @@ PalBool iconTest() result = palCreateIcon(&iconCreateInfo, &icon); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window icon: %s", error); - return false; + logResult(result, "Failed to create window icon"); + return PAL_FALSE; } // fill the create info struct createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.style = PAL_WINDOW_STYLE_RESIZABLE; createInfo.title = "Icon Window"; // create the window with the create info struct result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // set the dispatch mode for window close event to recieve it @@ -109,12 +105,11 @@ PalBool iconTest() // set the icon result = palSetWindowIcon(window, icon); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set window icon: %s", error); - return false; + logResult(result, "Failed to set window icon"); + return PAL_FALSE; } - running = true; + running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -123,7 +118,7 @@ PalBool iconTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -131,7 +126,7 @@ PalBool iconTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -151,5 +146,5 @@ PalBool iconTest() // destroy the event driver palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/video/input_window_test.c b/tests/video/input_window_test.c index 56862714..c6175639 100644 --- a/tests/video/input_window_test.c +++ b/tests/video/input_window_test.c @@ -272,7 +272,7 @@ static const char* dispatchString = "Poll Mode"; static const char* dispatchString = "Callback Mode"; #endif // DISPATCH_MODE_POLL -static PalBool s_Running = false; +static PalBool s_Running = PAL_FALSE; // inline helpers static inline void onKeydown(const PalEvent* event) @@ -287,7 +287,7 @@ static inline void onKeydown(const PalEvent* event) palLog(nullptr, "%s: Key pressed: (%s, %s)", dispatchString, keyName, scancodeName); if (keycode == PAL_KEYCODE_ESCAPE) { - s_Running = false; + s_Running = PAL_FALSE; } } @@ -347,24 +347,18 @@ static inline void onMouseMove(const PalEvent* event) static inline void onMouseDelta(const PalEvent* event) { - int32_t dx, dy; // dx == low, dy == high - palUnpackInt32(event->data, &dx, &dy); + float dx, dy; // dx == low, dy == high + palUnpackFloat(event->data, &dx, &dy); PalWindow* window = palUnpackPointer(event->data2); - palLog(nullptr, "%s: Mouse Delta: (%d, %d)", dispatchString, dx, dy); + palLog(nullptr, "%s: Mouse Delta: (%.2f, %.2f)", dispatchString, dx, dy); } static inline void onMouseWheel(const PalEvent* event) { - int32_t dx, dy; // dx == low, dy == high - palUnpackInt32(event->data, &dx, &dy); - - // get the raw wheel delta (float) - float fdx, fdy; - palGetRawMouseWheelDelta(&fdx, &fdy); - + float dx, dy; // dx == low, dy == high + palUnpackFloat(event->data, &dx, &dy); PalWindow* window = palUnpackPointer(event->data2); - palLog(nullptr, "%s: Mouse Wheel: (%d, %d)", dispatchString, dx, dy); - palLog(nullptr, "%s: Mouse Wheel Raw: (%.2f, %.2f)", dispatchString, fdx, fdy); + palLog(nullptr, "%s: Mouse Wheel: (%.2f, %.2f)", dispatchString, dx, dy); } static void PAL_CALL onEvent( @@ -404,7 +398,7 @@ PalBool inputWindowTest() PalResult result; PalWindow* window = nullptr; PalWindowCreateInfo createInfo = {0}; - PalBool running = false; + PalBool running = PAL_FALSE; // event driver PalEventDriver* eventDriver = nullptr; @@ -419,9 +413,8 @@ PalBool inputWindowTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // initialize the video system. We pass the event driver to recieve video @@ -429,22 +422,21 @@ PalBool inputWindowTest() // be valid till the video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // fill the create info struct createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.style = PAL_WINDOW_STYLE_RESIZABLE; createInfo.title = "Input Window"; // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { // if we dont support, we need to create a borderless window // and create the decorations ourselves createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; @@ -453,9 +445,8 @@ PalBool inputWindowTest() // create the window with the create info struct result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // we set window close to poll @@ -473,7 +464,7 @@ PalBool inputWindowTest() palSetEventDispatchMode(eventDriver, e, dispatchMode); } - s_Running = true; + s_Running = PAL_TRUE; while (s_Running) { // update the video system to push video events palUpdateVideo(); @@ -482,7 +473,7 @@ PalBool inputWindowTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - s_Running = false; + s_Running = PAL_FALSE; break; } @@ -537,5 +528,5 @@ PalBool inputWindowTest() // destroy the event driver palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/video/monitor_mode_test.c b/tests/video/monitor_mode_test.c index 872e85da..04f9e483 100644 --- a/tests/video/monitor_mode_test.c +++ b/tests/video/monitor_mode_test.c @@ -11,23 +11,21 @@ PalBool monitorModeTest() // initialize the video system PalResult result = palInitVideo(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // get the number of connected monitors result = palEnumerateMonitors(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query monitors: %s", error); - return false; + logResult(result, "Failed to get query monitors"); + return PAL_FALSE; } // if count == 0, we fail if (count == 0) { palLog(nullptr, "No monitor connected"); - return false; + return PAL_FALSE; } palLog(nullptr, "Monitor Count: %d", count); @@ -37,15 +35,14 @@ PalBool monitorModeTest() monitors = palAllocate(nullptr, sizeof(PalMonitor*) * count, 0); if (!monitors) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } // get the handle of the connected monitors result = palEnumerateMonitors(&count, monitors); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query monitors: %s", error); - return false; + logResult(result, "Failed to get query monitors"); + return PAL_FALSE; } // get monitor info for every monitor and log the information @@ -53,10 +50,8 @@ PalBool monitorModeTest() PalMonitor* monitor = monitors[i]; result = palGetMonitorInfo(monitor, &info); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get monitor info: %s", error); - palFree(nullptr, monitors); - return false; + logResult(result, "Failed to get monitor info"); + return PAL_FALSE; } // log monitor name @@ -65,9 +60,8 @@ PalBool monitorModeTest() // get number of monitor modes result = palEnumerateMonitorModes(monitor, &modeCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query monitor modes: %s", error); - return false; + logResult(result, "Failed to get query monitor modes"); + return PAL_FALSE; } palLog(nullptr, "Monitor Mode Count: %d", modeCount); @@ -78,15 +72,14 @@ PalBool monitorModeTest() if (!modes) { palLog(nullptr, "Failed to allocate memory"); palFree(nullptr, monitors); - return false; + return PAL_FALSE; } // get the monitor modes result = palEnumerateMonitorModes(monitor, &modeCount, modes); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query monitor modes: %s", error); - return false; + logResult(result, "Failed to get query monitor modes"); + return PAL_FALSE; } for (int32_t i = 0; i < modeCount; i++) { @@ -105,9 +98,8 @@ PalBool monitorModeTest() PalMonitorMode current; result = palGetCurrentMonitorMode(monitor, ¤t); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get current monitor mode: %s", error); - return false; + logResult(result, "Failed to get current monitor mode"); + return PAL_FALSE; } palLog(nullptr, ""); @@ -124,5 +116,5 @@ PalBool monitorModeTest() // free monitors array palFree(nullptr, monitors); - return true; + return PAL_TRUE; } diff --git a/tests/video/monitor_test.c b/tests/video/monitor_test.c index 55e00e8e..9880f1e9 100644 --- a/tests/video/monitor_test.c +++ b/tests/video/monitor_test.c @@ -10,23 +10,21 @@ PalBool monitorTest() // initialize the video system PalResult result = palInitVideo(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // get the number of connected monitors result = palEnumerateMonitors(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query monitors: %s", error); - return false; + logResult(result, "Failed to get query monitors"); + return PAL_FALSE; } // if count == 0, we fail if (count == 0) { palLog(nullptr, "No monitor connected"); - return false; + return PAL_FALSE; } palLog(nullptr, "Monitor Count: %d", count); @@ -36,15 +34,14 @@ PalBool monitorTest() monitors = palAllocate(nullptr, sizeof(PalMonitor*) * count, 0); if (!monitors) { palLog(nullptr, "Failed to allocate memory"); - return false; + return PAL_FALSE; } // get the handle of the connected monitors result = palEnumerateMonitors(&count, monitors); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query monitors: %s", error); - return false; + logResult(result, "Failed to get query monitors"); + return PAL_FALSE; } // get monitor info for every monitor and log the information @@ -52,10 +49,8 @@ PalBool monitorTest() PalMonitor* monitor = monitors[i]; result = palGetMonitorInfo(monitor, &info); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get monitor info: %s", error); - palFree(nullptr, monitors); - return false; + logResult(result, "Failed to get monitor info"); + return PAL_FALSE; } // log monitor info @@ -101,5 +96,5 @@ PalBool monitorTest() // free monitors array palFree(nullptr, monitors); - return true; + return PAL_TRUE; } diff --git a/tests/video/native_instance_test.c b/tests/video/native_instance_test.c index e188289a..10f4028e 100644 --- a/tests/video/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -132,7 +132,7 @@ static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_dis return (struct wl_registry*)registry; } -static PalBool s_Logged = false; +static PalBool s_Logged = PAL_FALSE; static void globalHandle( void* data, struct wl_registry* registry, @@ -142,7 +142,7 @@ static void globalHandle( { if (!s_Logged) { palLog(nullptr, "Registry global handle working"); - s_Logged = true; + s_Logged = PAL_TRUE; } } @@ -153,7 +153,7 @@ static void globalRemove( { if (s_Logged) { palLog(nullptr, "Registry global remove working"); - s_Logged = false; + s_Logged = PAL_FALSE; } } @@ -161,7 +161,7 @@ static const struct wl_registry_listener s_RegistryListener = { .global = globalHandle, .global_remove = globalRemove}; -static PalBool s_OnWayland = false; +static PalBool s_OnWayland = PAL_FALSE; #endif // _WIN32 @@ -279,9 +279,9 @@ void* openInstance() const char* session = getenv("XDG_SESSION_TYPE"); if (session) { if (strcmp(session, "wayland") == 0) { - s_OnWayland = true; + s_OnWayland = PAL_TRUE; } else { - s_OnWayland = false; + s_OnWayland = PAL_FALSE; } } @@ -319,16 +319,15 @@ PalBool nativeInstanceTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // open our own display or instance void* instance = openInstance(); if (!instance) { palLog(nullptr, "Failed to open instance"); - return false; + return PAL_FALSE; } // tell the video system to use out instance rather @@ -341,9 +340,8 @@ PalBool nativeInstanceTest() // be valid till the video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } PalWindow* window = nullptr; @@ -351,13 +349,13 @@ PalBool nativeInstanceTest() createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.style = PAL_WINDOW_STYLE_RESIZABLE; createInfo.title = "Native Instance Test"; // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { // if we dont support, we need to create a borderless window // and create the decorations ourselves createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; @@ -365,16 +363,15 @@ PalBool nativeInstanceTest() result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // we set window close to poll palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - PalBool running = true; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -383,7 +380,7 @@ PalBool nativeInstanceTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -391,7 +388,7 @@ PalBool nativeInstanceTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -411,5 +408,5 @@ PalBool nativeInstanceTest() // the video system does not destroy or close the handle provided closeInstance(instance); - return true; + return PAL_TRUE; } diff --git a/tests/video/native_integration_test.c b/tests/video/native_integration_test.c index 67c10649..2572df50 100644 --- a/tests/video/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -112,7 +112,7 @@ static XFreeFn s_XFree; static Atom s_NET_WM_NAME; static Atom s_UTF8_STRING; -static PalBool s_OnWayland = false; +static PalBool s_OnWayland = PAL_FALSE; static void* s_X11Lib; static void* s_WaylandLib; @@ -121,7 +121,7 @@ static void* s_WaylandLib; static char s_TitleBuffer[32]; -void setWindowTitleX11(PalWindowHandleInfoEx* windowInfo) +void setWindowTitleX11(PalWindowHandleInfo* windowInfo) { #ifdef __linux__ // load the procs @@ -186,7 +186,7 @@ void setWindowTitleX11(PalWindowHandleInfoEx* windowInfo) #endif // __linux__ } -void getWindowTitleX11(PalWindowHandleInfoEx* windowInfo) +void getWindowTitleX11(PalWindowHandleInfo* windowInfo) { #ifdef __linux__ Display* display = (Display*)windowInfo->nativeDisplay; @@ -227,7 +227,7 @@ void getWindowTitleX11(PalWindowHandleInfoEx* windowInfo) #endif // __linux__ } -void setWindowTitleWayland(PalWindowHandleInfoEx* windowInfo) +void setWindowTitleWayland(PalWindowHandleInfo* windowInfo) { #ifdef __linux__ s_WaylandLib = dlopen("libwayland-client.so.0", RTLD_LAZY); @@ -252,7 +252,7 @@ void setWindowTitleWayland(PalWindowHandleInfoEx* windowInfo) #endif // __linux__ } -void getWindowTitleWayland(PalWindowHandleInfoEx* windowInfo) +void getWindowTitleWayland(PalWindowHandleInfo* windowInfo) { #ifdef __linux__ // wayland does not support getting window title @@ -261,7 +261,7 @@ void getWindowTitleWayland(PalWindowHandleInfoEx* windowInfo) #endif // __linux__ } -void setWindowTitleWin32(PalWindowHandleInfoEx* windowInfo) +void setWindowTitleWin32(PalWindowHandleInfo* windowInfo) { #ifdef _WIN32 const char* title = "Hello from native Win32 API"; @@ -269,14 +269,14 @@ void setWindowTitleWin32(PalWindowHandleInfoEx* windowInfo) #endif // _WIN32 } -void getWindowTitleWin32(PalWindowHandleInfoEx* windowInfo) +void getWindowTitleWin32(PalWindowHandleInfo* windowInfo) { #ifdef _WIN32 GetWindowTextA((HWND)windowInfo->nativeWindow, s_TitleBuffer, sizeof(s_TitleBuffer)); #endif // _WIN32 } -void setWindowTitle(PalWindowHandleInfoEx* windowInfo) +void setWindowTitle(PalWindowHandleInfo* windowInfo) { #ifdef _WIN32 setWindowTitleWin32(windowInfo); @@ -285,9 +285,9 @@ void setWindowTitle(PalWindowHandleInfoEx* windowInfo) const char* session = getenv("XDG_SESSION_TYPE"); if (session) { if (strcmp(session, "wayland") == 0) { - s_OnWayland = true; + s_OnWayland = PAL_TRUE; } else { - s_OnWayland = false; + s_OnWayland = PAL_FALSE; } } @@ -299,7 +299,7 @@ void setWindowTitle(PalWindowHandleInfoEx* windowInfo) #endif // _WIN32 } -void getWindowTitle(PalWindowHandleInfoEx* windowInfo) +void getWindowTitle(PalWindowHandleInfo* windowInfo) { #ifdef _WIN32 getWindowTitleWin32(windowInfo); @@ -325,9 +325,8 @@ PalBool nativeIntegrationTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // initialize the video system. We pass the event driver to recieve video @@ -335,9 +334,8 @@ PalBool nativeIntegrationTest() // be valid till the video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } PalWindow* window = nullptr; @@ -345,13 +343,13 @@ PalBool nativeIntegrationTest() createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.style = PAL_WINDOW_STYLE_RESIZABLE; createInfo.title = "Native Integration Test"; // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { // if we dont support, we need to create a borderless window // and create the decorations ourselves createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; @@ -359,9 +357,8 @@ PalBool nativeIntegrationTest() result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // we set window close to poll @@ -369,8 +366,12 @@ PalBool nativeIntegrationTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // set the window title using native APIs - PalWindowHandleInfoEx windowInfo = {0}; - windowInfo = palGetWindowHandleInfoEx(window); + PalWindowHandleInfo windowInfo = {0}; + result = palGetWindowHandleInfo(window, &windowInfo); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } palLog(nullptr, "Window title: %s", createInfo.title); palLog(nullptr, "Setting window title with native API"); @@ -391,7 +392,7 @@ PalBool nativeIntegrationTest() // using native API like wl_proxy_set_user_data, XContext and // SetWindowLongPtr(GWLP_USERDATA) can be used freely - PalBool running = true; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -400,7 +401,7 @@ PalBool nativeIntegrationTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -408,7 +409,7 @@ PalBool nativeIntegrationTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -425,5 +426,5 @@ PalBool nativeIntegrationTest() // destroy the event driver palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/video/system_cursor_test.c b/tests/video/system_cursor_test.c index 089eef65..33082c58 100644 --- a/tests/video/system_cursor_test.c +++ b/tests/video/system_cursor_test.c @@ -10,7 +10,7 @@ PalBool systemCursorTest() PalWindow* window = nullptr; PalCursor* cursor = nullptr; PalWindowCreateInfo createInfo = {0}; - PalBool running = false; + PalBool running = PAL_FALSE; // event driver PalEventDriver* eventDriver = nullptr; @@ -25,9 +25,8 @@ PalBool systemCursorTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } // initialize the video system. We pass the event driver to recieve video @@ -35,38 +34,36 @@ PalBool systemCursorTest() // video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // check for support - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR)) { palLog(nullptr, "Seting cursors feature not supported"); palDestroyEventDriver(eventDriver); palShutdownVideo(); - return false; + return PAL_FALSE; } // create system cursor result = palCreateCursorFrom(PAL_CURSOR_CROSS, &cursor); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window cursor: %s", error); - return false; + logResult(result, "Failed to create window cursor"); + return PAL_FALSE; } // fill the create info struct createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.style = PAL_WINDOW_STYLE_RESIZABLE; createInfo.title = "System Cursor Window - Cross"; // check if we support decorated windows (title bar, close etc) - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + if (!(features & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { // if we dont support, we need to create a borderless window // and create the decorations ourselves createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; @@ -75,9 +72,8 @@ PalBool systemCursorTest() // create the window with the create info struct result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } // set the dispatch mode for window close event to recieve it @@ -89,7 +85,7 @@ PalBool systemCursorTest() // set the cursor palSetWindowCursor(window, cursor); - running = true; + running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -98,7 +94,7 @@ PalBool systemCursorTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -106,7 +102,7 @@ PalBool systemCursorTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -126,5 +122,5 @@ PalBool systemCursorTest() // destroy the event driver palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } diff --git a/tests/video/video_test.c b/tests/video/video_test.c index 62c56101..6988b859 100644 --- a/tests/video/video_test.c +++ b/tests/video/video_test.c @@ -11,176 +11,175 @@ PalBool videoTest() // initialize the video system result = palInitVideo(nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // get supported features. Now uses extended function - PalVideoFeatures64 features = palGetVideoFeaturesEx(); + PalVideoFeatures features = palGetVideoFeatures(); palLog(nullptr, "Supported Video Features:"); - if (features & PAL_VIDEO_FEATURE64_HIGH_DPI) { + if (features & PAL_VIDEO_FEATURE_HIGH_DPI) { palLog(nullptr, " High DPI windows"); } - if (features & PAL_VIDEO_FEATURE64_MONITOR_SET_ORIENTATION) { + if (features & PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION) { palLog(nullptr, " Setting monitor orientation"); } - if (features & PAL_VIDEO_FEATURE64_MONITOR_GET_ORIENTATION) { + if (features & PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION) { palLog(nullptr, " Getting monitor orientation"); } - if (features & PAL_VIDEO_FEATURE64_BORDERLESS_WINDOW) { + if (features & PAL_VIDEO_FEATURE_BORDERLESS_WINDOW) { palLog(nullptr, " Borderless windows"); } - if (features & PAL_VIDEO_FEATURE64_TRANSPARENT_WINDOW) { + if (features & PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW) { palLog(nullptr, " Transparent windows"); } - if (features & PAL_VIDEO_FEATURE64_TOOL_WINDOW) { + if (features & PAL_VIDEO_FEATURE_TOOL_WINDOW) { palLog(nullptr, " Tool windows"); } - if (features & PAL_VIDEO_FEATURE64_MONITOR_SET_MODE) { + if (features & PAL_VIDEO_FEATURE_MONITOR_SET_MODE) { palLog(nullptr, " Setting monitor display mode"); } - if (features & PAL_VIDEO_FEATURE64_MONITOR_GET_MODE) { + if (features & PAL_VIDEO_FEATURE_MONITOR_GET_MODE) { palLog(nullptr, " Getting monitor display mode"); } - if (features & PAL_VIDEO_FEATURE64_MULTI_MONITORS) { + if (features & PAL_VIDEO_FEATURE_MULTI_MONITORS) { palLog(nullptr, " Multi monitors"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_SET_SIZE) { + if (features & PAL_VIDEO_FEATURE_WINDOW_SET_SIZE) { palLog(nullptr, " Setting window size"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_GET_SIZE) { + if (features & PAL_VIDEO_FEATURE_WINDOW_GET_SIZE) { palLog(nullptr, " Getting window size"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_SET_POS) { + if (features & PAL_VIDEO_FEATURE_WINDOW_SET_POS) { palLog(nullptr, " Setting window position"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_GET_POS) { + if (features & PAL_VIDEO_FEATURE_WINDOW_GET_POS) { palLog(nullptr, " Getting window position"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_SET_STATE) { + if (features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE) { palLog(nullptr, " Setting window state"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_GET_STATE) { + if (features & PAL_VIDEO_FEATURE_WINDOW_GET_STATE) { palLog(nullptr, " Getting window state"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_SET_VISIBILITY) { + if (features & PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY) { palLog(nullptr, " Setting window visibility"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_GET_VISIBILITY) { + if (features & PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY) { palLog(nullptr, " Getting window visibility"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_SET_TITLE) { + if (features & PAL_VIDEO_FEATURE_WINDOW_SET_TITLE) { palLog(nullptr, " Setting window title"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_GET_TITLE) { + if (features & PAL_VIDEO_FEATURE_WINDOW_GET_TITLE) { palLog(nullptr, " Getting window title"); } - if (features & PAL_VIDEO_FEATURE64_NO_MINIMIZEBOX) { + if (features & PAL_VIDEO_FEATURE_NO_MINIMIZEBOX) { palLog(nullptr, " No minimize box for windows"); } - if (features & PAL_VIDEO_FEATURE64_NO_MAXIMIZEBOX) { + if (features & PAL_VIDEO_FEATURE_NO_MAXIMIZEBOX) { palLog(nullptr, " No maximize box for windows"); } - if (features & PAL_VIDEO_FEATURE64_CLIP_CURSOR) { + if (features & PAL_VIDEO_FEATURE_CLIP_CURSOR) { palLog(nullptr, " Clipping cursor (mouse)"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_FLASH_CAPTION) { + if (features & PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION) { palLog(nullptr, " Window titlebar flashing"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_FLASH_TRAY) { + if (features & PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY) { palLog(nullptr, " Window icon on taskbar flashing"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_FLASH_INTERVAL) { + if (features & PAL_VIDEO_FEATURE_WINDOW_FLASH_INTERVAL) { palLog(nullptr, " Setting window flash interval"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_SET_INPUT_FOCUS) { + if (features & PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS) { palLog(nullptr, " Setting input window"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_GET_INPUT_FOCUS) { + if (features & PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS) { palLog(nullptr, " Getting input window"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_SET_STYLE) { + if (features & PAL_VIDEO_FEATURE_WINDOW_SET_STYLE) { palLog(nullptr, " Setting window style"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_GET_STYLE) { + if (features & PAL_VIDEO_FEATURE_WINDOW_GET_STYLE) { palLog(nullptr, " Getting window style"); } - if (features & PAL_VIDEO_FEATURE64_CURSOR_SET_POS) { + if (features & PAL_VIDEO_FEATURE_CURSOR_SET_POS) { palLog(nullptr, " Setting cursor position"); } - if (features & PAL_VIDEO_FEATURE64_CURSOR_GET_POS) { + if (features & PAL_VIDEO_FEATURE_CURSOR_GET_POS) { palLog(nullptr, " Getting cursor position"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_SET_ICON) { + if (features & PAL_VIDEO_FEATURE_WINDOW_SET_ICON) { palLog(nullptr, " Setting window icon"); } - if (features & PAL_VIDEO_FEATURE64_TOPMOST_WINDOW) { + if (features & PAL_VIDEO_FEATURE_TOPMOST_WINDOW) { palLog(nullptr, " Topmost windows"); } - if (features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW) { + if (features & PAL_VIDEO_FEATURE_DECORATED_WINDOW) { palLog(nullptr, " Decorated (Normal) windows"); } - if (features & PAL_VIDEO_FEATURE64_CURSOR_SET_VISIBILITY) { + if (features & PAL_VIDEO_FEATURE_CURSOR_SET_VISIBILITY) { palLog(nullptr, " Setting cursor visibility"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_GET_MONITOR) { + if (features & PAL_VIDEO_FEATURE_WINDOW_GET_MONITOR) { palLog(nullptr, " Getting window current monitor"); } - if (features & PAL_VIDEO_FEATURE64_MONITOR_GET_PRIMARY) { + if (features & PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY) { palLog(nullptr, " Getting primary monitor"); } - if (features & PAL_VIDEO_FEATURE64_FOREIGN_WINDOWS) { + if (features & PAL_VIDEO_FEATURE_FOREIGN_WINDOWS) { palLog(nullptr, " Attaching and detaching foreign windows"); } - if (features & PAL_VIDEO_FEATURE64_MONITOR_VALIDATE_MODE) { + if (features & PAL_VIDEO_FEATURE_MONITOR_VALIDATE_MODE) { palLog(nullptr, " Validate monitor display mode"); } - if (features & PAL_VIDEO_FEATURE64_WINDOW_SET_CURSOR) { + if (features & PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR) { palLog(nullptr, " Setting window cursor"); } // shutdown the video system palShutdownVideo(); - return true; + return PAL_TRUE; } diff --git a/tests/video/window_test.c b/tests/video/window_test.c index 5611737e..fe41927a 100644 --- a/tests/video/window_test.c +++ b/tests/video/window_test.c @@ -149,7 +149,7 @@ PalBool windowTest() PalResult result; PalWindow* window = nullptr; PalWindowCreateInfo createInfo = {0}; - PalBool running = false; + PalBool running = PAL_FALSE; // event driver PalEventDriver* eventDriver = nullptr; @@ -164,9 +164,8 @@ PalBool windowTest() // create the event driver result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create event driver: %s", error); - return false; + logResult(result, "Failed to create event driver"); + return PAL_FALSE; } PalDispatchMode dispatchMode = PAL_DISPATCH_NONE; @@ -196,21 +195,20 @@ PalBool windowTest() // be valid till the video system is shutdown result = palInitVideo(nullptr, eventDriver); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize video: %s", error); - return false; + logResult(result, "Failed to initialize video"); + return PAL_FALSE; } // fill the create info struct createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; - createInfo.show = true; + createInfo.show = PAL_TRUE; createInfo.style = PAL_WINDOW_STYLE_RESIZABLE; // check if we support decorated windows (title bar, close etc) - PalVideoFeatures64 features = palGetVideoFeaturesEx(); - if (!(features & PAL_VIDEO_FEATURE64_DECORATED_WINDOW)) { + PalVideoFeatures features = palGetVideoFeatures(); + if (!(features & PAL_VIDEO_FEATURE_DECORATED_WINDOW)) { // if we dont support, we need to create a borderless window // and create the decorations ourselves createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; @@ -255,9 +253,8 @@ PalBool windowTest() // create the window with the create info struct result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create window: %s", error); - return false; + logResult(result, "Failed to create window"); + return PAL_FALSE; } #if MAKE_TRANSPARENT @@ -266,12 +263,12 @@ PalBool windowTest() if (result != PAL_RESULT_SUCCESS) { const char* error = palFormatResult(result); palLog(nullptr, "Failed to set window opacity: %s", error); - return false; + return PAL_FALSE; } } #endif // MAKE_TRANSPARENT - running = true; + running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -280,7 +277,7 @@ PalBool windowTest() while (palPollEvent(eventDriver, &event)) { switch (event.type) { case PAL_EVENT_WINDOW_CLOSE: { - running = false; + running = PAL_FALSE; break; } @@ -323,7 +320,7 @@ PalBool windowTest() PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { - running = false; + running = PAL_FALSE; } break; } @@ -351,5 +348,5 @@ PalBool windowTest() // destroy the event driver palDestroyEventDriver(eventDriver); - return true; + return PAL_TRUE; } From 9dcee5380b9ba8352ed1ba75e44b024951c35995 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 17 Jun 2026 00:07:43 +0000 Subject: [PATCH 270/372] start linux video src expanding --- pal.lua | 48 +- premake5.lua | 1 + src/core/linux/pal_result_linux.c | 2 +- .../{pal_result_common.h => pal_result.h} | 7 +- src/core/win32/pal_result_win32.c | 2 +- src/thread/linux/pal_condvar_linux.c | 2 +- src/thread/linux/pal_mutex_linux.c | 2 +- src/thread/linux/pal_thread_linux.c | 2 +- ...read_common_linux.h => pal_thread_linux.h} | 8 +- src/thread/win32/pal_condvar_win32.c | 2 +- src/thread/win32/pal_mutex_win32.c | 2 +- src/thread/win32/pal_thread_win32.c | 2 +- ...read_common_win32.h => pal_thread_win32.h} | 8 +- src/video/linux/pal_video_linux.c | 1485 +++ src/video/linux/pal_video_linux.h | 345 + src/video/linux/wayland/pal_cursor_wayland.c | 187 + src/video/linux/wayland/pal_icon_wayland.c | 40 + src/video/linux/wayland/pal_monitor_wayland.c | 151 + src/video/linux/wayland/pal_video_wayland.c | 415 + src/video/linux/wayland/pal_wayland.h | 214 + src/video/linux/wayland/pal_wayland_helper.c | 15 + src/video/linux/wayland/pal_wayland_helper.h | 1888 ++++ src/video/linux/wayland/pal_window_wayland.c | 505 + src/video/linux/x11/pal_cursor_x11.c | 207 + src/video/linux/x11/pal_icon_x11.c | 91 + src/video/linux/x11/pal_monitor_x11.c | 456 + src/video/linux/x11/pal_video_x11.c | 1349 +++ src/video/linux/x11/pal_window_x11.c | 1129 +++ src/video/linux/x11/pal_x11.h | 563 ++ src/video/pal_video_linux.c | 8260 ----------------- src/video/win32/pal_cursor_win32.c | 2 +- src/video/win32/pal_icon_win32.c | 2 +- src/video/win32/pal_monitor_win32.c | 2 +- src/video/win32/pal_video_win32.c | 2 +- ...video_common_win32.h => pal_video_win32.h} | 10 +- src/video/win32/pal_window_win32.c | 2 +- tests/tests_main.c | 12 +- tests/video/custom_decoration_test.c | 46 +- tests/video/native_instance_test.c | 8 +- 39 files changed, 9134 insertions(+), 8340 deletions(-) rename src/core/{pal_result_common.h => pal_result.h} (97%) rename src/thread/linux/{pal_thread_common_linux.h => pal_thread_linux.h} (77%) rename src/thread/win32/{pal_thread_common_win32.h => pal_thread_win32.h} (82%) create mode 100644 src/video/linux/pal_video_linux.c create mode 100644 src/video/linux/pal_video_linux.h create mode 100644 src/video/linux/wayland/pal_cursor_wayland.c create mode 100644 src/video/linux/wayland/pal_icon_wayland.c create mode 100644 src/video/linux/wayland/pal_monitor_wayland.c create mode 100644 src/video/linux/wayland/pal_video_wayland.c create mode 100644 src/video/linux/wayland/pal_wayland.h create mode 100644 src/video/linux/wayland/pal_wayland_helper.c create mode 100644 src/video/linux/wayland/pal_wayland_helper.h create mode 100644 src/video/linux/wayland/pal_window_wayland.c create mode 100644 src/video/linux/x11/pal_cursor_x11.c create mode 100644 src/video/linux/x11/pal_icon_x11.c create mode 100644 src/video/linux/x11/pal_monitor_x11.c create mode 100644 src/video/linux/x11/pal_video_x11.c create mode 100644 src/video/linux/x11/pal_window_x11.c create mode 100644 src/video/linux/x11/pal_x11.h delete mode 100644 src/video/pal_video_linux.c rename src/video/win32/{pal_video_common_win32.h => pal_video_win32.h} (92%) diff --git a/pal.lua b/pal.lua index 1598df3e..8f0ff898 100644 --- a/pal.lua +++ b/pal.lua @@ -84,24 +84,7 @@ project "PAL" end if (PAL_BUILD_VIDEO_MODULE) then - filter {"system:windows", "configurations:*"} - files { - "src/video/win32/pal_cursor_win32.c", - "src/video/win32/pal_icon_win32.c", - "src/video/win32/pal_monitor_win32.c", - "src/video/win32/pal_window_win32.c", - "src/video/win32/pal_video_win32.c" - } - - filter {"system:linux", "configurations:*"} - files { - "src/video/linux/pal_cursor_linux.c", - "src/video/linux/pal_icon_linux.c", - "src/video/linux/pal_monitor_linux.c", - "src/video/linux/pal_window_linux.c", - "src/video/linux/pal_video_linux.c" - } - + if (os.target() == "linux") then -- check for wayland support. This is cross compiler local waylandPaths = { "/usr/include/wayland-client.h", @@ -145,7 +128,36 @@ project "PAL" else defines { "PAL_HAS_X11_BACKEND=0" } end + end + filter {"system:windows", "configurations:*"} + files { + "src/video/win32/pal_cursor_win32.c", + "src/video/win32/pal_icon_win32.c", + "src/video/win32/pal_monitor_win32.c", + "src/video/win32/pal_window_win32.c", + "src/video/win32/pal_video_win32.c" + } + + filter {"system:linux", "configurations:*"} + files { + -- X11 + "src/video/linux/x11/pal_cursor_x11.c", + "src/video/linux/x11/pal_icon_x11.c", + "src/video/linux/x11/pal_monitor_x11.c", + "src/video/linux/x11/pal_window_x11.c", + "src/video/linux/x11/pal_video_x11.c", + + -- Wayland + "src/video/linux/wayland/pal_cursor_wayland.c", + "src/video/linux/wayland/pal_icon_wayland.c", + "src/video/linux/wayland/pal_monitor_wayland.c", + "src/video/linux/wayland/pal_window_wayland.c", + "src/video/linux/wayland/pal_video_wayland.c", + + "src/video/linux/pal_video_linux.c" + } + filter {} end diff --git a/premake5.lua b/premake5.lua index 73732541..f742b002 100644 --- a/premake5.lua +++ b/premake5.lua @@ -53,6 +53,7 @@ local function generateVscodeProperties() end for _, define in ipairs(prj.defines or {}) do + print(define) table.insert(prjDefines, define) end end diff --git a/src/core/linux/pal_result_linux.c b/src/core/linux/pal_result_linux.c index 860126a0..44b93f2a 100644 --- a/src/core/linux/pal_result_linux.c +++ b/src/core/linux/pal_result_linux.c @@ -8,7 +8,7 @@ #ifdef __linux__ #define _POSIX_C_SOURCE 200112L #include "core/pal_format.h" -#include "core/pal_result_common.h" +#include "core/pal_result.h" #include uint16_t PAL_CALL palGetResultCode(PalResult result) diff --git a/src/core/pal_result_common.h b/src/core/pal_result.h similarity index 97% rename from src/core/pal_result_common.h rename to src/core/pal_result.h index d0d9d6cc..755bb966 100644 --- a/src/core/pal_result_common.h +++ b/src/core/pal_result.h @@ -5,10 +5,11 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifndef _PAL_RESULT_COMMON_H -#define _PAL_RESULT_COMMON_H +#ifndef _PAL_RESULT_H +#define _PAL_RESULT_H #include "pal_shared.h" +#include "pal_format.h" static inline uint16_t getResultCode(PalResult result) { @@ -149,4 +150,4 @@ static void formatResultMsg(PalResult result, char* buffer, char* msg) description); } -#endif // _PAL_RESULT_COMMON_H \ No newline at end of file +#endif // _PAL_RESULT_H \ No newline at end of file diff --git a/src/core/win32/pal_result_win32.c b/src/core/win32/pal_result_win32.c index 5935d148..579a717b 100644 --- a/src/core/win32/pal_result_win32.c +++ b/src/core/win32/pal_result_win32.c @@ -20,7 +20,7 @@ #endif // UNICODE #include "core/pal_format.h" -#include "core/pal_result_common.h" +#include "core/pal_result.h" #include #include diff --git a/src/thread/linux/pal_condvar_linux.c b/src/thread/linux/pal_condvar_linux.c index 6ea0a1f1..1066dcfa 100644 --- a/src/thread/linux/pal_condvar_linux.c +++ b/src/thread/linux/pal_condvar_linux.c @@ -6,7 +6,7 @@ */ #ifdef __linux__ -#include "pal_thread_common_linux.h" +#include "pal_thread_linux.h" #include "pal_shared.h" PalResult PAL_CALL palCreateCondVar( diff --git a/src/thread/linux/pal_mutex_linux.c b/src/thread/linux/pal_mutex_linux.c index 8af71165..6328102c 100644 --- a/src/thread/linux/pal_mutex_linux.c +++ b/src/thread/linux/pal_mutex_linux.c @@ -6,7 +6,7 @@ */ #ifdef __linux__ -#include "pal_thread_common_linux.h" +#include "pal_thread_linux.h" #include "pal_shared.h" PalResult PAL_CALL palCreateMutex( diff --git a/src/thread/linux/pal_thread_linux.c b/src/thread/linux/pal_thread_linux.c index 6b9d32dd..e500d354 100644 --- a/src/thread/linux/pal_thread_linux.c +++ b/src/thread/linux/pal_thread_linux.c @@ -7,7 +7,7 @@ #ifdef __linux__ #define _GNU_SOURCE -#include "pal_thread_common_linux.h" +#include "pal_thread_linux.h" #include "pal_shared.h" #include #include diff --git a/src/thread/linux/pal_thread_common_linux.h b/src/thread/linux/pal_thread_linux.h similarity index 77% rename from src/thread/linux/pal_thread_common_linux.h rename to src/thread/linux/pal_thread_linux.h index 64fd517a..912749d9 100644 --- a/src/thread/linux/pal_thread_common_linux.h +++ b/src/thread/linux/pal_thread_linux.h @@ -5,9 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ +#ifndef _PAL_THREAD_LINUX_H +#define _PAL_THREAD_LINUX_H #ifdef __linux__ -#ifndef _PAL_THREAD_COMMON_LINUX_H -#define _PAL_THREAD_COMMON_LINUX_H #define _POSIX_C_SOURCE 200112L #include "pal/pal_thread.h" @@ -25,5 +25,5 @@ struct PalMutex { pthread_mutex_t handle; }; -#endif // _PAL_THREAD_COMMON_LINUX_H -#endif // __linux__ \ No newline at end of file +#endif // __linux__ +#endif // _PAL_THREAD_LINUX_H \ No newline at end of file diff --git a/src/thread/win32/pal_condvar_win32.c b/src/thread/win32/pal_condvar_win32.c index 2b497359..11009abc 100644 --- a/src/thread/win32/pal_condvar_win32.c +++ b/src/thread/win32/pal_condvar_win32.c @@ -6,7 +6,7 @@ */ #ifdef _WIN32 -#include "pal_thread_common_win32.h" +#include "pal_thread_win32.h" #include "pal_shared.h" PalResult PAL_CALL palCreateCondVar( diff --git a/src/thread/win32/pal_mutex_win32.c b/src/thread/win32/pal_mutex_win32.c index 50542bae..c1432f46 100644 --- a/src/thread/win32/pal_mutex_win32.c +++ b/src/thread/win32/pal_mutex_win32.c @@ -6,7 +6,7 @@ */ #ifdef _WIN32 -#include "pal_thread_common_win32.h" +#include "pal_thread_win32.h" #include "pal_shared.h" PalResult PAL_CALL palCreateMutex( diff --git a/src/thread/win32/pal_thread_win32.c b/src/thread/win32/pal_thread_win32.c index 42f81f8a..314a96fb 100644 --- a/src/thread/win32/pal_thread_win32.c +++ b/src/thread/win32/pal_thread_win32.c @@ -6,7 +6,7 @@ */ #ifdef _WIN32 -#include "pal_thread_common_win32.h" +#include "pal_thread_win32.h" #include "pal_shared.h" typedef HRESULT(WINAPI* SetThreadDescriptionFn)( diff --git a/src/thread/win32/pal_thread_common_win32.h b/src/thread/win32/pal_thread_win32.h similarity index 82% rename from src/thread/win32/pal_thread_common_win32.h rename to src/thread/win32/pal_thread_win32.h index 5ab001ae..623257a5 100644 --- a/src/thread/win32/pal_thread_common_win32.h +++ b/src/thread/win32/pal_thread_win32.h @@ -5,9 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ +#ifndef _PAL_THREAD_WIN32_H +#define _PAL_THREAD_WIN32_H #ifdef _WIN32 -#ifndef _PAL_THREAD_COMMON_WIN32_H -#define _PAL_THREAD_COMMON_WIN32_H #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN @@ -35,5 +35,5 @@ struct PalCondVar { CONDITION_VARIABLE cv; }; -#endif // _PAL_THREAD_COMMON_WIN32_H -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 +#endif // _PAL_THREAD_WIN32_H \ No newline at end of file diff --git a/src/video/linux/pal_video_linux.c b/src/video/linux/pal_video_linux.c new file mode 100644 index 00000000..cb0b752a --- /dev/null +++ b/src/video/linux/pal_video_linux.c @@ -0,0 +1,1485 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#include "pal_video_linux.h" +#include "pal_shared.h" +#include +#include + +EGL s_Egl = {0}; +VideoLinux s_Video = {0}; +Mouse s_Mouse = {0}; +Keyboard s_Keyboard = {0}; + +#if PAL_HAS_X11_BACKEND == 1 +PalResult xInitVideo(); +void xShutdownVideo(); +void xUpdateVideo(); +PalResult xSetFBConfig(const int, PalFBConfigBackend); +PalResult xEnumerateMonitors(int32_t*, PalMonitor**); +PalResult xGetPrimaryMonitor(PalMonitor**); +PalResult xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); +PalResult xEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); +PalResult xGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult xSetMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult xValidateMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult xSetMonitorOrientation(PalMonitor*, PalOrientation); + +PalResult xCreateWindow(const PalWindowCreateInfo*, PalWindow**); +void xDestroyWindow(PalWindow*); +PalResult xMaximizeWindow(PalWindow*); +PalResult xMinimizeWindow(PalWindow*); +PalResult xRestoreWindow(PalWindow*); +PalResult xShowWindow(PalWindow*); +PalResult xHideWindow(PalWindow*); +PalResult xFlashWindow(PalWindow*, const PalFlashInfo*); +PalResult xGetWindowStyle(PalWindow*, PalWindowStyle*); +PalResult xGetWindowMonitor(PalWindow*, PalMonitor**); +PalResult xGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); +PalResult xGetWindowPos(PalWindow*, int32_t*, int32_t*); +PalResult xGetWindowSize(PalWindow*, uint32_t*, uint32_t*); +PalResult xGetWindowState(PalWindow*, PalWindowState*); +PalBool xIsWindowVisible(PalWindow*); +PalWindow* xGetFocusWindow(); +PalResult xGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); +PalResult xSetWindowOpacity(PalWindow*, float); +PalResult xSetWindowStyle(PalWindow*, PalWindowStyle); +PalResult xSetWindowTitle(PalWindow*, const char*); +PalResult xSetWindowPos(PalWindow*, int32_t, int32_t); +PalResult xSetWindowSize(PalWindow*, uint32_t, uint32_t); +PalResult xSetFocusWindow(PalWindow*); + +PalResult xCreateIcon(const PalIconCreateInfo*, PalIcon**); +void xDestroyIcon(PalIcon*); +PalResult xSetWindowIcon(PalWindow*, PalIcon*); + +PalResult xCreateCursor(const PalCursorCreateInfo*, PalCursor**); +PalResult xCreateCursorFrom(PalCursorType, PalCursor**); +void xDestroyCursor(PalCursor*); +void xShowCursor(PalBool); +PalResult xClipCursor(PalWindow*, PalBool); +PalResult xGetCursorPos(PalWindow*, int32_t*, int32_t*); +PalResult xSetCursorPos(PalWindow*, int32_t, int32_t); +PalResult xSetWindowCursor(PalWindow*, PalCursor*); + +PalResult xAttachWindow(void*, PalWindow**); +PalResult xDetachWindow(PalWindow*, void**); + +static Backend s_XBackend = { + .shutdownVideo = xShutdownVideo, + .updateVideo = xUpdateVideo, + .setFBConfig = xSetFBConfig, + .enumerateMonitors = xEnumerateMonitors, + .getMonitorInfo = xGetMonitorInfo, + .getPrimaryMonitor = xGetPrimaryMonitor, + .enumerateMonitorModes = xEnumerateMonitorModes, + .getCurrentMonitorMode = xGetCurrentMonitorMode, + .setMonitorMode = xSetMonitorMode, + .validateMonitorMode = xValidateMonitorMode, + .setMonitorOrientation = xSetMonitorOrientation, + + .createWindow = xCreateWindow, + .destroyWindow = xDestroyWindow, + .maximizeWindow = xMaximizeWindow, + .minimizeWindow = xMinimizeWindow, + .restoreWindow = xRestoreWindow, + .showWindow = xShowWindow, + .hideWindow = xHideWindow, + .flashWindow = xFlashWindow, + .getWindowStyle = xGetWindowStyle, + .getWindowMonitor = xGetWindowMonitor, + .getWindowTitle = xGetWindowTitle, + .getWindowPos = xGetWindowPos, + .getWindowSize = xGetWindowSize, + .getWindowState = xGetWindowState, + .isWindowVisible = xIsWindowVisible, + .getFocusWindow = xGetFocusWindow, + .getWindowHandleInfo = xGetWindowHandleInfo, + .setWindowOpacity = xSetWindowOpacity, + .setWindowStyle = xSetWindowStyle, + .setWindowTitle = xSetWindowTitle, + .setWindowPos = xSetWindowPos, + .setWindowSize = xSetWindowSize, + .setFocusWindow = xSetFocusWindow, + + .createIcon = xCreateIcon, + .destroyIcon = xDestroyIcon, + .setWindowIcon = xSetWindowIcon, + + .createCursor = xCreateCursor, + .createCursorFrom = xCreateCursorFrom, + .destroyCursor = xDestroyCursor, + .showCursor = xShowCursor, + .clipCursor = xClipCursor, + .getCursorPos = xGetCursorPos, + .setCursorPos = xSetCursorPos, + .setWindowCursor = xSetWindowCursor, + + .attachWindow = xAttachWindow, + .detachWindow = xDetachWindow}; + +#endif // PAL_HAS_X11_BACKEND + +#if PAL_HAS_WAYLAND_BACKEND == 1 +PalResult wlInitVideo(); +void wlShutdownVideo(); +void wlUpdateVideo(); +PalResult wlSetFBConfig(const int, PalFBConfigBackend); +PalResult wlEnumerateMonitors(int32_t*, PalMonitor**); +PalResult wlGetPrimaryMonitor(PalMonitor**); +PalResult wlGetMonitorInfo(PalMonitor*, PalMonitorInfo*); +PalResult wlEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); +PalResult wlGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult wlSetMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult wlValidateMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult wlSetMonitorOrientation(PalMonitor*, PalOrientation); + +PalResult wlCreateWindow(const PalWindowCreateInfo*, PalWindow**); +void wlDestroyWindow(PalWindow*); +PalResult wlMaximizeWindow(PalWindow*); +PalResult wlMinimizeWindow(PalWindow*); +PalResult wlRestoreWindow(PalWindow*); +PalResult wlShowWindow(PalWindow*); +PalResult wlHideWindow(PalWindow*); +PalResult wlFlashWindow(PalWindow*, const PalFlashInfo*); +PalResult wlGetWindowStyle(PalWindow*, PalWindowStyle*); +PalResult wlGetWindowMonitor(PalWindow*, PalMonitor**); +PalResult wlGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); +PalResult wlGetWindowPos(PalWindow*, int32_t*, int32_t*); +PalResult wlGetWindowSize(PalWindow*, uint32_t*, uint32_t*); +PalResult wlGetWindowState(PalWindow*, PalWindowState*); +PalBool wlIsWindowVisible(PalWindow*); +PalWindow* wlGetFocusWindow(); +PalResult wlGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); +PalResult wlSetWindowOpacity(PalWindow*, float); +PalResult wlSetWindowStyle(PalWindow*, PalWindowStyle); +PalResult wlSetWindowTitle(PalWindow*, const char*); +PalResult wlSetWindowPos(PalWindow*, int32_t, int32_t); +PalResult wlSetWindowSize(PalWindow*, uint32_t, uint32_t); +PalResult wlSetFocusWindow(PalWindow*); + +PalResult wlCreateIcon(const PalIconCreateInfo*, PalIcon**); +void wlDestroyIcon(PalIcon*); +PalResult wlSetWindowIcon(PalWindow*, PalIcon*); + +PalResult wlCreateCursor(const PalCursorCreateInfo*, PalCursor**); +PalResult wlCreateCursorFrom(PalCursorType, PalCursor**); +void wlDestroyCursor(PalCursor*); +void wlShowCursor(PalBool); +PalResult wlClipCursor(PalWindow*, PalBool); +PalResult wlGetCursorPos(PalWindow*, int32_t*, int32_t*); +PalResult wlSetCursorPos(PalWindow*, int32_t, int32_t); +PalResult wlSetWindowCursor(PalWindow*, PalCursor*); + +PalResult wlAttachWindow(void*, PalWindow**); +PalResult wlDetachWindow(PalWindow*, void**); + +static Backend s_wlBackend = { + .shutdownVideo = wlShutdownVideo, + .updateVideo = wlUpdateVideo, + .setFBConfig = wlSetFBConfig, + .enumerateMonitors = wlEnumerateMonitors, + .getMonitorInfo = wlGetMonitorInfo, + .getPrimaryMonitor = wlGetPrimaryMonitor, + .enumerateMonitorModes = wlEnumerateMonitorModes, + .getCurrentMonitorMode = wlGetCurrentMonitorMode, + .setMonitorMode = wlSetMonitorMode, + .validateMonitorMode = wlValidateMonitorMode, + .setMonitorOrientation = wlSetMonitorOrientation, + + .createWindow = wlCreateWindow, + .destroyWindow = wlDestroyWindow, + .maximizeWindow = wlMaximizeWindow, + .minimizeWindow = wlMinimizeWindow, + .restoreWindow = wlRestoreWindow, + .showWindow = wlShowWindow, + .hideWindow = wlHideWindow, + .flashWindow = wlFlashWindow, + .getWindowStyle = wlGetWindowStyle, + .getWindowMonitor = wlGetWindowMonitor, + .getWindowTitle = wlGetWindowTitle, + .getWindowPos = wlGetWindowPos, + .getWindowSize = wlGetWindowSize, + .getWindowState = wlGetWindowState, + .isWindowVisible = wlIsWindowVisible, + .getFocusWindow = wlGetFocusWindow, + .getWindowHandleInfo = wlGetWindowHandleInfo, + .setWindowOpacity = wlSetWindowOpacity, + .setWindowStyle = wlSetWindowStyle, + .setWindowTitle = wlSetWindowTitle, + .setWindowPos = wlSetWindowPos, + .setWindowSize = wlSetWindowSize, + .setFocusWindow = wlSetFocusWindow, + + .createIcon = wlCreateIcon, + .destroyIcon = wlDestroyIcon, + .setWindowIcon = wlSetWindowIcon, + + .createCursor = wlCreateCursor, + .createCursorFrom = wlCreateCursorFrom, + .destroyCursor = wlDestroyCursor, + .showCursor = wlShowCursor, + .clipCursor = wlClipCursor, + .getCursorPos = wlGetCursorPos, + .setCursorPos = wlSetCursorPos, + .setWindowCursor = wlSetWindowCursor, + + .attachWindow = wlAttachWindow, + .detachWindow = wlDetachWindow}; + +#endif // PAL_HAS_WAYLAND_BACKEND + +static int compareModes( + const void* a, + const void* b) +{ + const PalMonitorMode* mode1 = (const PalMonitorMode*)a; + const PalMonitorMode* mode2 = (const PalMonitorMode*)b; + + // compare fields + if (mode1->width != mode2->width) { + return mode1->width - mode2->width; + } + + if (mode1->height != mode2->height) { + return mode1->height - mode2->height; + } + + if (mode1->refreshRate != mode2->refreshRate) { + return mode1->refreshRate - mode2->refreshRate; + } + + if (mode1->bpp != mode2->bpp) { + return mode1->bpp - mode2->bpp; + } +} + +static void createScancodeTable() +{ + // Letters + s_Keyboard.scancodes[0x01E] = PAL_SCANCODE_A; + s_Keyboard.scancodes[0x030] = PAL_SCANCODE_B; + s_Keyboard.scancodes[0x02E] = PAL_SCANCODE_C; + s_Keyboard.scancodes[0x020] = PAL_SCANCODE_D; + s_Keyboard.scancodes[0x012] = PAL_SCANCODE_E; + s_Keyboard.scancodes[0x021] = PAL_SCANCODE_F; + s_Keyboard.scancodes[0x022] = PAL_SCANCODE_G; + s_Keyboard.scancodes[0x023] = PAL_SCANCODE_H; + s_Keyboard.scancodes[0x017] = PAL_SCANCODE_I; + s_Keyboard.scancodes[0x024] = PAL_SCANCODE_J; + s_Keyboard.scancodes[0x025] = PAL_SCANCODE_K; + s_Keyboard.scancodes[0x026] = PAL_SCANCODE_L; + s_Keyboard.scancodes[0x032] = PAL_SCANCODE_M; + s_Keyboard.scancodes[0x031] = PAL_SCANCODE_N; + s_Keyboard.scancodes[0x018] = PAL_SCANCODE_O; + s_Keyboard.scancodes[0x019] = PAL_SCANCODE_P; + s_Keyboard.scancodes[0x010] = PAL_SCANCODE_Q; + s_Keyboard.scancodes[0x013] = PAL_SCANCODE_R; + s_Keyboard.scancodes[0x01F] = PAL_SCANCODE_S; + s_Keyboard.scancodes[0x014] = PAL_SCANCODE_T; + s_Keyboard.scancodes[0x016] = PAL_SCANCODE_U; + s_Keyboard.scancodes[0x02F] = PAL_SCANCODE_V; + s_Keyboard.scancodes[0x011] = PAL_SCANCODE_W; + s_Keyboard.scancodes[0x02D] = PAL_SCANCODE_X; + s_Keyboard.scancodes[0x015] = PAL_SCANCODE_Y; + s_Keyboard.scancodes[0x02C] = PAL_SCANCODE_Z; + + // Numbers (top row) + s_Keyboard.scancodes[0x00B] = PAL_SCANCODE_0; + s_Keyboard.scancodes[0x002] = PAL_SCANCODE_1; + s_Keyboard.scancodes[0x003] = PAL_SCANCODE_2; + s_Keyboard.scancodes[0x004] = PAL_SCANCODE_3; + s_Keyboard.scancodes[0x005] = PAL_SCANCODE_4; + s_Keyboard.scancodes[0x006] = PAL_SCANCODE_5; + s_Keyboard.scancodes[0x007] = PAL_SCANCODE_6; + s_Keyboard.scancodes[0x008] = PAL_SCANCODE_7; + s_Keyboard.scancodes[0x009] = PAL_SCANCODE_8; + s_Keyboard.scancodes[0x00A] = PAL_SCANCODE_9; + + // Function + s_Keyboard.scancodes[0x03B] = PAL_SCANCODE_F1; + s_Keyboard.scancodes[0x03C] = PAL_SCANCODE_F2; + s_Keyboard.scancodes[0x03D] = PAL_SCANCODE_F3; + s_Keyboard.scancodes[0x03E] = PAL_SCANCODE_F4; + s_Keyboard.scancodes[0x03F] = PAL_SCANCODE_F5; + s_Keyboard.scancodes[0x040] = PAL_SCANCODE_F6; + s_Keyboard.scancodes[0x041] = PAL_SCANCODE_F7; + s_Keyboard.scancodes[0x042] = PAL_SCANCODE_F8; + s_Keyboard.scancodes[0x043] = PAL_SCANCODE_F9; + s_Keyboard.scancodes[0x044] = PAL_SCANCODE_F10; + s_Keyboard.scancodes[0x057] = PAL_SCANCODE_F11; + s_Keyboard.scancodes[0x058] = PAL_SCANCODE_F12; + + // Control + s_Keyboard.scancodes[0x001] = PAL_SCANCODE_ESCAPE; + s_Keyboard.scancodes[0x01C] = PAL_SCANCODE_ENTER; + s_Keyboard.scancodes[0x00F] = PAL_SCANCODE_TAB; + s_Keyboard.scancodes[0x00E] = PAL_SCANCODE_BACKSPACE; + s_Keyboard.scancodes[0x039] = PAL_SCANCODE_SPACE; + s_Keyboard.scancodes[0x03A] = PAL_SCANCODE_CAPSLOCK; + s_Keyboard.scancodes[0x045] = PAL_SCANCODE_NUMLOCK; + s_Keyboard.scancodes[0x046] = PAL_SCANCODE_SCROLLLOCK; + s_Keyboard.scancodes[0x02A] = PAL_SCANCODE_LSHIFT; + s_Keyboard.scancodes[0x036] = PAL_SCANCODE_RSHIFT; + s_Keyboard.scancodes[0x01D] = PAL_SCANCODE_LCTRL; + s_Keyboard.scancodes[0x061] = PAL_SCANCODE_RCTRL; + s_Keyboard.scancodes[0x038] = PAL_SCANCODE_LALT; + s_Keyboard.scancodes[0x064] = PAL_SCANCODE_RALT; + + // Arrows + s_Keyboard.scancodes[0x069] = PAL_SCANCODE_LEFT; + s_Keyboard.scancodes[0x06A] = PAL_SCANCODE_RIGHT; + s_Keyboard.scancodes[0x067] = PAL_SCANCODE_UP; + s_Keyboard.scancodes[0x06C] = PAL_SCANCODE_DOWN; + + // Navigation + s_Keyboard.scancodes[0x06E] = PAL_SCANCODE_INSERT; + s_Keyboard.scancodes[0x06F] = PAL_SCANCODE_DELETE; + s_Keyboard.scancodes[0x066] = PAL_SCANCODE_HOME; + s_Keyboard.scancodes[0x067] = PAL_SCANCODE_END; + s_Keyboard.scancodes[0x068] = PAL_SCANCODE_PAGEUP; + s_Keyboard.scancodes[0x06D] = PAL_SCANCODE_PAGEDOWN; + + // Keypad + s_Keyboard.scancodes[0x052] = PAL_SCANCODE_KP_0; + s_Keyboard.scancodes[0x04F] = PAL_SCANCODE_KP_1; + s_Keyboard.scancodes[0x050] = PAL_SCANCODE_KP_2; + s_Keyboard.scancodes[0x051] = PAL_SCANCODE_KP_3; + s_Keyboard.scancodes[0x04B] = PAL_SCANCODE_KP_4; + s_Keyboard.scancodes[0x04C] = PAL_SCANCODE_KP_5; + s_Keyboard.scancodes[0x04D] = PAL_SCANCODE_KP_6; + s_Keyboard.scancodes[0x047] = PAL_SCANCODE_KP_7; + s_Keyboard.scancodes[0x048] = PAL_SCANCODE_KP_8; + s_Keyboard.scancodes[0x049] = PAL_SCANCODE_KP_9; + s_Keyboard.scancodes[0x060] = PAL_SCANCODE_KP_ENTER; + s_Keyboard.scancodes[0x04E] = PAL_SCANCODE_KP_ADD; + s_Keyboard.scancodes[0x04A] = PAL_SCANCODE_KP_SUBTRACT; + s_Keyboard.scancodes[0x037] = PAL_SCANCODE_KP_MULTIPLY; + s_Keyboard.scancodes[0x062] = PAL_SCANCODE_KP_DIVIDE; + s_Keyboard.scancodes[0x053] = PAL_SCANCODE_KP_DECIMAL; + + // Misc + s_Keyboard.scancodes[0x063] = PAL_SCANCODE_PRINTSCREEN; + s_Keyboard.scancodes[0x066] = PAL_SCANCODE_PAUSE; + s_Keyboard.scancodes[0x07F] = PAL_SCANCODE_MENU; + s_Keyboard.scancodes[0x028] = PAL_SCANCODE_APOSTROPHE; + s_Keyboard.scancodes[0x02B] = PAL_SCANCODE_BACKSLASH; + s_Keyboard.scancodes[0x033] = PAL_SCANCODE_COMMA; + s_Keyboard.scancodes[0x00D] = PAL_SCANCODE_EQUAL; + s_Keyboard.scancodes[0x029] = PAL_SCANCODE_GRAVEACCENT; + s_Keyboard.scancodes[0x00C] = PAL_SCANCODE_SUBTRACT; + s_Keyboard.scancodes[0x034] = PAL_SCANCODE_PERIOD; + s_Keyboard.scancodes[0x027] = PAL_SCANCODE_SEMICOLON; + s_Keyboard.scancodes[0x035] = PAL_SCANCODE_SLASH; + s_Keyboard.scancodes[0x01A] = PAL_SCANCODE_LBRACKET; + s_Keyboard.scancodes[0x01B] = PAL_SCANCODE_RBRACKET; + s_Keyboard.scancodes[0x07D] = PAL_SCANCODE_LSUPER; + s_Keyboard.scancodes[0x07E] = PAL_SCANCODE_RSUPER; +} + +PalResult PAL_CALL palInitVideo( + const PalAllocator* allocator, + PalEventDriver* eventDriver) +{ + if (s_Video.initialized) { + return PAL_RESULT_SUCCESS; + } + + if (allocator && (!allocator->allocate || !allocator->free)) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // get backend type + PalBool x11 = PAL_TRUE; + const char* session = getenv("XDG_SESSION_TYPE"); + if (session) { + if (strcmp(session, "wayland") == 0) { + x11 = PAL_FALSE; + } + } + + s_Video.maxMonitorData = 16; // initial size + s_Video.maxWindowData = 32; // initial size + uint32_t windowDataSize = sizeof(WindowData) * s_Video.maxWindowData; + uint32_t monitorDataSize = sizeof(MonitorData) * s_Video.maxMonitorData; + + s_Video.windowData = palAllocate(s_Video.allocator, windowDataSize, 0); + s_Video.monitorData = palAllocate(s_Video.allocator, monitorDataSize, 0); + if (!s_Video.monitorData || !s_Video.windowData) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_Video.className = "PAL"; + if (x11) { +#if PAL_HAS_X11_BACKEND == 1 + PalResult ret = xInitVideo(); + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + s_Video.backend = &s_XBackend; +#else + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); +#endif // PAL_HAS_X11_BACKEND + + } else { +#if PAL_HAS_WAYLAND_BACKEND == 1 + PalResult ret = wlInitVideo(); + if (ret != PAL_RESULT_SUCCESS) { + return ret; + } + s_Video.backend = &s_wlBackend; +#else + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); +#endif // PAL_HAS_WAYLAND_BACKEND + } + + createScancodeTable(); + + // we load EGL as well + s_Egl.handle = dlopen("libEGL.so", RTLD_LAZY); + if (s_Egl.handle) { + eglGetProcAddressFn load = nullptr; + load = (eglGetProcAddressFn)dlsym(s_Egl.handle, "eglGetProcAddress"); + + s_Egl.eglInitialize = (eglInitializeFn)load("eglInitialize"); + s_Egl.eglTerminate = (eglTerminateFn)load("eglTerminate"); + s_Egl.eglGetDisplay = (eglGetDisplayFn)load("eglGetDisplay"); + s_Egl.eglChooseConfig = (eglChooseConfigFn)load("eglChooseConfig"); + s_Egl.eglGetError = (eglGetErrorFn)load("eglGetError"); + s_Egl.eglBindAPI = (eglBindAPIFn)load("eglBindAPI"); + s_Egl.eglGetConfigs = (eglGetConfigsFn)load("eglGetConfigs"); + s_Egl.eglGetConfigAttrib = (eglGetConfigAttribFn)load("eglGetConfigAttrib"); + } + + s_Video.allocator = allocator; + s_Video.eventDriver = eventDriver; + s_Video.initialized = PAL_TRUE; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palShutdownVideo() +{ + if (s_Video.initialized) { + s_Video.backend->shutdownVideo(); + palFree(s_Video.allocator, s_Video.windowData); + palFree(s_Video.allocator, s_Video.monitorData); + + if (s_Egl.handle) { + dlclose(s_Egl.handle); + } + + s_Video.platformInstance = nullptr; + s_Video.display = nullptr; + memset(&s_Keyboard, 0, sizeof(Keyboard)); + memset(&s_Mouse, 0, sizeof(Mouse)); + s_Video.initialized = PAL_FALSE; + } +} + +void PAL_CALL palUpdateVideo() +{ + if (s_Video.initialized) { + s_Video.backend->updateVideo(); + } +} + +PalVideoFeatures PAL_CALL palGetVideoFeatures() +{ + if (!s_Video.initialized) { + return 0; + } + + return s_Video.features; +} + +PalResult PAL_CALL palSetFBConfig( + const int index, + PalFBConfigBackend backend) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // X11 and wayland can only used GLX and EGL + if (backend == PAL_CONFIG_BACKEND_WGL) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setFBConfig(index, backend); +} + +PalResult PAL_CALL palEnumerateMonitors( + int32_t* count, + PalMonitor** outMonitors) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!count || *count == 0 && outMonitors) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->enumerateMonitors(count, outMonitors); +} + +PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!outMonitor) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->getPrimaryMonitor(outMonitor); +} + +PalResult PAL_CALL palGetMonitorInfo( + PalMonitor* monitor, + PalMonitorInfo* info) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!info) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->getMonitorInfo(monitor, info); +} + +PalResult PAL_CALL palEnumerateMonitorModes( + PalMonitor* monitor, + int32_t* count, + PalMonitorMode* modes) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!monitor || !count || *count == 0 && modes) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + PalResult ret = s_Video.backend->enumerateMonitorModes(monitor, count, modes); + if (ret == PAL_RESULT_SUCCESS && modes) { + // sort the modes so that they are lowest to highest + qsort(modes, *count, sizeof(PalMonitorMode), compareModes); + } + + return ret; +} + +PalResult PAL_CALL palGetCurrentMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!monitor || !mode) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->getCurrentMonitorMode(monitor, mode); +} + +PalResult PAL_CALL palSetMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!monitor || !mode) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setMonitorMode(monitor, mode); +} + +PalResult PAL_CALL palValidateMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!monitor || !mode) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->validateMonitorMode(monitor, mode); +} + +PalResult PAL_CALL palSetMonitorOrientation( + PalMonitor* monitor, + PalOrientation orientation) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!monitor) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setMonitorOrientation(monitor, orientation); +} + +PalResult PAL_CALL palCreateWindow( + const PalWindowCreateInfo* info, + PalWindow** outWindow) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!info || !outWindow) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (info->style & PAL_WINDOW_STYLE_NO_MINIMIZEBOX) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (info->style & PAL_WINDOW_STYLE_NO_MAXIMIZEBOX) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->createWindow(info, outWindow); +} + +void PAL_CALL palDestroyWindow(PalWindow* window) +{ + if (s_Video.initialized && window) { + return s_Video.backend->destroyWindow(window); + } +} + +PalResult PAL_CALL palMinimizeWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->maximizeWindow(window); +} + +PalResult PAL_CALL palMaximizeWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->minimizeWindow(window); +} + +PalResult PAL_CALL palRestoreWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->restoreWindow(window); +} + +PalResult PAL_CALL palShowWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->showWindow(window); +} + +PalResult PAL_CALL palHideWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->hideWindow(window); +} + +PalResult PAL_CALL palFlashWindow( + PalWindow* window, + const PalFlashInfo* info) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window || !info) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->flashWindow(window, info); +} + +PalResult PAL_CALL palGetWindowStyle( + PalWindow* window, + PalWindowStyle* outStyle) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window || !outStyle) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->getWindowStyle(window, outStyle); +} + +PalResult PAL_CALL palGetWindowMonitor( + PalWindow* window, + PalMonitor** outMonitor) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window || !outMonitor) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->getWindowMonitor(window, outMonitor); +} + +PalResult PAL_CALL palGetWindowTitle( + PalWindow* window, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window || !outBuffer) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->getWindowTitle(window, bufferSize, outSize, outBuffer); +} + +PalResult PAL_CALL palGetWindowPos( + PalWindow* window, + int32_t* x, + int32_t* y) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->getWindowPos(window, x, y); +} + +PalResult PAL_CALL palGetWindowSize( + PalWindow* window, + uint32_t* width, + uint32_t* height) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->getWindowSize(window, width, height); +} + +PalResult PAL_CALL palGetWindowState( + PalWindow* window, + PalWindowState* outState) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window || !outState) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->getWindowState(window, outState); +} + +const PalBool* PAL_CALL palGetKeycodeState() +{ + if (!s_Video.initialized) { + return nullptr; + } + return s_Keyboard.keycodeState; +} + +const PalBool* PAL_CALL palGetScancodeState() +{ + if (!s_Video.initialized) { + return nullptr; + } + return s_Keyboard.scancodeState; +} + +const PalBool* PAL_CALL palGetMouseState() +{ + if (!s_Video.initialized) { + return nullptr; + } + return s_Mouse.state; +} + +void PAL_CALL palGetMouseDelta( + float* dx, + float* dy) +{ + if (!s_Video.initialized) { + return; + } + + if (dx) { + *dx = s_Mouse.dx; + } + + if (dy) { + *dy = s_Mouse.dy; + } +} + +void PAL_CALL palGetMouseWheelDelta( + float* dx, + float* dy) +{ + if (!s_Video.initialized) { + return; + } + + if (dx) { + *dx = (float)s_Mouse.tmpScrollX; + } + + if (dy) { + *dy = (float)s_Mouse.tmpScrollY; + } +} + +PalBool PAL_CALL palIsWindowVisible(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->isWindowVisible(window); +} + +PalWindow* PAL_CALL palGetFocusWindow() +{ + if (!s_Video.initialized) { + return nullptr; + } + + return s_Video.backend->getFocusWindow(); +} + +PalResult PAL_CALL palGetWindowHandleInfo( + PalWindow* window, + PalWindowHandleInfo* info) +{ + if (s_Video.initialized) { + return s_Video.backend->getWindowHandleInfo(window, info); + } + + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult PAL_CALL palSetWindowOpacity( + PalWindow* window, + float opacity) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!(s_Video.features & PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW)) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (opacity < 0.0f) { + opacity = 0.0f; + } + + if (opacity > 1.0f) { + opacity = 1.0f; + } + + return s_Video.backend->setWindowOpacity(window, opacity); +} + +PalResult PAL_CALL palSetWindowStyle( + PalWindow* window, + PalWindowStyle style) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setWindowStyle(window, style); +} + +PalResult PAL_CALL palSetWindowTitle( + PalWindow* window, + const char* title) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window || !title) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setWindowTitle(window, title); +} + +PalResult PAL_CALL palSetWindowPos( + PalWindow* window, + int32_t x, + int32_t y) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setWindowPos(window, x, y); +} + +PalResult PAL_CALL palSetWindowSize( + PalWindow* window, + uint32_t width, + uint32_t height) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setWindowSize(window, width, height); +} + +PalResult PAL_CALL palSetFocusWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setFocusWindow(window); +} + +PalResult PAL_CALL palCreateIcon( + const PalIconCreateInfo* info, + PalIcon** outIcon) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!info || !outIcon) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->createIcon(info, outIcon); +} + +void PAL_CALL palDestroyIcon(PalIcon* icon) +{ + if (s_Video.initialized && icon) { + s_Video.backend->destroyIcon(icon); + } +} + +PalResult PAL_CALL palSetWindowIcon( + PalWindow* window, + PalIcon* icon) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setWindowIcon(window, icon); +} + +PalResult PAL_CALL palCreateCursor( + const PalCursorCreateInfo* info, + PalCursor** outCursor) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!info || !outCursor) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->createCursor(info, outCursor); +} + +PalResult PAL_CALL palCreateCursorFrom( + PalCursorType type, + PalCursor** outCursor) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!outCursor) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->createCursorFrom(type, outCursor); +} + +void PAL_CALL palDestroyCursor(PalCursor* cursor) +{ + if (s_Video.initialized && cursor) { + s_Video.backend->destroyCursor(cursor); + } +} + +void PAL_CALL palShowCursor(PalBool show) +{ + if (s_Video.initialized) { + s_Video.backend->showCursor(show); + } +} + +PalResult PAL_CALL palClipCursor( + PalWindow* window, + PalBool clip) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->clipCursor(window, clip); +} + +PalResult PAL_CALL palGetCursorPos( + PalWindow* window, + int32_t* x, + int32_t* y) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->getCursorPos(window, x, y); +} + +PalResult PAL_CALL palSetCursorPos( + PalWindow* window, + int32_t x, + int32_t y) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setCursorPos(window, x, y); +} + +PalResult PAL_CALL palSetWindowCursor( + PalWindow* window, + PalCursor* cursor) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->setWindowCursor(window, cursor); +} + +void* PAL_CALL palGetInstance() +{ + if (!s_Video.initialized) { + return nullptr; + } + + return s_Video.display; +} + +PalResult PAL_CALL palAttachWindow( + void* windowHandle, + PalWindow** outWindow) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!windowHandle) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->attachWindow(windowHandle, outWindow); +} + +PalResult PAL_CALL palDetachWindow( + PalWindow* window, + void** outWindowHandle) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return s_Video.backend->detachWindow(window, outWindowHandle); +} + +void PAL_CALL palSetPreferredInstance(void* instance) +{ + if (!s_Video.initialized && instance) { + s_Video.platformInstance = instance; + } +} + +#endif // __linux__ diff --git a/src/video/linux/pal_video_linux.h b/src/video/linux/pal_video_linux.h new file mode 100644 index 00000000..afd4a2ab --- /dev/null +++ b/src/video/linux/pal_video_linux.h @@ -0,0 +1,345 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_VIDEO_LINUX_H +#define _PAL_VIDEO_LINUX_H +#ifdef __linux__ +#define _GNU_SOURCE +#define _POSIX_C_SOURCE 200112L +#include "pal/pal_video.h" +#include + +#define NULL_BUTTON_SERIAL 0xffffffffU +#define MAX_SPAN_MONITORS 4 + +#define TO_PAL_HANDLE(type, val) ((type*)(uintptr_t)(val)) +#define FROM_PAL_HANDLE(type, handle) ((type)(uintptr_t)(handle)) + +#define EGL_CAST(type, value) ((type)(value)) +#define EGL_OPENGL_API 0x30A2 +#define EGL_OPENGL_BIT 0x0008 +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0) +#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0) +#define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0) +#define EGL_NATIVE_VISUAL_ID 0x302E + +typedef void* EGLConfig; +typedef void* EGLSurface; +typedef void* EGLContext; +typedef void* EGLDisplay; +typedef void* EGLNativeDisplayType; + +typedef int32_t EGLint; +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; + +typedef void* (*eglGetProcAddressFn)(const char*); + +typedef EGLBoolean (*eglInitializeFn)( + EGLDisplay, + EGLint*, + EGLint*); + +typedef EGLBoolean (*eglTerminateFn)(EGLDisplay); + +typedef EGLDisplay (*eglGetDisplayFn)(void*); + +typedef EGLBoolean (*eglChooseConfigFn)( + EGLDisplay, + const EGLint*, + EGLConfig*, + EGLint, + EGLint*); + +typedef EGLBoolean (*eglGetConfigAttribFn)( + EGLDisplay, + EGLConfig, + EGLint, + EGLint*); + +typedef EGLint (*eglGetErrorFn)(void); + +typedef EGLBoolean (*eglBindAPIFn)(EGLenum); + +typedef EGLBoolean (*eglGetConfigsFn)( + EGLDisplay, + EGLConfig*, + EGLint, + EGLint*); + +typedef struct { + PalBool pendingScroll; + int32_t lastX; + int32_t lastY; + int32_t dx; + int32_t dy; + int32_t WheelX; + int32_t WheelY; + float WheelXf; + float WheelYf; + PalBool state[PAL_MOUSE_BUTTON_MAX]; + double tmpScrollX; + double tmpScrollY; + double accumScrollX; + double accumScrollY; +} Mouse; + +typedef struct { + PalBool scancodeState[PAL_SCANCODE_MAX]; + PalBool keycodeState[PAL_KEYCODE_MAX]; + int repeatRate; + int repeatDelay; + int repeatKey; + int repeatScancode; + int scancodes[512]; + int keycodes[256]; + uint64_t timer; + uint64_t frequency; +} Keyboard; + +typedef struct { + void* handle; + eglInitializeFn eglInitialize; + eglTerminateFn eglTerminate; + eglGetDisplayFn eglGetDisplay; + eglChooseConfigFn eglChooseConfig; + eglGetConfigAttribFn eglGetConfigAttrib; + eglGetErrorFn eglGetError; + eglBindAPIFn eglBindAPI; + eglGetConfigsFn eglGetConfigs; +} EGL; + +typedef struct { + // clang-format off + void (*shutdownVideo)(); + void (*updateVideo)(); + PalResult (*setFBConfig)(const int, PalFBConfigBackend); + PalResult (*enumerateMonitors)(int32_t*, PalMonitor**); + PalResult (*getPrimaryMonitor)(PalMonitor**); + PalResult (*getMonitorInfo)(PalMonitor*, PalMonitorInfo*); + PalResult (*enumerateMonitorModes)(PalMonitor*, int32_t*, PalMonitorMode*); + PalResult (*getCurrentMonitorMode)(PalMonitor*, PalMonitorMode*); + PalResult (*setMonitorMode)(PalMonitor*, PalMonitorMode*); + PalResult (*validateMonitorMode)(PalMonitor*, PalMonitorMode*); + PalResult (*setMonitorOrientation)(PalMonitor*, PalOrientation); + + PalResult (*createWindow)(const PalWindowCreateInfo*, PalWindow**); + void (*destroyWindow)(PalWindow*); + PalResult (*maximizeWindow)(PalWindow*); + PalResult (*minimizeWindow)(PalWindow*); + PalResult (*restoreWindow)(PalWindow*); + PalResult (*showWindow)(PalWindow*); + PalResult (*hideWindow)(PalWindow*); + PalResult (*flashWindow)(PalWindow*, const PalFlashInfo*); + PalResult (*getWindowStyle)(PalWindow*, PalWindowStyle*); + PalResult (*getWindowMonitor)(PalWindow*, PalMonitor**); + PalResult (*getWindowTitle)(PalWindow*, uint64_t, uint64_t*, char*); + PalResult (*getWindowPos)(PalWindow*, int32_t*, int32_t*); + PalResult (*getWindowSize)(PalWindow*, uint32_t*, uint32_t*); + PalResult (*getWindowState)(PalWindow*, PalWindowState*); + PalBool (*isWindowVisible)(PalWindow*); + PalWindow* (*getFocusWindow)(); + PalResult (*getWindowHandleInfo)(PalWindow*, PalWindowHandleInfo*); + PalResult (*setWindowOpacity)(PalWindow*, float); + PalResult (*setWindowStyle)(PalWindow*, PalWindowStyle); + PalResult (*setWindowTitle)(PalWindow*, const char*); + PalResult (*setWindowPos)(PalWindow*, int32_t, int32_t); + PalResult (*setWindowSize)(PalWindow*, uint32_t, uint32_t); + PalResult (*setFocusWindow)(PalWindow*); + + PalResult (*createIcon)(const PalIconCreateInfo*, PalIcon**); + void (*destroyIcon)(PalIcon*); + PalResult (*setWindowIcon)(PalWindow*, PalIcon*); + + PalResult (*createCursor)(const PalCursorCreateInfo*, PalCursor**); + PalResult (*createCursorFrom)(PalCursorType, PalCursor**); + void (*destroyCursor)(PalCursor*); + void (*showCursor)(PalBool); + PalResult (*clipCursor)(PalWindow*, PalBool); + PalResult (*getCursorPos)(PalWindow*, int32_t*, int32_t*); + PalResult (*setCursorPos)(PalWindow*, int32_t, int32_t); + PalResult (*setWindowCursor)(PalWindow*, PalCursor*); + + PalResult (*attachWindow)(void*, PalWindow**); + PalResult (*detachWindow)(PalWindow*, void**); + // clang-format on +} Backend; + +typedef struct { + void* monitor; + int dpi; +} SpanMonitor; + +typedef struct { + PalBool skipConfigure; + PalBool skipState; + PalBool used; + PalBool isAttached; + PalBool skipIfAttached; + PalBool focused; + PalBool pushConfigureEvent; + PalBool pushStateEvent; + int x; + int y; + uint32_t w; + int dpi; + int monitorCount; + uint32_t h; + PalWindowState state; + PalWindow* window; + + // X11 only + void* ic; + unsigned long colormap; + + // Wayland only + void* xdgSurface; + void* xdgToplevel; + void* buffer; + void* decoration; + void* cursor; + void* eglWindow; + SpanMonitor monitors[MAX_SPAN_MONITORS]; +} WindowData; + +typedef struct { + PalBool used; + int dpi; + int x; + int y; + uint32_t w; + uint32_t h; + uint32_t refreshRate; + uint32_t wlName; + PalOrientation orientation; + PalMonitor* monitor; + PalMonitorMode mode; // wayland only sends current + char name[32]; +} MonitorData; + +typedef struct { + PalBool initialized; + int32_t maxWindowData; + int32_t maxMonitorData; + int32_t pixelFormat; + PalVideoFeatures features; + const PalAllocator* allocator; + PalEventDriver* eventDriver; + const Backend* backend; + WindowData* windowData; + MonitorData* monitorData; + const char* className; + void* platformInstance; + void* display; +} VideoLinux; + +extern VideoLinux s_Video; +extern Mouse s_Mouse; +extern Keyboard s_Keyboard; +extern EGL s_Egl; + +static WindowData* getFreeWindowData() +{ + for (int i = 0; i < s_Video.maxWindowData; ++i) { + if (!s_Video.windowData[i].used) { + s_Video.windowData[i].used = PAL_TRUE; + return &s_Video.windowData[i]; + } + } + + // resize the data array + // It is rare for a user to create and manage + // 32 windows at the same time + WindowData* data = nullptr; + int count = s_Video.maxWindowData * 2; // double the size + int freeIndex = s_Video.maxWindowData + 1; + data = palAllocate(s_Video.allocator, sizeof(WindowData) * count, 0); + if (data) { + memcpy(data, s_Video.windowData, s_Video.maxWindowData * sizeof(WindowData)); + + palFree(s_Video.allocator, s_Video.windowData); + s_Video.windowData = data; + s_Video.maxWindowData = count; + + s_Video.windowData[freeIndex].used = PAL_TRUE; + return &s_Video.windowData[freeIndex]; + } + return nullptr; +} + +static WindowData* findWindowData(PalWindow* window) +{ + for (int i = 0; i < s_Video.maxWindowData; ++i) { + if (s_Video.windowData[i].used && s_Video.windowData[i].window == window) { + return &s_Video.windowData[i]; + } + } + return nullptr; +} + +static void resetMonitorData() +{ + memset(s_Video.monitorData, 0, s_Video.maxMonitorData * sizeof(MonitorData)); +} + +static MonitorData* getFreeMonitorData() +{ + for (int i = 0; i < s_Video.maxMonitorData; ++i) { + if (!s_Video.monitorData[i].used) { + s_Video.monitorData[i].used = PAL_TRUE; + return &s_Video.monitorData[i]; + } + } + + // resize the data array + // this will almost not reach here since most setups are 1-4 monitors + MonitorData* data = nullptr; + int count = s_Video.maxMonitorData * 2; // double the size + int freeIndex = s_Video.maxMonitorData + 1; + data = palAllocate(s_Video.allocator, sizeof(MonitorData) * count, 0); + if (data) { + memcpy(data, s_Video.monitorData, s_Video.maxMonitorData * sizeof(MonitorData)); + + palFree(s_Video.allocator, s_Video.monitorData); + s_Video.monitorData = data; + s_Video.maxWindowData = count; + + s_Video.monitorData[freeIndex].used = PAL_TRUE; + return &s_Video.monitorData[freeIndex]; + } + return nullptr; +} + +static MonitorData* findMonitorData(PalMonitor* monitor) +{ + for (int i = 0; i < s_Video.maxMonitorData; ++i) { + if (s_Video.monitorData[i].used && s_Video.monitorData[i].monitor == monitor) { + return &s_Video.monitorData[i]; + } + } + return nullptr; +} + +static void freeMonitorData(PalMonitor* monitor) +{ + for (int i = 0; i < s_Video.maxMonitorData; ++i) { + if (s_Video.monitorData[i].used && s_Video.monitorData[i].monitor == monitor) { + s_Video.monitorData[i].used = PAL_FALSE; + } + } +} + +static inline uint64_t getCurrentTime() +{ + uint64_t now = palGetPerformanceCounter(); + return (now * 1000) / s_Keyboard.frequency; +} + +#endif // __linux__ +#endif // _PAL_VIDEO_LINUX_H \ No newline at end of file diff --git a/src/video/linux/wayland/pal_cursor_wayland.c b/src/video/linux/wayland/pal_cursor_wayland.c new file mode 100644 index 00000000..8a0540dc --- /dev/null +++ b/src/video/linux/wayland/pal_cursor_wayland.c @@ -0,0 +1,187 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_WAYLAND_BACKEND == 1 + +#include "pal_wayland_helper.h" +#include "pal_shared.h" + +PalResult wlCreateCursor( + const PalCursorCreateInfo* info, + PalCursor** outCursor) +{ + WaylandCursor* cursor = nullptr; + cursor = palAllocate(s_Video.allocator, sizeof(WaylandCursor), 0); + if (!cursor) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + cursor->surface = compositorCreateSurface(s_Wl.compositor); + if (!cursor->surface) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + cursor->buffer = createShmBuffer(info->width, info->height, info->pixels, PAL_TRUE); + if (!cursor->buffer) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + surfaceAttach(cursor->surface, cursor->buffer, 0, 0); + surfaceCommit(cursor->surface); + cursor->hotspotX = info->xHotspot; + cursor->hotspotY = info->yHotspot; + + *outCursor = (PalCursor*)cursor; + return PAL_RESULT_SUCCESS; +} + +PalResult wlCreateCursorFrom( + PalCursorType type, + PalCursor** outCursor) +{ + const char* cursorType = nullptr; + switch (type) { + case PAL_CURSOR_ARROW: { + cursorType = "left_ptr"; + break; + } + + case PAL_CURSOR_HAND: { + cursorType = "hand1"; + break; + } + + case PAL_CURSOR_CROSS: { + cursorType = "crosshair"; + break; + } + + case PAL_CURSOR_IBEAM: { + cursorType = "text"; + break; + } + + case PAL_CURSOR_WAIT: { + cursorType = "wait"; + break; + } + } + + struct wl_cursor* wlCursor = nullptr; + wlCursor = s_Wl.cursorThemeGetCursor(s_Wl.cursorTheme, cursorType); + if (!wlCursor) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + WaylandCursor* cursor = nullptr; + cursor = palAllocate(s_Video.allocator, sizeof(WaylandCursor), 0); + if (!cursor) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + cursor->surface = compositorCreateSurface(s_Wl.compositor); + if (!cursor->surface) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + cursor->buffer = s_Wl.cursorImageGetBuffer(wlCursor->images[0]); + surfaceAttach(cursor->surface, cursor->buffer, 0, 0); + surfaceCommit(cursor->surface); + cursor->hotspotX = wlCursor->images[0]->hotspot_x; + cursor->hotspotY = wlCursor->images[0]->hotspot_y; + + *outCursor = (PalCursor*)cursor; + return PAL_RESULT_SUCCESS; +} + +void wlDestroyCursor(PalCursor* cursor) +{ + WaylandCursor* waylandCursor = (WaylandCursor*)cursor; + bufferDestroy(waylandCursor->buffer); + surfaceDestroy(waylandCursor->surface); + palFree(s_Video.allocator, waylandCursor); +} + +void wlShowCursor(PalBool show) +{ + // not supported + return; +} + +PalResult wlClipCursor( + PalWindow* window, + PalBool clip) +{ + if (!(s_Video.features & PAL_VIDEO_FEATURE_CLIP_CURSOR)) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult wlGetCursorPos( + PalWindow* window, + int32_t* x, + int32_t* y) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlSetCursorPos( + PalWindow* window, + int32_t x, + int32_t y) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlSetWindowCursor( + PalWindow* window, + PalCursor* cursor) +{ + WindowData* data = findWindowData(window); + if (!data) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + data->cursor = cursor; + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_WAYLAND_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/wayland/pal_icon_wayland.c b/src/video/linux/wayland/pal_icon_wayland.c new file mode 100644 index 00000000..6e8ec782 --- /dev/null +++ b/src/video/linux/wayland/pal_icon_wayland.c @@ -0,0 +1,40 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_WAYLAND_BACKEND == 1 + +#include "pal_wayland.h" +#include "pal_shared.h" + +PalResult wlCreateIcon( + const PalIconCreateInfo* info, + PalIcon** outIcon) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +void wlDestroyIcon(PalIcon* icon) +{ + return; +} + +PalResult wlSetWindowIcon( + PalWindow* window, + PalIcon* icon) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +#endif // PAL_HAS_WAYLAND_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/wayland/pal_monitor_wayland.c b/src/video/linux/wayland/pal_monitor_wayland.c new file mode 100644 index 00000000..0c59909b --- /dev/null +++ b/src/video/linux/wayland/pal_monitor_wayland.c @@ -0,0 +1,151 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_WAYLAND_BACKEND == 1 + +#include "pal_wayland.h" +#include "pal_shared.h" + +PalResult wlEnumerateMonitors( + int32_t* count, + PalMonitor** outMonitors) +{ + if (outMonitors) { + int index = 0; + int maxCount = s_Video.maxMonitorData; + for (int i = 0; i < maxCount && index < *count; i++) { + if (s_Video.monitorData[i].used) { + // found a monitor + PalMonitor* monitor = s_Video.monitorData[index].monitor; + outMonitors[index++] = monitor; + } + } + } + + if (!outMonitors) { + *count = s_Wl.monitorCount; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult wlGetPrimaryMonitor(PalMonitor** outMonitor) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlGetMonitorInfo( + PalMonitor* monitor, + PalMonitorInfo* info) +{ + MonitorData* monitorData = findMonitorData(monitor); + if (!monitorData) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + info->dpi = monitorData->dpi; + info->x = monitorData->x; + info->y = monitorData->y; + info->width = monitorData->w; + info->height = monitorData->h; + info->refreshRate = monitorData->refreshRate; + info->orientation = monitorData->orientation; + + info->primary = PAL_FALSE; // no way to query + strcpy(info->name, monitorData->name); + + return PAL_RESULT_SUCCESS; +} + +PalResult wlEnumerateMonitorModes( + PalMonitor* monitor, + int32_t* count, + PalMonitorMode* modes) +{ + MonitorData* monitorData = findMonitorData(monitor); + if (!monitorData) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (modes && *count > 0) { + PalMonitorMode* mode = &modes[0]; + mode->bpp = monitorData->mode.bpp; + mode->width = monitorData->mode.width; + mode->height = monitorData->mode.height; + mode->refreshRate = monitorData->mode.refreshRate; + } + + if (!modes) { + *count = 1; // wayland only gives the active mode + } + + return PAL_RESULT_SUCCESS; +} + +PalResult wlGetCurrentMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + MonitorData* monitorData = findMonitorData(monitor); + if (!monitorData) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // this is the same as the current mode + mode->bpp = monitorData->mode.bpp; + mode->width = monitorData->mode.width; + mode->height = monitorData->mode.height; + mode->refreshRate = monitorData->mode.refreshRate; + + return PAL_RESULT_SUCCESS; +} + +PalResult wlSetMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlValidateMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlSetMonitorOrientation( + PalMonitor* monitor, + PalOrientation orientation) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +#endif // PAL_HAS_WAYLAND_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/wayland/pal_video_wayland.c b/src/video/linux/wayland/pal_video_wayland.c new file mode 100644 index 00000000..c0a8ea87 --- /dev/null +++ b/src/video/linux/wayland/pal_video_wayland.c @@ -0,0 +1,415 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_WAYLAND_BACKEND == 1 + +#include "pal_wayland_helper.h" +#include "pal_shared.h" +#include + +Wayland s_Wl = {0}; + +PalResult eglWlBackend(const int index) +{ + // user choose EGL FBConfig backend + if (!s_Egl.handle) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + EGLDisplay display = EGL_NO_DISPLAY; + display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_Wl.display); + + if (display == EGL_NO_DISPLAY) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + EGLint numConfigs = 0; + if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + EGLint configSize = sizeof(EGLConfig) * numConfigs; + EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); + if (!eglConfigs) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); + s_Wl.eglFBConfig = eglConfigs[index]; + + return PAL_RESULT_SUCCESS; +} + +static void createKeycodeTable() +{ + // Tis is for only printable and text input keys + + // Letters + s_Keyboard.keycodes[XKB_KEY_a] = PAL_KEYCODE_A; + s_Keyboard.keycodes[XKB_KEY_b] = PAL_KEYCODE_B; + s_Keyboard.keycodes[XKB_KEY_c] = PAL_KEYCODE_C; + s_Keyboard.keycodes[XKB_KEY_d] = PAL_KEYCODE_D; + s_Keyboard.keycodes[XKB_KEY_e] = PAL_KEYCODE_E; + s_Keyboard.keycodes[XKB_KEY_f] = PAL_KEYCODE_F; + s_Keyboard.keycodes[XKB_KEY_g] = PAL_KEYCODE_G; + s_Keyboard.keycodes[XKB_KEY_h] = PAL_KEYCODE_H; + s_Keyboard.keycodes[XKB_KEY_i] = PAL_KEYCODE_I; + s_Keyboard.keycodes[XKB_KEY_j] = PAL_KEYCODE_J; + s_Keyboard.keycodes[XKB_KEY_k] = PAL_KEYCODE_K; + s_Keyboard.keycodes[XKB_KEY_l] = PAL_KEYCODE_L; + s_Keyboard.keycodes[XKB_KEY_m] = PAL_KEYCODE_M; + s_Keyboard.keycodes[XKB_KEY_n] = PAL_KEYCODE_N; + s_Keyboard.keycodes[XKB_KEY_o] = PAL_KEYCODE_O; + s_Keyboard.keycodes[XKB_KEY_p] = PAL_KEYCODE_P; + s_Keyboard.keycodes[XKB_KEY_q] = PAL_KEYCODE_Q; + s_Keyboard.keycodes[XKB_KEY_r] = PAL_KEYCODE_R; + s_Keyboard.keycodes[XKB_KEY_s] = PAL_KEYCODE_S; + s_Keyboard.keycodes[XKB_KEY_t] = PAL_KEYCODE_T; + s_Keyboard.keycodes[XKB_KEY_u] = PAL_KEYCODE_U; + s_Keyboard.keycodes[XKB_KEY_v] = PAL_KEYCODE_V; + s_Keyboard.keycodes[XKB_KEY_w] = PAL_KEYCODE_W; + s_Keyboard.keycodes[XKB_KEY_x] = PAL_KEYCODE_X; + s_Keyboard.keycodes[XKB_KEY_y] = PAL_KEYCODE_Y; + s_Keyboard.keycodes[XKB_KEY_z] = PAL_KEYCODE_Z; + + // Control + s_Keyboard.keycodes[XKB_KEY_space] = PAL_KEYCODE_SPACE; + + // Misc + s_Keyboard.keycodes[XKB_KEY_apostrophe] = PAL_KEYCODE_APOSTROPHE; + s_Keyboard.keycodes[XKB_KEY_backslash] = PAL_KEYCODE_BACKSLASH; + s_Keyboard.keycodes[XKB_KEY_comma] = PAL_KEYCODE_COMMA; + s_Keyboard.keycodes[XKB_KEY_equal] = PAL_KEYCODE_EQUAL; + s_Keyboard.keycodes[XKB_KEY_grave] = PAL_KEYCODE_GRAVEACCENT; + s_Keyboard.keycodes[XKB_KEY_minus] = PAL_KEYCODE_SUBTRACT; + s_Keyboard.keycodes[XKB_KEY_period] = PAL_KEYCODE_PERIOD; + s_Keyboard.keycodes[XKB_KEY_semicolon] = PAL_KEYCODE_SEMICOLON; + s_Keyboard.keycodes[XKB_KEY_slash] = PAL_KEYCODE_SLASH; + s_Keyboard.keycodes[XKB_KEY_bracketleft] = PAL_KEYCODE_LBRACKET; + s_Keyboard.keycodes[XKB_KEY_bracketright] = PAL_KEYCODE_RBRACKET; +} + +PalResult wlInitVideo() +{ + // load wayland libray + s_Wl.handle = dlopen("libwayland-client.so.0", RTLD_LAZY); + s_Wl.xkbCommon = dlopen("libxkbcommon.so", RTLD_LAZY); + s_Wl.libCursor = dlopen("libwayland-cursor.so", RTLD_LAZY); + s_Wl.libWaylandEgl = dlopen("libwayland-egl.so", RTLD_LAZY); + + // clang-format off + if (!s_Wl.handle || + !s_Wl.xkbCommon || + !s_Wl.libCursor || + !s_Wl.libWaylandEgl) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + // get the exported global variables + s_Wl.outputInterface = dlsym(s_Wl.handle, "wl_output_interface"); + s_Wl.seatInterface = dlsym(s_Wl.handle, "wl_seat_interface"); + s_Wl.compositorInterface = dlsym(s_Wl.handle, "wl_compositor_interface"); + s_Wl.surfaceInterface = dlsym(s_Wl.handle, "wl_surface_interface"); + s_Wl.registryInterface = dlsym(s_Wl.handle, "wl_registry_interface"); + s_Wl.shmInterface = dlsym(s_Wl.handle, "wl_shm_interface"); + s_Wl.bufferInterface = dlsym(s_Wl.handle, "wl_buffer_interface"); + s_Wl.shmPoolInterface = dlsym(s_Wl.handle, "wl_shm_pool_interface"); + s_Wl.regionInterface = dlsym(s_Wl.handle, "wl_region_interface"); + s_Wl.pointerInterface = dlsym(s_Wl.handle, "wl_pointer_interface"); + s_Wl.keyboardInterface = dlsym(s_Wl.handle, "wl_keyboard_interface"); + + // load function procs + s_Wl.displayConnect = (wl_display_connect_fn)dlsym( + s_Wl.handle, + "wl_display_connect"); + + s_Wl.displayDisconnect = (wl_display_disconnect_fn)dlsym( + s_Wl.handle, + "wl_display_disconnect"); + + s_Wl.displayRoundtrip = (wl_display_roundtrip_fn)dlsym( + s_Wl.handle, + "wl_display_roundtrip"); + + s_Wl.displayDispatch = (wl_display_dispatch_fn)dlsym( + s_Wl.handle, + "wl_display_dispatch"); + + s_Wl.proxyAddListener = (wl_proxy_add_listener_fn)dlsym( + s_Wl.handle, + "wl_proxy_add_listener"); + + s_Wl.proxyMarshalCnstructor = (wl_proxy_marshal_constructor_v_fn)dlsym( + s_Wl.handle, + "wl_proxy_marshal_constructor_versioned"); + + s_Wl.proxyDestroy = (wl_proxy_destroy_fn)dlsym( + s_Wl.handle, + "wl_proxy_destroy"); + + s_Wl.proxyMarshalFlags = (wl_proxy_marshal_flags_fn)dlsym( + s_Wl.handle, + "wl_proxy_marshal_flags"); + + s_Wl.proxyGetVersion = (wl_proxy_get_version_fn)dlsym( + s_Wl.handle, + "wl_proxy_get_version"); + + s_Wl.getError = (wl_display_get_error_fn)dlsym( + s_Wl.handle, + "wl_display_get_error"); + + s_Wl.dispatchPending = (wl_display_dispatch_pending_fn)dlsym( + s_Wl.handle, + "wl_display_dispatch_pending"); + + s_Wl.displayFlush = (wl_display_flush_fn)dlsym( + s_Wl.handle, + "wl_display_flush"); + + s_Wl.prepareRead = (wl_display_prepare_read_fn)dlsym( + s_Wl.handle, + "wl_display_prepare_read"); + + s_Wl.readEvents = (wl_display_read_events_fn)dlsym( + s_Wl.handle, + "wl_display_read_events"); + + s_Wl.displayGetFd = (wl_display_get_fd_fn)dlsym( + s_Wl.handle, + "wl_display_get_fd"); + + s_Wl.cancelRead = (wl_display_cancel_read_fn)dlsym( + s_Wl.handle, + "wl_display_cancel_read"); + + // load xkbcommon procs + s_Wl.xkbKeymapUnref = (xkb_keymap_unref_fn)dlsym( + s_Wl.xkbCommon, + "xkb_keymap_unref"); + + s_Wl.xkbStateKeyGetOneSym = (xkb_state_key_get_one_sym_fn)dlsym( + s_Wl.xkbCommon, + "xkb_state_key_get_one_sym"); + + s_Wl.xkbStateNew = (xkb_state_new_fn)dlsym( + s_Wl.xkbCommon, + "xkb_state_new"); + + s_Wl.xkbStateUnref = (xkb_state_unref_fn)dlsym( + s_Wl.xkbCommon, + "xkb_state_unref"); + + s_Wl.xkbContextUnref = (xkb_context_unref_fn)dlsym( + s_Wl.xkbCommon, + "xkb_context_unref"); + + s_Wl.xkbContextNew = (xkb_context_new_fn)dlsym( + s_Wl.xkbCommon, + "xkb_context_new"); + + s_Wl.xkbKeymapNewFromString = (xkb_keymap_new_from_string_fn)dlsym( + s_Wl.xkbCommon, + "xkb_keymap_new_from_string"); + + s_Wl.xkbKeysymToUtf32 = (xkb_keysym_to_utf32_fn)dlsym( + s_Wl.xkbCommon, + "xkb_keysym_to_utf32"); + + s_Wl.xkbStateUpdateMask = (xkb_state_update_mask_fn)dlsym( + s_Wl.xkbCommon, + "xkb_state_update_mask"); + + s_Wl.xkbKeymapKeyRepeats = (xkb_keymap_key_repeats_fn)dlsym( + s_Wl.xkbCommon, + "xkb_keymap_key_repeats"); + + // load wayland cursor procs + s_Wl.cursorImageGetBuffer = (wl_cursor_image_get_buffer_fn)dlsym( + s_Wl.libCursor, + "wl_cursor_image_get_buffer"); + + s_Wl.cursorThemeLoad = (wl_cursor_theme_load_fn)dlsym( + s_Wl.libCursor, + "wl_cursor_theme_load"); + + s_Wl.cursorThemeGetCursor = (wl_cursor_theme_get_cursor_fn)dlsym( + s_Wl.libCursor, + "wl_cursor_theme_get_cursor"); + + // wl_egl procs + s_Wl.eglWindowCreate = (wl_egl_window_create_fn)dlsym( + s_Wl.libWaylandEgl, + "wl_egl_window_create"); + + s_Wl.eglWindowDestroy = (wl_egl_window_destroy_fn)dlsym( + s_Wl.libWaylandEgl, + "wl_egl_window_destroy"); + + s_Wl.eglWindowResize = (wl_egl_window_resize_fn)dlsym( + s_Wl.libWaylandEgl, + "wl_egl_window_resize"); + // clang-format on + + // initialize wayland + s_Wl.checkFeatures = PAL_TRUE; + s_Wl.monitorCount = 0; + setupXdgShellProtocol(); + + // check if user supplied their own display + if (s_Video.platformInstance) { + s_Wl.display = (struct wl_display*)s_Video.platformInstance; + + } else { + s_Wl.display = s_Wl.displayConnect(nullptr); + s_Video.platformInstance = nullptr; + } + + if (!s_Wl.display) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + s_Video.display = (void*)s_Wl.display; + s_Wl.registry = displayGetRegistry(s_Wl.display); + registryAddListener(s_Wl.registry, &s_RegistryListener, nullptr); + s_Wl.displayRoundtrip(s_Wl.display); + + // do a roundtrip again to get remaining handles + s_Wl.displayRoundtrip(s_Wl.display); + + if (!s_Wl.compositor || !s_Wl.xdgBase || !s_Wl.shm) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + // create an input context + s_Wl.inputContext = s_Wl.xkbContextNew(XKB_CONTEXT_NO_FLAGS); + if (!s_Wl.inputContext) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + // get the current theme + s_Wl.cursorTheme = s_Wl.cursorThemeLoad(nullptr, 32, s_Wl.shm); + if (!s_Wl.cursorTheme) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + createKeycodeTable(); + + s_Video.display = (void*)s_Wl.display; + return PAL_RESULT_SUCCESS; +} + +void wlShutdownVideo() +{ + if (s_Wl.state) { + s_Wl.xkbStateUnref(s_Wl.state); + s_Wl.xkbKeymapUnref(s_Wl.keymap); + } + + s_Wl.xkbContextUnref(s_Wl.inputContext); + if (s_Wl.compositor) { + // if compositor was found, all this will be as well + // since we check all at init + s_Wl.proxyDestroy((struct wl_proxy*)s_Wl.compositor); + s_Wl.proxyDestroy((struct wl_proxy*)s_Wl.xdgBase); + s_Wl.proxyDestroy((struct wl_proxy*)s_Wl.shm); + s_Wl.proxyDestroy((struct wl_proxy*)s_Wl.seat); + } + + if (!s_Video.platformInstance) { + // opened by PAL + s_Wl.displayDisconnect(s_Wl.display); + } + + dlclose(s_Wl.libCursor); + dlclose(s_Wl.xkbCommon); + dlclose(s_Wl.libWaylandEgl); + dlclose(s_Wl.handle); + + memset(&s_Wl, 0, sizeof(Wayland)); +} + +PalResult wlSetFBConfig( + const int index, + PalFBConfigBackend backend) +{ + if (backend == PAL_CONFIG_BACKEND_GLES || backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { + return eglWlBackend(index); + + } else { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } +} + +void wlUpdateVideo() +{ + // flush pending requests + s_Mouse.tmpScrollX = 0; + s_Mouse.tmpScrollY = 0; + + // push key repeats + // we only do this if the user wants key repeat events + if (s_Keyboard.repeatKey != 0 && s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(driver, PAL_EVENT_KEYREPEAT); + if (mode != PAL_DISPATCH_NONE) { + // get now time and check with the key repeat time + uint64_t now = getCurrentTime(); + if (now >= s_Keyboard.timer) { + PalWindow* window = (PalWindow*)s_Wl.keyboardSurface; + PalKeycode key = s_Keyboard.repeatKey; + PalScancode scancode = s_Keyboard.repeatScancode; + + PalEvent event = {0}; + event.type = PAL_EVENT_KEYREPEAT; + event.data = palPackUint32(key, scancode); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + s_Keyboard.timer += s_Keyboard.repeatRate; + } + } + } + + while (s_Wl.prepareRead(s_Wl.display) != 0) { + s_Wl.dispatchPending(s_Wl.display); + } + + s_Wl.displayFlush(s_Wl.display); + int fd = s_Wl.displayGetFd(s_Wl.display); + struct pollfd pfd = {fd, POLLIN, 0}; + if (poll(&pfd, 1, 0) > 0) { + // there are events ready to be read + s_Wl.readEvents(s_Wl.display); + + } else { + s_Wl.cancelRead(s_Wl.display); + } + + // dispatch events that were read + s_Wl.dispatchPending(s_Wl.display); +} + +void* wlGetInstance() +{ + return (void*)s_Wl.display; +} + +#endif // PAL_HAS_WAYLAND_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/wayland/pal_wayland.h b/src/video/linux/wayland/pal_wayland.h new file mode 100644 index 00000000..055a4b76 --- /dev/null +++ b/src/video/linux/wayland/pal_wayland.h @@ -0,0 +1,214 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_WAYLAND_H +#define _PAL_WAYLAND_H +#ifdef __linux__ +#if PAL_HAS_WAYLAND_BACKEND == 1 + +#include "video/linux/pal_video_linux.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct wl_display* (*wl_display_connect_fn)(const char*); +typedef void (*wl_display_disconnect_fn)(struct wl_display*); +typedef int (*wl_display_roundtrip_fn)(struct wl_display*); +typedef int (*wl_display_dispatch_fn)(struct wl_display*); +typedef void (*wl_proxy_destroy_fn)(struct wl_proxy*); + +typedef int (*wl_proxy_add_listener_fn)( + struct wl_proxy*, + void (**)(void), + void*); + +typedef struct wl_proxy* (*wl_proxy_marshal_constructor_v_fn)( + struct wl_proxy*, + uint32_t, + const struct wl_interface*, + uint32_t, + ...); + +typedef struct wl_proxy* (*wl_proxy_marshal_flags_fn)( + struct wl_proxy*, + uint32_t, + const struct wl_interface*, + uint32_t, + uint32_t, + ...); + +typedef uint32_t (*wl_proxy_get_version_fn)(struct wl_proxy*); + +typedef int (*wl_proxy_add_listener_fn)( + struct wl_proxy*, + void (**)(void), + void*); + +typedef int (*wl_display_get_error_fn)(struct wl_display*); +typedef int (*wl_display_dispatch_pending_fn)(struct wl_display*); +typedef int (*wl_display_flush_fn)(struct wl_display*); +typedef int (*wl_display_prepare_read_fn)(struct wl_display*); +typedef int (*wl_display_read_events_fn)(struct wl_display*); +typedef int (*wl_display_get_fd_fn)(struct wl_display*); +typedef void (*wl_display_cancel_read_fn)(struct wl_display*); + +// xkb +typedef void (*xkb_keymap_unref_fn)(struct xkb_keymap*); +typedef struct xkb_state* (*xkb_state_new_fn)(struct xkb_keymap*); +typedef void (*xkb_state_unref_fn)(struct xkb_state*); +typedef void (*xkb_context_unref_fn)(struct xkb_context*); +typedef struct xkb_context* (*xkb_context_new_fn)(enum xkb_context_flags); +typedef uint32_t (*xkb_keysym_to_utf32_fn)(xkb_keysym_t); + +typedef xkb_keysym_t (*xkb_state_key_get_one_sym_fn)( + struct xkb_state*, + xkb_keycode_t); + +typedef struct xkb_keymap* (*xkb_keymap_new_from_string_fn)( + struct xkb_context*, + const char*, + enum xkb_keymap_format, + enum xkb_keymap_compile_flags); + +typedef enum xkb_state_component (*xkb_state_update_mask_fn)( + struct xkb_state*, + xkb_mod_mask_t, + xkb_mod_mask_t, + xkb_mod_mask_t, + xkb_layout_index_t, + xkb_layout_index_t, + xkb_layout_index_t); + +typedef int (*xkb_keymap_key_repeats_fn)( + struct xkb_keymap*, + xkb_keycode_t); + +// wayland cursor +typedef struct wl_cursor_theme* (*wl_cursor_theme_load_fn)( + const char*, + int, + struct wl_shm*); + +typedef struct wl_cursor* (*wl_cursor_theme_get_cursor_fn)( + struct wl_cursor_theme*, + const char*); + +typedef struct wl_buffer* (*wl_cursor_image_get_buffer_fn)(struct wl_cursor_image*); + +// egl_window +struct wl_egl_window; +struct wl_surface; + +typedef struct wl_egl_window* (*wl_egl_window_create_fn)( + struct wl_surface*, + int, + int); + +typedef void (*wl_egl_window_destroy_fn)(struct wl_egl_window*); + +typedef void (*wl_egl_window_resize_fn)( + struct wl_egl_window*, + int, + int, + int, + int); + +typedef struct { + struct wl_buffer* buffer; + struct wl_surface* surface; + int hotspotX; + int hotspotY; +} WaylandCursor; + +typedef struct { + PalBool checkFeatures; + int monitorCount; + + void* handle; + void* xkbCommon; + void* libCursor; + void* libWaylandEgl; + struct wl_display* display; + struct wl_registry* registry; + struct xdg_wm_base* xdgBase; + struct wl_compositor* compositor; + struct wl_shm* shm; + struct wl_seat* seat; + struct wl_pointer* pointer; + struct wl_keyboard* keyboard; + struct zxdg_decoration_manager_v1* decorationManager; + struct zwp_pointer_constraints* pointerConstraints; + struct wl_surface* pointerSurface; + struct wl_surface* keyboardSurface; + struct wl_cursor_theme* cursorTheme; + + struct xkb_context* inputContext; + struct xkb_keymap* keymap; + struct xkb_state* state; + + const struct wl_interface* outputInterface; + const struct wl_interface* seatInterface; + const struct wl_interface* compositorInterface; + const struct wl_interface* registryInterface; + const struct wl_interface* surfaceInterface; + const struct wl_interface* shmInterface; + const struct wl_interface* bufferInterface; + const struct wl_interface* shmPoolInterface; + const struct wl_interface* regionInterface; + const struct wl_interface* pointerInterface; + const struct wl_interface* keyboardInterface; + + wl_display_connect_fn displayConnect; + wl_display_disconnect_fn displayDisconnect; + wl_display_roundtrip_fn displayRoundtrip; + wl_display_dispatch_fn displayDispatch; + wl_proxy_destroy_fn proxyDestroy; + wl_proxy_add_listener_fn proxyAddListener; + wl_proxy_marshal_constructor_v_fn proxyMarshalCnstructor; + wl_proxy_marshal_flags_fn proxyMarshalFlags; + wl_proxy_get_version_fn proxyGetVersion; + wl_display_get_error_fn getError; + wl_display_dispatch_pending_fn dispatchPending; + wl_display_flush_fn displayFlush; + wl_display_prepare_read_fn prepareRead; + wl_display_read_events_fn readEvents; + wl_display_get_fd_fn displayGetFd; + wl_display_cancel_read_fn cancelRead; + + xkb_keymap_unref_fn xkbKeymapUnref; + xkb_state_new_fn xkbStateNew; + xkb_state_unref_fn xkbStateUnref; + xkb_context_unref_fn xkbContextUnref; + xkb_context_new_fn xkbContextNew; + xkb_state_key_get_one_sym_fn xkbStateKeyGetOneSym; + xkb_keymap_new_from_string_fn xkbKeymapNewFromString; + xkb_keysym_to_utf32_fn xkbKeysymToUtf32; + xkb_state_update_mask_fn xkbStateUpdateMask; + xkb_keymap_key_repeats_fn xkbKeymapKeyRepeats; + + wl_cursor_theme_load_fn cursorThemeLoad; + wl_cursor_theme_get_cursor_fn cursorThemeGetCursor; + wl_cursor_image_get_buffer_fn cursorImageGetBuffer; + + EGLConfig eglFBConfig; + wl_egl_window_create_fn eglWindowCreate; + wl_egl_window_destroy_fn eglWindowDestroy; + wl_egl_window_resize_fn eglWindowResize; +} Wayland; + +extern Wayland s_Wl; + +#endif // PAL_HAS_WAYLAND_BACKEND +#endif // __linux__ +#endif // _PAL_WAYLAND_H \ No newline at end of file diff --git a/src/video/linux/wayland/pal_wayland_helper.c b/src/video/linux/wayland/pal_wayland_helper.c new file mode 100644 index 00000000..7751a791 --- /dev/null +++ b/src/video/linux/wayland/pal_wayland_helper.c @@ -0,0 +1,15 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_WAYLAND_BACKEND == 1 + +#include "pal_wayland_helper.h" +#include "pal_shared.h" + +#endif // PAL_HAS_WAYLAND_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/wayland/pal_wayland_helper.h b/src/video/linux/wayland/pal_wayland_helper.h new file mode 100644 index 00000000..0c5dbb24 --- /dev/null +++ b/src/video/linux/wayland/pal_wayland_helper.h @@ -0,0 +1,1888 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_WAYLAND_HELPER_H +#define _PAL_WAYLAND_HELPER_H +#ifdef __linux__ +#if PAL_HAS_WAYLAND_BACKEND == 1 +#include "pal_wayland.h" +#include +#include + +static inline void* registryBind( + struct wl_registry* wl_registry, + uint32_t name, + const struct wl_interface* interface, + uint32_t version) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_registry, + WL_REGISTRY_BIND, + interface, + version, + 0, + name, + interface->name, + version, + NULL); + + return (void*)id; +} + +static inline int registryAddListener( + struct wl_registry* wl_registry, + const struct wl_registry_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); +} + +static inline struct wl_registry* displayGetRegistry(struct wl_display* wl_display) +{ + struct wl_proxy* registry; + registry = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_display, + 1, // WL_DISPLAY_GET_REGISTRY + s_Wl.registryInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_display), + 0, + NULL); + + return (struct wl_registry*)registry; +} + +static inline int outputAddListener( + struct wl_output* wl_output, + const struct wl_output_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener((struct wl_proxy*)wl_output, (void (**)(void))listener, data); +} + +static inline struct wl_surface* compositorCreateSurface(struct wl_compositor* wl_compositor) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_compositor, + 0, // WL_COMPOSITOR_CREATE_SURFACE, + s_Wl.surfaceInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_compositor), + 0, + NULL); + + return (struct wl_surface*)id; +} + +static inline void surfaceCommit(struct wl_surface* wl_surface) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, + 6, // WL_SURFACE_COMMIT + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0); +} + +static inline void surfaceDestroy(struct wl_surface* wl_surface) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, + 0, // WL_SURFACE_DESTROY + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline struct wl_shm_pool* shmCreatePool( + struct wl_shm* wl_shm, + int32_t fd, + int32_t size) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_shm, + 0, // WL_SHM_CREATE_POOL + s_Wl.shmPoolInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm), + 0, + NULL, + fd, + size); + + return (struct wl_shm_pool*)id; +} + +static inline void shmPoolDestroy(struct wl_shm_pool* wl_shm_pool) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_shm_pool, + WL_SHM_POOL_DESTROY, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm_pool), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline struct wl_buffer* shmPoolCreateBuffer( + struct wl_shm_pool* wl_shm_pool, + int32_t offset, + int32_t width, + int32_t height, + int32_t stride, + uint32_t format) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_shm_pool, + WL_SHM_POOL_CREATE_BUFFER, + s_Wl.bufferInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm_pool), + 0, + NULL, + offset, + width, + height, + stride, + format); + + return (struct wl_buffer*)id; +} + +static inline void bufferDestroy(struct wl_buffer* wl_buffer) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_buffer, + WL_BUFFER_DESTROY, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_buffer), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline void surfaceAttach( + struct wl_surface* wl_surface, + struct wl_buffer* buffer, + int32_t x, + int32_t y) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, + WL_SURFACE_ATTACH, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0, + buffer, + x, + y); +} + +static inline void surfaceDamageBuffer( + struct wl_surface* wl_surface, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, + WL_SURFACE_DAMAGE_BUFFER, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0, + x, + y, + width, + height); +} + +static inline int surfaceAddListener( + struct wl_surface* wl_surface, + const struct wl_surface_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener((struct wl_proxy*)wl_surface, (void (**)(void))listener, data); +} + +static inline int seatAddListener( + struct wl_seat* wl_seat, + const struct wl_seat_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener((struct wl_proxy*)wl_seat, (void (**)(void))listener, data); +} + +static inline struct wl_pointer* seatGetPointer(struct wl_seat* wl_seat) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_seat, + WL_SEAT_GET_POINTER, + s_Wl.pointerInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_seat), + 0, + NULL); + + return (struct wl_pointer*)id; +} + +static inline struct wl_keyboard* seatGetKeyboard(struct wl_seat* wl_seat) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_seat, + WL_SEAT_GET_KEYBOARD, + s_Wl.keyboardInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_seat), + 0, + NULL); + + return (struct wl_keyboard*)id; +} + +static inline int pointerAddListener( + struct wl_pointer* wl_pointer, + const struct wl_pointer_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener((struct wl_proxy*)wl_pointer, (void (**)(void))listener, data); +} + +static inline void pointerSetCursor( + struct wl_pointer* wl_pointer, + uint32_t serial, + struct wl_surface* surface, + int32_t hotspot_x, + int32_t hotspot_y) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_pointer, + WL_POINTER_SET_CURSOR, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_pointer), + 0, + serial, + surface, + hotspot_x, + hotspot_y); +} + +static inline int keyboardAddListener( + struct wl_keyboard* wl_keyboard, + const struct wl_keyboard_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener((struct wl_proxy*)wl_keyboard, (void (**)(void))listener, data); +} + +static inline struct wl_region* compositorCreateRegion(struct wl_compositor* wl_compositor) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_compositor, + WL_COMPOSITOR_CREATE_REGION, + s_Wl.regionInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_compositor), + 0, + NULL); + + return (struct wl_region*)id; +} + +static inline void regionAdd( + struct wl_region* wl_region, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_region, + WL_REGION_ADD, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_region), + 0, + x, + y, + width, + height); +} + +static inline void surfaceSetOpaqueRegion( + struct wl_surface* wl_surface, + struct wl_region* region) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, + WL_SURFACE_SET_OPAQUE_REGION, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0, + region); +} + +static inline void regionDestroy(struct wl_region* wl_region) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_region, + WL_REGION_DESTROY, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_region), + WL_MARSHAL_FLAG_DESTROY); +} + +static void surfaceHandleEnter( + void* userData, + struct wl_surface* surface, + struct wl_output* output) +{ + WindowData* data = userData; + MonitorData* monitorData = findMonitorData((PalMonitor*)output); + if (!monitorData) { + return; + } + + // wayland sends multiple surface enter events + // if the surface spans multiple monitors + // we get all and return the highest dpi + // this assumes a surface can only span 4 monitors + // at the sametime but this might be wrong + + // wayland will trigger this event if the window gains focus + // so we check if the output is the same + SpanMonitor* span = nullptr; + if (data->monitorCount > 0) { + for (int i = 0; i < data->monitorCount; i++) { + if (data->monitors[i].monitor == (void*)output) { + // the monitor already exist in our array + // so we just update it + span = &data->monitors[i]; + span->dpi = monitorData->dpi; + break; + } + } + } + + if (span == nullptr) { + // new entry + span = &data->monitors[data->monitorCount]; + span->monitor = output; + span->dpi = monitorData->dpi; + data->monitorCount++; + } + + if (data->dpi == 0) { + // this is triggered when the window is created + // we cache the DPI and skip the event + data->dpi = monitorData->dpi; + return; + } + + // the code below should be skipped if users are not + // interested in DPI changed events + PalDispatchMode mode = PAL_DISPATCH_NONE; + PalEventType type = PAL_EVENT_MONITOR_DPI_CHANGED; + if (!s_Video.eventDriver) { + return; + } + + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, type); + if (mode == PAL_DISPATCH_NONE) { + return; + } + + // get the highest dpi and check if the it has changed + int maxDPI = 96; // baseline + for (int i = 0; i < data->monitorCount; i++) { + if (!data->monitors[i].monitor) { + // not a valid index. continue + continue; + } + + if (data->monitors[i].dpi > maxDPI) { + // new highest + maxDPI = data->monitors[i].dpi; + } + } + + if (maxDPI != data->dpi) { + data->dpi = maxDPI; + + PalEvent event = {0}; + event.type = type; + event.data = maxDPI; + event.data2 = palPackPointer((void*)data->window); + palPushEvent(driver, &event); + } +} + +static void surfaceHandleLeave( + void* userData, + struct wl_surface* surface, + struct wl_output* output) +{ + // remove the monitor from our span monitor list + WindowData* data = userData; + MonitorData* monitorData = findMonitorData((PalMonitor*)output); + if (!monitorData) { + return; + } + + for (int i = 0; i < data->monitorCount; i++) { + if (data->monitors[i].monitor == (void*)output) { + // found our monitor + // we might want to pack the array but its just 4 monitors + // so we leave it like that + data->monitors[i].monitor = nullptr; + data->monitorCount--; + break; + } + } +} + +static struct wl_surface_listener surfaceListener = { + .enter = surfaceHandleEnter, + .leave = surfaceHandleLeave}; + +static void pointerHandleEnter( + void* userData, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface, + wl_fixed_t surface_x, + wl_fixed_t surface_y) +{ + WindowData* data = findWindowData((PalWindow*)surface); + if (!data) { + return; + } + + if (data->cursor) { + // our window + WaylandCursor* cursor = data->cursor; + pointerSetCursor(pointer, serial, cursor->surface, cursor->hotspotX, cursor->hotspotY); + } + + // cache the surface the pointer is currently on + s_Wl.pointerSurface = surface; +} + +static void pointerHandleLeave( + void* userData, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface) +{ + if (s_Wl.pointerSurface == surface) { + s_Wl.pointerSurface == nullptr; + } +} + +static void pointerHandleMotion( + void* userData, + struct wl_pointer* pointer, + uint32_t time, + wl_fixed_t surface_x, + wl_fixed_t surface_y) +{ + int x = wl_fixed_to_int(surface_x); + int y = wl_fixed_to_int(surface_y); + const int dx = x - s_Mouse.lastX; + const int dy = y - s_Mouse.lastY; + + PalDispatchMode mode = PAL_DISPATCH_NONE; + PalWindow* window = (PalWindow*)s_Wl.pointerSurface; + if (s_Video.eventDriver && window) { + // we only push a mouse move only if we are on a window + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_MOUSE_MOVE; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackInt32(x, y); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + + // push a mouse delta event + type = PAL_EVENT_MOUSE_DELTA; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackInt32(dx, dy); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + + s_Mouse.lastX = x; + s_Mouse.lastY = y; + s_Mouse.dx = dx; + s_Mouse.dy = dy; +} + +static void pointerHandleButton( + void* userData, + struct wl_pointer* pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state) +{ + PalWindow* window = nullptr; + if (s_Wl.pointerSurface) { + window = (PalWindow*)s_Wl.pointerSurface; + + } else { + // cannot recieve events without a focused surface + return; + } + + PalBool pressed = state == WL_POINTER_BUTTON_STATE_PRESSED; + PalMouseButton _button = 0; + PalEventType type = PAL_EVENT_MOUSE_BUTTONUP; + + if (button == BTN_LEFT) { + _button = PAL_MOUSE_BUTTON_LEFT; + + } else if (button == BTN_RIGHT) { + _button = PAL_MOUSE_BUTTON_RIGHT; + + } else if (button == BTN_MIDDLE) { + _button = PAL_MOUSE_BUTTON_MIDDLE; + + } else if (button == BTN_SIDE) { + _button = PAL_MOUSE_BUTTON_X1; + + } else if (button == BTN_EXTRA) { + _button = PAL_MOUSE_BUTTON_X2; + } + + if (pressed) { + type = PAL_EVENT_MOUSE_BUTTONDOWN; + } + + s_Mouse.state[_button] = pressed; + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + + // since we are not drawing decorations for users + // they need the serial in order to draw their decorations + // we put the serial at the upper 32 so ABI is preserved + event.data = palPackUint32(_button, serial); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } +} + +static void pointerHandleAxis( + void* userData, + struct wl_pointer* pointer, + uint32_t time, + uint32_t axis, + wl_fixed_t value) +{ + double delta = wl_fixed_to_double(value); + if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + s_Mouse.tmpScrollX += delta; + s_Mouse.accumScrollX += delta; + + } else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + s_Mouse.tmpScrollY += delta; + s_Mouse.accumScrollY += delta; + } + + s_Mouse.pendingScroll = PAL_TRUE; +} + +static void pointerHandleAxisDiscrete( + void* userData, + struct wl_pointer* pointer, + uint32_t axis, + int32_t discrete) +{ + if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + s_Mouse.tmpScrollX += discrete; + s_Mouse.accumScrollX += discrete; + + } else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + s_Mouse.tmpScrollY += discrete; + s_Mouse.accumScrollY += discrete; + } + + s_Mouse.pendingScroll = PAL_TRUE; +} + +static void pointerHandleFrame( + void* userData, + struct wl_pointer* pointer) +{ + if (!s_Mouse.pendingScroll) { + // no wheel event + return; + } + + PalWindow* window = nullptr; + if (s_Wl.pointerSurface) { + window = (PalWindow*)s_Wl.pointerSurface; + + } else { + // cannot recieve events without a focused surface + return; + } + + const int dx = (int)s_Mouse.accumScrollX; + const int dy = (int)s_Mouse.accumScrollY; + if (s_Video.eventDriver) { + PalEventType type = PAL_EVENT_MOUSE_WHEEL; + PalEventDriver* driver = s_Video.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackUint32(dx, dy); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + + s_Mouse.WheelX = dx; + s_Mouse.WheelY = dy; + s_Mouse.accumScrollX -= dx; + s_Mouse.accumScrollY -= dy; + s_Mouse.pendingScroll = PAL_FALSE; +} + +static void pointerHandleAxisSource( + void* userData, + struct wl_pointer* pointer, + uint32_t axis_source) +{ +} + +static void pointerHandleAxisStop( + void* userData, + struct wl_pointer* pointer, + uint32_t time, + uint32_t axis) +{ +} + +static void keyboardHandleEnter( + void* userData, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface, + struct wl_array* keys) +{ + // cache the surface the keyboard is currently on + s_Wl.keyboardSurface = surface; +} + +static void keyboardHandleLeave( + void* userData, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface) +{ + if (s_Wl.keyboardSurface == surface) { + s_Wl.keyboardSurface == nullptr; + } +} + +static void keyboardHandleRemap( + void* userData, + struct wl_keyboard* keyboard, + uint32_t format, + int32_t fd, + uint32_t size) +{ + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + struct xkb_keymap* keymap = nullptr; + struct xkb_state* state = nullptr; + + char* keymapStr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); + if (keymapStr == MAP_FAILED) { + close(fd); + return; + } + + keymap = s_Wl.xkbKeymapNewFromString( + s_Wl.inputContext, + keymapStr, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + + if (!keymap) { + return; + } + + munmap(keymapStr, size); + close(fd); + + state = s_Wl.xkbStateNew(keymap); + if (!state) { + return; + } + + // check if we have old keymap and state + if (s_Wl.state) { + s_Wl.xkbStateUnref(s_Wl.state); + s_Wl.xkbKeymapUnref(s_Wl.keymap); + } + + s_Wl.state = state; + s_Wl.keymap = keymap; + s_Keyboard.frequency = palGetPerformanceFrequency(); +} + +static void keyboardHandleKey( + void* userData, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state) +{ + PalWindow* window = nullptr; + if (s_Wl.keyboardSurface) { + window = (PalWindow*)s_Wl.keyboardSurface; + + } else { + // cannot recieve events without a focused surface + return; + } + + PalScancode scancode = 0; + PalKeycode keycode = 0; + PalBool pressed = (state == WL_KEYBOARD_KEY_STATE_PRESSED); + PalEventType type = PAL_EVENT_KEYUP; + PalDispatchMode mode = PAL_DISPATCH_NONE; + xkb_keysym_t keySym = s_Wl.xkbStateKeyGetOneSym(s_Wl.state, key + 8); + + // special handling + if (key == 119) { + scancode = PAL_SCANCODE_PAUSE; + } else if (key == 107) { + scancode = PAL_SCANCODE_END; + } else if (key == 103) { + scancode = PAL_SCANCODE_UP; + } else if (key == 102) { + scancode = PAL_SCANCODE_HOME; + + } else { + scancode = s_Keyboard.scancodes[key]; + } + + // printable and text input keys are from the range + // 32 (PAL_KEYCODE_SPACE) and 122 (PAL_KEYCODE_Z) + // The rest are almost the same as their scancode + // Maybe there will be a layout that makes this wrong + // but for now this works + if (keySym >= XKB_KEY_space && keySym <= XKB_KEY_z) { + // a printable or input key + keycode = s_Keyboard.keycodes[keySym]; + + } else { + // Since PalKeycode and PalScancode have the same integers + // we can make a direct cast without a table + // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) + keycode = (PalKeycode)(uint32_t)scancode; + } + + // If we got a keySym but its not mapped into our keycode array + // we do a direct cast as well + if (keycode == PAL_KEYCODE_UNKNOWN) { + keycode = (PalKeycode)(uint32_t)scancode; + } + + s_Keyboard.scancodeState[scancode] = pressed; + s_Keyboard.keycodeState[keycode] = pressed; + + // check for key repeats + if (pressed) { + if (s_Wl.xkbKeymapKeyRepeats(s_Wl.keymap, key + 8)) { + s_Keyboard.repeatKey = keycode; + s_Keyboard.repeatScancode = scancode; + s_Keyboard.timer = getCurrentTime() + s_Keyboard.repeatDelay; + + } else { + s_Keyboard.repeatKey = 0; + } + + type = PAL_EVENT_KEYDOWN; + + } else { + // key release + if (s_Keyboard.repeatKey == keycode) { + s_Keyboard.repeatKey = 0; + } + } + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackUint32(keycode, scancode); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + + // check for char event if enabled + type = PAL_EVENT_KEYCHAR; + mode = palGetEventDispatchMode(driver, type); + if (mode == PAL_DISPATCH_NONE) { + return; + } + + uint32_t codepoint = s_Wl.xkbKeysymToUtf32(keySym); + if (codepoint <= 0) { + return; + } + + PalEvent event = {0}; + event.type = type; + event.data = codepoint; + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } +} + +static void keyboardHandleRepeatInfo( + void* userData, + struct wl_keyboard* keyboard, + int32_t rate, + int32_t delay) +{ + if (s_Wl.keyboard == keyboard) { + s_Keyboard.repeatDelay = delay; + s_Keyboard.repeatRate = rate; + + } else { + if (s_Keyboard.repeatDelay == 0) { + s_Keyboard.repeatDelay = 500; + s_Keyboard.repeatRate = 30; + } + } +} + +static void keyboardHandleModifiers( + void* userData, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group) +{ + if (s_Wl.state) { + s_Wl.xkbStateUpdateMask(s_Wl.state, mods_depressed, mods_latched, mods_locked, group, 0, 0); + } +} + +static struct wl_pointer_listener pointerListener = { + .enter = pointerHandleEnter, + .leave = pointerHandleLeave, + .motion = pointerHandleMotion, + .button = pointerHandleButton, + .axis = pointerHandleAxis, + .axis_discrete = pointerHandleAxisDiscrete, + .frame = pointerHandleFrame, + .axis_source = pointerHandleAxisSource, + .axis_stop = pointerHandleAxisStop}; + +static struct wl_keyboard_listener keyboardListener = { + .enter = keyboardHandleEnter, + .leave = keyboardHandleLeave, + .keymap = keyboardHandleRemap, + .key = keyboardHandleKey, + .repeat_info = keyboardHandleRepeatInfo, + .modifiers = keyboardHandleModifiers}; + +static void seatHandleCapabilities( + void* userData, + struct wl_seat* seat, + enum wl_seat_capability caps) +{ + if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { + s_Wl.keyboard = seatGetKeyboard(seat); + keyboardAddListener(s_Wl.keyboard, &keyboardListener, nullptr); + } + + if (caps & WL_SEAT_CAPABILITY_POINTER) { + s_Wl.pointer = seatGetPointer(seat); + pointerAddListener(s_Wl.pointer, &pointerListener, nullptr); + } +} + +static void seatHandleName( + void* userData, + struct wl_seat* seat, + const char* name) +{ +} + +static struct wl_seat_listener seatListener = { + .capabilities = seatHandleCapabilities, + .name = seatHandleName}; + +// Protocols +struct xdg_wm_base; +struct xdg_surface; +struct xdg_toplevel; + +// forward declare +static struct wl_buffer* createShmBuffer( + int width, + int height, + const uint8_t* pixels, + PalBool cursor); + +static const struct wl_interface* xdg_shell_types[26]; + +static const struct wl_message xdg_wm_base_requests[] = { + {"destroy", "", xdg_shell_types + 0}, + {"create_positioner", "n", xdg_shell_types + 4}, + {"get_xdg_surface", "no", xdg_shell_types + 5}, + {"pong", "u", xdg_shell_types + 0}, +}; + +static const struct wl_message xdg_wm_base_events[] = { + {"ping", "u", xdg_shell_types + 0}, +}; + +const struct wl_interface xdg_wm_base_interface = { + "xdg_wm_base", + 6, + 4, + xdg_wm_base_requests, + 1, + xdg_wm_base_events, +}; + +static const struct wl_message xdg_positioner_requests[] = { + {"destroy", "", xdg_shell_types + 0}, + {"set_size", "ii", xdg_shell_types + 0}, + {"set_anchor_rect", "iiii", xdg_shell_types + 0}, + {"set_anchor", "u", xdg_shell_types + 0}, + {"set_gravity", "u", xdg_shell_types + 0}, + {"set_constraint_adjustment", "u", xdg_shell_types + 0}, + {"set_offset", "ii", xdg_shell_types + 0}, + {"set_reactive", "3", xdg_shell_types + 0}, + {"set_parent_size", "3ii", xdg_shell_types + 0}, + {"set_parent_configure", "3u", xdg_shell_types + 0}, +}; + +const struct wl_interface xdg_positioner_interface = { + "xdg_positioner", + 6, + 10, + xdg_positioner_requests, + 0, + NULL, +}; + +static const struct wl_message xdg_surface_requests[] = { + {"destroy", "", xdg_shell_types + 0}, + {"get_toplevel", "n", xdg_shell_types + 7}, + {"get_popup", "n?oo", xdg_shell_types + 8}, + {"set_window_geometry", "iiii", xdg_shell_types + 0}, + {"ack_configure", "u", xdg_shell_types + 0}, +}; + +static const struct wl_message xdg_surface_events[] = { + {"configure", "u", xdg_shell_types + 0}, +}; + +const struct wl_interface xdg_surface_interface = { + "xdg_surface", + 6, + 5, + xdg_surface_requests, + 1, + xdg_surface_events, +}; + +static const struct wl_message xdg_toplevel_requests[] = { + {"destroy", "", xdg_shell_types + 0}, + {"set_parent", "?o", xdg_shell_types + 11}, + {"set_title", "s", xdg_shell_types + 0}, + {"set_app_id", "s", xdg_shell_types + 0}, + {"show_window_menu", "ouii", xdg_shell_types + 12}, + {"move", "ou", xdg_shell_types + 16}, + {"resize", "ouu", xdg_shell_types + 18}, + {"set_max_size", "ii", xdg_shell_types + 0}, + {"set_min_size", "ii", xdg_shell_types + 0}, + {"set_maximized", "", xdg_shell_types + 0}, + {"unset_maximized", "", xdg_shell_types + 0}, + {"set_fullscreen", "?o", xdg_shell_types + 21}, + {"unset_fullscreen", "", xdg_shell_types + 0}, + {"set_minimized", "", xdg_shell_types + 0}, +}; + +static const struct wl_message xdg_toplevel_events[] = { + {"configure", "iia", xdg_shell_types + 0}, + {"close", "", xdg_shell_types + 0}, + {"configure_bounds", "4ii", xdg_shell_types + 0}, + {"wm_capabilities", "5a", xdg_shell_types + 0}, +}; + +const struct wl_interface xdg_toplevel_interface = { + "xdg_toplevel", + 6, + 14, + xdg_toplevel_requests, + 4, + xdg_toplevel_events, +}; + +static const struct wl_message xdg_popup_requests[] = { + {"destroy", "", xdg_shell_types + 0}, + {"grab", "ou", xdg_shell_types + 22}, + {"reposition", "3ou", xdg_shell_types + 24}, +}; + +static const struct wl_message xdg_popup_events[] = { + {"configure", "iiii", xdg_shell_types + 0}, + {"popup_done", "", xdg_shell_types + 0}, + {"repositioned", "3u", xdg_shell_types + 0}, +}; + +const struct wl_interface xdg_popup_interface = { + "xdg_popup", + 6, + 3, + xdg_popup_requests, + 3, + xdg_popup_events, +}; + +struct xdg_wm_base_listener { + void (*ping)( + void*, + struct xdg_wm_base*, + uint32_t); +}; + +struct xdg_surface_listener { + void (*configure)( + void*, + struct xdg_surface*, + uint32_t); +}; + +struct xdg_toplevel_listener { + // clang-format off + void (*configure)(void*, struct xdg_toplevel*, int32_t, int32_t, struct wl_array*); + void (*close)(void*, struct xdg_toplevel*); + void (*configure_bounds)(void*, struct xdg_toplevel*, int32_t, int32_t); + void (*wm_capabilities)(void*, struct xdg_toplevel*, struct wl_array*); + // clang-format on +}; + +static inline void xdgWmBasePong( + struct xdg_wm_base* xdg_wm_base, + uint32_t serial) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_wm_base, + 3, // XDG_WM_BASE_PONG + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_wm_base), + 0, + serial); +} + +static inline int xdgWmBaseAddListener( + struct xdg_wm_base* xdg_wm_base, + const struct xdg_wm_base_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener((struct wl_proxy*)xdg_wm_base, (void (**)(void))listener, data); +} + +static inline struct xdg_surface* xdgWmBaseGetXdgSurface( + struct xdg_wm_base* xdg_wm_base, + struct wl_surface* surface) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_wm_base, + 2, // XDG_WM_BASE_GET_XDG_SURFACE, + &xdg_surface_interface, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_wm_base), + 0, + NULL, + surface); + + return (struct xdg_surface*)id; +} + +static inline struct xdg_toplevel* xdgSurfaceGetToplevel(struct xdg_surface* xdg_surface) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_surface, + 1, // XDG_SURFACE_GET_TOPLEVEL, + &xdg_toplevel_interface, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), + 0, + NULL); + + return (struct xdg_toplevel*)id; +} + +static inline void xdgSurfaceAckConfigure( + struct xdg_surface* xdg_surface, + uint32_t serial) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_surface, + 4, // XDG_SURFACE_ACK_CONFIGURE + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), + 0, + serial); +} + +static void wmBaseHandlePing( + void* data, + struct xdg_wm_base* base, + uint32_t serial) +{ + xdgWmBasePong(base, serial); +} + +static void xdgSurfaceHandleConfigure( + void* data, + struct xdg_surface* surface, + uint32_t serial) +{ + WindowData* winData = (WindowData*)data; + xdgSurfaceAckConfigure(surface, serial); + + // push and resolve any pending events + if (!winData->skipConfigure) { + if (winData->pushConfigureEvent) { + if (winData->eglWindow) { + s_Wl.eglWindowResize(winData->eglWindow, winData->w, winData->h, 0, 0); + + } else { + // create a new buffer with the new size + struct wl_buffer* buffer = nullptr; + buffer = createShmBuffer(winData->w, winData->h, nullptr, PAL_FALSE); + if (!buffer) { + return; + } + + struct wl_surface* _surface = nullptr; + _surface = (struct wl_surface*)winData->window; + + surfaceAttach(_surface, buffer, 0, 0); + surfaceDamageBuffer(_surface, 0, 0, winData->w, winData->h); + surfaceCommit(_surface); + + // destroy old buffer + bufferDestroy(winData->buffer); + winData->buffer = buffer; + } + + // push a window resize event + if (s_Video.eventDriver) { + PalEventType type = PAL_EVENT_WINDOW_SIZE; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(s_Video.eventDriver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackUint32(winData->w, winData->h); + event.data2 = palPackPointer(winData->window); + palPushEvent(s_Video.eventDriver, &event); + } + } + + winData->pushConfigureEvent = PAL_FALSE; + } + } + + // pending state + if (!winData->skipState) { + if (!winData->pushStateEvent) { + return; + } + + // push a window state event + // we dont recreate buffers over here + // since we already create the buffer with the new size + if (s_Video.eventDriver) { + PalEventType type = PAL_EVENT_WINDOW_STATE; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(s_Video.eventDriver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = winData->state; + event.data2 = palPackPointer(winData->window); + palPushEvent(s_Video.eventDriver, &event); + } + } + + winData->pushStateEvent = PAL_FALSE; + } +} + +static void xdgToplevelHandleConfigure( + void* data, + struct xdg_toplevel* toplevel, + int32_t width, + int32_t height, + struct wl_array* states) +{ + WindowData* winData = (WindowData*)data; + uint32_t* state; + PalBool activated = PAL_FALSE; + wl_array_for_each(state, states) + { + // we need only maximized + if (*state == 1) { // XDG_TOPLEVEL_STATE_MAXIMIZED + if (winData->state != PAL_WINDOW_STATE_MAXIMIZED) { + winData->state = PAL_WINDOW_STATE_MAXIMIZED; + winData->pushStateEvent = PAL_TRUE; + } + + } else if (*state == 4) { // XDG_TOPLEVEL_STATE_ACTIVATED + activated = PAL_TRUE; + } + } + + if (width > 0 && height > 0) { + if (width != winData->w || height != winData->h) { + // size change + winData->pushConfigureEvent = PAL_TRUE; + } + + winData->w = width; + winData->h = height; + } + + if (activated && !winData->focused) { + // focus gained + winData->focused = PAL_TRUE; + + } else if (!activated && winData->focused) { + // focus lost + winData->focused = PAL_FALSE; + + } else { + // discard double focus gained and double focus lost + return; + } + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_NONE; + PalEventType type = PAL_EVENT_WINDOW_FOCUS; + mode = palGetEventDispatchMode(driver, type); + + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = winData->focused; + event.data2 = palPackPointer(winData->window); + palPushEvent(driver, &event); + } + } +} + +static void xdgToplevelHandleClose( + void* data, + struct xdg_toplevel* toplevel) +{ + WindowData* winData = (WindowData*)data; + if (s_Video.eventDriver) { + PalEventType type = PAL_EVENT_WINDOW_CLOSE; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(s_Video.eventDriver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data2 = palPackPointer(winData->window); + palPushEvent(s_Video.eventDriver, &event); + } + } +} + +static inline int xdgSurfaceAddListener( + struct xdg_surface* xdg_surface, + const struct xdg_surface_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener((struct wl_proxy*)xdg_surface, (void (**)(void))listener, data); +} + +static inline void xdgSurfaceDestroy(struct xdg_surface* xdg_surface) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_surface, + 0, // XDG_SURFACE_DESTROY + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline void xdgToplevelDestroy(struct xdg_toplevel* xdg_toplevel) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 0, // XDG_TOPLEVEL_DESTROY + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline void xdgToplevelSetTitle( + struct xdg_toplevel* xdg_toplevel, + const char* title) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 2, // XDG_TOPLEVEL_SET_TITLE + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0, + title); +} + +static inline void xdgToplevelSetMaximized(struct xdg_toplevel* xdg_toplevel) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 9, // XDG_TOPLEVEL_SET_MAXIMIZED + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0); +} + +static inline void xdgToplevelSetMinimized(struct xdg_toplevel* xdg_toplevel) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 13, // XDG_TOPLEVEL_SET_MINIMIZED + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0); +} + +static inline int xdgToplevelAddListener( + struct xdg_toplevel* xdg_toplevel, + const struct xdg_toplevel_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener((struct wl_proxy*)xdg_toplevel, (void (**)(void))listener, data); +} + +static inline void xdgToplevelSetMinSize( + struct xdg_toplevel* xdg_toplevel, + int32_t width, + int32_t height) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 8, // XDG_TOPLEVEL_SET_MIN_SIZE + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0, + width, + height); +} + +static inline void xdgToplevelSetMaxSize( + struct xdg_toplevel* xdg_toplevel, + int32_t width, + int32_t height) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 7, // XDG_TOPLEVEL_SET_MAX_SIZE + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0, + width, + height); +} + +static inline void xdgToplevelSetAppId( + struct xdg_toplevel* xdg_toplevel, + const char* app_id) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 3, // XDG_TOPLEVEL_SET_APP_ID + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0, + app_id); +} + +static inline void xdgToplevelUnsetMaximized(struct xdg_toplevel* xdg_toplevel) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 10, // XDG_TOPLEVEL_UNSET_MAXIMIZED + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0); +} + +static const struct xdg_wm_base_listener wmBaseListener = {.ping = wmBaseHandlePing}; + +struct xdg_toplevel; +struct zxdg_decoration_manager_v1; +struct zxdg_toplevel_decoration_v1; + +struct zxdg_toplevel_decoration_v1_listener { + void (*configure)( + void*, + struct zxdg_toplevel_decoration_v1*, + uint32_t); +}; + +const struct wl_interface zxdg_decoration_manager_v1_interface; +const struct wl_interface zxdg_toplevel_decoration_v1_interface; + +static inline void +zxdgDecorationManagerV1Destroy(struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)zxdg_decoration_manager_v1, + 0, // ZXDG_DECORATION_MANAGER_V1_DESTROY + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_decoration_manager_v1), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline struct zxdg_toplevel_decoration_v1* zxdgGetToplevelDecoration( + struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1, + struct xdg_toplevel* toplevel) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)zxdg_decoration_manager_v1, + 1, // ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, + &zxdg_toplevel_decoration_v1_interface, + s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_decoration_manager_v1), + 0, + NULL, + toplevel); + + return (struct zxdg_toplevel_decoration_v1*)id; +} + +static inline int zxdgToplevelDecorationV1AddListener( + struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, + const struct zxdg_toplevel_decoration_v1_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy*)zxdg_toplevel_decoration_v1, + (void (**)(void))listener, + data); +} + +static inline void +zxdgToplevelDecorationV1Destroy(struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)zxdg_toplevel_decoration_v1, + 0, // ZXDG_TOPLEVEL_DECORATION_V1_DESTROY + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_toplevel_decoration_v1), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline void zxdgToplevelDecorationV1SetMode( + struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, + uint32_t mode) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)zxdg_toplevel_decoration_v1, + 1, // ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_toplevel_decoration_v1), + 0, + mode); +} + +static void setupXdgShellProtocol() +{ + xdg_shell_types[0] = NULL; + xdg_shell_types[1] = NULL; + xdg_shell_types[2] = NULL; + xdg_shell_types[3] = NULL; + xdg_shell_types[4] = &xdg_positioner_interface; + xdg_shell_types[5] = &xdg_surface_interface; + xdg_shell_types[6] = s_Wl.surfaceInterface; + xdg_shell_types[7] = &xdg_toplevel_interface; + xdg_shell_types[8] = &xdg_popup_interface; + xdg_shell_types[9] = &xdg_surface_interface; + xdg_shell_types[10] = &xdg_positioner_interface; + xdg_shell_types[11] = &xdg_toplevel_interface; + xdg_shell_types[12] = s_Wl.seatInterface; + xdg_shell_types[13] = NULL; + xdg_shell_types[14] = NULL; + xdg_shell_types[15] = NULL; + xdg_shell_types[16] = s_Wl.seatInterface; + xdg_shell_types[17] = NULL; + xdg_shell_types[18] = s_Wl.seatInterface; + xdg_shell_types[19] = NULL; + xdg_shell_types[20] = NULL; + xdg_shell_types[21] = s_Wl.outputInterface; + xdg_shell_types[22] = s_Wl.seatInterface; + xdg_shell_types[23] = NULL; + xdg_shell_types[24] = &xdg_positioner_interface; + xdg_shell_types[25] = NULL; +} + +static const struct wl_interface* xdg_decoration_unstable_v1_types[] = { + NULL, + &zxdg_toplevel_decoration_v1_interface, + &xdg_toplevel_interface, +}; + +static const struct wl_message zxdg_decoration_manager_v1_requests[] = { + {"destroy", "", xdg_decoration_unstable_v1_types + 0}, + {"get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1}, +}; + +const struct wl_interface zxdg_decoration_manager_v1_interface = { + "zxdg_decoration_manager_v1", + 1, + 2, + zxdg_decoration_manager_v1_requests, + 0, + NULL, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = { + {"destroy", "", xdg_decoration_unstable_v1_types + 0}, + {"set_mode", "u", xdg_decoration_unstable_v1_types + 0}, + {"unset_mode", "", xdg_decoration_unstable_v1_types + 0}, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_events[] = { + {"configure", "u", xdg_decoration_unstable_v1_types + 0}, +}; + +const struct wl_interface zxdg_toplevel_decoration_v1_interface = { + "zxdg_toplevel_decoration_v1", + 1, + 3, + zxdg_toplevel_decoration_v1_requests, + 1, + zxdg_toplevel_decoration_v1_events, +}; + +static void zxdgDecorationHandleConfigure( + void* data, + struct zxdg_toplevel_decoration_v1* dec, + uint32_t mode) +{ + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalDispatchMode dispatchMode = PAL_DISPATCH_NONE; + PalEventType type = PAL_EVENT_WINDOW_DECORATION_MODE; + dispatchMode = palGetEventDispatchMode(driver, type); + + if (dispatchMode != PAL_DISPATCH_NONE) { + PalDecorationMode decorMode = PAL_DECORATION_MODE_SERVER_SIDE; + if (mode == 0 || mode == 1) { + // client side decoration + decorMode = PAL_DECORATION_MODE_CLIENT_SIDE; + } + + PalEvent event = {0}; + event.type = type; + event.data = decorMode; + event.data2 = palPackPointer(data); + palPushEvent(driver, &event); + } + } +} + +static int createShmFile(uint64_t size) +{ + char template[] = "/tmp/pal-shm-XXXXXX"; + int fd = mkstemp(template); + if (fd < 0) { + return -1; + } + + unlink(template); + if (ftruncate(fd, size) < 0) { + return -1; + } + + return fd; +} + +static struct wl_buffer* createShmBuffer( + int width, + int height, + const uint8_t* pixels, + PalBool cursor) +{ + int stride = width * 4; + uint64_t size = stride * height; + struct wl_buffer* buffer = nullptr; + struct wl_shm_pool* pool = nullptr; + void* data = nullptr; + + int fd = createShmFile(size); + if (fd == -1) { + return nullptr; + } + + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + return nullptr; + } + + enum wl_shm_format format = WL_SHM_FORMAT_XRGB8888; + if (cursor) { + format = WL_SHM_FORMAT_ARGB8888; + uint32_t* dataPixels = (uint32_t*)data; + + // convert from RGBA8 to ARGB32 + for (int i = 0; i < width * height; i++) { + uint8_t r = pixels[i * 4 + 0]; // Red + uint8_t g = pixels[i * 4 + 1]; // Green + uint8_t b = pixels[i * 4 + 2]; // Blue + uint8_t a = pixels[i * 4 + 3]; // Alpha + + // clang-format off + dataPixels[i] = ((unsigned long)a << 24) | + ((unsigned long)r << 16) | + ((unsigned long)g << 8) | + ((unsigned long)b); + // clang-format on + } + + } else { + memset(data, 0xFF, size); // white + } + + pool = shmCreatePool(s_Wl.shm, fd, size); + if (!pool) { + return nullptr; + } + + buffer = shmPoolCreateBuffer(pool, 0, width, height, stride, format); + if (!buffer) { + return nullptr; + } + + shmPoolDestroy(pool); + munmap(data, size); + close(fd); + return buffer; +} + +static void outputGeometry( + void* data, + struct wl_output* output, + int32_t x, + int32_t y, + int32_t, // we dont need physical size + int32_t, // we dont need physical size + int32_t, // we dont need subpixel + const char* make, + const char* model, + int32_t transform) +{ + MonitorData* monitorData = data; + monitorData->x = x; + monitorData->y = y; + + switch (transform) { + case WL_OUTPUT_TRANSFORM_NORMAL: + case WL_OUTPUT_TRANSFORM_180: { + monitorData->orientation = PAL_ORIENTATION_LANDSCAPE; + break; + } + + case WL_OUTPUT_TRANSFORM_90: + case WL_OUTPUT_TRANSFORM_270: { + monitorData->orientation = PAL_ORIENTATION_PORTRAIT; + break; + } + + case WL_OUTPUT_TRANSFORM_FLIPPED: + case WL_OUTPUT_TRANSFORM_FLIPPED_180: { + monitorData->orientation = PAL_ORIENTATION_LANDSCAPE_FLIPPED; + break; + } + + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_FLIPPED_270: { + monitorData->orientation = PAL_ORIENTATION_PORTRAIT_FLIPPED; + break; + } + } + + snprintf(monitorData->name, 32, "%s %s", make, model); +} + +static void outputMode( + void* data, + struct wl_output* output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh) +{ + MonitorData* monitorData = data; + if (flags & WL_OUTPUT_MODE_CURRENT) { + monitorData->w = width; + monitorData->h = height; + monitorData->refreshRate = (refresh + 500) / 1000; + + // wayland only sends the current mode + monitorData->mode.bpp = 0; + monitorData->mode.width = width; + monitorData->mode.height = height; + monitorData->mode.refreshRate = (refresh + 500) / 1000; + } +} + +static void outputScale( + void* data, + struct wl_output* output, + int32_t scale) +{ + MonitorData* monitorData = data; + float dpi = (float)scale * 96.0f; + monitorData->dpi = (uint32_t)dpi; +} + +static void outputDone( + void* data, + struct wl_output* output) +{ +} + +static const struct wl_output_listener s_OutputListener = { + .geometry = outputGeometry, + .mode = outputMode, + .done = outputDone, + .scale = outputScale}; + +static const struct wl_output_listener s_DefaultModeListener = { + .geometry = outputGeometry, + .mode = outputMode, + .done = outputDone, + .scale = outputScale}; + +static void globalHandle( + void* data, + struct wl_registry* registry, + uint32_t name, + const char* interface, + uint32_t version) +{ + if (s_Wl.checkFeatures) { + PalVideoFeatures features = 0; + features |= PAL_VIDEO_FEATURE_HIGH_DPI; + features |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; + features |= PAL_VIDEO_FEATURE_MULTI_MONITORS; + features |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; + features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; + + s_Video.features = features; + s_Wl.checkFeatures = PAL_FALSE; + } + + if (strcmp(interface, "wl_compositor") == 0) { + s_Wl.compositor = registryBind(registry, name, s_Wl.compositorInterface, 4); + + } else if (strcmp(interface, "xdg_wm_base") == 0) { + s_Wl.xdgBase = registryBind(registry, name, &xdg_wm_base_interface, 1); + + xdgWmBaseAddListener(s_Wl.xdgBase, &wmBaseListener, nullptr); + + } else if (strcmp(interface, "wl_shm") == 0) { + s_Wl.shm = registryBind(registry, name, s_Wl.shmInterface, 1); + + } else if (strcmp(interface, "wl_seat") == 0) { + s_Wl.seat = registryBind(registry, name, s_Wl.seatInterface, 5); + + seatAddListener(s_Wl.seat, &seatListener, nullptr); + + } else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) { + s_Wl.decorationManager = + registryBind(registry, name, &zxdg_decoration_manager_v1_interface, 1); + + s_Video.features |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; + + } else if (strcmp(interface, "wl_output") == 0) { + // wayland does not let use query monitors directly + // so we enumerate and store at init and update the + // cache when a monitor is added or removed + MonitorData* monitorData = getFreeMonitorData(); + if (!monitorData) { + return; + } + + struct wl_output* output = nullptr; + output = registryBind(s_Wl.registry, name, s_Wl.outputInterface, 3); + outputAddListener(output, &s_OutputListener, monitorData); + + monitorData->wlName = name; + monitorData->monitor = (PalMonitor*)output; + s_Wl.monitorCount++; + } +} + +static void globalRemove( + void* data, + struct wl_registry* registry, + uint32_t name) +{ + for (int i = 0; i < s_Video.maxMonitorData; ++i) { + if (s_Video.monitorData[i].used && s_Video.monitorData[i].wlName == name) { + MonitorData* data = &s_Video.monitorData[i]; + data->used = PAL_FALSE; + s_Wl.proxyDestroy((struct wl_proxy*)data->monitor); + s_Wl.monitorCount--; + } + } +} + +static const struct wl_registry_listener s_RegistryListener = { + .global = globalHandle, + .global_remove = globalRemove}; + +#endif // PAL_HAS_WAYLAND_BACKEND +#endif // __linux__ +#endif // _PAL_WAYLAND_HELPER_H \ No newline at end of file diff --git a/src/video/linux/wayland/pal_window_wayland.c b/src/video/linux/wayland/pal_window_wayland.c new file mode 100644 index 00000000..bf465100 --- /dev/null +++ b/src/video/linux/wayland/pal_window_wayland.c @@ -0,0 +1,505 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_WAYLAND_BACKEND == 1 + +#include "pal_wayland_helper.h" +#include "pal_shared.h" +#include + +static const struct xdg_surface_listener xdgSurfaceListener = { + .configure = xdgSurfaceHandleConfigure}; + +static const struct xdg_toplevel_listener xdgToplevelListener = { + .configure = xdgToplevelHandleConfigure, + .close = xdgToplevelHandleClose, + .configure_bounds = nullptr, + .wm_capabilities = nullptr}; + +static struct zxdg_toplevel_decoration_v1_listener decorationListener = { + .configure = zxdgDecorationHandleConfigure}; + +PalResult wlCreateWindow( + const PalWindowCreateInfo* info, + PalWindow** outWindow) +{ + struct wl_surface* surface = nullptr; + struct xdg_surface* xdgSurface = nullptr; + struct xdg_toplevel* xdgToplevel = nullptr; + + if (info->style & PAL_WINDOW_STYLE_TOPMOST) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (info->style & PAL_WINDOW_STYLE_TRANSPARENT) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (info->style & PAL_WINDOW_STYLE_TOOL) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!(info->style & PAL_WINDOW_STYLE_BORDERLESS)) { + if (!s_Wl.decorationManager) { + // user wants decorated window but its not supported + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + WindowData* data = getFreeWindowData(); + if (!data) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(data, 0, sizeof(WindowData)); + data->used = PAL_TRUE; + data->focused = PAL_FALSE; + + // create surface + surface = compositorCreateSurface(s_Wl.compositor); + if (!surface) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + surfaceAddListener(surface, &surfaceListener, data); + xdgSurface = xdgWmBaseGetXdgSurface(s_Wl.xdgBase, surface); + if (!xdgSurface) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + xdgToplevel = xdgSurfaceGetToplevel(xdgSurface); + if (!xdgSurface) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + // set APP id + const char* appID = getenv("RESOURCE_CLASS"); + if (!appID || strlen(appID) == 0) { + appID = s_Video.className; + } + + const char* title = info->title; + if (!title) { + title = ""; + } + + xdgToplevelSetTitle(xdgToplevel, title); + xdgToplevelSetAppId(xdgToplevel, appID); + + xdgToplevelAddListener(xdgToplevel, &xdgToplevelListener, data); + xdgSurfaceAddListener(xdgSurface, &xdgSurfaceListener, data); + + // decorated window + if (!(info->style & PAL_WINDOW_STYLE_BORDERLESS)) { + struct zxdg_toplevel_decoration_v1* decoration = nullptr; + decoration = zxdgGetToplevelDecoration(s_Wl.decorationManager, xdgToplevel); + zxdgToplevelDecorationV1AddListener(decoration, &decorationListener, surface); + zxdgToplevelDecorationV1SetMode(decoration, 2); + data->decoration = decoration; + } + + data->skipState = PAL_TRUE; + data->skipConfigure = PAL_TRUE; + surfaceCommit(surface); + s_Wl.displayRoundtrip(s_Wl.display); + + if (info->maximized && info->show) { + // we need the maximized size the compositor will use + // and use that to create the buffer + xdgToplevelSetMaximized(xdgToplevel); + surfaceCommit(surface); + s_Wl.displayRoundtrip(s_Wl.display); + data->state = PAL_WINDOW_STATE_MAXIMIZED; + + } else { + data->w = info->width; + data->h = info->height; + } + + data->xdgSurface = xdgSurface; + data->xdgToplevel = xdgToplevel; + data->window = (PalWindow*)surface; + data->buffer = nullptr; + data->isAttached = PAL_FALSE; + data->state = PAL_WINDOW_STATE_RESTORED; + + // minimize + // This is just a requeest, the compositor might ignore it + if (info->minimized) { + xdgToplevelSetMinimized(xdgToplevel); + surfaceCommit(surface); + data->state = PAL_WINDOW_STATE_MINIMIZED; + } + + if (s_Wl.eglFBConfig) { + data->eglWindow = s_Wl.eglWindowCreate(surface, data->w, data->h); + if (!data->eglWindow) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + } else { + // create a white buffer for the surface + struct wl_buffer* buffer = nullptr; + buffer = createShmBuffer(data->w, data->h, nullptr, PAL_FALSE); + if (!buffer) { + palSetLastPlatformError(errno); + return PAL_RESULT_PLATFORM_FAILURE; + } + + surfaceAttach(surface, buffer, 0, 0); + surfaceDamageBuffer(surface, 0, 0, data->w, data->h); + surfaceCommit(surface); + data->buffer = buffer; + } + + struct wl_region* region = compositorCreateRegion(s_Wl.compositor); + if (region) { + regionAdd(region, 0, 0, data->w, data->h); + surfaceSetOpaqueRegion(surface, region); + regionDestroy(region); + surfaceCommit(surface); + } + + s_Wl.displayRoundtrip(s_Wl.display); + if (!s_Wl.decorationManager && s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_NONE; + PalEventType type = PAL_EVENT_WINDOW_DECORATION_MODE; + mode = palGetEventDispatchMode(driver, type); + + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = PAL_DECORATION_MODE_CLIENT_SIDE; + event.data2 = palPackPointer(data->window); + palPushEvent(driver, &event); + } + } + + // Since wayland does not have a way to set unique data + // to a surface without taking control from users + // we might implement a simple hash map to do that + // but at the moment a linear search is fine + // FIXME: Implement a window hash map + + data->skipState = PAL_FALSE; + data->skipConfigure = PAL_FALSE; + *outWindow = data->window; + return PAL_RESULT_SUCCESS; +} + +void wlDestroyWindow(PalWindow* window) +{ + WindowData* data = findWindowData(window); + if (!data || (data && data->isAttached)) { + return; + } + + if (data->decoration) { + zxdgToplevelDecorationV1Destroy(data->decoration); + } + + if (data->eglWindow) { + s_Wl.eglWindowDestroy(data->eglWindow); + } else { + bufferDestroy(data->buffer); + } + + xdgToplevelDestroy(data->xdgToplevel); + xdgSurfaceDestroy(data->xdgSurface); + surfaceDestroy((struct wl_surface*)window); + data->used = PAL_FALSE; +} + +PalResult wlMinimizeWindow(PalWindow* window) +{ + WindowData* data = findWindowData(window); + if (!data) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + xdgToplevelSetMinimized(data->xdgToplevel); + return PAL_RESULT_SUCCESS; +} + +PalResult wlMaximizeWindow(PalWindow* window) +{ + WindowData* data = findWindowData(window); + if (!data) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + xdgToplevelSetMaximized(data->xdgToplevel); + return PAL_RESULT_SUCCESS; +} + +PalResult wlRestoreWindow(PalWindow* window) +{ + WindowData* data = findWindowData(window); + if (!data) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // we can only restore from a maximized state + xdgToplevelUnsetMaximized(data->xdgToplevel); + return PAL_RESULT_SUCCESS; +} + +PalResult wlShowWindow(PalWindow* window) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlHideWindow(PalWindow* window) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlFlashWindow( + PalWindow* window, + const PalFlashInfo* info) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlGetWindowStyle( + PalWindow* window, + PalWindowStyle* outStyle) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlGetWindowMonitor( + PalWindow* window, + PalMonitor** outMonitor) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlGetWindowTitle( + PalWindow* window, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlGetWindowPos( + PalWindow* window, + int32_t* x, + int32_t* y) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlGetWindowSize( + PalWindow* window, + uint32_t* width, + uint32_t* height) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlGetWindowState( + PalWindow* window, + PalWindowState* outState) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalBool wlIsWindowVisible(PalWindow* window) +{ + return PAL_FALSE; +} + +PalWindow* wlGetFocusWindow() +{ + // Wayland does not let client query focused window + return nullptr; +} + +PalResult wlGetWindowHandleInfo( + PalWindow* window, + PalWindowHandleInfo* info) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window || !info) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + WindowData* data = findWindowData(window); + if (data) { + info->nativeDisplay = (void*)s_Wl.display; + info->nativeWindow = (void*)window; + info->nativeHandle1 = data->xdgSurface; + info->nativeHandle2 = data->xdgToplevel; + info->nativeHandle3 = data->eglWindow; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult wlSetWindowOpacity( + PalWindow* window, + float opacity) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlSetWindowStyle( + PalWindow* window, + PalWindowStyle style) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlSetWindowTitle( + PalWindow* window, + const char* title) +{ + WindowData* data = findWindowData(window); + if (!data) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + xdgToplevelSetTitle(data->xdgToplevel, title); + s_Wl.displayFlush(s_Wl.display); + return PAL_RESULT_SUCCESS; +} + +PalResult wlSetWindowPos( + PalWindow* window, + int32_t x, + int32_t y) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlSetWindowSize( + PalWindow* window, + uint32_t width, + uint32_t height) +{ + WindowData* data = findWindowData(window); + if (!data) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + xdgToplevelSetMinSize(data->xdgToplevel, width, height); + xdgToplevelSetMaxSize(data->xdgToplevel, width, height); + surfaceCommit((struct wl_surface*)window); + return PAL_RESULT_SUCCESS; +} + +PalResult wlSetFocusWindow(PalWindow* window) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlAttachWindow( + void* windowHandle, + PalWindow** outWindow) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult wlDetachWindow( + PalWindow* window, + void** outWindowHandle) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +#endif // PAL_HAS_WAYLAND_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/x11/pal_cursor_x11.c b/src/video/linux/x11/pal_cursor_x11.c new file mode 100644 index 00000000..1b41f9af --- /dev/null +++ b/src/video/linux/x11/pal_cursor_x11.c @@ -0,0 +1,207 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_X11_BACKEND == 1 + +#include "pal_x11.h" +#include "pal_shared.h" + +PalResult xCreateCursor( + const PalCursorCreateInfo* info, + PalCursor** outCursor) +{ + XcursorImage* image = s_X11.cursorImageCreate(info->width, info->height); + image->xhot = info->xHotspot; + image->yhot = info->yHotspot; + + // convert from RGBA8 to ARGB32 + for (int i = 0; i < info->width * info->height; i++) { + uint8_t r = info->pixels[i * 4 + 0]; // Red + uint8_t g = info->pixels[i * 4 + 1]; // Green + uint8_t b = info->pixels[i * 4 + 2]; // Blue + uint8_t a = info->pixels[i * 4 + 3]; // Alpha + + // clang-format off + image->pixels[i] = ((unsigned long)a << 24) | + ((unsigned long)r << 16) | + ((unsigned long)g << 8) | + ((unsigned long)b); + // clang-format on + } + + Cursor cursor = s_X11.cursorImageLoadCursor(s_X11.display, image); + if (!cursor) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.cursorImageDestroy(image); + *outCursor = TO_PAL_HANDLE(PalCursor, cursor); + return PAL_RESULT_SUCCESS; +} + +PalResult xCreateCursorFrom( + PalCursorType type, + PalCursor** outCursor) +{ + int shape; + Cursor cursor; + switch (type) { + case PAL_CURSOR_ARROW: { + shape = XC_left_ptr; + break; + } + + case PAL_CURSOR_HAND: { + shape = XC_hand2; + break; + } + + case PAL_CURSOR_CROSS: { + shape = XC_cross; + break; + } + + case PAL_CURSOR_IBEAM: { + shape = XC_xterm; + break; + } + + case PAL_CURSOR_WAIT: { + shape = XC_watch; + break; + } + } + + cursor = s_X11.createFontCursor(s_X11.display, shape); + *outCursor = TO_PAL_HANDLE(PalCursor, cursor); + return PAL_RESULT_SUCCESS; +} + +void xDestroyCursor(PalCursor* cursor) +{ + s_X11.freeCursor(s_X11.display, FROM_PAL_HANDLE(Cursor, cursor)); +} + +void xShowCursor(PalBool show) +{ + // x11 does not support Hiding and showing cursor + return; +} + +PalResult xClipCursor( + PalWindow* window, + PalBool clip) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (clip) { + s_X11.grabPointer( + s_X11.display, + xWin, + True, + 0, + GrabModeAsync, + GrabModeAsync, + xWin, + None, + CurrentTime); + + } else { + s_X11.ungrabPointer(s_X11.display, CurrentTime); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult xGetCursorPos( + PalWindow* window, + int32_t* x, + int32_t* y) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + Window root, rootChild; + int rootX, rootY, winX, winY; + unsigned int mask; + s_X11.queryPointer(s_X11.display, xWin, &root, &rootChild, &rootX, &rootY, &winX, &winY, &mask); + + if (x) { + *x = winX; + } + + if (y) { + *y = winY; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult xSetCursorPos( + PalWindow* window, + int32_t x, + int32_t y) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.warpPointer(s_X11.display, None, xWin, 0, 0, 0, 0, x, y); + + s_X11.flush(s_X11.display); + return PAL_RESULT_SUCCESS; +} + +PalResult xSetWindowCursor( + PalWindow* window, + PalCursor* cursor) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + Window xCursor = FROM_PAL_HANDLE(Cursor, cursor); + if (xCursor) { + s_X11.defineCursor(s_X11.display, xWin, xCursor); + + } else { + s_X11.undefineCursor(s_X11.display, xWin); + } + + s_X11.flush(s_X11.display); + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_X11_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/x11/pal_icon_x11.c b/src/video/linux/x11/pal_icon_x11.c new file mode 100644 index 00000000..05391ac3 --- /dev/null +++ b/src/video/linux/x11/pal_icon_x11.c @@ -0,0 +1,91 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_X11_BACKEND == 1 + +#include "pal_x11.h" +#include "pal_shared.h" + +PalResult xCreateIcon( + const PalIconCreateInfo* info, + PalIcon** outIcon) +{ + uint64_t totalPixels = 2 + (uint64_t)(info->width * info->height); + uint64_t totalBytes = sizeof(unsigned long) * totalPixels; + + unsigned long* icon = palAllocate(s_Video.allocator, totalBytes, 0); + if (!icon) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // store width and height and populate data with icon pixels + // [width][height][pixels] + icon[0] = (unsigned long)info->width; + icon[1] = (unsigned long)info->height; + + // convert from RGBA8 to ARGB32 + for (int i = 0; i < info->width * info->height; i++) { + uint8_t r = info->pixels[i * 4 + 0]; // Red + uint8_t g = info->pixels[i * 4 + 1]; // Green + uint8_t b = info->pixels[i * 4 + 2]; // Blue + uint8_t a = info->pixels[i * 4 + 3]; // Alpha + + // clang-format off + icon[2 + i] = ((unsigned long)a << 24) | + ((unsigned long)r << 16) | + ((unsigned long)g << 8) | + ((unsigned long)b); + // clang-format on + } + + *outIcon = TO_PAL_HANDLE(PalIcon, icon); + return PAL_RESULT_SUCCESS; +} + +void xDestroyIcon(PalIcon* icon) +{ + if (icon) { + palFree(s_Video.allocator, icon); + } +} + +PalResult xSetWindowIcon( + PalWindow* window, + PalIcon* icon) +{ + WindowData* winData = nullptr; + Window xWin = FROM_PAL_HANDLE(Window, window); + s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&winData); + if (!winData) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + unsigned long* iconData = FROM_PAL_HANDLE(unsigned long*, icon); + uint64_t totalPixels = 2 + iconData[0] * iconData[1]; + s_X11.changeProperty( + s_X11.display, + xWin, + s_X11Atoms._NET_WM_ICON, + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char*)iconData, + (int)totalPixels); + + s_X11.flush(s_X11.display); + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_X11_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/x11/pal_monitor_x11.c b/src/video/linux/x11/pal_monitor_x11.c new file mode 100644 index 00000000..9c1aa244 --- /dev/null +++ b/src/video/linux/x11/pal_monitor_x11.c @@ -0,0 +1,456 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_X11_BACKEND == 1 + +#include "pal_x11.h" +#include "pal_shared.h" +#include + +static PalResult xEnumerateMonitors( + int32_t* count, + PalMonitor** outMonitors) +{ + int _count = 0; + int maxCount = outMonitors ? *count : 0; + XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); + for (int i = 0; i < resources->noutput; ++i) { + RROutput output = resources->outputs[i]; + XRROutputInfo* outputInfo = s_X11.getOutputInfo(s_X11.display, resources, output); + if (outputInfo->connection == RR_Connected && outputInfo->crtc != None) { + // a monitor + if (outMonitors) { + if (_count < maxCount) { + outMonitors[_count] = TO_PAL_HANDLE(PalMonitor, output); + } + } + _count++; + } + } + + if (!outMonitors) { + *count = _count; + } + return PAL_RESULT_SUCCESS; +} + +static PalResult xGetPrimaryMonitor(PalMonitor** outMonitor) +{ + RROutput primary = s_X11.getOutputPrimary(s_X11.display, s_X11.root); + if (primary) { + *outMonitor = TO_PAL_HANDLE(PalMonitor, primary); + return PAL_RESULT_SUCCESS; + } + + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +static PalResult xGetMonitorInfo( + PalMonitor* monitor, + PalMonitorInfo* info) +{ + XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); + + if (!outputInfo) { + // invalid monitor + s_X11.freeScreenResources(resources); + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (outputInfo->connection != RR_Connected) { + // invalid monitor + s_X11.freeScreenResources(resources); + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + strcpy(info->name, outputInfo->name); + + // check if its primary monitor + RROutput primary = s_X11.getOutputPrimary(s_X11.display, s_X11.root); + + if (monitor == TO_PAL_HANDLE(PalMonitor, primary)) { + info->primary = PAL_TRUE; + } else { + info->primary = PAL_FALSE; + } + + // get monitor pos and size + XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); + info->x = crtc->x; + info->y = crtc->y; + info->width = crtc->width; + info->height = crtc->height; + + // get refresh rate + double rate = 0; + for (int i = 0; i < resources->nmode; ++i) { + // check for our monitor + if (resources->modes[i].id == crtc->mode) { + XRRModeInfo* mode = &resources->modes[i]; + double tmp = (double)mode->hTotal * (double)mode->vTotal; + rate = (double)mode->dotClock / tmp; + info->refreshRate = rate + 0.5; + break; + } + } + + // orientation + switch (crtc->rotation) { + case RR_Rotate_0: { + info->orientation = PAL_ORIENTATION_LANDSCAPE; + break; + } + + case RR_Rotate_90: { + info->orientation = PAL_ORIENTATION_PORTRAIT; + break; + } + + case RR_Rotate_180: { + info->orientation = PAL_ORIENTATION_LANDSCAPE_FLIPPED; + break; + } + + case RR_Rotate_270: { + info->orientation = PAL_ORIENTATION_PORTRAIT_FLIPPED; + break; + } + + default: { + info->orientation = PAL_ORIENTATION_LANDSCAPE; + } + } + + // get dpi + float raw = crtc->width / 1920.0f; + float steps[] = {1.0f, 1.2f, 1.5f, 1.75, 2.0f}; + float closest = steps[0]; + float minDiff = fabsf(raw - steps[0]); + + for (int i = 1; i < sizeof(steps) / sizeof(steps[0]); i++) { + float diff = fabsf(raw - steps[i]); + if (diff < minDiff) { + minDiff = diff; + closest = steps[i]; + } + } + + info->dpi = (uint32_t)(closest * 96.0f); + + s_X11.freeCrtcInfo(crtc); + s_X11.freeOutputInfo(outputInfo); + s_X11.freeScreenResources(resources); + + return PAL_RESULT_SUCCESS; +} + +static PalResult xEnumerateMonitorModes( + PalMonitor* monitor, + int32_t* count, + PalMonitorMode* modes) +{ + int32_t modeCount = 0; + int maxModeCount = modes ? *count : 0; + XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); + + // get the monitor info + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); + + if (!outputInfo) { + // invalid monitor + s_X11.freeScreenResources(resources); + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (outputInfo->connection != RR_Connected) { + // invalid monitor + s_X11.freeScreenResources(resources); + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // get supported display modes + for (int i = 0; i < outputInfo->nmode; ++i) { + for (int j = 0; j < resources->nmode; ++j) { + // get the display mode and check if its for our monitor + XRRModeInfo* info = &resources->modes[j]; + if (info->id == outputInfo->modes[i]) { + // check if user supplied a PalMonitorMode array + if (modes) { + if (modeCount < maxModeCount) { + PalMonitorMode* mode = &modes[modeCount]; + mode->width = info->width; + mode->height = info->height; + mode->bpp = s_X11.bpp; + + double tmp = (double)info->hTotal * (double)info->vTotal; + double rate = (double)info->dotClock / tmp; + mode->refreshRate = rate + 0.5; + } + } + modeCount++; + } + } + } + + if (!modes) { + *count = modeCount; + } + + s_X11.freeOutputInfo(outputInfo); + s_X11.freeScreenResources(resources); + + return PAL_RESULT_SUCCESS; +} + +static PalResult xGetCurrentMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); + + // get the monitor info + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); + + if (!outputInfo) { + // invalid monitor + s_X11.freeScreenResources(resources); + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (outputInfo->connection != RR_Connected) { + // invalid monitor + s_X11.freeScreenResources(resources); + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // get the current display mode + XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); + + // find the display mode + XRRModeInfo* info = nullptr; + for (int i = 0; i < resources->nmode; ++i) { + if (resources->modes[i].id == crtc->mode) { + // found + info = &resources->modes[i]; + break; + } + } + + if (mode) { + mode->width = info->width; + mode->height = info->height; + mode->bpp = s_X11.bpp; + + double tmp = (double)info->hTotal * (double)info->vTotal; + double rate = (double)info->dotClock / tmp; + mode->refreshRate = rate + 0.5; + } + + s_X11.freeCrtcInfo(crtc); + s_X11.freeOutputInfo(outputInfo); + s_X11.freeScreenResources(resources); + + return PAL_RESULT_SUCCESS; +} + +static PalResult xSetMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); + + // get the monitor info + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); + + if (!outputInfo) { + // invalid monitor + s_X11.freeScreenResources(resources); + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (outputInfo->connection != RR_Connected) { + // invalid monitor + s_X11.freeScreenResources(resources); + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // find the monitor display mode + RRMode displayMode = findMode(resources, mode); + if (displayMode == None) { + s_X11.freeOutputInfo(outputInfo); + s_X11.freeScreenResources(resources); + + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // apply the display mode + XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); + + RROutput output = FROM_PAL_HANDLE(RROutput, monitor); + int ret = s_X11.setCrtcConfig( + s_X11.display, + resources, + outputInfo->crtc, + CurrentTime, + crtc->x, + crtc->y, + displayMode, + crtc->rotation, + &output, + 1); + + s_X11.freeCrtcInfo(crtc); + s_X11.freeOutputInfo(outputInfo); + s_X11.freeScreenResources(resources); + + if (ret != Success) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return PAL_RESULT_SUCCESS; +} + +static PalResult xValidateMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +static PalResult xSetMonitorOrientation( + PalMonitor* monitor, + PalOrientation orientation) +{ + XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); + + // get the monitor info + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); + + if (!outputInfo) { + // invalid monitor + s_X11.freeScreenResources(resources); + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (outputInfo->connection != RR_Connected) { + // invalid monitor + s_X11.freeScreenResources(resources); + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // get the current display mode + XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); + + // check if the new orientation is supported + Rotation rotation = 0; + switch (orientation) { + case PAL_ORIENTATION_LANDSCAPE: { + rotation = RR_Rotate_0; + break; + } + + case PAL_ORIENTATION_PORTRAIT: { + rotation = RR_Rotate_90; + break; + } + + case PAL_ORIENTATION_LANDSCAPE_FLIPPED: { + rotation = RR_Rotate_180; + break; + } + + case PAL_ORIENTATION_PORTRAIT_FLIPPED: { + rotation = RR_Rotate_270; + break; + } + } + + if (!(crtc->rotations & rotation)) { + return palMakeResult( + PAL_RESULT_INVALID_OPERATION, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + RROutput output = FROM_PAL_HANDLE(RROutput, monitor); + int ret = s_X11.setCrtcConfig( + s_X11.display, + resources, + outputInfo->crtc, + CurrentTime, + crtc->x, + crtc->y, + crtc->mode, + rotation, + &output, + 1); + + s_X11.freeCrtcInfo(crtc); + s_X11.freeOutputInfo(outputInfo); + s_X11.freeScreenResources(resources); + + if (ret != Success) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_X11_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/x11/pal_video_x11.c b/src/video/linux/x11/pal_video_x11.c new file mode 100644 index 00000000..45ae814b --- /dev/null +++ b/src/video/linux/x11/pal_video_x11.c @@ -0,0 +1,1349 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_X11_BACKEND == 1 + +#include "pal_x11.h" +#include "pal_shared.h" +#include +#include + +X11 s_X11 = {0}; +X11Atoms s_X11Atoms = {0}; + +static PalResult glxBackend(const int index) +{ + // user choose GLX FBConfig backend + if (!s_X11.glxHandle) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + int count = 0; + GLXFBConfig* configs = s_X11.glxGetFBConfigs(s_X11.display, s_X11.screen, &count); + GLXFBConfig fbConfig = configs[index]; + if (!fbConfig) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // get a matching visual + XVisualInfo* visualInfo = s_X11.glxGetVisualFromFBConfig(s_X11.display, fbConfig); + if (!visualInfo) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.visualInfo = visualInfo; + return PAL_RESULT_SUCCESS; +} + +static PalResult eglXBackend(int index) +{ + // user choose EGL FBConfig backend + if (!s_Egl.handle) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + EGLDisplay display = EGL_NO_DISPLAY; + display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_X11.display); + if (display == EGL_NO_DISPLAY) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + EGLint numConfigs = 0; + if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + EGLint configSize = sizeof(EGLConfig) * numConfigs; + EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); + if (!eglConfigs) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); + EGLConfig config = eglConfigs[index]; + + // we get a visual info from the config + EGLint visualID; + s_Egl.eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualID); + if (visualID == 0) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + int numVisuals = 0; + XVisualInfo tmp; + tmp.visualid = visualID; + + // get a matching visual info + XVisualInfo* visualInfo = s_X11.getVisualInfo(s_X11.display, VisualIDMask, &tmp, &numVisuals); + if (!visualInfo) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.visualInfo = visualInfo; + palFree(s_Video.allocator, eglConfigs); + return PAL_RESULT_SUCCESS; +} + +static RRMode findMode( + XRRScreenResources* resources, + const PalMonitorMode* mode) +{ + for (int i = 0; i < resources->nmode; ++i) { + XRRModeInfo* info = &resources->modes[i]; + + double tmp = (double)info->hTotal * (double)info->vTotal; + double rate = (double)info->dotClock / tmp; + + // compare with width, height and refresh rate + if (info->width == mode->width && info->height == mode->height && + (uint32_t)(rate + 0.5) == mode->refreshRate) { + return info->id; + } + } + return None; +} + +static void checkFeatures() +{ + // cache this atoms + X_INTERN(WM_DELETE_WINDOW); + X_INTERN(_NET_SUPPORTED); + X_INTERN(_NET_WM_STATE); + X_INTERN(_NET_WM_STATE_ABOVE); + X_INTERN(_NET_WM_STATE_MAXIMIZED_VERT); + X_INTERN(_NET_WM_STATE_MAXIMIZED_HORZ); + X_INTERN(_NET_WM_STATE_HIDDEN); + X_INTERN(_NET_WM_NAME); + X_INTERN(UTF8_STRING); + X_INTERN(_NET_WM_WINDOW_TYPE_UTILITY); + X_INTERN(_NET_WM_DESKTOP); + X_INTERN(_NET_WM_STATE_DEMANDS_ATTENTIONS); + X_INTERN(_NET_WM_WINDOW_OPACITY); + X_INTERN(_NET_WM_WINDOW_TYPE); + X_INTERN(_NET_WM_WINDOW_TYPE_SPLASH); + X_INTERN(_NET_WM_PID); + X_INTERN(_WM_CLASS); + X_INTERN(_NET_ACTIVE_WINDOW); + X_INTERN(_NET_WM_ICON); + + // check for support from the window manager + Atom type; + int format; + unsigned long count, bytesAfters; + Atom* supportedAtoms = nullptr; + s_X11.getWindowProperty( + s_X11.display, + s_X11.root, + s_X11Atoms._NET_SUPPORTED, + 0, + (~0L), + False, + XA_ATOM, + &type, + &format, + &count, + &bytesAfters, + (unsigned char**)&supportedAtoms); + + PalVideoFeatures features = 0; + for (unsigned long i = 0; i < count; ++i) { + if (supportedAtoms[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT) { + features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; + features |= PAL_VIDEO_FEATURE_WINDOW_GET_STATE; + } + + if (supportedAtoms[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ) { + features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; + features |= PAL_VIDEO_FEATURE_WINDOW_GET_STATE; + } + + if (supportedAtoms[i] == s_X11Atoms._NET_WM_STATE_HIDDEN) { + features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; + features |= PAL_VIDEO_FEATURE_WINDOW_GET_STATE; + } + + if (supportedAtoms[i] == s_X11Atoms._NET_WM_WINDOW_TYPE_SPLASH) { + features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; + } + + if (supportedAtoms[i] == s_X11Atoms._NET_WM_NAME) { + s_X11Atoms.unicodeTitle = PAL_TRUE; + } + + if (supportedAtoms[i] == s_X11Atoms._NET_WM_WINDOW_TYPE_UTILITY) { + features |= PAL_VIDEO_FEATURE_TOOL_WINDOW; + } + } + + // check for transparent windows + Atom compositor = s_X11.internAtom(s_X11.display, "_NET_WM_CM_S0", True); + if (compositor != None) { + Window owner = s_X11.getSelectionOwner(s_X11.display, compositor); + if (owner != None) { + features |= PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW; + } + } + + // general features + features |= PAL_VIDEO_FEATURE_MULTI_MONITORS; + features |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; + features |= PAL_VIDEO_FEATURE_MONITOR_SET_MODE; + features |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; + features |= PAL_VIDEO_FEATURE_WINDOW_GET_SIZE; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY; + features |= PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY; + + features |= PAL_VIDEO_FEATURE_CLIP_CURSOR; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS; + features |= PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS; + features |= PAL_VIDEO_FEATURE_CURSOR_SET_POS; + features |= PAL_VIDEO_FEATURE_CURSOR_GET_POS; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; + features |= PAL_VIDEO_FEATURE_WINDOW_GET_TITLE; + features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY; + + features |= PAL_VIDEO_FEATURE_WINDOW_SET_ICON; + features |= PAL_VIDEO_FEATURE_TOPMOST_WINDOW; + features |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; + features |= PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY; + features |= PAL_VIDEO_FEATURE_FOREIGN_WINDOWS; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; + + s_Video.features = features; + s_X11.free(supportedAtoms); +} + +static PalWindowState queryWindowState(Window xWin) +{ + Atom type; + int format; + unsigned long count, bytesAfter; + Atom* atoms = nullptr; + PalWindowState state = PAL_WINDOW_STATE_RESTORED; + + s_X11.getWindowProperty( + s_X11.display, + xWin, + s_X11Atoms._NET_WM_STATE, + 0, + 1024, + False, + XA_ATOM, + &type, + &format, + &count, + &bytesAfter, + (unsigned char**)&atoms); + + for (unsigned int i = 0; i < count; i++) { + if (atoms[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ) { + state = PAL_WINDOW_STATE_MAXIMIZED; + } + + if (atoms[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT) { + state = PAL_WINDOW_STATE_MAXIMIZED; + } + + if (atoms[i] == s_X11Atoms._NET_WM_STATE_HIDDEN) { + state = PAL_WINDOW_STATE_MINIMIZED; + } + } + + s_X11.free(atoms); + return state; +} + +static void cacheMonitors() +{ + resetMonitorData(); + XRRScreenResources* resources = nullptr; + resources = s_X11.getScreenResources(s_X11.display, s_X11.root); + + for (int i = 0; i < resources->noutput; ++i) { + RROutput output = resources->outputs[i]; + XRROutputInfo* info = s_X11.getOutputInfo(s_X11.display, resources, output); + if (info->connection == RR_Connected && info->crtc != None) { + // get monitor data and update info + PalMonitor* monitor = TO_PAL_HANDLE(PalMonitor, output); + MonitorData* data = nullptr; + data = getFreeMonitorData(); + if (!data) { + return; + } + + data->monitor = monitor; + XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, info->crtc); + + // get DPI + float raw = crtc->width / 1920.0f; + float steps[] = {1.0f, 1.2f, 1.5f, 1.75, 2.0f}; + float closest = steps[0]; + float minDiff = fabsf(raw - steps[0]); + + for (int i = 1; i < sizeof(steps) / sizeof(steps[0]); i++) { + float diff = fabsf(raw - steps[i]); + if (diff < minDiff) { + minDiff = diff; + closest = steps[i]; + } + } + + data->dpi = (uint32_t)(closest * 96.0f); + data->w = crtc->width; + data->h = crtc->height; + data->x = crtc->x; + data->y = crtc->y; + + s_X11.freeCrtcInfo(crtc); + s_X11.monitorCount++; + } + + s_X11.freeOutputInfo(info); + } + + s_X11.freeScreenResources(resources); +} + +static int getWindowMonitorDPI(WindowData* data) +{ + int winX = data->x + data->w / 2; + int winY = data->y + data->w / 2; + // get the DPI from our cached monitor + for (int i = 0; i < s_Video.maxMonitorData; i++) { + if (!s_Video.monitorData->used) { + continue; + } + + // we found a monitor, check the monitor bounds with the window + MonitorData* info = &s_Video.monitorData[i]; + if (winX >= info->x && winX < info->x + info->w && winY >= info->y && + winY < info->y + info->h) { + // found monitor + return info->dpi; + } + } +} + +static void sendWMEvent( + Window window, + Atom type, + long a, + long b, + long c, + long d, + PalBool add) +{ + XEvent e = {0}; + e.xclient.type = ClientMessage; + e.xclient.send_event = True; + e.xclient.window = window; + e.xclient.message_type = type; + e.xclient.format = 32; + if (add) { + e.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD + } else { + e.xclient.data.l[0] = 0; // _NET_WM_STATE_REMOVE + } + + e.xclient.data.l[1] = a; + e.xclient.data.l[2] = b; + e.xclient.data.l[3] = c; + e.xclient.data.l[4] = d; + + s_X11.sendEvent( + s_X11.display, + s_X11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &e); +} + +static void createKeycodeTable() +{ + // Tis is for only printable and text input keys + + // Letters + s_Keyboard.keycodes[XK_a] = PAL_KEYCODE_A; + s_Keyboard.keycodes[XK_b] = PAL_KEYCODE_B; + s_Keyboard.keycodes[XK_c] = PAL_KEYCODE_C; + s_Keyboard.keycodes[XK_d] = PAL_KEYCODE_D; + s_Keyboard.keycodes[XK_e] = PAL_KEYCODE_E; + s_Keyboard.keycodes[XK_f] = PAL_KEYCODE_F; + s_Keyboard.keycodes[XK_g] = PAL_KEYCODE_G; + s_Keyboard.keycodes[XK_h] = PAL_KEYCODE_H; + s_Keyboard.keycodes[XK_i] = PAL_KEYCODE_I; + s_Keyboard.keycodes[XK_j] = PAL_KEYCODE_J; + s_Keyboard.keycodes[XK_k] = PAL_KEYCODE_K; + s_Keyboard.keycodes[XK_l] = PAL_KEYCODE_L; + s_Keyboard.keycodes[XK_m] = PAL_KEYCODE_M; + s_Keyboard.keycodes[XK_n] = PAL_KEYCODE_N; + s_Keyboard.keycodes[XK_o] = PAL_KEYCODE_O; + s_Keyboard.keycodes[XK_p] = PAL_KEYCODE_P; + s_Keyboard.keycodes[XK_q] = PAL_KEYCODE_Q; + s_Keyboard.keycodes[XK_r] = PAL_KEYCODE_R; + s_Keyboard.keycodes[XK_s] = PAL_KEYCODE_S; + s_Keyboard.keycodes[XK_t] = PAL_KEYCODE_T; + s_Keyboard.keycodes[XK_u] = PAL_KEYCODE_U; + s_Keyboard.keycodes[XK_v] = PAL_KEYCODE_V; + s_Keyboard.keycodes[XK_w] = PAL_KEYCODE_W; + s_Keyboard.keycodes[XK_x] = PAL_KEYCODE_X; + s_Keyboard.keycodes[XK_y] = PAL_KEYCODE_Y; + s_Keyboard.keycodes[XK_z] = PAL_KEYCODE_Z; + + // Control + s_Keyboard.keycodes[XK_space] = PAL_KEYCODE_SPACE; + + // Misc + s_Keyboard.keycodes[XK_apostrophe] = PAL_KEYCODE_APOSTROPHE; + s_Keyboard.keycodes[XK_backslash] = PAL_KEYCODE_BACKSLASH; + s_Keyboard.keycodes[XK_comma] = PAL_KEYCODE_COMMA; + s_Keyboard.keycodes[XK_equal] = PAL_KEYCODE_EQUAL; + s_Keyboard.keycodes[XK_grave] = PAL_KEYCODE_GRAVEACCENT; + s_Keyboard.keycodes[XK_minus] = PAL_KEYCODE_SUBTRACT; + s_Keyboard.keycodes[XK_period] = PAL_KEYCODE_PERIOD; + s_Keyboard.keycodes[XK_semicolon] = PAL_KEYCODE_SEMICOLON; + s_Keyboard.keycodes[XK_slash] = PAL_KEYCODE_SLASH; + s_Keyboard.keycodes[XK_bracketleft] = PAL_KEYCODE_LBRACKET; + s_Keyboard.keycodes[XK_bracketright] = PAL_KEYCODE_RBRACKET; +} + +static PalResult xInitVideo() +{ + // load X11 library + s_X11.handle = dlopen("libX11.so", RTLD_LAZY); + if (!s_X11.handle) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // libXCursor is needed + s_X11.libCursor = dlopen("libXcursor.so", RTLD_LAZY); + if (!s_X11.libCursor) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // Xrandr is needed + s_X11.xrandr = dlopen("libXrandr.so.2", RTLD_LAZY); + if (!s_X11.xrandr) { + s_X11.xrandr = dlopen("libXrandr.so", RTLD_LAZY); + } + + // clang-format off + // load procs + s_X11.openDisplay = (XOpenDisplayFn)dlsym( + s_X11.handle, + "XOpenDisplay"); + + s_X11.closeDisplay = (XCloseDisplayFn)dlsym( + s_X11.handle, + "XCloseDisplay"); + + s_X11.getWindowAttributes = (XGetWindowAttributesFn)dlsym( + s_X11.handle, + "XGetWindowAttributes"); + + s_X11.setCrtcConfig = (XRRSetCrtcConfigFn)dlsym( + s_X11.handle, + "XRRSetCrtcConfig"); + + s_X11.getWindowProperty = (XGetWindowPropertyFn)dlsym( + s_X11.handle, + "XGetWindowProperty"); + + s_X11.internAtom = (XInternAtomFn)dlsym( + s_X11.handle, + "XInternAtom"); + + s_X11.getSelectionOwner = (XGetSelectionOwnerFn)dlsym( + s_X11.handle, + "XGetSelectionOwner"); + + s_X11.freeColormap = (XFreeColormapFn)dlsym( + s_X11.handle, + "XFreeColormap"); + + s_X11.storeName = (XStoreNameFn)dlsym( + s_X11.handle, + "XStoreName"); + + s_X11.changeProperty = (XChangePropertyFn)dlsym( + s_X11.handle, + "XChangeProperty"); + + s_X11.flush = (XFlushFn)dlsym( + s_X11.handle, + "XFlush"); + + s_X11.createColormap = (XCreateColormapFn)dlsym( + s_X11.handle, + "XCreateColormap"); + + s_X11.mapWindow = (XMapWindowFn)dlsym( + s_X11.handle, + "XMapWindow"); + + s_X11.unmapWindow = (XUnmapWindowFn)dlsym( + s_X11.handle, + "XUnmapWindow"); + + s_X11.createWindow = (XCreateWindowFn)dlsym( + s_X11.handle, + "XCreateWindow"); + + s_X11.destroyWindow = (XDestroyWindowFn)dlsym( + s_X11.handle, + "XDestroyWindow"); + + s_X11.matchVisualInfo = (XMatchVisualInfoFn)dlsym( + s_X11.handle, + "XMatchVisualInfo"); + + s_X11.pending = (XPendingFn)dlsym( + s_X11.handle, + "XPending"); + + s_X11.setWMProtocols = (XSetWMProtocolsFn)dlsym( + s_X11.handle, + "XSetWMProtocols"); + + s_X11.nextEvent = (XNextEventFn)dlsym( + s_X11.handle, + "XNextEvent"); + + s_X11.setWMNormalHints = (XSetWMNormalHintsFn)dlsym( + s_X11.handle, + "XSetWMNormalHints"); + + s_X11.getWMNormalHints = (XGetWMNormalHintsFn)dlsym( + s_X11.handle, + "XGetWMNormalHints"); + + s_X11.sendEvent = (XSendEventFn)dlsym( + s_X11.handle, + "XSendEvent"); + + s_X11.moveWindow = (XMoveWindowFn)dlsym( + s_X11.handle, + "XMoveWindow"); + + s_X11.resizeWindow = (XResizeWindowFn)dlsym( + s_X11.handle, + "XResizeWindow"); + + s_X11.iconifyWindow = (XIconifyWindowFn)dlsym( + s_X11.handle, + "XIconifyWindow"); + + s_X11.setErrorHandler = (XSetErrorHandlerFn)dlsym( + s_X11.handle, + "XSetErrorHandler"); + + s_X11.sync = (XSyncFn)dlsym( + s_X11.handle, + "XSync"); + + s_X11.saveContext = (XSaveContextFn)dlsym( + s_X11.handle, + "XSaveContext"); + + s_X11.findContext = (XFindContextFn)dlsym( + s_X11.handle, + "XFindContext"); + + s_X11.uniqueContext = (XrmUniqueQuarkFn)dlsym( + s_X11.handle, + "XrmUniqueQuark"); + + // load Xrandr functions + s_X11.getScreenResources = (XRRGetScreenResourcesFn)dlsym( + s_X11.xrandr, + "XRRGetScreenResources"); + + s_X11.getOutputPrimary = (XRRGetOutputPrimaryFn)dlsym( + s_X11.xrandr, + "XRRGetOutputPrimary"); + + s_X11.getOutputInfo = (XRRGetOutputInfoFn)dlsym( + s_X11.xrandr, + "XRRGetOutputInfo"); + + s_X11.getCrtcInfo = (XRRGetCrtcInfoFn)dlsym( + s_X11.xrandr, + "XRRGetCrtcInfo"); + + s_X11.freeScreenResources = (XRRFreeScreenResourcesFn)dlsym( + s_X11.xrandr, + "XRRFreeScreenResources"); + + s_X11.freeOutputInfo = (XRRFreeOutputInfoFn)dlsym( + s_X11.xrandr, + "XRRFreeScreenResources"); + + s_X11.freeCrtcInfo = (XRRFreeCrtcInfoFn)dlsym( + s_X11.xrandr, + "XRRFreeCrtcInfo"); + + s_X11.selectRRInput = (XRRSelectInputFn)dlsym( + s_X11.xrandr, + "XRRSelectInput"); + + s_X11.queryRRExtension = (XRRQueryExtensionFn)dlsym( + s_X11.xrandr, + "XRRQueryExtension"); + + s_X11.allocClassHint = (XAllocClassHintFn)dlsym( + s_X11.handle, + "XAllocClassHint"); + + s_X11.setClassHint = (XSetClassHintFn)dlsym( + s_X11.handle, + "XSetClassHint"); + + s_X11.free = (XFreeFn)dlsym( + s_X11.handle, + "XFree"); + + s_X11.getVisualInfo = (XGetVisualInfoFn)dlsym( + s_X11.handle, + "XGetVisualInfo"); + + s_X11.createFontCursor = (XCreateFontCursorFn)dlsym( + s_X11.handle, + "XCreateFontCursor"); + + s_X11.freePixmap = (XFreePixmapFn)dlsym( + s_X11.handle, + "XFreePixmap"); + + s_X11.setWMHints = (XSetWMHintsFn)dlsym( + s_X11.handle, + "XSetWMHints"); + + s_X11.grabPointer = (XGrabPointerFn)dlsym( + s_X11.handle, + "XGrabPointer"); + + s_X11.createPixmapCursor = (XCreatePixmapCursorFn)dlsym( + s_X11.handle, + "XCreatePixmapCursor"); + + s_X11.warpPointer = (XWarpPointerFn)dlsym( + s_X11.handle, + "XWarpPointer"); + + s_X11.getWMName = (XGetWMNameFn)dlsym( + s_X11.handle, + "XGetWMName"); + + s_X11.queryPointer = (XQueryPointerFn)dlsym( + s_X11.handle, + "XQueryPointer"); + + s_X11.ungrabPointer = (XUngrabPointerFn)dlsym( + s_X11.handle, + "XUngrabPointer"); + + s_X11.allocWMHints = (XAllocWMHintsFn)dlsym( + s_X11.handle, + "XAllocWMHints"); + + s_X11.mapRaised = (XMapRaisedFn)dlsym( + s_X11.handle, + "XMapRaised"); + + s_X11.undefineCursor = (XUndefineCursorFn)dlsym( + s_X11.handle, + "XUndefineCursor"); + + s_X11.defineCursor = (XDefineCursorFn)dlsym( + s_X11.handle, + "XDefineCursor"); + + s_X11.freeCursor = (XFreeCursorFn)dlsym( + s_X11.handle, + "XFreeCursor"); + + s_X11.getWMHints = (XGetWMHintsFn)dlsym( + s_X11.handle, + "XGetWMHints"); + + s_X11.createPixmap = (XCreatePixmapFn)dlsym( + s_X11.handle, + "XCreatePixmap"); + + s_X11.setInputFocus = (XSetInputFocusFn)dlsym( + s_X11.handle, + "XSetInputFocus"); + + s_X11.getInputFocus = (XGetInputFocusFn)dlsym( + s_X11.handle, + "XGetInputFocus"); + + s_X11.selectInput = (XSelectInputFn)dlsym( + s_X11.handle, + "XSelectInput"); + + // libXcursor + s_X11.cursorImageLoadCursor = (XcursorImageLoadCursorFn)dlsym( + s_X11.libCursor, + "XcursorImageLoadCursor"); + + s_X11.cursorImageCreate = (XcursorImageCreateFn)dlsym( + s_X11.libCursor, + "XcursorImageCreate"); + + s_X11.cursorImageDestroy = (XcursorImageDestroyFn)dlsym( + s_X11.libCursor, + "XcursorImageDestroy"); + + s_X11.lookupKeysym = (XLookupKeysymFn)dlsym( + s_X11.libCursor, + "XLookupKeysym"); + + s_X11.setDetectableAutoRepeat = (XkbSetDetectableAutoRepeatFn)dlsym( + s_X11.handle, + "XkbSetDetectableAutoRepeat"); + + s_X11.setLocaleModifiers = (XSetLocaleModifiersFn)dlsym( + s_X11.handle, + "XSetLocaleModifiers"); + + s_X11.openIM = (XOpenIMFn)dlsym( + s_X11.handle, + "XOpenIM"); + + s_X11.closeIM = (XCloseIMFn)dlsym( + s_X11.handle, + "XCloseIM"); + + s_X11.createIC = (XCreateICFn)dlsym( + s_X11.handle, + "XCreateIC"); + + s_X11.destroyIC = (XDestroyICFn)dlsym( + s_X11.handle, + "XDestroyIC"); + + s_X11.utf8LookupString = (Xutf8LookupStringFn)dlsym( + s_X11.handle, + "Xutf8LookupString"); + // clang-format on + + // X11 server + if (s_Video.platformInstance) { + s_X11.display = (Display*)s_Video.platformInstance; + + } else { + s_X11.display = s_X11.openDisplay(nullptr); + s_Video.platformInstance = nullptr; + } + + if (!s_X11.display) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.root = DefaultRootWindow(s_X11.display); + s_X11.screen = DefaultScreen(s_X11.display); + + checkFeatures(); + + // subscribe for monitor events + s_X11.selectRRInput(s_X11.display, s_X11.root, RRScreenChangeNotifyMask | RRNotify); + + int eventBase, errorBase = 0; + s_X11.queryRRExtension(s_X11.display, &eventBase, &errorBase); + s_X11.rrEventBase = eventBase; + s_X11.skipScreenEvent = PAL_TRUE; + + s_X11.dataID = (XContext)s_X11.uniqueContext(); + resetMonitorData(); + + s_X11.monitorCount = 0; + cacheMonitors(); + + // since X11 supports both EGL and GLX + // we try to load them and resolve the needed functions + + // we load GLX + s_X11.glxHandle = dlopen("libGL.so.1", RTLD_LAZY); + if (s_X11.glxHandle) { + GLXGetProcAddressFn load = nullptr; + load = (GLXGetProcAddressFn)dlsym(s_X11.glxHandle, "glXGetProcAddress"); + s_X11.glxGetFBConfigs = (GLXGetFBConfigsFn)load("glXGetFBConfigs"); + s_X11.glxGetFBConfigAttrib = (GLXGetFBConfigAttribFn)load("glXGetFBConfigAttrib"); + s_X11.glxGetVisualFromFBConfig = + (GLXGetVisualFromFBConfigFn)load("glXGetVisualFromFBConfig"); + } + + createKeycodeTable(); + + // disable auto key repeats + int supported; + s_X11.setDetectableAutoRepeat(s_X11.display, True, &supported); + + // create an input method + s_X11.setLocaleModifiers(""); + s_X11.im = s_X11.openIM(s_X11.display, nullptr, nullptr, nullptr); + if (s_X11.im == None) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_Video.display = (void*)s_X11.display; + return PAL_RESULT_SUCCESS; +} + +static void xShutdownVideo() +{ + s_X11.closeIM(s_X11.im); + if (!s_Video.platformInstance) { + // opened by PAL + s_X11.closeDisplay(s_X11.display); + } + + dlclose(s_X11.handle); + dlclose(s_X11.xrandr); + dlclose(s_X11.libCursor); + + if (s_X11.glxHandle) { + dlclose(s_X11.glxHandle); + } + memset(&s_X11, 0, sizeof(X11)); + memset(&s_X11Atoms, 0, sizeof(X11Atoms)); +} + +PalResult xSetFBConfig( + const int index, + PalFBConfigBackend backend) +{ + if (backend == PAL_CONFIG_BACKEND_GLX) { + return glxBackend(index); + + } else if (backend == PAL_CONFIG_BACKEND_EGL || backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { + return eglXBackend(index); + + } else { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } +} + +static void xUpdateVideo() +{ + XEvent event; + PalDispatchMode mode = PAL_DISPATCH_NONE; + while (s_X11.pending(s_X11.display)) { + s_X11.nextEvent(s_X11.display, &event); + + Window xWin = event.xany.window; + PalWindow* window = TO_PAL_HANDLE(PalWindow, xWin); + WindowData* data = nullptr; + s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&data); + + if (event.type == s_X11.rrEventBase + RRScreenChangeNotify) { + event.type = RANDR_SCREEN_CHANGE_EVENT; // for switch flow + } + + switch (event.type) { + case ClientMessage: { + // check for window close + Atom windowClose = event.xclient.data.l[0]; + if (windowClose == s_X11Atoms.WM_DELETE_WINDOW) { + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_WINDOW_CLOSE; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + } + break; + } + + case ConfigureNotify: { + // window resize or move + + // skip the first configure event + if (data->skipConfigure) { + data->skipConfigure = PAL_FALSE; + data->w = event.xconfigure.width; + data->h = event.xconfigure.height; + data->x = event.xconfigure.x; + data->y = event.xconfigure.y; + break; + } + + // real configure event + if (s_Video.eventDriver) { + // check if its a resize event + if (data->w != event.xconfigure.width || data->h != event.xconfigure.height) { + data->w = event.xconfigure.width; + data->h = event.xconfigure.height; + + // push a resize event + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_WINDOW_SIZE; + mode = palGetEventDispatchMode(driver, type); + + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackUint32(data->w, data->h); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + + // attach windows sometimes bypass + // skipConfgure an still send an initial move event + if (data->isAttached) { + if (data->skipIfAttached) { + data->skipIfAttached = PAL_FALSE; + break; + } + } + + // check if its a move event + if (data->x != event.xconfigure.x || data->y != event.xconfigure.y) { + data->x = event.xconfigure.x; + data->y = event.xconfigure.y; + + // push a move event + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_WINDOW_MOVE; + mode = palGetEventDispatchMode(driver, type); + + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackInt32(data->x, data->y); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + + /** a window has to be moved + before its can change monitors + we get the monitor the moved + window is on and check if the dpi is different + from the one it was created on */ + int monitorDPI = getWindowMonitorDPI(data); + if (monitorDPI != data->dpi) { + // window is on a different monitor + data->dpi = monitorDPI; + + // push a DPI event + type = PAL_EVENT_MONITOR_DPI_CHANGED; + mode = palGetEventDispatchMode(driver, type); + + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = monitorDPI; + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + } + } + break; + } + + case FocusIn: { + // window has gained focus + if (s_Video.eventDriver) { + int mode = event.xfocus.mode; + if (mode == NotifyGrab || mode == NotifyUngrab) { + // ignore dragging and popup focus events + break; + } + + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_WINDOW_FOCUS; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = PAL_TRUE; + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + break; + } + + case FocusOut: { + // window has lost focus + if (s_Video.eventDriver) { + int mode = event.xfocus.mode; + if (mode == NotifyGrab || mode == NotifyUngrab) { + // ignore dragging and popup focus events + break; + } + + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_WINDOW_FOCUS; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = PAL_FALSE; + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + break; + } + + case PropertyNotify: { + // check window state (maximize, minimize) + if (event.xproperty.atom == s_X11Atoms._NET_WM_STATE) { + PalWindowState state; + state = queryWindowState(event.xproperty.window); + if (state != data->state) { + data->state = state; + + // skip the first state event + if (data->skipState) { + data->skipState = PAL_FALSE; + break; + } + + // push event + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_WINDOW_STATE; + mode = palGetEventDispatchMode(driver, type); + + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = data->state; + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + } + break; + } + + case RANDR_SCREEN_CHANGE_EVENT: { + // skip the first event + if (s_X11.skipScreenEvent) { + s_X11.skipScreenEvent = PAL_FALSE; + break; + } + + // store old monitor count + int oldCount = s_X11.monitorCount; + s_X11.monitorCount = 0; + cacheMonitors(); + + if (oldCount != s_X11.monitorCount) { + // a monitor has been added or removed + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_MONITOR_LIST_CHANGED; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + } + break; + } + + case MotionNotify: { + // mouse moved + const int x = event.xmotion.x; + const int y = event.xmotion.y; + const int dx = x - s_Mouse.lastX; + const int dy = y - s_Mouse.lastY; + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_MOUSE_MOVE; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackInt32(x, y); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + + // push a mouse delta event + type = PAL_EVENT_MOUSE_DELTA; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackInt32(dx, dy); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + + s_Mouse.lastX = x; + s_Mouse.lastY = y; + s_Mouse.dx = dx; + s_Mouse.dy = dy; + break; + } + + case ButtonPress: + case ButtonRelease: { + int xButton = event.xbutton.button; + PalBool pressed = (event.xbutton.type == ButtonPress); + PalMouseButton button = 0; + PalEventType type; + + if (xButton == 1) { + button = PAL_MOUSE_BUTTON_LEFT; + } else if (xButton == 3) { + button = PAL_MOUSE_BUTTON_RIGHT; + } else if (xButton == 2) { + button = PAL_MOUSE_BUTTON_MIDDLE; + } + + s_Mouse.state[button] = pressed; + if (s_Video.eventDriver && button != 0) { + PalEventDriver* driver = s_Video.eventDriver; + if (pressed) { + type = PAL_EVENT_MOUSE_BUTTONDOWN; + } else { + type = PAL_EVENT_MOUSE_BUTTONUP; + } + + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackUint32(button, NULL_BUTTON_SERIAL); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + + int scrollX = 0; + int scrollY = 0; + if (xButton == 4) { + // scroll up + scrollY = 1; + } else if (xButton == 5) { + // scroll down + scrollY = -1; + } else if (xButton == 6) { + // scroll left + scrollX = -1; + } else if (xButton == 7) { + // scroll right + scrollX = 1; + } + + s_Mouse.WheelX = scrollX; + s_Mouse.WheelY = scrollY; + if (s_Video.eventDriver && (scrollX || scrollY)) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_WHEEL); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = PAL_EVENT_MOUSE_WHEEL; + event.data = palPackInt32(scrollX, scrollY); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + break; + } + + case KeyPress: + case KeyRelease: { + int xScancode = event.xkey.keycode; + PalBool pressed = (event.xbutton.type == KeyPress); + PalScancode scancode = PAL_SCANCODE_UNKNOWN; + PalKeycode keycode = PAL_KEYCODE_UNKNOWN; + PalEventType type; + KeySym keySym = s_X11.lookupKeysym(&event.xkey, 0); + + // special handling for Pause/break with Home + if (xScancode == 110) { + if (keySym == XK_Pause) { + scancode = PAL_SCANCODE_PAUSE; + } else { + scancode = PAL_SCANCODE_HOME; + } + + } else { + int index = xScancode - 8; + scancode = s_Keyboard.scancodes[index]; + } + + // printable and text input keys are from the range + // 32 (PAL_KEYCODE_SPACE) and 122 (PAL_KEYCODE_Z) + // The rest are almost the same as their scancode + // Maybe there will be a layout that makes this wrong + // but for now this works + if (keySym >= XK_space && keySym <= XK_z) { + // a printable or input key + keycode = s_Keyboard.keycodes[keySym]; + + } else { + // Since PalKeycode and PalScancode have the same integers + // we can make a direct cast without a table + // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) + keycode = (PalKeycode)(uint32_t)scancode; + } + + // If we got a keySym but its not mapped into our keycode array + // we do a direct cast as well + if (keycode == PAL_KEYCODE_UNKNOWN) { + keycode = (PalKeycode)(uint32_t)scancode; + } + + // update our keyboard and mouse state to handle key repeat + PalBool repeat = s_Keyboard.keycodeState[keycode]; + s_Keyboard.scancodeState[scancode] = pressed; + s_Keyboard.keycodeState[keycode] = pressed; + + if (pressed) { + if (repeat) { + type = PAL_EVENT_KEYREPEAT; + } else { + type = PAL_EVENT_KEYDOWN; + } + } else { + type = PAL_EVENT_KEYUP; + } + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackUint32(keycode, scancode); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + + // check for char event if enabled + type = PAL_EVENT_KEYCHAR; + mode = palGetEventDispatchMode(driver, type); + if (mode == PAL_DISPATCH_NONE) { + break; + } + + int status; + char buffer[32]; + KeySym keySym; + int len = s_X11.utf8LookupString( + data->ic, + &event.xkey, + buffer, + sizeof(buffer), + &keySym, + &status); + + uint32_t codepoint = 0; + if (status == XLookupChars || status == XLookupBoth) { + // decode to Unicode codepoint + unsigned char ch = buffer[0]; + if (ch < 0x80) { + // 1 byte (A-Z) + codepoint = ch; + + } else if ((ch >> 5) == 0x6 && len >= 2) { + // 2 byte + codepoint = ((ch & 0x1F) << 6) | buffer[1] & 0x3F; + + } else if ((ch >> 4) == 0xE && len >= 3) { + // 3 byte + // clang-format off + codepoint = ((ch & 0x0F) << 12) | + ((buffer[1] & 0x3F) << 6) | + (buffer[2] & 0x3F); + // clang-format on + + } else if ((ch >> 3) == 0x1E && len >= 4) { + // 4 byte + // clang-format off + codepoint = ((ch & 0x07) << 18) | + ((buffer[1] & 0x3F) << 12) | + ((buffer[2] & 0x3F) << 6) | + (buffer[3] & 0x3F); + // clang-format on + } + + PalEvent event = {0}; + event.type = type; + event.data = codepoint; + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + break; + } + } + } + + s_X11.flush(s_X11.display); +} + +void* xGetInstance() +{ + return (void*)s_X11.display; +} + +#endif // PAL_HAS_X11_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/x11/pal_window_x11.c b/src/video/linux/x11/pal_window_x11.c new file mode 100644 index 00000000..5c958d95 --- /dev/null +++ b/src/video/linux/x11/pal_window_x11.c @@ -0,0 +1,1129 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_X11_BACKEND == 1 + +#include "pal_x11.h" +#include "pal_shared.h" + +static int xErrorHandler( + Display*, + XErrorEvent* e) +{ + // this is use for simple success and failure + s_X11.error = PAL_TRUE; + return 0; +} + +static PalResult xCreateWindow( + const PalWindowCreateInfo* info, + PalWindow** outWindow) +{ + Window window = None; + PalMonitor* monitor = nullptr; + PalMonitorInfo monitorInfo; + + WindowData* data = getFreeWindowData(); + if (!data) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + Visual* visual = nullptr; + int depth = 0; + Colormap colormap = None; + unsigned long bgPixel = 0; + unsigned long borderPixel = 0; + + if (s_X11.visualInfo) { + visual = s_X11.visualInfo->visual; + depth = s_X11.visualInfo->depth; + bgPixel = 0; + borderPixel = 0; + colormap = s_X11.createColormap(s_X11.display, s_X11.root, visual, AllocNone); + + if (!colormap) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + data->colormap = colormap; + + } else { + // use a default visual + visual = DefaultVisual(s_X11.display, s_X11.screen); + depth = DefaultDepth(s_X11.display, s_X11.screen); + bgPixel = WhitePixel(s_X11.display, s_X11.screen); + borderPixel = BlackPixel(s_X11.display, s_X11.screen); + colormap = DefaultColormap(s_X11.display, s_X11.screen); + data->colormap = None; + } + + // get monitor + int monitorX = 0; + int monitorY = 0; + uint32_t monitorW = 0; + uint32_t monitorH = 0; + int dpi = 0; + if (info->monitor) { + monitor = info->monitor; + + } else { + // get primary monitor + xGetPrimaryMonitor(&monitor); + } + + if (monitor) { + // get monitor info + PalResult result = palGetMonitorInfo(monitor, &monitorInfo); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + monitorX = monitorInfo.x; + monitorY = monitorInfo.y; + monitorW = monitorInfo.width; + monitorH = monitorInfo.height; + dpi = monitorInfo.dpi; + + } else { + // primary monitor is not set + XRRScreenResources* resources = nullptr; + resources = s_X11.getScreenResources(s_X11.display, s_X11.root); + for (int i = 0; i < resources->noutput; ++i) { + RROutput output = resources->outputs[i]; + XRROutputInfo* outputInfo = + s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); + + // check if its a monitor + if (outputInfo->connection != RR_Connected || outputInfo->crtc == None) { + s_X11.freeOutputInfo(outputInfo); + continue; + } + + XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); + + monitorX = crtc->x; + monitorY = crtc->y; + monitorW = crtc->width; + monitorH = crtc->height; + + // get DPI + float raw = crtc->width / 1920.0f; + float steps[] = {1.0f, 1.2f, 1.5f, 1.75, 2.0f}; + float closest = steps[0]; + float minDiff = fabsf(raw - steps[0]); + + for (int i = 1; i < sizeof(steps) / sizeof(steps[0]); i++) { + float diff = fabsf(raw - steps[i]); + if (diff < minDiff) { + minDiff = diff; + closest = steps[i]; + } + } + + dpi = (uint32_t)(closest * 96.0f); + + s_X11.freeCrtcInfo(crtc); + s_X11.freeOutputInfo(outputInfo); + break; + } + s_X11.freeScreenResources(resources); + } + + int32_t x, y = 0; + // the position and size must be scaled with the dpi before this call + if (info->center) { + x = monitorX + (monitorW - info->width) / 2; + y = monitorY + (monitorH - info->height) / 2; + + } else { + // we set 100 for each axix + x = monitorX + 100; + y = monitorY + 100; + } + + // check and set transparency + if (info->style & PAL_WINDOW_STYLE_TRANSPARENT) { + if (!(s_Video.features & PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW)) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // we dont need to set any flag + } + + long mask = StructureNotifyMask | KeyPressMask; + mask |= KeyReleaseMask; + mask |= ButtonPressMask; + mask |= ButtonReleaseMask; + mask |= PointerMotionMask; + mask |= FocusChangeMask; + mask |= PropertyChangeMask; + + XSetWindowAttributes attrs = {0}; + attrs.colormap = colormap; + attrs.event_mask = mask; + attrs.background_pixel = bgPixel; + attrs.border_pixel = borderPixel; + attrs.override_redirect = False; + + // create window + window = s_X11.createWindow( + s_X11.display, + s_X11.root, + x, + y, + info->width, + info->height, + 0, // border width + depth, + InputOutput, // class + visual, + CWEventMask | CWColormap | CWBorderPixel | CWBackPixel, + &attrs); + + if (window == None) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // set pid property + pid_t pid = getpid(); + s_X11.changeProperty( + s_X11.display, + window, + s_X11Atoms._NET_WM_PID, + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char*)&pid, + 1); + + // set class property + XClassHint* hints = s_X11.allocClassHint(); + if (hints) { + const char* resName = getenv("RESOURCE_NAME"); + const char* resClass = getenv("RESOURCE_CLASS"); + + if (!resName || strlen(resName) == 0) { + resName = info->title; + } + + if (!resClass || strlen(resClass) == 0) { + resClass = s_Video.className; + } + + hints->res_name = (char*)resName; + hints->res_class = (char*)resClass; + s_X11.setClassHint(s_X11.display, window, hints); + s_X11.free(hints); + } + + if (s_X11Atoms.unicodeTitle && info->title) { + s_X11.changeProperty( + s_X11.display, + window, + s_X11Atoms._NET_WM_NAME, + s_X11Atoms.UTF8_STRING, + 8, // unsigned char + PropModeReplace, + info->title, + strlen(info->title)); + + } else { + if (info->title) { + s_X11.storeName(s_X11.display, window, info->title); + } + } + + // borderless + if (info->style & PAL_WINDOW_STYLE_BORDERLESS) { + if (!(s_Video.features & PAL_VIDEO_FEATURE_BORDERLESS_WINDOW)) { + s_X11.destroyWindow(s_X11.display, window); + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.changeProperty( + s_X11.display, + window, + s_X11Atoms._NET_WM_WINDOW_TYPE, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*)&s_X11Atoms._NET_WM_WINDOW_TYPE_SPLASH, + 1); + } + + // tool window + if (info->style & PAL_WINDOW_STYLE_TOOL) { + if (!(s_Video.features & PAL_VIDEO_FEATURE_TOOL_WINDOW)) { + s_X11.destroyWindow(s_X11.display, window); + + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.changeProperty( + s_X11.display, + window, + s_X11Atoms._NET_WM_WINDOW_TYPE, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*)&s_X11Atoms._NET_WM_WINDOW_TYPE_UTILITY, + 1); + } + + // topmost + if (info->style & PAL_WINDOW_STYLE_TOPMOST) { + if (s_X11Atoms._NET_WM_STATE_ABOVE) { + s_X11.changeProperty( + s_X11.display, + window, + s_X11Atoms._NET_WM_STATE, + XA_ATOM, + 32, + PropModeAppend, + (unsigned char*)&s_X11Atoms._NET_WM_STATE_ABOVE, + 1); + } + } + + // set size hints + XSizeHints wmHints = {0}; + wmHints.flags = PPosition | PSize; + wmHints.x = x; + wmHints.y = y; + wmHints.width = info->width; + wmHints.height = info->height; + + // resizable + if (!(info->style & PAL_WINDOW_STYLE_RESIZABLE)) { + wmHints.flags |= PMinSize; + wmHints.flags |= PMaxSize; + wmHints.min_width = wmHints.max_width = info->width; + wmHints.min_height = wmHints.max_height = info->height; + } + + // show window + s_X11.setWMNormalHints(s_X11.display, window, &wmHints); + if (info->show) { + s_X11.mapWindow(s_X11.display, window); + s_X11.flush(s_X11.display); + } + + // check if the window has been mapped + // we use this to minimize or maximize + XWindowAttributes attr; + s_X11.getWindowAttributes(s_X11.display, window, &attr); + PalBool windowMapped = attr.map_state = IsViewable; + + // maximize + if (info->maximized) { + if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { + s_X11.destroyWindow(s_X11.display, window); + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // if the window is not mapped, we wait till its mapped + if (!windowMapped) { + // wait till the window is mapped + for (;;) { + XEvent event; + s_X11.nextEvent(s_X11.display, &event); + if (event.type == MapNotify && event.xmap.window == window) { + windowMapped = PAL_TRUE; + break; + } + } + } + + xSendWMEvent( + window, + s_X11Atoms._NET_WM_STATE, + s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT, + s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ, + 1, + 0, + PAL_TRUE); // _NET_WM_STATE_ADD + } + + // minimize + if (info->minimized) { + if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { + s_X11.destroyWindow(s_X11.display, window); + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // if the window is not mapped, we wait till its mapped + if (!windowMapped) { + // wait till the window is mapped + for (;;) { + XEvent event; + s_X11.nextEvent(s_X11.display, &event); + if (event.type == MapNotify && event.xmap.window == window) { + windowMapped = PAL_TRUE; + break; + } + } + } + s_X11.iconifyWindow(s_X11.display, window, s_X11.screen); + } + + s_X11.setWMProtocols(s_X11.display, window, &s_X11Atoms.WM_DELETE_WINDOW, 1); + s_X11.flush(s_X11.display); + + // attach the window data to the window + data->skipConfigure = PAL_TRUE; + data->skipState = PAL_TRUE; + data->isAttached = PAL_FALSE; // PAL_TRUE for attached windows + data->dpi = dpi; // the current window monitor + data->window = TO_PAL_HANDLE(PalWindow, window); + s_X11.saveContext(s_X11.display, window, s_X11.dataID, (XPointer)data); + + // create an input context + data->ic = s_X11.createIC( + s_X11.im, + XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, + window, + XNFocusWindow, + window, + nullptr); + + if (!data->ic) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + *outWindow = TO_PAL_HANDLE(PalWindow, window); + return PAL_RESULT_SUCCESS; +} + +static void xDestroyWindow(PalWindow* window) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + WindowData* data = nullptr; + s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&data); + + // PAL does not destroy an attached window + if (data->isAttached) { + return; + } + + s_X11.destroyIC(data->ic); + s_X11.destroyWindow(s_X11.display, xWin); + + if (data->colormap != None) { + s_X11.freeColormap(s_X11.display, data->colormap); + } + + data->used = PAL_FALSE; +} + +PalResult xMinimizeWindow(PalWindow* window) +{ + if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.iconifyWindow(s_X11.display, xWin, s_X11.screen); + return PAL_RESULT_SUCCESS; +} + +PalResult xMaximizeWindow(PalWindow* window) +{ + if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + xSendWMEvent( + xWin, + s_X11Atoms._NET_WM_STATE, + s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT, + s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ, + 1, + 0, + PAL_TRUE); // _NET_WM_STATE_ADD + + return PAL_RESULT_SUCCESS; +} + +PalResult xRestoreWindow(PalWindow* window) +{ + if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // since we have no fixed way to restore the window + // we just restore from minimized and maximized state + xSendWMEvent( + xWin, + s_X11Atoms._NET_WM_STATE, + s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT, + s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ, + 1, + 0, + PAL_FALSE); // _NET_WM_STATE_REMOVE + + s_X11.mapRaised(s_X11.display, xWin); + + return PAL_RESULT_SUCCESS; +} + +PalResult xShowWindow(PalWindow* window) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.mapWindow(s_X11.display, xWin); + return PAL_RESULT_SUCCESS; +} + +PalResult xHideWindow(PalWindow* window) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.unmapWindow(s_X11.display, xWin); + return PAL_RESULT_SUCCESS; +} + +PalResult xFlashWindow( + PalWindow* window, + const PalFlashInfo* info) +{ + if (info->flags & PAL_FLASH_CAPTION) { + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + PalBool add = PAL_FALSE; + if (info->flags & PAL_FLASH_TRAY) { + add = PAL_TRUE; + } + + // check if modern flashing is supported + if (s_X11Atoms._NET_WM_STATE_DEMANDS_ATTENTIONS) { + xSendWMEvent( + xWin, + s_X11Atoms._NET_WM_STATE, + s_X11Atoms._NET_WM_STATE_DEMANDS_ATTENTIONS, + 0, + 0, + 0, + add); // _NET_WM_STATE_ADD + + } else { + // legacy mode + XWMHints* hints = s_X11.getWMHints(s_X11.display, xWin); + if (!hints) { + hints = s_X11.allocWMHints(); + if (!hints) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (add) { + hints->flags |= XUrgencyHint; + } else { + hints->flags &= ~XUrgencyHint; + } + s_X11.setWMHints(s_X11.display, xWin, hints); + s_X11.free(hints); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult xGetWindowStyle( + PalWindow* window, + PalWindowStyle* outStyle) +{ + // Window Manager quirks + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult xGetWindowMonitor( + PalWindow* window, + PalMonitor** outMonitor) +{ + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult xGetWindowTitle( + PalWindow* window, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!outBuffer || bufferSize <= 0) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (s_X11Atoms.unicodeTitle) { + Atom type; + int format; + unsigned long count, bytesAfter; + unsigned char* prop = nullptr; + s_X11.getWindowProperty( + s_X11.display, + xWin, + s_X11Atoms._NET_WM_NAME, + 0, + (~0L), + False, + s_X11Atoms.UTF8_STRING, + &type, + &format, + &count, + &bytesAfter, + &prop); + + if (bufferSize >= count) { + strcpy(outBuffer, (const char*)prop); + } else { + // copy up to the limiit of the supplied buffer + strncpy(outBuffer, (const char*)prop, bufferSize); + } + s_X11.free(prop); + + } else { + XTextProperty text; + if (!s_X11.getWMName(s_X11.display, xWin, &text)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (bufferSize >= text.nitems) { + strcpy(outBuffer, (const char*)text.value); + } else { + // copy up to the limiit of the supplied buffer + strncpy(outBuffer, (const char*)text.value, bufferSize); + } + s_X11.free(text.value); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult xGetWindowPos( + PalWindow* window, + int32_t* x, + int32_t* y) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (x) { + *x = attr.x; + } + + if (y) { + *y = attr.y; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult xGetWindowSize( + PalWindow* window, + uint32_t* width, + uint32_t* height) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (width) { + *width = attr.width; + } + + if (height) { + *height = attr.height; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult xGetWindowState( + PalWindow* window, + PalWindowState* outState) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + Atom type; + int format; + unsigned long count, bytesAfter; + unsigned char* props = nullptr; + s_X11.getWindowProperty( + s_X11.display, + xWin, + s_X11Atoms._NET_WM_STATE, + 0, + (~0L), + False, + XA_ATOM, + &type, + &format, + &count, + &bytesAfter, + &props); + + PalWindowState state = PAL_WINDOW_STATE_RESTORED; + for (unsigned long i = 0; i < count; ++i) { + if (props[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ) { + state = PAL_WINDOW_STATE_MAXIMIZED; + } + + if (props[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT) { + state = PAL_WINDOW_STATE_MAXIMIZED; + } + + if (props[i] == s_X11Atoms._NET_WM_STATE_HIDDEN) { + state = PAL_WINDOW_STATE_MINIMIZED; + } + } + + s_X11.free(props); + *outState = state; + return PAL_RESULT_SUCCESS; +} + +PalBool xIsWindowVisible(PalWindow* window) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return PAL_FALSE; + } + + return attr.map_state == IsViewable; +} + +PalWindow* xGetFocusWindow() +{ + Window window; + int tmp; + s_X11.getInputFocus(s_X11.display, &window, &tmp); + Window xWin = FROM_PAL_HANDLE(Window, window); + + if (xWin == s_X11.root) { + return nullptr; + } + return TO_PAL_HANDLE(PalWindow, window); +} + +PalResult xGetWindowHandleInfo( + PalWindow* window, + PalWindowHandleInfo* info) +{ + if (!s_Video.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!window || !info) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + info->nativeDisplay = (void*)s_X11.display; + info->nativeWindow = (void*)window; + info->nativeHandle1 = nullptr; + info->nativeHandle2 = nullptr; + info->nativeHandle3 = nullptr; + + return PAL_RESULT_SUCCESS; +} + +static PalResult xSetWindowOpacity( + PalWindow* window, + float opacity) +{ + XErrorHandler old = s_X11.setErrorHandler(xErrorHandler); + unsigned long value = (unsigned long)(opacity * 0xFFFFFFFFUL + 0.5f); + + s_X11.changeProperty( + s_X11.display, + FROM_PAL_HANDLE(Window, window), + s_X11Atoms._NET_WM_WINDOW_OPACITY, + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char*)&value, + 1); + + s_X11.sync(s_X11.display, False); + s_X11.setErrorHandler(old); + if (s_X11.error) { + // technically, this is the only error that can occur + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult xSetWindowStyle( + PalWindow* window, + PalWindowStyle style) +{ + // Window Manager quirks + return palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); +} + +PalResult xSetWindowTitle( + PalWindow* window, + const char* title) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (s_X11Atoms.unicodeTitle) { + s_X11.changeProperty( + s_X11.display, + xWin, + s_X11Atoms._NET_WM_NAME, + s_X11Atoms.UTF8_STRING, + 8, // unsigned char + PropModeReplace, + title, + strlen(title)); + + } else { + s_X11.storeName(s_X11.display, xWin, title); + } + + s_X11.flush(s_X11.display); + return PAL_RESULT_SUCCESS; +} + +PalResult xSetWindowPos( + PalWindow* window, + int32_t x, + int32_t y) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_X11.moveWindow(s_X11.display, xWin, x, y); + s_X11.flush(s_X11.display); + return PAL_RESULT_SUCCESS; +} + +PalResult xSetWindowSize( + PalWindow* window, + uint32_t width, + uint32_t height) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // X11 does not allow users resize programaticaly + // if the window is not resizable. + // so we hack it by making the window resizable and resizing + // then revert back. + XSizeHints hints; + long tmp; + s_X11.getWMNormalHints(s_X11.display, xWin, &hints, &tmp); + if ((hints.flags & PMinSize) && (hints.flags & PMaxSize)) { + hints.flags &= ~PMinSize; + hints.flags &= ~PMaxSize; + s_X11.resizeWindow(s_X11.display, xWin, width, height); + s_X11.flush(s_X11.display); + + // revert + hints.flags |= PMinSize; + hints.flags |= PMaxSize; + hints.min_width = hints.max_width = width; + hints.min_height = hints.max_height = height; + + } else { + // window is already resizable + s_X11.resizeWindow(s_X11.display, xWin, width, height); + } + + s_X11.flush(s_X11.display); + return PAL_RESULT_SUCCESS; +} + +PalResult xSetFocusWindow(PalWindow* window) +{ + Window xWin = FROM_PAL_HANDLE(Window, window); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (s_X11Atoms._NET_ACTIVE_WINDOW) { + xSendWMEvent(xWin, s_X11Atoms._NET_ACTIVE_WINDOW, CurrentTime, 0, 0, 0, + PAL_TRUE); // 1 + + } else { + s_X11.setInputFocus(s_X11.display, xWin, RevertToParent, CurrentTime); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult xAttachWindow( + void* windowHandle, + PalWindow** outWindow) +{ + Window xWin = FROM_PAL_HANDLE(Window, windowHandle); + XWindowAttributes attr; + if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // get a free slot and set the window handle to it + // we also set a flag to make sure we know this is an attached window + WindowData* data = getFreeWindowData(); + if (!data) { + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + PalWindow* window = TO_PAL_HANDLE(PalWindow, xWin); + // we assume the window was just created, since there is + // no official way to get the DPI + data->isAttached = PAL_TRUE; + data->dpi = 96; // if this is not the DPI, a dpi event will be triggered + + // If the window manager has not mapped the window yet, + // we dont need the initial Size / Move events + data->skipConfigure = PAL_TRUE; + data->skipState = PAL_TRUE; + data->skipIfAttached = PAL_TRUE; + data->window = window; + data->w = attr.width; + data->h = attr.height; + data->x = attr.x; + data->y = attr.y; + + // get the current window state + // we dont check the return code because we know the window is valid + xGetWindowState(window, &data->state); + + // listen to the events we support + long mask = StructureNotifyMask | KeyPressMask; + mask |= KeyReleaseMask; + mask |= ButtonPressMask; + mask |= ButtonReleaseMask; + mask |= PointerMotionMask; + mask |= FocusChangeMask; + mask |= PropertyChangeMask; + s_X11.selectInput(s_X11.display, xWin, mask); + + // listen to window close event + s_X11.setWMProtocols(s_X11.display, xWin, &s_X11Atoms.WM_DELETE_WINDOW, 1); + + s_X11.saveContext(s_X11.display, xWin, s_X11.dataID, (XPointer)data); + s_X11.flush(s_X11.display); + + *outWindow = window; + return PAL_RESULT_SUCCESS; +} + +PalResult xDetachWindow( + PalWindow* window, + void** outWindowHandle) +{ + // we check is the window is really detachable + Window xWin = FROM_PAL_HANDLE(Window, window); + WindowData* data = nullptr; + s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&data); + if (!data) { + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (data->isAttached == PAL_FALSE) { + // window was created by PAL + return palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // detach the window + data->used = PAL_FALSE; + long mask = 0; + s_X11.selectInput(s_X11.display, xWin, mask); + s_X11.setWMProtocols(s_X11.display, xWin, nullptr, 0); + + if (outWindowHandle) { + *outWindowHandle = (void*)window; + } + + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_X11_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/x11/pal_x11.h b/src/video/linux/x11/pal_x11.h new file mode 100644 index 00000000..b470930b --- /dev/null +++ b/src/video/linux/x11/pal_x11.h @@ -0,0 +1,563 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_X11_H +#define _PAL_X11_H +#ifdef __linux__ +#if PAL_HAS_X11_BACKEND == 1 + +#include "video/linux/pal_video_linux.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define X_INTERN(x) s_X11Atoms.x = s_X11.internAtom(s_X11.display, #x, False) +#define RANDR_SCREEN_CHANGE_EVENT 1040 + +// optionally, needed to create visual from FBConfig +#define GLX_FBCONFIG_ID 0x8012 +typedef struct __GLXFBConfigRec* GLXFBConfig; + +typedef GLXFBConfig* (*GLXGetFBConfigsFn)( + Display*, + int, + int*); + +typedef int (*GLXGetFBConfigAttribFn)( + Display*, + GLXFBConfig, + int, + int*); + +typedef XVisualInfo* (*GLXGetVisualFromFBConfigFn)( + Display*, + GLXFBConfig); + +typedef XVisualInfo* (*GLXGetProcAddressFn)(const unsigned char*); + +typedef Display* (*XOpenDisplayFn)(const char*); +typedef int (*XCloseDisplayFn)(Display*); + +typedef int (*XGetWindowAttributesFn)( + Display*, + Window, + XWindowAttributes*); + +typedef int (*XGetWindowPropertyFn)( + Display*, + Window, + Atom, + long, + long, + Bool, + Atom, + Atom*, + int*, + unsigned long*, + unsigned long*, + unsigned char**); + +typedef Atom (*XInternAtomFn)( + Display*, + _Xconst char*, + Bool); + +typedef Window (*XGetSelectionOwnerFn)( + Display*, + Atom); + +typedef Window (*XCreateWindowFn)( + Display*, + Window, + int, + int, + unsigned int, + unsigned int, + unsigned int, + int, + unsigned int, + Visual*, + unsigned long, + XSetWindowAttributes*); + +typedef int (*XChangePropertyFn)( + Display*, + Window, + Atom, + Atom, + int, + int, + _Xconst unsigned char*, + int); + +typedef int (*XFlushFn)(Display*); + +typedef Colormap (*XCreateColormapFn)( + Display*, + Window, + Visual*, + int); + +typedef int (*XFreeColormapFn)( + Display*, + Colormap); + +typedef int (*XDestroyWindowFn)( + Display*, + Window); + +typedef int (*XStoreNameFn)( + Display*, + Window, + _Xconst char*); + +typedef int (*XMapWindowFn)( + Display*, + Window); + +typedef int (*XUnmapWindowFn)( + Display*, + Window); + +typedef int (*XMatchVisualInfoFn)( + Display*, + int, + int, + int, + XVisualInfo*); + +typedef int (*XPendingFn)(Display*); + +typedef int (*XSetWMProtocolsFn)( + Display*, + Window, + Atom*, + int); + +typedef int (*XNextEventFn)( + Display*, + XEvent*); + +typedef int (*XSetWMNormalHintsFn)( + Display*, + Window, + XSizeHints*); + +typedef int (*XGetWMNormalHintsFn)( + Display*, + Window, + XSizeHints*, + long*); + +typedef int (*XSendEventFn)( + Display*, + Window, + Bool, + long, + XEvent*); + +typedef int (*XMoveWindowFn)( + Display*, + Window, + int, + int); + +typedef int (*XResizeWindowFn)( + Display*, + Window, + unsigned int, + unsigned int); + +typedef int (*XIconifyWindowFn)( + Display*, + Window, + int); + +typedef XErrorHandler (*XSetErrorHandlerFn)(XErrorHandler); + +typedef int (*XSyncFn)( + Display*, + Bool); + +typedef int (*XSaveContextFn)( + Display*, + XID, + XContext, + _Xconst char*); + +typedef int (*XFindContextFn)( + Display*, + XID, + XContext, + XPointer*); + +typedef XrmQuark (*XrmUniqueQuarkFn)(void); + +typedef int (*XRRSetCrtcConfigFn)( + Display*, + XRRScreenResources*, + RRCrtc, + Time, + int, + int, + RRMode, + Rotation, + RROutput*, + int); + +typedef XRRScreenResources* (*XRRGetScreenResourcesFn)( + Display*, + Window); + +typedef RROutput (*XRRGetOutputPrimaryFn)( + Display*, + Window); + +typedef XRROutputInfo* (*XRRGetOutputInfoFn)( + Display*, + XRRScreenResources*, + RROutput); + +typedef XRRCrtcInfo* (*XRRGetCrtcInfoFn)( + Display*, + XRRScreenResources*, + RRCrtc); + +typedef void (*XRRFreeScreenResourcesFn)(XRRScreenResources*); + +typedef void (*XRRFreeOutputInfoFn)(XRROutputInfo*); + +typedef void (*XRRFreeCrtcInfoFn)(XRRCrtcInfo*); + +typedef void (*XRRSelectInputFn)( + Display*, + Window, + int); + +typedef int (*XRRQueryExtensionFn)( + Display*, + int*, + int*); + +typedef XClassHint* (*XAllocClassHintFn)(void); + +typedef int (*XSetClassHintFn)( + Display*, + Window, + XClassHint*); + +typedef int (*XFreeFn)(void*); + +typedef Cursor (*XCreateFontCursorFn)( + Display*, + unsigned int); + +typedef int (*XFreePixmapFn)( + Display*, + Pixmap); + +typedef int (*XSetWMHintsFn)( + Display*, + Window, + XWMHints*); + +typedef int (*XGrabPointerFn)( + Display*, + Window, + Bool, + unsigned int, + int, + int, + Window, + Cursor, + Time); + +typedef Cursor (*XCreatePixmapCursorFn)( + Display*, + Pixmap, + Pixmap, + XColor*, + XColor*, + unsigned int, + unsigned int); + +typedef int (*XWarpPointerFn)( + Display*, + Window, + Window, + int, + int, + unsigned int, + unsigned int, + int, + int); + +typedef Status (*XGetWMNameFn)( + Display*, + Window, + XTextProperty*); + +typedef Bool (*XQueryPointerFn)( + Display*, + Window, + Window*, + Window*, + int*, + int*, + int*, + int*, + unsigned int*); + +typedef int (*XUngrabPointerFn)( + Display*, + Time); + +typedef XWMHints* (*XAllocWMHintsFn)(void); + +typedef int (*XMapRaisedFn)( + Display*, + Window); + +typedef int (*XUndefineCursorFn)( + Display*, + Window); + +typedef int (*XDefineCursorFn)( + Display*, + Window, + Cursor); + +typedef int (*XFreeCursorFn)( + Display*, + Cursor); + +typedef XWMHints* (*XGetWMHintsFn)( + Display*, + Window); + +typedef Cursor (*XCreatePixmapCursorFn)( + Display*, + Pixmap, + Pixmap, + XColor*, + XColor*, + unsigned int, + unsigned int); + +typedef int (*XSetInputFocusFn)( + Display*, + Window, + int, + Time); + +typedef int (*XGetInputFocusFn)( + Display*, + Window*, + int*); + +typedef Pixmap (*XCreatePixmapFn)( + Display*, + Drawable, + unsigned int, + unsigned int, + unsigned int); + +typedef XVisualInfo* (*XGetVisualInfoFn)( + Display*, + long, + XVisualInfo*, + int*); + +typedef int (*XSelectInputFn)( + Display*, + Window, + long); + +typedef Cursor (*XcursorImageLoadCursorFn)( + Display*, + const XcursorImage*); + +typedef XcursorImage* (*XcursorImageCreateFn)( + int, + int); + +typedef void (*XcursorImageDestroyFn)(XcursorImage*); + +typedef KeySym (*XLookupKeysymFn)( + XKeyEvent*, + int); + +typedef int (*XkbSetDetectableAutoRepeatFn)( + Display*, + int, + int*); + +typedef char* (*XSetLocaleModifiersFn)(const char*); + +typedef XIM (*XOpenIMFn)( + Display*, + struct _XrmHashBucketRec*, + char*, + char*); + +typedef int (*XCloseIMFn)(XIM); + +typedef XIC (*XCreateICFn)( + XIM, + ...) _X_SENTINEL(0); + +typedef void (*XDestroyICFn)(XIC); + +typedef int (*Xutf8LookupStringFn)( + XIC, + XKeyPressedEvent*, + char*, + int, + KeySym*, + int*); + +typedef struct { + PalBool unicodeTitle; + + Atom WM_DELETE_WINDOW; + Atom _NET_SUPPORTED; + Atom _NET_WM_STATE; + Atom _NET_WM_STATE_ABOVE; + Atom _NET_WM_STATE_HIDDEN; + Atom _NET_WM_STATE_MAXIMIZED_VERT; + Atom _NET_WM_STATE_MAXIMIZED_HORZ; + Atom _NET_WM_WINDOW_TYPE_UTILITY; + Atom _NET_WM_DESKTOP; + Atom _NET_WM_STATE_DEMANDS_ATTENTIONS; + Atom _NET_WM_WINDOW_OPACITY; + + Atom _NET_WM_NAME; + Atom UTF8_STRING; + Atom _NET_WM_WINDOW_TYPE; + Atom _NET_WM_WINDOW_TYPE_SPLASH; + Atom _NET_WM_PID; + Atom _WM_CLASS; + Atom _NET_ACTIVE_WINDOW; + Atom _NET_WM_ICON; +} X11Atoms; + +typedef struct { + PalBool error; + PalBool skipScreenEvent; + int bpp; + int screen; + int depth; + int monitorCount; + int rrEventBase; + void* handle; + void* xrandr; + void* glxHandle; + void* libCursor; + XIM im; + Display* display; + Window root; + XContext dataID; + XVisualInfo* visualInfo; + + XOpenDisplayFn openDisplay; + XCloseDisplayFn closeDisplay; + XGetWindowAttributesFn getWindowAttributes; + XGetWindowPropertyFn getWindowProperty; + XInternAtomFn internAtom; + XGetSelectionOwnerFn getSelectionOwner; + XFreeColormapFn freeColormap; + XStoreNameFn storeName; + XChangePropertyFn changeProperty; + XFlushFn flush; + XCreateColormapFn createColormap; + XMapWindowFn mapWindow; + XUnmapWindowFn unmapWindow; + + XCreateWindowFn createWindow; + XDestroyWindowFn destroyWindow; + XMatchVisualInfoFn matchVisualInfo; + XPendingFn pending; + XSetWMProtocolsFn setWMProtocols; + XNextEventFn nextEvent; + XSetWMNormalHintsFn setWMNormalHints; + XGetWMNormalHintsFn getWMNormalHints; + XSendEventFn sendEvent; + XMoveWindowFn moveWindow; + XResizeWindowFn resizeWindow; + XIconifyWindowFn iconifyWindow; + + XSetErrorHandlerFn setErrorHandler; + XSyncFn sync; + XSaveContextFn saveContext; + XFindContextFn findContext; + XrmUniqueQuarkFn uniqueContext; + + XRRSetCrtcConfigFn setCrtcConfig; + XRRGetScreenResourcesFn getScreenResources; + XRRGetOutputPrimaryFn getOutputPrimary; + XRRGetOutputInfoFn getOutputInfo; + XRRGetCrtcInfoFn getCrtcInfo; + XRRFreeScreenResourcesFn freeScreenResources; + XRRFreeOutputInfoFn freeOutputInfo; + XRRFreeCrtcInfoFn freeCrtcInfo; + XRRSelectInputFn selectRRInput; + XRRQueryExtensionFn queryRRExtension; + + XAllocClassHintFn allocClassHint; + XSetClassHintFn setClassHint; + XFreeFn free; + XGetVisualInfoFn getVisualInfo; + + // opengl + GLXGetFBConfigsFn glxGetFBConfigs; + GLXGetFBConfigAttribFn glxGetFBConfigAttrib; + GLXGetVisualFromFBConfigFn glxGetVisualFromFBConfig; + + XCreateFontCursorFn createFontCursor; + XFreePixmapFn freePixmap; + XSetWMHintsFn setWMHints; + XGrabPointerFn grabPointer; + XCreatePixmapCursorFn createPixmapCursor; + XWarpPointerFn warpPointer; + XGetWMNameFn getWMName; + XQueryPointerFn queryPointer; + XUngrabPointerFn ungrabPointer; + XAllocWMHintsFn allocWMHints; + XMapRaisedFn mapRaised; + XUndefineCursorFn undefineCursor; + XDefineCursorFn defineCursor; + XFreeCursorFn freeCursor; + XGetWMHintsFn getWMHints; + XCreatePixmapFn createPixmap; + XSetInputFocusFn setInputFocus; + XGetInputFocusFn getInputFocus; + XcursorImageLoadCursorFn cursorImageLoadCursor; + XcursorImageCreateFn cursorImageCreate; + XcursorImageDestroyFn cursorImageDestroy; + XLookupKeysymFn lookupKeysym; + XSelectInputFn selectInput; + + XkbSetDetectableAutoRepeatFn setDetectableAutoRepeat; + XSetLocaleModifiersFn setLocaleModifiers; + XOpenIMFn openIM; + XCloseIMFn closeIM; + XCreateICFn createIC; + XDestroyICFn destroyIC; + Xutf8LookupStringFn utf8LookupString; +} X11; + +extern X11 s_X11; +extern X11Atoms s_X11Atoms; + +#endif // PAL_HAS_X11_BACKEND +#endif // __linux__ +#endif // _PAL_X11_H \ No newline at end of file diff --git a/src/video/pal_video_linux.c b/src/video/pal_video_linux.c deleted file mode 100644 index 06028ff9..00000000 --- a/src/video/pal_video_linux.c +++ /dev/null @@ -1,8260 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -// ================================================== -// Includes -// ================================================== - -#ifdef __linux__ -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L -#include "pal/pal_video.h" - -#include -#include -#include -#include -#include -#include -#include - -// X11 headers -#if PAL_HAS_X11 -#include -#include -#include -#include -#include -#include -#include -#include -#endif // PAL_HAS_X11 - -// Wayland headers -#if PAL_HAS_WAYLAND -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#endif // PAL_HAS_WAYLAND - -// ================================================== -// Typedefs, enums and structs -// ================================================== - -#define TO_PAL_HANDLE(type, val) ((type*)(uintptr_t)(val)) -#define FROM_PAL_HANDLE(type, handle) ((type)(uintptr_t)(handle)) -#define MAX_SPAN_MONITORS 4 -#define NULL_BUTTON_SERIAL 0xffffffffU - -#pragma region EGL Typedefs - -typedef void* EGLConfig; -typedef void* EGLSurface; -typedef void* EGLContext; -typedef void* EGLDisplay; -typedef void* EGLNativeDisplayType; - -#define EGL_CAST(type, value) ((type)(value)) -#define EGL_OPENGL_API 0x30A2 -#define EGL_OPENGL_BIT 0x0008 -#define EGL_OPENGL_ES_BIT 0x0001 -#define EGL_OPENGL_ES_API 0x30A0 -#define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0) -#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0) -#define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0) -#define EGL_NATIVE_VISUAL_ID 0x302E - -typedef int32_t EGLint; -typedef unsigned int EGLBoolean; -typedef unsigned int EGLenum; - -typedef void* (*eglGetProcAddressFn)(const char*); - -typedef EGLBoolean (*eglInitializeFn)( - EGLDisplay, - EGLint*, - EGLint*); - -typedef EGLBoolean (*eglTerminateFn)(EGLDisplay); - -typedef EGLDisplay (*eglGetDisplayFn)(void*); - -typedef EGLBoolean (*eglChooseConfigFn)( - EGLDisplay, - const EGLint*, - EGLConfig*, - EGLint, - EGLint*); - -typedef EGLBoolean (*eglGetConfigAttribFn)( - EGLDisplay, - EGLConfig, - EGLint, - EGLint*); - -typedef EGLint (*eglGetErrorFn)(void); - -typedef EGLBoolean (*eglBindAPIFn)(EGLenum); - -typedef EGLBoolean (*eglGetConfigsFn)( - EGLDisplay, - EGLConfig*, - EGLint, - EGLint*); - -#pragma endregion - -typedef struct { - void* monitor; - int dpi; -} SpanMonitor; - -typedef struct { - PalBool skipConfigure; - PalBool skipState; - PalBool used; - PalBool isAttached; - PalBool skipIfAttached; - PalBool focused; - PalBool pushConfigureEvent; - PalBool pushStateEvent; - int x; - int y; - uint32_t w; - int dpi; - int monitorCount; - uint32_t h; - PalWindowState state; - PalWindow* window; - - // X11 only - void* ic; - unsigned long colormap; - - // Wayland only - void* xdgSurface; - void* xdgToplevel; - void* buffer; - void* decoration; - void* cursor; - void* eglWindow; - SpanMonitor monitors[MAX_SPAN_MONITORS]; -} WindowData; - -typedef struct { - PalBool used; - int dpi; - int x; - int y; - uint32_t w; - uint32_t h; - uint32_t refreshRate; - uint32_t wlName; - PalOrientation orientation; - PalMonitor* monitor; - PalMonitorMode mode; // wayland only sends current - char name[32]; -} MonitorData; - -typedef struct { - PalBool pendingScroll; - int32_t lastX; - int32_t lastY; - int32_t dx; - int32_t dy; - int32_t WheelX; - int32_t WheelY; - float WheelXf; - float WheelYf; - PalBool state[PAL_MOUSE_BUTTON_MAX]; - double tmpScrollX; - double tmpScrollY; - double accumScrollX; - double accumScrollY; -} Mouse; - -typedef struct { - PalBool scancodeState[PAL_SCANCODE_MAX]; - PalBool keycodeState[PAL_KEYCODE_MAX]; - int repeatRate; - int repeatDelay; - int repeatKey; - int repeatScancode; - int scancodes[512]; - int keycodes[256]; - uint64_t timer; - uint64_t frequency; -} Keyboard; - -typedef struct { - void* handle; - eglInitializeFn eglInitialize; - eglTerminateFn eglTerminate; - eglGetDisplayFn eglGetDisplay; - eglChooseConfigFn eglChooseConfig; - eglGetConfigAttribFn eglGetConfigAttrib; - eglGetErrorFn eglGetError; - eglBindAPIFn eglBindAPI; - eglGetConfigsFn eglGetConfigs; -} EGL; - -typedef struct { - // clang-format off - void (*shutdownVideo)(); - void (*updateVideo)(); - PalResult (*setFBConfig)(const int, PalFBConfigBackend); - PalResult (*enumerateMonitors)(int32_t*, PalMonitor**); - PalResult (*getPrimaryMonitor)(PalMonitor**); - PalResult (*getMonitorInfo)(PalMonitor*, PalMonitorInfo*); - PalResult (*enumerateMonitorModes)(PalMonitor*, int32_t*, PalMonitorMode*); - PalResult (*getCurrentMonitorMode)(PalMonitor*, PalMonitorMode*); - PalResult (*setMonitorMode)(PalMonitor*, PalMonitorMode*); - PalResult (*validateMonitorMode)(PalMonitor*, PalMonitorMode*); - PalResult (*setMonitorOrientation)(PalMonitor*, PalOrientation); - - PalResult (*createWindow)(const PalWindowCreateInfo*, PalWindow**); - void (*destroyWindow)(PalWindow*); - PalResult (*maximizeWindow)(PalWindow*); - PalResult (*minimizeWindow)(PalWindow*); - PalResult (*restoreWindow)(PalWindow*); - PalResult (*showWindow)(PalWindow*); - PalResult (*hideWindow)(PalWindow*); - PalResult (*flashWindow)(PalWindow*, const PalFlashInfo*); - PalResult (*getWindowStyle)(PalWindow*, PalWindowStyle*); - PalResult (*getWindowMonitor)(PalWindow*, PalMonitor**); - PalResult (*getWindowTitle)(PalWindow*, uint64_t, uint64_t*, char*); - PalResult (*getWindowPos)(PalWindow*, int32_t*, int32_t*); - PalResult (*getWindowSize)(PalWindow*, uint32_t*, uint32_t*); - PalResult (*getWindowState)(PalWindow*, PalWindowState*); - PalBool (*isWindowVisible)(PalWindow*); - PalWindow* (*getFocusWindow)(); - PalWindowHandleInfo (*getWindowHandleInfo)(PalWindow*); - PalWindowHandleInfoEx (*getWindowHandleInfoEx)(PalWindow*); - PalResult (*setWindowOpacity)(PalWindow*, float); - PalResult (*setWindowStyle)(PalWindow*, PalWindowStyle); - PalResult (*setWindowTitle)(PalWindow*, const char*); - PalResult (*setWindowPos)(PalWindow*, int32_t, int32_t); - PalResult (*setWindowSize)(PalWindow*, uint32_t, uint32_t); - PalResult (*setFocusWindow)(PalWindow*); - - PalResult (*createIcon)(const PalIconCreateInfo*, PalIcon**); - void (*destroyIcon)(PalIcon*); - PalResult (*setWindowIcon)(PalWindow*, PalIcon*); - - PalResult (*createCursor)(const PalCursorCreateInfo*, PalCursor**); - PalResult (*createCursorFrom)(PalCursorType, PalCursor**); - void (*destroyCursor)(PalCursor*); - void (*showCursor)(PalBool); - PalResult (*clipCursor)(PalWindow*, PalBool); - PalResult (*getCursorPos)(PalWindow*, int32_t*, int32_t*); - PalResult (*setCursorPos)(PalWindow*, int32_t, int32_t); - PalResult (*setWindowCursor)(PalWindow*, PalCursor*); - - PalResult (*attachWindow)(void*, PalWindow**); - PalResult (*detachWindow)(PalWindow*, void**); - // clang-format on -} Backend; - -typedef struct { - PalBool initialized; - int32_t maxWindowData; - int32_t maxMonitorData; - int32_t pixelFormat; - PalVideoFeatures features; - PalVideoFeatures64 features64; - const PalAllocator* allocator; - PalEventDriver* eventDriver; - const Backend* backend; - WindowData* windowData; - MonitorData* monitorData; - const char* className; - void* platformInstance; - void* display; -} VideoLinux; - -static VideoLinux s_Video = {0}; -static Mouse s_Mouse = {0}; -static Keyboard s_Keyboard = {0}; -static EGL s_Egl; - -// ================================================== -// X11 Typedefs, enums and structs -// ================================================== - -#pragma region X11 Typedefs -#if PAL_HAS_X11 - -#define X_INTERN(x) s_X11Atoms.x = s_X11.internAtom(s_X11.display, #x, False) -#define RANDR_SCREEN_CHANGE_EVENT 1040 - -// optionally, needed to create visual from FBConfig -#define GLX_FBCONFIG_ID 0x8012 -typedef struct __GLXFBConfigRec* GLXFBConfig; - -typedef GLXFBConfig* (*GLXGetFBConfigsFn)( - Display*, - int, - int*); - -typedef int (*GLXGetFBConfigAttribFn)( - Display*, - GLXFBConfig, - int, - int*); - -typedef XVisualInfo* (*GLXGetVisualFromFBConfigFn)( - Display*, - GLXFBConfig); - -typedef XVisualInfo* (*GLXGetProcAddressFn)(const unsigned char*); - -typedef Display* (*XOpenDisplayFn)(const char*); -typedef int (*XCloseDisplayFn)(Display*); - -typedef int (*XGetWindowAttributesFn)( - Display*, - Window, - XWindowAttributes*); - -typedef int (*XGetWindowPropertyFn)( - Display*, - Window, - Atom, - long, - long, - Bool, - Atom, - Atom*, - int*, - unsigned long*, - unsigned long*, - unsigned char**); - -typedef Atom (*XInternAtomFn)( - Display*, - _Xconst char*, - Bool); - -typedef Window (*XGetSelectionOwnerFn)( - Display*, - Atom); - -typedef Window (*XCreateWindowFn)( - Display*, - Window, - int, - int, - unsigned int, - unsigned int, - unsigned int, - int, - unsigned int, - Visual*, - unsigned long, - XSetWindowAttributes*); - -typedef int (*XChangePropertyFn)( - Display*, - Window, - Atom, - Atom, - int, - int, - _Xconst unsigned char*, - int); - -typedef int (*XFlushFn)(Display*); - -typedef Colormap (*XCreateColormapFn)( - Display*, - Window, - Visual*, - int); - -typedef int (*XFreeColormapFn)( - Display*, - Colormap); - -typedef int (*XDestroyWindowFn)( - Display*, - Window); - -typedef int (*XStoreNameFn)( - Display*, - Window, - _Xconst char*); - -typedef int (*XMapWindowFn)( - Display*, - Window); - -typedef int (*XUnmapWindowFn)( - Display*, - Window); - -typedef int (*XMatchVisualInfoFn)( - Display*, - int, - int, - int, - XVisualInfo*); - -typedef int (*XPendingFn)(Display*); - -typedef int (*XSetWMProtocolsFn)( - Display*, - Window, - Atom*, - int); - -typedef int (*XNextEventFn)( - Display*, - XEvent*); - -typedef int (*XSetWMNormalHintsFn)( - Display*, - Window, - XSizeHints*); - -typedef int (*XGetWMNormalHintsFn)( - Display*, - Window, - XSizeHints*, - long*); - -typedef int (*XSendEventFn)( - Display*, - Window, - Bool, - long, - XEvent*); - -typedef int (*XMoveWindowFn)( - Display*, - Window, - int, - int); - -typedef int (*XResizeWindowFn)( - Display*, - Window, - unsigned int, - unsigned int); - -typedef int (*XIconifyWindowFn)( - Display*, - Window, - int); - -typedef XErrorHandler (*XSetErrorHandlerFn)(XErrorHandler); - -typedef int (*XSyncFn)( - Display*, - Bool); - -typedef int (*XSaveContextFn)( - Display*, - XID, - XContext, - _Xconst char*); - -typedef int (*XFindContextFn)( - Display*, - XID, - XContext, - XPointer*); - -typedef XrmQuark (*XrmUniqueQuarkFn)(void); - -typedef int (*XRRSetCrtcConfigFn)( - Display*, - XRRScreenResources*, - RRCrtc, - Time, - int, - int, - RRMode, - Rotation, - RROutput*, - int); - -typedef XRRScreenResources* (*XRRGetScreenResourcesFn)( - Display*, - Window); - -typedef RROutput (*XRRGetOutputPrimaryFn)( - Display*, - Window); - -typedef XRROutputInfo* (*XRRGetOutputInfoFn)( - Display*, - XRRScreenResources*, - RROutput); - -typedef XRRCrtcInfo* (*XRRGetCrtcInfoFn)( - Display*, - XRRScreenResources*, - RRCrtc); - -typedef void (*XRRFreeScreenResourcesFn)(XRRScreenResources*); - -typedef void (*XRRFreeOutputInfoFn)(XRROutputInfo*); - -typedef void (*XRRFreeCrtcInfoFn)(XRRCrtcInfo*); - -typedef void (*XRRSelectInputFn)( - Display*, - Window, - int); - -typedef int (*XRRQueryExtensionFn)( - Display*, - int*, - int*); - -typedef XClassHint* (*XAllocClassHintFn)(void); - -typedef int (*XSetClassHintFn)( - Display*, - Window, - XClassHint*); - -typedef int (*XFreeFn)(void*); - -typedef Cursor (*XCreateFontCursorFn)( - Display*, - unsigned int); - -typedef int (*XFreePixmapFn)( - Display*, - Pixmap); - -typedef int (*XSetWMHintsFn)( - Display*, - Window, - XWMHints*); - -typedef int (*XGrabPointerFn)( - Display*, - Window, - Bool, - unsigned int, - int, - int, - Window, - Cursor, - Time); - -typedef Cursor (*XCreatePixmapCursorFn)( - Display*, - Pixmap, - Pixmap, - XColor*, - XColor*, - unsigned int, - unsigned int); - -typedef int (*XWarpPointerFn)( - Display*, - Window, - Window, - int, - int, - unsigned int, - unsigned int, - int, - int); - -typedef Status (*XGetWMNameFn)( - Display*, - Window, - XTextProperty*); - -typedef Bool (*XQueryPointerFn)( - Display*, - Window, - Window*, - Window*, - int*, - int*, - int*, - int*, - unsigned int*); - -typedef int (*XUngrabPointerFn)( - Display*, - Time); - -typedef XWMHints* (*XAllocWMHintsFn)(void); - -typedef int (*XMapRaisedFn)( - Display*, - Window); - -typedef int (*XUndefineCursorFn)( - Display*, - Window); - -typedef int (*XDefineCursorFn)( - Display*, - Window, - Cursor); - -typedef int (*XFreeCursorFn)( - Display*, - Cursor); - -typedef XWMHints* (*XGetWMHintsFn)( - Display*, - Window); - -typedef Cursor (*XCreatePixmapCursorFn)( - Display*, - Pixmap, - Pixmap, - XColor*, - XColor*, - unsigned int, - unsigned int); - -typedef int (*XSetInputFocusFn)( - Display*, - Window, - int, - Time); - -typedef int (*XGetInputFocusFn)( - Display*, - Window*, - int*); - -typedef Pixmap (*XCreatePixmapFn)( - Display*, - Drawable, - unsigned int, - unsigned int, - unsigned int); - -typedef XVisualInfo* (*XGetVisualInfoFn)( - Display*, - long, - XVisualInfo*, - int*); - -typedef int (*XSelectInputFn)( - Display*, - Window, - long); - -typedef Cursor (*XcursorImageLoadCursorFn)( - Display*, - const XcursorImage*); - -typedef XcursorImage* (*XcursorImageCreateFn)( - int, - int); - -typedef void (*XcursorImageDestroyFn)(XcursorImage*); - -typedef KeySym (*XLookupKeysymFn)( - XKeyEvent*, - int); - -typedef int (*XkbSetDetectableAutoRepeatFn)( - Display*, - int, - int*); - -typedef char* (*XSetLocaleModifiersFn)(const char*); - -typedef XIM (*XOpenIMFn)( - Display*, - struct _XrmHashBucketRec*, - char*, - char*); - -typedef int (*XCloseIMFn)(XIM); - -typedef XIC (*XCreateICFn)( - XIM, - ...) _X_SENTINEL(0); - -typedef void (*XDestroyICFn)(XIC); - -typedef int (*Xutf8LookupStringFn)( - XIC, - XKeyPressedEvent*, - char*, - int, - KeySym*, - int*); - -typedef struct { - PalBool unicodeTitle; - - Atom WM_DELETE_WINDOW; - Atom _NET_SUPPORTED; - Atom _NET_WM_STATE; - Atom _NET_WM_STATE_ABOVE; - Atom _NET_WM_STATE_HIDDEN; - Atom _NET_WM_STATE_MAXIMIZED_VERT; - Atom _NET_WM_STATE_MAXIMIZED_HORZ; - Atom _NET_WM_WINDOW_TYPE_UTILITY; - Atom _NET_WM_DESKTOP; - Atom _NET_WM_STATE_DEMANDS_ATTENTIONS; - Atom _NET_WM_WINDOW_OPACITY; - - Atom _NET_WM_NAME; - Atom UTF8_STRING; - Atom _NET_WM_WINDOW_TYPE; - Atom _NET_WM_WINDOW_TYPE_SPLASH; - Atom _NET_WM_PID; - Atom _WM_CLASS; - Atom _NET_ACTIVE_WINDOW; - Atom _NET_WM_ICON; -} X11Atoms; - -typedef struct { - PalBool error; - PalBool skipScreenEvent; - int bpp; - int screen; - int depth; - int monitorCount; - int rrEventBase; - void* handle; - void* xrandr; - void* glxHandle; - void* libCursor; - XIM im; - Display* display; - Window root; - XContext dataID; - XVisualInfo* visualInfo; - - XOpenDisplayFn openDisplay; - XCloseDisplayFn closeDisplay; - XGetWindowAttributesFn getWindowAttributes; - XGetWindowPropertyFn getWindowProperty; - XInternAtomFn internAtom; - XGetSelectionOwnerFn getSelectionOwner; - XFreeColormapFn freeColormap; - XStoreNameFn storeName; - XChangePropertyFn changeProperty; - XFlushFn flush; - XCreateColormapFn createColormap; - XMapWindowFn mapWindow; - XUnmapWindowFn unmapWindow; - - XCreateWindowFn createWindow; - XDestroyWindowFn destroyWindow; - XMatchVisualInfoFn matchVisualInfo; - XPendingFn pending; - XSetWMProtocolsFn setWMProtocols; - XNextEventFn nextEvent; - XSetWMNormalHintsFn setWMNormalHints; - XGetWMNormalHintsFn getWMNormalHints; - XSendEventFn sendEvent; - XMoveWindowFn moveWindow; - XResizeWindowFn resizeWindow; - XIconifyWindowFn iconifyWindow; - - XSetErrorHandlerFn setErrorHandler; - XSyncFn sync; - XSaveContextFn saveContext; - XFindContextFn findContext; - XrmUniqueQuarkFn uniqueContext; - - XRRSetCrtcConfigFn setCrtcConfig; - XRRGetScreenResourcesFn getScreenResources; - XRRGetOutputPrimaryFn getOutputPrimary; - XRRGetOutputInfoFn getOutputInfo; - XRRGetCrtcInfoFn getCrtcInfo; - XRRFreeScreenResourcesFn freeScreenResources; - XRRFreeOutputInfoFn freeOutputInfo; - XRRFreeCrtcInfoFn freeCrtcInfo; - XRRSelectInputFn selectRRInput; - XRRQueryExtensionFn queryRRExtension; - - XAllocClassHintFn allocClassHint; - XSetClassHintFn setClassHint; - XFreeFn free; - XGetVisualInfoFn getVisualInfo; - - // opengl - GLXGetFBConfigsFn glxGetFBConfigs; - GLXGetFBConfigAttribFn glxGetFBConfigAttrib; - GLXGetVisualFromFBConfigFn glxGetVisualFromFBConfig; - - XCreateFontCursorFn createFontCursor; - XFreePixmapFn freePixmap; - XSetWMHintsFn setWMHints; - XGrabPointerFn grabPointer; - XCreatePixmapCursorFn createPixmapCursor; - XWarpPointerFn warpPointer; - XGetWMNameFn getWMName; - XQueryPointerFn queryPointer; - XUngrabPointerFn ungrabPointer; - XAllocWMHintsFn allocWMHints; - XMapRaisedFn mapRaised; - XUndefineCursorFn undefineCursor; - XDefineCursorFn defineCursor; - XFreeCursorFn freeCursor; - XGetWMHintsFn getWMHints; - XCreatePixmapFn createPixmap; - XSetInputFocusFn setInputFocus; - XGetInputFocusFn getInputFocus; - XcursorImageLoadCursorFn cursorImageLoadCursor; - XcursorImageCreateFn cursorImageCreate; - XcursorImageDestroyFn cursorImageDestroy; - XLookupKeysymFn lookupKeysym; - XSelectInputFn selectInput; - - XkbSetDetectableAutoRepeatFn setDetectableAutoRepeat; - XSetLocaleModifiersFn setLocaleModifiers; - XOpenIMFn openIM; - XCloseIMFn closeIM; - XCreateICFn createIC; - XDestroyICFn destroyIC; - Xutf8LookupStringFn utf8LookupString; -} X11; - -static X11 s_X11 = {0}; -static X11Atoms s_X11Atoms = {0}; - -#endif // PAL_HAS_X11 -#pragma endregion - -// ================================================== -// Wayland Typedefs, enums and structs -// ================================================== - -#pragma region Wayland Typedefs -#if PAL_HAS_WAYLAND - -typedef struct wl_display* (*wl_display_connect_fn)(const char*); -typedef void (*wl_display_disconnect_fn)(struct wl_display*); -typedef int (*wl_display_roundtrip_fn)(struct wl_display*); -typedef int (*wl_display_dispatch_fn)(struct wl_display*); -typedef void (*wl_proxy_destroy_fn)(struct wl_proxy*); - -typedef int (*wl_proxy_add_listener_fn)( - struct wl_proxy*, - void (**)(void), - void*); - -typedef struct wl_proxy* (*wl_proxy_marshal_constructor_v_fn)( - struct wl_proxy*, - uint32_t, - const struct wl_interface*, - uint32_t, - ...); - -typedef struct wl_proxy* (*wl_proxy_marshal_flags_fn)( - struct wl_proxy*, - uint32_t, - const struct wl_interface*, - uint32_t, - uint32_t, - ...); - -typedef uint32_t (*wl_proxy_get_version_fn)(struct wl_proxy*); - -typedef int (*wl_proxy_add_listener_fn)( - struct wl_proxy*, - void (**)(void), - void*); - -typedef int (*wl_display_get_error_fn)(struct wl_display*); -typedef int (*wl_display_dispatch_pending_fn)(struct wl_display*); -typedef int (*wl_display_flush_fn)(struct wl_display*); -typedef int (*wl_display_prepare_read_fn)(struct wl_display*); -typedef int (*wl_display_read_events_fn)(struct wl_display*); -typedef int (*wl_display_get_fd_fn)(struct wl_display*); -typedef void (*wl_display_cancel_read_fn)(struct wl_display*); - -// xkb -typedef void (*xkb_keymap_unref_fn)(struct xkb_keymap*); -typedef struct xkb_state* (*xkb_state_new_fn)(struct xkb_keymap*); -typedef void (*xkb_state_unref_fn)(struct xkb_state*); -typedef void (*xkb_context_unref_fn)(struct xkb_context*); -typedef struct xkb_context* (*xkb_context_new_fn)(enum xkb_context_flags); -typedef uint32_t (*xkb_keysym_to_utf32_fn)(xkb_keysym_t); - -typedef xkb_keysym_t (*xkb_state_key_get_one_sym_fn)( - struct xkb_state*, - xkb_keycode_t); - -typedef struct xkb_keymap* (*xkb_keymap_new_from_string_fn)( - struct xkb_context*, - const char*, - enum xkb_keymap_format, - enum xkb_keymap_compile_flags); - -typedef enum xkb_state_component (*xkb_state_update_mask_fn)( - struct xkb_state*, - xkb_mod_mask_t, - xkb_mod_mask_t, - xkb_mod_mask_t, - xkb_layout_index_t, - xkb_layout_index_t, - xkb_layout_index_t); - -typedef int (*xkb_keymap_key_repeats_fn)( - struct xkb_keymap*, - xkb_keycode_t); - -// wayland cursor -typedef struct wl_cursor_theme* (*wl_cursor_theme_load_fn)( - const char*, - int, - struct wl_shm*); - -typedef struct wl_cursor* (*wl_cursor_theme_get_cursor_fn)( - struct wl_cursor_theme*, - const char*); - -typedef struct wl_buffer* (*wl_cursor_image_get_buffer_fn)(struct wl_cursor_image*); - -// egl_window -struct wl_egl_window; -struct wl_surface; - -typedef struct wl_egl_window* (*wl_egl_window_create_fn)( - struct wl_surface*, - int, - int); - -typedef void (*wl_egl_window_destroy_fn)(struct wl_egl_window*); - -typedef void (*wl_egl_window_resize_fn)( - struct wl_egl_window*, - int, - int, - int, - int); - -typedef struct { - PalBool checkFeatures; - int monitorCount; - - void* handle; - void* xkbCommon; - void* libCursor; - void* libWaylandEgl; - struct wl_display* display; - struct wl_registry* registry; - struct xdg_wm_base* xdgBase; - struct wl_compositor* compositor; - struct wl_shm* shm; - struct wl_seat* seat; - struct wl_pointer* pointer; - struct wl_keyboard* keyboard; - struct zxdg_decoration_manager_v1* decorationManager; - struct zwp_pointer_constraints* pointerConstraints; - struct wl_surface* pointerSurface; - struct wl_surface* keyboardSurface; - struct wl_cursor_theme* cursorTheme; - - struct xkb_context* inputContext; - struct xkb_keymap* keymap; - struct xkb_state* state; - - const struct wl_interface* outputInterface; - const struct wl_interface* seatInterface; - const struct wl_interface* compositorInterface; - const struct wl_interface* registryInterface; - const struct wl_interface* surfaceInterface; - const struct wl_interface* shmInterface; - const struct wl_interface* bufferInterface; - const struct wl_interface* shmPoolInterface; - const struct wl_interface* regionInterface; - const struct wl_interface* pointerInterface; - const struct wl_interface* keyboardInterface; - - wl_display_connect_fn displayConnect; - wl_display_disconnect_fn displayDisconnect; - wl_display_roundtrip_fn displayRoundtrip; - wl_display_dispatch_fn displayDispatch; - wl_proxy_destroy_fn proxyDestroy; - wl_proxy_add_listener_fn proxyAddListener; - wl_proxy_marshal_constructor_v_fn proxyMarshalCnstructor; - wl_proxy_marshal_flags_fn proxyMarshalFlags; - wl_proxy_get_version_fn proxyGetVersion; - wl_display_get_error_fn getError; - wl_display_dispatch_pending_fn dispatchPending; - wl_display_flush_fn displayFlush; - wl_display_prepare_read_fn prepareRead; - wl_display_read_events_fn readEvents; - wl_display_get_fd_fn displayGetFd; - wl_display_cancel_read_fn cancelRead; - - xkb_keymap_unref_fn xkbKeymapUnref; - xkb_state_new_fn xkbStateNew; - xkb_state_unref_fn xkbStateUnref; - xkb_context_unref_fn xkbContextUnref; - xkb_context_new_fn xkbContextNew; - xkb_state_key_get_one_sym_fn xkbStateKeyGetOneSym; - xkb_keymap_new_from_string_fn xkbKeymapNewFromString; - xkb_keysym_to_utf32_fn xkbKeysymToUtf32; - xkb_state_update_mask_fn xkbStateUpdateMask; - xkb_keymap_key_repeats_fn xkbKeymapKeyRepeats; - - wl_cursor_theme_load_fn cursorThemeLoad; - wl_cursor_theme_get_cursor_fn cursorThemeGetCursor; - wl_cursor_image_get_buffer_fn cursorImageGetBuffer; - - EGLConfig eglFBConfig; - wl_egl_window_create_fn eglWindowCreate; - wl_egl_window_destroy_fn eglWindowDestroy; - wl_egl_window_resize_fn eglWindowResize; -} Wayland; - -typedef struct { - struct wl_buffer* buffer; - struct wl_surface* surface; - int hotspotX; - int hotspotY; -} WaylandCursor; - -static Wayland s_Wl = {0}; - -#endif // PAL_HAS_WAYLAND -#pragma endregion - -#pragma region Wayland-Client-Protocol -#if PAL_HAS_WAYLAND - -static WindowData* findWindowData(PalWindow* window); -static MonitorData* findMonitorData(PalMonitor* monitor); - -static inline uint64_t getTime() -{ - uint64_t now = palGetPerformanceCounter(); - return (now * 1000) / s_Keyboard.frequency; -} - -static inline void* wlRegistryBind( - struct wl_registry* wl_registry, - uint32_t name, - const struct wl_interface* interface, - uint32_t version) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_registry, - WL_REGISTRY_BIND, - interface, - version, - 0, - name, - interface->name, - version, - NULL); - - return (void*)id; -} - -static inline int wlRegistryAddListener( - struct wl_registry* wl_registry, - const struct wl_registry_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); -} - -static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_display) -{ - struct wl_proxy* registry; - registry = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_display, - 1, // WL_DISPLAY_GET_REGISTRY - s_Wl.registryInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_display), - 0, - NULL); - - return (struct wl_registry*)registry; -} - -static inline int wlOutputAddListener( - struct wl_output* wl_output, - const struct wl_output_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_output, (void (**)(void))listener, data); -} - -static inline struct wl_surface* wlCompositorCreateSurface(struct wl_compositor* wl_compositor) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_compositor, - 0, // WL_COMPOSITOR_CREATE_SURFACE, - s_Wl.surfaceInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_compositor), - 0, - NULL); - - return (struct wl_surface*)id; -} - -static inline void wlSurfaceCommit(struct wl_surface* wl_surface) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_surface, - 6, // WL_SURFACE_COMMIT - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), - 0); -} - -static inline void wlSurfaceDestroy(struct wl_surface* wl_surface) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_surface, - 0, // WL_SURFACE_DESTROY - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline struct wl_shm_pool* wlShmCreatePool( - struct wl_shm* wl_shm, - int32_t fd, - int32_t size) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_shm, - 0, // WL_SHM_CREATE_POOL - s_Wl.shmPoolInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm), - 0, - NULL, - fd, - size); - - return (struct wl_shm_pool*)id; -} - -static inline void wlShmPoolDestroy(struct wl_shm_pool* wl_shm_pool) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_shm_pool, - WL_SHM_POOL_DESTROY, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm_pool), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline struct wl_buffer* wlShmPoolCreateBuffer( - struct wl_shm_pool* wl_shm_pool, - int32_t offset, - int32_t width, - int32_t height, - int32_t stride, - uint32_t format) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_shm_pool, - WL_SHM_POOL_CREATE_BUFFER, - s_Wl.bufferInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm_pool), - 0, - NULL, - offset, - width, - height, - stride, - format); - - return (struct wl_buffer*)id; -} - -static inline void wlBufferDestroy(struct wl_buffer* wl_buffer) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_buffer, - WL_BUFFER_DESTROY, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_buffer), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline void wlSurfaceAttach( - struct wl_surface* wl_surface, - struct wl_buffer* buffer, - int32_t x, - int32_t y) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_surface, - WL_SURFACE_ATTACH, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), - 0, - buffer, - x, - y); -} - -static inline void wlSurfaceDamageBuffer( - struct wl_surface* wl_surface, - int32_t x, - int32_t y, - int32_t width, - int32_t height) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_surface, - WL_SURFACE_DAMAGE_BUFFER, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), - 0, - x, - y, - width, - height); -} - -static inline int wlSurfaceAddListener( - struct wl_surface* wl_surface, - const struct wl_surface_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_surface, (void (**)(void))listener, data); -} - -static inline int wlSeatAddListener( - struct wl_seat* wl_seat, - const struct wl_seat_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_seat, (void (**)(void))listener, data); -} - -static inline struct wl_pointer* wlSeatGetPointer(struct wl_seat* wl_seat) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_seat, - WL_SEAT_GET_POINTER, - s_Wl.pointerInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_seat), - 0, - NULL); - - return (struct wl_pointer*)id; -} - -static inline struct wl_keyboard* wlSeatGetKeyboard(struct wl_seat* wl_seat) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_seat, - WL_SEAT_GET_KEYBOARD, - s_Wl.keyboardInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_seat), - 0, - NULL); - - return (struct wl_keyboard*)id; -} - -static inline int wlPointerAddListener( - struct wl_pointer* wl_pointer, - const struct wl_pointer_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_pointer, (void (**)(void))listener, data); -} - -static inline void wlPointerSetCursor( - struct wl_pointer* wl_pointer, - uint32_t serial, - struct wl_surface* surface, - int32_t hotspot_x, - int32_t hotspot_y) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_pointer, - WL_POINTER_SET_CURSOR, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_pointer), - 0, - serial, - surface, - hotspot_x, - hotspot_y); -} - -static inline int wlKeyboardAddListener( - struct wl_keyboard* wl_keyboard, - const struct wl_keyboard_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_keyboard, (void (**)(void))listener, data); -} - -static inline struct wl_region* wlCompositorCreateRegion(struct wl_compositor* wl_compositor) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_compositor, - WL_COMPOSITOR_CREATE_REGION, - s_Wl.regionInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_compositor), - 0, - NULL); - - return (struct wl_region*)id; -} - -static inline void wlRegionAdd( - struct wl_region* wl_region, - int32_t x, - int32_t y, - int32_t width, - int32_t height) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_region, - WL_REGION_ADD, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_region), - 0, - x, - y, - width, - height); -} - -static inline void wlSurfaceSetOpaqueRegion( - struct wl_surface* wl_surface, - struct wl_region* region) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_surface, - WL_SURFACE_SET_OPAQUE_REGION, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), - 0, - region); -} - -static inline void wlRegionDestroy(struct wl_region* wl_region) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_region, - WL_REGION_DESTROY, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_region), - WL_MARSHAL_FLAG_DESTROY); -} - -static void surfaceHandleEnter( - void* userData, - struct wl_surface* surface, - struct wl_output* output) -{ - WindowData* data = userData; - MonitorData* monitorData = findMonitorData((PalMonitor*)output); - if (!monitorData) { - return; - } - - // wayland sends multiple surface enter events - // if the surface spans multiple monitors - // we get all and return the highest dpi - // this assumes a surface can only span 4 monitors - // at the sametime but this might be wrong - // FIXME: check if we need more - - // wayland will trigger this event if the window gains focus - // so we check if the output is the same - SpanMonitor* span = nullptr; - if (data->monitorCount > 0) { - for (int i = 0; i < data->monitorCount; i++) { - if (data->monitors[i].monitor == (void*)output) { - // the monitor already exist in our array - // so we just update it - span = &data->monitors[i]; - span->dpi = monitorData->dpi; - break; - } - } - } - - if (span == nullptr) { - // new entry - span = &data->monitors[data->monitorCount]; - span->monitor = output; - span->dpi = monitorData->dpi; - data->monitorCount++; - } - - if (data->dpi == 0) { - // this is triggered when the window is created - // we cache the DPI and skip the event - data->dpi = monitorData->dpi; - return; - } - - // the code below should be skipped if users are not - // interested in DPI changed events - PalDispatchMode mode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_MONITOR_DPI_CHANGED; - if (!s_Video.eventDriver) { - return; - } - - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, type); - if (mode == PAL_DISPATCH_NONE) { - return; - } - - // get the highest dpi and check if the it has changed - int maxDPI = 96; // baseline - for (int i = 0; i < data->monitorCount; i++) { - if (!data->monitors[i].monitor) { - // not a valid index. continue - continue; - } - - if (data->monitors[i].dpi > maxDPI) { - // new highest - maxDPI = data->monitors[i].dpi; - } - } - - if (maxDPI != data->dpi) { - data->dpi = maxDPI; - - PalEvent event = {0}; - event.type = type; - event.data = maxDPI; - event.data2 = palPackPointer((void*)data->window); - palPushEvent(driver, &event); - } -} - -static void surfaceHandleLeave( - void* userData, - struct wl_surface* surface, - struct wl_output* output) -{ - // remove the monitor from our span monitor list - WindowData* data = userData; - MonitorData* monitorData = findMonitorData((PalMonitor*)output); - if (!monitorData) { - return; - } - - for (int i = 0; i < data->monitorCount; i++) { - if (data->monitors[i].monitor == (void*)output) { - // found our monitor - // we might want to pack the array but its just 4 monitors - // so we leave it like that - data->monitors[i].monitor = nullptr; - data->monitorCount--; - break; - } - } -} - -static struct wl_surface_listener surfaceListener = { - .enter = surfaceHandleEnter, - .leave = surfaceHandleLeave}; - -static void pointerHandleEnter( - void* userData, - struct wl_pointer* pointer, - uint32_t serial, - struct wl_surface* surface, - wl_fixed_t surface_x, - wl_fixed_t surface_y) -{ - WindowData* data = findWindowData((PalWindow*)surface); - if (!data) { - return; - } - - if (data->cursor) { - // our window - WaylandCursor* cursor = data->cursor; - wlPointerSetCursor(pointer, serial, cursor->surface, cursor->hotspotX, cursor->hotspotY); - } - - // cache the surface the pointer is currently on - s_Wl.pointerSurface = surface; -} - -static void pointerHandleLeave( - void* userData, - struct wl_pointer* pointer, - uint32_t serial, - struct wl_surface* surface) -{ - if (s_Wl.pointerSurface == surface) { - s_Wl.pointerSurface == nullptr; - } -} - -static void pointerHandleMotion( - void* userData, - struct wl_pointer* pointer, - uint32_t time, - wl_fixed_t surface_x, - wl_fixed_t surface_y) -{ - int x = wl_fixed_to_int(surface_x); - int y = wl_fixed_to_int(surface_y); - const int dx = x - s_Mouse.lastX; - const int dy = y - s_Mouse.lastY; - - PalDispatchMode mode = PAL_DISPATCH_NONE; - PalWindow* window = (PalWindow*)s_Wl.pointerSurface; - if (s_Video.eventDriver && window) { - // we only push a mouse move only if we are on a window - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MOUSE_MOVE; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackInt32(x, y); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - - // push a mouse delta event - type = PAL_EVENT_MOUSE_DELTA; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackInt32(dx, dy); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - - s_Mouse.lastX = x; - s_Mouse.lastY = y; - s_Mouse.dx = dx; - s_Mouse.dy = dy; -} - -static void pointerHandleButton( - void* userData, - struct wl_pointer* pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) -{ - PalWindow* window = nullptr; - if (s_Wl.pointerSurface) { - window = (PalWindow*)s_Wl.pointerSurface; - - } else { - // cannot recieve events without a focused surface - return; - } - - PalBool pressed = state == WL_POINTER_BUTTON_STATE_PRESSED; - PalMouseButton _button = 0; - PalEventType type = PAL_EVENT_MOUSE_BUTTONUP; - - if (button == BTN_LEFT) { - _button = PAL_MOUSE_BUTTON_LEFT; - - } else if (button == BTN_RIGHT) { - _button = PAL_MOUSE_BUTTON_RIGHT; - - } else if (button == BTN_MIDDLE) { - _button = PAL_MOUSE_BUTTON_MIDDLE; - - } else if (button == BTN_SIDE) { - _button = PAL_MOUSE_BUTTON_X1; - - } else if (button == BTN_EXTRA) { - _button = PAL_MOUSE_BUTTON_X2; - } - - if (pressed) { - type = PAL_EVENT_MOUSE_BUTTONDOWN; - } - - s_Mouse.state[_button] = pressed; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - - // since we are not drawing decorations for users - // they need the serial in order to draw their decorations - // we put the serial at the upper 32 so ABI is preserved - event.data = palPackUint32(_button, serial); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } -} - -static void pointerHandleAxis( - void* userData, - struct wl_pointer* pointer, - uint32_t time, - uint32_t axis, - wl_fixed_t value) -{ - double delta = wl_fixed_to_double(value); - if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - s_Mouse.tmpScrollX += delta; - s_Mouse.accumScrollX += delta; - - } else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { - s_Mouse.tmpScrollY += delta; - s_Mouse.accumScrollY += delta; - } - - s_Mouse.pendingScroll = PAL_TRUE; -} - -static void pointerHandleAxisDiscrete( - void* userData, - struct wl_pointer* pointer, - uint32_t axis, - int32_t discrete) -{ - if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - s_Mouse.tmpScrollX += discrete; - s_Mouse.accumScrollX += discrete; - - } else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { - s_Mouse.tmpScrollY += discrete; - s_Mouse.accumScrollY += discrete; - } - - s_Mouse.pendingScroll = PAL_TRUE; -} - -static void pointerHandleFrame( - void* userData, - struct wl_pointer* pointer) -{ - if (!s_Mouse.pendingScroll) { - // no wheel event - return; - } - - PalWindow* window = nullptr; - if (s_Wl.pointerSurface) { - window = (PalWindow*)s_Wl.pointerSurface; - - } else { - // cannot recieve events without a focused surface - return; - } - - const int dx = (int)s_Mouse.accumScrollX; - const int dy = (int)s_Mouse.accumScrollY; - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_MOUSE_WHEEL; - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(dx, dy); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - - s_Mouse.WheelX = dx; - s_Mouse.WheelY = dy; - s_Mouse.accumScrollX -= dx; - s_Mouse.accumScrollY -= dy; - s_Mouse.pendingScroll = PAL_FALSE; -} - -static void pointerHandleAxisSource( - void* userData, - struct wl_pointer* pointer, - uint32_t axis_source) -{ -} - -static void pointerHandleAxisStop( - void* userData, - struct wl_pointer* pointer, - uint32_t time, - uint32_t axis) -{ -} - -static void keyboardHandleEnter( - void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - struct wl_surface* surface, - struct wl_array* keys) -{ - // cache the surface the keyboard is currently on - s_Wl.keyboardSurface = surface; -} - -static void keyboardHandleLeave( - void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - struct wl_surface* surface) -{ - if (s_Wl.keyboardSurface == surface) { - s_Wl.keyboardSurface == nullptr; - } -} - -static void keyboardHandleRemap( - void* userData, - struct wl_keyboard* keyboard, - uint32_t format, - int32_t fd, - uint32_t size) -{ - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { - close(fd); - return; - } - - struct xkb_keymap* keymap = nullptr; - struct xkb_state* state = nullptr; - - char* keymapStr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); - if (keymapStr == MAP_FAILED) { - close(fd); - return; - } - - keymap = s_Wl.xkbKeymapNewFromString( - s_Wl.inputContext, - keymapStr, - XKB_KEYMAP_FORMAT_TEXT_V1, - XKB_KEYMAP_COMPILE_NO_FLAGS); - - if (!keymap) { - return; - } - - munmap(keymapStr, size); - close(fd); - - state = s_Wl.xkbStateNew(keymap); - if (!state) { - return; - } - - // check if we have old keymap and state - if (s_Wl.state) { - s_Wl.xkbStateUnref(s_Wl.state); - s_Wl.xkbKeymapUnref(s_Wl.keymap); - } - - s_Wl.state = state; - s_Wl.keymap = keymap; - s_Keyboard.frequency = palGetPerformanceFrequency(); -} - -static void keyboardHandleKey( - void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - uint32_t time, - uint32_t key, - uint32_t state) -{ - PalWindow* window = nullptr; - if (s_Wl.keyboardSurface) { - window = (PalWindow*)s_Wl.keyboardSurface; - - } else { - // cannot recieve events without a focused surface - return; - } - - PalScancode scancode = 0; - PalKeycode keycode = 0; - PalBool pressed = (state == WL_KEYBOARD_KEY_STATE_PRESSED); - PalEventType type = PAL_EVENT_KEYUP; - PalDispatchMode mode = PAL_DISPATCH_NONE; - xkb_keysym_t keySym = s_Wl.xkbStateKeyGetOneSym(s_Wl.state, key + 8); - - // special handling - if (key == 119) { - scancode = PAL_SCANCODE_PAUSE; - } else if (key == 107) { - scancode = PAL_SCANCODE_END; - } else if (key == 103) { - scancode = PAL_SCANCODE_UP; - } else if (key == 102) { - scancode = PAL_SCANCODE_HOME; - - } else { - scancode = s_Keyboard.scancodes[key]; - } - - // printable and text input keys are from the range - // 32 (PAL_KEYCODE_SPACE) and 122 (PAL_KEYCODE_Z) - // The rest are almost the same as their scancode - // Maybe there will be a layout that makes this wrong - // but for now this works - if (keySym >= XKB_KEY_space && keySym <= XKB_KEY_z) { - // a printable or input key - keycode = s_Keyboard.keycodes[keySym]; - - } else { - // Since PalKeycode and PalScancode have the same integers - // we can make a direct cast without a table - // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) - keycode = (PalKeycode)(uint32_t)scancode; - } - - // If we got a keySym but its not mapped into our keycode array - // we do a direct cast as well - if (keycode == PAL_KEYCODE_UNKNOWN) { - keycode = (PalKeycode)(uint32_t)scancode; - } - - s_Keyboard.scancodeState[scancode] = pressed; - s_Keyboard.keycodeState[keycode] = pressed; - - // check for key repeats - if (pressed) { - if (s_Wl.xkbKeymapKeyRepeats(s_Wl.keymap, key + 8)) { - s_Keyboard.repeatKey = keycode; - s_Keyboard.repeatScancode = scancode; - s_Keyboard.timer = getTime() + s_Keyboard.repeatDelay; - - } else { - s_Keyboard.repeatKey = 0; - } - - type = PAL_EVENT_KEYDOWN; - - } else { - // key release - if (s_Keyboard.repeatKey == keycode) { - s_Keyboard.repeatKey = 0; - } - } - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(keycode, scancode); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - - // check for char event if enabled - type = PAL_EVENT_KEYCHAR; - mode = palGetEventDispatchMode(driver, type); - if (mode == PAL_DISPATCH_NONE) { - return; - } - - uint32_t codepoint = s_Wl.xkbKeysymToUtf32(keySym); - if (codepoint <= 0) { - return; - } - - PalEvent event = {0}; - event.type = type; - event.data = codepoint; - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } -} - -static void keyboardHandleRepeatInfo( - void* userData, - struct wl_keyboard* keyboard, - int32_t rate, - int32_t delay) -{ - if (s_Wl.keyboard == keyboard) { - s_Keyboard.repeatDelay = delay; - s_Keyboard.repeatRate = rate; - - } else { - if (s_Keyboard.repeatDelay == 0) { - s_Keyboard.repeatDelay = 500; - s_Keyboard.repeatRate = 30; - } - } -} - -static void keyboardHandleModifiers( - void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - uint32_t mods_depressed, - uint32_t mods_latched, - uint32_t mods_locked, - uint32_t group) -{ - if (s_Wl.state) { - s_Wl.xkbStateUpdateMask(s_Wl.state, mods_depressed, mods_latched, mods_locked, group, 0, 0); - } -} - -static struct wl_pointer_listener pointerListener = { - .enter = pointerHandleEnter, - .leave = pointerHandleLeave, - .motion = pointerHandleMotion, - .button = pointerHandleButton, - .axis = pointerHandleAxis, - .axis_discrete = pointerHandleAxisDiscrete, - .frame = pointerHandleFrame, - .axis_source = pointerHandleAxisSource, - .axis_stop = pointerHandleAxisStop}; - -static struct wl_keyboard_listener keyboardListener = { - .enter = keyboardHandleEnter, - .leave = keyboardHandleLeave, - .keymap = keyboardHandleRemap, - .key = keyboardHandleKey, - .repeat_info = keyboardHandleRepeatInfo, - .modifiers = keyboardHandleModifiers}; - -static void seatHandleCapabilities( - void* userData, - struct wl_seat* seat, - enum wl_seat_capability caps) -{ - if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { - s_Wl.keyboard = wlSeatGetKeyboard(seat); - wlKeyboardAddListener(s_Wl.keyboard, &keyboardListener, nullptr); - } - - if (caps & WL_SEAT_CAPABILITY_POINTER) { - s_Wl.pointer = wlSeatGetPointer(seat); - wlPointerAddListener(s_Wl.pointer, &pointerListener, nullptr); - } -} - -static void seatHandleName( - void* userData, - struct wl_seat* seat, - const char* name) -{ -} - -static struct wl_seat_listener seatListener = { - .capabilities = seatHandleCapabilities, - .name = seatHandleName}; - -#endif // PAL_HAS_WAYLAND -#pragma endregion - -#pragma region Xdg-Shell-Protocol -#if PAL_HAS_WAYLAND - -struct xdg_wm_base; -struct xdg_surface; -struct xdg_toplevel; - -// forward declare -static struct wl_buffer* createShmBuffer( - int width, - int height, - const uint8_t* pixels, - PalBool cursor); - -const struct wl_interface xdg_popup_interface; -const struct wl_interface xdg_positioner_interface; -const struct wl_interface xdg_surface_interface; -const struct wl_interface xdg_toplevel_interface; - -struct xdg_wm_base_listener { - void (*ping)( - void*, - struct xdg_wm_base*, - uint32_t); -}; - -struct xdg_surface_listener { - void (*configure)( - void*, - struct xdg_surface*, - uint32_t); -}; - -struct xdg_toplevel_listener { - // clang-format off - void (*configure)(void*, struct xdg_toplevel*, int32_t, int32_t, struct wl_array*); - void (*close)(void*, struct xdg_toplevel*); - void (*configure_bounds)(void*, struct xdg_toplevel*, int32_t, int32_t); - void (*wm_capabilities)(void*, struct xdg_toplevel*, struct wl_array*); - // clang-format on -}; - -static inline void xdgWmBasePong( - struct xdg_wm_base* xdg_wm_base, - uint32_t serial) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_wm_base, - 3, // XDG_WM_BASE_PONG - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_wm_base), - 0, - serial); -} - -static inline int xdgWmBaseAddListener( - struct xdg_wm_base* xdg_wm_base, - const struct xdg_wm_base_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)xdg_wm_base, (void (**)(void))listener, data); -} - -static inline struct xdg_surface* xdgWmBaseGetXdgSurface( - struct xdg_wm_base* xdg_wm_base, - struct wl_surface* surface) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_wm_base, - 2, // XDG_WM_BASE_GET_XDG_SURFACE, - &xdg_surface_interface, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_wm_base), - 0, - NULL, - surface); - - return (struct xdg_surface*)id; -} - -static inline struct xdg_toplevel* xdgSurfaceGetToplevel(struct xdg_surface* xdg_surface) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_surface, - 1, // XDG_SURFACE_GET_TOPLEVEL, - &xdg_toplevel_interface, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), - 0, - NULL); - - return (struct xdg_toplevel*)id; -} - -static inline void xdgSurfaceAckConfigure( - struct xdg_surface* xdg_surface, - uint32_t serial) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_surface, - 4, // XDG_SURFACE_ACK_CONFIGURE - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), - 0, - serial); -} - -static void wmBaseHandlePing( - void* data, - struct xdg_wm_base* base, - uint32_t serial) -{ - xdgWmBasePong(base, serial); -} - -static void xdgSurfaceHandleConfigure( - void* data, - struct xdg_surface* surface, - uint32_t serial) -{ - WindowData* winData = (WindowData*)data; - xdgSurfaceAckConfigure(surface, serial); - - // push and resolve any pending events - if (!winData->skipConfigure) { - if (winData->pushConfigureEvent) { - if (winData->eglWindow) { - s_Wl.eglWindowResize(winData->eglWindow, winData->w, winData->h, 0, 0); - - } else { - // create a new buffer with the new size - struct wl_buffer* buffer = nullptr; - buffer = createShmBuffer(winData->w, winData->h, nullptr, PAL_FALSE); - if (!buffer) { - return; - } - - struct wl_surface* _surface = nullptr; - _surface = (struct wl_surface*)winData->window; - - wlSurfaceAttach(_surface, buffer, 0, 0); - wlSurfaceDamageBuffer(_surface, 0, 0, winData->w, winData->h); - wlSurfaceCommit(_surface); - - // destroy old buffer - wlBufferDestroy(winData->buffer); - winData->buffer = buffer; - } - - // push a window resize event - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_WINDOW_SIZE; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(s_Video.eventDriver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(winData->w, winData->h); - event.data2 = palPackPointer(winData->window); - palPushEvent(s_Video.eventDriver, &event); - } - } - - winData->pushConfigureEvent = PAL_FALSE; - } - } - - // pending state - if (!winData->skipState) { - if (!winData->pushStateEvent) { - return; - } - - // push a window state event - // we dont recreate buffers over here - // since we already create the buffer with the new size - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_WINDOW_STATE; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(s_Video.eventDriver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = winData->state; - event.data2 = palPackPointer(winData->window); - palPushEvent(s_Video.eventDriver, &event); - } - } - - winData->pushStateEvent = PAL_FALSE; - } -} - -static void xdgToplevelHandleConfigure( - void* data, - struct xdg_toplevel* toplevel, - int32_t width, - int32_t height, - struct wl_array* states) -{ - WindowData* winData = (WindowData*)data; - uint32_t* state; - PalBool activated = PAL_FALSE; - wl_array_for_each(state, states) - { - // we need only maximized - if (*state == 1) { // XDG_TOPLEVEL_STATE_MAXIMIZED - if (winData->state != PAL_WINDOW_STATE_MAXIMIZED) { - winData->state = PAL_WINDOW_STATE_MAXIMIZED; - winData->pushStateEvent = PAL_TRUE; - } - - } else if (*state == 4) { // XDG_TOPLEVEL_STATE_ACTIVATED - activated = PAL_TRUE; - } - } - - if (width > 0 && height > 0) { - if (width != winData->w || height != winData->h) { - // size change - winData->pushConfigureEvent = PAL_TRUE; - } - - winData->w = width; - winData->h = height; - } - - if (activated && !winData->focused) { - // focus gained - winData->focused = PAL_TRUE; - - } else if (!activated && winData->focused) { - // focus lost - winData->focused = PAL_FALSE; - - } else { - // discard double focus gained and double focus lost - return; - } - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_WINDOW_FOCUS; - mode = palGetEventDispatchMode(driver, type); - - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = winData->focused; - event.data2 = palPackPointer(winData->window); - palPushEvent(driver, &event); - } - } -} - -static void xdgToplevelHandleClose( - void* data, - struct xdg_toplevel* toplevel) -{ - WindowData* winData = (WindowData*)data; - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_WINDOW_CLOSE; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(s_Video.eventDriver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data2 = palPackPointer(winData->window); - palPushEvent(s_Video.eventDriver, &event); - } - } -} - -static inline int xdgSurfaceAddListener( - struct xdg_surface* xdg_surface, - const struct xdg_surface_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)xdg_surface, (void (**)(void))listener, data); -} - -static inline void xdgSurfaceDestroy(struct xdg_surface* xdg_surface) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_surface, - 0, // XDG_SURFACE_DESTROY - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline void xdgToplevelDestroy(struct xdg_toplevel* xdg_toplevel) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 0, // XDG_TOPLEVEL_DESTROY - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline void xdgToplevelSetTitle( - struct xdg_toplevel* xdg_toplevel, - const char* title) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 2, // XDG_TOPLEVEL_SET_TITLE - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0, - title); -} - -static inline void xdgToplevelSetMaximized(struct xdg_toplevel* xdg_toplevel) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 9, // XDG_TOPLEVEL_SET_MAXIMIZED - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0); -} - -static inline void xdgToplevelSetMinimized(struct xdg_toplevel* xdg_toplevel) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 13, // XDG_TOPLEVEL_SET_MINIMIZED - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0); -} - -static inline int xdgToplevelAddListener( - struct xdg_toplevel* xdg_toplevel, - const struct xdg_toplevel_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)xdg_toplevel, (void (**)(void))listener, data); -} - -static inline void xdgToplevelSetMinSize( - struct xdg_toplevel* xdg_toplevel, - int32_t width, - int32_t height) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 8, // XDG_TOPLEVEL_SET_MIN_SIZE - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0, - width, - height); -} - -static inline void xdgToplevelSetMaxSize( - struct xdg_toplevel* xdg_toplevel, - int32_t width, - int32_t height) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 7, // XDG_TOPLEVEL_SET_MAX_SIZE - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0, - width, - height); -} - -static inline void xdgToplevelSetAppId( - struct xdg_toplevel* xdg_toplevel, - const char* app_id) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 3, // XDG_TOPLEVEL_SET_APP_ID - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0, - app_id); -} - -static inline void xdgToplevelUnsetMaximized(struct xdg_toplevel* xdg_toplevel) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 10, // XDG_TOPLEVEL_UNSET_MAXIMIZED - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0); -} - -static const struct wl_interface* xdg_shell_types[26]; - -static const struct wl_message xdg_wm_base_requests[] = { - {"destroy", "", xdg_shell_types + 0}, - {"create_positioner", "n", xdg_shell_types + 4}, - {"get_xdg_surface", "no", xdg_shell_types + 5}, - {"pong", "u", xdg_shell_types + 0}, -}; - -static const struct wl_message xdg_wm_base_events[] = { - {"ping", "u", xdg_shell_types + 0}, -}; - -const struct wl_interface xdg_wm_base_interface = { - "xdg_wm_base", - 6, - 4, - xdg_wm_base_requests, - 1, - xdg_wm_base_events, -}; - -static const struct wl_message xdg_positioner_requests[] = { - {"destroy", "", xdg_shell_types + 0}, - {"set_size", "ii", xdg_shell_types + 0}, - {"set_anchor_rect", "iiii", xdg_shell_types + 0}, - {"set_anchor", "u", xdg_shell_types + 0}, - {"set_gravity", "u", xdg_shell_types + 0}, - {"set_constraint_adjustment", "u", xdg_shell_types + 0}, - {"set_offset", "ii", xdg_shell_types + 0}, - {"set_reactive", "3", xdg_shell_types + 0}, - {"set_parent_size", "3ii", xdg_shell_types + 0}, - {"set_parent_configure", "3u", xdg_shell_types + 0}, -}; - -const struct wl_interface xdg_positioner_interface = { - "xdg_positioner", - 6, - 10, - xdg_positioner_requests, - 0, - NULL, -}; - -static const struct wl_message xdg_surface_requests[] = { - {"destroy", "", xdg_shell_types + 0}, - {"get_toplevel", "n", xdg_shell_types + 7}, - {"get_popup", "n?oo", xdg_shell_types + 8}, - {"set_window_geometry", "iiii", xdg_shell_types + 0}, - {"ack_configure", "u", xdg_shell_types + 0}, -}; - -static const struct wl_message xdg_surface_events[] = { - {"configure", "u", xdg_shell_types + 0}, -}; - -const struct wl_interface xdg_surface_interface = { - "xdg_surface", - 6, - 5, - xdg_surface_requests, - 1, - xdg_surface_events, -}; - -static const struct wl_message xdg_toplevel_requests[] = { - {"destroy", "", xdg_shell_types + 0}, - {"set_parent", "?o", xdg_shell_types + 11}, - {"set_title", "s", xdg_shell_types + 0}, - {"set_app_id", "s", xdg_shell_types + 0}, - {"show_window_menu", "ouii", xdg_shell_types + 12}, - {"move", "ou", xdg_shell_types + 16}, - {"resize", "ouu", xdg_shell_types + 18}, - {"set_max_size", "ii", xdg_shell_types + 0}, - {"set_min_size", "ii", xdg_shell_types + 0}, - {"set_maximized", "", xdg_shell_types + 0}, - {"unset_maximized", "", xdg_shell_types + 0}, - {"set_fullscreen", "?o", xdg_shell_types + 21}, - {"unset_fullscreen", "", xdg_shell_types + 0}, - {"set_minimized", "", xdg_shell_types + 0}, -}; - -static const struct wl_message xdg_toplevel_events[] = { - {"configure", "iia", xdg_shell_types + 0}, - {"close", "", xdg_shell_types + 0}, - {"configure_bounds", "4ii", xdg_shell_types + 0}, - {"wm_capabilities", "5a", xdg_shell_types + 0}, -}; - -const struct wl_interface xdg_toplevel_interface = { - "xdg_toplevel", - 6, - 14, - xdg_toplevel_requests, - 4, - xdg_toplevel_events, -}; - -static const struct wl_message xdg_popup_requests[] = { - {"destroy", "", xdg_shell_types + 0}, - {"grab", "ou", xdg_shell_types + 22}, - {"reposition", "3ou", xdg_shell_types + 24}, -}; - -static const struct wl_message xdg_popup_events[] = { - {"configure", "iiii", xdg_shell_types + 0}, - {"popup_done", "", xdg_shell_types + 0}, - {"repositioned", "3u", xdg_shell_types + 0}, -}; - -const struct wl_interface xdg_popup_interface = { - "xdg_popup", - 6, - 3, - xdg_popup_requests, - 3, - xdg_popup_events, -}; - -static void setupXdgShellProtocol() -{ - xdg_shell_types[0] = NULL; - xdg_shell_types[1] = NULL; - xdg_shell_types[2] = NULL; - xdg_shell_types[3] = NULL; - xdg_shell_types[4] = &xdg_positioner_interface; - xdg_shell_types[5] = &xdg_surface_interface; - xdg_shell_types[6] = s_Wl.surfaceInterface; - xdg_shell_types[7] = &xdg_toplevel_interface; - xdg_shell_types[8] = &xdg_popup_interface; - xdg_shell_types[9] = &xdg_surface_interface; - xdg_shell_types[10] = &xdg_positioner_interface; - xdg_shell_types[11] = &xdg_toplevel_interface; - xdg_shell_types[12] = s_Wl.seatInterface; - xdg_shell_types[13] = NULL; - xdg_shell_types[14] = NULL; - xdg_shell_types[15] = NULL; - xdg_shell_types[16] = s_Wl.seatInterface; - xdg_shell_types[17] = NULL; - xdg_shell_types[18] = s_Wl.seatInterface; - xdg_shell_types[19] = NULL; - xdg_shell_types[20] = NULL; - xdg_shell_types[21] = s_Wl.outputInterface; - xdg_shell_types[22] = s_Wl.seatInterface; - xdg_shell_types[23] = NULL; - xdg_shell_types[24] = &xdg_positioner_interface; - xdg_shell_types[25] = NULL; -} - -static const struct xdg_wm_base_listener wmBaseListener = {.ping = wmBaseHandlePing}; - -static const struct xdg_surface_listener xdgSurfaceListener = { - .configure = xdgSurfaceHandleConfigure}; - -static const struct xdg_toplevel_listener xdgToplevelListener = { - .configure = xdgToplevelHandleConfigure, - .close = xdgToplevelHandleClose, - .configure_bounds = nullptr, - .wm_capabilities = nullptr}; - -#endif // PAL_HAS_WAYLAND -#pragma endregion - -#pragma region Zxdg-Decoraion_Manager-V1 -#if PAL_HAS_WAYLAND - -struct xdg_toplevel; -struct zxdg_decoration_manager_v1; -struct zxdg_toplevel_decoration_v1; - -struct zxdg_toplevel_decoration_v1_listener { - void (*configure)( - void*, - struct zxdg_toplevel_decoration_v1*, - uint32_t); -}; - -const struct wl_interface zxdg_decoration_manager_v1_interface; -const struct wl_interface zxdg_toplevel_decoration_v1_interface; - -static inline void -zxdgDecorationManagerV1Destroy(struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)zxdg_decoration_manager_v1, - 0, // ZXDG_DECORATION_MANAGER_V1_DESTROY - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_decoration_manager_v1), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline struct zxdg_toplevel_decoration_v1* zxdgGetToplevelDecoration( - struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1, - struct xdg_toplevel* toplevel) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)zxdg_decoration_manager_v1, - 1, // ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, - &zxdg_toplevel_decoration_v1_interface, - s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_decoration_manager_v1), - 0, - NULL, - toplevel); - - return (struct zxdg_toplevel_decoration_v1*)id; -} - -static inline int zxdgToplevelDecorationV1AddListener( - struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, - const struct zxdg_toplevel_decoration_v1_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener( - (struct wl_proxy*)zxdg_toplevel_decoration_v1, - (void (**)(void))listener, - data); -} - -static inline void -zxdgToplevelDecorationV1Destroy(struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)zxdg_toplevel_decoration_v1, - 0, // ZXDG_TOPLEVEL_DECORATION_V1_DESTROY - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_toplevel_decoration_v1), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline void zxdgToplevelDecorationV1SetMode( - struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, - uint32_t mode) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)zxdg_toplevel_decoration_v1, - 1, // ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_toplevel_decoration_v1), - 0, - mode); -} - -static const struct wl_interface* xdg_decoration_unstable_v1_types[] = { - NULL, - &zxdg_toplevel_decoration_v1_interface, - &xdg_toplevel_interface, -}; - -static const struct wl_message zxdg_decoration_manager_v1_requests[] = { - {"destroy", "", xdg_decoration_unstable_v1_types + 0}, - {"get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1}, -}; - -const struct wl_interface zxdg_decoration_manager_v1_interface = { - "zxdg_decoration_manager_v1", - 1, - 2, - zxdg_decoration_manager_v1_requests, - 0, - NULL, -}; - -static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = { - {"destroy", "", xdg_decoration_unstable_v1_types + 0}, - {"set_mode", "u", xdg_decoration_unstable_v1_types + 0}, - {"unset_mode", "", xdg_decoration_unstable_v1_types + 0}, -}; - -static const struct wl_message zxdg_toplevel_decoration_v1_events[] = { - {"configure", "u", xdg_decoration_unstable_v1_types + 0}, -}; - -const struct wl_interface zxdg_toplevel_decoration_v1_interface = { - "zxdg_toplevel_decoration_v1", - 1, - 3, - zxdg_toplevel_decoration_v1_requests, - 1, - zxdg_toplevel_decoration_v1_events, -}; - -void zxdgDecorationHandleConfigure( - void* data, - struct zxdg_toplevel_decoration_v1* dec, - uint32_t mode) -{ - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode dispatchMode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_WINDOW_DECORATION_MODE; - dispatchMode = palGetEventDispatchMode(driver, type); - - if (dispatchMode != PAL_DISPATCH_NONE) { - PalDecorationMode decorMode = PAL_DECORATION_MODE_SERVER_SIDE; - if (mode == 0 || mode == 1) { - // client side decoration - decorMode = PAL_DECORATION_MODE_CLIENT_SIDE; - } - - PalEvent event = {0}; - event.type = type; - event.data = decorMode; - event.data2 = palPackPointer(data); - palPushEvent(driver, &event); - } - } -} - -static struct zxdg_toplevel_decoration_v1_listener decorationListener = { - .configure = zxdgDecorationHandleConfigure}; - -#endif // PAL_HAS_WAYLAND -#pragma endregion - -// ================================================== -// Internal API -// ================================================== - -static int compareModes( - const void* a, - const void* b) -{ - const PalMonitorMode* mode1 = (const PalMonitorMode*)a; - const PalMonitorMode* mode2 = (const PalMonitorMode*)b; - - // compare fields - if (mode1->width != mode2->width) { - return mode1->width - mode2->width; - } - - if (mode1->height != mode2->height) { - return mode1->height - mode2->height; - } - - if (mode1->refreshRate != mode2->refreshRate) { - return mode1->refreshRate - mode2->refreshRate; - } - - if (mode1->bpp != mode2->bpp) { - return mode1->bpp - mode2->bpp; - } -} - -static WindowData* getFreeWindowData() -{ - for (int i = 0; i < s_Video.maxWindowData; ++i) { - if (!s_Video.windowData[i].used) { - s_Video.windowData[i].used = PAL_TRUE; - return &s_Video.windowData[i]; - } - } - - // resize the data array - // It is rare for a user to create and manage - // 32 windows at the same time - WindowData* data = nullptr; - int count = s_Video.maxWindowData * 2; // double the size - int freeIndex = s_Video.maxWindowData + 1; - data = palAllocate(s_Video.allocator, sizeof(WindowData) * count, 0); - if (data) { - memcpy(data, s_Video.windowData, s_Video.maxWindowData * sizeof(WindowData)); - - palFree(s_Video.allocator, s_Video.windowData); - s_Video.windowData = data; - s_Video.maxWindowData = count; - - s_Video.windowData[freeIndex].used = PAL_TRUE; - return &s_Video.windowData[freeIndex]; - } - return nullptr; -} - -static WindowData* findWindowData(PalWindow* window) -{ - for (int i = 0; i < s_Video.maxWindowData; ++i) { - if (s_Video.windowData[i].used && s_Video.windowData[i].window == window) { - return &s_Video.windowData[i]; - } - } - return nullptr; -} - -static void resetMonitorData() -{ - memset(s_Video.monitorData, 0, s_Video.maxMonitorData * sizeof(MonitorData)); -} - -static MonitorData* getFreeMonitorData() -{ - for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (!s_Video.monitorData[i].used) { - s_Video.monitorData[i].used = PAL_TRUE; - return &s_Video.monitorData[i]; - } - } - - // resize the data array - // this will almost not reach here since most setups are 1-4 monitors - MonitorData* data = nullptr; - int count = s_Video.maxMonitorData * 2; // double the size - int freeIndex = s_Video.maxMonitorData + 1; - data = palAllocate(s_Video.allocator, sizeof(MonitorData) * count, 0); - if (data) { - memcpy(data, s_Video.monitorData, s_Video.maxMonitorData * sizeof(MonitorData)); - - palFree(s_Video.allocator, s_Video.monitorData); - s_Video.monitorData = data; - s_Video.maxWindowData = count; - - s_Video.monitorData[freeIndex].used = PAL_TRUE; - return &s_Video.monitorData[freeIndex]; - } - return nullptr; -} - -static MonitorData* findMonitorData(PalMonitor* monitor) -{ - for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (s_Video.monitorData[i].used && s_Video.monitorData[i].monitor == monitor) { - return &s_Video.monitorData[i]; - } - } - return nullptr; -} - -static void freeMonitorData(PalMonitor* monitor) -{ - for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (s_Video.monitorData[i].used && s_Video.monitorData[i].monitor == monitor) { - s_Video.monitorData[i].used = PAL_FALSE; - } - } -} - -static void createScancodeTable() -{ - // Letters - s_Keyboard.scancodes[0x01E] = PAL_SCANCODE_A; - s_Keyboard.scancodes[0x030] = PAL_SCANCODE_B; - s_Keyboard.scancodes[0x02E] = PAL_SCANCODE_C; - s_Keyboard.scancodes[0x020] = PAL_SCANCODE_D; - s_Keyboard.scancodes[0x012] = PAL_SCANCODE_E; - s_Keyboard.scancodes[0x021] = PAL_SCANCODE_F; - s_Keyboard.scancodes[0x022] = PAL_SCANCODE_G; - s_Keyboard.scancodes[0x023] = PAL_SCANCODE_H; - s_Keyboard.scancodes[0x017] = PAL_SCANCODE_I; - s_Keyboard.scancodes[0x024] = PAL_SCANCODE_J; - s_Keyboard.scancodes[0x025] = PAL_SCANCODE_K; - s_Keyboard.scancodes[0x026] = PAL_SCANCODE_L; - s_Keyboard.scancodes[0x032] = PAL_SCANCODE_M; - s_Keyboard.scancodes[0x031] = PAL_SCANCODE_N; - s_Keyboard.scancodes[0x018] = PAL_SCANCODE_O; - s_Keyboard.scancodes[0x019] = PAL_SCANCODE_P; - s_Keyboard.scancodes[0x010] = PAL_SCANCODE_Q; - s_Keyboard.scancodes[0x013] = PAL_SCANCODE_R; - s_Keyboard.scancodes[0x01F] = PAL_SCANCODE_S; - s_Keyboard.scancodes[0x014] = PAL_SCANCODE_T; - s_Keyboard.scancodes[0x016] = PAL_SCANCODE_U; - s_Keyboard.scancodes[0x02F] = PAL_SCANCODE_V; - s_Keyboard.scancodes[0x011] = PAL_SCANCODE_W; - s_Keyboard.scancodes[0x02D] = PAL_SCANCODE_X; - s_Keyboard.scancodes[0x015] = PAL_SCANCODE_Y; - s_Keyboard.scancodes[0x02C] = PAL_SCANCODE_Z; - - // Numbers (top row) - s_Keyboard.scancodes[0x00B] = PAL_SCANCODE_0; - s_Keyboard.scancodes[0x002] = PAL_SCANCODE_1; - s_Keyboard.scancodes[0x003] = PAL_SCANCODE_2; - s_Keyboard.scancodes[0x004] = PAL_SCANCODE_3; - s_Keyboard.scancodes[0x005] = PAL_SCANCODE_4; - s_Keyboard.scancodes[0x006] = PAL_SCANCODE_5; - s_Keyboard.scancodes[0x007] = PAL_SCANCODE_6; - s_Keyboard.scancodes[0x008] = PAL_SCANCODE_7; - s_Keyboard.scancodes[0x009] = PAL_SCANCODE_8; - s_Keyboard.scancodes[0x00A] = PAL_SCANCODE_9; - - // Function - s_Keyboard.scancodes[0x03B] = PAL_SCANCODE_F1; - s_Keyboard.scancodes[0x03C] = PAL_SCANCODE_F2; - s_Keyboard.scancodes[0x03D] = PAL_SCANCODE_F3; - s_Keyboard.scancodes[0x03E] = PAL_SCANCODE_F4; - s_Keyboard.scancodes[0x03F] = PAL_SCANCODE_F5; - s_Keyboard.scancodes[0x040] = PAL_SCANCODE_F6; - s_Keyboard.scancodes[0x041] = PAL_SCANCODE_F7; - s_Keyboard.scancodes[0x042] = PAL_SCANCODE_F8; - s_Keyboard.scancodes[0x043] = PAL_SCANCODE_F9; - s_Keyboard.scancodes[0x044] = PAL_SCANCODE_F10; - s_Keyboard.scancodes[0x057] = PAL_SCANCODE_F11; - s_Keyboard.scancodes[0x058] = PAL_SCANCODE_F12; - - // Control - s_Keyboard.scancodes[0x001] = PAL_SCANCODE_ESCAPE; - s_Keyboard.scancodes[0x01C] = PAL_SCANCODE_ENTER; - s_Keyboard.scancodes[0x00F] = PAL_SCANCODE_TAB; - s_Keyboard.scancodes[0x00E] = PAL_SCANCODE_BACKSPACE; - s_Keyboard.scancodes[0x039] = PAL_SCANCODE_SPACE; - s_Keyboard.scancodes[0x03A] = PAL_SCANCODE_CAPSLOCK; - s_Keyboard.scancodes[0x045] = PAL_SCANCODE_NUMLOCK; - s_Keyboard.scancodes[0x046] = PAL_SCANCODE_SCROLLLOCK; - s_Keyboard.scancodes[0x02A] = PAL_SCANCODE_LSHIFT; - s_Keyboard.scancodes[0x036] = PAL_SCANCODE_RSHIFT; - s_Keyboard.scancodes[0x01D] = PAL_SCANCODE_LCTRL; - s_Keyboard.scancodes[0x061] = PAL_SCANCODE_RCTRL; - s_Keyboard.scancodes[0x038] = PAL_SCANCODE_LALT; - s_Keyboard.scancodes[0x064] = PAL_SCANCODE_RALT; - - // Arrows - s_Keyboard.scancodes[0x069] = PAL_SCANCODE_LEFT; - s_Keyboard.scancodes[0x06A] = PAL_SCANCODE_RIGHT; - s_Keyboard.scancodes[0x067] = PAL_SCANCODE_UP; - s_Keyboard.scancodes[0x06C] = PAL_SCANCODE_DOWN; - - // Navigation - s_Keyboard.scancodes[0x06E] = PAL_SCANCODE_INSERT; - s_Keyboard.scancodes[0x06F] = PAL_SCANCODE_DELETE; - s_Keyboard.scancodes[0x066] = PAL_SCANCODE_HOME; - s_Keyboard.scancodes[0x067] = PAL_SCANCODE_END; - s_Keyboard.scancodes[0x068] = PAL_SCANCODE_PAGEUP; - s_Keyboard.scancodes[0x06D] = PAL_SCANCODE_PAGEDOWN; - - // Keypad - s_Keyboard.scancodes[0x052] = PAL_SCANCODE_KP_0; - s_Keyboard.scancodes[0x04F] = PAL_SCANCODE_KP_1; - s_Keyboard.scancodes[0x050] = PAL_SCANCODE_KP_2; - s_Keyboard.scancodes[0x051] = PAL_SCANCODE_KP_3; - s_Keyboard.scancodes[0x04B] = PAL_SCANCODE_KP_4; - s_Keyboard.scancodes[0x04C] = PAL_SCANCODE_KP_5; - s_Keyboard.scancodes[0x04D] = PAL_SCANCODE_KP_6; - s_Keyboard.scancodes[0x047] = PAL_SCANCODE_KP_7; - s_Keyboard.scancodes[0x048] = PAL_SCANCODE_KP_8; - s_Keyboard.scancodes[0x049] = PAL_SCANCODE_KP_9; - s_Keyboard.scancodes[0x060] = PAL_SCANCODE_KP_ENTER; - s_Keyboard.scancodes[0x04E] = PAL_SCANCODE_KP_ADD; - s_Keyboard.scancodes[0x04A] = PAL_SCANCODE_KP_SUBTRACT; - s_Keyboard.scancodes[0x037] = PAL_SCANCODE_KP_MULTIPLY; - s_Keyboard.scancodes[0x062] = PAL_SCANCODE_KP_DIVIDE; - s_Keyboard.scancodes[0x053] = PAL_SCANCODE_KP_DECIMAL; - - // Misc - s_Keyboard.scancodes[0x063] = PAL_SCANCODE_PRINTSCREEN; - s_Keyboard.scancodes[0x066] = PAL_SCANCODE_PAUSE; - s_Keyboard.scancodes[0x07F] = PAL_SCANCODE_MENU; - s_Keyboard.scancodes[0x028] = PAL_SCANCODE_APOSTROPHE; - s_Keyboard.scancodes[0x02B] = PAL_SCANCODE_BACKSLASH; - s_Keyboard.scancodes[0x033] = PAL_SCANCODE_COMMA; - s_Keyboard.scancodes[0x00D] = PAL_SCANCODE_EQUAL; - s_Keyboard.scancodes[0x029] = PAL_SCANCODE_GRAVEACCENT; - s_Keyboard.scancodes[0x00C] = PAL_SCANCODE_SUBTRACT; - s_Keyboard.scancodes[0x034] = PAL_SCANCODE_PERIOD; - s_Keyboard.scancodes[0x027] = PAL_SCANCODE_SEMICOLON; - s_Keyboard.scancodes[0x035] = PAL_SCANCODE_SLASH; - s_Keyboard.scancodes[0x01A] = PAL_SCANCODE_LBRACKET; - s_Keyboard.scancodes[0x01B] = PAL_SCANCODE_RBRACKET; - s_Keyboard.scancodes[0x07D] = PAL_SCANCODE_LSUPER; - s_Keyboard.scancodes[0x07E] = PAL_SCANCODE_RSUPER; -} - -void palSetLastPlatformError(uint32_t e); - -// ================================================== -// X11 API -// ================================================== - -#pragma region X11 API -#if PAL_HAS_X11 - -static PalResult glxBackend(const int index) -{ - // user choose GLX FBConfig backend - if (!s_X11.glxHandle) { - // Rare - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - int count = 0; - GLXFBConfig* configs = s_X11.glxGetFBConfigs(s_X11.display, s_X11.screen, &count); - - GLXFBConfig fbConfig = configs[index]; - if (!fbConfig) { - return PAL_RESULT_INVALID_GL_FBCONFIG; - } - - // get a matching visual - XVisualInfo* visualInfo = s_X11.glxGetVisualFromFBConfig(s_X11.display, fbConfig); - if (!visualInfo) { - return PAL_RESULT_INVALID_GL_FBCONFIG; - } - - s_X11.visualInfo = visualInfo; - return PAL_RESULT_SUCCESS; -} - -static PalResult eglXBackend(int index) -{ - // user choose EGL FBConfig backend - if (!s_Egl.handle) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - EGLDisplay display = EGL_NO_DISPLAY; - display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_X11.display); - if (display == EGL_NO_DISPLAY) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - EGLint numConfigs = 0; - if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - EGLint configSize = sizeof(EGLConfig) * numConfigs; - EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); - if (!eglConfigs) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); - EGLConfig config = eglConfigs[index]; - - // we get a visual info from the config - EGLint visualID; - s_Egl.eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualID); - if (visualID == 0) { - return PAL_RESULT_INVALID_GL_FBCONFIG; - } - - int numVisuals = 0; - XVisualInfo tmp; - tmp.visualid = visualID; - - // get a matching visual info - XVisualInfo* visualInfo = s_X11.getVisualInfo(s_X11.display, VisualIDMask, &tmp, &numVisuals); - if (!visualInfo) { - return PAL_RESULT_INVALID_GL_FBCONFIG; - } - - s_X11.visualInfo = visualInfo; - palFree(s_Video.allocator, eglConfigs); - return PAL_RESULT_SUCCESS; -} - -static RRMode xFindMode( - XRRScreenResources* resources, - const PalMonitorMode* mode) -{ - for (int i = 0; i < resources->nmode; ++i) { - XRRModeInfo* info = &resources->modes[i]; - - double tmp = (double)info->hTotal * (double)info->vTotal; - double rate = (double)info->dotClock / tmp; - - // compare with width, height and refresh rate - if (info->width == mode->width && info->height == mode->height && - (uint32_t)(rate + 0.5) == mode->refreshRate) { - return info->id; - } - } - return None; -} - -static void xCheckFeatures() -{ - // cache this atoms - X_INTERN(WM_DELETE_WINDOW); - X_INTERN(_NET_SUPPORTED); - X_INTERN(_NET_WM_STATE); - X_INTERN(_NET_WM_STATE_ABOVE); - X_INTERN(_NET_WM_STATE_MAXIMIZED_VERT); - X_INTERN(_NET_WM_STATE_MAXIMIZED_HORZ); - X_INTERN(_NET_WM_STATE_HIDDEN); - X_INTERN(_NET_WM_NAME); - X_INTERN(UTF8_STRING); - X_INTERN(_NET_WM_WINDOW_TYPE_UTILITY); - X_INTERN(_NET_WM_DESKTOP); - X_INTERN(_NET_WM_STATE_DEMANDS_ATTENTIONS); - X_INTERN(_NET_WM_WINDOW_OPACITY); - X_INTERN(_NET_WM_WINDOW_TYPE); - X_INTERN(_NET_WM_WINDOW_TYPE_SPLASH); - X_INTERN(_NET_WM_PID); - X_INTERN(_WM_CLASS); - X_INTERN(_NET_ACTIVE_WINDOW); - X_INTERN(_NET_WM_ICON); - - // check for support from the window manager - Atom type; - int format; - unsigned long count, bytesAfters; - Atom* supportedAtoms = nullptr; - s_X11.getWindowProperty( - s_X11.display, - s_X11.root, - s_X11Atoms._NET_SUPPORTED, - 0, - (~0L), - False, - XA_ATOM, - &type, - &format, - &count, - &bytesAfters, - (unsigned char**)&supportedAtoms); - - PalVideoFeatures features = 0; - PalVideoFeatures64 features64 = 0; - for (unsigned long i = 0; i < count; ++i) { - if (supportedAtoms[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT) { - features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; - features |= PAL_VIDEO_FEATURE_WINDOW_GET_STATE; - } - - if (supportedAtoms[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ) { - features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; - features |= PAL_VIDEO_FEATURE_WINDOW_GET_STATE; - } - - if (supportedAtoms[i] == s_X11Atoms._NET_WM_STATE_HIDDEN) { - features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; - features |= PAL_VIDEO_FEATURE_WINDOW_GET_STATE; - } - - if (supportedAtoms[i] == s_X11Atoms._NET_WM_WINDOW_TYPE_SPLASH) { - features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; - } - - if (supportedAtoms[i] == s_X11Atoms._NET_WM_NAME) { - s_X11Atoms.unicodeTitle = PAL_TRUE; - } - - if (supportedAtoms[i] == s_X11Atoms._NET_WM_WINDOW_TYPE_UTILITY) { - features |= PAL_VIDEO_FEATURE_TOOL_WINDOW; - } - } - - // check for transparent windows - Atom compositor = s_X11.internAtom(s_X11.display, "_NET_WM_CM_S0", True); - if (compositor != None) { - Window owner = s_X11.getSelectionOwner(s_X11.display, compositor); - if (owner != None) { - features |= PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW; - } - } - - // general features - features |= PAL_VIDEO_FEATURE_MULTI_MONITORS; - features |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; - features |= PAL_VIDEO_FEATURE_MONITOR_SET_MODE; - features |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; - features |= PAL_VIDEO_FEATURE_WINDOW_GET_SIZE; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY; - features |= PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY; - - features |= PAL_VIDEO_FEATURE_CLIP_CURSOR; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS; - features |= PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS; - features |= PAL_VIDEO_FEATURE_CURSOR_SET_POS; - features |= PAL_VIDEO_FEATURE_CURSOR_GET_POS; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; - features |= PAL_VIDEO_FEATURE_WINDOW_GET_TITLE; - features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY; - - // extended features - // old features - features64 |= PAL_VIDEO_FEATURE_MULTI_MONITORS; - features64 |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; - features64 |= PAL_VIDEO_FEATURE_MONITOR_SET_MODE; - features64 |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; - features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; - features64 |= PAL_VIDEO_FEATURE_WINDOW_GET_SIZE; - features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY; - features64 |= PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY; - - features64 |= PAL_VIDEO_FEATURE_CLIP_CURSOR; - features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS; - features64 |= PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS; - features64 |= PAL_VIDEO_FEATURE_CURSOR_SET_POS; - features64 |= PAL_VIDEO_FEATURE_CURSOR_GET_POS; - features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; - features64 |= PAL_VIDEO_FEATURE_WINDOW_GET_TITLE; - features64 |= PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY; - - features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_ICON; - features64 |= PAL_VIDEO_FEATURE_TOPMOST_WINDOW; - features64 |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; - features64 |= PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY; - features64 |= PAL_VIDEO_FEATURE_FOREIGN_WINDOWS; - features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; - - s_Video.features = features; - s_Video.features64 = features64; - s_X11.free(supportedAtoms); -} - -static int xErrorHandler( - Display*, - XErrorEvent* e) -{ - // this is use for simple success and failure - s_X11.error = PAL_TRUE; - return 0; -} - -static PalWindowState xQueryWindowState(Window xWin) -{ - Atom type; - int format; - unsigned long count, bytesAfter; - Atom* atoms = nullptr; - PalWindowState state = PAL_WINDOW_STATE_RESTORED; - - s_X11.getWindowProperty( - s_X11.display, - xWin, - s_X11Atoms._NET_WM_STATE, - 0, - 1024, - False, - XA_ATOM, - &type, - &format, - &count, - &bytesAfter, - (unsigned char**)&atoms); - - for (unsigned int i = 0; i < count; i++) { - if (atoms[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ) { - state = PAL_WINDOW_STATE_MAXIMIZED; - } - - if (atoms[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT) { - state = PAL_WINDOW_STATE_MAXIMIZED; - } - - if (atoms[i] == s_X11Atoms._NET_WM_STATE_HIDDEN) { - state = PAL_WINDOW_STATE_MINIMIZED; - } - } - - s_X11.free(atoms); - return state; -} - -static void xCacheMonitors() -{ - resetMonitorData(); - XRRScreenResources* resources = nullptr; - resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - - for (int i = 0; i < resources->noutput; ++i) { - RROutput output = resources->outputs[i]; - XRROutputInfo* info = s_X11.getOutputInfo(s_X11.display, resources, output); - if (info->connection == RR_Connected && info->crtc != None) { - // get monitor data and update info - PalMonitor* monitor = TO_PAL_HANDLE(PalMonitor, output); - MonitorData* data = nullptr; - data = getFreeMonitorData(); - if (!data) { - return; - } - - data->monitor = monitor; - XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, info->crtc); - - // get DPI - float raw = crtc->width / 1920.0f; - float steps[] = {1.0f, 1.2f, 1.5f, 1.75, 2.0f}; - float closest = steps[0]; - float minDiff = fabsf(raw - steps[0]); - - for (int i = 1; i < sizeof(steps) / sizeof(steps[0]); i++) { - float diff = fabsf(raw - steps[i]); - if (diff < minDiff) { - minDiff = diff; - closest = steps[i]; - } - } - - data->dpi = (uint32_t)(closest * 96.0f); - data->w = crtc->width; - data->h = crtc->height; - data->x = crtc->x; - data->y = crtc->y; - - s_X11.freeCrtcInfo(crtc); - s_X11.monitorCount++; - } - - s_X11.freeOutputInfo(info); - } - - s_X11.freeScreenResources(resources); -} - -static int xGetWindowMonitorDPI(WindowData* data) -{ - int winX = data->x + data->w / 2; - int winY = data->y + data->w / 2; - // get the DPI from our cached monitor - for (int i = 0; i < s_Video.maxMonitorData; i++) { - if (!s_Video.monitorData->used) { - continue; - } - - // we found a monitor, check the monitor bounds with the window - MonitorData* info = &s_Video.monitorData[i]; - if (winX >= info->x && winX < info->x + info->w && winY >= info->y && - winY < info->y + info->h) { - // found monitor - return info->dpi; - } - } -} - -static void xSendWMEvent( - Window window, - Atom type, - long a, - long b, - long c, - long d, - PalBool add) -{ - XEvent e = {0}; - e.xclient.type = ClientMessage; - e.xclient.send_event = True; - e.xclient.window = window; - e.xclient.message_type = type; - e.xclient.format = 32; - if (add) { - e.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD - } else { - e.xclient.data.l[0] = 0; // _NET_WM_STATE_REMOVE - } - - e.xclient.data.l[1] = a; - e.xclient.data.l[2] = b; - e.xclient.data.l[3] = c; - e.xclient.data.l[4] = d; - - s_X11.sendEvent( - s_X11.display, - s_X11.root, - False, - SubstructureNotifyMask | SubstructureRedirectMask, - &e); -} - -static void xCreateKeycodeTable() -{ - // Tis is for only printable and text input keys - - // Letters - s_Keyboard.keycodes[XK_a] = PAL_KEYCODE_A; - s_Keyboard.keycodes[XK_b] = PAL_KEYCODE_B; - s_Keyboard.keycodes[XK_c] = PAL_KEYCODE_C; - s_Keyboard.keycodes[XK_d] = PAL_KEYCODE_D; - s_Keyboard.keycodes[XK_e] = PAL_KEYCODE_E; - s_Keyboard.keycodes[XK_f] = PAL_KEYCODE_F; - s_Keyboard.keycodes[XK_g] = PAL_KEYCODE_G; - s_Keyboard.keycodes[XK_h] = PAL_KEYCODE_H; - s_Keyboard.keycodes[XK_i] = PAL_KEYCODE_I; - s_Keyboard.keycodes[XK_j] = PAL_KEYCODE_J; - s_Keyboard.keycodes[XK_k] = PAL_KEYCODE_K; - s_Keyboard.keycodes[XK_l] = PAL_KEYCODE_L; - s_Keyboard.keycodes[XK_m] = PAL_KEYCODE_M; - s_Keyboard.keycodes[XK_n] = PAL_KEYCODE_N; - s_Keyboard.keycodes[XK_o] = PAL_KEYCODE_O; - s_Keyboard.keycodes[XK_p] = PAL_KEYCODE_P; - s_Keyboard.keycodes[XK_q] = PAL_KEYCODE_Q; - s_Keyboard.keycodes[XK_r] = PAL_KEYCODE_R; - s_Keyboard.keycodes[XK_s] = PAL_KEYCODE_S; - s_Keyboard.keycodes[XK_t] = PAL_KEYCODE_T; - s_Keyboard.keycodes[XK_u] = PAL_KEYCODE_U; - s_Keyboard.keycodes[XK_v] = PAL_KEYCODE_V; - s_Keyboard.keycodes[XK_w] = PAL_KEYCODE_W; - s_Keyboard.keycodes[XK_x] = PAL_KEYCODE_X; - s_Keyboard.keycodes[XK_y] = PAL_KEYCODE_Y; - s_Keyboard.keycodes[XK_z] = PAL_KEYCODE_Z; - - // Control - s_Keyboard.keycodes[XK_space] = PAL_KEYCODE_SPACE; - - // Misc - s_Keyboard.keycodes[XK_apostrophe] = PAL_KEYCODE_APOSTROPHE; - s_Keyboard.keycodes[XK_backslash] = PAL_KEYCODE_BACKSLASH; - s_Keyboard.keycodes[XK_comma] = PAL_KEYCODE_COMMA; - s_Keyboard.keycodes[XK_equal] = PAL_KEYCODE_EQUAL; - s_Keyboard.keycodes[XK_grave] = PAL_KEYCODE_GRAVEACCENT; - s_Keyboard.keycodes[XK_minus] = PAL_KEYCODE_SUBTRACT; - s_Keyboard.keycodes[XK_period] = PAL_KEYCODE_PERIOD; - s_Keyboard.keycodes[XK_semicolon] = PAL_KEYCODE_SEMICOLON; - s_Keyboard.keycodes[XK_slash] = PAL_KEYCODE_SLASH; - s_Keyboard.keycodes[XK_bracketleft] = PAL_KEYCODE_LBRACKET; - s_Keyboard.keycodes[XK_bracketright] = PAL_KEYCODE_RBRACKET; -} - -static PalResult xInitVideo() -{ - // load X11 library - s_X11.handle = dlopen("libX11.so", RTLD_LAZY); - if (!s_X11.handle) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // libXCursor is needed - s_X11.libCursor = dlopen("libXcursor.so", RTLD_LAZY); - if (!s_X11.libCursor) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // Xrandr is needed - s_X11.xrandr = dlopen("libXrandr.so.2", RTLD_LAZY); - if (!s_X11.xrandr) { - s_X11.xrandr = dlopen("libXrandr.so", RTLD_LAZY); - } - - // clang-format off - // load procs - s_X11.openDisplay = (XOpenDisplayFn)dlsym( - s_X11.handle, - "XOpenDisplay"); - - s_X11.closeDisplay = (XCloseDisplayFn)dlsym( - s_X11.handle, - "XCloseDisplay"); - - s_X11.getWindowAttributes = (XGetWindowAttributesFn)dlsym( - s_X11.handle, - "XGetWindowAttributes"); - - s_X11.setCrtcConfig = (XRRSetCrtcConfigFn)dlsym( - s_X11.handle, - "XRRSetCrtcConfig"); - - s_X11.getWindowProperty = (XGetWindowPropertyFn)dlsym( - s_X11.handle, - "XGetWindowProperty"); - - s_X11.internAtom = (XInternAtomFn)dlsym( - s_X11.handle, - "XInternAtom"); - - s_X11.getSelectionOwner = (XGetSelectionOwnerFn)dlsym( - s_X11.handle, - "XGetSelectionOwner"); - - s_X11.freeColormap = (XFreeColormapFn)dlsym( - s_X11.handle, - "XFreeColormap"); - - s_X11.storeName = (XStoreNameFn)dlsym( - s_X11.handle, - "XStoreName"); - - s_X11.changeProperty = (XChangePropertyFn)dlsym( - s_X11.handle, - "XChangeProperty"); - - s_X11.flush = (XFlushFn)dlsym( - s_X11.handle, - "XFlush"); - - s_X11.createColormap = (XCreateColormapFn)dlsym( - s_X11.handle, - "XCreateColormap"); - - s_X11.mapWindow = (XMapWindowFn)dlsym( - s_X11.handle, - "XMapWindow"); - - s_X11.unmapWindow = (XUnmapWindowFn)dlsym( - s_X11.handle, - "XUnmapWindow"); - - s_X11.createWindow = (XCreateWindowFn)dlsym( - s_X11.handle, - "XCreateWindow"); - - s_X11.destroyWindow = (XDestroyWindowFn)dlsym( - s_X11.handle, - "XDestroyWindow"); - - s_X11.matchVisualInfo = (XMatchVisualInfoFn)dlsym( - s_X11.handle, - "XMatchVisualInfo"); - - s_X11.pending = (XPendingFn)dlsym( - s_X11.handle, - "XPending"); - - s_X11.setWMProtocols = (XSetWMProtocolsFn)dlsym( - s_X11.handle, - "XSetWMProtocols"); - - s_X11.nextEvent = (XNextEventFn)dlsym( - s_X11.handle, - "XNextEvent"); - - s_X11.setWMNormalHints = (XSetWMNormalHintsFn)dlsym( - s_X11.handle, - "XSetWMNormalHints"); - - s_X11.getWMNormalHints = (XGetWMNormalHintsFn)dlsym( - s_X11.handle, - "XGetWMNormalHints"); - - s_X11.sendEvent = (XSendEventFn)dlsym( - s_X11.handle, - "XSendEvent"); - - s_X11.moveWindow = (XMoveWindowFn)dlsym( - s_X11.handle, - "XMoveWindow"); - - s_X11.resizeWindow = (XResizeWindowFn)dlsym( - s_X11.handle, - "XResizeWindow"); - - s_X11.iconifyWindow = (XIconifyWindowFn)dlsym( - s_X11.handle, - "XIconifyWindow"); - - s_X11.setErrorHandler = (XSetErrorHandlerFn)dlsym( - s_X11.handle, - "XSetErrorHandler"); - - s_X11.sync = (XSyncFn)dlsym( - s_X11.handle, - "XSync"); - - s_X11.saveContext = (XSaveContextFn)dlsym( - s_X11.handle, - "XSaveContext"); - - s_X11.findContext = (XFindContextFn)dlsym( - s_X11.handle, - "XFindContext"); - - s_X11.uniqueContext = (XrmUniqueQuarkFn)dlsym( - s_X11.handle, - "XrmUniqueQuark"); - - // load Xrandr functions - s_X11.getScreenResources = (XRRGetScreenResourcesFn)dlsym( - s_X11.xrandr, - "XRRGetScreenResources"); - - s_X11.getOutputPrimary = (XRRGetOutputPrimaryFn)dlsym( - s_X11.xrandr, - "XRRGetOutputPrimary"); - - s_X11.getOutputInfo = (XRRGetOutputInfoFn)dlsym( - s_X11.xrandr, - "XRRGetOutputInfo"); - - s_X11.getCrtcInfo = (XRRGetCrtcInfoFn)dlsym( - s_X11.xrandr, - "XRRGetCrtcInfo"); - - s_X11.freeScreenResources = (XRRFreeScreenResourcesFn)dlsym( - s_X11.xrandr, - "XRRFreeScreenResources"); - - s_X11.freeOutputInfo = (XRRFreeOutputInfoFn)dlsym( - s_X11.xrandr, - "XRRFreeScreenResources"); - - s_X11.freeCrtcInfo = (XRRFreeCrtcInfoFn)dlsym( - s_X11.xrandr, - "XRRFreeCrtcInfo"); - - s_X11.selectRRInput = (XRRSelectInputFn)dlsym( - s_X11.xrandr, - "XRRSelectInput"); - - s_X11.queryRRExtension = (XRRQueryExtensionFn)dlsym( - s_X11.xrandr, - "XRRQueryExtension"); - - s_X11.allocClassHint = (XAllocClassHintFn)dlsym( - s_X11.handle, - "XAllocClassHint"); - - s_X11.setClassHint = (XSetClassHintFn)dlsym( - s_X11.handle, - "XSetClassHint"); - - s_X11.free = (XFreeFn)dlsym( - s_X11.handle, - "XFree"); - - s_X11.getVisualInfo = (XGetVisualInfoFn)dlsym( - s_X11.handle, - "XGetVisualInfo"); - - s_X11.createFontCursor = (XCreateFontCursorFn)dlsym( - s_X11.handle, - "XCreateFontCursor"); - - s_X11.freePixmap = (XFreePixmapFn)dlsym( - s_X11.handle, - "XFreePixmap"); - - s_X11.setWMHints = (XSetWMHintsFn)dlsym( - s_X11.handle, - "XSetWMHints"); - - s_X11.grabPointer = (XGrabPointerFn)dlsym( - s_X11.handle, - "XGrabPointer"); - - s_X11.createPixmapCursor = (XCreatePixmapCursorFn)dlsym( - s_X11.handle, - "XCreatePixmapCursor"); - - s_X11.warpPointer = (XWarpPointerFn)dlsym( - s_X11.handle, - "XWarpPointer"); - - s_X11.getWMName = (XGetWMNameFn)dlsym( - s_X11.handle, - "XGetWMName"); - - s_X11.queryPointer = (XQueryPointerFn)dlsym( - s_X11.handle, - "XQueryPointer"); - - s_X11.ungrabPointer = (XUngrabPointerFn)dlsym( - s_X11.handle, - "XUngrabPointer"); - - s_X11.allocWMHints = (XAllocWMHintsFn)dlsym( - s_X11.handle, - "XAllocWMHints"); - - s_X11.mapRaised = (XMapRaisedFn)dlsym( - s_X11.handle, - "XMapRaised"); - - s_X11.undefineCursor = (XUndefineCursorFn)dlsym( - s_X11.handle, - "XUndefineCursor"); - - s_X11.defineCursor = (XDefineCursorFn)dlsym( - s_X11.handle, - "XDefineCursor"); - - s_X11.freeCursor = (XFreeCursorFn)dlsym( - s_X11.handle, - "XFreeCursor"); - - s_X11.getWMHints = (XGetWMHintsFn)dlsym( - s_X11.handle, - "XGetWMHints"); - - s_X11.createPixmap = (XCreatePixmapFn)dlsym( - s_X11.handle, - "XCreatePixmap"); - - s_X11.setInputFocus = (XSetInputFocusFn)dlsym( - s_X11.handle, - "XSetInputFocus"); - - s_X11.getInputFocus = (XGetInputFocusFn)dlsym( - s_X11.handle, - "XGetInputFocus"); - - s_X11.selectInput = (XSelectInputFn)dlsym( - s_X11.handle, - "XSelectInput"); - - // libXcursor - s_X11.cursorImageLoadCursor = (XcursorImageLoadCursorFn)dlsym( - s_X11.libCursor, - "XcursorImageLoadCursor"); - - s_X11.cursorImageCreate = (XcursorImageCreateFn)dlsym( - s_X11.libCursor, - "XcursorImageCreate"); - - s_X11.cursorImageDestroy = (XcursorImageDestroyFn)dlsym( - s_X11.libCursor, - "XcursorImageDestroy"); - - s_X11.lookupKeysym = (XLookupKeysymFn)dlsym( - s_X11.libCursor, - "XLookupKeysym"); - - s_X11.setDetectableAutoRepeat = (XkbSetDetectableAutoRepeatFn)dlsym( - s_X11.handle, - "XkbSetDetectableAutoRepeat"); - - s_X11.setLocaleModifiers = (XSetLocaleModifiersFn)dlsym( - s_X11.handle, - "XSetLocaleModifiers"); - - s_X11.openIM = (XOpenIMFn)dlsym( - s_X11.handle, - "XOpenIM"); - - s_X11.closeIM = (XCloseIMFn)dlsym( - s_X11.handle, - "XCloseIM"); - - s_X11.createIC = (XCreateICFn)dlsym( - s_X11.handle, - "XCreateIC"); - - s_X11.destroyIC = (XDestroyICFn)dlsym( - s_X11.handle, - "XDestroyIC"); - - s_X11.utf8LookupString = (Xutf8LookupStringFn)dlsym( - s_X11.handle, - "Xutf8LookupString"); - // clang-format on - - // X11 server - if (s_Video.platformInstance) { - s_X11.display = (Display*)s_Video.platformInstance; - - } else { - s_X11.display = s_X11.openDisplay(nullptr); - s_Video.platformInstance = nullptr; - } - - if (!s_X11.display) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - s_X11.root = DefaultRootWindow(s_X11.display); - s_X11.screen = DefaultScreen(s_X11.display); - - xCheckFeatures(); - - // subscribe for monitor events - s_X11.selectRRInput(s_X11.display, s_X11.root, RRScreenChangeNotifyMask | RRNotify); - - int eventBase, errorBase = 0; - s_X11.queryRRExtension(s_X11.display, &eventBase, &errorBase); - s_X11.rrEventBase = eventBase; - s_X11.skipScreenEvent = PAL_TRUE; - - s_X11.dataID = (XContext)s_X11.uniqueContext(); - resetMonitorData(); - - s_X11.monitorCount = 0; - xCacheMonitors(); - - // since X11 supports both EGL and GLX - // we try to load them and resolve the needed functions - - // we load GLX - s_X11.glxHandle = dlopen("libGL.so.1", RTLD_LAZY); - if (s_X11.glxHandle) { - GLXGetProcAddressFn load = nullptr; - load = (GLXGetProcAddressFn)dlsym(s_X11.glxHandle, "glXGetProcAddress"); - s_X11.glxGetFBConfigs = (GLXGetFBConfigsFn)load("glXGetFBConfigs"); - s_X11.glxGetFBConfigAttrib = (GLXGetFBConfigAttribFn)load("glXGetFBConfigAttrib"); - s_X11.glxGetVisualFromFBConfig = - (GLXGetVisualFromFBConfigFn)load("glXGetVisualFromFBConfig"); - } - - xCreateKeycodeTable(); - - // disable auto key repeats - int supported; - s_X11.setDetectableAutoRepeat(s_X11.display, True, &supported); - if (!supported) { - // FIXME: fallback to manual key repeat detection - } - - // create an input method - s_X11.setLocaleModifiers(""); - s_X11.im = s_X11.openIM(s_X11.display, nullptr, nullptr, nullptr); - if (s_X11.im == None) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - s_Video.display = (void*)s_X11.display; - return PAL_RESULT_SUCCESS; -} - -static void xShutdownVideo() -{ - s_X11.closeIM(s_X11.im); - if (!s_Video.platformInstance) { - // opened by PAL - s_X11.closeDisplay(s_X11.display); - } - - dlclose(s_X11.handle); - dlclose(s_X11.xrandr); - dlclose(s_X11.libCursor); - - if (s_X11.glxHandle) { - dlclose(s_X11.glxHandle); - } - memset(&s_X11, 0, sizeof(X11)); - memset(&s_X11Atoms, 0, sizeof(X11Atoms)); -} - -PalResult xSetFBConfig( - const int index, - PalFBConfigBackend backend) -{ - if (backend == PAL_CONFIG_BACKEND_GLX) { - return glxBackend(index); - - } else if (backend == PAL_CONFIG_BACKEND_EGL || backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { - return eglXBackend(index); - - } else { - return PAL_RESULT_INVALID_FBCONFIG_BACKEND; - } -} - -static void xUpdateVideo() -{ - XEvent event; - PalDispatchMode mode = PAL_DISPATCH_NONE; - while (s_X11.pending(s_X11.display)) { - s_X11.nextEvent(s_X11.display, &event); - - Window xWin = event.xany.window; - PalWindow* window = TO_PAL_HANDLE(PalWindow, xWin); - WindowData* data = nullptr; - s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&data); - - if (event.type == s_X11.rrEventBase + RRScreenChangeNotify) { - event.type = RANDR_SCREEN_CHANGE_EVENT; // for switch flow - } - - switch (event.type) { - case ClientMessage: { - // check for window close - Atom windowClose = event.xclient.data.l[0]; - if (windowClose == s_X11Atoms.WM_DELETE_WINDOW) { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_CLOSE; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - } - break; - } - - case ConfigureNotify: { - // window resize or move - - // skip the first configure event - if (data->skipConfigure) { - data->skipConfigure = PAL_FALSE; - data->w = event.xconfigure.width; - data->h = event.xconfigure.height; - data->x = event.xconfigure.x; - data->y = event.xconfigure.y; - break; - } - - // real configure event - if (s_Video.eventDriver) { - // check if its a resize event - if (data->w != event.xconfigure.width || data->h != event.xconfigure.height) { - data->w = event.xconfigure.width; - data->h = event.xconfigure.height; - - // push a resize event - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_SIZE; - mode = palGetEventDispatchMode(driver, type); - - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(data->w, data->h); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - - // attach windows sometimes bypass - // skipConfgure an still send an initial move event - if (data->isAttached) { - if (data->skipIfAttached) { - data->skipIfAttached = PAL_FALSE; - break; - } - } - - // check if its a move event - if (data->x != event.xconfigure.x || data->y != event.xconfigure.y) { - data->x = event.xconfigure.x; - data->y = event.xconfigure.y; - - // push a move event - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_MOVE; - mode = palGetEventDispatchMode(driver, type); - - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackInt32(data->x, data->y); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - - /** a window has to be moved - before its can change monitors - we get the monitor the moved - window is on and check if the dpi is different - from the one it was created on */ - int monitorDPI = xGetWindowMonitorDPI(data); - if (monitorDPI != data->dpi) { - // window is on a different monitor - data->dpi = monitorDPI; - - // push a DPI event - type = PAL_EVENT_MONITOR_DPI_CHANGED; - mode = palGetEventDispatchMode(driver, type); - - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = monitorDPI; - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - } - } - break; - } - - case FocusIn: { - // window has gained focus - if (s_Video.eventDriver) { - int mode = event.xfocus.mode; - if (mode == NotifyGrab || mode == NotifyUngrab) { - // ignore dragging and popup focus events - break; - } - - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_FOCUS; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = PAL_TRUE; - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - break; - } - - case FocusOut: { - // window has lost focus - if (s_Video.eventDriver) { - int mode = event.xfocus.mode; - if (mode == NotifyGrab || mode == NotifyUngrab) { - // ignore dragging and popup focus events - break; - } - - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_FOCUS; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = PAL_FALSE; - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - break; - } - - case PropertyNotify: { - // check window state (maximize, minimize) - if (event.xproperty.atom == s_X11Atoms._NET_WM_STATE) { - PalWindowState state; - state = xQueryWindowState(event.xproperty.window); - if (state != data->state) { - data->state = state; - - // skip the first state event - if (data->skipState) { - data->skipState = PAL_FALSE; - break; - } - - // push event - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_STATE; - mode = palGetEventDispatchMode(driver, type); - - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = data->state; - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - } - break; - } - - case RANDR_SCREEN_CHANGE_EVENT: { - // skip the first event - if (s_X11.skipScreenEvent) { - s_X11.skipScreenEvent = PAL_FALSE; - break; - } - - // store old monitor count - int oldCount = s_X11.monitorCount; - s_X11.monitorCount = 0; - xCacheMonitors(); - - if (oldCount != s_X11.monitorCount) { - // a monitor has been added or removed - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MONITOR_LIST_CHANGED; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - } - break; - } - - case MotionNotify: { - // mouse moved - const int x = event.xmotion.x; - const int y = event.xmotion.y; - const int dx = x - s_Mouse.lastX; - const int dy = y - s_Mouse.lastY; - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MOUSE_MOVE; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackInt32(x, y); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - - // push a mouse delta event - type = PAL_EVENT_MOUSE_DELTA; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackInt32(dx, dy); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - - s_Mouse.lastX = x; - s_Mouse.lastY = y; - s_Mouse.dx = dx; - s_Mouse.dy = dy; - break; - } - - case ButtonPress: - case ButtonRelease: { - int xButton = event.xbutton.button; - PalBool pressed = (event.xbutton.type == ButtonPress); - PalMouseButton button = 0; - PalEventType type; - - if (xButton == 1) { - button = PAL_MOUSE_BUTTON_LEFT; - } else if (xButton == 3) { - button = PAL_MOUSE_BUTTON_RIGHT; - } else if (xButton == 2) { - button = PAL_MOUSE_BUTTON_MIDDLE; - } - - s_Mouse.state[button] = pressed; - if (s_Video.eventDriver && button != 0) { - PalEventDriver* driver = s_Video.eventDriver; - if (pressed) { - type = PAL_EVENT_MOUSE_BUTTONDOWN; - } else { - type = PAL_EVENT_MOUSE_BUTTONUP; - } - - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(button, NULL_BUTTON_SERIAL); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - - int scrollX = 0; - int scrollY = 0; - if (xButton == 4) { - // scroll up - scrollY = 1; - } else if (xButton == 5) { - // scroll down - scrollY = -1; - } else if (xButton == 6) { - // scroll left - scrollX = -1; - } else if (xButton == 7) { - // scroll right - scrollX = 1; - } - - s_Mouse.WheelX = scrollX; - s_Mouse.WheelY = scrollY; - if (s_Video.eventDriver && (scrollX || scrollY)) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_WHEEL); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = PAL_EVENT_MOUSE_WHEEL; - event.data = palPackInt32(scrollX, scrollY); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - break; - } - - case KeyPress: - case KeyRelease: { - int xScancode = event.xkey.keycode; - PalBool pressed = (event.xbutton.type == KeyPress); - PalScancode scancode = PAL_SCANCODE_UNKNOWN; - PalKeycode keycode = PAL_KEYCODE_UNKNOWN; - PalEventType type; - KeySym keySym = s_X11.lookupKeysym(&event.xkey, 0); - - // special handling for Pause/break with Home - if (xScancode == 110) { - if (keySym == XK_Pause) { - scancode = PAL_SCANCODE_PAUSE; - } else { - scancode = PAL_SCANCODE_HOME; - } - - } else { - int index = xScancode - 8; - scancode = s_Keyboard.scancodes[index]; - } - - // printable and text input keys are from the range - // 32 (PAL_KEYCODE_SPACE) and 122 (PAL_KEYCODE_Z) - // The rest are almost the same as their scancode - // Maybe there will be a layout that makes this wrong - // but for now this works - if (keySym >= XK_space && keySym <= XK_z) { - // a printable or input key - keycode = s_Keyboard.keycodes[keySym]; - - } else { - // Since PalKeycode and PalScancode have the same integers - // we can make a direct cast without a table - // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) - keycode = (PalKeycode)(uint32_t)scancode; - } - - // If we got a keySym but its not mapped into our keycode array - // we do a direct cast as well - if (keycode == PAL_KEYCODE_UNKNOWN) { - keycode = (PalKeycode)(uint32_t)scancode; - } - - // update our keyboard and mouse state to handle key repeat - PalBool repeat = s_Keyboard.keycodeState[keycode]; - s_Keyboard.scancodeState[scancode] = pressed; - s_Keyboard.keycodeState[keycode] = pressed; - - if (pressed) { - if (repeat) { - type = PAL_EVENT_KEYREPEAT; - } else { - type = PAL_EVENT_KEYDOWN; - } - } else { - type = PAL_EVENT_KEYUP; - } - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(keycode, scancode); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - - // check for char event if enabled - type = PAL_EVENT_KEYCHAR; - mode = palGetEventDispatchMode(driver, type); - if (mode == PAL_DISPATCH_NONE) { - break; - } - - int status; - char buffer[32]; - KeySym keySym; - int len = s_X11.utf8LookupString( - data->ic, - &event.xkey, - buffer, - sizeof(buffer), - &keySym, - &status); - - uint32_t codepoint = 0; - if (status == XLookupChars || status == XLookupBoth) { - // decode to Unicode codepoint - unsigned char ch = buffer[0]; - if (ch < 0x80) { - // 1 byte (A-Z) - codepoint = ch; - - } else if ((ch >> 5) == 0x6 && len >= 2) { - // 2 byte - codepoint = ((ch & 0x1F) << 6) | buffer[1] & 0x3F; - - } else if ((ch >> 4) == 0xE && len >= 3) { - // 3 byte - // clang-format off - codepoint = ((ch & 0x0F) << 12) | - ((buffer[1] & 0x3F) << 6) | - (buffer[2] & 0x3F); - // clang-format on - - } else if ((ch >> 3) == 0x1E && len >= 4) { - // 4 byte - // clang-format off - codepoint = ((ch & 0x07) << 18) | - ((buffer[1] & 0x3F) << 12) | - ((buffer[2] & 0x3F) << 6) | - (buffer[3] & 0x3F); - // clang-format on - } - - PalEvent event = {0}; - event.type = type; - event.data = codepoint; - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - break; - } - } - } - - s_X11.flush(s_X11.display); -} - -static PalResult xEnumerateMonitors( - int32_t* count, - PalMonitor** outMonitors) -{ - int _count = 0; - int maxCount = outMonitors ? *count : 0; - XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - for (int i = 0; i < resources->noutput; ++i) { - RROutput output = resources->outputs[i]; - XRROutputInfo* outputInfo = s_X11.getOutputInfo(s_X11.display, resources, output); - if (outputInfo->connection == RR_Connected && outputInfo->crtc != None) { - // a monitor - if (outMonitors) { - if (_count < maxCount) { - outMonitors[_count] = TO_PAL_HANDLE(PalMonitor, output); - } - } - _count++; - } - } - - if (!outMonitors) { - *count = _count; - } - return PAL_RESULT_SUCCESS; -} - -static PalResult xGetPrimaryMonitor(PalMonitor** outMonitor) -{ - RROutput primary = s_X11.getOutputPrimary(s_X11.display, s_X11.root); - if (primary) { - *outMonitor = TO_PAL_HANDLE(PalMonitor, primary); - return PAL_RESULT_SUCCESS; - } - - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; -} - -static PalResult xGetMonitorInfo( - PalMonitor* monitor, - PalMonitorInfo* info) -{ - XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); - - if (!outputInfo) { - // invalid monitor - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR; - } - - if (outputInfo->connection != RR_Connected) { - // invalid monitor - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR; - } - - strcpy(info->name, outputInfo->name); - - // check if its primary monitor - RROutput primary = s_X11.getOutputPrimary(s_X11.display, s_X11.root); - - if (monitor == TO_PAL_HANDLE(PalMonitor, primary)) { - info->primary = PAL_TRUE; - } else { - info->primary = PAL_FALSE; - } - - // get monitor pos and size - XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - info->x = crtc->x; - info->y = crtc->y; - info->width = crtc->width; - info->height = crtc->height; - - // get refresh rate - double rate = 0; - for (int i = 0; i < resources->nmode; ++i) { - // check for our monitor - if (resources->modes[i].id == crtc->mode) { - XRRModeInfo* mode = &resources->modes[i]; - double tmp = (double)mode->hTotal * (double)mode->vTotal; - rate = (double)mode->dotClock / tmp; - info->refreshRate = rate + 0.5; - break; - } - } - - // orientation - switch (crtc->rotation) { - case RR_Rotate_0: { - info->orientation = PAL_ORIENTATION_LANDSCAPE; - break; - } - - case RR_Rotate_90: { - info->orientation = PAL_ORIENTATION_PORTRAIT; - break; - } - - case RR_Rotate_180: { - info->orientation = PAL_ORIENTATION_LANDSCAPE_FLIPPED; - break; - } - - case RR_Rotate_270: { - info->orientation = PAL_ORIENTATION_PORTRAIT_FLIPPED; - break; - } - - default: { - info->orientation = PAL_ORIENTATION_LANDSCAPE; - } - } - - // get dpi - float raw = crtc->width / 1920.0f; - float steps[] = {1.0f, 1.2f, 1.5f, 1.75, 2.0f}; - float closest = steps[0]; - float minDiff = fabsf(raw - steps[0]); - - for (int i = 1; i < sizeof(steps) / sizeof(steps[0]); i++) { - float diff = fabsf(raw - steps[i]); - if (diff < minDiff) { - minDiff = diff; - closest = steps[i]; - } - } - - info->dpi = (uint32_t)(closest * 96.0f); - - s_X11.freeCrtcInfo(crtc); - s_X11.freeOutputInfo(outputInfo); - s_X11.freeScreenResources(resources); - - return PAL_RESULT_SUCCESS; -} - -static PalResult xEnumerateMonitorModes( - PalMonitor* monitor, - int32_t* count, - PalMonitorMode* modes) -{ - int32_t modeCount = 0; - int maxModeCount = modes ? *count : 0; - XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - - // get the monitor info - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); - - if (!outputInfo) { - // invalid monitor - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR; - } - - if (outputInfo->connection != RR_Connected) { - // invalid monitor - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR; - } - - // get supported display modes - for (int i = 0; i < outputInfo->nmode; ++i) { - for (int j = 0; j < resources->nmode; ++j) { - // get the display mode and check if its for our monitor - XRRModeInfo* info = &resources->modes[j]; - if (info->id == outputInfo->modes[i]) { - // check if user supplied a PalMonitorMode array - if (modes) { - if (modeCount < maxModeCount) { - PalMonitorMode* mode = &modes[modeCount]; - mode->width = info->width; - mode->height = info->height; - mode->bpp = s_X11.bpp; - - double tmp = (double)info->hTotal * (double)info->vTotal; - double rate = (double)info->dotClock / tmp; - mode->refreshRate = rate + 0.5; - } - } - modeCount++; - } - } - } - - if (!modes) { - *count = modeCount; - } - - s_X11.freeOutputInfo(outputInfo); - s_X11.freeScreenResources(resources); - - return PAL_RESULT_SUCCESS; -} - -static PalResult xGetCurrentMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - - // get the monitor info - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); - - if (!outputInfo) { - // invalid monitor - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR; - } - - if (outputInfo->connection != RR_Connected) { - // invalid monitor - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR; - } - - // get the current display mode - XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - - // find the display mode - XRRModeInfo* info = nullptr; - for (int i = 0; i < resources->nmode; ++i) { - if (resources->modes[i].id == crtc->mode) { - // found - info = &resources->modes[i]; - break; - } - } - - if (mode) { - mode->width = info->width; - mode->height = info->height; - mode->bpp = s_X11.bpp; - - double tmp = (double)info->hTotal * (double)info->vTotal; - double rate = (double)info->dotClock / tmp; - mode->refreshRate = rate + 0.5; - } - - s_X11.freeCrtcInfo(crtc); - s_X11.freeOutputInfo(outputInfo); - s_X11.freeScreenResources(resources); - - return PAL_RESULT_SUCCESS; -} - -static PalResult xSetMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - - // get the monitor info - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); - - if (!outputInfo) { - // invalid monitor - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR; - } - - if (outputInfo->connection != RR_Connected) { - // invalid monitor - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR; - } - - // find the monitor display mode - RRMode displayMode = xFindMode(resources, mode); - if (displayMode == None) { - s_X11.freeOutputInfo(outputInfo); - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR_MODE; - } - - // apply the display mode - XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - - RROutput output = FROM_PAL_HANDLE(RROutput, monitor); - int ret = s_X11.setCrtcConfig( - s_X11.display, - resources, - outputInfo->crtc, - CurrentTime, - crtc->x, - crtc->y, - displayMode, - crtc->rotation, - &output, - 1); - - s_X11.freeCrtcInfo(crtc); - s_X11.freeOutputInfo(outputInfo); - s_X11.freeScreenResources(resources); - - if (ret != Success) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - return PAL_RESULT_SUCCESS; -} - -static PalResult xValidateMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -static PalResult xSetMonitorOrientation( - PalMonitor* monitor, - PalOrientation orientation) -{ - XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - - // get the monitor info - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); - - if (!outputInfo) { - // invalid monitor - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR; - } - - if (outputInfo->connection != RR_Connected) { - // invalid monitor - s_X11.freeScreenResources(resources); - return PAL_RESULT_INVALID_MONITOR; - } - - // get the current display mode - XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - - // check if the new orientation is supported - Rotation rotation = 0; - switch (orientation) { - case PAL_ORIENTATION_LANDSCAPE: { - rotation = RR_Rotate_0; - break; - } - - case PAL_ORIENTATION_PORTRAIT: { - rotation = RR_Rotate_90; - break; - } - - case PAL_ORIENTATION_LANDSCAPE_FLIPPED: { - rotation = RR_Rotate_180; - break; - } - - case PAL_ORIENTATION_PORTRAIT_FLIPPED: { - rotation = RR_Rotate_270; - break; - } - - default: { - return PAL_RESULT_INVALID_ORIENTATION; - } - } - - if (!(crtc->rotations & rotation)) { - return PAL_RESULT_INVALID_ORIENTATION; - } - - RROutput output = FROM_PAL_HANDLE(RROutput, monitor); - int ret = s_X11.setCrtcConfig( - s_X11.display, - resources, - outputInfo->crtc, - CurrentTime, - crtc->x, - crtc->y, - crtc->mode, - rotation, - &output, - 1); - - s_X11.freeCrtcInfo(crtc); - s_X11.freeOutputInfo(outputInfo); - s_X11.freeScreenResources(resources); - - if (ret != Success) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - return PAL_RESULT_SUCCESS; -} - -static PalResult xCreateWindow( - const PalWindowCreateInfo* info, - PalWindow** outWindow) -{ - Window window = None; - PalMonitor* monitor = nullptr; - PalMonitorInfo monitorInfo; - - WindowData* data = getFreeWindowData(); - if (!data) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - Visual* visual = nullptr; - int depth = 0; - Colormap colormap = None; - unsigned long bgPixel = 0; - unsigned long borderPixel = 0; - - if (s_X11.visualInfo) { - visual = s_X11.visualInfo->visual; - depth = s_X11.visualInfo->depth; - bgPixel = 0; - borderPixel = 0; - colormap = s_X11.createColormap(s_X11.display, s_X11.root, visual, AllocNone); - - if (!colormap) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - data->colormap = colormap; - - } else { - // use a default visual - visual = DefaultVisual(s_X11.display, s_X11.screen); - depth = DefaultDepth(s_X11.display, s_X11.screen); - bgPixel = WhitePixel(s_X11.display, s_X11.screen); - borderPixel = BlackPixel(s_X11.display, s_X11.screen); - colormap = DefaultColormap(s_X11.display, s_X11.screen); - data->colormap = None; - } - - // get monitor - int monitorX = 0; - int monitorY = 0; - uint32_t monitorW = 0; - uint32_t monitorH = 0; - int dpi = 0; - if (info->monitor) { - monitor = info->monitor; - - } else { - // get primary monitor - xGetPrimaryMonitor(&monitor); - } - - if (monitor) { - // get monitor info - PalResult result = palGetMonitorInfo(monitor, &monitorInfo); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - - monitorX = monitorInfo.x; - monitorY = monitorInfo.y; - monitorW = monitorInfo.width; - monitorH = monitorInfo.height; - dpi = monitorInfo.dpi; - - } else { - // primary monitor is not set - XRRScreenResources* resources = nullptr; - resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - for (int i = 0; i < resources->noutput; ++i) { - RROutput output = resources->outputs[i]; - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); - - // check if its a monitor - if (outputInfo->connection != RR_Connected || outputInfo->crtc == None) { - s_X11.freeOutputInfo(outputInfo); - continue; - } - - XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - - monitorX = crtc->x; - monitorY = crtc->y; - monitorW = crtc->width; - monitorH = crtc->height; - - // get DPI - float raw = crtc->width / 1920.0f; - float steps[] = {1.0f, 1.2f, 1.5f, 1.75, 2.0f}; - float closest = steps[0]; - float minDiff = fabsf(raw - steps[0]); - - for (int i = 1; i < sizeof(steps) / sizeof(steps[0]); i++) { - float diff = fabsf(raw - steps[i]); - if (diff < minDiff) { - minDiff = diff; - closest = steps[i]; - } - } - - dpi = (uint32_t)(closest * 96.0f); - - s_X11.freeCrtcInfo(crtc); - s_X11.freeOutputInfo(outputInfo); - break; - } - s_X11.freeScreenResources(resources); - } - - int32_t x, y = 0; - // the position and size must be scaled with the dpi before this call - if (info->center) { - x = monitorX + (monitorW - info->width) / 2; - y = monitorY + (monitorH - info->height) / 2; - - } else { - // we set 100 for each axix - x = monitorX + 100; - y = monitorY + 100; - } - - // check and set transparency - if (info->style & PAL_WINDOW_STYLE_TRANSPARENT) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW)) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - // we dont need to set any flag - } - - long mask = StructureNotifyMask | KeyPressMask; - mask |= KeyReleaseMask; - mask |= ButtonPressMask; - mask |= ButtonReleaseMask; - mask |= PointerMotionMask; - mask |= FocusChangeMask; - mask |= PropertyChangeMask; - - XSetWindowAttributes attrs = {0}; - attrs.colormap = colormap; - attrs.event_mask = mask; - attrs.background_pixel = bgPixel; - attrs.border_pixel = borderPixel; - attrs.override_redirect = False; - - // create window - window = s_X11.createWindow( - s_X11.display, - s_X11.root, - x, - y, - info->width, - info->height, - 0, // border width - depth, - InputOutput, // class - visual, - CWEventMask | CWColormap | CWBorderPixel | CWBackPixel, - &attrs); - - if (window == None) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // set pid property - pid_t pid = getpid(); - s_X11.changeProperty( - s_X11.display, - window, - s_X11Atoms._NET_WM_PID, - XA_CARDINAL, - 32, - PropModeReplace, - (unsigned char*)&pid, - 1); - - // set class property - XClassHint* hints = s_X11.allocClassHint(); - if (hints) { - const char* resName = getenv("RESOURCE_NAME"); - const char* resClass = getenv("RESOURCE_CLASS"); - - if (!resName || strlen(resName) == 0) { - resName = info->title; - } - - if (!resClass || strlen(resClass) == 0) { - resClass = s_Video.className; - } - - hints->res_name = (char*)resName; - hints->res_class = (char*)resClass; - s_X11.setClassHint(s_X11.display, window, hints); - s_X11.free(hints); - } - - if (s_X11Atoms.unicodeTitle && info->title) { - s_X11.changeProperty( - s_X11.display, - window, - s_X11Atoms._NET_WM_NAME, - s_X11Atoms.UTF8_STRING, - 8, // unsigned char - PropModeReplace, - info->title, - strlen(info->title)); - - } else { - if (info->title) { - s_X11.storeName(s_X11.display, window, info->title); - } - } - - // borderless - if (info->style & PAL_WINDOW_STYLE_BORDERLESS) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_BORDERLESS_WINDOW)) { - s_X11.destroyWindow(s_X11.display, window); - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - s_X11.changeProperty( - s_X11.display, - window, - s_X11Atoms._NET_WM_WINDOW_TYPE, - XA_ATOM, - 32, - PropModeReplace, - (unsigned char*)&s_X11Atoms._NET_WM_WINDOW_TYPE_SPLASH, - 1); - } - - // tool window - if (info->style & PAL_WINDOW_STYLE_TOOL) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_TOOL_WINDOW)) { - s_X11.destroyWindow(s_X11.display, window); - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - s_X11.changeProperty( - s_X11.display, - window, - s_X11Atoms._NET_WM_WINDOW_TYPE, - XA_ATOM, - 32, - PropModeReplace, - (unsigned char*)&s_X11Atoms._NET_WM_WINDOW_TYPE_UTILITY, - 1); - } - - // topmost - if (info->style & PAL_WINDOW_STYLE_TOPMOST) { - if (s_X11Atoms._NET_WM_STATE_ABOVE) { - s_X11.changeProperty( - s_X11.display, - window, - s_X11Atoms._NET_WM_STATE, - XA_ATOM, - 32, - PropModeAppend, - (unsigned char*)&s_X11Atoms._NET_WM_STATE_ABOVE, - 1); - } - } - - // set size hints - XSizeHints wmHints = {0}; - wmHints.flags = PPosition | PSize; - wmHints.x = x; - wmHints.y = y; - wmHints.width = info->width; - wmHints.height = info->height; - - // resizable - if (!(info->style & PAL_WINDOW_STYLE_RESIZABLE)) { - wmHints.flags |= PMinSize; - wmHints.flags |= PMaxSize; - wmHints.min_width = wmHints.max_width = info->width; - wmHints.min_height = wmHints.max_height = info->height; - } - - // show window - s_X11.setWMNormalHints(s_X11.display, window, &wmHints); - if (info->show) { - s_X11.mapWindow(s_X11.display, window); - s_X11.flush(s_X11.display); - } - - // check if the window has been mapped - // we use this to minimize or maximize - XWindowAttributes attr; - s_X11.getWindowAttributes(s_X11.display, window, &attr); - PalBool windowMapped = attr.map_state = IsViewable; - - // maximize - if (info->maximized) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - s_X11.destroyWindow(s_X11.display, window); - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - // if the window is not mapped, we wait till its mapped - if (!windowMapped) { - // wait till the window is mapped - for (;;) { - XEvent event; - s_X11.nextEvent(s_X11.display, &event); - if (event.type == MapNotify && event.xmap.window == window) { - windowMapped = PAL_TRUE; - break; - } - } - } - - xSendWMEvent( - window, - s_X11Atoms._NET_WM_STATE, - s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT, - s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ, - 1, - 0, - PAL_TRUE); // _NET_WM_STATE_ADD - } - - // minimize - if (info->minimized) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - s_X11.destroyWindow(s_X11.display, window); - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - // if the window is not mapped, we wait till its mapped - if (!windowMapped) { - // wait till the window is mapped - for (;;) { - XEvent event; - s_X11.nextEvent(s_X11.display, &event); - if (event.type == MapNotify && event.xmap.window == window) { - windowMapped = PAL_TRUE; - break; - } - } - } - s_X11.iconifyWindow(s_X11.display, window, s_X11.screen); - } - - s_X11.setWMProtocols(s_X11.display, window, &s_X11Atoms.WM_DELETE_WINDOW, 1); - s_X11.flush(s_X11.display); - - // attach the window data to the window - data->skipConfigure = PAL_TRUE; - data->skipState = PAL_TRUE; - data->isAttached = PAL_FALSE; // PAL_TRUE for attached windows - data->dpi = dpi; // the current window monitor - data->window = TO_PAL_HANDLE(PalWindow, window); - s_X11.saveContext(s_X11.display, window, s_X11.dataID, (XPointer)data); - - // create an input context - data->ic = s_X11.createIC( - s_X11.im, - XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, - XNClientWindow, - window, - XNFocusWindow, - window, - nullptr); - - if (!data->ic) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - *outWindow = TO_PAL_HANDLE(PalWindow, window); - return PAL_RESULT_SUCCESS; -} - -static void xDestroyWindow(PalWindow* window) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - WindowData* data = nullptr; - s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&data); - - // PAL does not destroy an attached window - if (data->isAttached) { - return; - } - - s_X11.destroyIC(data->ic); - s_X11.destroyWindow(s_X11.display, xWin); - - if (data->colormap != None) { - s_X11.freeColormap(s_X11.display, data->colormap); - } - - data->used = PAL_FALSE; -} - -PalResult xMinimizeWindow(PalWindow* window) -{ - if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - s_X11.iconifyWindow(s_X11.display, xWin, s_X11.screen); - return PAL_RESULT_SUCCESS; -} - -PalResult xMaximizeWindow(PalWindow* window) -{ - if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - xSendWMEvent( - xWin, - s_X11Atoms._NET_WM_STATE, - s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT, - s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ, - 1, - 0, - PAL_TRUE); // _NET_WM_STATE_ADD - - return PAL_RESULT_SUCCESS; -} - -PalResult xRestoreWindow(PalWindow* window) -{ - if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - // since we have no fixed way to restore the window - // we just restore from minimized and maximized state - xSendWMEvent( - xWin, - s_X11Atoms._NET_WM_STATE, - s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT, - s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ, - 1, - 0, - PAL_FALSE); // _NET_WM_STATE_REMOVE - - s_X11.mapRaised(s_X11.display, xWin); - - return PAL_RESULT_SUCCESS; -} - -PalResult xShowWindow(PalWindow* window) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - s_X11.mapWindow(s_X11.display, xWin); - return PAL_RESULT_SUCCESS; -} - -PalResult xHideWindow(PalWindow* window) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - s_X11.unmapWindow(s_X11.display, xWin); - return PAL_RESULT_SUCCESS; -} - -PalResult xFlashWindow( - PalWindow* window, - const PalFlashInfo* info) -{ - if (info->flags & PAL_FLASH_CAPTION) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - PalBool add = PAL_FALSE; - if (info->flags & PAL_FLASH_TRAY) { - add = PAL_TRUE; - } - - // check if modern flashing is supported - if (s_X11Atoms._NET_WM_STATE_DEMANDS_ATTENTIONS) { - xSendWMEvent( - xWin, - s_X11Atoms._NET_WM_STATE, - s_X11Atoms._NET_WM_STATE_DEMANDS_ATTENTIONS, - 0, - 0, - 0, - add); // _NET_WM_STATE_ADD - - } else { - // legacy mode - XWMHints* hints = s_X11.getWMHints(s_X11.display, xWin); - if (!hints) { - hints = s_X11.allocWMHints(); - if (!hints) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (add) { - hints->flags |= XUrgencyHint; - } else { - hints->flags &= ~XUrgencyHint; - } - s_X11.setWMHints(s_X11.display, xWin, hints); - s_X11.free(hints); - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult xGetWindowStyle( - PalWindow* window, - PalWindowStyle* outStyle) -{ - // Window Manager quirks - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult xGetWindowMonitor( - PalWindow* window, - PalMonitor** outMonitor) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult xGetWindowTitle( - PalWindow* window, - uint64_t bufferSize, - uint64_t* outSize, - char* outBuffer) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (!outBuffer || bufferSize <= 0) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - if (s_X11Atoms.unicodeTitle) { - Atom type; - int format; - unsigned long count, bytesAfter; - unsigned char* prop = nullptr; - s_X11.getWindowProperty( - s_X11.display, - xWin, - s_X11Atoms._NET_WM_NAME, - 0, - (~0L), - False, - s_X11Atoms.UTF8_STRING, - &type, - &format, - &count, - &bytesAfter, - &prop); - - if (bufferSize >= count) { - strcpy(outBuffer, (const char*)prop); - } else { - // copy up to the limiit of the supplied buffer - strncpy(outBuffer, (const char*)prop, bufferSize); - } - s_X11.free(prop); - - } else { - XTextProperty text; - if (!s_X11.getWMName(s_X11.display, xWin, &text)) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (bufferSize >= text.nitems) { - strcpy(outBuffer, (const char*)text.value); - } else { - // copy up to the limiit of the supplied buffer - strncpy(outBuffer, (const char*)text.value, bufferSize); - } - s_X11.free(text.value); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult xGetWindowPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (x) { - *x = attr.x; - } - - if (y) { - *y = attr.y; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult xGetWindowSize( - PalWindow* window, - uint32_t* width, - uint32_t* height) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (width) { - *width = attr.width; - } - - if (height) { - *height = attr.height; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult xGetWindowState( - PalWindow* window, - PalWindowState* outState) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - Atom type; - int format; - unsigned long count, bytesAfter; - unsigned char* props = nullptr; - s_X11.getWindowProperty( - s_X11.display, - xWin, - s_X11Atoms._NET_WM_STATE, - 0, - (~0L), - False, - XA_ATOM, - &type, - &format, - &count, - &bytesAfter, - &props); - - PalWindowState state = PAL_WINDOW_STATE_RESTORED; - for (unsigned long i = 0; i < count; ++i) { - if (props[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_HORZ) { - state = PAL_WINDOW_STATE_MAXIMIZED; - } - - if (props[i] == s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT) { - state = PAL_WINDOW_STATE_MAXIMIZED; - } - - if (props[i] == s_X11Atoms._NET_WM_STATE_HIDDEN) { - state = PAL_WINDOW_STATE_MINIMIZED; - } - } - - s_X11.free(props); - *outState = state; - return PAL_RESULT_SUCCESS; -} - -PalBool xIsWindowVisible(PalWindow* window) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_FALSE; - } - - return attr.map_state == IsViewable; -} - -PalWindow* xGetFocusWindow() -{ - Window window; - int tmp; - s_X11.getInputFocus(s_X11.display, &window, &tmp); - Window xWin = FROM_PAL_HANDLE(Window, window); - - if (xWin == s_X11.root) { - return nullptr; - } - return TO_PAL_HANDLE(PalWindow, window); -} - -PalWindowHandleInfo xGetWindowHandleInfo(PalWindow* window) -{ - PalWindowHandleInfo info; - info.nativeDisplay = (void*)s_X11.display; - info.nativeWindow = (void*)window; - return info; -} - -PalWindowHandleInfoEx xGetWindowHandleInfoEx(PalWindow* w) -{ - PalWindowHandleInfoEx info = {0}; - info.nativeDisplay = (void*)s_X11.display; - info.nativeWindow = (void*)w; - return info; -} - -static PalResult xSetWindowOpacity( - PalWindow* window, - float opacity) -{ - XErrorHandler old = s_X11.setErrorHandler(xErrorHandler); - unsigned long value = (unsigned long)(opacity * 0xFFFFFFFFUL + 0.5f); - - s_X11.changeProperty( - s_X11.display, - FROM_PAL_HANDLE(Window, window), - s_X11Atoms._NET_WM_WINDOW_OPACITY, - XA_CARDINAL, - 32, - PropModeReplace, - (unsigned char*)&value, - 1); - - s_X11.sync(s_X11.display, False); - s_X11.setErrorHandler(old); - if (s_X11.error) { - // technically, this is the only error that can occur - return PAL_RESULT_INVALID_WINDOW; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult xSetWindowStyle( - PalWindow* window, - PalWindowStyle style) -{ - // Window Manager quirks - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult xSetWindowTitle( - PalWindow* window, - const char* title) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (s_X11Atoms.unicodeTitle) { - s_X11.changeProperty( - s_X11.display, - xWin, - s_X11Atoms._NET_WM_NAME, - s_X11Atoms.UTF8_STRING, - 8, // unsigned char - PropModeReplace, - title, - strlen(title)); - - } else { - s_X11.storeName(s_X11.display, xWin, title); - } - - s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; -} - -PalResult xSetWindowPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - s_X11.moveWindow(s_X11.display, xWin, x, y); - s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; -} - -PalResult xSetWindowSize( - PalWindow* window, - uint32_t width, - uint32_t height) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - // X11 does not allow users resize programaticaly - // if the window is not resizable. - // so we hack it by making the window resizable and resizing - // then revert back. - XSizeHints hints; - long tmp; - s_X11.getWMNormalHints(s_X11.display, xWin, &hints, &tmp); - if ((hints.flags & PMinSize) && (hints.flags & PMaxSize)) { - hints.flags &= ~PMinSize; - hints.flags &= ~PMaxSize; - s_X11.resizeWindow(s_X11.display, xWin, width, height); - s_X11.flush(s_X11.display); - - // revert - hints.flags |= PMinSize; - hints.flags |= PMaxSize; - hints.min_width = hints.max_width = width; - hints.min_height = hints.max_height = height; - - } else { - // window is already resizable - s_X11.resizeWindow(s_X11.display, xWin, width, height); - } - - s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; -} - -PalResult xSetFocusWindow(PalWindow* window) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (s_X11Atoms._NET_ACTIVE_WINDOW) { - xSendWMEvent(xWin, s_X11Atoms._NET_ACTIVE_WINDOW, CurrentTime, 0, 0, 0, - PAL_TRUE); // 1 - - } else { - s_X11.setInputFocus(s_X11.display, xWin, RevertToParent, CurrentTime); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult xCreateIcon( - const PalIconCreateInfo* info, - PalIcon** outIcon) -{ - uint64_t totalPixels = 2 + (uint64_t)(info->width * info->height); - uint64_t totalBytes = sizeof(unsigned long) * totalPixels; - - unsigned long* icon = palAllocate(s_Video.allocator, totalBytes, 0); - if (!icon) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // store width and height and populate data with icon pixels - // [width][height][pixels] - icon[0] = (unsigned long)info->width; - icon[1] = (unsigned long)info->height; - - // convert from RGBA8 to ARGB32 - for (int i = 0; i < info->width * info->height; i++) { - uint8_t r = info->pixels[i * 4 + 0]; // Red - uint8_t g = info->pixels[i * 4 + 1]; // Green - uint8_t b = info->pixels[i * 4 + 2]; // Blue - uint8_t a = info->pixels[i * 4 + 3]; // Alpha - - // clang-format off - icon[2 + i] = ((unsigned long)a << 24) | - ((unsigned long)r << 16) | - ((unsigned long)g << 8) | - ((unsigned long)b); - // clang-format on - } - - *outIcon = TO_PAL_HANDLE(PalIcon, icon); - return PAL_RESULT_SUCCESS; -} - -void xDestroyIcon(PalIcon* icon) -{ - if (icon) { - palFree(s_Video.allocator, icon); - } -} - -PalResult xSetWindowIcon( - PalWindow* window, - PalIcon* icon) -{ - WindowData* winData = nullptr; - Window xWin = FROM_PAL_HANDLE(Window, window); - s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&winData); - if (!winData) { - return PAL_RESULT_INVALID_WINDOW; - } - - unsigned long* iconData = FROM_PAL_HANDLE(unsigned long*, icon); - uint64_t totalPixels = 2 + iconData[0] * iconData[1]; - s_X11.changeProperty( - s_X11.display, - xWin, - s_X11Atoms._NET_WM_ICON, - XA_CARDINAL, - 32, - PropModeReplace, - (unsigned char*)iconData, - (int)totalPixels); - - s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; -} - -PalResult xCreateCursor( - const PalCursorCreateInfo* info, - PalCursor** outCursor) -{ - XcursorImage* image = s_X11.cursorImageCreate(info->width, info->height); - image->xhot = info->xHotspot; - image->yhot = info->yHotspot; - - // convert from RGBA8 to ARGB32 - for (int i = 0; i < info->width * info->height; i++) { - uint8_t r = info->pixels[i * 4 + 0]; // Red - uint8_t g = info->pixels[i * 4 + 1]; // Green - uint8_t b = info->pixels[i * 4 + 2]; // Blue - uint8_t a = info->pixels[i * 4 + 3]; // Alpha - - // clang-format off - image->pixels[i] = ((unsigned long)a << 24) | - ((unsigned long)r << 16) | - ((unsigned long)g << 8) | - ((unsigned long)b); - // clang-format on - } - - Cursor cursor = s_X11.cursorImageLoadCursor(s_X11.display, image); - if (!cursor) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - s_X11.cursorImageDestroy(image); - *outCursor = TO_PAL_HANDLE(PalCursor, cursor); - return PAL_RESULT_SUCCESS; -} - -PalResult xCreateCursorFrom( - PalCursorType type, - PalCursor** outCursor) -{ - int shape; - Cursor cursor; - switch (type) { - case PAL_CURSOR_ARROW: { - shape = XC_left_ptr; - break; - } - - case PAL_CURSOR_HAND: { - shape = XC_hand2; - break; - } - - case PAL_CURSOR_CROSS: { - shape = XC_cross; - break; - } - - case PAL_CURSOR_IBEAM: { - shape = XC_xterm; - break; - } - - case PAL_CURSOR_WAIT: { - shape = XC_watch; - break; - } - - default: { - return PAL_RESULT_INVALID_ARGUMENT; - } - } - - cursor = s_X11.createFontCursor(s_X11.display, shape); - *outCursor = TO_PAL_HANDLE(PalCursor, cursor); - return PAL_RESULT_SUCCESS; -} - -void xDestroyCursor(PalCursor* cursor) -{ - s_X11.freeCursor(s_X11.display, FROM_PAL_HANDLE(Cursor, cursor)); -} - -void xShowCursor(PalBool show) -{ - // x11 does not support Hiding and showing cursor - return; -} - -PalResult xClipCursor( - PalWindow* window, - PalBool clip) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (clip) { - s_X11.grabPointer( - s_X11.display, - xWin, - True, - 0, - GrabModeAsync, - GrabModeAsync, - xWin, - None, - CurrentTime); - - } else { - s_X11.ungrabPointer(s_X11.display, CurrentTime); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult xGetCursorPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - Window root, rootChild; - int rootX, rootY, winX, winY; - unsigned int mask; - s_X11.queryPointer(s_X11.display, xWin, &root, &rootChild, &rootX, &rootY, &winX, &winY, &mask); - - if (x) { - *x = winX; - } - - if (y) { - *y = winY; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult xSetCursorPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - s_X11.warpPointer(s_X11.display, None, xWin, 0, 0, 0, 0, x, y); - - s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; -} - -PalResult xSetWindowCursor( - PalWindow* window, - PalCursor* cursor) -{ - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - Window xCursor = FROM_PAL_HANDLE(Cursor, cursor); - if (xCursor) { - s_X11.defineCursor(s_X11.display, xWin, xCursor); - - } else { - s_X11.undefineCursor(s_X11.display, xWin); - } - - s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; -} - -PalResult xAttachWindow( - void* windowHandle, - PalWindow** outWindow) -{ - Window xWin = FROM_PAL_HANDLE(Window, windowHandle); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_INVALID_WINDOW; - } - - // get a free slot and set the window handle to it - // we also set a flag to make sure we know this is an attached window - WindowData* data = getFreeWindowData(); - if (!data) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - PalWindow* window = TO_PAL_HANDLE(PalWindow, xWin); - // we assume the window was just created, since there is - // no official way to get the DPI - data->isAttached = PAL_TRUE; - data->dpi = 96; // if this is not the DPI, a dpi event will be triggered - - // If the window manager has not mapped the window yet, - // we dont need the initial Size / Move events - data->skipConfigure = PAL_TRUE; - data->skipState = PAL_TRUE; - data->skipIfAttached = PAL_TRUE; - data->window = window; - data->w = attr.width; - data->h = attr.height; - data->x = attr.x; - data->y = attr.y; - - // get the current window state - // we dont check the return code because we know the window is valid - xGetWindowState(window, &data->state); - - // listen to the events we support - long mask = StructureNotifyMask | KeyPressMask; - mask |= KeyReleaseMask; - mask |= ButtonPressMask; - mask |= ButtonReleaseMask; - mask |= PointerMotionMask; - mask |= FocusChangeMask; - mask |= PropertyChangeMask; - s_X11.selectInput(s_X11.display, xWin, mask); - - // listen to window close event - s_X11.setWMProtocols(s_X11.display, xWin, &s_X11Atoms.WM_DELETE_WINDOW, 1); - - s_X11.saveContext(s_X11.display, xWin, s_X11.dataID, (XPointer)data); - s_X11.flush(s_X11.display); - - *outWindow = window; - return PAL_RESULT_SUCCESS; -} - -PalResult xDetachWindow( - PalWindow* window, - void** outWindowHandle) -{ - // we check is the window is really detachable - Window xWin = FROM_PAL_HANDLE(Window, window); - WindowData* data = nullptr; - s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&data); - if (!data) { - return PAL_RESULT_INVALID_WINDOW; - } - - if (data->isAttached == PAL_FALSE) { - // window was created by PAL - return PAL_RESULT_INVALID_WINDOW; - } - - // detach the window - data->used = PAL_FALSE; - long mask = 0; - s_X11.selectInput(s_X11.display, xWin, mask); - s_X11.setWMProtocols(s_X11.display, xWin, nullptr, 0); - - if (outWindowHandle) { - *outWindowHandle = (void*)window; - } - - return PAL_RESULT_SUCCESS; -} - -static Backend s_XBackend = { - .shutdownVideo = xShutdownVideo, - .updateVideo = xUpdateVideo, - .setFBConfig = xSetFBConfig, - .enumerateMonitors = xEnumerateMonitors, - .getMonitorInfo = xGetMonitorInfo, - .getPrimaryMonitor = xGetPrimaryMonitor, - .enumerateMonitorModes = xEnumerateMonitorModes, - .getCurrentMonitorMode = xGetCurrentMonitorMode, - .setMonitorMode = xSetMonitorMode, - .validateMonitorMode = xValidateMonitorMode, - .setMonitorOrientation = xSetMonitorOrientation, - - .createWindow = xCreateWindow, - .destroyWindow = xDestroyWindow, - .maximizeWindow = xMaximizeWindow, - .minimizeWindow = xMinimizeWindow, - .restoreWindow = xRestoreWindow, - .showWindow = xShowWindow, - .hideWindow = xHideWindow, - .flashWindow = xFlashWindow, - .getWindowStyle = xGetWindowStyle, - .getWindowMonitor = xGetWindowMonitor, - .getWindowTitle = xGetWindowTitle, - .getWindowPos = xGetWindowPos, - .getWindowSize = xGetWindowSize, - .getWindowState = xGetWindowState, - .isWindowVisible = xIsWindowVisible, - .getFocusWindow = xGetFocusWindow, - .getWindowHandleInfo = xGetWindowHandleInfo, - .getWindowHandleInfoEx = xGetWindowHandleInfoEx, - .setWindowOpacity = xSetWindowOpacity, - .setWindowStyle = xSetWindowStyle, - .setWindowTitle = xSetWindowTitle, - .setWindowPos = xSetWindowPos, - .setWindowSize = xSetWindowSize, - .setFocusWindow = xSetFocusWindow, - - .createIcon = xCreateIcon, - .destroyIcon = xDestroyIcon, - .setWindowIcon = xSetWindowIcon, - - .createCursor = xCreateCursor, - .createCursorFrom = xCreateCursorFrom, - .destroyCursor = xDestroyCursor, - .showCursor = xShowCursor, - .clipCursor = xClipCursor, - .getCursorPos = xGetCursorPos, - .setCursorPos = xSetCursorPos, - .setWindowCursor = xSetWindowCursor, - - .attachWindow = xAttachWindow, - .detachWindow = xDetachWindow}; - -#endif // PAL_HAS_X11 -#pragma endregion - -// ================================================== -// Wayland API -// ================================================== - -#pragma region Wayland API -#if PAL_HAS_WAYLAND - -PalResult eglWlBackend(const int index) -{ - // user choose EGL FBConfig backend - if (!s_Egl.handle) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - EGLDisplay display = EGL_NO_DISPLAY; - display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_Wl.display); - - if (display == EGL_NO_DISPLAY) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - EGLint numConfigs = 0; - if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - EGLint configSize = sizeof(EGLConfig) * numConfigs; - EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); - if (!eglConfigs) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); - s_Wl.eglFBConfig = eglConfigs[index]; - - return PAL_RESULT_SUCCESS; -} - -static void wlCreateKeycodeTable() -{ - // Tis is for only printable and text input keys - - // Letters - s_Keyboard.keycodes[XKB_KEY_a] = PAL_KEYCODE_A; - s_Keyboard.keycodes[XKB_KEY_b] = PAL_KEYCODE_B; - s_Keyboard.keycodes[XKB_KEY_c] = PAL_KEYCODE_C; - s_Keyboard.keycodes[XKB_KEY_d] = PAL_KEYCODE_D; - s_Keyboard.keycodes[XKB_KEY_e] = PAL_KEYCODE_E; - s_Keyboard.keycodes[XKB_KEY_f] = PAL_KEYCODE_F; - s_Keyboard.keycodes[XKB_KEY_g] = PAL_KEYCODE_G; - s_Keyboard.keycodes[XKB_KEY_h] = PAL_KEYCODE_H; - s_Keyboard.keycodes[XKB_KEY_i] = PAL_KEYCODE_I; - s_Keyboard.keycodes[XKB_KEY_j] = PAL_KEYCODE_J; - s_Keyboard.keycodes[XKB_KEY_k] = PAL_KEYCODE_K; - s_Keyboard.keycodes[XKB_KEY_l] = PAL_KEYCODE_L; - s_Keyboard.keycodes[XKB_KEY_m] = PAL_KEYCODE_M; - s_Keyboard.keycodes[XKB_KEY_n] = PAL_KEYCODE_N; - s_Keyboard.keycodes[XKB_KEY_o] = PAL_KEYCODE_O; - s_Keyboard.keycodes[XKB_KEY_p] = PAL_KEYCODE_P; - s_Keyboard.keycodes[XKB_KEY_q] = PAL_KEYCODE_Q; - s_Keyboard.keycodes[XKB_KEY_r] = PAL_KEYCODE_R; - s_Keyboard.keycodes[XKB_KEY_s] = PAL_KEYCODE_S; - s_Keyboard.keycodes[XKB_KEY_t] = PAL_KEYCODE_T; - s_Keyboard.keycodes[XKB_KEY_u] = PAL_KEYCODE_U; - s_Keyboard.keycodes[XKB_KEY_v] = PAL_KEYCODE_V; - s_Keyboard.keycodes[XKB_KEY_w] = PAL_KEYCODE_W; - s_Keyboard.keycodes[XKB_KEY_x] = PAL_KEYCODE_X; - s_Keyboard.keycodes[XKB_KEY_y] = PAL_KEYCODE_Y; - s_Keyboard.keycodes[XKB_KEY_z] = PAL_KEYCODE_Z; - - // Control - s_Keyboard.keycodes[XKB_KEY_space] = PAL_KEYCODE_SPACE; - - // Misc - s_Keyboard.keycodes[XKB_KEY_apostrophe] = PAL_KEYCODE_APOSTROPHE; - s_Keyboard.keycodes[XKB_KEY_backslash] = PAL_KEYCODE_BACKSLASH; - s_Keyboard.keycodes[XKB_KEY_comma] = PAL_KEYCODE_COMMA; - s_Keyboard.keycodes[XKB_KEY_equal] = PAL_KEYCODE_EQUAL; - s_Keyboard.keycodes[XKB_KEY_grave] = PAL_KEYCODE_GRAVEACCENT; - s_Keyboard.keycodes[XKB_KEY_minus] = PAL_KEYCODE_SUBTRACT; - s_Keyboard.keycodes[XKB_KEY_period] = PAL_KEYCODE_PERIOD; - s_Keyboard.keycodes[XKB_KEY_semicolon] = PAL_KEYCODE_SEMICOLON; - s_Keyboard.keycodes[XKB_KEY_slash] = PAL_KEYCODE_SLASH; - s_Keyboard.keycodes[XKB_KEY_bracketleft] = PAL_KEYCODE_LBRACKET; - s_Keyboard.keycodes[XKB_KEY_bracketright] = PAL_KEYCODE_RBRACKET; -} - -static int createShmFile(uint64_t size) -{ - char template[] = "/tmp/pal-shm-XXXXXX"; - int fd = mkstemp(template); - if (fd < 0) { - return -1; - } - - unlink(template); - if (ftruncate(fd, size) < 0) { - return -1; - } - - return fd; -} - -static struct wl_buffer* createShmBuffer( - int width, - int height, - const uint8_t* pixels, - PalBool cursor) -{ - int stride = width * 4; - uint64_t size = stride * height; - struct wl_buffer* buffer = nullptr; - struct wl_shm_pool* pool = nullptr; - void* data = nullptr; - - int fd = createShmFile(size); - if (fd == -1) { - return nullptr; - } - - data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) { - return nullptr; - } - - enum wl_shm_format format = WL_SHM_FORMAT_XRGB8888; - if (cursor) { - format = WL_SHM_FORMAT_ARGB8888; - uint32_t* dataPixels = (uint32_t*)data; - - // convert from RGBA8 to ARGB32 - for (int i = 0; i < width * height; i++) { - uint8_t r = pixels[i * 4 + 0]; // Red - uint8_t g = pixels[i * 4 + 1]; // Green - uint8_t b = pixels[i * 4 + 2]; // Blue - uint8_t a = pixels[i * 4 + 3]; // Alpha - - // clang-format off - dataPixels[i] = ((unsigned long)a << 24) | - ((unsigned long)r << 16) | - ((unsigned long)g << 8) | - ((unsigned long)b); - // clang-format on - } - - } else { - memset(data, 0xFF, size); // white - } - - pool = wlShmCreatePool(s_Wl.shm, fd, size); - if (!pool) { - return nullptr; - } - - buffer = wlShmPoolCreateBuffer(pool, 0, width, height, stride, format); - if (!buffer) { - return nullptr; - } - - wlShmPoolDestroy(pool); - munmap(data, size); - close(fd); - return buffer; -} - -static void wlOutputGeometry( - void* data, - struct wl_output* output, - int32_t x, - int32_t y, - int32_t, // we dont need physical size - int32_t, // we dont need physical size - int32_t, // we dont need subpixel - const char* make, - const char* model, - int32_t transform) -{ - MonitorData* monitorData = data; - monitorData->x = x; - monitorData->y = y; - - switch (transform) { - case WL_OUTPUT_TRANSFORM_NORMAL: - case WL_OUTPUT_TRANSFORM_180: { - monitorData->orientation = PAL_ORIENTATION_LANDSCAPE; - break; - } - - case WL_OUTPUT_TRANSFORM_90: - case WL_OUTPUT_TRANSFORM_270: { - monitorData->orientation = PAL_ORIENTATION_PORTRAIT; - break; - } - - case WL_OUTPUT_TRANSFORM_FLIPPED: - case WL_OUTPUT_TRANSFORM_FLIPPED_180: { - monitorData->orientation = PAL_ORIENTATION_LANDSCAPE_FLIPPED; - break; - } - - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - case WL_OUTPUT_TRANSFORM_FLIPPED_270: { - monitorData->orientation = PAL_ORIENTATION_PORTRAIT_FLIPPED; - break; - } - } - - snprintf(monitorData->name, 32, "%s %s", make, model); -} - -static void wlOutputMode( - void* data, - struct wl_output* output, - uint32_t flags, - int32_t width, - int32_t height, - int32_t refresh) -{ - MonitorData* monitorData = data; - if (flags & WL_OUTPUT_MODE_CURRENT) { - monitorData->w = width; - monitorData->h = height; - monitorData->refreshRate = (refresh + 500) / 1000; - - // wayland only sends the current mode - monitorData->mode.bpp = 0; - monitorData->mode.width = width; - monitorData->mode.height = height; - monitorData->mode.refreshRate = (refresh + 500) / 1000; - } -} - -static void wlOutputScale( - void* data, - struct wl_output* output, - int32_t scale) -{ - MonitorData* monitorData = data; - float dpi = (float)scale * 96.0f; - monitorData->dpi = (uint32_t)dpi; -} - -static void wlOutputDone( - void* data, - struct wl_output* output) -{ -} - -static const struct wl_output_listener s_OutputListener = { - .geometry = wlOutputGeometry, - .mode = wlOutputMode, - .done = wlOutputDone, - .scale = wlOutputScale}; - -static const struct wl_output_listener s_DefaultModeListener = { - .geometry = wlOutputGeometry, - .mode = wlOutputMode, - .done = wlOutputDone, - .scale = wlOutputScale}; - -static void globalHandle( - void* data, - struct wl_registry* registry, - uint32_t name, - const char* interface, - uint32_t version) -{ - if (s_Wl.checkFeatures) { - PalVideoFeatures features = 0; - PalVideoFeatures64 features64 = 0; - features |= PAL_VIDEO_FEATURE_HIGH_DPI; - features |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; - features |= PAL_VIDEO_FEATURE_MULTI_MONITORS; - features |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; - features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; - - features64 |= PAL_VIDEO_FEATURE_HIGH_DPI; - features64 |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; - features64 |= PAL_VIDEO_FEATURE_MULTI_MONITORS; - features64 |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; - features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; - features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; - features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; - features64 |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; - - features64 |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; - - s_Video.features = features; - s_Video.features64 = features64; - s_Wl.checkFeatures = PAL_FALSE; - } - - if (strcmp(interface, "wl_compositor") == 0) { - s_Wl.compositor = wlRegistryBind(registry, name, s_Wl.compositorInterface, 4); - - } else if (strcmp(interface, "xdg_wm_base") == 0) { - s_Wl.xdgBase = wlRegistryBind(registry, name, &xdg_wm_base_interface, 1); - - xdgWmBaseAddListener(s_Wl.xdgBase, &wmBaseListener, nullptr); - - } else if (strcmp(interface, "wl_shm") == 0) { - s_Wl.shm = wlRegistryBind(registry, name, s_Wl.shmInterface, 1); - - } else if (strcmp(interface, "wl_seat") == 0) { - s_Wl.seat = wlRegistryBind(registry, name, s_Wl.seatInterface, 5); - - wlSeatAddListener(s_Wl.seat, &seatListener, nullptr); - - } else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) { - s_Wl.decorationManager = - wlRegistryBind(registry, name, &zxdg_decoration_manager_v1_interface, 1); - - s_Video.features64 |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; - - } else if (strcmp(interface, "wl_output") == 0) { - // wayland does not let use query monitors directly - // so we enumerate and store at init and update the - // cache when a monitor is added or removed - MonitorData* monitorData = getFreeMonitorData(); - if (!monitorData) { - return; - } - - struct wl_output* output = nullptr; - output = wlRegistryBind(s_Wl.registry, name, s_Wl.outputInterface, 3); - wlOutputAddListener(output, &s_OutputListener, monitorData); - - monitorData->wlName = name; - monitorData->monitor = (PalMonitor*)output; - s_Wl.monitorCount++; - } -} - -static void globalRemove( - void* data, - struct wl_registry* registry, - uint32_t name) -{ - for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (s_Video.monitorData[i].used && s_Video.monitorData[i].wlName == name) { - MonitorData* data = &s_Video.monitorData[i]; - data->used = PAL_FALSE; - s_Wl.proxyDestroy((struct wl_proxy*)data->monitor); - s_Wl.monitorCount--; - } - } -} - -static const struct wl_registry_listener s_RegistryListener = { - .global = globalHandle, - .global_remove = globalRemove}; - -PalResult wlInitVideo() -{ - // load wayland libray - s_Wl.handle = dlopen("libwayland-client.so.0", RTLD_LAZY); - s_Wl.xkbCommon = dlopen("libxkbcommon.so", RTLD_LAZY); - s_Wl.libCursor = dlopen("libwayland-cursor.so", RTLD_LAZY); - s_Wl.libWaylandEgl = dlopen("libwayland-egl.so", RTLD_LAZY); - - // clang-format off - if (!s_Wl.handle || - !s_Wl.xkbCommon || - !s_Wl.libCursor || - !s_Wl.libWaylandEgl) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // get the exported global variables - s_Wl.outputInterface = dlsym(s_Wl.handle, "wl_output_interface"); - s_Wl.seatInterface = dlsym(s_Wl.handle, "wl_seat_interface"); - s_Wl.compositorInterface = dlsym(s_Wl.handle, "wl_compositor_interface"); - s_Wl.surfaceInterface = dlsym(s_Wl.handle, "wl_surface_interface"); - s_Wl.registryInterface = dlsym(s_Wl.handle, "wl_registry_interface"); - s_Wl.shmInterface = dlsym(s_Wl.handle, "wl_shm_interface"); - s_Wl.bufferInterface = dlsym(s_Wl.handle, "wl_buffer_interface"); - s_Wl.shmPoolInterface = dlsym(s_Wl.handle, "wl_shm_pool_interface"); - s_Wl.regionInterface = dlsym(s_Wl.handle, "wl_region_interface"); - s_Wl.pointerInterface = dlsym(s_Wl.handle, "wl_pointer_interface"); - s_Wl.keyboardInterface = dlsym(s_Wl.handle, "wl_keyboard_interface"); - - // load function procs - s_Wl.displayConnect = (wl_display_connect_fn)dlsym( - s_Wl.handle, - "wl_display_connect"); - - s_Wl.displayDisconnect = (wl_display_disconnect_fn)dlsym( - s_Wl.handle, - "wl_display_disconnect"); - - s_Wl.displayRoundtrip = (wl_display_roundtrip_fn)dlsym( - s_Wl.handle, - "wl_display_roundtrip"); - - s_Wl.displayDispatch = (wl_display_dispatch_fn)dlsym( - s_Wl.handle, - "wl_display_dispatch"); - - s_Wl.proxyAddListener = (wl_proxy_add_listener_fn)dlsym( - s_Wl.handle, - "wl_proxy_add_listener"); - - s_Wl.proxyMarshalCnstructor = (wl_proxy_marshal_constructor_v_fn)dlsym( - s_Wl.handle, - "wl_proxy_marshal_constructor_versioned"); - - s_Wl.proxyDestroy = (wl_proxy_destroy_fn)dlsym( - s_Wl.handle, - "wl_proxy_destroy"); - - s_Wl.proxyMarshalFlags = (wl_proxy_marshal_flags_fn)dlsym( - s_Wl.handle, - "wl_proxy_marshal_flags"); - - s_Wl.proxyGetVersion = (wl_proxy_get_version_fn)dlsym( - s_Wl.handle, - "wl_proxy_get_version"); - - s_Wl.getError = (wl_display_get_error_fn)dlsym( - s_Wl.handle, - "wl_display_get_error"); - - s_Wl.dispatchPending = (wl_display_dispatch_pending_fn)dlsym( - s_Wl.handle, - "wl_display_dispatch_pending"); - - s_Wl.displayFlush = (wl_display_flush_fn)dlsym( - s_Wl.handle, - "wl_display_flush"); - - s_Wl.prepareRead = (wl_display_prepare_read_fn)dlsym( - s_Wl.handle, - "wl_display_prepare_read"); - - s_Wl.readEvents = (wl_display_read_events_fn)dlsym( - s_Wl.handle, - "wl_display_read_events"); - - s_Wl.displayGetFd = (wl_display_get_fd_fn)dlsym( - s_Wl.handle, - "wl_display_get_fd"); - - s_Wl.cancelRead = (wl_display_cancel_read_fn)dlsym( - s_Wl.handle, - "wl_display_cancel_read"); - - // load xkbcommon procs - s_Wl.xkbKeymapUnref = (xkb_keymap_unref_fn)dlsym( - s_Wl.xkbCommon, - "xkb_keymap_unref"); - - s_Wl.xkbStateKeyGetOneSym = (xkb_state_key_get_one_sym_fn)dlsym( - s_Wl.xkbCommon, - "xkb_state_key_get_one_sym"); - - s_Wl.xkbStateNew = (xkb_state_new_fn)dlsym( - s_Wl.xkbCommon, - "xkb_state_new"); - - s_Wl.xkbStateUnref = (xkb_state_unref_fn)dlsym( - s_Wl.xkbCommon, - "xkb_state_unref"); - - s_Wl.xkbContextUnref = (xkb_context_unref_fn)dlsym( - s_Wl.xkbCommon, - "xkb_context_unref"); - - s_Wl.xkbContextNew = (xkb_context_new_fn)dlsym( - s_Wl.xkbCommon, - "xkb_context_new"); - - s_Wl.xkbKeymapNewFromString = (xkb_keymap_new_from_string_fn)dlsym( - s_Wl.xkbCommon, - "xkb_keymap_new_from_string"); - - s_Wl.xkbKeysymToUtf32 = (xkb_keysym_to_utf32_fn)dlsym( - s_Wl.xkbCommon, - "xkb_keysym_to_utf32"); - - s_Wl.xkbStateUpdateMask = (xkb_state_update_mask_fn)dlsym( - s_Wl.xkbCommon, - "xkb_state_update_mask"); - - s_Wl.xkbKeymapKeyRepeats = (xkb_keymap_key_repeats_fn)dlsym( - s_Wl.xkbCommon, - "xkb_keymap_key_repeats"); - - // load wayland cursor procs - s_Wl.cursorImageGetBuffer = (wl_cursor_image_get_buffer_fn)dlsym( - s_Wl.libCursor, - "wl_cursor_image_get_buffer"); - - s_Wl.cursorThemeLoad = (wl_cursor_theme_load_fn)dlsym( - s_Wl.libCursor, - "wl_cursor_theme_load"); - - s_Wl.cursorThemeGetCursor = (wl_cursor_theme_get_cursor_fn)dlsym( - s_Wl.libCursor, - "wl_cursor_theme_get_cursor"); - - // wl_egl procs - s_Wl.eglWindowCreate = (wl_egl_window_create_fn)dlsym( - s_Wl.libWaylandEgl, - "wl_egl_window_create"); - - s_Wl.eglWindowDestroy = (wl_egl_window_destroy_fn)dlsym( - s_Wl.libWaylandEgl, - "wl_egl_window_destroy"); - - s_Wl.eglWindowResize = (wl_egl_window_resize_fn)dlsym( - s_Wl.libWaylandEgl, - "wl_egl_window_resize"); - // clang-format on - - // initialize wayland - s_Wl.checkFeatures = PAL_TRUE; - s_Wl.monitorCount = 0; - setupXdgShellProtocol(); - - // check if user supplied their own display - if (s_Video.platformInstance) { - s_Wl.display = (struct wl_display*)s_Video.platformInstance; - - } else { - s_Wl.display = s_Wl.displayConnect(nullptr); - s_Video.platformInstance = nullptr; - } - - if (!s_Wl.display) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - s_Video.display = (void*)s_Wl.display; - s_Wl.registry = wlDisplayGetRegistry(s_Wl.display); - wlRegistryAddListener(s_Wl.registry, &s_RegistryListener, nullptr); - s_Wl.displayRoundtrip(s_Wl.display); - - // do a roundtrip again to get remaining handles - s_Wl.displayRoundtrip(s_Wl.display); - - if (!s_Wl.compositor || !s_Wl.xdgBase || !s_Wl.shm) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // create an input context - s_Wl.inputContext = s_Wl.xkbContextNew(XKB_CONTEXT_NO_FLAGS); - if (!s_Wl.inputContext) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // get the current theme - s_Wl.cursorTheme = s_Wl.cursorThemeLoad(nullptr, 32, s_Wl.shm); - if (!s_Wl.cursorTheme) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - wlCreateKeycodeTable(); - - s_Video.display = (void*)s_Wl.display; - return PAL_RESULT_SUCCESS; -} - -void wlShutdownVideo() -{ - if (s_Wl.state) { - s_Wl.xkbStateUnref(s_Wl.state); - s_Wl.xkbKeymapUnref(s_Wl.keymap); - } - - s_Wl.xkbContextUnref(s_Wl.inputContext); - if (s_Wl.compositor) { - // if compositor was found, all this will be as well - // since we check all at init - s_Wl.proxyDestroy((struct wl_proxy*)s_Wl.compositor); - s_Wl.proxyDestroy((struct wl_proxy*)s_Wl.xdgBase); - s_Wl.proxyDestroy((struct wl_proxy*)s_Wl.shm); - s_Wl.proxyDestroy((struct wl_proxy*)s_Wl.seat); - } - - if (!s_Video.platformInstance) { - // opened by PAL - s_Wl.displayDisconnect(s_Wl.display); - } - - dlclose(s_Wl.libCursor); - dlclose(s_Wl.xkbCommon); - dlclose(s_Wl.libWaylandEgl); - dlclose(s_Wl.handle); - - memset(&s_Wl, 0, sizeof(Wayland)); -} - -PalResult wlSetFBConfig( - const int index, - PalFBConfigBackend backend) -{ - if (backend == PAL_CONFIG_BACKEND_GLES || backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { - return eglWlBackend(index); - - } else { - return PAL_RESULT_INVALID_FBCONFIG_BACKEND; - } -} - -void wlUpdateVideo() -{ - // flush pending requests - s_Mouse.tmpScrollX = 0; - s_Mouse.tmpScrollY = 0; - - // push key repeats - // we only do this if the user wants key repeat events - if (s_Keyboard.repeatKey != 0 && s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(driver, PAL_EVENT_KEYREPEAT); - if (mode != PAL_DISPATCH_NONE) { - // get now time and check with the key repeat time - uint64_t now = getTime(); - if (now >= s_Keyboard.timer) { - PalWindow* window = (PalWindow*)s_Wl.keyboardSurface; - PalKeycode key = s_Keyboard.repeatKey; - PalScancode scancode = s_Keyboard.repeatScancode; - - PalEvent event = {0}; - event.type = PAL_EVENT_KEYREPEAT; - event.data = palPackUint32(key, scancode); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - s_Keyboard.timer += s_Keyboard.repeatRate; - } - } - } - - while (s_Wl.prepareRead(s_Wl.display) != 0) { - s_Wl.dispatchPending(s_Wl.display); - } - - s_Wl.displayFlush(s_Wl.display); - int fd = s_Wl.displayGetFd(s_Wl.display); - struct pollfd pfd = {fd, POLLIN, 0}; - if (poll(&pfd, 1, 0) > 0) { - // there are events ready to be read - s_Wl.readEvents(s_Wl.display); - - } else { - s_Wl.cancelRead(s_Wl.display); - } - - // dispatch events that were read - s_Wl.dispatchPending(s_Wl.display); -} - -PalResult wlEnumerateMonitors( - int32_t* count, - PalMonitor** outMonitors) -{ - if (outMonitors) { - int index = 0; - int maxCount = s_Video.maxMonitorData; - for (int i = 0; i < maxCount && index < *count; i++) { - if (s_Video.monitorData[i].used) { - // found a monitor - PalMonitor* monitor = s_Video.monitorData[index].monitor; - outMonitors[index++] = monitor; - } - } - } - - if (!outMonitors) { - *count = s_Wl.monitorCount; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult wlGetPrimaryMonitor(PalMonitor** outMonitor) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetMonitorInfo( - PalMonitor* monitor, - PalMonitorInfo* info) -{ - MonitorData* monitorData = findMonitorData(monitor); - if (!monitorData) { - return PAL_RESULT_INVALID_MONITOR; - } - - info->dpi = monitorData->dpi; - info->x = monitorData->x; - info->y = monitorData->y; - info->width = monitorData->w; - info->height = monitorData->h; - info->refreshRate = monitorData->refreshRate; - info->orientation = monitorData->orientation; - - info->primary = PAL_FALSE; // no way to query - strcpy(info->name, monitorData->name); - - return PAL_RESULT_SUCCESS; -} - -PalResult wlEnumerateMonitorModes( - PalMonitor* monitor, - int32_t* count, - PalMonitorMode* modes) -{ - MonitorData* monitorData = findMonitorData(monitor); - if (!monitorData) { - return PAL_RESULT_INVALID_MONITOR; - } - - if (modes && *count > 0) { - PalMonitorMode* mode = &modes[0]; - mode->bpp = monitorData->mode.bpp; - mode->width = monitorData->mode.width; - mode->height = monitorData->mode.height; - mode->refreshRate = monitorData->mode.refreshRate; - } - - if (!modes) { - *count = 1; // wayland only gives the active mode - } - - return PAL_RESULT_SUCCESS; -} - -PalResult wlGetCurrentMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - MonitorData* monitorData = findMonitorData(monitor); - if (!monitorData) { - return PAL_RESULT_INVALID_MONITOR; - } - - // this is the same as the current mode - mode->bpp = monitorData->mode.bpp; - mode->width = monitorData->mode.width; - mode->height = monitorData->mode.height; - mode->refreshRate = monitorData->mode.refreshRate; - - return PAL_RESULT_SUCCESS; -} - -PalResult wlSetMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlValidateMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlSetMonitorOrientation( - PalMonitor* monitor, - PalOrientation orientation) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlCreateWindow( - const PalWindowCreateInfo* info, - PalWindow** outWindow) -{ - struct wl_surface* surface = nullptr; - struct xdg_surface* xdgSurface = nullptr; - struct xdg_toplevel* xdgToplevel = nullptr; - - if (info->style & PAL_WINDOW_STYLE_TOPMOST) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - if (info->style & PAL_WINDOW_STYLE_TRANSPARENT) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - if (info->style & PAL_WINDOW_STYLE_TOOL) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - if (!(info->style & PAL_WINDOW_STYLE_BORDERLESS)) { - if (!s_Wl.decorationManager) { - // user wants decorated window but its not supported - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - } - - WindowData* data = getFreeWindowData(); - if (!data) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(data, 0, sizeof(WindowData)); - data->used = PAL_TRUE; - data->focused = PAL_FALSE; - - // create surface - surface = wlCompositorCreateSurface(s_Wl.compositor); - if (!surface) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - wlSurfaceAddListener(surface, &surfaceListener, data); - xdgSurface = xdgWmBaseGetXdgSurface(s_Wl.xdgBase, surface); - if (!xdgSurface) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - xdgToplevel = xdgSurfaceGetToplevel(xdgSurface); - if (!xdgSurface) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // set APP id - const char* appID = getenv("RESOURCE_CLASS"); - if (!appID || strlen(appID) == 0) { - appID = s_Video.className; - } - - const char* title = info->title; - if (!title) { - title = ""; - } - - xdgToplevelSetTitle(xdgToplevel, title); - xdgToplevelSetAppId(xdgToplevel, appID); - - xdgToplevelAddListener(xdgToplevel, &xdgToplevelListener, data); - xdgSurfaceAddListener(xdgSurface, &xdgSurfaceListener, data); - - // decorated window - if (!(info->style & PAL_WINDOW_STYLE_BORDERLESS)) { - struct zxdg_toplevel_decoration_v1* decoration = nullptr; - decoration = zxdgGetToplevelDecoration(s_Wl.decorationManager, xdgToplevel); - zxdgToplevelDecorationV1AddListener(decoration, &decorationListener, surface); - zxdgToplevelDecorationV1SetMode(decoration, 2); - data->decoration = decoration; - } - - data->skipState = PAL_TRUE; - data->skipConfigure = PAL_TRUE; - wlSurfaceCommit(surface); - s_Wl.displayRoundtrip(s_Wl.display); - - if (info->maximized && info->show) { - // we need the maximized size the compositor will use - // and use that to create the buffer - xdgToplevelSetMaximized(xdgToplevel); - wlSurfaceCommit(surface); - s_Wl.displayRoundtrip(s_Wl.display); - data->state = PAL_WINDOW_STATE_MAXIMIZED; - - } else { - data->w = info->width; - data->h = info->height; - } - - data->xdgSurface = xdgSurface; - data->xdgToplevel = xdgToplevel; - data->window = (PalWindow*)surface; - data->buffer = nullptr; - data->isAttached = PAL_FALSE; - data->state = PAL_WINDOW_STATE_RESTORED; - - // minimize - // This is just a requeest, the compositor might ignore it - if (info->minimized) { - xdgToplevelSetMinimized(xdgToplevel); - wlSurfaceCommit(surface); - data->state = PAL_WINDOW_STATE_MINIMIZED; - } - - if (s_Wl.eglFBConfig) { - data->eglWindow = s_Wl.eglWindowCreate(surface, data->w, data->h); - if (!data->eglWindow) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - } else { - // create a white buffer for the surface - struct wl_buffer* buffer = nullptr; - buffer = createShmBuffer(data->w, data->h, nullptr, PAL_FALSE); - if (!buffer) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - wlSurfaceAttach(surface, buffer, 0, 0); - wlSurfaceDamageBuffer(surface, 0, 0, data->w, data->h); - wlSurfaceCommit(surface); - data->buffer = buffer; - } - - struct wl_region* region = wlCompositorCreateRegion(s_Wl.compositor); - if (region) { - wlRegionAdd(region, 0, 0, data->w, data->h); - wlSurfaceSetOpaqueRegion(surface, region); - wlRegionDestroy(region); - wlSurfaceCommit(surface); - } - - s_Wl.displayRoundtrip(s_Wl.display); - if (!s_Wl.decorationManager && s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_WINDOW_DECORATION_MODE; - mode = palGetEventDispatchMode(driver, type); - - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = PAL_DECORATION_MODE_CLIENT_SIDE; - event.data2 = palPackPointer(data->window); - palPushEvent(driver, &event); - } - } - - // Since wayland does not have a way to set unique data - // to a surface without taking control from users - // we might implement a simple hash map to do that - // but at the moment a linear search is fine - // FIXME: Implement a window hash map - - data->skipState = PAL_FALSE; - data->skipConfigure = PAL_FALSE; - *outWindow = data->window; - return PAL_RESULT_SUCCESS; -} - -void wlDestroyWindow(PalWindow* window) -{ - WindowData* data = findWindowData(window); - if (!data || (data && data->isAttached)) { - return; - } - - if (data->decoration) { - zxdgToplevelDecorationV1Destroy(data->decoration); - } - - if (data->eglWindow) { - s_Wl.eglWindowDestroy(data->eglWindow); - } else { - wlBufferDestroy(data->buffer); - } - - xdgToplevelDestroy(data->xdgToplevel); - xdgSurfaceDestroy(data->xdgSurface); - wlSurfaceDestroy((struct wl_surface*)window); - data->used = PAL_FALSE; -} - -PalResult wlMinimizeWindow(PalWindow* window) -{ - WindowData* data = findWindowData(window); - if (!data) { - return PAL_RESULT_INVALID_WINDOW; - } - - xdgToplevelSetMinimized(data->xdgToplevel); - return PAL_RESULT_SUCCESS; -} - -PalResult wlMaximizeWindow(PalWindow* window) -{ - WindowData* data = findWindowData(window); - if (!data) { - return PAL_RESULT_INVALID_WINDOW; - } - - xdgToplevelSetMaximized(data->xdgToplevel); - return PAL_RESULT_SUCCESS; -} - -PalResult wlRestoreWindow(PalWindow* window) -{ - WindowData* data = findWindowData(window); - if (!data) { - return PAL_RESULT_INVALID_WINDOW; - } - - // we can only restore from a maximized state - xdgToplevelUnsetMaximized(data->xdgToplevel); - return PAL_RESULT_SUCCESS; -} - -PalResult wlShowWindow(PalWindow* window) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlHideWindow(PalWindow* window) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlFlashWindow( - PalWindow* window, - const PalFlashInfo* info) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowStyle( - PalWindow* window, - PalWindowStyle* outStyle) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowMonitor( - PalWindow* window, - PalMonitor** outMonitor) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowTitle( - PalWindow* window, - uint64_t bufferSize, - uint64_t* outSize, - char* outBuffer) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowSize( - PalWindow* window, - uint32_t* width, - uint32_t* height) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowState( - PalWindow* window, - PalWindowState* outState) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalBool wlIsWindowVisible(PalWindow* window) -{ - return PAL_FALSE; -} - -PalWindow* wlGetFocusWindow() -{ - // Wayland does not let client query focused window - return nullptr; -} - -PalWindowHandleInfo wlGetWindowHandleInfo(PalWindow* window) -{ - PalWindowHandleInfo info; - info.nativeDisplay = (void*)s_Wl.display; - info.nativeWindow = (void*)window; - return info; -} - -PalWindowHandleInfoEx wlGetWindowHandleInfoEx(PalWindow* window) -{ - PalWindowHandleInfoEx info = {0}; - WindowData* data = findWindowData(window); - if (data) { - info.nativeDisplay = (void*)s_Wl.display; - info.nativeWindow = (void*)window; - info.nativeHandle1 = data->xdgSurface; - info.nativeHandle2 = data->xdgToplevel; - info.nativeHandle3 = data->eglWindow; - } - - return info; -} - -PalResult wlSetWindowOpacity( - PalWindow* window, - float opacity) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlSetWindowStyle( - PalWindow* window, - PalWindowStyle style) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlSetWindowTitle( - PalWindow* window, - const char* title) -{ - WindowData* data = findWindowData(window); - if (!data) { - return PAL_RESULT_INVALID_WINDOW; - } - - xdgToplevelSetTitle(data->xdgToplevel, title); - s_Wl.displayFlush(s_Wl.display); - return PAL_RESULT_SUCCESS; -} - -PalResult wlSetWindowPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlSetWindowSize( - PalWindow* window, - uint32_t width, - uint32_t height) -{ - WindowData* data = findWindowData(window); - if (!data) { - return PAL_RESULT_INVALID_WINDOW; - } - - xdgToplevelSetMinSize(data->xdgToplevel, width, height); - xdgToplevelSetMaxSize(data->xdgToplevel, width, height); - wlSurfaceCommit((struct wl_surface*)window); - return PAL_RESULT_SUCCESS; -} - -PalResult wlSetFocusWindow(PalWindow* window) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlCreateIcon( - const PalIconCreateInfo* info, - PalIcon** outIcon) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -void wlDestroyIcon(PalIcon* icon) -{ - return; -} - -PalResult wlSetWindowIcon( - PalWindow* window, - PalIcon* icon) -{ - return PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED; -} - -PalResult wlCreateCursor( - const PalCursorCreateInfo* info, - PalCursor** outCursor) -{ - WaylandCursor* cursor = nullptr; - cursor = palAllocate(s_Video.allocator, sizeof(WaylandCursor), 0); - if (!cursor) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - cursor->surface = wlCompositorCreateSurface(s_Wl.compositor); - if (!cursor->surface) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - cursor->buffer = createShmBuffer(info->width, info->height, info->pixels, PAL_TRUE); - if (!cursor->buffer) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - wlSurfaceAttach(cursor->surface, cursor->buffer, 0, 0); - wlSurfaceCommit(cursor->surface); - cursor->hotspotX = info->xHotspot; - cursor->hotspotY = info->yHotspot; - - *outCursor = (PalCursor*)cursor; - return PAL_RESULT_SUCCESS; -} - -PalResult wlCreateCursorFrom( - PalCursorType type, - PalCursor** outCursor) -{ - const char* cursorType = nullptr; - switch (type) { - case PAL_CURSOR_ARROW: { - cursorType = "left_ptr"; - break; - } - - case PAL_CURSOR_HAND: { - cursorType = "hand1"; - break; - } - - case PAL_CURSOR_CROSS: { - cursorType = "crosshair"; - break; - } - - case PAL_CURSOR_IBEAM: { - cursorType = "text"; - break; - } - - case PAL_CURSOR_WAIT: { - cursorType = "wait"; - break; - } - } - - struct wl_cursor* wlCursor = nullptr; - wlCursor = s_Wl.cursorThemeGetCursor(s_Wl.cursorTheme, cursorType); - if (!wlCursor) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - WaylandCursor* cursor = nullptr; - cursor = palAllocate(s_Video.allocator, sizeof(WaylandCursor), 0); - if (!cursor) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - cursor->surface = wlCompositorCreateSurface(s_Wl.compositor); - if (!cursor->surface) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - cursor->buffer = s_Wl.cursorImageGetBuffer(wlCursor->images[0]); - wlSurfaceAttach(cursor->surface, cursor->buffer, 0, 0); - wlSurfaceCommit(cursor->surface); - cursor->hotspotX = wlCursor->images[0]->hotspot_x; - cursor->hotspotY = wlCursor->images[0]->hotspot_y; - - *outCursor = (PalCursor*)cursor; - return PAL_RESULT_SUCCESS; -} - -void wlDestroyCursor(PalCursor* cursor) -{ - WaylandCursor* waylandCursor = (WaylandCursor*)cursor; - wlBufferDestroy(waylandCursor->buffer); - wlSurfaceDestroy(waylandCursor->surface); - palFree(s_Video.allocator, waylandCursor); -} - -void wlShowCursor(PalBool show) -{ - // not supported - return; -} - -PalResult wlClipCursor( - PalWindow* window, - PalBool clip) -{ - if (!(s_Video.features & PAL_VIDEO_FEATURE_CLIP_CURSOR)) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult wlGetCursorPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlSetCursorPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlSetWindowCursor( - PalWindow* window, - PalCursor* cursor) -{ - WindowData* data = findWindowData(window); - if (!data) { - return PAL_RESULT_INVALID_WINDOW; - } - - data->cursor = cursor; - return PAL_RESULT_SUCCESS; -} - -void* wlGetInstance() -{ - return (void*)s_Wl.display; -} - -PalResult wlAttachWindow( - void* windowHandle, - PalWindow** outWindow) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -PalResult wlDetachWindow( - PalWindow* window, - void** outWindowHandle) -{ - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; -} - -static Backend s_wlBackend = { - .shutdownVideo = wlShutdownVideo, - .updateVideo = wlUpdateVideo, - .setFBConfig = wlSetFBConfig, - .enumerateMonitors = wlEnumerateMonitors, - .getMonitorInfo = wlGetMonitorInfo, - .getPrimaryMonitor = wlGetPrimaryMonitor, - .enumerateMonitorModes = wlEnumerateMonitorModes, - .getCurrentMonitorMode = wlGetCurrentMonitorMode, - .setMonitorMode = wlSetMonitorMode, - .validateMonitorMode = wlValidateMonitorMode, - .setMonitorOrientation = wlSetMonitorOrientation, - - .createWindow = wlCreateWindow, - .destroyWindow = wlDestroyWindow, - .maximizeWindow = wlMaximizeWindow, - .minimizeWindow = wlMinimizeWindow, - .restoreWindow = wlRestoreWindow, - .showWindow = wlShowWindow, - .hideWindow = wlHideWindow, - .flashWindow = wlFlashWindow, - .getWindowStyle = wlGetWindowStyle, - .getWindowMonitor = wlGetWindowMonitor, - .getWindowTitle = wlGetWindowTitle, - .getWindowPos = wlGetWindowPos, - .getWindowSize = wlGetWindowSize, - .getWindowState = wlGetWindowState, - .isWindowVisible = wlIsWindowVisible, - .getFocusWindow = wlGetFocusWindow, - .getWindowHandleInfo = wlGetWindowHandleInfo, - .getWindowHandleInfoEx = wlGetWindowHandleInfoEx, - .setWindowOpacity = wlSetWindowOpacity, - .setWindowStyle = wlSetWindowStyle, - .setWindowTitle = wlSetWindowTitle, - .setWindowPos = wlSetWindowPos, - .setWindowSize = wlSetWindowSize, - .setFocusWindow = wlSetFocusWindow, - - .createIcon = wlCreateIcon, - .destroyIcon = wlDestroyIcon, - .setWindowIcon = wlSetWindowIcon, - - .createCursor = wlCreateCursor, - .createCursorFrom = wlCreateCursorFrom, - .destroyCursor = wlDestroyCursor, - .showCursor = wlShowCursor, - .clipCursor = wlClipCursor, - .getCursorPos = wlGetCursorPos, - .setCursorPos = wlSetCursorPos, - .setWindowCursor = wlSetWindowCursor, - - .attachWindow = wlAttachWindow, - .detachWindow = wlDetachWindow}; - -#endif // PAL_HAS_WAYLAND -#pragma endregion - -// ================================================== -// Public API -// ================================================== - -PalResult PAL_CALL palInitVideo( - const PalAllocator* allocator, - PalEventDriver* eventDriver) -{ - if (s_Video.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - - // get backend type - PalBool x11 = PAL_TRUE; - const char* session = getenv("XDG_SESSION_TYPE"); - if (session) { - if (strcmp(session, "wayland") == 0) { - x11 = PAL_FALSE; - } - } - - s_Video.maxMonitorData = 16; // initial size - s_Video.maxWindowData = 32; // initial size - - s_Video.windowData = - palAllocate(s_Video.allocator, sizeof(WindowData) * s_Video.maxWindowData, 0); - - s_Video.monitorData = - palAllocate(s_Video.allocator, sizeof(MonitorData) * s_Video.maxMonitorData, 0); - - if (!s_Video.monitorData || !s_Video.windowData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_Video.className = "PAL"; - if (x11) { -#if PAL_HAS_X11 - PalResult ret = xInitVideo(); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - s_Video.backend = &s_XBackend; -#else - return PAL_RESULT_PLATFORM_FAILURE; -#endif // PAL_HAS_X11 - - } else { -#if PAL_HAS_WAYLAND - PalResult ret = wlInitVideo(); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - s_Video.backend = &s_wlBackend; -#else - return PAL_RESULT_PLATFORM_FAILURE; -#endif // PAL_HAS_WAYLAND - } - - createScancodeTable(); - - // we load EGL as well - s_Egl.handle = dlopen("libEGL.so", RTLD_LAZY); - if (s_Egl.handle) { - eglGetProcAddressFn load = nullptr; - load = (eglGetProcAddressFn)dlsym(s_Egl.handle, "eglGetProcAddress"); - - s_Egl.eglInitialize = (eglInitializeFn)load("eglInitialize"); - s_Egl.eglTerminate = (eglTerminateFn)load("eglTerminate"); - s_Egl.eglGetDisplay = (eglGetDisplayFn)load("eglGetDisplay"); - s_Egl.eglChooseConfig = (eglChooseConfigFn)load("eglChooseConfig"); - s_Egl.eglGetError = (eglGetErrorFn)load("eglGetError"); - s_Egl.eglBindAPI = (eglBindAPIFn)load("eglBindAPI"); - s_Egl.eglGetConfigs = (eglGetConfigsFn)load("eglGetConfigs"); - s_Egl.eglGetConfigAttrib = (eglGetConfigAttribFn)load("eglGetConfigAttrib"); - } - - s_Video.allocator = allocator; - s_Video.eventDriver = eventDriver; - s_Video.initialized = PAL_TRUE; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palShutdownVideo() -{ - if (s_Video.initialized) { - s_Video.backend->shutdownVideo(); - palFree(s_Video.allocator, s_Video.windowData); - palFree(s_Video.allocator, s_Video.monitorData); - - if (s_Egl.handle) { - dlclose(s_Egl.handle); - } - - s_Video.platformInstance = nullptr; - s_Video.display = nullptr; - memset(&s_Keyboard, 0, sizeof(Keyboard)); - memset(&s_Mouse, 0, sizeof(Mouse)); - s_Video.initialized = PAL_FALSE; - } -} - -void PAL_CALL palUpdateVideo() -{ - if (s_Video.initialized) { - s_Video.backend->updateVideo(); - } -} - -PalVideoFeatures PAL_CALL palGetVideoFeatures() -{ - if (!s_Video.initialized) { - return 0; - } - - return s_Video.features; -} - -PalVideoFeatures64 PAL_CALL palGetVideoFeaturesEx() -{ - if (!s_Video.initialized) { - return 0; - } - - return s_Video.features64; -} - -PalResult PAL_CALL palSetFBConfig( - const int index, - PalFBConfigBackend backend) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - // X11 and wayland can only used GLX and EGL - if (backend == PAL_CONFIG_BACKEND_WGL) { - return PAL_RESULT_INVALID_FBCONFIG_BACKEND; - } - - return s_Video.backend->setFBConfig(index, backend); -} - -PalResult PAL_CALL palEnumerateMonitors( - int32_t* count, - PalMonitor** outMonitors) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!count) { - return PAL_RESULT_NULL_POINTER; - } - - if (*count == 0 && outMonitors) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - return s_Video.backend->enumerateMonitors(count, outMonitors); -} - -PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!outMonitor) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->getPrimaryMonitor(outMonitor); -} - -PalResult PAL_CALL palGetMonitorInfo( - PalMonitor* monitor, - PalMonitorInfo* info) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!info) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->getMonitorInfo(monitor, info); -} - -PalResult PAL_CALL palEnumerateMonitorModes( - PalMonitor* monitor, - int32_t* count, - PalMonitorMode* modes) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!monitor || !count) { - return PAL_RESULT_NULL_POINTER; - } - - if (*count == 0 && modes) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - PalResult ret = s_Video.backend->enumerateMonitorModes(monitor, count, modes); - if (ret == PAL_RESULT_SUCCESS && modes) { - // sort the modes so that they are lowest to highest - qsort(modes, *count, sizeof(PalMonitorMode), compareModes); - } - - return ret; -} - -PalResult PAL_CALL palGetCurrentMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!monitor || !mode) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->getCurrentMonitorMode(monitor, mode); -} - -PalResult PAL_CALL palSetMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!monitor || !mode) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->setMonitorMode(monitor, mode); -} - -PalResult PAL_CALL palValidateMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!monitor || !mode) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->validateMonitorMode(monitor, mode); -} - -PalResult PAL_CALL palSetMonitorOrientation( - PalMonitor* monitor, - PalOrientation orientation) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!monitor) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->setMonitorOrientation(monitor, orientation); -} - -// ================================================== -// Window -// ================================================== - -PalResult PAL_CALL palCreateWindow( - const PalWindowCreateInfo* info, - PalWindow** outWindow) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!info || !outWindow) { - return PAL_RESULT_NULL_POINTER; - } - - if (info->style & PAL_WINDOW_STYLE_NO_MINIMIZEBOX) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - if (info->style & PAL_WINDOW_STYLE_NO_MAXIMIZEBOX) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - return s_Video.backend->createWindow(info, outWindow); -} - -void PAL_CALL palDestroyWindow(PalWindow* window) -{ - if (s_Video.initialized && window) { - return s_Video.backend->destroyWindow(window); - } -} - -PalResult PAL_CALL palMinimizeWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->maximizeWindow(window); -} - -PalResult PAL_CALL palMaximizeWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->minimizeWindow(window); -} - -PalResult PAL_CALL palRestoreWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->restoreWindow(window); -} - -PalResult PAL_CALL palShowWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->showWindow(window); -} - -PalResult PAL_CALL palHideWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->hideWindow(window); -} - -PalResult PAL_CALL palFlashWindow( - PalWindow* window, - const PalFlashInfo* info) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !info) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->flashWindow(window, info); -} - -PalResult PAL_CALL palGetWindowStyle( - PalWindow* window, - PalWindowStyle* outStyle) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !outStyle) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->getWindowStyle(window, outStyle); -} - -PalResult PAL_CALL palGetWindowMonitor( - PalWindow* window, - PalMonitor** outMonitor) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !outMonitor) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->getWindowMonitor(window, outMonitor); -} - -PalResult PAL_CALL palGetWindowTitle( - PalWindow* window, - uint64_t bufferSize, - uint64_t* outSize, - char* outBuffer) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !outBuffer) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->getWindowTitle(window, bufferSize, outSize, outBuffer); -} - -PalResult PAL_CALL palGetWindowPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->getWindowPos(window, x, y); -} - -PalResult PAL_CALL palGetWindowSize( - PalWindow* window, - uint32_t* width, - uint32_t* height) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->getWindowSize(window, width, height); -} - -PalResult PAL_CALL palGetWindowState( - PalWindow* window, - PalWindowState* outState) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !outState) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->getWindowState(window, outState); -} - -const PalBool* PAL_CALL palGetKeycodeState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Keyboard.keycodeState; -} - -const PalBool* PAL_CALL palGetScancodeState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Keyboard.scancodeState; -} - -const PalBool* PAL_CALL palGetMouseState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Mouse.state; -} - -void PAL_CALL palGetMouseDelta( - int32_t* dx, - int32_t* dy) -{ - if (!s_Video.initialized) { - return; - } - - if (dx) { - *dx = s_Mouse.dx; - } - - if (dy) { - *dy = s_Mouse.dy; - } -} - -void PAL_CALL palGetMouseWheelDelta( - int32_t* dx, - int32_t* dy) -{ - if (!s_Video.initialized) { - return; - } - - if (dx) { - *dx = s_Mouse.WheelX; - } - - if (dy) { - *dy = s_Mouse.WheelY; - } -} - -void PAL_CALL palGetRawMouseWheelDelta( - float* dx, - float* dy) -{ - if (!s_Video.initialized) { - return; - } - - if (dx) { - *dx = (float)s_Mouse.tmpScrollX; - } - - if (dy) { - *dy = (float)s_Mouse.tmpScrollY; - } -} - -PalBool PAL_CALL palIsWindowVisible(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->isWindowVisible(window); -} - -PalWindow* PAL_CALL palGetFocusWindow() -{ - if (!s_Video.initialized) { - return nullptr; - } - - return s_Video.backend->getFocusWindow(); -} - -PalResult PAL_CALL palGetWindowHandleInfo( - PalWindow* window, - PalWindowHandleInfo* info) -{ - if (s_Video.initialized) { - return s_Video.backend->getWindowHandleInfo(window); - } -} - -PalResult PAL_CALL palSetWindowOpacity( - PalWindow* window, - float opacity) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - if (!(s_Video.features & PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW)) { - return PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED; - } - - if (opacity < 0.0f) { - opacity = 0.0f; - } - - if (opacity > 1.0f) { - opacity = 1.0f; - } - - return s_Video.backend->setWindowOpacity(window, opacity); -} - -PalResult PAL_CALL palSetWindowStyle( - PalWindow* window, - PalWindowStyle style) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->setWindowStyle(window, style); -} - -PalResult PAL_CALL palSetWindowTitle( - PalWindow* window, - const char* title) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window || !title) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->setWindowTitle(window, title); -} - -PalResult PAL_CALL palSetWindowPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->setWindowPos(window, x, y); -} - -PalResult PAL_CALL palSetWindowSize( - PalWindow* window, - uint32_t width, - uint32_t height) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->setWindowSize(window, width, height); -} - -PalResult PAL_CALL palSetFocusWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->setFocusWindow(window); -} - -// ================================================== -// Icon -// ================================================== - -PalResult PAL_CALL palCreateIcon( - const PalIconCreateInfo* info, - PalIcon** outIcon) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!info || !outIcon) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->createIcon(info, outIcon); -} - -void PAL_CALL palDestroyIcon(PalIcon* icon) -{ - if (s_Video.initialized && icon) { - s_Video.backend->destroyIcon(icon); - } -} - -PalResult PAL_CALL palSetWindowIcon( - PalWindow* window, - PalIcon* icon) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->setWindowIcon(window, icon); -} - -// ================================================== -// Cursor -// ================================================== - -PalResult PAL_CALL palCreateCursor( - const PalCursorCreateInfo* info, - PalCursor** outCursor) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!info || !outCursor) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->createCursor(info, outCursor); -} - -PalResult PAL_CALL palCreateCursorFrom( - PalCursorType type, - PalCursor** outCursor) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!outCursor) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->createCursorFrom(type, outCursor); -} - -void PAL_CALL palDestroyCursor(PalCursor* cursor) -{ - if (s_Video.initialized && cursor) { - s_Video.backend->destroyCursor(cursor); - } -} - -void PAL_CALL palShowCursor(PalBool show) -{ - if (s_Video.initialized) { - s_Video.backend->showCursor(show); - } -} - -PalResult PAL_CALL palClipCursor( - PalWindow* window, - PalBool clip) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->clipCursor(window, clip); -} - -PalResult PAL_CALL palGetCursorPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->getCursorPos(window, x, y); -} - -PalResult PAL_CALL palSetCursorPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->setCursorPos(window, x, y); -} - -PalResult PAL_CALL palSetWindowCursor( - PalWindow* window, - PalCursor* cursor) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->setWindowCursor(window, cursor); -} - -void* PAL_CALL palGetInstance() -{ - if (!s_Video.initialized) { - return nullptr; - } - - return s_Video.display; -} - -PalResult PAL_CALL palAttachWindow( - void* windowHandle, - PalWindow** outWindow) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!windowHandle) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->attachWindow(windowHandle, outWindow); -} - -PalResult PAL_CALL palDetachWindow( - PalWindow* window, - void** outWindowHandle) -{ - if (!s_Video.initialized) { - return PAL_RESULT_VIDEO_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_NULL_POINTER; - } - - return s_Video.backend->detachWindow(window, outWindowHandle); -} - -void PAL_CALL palSetPreferredInstance(void* instance) -{ - if (!s_Video.initialized && instance) { - s_Video.platformInstance = instance; - } -} - -#endif // __linux__ diff --git a/src/video/win32/pal_cursor_win32.c b/src/video/win32/pal_cursor_win32.c index ee21285f..a402be5b 100644 --- a/src/video/win32/pal_cursor_win32.c +++ b/src/video/win32/pal_cursor_win32.c @@ -6,7 +6,7 @@ */ #ifdef _WIN32 -#include "pal_video_common_win32.h" +#include "pal_video_win32.h" #include "pal_shared.h" PalResult PAL_CALL palCreateCursor( diff --git a/src/video/win32/pal_icon_win32.c b/src/video/win32/pal_icon_win32.c index adca2358..742befaa 100644 --- a/src/video/win32/pal_icon_win32.c +++ b/src/video/win32/pal_icon_win32.c @@ -6,7 +6,7 @@ */ #ifdef _WIN32 -#include "pal_video_common_win32.h" +#include "pal_video_win32.h" #include "pal_shared.h" PalResult PAL_CALL palCreateIcon( diff --git a/src/video/win32/pal_monitor_win32.c b/src/video/win32/pal_monitor_win32.c index a5dbe99b..3459fe28 100644 --- a/src/video/win32/pal_monitor_win32.c +++ b/src/video/win32/pal_monitor_win32.c @@ -6,7 +6,7 @@ */ #ifdef _WIN32 -#include "pal_video_common_win32.h" +#include "pal_video_win32.h" #include "pal_shared.h" #define MONITOR_DPI 0 diff --git a/src/video/win32/pal_video_win32.c b/src/video/win32/pal_video_win32.c index 6c635106..1cc7f50b 100644 --- a/src/video/win32/pal_video_win32.c +++ b/src/video/win32/pal_video_win32.c @@ -6,7 +6,7 @@ */ #ifdef _WIN32 -#include "pal_video_common_win32.h" +#include "pal_video_win32.h" #include "pal_shared.h" #include diff --git a/src/video/win32/pal_video_common_win32.h b/src/video/win32/pal_video_win32.h similarity index 92% rename from src/video/win32/pal_video_common_win32.h rename to src/video/win32/pal_video_win32.h index 962ccc9f..5e0048f2 100644 --- a/src/video/win32/pal_video_common_win32.h +++ b/src/video/win32/pal_video_win32.h @@ -5,9 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ +#ifndef _PAL_VIDEO_WIN32_H +#define _PAL_VIDEO_WIN32_H #ifdef _WIN32 -#ifndef _PAL_VIDEO_COMMON_WIN32_H -#define _PAL_VIDEO_COMMON_WIN32_H #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN @@ -103,7 +103,7 @@ typedef struct { WindowData* windowData; } VideoWin32; -static VideoWin32 s_Video = {0}; +extern VideoWin32 s_Video = {0}; -#endif // _PAL_VIDEO_COMMON_WIN32_H -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 +#endif // _PAL_VIDEO_WIN32_H \ No newline at end of file diff --git a/src/video/win32/pal_window_win32.c b/src/video/win32/pal_window_win32.c index 27eaaac3..a549d770 100644 --- a/src/video/win32/pal_window_win32.c +++ b/src/video/win32/pal_window_win32.c @@ -6,7 +6,7 @@ */ #ifdef _WIN32 -#include "pal_video_common_win32.h" +#include "pal_video_win32.h" #include "pal_shared.h" static WindowData* getFreeWindowData() diff --git a/tests/tests_main.c b/tests/tests_main.c index 7c4d14f2..18275bf8 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -16,15 +16,15 @@ int main(int argc, char** argv) // registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE == 1 - registerTest(platformTest, "Platform Test"); - registerTest(cpuTest, "CPU Test"); + // registerTest(platformTest, "Platform Test"); + // registerTest(cpuTest, "CPU Test"); #endif // PAL_HAS_SYSTEM_MODULE #if PAL_HAS_THREAD_MODULE == 1 - registerTest(threadTest, "Thread Test"); - registerTest(tlsTest, "TLS Test"); - registerTest(mutexTest, "Mutex Test"); - registerTest(condvarTest, "Condvar Test"); + // registerTest(threadTest, "Thread Test"); + // registerTest(tlsTest, "TLS Test"); + // registerTest(mutexTest, "Mutex Test"); + // registerTest(condvarTest, "Condvar Test"); #endif // PAL_HAS_THREAD_MODULE #if PAL_HAS_VIDEO_MODULE == 1 diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index 2fbfeb88..f60c4154 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -140,7 +140,7 @@ static inline void* wlRegistryBind( return (void*)id; } -static inline int wlRegistryAddListener( +static inline int registryAddListener( struct wl_registry* wl_registry, const struct wl_registry_listener* listener, void* data) @@ -148,7 +148,7 @@ static inline int wlRegistryAddListener( return s_wl_proxy_add_listener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); } -static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_display) +static inline struct wl_registry* displayGetRegistry(struct wl_display* wl_display) { struct wl_proxy* registry; registry = s_wl_proxy_marshal_flags( @@ -162,7 +162,7 @@ static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_dis return (struct wl_registry*)registry; } -static inline struct wl_surface* wlCompositorCreateSurface(struct wl_compositor* wl_compositor) +static inline struct wl_surface* compositorCreateSurface(struct wl_compositor* wl_compositor) { struct wl_proxy* id; id = s_wl_proxy_marshal_flags( @@ -176,7 +176,7 @@ static inline struct wl_surface* wlCompositorCreateSurface(struct wl_compositor* return (struct wl_surface*)id; } -static inline void wlSurfaceCommit(struct wl_surface* wl_surface) +static inline void surfaceCommit(struct wl_surface* wl_surface) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_surface, @@ -186,7 +186,7 @@ static inline void wlSurfaceCommit(struct wl_surface* wl_surface) 0); } -static inline void wlSurfaceDestroy(struct wl_surface* wl_surface) +static inline void surfaceDestroy(struct wl_surface* wl_surface) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_surface, @@ -196,7 +196,7 @@ static inline void wlSurfaceDestroy(struct wl_surface* wl_surface) WL_MARSHAL_FLAG_DESTROY); } -static inline struct wl_shm_pool* wlShmCreatePool( +static inline struct wl_shm_pool* shmCreatePool( struct wl_shm* wl_shm, int32_t fd, int32_t size) @@ -215,7 +215,7 @@ static inline struct wl_shm_pool* wlShmCreatePool( return (struct wl_shm_pool*)id; } -static inline void wlShmPoolDestroy(struct wl_shm_pool* wl_shm_pool) +static inline void shmPoolDestroy(struct wl_shm_pool* wl_shm_pool) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_shm_pool, @@ -225,7 +225,7 @@ static inline void wlShmPoolDestroy(struct wl_shm_pool* wl_shm_pool) WL_MARSHAL_FLAG_DESTROY); } -static inline struct wl_buffer* wlShmPoolCreateBuffer( +static inline struct wl_buffer* shmPoolCreateBuffer( struct wl_shm_pool* wl_shm_pool, int32_t offset, int32_t width, @@ -250,7 +250,7 @@ static inline struct wl_buffer* wlShmPoolCreateBuffer( return (struct wl_buffer*)id; } -static inline void wlBufferDestroy(struct wl_buffer* wl_buffer) +static inline void bufferDestroy(struct wl_buffer* wl_buffer) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_buffer, @@ -260,7 +260,7 @@ static inline void wlBufferDestroy(struct wl_buffer* wl_buffer) WL_MARSHAL_FLAG_DESTROY); } -static inline void wlSurfaceAttach( +static inline void surfaceAttach( struct wl_surface* wl_surface, struct wl_buffer* buffer, int32_t x, @@ -277,7 +277,7 @@ static inline void wlSurfaceAttach( y); } -static inline void wlSurfaceDamageBuffer( +static inline void surfaceDamageBuffer( struct wl_surface* wl_surface, int32_t x, int32_t y, @@ -481,8 +481,8 @@ static void openDisplayWayland() struct wl_display* display = s_wl_display_connect(nullptr); if (display) { - struct wl_registry* registry = wlDisplayGetRegistry(display); - wlRegistryAddListener(registry, &s_RegistryListener, nullptr); + struct wl_registry* registry = displayGetRegistry(display); + registryAddListener(registry, &s_RegistryListener, nullptr); s_wl_display_roundtrip(display); s_Display = display; } @@ -545,17 +545,17 @@ static struct wl_buffer* createShmBuffer( return nullptr; } - pool = wlShmCreatePool(s_Shm, fd, size); + pool = shmCreatePool(s_Shm, fd, size); if (!pool) { return nullptr; } - buffer = wlShmPoolCreateBuffer(pool, 0, width, height, stride, 1); + buffer = shmPoolCreateBuffer(pool, 0, width, height, stride, 1); if (!buffer) { return nullptr; } - wlShmPoolDestroy(pool); + shmPoolDestroy(pool); *outPixels = (uint32_t*)data; *outFd = fd; @@ -683,7 +683,7 @@ static PalWindowHandleInfo s_WinHandle; static void createDecoration() { - s_Decoration.surface = wlCompositorCreateSurface(s_Compositor); + s_Decoration.surface = compositorCreateSurface(s_Compositor); if (!s_Decoration.surface) { palLog(nullptr, "Failed to create wayland surface"); return; @@ -753,12 +753,12 @@ static void createDecoration() TITLEBAR_HEIGHT / 2, // half of the size of the title bar 0x0033AAAA); - wlSurfaceAttach(s_Decoration.surface, s_Decoration.buffer, 0, 0); - wlSurfaceDamageBuffer(s_Decoration.surface, 0, 0, width, TITLEBAR_HEIGHT); - wlSurfaceCommit(s_Decoration.surface); + surfaceAttach(s_Decoration.surface, s_Decoration.buffer, 0, 0); + surfaceDamageBuffer(s_Decoration.surface, 0, 0, width, TITLEBAR_HEIGHT); + surfaceCommit(s_Decoration.surface); // wayland requires the main surface to be committed as well - wlSurfaceCommit(s_WinHandle.nativeWindow); + surfaceCommit(s_WinHandle.nativeWindow); // draw window title // this example does not support unicode characters @@ -777,8 +777,8 @@ static void createDecoration() static void destroyDecoration() { wlSubsurfaceDestroy(s_Decoration.subsurface); - wlSurfaceDestroy(s_Decoration.surface); - wlBufferDestroy(s_Decoration.buffer); + surfaceDestroy(s_Decoration.surface); + bufferDestroy(s_Decoration.buffer); munmap((void*)s_Decoration.pixels, s_Decoration.size); close(s_Decoration.fd); } diff --git a/tests/video/native_instance_test.c b/tests/video/native_instance_test.c index 10f4028e..26b83a37 100644 --- a/tests/video/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -110,7 +110,7 @@ static inline void* wlRegistryBind( return (void*)id; } -static inline int wlRegistryAddListener( +static inline int registryAddListener( struct wl_registry* wl_registry, const struct wl_registry_listener* listener, void* data) @@ -118,7 +118,7 @@ static inline int wlRegistryAddListener( return s_wl_proxy_add_listener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); } -static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_display) +static inline struct wl_registry* displayGetRegistry(struct wl_display* wl_display) { struct wl_proxy* registry; registry = s_wl_proxy_marshal_flags( @@ -239,8 +239,8 @@ void* openDisplayWayland() registryInterface = dlsym(s_LibWayland, "wl_registry_interface"); struct wl_display* display = s_wl_display_connect(nullptr); if (display) { - s_Registry = wlDisplayGetRegistry(display); - wlRegistryAddListener(s_Registry, &s_RegistryListener, nullptr); + s_Registry = displayGetRegistry(display); + registryAddListener(s_Registry, &s_RegistryListener, nullptr); s_wl_display_roundtrip(display); } From 1d40317d55311b417012ddbb0fc9d0dfabcaf549 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 17 Jun 2026 11:06:46 +0000 Subject: [PATCH 271/372] test video rewrite win32 --- CHANGELOG.md | 3 +- include/pal/pal_video.h | 30 ++++--------- src/video/linux/pal_video_linux.c | 15 +++---- src/video/win32/pal_video_win32.c | 26 ++++++------ src/video/win32/pal_video_win32.h | 2 +- tests/graphics/clear_color_test.c | 2 +- tests/graphics/descriptor_indexing_test.c | 2 +- tests/graphics/geometry_test.c | 2 +- tests/graphics/indirect_draw_test.c | 2 +- tests/graphics/mesh_test.c | 2 +- tests/graphics/texture_test.c | 2 +- tests/graphics/triangle_test.c | 2 +- tests/opengl/opengl_context_test.c | 2 +- tests/opengl/opengl_fbconfig_test.c | 2 +- tests/opengl/opengl_multi_context_test.c | 2 +- tests/opengl/opengl_test.c | 2 +- tests/tests_main.c | 4 +- tests/video/attach_window_test.c | 14 +++--- tests/video/char_event_test.c | 18 ++++---- tests/video/cursor_test.c | 29 +++++-------- tests/video/custom_decoration_test.c | 52 +++++++++++------------ tests/video/icon_test.c | 27 +++++------- tests/video/input_window_test.c | 17 +++----- tests/video/monitor_mode_test.c | 9 ++-- tests/video/monitor_test.c | 7 ++- tests/video/native_instance_test.c | 20 ++++----- tests/video/native_integration_test.c | 14 +++--- tests/video/system_cursor_test.c | 27 +++++------- tests/video/video_test.c | 8 +--- tests/video/window_test.c | 19 +++------ 30 files changed, 158 insertions(+), 205 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa761f49..80d6319c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -156,6 +156,7 @@ palJoinThread(thread, &retval); - **Video:** **palGetWindowHandleInfo()** now takes an info parameter. - **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. - **Video:** **palGetMouseWheelDelta()** now takes floats instead of uint32_t. +- **Video:** **palInitVideo()** now takes a preferredInstance parameter. ### Removed - **Core:** Removed **PAL_RESULT_NULL_POINTER** result code. @@ -184,7 +185,7 @@ palJoinThread(thread, &retval); - **Video:** Removed **palGetWindowHandleInfoEx** function. - **Video:** Removed **palGetRawMouseWheelDelta** function. - +- **Video:** Removed **palSetPreferredInstance** function. ### Tests diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 47882534..fb83bfb0 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -599,11 +599,17 @@ typedef struct { * The allocator will not not copied, therefore the pointer must remain valid * until the video system is shutdown. The event driver must be valid to recieve * video events. + * + * If `preferredInstance` is nullptr, the video system creates one and control its lifetime. + * The provided instance will not be freed by the video system. + * `Linux`: This is the Display associated with the connection. + * `Windows`: This is the HINSTANCE of the process. * * @param[in] allocator Optional user-provided allocator. Set to nullptr to use * default. * @param[in] eventDriver Optional user-provided event driver. This is needed to * push video events. Set to nullptr to use default. + * @param[in] preferredInstance User-provided instance (eg. HINSTANCE). Can be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -612,11 +618,11 @@ typedef struct { * * @since 1.0 * @sa palShutdownVideo - * @sa palSetPreferredInstance */ PAL_API PalResult PAL_CALL palInitVideo( const PalAllocator* allocator, - PalEventDriver* eventDriver); + PalEventDriver* eventDriver, + void* preferredInstance); /** * @brief Shutdown the video system. @@ -1799,26 +1805,6 @@ PAL_API PalResult PAL_CALL palDetachWindow( PalWindow* window, void** outWindowHandle); -/** - * @brief Set the preferred instance the video system should use. - * - * Must be called before palInitVideo(). This will be ignored - * if the video system is already initialized. - * If there is no preferred instance set, the video system creates one. - * - * On Linux: This is the Display associated with the connection. - - * On Windows: This is the HINSTANCE of the process. - * - * Thread safety: Must be called from the main thread. - * - * @note The provided instance will not be freed by the video system. - * - * @since 1.3 - * @sa palInitVideo - */ -PAL_API void PAL_CALL palSetPreferredInstance(void* instance); - /** @} */ // end of pal_video group #endif // _PAL_VIDEO_H diff --git a/src/video/linux/pal_video_linux.c b/src/video/linux/pal_video_linux.c index cb0b752a..03896ff4 100644 --- a/src/video/linux/pal_video_linux.c +++ b/src/video/linux/pal_video_linux.c @@ -384,7 +384,8 @@ static void createScancodeTable() PalResult PAL_CALL palInitVideo( const PalAllocator* allocator, - PalEventDriver* eventDriver) + PalEventDriver* eventDriver, + void* preferredInstance) { if (s_Video.initialized) { return PAL_RESULT_SUCCESS; @@ -420,6 +421,11 @@ PalResult PAL_CALL palInitVideo( errno); } + // user provided instance + if (preferredInstance) { + s_Video.platformInstance = preferredInstance; + } + s_Video.className = "PAL"; if (x11) { #if PAL_HAS_X11_BACKEND == 1 @@ -1475,11 +1481,4 @@ PalResult PAL_CALL palDetachWindow( return s_Video.backend->detachWindow(window, outWindowHandle); } -void PAL_CALL palSetPreferredInstance(void* instance) -{ - if (!s_Video.initialized && instance) { - s_Video.platformInstance = instance; - } -} - #endif // __linux__ diff --git a/src/video/win32/pal_video_win32.c b/src/video/win32/pal_video_win32.c index 1cc7f50b..7ee0ec7e 100644 --- a/src/video/win32/pal_video_win32.c +++ b/src/video/win32/pal_video_win32.c @@ -46,6 +46,7 @@ static PendingEvent s_Event; static BYTE s_RawBuffer[4096] = {0}; static Mouse s_Mouse = {0}; static Keyboard s_Keyboard = {0}; +VideoWin32 s_Video = {0}; LRESULT CALLBACK videoProc( HWND hwnd, @@ -287,7 +288,7 @@ LRESULT CALLBACK videoProc( if (mode != PAL_DISPATCH_NONE) { PalEvent event = {0}; event.type = PAL_EVENT_MOUSE_WHEEL; - event.data = palPackInt32(delta, 0); + event.data = palPackFloat(s_Mouse.WheelX, 0); event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); } @@ -305,7 +306,7 @@ LRESULT CALLBACK videoProc( if (mode != PAL_DISPATCH_NONE) { PalEvent event = {0}; event.type = PAL_EVENT_MOUSE_WHEEL; - event.data = palPackInt32(0, delta); + event.data = palPackFloat(0, s_Mouse.WheelY); event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); } @@ -351,6 +352,9 @@ LRESULT CALLBACK videoProc( s_Mouse.dx += mouse->lLastX; s_Mouse.dy += mouse->lLastY; + float dx = (float)s_Mouse.dx; + float dy = (float)s_Mouse.dy; + if (s_Video.eventDriver) { PalEventDriver* driver = s_Video.eventDriver; PalEventType type = PAL_EVENT_MOUSE_DELTA; @@ -358,7 +362,7 @@ LRESULT CALLBACK videoProc( if (mode != PAL_DISPATCH_NONE) { PalEvent event = {0}; event.type = type; - event.data = palPackInt32(s_Mouse.dx, s_Mouse.dy); + event.data = palPackFloat(dx, dy); palPushEvent(driver, &event); } } @@ -757,7 +761,8 @@ static void createScancodeTable() PalResult PAL_CALL palInitVideo( const PalAllocator* allocator, - PalEventDriver* eventDriver) + PalEventDriver* eventDriver, + void* preferredInstance) { if (s_Video.initialized) { return PAL_RESULT_SUCCESS; @@ -774,8 +779,10 @@ PalResult PAL_CALL palInitVideo( s_Video.windowData = palAllocate(s_Video.allocator, sizeof(WindowData) * s_Video.maxWindowData, 0); - // get the instance - if (!s_Video.instance) { + // user provided instance + if (preferredInstance) { + s_Video.instance = preferredInstance; + } else { s_Video.instance = GetModuleHandleW(nullptr); } @@ -1101,13 +1108,6 @@ void PAL_CALL palGetMouseWheelDelta( } } -void PAL_CALL palSetPreferredInstance(void* instance) -{ - if (!s_Video.initialized && instance) { - s_Video.instance = instance; - } -} - void* PAL_CALL palGetInstance() { if (!s_Video.initialized) { diff --git a/src/video/win32/pal_video_win32.h b/src/video/win32/pal_video_win32.h index 5e0048f2..9057ede3 100644 --- a/src/video/win32/pal_video_win32.h +++ b/src/video/win32/pal_video_win32.h @@ -103,7 +103,7 @@ typedef struct { WindowData* windowData; } VideoWin32; -extern VideoWin32 s_Video = {0}; +extern VideoWin32 s_Video; #endif // _WIN32 #endif // _PAL_VIDEO_WIN32_H \ No newline at end of file diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index d702d9dc..adc23240 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -48,7 +48,7 @@ PalBool clearColorTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index b46c879d..55dd9722 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -98,7 +98,7 @@ PalBool descriptorIndexingTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index 0a21287d..d5c1b741 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -52,7 +52,7 @@ PalBool geometryTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 98c3dd59..9ec969ee 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -69,7 +69,7 @@ PalBool indirectDrawTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 995cfa82..29aff9ad 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -52,7 +52,7 @@ PalBool meshTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 3ecf9c13..60aabe68 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -91,7 +91,7 @@ PalBool textureTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index a670ef9c..dcb4598b 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -57,7 +57,7 @@ PalBool triangleTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/opengl/opengl_context_test.c b/tests/opengl/opengl_context_test.c index 8247186c..043c26aa 100644 --- a/tests/opengl/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -37,7 +37,7 @@ PalBool openglContextTest() // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must // be valid till the video system is shutdown - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/opengl/opengl_fbconfig_test.c b/tests/opengl/opengl_fbconfig_test.c index 7076f7ad..4f4c9010 100644 --- a/tests/opengl/opengl_fbconfig_test.c +++ b/tests/opengl/opengl_fbconfig_test.c @@ -8,7 +8,7 @@ static const char* g_BoolsToSting[2] = {"False", "True"}; PalBool openglFBConfigTest() { // initialize the video system and create a window - PalResult result = palInitVideo(nullptr, nullptr); + PalResult result = palInitVideo(nullptr, nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/opengl/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c index 523d9e0e..681d3c73 100644 --- a/tests/opengl/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -37,7 +37,7 @@ PalBool openglMultiContextTest() // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must // be valid till the video system is shutdown - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/opengl/opengl_test.c b/tests/opengl/opengl_test.c index 2db36be6..26336435 100644 --- a/tests/opengl/opengl_test.c +++ b/tests/opengl/opengl_test.c @@ -6,7 +6,7 @@ PalBool openglTest() { // initialize the video system and create a window - PalResult result = palInitVideo(nullptr, nullptr); + PalResult result = palInitVideo(nullptr, nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/tests_main.c b/tests/tests_main.c index 18275bf8..40cb31d5 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -39,13 +39,13 @@ int main(int argc, char** argv) // registerTest(attachWindowTest, "Attach Window Test"); // registerTest(charEventTest, "Char Event Test"); // registerTest(nativeIntegrationTest, "Native Integration Test"); - // registerTest(nativeInstanceTest, "Native Instance Test"); + registerTest(nativeInstanceTest, "Native Instance Test"); // registerTest(customDecorationTest, "Custom Decoration Test"); #endif // PAL_HAS_VIDEO_MODULE // This test can run without video system so long as your have a valid // window -#if PAL_HAS_OPENGL_MODULE == 1&& PAL_HAS_VIDEO_MODULE == 1 +#if PAL_HAS_OPENGL_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 // registerTest(openglTest, "Opengl Test"); // registerTest(openglFBConfigTest, "Opengl FBConfig Test"); // registerTest(openglContextTest, "Context Test"); diff --git a/tests/video/attach_window_test.c b/tests/video/attach_window_test.c index ff1ded7e..f49d0756 100644 --- a/tests/video/attach_window_test.c +++ b/tests/video/attach_window_test.c @@ -210,14 +210,16 @@ PalBool attachWindowTest() palLog(nullptr, "Press A to attach and D to detach window"); palLog(nullptr, "Press Escape or click close button to close Test"); - PalResult result; - - // event driver - PalEventDriver* eventDriver = nullptr; + // fill the event driver create info PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + eventDriverCreateInfo.allocator = nullptr; // default allocator + eventDriverCreateInfo.callback = nullptr; // no callback dispatch + eventDriverCreateInfo.queue = nullptr; // default queue + eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -226,7 +228,7 @@ PalBool attachWindowTest() // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must // be valid till the video system is shutdown - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/video/char_event_test.c b/tests/video/char_event_test.c index f99565e4..0a62cc06 100644 --- a/tests/video/char_event_test.c +++ b/tests/video/char_event_test.c @@ -5,17 +5,17 @@ PalBool charEventTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - - PalResult result; - PalWindow* window = nullptr; - PalWindowCreateInfo createInfo = {0}; - // event driver - PalEventDriver* eventDriver = nullptr; + // fill the event driver create info PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + eventDriverCreateInfo.allocator = nullptr; // default allocator + eventDriverCreateInfo.callback = nullptr; // no callback dispatch + eventDriverCreateInfo.queue = nullptr; // default queue + eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -24,13 +24,14 @@ PalBool charEventTest() // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must // be valid till the video system is shutdown - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; } // fill the create info struct + PalWindowCreateInfo createInfo = {0}; createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; @@ -46,6 +47,7 @@ PalBool charEventTest() } // create the window with the create info struct + PalWindow* window = nullptr; result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window"); diff --git a/tests/video/cursor_test.c b/tests/video/cursor_test.c index fd64a29d..dcaa9d0e 100644 --- a/tests/video/cursor_test.c +++ b/tests/video/cursor_test.c @@ -5,26 +5,17 @@ PalBool cursorTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - - PalResult result; - PalWindow* window = nullptr; - PalCursor* cursor = nullptr; - PalWindowCreateInfo createInfo = {0}; - PalCursorCreateInfo cursorCreateInfo = {0}; - PalBool running = PAL_FALSE; - - // event driver - PalEventDriver* eventDriver = nullptr; - PalEventDriverCreateInfo eventDriverCreateInfo = {0}; // fill the event driver create info + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator eventDriverCreateInfo.callback = nullptr; // for callback dispatch eventDriverCreateInfo.queue = nullptr; // default queue eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -33,7 +24,7 @@ PalBool cursorTest() // initialize the video system. We pass the event driver to recieve video // related events the video does not copy this, this must be valid till the // video system is shutdown - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; @@ -71,19 +62,22 @@ PalBool cursorTest() } // create cursor + PalCursorCreateInfo cursorCreateInfo = {0}; cursorCreateInfo.width = 32; cursorCreateInfo.height = 32; cursorCreateInfo.xHotspot = 0; cursorCreateInfo.yHotspot = 0; cursorCreateInfo.pixels = pixels; + PalCursor* cursor = nullptr; result = palCreateCursor(&cursorCreateInfo, &cursor); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window cursor"); return PAL_FALSE; } - + // fill the create info struct + PalWindowCreateInfo createInfo = {0}; createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; @@ -99,6 +93,7 @@ PalBool cursorTest() } // create the window with the create info struct + PalWindow* window = nullptr; result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window"); @@ -106,15 +101,13 @@ PalBool cursorTest() } // set the dispatch mode for window close event to recieve it - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); // polling - + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // set the cursor palSetWindowCursor(window, cursor); - running = PAL_TRUE; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index f60c4154..40bce9d7 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -119,7 +119,7 @@ static const struct wl_interface* surfaceInterface; static const struct wl_interface* bufferInterface; static const struct wl_interface* subsurfaceInterface; -static inline void* wlRegistryBind( +static inline void* registryBind( struct wl_registry* wl_registry, uint32_t name, const struct wl_interface* interface, @@ -296,7 +296,7 @@ static inline void surfaceDamageBuffer( height); } -static inline void wlSubcompositorDestroy(struct wl_subcompositor* wl_subcompositor) +static inline void subcompositorDestroy(struct wl_subcompositor* wl_subcompositor) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_subcompositor, @@ -306,7 +306,7 @@ static inline void wlSubcompositorDestroy(struct wl_subcompositor* wl_subcomposi WL_MARSHAL_FLAG_DESTROY); } -static inline struct wl_subsurface* wlSubcompositorGetSubsurface( +static inline struct wl_subsurface* subcompositorGetSubsurface( struct wl_subcompositor* wl_subcompositor, struct wl_surface* surface, struct wl_surface* parent) @@ -325,7 +325,7 @@ static inline struct wl_subsurface* wlSubcompositorGetSubsurface( return (struct wl_subsurface*)id; } -static inline void wlSubsurfaceDestroy(struct wl_subsurface* wl_subsurface) +static inline void subsurfaceDestroy(struct wl_subsurface* wl_subsurface) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_subsurface, @@ -335,7 +335,7 @@ static inline void wlSubsurfaceDestroy(struct wl_subsurface* wl_subsurface) WL_MARSHAL_FLAG_DESTROY); } -static inline void wlSubsurfaceSetPosition( +static inline void subsurfaceSetPosition( struct wl_subsurface* wl_subsurface, int32_t x, int32_t y) @@ -350,7 +350,7 @@ static inline void wlSubsurfaceSetPosition( y); } -static inline void wlSubsurfaceSetDesync(struct wl_subsurface* wl_subsurface) +static inline void subsurfaceSetDesync(struct wl_subsurface* wl_subsurface) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_subsurface, @@ -368,16 +368,16 @@ static void globalHandle( uint32_t version) { if (strcmp(interface, "wl_seat") == 0) { - s_Seat = wlRegistryBind(registry, name, seatInterface, 5); + s_Seat = registryBind(registry, name, seatInterface, 5); } else if (strcmp(interface, "wl_compositor") == 0) { - s_Compositor = wlRegistryBind(registry, name, compositorInterface, 4); + s_Compositor = registryBind(registry, name, compositorInterface, 4); } else if (strcmp(interface, "wl_subcompositor") == 0) { - s_Subcompositor = wlRegistryBind(registry, name, subCompositorInterface, 1); + s_Subcompositor = registryBind(registry, name, subCompositorInterface, 1); } else if (strcmp(interface, "wl_shm") == 0) { - s_Shm = wlRegistryBind(registry, name, shmInterface, 1); + s_Shm = registryBind(registry, name, shmInterface, 1); } } @@ -499,7 +499,7 @@ static void closeDisplayWayland() s_wl_proxy_destroy((struct wl_proxy*)s_Compositor); s_wl_proxy_destroy((struct wl_proxy*)s_Shm); s_wl_proxy_destroy((struct wl_proxy*)s_Seat); - wlSubcompositorDestroy(s_Subcompositor); + subcompositorDestroy(s_Subcompositor); } s_wl_display_disconnect((struct wl_display*)s_Display); @@ -689,7 +689,7 @@ static void createDecoration() return; } - s_Decoration.subsurface = wlSubcompositorGetSubsurface( + s_Decoration.subsurface = subcompositorGetSubsurface( s_Subcompositor, s_Decoration.surface, (struct wl_surface*)s_WinHandle.nativeWindow); @@ -700,8 +700,8 @@ static void createDecoration() } // make it soo that the decoration updates independently of the window - wlSubsurfaceSetDesync(s_Decoration.subsurface); - wlSubsurfaceSetPosition(s_Decoration.subsurface, 0, 0); + subsurfaceSetDesync(s_Decoration.subsurface); + subsurfaceSetPosition(s_Decoration.subsurface, 0, 0); // create decoration shm buffer int width = 640; @@ -776,7 +776,7 @@ static void createDecoration() static void destroyDecoration() { - wlSubsurfaceDestroy(s_Decoration.subsurface); + subsurfaceDestroy(s_Decoration.subsurface); surfaceDestroy(s_Decoration.surface); bufferDestroy(s_Decoration.buffer); munmap((void*)s_Decoration.pixels, s_Decoration.size); @@ -845,14 +845,16 @@ PalBool customDecorationTest() return PAL_FALSE; } - PalResult result; - - // create an event driver - PalEventDriver* eventDriver = nullptr; + // fill the event driver create info PalEventDriverCreateInfo eventDriverCreateInfo = {0}; - eventDriverCreateInfo.callback = onEvent; + eventDriverCreateInfo.allocator = nullptr; // default allocator + eventDriverCreateInfo.callback = nullptr; // no callback dispatch + eventDriverCreateInfo.queue = nullptr; // default queue + eventDriverCreateInfo.userData = nullptr; // null - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + // create the event driver + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -868,14 +870,11 @@ PalBool customDecorationTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_MOUSE_MOVE, PAL_DISPATCH_CALLBACK); palSetEventDispatchMode(eventDriver, PAL_EVENT_MONITOR_DPI_CHANGED, PAL_DISPATCH_CALLBACK); - // tell the video system to use out instance rather - // than creating a new one - palSetPreferredInstance((void*)s_Display); - // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must // be valid till the video system is shutdown - result = palInitVideo(nullptr, eventDriver); + // tell the video system to use out instance rather than creating a new one + result = palInitVideo(nullptr, eventDriver, (void*)s_Display); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; @@ -961,6 +960,7 @@ PalBool customDecorationTest() #include "tests.h" PalBool customDecorationTest() { + palLog(nullptr, "Custom decoration not supported"); return PAL_FALSE; } diff --git a/tests/video/icon_test.c b/tests/video/icon_test.c index 911d1fe1..0379f4f2 100644 --- a/tests/video/icon_test.c +++ b/tests/video/icon_test.c @@ -5,26 +5,17 @@ PalBool iconTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - - PalResult result; - PalWindow* window = nullptr; - PalIcon* icon = nullptr; - PalWindowCreateInfo createInfo = {0}; - PalIconCreateInfo iconCreateInfo = {0}; - PalBool running = PAL_FALSE; - - // event driver - PalEventDriver* eventDriver = nullptr; - PalEventDriverCreateInfo eventDriverCreateInfo = {0}; // fill the event driver create info + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator eventDriverCreateInfo.callback = nullptr; // for callback dispatch eventDriverCreateInfo.queue = nullptr; // default queue eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -33,7 +24,7 @@ PalBool iconTest() // initialize the video system. We pass the event driver to recieve video // related events the video does not copy this, this must be valid till the // video system is shutdown - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; @@ -71,10 +62,12 @@ PalBool iconTest() } // create icon + PalIconCreateInfo iconCreateInfo = {0}; iconCreateInfo.width = 32; iconCreateInfo.height = 32; iconCreateInfo.pixels = pixels; // can be loaded from an .ico file + PalIcon* icon = nullptr; result = palCreateIcon(&iconCreateInfo, &icon); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window icon"); @@ -82,6 +75,7 @@ PalBool iconTest() } // fill the create info struct + PalWindowCreateInfo createInfo = {0}; createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; @@ -90,6 +84,7 @@ PalBool iconTest() createInfo.title = "Icon Window"; // create the window with the create info struct + PalWindow* window = nullptr; result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window"); @@ -97,9 +92,7 @@ PalBool iconTest() } // set the dispatch mode for window close event to recieve it - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); // polling - + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // set the icon @@ -109,7 +102,7 @@ PalBool iconTest() return PAL_FALSE; } - running = PAL_TRUE; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); diff --git a/tests/video/input_window_test.c b/tests/video/input_window_test.c index c6175639..3693df68 100644 --- a/tests/video/input_window_test.c +++ b/tests/video/input_window_test.c @@ -394,24 +394,17 @@ static void PAL_CALL onEvent( PalBool inputWindowTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - - PalResult result; - PalWindow* window = nullptr; - PalWindowCreateInfo createInfo = {0}; - PalBool running = PAL_FALSE; - - // event driver - PalEventDriver* eventDriver = nullptr; - PalEventDriverCreateInfo eventDriverCreateInfo = {0}; // fill the event driver create info + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator eventDriverCreateInfo.callback = onEvent; // for callback dispatch eventDriverCreateInfo.queue = nullptr; // default queue eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -420,13 +413,14 @@ PalBool inputWindowTest() // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must // be valid till the video system is shutdown - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; } // fill the create info struct + PalWindowCreateInfo createInfo = {0}; createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; @@ -443,6 +437,7 @@ PalBool inputWindowTest() } // create the window with the create info struct + PalWindow* window = nullptr; result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window"); diff --git a/tests/video/monitor_mode_test.c b/tests/video/monitor_mode_test.c index 04f9e483..5ca1bc6a 100644 --- a/tests/video/monitor_mode_test.c +++ b/tests/video/monitor_mode_test.c @@ -4,18 +4,15 @@ PalBool monitorModeTest() { - PalMonitorInfo info; - int32_t count = 0; - int32_t modeCount = 0; - // initialize the video system - PalResult result = palInitVideo(nullptr, nullptr); + PalResult result = palInitVideo(nullptr, nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; } // get the number of connected monitors + int32_t count = 0; result = palEnumerateMonitors(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get query monitors"); @@ -46,6 +43,7 @@ PalBool monitorModeTest() } // get monitor info for every monitor and log the information + PalMonitorInfo info = {0}; for (int32_t i = 0; i < count; i++) { PalMonitor* monitor = monitors[i]; result = palGetMonitorInfo(monitor, &info); @@ -58,6 +56,7 @@ PalBool monitorModeTest() palLog(nullptr, "Monitor Name: %s", info.name); // get number of monitor modes + int32_t modeCount = 0; result = palEnumerateMonitorModes(monitor, &modeCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get query monitor modes"); diff --git a/tests/video/monitor_test.c b/tests/video/monitor_test.c index 9880f1e9..8f3a9f2f 100644 --- a/tests/video/monitor_test.c +++ b/tests/video/monitor_test.c @@ -4,17 +4,15 @@ PalBool monitorTest() { - PalMonitorInfo info; - int32_t count = 0; - // initialize the video system - PalResult result = palInitVideo(nullptr, nullptr); + PalResult result = palInitVideo(nullptr, nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; } // get the number of connected monitors + int32_t count = 0; result = palEnumerateMonitors(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get query monitors"); @@ -45,6 +43,7 @@ PalBool monitorTest() } // get monitor info for every monitor and log the information + PalMonitorInfo info = {0}; for (int32_t i = 0; i < count; i++) { PalMonitor* monitor = monitors[i]; result = palGetMonitorInfo(monitor, &info); diff --git a/tests/video/native_instance_test.c b/tests/video/native_instance_test.c index 26b83a37..509511fd 100644 --- a/tests/video/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -310,14 +310,16 @@ PalBool nativeInstanceTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - PalResult result; - - // event driver - PalEventDriver* eventDriver = nullptr; + // fill the event driver create info PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + eventDriverCreateInfo.allocator = nullptr; // default allocator + eventDriverCreateInfo.callback = nullptr; // no callback dispatch + eventDriverCreateInfo.queue = nullptr; // default queue + eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -330,15 +332,11 @@ PalBool nativeInstanceTest() return PAL_FALSE; } - // tell the video system to use out instance rather - // than creating a new one - // this can be set to the opengl system as well - palSetPreferredInstance(instance); - // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must // be valid till the video system is shutdown - result = palInitVideo(nullptr, eventDriver); + // tell the video system to use out instance rather than creating a new one + result = palInitVideo(nullptr, eventDriver, instance); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/video/native_integration_test.c b/tests/video/native_integration_test.c index 2572df50..d90cacc0 100644 --- a/tests/video/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -315,15 +315,17 @@ void getWindowTitle(PalWindowHandleInfo* windowInfo) PalBool nativeIntegrationTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - - PalResult result; - // event driver - PalEventDriver* eventDriver = nullptr; + // fill the event driver create info PalEventDriverCreateInfo eventDriverCreateInfo = {0}; + eventDriverCreateInfo.allocator = nullptr; // default allocator + eventDriverCreateInfo.callback = nullptr; // no callback dispatch + eventDriverCreateInfo.queue = nullptr; // default queue + eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -332,7 +334,7 @@ PalBool nativeIntegrationTest() // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must // be valid till the video system is shutdown - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; diff --git a/tests/video/system_cursor_test.c b/tests/video/system_cursor_test.c index 33082c58..db611c36 100644 --- a/tests/video/system_cursor_test.c +++ b/tests/video/system_cursor_test.c @@ -5,25 +5,17 @@ PalBool systemCursorTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - - PalResult result; - PalWindow* window = nullptr; - PalCursor* cursor = nullptr; - PalWindowCreateInfo createInfo = {0}; - PalBool running = PAL_FALSE; - - // event driver - PalEventDriver* eventDriver = nullptr; - PalEventDriverCreateInfo eventDriverCreateInfo = {0}; // fill the event driver create info + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator - eventDriverCreateInfo.callback = nullptr; // for callback dispatch + eventDriverCreateInfo.callback = nullptr; // no callback dispatch eventDriverCreateInfo.queue = nullptr; // default queue eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -32,7 +24,7 @@ PalBool systemCursorTest() // initialize the video system. We pass the event driver to recieve video // related events the video does not copy this, this must be valid till the // video system is shutdown - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; @@ -48,6 +40,7 @@ PalBool systemCursorTest() } // create system cursor + PalCursor* cursor = nullptr; result = palCreateCursorFrom(PAL_CURSOR_CROSS, &cursor); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window cursor"); @@ -55,6 +48,7 @@ PalBool systemCursorTest() } // fill the create info struct + PalWindowCreateInfo createInfo = {0}; createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; @@ -70,6 +64,7 @@ PalBool systemCursorTest() } // create the window with the create info struct + PalWindow* window = nullptr; result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window"); @@ -77,15 +72,13 @@ PalBool systemCursorTest() } // set the dispatch mode for window close event to recieve it - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, - PAL_DISPATCH_POLL); // polling - + palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); // set the cursor palSetWindowCursor(window, cursor); - running = PAL_TRUE; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); diff --git a/tests/video/video_test.c b/tests/video/video_test.c index 6988b859..fef72a7b 100644 --- a/tests/video/video_test.c +++ b/tests/video/video_test.c @@ -4,18 +4,14 @@ PalBool videoTest() { - palLog(nullptr, "Press Escape or click close button to close Test"); - - PalResult result; - // initialize the video system - result = palInitVideo(nullptr, nullptr); + PalResult result = palInitVideo(nullptr, nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; } - // get supported features. Now uses extended function + // get supported features PalVideoFeatures features = palGetVideoFeatures(); palLog(nullptr, "Supported Video Features:"); if (features & PAL_VIDEO_FEATURE_HIGH_DPI) { diff --git a/tests/video/window_test.c b/tests/video/window_test.c index fe41927a..d58fc07a 100644 --- a/tests/video/window_test.c +++ b/tests/video/window_test.c @@ -145,24 +145,17 @@ static void PAL_CALL onEvent( PalBool windowTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - - PalResult result; - PalWindow* window = nullptr; - PalWindowCreateInfo createInfo = {0}; - PalBool running = PAL_FALSE; - - // event driver - PalEventDriver* eventDriver = nullptr; - PalEventDriverCreateInfo eventDriverCreateInfo = {0}; // fill the event driver create info + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator eventDriverCreateInfo.callback = onEvent; // for callback dispatch eventDriverCreateInfo.queue = nullptr; // default queue eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -193,13 +186,14 @@ PalBool windowTest() // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must // be valid till the video system is shutdown - result = palInitVideo(nullptr, eventDriver); + result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; } // fill the create info struct + PalWindowCreateInfo createInfo = {0}; createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; @@ -251,6 +245,7 @@ PalBool windowTest() #endif // NO_MAXIMIZEBOX // create the window with the create info struct + PalWindow* window = nullptr; result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window"); @@ -268,7 +263,7 @@ PalBool windowTest() } #endif // MAKE_TRANSPARENT - running = PAL_TRUE; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); From 44547e9feddbf7e3ce4c2059a9b0c93431cf6f0e Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 17 Jun 2026 12:06:46 +0000 Subject: [PATCH 272/372] add system abi dump --- include/pal/pal_video.h | 2 +- tools/abi_dump/abi_dump.lua | 1 + tools/abi_dump/abi_dump_main.c | 4 + tools/abi_dump/dumps.h | 1 + tools/abi_dump/system_abi_dump.c | 147 +++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 tools/abi_dump/system_abi_dump.c diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index fb83bfb0..a4e7513a 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -616,7 +616,7 @@ typedef struct { * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palShutdownVideo */ PAL_API PalResult PAL_CALL palInitVideo( diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index aadc22b2..f23714cb 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -9,6 +9,7 @@ project "pal-abi-dump" "core_abi_dump.c", "event_abi_dump.c", "thread_abi_dump.c", + "system_abi_dump.c", "abi_dump_main.c" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 094e1fe1..52d6771c 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -85,6 +85,10 @@ int main(int argc, char** argv) threadABIDump(); } + if (dumpSystem) { + systemABIDump(); + } + if (dumpVersion) { palLog(nullptr, "PAL ABI dump %s", VERSION); } diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 48f8e2ee..015e7664 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -23,5 +23,6 @@ static const char* s_PassedString = "PASSED"; void coreABIDump(); void eventABIDump(); void threadABIDump(); +void systemABIDump(); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/system_abi_dump.c b/tools/abi_dump/system_abi_dump.c new file mode 100644 index 00000000..4fd15c92 --- /dev/null +++ b/tools/abi_dump/system_abi_dump.c @@ -0,0 +1,147 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "dumps.h" +#include "pal/pal_system.h" + +static void platformDump() +{ + uint32_t xSize = 60; + uint32_t xAlign = 4; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 4; + uint32_t xOffset3 = 8; + uint32_t xOffset4 = 12; + uint32_t xOffset5 = 16; + uint32_t xOffset6 = 28; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalPlatformInfo); + uint32_t yAlign = PAL_ALIGNOF(PalPlatformInfo); + uint32_t yOffset1 = offsetof(PalPlatformInfo, type); + uint32_t yOffset2 = offsetof(PalPlatformInfo, apiType); + uint32_t yOffset3 = offsetof(PalPlatformInfo, totalMemory); + uint32_t yOffset4 = offsetof(PalPlatformInfo, totalRAM); + uint32_t yOffset5 = offsetof(PalPlatformInfo, version); + uint32_t yOffset6 = offsetof(PalPlatformInfo, name); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xOffset6 == yOffset6 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalPlatformInfo"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "type @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "apiType @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "totalMemory @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "totalRAM @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "version @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "name @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void cpuDump() +{ + uint32_t xSize = 112; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 12; + uint32_t xOffset4 = 16; + uint32_t xOffset5 = 20; + uint32_t xOffset6 = 24; + uint32_t xOffset7 = 28; + uint32_t xOffset8 = 32; + uint32_t xOffset9 = 48; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalCPUInfo); + uint32_t yAlign = PAL_ALIGNOF(PalCPUInfo); + uint32_t yOffset1 = offsetof(PalCPUInfo, features); + uint32_t yOffset2 = offsetof(PalCPUInfo, architecture); + uint32_t yOffset3 = offsetof(PalCPUInfo, numCores); + uint32_t yOffset4 = offsetof(PalCPUInfo, cacheL1); + uint32_t yOffset5 = offsetof(PalCPUInfo, cacheL2); + uint32_t yOffset6 = offsetof(PalCPUInfo, cacheL3); + uint32_t yOffset7 = offsetof(PalCPUInfo, numLogicalProcessors); + uint32_t yOffset8 = offsetof(PalCPUInfo, vendor); + uint32_t yOffset9 = offsetof(PalCPUInfo, model); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xOffset6 == yOffset6 && + xOffset7 == yOffset7 && + xOffset8 == yOffset8 && + xOffset9 == yOffset9 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalCPUInfo"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "features @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "architecture @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "numCores @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "cacheL1 @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "cacheL2 @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "cacheL3 @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "numLogicalProcessors @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "vendor @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "model @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +void systemABIDump() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "System ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + platformDump(); + cpuDump(); +} \ No newline at end of file From 77e87a8b42687894861c8b9841d9ba99819d35ea Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 17 Jun 2026 14:03:17 +0000 Subject: [PATCH 273/372] add video abi dump --- tools/abi_dump/abi_dump.lua | 1 + tools/abi_dump/abi_dump_main.c | 4 + tools/abi_dump/dumps.h | 1 + tools/abi_dump/video_abi_dump.c | 409 ++++++++++++++++++++++++++++++++ 4 files changed, 415 insertions(+) create mode 100644 tools/abi_dump/video_abi_dump.c diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index f23714cb..1cd05635 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -10,6 +10,7 @@ project "pal-abi-dump" "event_abi_dump.c", "thread_abi_dump.c", "system_abi_dump.c", + "video_abi_dump.c", "abi_dump_main.c" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 52d6771c..ca97e6de 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -89,6 +89,10 @@ int main(int argc, char** argv) systemABIDump(); } + if (dumpVideo) { + videoABIDump(); + } + if (dumpVersion) { palLog(nullptr, "PAL ABI dump %s", VERSION); } diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 015e7664..9451d5b7 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -24,5 +24,6 @@ void coreABIDump(); void eventABIDump(); void threadABIDump(); void systemABIDump(); +void videoABIDump(); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c new file mode 100644 index 00000000..b58c68cc --- /dev/null +++ b/tools/abi_dump/video_abi_dump.c @@ -0,0 +1,409 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "dumps.h" +#include "pal/pal_video.h" + +static void monitorDump() +{ + uint32_t xSize = 64; + uint32_t xAlign = 4; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 4; + uint32_t xOffset3 = 8; + uint32_t xOffset4 = 12; + uint32_t xOffset5 = 16; + uint32_t xOffset6 = 20; + uint32_t xOffset7 = 24; + uint32_t xOffset8 = 28; + uint32_t xOffset9 = 32; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalMonitorInfo); + uint32_t yAlign = PAL_ALIGNOF(PalMonitorInfo); + uint32_t yOffset1 = offsetof(PalMonitorInfo, x); + uint32_t yOffset2 = offsetof(PalMonitorInfo, y); + uint32_t yOffset3 = offsetof(PalMonitorInfo, width); + uint32_t yOffset4 = offsetof(PalMonitorInfo, height); + uint32_t yOffset5 = offsetof(PalMonitorInfo, dpi); + uint32_t yOffset6 = offsetof(PalMonitorInfo, refreshRate); + uint32_t yOffset7 = offsetof(PalMonitorInfo, orientation); + uint32_t yOffset8 = offsetof(PalMonitorInfo, primary); + uint32_t yOffset9 = offsetof(PalMonitorInfo, name); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xOffset6 == yOffset6 && + xOffset7 == yOffset7 && + xOffset8 == yOffset8 && + xOffset9 == yOffset9 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalMonitorInfo"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "x @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "y @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "width @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "height @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "dpi @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "refreshRate @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "orientation @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "primary @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "name @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void monitorModeDump() +{ + uint32_t xSize = 16; + uint32_t xAlign = 4; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 4; + uint32_t xOffset3 = 8; + uint32_t xOffset4 = 12; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalMonitorMode); + uint32_t yAlign = PAL_ALIGNOF(PalMonitorMode); + uint32_t yOffset1 = offsetof(PalMonitorMode, bpp); + uint32_t yOffset2 = offsetof(PalMonitorMode, refreshRate); + uint32_t yOffset3 = offsetof(PalMonitorMode, width); + uint32_t yOffset4 = offsetof(PalMonitorMode, height); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalMonitorMode"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "bpp @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "refreshRate @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "width @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "height @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void flashDump() +{ + uint32_t xSize = 16; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 12; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalFlashInfo); + uint32_t yAlign = PAL_ALIGNOF(PalFlashInfo); + uint32_t yOffset1 = offsetof(PalFlashInfo, flags); + uint32_t yOffset2 = offsetof(PalFlashInfo, interval); + uint32_t yOffset3 = offsetof(PalFlashInfo, count); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalFlashInfo"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "flags @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "interval @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "count @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void iconDump() +{ + uint32_t xSize = 16; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 12; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalIconCreateInfo); + uint32_t yAlign = PAL_ALIGNOF(PalIconCreateInfo); + uint32_t yOffset1 = offsetof(PalIconCreateInfo, pixels); + uint32_t yOffset2 = offsetof(PalIconCreateInfo, width); + uint32_t yOffset3 = offsetof(PalIconCreateInfo, height); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalIconCreateInfo"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "pixels @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "width @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "height @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void cursorDump() +{ + uint32_t xSize = 24; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 12; + uint32_t xOffset4 = 16; + uint32_t xOffset5 = 20; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalCursorCreateInfo); + uint32_t yAlign = PAL_ALIGNOF(PalCursorCreateInfo); + uint32_t yOffset1 = offsetof(PalCursorCreateInfo, pixels); + uint32_t yOffset2 = offsetof(PalCursorCreateInfo, width); + uint32_t yOffset3 = offsetof(PalCursorCreateInfo, height); + uint32_t yOffset4 = offsetof(PalCursorCreateInfo, xHotspot); + uint32_t yOffset5 = offsetof(PalCursorCreateInfo, yHotspot); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalCursorCreateInfo"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "pixels @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "width @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "height @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "xHotspot @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "yHotspot @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void windowInfoDump() +{ + uint32_t xSize = 40; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 16; + uint32_t xOffset4 = 24; + uint32_t xOffset5 = 32; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalWindowHandleInfo); + uint32_t yAlign = PAL_ALIGNOF(PalWindowHandleInfo); + uint32_t yOffset1 = offsetof(PalWindowHandleInfo, nativeDisplay); + uint32_t yOffset2 = offsetof(PalWindowHandleInfo, nativeWindow); + uint32_t yOffset3 = offsetof(PalWindowHandleInfo, nativeHandle1); + uint32_t yOffset4 = offsetof(PalWindowHandleInfo, nativeHandle2); + uint32_t yOffset5 = offsetof(PalWindowHandleInfo, nativeHandle3); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalWindowHandleInfo"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "nativeDisplay @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "nativeWindow @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "nativeHandle1 @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "nativeHandle2 @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "nativeHandle3 @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void windowDump() +{ + uint32_t xSize = 48; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 16; + uint32_t xOffset4 = 24; + uint32_t xOffset5 = 28; + uint32_t xOffset6 = 32; + uint32_t xOffset7 = 36; + uint32_t xOffset8 = 40; + uint32_t xOffset9 = 44; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalWindowCreateInfo); + uint32_t yAlign = PAL_ALIGNOF(PalWindowCreateInfo); + uint32_t yOffset1 = offsetof(PalWindowCreateInfo, style); + uint32_t yOffset2 = offsetof(PalWindowCreateInfo, title); + uint32_t yOffset3 = offsetof(PalWindowCreateInfo, monitor); + uint32_t yOffset4 = offsetof(PalWindowCreateInfo, width); + uint32_t yOffset5 = offsetof(PalWindowCreateInfo, height); + uint32_t yOffset6 = offsetof(PalWindowCreateInfo, show); + uint32_t yOffset7 = offsetof(PalWindowCreateInfo, maximized); + uint32_t yOffset8 = offsetof(PalWindowCreateInfo, minimized); + uint32_t yOffset9 = offsetof(PalWindowCreateInfo, center); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xOffset6 == yOffset6 && + xOffset7 == yOffset7 && + xOffset8 == yOffset8 && + xOffset9 == yOffset9 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "PalWindowCreateInfo"); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "style @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "title @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "monitor @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "width @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "height @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "show @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "maximized @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "minimized @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "center @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +void videoABIDump() +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Video ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + monitorDump(); + monitorModeDump(); + flashDump(); + iconDump(); + cursorDump(); + windowInfoDump(); + windowDump(); +} \ No newline at end of file From 594a9231341fba4a397d91a600d4b0380ee3e617 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 17 Jun 2026 15:50:23 +0000 Subject: [PATCH 274/372] rewrite opengl API --- CHANGELOG.md | 5 +- include/pal/pal_graphics.h | 6 -- include/pal/pal_opengl.h | 155 +++++++++++++++++-------------------- include/pal/pal_video.h | 6 -- 4 files changed, 73 insertions(+), 99 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80d6319c..c1e0bf7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -152,6 +152,8 @@ palJoinThread(thread, &retval); - **Thread:** **palJoinThread()** now takes a void** for retval parameter. - **Opengl:** **palEnumerateGLFBConfigs()** now does not take glWindow parameter anymore. +- **Video:** **palInitGL()** now takes a instance parameter. +- **Opengl:** rename **PalGLRelease** to **PalGLReleaseBehavior**. - **Video:** **palGetWindowHandleInfo()** now takes an info parameter. - **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. @@ -181,10 +183,11 @@ palJoinThread(thread, &retval); - **Core:** Removed **PAL_RESULT_INVALID_GL_CONTEXT** result code. - **Core:** Removed **PAL_RESULT_INVALID_FBCONFIG_BACKEND** result code. +- **Opengl:** Removed **palGLSetInstance** function. + - **Video:** Removed **palGetVideoFeaturesEx** function. - **Video:** Removed **palGetWindowHandleInfoEx** function. - **Video:** Removed **palGetRawMouseWheelDelta** function. - - **Video:** Removed **palSetPreferredInstance** function. ### Tests diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 7936f4ce..899ef567 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3975,9 +3975,6 @@ PAL_API void PAL_CALL palShutdownGraphics(); * Allocate memory for the PalAdapter array and passed in the count and the allocated array. If * the count of the array is less than the number of adapters, PAL will write upto that limit. * - * If the count is 0 and the PalAdapter array is nullptr, the function fails - * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. - * * The adapter handles must not be freed by the user, they are managed by the * graphics system. Users are required to cache this, and call this function again * if adapters are added or removed which is rare except for virtual ones. @@ -4440,9 +4437,6 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); * Allocate memory for the PalFormatInfo array and passed in the count and the allocated array. If * the count of the array is less than the number of formats, PAL will write upto that limit. * - * If the count is 0 and the PalFormatInfo array is nullptr, the function fails - * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. - * * @param[in] adapter Adapter to query formats on. * @param[in, out] count Capacity of the PalFormatInfo array. * @param[out] outFormats User allocated array of PalFormatInfo. diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index bdeddd33..c2245bad 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -23,6 +23,33 @@ #define PAL_GL_APIENTRY #endif // _WIN32 +#define PAL_GL_VENDOR_NAME_SIZE 32 +#define PAL_GL_VERSION_NAME_SIZE 64 +#define PAL_GL_GRAPHICS_CARD_NAME_SIZE 64 + +#define PAL_GL_EXTENSION_CREATE_CONTEXT (1ULL << 0) +#define PAL_GL_EXTENSION_CONTEXT_PROFILE (1ULL << 1) +#define PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2 (1ULL << 2) +#define PAL_GL_EXTENSION_ROBUSTNESS (1ULL << 3) +#define PAL_GL_EXTENSION_NO_ERROR (1ULL << 4) +#define PAL_GL_EXTENSION_PIXEL_FORMAT (1ULL << 5) +#define PAL_GL_EXTENSION_MULTISAMPLE (1ULL << 6) +#define PAL_GL_EXTENSION_SWAP_CONTROL (1ULL << 7) +#define PAL_GL_EXTENSION_FLUSH_CONTROL (1ULL << 8) +#define PAL_GL_EXTENSION_COLORSPACE_SRGB (1ULL << 9) + +#define PAL_GL_PROFILE_NONE 0 +#define PAL_GL_PROFILE_CORE 1 +#define PAL_GL_PROFILE_COMPATIBILITY 2 +#define PAL_GL_PROFILE_ES 3 + +#define PAL_GL_CONTEXT_RESET_NONE 0 +#define PAL_GL_CONTEXT_RESET_NO_NOTIFICATION 1 +#define PAL_GL_CONTEXT_RESET_LOSE_CONTEXT 2 + +#define PAL_GL_RELEASE_BEHAVIOR_NONE 0 +#define PAL_GL_RELEASE_BEHAVIOR_FLUSH 1 + /** * @struct PalGLContext * @brief Opaque handle to an opengl context. @@ -38,20 +65,9 @@ typedef struct PalGLContext PalGLContext; * All opengl extensions follow the format `PAL_GL_EXTENSION_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ -typedef enum { - PAL_GL_EXTENSION_CREATE_CONTEXT = (1ULL << 0), /**< Modern context.*/ - PAL_GL_EXTENSION_CONTEXT_PROFILE = (1ULL << 1), - PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2 = (1ULL << 2), - PAL_GL_EXTENSION_ROBUSTNESS = (1ULL << 3), /**< Reset behaviour.*/ - PAL_GL_EXTENSION_NO_ERROR = (1ULL << 4), /**< No errors*/ - PAL_GL_EXTENSION_PIXEL_FORMAT = (1ULL << 5), /**< Modern PalGLFBConfig.*/ - PAL_GL_EXTENSION_MULTISAMPLE = (1ULL << 6), /**< Multisample FBConfigs.*/ - PAL_GL_EXTENSION_SWAP_CONTROL = (1ULL << 7), /**< Vsync.*/ - PAL_GL_EXTENSION_FLUSH_CONTROL = (1ULL << 8), /**< Release behavior.*/ - PAL_GL_EXTENSION_COLORSPACE_SRGB = (1ULL << 9) /**< Standard RGB.*/ -} PalGLExtensions; +typedef uint64_t PalGLExtensions; /** * @typedef PalGLProfile @@ -60,14 +76,9 @@ typedef enum { * All opengl profiles follow the format `PAL_GL_PROFILE_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ -typedef enum { - PAL_GL_PROFILE_NONE, /**< Default profile.*/ - PAL_GL_PROFILE_CORE, /**< PAL_GL_EXTENSION_CONTEXT_PROFILE.*/ - PAL_GL_PROFILE_COMPATIBILITY, /**< PAL_GL_EXTENSION_CONTEXT_PROFILE.*/ - PAL_GL_PROFILE_ES /**< PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2.*/ -} PalGLProfile; +typedef uint32_t PalGLProfile; /** * @typedef PalGLContextReset @@ -76,61 +87,54 @@ typedef enum { * All context reset behavior follow the format `PAL_GL_CONTEXT_RESET_**` * for consistency and API use. * - * @since 1.0 + * @since 2.0 */ -typedef enum { - PAL_GL_CONTEXT_RESET_NONE, /**< Default reset behaviour.*/ - PAL_GL_CONTEXT_RESET_NO_NOTIFICATION, /**< PAL_GL_EXTENSION_ROBUSTNESS.*/ - PAL_GL_CONTEXT_RESET_LOSE_CONTEXT /**< PAL_GL_EXTENSION_ROBUSTNESS.*/ -} PalGLContextReset; +typedef uint32_t PalGLContextReset; /** - * @typedef PalGLRelease + * @typedef PalGLReleaseBehavior * @brief Opengl context release behavior. This is not a bitmask. * * All opengl context release behavior follow the format * `PAL_GL_RELEASE_BEHAVIOR_**` for consistency and API use. * - * @since 1.0 + * @since 2.0 */ -typedef enum { - PAL_GL_RELEASE_BEHAVIOR_NONE, /**< Default release behaviour..*/ - PAL_GL_RELEASE_BEHAVIOR_FLUSH /**< PAL_GL_EXTENSION_FLUSH_CONTROL.*/ -} PalGLRelease; +typedef uint32_t PalGLReleaseBehavior; /** * @struct PalGLInfo * @brief Information about the opengl driver. * - * @since 1.0 + * @since 2.0 */ typedef struct { PalGLExtensions extensions; - uint32_t major; /**< Version major.*/ - uint32_t minor; /**< Version minor.*/ - char vendor[32]; /**< Graphics card vendor name (eg. Intel).*/ - char graphicsCard[64]; /**< Graphics card name.*/ - char version[64]; /**< Version string (major, minor, build).*/ + uint32_t major; + uint32_t minor; + char vendor[PAL_GL_VENDOR_NAME_SIZE]; + char graphicsCard[PAL_GL_GRAPHICS_CARD_NAME_SIZE]; + char version[PAL_GL_VERSION_NAME_SIZE]; } PalGLInfo; /** * @struct PalGLFBConfig * @brief Information about an opengl framebuffer. * - * @since 1.0 + * @since 2.0 */ typedef struct { PalBool doubleBuffer; PalBool stereo; PalBool sRGB; - uint16_t index; /**< Driver index. Must not be changed.*/ + uint16_t index; uint16_t redBits; uint16_t greenBits; uint16_t blueBits; uint16_t alphaBits; uint16_t depthBits; uint16_t stencilBits; - uint16_t samples; /**< PAL_GL_EXTENSION_MULTISAMPLE or 1.*/ + uint16_t samples; } PalGLFBConfig; /** @@ -153,20 +157,20 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 + * @since 2.0 */ typedef struct { - PalBool forward; /**< Forward compatible context.*/ - PalBool noError; /**< No error context.*/ - PalBool debug; /**< Debug context. */ - uint16_t major; /** major version.*/ - uint16_t minor; /** minor version.*/ - PalGLProfile profile; /**< see PalGLProfile.*/ - PalGLContextReset reset; /**< see PalGLContextReset.*/ - PalGLRelease release; /**< see PalGLRelease.*/ - PalGLContext* shareContext; /**< Can be nullptr.*/ - const PalGLFBConfig* fbConfig; /**< Must not be nullptr.*/ - const PalGLWindow* window; /** Must not be nullptr.*/ + const PalGLWindow* window; + const PalGLFBConfig* fbConfig; + PalGLContext* shareContext; + PalGLProfile profile; + PalGLContextReset reset; + PalGLReleaseBehavior release; + PalBool forward; + PalBool noError; + PalBool debug; + uint32_t major; + uint32_t minor; } PalGLContextCreateInfo; /** @@ -177,20 +181,28 @@ typedef struct { * * The allocator will not not copied, therefore the pointer must remain valid * until the opengl system is shutdown. + * + * `instance` must not be nullptr and will not be freed by the opengl system. It must be valid until + * palShutdownGL() is called. + * `Linux`: This is the Display associated with the connection. + * `Windows`: This is the HINSTANCE of the process. * * @param[in] allocator Optional user-provided allocator. Set to nullptr to use * default. + * @param[in] instance The instance the opengl system will be tied to (eg. XDisplay). + * Must not be nullptr. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palShutdownGL - * @sa palGLSetInstance */ -PAL_API PalResult PAL_CALL palInitGL(const PalAllocator* allocator); +PAL_API PalResult PAL_CALL palInitGL( + const PalAllocator* allocator, + void* instance); /** * @brief Shutdown the opengl system. @@ -230,10 +242,6 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); * array is less than the number of supported PalGLFBConfigs, PAL will write * upto that limit. * - * If the count is 0 and the PalGLFBConfigs array is nullptr, the function fails - * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. - * - * @param[in] glWindow Set to nullptr. * @param[in, out] count Capacity of the PalGLFBConfig array. * @param[out] configs User allocated array of PalGLFBConfig. * @@ -242,11 +250,10 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palInitGL */ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( - PalGLWindow* glWindow, int32_t* count, PalGLFBConfig* configs); @@ -334,10 +341,6 @@ PAL_API void PAL_CALL palDestroyGLContext(PalGLContext* context); * used to create the context, this function fails and returns * `PAL_RESULT_INVALID_GL_WINDOW`. * - * If the window was created with a different display other than the one - * passed to the opengl system, this function fails and returns - * `PAL_RESULT_INVALID_GL_WINDOW`. see palGLSetInstance() - * * @param[in] glWindow Pointer to the opengl window. * @param[in] context Pointer to the context to make current. * @@ -412,26 +415,6 @@ PAL_API PalResult PAL_CALL palSwapBuffers( */ PAL_API PalResult PAL_CALL palSetSwapInterval(int32_t interval); -/** - * @brief Set the native application instance or display for the opengl system. - * - * This must be called before palInitGL() is called. if palInitGL() is called - * before this function, - * it fails and returns `PAL_RESULT_PLATFORM_FAILURE` will be returned. - * - * On Linux: This is the Display associated with the connection. - - * On Windows: This is the HINSTANCE of the process. - * - * Thread safety: Thread safe. - * - * @note The provided instance will not be freed by the opengl system. - * - * @since 1.3 - * @sa palInitGL - */ -PAL_API void PAL_CALL palGLSetInstance(void* instance); - /** * @brief Get the backend of the opengl system. * diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index a4e7513a..dd1f4b27 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -710,9 +710,6 @@ PAL_API PalResult PAL_CALL palSetFBConfig( * array is less than the number of connected monitors, PAL will write upto that * limit. * - * If the count is 0 and the PalMonitor array is nullptr, the function fails - * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. - * * The monitor handles must not be freed by the user, they are managed by the * platform (OS). Users are required to cache this, and call this function again * if monitors are added or removed. @@ -789,9 +786,6 @@ PAL_API PalResult PAL_CALL palGetMonitorInfo( * count of the array is less than the number of supported monitor display * modes, PAL will write upto that limit. * - * If the count is 0 and the PalMonitorMode array is nullptr, the function fails - * and returns `PAL_RESULT_INSUFFICIENT_BUFFER`. - * * @param[in] monitor Monitor to query display modes on. * @param[in, out] count Capacity of the PalMonitorMode array. * @param[out] modes User allocated array of PalMonitorMode. From eec2d27ac3ae636a9c000fa06b964501d3401c43 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 18 Jun 2026 00:54:07 +0000 Subject: [PATCH 275/372] test video rewrite wayland --- CHANGELOG.md | 1 + README.md | 4 - include/pal/pal_video.h | 2 + pal.lua | 1 + premake5.lua | 1 - src/video/linux/pal_backends_linux.h | 236 +++ src/video/linux/pal_video_linux.c | 219 +- src/video/linux/wayland/pal_cursor_wayland.c | 19 +- src/video/linux/wayland/pal_video_wayland.c | 1207 ++++++++++- src/video/linux/wayland/pal_wayland.h | 21 + src/video/linux/wayland/pal_wayland_helper.c | 15 - src/video/linux/wayland/pal_wayland_helper.h | 1888 ----------------- .../linux/wayland/pal_wayland_protocols.c | 214 ++ .../linux/wayland/pal_wayland_protocols.h | 680 ++++++ src/video/linux/wayland/pal_window_wayland.c | 85 +- src/video/linux/x11/pal_monitor_x11.c | 16 +- src/video/linux/x11/pal_video_x11.c | 10 +- src/video/linux/x11/pal_window_x11.c | 23 +- src/video/linux/x11/pal_x11.h | 15 + tests/tests_main.c | 4 +- tests/video/custom_decoration_test.c | 75 +- tests/video/native_instance_test.c | 8 +- tools/abi_dump/video_abi_dump.c | 44 +- 23 files changed, 2504 insertions(+), 2284 deletions(-) create mode 100644 src/video/linux/pal_backends_linux.h delete mode 100644 src/video/linux/wayland/pal_wayland_helper.c delete mode 100644 src/video/linux/wayland/pal_wayland_helper.h create mode 100644 src/video/linux/wayland/pal_wayland_protocols.c create mode 100644 src/video/linux/wayland/pal_wayland_protocols.h diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e0bf7c..8d8a9eaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -159,6 +159,7 @@ palJoinThread(thread, &retval); - **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. - **Video:** **palGetMouseWheelDelta()** now takes floats instead of uint32_t. - **Video:** **palInitVideo()** now takes a preferredInstance parameter. +- **Video:** **PalWindowCreateInfo()** now takes `appName` and `instanceName` optional fields. ### Removed - **Core:** Removed **PAL_RESULT_NULL_POINTER** result code. diff --git a/README.md b/README.md index 8ce33eef..b27c340e 100644 --- a/README.md +++ b/README.md @@ -119,10 +119,6 @@ For more detailed examples, see the [tests folder](./tests) tests folder, which PAL is written in **C99** and uses Premake as its build system. Configure modules via [pal_config.lua](./pal_config.lua). See [pal_config.h](./include/pal/pal_config.h) to see the reflection of modules that will be built. -// TODO: docs -const char* resName = getenv("RESOURCE_NAME"); -const char* resClass = getenv("RESOURCE_CLASS"); - **Windows** ```bash premake\premake5.exe gmake # generate Makefiles (default: GCC) diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index dd1f4b27..ff23f15f 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -582,6 +582,8 @@ typedef struct { PalWindowStyle style; /**< Window style.*/ const char* title; /**< Title in UTF-8 encoding.*/ PalMonitor* monitor; /**< Set to nullptr to use primary monitor.*/ + const char* appName; /**< If nullptr, `PAL` will be used.*/ + const char* instanceName; /**< If nullptr, `title` will be used.*/ uint32_t width; /**< Width in pixels.*/ uint32_t height; /**< Width in pixels.*/ PalBool show; /**< Show after creation.*/ diff --git a/pal.lua b/pal.lua index 8f0ff898..25b6e73f 100644 --- a/pal.lua +++ b/pal.lua @@ -153,6 +153,7 @@ project "PAL" "src/video/linux/wayland/pal_icon_wayland.c", "src/video/linux/wayland/pal_monitor_wayland.c", "src/video/linux/wayland/pal_window_wayland.c", + "src/video/linux/wayland/pal_wayland_protocols.c", "src/video/linux/wayland/pal_video_wayland.c", "src/video/linux/pal_video_linux.c" diff --git a/premake5.lua b/premake5.lua index f742b002..73732541 100644 --- a/premake5.lua +++ b/premake5.lua @@ -53,7 +53,6 @@ local function generateVscodeProperties() end for _, define in ipairs(prj.defines or {}) do - print(define) table.insert(prjDefines, define) end end diff --git a/src/video/linux/pal_backends_linux.h b/src/video/linux/pal_backends_linux.h new file mode 100644 index 00000000..f7c1c985 --- /dev/null +++ b/src/video/linux/pal_backends_linux.h @@ -0,0 +1,236 @@ +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_BACKENDS_LINUX_H +#define _PAL_BACKENDS_LINUX_H +#ifdef __linux__ + +#include "pal/pal_video.h" + +// ================================================== +// X11 +// ================================================== + +PalResult xInitVideo(); +void xShutdownVideo(); +void xUpdateVideo(); + +PalResult xSetFBConfig(const int, PalFBConfigBackend); +PalResult xEnumerateMonitors(int32_t*, PalMonitor**); +PalResult xGetPrimaryMonitor(PalMonitor**); +PalResult xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); +PalResult xEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); +PalResult xGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult xSetMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult xValidateMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult xSetMonitorOrientation(PalMonitor*, PalOrientation); + +PalResult xCreateWindow(const PalWindowCreateInfo*, PalWindow**); +void xDestroyWindow(PalWindow*); +PalResult xMaximizeWindow(PalWindow*); +PalResult xMinimizeWindow(PalWindow*); +PalResult xRestoreWindow(PalWindow*); +PalResult xShowWindow(PalWindow*); +PalResult xHideWindow(PalWindow*); +PalResult xFlashWindow(PalWindow*, const PalFlashInfo*); +PalResult xGetWindowStyle(PalWindow*, PalWindowStyle*); +PalResult xGetWindowMonitor(PalWindow*, PalMonitor**); +PalResult xGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); +PalResult xGetWindowPos(PalWindow*, int32_t*, int32_t*); +PalResult xGetWindowSize(PalWindow*, uint32_t*, uint32_t*); +PalResult xGetWindowState(PalWindow*, PalWindowState*); +PalBool xIsWindowVisible(PalWindow*); +PalWindow* xGetFocusWindow(); +PalResult xGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); +PalResult xSetWindowOpacity(PalWindow*, float); +PalResult xSetWindowStyle(PalWindow*, PalWindowStyle); +PalResult xSetWindowTitle(PalWindow*, const char*); +PalResult xSetWindowPos(PalWindow*, int32_t, int32_t); +PalResult xSetWindowSize(PalWindow*, uint32_t, uint32_t); +PalResult xSetFocusWindow(PalWindow*); + +PalResult xCreateIcon(const PalIconCreateInfo*, PalIcon**); +void xDestroyIcon(PalIcon*); +PalResult xSetWindowIcon(PalWindow*, PalIcon*); + +PalResult xCreateCursor(const PalCursorCreateInfo*, PalCursor**); +PalResult xCreateCursorFrom(PalCursorType, PalCursor**); +void xDestroyCursor(PalCursor*); +void xShowCursor(PalBool); +PalResult xClipCursor(PalWindow*, PalBool); +PalResult xGetCursorPos(PalWindow*, int32_t*, int32_t*); +PalResult xSetCursorPos(PalWindow*, int32_t, int32_t); +PalResult xSetWindowCursor(PalWindow*, PalCursor*); + +PalResult xAttachWindow(void*, PalWindow**); +PalResult xDetachWindow(PalWindow*, void**); + +static Backend s_XBackend = { + .shutdownVideo = xShutdownVideo, + .updateVideo = xUpdateVideo, + .setFBConfig = xSetFBConfig, + .enumerateMonitors = xEnumerateMonitors, + .getMonitorInfo = xGetMonitorInfo, + .getPrimaryMonitor = xGetPrimaryMonitor, + .enumerateMonitorModes = xEnumerateMonitorModes, + .getCurrentMonitorMode = xGetCurrentMonitorMode, + .setMonitorMode = xSetMonitorMode, + .validateMonitorMode = xValidateMonitorMode, + .setMonitorOrientation = xSetMonitorOrientation, + + .createWindow = xCreateWindow, + .destroyWindow = xDestroyWindow, + .maximizeWindow = xMaximizeWindow, + .minimizeWindow = xMinimizeWindow, + .restoreWindow = xRestoreWindow, + .showWindow = xShowWindow, + .hideWindow = xHideWindow, + .flashWindow = xFlashWindow, + .getWindowStyle = xGetWindowStyle, + .getWindowMonitor = xGetWindowMonitor, + .getWindowTitle = xGetWindowTitle, + .getWindowPos = xGetWindowPos, + .getWindowSize = xGetWindowSize, + .getWindowState = xGetWindowState, + .isWindowVisible = xIsWindowVisible, + .getFocusWindow = xGetFocusWindow, + .getWindowHandleInfo = xGetWindowHandleInfo, + .setWindowOpacity = xSetWindowOpacity, + .setWindowStyle = xSetWindowStyle, + .setWindowTitle = xSetWindowTitle, + .setWindowPos = xSetWindowPos, + .setWindowSize = xSetWindowSize, + .setFocusWindow = xSetFocusWindow, + + .createIcon = xCreateIcon, + .destroyIcon = xDestroyIcon, + .setWindowIcon = xSetWindowIcon, + + .createCursor = xCreateCursor, + .createCursorFrom = xCreateCursorFrom, + .destroyCursor = xDestroyCursor, + .showCursor = xShowCursor, + .clipCursor = xClipCursor, + .getCursorPos = xGetCursorPos, + .setCursorPos = xSetCursorPos, + .setWindowCursor = xSetWindowCursor, + + .attachWindow = xAttachWindow, + .detachWindow = xDetachWindow}; + +// ================================================== +// Wayland +// ================================================== + +PalResult wlInitVideo(); +void wlShutdownVideo(); +void wlUpdateVideo(); + +PalResult wlSetFBConfig(const int, PalFBConfigBackend); +PalResult wlEnumerateMonitors(int32_t*, PalMonitor**); +PalResult wlGetPrimaryMonitor(PalMonitor**); +PalResult wlGetMonitorInfo(PalMonitor*, PalMonitorInfo*); +PalResult wlEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); +PalResult wlGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult wlSetMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult wlValidateMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult wlSetMonitorOrientation(PalMonitor*, PalOrientation); + +PalResult wlCreateWindow(const PalWindowCreateInfo*, PalWindow**); +void wlDestroyWindow(PalWindow*); +PalResult wlMaximizeWindow(PalWindow*); +PalResult wlMinimizeWindow(PalWindow*); +PalResult wlRestoreWindow(PalWindow*); +PalResult wlShowWindow(PalWindow*); +PalResult wlHideWindow(PalWindow*); +PalResult wlFlashWindow(PalWindow*, const PalFlashInfo*); +PalResult wlGetWindowStyle(PalWindow*, PalWindowStyle*); +PalResult wlGetWindowMonitor(PalWindow*, PalMonitor**); +PalResult wlGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); +PalResult wlGetWindowPos(PalWindow*, int32_t*, int32_t*); +PalResult wlGetWindowSize(PalWindow*, uint32_t*, uint32_t*); +PalResult wlGetWindowState(PalWindow*, PalWindowState*); +PalBool wlIsWindowVisible(PalWindow*); +PalWindow* wlGetFocusWindow(); +PalResult wlGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); +PalResult wlSetWindowOpacity(PalWindow*, float); +PalResult wlSetWindowStyle(PalWindow*, PalWindowStyle); +PalResult wlSetWindowTitle(PalWindow*, const char*); +PalResult wlSetWindowPos(PalWindow*, int32_t, int32_t); +PalResult wlSetWindowSize(PalWindow*, uint32_t, uint32_t); +PalResult wlSetFocusWindow(PalWindow*); + +PalResult wlCreateIcon(const PalIconCreateInfo*, PalIcon**); +void wlDestroyIcon(PalIcon*); +PalResult wlSetWindowIcon(PalWindow*, PalIcon*); + +PalResult wlCreateCursor(const PalCursorCreateInfo*, PalCursor**); +PalResult wlCreateCursorFrom(PalCursorType, PalCursor**); +void wlDestroyCursor(PalCursor*); +void wlShowCursor(PalBool); +PalResult wlClipCursor(PalWindow*, PalBool); +PalResult wlGetCursorPos(PalWindow*, int32_t*, int32_t*); +PalResult wlSetCursorPos(PalWindow*, int32_t, int32_t); +PalResult wlSetWindowCursor(PalWindow*, PalCursor*); + +PalResult wlAttachWindow(void*, PalWindow**); +PalResult wlDetachWindow(PalWindow*, void**); + +static Backend s_wlBackend = { + .shutdownVideo = wlShutdownVideo, + .updateVideo = wlUpdateVideo, + .setFBConfig = wlSetFBConfig, + .enumerateMonitors = wlEnumerateMonitors, + .getMonitorInfo = wlGetMonitorInfo, + .getPrimaryMonitor = wlGetPrimaryMonitor, + .enumerateMonitorModes = wlEnumerateMonitorModes, + .getCurrentMonitorMode = wlGetCurrentMonitorMode, + .setMonitorMode = wlSetMonitorMode, + .validateMonitorMode = wlValidateMonitorMode, + .setMonitorOrientation = wlSetMonitorOrientation, + + .createWindow = wlCreateWindow, + .destroyWindow = wlDestroyWindow, + .maximizeWindow = wlMaximizeWindow, + .minimizeWindow = wlMinimizeWindow, + .restoreWindow = wlRestoreWindow, + .showWindow = wlShowWindow, + .hideWindow = wlHideWindow, + .flashWindow = wlFlashWindow, + .getWindowStyle = wlGetWindowStyle, + .getWindowMonitor = wlGetWindowMonitor, + .getWindowTitle = wlGetWindowTitle, + .getWindowPos = wlGetWindowPos, + .getWindowSize = wlGetWindowSize, + .getWindowState = wlGetWindowState, + .isWindowVisible = wlIsWindowVisible, + .getFocusWindow = wlGetFocusWindow, + .getWindowHandleInfo = wlGetWindowHandleInfo, + .setWindowOpacity = wlSetWindowOpacity, + .setWindowStyle = wlSetWindowStyle, + .setWindowTitle = wlSetWindowTitle, + .setWindowPos = wlSetWindowPos, + .setWindowSize = wlSetWindowSize, + .setFocusWindow = wlSetFocusWindow, + + .createIcon = wlCreateIcon, + .destroyIcon = wlDestroyIcon, + .setWindowIcon = wlSetWindowIcon, + + .createCursor = wlCreateCursor, + .createCursorFrom = wlCreateCursorFrom, + .destroyCursor = wlDestroyCursor, + .showCursor = wlShowCursor, + .clipCursor = wlClipCursor, + .getCursorPos = wlGetCursorPos, + .setCursorPos = wlSetCursorPos, + .setWindowCursor = wlSetWindowCursor, + + .attachWindow = wlAttachWindow, + .detachWindow = wlDetachWindow}; + +#endif // __linux__ +#endif // _PAL_BACKENDS_LINUX_H \ No newline at end of file diff --git a/src/video/linux/pal_video_linux.c b/src/video/linux/pal_video_linux.c index 03896ff4..a5e31262 100644 --- a/src/video/linux/pal_video_linux.c +++ b/src/video/linux/pal_video_linux.c @@ -8,6 +8,7 @@ #ifdef __linux__ #include "pal_video_linux.h" #include "pal_shared.h" +#include "pal_backends_linux.h" #include #include @@ -16,224 +17,6 @@ VideoLinux s_Video = {0}; Mouse s_Mouse = {0}; Keyboard s_Keyboard = {0}; -#if PAL_HAS_X11_BACKEND == 1 -PalResult xInitVideo(); -void xShutdownVideo(); -void xUpdateVideo(); -PalResult xSetFBConfig(const int, PalFBConfigBackend); -PalResult xEnumerateMonitors(int32_t*, PalMonitor**); -PalResult xGetPrimaryMonitor(PalMonitor**); -PalResult xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); -PalResult xEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); -PalResult xGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult xSetMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult xValidateMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult xSetMonitorOrientation(PalMonitor*, PalOrientation); - -PalResult xCreateWindow(const PalWindowCreateInfo*, PalWindow**); -void xDestroyWindow(PalWindow*); -PalResult xMaximizeWindow(PalWindow*); -PalResult xMinimizeWindow(PalWindow*); -PalResult xRestoreWindow(PalWindow*); -PalResult xShowWindow(PalWindow*); -PalResult xHideWindow(PalWindow*); -PalResult xFlashWindow(PalWindow*, const PalFlashInfo*); -PalResult xGetWindowStyle(PalWindow*, PalWindowStyle*); -PalResult xGetWindowMonitor(PalWindow*, PalMonitor**); -PalResult xGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); -PalResult xGetWindowPos(PalWindow*, int32_t*, int32_t*); -PalResult xGetWindowSize(PalWindow*, uint32_t*, uint32_t*); -PalResult xGetWindowState(PalWindow*, PalWindowState*); -PalBool xIsWindowVisible(PalWindow*); -PalWindow* xGetFocusWindow(); -PalResult xGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); -PalResult xSetWindowOpacity(PalWindow*, float); -PalResult xSetWindowStyle(PalWindow*, PalWindowStyle); -PalResult xSetWindowTitle(PalWindow*, const char*); -PalResult xSetWindowPos(PalWindow*, int32_t, int32_t); -PalResult xSetWindowSize(PalWindow*, uint32_t, uint32_t); -PalResult xSetFocusWindow(PalWindow*); - -PalResult xCreateIcon(const PalIconCreateInfo*, PalIcon**); -void xDestroyIcon(PalIcon*); -PalResult xSetWindowIcon(PalWindow*, PalIcon*); - -PalResult xCreateCursor(const PalCursorCreateInfo*, PalCursor**); -PalResult xCreateCursorFrom(PalCursorType, PalCursor**); -void xDestroyCursor(PalCursor*); -void xShowCursor(PalBool); -PalResult xClipCursor(PalWindow*, PalBool); -PalResult xGetCursorPos(PalWindow*, int32_t*, int32_t*); -PalResult xSetCursorPos(PalWindow*, int32_t, int32_t); -PalResult xSetWindowCursor(PalWindow*, PalCursor*); - -PalResult xAttachWindow(void*, PalWindow**); -PalResult xDetachWindow(PalWindow*, void**); - -static Backend s_XBackend = { - .shutdownVideo = xShutdownVideo, - .updateVideo = xUpdateVideo, - .setFBConfig = xSetFBConfig, - .enumerateMonitors = xEnumerateMonitors, - .getMonitorInfo = xGetMonitorInfo, - .getPrimaryMonitor = xGetPrimaryMonitor, - .enumerateMonitorModes = xEnumerateMonitorModes, - .getCurrentMonitorMode = xGetCurrentMonitorMode, - .setMonitorMode = xSetMonitorMode, - .validateMonitorMode = xValidateMonitorMode, - .setMonitorOrientation = xSetMonitorOrientation, - - .createWindow = xCreateWindow, - .destroyWindow = xDestroyWindow, - .maximizeWindow = xMaximizeWindow, - .minimizeWindow = xMinimizeWindow, - .restoreWindow = xRestoreWindow, - .showWindow = xShowWindow, - .hideWindow = xHideWindow, - .flashWindow = xFlashWindow, - .getWindowStyle = xGetWindowStyle, - .getWindowMonitor = xGetWindowMonitor, - .getWindowTitle = xGetWindowTitle, - .getWindowPos = xGetWindowPos, - .getWindowSize = xGetWindowSize, - .getWindowState = xGetWindowState, - .isWindowVisible = xIsWindowVisible, - .getFocusWindow = xGetFocusWindow, - .getWindowHandleInfo = xGetWindowHandleInfo, - .setWindowOpacity = xSetWindowOpacity, - .setWindowStyle = xSetWindowStyle, - .setWindowTitle = xSetWindowTitle, - .setWindowPos = xSetWindowPos, - .setWindowSize = xSetWindowSize, - .setFocusWindow = xSetFocusWindow, - - .createIcon = xCreateIcon, - .destroyIcon = xDestroyIcon, - .setWindowIcon = xSetWindowIcon, - - .createCursor = xCreateCursor, - .createCursorFrom = xCreateCursorFrom, - .destroyCursor = xDestroyCursor, - .showCursor = xShowCursor, - .clipCursor = xClipCursor, - .getCursorPos = xGetCursorPos, - .setCursorPos = xSetCursorPos, - .setWindowCursor = xSetWindowCursor, - - .attachWindow = xAttachWindow, - .detachWindow = xDetachWindow}; - -#endif // PAL_HAS_X11_BACKEND - -#if PAL_HAS_WAYLAND_BACKEND == 1 -PalResult wlInitVideo(); -void wlShutdownVideo(); -void wlUpdateVideo(); -PalResult wlSetFBConfig(const int, PalFBConfigBackend); -PalResult wlEnumerateMonitors(int32_t*, PalMonitor**); -PalResult wlGetPrimaryMonitor(PalMonitor**); -PalResult wlGetMonitorInfo(PalMonitor*, PalMonitorInfo*); -PalResult wlEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); -PalResult wlGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult wlSetMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult wlValidateMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult wlSetMonitorOrientation(PalMonitor*, PalOrientation); - -PalResult wlCreateWindow(const PalWindowCreateInfo*, PalWindow**); -void wlDestroyWindow(PalWindow*); -PalResult wlMaximizeWindow(PalWindow*); -PalResult wlMinimizeWindow(PalWindow*); -PalResult wlRestoreWindow(PalWindow*); -PalResult wlShowWindow(PalWindow*); -PalResult wlHideWindow(PalWindow*); -PalResult wlFlashWindow(PalWindow*, const PalFlashInfo*); -PalResult wlGetWindowStyle(PalWindow*, PalWindowStyle*); -PalResult wlGetWindowMonitor(PalWindow*, PalMonitor**); -PalResult wlGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); -PalResult wlGetWindowPos(PalWindow*, int32_t*, int32_t*); -PalResult wlGetWindowSize(PalWindow*, uint32_t*, uint32_t*); -PalResult wlGetWindowState(PalWindow*, PalWindowState*); -PalBool wlIsWindowVisible(PalWindow*); -PalWindow* wlGetFocusWindow(); -PalResult wlGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); -PalResult wlSetWindowOpacity(PalWindow*, float); -PalResult wlSetWindowStyle(PalWindow*, PalWindowStyle); -PalResult wlSetWindowTitle(PalWindow*, const char*); -PalResult wlSetWindowPos(PalWindow*, int32_t, int32_t); -PalResult wlSetWindowSize(PalWindow*, uint32_t, uint32_t); -PalResult wlSetFocusWindow(PalWindow*); - -PalResult wlCreateIcon(const PalIconCreateInfo*, PalIcon**); -void wlDestroyIcon(PalIcon*); -PalResult wlSetWindowIcon(PalWindow*, PalIcon*); - -PalResult wlCreateCursor(const PalCursorCreateInfo*, PalCursor**); -PalResult wlCreateCursorFrom(PalCursorType, PalCursor**); -void wlDestroyCursor(PalCursor*); -void wlShowCursor(PalBool); -PalResult wlClipCursor(PalWindow*, PalBool); -PalResult wlGetCursorPos(PalWindow*, int32_t*, int32_t*); -PalResult wlSetCursorPos(PalWindow*, int32_t, int32_t); -PalResult wlSetWindowCursor(PalWindow*, PalCursor*); - -PalResult wlAttachWindow(void*, PalWindow**); -PalResult wlDetachWindow(PalWindow*, void**); - -static Backend s_wlBackend = { - .shutdownVideo = wlShutdownVideo, - .updateVideo = wlUpdateVideo, - .setFBConfig = wlSetFBConfig, - .enumerateMonitors = wlEnumerateMonitors, - .getMonitorInfo = wlGetMonitorInfo, - .getPrimaryMonitor = wlGetPrimaryMonitor, - .enumerateMonitorModes = wlEnumerateMonitorModes, - .getCurrentMonitorMode = wlGetCurrentMonitorMode, - .setMonitorMode = wlSetMonitorMode, - .validateMonitorMode = wlValidateMonitorMode, - .setMonitorOrientation = wlSetMonitorOrientation, - - .createWindow = wlCreateWindow, - .destroyWindow = wlDestroyWindow, - .maximizeWindow = wlMaximizeWindow, - .minimizeWindow = wlMinimizeWindow, - .restoreWindow = wlRestoreWindow, - .showWindow = wlShowWindow, - .hideWindow = wlHideWindow, - .flashWindow = wlFlashWindow, - .getWindowStyle = wlGetWindowStyle, - .getWindowMonitor = wlGetWindowMonitor, - .getWindowTitle = wlGetWindowTitle, - .getWindowPos = wlGetWindowPos, - .getWindowSize = wlGetWindowSize, - .getWindowState = wlGetWindowState, - .isWindowVisible = wlIsWindowVisible, - .getFocusWindow = wlGetFocusWindow, - .getWindowHandleInfo = wlGetWindowHandleInfo, - .setWindowOpacity = wlSetWindowOpacity, - .setWindowStyle = wlSetWindowStyle, - .setWindowTitle = wlSetWindowTitle, - .setWindowPos = wlSetWindowPos, - .setWindowSize = wlSetWindowSize, - .setFocusWindow = wlSetFocusWindow, - - .createIcon = wlCreateIcon, - .destroyIcon = wlDestroyIcon, - .setWindowIcon = wlSetWindowIcon, - - .createCursor = wlCreateCursor, - .createCursorFrom = wlCreateCursorFrom, - .destroyCursor = wlDestroyCursor, - .showCursor = wlShowCursor, - .clipCursor = wlClipCursor, - .getCursorPos = wlGetCursorPos, - .setCursorPos = wlSetCursorPos, - .setWindowCursor = wlSetWindowCursor, - - .attachWindow = wlAttachWindow, - .detachWindow = wlDetachWindow}; - -#endif // PAL_HAS_WAYLAND_BACKEND - static int compareModes( const void* a, const void* b) diff --git a/src/video/linux/wayland/pal_cursor_wayland.c b/src/video/linux/wayland/pal_cursor_wayland.c index 8a0540dc..b849eac0 100644 --- a/src/video/linux/wayland/pal_cursor_wayland.c +++ b/src/video/linux/wayland/pal_cursor_wayland.c @@ -8,7 +8,8 @@ #ifdef __linux__ #if PAL_HAS_WAYLAND_BACKEND == 1 -#include "pal_wayland_helper.h" +#include "pal_wayland.h" +#include "pal_wayland_protocols.h" #include "pal_shared.h" PalResult wlCreateCursor( @@ -24,7 +25,7 @@ PalResult wlCreateCursor( errno); } - cursor->surface = compositorCreateSurface(s_Wl.compositor); + cursor->surface = wlCompositorCreateSurface(s_Wl.compositor); if (!cursor->surface) { return palMakeResult( PAL_RESULT_PLATFORM_FAILURE, @@ -40,8 +41,8 @@ PalResult wlCreateCursor( errno); } - surfaceAttach(cursor->surface, cursor->buffer, 0, 0); - surfaceCommit(cursor->surface); + wlSurfaceAttach(cursor->surface, cursor->buffer, 0, 0); + wlSurfaceCommit(cursor->surface); cursor->hotspotX = info->xHotspot; cursor->hotspotY = info->yHotspot; @@ -99,7 +100,7 @@ PalResult wlCreateCursorFrom( errno); } - cursor->surface = compositorCreateSurface(s_Wl.compositor); + cursor->surface = wlCompositorCreateSurface(s_Wl.compositor); if (!cursor->surface) { return palMakeResult( PAL_RESULT_PLATFORM_FAILURE, @@ -108,8 +109,8 @@ PalResult wlCreateCursorFrom( } cursor->buffer = s_Wl.cursorImageGetBuffer(wlCursor->images[0]); - surfaceAttach(cursor->surface, cursor->buffer, 0, 0); - surfaceCommit(cursor->surface); + wlSurfaceAttach(cursor->surface, cursor->buffer, 0, 0); + wlSurfaceCommit(cursor->surface); cursor->hotspotX = wlCursor->images[0]->hotspot_x; cursor->hotspotY = wlCursor->images[0]->hotspot_y; @@ -120,8 +121,8 @@ PalResult wlCreateCursorFrom( void wlDestroyCursor(PalCursor* cursor) { WaylandCursor* waylandCursor = (WaylandCursor*)cursor; - bufferDestroy(waylandCursor->buffer); - surfaceDestroy(waylandCursor->surface); + wlBufferDestroy(waylandCursor->buffer); + wlSurfaceDestroy(waylandCursor->surface); palFree(s_Video.allocator, waylandCursor); } diff --git a/src/video/linux/wayland/pal_video_wayland.c b/src/video/linux/wayland/pal_video_wayland.c index c0a8ea87..e2418eac 100644 --- a/src/video/linux/wayland/pal_video_wayland.c +++ b/src/video/linux/wayland/pal_video_wayland.c @@ -8,32 +8,1118 @@ #ifdef __linux__ #if PAL_HAS_WAYLAND_BACKEND == 1 -#include "pal_wayland_helper.h" +#include "pal_wayland.h" +#include "pal_wayland_protocols.h" #include "pal_shared.h" #include +#include +#include Wayland s_Wl = {0}; +// ================================================== +// Helpers +// ================================================== + +static int createShmFile(uint64_t size) +{ + char template[] = "/tmp/pal-shm-XXXXXX"; + int fd = mkstemp(template); + if (fd < 0) { + return -1; + } + + unlink(template); + if (ftruncate(fd, size) < 0) { + return -1; + } + + return fd; +} + +struct wl_buffer* createShmBuffer( + int width, + int height, + const uint8_t* pixels, + PalBool cursor) +{ + int stride = width * 4; + uint64_t size = stride * height; + struct wl_buffer* buffer = nullptr; + struct wl_shm_pool* pool = nullptr; + void* data = nullptr; + + int fd = createShmFile(size); + if (fd == -1) { + return nullptr; + } + + data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + return nullptr; + } + + enum wl_shm_format format = WL_SHM_FORMAT_XRGB8888; + if (cursor) { + format = WL_SHM_FORMAT_ARGB8888; + uint32_t* dataPixels = (uint32_t*)data; + + // convert from RGBA8 to ARGB32 + for (int i = 0; i < width * height; i++) { + uint8_t r = pixels[i * 4 + 0]; // Red + uint8_t g = pixels[i * 4 + 1]; // Green + uint8_t b = pixels[i * 4 + 2]; // Blue + uint8_t a = pixels[i * 4 + 3]; // Alpha + + // clang-format off + dataPixels[i] = ((unsigned long)a << 24) | + ((unsigned long)r << 16) | + ((unsigned long)g << 8) | + ((unsigned long)b); + // clang-format on + } + + } else { + memset(data, 0xFF, size); // white + } + + pool = wlShmCreatePool(s_Wl.shm, fd, size); + if (!pool) { + return nullptr; + } + + buffer = wlShmPoolCreateBuffer(pool, 0, width, height, stride, format); + if (!buffer) { + return nullptr; + } + + wlShmPoolDestroy(pool); + munmap(data, size); + close(fd); + return buffer; +} + +// ================================================== +// Registry +// ================================================== + +extern struct wl_interface xdg_wm_base_interface; + +static void globalHandle( + void* data, + struct wl_registry* registry, + uint32_t name, + const char* interface, + uint32_t version) +{ + if (s_Wl.checkFeatures) { + PalVideoFeatures features = 0; + features |= PAL_VIDEO_FEATURE_HIGH_DPI; + features |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; + features |= PAL_VIDEO_FEATURE_MULTI_MONITORS; + features |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; + features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; + features |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; + + s_Video.features = features; + s_Wl.checkFeatures = PAL_FALSE; + } + + if (strcmp(interface, "wl_compositor") == 0) { + s_Wl.compositor = wlRegistryBind(registry, name, s_Wl.compositorInterface, 4); + + } else if (strcmp(interface, "xdg_wm_base") == 0) { + s_Wl.xdgBase = wlRegistryBind(registry, name, &xdg_wm_base_interface, 1); + + xdgWmBaseAddListener(s_Wl.xdgBase, &s_WmBaseListener, nullptr); + + } else if (strcmp(interface, "wl_shm") == 0) { + s_Wl.shm = wlRegistryBind(registry, name, s_Wl.shmInterface, 1); + + } else if (strcmp(interface, "wl_seat") == 0) { + s_Wl.seat = wlRegistryBind(registry, name, s_Wl.seatInterface, 5); + + wlSeatAddListener(s_Wl.seat, &s_SeatListener, nullptr); + + } else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) { + s_Wl.decorationManager = + wlRegistryBind(registry, name, &zxdg_decoration_manager_v1_interface, 1); + + s_Video.features |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; + + } else if (strcmp(interface, "wl_output") == 0) { + // wayland does not let use query monitors directly + // so we enumerate and store at init and update the + // cache when a monitor is added or removed + MonitorData* monitorData = getFreeMonitorData(); + if (!monitorData) { + return; + } + + struct wl_output* output = nullptr; + output = wlRegistryBind(s_Wl.registry, name, s_Wl.outputInterface, 3); + wlOutputAddListener(output, &s_OutputListener, monitorData); + + monitorData->wlName = name; + monitorData->monitor = (PalMonitor*)output; + s_Wl.monitorCount++; + } +} + +static void globalRemove( + void* data, + struct wl_registry* registry, + uint32_t name) +{ + for (int i = 0; i < s_Video.maxMonitorData; ++i) { + if (s_Video.monitorData[i].used && s_Video.monitorData[i].wlName == name) { + MonitorData* data = &s_Video.monitorData[i]; + data->used = PAL_FALSE; + s_Wl.proxyDestroy((struct wl_proxy*)data->monitor); + s_Wl.monitorCount--; + } + } +} + +// ================================================== +// Output +// ================================================== + +static void outputGeometry( + void* data, + struct wl_output* output, + int32_t x, + int32_t y, + int32_t, // we dont need physical size + int32_t, // we dont need physical size + int32_t, // we dont need subpixel + const char* make, + const char* model, + int32_t transform) +{ + MonitorData* monitorData = data; + monitorData->x = x; + monitorData->y = y; + + switch (transform) { + case WL_OUTPUT_TRANSFORM_NORMAL: + case WL_OUTPUT_TRANSFORM_180: { + monitorData->orientation = PAL_ORIENTATION_LANDSCAPE; + break; + } + + case WL_OUTPUT_TRANSFORM_90: + case WL_OUTPUT_TRANSFORM_270: { + monitorData->orientation = PAL_ORIENTATION_PORTRAIT; + break; + } + + case WL_OUTPUT_TRANSFORM_FLIPPED: + case WL_OUTPUT_TRANSFORM_FLIPPED_180: { + monitorData->orientation = PAL_ORIENTATION_LANDSCAPE_FLIPPED; + break; + } + + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_FLIPPED_270: { + monitorData->orientation = PAL_ORIENTATION_PORTRAIT_FLIPPED; + break; + } + } + + snprintf(monitorData->name, 32, "%s %s", make, model); +} + +static void outputMode( + void* data, + struct wl_output* output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh) +{ + MonitorData* monitorData = data; + if (flags & WL_OUTPUT_MODE_CURRENT) { + monitorData->w = width; + monitorData->h = height; + monitorData->refreshRate = (refresh + 500) / 1000; + + // wayland only sends the current mode + monitorData->mode.bpp = 0; + monitorData->mode.width = width; + monitorData->mode.height = height; + monitorData->mode.refreshRate = (refresh + 500) / 1000; + } +} + +static void outputScale( + void* data, + struct wl_output* output, + int32_t scale) +{ + MonitorData* monitorData = data; + float dpi = (float)scale * 96.0f; + monitorData->dpi = (uint32_t)dpi; +} + +static void outputDone( + void* data, + struct wl_output* output) +{ +} + +// ================================================== +// Surface +// ================================================== + +static void surfaceHandleEnter( + void* userData, + struct wl_surface* surface, + struct wl_output* output) +{ + WindowData* data = userData; + MonitorData* monitorData = findMonitorData((PalMonitor*)output); + if (!monitorData) { + return; + } + + // wayland sends multiple surface enter events + // if the surface spans multiple monitors + // we get all and return the highest dpi + // this assumes a surface can only span 4 monitors + // at the sametime but this might be wrong + + // wayland will trigger this event if the window gains focus + // so we check if the output is the same + SpanMonitor* span = nullptr; + if (data->monitorCount > 0) { + for (int i = 0; i < data->monitorCount; i++) { + if (data->monitors[i].monitor == (void*)output) { + // the monitor already exist in our array + // so we just update it + span = &data->monitors[i]; + span->dpi = monitorData->dpi; + break; + } + } + } + + if (span == nullptr) { + // new entry + span = &data->monitors[data->monitorCount]; + span->monitor = output; + span->dpi = monitorData->dpi; + data->monitorCount++; + } + + if (data->dpi == 0) { + // this is triggered when the window is created + // we cache the DPI and skip the event + data->dpi = monitorData->dpi; + return; + } + + // the code below should be skipped if users are not + // interested in DPI changed events + PalDispatchMode mode = PAL_DISPATCH_NONE; + PalEventType type = PAL_EVENT_MONITOR_DPI_CHANGED; + if (!s_Video.eventDriver) { + return; + } + + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, type); + if (mode == PAL_DISPATCH_NONE) { + return; + } + + // get the highest dpi and check if the it has changed + int maxDPI = 96; // baseline + for (int i = 0; i < data->monitorCount; i++) { + if (!data->monitors[i].monitor) { + // not a valid index. continue + continue; + } + + if (data->monitors[i].dpi > maxDPI) { + // new highest + maxDPI = data->monitors[i].dpi; + } + } + + if (maxDPI != data->dpi) { + data->dpi = maxDPI; + + PalEvent event = {0}; + event.type = type; + event.data = maxDPI; + event.data2 = palPackPointer((void*)data->window); + palPushEvent(driver, &event); + } +} + +static void surfaceHandleLeave( + void* userData, + struct wl_surface* surface, + struct wl_output* output) +{ + // remove the monitor from our span monitor list + WindowData* data = userData; + MonitorData* monitorData = findMonitorData((PalMonitor*)output); + if (!monitorData) { + return; + } + + for (int i = 0; i < data->monitorCount; i++) { + if (data->monitors[i].monitor == (void*)output) { + // found our monitor + // we might want to pack the array but its just 4 monitors + // so we leave it like that + data->monitors[i].monitor = nullptr; + data->monitorCount--; + break; + } + } +} + +// ================================================== +// Pointer +// ================================================== + +static void pointerHandleEnter( + void* userData, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface, + wl_fixed_t surface_x, + wl_fixed_t surface_y) +{ + WindowData* data = findWindowData((PalWindow*)surface); + if (!data) { + return; + } + + if (data->cursor) { + // our window + WaylandCursor* cursor = data->cursor; + wlPointerSetCursor( + pointer, + serial, + cursor->surface, + cursor->hotspotX, + cursor->hotspotY); + } + + // cache the surface the pointer is currently on + s_Wl.pointerSurface = surface; +} + +static void pointerHandleLeave( + void* userData, + struct wl_pointer* pointer, + uint32_t serial, + struct wl_surface* surface) +{ + if (s_Wl.pointerSurface == surface) { + s_Wl.pointerSurface == nullptr; + } +} + +static void pointerHandleMotion( + void* userData, + struct wl_pointer* pointer, + uint32_t time, + wl_fixed_t surface_x, + wl_fixed_t surface_y) +{ + int x = wl_fixed_to_int(surface_x); + int y = wl_fixed_to_int(surface_y); + const int dx = x - s_Mouse.lastX; + const int dy = y - s_Mouse.lastY; + + PalDispatchMode mode = PAL_DISPATCH_NONE; + PalWindow* window = (PalWindow*)s_Wl.pointerSurface; + if (s_Video.eventDriver && window) { + // we only push a mouse move only if we are on a window + PalEventDriver* driver = s_Video.eventDriver; + PalEventType type = PAL_EVENT_MOUSE_MOVE; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackInt32(x, y); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + + // push a mouse delta event + type = PAL_EVENT_MOUSE_DELTA; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackFloat((float)dx, (float)dy); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + + s_Mouse.lastX = x; + s_Mouse.lastY = y; + s_Mouse.dx = dx; + s_Mouse.dy = dy; +} + +static void pointerHandleButton( + void* userData, + struct wl_pointer* pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state) +{ + PalWindow* window = nullptr; + if (s_Wl.pointerSurface) { + window = (PalWindow*)s_Wl.pointerSurface; + + } else { + // cannot recieve events without a focused surface + return; + } + + PalBool pressed = state == WL_POINTER_BUTTON_STATE_PRESSED; + PalMouseButton _button = 0; + PalEventType type = PAL_EVENT_MOUSE_BUTTONUP; + + if (button == BTN_LEFT) { + _button = PAL_MOUSE_BUTTON_LEFT; + + } else if (button == BTN_RIGHT) { + _button = PAL_MOUSE_BUTTON_RIGHT; + + } else if (button == BTN_MIDDLE) { + _button = PAL_MOUSE_BUTTON_MIDDLE; + + } else if (button == BTN_SIDE) { + _button = PAL_MOUSE_BUTTON_X1; + + } else if (button == BTN_EXTRA) { + _button = PAL_MOUSE_BUTTON_X2; + } + + if (pressed) { + type = PAL_EVENT_MOUSE_BUTTONDOWN; + } + + s_Mouse.state[_button] = pressed; + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + + // since we are not drawing decorations for users + // they need the serial in order to draw their decorations + // we put the serial at the upper 32 so ABI is preserved + event.data = palPackUint32(_button, serial); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } +} + +static void pointerHandleAxis( + void* userData, + struct wl_pointer* pointer, + uint32_t time, + uint32_t axis, + wl_fixed_t value) +{ + double delta = wl_fixed_to_double(value); + if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + s_Mouse.tmpScrollX += delta; + s_Mouse.accumScrollX += delta; + + } else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + s_Mouse.tmpScrollY += delta; + s_Mouse.accumScrollY += delta; + } + + s_Mouse.pendingScroll = PAL_TRUE; +} + +static void pointerHandleAxisDiscrete( + void* userData, + struct wl_pointer* pointer, + uint32_t axis, + int32_t discrete) +{ + if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { + s_Mouse.tmpScrollX += discrete; + s_Mouse.accumScrollX += discrete; + + } else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { + s_Mouse.tmpScrollY += discrete; + s_Mouse.accumScrollY += discrete; + } + + s_Mouse.pendingScroll = PAL_TRUE; +} + +static void pointerHandleFrame( + void* userData, + struct wl_pointer* pointer) +{ + if (!s_Mouse.pendingScroll) { + // no wheel event + return; + } + + PalWindow* window = nullptr; + if (s_Wl.pointerSurface) { + window = (PalWindow*)s_Wl.pointerSurface; + + } else { + // cannot recieve events without a focused surface + return; + } + + const int dx = (int)s_Mouse.accumScrollX; + const int dy = (int)s_Mouse.accumScrollY; + if (s_Video.eventDriver) { + PalEventType type = PAL_EVENT_MOUSE_WHEEL; + PalEventDriver* driver = s_Video.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackFloat((float)dx, (float)dy); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + } + + s_Mouse.WheelX = dx; + s_Mouse.WheelY = dy; + s_Mouse.accumScrollX -= dx; + s_Mouse.accumScrollY -= dy; + s_Mouse.pendingScroll = PAL_FALSE; +} + +static void pointerHandleAxisSource( + void* userData, + struct wl_pointer* pointer, + uint32_t axis_source) +{ + +} + +static void pointerHandleAxisStop( + void* userData, + struct wl_pointer* pointer, + uint32_t time, + uint32_t axis) +{ + +} + +// ================================================== +// Keyboard +// ================================================== + +static void keyboardHandleEnter( + void* userData, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface, + struct wl_array* keys) +{ + // cache the surface the keyboard is currently on + s_Wl.keyboardSurface = surface; +} + +static void keyboardHandleLeave( + void* userData, + struct wl_keyboard* keyboard, + uint32_t serial, + struct wl_surface* surface) +{ + if (s_Wl.keyboardSurface == surface) { + s_Wl.keyboardSurface == nullptr; + } +} + +static void keyboardHandleRemap( + void* userData, + struct wl_keyboard* keyboard, + uint32_t format, + int32_t fd, + uint32_t size) +{ + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + struct xkb_keymap* keymap = nullptr; + struct xkb_state* state = nullptr; + + char* keymapStr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); + if (keymapStr == MAP_FAILED) { + close(fd); + return; + } + + keymap = s_Wl.xkbKeymapNewFromString( + s_Wl.inputContext, + keymapStr, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + + if (!keymap) { + return; + } + + munmap(keymapStr, size); + close(fd); + + state = s_Wl.xkbStateNew(keymap); + if (!state) { + return; + } + + // check if we have old keymap and state + if (s_Wl.state) { + s_Wl.xkbStateUnref(s_Wl.state); + s_Wl.xkbKeymapUnref(s_Wl.keymap); + } + + s_Wl.state = state; + s_Wl.keymap = keymap; + s_Keyboard.frequency = palGetPerformanceFrequency(); +} + +static void keyboardHandleKey( + void* userData, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t time, + uint32_t key, + uint32_t state) +{ + PalWindow* window = nullptr; + if (s_Wl.keyboardSurface) { + window = (PalWindow*)s_Wl.keyboardSurface; + + } else { + // cannot recieve events without a focused surface + return; + } + + PalScancode scancode = 0; + PalKeycode keycode = 0; + PalBool pressed = (state == WL_KEYBOARD_KEY_STATE_PRESSED); + PalEventType type = PAL_EVENT_KEYUP; + PalDispatchMode mode = PAL_DISPATCH_NONE; + xkb_keysym_t keySym = s_Wl.xkbStateKeyGetOneSym(s_Wl.state, key + 8); + + // special handling + if (key == 119) { + scancode = PAL_SCANCODE_PAUSE; + } else if (key == 107) { + scancode = PAL_SCANCODE_END; + } else if (key == 103) { + scancode = PAL_SCANCODE_UP; + } else if (key == 102) { + scancode = PAL_SCANCODE_HOME; + + } else { + scancode = s_Keyboard.scancodes[key]; + } + + // printable and text input keys are from the range + // 32 (PAL_KEYCODE_SPACE) and 122 (PAL_KEYCODE_Z) + // The rest are almost the same as their scancode + // Maybe there will be a layout that makes this wrong + // but for now this works + if (keySym >= XKB_KEY_space && keySym <= XKB_KEY_z) { + // a printable or input key + keycode = s_Keyboard.keycodes[keySym]; + + } else { + // Since PalKeycode and PalScancode have the same integers + // we can make a direct cast without a table + // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) + keycode = (PalKeycode)(uint32_t)scancode; + } + + // If we got a keySym but its not mapped into our keycode array + // we do a direct cast as well + if (keycode == PAL_KEYCODE_UNKNOWN) { + keycode = (PalKeycode)(uint32_t)scancode; + } + + s_Keyboard.scancodeState[scancode] = pressed; + s_Keyboard.keycodeState[keycode] = pressed; + + // check for key repeats + if (pressed) { + if (s_Wl.xkbKeymapKeyRepeats(s_Wl.keymap, key + 8)) { + s_Keyboard.repeatKey = keycode; + s_Keyboard.repeatScancode = scancode; + s_Keyboard.timer = getCurrentTime() + s_Keyboard.repeatDelay; + + } else { + s_Keyboard.repeatKey = 0; + } + + type = PAL_EVENT_KEYDOWN; + + } else { + // key release + if (s_Keyboard.repeatKey == keycode) { + s_Keyboard.repeatKey = 0; + } + } + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + mode = palGetEventDispatchMode(driver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackUint32(keycode, scancode); + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } + + // check for char event if enabled + type = PAL_EVENT_KEYCHAR; + mode = palGetEventDispatchMode(driver, type); + if (mode == PAL_DISPATCH_NONE) { + return; + } + + uint32_t codepoint = s_Wl.xkbKeysymToUtf32(keySym); + if (codepoint <= 0) { + return; + } + + PalEvent event = {0}; + event.type = type; + event.data = codepoint; + event.data2 = palPackPointer(window); + palPushEvent(driver, &event); + } +} + +static void keyboardHandleRepeatInfo( + void* userData, + struct wl_keyboard* keyboard, + int32_t rate, + int32_t delay) +{ + if (s_Wl.keyboard == keyboard) { + s_Keyboard.repeatDelay = delay; + s_Keyboard.repeatRate = rate; + + } else { + if (s_Keyboard.repeatDelay == 0) { + s_Keyboard.repeatDelay = 500; + s_Keyboard.repeatRate = 30; + } + } +} + +static void keyboardHandleModifiers( + void* userData, + struct wl_keyboard* keyboard, + uint32_t serial, + uint32_t mods_depressed, + uint32_t mods_latched, + uint32_t mods_locked, + uint32_t group) +{ + if (s_Wl.state) { + s_Wl.xkbStateUpdateMask( + s_Wl.state, + mods_depressed, + mods_latched, + mods_locked, + group, + 0, + 0); + } +} + +// ================================================== +// Seat +// ================================================== + +static void seatHandleCapabilities( + void* userData, + struct wl_seat* seat, + enum wl_seat_capability caps) +{ + if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { + s_Wl.keyboard = wlSeatGetKeyboard(seat); + wlKeyboardAddListener(s_Wl.keyboard, &s_KeyboardListener, nullptr); + } + + if (caps & WL_SEAT_CAPABILITY_POINTER) { + s_Wl.pointer = wlSeatGetPointer(seat); + wlPointerAddListener(s_Wl.pointer, &s_PointerListener, nullptr); + } +} + +static void seatHandleName( + void* userData, + struct wl_seat* seat, + const char* name) +{ + +} + +// ================================================== +// Xdg +// ================================================== + +static void wmBaseHandlePing( + void* data, + struct xdg_wm_base* base, + uint32_t serial) +{ + xdgWmBasePong(base, serial); +} + +static void xdgSurfaceHandleConfigure( + void* data, + struct xdg_surface* surface, + uint32_t serial) +{ + WindowData* winData = (WindowData*)data; + xdgSurfaceAckConfigure(surface, serial); + + // push and resolve any pending events + if (!winData->skipConfigure) { + if (winData->pushConfigureEvent) { + if (winData->eglWindow) { + s_Wl.eglWindowResize( + winData->eglWindow, + winData->w, + winData->h, + 0, + 0); + + } else { + // create a new buffer with the new size + struct wl_buffer* buffer = nullptr; + buffer = + createShmBuffer(winData->w, winData->h, nullptr, PAL_FALSE); + if (!buffer) { + return; + } + + struct wl_surface* _surface = nullptr; + _surface = (struct wl_surface*)winData->window; + + wlSurfaceAttach(_surface, buffer, 0, 0); + wlSurfaceDamageBuffer(_surface, 0, 0, winData->w, winData->h); + wlSurfaceCommit(_surface); + + // destroy old buffer + wlBufferDestroy(winData->buffer); + winData->buffer = buffer; + } + + // push a window resize event + if (s_Video.eventDriver) { + PalEventType type = PAL_EVENT_WINDOW_SIZE; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(s_Video.eventDriver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = palPackUint32(winData->w, winData->h); + event.data2 = palPackPointer(winData->window); + palPushEvent(s_Video.eventDriver, &event); + } + } + + winData->pushConfigureEvent = PAL_FALSE; + } + } + + // pending state + if (!winData->skipState) { + if (!winData->pushStateEvent) { + return; + } + + // push a window state event + // we dont recreate buffers over here + // since we already create the buffer with the new size + if (s_Video.eventDriver) { + PalEventType type = PAL_EVENT_WINDOW_STATE; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(s_Video.eventDriver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = winData->state; + event.data2 = palPackPointer(winData->window); + palPushEvent(s_Video.eventDriver, &event); + } + } + + winData->pushStateEvent = PAL_FALSE; + } +} + +static void xdgToplevelHandleConfigure( + void* data, + struct xdg_toplevel* toplevel, + int32_t width, + int32_t height, + struct wl_array* states) +{ + WindowData* winData = (WindowData*)data; + uint32_t* state; + PalBool activated = PAL_FALSE; + wl_array_for_each(state, states) + { + // we need only maximized + if (*state == 1) { // XDG_TOPLEVEL_STATE_MAXIMIZED + if (winData->state != PAL_WINDOW_STATE_MAXIMIZED) { + winData->state = PAL_WINDOW_STATE_MAXIMIZED; + winData->pushStateEvent = PAL_TRUE; + } + + } else if (*state == 4) { // XDG_TOPLEVEL_STATE_ACTIVATED + activated = PAL_TRUE; + } + } + + if (width > 0 && height > 0) { + if (width != winData->w || height != winData->h) { + // size change + winData->pushConfigureEvent = PAL_TRUE; + } + + winData->w = width; + winData->h = height; + } + + if (activated && !winData->focused) { + // focus gained + winData->focused = PAL_TRUE; + + } else if (!activated && winData->focused) { + // focus lost + winData->focused = PAL_FALSE; + + } else { + // discard double focus gained and double focus lost + return; + } + + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_NONE; + PalEventType type = PAL_EVENT_WINDOW_FOCUS; + mode = palGetEventDispatchMode(driver, type); + + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data = winData->focused; + event.data2 = palPackPointer(winData->window); + palPushEvent(driver, &event); + } + } +} + +static void xdgToplevelHandleClose( + void* data, + struct xdg_toplevel* toplevel) +{ + WindowData* winData = (WindowData*)data; + if (s_Video.eventDriver) { + PalEventType type = PAL_EVENT_WINDOW_CLOSE; + PalDispatchMode mode = PAL_DISPATCH_NONE; + mode = palGetEventDispatchMode(s_Video.eventDriver, type); + if (mode != PAL_DISPATCH_NONE) { + PalEvent event = {0}; + event.type = type; + event.data2 = palPackPointer(winData->window); + palPushEvent(s_Video.eventDriver, &event); + } + } +} + +// ================================================== +// Zxdg Decoration +// ================================================== + +void zxdgDecorationHandleConfigure( + void* data, + struct zxdg_toplevel_decoration_v1* dec, + uint32_t mode) +{ + if (s_Video.eventDriver) { + PalEventDriver* driver = s_Video.eventDriver; + PalDispatchMode dispatchMode = PAL_DISPATCH_NONE; + PalEventType type = PAL_EVENT_WINDOW_DECORATION_MODE; + dispatchMode = palGetEventDispatchMode(driver, type); + + if (dispatchMode != PAL_DISPATCH_NONE) { + PalDecorationMode decorMode = PAL_DECORATION_MODE_SERVER_SIDE; + if (mode == 0 || mode == 1) { + // client side decoration + decorMode = PAL_DECORATION_MODE_CLIENT_SIDE; + } + + PalEvent event = {0}; + event.type = type; + event.data = decorMode; + event.data2 = palPackPointer(data); + palPushEvent(driver, &event); + } + } +} + PalResult eglWlBackend(const int index) { // user choose EGL FBConfig backend if (!s_Egl.handle) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } EGLDisplay display = EGL_NO_DISPLAY; display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_Wl.display); if (display == EGL_NO_DISPLAY) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } EGLint numConfigs = 0; if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } EGLint configSize = sizeof(EGLConfig) * numConfigs; @@ -110,8 +1196,10 @@ PalResult wlInitVideo() !s_Wl.xkbCommon || !s_Wl.libCursor || !s_Wl.libWaylandEgl) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } // get the exported global variables @@ -263,7 +1351,7 @@ PalResult wlInitVideo() // initialize wayland s_Wl.checkFeatures = PAL_TRUE; s_Wl.monitorCount = 0; - setupXdgShellProtocol(); + setupProtocols(); // check if user supplied their own display if (s_Video.platformInstance) { @@ -275,35 +1363,43 @@ PalResult wlInitVideo() } if (!s_Wl.display) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } s_Video.display = (void*)s_Wl.display; - s_Wl.registry = displayGetRegistry(s_Wl.display); - registryAddListener(s_Wl.registry, &s_RegistryListener, nullptr); + s_Wl.registry = wlDisplayGetRegistry(s_Wl.display); + wlRegistryAddListener(s_Wl.registry, &s_RegistryListener, nullptr); s_Wl.displayRoundtrip(s_Wl.display); // do a roundtrip again to get remaining handles s_Wl.displayRoundtrip(s_Wl.display); if (!s_Wl.compositor || !s_Wl.xdgBase || !s_Wl.shm) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } // create an input context s_Wl.inputContext = s_Wl.xkbContextNew(XKB_CONTEXT_NO_FLAGS); if (!s_Wl.inputContext) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } // get the current theme s_Wl.cursorTheme = s_Wl.cursorThemeLoad(nullptr, 32, s_Wl.shm); if (!s_Wl.cursorTheme) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } createKeycodeTable(); @@ -411,5 +1507,76 @@ void* wlGetInstance() return (void*)s_Wl.display; } +// ================================================== +// Listeners +// ================================================== + +struct wl_registry_listener s_RegistryListener = { + .global = globalHandle, + .global_remove = globalRemove +}; + +struct wl_output_listener s_OutputListener = { + .geometry = outputGeometry, + .mode = outputMode, + .done = outputDone, + .scale = outputScale}; + +struct wl_output_listener s_DefaultModeListener = { + .geometry = outputGeometry, + .mode = outputMode, + .done = outputDone, + .scale = outputScale}; + +struct wl_surface_listener s_SurfaceListener = { + .enter = surfaceHandleEnter, + .leave = surfaceHandleLeave +}; + +struct wl_pointer_listener s_PointerListener = { + .enter = pointerHandleEnter, + .leave = pointerHandleLeave, + .motion = pointerHandleMotion, + .button = pointerHandleButton, + .axis = pointerHandleAxis, + .axis_discrete = pointerHandleAxisDiscrete, + .frame = pointerHandleFrame, + .axis_source = pointerHandleAxisSource, + .axis_stop = pointerHandleAxisStop +}; + +struct wl_keyboard_listener s_KeyboardListener = { + .enter = keyboardHandleEnter, + .leave = keyboardHandleLeave, + .keymap = keyboardHandleRemap, + .key = keyboardHandleKey, + .repeat_info = keyboardHandleRepeatInfo, + .modifiers = keyboardHandleModifiers +}; + +struct zxdg_toplevel_decoration_v1_listener s_DecorationListener = { + .configure = zxdgDecorationHandleConfigure +}; + +struct wl_seat_listener s_SeatListener = { + .capabilities = seatHandleCapabilities, + .name = seatHandleName +}; + +struct xdg_wm_base_listener s_WmBaseListener = { + .ping = wmBaseHandlePing +}; + +struct xdg_surface_listener s_XdgSurfaceListener = { + .configure = xdgSurfaceHandleConfigure +}; + +struct xdg_toplevel_listener s_XdgToplevelListener = { + .configure = xdgToplevelHandleConfigure, + .close = xdgToplevelHandleClose, + .configure_bounds = nullptr, + .wm_capabilities = nullptr +}; + #endif // PAL_HAS_WAYLAND_BACKEND #endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/wayland/pal_wayland.h b/src/video/linux/wayland/pal_wayland.h index 055a4b76..6632c217 100644 --- a/src/video/linux/wayland/pal_wayland.h +++ b/src/video/linux/wayland/pal_wayland.h @@ -208,6 +208,27 @@ typedef struct { } Wayland; extern Wayland s_Wl; +extern struct wl_registry_listener s_RegistryListener; +extern struct wl_output_listener s_OutputListener; +extern struct wl_output_listener s_DefaultModeListener; + +extern struct wl_surface_listener s_SurfaceListener; +extern struct wl_pointer_listener s_PointerListener; +extern struct wl_keyboard_listener s_KeyboardListener; +extern struct zxdg_toplevel_decoration_v1_listener s_DecorationListener; + +extern struct wl_seat_listener s_SeatListener; +extern struct xdg_wm_base_listener s_WmBaseListener; +extern struct xdg_surface_listener s_XdgSurfaceListener; +extern struct xdg_toplevel_listener s_XdgToplevelListener; + +void setupProtocols(); + +struct wl_buffer* createShmBuffer( + int width, + int height, + const uint8_t* pixels, + PalBool cursor); #endif // PAL_HAS_WAYLAND_BACKEND #endif // __linux__ diff --git a/src/video/linux/wayland/pal_wayland_helper.c b/src/video/linux/wayland/pal_wayland_helper.c deleted file mode 100644 index 7751a791..00000000 --- a/src/video/linux/wayland/pal_wayland_helper.c +++ /dev/null @@ -1,15 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifdef __linux__ -#if PAL_HAS_WAYLAND_BACKEND == 1 - -#include "pal_wayland_helper.h" -#include "pal_shared.h" - -#endif // PAL_HAS_WAYLAND_BACKEND -#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/wayland/pal_wayland_helper.h b/src/video/linux/wayland/pal_wayland_helper.h deleted file mode 100644 index 0c5dbb24..00000000 --- a/src/video/linux/wayland/pal_wayland_helper.h +++ /dev/null @@ -1,1888 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifndef _PAL_WAYLAND_HELPER_H -#define _PAL_WAYLAND_HELPER_H -#ifdef __linux__ -#if PAL_HAS_WAYLAND_BACKEND == 1 -#include "pal_wayland.h" -#include -#include - -static inline void* registryBind( - struct wl_registry* wl_registry, - uint32_t name, - const struct wl_interface* interface, - uint32_t version) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_registry, - WL_REGISTRY_BIND, - interface, - version, - 0, - name, - interface->name, - version, - NULL); - - return (void*)id; -} - -static inline int registryAddListener( - struct wl_registry* wl_registry, - const struct wl_registry_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); -} - -static inline struct wl_registry* displayGetRegistry(struct wl_display* wl_display) -{ - struct wl_proxy* registry; - registry = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_display, - 1, // WL_DISPLAY_GET_REGISTRY - s_Wl.registryInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_display), - 0, - NULL); - - return (struct wl_registry*)registry; -} - -static inline int outputAddListener( - struct wl_output* wl_output, - const struct wl_output_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_output, (void (**)(void))listener, data); -} - -static inline struct wl_surface* compositorCreateSurface(struct wl_compositor* wl_compositor) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_compositor, - 0, // WL_COMPOSITOR_CREATE_SURFACE, - s_Wl.surfaceInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_compositor), - 0, - NULL); - - return (struct wl_surface*)id; -} - -static inline void surfaceCommit(struct wl_surface* wl_surface) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_surface, - 6, // WL_SURFACE_COMMIT - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), - 0); -} - -static inline void surfaceDestroy(struct wl_surface* wl_surface) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_surface, - 0, // WL_SURFACE_DESTROY - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline struct wl_shm_pool* shmCreatePool( - struct wl_shm* wl_shm, - int32_t fd, - int32_t size) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_shm, - 0, // WL_SHM_CREATE_POOL - s_Wl.shmPoolInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm), - 0, - NULL, - fd, - size); - - return (struct wl_shm_pool*)id; -} - -static inline void shmPoolDestroy(struct wl_shm_pool* wl_shm_pool) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_shm_pool, - WL_SHM_POOL_DESTROY, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm_pool), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline struct wl_buffer* shmPoolCreateBuffer( - struct wl_shm_pool* wl_shm_pool, - int32_t offset, - int32_t width, - int32_t height, - int32_t stride, - uint32_t format) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_shm_pool, - WL_SHM_POOL_CREATE_BUFFER, - s_Wl.bufferInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm_pool), - 0, - NULL, - offset, - width, - height, - stride, - format); - - return (struct wl_buffer*)id; -} - -static inline void bufferDestroy(struct wl_buffer* wl_buffer) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_buffer, - WL_BUFFER_DESTROY, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_buffer), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline void surfaceAttach( - struct wl_surface* wl_surface, - struct wl_buffer* buffer, - int32_t x, - int32_t y) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_surface, - WL_SURFACE_ATTACH, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), - 0, - buffer, - x, - y); -} - -static inline void surfaceDamageBuffer( - struct wl_surface* wl_surface, - int32_t x, - int32_t y, - int32_t width, - int32_t height) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_surface, - WL_SURFACE_DAMAGE_BUFFER, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), - 0, - x, - y, - width, - height); -} - -static inline int surfaceAddListener( - struct wl_surface* wl_surface, - const struct wl_surface_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_surface, (void (**)(void))listener, data); -} - -static inline int seatAddListener( - struct wl_seat* wl_seat, - const struct wl_seat_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_seat, (void (**)(void))listener, data); -} - -static inline struct wl_pointer* seatGetPointer(struct wl_seat* wl_seat) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_seat, - WL_SEAT_GET_POINTER, - s_Wl.pointerInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_seat), - 0, - NULL); - - return (struct wl_pointer*)id; -} - -static inline struct wl_keyboard* seatGetKeyboard(struct wl_seat* wl_seat) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_seat, - WL_SEAT_GET_KEYBOARD, - s_Wl.keyboardInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_seat), - 0, - NULL); - - return (struct wl_keyboard*)id; -} - -static inline int pointerAddListener( - struct wl_pointer* wl_pointer, - const struct wl_pointer_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_pointer, (void (**)(void))listener, data); -} - -static inline void pointerSetCursor( - struct wl_pointer* wl_pointer, - uint32_t serial, - struct wl_surface* surface, - int32_t hotspot_x, - int32_t hotspot_y) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_pointer, - WL_POINTER_SET_CURSOR, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_pointer), - 0, - serial, - surface, - hotspot_x, - hotspot_y); -} - -static inline int keyboardAddListener( - struct wl_keyboard* wl_keyboard, - const struct wl_keyboard_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)wl_keyboard, (void (**)(void))listener, data); -} - -static inline struct wl_region* compositorCreateRegion(struct wl_compositor* wl_compositor) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_compositor, - WL_COMPOSITOR_CREATE_REGION, - s_Wl.regionInterface, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_compositor), - 0, - NULL); - - return (struct wl_region*)id; -} - -static inline void regionAdd( - struct wl_region* wl_region, - int32_t x, - int32_t y, - int32_t width, - int32_t height) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_region, - WL_REGION_ADD, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_region), - 0, - x, - y, - width, - height); -} - -static inline void surfaceSetOpaqueRegion( - struct wl_surface* wl_surface, - struct wl_region* region) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_surface, - WL_SURFACE_SET_OPAQUE_REGION, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), - 0, - region); -} - -static inline void regionDestroy(struct wl_region* wl_region) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)wl_region, - WL_REGION_DESTROY, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)wl_region), - WL_MARSHAL_FLAG_DESTROY); -} - -static void surfaceHandleEnter( - void* userData, - struct wl_surface* surface, - struct wl_output* output) -{ - WindowData* data = userData; - MonitorData* monitorData = findMonitorData((PalMonitor*)output); - if (!monitorData) { - return; - } - - // wayland sends multiple surface enter events - // if the surface spans multiple monitors - // we get all and return the highest dpi - // this assumes a surface can only span 4 monitors - // at the sametime but this might be wrong - - // wayland will trigger this event if the window gains focus - // so we check if the output is the same - SpanMonitor* span = nullptr; - if (data->monitorCount > 0) { - for (int i = 0; i < data->monitorCount; i++) { - if (data->monitors[i].monitor == (void*)output) { - // the monitor already exist in our array - // so we just update it - span = &data->monitors[i]; - span->dpi = monitorData->dpi; - break; - } - } - } - - if (span == nullptr) { - // new entry - span = &data->monitors[data->monitorCount]; - span->monitor = output; - span->dpi = monitorData->dpi; - data->monitorCount++; - } - - if (data->dpi == 0) { - // this is triggered when the window is created - // we cache the DPI and skip the event - data->dpi = monitorData->dpi; - return; - } - - // the code below should be skipped if users are not - // interested in DPI changed events - PalDispatchMode mode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_MONITOR_DPI_CHANGED; - if (!s_Video.eventDriver) { - return; - } - - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, type); - if (mode == PAL_DISPATCH_NONE) { - return; - } - - // get the highest dpi and check if the it has changed - int maxDPI = 96; // baseline - for (int i = 0; i < data->monitorCount; i++) { - if (!data->monitors[i].monitor) { - // not a valid index. continue - continue; - } - - if (data->monitors[i].dpi > maxDPI) { - // new highest - maxDPI = data->monitors[i].dpi; - } - } - - if (maxDPI != data->dpi) { - data->dpi = maxDPI; - - PalEvent event = {0}; - event.type = type; - event.data = maxDPI; - event.data2 = palPackPointer((void*)data->window); - palPushEvent(driver, &event); - } -} - -static void surfaceHandleLeave( - void* userData, - struct wl_surface* surface, - struct wl_output* output) -{ - // remove the monitor from our span monitor list - WindowData* data = userData; - MonitorData* monitorData = findMonitorData((PalMonitor*)output); - if (!monitorData) { - return; - } - - for (int i = 0; i < data->monitorCount; i++) { - if (data->monitors[i].monitor == (void*)output) { - // found our monitor - // we might want to pack the array but its just 4 monitors - // so we leave it like that - data->monitors[i].monitor = nullptr; - data->monitorCount--; - break; - } - } -} - -static struct wl_surface_listener surfaceListener = { - .enter = surfaceHandleEnter, - .leave = surfaceHandleLeave}; - -static void pointerHandleEnter( - void* userData, - struct wl_pointer* pointer, - uint32_t serial, - struct wl_surface* surface, - wl_fixed_t surface_x, - wl_fixed_t surface_y) -{ - WindowData* data = findWindowData((PalWindow*)surface); - if (!data) { - return; - } - - if (data->cursor) { - // our window - WaylandCursor* cursor = data->cursor; - pointerSetCursor(pointer, serial, cursor->surface, cursor->hotspotX, cursor->hotspotY); - } - - // cache the surface the pointer is currently on - s_Wl.pointerSurface = surface; -} - -static void pointerHandleLeave( - void* userData, - struct wl_pointer* pointer, - uint32_t serial, - struct wl_surface* surface) -{ - if (s_Wl.pointerSurface == surface) { - s_Wl.pointerSurface == nullptr; - } -} - -static void pointerHandleMotion( - void* userData, - struct wl_pointer* pointer, - uint32_t time, - wl_fixed_t surface_x, - wl_fixed_t surface_y) -{ - int x = wl_fixed_to_int(surface_x); - int y = wl_fixed_to_int(surface_y); - const int dx = x - s_Mouse.lastX; - const int dy = y - s_Mouse.lastY; - - PalDispatchMode mode = PAL_DISPATCH_NONE; - PalWindow* window = (PalWindow*)s_Wl.pointerSurface; - if (s_Video.eventDriver && window) { - // we only push a mouse move only if we are on a window - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MOUSE_MOVE; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackInt32(x, y); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - - // push a mouse delta event - type = PAL_EVENT_MOUSE_DELTA; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackInt32(dx, dy); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - - s_Mouse.lastX = x; - s_Mouse.lastY = y; - s_Mouse.dx = dx; - s_Mouse.dy = dy; -} - -static void pointerHandleButton( - void* userData, - struct wl_pointer* pointer, - uint32_t serial, - uint32_t time, - uint32_t button, - uint32_t state) -{ - PalWindow* window = nullptr; - if (s_Wl.pointerSurface) { - window = (PalWindow*)s_Wl.pointerSurface; - - } else { - // cannot recieve events without a focused surface - return; - } - - PalBool pressed = state == WL_POINTER_BUTTON_STATE_PRESSED; - PalMouseButton _button = 0; - PalEventType type = PAL_EVENT_MOUSE_BUTTONUP; - - if (button == BTN_LEFT) { - _button = PAL_MOUSE_BUTTON_LEFT; - - } else if (button == BTN_RIGHT) { - _button = PAL_MOUSE_BUTTON_RIGHT; - - } else if (button == BTN_MIDDLE) { - _button = PAL_MOUSE_BUTTON_MIDDLE; - - } else if (button == BTN_SIDE) { - _button = PAL_MOUSE_BUTTON_X1; - - } else if (button == BTN_EXTRA) { - _button = PAL_MOUSE_BUTTON_X2; - } - - if (pressed) { - type = PAL_EVENT_MOUSE_BUTTONDOWN; - } - - s_Mouse.state[_button] = pressed; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - - // since we are not drawing decorations for users - // they need the serial in order to draw their decorations - // we put the serial at the upper 32 so ABI is preserved - event.data = palPackUint32(_button, serial); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } -} - -static void pointerHandleAxis( - void* userData, - struct wl_pointer* pointer, - uint32_t time, - uint32_t axis, - wl_fixed_t value) -{ - double delta = wl_fixed_to_double(value); - if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - s_Mouse.tmpScrollX += delta; - s_Mouse.accumScrollX += delta; - - } else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { - s_Mouse.tmpScrollY += delta; - s_Mouse.accumScrollY += delta; - } - - s_Mouse.pendingScroll = PAL_TRUE; -} - -static void pointerHandleAxisDiscrete( - void* userData, - struct wl_pointer* pointer, - uint32_t axis, - int32_t discrete) -{ - if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) { - s_Mouse.tmpScrollX += discrete; - s_Mouse.accumScrollX += discrete; - - } else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { - s_Mouse.tmpScrollY += discrete; - s_Mouse.accumScrollY += discrete; - } - - s_Mouse.pendingScroll = PAL_TRUE; -} - -static void pointerHandleFrame( - void* userData, - struct wl_pointer* pointer) -{ - if (!s_Mouse.pendingScroll) { - // no wheel event - return; - } - - PalWindow* window = nullptr; - if (s_Wl.pointerSurface) { - window = (PalWindow*)s_Wl.pointerSurface; - - } else { - // cannot recieve events without a focused surface - return; - } - - const int dx = (int)s_Mouse.accumScrollX; - const int dy = (int)s_Mouse.accumScrollY; - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_MOUSE_WHEEL; - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(dx, dy); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - } - - s_Mouse.WheelX = dx; - s_Mouse.WheelY = dy; - s_Mouse.accumScrollX -= dx; - s_Mouse.accumScrollY -= dy; - s_Mouse.pendingScroll = PAL_FALSE; -} - -static void pointerHandleAxisSource( - void* userData, - struct wl_pointer* pointer, - uint32_t axis_source) -{ -} - -static void pointerHandleAxisStop( - void* userData, - struct wl_pointer* pointer, - uint32_t time, - uint32_t axis) -{ -} - -static void keyboardHandleEnter( - void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - struct wl_surface* surface, - struct wl_array* keys) -{ - // cache the surface the keyboard is currently on - s_Wl.keyboardSurface = surface; -} - -static void keyboardHandleLeave( - void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - struct wl_surface* surface) -{ - if (s_Wl.keyboardSurface == surface) { - s_Wl.keyboardSurface == nullptr; - } -} - -static void keyboardHandleRemap( - void* userData, - struct wl_keyboard* keyboard, - uint32_t format, - int32_t fd, - uint32_t size) -{ - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { - close(fd); - return; - } - - struct xkb_keymap* keymap = nullptr; - struct xkb_state* state = nullptr; - - char* keymapStr = mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0); - if (keymapStr == MAP_FAILED) { - close(fd); - return; - } - - keymap = s_Wl.xkbKeymapNewFromString( - s_Wl.inputContext, - keymapStr, - XKB_KEYMAP_FORMAT_TEXT_V1, - XKB_KEYMAP_COMPILE_NO_FLAGS); - - if (!keymap) { - return; - } - - munmap(keymapStr, size); - close(fd); - - state = s_Wl.xkbStateNew(keymap); - if (!state) { - return; - } - - // check if we have old keymap and state - if (s_Wl.state) { - s_Wl.xkbStateUnref(s_Wl.state); - s_Wl.xkbKeymapUnref(s_Wl.keymap); - } - - s_Wl.state = state; - s_Wl.keymap = keymap; - s_Keyboard.frequency = palGetPerformanceFrequency(); -} - -static void keyboardHandleKey( - void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - uint32_t time, - uint32_t key, - uint32_t state) -{ - PalWindow* window = nullptr; - if (s_Wl.keyboardSurface) { - window = (PalWindow*)s_Wl.keyboardSurface; - - } else { - // cannot recieve events without a focused surface - return; - } - - PalScancode scancode = 0; - PalKeycode keycode = 0; - PalBool pressed = (state == WL_KEYBOARD_KEY_STATE_PRESSED); - PalEventType type = PAL_EVENT_KEYUP; - PalDispatchMode mode = PAL_DISPATCH_NONE; - xkb_keysym_t keySym = s_Wl.xkbStateKeyGetOneSym(s_Wl.state, key + 8); - - // special handling - if (key == 119) { - scancode = PAL_SCANCODE_PAUSE; - } else if (key == 107) { - scancode = PAL_SCANCODE_END; - } else if (key == 103) { - scancode = PAL_SCANCODE_UP; - } else if (key == 102) { - scancode = PAL_SCANCODE_HOME; - - } else { - scancode = s_Keyboard.scancodes[key]; - } - - // printable and text input keys are from the range - // 32 (PAL_KEYCODE_SPACE) and 122 (PAL_KEYCODE_Z) - // The rest are almost the same as their scancode - // Maybe there will be a layout that makes this wrong - // but for now this works - if (keySym >= XKB_KEY_space && keySym <= XKB_KEY_z) { - // a printable or input key - keycode = s_Keyboard.keycodes[keySym]; - - } else { - // Since PalKeycode and PalScancode have the same integers - // we can make a direct cast without a table - // Examle: PAL_KEYCODE_A(int 0) == PAL_SCANCODE_A(int 0) - keycode = (PalKeycode)(uint32_t)scancode; - } - - // If we got a keySym but its not mapped into our keycode array - // we do a direct cast as well - if (keycode == PAL_KEYCODE_UNKNOWN) { - keycode = (PalKeycode)(uint32_t)scancode; - } - - s_Keyboard.scancodeState[scancode] = pressed; - s_Keyboard.keycodeState[keycode] = pressed; - - // check for key repeats - if (pressed) { - if (s_Wl.xkbKeymapKeyRepeats(s_Wl.keymap, key + 8)) { - s_Keyboard.repeatKey = keycode; - s_Keyboard.repeatScancode = scancode; - s_Keyboard.timer = getCurrentTime() + s_Keyboard.repeatDelay; - - } else { - s_Keyboard.repeatKey = 0; - } - - type = PAL_EVENT_KEYDOWN; - - } else { - // key release - if (s_Keyboard.repeatKey == keycode) { - s_Keyboard.repeatKey = 0; - } - } - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(keycode, scancode); - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } - - // check for char event if enabled - type = PAL_EVENT_KEYCHAR; - mode = palGetEventDispatchMode(driver, type); - if (mode == PAL_DISPATCH_NONE) { - return; - } - - uint32_t codepoint = s_Wl.xkbKeysymToUtf32(keySym); - if (codepoint <= 0) { - return; - } - - PalEvent event = {0}; - event.type = type; - event.data = codepoint; - event.data2 = palPackPointer(window); - palPushEvent(driver, &event); - } -} - -static void keyboardHandleRepeatInfo( - void* userData, - struct wl_keyboard* keyboard, - int32_t rate, - int32_t delay) -{ - if (s_Wl.keyboard == keyboard) { - s_Keyboard.repeatDelay = delay; - s_Keyboard.repeatRate = rate; - - } else { - if (s_Keyboard.repeatDelay == 0) { - s_Keyboard.repeatDelay = 500; - s_Keyboard.repeatRate = 30; - } - } -} - -static void keyboardHandleModifiers( - void* userData, - struct wl_keyboard* keyboard, - uint32_t serial, - uint32_t mods_depressed, - uint32_t mods_latched, - uint32_t mods_locked, - uint32_t group) -{ - if (s_Wl.state) { - s_Wl.xkbStateUpdateMask(s_Wl.state, mods_depressed, mods_latched, mods_locked, group, 0, 0); - } -} - -static struct wl_pointer_listener pointerListener = { - .enter = pointerHandleEnter, - .leave = pointerHandleLeave, - .motion = pointerHandleMotion, - .button = pointerHandleButton, - .axis = pointerHandleAxis, - .axis_discrete = pointerHandleAxisDiscrete, - .frame = pointerHandleFrame, - .axis_source = pointerHandleAxisSource, - .axis_stop = pointerHandleAxisStop}; - -static struct wl_keyboard_listener keyboardListener = { - .enter = keyboardHandleEnter, - .leave = keyboardHandleLeave, - .keymap = keyboardHandleRemap, - .key = keyboardHandleKey, - .repeat_info = keyboardHandleRepeatInfo, - .modifiers = keyboardHandleModifiers}; - -static void seatHandleCapabilities( - void* userData, - struct wl_seat* seat, - enum wl_seat_capability caps) -{ - if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { - s_Wl.keyboard = seatGetKeyboard(seat); - keyboardAddListener(s_Wl.keyboard, &keyboardListener, nullptr); - } - - if (caps & WL_SEAT_CAPABILITY_POINTER) { - s_Wl.pointer = seatGetPointer(seat); - pointerAddListener(s_Wl.pointer, &pointerListener, nullptr); - } -} - -static void seatHandleName( - void* userData, - struct wl_seat* seat, - const char* name) -{ -} - -static struct wl_seat_listener seatListener = { - .capabilities = seatHandleCapabilities, - .name = seatHandleName}; - -// Protocols -struct xdg_wm_base; -struct xdg_surface; -struct xdg_toplevel; - -// forward declare -static struct wl_buffer* createShmBuffer( - int width, - int height, - const uint8_t* pixels, - PalBool cursor); - -static const struct wl_interface* xdg_shell_types[26]; - -static const struct wl_message xdg_wm_base_requests[] = { - {"destroy", "", xdg_shell_types + 0}, - {"create_positioner", "n", xdg_shell_types + 4}, - {"get_xdg_surface", "no", xdg_shell_types + 5}, - {"pong", "u", xdg_shell_types + 0}, -}; - -static const struct wl_message xdg_wm_base_events[] = { - {"ping", "u", xdg_shell_types + 0}, -}; - -const struct wl_interface xdg_wm_base_interface = { - "xdg_wm_base", - 6, - 4, - xdg_wm_base_requests, - 1, - xdg_wm_base_events, -}; - -static const struct wl_message xdg_positioner_requests[] = { - {"destroy", "", xdg_shell_types + 0}, - {"set_size", "ii", xdg_shell_types + 0}, - {"set_anchor_rect", "iiii", xdg_shell_types + 0}, - {"set_anchor", "u", xdg_shell_types + 0}, - {"set_gravity", "u", xdg_shell_types + 0}, - {"set_constraint_adjustment", "u", xdg_shell_types + 0}, - {"set_offset", "ii", xdg_shell_types + 0}, - {"set_reactive", "3", xdg_shell_types + 0}, - {"set_parent_size", "3ii", xdg_shell_types + 0}, - {"set_parent_configure", "3u", xdg_shell_types + 0}, -}; - -const struct wl_interface xdg_positioner_interface = { - "xdg_positioner", - 6, - 10, - xdg_positioner_requests, - 0, - NULL, -}; - -static const struct wl_message xdg_surface_requests[] = { - {"destroy", "", xdg_shell_types + 0}, - {"get_toplevel", "n", xdg_shell_types + 7}, - {"get_popup", "n?oo", xdg_shell_types + 8}, - {"set_window_geometry", "iiii", xdg_shell_types + 0}, - {"ack_configure", "u", xdg_shell_types + 0}, -}; - -static const struct wl_message xdg_surface_events[] = { - {"configure", "u", xdg_shell_types + 0}, -}; - -const struct wl_interface xdg_surface_interface = { - "xdg_surface", - 6, - 5, - xdg_surface_requests, - 1, - xdg_surface_events, -}; - -static const struct wl_message xdg_toplevel_requests[] = { - {"destroy", "", xdg_shell_types + 0}, - {"set_parent", "?o", xdg_shell_types + 11}, - {"set_title", "s", xdg_shell_types + 0}, - {"set_app_id", "s", xdg_shell_types + 0}, - {"show_window_menu", "ouii", xdg_shell_types + 12}, - {"move", "ou", xdg_shell_types + 16}, - {"resize", "ouu", xdg_shell_types + 18}, - {"set_max_size", "ii", xdg_shell_types + 0}, - {"set_min_size", "ii", xdg_shell_types + 0}, - {"set_maximized", "", xdg_shell_types + 0}, - {"unset_maximized", "", xdg_shell_types + 0}, - {"set_fullscreen", "?o", xdg_shell_types + 21}, - {"unset_fullscreen", "", xdg_shell_types + 0}, - {"set_minimized", "", xdg_shell_types + 0}, -}; - -static const struct wl_message xdg_toplevel_events[] = { - {"configure", "iia", xdg_shell_types + 0}, - {"close", "", xdg_shell_types + 0}, - {"configure_bounds", "4ii", xdg_shell_types + 0}, - {"wm_capabilities", "5a", xdg_shell_types + 0}, -}; - -const struct wl_interface xdg_toplevel_interface = { - "xdg_toplevel", - 6, - 14, - xdg_toplevel_requests, - 4, - xdg_toplevel_events, -}; - -static const struct wl_message xdg_popup_requests[] = { - {"destroy", "", xdg_shell_types + 0}, - {"grab", "ou", xdg_shell_types + 22}, - {"reposition", "3ou", xdg_shell_types + 24}, -}; - -static const struct wl_message xdg_popup_events[] = { - {"configure", "iiii", xdg_shell_types + 0}, - {"popup_done", "", xdg_shell_types + 0}, - {"repositioned", "3u", xdg_shell_types + 0}, -}; - -const struct wl_interface xdg_popup_interface = { - "xdg_popup", - 6, - 3, - xdg_popup_requests, - 3, - xdg_popup_events, -}; - -struct xdg_wm_base_listener { - void (*ping)( - void*, - struct xdg_wm_base*, - uint32_t); -}; - -struct xdg_surface_listener { - void (*configure)( - void*, - struct xdg_surface*, - uint32_t); -}; - -struct xdg_toplevel_listener { - // clang-format off - void (*configure)(void*, struct xdg_toplevel*, int32_t, int32_t, struct wl_array*); - void (*close)(void*, struct xdg_toplevel*); - void (*configure_bounds)(void*, struct xdg_toplevel*, int32_t, int32_t); - void (*wm_capabilities)(void*, struct xdg_toplevel*, struct wl_array*); - // clang-format on -}; - -static inline void xdgWmBasePong( - struct xdg_wm_base* xdg_wm_base, - uint32_t serial) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_wm_base, - 3, // XDG_WM_BASE_PONG - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_wm_base), - 0, - serial); -} - -static inline int xdgWmBaseAddListener( - struct xdg_wm_base* xdg_wm_base, - const struct xdg_wm_base_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)xdg_wm_base, (void (**)(void))listener, data); -} - -static inline struct xdg_surface* xdgWmBaseGetXdgSurface( - struct xdg_wm_base* xdg_wm_base, - struct wl_surface* surface) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_wm_base, - 2, // XDG_WM_BASE_GET_XDG_SURFACE, - &xdg_surface_interface, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_wm_base), - 0, - NULL, - surface); - - return (struct xdg_surface*)id; -} - -static inline struct xdg_toplevel* xdgSurfaceGetToplevel(struct xdg_surface* xdg_surface) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_surface, - 1, // XDG_SURFACE_GET_TOPLEVEL, - &xdg_toplevel_interface, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), - 0, - NULL); - - return (struct xdg_toplevel*)id; -} - -static inline void xdgSurfaceAckConfigure( - struct xdg_surface* xdg_surface, - uint32_t serial) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_surface, - 4, // XDG_SURFACE_ACK_CONFIGURE - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), - 0, - serial); -} - -static void wmBaseHandlePing( - void* data, - struct xdg_wm_base* base, - uint32_t serial) -{ - xdgWmBasePong(base, serial); -} - -static void xdgSurfaceHandleConfigure( - void* data, - struct xdg_surface* surface, - uint32_t serial) -{ - WindowData* winData = (WindowData*)data; - xdgSurfaceAckConfigure(surface, serial); - - // push and resolve any pending events - if (!winData->skipConfigure) { - if (winData->pushConfigureEvent) { - if (winData->eglWindow) { - s_Wl.eglWindowResize(winData->eglWindow, winData->w, winData->h, 0, 0); - - } else { - // create a new buffer with the new size - struct wl_buffer* buffer = nullptr; - buffer = createShmBuffer(winData->w, winData->h, nullptr, PAL_FALSE); - if (!buffer) { - return; - } - - struct wl_surface* _surface = nullptr; - _surface = (struct wl_surface*)winData->window; - - surfaceAttach(_surface, buffer, 0, 0); - surfaceDamageBuffer(_surface, 0, 0, winData->w, winData->h); - surfaceCommit(_surface); - - // destroy old buffer - bufferDestroy(winData->buffer); - winData->buffer = buffer; - } - - // push a window resize event - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_WINDOW_SIZE; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(s_Video.eventDriver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = palPackUint32(winData->w, winData->h); - event.data2 = palPackPointer(winData->window); - palPushEvent(s_Video.eventDriver, &event); - } - } - - winData->pushConfigureEvent = PAL_FALSE; - } - } - - // pending state - if (!winData->skipState) { - if (!winData->pushStateEvent) { - return; - } - - // push a window state event - // we dont recreate buffers over here - // since we already create the buffer with the new size - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_WINDOW_STATE; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(s_Video.eventDriver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = winData->state; - event.data2 = palPackPointer(winData->window); - palPushEvent(s_Video.eventDriver, &event); - } - } - - winData->pushStateEvent = PAL_FALSE; - } -} - -static void xdgToplevelHandleConfigure( - void* data, - struct xdg_toplevel* toplevel, - int32_t width, - int32_t height, - struct wl_array* states) -{ - WindowData* winData = (WindowData*)data; - uint32_t* state; - PalBool activated = PAL_FALSE; - wl_array_for_each(state, states) - { - // we need only maximized - if (*state == 1) { // XDG_TOPLEVEL_STATE_MAXIMIZED - if (winData->state != PAL_WINDOW_STATE_MAXIMIZED) { - winData->state = PAL_WINDOW_STATE_MAXIMIZED; - winData->pushStateEvent = PAL_TRUE; - } - - } else if (*state == 4) { // XDG_TOPLEVEL_STATE_ACTIVATED - activated = PAL_TRUE; - } - } - - if (width > 0 && height > 0) { - if (width != winData->w || height != winData->h) { - // size change - winData->pushConfigureEvent = PAL_TRUE; - } - - winData->w = width; - winData->h = height; - } - - if (activated && !winData->focused) { - // focus gained - winData->focused = PAL_TRUE; - - } else if (!activated && winData->focused) { - // focus lost - winData->focused = PAL_FALSE; - - } else { - // discard double focus gained and double focus lost - return; - } - - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_WINDOW_FOCUS; - mode = palGetEventDispatchMode(driver, type); - - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data = winData->focused; - event.data2 = palPackPointer(winData->window); - palPushEvent(driver, &event); - } - } -} - -static void xdgToplevelHandleClose( - void* data, - struct xdg_toplevel* toplevel) -{ - WindowData* winData = (WindowData*)data; - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_WINDOW_CLOSE; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(s_Video.eventDriver, type); - if (mode != PAL_DISPATCH_NONE) { - PalEvent event = {0}; - event.type = type; - event.data2 = palPackPointer(winData->window); - palPushEvent(s_Video.eventDriver, &event); - } - } -} - -static inline int xdgSurfaceAddListener( - struct xdg_surface* xdg_surface, - const struct xdg_surface_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)xdg_surface, (void (**)(void))listener, data); -} - -static inline void xdgSurfaceDestroy(struct xdg_surface* xdg_surface) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_surface, - 0, // XDG_SURFACE_DESTROY - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline void xdgToplevelDestroy(struct xdg_toplevel* xdg_toplevel) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 0, // XDG_TOPLEVEL_DESTROY - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline void xdgToplevelSetTitle( - struct xdg_toplevel* xdg_toplevel, - const char* title) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 2, // XDG_TOPLEVEL_SET_TITLE - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0, - title); -} - -static inline void xdgToplevelSetMaximized(struct xdg_toplevel* xdg_toplevel) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 9, // XDG_TOPLEVEL_SET_MAXIMIZED - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0); -} - -static inline void xdgToplevelSetMinimized(struct xdg_toplevel* xdg_toplevel) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 13, // XDG_TOPLEVEL_SET_MINIMIZED - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0); -} - -static inline int xdgToplevelAddListener( - struct xdg_toplevel* xdg_toplevel, - const struct xdg_toplevel_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener((struct wl_proxy*)xdg_toplevel, (void (**)(void))listener, data); -} - -static inline void xdgToplevelSetMinSize( - struct xdg_toplevel* xdg_toplevel, - int32_t width, - int32_t height) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 8, // XDG_TOPLEVEL_SET_MIN_SIZE - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0, - width, - height); -} - -static inline void xdgToplevelSetMaxSize( - struct xdg_toplevel* xdg_toplevel, - int32_t width, - int32_t height) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 7, // XDG_TOPLEVEL_SET_MAX_SIZE - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0, - width, - height); -} - -static inline void xdgToplevelSetAppId( - struct xdg_toplevel* xdg_toplevel, - const char* app_id) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 3, // XDG_TOPLEVEL_SET_APP_ID - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0, - app_id); -} - -static inline void xdgToplevelUnsetMaximized(struct xdg_toplevel* xdg_toplevel) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)xdg_toplevel, - 10, // XDG_TOPLEVEL_UNSET_MAXIMIZED - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), - 0); -} - -static const struct xdg_wm_base_listener wmBaseListener = {.ping = wmBaseHandlePing}; - -struct xdg_toplevel; -struct zxdg_decoration_manager_v1; -struct zxdg_toplevel_decoration_v1; - -struct zxdg_toplevel_decoration_v1_listener { - void (*configure)( - void*, - struct zxdg_toplevel_decoration_v1*, - uint32_t); -}; - -const struct wl_interface zxdg_decoration_manager_v1_interface; -const struct wl_interface zxdg_toplevel_decoration_v1_interface; - -static inline void -zxdgDecorationManagerV1Destroy(struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)zxdg_decoration_manager_v1, - 0, // ZXDG_DECORATION_MANAGER_V1_DESTROY - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_decoration_manager_v1), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline struct zxdg_toplevel_decoration_v1* zxdgGetToplevelDecoration( - struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1, - struct xdg_toplevel* toplevel) -{ - struct wl_proxy* id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy*)zxdg_decoration_manager_v1, - 1, // ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, - &zxdg_toplevel_decoration_v1_interface, - s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_decoration_manager_v1), - 0, - NULL, - toplevel); - - return (struct zxdg_toplevel_decoration_v1*)id; -} - -static inline int zxdgToplevelDecorationV1AddListener( - struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, - const struct zxdg_toplevel_decoration_v1_listener* listener, - void* data) -{ - return s_Wl.proxyAddListener( - (struct wl_proxy*)zxdg_toplevel_decoration_v1, - (void (**)(void))listener, - data); -} - -static inline void -zxdgToplevelDecorationV1Destroy(struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)zxdg_toplevel_decoration_v1, - 0, // ZXDG_TOPLEVEL_DECORATION_V1_DESTROY - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_toplevel_decoration_v1), - WL_MARSHAL_FLAG_DESTROY); -} - -static inline void zxdgToplevelDecorationV1SetMode( - struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, - uint32_t mode) -{ - s_Wl.proxyMarshalFlags( - (struct wl_proxy*)zxdg_toplevel_decoration_v1, - 1, // ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, - NULL, - s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_toplevel_decoration_v1), - 0, - mode); -} - -static void setupXdgShellProtocol() -{ - xdg_shell_types[0] = NULL; - xdg_shell_types[1] = NULL; - xdg_shell_types[2] = NULL; - xdg_shell_types[3] = NULL; - xdg_shell_types[4] = &xdg_positioner_interface; - xdg_shell_types[5] = &xdg_surface_interface; - xdg_shell_types[6] = s_Wl.surfaceInterface; - xdg_shell_types[7] = &xdg_toplevel_interface; - xdg_shell_types[8] = &xdg_popup_interface; - xdg_shell_types[9] = &xdg_surface_interface; - xdg_shell_types[10] = &xdg_positioner_interface; - xdg_shell_types[11] = &xdg_toplevel_interface; - xdg_shell_types[12] = s_Wl.seatInterface; - xdg_shell_types[13] = NULL; - xdg_shell_types[14] = NULL; - xdg_shell_types[15] = NULL; - xdg_shell_types[16] = s_Wl.seatInterface; - xdg_shell_types[17] = NULL; - xdg_shell_types[18] = s_Wl.seatInterface; - xdg_shell_types[19] = NULL; - xdg_shell_types[20] = NULL; - xdg_shell_types[21] = s_Wl.outputInterface; - xdg_shell_types[22] = s_Wl.seatInterface; - xdg_shell_types[23] = NULL; - xdg_shell_types[24] = &xdg_positioner_interface; - xdg_shell_types[25] = NULL; -} - -static const struct wl_interface* xdg_decoration_unstable_v1_types[] = { - NULL, - &zxdg_toplevel_decoration_v1_interface, - &xdg_toplevel_interface, -}; - -static const struct wl_message zxdg_decoration_manager_v1_requests[] = { - {"destroy", "", xdg_decoration_unstable_v1_types + 0}, - {"get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1}, -}; - -const struct wl_interface zxdg_decoration_manager_v1_interface = { - "zxdg_decoration_manager_v1", - 1, - 2, - zxdg_decoration_manager_v1_requests, - 0, - NULL, -}; - -static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = { - {"destroy", "", xdg_decoration_unstable_v1_types + 0}, - {"set_mode", "u", xdg_decoration_unstable_v1_types + 0}, - {"unset_mode", "", xdg_decoration_unstable_v1_types + 0}, -}; - -static const struct wl_message zxdg_toplevel_decoration_v1_events[] = { - {"configure", "u", xdg_decoration_unstable_v1_types + 0}, -}; - -const struct wl_interface zxdg_toplevel_decoration_v1_interface = { - "zxdg_toplevel_decoration_v1", - 1, - 3, - zxdg_toplevel_decoration_v1_requests, - 1, - zxdg_toplevel_decoration_v1_events, -}; - -static void zxdgDecorationHandleConfigure( - void* data, - struct zxdg_toplevel_decoration_v1* dec, - uint32_t mode) -{ - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode dispatchMode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_WINDOW_DECORATION_MODE; - dispatchMode = palGetEventDispatchMode(driver, type); - - if (dispatchMode != PAL_DISPATCH_NONE) { - PalDecorationMode decorMode = PAL_DECORATION_MODE_SERVER_SIDE; - if (mode == 0 || mode == 1) { - // client side decoration - decorMode = PAL_DECORATION_MODE_CLIENT_SIDE; - } - - PalEvent event = {0}; - event.type = type; - event.data = decorMode; - event.data2 = palPackPointer(data); - palPushEvent(driver, &event); - } - } -} - -static int createShmFile(uint64_t size) -{ - char template[] = "/tmp/pal-shm-XXXXXX"; - int fd = mkstemp(template); - if (fd < 0) { - return -1; - } - - unlink(template); - if (ftruncate(fd, size) < 0) { - return -1; - } - - return fd; -} - -static struct wl_buffer* createShmBuffer( - int width, - int height, - const uint8_t* pixels, - PalBool cursor) -{ - int stride = width * 4; - uint64_t size = stride * height; - struct wl_buffer* buffer = nullptr; - struct wl_shm_pool* pool = nullptr; - void* data = nullptr; - - int fd = createShmFile(size); - if (fd == -1) { - return nullptr; - } - - data = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) { - return nullptr; - } - - enum wl_shm_format format = WL_SHM_FORMAT_XRGB8888; - if (cursor) { - format = WL_SHM_FORMAT_ARGB8888; - uint32_t* dataPixels = (uint32_t*)data; - - // convert from RGBA8 to ARGB32 - for (int i = 0; i < width * height; i++) { - uint8_t r = pixels[i * 4 + 0]; // Red - uint8_t g = pixels[i * 4 + 1]; // Green - uint8_t b = pixels[i * 4 + 2]; // Blue - uint8_t a = pixels[i * 4 + 3]; // Alpha - - // clang-format off - dataPixels[i] = ((unsigned long)a << 24) | - ((unsigned long)r << 16) | - ((unsigned long)g << 8) | - ((unsigned long)b); - // clang-format on - } - - } else { - memset(data, 0xFF, size); // white - } - - pool = shmCreatePool(s_Wl.shm, fd, size); - if (!pool) { - return nullptr; - } - - buffer = shmPoolCreateBuffer(pool, 0, width, height, stride, format); - if (!buffer) { - return nullptr; - } - - shmPoolDestroy(pool); - munmap(data, size); - close(fd); - return buffer; -} - -static void outputGeometry( - void* data, - struct wl_output* output, - int32_t x, - int32_t y, - int32_t, // we dont need physical size - int32_t, // we dont need physical size - int32_t, // we dont need subpixel - const char* make, - const char* model, - int32_t transform) -{ - MonitorData* monitorData = data; - monitorData->x = x; - monitorData->y = y; - - switch (transform) { - case WL_OUTPUT_TRANSFORM_NORMAL: - case WL_OUTPUT_TRANSFORM_180: { - monitorData->orientation = PAL_ORIENTATION_LANDSCAPE; - break; - } - - case WL_OUTPUT_TRANSFORM_90: - case WL_OUTPUT_TRANSFORM_270: { - monitorData->orientation = PAL_ORIENTATION_PORTRAIT; - break; - } - - case WL_OUTPUT_TRANSFORM_FLIPPED: - case WL_OUTPUT_TRANSFORM_FLIPPED_180: { - monitorData->orientation = PAL_ORIENTATION_LANDSCAPE_FLIPPED; - break; - } - - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - case WL_OUTPUT_TRANSFORM_FLIPPED_270: { - monitorData->orientation = PAL_ORIENTATION_PORTRAIT_FLIPPED; - break; - } - } - - snprintf(monitorData->name, 32, "%s %s", make, model); -} - -static void outputMode( - void* data, - struct wl_output* output, - uint32_t flags, - int32_t width, - int32_t height, - int32_t refresh) -{ - MonitorData* monitorData = data; - if (flags & WL_OUTPUT_MODE_CURRENT) { - monitorData->w = width; - monitorData->h = height; - monitorData->refreshRate = (refresh + 500) / 1000; - - // wayland only sends the current mode - monitorData->mode.bpp = 0; - monitorData->mode.width = width; - monitorData->mode.height = height; - monitorData->mode.refreshRate = (refresh + 500) / 1000; - } -} - -static void outputScale( - void* data, - struct wl_output* output, - int32_t scale) -{ - MonitorData* monitorData = data; - float dpi = (float)scale * 96.0f; - monitorData->dpi = (uint32_t)dpi; -} - -static void outputDone( - void* data, - struct wl_output* output) -{ -} - -static const struct wl_output_listener s_OutputListener = { - .geometry = outputGeometry, - .mode = outputMode, - .done = outputDone, - .scale = outputScale}; - -static const struct wl_output_listener s_DefaultModeListener = { - .geometry = outputGeometry, - .mode = outputMode, - .done = outputDone, - .scale = outputScale}; - -static void globalHandle( - void* data, - struct wl_registry* registry, - uint32_t name, - const char* interface, - uint32_t version) -{ - if (s_Wl.checkFeatures) { - PalVideoFeatures features = 0; - features |= PAL_VIDEO_FEATURE_HIGH_DPI; - features |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; - features |= PAL_VIDEO_FEATURE_MULTI_MONITORS; - features |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; - features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; - features |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; - - s_Video.features = features; - s_Wl.checkFeatures = PAL_FALSE; - } - - if (strcmp(interface, "wl_compositor") == 0) { - s_Wl.compositor = registryBind(registry, name, s_Wl.compositorInterface, 4); - - } else if (strcmp(interface, "xdg_wm_base") == 0) { - s_Wl.xdgBase = registryBind(registry, name, &xdg_wm_base_interface, 1); - - xdgWmBaseAddListener(s_Wl.xdgBase, &wmBaseListener, nullptr); - - } else if (strcmp(interface, "wl_shm") == 0) { - s_Wl.shm = registryBind(registry, name, s_Wl.shmInterface, 1); - - } else if (strcmp(interface, "wl_seat") == 0) { - s_Wl.seat = registryBind(registry, name, s_Wl.seatInterface, 5); - - seatAddListener(s_Wl.seat, &seatListener, nullptr); - - } else if (strcmp(interface, "zxdg_decoration_manager_v1") == 0) { - s_Wl.decorationManager = - registryBind(registry, name, &zxdg_decoration_manager_v1_interface, 1); - - s_Video.features |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; - - } else if (strcmp(interface, "wl_output") == 0) { - // wayland does not let use query monitors directly - // so we enumerate and store at init and update the - // cache when a monitor is added or removed - MonitorData* monitorData = getFreeMonitorData(); - if (!monitorData) { - return; - } - - struct wl_output* output = nullptr; - output = registryBind(s_Wl.registry, name, s_Wl.outputInterface, 3); - outputAddListener(output, &s_OutputListener, monitorData); - - monitorData->wlName = name; - monitorData->monitor = (PalMonitor*)output; - s_Wl.monitorCount++; - } -} - -static void globalRemove( - void* data, - struct wl_registry* registry, - uint32_t name) -{ - for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (s_Video.monitorData[i].used && s_Video.monitorData[i].wlName == name) { - MonitorData* data = &s_Video.monitorData[i]; - data->used = PAL_FALSE; - s_Wl.proxyDestroy((struct wl_proxy*)data->monitor); - s_Wl.monitorCount--; - } - } -} - -static const struct wl_registry_listener s_RegistryListener = { - .global = globalHandle, - .global_remove = globalRemove}; - -#endif // PAL_HAS_WAYLAND_BACKEND -#endif // __linux__ -#endif // _PAL_WAYLAND_HELPER_H \ No newline at end of file diff --git a/src/video/linux/wayland/pal_wayland_protocols.c b/src/video/linux/wayland/pal_wayland_protocols.c new file mode 100644 index 00000000..b61427f4 --- /dev/null +++ b/src/video/linux/wayland/pal_wayland_protocols.c @@ -0,0 +1,214 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#if PAL_HAS_WAYLAND_BACKEND == 1 + +#include "pal_wayland_protocols.h" + +// ================================================== +// Xdg Shell +// ================================================== + +static const struct wl_interface* xdg_shell_types[26]; + +static const struct wl_message xdg_wm_base_requests[] = { + {"destroy", "", xdg_shell_types + 0}, + {"create_positioner", "n", xdg_shell_types + 4}, + {"get_xdg_surface", "no", xdg_shell_types + 5}, + {"pong", "u", xdg_shell_types + 0}, +}; + +static const struct wl_message xdg_wm_base_events[] = { + {"ping", "u", xdg_shell_types + 0}, +}; + +const struct wl_interface xdg_wm_base_interface = { + "xdg_wm_base", + 6, + 4, + xdg_wm_base_requests, + 1, + xdg_wm_base_events, +}; + +static const struct wl_message xdg_positioner_requests[] = { + {"destroy", "", xdg_shell_types + 0}, + {"set_size", "ii", xdg_shell_types + 0}, + {"set_anchor_rect", "iiii", xdg_shell_types + 0}, + {"set_anchor", "u", xdg_shell_types + 0}, + {"set_gravity", "u", xdg_shell_types + 0}, + {"set_constraint_adjustment", "u", xdg_shell_types + 0}, + {"set_offset", "ii", xdg_shell_types + 0}, + {"set_reactive", "3", xdg_shell_types + 0}, + {"set_parent_size", "3ii", xdg_shell_types + 0}, + {"set_parent_configure", "3u", xdg_shell_types + 0}, +}; + +const struct wl_interface xdg_positioner_interface = { + "xdg_positioner", + 6, + 10, + xdg_positioner_requests, + 0, + NULL, +}; + +static const struct wl_message xdg_surface_requests[] = { + {"destroy", "", xdg_shell_types + 0}, + {"get_toplevel", "n", xdg_shell_types + 7}, + {"get_popup", "n?oo", xdg_shell_types + 8}, + {"set_window_geometry", "iiii", xdg_shell_types + 0}, + {"ack_configure", "u", xdg_shell_types + 0}, +}; + +static const struct wl_message xdg_surface_events[] = { + {"configure", "u", xdg_shell_types + 0}, +}; + +const struct wl_interface xdg_surface_interface = { + "xdg_surface", + 6, + 5, + xdg_surface_requests, + 1, + xdg_surface_events, +}; + +static const struct wl_message xdg_toplevel_requests[] = { + {"destroy", "", xdg_shell_types + 0}, + {"set_parent", "?o", xdg_shell_types + 11}, + {"set_title", "s", xdg_shell_types + 0}, + {"set_app_id", "s", xdg_shell_types + 0}, + {"show_window_menu", "ouii", xdg_shell_types + 12}, + {"move", "ou", xdg_shell_types + 16}, + {"resize", "ouu", xdg_shell_types + 18}, + {"set_max_size", "ii", xdg_shell_types + 0}, + {"set_min_size", "ii", xdg_shell_types + 0}, + {"set_maximized", "", xdg_shell_types + 0}, + {"unset_maximized", "", xdg_shell_types + 0}, + {"set_fullscreen", "?o", xdg_shell_types + 21}, + {"unset_fullscreen", "", xdg_shell_types + 0}, + {"set_minimized", "", xdg_shell_types + 0}, +}; + +static const struct wl_message xdg_toplevel_events[] = { + {"configure", "iia", xdg_shell_types + 0}, + {"close", "", xdg_shell_types + 0}, + {"configure_bounds", "4ii", xdg_shell_types + 0}, + {"wm_capabilities", "5a", xdg_shell_types + 0}, +}; + +const struct wl_interface xdg_toplevel_interface = { + "xdg_toplevel", + 6, + 14, + xdg_toplevel_requests, + 4, + xdg_toplevel_events, +}; + +static const struct wl_message xdg_popup_requests[] = { + {"destroy", "", xdg_shell_types + 0}, + {"grab", "ou", xdg_shell_types + 22}, + {"reposition", "3ou", xdg_shell_types + 24}, +}; + +static const struct wl_message xdg_popup_events[] = { + {"configure", "iiii", xdg_shell_types + 0}, + {"popup_done", "", xdg_shell_types + 0}, + {"repositioned", "3u", xdg_shell_types + 0}, +}; + +const struct wl_interface xdg_popup_interface = { + "xdg_popup", + 6, + 3, + xdg_popup_requests, + 3, + xdg_popup_events, +}; + +// ================================================== +// Zxdg Decoration +// ================================================== + +static const struct wl_interface* xdg_decoration_unstable_v1_types[] = { + NULL, + &zxdg_toplevel_decoration_v1_interface, + &xdg_toplevel_interface, +}; + +static const struct wl_message zxdg_decoration_manager_v1_requests[] = { + {"destroy", "", xdg_decoration_unstable_v1_types + 0}, + {"get_toplevel_decoration", "no", xdg_decoration_unstable_v1_types + 1}, +}; + +const struct wl_interface zxdg_decoration_manager_v1_interface = { + "zxdg_decoration_manager_v1", + 1, + 2, + zxdg_decoration_manager_v1_requests, + 0, + NULL, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_requests[] = { + {"destroy", "", xdg_decoration_unstable_v1_types + 0}, + {"set_mode", "u", xdg_decoration_unstable_v1_types + 0}, + {"unset_mode", "", xdg_decoration_unstable_v1_types + 0}, +}; + +static const struct wl_message zxdg_toplevel_decoration_v1_events[] = { + {"configure", "u", xdg_decoration_unstable_v1_types + 0}, +}; + +const struct wl_interface zxdg_toplevel_decoration_v1_interface = { + "zxdg_toplevel_decoration_v1", + 1, + 3, + zxdg_toplevel_decoration_v1_requests, + 1, + zxdg_toplevel_decoration_v1_events, +}; + +// ================================================== +// Protocols +// ================================================== + +void setupProtocols() +{ + xdg_shell_types[0] = NULL; + xdg_shell_types[1] = NULL; + xdg_shell_types[2] = NULL; + xdg_shell_types[3] = NULL; + xdg_shell_types[4] = &xdg_positioner_interface; + xdg_shell_types[5] = &xdg_surface_interface; + xdg_shell_types[6] = s_Wl.surfaceInterface; + xdg_shell_types[7] = &xdg_toplevel_interface; + xdg_shell_types[8] = &xdg_popup_interface; + xdg_shell_types[9] = &xdg_surface_interface; + xdg_shell_types[10] = &xdg_positioner_interface; + xdg_shell_types[11] = &xdg_toplevel_interface; + xdg_shell_types[12] = s_Wl.seatInterface; + xdg_shell_types[13] = NULL; + xdg_shell_types[14] = NULL; + xdg_shell_types[15] = NULL; + xdg_shell_types[16] = s_Wl.seatInterface; + xdg_shell_types[17] = NULL; + xdg_shell_types[18] = s_Wl.seatInterface; + xdg_shell_types[19] = NULL; + xdg_shell_types[20] = NULL; + xdg_shell_types[21] = s_Wl.outputInterface; + xdg_shell_types[22] = s_Wl.seatInterface; + xdg_shell_types[23] = NULL; + xdg_shell_types[24] = &xdg_positioner_interface; + xdg_shell_types[25] = NULL; +} + +#endif // PAL_HAS_WAYLAND_BACKEND +#endif // __linux__ \ No newline at end of file diff --git a/src/video/linux/wayland/pal_wayland_protocols.h b/src/video/linux/wayland/pal_wayland_protocols.h new file mode 100644 index 00000000..2468e84c --- /dev/null +++ b/src/video/linux/wayland/pal_wayland_protocols.h @@ -0,0 +1,680 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_WAYLAND_PROTOCOLS_H +#define _PAL_WAYLAND_PROTOCOLS_H +#ifdef __linux__ +#if PAL_HAS_WAYLAND_BACKEND == 1 + +#include "pal_wayland.h" + +// ================================================== +// Wayland Client +// ================================================== + +static inline void* wlRegistryBind( + struct wl_registry *wl_registry, + uint32_t name, + const struct wl_interface *interface, + uint32_t version) +{ + struct wl_proxy *id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy *)wl_registry, + WL_REGISTRY_BIND, + interface, + version, + 0, + name, + interface->name, + version, + NULL); + + return (void *)id; +} + +static inline int wlRegistryAddListener( + struct wl_registry *wl_registry, + const struct wl_registry_listener *listener, + void *data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy *) wl_registry, + (void (**)(void)) listener, data); +} + +static inline struct wl_registry* wlDisplayGetRegistry( + struct wl_display *wl_display) +{ + struct wl_proxy *registry; + registry = s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_display, + 1, // WL_DISPLAY_GET_REGISTRY + s_Wl.registryInterface, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_display), + 0, + NULL); + + return (struct wl_registry *)registry; +} + +static inline int wlOutputAddListener( + struct wl_output *wl_output, + const struct wl_output_listener *listener, + void *data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy *) wl_output, + (void (**)(void)) listener, data); +} + +static inline struct wl_surface* wlCompositorCreateSurface( + struct wl_compositor *wl_compositor) +{ + struct wl_proxy *id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_compositor, + 0, // WL_COMPOSITOR_CREATE_SURFACE, + s_Wl.surfaceInterface, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_compositor), + 0, + NULL); + + return (struct wl_surface*) id; +} + +static inline void wlSurfaceCommit(struct wl_surface *wl_surface) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_surface, + 6, // WL_SURFACE_COMMIT + NULL, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_surface), + 0); +} + +static inline void wlSurfaceDestroy(struct wl_surface *wl_surface) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_surface, + 0, // WL_SURFACE_DESTROY + NULL, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_surface), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline struct wl_shm_pool* wlShmCreatePool( + struct wl_shm *wl_shm, + int32_t fd, + int32_t size) +{ + struct wl_proxy *id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_shm, + 0, // WL_SHM_CREATE_POOL + s_Wl.shmPoolInterface, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_shm), + 0, + NULL, + fd, + size); + + return (struct wl_shm_pool *) id; +} + +static inline void wlShmPoolDestroy(struct wl_shm_pool *wl_shm_pool) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_DESTROY, + NULL, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_shm_pool), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline struct wl_buffer* wlShmPoolCreateBuffer( + struct wl_shm_pool *wl_shm_pool, + int32_t offset, + int32_t width, + int32_t height, + int32_t stride, + uint32_t format) +{ + struct wl_proxy *id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_shm_pool, + WL_SHM_POOL_CREATE_BUFFER, + s_Wl.bufferInterface, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_shm_pool), + 0, + NULL, + offset, + width, + height, + stride, + format); + + return (struct wl_buffer *) id; +} + +static inline void wlBufferDestroy(struct wl_buffer *wl_buffer) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_buffer, + WL_BUFFER_DESTROY, + NULL, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_buffer), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline void wlSurfaceAttach( + struct wl_surface *wl_surface, + struct wl_buffer *buffer, + int32_t x, + int32_t y) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_surface, + WL_SURFACE_ATTACH, + NULL, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_surface), + 0, + buffer, + x, + y); +} + +static inline void wlSurfaceDamageBuffer( + struct wl_surface *wl_surface, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_surface, + WL_SURFACE_DAMAGE_BUFFER, + NULL, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_surface), + 0, + x, + y, + width, + height); +} + +static inline int wlSurfaceAddListener( + struct wl_surface *wl_surface, + const struct wl_surface_listener *listener, + void *data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy *) wl_surface, + (void (**)(void)) listener, data); +} + +static inline int wlSeatAddListener( + struct wl_seat *wl_seat, + const struct wl_seat_listener *listener, + void *data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy *) wl_seat, + (void (**)(void)) listener, data); +} + +static inline struct wl_pointer* wlSeatGetPointer(struct wl_seat *wl_seat) +{ + struct wl_proxy *id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_seat, + WL_SEAT_GET_POINTER, + s_Wl.pointerInterface, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_seat), + 0, + NULL); + + return (struct wl_pointer *) id; +} + +static inline struct wl_keyboard* wlSeatGetKeyboard(struct wl_seat *wl_seat) +{ + struct wl_proxy *id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_seat, + WL_SEAT_GET_KEYBOARD, + s_Wl.keyboardInterface, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_seat), + 0, + NULL); + + return (struct wl_keyboard *) id; +} + +static inline int wlPointerAddListener( + struct wl_pointer *wl_pointer, + const struct wl_pointer_listener *listener, + void *data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy *) wl_pointer, + (void (**)(void)) listener, data); +} + +static inline void wlPointerSetCursor( + struct wl_pointer *wl_pointer, + uint32_t serial, + struct wl_surface *surface, + int32_t hotspot_x, + int32_t hotspot_y) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_pointer, + WL_POINTER_SET_CURSOR, + NULL, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_pointer), + 0, + serial, + surface, + hotspot_x, + hotspot_y); +} + +static inline int wlKeyboardAddListener( + struct wl_keyboard *wl_keyboard, + const struct wl_keyboard_listener *listener, + void *data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy *) wl_keyboard, + (void (**)(void)) listener, data); +} + +static inline struct wl_region* wlCompositorCreateRegion( + struct wl_compositor *wl_compositor) +{ + struct wl_proxy *id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_compositor, + WL_COMPOSITOR_CREATE_REGION, + s_Wl.regionInterface, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_compositor), + 0, + NULL); + + return (struct wl_region *) id; +} + +static inline void wlRegionAdd( + struct wl_region *wl_region, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_region, + WL_REGION_ADD, + NULL, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_region), + 0, + x, + y, + width, + height); +} + +static inline void wlSurfaceSetOpaqueRegion( + struct wl_surface *wl_surface, + struct wl_region *region) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_surface, + WL_SURFACE_SET_OPAQUE_REGION, + NULL, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_surface), + 0, + region); +} + +static inline void wlRegionDestroy(struct wl_region *wl_region) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy *) wl_region, + WL_REGION_DESTROY, + NULL, + s_Wl.proxyGetVersion( + (struct wl_proxy *) wl_region), + WL_MARSHAL_FLAG_DESTROY); +} + +// ================================================== +// Xdg +// ================================================== + +struct xdg_wm_base; +struct xdg_surface; +struct xdg_toplevel; + +extern const struct wl_interface xdg_popup_interface; +extern const struct wl_interface xdg_positioner_interface; +extern const struct wl_interface xdg_surface_interface; +extern const struct wl_interface xdg_toplevel_interface; + +struct xdg_wm_base_listener { + void (*ping)(void*, struct xdg_wm_base*, uint32_t); +}; + +struct xdg_surface_listener { + void (*configure)(void*, struct xdg_surface*, uint32_t); +}; + +struct xdg_toplevel_listener { + // clang-format off + void (*configure)(void*, struct xdg_toplevel*, int32_t, int32_t, struct wl_array*); + void (*close)(void*, struct xdg_toplevel*); + void (*configure_bounds)(void*, struct xdg_toplevel*, int32_t, int32_t); + void (*wm_capabilities)(void*, struct xdg_toplevel*, struct wl_array*); + // clang-format on +}; + +static inline void xdgWmBasePong( + struct xdg_wm_base* xdg_wm_base, + uint32_t serial) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_wm_base, + 3, // XDG_WM_BASE_PONG + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_wm_base), + 0, + serial); +} + +static inline int xdgWmBaseAddListener( + struct xdg_wm_base* xdg_wm_base, + const struct xdg_wm_base_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy*)xdg_wm_base, + (void (**)(void))listener, + data); +} + +static inline struct xdg_surface* xdgWmBaseGetXdgSurface( + struct xdg_wm_base* xdg_wm_base, + struct wl_surface* surface) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_wm_base, + 2, // XDG_WM_BASE_GET_XDG_SURFACE, + &xdg_surface_interface, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_wm_base), + 0, + NULL, + surface); + + return (struct xdg_surface*)id; +} + +static inline struct xdg_toplevel* +xdgSurfaceGetToplevel(struct xdg_surface* xdg_surface) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_surface, + 1, // XDG_SURFACE_GET_TOPLEVEL, + &xdg_toplevel_interface, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), + 0, + NULL); + + return (struct xdg_toplevel*)id; +} + +static inline void xdgSurfaceAckConfigure( + struct xdg_surface* xdg_surface, + uint32_t serial) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_surface, + 4, // XDG_SURFACE_ACK_CONFIGURE + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), + 0, + serial); +} + +static inline int xdgSurfaceAddListener( + struct xdg_surface* xdg_surface, + const struct xdg_surface_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy*)xdg_surface, + (void (**)(void))listener, + data); +} + +static inline void xdgSurfaceDestroy(struct xdg_surface* xdg_surface) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_surface, + 0, // XDG_SURFACE_DESTROY + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_surface), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline void xdgToplevelDestroy(struct xdg_toplevel* xdg_toplevel) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 0, // XDG_TOPLEVEL_DESTROY + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline void xdgToplevelSetTitle( + struct xdg_toplevel* xdg_toplevel, + const char* title) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 2, // XDG_TOPLEVEL_SET_TITLE + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0, + title); +} + +static inline void xdgToplevelSetMaximized(struct xdg_toplevel* xdg_toplevel) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 9, // XDG_TOPLEVEL_SET_MAXIMIZED + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0); +} + +static inline void xdgToplevelSetMinimized(struct xdg_toplevel* xdg_toplevel) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 13, // XDG_TOPLEVEL_SET_MINIMIZED + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0); +} + +static inline int xdgToplevelAddListener( + struct xdg_toplevel* xdg_toplevel, + const struct xdg_toplevel_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy*)xdg_toplevel, + (void (**)(void))listener, + data); +} + +static inline void xdgToplevelSetMinSize( + struct xdg_toplevel* xdg_toplevel, + int32_t width, + int32_t height) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 8, // XDG_TOPLEVEL_SET_MIN_SIZE + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0, + width, + height); +} + +static inline void xdgToplevelSetMaxSize( + struct xdg_toplevel* xdg_toplevel, + int32_t width, + int32_t height) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 7, // XDG_TOPLEVEL_SET_MAX_SIZE + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0, + width, + height); +} + +static inline void xdgToplevelSetAppId( + struct xdg_toplevel* xdg_toplevel, + const char* app_id) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 3, // XDG_TOPLEVEL_SET_APP_ID + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0, + app_id); +} + +static inline void xdgToplevelUnsetMaximized(struct xdg_toplevel* xdg_toplevel) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)xdg_toplevel, + 10, // XDG_TOPLEVEL_UNSET_MAXIMIZED + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)xdg_toplevel), + 0); +} + +// ================================================== +// Zxdg +// ================================================== + +struct zxdg_decoration_manager_v1; +struct zxdg_toplevel_decoration_v1; + +struct zxdg_toplevel_decoration_v1_listener { + void (*configure)( + void*, + struct zxdg_toplevel_decoration_v1*, + uint32_t); +}; + +extern const struct wl_interface zxdg_decoration_manager_v1_interface; +extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; + +static inline void zxdgDecorationManagerV1Destroy( + struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)zxdg_decoration_manager_v1, + 0, // ZXDG_DECORATION_MANAGER_V1_DESTROY + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_decoration_manager_v1), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline struct zxdg_toplevel_decoration_v1* zxdgGetToplevelDecoration( + struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1, + struct xdg_toplevel* toplevel) +{ + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)zxdg_decoration_manager_v1, + 1, // ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION, + &zxdg_toplevel_decoration_v1_interface, + s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_decoration_manager_v1), + 0, + NULL, + toplevel); + + return (struct zxdg_toplevel_decoration_v1*)id; +} + +static inline int zxdgToplevelDecorationV1AddListener( + struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, + const struct zxdg_toplevel_decoration_v1_listener* listener, + void* data) +{ + return s_Wl.proxyAddListener( + (struct wl_proxy*)zxdg_toplevel_decoration_v1, + (void (**)(void))listener, + data); +} + +static inline void zxdgToplevelDecorationV1Destroy( + struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)zxdg_toplevel_decoration_v1, + 0, // ZXDG_TOPLEVEL_DECORATION_V1_DESTROY + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_toplevel_decoration_v1), + WL_MARSHAL_FLAG_DESTROY); +} + +static inline void zxdgToplevelDecorationV1SetMode( + struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, + uint32_t mode) +{ + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)zxdg_toplevel_decoration_v1, + 1, // ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)zxdg_toplevel_decoration_v1), + 0, + mode); +} + +#endif // PAL_HAS_WAYLAND_BACKEND +#endif // __linux__ +#endif // _PAL_WAYLAND_PROTOCOLS_H \ No newline at end of file diff --git a/src/video/linux/wayland/pal_window_wayland.c b/src/video/linux/wayland/pal_window_wayland.c index bf465100..23d39fec 100644 --- a/src/video/linux/wayland/pal_window_wayland.c +++ b/src/video/linux/wayland/pal_window_wayland.c @@ -8,22 +8,11 @@ #ifdef __linux__ #if PAL_HAS_WAYLAND_BACKEND == 1 -#include "pal_wayland_helper.h" +#include "pal_wayland.h" +#include "pal_wayland_protocols.h" #include "pal_shared.h" #include -static const struct xdg_surface_listener xdgSurfaceListener = { - .configure = xdgSurfaceHandleConfigure}; - -static const struct xdg_toplevel_listener xdgToplevelListener = { - .configure = xdgToplevelHandleConfigure, - .close = xdgToplevelHandleClose, - .configure_bounds = nullptr, - .wm_capabilities = nullptr}; - -static struct zxdg_toplevel_decoration_v1_listener decorationListener = { - .configure = zxdgDecorationHandleConfigure}; - PalResult wlCreateWindow( const PalWindowCreateInfo* info, PalWindow** outWindow) @@ -73,27 +62,33 @@ PalResult wlCreateWindow( data->focused = PAL_FALSE; // create surface - surface = compositorCreateSurface(s_Wl.compositor); + surface = wlCompositorCreateSurface(s_Wl.compositor); if (!surface) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } - surfaceAddListener(surface, &surfaceListener, data); + wlSurfaceAddListener(surface, &s_SurfaceListener, data); xdgSurface = xdgWmBaseGetXdgSurface(s_Wl.xdgBase, surface); if (!xdgSurface) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } xdgToplevel = xdgSurfaceGetToplevel(xdgSurface); if (!xdgSurface) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } // set APP id - const char* appID = getenv("RESOURCE_CLASS"); + const char* appID = info->appName; if (!appID || strlen(appID) == 0) { appID = s_Video.className; } @@ -106,28 +101,28 @@ PalResult wlCreateWindow( xdgToplevelSetTitle(xdgToplevel, title); xdgToplevelSetAppId(xdgToplevel, appID); - xdgToplevelAddListener(xdgToplevel, &xdgToplevelListener, data); - xdgSurfaceAddListener(xdgSurface, &xdgSurfaceListener, data); + xdgToplevelAddListener(xdgToplevel, &s_XdgToplevelListener, data); + xdgSurfaceAddListener(xdgSurface, &s_XdgSurfaceListener, data); // decorated window if (!(info->style & PAL_WINDOW_STYLE_BORDERLESS)) { struct zxdg_toplevel_decoration_v1* decoration = nullptr; decoration = zxdgGetToplevelDecoration(s_Wl.decorationManager, xdgToplevel); - zxdgToplevelDecorationV1AddListener(decoration, &decorationListener, surface); + zxdgToplevelDecorationV1AddListener(decoration, &s_DecorationListener, surface); zxdgToplevelDecorationV1SetMode(decoration, 2); data->decoration = decoration; } data->skipState = PAL_TRUE; data->skipConfigure = PAL_TRUE; - surfaceCommit(surface); + wlSurfaceCommit(surface); s_Wl.displayRoundtrip(s_Wl.display); if (info->maximized && info->show) { // we need the maximized size the compositor will use // and use that to create the buffer xdgToplevelSetMaximized(xdgToplevel); - surfaceCommit(surface); + wlSurfaceCommit(surface); s_Wl.displayRoundtrip(s_Wl.display); data->state = PAL_WINDOW_STATE_MAXIMIZED; @@ -147,15 +142,17 @@ PalResult wlCreateWindow( // This is just a requeest, the compositor might ignore it if (info->minimized) { xdgToplevelSetMinimized(xdgToplevel); - surfaceCommit(surface); + wlSurfaceCommit(surface); data->state = PAL_WINDOW_STATE_MINIMIZED; } if (s_Wl.eglFBConfig) { data->eglWindow = s_Wl.eglWindowCreate(surface, data->w, data->h); if (!data->eglWindow) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } } else { @@ -163,22 +160,24 @@ PalResult wlCreateWindow( struct wl_buffer* buffer = nullptr; buffer = createShmBuffer(data->w, data->h, nullptr, PAL_FALSE); if (!buffer) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); } - surfaceAttach(surface, buffer, 0, 0); - surfaceDamageBuffer(surface, 0, 0, data->w, data->h); - surfaceCommit(surface); + wlSurfaceAttach(surface, buffer, 0, 0); + wlSurfaceDamageBuffer(surface, 0, 0, data->w, data->h); + wlSurfaceCommit(surface); data->buffer = buffer; } - struct wl_region* region = compositorCreateRegion(s_Wl.compositor); + struct wl_region* region = wlCompositorCreateRegion(s_Wl.compositor); if (region) { - regionAdd(region, 0, 0, data->w, data->h); - surfaceSetOpaqueRegion(surface, region); - regionDestroy(region); - surfaceCommit(surface); + wlRegionAdd(region, 0, 0, data->w, data->h); + wlSurfaceSetOpaqueRegion(surface, region); + wlRegionDestroy(region); + wlSurfaceCommit(surface); } s_Wl.displayRoundtrip(s_Wl.display); @@ -223,12 +222,12 @@ void wlDestroyWindow(PalWindow* window) if (data->eglWindow) { s_Wl.eglWindowDestroy(data->eglWindow); } else { - bufferDestroy(data->buffer); + wlBufferDestroy(data->buffer); } xdgToplevelDestroy(data->xdgToplevel); xdgSurfaceDestroy(data->xdgSurface); - surfaceDestroy((struct wl_surface*)window); + wlSurfaceDestroy((struct wl_surface*)window); data->used = PAL_FALSE; } @@ -469,7 +468,7 @@ PalResult wlSetWindowSize( xdgToplevelSetMinSize(data->xdgToplevel, width, height); xdgToplevelSetMaxSize(data->xdgToplevel, width, height); - surfaceCommit((struct wl_surface*)window); + wlSurfaceCommit((struct wl_surface*)window); return PAL_RESULT_SUCCESS; } diff --git a/src/video/linux/x11/pal_monitor_x11.c b/src/video/linux/x11/pal_monitor_x11.c index 9c1aa244..27e4554a 100644 --- a/src/video/linux/x11/pal_monitor_x11.c +++ b/src/video/linux/x11/pal_monitor_x11.c @@ -12,7 +12,7 @@ #include "pal_shared.h" #include -static PalResult xEnumerateMonitors( +PalResult xEnumerateMonitors( int32_t* count, PalMonitor** outMonitors) { @@ -39,7 +39,7 @@ static PalResult xEnumerateMonitors( return PAL_RESULT_SUCCESS; } -static PalResult xGetPrimaryMonitor(PalMonitor** outMonitor) +PalResult xGetPrimaryMonitor(PalMonitor** outMonitor) { RROutput primary = s_X11.getOutputPrimary(s_X11.display, s_X11.root); if (primary) { @@ -53,7 +53,7 @@ static PalResult xGetPrimaryMonitor(PalMonitor** outMonitor) errno); } -static PalResult xGetMonitorInfo( +PalResult xGetMonitorInfo( PalMonitor* monitor, PalMonitorInfo* info) { @@ -160,7 +160,7 @@ static PalResult xGetMonitorInfo( return PAL_RESULT_SUCCESS; } -static PalResult xEnumerateMonitorModes( +PalResult xEnumerateMonitorModes( PalMonitor* monitor, int32_t* count, PalMonitorMode* modes) @@ -225,7 +225,7 @@ static PalResult xEnumerateMonitorModes( return PAL_RESULT_SUCCESS; } -static PalResult xGetCurrentMonitorMode( +PalResult xGetCurrentMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { @@ -283,7 +283,7 @@ static PalResult xGetCurrentMonitorMode( return PAL_RESULT_SUCCESS; } -static PalResult xSetMonitorMode( +PalResult xSetMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { @@ -353,7 +353,7 @@ static PalResult xSetMonitorMode( return PAL_RESULT_SUCCESS; } -static PalResult xValidateMonitorMode( +PalResult xValidateMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { @@ -363,7 +363,7 @@ static PalResult xValidateMonitorMode( errno); } -static PalResult xSetMonitorOrientation( +PalResult xSetMonitorOrientation( PalMonitor* monitor, PalOrientation orientation) { diff --git a/src/video/linux/x11/pal_video_x11.c b/src/video/linux/x11/pal_video_x11.c index 45ae814b..51b09ac9 100644 --- a/src/video/linux/x11/pal_video_x11.c +++ b/src/video/linux/x11/pal_video_x11.c @@ -116,7 +116,7 @@ static PalResult eglXBackend(int index) return PAL_RESULT_SUCCESS; } -static RRMode findMode( +RRMode findMode( XRRScreenResources* resources, const PalMonitorMode* mode) { @@ -357,7 +357,7 @@ static int getWindowMonitorDPI(WindowData* data) } } -static void sendWMEvent( +void sendWMEvent( Window window, Atom type, long a, @@ -440,7 +440,7 @@ static void createKeycodeTable() s_Keyboard.keycodes[XK_bracketright] = PAL_KEYCODE_RBRACKET; } -static PalResult xInitVideo() +PalResult xInitVideo() { // load X11 library s_X11.handle = dlopen("libX11.so", RTLD_LAZY); @@ -836,7 +836,7 @@ static PalResult xInitVideo() return PAL_RESULT_SUCCESS; } -static void xShutdownVideo() +void xShutdownVideo() { s_X11.closeIM(s_X11.im); if (!s_Video.platformInstance) { @@ -873,7 +873,7 @@ PalResult xSetFBConfig( } } -static void xUpdateVideo() +void xUpdateVideo() { XEvent event; PalDispatchMode mode = PAL_DISPATCH_NONE; diff --git a/src/video/linux/x11/pal_window_x11.c b/src/video/linux/x11/pal_window_x11.c index 5c958d95..96e1b92f 100644 --- a/src/video/linux/x11/pal_window_x11.c +++ b/src/video/linux/x11/pal_window_x11.c @@ -10,6 +10,9 @@ #include "pal_x11.h" #include "pal_shared.h" +#include +#include +#include static int xErrorHandler( Display*, @@ -20,7 +23,7 @@ static int xErrorHandler( return 0; } -static PalResult xCreateWindow( +PalResult xCreateWindow( const PalWindowCreateInfo* info, PalWindow** outWindow) { @@ -216,8 +219,8 @@ static PalResult xCreateWindow( // set class property XClassHint* hints = s_X11.allocClassHint(); if (hints) { - const char* resName = getenv("RESOURCE_NAME"); - const char* resClass = getenv("RESOURCE_CLASS"); + const char* resName = info->instanceName; + const char* resClass = info->appName; if (!resName || strlen(resName) == 0) { resName = info->title; @@ -360,7 +363,7 @@ static PalResult xCreateWindow( } } - xSendWMEvent( + sendWMEvent( window, s_X11Atoms._NET_WM_STATE, s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT, @@ -428,7 +431,7 @@ static PalResult xCreateWindow( return PAL_RESULT_SUCCESS; } -static void xDestroyWindow(PalWindow* window) +void xDestroyWindow(PalWindow* window) { Window xWin = FROM_PAL_HANDLE(Window, window); WindowData* data = nullptr; @@ -489,7 +492,7 @@ PalResult xMaximizeWindow(PalWindow* window) errno); } - xSendWMEvent( + sendWMEvent( xWin, s_X11Atoms._NET_WM_STATE, s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT, @@ -521,7 +524,7 @@ PalResult xRestoreWindow(PalWindow* window) // since we have no fixed way to restore the window // we just restore from minimized and maximized state - xSendWMEvent( + sendWMEvent( xWin, s_X11Atoms._NET_WM_STATE, s_X11Atoms._NET_WM_STATE_MAXIMIZED_VERT, @@ -592,7 +595,7 @@ PalResult xFlashWindow( // check if modern flashing is supported if (s_X11Atoms._NET_WM_STATE_DEMANDS_ATTENTIONS) { - xSendWMEvent( + sendWMEvent( xWin, s_X11Atoms._NET_WM_STATE, s_X11Atoms._NET_WM_STATE_DEMANDS_ATTENTIONS, @@ -869,7 +872,7 @@ PalResult xGetWindowHandleInfo( return PAL_RESULT_SUCCESS; } -static PalResult xSetWindowOpacity( +PalResult xSetWindowOpacity( PalWindow* window, float opacity) { @@ -1015,7 +1018,7 @@ PalResult xSetFocusWindow(PalWindow* window) } if (s_X11Atoms._NET_ACTIVE_WINDOW) { - xSendWMEvent(xWin, s_X11Atoms._NET_ACTIVE_WINDOW, CurrentTime, 0, 0, 0, + sendWMEvent(xWin, s_X11Atoms._NET_ACTIVE_WINDOW, CurrentTime, 0, 0, 0, PAL_TRUE); // 1 } else { diff --git a/src/video/linux/x11/pal_x11.h b/src/video/linux/x11/pal_x11.h index b470930b..8c542f78 100644 --- a/src/video/linux/x11/pal_x11.h +++ b/src/video/linux/x11/pal_x11.h @@ -558,6 +558,21 @@ typedef struct { extern X11 s_X11; extern X11Atoms s_X11Atoms; +RRMode findMode( + XRRScreenResources* resources, + const PalMonitorMode* mode); + +void sendWMEvent( + Window window, + Atom type, + long a, + long b, + long c, + long d, + PalBool add); + +PalResult xGetPrimaryMonitor(PalMonitor**); + #endif // PAL_HAS_X11_BACKEND #endif // __linux__ #endif // _PAL_X11_H \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index 40cb31d5..e63b95c2 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -28,7 +28,7 @@ int main(int argc, char** argv) #endif // PAL_HAS_THREAD_MODULE #if PAL_HAS_VIDEO_MODULE == 1 - // registerTest(videoTest, "Video Test"); + registerTest(videoTest, "Video Test"); // registerTest(monitorTest, "Monitor Test"); // registerTest(monitorModeTest, "Monitor Mode Test"); // registerTest(windowTest, "Window Test"); @@ -39,7 +39,7 @@ int main(int argc, char** argv) // registerTest(attachWindowTest, "Attach Window Test"); // registerTest(charEventTest, "Char Event Test"); // registerTest(nativeIntegrationTest, "Native Integration Test"); - registerTest(nativeInstanceTest, "Native Instance Test"); + // registerTest(nativeInstanceTest, "Native Instance Test"); // registerTest(customDecorationTest, "Custom Decoration Test"); #endif // PAL_HAS_VIDEO_MODULE diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index 40bce9d7..a38a78e0 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -119,7 +119,7 @@ static const struct wl_interface* surfaceInterface; static const struct wl_interface* bufferInterface; static const struct wl_interface* subsurfaceInterface; -static inline void* registryBind( +static inline void* wlRegistryBind( struct wl_registry* wl_registry, uint32_t name, const struct wl_interface* interface, @@ -140,7 +140,7 @@ static inline void* registryBind( return (void*)id; } -static inline int registryAddListener( +static inline int wlRegistryAddListener( struct wl_registry* wl_registry, const struct wl_registry_listener* listener, void* data) @@ -148,7 +148,7 @@ static inline int registryAddListener( return s_wl_proxy_add_listener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); } -static inline struct wl_registry* displayGetRegistry(struct wl_display* wl_display) +static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_display) { struct wl_proxy* registry; registry = s_wl_proxy_marshal_flags( @@ -162,7 +162,7 @@ static inline struct wl_registry* displayGetRegistry(struct wl_display* wl_displ return (struct wl_registry*)registry; } -static inline struct wl_surface* compositorCreateSurface(struct wl_compositor* wl_compositor) +static inline struct wl_surface* wlCompositorCreateSurface(struct wl_compositor* wl_compositor) { struct wl_proxy* id; id = s_wl_proxy_marshal_flags( @@ -176,7 +176,7 @@ static inline struct wl_surface* compositorCreateSurface(struct wl_compositor* w return (struct wl_surface*)id; } -static inline void surfaceCommit(struct wl_surface* wl_surface) +static inline void wlSurfaceCommit(struct wl_surface* wl_surface) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_surface, @@ -186,7 +186,7 @@ static inline void surfaceCommit(struct wl_surface* wl_surface) 0); } -static inline void surfaceDestroy(struct wl_surface* wl_surface) +static inline void wlSurfaceDestroy(struct wl_surface* wl_surface) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_surface, @@ -196,7 +196,7 @@ static inline void surfaceDestroy(struct wl_surface* wl_surface) WL_MARSHAL_FLAG_DESTROY); } -static inline struct wl_shm_pool* shmCreatePool( +static inline struct wl_shm_pool* wlShmCreatePool( struct wl_shm* wl_shm, int32_t fd, int32_t size) @@ -215,7 +215,7 @@ static inline struct wl_shm_pool* shmCreatePool( return (struct wl_shm_pool*)id; } -static inline void shmPoolDestroy(struct wl_shm_pool* wl_shm_pool) +static inline void wlShmPoolDestroy(struct wl_shm_pool* wl_shm_pool) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_shm_pool, @@ -225,7 +225,7 @@ static inline void shmPoolDestroy(struct wl_shm_pool* wl_shm_pool) WL_MARSHAL_FLAG_DESTROY); } -static inline struct wl_buffer* shmPoolCreateBuffer( +static inline struct wl_buffer* wlShmPoolCreateBuffer( struct wl_shm_pool* wl_shm_pool, int32_t offset, int32_t width, @@ -250,7 +250,7 @@ static inline struct wl_buffer* shmPoolCreateBuffer( return (struct wl_buffer*)id; } -static inline void bufferDestroy(struct wl_buffer* wl_buffer) +static inline void wlBufferDestroy(struct wl_buffer* wl_buffer) { s_wl_proxy_marshal_flags( (struct wl_proxy*)wl_buffer, @@ -260,7 +260,7 @@ static inline void bufferDestroy(struct wl_buffer* wl_buffer) WL_MARSHAL_FLAG_DESTROY); } -static inline void surfaceAttach( +static inline void wlSurfaceAttach( struct wl_surface* wl_surface, struct wl_buffer* buffer, int32_t x, @@ -277,7 +277,7 @@ static inline void surfaceAttach( y); } -static inline void surfaceDamageBuffer( +static inline void wlSurfaceDamageBuffer( struct wl_surface* wl_surface, int32_t x, int32_t y, @@ -368,16 +368,16 @@ static void globalHandle( uint32_t version) { if (strcmp(interface, "wl_seat") == 0) { - s_Seat = registryBind(registry, name, seatInterface, 5); + s_Seat = wlRegistryBind(registry, name, seatInterface, 5); } else if (strcmp(interface, "wl_compositor") == 0) { - s_Compositor = registryBind(registry, name, compositorInterface, 4); + s_Compositor = wlRegistryBind(registry, name, compositorInterface, 4); } else if (strcmp(interface, "wl_subcompositor") == 0) { - s_Subcompositor = registryBind(registry, name, subCompositorInterface, 1); + s_Subcompositor = wlRegistryBind(registry, name, subCompositorInterface, 1); } else if (strcmp(interface, "wl_shm") == 0) { - s_Shm = registryBind(registry, name, shmInterface, 1); + s_Shm = wlRegistryBind(registry, name, shmInterface, 1); } } @@ -481,8 +481,8 @@ static void openDisplayWayland() struct wl_display* display = s_wl_display_connect(nullptr); if (display) { - struct wl_registry* registry = displayGetRegistry(display); - registryAddListener(registry, &s_RegistryListener, nullptr); + struct wl_registry* registry = wlDisplayGetRegistry(display); + wlRegistryAddListener(registry, &s_RegistryListener, nullptr); s_wl_display_roundtrip(display); s_Display = display; } @@ -545,17 +545,17 @@ static struct wl_buffer* createShmBuffer( return nullptr; } - pool = shmCreatePool(s_Shm, fd, size); + pool = wlShmCreatePool(s_Shm, fd, size); if (!pool) { return nullptr; } - buffer = shmPoolCreateBuffer(pool, 0, width, height, stride, 1); + buffer = wlShmPoolCreateBuffer(pool, 0, width, height, stride, 1); if (!buffer) { return nullptr; } - shmPoolDestroy(pool); + wlShmPoolDestroy(pool); *outPixels = (uint32_t*)data; *outFd = fd; @@ -683,7 +683,7 @@ static PalWindowHandleInfo s_WinHandle; static void createDecoration() { - s_Decoration.surface = compositorCreateSurface(s_Compositor); + s_Decoration.surface = wlCompositorCreateSurface(s_Compositor); if (!s_Decoration.surface) { palLog(nullptr, "Failed to create wayland surface"); return; @@ -753,12 +753,12 @@ static void createDecoration() TITLEBAR_HEIGHT / 2, // half of the size of the title bar 0x0033AAAA); - surfaceAttach(s_Decoration.surface, s_Decoration.buffer, 0, 0); - surfaceDamageBuffer(s_Decoration.surface, 0, 0, width, TITLEBAR_HEIGHT); - surfaceCommit(s_Decoration.surface); + wlSurfaceAttach(s_Decoration.surface, s_Decoration.buffer, 0, 0); + wlSurfaceDamageBuffer(s_Decoration.surface, 0, 0, width, TITLEBAR_HEIGHT); + wlSurfaceCommit(s_Decoration.surface); // wayland requires the main surface to be committed as well - surfaceCommit(s_WinHandle.nativeWindow); + wlSurfaceCommit(s_WinHandle.nativeWindow); // draw window title // this example does not support unicode characters @@ -777,8 +777,8 @@ static void createDecoration() static void destroyDecoration() { subsurfaceDestroy(s_Decoration.subsurface); - surfaceDestroy(s_Decoration.surface); - bufferDestroy(s_Decoration.buffer); + wlSurfaceDestroy(s_Decoration.surface); + wlBufferDestroy(s_Decoration.buffer); munmap((void*)s_Decoration.pixels, s_Decoration.size); close(s_Decoration.fd); } @@ -833,8 +833,15 @@ static void PAL_CALL onEvent( } } +#endif // __linux__ + PalBool customDecorationTest() { +#ifndef __linux__ + palLog(nullptr, "Custom decoration not supported"); + return PAL_FALSE; +#endif // __linux__ + palLog(nullptr, "Press Escape or click close button to close Test"); palLog(nullptr, "This only implements close and window movement for simplicity"); @@ -848,7 +855,7 @@ PalBool customDecorationTest() // fill the event driver create info PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator - eventDriverCreateInfo.callback = nullptr; // no callback dispatch + eventDriverCreateInfo.callback = onEvent; // no callback dispatch eventDriverCreateInfo.queue = nullptr; // default queue eventDriverCreateInfo.userData = nullptr; // null @@ -955,13 +962,3 @@ PalBool customDecorationTest() return PAL_TRUE; } - -#else -#include "tests.h" -PalBool customDecorationTest() -{ - palLog(nullptr, "Custom decoration not supported"); - return PAL_FALSE; -} - -#endif // __linux__ diff --git a/tests/video/native_instance_test.c b/tests/video/native_instance_test.c index 509511fd..c03f31a7 100644 --- a/tests/video/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -110,7 +110,7 @@ static inline void* wlRegistryBind( return (void*)id; } -static inline int registryAddListener( +static inline int wlRegistryAddListener( struct wl_registry* wl_registry, const struct wl_registry_listener* listener, void* data) @@ -118,7 +118,7 @@ static inline int registryAddListener( return s_wl_proxy_add_listener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); } -static inline struct wl_registry* displayGetRegistry(struct wl_display* wl_display) +static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_display) { struct wl_proxy* registry; registry = s_wl_proxy_marshal_flags( @@ -239,8 +239,8 @@ void* openDisplayWayland() registryInterface = dlsym(s_LibWayland, "wl_registry_interface"); struct wl_display* display = s_wl_display_connect(nullptr); if (display) { - s_Registry = displayGetRegistry(display); - registryAddListener(s_Registry, &s_RegistryListener, nullptr); + s_Registry = wlDisplayGetRegistry(display); + wlRegistryAddListener(s_Registry, &s_RegistryListener, nullptr); s_wl_display_roundtrip(display); } diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index b58c68cc..037c107c 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -324,17 +324,19 @@ static void windowInfoDump() static void windowDump() { - uint32_t xSize = 48; + uint32_t xSize = 64; uint32_t xAlign = 8; uint32_t xOffset1 = 0; uint32_t xOffset2 = 8; uint32_t xOffset3 = 16; uint32_t xOffset4 = 24; - uint32_t xOffset5 = 28; - uint32_t xOffset6 = 32; - uint32_t xOffset7 = 36; - uint32_t xOffset8 = 40; - uint32_t xOffset9 = 44; + uint32_t xOffset5 = 32; + uint32_t xOffset6 = 40; + uint32_t xOffset7 = 44; + uint32_t xOffset8 = 48; + uint32_t xOffset9 = 52; + uint32_t xOffset10 = 56; + uint32_t xOffset11 = 60; uint32_t xPadding = 0; uint32_t ySize = sizeof(PalWindowCreateInfo); @@ -342,12 +344,14 @@ static void windowDump() uint32_t yOffset1 = offsetof(PalWindowCreateInfo, style); uint32_t yOffset2 = offsetof(PalWindowCreateInfo, title); uint32_t yOffset3 = offsetof(PalWindowCreateInfo, monitor); - uint32_t yOffset4 = offsetof(PalWindowCreateInfo, width); - uint32_t yOffset5 = offsetof(PalWindowCreateInfo, height); - uint32_t yOffset6 = offsetof(PalWindowCreateInfo, show); - uint32_t yOffset7 = offsetof(PalWindowCreateInfo, maximized); - uint32_t yOffset8 = offsetof(PalWindowCreateInfo, minimized); - uint32_t yOffset9 = offsetof(PalWindowCreateInfo, center); + uint32_t yOffset4 = offsetof(PalWindowCreateInfo, appName); + uint32_t yOffset5 = offsetof(PalWindowCreateInfo, instanceName); + uint32_t yOffset6 = offsetof(PalWindowCreateInfo, width); + uint32_t yOffset7 = offsetof(PalWindowCreateInfo, height); + uint32_t yOffset8 = offsetof(PalWindowCreateInfo, show); + uint32_t yOffset9 = offsetof(PalWindowCreateInfo, maximized); + uint32_t yOffset10 = offsetof(PalWindowCreateInfo, minimized); + uint32_t yOffset11 = offsetof(PalWindowCreateInfo, center); uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; const char* result = s_FailedString; @@ -363,6 +367,8 @@ static void windowDump() xOffset7 == yOffset7 && xOffset8 == yOffset8 && xOffset9 == yOffset9 && + xOffset10 == yOffset10 && + xOffset11 == yOffset11 && xPadding == yPadding) { result = s_PassedString; } @@ -379,12 +385,14 @@ static void windowDump() palLog(nullptr, "style @ %u %u", xOffset1, yOffset1); palLog(nullptr, "title @ %u %u", xOffset2, yOffset2); palLog(nullptr, "monitor @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "width @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "height @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "show @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "maximized @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "minimized @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "center @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "appName @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "instanceName @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "width @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "height @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "show @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "maximized @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "minimized @ %u %u", xOffset10, yOffset10); + palLog(nullptr, "center @ %u %u", xOffset11, yOffset11); palLog(nullptr, "==========================================="); palLog(nullptr, "Status: %s", result); From 3707eb8b66163c398a6c37118bcffe06e335e12b Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 18 Jun 2026 02:18:48 +0000 Subject: [PATCH 276/372] test video rewrite x11 --- src/video/linux/pal_video_linux.c | 5 ++--- src/video/linux/pal_video_linux.h | 1 - src/video/linux/wayland/pal_video_wayland.c | 18 +++++++-------- src/video/linux/x11/pal_video_x11.c | 25 +++++++++++---------- tests/tests_main.c | 4 ++-- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/video/linux/pal_video_linux.c b/src/video/linux/pal_video_linux.c index a5e31262..75c6faa5 100644 --- a/src/video/linux/pal_video_linux.c +++ b/src/video/linux/pal_video_linux.c @@ -206,7 +206,7 @@ PalResult PAL_CALL palInitVideo( // user provided instance if (preferredInstance) { - s_Video.platformInstance = preferredInstance; + s_Video.display = preferredInstance; } s_Video.className = "PAL"; @@ -274,10 +274,9 @@ void PAL_CALL palShutdownVideo() dlclose(s_Egl.handle); } - s_Video.platformInstance = nullptr; - s_Video.display = nullptr; memset(&s_Keyboard, 0, sizeof(Keyboard)); memset(&s_Mouse, 0, sizeof(Mouse)); + memset(&s_Video, 0, sizeof(VideoLinux)); s_Video.initialized = PAL_FALSE; } } diff --git a/src/video/linux/pal_video_linux.h b/src/video/linux/pal_video_linux.h index afd4a2ab..dcce99e0 100644 --- a/src/video/linux/pal_video_linux.h +++ b/src/video/linux/pal_video_linux.h @@ -235,7 +235,6 @@ typedef struct { WindowData* windowData; MonitorData* monitorData; const char* className; - void* platformInstance; void* display; } VideoLinux; diff --git a/src/video/linux/wayland/pal_video_wayland.c b/src/video/linux/wayland/pal_video_wayland.c index e2418eac..f3aec667 100644 --- a/src/video/linux/wayland/pal_video_wayland.c +++ b/src/video/linux/wayland/pal_video_wayland.c @@ -1354,12 +1354,12 @@ PalResult wlInitVideo() setupProtocols(); // check if user supplied their own display - if (s_Video.platformInstance) { - s_Wl.display = (struct wl_display*)s_Video.platformInstance; + if (s_Video.display) { + s_Wl.display = (struct wl_display*)s_Video.display; } else { s_Wl.display = s_Wl.displayConnect(nullptr); - s_Video.platformInstance = nullptr; + s_Video.display = nullptr; } if (!s_Wl.display) { @@ -1425,15 +1425,15 @@ void wlShutdownVideo() s_Wl.proxyDestroy((struct wl_proxy*)s_Wl.seat); } - if (!s_Video.platformInstance) { + if (!s_Video.display) { // opened by PAL s_Wl.displayDisconnect(s_Wl.display); - } - dlclose(s_Wl.libCursor); - dlclose(s_Wl.xkbCommon); - dlclose(s_Wl.libWaylandEgl); - dlclose(s_Wl.handle); + dlclose(s_Wl.libCursor); + dlclose(s_Wl.xkbCommon); + dlclose(s_Wl.libWaylandEgl); + dlclose(s_Wl.handle); + } memset(&s_Wl, 0, sizeof(Wayland)); } diff --git a/src/video/linux/x11/pal_video_x11.c b/src/video/linux/x11/pal_video_x11.c index 51b09ac9..35b3317e 100644 --- a/src/video/linux/x11/pal_video_x11.c +++ b/src/video/linux/x11/pal_video_x11.c @@ -768,12 +768,12 @@ PalResult xInitVideo() // clang-format on // X11 server - if (s_Video.platformInstance) { - s_X11.display = (Display*)s_Video.platformInstance; + if (s_Video.display) { + s_X11.display = (Display*)s_Video.display; } else { s_X11.display = s_X11.openDisplay(nullptr); - s_Video.platformInstance = nullptr; + s_Video.display = nullptr; } if (!s_X11.display) { @@ -839,18 +839,19 @@ PalResult xInitVideo() void xShutdownVideo() { s_X11.closeIM(s_X11.im); - if (!s_Video.platformInstance) { + if (!s_Video.display) { // opened by PAL s_X11.closeDisplay(s_X11.display); - } - dlclose(s_X11.handle); - dlclose(s_X11.xrandr); - dlclose(s_X11.libCursor); + dlclose(s_X11.handle); + dlclose(s_X11.xrandr); + dlclose(s_X11.libCursor); - if (s_X11.glxHandle) { - dlclose(s_X11.glxHandle); + if (s_X11.glxHandle) { + dlclose(s_X11.glxHandle); + } } + memset(&s_X11, 0, sizeof(X11)); memset(&s_X11Atoms, 0, sizeof(X11Atoms)); } @@ -1128,7 +1129,7 @@ void xUpdateVideo() if (mode != PAL_DISPATCH_NONE) { PalEvent event = {0}; event.type = type; - event.data = palPackInt32(dx, dy); + event.data = palPackFloat((float)dx, (float)dy); event.data2 = palPackPointer(window); palPushEvent(driver, &event); } @@ -1199,7 +1200,7 @@ void xUpdateVideo() if (mode != PAL_DISPATCH_NONE) { PalEvent event = {0}; event.type = PAL_EVENT_MOUSE_WHEEL; - event.data = palPackInt32(scrollX, scrollY); + event.data = palPackFloat((float)scrollX, (float)scrollY); event.data2 = palPackPointer(window); palPushEvent(driver, &event); } diff --git a/tests/tests_main.c b/tests/tests_main.c index e63b95c2..40cb31d5 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -28,7 +28,7 @@ int main(int argc, char** argv) #endif // PAL_HAS_THREAD_MODULE #if PAL_HAS_VIDEO_MODULE == 1 - registerTest(videoTest, "Video Test"); + // registerTest(videoTest, "Video Test"); // registerTest(monitorTest, "Monitor Test"); // registerTest(monitorModeTest, "Monitor Mode Test"); // registerTest(windowTest, "Window Test"); @@ -39,7 +39,7 @@ int main(int argc, char** argv) // registerTest(attachWindowTest, "Attach Window Test"); // registerTest(charEventTest, "Char Event Test"); // registerTest(nativeIntegrationTest, "Native Integration Test"); - // registerTest(nativeInstanceTest, "Native Instance Test"); + registerTest(nativeInstanceTest, "Native Instance Test"); // registerTest(customDecorationTest, "Custom Decoration Test"); #endif // PAL_HAS_VIDEO_MODULE From 72f0a336602c3e8ac179eac941c3454698b14549 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 18 Jun 2026 12:21:45 +0000 Subject: [PATCH 277/372] remove palSetFBConfig function win32 --- CHANGELOG.md | 4 +- include/pal/pal_video.h | 51 ++++++------------- src/video/linux/wayland/pal_video_wayland.c | 5 +- src/video/linux/wayland/pal_window_wayland.c | 5 +- src/video/win32/pal_video_win32.c | 35 ------------- src/video/win32/pal_video_win32.h | 1 - src/video/win32/pal_window_win32.c | 16 ++++-- tests/video/custom_decoration_test.c | 15 +++--- tools/abi_dump/video_abi_dump.c | 52 +++++++++++--------- 9 files changed, 78 insertions(+), 106 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d8a9eaa..ac7ac8d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -159,7 +159,8 @@ palJoinThread(thread, &retval); - **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. - **Video:** **palGetMouseWheelDelta()** now takes floats instead of uint32_t. - **Video:** **palInitVideo()** now takes a preferredInstance parameter. -- **Video:** **PalWindowCreateInfo()** now takes `appName` and `instanceName` optional fields. +- **Video:** **PalWindowCreateInfo** now has `appName`, `instanceName`, `fbConfigBackend` and +`fbConfigId` fields. ### Removed - **Core:** Removed **PAL_RESULT_NULL_POINTER** result code. @@ -190,6 +191,7 @@ palJoinThread(thread, &retval); - **Video:** Removed **palGetWindowHandleInfoEx** function. - **Video:** Removed **palGetRawMouseWheelDelta** function. - **Video:** Removed **palSetPreferredInstance** function. +- **Video:** Removed **palSetFBConfig** function. ### Tests diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index ff23f15f..226f8576 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -84,7 +84,6 @@ #define PAL_CONFIG_BACKEND_EGL 1 #define PAL_CONFIG_BACKEND_GLX 2 #define PAL_CONFIG_BACKEND_WGL 3 -#define PAL_CONFIG_BACKEND_GLES 4 #define PAL_SCANCODE_UNKNOWN 0 #define PAL_SCANCODE_A 1 @@ -584,6 +583,8 @@ typedef struct { PalMonitor* monitor; /**< Set to nullptr to use primary monitor.*/ const char* appName; /**< If nullptr, `PAL` will be used.*/ const char* instanceName; /**< If nullptr, `title` will be used.*/ + PalFBConfigBackend fbConfigBackend; + int32_t fbConfigId; uint32_t width; /**< Width in pixels.*/ uint32_t height; /**< Width in pixels.*/ PalBool show; /**< Show after creation.*/ @@ -667,40 +668,6 @@ PAL_API void PAL_CALL palUpdateVideo(); */ PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures(); -/** - * @brief Set the FBConfig for the video system. - * - * The video system must be initialized before this call. - * The provided FBConfig will be used for all created windows after this call. - * The `index` is the loop index from the drivers - * supported FBConfigs. - * - * The `backend` is used to tell the video system, the source of the index. - * Examples: PAL_CONFIG_BACKEND_EGL tells the video system, we got this loop - * index from EGL. This will enable the video system to find your FBConfig. - * - * Example Flow: - * Enumerate and select your FBConfig using any backend(EGL, GLX, WGL, etc) - * and just let the video system know which one you used. - * - * If the backend passed is not the same as the one used, - * the video system might still get a FBConfig but it will not be the - * one requested. - * - * @param[in] index The FBConfig driver index. - * @param[in] backend The FBConfig backend or source. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Must be called from the main thread. - * - * @since 1.1 - */ -PAL_API PalResult PAL_CALL palSetFBConfig( - const int index, - PalFBConfigBackend backend); - /** * @brief Return a list of all connected monitors. * @@ -901,6 +868,18 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * @brief Create a window. * * The video system must be initialized before this call. + * + * `PalWindowCreateInfo::fbConfigId` is the loop index from the drivers supported FBConfigs. + * `PalWindowCreateInfo::fbConfigBackend` is used to tell the video system the source of + * `PalWindowCreateInfo::fbConfigId`. + * + * Example Flow: + * Enumerate and select your FBConfig using any backend(EGL, GLX, WGL) + * and just let the video system know which one you used. + * + * If the backend passed is not the same as the one used, + * the video system might still get a FBConfig but it will not be the + * one requested. * * @param[in] info Pointer to a PalWindowCreateInfo struct that specifies * parameters. Must not be nullptr. @@ -921,7 +900,7 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * * - Creating hidden window is not supported. It will be ignored. * - * @since 1.0 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCreateWindow( const PalWindowCreateInfo* info, diff --git a/src/video/linux/wayland/pal_video_wayland.c b/src/video/linux/wayland/pal_video_wayland.c index f3aec667..6aa94a4a 100644 --- a/src/video/linux/wayland/pal_video_wayland.c +++ b/src/video/linux/wayland/pal_video_wayland.c @@ -1125,7 +1125,10 @@ PalResult eglWlBackend(const int index) EGLint configSize = sizeof(EGLConfig) * numConfigs; EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); if (!eglConfigs) { - return PAL_RESULT_OUT_OF_MEMORY; + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); } s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); diff --git a/src/video/linux/wayland/pal_window_wayland.c b/src/video/linux/wayland/pal_window_wayland.c index 23d39fec..0adaa448 100644 --- a/src/video/linux/wayland/pal_window_wayland.c +++ b/src/video/linux/wayland/pal_window_wayland.c @@ -54,7 +54,10 @@ PalResult wlCreateWindow( WindowData* data = getFreeWindowData(); if (!data) { - return PAL_RESULT_OUT_OF_MEMORY; + return palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); } memset(data, 0, sizeof(WindowData)); diff --git a/src/video/win32/pal_video_win32.c b/src/video/win32/pal_video_win32.c index 7ee0ec7e..3439c535 100644 --- a/src/video/win32/pal_video_win32.c +++ b/src/video/win32/pal_video_win32.c @@ -936,7 +936,6 @@ PalResult PAL_CALL palInitVideo( s_Video.initialized = PAL_TRUE; s_Video.allocator = allocator; s_Video.eventDriver = eventDriver; - s_Video.pixelFormat = 0; return PAL_RESULT_SUCCESS; } @@ -1016,40 +1015,6 @@ PalVideoFeatures PAL_CALL palGetVideoFeatures() return s_Video.features; } -PalResult PAL_CALL palSetFBConfig( - const int index, - PalFBConfigBackend backend) -{ - // Win32 uses only WGL and WGL index starts from 1 - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - // clang-format off - if (backend == PAL_CONFIG_BACKEND_EGL || - backend == PAL_CONFIG_BACKEND_GLES || - backend == PAL_CONFIG_BACKEND_GLX) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - // clang-format on - - if (index >= 1) { - s_Video.pixelFormat = index; - return PAL_RESULT_SUCCESS; - } - - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); -} - const PalBool* PAL_CALL palGetKeycodeState() { if (!s_Video.initialized) { diff --git a/src/video/win32/pal_video_win32.h b/src/video/win32/pal_video_win32.h index 9057ede3..890457aa 100644 --- a/src/video/win32/pal_video_win32.h +++ b/src/video/win32/pal_video_win32.h @@ -81,7 +81,6 @@ typedef struct { typedef struct { PalBool initialized; - int32_t pixelFormat; int32_t maxWindowData; PalVideoFeatures features; const PalAllocator* allocator; diff --git a/src/video/win32/pal_window_win32.c b/src/video/win32/pal_window_win32.c index a549d770..cac8a2c3 100644 --- a/src/video/win32/pal_window_win32.c +++ b/src/video/win32/pal_window_win32.c @@ -171,7 +171,17 @@ PalResult PAL_CALL palCreateWindow( } // set the pixel format is set - if (s_Video.pixelFormat) { + if (info->fbConfigId) { + // clang-format off + if (info->fbConfigBackend == PAL_CONFIG_BACKEND_EGL || + info->fbConfigBackend == PAL_CONFIG_BACKEND_GLX) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + // clang-format on + HDC hdc = GetDC(handle); // since we have the pixel format already // we ask the OS (platform) to fill the pfd struct for us from that @@ -179,7 +189,7 @@ PalResult PAL_CALL palCreateWindow( PIXELFORMATDESCRIPTOR pfd; if (!s_Video.describePixelFormat( hdc, - s_Video.pixelFormat, + info->fbConfigId, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { return palMakeResult( @@ -188,7 +198,7 @@ PalResult PAL_CALL palCreateWindow( GetLastError()); } - s_Video.setPixelFormat(hdc, s_Video.pixelFormat, &pfd); + s_Video.setPixelFormat(hdc, info->fbConfigBackend, &pfd); ReleaseDC(handle, hdc); } diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index a38a78e0..8c797e66 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -1,5 +1,7 @@ -#if defined(__linux__) +#include "pal/pal_core.h" + +#ifdef __linux__ #define _GNU_SOURCE #define _POSIX_C_SOURCE 200112L // for linux #include "pal/pal_video.h" @@ -837,11 +839,7 @@ static void PAL_CALL onEvent( PalBool customDecorationTest() { -#ifndef __linux__ - palLog(nullptr, "Custom decoration not supported"); - return PAL_FALSE; -#endif // __linux__ - +#ifdef __linux__ palLog(nullptr, "Press Escape or click close button to close Test"); palLog(nullptr, "This only implements close and window movement for simplicity"); @@ -961,4 +959,9 @@ PalBool customDecorationTest() closeDisplayWayland(); return PAL_TRUE; + +#else + palLog(nullptr, "Custom decoration not supported"); + return PAL_FALSE; +#endif // __linux__ } diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index 037c107c..65af43d7 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -324,7 +324,7 @@ static void windowInfoDump() static void windowDump() { - uint32_t xSize = 64; + uint32_t xSize = 72; uint32_t xAlign = 8; uint32_t xOffset1 = 0; uint32_t xOffset2 = 8; @@ -337,6 +337,8 @@ static void windowDump() uint32_t xOffset9 = 52; uint32_t xOffset10 = 56; uint32_t xOffset11 = 60; + uint32_t xOffset12 = 64; + uint32_t xOffset13 = 68; uint32_t xPadding = 0; uint32_t ySize = sizeof(PalWindowCreateInfo); @@ -346,12 +348,14 @@ static void windowDump() uint32_t yOffset3 = offsetof(PalWindowCreateInfo, monitor); uint32_t yOffset4 = offsetof(PalWindowCreateInfo, appName); uint32_t yOffset5 = offsetof(PalWindowCreateInfo, instanceName); - uint32_t yOffset6 = offsetof(PalWindowCreateInfo, width); - uint32_t yOffset7 = offsetof(PalWindowCreateInfo, height); - uint32_t yOffset8 = offsetof(PalWindowCreateInfo, show); - uint32_t yOffset9 = offsetof(PalWindowCreateInfo, maximized); - uint32_t yOffset10 = offsetof(PalWindowCreateInfo, minimized); - uint32_t yOffset11 = offsetof(PalWindowCreateInfo, center); + uint32_t yOffset6 = offsetof(PalWindowCreateInfo, fbConfigBackend); + uint32_t yOffset7 = offsetof(PalWindowCreateInfo, fbConfigId); + uint32_t yOffset8 = offsetof(PalWindowCreateInfo, width); + uint32_t yOffset9 = offsetof(PalWindowCreateInfo, height); + uint32_t yOffset10 = offsetof(PalWindowCreateInfo, show); + uint32_t yOffset11 = offsetof(PalWindowCreateInfo, maximized); + uint32_t yOffset12 = offsetof(PalWindowCreateInfo, minimized); + uint32_t yOffset13 = offsetof(PalWindowCreateInfo, center); uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; const char* result = s_FailedString; @@ -369,6 +373,8 @@ static void windowDump() xOffset9 == yOffset9 && xOffset10 == yOffset10 && xOffset11 == yOffset11 && + xOffset12 == yOffset12 && + xOffset13 == yOffset13 && xPadding == yPadding) { result = s_PassedString; } @@ -376,23 +382,25 @@ static void windowDump() palLog(nullptr, "PalWindowCreateInfo"); palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "Field Expected Actual"); palLog(nullptr, "==========================================="); - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "style @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "title @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "monitor @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "appName @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "instanceName @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "width @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "height @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "show @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "maximized @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "minimized @ %u %u", xOffset10, yOffset10); - palLog(nullptr, "center @ %u %u", xOffset11, yOffset11); + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "style @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "title @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "monitor @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "appName @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "instanceName @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "fbConfigBackend @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "fbConfigId @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "width @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "height @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "show @ %u %u", xOffset10, yOffset10); + palLog(nullptr, "maximized @ %u %u", xOffset11, yOffset11); + palLog(nullptr, "minimized @ %u %u", xOffset12, yOffset12); + palLog(nullptr, "center @ %u %u", xOffset13, yOffset13); palLog(nullptr, "==========================================="); palLog(nullptr, "Status: %s", result); From 096ffe7475f1bdff75e857afcef666aa8013b0dd Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 18 Jun 2026 14:45:53 +0000 Subject: [PATCH 278/372] prepare opengl backend helpers --- CHANGELOG.md | 7 ++- include/pal/pal_opengl.h | 60 +++++++++++++++--- src/opengl/pal_backends_opengl.h | 94 ++++++++++++++++++++++++++++ src/opengl/pal_opengl.c | 0 src/opengl/pal_opengl_helper.h | 39 ++++++++++++ src/video/linux/pal_backends_linux.h | 2 +- src/video/linux/pal_video_linux.c | 3 +- src/video/linux/pal_video_linux.h | 1 - 8 files changed, 192 insertions(+), 14 deletions(-) create mode 100644 src/opengl/pal_backends_opengl.h create mode 100644 src/opengl/pal_opengl.c create mode 100644 src/opengl/pal_opengl_helper.h diff --git a/CHANGELOG.md b/CHANGELOG.md index ac7ac8d6..4d463393 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -133,6 +133,8 @@ palJoinThread(thread, &retval); - **Graphics:** Added **Graphics System To PAL**. +palGetGLAPI + ### Changed - **All systems:** All enum types have been changed to defines and explicit width types. @@ -152,8 +154,11 @@ palJoinThread(thread, &retval); - **Thread:** **palJoinThread()** now takes a void** for retval parameter. - **Opengl:** **palEnumerateGLFBConfigs()** now does not take glWindow parameter anymore. -- **Video:** **palInitGL()** now takes a instance parameter. +- **Opengl:** **palInitGL()** now takes a instance parameter. - **Opengl:** rename **PalGLRelease** to **PalGLReleaseBehavior**. +- **Opengl:** rename **palGLGetProcAddress()** to **palGetGLProcAddress()**. +- **Opengl:** rename **palGLGetBackend()** to **palGetGLBackend()**. +- **Opengl:** **palGetGLBackend()** now returns a **PalGLBackend**. - **Video:** **palGetWindowHandleInfo()** now takes an info parameter. - **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index c2245bad..028eb852 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -50,6 +50,13 @@ #define PAL_GL_RELEASE_BEHAVIOR_NONE 0 #define PAL_GL_RELEASE_BEHAVIOR_FLUSH 1 +#define PAL_GL_BACKEND_EGL 0 +#define PAL_GL_BACKEND_GLX 1 +#define PAL_GL_BACKEND_WGL 2 + +#define PAL_GL_API_OPENGL 0 +#define PAL_GL_API_OPENGL_ES 1 + /** * @struct PalGLContext * @brief Opaque handle to an opengl context. @@ -102,6 +109,26 @@ typedef uint32_t PalGLContextReset; */ typedef uint32_t PalGLReleaseBehavior; +/** + * @typedef PalGLBackend + * @brief Opengl backend. This is not a bitmask. + * + * All opengl backends follow the format `PAL_GL_BACKEND_**` for consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalGLBackend; + +/** + * @typedef PalGLAPI + * @brief Opengl api. This is not a bitmask. + * + * All opengl apis follow the format `PAL_GL_API_**` for consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalGLAPI; + /** * @struct PalGLInfo * @brief Information about the opengl driver. @@ -186,11 +213,14 @@ typedef struct { * palShutdownGL() is called. * `Linux`: This is the Display associated with the connection. * `Windows`: This is the HINSTANCE of the process. - * - * @param[in] allocator Optional user-provided allocator. Set to nullptr to use - * default. + * * @param[in] instance The instance the opengl system will be tied to (eg. XDisplay). * Must not be nullptr. + * @param[in] backend The backend to use. (eg. PAL_GL_BACKEND_WGL). + * @param[in] api The backend api to use. (eg. PAL_GL_API_OPENGL). Some apis are not compatible + * with some backends. + * @param[in] allocator Optional user-provided allocator. Set to nullptr to use + * default. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -201,8 +231,10 @@ typedef struct { * @sa palShutdownGL */ PAL_API PalResult PAL_CALL palInitGL( - const PalAllocator* allocator, - void* instance); + void* instance, + PalGLBackend backend, + PalGLAPI api, + const PalAllocator* allocator); /** * @brief Shutdown the opengl system. @@ -370,7 +402,7 @@ PAL_API PalResult PAL_CALL palMakeContextCurrent( * @since 1.0 * @sa palInitGL */ -PAL_API void* PAL_CALL palGLGetProcAddress(const char* name); +PAL_API void* PAL_CALL palGetGLProcAddress(const char* name); /** * @brief Present the contents of the back buffer of the provided context to @@ -419,13 +451,23 @@ PAL_API PalResult PAL_CALL palSetSwapInterval(int32_t interval); * @brief Get the backend of the opengl system. * * The opengl system must be initialized before this call. - * Possible values are `wgl`, `glx`, `gles`, `egl`. * * Thread safety: Thread safe. * - * @since 1.3 + * @since 2.0 + */ +PAL_API PalGLBackend PAL_CALL palGetGLBackend(); + +/** + * @brief Get the api of the opengl system. + * + * The opengl system must be initialized before this call. + * + * Thread safety: Thread safe. + * + * @since 2.0 */ -PAL_API const char* PAL_CALL palGLGetBackend(); +PAL_API PalGLAPI PAL_CALL palGetGLAPI(); /** @} */ // end of pal_opengl group diff --git a/src/opengl/pal_backends_opengl.h b/src/opengl/pal_backends_opengl.h new file mode 100644 index 00000000..33815710 --- /dev/null +++ b/src/opengl/pal_backends_opengl.h @@ -0,0 +1,94 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_BACKENDS_OPENGL_H +#define _PAL_BACKENDS_OPENGL_H + +#include "pal_opengl_helper.h" + +// ================================================== +// WGL +// ================================================== + +PalResult PAL_CALL wglInitGL(); +void PAL_CALL wglShutdownGL(); +const PalGLInfo* PAL_CALL wglGetGLInfo(); +PalResult PAL_CALL wglEnumerateGLFBConfigs(int32_t*, PalGLFBConfig*); +PalResult PAL_CALL wglCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); +void PAL_CALL wglDestroyGLContext(PalGLContext*); +PalResult PAL_CALL wglMakeContextCurrent(PalGLWindow*, PalGLContext*); +void* PAL_CALL wglGetGLProcAddress(const char*); +PalResult PAL_CALL wglSwapBuffers(PalGLWindow*, PalGLContext*); +PalResult PAL_CALL wglSetSwapInterval(int32_t); + +static Backend s_WglBackend = { + .shutdownGL = wglShutdownGL, + .getGLInfo = wglGetGLInfo, + .enumerateGLFBConfigs = wglEnumerateGLFBConfigs, + .createGLContext = wglCreateGLContext, + .destroyGLContext = wglDestroyGLContext, + .makeContextCurrent = wglMakeContextCurrent, + .getGLProcAddress = wglGetGLProcAddress, + .swapBuffers = wglSwapBuffers, + .setSwapInterval = wglSetSwapInterval, +}; + +// ================================================== +// GLX +// ================================================== + +PalResult PAL_CALL glxInitGL(); +void PAL_CALL glxShutdownGL(); +const PalGLInfo* PAL_CALL glxGetGLInfo(); +PalResult PAL_CALL glxEnumerateGLFBConfigs(int32_t*, PalGLFBConfig*); +PalResult PAL_CALL glxCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); +void PAL_CALL glxDestroyGLContext(PalGLContext*); +PalResult PAL_CALL glxMakeContextCurrent(PalGLWindow*, PalGLContext*); +void* PAL_CALL glxGetGLProcAddress(const char*); +PalResult PAL_CALL glxSwapBuffers(PalGLWindow*, PalGLContext*); +PalResult PAL_CALL glxSetSwapInterval(int32_t); + +static Backend s_GlxBackend = { + .shutdownGL = glxShutdownGL, + .getGLInfo = glxGetGLInfo, + .enumerateGLFBConfigs = glxEnumerateGLFBConfigs, + .createGLContext = glxCreateGLContext, + .destroyGLContext = glxDestroyGLContext, + .makeContextCurrent = glxMakeContextCurrent, + .getGLProcAddress = glxGetGLProcAddress, + .swapBuffers = glxSwapBuffers, + .setSwapInterval = glxSetSwapInterval, +}; + +// ================================================== +// EGL +// ================================================== + +PalResult PAL_CALL eglInitGL(); +void PAL_CALL eglShutdownGL(); +const PalGLInfo* PAL_CALL eglGetGLInfo(); +PalResult PAL_CALL eglEnumerateGLFBConfigs(int32_t*, PalGLFBConfig*); +PalResult PAL_CALL eglCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); +void PAL_CALL eglDestroyGLContext(PalGLContext*); +PalResult PAL_CALL eglMakeContextCurrent(PalGLWindow*, PalGLContext*); +void* PAL_CALL eglGetGLProcAddress(const char*); +PalResult PAL_CALL eglSwapBuffers(PalGLWindow*, PalGLContext*); +PalResult PAL_CALL eglSetSwapInterval(int32_t); + +static Backend s_EglBackend = { + .shutdownGL = eglShutdownGL, + .getGLInfo = eglGetGLInfo, + .enumerateGLFBConfigs = eglEnumerateGLFBConfigs, + .createGLContext = eglCreateGLContext, + .destroyGLContext = eglDestroyGLContext, + .makeContextCurrent = eglMakeContextCurrent, + .getGLProcAddress = eglGetGLProcAddress, + .swapBuffers = eglSwapBuffers, + .setSwapInterval = eglSetSwapInterval, +}; + +#endif // _PAL_BACKENDS_OPENGL_H diff --git a/src/opengl/pal_opengl.c b/src/opengl/pal_opengl.c new file mode 100644 index 00000000..e69de29b diff --git a/src/opengl/pal_opengl_helper.h b/src/opengl/pal_opengl_helper.h new file mode 100644 index 00000000..fb29dcde --- /dev/null +++ b/src/opengl/pal_opengl_helper.h @@ -0,0 +1,39 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_OPENGL_HELPER_H +#define _PAL_OPENGL_HELPER_H + +#include "pal/pal_opengl.h" + +typedef struct { + // clang-format off + void (PAL_CALL *shutdownGL)(); + const PalGLInfo* (PAL_CALL *getGLInfo)(); + PalResult (PAL_CALL *enumerateGLFBConfigs)(int32_t*, PalGLFBConfig*); + PalResult (PAL_CALL *createGLContext)(const PalGLContextCreateInfo*, PalGLContext**); + void (PAL_CALL *destroyGLContext)(PalGLContext*); + PalResult (PAL_CALL *makeContextCurrent)(PalGLWindow*, PalGLContext*); + void* (PAL_CALL *getGLProcAddress)(const char*); + + PalResult (PAL_CALL *swapBuffers)(PalGLWindow*, PalGLContext*); + PalResult (PAL_CALL *setSwapInterval)(int32_t); + // clang-format on +} Backend; + +typedef struct { + PalBool initialized; + void* handle; + void* instance; + const PalAllocator* allocator; + Backend* backend; + PalGLInfo info; +} Opengl; + +extern Opengl s_GL; + +#endif // _PAL_OPENGL_HELPER_H \ No newline at end of file diff --git a/src/video/linux/pal_backends_linux.h b/src/video/linux/pal_backends_linux.h index f7c1c985..22c7a79d 100644 --- a/src/video/linux/pal_backends_linux.h +++ b/src/video/linux/pal_backends_linux.h @@ -8,7 +8,7 @@ #define _PAL_BACKENDS_LINUX_H #ifdef __linux__ -#include "pal/pal_video.h" +#include "pal_video_linux.h" // ================================================== // X11 diff --git a/src/video/linux/pal_video_linux.c b/src/video/linux/pal_video_linux.c index 75c6faa5..eb680b81 100644 --- a/src/video/linux/pal_video_linux.c +++ b/src/video/linux/pal_video_linux.c @@ -6,9 +6,8 @@ */ #ifdef __linux__ -#include "pal_video_linux.h" -#include "pal_shared.h" #include "pal_backends_linux.h" +#include "pal_shared.h" #include #include diff --git a/src/video/linux/pal_video_linux.h b/src/video/linux/pal_video_linux.h index dcce99e0..c1e33c42 100644 --- a/src/video/linux/pal_video_linux.h +++ b/src/video/linux/pal_video_linux.h @@ -119,7 +119,6 @@ typedef struct { // clang-format off void (*shutdownVideo)(); void (*updateVideo)(); - PalResult (*setFBConfig)(const int, PalFBConfigBackend); PalResult (*enumerateMonitors)(int32_t*, PalMonitor**); PalResult (*getPrimaryMonitor)(PalMonitor**); PalResult (*getMonitorInfo)(PalMonitor*, PalMonitorInfo*); From cde4f316f2146e8257011f684007960c047992ff Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 18 Jun 2026 21:26:23 +0000 Subject: [PATCH 279/372] remove palSetFBConfig function linux --- src/video/linux/pal_backends_linux.h | 4 - src/video/linux/pal_video_linux.c | 22 ---- src/video/linux/wayland/pal_video_wayland.c | 58 --------- src/video/linux/wayland/pal_wayland.h | 1 - src/video/linux/wayland/pal_window_wayland.c | 43 ++++++- src/video/linux/x11/pal_video_x11.c | 118 ------------------- src/video/linux/x11/pal_window_x11.c | 89 +++++++++++++- src/video/linux/x11/pal_x11.h | 1 - tests/video/custom_decoration_test.c | 4 +- 9 files changed, 130 insertions(+), 210 deletions(-) diff --git a/src/video/linux/pal_backends_linux.h b/src/video/linux/pal_backends_linux.h index 22c7a79d..cff79c1c 100644 --- a/src/video/linux/pal_backends_linux.h +++ b/src/video/linux/pal_backends_linux.h @@ -18,7 +18,6 @@ PalResult xInitVideo(); void xShutdownVideo(); void xUpdateVideo(); -PalResult xSetFBConfig(const int, PalFBConfigBackend); PalResult xEnumerateMonitors(int32_t*, PalMonitor**); PalResult xGetPrimaryMonitor(PalMonitor**); PalResult xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); @@ -71,7 +70,6 @@ PalResult xDetachWindow(PalWindow*, void**); static Backend s_XBackend = { .shutdownVideo = xShutdownVideo, .updateVideo = xUpdateVideo, - .setFBConfig = xSetFBConfig, .enumerateMonitors = xEnumerateMonitors, .getMonitorInfo = xGetMonitorInfo, .getPrimaryMonitor = xGetPrimaryMonitor, @@ -129,7 +127,6 @@ PalResult wlInitVideo(); void wlShutdownVideo(); void wlUpdateVideo(); -PalResult wlSetFBConfig(const int, PalFBConfigBackend); PalResult wlEnumerateMonitors(int32_t*, PalMonitor**); PalResult wlGetPrimaryMonitor(PalMonitor**); PalResult wlGetMonitorInfo(PalMonitor*, PalMonitorInfo*); @@ -182,7 +179,6 @@ PalResult wlDetachWindow(PalWindow*, void**); static Backend s_wlBackend = { .shutdownVideo = wlShutdownVideo, .updateVideo = wlUpdateVideo, - .setFBConfig = wlSetFBConfig, .enumerateMonitors = wlEnumerateMonitors, .getMonitorInfo = wlGetMonitorInfo, .getPrimaryMonitor = wlGetPrimaryMonitor, diff --git a/src/video/linux/pal_video_linux.c b/src/video/linux/pal_video_linux.c index eb680b81..848f5e0f 100644 --- a/src/video/linux/pal_video_linux.c +++ b/src/video/linux/pal_video_linux.c @@ -296,28 +296,6 @@ PalVideoFeatures PAL_CALL palGetVideoFeatures() return s_Video.features; } -PalResult PAL_CALL palSetFBConfig( - const int index, - PalFBConfigBackend backend) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - // X11 and wayland can only used GLX and EGL - if (backend == PAL_CONFIG_BACKEND_WGL) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setFBConfig(index, backend); -} - PalResult PAL_CALL palEnumerateMonitors( int32_t* count, PalMonitor** outMonitors) diff --git a/src/video/linux/wayland/pal_video_wayland.c b/src/video/linux/wayland/pal_video_wayland.c index 6aa94a4a..c7ab71aa 100644 --- a/src/video/linux/wayland/pal_video_wayland.c +++ b/src/video/linux/wayland/pal_video_wayland.c @@ -1094,49 +1094,6 @@ void zxdgDecorationHandleConfigure( } } -PalResult eglWlBackend(const int index) -{ - // user choose EGL FBConfig backend - if (!s_Egl.handle) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLDisplay display = EGL_NO_DISPLAY; - display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_Wl.display); - - if (display == EGL_NO_DISPLAY) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLint numConfigs = 0; - if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLint configSize = sizeof(EGLConfig) * numConfigs; - EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); - if (!eglConfigs) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); - s_Wl.eglFBConfig = eglConfigs[index]; - - return PAL_RESULT_SUCCESS; -} - static void createKeycodeTable() { // Tis is for only printable and text input keys @@ -1441,21 +1398,6 @@ void wlShutdownVideo() memset(&s_Wl, 0, sizeof(Wayland)); } -PalResult wlSetFBConfig( - const int index, - PalFBConfigBackend backend) -{ - if (backend == PAL_CONFIG_BACKEND_GLES || backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { - return eglWlBackend(index); - - } else { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } -} - void wlUpdateVideo() { // flush pending requests diff --git a/src/video/linux/wayland/pal_wayland.h b/src/video/linux/wayland/pal_wayland.h index 6632c217..ed4854e9 100644 --- a/src/video/linux/wayland/pal_wayland.h +++ b/src/video/linux/wayland/pal_wayland.h @@ -201,7 +201,6 @@ typedef struct { wl_cursor_theme_get_cursor_fn cursorThemeGetCursor; wl_cursor_image_get_buffer_fn cursorImageGetBuffer; - EGLConfig eglFBConfig; wl_egl_window_create_fn eglWindowCreate; wl_egl_window_destroy_fn eglWindowDestroy; wl_egl_window_resize_fn eglWindowResize; diff --git a/src/video/linux/wayland/pal_window_wayland.c b/src/video/linux/wayland/pal_window_wayland.c index 0adaa448..71661ea4 100644 --- a/src/video/linux/wayland/pal_window_wayland.c +++ b/src/video/linux/wayland/pal_window_wayland.c @@ -13,6 +13,29 @@ #include "pal_shared.h" #include +EGLConfig eglWlBackend(const int fbConfigId) +{ + EGLDisplay display = EGL_NO_DISPLAY; + display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_Wl.display); + if (display == EGL_NO_DISPLAY) { + return nullptr; + } + + EGLint numConfigs = 0; + if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { + return nullptr; + } + + EGLint configSize = sizeof(EGLConfig) * numConfigs; + EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); + if (!eglConfigs) { + return nullptr; + } + + s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); + return eglConfigs[fbConfigId]; +} + PalResult wlCreateWindow( const PalWindowCreateInfo* info, PalWindow** outWindow) @@ -149,7 +172,25 @@ PalResult wlCreateWindow( data->state = PAL_WINDOW_STATE_MINIMIZED; } - if (s_Wl.eglFBConfig) { + // user provided a config id + if (info->fbConfigId) { + PalFBConfigBackend backend = info->fbConfigBackend; + EGLConfig config = nullptr; + + if (backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { + backend = PAL_CONFIG_BACKEND_EGL; + } + + if (backend == PAL_CONFIG_BACKEND_EGL) { + config = eglWlBackend(info->fbConfigId); + + } else { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + data->eglWindow = s_Wl.eglWindowCreate(surface, data->w, data->h); if (!data->eglWindow) { return palMakeResult( diff --git a/src/video/linux/x11/pal_video_x11.c b/src/video/linux/x11/pal_video_x11.c index 35b3317e..e01c0e2d 100644 --- a/src/video/linux/x11/pal_video_x11.c +++ b/src/video/linux/x11/pal_video_x11.c @@ -16,106 +16,6 @@ X11 s_X11 = {0}; X11Atoms s_X11Atoms = {0}; -static PalResult glxBackend(const int index) -{ - // user choose GLX FBConfig backend - if (!s_X11.glxHandle) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - int count = 0; - GLXFBConfig* configs = s_X11.glxGetFBConfigs(s_X11.display, s_X11.screen, &count); - GLXFBConfig fbConfig = configs[index]; - if (!fbConfig) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - // get a matching visual - XVisualInfo* visualInfo = s_X11.glxGetVisualFromFBConfig(s_X11.display, fbConfig); - if (!visualInfo) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_X11.visualInfo = visualInfo; - return PAL_RESULT_SUCCESS; -} - -static PalResult eglXBackend(int index) -{ - // user choose EGL FBConfig backend - if (!s_Egl.handle) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLDisplay display = EGL_NO_DISPLAY; - display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_X11.display); - if (display == EGL_NO_DISPLAY) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLint numConfigs = 0; - if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLint configSize = sizeof(EGLConfig) * numConfigs; - EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); - if (!eglConfigs) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); - EGLConfig config = eglConfigs[index]; - - // we get a visual info from the config - EGLint visualID; - s_Egl.eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualID); - if (visualID == 0) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - int numVisuals = 0; - XVisualInfo tmp; - tmp.visualid = visualID; - - // get a matching visual info - XVisualInfo* visualInfo = s_X11.getVisualInfo(s_X11.display, VisualIDMask, &tmp, &numVisuals); - if (!visualInfo) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_X11.visualInfo = visualInfo; - palFree(s_Video.allocator, eglConfigs); - return PAL_RESULT_SUCCESS; -} - RRMode findMode( XRRScreenResources* resources, const PalMonitorMode* mode) @@ -856,24 +756,6 @@ void xShutdownVideo() memset(&s_X11Atoms, 0, sizeof(X11Atoms)); } -PalResult xSetFBConfig( - const int index, - PalFBConfigBackend backend) -{ - if (backend == PAL_CONFIG_BACKEND_GLX) { - return glxBackend(index); - - } else if (backend == PAL_CONFIG_BACKEND_EGL || backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { - return eglXBackend(index); - - } else { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } -} - void xUpdateVideo() { XEvent event; diff --git a/src/video/linux/x11/pal_window_x11.c b/src/video/linux/x11/pal_window_x11.c index 96e1b92f..5b2e1056 100644 --- a/src/video/linux/x11/pal_window_x11.c +++ b/src/video/linux/x11/pal_window_x11.c @@ -23,6 +23,67 @@ static int xErrorHandler( return 0; } +static XVisualInfo* glxBackend(const int fbConfigId) +{ + int count = 0; + GLXFBConfig* configs = s_X11.glxGetFBConfigs(s_X11.display, s_X11.screen, &count); + GLXFBConfig fbConfig = configs[fbConfigId]; + if (!fbConfig) { + return nullptr; + } + + // get a matching visual + XVisualInfo* visualInfo = s_X11.glxGetVisualFromFBConfig(s_X11.display, fbConfig); + if (!visualInfo) { + return nullptr; + } + + return visualInfo; +} + +static XVisualInfo* eglXBackend(int fbConfigId) +{ + EGLDisplay display = EGL_NO_DISPLAY; + display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_X11.display); + if (display == EGL_NO_DISPLAY) { + return nullptr; + } + + EGLint numConfigs = 0; + if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { + return nullptr; + } + + EGLint configSize = sizeof(EGLConfig) * numConfigs; + EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); + if (!eglConfigs) { + return nullptr; + } + + s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); + EGLConfig config = eglConfigs[fbConfigId]; + + // we get a visual info from the config + EGLint visualID; + s_Egl.eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualID); + if (visualID == 0) { + return nullptr; + } + + int numVisuals = 0; + XVisualInfo tmp; + tmp.visualid = visualID; + + // get a matching visual info + XVisualInfo* visualInfo = s_X11.getVisualInfo(s_X11.display, VisualIDMask, &tmp, &numVisuals); + if (!visualInfo) { + return nullptr; + } + + palFree(s_Video.allocator, eglConfigs); + return visualInfo; +} + PalResult xCreateWindow( const PalWindowCreateInfo* info, PalWindow** outWindow) @@ -45,9 +106,31 @@ PalResult xCreateWindow( unsigned long bgPixel = 0; unsigned long borderPixel = 0; - if (s_X11.visualInfo) { - visual = s_X11.visualInfo->visual; - depth = s_X11.visualInfo->depth; + // user provided a config id + if (info->fbConfigId) { + PalFBConfigBackend backend = info->fbConfigBackend; + XVisualInfo* visualInfo = nullptr; + + if (backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { + backend = PAL_CONFIG_BACKEND_GLX; + } + + if (info->fbConfigBackend == PAL_CONFIG_BACKEND_GLX) { + visualInfo = glxBackend(info->fbConfigId); + + } else if (info->fbConfigBackend == PAL_CONFIG_BACKEND_EGL) { + visualInfo = eglXBackend(info->fbConfigId); + + } else { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // create a colormap from the visual info + visual = visualInfo->visual; + depth = visualInfo->depth; bgPixel = 0; borderPixel = 0; colormap = s_X11.createColormap(s_X11.display, s_X11.root, visual, AllocNone); diff --git a/src/video/linux/x11/pal_x11.h b/src/video/linux/x11/pal_x11.h index 8c542f78..d1e48be2 100644 --- a/src/video/linux/x11/pal_x11.h +++ b/src/video/linux/x11/pal_x11.h @@ -466,7 +466,6 @@ typedef struct { Display* display; Window root; XContext dataID; - XVisualInfo* visualInfo; XOpenDisplayFn openDisplay; XCloseDisplayFn closeDisplay; diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index 8c797e66..4959e447 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -1,6 +1,4 @@ -#include "pal/pal_core.h" - #ifdef __linux__ #define _GNU_SOURCE #define _POSIX_C_SOURCE 200112L // for linux @@ -835,6 +833,8 @@ static void PAL_CALL onEvent( } } +#else +#include "pal/pal_core.h" #endif // __linux__ PalBool customDecorationTest() From 2b6cab1df51ccce4bd7fdd402bf1139fd51c74da Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 19 Jun 2026 00:39:02 +0000 Subject: [PATCH 280/372] test opengl rewrite wayland --- CHANGELOG.md | 11 +- include/pal/pal_opengl.h | 33 +- include/pal/pal_video.h | 6 +- pal.lua | 12 +- pal_config.lua | 4 +- src/opengl/linux/pal_context_linux.c | 368 ++++++ src/opengl/linux/pal_opengl_linux.c | 728 +++++++++++ src/opengl/linux/pal_opengl_linux.h | 241 ++++ src/opengl/pal_backends_opengl.h | 94 -- src/opengl/pal_opengl.c | 0 src/opengl/pal_opengl_helper.h | 39 - src/opengl/pal_opengl_linux.c | 1211 ------------------ src/opengl/pal_opengl_shared.c | 65 + src/opengl/pal_opengl_win32.c | 2 +- src/video/linux/wayland/pal_window_wayland.c | 8 +- src/video/linux/x11/pal_window_x11.c | 14 +- src/video/win32/pal_window_win32.c | 4 +- tests/opengl/multi_thread_opengl_test.c | 118 +- tests/opengl/opengl_context_test.c | 119 +- tests/opengl/opengl_fbconfig_test.c | 37 +- tests/opengl/opengl_multi_context_test.c | 129 +- tests/opengl/opengl_test.c | 26 +- tests/tests_main.c | 4 +- tools/abi_dump/video_abi_dump.c | 4 +- 24 files changed, 1633 insertions(+), 1644 deletions(-) create mode 100644 src/opengl/linux/pal_context_linux.c create mode 100644 src/opengl/linux/pal_opengl_linux.c create mode 100644 src/opengl/linux/pal_opengl_linux.h delete mode 100644 src/opengl/pal_backends_opengl.h delete mode 100644 src/opengl/pal_opengl.c delete mode 100644 src/opengl/pal_opengl_helper.h delete mode 100644 src/opengl/pal_opengl_linux.c create mode 100644 src/opengl/pal_opengl_shared.c diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d463393..4917d014 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -133,7 +133,7 @@ palJoinThread(thread, &retval); - **Graphics:** Added **Graphics System To PAL**. -palGetGLAPI +- **Opengl:** Added **palGetSupportedGLAPIs()**. ### Changed - **All systems:** All enum types have been changed to defines and explicit width types. @@ -154,18 +154,16 @@ palGetGLAPI - **Thread:** **palJoinThread()** now takes a void** for retval parameter. - **Opengl:** **palEnumerateGLFBConfigs()** now does not take glWindow parameter anymore. -- **Opengl:** **palInitGL()** now takes a instance parameter. +- **Opengl:** **palInitGL()** now takes an api and instance parameter. - **Opengl:** rename **PalGLRelease** to **PalGLReleaseBehavior**. -- **Opengl:** rename **palGLGetProcAddress()** to **palGetGLProcAddress()**. -- **Opengl:** rename **palGLGetBackend()** to **palGetGLBackend()**. -- **Opengl:** **palGetGLBackend()** now returns a **PalGLBackend**. +- **Opengl:** rename **palGetGLProcAddress()** to **palGetGLProcAddress()**. - **Video:** **palGetWindowHandleInfo()** now takes an info parameter. - **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. - **Video:** **palGetMouseWheelDelta()** now takes floats instead of uint32_t. - **Video:** **palInitVideo()** now takes a preferredInstance parameter. - **Video:** **PalWindowCreateInfo** now has `appName`, `instanceName`, `fbConfigBackend` and -`fbConfigId` fields. +`fbConfigIndex` fields. ### Removed - **Core:** Removed **PAL_RESULT_NULL_POINTER** result code. @@ -191,6 +189,7 @@ palGetGLAPI - **Core:** Removed **PAL_RESULT_INVALID_FBCONFIG_BACKEND** result code. - **Opengl:** Removed **palGLSetInstance** function. +- **Opengl:** Removed **palGLGetBackend** function. - **Video:** Removed **palGetVideoFeaturesEx** function. - **Video:** Removed **palGetWindowHandleInfoEx** function. diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 028eb852..fcbc59fa 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -139,6 +139,8 @@ typedef struct { PalGLExtensions extensions; uint32_t major; uint32_t minor; + PalGLBackend backend; + PalGLAPI api; char vendor[PAL_GL_VENDOR_NAME_SIZE]; char graphicsCard[PAL_GL_GRAPHICS_CARD_NAME_SIZE]; char version[PAL_GL_VERSION_NAME_SIZE]; @@ -214,11 +216,10 @@ typedef struct { * `Linux`: This is the Display associated with the connection. * `Windows`: This is the HINSTANCE of the process. * + * @param[in] api The api to use. (eg. PAL_GL_API_OPENGL). Call palGetSupportedGLAPIs() to check + * if an api is supported on `instance`. * @param[in] instance The instance the opengl system will be tied to (eg. XDisplay). * Must not be nullptr. - * @param[in] backend The backend to use. (eg. PAL_GL_BACKEND_WGL). - * @param[in] api The backend api to use. (eg. PAL_GL_API_OPENGL). Some apis are not compatible - * with some backends. * @param[in] allocator Optional user-provided allocator. Set to nullptr to use * default. * @@ -231,9 +232,8 @@ typedef struct { * @sa palShutdownGL */ PAL_API PalResult PAL_CALL palInitGL( - void* instance, - PalGLBackend backend, PalGLAPI api, + void* instance, const PalAllocator* allocator); /** @@ -448,27 +448,18 @@ PAL_API PalResult PAL_CALL palSwapBuffers( PAL_API PalResult PAL_CALL palSetSwapInterval(int32_t interval); /** - * @brief Get the backend of the opengl system. - * - * The opengl system must be initialized before this call. - * - * Thread safety: Thread safe. - * - * @since 2.0 - */ -PAL_API PalGLBackend PAL_CALL palGetGLBackend(); - -/** - * @brief Get the api of the opengl system. + * @brief Get supported opengl APIs + * + * @param[in] instance The instance (eg. HINSTANCE or XDisplay). * - * The opengl system must be initialized before this call. + * @return An array of bools or nullptr on failure. * - * Thread safety: Thread safe. + * Thread safety: Must only be called from the main thread. * * @since 2.0 */ -PAL_API PalGLAPI PAL_CALL palGetGLAPI(); +PAL_API const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance); -/** @} */ // end of pal_opengl group +/** @} */ #endif // _PAL_OPENGL_H diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 226f8576..883257bc 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -584,7 +584,7 @@ typedef struct { const char* appName; /**< If nullptr, `PAL` will be used.*/ const char* instanceName; /**< If nullptr, `title` will be used.*/ PalFBConfigBackend fbConfigBackend; - int32_t fbConfigId; + int32_t fbConfigIndex; uint32_t width; /**< Width in pixels.*/ uint32_t height; /**< Width in pixels.*/ PalBool show; /**< Show after creation.*/ @@ -869,9 +869,9 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * * The video system must be initialized before this call. * - * `PalWindowCreateInfo::fbConfigId` is the loop index from the drivers supported FBConfigs. + * `PalWindowCreateInfo::fbConfigIndex` is the loop index from the drivers supported FBConfigs. * `PalWindowCreateInfo::fbConfigBackend` is used to tell the video system the source of - * `PalWindowCreateInfo::fbConfigId`. + * `PalWindowCreateInfo::fbConfigIndex`. * * Example Flow: * Enumerate and select your FBConfig using any backend(EGL, GLX, WGL) diff --git a/pal.lua b/pal.lua index 25b6e73f..78bbf69f 100644 --- a/pal.lua +++ b/pal.lua @@ -163,11 +163,19 @@ project "PAL" end if (PAL_BUILD_OPENGL_MODULE) then + files { "src/opengl/pal_opengl_shared.c" } + filter {"system:windows", "configurations:*"} - files { "src/opengl/pal_opengl_win32.c" } + files { + "src/opengl/win32/pal_context_win32.c", + "src/opengl/win32/pal_opengl_win32.c" + } filter {"system:linux", "configurations:*"} - files { "src/opengl/pal_opengl_linux.c" } + files { + "src/opengl/linux/pal_context_linux.c", + "src/opengl/linux/pal_opengl_linux.c" + } filter {} end diff --git a/pal_config.lua b/pal_config.lua index 07bf5d26..9ecc849e 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -12,13 +12,13 @@ PAL_BUILD_ABI_DUMP = true PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD_MODULE = false +PAL_BUILD_THREAD_MODULE = true -- build video module PAL_BUILD_VIDEO_MODULE = true -- build opengl module -PAL_BUILD_OPENGL_MODULE = false +PAL_BUILD_OPENGL_MODULE = true -- build graphics module PAL_BUILD_GRAPHICS_MODULE = false diff --git a/src/opengl/linux/pal_context_linux.c b/src/opengl/linux/pal_context_linux.c new file mode 100644 index 00000000..bcfd89bf --- /dev/null +++ b/src/opengl/linux/pal_context_linux.c @@ -0,0 +1,368 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#define _GNU_SOURCE +#define _POSIX_C_SOURCE 200112L + +#include "pal_opengl_linux.h" +#include "pal_shared.h" + +PalResult PAL_CALL palCreateGLContext( + const PalGLContextCreateInfo* info, + PalGLContext** outContext) +{ + if (!s_GL.initialized) { + palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!info || !outContext) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!info->window || !info->fbConfig) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // check if the window was created with the same display + // the opengl system is using + if (info->window->display != s_GL.instance) { + palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // check support for requested features + if (info->profile != PAL_GL_PROFILE_NONE) { + if (!(s_GL.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE)) { + palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + if (info->forward) { + if (!(s_GL.info.extensions & PAL_GL_EXTENSION_CREATE_CONTEXT)) { + palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { + if (!(s_GL.info.extensions & PAL_GL_EXTENSION_ROBUSTNESS)) { + palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + if (info->noError) { + if (!(s_GL.info.extensions & PAL_GL_EXTENSION_NO_ERROR)) { + palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { + if (!(s_GL.info.extensions & PAL_GL_EXTENSION_FLUSH_CONTROL)) { + palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + // check version + PalBool valid = info->major < s_GL.info.major || + (info->major == s_GL.info.major && info->minor <= s_GL.info.minor); + + if (!valid) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + ContextData* data = getFreeContextData(); + if (!data) { + palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // we need to get the EGL config from the user supplied index + EGLint numConfigs = 0; + if (!s_GL.eglGetConfigs(s_GL.display, nullptr, 0, &numConfigs)) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + EGLint configSize = sizeof(EGLConfig) * numConfigs; + EGLConfig* eglConfigs = palAllocate(s_GL.allocator, configSize, 0); + if (!eglConfigs) { + palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_GL.eglGetConfigs(s_GL.display, eglConfigs, numConfigs, &numConfigs); + EGLConfig config = eglConfigs[info->fbConfig->index]; + + EGLContext* share = nullptr; + if (info->shareContext) { + share = (EGLContext)info->shareContext; + } else { + share = EGL_NO_CONTEXT; + } + + int32_t attribs[40]; + int32_t index = 0; + int32_t profile = 0; + int32_t flags = 0; + + // set context attributes + // the first element is the key and the second is the value + if (s_GL.apiType == EGL_OPENGL_API) { + // set version + attribs[index++] = EGL_CONTEXT_MAJOR_VERSION_KHR; // key + attribs[index++] = info->major; // value + + attribs[index++] = EGL_CONTEXT_MINOR_VERSION_KHR; + attribs[index++] = info->minor; + + // set profile mask + if (info->profile != PAL_GL_PROFILE_NONE) { + attribs[index++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; + + if (info->profile == PAL_GL_PROFILE_COMPATIBILITY) { + profile = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; + } else if (info->profile == PAL_GL_PROFILE_CORE) { + profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; + } + + attribs[index++] = info->profile; + } + + // set forward flag + if (info->forward) { + flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; + } + + } else { + attribs[index++] = EGL_CONTEXT_CLIENT_VERSION; + // our configs support EGL_OPENGL_ES2_BIT and EGL_OPENGL_ES3_BIT + attribs[index++] = info->major; + } + + // set debug flag + if (info->debug) { + flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; + } + + // set robustness + if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { + flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; + attribs[index++] = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR; + + if (info->reset == PAL_GL_CONTEXT_RESET_LOSE_CONTEXT) { + attribs[index++] = EGL_LOSE_CONTEXT_ON_RESET_KHR; + + } else if (info->reset == PAL_GL_CONTEXT_RESET_NO_NOTIFICATION) { + attribs[index++] = EGL_NO_RESET_NOTIFICATION_KHR; + } + } + + // set no error + if (info->noError) { + attribs[index++] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR; + attribs[index++] = PAL_TRUE; + } + + // release + if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { + attribs[index++] = EGL_CONTEXT_RELEASE_BEHAVIOR_KHR; + attribs[index++] = EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR; + } + + if (flags) { + attribs[index++] = EGL_CONTEXT_FLAGS_KHR; + attribs[index++] = flags; + } + attribs[index++] = EGL_NONE; + + // create context + EGLContext context = s_GL.eglCreateContext(s_GL.display, config, share, attribs); + if (context == EGL_NO_CONTEXT) { + EGLint error = s_GL.eglGetError(); + if (error == EGL_BAD_CONFIG) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + + } else if (error == EGL_BAD_ATTRIBUTE) { + // we just return invalid version + // it could be invalid profile + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + + } else { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + // create a window surface + // The only attrib we want is colorspace + EGLint surfaceAttribs[3]; + surfaceAttribs[0] = EGL_GL_COLORSPACE; + if (info->fbConfig->sRGB) { + surfaceAttribs[1] = EGL_GL_COLORSPACE_SRGB_KHR; + } else { + surfaceAttribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; + } + surfaceAttribs[2] = EGL_NONE; + + EGLSurface surface = s_GL.eglCreateWindowSurface( + s_GL.display, + config, + (EGLNativeWindowType)info->window->window, + surfaceAttribs); + + if (surface == EGL_NO_SURFACE) { + EGLint error = s_GL.eglGetError(); + if (error == EGL_BAD_CONFIG) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + + } else { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + // make the context current and swap for the first time + // this will make the window visible + if (s_GL.eglMakeCurrent(s_GL.display, surface, surface, context)) { + s_GL.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + s_GL.glClear(0x00004000); + s_GL.eglSwapBuffers(s_GL.display, surface); + + // revert + s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + + palFree(s_GL.allocator, eglConfigs); + data->context = (PalGLContext*)context; + data->surface = surface; + + *outContext = (PalGLContext*)context; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyGLContext(PalGLContext* context) +{ + if (s_GL.initialized && context) { + ContextData* data = findContextData(context); + if (data) { + // make it not current if it was current + s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + s_GL.eglDestroyContext(s_GL.display, (EGLContext)context); + s_GL.eglDestroySurface(s_GL.display, data->surface); + data->used = PAL_FALSE; + } + } +} + +PalResult PAL_CALL palMakeContextCurrent( + PalGLWindow* glWindow, + PalGLContext* context) +{ + if (!s_GL.initialized) { + palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if ((!glWindow && context) || (glWindow && !context)) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (context && glWindow) { + ContextData* data = findContextData(context); + if (!data) { + palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + EGLint ret; + ret = s_GL.eglMakeCurrent(s_GL.display, data->surface, data->surface, (EGLConfig)context); + if (!ret) { + EGLint error = s_GL.eglGetError(); + if (error == EGL_BAD_CONTEXT) { + palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + + } else if (error == EGL_BAD_SURFACE) { + // since we always create a window surface + palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + + } else { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + } else if (!context && !glWindow) { + s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + + return PAL_RESULT_SUCCESS; +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/opengl/linux/pal_opengl_linux.c b/src/opengl/linux/pal_opengl_linux.c new file mode 100644 index 00000000..ea511029 --- /dev/null +++ b/src/opengl/linux/pal_opengl_linux.c @@ -0,0 +1,728 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef __linux__ +#define _GNU_SOURCE +#define _POSIX_C_SOURCE 200112L +#include "pal_opengl_linux.h" +#include "pal_shared.h" + +#include +#include +#include +#include + +#include + +GLLinux s_GL = {0}; +static PalBool s_SupportedAPIs[2] = {0}; + +static inline PalBool checkString( + const char* string, + const char* strings) +{ + const char* start = strings; + size_t stringLen = strlen(string); + + for (;;) { + const char* where = nullptr; + const char* terminator = nullptr; + + where = strstr(start, string); + if (!where) { + return PAL_FALSE; + } + + // the string was found, we find the terminator by adding the sizeof the strings + terminator = where + stringLen; + if (where == start || *(where - 1) == ' ') { + if (*terminator == ' ' || *terminator == '\0') { + return PAL_TRUE; + } + } + + start = terminator; + } +} + +ContextData* getFreeContextData() +{ + for (int i = 0; i < s_GL.maxContextData; ++i) { + if (!s_GL.contextData[i].used) { + s_GL.contextData[i].used = PAL_TRUE; + return &s_GL.contextData[i]; + } + } + + // resize the data array + // this will almost not reach here since most setups are 1-4 monitors + ContextData* data = nullptr; + int count = s_GL.maxContextData * 2; // double the size + int freeIndex = s_GL.maxContextData + 1; + data = palAllocate(s_GL.allocator, sizeof(ContextData) * count, 0); + if (data) { + memcpy(data, s_GL.contextData, s_GL.maxContextData * sizeof(ContextData)); + + palFree(s_GL.allocator, s_GL.contextData); + s_GL.contextData = data; + s_GL.maxContextData = count; + + s_GL.contextData[freeIndex].used = PAL_TRUE; + return &s_GL.contextData[freeIndex]; + } + return nullptr; +} + +ContextData* findContextData(PalGLContext* context) +{ + for (int i = 0; i < s_GL.maxContextData; ++i) { + if (s_GL.contextData[i].used && s_GL.contextData[i].context == context) { + return &s_GL.contextData[i]; + } + } +} + +void freeContextData(PalGLContext* context) +{ + for (int i = 0; i < s_GL.maxContextData; ++i) { + if (s_GL.contextData[i].used && s_GL.contextData[i].context == context) { + s_GL.contextData[i].used = PAL_FALSE; + } + } +} + +PalResult PAL_CALL palInitGL( + PalGLAPI api, + void* instance, + const PalAllocator* allocator) +{ + if (s_GL.initialized) { + return PAL_RESULT_SUCCESS; + } + + if (!instance) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (allocator && (!allocator->allocate || !allocator->free)) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_GL.maxContextData = 16; // initial size + s_GL.contextData = palAllocate(s_GL.allocator, sizeof(ContextData) * s_GL.maxContextData, 0); + if (!s_GL.maxContextData) { + palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_GL.handle = dlopen("libEGL.so", RTLD_LAZY); + if (!s_GL.handle) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // clang-format off + s_GL.eglGetProcAddress = (eglGetProcAddressFn)dlsym( + s_GL.handle, + "eglGetProcAddress"); + + s_GL.eglCreateContext = (eglCreateContextFn)s_GL.eglGetProcAddress( + "eglCreateContext"); + + s_GL.eglDestroyContext = (eglDestroyContextFn)s_GL.eglGetProcAddress( + "eglDestroyContext"); + + s_GL.eglDestroySurface = (eglDestroySurfaceFn)s_GL.eglGetProcAddress( + "eglDestroySurface"); + + s_GL.eglMakeCurrent = (eglMakeCurrentFn)s_GL.eglGetProcAddress( + "eglMakeCurrent"); + + s_GL.eglSwapBuffers = (eglSwapBuffersFn)s_GL.eglGetProcAddress( + "eglSwapBuffers"); + + s_GL.eglSwapInterval = (eglSwapIntervalFn)s_GL.eglGetProcAddress( + "eglSwapInterval"); + + s_GL.eglInitialize = (eglInitializeFn)s_GL.eglGetProcAddress( + "eglInitialize"); + + s_GL.eglTerminate = (eglTerminateFn)s_GL.eglGetProcAddress("eglTerminate"); + + s_GL.eglGetDisplay = (eglGetDisplayFn)s_GL.eglGetProcAddress( + "eglGetDisplay"); + + s_GL.eglCreatePbufferSurface = (eglCreatePbufferSurfaceFn)s_GL.eglGetProcAddress( + "eglCreatePbufferSurface"); + + s_GL.eglChooseConfig = (eglChooseConfigFn)s_GL.eglGetProcAddress( + "eglChooseConfig"); + + s_GL.eglGetConfigAttrib = (eglGetConfigAttribFn)s_GL.eglGetProcAddress( + "eglGetConfigAttrib"); + + s_GL.eglGetError = (eglGetErrorFn)s_GL.eglGetProcAddress("eglGetError"); + s_GL.eglBindAPI = (eglBindAPIFn)s_GL.eglGetProcAddress("eglBindAPI"); + + s_GL.eglQueryString = (eglQueryStringFn)s_GL.eglGetProcAddress( + "eglQueryString"); + + s_GL.eglGetConfigs = (eglGetConfigsFn)s_GL.eglGetProcAddress( + "eglGetConfigs"); + + s_GL.eglCreateWindowSurface = (eglCreateWindowSurfaceFn)s_GL.eglGetProcAddress( + "eglCreateWindowSurface"); + + s_GL.glClearColor = (glClearColorFn)s_GL.eglGetProcAddress("glClearColor"); + s_GL.glClear = (glClearFn)s_GL.eglGetProcAddress("glClear"); + + if (!s_GL.eglBindAPI || + !s_GL.eglChooseConfig || + !s_GL.eglCreateContext || + !s_GL.eglCreatePbufferSurface || + !s_GL.eglDestroyContext || + !s_GL.eglDestroySurface || + !s_GL.eglGetConfigAttrib || + !s_GL.eglGetDisplay || + !s_GL.eglGetError || + !s_GL.eglGetProcAddress || + !s_GL.eglInitialize || + !s_GL.eglMakeCurrent || + !s_GL.eglSwapBuffers || + !s_GL.eglSwapInterval || + !s_GL.eglTerminate || + !s_GL.eglQueryString || + !s_GL.eglGetConfigs || + !s_GL.eglCreateWindowSurface) { + + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + // clang-format on + + // get api type + if (api == PAL_GL_API_OPENGL) { + s_GL.apiType = EGL_OPENGL_API; + s_GL.apiTypeBit = EGL_OPENGL_BIT; + + } else { + s_GL.apiType = EGL_OPENGL_ES_API; + s_GL.apiTypeBit = EGL_OPENGL_ES2_BIT; // default + } + + if (!s_GL.eglBindAPI(s_GL.apiType)) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + EGLDisplay display = s_GL.eglGetDisplay(instance); + EGLDisplay* tmpDisplay = EGL_NO_DISPLAY; + if (display == EGL_NO_DISPLAY) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!s_GL.eglInitialize(display, nullptr, nullptr)) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // use a simple FBConfig + EGLConfig config; + int numConfigs; + EGLint type; + + // clang-format off + EGLint attribs[] = { + EGL_RENDERABLE_TYPE, + s_GL.apiTypeBit, + EGL_SURFACE_TYPE, + EGL_PBUFFER_BIT, + EGL_NONE + }; + // clang-format on + + s_GL.eglChooseConfig(display, attribs, &config, 1, &numConfigs); + if (!config || numConfigs == 0) { + // API bind type might not support puffer + // create a default display and use that + tmpDisplay = s_GL.eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (display == EGL_NO_DISPLAY) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!s_GL.eglInitialize(tmpDisplay, nullptr, nullptr)) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } else { + // set the tmp display to our display + tmpDisplay = display; + } + + s_GL.eglChooseConfig(tmpDisplay, attribs, &config, 1, &numConfigs); + if (!config) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_GL.eglGetConfigAttrib(tmpDisplay, config, EGL_RENDERABLE_TYPE, &type); + if (!(type & s_GL.apiTypeBit)) { + // we must support the required API + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + EGLSurface surface = EGL_NO_SURFACE; + EGLint pBufferAttribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; + surface = s_GL.eglCreatePbufferSurface(tmpDisplay, config, pBufferAttribs); + if (surface == EGL_NO_SURFACE) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + // create a dummy context + EGLContext context = EGL_NO_CONTEXT; + if (s_GL.apiType == EGL_OPENGL_API) { + // clang-format off + EGLint contextAttrib[] = { + EGL_CONTEXT_MAJOR_VERSION, + 2, + EGL_CONTEXT_MINOR_VERSION, + 1, + EGL_NONE + }; + // clang-format on + + context = s_GL.eglCreateContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); + + } else { + EGLint contextAttrib[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + context = s_GL.eglCreateContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); + } + + if (context == EGL_NO_CONTEXT) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_GL.eglMakeCurrent(tmpDisplay, surface, surface, context); + s_GL.glGetString = (glGetStringFn)s_GL.eglGetProcAddress("glGetString"); + + const char* version = (const char*)s_GL.glGetString(GL_VERSION); + if (version) { + if (s_GL.apiType == EGL_OPENGL_API) { + sscanf(version, "%d.%d", &s_GL.info.major, &s_GL.info.minor); + } else { + sscanf(version + 10, "%d.%d", &s_GL.info.major, &s_GL.info.minor); + } + } + + const char* renderer = (const char*)s_GL.glGetString(GL_RENDERER); + const char* vendor = (const char*)s_GL.glGetString(GL_VENDOR); + strcpy(s_GL.info.vendor, vendor); + strcpy(s_GL.info.version, version); + strcpy(s_GL.info.graphicsCard, renderer); + + // EGL extensions can be queried without a bound context + // we just do that over here after making the context current + const char* extensions = s_GL.eglQueryString(tmpDisplay, EGL_EXTENSIONS); + if (extensions) { + // color space + if (checkString("EGL_KHR_gl_colorspace", extensions)) { + s_GL.info.extensions |= PAL_GL_EXTENSION_COLORSPACE_SRGB; + } + + // create context + if (checkString("EGL_KHR_create_context", extensions)) { + s_GL.info.extensions |= PAL_GL_EXTENSION_CREATE_CONTEXT; + s_GL.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE; + } + + // robustness + if (checkString("EGL_EXT_create_context_robustness", extensions)) { + s_GL.info.extensions |= PAL_GL_EXTENSION_ROBUSTNESS; + } + + // no error + if (checkString("EGL_KHR_create_context_no_error", extensions)) { + s_GL.info.extensions |= PAL_GL_EXTENSION_NO_ERROR; + } + + // flush control + if (checkString("EGL_KHR_context_flush_control", extensions)) { + s_GL.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; + } + + // swap control + if (checkString("EGL_EXT_swap_control", extensions)) { + s_GL.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; + } + + if (checkString("EGL_EXT_swap_control_tear", extensions)) { + s_GL.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; + } + } + + // part of the core API + s_GL.info.extensions |= PAL_GL_EXTENSION_MULTISAMPLE; + if (type & EGL_OPENGL_ES_BIT || type & EGL_OPENGL_ES2_BIT) { + s_GL.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; + } + + // check if we support the core swap interval + if (s_GL.eglSwapInterval) { + s_GL.info.extensions |= PAL_GL_EXTENSION_SWAP_CONTROL; + } + + if (s_GL.apiType != EGL_OPENGL_API) { + if (s_GL.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE) { + s_GL.info.extensions &= ~PAL_GL_EXTENSION_CONTEXT_PROFILE; + s_GL.info.extensions &= ~PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; + } + + if (type & EGL_OPENGL_ES3_BIT) { + s_GL.apiTypeBit = EGL_OPENGL_ES3_BIT; + } + } + + s_GL.eglMakeCurrent(tmpDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + s_GL.eglDestroyContext(tmpDisplay, context); + s_GL.eglDestroySurface(tmpDisplay, surface); + + s_GL.info.api = api; + s_GL.info.backend = PAL_GL_BACKEND_EGL; + s_GL.allocator = allocator; + s_GL.initialized = PAL_TRUE; + + if (tmpDisplay != display) { + // tmpDisplay is a seperate display + // terminate it + s_GL.eglTerminate(tmpDisplay); + } + + s_GL.display = display; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palShutdownGL() +{ + if (!s_GL.initialized) { + return; + } + + palFree(s_GL.allocator, s_GL.contextData); + if (s_GL.display) { + s_GL.eglTerminate(s_GL.display); + } + + dlclose(s_GL.handle); + s_GL.initialized = PAL_FALSE; +} + +const PalGLInfo* PAL_CALL palGetGLInfo() +{ + if (!s_GL.initialized) { + return nullptr; + } + return &s_GL.info; +} + +PalResult PAL_CALL palEnumerateGLFBConfigs( + int32_t* count, + PalGLFBConfig* configs) +{ + if (!s_GL.initialized) { + palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!count || count == 0 && configs) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + int32_t configCount = 0; + int32_t maxConfigCount = 0; + if (configs) { + maxConfigCount = *count; + } + + // get the number of configs and filter the ones for opengl desktop + EGLint numConfigs = 0; + if (!s_GL.eglGetConfigs(s_GL.display, nullptr, 0, &numConfigs)) { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + EGLint configSize = sizeof(EGLConfig) * numConfigs; + EGLConfig* eglConfigs = palAllocate(s_GL.allocator, configSize, 0); + if (!eglConfigs) { + palMakeResult( + PAL_RESULT_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_GL.eglGetConfigs(s_GL.display, eglConfigs, numConfigs, &numConfigs); + for (int i = 0; i < numConfigs; i++) { + // attributes we care about + EGLint surfaceType = 0, renderable = 0; + EGLint colorType = 0; + + EGLConfig config = eglConfigs[i]; + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_SURFACE_TYPE, &surfaceType); + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_RENDERABLE_TYPE, &renderable); + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_COLOR_BUFFER_TYPE, &colorType); + + // we need only opengl API configs + if (colorType != EGL_RGB_BUFFER) { + continue; + } + + if (s_GL.apiType == EGL_OPENGL_ES3_BIT) { + // EGL_OPENGL_ES2_BIT + if (!(renderable & EGL_OPENGL_ES2_BIT) && !(renderable & EGL_OPENGL_ES3_BIT)) { + continue; + } + + } else if (s_GL.apiType == EGL_OPENGL_ES2_BIT) { + if (!(renderable & EGL_OPENGL_ES2_BIT)) { + continue; + } + + } else { + if (!(renderable & EGL_OPENGL_BIT)) { + continue; + } + } + + if (!(surfaceType & EGL_WINDOW_BIT)) { + continue; + } + + if (configs && configCount < maxConfigCount) { + // get this only if user supplied an output buffer (PalGLFBConfig*) + PalGLFBConfig* fbConfig = &configs[configCount]; + fbConfig->index = i; + + EGLint redBits, greenBits, blueBits, alphaBits; + EGLint depthBits, stencilBits, samples; + + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_RED_SIZE, &redBits); + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_GREEN_SIZE, &greenBits); + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_BLUE_SIZE, &blueBits); + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_ALPHA_SIZE, &alphaBits); + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_DEPTH_SIZE, &depthBits); + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_STENCIL_SIZE, &stencilBits); + s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_SAMPLES, &samples); + if (samples == 0) { + samples = 1; + } + + fbConfig->redBits = redBits; + fbConfig->greenBits = greenBits; + fbConfig->blueBits = blueBits; + fbConfig->alphaBits = alphaBits; + fbConfig->depthBits = depthBits; + fbConfig->stencilBits = stencilBits; + fbConfig->samples = samples; + + // True for EGL_WINDOW_BIT + fbConfig->doubleBuffer = PAL_TRUE; + fbConfig->stereo = PAL_FALSE; + + fbConfig->sRGB = PAL_FALSE; + if (s_GL.info.extensions & PAL_GL_EXTENSION_COLORSPACE_SRGB) { + // since EGL does not have a bit to check SRGB support + // we check if all the color bits are greater than or equal to 8 + if (fbConfig->redBits >= 8 && fbConfig->greenBits >= 8 && fbConfig->blueBits >= 8) { + fbConfig->sRGB = PAL_TRUE; + } + } + } + configCount++; + } + + palFree(s_GL.allocator, eglConfigs); + if (!configs) { + *count = configCount; + } + + return PAL_RESULT_SUCCESS; +} + +void* PAL_CALL palGetGLProcAddress(const char* name) +{ + if (!s_GL.initialized) { + return nullptr; + } + + return s_GL.eglGetProcAddress(name); +} + +PalResult PAL_CALL palSwapBuffers( + PalGLWindow* glWindow, + PalGLContext* context) +{ + if (!s_GL.initialized) { + palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!context || !glWindow) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + ContextData* data = findContextData(context); + if (!data) { + palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!s_GL.eglSwapBuffers(s_GL.display, data->surface)) { + EGLint error = s_GL.eglGetError(); + if (error == EGL_BAD_CONTEXT) { + palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + + } else if (error == EGL_BAD_SURFACE) { + // since we always create a window surface + palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + + } else { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSetSwapInterval(int32_t interval) +{ + if (!s_GL.initialized) { + palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!s_GL.eglSwapInterval) { + palMakeResult( + PAL_RESULT_FEATURE_NOT_SUPPORTED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + s_GL.eglSwapInterval(s_GL.display, interval); + return PAL_RESULT_SUCCESS; +} + +const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance) +{ + if (!instance) { + return nullptr; + } + + void* handle = dlopen("libEGL.so", RTLD_LAZY); + if (!handle) { + return nullptr; + } + + // clang-format off + eglGetProcAddressFn getProcAddress = (eglGetProcAddressFn)dlsym(handle, "eglGetProcAddress"); + eglInitializeFn initialize = (eglInitializeFn)getProcAddress("eglInitialize"); + eglTerminateFn terminate = (eglTerminateFn)getProcAddress("eglTerminate"); + eglGetDisplayFn getDisplay = (eglGetDisplayFn)getProcAddress("eglGetDisplay"); + eglQueryStringFn queryString = (eglQueryStringFn)getProcAddress("eglQueryString"); + if (!getProcAddress || !initialize || !terminate || !getDisplay || !queryString) { + return nullptr; + } + // clang-format on + + EGLDisplay display = getDisplay(instance); + if (display == EGL_NO_DISPLAY) { + return nullptr; + } + + if (!initialize(display, nullptr, nullptr)) { + return nullptr; + } + + const char* apis = queryString(display, EGL_CLIENT_APIS); + if (apis) { + if (checkString("OpenGL", apis)) { + s_SupportedAPIs[PAL_GL_API_OPENGL] = PAL_TRUE; + } else { + s_SupportedAPIs[PAL_GL_API_OPENGL] = PAL_FALSE; + } + + if (checkString("OpenGL_ES", apis)) { + s_SupportedAPIs[PAL_GL_API_OPENGL_ES] = PAL_TRUE; + } else { + s_SupportedAPIs[PAL_GL_API_OPENGL_ES] = PAL_FALSE; + } + } + + terminate(display); + dlclose(handle); + return s_SupportedAPIs; +} + +#endif // __linux__ \ No newline at end of file diff --git a/src/opengl/linux/pal_opengl_linux.h b/src/opengl/linux/pal_opengl_linux.h new file mode 100644 index 00000000..2a5d3c6f --- /dev/null +++ b/src/opengl/linux/pal_opengl_linux.h @@ -0,0 +1,241 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_OPENGL_LINUX_H +#define _PAL_OPENGL_LINUX_H +#ifdef __linux__ + +#include "pal/pal_opengl.h" +#include + +#ifndef GL_VENDOR +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#endif // GL_VENDOR + +typedef unsigned int GLenum; +typedef unsigned char GLubyte; +typedef int32_t EGLint; +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; + +typedef unsigned long int khronos_uintptr_t; +typedef khronos_uintptr_t EGLNativeWindowType; + +typedef void* EGLConfig; +typedef void* EGLSurface; +typedef void* EGLContext; +typedef void* EGLDisplay; +typedef void* EGLNativeDisplayType; + +#ifndef EGL_OPENGL_API +#define EGL_CAST(type, value) ((type)(value)) +#define EGL_OPENGL_API 0x30A2 +#define EGL_OPENGL_BIT 0x0008 +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_CLIENT_APIS 0x308D +#define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0) +#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0) +#define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0) +#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType, 0) +#define EGL_GL_COLORSPACE 0x309D +#define EGL_COLORSPACE_sRGB 0x3089 +#define EGL_COLORSPACE_LINEAR 0x308A +#define EGL_COLOR_BUFFER_TYPE 0x303F +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_RGB_BUFFER 0x308E +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_SURFACE 0x300D +#define EGL_EXTENSIONS 0x3055 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_MAX_PBUFFER_WIDTH 0x302C +#define EGL_NATIVE_VISUAL_ID 0x302E +#define EGL_NONE 0x3038 +#define EGL_HEIGHT 0x3056 +#define EGL_WIDTH 0x3057 +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENGL_ES2_BIT 0x0004 +#define EGL_OPENGL_ES3_BIT 0x00000040 + +#define EGL_PBUFFER_BIT 0x0001 +#define EGL_RED_SIZE 0x3024 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_SAMPLES 0x3031 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_WINDOW_BIT 0x0004 +#define EGL_CONTEXT_MAJOR_VERSION 0x3098 +#define EGL_CONTEXT_MINOR_VERSION 0x30FB +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 + +#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB +#define EGL_CONTEXT_FLAGS_KHR 0x30FC +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD +#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD +#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE +#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 +#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 +#define EGL_OPENGL_ES3_BIT_KHR 0x00000040 +#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 +#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 +#define EGL_GL_COLORSPACE_KHR 0x309D +#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 +#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A +#endif // EGL header + +typedef void* (*eglGetProcAddressFn)(const char*); + +typedef EGLContext (*eglCreateContextFn)( + EGLDisplay, + EGLConfig, + EGLContext, + const EGLint*); + +typedef EGLBoolean (*eglDestroyContextFn)( + EGLDisplay, + EGLContext); + +typedef EGLBoolean (*eglMakeCurrentFn)( + EGLDisplay, + EGLSurface, + EGLSurface, + EGLContext); + +typedef EGLBoolean (*eglSwapBuffersFn)( + EGLDisplay, + EGLSurface); + +typedef EGLBoolean (*eglSwapIntervalFn)( + EGLDisplay, + EGLint); + +typedef EGLBoolean (*eglInitializeFn)( + EGLDisplay, + EGLint*, + EGLint*); + +typedef EGLBoolean (*eglTerminateFn)(EGLDisplay); + +typedef EGLDisplay (*eglGetDisplayFn)(EGLNativeDisplayType); + +typedef EGLBoolean (*eglDestroySurfaceFn)( + EGLDisplay, + EGLSurface); + +typedef EGLSurface (*eglCreatePbufferSurfaceFn)( + EGLDisplay, + EGLConfig, + const EGLint*); + +typedef EGLBoolean (*eglChooseConfigFn)( + EGLDisplay, + const EGLint*, + EGLConfig*, + EGLint, + EGLint*); + +typedef EGLBoolean (*eglGetConfigAttribFn)( + EGLDisplay, + EGLConfig, + EGLint, + EGLint*); + +typedef EGLint (*eglGetErrorFn)(void); + +typedef EGLBoolean (*eglBindAPIFn)(EGLenum); + +typedef const char* (*eglQueryStringFn)( + EGLDisplay, + EGLint); + +typedef EGLBoolean (*eglGetConfigsFn)( + EGLDisplay, + EGLConfig*, + EGLint, + EGLint*); + +typedef EGLSurface (*eglCreateWindowSurfaceFn)( + EGLDisplay, + EGLConfig, + EGLNativeWindowType, + const EGLint*); + +typedef const GLubyte* (*glGetStringFn)(GLenum); +typedef void(PAL_GL_APIENTRY* glClearFn)(uint32_t); + +typedef void(PAL_GL_APIENTRY* glClearColorFn)( + float, + float, + float, + float); + +typedef struct { + PalBool used; + EGLSurface surface; + PalGLContext* context; +} ContextData; + +typedef struct { + PalBool initialized; + int32_t maxContextData; + EGLenum apiType; + int apiTypeBit; + const PalAllocator* allocator; + + eglGetProcAddressFn eglGetProcAddress; + eglCreateContextFn eglCreateContext; + eglDestroyContextFn eglDestroyContext; + eglMakeCurrentFn eglMakeCurrent; + eglSwapBuffersFn eglSwapBuffers; + eglSwapIntervalFn eglSwapInterval; + eglInitializeFn eglInitialize; + eglTerminateFn eglTerminate; + eglGetDisplayFn eglGetDisplay; + eglDestroySurfaceFn eglDestroySurface; + eglCreatePbufferSurfaceFn eglCreatePbufferSurface; + eglChooseConfigFn eglChooseConfig; + eglGetConfigAttribFn eglGetConfigAttrib; + eglGetErrorFn eglGetError; + eglBindAPIFn eglBindAPI; + eglQueryStringFn eglQueryString; + eglGetConfigsFn eglGetConfigs; + eglCreateWindowSurfaceFn eglCreateWindowSurface; + + glGetStringFn glGetString; + glClearColorFn glClearColor; + glClearFn glClear; + + void* handle; + void* instance; + ContextData* contextData; + EGLDisplay display; + PalGLInfo info; +} GLLinux; + +extern GLLinux s_GL; + +ContextData* getFreeContextData(); +ContextData* findContextData(PalGLContext* context); +void freeContextData(PalGLContext* context); + +#endif // __linux__ +#endif // _PAL_OPENGL_LINUX_H \ No newline at end of file diff --git a/src/opengl/pal_backends_opengl.h b/src/opengl/pal_backends_opengl.h deleted file mode 100644 index 33815710..00000000 --- a/src/opengl/pal_backends_opengl.h +++ /dev/null @@ -1,94 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifndef _PAL_BACKENDS_OPENGL_H -#define _PAL_BACKENDS_OPENGL_H - -#include "pal_opengl_helper.h" - -// ================================================== -// WGL -// ================================================== - -PalResult PAL_CALL wglInitGL(); -void PAL_CALL wglShutdownGL(); -const PalGLInfo* PAL_CALL wglGetGLInfo(); -PalResult PAL_CALL wglEnumerateGLFBConfigs(int32_t*, PalGLFBConfig*); -PalResult PAL_CALL wglCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); -void PAL_CALL wglDestroyGLContext(PalGLContext*); -PalResult PAL_CALL wglMakeContextCurrent(PalGLWindow*, PalGLContext*); -void* PAL_CALL wglGetGLProcAddress(const char*); -PalResult PAL_CALL wglSwapBuffers(PalGLWindow*, PalGLContext*); -PalResult PAL_CALL wglSetSwapInterval(int32_t); - -static Backend s_WglBackend = { - .shutdownGL = wglShutdownGL, - .getGLInfo = wglGetGLInfo, - .enumerateGLFBConfigs = wglEnumerateGLFBConfigs, - .createGLContext = wglCreateGLContext, - .destroyGLContext = wglDestroyGLContext, - .makeContextCurrent = wglMakeContextCurrent, - .getGLProcAddress = wglGetGLProcAddress, - .swapBuffers = wglSwapBuffers, - .setSwapInterval = wglSetSwapInterval, -}; - -// ================================================== -// GLX -// ================================================== - -PalResult PAL_CALL glxInitGL(); -void PAL_CALL glxShutdownGL(); -const PalGLInfo* PAL_CALL glxGetGLInfo(); -PalResult PAL_CALL glxEnumerateGLFBConfigs(int32_t*, PalGLFBConfig*); -PalResult PAL_CALL glxCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); -void PAL_CALL glxDestroyGLContext(PalGLContext*); -PalResult PAL_CALL glxMakeContextCurrent(PalGLWindow*, PalGLContext*); -void* PAL_CALL glxGetGLProcAddress(const char*); -PalResult PAL_CALL glxSwapBuffers(PalGLWindow*, PalGLContext*); -PalResult PAL_CALL glxSetSwapInterval(int32_t); - -static Backend s_GlxBackend = { - .shutdownGL = glxShutdownGL, - .getGLInfo = glxGetGLInfo, - .enumerateGLFBConfigs = glxEnumerateGLFBConfigs, - .createGLContext = glxCreateGLContext, - .destroyGLContext = glxDestroyGLContext, - .makeContextCurrent = glxMakeContextCurrent, - .getGLProcAddress = glxGetGLProcAddress, - .swapBuffers = glxSwapBuffers, - .setSwapInterval = glxSetSwapInterval, -}; - -// ================================================== -// EGL -// ================================================== - -PalResult PAL_CALL eglInitGL(); -void PAL_CALL eglShutdownGL(); -const PalGLInfo* PAL_CALL eglGetGLInfo(); -PalResult PAL_CALL eglEnumerateGLFBConfigs(int32_t*, PalGLFBConfig*); -PalResult PAL_CALL eglCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); -void PAL_CALL eglDestroyGLContext(PalGLContext*); -PalResult PAL_CALL eglMakeContextCurrent(PalGLWindow*, PalGLContext*); -void* PAL_CALL eglGetGLProcAddress(const char*); -PalResult PAL_CALL eglSwapBuffers(PalGLWindow*, PalGLContext*); -PalResult PAL_CALL eglSetSwapInterval(int32_t); - -static Backend s_EglBackend = { - .shutdownGL = eglShutdownGL, - .getGLInfo = eglGetGLInfo, - .enumerateGLFBConfigs = eglEnumerateGLFBConfigs, - .createGLContext = eglCreateGLContext, - .destroyGLContext = eglDestroyGLContext, - .makeContextCurrent = eglMakeContextCurrent, - .getGLProcAddress = eglGetGLProcAddress, - .swapBuffers = eglSwapBuffers, - .setSwapInterval = eglSetSwapInterval, -}; - -#endif // _PAL_BACKENDS_OPENGL_H diff --git a/src/opengl/pal_opengl.c b/src/opengl/pal_opengl.c deleted file mode 100644 index e69de29b..00000000 diff --git a/src/opengl/pal_opengl_helper.h b/src/opengl/pal_opengl_helper.h deleted file mode 100644 index fb29dcde..00000000 --- a/src/opengl/pal_opengl_helper.h +++ /dev/null @@ -1,39 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifndef _PAL_OPENGL_HELPER_H -#define _PAL_OPENGL_HELPER_H - -#include "pal/pal_opengl.h" - -typedef struct { - // clang-format off - void (PAL_CALL *shutdownGL)(); - const PalGLInfo* (PAL_CALL *getGLInfo)(); - PalResult (PAL_CALL *enumerateGLFBConfigs)(int32_t*, PalGLFBConfig*); - PalResult (PAL_CALL *createGLContext)(const PalGLContextCreateInfo*, PalGLContext**); - void (PAL_CALL *destroyGLContext)(PalGLContext*); - PalResult (PAL_CALL *makeContextCurrent)(PalGLWindow*, PalGLContext*); - void* (PAL_CALL *getGLProcAddress)(const char*); - - PalResult (PAL_CALL *swapBuffers)(PalGLWindow*, PalGLContext*); - PalResult (PAL_CALL *setSwapInterval)(int32_t); - // clang-format on -} Backend; - -typedef struct { - PalBool initialized; - void* handle; - void* instance; - const PalAllocator* allocator; - Backend* backend; - PalGLInfo info; -} Opengl; - -extern Opengl s_GL; - -#endif // _PAL_OPENGL_HELPER_H \ No newline at end of file diff --git a/src/opengl/pal_opengl_linux.c b/src/opengl/pal_opengl_linux.c deleted file mode 100644 index b5d9ca97..00000000 --- a/src/opengl/pal_opengl_linux.c +++ /dev/null @@ -1,1211 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -// ================================================== -// Includes -// ================================================== - -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L -#include "pal/pal_opengl.h" - -#include -#include -#include -#include -#include - -// ================================================== -// Typedefs, enums and structs -// ================================================== - -#ifndef GL_VENDOR -#define GL_VENDOR 0x1F00 -#define GL_RENDERER 0x1F01 -#define GL_VERSION 0x1F02 -#define GL_EXTENSIONS 0x1F03 -#endif // GL_VENDOR - -typedef unsigned int GLenum; -typedef unsigned char GLubyte; -typedef int32_t EGLint; -typedef unsigned int EGLBoolean; -typedef unsigned int EGLenum; - -typedef unsigned long int khronos_uintptr_t; -typedef khronos_uintptr_t EGLNativeWindowType; - -typedef void* EGLConfig; -typedef void* EGLSurface; -typedef void* EGLContext; -typedef void* EGLDisplay; -typedef void* EGLNativeDisplayType; - -#ifndef EGL_OPENGL_API -#define EGL_CAST(type, value) ((type)(value)) -#define EGL_OPENGL_API 0x30A2 -#define EGL_OPENGL_BIT 0x0008 -#define EGL_OPENGL_ES_BIT 0x0001 -#define EGL_OPENGL_ES_API 0x30A0 -#define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0) -#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0) -#define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0) -#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType, 0) -#define EGL_GL_COLORSPACE 0x309D -#define EGL_COLORSPACE_sRGB 0x3089 -#define EGL_COLORSPACE_LINEAR 0x308A -#define EGL_COLOR_BUFFER_TYPE 0x303F -#define EGL_OPENGL_ES_BIT 0x0001 -#define EGL_OPENGL_ES_API 0x30A0 -#define EGL_RENDERABLE_TYPE 0x3040 -#define EGL_RGB_BUFFER 0x308E -#define EGL_ALPHA_SIZE 0x3021 -#define EGL_BAD_ATTRIBUTE 0x3004 -#define EGL_BAD_CONFIG 0x3005 -#define EGL_BAD_CONTEXT 0x3006 -#define EGL_BAD_SURFACE 0x300D -#define EGL_EXTENSIONS 0x3055 -#define EGL_GREEN_SIZE 0x3023 -#define EGL_MAX_PBUFFER_WIDTH 0x302C -#define EGL_NATIVE_VISUAL_ID 0x302E -#define EGL_NONE 0x3038 -#define EGL_HEIGHT 0x3056 -#define EGL_WIDTH 0x3057 -#define EGL_OPENGL_ES_BIT 0x0001 -#define EGL_OPENGL_ES2_BIT 0x0004 -#define EGL_OPENGL_ES3_BIT 0x00000040 - -#define EGL_PBUFFER_BIT 0x0001 -#define EGL_RED_SIZE 0x3024 -#define EGL_BLUE_SIZE 0x3022 -#define EGL_DEPTH_SIZE 0x3025 -#define EGL_SAMPLES 0x3031 -#define EGL_STENCIL_SIZE 0x3026 -#define EGL_SURFACE_TYPE 0x3033 -#define EGL_WINDOW_BIT 0x0004 -#define EGL_CONTEXT_MAJOR_VERSION 0x3098 -#define EGL_CONTEXT_MINOR_VERSION 0x30FB -#define EGL_CONTEXT_CLIENT_VERSION 0x3098 - -#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 -#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB -#define EGL_CONTEXT_FLAGS_KHR 0x30FC -#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD -#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD -#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE -#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF -#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 -#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 -#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 -#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 -#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 -#define EGL_OPENGL_ES3_BIT_KHR 0x00000040 -#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3 -#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097 -#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098 -#define EGL_GL_COLORSPACE_KHR 0x309D -#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089 -#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A -#endif // EGL header - -typedef void* (*eglGetProcAddressFn)(const char*); - -typedef EGLContext (*eglCreateContextFn)( - EGLDisplay, - EGLConfig, - EGLContext, - const EGLint*); - -typedef EGLBoolean (*eglDestroyContextFn)( - EGLDisplay, - EGLContext); - -typedef EGLBoolean (*eglMakeCurrentFn)( - EGLDisplay, - EGLSurface, - EGLSurface, - EGLContext); - -typedef EGLBoolean (*eglSwapBuffersFn)( - EGLDisplay, - EGLSurface); - -typedef EGLBoolean (*eglSwapIntervalFn)( - EGLDisplay, - EGLint); - -typedef EGLBoolean (*eglInitializeFn)( - EGLDisplay, - EGLint*, - EGLint*); - -typedef EGLBoolean (*eglTerminateFn)(EGLDisplay); - -typedef EGLDisplay (*eglGetDisplayFn)(EGLNativeDisplayType); - -typedef EGLBoolean (*eglDestroySurfaceFn)( - EGLDisplay, - EGLSurface); - -typedef EGLSurface (*eglCreatePbufferSurfaceFn)( - EGLDisplay, - EGLConfig, - const EGLint*); - -typedef EGLBoolean (*eglChooseConfigFn)( - EGLDisplay, - const EGLint*, - EGLConfig*, - EGLint, - EGLint*); - -typedef EGLBoolean (*eglGetConfigAttribFn)( - EGLDisplay, - EGLConfig, - EGLint, - EGLint*); - -typedef EGLint (*eglGetErrorFn)(void); - -typedef EGLBoolean (*eglBindAPIFn)(EGLenum); - -typedef const char* (*eglQueryStringFn)( - EGLDisplay, - EGLint); - -typedef EGLBoolean (*eglGetConfigsFn)( - EGLDisplay, - EGLConfig*, - EGLint, - EGLint*); - -typedef EGLSurface (*eglCreateWindowSurfaceFn)( - EGLDisplay, - EGLConfig, - EGLNativeWindowType, - const EGLint*); - -typedef const GLubyte* (*glGetStringFn)(GLenum); -typedef void(PAL_GL_APIENTRY* glClearFn)(uint32_t); - -typedef void(PAL_GL_APIENTRY* glClearColorFn)( - float, - float, - float, - float); - -typedef struct { - PalBool used; - EGLSurface surface; - PalGLContext* context; -} ContextData; - -typedef struct { - PalBool initialized; - int32_t maxContextData; - EGLenum apiType; - int apiTypeBit; - const PalAllocator* allocator; - - eglGetProcAddressFn eglGetProcAddress; - eglCreateContextFn eglCreateContext; - eglDestroyContextFn eglDestroyContext; - eglMakeCurrentFn eglMakeCurrent; - eglSwapBuffersFn eglSwapBuffers; - eglSwapIntervalFn eglSwapInterval; - eglInitializeFn eglInitialize; - eglTerminateFn eglTerminate; - eglGetDisplayFn eglGetDisplay; - eglDestroySurfaceFn eglDestroySurface; - eglCreatePbufferSurfaceFn eglCreatePbufferSurface; - eglChooseConfigFn eglChooseConfig; - eglGetConfigAttribFn eglGetConfigAttrib; - eglGetErrorFn eglGetError; - eglBindAPIFn eglBindAPI; - eglQueryStringFn eglQueryString; - eglGetConfigsFn eglGetConfigs; - eglCreateWindowSurfaceFn eglCreateWindowSurface; - - glGetStringFn glGetString; - glClearColorFn glClearColor; - glClearFn glClear; - - void* handle; - void* platformDisplay; - ContextData* contextData; - EGLDisplay display; - PalGLInfo info; -} GLLinux; - -static GLLinux s_GL = {0}; - -// ================================================== -// Internal API -// ================================================== - -static inline PalBool checkExtension( - const char* extension, - const char* extensions) -{ - const char* start = extensions; - size_t extensionLen = strlen(extension); - - for (;;) { - const char* where = nullptr; - const char* terminator = nullptr; - - where = strstr(start, extension); - if (!where) { - return PAL_FALSE; - } - - // the extension was found, we find the terminator by adding the sizeof - // the extension - terminator = where + extensionLen; - if (where == start || *(where - 1) == ' ') { - if (*terminator == ' ' || *terminator == '\0') { - return PAL_TRUE; - } - } - - start = terminator; - } -} - -static ContextData* getFreeContextData() -{ - for (int i = 0; i < s_GL.maxContextData; ++i) { - if (!s_GL.contextData[i].used) { - s_GL.contextData[i].used = PAL_TRUE; - return &s_GL.contextData[i]; - } - } - - // resize the data array - // this will almost not reach here since most setups are 1-4 monitors - ContextData* data = nullptr; - int count = s_GL.maxContextData * 2; // double the size - int freeIndex = s_GL.maxContextData + 1; - data = palAllocate(s_GL.allocator, sizeof(ContextData) * count, 0); - if (data) { - memcpy(data, s_GL.contextData, s_GL.maxContextData * sizeof(ContextData)); - - palFree(s_GL.allocator, s_GL.contextData); - s_GL.contextData = data; - s_GL.maxContextData = count; - - s_GL.contextData[freeIndex].used = PAL_TRUE; - return &s_GL.contextData[freeIndex]; - } - return nullptr; -} - -static ContextData* findContextData(PalGLContext* context) -{ - for (int i = 0; i < s_GL.maxContextData; ++i) { - if (s_GL.contextData[i].used && s_GL.contextData[i].context == context) { - return &s_GL.contextData[i]; - } - } -} - -static void freeContextData(PalGLContext* context) -{ - for (int i = 0; i < s_GL.maxContextData; ++i) { - if (s_GL.contextData[i].used && s_GL.contextData[i].context == context) { - s_GL.contextData[i].used = PAL_FALSE; - } - } -} - -void palSetLastPlatformError(uint32_t e); - -// ================================================== -// Public API -// ================================================== - -PalResult PAL_CALL palInitGL(const PalAllocator* allocator) -{ - if (s_GL.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - - if (!s_GL.platformDisplay) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - s_GL.maxContextData = 16; // initial size - s_GL.contextData = palAllocate(s_GL.allocator, sizeof(ContextData) * s_GL.maxContextData, 0); - if (!s_GL.maxContextData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_GL.handle = dlopen("libEGL.so", RTLD_LAZY); - if (!s_GL.handle) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // clang-format off - s_GL.eglGetProcAddress = (eglGetProcAddressFn)dlsym( - s_GL.handle, - "eglGetProcAddress"); - - s_GL.eglCreateContext = (eglCreateContextFn)s_GL.eglGetProcAddress( - "eglCreateContext"); - - s_GL.eglDestroyContext = (eglDestroyContextFn)s_GL.eglGetProcAddress( - "eglDestroyContext"); - - s_GL.eglDestroySurface = (eglDestroySurfaceFn)s_GL.eglGetProcAddress( - "eglDestroySurface"); - - s_GL.eglMakeCurrent = (eglMakeCurrentFn)s_GL.eglGetProcAddress( - "eglMakeCurrent"); - - s_GL.eglSwapBuffers = (eglSwapBuffersFn)s_GL.eglGetProcAddress( - "eglSwapBuffers"); - - s_GL.eglSwapInterval = (eglSwapIntervalFn)s_GL.eglGetProcAddress( - "eglSwapInterval"); - - s_GL.eglInitialize = (eglInitializeFn)s_GL.eglGetProcAddress( - "eglInitialize"); - - s_GL.eglTerminate = (eglTerminateFn)s_GL.eglGetProcAddress("eglTerminate"); - - s_GL.eglGetDisplay = (eglGetDisplayFn)s_GL.eglGetProcAddress( - "eglGetDisplay"); - - s_GL.eglCreatePbufferSurface = (eglCreatePbufferSurfaceFn)s_GL.eglGetProcAddress( - "eglCreatePbufferSurface"); - - s_GL.eglChooseConfig = (eglChooseConfigFn)s_GL.eglGetProcAddress( - "eglChooseConfig"); - - s_GL.eglGetConfigAttrib = (eglGetConfigAttribFn)s_GL.eglGetProcAddress( - "eglGetConfigAttrib"); - - s_GL.eglGetError = (eglGetErrorFn)s_GL.eglGetProcAddress("eglGetError"); - s_GL.eglBindAPI = (eglBindAPIFn)s_GL.eglGetProcAddress("eglBindAPI"); - - s_GL.eglQueryString = (eglQueryStringFn)s_GL.eglGetProcAddress( - "eglQueryString"); - - s_GL.eglGetConfigs = (eglGetConfigsFn)s_GL.eglGetProcAddress( - "eglGetConfigs"); - - s_GL.eglCreateWindowSurface = (eglCreateWindowSurfaceFn)s_GL.eglGetProcAddress( - "eglCreateWindowSurface"); - - s_GL.glClearColor = (glClearColorFn)s_GL.eglGetProcAddress("glClearColor"); - s_GL.glClear = (glClearFn)s_GL.eglGetProcAddress("glClear"); - - if (!s_GL.eglBindAPI || - !s_GL.eglChooseConfig || - !s_GL.eglCreateContext || - !s_GL.eglCreatePbufferSurface || - !s_GL.eglDestroyContext || - !s_GL.eglDestroySurface || - !s_GL.eglGetConfigAttrib || - !s_GL.eglGetDisplay || - !s_GL.eglGetError || - !s_GL.eglGetProcAddress || - !s_GL.eglInitialize || - !s_GL.eglMakeCurrent || - !s_GL.eglSwapBuffers || - !s_GL.eglSwapInterval || - !s_GL.eglTerminate || - !s_GL.eglQueryString || - !s_GL.eglGetConfigs || - !s_GL.eglCreateWindowSurface) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - // clang-format on - - // get backend type - const char* session = getenv("XDG_SESSION_TYPE"); - if (session) { - if (strcmp(session, "wayland") == 0) { - s_GL.apiType = EGL_OPENGL_ES_API; - s_GL.apiTypeBit = EGL_OPENGL_ES2_BIT; // default - - } else { - s_GL.apiType = EGL_OPENGL_API; - s_GL.apiTypeBit = EGL_OPENGL_BIT; - } - } - - if (!s_GL.eglBindAPI(s_GL.apiType)) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - EGLDisplay display = s_GL.eglGetDisplay(s_GL.platformDisplay); - EGLDisplay* tmpDisplay = EGL_NO_DISPLAY; - if (display == EGL_NO_DISPLAY) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - if (!s_GL.eglInitialize(display, nullptr, nullptr)) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // use a simple FBConfig - EGLConfig config; - int numConfigs; - EGLint type; - EGLint attribs[] = - {EGL_RENDERABLE_TYPE, s_GL.apiTypeBit, EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_NONE}; - - s_GL.eglChooseConfig(display, attribs, &config, 1, &numConfigs); - if (!config || numConfigs == 0) { - // API bind type might not support puffer - // create a default display and use that - tmpDisplay = s_GL.eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (display == EGL_NO_DISPLAY) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - if (!s_GL.eglInitialize(tmpDisplay, nullptr, nullptr)) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - } else { - // set the tmp display to our display - tmpDisplay = display; - } - - s_GL.eglChooseConfig(tmpDisplay, attribs, &config, 1, &numConfigs); - if (!config) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - s_GL.eglGetConfigAttrib(tmpDisplay, config, EGL_RENDERABLE_TYPE, &type); - if (!(type & s_GL.apiTypeBit)) { - // we must support the required API - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // Since we don't want to create dummy window to get the driver info - // we use EGL_OPENGL_ES2_BIT to create without a window - if (s_GL.apiType == EGL_OPENGL_API) { - if (!(type & EGL_OPENGL_ES2_BIT)) { - // FIXME: create a dummy window if EGL_OPENGL_ES2_BIT - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - EGLSurface surface = EGL_NO_SURFACE; - EGLint pBufferAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; - - surface = s_GL.eglCreatePbufferSurface(tmpDisplay, config, pBufferAttribs); - if (surface == EGL_NO_SURFACE) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // create a dummy context - EGLContext context = EGL_NO_CONTEXT; - if (s_GL.apiType == EGL_OPENGL_API) { - EGLint contextAttrib[] = - {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_CONTEXT_MINOR_VERSION, 1, EGL_NONE}; - context = s_GL.eglCreateContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); - - } else { - EGLint contextAttrib[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - context = s_GL.eglCreateContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); - } - - if (context == EGL_NO_CONTEXT) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - s_GL.eglMakeCurrent(tmpDisplay, surface, surface, context); - s_GL.glGetString = (glGetStringFn)s_GL.eglGetProcAddress("glGetString"); - - const char* version = (const char*)s_GL.glGetString(GL_VERSION); - if (version) { - if (s_GL.apiType == EGL_OPENGL_API) { - sscanf(version, "%d.%d", &s_GL.info.major, &s_GL.info.minor); - } else { - sscanf(version + 10, "%d.%d", &s_GL.info.major, &s_GL.info.minor); - } - } - - const char* renderer = (const char*)s_GL.glGetString(GL_RENDERER); - const char* vendor = (const char*)s_GL.glGetString(GL_VENDOR); - strcpy(s_GL.info.vendor, vendor); - strcpy(s_GL.info.version, version); - strcpy(s_GL.info.graphicsCard, renderer); - - // EGL extensions can be queried without a bound context - // we just do that over here after making the context current - const char* extensions = s_GL.eglQueryString(tmpDisplay, EGL_EXTENSIONS); - if (extensions) { - // color space - if (checkExtension("EGL_KHR_gl_colorspace", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_COLORSPACE_SRGB; - } - - // create context - if (checkExtension("EGL_KHR_create_context", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_CREATE_CONTEXT; - s_GL.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE; - } - - // robustness - if (checkExtension("EGL_EXT_create_context_robustness", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_ROBUSTNESS; - } - - // no error - if (checkExtension("EGL_KHR_create_context_no_error", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_NO_ERROR; - } - - // flush control - if (checkExtension("EGL_KHR_context_flush_control", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; - } - - // swap control - if (checkExtension("EGL_EXT_swap_control", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; - } - - if (checkExtension("EGL_EXT_swap_control_tear", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; - } - } - - // part of the core API - s_GL.info.extensions |= PAL_GL_EXTENSION_MULTISAMPLE; - if (type & EGL_OPENGL_ES_BIT || type & EGL_OPENGL_ES2_BIT) { - s_GL.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; - } - - // check if we support the core swap interval - if (s_GL.eglSwapInterval) { - s_GL.info.extensions |= PAL_GL_EXTENSION_SWAP_CONTROL; - } - - if (s_GL.apiType != EGL_OPENGL_API) { - if (s_GL.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE) { - s_GL.info.extensions &= ~PAL_GL_EXTENSION_CONTEXT_PROFILE; - s_GL.info.extensions &= ~PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; - } - - if (type & EGL_OPENGL_ES3_BIT) { - s_GL.apiTypeBit = EGL_OPENGL_ES3_BIT; - } - } - - s_GL.eglMakeCurrent(tmpDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - s_GL.eglDestroyContext(tmpDisplay, context); - s_GL.eglDestroySurface(tmpDisplay, surface); - - s_GL.allocator = allocator; - s_GL.initialized = PAL_TRUE; - - if (tmpDisplay != display) { - // tmpDisplay is a seperate display - // terminate it - s_GL.eglTerminate(tmpDisplay); - } - - s_GL.display = display; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palShutdownGL() -{ - if (!s_GL.initialized) { - return; - } - - palFree(s_GL.allocator, s_GL.contextData); - if (s_GL.display) { - s_GL.eglTerminate(s_GL.display); - } - - dlclose(s_GL.handle); - s_GL.initialized = PAL_FALSE; -} - -const PalGLInfo* PAL_CALL palGetGLInfo() -{ - if (!s_GL.initialized) { - return nullptr; - } - return &s_GL.info; -} - -PalResult PAL_CALL palEnumerateGLFBConfigs( - PalGLWindow* glWindow, - int32_t* count, - PalGLFBConfig* configs) -{ - if (!s_GL.initialized) { - return PAL_RESULT_GL_NOT_INITIALIZED; - } - - if (!count) { - return PAL_RESULT_NULL_POINTER; - } - - if (count == 0 && configs) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - int32_t configCount = 0; - int32_t maxConfigCount = 0; - - if (configs) { - maxConfigCount = *count; - } - - // get the number of configs and filter the ones for opengl desktop - EGLint numConfigs = 0; - if (!s_GL.eglGetConfigs(s_GL.display, nullptr, 0, &numConfigs)) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - EGLint configSize = sizeof(EGLConfig) * numConfigs; - EGLConfig* eglConfigs = palAllocate(s_GL.allocator, configSize, 0); - if (!eglConfigs) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_GL.eglGetConfigs(s_GL.display, eglConfigs, numConfigs, &numConfigs); - for (int i = 0; i < numConfigs; i++) { - // attributes we care about - EGLint surfaceType = 0, renderable = 0; - EGLint colorType = 0; - - EGLConfig config = eglConfigs[i]; - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_SURFACE_TYPE, &surfaceType); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_RENDERABLE_TYPE, &renderable); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_COLOR_BUFFER_TYPE, &colorType); - - // we need only opengl API configs - if (colorType != EGL_RGB_BUFFER) { - continue; - } - - if (s_GL.apiType == EGL_OPENGL_ES3_BIT) { - // EGL_OPENGL_ES2_BIT - if (!(renderable & EGL_OPENGL_ES2_BIT) && !(renderable & EGL_OPENGL_ES3_BIT)) { - continue; - } - - } else if (s_GL.apiType == EGL_OPENGL_ES2_BIT) { - if (!(renderable & EGL_OPENGL_ES2_BIT)) { - continue; - } - - } else { - if (!(renderable & EGL_OPENGL_BIT)) { - continue; - } - } - - if (!(surfaceType & EGL_WINDOW_BIT)) { - continue; - } - - if (configs && configCount < maxConfigCount) { - // get this only if user supplied an output buffer (PalGLFBConfig*) - PalGLFBConfig* fbConfig = &configs[configCount]; - fbConfig->index = i; - - EGLint redBits, greenBits, blueBits, alphaBits; - EGLint depthBits, stencilBits, samples; - - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_RED_SIZE, &redBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_GREEN_SIZE, &greenBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_BLUE_SIZE, &blueBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_ALPHA_SIZE, &alphaBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_DEPTH_SIZE, &depthBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_STENCIL_SIZE, &stencilBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_SAMPLES, &samples); - if (samples == 0) { - samples = 1; - } - - fbConfig->redBits = redBits; - fbConfig->greenBits = greenBits; - fbConfig->blueBits = blueBits; - fbConfig->alphaBits = alphaBits; - fbConfig->depthBits = depthBits; - fbConfig->stencilBits = stencilBits; - fbConfig->samples = samples; - - // True for EGL_WINDOW_BIT - fbConfig->doubleBuffer = PAL_TRUE; - fbConfig->stereo = PAL_FALSE; - - if (s_GL.info.extensions & PAL_GL_EXTENSION_COLORSPACE_SRGB) { - // since EGL does not have a bit to check SRGB support - // we check if all the color bits are greater than or equal to 8 - if (fbConfig->redBits >= 8 && fbConfig->greenBits >= 8 && fbConfig->blueBits >= 8) { - fbConfig->sRGB = PAL_TRUE; - } - } else { - fbConfig->sRGB = PAL_FALSE; - } - } - configCount++; - } - - palFree(s_GL.allocator, eglConfigs); - if (!configs) { - *count = configCount; - } - - return PAL_RESULT_SUCCESS; -} - -const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( - PalGLFBConfig* configs, - int32_t count, - const PalGLFBConfig* desired) -{ - if (!s_GL.initialized) { - return nullptr; - } - - if (!configs || !desired) { - return nullptr; - } - - if (count == 0) { - return nullptr; - } - - int32_t score = 0; - int32_t bestScore = 0x7FFFFFFF; - PalGLFBConfig* best = nullptr; - for (int32_t i = 0; i < count; i++) { - PalGLFBConfig* tmp = &configs[i]; - - // filter out hard constraints - if (desired->doubleBuffer && !tmp->doubleBuffer) { - continue; - } - - if (desired->stereo && !tmp->stereo) { - continue; - } - - score = 0; - - // score color bits - score += abs(tmp->redBits - desired->redBits); - score += abs(tmp->greenBits - desired->greenBits); - score += abs(tmp->blueBits - desired->blueBits); - score += abs(tmp->alphaBits - desired->alphaBits); - score += abs(tmp->depthBits - desired->depthBits); - score += abs(tmp->stencilBits - desired->stencilBits); - - // score soft constraints - if (desired->samples != tmp->samples) { - score += 1000; - } - - if (desired->sRGB != tmp->sRGB) { - score += 500; - } - - if (score < bestScore) { - bestScore = score; - best = &configs[i]; - } - } - - return best; -} - -// ================================================== -// Context -// ================================================== - -PalResult PAL_CALL palCreateGLContext( - const PalGLContextCreateInfo* info, - PalGLContext** outContext) -{ - if (!s_GL.initialized) { - return PAL_RESULT_GL_NOT_INITIALIZED; - } - - if (!info || !outContext) { - return PAL_RESULT_NULL_POINTER; - } - - if (!info->window || !info->fbConfig) { - return PAL_RESULT_NULL_POINTER; - } - - // check if the window was created with the same display - // the opengl system is using - if (info->window->display != s_GL.platformDisplay) { - return PAL_RESULT_INVALID_GL_WINDOW; - } - - // check support for requested features - if (info->profile != PAL_GL_PROFILE_NONE) { - if (!(s_GL.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE)) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - } - - if (info->forward) { - if (!(s_GL.info.extensions & PAL_GL_EXTENSION_CREATE_CONTEXT)) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - } - - if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { - if (!(s_GL.info.extensions & PAL_GL_EXTENSION_ROBUSTNESS)) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - } - - if (info->noError) { - if (!(s_GL.info.extensions & PAL_GL_EXTENSION_NO_ERROR)) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - } - - if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { - if (!(s_GL.info.extensions & PAL_GL_EXTENSION_FLUSH_CONTROL)) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - } - - // check version - PalBool valid = info->major < s_GL.info.major || - (info->major == s_GL.info.major && info->minor <= s_GL.info.minor); - - if (!valid) { - return PAL_RESULT_INVALID_GL_VERSION; - } - - ContextData* data = getFreeContextData(); - if (!data) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // we need to get the EGL config from the user supplied index - EGLint numConfigs = 0; - if (!s_GL.eglGetConfigs(s_GL.display, nullptr, 0, &numConfigs)) { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - - EGLint configSize = sizeof(EGLConfig) * numConfigs; - EGLConfig* eglConfigs = palAllocate(s_GL.allocator, configSize, 0); - if (!eglConfigs) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_GL.eglGetConfigs(s_GL.display, eglConfigs, numConfigs, &numConfigs); - EGLConfig config = eglConfigs[info->fbConfig->index]; - - EGLContext* share = nullptr; - if (info->shareContext) { - share = (EGLContext)info->shareContext; - } else { - share = EGL_NO_CONTEXT; - } - - int32_t attribs[40]; - int32_t index = 0; - int32_t profile = 0; - int32_t flags = 0; - - // set context attributes - // the first element is the key and the second is the value - if (s_GL.apiType == EGL_OPENGL_API) { - // set version - attribs[index++] = EGL_CONTEXT_MAJOR_VERSION_KHR; // key - attribs[index++] = info->major; // value - - attribs[index++] = EGL_CONTEXT_MINOR_VERSION_KHR; - attribs[index++] = info->minor; - - // set profile mask - if (info->profile != PAL_GL_PROFILE_NONE) { - attribs[index++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; - - if (info->profile == PAL_GL_PROFILE_COMPATIBILITY) { - profile = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; - } else if (info->profile == PAL_GL_PROFILE_CORE) { - profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; - } - - attribs[index++] = info->profile; - } - - // set forward flag - if (info->forward) { - flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; - } - - } else { - attribs[index++] = EGL_CONTEXT_CLIENT_VERSION; - // our configs support EGL_OPENGL_ES2_BIT and EGL_OPENGL_ES3_BIT - attribs[index++] = info->major; - } - - // set debug flag - if (info->debug) { - flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; - } - - // set robustness - if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { - flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; - attribs[index++] = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR; - - if (info->reset == PAL_GL_CONTEXT_RESET_LOSE_CONTEXT) { - attribs[index++] = EGL_LOSE_CONTEXT_ON_RESET_KHR; - - } else if (info->reset == PAL_GL_CONTEXT_RESET_NO_NOTIFICATION) { - attribs[index++] = EGL_NO_RESET_NOTIFICATION_KHR; - } - } - - // set no error - if (info->noError) { - attribs[index++] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR; - attribs[index++] = PAL_TRUE; - } - - // release - if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { - attribs[index++] = EGL_CONTEXT_RELEASE_BEHAVIOR_KHR; - attribs[index++] = EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR; - } - - if (flags) { - attribs[index++] = EGL_CONTEXT_FLAGS_KHR; - attribs[index++] = flags; - } - attribs[index++] = EGL_NONE; - - // create context - EGLContext context = s_GL.eglCreateContext(s_GL.display, config, share, attribs); - if (context == EGL_NO_CONTEXT) { - EGLint error = s_GL.eglGetError(); - if (error == EGL_BAD_CONFIG) { - return PAL_RESULT_INVALID_GL_FBCONFIG; - - } else if (error == EGL_BAD_ATTRIBUTE) { - // we just return invalid version - // it could be invalid profile - return PAL_RESULT_INVALID_GL_VERSION; - - } else { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - // create a window surface - // The only attrib we want is colorspace - EGLint surfaceAttribs[3]; - surfaceAttribs[0] = EGL_GL_COLORSPACE; - if (info->fbConfig->sRGB) { - surfaceAttribs[1] = EGL_GL_COLORSPACE_SRGB_KHR; - } else { - surfaceAttribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; - } - surfaceAttribs[2] = EGL_NONE; - - EGLSurface surface = s_GL.eglCreateWindowSurface( - s_GL.display, - config, - (EGLNativeWindowType)info->window->window, - surfaceAttribs); - - if (surface == EGL_NO_SURFACE) { - EGLint error = s_GL.eglGetError(); - if (error == EGL_BAD_CONFIG) { - return PAL_RESULT_INVALID_GL_FBCONFIG; - - } else { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - // make the context current and swap for the first time - // this will make the window visible - if (s_GL.eglMakeCurrent(s_GL.display, surface, surface, context)) { - s_GL.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - s_GL.glClear(0x00004000); - s_GL.eglSwapBuffers(s_GL.display, surface); - - // revert - s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - - palFree(s_GL.allocator, eglConfigs); - data->context = (PalGLContext*)context; - data->surface = surface; - - *outContext = (PalGLContext*)context; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyGLContext(PalGLContext* context) -{ - if (s_GL.initialized && context) { - ContextData* data = findContextData(context); - if (data) { - // make it not current if it was current - s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - s_GL.eglDestroyContext(s_GL.display, (EGLContext)context); - s_GL.eglDestroySurface(s_GL.display, data->surface); - data->used = PAL_FALSE; - } - } -} - -PalResult PAL_CALL palMakeContextCurrent( - PalGLWindow* glWindow, - PalGLContext* context) -{ - if (!s_GL.initialized) { - return PAL_RESULT_GL_NOT_INITIALIZED; - } - - if ((!glWindow && context) || (glWindow && !context)) { - return PAL_RESULT_NULL_POINTER; - } - - if (context && glWindow) { - ContextData* data = findContextData(context); - if (!data) { - return PAL_RESULT_INVALID_GL_CONTEXT; - } - - EGLint ret; - ret = s_GL.eglMakeCurrent(s_GL.display, data->surface, data->surface, (EGLConfig)context); - if (!ret) { - EGLint error = s_GL.eglGetError(); - if (error == EGL_BAD_CONTEXT) { - return PAL_RESULT_INVALID_GL_CONTEXT; - - } else if (error == EGL_BAD_SURFACE) { - // since we always create a window surface - return PAL_RESULT_INVALID_GL_WINDOW; - - } else { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - } else if (!context && !glWindow) { - s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - - return PAL_RESULT_SUCCESS; -} - -void* PAL_CALL palGLGetProcAddress(const char* name) -{ - if (!s_GL.initialized) { - return nullptr; - } - - return s_GL.eglGetProcAddress(name); -} - -PalResult PAL_CALL palSwapBuffers( - PalGLWindow* glWindow, - PalGLContext* context) -{ - if (!s_GL.initialized) { - return PAL_RESULT_GL_NOT_INITIALIZED; - } - - if (!context || !glWindow) { - return PAL_RESULT_NULL_POINTER; - } - - ContextData* data = findContextData(context); - if (!data) { - return PAL_RESULT_INVALID_GL_CONTEXT; - } - - if (!s_GL.eglSwapBuffers(s_GL.display, data->surface)) { - EGLint error = s_GL.eglGetError(); - if (error == EGL_BAD_CONTEXT) { - return PAL_RESULT_INVALID_GL_CONTEXT; - - } else if (error == EGL_BAD_SURFACE) { - // since we always create a window surface - return PAL_RESULT_INVALID_GL_WINDOW; - - } else { - palSetLastPlatformError(errno); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetSwapInterval(int32_t interval) -{ - if (!s_GL.initialized) { - return PAL_RESULT_GL_NOT_INITIALIZED; - } - - if (!s_GL.eglSwapInterval) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - - s_GL.eglSwapInterval(s_GL.display, interval); - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palGLSetInstance(void* instance) -{ - s_GL.platformDisplay = instance; -} - -const char* PAL_CALL palGLGetBackend() -{ - if (!s_GL.initialized) { - return nullptr; - } - - if (s_GL.apiType == EGL_OPENGL_API) { - return "egl"; - } else { - return "gles"; - } -} diff --git a/src/opengl/pal_opengl_shared.c b/src/opengl/pal_opengl_shared.c new file mode 100644 index 00000000..4f2c4488 --- /dev/null +++ b/src/opengl/pal_opengl_shared.c @@ -0,0 +1,65 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal/pal_opengl.h" +#include + +const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( + PalGLFBConfig* configs, + int32_t count, + const PalGLFBConfig* desired) +{ + if (!configs || !desired) { + return nullptr; + } + + if (count == 0) { + return nullptr; + } + + int32_t score = 0; + int32_t bestScore = 0x7FFFFFFF; + PalGLFBConfig* best = nullptr; + for (int32_t i = 0; i < count; i++) { + PalGLFBConfig* tmp = &configs[i]; + + // filter out hard constraints + if (desired->doubleBuffer && !tmp->doubleBuffer) { + continue; + } + + if (desired->stereo && !tmp->stereo) { + continue; + } + + score = 0; + + // score color bits + score += abs(tmp->redBits - desired->redBits); + score += abs(tmp->greenBits - desired->greenBits); + score += abs(tmp->blueBits - desired->blueBits); + score += abs(tmp->alphaBits - desired->alphaBits); + score += abs(tmp->depthBits - desired->depthBits); + score += abs(tmp->stencilBits - desired->stencilBits); + + // score soft constraints + if (desired->samples != tmp->samples) { + score += 1000; + } + + if (desired->sRGB != tmp->sRGB) { + score += 500; + } + + if (score < bestScore) { + bestScore = score; + best = &configs[i]; + } + } + + return best; +} \ No newline at end of file diff --git a/src/opengl/pal_opengl_win32.c b/src/opengl/pal_opengl_win32.c index d444eb41..20576806 100644 --- a/src/opengl/pal_opengl_win32.c +++ b/src/opengl/pal_opengl_win32.c @@ -966,7 +966,7 @@ PalResult PAL_CALL palMakeContextCurrent( return PAL_RESULT_SUCCESS; } -void* PAL_CALL palGLGetProcAddress(const char* name) +void* PAL_CALL palGetGLProcAddress(const char* name) { if (!s_Wgl.initialized) { return nullptr; diff --git a/src/video/linux/wayland/pal_window_wayland.c b/src/video/linux/wayland/pal_window_wayland.c index 71661ea4..d5cb5909 100644 --- a/src/video/linux/wayland/pal_window_wayland.c +++ b/src/video/linux/wayland/pal_window_wayland.c @@ -13,7 +13,7 @@ #include "pal_shared.h" #include -EGLConfig eglWlBackend(const int fbConfigId) +EGLConfig eglWlBackend(const int fbConfigIndex) { EGLDisplay display = EGL_NO_DISPLAY; display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_Wl.display); @@ -33,7 +33,7 @@ EGLConfig eglWlBackend(const int fbConfigId) } s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); - return eglConfigs[fbConfigId]; + return eglConfigs[fbConfigIndex]; } PalResult wlCreateWindow( @@ -173,7 +173,7 @@ PalResult wlCreateWindow( } // user provided a config id - if (info->fbConfigId) { + if (info->fbConfigIndex) { PalFBConfigBackend backend = info->fbConfigBackend; EGLConfig config = nullptr; @@ -182,7 +182,7 @@ PalResult wlCreateWindow( } if (backend == PAL_CONFIG_BACKEND_EGL) { - config = eglWlBackend(info->fbConfigId); + config = eglWlBackend(info->fbConfigIndex); } else { return palMakeResult( diff --git a/src/video/linux/x11/pal_window_x11.c b/src/video/linux/x11/pal_window_x11.c index 5b2e1056..a7e94fc7 100644 --- a/src/video/linux/x11/pal_window_x11.c +++ b/src/video/linux/x11/pal_window_x11.c @@ -23,11 +23,11 @@ static int xErrorHandler( return 0; } -static XVisualInfo* glxBackend(const int fbConfigId) +static XVisualInfo* glxBackend(const int fbConfigIndex) { int count = 0; GLXFBConfig* configs = s_X11.glxGetFBConfigs(s_X11.display, s_X11.screen, &count); - GLXFBConfig fbConfig = configs[fbConfigId]; + GLXFBConfig fbConfig = configs[fbConfigIndex]; if (!fbConfig) { return nullptr; } @@ -41,7 +41,7 @@ static XVisualInfo* glxBackend(const int fbConfigId) return visualInfo; } -static XVisualInfo* eglXBackend(int fbConfigId) +static XVisualInfo* eglXBackend(int fbConfigIndex) { EGLDisplay display = EGL_NO_DISPLAY; display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_X11.display); @@ -61,7 +61,7 @@ static XVisualInfo* eglXBackend(int fbConfigId) } s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); - EGLConfig config = eglConfigs[fbConfigId]; + EGLConfig config = eglConfigs[fbConfigIndex]; // we get a visual info from the config EGLint visualID; @@ -107,7 +107,7 @@ PalResult xCreateWindow( unsigned long borderPixel = 0; // user provided a config id - if (info->fbConfigId) { + if (info->fbConfigIndex) { PalFBConfigBackend backend = info->fbConfigBackend; XVisualInfo* visualInfo = nullptr; @@ -116,10 +116,10 @@ PalResult xCreateWindow( } if (info->fbConfigBackend == PAL_CONFIG_BACKEND_GLX) { - visualInfo = glxBackend(info->fbConfigId); + visualInfo = glxBackend(info->fbConfigIndex); } else if (info->fbConfigBackend == PAL_CONFIG_BACKEND_EGL) { - visualInfo = eglXBackend(info->fbConfigId); + visualInfo = eglXBackend(info->fbConfigIndex); } else { return palMakeResult( diff --git a/src/video/win32/pal_window_win32.c b/src/video/win32/pal_window_win32.c index cac8a2c3..2ff60611 100644 --- a/src/video/win32/pal_window_win32.c +++ b/src/video/win32/pal_window_win32.c @@ -171,7 +171,7 @@ PalResult PAL_CALL palCreateWindow( } // set the pixel format is set - if (info->fbConfigId) { + if (info->fbConfigIndex) { // clang-format off if (info->fbConfigBackend == PAL_CONFIG_BACKEND_EGL || info->fbConfigBackend == PAL_CONFIG_BACKEND_GLX) { @@ -189,7 +189,7 @@ PalResult PAL_CALL palCreateWindow( PIXELFORMATDESCRIPTOR pfd; if (!s_Video.describePixelFormat( hdc, - info->fbConfigId, + info->fbConfigIndex, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { return palMakeResult( diff --git a/tests/opengl/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c index f8a1a92b..c141182f 100644 --- a/tests/opengl/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -91,9 +91,8 @@ static void* PAL_CALL rendererWorkder(void* arg) // make the context current on the renderer thread result = palMakeContextCurrent(&shared->window, shared->context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to make opengl context current: %s", error); - return nullptr; + logResult(result, "Failed to make opengl context current"); + return PAL_FALSE; } // load function procs @@ -107,16 +106,16 @@ static void* PAL_CALL rendererWorkder(void* arg) glGetErrorFn glGetError; glViewportFn glViewport; - glClearColor = (PFNGLCLEARCOLORPROC)palGLGetProcAddress("glClearColor"); - glClear = (PFNGLCLEARPROC)palGLGetProcAddress("glClear"); - glBegin = (glBeginFn)palGLGetProcAddress("glBegin"); - glEnd = (glEndFn)palGLGetProcAddress("glEnd"); - glVertex2f = (glVertex2fFn)palGLGetProcAddress("glVertex2f"); - glColor3f = (glColor3fFn)palGLGetProcAddress("glColor3f"); - glFlush = (glFlushFn)palGLGetProcAddress("glFlush"); + glClearColor = (PFNGLCLEARCOLORPROC)palGetGLProcAddress("glClearColor"); + glClear = (PFNGLCLEARPROC)palGetGLProcAddress("glClear"); + glBegin = (glBeginFn)palGetGLProcAddress("glBegin"); + glEnd = (glEndFn)palGetGLProcAddress("glEnd"); + glVertex2f = (glVertex2fFn)palGetGLProcAddress("glVertex2f"); + glColor3f = (glColor3fFn)palGetGLProcAddress("glColor3f"); + glFlush = (glFlushFn)palGetGLProcAddress("glFlush"); - glGetError = (glGetErrorFn)palGLGetProcAddress("glGetError"); - glViewport = (glViewportFn)palGLGetProcAddress("glViewport"); + glGetError = (glGetErrorFn)palGetGLProcAddress("glGetError"); + glViewport = (glViewportFn)palGetGLProcAddress("glViewport"); // set clear color glViewport(0, 0, 640, 480); @@ -162,8 +161,7 @@ static void* PAL_CALL rendererWorkder(void* arg) // swap buffers result = palSwapBuffers(&shared->window, shared->context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to swap buffers from: %s", error); + logResult(result, "Failed to swap buffers"); return nullptr; } } @@ -174,8 +172,6 @@ static void* PAL_CALL rendererWorkder(void* arg) PalBool multiThreadOpenGlTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - PalResult result; - PalThread* eventDriverThread = nullptr; SharedState* shared = nullptr; shared = palAllocate(nullptr, sizeof(SharedState), 0); @@ -188,10 +184,11 @@ PalBool multiThreadOpenGlTest() PalThreadCreateInfo threadCreateInfo = {0}; threadCreateInfo.entry = eventDriverWorker; threadCreateInfo.arg = (void*)shared; - result = palCreateThread(&threadCreateInfo, &eventDriverThread); + + PalThread* eventDriverThread = nullptr; + PalResult result = palCreateThread(&threadCreateInfo, &eventDriverThread); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create thread: %s", error); + logResult(result, "Failed to create thread"); return PAL_FALSE; } @@ -208,31 +205,41 @@ PalBool multiThreadOpenGlTest() // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must // be valid till the video system is shutdown - result = palInitVideo(nullptr, shared->videoEventDriver); + result = palInitVideo(nullptr, shared->videoEventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; } - // get the instance or display handle and pass it to the opengl system - // This must be called before the opengl system is initialized - palGLSetInstance(palGetInstance()); + // check if opengl API is supported or fallback to opengl es + PalGLAPI openglAPI; + void* videoInstance = palGetInstance(); + const PalBool* supportedAPIs = palGetSupportedGLAPIs(videoInstance); + if (supportedAPIs) { + if (supportedAPIs[PAL_GL_API_OPENGL]) { + openglAPI = PAL_GL_API_OPENGL; + + } else { + openglAPI = PAL_GL_API_OPENGL_ES; + } + + } else { + palLog(nullptr, "Failed to get supported opengl apis"); + return PAL_FALSE; + } - // initialize video and opengl systems - // we need to initialize these on the main thread - result = palInitGL(nullptr); + // initialize the opengl system. This loads the icd. + result = palInitGL(openglAPI, videoInstance, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize opengl: %s", error); + logResult(result, "Failed to initialize opengl"); return PAL_FALSE; } // get all FBConfigs and select one int32_t fbCount = 0; - result = palEnumerateGLFBConfigs(nullptr, &fbCount, nullptr); + result = palEnumerateGLFBConfigs(&fbCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query GL FBConfigs: %s", error); + logResult(result, "Failed to query GL FBConfigs"); return PAL_FALSE; } @@ -248,11 +255,9 @@ PalBool multiThreadOpenGlTest() return PAL_FALSE; } - result = palEnumerateGLFBConfigs(nullptr, &fbCount, fbConfigs); + result = palEnumerateGLFBConfigs(&fbCount, fbConfigs); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query GL FBConfigs: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to query GL FBConfigs"); return PAL_FALSE; } @@ -273,36 +278,8 @@ PalBool multiThreadOpenGlTest() const PalGLFBConfig* closest = nullptr; closest = palGetClosestGLFBConfig(fbConfigs, fbCount, &desired); - // tell the video system to use our closest FBConfig - // to create the windows - result = palSetFBConfig(closest->index, PAL_CONFIG_BACKEND_PAL_OPENGL); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set FBConfig: %s", error); - return PAL_FALSE; - } - - // if not using pal_opengl with pal_video - // we get the backend string from the opengl system and - // get the backend from it - // Possible values are `wgl`, `glx`, `gles`, `egl`. - // PalFBConfigBackend backend; - // const char* glBackendString = palGLGetBackend(); - // if (strcmp(glBackendString, "wgl") == 0) { - // backend = PAL_CONFIG_BACKEND_WGL; - - // } else if (strcmp(glBackendString, "glx") == 0) { - // backend = PAL_CONFIG_BACKEND_GLX; - - // } else if (strcmp(glBackendString, "gles") == 0) { - // backend = PAL_CONFIG_BACKEND_GLES; - - // } else if (strcmp(glBackendString, "egl") == 0) { - // backend = PAL_CONFIG_BACKEND_EGL; - // } - + // all windows also needs to be created on the main thread - PalWindow* window = nullptr; PalWindowCreateInfo windowCreateInfo = {0}; windowCreateInfo.width = 640; windowCreateInfo.height = 480; @@ -318,6 +295,12 @@ PalBool multiThreadOpenGlTest() windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } + // set the backend and the fbConfig. We use PAL_CONFIG_BACKEND_PAL_OPENGL + // because we are using both pal_video and pal_opengl + windowCreateInfo.fbConfigBackend = PAL_CONFIG_BACKEND_PAL_OPENGL; + windowCreateInfo.fbConfigIndex = closest->index; + + PalWindow* window = nullptr; result = palCreateWindow(&windowCreateInfo, &window); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window"); @@ -367,9 +350,7 @@ PalBool multiThreadOpenGlTest() result = palCreateGLContext(&contextCreateInfo, &shared->context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create opengl context: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to create opengl context"); return PAL_FALSE; } @@ -384,8 +365,7 @@ PalBool multiThreadOpenGlTest() threadCreateInfo.arg = (void*)shared; result = palCreateThread(&threadCreateInfo, &rendererThread); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create thread: %s", error); + logResult(result, "Failed to create thread"); return PAL_FALSE; } diff --git a/tests/opengl/opengl_context_test.c b/tests/opengl/opengl_context_test.c index 043c26aa..72b8e0da 100644 --- a/tests/opengl/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -17,18 +17,17 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(uint32_t mask); // use GL typedefs PalBool openglContextTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - PalResult result; - PalEventDriver* eventDriver = nullptr; - PalEventDriverCreateInfo eventDriverCreateInfo = {0}; - + // fill the event driver create info + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator eventDriverCreateInfo.callback = nullptr; // for callback dispatch eventDriverCreateInfo.queue = nullptr; // default queue eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -43,31 +42,35 @@ PalBool openglContextTest() return PAL_FALSE; } - // get the instance or display handle and pass it to the opengl system - // This must be called before the opengl system is initialized - palGLSetInstance(palGetInstance()); + // check if opengl API is supported or fallback to opengl es + PalGLAPI openglAPI; + void* videoInstance = palGetInstance(); + const PalBool* supportedAPIs = palGetSupportedGLAPIs(videoInstance); + if (supportedAPIs) { + if (supportedAPIs[PAL_GL_API_OPENGL]) { + openglAPI = PAL_GL_API_OPENGL; - // initialize the opengl system - result = palInitGL(nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize opengl: %s", error); + } else { + openglAPI = PAL_GL_API_OPENGL_ES; + } + + } else { + palLog(nullptr, "Failed to get supported opengl apis"); return PAL_FALSE; } - PalWindow* window = nullptr; - PalGLContext* context = nullptr; - PalWindowCreateInfo createInfo = {0}; - PalGLContextCreateInfo contextCreateInfo = {0}; - int32_t fbCount = 0; - PalBool running = PAL_FALSE; - + // initialize the opengl system. This loads the icd. + result = palInitGL(openglAPI, videoInstance, nullptr); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to initialize opengl"); + return PAL_FALSE; + } + // enumerate supported opengl framebuffer configs - // glWindow must be nullptr - result = palEnumerateGLFBConfigs(nullptr, &fbCount, nullptr); + int32_t fbCount = 0; + result = palEnumerateGLFBConfigs(&fbCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query GL FBConfigs: %s", error); + logResult(result, "Failed to query GL FBConfigs"); return PAL_FALSE; } @@ -85,12 +88,9 @@ PalBool openglContextTest() } // enumerate supported opengl framebuffer configs - // glWindow must be nullptr - result = palEnumerateGLFBConfigs(nullptr, &fbCount, fbConfigs); + result = palEnumerateGLFBConfigs(&fbCount, fbConfigs); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query GL FBConfigs: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to query GL FBConfigs"); return PAL_FALSE; } @@ -129,40 +129,7 @@ PalBool openglContextTest() palLog(nullptr, " sRGB: %s", g_BoolsToSting[closest->sRGB]); palLog(nullptr, ""); - // set the FBConfig that will be used by PAL video system - // to create windows. this must be set before creating a window - // for this example, we set the closest we desired. - // If pal_opengl and pal_video will be used together, - // then its recommended to use PAL_CONFIG_BACKEND_PAL_OPENGL - - // NOTE: If PAL video system will not be used, - // users need to call the direct OS call to achieve this. - result = palSetFBConfig(closest->index, PAL_CONFIG_BACKEND_PAL_OPENGL); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set GL FBConfig: %s", error); - return PAL_FALSE; - } - - // if not using pal_opengl with pal_video - // we get the backend string from the opengl system and - // get the backend from it - // Possible values are `wgl`, `glx`, `gles`, `egl`. - // PalFBConfigBackend backend; - // const char* glBackendString = palGLGetBackend(); - // if (strcmp(glBackendString, "wgl") == 0) { - // backend = PAL_CONFIG_BACKEND_WGL; - - // } else if (strcmp(glBackendString, "glx") == 0) { - // backend = PAL_CONFIG_BACKEND_GLX; - - // } else if (strcmp(glBackendString, "gles") == 0) { - // backend = PAL_CONFIG_BACKEND_GLES; - - // } else if (strcmp(glBackendString, "egl") == 0) { - // backend = PAL_CONFIG_BACKEND_EGL; - // } - + PalWindowCreateInfo createInfo = {0}; createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; @@ -178,7 +145,13 @@ PalBool openglContextTest() createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } + // set the backend and the fbConfig. We use PAL_CONFIG_BACKEND_PAL_OPENGL + // because we are using both pal_video and pal_opengl + createInfo.fbConfigBackend = PAL_CONFIG_BACKEND_PAL_OPENGL; + createInfo.fbConfigIndex = closest->index; + // create the window with the create info struct + PalWindow* window = nullptr; result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window"); @@ -216,6 +189,7 @@ PalBool openglContextTest() const PalGLInfo* info = palGetGLInfo(); // fill the context create info with the closest FBConfig + PalGLContextCreateInfo contextCreateInfo = {0}; contextCreateInfo.debug = PAL_TRUE; // debug context contextCreateInfo.fbConfig = closest; // we use the closest to what we want contextCreateInfo.major = info->major; // context major @@ -240,20 +214,17 @@ PalBool openglContextTest() } // create the opengl context with the context create info + PalGLContext* context = nullptr; result = palCreateGLContext(&contextCreateInfo, &context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create opengl context: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to create opengl context"); return PAL_FALSE; } // make the context current and optionally set vsync if supported result = palMakeContextCurrent(&glWindow, context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to make opengl context current: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to make opengl context current"); return PAL_FALSE; } @@ -265,13 +236,13 @@ PalBool openglContextTest() // load function procs PFNGLCLEARCOLORPROC glClearColor = nullptr; PFNGLCLEARPROC glClear = nullptr; - glClearColor = (PFNGLCLEARCOLORPROC)palGLGetProcAddress("glClearColor"); - glClear = (PFNGLCLEARPROC)palGLGetProcAddress("glClear"); + glClearColor = (PFNGLCLEARCOLORPROC)palGetGLProcAddress("glClearColor"); + glClear = (PFNGLCLEARPROC)palGetGLProcAddress("glClear"); // set clear color glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - running = PAL_TRUE; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -301,9 +272,7 @@ PalBool openglContextTest() // swap buffers result = palSwapBuffers(&glWindow, context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to swap buffers: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to swap buffers"); return PAL_FALSE; } } diff --git a/tests/opengl/opengl_fbconfig_test.c b/tests/opengl/opengl_fbconfig_test.c index 4f4c9010..68e96048 100644 --- a/tests/opengl/opengl_fbconfig_test.c +++ b/tests/opengl/opengl_fbconfig_test.c @@ -14,24 +14,35 @@ PalBool openglFBConfigTest() return PAL_FALSE; } - // get the instance or display handle and pass it to the opengl system - // This must be called before the opengl system is initialized - palGLSetInstance(palGetInstance()); + // check if opengl API is supported or fallback to opengl es + PalGLAPI openglAPI; + void* videoInstance = palGetInstance(); + const PalBool* supportedAPIs = palGetSupportedGLAPIs(videoInstance); + if (supportedAPIs) { + if (supportedAPIs[PAL_GL_API_OPENGL]) { + openglAPI = PAL_GL_API_OPENGL; + + } else { + openglAPI = PAL_GL_API_OPENGL_ES; + } + + } else { + palLog(nullptr, "Failed to get supported opengl apis"); + return PAL_FALSE; + } - // initialize the opengl system - result = palInitGL(nullptr); + // initialize the opengl system. This loads the icd. + result = palInitGL(openglAPI, videoInstance, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize opengl: %s", error); + logResult(result, "Failed to initialize opengl"); return PAL_FALSE; } // enumerate supported opengl framebuffer configs int32_t fbCount = 0; - result = palEnumerateGLFBConfigs(nullptr, &fbCount, nullptr); + result = palEnumerateGLFBConfigs(&fbCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query GL FBConfigs: %s", error); + logResult(result, "Failed to query GL FBConfigs"); return PAL_FALSE; } @@ -49,11 +60,9 @@ PalBool openglFBConfigTest() } // enumerate supported opengl framebuffer configs - result = palEnumerateGLFBConfigs(nullptr, &fbCount, fbConfigs); + result = palEnumerateGLFBConfigs(&fbCount, fbConfigs); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query GL FBConfigs: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to query GL FBConfigs"); return PAL_FALSE; } diff --git a/tests/opengl/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c index 681d3c73..4faaba95 100644 --- a/tests/opengl/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -17,18 +17,17 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(uint32_t mask); // use GL typedefs PalBool openglMultiContextTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - PalResult result; - PalEventDriver* eventDriver = nullptr; - PalEventDriverCreateInfo eventDriverCreateInfo = {0}; // fill the event driver create info + PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator eventDriverCreateInfo.callback = nullptr; // for callback dispatch eventDriverCreateInfo.queue = nullptr; // default queue eventDriverCreateInfo.userData = nullptr; // null // create the event driver - result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); + PalEventDriver* eventDriver = nullptr; + PalResult result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return PAL_FALSE; @@ -43,31 +42,35 @@ PalBool openglMultiContextTest() return PAL_FALSE; } - // get the instance or display handle and pass it to the opengl system - // This must be called before the opengl system is initialized - palGLSetInstance(palGetInstance()); + // check if opengl API is supported or fallback to opengl es + PalGLAPI openglAPI; + void* videoInstance = palGetInstance(); + const PalBool* supportedAPIs = palGetSupportedGLAPIs(videoInstance); + if (supportedAPIs) { + if (supportedAPIs[PAL_GL_API_OPENGL]) { + openglAPI = PAL_GL_API_OPENGL; - // initialize the opengl system - result = palInitGL(nullptr); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize opengl: %s", error); + } else { + openglAPI = PAL_GL_API_OPENGL_ES; + } + + } else { + palLog(nullptr, "Failed to get supported opengl apis"); return PAL_FALSE; } - PalWindow* window = nullptr; - PalGLContext* context = nullptr; - PalWindowCreateInfo createInfo = {0}; - PalGLContextCreateInfo contextCreateInfo = {0}; - int32_t fbCount = 0; - PalBool running = PAL_FALSE; - + // initialize the opengl system. This loads the icd. + result = palInitGL(openglAPI, videoInstance, nullptr); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to initialize opengl"); + return PAL_FALSE; + } + // enumerate supported opengl framebuffer configs - // glWindow must be nullptr - result = palEnumerateGLFBConfigs(nullptr, &fbCount, nullptr); + int32_t fbCount = 0; + result = palEnumerateGLFBConfigs(&fbCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query GL FBConfigs: %s", error); + logResult(result, "Failed to query GL FBConfigs"); return PAL_FALSE; } @@ -85,12 +88,9 @@ PalBool openglMultiContextTest() } // enumerate supported opengl framebuffer configs - // glWindow must be nullptr - result = palEnumerateGLFBConfigs(nullptr, &fbCount, fbConfigs); + result = palEnumerateGLFBConfigs(&fbCount, fbConfigs); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to query GL FBConfigs: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to query GL FBConfigs"); return PAL_FALSE; } @@ -129,40 +129,7 @@ PalBool openglMultiContextTest() palLog(nullptr, " sRGB: %s", g_BoolsToSting[closest->sRGB]); palLog(nullptr, ""); - // set the FBConfig that will be used by PAL video system - // to create windows. this must be set before creating a window - // for this example, we set the closest we desired. - // If pal_opengl and pal_video will be used together, - // then its recommended to use PAL_CONFIG_BACKEND_PAL_OPENGL - - // NOTE: If PAL video system will not be used, - // users need to call the direct OS call to achieve this. - result = palSetFBConfig(closest->index, PAL_CONFIG_BACKEND_PAL_OPENGL); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set GL FBConfig: %s", error); - return PAL_FALSE; - } - - // if not using pal_opengl with pal_video - // we get the backend string from the opengl system and - // get the backend from it - // Possible values are `wgl`, `glx`, `gles`, `egl`. - // PalFBConfigBackend backend; - // const char* glBackendString = palGLGetBackend(); - // if (strcmp(glBackendString, "wgl") == 0) { - // backend = PAL_CONFIG_BACKEND_WGL; - - // } else if (strcmp(glBackendString, "glx") == 0) { - // backend = PAL_CONFIG_BACKEND_GLX; - - // } else if (strcmp(glBackendString, "gles") == 0) { - // backend = PAL_CONFIG_BACKEND_GLES; - - // } else if (strcmp(glBackendString, "egl") == 0) { - // backend = PAL_CONFIG_BACKEND_EGL; - // } - + PalWindowCreateInfo createInfo = {0}; createInfo.monitor = nullptr; // use default monitor createInfo.height = 480; createInfo.width = 640; @@ -178,7 +145,13 @@ PalBool openglMultiContextTest() createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } + // set the backend and the fbConfig. We use PAL_CONFIG_BACKEND_PAL_OPENGL + // because we are using both pal_video and pal_opengl + createInfo.fbConfigBackend = PAL_CONFIG_BACKEND_PAL_OPENGL; + createInfo.fbConfigIndex = closest->index; + // create the window with the create info struct + PalWindow* window = nullptr; result = palCreateWindow(&createInfo, &window); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window"); @@ -216,6 +189,7 @@ PalBool openglMultiContextTest() const PalGLInfo* info = palGetGLInfo(); // fill the context create info with the closest FBConfig + PalGLContextCreateInfo contextCreateInfo = {0}; contextCreateInfo.debug = PAL_TRUE; // debug context contextCreateInfo.fbConfig = closest; // we use the closest to what we want contextCreateInfo.major = info->major; // context major @@ -240,20 +214,17 @@ PalBool openglMultiContextTest() } // create the opengl context with the context create info + PalGLContext* context = nullptr; result = palCreateGLContext(&contextCreateInfo, &context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create opengl context: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to create opengl context"); return PAL_FALSE; } // make the context current and optionally set vsync if supported result = palMakeContextCurrent(&glWindow, context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to make opengl context current: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to make opengl context current"); return PAL_FALSE; } @@ -265,13 +236,13 @@ PalBool openglMultiContextTest() // load function procs PFNGLCLEARCOLORPROC glClearColor = nullptr; PFNGLCLEARPROC glClear = nullptr; - glClearColor = (PFNGLCLEARCOLORPROC)palGLGetProcAddress("glClearColor"); - glClear = (PFNGLCLEARPROC)palGLGetProcAddress("glClear"); + glClearColor = (PFNGLCLEARCOLORPROC)palGetGLProcAddress("glClearColor"); + glClear = (PFNGLCLEARPROC)palGetGLProcAddress("glClear"); // set clear color glClearColor(0.2f, 0.2f, 0.2f, 1.0f); - running = PAL_TRUE; + PalBool running = PAL_TRUE; while (running) { // update the video system to push video events palUpdateVideo(); @@ -301,9 +272,7 @@ PalBool openglMultiContextTest() // swap buffers result = palSwapBuffers(&glWindow, context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to swap buffers: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to swap buffers"); return PAL_FALSE; } } @@ -316,18 +285,14 @@ PalBool openglMultiContextTest() context = nullptr; result = palCreateGLContext(&contextCreateInfo, &context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create opengl context: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to create opengl context"); return PAL_FALSE; } // make the context current on this thread result = palMakeContextCurrent(&glWindow, context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to make opengl context current: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to make opengl context current"); return PAL_FALSE; } @@ -358,9 +323,7 @@ PalBool openglMultiContextTest() glClear(0x00004000); // GL_COLOR_BUFFER_BIT result = palSwapBuffers(&glWindow, context); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to swap buffers: %s", error); - palFree(nullptr, fbConfigs); + logResult(result, "Failed to swap buffers"); return PAL_FALSE; } } diff --git a/tests/opengl/opengl_test.c b/tests/opengl/opengl_test.c index 26336435..cf0c0411 100644 --- a/tests/opengl/opengl_test.c +++ b/tests/opengl/opengl_test.c @@ -5,22 +5,34 @@ PalBool openglTest() { - // initialize the video system and create a window + // initialize the video system PalResult result = palInitVideo(nullptr, nullptr, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize video"); return PAL_FALSE; } - // get the instance or display handle and pass it to the opengl system - // This must be called before the opengl system is initialized - palGLSetInstance(palGetInstance()); + // check if opengl API is supported or fallback to opengl es + PalGLAPI openglAPI; + void* videoInstance = palGetInstance(); + const PalBool* supportedAPIs = palGetSupportedGLAPIs(videoInstance); + if (supportedAPIs) { + if (supportedAPIs[PAL_GL_API_OPENGL]) { + openglAPI = PAL_GL_API_OPENGL; + + } else { + openglAPI = PAL_GL_API_OPENGL_ES; + } + + } else { + palLog(nullptr, "Failed to get supported opengl apis"); + return PAL_FALSE; + } // initialize the opengl system. This loads the icd. - result = palInitGL(nullptr); + result = palInitGL(openglAPI, videoInstance, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize opengl: %s", error); + logResult(result, "Failed to initialize opengl"); return PAL_FALSE; } diff --git a/tests/tests_main.c b/tests/tests_main.c index 40cb31d5..3d62e53c 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -39,7 +39,7 @@ int main(int argc, char** argv) // registerTest(attachWindowTest, "Attach Window Test"); // registerTest(charEventTest, "Char Event Test"); // registerTest(nativeIntegrationTest, "Native Integration Test"); - registerTest(nativeInstanceTest, "Native Instance Test"); + // registerTest(nativeInstanceTest, "Native Instance Test"); // registerTest(customDecorationTest, "Custom Decoration Test"); #endif // PAL_HAS_VIDEO_MODULE @@ -53,7 +53,7 @@ int main(int argc, char** argv) #endif // PAL_HAS_OPENGL_MODULE #if PAL_HAS_OPENGL_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 && PAL_HAS_THREAD_MODULE == 1 - // registerTest(multiThreadOpenGlTest, "Multi Thread Opengl Test"); + registerTest(multiThreadOpenGlTest, "Multi Thread Opengl Test"); #endif #if PAL_HAS_GRAPHICS_MODULE == 1 diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index 65af43d7..4269d258 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -349,7 +349,7 @@ static void windowDump() uint32_t yOffset4 = offsetof(PalWindowCreateInfo, appName); uint32_t yOffset5 = offsetof(PalWindowCreateInfo, instanceName); uint32_t yOffset6 = offsetof(PalWindowCreateInfo, fbConfigBackend); - uint32_t yOffset7 = offsetof(PalWindowCreateInfo, fbConfigId); + uint32_t yOffset7 = offsetof(PalWindowCreateInfo, fbConfigIndex); uint32_t yOffset8 = offsetof(PalWindowCreateInfo, width); uint32_t yOffset9 = offsetof(PalWindowCreateInfo, height); uint32_t yOffset10 = offsetof(PalWindowCreateInfo, show); @@ -394,7 +394,7 @@ static void windowDump() palLog(nullptr, "appName @ %u %u", xOffset4, yOffset4); palLog(nullptr, "instanceName @ %u %u", xOffset5, yOffset5); palLog(nullptr, "fbConfigBackend @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "fbConfigId @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "fbConfigIndex @ %u %u", xOffset7, yOffset7); palLog(nullptr, "width @ %u %u", xOffset8, yOffset8); palLog(nullptr, "height @ %u %u", xOffset9, yOffset9); palLog(nullptr, "show @ %u %u", xOffset10, yOffset10); From a7690e38df889e5ad6c0b7ff29a2a17ae0560fff Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 19 Jun 2026 00:55:35 +0000 Subject: [PATCH 281/372] test opengl rewrite x11 --- src/video/linux/x11/pal_window_x11.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/video/linux/x11/pal_window_x11.c b/src/video/linux/x11/pal_window_x11.c index a7e94fc7..3578dc0e 100644 --- a/src/video/linux/x11/pal_window_x11.c +++ b/src/video/linux/x11/pal_window_x11.c @@ -112,13 +112,10 @@ PalResult xCreateWindow( XVisualInfo* visualInfo = nullptr; if (backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { - backend = PAL_CONFIG_BACKEND_GLX; + backend = PAL_CONFIG_BACKEND_EGL; } - if (info->fbConfigBackend == PAL_CONFIG_BACKEND_GLX) { - visualInfo = glxBackend(info->fbConfigIndex); - - } else if (info->fbConfigBackend == PAL_CONFIG_BACKEND_EGL) { + if (backend == PAL_CONFIG_BACKEND_EGL) { visualInfo = eglXBackend(info->fbConfigIndex); } else { From 89423203567ce6a219b1200b801f793de418aa07 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 19 Jun 2026 10:19:40 +0000 Subject: [PATCH 282/372] test opengl rewrite win32 --- CHANGELOG.md | 2 +- src/opengl/linux/pal_context_linux.c | 52 ++ src/opengl/linux/pal_opengl_linux.c | 81 +- src/opengl/pal_opengl_shared.c | 29 + src/opengl/pal_opengl_shared.h | 17 + src/opengl/pal_opengl_win32.c | 1040 ----------------------- src/opengl/win32/pal_context_win32.c | 336 ++++++++ src/opengl/win32/pal_opengl_win32.c | 543 ++++++++++++ src/opengl/win32/pal_opengl_win32.h | 187 ++++ src/thread/win32/pal_thread_win32.c | 11 +- src/video/win32/pal_window_win32.c | 2 +- tests/opengl/multi_thread_opengl_test.c | 21 +- tests/tests_main.c | 3 +- 13 files changed, 1188 insertions(+), 1136 deletions(-) create mode 100644 src/opengl/pal_opengl_shared.h delete mode 100644 src/opengl/pal_opengl_win32.c create mode 100644 src/opengl/win32/pal_context_win32.c create mode 100644 src/opengl/win32/pal_opengl_win32.c create mode 100644 src/opengl/win32/pal_opengl_win32.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 4917d014..e90c55ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -156,7 +156,7 @@ palJoinThread(thread, &retval); - **Opengl:** **palEnumerateGLFBConfigs()** now does not take glWindow parameter anymore. - **Opengl:** **palInitGL()** now takes an api and instance parameter. - **Opengl:** rename **PalGLRelease** to **PalGLReleaseBehavior**. -- **Opengl:** rename **palGetGLProcAddress()** to **palGetGLProcAddress()**. +- **Opengl:** rename **palGLGetProcAddress()** to **palGetGLProcAddress()**. - **Video:** **palGetWindowHandleInfo()** now takes an info parameter. - **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. diff --git a/src/opengl/linux/pal_context_linux.c b/src/opengl/linux/pal_context_linux.c index bcfd89bf..497b8cf0 100644 --- a/src/opengl/linux/pal_context_linux.c +++ b/src/opengl/linux/pal_context_linux.c @@ -365,4 +365,56 @@ PalResult PAL_CALL palMakeContextCurrent( return PAL_RESULT_SUCCESS; } +PalResult PAL_CALL palSwapBuffers( + PalGLWindow* glWindow, + PalGLContext* context) +{ + if (!s_GL.initialized) { + palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!context || !glWindow) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + ContextData* data = findContextData(context); + if (!data) { + palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + + if (!s_GL.eglSwapBuffers(s_GL.display, data->surface)) { + EGLint error = s_GL.eglGetError(); + if (error == EGL_BAD_CONTEXT) { + palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + + } else if (error == EGL_BAD_SURFACE) { + // since we always create a window surface + palMakeResult( + PAL_RESULT_INVALID_HANDLE, + PAL_RESULT_SOURCE_LINUX, + errno); + + } else { + palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_LINUX, + errno); + } + } + + return PAL_RESULT_SUCCESS; +} + #endif // __linux__ \ No newline at end of file diff --git a/src/opengl/linux/pal_opengl_linux.c b/src/opengl/linux/pal_opengl_linux.c index ea511029..49bccaea 100644 --- a/src/opengl/linux/pal_opengl_linux.c +++ b/src/opengl/linux/pal_opengl_linux.c @@ -9,6 +9,7 @@ #define _GNU_SOURCE #define _POSIX_C_SOURCE 200112L #include "pal_opengl_linux.h" +#include "opengl/pal_opengl_shared.h" #include "pal_shared.h" #include @@ -21,34 +22,6 @@ GLLinux s_GL = {0}; static PalBool s_SupportedAPIs[2] = {0}; -static inline PalBool checkString( - const char* string, - const char* strings) -{ - const char* start = strings; - size_t stringLen = strlen(string); - - for (;;) { - const char* where = nullptr; - const char* terminator = nullptr; - - where = strstr(start, string); - if (!where) { - return PAL_FALSE; - } - - // the string was found, we find the terminator by adding the sizeof the strings - terminator = where + stringLen; - if (where == start || *(where - 1) == ' ') { - if (*terminator == ' ' || *terminator == '\0') { - return PAL_TRUE; - } - } - - start = terminator; - } -} - ContextData* getFreeContextData() { for (int i = 0; i < s_GL.maxContextData; ++i) { @@ -602,58 +575,6 @@ void* PAL_CALL palGetGLProcAddress(const char* name) return s_GL.eglGetProcAddress(name); } -PalResult PAL_CALL palSwapBuffers( - PalGLWindow* glWindow, - PalGLContext* context) -{ - if (!s_GL.initialized) { - palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!context || !glWindow) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - ContextData* data = findContextData(context); - if (!data) { - palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!s_GL.eglSwapBuffers(s_GL.display, data->surface)) { - EGLint error = s_GL.eglGetError(); - if (error == EGL_BAD_CONTEXT) { - palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - - } else if (error == EGL_BAD_SURFACE) { - // since we always create a window surface - palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - - } else { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } - - return PAL_RESULT_SUCCESS; -} - PalResult PAL_CALL palSetSwapInterval(int32_t interval) { if (!s_GL.initialized) { diff --git a/src/opengl/pal_opengl_shared.c b/src/opengl/pal_opengl_shared.c index 4f2c4488..6616b4ee 100644 --- a/src/opengl/pal_opengl_shared.c +++ b/src/opengl/pal_opengl_shared.c @@ -6,8 +6,37 @@ */ #include "pal/pal_opengl.h" +#include "pal_opengl_shared.h" #include +PalBool checkString( + const char* string, + const char* strings) +{ + const char* start = strings; + size_t stringLen = strlen(string); + + for (;;) { + const char* where = nullptr; + const char* terminator = nullptr; + + where = strstr(start, string); + if (!where) { + return PAL_FALSE; + } + + // the string was found, we find the terminator by adding the sizeof the strings + terminator = where + stringLen; + if (where == start || *(where - 1) == ' ') { + if (*terminator == ' ' || *terminator == '\0') { + return PAL_TRUE; + } + } + + start = terminator; + } +} + const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( PalGLFBConfig* configs, int32_t count, diff --git a/src/opengl/pal_opengl_shared.h b/src/opengl/pal_opengl_shared.h new file mode 100644 index 00000000..745a12a3 --- /dev/null +++ b/src/opengl/pal_opengl_shared.h @@ -0,0 +1,17 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_OPENGL_SHARED_H +#define _PAL_OPENGL_SHARED_H + +#include "pal/pal_core.h" + +PalBool checkString( + const char* string, + const char* strings); + +#endif // _PAL_OPENGL_SHARED_H \ No newline at end of file diff --git a/src/opengl/pal_opengl_win32.c b/src/opengl/pal_opengl_win32.c deleted file mode 100644 index 20576806..00000000 --- a/src/opengl/pal_opengl_win32.c +++ /dev/null @@ -1,1040 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -// ================================================== -// Includes -// ================================================== - -#include "pal/pal_opengl.h" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN - -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -// set unicode -#ifndef UNICODE -#define UNICODE -#endif // UNICODE - -#include -#include -#include - -// ================================================== -// Typedefs, enums and structs -// ================================================== - -#define PAL_GL_CLASS L"PALGLClass" - -// check to see if this is not defined yet -#ifndef GL_VENDOR -#define GL_VENDOR 0x1F00 -#define GL_RENDERER 0x1F01 -#define GL_VERSION 0x1F02 -#define GL_EXTENSIONS 0x1F03 -#endif // GL_VENDOR - -#ifndef WGL_NUMBER_PIXEL_FORMATS_ARB - -#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_RED_BITS_ARB 0x2015 -#define WGL_GREEN_BITS_ARB 0x2017 -#define WGL_BLUE_BITS_ARB 0x2019 -#define WGL_ALPHA_BITS_ARB 0x201b - -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_PIXEL_TYPE_ARB 0x2013 -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 -#define WGL_STEREO_ARB 0x2012 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_SAMPLES_ARB 0x2042 -#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 -#define WGL_TYPE_RGBA_ARB 0x202b -#define WGL_NO_ACCELERATION_ARB 0x2025 - -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 -#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 -#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 -#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 -#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 -#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 -#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 -#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 -#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 - -#define ERROR_INVALID_PROFILE_ARB 0x2096 - -#endif // WGL_NUMBER_PIXEL_FORMATS_ARB - -typedef unsigned int GLenum; -typedef unsigned char GLubyte; - -// gdi functions -typedef int(WINAPI* ChoosePixelFormatFn)( - HDC, - CONST PIXELFORMATDESCRIPTOR*); - -typedef BOOL(WINAPI* SetPixelFormatFn)( - HDC, - int, - CONST PIXELFORMATDESCRIPTOR*); - -typedef int(WINAPI* DescribePixelFormatFn)( - HDC, - int, - UINT, - LPPIXELFORMATDESCRIPTOR); - -typedef int(WINAPI* GetPixelFormatFn)(HDC); - -typedef BOOL(WINAPI* SwapBuffersFn)(HDC); - -// wgl functions -typedef PROC(WINAPI* wglGetProcAddressFn)(LPCSTR); - -typedef HGLRC(WINAPI* wglCreateContextFn)(HDC); - -typedef BOOL(WINAPI* wglDeleteContextFn)(HGLRC); - -typedef BOOL(WINAPI* wglShareListsFn)( - HGLRC, - HGLRC); - -typedef BOOL(WINAPI* wglMakeCurrentFn)( - HDC, - HGLRC); - -// gl functions -typedef const GLubyte*(WINAPI* glGetStringFn)(GLenum); - -// extensions -typedef BOOL(WINAPI* wglChoosePixelFormatARBFn)( - HDC, - const int*, - const FLOAT*, - UINT, - int*, - UINT*); - -typedef BOOL(WINAPI* wglGetPixelFormatAttribivARBFn)( - HDC, - int, - int, - UINT, - const int*, - int*); - -typedef HGLRC(WINAPI* wglCreateContextAttribsARBFn)( - HDC, - HGLRC, - const int*); - -typedef BOOL(WINAPI* wglSwapIntervalEXTFn)(int); - -typedef const char*(WINAPI* wglGetExtensionsStringEXTFn)(); - -typedef const char*(WINAPI* wglGetExtensionsStringARBFn)(HDC); - -typedef struct { - SetPixelFormatFn setPixelFormat; - DescribePixelFormatFn describePixelFormat; - ChoosePixelFormatFn choosePixelFormat; - GetPixelFormatFn getPixelFormat; - SwapBuffersFn swapBuffers; - HINSTANCE handle; -} Gdi; - -typedef struct { - PalBool initialized; - wglGetProcAddressFn wglGetProcAddress; - wglCreateContextFn wglCreateContext; - wglDeleteContextFn wglDeleteContext; - wglMakeCurrentFn wglMakeCurrent; - wglShareListsFn wglShareLists; - glGetStringFn glGetString; - - wglCreateContextAttribsARBFn wglCreateContextAttribsARB; - wglChoosePixelFormatARBFn wglChoosePixelFormatARB; - wglSwapIntervalEXTFn wglSwapIntervalEXT; - wglGetExtensionsStringEXTFn wglGetExtensionsStringEXT; - wglGetExtensionsStringARBFn wglGetExtensionsStringARB; - wglGetPixelFormatAttribivARBFn wglGetPixelFormatAttribivARB; - - const PalAllocator* allocator; - HINSTANCE opengl; - HINSTANCE instance; - HWND window; - HDC hdc; - HGLRC context; - PalGLInfo info; -} Wgl; - -static Gdi s_Gdi = {0}; -static Wgl s_Wgl = {0}; - -// ================================================== -// Internal API -// ================================================== - -static inline PalBool checkExtension( - const char* extension, - const char* extensions) -{ - const char* start = extensions; - size_t extensionLen = strlen(extension); - - for (;;) { - const char* where = nullptr; - const char* terminator = nullptr; - - where = strstr(start, extension); - if (!where) { - return PAL_FALSE; - } - - // the extension was found, we find the terminator by adding the sizeof - // the extension - terminator = where + extensionLen; - if (where == start || *(where - 1) == ' ') { - if (*terminator == ' ' || *terminator == '\0') { - return PAL_TRUE; - } - } - - start = terminator; - } -} - -void palSetLastPlatformError(uint32_t e); - -// ================================================== -// Public API -// ================================================== - -PalResult PAL_CALL palInitGL(const PalAllocator* allocator) -{ - if (s_Wgl.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_INVALID_ALLOCATOR; - } - - // get the instance - if (!s_Wgl.instance) { - s_Wgl.instance = GetModuleHandleW(nullptr); - } - - // register class - WNDCLASSEXW wc = {0}; - wc.style = CS_OWNDC; - wc.lpfnWndProc = DefWindowProcW; - wc.lpszClassName = PAL_GL_CLASS; - wc.cbSize = sizeof(WNDCLASSEXW); - - // since we check every input carefully, the only error we can get is access - // denied - if (!RegisterClassExW(&wc)) { - return PAL_RESULT_ACCESS_DENIED; - } - - // create hidden window - s_Wgl.window = CreateWindowExW( - 0, - PAL_GL_CLASS, - L"Dummy Window", - 0, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - CW_USEDEFAULT, - 0, - 0, - s_Wgl.instance, - 0); - - if (!s_Wgl.window) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - s_Gdi.handle = LoadLibraryA("gdi32.dll"); - s_Wgl.opengl = LoadLibraryA("opengl32.dll"); - if (!s_Gdi.handle || !s_Wgl.opengl) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // clang-format off - // load gdi function pointers - s_Gdi.choosePixelFormat = (ChoosePixelFormatFn)GetProcAddress( - s_Gdi.handle, - "ChoosePixelFormat"); - - s_Gdi.setPixelFormat = (SetPixelFormatFn)GetProcAddress( - s_Gdi.handle, - "SetPixelFormat"); - - s_Gdi.getPixelFormat = (GetPixelFormatFn)GetProcAddress( - s_Gdi.handle, - "GetPixelFormat"); - - s_Gdi.describePixelFormat = (DescribePixelFormatFn)GetProcAddress( - s_Gdi.handle, - "DescribePixelFormat"); - - s_Gdi.swapBuffers = (SwapBuffersFn)GetProcAddress( - s_Gdi.handle, - "SwapBuffers"); - - // load wgl function pointers - s_Wgl.wglGetProcAddress = (wglGetProcAddressFn)GetProcAddress( - s_Wgl.opengl, - "wglGetProcAddress"); - - s_Wgl.wglCreateContext = (wglCreateContextFn)GetProcAddress( - s_Wgl.opengl, - "wglCreateContext"); - - s_Wgl.wglDeleteContext = (wglDeleteContextFn)GetProcAddress( - s_Wgl.opengl, - "wglDeleteContext"); - - s_Wgl.wglMakeCurrent = (wglMakeCurrentFn)GetProcAddress( - s_Wgl.opengl, - "wglMakeCurrent"); - - s_Wgl.wglShareLists = (wglShareListsFn)GetProcAddress( - s_Wgl.opengl, - "wglShareLists"); - - if (!s_Gdi.choosePixelFormat || - !s_Gdi.describePixelFormat || - !s_Gdi.swapBuffers || - !s_Gdi.setPixelFormat) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - if (!s_Wgl.wglGetProcAddress || - !s_Wgl.wglCreateContext || - !s_Wgl.wglDeleteContext || - !s_Wgl.wglMakeCurrent) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - // clang-format on - - s_Wgl.hdc = GetDC(s_Wgl.window); - PIXELFORMATDESCRIPTOR pfd = {0}; - pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.iPixelType = PFD_TYPE_RGBA; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.cColorBits = 32; - pfd.cAlphaBits = 8; - pfd.iLayerType = PFD_MAIN_PLANE; - pfd.cDepthBits = 24; - pfd.cStencilBits = 8; - - int32_t pixelFormat = s_Gdi.choosePixelFormat(s_Wgl.hdc, &pfd); - s_Gdi.setPixelFormat(s_Wgl.hdc, pixelFormat, &pfd); - s_Wgl.context = s_Wgl.wglCreateContext(s_Wgl.hdc); - - if (!s_Wgl.wglMakeCurrent(s_Wgl.hdc, s_Wgl.context)) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // clang-format off - // load wgl extension function pointers - s_Wgl.wglChoosePixelFormatARB = (wglChoosePixelFormatARBFn)s_Wgl.wglGetProcAddress( - "wglChoosePixelFormatARB"); - - s_Wgl.wglGetPixelFormatAttribivARB = (wglGetPixelFormatAttribivARBFn)s_Wgl.wglGetProcAddress( - "wglGetPixelFormatAttribivARB"); - - s_Wgl.wglCreateContextAttribsARB = (wglCreateContextAttribsARBFn)s_Wgl.wglGetProcAddress( - "wglCreateContextAttribsARB"); - - s_Wgl.wglSwapIntervalEXT = (wglSwapIntervalEXTFn)s_Wgl.wglGetProcAddress( - "wglSwapIntervalEXT"); - - s_Wgl.wglGetExtensionsStringARB = (wglGetExtensionsStringARBFn)s_Wgl.wglGetProcAddress( - "wglGetExtensionsStringARB"); - - s_Wgl.wglGetExtensionsStringEXT = (wglGetExtensionsStringEXTFn)s_Wgl.wglGetProcAddress( - "wglGetExtensionsStringEXT"); - - // load gl functions - s_Wgl.glGetString = (glGetStringFn)GetProcAddress( - s_Wgl.opengl, - "glGetString"); - // clang-format on - - const char* version = (const char*)s_Wgl.glGetString(GL_VERSION); - if (version) { -#ifdef _MSC_VER - sscanf_s(version, "%d.%d", &s_Wgl.info.major, &s_Wgl.info.minor); -#else - sscanf(version, "%d.%d", &s_Wgl.info.major, &s_Wgl.info.minor); -#endif - } - - const char* renderer = (const char*)s_Wgl.glGetString(GL_RENDERER); - const char* vendor = (const char*)s_Wgl.glGetString(GL_VENDOR); - strcpy(s_Wgl.info.vendor, vendor); - strcpy(s_Wgl.info.version, version); - strcpy(s_Wgl.info.graphicsCard, renderer); - - // check available extensions - const char* extensions = nullptr; - if (s_Wgl.wglGetExtensionsStringARB) { - extensions = s_Wgl.wglGetExtensionsStringARB(s_Wgl.hdc); - - } else if (s_Wgl.wglGetExtensionsStringEXT) { - extensions = s_Wgl.wglGetExtensionsStringEXT(); - } - - if (extensions) { - // multisample - if (checkExtension("WGL_ARB_multisample", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_MULTISAMPLE; - } - // multisample - - // color space - if (checkExtension("WGL_ARB_framebuffer_sRGB", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_COLORSPACE_SRGB; - } - - if (checkExtension("WGL_EXT_framebuffer_sRGB", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_COLORSPACE_SRGB; - } - - if (checkExtension("WGL_EXT_colorspace", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_COLORSPACE_SRGB; - } - // color space - - // create context - if (checkExtension("WGL_ARB_create_context", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_CREATE_CONTEXT; - } - // create context - - // create profile - if (checkExtension("WGL_ARB_create_context_profile", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE; - } - // create profile - - // create profile es2 - if (checkExtension("WGL_EXT_create_context_es2_profile", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; - } - // create profile es2 - - // robustness - if (checkExtension("WGL_ARB_create_context_robustness", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_ROBUSTNESS; - } - // robustness - - // no error - if (checkExtension("WGL_ARB_create_context_no_error", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_NO_ERROR; - } - // no error - - // swap control - if (checkExtension("WGL_EXT_swap_control", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_SWAP_CONTROL; - } - // swap control - - // flush control - if (checkExtension("WGL_ARB_context_flush_control", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; - } - // flush control - - // pixel format - if (checkExtension("WGL_ARB_pixel_format", extensions)) { - s_Wgl.info.extensions |= PAL_GL_EXTENSION_PIXEL_FORMAT; - } - // pixel format - } - - s_Wgl.initialized = PAL_TRUE; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palShutdownGL() -{ - if (!s_Wgl.initialized) { - return; - } - - s_Wgl.wglMakeCurrent(s_Wgl.hdc, nullptr); - s_Wgl.wglDeleteContext(s_Wgl.context); - ReleaseDC(s_Wgl.window, s_Wgl.hdc); - DestroyWindow(s_Wgl.window); - UnregisterClassW(PAL_GL_CLASS, s_Wgl.instance); - - FreeLibrary(s_Wgl.opengl); - FreeLibrary(s_Gdi.handle); - - memset(&s_Wgl, 0, sizeof(Wgl)); - s_Wgl.initialized = PAL_FALSE; -} - -const PalGLInfo* PAL_CALL palGetGLInfo() -{ - if (!s_Wgl.initialized) { - return nullptr; - } - return &s_Wgl.info; -} - -PalResult PAL_CALL palEnumerateGLFBConfigs( - PalGLWindow* glWindow, - int32_t* count, - PalGLFBConfig* configs) -{ - if (!s_Wgl.initialized) { - return PAL_RESULT_GL_NOT_INITIALIZED; - } - - if (!count) { - return PAL_RESULT_NULL_POINTER; - } - - if (count == 0 && configs) { - return PAL_RESULT_INSUFFICIENT_BUFFER; - } - - int32_t configCount = 0; - int32_t maxConfigCount = 0; - int32_t nativeCount = 0; - const int32_t configAttrib = WGL_NUMBER_PIXEL_FORMATS_ARB; - - if (configs) { - maxConfigCount = *count; - } - - // check if we support modern extention - if (s_Wgl.wglGetPixelFormatAttribivARB) { - // get framebuffer config with extensions - if (!s_Wgl.wglGetPixelFormatAttribivARB(s_Wgl.hdc, 0, 0, 1, &configAttrib, &nativeCount)) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // attributes we care about - int32_t attributes[] = { - WGL_SUPPORT_OPENGL_ARB, - WGL_DRAW_TO_WINDOW_ARB, - WGL_PIXEL_TYPE_ARB, - WGL_ACCELERATION_ARB, - WGL_RED_BITS_ARB, - WGL_GREEN_BITS_ARB, - WGL_BLUE_BITS_ARB, - WGL_ALPHA_BITS_ARB, - WGL_DEPTH_BITS_ARB, - WGL_STENCIL_BITS_ARB, - WGL_SAMPLES_ARB, - WGL_STEREO_ARB, - WGL_DOUBLE_BUFFER_ARB, - WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB}; - - int32_t values[sizeof(attributes) / sizeof(attributes[0])]; - for (int32_t i = 1; i <= nativeCount; i++) { - if (!s_Wgl.wglGetPixelFormatAttribivARB( - s_Wgl.hdc, - i, - 0, - sizeof(attributes) / sizeof(attributes[0]), - attributes, - values)) { - continue; - } - - // we index the values list in the same way as the arributes list - // so index 0 is WGL_SUPPORT_OPENGL_ARB and 1 is - // WGL_DRAW_TO_WINDOW_ARB - if (!values[0] || !values[1]) { - // WGL_SUPPORT_OPENGL_ARB and WGL_DRAW_TO_WINDOW_ARB support - continue; - } - - if (values[2] != WGL_TYPE_RGBA_ARB) { - // WGL_PIXEL_TYPE_ARB support - continue; - } - - if (values[3] == WGL_NO_ACCELERATION_ARB) { - continue; - } - - if (configs && configCount < maxConfigCount) { - PalGLFBConfig* config = &configs[configCount]; - config->index = i; - - config->redBits = values[4]; // WGL_RED_BITS_ARB - config->greenBits = values[5]; // WGL_GREEN_BITS_ARB - config->blueBits = values[6]; // WGL_BLUE_BITS_ARB - config->alphaBits = values[7]; // WGL_ALPHA_BITS_ARB - config->depthBits = values[8]; // WGL_DEPTH_BITS_ARB - config->stencilBits = values[9]; // WGL_STENCIL_BITS_ARB - config->samples = values[10]; // WGL_SAMPLES_ARB - - if (config->samples == 0) { - config->samples = 1; - } - - // WGL_STEREO_ARB - config->stereo = values[11]; - - // WGL_DOUBLE_BUFFER_ARB - config->doubleBuffer = values[12]; - - // WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB - config->sRGB = values[13]; - } - configCount++; - } - - } else { - // get pixel format with legacy pixel descriptor - nativeCount = s_Gdi.describePixelFormat(s_Wgl.hdc, 1, 0, nullptr); - - for (int32_t i = 1; i <= nativeCount; i++) { - PIXELFORMATDESCRIPTOR pfd; - if (!s_Gdi.describePixelFormat(s_Wgl.hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { - continue; - } - - // filter for opengl pixel formats - if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) || !(pfd.dwFlags & PFD_DRAW_TO_WINDOW)) { - continue; - } - - if (pfd.iPixelType != PFD_TYPE_RGBA) { - continue; - } - - if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && (pfd.dwFlags & PFD_GENERIC_FORMAT)) { - continue; - } - - if (configs && configCount < maxConfigCount) { - PalGLFBConfig* config = &configs[configCount]; - config->index = i; - - config->redBits = pfd.cRedBits; - config->greenBits = pfd.cGreenBits; - config->blueBits = pfd.cBlueBits; - config->alphaBits = pfd.cAlphaBits; - config->depthBits = pfd.cDepthBits; - config->stencilBits = pfd.cStencilBits; - config->samples = 1; - - config->stereo = (pfd.dwFlags & PFD_STEREO) ? PAL_TRUE : PAL_FALSE; - config->sRGB = PAL_FALSE; - config->doubleBuffer = (pfd.dwFlags & PFD_DOUBLEBUFFER) ? PAL_TRUE : PAL_FALSE; - } - configCount++; - } - } - - if (!configs) { - *count = configCount; - } - return PAL_RESULT_SUCCESS; -} - -const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( - PalGLFBConfig* configs, - int32_t count, - const PalGLFBConfig* desired) -{ - if (!s_Wgl.initialized) { - return nullptr; - } - - if (!configs || !desired) { - return nullptr; - } - - if (count == 0) { - return nullptr; - } - - int32_t score = 0; - int32_t bestScore = 0x7FFFFFFF; - PalGLFBConfig* best = nullptr; - for (int32_t i = 0; i < count; i++) { - PalGLFBConfig* tmp = &configs[i]; - - // filter out hard constraints - if (desired->doubleBuffer && !tmp->doubleBuffer) { - continue; - } - - if (desired->stereo && !tmp->stereo) { - continue; - } - - score = 0; - - // score color bits - score += abs(tmp->redBits - desired->redBits); - score += abs(tmp->greenBits - desired->greenBits); - score += abs(tmp->blueBits - desired->blueBits); - score += abs(tmp->alphaBits - desired->alphaBits); - score += abs(tmp->depthBits - desired->depthBits); - score += abs(tmp->stencilBits - desired->stencilBits); - - // score soft constraints - if (desired->samples != tmp->samples) { - score += 1000; - } - - if (desired->sRGB != tmp->sRGB) { - score += 500; - } - - if (score < bestScore) { - bestScore = score; - best = &configs[i]; - } - } - - return best; -} - -// ================================================== -// Context -// ================================================== - -PalResult PAL_CALL palCreateGLContext( - const PalGLContextCreateInfo* info, - PalGLContext** outContext) -{ - if (!s_Wgl.initialized) { - return PAL_RESULT_GL_NOT_INITIALIZED; - } - - if (!info || !outContext || (info && (!info->window || !info->fbConfig))) { - return PAL_RESULT_NULL_POINTER; - } - - // check support for requested features - if (info->profile != PAL_GL_PROFILE_NONE) { - if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE)) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - } - - if (info->forward) { - if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_CREATE_CONTEXT)) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - } - - if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { - if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_ROBUSTNESS)) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - } - - if (info->noError) { - if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_NO_ERROR)) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - } - - if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { - if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_FLUSH_CONTROL)) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - } - - // clang-format off - // check version - PalBool valid = info->major < s_Wgl.info.major || - (info->major == s_Wgl.info.major && info->minor <= s_Wgl.info.minor); - // clang-format on - - if (!valid) { - return PAL_RESULT_INVALID_GL_VERSION; - } - - HDC hdc = GetDC((HWND)info->window->window); - if (!hdc) { - return PAL_RESULT_INVALID_GL_WINDOW; - } - - // check if the provided pixel format is the same as the windows - if (s_Gdi.getPixelFormat(hdc) != info->fbConfig->index) { - return PAL_RESULT_INVALID_GL_FBCONFIG; - } - - HGLRC share = nullptr; - if (info->shareContext) { - share = (HGLRC)info->shareContext; - } - - HGLRC context = nullptr; - if (s_Wgl.wglCreateContextAttribsARB) { - // create context with modern wgl functions - int32_t attribs[40]; - int32_t index = 0; - int32_t profile = 0; - int32_t flags = 0; - - // set context attributes - // the first element is the key and the second is the value - // set version - attribs[index++] = WGL_CONTEXT_MAJOR_VERSION_ARB; // key - attribs[index++] = info->major; // value - - attribs[index++] = WGL_CONTEXT_MINOR_VERSION_ARB; - attribs[index++] = info->minor; - - // set profile mask - if (info->profile != PAL_GL_PROFILE_NONE) { - attribs[index++] = WGL_CONTEXT_PROFILE_MASK_ARB; - - if (info->profile == PAL_GL_PROFILE_COMPATIBILITY) { - profile = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; - } else if (info->profile == PAL_GL_PROFILE_CORE) { - profile = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; - } else { - profile = WGL_CONTEXT_ES2_PROFILE_BIT_EXT; - } - attribs[index++] = info->profile; - } - - // set forward flag - if (info->forward) { - flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; - } - - // set debug flag - if (info->debug) { - flags |= WGL_CONTEXT_DEBUG_BIT_ARB; - } - - // set robustness - if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { - flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; - attribs[index++] = WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB; - - if (info->reset == PAL_GL_CONTEXT_RESET_LOSE_CONTEXT) { - attribs[index++] = WGL_LOSE_CONTEXT_ON_RESET_ARB; - - } else if (info->reset == PAL_GL_CONTEXT_RESET_NO_NOTIFICATION) { - attribs[index++] = WGL_NO_RESET_NOTIFICATION_ARB; - } - } - - // set no error - if (info->noError) { - attribs[index++] = WGL_CONTEXT_OPENGL_NO_ERROR_ARB; - attribs[index++] = PAL_TRUE; - } - - // release - if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { - attribs[index++] = WGL_CONTEXT_RELEASE_BEHAVIOR_ARB; - attribs[index++] = WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB; - } - - if (flags) { - attribs[index++] = WGL_CONTEXT_FLAGS_ARB; - attribs[index++] = flags; - } - attribs[index++] = 0; - - context = s_Wgl.wglCreateContextAttribsARB(hdc, share, attribs); - if (!context) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_PROFILE_ARB) { - return PAL_RESULT_INVALID_GL_PROFILE; - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - } else { - // create context with legacy wgl functions - context = s_Wgl.wglCreateContext(hdc); - if (!context) { - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - - // share context - if (share) { - if (!s_Wgl.wglShareLists(share, context)) { - s_Wgl.wglDeleteContext(context); - ReleaseDC((HWND)info->window->window, hdc); - DWORD error = GetLastError(); - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - } - - ReleaseDC((HWND)info->window->window, hdc); - *outContext = (PalGLContext*)context; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyGLContext(PalGLContext* context) -{ - if (!s_Wgl.initialized || !context) { - return; - } - s_Wgl.wglDeleteContext((HGLRC)context); -} - -PalResult PAL_CALL palMakeContextCurrent( - PalGLWindow* glWindow, - PalGLContext* context) -{ - if (!s_Wgl.initialized) { - return PAL_RESULT_GL_NOT_INITIALIZED; - } - - if ((!glWindow && context) || (glWindow && !context)) { - return PAL_RESULT_NULL_POINTER; - } - - if (context && glWindow) { - // get hdc - HDC hdc = GetDC((HWND)glWindow->window); - if (!hdc) { - return PAL_RESULT_INVALID_GL_WINDOW; - } - - if (!s_Wgl.wglMakeCurrent(hdc, (HGLRC)context)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return PAL_RESULT_INVALID_GL_CONTEXT; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - ReleaseDC((HWND)glWindow->window, hdc); - - } else if (!context && !glWindow) { - s_Wgl.wglMakeCurrent(nullptr, nullptr); - } - - return PAL_RESULT_SUCCESS; -} - -void* PAL_CALL palGetGLProcAddress(const char* name) -{ - if (!s_Wgl.initialized) { - return nullptr; - } - - void* proc = s_Wgl.wglGetProcAddress(name); - if (!proc) { - proc = (void*)GetProcAddress(s_Wgl.opengl, name); - } - return proc; -} - -PalResult PAL_CALL palSwapBuffers( - PalGLWindow* glWindow, - PalGLContext* context) -{ - if (!s_Wgl.initialized) { - return PAL_RESULT_GL_NOT_INITIALIZED; - } - - if (!context || !glWindow) { - return PAL_RESULT_NULL_POINTER; - } - - // get hdc - HDC hdc = GetDC((HWND)glWindow->window); - if (!hdc) { - return PAL_RESULT_INVALID_GL_WINDOW; - } - - if (!s_Gdi.swapBuffers(hdc)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_PIXEL_FORMAT) { - return PAL_RESULT_INVALID_GL_FBCONFIG; - - } else { - palSetLastPlatformError(error); - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - ReleaseDC((HWND)glWindow->window, hdc); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSetSwapInterval(int32_t interval) -{ - if (!s_Wgl.initialized) { - return PAL_RESULT_GL_NOT_INITIALIZED; - } - - if (!s_Wgl.wglSwapIntervalEXT) { - return PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED; - } - - s_Wgl.wglSwapIntervalEXT(interval); - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palGLSetInstance(void* instance) -{ - s_Wgl.instance = instance; -} - -const char* PAL_CALL palGLGetBackend() -{ - if (!s_Wgl.initialized) { - return nullptr; - } - return "wgl"; -} diff --git a/src/opengl/win32/pal_context_win32.c b/src/opengl/win32/pal_context_win32.c new file mode 100644 index 00000000..9d813bef --- /dev/null +++ b/src/opengl/win32/pal_context_win32.c @@ -0,0 +1,336 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_opengl_win32.h" +#include "pal_shared.h" + +PalResult PAL_CALL palCreateGLContext( + const PalGLContextCreateInfo* info, + PalGLContext** outContext) +{ + if (!s_Wgl.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!info || !outContext || (info && (!info->window || !info->fbConfig))) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // check support for requested features + if (info->profile != PAL_GL_PROFILE_NONE) { + if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE)) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + } + + if (info->forward) { + if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_CREATE_CONTEXT)) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + } + + if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { + if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_ROBUSTNESS)) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + } + + if (info->noError) { + if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_NO_ERROR)) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + } + + if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { + if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_FLUSH_CONTROL)) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + } + + // clang-format off + // check version + PalBool valid = info->major < s_Wgl.info.major || + (info->major == s_Wgl.info.major && info->minor <= s_Wgl.info.minor); + // clang-format on + + if (!valid) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + HDC hdc = GetDC((HWND)info->window->window); + if (!hdc) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + + } + + // check if the provided pixel format is the same as the window + if (s_Gdi.getPixelFormat(hdc) != info->fbConfig->index) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + HGLRC share = nullptr; + if (info->shareContext) { + share = (HGLRC)info->shareContext; + } + + HGLRC context = nullptr; + if (s_Wgl.wglCreateContextAttribsARB) { + // create context with modern wgl functions + int32_t attribs[40]; + int32_t index = 0; + int32_t profile = 0; + int32_t flags = 0; + + // set context attributes + // the first element is the key and the second is the value + // set version + attribs[index++] = WGL_CONTEXT_MAJOR_VERSION_ARB; // key + attribs[index++] = info->major; // value + + attribs[index++] = WGL_CONTEXT_MINOR_VERSION_ARB; + attribs[index++] = info->minor; + + // set profile mask + if (info->profile != PAL_GL_PROFILE_NONE) { + attribs[index++] = WGL_CONTEXT_PROFILE_MASK_ARB; + + if (info->profile == PAL_GL_PROFILE_COMPATIBILITY) { + profile = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; + } else if (info->profile == PAL_GL_PROFILE_CORE) { + profile = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; + } else { + profile = WGL_CONTEXT_ES2_PROFILE_BIT_EXT; + } + attribs[index++] = info->profile; + } + + // set forward flag + if (info->forward) { + flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + } + + // set debug flag + if (info->debug) { + flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + } + + // set robustness + if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { + flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB; + attribs[index++] = WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB; + + if (info->reset == PAL_GL_CONTEXT_RESET_LOSE_CONTEXT) { + attribs[index++] = WGL_LOSE_CONTEXT_ON_RESET_ARB; + + } else if (info->reset == PAL_GL_CONTEXT_RESET_NO_NOTIFICATION) { + attribs[index++] = WGL_NO_RESET_NOTIFICATION_ARB; + } + } + + // set no error + if (info->noError) { + attribs[index++] = WGL_CONTEXT_OPENGL_NO_ERROR_ARB; + attribs[index++] = PAL_TRUE; + } + + // release + if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { + attribs[index++] = WGL_CONTEXT_RELEASE_BEHAVIOR_ARB; + attribs[index++] = WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB; + } + + if (flags) { + attribs[index++] = WGL_CONTEXT_FLAGS_ARB; + attribs[index++] = flags; + } + attribs[index++] = 0; + + context = s_Wgl.wglCreateContextAttribsARB(hdc, share, attribs); + if (!context) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_PROFILE_ARB) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + } else { + // create context with legacy wgl functions + context = s_Wgl.wglCreateContext(hdc); + if (!context) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // share context + if (share) { + if (!s_Wgl.wglShareLists(share, context)) { + s_Wgl.wglDeleteContext(context); + ReleaseDC((HWND)info->window->window, hdc); + + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + } + } + + ReleaseDC((HWND)info->window->window, hdc); + *outContext = (PalGLContext*)context; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palDestroyGLContext(PalGLContext* context) +{ + if (!s_Wgl.initialized || !context) { + return; + } + s_Wgl.wglDeleteContext((HGLRC)context); +} + +PalResult PAL_CALL palMakeContextCurrent( + PalGLWindow* glWindow, + PalGLContext* context) +{ + if (!s_Wgl.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if ((!glWindow && context) || (glWindow && !context)) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (context && glWindow) { + // get hdc + HDC hdc = GetDC((HWND)glWindow->window); + if (!hdc) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!s_Wgl.wglMakeCurrent(hdc, (HGLRC)context)) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_HANDLE) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + ReleaseDC((HWND)glWindow->window, hdc); + + } else if (!context && !glWindow) { + s_Wgl.wglMakeCurrent(nullptr, nullptr); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL palSwapBuffers( + PalGLWindow* glWindow, + PalGLContext* context) +{ + if (!s_Wgl.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!context || !glWindow) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // get hdc + HDC hdc = GetDC((HWND)glWindow->window); + if (!hdc) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!s_Gdi.swapBuffers(hdc)) { + DWORD error = GetLastError(); + if (error == ERROR_INVALID_PIXEL_FORMAT) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + error); + + } else { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + error); + } + } + + ReleaseDC((HWND)glWindow->window, hdc); + return PAL_RESULT_SUCCESS; +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/opengl/win32/pal_opengl_win32.c b/src/opengl/win32/pal_opengl_win32.c new file mode 100644 index 00000000..7400b1ed --- /dev/null +++ b/src/opengl/win32/pal_opengl_win32.c @@ -0,0 +1,543 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifdef _WIN32 +#include "pal_opengl_win32.h" +#include "opengl/pal_opengl_shared.h" +#include "pal_shared.h" +#include +#include + +Gdi s_Gdi = {0}; +Wgl s_Wgl = {0}; +static PalBool s_SupportedAPIs[2] = {0}; + +PalResult PAL_CALL palInitGL( + PalGLAPI api, + void* instance, + const PalAllocator* allocator) +{ + if (s_Wgl.initialized) { + return PAL_RESULT_SUCCESS; + } + + if (!instance) { + palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (api != PAL_GL_API_OPENGL) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (allocator && (!allocator->allocate || !allocator->free)) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // register class + s_Wgl.instance = instance; + WNDCLASSEXW wc = {0}; + wc.style = CS_OWNDC; + wc.lpfnWndProc = DefWindowProcW; + wc.lpszClassName = PAL_GL_CLASS; + wc.cbSize = sizeof(WNDCLASSEXW); + + // since we check every input carefully, the only error we can get is access + // denied + if (!RegisterClassExW(&wc)) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // create hidden window + s_Wgl.window = CreateWindowExW( + 0, + PAL_GL_CLASS, + L"Dummy Window", + 0, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + 0, + 0, + s_Wgl.instance, + 0); + + if (!s_Wgl.window) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + s_Gdi.handle = LoadLibraryA("gdi32.dll"); + s_Wgl.opengl = LoadLibraryA("opengl32.dll"); + if (!s_Gdi.handle || !s_Wgl.opengl) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // clang-format off + // load gdi function pointers + s_Gdi.choosePixelFormat = (ChoosePixelFormatFn)GetProcAddress( + s_Gdi.handle, + "ChoosePixelFormat"); + + s_Gdi.setPixelFormat = (SetPixelFormatFn)GetProcAddress( + s_Gdi.handle, + "SetPixelFormat"); + + s_Gdi.getPixelFormat = (GetPixelFormatFn)GetProcAddress( + s_Gdi.handle, + "GetPixelFormat"); + + s_Gdi.describePixelFormat = (DescribePixelFormatFn)GetProcAddress( + s_Gdi.handle, + "DescribePixelFormat"); + + s_Gdi.swapBuffers = (SwapBuffersFn)GetProcAddress( + s_Gdi.handle, + "SwapBuffers"); + + // load wgl function pointers + s_Wgl.wglGetProcAddress = (wglGetProcAddressFn)GetProcAddress( + s_Wgl.opengl, + "wglGetProcAddress"); + + s_Wgl.wglCreateContext = (wglCreateContextFn)GetProcAddress( + s_Wgl.opengl, + "wglCreateContext"); + + s_Wgl.wglDeleteContext = (wglDeleteContextFn)GetProcAddress( + s_Wgl.opengl, + "wglDeleteContext"); + + s_Wgl.wglMakeCurrent = (wglMakeCurrentFn)GetProcAddress( + s_Wgl.opengl, + "wglMakeCurrent"); + + s_Wgl.wglShareLists = (wglShareListsFn)GetProcAddress( + s_Wgl.opengl, + "wglShareLists"); + + if (!s_Gdi.choosePixelFormat || + !s_Gdi.describePixelFormat || + !s_Gdi.swapBuffers || + !s_Gdi.setPixelFormat) { + + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!s_Wgl.wglGetProcAddress || + !s_Wgl.wglCreateContext || + !s_Wgl.wglDeleteContext || + !s_Wgl.wglMakeCurrent) { + + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + // clang-format on + + s_Wgl.hdc = GetDC(s_Wgl.window); + PIXELFORMATDESCRIPTOR pfd = {0}; + pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pfd.nVersion = 1; + pfd.iPixelType = PFD_TYPE_RGBA; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.cColorBits = 32; + pfd.cAlphaBits = 8; + pfd.iLayerType = PFD_MAIN_PLANE; + pfd.cDepthBits = 24; + pfd.cStencilBits = 8; + + int32_t pixelFormat = s_Gdi.choosePixelFormat(s_Wgl.hdc, &pfd); + s_Gdi.setPixelFormat(s_Wgl.hdc, pixelFormat, &pfd); + s_Wgl.context = s_Wgl.wglCreateContext(s_Wgl.hdc); + + if (!s_Wgl.wglMakeCurrent(s_Wgl.hdc, s_Wgl.context)) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // clang-format off + // load wgl extension function pointers + s_Wgl.wglChoosePixelFormatARB = (wglChoosePixelFormatARBFn)s_Wgl.wglGetProcAddress( + "wglChoosePixelFormatARB"); + + s_Wgl.wglGetPixelFormatAttribivARB = (wglGetPixelFormatAttribivARBFn)s_Wgl.wglGetProcAddress( + "wglGetPixelFormatAttribivARB"); + + s_Wgl.wglCreateContextAttribsARB = (wglCreateContextAttribsARBFn)s_Wgl.wglGetProcAddress( + "wglCreateContextAttribsARB"); + + s_Wgl.wglSwapIntervalEXT = (wglSwapIntervalEXTFn)s_Wgl.wglGetProcAddress( + "wglSwapIntervalEXT"); + + s_Wgl.wglGetExtensionsStringARB = (wglGetExtensionsStringARBFn)s_Wgl.wglGetProcAddress( + "wglGetExtensionsStringARB"); + + s_Wgl.wglGetExtensionsStringEXT = (wglGetExtensionsStringEXTFn)s_Wgl.wglGetProcAddress( + "wglGetExtensionsStringEXT"); + + // load gl functions + s_Wgl.glGetString = (glGetStringFn)GetProcAddress( + s_Wgl.opengl, + "glGetString"); + // clang-format on + + const char* version = (const char*)s_Wgl.glGetString(GL_VERSION); + if (version) { +#ifdef _MSC_VER + sscanf_s(version, "%d.%d", &s_Wgl.info.major, &s_Wgl.info.minor); +#else + sscanf(version, "%d.%d", &s_Wgl.info.major, &s_Wgl.info.minor); +#endif + } + + const char* renderer = (const char*)s_Wgl.glGetString(GL_RENDERER); + const char* vendor = (const char*)s_Wgl.glGetString(GL_VENDOR); + strcpy(s_Wgl.info.vendor, vendor); + strcpy(s_Wgl.info.version, version); + strcpy(s_Wgl.info.graphicsCard, renderer); + + // check available extensions + const char* extensions = nullptr; + if (s_Wgl.wglGetExtensionsStringARB) { + extensions = s_Wgl.wglGetExtensionsStringARB(s_Wgl.hdc); + + } else if (s_Wgl.wglGetExtensionsStringEXT) { + extensions = s_Wgl.wglGetExtensionsStringEXT(); + } + + if (extensions) { + // multisample + if (checkString("WGL_ARB_multisample", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_MULTISAMPLE; + } + // multisample + + // color space + if (checkString("WGL_ARB_framebuffer_sRGB", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_COLORSPACE_SRGB; + } + + if (checkString("WGL_EXT_framebuffer_sRGB", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_COLORSPACE_SRGB; + } + + if (checkString("WGL_EXT_colorspace", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_COLORSPACE_SRGB; + } + // color space + + // create context + if (checkString("WGL_ARB_create_context", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_CREATE_CONTEXT; + } + // create context + + // create profile + if (checkString("WGL_ARB_create_context_profile", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE; + } + // create profile + + // create profile es2 + if (checkString("WGL_EXT_create_context_es2_profile", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; + } + // create profile es2 + + // robustness + if (checkString("WGL_ARB_create_context_robustness", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_ROBUSTNESS; + } + // robustness + + // no error + if (checkString("WGL_ARB_create_context_no_error", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_NO_ERROR; + } + // no error + + // swap control + if (checkString("WGL_EXT_swap_control", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_SWAP_CONTROL; + } + // swap control + + // flush control + if (checkString("WGL_ARB_context_flush_control", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; + } + // flush control + + // pixel format + if (checkString("WGL_ARB_pixel_format", extensions)) { + s_Wgl.info.extensions |= PAL_GL_EXTENSION_PIXEL_FORMAT; + } + // pixel format + } + + s_Wgl.info.api = PAL_GL_API_OPENGL; + s_Wgl.info.backend = PAL_GL_BACKEND_WGL; + s_Wgl.initialized = PAL_TRUE; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palShutdownGL() +{ + if (!s_Wgl.initialized) { + return; + } + + s_Wgl.wglMakeCurrent(s_Wgl.hdc, nullptr); + s_Wgl.wglDeleteContext(s_Wgl.context); + ReleaseDC(s_Wgl.window, s_Wgl.hdc); + DestroyWindow(s_Wgl.window); + UnregisterClassW(PAL_GL_CLASS, s_Wgl.instance); + + FreeLibrary(s_Wgl.opengl); + FreeLibrary(s_Gdi.handle); + + memset(&s_Wgl, 0, sizeof(Wgl)); + s_Wgl.initialized = PAL_FALSE; +} + +const PalGLInfo* PAL_CALL palGetGLInfo() +{ + if (!s_Wgl.initialized) { + return nullptr; + } + return &s_Wgl.info; +} + +PalResult PAL_CALL palEnumerateGLFBConfigs( + int32_t* count, + PalGLFBConfig* configs) +{ + if (!s_Wgl.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!count || *count == 0 && configs) { + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + int32_t configCount = 0; + int32_t maxConfigCount = 0; + int32_t nativeCount = 0; + const int32_t configAttrib = WGL_NUMBER_PIXEL_FORMATS_ARB; + + if (configs) { + maxConfigCount = *count; + } + + // check if we support modern extention + if (s_Wgl.wglGetPixelFormatAttribivARB) { + // get framebuffer config with extensions + if (!s_Wgl.wglGetPixelFormatAttribivARB(s_Wgl.hdc, 0, 0, 1, &configAttrib, &nativeCount)) { + return palMakeResult( + PAL_RESULT_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + // attributes we care about + int32_t attributes[] = { + WGL_SUPPORT_OPENGL_ARB, + WGL_DRAW_TO_WINDOW_ARB, + WGL_PIXEL_TYPE_ARB, + WGL_ACCELERATION_ARB, + WGL_RED_BITS_ARB, + WGL_GREEN_BITS_ARB, + WGL_BLUE_BITS_ARB, + WGL_ALPHA_BITS_ARB, + WGL_DEPTH_BITS_ARB, + WGL_STENCIL_BITS_ARB, + WGL_SAMPLES_ARB, + WGL_STEREO_ARB, + WGL_DOUBLE_BUFFER_ARB, + WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB}; + + int32_t values[sizeof(attributes) / sizeof(attributes[0])]; + for (int32_t i = 1; i <= nativeCount; i++) { + if (!s_Wgl.wglGetPixelFormatAttribivARB( + s_Wgl.hdc, + i, + 0, + sizeof(attributes) / sizeof(attributes[0]), + attributes, + values)) { + continue; + } + + // we index the values list in the same way as the arributes list + // so index 0 is WGL_SUPPORT_OPENGL_ARB and 1 is + // WGL_DRAW_TO_WINDOW_ARB + if (!values[0] || !values[1]) { + // WGL_SUPPORT_OPENGL_ARB and WGL_DRAW_TO_WINDOW_ARB support + continue; + } + + if (values[2] != WGL_TYPE_RGBA_ARB) { + // WGL_PIXEL_TYPE_ARB support + continue; + } + + if (values[3] == WGL_NO_ACCELERATION_ARB) { + continue; + } + + if (configs && configCount < maxConfigCount) { + PalGLFBConfig* config = &configs[configCount]; + config->index = i; + + config->redBits = values[4]; // WGL_RED_BITS_ARB + config->greenBits = values[5]; // WGL_GREEN_BITS_ARB + config->blueBits = values[6]; // WGL_BLUE_BITS_ARB + config->alphaBits = values[7]; // WGL_ALPHA_BITS_ARB + config->depthBits = values[8]; // WGL_DEPTH_BITS_ARB + config->stencilBits = values[9]; // WGL_STENCIL_BITS_ARB + config->samples = values[10]; // WGL_SAMPLES_ARB + + if (config->samples == 0) { + config->samples = 1; + } + + // WGL_STEREO_ARB + config->stereo = values[11]; + + // WGL_DOUBLE_BUFFER_ARB + config->doubleBuffer = values[12]; + + // WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB + config->sRGB = values[13]; + } + configCount++; + } + + } else { + // get pixel format with legacy pixel descriptor + nativeCount = s_Gdi.describePixelFormat(s_Wgl.hdc, 1, 0, nullptr); + + for (int32_t i = 1; i <= nativeCount; i++) { + PIXELFORMATDESCRIPTOR pfd; + if (!s_Gdi.describePixelFormat(s_Wgl.hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { + continue; + } + + // filter for opengl pixel formats + if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) || !(pfd.dwFlags & PFD_DRAW_TO_WINDOW)) { + continue; + } + + if (pfd.iPixelType != PFD_TYPE_RGBA) { + continue; + } + + if (!(pfd.dwFlags & PFD_GENERIC_ACCELERATED) && (pfd.dwFlags & PFD_GENERIC_FORMAT)) { + continue; + } + + if (configs && configCount < maxConfigCount) { + PalGLFBConfig* config = &configs[configCount]; + config->index = i; + + config->redBits = pfd.cRedBits; + config->greenBits = pfd.cGreenBits; + config->blueBits = pfd.cBlueBits; + config->alphaBits = pfd.cAlphaBits; + config->depthBits = pfd.cDepthBits; + config->stencilBits = pfd.cStencilBits; + config->samples = 1; + + config->stereo = (pfd.dwFlags & PFD_STEREO) ? PAL_TRUE : PAL_FALSE; + config->sRGB = PAL_FALSE; + config->doubleBuffer = (pfd.dwFlags & PFD_DOUBLEBUFFER) ? PAL_TRUE : PAL_FALSE; + } + configCount++; + } + } + + if (!configs) { + *count = configCount; + } + return PAL_RESULT_SUCCESS; +} + +void* PAL_CALL palGetGLProcAddress(const char* name) +{ + if (!s_Wgl.initialized) { + return nullptr; + } + + void* proc = s_Wgl.wglGetProcAddress(name); + if (!proc) { + proc = (void*)GetProcAddress(s_Wgl.opengl, name); + } + return proc; +} + +PalResult PAL_CALL palSetSwapInterval(int32_t interval) +{ + if (!s_Wgl.initialized) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + if (!s_Wgl.wglSwapIntervalEXT) { + return palMakeResult( + PAL_RESULT_NOT_INITIALIZED, + PAL_RESULT_SOURCE_WINDOWS, + GetLastError()); + } + + s_Wgl.wglSwapIntervalEXT(interval); + return PAL_RESULT_SUCCESS; +} + +const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance) +{ + if (!instance) { + return nullptr; + } + + s_SupportedAPIs[PAL_GL_API_OPENGL] = PAL_TRUE; + s_SupportedAPIs[PAL_GL_API_OPENGL_ES] = PAL_FALSE; + return s_SupportedAPIs; +} + +#endif // _WIN32 \ No newline at end of file diff --git a/src/opengl/win32/pal_opengl_win32.h b/src/opengl/win32/pal_opengl_win32.h new file mode 100644 index 00000000..fdfff139 --- /dev/null +++ b/src/opengl/win32/pal_opengl_win32.h @@ -0,0 +1,187 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_OPENGL_WIN32_H +#define _PAL_OPENGL_WIN32_H +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE + +#include "pal/pal_opengl.h" +#include + +#define PAL_GL_CLASS L"PALGLClass" + +// check to see if this is not defined yet +#ifndef GL_VENDOR +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 +#endif // GL_VENDOR + +#ifndef WGL_NUMBER_PIXEL_FORMATS_ARB + +#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_RED_BITS_ARB 0x2015 +#define WGL_GREEN_BITS_ARB 0x2017 +#define WGL_BLUE_BITS_ARB 0x2019 +#define WGL_ALPHA_BITS_ARB 0x201b + +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_STEREO_ARB 0x2012 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_SAMPLES_ARB 0x2042 +#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 +#define WGL_TYPE_RGBA_ARB 0x202b +#define WGL_NO_ACCELERATION_ARB 0x2025 + +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 +#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 +#define WGL_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004 +#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define WGL_NO_RESET_NOTIFICATION_ARB 0x8261 +#define WGL_CONTEXT_OPENGL_NO_ERROR_ARB 0x31b3 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097 +#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 + +#define ERROR_INVALID_PROFILE_ARB 0x2096 + +#endif // WGL_NUMBER_PIXEL_FORMATS_ARB + +typedef unsigned int GLenum; +typedef unsigned char GLubyte; + +// gdi functions +typedef int(WINAPI* ChoosePixelFormatFn)( + HDC, + CONST PIXELFORMATDESCRIPTOR*); + +typedef BOOL(WINAPI* SetPixelFormatFn)( + HDC, + int, + CONST PIXELFORMATDESCRIPTOR*); + +typedef int(WINAPI* DescribePixelFormatFn)( + HDC, + int, + UINT, + LPPIXELFORMATDESCRIPTOR); + +typedef int(WINAPI* GetPixelFormatFn)(HDC); + +typedef BOOL(WINAPI* SwapBuffersFn)(HDC); + +// wgl functions +typedef PROC(WINAPI* wglGetProcAddressFn)(LPCSTR); + +typedef HGLRC(WINAPI* wglCreateContextFn)(HDC); + +typedef BOOL(WINAPI* wglDeleteContextFn)(HGLRC); + +typedef BOOL(WINAPI* wglShareListsFn)( + HGLRC, + HGLRC); + +typedef BOOL(WINAPI* wglMakeCurrentFn)( + HDC, + HGLRC); + +// gl functions +typedef const GLubyte*(WINAPI* glGetStringFn)(GLenum); + +// extensions +typedef BOOL(WINAPI* wglChoosePixelFormatARBFn)( + HDC, + const int*, + const FLOAT*, + UINT, + int*, + UINT*); + +typedef BOOL(WINAPI* wglGetPixelFormatAttribivARBFn)( + HDC, + int, + int, + UINT, + const int*, + int*); + +typedef HGLRC(WINAPI* wglCreateContextAttribsARBFn)( + HDC, + HGLRC, + const int*); + +typedef BOOL(WINAPI* wglSwapIntervalEXTFn)(int); + +typedef const char*(WINAPI* wglGetExtensionsStringEXTFn)(); + +typedef const char*(WINAPI* wglGetExtensionsStringARBFn)(HDC); + +typedef struct { + SetPixelFormatFn setPixelFormat; + DescribePixelFormatFn describePixelFormat; + ChoosePixelFormatFn choosePixelFormat; + GetPixelFormatFn getPixelFormat; + SwapBuffersFn swapBuffers; + HINSTANCE handle; +} Gdi; + +typedef struct { + PalBool initialized; + wglGetProcAddressFn wglGetProcAddress; + wglCreateContextFn wglCreateContext; + wglDeleteContextFn wglDeleteContext; + wglMakeCurrentFn wglMakeCurrent; + wglShareListsFn wglShareLists; + glGetStringFn glGetString; + + wglCreateContextAttribsARBFn wglCreateContextAttribsARB; + wglChoosePixelFormatARBFn wglChoosePixelFormatARB; + wglSwapIntervalEXTFn wglSwapIntervalEXT; + wglGetExtensionsStringEXTFn wglGetExtensionsStringEXT; + wglGetExtensionsStringARBFn wglGetExtensionsStringARB; + wglGetPixelFormatAttribivARBFn wglGetPixelFormatAttribivARB; + + const PalAllocator* allocator; + HINSTANCE opengl; + HINSTANCE instance; + HWND window; + HDC hdc; + HGLRC context; + PalGLInfo info; +} Wgl; + +extern Gdi s_Gdi; +extern Wgl s_Wgl; + +#endif // _WIN32 +#endif // _PAL_OPENGL_WIN32_H \ No newline at end of file diff --git a/src/thread/win32/pal_thread_win32.c b/src/thread/win32/pal_thread_win32.c index 314a96fb..b1dd8a0b 100644 --- a/src/thread/win32/pal_thread_win32.c +++ b/src/thread/win32/pal_thread_win32.c @@ -110,11 +110,12 @@ PalResult PAL_CALL palJoinThread( } DWORD wait = WaitForSingleObject((HANDLE)thread, INFINITE); - if (wait == WAIT_OBJECT_0 && retval) { - uintptr_t ret; - GetExitCodeThread((HANDLE)thread, (LPDWORD)&ret); - *retval = (void*)ret; - + if (wait == WAIT_OBJECT_0) { + if (retval) { + uintptr_t ret; + GetExitCodeThread((HANDLE)thread, (LPDWORD)&ret); + *retval = (void*)ret; + } // thread is done destroy the HANDLE CloseHandle((HANDLE)thread); diff --git a/src/video/win32/pal_window_win32.c b/src/video/win32/pal_window_win32.c index 2ff60611..1aac7cfb 100644 --- a/src/video/win32/pal_window_win32.c +++ b/src/video/win32/pal_window_win32.c @@ -198,7 +198,7 @@ PalResult PAL_CALL palCreateWindow( GetLastError()); } - s_Video.setPixelFormat(hdc, info->fbConfigBackend, &pfd); + s_Video.setPixelFormat(hdc, info->fbConfigIndex, &pfd); ReleaseDC(handle, hdc); } diff --git a/tests/opengl/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c index c141182f..6830e6d6 100644 --- a/tests/opengl/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -45,7 +45,6 @@ typedef struct { static void* PAL_CALL eventDriverWorker(void* arg) { - PalResult result; SharedState* shared = (SharedState*)arg; if (!shared) { palLog(nullptr, "Failed to get thread arg"); @@ -53,7 +52,7 @@ static void* PAL_CALL eventDriverWorker(void* arg) } PalEventDriverCreateInfo createInfo = {0}; - result = palCreateEventDriver(&createInfo, &shared->videoEventDriver); + PalResult result = palCreateEventDriver(&createInfo, &shared->videoEventDriver); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create event driver"); return nullptr; @@ -81,7 +80,6 @@ static void* PAL_CALL eventDriverWorker(void* arg) static void* PAL_CALL rendererWorkder(void* arg) { - PalResult result; SharedState* shared = (SharedState*)arg; if (!shared) { palLog(nullptr, "Failed to get thread arg"); @@ -89,7 +87,7 @@ static void* PAL_CALL rendererWorkder(void* arg) } // make the context current on the renderer thread - result = palMakeContextCurrent(&shared->window, shared->context); + PalResult result = palMakeContextCurrent(&shared->window, shared->context); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to make opengl context current"); return PAL_FALSE; @@ -129,7 +127,7 @@ static void* PAL_CALL rendererWorkder(void* arg) case PAL_EVENT_WINDOW_SIZE: { uint32_t width, height; palUnpackUint32(event.data, &width, &height); - palLog(nullptr, "Video driver sent a resize event (%d, %d)", width, height); + palLog(nullptr, "Video event driver sent a resize event (%d, %d)", width, height); glViewport(0, 0, width, height); // we can optionally send back a user event @@ -179,6 +177,7 @@ PalBool multiThreadOpenGlTest() palLog(nullptr, "Failed to allocate shared state"); return PAL_FALSE; } + memset(shared, 0, sizeof(SharedState)); // create a thread that creates two event drivers PalThreadCreateInfo threadCreateInfo = {0}; @@ -196,7 +195,11 @@ PalBool multiThreadOpenGlTest() // if not we wait for it if (!shared->driverCreated) { // this will be detached automatically when done - palJoinThread(eventDriverThread, nullptr); + result = palJoinThread(eventDriverThread, nullptr); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to join thread"); + return PAL_FALSE; + } } else { palDetachThread(eventDriverThread); // we dont need it anymore @@ -402,7 +405,11 @@ PalBool multiThreadOpenGlTest() // we wait for the render thread to finish with // the current frame and destroy the context - palJoinThread(rendererThread, nullptr); + result = palJoinThread(rendererThread, nullptr); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to join thread"); + return PAL_FALSE; + } palDestroyGLContext(shared->context); palShutdownGL(); diff --git a/tests/tests_main.c b/tests/tests_main.c index 3d62e53c..5d4e2f46 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -43,8 +43,7 @@ int main(int argc, char** argv) // registerTest(customDecorationTest, "Custom Decoration Test"); #endif // PAL_HAS_VIDEO_MODULE - // This test can run without video system so long as your have a valid - // window + // This test can run without video system so long as your have a valid window #if PAL_HAS_OPENGL_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 // registerTest(openglTest, "Opengl Test"); // registerTest(openglFBConfigTest, "Opengl FBConfig Test"); From 08557072bc34dbf165aa8df2b81276103fef322c Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 19 Jun 2026 11:23:33 +0000 Subject: [PATCH 283/372] add verbose flag to pal abi dump tool --- tools/abi_dump/abi_dump_main.c | 33 ++-- tools/abi_dump/core_abi_dump.c | 90 ++++++----- tools/abi_dump/dumps.h | 10 +- tools/abi_dump/event_abi_dump.c | 96 ++++++------ tools/abi_dump/system_abi_dump.c | 80 +++++----- tools/abi_dump/thread_abi_dump.c | 28 ++-- tools/abi_dump/video_abi_dump.c | 254 ++++++++++++++++--------------- 7 files changed, 314 insertions(+), 277 deletions(-) diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index ca97e6de..e44a3713 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -29,6 +29,7 @@ int main(int argc, char** argv) PalBool dumpVideo = PAL_FALSE; PalBool dumpVersion = PAL_FALSE; PalBool dumpHelp = PAL_FALSE; + PalBool verbose = PAL_FALSE; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--all") == 0) { @@ -60,6 +61,9 @@ int main(int argc, char** argv) } else if (strcmp(argv[i], "--help") == 0) { dumpHelp = PAL_TRUE; + + } else if (strcmp(argv[i], "--verbose") == 0) { + verbose = PAL_TRUE; } } @@ -74,23 +78,23 @@ int main(int argc, char** argv) } if (dumpCore) { - coreABIDump(); + coreABIDump(verbose); } if (dumpEvent) { - eventABIDump(); + eventABIDump(verbose); } if (dumpThread) { - threadABIDump(); + threadABIDump(verbose); } if (dumpSystem) { - systemABIDump(); + systemABIDump(verbose); } if (dumpVideo) { - videoABIDump(); + videoABIDump(verbose); } if (dumpVersion) { @@ -101,15 +105,16 @@ int main(int argc, char** argv) palLog(nullptr, "USAGE: %s [options]", EXE_NAME); palLog(nullptr, "Options:"); palLog(nullptr, " --help Display available options"); - palLog(nullptr, " --version Display ABI dump version information"); - palLog(nullptr, " --all Display all PAL structs ABI information"); - palLog(nullptr, " --core Display PAL core structs ABI information"); - palLog(nullptr, " --event Display PAL event structs ABI information"); - palLog(nullptr, " --graphics Display PAL graphics structs ABI information"); - palLog(nullptr, " --opengl Display PAL opengl structs ABI information"); - palLog(nullptr, " --system Display PAL system structs ABI information"); - palLog(nullptr, " --thread Display PAL thread structs ABI information"); - palLog(nullptr, " --video Display PAL video structs ABI information"); + palLog(nullptr, " --version Display version"); + palLog(nullptr, " --verbose Display ABI dump information"); + palLog(nullptr, " --all Check ABI for all PAL structs"); + palLog(nullptr, " --core Check ABI for core PAL structs"); + palLog(nullptr, " --event Check ABI for event PAL structs"); + palLog(nullptr, " --graphics Check ABI for graphics PAL structs"); + palLog(nullptr, " --opengl Check ABI for opengl PAL structs"); + palLog(nullptr, " --system Check ABI for system PAL structs"); + palLog(nullptr, " --thread Check ABI for thread PAL structs"); + palLog(nullptr, " --video Check ABI for video PAL structs"); } return 0; diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c index 455cfb79..467a3963 100644 --- a/tools/abi_dump/core_abi_dump.c +++ b/tools/abi_dump/core_abi_dump.c @@ -7,7 +7,7 @@ #include "dumps.h" -static void versionDump() +static void versionDump(PalBool verbose) { uint32_t xSize = 12; uint32_t xAlign = 4; @@ -35,24 +35,26 @@ static void versionDump() } // clang-format on - palLog(nullptr, "PalVersion"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "major @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "minor @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "build @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalVersion"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "major @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "minor @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "build @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void allocatorDump() +static void allocatorDump(PalBool verbose) { uint32_t xSize = 24; uint32_t xAlign = 8; @@ -80,24 +82,26 @@ static void allocatorDump() } // clang-format on - palLog(nullptr, "PalAllocator"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "allocate @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "free @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "userData @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalAllocator"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "allocate @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "free @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "userData @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void loggerDump() +static void loggerDump(PalBool verbose) { uint32_t xSize = 16; uint32_t xAlign = 8; @@ -122,23 +126,25 @@ static void loggerDump() } // clang-format on - palLog(nullptr, "PalLogger"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "allocate @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "userData @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalLogger"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "allocate @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "userData @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -void coreABIDump() +void coreABIDump(PalBool verbose) { palLog(nullptr, ""); palLog(nullptr, "==========================================="); @@ -146,7 +152,7 @@ void coreABIDump() palLog(nullptr, "==========================================="); palLog(nullptr, ""); - versionDump(); - allocatorDump(); - loggerDump(); + versionDump(verbose); + allocatorDump(verbose); + loggerDump(verbose); } \ No newline at end of file diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 9451d5b7..403ed57a 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -20,10 +20,10 @@ static const char* s_PassedString = "PASSED"; #define PAL_ALIGNOF(type) __alignof__(type) #endif // _MSC_VER -void coreABIDump(); -void eventABIDump(); -void threadABIDump(); -void systemABIDump(); -void videoABIDump(); +void coreABIDump(PalBool verbose); +void eventABIDump(PalBool verbose); +void threadABIDump(PalBool verbose); +void systemABIDump(PalBool verbose); +void videoABIDump(PalBool verbose); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index 3d5f69c2..b7ec75f0 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -8,7 +8,7 @@ #include "dumps.h" #include "pal/pal_event.h" -static void eventDump() +static void eventDump(PalBool verbose) { uint32_t xSize = 32; uint32_t xAlign = 8; @@ -39,25 +39,27 @@ static void eventDump() } // clang-format on - palLog(nullptr, "PalEvent"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "userId @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "data @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "data2 @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "type @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalEvent"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "userId @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "data @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "data2 @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "type @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void eventQueueDump() +static void eventQueueDump(PalBool verbose) { uint32_t xSize = 24; uint32_t xAlign = 8; @@ -85,24 +87,26 @@ static void eventQueueDump() } // clang-format on - palLog(nullptr, "PalEventQueue"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "push @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "poll @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "userData @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalEventQueue"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "push @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "poll @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "userData @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void eventCreateInfoDump() +static void eventCreateInfoDump(PalBool verbose) { uint32_t xSize = 32; uint32_t xAlign = 8; @@ -133,25 +137,27 @@ static void eventCreateInfoDump() } // clang-format on - palLog(nullptr, "PalEventDriverCreateInfo"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "allocator @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "queue @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "callback @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "userData @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalEventDriverCreateInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "allocator @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "queue @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "callback @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "userData @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -void eventABIDump() +void eventABIDump(PalBool verbose) { palLog(nullptr, ""); palLog(nullptr, "==========================================="); @@ -159,7 +165,7 @@ void eventABIDump() palLog(nullptr, "==========================================="); palLog(nullptr, ""); - eventDump(); - eventQueueDump(); - eventCreateInfoDump(); + eventDump(verbose); + eventQueueDump(verbose); + eventCreateInfoDump(verbose); } \ No newline at end of file diff --git a/tools/abi_dump/system_abi_dump.c b/tools/abi_dump/system_abi_dump.c index 4fd15c92..6e9aca75 100644 --- a/tools/abi_dump/system_abi_dump.c +++ b/tools/abi_dump/system_abi_dump.c @@ -8,7 +8,7 @@ #include "dumps.h" #include "pal/pal_system.h" -static void platformDump() +static void platformDump(PalBool verbose) { uint32_t xSize = 60; uint32_t xAlign = 4; @@ -45,27 +45,29 @@ static void platformDump() } // clang-format on - palLog(nullptr, "PalPlatformInfo"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "type @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "apiType @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "totalMemory @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "totalRAM @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "version @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "name @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalPlatformInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "type @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "apiType @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "totalMemory @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "totalRAM @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "version @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "name @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void cpuDump() +static void cpuDump(PalBool verbose) { uint32_t xSize = 112; uint32_t xAlign = 8; @@ -111,30 +113,32 @@ static void cpuDump() } // clang-format on - palLog(nullptr, "PalCPUInfo"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "features @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "architecture @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "numCores @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "cacheL1 @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "cacheL2 @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "cacheL3 @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "numLogicalProcessors @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "vendor @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "model @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalCPUInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "features @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "architecture @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "numCores @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "cacheL1 @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "cacheL2 @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "cacheL3 @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "numLogicalProcessors @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "vendor @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "model @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -void systemABIDump() +void systemABIDump(PalBool verbose) { palLog(nullptr, ""); palLog(nullptr, "==========================================="); @@ -142,6 +146,6 @@ void systemABIDump() palLog(nullptr, "==========================================="); palLog(nullptr, ""); - platformDump(); - cpuDump(); + platformDump(verbose); + cpuDump(verbose); } \ No newline at end of file diff --git a/tools/abi_dump/thread_abi_dump.c b/tools/abi_dump/thread_abi_dump.c index 6419378e..dfd6ddf9 100644 --- a/tools/abi_dump/thread_abi_dump.c +++ b/tools/abi_dump/thread_abi_dump.c @@ -8,7 +8,7 @@ #include "dumps.h" #include "pal/pal_thread.h" -void threadABIDump() +void threadABIDump(PalBool verbose) { palLog(nullptr, ""); palLog(nullptr, "==========================================="); @@ -42,18 +42,20 @@ void threadABIDump() } // clang-format on - palLog(nullptr, "PalThreadCreateInfo"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "stackSize @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "allocator @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "entry @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "arg @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalThreadCreateInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "stackSize @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "allocator @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "entry @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "arg @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index 4269d258..002d0aab 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -8,7 +8,7 @@ #include "dumps.h" #include "pal/pal_video.h" -static void monitorDump() +static void monitorDump(PalBool verbose) { uint32_t xSize = 64; uint32_t xAlign = 4; @@ -54,30 +54,32 @@ static void monitorDump() } // clang-format on - palLog(nullptr, "PalMonitorInfo"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "x @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "y @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "width @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "height @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "dpi @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "refreshRate @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "orientation @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "primary @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "name @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalMonitorInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "x @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "y @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "width @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "height @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "dpi @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "refreshRate @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "orientation @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "primary @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "name @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void monitorModeDump() +static void monitorModeDump(PalBool verbose) { uint32_t xSize = 16; uint32_t xAlign = 4; @@ -108,25 +110,27 @@ static void monitorModeDump() } // clang-format on - palLog(nullptr, "PalMonitorMode"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "bpp @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "refreshRate @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "width @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "height @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalMonitorMode"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "bpp @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "refreshRate @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "width @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "height @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void flashDump() +static void flashDump(PalBool verbose) { uint32_t xSize = 16; uint32_t xAlign = 8; @@ -154,24 +158,26 @@ static void flashDump() } // clang-format on - palLog(nullptr, "PalFlashInfo"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "flags @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "interval @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "count @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalFlashInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "flags @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "interval @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "count @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void iconDump() +static void iconDump(PalBool verbose) { uint32_t xSize = 16; uint32_t xAlign = 8; @@ -199,24 +205,26 @@ static void iconDump() } // clang-format on - palLog(nullptr, "PalIconCreateInfo"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "pixels @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "width @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "height @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalIconCreateInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "pixels @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "width @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "height @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void cursorDump() +static void cursorDump(PalBool verbose) { uint32_t xSize = 24; uint32_t xAlign = 8; @@ -250,26 +258,28 @@ static void cursorDump() } // clang-format on - palLog(nullptr, "PalCursorCreateInfo"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "pixels @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "width @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "height @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "xHotspot @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "yHotspot @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalCursorCreateInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "pixels @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "width @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "height @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "xHotspot @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "yHotspot @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void windowInfoDump() +static void windowInfoDump(PalBool verbose) { uint32_t xSize = 40; uint32_t xAlign = 8; @@ -303,26 +313,28 @@ static void windowInfoDump() } // clang-format on - palLog(nullptr, "PalWindowHandleInfo"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "nativeDisplay @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "nativeWindow @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "nativeHandle1 @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "nativeHandle2 @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "nativeHandle3 @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalWindowHandleInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "nativeDisplay @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "nativeWindow @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "nativeHandle1 @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "nativeHandle2 @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "nativeHandle3 @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -static void windowDump() +static void windowDump(PalBool verbose) { uint32_t xSize = 72; uint32_t xAlign = 8; @@ -380,34 +392,36 @@ static void windowDump() } // clang-format on - palLog(nullptr, "PalWindowCreateInfo"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "style @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "title @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "monitor @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "appName @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "instanceName @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "fbConfigBackend @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "fbConfigIndex @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "width @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "height @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "show @ %u %u", xOffset10, yOffset10); - palLog(nullptr, "maximized @ %u %u", xOffset11, yOffset11); - palLog(nullptr, "minimized @ %u %u", xOffset12, yOffset12); - palLog(nullptr, "center @ %u %u", xOffset13, yOffset13); - palLog(nullptr, "==========================================="); + palLog(nullptr, "struct: PalWindowCreateInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "style @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "title @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "monitor @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "appName @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "instanceName @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "fbConfigBackend @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "fbConfigIndex @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "width @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "height @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "show @ %u %u", xOffset10, yOffset10); + palLog(nullptr, "maximized @ %u %u", xOffset11, yOffset11); + palLog(nullptr, "minimized @ %u %u", xOffset12, yOffset12); + palLog(nullptr, "center @ %u %u", xOffset13, yOffset13); + palLog(nullptr, "==========================================="); + } palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); } -void videoABIDump() +void videoABIDump(PalBool verbose) { palLog(nullptr, ""); palLog(nullptr, "==========================================="); @@ -415,11 +429,11 @@ void videoABIDump() palLog(nullptr, "==========================================="); palLog(nullptr, ""); - monitorDump(); - monitorModeDump(); - flashDump(); - iconDump(); - cursorDump(); - windowInfoDump(); - windowDump(); + monitorDump(verbose); + monitorModeDump(verbose); + flashDump(verbose); + iconDump(verbose); + cursorDump(verbose); + windowInfoDump(verbose); + windowDump(verbose); } \ No newline at end of file From 5e0b8f02a4c64f01701fcaffda58f4147bef69b9 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 19 Jun 2026 12:53:17 +0000 Subject: [PATCH 284/372] add opengl abi dump --- tools/abi_dump/abi_dump.lua | 1 + tools/abi_dump/abi_dump_main.c | 4 + tools/abi_dump/dumps.h | 1 + tools/abi_dump/opengl_abi_dump.c | 291 +++++++++++++++++++++++++++++++ 4 files changed, 297 insertions(+) create mode 100644 tools/abi_dump/opengl_abi_dump.c diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index 1cd05635..4aac0393 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -11,6 +11,7 @@ project "pal-abi-dump" "thread_abi_dump.c", "system_abi_dump.c", "video_abi_dump.c", + "opengl_abi_dump.c", "abi_dump_main.c" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index e44a3713..507174b8 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -97,6 +97,10 @@ int main(int argc, char** argv) videoABIDump(verbose); } + if (dumpOpengl) { + openglABIDump(verbose); + } + if (dumpVersion) { palLog(nullptr, "PAL ABI dump %s", VERSION); } diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 403ed57a..9eeca320 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -25,5 +25,6 @@ void eventABIDump(PalBool verbose); void threadABIDump(PalBool verbose); void systemABIDump(PalBool verbose); void videoABIDump(PalBool verbose); +void openglABIDump(PalBool verbose); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/opengl_abi_dump.c b/tools/abi_dump/opengl_abi_dump.c new file mode 100644 index 00000000..f66f0eec --- /dev/null +++ b/tools/abi_dump/opengl_abi_dump.c @@ -0,0 +1,291 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "dumps.h" +#include "pal/pal_opengl.h" + +static void infoDump(PalBool verbose) +{ + uint32_t xSize = 184; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 12; + uint32_t xOffset4 = 16; + uint32_t xOffset5 = 20; + uint32_t xOffset6 = 24; + uint32_t xOffset7 = 56; + uint32_t xOffset8 = 120; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalGLInfo); + uint32_t yAlign = PAL_ALIGNOF(PalGLInfo); + uint32_t yOffset1 = offsetof(PalGLInfo, extensions); + uint32_t yOffset2 = offsetof(PalGLInfo, major); + uint32_t yOffset3 = offsetof(PalGLInfo, minor); + uint32_t yOffset4 = offsetof(PalGLInfo, backend); + uint32_t yOffset5 = offsetof(PalGLInfo, api); + uint32_t yOffset6 = offsetof(PalGLInfo, vendor); + uint32_t yOffset7 = offsetof(PalGLInfo, graphicsCard); + uint32_t yOffset8 = offsetof(PalGLInfo, version); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xOffset6 == yOffset6 && + xOffset7 == yOffset7 && + xOffset8 == yOffset8 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "struct: PalGLInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "extensions @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "major @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "minor @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "backend @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "api @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "vendor @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "graphicsCard @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "version @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "==========================================="); + } + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void configDump(PalBool verbose) +{ + uint32_t xSize = 28; + uint32_t xAlign = 4; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 4; + uint32_t xOffset3 = 8; + uint32_t xOffset4 = 12; + uint32_t xOffset5 = 14; + uint32_t xOffset6 = 16; + uint32_t xOffset7 = 18; + uint32_t xOffset8 = 20; + uint32_t xOffset9 = 22; + uint32_t xOffset10 = 24; + uint32_t xOffset11 = 26; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalGLFBConfig); + uint32_t yAlign = PAL_ALIGNOF(PalGLFBConfig); + uint32_t yOffset1 = offsetof(PalGLFBConfig, doubleBuffer); + uint32_t yOffset2 = offsetof(PalGLFBConfig, stereo); + uint32_t yOffset3 = offsetof(PalGLFBConfig, sRGB); + uint32_t yOffset4 = offsetof(PalGLFBConfig, index); + uint32_t yOffset5 = offsetof(PalGLFBConfig, redBits); + uint32_t yOffset6 = offsetof(PalGLFBConfig, greenBits); + uint32_t yOffset7 = offsetof(PalGLFBConfig, blueBits); + uint32_t yOffset8 = offsetof(PalGLFBConfig, alphaBits); + uint32_t yOffset9 = offsetof(PalGLFBConfig, depthBits); + uint32_t yOffset10 = offsetof(PalGLFBConfig, stencilBits); + uint32_t yOffset11 = offsetof(PalGLFBConfig, samples); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xOffset6 == yOffset6 && + xOffset7 == yOffset7 && + xOffset8 == yOffset8 && + xOffset9 == yOffset9 && + xOffset10 == yOffset10 && + xOffset11 == yOffset11 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "struct: PalGLFBConfig"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "doubleBuffer @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "stereo @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "sRGB @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "index @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "redBits @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "greenBits @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "blueBits @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "alphaBits @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "depthBits @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "stencilBits @ %u %u", xOffset10, yOffset10); + palLog(nullptr, "samples @ %u %u", xOffset11, yOffset11); + palLog(nullptr, "==========================================="); + } + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void windowDump(PalBool verbose) +{ + uint32_t xSize = 16; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalGLWindow); + uint32_t yAlign = PAL_ALIGNOF(PalGLWindow); + uint32_t yOffset1 = offsetof(PalGLWindow, display); + uint32_t yOffset2 = offsetof(PalGLWindow, window); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "struct: PalGLWindow"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "display @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "window @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "==========================================="); + } + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void contextDump(PalBool verbose) +{ + uint32_t xSize = 56; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 16; + uint32_t xOffset4 = 24; + uint32_t xOffset5 = 28; + uint32_t xOffset6 = 32; + uint32_t xOffset7 = 36; + uint32_t xOffset8 = 40; + uint32_t xOffset9 = 44; + uint32_t xOffset10 = 48; + uint32_t xOffset11 = 52; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalGLContextCreateInfo); + uint32_t yAlign = PAL_ALIGNOF(PalGLContextCreateInfo); + uint32_t yOffset1 = offsetof(PalGLContextCreateInfo, window); + uint32_t yOffset2 = offsetof(PalGLContextCreateInfo, fbConfig); + uint32_t yOffset3 = offsetof(PalGLContextCreateInfo, shareContext); + uint32_t yOffset4 = offsetof(PalGLContextCreateInfo, profile); + uint32_t yOffset5 = offsetof(PalGLContextCreateInfo, reset); + uint32_t yOffset6 = offsetof(PalGLContextCreateInfo, release); + uint32_t yOffset7 = offsetof(PalGLContextCreateInfo, forward); + uint32_t yOffset8 = offsetof(PalGLContextCreateInfo, noError); + uint32_t yOffset9 = offsetof(PalGLContextCreateInfo, debug); + uint32_t yOffset10 = offsetof(PalGLContextCreateInfo, major); + uint32_t yOffset11 = offsetof(PalGLContextCreateInfo, minor); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xOffset6 == yOffset6 && + xOffset7 == yOffset7 && + xOffset8 == yOffset8 && + xOffset9 == yOffset9 && + xOffset10 == yOffset10 && + xOffset11 == yOffset11 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "struct: PalGLContextCreateInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "window @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "fbConfig @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "shareContext @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "profile @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "reset @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "release @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "forward @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "noError @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "debug @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "major @ %u %u", xOffset10, yOffset10); + palLog(nullptr, "minor @ %u %u", xOffset11, yOffset11); + palLog(nullptr, "==========================================="); + } + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +void openglABIDump(PalBool verbose) +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Opengl ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + infoDump(verbose); + configDump(verbose); + windowDump(verbose); + contextDump(verbose); +} \ No newline at end of file From be5214ff87d0b137a8293e92000632c5ac4a1827 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 19 Jun 2026 16:22:25 +0000 Subject: [PATCH 285/372] prepare graphics API rewrite --- include/pal/pal_graphics.h | 1465 ++++++++++++++++++------------------ 1 file changed, 712 insertions(+), 753 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 899ef567..e01e67a5 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -16,56 +16,16 @@ #include "pal_core.h" -/** - * @brief The maximum name size of an adapter (GPU). - * @since 1.4 - */ #define PAL_ADAPTER_NAME_SIZE 128 - -/** - * @brief The maximum name size of a shader entry. - * @since 1.4 - */ #define PAL_SHADER_ENTRY_NAME_SIZE 32 - #define PAL_MAX_RESOLVE_MODES 8 #define PAL_MAX_COMBINER_OPS 8 -/** - * @brief A Unused shader index. Used to make a shader index invalid. - * @since 1.4 - */ #define PAL_UNUSED_SHADER_INDEX UINT32_MAX - -/** - * @brief An encoding scheme for shader format target versions. - * @since 1.4 - */ #define PAL_MAKE_SHADER_TARGET(major, minor) ((uint32_t)((major) << 8) | (minor)) - -/** - * @brief Get the major of an encoded shader target. - * @since 1.4 - */ #define PAL_SHADER_TARGET_MAJOR(target) ((uint32_t)(target) >> 8); - -/** - * @brief Get the minor of an encoded shader target. - * @since 1.4 - */ #define PAL_SHADER_TARGET_MINOR(target) ((uint32_t)(target) & 0xFF); -/** - * @typedef PalAdapterFeatures - * @brief Adapter features. This is a bitmask. - * - * All adapter features follow the format `PAL_ADAPTER_FEATURE_**` for - * consistency and API use. - * - * @since 1.4 - */ -typedef uint64_t PalAdapterFeatures; - #define PAL_ADAPTER_FEATURE_NONE 0; #define PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY (1ULL << 1) #define PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING (1ULL << 2) @@ -106,11 +66,352 @@ typedef uint64_t PalAdapterFeatures; #define PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS (1ULL << 37) #define PAL_ADAPTER_FEATURE_RAY_QUERY (1ULL << 38) +#define PAL_ADAPTER_TYPE_UNKNOWN 0 +#define PAL_ADAPTER_TYPE_DISCRETE 1 +#define PAL_ADAPTER_TYPE_INTEGRATED 2 +#define PAL_ADAPTER_TYPE_VIRTUAL 3 +#define PAL_ADAPTER_TYPE_CPU 4 + +#define PAL_ADAPTER_API_TYPE_VULKAN 0 +#define PAL_ADAPTER_API_TYPE_D3D12 1 +#define PAL_ADAPTER_API_TYPE_METAL 2 +#define PAL_ADAPTER_API_TYPE_CUSTOM 3 + +#define PAL_QUEUE_TYPE_GRAPHICS 0 +#define PAL_QUEUE_TYPE_COMPUTE 1 +#define PAL_QUEUE_TYPE_COPY 2 + +/** V-Sync.*/ +#define PAL_PRESENT_MODE_FIFO 0 +#define PAL_PRESENT_MODE_IMMEDIATE 1 +#define PAL_PRESENT_MODE_MAILBOX 2 +#define PAL_PRESENT_MODE_MAX 3 + +#define PAL_COMPOSITE_ALPHA_OPAQUE 0 +#define PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED 1 +#define PAL_COMPOSITE_ALPHA_POST_MULTIPLIED 2 +#define PAL_COMPOSITE_ALPHA_MAX 3 + +#define PAL_FORMAT_UNDEFINED 0 +#define PAL_FORMAT_R8_UNORM 1 +#define PAL_FORMAT_R8_SNORM 2 +#define PAL_FORMAT_R8_UINT 3 +#define PAL_FORMAT_R8_SINT 4 +#define PAL_FORMAT_R8_SRGB 5 +#define PAL_FORMAT_R16_UNORM 6 +#define PAL_FORMAT_R16_SNORM 7 +#define PAL_FORMAT_R16_UINT 8 +#define PAL_FORMAT_R16_SINT 9 +#define PAL_FORMAT_R16_SFLOAT 10 +#define PAL_FORMAT_R32_UINT 11 +#define PAL_FORMAT_R32_SINT 12 +#define PAL_FORMAT_R32_SFLOAT 13 +#define PAL_FORMAT_R64_UINT 14 +#define PAL_FORMAT_R64_SINT 15 +#define PAL_FORMAT_R64_SFLOAT 16 +#define PAL_FORMAT_R8G8_UNORM 17 +#define PAL_FORMAT_R8G8_SNORM 18 +#define PAL_FORMAT_R8G8_UINT 19 +#define PAL_FORMAT_R8G8_SINT 20 +#define PAL_FORMAT_R8G8_SRGB 21 +#define PAL_FORMAT_R16G16_UNORM 22 +#define PAL_FORMAT_R16G16_SNORM 23 +#define PAL_FORMAT_R16G16_UINT 24 +#define PAL_FORMAT_R16G16_SINT 25 +#define PAL_FORMAT_R16G16_SFLOAT 26 +#define PAL_FORMAT_R32G32_UINT 27 +#define PAL_FORMAT_R32G32_SINT 28 +#define PAL_FORMAT_R32G32_SFLOAT 29 +#define PAL_FORMAT_R64G64_UINT 30 +#define PAL_FORMAT_R64G64_SINT 31 +#define PAL_FORMAT_R64G64_SFLOAT 32 +#define PAL_FORMAT_R8G8B8_UNORM 33 +#define PAL_FORMAT_R8G8B8_SNORM 34 +#define PAL_FORMAT_R8G8B8_UINT 35 +#define PAL_FORMAT_R8G8B8_SINT 36 +#define PAL_FORMAT_R8G8B8_SRGB 37 +#define PAL_FORMAT_R16G16B16_UNORM 38 +#define PAL_FORMAT_R16G16B16_SNORM 39 +#define PAL_FORMAT_R16G16B16_UINT 40 +#define PAL_FORMAT_R16G16B16_SINT 41 +#define PAL_FORMAT_R16G16B16_SFLOAT 42 +#define PAL_FORMAT_R32G32B32_UINT 43 +#define PAL_FORMAT_R32G32B32_SINT 44 +#define PAL_FORMAT_R32G32B32_SFLOAT 45 +#define PAL_FORMAT_R64G64B64_UINT 46 +#define PAL_FORMAT_R64G64B64_SINT 47 +#define PAL_FORMAT_R64G64B64_SFLOAT 48 +#define PAL_FORMAT_B8G8R8_UNORM 49 +#define PAL_FORMAT_B8G8R8_SNORM 50 +#define PAL_FORMAT_B8G8R8_UINT 51 +#define PAL_FORMAT_B8G8R8_SINT 52 +#define PAL_FORMAT_B8G8R8_SRGB 53 +#define PAL_FORMAT_R8G8B8A8_UNORM 54 +#define PAL_FORMAT_R8G8B8A8_SNORM 55 +#define PAL_FORMAT_R8G8B8A8_UINT 56 +#define PAL_FORMAT_R8G8B8A8_SINT 57 +#define PAL_FORMAT_R8G8B8A8_SRGB 58 +#define PAL_FORMAT_R16G16B16A16_UNORM 59 +#define PAL_FORMAT_R16G16B16A16_SNORM 60 +#define PAL_FORMAT_R16G16B16A16_UINT 61 +#define PAL_FORMAT_R16G16B16A16_SINT 62 +#define PAL_FORMAT_R16G16B16A16_SFLOAT 63 +#define PAL_FORMAT_R32G32B32A32_UINT 64 +#define PAL_FORMAT_R32G32B32A32_SINT 65 +#define PAL_FORMAT_R32G32B32A32_SFLOAT 66 +#define PAL_FORMAT_R64G64B64A64_UINT 67 +#define PAL_FORMAT_R64G64B64A64_SINT 68 +#define PAL_FORMAT_R64G64B64A64_SFLOAT 69 +#define PAL_FORMAT_B8G8R8A8_UNORM 70 +#define PAL_FORMAT_B8G8R8A8_SNORM 71 +#define PAL_FORMAT_B8G8R8A8_UINT 72 +#define PAL_FORMAT_B8G8R8A8_SINT 73 +#define PAL_FORMAT_B8G8R8A8_SRGB 74 +#define PAL_FORMAT_S8_UINT 75 +#define PAL_FORMAT_D16_UNORM 76 +#define PAL_FORMAT_D32_SFLOAT 77 +#define PAL_FORMAT_D16_UNORM_S8_UINT 78 +#define PAL_FORMAT_D32_SFLOAT_S8_UINT 79 +#define PAL_FORMAT_D24_UNORM_S8_UINT 80 +#define PAL_FORMAT_MAX 81 + +#define PAL_IMAGE_USAGE_UNDEFINED 0 +#define PAL_IMAGE_USAGE_COLOR_ATTACHEMENT (1ULL << 0) +#define PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT (1ULL << 1) +#define PAL_IMAGE_USAGE_TRANSFER_SRC (1ULL << 2) +#define PAL_IMAGE_USAGE_TRANSFER_DST (1ULL << 3) +#define PAL_IMAGE_USAGE_STORAGE (1ULL << 4) +#define PAL_IMAGE_USAGE_SAMPLED (1ULL << 5) + +#define PAL_SHADER_FORMAT_SPIRV (1ULL << 0) +#define PAL_SHADER_FORMAT_DXIL (1ULL << 1) +#define PAL_SHADER_FORMAT_MSL (1ULL << 2) +#define PAL_SHADER_FORMAT_CUSTOM (1ULL << 3) + +#define PAL_LOAD_OP_LOAD 0 +#define PAL_LOAD_OP_CLEAR 1 +#define PAL_LOAD_OP_DONT_CARE 2 + +#define PAL_STORE_OP_STORE 0 +#define PAL_STORE_OP_DONT_CARE 1 + +#define PAL_MEMORY_TYPE_GPU_ONLY 0 +#define PAL_MEMORY_TYPE_CPU_UPLOAD 1 +#define PAL_MEMORY_TYPE_CPU_READBACK 2 +#define PAL_MEMORY_TYPE_MAX 3 + +#define PAL_IMAGE_TYPE_1D 0 +#define PAL_IMAGE_TYPE_2D 1 +#define PAL_IMAGE_TYPE_3D 2 + +#define PAL_IMAGE_ASPECT_COLOR 0 +#define PAL_IMAGE_ASPECT_DEPTH 1 +#define PAL_IMAGE_ASPECT_STENCIL 2 +#define PAL_IMAGE_ASPECT_DEPTH_STENCIL 3 + +#define PAL_IMAGE_VIEW_TYPE_1D 0 +#define PAL_IMAGE_VIEW_TYPE_1D_ARRAY 1 +#define PAL_IMAGE_VIEW_TYPE_2D 2 +#define PAL_IMAGE_VIEW_TYPE_2D_ARRAY 3 +#define PAL_IMAGE_VIEW_TYPE_3D 4 +#define PAL_IMAGE_VIEW_TYPE_CUBE 5 +#define PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY 6 + +#define PAL_FILTER_MODE_NEAREST 0 +#define PAL_FILTER_MODE_LINEAR 1 + +#define PAL_SAMPLER_MIPMAP_MODE_NEAREST 0 +#define PAL_SAMPLER_MIPMAP_MODE_LINEAR 1 + +#define PAL_SAMPLER_ADDRESS_MODE_REPEAT 0 +#define PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT 1 +#define PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE 2 +#define PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER 3 + +#define PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK 0 +#define PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK 1 +#define PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK 2 +#define PAL_BORDER_COLOR_INT_OPAQUE_BLACK 3 +#define PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE 4 +#define PAL_BORDER_COLOR_INT_OPAQUE_WHITE 5 + +#define PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR 0 +#define PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR 1 +#define PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR 2 +#define PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10 3 /**< HDR.*/ +#define PAL_SURFACE_FORMAT_MAX 4 + +#define PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND 0 +#define PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11 1 +#define PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB 2 + +#define PAL_SHADER_STAGE_UNDEFINED 0 +#define PAL_SHADER_STAGE_VERTEX 1 +#define PAL_SHADER_STAGE_FRAGMENT 2 +#define PAL_SHADER_STAGE_COMPUTE 3 +#define PAL_SHADER_STAGE_GEOMETRY 4 +#define PAL_SHADER_STAGE_MESH 5 +#define PAL_SHADER_STAGE_TASK 6 +#define PAL_SHADER_STAGE_TESSELLATION_CONTROL 7 +#define PAL_SHADER_STAGE_TESSELLATION_EVALUATION 8 +#define PAL_SHADER_STAGE_RAYGEN 9 +#define PAL_SHADER_STAGE_CLOSEST_HIT 10 +#define PAL_SHADER_STAGE_ANY_HIT 11 +#define PAL_SHADER_STAGE_MISS 12 +#define PAL_SHADER_STAGE_INTERSECTION 13 +#define PAL_SHADER_STAGE_CALLABLE 14 + +#define PAL_SAMPLE_COUNT_1 0 +#define PAL_SAMPLE_COUNT_2 1 +#define PAL_SAMPLE_COUNT_4 2 +#define PAL_SAMPLE_COUNT_8 3 +#define PAL_SAMPLE_COUNT_16 4 +#define PAL_SAMPLE_COUNT_32 5 +#define PAL_SAMPLE_COUNT_64 6 + +#define PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST 0 +#define PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP 1 +#define PAL_PRIMITIVE_TOPOLOGY_LINE_LIST 2 +#define PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP 3 +#define PAL_PRIMITIVE_TOPOLOGY_POINT_LIST 4 +#define PAL_PRIMITIVE_TOPOLOGY_PATCH 5 + +#define PAL_CULL_MODE_NONE 0 +#define PAL_CULL_MODE_FRONT 1 +#define PAL_CULL_MODE_BACK 2 + +#define PAL_FRONT_FACE_CLOCKWISE 0 +#define PAL_FRONT_FACE_COUNTER_CLOCKWISE 1 + +#define PAL_POLYGON_MODE_FILL 0 +#define PAL_POLYGON_MODE_LINE 1 + +#define PAL_STENCIL_FACE_FRONT (1ULL << 0) +#define PAL_STENCIL_FACE_BACK (1ULL << 1) +#define PAL_STENCIL_FACE_BOTH (PAL_STENCIL_FACE_FRONT | PAL_STENCIL_FACE_BACK) + +#define PAL_VERTEX_TYPE_UNDEFINED 0 +#define PAL_VERTEX_TYPE_INT32 1 /**< int32_t.*/ +#define PAL_VERTEX_TYPE_INT32_2 2 /**< int32_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_INT32_3 3 /**< int32_t vec3 or array[3].*/ +#define PAL_VERTEX_TYPE_INT32_4 4 /**< int32_t vec4 or array[4].*/ + +#define PAL_VERTEX_TYPE_UINT32 5 /**< uint32_t.*/ +#define PAL_VERTEX_TYPE_UINT32_2 6 /**< uint32_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_UINT32_3 7 /**< uint32_t vec3 or array[3].*/ +#define PAL_VERTEX_TYPE_UINT32_4 8 /**< uint32_t vec4 or array[4].*/ + +#define PAL_VERTEX_TYPE_INT8_2 9 /**< int8_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_INT8_4 10 /**< int8_t vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_UINT8_2 11 /**< uint8_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_UINT8_4 12 /**< uint8_t vec4 or array[4].*/ + +#define PAL_VERTEX_TYPE_INT8_2NORM 13 /**< int8_t vec2 or array[2] normalized.*/ +#define PAL_VERTEX_TYPE_INT8_4NORM 14 /**< int8_t vec4 or array[4] normalized.*/ +#define PAL_VERTEX_TYPE_UINT8_2NORM 15 /**< uint8_t vec2 or array[2] normalized.*/ +#define PAL_VERTEX_TYPE_UINT8_4NORM 16 /**< uint8_t vec4 or array[4] normalized.*/ + +#define PAL_VERTEX_TYPE_INT16_2 17 /**< int16_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_INT16_4 18 /**< int16_t vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_UINT16_2 19 /**< uint16_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_UINT16_4 20 /**< uint16_t vec4 or array[4].*/ + +#define PAL_VERTEX_TYPE_INT16_2NORM 21 /**< int16_t vec2 or array[2] normalized.*/ +#define PAL_VERTEX_TYPE_INT16_4NORM 22 /**< int16_t vec4 or array[4] normalized.*/ +#define PAL_VERTEX_TYPE_UINT16_2NORM 23 /**< uint16_t vec2 or array[2] normalized.*/ +#define PAL_VERTEX_TYPE_UINT16_4NORM 24 /**< uint16_t vec4 or array[4] normalized.*/ + +#define PAL_VERTEX_TYPE_FLOAT 25 /**< float*/ +#define PAL_VERTEX_TYPE_FLOAT2 26 /**< float vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_FLOAT3 27 /**< float vec3 or array[3].*/ +#define PAL_VERTEX_TYPE_FLOAT4 28 /**< float vec4 or array[4].*/ + +#define PAL_VERTEX_TYPE_HALF_FLOAT16_2 29 /**< float16 vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_HALF_FLOAT16_4 30 /**< float16 vec4 or array[4].*/ + +#define PAL_VERTEX_SEMANTIC_ID_POSITION 0 +#define PAL_VERTEX_SEMANTIC_ID_COLOR 1 +#define PAL_VERTEX_SEMANTIC_ID_TEXCOORD 2 +#define PAL_VERTEX_SEMANTIC_ID_NORMAL 3 +#define PAL_VERTEX_SEMANTIC_ID_TANGENT 4 + +#define PAL_COMMAND_BUFFER_TYPE_PRIMARY 0 +#define PAL_COMMAND_BUFFER_TYPE_SECONDARY 1 + +#define PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX 0 +#define PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE 1 + +#define PAL_COMPARE_OP_NEVER 0 +#define PAL_COMPARE_OP_LESS 1 +#define PAL_COMPARE_OP_EQUAL 2 +#define PAL_COMPARE_OP_LESS_OR_EQUAL 3 +#define PAL_COMPARE_OP_GREATER 4 +#define PAL_COMPARE_OP_NOT_EQUAL 5 +#define PAL_COMPARE_OP_GREATER_OR_EQUAL 6 +#define PAL_COMPARE_OP_ALWAYS 7 + +#define PAL_STENCIL_OP_KEEP 0 +#define PAL_STENCIL_OP_ZERO 1 +#define PAL_STENCIL_OP_REPLACE 2 +#define PAL_STENCIL_OP_INCREMENT_AND_CLAMP 3 +#define PAL_STENCIL_OP_DECREMENT_AND_CLAMP 4 +#define PAL_STENCIL_OP_INVERT 5 +#define PAL_STENCIL_OP_INCREMENT_AND_WRAP 6 +#define PAL_STENCIL_OP_DECREMENT_AND_WRAP 7 + +#define PAL_BLEND_OP_ADD 0 +#define PAL_BLEND_OP_SUBTRACT 1 +#define PAL_BLEND_OP_REVERSE_SUBTRACT 2 +#define PAL_BLEND_OP_MIN 3 +#define PAL_BLEND_OP_MAX 4 + +#define PAL_BLEND_FACTOR_ZERO 0 +#define PAL_BLEND_FACTOR_ONE 1 +#define PAL_BLEND_FACTOR_SRC_COLOR 2 +#define PAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR 3 +#define PAL_BLEND_FACTOR_DST_COLOR 4 +#define PAL_BLEND_FACTOR_ONE_MINUX_DST_COLOR 5 +#define PAL_BLEND_FACTOR_SRC_ALPHA 6 +#define PAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA 7 +#define PAL_BLEND_FACTOR_DST_ALPHA 8 +#define PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA 9 +#define PAL_BLEND_FACTOR_CONSTANT_COLOR 10 +#define PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR 10 +#define PAL_BLEND_FACTOR_CONSTANT_ALPHA 11 +#define PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA 12 + +#define PAL_COLOR_MASK_NONE 0 +#define PAL_COLOR_MASK_RED (1ULL << 0) +#define PAL_COLOR_MASK_GREEN (1ULL << 1) +#define PAL_COLOR_MASK_BLUE (1ULL << 2) +#define PAL_COLOR_MASK_ALPHA (1ULL << 3) + +#define PAL_RESOLVE_MODE_NONE 0 +#define PAL_RESOLVE_MODE_SAMPLE_ZERO 1 +#define PAL_RESOLVE_MODE_AVERAGE 2 +#define PAL_RESOLVE_MODE_MIN 3 +#define PAL_RESOLVE_MODE_MAX 4 + +#define PAL_FRAGMENT_SHADING_RATE_1X1 0 +#define PAL_FRAGMENT_SHADING_RATE_1X2 1 +#define PAL_FRAGMENT_SHADING_RATE_2X1 2 +#define PAL_FRAGMENT_SHADING_RATE_2X2 3 +#define PAL_FRAGMENT_SHADING_RATE_2X4 4 +#define PAL_FRAGMENT_SHADING_RATE_4X2 5 +#define PAL_FRAGMENT_SHADING_RATE_4X4 6 +#define PAL_FRAGMENT_SHADING_RATE_MAX 7 + +#define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP 0 +#define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE 1 +#define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN 2 +#define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX 3 +#define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL 4 + /** * @struct PalAdapter * @brief Opaque handle to an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct PalAdapter PalAdapter; @@ -118,7 +419,7 @@ typedef struct PalAdapter PalAdapter; * @struct PalDevice * @brief Opaque handle to a device. Devices are created from an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct PalDevice PalDevice; @@ -126,7 +427,7 @@ typedef struct PalDevice PalDevice; * @struct PalMemory * @brief Opaque handle to a device memory. This is not `CPU` memory. * - * @since 1.4 + * @since 2.0 */ typedef struct PalMemory PalMemory; @@ -134,7 +435,7 @@ typedef struct PalMemory PalMemory; * @struct PalQueue * @brief Opaque handle to a queue. * - * @since 1.4 + * @since 2.0 */ typedef struct PalQueue PalQueue; @@ -142,7 +443,7 @@ typedef struct PalQueue PalQueue; * @struct PalSurface * @brief Opaque handle to a surface. * - * @since 1.4 + * @since 2.0 */ typedef struct PalSurface PalSurface; @@ -150,7 +451,7 @@ typedef struct PalSurface PalSurface; * @struct PalSwapchain * @brief Opaque handle to a swapchain. * - * @since 1.4 + * @since 2.0 */ typedef struct PalSwapchain PalSwapchain; @@ -158,7 +459,7 @@ typedef struct PalSwapchain PalSwapchain; * @struct PalImage * @brief Opaque handle to an image. * - * @since 1.4 + * @since 2.0 */ typedef struct PalImage PalImage; @@ -166,7 +467,7 @@ typedef struct PalImage PalImage; * @struct PalImageView * @brief Opaque handle to an image view. * - * @since 1.4 + * @since 2.0 */ typedef struct PalImageView PalImageView; @@ -174,7 +475,7 @@ typedef struct PalImageView PalImageView; * @struct PalShader * @brief Opaque handle to a shader. * - * @since 1.4 + * @since 2.0 */ typedef struct PalShader PalShader; @@ -182,7 +483,7 @@ typedef struct PalShader PalShader; * @struct PalBuffer * @brief Opaque handle to a buffer. * - * @since 1.4 + * @since 2.0 */ typedef struct PalBuffer PalBuffer; @@ -190,7 +491,7 @@ typedef struct PalBuffer PalBuffer; * @struct PalFence * @brief Opaque handle to a fence. * - * @since 1.4 + * @since 2.0 */ typedef struct PalFence PalFence; @@ -198,7 +499,7 @@ typedef struct PalFence PalFence; * @struct PalSemaphore * @brief Opaque handle to a semaphore. * - * @since 1.4 + * @since 2.0 */ typedef struct PalSemaphore PalSemaphore; @@ -206,7 +507,7 @@ typedef struct PalSemaphore PalSemaphore; * @struct PalCommandPool * @brief Opaque handle to a command pool. * - * @since 1.4 + * @since 2.0 */ typedef struct PalCommandPool PalCommandPool; @@ -214,7 +515,7 @@ typedef struct PalCommandPool PalCommandPool; * @struct PalCommandBuffer * @brief Opaque handle to a command buffer. * - * @since 1.4 + * @since 2.0 */ typedef struct PalCommandBuffer PalCommandBuffer; @@ -228,7 +529,7 @@ typedef struct PalCommandBuffer PalCommandBuffer; * descriptorBindings[2] = { sampler, sampled image } is different from * descriptorBindings[2] = { sampled image, sampler }. The ordering must be correct. * - * @since 1.4 + * @since 2.0 */ typedef struct PalDescriptorSetLayout PalDescriptorSetLayout; @@ -236,7 +537,7 @@ typedef struct PalDescriptorSetLayout PalDescriptorSetLayout; * @struct PalDescriptorPool * @brief Opaque handle to a descriptor pool. * - * @since 1.4 + * @since 2.0 */ typedef struct PalDescriptorPool PalDescriptorPool; @@ -244,7 +545,7 @@ typedef struct PalDescriptorPool PalDescriptorPool; * @struct PalDescriptorSet * @brief Opaque handle to a descriptor set. * - * @since 1.4 + * @since 2.0 */ typedef struct PalDescriptorSet PalDescriptorSet; @@ -252,7 +553,7 @@ typedef struct PalDescriptorSet PalDescriptorSet; * @struct PalSampler * @brief Opaque handle to a sampler. * - * @since 1.4 + * @since 2.0 */ typedef struct PalSampler PalSampler; @@ -260,7 +561,7 @@ typedef struct PalSampler PalSampler; * @struct PalPipelineLayout * @brief Opaque handle to a pipeline layout. * - * @since 1.4 + * @since 2.0 */ typedef struct PalPipelineLayout PalPipelineLayout; @@ -269,7 +570,7 @@ typedef struct PalPipelineLayout PalPipelineLayout; * @brief Opaque handle to a pipeline. This is the same handle used for all pipeline types * (Graphics, Compute and Ray tracing). * - * @since 1.4 + * @since 2.0 */ typedef struct PalPipeline PalPipeline; @@ -277,7 +578,7 @@ typedef struct PalPipeline PalPipeline; * @struct PalShaderBindingTable * @brief Opaque handle to a shader binding table. * - * @since 1.4 + * @since 2.0 */ typedef struct PalShaderBindingTable PalShaderBindingTable; @@ -285,53 +586,50 @@ typedef struct PalShaderBindingTable PalShaderBindingTable; * @struct PalAccelerationStructure * @brief Opaque handle to an acceleration structure. * - * @since 1.4 + * @since 2.0 */ typedef struct PalAccelerationStructure PalAccelerationStructure; /** * @typedef PalDebugMessageSeverity * @brief Debugger messages severity types used to filter incoming messages. + * + * All message severities follow the format `PAL_DEBUG_MESSAGE_SEVERITY_**` for + * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum PalDebugMessageSeverity PalDebugMessageSeverity; +typedef uint32_t PalDebugMessageSeverity; /** * @typedef PalDebugMessageType * @brief Debugger messages types used to filter incoming messages. + * + * All message types follow the format `PAL_DEBUG_MESSAGE_TYPE_**` for + * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum PalDebugMessageType PalDebugMessageType; +typedef uint32_t PalDebugMessageType; /** * @typedef PalDeviceAddress * @brief Adapter address. Used to get adapter (GPU) address of mostly buffers. * - * @since 1.4 + * @since 2.0 */ typedef uint64_t PalDeviceAddress; /** - * @typedef PalDebugCallback - * @brief Function pointer type used for debug callbacks. + * @typedef PalAdapterFeatures + * @brief Adapter features. This is a bitmask. * - * @param userData Optional pointer to user data passed from ::PalGraphicsDebugger. Can be nullptr. - * @param severity Severity of the message. (`PAL_DEBUG_MESSAGE_SEVERITY_INFO`, - * `PAL_DEBUG_MESSAGE_SEVERITY_WARNING` and `PAL_DEBUG_MESSAGE_SEVERITY_ERROR`). - * @param type Type of the message. (`PAL_DEBUG_MESSAGE_TYPE_GENERAL`, - * `PAL_DEBUG_MESSAGE_TYPE_VALIDATION` and `PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE`). - * @param msg Null-terminated UTF-8 debug message. + * All adapter features follow the format `PAL_ADAPTER_FEATURE_**` for + * consistency and API use. * - * @since 1.4 - * @sa palInitGraphics + * @since 2.0 */ -typedef void(PAL_CALL* PalDebugCallback)( - void* userData, - PalDebugMessageSeverity severity, - PalDebugMessageType type, - const char* msg); +typedef uint64_t PalAdapterFeatures; /** * @typedef PalAdapterType @@ -340,15 +638,9 @@ typedef void(PAL_CALL* PalDebugCallback)( * All adapter types follow the format `PAL_ADAPTER_TYPE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_ADAPTER_TYPE_UNKNOWN, - PAL_ADAPTER_TYPE_DISCRETE, - PAL_ADAPTER_TYPE_INTEGRATED, - PAL_ADAPTER_TYPE_VIRTUAL, - PAL_ADAPTER_TYPE_CPU -} PalAdapterType; +typedef uint32_t PalAdapterType; /** * @typedef PalAdapterApiType @@ -356,23 +648,13 @@ typedef enum { * * All adapter api types follow the format `PAL_ADAPTER_API_TYPE_**` for * consistency and API use. + * + * Customs backends that dont fit the already declared api types should use + * `PAL_ADAPTER_API_TYPE_CUSTOM`. * - * (`PAL_ADAPTER_API_TYPE_OPENGL`, `PAL_ADAPTER_API_TYPE_GLES`, `PAL_ADAPTER_API_TYPE_D3D11` - * `PAL_ADAPTER_API_TYPE_D3D9`, `PAL_ADAPTER_API_TYPE_PPM`, etc) will not be supported by the - * core graphics system. These are custom backends that can be use to extend the graphics systems. - * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_ADAPTER_API_TYPE_VULKAN, - PAL_ADAPTER_API_TYPE_D3D12, - PAL_ADAPTER_API_TYPE_METAL, - PAL_ADAPTER_API_TYPE_OPENGL, - PAL_ADAPTER_API_TYPE_GLES, - PAL_ADAPTER_API_TYPE_D3D11, - PAL_ADAPTER_API_TYPE_D3D9, - PAL_ADAPTER_API_TYPE_PPM -} PalAdapterApiType; +typedef uint32_t PalAdapterApiType; /** * @typedef PalQueueType @@ -381,13 +663,9 @@ typedef enum { * All queue types follow the format `PAL_QUEUE_TYPE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_QUEUE_TYPE_GRAPHICS, - PAL_QUEUE_TYPE_COMPUTE, - PAL_QUEUE_TYPE_COPY -} PalQueueType; +typedef uint32_t PalQueueType; /** * @typedef PalPresentMode @@ -396,15 +674,9 @@ typedef enum { * All present modes follow the format `PAL_PRESENT_MODE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_PRESENT_MODE_FIFO, /**< V-Sync.*/ - PAL_PRESENT_MODE_IMMEDIATE, - PAL_PRESENT_MODE_MAILBOX, - - PAL_PRESENT_MODE_MAX -} PalPresentMode; +typedef uint32_t PalPresentMode; /** * @typedef PalCompositeAplha @@ -413,15 +685,9 @@ typedef enum { * All composite alphas follow the format `PAL_COMPOSITE_ALPHA_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_COMPOSITE_ALPHA_OPAQUE, /**< Default behavior.*/ - PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED, - PAL_COMPOSITE_ALPHA_POST_MULTIPLIED, - - PAL_COMPOSITE_ALPHA_MAX -} PalCompositeAplha; +typedef uint32_t PalCompositeAplha; /** * @typedef PalFormat @@ -430,94 +696,9 @@ typedef enum { * All format types follow the format `PAL_FORMAT_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_FORMAT_UNDEFINED, - - PAL_FORMAT_R8_UNORM, - PAL_FORMAT_R8_SNORM, - PAL_FORMAT_R8_UINT, - PAL_FORMAT_R8_SINT, - PAL_FORMAT_R8_SRGB, - PAL_FORMAT_R16_UNORM, - PAL_FORMAT_R16_SNORM, - PAL_FORMAT_R16_UINT, - PAL_FORMAT_R16_SINT, - PAL_FORMAT_R16_SFLOAT, - PAL_FORMAT_R32_UINT, - PAL_FORMAT_R32_SINT, - PAL_FORMAT_R32_SFLOAT, - PAL_FORMAT_R64_UINT, - PAL_FORMAT_R64_SINT, - PAL_FORMAT_R64_SFLOAT, - PAL_FORMAT_R8G8_UNORM, - PAL_FORMAT_R8G8_SNORM, - PAL_FORMAT_R8G8_UINT, - PAL_FORMAT_R8G8_SINT, - PAL_FORMAT_R8G8_SRGB, - PAL_FORMAT_R16G16_UNORM, - PAL_FORMAT_R16G16_SNORM, - PAL_FORMAT_R16G16_UINT, - PAL_FORMAT_R16G16_SINT, - PAL_FORMAT_R16G16_SFLOAT, - PAL_FORMAT_R32G32_UINT, - PAL_FORMAT_R32G32_SINT, - PAL_FORMAT_R32G32_SFLOAT, - PAL_FORMAT_R64G64_UINT, - PAL_FORMAT_R64G64_SINT, - PAL_FORMAT_R64G64_SFLOAT, - PAL_FORMAT_R8G8B8_UNORM, - PAL_FORMAT_R8G8B8_SNORM, - PAL_FORMAT_R8G8B8_UINT, - PAL_FORMAT_R8G8B8_SINT, - PAL_FORMAT_R8G8B8_SRGB, - PAL_FORMAT_R16G16B16_UNORM, - PAL_FORMAT_R16G16B16_SNORM, - PAL_FORMAT_R16G16B16_UINT, - PAL_FORMAT_R16G16B16_SINT, - PAL_FORMAT_R16G16B16_SFLOAT, - PAL_FORMAT_R32G32B32_UINT, - PAL_FORMAT_R32G32B32_SINT, - PAL_FORMAT_R32G32B32_SFLOAT, - PAL_FORMAT_R64G64B64_UINT, - PAL_FORMAT_R64G64B64_SINT, - PAL_FORMAT_R64G64B64_SFLOAT, - PAL_FORMAT_B8G8R8_UNORM, - PAL_FORMAT_B8G8R8_SNORM, - PAL_FORMAT_B8G8R8_UINT, - PAL_FORMAT_B8G8R8_SINT, - PAL_FORMAT_B8G8R8_SRGB, - PAL_FORMAT_R8G8B8A8_UNORM, - PAL_FORMAT_R8G8B8A8_SNORM, - PAL_FORMAT_R8G8B8A8_UINT, - PAL_FORMAT_R8G8B8A8_SINT, - PAL_FORMAT_R8G8B8A8_SRGB, - PAL_FORMAT_R16G16B16A16_UNORM, - PAL_FORMAT_R16G16B16A16_SNORM, - PAL_FORMAT_R16G16B16A16_UINT, - PAL_FORMAT_R16G16B16A16_SINT, - PAL_FORMAT_R16G16B16A16_SFLOAT, - PAL_FORMAT_R32G32B32A32_UINT, - PAL_FORMAT_R32G32B32A32_SINT, - PAL_FORMAT_R32G32B32A32_SFLOAT, - PAL_FORMAT_R64G64B64A64_UINT, - PAL_FORMAT_R64G64B64A64_SINT, - PAL_FORMAT_R64G64B64A64_SFLOAT, - PAL_FORMAT_B8G8R8A8_UNORM, - PAL_FORMAT_B8G8R8A8_SNORM, - PAL_FORMAT_B8G8R8A8_UINT, - PAL_FORMAT_B8G8R8A8_SINT, - PAL_FORMAT_B8G8R8A8_SRGB, - PAL_FORMAT_S8_UINT, - PAL_FORMAT_D16_UNORM, - PAL_FORMAT_D32_SFLOAT, - PAL_FORMAT_D16_UNORM_S8_UINT, - PAL_FORMAT_D32_SFLOAT_S8_UINT, - PAL_FORMAT_D24_UNORM_S8_UINT, - - PAL_FORMAT_MAX -} PalFormat; +typedef uint32_t PalFormat; /** * @typedef PalImageUsages @@ -527,18 +708,9 @@ typedef enum { * All image usages follow the format `PAL_IMAGE_USAGE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_IMAGE_USAGE_UNDEFINED = 0, - - PAL_IMAGE_USAGE_COLOR_ATTACHEMENT = (1ULL << 0), - PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT = (1ULL << 1), - PAL_IMAGE_USAGE_TRANSFER_SRC = (1ULL << 2), - PAL_IMAGE_USAGE_TRANSFER_DST = (1ULL << 3), - PAL_IMAGE_USAGE_STORAGE = (1ULL << 4), - PAL_IMAGE_USAGE_SAMPLED = (1ULL << 5) -} PalImageUsages; +typedef uint64_t PalImageUsages; /** * @typedef PalShaderFormats @@ -547,16 +719,9 @@ typedef enum { * All shader formats follow the format `PAL_SHADER_FORMAT_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_SHADER_FORMAT_SPIRV = (1ULL << 0), - PAL_SHADER_FORMAT_DXIL = (1ULL << 1), - PAL_SHADER_FORMAT_DXBC = (1ULL << 2), - PAL_SHADER_FORMAT_GLSL = (1ULL << 3), - PAL_SHADER_FORMAT_MSL = (1ULL << 4), - PAL_SHADER_FORMAT_PPM = (1ULL << 5) -} PalShaderFormats; +typedef uint64_t PalShaderFormats; /** * @typedef PalLoadOp @@ -565,13 +730,9 @@ typedef enum { * All load operation type follow the format `PAL_LOAD_OP_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_LOAD_OP_LOAD, - PAL_LOAD_OP_CLEAR, - PAL_LOAD_OP_DONT_CARE, -} PalLoadOp; +typedef uint32_t PalLoadOp; /** * @typedef PalStoreOp @@ -580,12 +741,9 @@ typedef enum { * All store operation type follow the format `PAL_STORE_OP_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_STORE_OP_STORE, - PAL_STORE_OP_DONT_CARE -} PalStoreOp; +typedef uint32_t PalStoreOp; /** * @typedef PalMemoryType @@ -594,15 +752,9 @@ typedef enum { * All memory types follow the format `PAL_MEMORY_TYPE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_MEMORY_TYPE_GPU_ONLY, - PAL_MEMORY_TYPE_CPU_UPLOAD, - PAL_MEMORY_TYPE_CPU_READBACK, - - PAL_MEMORY_TYPE_MAX -} PalMemoryType; +typedef uint32_t PalMemoryType; /** * @typedef PalImageType @@ -611,13 +763,9 @@ typedef enum { * All image types follow the format `PAL_IMAGE_TYPE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_IMAGE_TYPE_1D, - PAL_IMAGE_TYPE_2D, - PAL_IMAGE_TYPE_3D -} PalImageType; +typedef uint32_t PalImageType; /** * @typedef PalImageAspect @@ -626,14 +774,9 @@ typedef enum { * All image aspect follow the format `PAL_IMAGE_ASPECT_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_IMAGE_ASPECT_COLOR, - PAL_IMAGE_ASPECT_DEPTH, - PAL_IMAGE_ASPECT_STENCIL, - PAL_IMAGE_ASPECT_DEPTH_STENCIL -} PalImageAspect; +typedef uint32_t PalImageAspect; /** * @typedef PalImageViewType @@ -642,17 +785,9 @@ typedef enum { * All image view types follow the format `PAL_IMAGE_VIEW_TYPE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_IMAGE_VIEW_TYPE_1D, - PAL_IMAGE_VIEW_TYPE_1D_ARRAY, - PAL_IMAGE_VIEW_TYPE_2D, - PAL_IMAGE_VIEW_TYPE_2D_ARRAY, - PAL_IMAGE_VIEW_TYPE_3D, - PAL_IMAGE_VIEW_TYPE_CUBE, - PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY, -} PalImageViewType; +typedef uint32_t PalImageViewType; /** * @typedef PalFilterMode @@ -661,12 +796,9 @@ typedef enum { * All filter modes follow the format `PAL_FILTER_MODE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_FILTER_MODE_NEAREST, - PAL_FILTER_MODE_LINEAR -} PalFilterMode; +typedef uint32_t PalFilterMode; /** * @typedef PalSamplerMipmapMode @@ -675,12 +807,9 @@ typedef enum { * All sampler mipmap modes follow the format `PAL_SAMPLER_MIPMAP_MODE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_SAMPLER_MIPMAP_MODE_NEAREST, - PAL_SAMPLER_MIPMAP_MODE_LINEAR -} PalSamplerMipmapMode; +typedef uint32_t PalSamplerMipmapMode; /** * @typedef PalSamplerAddressMode @@ -689,14 +818,9 @@ typedef enum { * All sampler address modes follow the format `PAL_SAMPLER_ADDRESS_MODE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_SAMPLER_ADDRESS_MODE_REPEAT, - PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, - PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, - PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER -} PalSamplerAddressMode; +typedef uint32_t PalSamplerAddressMode; /** * @typedef PalBorderColor @@ -705,16 +829,9 @@ typedef enum { * All border colors follow the format `PAL_BORDER_COLOR_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, - PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK, - PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK, - PAL_BORDER_COLOR_INT_OPAQUE_BLACK, - PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE, - PAL_BORDER_COLOR_INT_OPAQUE_WHITE -} PalBorderColor; +typedef uint32_t PalBorderColor; /** * @typedef PalSurfaceFormat @@ -723,16 +840,9 @@ typedef enum { * All surface format types follow the format `PAL_SURFACE_FORMAT_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR, - PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR, - PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR, - PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10, /**< HDR.*/ - - PAL_SURFACE_FORMAT_MAX -} PalSurfaceFormat; +typedef uint32_t PalSurfaceFormat; /** * @typedef PalGraphicsWindowDisplayType @@ -741,13 +851,9 @@ typedef enum { * All graphics window display types follow the format `PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND, - PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11, - PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB -} PalGraphicsWindowDisplayType; +typedef uint32_t PalGraphicsWindowDisplayType; /** * @typedef PalShaderStage @@ -756,26 +862,9 @@ typedef enum { * All shader stage types follow the format `PAL_SHADER_STAGE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_SHADER_STAGE_UNDEFINED, - - PAL_SHADER_STAGE_VERTEX, - PAL_SHADER_STAGE_FRAGMENT, - PAL_SHADER_STAGE_COMPUTE, - PAL_SHADER_STAGE_GEOMETRY, - PAL_SHADER_STAGE_MESH, - PAL_SHADER_STAGE_TASK, - PAL_SHADER_STAGE_TESSELLATION_CONTROL, - PAL_SHADER_STAGE_TESSELLATION_EVALUATION, - PAL_SHADER_STAGE_RAYGEN, - PAL_SHADER_STAGE_CLOSEST_HIT, - PAL_SHADER_STAGE_ANY_HIT, - PAL_SHADER_STAGE_MISS, - PAL_SHADER_STAGE_INTERSECTION, - PAL_SHADER_STAGE_CALLABLE -} PalShaderStage; +typedef uint32_t PalShaderStage; /** * @typedef PalSampleCount @@ -784,17 +873,9 @@ typedef enum { * All sample count follow the format `PAL_SAMPLE_COUNT_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_SAMPLE_COUNT_1, - PAL_SAMPLE_COUNT_2, - PAL_SAMPLE_COUNT_4, - PAL_SAMPLE_COUNT_8, - PAL_SAMPLE_COUNT_16, - PAL_SAMPLE_COUNT_32, - PAL_SAMPLE_COUNT_64 -} PalSampleCount; +typedef uint32_t PalSampleCount; /** * @typedef PalPrimitiveTopology @@ -803,16 +884,9 @@ typedef enum { * All primitve topology types follow the format `PAL_PRIMITIVE_TOPOLOGY_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - PAL_PRIMITIVE_TOPOLOGY_LINE_LIST, - PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP, - PAL_PRIMITIVE_TOPOLOGY_POINT_LIST, - PAL_PRIMITIVE_TOPOLOGY_PATCH -} PalPrimitiveTopology; +typedef uint32_t PalPrimitiveTopology; /** * @typedef PalCullMode @@ -821,13 +895,9 @@ typedef enum { * All cull modes follow the format `PAL_CULL_MODE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_CULL_MODE_NONE, - PAL_CULL_MODE_FRONT, - PAL_CULL_MODE_BACK -} PalCullMode; +typedef uint32_t PalCullMode; /** * @typedef PalFrontFace @@ -836,12 +906,9 @@ typedef enum { * All front face modes follow the format `PAL_FRONT_FACE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_FRONT_FACE_CLOCKWISE, - PAL_FRONT_FACE_COUNTER_CLOCKWISE -} PalFrontFace; +typedef uint32_t PalFrontFace; /** * @typedef PalPolygonMode @@ -850,12 +917,9 @@ typedef enum { * All polygon modes follow the format `PAL_POLYGON_MODE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_POLYGON_MODE_FILL, - PAL_POLYGON_MODE_LINE -} PalPolygonMode; +typedef uint32_t PalPolygonMode; /** * @typedef PalStencilFaceFlags @@ -865,13 +929,9 @@ typedef enum { * All tencil face flags follow the format `PAL_STENCIL_FACE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_STENCIL_FACE_FRONT = (1ULL << 0), - PAL_STENCIL_FACE_BACK = (1ULL << 1), - PAL_STENCIL_FACE_BOTH = PAL_STENCIL_FACE_FRONT | PAL_STENCIL_FACE_BACK -} PalStencilFaceFlags; +typedef uint64_t PalStencilFaceFlags; /** * @typedef PalVertexType @@ -880,49 +940,9 @@ typedef enum { * All vertex attribute types follow the format `PAL_VERTEX_TYPE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_VERTEX_TYPE_UNDEFINED, - - PAL_VERTEX_TYPE_INT32, /**< int32_t.*/ - PAL_VERTEX_TYPE_INT32_2, /**< int32_t vec2 or array[2].*/ - PAL_VERTEX_TYPE_INT32_3, /**< int32_t vec3 or array[3].*/ - PAL_VERTEX_TYPE_INT32_4, /**< int32_t vec4 or array[4].*/ - - PAL_VERTEX_TYPE_UINT32, /**< uint32_t.*/ - PAL_VERTEX_TYPE_UINT32_2, /**< uint32_t vec2 or array[2].*/ - PAL_VERTEX_TYPE_UINT32_3, /**< uint32_t vec3 or array[3].*/ - PAL_VERTEX_TYPE_UINT32_4, /**< uint32_t vec4 or array[4].*/ - - PAL_VERTEX_TYPE_INT8_2, /**< int8_t vec2 or array[2].*/ - PAL_VERTEX_TYPE_INT8_4, /**< int8_t vec4 or array[4].*/ - PAL_VERTEX_TYPE_UINT8_2, /**< uint8_t vec2 or array[2].*/ - PAL_VERTEX_TYPE_UINT8_4, /**< uint8_t vec4 or array[4].*/ - - PAL_VERTEX_TYPE_INT8_2NORM, /**< int8_t vec2 or array[2] normalized.*/ - PAL_VERTEX_TYPE_INT8_4NORM, /**< int8_t vec4 or array[4] normalized.*/ - PAL_VERTEX_TYPE_UINT8_2NORM, /**< uint8_t vec2 or array[2] normalized.*/ - PAL_VERTEX_TYPE_UINT8_4NORM, /**< uint8_t vec4 or array[4] normalized.*/ - - PAL_VERTEX_TYPE_INT16_2, /**< int16_t vec2 or array[2].*/ - PAL_VERTEX_TYPE_INT16_4, /**< int16_t vec4 or array[4].*/ - PAL_VERTEX_TYPE_UINT16_2, /**< uint16_t vec2 or array[2].*/ - PAL_VERTEX_TYPE_UINT16_4, /**< uint16_t vec4 or array[4].*/ - - PAL_VERTEX_TYPE_INT16_2NORM, /**< int16_t vec2 or array[2] normalized.*/ - PAL_VERTEX_TYPE_INT16_4NORM, /**< int16_t vec4 or array[4] normalized.*/ - PAL_VERTEX_TYPE_UINT16_2NORM, /**< uint16_t vec2 or array[2] normalized.*/ - PAL_VERTEX_TYPE_UINT16_4NORM, /**< uint16_t vec4 or array[4] normalized.*/ - - PAL_VERTEX_TYPE_FLOAT, /**< float*/ - PAL_VERTEX_TYPE_FLOAT2, /**< float vec2 or array[2].*/ - PAL_VERTEX_TYPE_FLOAT3, /**< float vec3 or array[3].*/ - PAL_VERTEX_TYPE_FLOAT4, /**< float vec4 or array[4].*/ - - PAL_VERTEX_TYPE_HALF_FLOAT16_2, /**< float16 vec2 or array[2].*/ - PAL_VERTEX_TYPE_HALF_FLOAT16_4 /**< float16 vec4 or array[4].*/ -} PalVertexType; +typedef uint32_t PalVertexType; /** * @typedef PalVertexSemanticID @@ -931,15 +951,9 @@ typedef enum { * All vertex semantic id types follow the format `PAL_VERTEX_SEMANTIC_ID_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_VERTEX_SEMANTIC_ID_POSITION, - PAL_VERTEX_SEMANTIC_ID_COLOR, - PAL_VERTEX_SEMANTIC_ID_TEXCOORD, - PAL_VERTEX_SEMANTIC_ID_NORMAL, - PAL_VERTEX_SEMANTIC_ID_TANGENT -} PalVertexSemanticID; +typedef uint32_t PalVertexSemanticID; /** * @typedef PalCommandBufferType @@ -948,12 +962,9 @@ typedef enum { * All command buffer types follow the format `PAL_COMMAND_BUFFER_TYPE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_COMMAND_BUFFER_TYPE_PRIMARY, - PAL_COMMAND_BUFFER_TYPE_SECONDARY -} PalCommandBufferType; +typedef uint32_t PalCommandBufferType; /** * @typedef PalVertexLayoutType @@ -962,12 +973,9 @@ typedef enum { * All vertex layout types follow the format `PAL_VERTEX_LAYOUT_TYPE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX, - PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE -} PalVertexLayoutType; +typedef uint32_t PalVertexLayoutType; /** * @typedef PalCompareOp @@ -976,18 +984,9 @@ typedef enum { * All compare operation modes follow the format `PAL_COMPARE_OP_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_COMPARE_OP_NEVER, - PAL_COMPARE_OP_LESS, - PAL_COMPARE_OP_EQUAL, - PAL_COMPARE_OP_LESS_OR_EQUAL, - PAL_COMPARE_OP_GREATER, - PAL_COMPARE_OP_NOT_EQUAL, - PAL_COMPARE_OP_GREATER_OR_EQUAL, - PAL_COMPARE_OP_ALWAYS -} PalCompareOp; +typedef uint32_t PalCompareOp; /** * @typedef PalStencilOp @@ -996,18 +995,9 @@ typedef enum { * All stencil operation modes follow the format `PAL_STENCIL_OP_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_STENCIL_OP_KEEP, - PAL_STENCIL_OP_ZERO, - PAL_STENCIL_OP_REPLACE, - PAL_STENCIL_OP_INCREMENT_AND_CLAMP, - PAL_STENCIL_OP_DECREMENT_AND_CLAMP, - PAL_STENCIL_OP_INVERT, - PAL_STENCIL_OP_INCREMENT_AND_WRAP, - PAL_STENCIL_OP_DECREMENT_AND_WRAP -} PalStencilOp; +typedef uint32_t PalStencilOp; /** * @typedef PalBlendOp @@ -1016,41 +1006,20 @@ typedef enum { * All blend operation modes follow the format `PAL_BLEND_OP_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_BLEND_OP_ADD, - PAL_BLEND_OP_SUBTRACT, - PAL_BLEND_OP_REVERSE_SUBTRACT, - PAL_BLEND_OP_MIN, - PAL_BLEND_OP_MAX -} PalBlendOp; +typedef uint32_t PalBlendOp; /** - * @typedef PalBlendOp + * @typedef PalBlendFactor * @brief Blend factor modes. * * All blend factor modes follow the format `PAL_BLEND_FACTOR_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_BLEND_FACTOR_ZERO, - PAL_BLEND_FACTOR_ONE, - PAL_BLEND_FACTOR_SRC_COLOR, - PAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, - PAL_BLEND_FACTOR_DST_COLOR, - PAL_BLEND_FACTOR_ONE_MINUX_DST_COLOR, - PAL_BLEND_FACTOR_SRC_ALPHA, - PAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - PAL_BLEND_FACTOR_DST_ALPHA, - PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, - PAL_BLEND_FACTOR_CONSTANT_COLOR, - PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, - PAL_BLEND_FACTOR_CONSTANT_ALPHA, - PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA -} PalBlendFactor; +typedef uint32_t PalBlendFactor; /** * @typedef PalColorMask @@ -1059,19 +1028,12 @@ typedef enum { * * `PAL_COLOR_MASK_NONE` is not a bit and must not be combined with other bits. * - * All color mask flags follow the format `PAL_BLEND_FACTOR_**` for + * All color mask flags follow the format `PAL_COLOR_MASK_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_COLOR_MASK_NONE = 0, - - PAL_COLOR_MASK_RED = (1ULL << 0), - PAL_COLOR_MASK_GREEN = (1ULL << 1), - PAL_COLOR_MASK_BLUE = (1ULL << 2), - PAL_COLOR_MASK_ALPHA = (1ULL << 3), -} PalColorMask; +typedef uint64_t PalColorMask; /** * @typedef PalResolveMode @@ -1080,16 +1042,9 @@ typedef enum { * All resolve modes follow the format `PAL_RESOLVE_MODE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_RESOLVE_MODE_NONE = 0, - - PAL_RESOLVE_MODE_SAMPLE_ZERO, - PAL_RESOLVE_MODE_AVERAGE, - PAL_RESOLVE_MODE_MIN, - PAL_RESOLVE_MODE_MAX -} PalResolveMode; +typedef uint32_t PalResolveMode; /** * @typedef PalFragmentShadingRate @@ -1098,19 +1053,9 @@ typedef enum { * All fragment shading rates follow the format `PAL_FRAGMENT_SHADING_RATE_**` for * consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_FRAGMENT_SHADING_RATE_1X1, - PAL_FRAGMENT_SHADING_RATE_1X2, - PAL_FRAGMENT_SHADING_RATE_2X1, - PAL_FRAGMENT_SHADING_RATE_2X2, - PAL_FRAGMENT_SHADING_RATE_2X4, - PAL_FRAGMENT_SHADING_RATE_4X2, - PAL_FRAGMENT_SHADING_RATE_4X4, - - PAL_FRAGMENT_SHADING_RATE_MAX -} PalFragmentShadingRate; +typedef uint32_t PalFragmentShadingRate; /** * @typedef PalFragmentShadingRateCombinerOp @@ -1119,15 +1064,29 @@ typedef enum { * All fragment shading rate combiner operation modes follow the format * `PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_**` for consistency and API use. * - * @since 1.4 + * @since 2.0 */ -typedef enum { - PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP, - PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE, - PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN, - PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX, - PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL -} PalFragmentShadingRateCombinerOp; +typedef uint32_t PalFragmentShadingRateCombinerOp; + +/** + * @typedef PalDebugCallback + * @brief Function pointer type used for debug callbacks. + * + * @param userData Optional pointer to user data passed from ::PalGraphicsDebugger. Can be nullptr. + * @param severity Severity of the message. (`PAL_DEBUG_MESSAGE_SEVERITY_INFO`, + * `PAL_DEBUG_MESSAGE_SEVERITY_WARNING` and `PAL_DEBUG_MESSAGE_SEVERITY_ERROR`). + * @param type Type of the message. (`PAL_DEBUG_MESSAGE_TYPE_GENERAL`, + * `PAL_DEBUG_MESSAGE_TYPE_VALIDATION` and `PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE`). + * @param msg Null-terminated UTF-8 debug message. + * + * @since 2.0 + * @sa palInitGraphics + */ +typedef void(PAL_CALL* PalDebugCallback)( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg); /** * @typedef PalAccelerationStructureType @@ -1136,7 +1095,7 @@ typedef enum { * All acceleration structure types follow the format `PAL_ACCELERATION_STRUCTURE_TYPE_**` * for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL, @@ -1150,7 +1109,7 @@ typedef enum { * All acceleration structure build modes follow the format * `PAL_ACCELERATION_STRUCTURE_BUILD_MODE_**` for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD, @@ -1165,7 +1124,7 @@ typedef enum { * All acceleration structure build hints follow the format * `PAL_ACCELERATION_STRUCTURE_BUILD_HINT_**` for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD = (1ULL << 0), @@ -1181,7 +1140,7 @@ typedef enum { * All acceleration structure instance flags follow the format * `PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_**` for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE = (1ULL << 0), @@ -1196,7 +1155,7 @@ typedef enum { * * All geometry types follow the format `PAL_GEOMETRY_TYPE_**` for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_GEOMETRY_TYPE_TRIANGLE, @@ -1210,7 +1169,7 @@ typedef enum { * * All geometry flags follow the format `PAL_GEOMETRY_FLAG_**` for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_GEOMETRY_FLAG_OPAQUE = (1ULL << 0), @@ -1223,7 +1182,7 @@ typedef enum { * * All index types follow the format `PAL_INDEX_TYPE_**` for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_INDEX_TYPE_UINT16, @@ -1237,7 +1196,7 @@ typedef enum { * * All buffer usages follow the format `PAL_BUFFER_USAGE_**` for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_BUFFER_USAGE_VERTEX = (1ULL << 0), @@ -1271,7 +1230,7 @@ enum PalDebugMessageType { * * All usage states follow the format `PAL_USAGE_STATE_**` for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_USAGE_STATE_UNDEFINED, @@ -1305,7 +1264,7 @@ typedef enum { * * All descriptor types follow the format `PAL_DESCRIPTOR_TYPE_**` for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER, @@ -1323,7 +1282,7 @@ typedef enum { * All ray tracing shader group types follow the format `PAL_RAY_TRACING_SHADER_GROUP_TYPE_**` * for consistency and API use. * - * @since 1.4 + * @since 2.0 */ typedef enum { PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL, @@ -1335,7 +1294,7 @@ typedef enum { * @struct PalAdapterInfo * @brief Information about an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t vendorId; @@ -1353,7 +1312,7 @@ typedef struct { * @struct PalImageCapabilities * @brief Image capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t maxWidth; @@ -1367,7 +1326,7 @@ typedef struct { * @struct PalResourceCapabilities * @brief Resource capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool sampledImageDynamicArrayIndexing; @@ -1393,7 +1352,7 @@ typedef struct { * @struct PalComputeCapabilities * @brief Compute capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t maxWorkGroupInvocations; @@ -1405,7 +1364,7 @@ typedef struct { * @struct PalViewportCapabilities * @brief Viewport capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t maxWidth; @@ -1418,7 +1377,7 @@ typedef struct { * @struct PalAdapterCapabilities * @brief Capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t maxComputeQueues; @@ -1441,7 +1400,7 @@ typedef struct { * @struct PalSamplerAnisotropyCapabilities * @brief Sampler anisotropy capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t maxAnisotropy; @@ -1451,7 +1410,7 @@ typedef struct { * @struct PalMultiViewCapabilities * @brief Multi view capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t maxViewCount; @@ -1461,7 +1420,7 @@ typedef struct { * @struct PalMultiViewportCapabilities * @brief Multi viewport capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t maxCount; @@ -1471,7 +1430,7 @@ typedef struct { * @struct PalDepthStencilCapabilities * @brief Depth stencil capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool independentResolve; @@ -1483,7 +1442,7 @@ typedef struct { * @struct PalFragmentShadingRateCapabilities * @brief Fragment shading rate capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; @@ -1498,7 +1457,7 @@ typedef struct { * @struct PalMeshShaderCapabilities * @brief Mesh shader capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t maxOutputPrimitives; @@ -1513,7 +1472,7 @@ typedef struct { * @struct PalRayTracingCapabilities * @brief Ray tracing capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t maxRecursionDepth; @@ -1529,7 +1488,7 @@ typedef struct { * @struct PalDescriptorIndexingCapabilities * @brief Descriptor indexing capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool sampledImageNonUniformIndexing; @@ -1558,7 +1517,7 @@ typedef struct { * @struct PalSurfaceCapabilities * @brief surface capabilities of an adapter (GPU). * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool presentModes[PAL_PRESENT_MODE_MAX]; @@ -1580,7 +1539,7 @@ typedef struct { * This can be allocated statically or dynamically since its used for * holding native handles. The handles will not be copied. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalGraphicsWindowDisplayType displayType; /**< Will be used only on linux platform.*/ @@ -1593,7 +1552,7 @@ typedef struct { * @brief Information about a format. This includes the supported image usages and maximum sample * count from the provided format. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalFormat format; @@ -1605,7 +1564,7 @@ typedef struct { * @struct PalImageInfo * @brief Information about an image. This can be a swapchain image. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t width; /**< Width of the image in pixels.*/ @@ -1625,7 +1584,7 @@ typedef struct { * If used with a color attachment, the color values will be used and depth and stencil * will be used with depth stencil attachments. * - * @since 1.4 + * @since 2.0 */ typedef struct { float color[4]; /**< Color for color attachments only.*/ @@ -1639,7 +1598,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalLoadOp loadOp; @@ -1660,7 +1619,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t shaderStageCount; @@ -1672,7 +1631,7 @@ typedef struct { * @struct PalViewport * @brief A viewport in pixels (float). * - * @since 1.4 + * @since 2.0 */ typedef struct { float x; @@ -1687,7 +1646,7 @@ typedef struct { * @struct PalRect2D * @brief A 2D rectangle in pixels. * - * @since 1.4 + * @since 2.0 */ typedef struct { int32_t x; @@ -1700,7 +1659,7 @@ typedef struct { * @struct PalMemoryRequirements * @brief Memory requirements for a resource (image, buffer etc). * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool memoryTypes[PAL_MEMORY_TYPE_MAX]; @@ -1715,7 +1674,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint64_t waitValue; @@ -1732,7 +1691,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint64_t timeout; /**< Timeout in milliseconds.*/ @@ -1747,7 +1706,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t imageIndex; /**< Image index to present. Must be 0 and less than max images.*/ @@ -1761,7 +1720,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ @@ -1778,7 +1737,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ @@ -1796,7 +1755,7 @@ typedef struct { * Uninitialized fields may result in undefined behavior. `workCount` can be specified in pixels, * vertices etc.Eg. an image of 800 x 600 will be [0] = 800, [1] = 600 and [2] = 1. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t workCount[3]; @@ -1808,7 +1767,7 @@ typedef struct { * @struct PalWorkGroupInfo * @brief Information about compute or mesh(or task) dispatch data or a dispatch tile. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t workGroupBase[3]; /**< Offset per axis of a dispatch tile.*/ @@ -1821,7 +1780,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t vertexCount; @@ -1836,7 +1795,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t indexCount; @@ -1852,7 +1811,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t groupCountXOrWidth; /**< Number of groups on the x axis or width.*/ @@ -1868,7 +1827,7 @@ typedef struct { * (eg. "position" or "myown"). Set to nullptr to use the default that will be derived from ` * semanticID` which are (`POSITION`, `COLOR`, `TEXCOORD`, `NORMAL` and `TANGENT`). * - * @since 1.4 + * @since 2.0 */ typedef struct { PalVertexSemanticID semanticID; @@ -1888,7 +1847,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalVertexLayoutType type; @@ -1903,7 +1862,7 @@ typedef struct { * * The debugger will not be initialized if PalGraphicsDebugger::callback is set and valid. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool denyGeneral; @@ -1922,7 +1881,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool enableDepthClamp; @@ -1941,7 +1900,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool enableSampleShading; @@ -1957,7 +1916,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalStencilOp failOp; @@ -1972,7 +1931,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool enableDepthTest; @@ -1992,7 +1951,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool enableBlend; @@ -2011,7 +1970,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalFragmentShadingRate rate; @@ -2024,7 +1983,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t instanceId; @@ -2039,7 +1998,7 @@ typedef struct { * @struct PalAccelerationStructureBuildSize * @brief Acceleration structure build size. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t accelerationStructureSize; @@ -2053,7 +2012,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalVertexType vertexType; @@ -2071,7 +2030,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t stride; @@ -2084,7 +2043,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalGeometryFlags flags; @@ -2099,7 +2058,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalAccelerationStructureType type; @@ -2120,7 +2079,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t descriptorCount; @@ -2134,7 +2093,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t bindingCount; @@ -2147,7 +2106,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t size; @@ -2162,7 +2121,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalImageView* imageView; @@ -2174,7 +2133,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalSampler* sampler; @@ -2186,7 +2145,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalAccelerationStructure* tlas; @@ -2198,7 +2157,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t layoutBindingIndex; /**< Index into the descriptor set layout bindings.*/ @@ -2218,7 +2177,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint64_t offset; @@ -2233,7 +2192,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t startMipLevel; @@ -2249,7 +2208,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t size; @@ -2263,7 +2222,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint64_t bufferOffset; @@ -2287,7 +2246,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t dstMipLevel; @@ -2315,7 +2274,7 @@ typedef struct { * * The records array must be in this order [raygen][miss][hitgroup][callable]. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t groupIndex; /**< Index into the shader groups used to create the ray tracing pipeline.*/ @@ -2329,7 +2288,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ @@ -2343,7 +2302,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t width; @@ -2362,7 +2321,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalFormat format; /**< Must be compatible with the image format.*/ @@ -2376,7 +2335,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool enableCompare; @@ -2401,7 +2360,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool clipped; @@ -2420,7 +2379,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t entryCount; @@ -2435,7 +2394,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBufferUsages usages; @@ -2448,7 +2407,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalAccelerationStructureType type; @@ -2464,7 +2423,7 @@ typedef struct { * Uninitialized fields may result in undefined behavior. Set `enableDescriptorIndexing` to * `PAL_TRUE` to enable descriptor indexing for the descriptor set layout. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool enableDescriptorIndexing; @@ -2481,7 +2440,7 @@ typedef struct { * Uninitialized fields may result in undefined behavior. Set `enableDescriptorIndexing` to * `PAL_TRUE` to enable descriptor indexing for the descriptor pool. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool enableDescriptorIndexing; @@ -2496,7 +2455,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t descriptorSetLayoutCount; @@ -2511,7 +2470,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalBool primitiveRestartEnable; @@ -2537,7 +2496,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalPipelineLayout* pipelineLayout; @@ -2552,7 +2511,7 @@ typedef struct { * * The shader group array must be in this order [raygen][miss][hitgroup][callable]. * - * @since 1.4 + * @since 2.0 */ typedef struct { PalRayTracingShaderGroupType type; @@ -2573,7 +2532,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t shaderCount; @@ -2592,7 +2551,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { uint32_t recordCount; @@ -2606,7 +2565,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.4 + * @since 2.0 */ typedef struct { /** @@ -3911,7 +3870,7 @@ typedef struct { * * Thread safety: Must only be called from the main thread. * - * @since 1.4 + * @since 2.0 * @sa palInitGraphics * @sa palShutdownGraphics */ @@ -3940,7 +3899,7 @@ PAL_API PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backe * * Thread safety: Must only be called from the main thread. * - * @since 1.4 + * @since 2.0 * @sa palAddGraphicsBackend * @sa palShutdownGraphics */ @@ -3956,7 +3915,7 @@ PAL_API PalResult PAL_CALL palInitGraphics( * * Thread safety: Must only be called from the main thread. * - * @since 1.4 + * @since 2.0 * @sa palInitGraphics */ PAL_API void PAL_CALL palShutdownGraphics(); @@ -3987,7 +3946,7 @@ PAL_API void PAL_CALL palShutdownGraphics(); * * Thread safety: Must only be called from the main thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palEnumerateAdapters( int32_t* count, @@ -4006,7 +3965,7 @@ PAL_API PalResult PAL_CALL palEnumerateAdapters( * * Thread safety: Thread safe if `info` is per thread. * - * @since 1.4 + * @since 2.0 * @sa palEnumerateAdapters */ PAL_API PalResult PAL_CALL palGetAdapterInfo( @@ -4026,7 +3985,7 @@ PAL_API PalResult PAL_CALL palGetAdapterInfo( * * Thread safety: Thread safe if `caps` is per thread. * - * @since 1.4 + * @since 2.0 * @sa palEnumerateAdapters */ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( @@ -4044,7 +4003,7 @@ PAL_API PalResult PAL_CALL palGetAdapterCapabilities( * * Thread safety: Thread safe. * - * @since 1.4 + * @since 2.0 * @sa palEnumerateAdapters */ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); @@ -4062,7 +4021,7 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); * * Thread safety: Thread safe. * - * @since 1.4 + * @since 2.0 * @sa palEnumerateAdapters */ PAL_API uint32_t PAL_CALL palGetHighestSupportedShaderTarget( @@ -4088,7 +4047,7 @@ PAL_API uint32_t PAL_CALL palGetHighestSupportedShaderTarget( * * Thread safety: Thread safe if `adapter` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyDevice */ PAL_API PalResult PAL_CALL palCreateDevice( @@ -4108,7 +4067,7 @@ PAL_API PalResult PAL_CALL palCreateDevice( * Thread safety: Thread safe if the adapter used to create the device is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateDevice */ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); @@ -4133,7 +4092,7 @@ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); * Thread safety: Thread safe if `device` is externally synchronized and * `outMemory` is per thread. * - * @since 1.4 + * @since 2.0 * @sa palFreeMemory */ PAL_API PalResult PAL_CALL palAllocateMemory( @@ -4155,7 +4114,7 @@ PAL_API PalResult PAL_CALL palAllocateMemory( * Thread safety: Thread safe if `device` is externally synchronized and * `outMemory` is per thread. * - * @since 1.4 + * @since 2.0 * @sa palAllocateMemory */ PAL_API void PAL_CALL palFreeMemory( @@ -4178,7 +4137,7 @@ PAL_API void PAL_CALL palFreeMemory( * * Thread safety: Thread safe if `caps` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( PalDevice* device, @@ -4200,7 +4159,7 @@ PAL_API PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( * * Thread safety: Thread safe if `caps` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palQueryMultiViewCapabilities( PalDevice* device, @@ -4222,7 +4181,7 @@ PAL_API PalResult PAL_CALL palQueryMultiViewCapabilities( * * Thread safety: Thread safe if `caps` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palQueryMultiViewportCapabilities( PalDevice* device, @@ -4244,7 +4203,7 @@ PAL_API PalResult PAL_CALL palQueryMultiViewportCapabilities( * * Thread safety: Thread safe if `caps` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, @@ -4266,7 +4225,7 @@ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( * * Thread safety: Thread safe if `caps` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( PalDevice* device, @@ -4288,7 +4247,7 @@ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( * * Thread safety: Thread safe if `caps` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( PalDevice* device, @@ -4310,7 +4269,7 @@ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( * * Thread safety: Thread safe if `caps` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( PalDevice* device, @@ -4332,7 +4291,7 @@ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( * * Thread safety: Thread safe if `caps` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( PalDevice* device, @@ -4361,7 +4320,7 @@ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyQueue */ PAL_API PalResult PAL_CALL palCreateQueue( @@ -4381,7 +4340,7 @@ PAL_API PalResult PAL_CALL palCreateQueue( * Thread safety: Thread safe if the device used to create the queue is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateQueue */ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); @@ -4398,7 +4357,7 @@ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); * * Thread safety: Must only be called from the main thread. * - * @since 1.4 + * @since 2.0 * @sa palCreateQueue */ PAL_API PalBool PAL_CALL palCanQueuePresent( @@ -4420,7 +4379,7 @@ PAL_API PalBool PAL_CALL palCanQueuePresent( * * Thread safety: Thread safe if `queue` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); @@ -4446,7 +4405,7 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); * * Thread safety: Thread safe if `outFormats` is per thread. * - * @since 1.4 + * @since 2.0 * @sa palIsFormatSupported */ PAL_API PalResult PAL_CALL palEnumerateFormats( @@ -4470,7 +4429,7 @@ PAL_API PalResult PAL_CALL palEnumerateFormats( * * Thread safety: Thread safe. * - * @since 1.4 + * @since 2.0 * @sa palQueryFormatImageUsages * @sa palQueryFormatImageViewUsages */ @@ -4490,7 +4449,7 @@ PAL_API PalBool PAL_CALL palIsFormatSupported( * * Thread safety: Thread safe. * - * @since 1.4 + * @since 2.0 */ PAL_API PalImageUsages PAL_CALL palQueryFormatImageUsages( PalAdapter* adapter, @@ -4508,7 +4467,7 @@ PAL_API PalImageUsages PAL_CALL palQueryFormatImageUsages( * * Thread safety: Thread safe. * - * @since 1.4 + * @since 2.0 */ PAL_API PalSampleCount PAL_CALL palQueryFormatSampleCount( PalAdapter* adapter, @@ -4533,7 +4492,7 @@ PAL_API PalSampleCount PAL_CALL palQueryFormatSampleCount( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyImage */ PAL_API PalResult PAL_CALL palCreateImage( @@ -4553,7 +4512,7 @@ PAL_API PalResult PAL_CALL palCreateImage( * Thread safety: Thread safe if the device used to create the image is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateImage */ PAL_API void PAL_CALL palDestroyImage(PalImage* image); @@ -4572,7 +4531,7 @@ PAL_API void PAL_CALL palDestroyImage(PalImage* image); * * Thread safety: Thread safe if `info` is per thread. * - * @since 1.4 + * @since 2.0 * @sa palCreateImage */ PAL_API PalResult PAL_CALL palGetImageInfo( @@ -4592,7 +4551,7 @@ PAL_API PalResult PAL_CALL palGetImageInfo( * * Thread safety: Thread safe if `requirements` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( PalImage* image, @@ -4614,7 +4573,7 @@ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( * * Thread safety: Thread safe if `requirements` is per thread. * - * @since 1.4 + * @since 2.0 * @sa palGetImageMemoryRequirements */ PAL_API PalResult PAL_CALL palBindImageMemory( @@ -4645,7 +4604,7 @@ PAL_API PalResult PAL_CALL palBindImageMemory( * Mapping with different offsets into the same image is thread safe as long as `image` * is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palUnmapImageMemory */ PAL_API PalResult PAL_CALL palMapImageMemory( @@ -4664,7 +4623,7 @@ PAL_API PalResult PAL_CALL palMapImageMemory( * * Thread safety: Thread safe if `image` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palMapImageMemory */ PAL_API void PAL_CALL palUnmapImageMemory(PalImage* image); @@ -4692,7 +4651,7 @@ PAL_API void PAL_CALL palUnmapImageMemory(PalImage* image); * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyImageView */ PAL_API PalResult PAL_CALL palCreateImageView( @@ -4713,7 +4672,7 @@ PAL_API PalResult PAL_CALL palCreateImageView( * Thread safety: Thread safe if the device used to create the image view is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateImageView */ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); @@ -4735,7 +4694,7 @@ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroySampler */ PAL_API PalResult PAL_CALL palCreateSampler( @@ -4755,7 +4714,7 @@ PAL_API PalResult PAL_CALL palCreateSampler( * Thread safety: Thread safe if the device used to create the sampler is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateSampler */ PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); @@ -4777,7 +4736,7 @@ PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroySurface */ PAL_API PalResult PAL_CALL palCreateSurface( @@ -4797,7 +4756,7 @@ PAL_API PalResult PAL_CALL palCreateSurface( * Thread safety: Thread safe if the device used to create the surface is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateSurface */ PAL_API void PAL_CALL palDestroySurface(PalSurface* surface); @@ -4819,7 +4778,7 @@ PAL_API void PAL_CALL palDestroySurface(PalSurface* surface); * * Thread safety: Thread safe if `caps` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palGetSurfaceCapabilities( PalDevice* device, @@ -4846,7 +4805,7 @@ PAL_API PalResult PAL_CALL palGetSurfaceCapabilities( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroySwapchain */ PAL_API PalResult PAL_CALL palCreateSwapchain( @@ -4868,7 +4827,7 @@ PAL_API PalResult PAL_CALL palCreateSwapchain( * Thread safety: Thread safe if the device used to create the swapchain is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateSwapchain */ PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); @@ -4885,7 +4844,7 @@ PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); * * Thread safety: Thread safe. * - * @since 1.4 + * @since 2.0 * @sa palGetNextSwapchainImage */ PAL_API PalImage* PAL_CALL palGetSwapchainImage( @@ -4907,7 +4866,7 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( * * Thread safety: Thread safe if `swapchain` externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palGetSwapchainImage */ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( @@ -4929,7 +4888,7 @@ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( * * Thread safety: Must only be called from the main thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, @@ -4952,7 +4911,7 @@ PAL_API PalResult PAL_CALL palPresentSwapchain( * * Thread safety: Thread safe if `swapchain` externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palResizeSwapchain( PalSwapchain* swapchain, @@ -4991,7 +4950,7 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * * @note The shader entry name must not be greater than `PAL_SHADER_ENTRY_NAME_SIZE (32)`. * - * @since 1.4 + * @since 2.0 * @sa palDestroyShader */ PAL_API PalResult PAL_CALL palCreateShader( @@ -5011,7 +4970,7 @@ PAL_API PalResult PAL_CALL palCreateShader( * Thread safety: Thread safe if the device used to create the shader is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateShader */ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); @@ -5031,7 +4990,7 @@ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyFence */ PAL_API PalResult PAL_CALL palCreateFence( @@ -5051,7 +5010,7 @@ PAL_API PalResult PAL_CALL palCreateFence( * Thread safety: Thread safe if the device used to create the fence is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateFence */ PAL_API void PAL_CALL palDestroyFence(PalFence* fence); @@ -5072,7 +5031,7 @@ PAL_API void PAL_CALL palDestroyFence(PalFence* fence); * * Thread safety: Thread safe if `fence` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palIsFenceSignaled */ PAL_API PalResult PAL_CALL palWaitFence( @@ -5094,7 +5053,7 @@ PAL_API PalResult PAL_CALL palWaitFence( * * Thread safety: Thread safe if `fence` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palIsFenceSignaled */ PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); @@ -5110,7 +5069,7 @@ PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); * * Thread safety: Thread safe. * - * @since 1.4 + * @since 2.0 * @sa palResetFence * @sa palWaitFence */ @@ -5131,7 +5090,7 @@ PAL_API PalBool PAL_CALL palIsFenceSignaled(PalFence* fence); * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroySemaphore */ PAL_API PalResult PAL_CALL palCreateSemaphore( @@ -5151,7 +5110,7 @@ PAL_API PalResult PAL_CALL palCreateSemaphore( * Thread safety: Thread safe if the device used to create the semaphore is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateSemaphore */ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); @@ -5173,7 +5132,7 @@ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); * * Thread safety: Thread safe if `semaphore` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palSignalSemaphore * @sa palGetSemaphoreValue */ @@ -5199,7 +5158,7 @@ PAL_API PalResult PAL_CALL palWaitSemaphore( * * Thread safety: Thread safe if `queue` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palWaitSemaphore * @sa palGetSemaphoreValue */ @@ -5224,7 +5183,7 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * * Thread safety: Thread safe if `semaphore` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palWaitSemaphore * @sa palSignalSemaphore */ @@ -5246,7 +5205,7 @@ PAL_API PalResult PAL_CALL palGetSemaphoreValue( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyCommandPool */ PAL_API PalResult PAL_CALL palCreateCommandPool( @@ -5268,7 +5227,7 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( * Thread safety: Thread safe if the device used to create the command pool is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateCommandPool */ PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); @@ -5285,7 +5244,7 @@ PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); * * Thread safety: Thread safe if `pool` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); @@ -5304,7 +5263,7 @@ PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); * * Thread safety: Thread safe if `device` and `pool` are externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palFreeCommandBuffer */ PAL_API PalResult PAL_CALL palAllocateCommandBuffer( @@ -5325,7 +5284,7 @@ PAL_API PalResult PAL_CALL palAllocateCommandBuffer( * Thread safety: Thread safe if the command pool used to create the command buffer is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palAllocateCommandBuffer */ PAL_API void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -5342,7 +5301,7 @@ PAL_API void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer); * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); @@ -5361,7 +5320,7 @@ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); * * Thread safety: Thread safe if `queue` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, @@ -5380,7 +5339,7 @@ PAL_API PalResult PAL_CALL palSubmitCommandBuffer( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCmdEnd */ PAL_API PalResult PAL_CALL palCmdBegin( @@ -5399,7 +5358,7 @@ PAL_API PalResult PAL_CALL palCmdBegin( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCmdBegin */ PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); @@ -5418,7 +5377,7 @@ PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); * * Thread safety: Thread safe if `primaryCmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, @@ -5441,7 +5400,7 @@ PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( PalCommandBuffer* cmdBuffer, @@ -5467,7 +5426,7 @@ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( @@ -5498,7 +5457,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * - * @since 1.4 + * @since 2.0 * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( @@ -5529,7 +5488,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * - * @since 1.4 + * @since 2.0 * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( @@ -5555,7 +5514,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, @@ -5575,7 +5534,7 @@ PAL_API PalResult PAL_CALL palCmdBuildAccelerationStructure( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdBeginRendering( PalCommandBuffer* cmdBuffer, @@ -5593,7 +5552,7 @@ PAL_API PalResult PAL_CALL palCmdBeginRendering( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); @@ -5616,7 +5575,7 @@ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdCopyBuffer( PalCommandBuffer* cmdBuffer, @@ -5640,7 +5599,7 @@ PAL_API PalResult PAL_CALL palCmdCopyBuffer( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdCopyBufferToImage( PalCommandBuffer* cmdBuffer, @@ -5664,7 +5623,7 @@ PAL_API PalResult PAL_CALL palCmdCopyBufferToImage( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdCopyImage( PalCommandBuffer* cmdBuffer, @@ -5688,7 +5647,7 @@ PAL_API PalResult PAL_CALL palCmdCopyImage( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( PalCommandBuffer* cmdBuffer, @@ -5710,7 +5669,7 @@ PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, @@ -5731,7 +5690,7 @@ PAL_API PalResult PAL_CALL palCmdBindPipeline( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdSetViewport( PalCommandBuffer* cmdBuffer, @@ -5753,7 +5712,7 @@ PAL_API PalResult PAL_CALL palCmdSetViewport( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdSetScissors( PalCommandBuffer* cmdBuffer, @@ -5779,7 +5738,7 @@ PAL_API PalResult PAL_CALL palCmdSetScissors( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, @@ -5805,7 +5764,7 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( PalCommandBuffer* cmdBuffer, @@ -5831,7 +5790,7 @@ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 * @sa palDrawIndexed */ PAL_API PalResult PAL_CALL palCmdDraw( @@ -5862,7 +5821,7 @@ PAL_API PalResult PAL_CALL palCmdDraw( * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * - * @since 1.4 + * @since 2.0 * @sa palDrawIndexedIndirect */ PAL_API PalResult PAL_CALL palCmdDrawIndirect( @@ -5892,7 +5851,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirect( * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * - * @since 1.4 + * @since 2.0 * @sa palCmdDrawIndexedIndirectCount */ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( @@ -5920,7 +5879,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 * @sa palDraw */ PAL_API PalResult PAL_CALL palCmdDrawIndexed( @@ -5952,7 +5911,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexed( * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * - * @since 1.4 + * @since 2.0 * @sa palDrawIndirect */ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( @@ -5982,7 +5941,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * - * @since 1.4 + * @since 2.0 * @sa palCmdDrawIndirectCount */ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( @@ -6031,7 +5990,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 * @sa palCmdImageBarrier * @sa palCmdBufferBarrier */ @@ -6074,7 +6033,7 @@ PAL_API PalResult PAL_CALL palCmdAccelerationStructureBarrier( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCmdAccelerationStructureBarrier * @sa palCmdBufferBarrier */ @@ -6117,7 +6076,7 @@ PAL_API PalResult PAL_CALL palCmdImageBarrier( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCmdAccelerationStructureBarrier * @sa palCmdImageBarrier */ @@ -6144,7 +6103,7 @@ PAL_API PalResult PAL_CALL palCmdBufferBarrier( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDispatch( @@ -6176,7 +6135,7 @@ PAL_API PalResult PAL_CALL palCmdDispatch( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDispatchBase( @@ -6207,7 +6166,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * - * @since 1.4 + * @since 2.0 * @sa palBuildWorkGroupInfo */ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( @@ -6236,7 +6195,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, @@ -6270,7 +6229,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, @@ -6294,7 +6253,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, @@ -6320,7 +6279,7 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( * * @note A pipeline must be bound before this call. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, @@ -6346,7 +6305,7 @@ PAL_API PalResult PAL_CALL palCmdPushConstants( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdSetCullMode( PalCommandBuffer* cmdBuffer, @@ -6368,7 +6327,7 @@ PAL_API PalResult PAL_CALL palCmdSetCullMode( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdSetFrontFace( PalCommandBuffer* cmdBuffer, @@ -6390,7 +6349,7 @@ PAL_API PalResult PAL_CALL palCmdSetFrontFace( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdSetPrimitiveTopology( PalCommandBuffer* cmdBuffer, @@ -6412,7 +6371,7 @@ PAL_API PalResult PAL_CALL palCmdSetPrimitiveTopology( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdSetDepthTestEnable( PalCommandBuffer* cmdBuffer, @@ -6434,7 +6393,7 @@ PAL_API PalResult PAL_CALL palCmdSetDepthTestEnable( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdSetDepthWriteEnable( PalCommandBuffer* cmdBuffer, @@ -6460,7 +6419,7 @@ PAL_API PalResult PAL_CALL palCmdSetDepthWriteEnable( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCmdSetStencilOp( PalCommandBuffer* cmdBuffer, @@ -6492,7 +6451,7 @@ PAL_API PalResult PAL_CALL palCmdSetStencilOp( * @note The memory associated with PalAccelerationStructureCreateInfo::buffer must be * `PAL_MEMORY_TYPE_GPU_ONLY`. * - * @since 1.4 + * @since 2.0 * @sa palDestroyAccelerationstructure */ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( @@ -6512,7 +6471,7 @@ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( * Thread safety: Thread safe if the device used to create the acceleration structure is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateAccelerationstructure */ PAL_API void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* as); @@ -6537,7 +6496,7 @@ PAL_API void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( PalDevice* device, @@ -6569,7 +6528,7 @@ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyBuffer */ PAL_API PalResult PAL_CALL palCreateBuffer( @@ -6589,7 +6548,7 @@ PAL_API PalResult PAL_CALL palCreateBuffer( * Thread safety: Thread safe if the device used to create the buffer is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateBuffer */ PAL_API void PAL_CALL palDestroyBuffer(PalBuffer* buffer); @@ -6607,7 +6566,7 @@ PAL_API void PAL_CALL palDestroyBuffer(PalBuffer* buffer); * * Thread safety: Thread safe if `requirements` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( PalBuffer* buffer, @@ -6633,7 +6592,7 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( PalDevice* device, @@ -6668,7 +6627,7 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( PalDevice* device, @@ -6694,7 +6653,7 @@ PAL_API PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( PalDevice* device, @@ -6719,7 +6678,7 @@ PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palWriteToImageCopyStagingBuffer( PalDevice* device, @@ -6744,7 +6703,7 @@ PAL_API PalResult PAL_CALL palWriteToImageCopyStagingBuffer( * * Thread safety: Thread safe if `requirements` is per thread. * - * @since 1.4 + * @since 2.0 * @sa palGetBufferMemoryRequirements */ PAL_API PalResult PAL_CALL palBindBufferMemory( @@ -6775,7 +6734,7 @@ PAL_API PalResult PAL_CALL palBindBufferMemory( * Mapping with different offsets into the same buffer is thread safe as long as `buffer` * is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palUnmapBufferMemory */ PAL_API PalResult PAL_CALL palMapBufferMemory( @@ -6794,7 +6753,7 @@ PAL_API PalResult PAL_CALL palMapBufferMemory( * * Thread safety: Thread safe if `buffer` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palMapBufferMemory */ PAL_API void PAL_CALL palUnmapBufferMemory(PalBuffer* buffer); @@ -6811,7 +6770,7 @@ PAL_API void PAL_CALL palUnmapBufferMemory(PalBuffer* buffer); * * Thread safety: Thread safe if `buffer` is per thread. * - * @since 1.4 + * @since 2.0 */ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); @@ -6842,7 +6801,7 @@ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyDescriptorSetLayout */ PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( @@ -6862,7 +6821,7 @@ PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( * Thread safety: Thread safe if the device used to create the descriptor set layout is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateDescriptorSetLayout */ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layout); @@ -6887,7 +6846,7 @@ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layo * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyDescriptorPool */ PAL_API PalResult PAL_CALL palCreateDescriptorPool( @@ -6907,7 +6866,7 @@ PAL_API PalResult PAL_CALL palCreateDescriptorPool( * Thread safety: Thread safe if the device used to create the descriptor pool is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateDescriptorPool */ PAL_API void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool); @@ -6924,7 +6883,7 @@ PAL_API void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool); * * Thread safety: Thread safe if `pool` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); @@ -6948,7 +6907,7 @@ PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); * * Thread safety: Thread safe if `device` and `pool` are externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( PalDevice* device, @@ -6979,7 +6938,7 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palUpdateDescriptorSet( PalDevice* device, @@ -7002,7 +6961,7 @@ PAL_API PalResult PAL_CALL palUpdateDescriptorSet( * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyPipelineLayout */ PAL_API PalResult PAL_CALL palCreatePipelineLayout( @@ -7022,7 +6981,7 @@ PAL_API PalResult PAL_CALL palCreatePipelineLayout( * Thread safety: Thread safe if the device used to create the pipeline layout is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreatePipelineLayout */ PAL_API void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout); @@ -7042,7 +7001,7 @@ PAL_API void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout); * * Thread safety: Thread safe if `device` is externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palDestroyPipeline */ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( @@ -7067,7 +7026,7 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( * * @note The first entry of the compute shader will be used. * - * @since 1.4 + * @since 2.0 * @sa palDestroyPipeline */ PAL_API PalResult PAL_CALL palCreateComputePipeline( @@ -7095,7 +7054,7 @@ PAL_API PalResult PAL_CALL palCreateComputePipeline( * * @note The shader group array must be in this order [raygen][miss][hitgroup][callable]. * - * @since 1.4 + * @since 2.0 * @sa palDestroyPipeline */ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( @@ -7115,7 +7074,7 @@ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( * Thread safety: Thread safe if the device used to create the pipeline is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateGraphicsPipeline * @sa palCreateComputePipeline * @sa palCreateRayTracingPipeline @@ -7146,7 +7105,7 @@ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); * * @note The records array must be in this order [raygen][miss][hitgroup][callable]. * - * @since 1.4 + * @since 2.0 * @sa palDestroyShaderBindingTable */ PAL_API PalResult PAL_CALL palCreateShaderBindingTable( @@ -7166,7 +7125,7 @@ PAL_API PalResult PAL_CALL palCreateShaderBindingTable( * Thread safety: Thread safe if the device used to create the shader binding table is * externally synchronized. * - * @since 1.4 + * @since 2.0 * @sa palCreateShaderBindingTable */ PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); @@ -7189,7 +7148,7 @@ PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); * * Thread safety: Thread safe if `sbt` is externally synchronized. * - * @since 1.4 + * @since 2.0 */ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( PalShaderBindingTable* sbt, @@ -7219,7 +7178,7 @@ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( * * Thread safety: Must only be called from the main thread. * - * @since 1.4 + * @since 2.0 * @sa palCmdDrawMeshTasks * @sa palCmdDrawMeshTasksIndirect * @sa palCmdDrawMeshTasksIndirectCount From 6a593344e3275745980a921d92eb4f4ff66bf340 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 20 Jun 2026 12:59:31 +0000 Subject: [PATCH 286/372] finish core changelog --- CHANGELOG.md | 139 ++++++++++++++++++++++++++++------------- include/pal/pal_core.h | 6 +- 2 files changed, 98 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e90c55ca..2a85d9b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -123,33 +123,104 @@ palJoinThread(thread, &retval); ## [2.0.0] - 2026-01-00 -### Features -- **Core:** Added **PAL_RESULT_INVALID_HANDLE** result code. -- **Core:** Added **PAL_RESULT_FEATURE_NOT_SUPPORTED** result code. -- **Core:** Added **PAL_RESULT_NOT_INITIALIZED** result code. -- **Core:** Added **PAL_RESULT_DEVICE_LOST** result code. -- **Core:** Added **PAL_RESULT_OUT_OF_DATE** result code. -- **Core:** Added **palGetResultCode()**. - -- **Graphics:** Added **Graphics System To PAL**. +### Core +Added +- Added `PalBool` type. +- Added `palGetResultCode()` to get the result code from a result value. +- Added `PAL_RESULT_SUCCESS` define. +- Added `PAL_RESULT_INVALID_ARGUMENT` define. +- Added `PAL_RESULT_OUT_OF_MEMORY` define. +- Added `PAL_RESULT_PLATFORM_FAILURE` define. +- Added `PAL_RESULT_TIMEOUT` define. +- Added `PAL_RESULT_INVALID_HANDLE` define. +- Added `PAL_RESULT_FEATURE_NOT_SUPPORTED` define. +- Added `PAL_RESULT_NOT_INITIALIZED` define. +- Added `PAL_RESULT_INVALID_OPERATION` define. +- Added `PAL_RESULT_DEVICE_LOST` define. +- Added `PAL_RESULT_OUT_OF_DATE` define. +- Added `PAL_TRUE` define. +- Added `PAL_FALSE` define. + +Changed +- `PalResult` is now a `uint64_t` instead of an enum. +- Replaced `Int8` with `int8_t`. +- Replaced `Int16` with `int16_t`. +- Replaced `Int32` with `int32_t`. +- Replaced `Int64` with `int64_t`. +- Replaced `IntPtr` with `intptr_t`. +- Replaced `Uint8` with `uint8_t`. +- Replaced `Uint16` with `uint16_t`. +- Replaced `Uint32` with `uint32_t`. +- Replaced `Uint64` with `uint64_t`. +- Replaced `UintPtr` with `uintptr_t`. +- `palFormatResult()` now takes two more additional parameters. +- `palGetVersion()` now returns `void` and takes an output parameter. + +Removed +- `PalResult` enum. +- `Int8` type. +- `Int16` type. +- `Int32` type. +- `Int64` type. +- `IntPtr` type. +- `Uint8` type. +- `Uint16` type. +- `Uint32` type. +- `Uint64` type. +- `UintPtr` type. +- `PAL_RESULT_SUCCESS` enum value. +- `PAL_RESULT_INVALID_ARGUMENT` enum value. +- `PAL_RESULT_OUT_OF_MEMORY` enum value. +- `PAL_RESULT_PLATFORM_FAILURE` enum value. +- `PAL_RESULT_TIMEOUT` enum value. +- `PAL_RESULT_INVALID_OPERATION` enum value. +- `PAL_RESULT_NULL_POINTER` enum value. +- `PAL_RESULT_INVALID_ALLOCATOR` enum value. +- `PAL_RESULT_ACCESS_DENIED` enum value. +- `PAL_RESULT_INSUFFICIENT_BUFFER` enum value. +- `PAL_RESULT_INVALID_THREAD` enum value. +- `PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED` enum value. +- `PAL_RESULT_VIDEO_NOT_INITIALIZED` enum value. +- `PAL_RESULT_INVALID_MONITOR` enum value. +- `PAL_RESULT_INVALID_MONITOR_MODE` enum value. +- `PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED` enum value. +- `PAL_RESULT_INVALID_KEYCODE` enum value. +- `PAL_RESULT_INVALID_SCANCODE` enum value. +- `PAL_RESULT_INVALID_MOUSE_BUTTON` enum value. +- `PAL_RESULT_GL_NOT_INITIALIZED` enum value. +- `PAL_RESULT_INVALID_GL_WINDOW` enum value. +- `PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED` enum value. +- `PAL_RESULT_INVALID_GL_FBCONFIG` enum value. +- `PAL_RESULT_INVALID_GL_VERSION` enum value. +- `PAL_RESULT_INVALID_GL_PROFILE` enum value. +- `PAL_RESULT_INVALID_GL_CONTEXT` enum value. +- `PAL_RESULT_INVALID_FBCONFIG_BACKEND` enum value. + +### Video +Added + +Changed + +Removed + +### Opengl +Added + +Changed + +Removed + +### Thread +Added + +Changed + +Removed +### Features - **Opengl:** Added **palGetSupportedGLAPIs()**. ### Changed -- **All systems:** All enum types have been changed to defines and explicit width types. - -- **Core:** Rename **Int8** to **int8_t**. -- **Core:** Rename **Int16** to **int16_t**. -- **Core:** Rename **Int32** to **int32_t**. -- **Core:** Rename **Int64** to **int64_t**. -- **Core:** Rename **IntPtr** to **intptr_t**. -- **Core:** Rename **Uint8** to **uint8_t**. -- **Core:** Rename **Uint16** to **uint16_t**. -- **Core:** Rename **Uint32** to **uint32_t**. -- **Core:** Rename **Uint64** to **uint64_t**. -- **Core:** Rename **UintPtr** to **uintptr_t**. -- **Core:** **palFormatResult()** now takes two additional parameters. -- **Core:** **palGetVersion()** now takes a parameter and returns nothing. - **Thread:** **palJoinThread()** now takes a void** for retval parameter. @@ -166,27 +237,7 @@ palJoinThread(thread, &retval); `fbConfigIndex` fields. ### Removed -- **Core:** Removed **PAL_RESULT_NULL_POINTER** result code. -- **Core:** Removed **PAL_RESULT_INVALID_ALLOCATOR** result code. -- **Core:** Removed **PAL_RESULT_ACCESS_DENIED** result code. -- **Core:** Removed **PAL_RESULT_INSUFFICIENT_BUFFER** result code. -- **Core:** Removed **PAL_RESULT_INVALID_THREAD** result code. -- **Core:** Removed **PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED** result code. -- **Core:** Removed **PAL_RESULT_VIDEO_NOT_INITIALIZED** result code. -- **Core:** Removed **PAL_RESULT_INVALID_MONITOR** result code. -- **Core:** Removed **PAL_RESULT_INVALID_MONITOR_MODE** result code. -- **Core:** Removed **PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED** result code. -- **Core:** Removed **PAL_RESULT_INVALID_KEYCODE** result code. -- **Core:** Removed **PAL_RESULT_INVALID_SCANCODE** result code. -- **Core:** Removed **PAL_RESULT_INVALID_MOUSE_BUTTON** result code. -- **Core:** Removed **PAL_RESULT_GL_NOT_INITIALIZED** result code. -- **Core:** Removed **PAL_RESULT_INVALID_GL_WINDOW** result code. -- **Core:** Removed **PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED** result code. -- **Core:** Removed **PAL_RESULT_INVALID_GL_FBCONFIG** result code. -- **Core:** Removed **PAL_RESULT_INVALID_GL_VERSION** result code. -- **Core:** Removed **PAL_RESULT_INVALID_GL_PROFILE** result code. -- **Core:** Removed **PAL_RESULT_INVALID_GL_CONTEXT** result code. -- **Core:** Removed **PAL_RESULT_INVALID_FBCONFIG_BACKEND** result code. + - **Opengl:** Removed **palGLSetInstance** function. - **Opengl:** Removed **palGLGetBackend** function. diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 76cd875d..8d53e5f3 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -95,7 +95,7 @@ typedef uint32_t PalBool; * * All result codes follow the format `PAL_RESULT_**` for consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint64_t PalResult; @@ -212,7 +212,7 @@ PAL_API uint16_t PAL_CALL palGetResultCode(PalResult result); * * Thread safety: Thread safe if buffer is per thread. * - * @since 2.0 + * @since 1.0 */ PAL_API void PAL_CALL palFormatResult( PalResult result, @@ -226,7 +226,7 @@ PAL_API void PAL_CALL palFormatResult( * * Thread safety: Thread safe if version is per thread. * - * @since 2.0 + * @since 1.0 * @sa palGetVersionString */ PAL_API void PAL_CALL palGetVersion(PalVersion* version); From c5ce94bfb86b8aeec751d188464d4125fdea25ea Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 20 Jun 2026 13:32:52 +0000 Subject: [PATCH 287/372] finish event changelog --- CHANGELOG.md | 113 ++++++++++++++++++++++++++++++---------- include/pal/pal_core.h | 1 + include/pal/pal_event.h | 20 ++----- 3 files changed, 91 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a85d9b0..d870b48e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,34 +125,35 @@ palJoinThread(thread, &retval); ### Core Added -- Added `PalBool` type. -- Added `palGetResultCode()` to get the result code from a result value. -- Added `PAL_RESULT_SUCCESS` define. -- Added `PAL_RESULT_INVALID_ARGUMENT` define. -- Added `PAL_RESULT_OUT_OF_MEMORY` define. -- Added `PAL_RESULT_PLATFORM_FAILURE` define. -- Added `PAL_RESULT_TIMEOUT` define. -- Added `PAL_RESULT_INVALID_HANDLE` define. -- Added `PAL_RESULT_FEATURE_NOT_SUPPORTED` define. -- Added `PAL_RESULT_NOT_INITIALIZED` define. -- Added `PAL_RESULT_INVALID_OPERATION` define. -- Added `PAL_RESULT_DEVICE_LOST` define. -- Added `PAL_RESULT_OUT_OF_DATE` define. -- Added `PAL_TRUE` define. -- Added `PAL_FALSE` define. +- `PalBool` type. +- `palGetResultCode()` to get the result code from a result value. +- `PAL_RESULT_SUCCESS` define. +- `PAL_RESULT_INVALID_ARGUMENT` define. +- `PAL_RESULT_OUT_OF_MEMORY` define. +- `PAL_RESULT_PLATFORM_FAILURE` define. +- `PAL_RESULT_TIMEOUT` define. +- `PAL_RESULT_INVALID_HANDLE` define. +- `PAL_RESULT_FEATURE_NOT_SUPPORTED` define. +- `PAL_RESULT_NOT_INITIALIZED` define. +- `PAL_RESULT_INVALID_OPERATION` define. +- `PAL_RESULT_DEVICE_LOST` define. +- `PAL_RESULT_OUT_OF_DATE` define. +- `PAL_RESULT_MAX` define. +- `PAL_TRUE` define. +- `PAL_FALSE` define. Changed -- `PalResult` is now a `uint64_t` instead of an enum. -- Replaced `Int8` with `int8_t`. -- Replaced `Int16` with `int16_t`. -- Replaced `Int32` with `int32_t`. -- Replaced `Int64` with `int64_t`. -- Replaced `IntPtr` with `intptr_t`. -- Replaced `Uint8` with `uint8_t`. -- Replaced `Uint16` with `uint16_t`. -- Replaced `Uint32` with `uint32_t`. -- Replaced `Uint64` with `uint64_t`. -- Replaced `UintPtr` with `uintptr_t`. +- `PalResult` is now `uint64_t`. +- `Int8` is now `int8_t`. +- `Int16` is now `int16_t`. +- `Int32` is now `int32_t`. +- `Int64` is now `int64_t`. +- `IntPtr` is now `intptr_t`. +- `Uint8` is now `uint8_t`. +- `Uint16` is now `uint16_t`. +- `Uint32` is now `uint32_t`. +- `Uint64` is now `uint64_t`. +- `UintPtr` is now `uintptr_t`. - `palFormatResult()` now takes two more additional parameters. - `palGetVersion()` now returns `void` and takes an output parameter. @@ -196,12 +197,70 @@ Removed - `PAL_RESULT_INVALID_GL_CONTEXT` enum value. - `PAL_RESULT_INVALID_FBCONFIG_BACKEND` enum value. -### Video +### Event Added +- Added `PAL_EVENT_WINDOW_CLOSE` define. +- Added `PAL_EVENT_WINDOW_SIZE` define. +- Added `PAL_EVENT_WINDOW_MOVE` define. +- Added `PAL_EVENT_WINDOW_STATE` define. +- Added `PAL_EVENT_WINDOW_FOCUS` define. +- Added `PAL_EVENT_WINDOW_VISIBILITY` define. +- Added `PAL_EVENT_WINDOW_MODAL_BEGIN` define. +- Added `PAL_EVENT_WINDOW_MODAL_END` define. +- Added `PAL_EVENT_MONITOR_DPI_CHANGED` define. +- Added `PAL_EVENT_MONITOR_LIST_CHANGED` define. +- Added `PAL_EVENT_KEYDOWN` define. +- Added `PAL_EVENT_KEYREPEAT` define. +- Added `PAL_EVENT_KEYUP` define. +- Added `PAL_EVENT_MOUSE_BUTTONDOWN` define. +- Added `PAL_EVENT_MOUSE_BUTTONUP` define. +- Added `PAL_EVENT_MOUSE_MOVE` define. +- Added `PAL_EVENT_MOUSE_DELTA` define. +- Added `PAL_EVENT_MOUSE_WHEEL` define. +- Added `PAL_EVENT_USER` define. +- Added `PAL_EVENT_KEYCHAR` define. +- Added `PAL_EVENT_WINDOW_DECORATION_MODE` define. +- Added `PAL_EVENT_MAX` define. +- Added `PAL_DISPATCH_NONE` define. +- Added `PAL_DISPATCH_CALLBACK` define. +- Added `PAL_DISPATCH_POLL` define. +- Added `PAL_DISPATCH_MAX` define. +- Added `PAL_DECORATION_MODE_CLIENT_SIDE` define. +- Added `PAL_DECORATION_MODE_CLIENT_SIDE` define. Changed +- `PalEventType` is now a `uint64_t`. Removed +- `PalEventType` enum. +- `PAL_EVENT_WINDOW_CLOSE` enum value. +- `PAL_EVENT_WINDOW_SIZE` enum value. +- `PAL_EVENT_WINDOW_MOVE` enum value. +- `PAL_EVENT_WINDOW_STATE` enum value. +- `PAL_EVENT_WINDOW_FOCUS` enum value. +- `PAL_EVENT_WINDOW_VISIBILITY` enum value. +- `PAL_EVENT_WINDOW_MODAL_BEGIN` enum value. +- `PAL_EVENT_WINDOW_MODAL_END` enum value. +- `PAL_EVENT_MONITOR_DPI_CHANGED` enum value. +- `PAL_EVENT_MONITOR_LIST_CHANGED` enum value. +- `PAL_EVENT_KEYDOWN` enum value. +- `PAL_EVENT_KEYREPEAT` enum value. +- `PAL_EVENT_KEYUP` enum value. +- `PAL_EVENT_MOUSE_BUTTONDOWN` enum value. +- `PAL_EVENT_MOUSE_BUTTONUP` enum value. +- `PAL_EVENT_MOUSE_MOVE` enum value. +- `PAL_EVENT_MOUSE_DELTA` enum value. +- `PAL_EVENT_MOUSE_WHEEL` enum value. +- `PAL_EVENT_USER` enum value. +- `PAL_EVENT_KEYCHAR` enum value. +- `PAL_EVENT_WINDOW_DECORATION_MODE` enum value. +- `PAL_EVENT_MAX` enum value. +- `PAL_DISPATCH_NONE` enum value. +- `PAL_DISPATCH_CALLBACK` enum value. +- `PAL_DISPATCH_POLL` enum value. +- `PAL_DISPATCH_MAX` enum value. +- `PAL_DECORATION_MODE_CLIENT_SIDE` enum value. +- `PAL_DECORATION_MODE_CLIENT_SIDE` enum value. ### Opengl Added diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 8d53e5f3..c94ccdd6 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -70,6 +70,7 @@ #define PAL_RESULT_INVALID_OPERATION 8 #define PAL_RESULT_DEVICE_LOST 9 #define PAL_RESULT_OUT_OF_DATE 10 +#define PAL_RESULT_MAX 11 /** * @typedef PalBool diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 38e2db42..04a1c744 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -220,22 +220,10 @@ #define PAL_EVENT_MAX 21 -/** - * No dispatch. - */ #define PAL_DISPATCH_NONE 0 - -/** - * Dispatch to event callback. - */ #define PAL_DISPATCH_CALLBACK 1 - -/** - * Dispatch to event queue. - */ #define PAL_DISPATCH_POLL 2 - -#define PAL_DISPATCH_MAX +#define PAL_DISPATCH_MAX 3 /** * @struct PalEventDriver @@ -260,7 +248,7 @@ typedef struct PalEvent PalEvent; * All decoration types follow the format `PAL_DECORATION_MODE_**` for * consistency and API use. * - * @since 2.0 + * @since 1.3 */ typedef uint32_t PalDecorationMode; @@ -271,7 +259,7 @@ typedef uint32_t PalDecorationMode; * All event types follow the format `PAL_EVENT_**` for consistency and * API use. * - * @since 2.0 + * @since 1.0 */ typedef uint64_t PalEventType; @@ -282,7 +270,7 @@ typedef uint64_t PalEventType; * All dispatch modes follow the format `PAL_DISPATCH_**` for consistency * and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint64_t PalDispatchMode; From 67a031e7c54153e59582f48c9e220375fd8f6345 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 20 Jun 2026 17:33:51 +0000 Subject: [PATCH 288/372] update changelog style --- CHANGELOG.md | 382 +++++++++++++++------------------------ include/pal/pal_opengl.h | 28 ++- 2 files changed, 161 insertions(+), 249 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d870b48e..ee536a17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,74 +1,118 @@ -# CHANGELOG -## [1.0.0] - 2025-09-27 -- Initial stable release of PAL. +## 2.0.0 -## [1.0.1] - 2025-10-01 +### Features -**Bugfix release** - improve C/C++ interop and build integration +- Added `palGetResultCode()` to get the result code from a result value. +- Added new `PalResult` values: + - `PAL_RESULT_INVALID_HANDLE` + - `PAL_RESULT_FEATURE_NOT_SUPPORTED` + - `PAL_RESULT_NOT_INITIALIZED` + - `PAL_RESULT_OUT_OF_DATE` + - `PAL_RESULT_MAX` +- Added type `PalGLBackend` with values: + - `PAL_GL_BACKEND_EGL` + - `PAL_GL_BACKEND_GLX` + - `PAL_GL_BACKEND_WGL` +- Added type `PalGLAPI` with values: + - `PAL_GL_API_OPENGL` + - `PAL_GL_API_OPENGL_ES` + +### Changes + +- Converted `PalResult` from an enum type to `uint64_t` and the values to constants. +- Removed all previous `PalResult` values except: + - `PAL_RESULT_SUCCESS` + - `PAL_RESULT_INVALID_ARGUMENT` + - `PAL_RESULT_PLATFORM_FAILURE` + - `PAL_RESULT_OUT_OF_MEMORY` + - `PAL_RESULT_TIMEOUT` + - `PAL_RESULT_INVALID_OPERATION`. + - `PAL_RESULT_DEVICE_LOST`. +- Removed `UintXX` and `IntXX` types in favor of standard `uintXX_t` and `intXX_t`. +- Replaced standard `bool` type and `true`/`false` constants with `PalBool` type and `PAL_TRUE`/`PAL_FALSE`. +- `palGetVersion()` now returns `void` and takes a pointer to the struct. +- `palFormatResult()` now takes two additional parameters. +- Converted `PalEventType` from an enum type to `uint64_t` and the values to constants. +- Converted `PalGLExtensions` from an enum type to `uint64_t` and the values to constants. +- Converted `PalGLProfile` from an enum type to `uint32_t` and the values to constants. +- Converted `PalGLContextReset` from an enum type to `uint32_t` and the values to constants. +- Converted `PalGLReleaseBehavior` from an enum type to `uint32_t` and the values to constants. -### Fixed -- Added extern "C" guards to all exported functions so PAL can now be linked from both **C** and **C++** projects. -- Fixed a **condition variable** bug where the wrong thread could acquire the mutex first, causing intermittent locking issues. See **tests/condvar_test.c** -- Updated premake scripts to allow **PAL to be included as a submodule or directly in another workspace** if the build system is **premake**. +### Opengl +Added -### Notes -- No API or ABI changes -- Safe upgrade from **v1.0** - just rebuild your project after updating. +Changed -## [1.1.0] - 2025-10-17 + +typedef struct { + PalGLExtensions extensions; + uint32_t major; + uint32_t minor; + PalGLBackend backend; + PalGLAPI api; + char vendor[PAL_GL_VENDOR_NAME_SIZE]; + char graphicsCard[PAL_GL_GRAPHICS_CARD_NAME_SIZE]; + char version[PAL_GL_VERSION_NAME_SIZE]; +} PalGLInfo; + +PAL_API PalResult PAL_CALL palInitGL( + PalGLAPI api, + void* instance, + const PalAllocator* allocator); + + PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( + int32_t* count, + PalGLFBConfig* configs); + +PAL_API const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance); + +Removed ### Features -- **Build:** Added Linux platform support across all modules. -- **Core:** Added Linux backend support. -- **Video:** Added X11-based backend support. -- **Thread:** Added Linux backend support. -- **Opengl:** Added Linux backend support. -- **System:** Added Linux backend support. -- **Video:** Added **palCreateCursorFrom()** to create system cursors. -- **Video:** Added **palSetFBConfig()** to select window FBConfig. -- **Video:** Added **PAL_VIDEO_FEATURE_WINDOW_SET_ICON** to `PalVideoFeatures` enum. -- **System:** Added **PAL_PLATFORM_API_COCOA** to `PalPlatformApiType` enum. -- **System:** Added **PAL_PLATFORM_API_ANDRIOD** to `PalPlatformApiType` enum. -- **System:** Added **PAL_PLATFORM_API_UIKIT** to `PalPlatformApiType` enum. -- **System:** Added **PAL_PLATFORM_API_HEADLESS** to `PalPlatformApiType` enum. -- **Core:** Added **PAL_RESULT_INVALID_FBCONFIG_BACKEND** to `PalResult` enum. +- **Opengl:** Added **palGetSupportedGLAPIs()**. ### Changed -- **System:** `PalCPUInfo.architecture` is now determined at runtime instead of build time. -- **Opengl:** **palEnumerateGLFBConfigs()** now does not use the `glWindow` paramter. Set to `nullptr` -### Fixed -- Fixed a bug where **enter modal mode and exit modal mode** operations triggered only one event. -- Fixed repeated window state event (**minimized**, **maximized**, **restore**). +- **Thread:** **palJoinThread()** now takes a void** for retval parameter. -### Notes -- No API or ABI changes - existing Windows code remains compatible. -- Linux video support currently targets **X11** only: **Wayland** is planned for future releases. -- Safe upgrade from **v1.0.1** - just rebuild your project after updating. +- **Opengl:** **palEnumerateGLFBConfigs()** now does not take glWindow parameter anymore. +- **Opengl:** **palInitGL()** now takes an api and instance parameter. +- **Opengl:** rename **PalGLRelease** to **PalGLReleaseBehavior**. +- **Opengl:** rename **palGLGetProcAddress()** to **palGetGLProcAddress()**. -## [1.2.0] - 2025-10-22 +- **Video:** **palGetWindowHandleInfo()** now takes an info parameter. +- **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. +- **Video:** **palGetMouseWheelDelta()** now takes floats instead of uint32_t. +- **Video:** **palInitVideo()** now takes a preferredInstance parameter. +- **Video:** **PalWindowCreateInfo** now has `appName`, `instanceName`, `fbConfigBackend` and +`fbConfigIndex` fields. -### Features -- **Video:** Added **palGetInstance()** to retrieve the native display or instance handle. -- **Video:** Added **palAttachWindow()** for attaching **foreign windows** to PAL. -- **Video:** Added **palDetachWindow()** for detaching **foreign windows** from PAL. -- **Event:** Added **PAL_EVENT_KEYCHAR** to `PalEventType` enum. -- **Event:** Added documentation for event bits(payload) layout. +### Removed -### Naming Update -- PAL now stands for **Prime Abstraction Layer**, -reflecting its role as the primary explicit foundation for OS and graphics abstraction. -- All API remains unchanged — this is an identity update only. + +- **Opengl:** Removed **palGLSetInstance** function. +- **Opengl:** Removed **palGLGetBackend** function. + +- **Video:** Removed **palGetVideoFeaturesEx** function. +- **Video:** Removed **palGetWindowHandleInfoEx** function. +- **Video:** Removed **palGetRawMouseWheelDelta** function. +- **Video:** Removed **palSetPreferredInstance** function. +- **Video:** Removed **palSetFBConfig** function. ### Tests -- Added multi-threaded OpenGL example: demonstrating **Multi-Threaded OpenGL Rendering**. see **multi_thread_opengl_test.c**. -- Added attaching and detach foreign windows example. see **attach_window_test.c** -- Added key character example. see **char_event_test.c** + +- Added grapics example: see **graphics_test.c** +- Added clear color example: see **clear_color_test.c** +- Added vertex shader/buffer triangle example: see **triangle_test.c** +- Added mesh example: see **mesh_test.c** +- Added compute example: see **compute_test.c** +- Added ray tracing example: see **ray_tracing_test.c** +- Added texture rendering example: see **texture_test.c** ### Notes -- No API or ABI changes - existing code remains compatible. -- Safe upgrade from **v1.1.0** - just rebuild your project after updating. +- API or ABI changes + ## [1.3.0] - 2025-11-21 @@ -121,201 +165,73 @@ void* retval; palJoinThread(thread, &retval); ``` -## [2.0.0] - 2026-01-00 -### Core -Added -- `PalBool` type. -- `palGetResultCode()` to get the result code from a result value. -- `PAL_RESULT_SUCCESS` define. -- `PAL_RESULT_INVALID_ARGUMENT` define. -- `PAL_RESULT_OUT_OF_MEMORY` define. -- `PAL_RESULT_PLATFORM_FAILURE` define. -- `PAL_RESULT_TIMEOUT` define. -- `PAL_RESULT_INVALID_HANDLE` define. -- `PAL_RESULT_FEATURE_NOT_SUPPORTED` define. -- `PAL_RESULT_NOT_INITIALIZED` define. -- `PAL_RESULT_INVALID_OPERATION` define. -- `PAL_RESULT_DEVICE_LOST` define. -- `PAL_RESULT_OUT_OF_DATE` define. -- `PAL_RESULT_MAX` define. -- `PAL_TRUE` define. -- `PAL_FALSE` define. - -Changed -- `PalResult` is now `uint64_t`. -- `Int8` is now `int8_t`. -- `Int16` is now `int16_t`. -- `Int32` is now `int32_t`. -- `Int64` is now `int64_t`. -- `IntPtr` is now `intptr_t`. -- `Uint8` is now `uint8_t`. -- `Uint16` is now `uint16_t`. -- `Uint32` is now `uint32_t`. -- `Uint64` is now `uint64_t`. -- `UintPtr` is now `uintptr_t`. -- `palFormatResult()` now takes two more additional parameters. -- `palGetVersion()` now returns `void` and takes an output parameter. - -Removed -- `PalResult` enum. -- `Int8` type. -- `Int16` type. -- `Int32` type. -- `Int64` type. -- `IntPtr` type. -- `Uint8` type. -- `Uint16` type. -- `Uint32` type. -- `Uint64` type. -- `UintPtr` type. -- `PAL_RESULT_SUCCESS` enum value. -- `PAL_RESULT_INVALID_ARGUMENT` enum value. -- `PAL_RESULT_OUT_OF_MEMORY` enum value. -- `PAL_RESULT_PLATFORM_FAILURE` enum value. -- `PAL_RESULT_TIMEOUT` enum value. -- `PAL_RESULT_INVALID_OPERATION` enum value. -- `PAL_RESULT_NULL_POINTER` enum value. -- `PAL_RESULT_INVALID_ALLOCATOR` enum value. -- `PAL_RESULT_ACCESS_DENIED` enum value. -- `PAL_RESULT_INSUFFICIENT_BUFFER` enum value. -- `PAL_RESULT_INVALID_THREAD` enum value. -- `PAL_RESULT_THREAD_FEATURE_NOT_SUPPORTED` enum value. -- `PAL_RESULT_VIDEO_NOT_INITIALIZED` enum value. -- `PAL_RESULT_INVALID_MONITOR` enum value. -- `PAL_RESULT_INVALID_MONITOR_MODE` enum value. -- `PAL_RESULT_VIDEO_FEATURE_NOT_SUPPORTED` enum value. -- `PAL_RESULT_INVALID_KEYCODE` enum value. -- `PAL_RESULT_INVALID_SCANCODE` enum value. -- `PAL_RESULT_INVALID_MOUSE_BUTTON` enum value. -- `PAL_RESULT_GL_NOT_INITIALIZED` enum value. -- `PAL_RESULT_INVALID_GL_WINDOW` enum value. -- `PAL_RESULT_GL_EXTENSION_NOT_SUPPORTED` enum value. -- `PAL_RESULT_INVALID_GL_FBCONFIG` enum value. -- `PAL_RESULT_INVALID_GL_VERSION` enum value. -- `PAL_RESULT_INVALID_GL_PROFILE` enum value. -- `PAL_RESULT_INVALID_GL_CONTEXT` enum value. -- `PAL_RESULT_INVALID_FBCONFIG_BACKEND` enum value. - -### Event -Added -- Added `PAL_EVENT_WINDOW_CLOSE` define. -- Added `PAL_EVENT_WINDOW_SIZE` define. -- Added `PAL_EVENT_WINDOW_MOVE` define. -- Added `PAL_EVENT_WINDOW_STATE` define. -- Added `PAL_EVENT_WINDOW_FOCUS` define. -- Added `PAL_EVENT_WINDOW_VISIBILITY` define. -- Added `PAL_EVENT_WINDOW_MODAL_BEGIN` define. -- Added `PAL_EVENT_WINDOW_MODAL_END` define. -- Added `PAL_EVENT_MONITOR_DPI_CHANGED` define. -- Added `PAL_EVENT_MONITOR_LIST_CHANGED` define. -- Added `PAL_EVENT_KEYDOWN` define. -- Added `PAL_EVENT_KEYREPEAT` define. -- Added `PAL_EVENT_KEYUP` define. -- Added `PAL_EVENT_MOUSE_BUTTONDOWN` define. -- Added `PAL_EVENT_MOUSE_BUTTONUP` define. -- Added `PAL_EVENT_MOUSE_MOVE` define. -- Added `PAL_EVENT_MOUSE_DELTA` define. -- Added `PAL_EVENT_MOUSE_WHEEL` define. -- Added `PAL_EVENT_USER` define. -- Added `PAL_EVENT_KEYCHAR` define. -- Added `PAL_EVENT_WINDOW_DECORATION_MODE` define. -- Added `PAL_EVENT_MAX` define. -- Added `PAL_DISPATCH_NONE` define. -- Added `PAL_DISPATCH_CALLBACK` define. -- Added `PAL_DISPATCH_POLL` define. -- Added `PAL_DISPATCH_MAX` define. -- Added `PAL_DECORATION_MODE_CLIENT_SIDE` define. -- Added `PAL_DECORATION_MODE_CLIENT_SIDE` define. - -Changed -- `PalEventType` is now a `uint64_t`. - -Removed -- `PalEventType` enum. -- `PAL_EVENT_WINDOW_CLOSE` enum value. -- `PAL_EVENT_WINDOW_SIZE` enum value. -- `PAL_EVENT_WINDOW_MOVE` enum value. -- `PAL_EVENT_WINDOW_STATE` enum value. -- `PAL_EVENT_WINDOW_FOCUS` enum value. -- `PAL_EVENT_WINDOW_VISIBILITY` enum value. -- `PAL_EVENT_WINDOW_MODAL_BEGIN` enum value. -- `PAL_EVENT_WINDOW_MODAL_END` enum value. -- `PAL_EVENT_MONITOR_DPI_CHANGED` enum value. -- `PAL_EVENT_MONITOR_LIST_CHANGED` enum value. -- `PAL_EVENT_KEYDOWN` enum value. -- `PAL_EVENT_KEYREPEAT` enum value. -- `PAL_EVENT_KEYUP` enum value. -- `PAL_EVENT_MOUSE_BUTTONDOWN` enum value. -- `PAL_EVENT_MOUSE_BUTTONUP` enum value. -- `PAL_EVENT_MOUSE_MOVE` enum value. -- `PAL_EVENT_MOUSE_DELTA` enum value. -- `PAL_EVENT_MOUSE_WHEEL` enum value. -- `PAL_EVENT_USER` enum value. -- `PAL_EVENT_KEYCHAR` enum value. -- `PAL_EVENT_WINDOW_DECORATION_MODE` enum value. -- `PAL_EVENT_MAX` enum value. -- `PAL_DISPATCH_NONE` enum value. -- `PAL_DISPATCH_CALLBACK` enum value. -- `PAL_DISPATCH_POLL` enum value. -- `PAL_DISPATCH_MAX` enum value. -- `PAL_DECORATION_MODE_CLIENT_SIDE` enum value. -- `PAL_DECORATION_MODE_CLIENT_SIDE` enum value. - -### Opengl -Added +## [1.2.0] - 2025-10-22 -Changed +### Features +- **Video:** Added **palGetInstance()** to retrieve the native display or instance handle. +- **Video:** Added **palAttachWindow()** for attaching **foreign windows** to PAL. +- **Video:** Added **palDetachWindow()** for detaching **foreign windows** from PAL. +- **Event:** Added **PAL_EVENT_KEYCHAR** to `PalEventType` enum. +- **Event:** Added documentation for event bits(payload) layout. -Removed +### Naming Update +- PAL now stands for **Prime Abstraction Layer**, +reflecting its role as the primary explicit foundation for OS and graphics abstraction. +- All API remains unchanged — this is an identity update only. -### Thread -Added +### Tests +- Added multi-threaded OpenGL example: demonstrating **Multi-Threaded OpenGL Rendering**. see **multi_thread_opengl_test.c**. +- Added attaching and detach foreign windows example. see **attach_window_test.c** +- Added key character example. see **char_event_test.c** -Changed +### Notes +- No API or ABI changes - existing code remains compatible. +- Safe upgrade from **v1.1.0** - just rebuild your project after updating. -Removed +## [1.1.0] - 2025-10-17 ### Features -- **Opengl:** Added **palGetSupportedGLAPIs()**. +- **Build:** Added Linux platform support across all modules. +- **Core:** Added Linux backend support. +- **Video:** Added X11-based backend support. +- **Thread:** Added Linux backend support. +- **Opengl:** Added Linux backend support. +- **System:** Added Linux backend support. +- **Video:** Added **palCreateCursorFrom()** to create system cursors. +- **Video:** Added **palSetFBConfig()** to select window FBConfig. +- **Video:** Added **PAL_VIDEO_FEATURE_WINDOW_SET_ICON** to `PalVideoFeatures` enum. +- **System:** Added **PAL_PLATFORM_API_COCOA** to `PalPlatformApiType` enum. +- **System:** Added **PAL_PLATFORM_API_ANDRIOD** to `PalPlatformApiType` enum. +- **System:** Added **PAL_PLATFORM_API_UIKIT** to `PalPlatformApiType` enum. +- **System:** Added **PAL_PLATFORM_API_HEADLESS** to `PalPlatformApiType` enum. +- **Core:** Added **PAL_RESULT_INVALID_FBCONFIG_BACKEND** to `PalResult` enum. ### Changed +- **System:** `PalCPUInfo.architecture` is now determined at runtime instead of build time. +- **Opengl:** **palEnumerateGLFBConfigs()** now does not use the `glWindow` paramter. Set to `nullptr` -- **Thread:** **palJoinThread()** now takes a void** for retval parameter. - -- **Opengl:** **palEnumerateGLFBConfigs()** now does not take glWindow parameter anymore. -- **Opengl:** **palInitGL()** now takes an api and instance parameter. -- **Opengl:** rename **PalGLRelease** to **PalGLReleaseBehavior**. -- **Opengl:** rename **palGLGetProcAddress()** to **palGetGLProcAddress()**. - -- **Video:** **palGetWindowHandleInfo()** now takes an info parameter. -- **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. -- **Video:** **palGetMouseWheelDelta()** now takes floats instead of uint32_t. -- **Video:** **palInitVideo()** now takes a preferredInstance parameter. -- **Video:** **PalWindowCreateInfo** now has `appName`, `instanceName`, `fbConfigBackend` and -`fbConfigIndex` fields. - -### Removed - +### Fixed +- Fixed a bug where **enter modal mode and exit modal mode** operations triggered only one event. +- Fixed repeated window state event (**minimized**, **maximized**, **restore**). -- **Opengl:** Removed **palGLSetInstance** function. -- **Opengl:** Removed **palGLGetBackend** function. +### Notes +- No API or ABI changes - existing Windows code remains compatible. +- Linux video support currently targets **X11** only: **Wayland** is planned for future releases. +- Safe upgrade from **v1.0.1** - just rebuild your project after updating. -- **Video:** Removed **palGetVideoFeaturesEx** function. -- **Video:** Removed **palGetWindowHandleInfoEx** function. -- **Video:** Removed **palGetRawMouseWheelDelta** function. -- **Video:** Removed **palSetPreferredInstance** function. -- **Video:** Removed **palSetFBConfig** function. +## [1.0.1] - 2025-10-01 -### Tests +**Bugfix release** - improve C/C++ interop and build integration -- Added grapics example: see **graphics_test.c** -- Added clear color example: see **clear_color_test.c** -- Added vertex shader/buffer triangle example: see **triangle_test.c** -- Added mesh example: see **mesh_test.c** -- Added compute example: see **compute_test.c** -- Added ray tracing example: see **ray_tracing_test.c** -- Added texture rendering example: see **texture_test.c** +### Fixed +- Added extern "C" guards to all exported functions so PAL can now be linked from both **C** and **C++** projects. +- Fixed a **condition variable** bug where the wrong thread could acquire the mutex first, causing intermittent locking issues. See **tests/condvar_test.c** +- Updated premake scripts to allow **PAL to be included as a submodule or directly in another workspace** if the build system is **premake**. ### Notes -- API or ABI changes +- No API or ABI changes +- Safe upgrade from **v1.0** - just rebuild your project after updating. + +## [1.0.0] - 2025-09-27 +- Initial stable release of PAL. \ No newline at end of file diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index fcbc59fa..99b99701 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -23,10 +23,6 @@ #define PAL_GL_APIENTRY #endif // _WIN32 -#define PAL_GL_VENDOR_NAME_SIZE 32 -#define PAL_GL_VERSION_NAME_SIZE 64 -#define PAL_GL_GRAPHICS_CARD_NAME_SIZE 64 - #define PAL_GL_EXTENSION_CREATE_CONTEXT (1ULL << 0) #define PAL_GL_EXTENSION_CONTEXT_PROFILE (1ULL << 1) #define PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2 (1ULL << 2) @@ -72,7 +68,7 @@ typedef struct PalGLContext PalGLContext; * All opengl extensions follow the format `PAL_GL_EXTENSION_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint64_t PalGLExtensions; @@ -83,7 +79,7 @@ typedef uint64_t PalGLExtensions; * All opengl profiles follow the format `PAL_GL_PROFILE_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalGLProfile; @@ -94,7 +90,7 @@ typedef uint32_t PalGLProfile; * All context reset behavior follow the format `PAL_GL_CONTEXT_RESET_**` * for consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalGLContextReset; @@ -105,7 +101,7 @@ typedef uint32_t PalGLContextReset; * All opengl context release behavior follow the format * `PAL_GL_RELEASE_BEHAVIOR_**` for consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalGLReleaseBehavior; @@ -133,7 +129,7 @@ typedef uint32_t PalGLAPI; * @struct PalGLInfo * @brief Information about the opengl driver. * - * @since 2.0 + * @since 1.0 */ typedef struct { PalGLExtensions extensions; @@ -141,16 +137,16 @@ typedef struct { uint32_t minor; PalGLBackend backend; PalGLAPI api; - char vendor[PAL_GL_VENDOR_NAME_SIZE]; - char graphicsCard[PAL_GL_GRAPHICS_CARD_NAME_SIZE]; - char version[PAL_GL_VERSION_NAME_SIZE]; + char vendor[32]; + char graphicsCard[64]; + char version[64]; } PalGLInfo; /** * @struct PalGLFBConfig * @brief Information about an opengl framebuffer. * - * @since 2.0 + * @since 1.0 */ typedef struct { PalBool doubleBuffer; @@ -186,7 +182,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 2.0 + * @since 1.0 */ typedef struct { const PalGLWindow* window; @@ -228,7 +224,7 @@ typedef struct { * * Thread safety: Must only be called from the main thread. * - * @since 2.0 + * @since 1.0 * @sa palShutdownGL */ PAL_API PalResult PAL_CALL palInitGL( @@ -282,7 +278,7 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); * * Thread safety: Must only be called from the main thread. * - * @since 2.0 + * @since 1.0 * @sa palInitGL */ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( From fbee94632c5c1b249ea47ca1b8f7572dc134f456 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 21 Jun 2026 13:49:42 +0000 Subject: [PATCH 289/372] update changelog with new format --- CHANGELOG.md | 133 ++++++++++++++----------------------- include/pal/pal_core.h | 4 +- include/pal/pal_event.h | 5 +- include/pal/pal_graphics.h | 62 +++++++++++------ include/pal/pal_opengl.h | 17 +++-- include/pal/pal_system.h | 15 +++-- include/pal/pal_thread.h | 7 +- include/pal/pal_video.h | 65 +++++++++--------- 8 files changed, 154 insertions(+), 154 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee536a17..b2112a2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,20 @@ + + + + ## 2.0.0 ### Features +- Added a graphics system API (`pal_graphics.h`). - Added `palGetResultCode()` to get the result code from a result value. +- Added `palGetSupportedGLAPIs()` to check supported opengl api types. - Added new `PalResult` values: - `PAL_RESULT_INVALID_HANDLE` - `PAL_RESULT_FEATURE_NOT_SUPPORTED` - `PAL_RESULT_NOT_INITIALIZED` - `PAL_RESULT_OUT_OF_DATE` - - `PAL_RESULT_MAX` - Added type `PalGLBackend` with values: - `PAL_GL_BACKEND_EGL` - `PAL_GL_BACKEND_GLX` @@ -17,10 +22,12 @@ - Added type `PalGLAPI` with values: - `PAL_GL_API_OPENGL` - `PAL_GL_API_OPENGL_ES` +- Added `_COUNT` constants to all type groups (eg. `PAL_EVENT_COUNT`). +- Added `PAL_GL_GRAPHICS_CARD_NAME_SIZE`,`PAL_GL_VENDOR_NAME_SIZE` and `PAL_GL_VERSION_NAME_SIZE` constants. ### Changes -- Converted `PalResult` from an enum type to `uint64_t` and the values to constants. +- Converted all enum types to fixed-width integer types and their values to standalone constants (eg. `PalResult` to `uint64_t`). - Removed all previous `PalResult` values except: - `PAL_RESULT_SUCCESS` - `PAL_RESULT_INVALID_ARGUMENT` @@ -30,89 +37,36 @@ - `PAL_RESULT_INVALID_OPERATION`. - `PAL_RESULT_DEVICE_LOST`. - Removed `UintXX` and `IntXX` types in favor of standard `uintXX_t` and `intXX_t`. +- Removed `_MAX` constants from all type groups (eg. `PAL_EVENT_MAX`). - Replaced standard `bool` type and `true`/`false` constants with `PalBool` type and `PAL_TRUE`/`PAL_FALSE`. - `palGetVersion()` now returns `void` and takes a pointer to the struct. - `palFormatResult()` now takes two additional parameters. -- Converted `PalEventType` from an enum type to `uint64_t` and the values to constants. -- Converted `PalGLExtensions` from an enum type to `uint64_t` and the values to constants. -- Converted `PalGLProfile` from an enum type to `uint32_t` and the values to constants. -- Converted `PalGLContextReset` from an enum type to `uint32_t` and the values to constants. -- Converted `PalGLReleaseBehavior` from an enum type to `uint32_t` and the values to constants. - -### Opengl -Added - -Changed - - -typedef struct { - PalGLExtensions extensions; - uint32_t major; - uint32_t minor; - PalGLBackend backend; - PalGLAPI api; - char vendor[PAL_GL_VENDOR_NAME_SIZE]; - char graphicsCard[PAL_GL_GRAPHICS_CARD_NAME_SIZE]; - char version[PAL_GL_VERSION_NAME_SIZE]; -} PalGLInfo; - -PAL_API PalResult PAL_CALL palInitGL( - PalGLAPI api, - void* instance, - const PalAllocator* allocator); - - PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( - int32_t* count, - PalGLFBConfig* configs); - -PAL_API const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance); - -Removed - -### Features -- **Opengl:** Added **palGetSupportedGLAPIs()**. - -### Changed - -- **Thread:** **palJoinThread()** now takes a void** for retval parameter. - -- **Opengl:** **palEnumerateGLFBConfigs()** now does not take glWindow parameter anymore. -- **Opengl:** **palInitGL()** now takes an api and instance parameter. -- **Opengl:** rename **PalGLRelease** to **PalGLReleaseBehavior**. -- **Opengl:** rename **palGLGetProcAddress()** to **palGetGLProcAddress()**. - -- **Video:** **palGetWindowHandleInfo()** now takes an info parameter. -- **Video:** **palGetMouseDelta()** now takes floats instead of uint32_t. -- **Video:** **palGetMouseWheelDelta()** now takes floats instead of uint32_t. -- **Video:** **palInitVideo()** now takes a preferredInstance parameter. -- **Video:** **PalWindowCreateInfo** now has `appName`, `instanceName`, `fbConfigBackend` and -`fbConfigIndex` fields. - -### Removed - - -- **Opengl:** Removed **palGLSetInstance** function. -- **Opengl:** Removed **palGLGetBackend** function. - -- **Video:** Removed **palGetVideoFeaturesEx** function. -- **Video:** Removed **palGetWindowHandleInfoEx** function. -- **Video:** Removed **palGetRawMouseWheelDelta** function. -- **Video:** Removed **palSetPreferredInstance** function. -- **Video:** Removed **palSetFBConfig** function. - -### Tests - -- Added grapics example: see **graphics_test.c** -- Added clear color example: see **clear_color_test.c** -- Added vertex shader/buffer triangle example: see **triangle_test.c** -- Added mesh example: see **mesh_test.c** -- Added compute example: see **compute_test.c** -- Added ray tracing example: see **ray_tracing_test.c** -- Added texture rendering example: see **texture_test.c** - -### Notes -- API or ABI changes - +- Renamed `PalGLRelease` to `PalGLReleaseBehavior`. +- Renamed `palGLGetProcAddress()` to `palGetGLProcAddress()`. +- `palInitGL()` now takes two additional parameters. +- `palEnumerateGLFBConfigs()` no longer takes the `glWindow` parameter. +- `palInitVideo()` now takes an additional parameter. +- `palGetMouseDelta()` now takes `dx` and `dy` paramters as `float`. +- `palGetMouseWheelDelta()` now takes `dx` and `dy` paramters as `float`. +- `palJoinThread()` now takes `retval` paramters as `void**`. +- Removed `palGLSetInstance()` function. +- Removed `palGLGetBackend()` function. +- Removed `palGetVideoFeaturesEx()` function and `PalVideoFeatures64` enum. +- Removed `palGetWindowHandleInfoEx()` function and `PalWindowHandleInfoEX` struct. +- Removed `palGetRawMouseWheelDelta()` function. +- Removed `palSetPreferredInstance()` function. +- Removed `palSetFBConfig()` function. +- Removed `PAL_CONFIG_BACKEND_GLES`. +- `palGetWindowHandleInfo()` now returns `PalResult` and takes a pointer to the struct. +- `PalGLInfo` now has `backend` and `api` fields. +- Renamed `nativeDisplay` to `nativeInstance` in `PalWindowHandleInfo`. +- Renamed `display` to `instance` in `PalGLWindow`. +- `PalWindowHandleInfo` now has `nativeHandle1`, `nativeHandle2` and `nativeHandle3` fields. +- `PalWindowCreateInfo` now has `appName`, `instanceName`, `fbConfigBackend` and `fbConfigIndex` fields. + + + + ## [1.3.0] - 2025-11-21 @@ -165,6 +119,9 @@ void* retval; palJoinThread(thread, &retval); ``` + + + ## [1.2.0] - 2025-10-22 @@ -189,6 +146,10 @@ reflecting its role as the primary explicit foundation for OS and graphics abstr - No API or ABI changes - existing code remains compatible. - Safe upgrade from **v1.1.0** - just rebuild your project after updating. + + + + ## [1.1.0] - 2025-10-17 ### Features @@ -220,6 +181,10 @@ reflecting its role as the primary explicit foundation for OS and graphics abstr - Linux video support currently targets **X11** only: **Wayland** is planned for future releases. - Safe upgrade from **v1.0.1** - just rebuild your project after updating. + + + + ## [1.0.1] - 2025-10-01 **Bugfix release** - improve C/C++ interop and build integration @@ -233,5 +198,9 @@ reflecting its role as the primary explicit foundation for OS and graphics abstr - No API or ABI changes - Safe upgrade from **v1.0** - just rebuild your project after updating. + + + + ## [1.0.0] - 2025-09-27 - Initial stable release of PAL. \ No newline at end of file diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index c94ccdd6..f11d1f2d 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -70,13 +70,11 @@ #define PAL_RESULT_INVALID_OPERATION 8 #define PAL_RESULT_DEVICE_LOST 9 #define PAL_RESULT_OUT_OF_DATE 10 -#define PAL_RESULT_MAX 11 +#define PAL_RESULT_COUNT 11 /** * @typedef PalBool * @brief Must be `PAL_TRUE` or `PAL_FALSE`. - * - * @since 2.0 */ typedef uint32_t PalBool; diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 04a1c744..6cc52895 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -18,6 +18,7 @@ #define PAL_DECORATION_MODE_CLIENT_SIDE 0 #define PAL_DECORATION_MODE_SERVER_SIDE 1 +#define PAL_DECORATION_MODE_COUNT 2 /** * event.data2 : window @@ -218,12 +219,12 @@ */ #define PAL_EVENT_WINDOW_DECORATION_MODE 20 -#define PAL_EVENT_MAX 21 +#define PAL_EVENT_COUNT 21 #define PAL_DISPATCH_NONE 0 #define PAL_DISPATCH_CALLBACK 1 #define PAL_DISPATCH_POLL 2 -#define PAL_DISPATCH_MAX 3 +#define PAL_DISPATCH_COUNT 3 /** * @struct PalEventDriver diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index e01e67a5..b8a1059e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -18,15 +18,13 @@ #define PAL_ADAPTER_NAME_SIZE 128 #define PAL_SHADER_ENTRY_NAME_SIZE 32 -#define PAL_MAX_RESOLVE_MODES 8 -#define PAL_MAX_COMBINER_OPS 8 - #define PAL_UNUSED_SHADER_INDEX UINT32_MAX + #define PAL_MAKE_SHADER_TARGET(major, minor) ((uint32_t)((major) << 8) | (minor)) #define PAL_SHADER_TARGET_MAJOR(target) ((uint32_t)(target) >> 8); #define PAL_SHADER_TARGET_MINOR(target) ((uint32_t)(target) & 0xFF); -#define PAL_ADAPTER_FEATURE_NONE 0; +#define PAL_ADAPTER_FEATURE_NONE 0 #define PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY (1ULL << 1) #define PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING (1ULL << 2) #define PAL_ADAPTER_FEATURE_MULTI_VIEWPORT (1ULL << 3) @@ -71,26 +69,29 @@ #define PAL_ADAPTER_TYPE_INTEGRATED 2 #define PAL_ADAPTER_TYPE_VIRTUAL 3 #define PAL_ADAPTER_TYPE_CPU 4 +#define PAL_ADAPTER_TYPE_COUNT 5 #define PAL_ADAPTER_API_TYPE_VULKAN 0 #define PAL_ADAPTER_API_TYPE_D3D12 1 #define PAL_ADAPTER_API_TYPE_METAL 2 #define PAL_ADAPTER_API_TYPE_CUSTOM 3 +#define PAL_ADAPTER_API_TYPE_COUNT 4 #define PAL_QUEUE_TYPE_GRAPHICS 0 #define PAL_QUEUE_TYPE_COMPUTE 1 #define PAL_QUEUE_TYPE_COPY 2 +#define PAL_QUEUE_TYPE_COUNT 3 /** V-Sync.*/ #define PAL_PRESENT_MODE_FIFO 0 #define PAL_PRESENT_MODE_IMMEDIATE 1 #define PAL_PRESENT_MODE_MAILBOX 2 -#define PAL_PRESENT_MODE_MAX 3 +#define PAL_PRESENT_MODE_COUNT 3 #define PAL_COMPOSITE_ALPHA_OPAQUE 0 #define PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED 1 #define PAL_COMPOSITE_ALPHA_POST_MULTIPLIED 2 -#define PAL_COMPOSITE_ALPHA_MAX 3 +#define PAL_COMPOSITE_ALPHA_COUNT 3 #define PAL_FORMAT_UNDEFINED 0 #define PAL_FORMAT_R8_UNORM 1 @@ -173,7 +174,7 @@ #define PAL_FORMAT_D16_UNORM_S8_UINT 78 #define PAL_FORMAT_D32_SFLOAT_S8_UINT 79 #define PAL_FORMAT_D24_UNORM_S8_UINT 80 -#define PAL_FORMAT_MAX 81 +#define PAL_FORMAT_COUNT 81 #define PAL_IMAGE_USAGE_UNDEFINED 0 #define PAL_IMAGE_USAGE_COLOR_ATTACHEMENT (1ULL << 0) @@ -191,23 +192,27 @@ #define PAL_LOAD_OP_LOAD 0 #define PAL_LOAD_OP_CLEAR 1 #define PAL_LOAD_OP_DONT_CARE 2 +#define PAL_LOAD_OP_COUNT 3 #define PAL_STORE_OP_STORE 0 #define PAL_STORE_OP_DONT_CARE 1 +#define PAL_STORE_OP_COUNT 2 #define PAL_MEMORY_TYPE_GPU_ONLY 0 #define PAL_MEMORY_TYPE_CPU_UPLOAD 1 #define PAL_MEMORY_TYPE_CPU_READBACK 2 -#define PAL_MEMORY_TYPE_MAX 3 +#define PAL_MEMORY_TYPE_COUNT 3 #define PAL_IMAGE_TYPE_1D 0 #define PAL_IMAGE_TYPE_2D 1 #define PAL_IMAGE_TYPE_3D 2 +#define PAL_IMAGE_TYPE_COUNT 3 #define PAL_IMAGE_ASPECT_COLOR 0 #define PAL_IMAGE_ASPECT_DEPTH 1 #define PAL_IMAGE_ASPECT_STENCIL 2 #define PAL_IMAGE_ASPECT_DEPTH_STENCIL 3 +#define PAL_IMAGE_ASPECT_COUNT 4 #define PAL_IMAGE_VIEW_TYPE_1D 0 #define PAL_IMAGE_VIEW_TYPE_1D_ARRAY 1 @@ -216,17 +221,21 @@ #define PAL_IMAGE_VIEW_TYPE_3D 4 #define PAL_IMAGE_VIEW_TYPE_CUBE 5 #define PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY 6 +#define PAL_IMAGE_VIEW_TYPE_COUNT 7 #define PAL_FILTER_MODE_NEAREST 0 #define PAL_FILTER_MODE_LINEAR 1 +#define PAL_FILTER_MODE_COUNT 2 #define PAL_SAMPLER_MIPMAP_MODE_NEAREST 0 #define PAL_SAMPLER_MIPMAP_MODE_LINEAR 1 +#define PAL_SAMPLER_MIPMAP_MODE_COUNT 2 #define PAL_SAMPLER_ADDRESS_MODE_REPEAT 0 #define PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT 1 #define PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE 2 #define PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER 3 +#define PAL_SAMPLER_ADDRESS_MODE_COUNT 4 #define PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK 0 #define PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK 1 @@ -234,16 +243,19 @@ #define PAL_BORDER_COLOR_INT_OPAQUE_BLACK 3 #define PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE 4 #define PAL_BORDER_COLOR_INT_OPAQUE_WHITE 5 +#define PAL_BORDER_COLOR_COUNT 6 #define PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR 0 #define PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR 1 #define PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR 2 #define PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10 3 /**< HDR.*/ -#define PAL_SURFACE_FORMAT_MAX 4 +#define PAL_SURFACE_FORMAT_COUNT 4 -#define PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND 0 -#define PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11 1 -#define PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB 2 +#define PAL_WINDOW_INSTANCE_TYPE_WAYLAND 0 +#define PAL_WINDOW_INSTANCE_TYPE_X11 1 +#define PAL_WINDOW_INSTANCE_TYPE_XCB 2 +#define PAL_WINDOW_INSTANCE_TYPE_WIN32 3 +#define PAL_WINDOW_INSTANCE_TYPE_COUNT 4 #define PAL_SHADER_STAGE_UNDEFINED 0 #define PAL_SHADER_STAGE_VERTEX 1 @@ -260,6 +272,7 @@ #define PAL_SHADER_STAGE_MISS 12 #define PAL_SHADER_STAGE_INTERSECTION 13 #define PAL_SHADER_STAGE_CALLABLE 14 +#define PAL_SHADER_STAGE_COUNT 15 #define PAL_SAMPLE_COUNT_1 0 #define PAL_SAMPLE_COUNT_2 1 @@ -268,6 +281,7 @@ #define PAL_SAMPLE_COUNT_16 4 #define PAL_SAMPLE_COUNT_32 5 #define PAL_SAMPLE_COUNT_64 6 +#define PAL_SAMPLE_COUNT 7 #define PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST 0 #define PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP 1 @@ -275,16 +289,20 @@ #define PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP 3 #define PAL_PRIMITIVE_TOPOLOGY_POINT_LIST 4 #define PAL_PRIMITIVE_TOPOLOGY_PATCH 5 +#define PAL_PRIMITIVE_TOPOLOGY_COUNT 6 #define PAL_CULL_MODE_NONE 0 #define PAL_CULL_MODE_FRONT 1 #define PAL_CULL_MODE_BACK 2 +#define PAL_CULL_MODE_COUNT 3 #define PAL_FRONT_FACE_CLOCKWISE 0 #define PAL_FRONT_FACE_COUNTER_CLOCKWISE 1 +#define PAL_FRONT_FACE_COUNT 2 #define PAL_POLYGON_MODE_FILL 0 #define PAL_POLYGON_MODE_LINE 1 +#define PAL_POLYGON_MODE_COUNT 2 #define PAL_STENCIL_FACE_FRONT (1ULL << 0) #define PAL_STENCIL_FACE_BACK (1ULL << 1) @@ -295,51 +313,48 @@ #define PAL_VERTEX_TYPE_INT32_2 2 /**< int32_t vec2 or array[2].*/ #define PAL_VERTEX_TYPE_INT32_3 3 /**< int32_t vec3 or array[3].*/ #define PAL_VERTEX_TYPE_INT32_4 4 /**< int32_t vec4 or array[4].*/ - #define PAL_VERTEX_TYPE_UINT32 5 /**< uint32_t.*/ #define PAL_VERTEX_TYPE_UINT32_2 6 /**< uint32_t vec2 or array[2].*/ #define PAL_VERTEX_TYPE_UINT32_3 7 /**< uint32_t vec3 or array[3].*/ #define PAL_VERTEX_TYPE_UINT32_4 8 /**< uint32_t vec4 or array[4].*/ - #define PAL_VERTEX_TYPE_INT8_2 9 /**< int8_t vec2 or array[2].*/ #define PAL_VERTEX_TYPE_INT8_4 10 /**< int8_t vec4 or array[4].*/ #define PAL_VERTEX_TYPE_UINT8_2 11 /**< uint8_t vec2 or array[2].*/ #define PAL_VERTEX_TYPE_UINT8_4 12 /**< uint8_t vec4 or array[4].*/ - #define PAL_VERTEX_TYPE_INT8_2NORM 13 /**< int8_t vec2 or array[2] normalized.*/ #define PAL_VERTEX_TYPE_INT8_4NORM 14 /**< int8_t vec4 or array[4] normalized.*/ #define PAL_VERTEX_TYPE_UINT8_2NORM 15 /**< uint8_t vec2 or array[2] normalized.*/ #define PAL_VERTEX_TYPE_UINT8_4NORM 16 /**< uint8_t vec4 or array[4] normalized.*/ - #define PAL_VERTEX_TYPE_INT16_2 17 /**< int16_t vec2 or array[2].*/ #define PAL_VERTEX_TYPE_INT16_4 18 /**< int16_t vec4 or array[4].*/ #define PAL_VERTEX_TYPE_UINT16_2 19 /**< uint16_t vec2 or array[2].*/ #define PAL_VERTEX_TYPE_UINT16_4 20 /**< uint16_t vec4 or array[4].*/ - #define PAL_VERTEX_TYPE_INT16_2NORM 21 /**< int16_t vec2 or array[2] normalized.*/ #define PAL_VERTEX_TYPE_INT16_4NORM 22 /**< int16_t vec4 or array[4] normalized.*/ #define PAL_VERTEX_TYPE_UINT16_2NORM 23 /**< uint16_t vec2 or array[2] normalized.*/ #define PAL_VERTEX_TYPE_UINT16_4NORM 24 /**< uint16_t vec4 or array[4] normalized.*/ - #define PAL_VERTEX_TYPE_FLOAT 25 /**< float*/ #define PAL_VERTEX_TYPE_FLOAT2 26 /**< float vec2 or array[2].*/ #define PAL_VERTEX_TYPE_FLOAT3 27 /**< float vec3 or array[3].*/ #define PAL_VERTEX_TYPE_FLOAT4 28 /**< float vec4 or array[4].*/ - #define PAL_VERTEX_TYPE_HALF_FLOAT16_2 29 /**< float16 vec2 or array[2].*/ #define PAL_VERTEX_TYPE_HALF_FLOAT16_4 30 /**< float16 vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_COUNT 31 #define PAL_VERTEX_SEMANTIC_ID_POSITION 0 #define PAL_VERTEX_SEMANTIC_ID_COLOR 1 #define PAL_VERTEX_SEMANTIC_ID_TEXCOORD 2 #define PAL_VERTEX_SEMANTIC_ID_NORMAL 3 #define PAL_VERTEX_SEMANTIC_ID_TANGENT 4 +#define PAL_VERTEX_SEMANTIC_ID_COUNT 5 #define PAL_COMMAND_BUFFER_TYPE_PRIMARY 0 #define PAL_COMMAND_BUFFER_TYPE_SECONDARY 1 +#define PAL_COMMAND_BUFFER_TYPE_COUNT 2 #define PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX 0 #define PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE 1 +#define PAL_VERTEX_LAYOUT_TYPE_COUNT 2 #define PAL_COMPARE_OP_NEVER 0 #define PAL_COMPARE_OP_LESS 1 @@ -349,6 +364,7 @@ #define PAL_COMPARE_OP_NOT_EQUAL 5 #define PAL_COMPARE_OP_GREATER_OR_EQUAL 6 #define PAL_COMPARE_OP_ALWAYS 7 +#define PAL_COMPARE_OP_COUNT 8 #define PAL_STENCIL_OP_KEEP 0 #define PAL_STENCIL_OP_ZERO 1 @@ -358,12 +374,13 @@ #define PAL_STENCIL_OP_INVERT 5 #define PAL_STENCIL_OP_INCREMENT_AND_WRAP 6 #define PAL_STENCIL_OP_DECREMENT_AND_WRAP 7 +#define PAL_STENCIL_OP_COUNT 8 #define PAL_BLEND_OP_ADD 0 #define PAL_BLEND_OP_SUBTRACT 1 #define PAL_BLEND_OP_REVERSE_SUBTRACT 2 #define PAL_BLEND_OP_MIN 3 -#define PAL_BLEND_OP_MAX 4 +#define PAL_BLEND_OP_COUNT 4 #define PAL_BLEND_FACTOR_ZERO 0 #define PAL_BLEND_FACTOR_ONE 1 @@ -379,6 +396,7 @@ #define PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR 10 #define PAL_BLEND_FACTOR_CONSTANT_ALPHA 11 #define PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA 12 +#define PAL_BLEND_FACTOR_COUNT 13 #define PAL_COLOR_MASK_NONE 0 #define PAL_COLOR_MASK_RED (1ULL << 0) @@ -391,6 +409,7 @@ #define PAL_RESOLVE_MODE_AVERAGE 2 #define PAL_RESOLVE_MODE_MIN 3 #define PAL_RESOLVE_MODE_MAX 4 +#define PAL_RESOLVE_MODE_COUNT 5 #define PAL_FRAGMENT_SHADING_RATE_1X1 0 #define PAL_FRAGMENT_SHADING_RATE_1X2 1 @@ -399,13 +418,14 @@ #define PAL_FRAGMENT_SHADING_RATE_2X4 4 #define PAL_FRAGMENT_SHADING_RATE_4X2 5 #define PAL_FRAGMENT_SHADING_RATE_4X4 6 -#define PAL_FRAGMENT_SHADING_RATE_MAX 7 +#define PAL_FRAGMENT_SHADING_RATE_COUNT 7 #define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP 0 #define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE 1 #define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN 2 #define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX 3 #define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL 4 +#define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_COUNT 5 /** * @struct PalAdapter diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 99b99701..67c42a29 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -23,6 +23,10 @@ #define PAL_GL_APIENTRY #endif // _WIN32 +#define PAL_GL_VENDOR_NAME_SIZE 32 +#define PAL_GL_GRAPHICS_CARD_NAME_SIZE 64 +#define PAL_GL_VERSION_NAME_SIZE 64 + #define PAL_GL_EXTENSION_CREATE_CONTEXT (1ULL << 0) #define PAL_GL_EXTENSION_CONTEXT_PROFILE (1ULL << 1) #define PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2 (1ULL << 2) @@ -38,20 +42,25 @@ #define PAL_GL_PROFILE_CORE 1 #define PAL_GL_PROFILE_COMPATIBILITY 2 #define PAL_GL_PROFILE_ES 3 +#define PAL_GL_PROFILE_COUNT 4 #define PAL_GL_CONTEXT_RESET_NONE 0 #define PAL_GL_CONTEXT_RESET_NO_NOTIFICATION 1 #define PAL_GL_CONTEXT_RESET_LOSE_CONTEXT 2 +#define PAL_GL_CONTEXT_RESET_COUNT 3 #define PAL_GL_RELEASE_BEHAVIOR_NONE 0 #define PAL_GL_RELEASE_BEHAVIOR_FLUSH 1 +#define PAL_GL_RELEASE_BEHAVIOR_COUNT 2 #define PAL_GL_BACKEND_EGL 0 #define PAL_GL_BACKEND_GLX 1 #define PAL_GL_BACKEND_WGL 2 +#define PAL_GL_BACKEND_COUNT 3 #define PAL_GL_API_OPENGL 0 #define PAL_GL_API_OPENGL_ES 1 +#define PAL_GL_API_COUNT 2 /** * @struct PalGLContext @@ -137,9 +146,9 @@ typedef struct { uint32_t minor; PalGLBackend backend; PalGLAPI api; - char vendor[32]; - char graphicsCard[64]; - char version[64]; + char vendor[PAL_GL_VENDOR_NAME_SIZE]; + char graphicsCard[PAL_GL_GRAPHICS_CARD_NAME_SIZE]; + char version[PAL_GL_VERSION_NAME_SIZE]; } PalGLInfo; /** @@ -172,7 +181,7 @@ typedef struct { * @since 1.0 */ typedef struct { - void* display; /**< Can be nullptr depending on platform (eg. Windows).*/ + void* instance; /**< Must not be nullptr. (HINSTANCE on Win32 or wl_display on Wayland)*/ void* window; /**< Must not be nullptr. (egl_wl_window on Wayland)*/ } PalGLWindow; diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index 2deefa41..753ad65f 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -24,6 +24,7 @@ #define PAL_CPU_ARCH_X86_64 2 #define PAL_CPU_ARCH_ARM 3 #define PAL_CPU_ARCH_ARM64 4 +#define PAL_CPU_ARCH_COUNT 5 #define PAL_CPU_FEATURE_SSE (1ULL << 0) #define PAL_CPU_FEATURE_SSE2 (1ULL << 1) @@ -43,6 +44,7 @@ #define PAL_PLATFORM_MACOS 2 #define PAL_PLATFORM_ANDROID 3 #define PAL_PLATFORM_IOS 4 +#define PAL_PLATFORM_COUNT 5 #define PAL_PLATFORM_API_WIN32 0 #define PAL_PLATFORM_API_WAYLAND 1 @@ -51,6 +53,7 @@ #define PAL_PLATFORM_API_ANDRIOD 4 #define PAL_PLATFORM_API_UIKIT 5 #define PAL_PLATFORM_API_HEADLESS 6 +#define PAL_PLATFORM_API_COUNT 7 /** * @typedef PalCpuArch @@ -59,7 +62,7 @@ * All CPU achitectures follow the format `PAL_CPU_ARCH_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalCpuArch; @@ -70,7 +73,7 @@ typedef uint32_t PalCpuArch; * All CPU features sets follow the format `PAL_CPU_FEATURE_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint64_t PalCpuFeatures; @@ -84,7 +87,7 @@ typedef uint64_t PalCpuFeatures; * All platform types follow the format `PAL_PLATFORM_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalPlatformType; @@ -98,7 +101,7 @@ typedef uint32_t PalPlatformType; * All platform API types follow the format `PAL_PLATFORM_API_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalPlatformApiType; @@ -106,7 +109,7 @@ typedef uint32_t PalPlatformApiType; * @struct PalPlatformInfo * @brief Information about a platform (OS). * - * @since 2.0 + * @since 1.0 */ typedef struct { PalPlatformType type; @@ -121,7 +124,7 @@ typedef struct { * @struct PalCPUInfo * @brief Information about a CPU. * - * @since 2.0 + * @since 1.0 */ typedef struct { PalCpuFeatures features; diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index 581cb50c..f95d2ca0 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -24,6 +24,7 @@ #define PAL_THREAD_PRIORITY_LOW 0 #define PAL_THREAD_PRIORITY_NORMAL 1 #define PAL_THREAD_PRIORITY_HIGH 2 +#define PAL_THREAD_PRIORITY_COUNT 3 /** * @struct PalThread @@ -64,7 +65,7 @@ typedef struct PalCondVar PalCondVar; * All thread features follow the format `PAL_THREAD_FEATURE_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint64_t PalThreadFeatures; @@ -75,7 +76,7 @@ typedef uint64_t PalThreadFeatures; * All thread priority types follow the format `PAL_THREAD_PRIORITY_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalThreadPriority; @@ -162,7 +163,7 @@ PAL_API PalResult PAL_CALL palCreateThread( * * Thread safety: Thread safe if `retval` is per thread. * - * @since 2.0 + * @since 1.0 */ PAL_API PalResult PAL_CALL palJoinThread( PalThread* thread, diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 883257bc..23700f05 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -63,6 +63,7 @@ #define PAL_ORIENTATION_PORTRAIT 1 #define PAL_ORIENTATION_LANDSCAPE_FLIPPED 2 #define PAL_ORIENTATION_PORTRAIT_FLIPPED 3 +#define PAL_ORIENTATION_COUNT 4 #define PAL_WINDOW_STYLE_RESIZABLE (1ULL << 0) #define PAL_WINDOW_STYLE_TRANSPARENT (1ULL << 1) @@ -75,6 +76,7 @@ #define PAL_WINDOW_STATE_MAXIMIZED 0 #define PAL_WINDOW_STATE_MINIMIZED 1 #define PAL_WINDOW_STATE_RESTORED 2 +#define PAL_WINDOW_STATE_COUNT 3 #define PAL_FLASH_STOP 0 /**< Stop flashing.*/ #define PAL_FLASH_CAPTION (1ULL << 0) /**< Flash the titlebar of the window.*/ @@ -84,6 +86,7 @@ #define PAL_CONFIG_BACKEND_EGL 1 #define PAL_CONFIG_BACKEND_GLX 2 #define PAL_CONFIG_BACKEND_WGL 3 +#define PAL_CONFIG_BACKEND_COUNT 4 #define PAL_SCANCODE_UNKNOWN 0 #define PAL_SCANCODE_A 1 @@ -198,8 +201,7 @@ #define PAL_SCANCODE_RBRACKET 103 #define PAL_SCANCODE_LSUPER 104 #define PAL_SCANCODE_RSUPER 105 - -#define PAL_SCANCODE_MAX 106 +#define PAL_SCANCODE_COUNT 106 #define PAL_KEYCODE_UNKNOWN 0 #define PAL_KEYCODE_A 1 @@ -314,8 +316,7 @@ #define PAL_KEYCODE_RBRACKET 103 #define PAL_KEYCODE_LSUPER 104 #define PAL_KEYCODE_RSUPER 105 - -#define PAL_KEYCODE_MAX 106 +#define PAL_KEYCODE_COUNT 106 #define PAL_MOUSE_BUTTON_UNKNOWN 0 #define PAL_MOUSE_BUTTON_LEFT 1 @@ -323,16 +324,14 @@ #define PAL_MOUSE_BUTTON_MIDDLE 3 #define PAL_MOUSE_BUTTON_X1 4 #define PAL_MOUSE_BUTTON_X2 5 - -#define PAL_MOUSE_BUTTON_MAX 6 +#define PAL_MOUSE_BUTTON_COUNT 6 #define PAL_CURSOR_ARROW 0 #define PAL_CURSOR_HAND 1 #define PAL_CURSOR_CROSS 2 #define PAL_CURSOR_IBEAM 3 #define PAL_CURSOR_WAIT 4 - -#define PAL_CURSOR_MAX 5 +#define PAL_CURSOR_COUNT 5 /** * @struct PalMonitor @@ -373,7 +372,7 @@ typedef struct PalCursor PalCursor; * All video features follow the format `PAL_VIDEO_FEATURE_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint64_t PalVideoFeatures; @@ -384,7 +383,7 @@ typedef uint64_t PalVideoFeatures; * All orientation types follow the format `PAL_ORIENTATION_**` for consistency * and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalOrientation; @@ -396,7 +395,7 @@ typedef uint32_t PalOrientation; * All window flags follow the format `PAL_WINDOW_STYLE_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint64_t PalWindowStyle; @@ -407,7 +406,7 @@ typedef uint64_t PalWindowStyle; * All window states follow the format `PAL_WINDOW_STATE_**` for consistency and * API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalWindowState; @@ -421,7 +420,7 @@ typedef uint32_t PalWindowState; * All flash flags follow the format `PAL_FLASH_**` for consistency and * API use. * - * @since 2.0 + * @since 1.0 */ typedef uint64_t PalFlashFlag; @@ -432,7 +431,7 @@ typedef uint64_t PalFlashFlag; * All FBConfig backends follow the format `PAL_CONFIG_BACKEND**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalFBConfigBackend; @@ -443,7 +442,7 @@ typedef uint32_t PalFBConfigBackend; * All scancodes follow the format `PAL_SCANCODE_**` for consistency and * API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalScancode; @@ -454,7 +453,7 @@ typedef uint32_t PalScancode; * All keycodes follow the format `PAL_KEYCODE_**` for consistency and API * use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalKeycode; @@ -465,7 +464,7 @@ typedef uint32_t PalKeycode; * All mouse buttons follow the format `PAL_MOUSE_BUTTON_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalMouseButton; @@ -476,7 +475,7 @@ typedef uint32_t PalMouseButton; * All cursor types follow the format `PAL_CURSOR_**` for * consistency and API use. * - * @since 2.0 + * @since 1.0 */ typedef uint32_t PalCursorType; @@ -484,7 +483,7 @@ typedef uint32_t PalCursorType; * @struct PalMonitorInfo * @brief Information about a monitor. * - * @since 2.0 + * @since 1.0 */ typedef struct { int32_t x; /**< X position in pixels.*/ @@ -517,7 +516,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 2.0 + * @since 1.0 */ typedef struct { PalFlashFlag flags; /**< See PalFlashFlag.*/ @@ -531,7 +530,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 2.0 + * @since 1.0 */ typedef struct { const uint8_t* pixels; /**< Pixels in `RGBA` format.*/ @@ -545,7 +544,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 2.0 + * @since 1.0 */ typedef struct { const uint8_t* pixels; /**< Pixels in `RGBA` format.*/ @@ -559,10 +558,10 @@ typedef struct { * @struct PalWindowHandleInfo * @brief Information about a window handle. * - * @since 2.0 + * @since 1.0 */ typedef struct { - void* nativeDisplay; /**< The platform (OS) display or instance.*/ + void* nativeInstance; /**< The platform (OS) display or instance.*/ void* nativeWindow; /**< The window platform (OS) handle.*/ void* nativeHandle1; /**< Extra window handle (xdgSurface)*/ void* nativeHandle2; /**< Extra window handle (xdgToplevel)*/ @@ -575,7 +574,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 2.0 + * @since 1.0 */ typedef struct { PalWindowStyle style; /**< Window style.*/ @@ -619,7 +618,7 @@ typedef struct { * * Thread safety: Must only be called from the main thread. * - * @since 2.0 + * @since 1.0 * @sa palShutdownVideo */ PAL_API PalResult PAL_CALL palInitVideo( @@ -900,7 +899,7 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * * - Creating hidden window is not supported. It will be ignored. * - * @since 2.0 + * @since 1.0 */ PAL_API PalResult PAL_CALL palCreateWindow( const PalWindowCreateInfo* info, @@ -1190,7 +1189,7 @@ PAL_API PalResult PAL_CALL palGetWindowState( * * The returned pointer must not be freed. The state is updated when * palUpdateVideo() is called. The array must be index with PalKeycodes and - * not exceed `PAL_KEYCODE_MAX`. + * not exceed `PAL_KEYCODE_COUNT`. * * @return A pointer to the keycodes array on success or nullptr on failure. * @@ -1208,7 +1207,7 @@ PAL_API const PalBool* PAL_CALL palGetKeycodeState(); * * The returned pointer must not be freed. The state is updated when * palUpdateVideo() is called. The array must be index with PalScancodes and - * not exceed PAL_SCANCODE_MAX. + * not exceed PAL_SCANCODE_COUNT. * * @return A pointer to the scancodes array on success or nullptr on failure. * @@ -1225,7 +1224,7 @@ PAL_API const PalBool* PAL_CALL palGetScancodeState(); * * The returned pointer must not be freed. The state is updated when * palUpdateVideo() is called. The array must be index with PalMouseButton and - * not exceed `PAL_MOUSE_BUTTON_MAX`. + * not exceed `PAL_MOUSE_BUTTON_COUNT`. * * @return A pointer to the mouse button array on success or nullptr on failure. * @@ -1249,7 +1248,7 @@ PAL_API const PalBool* PAL_CALL palGetMouseState(); * Thread safety: Thread-safe if `dx` and `dy` are thread * local. * - * @since 2.0 + * @since 1.0 */ PAL_API void PAL_CALL palGetMouseDelta( float* dx, @@ -1267,7 +1266,7 @@ PAL_API void PAL_CALL palGetMouseDelta( * Thread safety: Thread-safe if `dx` and `dy` are thread * local. * - * @since 2.0 + * @since 1.0 */ PAL_API void PAL_CALL palGetMouseWheelDelta( float* dx, @@ -1320,7 +1319,7 @@ PAL_API PalWindow* PAL_CALL palGetFocusWindow(); * * Thread safety: Thread-safe. * - * @since 2.0 + * @since 1.0 */ PAL_API PalResult PAL_CALL palGetWindowHandleInfo( PalWindow* window, From f0b530d879ee9901f0289de64fe4fbee05eb3f7a Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 21 Jun 2026 21:47:19 +0000 Subject: [PATCH 290/372] start graphics system rework --- include/pal/pal_graphics.h | 426 +++++++++++++++++++------------------ 1 file changed, 216 insertions(+), 210 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index b8a1059e..bf1a85f4 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -251,11 +251,11 @@ #define PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10 3 /**< HDR.*/ #define PAL_SURFACE_FORMAT_COUNT 4 -#define PAL_WINDOW_INSTANCE_TYPE_WAYLAND 0 -#define PAL_WINDOW_INSTANCE_TYPE_X11 1 -#define PAL_WINDOW_INSTANCE_TYPE_XCB 2 -#define PAL_WINDOW_INSTANCE_TYPE_WIN32 3 -#define PAL_WINDOW_INSTANCE_TYPE_COUNT 4 +#define PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_WAYLAND 0 +#define PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_X11 1 +#define PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_XCB 2 +#define PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_WIN32 3 +#define PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_COUNT 4 #define PAL_SHADER_STAGE_UNDEFINED 0 #define PAL_SHADER_STAGE_VERTEX 1 @@ -281,7 +281,7 @@ #define PAL_SAMPLE_COUNT_16 4 #define PAL_SAMPLE_COUNT_32 5 #define PAL_SAMPLE_COUNT_64 6 -#define PAL_SAMPLE_COUNT 7 +#define PAL_SAMPLE_COUNT_COUNT 7 /**< Name redundancy is intentionally consistent.*/ #define PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST 0 #define PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP 1 @@ -427,6 +427,93 @@ #define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL 4 #define PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_COUNT 5 +#define PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL 0 +#define PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL 1 +#define PAL_ACCELERATION_STRUCTURE_TYPE_COUNT 2 + +#define PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD 0 +#define PAL_ACCELERATION_STRUCTURE_BUILD_MODE_UPDATE 1 +#define PAL_ACCELERATION_STRUCTURE_BUILD_MODE_COUNT 2 + +#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD (1ULL << 0) +#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE (1ULL << 1) +#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY (1ULL << 2) + +#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE (1ULL << 0) +#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE (1ULL << 1) +#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE (1ULL << 2) +#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE (1ULL << 3) + +#define PAL_GEOMETRY_TYPE_TRIANGLE 0 +#define PAL_GEOMETRY_TYPE_AABBS 1 +#define PAL_GEOMETRY_TYPE_COUNT 2 + +#define PAL_GEOMETRY_FLAG_OPAQUE (1ULL << 0) +#define PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT (1ULL << 1) + +#define PAL_INDEX_TYPE_UINT16 0 +#define PAL_INDEX_TYPE_UINT32 1 +#define PAL_INDEX_TYPE_COUNT 2 + +#define PAL_BUFFER_USAGE_VERTEX (1ULL << 0) +#define PAL_BUFFER_USAGE_INDEX (1ULL << 1) +#define PAL_BUFFER_USAGE_UNIFORM (1ULL << 2) +#define PAL_BUFFER_USAGE_STORAGE (1ULL << 3) +#define PAL_BUFFER_USAGE_TRANSFER_SRC (1ULL << 4) +#define PAL_BUFFER_USAGE_TRANSFER_DST (1ULL << 5) +#define PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE (1ULL << 6) +#define PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH (1ULL << 7) +#define PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT (1ULL << 8) +#define PAL_BUFFER_USAGE_DEVICE_ADDRESS (1ULL << 9) +#define PAL_BUFFER_USAGE_INDIRECT (1ULL << 10) + +#define PAL_DEBUG_MESSAGE_SEVERITY_INFO 0 +#define PAL_DEBUG_MESSAGE_SEVERITY_WARNING 1 +#define PAL_DEBUG_MESSAGE_SEVERITY_ERROR 2 +#define PAL_DEBUG_MESSAGE_SEVERITY_COUNT 3 + +#define PAL_DEBUG_MESSAGE_TYPE_GENERAL 0 +#define PAL_DEBUG_MESSAGE_TYPE_VALIDATION 1 +#define PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE 2 +#define PAL_DEBUG_MESSAGE_TYPE_COUNT 3 + +#define PAL_USAGE_STATE_UNDEFINED 0 +#define PAL_USAGE_STATE_PRESENT 1 +#define PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE 2 +#define PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ 3 +#define PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE 4 +#define PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ 5 +#define PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE 6 +#define PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ 7 +#define PAL_USAGE_STATE_TRANSFER_READ 8 +#define PAL_USAGE_STATE_TRANSFER_WRITE 9 +#define PAL_USAGE_STATE_VERTEX_READ 10 +#define PAL_USAGE_STATE_INDEX_READ 11 +#define PAL_USAGE_STATE_INDIRECT_READ 12 +#define PAL_USAGE_STATE_UNIFORM_READ 13 +#define PAL_USAGE_STATE_SHADER_READ 14 +#define PAL_USAGE_STATE_SHADER_WRITE 15 +#define PAL_USAGE_STATE_STORAGE_READ 16 +#define PAL_USAGE_STATE_STORAGE_WRITE 17 +#define PAL_USAGE_STATE_HOST_READ 18 +#define PAL_USAGE_STATE_HOST_WRITE 19 +#define PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ 20 +#define PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE 21 +#define PAL_USAGE_STATE_COUNT 22 + +#define PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER 0 +#define PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER 1 +#define PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE 2 +#define PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE 3 +#define PAL_DESCRIPTOR_TYPE_SAMPLER 4 +#define PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE 5 +#define PAL_DESCRIPTOR_TYPE_COUNT 6 + +#define PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL 0 +#define PAL_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT 1 +#define PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT 2 +#define PAL_RAY_TRACING_SHADER_GROUP_TYPE_COUNT 3 + /** * @struct PalAdapter * @brief Opaque handle to an adapter (GPU). @@ -865,15 +952,15 @@ typedef uint32_t PalBorderColor; typedef uint32_t PalSurfaceFormat; /** - * @typedef PalGraphicsWindowDisplayType + * @typedef PalGraphicsWindowInstanceType * @brief Display types for a graphics window. * - * All graphics window display types follow the format `PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_**` for + * All graphics window display types follow the format `PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_**` for * consistency and API use. * * @since 2.0 */ -typedef uint32_t PalGraphicsWindowDisplayType; +typedef uint32_t PalGraphicsWindowInstanceType; /** * @typedef PalShaderStage @@ -1088,26 +1175,6 @@ typedef uint32_t PalFragmentShadingRate; */ typedef uint32_t PalFragmentShadingRateCombinerOp; -/** - * @typedef PalDebugCallback - * @brief Function pointer type used for debug callbacks. - * - * @param userData Optional pointer to user data passed from ::PalGraphicsDebugger. Can be nullptr. - * @param severity Severity of the message. (`PAL_DEBUG_MESSAGE_SEVERITY_INFO`, - * `PAL_DEBUG_MESSAGE_SEVERITY_WARNING` and `PAL_DEBUG_MESSAGE_SEVERITY_ERROR`). - * @param type Type of the message. (`PAL_DEBUG_MESSAGE_TYPE_GENERAL`, - * `PAL_DEBUG_MESSAGE_TYPE_VALIDATION` and `PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE`). - * @param msg Null-terminated UTF-8 debug message. - * - * @since 2.0 - * @sa palInitGraphics - */ -typedef void(PAL_CALL* PalDebugCallback)( - void* userData, - PalDebugMessageSeverity severity, - PalDebugMessageType type, - const char* msg); - /** * @typedef PalAccelerationStructureType * @brief Acceleration structure types. @@ -1117,10 +1184,7 @@ typedef void(PAL_CALL* PalDebugCallback)( * * @since 2.0 */ -typedef enum { - PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL, - PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL -} PalAccelerationStructureType; +typedef uint32_t PalAccelerationStructureType; /** * @typedef PalAccelerationStructureBuildMode @@ -1131,10 +1195,7 @@ typedef enum { * * @since 2.0 */ -typedef enum { - PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD, - PAL_ACCELERATION_STRUCTURE_BUILD_MODE_UPDATE -} PalAccelerationStructureBuildMode; +typedef uint32_t PalAccelerationStructureBuildMode; /** * @typedef PalAccelerationStructureBuildHints @@ -1146,11 +1207,7 @@ typedef enum { * * @since 2.0 */ -typedef enum { - PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD = (1ULL << 0), - PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE = (1ULL << 1), - PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY = (1ULL << 2) -} PalAccelerationStructureBuildHints; +typedef uint64_t PalAccelerationStructureBuildHints; /** * @typedef PalAccelerationStructureInstanceFlags @@ -1162,12 +1219,7 @@ typedef enum { * * @since 2.0 */ -typedef enum { - PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE = (1ULL << 0), - PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE = (1ULL << 1), - PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE = (1ULL << 2), - PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE = (1ULL << 3) -} PalAccelerationStructureInstanceFlags; +typedef uint64_t PalAccelerationStructureInstanceFlags; /** * @typedef PalGeometryType @@ -1177,10 +1229,7 @@ typedef enum { * * @since 2.0 */ -typedef enum { - PAL_GEOMETRY_TYPE_TRIANGLE, - PAL_GEOMETRY_TYPE_AABBS -} PalGeometryType; +typedef uint32_t PalGeometryType; /** * @typedef PalGeometryFlags @@ -1191,10 +1240,7 @@ typedef enum { * * @since 2.0 */ -typedef enum { - PAL_GEOMETRY_FLAG_OPAQUE = (1ULL << 0), - PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT = (1ULL << 1) -} PalGeometryFlags; +typedef uint64_t PalGeometryFlags; /** * @typedef PalIndexType @@ -1204,10 +1250,7 @@ typedef enum { * * @since 2.0 */ -typedef enum { - PAL_INDEX_TYPE_UINT16, - PAL_INDEX_TYPE_UINT32 -} PalIndexType; +typedef uint32_t PalIndexType; /** * @typedef PalBufferUsages @@ -1218,31 +1261,7 @@ typedef enum { * * @since 2.0 */ -typedef enum { - PAL_BUFFER_USAGE_VERTEX = (1ULL << 0), - PAL_BUFFER_USAGE_INDEX = (1ULL << 1), - PAL_BUFFER_USAGE_UNIFORM = (1ULL << 2), - PAL_BUFFER_USAGE_STORAGE = (1ULL << 3), - PAL_BUFFER_USAGE_TRANSFER_SRC = (1ULL << 4), - PAL_BUFFER_USAGE_TRANSFER_DST = (1ULL << 5), - PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE = (1ULL << 6), - PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH = (1ULL << 7), - PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT = (1ULL << 8), - PAL_BUFFER_USAGE_DEVICE_ADDRESS = (1ULL << 9), - PAL_BUFFER_USAGE_INDIRECT = (1ULL << 10) -} PalBufferUsages; - -enum PalDebugMessageSeverity { - PAL_DEBUG_MESSAGE_SEVERITY_INFO, - PAL_DEBUG_MESSAGE_SEVERITY_WARNING, - PAL_DEBUG_MESSAGE_SEVERITY_ERROR -}; - -enum PalDebugMessageType { - PAL_DEBUG_MESSAGE_TYPE_GENERAL, - PAL_DEBUG_MESSAGE_TYPE_VALIDATION, - PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE -}; +typedef uint64_t PalBufferUsages; /** * @typedef PalUsageState @@ -1252,31 +1271,7 @@ enum PalDebugMessageType { * * @since 2.0 */ -typedef enum { - PAL_USAGE_STATE_UNDEFINED, - - PAL_USAGE_STATE_PRESENT, - PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE, - PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ, - PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE, - PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ, - PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE, - PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ, - PAL_USAGE_STATE_TRANSFER_READ, - PAL_USAGE_STATE_TRANSFER_WRITE, - PAL_USAGE_STATE_VERTEX_READ, - PAL_USAGE_STATE_INDEX_READ, - PAL_USAGE_STATE_INDIRECT_READ, - PAL_USAGE_STATE_UNIFORM_READ, - PAL_USAGE_STATE_SHADER_READ, - PAL_USAGE_STATE_SHADER_WRITE, - PAL_USAGE_STATE_STORAGE_READ, - PAL_USAGE_STATE_STORAGE_WRITE, - PAL_USAGE_STATE_HOST_READ, - PAL_USAGE_STATE_HOST_WRITE, - PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ, - PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE -} PalUsageState; +typedef uint32_t PalUsageState; /** * @typedef PalDescriptorType @@ -1286,14 +1281,7 @@ typedef enum { * * @since 2.0 */ -typedef enum { - PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER, - PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE, - PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE, - PAL_DESCRIPTOR_TYPE_SAMPLER, - PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE -} PalDescriptorType; +typedef uint32_t PalDescriptorType; /** * @typedef PalRayTracingShaderGroupType @@ -1304,11 +1292,27 @@ typedef enum { * * @since 2.0 */ -typedef enum { - PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL, - PAL_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT, - PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT -} PalRayTracingShaderGroupType; +typedef uint32_t PalRayTracingShaderGroupType; + +/** + * @typedef PalDebugCallback + * @brief Function pointer type used for debug callbacks. + * + * @param userData Optional pointer to user data passed from ::PalGraphicsDebugger. Can be nullptr. + * @param severity Severity of the message. (`PAL_DEBUG_MESSAGE_SEVERITY_INFO`, + * `PAL_DEBUG_MESSAGE_SEVERITY_WARNING` and `PAL_DEBUG_MESSAGE_SEVERITY_ERROR`). + * @param type Type of the message. (`PAL_DEBUG_MESSAGE_TYPE_GENERAL`, + * `PAL_DEBUG_MESSAGE_TYPE_VALIDATION` and `PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE`). + * @param msg Null-terminated UTF-8 debug message. + * + * @since 2.0 + * @sa palInitGraphics + */ +typedef void(PAL_CALL* PalDebugCallback)( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg); /** * @struct PalAdapterInfo @@ -1317,13 +1321,13 @@ typedef enum { * @since 2.0 */ typedef struct { + PalShaderFormats shaderFormats; /**< Supported shader formats mask (eg. Spirv, DXIL, ect).*/ + uint64_t vram; + uint64_t sharedMemory; uint32_t vendorId; uint32_t deviceId; PalAdapterType type; /**< Discrete, Integrated, etc.*/ PalAdapterApiType apiType; /**< Vulkan, D3D12, etc.*/ - PalShaderFormats shaderFormats; /**< Supported shader formats mask (eg. Spirv, DXIL, ect).*/ - uint64_t vram; - uint64_t sharedMemory; char name[PAL_ADAPTER_NAME_SIZE]; char backendName[PAL_ADAPTER_NAME_SIZE]; /**< Adapter backend name (eg. `PAL`, `Custom`).*/ } PalAdapterInfo; @@ -1453,9 +1457,10 @@ typedef struct { * @since 2.0 */ typedef struct { + uint64_t supportedDepthResolveModes; + uint64_t supportedStencilResolveModes; PalBool independentResolve; - PalBool depthResolves[PAL_MAX_RESOLVE_MODES]; - PalBool stencilResolves[PAL_MAX_RESOLVE_MODES]; + PalBool independentResolveNone; /**< If PAL_TRUE, depth or stencil can be NONE while the other is resolved.*/ } PalDepthStencilCapabilities; /** @@ -1465,12 +1470,12 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool shadingRates[PAL_FRAGMENT_SHADING_RATE_MAX]; + uint64_t supportedShadingRates; + uint64_t supportedCombinerOps; uint32_t minTexelWidth; uint32_t minTexelHeight; uint32_t maxTexelWidth; uint32_t maxTexelHeight; - PalBool combinerOps[PAL_MAX_COMBINER_OPS]; } PalFragmentShadingRateCapabilities; /** @@ -1540,9 +1545,9 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool presentModes[PAL_PRESENT_MODE_MAX]; - PalBool compositeAlphas[PAL_COMPOSITE_ALPHA_MAX]; - PalBool formats[PAL_SURFACE_FORMAT_MAX]; + uint64_t supportedPresentModes; + uint64_t supportedCompositeAlphas; + uint64_t supportedFormats; uint32_t minImageCount; uint32_t maxImageCount; uint32_t minImageWidth; @@ -1550,6 +1555,7 @@ typedef struct { uint32_t maxImageWidth; uint32_t maxImageHeight; uint32_t maxImageArrayLayers; + PalBool supportsDisabledClipping; } PalSurfaceCapabilities; /** @@ -1562,8 +1568,8 @@ typedef struct { * @since 2.0 */ typedef struct { - PalGraphicsWindowDisplayType displayType; /**< Will be used only on linux platform.*/ - void* display; /**< Can be nullptr depending on platform (eg. Windows).*/ + PalGraphicsWindowInstanceType instanceType; + void* instance; /**< Must not be nullptr. (HINSTANCE on Win32 or wl_display on Wayland)*/ void* window; /**< Must not be nullptr.*/ } PalGraphicsWindow; @@ -1575,8 +1581,8 @@ typedef struct { * @since 2.0 */ typedef struct { - PalFormat format; PalImageUsages usages; + PalFormat format; PalSampleCount sampleCount; /**< Maximum supported multisample count.*/ } PalFormatInfo; @@ -1587,6 +1593,7 @@ typedef struct { * @since 2.0 */ typedef struct { + PalImageUsages usages; uint32_t width; /**< Width of the image in pixels.*/ uint32_t height; /**< Height of the image in pixels.*/ uint32_t depthOrArraySize; /**< Depth for 3D image and array size for 2D image.*/ @@ -1594,8 +1601,7 @@ typedef struct { PalSampleCount sampleCount; PalImageType type; /**< 1D, 2D, 3D.*/ PalFormat format; - PalImageUsages usages; -} PalImageInfo; +} PalImageInfo; // TODO: /** * @struct PalClearValue @@ -1621,6 +1627,8 @@ typedef struct { * @since 2.0 */ typedef struct { + PalImageView* imageView; /**< Image view. Must not be nullptr.*/ + PalImageView* resolveImageView; /**< Optional resolve image view.*/ PalLoadOp loadOp; PalStoreOp storeOp; PalLoadOp stencilLoadOp; @@ -1628,8 +1636,6 @@ typedef struct { PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ uint32_t texelWidth; /**< Texel width for fragment shading rate attachment.*/ uint32_t texelHeight; /**< Texel height for fragment shading rate attachment.*/ - PalImageView* imageView; /**< Image view. Must not be nullptr.*/ - PalImageView* resolveImageView; /**< Optional resolve image view.*/ PalClearValue clearValue; } PalAttachmentDesc; @@ -1642,9 +1648,9 @@ typedef struct { * @since 2.0 */ typedef struct { + PalShaderStage* shaderStages; uint32_t shaderStageCount; PalUsageState usageState; - PalShaderStage* shaderStages; } PalUsageStateInfo; /** @@ -1682,7 +1688,7 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool memoryTypes[PAL_MEMORY_TYPE_MAX]; + uint64_t supportedMemoryTypes; uint64_t memoryMask; uint64_t size; uint64_t alignment; @@ -1729,7 +1735,7 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t imageIndex; /**< Image index to present. Must be 0 and less than max images.*/ + uint64_t imageIndex; /**< Image index to present. Must be 0 and less than max images.*/ uint64_t waitValue; PalSemaphore* waitSemaphore; } PalSwapchainPresentInfo; @@ -1743,11 +1749,11 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ - uint32_t colorAttachentCount; PalAttachmentDesc* colorAttachments; PalAttachmentDesc* depthStencilAttachment; PalAttachmentDesc* fragmentShadingRateAttachment; + uint32_t viewCount; + uint32_t colorAttachentCount; } PalRenderingInfo; /** @@ -1760,12 +1766,12 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t viewCount; /**< If > 1 `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported.*/ - uint32_t colorAttachentCount; + PalFormat* colorAttachmentsFormat; + uint64_t colorAttachentCount; + uint32_t viewCount; PalSampleCount multisampleCount; PalFormat depthStencilAttachmentFormat; PalFormat fragmentShadingRateAttachmentFormat; - PalFormat* colorAttachmentsFormat; } PalRenderingLayoutInfo; /** @@ -1850,9 +1856,9 @@ typedef struct { * @since 2.0 */ typedef struct { + const char* semanticName; PalVertexSemanticID semanticID; PalVertexType type; - const char* semanticName; } PalVertexAttribute; /** @@ -1870,10 +1876,10 @@ typedef struct { * @since 2.0 */ typedef struct { + PalVertexAttribute* attributes; + uint64_t attributeCount; PalVertexLayoutType type; uint32_t binding; - uint32_t attributeCount; - PalVertexAttribute* attributes; } PalVertexLayout; /** @@ -1885,14 +1891,14 @@ typedef struct { * @since 2.0 */ typedef struct { + void* userData; + PalDebugCallback callback; PalBool denyGeneral; PalBool denyValidation; PalBool denyPerformance; PalBool denyInfoSeverity; PalBool denyWarningSeverity; PalBool denyErrorSeverity; - void* userData; - PalDebugCallback callback; } PalGraphicsDebugger; /** @@ -1923,10 +1929,10 @@ typedef struct { * @since 2.0 */ typedef struct { + uint64_t sampleMask; PalBool enableSampleShading; PalBool enableAlphaToCoverage; PalSampleCount sampleCount; - uint64_t sampleMask; float minSampleShading; } PalMultisampleState; @@ -1974,15 +1980,15 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool enableBlend; PalColorMask colorWriteMask; + PalBool enableBlend; PalBlendFactor srcColorBlendFactor; PalBlendFactor dstColorBlendFactor; PalBlendOp colorBlendOp; PalBlendFactor srcAlphaBlendFactor; PalBlendFactor dstAlphaBlendFactor; PalBlendOp alphaBlendOp; -} PalColorBlendAttachment; +} PalColorBlendAttachment; // TODO: /** * @struct PalFragmentShadingRateState @@ -2006,13 +2012,13 @@ typedef struct { * @since 2.0 */ typedef struct { + PalAccelerationStructure* blas; + PalAccelerationStructureInstanceFlags flags; uint32_t instanceId; uint32_t mask; uint32_t hitGroupOffset; - PalAccelerationStructureInstanceFlags flags; - PalAccelerationStructure* blas; float transform[12]; /**< row major (3x4).*/ -} PalAccelerationStructureInstance; +} PalAccelerationStructureInstance; // TODO: /** * @struct PalAccelerationStructureBuildSize @@ -2035,14 +2041,14 @@ typedef struct { * @since 2.0 */ typedef struct { + PalDeviceAddress vertexBufferAddress; + PalDeviceAddress indexBufferAddress; PalVertexType vertexType; PalIndexType indexType; uint32_t vertexStride; uint32_t indexCount; uint32_t vertexCount; - PalDeviceAddress vertexBufferAddress; - PalDeviceAddress indexBufferAddress; -} PalGeometryDataTriangle; +} PalGeometryDataTriangle; // TODO: /** * @struct PalGeometryDataAABBS @@ -2053,9 +2059,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t stride; PalDeviceAddress bufferAddress; -} PalGeometryDataAABBS; + uint32_t stride; +} PalGeometryDataAABBS; // TODO: /** * @struct PalGeometry @@ -2066,10 +2072,10 @@ typedef struct { * @since 2.0 */ typedef struct { + void* data; /**< Pointer to geometry data. This will be casted based on the geometry type.*/ PalGeometryFlags flags; uint32_t primitiveCount; PalGeometryType type; - void* data; /**< Pointer to geometry data. This will be casted based on the geometry type.*/ } PalGeometry; /** @@ -2081,16 +2087,16 @@ typedef struct { * @since 2.0 */ typedef struct { - PalAccelerationStructureType type; - uint32_t geometryCount; - uint32_t instanceCount; - PalAccelerationStructureBuildHints buildHints; - PalAccelerationStructureBuildMode buildMode; - PalDeviceAddress scratchBufferAddress; - PalDeviceAddress instanceBufferAddress; PalAccelerationStructure* dst; PalAccelerationStructure* src; PalGeometry* geometries; + PalDeviceAddress scratchBufferAddress; + PalDeviceAddress instanceBufferAddress; + PalAccelerationStructureBuildHints buildHints; + PalAccelerationStructureType type; + PalAccelerationStructureBuildMode buildMode; + uint32_t geometryCount; + uint32_t instanceCount; } PalAccelerationStructureBuildInfo; /** @@ -2129,10 +2135,10 @@ typedef struct { * @since 2.0 */ typedef struct { + PalBuffer* buffer; + uint64_t offset; /**< Offset in bytes. If structured, will be divided by `stride`.*/ uint32_t size; uint32_t stride; /**< For structured buffers. Will be ignored if not supported. 0 for default.*/ - uint64_t offset; /**< Offset in bytes. If structured, will be divided by `stride`.*/ - PalBuffer* buffer; } PalDescriptorBufferInfo; /** @@ -2180,15 +2186,15 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t layoutBindingIndex; /**< Index into the descriptor set layout bindings.*/ - uint32_t arrayElement; - uint32_t descriptorCount; - PalDescriptorType descriptorType; PalDescriptorSet* descriptorSet; PalDescriptorBufferInfo* bufferInfos; PalDescriptorImageViewInfo* imageViewInfos; PalDescriptorSamplerInfo* samplerInfos; PalDescriptorTLASInfo* tlasInfos; + PalDescriptorType descriptorType; + uint32_t layoutBindingIndex; /**< Index into the descriptor set layout bindings.*/ + uint32_t arrayElement; + uint32_t descriptorCount; } PalDescriptorSetWriteInfo; /** @@ -2200,10 +2206,10 @@ typedef struct { * @since 2.0 */ typedef struct { + PalShaderStage* shaderStages; uint64_t offset; uint64_t size; - uint32_t shaderStageCount; - PalShaderStage* shaderStages; + uint64_t shaderStageCount; } PalPushConstantRange; /** @@ -2215,11 +2221,11 @@ typedef struct { * @since 2.0 */ typedef struct { + PalImageAspect aspect; /**< Must be compatible with the image format.*/ uint32_t startMipLevel; uint32_t mipLevelCount; uint32_t startArrayLayer; uint32_t layerArrayCount; - PalImageAspect aspect; /**< Must be compatible with the image format.*/ } PalImageSubresourceRange; /** @@ -2231,7 +2237,7 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t size; + uint64_t size; uint64_t dstOffset; uint64_t srcOffset; } PalBufferCopyInfo; @@ -2297,9 +2303,9 @@ typedef struct { * @since 2.0 */ typedef struct { + void* localData; uint32_t groupIndex; /**< Index into the shader groups used to create the ray tracing pipeline.*/ uint32_t localDataSize; /**< Must not be greater than the data size of the group.*/ - void* localData; } PalShaderBindingTableRecordInfo; /** @@ -2311,9 +2317,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ - PalShaderStage stage; const char* entryName; + PalShaderStage stage; + uint32_t patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ } PalShaderEntryInfo; /** @@ -2325,6 +2331,7 @@ typedef struct { * @since 2.0 */ typedef struct { + PalImageUsages usages; uint32_t width; uint32_t height; uint32_t depthOrArraySize; @@ -2332,8 +2339,7 @@ typedef struct { PalSampleCount sampleCount; PalImageType type; PalFormat format; - PalImageUsages usages; -} PalImageCreateInfo; +} PalImageCreateInfo; // TODO: /** * @struct PalImageCreateInfo @@ -2359,7 +2365,7 @@ typedef struct { */ typedef struct { PalBool enableCompare; - PalBool enableAnisotropy; /**< `PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY` must be supported.*/ + PalBool enableAnisotropy; float mipLodBias; float minLod; float maxLod; @@ -2402,10 +2408,10 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t entryCount; - uint64_t bytecodeSize; void* bytecode; PalShaderEntryInfo* entries; + uint64_t bytecodeSize; + uint64_t entryCount; } PalShaderCreateInfo; /** @@ -2430,11 +2436,11 @@ typedef struct { * @since 2.0 */ typedef struct { - PalAccelerationStructureType type; PalBuffer* buffer; uint64_t offset; uint64_t size; -} PalAccelerationStructureCreateInfo; + PalAccelerationStructureType type; +} PalAccelerationStructureCreateInfo; // TODO: /** * @struct PalDescriptorSetLayoutCreateInfo @@ -2446,12 +2452,12 @@ typedef struct { * @since 2.0 */ typedef struct { + PalShaderStage* shaderStages; + PalDescriptorSetLayoutBinding* bindings; PalBool enableDescriptorIndexing; uint32_t bindingCount; uint32_t shaderStageCount; - PalShaderStage* shaderStages; - PalDescriptorSetLayoutBinding* bindings; -} PalDescriptorSetLayoutCreateInfo; +} PalDescriptorSetLayoutCreateInfo; // TODO: /** * @struct PalDescriptorPoolCreateInfo @@ -2463,11 +2469,11 @@ typedef struct { * @since 2.0 */ typedef struct { + PalDescriptorPoolBindingSize* bindingSizes; PalBool enableDescriptorIndexing; uint32_t maxDescriptorSets; uint32_t maxDescriptorBindingSizes; - PalDescriptorPoolBindingSize* bindingSizes; -} PalDescriptorPoolCreateInfo; +} PalDescriptorPoolCreateInfo; // TODO: /** * @struct PalPipelineLayoutCreateInfo @@ -2478,10 +2484,10 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t descriptorSetLayoutCount; - uint32_t pushConstantRangeCount; PalDescriptorSetLayout** descriptorSetLayouts; PalPushConstantRange* pushConstantRanges; + uint32_t descriptorSetLayoutCount; + uint32_t pushConstantRangeCount; } PalPipelineLayoutCreateInfo; /** @@ -2493,12 +2499,6 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool primitiveRestartEnable; - uint32_t vertexLayoutCount; - uint32_t colorBlendAttachmentCount; - uint32_t shaderCount; - PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is `PAL_TRUE`.*/ - PalPrimitiveTopology topology; PalPipelineLayout* pipelineLayout; PalShader** shaders; PalVertexLayout* vertexLayouts; @@ -2508,6 +2508,12 @@ typedef struct { PalDepthStencilState* depthStencilState; PalFragmentShadingRateState* fragmentShadingRateState; PalRenderingLayoutInfo* renderingLayout; + PalBool primitiveRestartEnable; + uint32_t vertexLayoutCount; + uint32_t colorBlendAttachmentCount; + uint32_t shaderCount; + PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is `PAL_TRUE`.*/ + PalPrimitiveTopology topology; } PalGraphicsPipelineCreateInfo; /** @@ -2555,15 +2561,15 @@ typedef struct { * @since 2.0 */ typedef struct { + PalPipelineLayout* pipelineLayout; + PalRayTracingShaderGroupCreateInfo* shaderGroups; + PalShader** shaders; uint32_t shaderCount; uint32_t shaderGroupCount; uint32_t maxRecursionDepth; uint32_t maxAttributeSize; uint32_t maxPayloadSize; - PalPipelineLayout* pipelineLayout; - PalRayTracingShaderGroupCreateInfo* shaderGroups; - PalShader** shaders; -} PalRayTracingPipelineCreateInfo; +} PalRayTracingPipelineCreateInfo; // TODO: /** * @struct PalShaderBindingTableCreateInfo @@ -2574,9 +2580,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t recordCount; PalShaderBindingTableRecordInfo* records; PalPipeline* rayTracingPipeline; + uint64_t recordCount; } PalShaderBindingTableCreateInfo; /** From c12e0bddff61ba356ceef815fe27b33eb6d09652 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 22 Jun 2026 14:34:49 +0000 Subject: [PATCH 291/372] improve API --- CHANGELOG.md | 3 +- include/pal/pal_event.h | 6 +- include/pal/pal_graphics.h | 384 +++++++++---------- include/pal/pal_video.h | 31 +- src/graphics/pal_d3d12.c | 2 +- src/graphics/pal_vulkan.c | 19 +- src/video/linux/wayland/pal_window_wayland.c | 2 - 7 files changed, 197 insertions(+), 250 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2112a2b..bee4aeba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,7 +62,8 @@ - Renamed `nativeDisplay` to `nativeInstance` in `PalWindowHandleInfo`. - Renamed `display` to `instance` in `PalGLWindow`. - `PalWindowHandleInfo` now has `nativeHandle1`, `nativeHandle2` and `nativeHandle3` fields. -- `PalWindowCreateInfo` now has `appName`, `instanceName`, `fbConfigBackend` and `fbConfigIndex` fields. +- `PalWindowCreateInfo` now has `state`, `appName`, `instanceName`, `fbConfigBackend` and `fbConfigIndex` fields. +- Removed `maximized` and `minimized` in `PalWindowCreateInfo`. diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 6cc52895..cb680960 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -262,7 +262,7 @@ typedef uint32_t PalDecorationMode; * * @since 1.0 */ -typedef uint64_t PalEventType; +typedef uint32_t PalEventType; /** * @typedef PalDispatchMode @@ -273,7 +273,7 @@ typedef uint64_t PalEventType; * * @since 1.0 */ -typedef uint64_t PalDispatchMode; +typedef uint32_t PalDispatchMode; /** * @typedef PalEventCallback @@ -322,9 +322,9 @@ typedef PalBool(PAL_CALL* PalPollFn)( PalEvent* outEvent); struct PalEvent { - int64_t userId; /**< You can have user events upto int64_t max.*/ int64_t data; /**< First data payload.*/ int64_t data2; /**< Second data payload.*/ + int32_t userId; /**< You can have user events upto int32_t max.*/ PalEventType type; }; diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index bf1a85f4..be5ef399 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -17,6 +17,7 @@ #include "pal_core.h" #define PAL_ADAPTER_NAME_SIZE 128 +#define PAL_ADAPTER_BACKEND_NAME_SIZE 32 #define PAL_SHADER_ENTRY_NAME_SIZE 32 #define PAL_UNUSED_SHADER_INDEX UINT32_MAX @@ -177,17 +178,17 @@ #define PAL_FORMAT_COUNT 81 #define PAL_IMAGE_USAGE_UNDEFINED 0 -#define PAL_IMAGE_USAGE_COLOR_ATTACHEMENT (1ULL << 0) -#define PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT (1ULL << 1) -#define PAL_IMAGE_USAGE_TRANSFER_SRC (1ULL << 2) -#define PAL_IMAGE_USAGE_TRANSFER_DST (1ULL << 3) -#define PAL_IMAGE_USAGE_STORAGE (1ULL << 4) -#define PAL_IMAGE_USAGE_SAMPLED (1ULL << 5) - -#define PAL_SHADER_FORMAT_SPIRV (1ULL << 0) -#define PAL_SHADER_FORMAT_DXIL (1ULL << 1) -#define PAL_SHADER_FORMAT_MSL (1ULL << 2) -#define PAL_SHADER_FORMAT_CUSTOM (1ULL << 3) +#define PAL_IMAGE_USAGE_COLOR_ATTACHEMENT (1U << 0) +#define PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT (1U << 1) +#define PAL_IMAGE_USAGE_TRANSFER_SRC (1U << 2) +#define PAL_IMAGE_USAGE_TRANSFER_DST (1U << 3) +#define PAL_IMAGE_USAGE_STORAGE (1U << 4) +#define PAL_IMAGE_USAGE_SAMPLED (1U << 5) + +#define PAL_SHADER_FORMAT_SPIRV (1U << 0) +#define PAL_SHADER_FORMAT_DXIL (1U << 1) +#define PAL_SHADER_FORMAT_MSL (1U << 2) +#define PAL_SHADER_FORMAT_CUSTOM (1U << 3) #define PAL_LOAD_OP_LOAD 0 #define PAL_LOAD_OP_CLEAR 1 @@ -251,11 +252,11 @@ #define PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10 3 /**< HDR.*/ #define PAL_SURFACE_FORMAT_COUNT 4 -#define PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_WAYLAND 0 -#define PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_X11 1 -#define PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_XCB 2 -#define PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_WIN32 3 -#define PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_COUNT 4 +#define PAL_WINDOW_INSTANCE_TYPE_WAYLAND 0 +#define PAL_WINDOW_INSTANCE_TYPE_X11 1 +#define PAL_WINDOW_INSTANCE_TYPE_XCB 2 +#define PAL_WINDOW_INSTANCE_TYPE_WIN32 3 +#define PAL_WINDOW_INSTANCE_TYPE_COUNT 4 #define PAL_SHADER_STAGE_UNDEFINED 0 #define PAL_SHADER_STAGE_VERTEX 1 @@ -304,8 +305,8 @@ #define PAL_POLYGON_MODE_LINE 1 #define PAL_POLYGON_MODE_COUNT 2 -#define PAL_STENCIL_FACE_FRONT (1ULL << 0) -#define PAL_STENCIL_FACE_BACK (1ULL << 1) +#define PAL_STENCIL_FACE_FRONT (1U << 0) +#define PAL_STENCIL_FACE_BACK (1U << 1) #define PAL_STENCIL_FACE_BOTH (PAL_STENCIL_FACE_FRONT | PAL_STENCIL_FACE_BACK) #define PAL_VERTEX_TYPE_UNDEFINED 0 @@ -399,10 +400,10 @@ #define PAL_BLEND_FACTOR_COUNT 13 #define PAL_COLOR_MASK_NONE 0 -#define PAL_COLOR_MASK_RED (1ULL << 0) -#define PAL_COLOR_MASK_GREEN (1ULL << 1) -#define PAL_COLOR_MASK_BLUE (1ULL << 2) -#define PAL_COLOR_MASK_ALPHA (1ULL << 3) +#define PAL_COLOR_MASK_RED (1U << 0) +#define PAL_COLOR_MASK_GREEN (1U << 1) +#define PAL_COLOR_MASK_BLUE (1U << 2) +#define PAL_COLOR_MASK_ALPHA (1U << 3) #define PAL_RESOLVE_MODE_NONE 0 #define PAL_RESOLVE_MODE_SAMPLE_ZERO 1 @@ -435,37 +436,37 @@ #define PAL_ACCELERATION_STRUCTURE_BUILD_MODE_UPDATE 1 #define PAL_ACCELERATION_STRUCTURE_BUILD_MODE_COUNT 2 -#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD (1ULL << 0) -#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE (1ULL << 1) -#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY (1ULL << 2) +#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD (1U << 0) +#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE (1U << 1) +#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY (1U << 2) -#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE (1ULL << 0) -#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE (1ULL << 1) -#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE (1ULL << 2) -#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE (1ULL << 3) +#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE (1U << 0) +#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE (1U << 1) +#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CU_DISABLE (1U << 2) +#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE (1U << 3) #define PAL_GEOMETRY_TYPE_TRIANGLE 0 #define PAL_GEOMETRY_TYPE_AABBS 1 #define PAL_GEOMETRY_TYPE_COUNT 2 -#define PAL_GEOMETRY_FLAG_OPAQUE (1ULL << 0) -#define PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT (1ULL << 1) +#define PAL_GEOMETRY_FLAG_OPAQUE (1U << 0) +#define PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT (1U << 1) #define PAL_INDEX_TYPE_UINT16 0 #define PAL_INDEX_TYPE_UINT32 1 #define PAL_INDEX_TYPE_COUNT 2 -#define PAL_BUFFER_USAGE_VERTEX (1ULL << 0) -#define PAL_BUFFER_USAGE_INDEX (1ULL << 1) -#define PAL_BUFFER_USAGE_UNIFORM (1ULL << 2) -#define PAL_BUFFER_USAGE_STORAGE (1ULL << 3) -#define PAL_BUFFER_USAGE_TRANSFER_SRC (1ULL << 4) -#define PAL_BUFFER_USAGE_TRANSFER_DST (1ULL << 5) -#define PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE (1ULL << 6) -#define PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH (1ULL << 7) -#define PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT (1ULL << 8) -#define PAL_BUFFER_USAGE_DEVICE_ADDRESS (1ULL << 9) -#define PAL_BUFFER_USAGE_INDIRECT (1ULL << 10) +#define PAL_BUFFER_USAGE_VERTEX (1U << 0) +#define PAL_BUFFER_USAGE_INDEX (1U << 1) +#define PAL_BUFFER_USAGE_UNIFORM (1U << 2) +#define PAL_BUFFER_USAGE_STORAGE (1U << 3) +#define PAL_BUFFER_USAGE_TRANSFER_SRC (1U << 4) +#define PAL_BUFFER_USAGE_TRANSFER_DST (1U << 5) +#define PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE (1U << 6) +#define PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH (1U << 7) +#define PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT (1U << 8) +#define PAL_BUFFER_USAGE_DEVICE_ADDRESS (1U << 9) +#define PAL_BUFFER_USAGE_INDIRECT (1U << 10) #define PAL_DEBUG_MESSAGE_SEVERITY_INFO 0 #define PAL_DEBUG_MESSAGE_SEVERITY_WARNING 1 @@ -509,6 +510,14 @@ #define PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE 5 #define PAL_DESCRIPTOR_TYPE_COUNT 6 +#define PAL_DESCRIPTOR_INDEXING_FLAG_NONE 0 +#define PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND (1U << 0) +#define PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND (1U << 1) +#define PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING (1U << 2) + +#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE (1U << 1) +#define PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY (1U << 2) + #define PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL 0 #define PAL_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT 1 #define PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT 2 @@ -817,7 +826,7 @@ typedef uint32_t PalFormat; * * @since 2.0 */ -typedef uint64_t PalImageUsages; +typedef uint32_t PalImageUsages; /** * @typedef PalShaderFormats @@ -828,7 +837,7 @@ typedef uint64_t PalImageUsages; * * @since 2.0 */ -typedef uint64_t PalShaderFormats; +typedef uint32_t PalShaderFormats; /** * @typedef PalLoadOp @@ -952,15 +961,15 @@ typedef uint32_t PalBorderColor; typedef uint32_t PalSurfaceFormat; /** - * @typedef PalGraphicsWindowInstanceType - * @brief Display types for a graphics window. + * @typedef WindowInstanceType + * @brief Display types for a window. * - * All graphics window display types follow the format `PAL_GRAPHICS_WINDOW_INSTANCE_TYPE_**` for + * All window display types follow the format `PAL_WINDOW_INSTANCE_TYPE_**` for * consistency and API use. * * @since 2.0 */ -typedef uint32_t PalGraphicsWindowInstanceType; +typedef uint32_t PalWindowInstanceType; /** * @typedef PalShaderStage @@ -1038,7 +1047,7 @@ typedef uint32_t PalPolygonMode; * * @since 2.0 */ -typedef uint64_t PalStencilFaceFlags; +typedef uint32_t PalStencilFaceFlags; /** * @typedef PalVertexType @@ -1140,7 +1149,7 @@ typedef uint32_t PalBlendFactor; * * @since 2.0 */ -typedef uint64_t PalColorMask; +typedef uint32_t PalColorMask; /** * @typedef PalResolveMode @@ -1207,7 +1216,7 @@ typedef uint32_t PalAccelerationStructureBuildMode; * * @since 2.0 */ -typedef uint64_t PalAccelerationStructureBuildHints; +typedef uint32_t PalAccelerationStructureBuildHints; /** * @typedef PalAccelerationStructureInstanceFlags @@ -1219,7 +1228,7 @@ typedef uint64_t PalAccelerationStructureBuildHints; * * @since 2.0 */ -typedef uint64_t PalAccelerationStructureInstanceFlags; +typedef uint32_t PalAccelerationStructureInstanceFlags; /** * @typedef PalGeometryType @@ -1240,7 +1249,7 @@ typedef uint32_t PalGeometryType; * * @since 2.0 */ -typedef uint64_t PalGeometryFlags; +typedef uint32_t PalGeometryFlags; /** * @typedef PalIndexType @@ -1261,7 +1270,7 @@ typedef uint32_t PalIndexType; * * @since 2.0 */ -typedef uint64_t PalBufferUsages; +typedef uint32_t PalBufferUsages; /** * @typedef PalUsageState @@ -1294,6 +1303,17 @@ typedef uint32_t PalDescriptorType; */ typedef uint32_t PalRayTracingShaderGroupType; +/** + * @typedef PalDescriptorIndexingFlags + * @brief Descriptor indexing subfeature flags. + * + * All descriptor indexing flags follow the format `PAL_DESCRIPTOR_INDEXING_FLAG_**` + * for consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalDescriptorIndexingFlags; + /** * @typedef PalDebugCallback * @brief Function pointer type used for debug callbacks. @@ -1321,15 +1341,16 @@ typedef void(PAL_CALL* PalDebugCallback)( * @since 2.0 */ typedef struct { - PalShaderFormats shaderFormats; /**< Supported shader formats mask (eg. Spirv, DXIL, ect).*/ uint64_t vram; uint64_t sharedMemory; uint32_t vendorId; uint32_t deviceId; + uint32_t driverVersion; + PalShaderFormats shaderFormats; /**< Supported shader formats mask (eg. Spirv, DXIL, ect).*/ PalAdapterType type; /**< Discrete, Integrated, etc.*/ PalAdapterApiType apiType; /**< Vulkan, D3D12, etc.*/ char name[PAL_ADAPTER_NAME_SIZE]; - char backendName[PAL_ADAPTER_NAME_SIZE]; /**< Adapter backend name (eg. `PAL`, `Custom`).*/ + char backendName[PAL_ADAPTER_BACKEND_NAME_SIZE]; /**< Adapter backend name (eg. `PAL`, `Custom`).*/ } PalAdapterInfo; /** @@ -1353,10 +1374,6 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool sampledImageDynamicArrayIndexing; - PalBool storageImageDynamicArrayIndexing; - PalBool storageBufferDynamicArrayIndexing; - PalBool uniformBufferDynamicArrayIndexing; uint32_t maxPerStageSampledImages; uint32_t maxPerSetSampledImages; uint32_t maxPerStageStorageImages; @@ -1457,10 +1474,10 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t supportedDepthResolveModes; - uint64_t supportedStencilResolveModes; - PalBool independentResolve; - PalBool independentResolveNone; /**< If PAL_TRUE, depth or stencil can be NONE while the other is resolved.*/ + uint32_t supportedDepthResolveModes; + uint32_t supportedStencilResolveModes; + PalBool supportsIndependentResolve; + PalBool supportsIndependentResolveNone; /**< If PAL_TRUE, depth or stencil can be NONE while the other is resolved.*/ } PalDepthStencilCapabilities; /** @@ -1470,8 +1487,8 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t supportedShadingRates; - uint64_t supportedCombinerOps; + uint32_t supportedShadingRates; + uint32_t supportedCombinerOps; uint32_t minTexelWidth; uint32_t minTexelHeight; uint32_t maxTexelWidth; @@ -1516,14 +1533,7 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool sampledImageNonUniformIndexing; - PalBool sampledImageUpdateAfterBind; - PalBool storageImageNonUniformIndexing; - PalBool storageImageUpdateAfterBind; - PalBool storageBufferNonUniformIndexing; - PalBool storageBufferUpdateAfterBind; - PalBool uniformBufferNonUniformIndexing; - PalBool uniformBufferUpdateAfterBind; + PalDescriptorIndexingFlags flags; uint32_t maxPerStageSampledImages; uint32_t maxPerSetSampledImages; uint32_t maxPerStageStorageImages; @@ -1545,9 +1555,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t supportedPresentModes; - uint64_t supportedCompositeAlphas; - uint64_t supportedFormats; + uint32_t supportedPresentModes; + uint32_t supportedCompositeAlphas; + uint32_t supportedFormats; uint32_t minImageCount; uint32_t maxImageCount; uint32_t minImageWidth; @@ -1555,24 +1565,8 @@ typedef struct { uint32_t maxImageWidth; uint32_t maxImageHeight; uint32_t maxImageArrayLayers; - PalBool supportsDisabledClipping; } PalSurfaceCapabilities; -/** - * @struct PalGraphicsWindow - * @brief Information about a graphics window. - * - * This can be allocated statically or dynamically since its used for - * holding native handles. The handles will not be copied. - * - * @since 2.0 - */ -typedef struct { - PalGraphicsWindowInstanceType instanceType; - void* instance; /**< Must not be nullptr. (HINSTANCE on Win32 or wl_display on Wayland)*/ - void* window; /**< Must not be nullptr.*/ -} PalGraphicsWindow; - /** * @struct PalFormatInfo * @brief Information about a format. This includes the supported image usages and maximum sample @@ -1596,12 +1590,13 @@ typedef struct { PalImageUsages usages; uint32_t width; /**< Width of the image in pixels.*/ uint32_t height; /**< Height of the image in pixels.*/ - uint32_t depthOrArraySize; /**< Depth for 3D image and array size for 2D image.*/ + uint32_t depth; /**< Depth of the image in pixels.*/ + uint32_t arrayLayerCount; uint32_t mipLevelCount; PalSampleCount sampleCount; PalImageType type; /**< 1D, 2D, 3D.*/ PalFormat format; -} PalImageInfo; // TODO: +} PalImageInfo; /** * @struct PalClearValue @@ -1633,26 +1628,13 @@ typedef struct { PalStoreOp storeOp; PalLoadOp stencilLoadOp; PalStoreOp stencilStoreOp; - PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ + PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ + PalResolveMode stencilResolveMode; /**< Used if resolveImageView is set.*/ uint32_t texelWidth; /**< Texel width for fragment shading rate attachment.*/ uint32_t texelHeight; /**< Texel height for fragment shading rate attachment.*/ PalClearValue clearValue; } PalAttachmentDesc; -/** - * @struct PalUsageStateInfo - * @brief Information about resource usage state. This is used with barrier commands. - * - * Uninitialized fields may result in undefined behavior. - * - * @since 2.0 - */ -typedef struct { - PalShaderStage* shaderStages; - uint32_t shaderStageCount; - PalUsageState usageState; -} PalUsageStateInfo; - /** * @struct PalViewport * @brief A viewport in pixels (float). @@ -1688,10 +1670,10 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t supportedMemoryTypes; - uint64_t memoryMask; uint64_t size; uint64_t alignment; + uint32_t supportedMemoryTypes; + uint32_t memoryMask; } PalMemoryRequirements; /** @@ -1849,14 +1831,11 @@ typedef struct { * @struct PalVertexAttribute * @brief Vertex attribute. * - * Uninitialized fields may result in undefined behavior. `semanticName` Must not include the index - * (eg. "position" or "myown"). Set to nullptr to use the default that will be derived from ` - * semanticID` which are (`POSITION`, `COLOR`, `TEXCOORD`, `NORMAL` and `TANGENT`). + * Uninitialized fields may result in undefined behavior. * * @since 2.0 */ typedef struct { - const char* semanticName; PalVertexSemanticID semanticID; PalVertexType type; } PalVertexAttribute; @@ -1988,7 +1967,7 @@ typedef struct { PalBlendFactor srcAlphaBlendFactor; PalBlendFactor dstAlphaBlendFactor; PalBlendOp alphaBlendOp; -} PalColorBlendAttachment; // TODO: +} PalColorBlendAttachment; /** * @struct PalFragmentShadingRateState @@ -2014,11 +1993,11 @@ typedef struct { typedef struct { PalAccelerationStructure* blas; PalAccelerationStructureInstanceFlags flags; - uint32_t instanceId; uint32_t mask; + uint32_t instanceId; uint32_t hitGroupOffset; float transform[12]; /**< row major (3x4).*/ -} PalAccelerationStructureInstance; // TODO: +} PalAccelerationStructureInstance; /** * @struct PalAccelerationStructureBuildSize @@ -2027,9 +2006,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t accelerationStructureSize; - uint32_t scratchBufferSize; - uint32_t updateScratchBufferSize; + uint64_t accelerationStructureSize; + uint64_t scratchBufferSize; + uint64_t updateScratchBufferSize; } PalAccelerationStructureBuildSize; /** @@ -2043,12 +2022,12 @@ typedef struct { typedef struct { PalDeviceAddress vertexBufferAddress; PalDeviceAddress indexBufferAddress; + PalDeviceAddress transformBufferAddress; PalVertexType vertexType; PalIndexType indexType; - uint32_t vertexStride; - uint32_t indexCount; uint32_t vertexCount; -} PalGeometryDataTriangle; // TODO: + uint32_t vertexStride; +} PalGeometryDataTriangle; /** * @struct PalGeometryDataAABBS @@ -2060,8 +2039,8 @@ typedef struct { */ typedef struct { PalDeviceAddress bufferAddress; - uint32_t stride; -} PalGeometryDataAABBS; // TODO: + uint64_t stride; +} PalGeometryDataAABBS; /** * @struct PalGeometry @@ -2073,8 +2052,8 @@ typedef struct { */ typedef struct { void* data; /**< Pointer to geometry data. This will be casted based on the geometry type.*/ + uint64_t primitiveCount; PalGeometryFlags flags; - uint32_t primitiveCount; PalGeometryType type; } PalGeometry; @@ -2095,8 +2074,7 @@ typedef struct { PalAccelerationStructureBuildHints buildHints; PalAccelerationStructureType type; PalAccelerationStructureBuildMode buildMode; - uint32_t geometryCount; - uint32_t instanceCount; + uint32_t count; } PalAccelerationStructureBuildInfo; /** @@ -2137,8 +2115,8 @@ typedef struct { typedef struct { PalBuffer* buffer; uint64_t offset; /**< Offset in bytes. If structured, will be divided by `stride`.*/ - uint32_t size; - uint32_t stride; /**< For structured buffers. Will be ignored if not supported. 0 for default.*/ + uint64_t size; + uint64_t stride; /**< For structured buffers. Will be ignored if not supported. 0 for default.*/ } PalDescriptorBufferInfo; /** @@ -2206,10 +2184,8 @@ typedef struct { * @since 2.0 */ typedef struct { - PalShaderStage* shaderStages; - uint64_t offset; - uint64_t size; - uint64_t shaderStageCount; + uint32_t offset; + uint32_t size; } PalPushConstantRange; /** @@ -2251,6 +2227,7 @@ typedef struct { * @since 2.0 */ typedef struct { + PalImageAspect imageAspect; uint64_t bufferOffset; uint32_t bufferRowLength; uint32_t bufferImageHeight; @@ -2263,7 +2240,6 @@ typedef struct { uint32_t imageWidth; uint32_t imageHeight; uint32_t imageDepth; - PalImageAspect imageAspect; } PalBufferImageCopyInfo; /** @@ -2275,6 +2251,7 @@ typedef struct { * @since 2.0 */ typedef struct { + PalImageAspect aspect; uint32_t dstMipLevel; uint32_t srcMipLevel; uint32_t dstStartArrayLayer; @@ -2289,7 +2266,6 @@ typedef struct { uint32_t width; uint32_t height; uint32_t depth; - PalImageAspect aspect; } PalImageCopyInfo; /** @@ -2334,12 +2310,13 @@ typedef struct { PalImageUsages usages; uint32_t width; uint32_t height; - uint32_t depthOrArraySize; + uint32_t depth; + uint32_t arrayLayerCount; uint32_t mipLevelCount; PalSampleCount sampleCount; PalImageType type; PalFormat format; -} PalImageCreateInfo; // TODO: +} PalImageCreateInfo; /** * @struct PalImageCreateInfo @@ -2410,8 +2387,8 @@ typedef struct { typedef struct { void* bytecode; PalShaderEntryInfo* entries; - uint64_t bytecodeSize; - uint64_t entryCount; + uint32_t bytecodeSize; + uint32_t entryCount; } PalShaderCreateInfo; /** @@ -2440,40 +2417,36 @@ typedef struct { uint64_t offset; uint64_t size; PalAccelerationStructureType type; -} PalAccelerationStructureCreateInfo; // TODO: +} PalAccelerationStructureCreateInfo; /** * @struct PalDescriptorSetLayoutCreateInfo * @brief Creation parameters for a descriptor set layout. * - * Uninitialized fields may result in undefined behavior. Set `enableDescriptorIndexing` to - * `PAL_TRUE` to enable descriptor indexing for the descriptor set layout. + * Uninitialized fields may result in undefined behavior. * * @since 2.0 */ typedef struct { - PalShaderStage* shaderStages; PalDescriptorSetLayoutBinding* bindings; - PalBool enableDescriptorIndexing; + PalDescriptorIndexingFlags descriptorIndexingFlags; uint32_t bindingCount; - uint32_t shaderStageCount; -} PalDescriptorSetLayoutCreateInfo; // TODO: +} PalDescriptorSetLayoutCreateInfo; /** * @struct PalDescriptorPoolCreateInfo * @brief Creation parameters for a descriptor pool. * - * Uninitialized fields may result in undefined behavior. Set `enableDescriptorIndexing` to - * `PAL_TRUE` to enable descriptor indexing for the descriptor pool. + * Uninitialized fields may result in undefined behavior. * * @since 2.0 */ typedef struct { PalDescriptorPoolBindingSize* bindingSizes; - PalBool enableDescriptorIndexing; + uint64_t bindingSizeCount; uint32_t maxDescriptorSets; - uint32_t maxDescriptorBindingSizes; -} PalDescriptorPoolCreateInfo; // TODO: + PalDescriptorIndexingFlags descriptorIndexingFlags; +} PalDescriptorPoolCreateInfo; /** * @struct PalPipelineLayoutCreateInfo @@ -2564,12 +2537,12 @@ typedef struct { PalPipelineLayout* pipelineLayout; PalRayTracingShaderGroupCreateInfo* shaderGroups; PalShader** shaders; + uint64_t shaderGroupCount; uint32_t shaderCount; - uint32_t shaderGroupCount; uint32_t maxRecursionDepth; uint32_t maxAttributeSize; uint32_t maxPayloadSize; -} PalRayTracingPipelineCreateInfo; // TODO: +} PalRayTracingPipelineCreateInfo; /** * @struct PalShaderBindingTableCreateInfo @@ -2930,7 +2903,9 @@ typedef struct { */ PalResult (PAL_CALL *createSurface)( PalDevice* device, - PalGraphicsWindow* window, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, PalSurface** outSurface); /** @@ -3430,8 +3405,8 @@ typedef struct { PalResult (PAL_CALL *cmdAccelerationStructureBarrier)( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); + PalUsageState oldUsageState, + PalUsageState newUsageState); /** * Backend implementation of ::palCmdImageBarrier. @@ -3442,8 +3417,8 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); + PalUsageState oldUsageState, + PalUsageState newUsageState); /** * Backend implementation of ::palCmdBufferBarrier. @@ -3453,8 +3428,8 @@ typedef struct { PalResult (PAL_CALL *cmdBufferBarrier)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); + PalUsageState oldUsageState, + PalUsageState newUsageState); /** * Backend implementation of ::palCmdDispatch. @@ -4755,6 +4730,8 @@ PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); * * @param[in] device Device that creates the surface. * @param[in] window Window to create the surface for. + * @param[in] windowInstance The instance of the window. + * @param[in] instanceType The instance type of the window. * @param[out] outSurface Pointer to a PalSurface to recieve the created surface. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4767,7 +4744,9 @@ PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); */ PAL_API PalResult PAL_CALL palCreateSurface( PalDevice* device, - PalGraphicsWindow* window, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, PalSurface** outSurface); /** @@ -5753,7 +5732,6 @@ PAL_API PalResult PAL_CALL palCmdSetScissors( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] firstSlot Index of the first vertex buffer binding slot. * @param[in] count Number of vertex buffers to bind. - * @param[in] strides Pointer to an array of strides for each vertex buffer. * @param[in] buffers Pointer to an array of vertex buffers. * @param[in] offsets Pointer to an array of offsets in bytes into each vertex buffer. * @@ -5983,9 +5961,9 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * The graphics system must be initialized before this call. This function defines a - * dependency between `oldUsageStateInfo` and `newUsageStateInfo`. It ensures that all - * operations performed under `oldUsageStateInfo` are completed and visible before the acceleration - * structure is accessed under `newUsageStateInfo`. + * dependency between `oldUsageState` and `newUsageState`. It ensures that all + * operations performed under `oldUsageState` are completed and visible before the acceleration + * structure is accessed under `newUsageState`. * * This function does not modify the acceleration structure, it only exforces execution ordering * and acceleration structure memory visibility. @@ -5998,16 +5976,16 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * To make sure BLAS builds before TLAS access it and TLAS does not use scratch buffer * whilst BLAS is buidling, * we put a barrier to transition the BLAS to ensure it has finished building and the scratch - * buffer is not being used. This is expressed with oldUsageStateInfo.usageState being + * buffer is not being used. This is expressed with `oldUsageState` being * `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE`. * - * newUsageStateInfo.usageState should be the new usage state we want after the BLAS - * has finished wbuilding which is `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ`. + * `newUsageState` should be the new usage state we want after the BLAS + * has finished building which is `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] as Acceleration structure to set barrier on. - * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. - * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. + * @param[in] oldUsageState The old usage state. + * @param[in] newUsageState The new usage state. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6023,16 +6001,16 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( PAL_API PalResult PAL_CALL palCmdAccelerationStructureBarrier( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); + PalUsageState oldUsageState, + PalUsageState newUsageState); /** * @brief Transition an image from one usage state to another. * * The graphics system must be initialized before this call. This function defines a - * dependency between `oldUsageStateInfo` and `newUsageStateInfo`. It ensures that all - * operations performed under `oldUsageStateInfo` are completed and visible before the image - * is accessed under `newUsageStateInfo`. + * dependency between `oldUsageState` and `newUsageState`. It ensures that all + * operations performed under `oldUsageState` are completed and visible before the image + * is accessed under `newUsageState`. * * This function does not modify the image, it only exforces execution ordering and image memory * visibility. @@ -6041,18 +6019,17 @@ PAL_API PalResult PAL_CALL palCmdAccelerationStructureBarrier( * * To make sure the an image is ready for presenting after a render pass, * we put a barrier to transition the image to ensure the render pass has finished writing - * to the image. This is expressed with oldUsageStateInfo.usageState being - * `PAL_USAGE_STATE_COLOR_ATTACHMENT` or `PAL_USAGE_STATE_COLOR_ATTACHMENT` or both set - * after each other. + * to the image. This is expressed with `oldUsageState` being + * `PAL_USAGE_STATE_COLOR_ATTACHMENT`. * - * newUsageStateInfo.usageState should be the new usage state we want after the render pass + * `newUsageState` should be the new usage state we want after the render pass * has finished which is `PAL_USAGE_STATE_PRESENT`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] image Image to set barrier on. * @param[in] subresourceRange Subresource range of the image. - * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. - * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. + * @param[in] oldUsageStateInfo The old usage state. + * @param[in] newUsageStateInfo The new usage state. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6067,16 +6044,16 @@ PAL_API PalResult PAL_CALL palCmdImageBarrier( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); + PalUsageState oldUsageState, + PalUsageState newUsageState); /** * @brief Transition a buffer from one usage state to another. * * The graphics system must be initialized before this call. This function defines a - * dependency between `oldUsageStateInfo` and `newUsageStateInfo`. It ensures that all - * operations performed under `oldUsageStateInfo` are completed and visible before the buffer - * is accessed under `newUsageStateInfo`. + * dependency between `oldUsageState` and `newUsageState`. It ensures that all + * operations performed under `oldUsageState` are completed and visible before the buffer + * is accessed under `newUsageState`. * * This function does not modify the buffer, it only exforces execution ordering and buffer memory * visibility. @@ -6085,17 +6062,15 @@ PAL_API PalResult PAL_CALL palCmdImageBarrier( * * To read back data from a buffer that will be written to by a shader, * we put a barrier to transition the buffer to ensurethe shader has finished writing to the - * buffer. This is expressed with oldUsageStateInfo.usageState being `PAL_USAGE_STATE_SHADER_WRITE` - * and optional oldUsageStateInfo.shaderStage set to the shader stage that we will be doing the - * writing. + * buffer. This is expressed with `oldUsageState` being `PAL_USAGE_STATE_SHADER_WRITE`. * - * newUsageStateInfo.usageState should be the new usage state we want after the write + * `newUsageState` should be the new usage state we want after the write * has finished which is`PAL_USAGE_STATE_TRANSFER_READ`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer to set barrier on. - * @param[in] oldUsageStateInfo Pointer to a PalUsageStateInfo specifying the old usage state. - * @param[in] newUsageStateInfo Pointer to a PalUsageStateInfo specifying the new usage state. + * @param[in] oldUsageStateInfo The old usage state. + * @param[in] newUsageStateInfo The new usage state. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6109,8 +6084,8 @@ PAL_API PalResult PAL_CALL palCmdImageBarrier( PAL_API PalResult PAL_CALL palCmdBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); + PalUsageState oldUsageState, + PalUsageState newUsageState); /** * @brief Dispatch compute shader workgroups. @@ -6805,11 +6780,6 @@ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); * * The graphics system must be initialized before this call. * - * Set PalDescriptorSetLayoutCreateInfo::enableDescriptorIndexing to true to enable - * descriptor indexing on the descriptor set layout. `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` - * must be supported and enabled when creating the device if not, this function will fail and - * return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * * This defines the layout, ordering and the number of descriptors a descriptor set uses. * * The layouts should reflect the exact layout of the shaders. Eg. @@ -6856,11 +6826,6 @@ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layo * @brief Create a descriptor pool to allocate descriptor sets. * * The graphics system must be initialized before this call. - * - * Set PalDescriptorPoolCreateInfo::enableDescriptorIndexing to true to enable - * descriptor indexing on the descriptor pool. `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` - * must be supported and enabled when creating the device if not, this function will fail and - * return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device that creates the descriptor pool. * @param[in] info Pointer to a PalDescriptorPoolCreateInfo struct that specifies parameters. @@ -6950,11 +6915,6 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( * must be supported and enabled when creating the device if not, this function will fail and * return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * - * Set PalDescriptorPoolCreateInfo::enableDescriptorIndexing to true to enable - * descriptor indexing on the descriptor pool. `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` - * must be supported and enabled when creating the device if not, this function will fail and - * return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * * @param[in] device The Device. Must match the one used to allocate descriptor set. * @param[in] count Capacity of the PalDescriptorSetWriteInfo array. * @param[in] infos Array of PalDescriptorSetWriteInfo to write. diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 23700f05..642abb78 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -65,22 +65,22 @@ #define PAL_ORIENTATION_PORTRAIT_FLIPPED 3 #define PAL_ORIENTATION_COUNT 4 -#define PAL_WINDOW_STYLE_RESIZABLE (1ULL << 0) -#define PAL_WINDOW_STYLE_TRANSPARENT (1ULL << 1) -#define PAL_WINDOW_STYLE_TOPMOST (1ULL << 2) -#define PAL_WINDOW_STYLE_NO_MINIMIZEBOX (1ULL << 3) -#define PAL_WINDOW_STYLE_NO_MAXIMIZEBOX (1ULL << 4) -#define PAL_WINDOW_STYLE_TOOL (1ULL << 5) -#define PAL_WINDOW_STYLE_BORDERLESS (1ULL << 6) +#define PAL_WINDOW_STYLE_RESIZABLE (1U << 0) +#define PAL_WINDOW_STYLE_TRANSPARENT (1U << 1) +#define PAL_WINDOW_STYLE_TOPMOST (1U << 2) +#define PAL_WINDOW_STYLE_NO_MINIMIZEBOX (1U << 3) +#define PAL_WINDOW_STYLE_NO_MAXIMIZEBOX (1U << 4) +#define PAL_WINDOW_STYLE_TOOL (1U << 5) +#define PAL_WINDOW_STYLE_BORDERLESS (1U << 6) #define PAL_WINDOW_STATE_MAXIMIZED 0 #define PAL_WINDOW_STATE_MINIMIZED 1 #define PAL_WINDOW_STATE_RESTORED 2 #define PAL_WINDOW_STATE_COUNT 3 -#define PAL_FLASH_STOP 0 /**< Stop flashing.*/ -#define PAL_FLASH_CAPTION (1ULL << 0) /**< Flash the titlebar of the window.*/ -#define PAL_FLASH_TRAY (1ULL << 1) /**< Flash the icon of the window.*/ +#define PAL_FLASH_STOP 0 /**< Stop flashing.*/ +#define PAL_FLASH_CAPTION (1U << 0) /**< Flash the titlebar of the window.*/ +#define PAL_FLASH_TRAY (1U << 1) /**< Flash the icon of the window.*/ #define PAL_CONFIG_BACKEND_PAL_OPENGL 0 /**< Use PAL opengl module backend.*/ #define PAL_CONFIG_BACKEND_EGL 1 @@ -397,7 +397,7 @@ typedef uint32_t PalOrientation; * * @since 1.0 */ -typedef uint64_t PalWindowStyle; +typedef uint32_t PalWindowStyle; /** * @typedef PalWindowState @@ -422,7 +422,7 @@ typedef uint32_t PalWindowState; * * @since 1.0 */ -typedef uint64_t PalFlashFlag; +typedef uint32_t PalFlashFlag; /** * @typedef PalFBConfigBackend @@ -519,7 +519,7 @@ typedef struct { * @since 1.0 */ typedef struct { - PalFlashFlag flags; /**< See PalFlashFlag.*/ + PalFlashFlag flags; uint32_t interval; /**< In milliseconds. Set to 0 for default.*/ uint32_t count; /**< Set to 0 to flash until focused or cancelled.*/ } PalFlashInfo; @@ -577,7 +577,6 @@ typedef struct { * @since 1.0 */ typedef struct { - PalWindowStyle style; /**< Window style.*/ const char* title; /**< Title in UTF-8 encoding.*/ PalMonitor* monitor; /**< Set to nullptr to use primary monitor.*/ const char* appName; /**< If nullptr, `PAL` will be used.*/ @@ -587,8 +586,8 @@ typedef struct { uint32_t width; /**< Width in pixels.*/ uint32_t height; /**< Width in pixels.*/ PalBool show; /**< Show after creation.*/ - PalBool maximized; /**< Maximize after creation.*/ - PalBool minimized; /**< Minimze after creation.*/ + PalWindowStyle style; /**< Window style.*/ + PalWindowState state; PalBool center; /**< Center after creation.*/ } PalWindowCreateInfo; diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 0d6daaea..0180be19 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -3682,7 +3682,7 @@ PalResult PAL_CALL mapImageMemoryD3D12( uint64_t size, void** outPtr) { - return PAL_RESULT_MEMORY_MAP_FAILED; + return PAL_RESULT_INVALID_OPERATION; } void PAL_CALL unmapImageMemoryD3D12(PalImage* image) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index 20270255..a07de74d 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -5448,6 +5448,8 @@ PalResult PAL_CALL getImageMemoryRequirementsVk( return PAL_RESULT_INVALID_OPERATION; } + // TODO: support only GPU memory + Device* device = vkImage->device; VkMemoryRequirements memReq = {0}; s_Vk.getImageMemoryRequirements(device->handle, vkImage->handle, &memReq); @@ -5492,25 +5494,12 @@ PalResult PAL_CALL mapImageMemoryVk( uint64_t size, void** outPtr) { - VkResult result; - Image* vkImage = (Image*)image; - Device* device = vkImage->device; - - if (vkImage->memory->type == PAL_MEMORY_TYPE_GPU_ONLY) { - return PAL_RESULT_MEMORY_MAP_FAILED; - } - - result = s_Vk.mapMemory(device->handle, vkImage->memory->handle, offset, size, 0, outPtr); - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - return PAL_RESULT_SUCCESS; + return PAL_RESULT_INVALID_OPERATION; } void PAL_CALL unmapImageMemoryVk(PalImage* image) { - Image* vkImage = (Image*)image; - s_Vk.unmapMemory(vkImage->device->handle, vkImage->memory->handle); + // do nothing. } // ================================================== diff --git a/src/video/linux/wayland/pal_window_wayland.c b/src/video/linux/wayland/pal_window_wayland.c index d5cb5909..8b0083e2 100644 --- a/src/video/linux/wayland/pal_window_wayland.c +++ b/src/video/linux/wayland/pal_window_wayland.c @@ -244,8 +244,6 @@ PalResult wlCreateWindow( // to a surface without taking control from users // we might implement a simple hash map to do that // but at the moment a linear search is fine - // FIXME: Implement a window hash map - data->skipState = PAL_FALSE; data->skipConfigure = PAL_FALSE; *outWindow = data->window; From eec4466746b6a93766734d9c0e57477c494dc17c Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 23 Jun 2026 16:34:43 +0000 Subject: [PATCH 292/372] add internal incremental graphics vtable --- include/pal/pal_graphics.h | 141 +- src/graphics/pal_backends_graphics.h | 1759 +++++++++++++++ src/graphics/pal_graphics.c | 2952 ++++++-------------------- src/graphics/pal_graphics_vtable.h | 611 ++++++ 4 files changed, 3134 insertions(+), 2329 deletions(-) create mode 100644 src/graphics/pal_backends_graphics.h create mode 100644 src/graphics/pal_graphics_vtable.h diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index be5ef399..211196b6 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -21,6 +21,9 @@ #define PAL_SHADER_ENTRY_NAME_SIZE 32 #define PAL_UNUSED_SHADER_INDEX UINT32_MAX +#define PAL_BACKEND_KEY ((void*)(uintptr_t)0x50414C48414E4453) +#define PAL_MAX_CUSTOM_BACKENDS 16 + #define PAL_MAKE_SHADER_TARGET(major, minor) ((uint32_t)((major) << 8) | (minor)) #define PAL_SHADER_TARGET_MAJOR(target) ((uint32_t)(target) >> 8); #define PAL_SHADER_TARGET_MINOR(target) ((uint32_t)(target) & 0xFF); @@ -445,6 +448,8 @@ #define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CU_DISABLE (1U << 2) #define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE (1U << 3) +#define ePAL_ACCELERATION_STRUCTURE_CREATE_FLAG_NONE 0 + #define PAL_GEOMETRY_TYPE_TRIANGLE 0 #define PAL_GEOMETRY_TYPE_AABBS 1 #define PAL_GEOMETRY_TYPE_COUNT 2 @@ -523,6 +528,18 @@ #define PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT 2 #define PAL_RAY_TRACING_SHADER_GROUP_TYPE_COUNT 3 +#define PAL_BUFFER_MEMORY_USAGE_MANUAL 0 +#define PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY 1 +#define PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD 2 +#define PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK 3 +#define PAL_BUFFER_MEMORY_USAGE_COUNT 4 + +#define PAL_IMAGE_MEMORY_USAGE_MANUAL 0 +#define PAL_IMAGE_MEMORY_USAGE_AUTO_GPU_ONLY 1 +#define PAL_IMAGE_MEMORY_USAGE_COUNT 2 + +#define PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1 0 + /** * @struct PalAdapter * @brief Opaque handle to an adapter (GPU). @@ -1195,6 +1212,18 @@ typedef uint32_t PalFragmentShadingRateCombinerOp; */ typedef uint32_t PalAccelerationStructureType; +/** + * @typedef PalAccelerationStructureCreateFlags + * @brief Acceleration structure create flags. Multiple hints can be OR'ed together using + * bitwise OR operator (`|`). + * + * All acceleration structure create flags follow the format `PAL_ACCELERATION_STRUCTURE_CREATE_FLAG_**` + * for consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalAccelerationStructureCreateFlags; + /** * @typedef PalAccelerationStructureBuildMode * @brief Acceleration structure build modes. @@ -1314,6 +1343,39 @@ typedef uint32_t PalRayTracingShaderGroupType; */ typedef uint32_t PalDescriptorIndexingFlags; +/** + * @typedef PalBufferMemoryUsage + * @brief Buffer memory usages. + * + * All buffer memory usages follow the format `PAL_BUFFER_MEMORY_USAGE_**` + * for consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalBufferMemoryUsage; + +/** + * @typedef PalImageMemoryUsage + * @brief Image memory usages. + * + * All image memory usages follow the format `PAL_IMAGE_MEMORY_USAGE_**` + * for consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalImageMemoryUsage; + +/** + * @typedef PalGraphicsBackendVtableVersion + * @brief Graphics backend vtable versions. + * + * All graphics backend vtable versions follow the format `PAL_GRAPHICS_BACKEND_VTABLE_VERSION_**` + * for consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalGraphicsBackendVtableVersion; + /** * @typedef PalDebugCallback * @brief Function pointer type used for debug callbacks. @@ -2316,6 +2378,7 @@ typedef struct { PalSampleCount sampleCount; PalImageType type; PalFormat format; + PalImageMemoryUsage memoryUsage; } PalImageCreateInfo; /** @@ -2400,8 +2463,9 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBufferUsages usages; uint64_t size; + PalBufferUsages usages; + PalBufferMemoryUsage memoryUsage; } PalBufferCreateInfo; /** @@ -2417,6 +2481,7 @@ typedef struct { uint64_t offset; uint64_t size; PalAccelerationStructureType type; + PalAccelerationStructureCreateFlags createFlags; } PalAccelerationStructureCreateInfo; /** @@ -2559,10 +2624,31 @@ typedef struct { } PalShaderBindingTableCreateInfo; /** - * @struct PalGraphicsBackend - * @brief Dispatch table for PAL graphics system backends. + * @struct PalGraphicsBackendRegistrationInfo + * @brief Registration info of a graphics backend. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 2.0 + */ +typedef struct { + const void* vtable; + PalGraphicsBackendVtableVersion version; +} PalGraphicsBackendInfo; + +/** + * @struct PalGraphicsBackendVtable1 + * @brief Version 1 dispatch table for PAL graphics system backends. * * Uninitialized fields may result in undefined behavior. + * + * All backend handle implementation (eg. struct CustomBuffer) must reserve its first field as + * a `void*` and set it to `PAL_BACKEND_KEY` at the handles creation function pointer + * (eg. createBufferCustom). This will be validated at the handle creation function + * (eg. palCreateBuffer). + * + * Pal trust thee backend author to not overwrite or use the reserve space. It is used by the + * graphics layer. * * @since 2.0 */ @@ -3846,54 +3932,28 @@ typedef struct { PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos); -} PalGraphicsBackend; - -/** - * @brief Add a custom graphics backend to the graphics system. - * - * The graphics system must not be initialized before this call. If already initialized, - * the system should be shutdown and re-initialized after this call. - * The graphics system supports 16 custom backends. - * - * The `backend` dispatch table must have its function pointers all set even if a - * function will not be used. If a feature is not supported by the backend, - * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED` must be returned by the appropriate function. - * If any of the function pointers are not set, this function will fail and - * `PAL_RESULT_INVALID_BACKEND` will be returned. - * - * The backend will not not copied, therefore the pointer must remain valid - * until the graphics system is shutdown. - * - * @param[in] backend Pointer to the backend dispatch table to add. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Must only be called from the main thread. - * - * @since 2.0 - * @sa palInitGraphics - * @sa palShutdownGraphics - */ -PAL_API PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend); +} PalGraphicsBackendVtable1; /** * @brief Initialize the graphics system. * - * Any custom backends added with palAddGraphicsBackend() will be registered with the - * graphics system. The graphics system must be shutdown with palShutdownGraphics() when no longer - * needed. - * - * The debugger and allocator will not not copied, therefore the pointers must remain valid + * The debugger, allocator and custom backends will not not copied, therefore the pointers must remain valid * until the graphics system is shutdown. Set the debugger or PalGraphicsDebugger::callback to * nullptr to disable debugging and validation layers. * * If `debugger` is not nullptr and there is no debug layers, this function will not fail but * debugging will be disabled. + * + * All backends must have their vtable functions fully set according to the version requirements. + * If a feature is not supported by a backend, `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED` must be + * returned by the appropriate function. This is validated at initialization and will fail and return + * `PAL_RESULT_INVALID_ARGUMENT`. * * @param[in] debugger Optional debugger. Set to nullptr to disable debugging and validation * layers. * @param[in] allocator Optional user-provided allocator. Set to nullptr to use default. + * @param[in] customBackendCount The number of custom backends in `customBackends`. + * @param[in] customBackends Pointer to an array of custom backends. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -3901,12 +3961,13 @@ PAL_API PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backe * Thread safety: Must only be called from the main thread. * * @since 2.0 - * @sa palAddGraphicsBackend * @sa palShutdownGraphics */ PAL_API PalResult PAL_CALL palInitGraphics( const PalGraphicsDebugger* debugger, - const PalAllocator* allocator); + const PalAllocator* allocator, + uint32_t customBackendCount, + const PalGraphicsBackendInfo* customBackends); /** * @brief Shutdown the graphics system. diff --git a/src/graphics/pal_backends_graphics.h b/src/graphics/pal_backends_graphics.h new file mode 100644 index 00000000..593d3372 --- /dev/null +++ b/src/graphics/pal_backends_graphics.h @@ -0,0 +1,1759 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_BACKENDS_GRAPHICS_H +#define _PAL_BACKENDS_GRAPHICS_H + +#include "pal_graphics_vtable.h" + +// ================================================== +// Vulkan +// ================================================== + +PalResult PAL_CALL initGraphicsVk( + const PalGraphicsDebugger* debugger, + const PalAllocator* allocator); + +void PAL_CALL shutdownGraphicsVk(); + +PalResult PAL_CALL enumerateAdaptersVk( + int32_t* count, + PalAdapter** outAdapters); + +PalResult PAL_CALL getAdapterInfoVk( + PalAdapter* adapter, + PalAdapterInfo* info); + +PalResult PAL_CALL getAdapterCapabilitiesVk( + PalAdapter* adapter, + PalAdapterCapabilities* caps); + +PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter); + +uint32_t PAL_CALL getHighestSupportedShaderTargetVk( + PalAdapter* adapter, + PalShaderFormats shaderFormat); + +// ================================================== +// Device +// ================================================== + +PalResult PAL_CALL createDeviceVk( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); + +void PAL_CALL destroyDeviceVk(PalDevice* device); + +PalResult PAL_CALL waitDeviceVk(PalDevice* device); + +// ================================================== +// Memory +// ================================================== + +PalResult PAL_CALL allocateMemoryVk( + PalDevice* device, + PalMemoryType type, + uint64_t memoryMask, + uint64_t size, + PalMemory** outMemory); + +void PAL_CALL freeMemoryVk( + PalDevice* device, + PalMemory* memory); + +// ================================================== +// Extended Adapter Features +// ================================================== + +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps); + +PalResult PAL_CALL queryMultiViewCapabilitiesVk( + PalDevice* device, + PalMultiViewCapabilities* caps); + +PalResult PAL_CALL queryMultiViewportCapabilitiesVk( + PalDevice* device, + PalMultiViewportCapabilities* caps); + +PalResult PAL_CALL queryDepthStencilCapabilitiesVk( + PalDevice* device, + PalDepthStencilCapabilities* caps); + +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); + +PalResult PAL_CALL queryMeshShaderCapabilitiesVk( + PalDevice* device, + PalMeshShaderCapabilities* caps); + +PalResult PAL_CALL queryRayTracingCapabilitiesVk( + PalDevice* device, + PalRayTracingCapabilities* caps); + +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); + +// ================================================== +// Queue +// ================================================== + +PalResult PAL_CALL createQueueVk( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); + +void PAL_CALL destroyQueueVk(PalQueue* queue); + +PalResult PAL_CALL waitQueueVk(PalQueue* queue); + +PalBool PAL_CALL canQueuePresentVk( + PalQueue* queue, + PalSurface* surface); + +// ================================================== +// Formats +// ================================================== + +PalResult PAL_CALL enumerateFormatsVk( + PalAdapter* adapter, + int32_t* count, + PalFormatInfo* outFormats); + +PalBool PAL_CALL isFormatSupportedVk( + PalAdapter* adapter, + PalFormat format); + +PalImageUsages PAL_CALL queryFormatImageUsagesVk( + PalAdapter* adapter, + PalFormat format); + +PalSampleCount PAL_CALL queryFormatSampleCountVk( + PalAdapter* adapter, + PalFormat format); + +// ================================================== +// Image +// ================================================== + +PalResult PAL_CALL createImageVk( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + +void PAL_CALL destroyImageVk(PalImage* image); + +PalResult PAL_CALL getImageInfoVk( + PalImage* image, + PalImageInfo* info); + +PalResult PAL_CALL getImageMemoryRequirementsVk( + PalImage* image, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL bindImageMemoryVk( + PalImage* image, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL mapImageMemoryVk( + PalImage* image, + uint64_t offset, + uint64_t size, + void** outPtr); + +void PAL_CALL unmapImageMemoryVk(PalImage* image); + +// ================================================== +// Image View +// ================================================== + +PalResult PAL_CALL createImageViewVk( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + +void PAL_CALL destroyImageViewVk(PalImageView* imageView); + +// ================================================== +// Sampler +// ================================================== + +PalResult PAL_CALL createSamplerVk( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler); + +void PAL_CALL destroySamplerVk(PalSampler* sampler); + +// ================================================== +// Surface +// ================================================== + +PalResult PAL_CALL createSurfaceVk( + PalDevice* device, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, + PalSurface** outSurface); + +void PAL_CALL destroySurfaceVk(PalSurface* surface); + +PalResult PAL_CALL getSurfaceCapabilitiesVk( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps); + +// ================================================== +// Swapchain +// ================================================== + +PalResult PAL_CALL createSwapchainVk( + PalDevice* device, + PalQueue* queue, + PalSurface* surface, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + +void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain); + +PalImage* PAL_CALL getSwapchainImageVk( + PalSwapchain* swapchain, + int32_t index); + +PalResult PAL_CALL getNextSwapchainImageVk( + PalSwapchain* swapchain, + PalSwapchainNextImageInfo* info, + uint32_t* outIndex); + +PalResult PAL_CALL presentSwapchainVk( + PalSwapchain* swapchain, + PalSwapchainPresentInfo* info); + +PalResult PAL_CALL resizeSwapchainVk( + PalSwapchain* swapchain, + uint32_t newWidth, + uint32_t newHeight); + +// ================================================== +// Shader +// ================================================== + +PalResult PAL_CALL createShaderVk( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + +void PAL_CALL destroyShaderVk(PalShader* shader); + +// ================================================== +// Fence +// ================================================== + +PalResult PAL_CALL createFenceVk( + PalDevice* device, + PalBool signaled, + PalFence** outFence); + +void PAL_CALL destroyFenceVk(PalFence* fence); + +PalResult PAL_CALL waitFenceVk( + PalFence* fence, + uint64_t timeout); + +PalResult PAL_CALL resetFenceVk(PalFence* fence); + +PalBool PAL_CALL isFenceSignaledVk(PalFence* fence); + +// ================================================== +// Semaphore +// ================================================== + +PalResult PAL_CALL createSemaphoreVk( + PalDevice* device, + PalBool enableTimeline, + PalSemaphore** outSemaphore); + +void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore); + +PalResult PAL_CALL waitSemaphoreVk( + PalSemaphore* semaphore, + uint64_t value, + uint64_t timeout); + +PalResult PAL_CALL signalSemaphoreVk( + PalSemaphore* semaphore, + PalQueue* queue, + uint64_t value); + +PalResult PAL_CALL getSemaphoreValueVk( + PalSemaphore* semaphore, + uint64_t* outValue); + +// ================================================== +// Command Pool And Buffer +// ================================================== + +PalResult PAL_CALL createCommandPoolVk( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool); + +void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool); + +PalResult PAL_CALL resetCommandPoolVk(PalCommandPool* pool); + +PalResult PAL_CALL allocateCommandBufferVk( + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outCmdBuffer); + +void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL submitCommandBufferVk( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + +// ================================================== +// Command Recording +// ================================================== + +PalResult PAL_CALL cmdBeginVk( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info); + +PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdExecuteCommandBufferVk( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + +PalResult PAL_CALL cmdSetFragmentShadingRateVk( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + +PalResult PAL_CALL cmdDrawMeshTasksVk( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t drawCount); + +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +PalResult PAL_CALL cmdBuildAccelerationStructureVk( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); + +PalResult PAL_CALL cmdBeginRenderingVk( + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info); + +PalResult PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdCopyBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyBufferToImageVk( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageVk( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageToBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdBindPipelineVk( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline); + +PalResult PAL_CALL cmdSetViewportVk( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalViewport* viewports); + +PalResult PAL_CALL cmdSetScissorsVk( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalRect2D* scissors); + +PalResult PAL_CALL cmdBindVertexBuffersVk( + PalCommandBuffer* cmdBuffer, + uint32_t firstSlot, + uint32_t count, + PalBuffer** buffers, + uint64_t* offsets); + +PalResult PAL_CALL cmdBindIndexBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint64_t offset, + PalIndexType type); + +PalResult PAL_CALL cmdDrawVk( + PalCommandBuffer* cmdBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + +PalResult PAL_CALL cmdDrawIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + +PalResult PAL_CALL cmdDrawIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +PalResult PAL_CALL cmdDrawIndexedVk( + PalCommandBuffer* cmdBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + +PalResult PAL_CALL cmdDrawIndexedIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + +PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +PalResult PAL_CALL cmdAccelerationStructureBarrierVk( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PalResult PAL_CALL cmdImageBarrierVk( + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PalResult PAL_CALL cmdBufferBarrierVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PalResult PAL_CALL cmdDispatchVk( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +PalResult PAL_CALL cmdDispatchBaseVk( + PalCommandBuffer* cmdBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +PalResult PAL_CALL cmdDispatchIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer); + +PalResult PAL_CALL cmdTraceRaysVk( + PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth); + +PalResult PAL_CALL cmdTraceRaysIndirectVk( + PalCommandBuffer* cmdBuffer, + uint32_t raygenIndex, + PalShaderBindingTable* sbt, + PalBuffer* buffer); + +PalResult PAL_CALL cmdBindDescriptorSetVk( + PalCommandBuffer* cmdBuffer, + uint32_t setIndex, + PalDescriptorSet* set); + +PalResult PAL_CALL cmdPushConstantsVk( + PalCommandBuffer* cmdBuffer, + uint32_t shaderStageCount, + PalShaderStage* shaderStages, + uint32_t offset, + uint32_t size, + const void* value); + +PalResult PAL_CALL cmdSetCullModeVk( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + +PalResult PAL_CALL cmdSetFrontFaceVk( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + +PalResult PAL_CALL cmdSetPrimitiveTopologyVk( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + +PalResult PAL_CALL cmdSetDepthTestEnableVk( + PalCommandBuffer* cmdBuffer, + PalBool enable); + +PalResult PAL_CALL cmdSetDepthWriteEnableVk( + PalCommandBuffer* cmdBuffer, + PalBool enable); + +PalResult PAL_CALL cmdSetStencilOpVk( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); + +// ================================================== +// Acceleration Structure +// ================================================== + +PalResult PAL_CALL createAccelerationstructureVk( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + +void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as); + +PalResult PAL_CALL getAccelerationStructureBuildSizeVk( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + +// ================================================== +// Buffer +// ================================================== + +PalResult PAL_CALL createBufferVk( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + +void PAL_CALL destroyBufferVk(PalBuffer* buffer); + +PalResult PAL_CALL getBufferMemoryRequirementsVk( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL computeInstanceBufferRequirementsVk( + PalDevice* device, + uint32_t instanceCount, + uint64_t* outSize); + +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( + PalDevice* device, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo, + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize); + +PalResult PAL_CALL writeToInstanceBufferVk( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + uint32_t instanceCount); + +PalResult PAL_CALL writeToImageCopyStagingBufferVk( + PalDevice* device, + void* ptr, + void* srcData, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL bindBufferMemoryVk( + PalBuffer* buffer, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL mapBufferMemoryVk( + PalBuffer* buffer, + uint64_t offset, + uint64_t size, + void** outPtr); + +void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer); + +PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer); + +// ================================================== +// Descriptor Pool, Set and Layout +// ================================================== + +PalResult PAL_CALL createDescriptorSetLayoutVk( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + +void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout); + +PalResult PAL_CALL createDescriptorPoolVk( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + +void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool); + +PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool); + +PalResult PAL_CALL allocateDescriptorSetVk( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + +PalResult PAL_CALL updateDescriptorSetVk( + PalDevice* device, + uint32_t count, + PalDescriptorSetWriteInfo* infos); + +// ================================================== +// Pipeline Layout +// ================================================== + +PalResult PAL_CALL createPipelineLayoutVk( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + +void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout); + +// ================================================== +// Pipeline +// ================================================== + +PalResult PAL_CALL createGraphicsPipelineVk( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createComputePipelineVk( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createRayTracingPipelineVk( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + +void PAL_CALL destroyPipelineVk(PalPipeline* pipeline); + +// ================================================== +// Shader Binding Table +// ================================================== + +PalResult PAL_CALL createShaderBindingTableVk( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + +void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt); + +PalResult PAL_CALL updateShaderBindingTableVk( + PalShaderBindingTable* sbt, + uint32_t count, + PalShaderBindingTableRecordInfo* infos); + +static PalGraphicsVtable s_VkBackend = { + // adapter + .enumerateAdapters = enumerateAdaptersVk, + .getAdapterInfo = getAdapterInfoVk, + .getAdapterCapabilities = getAdapterCapabilitiesVk, + .getAdapterFeatures = getAdapterFeaturesVk, + .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetVk, + + // device + .createDevice = createDeviceVk, + .destroyDevice = destroyDeviceVk, + + // memory + .allocateMemory = allocateMemoryVk, + .freeMemory = freeMemoryVk, + + // extended adapter features + .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesVk, + .queryMultiViewCapabilities = queryMultiViewCapabilitiesVk, + .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesVk, + .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesVk, + .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesVk, + .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesVk, + .queryRayTracingCapabilities = queryRayTracingCapabilitiesVk, + .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesVk, + + // queue + .createQueue = createQueueVk, + .destroyQueue = destroyQueueVk, + .waitQueue = waitQueueVk, + .canQueuePresent = canQueuePresentVk, + + // format + .enumerateFormats = enumerateFormatsVk, + .isFormatSupported = isFormatSupportedVk, + .queryFormatImageUsages = queryFormatImageUsagesVk, + .queryFormatSampleCount = queryFormatSampleCountVk, + + // image + .createImage = createImageVk, + .destroyImage = destroyImageVk, + .getImageInfo = getImageInfoVk, + .getImageMemoryRequirements = getImageMemoryRequirementsVk, + .bindImageMemory = bindImageMemoryVk, + .mapImageMemory = mapImageMemoryVk, + .unmapImageMemory = unmapImageMemoryVk, + + // image view + .createImageView = createImageViewVk, + .destroyImageView = destroyImageViewVk, + + // sampler + .createSampler = createSamplerVk, + .destroySampler = destroySamplerVk, + + // surface + .createSurface = createSurfaceVk, + .destroySurface = destroySurfaceVk, + .getSurfaceCapabilities = getSurfaceCapabilitiesVk, + + // swapchain + .createSwapchain = createSwapchainVk, + .destroySwapchain = destroySwapchainVk, + .getSwapchainImage = getSwapchainImageVk, + .getNextSwapchainImage = getNextSwapchainImageVk, + .presentSwapchain = presentSwapchainVk, + .resizeSwapchain = resizeSwapchainVk, + + // shader + .createShader = createShaderVk, + .destroyShader = destroyShaderVk, + + // fence + .createFence = createFenceVk, + .destroyFence = destroyFenceVk, + .waitFence = waitFenceVk, + .resetFence = resetFenceVk, + .isFenceSignaled = isFenceSignaledVk, + + // semaphore + .createSemaphore = createSemaphoreVk, + .destroySemaphore = destroySemaphoreVk, + .waitSemaphore = waitSemaphoreVk, + .signalSemaphore = signalSemaphoreVk, + .getSemaphoreValue = getSemaphoreValueVk, + + // command pool and command buffer + .createCommandPool = createCommandPoolVk, + .destroyCommandPool = destroyCommandPoolVk, + .resetCommandPool = resetCommandPoolVk, + .allocateCommandBuffer = allocateCommandBufferVk, + .freeCommandBuffer = freeCommandBufferVk, + .resetCommandBuffer = resetCommandBufferVk, + .submitCommandBuffer = submitCommandBufferVk, + + // command recording + .cmdBegin = cmdBeginVk, + .cmdEnd = cmdEndVk, + .cmdExecuteCommandBuffer = cmdExecuteCommandBufferVk, + .cmdSetFragmentShadingRate = cmdSetFragmentShadingRateVk, + .cmdDrawMeshTasks = cmdDrawMeshTasksVk, + .cmdDrawMeshTasksIndirect = cmdDrawMeshTasksIndirectVk, + .cmdDrawMeshTasksIndirectCount = cmdDrawMeshTasksIndirectCountVk, + .cmdBuildAccelerationStructure = cmdBuildAccelerationStructureVk, + .cmdBeginRendering = cmdBeginRenderingVk, + .cmdEndRendering = cmdEndRenderingVk, + .cmdCopyBuffer = cmdCopyBufferVk, + .cmdCopyBufferToImage = cmdCopyBufferToImageVk, + .cmdCopyImage = cmdCopyImageVk, + .cmdCopyImageToBuffer = cmdCopyImageToBufferVk, + .cmdBindPipeline = cmdBindPipelineVk, + .cmdSetViewport = cmdSetViewportVk, + .cmdSetScissors = cmdSetScissorsVk, + .cmdBindVertexBuffers = cmdBindVertexBuffersVk, + .cmdBindIndexBuffer = cmdBindIndexBufferVk, + .cmdDraw = cmdDrawVk, + .cmdDrawIndirect = cmdDrawIndirectVk, + .cmdDrawIndirectCount = cmdDrawIndirectCountVk, + .cmdDrawIndexed = cmdDrawIndexedVk, + .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectVk, + .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountVk, + .cmdAccelerationStructureBarrier = cmdAccelerationStructureBarrierVk, + .cmdImageBarrier = cmdImageBarrierVk, + .cmdBufferBarrier = cmdBufferBarrierVk, + .cmdDispatch = cmdDispatchVk, + .cmdDispatchBase = cmdDispatchBaseVk, + .cmdDispatchIndirect = cmdDispatchIndirectVk, + .cmdTraceRays = cmdTraceRaysVk, + .cmdTraceRaysIndirect = cmdTraceRaysIndirectVk, + .cmdBindDescriptorSet = cmdBindDescriptorSetVk, + .cmdPushConstants = cmdPushConstantsVk, + .cmdSetCullMode = cmdSetCullModeVk, + .cmdSetFrontFace = cmdSetFrontFaceVk, + .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyVk, + .cmdSetDepthTestEnable = cmdSetDepthTestEnableVk, + .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableVk, + .cmdSetStencilOp = cmdSetStencilOpVk, + + // acceleration structure + .createAccelerationstructure = createAccelerationstructureVk, + .destroyAccelerationstructure = destroyAccelerationstructureVk, + .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeVk, + + // buffer + .createBuffer = createBufferVk, + .destroyBuffer = destroyBufferVk, + .getBufferMemoryRequirements = getBufferMemoryRequirementsVk, + .computeInstanceBufferRequirements = computeInstanceBufferRequirementsVk, + .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsVk, + .writeToInstanceBuffer = writeToInstanceBufferVk, + .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferVk, + .bindBufferMemory = bindBufferMemoryVk, + .getBufferDeviceAddress = getBufferDeviceAddressVk, + .mapBufferMemory = mapBufferMemoryVk, + .unmapBufferMemory = unmapBufferMemoryVk, + + // descriptor set layout, descriptor pool and descriptor set + .createDescriptorSetLayout = createDescriptorSetLayoutVk, + .destroyDescriptorSetLayout = destroyDescriptorSetLayoutVk, + .createDescriptorPool = createDescriptorPoolVk, + .destroyDescriptorPool = destroyDescriptorPoolVk, + .resetDescriptorPool = resetDescriptorPoolVk, + .allocateDescriptorSet = allocateDescriptorSetVk, + .updateDescriptorSet = updateDescriptorSetVk, + + // pipeline layout + .createPipelineLayout = createPipelineLayoutVk, + .destroyPipelineLayout = destroyPipelineLayoutVk, + + // pipeline + .createGraphicsPipeline = createGraphicsPipelineVk, + .createComputePipeline = createComputePipelineVk, + .createRayTracingPipeline = createRayTracingPipelineVk, + .destroyPipeline = destroyPipelineVk, + + // shader binding table + .createShaderBindingTable = createShaderBindingTableVk, + .destroyShaderBindingTable = destroyShaderBindingTableVk, + .updateShaderBindingTable = updateShaderBindingTableVk}; + +// ================================================== +// D3D12 +// ================================================== + +PalResult PAL_CALL initGraphicsD3D12( + const PalGraphicsDebugger* debugger, + const PalAllocator* allocator); + +void PAL_CALL shutdownGraphicsD3D12(); + +PalResult PAL_CALL enumerateAdaptersD3D12( + int32_t* count, + PalAdapter** outAdapters); + +PalResult PAL_CALL getAdapterInfoD3D12( + PalAdapter* adapter, + PalAdapterInfo* info); + +PalResult PAL_CALL getAdapterCapabilitiesD3D12( + PalAdapter* adapter, + PalAdapterCapabilities* caps); + +PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); + +uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( + PalAdapter* adapter, + PalShaderFormats shaderFormat); + +// ================================================== +// Device +// ================================================== + +PalResult PAL_CALL createDeviceD3D12( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); + +void PAL_CALL destroyDeviceD3D12(PalDevice* device); + +PalResult PAL_CALL waitDeviceD3D12(PalDevice* device); + +// ================================================== +// Memory +// ================================================== + +PalResult PAL_CALL allocateMemoryD3D12( + PalDevice* device, + PalMemoryType type, + uint64_t memoryMask, + uint64_t size, + PalMemory** outMemory); + +void PAL_CALL freeMemoryD3D12( + PalDevice* device, + PalMemory* memory); + +// ================================================== +// Extended Adapter Features +// ================================================== + +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps); + +PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( + PalDevice* device, + PalMultiViewCapabilities* caps); + +PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( + PalDevice* device, + PalMultiViewportCapabilities* caps); + +PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( + PalDevice* device, + PalDepthStencilCapabilities* caps); + +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); + +PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( + PalDevice* device, + PalMeshShaderCapabilities* caps); + +PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( + PalDevice* device, + PalRayTracingCapabilities* caps); + +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); + +// ================================================== +// Queue +// ================================================== + +PalResult PAL_CALL createQueueD3D12( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); + +void PAL_CALL destroyQueueD3D12(PalQueue* queue); + +PalResult PAL_CALL waitQueueD3D12(PalQueue* queue); + +PalBool PAL_CALL canQueuePresentD3D12( + PalQueue* queue, + PalSurface* surface); + +// ================================================== +// Formats +// ================================================== + +PalResult PAL_CALL enumerateFormatsD3D12( + PalAdapter* adapter, + int32_t* count, + PalFormatInfo* outFormats); + +PalBool PAL_CALL isFormatSupportedD3D12( + PalAdapter* adapter, + PalFormat format); + +PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( + PalAdapter* adapter, + PalFormat format); + +PalSampleCount PAL_CALL queryFormatSampleCountD3D12( + PalAdapter* adapter, + PalFormat format); + +// ================================================== +// Image +// ================================================== + +PalResult PAL_CALL createImageD3D12( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + +void PAL_CALL destroyImageD3D12(PalImage* image); + +PalResult PAL_CALL getImageInfoD3D12( + PalImage* image, + PalImageInfo* info); + +PalResult PAL_CALL getImageMemoryRequirementsD3D12( + PalImage* image, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL bindImageMemoryD3D12( + PalImage* image, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL mapImageMemoryD3D12( + PalImage* image, + uint64_t offset, + uint64_t size, + void** outPtr); + +void PAL_CALL unmapImageMemoryD3D12(PalImage* image); + +// ================================================== +// Image View +// ================================================== + +PalResult PAL_CALL createImageViewD3D12( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + +void PAL_CALL destroyImageViewD3D12(PalImageView* imageView); + +// ================================================== +// Sampler +// ================================================== + +PalResult PAL_CALL createSamplerD3D12( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler); + +void PAL_CALL destroySamplerD3D12(PalSampler* sampler); + +// ================================================== +// Surface +// ================================================== + +PalResult PAL_CALL createSurfaceD3D12( + PalDevice* device, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, + PalSurface** outSurface); + +void PAL_CALL destroySurfaceD3D12(PalSurface* surface); + +PalResult PAL_CALL getSurfaceCapabilitiesD3D12( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps); + +// ================================================== +// Swapchain +// ================================================== + +PalResult PAL_CALL createSwapchainD3D12( + PalDevice* device, + PalQueue* queue, + PalSurface* surface, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + +void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain); + +PalImage* PAL_CALL getSwapchainImageD3D12( + PalSwapchain* swapchain, + int32_t index); + +PalResult PAL_CALL getNextSwapchainImageD3D12( + PalSwapchain* swapchain, + PalSwapchainNextImageInfo* info, + uint32_t* outIndex); + +PalResult PAL_CALL presentSwapchainD3D12( + PalSwapchain* swapchain, + PalSwapchainPresentInfo* info); + +PalResult PAL_CALL resizeSwapchainD3D12( + PalSwapchain* swapchain, + uint32_t newWidth, + uint32_t newHeight); + +// ================================================== +// Shader +// ================================================== + +PalResult PAL_CALL createShaderD3D12( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + +void PAL_CALL destroyShaderD3D12(PalShader* shader); + +// ================================================== +// Fence +// ================================================== + +PalResult PAL_CALL createFenceD3D12( + PalDevice* device, + PalBool signaled, + PalFence** outFence); + +void PAL_CALL destroyFenceD3D12(PalFence* fence); + +PalResult PAL_CALL waitFenceD3D12( + PalFence* fence, + uint64_t timeout); + +PalResult PAL_CALL resetFenceD3D12(PalFence* fence); + +PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence); + +// ================================================== +// Semaphore +// ================================================== + +PalResult PAL_CALL createSemaphoreD3D12( + PalDevice* device, + PalBool enableTimeline, + PalSemaphore** outSemaphore); + +void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); + +PalResult PAL_CALL waitSemaphoreD3D12( + PalSemaphore* semaphore, + uint64_t value, + uint64_t timeout); + +PalResult PAL_CALL signalSemaphoreD3D12( + PalSemaphore* semaphore, + PalQueue* queue, + uint64_t value); + +PalResult PAL_CALL getSemaphoreValueD3D12( + PalSemaphore* semaphore, + uint64_t* outValue); + +// ================================================== +// Command Pool And Buffer +// ================================================== + +PalResult PAL_CALL createCommandPoolD3D12( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool); + +void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool); + +PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool); + +PalResult PAL_CALL allocateCommandBufferD3D12( + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outCmdBuffer); + +void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL submitCommandBufferD3D12( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + +// ================================================== +// Command Recording +// ================================================== + +PalResult PAL_CALL cmdBeginD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info); + +PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdExecuteCommandBufferD3D12( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + +PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + +PalResult PAL_CALL cmdDrawMeshTasksD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t drawCount); + +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); + +PalResult PAL_CALL cmdBeginRenderingD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info); + +PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdCopyBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyBufferToImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageToBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdBindPipelineD3D12( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline); + +PalResult PAL_CALL cmdSetViewportD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalViewport* viewports); + +PalResult PAL_CALL cmdSetScissorsD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalRect2D* scissors); + +PalResult PAL_CALL cmdBindVertexBuffersD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t firstSlot, + uint32_t count, + PalBuffer** buffers, + uint64_t* offsets); + +PalResult PAL_CALL cmdBindIndexBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint64_t offset, + PalIndexType type); + +PalResult PAL_CALL cmdDrawD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + +PalResult PAL_CALL cmdDrawIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + +PalResult PAL_CALL cmdDrawIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +PalResult PAL_CALL cmdDrawIndexedD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + +PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + +PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PalResult PAL_CALL cmdImageBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PalResult PAL_CALL cmdBufferBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PalResult PAL_CALL cmdDispatchD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +PalResult PAL_CALL cmdDispatchBaseD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +PalResult PAL_CALL cmdDispatchIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer); + +PalResult PAL_CALL cmdTraceRaysD3D12( + PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth); + +PalResult PAL_CALL cmdTraceRaysIndirectD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t raygenIndex, + PalShaderBindingTable* sbt, + PalBuffer* buffer); + +PalResult PAL_CALL cmdBindDescriptorSetD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t setIndex, + PalDescriptorSet* set); + +PalResult PAL_CALL cmdPushConstantsD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t shaderStageCount, + PalShaderStage* shaderStages, + uint32_t offset, + uint32_t size, + const void* value); + +PalResult PAL_CALL cmdSetCullModeD3D12( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + +PalResult PAL_CALL cmdSetFrontFaceD3D12( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + +PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + +PalResult PAL_CALL cmdSetDepthTestEnableD3D12( + PalCommandBuffer* cmdBuffer, + PalBool enable); + +PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( + PalCommandBuffer* cmdBuffer, + PalBool enable); + +PalResult PAL_CALL cmdSetStencilOpD3D12( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); + +// ================================================== +// Acceleration Structure +// ================================================== + +PalResult PAL_CALL createAccelerationstructureD3D12( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + +void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as); + +PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + +// ================================================== +// Buffer +// ================================================== + +PalResult PAL_CALL createBufferD3D12( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + +void PAL_CALL destroyBufferD3D12(PalBuffer* buffer); + +PalResult PAL_CALL getBufferMemoryRequirementsD3D12( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( + PalDevice* device, + uint32_t instanceCount, + uint64_t* outSize); + +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( + PalDevice* device, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo, + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize); + +PalResult PAL_CALL writeToInstanceBufferD3D12( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + uint32_t instanceCount); + +PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( + PalDevice* device, + void* ptr, + void* srcData, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL bindBufferMemoryD3D12( + PalBuffer* buffer, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL mapBufferMemoryD3D12( + PalBuffer* buffer, + uint64_t offset, + uint64_t size, + void** outPtr); + +void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer); + +PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); + +// ================================================== +// Descriptor Pool, Set and Layout +// ================================================== + +PalResult PAL_CALL createDescriptorSetLayoutD3D12( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + +void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout); + +PalResult PAL_CALL createDescriptorPoolD3D12( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + +void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool); + +PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool); + +PalResult PAL_CALL allocateDescriptorSetD3D12( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + +PalResult PAL_CALL updateDescriptorSetD3D12( + PalDevice* device, + uint32_t count, + PalDescriptorSetWriteInfo* infos); + +// ================================================== +// Pipeline Layout +// ================================================== + +PalResult PAL_CALL createPipelineLayoutD3D12( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + +void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout); + +// ================================================== +// Pipeline +// ================================================== + +PalResult PAL_CALL createGraphicsPipelineD3D12( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createComputePipelineD3D12( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createRayTracingPipelineD3D12( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + +void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline); + +// ================================================== +// Shader Binding Table +// ================================================== + +PalResult PAL_CALL createShaderBindingTableD3D12( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + +void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); + +PalResult PAL_CALL updateShaderBindingTableD3D12( + PalShaderBindingTable* sbt, + uint32_t count, + PalShaderBindingTableRecordInfo* infos); + +static PalGraphicsVtable s_D3D12Backend = { + // adapter + .enumerateAdapters = enumerateAdaptersD3D12, + .getAdapterInfo = getAdapterInfoD3D12, + .getAdapterCapabilities = getAdapterCapabilitiesD3D12, + .getAdapterFeatures = getAdapterFeaturesD3D12, + .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetD3D12, + + // device + .createDevice = createDeviceD3D12, + .destroyDevice = destroyDeviceD3D12, + + // memory + .allocateMemory = allocateMemoryD3D12, + .freeMemory = freeMemoryD3D12, + + // extended adapter features + .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesD3D12, + .queryMultiViewCapabilities = queryMultiViewCapabilitiesD3D12, + .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesD3D12, + .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesD3D12, + .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesD3D12, + .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesD3D12, + .queryRayTracingCapabilities = queryRayTracingCapabilitiesD3D12, + .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesD3D12, + + // queue + .createQueue = createQueueD3D12, + .destroyQueue = destroyQueueD3D12, + .waitQueue = waitQueueD3D12, + .canQueuePresent = canQueuePresentD3D12, + + // format + .enumerateFormats = enumerateFormatsD3D12, + .isFormatSupported = isFormatSupportedD3D12, + .queryFormatImageUsages = queryFormatImageUsagesD3D12, + .queryFormatSampleCount = queryFormatSampleCountD3D12, + + // image + .createImage = createImageD3D12, + .destroyImage = destroyImageD3D12, + .getImageInfo = getImageInfoD3D12, + .getImageMemoryRequirements = getImageMemoryRequirementsD3D12, + .bindImageMemory = bindImageMemoryD3D12, + .mapImageMemory = mapImageMemoryD3D12, + .unmapImageMemory = unmapImageMemoryD3D12, + + // image view + .createImageView = createImageViewD3D12, + .destroyImageView = destroyImageViewD3D12, + + // sampler + .createSampler = createSamplerD3D12, + .destroySampler = destroySamplerD3D12, + + // surface + .createSurface = createSurfaceD3D12, + .destroySurface = destroySurfaceD3D12, + .getSurfaceCapabilities = getSurfaceCapabilitiesD3D12, + + // swapchain + .createSwapchain = createSwapchainD3D12, + .destroySwapchain = destroySwapchainD3D12, + .getSwapchainImage = getSwapchainImageD3D12, + .getNextSwapchainImage = getNextSwapchainImageD3D12, + .presentSwapchain = presentSwapchainD3D12, + .resizeSwapchain = resizeSwapchainD3D12, + + // shader + .createShader = createShaderD3D12, + .destroyShader = destroyShaderD3D12, + + // fence + .createFence = createFenceD3D12, + .destroyFence = destroyFenceD3D12, + .waitFence = waitFenceD3D12, + .resetFence = resetFenceD3D12, + .isFenceSignaled = isFenceSignaledD3D12, + + // semaphore + .createSemaphore = createSemaphoreD3D12, + .destroySemaphore = destroySemaphoreD3D12, + .waitSemaphore = waitSemaphoreD3D12, + .signalSemaphore = signalSemaphoreD3D12, + .getSemaphoreValue = getSemaphoreValueD3D12, + + // command pool and command buffer + .createCommandPool = createCommandPoolD3D12, + .destroyCommandPool = destroyCommandPoolD3D12, + .resetCommandPool = resetCommandPoolD3D12, + .allocateCommandBuffer = allocateCommandBufferD3D12, + .freeCommandBuffer = freeCommandBufferD3D12, + .resetCommandBuffer = resetCommandBufferD3D12, + .submitCommandBuffer = submitCommandBufferD3D12, + + // command recording + .cmdBegin = cmdBeginD3D12, + .cmdEnd = cmdEndD3D12, + .cmdExecuteCommandBuffer = cmdExecuteCommandBufferD3D12, + .cmdSetFragmentShadingRate = cmdSetFragmentShadingRateD3D12, + .cmdDrawMeshTasks = cmdDrawMeshTasksD3D12, + .cmdDrawMeshTasksIndirect = cmdDrawMeshTasksIndirectD3D12, + .cmdDrawMeshTasksIndirectCount = cmdDrawMeshTasksIndirectCountD3D12, + .cmdBuildAccelerationStructure = cmdBuildAccelerationStructureD3D12, + .cmdBeginRendering = cmdBeginRenderingD3D12, + .cmdEndRendering = cmdEndRenderingD3D12, + .cmdCopyBuffer = cmdCopyBufferD3D12, + .cmdCopyBufferToImage = cmdCopyBufferToImageD3D12, + .cmdCopyImage = cmdCopyImageD3D12, + .cmdCopyImageToBuffer = cmdCopyImageToBufferD3D12, + .cmdBindPipeline = cmdBindPipelineD3D12, + .cmdSetViewport = cmdSetViewportD3D12, + .cmdSetScissors = cmdSetScissorsD3D12, + .cmdBindVertexBuffers = cmdBindVertexBuffersD3D12, + .cmdBindIndexBuffer = cmdBindIndexBufferD3D12, + .cmdDraw = cmdDrawD3D12, + .cmdDrawIndirect = cmdDrawIndirectD3D12, + .cmdDrawIndirectCount = cmdDrawIndirectCountD3D12, + .cmdDrawIndexed = cmdDrawIndexedD3D12, + .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectD3D12, + .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountD3D12, + .cmdAccelerationStructureBarrier = cmdAccelerationStructureBarrierD3D12, + .cmdImageBarrier = cmdImageBarrierD3D12, + .cmdBufferBarrier = cmdBufferBarrierD3D12, + .cmdDispatch = cmdDispatchD3D12, + .cmdDispatchBase = cmdDispatchBaseD3D12, + .cmdDispatchIndirect = cmdDispatchIndirectD3D12, + .cmdTraceRays = cmdTraceRaysD3D12, + .cmdTraceRaysIndirect = cmdTraceRaysIndirectD3D12, + .cmdBindDescriptorSet = cmdBindDescriptorSetD3D12, + .cmdPushConstants = cmdPushConstantsD3D12, + .cmdSetCullMode = cmdSetCullModeD3D12, + .cmdSetFrontFace = cmdSetFrontFaceD3D12, + .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyD3D12, + .cmdSetDepthTestEnable = cmdSetDepthTestEnableD3D12, + .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableD3D12, + .cmdSetStencilOp = cmdSetStencilOpD3D12, + + // acceleration structure + .createAccelerationstructure = createAccelerationstructureD3D12, + .destroyAccelerationstructure = destroyAccelerationstructureD3D12, + .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeD3D12, + + // buffer + .createBuffer = createBufferD3D12, + .destroyBuffer = destroyBufferD3D12, + .getBufferMemoryRequirements = getBufferMemoryRequirementsD3D12, + .computeInstanceBufferRequirements = computeInstanceBufferRequirementsD3D12, + .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsD3D12, + .writeToInstanceBuffer = writeToInstanceBufferD3D12, + .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferD3D12, + .bindBufferMemory = bindBufferMemoryD3D12, + .getBufferDeviceAddress = getBufferDeviceAddressD3D12, + .mapBufferMemory = mapBufferMemoryD3D12, + .unmapBufferMemory = unmapBufferMemoryD3D12, + + // descriptor set layout, descriptor pool and descriptor set + .createDescriptorSetLayout = createDescriptorSetLayoutD3D12, + .destroyDescriptorSetLayout = destroyDescriptorSetLayoutD3D12, + .createDescriptorPool = createDescriptorPoolD3D12, + .destroyDescriptorPool = destroyDescriptorPoolD3D12, + .resetDescriptorPool = resetDescriptorPoolD3D12, + .allocateDescriptorSet = allocateDescriptorSetD3D12, + .updateDescriptorSet = updateDescriptorSetD3D12, + + // pipeline layout + .createPipelineLayout = createPipelineLayoutD3D12, + .destroyPipelineLayout = destroyPipelineLayoutD3D12, + + // pipeline + .createGraphicsPipeline = createGraphicsPipelineD3D12, + .createComputePipeline = createComputePipelineD3D12, + .createRayTracingPipeline = createRayTracingPipelineD3D12, + .destroyPipeline = destroyPipelineD3D12, + + // shader binding tables + .createShaderBindingTable = createShaderBindingTableD3D12, + .destroyShaderBindingTable = destroyShaderBindingTableD3D12, + .updateShaderBindingTable = updateShaderBindingTableD3D12}; + +#endif // _PAL_BACKENDS_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 6222e728..430215f5 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -5,2064 +5,501 @@ Licensed under the Zlib license. See LICENSE file in root. */ -// ================================================== -// Includes -// ================================================== - -#include "pal/pal_graphics.h" - -// ================================================== -// Typedefs, enums and structs -// ================================================== - -#define MAX_BACKENDS 18 // 16 for users -#define PAL_HANDLE(name) \ - struct name { \ - const PalGraphicsBackend* backend; \ - }; - -PAL_HANDLE(PalAdapter) -PAL_HANDLE(PalDevice) -PAL_HANDLE(PalQueue) -PAL_HANDLE(PalSwapchain) -PAL_HANDLE(PalImage) -PAL_HANDLE(PalImageView) -PAL_HANDLE(PalShader) -PAL_HANDLE(PalBuffer) - -PAL_HANDLE(PalFence) -PAL_HANDLE(PalSemaphore) -PAL_HANDLE(PalCommandPool) -PAL_HANDLE(PalCommandBuffer) -PAL_HANDLE(PalPipeline) -PAL_HANDLE(PalAccelerationStructure) -PAL_HANDLE(PalPipelineLayout) -PAL_HANDLE(PalDescriptorSetLayout) -PAL_HANDLE(PalDescriptorPool) -PAL_HANDLE(PalDescriptorSet) -PAL_HANDLE(PalSampler) -PAL_HANDLE(PalSurface) -PAL_HANDLE(PalShaderBindingTable) - -typedef struct { - int32_t count; - int32_t startIndex; - const PalGraphicsBackend* base; -} BackendData; - -typedef struct { - PalBool initialized; - int32_t backendCount; - const PalAllocator* allocator; - BackendData backends[MAX_BACKENDS]; -} GraphicsLinux; - -static GraphicsLinux s_Graphics = {0}; - -// ================================================== -// Internal API -// ================================================== - -static inline uint32_t _ceil( - uint32_t a, - uint32_t b) -{ - return (a + b - 1) / b; -} - -static inline uint32_t _min( - uint32_t a, - uint32_t b) -{ - return (a < b) ? a : b; -} - -// ================================================== -// Vulkan API -// ================================================== - -#if PAL_HAS_VULKAN_BACKEND - -// ================================================== -// Adapter -// ================================================== - -PalResult PAL_CALL initGraphicsVk( - const PalGraphicsDebugger* debugger, - const PalAllocator* allocator); - -void PAL_CALL shutdownGraphicsVk(); - -PalResult PAL_CALL enumerateAdaptersVk( - int32_t* count, - PalAdapter** outAdapters); - -PalResult PAL_CALL getAdapterInfoVk( - PalAdapter* adapter, - PalAdapterInfo* info); - -PalResult PAL_CALL getAdapterCapabilitiesVk( - PalAdapter* adapter, - PalAdapterCapabilities* caps); - -PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter); - -uint32_t PAL_CALL getHighestSupportedShaderTargetVk( - PalAdapter* adapter, - PalShaderFormats shaderFormat); - -// ================================================== -// Device -// ================================================== - -PalResult PAL_CALL createDeviceVk( - PalAdapter* adapter, - PalAdapterFeatures features, - PalDevice** outDevice); - -void PAL_CALL destroyDeviceVk(PalDevice* device); - -PalResult PAL_CALL waitDeviceVk(PalDevice* device); - -// ================================================== -// Memory -// ================================================== - -PalResult PAL_CALL allocateMemoryVk( - PalDevice* device, - PalMemoryType type, - uint64_t memoryMask, - uint64_t size, - PalMemory** outMemory); - -void PAL_CALL freeMemoryVk( - PalDevice* device, - PalMemory* memory); - -// ================================================== -// Extended Adapter Features -// ================================================== - -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk( - PalDevice* device, - PalSamplerAnisotropyCapabilities* caps); - -PalResult PAL_CALL queryMultiViewCapabilitiesVk( - PalDevice* device, - PalMultiViewCapabilities* caps); - -PalResult PAL_CALL queryMultiViewportCapabilitiesVk( - PalDevice* device, - PalMultiViewportCapabilities* caps); - -PalResult PAL_CALL queryDepthStencilCapabilitiesVk( - PalDevice* device, - PalDepthStencilCapabilities* caps); - -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk( - PalDevice* device, - PalFragmentShadingRateCapabilities* caps); - -PalResult PAL_CALL queryMeshShaderCapabilitiesVk( - PalDevice* device, - PalMeshShaderCapabilities* caps); - -PalResult PAL_CALL queryRayTracingCapabilitiesVk( - PalDevice* device, - PalRayTracingCapabilities* caps); - -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( - PalDevice* device, - PalDescriptorIndexingCapabilities* caps); - -// ================================================== -// Queue -// ================================================== - -PalResult PAL_CALL createQueueVk( - PalDevice* device, - PalQueueType type, - PalQueue** outQueue); - -void PAL_CALL destroyQueueVk(PalQueue* queue); - -PalResult PAL_CALL waitQueueVk(PalQueue* queue); - -PalBool PAL_CALL canQueuePresentVk( - PalQueue* queue, - PalSurface* surface); - -// ================================================== -// Formats -// ================================================== - -PalResult PAL_CALL enumerateFormatsVk( - PalAdapter* adapter, - int32_t* count, - PalFormatInfo* outFormats); - -PalBool PAL_CALL isFormatSupportedVk( - PalAdapter* adapter, - PalFormat format); - -PalImageUsages PAL_CALL queryFormatImageUsagesVk( - PalAdapter* adapter, - PalFormat format); - -PalSampleCount PAL_CALL queryFormatSampleCountVk( - PalAdapter* adapter, - PalFormat format); - -// ================================================== -// Image -// ================================================== - -PalResult PAL_CALL createImageVk( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage); - -void PAL_CALL destroyImageVk(PalImage* image); - -PalResult PAL_CALL getImageInfoVk( - PalImage* image, - PalImageInfo* info); - -PalResult PAL_CALL getImageMemoryRequirementsVk( - PalImage* image, - PalMemoryRequirements* requirements); - -PalResult PAL_CALL bindImageMemoryVk( - PalImage* image, - PalMemory* memory, - uint64_t offset); - -PalResult PAL_CALL mapImageMemoryVk( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr); - -void PAL_CALL unmapImageMemoryVk(PalImage* image); - -// ================================================== -// Image View -// ================================================== - -PalResult PAL_CALL createImageViewVk( - PalDevice* device, - PalImage* image, - const PalImageViewCreateInfo* info, - PalImageView** outImageView); - -void PAL_CALL destroyImageViewVk(PalImageView* imageView); - -// ================================================== -// Sampler -// ================================================== - -PalResult PAL_CALL createSamplerVk( - PalDevice* device, - const PalSamplerCreateInfo* info, - PalSampler** outSampler); - -void PAL_CALL destroySamplerVk(PalSampler* sampler); - -// ================================================== -// Surface -// ================================================== - -PalResult PAL_CALL createSurfaceVk( - PalDevice* device, - PalGraphicsWindow* window, - PalSurface** outSurface); - -void PAL_CALL destroySurfaceVk(PalSurface* surface); - -PalResult PAL_CALL getSurfaceCapabilitiesVk( - PalDevice* device, - PalSurface* surface, - PalSurfaceCapabilities* caps); - -// ================================================== -// Swapchain -// ================================================== - -PalResult PAL_CALL createSwapchainVk( - PalDevice* device, - PalQueue* queue, - PalSurface* surface, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain); - -void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain); - -PalImage* PAL_CALL getSwapchainImageVk( - PalSwapchain* swapchain, - int32_t index); - -PalResult PAL_CALL getNextSwapchainImageVk( - PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, - uint32_t* outIndex); - -PalResult PAL_CALL presentSwapchainVk( - PalSwapchain* swapchain, - PalSwapchainPresentInfo* info); - -PalResult PAL_CALL resizeSwapchainVk( - PalSwapchain* swapchain, - uint32_t newWidth, - uint32_t newHeight); - -// ================================================== -// Shader -// ================================================== - -PalResult PAL_CALL createShaderVk( - PalDevice* device, - const PalShaderCreateInfo* info, - PalShader** outShader); - -void PAL_CALL destroyShaderVk(PalShader* shader); - -// ================================================== -// Fence -// ================================================== - -PalResult PAL_CALL createFenceVk( - PalDevice* device, - PalBool signaled, - PalFence** outFence); - -void PAL_CALL destroyFenceVk(PalFence* fence); - -PalResult PAL_CALL waitFenceVk( - PalFence* fence, - uint64_t timeout); - -PalResult PAL_CALL resetFenceVk(PalFence* fence); - -PalBool PAL_CALL isFenceSignaledVk(PalFence* fence); - -// ================================================== -// Semaphore -// ================================================== - -PalResult PAL_CALL createSemaphoreVk( - PalDevice* device, - PalBool enableTimeline, - PalSemaphore** outSemaphore); - -void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore); - -PalResult PAL_CALL waitSemaphoreVk( - PalSemaphore* semaphore, - uint64_t value, - uint64_t timeout); - -PalResult PAL_CALL signalSemaphoreVk( - PalSemaphore* semaphore, - PalQueue* queue, - uint64_t value); - -PalResult PAL_CALL getSemaphoreValueVk( - PalSemaphore* semaphore, - uint64_t* outValue); - -// ================================================== -// Command Pool And Buffer -// ================================================== - -PalResult PAL_CALL createCommandPoolVk( - PalDevice* device, - PalQueue* queue, - PalCommandPool** outPool); - -void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool); - -PalResult PAL_CALL resetCommandPoolVk(PalCommandPool* pool); - -PalResult PAL_CALL allocateCommandBufferVk( - PalDevice* device, - PalCommandPool* pool, - PalCommandBufferType type, - PalCommandBuffer** outCmdBuffer); - -void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL submitCommandBufferVk( - PalQueue* queue, - PalCommandBufferSubmitInfo* info); - -// ================================================== -// Command Recording -// ================================================== - -PalResult PAL_CALL cmdBeginVk( - PalCommandBuffer* cmdBuffer, - PalRenderingLayoutInfo* info); - -PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL cmdExecuteCommandBufferVk( - PalCommandBuffer* primaryCmdBuffer, - PalCommandBuffer* secondaryCmdBuffer); - -PalResult PAL_CALL cmdSetFragmentShadingRateVk( - PalCommandBuffer* cmdBuffer, - PalFragmentShadingRateState* state); - -PalResult PAL_CALL cmdDrawMeshTasksVk( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t drawCount); - -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdBuildAccelerationStructureVk( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructureBuildInfo* info); - -PalResult PAL_CALL cmdBeginRenderingVk( - PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info); - -PalResult PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL cmdCopyBufferVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* dst, - PalBuffer* src, - PalBufferCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyBufferToImageVk( - PalCommandBuffer* cmdBuffer, - PalImage* dstImage, - PalBuffer* srcBuffer, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyImageVk( - PalCommandBuffer* cmdBuffer, - PalImage* dst, - PalImage* src, - PalImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyImageToBufferVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* dstBuffer, - PalImage* srcImage, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdBindPipelineVk( - PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline); - -PalResult PAL_CALL cmdSetViewportVk( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalViewport* viewports); - -PalResult PAL_CALL cmdSetScissorsVk( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalRect2D* scissors); - -PalResult PAL_CALL cmdBindVertexBuffersVk( - PalCommandBuffer* cmdBuffer, - uint32_t firstSlot, - uint32_t count, - PalBuffer** buffers, - uint64_t* offsets); - -PalResult PAL_CALL cmdBindIndexBufferVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint64_t offset, - PalIndexType type); - -PalResult PAL_CALL cmdDrawVk( - PalCommandBuffer* cmdBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance); - -PalResult PAL_CALL cmdDrawIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - -PalResult PAL_CALL cmdDrawIndirectCountVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdDrawIndexedVk( - PalCommandBuffer* cmdBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance); - -PalResult PAL_CALL cmdDrawIndexedIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - -PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdAccelerationStructureBarrierVk( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructure* as, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); - -PalResult PAL_CALL cmdImageBarrierVk( - PalCommandBuffer* cmdBuffer, - PalImage* image, - PalImageSubresourceRange* subresourceRange, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); - -PalResult PAL_CALL cmdBufferBarrierVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); - -PalResult PAL_CALL cmdDispatchVk( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDispatchBaseVk( - PalCommandBuffer* cmdBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDispatchIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer); - -PalResult PAL_CALL cmdTraceRaysVk( - PalCommandBuffer* cmdBuffer, - PalShaderBindingTable* sbt, - uint32_t raygenIndex, - uint32_t width, - uint32_t height, - uint32_t depth); - -PalResult PAL_CALL cmdTraceRaysIndirectVk( - PalCommandBuffer* cmdBuffer, - uint32_t raygenIndex, - PalShaderBindingTable* sbt, - PalBuffer* buffer); - -PalResult PAL_CALL cmdBindDescriptorSetVk( - PalCommandBuffer* cmdBuffer, - uint32_t setIndex, - PalDescriptorSet* set); - -PalResult PAL_CALL cmdPushConstantsVk( - PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, - uint32_t offset, - uint32_t size, - const void* value); - -PalResult PAL_CALL cmdSetCullModeVk( - PalCommandBuffer* cmdBuffer, - PalCullMode cullMode); - -PalResult PAL_CALL cmdSetFrontFaceVk( - PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace); - -PalResult PAL_CALL cmdSetPrimitiveTopologyVk( - PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology); - -PalResult PAL_CALL cmdSetDepthTestEnableVk( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -PalResult PAL_CALL cmdSetDepthWriteEnableVk( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -PalResult PAL_CALL cmdSetStencilOpVk( - PalCommandBuffer* cmdBuffer, - PalStencilFaceFlags faceMask, - PalStencilOp failOp, - PalStencilOp passOp, - PalStencilOp depthFailOp, - PalCompareOp compareOp); - -// ================================================== -// Acceleration Structure -// ================================================== - -PalResult PAL_CALL createAccelerationstructureVk( - PalDevice* device, - const PalAccelerationStructureCreateInfo* info, - PalAccelerationStructure** outAs); - -void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as); - -PalResult PAL_CALL getAccelerationStructureBuildSizeVk( - PalDevice* device, - PalAccelerationStructureBuildInfo* info, - PalAccelerationStructureBuildSize* size); - -// ================================================== -// Buffer -// ================================================== - -PalResult PAL_CALL createBufferVk( - PalDevice* device, - const PalBufferCreateInfo* info, - PalBuffer** outBuffer); - -void PAL_CALL destroyBufferVk(PalBuffer* buffer); - -PalResult PAL_CALL getBufferMemoryRequirementsVk( - PalBuffer* buffer, - PalMemoryRequirements* requirements); - -PalResult PAL_CALL computeInstanceBufferRequirementsVk( - PalDevice* device, - uint32_t instanceCount, - uint64_t* outSize); - -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( - PalDevice* device, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize); - -PalResult PAL_CALL writeToInstanceBufferVk( - PalDevice* device, - void* ptr, - PalAccelerationStructureInstance* instances, - uint32_t instanceCount); - -PalResult PAL_CALL writeToImageCopyStagingBufferVk( - PalDevice* device, - void* ptr, - void* srcData, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL bindBufferMemoryVk( - PalBuffer* buffer, - PalMemory* memory, - uint64_t offset); - -PalResult PAL_CALL mapBufferMemoryVk( - PalBuffer* buffer, - uint64_t offset, - uint64_t size, - void** outPtr); - -void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer); - -PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer); - -// ================================================== -// Descriptor Pool, Set and Layout -// ================================================== - -PalResult PAL_CALL createDescriptorSetLayoutVk( - PalDevice* device, - const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout); - -void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout); - -PalResult PAL_CALL createDescriptorPoolVk( - PalDevice* device, - const PalDescriptorPoolCreateInfo* info, - PalDescriptorPool** outPool); - -void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool); - -PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool); - -PalResult PAL_CALL allocateDescriptorSetVk( - PalDevice* device, - PalDescriptorPool* pool, - PalDescriptorSetLayout* layout, - PalDescriptorSet** outSet); - -PalResult PAL_CALL updateDescriptorSetVk( - PalDevice* device, - uint32_t count, - PalDescriptorSetWriteInfo* infos); - -// ================================================== -// Pipeline Layout -// ================================================== - -PalResult PAL_CALL createPipelineLayoutVk( - PalDevice* device, - const PalPipelineLayoutCreateInfo* info, - PalPipelineLayout** outLayout); - -void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout); - -// ================================================== -// Pipeline -// ================================================== - -PalResult PAL_CALL createGraphicsPipelineVk( - PalDevice* device, - const PalGraphicsPipelineCreateInfo* info, - PalPipeline** outPipeline); - -PalResult PAL_CALL createComputePipelineVk( - PalDevice* device, - const PalComputePipelineCreateInfo* info, - PalPipeline** outPipeline); - -PalResult PAL_CALL createRayTracingPipelineVk( - PalDevice* device, - const PalRayTracingPipelineCreateInfo* info, - PalPipeline** outPipeline); - -void PAL_CALL destroyPipelineVk(PalPipeline* pipeline); - -// ================================================== -// Shader Binding Table -// ================================================== - -PalResult PAL_CALL createShaderBindingTableVk( - PalDevice* device, - const PalShaderBindingTableCreateInfo* info, - PalShaderBindingTable** outSbt); - -void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt); - -PalResult PAL_CALL updateShaderBindingTableVk( - PalShaderBindingTable* sbt, - uint32_t count, - PalShaderBindingTableRecordInfo* infos); - -static PalGraphicsBackend s_VkBackend = { - // adapter - .enumerateAdapters = enumerateAdaptersVk, - .getAdapterInfo = getAdapterInfoVk, - .getAdapterCapabilities = getAdapterCapabilitiesVk, - .getAdapterFeatures = getAdapterFeaturesVk, - .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetVk, - - // device - .createDevice = createDeviceVk, - .destroyDevice = destroyDeviceVk, - - // memory - .allocateMemory = allocateMemoryVk, - .freeMemory = freeMemoryVk, - - // extended adapter features - .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesVk, - .queryMultiViewCapabilities = queryMultiViewCapabilitiesVk, - .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesVk, - .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesVk, - .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesVk, - .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesVk, - .queryRayTracingCapabilities = queryRayTracingCapabilitiesVk, - .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesVk, - - // queue - .createQueue = createQueueVk, - .destroyQueue = destroyQueueVk, - .waitQueue = waitQueueVk, - .canQueuePresent = canQueuePresentVk, - - // format - .enumerateFormats = enumerateFormatsVk, - .isFormatSupported = isFormatSupportedVk, - .queryFormatImageUsages = queryFormatImageUsagesVk, - .queryFormatSampleCount = queryFormatSampleCountVk, - - // image - .createImage = createImageVk, - .destroyImage = destroyImageVk, - .getImageInfo = getImageInfoVk, - .getImageMemoryRequirements = getImageMemoryRequirementsVk, - .bindImageMemory = bindImageMemoryVk, - .mapImageMemory = mapImageMemoryVk, - .unmapImageMemory = unmapImageMemoryVk, - - // image view - .createImageView = createImageViewVk, - .destroyImageView = destroyImageViewVk, - - // sampler - .createSampler = createSamplerVk, - .destroySampler = destroySamplerVk, - - // surface - .createSurface = createSurfaceVk, - .destroySurface = destroySurfaceVk, - .getSurfaceCapabilities = getSurfaceCapabilitiesVk, - - // swapchain - .createSwapchain = createSwapchainVk, - .destroySwapchain = destroySwapchainVk, - .getSwapchainImage = getSwapchainImageVk, - .getNextSwapchainImage = getNextSwapchainImageVk, - .presentSwapchain = presentSwapchainVk, - .resizeSwapchain = resizeSwapchainVk, - - // shader - .createShader = createShaderVk, - .destroyShader = destroyShaderVk, - - // fence - .createFence = createFenceVk, - .destroyFence = destroyFenceVk, - .waitFence = waitFenceVk, - .resetFence = resetFenceVk, - .isFenceSignaled = isFenceSignaledVk, - - // semaphore - .createSemaphore = createSemaphoreVk, - .destroySemaphore = destroySemaphoreVk, - .waitSemaphore = waitSemaphoreVk, - .signalSemaphore = signalSemaphoreVk, - .getSemaphoreValue = getSemaphoreValueVk, - - // command pool and command buffer - .createCommandPool = createCommandPoolVk, - .destroyCommandPool = destroyCommandPoolVk, - .resetCommandPool = resetCommandPoolVk, - .allocateCommandBuffer = allocateCommandBufferVk, - .freeCommandBuffer = freeCommandBufferVk, - .resetCommandBuffer = resetCommandBufferVk, - .submitCommandBuffer = submitCommandBufferVk, - - // command recording - .cmdBegin = cmdBeginVk, - .cmdEnd = cmdEndVk, - .cmdExecuteCommandBuffer = cmdExecuteCommandBufferVk, - .cmdSetFragmentShadingRate = cmdSetFragmentShadingRateVk, - .cmdDrawMeshTasks = cmdDrawMeshTasksVk, - .cmdDrawMeshTasksIndirect = cmdDrawMeshTasksIndirectVk, - .cmdDrawMeshTasksIndirectCount = cmdDrawMeshTasksIndirectCountVk, - .cmdBuildAccelerationStructure = cmdBuildAccelerationStructureVk, - .cmdBeginRendering = cmdBeginRenderingVk, - .cmdEndRendering = cmdEndRenderingVk, - .cmdCopyBuffer = cmdCopyBufferVk, - .cmdCopyBufferToImage = cmdCopyBufferToImageVk, - .cmdCopyImage = cmdCopyImageVk, - .cmdCopyImageToBuffer = cmdCopyImageToBufferVk, - .cmdBindPipeline = cmdBindPipelineVk, - .cmdSetViewport = cmdSetViewportVk, - .cmdSetScissors = cmdSetScissorsVk, - .cmdBindVertexBuffers = cmdBindVertexBuffersVk, - .cmdBindIndexBuffer = cmdBindIndexBufferVk, - .cmdDraw = cmdDrawVk, - .cmdDrawIndirect = cmdDrawIndirectVk, - .cmdDrawIndirectCount = cmdDrawIndirectCountVk, - .cmdDrawIndexed = cmdDrawIndexedVk, - .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectVk, - .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountVk, - .cmdAccelerationStructureBarrier = cmdAccelerationStructureBarrierVk, - .cmdImageBarrier = cmdImageBarrierVk, - .cmdBufferBarrier = cmdBufferBarrierVk, - .cmdDispatch = cmdDispatchVk, - .cmdDispatchBase = cmdDispatchBaseVk, - .cmdDispatchIndirect = cmdDispatchIndirectVk, - .cmdTraceRays = cmdTraceRaysVk, - .cmdTraceRaysIndirect = cmdTraceRaysIndirectVk, - .cmdBindDescriptorSet = cmdBindDescriptorSetVk, - .cmdPushConstants = cmdPushConstantsVk, - .cmdSetCullMode = cmdSetCullModeVk, - .cmdSetFrontFace = cmdSetFrontFaceVk, - .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyVk, - .cmdSetDepthTestEnable = cmdSetDepthTestEnableVk, - .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableVk, - .cmdSetStencilOp = cmdSetStencilOpVk, - - // acceleration structure - .createAccelerationstructure = createAccelerationstructureVk, - .destroyAccelerationstructure = destroyAccelerationstructureVk, - .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeVk, - - // buffer - .createBuffer = createBufferVk, - .destroyBuffer = destroyBufferVk, - .getBufferMemoryRequirements = getBufferMemoryRequirementsVk, - .computeInstanceBufferRequirements = computeInstanceBufferRequirementsVk, - .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsVk, - .writeToInstanceBuffer = writeToInstanceBufferVk, - .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferVk, - .bindBufferMemory = bindBufferMemoryVk, - .getBufferDeviceAddress = getBufferDeviceAddressVk, - .mapBufferMemory = mapBufferMemoryVk, - .unmapBufferMemory = unmapBufferMemoryVk, - - // descriptor set layout, descriptor pool and descriptor set - .createDescriptorSetLayout = createDescriptorSetLayoutVk, - .destroyDescriptorSetLayout = destroyDescriptorSetLayoutVk, - .createDescriptorPool = createDescriptorPoolVk, - .destroyDescriptorPool = destroyDescriptorPoolVk, - .resetDescriptorPool = resetDescriptorPoolVk, - .allocateDescriptorSet = allocateDescriptorSetVk, - .updateDescriptorSet = updateDescriptorSetVk, - - // pipeline layout - .createPipelineLayout = createPipelineLayoutVk, - .destroyPipelineLayout = destroyPipelineLayoutVk, - - // pipeline - .createGraphicsPipeline = createGraphicsPipelineVk, - .createComputePipeline = createComputePipelineVk, - .createRayTracingPipeline = createRayTracingPipelineVk, - .destroyPipeline = destroyPipelineVk, - - // shader binding table - .createShaderBindingTable = createShaderBindingTableVk, - .destroyShaderBindingTable = destroyShaderBindingTableVk, - .updateShaderBindingTable = updateShaderBindingTableVk}; - -#endif // PAL_HAS_VULKAN_BACKEND - -// ================================================== -// D3D12 API -// ================================================== - -#if PAL_HAS_D3D12_BACKEND - -// ================================================== -// Adapter -// ================================================== - -PalResult PAL_CALL initGraphicsD3D12( - const PalGraphicsDebugger* debugger, - const PalAllocator* allocator); - -void PAL_CALL shutdownGraphicsD3D12(); - -PalResult PAL_CALL enumerateAdaptersD3D12( - int32_t* count, - PalAdapter** outAdapters); - -PalResult PAL_CALL getAdapterInfoD3D12( - PalAdapter* adapter, - PalAdapterInfo* info); - -PalResult PAL_CALL getAdapterCapabilitiesD3D12( - PalAdapter* adapter, - PalAdapterCapabilities* caps); - -PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); - -uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( - PalAdapter* adapter, - PalShaderFormats shaderFormat); - -// ================================================== -// Device -// ================================================== - -PalResult PAL_CALL createDeviceD3D12( - PalAdapter* adapter, - PalAdapterFeatures features, - PalDevice** outDevice); - -void PAL_CALL destroyDeviceD3D12(PalDevice* device); - -PalResult PAL_CALL waitDeviceD3D12(PalDevice* device); - -// ================================================== -// Memory -// ================================================== - -PalResult PAL_CALL allocateMemoryD3D12( - PalDevice* device, - PalMemoryType type, - uint64_t memoryMask, - uint64_t size, - PalMemory** outMemory); - -void PAL_CALL freeMemoryD3D12( - PalDevice* device, - PalMemory* memory); - -// ================================================== -// Extended Adapter Features -// ================================================== - -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( - PalDevice* device, - PalSamplerAnisotropyCapabilities* caps); - -PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( - PalDevice* device, - PalMultiViewCapabilities* caps); - -PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( - PalDevice* device, - PalMultiViewportCapabilities* caps); - -PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( - PalDevice* device, - PalDepthStencilCapabilities* caps); - -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( - PalDevice* device, - PalFragmentShadingRateCapabilities* caps); - -PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( - PalDevice* device, - PalMeshShaderCapabilities* caps); - -PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( - PalDevice* device, - PalRayTracingCapabilities* caps); - -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( - PalDevice* device, - PalDescriptorIndexingCapabilities* caps); - -// ================================================== -// Queue -// ================================================== - -PalResult PAL_CALL createQueueD3D12( - PalDevice* device, - PalQueueType type, - PalQueue** outQueue); - -void PAL_CALL destroyQueueD3D12(PalQueue* queue); - -PalResult PAL_CALL waitQueueD3D12(PalQueue* queue); - -PalBool PAL_CALL canQueuePresentD3D12( - PalQueue* queue, - PalSurface* surface); - -// ================================================== -// Formats -// ================================================== - -PalResult PAL_CALL enumerateFormatsD3D12( - PalAdapter* adapter, - int32_t* count, - PalFormatInfo* outFormats); - -PalBool PAL_CALL isFormatSupportedD3D12( - PalAdapter* adapter, - PalFormat format); - -PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( - PalAdapter* adapter, - PalFormat format); - -PalSampleCount PAL_CALL queryFormatSampleCountD3D12( - PalAdapter* adapter, - PalFormat format); - -// ================================================== -// Image -// ================================================== - -PalResult PAL_CALL createImageD3D12( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage); - -void PAL_CALL destroyImageD3D12(PalImage* image); - -PalResult PAL_CALL getImageInfoD3D12( - PalImage* image, - PalImageInfo* info); - -PalResult PAL_CALL getImageMemoryRequirementsD3D12( - PalImage* image, - PalMemoryRequirements* requirements); - -PalResult PAL_CALL bindImageMemoryD3D12( - PalImage* image, - PalMemory* memory, - uint64_t offset); - -PalResult PAL_CALL mapImageMemoryD3D12( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr); - -void PAL_CALL unmapImageMemoryD3D12(PalImage* image); - -// ================================================== -// Image View -// ================================================== - -PalResult PAL_CALL createImageViewD3D12( - PalDevice* device, - PalImage* image, - const PalImageViewCreateInfo* info, - PalImageView** outImageView); - -void PAL_CALL destroyImageViewD3D12(PalImageView* imageView); - -// ================================================== -// Sampler -// ================================================== - -PalResult PAL_CALL createSamplerD3D12( - PalDevice* device, - const PalSamplerCreateInfo* info, - PalSampler** outSampler); - -void PAL_CALL destroySamplerD3D12(PalSampler* sampler); - -// ================================================== -// Surface -// ================================================== - -PalResult PAL_CALL createSurfaceD3D12( - PalDevice* device, - PalGraphicsWindow* window, - PalSurface** outSurface); - -void PAL_CALL destroySurfaceD3D12(PalSurface* surface); - -PalResult PAL_CALL getSurfaceCapabilitiesD3D12( - PalDevice* device, - PalSurface* surface, - PalSurfaceCapabilities* caps); - -// ================================================== -// Swapchain -// ================================================== - -PalResult PAL_CALL createSwapchainD3D12( - PalDevice* device, - PalQueue* queue, - PalSurface* surface, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain); - -void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain); - -PalImage* PAL_CALL getSwapchainImageD3D12( - PalSwapchain* swapchain, - int32_t index); - -PalResult PAL_CALL getNextSwapchainImageD3D12( - PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, - uint32_t* outIndex); - -PalResult PAL_CALL presentSwapchainD3D12( - PalSwapchain* swapchain, - PalSwapchainPresentInfo* info); - -PalResult PAL_CALL resizeSwapchainD3D12( - PalSwapchain* swapchain, - uint32_t newWidth, - uint32_t newHeight); - -// ================================================== -// Shader -// ================================================== - -PalResult PAL_CALL createShaderD3D12( - PalDevice* device, - const PalShaderCreateInfo* info, - PalShader** outShader); - -void PAL_CALL destroyShaderD3D12(PalShader* shader); - -// ================================================== -// Fence -// ================================================== - -PalResult PAL_CALL createFenceD3D12( - PalDevice* device, - PalBool signaled, - PalFence** outFence); - -void PAL_CALL destroyFenceD3D12(PalFence* fence); - -PalResult PAL_CALL waitFenceD3D12( - PalFence* fence, - uint64_t timeout); - -PalResult PAL_CALL resetFenceD3D12(PalFence* fence); - -PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence); - -// ================================================== -// Semaphore -// ================================================== - -PalResult PAL_CALL createSemaphoreD3D12( - PalDevice* device, - PalBool enableTimeline, - PalSemaphore** outSemaphore); - -void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); - -PalResult PAL_CALL waitSemaphoreD3D12( - PalSemaphore* semaphore, - uint64_t value, - uint64_t timeout); - -PalResult PAL_CALL signalSemaphoreD3D12( - PalSemaphore* semaphore, - PalQueue* queue, - uint64_t value); - -PalResult PAL_CALL getSemaphoreValueD3D12( - PalSemaphore* semaphore, - uint64_t* outValue); - -// ================================================== -// Command Pool And Buffer -// ================================================== - -PalResult PAL_CALL createCommandPoolD3D12( - PalDevice* device, - PalQueue* queue, - PalCommandPool** outPool); - -void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool); - -PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool); - -PalResult PAL_CALL allocateCommandBufferD3D12( - PalDevice* device, - PalCommandPool* pool, - PalCommandBufferType type, - PalCommandBuffer** outCmdBuffer); - -void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL submitCommandBufferD3D12( - PalQueue* queue, - PalCommandBufferSubmitInfo* info); - -// ================================================== -// Command Recording -// ================================================== - -PalResult PAL_CALL cmdBeginD3D12( - PalCommandBuffer* cmdBuffer, - PalRenderingLayoutInfo* info); - -PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL cmdExecuteCommandBufferD3D12( - PalCommandBuffer* primaryCmdBuffer, - PalCommandBuffer* secondaryCmdBuffer); - -PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( - PalCommandBuffer* cmdBuffer, - PalFragmentShadingRateState* state); - -PalResult PAL_CALL cmdDrawMeshTasksD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t drawCount); - -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructureBuildInfo* info); - -PalResult PAL_CALL cmdBeginRenderingD3D12( - PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info); - -PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL cmdCopyBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* dst, - PalBuffer* src, - PalBufferCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyBufferToImageD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* dstImage, - PalBuffer* srcBuffer, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyImageD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* dst, - PalImage* src, - PalImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyImageToBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* dstBuffer, - PalImage* srcImage, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdBindPipelineD3D12( - PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline); - -PalResult PAL_CALL cmdSetViewportD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalViewport* viewports); - -PalResult PAL_CALL cmdSetScissorsD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalRect2D* scissors); - -PalResult PAL_CALL cmdBindVertexBuffersD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t firstSlot, - uint32_t count, - PalBuffer** buffers, - uint64_t* offsets); - -PalResult PAL_CALL cmdBindIndexBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint64_t offset, - PalIndexType type); - -PalResult PAL_CALL cmdDrawD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance); - -PalResult PAL_CALL cmdDrawIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - -PalResult PAL_CALL cmdDrawIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdDrawIndexedD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance); - -PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - -PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructure* as, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); - -PalResult PAL_CALL cmdImageBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* image, - PalImageSubresourceRange* subresourceRange, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); - -PalResult PAL_CALL cmdBufferBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo); - -PalResult PAL_CALL cmdDispatchD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDispatchBaseD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDispatchIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer); - -PalResult PAL_CALL cmdTraceRaysD3D12( - PalCommandBuffer* cmdBuffer, - PalShaderBindingTable* sbt, - uint32_t raygenIndex, - uint32_t width, - uint32_t height, - uint32_t depth); - -PalResult PAL_CALL cmdTraceRaysIndirectD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t raygenIndex, - PalShaderBindingTable* sbt, - PalBuffer* buffer); - -PalResult PAL_CALL cmdBindDescriptorSetD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t setIndex, - PalDescriptorSet* set); - -PalResult PAL_CALL cmdPushConstantsD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, - uint32_t offset, - uint32_t size, - const void* value); - -PalResult PAL_CALL cmdSetCullModeD3D12( - PalCommandBuffer* cmdBuffer, - PalCullMode cullMode); - -PalResult PAL_CALL cmdSetFrontFaceD3D12( - PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace); - -PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( - PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology); - -PalResult PAL_CALL cmdSetDepthTestEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -PalResult PAL_CALL cmdSetStencilOpD3D12( - PalCommandBuffer* cmdBuffer, - PalStencilFaceFlags faceMask, - PalStencilOp failOp, - PalStencilOp passOp, - PalStencilOp depthFailOp, - PalCompareOp compareOp); - -// ================================================== -// Acceleration Structure -// ================================================== - -PalResult PAL_CALL createAccelerationstructureD3D12( - PalDevice* device, - const PalAccelerationStructureCreateInfo* info, - PalAccelerationStructure** outAs); +#include "pal_backends_graphics.h" +#include "pal_shared.h" -void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as); - -PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( - PalDevice* device, - PalAccelerationStructureBuildInfo* info, - PalAccelerationStructureBuildSize* size); +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN -// ================================================== -// Buffer -// ================================================== +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX -PalResult PAL_CALL createBufferD3D12( - PalDevice* device, - const PalBufferCreateInfo* info, - PalBuffer** outBuffer); +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE -void PAL_CALL destroyBufferD3D12(PalBuffer* buffer); +#include +#define PLATFORM_SOURCE PAL_RESULT_SOURCE_WINDOWS +#elif defined(__linux__) +#include +#define PLATFORM_SOURCE PAL_RESULT_SOURCE_LINUX +#endif // _WIN32 -PalResult PAL_CALL getBufferMemoryRequirementsD3D12( - PalBuffer* buffer, - PalMemoryRequirements* requirements); +#define MAX_BACKENDS (PAL_MAX_CUSTOM_BACKENDS + 2) +#define PAL_HANDLE(name) \ + struct name { \ + const PalGraphicsVtable* backend; \ + }; -PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( - PalDevice* device, - uint32_t instanceCount, - uint64_t* outSize); +PAL_HANDLE(PalAdapter) +PAL_HANDLE(PalDevice) +PAL_HANDLE(PalQueue) +PAL_HANDLE(PalSwapchain) +PAL_HANDLE(PalImage) +PAL_HANDLE(PalImageView) +PAL_HANDLE(PalShader) +PAL_HANDLE(PalBuffer) -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( - PalDevice* device, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize); +PAL_HANDLE(PalFence) +PAL_HANDLE(PalSemaphore) +PAL_HANDLE(PalCommandPool) +PAL_HANDLE(PalCommandBuffer) +PAL_HANDLE(PalPipeline) +PAL_HANDLE(PalAccelerationStructure) +PAL_HANDLE(PalPipelineLayout) +PAL_HANDLE(PalDescriptorSetLayout) +PAL_HANDLE(PalDescriptorPool) +PAL_HANDLE(PalDescriptorSet) +PAL_HANDLE(PalSampler) +PAL_HANDLE(PalSurface) +PAL_HANDLE(PalShaderBindingTable) -PalResult PAL_CALL writeToInstanceBufferD3D12( - PalDevice* device, - void* ptr, - PalAccelerationStructureInstance* instances, - uint32_t instanceCount); +typedef struct { + int32_t count; + int32_t startIndex; + PalGraphicsVtable base; +} BackendData; -PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( - PalDevice* device, - void* ptr, - void* srcData, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo); +typedef struct { + PalBool initialized; + int32_t backendCount; + const PalAllocator* allocator; + BackendData backends[MAX_BACKENDS]; +} Graphics; -PalResult PAL_CALL bindBufferMemoryD3D12( - PalBuffer* buffer, - PalMemory* memory, - uint64_t offset); +static Graphics s_Graphics = {0}; -PalResult PAL_CALL mapBufferMemoryD3D12( - PalBuffer* buffer, - uint64_t offset, - uint64_t size, - void** outPtr); +static inline uint32_t _ceil( + uint32_t a, + uint32_t b) +{ + return (a + b - 1) / b; +} -void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer); +static inline uint32_t _min( + uint32_t a, + uint32_t b) +{ + return (a < b) ? a : b; +} -PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); +static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) +{ + // clang-format off + if (!vtable1->enumerateAdapters || + !vtable1->getAdapterInfo || + !vtable1->getAdapterCapabilities || + !vtable1->getAdapterFeatures || + !vtable1->getHighestSupportedShaderTarget || -// ================================================== -// Descriptor Pool, Set and Layout -// ================================================== + // device + !vtable1->createDevice || + !vtable1->destroyDevice || -PalResult PAL_CALL createDescriptorSetLayoutD3D12( - PalDevice* device, - const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout); + // memory + !vtable1->allocateMemory || + !vtable1->freeMemory || -void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout); + // extended adapter features + !vtable1->querySamplerAnisotropyCapabilities || + !vtable1->queryMultiViewCapabilities || + !vtable1->queryMultiViewportCapabilities || + !vtable1->queryDepthStencilCapabilities || + !vtable1->queryFragmentShadingRateCapabilities || + !vtable1->queryMeshShaderCapabilities || + !vtable1->queryRayTracingCapabilities || + !vtable1->queryDescriptorIndexingCapabilities || -PalResult PAL_CALL createDescriptorPoolD3D12( - PalDevice* device, - const PalDescriptorPoolCreateInfo* info, - PalDescriptorPool** outPool); + // queue + !vtable1->createQueue || + !vtable1->destroyQueue || + !vtable1->waitQueue || + !vtable1->canQueuePresent || -void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool); + // formats + !vtable1->enumerateFormats || + !vtable1->isFormatSupported || + !vtable1->queryFormatImageUsages || + !vtable1->queryFormatSampleCount || -PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool); + // image + !vtable1->createImage || + !vtable1->destroyImage || + !vtable1->getImageInfo || + !vtable1->getImageMemoryRequirements || + !vtable1->bindImageMemory || + !vtable1->mapImageMemory || + !vtable1->unmapImageMemory || -PalResult PAL_CALL allocateDescriptorSetD3D12( - PalDevice* device, - PalDescriptorPool* pool, - PalDescriptorSetLayout* layout, - PalDescriptorSet** outSet); + // image view + !vtable1->createImageView || + !vtable1->destroyImageView || -PalResult PAL_CALL updateDescriptorSetD3D12( - PalDevice* device, - uint32_t count, - PalDescriptorSetWriteInfo* infos); + // sampler + !vtable1->createSampler || + !vtable1->destroySampler || -// ================================================== -// Pipeline Layout -// ================================================== + // surface + !vtable1->createSurface || + !vtable1->destroySurface || + !vtable1->getSurfaceCapabilities || -PalResult PAL_CALL createPipelineLayoutD3D12( - PalDevice* device, - const PalPipelineLayoutCreateInfo* info, - PalPipelineLayout** outLayout); + // swapchain + !vtable1->createSwapchain || + !vtable1->destroySwapchain || + !vtable1->getSwapchainImage || + !vtable1->getNextSwapchainImage || + !vtable1->presentSwapchain || + !vtable1->resizeSwapchain || -void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout); + // shader + !vtable1->createShader || + !vtable1->destroyShader || -// ================================================== -// Pipeline -// ================================================== + // fence + !vtable1->createFence || + !vtable1->destroyFence || + !vtable1->waitFence || + !vtable1->resetFence || + !vtable1->isFenceSignaled || -PalResult PAL_CALL createGraphicsPipelineD3D12( - PalDevice* device, - const PalGraphicsPipelineCreateInfo* info, - PalPipeline** outPipeline); + // semaphore + !vtable1->createSemaphore || + !vtable1->destroySemaphore || + !vtable1->waitSemaphore || + !vtable1->signalSemaphore || + !vtable1->getSemaphoreValue || -PalResult PAL_CALL createComputePipelineD3D12( - PalDevice* device, - const PalComputePipelineCreateInfo* info, - PalPipeline** outPipeline); + // command pool and command buffer + !vtable1->createCommandPool || + !vtable1->destroyCommandPool || + !vtable1->resetCommandPool || + !vtable1->allocateCommandBuffer || + !vtable1->freeCommandBuffer || + !vtable1->submitCommandBuffer || -PalResult PAL_CALL createRayTracingPipelineD3D12( - PalDevice* device, - const PalRayTracingPipelineCreateInfo* info, - PalPipeline** outPipeline); + // command recording + !vtable1->cmdBegin || + !vtable1->cmdEnd || + !vtable1->resetCommandBuffer || + !vtable1->cmdExecuteCommandBuffer || + !vtable1->cmdSetFragmentShadingRate || + !vtable1->cmdDrawMeshTasks || + !vtable1->cmdDrawMeshTasksIndirect || + !vtable1->cmdDrawMeshTasksIndirectCount || + !vtable1->cmdBuildAccelerationStructure || + !vtable1->cmdBeginRendering || + !vtable1->cmdEndRendering || + !vtable1->cmdCopyBuffer || + !vtable1->cmdCopyBufferToImage || + !vtable1->cmdCopyImage || + !vtable1->cmdCopyImageToBuffer || + !vtable1->cmdBindPipeline || + !vtable1->cmdSetViewport || + !vtable1->cmdSetScissors || + !vtable1->cmdBindVertexBuffers || + !vtable1->cmdBindIndexBuffer || + !vtable1->cmdDraw || + !vtable1->cmdDrawIndirect || + !vtable1->cmdDrawIndirectCount || + !vtable1->cmdDrawIndexed || + !vtable1->cmdDrawIndexedIndirect || + !vtable1->cmdDrawIndexedIndirectCount || + !vtable1->cmdAccelerationStructureBarrier || + !vtable1->cmdImageBarrier || + !vtable1->cmdBufferBarrier || + !vtable1->cmdDispatch || + !vtable1->cmdDispatchBase || + !vtable1->cmdDispatchIndirect || + !vtable1->cmdTraceRays || + !vtable1->cmdTraceRaysIndirect || + !vtable1->cmdBindDescriptorSet || + !vtable1->cmdPushConstants || + !vtable1->cmdSetCullMode || + !vtable1->cmdSetFrontFace || + !vtable1->cmdSetPrimitiveTopology || + !vtable1->cmdSetDepthTestEnable || + !vtable1->cmdSetDepthWriteEnable || + !vtable1->cmdSetStencilOp || -void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline); + // acceleration structure + !vtable1->createAccelerationstructure || + !vtable1->destroyAccelerationstructure || + !vtable1->getAccelerationStructureBuildSize || -// ================================================== -// Shader Binding Table -// ================================================== + // buffer + !vtable1->createBuffer || + !vtable1->destroyBuffer || + !vtable1->getBufferMemoryRequirements || + !vtable1->computeInstanceBufferRequirements || + !vtable1->computeImageCopyStagingBufferRequirements || + !vtable1->writeToInstanceBuffer || + !vtable1->writeToImageCopyStagingBuffer || + !vtable1->bindBufferMemory || + !vtable1->getBufferDeviceAddress || + !vtable1->mapBufferMemory || + !vtable1->unmapBufferMemory || + + // descriptors + !vtable1->createDescriptorSetLayout || + !vtable1->destroyDescriptorSetLayout || + !vtable1->createDescriptorPool || + !vtable1->destroyDescriptorPool || + !vtable1->resetDescriptorPool || + !vtable1->allocateDescriptorSet || + !vtable1->updateDescriptorSet || -PalResult PAL_CALL createShaderBindingTableD3D12( - PalDevice* device, - const PalShaderBindingTableCreateInfo* info, - PalShaderBindingTable** outSbt); + // pipeline layout + !vtable1->createPipelineLayout || + !vtable1->destroyPipelineLayout || -void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); + // pipeline + !vtable1->createGraphicsPipeline || + !vtable1->createComputePipeline || + !vtable1->createRayTracingPipeline || + !vtable1->destroyPipeline || -PalResult PAL_CALL updateShaderBindingTableD3D12( - PalShaderBindingTable* sbt, - uint32_t count, - PalShaderBindingTableRecordInfo* infos); + // shader binding table + !vtable1->createShaderBindingTable || + !vtable1->destroyShaderBindingTable || + !vtable1->updateShaderBindingTable) { + return PAL_FALSE; + } + // clang-format on + return PAL_TRUE; +} -static PalGraphicsBackend s_D3D12Backend = { - // adapter - .enumerateAdapters = enumerateAdaptersD3D12, - .getAdapterInfo = getAdapterInfoD3D12, - .getAdapterCapabilities = getAdapterCapabilitiesD3D12, - .getAdapterFeatures = getAdapterFeaturesD3D12, - .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetD3D12, +static void populateVtableVersion1( + PalGraphicsVtable* vtable, + const PalGraphicsBackendVtable1* vtable1) +{ + // clang-format off + vtable->enumerateAdapters = vtable1->enumerateAdapters; + vtable->getAdapterInfo = vtable1->getAdapterInfo; + vtable->getAdapterCapabilities = vtable1->getAdapterCapabilities; + vtable->getAdapterFeatures = vtable1->getAdapterFeatures; + vtable->getHighestSupportedShaderTarget = vtable1->getHighestSupportedShaderTarget; // device - .createDevice = createDeviceD3D12, - .destroyDevice = destroyDeviceD3D12, + vtable->createDevice = vtable1->createDevice; + vtable->destroyDevice = vtable1->destroyDevice; // memory - .allocateMemory = allocateMemoryD3D12, - .freeMemory = freeMemoryD3D12, + vtable->allocateMemory = vtable1->allocateMemory; + vtable->freeMemory = vtable1->freeMemory; // extended adapter features - .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesD3D12, - .queryMultiViewCapabilities = queryMultiViewCapabilitiesD3D12, - .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesD3D12, - .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesD3D12, - .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesD3D12, - .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesD3D12, - .queryRayTracingCapabilities = queryRayTracingCapabilitiesD3D12, - .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesD3D12, + vtable->querySamplerAnisotropyCapabilities = vtable1->querySamplerAnisotropyCapabilities; + vtable->queryMultiViewCapabilities = vtable1->queryMultiViewCapabilities; + vtable->queryMultiViewportCapabilities = vtable1->queryMultiViewportCapabilities; + vtable->queryDepthStencilCapabilities = vtable1->queryDepthStencilCapabilities; + vtable->queryFragmentShadingRateCapabilities = vtable1->queryFragmentShadingRateCapabilities; + vtable->queryMeshShaderCapabilities = vtable1->queryMeshShaderCapabilities; + vtable->queryRayTracingCapabilities = vtable1->queryRayTracingCapabilities; + vtable->queryDescriptorIndexingCapabilities = vtable1->queryDescriptorIndexingCapabilities; // queue - .createQueue = createQueueD3D12, - .destroyQueue = destroyQueueD3D12, - .waitQueue = waitQueueD3D12, - .canQueuePresent = canQueuePresentD3D12, + vtable->createQueue = vtable1->createQueue; + vtable->destroyQueue = vtable1->destroyQueue; + vtable->waitQueue = vtable1->waitQueue; + vtable->canQueuePresent = vtable1->canQueuePresent; - // format - .enumerateFormats = enumerateFormatsD3D12, - .isFormatSupported = isFormatSupportedD3D12, - .queryFormatImageUsages = queryFormatImageUsagesD3D12, - .queryFormatSampleCount = queryFormatSampleCountD3D12, + // formats + vtable->enumerateFormats = vtable1->enumerateFormats; + vtable->isFormatSupported = vtable1->isFormatSupported; + vtable->queryFormatImageUsages = vtable1->queryFormatImageUsages; + vtable->queryFormatSampleCount = vtable1->queryFormatSampleCount; // image - .createImage = createImageD3D12, - .destroyImage = destroyImageD3D12, - .getImageInfo = getImageInfoD3D12, - .getImageMemoryRequirements = getImageMemoryRequirementsD3D12, - .bindImageMemory = bindImageMemoryD3D12, - .mapImageMemory = mapImageMemoryD3D12, - .unmapImageMemory = unmapImageMemoryD3D12, + vtable->createImage = vtable1->createImage; + vtable->destroyImage = vtable1->destroyImage; + vtable->getImageInfo = vtable1->getImageInfo; + vtable->getImageMemoryRequirements = vtable1->getImageMemoryRequirements; + vtable->bindImageMemory = vtable1->bindImageMemory; + vtable->mapImageMemory = vtable1->mapImageMemory; + vtable->unmapImageMemory = vtable1->unmapImageMemory; // image view - .createImageView = createImageViewD3D12, - .destroyImageView = destroyImageViewD3D12, + vtable->createImageView = vtable1->createImageView; + vtable->destroyImageView = vtable1->destroyImageView; // sampler - .createSampler = createSamplerD3D12, - .destroySampler = destroySamplerD3D12, + vtable->createSampler = vtable1->createSampler; + vtable->destroySampler = vtable1->destroySampler; // surface - .createSurface = createSurfaceD3D12, - .destroySurface = destroySurfaceD3D12, - .getSurfaceCapabilities = getSurfaceCapabilitiesD3D12, + vtable->createSurface = vtable1->createSurface; + vtable->destroySurface = vtable1->destroySurface; + vtable->getSurfaceCapabilities = vtable1->getSurfaceCapabilities; // swapchain - .createSwapchain = createSwapchainD3D12, - .destroySwapchain = destroySwapchainD3D12, - .getSwapchainImage = getSwapchainImageD3D12, - .getNextSwapchainImage = getNextSwapchainImageD3D12, - .presentSwapchain = presentSwapchainD3D12, - .resizeSwapchain = resizeSwapchainD3D12, + vtable->createSwapchain = vtable1->createSwapchain; + vtable->destroySwapchain = vtable1->destroySwapchain; + vtable->getSwapchainImage = vtable1->getSwapchainImage; + vtable->getNextSwapchainImage = vtable1->getNextSwapchainImage; + vtable->presentSwapchain = vtable1->presentSwapchain; + vtable->resizeSwapchain = vtable1->resizeSwapchain; // shader - .createShader = createShaderD3D12, - .destroyShader = destroyShaderD3D12, + vtable->createShader = vtable1->createShader; + vtable->destroyShader = vtable1->destroyShader; // fence - .createFence = createFenceD3D12, - .destroyFence = destroyFenceD3D12, - .waitFence = waitFenceD3D12, - .resetFence = resetFenceD3D12, - .isFenceSignaled = isFenceSignaledD3D12, + vtable->createFence = vtable1->createFence; + vtable->destroyFence = vtable1->destroyFence; + vtable->waitFence = vtable1->waitFence; + vtable->resetFence = vtable1->resetFence; + vtable->isFenceSignaled = vtable1->isFenceSignaled; // semaphore - .createSemaphore = createSemaphoreD3D12, - .destroySemaphore = destroySemaphoreD3D12, - .waitSemaphore = waitSemaphoreD3D12, - .signalSemaphore = signalSemaphoreD3D12, - .getSemaphoreValue = getSemaphoreValueD3D12, + vtable->createSemaphore = vtable1->createSemaphore; + vtable->destroySemaphore = vtable1->destroySemaphore; + vtable->waitSemaphore = vtable1->waitSemaphore; + vtable->signalSemaphore = vtable1->signalSemaphore; + vtable->getSemaphoreValue = vtable1->getSemaphoreValue; // command pool and command buffer - .createCommandPool = createCommandPoolD3D12, - .destroyCommandPool = destroyCommandPoolD3D12, - .resetCommandPool = resetCommandPoolD3D12, - .allocateCommandBuffer = allocateCommandBufferD3D12, - .freeCommandBuffer = freeCommandBufferD3D12, - .resetCommandBuffer = resetCommandBufferD3D12, - .submitCommandBuffer = submitCommandBufferD3D12, + vtable->createCommandPool = vtable1->createCommandPool; + vtable->destroyCommandPool = vtable1->destroyCommandPool; + vtable->resetCommandPool = vtable1->resetCommandPool; + vtable->allocateCommandBuffer = vtable1->allocateCommandBuffer; + vtable->freeCommandBuffer = vtable1->freeCommandBuffer; + vtable->submitCommandBuffer = vtable1->submitCommandBuffer; // command recording - .cmdBegin = cmdBeginD3D12, - .cmdEnd = cmdEndD3D12, - .cmdExecuteCommandBuffer = cmdExecuteCommandBufferD3D12, - .cmdSetFragmentShadingRate = cmdSetFragmentShadingRateD3D12, - .cmdDrawMeshTasks = cmdDrawMeshTasksD3D12, - .cmdDrawMeshTasksIndirect = cmdDrawMeshTasksIndirectD3D12, - .cmdDrawMeshTasksIndirectCount = cmdDrawMeshTasksIndirectCountD3D12, - .cmdBuildAccelerationStructure = cmdBuildAccelerationStructureD3D12, - .cmdBeginRendering = cmdBeginRenderingD3D12, - .cmdEndRendering = cmdEndRenderingD3D12, - .cmdCopyBuffer = cmdCopyBufferD3D12, - .cmdCopyBufferToImage = cmdCopyBufferToImageD3D12, - .cmdCopyImage = cmdCopyImageD3D12, - .cmdCopyImageToBuffer = cmdCopyImageToBufferD3D12, - .cmdBindPipeline = cmdBindPipelineD3D12, - .cmdSetViewport = cmdSetViewportD3D12, - .cmdSetScissors = cmdSetScissorsD3D12, - .cmdBindVertexBuffers = cmdBindVertexBuffersD3D12, - .cmdBindIndexBuffer = cmdBindIndexBufferD3D12, - .cmdDraw = cmdDrawD3D12, - .cmdDrawIndirect = cmdDrawIndirectD3D12, - .cmdDrawIndirectCount = cmdDrawIndirectCountD3D12, - .cmdDrawIndexed = cmdDrawIndexedD3D12, - .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectD3D12, - .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountD3D12, - .cmdAccelerationStructureBarrier = cmdAccelerationStructureBarrierD3D12, - .cmdImageBarrier = cmdImageBarrierD3D12, - .cmdBufferBarrier = cmdBufferBarrierD3D12, - .cmdDispatch = cmdDispatchD3D12, - .cmdDispatchBase = cmdDispatchBaseD3D12, - .cmdDispatchIndirect = cmdDispatchIndirectD3D12, - .cmdTraceRays = cmdTraceRaysD3D12, - .cmdTraceRaysIndirect = cmdTraceRaysIndirectD3D12, - .cmdBindDescriptorSet = cmdBindDescriptorSetD3D12, - .cmdPushConstants = cmdPushConstantsD3D12, - .cmdSetCullMode = cmdSetCullModeD3D12, - .cmdSetFrontFace = cmdSetFrontFaceD3D12, - .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyD3D12, - .cmdSetDepthTestEnable = cmdSetDepthTestEnableD3D12, - .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableD3D12, - .cmdSetStencilOp = cmdSetStencilOpD3D12, + vtable->cmdBegin = vtable1->cmdBegin; + vtable->cmdEnd = vtable1->cmdEnd; + vtable->resetCommandBuffer = vtable1->resetCommandBuffer; + vtable->cmdExecuteCommandBuffer = vtable1->cmdExecuteCommandBuffer; + vtable->cmdSetFragmentShadingRate = vtable1->cmdSetFragmentShadingRate; + vtable->cmdDrawMeshTasks = vtable1->cmdDrawMeshTasks; + vtable->cmdDrawMeshTasksIndirect = vtable1->cmdDrawMeshTasksIndirect; + vtable->cmdDrawMeshTasksIndirectCount = vtable1->cmdDrawMeshTasksIndirectCount; + vtable->cmdBuildAccelerationStructure = vtable1->cmdBuildAccelerationStructure; + vtable->cmdBeginRendering = vtable1->cmdBeginRendering; + vtable->cmdEndRendering = vtable1->cmdEndRendering; + vtable->cmdCopyBuffer = vtable1->cmdCopyBuffer; + vtable->cmdCopyBufferToImage = vtable1->cmdCopyBufferToImage; + vtable->cmdCopyImage = vtable1->cmdCopyImage; + vtable->cmdCopyImageToBuffer = vtable1->cmdCopyImageToBuffer; + vtable->cmdBindPipeline = vtable1->cmdBindPipeline; + vtable->cmdSetViewport = vtable1->cmdSetViewport; + vtable->cmdSetScissors = vtable1->cmdSetScissors; + vtable->cmdBindVertexBuffers = vtable1->cmdBindVertexBuffers; + vtable->cmdBindIndexBuffer = vtable1->cmdBindIndexBuffer; + vtable->cmdDraw = vtable1->cmdDraw; + vtable->cmdDrawIndirect = vtable1->cmdDrawIndirect; + vtable->cmdDrawIndirectCount = vtable1->cmdDrawIndirectCount; + vtable->cmdDrawIndexed = vtable1->cmdDrawIndexed; + vtable->cmdDrawIndexedIndirect = vtable1->cmdDrawIndexedIndirect; + vtable->cmdDrawIndexedIndirectCount = vtable1->cmdDrawIndexedIndirectCount; + vtable->cmdAccelerationStructureBarrier = vtable1->cmdAccelerationStructureBarrier; + vtable->cmdImageBarrier = vtable1->cmdImageBarrier; + vtable->cmdBufferBarrier = vtable1->cmdBufferBarrier; + vtable->cmdDispatch = vtable1->cmdDispatch; + vtable->cmdDispatchBase = vtable1->cmdDispatchBase; + vtable->cmdDispatchIndirect = vtable1->cmdDispatchIndirect; + vtable->cmdTraceRays = vtable1->cmdTraceRays; + vtable->cmdTraceRaysIndirect = vtable1->cmdTraceRaysIndirect; + vtable->cmdBindDescriptorSet = vtable1->cmdBindDescriptorSet; + vtable->cmdPushConstants = vtable1->cmdPushConstants; + vtable->cmdSetCullMode = vtable1->cmdSetCullMode; + vtable->cmdSetFrontFace = vtable1->cmdSetFrontFace; + vtable->cmdSetPrimitiveTopology = vtable1->cmdSetPrimitiveTopology; + vtable->cmdSetDepthTestEnable = vtable1->cmdSetDepthTestEnable; + vtable->cmdSetDepthWriteEnable = vtable1->cmdSetDepthWriteEnable; + vtable->cmdSetStencilOp = vtable1->cmdSetStencilOp; // acceleration structure - .createAccelerationstructure = createAccelerationstructureD3D12, - .destroyAccelerationstructure = destroyAccelerationstructureD3D12, - .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeD3D12, + vtable->createAccelerationstructure = vtable1->createAccelerationstructure; + vtable->destroyAccelerationstructure = vtable1->destroyAccelerationstructure; + vtable->getAccelerationStructureBuildSize = vtable1->getAccelerationStructureBuildSize; // buffer - .createBuffer = createBufferD3D12, - .destroyBuffer = destroyBufferD3D12, - .getBufferMemoryRequirements = getBufferMemoryRequirementsD3D12, - .computeInstanceBufferRequirements = computeInstanceBufferRequirementsD3D12, - .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsD3D12, - .writeToInstanceBuffer = writeToInstanceBufferD3D12, - .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferD3D12, - .bindBufferMemory = bindBufferMemoryD3D12, - .getBufferDeviceAddress = getBufferDeviceAddressD3D12, - .mapBufferMemory = mapBufferMemoryD3D12, - .unmapBufferMemory = unmapBufferMemoryD3D12, - - // descriptor set layout, descriptor pool and descriptor set - .createDescriptorSetLayout = createDescriptorSetLayoutD3D12, - .destroyDescriptorSetLayout = destroyDescriptorSetLayoutD3D12, - .createDescriptorPool = createDescriptorPoolD3D12, - .destroyDescriptorPool = destroyDescriptorPoolD3D12, - .resetDescriptorPool = resetDescriptorPoolD3D12, - .allocateDescriptorSet = allocateDescriptorSetD3D12, - .updateDescriptorSet = updateDescriptorSetD3D12, + vtable->createBuffer = vtable1->createBuffer; + vtable->destroyBuffer = vtable1->destroyBuffer; + vtable->getBufferMemoryRequirements = vtable1->getBufferMemoryRequirements; + vtable->computeInstanceBufferRequirements = vtable1->computeInstanceBufferRequirements; + vtable->computeImageCopyStagingBufferRequirements = vtable1->computeImageCopyStagingBufferRequirements; + vtable->writeToInstanceBuffer = vtable1->writeToInstanceBuffer; + + vtable->writeToImageCopyStagingBuffer = vtable1->writeToImageCopyStagingBuffer; + vtable->bindBufferMemory = vtable1->bindBufferMemory; + vtable->getBufferDeviceAddress = vtable1->getBufferDeviceAddress; + vtable->mapBufferMemory = vtable1->mapBufferMemory; + vtable->unmapBufferMemory = vtable1->unmapBufferMemory; + + // descriptors + vtable->createDescriptorSetLayout = vtable1->createDescriptorSetLayout; + vtable->destroyDescriptorSetLayout = vtable1->destroyDescriptorSetLayout; + vtable->createDescriptorPool = vtable1->createDescriptorPool; + vtable->destroyDescriptorPool = vtable1->destroyDescriptorPool; + vtable->resetDescriptorPool = vtable1->resetDescriptorPool; + vtable->allocateDescriptorSet = vtable1->allocateDescriptorSet; + vtable->updateDescriptorSet = vtable1->updateDescriptorSet; // pipeline layout - .createPipelineLayout = createPipelineLayoutD3D12, - .destroyPipelineLayout = destroyPipelineLayoutD3D12, + vtable->createPipelineLayout = vtable1->createPipelineLayout; + vtable->destroyPipelineLayout = vtable1->destroyPipelineLayout; // pipeline - .createGraphicsPipeline = createGraphicsPipelineD3D12, - .createComputePipeline = createComputePipelineD3D12, - .createRayTracingPipeline = createRayTracingPipelineD3D12, - .destroyPipeline = destroyPipelineD3D12, - - // shader binding tables - .createShaderBindingTable = createShaderBindingTableD3D12, - .destroyShaderBindingTable = destroyShaderBindingTableD3D12, - .updateShaderBindingTable = updateShaderBindingTableD3D12}; + vtable->createGraphicsPipeline = vtable1->createGraphicsPipeline; + vtable->createComputePipeline = vtable1->createComputePipeline; + vtable->createRayTracingPipeline = vtable1->createRayTracingPipeline; + vtable->destroyPipeline = vtable1->destroyPipeline; -#endif // PAL_HAS_D3D12_BACKEND + // shader binding table + vtable->createShaderBindingTable = vtable1->createShaderBindingTable; + vtable->destroyShaderBindingTable = vtable1->destroyShaderBindingTable; + vtable->updateShaderBindingTable = vtable1->updateShaderBindingTable; + // clang-format on +} -// ================================================== -// Metal API -// ================================================== +static void addBackend(PalGraphicsBackendInfo* backendInfo) +{ + BackendData* backendData = &s_Graphics.backends[s_Graphics.backendCount++]; + backendData->startIndex = 0; + backendData->count = 0; -// ================================================== -// Public API -// ================================================== + // populate our internal vtable + if (backendInfo->version == PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1) { + // validate that all version 1 pointers are set + const PalGraphicsBackendVtable1* vtable1 = (PalGraphicsBackendVtable1*)backendInfo->vtable; + validateVtableVersion1(vtable1); -PalResult PAL_CALL palAddGraphicsBackend(const PalGraphicsBackend* backend) -{ - if (s_Graphics.initialized) { - return PAL_RESULT_INVALID_BACKEND; + memset(&backendData->base, 0, sizeof(PalGraphicsVtable)); + populateVtableVersion1(&backendData->base, vtable1); } +} +static inline uint32_t getLastErrorCode() +{ #ifdef _WIN32 - // we reserve two slots for vulkan and d3d12 - if (s_Graphics.backendCount == MAX_BACKENDS - 2) { - return PAL_RESULT_INVALID_BACKEND; - } -#else - // we reserve one slot for vulkan or metal depending on platform - if (s_Graphics.backendCount == MAX_BACKENDS - 1) { - return PAL_RESULT_INVALID_BACKEND; - } + return (uint32_t)GetLastError(); +#elif defined(__linux__) + return (uint32_t)errno; #endif // _WIN32 - - // check if all the function pointers are set - // clang-format off - // adapter - if (!backend->enumerateAdapters || - !backend->getAdapterInfo || - !backend->getAdapterCapabilities || - !backend->getAdapterFeatures || - !backend->getHighestSupportedShaderTarget || - - // device - !backend->createDevice || - !backend->destroyDevice || - - // memory - !backend->allocateMemory || - !backend->freeMemory || - - // extended adapter features - !backend->querySamplerAnisotropyCapabilities || - !backend->queryMultiViewCapabilities || - !backend->queryMultiViewportCapabilities || - !backend->queryDepthStencilCapabilities || - !backend->queryFragmentShadingRateCapabilities || - !backend->queryMeshShaderCapabilities || - !backend->queryRayTracingCapabilities || - !backend->queryDescriptorIndexingCapabilities || - - // queue - !backend->createQueue || - !backend->destroyQueue || - !backend->waitQueue || - !backend->canQueuePresent || - - // formats - !backend->enumerateFormats || - !backend->isFormatSupported || - !backend->queryFormatImageUsages || - !backend->queryFormatSampleCount || - - // image - !backend->createImage || - !backend->destroyImage || - !backend->getImageInfo || - !backend->getImageMemoryRequirements || - !backend->bindImageMemory || - !backend->mapImageMemory || - !backend->unmapImageMemory || - - // image view - !backend->createImageView || - !backend->destroyImageView || - - // sampler - !backend->createSampler || - !backend->destroySampler || - - // surface - !backend->createSurface || - !backend->destroySurface || - !backend->getSurfaceCapabilities || - - // swapchain - !backend->createSwapchain || - !backend->destroySwapchain || - !backend->getSwapchainImage || - !backend->getNextSwapchainImage || - !backend->presentSwapchain || - !backend->resizeSwapchain || - - // shader - !backend->createShader || - !backend->destroyShader || - - // fence - !backend->createFence || - !backend->destroyFence || - !backend->waitFence || - !backend->resetFence || - !backend->isFenceSignaled || - - // semaphore - !backend->createSemaphore || - !backend->destroySemaphore || - !backend->waitSemaphore || - !backend->signalSemaphore || - !backend->getSemaphoreValue || - - // command pool and command buffer - !backend->createCommandPool || - !backend->destroyCommandPool || - !backend->resetCommandPool || - !backend->allocateCommandBuffer || - !backend->freeCommandBuffer || - !backend->submitCommandBuffer || - - // command recording - !backend->cmdBegin || - !backend->cmdEnd || - !backend->resetCommandBuffer || - !backend->cmdExecuteCommandBuffer || - !backend->cmdSetFragmentShadingRate || - !backend->cmdDrawMeshTasks || - !backend->cmdDrawMeshTasksIndirect || - !backend->cmdDrawMeshTasksIndirectCount || - !backend->cmdBuildAccelerationStructure || - !backend->cmdBeginRendering || - !backend->cmdEndRendering || - !backend->cmdCopyBuffer || - !backend->cmdCopyBufferToImage || - !backend->cmdCopyImage || - !backend->cmdCopyImageToBuffer || - !backend->cmdBindPipeline || - !backend->cmdSetViewport || - !backend->cmdSetScissors || - !backend->cmdBindVertexBuffers || - !backend->cmdBindIndexBuffer || - !backend->cmdDraw || - !backend->cmdDrawIndirect || - !backend->cmdDrawIndirectCount || - !backend->cmdDrawIndexed || - !backend->cmdDrawIndexedIndirect || - !backend->cmdDrawIndexedIndirectCount || - !backend->cmdAccelerationStructureBarrier || - !backend->cmdImageBarrier || - !backend->cmdBufferBarrier || - !backend->cmdDispatch || - !backend->cmdDispatchBase || - !backend->cmdDispatchIndirect || - !backend->cmdTraceRays || - !backend->cmdTraceRaysIndirect || - !backend->cmdBindDescriptorSet || - !backend->cmdPushConstants || - !backend->cmdSetCullMode || - !backend->cmdSetFrontFace || - !backend->cmdSetPrimitiveTopology || - !backend->cmdSetDepthTestEnable || - !backend->cmdSetDepthWriteEnable || - !backend->cmdSetStencilOp || - - // acceleration structure - !backend->createAccelerationstructure || - !backend->destroyAccelerationstructure || - !backend->getAccelerationStructureBuildSize || - - // buffer - !backend->createBuffer || - !backend->destroyBuffer || - !backend->getBufferMemoryRequirements || - !backend->computeInstanceBufferRequirements || - !backend->computeImageCopyStagingBufferRequirements || - !backend->writeToInstanceBuffer || - !backend->writeToImageCopyStagingBuffer || - !backend->bindBufferMemory || - !backend->getBufferDeviceAddress || - !backend->mapBufferMemory || - !backend->unmapBufferMemory || - - // descriptor set layout, descriptor pool and descriptor set - !backend->createDescriptorSetLayout || - !backend->destroyDescriptorSetLayout || - !backend->createDescriptorPool || - !backend->destroyDescriptorPool || - !backend->resetDescriptorPool || - !backend->allocateDescriptorSet || - !backend->updateDescriptorSet || - - // pipeline layout - !backend->createPipelineLayout || - !backend->destroyPipelineLayout || - - // pipeline - !backend->createGraphicsPipeline || - !backend->createComputePipeline || - !backend->createRayTracingPipeline || - !backend->destroyPipeline || - - // shader binding table - !backend->createShaderBindingTable || - !backend->destroyShaderBindingTable || - !backend->updateShaderBindingTable) { - return PAL_RESULT_INVALID_BACKEND; - } - // clang-format on - - BackendData* attached = &s_Graphics.backends[s_Graphics.backendCount++]; - attached->base = backend; - attached->startIndex = 0; - attached->count = 0; - - return PAL_RESULT_SUCCESS; } PalResult PAL_CALL palInitGraphics( const PalGraphicsDebugger* debugger, - const PalAllocator* allocator) + const PalAllocator* allocator, + uint32_t customBackendCount, + const PalGraphicsBackendInfo* customBackends) { if (s_Graphics.initialized) { return PAL_RESULT_SUCCESS; } if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_INVALID_ALLOCATOR; + return palMakeResult( + PAL_RESULT_INVALID_ARGUMENT, + PLATFORM_SOURCE, + getLastErrorCode()); } PalResult result; @@ -2157,15 +594,11 @@ PalResult PAL_CALL palEnumerateAdapters( { // enumerate all adapters for both custom and PAL backends if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!count) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } - if (*count == 0 && outAdapters) { - return PAL_RESULT_INSUFFICIENT_BUFFER; + if (!count || *count == 0 && outAdapters) { + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -2179,7 +612,7 @@ PalResult PAL_CALL palEnumerateAdapters( // offset into the array so all backends write at the correct index PalAdapter** adapters = &outAdapters[backend->startIndex]; _count = backend->count; - result = backend->base->enumerateAdapters(&_count, adapters); + result = backend->base.enumerateAdapters(&_count, adapters); // break if a backend fails if (result != PAL_RESULT_SUCCESS) { return result; @@ -2187,11 +620,11 @@ PalResult PAL_CALL palEnumerateAdapters( for (int j = 0; j < _count; j++) { PalAdapter* tmp = adapters[j]; - adapters[j]->backend = backend->base; + adapters[j]->backend = &backend->base; } } else { - result = backend->base->enumerateAdapters(&_count, nullptr); + result = backend->base.enumerateAdapters(&_count, nullptr); // break if a backend fails if (result != PAL_RESULT_SUCCESS) { return result; @@ -2215,11 +648,11 @@ PalResult PAL_CALL palGetAdapterInfo( PalAdapterInfo* info) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!adapter || !info) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return adapter->backend->getAdapterInfo(adapter, info); @@ -2230,11 +663,11 @@ PalResult PAL_CALL palGetAdapterCapabilities( PalAdapterCapabilities* caps) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!adapter || !caps) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return adapter->backend->getAdapterCapabilities(adapter, caps); @@ -2250,7 +683,7 @@ PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) } uint32_t PAL_CALL palGetHighestSupportedShaderTarget( - PalAdapter* adapter, + PalAdapter* adapter, PalShaderFormats shaderFormat) { if (!s_Graphics.initialized || !adapter) { @@ -2269,11 +702,11 @@ PalResult PAL_CALL palCreateDevice( PalDevice** outDevice) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!outDevice) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalDevice* device = nullptr; @@ -2303,11 +736,11 @@ PalResult PAL_CALL palAllocateMemory( PalMemory** outMemory) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!outMemory || !device) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->allocateMemory(device, type, memoryMask, size, outMemory); @@ -2331,11 +764,11 @@ PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( PalSamplerAnisotropyCapabilities* caps) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !caps) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->querySamplerAnisotropyCapabilities(device, caps); @@ -2346,11 +779,11 @@ PalResult PAL_CALL palQueryMultiViewCapabilities( PalMultiViewCapabilities* caps) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !caps) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->queryMultiViewCapabilities(device, caps); @@ -2361,11 +794,11 @@ PalResult PAL_CALL palQueryMultiViewportCapabilities( PalMultiViewportCapabilities* caps) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !caps) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->queryMultiViewportCapabilities(device, caps); @@ -2376,11 +809,11 @@ PalResult PAL_CALL palQueryDepthStencilCapabilities( PalDepthStencilCapabilities* caps) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !caps) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->queryDepthStencilCapabilities(device, caps); @@ -2391,11 +824,11 @@ PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( PalFragmentShadingRateCapabilities* caps) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !caps) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->queryFragmentShadingRateCapabilities(device, caps); @@ -2406,11 +839,11 @@ PalResult PAL_CALL palQueryMeshShaderCapabilities( PalMeshShaderCapabilities* caps) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !caps) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->queryMeshShaderCapabilities(device, caps); @@ -2421,11 +854,11 @@ PalResult PAL_CALL palQueryRayTracingCapabilities( PalRayTracingCapabilities* caps) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !caps) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->queryRayTracingCapabilities(device, caps); @@ -2436,11 +869,11 @@ PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( PalDescriptorIndexingCapabilities* caps) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !caps) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->queryDescriptorIndexingCapabilities(device, caps); @@ -2456,11 +889,11 @@ PalResult PAL_CALL palCreateQueue( PalQueue** outQueue) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !outQueue) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalQueue* queue = nullptr; @@ -2495,11 +928,11 @@ PalBool PAL_CALL palCanQueuePresent( PalResult PAL_CALL palWaitQueue(PalQueue* queue) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!queue) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return queue->backend->waitQueue(queue); @@ -2515,15 +948,11 @@ PalResult PAL_CALL palEnumerateFormats( PalFormatInfo* outFormats) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!adapter || !count) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } - if (*count == 0 && outFormats) { - return PAL_RESULT_INSUFFICIENT_BUFFER; + if (!adapter || !count || *count == 0 && outFormats) { + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return adapter->backend->enumerateFormats(adapter, count, outFormats); @@ -2572,11 +1001,11 @@ PalResult PAL_CALL palCreateImage( PalImage** outImage) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outImage) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalImage* image = nullptr; @@ -2603,11 +1032,11 @@ PalResult PAL_CALL palGetImageInfo( PalImageInfo* info) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!image || !info) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return image->backend->getImageInfo(image, info); @@ -2618,11 +1047,11 @@ PalResult PAL_CALL palGetImageMemoryRequirements( PalMemoryRequirements* requirements) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!image) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return image->backend->getImageMemoryRequirements(image, requirements); @@ -2634,11 +1063,11 @@ PalResult PAL_CALL palBindImageMemory( uint64_t offset) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!image || !memory) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return image->backend->bindImageMemory(image, memory, offset); @@ -2651,11 +1080,11 @@ PalResult PAL_CALL palMapImageMemory( void** outPtr) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!image) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return image->backend->mapImageMemory(image, offset, size, outPtr); @@ -2679,11 +1108,11 @@ PalResult PAL_CALL palCreateImageView( PalImageView** outImageView) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !image || !info || !outImageView) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalImageView* imageView = nullptr; @@ -2715,11 +1144,11 @@ PalResult PAL_CALL palCreateSampler( PalSampler** outSampler) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outSampler) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalSampler* sampler = nullptr; @@ -2747,20 +1176,22 @@ void PAL_CALL palDestroySampler(PalSampler* sampler) PalResult PAL_CALL palCreateSurface( PalDevice* device, - PalGraphicsWindow* window, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, PalSurface** outSurface) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !window || !outSurface) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalSurface* surface = nullptr; PalResult result; - result = device->backend->createSurface(device, window, &surface); + result = device->backend->createSurface(device, window, windowInstance, instanceType, &surface); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -2783,11 +1214,11 @@ PalResult PAL_CALL palGetSurfaceCapabilities( PalSurfaceCapabilities* caps) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !surface || !caps) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->getSurfaceCapabilities(device, surface, caps); @@ -2805,11 +1236,11 @@ PalResult PAL_CALL palCreateSwapchain( PalSwapchain** outSwapchain) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !queue || !surface || !info || !outSwapchain) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -2854,11 +1285,11 @@ PalResult PAL_CALL palGetNextSwapchainImage( uint32_t* outIndex) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!swapchain || !info) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return swapchain->backend->getNextSwapchainImage(swapchain, info, outIndex); @@ -2869,11 +1300,11 @@ PalResult PAL_CALL palPresentSwapchain( PalSwapchainPresentInfo* info) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!swapchain || !info) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return swapchain->backend->presentSwapchain(swapchain, info); @@ -2885,11 +1316,11 @@ PalResult PAL_CALL palResizeSwapchain( uint32_t newHeight) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!swapchain) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return swapchain->backend->resizeSwapchain(swapchain, newWidth, newHeight); @@ -2905,11 +1336,11 @@ PalResult PAL_CALL palCreateShader( PalShader** outShader) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outShader) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalShader* shader = nullptr; @@ -2941,11 +1372,11 @@ PalResult PAL_CALL palCreateFence( PalFence** outFence) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !outFence) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalFence* fence = nullptr; @@ -2972,11 +1403,11 @@ PalResult PAL_CALL palWaitFence( uint64_t timeout) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!fence) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return fence->backend->waitFence(fence, timeout); @@ -2985,11 +1416,11 @@ PalResult PAL_CALL palWaitFence( PalResult PAL_CALL palResetFence(PalFence* fence) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!fence) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return fence->backend->resetFence(fence); @@ -3013,11 +1444,11 @@ PalResult PAL_CALL palCreateSemaphore( PalSemaphore** outSemaphore) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !outSemaphore) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalSemaphore* semaphore = nullptr; @@ -3045,11 +1476,11 @@ PalResult PAL_CALL palWaitSemaphore( uint64_t timeout) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!semaphore) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return semaphore->backend->waitSemaphore(semaphore, value, timeout); @@ -3061,11 +1492,11 @@ PalResult PAL_CALL palSignalSemaphore( uint64_t value) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!semaphore || !queue) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return semaphore->backend->signalSemaphore(semaphore, queue, value); @@ -3076,11 +1507,11 @@ PalResult PAL_CALL palGetSemaphoreValue( uint64_t* outValue) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!semaphore || !outValue) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return semaphore->backend->getSemaphoreValue(semaphore, outValue); @@ -3096,11 +1527,11 @@ PalResult PAL_CALL palCreateCommandPool( PalCommandPool** outPool) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !queue || !outPool) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalCommandPool* pool = nullptr; @@ -3125,11 +1556,11 @@ void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!pool) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return pool->backend->resetCommandPool(pool); @@ -3142,11 +1573,11 @@ PalResult PAL_CALL palAllocateCommandBuffer( PalCommandBuffer** outCmdBuffer) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !pool || !outCmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalCommandBuffer* cmdBuffer = nullptr; @@ -3171,11 +1602,11 @@ void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->resetCommandBuffer(cmdBuffer); @@ -3186,11 +1617,11 @@ PalResult PAL_CALL palSubmitCommandBuffer( PalCommandBufferSubmitInfo* info) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!queue || !info) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return queue->backend->submitCommandBuffer(queue, info); @@ -3205,11 +1636,11 @@ PalResult PAL_CALL palCmdBegin( PalRenderingLayoutInfo* info) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdBegin(cmdBuffer, info); @@ -3218,11 +1649,11 @@ PalResult PAL_CALL palCmdBegin( PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdEnd(cmdBuffer); @@ -3233,11 +1664,11 @@ PalResult PAL_CALL palCmdExecuteCommandBuffer( PalCommandBuffer* secondaryCmdBuffer) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!primaryCmdBuffer || !secondaryCmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return primaryCmdBuffer->backend->cmdExecuteCommandBuffer(primaryCmdBuffer, secondaryCmdBuffer); @@ -3248,11 +1679,11 @@ PalResult PAL_CALL palCmdSetFragmentShadingRate( PalFragmentShadingRateState* state) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !state) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdSetFragmentShadingRate(cmdBuffer, state); @@ -3265,11 +1696,11 @@ PalResult PAL_CALL palCmdDrawMeshTasks( uint32_t groupCountZ) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdDrawMeshTasks(cmdBuffer, groupCountX, groupCountY, groupCountZ); @@ -3281,11 +1712,11 @@ PalResult PAL_CALL palCmdDrawMeshTasksIndirect( uint32_t drawCount) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !buffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdDrawMeshTasksIndirect(cmdBuffer, buffer, drawCount); @@ -3298,18 +1729,15 @@ PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( uint32_t maxDrawCount) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !buffer || !countBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdDrawMeshTasksIndirectCount( - cmdBuffer, - buffer, - countBuffer, - maxDrawCount); + return cmdBuffer->backend + ->cmdDrawMeshTasksIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); } PalResult PAL_CALL palCmdBuildAccelerationStructure( @@ -3317,15 +1745,15 @@ PalResult PAL_CALL palCmdBuildAccelerationStructure( PalAccelerationStructureBuildInfo* info) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } if (!info->dst || info->scratchBufferAddress == 0) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdBuildAccelerationStructure(cmdBuffer, info); @@ -3336,11 +1764,11 @@ PalResult PAL_CALL palCmdBeginRendering( PalRenderingInfo* info) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !info) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdBeginRendering(cmdBuffer, info); @@ -3349,11 +1777,11 @@ PalResult PAL_CALL palCmdBeginRendering( PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdEndRendering(cmdBuffer); @@ -3366,11 +1794,11 @@ PalResult PAL_CALL palCmdCopyBuffer( PalBufferCopyInfo* copyInfo) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !dst || !src || !copyInfo) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdCopyBuffer(cmdBuffer, dst, src, copyInfo); @@ -3383,18 +1811,14 @@ PalResult PAL_CALL palCmdCopyBufferToImage( PalBufferImageCopyInfo* copyInfo) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !dstImage || !srcBuffer || !copyInfo) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdCopyBufferToImage( - cmdBuffer, - dstImage, - srcBuffer, - copyInfo); + return cmdBuffer->backend->cmdCopyBufferToImage(cmdBuffer, dstImage, srcBuffer, copyInfo); } PalResult PAL_CALL palCmdCopyImage( @@ -3404,20 +1828,16 @@ PalResult PAL_CALL palCmdCopyImage( PalImageCopyInfo* copyInfo) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !dst || !src || !copyInfo) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdCopyImage( - cmdBuffer, - dst, - src, - copyInfo); + return cmdBuffer->backend->cmdCopyImage(cmdBuffer, dst, src, copyInfo); } - + PalResult PAL_CALL palCmdCopyImageToBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, @@ -3425,18 +1845,14 @@ PalResult PAL_CALL palCmdCopyImageToBuffer( PalBufferImageCopyInfo* copyInfo) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !dstBuffer || !srcImage || !copyInfo) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdCopyImageToBuffer( - cmdBuffer, - dstBuffer, - srcImage, - copyInfo); + return cmdBuffer->backend->cmdCopyImageToBuffer(cmdBuffer, dstBuffer, srcImage, copyInfo); } PalResult PAL_CALL palCmdBindPipeline( @@ -3444,11 +1860,11 @@ PalResult PAL_CALL palCmdBindPipeline( PalPipeline* pipeline) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !pipeline) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdBindPipeline(cmdBuffer, pipeline); @@ -3460,11 +1876,11 @@ PalResult PAL_CALL palCmdSetViewport( PalViewport* viewports) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !viewports || !count) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdSetViewport(cmdBuffer, count, viewports); @@ -3476,11 +1892,11 @@ PalResult PAL_CALL palCmdSetScissors( PalRect2D* scissors) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !scissors || !count) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdSetScissors(cmdBuffer, count, scissors); @@ -3494,19 +1910,14 @@ PalResult PAL_CALL palCmdBindVertexBuffers( uint64_t* offsets) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !buffers || !offsets) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdBindVertexBuffers( - cmdBuffer, - firstSlot, - count, - buffers, - offsets); + return cmdBuffer->backend->cmdBindVertexBuffers(cmdBuffer, firstSlot, count, buffers, offsets); } PalResult PAL_CALL palCmdBindIndexBuffer( @@ -3516,11 +1927,11 @@ PalResult PAL_CALL palCmdBindIndexBuffer( PalIndexType type) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !buffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdBindIndexBuffer(cmdBuffer, buffer, offset, type); @@ -3534,11 +1945,11 @@ PalResult PAL_CALL palCmdDraw( uint32_t firstInstance) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend @@ -3551,11 +1962,11 @@ PalResult PAL_CALL palCmdDrawIndirect( uint32_t count) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !buffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdDrawIndirect(cmdBuffer, buffer, count); @@ -3568,18 +1979,14 @@ PalResult PAL_CALL palCmdDrawIndirectCount( uint32_t maxDrawCount) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !buffer || !countBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdDrawIndirectCount( - cmdBuffer, - buffer, - countBuffer, - maxDrawCount); + return cmdBuffer->backend->cmdDrawIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); } PalResult PAL_CALL palCmdDrawIndexed( @@ -3591,11 +1998,11 @@ PalResult PAL_CALL palCmdDrawIndexed( uint32_t firstInstance) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdDrawIndexed( @@ -3613,11 +2020,11 @@ PalResult PAL_CALL palCmdDrawIndexedIndirect( uint32_t count) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !buffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdDrawIndexedIndirect(cmdBuffer, buffer, count); @@ -3630,80 +2037,70 @@ PalResult PAL_CALL palCmdDrawIndexedIndirectCount( uint32_t maxDrawCount) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !buffer || !countBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdDrawIndexedIndirectCount( - cmdBuffer, - buffer, - countBuffer, - maxDrawCount); + return cmdBuffer->backend + ->cmdDrawIndexedIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); } PalResult PAL_CALL palCmdAccelerationStructureBarrier( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo) + PalUsageState oldUsageState, + PalUsageState newUsageState) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } - if (!cmdBuffer || !as || !oldUsageStateInfo || !newUsageStateInfo) { - return PAL_RESULT_NULL_POINTER; + if (!cmdBuffer || !as) { + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdAccelerationStructureBarrier( - cmdBuffer, - as, - oldUsageStateInfo, - newUsageStateInfo); + return cmdBuffer->backend + ->cmdAccelerationStructureBarrier(cmdBuffer, as, oldUsageState, newUsageState); } PalResult PAL_CALL palCmdImageBarrier( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo) + PalUsageState oldUsageState, + PalUsageState newUsageState) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } - if (!cmdBuffer || !image ||!subresourceRange || !oldUsageStateInfo || !newUsageStateInfo) { - return PAL_RESULT_NULL_POINTER; + if (!cmdBuffer || !image || !subresourceRange) { + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdImageBarrier( - cmdBuffer, - image, - subresourceRange, - oldUsageStateInfo, - newUsageStateInfo); + return cmdBuffer->backend + ->cmdImageBarrier(cmdBuffer, image, subresourceRange, oldUsageState, newUsageState); } PalResult PAL_CALL palCmdBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo) + PalUsageState oldUsageState, + PalUsageState newUsageState) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } - if (!cmdBuffer || !buffer || !oldUsageStateInfo || !newUsageStateInfo) { - return PAL_RESULT_NULL_POINTER; + if (!cmdBuffer || !buffer) { + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend - ->cmdBufferBarrier(cmdBuffer, buffer, oldUsageStateInfo, newUsageStateInfo); + ->cmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); } PalResult PAL_CALL palCmdDispatch( @@ -3713,11 +2110,11 @@ PalResult PAL_CALL palCmdDispatch( uint32_t groupCountZ) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); @@ -3733,11 +2130,11 @@ PalResult PAL_CALL palCmdDispatchBase( uint32_t groupCountZ) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdDispatchBase( @@ -3755,11 +2152,11 @@ PalResult PAL_CALL palCmdDispatchIndirect( PalBuffer* buffer) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !buffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdDispatchIndirect(cmdBuffer, buffer); @@ -3774,11 +2171,11 @@ PalResult PAL_CALL palCmdTraceRays( uint32_t depth) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !sbt) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdTraceRays(cmdBuffer, sbt, raygenIndex, width, height, depth); @@ -3791,11 +2188,11 @@ PalResult PAL_CALL palCmdTraceRaysIndirect( PalBuffer* buffer) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !sbt || !buffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdTraceRaysIndirect(cmdBuffer, raygenIndex, sbt, buffer); @@ -3807,17 +2204,14 @@ PalResult PAL_CALL palCmdBindDescriptorSet( PalDescriptorSet* set) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !set) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdBindDescriptorSet( - cmdBuffer, - setIndex, - set); + return cmdBuffer->backend->cmdBindDescriptorSet(cmdBuffer, setIndex, set); } PalResult PAL_CALL palCmdPushConstants( @@ -3829,11 +2223,11 @@ PalResult PAL_CALL palCmdPushConstants( const void* value) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer || !shaderStages || !value) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } // clang-format off @@ -3852,11 +2246,11 @@ PalResult PAL_CALL palCmdSetCullMode( PalCullMode cullMode) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdSetCullMode(cmdBuffer, cullMode); @@ -3867,11 +2261,11 @@ PalResult PAL_CALL palCmdSetFrontFace( PalFrontFace frontFace) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdSetFrontFace(cmdBuffer, frontFace); @@ -3882,11 +2276,11 @@ PalResult PAL_CALL palCmdSetPrimitiveTopology( PalPrimitiveTopology topology) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdSetPrimitiveTopology(cmdBuffer, topology); @@ -3897,11 +2291,11 @@ PalResult PAL_CALL palCmdSetDepthTestEnable( PalBool enable) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdSetDepthTestEnable(cmdBuffer, enable); @@ -3912,11 +2306,11 @@ PalResult PAL_CALL palCmdSetDepthWriteEnable( PalBool enable) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return cmdBuffer->backend->cmdSetDepthWriteEnable(cmdBuffer, enable); @@ -3931,20 +2325,15 @@ PalResult PAL_CALL palCmdSetStencilOp( PalCompareOp compareOp) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!cmdBuffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return cmdBuffer->backend->cmdSetStencilOp( - cmdBuffer, - faceMask, - failOp, - passOp, - depthFailOp, - compareOp); + return cmdBuffer->backend + ->cmdSetStencilOp(cmdBuffer, faceMask, failOp, passOp, depthFailOp, compareOp); } // ================================================== @@ -3957,15 +2346,15 @@ PalResult PAL_CALL palCreateAccelerationstructure( PalAccelerationStructure** outAs) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outAs) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } if (!info->buffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -3993,11 +2382,11 @@ PalResult PAL_CALL palGetAccelerationStructureBuildSize( PalAccelerationStructureBuildSize* size) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !size) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->getAccelerationStructureBuildSize(device, info, size); @@ -4013,11 +2402,11 @@ PalResult PAL_CALL palCreateBuffer( PalBuffer** outBuffer) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -4044,11 +2433,11 @@ PalResult PAL_CALL palGetBufferMemoryRequirements( PalMemoryRequirements* requirements) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!buffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return buffer->backend->getBufferMemoryRequirements(buffer, requirements); @@ -4060,17 +2449,14 @@ PalResult PAL_CALL palComputeInstanceBufferRequirements( uint64_t* outSize) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !outSize) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } - return device->backend->computeInstanceBufferRequirements( - device, - instanceCount, - outSize); + return device->backend->computeInstanceBufferRequirements(device, instanceCount, outSize); } PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( @@ -4082,11 +2468,11 @@ PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( uint64_t* outSize) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !outBufferRowLength || !outBufferImageHeight || !outSize) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } if (copyInfo->bufferRowLength < copyInfo->imageWidth && copyInfo->bufferRowLength) { @@ -4098,9 +2484,9 @@ PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( } return device->backend->computeImageCopyStagingBufferRequirements( - device, + device, imageFormat, - copyInfo, + copyInfo, outBufferRowLength, outBufferImageHeight, outSize); @@ -4113,11 +2499,11 @@ PalResult PAL_CALL palWriteToInstanceBuffer( uint32_t instanceCount) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !ptr || !instances || instanceCount == 0) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } // since all tlas have backend pointer, we use the first one @@ -4132,11 +2518,11 @@ PalResult PAL_CALL palWriteToImageCopyStagingBuffer( PalBufferImageCopyInfo* copyInfo) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !ptr || !srcData || !copyInfo) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } if (copyInfo->bufferRowLength < copyInfo->imageWidth && copyInfo->bufferRowLength) { @@ -4147,12 +2533,8 @@ PalResult PAL_CALL palWriteToImageCopyStagingBuffer( return PAL_RESULT_INVALID_ARGUMENT; } - return device->backend->writeToImageCopyStagingBuffer( - device, - ptr, - srcData, - imageFormat, - copyInfo); + return device->backend + ->writeToImageCopyStagingBuffer(device, ptr, srcData, imageFormat, copyInfo); } PalResult PAL_CALL palBindBufferMemory( @@ -4161,11 +2543,11 @@ PalResult PAL_CALL palBindBufferMemory( uint64_t offset) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!buffer || !memory) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return buffer->backend->bindBufferMemory(buffer, memory, offset); @@ -4178,11 +2560,11 @@ PalResult PAL_CALL palMapBufferMemory( void** outPtr) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!buffer) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return buffer->backend->mapBufferMemory(buffer, offset, size, outPtr); @@ -4213,11 +2595,11 @@ PalResult PAL_CALL palCreateDescriptorSetLayout( PalDescriptorSetLayout** outLayout) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outLayout) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -4245,11 +2627,11 @@ PalResult PAL_CALL palCreateDescriptorPool( PalDescriptorPool** outPool) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outPool) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } if (!info->maxDescriptorSets) { @@ -4278,11 +2660,11 @@ void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool) PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!pool) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return pool->backend->resetDescriptorPool(pool); @@ -4295,11 +2677,11 @@ PalResult PAL_CALL palAllocateDescriptorSet( PalDescriptorSet** outSet) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !pool || !layout || !outSet) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -4320,15 +2702,11 @@ PalResult PAL_CALL palUpdateDescriptorSet( PalDescriptorSetWriteInfo* infos) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!device || !infos) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } - if (count == 0 && infos) { - return PAL_RESULT_INSUFFICIENT_BUFFER; + if (!device || !infos || count == 0 && infos) { + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return device->backend->updateDescriptorSet(device, count, infos); @@ -4344,11 +2722,11 @@ PalResult PAL_CALL palCreatePipelineLayout( PalPipelineLayout** outLayout) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outLayout) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -4380,15 +2758,15 @@ PalResult PAL_CALL palCreateGraphicsPipeline( PalPipeline** outPipeline) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outPipeline) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } if (!info->renderingLayout) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -4409,11 +2787,11 @@ PalResult PAL_CALL palCreateComputePipeline( PalPipeline** outPipeline) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outPipeline) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -4434,11 +2812,11 @@ PalResult PAL_CALL palCreateRayTracingPipeline( PalPipeline** outPipeline) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outPipeline) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -4470,15 +2848,15 @@ PalResult PAL_CALL palCreateShaderBindingTable( PalShaderBindingTable** outSbt) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } if (!device || !info || !outSbt) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } if (!info->rayTracingPipeline) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } PalResult result; @@ -4501,20 +2879,16 @@ void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt) } PalResult PAL_CALL palUpdateShaderBindingTable( - PalShaderBindingTable* sbt, + PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos) { if (!s_Graphics.initialized) { - return PAL_RESULT_GRAPHICS_NOT_INITIALIZED; - } - - if (!sbt || !infos) { - return PAL_RESULT_NULL_POINTER; + return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); } - if (count == 0 && infos) { - return PAL_RESULT_INSUFFICIENT_BUFFER; + if (!sbt || !infos || count == 0 && infos) { + return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); } return sbt->backend->updateShaderBindingTable(sbt, count, infos); diff --git a/src/graphics/pal_graphics_vtable.h b/src/graphics/pal_graphics_vtable.h new file mode 100644 index 00000000..8135d369 --- /dev/null +++ b/src/graphics/pal_graphics_vtable.h @@ -0,0 +1,611 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_GRAPHICS_VTABLE_H +#define _PAL_GRAPHICS_VTABLE_H + +#include "pal/pal_graphics.h" + +typedef struct { + PalResult (PAL_CALL *enumerateAdapters)( + int32_t* count, + PalAdapter** outAdapters); + + PalResult (PAL_CALL *getAdapterInfo)( + PalAdapter* adapter, + PalAdapterInfo* info); + + PalResult (PAL_CALL *getAdapterCapabilities)( + PalAdapter* adapter, + PalAdapterCapabilities* caps); + + PalAdapterFeatures (PAL_CALL *getAdapterFeatures)(PalAdapter* adapter); + + uint32_t (PAL_CALL *getHighestSupportedShaderTarget)( + PalAdapter* adapter, + PalShaderFormats shaderFormat); + + PalResult (PAL_CALL *createDevice)( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); + + void (PAL_CALL *destroyDevice)(PalDevice* device); + + PalResult (PAL_CALL *allocateMemory)( + PalDevice* device, + PalMemoryType type, + uint64_t memoryMask, + uint64_t size, + PalMemory** outMemory); + + void (PAL_CALL *freeMemory)( + PalDevice* device, + PalMemory* memory); + + PalResult (PAL_CALL *querySamplerAnisotropyCapabilities)( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps); + + PalResult (PAL_CALL *queryMultiViewCapabilities)( + PalDevice* device, + PalMultiViewCapabilities* caps); + + PalResult (PAL_CALL *queryMultiViewportCapabilities)( + PalDevice* device, + PalMultiViewportCapabilities* caps); + + PalResult (PAL_CALL *queryDepthStencilCapabilities)( + PalDevice* device, + PalDepthStencilCapabilities* caps); + PalResult (PAL_CALL *queryFragmentShadingRateCapabilities)( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); + + PalResult (PAL_CALL *queryMeshShaderCapabilities)( + PalDevice* device, + PalMeshShaderCapabilities* caps); + + PalResult (PAL_CALL *queryRayTracingCapabilities)( + PalDevice* device, + PalRayTracingCapabilities* caps); + + PalResult (PAL_CALL *queryDescriptorIndexingCapabilities)( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); + + PalResult (PAL_CALL *createQueue)( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); + + void (PAL_CALL *destroyQueue)(PalQueue* queue); + + PalBool (PAL_CALL *canQueuePresent)( + PalQueue* queue, + PalSurface* surface); + + PalResult (PAL_CALL *waitQueue)(PalQueue* queue); + + PalResult (PAL_CALL *enumerateFormats)( + PalAdapter* adapter, + int32_t* count, + PalFormatInfo* outFormats); + + PalBool (PAL_CALL *isFormatSupported)( + PalAdapter* adapter, + PalFormat format); + + PalImageUsages (PAL_CALL *queryFormatImageUsages)( + PalAdapter* adapter, + PalFormat format); + + PalSampleCount (PAL_CALL *queryFormatSampleCount)( + PalAdapter* adapter, + PalFormat format); + + PalResult (PAL_CALL *createImage)( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + + void (PAL_CALL *destroyImage)(PalImage* image); + + PalResult (PAL_CALL *getImageInfo)( + PalImage* image, + PalImageInfo* info); + + PalResult (PAL_CALL *getImageMemoryRequirements)( + PalImage* image, + PalMemoryRequirements* requirements); + + PalResult (PAL_CALL *bindImageMemory)( + PalImage* image, + PalMemory* memory, + uint64_t offset); + + PalResult (PAL_CALL *mapImageMemory)( + PalImage* image, + uint64_t offset, + uint64_t size, + void** outPtr); + + void (PAL_CALL *unmapImageMemory)(PalImage* image); + + PalResult (PAL_CALL *createImageView)( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + + void (PAL_CALL *destroyImageView)(PalImageView* imageView); + + PalResult (PAL_CALL *createSampler)( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler); + + void (PAL_CALL *destroySampler)(PalSampler* sampler); + + PalResult (PAL_CALL *createSurface)( + PalDevice* device, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, + PalSurface** outSurface); + + void (PAL_CALL *destroySurface)(PalSurface* surface); + + PalResult (PAL_CALL *getSurfaceCapabilities)( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps); + + PalResult (PAL_CALL *createSwapchain)( + PalDevice* device, + PalQueue* queue, + PalSurface* surface, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + + void (PAL_CALL *destroySwapchain)(PalSwapchain* swapchain); + + PalImage* (PAL_CALL *getSwapchainImage)( + PalSwapchain* swapchain, + int32_t index); + + PalResult (PAL_CALL *getNextSwapchainImage)( + PalSwapchain* swapchain, + PalSwapchainNextImageInfo* info, + uint32_t* outIndex); + + PalResult (PAL_CALL *presentSwapchain)( + PalSwapchain* swapchain, + PalSwapchainPresentInfo* info); + + PalResult (PAL_CALL *resizeSwapchain)( + PalSwapchain* swapchain, + uint32_t newWidth, + uint32_t newHeight); + + PalResult (PAL_CALL *createShader)( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + + void (PAL_CALL *destroyShader)(PalShader* shader); + + PalResult (PAL_CALL *createFence)( + PalDevice* device, + PalBool signaled, + PalFence** outFence); + + void (PAL_CALL *destroyFence)(PalFence* fence); + + PalResult (PAL_CALL *waitFence)( + PalFence* fence, + uint64_t timeout); + + PalResult (PAL_CALL *resetFence)(PalFence* fence); + + PalBool (PAL_CALL *isFenceSignaled)(PalFence* fence); + + PalResult (PAL_CALL *createSemaphore)( + PalDevice* device, + PalBool enableTimeline, + PalSemaphore** outSemaphore); + + void (PAL_CALL *destroySemaphore)(PalSemaphore* semaphore); + + PalResult (PAL_CALL *waitSemaphore)( + PalSemaphore* semaphore, + uint64_t value, + uint64_t timeout); + + PalResult (PAL_CALL *signalSemaphore)( + PalSemaphore* semaphore, + PalQueue* queue, + uint64_t value); + + PalResult (PAL_CALL *getSemaphoreValue)( + PalSemaphore* semaphore, + uint64_t* outValue); + + PalResult (PAL_CALL *createCommandPool)( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool); + + void (PAL_CALL *destroyCommandPool)(PalCommandPool* pool); + + PalResult (PAL_CALL *resetCommandPool)(PalCommandPool* pool); + + PalResult (PAL_CALL *allocateCommandBuffer)( + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outCmdBuffer); + + void (PAL_CALL *freeCommandBuffer)(PalCommandBuffer* cmdBuffer); + + PalResult (PAL_CALL *resetCommandBuffer)(PalCommandBuffer* cmdBuffer); + + PalResult (PAL_CALL *submitCommandBuffer)( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + + PalResult (PAL_CALL *cmdBegin)( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info); + + PalResult (PAL_CALL *cmdEnd)(PalCommandBuffer* cmdBuffer); + + PalResult (PAL_CALL *cmdExecuteCommandBuffer)( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + + PalResult (PAL_CALL *cmdSetFragmentShadingRate)( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + + PalResult (PAL_CALL *cmdDrawMeshTasks)( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + + PalResult (PAL_CALL *cmdDrawMeshTasksIndirect)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t drawCount); + + PalResult (PAL_CALL *cmdDrawMeshTasksIndirectCount)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + + PalResult (PAL_CALL *cmdBuildAccelerationStructure)( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); + + PalResult (PAL_CALL *cmdBeginRendering)( + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info); + + PalResult (PAL_CALL *cmdEndRendering)(PalCommandBuffer* cmdBuffer); + + PalResult (PAL_CALL *cmdCopyBuffer)( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo); + + PalResult (PAL_CALL *cmdCopyBufferToImage)( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + + PalResult (PAL_CALL *cmdCopyImage)( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + + PalResult (PAL_CALL *cmdCopyImageToBuffer)( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo); + + PalResult (PAL_CALL *cmdBindPipeline)( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline); + + PalResult (PAL_CALL *cmdSetViewport)( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalViewport* viewports); + + PalResult (PAL_CALL *cmdSetScissors)( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalRect2D* scissors); + + PalResult (PAL_CALL *cmdBindVertexBuffers)( + PalCommandBuffer* cmdBuffer, + uint32_t firstSlot, + uint32_t count, + PalBuffer** buffers, + uint64_t* offsets); + + PalResult (PAL_CALL *cmdBindIndexBuffer)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint64_t offset, + PalIndexType type); + + PalResult (PAL_CALL *cmdDraw)( + PalCommandBuffer* cmdBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + + PalResult (PAL_CALL *cmdDrawIndirect)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + + PalResult (PAL_CALL *cmdDrawIndirectCount)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t count); + + PalResult (PAL_CALL *cmdDrawIndexed)( + PalCommandBuffer* cmdBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + + PalResult (PAL_CALL *cmdDrawIndexedIndirect)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + + PalResult (PAL_CALL *cmdDrawIndexedIndirectCount)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t count); + + PalResult (PAL_CALL *cmdAccelerationStructureBarrier)( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, + PalUsageState oldUsageState, + PalUsageState newUsageState); + + PalResult (PAL_CALL *cmdImageBarrier)( + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalUsageState oldUsageState, + PalUsageState newUsageState); + + PalResult (PAL_CALL *cmdBufferBarrier)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState); + + PalResult (PAL_CALL *cmdDispatch)( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + + PalResult (PAL_CALL *cmdDispatchBase)( + PalCommandBuffer* cmdBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + + PalResult (PAL_CALL *cmdDispatchIndirect)( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer); + + PalResult (PAL_CALL *cmdTraceRays)( + PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth); + + PalResult (PAL_CALL *cmdTraceRaysIndirect)( + PalCommandBuffer* cmdBuffer, + uint32_t raygenIndex, + PalShaderBindingTable* sbt, + PalBuffer* buffer); + + PalResult (PAL_CALL *cmdBindDescriptorSet)( + PalCommandBuffer* cmdBuffer, + uint32_t setIndex, + PalDescriptorSet* set); + + PalResult (PAL_CALL *cmdPushConstants)( + PalCommandBuffer* cmdBuffer, + uint32_t shaderStageCount, + PalShaderStage* shaderStages, + uint32_t offset, + uint32_t size, + const void* value); + + PalResult (PAL_CALL *cmdSetCullMode)( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + + PalResult (PAL_CALL *cmdSetFrontFace)( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + + PalResult (PAL_CALL *cmdSetPrimitiveTopology)( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + + PalResult (PAL_CALL *cmdSetDepthTestEnable)( + PalCommandBuffer* cmdBuffer, + PalBool enable); + + PalResult (PAL_CALL *cmdSetDepthWriteEnable)( + PalCommandBuffer* cmdBuffer, + PalBool enable); + + PalResult (PAL_CALL *cmdSetStencilOp)( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); + + PalResult (PAL_CALL *createAccelerationstructure)( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + + void (PAL_CALL *destroyAccelerationstructure)(PalAccelerationStructure* as); + + PalResult (PAL_CALL *getAccelerationStructureBuildSize)( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + + PalResult (PAL_CALL *createBuffer)( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + + void (PAL_CALL *destroyBuffer)(PalBuffer* buffer); + + PalResult (PAL_CALL *getBufferMemoryRequirements)( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + + PalResult (PAL_CALL *computeInstanceBufferRequirements)( + PalDevice* device, + uint32_t instanceCount, + uint64_t* outSize); + + PalResult (PAL_CALL *computeImageCopyStagingBufferRequirements)( + PalDevice* device, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo, + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize); + + PalResult (PAL_CALL *writeToInstanceBuffer)( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + uint32_t instanceCount); + + PalResult (PAL_CALL *writeToImageCopyStagingBuffer)( + PalDevice* device, + void* ptr, + void* srcData, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo); + + PalResult (PAL_CALL *bindBufferMemory)( + PalBuffer* buffer, + PalMemory* memory, + uint64_t offset); + + PalResult (PAL_CALL *mapBufferMemory)( + PalBuffer* buffer, + uint64_t offset, + uint64_t size, + void** outPtr); + + void (PAL_CALL *unmapBufferMemory)(PalBuffer* buffer); + + PalDeviceAddress (PAL_CALL *getBufferDeviceAddress)(PalBuffer* buffer); + + PalResult (PAL_CALL *createDescriptorSetLayout)( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + + void (PAL_CALL *destroyDescriptorSetLayout)(PalDescriptorSetLayout* layout); + + PalResult (PAL_CALL *createDescriptorPool)( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + + void (PAL_CALL *destroyDescriptorPool)(PalDescriptorPool* pool); + + PalResult (PAL_CALL *resetDescriptorPool)(PalDescriptorPool* pool); + + PalResult (PAL_CALL *allocateDescriptorSet)( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + + PalResult (PAL_CALL *updateDescriptorSet)( + PalDevice* device, + uint32_t count, + PalDescriptorSetWriteInfo* infos); + + PalResult (PAL_CALL *createPipelineLayout)( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + + void (PAL_CALL *destroyPipelineLayout)(PalPipelineLayout* layout); + + PalResult (PAL_CALL *createGraphicsPipeline)( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + + PalResult (PAL_CALL *createComputePipeline)( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + + PalResult (PAL_CALL *createRayTracingPipeline)( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + + void (PAL_CALL *destroyPipeline)(PalPipeline* pipeline); + + PalResult (PAL_CALL *createShaderBindingTable)( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + + void (PAL_CALL *destroyShaderBindingTable)(PalShaderBindingTable* sbt); + + PalResult (PAL_CALL *updateShaderBindingTable)( + PalShaderBindingTable* sbt, + uint32_t count, + PalShaderBindingTableRecordInfo* infos); +} PalGraphicsVtable; + +#endif // _PAL_GRAPHICS_VTABLE_H \ No newline at end of file From 6546ca5a6aa671cbfb66d9969e3b5e7d03697282 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 24 Jun 2026 14:26:00 +0000 Subject: [PATCH 293/372] start struct inline docs --- include/pal/pal_core.h | 56 +-- include/pal/pal_event.h | 26 +- include/pal/pal_graphics.h | 835 +++++++++++++++++++------------------ include/pal/pal_opengl.h | 78 ++-- include/pal/pal_system.h | 24 +- include/pal/pal_thread.h | 4 +- include/pal/pal_video.h | 91 ++-- 7 files changed, 563 insertions(+), 551 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index f11d1f2d..821032c5 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -81,15 +81,15 @@ typedef uint32_t PalBool; /** * @typedef PalResult * @brief Value returned by most PAL functions. - * + * * Non-success results (eg. `PAL_RESULT_INVALID_HANDLE`) may contain * additional information for debugging and logging purposes. For checking specific - * result codes, call `palGetResultCode()` to get the code from the result value. - * - * Example: - * + * result codes, call `palGetResultCode()` to get the code from the result value. + * + * Example: + * * uint16_t resultCode = palGetResultCode(result); - * + * * if (resultCode == `PAL_RESULT_INVALID_DEVICE_LOST`) {}. * * All result codes follow the format `PAL_RESULT_**` for consistency and API use. @@ -102,9 +102,9 @@ typedef uint64_t PalResult; * @typedef PalAllocateFn * @brief Function pointer type used for memory allocations. * - * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. + * @param[in] userData Optional pointer to user data. Can be nullptr. * @param[in] size Number of bytes to allocate. Must not be 0. - * @param[in] alignment Must be power of two. Set to 0 to use default (16). + * @param[in] alignment Must be power of two. Set to 0 to use default. * * @return Pointer to the allocated memory on success or nullptr on failure. * @@ -120,7 +120,7 @@ typedef void*(PAL_CALL* PalAllocateFn)( * @typedef PalFreeFn * @brief Function pointer type used for memory deallocations. * - * @param[in] userData Optional pointer to user data passed from ::PalAllocator. Can be nullptr. + * @param[in] userData Optional pointer to user data. Can be nullptr. * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must return safely if * pointer is nullptr. * @@ -163,12 +163,14 @@ typedef struct { * * Provides user-defined memory allocation and free functions. * + * Uninitialized fields may result in undefined behavior. + * * @since 1.0 */ typedef struct { - PalAllocateFn allocate; - PalFreeFn free; - void* userData; /**< Optional user-provided data. Can be nullptr.*/ + PalAllocateFn allocate; /**< Allocate function pointer. Must not be nullptr.*/ + PalFreeFn free; /**< Free function pointer. Must not be nullptr.*/ + void* userData; /**< Optional user-provided data. Can be nullptr.*/ } PalAllocator; /** @@ -177,19 +179,21 @@ typedef struct { * * Provides a callback and user data for handling log messages. * + * Uninitialized fields may result in undefined behavior. + * * @since 1.0 */ typedef struct { - PalLogCallback callback; - void* userData; /** Optional user-provided data. Can be nullptr.*/ + PalLogCallback callback; /**< Callback function pointer. Must not be nullptr.*/ + void* userData; /** Optional user-provided data. Can be nullptr.*/ } PalLogger; /** * Get the result code from the result value. - * + * * `PAL_RESULT_SUCCESS` code can be compared with the result value without comparing the - * result code. - * + * result code. + * * @param result The result value. * * @return The result code from the result value. @@ -202,7 +206,7 @@ PAL_API uint16_t PAL_CALL palGetResultCode(PalResult result); /** * Convert a result value to a human-readable string. - * + * * This returns a null-terminated string. The string is truncated if `bufferSize` is insufficient. * * @param result The PalResult value to format. @@ -214,13 +218,13 @@ PAL_API uint16_t PAL_CALL palGetResultCode(PalResult result); * @since 1.0 */ PAL_API void PAL_CALL palFormatResult( - PalResult result, + PalResult result, uint64_t bufferSize, char* buffer); /** * Retrieve the PAL version number. - * + * * @param version Pointer to PalVersion struct to fill. * * Thread safety: Thread safe if version is per thread. @@ -243,15 +247,15 @@ PAL_API void PAL_CALL palGetVersion(PalVersion* version); PAL_API const char* PAL_CALL palGetVersionString(); /** - * Allocate memory using the provided allocator. + * Allocate memory using a custom or default allocator. * * @param allocator The allocator to use. Set to nullptr to use default. * @param size Number of bytes to allocate. - * @param alignment Alignment in bytes. Must be a power of two. + * @param alignment Alignment in bytes. Must be a power of two. Set to 0 to use default. * * @return Pointer to allocated memory on success, or nullptr on failure. * - * Thread safety: Thread safe only if the provided allocator is thread safe. The default allocator + * Thread safety: Thread safe if the provided allocator is thread safe. The default allocator * is thread safe. * * @since 1.0 @@ -270,7 +274,7 @@ PAL_API void* PAL_CALL palAllocate( * @param ptr Pointer to memory to free. If nullptr, the function returns * silently. * - * Thread safety: Thread safe only if the provided allocator is thread + * Thread safety: Thread safe if the provided allocator is thread * safe. The default allocator is thread safe. * * @since 1.0 @@ -431,7 +435,7 @@ static inline void PAL_CALL palUnpackUint32( * @param[out] outLow Low value of the 64-bit signed integer. * @param[out] outHigh High value of the 64-bit signed integer. * - * Thread safety: Thread-safe if @c outLow and @c outHigh are + * Thread safety: Thread-safe if `outLow` and `outHigh` are * thread local. * * @since 1.0 @@ -472,7 +476,7 @@ static inline void* PAL_CALL palUnpackPointer(int64_t data) * @param[out] outLow Low value of the 64-bit signed integer. * @param[out] outHigh High value of the 64-bit signed integer. * - * Thread safety: Thread-safe if @c outLow and @c outHigh are + * Thread safety: Thread-safe if `outLow` and `outHigh` are * thread local. * * @since 1.3 diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index cb680960..1e4560d5 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -244,7 +244,7 @@ typedef struct PalEvent PalEvent; /** * @typedef PalDecorationMode - * @brief Decoration types. This is not a bitmask enum. + * @brief Decoration types. * * All decoration types follow the format `PAL_DECORATION_MODE_**` for * consistency and API use. @@ -255,7 +255,7 @@ typedef uint32_t PalDecorationMode; /** * @typedef PalEventType - * @brief Event types. This is not a bitmask enum. + * @brief Event types. * * All event types follow the format `PAL_EVENT_**` for consistency and * API use. @@ -266,7 +266,7 @@ typedef uint32_t PalEventType; /** * @typedef PalDispatchMode - * @brief Dispatch types for an event. This is not a bitmask enum. + * @brief Dispatch types for an event. * * All dispatch modes follow the format `PAL_DISPATCH_**` for consistency * and API use. @@ -322,10 +322,10 @@ typedef PalBool(PAL_CALL* PalPollFn)( PalEvent* outEvent); struct PalEvent { - int64_t data; /**< First data payload.*/ - int64_t data2; /**< Second data payload.*/ - int32_t userId; /**< You can have user events upto int32_t max.*/ - PalEventType type; + int64_t data; /**< First data payload.*/ + int64_t data2; /**< Second data payload.*/ + int32_t userId; /**< You can have user events upto int32_t max.*/ + PalEventType type; /**< (eg. `PAL_EVENT_WINDOW_MOVE`).*/ }; /** @@ -337,8 +337,8 @@ struct PalEvent { * @since 1.0 */ typedef struct { - PalPushFn push; - PalPollFn poll; + PalPushFn push; /**< Push function pointer. Must not be nullptr.*/ + PalPollFn poll; /**< Poll function pointer. Must not be nullptr.*/ void* userData; /**< Optional user-provided data. Can be nullptr.*/ } PalEventQueue; @@ -417,7 +417,7 @@ PAL_API void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver); * @param[in] type Event type to set dispatch mode for. * @param[in] mode Dispatch mode to use. * - * Thread safety: Thread if multiple threads are not + * Thread safety: Thread safe if multiple threads are not * simultaneously setting dispatch mode on the same `eventDriver`. * * @since 1.0 @@ -437,7 +437,7 @@ PAL_API void PAL_CALL palSetEventDispatchMode( * * @return The dispatch mode on success or `PAL_DISPATCH_NONE` on failure. * - * Thread safety: Thread if multiple threads are not + * Thread safety: Thread safe if multiple threads are not * simultaneously setting dispatch mode on the same `eventDriver`. * * @since 1.0 @@ -464,7 +464,7 @@ PAL_API PalDispatchMode PAL_CALL palGetEventDispatchMode( * @param[in] eventDriver Pointer to the event driver. * @param[in] event Pointer to the event to push. * - * Thread safety: Thread if the provided event queue is thread + * Thread safety: Thread safe if the provided event queue is thread * safe or every thread has its own `eventDriver`. The default event queue is * not thread safe. * @@ -490,7 +490,7 @@ PAL_API void PAL_CALL palPushEvent( * @param[out] outEvent Pointer to a PalEvent to recieve the event. Must be * valid. * - * Thread safety: Thread if the provided event queue is thread + * Thread safety: Thread safe if the provided event queue is thread * safe or every thread has its own `eventDriver`. The default event queue is * not thread safe. * diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 211196b6..d7ddeb35 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -229,7 +229,7 @@ #define PAL_FILTER_MODE_NEAREST 0 #define PAL_FILTER_MODE_LINEAR 1 -#define PAL_FILTER_MODE_COUNT 2 +#define PAL_FILTER_MODE_COUNT 2 #define PAL_SAMPLER_MIPMAP_MODE_NEAREST 0 #define PAL_SAMPLER_MIPMAP_MODE_LINEAR 1 @@ -280,7 +280,7 @@ #define PAL_SAMPLE_COUNT_1 0 #define PAL_SAMPLE_COUNT_2 1 -#define PAL_SAMPLE_COUNT_4 2 +#define PAL_SAMPLE_COUNT_4 2 #define PAL_SAMPLE_COUNT_8 3 #define PAL_SAMPLE_COUNT_16 4 #define PAL_SAMPLE_COUNT_32 5 @@ -313,36 +313,36 @@ #define PAL_STENCIL_FACE_BOTH (PAL_STENCIL_FACE_FRONT | PAL_STENCIL_FACE_BACK) #define PAL_VERTEX_TYPE_UNDEFINED 0 -#define PAL_VERTEX_TYPE_INT32 1 /**< int32_t.*/ -#define PAL_VERTEX_TYPE_INT32_2 2 /**< int32_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_INT32_3 3 /**< int32_t vec3 or array[3].*/ -#define PAL_VERTEX_TYPE_INT32_4 4 /**< int32_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_UINT32 5 /**< uint32_t.*/ -#define PAL_VERTEX_TYPE_UINT32_2 6 /**< uint32_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_UINT32_3 7 /**< uint32_t vec3 or array[3].*/ -#define PAL_VERTEX_TYPE_UINT32_4 8 /**< uint32_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_INT8_2 9 /**< int8_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_INT8_4 10 /**< int8_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_UINT8_2 11 /**< uint8_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_UINT8_4 12 /**< uint8_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_INT8_2NORM 13 /**< int8_t vec2 or array[2] normalized.*/ -#define PAL_VERTEX_TYPE_INT8_4NORM 14 /**< int8_t vec4 or array[4] normalized.*/ +#define PAL_VERTEX_TYPE_INT32 1 /**< int32_t.*/ +#define PAL_VERTEX_TYPE_INT32_2 2 /**< int32_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_INT32_3 3 /**< int32_t vec3 or array[3].*/ +#define PAL_VERTEX_TYPE_INT32_4 4 /**< int32_t vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_UINT32 5 /**< uint32_t.*/ +#define PAL_VERTEX_TYPE_UINT32_2 6 /**< uint32_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_UINT32_3 7 /**< uint32_t vec3 or array[3].*/ +#define PAL_VERTEX_TYPE_UINT32_4 8 /**< uint32_t vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_INT8_2 9 /**< int8_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_INT8_4 10 /**< int8_t vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_UINT8_2 11 /**< uint8_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_UINT8_4 12 /**< uint8_t vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_INT8_2NORM 13 /**< int8_t vec2 or array[2] normalized.*/ +#define PAL_VERTEX_TYPE_INT8_4NORM 14 /**< int8_t vec4 or array[4] normalized.*/ #define PAL_VERTEX_TYPE_UINT8_2NORM 15 /**< uint8_t vec2 or array[2] normalized.*/ -#define PAL_VERTEX_TYPE_UINT8_4NORM 16 /**< uint8_t vec4 or array[4] normalized.*/ -#define PAL_VERTEX_TYPE_INT16_2 17 /**< int16_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_INT16_4 18 /**< int16_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_UINT16_2 19 /**< uint16_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_UINT16_4 20 /**< uint16_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_INT16_2NORM 21 /**< int16_t vec2 or array[2] normalized.*/ -#define PAL_VERTEX_TYPE_INT16_4NORM 22 /**< int16_t vec4 or array[4] normalized.*/ -#define PAL_VERTEX_TYPE_UINT16_2NORM 23 /**< uint16_t vec2 or array[2] normalized.*/ -#define PAL_VERTEX_TYPE_UINT16_4NORM 24 /**< uint16_t vec4 or array[4] normalized.*/ -#define PAL_VERTEX_TYPE_FLOAT 25 /**< float*/ -#define PAL_VERTEX_TYPE_FLOAT2 26 /**< float vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_FLOAT3 27 /**< float vec3 or array[3].*/ -#define PAL_VERTEX_TYPE_FLOAT4 28 /**< float vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_HALF_FLOAT16_2 29 /**< float16 vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_HALF_FLOAT16_4 30 /**< float16 vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_UINT8_4NORM 16 /**< uint8_t vec4 or array[4] normalized.*/ +#define PAL_VERTEX_TYPE_INT16_2 17 /**< int16_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_INT16_4 18 /**< int16_t vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_UINT16_2 19 /**< uint16_t vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_UINT16_4 20 /**< uint16_t vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_INT16_2NORM 21 /**< int16_t vec2 or array[2] normalized.*/ +#define PAL_VERTEX_TYPE_INT16_4NORM 22 /**< int16_t vec4 or array[4] normalized.*/ +#define PAL_VERTEX_TYPE_UINT16_2NORM 23 /**< uint16_t vec2 or array[2] normalized.*/ +#define PAL_VERTEX_TYPE_UINT16_4NORM 24 /**< uint16_t vec4 or array[4] normalized.*/ +#define PAL_VERTEX_TYPE_FLOAT 25 /**< float*/ +#define PAL_VERTEX_TYPE_FLOAT2 26 /**< float vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_FLOAT3 27 /**< float vec3 or array[3].*/ +#define PAL_VERTEX_TYPE_FLOAT4 28 /**< float vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_HALF_FLOAT16_2 29 /**< float16 vec2 or array[2].*/ +#define PAL_VERTEX_TYPE_HALF_FLOAT16_4 30 /**< float16 vec4 or array[4].*/ #define PAL_VERTEX_TYPE_COUNT 31 #define PAL_VERTEX_SEMANTIC_ID_POSITION 0 @@ -655,11 +655,11 @@ typedef struct PalCommandBuffer PalCommandBuffer; /** * @struct PalDescriptorSetLayout * @brief Opaque handle to a descriptor set layout. - * + * * This defines the layout, ordering and the number of descriptors a descriptor set uses. - * - * The layouts should reflect the exact layout of the shaders. Eg. - * descriptorBindings[2] = { sampler, sampled image } is different from + * + * The layouts should reflect the exact layout of the shaders. Eg. + * descriptorBindings[2] = { sampler, sampled image } is different from * descriptorBindings[2] = { sampled image, sampler }. The ordering must be correct. * * @since 2.0 @@ -726,7 +726,7 @@ typedef struct PalAccelerationStructure PalAccelerationStructure; /** * @typedef PalDebugMessageSeverity * @brief Debugger messages severity types used to filter incoming messages. - * + * * All message severities follow the format `PAL_DEBUG_MESSAGE_SEVERITY_**` for * consistency and API use. * @@ -737,7 +737,7 @@ typedef uint32_t PalDebugMessageSeverity; /** * @typedef PalDebugMessageType * @brief Debugger messages types used to filter incoming messages. - * + * * All message types follow the format `PAL_DEBUG_MESSAGE_TYPE_**` for * consistency and API use. * @@ -781,9 +781,9 @@ typedef uint32_t PalAdapterType; * * All adapter api types follow the format `PAL_ADAPTER_API_TYPE_**` for * consistency and API use. - * - * Customs backends that dont fit the already declared api types should use - * `PAL_ADAPTER_API_TYPE_CUSTOM`. + * + * Customs backends that dont fit the already declared api types should use + * `PAL_ADAPTER_API_TYPE_CUSTOM`. * * @since 2.0 */ @@ -1214,11 +1214,11 @@ typedef uint32_t PalAccelerationStructureType; /** * @typedef PalAccelerationStructureCreateFlags - * @brief Acceleration structure create flags. Multiple hints can be OR'ed together using + * @brief Acceleration structure create flags. Multiple hints can be OR'ed together using * bitwise OR operator (`|`). * - * All acceleration structure create flags follow the format `PAL_ACCELERATION_STRUCTURE_CREATE_FLAG_**` - * for consistency and API use. + * All acceleration structure create flags follow the format + * `PAL_ACCELERATION_STRUCTURE_CREATE_FLAG_**` for consistency and API use. * * @since 2.0 */ @@ -1228,7 +1228,7 @@ typedef uint32_t PalAccelerationStructureCreateFlags; * @typedef PalAccelerationStructureBuildMode * @brief Acceleration structure build modes. * - * All acceleration structure build modes follow the format + * All acceleration structure build modes follow the format * `PAL_ACCELERATION_STRUCTURE_BUILD_MODE_**` for consistency and API use. * * @since 2.0 @@ -1237,10 +1237,10 @@ typedef uint32_t PalAccelerationStructureBuildMode; /** * @typedef PalAccelerationStructureBuildHints - * @brief Acceleration structure build hints. Multiple hints can be OR'ed together using + * @brief Acceleration structure build hints. Multiple hints can be OR'ed together using * bitwise OR operator (`|`). Hints can be ignored by the driver. * - * All acceleration structure build hints follow the format + * All acceleration structure build hints follow the format * `PAL_ACCELERATION_STRUCTURE_BUILD_HINT_**` for consistency and API use. * * @since 2.0 @@ -1249,10 +1249,10 @@ typedef uint32_t PalAccelerationStructureBuildHints; /** * @typedef PalAccelerationStructureInstanceFlags - * @brief Acceleration structure instance flags. Multiple flags can be OR'ed together using + * @brief Acceleration structure instance flags. Multiple flags can be OR'ed together using * bitwise OR operator (`|`). Not all combinations are valid. * - * All acceleration structure instance flags follow the format + * All acceleration structure instance flags follow the format * `PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_**` for consistency and API use. * * @since 2.0 @@ -1271,7 +1271,7 @@ typedef uint32_t PalGeometryType; /** * @typedef PalGeometryFlags - * @brief Geometry flags. Multiple flags can be OR'ed together using + * @brief Geometry flags. Multiple flags can be OR'ed together using * bitwise OR operator (`|`). Not all combinations are valid. * * All geometry flags follow the format `PAL_GEOMETRY_FLAG_**` for consistency and API use. @@ -1403,16 +1403,16 @@ typedef void(PAL_CALL* PalDebugCallback)( * @since 2.0 */ typedef struct { - uint64_t vram; - uint64_t sharedMemory; - uint32_t vendorId; - uint32_t deviceId; - uint32_t driverVersion; - PalShaderFormats shaderFormats; /**< Supported shader formats mask (eg. Spirv, DXIL, ect).*/ - PalAdapterType type; /**< Discrete, Integrated, etc.*/ - PalAdapterApiType apiType; /**< Vulkan, D3D12, etc.*/ - char name[PAL_ADAPTER_NAME_SIZE]; - char backendName[PAL_ADAPTER_BACKEND_NAME_SIZE]; /**< Adapter backend name (eg. `PAL`, `Custom`).*/ + uint64_t vram; /**< Total video memory in bytes*/ + uint64_t sharedMemory; /**< Total shared memory in bytes*/ + uint32_t vendorId; /**< Adapter vendor id.*/ + uint32_t deviceId; /**< Adapter device id.*/ + uint32_t driverVersion; /**< Adapter version.*/ + PalShaderFormats shaderFormats; /**< (eg. `PAL_SHADER_FORMAT_SPIRV`)*/ + PalAdapterType type; /**< (eg. `PAL_ADAPTER_TYPE_DISCRETE`).*/ + PalAdapterApiType apiType; /**< (eg. `PAL_ADAPTER_API_TYPE_VULKAN`).*/ + char name[PAL_ADAPTER_NAME_SIZE]; /**< Adapter name.*/ + char backendName[PAL_ADAPTER_BACKEND_NAME_SIZE]; /**< Adapter backend name.*/ } PalAdapterInfo; /** @@ -1422,11 +1422,11 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxWidth; - uint32_t maxHeight; - uint32_t maxDepth; - uint32_t maxArrayLayers; - uint32_t maxMipLevels; + uint32_t maxWidth; /**< Max width in pixels.*/ + uint32_t maxHeight; /**< Max height in pixels.*/ + uint32_t maxDepth; /**< Max depth in pixels.*/ + uint32_t maxArrayLayers; /**< Max array layers.*/ + uint32_t maxMipLevels; /**< Max mip map levels.*/ } PalImageCapabilities; /** @@ -1436,19 +1436,19 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxPerStageSampledImages; - uint32_t maxPerSetSampledImages; - uint32_t maxPerStageStorageImages; - uint32_t maxPerSetStorageImages; - uint32_t maxPerStageSamplers; - uint32_t maxPerSetSamplers; - uint32_t maxPerStageStorageBuffers; - uint32_t maxPerSetStorageBuffers; - uint32_t maxPerStageUniformBuffers; - uint32_t maxPerSetUniformBuffers; - uint32_t maxPerStageAccelerationStructure; - uint32_t maxPerSetAccelerationStructure; - uint32_t maxBoundSets; + uint32_t maxPerStageSampledImages; /**< Max sampled images per shader stage .*/ + uint32_t maxPerSetSampledImages; /**< Max sampled images per descriptor set.*/ + uint32_t maxPerStageStorageImages; /**< Max storage images per shader stage.*/ + uint32_t maxPerSetStorageImages; /**< Max storage images per descriptor set.*/ + uint32_t maxPerStageSamplers; /**< Max samplers per shader stage.*/ + uint32_t maxPerSetSamplers; /**< Max samplers per descriptor set.*/ + uint32_t maxPerStageStorageBuffers; /**< Max storage buffers per shader stage.*/ + uint32_t maxPerSetStorageBuffers; /**< Max storage buffers per descriptor set.*/ + uint32_t maxPerStageUniformBuffers; /**< Max uniform buffers per shader stage.*/ + uint32_t maxPerSetUniformBuffers; /**< Max uniform buffers per descriptor set.*/ + uint32_t maxPerStageAccelerationStructure; /**< Max acceleration structures per shader stage.*/ + uint32_t maxPerSetAccelerationStructure; /**< Max acceleration structures per descriptor set.*/ + uint32_t maxBoundSets; /**< Max bound descriptor sets.*/ } PalResourceCapabilities; /** @@ -1458,9 +1458,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxWorkGroupInvocations; - uint32_t maxWorkGroupCount[3]; - uint32_t maxWorkGroupSize[3]; + uint32_t maxWorkGroupInvocations; /**< Max invocations across all workgroups.*/ + uint32_t maxWorkGroupCount[3]; /**< Max workgroups per dimension.*/ + uint32_t maxWorkGroupSize[3]; /**< Max workgroup size per dimension.*/ } PalComputeCapabilities; /** @@ -1470,10 +1470,10 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxWidth; - uint32_t maxHeight; - float minBoundsRange; - float maxBoundsRange; + uint32_t maxWidth; /**< Max width in pixels.*/ + uint32_t maxHeight; /**< Max height in pixels.*/ + float minBoundsRange; /**< Min coordinate range.*/ + float maxBoundsRange; /**< Max coordinate range.*/ } PalViewportCapabilities; /** @@ -1483,20 +1483,20 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxComputeQueues; - uint32_t maxGraphicsQueues; - uint32_t maxCopyQueues; - uint32_t maxColorAttachments; - uint32_t maxUniformBufferSize; - uint32_t maxStorageBufferSize; - uint32_t maxPushConstantSize; - uint32_t maxVertexLayouts; - uint32_t maxVertexAttributes; - uint32_t maxTessellationPatchPoint; - PalViewportCapabilities viewportCaps; - PalImageCapabilities imageCaps; - PalResourceCapabilities resourceCaps; - PalComputeCapabilities computeCaps; + uint32_t maxComputeQueues; /**< Max compute queues that can b created.*/ + uint32_t maxGraphicsQueues; /**< Max graphics queues that can b created.*/ + uint32_t maxCopyQueues; /**< Max copy queues that can b created.*/ + uint32_t maxColorAttachments; /**< Max number of simultaneous color attachments.*/ + uint32_t maxUniformBufferSize; /**< Max uniform buffer size in bytes.*/ + uint32_t maxStorageBufferSize; /**< Max storage buffer size in bytes.*/ + uint32_t maxPushConstantSize; /**< Max push constants size in bytes.*/ + uint32_t maxVertexLayouts; /**< Max vertex layouts.*/ + uint32_t maxVertexAttributes; /**< Max vertex attributes across all vertex layouts.*/ + uint32_t maxTessellationPatchPoint; /**< Max tessellation patch point.*/ + PalViewportCapabilities viewportCaps; /**< Viewport capabilities.*/ + PalImageCapabilities imageCaps; /**< Image capabilities.*/ + PalResourceCapabilities resourceCaps; /**< resource (descriptors) capabilities.*/ + PalComputeCapabilities computeCaps; /**< Compute capabilities.*/ } PalAdapterCapabilities; /** @@ -1506,7 +1506,7 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxAnisotropy; + uint32_t maxAnisotropy; /**< Max texture filtering level.*/ } PalSamplerAnisotropyCapabilities; /** @@ -1516,7 +1516,7 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxViewCount; + uint32_t maxViewCount; /**< Max number views of an image.*/ } PalMultiViewCapabilities; /** @@ -1526,20 +1526,24 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxCount; + uint32_t maxCount; /**< Max number of simultaneous viewports.*/ } PalMultiViewportCapabilities; /** * @struct PalDepthStencilCapabilities * @brief Depth stencil capabilities of an adapter (GPU). - * + * * @since 2.0 */ typedef struct { - uint32_t supportedDepthResolveModes; - uint32_t supportedStencilResolveModes; + uint32_t supportedDepthResolveModes; /**< Masks of supported depth resolve modes.*/ + uint32_t supportedStencilResolveModes; /**< Masks of supported stencil resolve modes.*/ + + /** If `PAL_TRUE`, depth/stencil can have seperate resolve modes.*/ PalBool supportsIndependentResolve; - PalBool supportsIndependentResolveNone; /**< If PAL_TRUE, depth or stencil can be NONE while the other is resolved.*/ + + /**If `PAL_TRUE`, depth/stencil can be `PAL_RESOLVE_MODE_NONE` while the other is resolved.*/ + PalBool supportsIndependentResolveNone; } PalDepthStencilCapabilities; /** @@ -1549,12 +1553,12 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t supportedShadingRates; - uint32_t supportedCombinerOps; - uint32_t minTexelWidth; - uint32_t minTexelHeight; - uint32_t maxTexelWidth; - uint32_t maxTexelHeight; + uint32_t supportedShadingRates; /**< Masks of supported shading rates.*/ + uint32_t supportedCombinerOps; /**< Masks of supported combiner operations.*/ + uint32_t minTexelWidth; /**< Min texel width in pixels*/ + uint32_t minTexelHeight; /**< Min texel height in pixels*/ + uint32_t maxTexelWidth; /**< Max texel width in pixels*/ + uint32_t maxTexelHeight; /**< Max texel height in pixels*/ } PalFragmentShadingRateCapabilities; /** @@ -1564,12 +1568,12 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxOutputPrimitives; - uint32_t maxOutputVertices; - uint32_t maxWorkGroupInvocations; - uint32_t maxTaskWorkGroupInvocations; - uint32_t maxWorkGroupCount[3]; - uint32_t maxTaskWorkGroupCount[3]; + uint32_t maxOutputPrimitives; /**< Max number of primitives per mesh workgroup.*/ + uint32_t maxOutputVertices; /**< Max number of vertices per mesh workgroup.*/ + uint32_t maxWorkGroupInvocations; /**< Max mesh invocations across all workgroups.*/ + uint32_t maxTaskWorkGroupInvocations; /**< Max task invocations across all workgroups.*/ + uint32_t maxWorkGroupCount[3]; /**< Max mesh workgroups per dimension.*/ + uint32_t maxTaskWorkGroupCount[3]; /**< Max task workgroups per dimension.*/ } PalMeshShaderCapabilities; /** @@ -1579,13 +1583,13 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxRecursionDepth; - uint32_t maxHitAttributeSize; - uint32_t maxInstanceCount; - uint32_t maxPrimitiveCount; - uint32_t maxGeometryCount; - uint32_t maxPayloadSize; - uint32_t maxDispatchInvocations; + uint32_t maxRecursionDepth; /**< Max number of ray recursion.*/ + uint32_t maxHitAttributeSize; /**< Max attributes size in bytes.*/ + uint32_t maxInstanceCount; /**< Max number of instances.*/ + uint32_t maxPrimitiveCount; /**< Max number of primitives.*/ + uint32_t maxGeometryCount; /**< Max number of geometries.*/ + uint32_t maxPayloadSize; /**< Max payload size in bytes.*/ + uint32_t maxDispatchInvocations; /**< Max number of dispatch threads.*/ } PalRayTracingCapabilities; /** @@ -1595,19 +1599,19 @@ typedef struct { * @since 2.0 */ typedef struct { - PalDescriptorIndexingFlags flags; - uint32_t maxPerStageSampledImages; - uint32_t maxPerSetSampledImages; - uint32_t maxPerStageStorageImages; - uint32_t maxPerSetStorageImages; - uint32_t maxPerStageSamplers; - uint32_t maxPerSetSamplers; - uint32_t maxPerStageStorageBuffers; - uint32_t maxPerSetStorageBuffers; - uint32_t maxPerStageUniformBuffers; - uint32_t maxPerSetUniformBuffers; - uint32_t maxPerStageAccelerationStructure; - uint32_t maxPerSetAccelerationStructure; + PalDescriptorIndexingFlags flags; /**< Capabilities flags. see `PalDescriptorIndexingFlags`*/ + uint32_t maxPerStageSampledImages; /**< Max sampled images per shader stage .*/ + uint32_t maxPerSetSampledImages; /**< Max sampled images per descriptor set.*/ + uint32_t maxPerStageStorageImages; /**< Max storage images per shader stage.*/ + uint32_t maxPerSetStorageImages; /**< Max storage images per descriptor set.*/ + uint32_t maxPerStageSamplers; /**< Max samplers per shader stage.*/ + uint32_t maxPerSetSamplers; /**< Max samplers per descriptor set.*/ + uint32_t maxPerStageStorageBuffers; /**< Max storage buffers per shader stage.*/ + uint32_t maxPerSetStorageBuffers; /**< Max storage buffers per descriptor set.*/ + uint32_t maxPerStageUniformBuffers; /**< Max uniform buffers per shader stage.*/ + uint32_t maxPerSetUniformBuffers; /**< Max uniform buffers per descriptor set.*/ + uint32_t maxPerStageAccelerationStructure; /**< Max acceleration structures per shader stage.*/ + uint32_t maxPerSetAccelerationStructure; /**< Max acceleration structures per descriptor set.*/ } PalDescriptorIndexingCapabilities; /** @@ -1650,9 +1654,9 @@ typedef struct { */ typedef struct { PalImageUsages usages; - uint32_t width; /**< Width of the image in pixels.*/ - uint32_t height; /**< Height of the image in pixels.*/ - uint32_t depth; /**< Depth of the image in pixels.*/ + uint32_t width; /**< Width of the image in pixels.*/ + uint32_t height; /**< Height of the image in pixels.*/ + uint32_t depth; /**< Depth of the image in pixels.*/ uint32_t arrayLayerCount; uint32_t mipLevelCount; PalSampleCount sampleCount; @@ -1690,10 +1694,10 @@ typedef struct { PalStoreOp storeOp; PalLoadOp stencilLoadOp; PalStoreOp stencilStoreOp; - PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ - PalResolveMode stencilResolveMode; /**< Used if resolveImageView is set.*/ - uint32_t texelWidth; /**< Texel width for fragment shading rate attachment.*/ - uint32_t texelHeight; /**< Texel height for fragment shading rate attachment.*/ + PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ + PalResolveMode stencilResolveMode; /**< Used if resolveImageView is set.*/ + uint32_t texelWidth; /**< Texel width for fragment shading rate attachment.*/ + uint32_t texelHeight; /**< Texel height for fragment shading rate attachment.*/ PalClearValue clearValue; } PalAttachmentDesc; @@ -1764,7 +1768,7 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t timeout; /**< Timeout in milliseconds.*/ + uint64_t timeout; /**< Timeout in milliseconds.*/ uint64_t signalValue; PalSemaphore* signalSemaphore; PalFence* fence; @@ -1905,11 +1909,11 @@ typedef struct { /** * @struct PalVertexLayout * @brief Vertex layout. - * + * * This defines the layout, ordering and the number of vertex attributes the layout uses. - * - * The layouts should reflect the exact layout of the shaders. Eg. - * attributes[2] = { position, color } is different from + * + * The layouts should reflect the exact layout of the shaders. Eg. + * attributes[2] = { position, color } is different from * attributes[2] = { color, position }. The ordering must be correct. * * Uninitialized fields may result in undefined behavior. @@ -2058,7 +2062,7 @@ typedef struct { uint32_t mask; uint32_t instanceId; uint32_t hitGroupOffset; - float transform[12]; /**< row major (3x4).*/ + float transform[12]; /**< row major (3x4).*/ } PalAccelerationStructureInstance; /** @@ -2069,8 +2073,8 @@ typedef struct { */ typedef struct { uint64_t accelerationStructureSize; - uint64_t scratchBufferSize; - uint64_t updateScratchBufferSize; + uint64_t scratchBufferSize; + uint64_t updateScratchBufferSize; } PalAccelerationStructureBuildSize; /** @@ -2177,7 +2181,7 @@ typedef struct { typedef struct { PalBuffer* buffer; uint64_t offset; /**< Offset in bytes. If structured, will be divided by `stride`.*/ - uint64_t size; + uint64_t size; uint64_t stride; /**< For structured buffers. Will be ignored if not supported. 0 for default.*/ } PalDescriptorBufferInfo; @@ -2234,7 +2238,7 @@ typedef struct { PalDescriptorType descriptorType; uint32_t layoutBindingIndex; /**< Index into the descriptor set layout bindings.*/ uint32_t arrayElement; - uint32_t descriptorCount; + uint32_t descriptorCount; } PalDescriptorSetWriteInfo; /** @@ -2335,14 +2339,15 @@ typedef struct { * @brief Information for image to image copies. * * Uninitialized fields may result in undefined behavior. - * - * The records array must be in this order [raygen][miss][hitgroup][callable]. + * + * The records array must be in this order [raygen][miss][hitgroup][callable]. * * @since 2.0 */ typedef struct { void* localData; - uint32_t groupIndex; /**< Index into the shader groups used to create the ray tracing pipeline.*/ + uint32_t + groupIndex; /**< Index into the shader groups used to create the ray tracing pipeline.*/ uint32_t localDataSize; /**< Must not be greater than the data size of the group.*/ } PalShaderBindingTableRecordInfo; @@ -2501,7 +2506,7 @@ typedef struct { /** * @struct PalDescriptorPoolCreateInfo * @brief Creation parameters for a descriptor pool. - * + * * Uninitialized fields may result in undefined behavior. * * @since 2.0 @@ -2550,7 +2555,7 @@ typedef struct { uint32_t vertexLayoutCount; uint32_t colorBlendAttachmentCount; uint32_t shaderCount; - PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is `PAL_TRUE`.*/ + PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is `PAL_TRUE`.*/ PalPrimitiveTopology topology; } PalGraphicsPipelineCreateInfo; @@ -2572,8 +2577,8 @@ typedef struct { * @brief Creation parameters for a ray tracing pipeline shader group. * * Uninitialized fields may result in undefined behavior. - * - * The shader group array must be in this order [raygen][miss][hitgroup][callable]. + * + * The shader group array must be in this order [raygen][miss][hitgroup][callable]. * * @since 2.0 */ @@ -2587,7 +2592,7 @@ typedef struct { uint32_t generalShaderEntryIndex; uint32_t intersectionShaderIndex; uint32_t intersectionShaderEntryIndex; - uint32_t maxDataSize; /**< Size of extra data associated with the shader group.*/ + uint32_t maxDataSize; /**< Size of extra data associated with the shader group.*/ } PalRayTracingShaderGroupCreateInfo; /** @@ -2641,12 +2646,12 @@ typedef struct { * @brief Version 1 dispatch table for PAL graphics system backends. * * Uninitialized fields may result in undefined behavior. - * + * * All backend handle implementation (eg. struct CustomBuffer) must reserve its first field as * a `void*` and set it to `PAL_BACKEND_KEY` at the handles creation function pointer - * (eg. createBufferCustom). This will be validated at the handle creation function + * (eg. createBufferCustom). This will be validated at the handle creation function * (eg. palCreateBuffer). - * + * * Pal trust thee backend author to not overwrite or use the reserve space. It is used by the * graphics layer. * @@ -2658,7 +2663,7 @@ typedef struct { * * Must obey the rules and semantics documented in palEnumerateAdapters(). */ - PalResult (PAL_CALL *enumerateAdapters)( + PalResult(PAL_CALL* enumerateAdapters)( int32_t* count, PalAdapter** outAdapters); @@ -2667,7 +2672,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetAdapterInfo(). */ - PalResult (PAL_CALL *getAdapterInfo)( + PalResult(PAL_CALL* getAdapterInfo)( PalAdapter* adapter, PalAdapterInfo* info); @@ -2676,7 +2681,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetAdapterCapabilities(). */ - PalResult (PAL_CALL *getAdapterCapabilities)( + PalResult(PAL_CALL* getAdapterCapabilities)( PalAdapter* adapter, PalAdapterCapabilities* caps); @@ -2685,15 +2690,15 @@ typedef struct { * * Must obey the rules and semantics documented in palGetAdapterFeatures(). */ - PalAdapterFeatures (PAL_CALL *getAdapterFeatures)(PalAdapter* adapter); + PalAdapterFeatures(PAL_CALL* getAdapterFeatures)(PalAdapter* adapter); /** * Backend implementation of ::palGetHighestSupportedShaderTarget. * * Must obey the rules and semantics documented in palGetHighestSupportedShaderTarget(). */ - uint32_t (PAL_CALL *getHighestSupportedShaderTarget)( - PalAdapter* adapter, + uint32_t(PAL_CALL* getHighestSupportedShaderTarget)( + PalAdapter* adapter, PalShaderFormats shaderFormat); /** @@ -2701,7 +2706,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateDevice(). */ - PalResult (PAL_CALL *createDevice)( + PalResult(PAL_CALL* createDevice)( PalAdapter* adapter, PalAdapterFeatures features, PalDevice** outDevice); @@ -2711,14 +2716,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyDevice(). */ - void (PAL_CALL *destroyDevice)(PalDevice* device); + void(PAL_CALL* destroyDevice)(PalDevice* device); /** * Backend implementation of ::palAllocateMemory. * * Must obey the rules and semantics documented in palAllocateMemory(). */ - PalResult (PAL_CALL *allocateMemory)( + PalResult(PAL_CALL* allocateMemory)( PalDevice* device, PalMemoryType type, uint64_t memoryMask, @@ -2730,7 +2735,7 @@ typedef struct { * * Must obey the rules and semantics documented in palFreeMemory(). */ - void (PAL_CALL *freeMemory)( + void(PAL_CALL* freeMemory)( PalDevice* device, PalMemory* memory); @@ -2740,7 +2745,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQuerySamplerAnisotropyCapabilities(). */ - PalResult (PAL_CALL *querySamplerAnisotropyCapabilities)( + PalResult(PAL_CALL* querySamplerAnisotropyCapabilities)( PalDevice* device, PalSamplerAnisotropyCapabilities* caps); @@ -2750,7 +2755,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryMultiViewCapabilities(). */ - PalResult (PAL_CALL *queryMultiViewCapabilities)( + PalResult(PAL_CALL* queryMultiViewCapabilities)( PalDevice* device, PalMultiViewCapabilities* caps); @@ -2760,7 +2765,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryMultiViewportCapabilities(). */ - PalResult (PAL_CALL *queryMultiViewportCapabilities)( + PalResult(PAL_CALL* queryMultiViewportCapabilities)( PalDevice* device, PalMultiViewportCapabilities* caps); @@ -2770,7 +2775,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryDepthStencilCapabilities(). */ - PalResult (PAL_CALL *queryDepthStencilCapabilities)( + PalResult(PAL_CALL* queryDepthStencilCapabilities)( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -2780,7 +2785,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryFragmentShadingRateCapabilities(). */ - PalResult (PAL_CALL *queryFragmentShadingRateCapabilities)( + PalResult(PAL_CALL* queryFragmentShadingRateCapabilities)( PalDevice* device, PalFragmentShadingRateCapabilities* caps); @@ -2790,7 +2795,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryMeshShaderCapabilities(). */ - PalResult (PAL_CALL *queryMeshShaderCapabilities)( + PalResult(PAL_CALL* queryMeshShaderCapabilities)( PalDevice* device, PalMeshShaderCapabilities* caps); @@ -2800,7 +2805,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryRayTracingCapabilities(). */ - PalResult (PAL_CALL *queryRayTracingCapabilities)( + PalResult(PAL_CALL* queryRayTracingCapabilities)( PalDevice* device, PalRayTracingCapabilities* caps); @@ -2810,7 +2815,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryDescriptorIndexingCapabilities(). */ - PalResult (PAL_CALL *queryDescriptorIndexingCapabilities)( + PalResult(PAL_CALL* queryDescriptorIndexingCapabilities)( PalDevice* device, PalDescriptorIndexingCapabilities* caps); @@ -2819,7 +2824,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateQueue(). */ - PalResult (PAL_CALL *createQueue)( + PalResult(PAL_CALL* createQueue)( PalDevice* device, PalQueueType type, PalQueue** outQueue); @@ -2829,14 +2834,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyQueue(). */ - void (PAL_CALL *destroyQueue)(PalQueue* queue); + void(PAL_CALL* destroyQueue)(PalQueue* queue); /** * Backend implementation of ::palCanQueuePresent. * * Must obey the rules and semantics documented in palCanQueuePresent(). */ - PalBool (PAL_CALL *canQueuePresent)( + PalBool(PAL_CALL* canQueuePresent)( PalQueue* queue, PalSurface* surface); @@ -2845,14 +2850,14 @@ typedef struct { * * Must obey the rules and semantics documented in palWaitQueue(). */ - PalResult (PAL_CALL *waitQueue)(PalQueue* queue); + PalResult(PAL_CALL* waitQueue)(PalQueue* queue); /** * Backend implementation of ::palEnumerateFormats. * * Must obey the rules and semantics documented in palEnumerateFormats(). */ - PalResult (PAL_CALL *enumerateFormats)( + PalResult(PAL_CALL* enumerateFormats)( PalAdapter* adapter, int32_t* count, PalFormatInfo* outFormats); @@ -2862,7 +2867,7 @@ typedef struct { * * Must obey the rules and semantics documented in palIsFormatSupported(). */ - PalBool (PAL_CALL *isFormatSupported)( + PalBool(PAL_CALL* isFormatSupported)( PalAdapter* adapter, PalFormat format); @@ -2871,7 +2876,7 @@ typedef struct { * * Must obey the rules and semantics documented in palQueryFormatImageUsages(). */ - PalImageUsages (PAL_CALL *queryFormatImageUsages)( + PalImageUsages(PAL_CALL* queryFormatImageUsages)( PalAdapter* adapter, PalFormat format); @@ -2880,7 +2885,7 @@ typedef struct { * * Must obey the rules and semantics documented in palQueryFormatSampleCount(). */ - PalSampleCount (PAL_CALL *queryFormatSampleCount)( + PalSampleCount(PAL_CALL* queryFormatSampleCount)( PalAdapter* adapter, PalFormat format); @@ -2889,7 +2894,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateImage(). */ - PalResult (PAL_CALL *createImage)( + PalResult(PAL_CALL* createImage)( PalDevice* device, const PalImageCreateInfo* info, PalImage** outImage); @@ -2899,14 +2904,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyImage(). */ - void (PAL_CALL *destroyImage)(PalImage* image); + void(PAL_CALL* destroyImage)(PalImage* image); /** * Backend implementation of ::palGetImageInfo. * * Must obey the rules and semantics documented in palGetImageInfo(). */ - PalResult (PAL_CALL *getImageInfo)( + PalResult(PAL_CALL* getImageInfo)( PalImage* image, PalImageInfo* info); @@ -2915,7 +2920,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetImageMemoryRequirements(). */ - PalResult (PAL_CALL *getImageMemoryRequirements)( + PalResult(PAL_CALL* getImageMemoryRequirements)( PalImage* image, PalMemoryRequirements* requirements); @@ -2924,7 +2929,7 @@ typedef struct { * * Must obey the rules and semantics documented in palBindImageMemory(). */ - PalResult (PAL_CALL *bindImageMemory)( + PalResult(PAL_CALL* bindImageMemory)( PalImage* image, PalMemory* memory, uint64_t offset); @@ -2934,7 +2939,7 @@ typedef struct { * * Must obey the rules and semantics documented in palMapImageMemory(). */ - PalResult (PAL_CALL *mapImageMemory)( + PalResult(PAL_CALL* mapImageMemory)( PalImage* image, uint64_t offset, uint64_t size, @@ -2945,14 +2950,14 @@ typedef struct { * * Must obey the rules and semantics documented in palUnmapImageMemory(). */ - void (PAL_CALL *unmapImageMemory)(PalImage* image); + void(PAL_CALL* unmapImageMemory)(PalImage* image); /** * Backend implementation of ::palCreateImageView. * * Must obey the rules and semantics documented in palCreateImageView(). */ - PalResult (PAL_CALL *createImageView)( + PalResult(PAL_CALL* createImageView)( PalDevice* device, PalImage* image, const PalImageViewCreateInfo* info, @@ -2963,14 +2968,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyImageView(). */ - void (PAL_CALL *destroyImageView)(PalImageView* imageView); + void(PAL_CALL* destroyImageView)(PalImageView* imageView); /** * Backend implementation of ::palCreateSampler. * * Must obey the rules and semantics documented in palCreateSampler(). */ - PalResult (PAL_CALL *createSampler)( + PalResult(PAL_CALL* createSampler)( PalDevice* device, const PalSamplerCreateInfo* info, PalSampler** outSampler); @@ -2980,14 +2985,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroySampler(). */ - void (PAL_CALL *destroySampler)(PalSampler* sampler); + void(PAL_CALL* destroySampler)(PalSampler* sampler); /** * Backend implementation of ::palCreateSurface. * * Must obey the rules and semantics documented in palCreateSurface(). */ - PalResult (PAL_CALL *createSurface)( + PalResult(PAL_CALL* createSurface)( PalDevice* device, void* window, void* windowInstance, @@ -2999,14 +3004,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroySurface(). */ - void (PAL_CALL *destroySurface)(PalSurface* surface); + void(PAL_CALL* destroySurface)(PalSurface* surface); /** * Backend implementation of ::palGetSurfaceCapabilities. * * Must obey the rules and semantics documented in palGetSurfaceCapabilities(). */ - PalResult (PAL_CALL *getSurfaceCapabilities)( + PalResult(PAL_CALL* getSurfaceCapabilities)( PalDevice* device, PalSurface* surface, PalSurfaceCapabilities* caps); @@ -3016,7 +3021,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateSwapchain(). */ - PalResult (PAL_CALL *createSwapchain)( + PalResult(PAL_CALL* createSwapchain)( PalDevice* device, PalQueue* queue, PalSurface* surface, @@ -3028,14 +3033,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroySwapchain(). */ - void (PAL_CALL *destroySwapchain)(PalSwapchain* swapchain); + void(PAL_CALL* destroySwapchain)(PalSwapchain* swapchain); /** * Backend implementation of ::palGetSwapchainImage. * * Must obey the rules and semantics documented in palGetSwapchainImage(). */ - PalImage* (PAL_CALL *getSwapchainImage)( + PalImage*(PAL_CALL* getSwapchainImage)( PalSwapchain* swapchain, int32_t index); @@ -3044,7 +3049,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetNextSwapchainImage(). */ - PalResult (PAL_CALL *getNextSwapchainImage)( + PalResult(PAL_CALL* getNextSwapchainImage)( PalSwapchain* swapchain, PalSwapchainNextImageInfo* info, uint32_t* outIndex); @@ -3054,7 +3059,7 @@ typedef struct { * * Must obey the rules and semantics documented in palPresentSwapchain(). */ - PalResult (PAL_CALL *presentSwapchain)( + PalResult(PAL_CALL* presentSwapchain)( PalSwapchain* swapchain, PalSwapchainPresentInfo* info); @@ -3063,7 +3068,7 @@ typedef struct { * * Must obey the rules and semantics documented in palResizeSwapchain(). */ - PalResult (PAL_CALL *resizeSwapchain)( + PalResult(PAL_CALL* resizeSwapchain)( PalSwapchain* swapchain, uint32_t newWidth, uint32_t newHeight); @@ -3073,7 +3078,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateShader(). */ - PalResult (PAL_CALL *createShader)( + PalResult(PAL_CALL* createShader)( PalDevice* device, const PalShaderCreateInfo* info, PalShader** outShader); @@ -3083,14 +3088,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyShader(). */ - void (PAL_CALL *destroyShader)(PalShader* shader); + void(PAL_CALL* destroyShader)(PalShader* shader); /** * Backend implementation of ::palCreateFence. * * Must obey the rules and semantics documented in palCreateFence(). */ - PalResult (PAL_CALL *createFence)( + PalResult(PAL_CALL* createFence)( PalDevice* device, PalBool signaled, PalFence** outFence); @@ -3100,14 +3105,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyFence(). */ - void (PAL_CALL *destroyFence)(PalFence* fence); + void(PAL_CALL* destroyFence)(PalFence* fence); /** * Backend implementation of ::palWaitFence. * * Must obey the rules and semantics documented in palWaitFence(). */ - PalResult (PAL_CALL *waitFence)( + PalResult(PAL_CALL* waitFence)( PalFence* fence, uint64_t timeout); @@ -3116,21 +3121,21 @@ typedef struct { * * Must obey the rules and semantics documented in palResetFence(). */ - PalResult (PAL_CALL *resetFence)(PalFence* fence); + PalResult(PAL_CALL* resetFence)(PalFence* fence); /** * Backend implementation of ::palIsFenceSignaled. * * Must obey the rules and semantics documented in palIsFenceSignaled(). */ - PalBool (PAL_CALL *isFenceSignaled)(PalFence* fence); + PalBool(PAL_CALL* isFenceSignaled)(PalFence* fence); /** * Backend implementation of ::palCreateSemaphore. * * Must obey the rules and semantics documented in palCreateSemaphore(). */ - PalResult (PAL_CALL *createSemaphore)( + PalResult(PAL_CALL* createSemaphore)( PalDevice* device, PalBool enableTimeline, PalSemaphore** outSemaphore); @@ -3140,14 +3145,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroySemaphore(). */ - void (PAL_CALL *destroySemaphore)(PalSemaphore* semaphore); + void(PAL_CALL* destroySemaphore)(PalSemaphore* semaphore); /** * Backend implementation of ::palWaitSemaphore. * * Must obey the rules and semantics documented in palWaitSemaphore(). */ - PalResult (PAL_CALL *waitSemaphore)( + PalResult(PAL_CALL* waitSemaphore)( PalSemaphore* semaphore, uint64_t value, uint64_t timeout); @@ -3157,7 +3162,7 @@ typedef struct { * * Must obey the rules and semantics documented in palSignalSemaphore(). */ - PalResult (PAL_CALL *signalSemaphore)( + PalResult(PAL_CALL* signalSemaphore)( PalSemaphore* semaphore, PalQueue* queue, uint64_t value); @@ -3167,7 +3172,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetSemaphoreValue(). */ - PalResult (PAL_CALL *getSemaphoreValue)( + PalResult(PAL_CALL* getSemaphoreValue)( PalSemaphore* semaphore, uint64_t* outValue); @@ -3176,7 +3181,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateCommandPool(). */ - PalResult (PAL_CALL *createCommandPool)( + PalResult(PAL_CALL* createCommandPool)( PalDevice* device, PalQueue* queue, PalCommandPool** outPool); @@ -3186,21 +3191,21 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyCommandPool(). */ - void (PAL_CALL *destroyCommandPool)(PalCommandPool* pool); + void(PAL_CALL* destroyCommandPool)(PalCommandPool* pool); /** * Backend implementation of ::palResetCommandPool. * * Must obey the rules and semantics documented in palResetCommandPool(). */ - PalResult (PAL_CALL *resetCommandPool)(PalCommandPool* pool); + PalResult(PAL_CALL* resetCommandPool)(PalCommandPool* pool); /** * Backend implementation of ::palAllocateCommandBuffer. * * Must obey the rules and semantics documented in palAllocateCommandBuffer(). */ - PalResult (PAL_CALL *allocateCommandBuffer)( + PalResult(PAL_CALL* allocateCommandBuffer)( PalDevice* device, PalCommandPool* pool, PalCommandBufferType type, @@ -3211,21 +3216,21 @@ typedef struct { * * Must obey the rules and semantics documented in palFreeCommandBuffer(). */ - void (PAL_CALL *freeCommandBuffer)(PalCommandBuffer* cmdBuffer); + void(PAL_CALL* freeCommandBuffer)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palResetCommandBuffer. * * Must obey the rules and semantics documented in palResetCommandBuffer(). */ - PalResult (PAL_CALL *resetCommandBuffer)(PalCommandBuffer* cmdBuffer); + PalResult(PAL_CALL* resetCommandBuffer)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palSubmitCommandBuffer. * * Must obey the rules and semantics documented in palSubmitCommandBuffer(). */ - PalResult (PAL_CALL *submitCommandBuffer)( + PalResult(PAL_CALL* submitCommandBuffer)( PalQueue* queue, PalCommandBufferSubmitInfo* info); @@ -3234,7 +3239,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBegin(). */ - PalResult (PAL_CALL *cmdBegin)( + PalResult(PAL_CALL* cmdBegin)( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info); @@ -3243,14 +3248,14 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdEnd(). */ - PalResult (PAL_CALL *cmdEnd)(PalCommandBuffer* cmdBuffer); + PalResult(PAL_CALL* cmdEnd)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palCmdExecuteCommandBuffer. * * Must obey the rules and semantics documented in palCmdExecuteCommandBuffer(). */ - PalResult (PAL_CALL *cmdExecuteCommandBuffer)( + PalResult(PAL_CALL* cmdExecuteCommandBuffer)( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -3259,7 +3264,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetFragmentShadingRate(). */ - PalResult (PAL_CALL *cmdSetFragmentShadingRate)( + PalResult(PAL_CALL* cmdSetFragmentShadingRate)( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state); @@ -3268,7 +3273,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawMeshTasks(). */ - PalResult (PAL_CALL *cmdDrawMeshTasks)( + PalResult(PAL_CALL* cmdDrawMeshTasks)( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, @@ -3279,7 +3284,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawMeshTasksIndirect(). */ - PalResult (PAL_CALL *cmdDrawMeshTasksIndirect)( + PalResult(PAL_CALL* cmdDrawMeshTasksIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t drawCount); @@ -3289,7 +3294,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawMeshTasksIndirectCount(). */ - PalResult (PAL_CALL *cmdDrawMeshTasksIndirectCount)( + PalResult(PAL_CALL* cmdDrawMeshTasksIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -3300,7 +3305,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBuildAccelerationStructure(). */ - PalResult (PAL_CALL *cmdBuildAccelerationStructure)( + PalResult(PAL_CALL* cmdBuildAccelerationStructure)( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); @@ -3309,7 +3314,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBeginRendering(). */ - PalResult (PAL_CALL *cmdBeginRendering)( + PalResult(PAL_CALL* cmdBeginRendering)( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info); @@ -3318,14 +3323,14 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdEndRendering(). */ - PalResult (PAL_CALL *cmdEndRendering)(PalCommandBuffer* cmdBuffer); + PalResult(PAL_CALL* cmdEndRendering)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palCmdCopyBuffer. * * Must obey the rules and semantics documented in palCmdCopyBuffer(). */ - PalResult (PAL_CALL *cmdCopyBuffer)( + PalResult(PAL_CALL* cmdCopyBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -3336,7 +3341,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdCopyBufferToImage(). */ - PalResult (PAL_CALL *cmdCopyBufferToImage)( + PalResult(PAL_CALL* cmdCopyBufferToImage)( PalCommandBuffer* cmdBuffer, PalImage* dstImage, PalBuffer* srcBuffer, @@ -3347,7 +3352,7 @@ typedef struct { * * Must obey the rules and semantics documented in cmdCopyImage(). */ - PalResult (PAL_CALL *cmdCopyImage)( + PalResult(PAL_CALL* cmdCopyImage)( PalCommandBuffer* cmdBuffer, PalImage* dst, PalImage* src, @@ -3358,7 +3363,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdCopyImageToBuffer(). */ - PalResult (PAL_CALL *cmdCopyImageToBuffer)( + PalResult(PAL_CALL* cmdCopyImageToBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, @@ -3369,7 +3374,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindPipeline(). */ - PalResult (PAL_CALL *cmdBindPipeline)( + PalResult(PAL_CALL* cmdBindPipeline)( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline); @@ -3378,7 +3383,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetViewport(). */ - PalResult (PAL_CALL *cmdSetViewport)( + PalResult(PAL_CALL* cmdSetViewport)( PalCommandBuffer* cmdBuffer, uint32_t count, PalViewport* viewports); @@ -3388,7 +3393,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetScissors(). */ - PalResult (PAL_CALL *cmdSetScissors)( + PalResult(PAL_CALL* cmdSetScissors)( PalCommandBuffer* cmdBuffer, uint32_t count, PalRect2D* scissors); @@ -3398,7 +3403,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindVertexBuffers(). */ - PalResult (PAL_CALL *cmdBindVertexBuffers)( + PalResult(PAL_CALL* cmdBindVertexBuffers)( PalCommandBuffer* cmdBuffer, uint32_t firstSlot, uint32_t count, @@ -3410,7 +3415,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindIndexBuffer(). */ - PalResult (PAL_CALL *cmdBindIndexBuffer)( + PalResult(PAL_CALL* cmdBindIndexBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint64_t offset, @@ -3421,7 +3426,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDraw(). */ - PalResult (PAL_CALL *cmdDraw)( + PalResult(PAL_CALL* cmdDraw)( PalCommandBuffer* cmdBuffer, uint32_t vertexCount, uint32_t instanceCount, @@ -3433,7 +3438,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndirect(). */ - PalResult (PAL_CALL *cmdDrawIndirect)( + PalResult(PAL_CALL* cmdDrawIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count); @@ -3443,7 +3448,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndirectCount(). */ - PalResult (PAL_CALL *cmdDrawIndirectCount)( + PalResult(PAL_CALL* cmdDrawIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -3454,7 +3459,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndexed(). */ - PalResult (PAL_CALL *cmdDrawIndexed)( + PalResult(PAL_CALL* cmdDrawIndexed)( PalCommandBuffer* cmdBuffer, uint32_t indexCount, uint32_t instanceCount, @@ -3467,7 +3472,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndexedIndirect(). */ - PalResult (PAL_CALL *cmdDrawIndexedIndirect)( + PalResult(PAL_CALL* cmdDrawIndexedIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count); @@ -3477,7 +3482,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndexedIndirectCount(). */ - PalResult (PAL_CALL *cmdDrawIndexedIndirectCount)( + PalResult(PAL_CALL* cmdDrawIndexedIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -3488,7 +3493,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdAccelerationStructureBarrier(). */ - PalResult (PAL_CALL *cmdAccelerationStructureBarrier)( + PalResult(PAL_CALL* cmdAccelerationStructureBarrier)( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, PalUsageState oldUsageState, @@ -3499,7 +3504,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdImageBarrier(). */ - PalResult (PAL_CALL *cmdImageBarrier)( + PalResult(PAL_CALL* cmdImageBarrier)( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, @@ -3511,7 +3516,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBufferBarrier(). */ - PalResult (PAL_CALL *cmdBufferBarrier)( + PalResult(PAL_CALL* cmdBufferBarrier)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageState oldUsageState, @@ -3522,7 +3527,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDispatch(). */ - PalResult (PAL_CALL *cmdDispatch)( + PalResult(PAL_CALL* cmdDispatch)( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, @@ -3533,7 +3538,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDispatchBase(). */ - PalResult (PAL_CALL *cmdDispatchBase)( + PalResult(PAL_CALL* cmdDispatchBase)( PalCommandBuffer* cmdBuffer, uint32_t baseGroupX, uint32_t baseGroupY, @@ -3547,7 +3552,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDispatchIndirect(). */ - PalResult (PAL_CALL *cmdDispatchIndirect)( + PalResult(PAL_CALL* cmdDispatchIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer); @@ -3556,7 +3561,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdTraceRays(). */ - PalResult (PAL_CALL *cmdTraceRays)( + PalResult(PAL_CALL* cmdTraceRays)( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, uint32_t raygenIndex, @@ -3569,7 +3574,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdTraceRaysIndirect(). */ - PalResult (PAL_CALL *cmdTraceRaysIndirect)( + PalResult(PAL_CALL* cmdTraceRaysIndirect)( PalCommandBuffer* cmdBuffer, uint32_t raygenIndex, PalShaderBindingTable* sbt, @@ -3580,7 +3585,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindDescriptorSet(). */ - PalResult (PAL_CALL *cmdBindDescriptorSet)( + PalResult(PAL_CALL* cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, uint32_t setIndex, PalDescriptorSet* set); @@ -3590,7 +3595,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdPushConstants(). */ - PalResult (PAL_CALL *cmdPushConstants)( + PalResult(PAL_CALL* cmdPushConstants)( PalCommandBuffer* cmdBuffer, uint32_t shaderStageCount, PalShaderStage* shaderStages, @@ -3603,7 +3608,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetCullMode(). */ - PalResult (PAL_CALL *cmdSetCullMode)( + PalResult(PAL_CALL* cmdSetCullMode)( PalCommandBuffer* cmdBuffer, PalCullMode cullMode); @@ -3612,7 +3617,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetFrontFace(). */ - PalResult (PAL_CALL *cmdSetFrontFace)( + PalResult(PAL_CALL* cmdSetFrontFace)( PalCommandBuffer* cmdBuffer, PalFrontFace frontFace); @@ -3621,7 +3626,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetPrimitiveTopology(). */ - PalResult (PAL_CALL *cmdSetPrimitiveTopology)( + PalResult(PAL_CALL* cmdSetPrimitiveTopology)( PalCommandBuffer* cmdBuffer, PalPrimitiveTopology topology); @@ -3630,7 +3635,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetDepthTestEnable(). */ - PalResult (PAL_CALL *cmdSetDepthTestEnable)( + PalResult(PAL_CALL* cmdSetDepthTestEnable)( PalCommandBuffer* cmdBuffer, PalBool enable); @@ -3639,7 +3644,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetDepthWriteEnable(). */ - PalResult (PAL_CALL *cmdSetDepthWriteEnable)( + PalResult(PAL_CALL* cmdSetDepthWriteEnable)( PalCommandBuffer* cmdBuffer, PalBool enable); @@ -3648,7 +3653,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetStencilOp(). */ - PalResult (PAL_CALL *cmdSetStencilOp)( + PalResult(PAL_CALL* cmdSetStencilOp)( PalCommandBuffer* cmdBuffer, PalStencilFaceFlags faceMask, PalStencilOp failOp, @@ -3661,7 +3666,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateAccelerationstructure(). */ - PalResult (PAL_CALL *createAccelerationstructure)( + PalResult(PAL_CALL* createAccelerationstructure)( PalDevice* device, const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs); @@ -3671,14 +3676,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyAccelerationstructure(). */ - void (PAL_CALL *destroyAccelerationstructure)(PalAccelerationStructure* as); + void(PAL_CALL* destroyAccelerationstructure)(PalAccelerationStructure* as); /** * Backend implementation of ::palGetAccelerationStructureBuildSize. * * Must obey the rules and semantics documented in palGetAccelerationStructureBuildSize(). */ - PalResult (PAL_CALL *getAccelerationStructureBuildSize)( + PalResult(PAL_CALL* getAccelerationStructureBuildSize)( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); @@ -3688,7 +3693,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateBuffer(). */ - PalResult (PAL_CALL *createBuffer)( + PalResult(PAL_CALL* createBuffer)( PalDevice* device, const PalBufferCreateInfo* info, PalBuffer** outBuffer); @@ -3698,14 +3703,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyBuffer(). */ - void (PAL_CALL *destroyBuffer)(PalBuffer* buffer); + void(PAL_CALL* destroyBuffer)(PalBuffer* buffer); /** * Backend implementation of ::palGetBufferMemoryRequirements. * * Must obey the rules and semantics documented in palGetBufferMemoryRequirements(). */ - PalResult (PAL_CALL *getBufferMemoryRequirements)( + PalResult(PAL_CALL* getBufferMemoryRequirements)( PalBuffer* buffer, PalMemoryRequirements* requirements); @@ -3714,7 +3719,7 @@ typedef struct { * * Must obey the rules and semantics documented in palComputeInstanceBufferRequirements(). */ - PalResult (PAL_CALL *computeInstanceBufferRequirements)( + PalResult(PAL_CALL* computeInstanceBufferRequirements)( PalDevice* device, uint32_t instanceCount, uint64_t* outSize); @@ -3722,9 +3727,10 @@ typedef struct { /** * Backend implementation of ::palComputeImageCopyStagingBufferRequirements. * - * Must obey the rules and semantics documented in palComputeImageCopyStagingBufferRequirements(). + * Must obey the rules and semantics documented in + * palComputeImageCopyStagingBufferRequirements(). */ - PalResult (PAL_CALL *computeImageCopyStagingBufferRequirements)( + PalResult(PAL_CALL* computeImageCopyStagingBufferRequirements)( PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, @@ -3737,7 +3743,7 @@ typedef struct { * * Must obey the rules and semantics documented in palWriteToInstanceBuffer(). */ - PalResult (PAL_CALL *writeToInstanceBuffer)( + PalResult(PAL_CALL* writeToInstanceBuffer)( PalDevice* device, void* ptr, PalAccelerationStructureInstance* instances, @@ -3748,7 +3754,7 @@ typedef struct { * * Must obey the rules and semantics documented in palWriteToImageCopyStagingBuffer(). */ - PalResult (PAL_CALL *writeToImageCopyStagingBuffer)( + PalResult(PAL_CALL* writeToImageCopyStagingBuffer)( PalDevice* device, void* ptr, void* srcData, @@ -3760,7 +3766,7 @@ typedef struct { * * Must obey the rules and semantics documented in palBindBufferMemory(). */ - PalResult (PAL_CALL *bindBufferMemory)( + PalResult(PAL_CALL* bindBufferMemory)( PalBuffer* buffer, PalMemory* memory, uint64_t offset); @@ -3770,7 +3776,7 @@ typedef struct { * * Must obey the rules and semantics documented in palMapBufferMemory(). */ - PalResult (PAL_CALL *mapBufferMemory)( + PalResult(PAL_CALL* mapBufferMemory)( PalBuffer* buffer, uint64_t offset, uint64_t size, @@ -3781,21 +3787,21 @@ typedef struct { * * Must obey the rules and semantics documented in palUnmapBufferMemory(). */ - void (PAL_CALL *unmapBufferMemory)(PalBuffer* buffer); + void(PAL_CALL* unmapBufferMemory)(PalBuffer* buffer); /** * Backend implementation of ::palGetBufferDeviceAddress. * * Must obey the rules and semantics documented in palGetBufferDeviceAddress(). */ - PalDeviceAddress (PAL_CALL *getBufferDeviceAddress)(PalBuffer* buffer); + PalDeviceAddress(PAL_CALL* getBufferDeviceAddress)(PalBuffer* buffer); /** * Backend implementation of ::palCreateDescriptorSetLayout. * * Must obey the rules and semantics documented in palCreateDescriptorSetLayout(). */ - PalResult (PAL_CALL *createDescriptorSetLayout)( + PalResult(PAL_CALL* createDescriptorSetLayout)( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout); @@ -3805,14 +3811,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyDescriptorSetLayout(). */ - void (PAL_CALL *destroyDescriptorSetLayout)(PalDescriptorSetLayout* layout); + void(PAL_CALL* destroyDescriptorSetLayout)(PalDescriptorSetLayout* layout); /** * Backend implementation of ::palCreateDescriptorPool. * * Must obey the rules and semantics documented in palCreateDescriptorPool(). */ - PalResult (PAL_CALL *createDescriptorPool)( + PalResult(PAL_CALL* createDescriptorPool)( PalDevice* device, const PalDescriptorPoolCreateInfo* info, PalDescriptorPool** outPool); @@ -3822,21 +3828,21 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyDescriptorPool(). */ - void (PAL_CALL *destroyDescriptorPool)(PalDescriptorPool* pool); + void(PAL_CALL* destroyDescriptorPool)(PalDescriptorPool* pool); /** * Backend implementation of ::palResetDescriptorPool. * * Must obey the rules and semantics documented in palResetDescriptorPool(). */ - PalResult (PAL_CALL *resetDescriptorPool)(PalDescriptorPool* pool); + PalResult(PAL_CALL* resetDescriptorPool)(PalDescriptorPool* pool); /** * Backend implementation of ::palAllocateDescriptorSet. * * Must obey the rules and semantics documented in palAllocateDescriptorSet(). */ - PalResult (PAL_CALL *allocateDescriptorSet)( + PalResult(PAL_CALL* allocateDescriptorSet)( PalDevice* device, PalDescriptorPool* pool, PalDescriptorSetLayout* layout, @@ -3847,7 +3853,7 @@ typedef struct { * * Must obey the rules and semantics documented in palUpdateDescriptorSet(). */ - PalResult (PAL_CALL *updateDescriptorSet)( + PalResult(PAL_CALL* updateDescriptorSet)( PalDevice* device, uint32_t count, PalDescriptorSetWriteInfo* infos); @@ -3857,7 +3863,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreatePipelineLayout(). */ - PalResult (PAL_CALL *createPipelineLayout)( + PalResult(PAL_CALL* createPipelineLayout)( PalDevice* device, const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout); @@ -3867,14 +3873,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyPipelineLayout(). */ - void (PAL_CALL *destroyPipelineLayout)(PalPipelineLayout* layout); + void(PAL_CALL* destroyPipelineLayout)(PalPipelineLayout* layout); /** * Backend implementation of ::palCreateGraphicsPipeline. * * Must obey the rules and semantics documented in palCreateGraphicsPipeline(). */ - PalResult (PAL_CALL *createGraphicsPipeline)( + PalResult(PAL_CALL* createGraphicsPipeline)( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline); @@ -3884,7 +3890,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateComputePipeline(). */ - PalResult (PAL_CALL *createComputePipeline)( + PalResult(PAL_CALL* createComputePipeline)( PalDevice* device, const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline); @@ -3894,7 +3900,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCreateRayTracingPipeline(). */ - PalResult (PAL_CALL *createRayTracingPipeline)( + PalResult(PAL_CALL* createRayTracingPipeline)( PalDevice* device, const PalRayTracingPipelineCreateInfo* info, PalPipeline** outPipeline); @@ -3904,14 +3910,14 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyPipeline(). */ - void (PAL_CALL *destroyPipeline)(PalPipeline* pipeline); + void(PAL_CALL* destroyPipeline)(PalPipeline* pipeline); /** * Backend implementation of ::palCreateShaderBindingTable. * * Must obey the rules and semantics documented in palCreateShaderBindingTable(). */ - PalResult (PAL_CALL *createShaderBindingTable)( + PalResult(PAL_CALL* createShaderBindingTable)( PalDevice* device, const PalShaderBindingTableCreateInfo* info, PalShaderBindingTable** outSbt); @@ -3921,15 +3927,15 @@ typedef struct { * * Must obey the rules and semantics documented in palDestroyShaderBindingTable(). */ - void (PAL_CALL *destroyShaderBindingTable)(PalShaderBindingTable* sbt); + void(PAL_CALL* destroyShaderBindingTable)(PalShaderBindingTable* sbt); /** * Backend implementation of ::palUpdateShaderBindingTable. * * Must obey the rules and semantics documented in palUpdateShaderBindingTable(). */ - PalResult (PAL_CALL *updateShaderBindingTable)( - PalShaderBindingTable* sbt, + PalResult(PAL_CALL* updateShaderBindingTable)( + PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos); } PalGraphicsBackendVtable1; @@ -3937,17 +3943,17 @@ typedef struct { /** * @brief Initialize the graphics system. * - * The debugger, allocator and custom backends will not not copied, therefore the pointers must remain valid - * until the graphics system is shutdown. Set the debugger or PalGraphicsDebugger::callback to - * nullptr to disable debugging and validation layers. - * - * If `debugger` is not nullptr and there is no debug layers, this function will not fail but + * The debugger, allocator and custom backends will not not copied, therefore the pointers must + * remain valid until the graphics system is shutdown. Set the debugger or + * PalGraphicsDebugger::callback to nullptr to disable debugging and validation layers. + * + * If `debugger` is not nullptr and there is no debug layers, this function will not fail but * debugging will be disabled. - * + * * All backends must have their vtable functions fully set according to the version requirements. - * If a feature is not supported by a backend, `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED` must be - * returned by the appropriate function. This is validated at initialization and will fail and return - * `PAL_RESULT_INVALID_ARGUMENT`. + * If a feature is not supported by a backend, `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED` must be + * returned by the appropriate function. This is validated at initialization and will fail and + * return `PAL_RESULT_INVALID_ARGUMENT`. * * @param[in] debugger Optional debugger. Set to nullptr to disable debugging and validation * layers. @@ -4078,7 +4084,7 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); * @param[in] adapter Adapter to query. * @param[in] shaderFormat The shader format. Must have only a single bit set. * - * @return The highest supported shader target encoded with `PAL_MAKE_SHADER_TARGET` macro + * @return The highest supported shader target encoded with `PAL_MAKE_SHADER_TARGET` macro * on success otherwise `0` on failure. * * Thread safety: Thread safe. @@ -4087,7 +4093,7 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); * @sa palEnumerateAdapters */ PAL_API uint32_t PAL_CALL palGetHighestSupportedShaderTarget( - PalAdapter* adapter, + PalAdapter* adapter, PalShaderFormats shaderFormat); /** @@ -4203,13 +4209,13 @@ PAL_API void PAL_CALL palFreeMemory( */ PAL_API PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( PalDevice* device, - PalSamplerAnisotropyCapabilities* caps); + PalSamplerAnisotropyCapabilities* caps); /** * @brief Get multi view feature capabilites or limits about a device. * * The graphics system must be initialized before this call. - * + * * `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * @@ -4231,7 +4237,7 @@ PAL_API PalResult PAL_CALL palQueryMultiViewCapabilities( * @brief Get multi viewport feature capabilites or limits about a device. * * The graphics system must be initialized before this call. - * + * * `PAL_ADAPTER_FEATURE_MULTI_VIEWPORT` must be supported and enabled when creating the * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * @@ -4368,7 +4374,7 @@ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( * PalAdapterCapabilities::maxComputeQueues, PalAdapterCapabilities::maxGraphicsQueues and * PalAdapterCapabilities::maxCopyQueues respectively for the limit for each queue type. * Creating more queues than the supported will fail and return `PAL_RESULT_OUT_OF_QUEUE`. - * + * * Not all graphics queues support presentation. Create a graphics queue and then check if * its support presentation for the provided surface. see palCanQueuePresent(). Any graphics * queue supports offscreen rendering. @@ -4963,9 +4969,9 @@ PAL_API PalResult PAL_CALL palPresentSwapchain( /** * @brief Resize the provided swapchain. * - * The graphics system must be initialized before this call. - * - * The swapchain images must not be in use before this call. All resources (image views) that + * The graphics system must be initialized before this call. + * + * The swapchain images must not be in use before this call. All resources (image views) that * reference the swapchain images must be destroyed and recreated. * * @param[in] swapchain Swapchain to resize. @@ -5013,7 +5019,7 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. - * + * * @note The shader entry name must not be greater than `PAL_SHADER_ENTRY_NAME_SIZE (32)`. * * @since 2.0 @@ -5184,9 +5190,9 @@ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); /** * @brief Waits for a semaphore to reach the provided value. * - * The graphics system must be initialized before this call. - * - * The provided semaphore must be a timeline semaphore If not, this function fails and returns + * The graphics system must be initialized before this call. + * + * The provided semaphore must be a timeline semaphore If not, this function fails and returns * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] semaphore Semaphore to wait on. @@ -5212,7 +5218,7 @@ PAL_API PalResult PAL_CALL palWaitSemaphore( * * The graphics system must be initialized before this call. * - * The provided semaphore must be a timeline semaphore If not, this function fails and returns + * The provided semaphore must be a timeline semaphore If not, this function fails and returns * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] semaphore Semaphore to signal. @@ -5238,7 +5244,7 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * * The graphics system must be initialized before this call. * - * The provided semaphore must be a timeline semaphore If not, this function fails and returns + * The provided semaphore must be a timeline semaphore If not, this function fails and returns * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] semaphore Semaphore to get its value. @@ -5285,7 +5291,7 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( * The graphics system must be initialized before this call. * If the provided command pool is invalid or nullptr, this function returns * silently. - * + * * Destroying a command pool frees all command buffers automatically. * * @param[in] pool Command pool to destroy. @@ -5489,7 +5495,7 @@ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -5519,7 +5525,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * @@ -5550,7 +5556,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * @@ -5632,7 +5638,7 @@ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); * @param[in] src Source buffer. * @param[in] copyInfo Pointer to a PalBufferCopyInfo struct that specifies parameters. * Must not be nullptr. - * + * * Pointer to a PalImageCreateInfo struct that specifies parameters. * Must not be nullptr. * @@ -5800,7 +5806,7 @@ PAL_API PalResult PAL_CALL palCmdSetScissors( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -5826,7 +5832,7 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -5852,7 +5858,7 @@ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -5882,7 +5888,7 @@ PAL_API PalResult PAL_CALL palCmdDraw( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * @@ -5912,7 +5918,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirect( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * @@ -5941,7 +5947,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -5972,7 +5978,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexed( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * @@ -6002,7 +6008,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * @@ -6017,30 +6023,30 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( /** * @brief Transition an acceleration structure from one usage state to another. - * + * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * + * * The graphics system must be initialized before this call. This function defines a * dependency between `oldUsageState` and `newUsageState`. It ensures that all * operations performed under `oldUsageState` are completed and visible before the acceleration * structure is accessed under `newUsageState`. - * - * This function does not modify the acceleration structure, it only exforces execution ordering + * + * This function does not modify the acceleration structure, it only exforces execution ordering * and acceleration structure memory visibility. - * + * * A barrier is not needed between BLAS and TLAS if there dont shared any resource. If both * builds use a different scratch buffer, no barrier is needed. - * - * Example: - * + * + * Example: + * * To make sure BLAS builds before TLAS access it and TLAS does not use scratch buffer * whilst BLAS is buidling, * we put a barrier to transition the BLAS to ensure it has finished building and the scratch - * buffer is not being used. This is expressed with `oldUsageState` being + * buffer is not being used. This is expressed with `oldUsageState` being * `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE`. - * - * `newUsageState` should be the new usage state we want after the BLAS + * + * `newUsageState` should be the new usage state we want after the BLAS * has finished building which is `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -6052,7 +6058,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -6070,20 +6076,20 @@ PAL_API PalResult PAL_CALL palCmdAccelerationStructureBarrier( * * The graphics system must be initialized before this call. This function defines a * dependency between `oldUsageState` and `newUsageState`. It ensures that all - * operations performed under `oldUsageState` are completed and visible before the image + * operations performed under `oldUsageState` are completed and visible before the image * is accessed under `newUsageState`. - * - * This function does not modify the image, it only exforces execution ordering and image memory + * + * This function does not modify the image, it only exforces execution ordering and image memory * visibility. - * - * Example: - * + * + * Example: + * * To make sure the an image is ready for presenting after a render pass, * we put a barrier to transition the image to ensure the render pass has finished writing - * to the image. This is expressed with `oldUsageState` being + * to the image. This is expressed with `oldUsageState` being * `PAL_USAGE_STATE_COLOR_ATTACHMENT`. - * - * `newUsageState` should be the new usage state we want after the render pass + * + * `newUsageState` should be the new usage state we want after the render pass * has finished which is `PAL_USAGE_STATE_PRESENT`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -6113,19 +6119,19 @@ PAL_API PalResult PAL_CALL palCmdImageBarrier( * * The graphics system must be initialized before this call. This function defines a * dependency between `oldUsageState` and `newUsageState`. It ensures that all - * operations performed under `oldUsageState` are completed and visible before the buffer + * operations performed under `oldUsageState` are completed and visible before the buffer * is accessed under `newUsageState`. - * - * This function does not modify the buffer, it only exforces execution ordering and buffer memory + * + * This function does not modify the buffer, it only exforces execution ordering and buffer memory * visibility. - * - * Example: - * + * + * Example: + * * To read back data from a buffer that will be written to by a shader, - * we put a barrier to transition the buffer to ensurethe shader has finished writing to the + * we put a barrier to transition the buffer to ensurethe shader has finished writing to the * buffer. This is expressed with `oldUsageState` being `PAL_USAGE_STATE_SHADER_WRITE`. - * - * `newUsageState` should be the new usage state we want after the write + * + * `newUsageState` should be the new usage state we want after the write * has finished which is`PAL_USAGE_STATE_TRANSFER_READ`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -6162,7 +6168,7 @@ PAL_API PalResult PAL_CALL palCmdBufferBarrier( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -6179,7 +6185,7 @@ PAL_API PalResult PAL_CALL palCmdDispatch( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_DISPATCH_BASE` must be supported and enabled by the device if not, this + * `PAL_ADAPTER_FEATURE_DISPATCH_BASE` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -6194,7 +6200,7 @@ PAL_API PalResult PAL_CALL palCmdDispatch( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -6214,7 +6220,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH` must be supported and enabled by the device if not, this + * `PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -6224,7 +6230,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * @@ -6254,7 +6260,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -6272,7 +6278,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING` must be supported and enabled by the device if not, + * `PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING` must be supported and enabled by the device if not, * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -6284,10 +6290,10 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note The argument buffer memory must not be `PAL_MEMORY_TYPE_GPU_ONLY`. The implementation * internally copies the data into a GPU buffer for execution. - * + * * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * @@ -6312,7 +6318,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -6338,7 +6344,7 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. - * + * * @note A pipeline must be bound before this call. * * @since 2.0 @@ -6400,7 +6406,7 @@ PAL_API PalResult PAL_CALL palCmdSetFrontFace( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY` must be supported and enabled by the device + * `PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY` must be supported and enabled by the device * if not, this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -6422,7 +6428,7 @@ PAL_API PalResult PAL_CALL palCmdSetPrimitiveTopology( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE` must be supported and enabled by the device + * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE` must be supported and enabled by the device * if not, this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. @@ -6509,8 +6515,8 @@ PAL_API PalResult PAL_CALL palCmdSetStencilOp( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. - * - * @note The memory associated with PalAccelerationStructureCreateInfo::buffer must be + * + * @note The memory associated with PalAccelerationStructureCreateInfo::buffer must be * `PAL_MEMORY_TYPE_GPU_ONLY`. * * @since 2.0 @@ -6570,16 +6576,16 @@ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS` must be supported and enabled by the device if + * `PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS` must be supported and enabled by the device if * `PAL_BUFFER_USAGE_DEVICE_ADDRESS` will be used. - * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if * `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE` or `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH` * or `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT` will be used. - * + * * `PAL_BUFFER_USAGE_INDIRECT` must be supported and enabled by the device if the buffer will be * used as an indirect buffer. - * + * * @param[in] device Device that creates the buffer. * @param[in] info Pointer to a PalBufferCreateInfo struct that specifies parameters. * Must not be nullptr. @@ -6640,9 +6646,9 @@ PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( * The graphics system must be initialized before this call. This does not allocate memory * for the buffer. * - * `outSize` must be the size that is used to create the instance buffer. It will be + * `outSize` must be the size that is used to create the instance buffer. It will be * computed with regards to the provided `instanceCount`. This function must be used and required - * for all instance buffers. This is used with acceleration + * for all instance buffers. This is used with acceleration * structure (`TLAS`). * * @param[in] device Device to compute instance buffer requirements with. @@ -6667,13 +6673,13 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * The graphics system must be initialized before this call. This does not allocate memory * for the buffer. * - * `outSize` must be the size that is used to create the image copy staging buffer. It will be - * computed with regards to the provided `imageFormat` and `copyInfo`. This function must be + * `outSize` must be the size that is used to create the image copy staging buffer. It will be + * computed with regards to the provided `imageFormat` and `copyInfo`. This function must be * used and required for all image copy staging buffers. This is used with image copy commands. - * + * * PalBufferImageCopyInfo::bufferRowLength and PalBufferImageCopyInfo::bufferImageHeight are hints. * The driver might used it defaults if the requested is not supported. Check `outBufferRowLength` - * and `outBufferImageHeight` to see the values the driver used. Set the new values to + * and `outBufferImageHeight` to see the values the driver used. Set the new values to * `copyInfo` before writing to the buffer with `palWriteToImageCopyStagingBuffer()`. * * @param[in] device Device to compute image copy staging buffer requirements with. @@ -6681,7 +6687,8 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * Must not be nullptr. * @param[out] outBufferRowLength Pointer to a uint32_t to recieve the required buffer row length. - * @param[out] outBufferImageHeight Pointer to a uint32_t to recieve the required buffer imag height. + * @param[out] outBufferImageHeight Pointer to a uint32_t to recieve the required buffer imag + * height. * @param[out] outSize Pointer to a uint64_t to recieve the required size. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6840,11 +6847,11 @@ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); * @brief Create a descriptor set layout that defines the bindings used by descriptor sets. * * The graphics system must be initialized before this call. - * + * * This defines the layout, ordering and the number of descriptors a descriptor set uses. - * - * The layouts should reflect the exact layout of the shaders. Eg. - * descriptorBindings[2] = { sampler, sampled image } is different from + * + * The layouts should reflect the exact layout of the shaders. Eg. + * descriptorBindings[2] = { sampler, sampled image } is different from * descriptorBindings[2] = { sampled image, sampler }. The ordering must be correct. * * @param[in] device Device that creates the descriptor set layout. @@ -6945,7 +6952,7 @@ PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); * The graphics system must be initialized before this call. The descriptor set will be * allocated uninitialized therefore update it before use except the case where descriptor * indexing is enabled. - * + * * `pool` and `layout` must either be created with descriptor indexing enabled or not. Any other * pair will fail and return `PAL_RESULT_INVALID_OPERATION`. * @@ -6971,9 +6978,9 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( * @brief Update a descriptor set with descriptors (resources). * * The graphics system must be initialized before this call. - * + * * If the write info has no valid resource handle, then `PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS` - * must be supported and enabled when creating the device if not, this function will fail and + * must be supported and enabled when creating the device if not, this function will fail and * return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device The Device. Must match the one used to allocate descriptor set. @@ -7070,7 +7077,7 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. - * + * * @note The first entry of the compute shader will be used. * * @since 2.0 @@ -7098,8 +7105,8 @@ PAL_API PalResult PAL_CALL palCreateComputePipeline( * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. - * - * @note The shader group array must be in this order [raygen][miss][hitgroup][callable]. + * + * @note The shader group array must be in this order [raygen][miss][hitgroup][callable]. * * @since 2.0 * @sa palDestroyPipeline @@ -7135,22 +7142,22 @@ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. - * - * PalShaderBindingTableCreateInfo::recordCount must match the shader group count of + * + * PalShaderBindingTableCreateInfo::recordCount must match the shader group count of * PalShaderBindingTableCreateInfo::rayTracingPipeline. * * @param[in] device Device that creates the shader binding table. * @param[in] info Pointer to a PalShaderBindingTableCreateInfo struct that specifies parameters. * Must not be nullptr. - * @param[out] outSbt Pointer to a PalShaderBindingTable to recieve the created shader binding + * @param[out] outSbt Pointer to a PalShaderBindingTable to recieve the created shader binding * table. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. - * - * @note The records array must be in this order [raygen][miss][hitgroup][callable]. + * + * @note The records array must be in this order [raygen][miss][hitgroup][callable]. * * @since 2.0 * @sa palDestroyShaderBindingTable @@ -7181,7 +7188,7 @@ PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); * @brief Update a shader binding table record payloads. * * The graphics system must be initialized before this call. - * + * * This call does not update shader handles. It only updates the payload associated * with the record. PalShaderBindingTableRecordInfo::groupIndex is the index into * the shader groups used to create the ray tracing pipeline. @@ -7198,7 +7205,7 @@ PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); * @since 2.0 */ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( - PalShaderBindingTable* sbt, + PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos); diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 67c42a29..a6581580 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -38,8 +38,8 @@ #define PAL_GL_EXTENSION_FLUSH_CONTROL (1ULL << 8) #define PAL_GL_EXTENSION_COLORSPACE_SRGB (1ULL << 9) -#define PAL_GL_PROFILE_NONE 0 -#define PAL_GL_PROFILE_CORE 1 +#define PAL_GL_PROFILE_NONE 0 +#define PAL_GL_PROFILE_CORE 1 #define PAL_GL_PROFILE_COMPATIBILITY 2 #define PAL_GL_PROFILE_ES 3 #define PAL_GL_PROFILE_COUNT 4 @@ -141,14 +141,14 @@ typedef uint32_t PalGLAPI; * @since 1.0 */ typedef struct { - PalGLExtensions extensions; - uint32_t major; - uint32_t minor; - PalGLBackend backend; - PalGLAPI api; - char vendor[PAL_GL_VENDOR_NAME_SIZE]; - char graphicsCard[PAL_GL_GRAPHICS_CARD_NAME_SIZE]; - char version[PAL_GL_VERSION_NAME_SIZE]; + PalGLExtensions extensions; /**< Supported extensions.*/ + uint32_t major; /**< Version major.*/ + uint32_t minor; /**< Version minor.*/ + PalGLBackend backend; /**< (eg. `PAL_GL_BACKEND_WGL`).*/ + PalGLAPI api; /**< (eg. `PAL_GL_API_OPENGL_ES`).*/ + char vendor[PAL_GL_VENDOR_NAME_SIZE]; /**< Graphics card vendor name.*/ + char graphicsCard[PAL_GL_GRAPHICS_CARD_NAME_SIZE]; /**< Graphics card name.*/ + char version[PAL_GL_VERSION_NAME_SIZE]; /**< Graphics card version string.*/ } PalGLInfo; /** @@ -158,17 +158,17 @@ typedef struct { * @since 1.0 */ typedef struct { - PalBool doubleBuffer; - PalBool stereo; - PalBool sRGB; - uint16_t index; - uint16_t redBits; - uint16_t greenBits; - uint16_t blueBits; - uint16_t alphaBits; - uint16_t depthBits; - uint16_t stencilBits; - uint16_t samples; + PalBool doubleBuffer; /**< If `PAL_TRUE` double buffering is supported.*/ + PalBool stereo; /**< If `PAL_TRUE` stereo is supported.*/ + PalBool sRGB; /**< If `PAL_TRUE` SRGB colorspace is supported.*/ + uint16_t index; /**< Driver index or id.*/ + uint16_t redBits; /**< Number of bits in the red channel.*/ + uint16_t greenBits; /**< Number of bits in the green channel.*/ + uint16_t blueBits; /**< Number of bits in the blue channel.*/ + uint16_t alphaBits; /**< Number of bits in the alpha channel.*/ + uint16_t depthBits; /**< Number of depth buffer bits.*/ + uint16_t stencilBits; /**< Number of stencil buffer bits.*/ + uint16_t samples; /**< Number of samples.*/ } PalGLFBConfig; /** @@ -182,7 +182,7 @@ typedef struct { */ typedef struct { void* instance; /**< Must not be nullptr. (HINSTANCE on Win32 or wl_display on Wayland)*/ - void* window; /**< Must not be nullptr. (egl_wl_window on Wayland)*/ + void* window; /**< Must not be nullptr. (egl_wl_window on Wayland)*/ } PalGLWindow; /** @@ -194,17 +194,17 @@ typedef struct { * @since 1.0 */ typedef struct { - const PalGLWindow* window; - const PalGLFBConfig* fbConfig; - PalGLContext* shareContext; - PalGLProfile profile; - PalGLContextReset reset; - PalGLReleaseBehavior release; - PalBool forward; - PalBool noError; - PalBool debug; - uint32_t major; - uint32_t minor; + const PalGLWindow* window; /**< Window to create context for. Must not be nullptr.*/ + const PalGLFBConfig* fbConfig; /**< The framebuffer config to use. Must not be nullptr.*/ + PalGLContext* shareContext; /**< Can be nullptr.*/ + PalGLProfile profile; /**< (eg. `PAL_GL_PROFILE_CORE`).*/ + PalGLContextReset reset; /**< (eg. `PAL_GL_CONTEXT_RESET_LOSE_CONTEXT`).*/ + PalGLReleaseBehavior release; /**< (eg. `PAL_GL_RELEASE_BEHAVIOR_FLUSH`).*/ + PalBool forward; /**< Create a forward compatible context.*/ + PalBool noError; /**< Create a no error context.*/ + PalBool debug; /**< Create a debug context.*/ + uint32_t major; /**< Must not be greater than what the driver supports.*/ + uint32_t minor; /**< Must not be greater than what the driver supports.*/ } PalGLContextCreateInfo; /** @@ -215,15 +215,15 @@ typedef struct { * * The allocator will not not copied, therefore the pointer must remain valid * until the opengl system is shutdown. - * + * * `instance` must not be nullptr and will not be freed by the opengl system. It must be valid until * palShutdownGL() is called. - * `Linux`: This is the Display associated with the connection. + * `Linux`: This is the Display associated with the connection. * `Windows`: This is the HINSTANCE of the process. - * - * @param[in] api The api to use. (eg. PAL_GL_API_OPENGL). Call palGetSupportedGLAPIs() to check + * + * @param[in] api The api to use. (eg. `PAL_GL_API_OPENGL`). Call `palGetSupportedGLAPIs()` to check * if an api is supported on `instance`. - * @param[in] instance The instance the opengl system will be tied to (eg. XDisplay). + * @param[in] instance The instance the opengl system will be tied to (eg. XDisplay). * Must not be nullptr. * @param[in] allocator Optional user-provided allocator. Set to nullptr to use * default. @@ -454,7 +454,7 @@ PAL_API PalResult PAL_CALL palSetSwapInterval(int32_t interval); /** * @brief Get supported opengl APIs - * + * * @param[in] instance The instance (eg. HINSTANCE or XDisplay). * * @return An array of bools or nullptr on failure. diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index 753ad65f..eb35681d 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -112,11 +112,11 @@ typedef uint32_t PalPlatformApiType; * @since 1.0 */ typedef struct { - PalPlatformType type; - PalPlatformApiType apiType; - uint32_t totalMemory; /**< Total Disk space (memory) in GB.*/ - uint32_t totalRAM; /**< Total CPU RAM (memory) in MB.*/ - PalVersion version; + PalPlatformType type; /**< (eg. `PAL_PLATFORM_WINDOWS`).*/ + PalPlatformApiType apiType; /**< (eg. `PAL_PLATFORM_API_WIN32`).*/ + uint32_t totalMemory; /**< Total Disk space (memory) in GB.*/ + uint32_t totalRAM; /**< Total CPU RAM (memory) in MB.*/ + PalVersion version; /**< Platform version.*/ char name[PAL_PLATFORM_NAME_SIZE]; /**< (eg. Windows 11.22000).*/ } PalPlatformInfo; @@ -127,13 +127,13 @@ typedef struct { * @since 1.0 */ typedef struct { - PalCpuFeatures features; - PalCpuArch architecture; - uint32_t numCores; - uint32_t cacheL1; /**< L1 cache in KB.*/ - uint32_t cacheL2; /**< L2 cache in KB.*/ - uint32_t cacheL3; /**< L3 cache in KB.*/ - uint32_t numLogicalProcessors; /**< Number of CPUs.*/ + PalCpuFeatures features; /**< Supported CPU features (instructions).*/ + PalCpuArch architecture; /**< (eg. `PAL_CPU_ARCH_X86_64`).*/ + uint32_t numCores; /**< Number of cores.*/ + uint32_t cacheL1; /**< L1 cache in KB.*/ + uint32_t cacheL2; /**< L2 cache in KB.*/ + uint32_t cacheL3; /**< L3 cache in KB.*/ + uint32_t numLogicalProcessors; /**< Number of CPUs.*/ char vendor[PAL_CPU_VENDOR_NAME_SIZE]; /**< CPU vendor name.*/ char model[PAL_CPU_MODEL_NAME_SIZE]; /**< CPU modal name.*/ } PalCPUInfo; diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index f95d2ca0..96dfb117 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -113,9 +113,9 @@ typedef void (*PaTlsDestructorFn)(void* userData); * @since 1.0 */ typedef struct { - uint64_t stackSize; /**< Set to 0 to use default*/ + uint64_t stackSize; /**< Set to 0 to use default*/ const PalAllocator* allocator; /**< Set to nullptr to use default.*/ - PalThreadFn entry; /**< Thread entry function*/ + PalThreadFn entry; /**< Thread entry function. Must not be nullptr*/ void* arg; /**< Optional user-provided data. Can be nullptr.*/ } PalThreadCreateInfo; diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 642abb78..2f45e4c7 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -73,14 +73,15 @@ #define PAL_WINDOW_STYLE_TOOL (1U << 5) #define PAL_WINDOW_STYLE_BORDERLESS (1U << 6) -#define PAL_WINDOW_STATE_MAXIMIZED 0 -#define PAL_WINDOW_STATE_MINIMIZED 1 -#define PAL_WINDOW_STATE_RESTORED 2 -#define PAL_WINDOW_STATE_COUNT 3 +#define PAL_WINDOW_STATE_NORMAL 0 +#define PAL_WINDOW_STATE_MAXIMIZED 1 +#define PAL_WINDOW_STATE_MINIMIZED 2 +#define PAL_WINDOW_STATE_RESTORED 3 +#define PAL_WINDOW_STATE_COUNT 4 -#define PAL_FLASH_STOP 0 /**< Stop flashing.*/ -#define PAL_FLASH_CAPTION (1U << 0) /**< Flash the titlebar of the window.*/ -#define PAL_FLASH_TRAY (1U << 1) /**< Flash the icon of the window.*/ +#define PAL_FLASH_STOP 0 /**< Stop flashing.*/ +#define PAL_FLASH_CAPTION (1U << 0) /**< Flash the titlebar of the window.*/ +#define PAL_FLASH_TRAY (1U << 1) /**< Flash the icon of the window.*/ #define PAL_CONFIG_BACKEND_PAL_OPENGL 0 /**< Use PAL opengl module backend.*/ #define PAL_CONFIG_BACKEND_EGL 1 @@ -486,15 +487,15 @@ typedef uint32_t PalCursorType; * @since 1.0 */ typedef struct { - int32_t x; /**< X position in pixels.*/ - int32_t y; /**< Y position in pixels.*/ - uint32_t width; /**< Width in pixels.*/ - uint32_t height; /**< Height in pixels.*/ - uint32_t dpi; - uint32_t refreshRate; - PalOrientation orientation; - PalBool primary; /**< True if this is the primary monitor.*/ - char name[PAL_MONITOR_NAME_SIZE]; + int32_t x; /**< X position in pixels.*/ + int32_t y; /**< Y position in pixels.*/ + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Height in pixels.*/ + uint32_t dpi; /**< Display dots per inch.*/ + uint32_t refreshRate; /**< Refresh rate in Hz.*/ + PalOrientation orientation; /**< (eg. `PAL_ORIENTATION_LANDSCAPE`).*/ + PalBool primary; /**< `PAL_TRUE` if this is the primary monitor.*/ + char name[PAL_MONITOR_NAME_SIZE]; /**< Name of the monitor.*/ } PalMonitorInfo; /** @@ -504,10 +505,10 @@ typedef struct { * @since 1.0 */ typedef struct { - uint32_t bpp; /**< Bits per pixel.*/ - uint32_t refreshRate; - uint32_t width; /**< Width in pixels.*/ - uint32_t height; /**< Height in pixels.*/ + uint32_t bpp; /**< Bits per pixel.*/ + uint32_t refreshRate; /**< Refresh rate in Hz.*/ + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Height in pixels.*/ } PalMonitorMode; /** @@ -519,9 +520,9 @@ typedef struct { * @since 1.0 */ typedef struct { - PalFlashFlag flags; - uint32_t interval; /**< In milliseconds. Set to 0 for default.*/ - uint32_t count; /**< Set to 0 to flash until focused or cancelled.*/ + PalFlashFlag flags; /**< (eg. `PAL_FLASH_CAPTION`).*/ + uint32_t interval; /**< In milliseconds. Set to 0 for default.*/ + uint32_t count; /**< Set to 0 to flash until focused or cancelled.*/ } PalFlashInfo; /** @@ -562,10 +563,10 @@ typedef struct { */ typedef struct { void* nativeInstance; /**< The platform (OS) display or instance.*/ - void* nativeWindow; /**< The window platform (OS) handle.*/ - void* nativeHandle1; /**< Extra window handle (xdgSurface)*/ - void* nativeHandle2; /**< Extra window handle (xdgToplevel)*/ - void* nativeHandle3; /**< Extra window handle (wl_egl_window)*/ + void* nativeWindow; /**< The window platform (OS) handle.*/ + void* nativeHandle1; /**< Extra window handle (xdgSurface)*/ + void* nativeHandle2; /**< Extra window handle (xdgToplevel)*/ + void* nativeHandle3; /**< Extra window handle (wl_egl_window)*/ } PalWindowHandleInfo; /** @@ -577,18 +578,18 @@ typedef struct { * @since 1.0 */ typedef struct { - const char* title; /**< Title in UTF-8 encoding.*/ - PalMonitor* monitor; /**< Set to nullptr to use primary monitor.*/ - const char* appName; /**< If nullptr, `PAL` will be used.*/ - const char* instanceName; /**< If nullptr, `title` will be used.*/ - PalFBConfigBackend fbConfigBackend; - int32_t fbConfigIndex; - uint32_t width; /**< Width in pixels.*/ - uint32_t height; /**< Width in pixels.*/ - PalBool show; /**< Show after creation.*/ - PalWindowStyle style; /**< Window style.*/ - PalWindowState state; - PalBool center; /**< Center after creation.*/ + const char* title; /**< Title in UTF-8 encoding.*/ + PalMonitor* monitor; /**< Set to nullptr to use primary monitor.*/ + const char* appName; /**< If nullptr, `PAL` will be used.*/ + const char* instanceName; /**< If nullptr, `title` will be used.*/ + PalFBConfigBackend fbConfigBackend; /**< Will be used if `fbConfigIndex` is not 0.*/ + int32_t fbConfigIndex; /**< Set to 0 to create the window with no pixel format.*/ + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Width in pixels.*/ + PalBool show; /**< Show after creation.*/ + PalWindowStyle style; /**< Window style.*/ + PalWindowState state; /**< (eg. `PAL_WINDOW_STATE_MAXIMIZED`).*/ + PalBool center; /**< Center after creation.*/ } PalWindowCreateInfo; /** @@ -600,10 +601,10 @@ typedef struct { * The allocator will not not copied, therefore the pointer must remain valid * until the video system is shutdown. The event driver must be valid to recieve * video events. - * + * * If `preferredInstance` is nullptr, the video system creates one and control its lifetime. * The provided instance will not be freed by the video system. - * `Linux`: This is the Display associated with the connection. + * `Linux`: This is the Display associated with the connection. * `Windows`: This is the HINSTANCE of the process. * * @param[in] allocator Optional user-provided allocator. Set to nullptr to use @@ -866,7 +867,7 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * @brief Create a window. * * The video system must be initialized before this call. - * + * * `PalWindowCreateInfo::fbConfigIndex` is the loop index from the drivers supported FBConfigs. * `PalWindowCreateInfo::fbConfigBackend` is used to tell the video system the source of * `PalWindowCreateInfo::fbConfigIndex`. @@ -1306,8 +1307,8 @@ PAL_API PalWindow* PAL_CALL palGetFocusWindow(); * @brief Get the native handle of the provided window. * * The video system must be initialized before this call. - * - * On Wayland: `::nativeHandle1`, `::nativeHandle2` and `::nativeHandle3` + * + * On Wayland: `::nativeHandle1`, `::nativeHandle2` and `::nativeHandle3` * are `xdg_surface`, `xdg_toplevel` and `wl_egl_window` respectively if available. * * @param[in] window Pointer to the window. @@ -1321,7 +1322,7 @@ PAL_API PalWindow* PAL_CALL palGetFocusWindow(); * @since 1.0 */ PAL_API PalResult PAL_CALL palGetWindowHandleInfo( - PalWindow* window, + PalWindow* window, PalWindowHandleInfo* info); /** From 3e48fd1df654b5d60df832cd5210d21cb7bd9202 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 24 Jun 2026 16:02:43 +0000 Subject: [PATCH 294/372] add more inline struct docs: pal_graphics --- include/pal/pal_graphics.h | 167 +++++++++++++++++++------------------ 1 file changed, 84 insertions(+), 83 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d7ddeb35..d74a721e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1599,17 +1599,17 @@ typedef struct { * @since 2.0 */ typedef struct { - PalDescriptorIndexingFlags flags; /**< Capabilities flags. see `PalDescriptorIndexingFlags`*/ - uint32_t maxPerStageSampledImages; /**< Max sampled images per shader stage .*/ - uint32_t maxPerSetSampledImages; /**< Max sampled images per descriptor set.*/ - uint32_t maxPerStageStorageImages; /**< Max storage images per shader stage.*/ - uint32_t maxPerSetStorageImages; /**< Max storage images per descriptor set.*/ - uint32_t maxPerStageSamplers; /**< Max samplers per shader stage.*/ - uint32_t maxPerSetSamplers; /**< Max samplers per descriptor set.*/ - uint32_t maxPerStageStorageBuffers; /**< Max storage buffers per shader stage.*/ - uint32_t maxPerSetStorageBuffers; /**< Max storage buffers per descriptor set.*/ - uint32_t maxPerStageUniformBuffers; /**< Max uniform buffers per shader stage.*/ - uint32_t maxPerSetUniformBuffers; /**< Max uniform buffers per descriptor set.*/ + PalDescriptorIndexingFlags flags; /**< Capabilities flags. see `PalDescriptorIndexingFlags`*/ + uint32_t maxPerStageSampledImages; /**< Max sampled images per shader stage .*/ + uint32_t maxPerSetSampledImages; /**< Max sampled images per descriptor set.*/ + uint32_t maxPerStageStorageImages; /**< Max storage images per shader stage.*/ + uint32_t maxPerSetStorageImages; /**< Max storage images per descriptor set.*/ + uint32_t maxPerStageSamplers; /**< Max samplers per shader stage.*/ + uint32_t maxPerSetSamplers; /**< Max samplers per descriptor set.*/ + uint32_t maxPerStageStorageBuffers; /**< Max storage buffers per shader stage.*/ + uint32_t maxPerSetStorageBuffers; /**< Max storage buffers per descriptor set.*/ + uint32_t maxPerStageUniformBuffers; /**< Max uniform buffers per shader stage.*/ + uint32_t maxPerSetUniformBuffers; /**< Max uniform buffers per descriptor set.*/ uint32_t maxPerStageAccelerationStructure; /**< Max acceleration structures per shader stage.*/ uint32_t maxPerSetAccelerationStructure; /**< Max acceleration structures per descriptor set.*/ } PalDescriptorIndexingCapabilities; @@ -1621,16 +1621,16 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t supportedPresentModes; - uint32_t supportedCompositeAlphas; - uint32_t supportedFormats; - uint32_t minImageCount; - uint32_t maxImageCount; - uint32_t minImageWidth; - uint32_t minImageHeight; - uint32_t maxImageWidth; - uint32_t maxImageHeight; - uint32_t maxImageArrayLayers; + uint32_t supportedPresentModes; /**< Masks of supported present modes.*/ + uint32_t supportedCompositeAlphas; /**< Masks of supported composite alphas.*/ + uint32_t supportedFormats; /**< Masks of supported surface formats.*/ + uint32_t minImageCount; /**< Min image or back buffer count.*/ + uint32_t maxImageCount; /**< Max image or back buffer count.*/ + uint32_t minImageWidth; /**< Min image width in pixels.*/ + uint32_t minImageHeight; /**< Min image height in pixels.*/ + uint32_t maxImageWidth; /**< Max image width in pixels.*/ + uint32_t maxImageHeight; /**< Max image height in pixels.*/ + uint32_t maxImageArrayLayers; /**< Max number of image layers.*/ } PalSurfaceCapabilities; /** @@ -1641,27 +1641,28 @@ typedef struct { * @since 2.0 */ typedef struct { - PalImageUsages usages; - PalFormat format; - PalSampleCount sampleCount; /**< Maximum supported multisample count.*/ + PalImageUsages usages; /**< (eg. `PAL_IMAGE_USAGE_COLOR`).*/ + PalFormat format; /**< (eg. `PAL_FORMAT_R8G8B8A8_UNORM`).*/ + PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_8`).*/ } PalFormatInfo; /** * @struct PalImageInfo - * @brief Information about an image. This can be a swapchain image. + * @brief Information about an image. * * @since 2.0 */ typedef struct { - PalImageUsages usages; - uint32_t width; /**< Width of the image in pixels.*/ - uint32_t height; /**< Height of the image in pixels.*/ - uint32_t depth; /**< Depth of the image in pixels.*/ - uint32_t arrayLayerCount; - uint32_t mipLevelCount; - PalSampleCount sampleCount; - PalImageType type; /**< 1D, 2D, 3D.*/ - PalFormat format; + PalImageUsages usages; /**< (eg. `PAL_IMAGE_USAGE_COLOR`).*/ + uint32_t width; /**< Width of the image in pixels.*/ + uint32_t height; /**< Height of the image in pixels.*/ + uint32_t depth; /**< Depth of the image in pixels.*/ + uint32_t arrayLayerCount; /**< Number of array layers.*/ + uint32_t mipLevelCount; /**< Number of mip map levels.*/ + PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_8`).*/ + PalImageType type; /**< (eg. `PAL_IMAGE_TYPE_2D`).*/ + PalFormat format; /**< (eg. `PAL_FORMAT_R8G8B8A8_UNORM`).*/ + PalBool belongsToSwapcchain; /**< If `PAL_TRUE`, the image belongs to a swapchain.*/ } PalImageInfo; /** @@ -1674,9 +1675,9 @@ typedef struct { * @since 2.0 */ typedef struct { - float color[4]; /**< Color for color attachments only.*/ - float depth; - uint32_t stencil; + float color[4]; /**< Color clear value.*/ + float depth; /**< Depth clear value.*/ + uint32_t stencil; /**< Stencil clear value.*/ } PalClearValue; /** @@ -1688,17 +1689,17 @@ typedef struct { * @since 2.0 */ typedef struct { - PalImageView* imageView; /**< Image view. Must not be nullptr.*/ - PalImageView* resolveImageView; /**< Optional resolve image view.*/ - PalLoadOp loadOp; - PalStoreOp storeOp; - PalLoadOp stencilLoadOp; - PalStoreOp stencilStoreOp; + PalImageView* imageView; /**< Image view. Must not be nullptr.*/ + PalImageView* resolveImageView; /**< Resolve image view. Can be nullptr.*/ + PalLoadOp loadOp; /**< (eg. `PAL_LOAD_OP_CLEAR`).*/ + PalStoreOp storeOp; /**< (eg. `PAL_STORE_OP_STORE`).*/ + PalLoadOp stencilLoadOp; /**< (eg. `PAL_LOAD_OP_DONT_CARE`).*/ + PalStoreOp stencilStoreOp; /**< (eg. `PAL_STORE_OP_DONT_CARE`).*/ PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ PalResolveMode stencilResolveMode; /**< Used if resolveImageView is set.*/ uint32_t texelWidth; /**< Texel width for fragment shading rate attachment.*/ uint32_t texelHeight; /**< Texel height for fragment shading rate attachment.*/ - PalClearValue clearValue; + PalClearValue clearValue; /**< Clear value for color and depth/stencil attachments.*/ } PalAttachmentDesc; /** @@ -1708,12 +1709,12 @@ typedef struct { * @since 2.0 */ typedef struct { - float x; - float y; - float width; - float height; - float minDepth; - float maxDepth; + float x; /**< X position in pixels.*/ + float y; /**< Y position in pixels.*/ + float width; /**< Width in pixels.*/ + float height; /**< Height in pixels.*/ + float minDepth; /**< Min depth value.*/ + float maxDepth; /**< Max depth value.*/ } PalViewport; /** @@ -1723,10 +1724,10 @@ typedef struct { * @since 2.0 */ typedef struct { - int32_t x; - int32_t y; - uint32_t width; - uint32_t height; + int32_t x; /**< X position in pixels.*/ + int32_t y; /**< Y position in pixels.*/ + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Height in pixels.*/ } PalRect2D; /** @@ -1736,10 +1737,10 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t size; - uint64_t alignment; - uint32_t supportedMemoryTypes; - uint32_t memoryMask; + uint64_t size; /**< Required size in bytes.*/ + uint64_t alignment; /**< Required alignment in bytes.*/ + uint32_t supportedMemoryTypes; /**< Masks of supported memory types.*/ + uint32_t memoryMask; /**< Memory masks used in allocations. Must not be changed.*/ } PalMemoryRequirements; /** @@ -1751,12 +1752,12 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t waitValue; - uint64_t signalValue; - PalCommandBuffer* cmdBuffer; - PalSemaphore* waitSemaphore; - PalSemaphore* signalSemaphore; - PalFence* fence; + uint64_t waitValue; /**< Timeline semaphore value to wait on.*/ + uint64_t signalValue; /**< Timeline semaphore value to signal.*/ + PalCommandBuffer* cmdBuffer; /**< Command buffer to submit.*/ + PalSemaphore* waitSemaphore; /**< Wait semaphore.*/ + PalSemaphore* signalSemaphore; /**< Signal semaphore.*/ + PalFence* fence; /**< Fence to signal.*/ } PalCommandBufferSubmitInfo; /** @@ -1768,10 +1769,10 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t timeout; /**< Timeout in milliseconds.*/ - uint64_t signalValue; - PalSemaphore* signalSemaphore; - PalFence* fence; + uint64_t timeout; /**< Timeout in milliseconds.*/ + uint64_t signalValue; /**< Timeline semaphore value to signal.*/ + PalSemaphore* signalSemaphore; /**< Timeline semaphore value to signal.*/ + PalFence* fence; /**< Fence to signal.*/ } PalSwapchainNextImageInfo; /** @@ -1783,9 +1784,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t imageIndex; /**< Image index to present. Must be 0 and less than max images.*/ - uint64_t waitValue; - PalSemaphore* waitSemaphore; + uint64_t imageIndex; /**< Image index to present.*/ + uint64_t waitValue; /**< Timeline semaphore value to wait on.*/ + PalSemaphore* waitSemaphore; /**< Wait semaphore.*/ } PalSwapchainPresentInfo; /** @@ -1797,11 +1798,11 @@ typedef struct { * @since 2.0 */ typedef struct { - PalAttachmentDesc* colorAttachments; - PalAttachmentDesc* depthStencilAttachment; - PalAttachmentDesc* fragmentShadingRateAttachment; - uint32_t viewCount; - uint32_t colorAttachentCount; + PalAttachmentDesc* colorAttachments; /**< Color attachments.*/ + PalAttachmentDesc* depthStencilAttachment; /**< Depth/Stencil attachment.*/ + PalAttachmentDesc* fragmentShadingRateAttachment; /**< Fragment shading rate attachment.*/ + uint32_t viewCount; /**< View count. Set to 1 for default.*/ + uint32_t colorAttachentCount; /**< Number of color attachments.*/ } PalRenderingInfo; /** @@ -1814,12 +1815,11 @@ typedef struct { * @since 2.0 */ typedef struct { - PalFormat* colorAttachmentsFormat; - uint64_t colorAttachentCount; - uint32_t viewCount; - PalSampleCount multisampleCount; - PalFormat depthStencilAttachmentFormat; - PalFormat fragmentShadingRateAttachmentFormat; + PalFormat* colorAttachmentsFormat; /**< Color attachments formats.*/ + uint32_t colorAttachentCount; /**< Number of color attachment formats.*/ + uint32_t viewCount; /**< View count. Set to 1 for default.*/ + PalFormat depthStencilAttachmentFormat; /**< Depth/Stencil attachment format.*/ + PalFormat fragmentShadingRateAttachmentFormat; /**< Fragment shading rate attachment format.*/ } PalRenderingLayoutInfo; /** @@ -1832,7 +1832,7 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t workCount[3]; + uint32_t workCount[3]; /**< Workload per dimension. (eg. Image (200, 200, 1)).*/ uint32_t workGroupSize[3]; /**< Threads per workgroup per axis of the adapter (GPU).*/ uint32_t workGroupCount[3]; /**< Workgroups per axis of the adapter (GPU).*/ } PalWorkGroupBuildData; @@ -1848,6 +1848,7 @@ typedef struct { uint32_t workGroupCount[3]; /**< Workgroup count per axis of a dispatch tile.*/ } PalWorkGroupInfo; +// TODO: continue /** * @struct PalDrawIndirectData * @brief Draw indirect data of a single draw call. From cc9eb5fd0e41c9877d7761dcf5492d7f59a8b28f Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 25 Jun 2026 14:19:01 +0000 Subject: [PATCH 295/372] add additional structs inline docs: graphics --- include/pal/pal_graphics.h | 374 ++++++++++++++++++------------------- 1 file changed, 186 insertions(+), 188 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d74a721e..397a1bbc 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -391,7 +391,7 @@ #define PAL_BLEND_FACTOR_SRC_COLOR 2 #define PAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR 3 #define PAL_BLEND_FACTOR_DST_COLOR 4 -#define PAL_BLEND_FACTOR_ONE_MINUX_DST_COLOR 5 +#define PAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR 5 #define PAL_BLEND_FACTOR_SRC_ALPHA 6 #define PAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA 7 #define PAL_BLEND_FACTOR_DST_ALPHA 8 @@ -1250,7 +1250,7 @@ typedef uint32_t PalAccelerationStructureBuildHints; /** * @typedef PalAccelerationStructureInstanceFlags * @brief Acceleration structure instance flags. Multiple flags can be OR'ed together using - * bitwise OR operator (`|`). Not all combinations are valid. + * bitwise OR operator (`|`). * * All acceleration structure instance flags follow the format * `PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_**` for consistency and API use. @@ -1426,7 +1426,7 @@ typedef struct { uint32_t maxHeight; /**< Max height in pixels.*/ uint32_t maxDepth; /**< Max depth in pixels.*/ uint32_t maxArrayLayers; /**< Max array layers.*/ - uint32_t maxMipLevels; /**< Max mip map levels.*/ + uint32_t maxMipLevels; /**< Max mipmap levels.*/ } PalImageCapabilities; /** @@ -1658,7 +1658,7 @@ typedef struct { uint32_t height; /**< Height of the image in pixels.*/ uint32_t depth; /**< Depth of the image in pixels.*/ uint32_t arrayLayerCount; /**< Number of array layers.*/ - uint32_t mipLevelCount; /**< Number of mip map levels.*/ + uint32_t mipLevelCount; /**< Number of mipmap levels.*/ PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_8`).*/ PalImageType type; /**< (eg. `PAL_IMAGE_TYPE_2D`).*/ PalFormat format; /**< (eg. `PAL_FORMAT_R8G8B8A8_UNORM`).*/ @@ -1832,7 +1832,7 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t workCount[3]; /**< Workload per dimension. (eg. Image (200, 200, 1)).*/ + uint32_t workCount[3]; /**< Workload per dimension. (eg. Image (200, 200, 1)).*/ uint32_t workGroupSize[3]; /**< Threads per workgroup per axis of the adapter (GPU).*/ uint32_t workGroupCount[3]; /**< Workgroups per axis of the adapter (GPU).*/ } PalWorkGroupBuildData; @@ -1844,11 +1844,10 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t workGroupBase[3]; /**< Offset per axis of a dispatch tile.*/ - uint32_t workGroupCount[3]; /**< Workgroup count per axis of a dispatch tile.*/ + uint32_t workGroupBase[3]; /**< Offset per dimension of a dispatch tile.*/ + uint32_t workGroupCount[3]; /**< Workgroup count per dimension of a dispatch tile.*/ } PalWorkGroupInfo; -// TODO: continue /** * @struct PalDrawIndirectData * @brief Draw indirect data of a single draw call. @@ -1858,10 +1857,10 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t vertexCount; - uint32_t instanceCount; - uint32_t firstVertex; - uint32_t firstInstance; + uint32_t vertexCount; /**< Vertex count.*/ + uint32_t instanceCount; /**< Instance count.*/ + uint32_t firstVertex; /**< First vertex.*/ + uint32_t firstInstance; /**< First instance.*/ } PalDrawIndirectData; /** @@ -1873,11 +1872,11 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t indexCount; - uint32_t instanceCount; - uint32_t firstIndex; - int32_t vertexOffset; - uint32_t firstInstance; + uint32_t indexCount; /**< Index count.*/ + uint32_t instanceCount; /**< Instance count.*/ + uint32_t firstIndex; /**< First index.*/ + int32_t vertexOffset; /**< Vertex offset.*/ + uint32_t firstInstance; /**< First instance.*/ } PalDrawIndexedIndirectData; /** @@ -1889,9 +1888,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t groupCountXOrWidth; /**< Number of groups on the x axis or width.*/ - uint32_t groupCountXOrHeight; /**< Number of groups on the y axis or height.*/ - uint32_t groupCountXOrDepth; /**< Number of groups on the z axis or depth.*/ + uint32_t groupCountXOrWidth; /**< Number of groups on the x dimension or dispatch width.*/ + uint32_t groupCountXOrHeight; /**< Number of groups on the y dimension or dispatch height.*/ + uint32_t groupCountXOrDepth; /**< Number of groups on the z dimension or dispatch depth.*/ } PalDispatchIndirectData; /** @@ -1903,8 +1902,8 @@ typedef struct { * @since 2.0 */ typedef struct { - PalVertexSemanticID semanticID; - PalVertexType type; + PalVertexSemanticID semanticID; /**< (eg. `PAL_VERTEX_SEMANTIC_ID_POSITION`).*/ + PalVertexType type; /**< (eg. `PAL_VERTEX_TYPE_FLOAT3`).*/ } PalVertexAttribute; /** @@ -1922,10 +1921,10 @@ typedef struct { * @since 2.0 */ typedef struct { - PalVertexAttribute* attributes; - uint64_t attributeCount; - PalVertexLayoutType type; - uint32_t binding; + PalVertexAttribute* attributes; /**< Vertex attributes.*/ + uint64_t attributeCount; /**< Number of vertex attributes.*/ + PalVertexLayoutType type; /**< (eg. `PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX`).*/ + uint32_t binding; /**< Vertex buffer binding slot.*/ } PalVertexLayout; /** @@ -1937,14 +1936,14 @@ typedef struct { * @since 2.0 */ typedef struct { - void* userData; - PalDebugCallback callback; - PalBool denyGeneral; - PalBool denyValidation; - PalBool denyPerformance; - PalBool denyInfoSeverity; - PalBool denyWarningSeverity; - PalBool denyErrorSeverity; + void* userData; /**< Optional user provided data. Can be nullptr.*/ + PalDebugCallback callback; /**< Debug callback function.*/ + PalBool denyGeneral; /**< Do not recieve general messages.*/ + PalBool denyValidation; /**< Do not recieve validation messages.*/ + PalBool denyPerformance; /**< Do not recieve performance messages.*/ + PalBool denyInfoSeverity; /**< Do not recieve info severity messages.*/ + PalBool denyWarningSeverity; /**< Do not recieve warning severity messages.*/ + PalBool denyErrorSeverity; /**< Do not recieve error severity messages.*/ } PalGraphicsDebugger; /** @@ -1956,14 +1955,14 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool enableDepthClamp; - PalBool enableDepthBias; - float depthBiasConstant; - float depthBiasSlope; - float depthBiasClamp; - PalPolygonMode polygonMode; - PalCullMode cullMode; - PalFrontFace frontFace; + PalBool enableDepthClamp; /**< `PAL_TRUE` to enable depth clamp.*/ + PalBool enableDepthBias; /**< `PAL_TRUE` to enable depth bias.*/ + float depthBiasConstant; /**< Depth bias constant.*/ + float depthBiasSlope; /**< Depth bias slope.*/ + float depthBiasClamp; /**< Depth bias clamp.*/ + PalPolygonMode polygonMode; /**< (eg. `PAL_POLYGON_MODE_FILL`).*/ + PalCullMode cullMode; /**< (eg. `PAL_CULL_MODE_NONE`).*/ + PalFrontFace frontFace; /**< (eg. `PAL_FRONT_FACE_CLOCKWISE`).*/ } PalRasterizerState; /** @@ -1975,11 +1974,11 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t sampleMask; - PalBool enableSampleShading; - PalBool enableAlphaToCoverage; - PalSampleCount sampleCount; - float minSampleShading; + uint64_t sampleMask; /**< Set to nullptr to use default.*/ + PalBool enableSampleShading; /**< `PAL_TRUE` to enable sample shading.*/ + PalBool enableAlphaToCoverage; /**< `PAL_TRUE` to enable alpha to coverage.*/ + PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_4`).*/ + float minSampleShading; /**< Minimum sample shading.*/ } PalMultisampleState; /** @@ -1991,10 +1990,10 @@ typedef struct { * @since 2.0 */ typedef struct { - PalStencilOp failOp; - PalStencilOp passOp; - PalStencilOp depthFailOp; - PalCompareOp compareOp; + PalStencilOp failOp; /**< Stencil fail operation.*/ + PalStencilOp passOp; /**< Pass operation.*/ + PalStencilOp depthFailOp; /**< Depth fail operation.*/ + PalCompareOp compareOp; /**< Compare operation.*/ } PalStencilOpState; /** @@ -2006,12 +2005,12 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool enableDepthTest; - PalBool enableDepthWrite; - PalBool enableStencilTest; - PalCompareOp compareOp; - PalStencilOpState frontStencilOpState; - PalStencilOpState backStencilOpState; + PalBool enableDepthTest; /**< `PAL_TRUE` to enable depth test.*/ + PalBool enableDepthWrite; /**< `PAL_TRUE` to enable depth write.*/ + PalBool enableStencilTest; /**< `PAL_TRUE` to enable stencil test.*/ + PalCompareOp compareOp; /**< Compare operation.*/ + PalStencilOpState frontStencilOpState; /**< Front stencil operation state.*/ + PalStencilOpState backStencilOpState; /**< Back stencil operation state.*/ } PalDepthStencilState; /** @@ -2026,14 +2025,14 @@ typedef struct { * @since 2.0 */ typedef struct { - PalColorMask colorWriteMask; - PalBool enableBlend; - PalBlendFactor srcColorBlendFactor; - PalBlendFactor dstColorBlendFactor; - PalBlendOp colorBlendOp; - PalBlendFactor srcAlphaBlendFactor; - PalBlendFactor dstAlphaBlendFactor; - PalBlendOp alphaBlendOp; + PalColorMask colorWriteMask; /**< (eg. `PAL_COLOR_MASK_RED` | `PAL_COLOR_MASK_RED`).*/ + PalBool enableBlend; /**< `PAL_TRUE` to enable blending.*/ + PalBlendFactor srcColorBlendFactor; /**< (eg. `PAL_BLEND_FACTOR_SRC_ALPHA`).*/ + PalBlendFactor dstColorBlendFactor; /**< (eg. `PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA`).*/ + PalBlendOp colorBlendOp; /**< (eg. `PAL_BLEND_OP_ADD`).*/ + PalBlendFactor srcAlphaBlendFactor; /**< (eg. `PAL_BLEND_FACTOR_SRC_COLOR`).*/ + PalBlendFactor dstAlphaBlendFactor; /**< (eg. `PAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR`).*/ + PalBlendOp alphaBlendOp; /**< (eg. `PAL_BLEND_OP_SUBTRACT`).*/ } PalColorBlendAttachment; /** @@ -2045,8 +2044,8 @@ typedef struct { * @since 2.0 */ typedef struct { - PalFragmentShadingRate rate; - PalFragmentShadingRateCombinerOp combinerOps[2]; + PalFragmentShadingRate rate; /**< (eg. `PAL_FRAGMENT_SHADING_RATE_2X2`).*/ + PalFragmentShadingRateCombinerOp combinerOps[2]; /**< Combiner operations.*/ } PalFragmentShadingRateState; /** @@ -2058,12 +2057,12 @@ typedef struct { * @since 2.0 */ typedef struct { - PalAccelerationStructure* blas; - PalAccelerationStructureInstanceFlags flags; - uint32_t mask; - uint32_t instanceId; - uint32_t hitGroupOffset; - float transform[12]; /**< row major (3x4).*/ + PalAccelerationStructure* blas; /**< Bottom level acceleration structure.*/ + PalAccelerationStructureInstanceFlags flags; /**< Instance flags.*/ + uint32_t mask; /**< Only the lower 8-bits are used (0x00 - 0xFF).*/ + uint32_t instanceId; /**< User defined identifier.*/ + uint32_t hitGroupOffset; /**< Offset added to hitgroup index in the Shader Binding Table.*/ + float transform[12]; /**< Transform (row major 3x4).*/ } PalAccelerationStructureInstance; /** @@ -2073,9 +2072,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t accelerationStructureSize; - uint64_t scratchBufferSize; - uint64_t updateScratchBufferSize; + uint64_t accelerationStructureSize; /**< Required acceleration structure size in bytes.*/ + uint64_t scratchBufferSize; /**< Required scratch buffer size in bytes.*/ + uint64_t updateScratchBufferSize; /**< Required scratch buffer update size in bytes.*/ } PalAccelerationStructureBuildSize; /** @@ -2087,13 +2086,13 @@ typedef struct { * @since 2.0 */ typedef struct { - PalDeviceAddress vertexBufferAddress; - PalDeviceAddress indexBufferAddress; - PalDeviceAddress transformBufferAddress; - PalVertexType vertexType; - PalIndexType indexType; - uint32_t vertexCount; - uint32_t vertexStride; + PalDeviceAddress vertexBufferAddress; /**< Address of the vertex buffer.*/ + PalDeviceAddress indexBufferAddress; /**< Address of the index buffer.*/ + PalDeviceAddress transformBufferAddress; /**< Address of the transform buffer.*/ + PalVertexType vertexType; /**< (eg. `PAL_VERTEX_TYPE_FLOAT3`)*/ + PalIndexType indexType; /**< (eg. `PAL_INDEX_TYPE_UINT32`).*/ + uint32_t vertexCount; /**< Number of vertices.*/ + uint32_t vertexStride; /**< Size of each vertex in bytes.*/ } PalGeometryDataTriangle; /** @@ -2105,8 +2104,8 @@ typedef struct { * @since 2.0 */ typedef struct { - PalDeviceAddress bufferAddress; - uint64_t stride; + PalDeviceAddress bufferAddress; /**< Address of the AABBS buffer.*/ + uint64_t stride; /**< Size of each AABBS in bytes.*/ } PalGeometryDataAABBS; /** @@ -2118,10 +2117,10 @@ typedef struct { * @since 2.0 */ typedef struct { - void* data; /**< Pointer to geometry data. This will be casted based on the geometry type.*/ - uint64_t primitiveCount; - PalGeometryFlags flags; - PalGeometryType type; + const void* data; /**< This will be casted based on `type`.*/ + uint64_t primitiveCount; /**< Number of primitives in `data`.*/ + PalGeometryFlags flags; /**< (eg. `PAL_GEOMETRY_FLAG_OPAQUE`).*/ + PalGeometryType type; /**< (eg. `PAL_GEOMETRY_TYPE_TRIANGLE`).*/ } PalGeometry; /** @@ -2133,15 +2132,15 @@ typedef struct { * @since 2.0 */ typedef struct { - PalAccelerationStructure* dst; - PalAccelerationStructure* src; - PalGeometry* geometries; - PalDeviceAddress scratchBufferAddress; - PalDeviceAddress instanceBufferAddress; - PalAccelerationStructureBuildHints buildHints; - PalAccelerationStructureType type; - PalAccelerationStructureBuildMode buildMode; - uint32_t count; + PalAccelerationStructure* dst; /**< Destination aceleration structure.*/ + PalAccelerationStructure* src; /**< Source aceleration structure. Used for updates.*/ + PalGeometry* geometries; /**< BLAS geometries. nullptr for TLAS*/ + PalDeviceAddress scratchBufferAddress; /**< Address of scratch buffer.*/ + PalDeviceAddress instanceBufferAddress; /**< Address of instance buffer. nullptr for BLAS.*/ + PalAccelerationStructureBuildHints buildHints; /**< See `PalAccelerationStructureBuildHints`.*/ + PalAccelerationStructureType type; /**< (eg. `PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL`).*/ + PalAccelerationStructureBuildMode buildMode; /**< See `PalAccelerationStructureBuildMode`.*/ + uint32_t count; /**< Number of elements in `geometries` or `instanceBufferAddress`.*/ } PalAccelerationStructureBuildInfo; /** @@ -2153,8 +2152,8 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t descriptorCount; - PalDescriptorType descriptorType; + uint32_t descriptorCount; /**< Number of descriptors of `descriptorType`.*/ + PalDescriptorType descriptorType; /**< (eg. `PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE`).*/ } PalDescriptorSetLayoutBinding; /** @@ -2167,8 +2166,8 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t bindingCount; - PalDescriptorType descriptorType; + uint32_t bindingCount; /**< Number of bindings of `descriptorType`.*/ + PalDescriptorType descriptorType; /**< (eg. `PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE`).*/ } PalDescriptorPoolBindingSize; /** @@ -2180,10 +2179,10 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBuffer* buffer; - uint64_t offset; /**< Offset in bytes. If structured, will be divided by `stride`.*/ - uint64_t size; - uint64_t stride; /**< For structured buffers. Will be ignored if not supported. 0 for default.*/ + PalBuffer* buffer; /**< Buffer associated with the descriptor.*/ + uint64_t offset; /**< Offset in bytes. If structured, this will be divided by `stride`.*/ + uint64_t size; /**< Size of the buffer in bytes.*/ + uint64_t stride; /**< For structured buffers. This will be ignored if not supported.*/ } PalDescriptorBufferInfo; /** @@ -2195,7 +2194,7 @@ typedef struct { * @since 2.0 */ typedef struct { - PalImageView* imageView; + PalImageView* imageView; /**< Image view associated with the descriptor.*/ } PalDescriptorImageViewInfo; /** @@ -2207,7 +2206,7 @@ typedef struct { * @since 2.0 */ typedef struct { - PalSampler* sampler; + PalSampler* sampler; /**< Sampler associated with the descriptor.*/ } PalDescriptorSamplerInfo; /** @@ -2219,7 +2218,7 @@ typedef struct { * @since 2.0 */ typedef struct { - PalAccelerationStructure* tlas; + PalAccelerationStructure* tlas; /**< TLAS associated with the descriptor.*/ } PalDescriptorTLASInfo; /** @@ -2231,15 +2230,15 @@ typedef struct { * @since 2.0 */ typedef struct { - PalDescriptorSet* descriptorSet; - PalDescriptorBufferInfo* bufferInfos; - PalDescriptorImageViewInfo* imageViewInfos; - PalDescriptorSamplerInfo* samplerInfos; - PalDescriptorTLASInfo* tlasInfos; - PalDescriptorType descriptorType; + PalDescriptorSet* descriptorSet; /**< Descriptor set to write into.*/ + PalDescriptorBufferInfo* bufferInfos; /**< Used with buffer descriptors.*/ + PalDescriptorImageViewInfo* imageViewInfos; /**< Used with image descriptors.*/ + PalDescriptorSamplerInfo* samplerInfos; /**< Used with sampler descriptors.*/ + PalDescriptorTLASInfo* tlasInfos; /**< Used with TLAS descriptors.*/ + PalDescriptorType descriptorType; /**< (eg. `PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE`).*/ uint32_t layoutBindingIndex; /**< Index into the descriptor set layout bindings.*/ - uint32_t arrayElement; - uint32_t descriptorCount; + uint32_t arrayElement; /**< First index within the descriptor set layout bindings.*/ + uint32_t descriptorCount; /**< Number of descriptors to write.*/ } PalDescriptorSetWriteInfo; /** @@ -2251,8 +2250,8 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t offset; - uint32_t size; + uint32_t offset; /**< Offset in bytes.*/ + uint32_t size; /**< Size in bytes.*/ } PalPushConstantRange; /** @@ -2264,11 +2263,11 @@ typedef struct { * @since 2.0 */ typedef struct { - PalImageAspect aspect; /**< Must be compatible with the image format.*/ - uint32_t startMipLevel; - uint32_t mipLevelCount; - uint32_t startArrayLayer; - uint32_t layerArrayCount; + PalImageAspect aspect; /**< (eg. `PAL_IMAGE_ASPECT_COLOR`).*/ + uint32_t startMipLevel; /**< Start mipmap level. 0 for default.*/ + uint32_t mipLevelCount; /**< Number of mipmap levels.*/ + uint32_t startArrayLayer; /**< Start array layer. 0 for default.*/ + uint32_t layerArrayCount; /**< Number of array layers.*/ } PalImageSubresourceRange; /** @@ -2280,9 +2279,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t size; - uint64_t dstOffset; - uint64_t srcOffset; + uint64_t size; /**< Size in bytes to copy from source buffer.*/ + uint64_t dstOffset; /**< Offset in bytes in destination buffer.*/ + uint64_t srcOffset; /**< Offset in bytes in source buffer.*/ } PalBufferCopyInfo; /** @@ -2294,19 +2293,19 @@ typedef struct { * @since 2.0 */ typedef struct { - PalImageAspect imageAspect; - uint64_t bufferOffset; - uint32_t bufferRowLength; - uint32_t bufferImageHeight; - uint32_t ImageMipLevel; - uint32_t ImageStartArrayLayer; - uint32_t ImageArrayLayerCount; - int32_t imageOffsetX; - int32_t imageOffsetY; - int32_t imageOffsetZ; - uint32_t imageWidth; - uint32_t imageHeight; - uint32_t imageDepth; + uint64_t bufferOffset; /**< Offset in bytes into the buffer.*/ + PalImageAspect imageAspect; /**< (eg. `PAL_IMAGE_ASPECT_COLOR`).*/ + uint32_t bufferRowLength; /**< Buffer row length in texels.*/ + uint32_t bufferImageHeight; /**< Buffer image height in texels.*/ + uint32_t ImageMipLevel; /**< Mipmap level of the image.*/ + uint32_t ImageStartArrayLayer; /**< Starting array layer of the image.*/ + uint32_t ImageArrayLayerCount; /**< Number of array layers of the image.*/ + int32_t imageOffsetX; /**< X image offset in bytes.*/ + int32_t imageOffsetY; /**< Y image offset in bytes.*/ + int32_t imageOffsetZ; /**< Z image offset in bytes.*/ + uint32_t imageWidth; /**< Image width in bytes.*/ + uint32_t imageHeight; /**< Image height in bytes.*/ + uint32_t imageDepth; /**< Image depth in bytes.*/ } PalBufferImageCopyInfo; /** @@ -2318,25 +2317,25 @@ typedef struct { * @since 2.0 */ typedef struct { - PalImageAspect aspect; - uint32_t dstMipLevel; - uint32_t srcMipLevel; - uint32_t dstStartArrayLayer; - uint32_t srcStartArrayLayer; - uint32_t arrayLayerCount; - int32_t dstOffsetX; - int32_t srcOffsetX; - int32_t dstOffsetY; - int32_t srcOffsetY; - int32_t dstOffsetZ; - int32_t srcOffsetZ; - uint32_t width; - uint32_t height; - uint32_t depth; + PalImageAspect aspect; /**< (eg. `PAL_IMAGE_ASPECT_COLOR`).*/ + uint32_t dstMipLevel; /**< Mipmap level of destination image.*/ + uint32_t srcMipLevel; /**< Mipmap level of source image.*/ + uint32_t dstStartArrayLayer; /**< Starting array layer of destination image.*/ + uint32_t srcStartArrayLayer; /**< Starting array layer of source image.*/ + uint32_t arrayLayerCount; /**< Number of array layers of destination and source images.*/ + int32_t dstOffsetX; /**< X destination image offset in bytes.*/ + int32_t srcOffsetX; /**< X source image offset in bytes.*/ + int32_t dstOffsetY; /**< Y destination image offset in bytes.*/ + int32_t srcOffsetY; /**< Y source image offset in bytes.*/ + int32_t dstOffsetZ; /**< Z destination image offset in bytes.*/ + int32_t srcOffsetZ; /**< Z source image offset in bytes.*/ + uint32_t width; /**< Width of the region to copy from source image.*/ + uint32_t height; /**< Height of the region to copy from source image.*/ + uint32_t depth; /**< Depth of the region to copy from source image.*/ } PalImageCopyInfo; /** - * @struct PalImageCopyInfo + * @struct PalShaderBindingTableRecordInfo * @brief Information for image to image copies. * * Uninitialized fields may result in undefined behavior. @@ -2346,9 +2345,8 @@ typedef struct { * @since 2.0 */ typedef struct { - void* localData; - uint32_t - groupIndex; /**< Index into the shader groups used to create the ray tracing pipeline.*/ + void* localData; /**< Must not be nullptr if `localDataSize` is not 0.*/ + uint32_t groupIndex; /**< Index into the shader groups used to create the pipeline.*/ uint32_t localDataSize; /**< Must not be greater than the data size of the group.*/ } PalShaderBindingTableRecordInfo; @@ -2361,8 +2359,8 @@ typedef struct { * @since 2.0 */ typedef struct { - const char* entryName; - PalShaderStage stage; + const char* entryName; /**< Must not be nullptr.*/ + PalShaderStage stage; /**< (eg. `PAL_SHADER_STAGE_VERTEX`).*/ uint32_t patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ } PalShaderEntryInfo; @@ -2375,16 +2373,16 @@ typedef struct { * @since 2.0 */ typedef struct { - PalImageUsages usages; - uint32_t width; - uint32_t height; - uint32_t depth; - uint32_t arrayLayerCount; - uint32_t mipLevelCount; - PalSampleCount sampleCount; - PalImageType type; - PalFormat format; - PalImageMemoryUsage memoryUsage; + PalImageUsages usages; /**< (eg. `PAL_IMAGE_USAGE_COLOR` | `PAL_IMAGE_USAGE_TRANSFER_DST`).*/ + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Height in pixels.*/ + uint32_t depth; /**< Depth in pixels.*/ + uint32_t arrayLayerCount; /**< Number of array layers.*/ + uint32_t mipLevelCount; /**< Number of mipmap levels.*/ + PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_1`).*/ + PalImageType type; /**< (eg. `PAL_IMAGE_TYPE_2D`).*/ + PalFormat format; /**< (eg. `PAL_FORMAT_B8G8R8A8_UNORM`).*/ + PalImageMemoryUsage memoryUsage; /**< See `PalImageMemoryUsage`.*/ } PalImageCreateInfo; /** @@ -2396,9 +2394,9 @@ typedef struct { * @since 2.0 */ typedef struct { - PalFormat format; /**< Must be compatible with the image format.*/ - PalImageViewType type; - PalImageSubresourceRange subresourceRange; + PalFormat format; /**< (eg. `PAL_FORMAT_B8G8R8A8_UNORM`).*/ + PalImageViewType type; /**< (eg. `PAL_IMAGE_VIEW_TYPE_2D`).*/ + PalImageSubresourceRange subresourceRange; /**< Range of the image to create the view with.*/ } PalImageViewCreateInfo; /** @@ -2410,20 +2408,20 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool enableCompare; - PalBool enableAnisotropy; - float mipLodBias; - float minLod; - float maxLod; - float maxAnisotropy; - PalFilterMode minFilterMode; - PalFilterMode magFilterMode; - PalSamplerMipmapMode mipmapMode; - PalSamplerAddressMode addressModeU; - PalSamplerAddressMode addressModeV; - PalSamplerAddressMode addressModeW; - PalCompareOp compareOp; - PalBorderColor borderColor; + PalBool enableCompare; /**< `PAL_TRUE` to enable compare operations.*/ + PalBool enableAnisotropy; /**< `PAL_TRUE` to enable texture filtering.*/ + float mipLodBias; /**< Mipmap level bias.*/ + float minLod; /**< Minimum Mipmap level allowed.*/ + float maxLod; /**< Maximum Mipmap level allowed.*/ + float maxAnisotropy; /**< Texture filtering level.*/ + PalFilterMode minFilterMode; /**< (eg. `PAL_FILTER_MODE_LINEAR`).*/ + PalFilterMode magFilterMode; /**< (eg. `PAL_FILTER_MODE_LINEAR`).*/ + PalSamplerMipmapMode mipmapMode; /**< (eg. `PAL_SAMPLER_MIPMAP_MODE_LINEAR`).*/ + PalSamplerAddressMode addressModeU; /**< (eg. `PAL_SAMPLER_ADDRESS_MODE_REPEAT`).*/ + PalSamplerAddressMode addressModeV; /**< (eg. `PAL_SAMPLER_ADDRESS_MODE_REPEAT`).*/ + PalSamplerAddressMode addressModeW; /**< (eg. `PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE`).*/ + PalCompareOp compareOp; /**< (eg. `PAL_COMPARE_OP_GREATER`).*/ + PalBorderColor borderColor; /**< (eg. `PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK`).*/ } PalSamplerCreateInfo; /** From bf8b7c98ea322afd5ef9a91d84a728859b450d18 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 25 Jun 2026 16:14:22 +0000 Subject: [PATCH 296/372] rename PAL_EVENT_** to PAL_EVENT_TYPE_** --- CHANGELOG.md | 4 +- include/pal/pal_event.h | 70 +++++++++---------- include/pal/pal_graphics.h | 138 ++++++++++++++++++------------------- 3 files changed, 107 insertions(+), 105 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bee4aeba..0428590a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ - Added type `PalGLAPI` with values: - `PAL_GL_API_OPENGL` - `PAL_GL_API_OPENGL_ES` -- Added `_COUNT` constants to all type groups (eg. `PAL_EVENT_COUNT`). +- Added `_COUNT` constants to all type groups (eg. `PAL_EVENT_TYPE_COUNT`). - Added `PAL_GL_GRAPHICS_CARD_NAME_SIZE`,`PAL_GL_VENDOR_NAME_SIZE` and `PAL_GL_VERSION_NAME_SIZE` constants. ### Changes @@ -43,6 +43,8 @@ - `palFormatResult()` now takes two additional parameters. - Renamed `PalGLRelease` to `PalGLReleaseBehavior`. - Renamed `palGLGetProcAddress()` to `palGetGLProcAddress()`. +- Renamed event type constants from `PAL_EVENT_**` to `PAL_EVENT_TYPE_**`. +- Renamed dispatch mode constants from `PAL_DISPATCH_**` to `PAL_DISPATCH_MODE_**`. - `palInitGL()` now takes two additional parameters. - `palEnumerateGLFBConfigs()` no longer takes the `glWindow` parameter. - `palInitVideo()` now takes an additional parameter. diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 1e4560d5..5c88631f 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -26,7 +26,7 @@ * Use inline helpers: * - palUnpackPointer() */ -#define PAL_EVENT_WINDOW_CLOSE 0 +#define PAL_EVENT_TYPE_WINDOW_CLOSE 0 /** * event.data : lower 32 bits = width, upper 32 bits = height @@ -37,7 +37,7 @@ * - palUnpackUint32() * - palUnpackPointer() */ -#define PAL_EVENT_WINDOW_SIZE 1 +#define PAL_EVENT_TYPE_WINDOW_SIZE 1 /** * event.data : lower 32 bits = x, upper 32 bits = y @@ -48,7 +48,7 @@ * - palUnpackInt32() * - palUnpackPointer() */ -#define PAL_EVENT_WINDOW_MOVE 2 +#define PAL_EVENT_TYPE_WINDOW_MOVE 2 /** * event.data : state(minimized, maximized, restored). @@ -58,7 +58,7 @@ * Use inline helpers: * - palUnpackPointer() */ -#define PAL_EVENT_WINDOW_STATE 3 +#define PAL_EVENT_TYPE_WINDOW_STATE 3 /** * event.data : `PAL_TRUE` for focus gained or `PAL_FALSE` for focus lost. @@ -68,7 +68,7 @@ * Use inline helpers: * - palUnpackPointer() */ -#define PAL_EVENT_WINDOW_FOCUS 4 +#define PAL_EVENT_TYPE_WINDOW_FOCUS 4 /** * event.data : `PAL_TRUE` for visible or `PAL_FALSE` for hidden. @@ -78,27 +78,27 @@ * Use inline helpers: * - palUnpackPointer() */ -#define PAL_EVENT_WINDOW_VISIBILITY 5 +#define PAL_EVENT_TYPE_WINDOW_VISIBILITY 5 /** * event.data2 : window */ -#define PAL_EVENT_WINDOW_MODAL_BEGIN 6 +#define PAL_EVENT_TYPE_WINDOW_MODAL_BEGIN 6 /** * event.data2 : window */ -#define PAL_EVENT_WINDOW_MODAL_END 7 +#define PAL_EVENT_TYPE_WINDOW_MODAL_END 7 /** * event.data2 : window */ -#define PAL_EVENT_MONITOR_DPI_CHANGED 8 +#define PAL_EVENT_TYPE_MONITOR_DPI_CHANGED 8 /** * event.data2 : window */ -#define PAL_EVENT_MONITOR_LIST_CHANGED 9 +#define PAL_EVENT_TYPE_MONITOR_LIST_CHANGED 9 /** * event.data : lower 32 bits = keycode, upper 32 bits = scancode @@ -109,7 +109,7 @@ * - palUnpackUint32() * - palUnpackPointer() */ -#define PAL_EVENT_KEYDOWN 10 +#define PAL_EVENT_TYPE_KEYDOWN 10 /** * event.data : lower 32 bits = keycode, upper 32 bits = scancode @@ -120,7 +120,7 @@ * - palUnpackUint32() * - palUnpackPointer() */ -#define PAL_EVENT_KEYREPEAT 11 +#define PAL_EVENT_TYPE_KEYREPEAT 11 /** * event.data : lower 32 bits = keycode, upper 32 bits = scancode @@ -131,7 +131,7 @@ * - palUnpackUint32() * - palUnpackPointer() */ -#define PAL_EVENT_KEYUP 12 +#define PAL_EVENT_TYPE_KEYUP 12 /** * event.data : lower 32 bits = button, upper 32 bits = serial @@ -141,7 +141,7 @@ * Use inline helpers: * - palUnpackPointer() */ -#define PAL_EVENT_MOUSE_BUTTONDOWN 13 +#define PAL_EVENT_TYPE_MOUSE_BUTTONDOWN 13 /** * event.data : lower 32 bits = button, upper 32 bits = serial @@ -151,7 +151,7 @@ * Use inline helpers: * - palUnpackPointer() */ -#define PAL_EVENT_MOUSE_BUTTONUP 14 +#define PAL_EVENT_TYPE_MOUSE_BUTTONUP 14 /** * event.data : lower 32 bits = x, upper 32 bits = y @@ -162,7 +162,7 @@ * - palUnpackInt32() * - palUnpackPointer() */ -#define PAL_EVENT_MOUSE_MOVE 15 +#define PAL_EVENT_TYPE_MOUSE_MOVE 15 /** * event.data : lower 32 bits = dx, upper 32 bits = dy @@ -173,7 +173,7 @@ * - palUnpackFloat() * - palUnpackPointer() */ -#define PAL_EVENT_MOUSE_DELTA 16 +#define PAL_EVENT_TYPE_MOUSE_DELTA 16 /** * event.data : lower 32 bits = dx, upper 32 bits = dy @@ -184,7 +184,7 @@ * - palUnpackFloat() * - palUnpackPointer() */ -#define PAL_EVENT_MOUSE_WHEEL 17 +#define PAL_EVENT_TYPE_MOUSE_WHEEL 17 /** * event.userId : User event ID or type. @@ -197,7 +197,7 @@ * - palUnpackUint32() * - palUnpackPointer() */ -#define PAL_EVENT_USER 18 +#define PAL_EVENT_TYPE_USER 18 /** * event.data : codepoint @@ -207,7 +207,7 @@ * Use inline helpers: * - palUnpackPointer() */ -#define PAL_EVENT_KEYCHAR 19 +#define PAL_EVENT_TYPE_KEYCHAR 19 /** * event.data : negotiated decorations mode @@ -217,14 +217,14 @@ * Use inline helpers: * - palUnpackPointer() */ -#define PAL_EVENT_WINDOW_DECORATION_MODE 20 +#define PAL_EVENT_TYPE_WINDOW_DECORATION_MODE 20 -#define PAL_EVENT_COUNT 21 +#define PAL_EVENT_TYPE_COUNT 21 -#define PAL_DISPATCH_NONE 0 -#define PAL_DISPATCH_CALLBACK 1 -#define PAL_DISPATCH_POLL 2 -#define PAL_DISPATCH_COUNT 3 +#define PAL_DISPATCH_MODE_NONE 0 +#define PAL_DISPATCH_MODE_CALLBACK 1 +#define PAL_DISPATCH_MODE_POLL 2 +#define PAL_DISPATCH_MODE_COUNT 3 /** * @struct PalEventDriver @@ -257,7 +257,7 @@ typedef uint32_t PalDecorationMode; * @typedef PalEventType * @brief Event types. * - * All event types follow the format `PAL_EVENT_**` for consistency and + * All event types follow the format `PAL_EVENT_TYPE_**` for consistency and * API use. * * @since 1.0 @@ -266,9 +266,9 @@ typedef uint32_t PalEventType; /** * @typedef PalDispatchMode - * @brief Dispatch types for an event. + * @brief Dispatch modes for an event. * - * All dispatch modes follow the format `PAL_DISPATCH_**` for consistency + * All dispatch modes follow the format `PAL_DISPATCH_MODE_**` for consistency * and API use. * * @since 1.0 @@ -325,7 +325,7 @@ struct PalEvent { int64_t data; /**< First data payload.*/ int64_t data2; /**< Second data payload.*/ int32_t userId; /**< You can have user events upto int32_t max.*/ - PalEventType type; /**< (eg. `PAL_EVENT_WINDOW_MOVE`).*/ + PalEventType type; /**< (eg. `PAL_EVENT_TYPE_WINDOW_MOVE`).*/ }; /** @@ -407,9 +407,9 @@ PAL_API void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver); * If the provided event driver is invalid or nullptr, this function returns * silently. * - * If the dispatch mode is `PAL_DISPATCH_POLL`, the event will be dispatched + * If the dispatch mode is `PAL_DISPATCH_MODE_POLL`, the event will be dispatched * into the event drivers event queue. If the dispatch mode is - * `PAL_DISPATCH_CALLBACK` and the event driver has a valid callback function, + * `PAL_DISPATCH_MODE_CALLBACK` and the event driver has a valid callback function, * the event will be dispatched to the callback function of the event driver * otherwise the event will be discarded. * @@ -435,7 +435,7 @@ PAL_API void PAL_CALL palSetEventDispatchMode( * @param[in] eventDriver Pointer to the event driver. * @param[in] type The event type. * - * @return The dispatch mode on success or `PAL_DISPATCH_NONE` on failure. + * @return The dispatch mode on success or `PAL_DISPATCH_MODE_NONE` on failure. * * Thread safety: Thread safe if multiple threads are not * simultaneously setting dispatch mode on the same `eventDriver`. @@ -454,10 +454,10 @@ PAL_API PalDispatchMode PAL_CALL palGetEventDispatchMode( * If the provided event driver is invalid or nullptr, this function returns * silently. * - * If the dispatch mode for the event is `PAL_DISPATCH_POLL`, the event will be + * If the dispatch mode for the event is `PAL_DISPATCH_MODE_POLL`, the event will be * pushed to the event queue. * - * If dispatch mode is `PAL_DISPATCH_CALLBACK` and the event driver has a valid + * If dispatch mode is `PAL_DISPATCH_MODE_CALLBACK` and the event driver has a valid * event callback, the callback will be called otherwise the event will be * discarded. * diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 397a1bbc..98da262c 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1374,7 +1374,7 @@ typedef uint32_t PalImageMemoryUsage; * * @since 2.0 */ -typedef uint32_t PalGraphicsBackendVtableVersion; +typedef uint64_t PalGraphicsBackendVtableVersion; /** * @typedef PalDebugCallback @@ -2433,14 +2433,14 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBool clipped; - uint32_t width; - uint32_t height; - uint32_t imageCount; - uint32_t imageArrayLayerCount; - PalPresentMode presentMode; - PalCompositeAplha compositeAlpha; - PalSurfaceFormat format; + PalBool clipped; /**< `PAL_TRUE` to discard pixels that are not visible.*/ + uint32_t width; /**< Width in pixels.*/ + uint32_t height; /**< Height in pixels.*/ + uint32_t imageCount; /**< Number of images or back buffers.*/ + uint32_t imageArrayLayerCount; /**< Number of array layers.*/ + PalPresentMode presentMode; /**< (eg. `PAL_PRESENT_MODE_FIFO`).*/ + PalCompositeAplha compositeAlpha; /**< (eg. `PAL_COMPOSITE_ALPHA_OPAQUE`).*/ + PalSurfaceFormat format; /**< (eg. `PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR`).*/ } PalSwapchainCreateInfo; /** @@ -2452,10 +2452,10 @@ typedef struct { * @since 2.0 */ typedef struct { - void* bytecode; - PalShaderEntryInfo* entries; - uint32_t bytecodeSize; - uint32_t entryCount; + void* bytecode; /**< Pointer to the shader bytecode.*/ + PalShaderEntryInfo* entries; /**< Shader entries.*/ + uint32_t bytecodeSize; /**< Size of `bytecode` in bytes.*/ + uint32_t entryCount; /**< Number of shader entries.*/ } PalShaderCreateInfo; /** @@ -2467,9 +2467,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t size; - PalBufferUsages usages; - PalBufferMemoryUsage memoryUsage; + uint64_t size; /**< Size in bytes.*/ + PalBufferUsages usages; /**< (eg. `PAL_BUFFER_USAGE_VERTEX`).*/ + PalBufferMemoryUsage memoryUsage; /**< See `PalBufferMemoryUsage`.*/ } PalBufferCreateInfo; /** @@ -2481,11 +2481,11 @@ typedef struct { * @since 2.0 */ typedef struct { - PalBuffer* buffer; - uint64_t offset; - uint64_t size; - PalAccelerationStructureType type; - PalAccelerationStructureCreateFlags createFlags; + PalBuffer* buffer; /**< Acceleration structure buffer.*/ + uint64_t offset; /**< Size in bytes.*/ + uint64_t size; /**< Offset in bytes.*/ + PalAccelerationStructureType type; /**< (eg. `PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL`).*/ + PalAccelerationStructureCreateFlags createFlags; /**< Set to 0 for default.*/ } PalAccelerationStructureCreateInfo; /** @@ -2497,9 +2497,9 @@ typedef struct { * @since 2.0 */ typedef struct { - PalDescriptorSetLayoutBinding* bindings; - PalDescriptorIndexingFlags descriptorIndexingFlags; - uint32_t bindingCount; + PalDescriptorSetLayoutBinding* bindings; /**< Bindings.*/ + PalDescriptorIndexingFlags descriptorIndexingFlags; /**< See `PalDescriptorIndexingFlags`.*/ + uint32_t bindingCount; /**< Number of bindings.*/ } PalDescriptorSetLayoutCreateInfo; /** @@ -2511,10 +2511,10 @@ typedef struct { * @since 2.0 */ typedef struct { - PalDescriptorPoolBindingSize* bindingSizes; - uint64_t bindingSizeCount; - uint32_t maxDescriptorSets; - PalDescriptorIndexingFlags descriptorIndexingFlags; + PalDescriptorPoolBindingSize* bindingSizes; /**< Binding sizes.*/ + uint64_t bindingSizeCount; /**< Number of bindings sizes.*/ + uint32_t maxDescriptorSets; /**< Maximum number of descriptor sets that can be allocated.*/ + PalDescriptorIndexingFlags descriptorIndexingFlags; /**< See `PalDescriptorIndexingFlags`.*/ } PalDescriptorPoolCreateInfo; /** @@ -2526,10 +2526,10 @@ typedef struct { * @since 2.0 */ typedef struct { - PalDescriptorSetLayout** descriptorSetLayouts; - PalPushConstantRange* pushConstantRanges; - uint32_t descriptorSetLayoutCount; - uint32_t pushConstantRangeCount; + PalDescriptorSetLayout** descriptorSetLayouts; /**< Descriptor set layouts.*/ + PalPushConstantRange* pushConstantRanges; /**< Push constant ranges.*/ + uint32_t descriptorSetLayoutCount; /**< Number of descriptor set layouts.*/ + uint32_t pushConstantRangeCount; /**< Number of push constant ranges.*/ } PalPipelineLayoutCreateInfo; /** @@ -2541,19 +2541,19 @@ typedef struct { * @since 2.0 */ typedef struct { - PalPipelineLayout* pipelineLayout; - PalShader** shaders; - PalVertexLayout* vertexLayouts; - PalColorBlendAttachment* colorBlendAttachments; - PalRasterizerState* rasterizerState; - PalMultisampleState* multisampleState; - PalDepthStencilState* depthStencilState; - PalFragmentShadingRateState* fragmentShadingRateState; - PalRenderingLayoutInfo* renderingLayout; - PalBool primitiveRestartEnable; - uint32_t vertexLayoutCount; - uint32_t colorBlendAttachmentCount; - uint32_t shaderCount; + PalPipelineLayout* pipelineLayout; /**< Pipeline layout.*/ + PalShader** shaders; /**< Shaders.*/ + PalVertexLayout* vertexLayouts; /**< Vertex layouts.*/ + PalColorBlendAttachment* colorBlendAttachments; /**< Color blend attachments.*/ + PalRasterizerState* rasterizerState; /**< Rasterizer state.*/ + PalMultisampleState* multisampleState; /**< Multisample state.*/ + PalDepthStencilState* depthStencilState; /**< Depth stencil state.*/ + PalFragmentShadingRateState* fragmentShadingRateState; /**< Fragment shading rate state.*/ + PalRenderingLayoutInfo* renderingLayout; /**< Rendering layout.*/ + PalBool primitiveRestartEnable; /**< `PAL_TRUE` to enable primitive restart for indexed draw.*/ + uint32_t vertexLayoutCount; /**< Number of vertex layouts.*/ + uint32_t colorBlendAttachmentCount; /**< Number of color attachments.*/ + uint32_t shaderCount; /**< Number of shaders.*/ PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is `PAL_TRUE`.*/ PalPrimitiveTopology topology; } PalGraphicsPipelineCreateInfo; @@ -2567,8 +2567,8 @@ typedef struct { * @since 2.0 */ typedef struct { - PalPipelineLayout* pipelineLayout; - PalShader* computeShader; + PalPipelineLayout* pipelineLayout; /**< Pipeline layout.*/ + PalShader* computeShader; /**< Compute shader.*/ } PalComputePipelineCreateInfo; /** @@ -2582,15 +2582,15 @@ typedef struct { * @since 2.0 */ typedef struct { - PalRayTracingShaderGroupType type; - uint32_t anyHitShaderIndex; - uint32_t anyHitShaderEntryIndex; - uint32_t closestHitShaderIndex; - uint32_t closestHitShaderEntryIndex; - uint32_t generalShaderIndex; - uint32_t generalShaderEntryIndex; - uint32_t intersectionShaderIndex; - uint32_t intersectionShaderEntryIndex; + PalRayTracingShaderGroupType type; /**< (eg. `PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL`).*/ + uint32_t anyHitShaderIndex; /**< Index of the anyhit shader.*/ + uint32_t anyHitShaderEntryIndex; /**< Index of the anyhit shader entry.*/ + uint32_t closestHitShaderIndex; /**< Index of the closest hit shader.*/ + uint32_t closestHitShaderEntryIndex; /**< Index of the closest hit shader entry.*/ + uint32_t generalShaderIndex; /**< Index of the general shader.*/ + uint32_t generalShaderEntryIndex; /**< Index of the general shader entry.*/ + uint32_t intersectionShaderIndex; /**< Index of the intersection shader.*/ + uint32_t intersectionShaderEntryIndex; /**< Index of the intersection shader entry.*/ uint32_t maxDataSize; /**< Size of extra data associated with the shader group.*/ } PalRayTracingShaderGroupCreateInfo; @@ -2603,14 +2603,14 @@ typedef struct { * @since 2.0 */ typedef struct { - PalPipelineLayout* pipelineLayout; - PalRayTracingShaderGroupCreateInfo* shaderGroups; - PalShader** shaders; - uint64_t shaderGroupCount; - uint32_t shaderCount; - uint32_t maxRecursionDepth; - uint32_t maxAttributeSize; - uint32_t maxPayloadSize; + PalPipelineLayout* pipelineLayout; /**< Pipeline layout.*/ + PalRayTracingShaderGroupCreateInfo* shaderGroups; /**< Shader groups.*/ + PalShader** shaders; /**< Shaders.*/ + uint64_t shaderGroupCount; /**< Number of shader groups.*/ + uint32_t shaderCount; /**< Number of shaders.*/ + uint32_t maxRecursionDepth; /**< Max number of ray recursion.*/ + uint32_t maxAttributeSize; /**< Max attributes size in bytes.*/ + uint32_t maxPayloadSize; /**< Max payload size in bytes.*/ } PalRayTracingPipelineCreateInfo; /** @@ -2622,9 +2622,9 @@ typedef struct { * @since 2.0 */ typedef struct { - PalShaderBindingTableRecordInfo* records; - PalPipeline* rayTracingPipeline; - uint64_t recordCount; + PalShaderBindingTableRecordInfo* records; /**< Shader binding table records.*/ + PalPipeline* rayTracingPipeline; /**< Ray tracing pipeline.*/ + uint64_t recordCount; /**< Number of shader binding table records.*/ } PalShaderBindingTableCreateInfo; /** @@ -2636,8 +2636,8 @@ typedef struct { * @since 2.0 */ typedef struct { - const void* vtable; - PalGraphicsBackendVtableVersion version; + const void* vtable; /**< Pointer to the backend vtable.*/ + PalGraphicsBackendVtableVersion version; /**< (eg. `PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1`).*/ } PalGraphicsBackendInfo; /** From f74b0c6a810b0fc5ca39e42b0f45d814e752110f Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 26 Jun 2026 09:46:03 +0000 Subject: [PATCH 297/372] finalize API changes --- CHANGELOG.md | 6 ++++ include/pal/pal_graphics.h | 44 ++++++++++++++++++++++----- include/pal/pal_system.h | 38 +++++++++++------------ include/pal/pal_thread.h | 10 +++--- include/pal/pal_video.h | 62 +++++++++++++++----------------------- 5 files changed, 90 insertions(+), 70 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0428590a..0ba44b91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,12 @@ - Renamed `palGLGetProcAddress()` to `palGetGLProcAddress()`. - Renamed event type constants from `PAL_EVENT_**` to `PAL_EVENT_TYPE_**`. - Renamed dispatch mode constants from `PAL_DISPATCH_**` to `PAL_DISPATCH_MODE_**`. +- Renamed platform type constants from `PAL_PLATFORM_**` to `PAL_PLATFORM_TYPE_**`. +- Renamed platform api type constants from `PAL_PLATFORM_API_**` to `PAL_PLATFORM_API_TYPE_**`. +- Renamed cursor type constants from `PAL_CURSOR_**` to `PAL_CURSOR_TYPE_**`. +- Renamed flash flag constants from `PAL_FLASH_**` to `PAL_FLASH_FLAG_**`. +- Renamed fbConfig backend type constants from `PAL_CONFIG_BACKEND_**` to `PAL_FBCONFIG_BACKEND_**`. +- Renamed `PalFlashFlag` to `PalFlashFlags`. - `palInitGL()` now takes two additional parameters. - `palEnumerateGLFBConfigs()` no longer takes the `glWindow` parameter. - `palInitVideo()` now takes an additional parameter. diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 98da262c..98e073eb 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -308,9 +308,9 @@ #define PAL_POLYGON_MODE_LINE 1 #define PAL_POLYGON_MODE_COUNT 2 -#define PAL_STENCIL_FACE_FRONT (1U << 0) -#define PAL_STENCIL_FACE_BACK (1U << 1) -#define PAL_STENCIL_FACE_BOTH (PAL_STENCIL_FACE_FRONT | PAL_STENCIL_FACE_BACK) +#define PAL_STENCIL_FACE_FLAG_FRONT (1U << 0) +#define PAL_STENCIL_FACE_FLAG_BACK (1U << 1) +#define PAL_STENCIL_FACE_FLAG_BOTH (PAL_STENCIL_FACE_FLAG_FRONT | PAL_STENCIL_FACE_FLAG_BACK) #define PAL_VERTEX_TYPE_UNDEFINED 0 #define PAL_VERTEX_TYPE_INT32 1 /**< int32_t.*/ @@ -1059,7 +1059,7 @@ typedef uint32_t PalPolygonMode; * @brief Stencil face flags. Multiple stencil face flags can be OR'ed together using bitwise * OR operator (`|`). * - * All tencil face flags follow the format `PAL_STENCIL_FACE_**` for + * All tencil face flags follow the format `PAL_STENCIL_FACE_FLAG_**` for * consistency and API use. * * @since 2.0 @@ -4748,7 +4748,7 @@ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); * @brief Create a sampler. * * The graphics system must be initialized before this call. - * Samplers are immutable so any paramter used to create it cannot will be fixed after + * Samplers are immutable so any parameter used to create it cannot will be fixed after * creation. * * @param[in] device Device that creates the sampler. @@ -7223,11 +7223,11 @@ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( * times it needs to be dispatch in order for the work to be done. It works well with * palCmdDispatchBase() since its also gives the base for each work group. * - * @param[in] data Pointer to a PalWorkGroupBuildData with paramters. + * @param[in] data Pointer to a PalWorkGroupBuildData with parameters. * @param[in, out] count Capacity of the PalWorkGroupInfo array. * @param[out] infos Pointer to an Array of PalWorkGroupInfo. * - * @return True on success otherwise `PAL_FALSE`. + * @return `PAL_TRUE` on success otherwise `PAL_FALSE`. * * Thread safety: Must only be called from the main thread. * @@ -7243,6 +7243,34 @@ PAL_API PalBool PAL_CALL palBuildWorkGroupInfo( int32_t* count, PalWorkGroupInfo* info); -/** @} */ // end of pal_graphics group +/** + * @brief Check if a constant is supported in a mask. + * + * This function is used to check all masks in `supported_**` format in most of the capabilities + * query structs. + * + * Example: + * + * To check if `PAL_PRESENT_MODE_IMMEDIATE` is supported after querying `PalSurfaceCapabilities` + * capabilities of a surface, PalSurfaceCapabilities::supportedPresentModes should be the `mask` + * parameter and `PAL_PRESENT_MODE_IMMEDIATE` as the value parameter. + * + * @param[in] mask The supported mask. + * @param[in, out] value The value to check in the supported mask. + * + * @return `PAL_TRUE` on success otherwise `PAL_FALSE`. + * + * Thread safety: Thread safe. + * + * @since 2.0 + */ +static inline PalBool PAL_CALL palIsSupported( + uint32_t mask, + uint32_t value) +{ + return (mask & (1ULL << value)) != 0; +} + +/** @} */ #endif // _PAL_GRAPHICS_H diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index eb35681d..1debeeaa 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -39,21 +39,21 @@ #define PAL_CPU_FEATURE_BMI1 (1ULL << 10) #define PAL_CPU_FEATURE_BMI2 (1ULL << 11) -#define PAL_PLATFORM_WINDOWS 0 -#define PAL_PLATFORM_LINUX 1 -#define PAL_PLATFORM_MACOS 2 -#define PAL_PLATFORM_ANDROID 3 -#define PAL_PLATFORM_IOS 4 -#define PAL_PLATFORM_COUNT 5 - -#define PAL_PLATFORM_API_WIN32 0 -#define PAL_PLATFORM_API_WAYLAND 1 -#define PAL_PLATFORM_API_X11 2 -#define PAL_PLATFORM_API_COCOA 3 -#define PAL_PLATFORM_API_ANDRIOD 4 -#define PAL_PLATFORM_API_UIKIT 5 -#define PAL_PLATFORM_API_HEADLESS 6 -#define PAL_PLATFORM_API_COUNT 7 +#define PAL_PLATFORM_TYPE_WINDOWS 0 +#define PAL_PLATFORM_TYPE_LINUX 1 +#define PAL_PLATFORM_TYPE_MACOS 2 +#define PAL_PLATFORM_TYPE_ANDROID 3 +#define PAL_PLATFORM_TYPE_IOS 4 +#define PAL_PLATFORM_TYPE_COUNT 5 + +#define PAL_PLATFORM_API_TYPE_WIN32 0 +#define PAL_PLATFORM_API_TYPE_WAYLAND 1 +#define PAL_PLATFORM_API_TYPE_X11 2 +#define PAL_PLATFORM_API_TYPE_COCOA 3 +#define PAL_PLATFORM_API_TYPE_ANDRIOD 4 +#define PAL_PLATFORM_API_TYPE_UIKIT 5 +#define PAL_PLATFORM_API_TYPE_HEADLESS 6 +#define PAL_PLATFORM_API_TYPE_COUNT 7 /** * @typedef PalCpuArch @@ -84,7 +84,7 @@ typedef uint64_t PalCpuFeatures; * This is the family name (eg. This does not show if its Windows 7 or Windows 8 * etc). * - * All platform types follow the format `PAL_PLATFORM_**` for + * All platform types follow the format `PAL_PLATFORM_TYPE_**` for * consistency and API use. * * @since 1.0 @@ -98,7 +98,7 @@ typedef uint32_t PalPlatformType; * This is the API the playform uses. Most platforms support only one (eg. * Windows). * - * All platform API types follow the format `PAL_PLATFORM_API_**` for + * All platform API types follow the format `PAL_PLATFORM_API_TYPE_**` for * consistency and API use. * * @since 1.0 @@ -112,8 +112,8 @@ typedef uint32_t PalPlatformApiType; * @since 1.0 */ typedef struct { - PalPlatformType type; /**< (eg. `PAL_PLATFORM_WINDOWS`).*/ - PalPlatformApiType apiType; /**< (eg. `PAL_PLATFORM_API_WIN32`).*/ + PalPlatformType type; /**< (eg. `PAL_PLATFORM_TYPE_WINDOWS`).*/ + PalPlatformApiType apiType; /**< (eg. `PAL_PLATFORM_API_TYPE_WIN32`).*/ uint32_t totalMemory; /**< Total Disk space (memory) in GB.*/ uint32_t totalRAM; /**< Total CPU RAM (memory) in MB.*/ PalVersion version; /**< Platform version.*/ diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index 96dfb117..bce08ab7 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -16,10 +16,10 @@ #include "pal_core.h" -#define PAL_THREAD_FEATURE_STACK_SIZE (1ULL << 0) -#define PAL_THREAD_FEATURE_PRIORITY (1ULL << 1) -#define PAL_THREAD_FEATURE_AFFINITY (1ULL << 2) -#define PAL_THREAD_FEATURE_NAME (1ULL << 3) +#define PAL_THREAD_FEATURE_STACK_SIZE (1U << 0) +#define PAL_THREAD_FEATURE_PRIORITY (1U << 1) +#define PAL_THREAD_FEATURE_AFFINITY (1U << 2) +#define PAL_THREAD_FEATURE_NAME (1U << 3) #define PAL_THREAD_PRIORITY_LOW 0 #define PAL_THREAD_PRIORITY_NORMAL 1 @@ -67,7 +67,7 @@ typedef struct PalCondVar PalCondVar; * * @since 1.0 */ -typedef uint64_t PalThreadFeatures; +typedef uint32_t PalThreadFeatures; /** * @typedef PalThreadPriority diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 2f45e4c7..1b7e750b 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -79,15 +79,15 @@ #define PAL_WINDOW_STATE_RESTORED 3 #define PAL_WINDOW_STATE_COUNT 4 -#define PAL_FLASH_STOP 0 /**< Stop flashing.*/ -#define PAL_FLASH_CAPTION (1U << 0) /**< Flash the titlebar of the window.*/ -#define PAL_FLASH_TRAY (1U << 1) /**< Flash the icon of the window.*/ +#define PAL_FLASH_FLAG_STOP 0 /**< Stop flashing.*/ +#define PAL_FLASH_FLAG_CAPTION (1U << 0) /**< Flash the titlebar of the window.*/ +#define PAL_FLASH_FLAG_TRAY (1U << 1) /**< Flash the icon of the window.*/ -#define PAL_CONFIG_BACKEND_PAL_OPENGL 0 /**< Use PAL opengl module backend.*/ -#define PAL_CONFIG_BACKEND_EGL 1 -#define PAL_CONFIG_BACKEND_GLX 2 -#define PAL_CONFIG_BACKEND_WGL 3 -#define PAL_CONFIG_BACKEND_COUNT 4 +#define PAL_FBCONFIG_BACKEND_PAL_OPENGL 0 /**< Use PAL opengl module backend.*/ +#define PAL_FBCONFIG_BACKEND_EGL 1 +#define PAL_FBCONFIG_BACKEND_GLX 2 +#define PAL_FBCONFIG_BACKEND_WGL 3 +#define PAL_FBCONFIG_BACKEND_COUNT 4 #define PAL_SCANCODE_UNKNOWN 0 #define PAL_SCANCODE_A 1 @@ -116,7 +116,6 @@ #define PAL_SCANCODE_X 24 #define PAL_SCANCODE_Y 25 #define PAL_SCANCODE_Z 26 - #define PAL_SCANCODE_0 27 #define PAL_SCANCODE_1 28 #define PAL_SCANCODE_2 29 @@ -127,7 +126,6 @@ #define PAL_SCANCODE_7 34 #define PAL_SCANCODE_8 35 #define PAL_SCANCODE_9 36 - #define PAL_SCANCODE_F1 37 #define PAL_SCANCODE_F2 38 #define PAL_SCANCODE_F3 39 @@ -140,7 +138,6 @@ #define PAL_SCANCODE_F10 46 #define PAL_SCANCODE_F11 47 #define PAL_SCANCODE_F12 48 - #define PAL_SCANCODE_ESCAPE 49 #define PAL_SCANCODE_ENTER 50 #define PAL_SCANCODE_TAB 51 @@ -155,19 +152,16 @@ #define PAL_SCANCODE_RCTRL 60 #define PAL_SCANCODE_LALT 61 #define PAL_SCANCODE_RALT 62 - #define PAL_SCANCODE_LEFT 63 #define PAL_SCANCODE_RIGHT 64 #define PAL_SCANCODE_UP 65 #define PAL_SCANCODE_DOWN 66 - #define PAL_SCANCODE_INSERT 67 #define PAL_SCANCODE_DELETE 68 #define PAL_SCANCODE_HOME 69 #define PAL_SCANCODE_END 70 #define PAL_SCANCODE_PAGEUP 71 #define PAL_SCANCODE_PAGEDOWN 72 - #define PAL_SCANCODE_KP_0 73 #define PAL_SCANCODE_KP_1 74 #define PAL_SCANCODE_KP_2 75 @@ -185,7 +179,6 @@ #define PAL_SCANCODE_KP_DIVIDE 87 #define PAL_SCANCODE_KP_DECIMAL 88 #define PAL_SCANCODE_KP_EQUAL 89 - #define PAL_SCANCODE_PRINTSCREEN 90 #define PAL_SCANCODE_PAUSE 91 #define PAL_SCANCODE_MENU 92 @@ -231,7 +224,6 @@ #define PAL_KEYCODE_X 24 #define PAL_KEYCODE_Y 25 #define PAL_KEYCODE_Z 26 - #define PAL_KEYCODE_0 27 #define PAL_KEYCODE_1 28 #define PAL_KEYCODE_2 29 @@ -242,7 +234,6 @@ #define PAL_KEYCODE_7 34 #define PAL_KEYCODE_8 35 #define PAL_KEYCODE_9 36 - #define PAL_KEYCODE_F1 37 #define PAL_KEYCODE_F2 38 #define PAL_KEYCODE_F3 39 @@ -255,7 +246,6 @@ #define PAL_KEYCODE_F10 46 #define PAL_KEYCODE_F11 47 #define PAL_KEYCODE_F12 48 - #define PAL_KEYCODE_ESCAPE 49 #define PAL_KEYCODE_ENTER 50 #define PAL_KEYCODE_TAB 51 @@ -270,19 +260,16 @@ #define PAL_KEYCODE_RCTRL 60 #define PAL_KEYCODE_LALT 61 #define PAL_KEYCODE_RALT 62 - #define PAL_KEYCODE_LEFT 63 #define PAL_KEYCODE_RIGHT 64 #define PAL_KEYCODE_UP 65 #define PAL_KEYCODE_DOWN 66 - #define PAL_KEYCODE_INSERT 67 #define PAL_KEYCODE_DELETE 68 #define PAL_KEYCODE_HOME 69 #define PAL_KEYCODE_END 70 #define PAL_KEYCODE_PAGEUP 71 #define PAL_KEYCODE_PAGEDOWN 72 - #define PAL_KEYCODE_KP_0 73 #define PAL_KEYCODE_KP_1 74 #define PAL_KEYCODE_KP_2 75 @@ -300,7 +287,6 @@ #define PAL_KEYCODE_KP_DIVIDE 87 #define PAL_KEYCODE_KP_DECIMAL 88 #define PAL_KEYCODE_KP_EQUAL 89 - #define PAL_KEYCODE_PRINTSCREEN 90 #define PAL_KEYCODE_PAUSE 91 #define PAL_KEYCODE_MENU 92 @@ -327,12 +313,12 @@ #define PAL_MOUSE_BUTTON_X2 5 #define PAL_MOUSE_BUTTON_COUNT 6 -#define PAL_CURSOR_ARROW 0 -#define PAL_CURSOR_HAND 1 -#define PAL_CURSOR_CROSS 2 -#define PAL_CURSOR_IBEAM 3 -#define PAL_CURSOR_WAIT 4 -#define PAL_CURSOR_COUNT 5 +#define PAL_CURSOR_TYPE_ARROW 0 +#define PAL_CURSOR_TYPE_HAND 1 +#define PAL_CURSOR_TYPE_CROSS 2 +#define PAL_CURSOR_TYPE_IBEAM 3 +#define PAL_CURSOR_TYPE_WAIT 4 +#define PAL_CURSOR_TYPE_COUNT 5 /** * @struct PalMonitor @@ -412,24 +398,24 @@ typedef uint32_t PalWindowStyle; typedef uint32_t PalWindowState; /** - * @typedef PalFlashFlag + * @typedef PalFlashFlags * @brief Flash flags. Multiple flash flags can be OR'ed together using bitwise * OR operator (`|`). * - * `PAL_FLASH_STOP` is not a bit and must not be combined with other bits. + * `PAL_FLASH_FLAG_STOP` is not a bit and must not be combined with other bits. * - * All flash flags follow the format `PAL_FLASH_**` for consistency and + * All flash flags follow the format `PAL_FLASH_FLAG_**` for consistency and * API use. * * @since 1.0 */ -typedef uint32_t PalFlashFlag; +typedef uint32_t PalFlashFlags; /** * @typedef PalFBConfigBackend * @brief Represents the backend of a FBConfig. * - * All FBConfig backends follow the format `PAL_CONFIG_BACKEND**` for + * All FBConfig backends follow the format `PAL_FBCONFIG_BACKEND_**` for * consistency and API use. * * @since 1.0 @@ -473,7 +459,7 @@ typedef uint32_t PalMouseButton; * @typedef PalCursorType * @brief System cursor types. * - * All cursor types follow the format `PAL_CURSOR_**` for + * All cursor types follow the format `PAL_CURSOR_TYPE_**` for * consistency and API use. * * @since 1.0 @@ -520,7 +506,7 @@ typedef struct { * @since 1.0 */ typedef struct { - PalFlashFlag flags; /**< (eg. `PAL_FLASH_CAPTION`).*/ + PalFlashFlags flags; /**< (eg. `PAL_FLASH_FLAG_CAPTION`).*/ uint32_t interval; /**< In milliseconds. Set to 0 for default.*/ uint32_t count; /**< Set to 0 to flash until focused or cancelled.*/ } PalFlashInfo; @@ -1027,10 +1013,10 @@ PAL_API PalResult PAL_CALL palHideWindow(PalWindow* window); * * The video system must be initialized before this call. * - * If `PAL_FLASH_CAPTION` is used, `PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION` must + * If `PAL_FLASH_FLAG_CAPTION` is used, `PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION` must * be supported. * - * If `PAL_FLASH_TRAY` is used, `PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY` must be + * If `PAL_FLASH_FLAG_TRAY` is used, `PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY` must be * supported. * * @param[in] window Pointer to the window. @@ -1779,6 +1765,6 @@ PAL_API PalResult PAL_CALL palDetachWindow( PalWindow* window, void** outWindowHandle); -/** @} */ // end of pal_video group +/** @} */ #endif // _PAL_VIDEO_H From 4c59a9ca5f07fc9fb7cf6dca8ce22b51ea1240dd Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 28 Jun 2026 14:57:55 +0000 Subject: [PATCH 298/372] finalize result system --- CHANGELOG.md | 35 +++++--- include/pal/pal_core.h | 169 ++++++++++++++++++++++++++++--------- include/pal/pal_graphics.h | 100 ++++++++++++++-------- src/core/pal_result.h | 114 +++++++++++-------------- src/pal_shared.h | 26 ------ 5 files changed, 266 insertions(+), 178 deletions(-) delete mode 100644 src/pal_shared.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ba44b91..da8e1f94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,28 @@ - Added a graphics system API (`pal_graphics.h`). - Added `palGetResultCode()` to get the result code from a result value. +- Added `palGetResultSource()` to get the result source from a result value. +- Added `palGetResultNativeCode()` to get the result native code from a result value. - Added `palGetSupportedGLAPIs()` to check supported opengl api types. -- Added new `PalResult` values: - - `PAL_RESULT_INVALID_HANDLE` - - `PAL_RESULT_FEATURE_NOT_SUPPORTED` - - `PAL_RESULT_NOT_INITIALIZED` - - `PAL_RESULT_OUT_OF_DATE` +- Added type `PalResultCode` with values: + - `PAL_RESULT_CODE_INVALID_ARGUMENT` + - `PAL_RESULT_CODE_OUT_OF_MEMORY` + - `PAL_RESULT_CODE_PLATFORM_FAILURE` + - `PAL_RESULT_CODE_TIMEOUT` + - `PAL_RESULT_CODE_INVALID_HANDLE` + - `PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED` + - `PAL_RESULT_CODE_NOT_INITIALIZED` + - `PAL_RESULT_CODE_INVALID_OPERATION` + - `PAL_RESULT_CODE_DEVICE_LOST` + - `PAL_RESULT_CODE_OUT_OF_DATE` +- Added type `PalResultSource` with values: + - `PAL_RESULT_SOURCE_NONE` + - `PAL_RESULT_SOURCE_WIN32` + - `PAL_RESULT_SOURCE_POSIX` + - `PAL_RESULT_SOURCE_EGL` + - `PAL_RESULT_SOURCE_VULKAN` + - `PAL_RESULT_SOURCE_DIRECTX12` + - `PAL_RESULT_SOURCE_METAL` - Added type `PalGLBackend` with values: - `PAL_GL_BACKEND_EGL` - `PAL_GL_BACKEND_GLX` @@ -28,14 +44,7 @@ ### Changes - Converted all enum types to fixed-width integer types and their values to standalone constants (eg. `PalResult` to `uint64_t`). -- Removed all previous `PalResult` values except: - - `PAL_RESULT_SUCCESS` - - `PAL_RESULT_INVALID_ARGUMENT` - - `PAL_RESULT_PLATFORM_FAILURE` - - `PAL_RESULT_OUT_OF_MEMORY` - - `PAL_RESULT_TIMEOUT` - - `PAL_RESULT_INVALID_OPERATION`. - - `PAL_RESULT_DEVICE_LOST`. +- Removed all previous `PalResult` values except: `PAL_RESULT_SUCCESS` - Removed `UintXX` and `IntXX` types in favor of standard `uintXX_t` and `intXX_t`. - Removed `_MAX` constants from all type groups (eg. `PAL_EVENT_MAX`). - Replaced standard `bool` type and `true`/`false` constants with `PalBool` type and `PAL_TRUE`/`PAL_FALSE`. diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 821032c5..fb153209 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -58,19 +58,30 @@ #define PAL_TRUE 1 #define PAL_FALSE 0 #define PAL_INFINITE UINT32_MAX - #define PAL_RESULT_SUCCESS 0 -#define PAL_RESULT_INVALID_ARGUMENT 1 -#define PAL_RESULT_OUT_OF_MEMORY 2 -#define PAL_RESULT_PLATFORM_FAILURE 3 -#define PAL_RESULT_TIMEOUT 4 -#define PAL_RESULT_INVALID_HANDLE 5 -#define PAL_RESULT_FEATURE_NOT_SUPPORTED 6 -#define PAL_RESULT_NOT_INITIALIZED 7 -#define PAL_RESULT_INVALID_OPERATION 8 -#define PAL_RESULT_DEVICE_LOST 9 -#define PAL_RESULT_OUT_OF_DATE 10 -#define PAL_RESULT_COUNT 11 + +#define PAL_RESULT_CODE_INVALID_ARGUMENT 1 +#define PAL_RESULT_CODE_OUT_OF_MEMORY 2 +#define PAL_RESULT_CODE_PLATFORM_FAILURE 3 +#define PAL_RESULT_CODE_TIMEOUT 4 +#define PAL_RESULT_CODE_INVALID_HANDLE 5 +#define PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED 6 +#define PAL_RESULT_CODE_NOT_INITIALIZED 7 +#define PAL_RESULT_CODE_INVALID_OPERATION 8 +#define PAL_RESULT_CODE_DEVICE_LOST 9 +#define PAL_RESULT_CODE_OUT_OF_DATE 10 + +#define PAL_RESULT_CODE_COUNT 11 + +#define PAL_RESULT_SOURCE_NONE 0 +#define PAL_RESULT_SOURCE_WIN32 1 +#define PAL_RESULT_SOURCE_POSIX 2 +#define PAL_RESULT_SOURCE_EGL 3 +#define PAL_RESULT_SOURCE_VULKAN 4 +#define PAL_RESULT_SOURCE_DIRECTX12 5 +#define PAL_RESULT_SOURCE_METAL 6 + +#define PAL_RESULT_SOURCE_COUNT 7 /** * @typedef PalBool @@ -81,23 +92,48 @@ typedef uint32_t PalBool; /** * @typedef PalResult * @brief Value returned by most PAL functions. - * - * Non-success results (eg. `PAL_RESULT_INVALID_HANDLE`) may contain - * additional information for debugging and logging purposes. For checking specific - * result codes, call `palGetResultCode()` to get the code from the result value. - * - * Example: - * - * uint16_t resultCode = palGetResultCode(result); - * - * if (resultCode == `PAL_RESULT_INVALID_DEVICE_LOST`) {}. - * - * All result codes follow the format `PAL_RESULT_**` for consistency and API use. + * + * `PalResult` constains the PAL result code (eg. `PAL_RESULT_CODE_INVALID_HANDLE`), the native + * source (eg. `PAL_RESULT_SOURCE_POSIX`) and the native code itself. + * The native code and the source are optional and both can be zero if not provided. + * + * Only `PAL_RESULT_SUCCESS` is guarantee to be checked directly with the result value. + * To check specific result codes for fast path error handling, + * Call `palGetResultCode(result)` to get the PAL result code from the result value. + * + * Call `palGetResultSource(result)` and `palGetResultNativeCode(result)` to get the native + * source and native code. The native source shows where the native code was retrieved from. + * Example: `PAL_RESULT_SOURCE_WIN32` means the native code was retrieved from win32 + * (`GetLastError()`). * * @since 1.0 */ typedef uint64_t PalResult; +/** + * @typedef PalResultCode + * @brief Result codes that are extracted from `PalResult`. + * + * `palGetResultCode(result)` to get the result code from a result value. + * + * All result codes follow the format `PAL_RESULT_CODE_**` for consistency and API use. + * + * @since 2.0 + */ +typedef uint16_t PalResultCode; + +/** + * @typedef PalResultSource + * @brief Result sources that are extracted from `PalResult`. + * + * `palGetResultSource(result)` to get the result source from a result value. + * + * All result sources follow the format `PAL_RESULT_SOURCE_**` for consistency and API use. + * + * @since 2.0 + */ +typedef uint16_t PalResultSource; + /** * @typedef PalAllocateFn * @brief Function pointer type used for memory allocations. @@ -188,22 +224,6 @@ typedef struct { void* userData; /** Optional user-provided data. Can be nullptr.*/ } PalLogger; -/** - * Get the result code from the result value. - * - * `PAL_RESULT_SUCCESS` code can be compared with the result value without comparing the - * result code. - * - * @param result The result value. - * - * @return The result code from the result value. - * - * Thread safety: Thread safe. - * - * @since 2.0 - */ -PAL_API uint16_t PAL_CALL palGetResultCode(PalResult result); - /** * Convert a result value to a human-readable string. * @@ -327,6 +347,75 @@ PAL_API uint64_t PAL_CALL palGetPerformanceCounter(); */ PAL_API uint64_t PAL_CALL palGetPerformanceFrequency(); +/** + * Get the result code from the result value. + * + * @param result The result value. + * + * @return The result code from the result value. + * + * Thread safety: Thread safe. + * + * @since 2.0 + */ +static inline PalResultCode PAL_CALL palGetResultCode(PalResult result) +{ + return (uint16_t)(result & 0xFFFFU); +} + +/** + * Get the result source from the result value. + * + * @param result The result value. + * + * @return The result source from the result value. + * + * Thread safety: Thread safe. + * + * @since 2.0 + */ +static inline PalResultSource PAL_CALL palGetResultSource(PalResult result) +{ + return (uint16_t)((result >> 16) & 0xFFFFu); +} + +/** + * Get the result native code from the result value. + * + * @param result The result value. + * + * @return The result native code from the result value. + * + * Thread safety: Thread safe. + * + * @since 2.0 + */ +static inline uint32_t PAL_CALL palGetResultNativeCode(PalResult result) +{ + return (uint32_t)(result >> 32); +} + +/** + * Create a `PalResult` value. + * + * @param code The result code. + * @param source The result source. + * @param nativeCode The result native code. + * + * @return The created `PalResult` value. + * + * Thread safety: Thread safe. + * + * @since 2.0 + */ +static inline PalResult PAL_CALL palMakeResult( + PalResultCode code, + PalResultSource source, + uint32_t nativeCode) +{ + return ((uint64_t)nativeCode << 32) | ((uint64_t)source << 16) | (uint64_t)code; +} + /** * @brief Combine two 32-bit unsigned integers into a single 64-bit signed * integer. diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 98e073eb..74107397 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -252,7 +252,7 @@ #define PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR 0 #define PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR 1 #define PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR 2 -#define PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10 3 /**< HDR.*/ +#define PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10 3 #define PAL_SURFACE_FORMAT_COUNT 4 #define PAL_WINDOW_INSTANCE_TYPE_WAYLAND 0 @@ -313,36 +313,36 @@ #define PAL_STENCIL_FACE_FLAG_BOTH (PAL_STENCIL_FACE_FLAG_FRONT | PAL_STENCIL_FACE_FLAG_BACK) #define PAL_VERTEX_TYPE_UNDEFINED 0 -#define PAL_VERTEX_TYPE_INT32 1 /**< int32_t.*/ -#define PAL_VERTEX_TYPE_INT32_2 2 /**< int32_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_INT32_3 3 /**< int32_t vec3 or array[3].*/ -#define PAL_VERTEX_TYPE_INT32_4 4 /**< int32_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_UINT32 5 /**< uint32_t.*/ -#define PAL_VERTEX_TYPE_UINT32_2 6 /**< uint32_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_UINT32_3 7 /**< uint32_t vec3 or array[3].*/ -#define PAL_VERTEX_TYPE_UINT32_4 8 /**< uint32_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_INT8_2 9 /**< int8_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_INT8_4 10 /**< int8_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_UINT8_2 11 /**< uint8_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_UINT8_4 12 /**< uint8_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_INT8_2NORM 13 /**< int8_t vec2 or array[2] normalized.*/ -#define PAL_VERTEX_TYPE_INT8_4NORM 14 /**< int8_t vec4 or array[4] normalized.*/ -#define PAL_VERTEX_TYPE_UINT8_2NORM 15 /**< uint8_t vec2 or array[2] normalized.*/ -#define PAL_VERTEX_TYPE_UINT8_4NORM 16 /**< uint8_t vec4 or array[4] normalized.*/ -#define PAL_VERTEX_TYPE_INT16_2 17 /**< int16_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_INT16_4 18 /**< int16_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_UINT16_2 19 /**< uint16_t vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_UINT16_4 20 /**< uint16_t vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_INT16_2NORM 21 /**< int16_t vec2 or array[2] normalized.*/ -#define PAL_VERTEX_TYPE_INT16_4NORM 22 /**< int16_t vec4 or array[4] normalized.*/ -#define PAL_VERTEX_TYPE_UINT16_2NORM 23 /**< uint16_t vec2 or array[2] normalized.*/ -#define PAL_VERTEX_TYPE_UINT16_4NORM 24 /**< uint16_t vec4 or array[4] normalized.*/ -#define PAL_VERTEX_TYPE_FLOAT 25 /**< float*/ -#define PAL_VERTEX_TYPE_FLOAT2 26 /**< float vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_FLOAT3 27 /**< float vec3 or array[3].*/ -#define PAL_VERTEX_TYPE_FLOAT4 28 /**< float vec4 or array[4].*/ -#define PAL_VERTEX_TYPE_HALF_FLOAT16_2 29 /**< float16 vec2 or array[2].*/ -#define PAL_VERTEX_TYPE_HALF_FLOAT16_4 30 /**< float16 vec4 or array[4].*/ +#define PAL_VERTEX_TYPE_INT32 1 +#define PAL_VERTEX_TYPE_INT32_2 2 +#define PAL_VERTEX_TYPE_INT32_3 3 +#define PAL_VERTEX_TYPE_INT32_4 4 +#define PAL_VERTEX_TYPE_UINT32 5 +#define PAL_VERTEX_TYPE_UINT32_2 6 +#define PAL_VERTEX_TYPE_UINT32_3 7 +#define PAL_VERTEX_TYPE_UINT32_4 8 +#define PAL_VERTEX_TYPE_INT8_2 9 +#define PAL_VERTEX_TYPE_INT8_4 10 +#define PAL_VERTEX_TYPE_UINT8_2 11 +#define PAL_VERTEX_TYPE_UINT8_4 12 +#define PAL_VERTEX_TYPE_INT8_2NORM 13 +#define PAL_VERTEX_TYPE_INT8_4NORM 14 +#define PAL_VERTEX_TYPE_UINT8_2NORM 15 +#define PAL_VERTEX_TYPE_UINT8_4NORM 16 +#define PAL_VERTEX_TYPE_INT16_2 17 +#define PAL_VERTEX_TYPE_INT16_4 18 +#define PAL_VERTEX_TYPE_UINT16_2 19 +#define PAL_VERTEX_TYPE_UINT16_4 20 +#define PAL_VERTEX_TYPE_INT16_2NORM 21 +#define PAL_VERTEX_TYPE_INT16_4NORM 22 +#define PAL_VERTEX_TYPE_UINT16_2NORM 23 +#define PAL_VERTEX_TYPE_UINT16_4NORM 24 +#define PAL_VERTEX_TYPE_FLOAT 25 +#define PAL_VERTEX_TYPE_FLOAT2 26 +#define PAL_VERTEX_TYPE_FLOAT3 27 +#define PAL_VERTEX_TYPE_FLOAT4 28 +#define PAL_VERTEX_TYPE_HALF_FLOAT16_2 29 +#define PAL_VERTEX_TYPE_HALF_FLOAT16_4 30 #define PAL_VERTEX_TYPE_COUNT 31 #define PAL_VERTEX_SEMANTIC_ID_POSITION 0 @@ -1335,6 +1335,18 @@ typedef uint32_t PalRayTracingShaderGroupType; /** * @typedef PalDescriptorIndexingFlags * @brief Descriptor indexing subfeature flags. + * + * These flags show the capabilities of the descriptor indexing feature. Each flag determines + * the operations that are allowed. + * + * `PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND`: Descriptors in a descriptor set can be updated + * after the descriptor set been bound in a command buffer. + * + * `PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND`: Unused descriptors can be left uninitialized if + * a shader never accesses them. + * + * `PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING`: Different threads can access different + * descriptors. * * All descriptor indexing flags follow the format `PAL_DESCRIPTOR_INDEXING_FLAG_**` * for consistency and API use. @@ -1346,6 +1358,19 @@ typedef uint32_t PalDescriptorIndexingFlags; /** * @typedef PalBufferMemoryUsage * @brief Buffer memory usages. + * + * `PAL_BUFFER_MEMORY_USAGE_MANUAL`: PAL does not allocate memory for the buffer. Users are required + * to get the required size and allocate memory for the buffer after the buffer has been created. + * The lifetime of the memory is the responsibility of the user. + * + * `PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY`: PAL allocates gpu only memory and manages the memory + * for the user. This is ideal if a custom allocator will not be used by the user. + * + * `PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD`: PAL allocates cpu upload memory and manages the + * memory for the user. This is ideal if a custom allocator will not be used by the user. + * + * `PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK`: PAL allocates cpu readback memory and manages the + * memory for the user. This is ideal if a custom allocator will not be used by the user. * * All buffer memory usages follow the format `PAL_BUFFER_MEMORY_USAGE_**` * for consistency and API use. @@ -1357,6 +1382,13 @@ typedef uint32_t PalBufferMemoryUsage; /** * @typedef PalImageMemoryUsage * @brief Image memory usages. + * + * `PAL_IMAGE_MEMORY_USAGE_MANUAL`: PAL does not allocate memory for the image. Users are required + * to get the required size and allocate memory for the image after the image has been created. + * The lifetime of the memory is the responsibility of the user. + * + * `PAL_IMAGE_MEMORY_USAGE_AUTO_GPU_ONLY`: PAL allocates gpu only memory and manages the memory + * for the user. This is ideal if a custom allocator will not be used by the user. * * All image memory usages follow the format `PAL_IMAGE_MEMORY_USAGE_**` * for consistency and API use. @@ -2137,9 +2169,9 @@ typedef struct { PalGeometry* geometries; /**< BLAS geometries. nullptr for TLAS*/ PalDeviceAddress scratchBufferAddress; /**< Address of scratch buffer.*/ PalDeviceAddress instanceBufferAddress; /**< Address of instance buffer. nullptr for BLAS.*/ - PalAccelerationStructureBuildHints buildHints; /**< See `PalAccelerationStructureBuildHints`.*/ + PalAccelerationStructureBuildHints buildHints; /**< Might be ignored by driver.*/ PalAccelerationStructureType type; /**< (eg. `PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL`).*/ - PalAccelerationStructureBuildMode buildMode; /**< See `PalAccelerationStructureBuildMode`.*/ + PalAccelerationStructureBuildMode buildMode; /**< Build or update.*/ uint32_t count; /**< Number of elements in `geometries` or `instanceBufferAddress`.*/ } PalAccelerationStructureBuildInfo; @@ -4375,7 +4407,7 @@ PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( * Creating more queues than the supported will fail and return `PAL_RESULT_OUT_OF_QUEUE`. * * Not all graphics queues support presentation. Create a graphics queue and then check if - * its support presentation for the provided surface. see palCanQueuePresent(). Any graphics + * its support presentation for the provided surface. see `palCanQueuePresent()`. Any graphics * queue supports offscreen rendering. * * @param[in] device Device that creates the queue. diff --git a/src/core/pal_result.h b/src/core/pal_result.h index 755bb966..6f71c249 100644 --- a/src/core/pal_result.h +++ b/src/core/pal_result.h @@ -8,100 +8,78 @@ #ifndef _PAL_RESULT_H #define _PAL_RESULT_H -#include "pal_shared.h" #include "pal_format.h" -static inline uint16_t getResultCode(PalResult result) -{ - return (uint16_t)(result & 0xFFFFU); -} - -static inline uint16_t getResultSource(PalResult result) -{ - return (uint16_t)((result >> 16) & 0xFFFFu); -} - -static inline uint32_t getResultNativeCode(PalResult result) -{ - return (uint32_t)(result >> 32); -} - static const char* PAL_CALL resultCodeToString(PalResult result) { - uint16_t code = getResultCode(result); + PalResultCode code = palGetResultCode(result); switch (code) { - case PAL_RESULT_SUCCESS: - return "PAL_RESULT_SUCCESS"; - - case PAL_RESULT_INVALID_ARGUMENT: - return "PAL_RESULT_INVALID_ARGUMENT"; + case PAL_RESULT_CODE_INVALID_ARGUMENT: + return "PAL_RESULT_CODE_INVALID_ARGUMENT"; - case PAL_RESULT_OUT_OF_MEMORY: - return "PAL_RESULT_OUT_OF_MEMORY"; + case PAL_RESULT_CODE_OUT_OF_MEMORY: + return "PAL_RESULT_CODE_OUT_OF_MEMORY"; - case PAL_RESULT_PLATFORM_FAILURE: - return "PAL_RESULT_PLATFORM_FAILURE"; + case PAL_RESULT_CODE_PLATFORM_FAILURE: + return "PAL_RESULT_CODE_PLATFORM_FAILURE"; - case PAL_RESULT_TIMEOUT: - return "PAL_RESULT_TIMEOUT"; + case PAL_RESULT_CODE_TIMEOUT: + return "PAL_RESULT_CODE_TIMEOUT"; - case PAL_RESULT_INVALID_HANDLE: - return "PAL_RESULT_INVALID_HANDLE"; + case PAL_RESULT_CODE_INVALID_HANDLE: + return "PAL_RESULT_CODE_INVALID_HANDLE"; - case PAL_RESULT_FEATURE_NOT_SUPPORTED: - return "PAL_RESULT_FEATURE_NOT_SUPPORTED"; + case PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED: + return "PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED"; - case PAL_RESULT_NOT_INITIALIZED: - return "PAL_RESULT_NOT_INITIALIZED"; + case PAL_RESULT_CODE_NOT_INITIALIZED: + return "PAL_RESULT_CODE_NOT_INITIALIZED"; - case PAL_RESULT_INVALID_OPERATION: - return "PAL_RESULT_INVALID_OPERATION"; + case PAL_RESULT_CODE_INVALID_OPERATION: + return "PAL_RESULT_CODE_INVALID_OPERATION"; - case PAL_RESULT_DEVICE_LOST: - return "PAL_RESULT_DEVICE_LOST"; + case PAL_RESULT_CODE_DEVICE_LOST: + return "PAL_RESULT_CODE_DEVICE_LOST"; - case PAL_RESULT_OUT_OF_DATE: - return "PAL_RESULT_OUT_OF_DATE"; + case PAL_RESULT_CODE_OUT_OF_DATE: + return "PAL_RESULT_CODE_OUT_OF_DATE"; } - return nullptr; + return ""; } static const char* PAL_CALL resultCodeToDescription(PalResult result) { - uint16_t code = getResultCode(result); + PalResultCode code = palGetResultCode(result); switch (code) { - case PAL_RESULT_SUCCESS: - return "Success"; - - case PAL_RESULT_INVALID_ARGUMENT: + case PAL_RESULT_CODE_INVALID_ARGUMENT: return "Invalid argument"; - case PAL_RESULT_OUT_OF_MEMORY: + case PAL_RESULT_CODE_OUT_OF_MEMORY: return "Out of memory"; - case PAL_RESULT_PLATFORM_FAILURE: + case PAL_RESULT_CODE_PLATFORM_FAILURE: return "Platform failure"; - case PAL_RESULT_TIMEOUT: + case PAL_RESULT_CODE_TIMEOUT: return "Timeout"; - case PAL_RESULT_INVALID_HANDLE: + case PAL_RESULT_CODE_INVALID_HANDLE: return "Invalid handle"; - case PAL_RESULT_FEATURE_NOT_SUPPORTED: + case PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED: return "Feature not supported"; - case PAL_RESULT_NOT_INITIALIZED: + case PAL_RESULT_CODE_NOT_INITIALIZED: return "Not initialized"; - case PAL_RESULT_INVALID_OPERATION: + case PAL_RESULT_CODE_INVALID_OPERATION: return "Invalid operation"; - case PAL_RESULT_DEVICE_LOST: + case PAL_RESULT_CODE_DEVICE_LOST: return "Device lost"; - case PAL_RESULT_OUT_OF_DATE: + case PAL_RESULT_CODE_OUT_OF_DATE: return "Out of date"; } @@ -110,22 +88,28 @@ static const char* PAL_CALL resultCodeToDescription(PalResult result) static const char* PAL_CALL resultSourceToString(PalResult result) { - uint16_t source = getResultSource(result); + PalResultSource source = palGetResultSource(result); switch (source) { - case PAL_RESULT_SOURCE_WINDOWS: - return "Windows"; + case PAL_RESULT_SOURCE_WIN32: + return "WIN32"; - case PAL_RESULT_SOURCE_LINUX: - return "Linux"; + case PAL_RESULT_SOURCE_POSIX: + return "POSIX"; + + case PAL_RESULT_SOURCE_EGL: + return "EGL"; case PAL_RESULT_SOURCE_VULKAN: - return "Vulkan"; + return "VULKAN"; + + case PAL_RESULT_SOURCE_DIRECTX12: + return "DIRECTX12"; - case PAL_RESULT_SOURCE_D3D12: - return "D3D12"; + case PAL_RESULT_SOURCE_METAL: + return "METAL"; } - return nullptr; + return ""; } static void formatResultMsg(PalResult result, char* buffer, char* msg) @@ -133,7 +117,7 @@ static void formatResultMsg(PalResult result, char* buffer, char* msg) const char* baseString = resultCodeToString(result); const char* sourceString = resultSourceToString(result); const char* baseDescription = resultCodeToDescription(result); - uint32_t nativeCode = getResultNativeCode(result); + uint32_t nativeCode = palGetResultNativeCode(result); const char* description = ""; if (msg) { diff --git a/src/pal_shared.h b/src/pal_shared.h deleted file mode 100644 index 6ada50c2..00000000 --- a/src/pal_shared.h +++ /dev/null @@ -1,26 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifndef _PAL_SHARED_H -#define _PAL_SHARED_H - -#include "pal/pal_core.h" - -#define PAL_RESULT_SOURCE_WINDOWS 100 -#define PAL_RESULT_SOURCE_LINUX 101 -#define PAL_RESULT_SOURCE_VULKAN 102 -#define PAL_RESULT_SOURCE_D3D12 103 - -static inline PalResult palMakeResult( - uint16_t code, - uint16_t source, - uint32_t nativeCode) -{ - return ((uint64_t)nativeCode << 32) | ((uint64_t)source << 16) | (uint64_t)code; -} - -#endif // _PAL_SHARED_H \ No newline at end of file From 02d935ab13417d2ab236d152731a4765615fe5a4 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 28 Jun 2026 15:30:28 +0000 Subject: [PATCH 299/372] update core system and tests --- pal.lua | 12 +++++------ pal_config.lua | 6 +++--- src/core/pal_result.h | 6 +++--- .../pal_log_linux.c => posix/pal_log_posix.c} | 6 ++++-- .../pal_memory_posix.c} | 6 ++++-- .../pal_result_posix.c} | 13 +++++------- .../pal_time_posix.c} | 6 ++++-- src/core/win32/pal_result_win32.c | 7 +------ src/pal_posix.h | 20 +++++++++++++++++++ tests/tests.lua | 4 ++-- tools/abi_dump/opengl_abi_dump.c | 4 ++-- tools/abi_dump/video_abi_dump.c | 10 ++-------- 12 files changed, 56 insertions(+), 44 deletions(-) rename src/core/{linux/pal_log_linux.c => posix/pal_log_posix.c} (96%) rename src/core/{linux/pal_memory_linux.c => posix/pal_memory_posix.c} (93%) rename src/core/{linux/pal_result_linux.c => posix/pal_result_posix.c} (76%) rename src/core/{linux/pal_time_linux.c => posix/pal_time_posix.c} (87%) create mode 100644 src/pal_posix.h diff --git a/pal.lua b/pal.lua index 78bbf69f..daf48814 100644 --- a/pal.lua +++ b/pal.lua @@ -25,8 +25,8 @@ project "PAL" "src/core/pal_version.c", -- event - "src/event/pal_default_queue.c", - "src/event/pal_event.c" + -- "src/event/pal_default_queue.c", + -- "src/event/pal_event.c" } filter {"system:windows", "configurations:*"} @@ -39,10 +39,10 @@ project "PAL" filter {"system:linux", "configurations:*"} files { - "src/core/linux/pal_log_linux.c", - "src/core/linux/pal_memory_linux.c", - "src/core/linux/pal_result_linux.c", - "src/core/linux/pal_time_linux.c" + "src/core/posix/pal_log_posix.c", + "src/core/posix/pal_memory_posix.c", + "src/core/posix/pal_result_posix.c", + "src/core/posix/pal_time_posix.c" } filter {} diff --git a/pal_config.lua b/pal_config.lua index 9ecc849e..78d521da 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -12,13 +12,13 @@ PAL_BUILD_ABI_DUMP = true PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD_MODULE = true +PAL_BUILD_THREAD_MODULE = false -- build video module -PAL_BUILD_VIDEO_MODULE = true +PAL_BUILD_VIDEO_MODULE = false -- build opengl module -PAL_BUILD_OPENGL_MODULE = true +PAL_BUILD_OPENGL_MODULE = false -- build graphics module PAL_BUILD_GRAPHICS_MODULE = false diff --git a/src/core/pal_result.h b/src/core/pal_result.h index 6f71c249..4b97dc44 100644 --- a/src/core/pal_result.h +++ b/src/core/pal_result.h @@ -10,7 +10,7 @@ #include "pal_format.h" -static const char* PAL_CALL resultCodeToString(PalResult result) +static const char* resultCodeToString(PalResult result) { PalResultCode code = palGetResultCode(result); switch (code) { @@ -48,7 +48,7 @@ static const char* PAL_CALL resultCodeToString(PalResult result) return ""; } -static const char* PAL_CALL resultCodeToDescription(PalResult result) +static const char* resultCodeToDescription(PalResult result) { PalResultCode code = palGetResultCode(result); switch (code) { @@ -86,7 +86,7 @@ static const char* PAL_CALL resultCodeToDescription(PalResult result) return nullptr; } -static const char* PAL_CALL resultSourceToString(PalResult result) +static const char* resultSourceToString(PalResult result) { PalResultSource source = palGetResultSource(result); switch (source) { diff --git a/src/core/linux/pal_log_linux.c b/src/core/posix/pal_log_posix.c similarity index 96% rename from src/core/linux/pal_log_linux.c rename to src/core/posix/pal_log_posix.c index 77a9b097..4035e1e4 100644 --- a/src/core/linux/pal_log_linux.c +++ b/src/core/posix/pal_log_posix.c @@ -5,7 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ +#include "pal_posix.h" + +#if _PAL_ON_POSIX #include "core/pal_format.h" #include #include @@ -86,4 +88,4 @@ void PAL_CALL palLog( pthread_setspecific(s_TLSID, data); } -#endif // __linux__ \ No newline at end of file +#endif // _PAL_ON_POSIX \ No newline at end of file diff --git a/src/core/linux/pal_memory_linux.c b/src/core/posix/pal_memory_posix.c similarity index 93% rename from src/core/linux/pal_memory_linux.c rename to src/core/posix/pal_memory_posix.c index 75ad4d26..41435689 100644 --- a/src/core/linux/pal_memory_linux.c +++ b/src/core/posix/pal_memory_posix.c @@ -5,7 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ +#include "pal_posix.h" + +#if _PAL_ON_POSIX #define _POSIX_C_SOURCE 200112L #include "pal/pal_core.h" #include @@ -45,4 +47,4 @@ void PAL_CALL palFree( } } -#endif // __linux__ \ No newline at end of file +#endif // _PAL_ON_POSIX \ No newline at end of file diff --git a/src/core/linux/pal_result_linux.c b/src/core/posix/pal_result_posix.c similarity index 76% rename from src/core/linux/pal_result_linux.c rename to src/core/posix/pal_result_posix.c index 44b93f2a..ecae1010 100644 --- a/src/core/linux/pal_result_linux.c +++ b/src/core/posix/pal_result_posix.c @@ -5,24 +5,21 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ +#include "pal_posix.h" + +#if _PAL_ON_POSIX #define _POSIX_C_SOURCE 200112L #include "core/pal_format.h" #include "core/pal_result.h" #include -uint16_t PAL_CALL palGetResultCode(PalResult result) -{ - getResultCode(result); -} - void PAL_CALL palFormatResult( PalResult result, uint64_t bufferSize, char* buffer) { char tmpBuffer[256]; - uint32_t nativeCode = getResultNativeCode(result); + uint32_t nativeCode = palGetResultNativeCode(result); if (nativeCode != 0) { strerror_r(nativeCode, tmpBuffer, 256); formatResultMsg(result, buffer, tmpBuffer); @@ -32,4 +29,4 @@ void PAL_CALL palFormatResult( } } -#endif // __linux__ \ No newline at end of file +#endif // _PAL_ON_POSIX \ No newline at end of file diff --git a/src/core/linux/pal_time_linux.c b/src/core/posix/pal_time_posix.c similarity index 87% rename from src/core/linux/pal_time_linux.c rename to src/core/posix/pal_time_posix.c index a241e9eb..3013b572 100644 --- a/src/core/linux/pal_time_linux.c +++ b/src/core/posix/pal_time_posix.c @@ -5,7 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ +#include "pal_posix.h" + +#if _PAL_ON_POSIX #define _POSIX_C_SOURCE 200112L #include "pal/pal_core.h" #include @@ -22,4 +24,4 @@ uint64_t PAL_CALL palGetPerformanceFrequency() return 1000000000LL; } -#endif // __linux__ \ No newline at end of file +#endif // _PAL_ON_POSIX \ No newline at end of file diff --git a/src/core/win32/pal_result_win32.c b/src/core/win32/pal_result_win32.c index 579a717b..86c3c2c6 100644 --- a/src/core/win32/pal_result_win32.c +++ b/src/core/win32/pal_result_win32.c @@ -24,18 +24,13 @@ #include #include -uint16_t PAL_CALL palGetResultCode(PalResult result) -{ - getResultCode(result); -} - void PAL_CALL palFormatResult( PalResult result, uint64_t bufferSize, char* buffer) { char tmpBuffer[256]; - uint32_t nativeCode = getResultNativeCode(result); + uint32_t nativeCode = palGetResultNativeCode(result); if (nativeCode != 0) { FormatMessageA( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, diff --git a/src/pal_posix.h b/src/pal_posix.h new file mode 100644 index 00000000..b330b6f5 --- /dev/null +++ b/src/pal_posix.h @@ -0,0 +1,20 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_POSIX_H +#define _PAL_POSIX_H + +// clang-format off +#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) \ + || defined(__NetBSD) || defined(__OpenBSD) +#define _PAL_ON_POSIX 1 +#else +#define _PAL_ON_POSIX 0 +#endif // _PAL_ON_POSIX +// clang-format on + +#endif // _PAL_POSIX_H \ No newline at end of file diff --git a/tests/tests.lua b/tests/tests.lua index ca867607..f065d7ea 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -14,8 +14,8 @@ project "tests" "core/time_test.c", -- event - "event/user_event_test.c", - "event/event_test.c" + -- "event/user_event_test.c", + -- "event/event_test.c" } if (PAL_BUILD_SYSTEM_MODULE) then diff --git a/tools/abi_dump/opengl_abi_dump.c b/tools/abi_dump/opengl_abi_dump.c index f66f0eec..343a2df0 100644 --- a/tools/abi_dump/opengl_abi_dump.c +++ b/tools/abi_dump/opengl_abi_dump.c @@ -164,7 +164,7 @@ static void windowDump(PalBool verbose) uint32_t ySize = sizeof(PalGLWindow); uint32_t yAlign = PAL_ALIGNOF(PalGLWindow); - uint32_t yOffset1 = offsetof(PalGLWindow, display); + uint32_t yOffset1 = offsetof(PalGLWindow, instance); uint32_t yOffset2 = offsetof(PalGLWindow, window); uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; @@ -188,7 +188,7 @@ static void windowDump(PalBool verbose) palLog(nullptr, "size %u %u", xSize, ySize); palLog(nullptr, "align %u %u", xAlign, yAlign); palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "display @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "instance @ %u %u", xOffset1, yOffset1); palLog(nullptr, "window @ %u %u", xOffset2, yOffset2); palLog(nullptr, "==========================================="); } diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index 002d0aab..7a3f1866 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -292,7 +292,7 @@ static void windowInfoDump(PalBool verbose) uint32_t ySize = sizeof(PalWindowHandleInfo); uint32_t yAlign = PAL_ALIGNOF(PalWindowHandleInfo); - uint32_t yOffset1 = offsetof(PalWindowHandleInfo, nativeDisplay); + uint32_t yOffset1 = offsetof(PalWindowHandleInfo, nativeInstance); uint32_t yOffset2 = offsetof(PalWindowHandleInfo, nativeWindow); uint32_t yOffset3 = offsetof(PalWindowHandleInfo, nativeHandle1); uint32_t yOffset4 = offsetof(PalWindowHandleInfo, nativeHandle2); @@ -322,7 +322,7 @@ static void windowInfoDump(PalBool verbose) palLog(nullptr, "size %u %u", xSize, ySize); palLog(nullptr, "align %u %u", xAlign, yAlign); palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "nativeDisplay @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "nativeInstance @ %u %u", xOffset1, yOffset1); palLog(nullptr, "nativeWindow @ %u %u", xOffset2, yOffset2); palLog(nullptr, "nativeHandle1 @ %u %u", xOffset3, yOffset3); palLog(nullptr, "nativeHandle2 @ %u %u", xOffset4, yOffset4); @@ -365,8 +365,6 @@ static void windowDump(PalBool verbose) uint32_t yOffset8 = offsetof(PalWindowCreateInfo, width); uint32_t yOffset9 = offsetof(PalWindowCreateInfo, height); uint32_t yOffset10 = offsetof(PalWindowCreateInfo, show); - uint32_t yOffset11 = offsetof(PalWindowCreateInfo, maximized); - uint32_t yOffset12 = offsetof(PalWindowCreateInfo, minimized); uint32_t yOffset13 = offsetof(PalWindowCreateInfo, center); uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; @@ -384,8 +382,6 @@ static void windowDump(PalBool verbose) xOffset8 == yOffset8 && xOffset9 == yOffset9 && xOffset10 == yOffset10 && - xOffset11 == yOffset11 && - xOffset12 == yOffset12 && xOffset13 == yOffset13 && xPadding == yPadding) { result = s_PassedString; @@ -411,8 +407,6 @@ static void windowDump(PalBool verbose) palLog(nullptr, "width @ %u %u", xOffset8, yOffset8); palLog(nullptr, "height @ %u %u", xOffset9, yOffset9); palLog(nullptr, "show @ %u %u", xOffset10, yOffset10); - palLog(nullptr, "maximized @ %u %u", xOffset11, yOffset11); - palLog(nullptr, "minimized @ %u %u", xOffset12, yOffset12); palLog(nullptr, "center @ %u %u", xOffset13, yOffset13); palLog(nullptr, "==========================================="); } From 59573609d56fdfb0115466a1e6fe39c4fcc0bedf Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 28 Jun 2026 15:37:51 +0000 Subject: [PATCH 300/372] make nullptr a code in docs --- include/pal/pal_core.h | 30 ++++---- include/pal/pal_event.h | 32 ++++----- include/pal/pal_graphics.h | 144 ++++++++++++++++++------------------- include/pal/pal_opengl.h | 36 +++++----- include/pal/pal_system.h | 2 +- include/pal/pal_thread.h | 34 ++++----- include/pal/pal_video.h | 84 +++++++++++----------- tests/tests_main.c | 2 +- 8 files changed, 182 insertions(+), 182 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index fb153209..a28c854d 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -138,11 +138,11 @@ typedef uint16_t PalResultSource; * @typedef PalAllocateFn * @brief Function pointer type used for memory allocations. * - * @param[in] userData Optional pointer to user data. Can be nullptr. + * @param[in] userData Optional pointer to user data. Can be `nullptr`. * @param[in] size Number of bytes to allocate. Must not be 0. * @param[in] alignment Must be power of two. Set to 0 to use default. * - * @return Pointer to the allocated memory on success or nullptr on failure. + * @return Pointer to the allocated memory on success or `nullptr` on failure. * * @since 1.0 * @sa PalFreeFn @@ -156,9 +156,9 @@ typedef void*(PAL_CALL* PalAllocateFn)( * @typedef PalFreeFn * @brief Function pointer type used for memory deallocations. * - * @param[in] userData Optional pointer to user data. Can be nullptr. + * @param[in] userData Optional pointer to user data. Can be `nullptr`. * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must return safely if - * pointer is nullptr. + * pointer is `nullptr`. * * @since 1.0 * @sa PalAllocateFn @@ -171,7 +171,7 @@ typedef void(PAL_CALL* PalFreeFn)( * @typedef PalLogCallback * @brief Function pointer type used for log callbacks. * - * @param userData Optional pointer to user data passed from ::PalLogger. Can be nullptr. + * @param userData Optional pointer to user data passed from ::PalLogger. Can be `nullptr`. * @param msg Null-terminated UTF-8 log message. * * @since 1.0 @@ -204,9 +204,9 @@ typedef struct { * @since 1.0 */ typedef struct { - PalAllocateFn allocate; /**< Allocate function pointer. Must not be nullptr.*/ - PalFreeFn free; /**< Free function pointer. Must not be nullptr.*/ - void* userData; /**< Optional user-provided data. Can be nullptr.*/ + PalAllocateFn allocate; /**< Allocate function pointer. Must not be `nullptr`.*/ + PalFreeFn free; /**< Free function pointer. Must not be `nullptr`.*/ + void* userData; /**< Optional user-provided data. Can be `nullptr`.*/ } PalAllocator; /** @@ -220,8 +220,8 @@ typedef struct { * @since 1.0 */ typedef struct { - PalLogCallback callback; /**< Callback function pointer. Must not be nullptr.*/ - void* userData; /** Optional user-provided data. Can be nullptr.*/ + PalLogCallback callback; /**< Callback function pointer. Must not be `nullptr`.*/ + void* userData; /** Optional user-provided data. Can be `nullptr`.*/ } PalLogger; /** @@ -269,11 +269,11 @@ PAL_API const char* PAL_CALL palGetVersionString(); /** * Allocate memory using a custom or default allocator. * - * @param allocator The allocator to use. Set to nullptr to use default. + * @param allocator The allocator to use. Set to `nullptr` to use default. * @param size Number of bytes to allocate. * @param alignment Alignment in bytes. Must be a power of two. Set to 0 to use default. * - * @return Pointer to allocated memory on success, or nullptr on failure. + * @return Pointer to allocated memory on success, or `nullptr` on failure. * * Thread safety: Thread safe if the provided allocator is thread safe. The default allocator * is thread safe. @@ -289,9 +289,9 @@ PAL_API void* PAL_CALL palAllocate( /** * Free memory allocated by palAllocate. * - * @param allocator The allocator used to allocate the memory. Set to nullptr to + * @param allocator The allocator used to allocate the memory. Set to `nullptr` to * use default. - * @param ptr Pointer to memory to free. If nullptr, the function returns + * @param ptr Pointer to memory to free. If `nullptr`, the function returns * silently. * * Thread safety: Thread safe if the provided allocator is thread @@ -307,7 +307,7 @@ PAL_API void PAL_CALL palFree( /** * Log a formatted message. * - * @param logger Logger instance. Set to nullptr to use default logger. + * @param logger Logger instance. Set to `nullptr` to use default logger. * @param fmt printf-style format string. * @param ... Arguments for the format string. * diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 5c88631f..184b5274 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -279,7 +279,7 @@ typedef uint32_t PalDispatchMode; * @typedef PalEventCallback * @brief Function pointer type used for event callbacks. * - * @param[in] userData Optional pointer to user data. Can be nullptr. + * @param[in] userData Optional pointer to user data. Can be `nullptr`. * @param[in] event Pointer to the event. * * @since 1.0 @@ -293,7 +293,7 @@ typedef void(PAL_CALL* PalEventCallback)( * @typedef PalPushFn * @brief Function pointer type used for pushing events into event queues. * - * @param[in] userData Optional pointer to user data. Can be nullptr. + * @param[in] userData Optional pointer to user data. Can be `nullptr`. * @param[in] event Pointer to the event to push. * * @since 1.0 @@ -311,7 +311,7 @@ typedef void(PAL_CALL* PalPushFn)( * If the queue is not empty and the event was retrieved, this should return * `PAL_TRUE`. * - * @param[in] userData Optional pointer to user data. Can be nullptr. + * @param[in] userData Optional pointer to user data. Can be `nullptr`. * @param[out] event Pointer to the PalEvent to recieve the event. * * @since 1.0 @@ -337,9 +337,9 @@ struct PalEvent { * @since 1.0 */ typedef struct { - PalPushFn push; /**< Push function pointer. Must not be nullptr.*/ - PalPollFn poll; /**< Poll function pointer. Must not be nullptr.*/ - void* userData; /**< Optional user-provided data. Can be nullptr.*/ + PalPushFn push; /**< Push function pointer. Must not be `nullptr`.*/ + PalPollFn poll; /**< Poll function pointer. Must not be `nullptr`.*/ + void* userData; /**< Optional user-provided data. Can be `nullptr`.*/ } PalEventQueue; /** @@ -351,10 +351,10 @@ typedef struct { * @since 1.0 */ typedef struct { - const PalAllocator* allocator; /**< Set to nullptr to use default.*/ - PalEventQueue* queue; /**< Set to nullptr to use default.*/ - PalEventCallback callback; /**< Can be nullptr.*/ - void* userData; /**< Optional user-provided data. Can be nullptr.*/ + const PalAllocator* allocator; /**< Set to `nullptr` to use default.*/ + PalEventQueue* queue; /**< Set to `nullptr` to use default.*/ + PalEventCallback callback; /**< Can be `nullptr`.*/ + void* userData; /**< Optional user-provided data. Can be `nullptr`.*/ } PalEventDriverCreateInfo; /** @@ -366,9 +366,9 @@ typedef struct { * longer needed. * * @param[in] info Pointer to a PalEventDriverCreateInfo struct that specifies - * parameters. Must not be nullptr. + * parameters. Must not be `nullptr`. * @param[out] outEventDriver Pointer to a PalEventDriver to recieve the created - * event driver. Must not be nullptr. + * event driver. Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -387,7 +387,7 @@ PAL_API PalResult PAL_CALL palCreateEventDriver( /** * @brief Destroy the provided event driver. * - * If the provided event driver is invalid or nullptr, this function returns + * If the provided event driver is invalid or `nullptr`, this function returns * silently. * * @param[in] eventDriver Pointer to the event driver to destroy. @@ -404,7 +404,7 @@ PAL_API void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver); * @brief Set the dispatch mode for an event type with the provided event * driver. * - * If the provided event driver is invalid or nullptr, this function returns + * If the provided event driver is invalid or `nullptr`, this function returns * silently. * * If the dispatch mode is `PAL_DISPATCH_MODE_POLL`, the event will be dispatched @@ -451,7 +451,7 @@ PAL_API PalDispatchMode PAL_CALL palGetEventDispatchMode( * @brief Push an event into the queue or callback function of the provided * event driver. * - * If the provided event driver is invalid or nullptr, this function returns + * If the provided event driver is invalid or `nullptr`, this function returns * silently. * * If the dispatch mode for the event is `PAL_DISPATCH_MODE_POLL`, the event will be @@ -479,7 +479,7 @@ PAL_API void PAL_CALL palPushEvent( * @brief Retrieve the next available event from the queue of the provided event * driver. * - * If the provided event driver is invalid or nullptr, this function returns + * If the provided event driver is invalid or `nullptr`, this function returns * silently. * * This function retrieves the next pending event from the queue of the diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 74107397..f1c639e9 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1412,7 +1412,7 @@ typedef uint64_t PalGraphicsBackendVtableVersion; * @typedef PalDebugCallback * @brief Function pointer type used for debug callbacks. * - * @param userData Optional pointer to user data passed from ::PalGraphicsDebugger. Can be nullptr. + * @param userData Optional pointer to user data passed from ::PalGraphicsDebugger. Can be `nullptr`. * @param severity Severity of the message. (`PAL_DEBUG_MESSAGE_SEVERITY_INFO`, * `PAL_DEBUG_MESSAGE_SEVERITY_WARNING` and `PAL_DEBUG_MESSAGE_SEVERITY_ERROR`). * @param type Type of the message. (`PAL_DEBUG_MESSAGE_TYPE_GENERAL`, @@ -1721,8 +1721,8 @@ typedef struct { * @since 2.0 */ typedef struct { - PalImageView* imageView; /**< Image view. Must not be nullptr.*/ - PalImageView* resolveImageView; /**< Resolve image view. Can be nullptr.*/ + PalImageView* imageView; /**< Image view. Must not be `nullptr`.*/ + PalImageView* resolveImageView; /**< Resolve image view. Can be `nullptr`.*/ PalLoadOp loadOp; /**< (eg. `PAL_LOAD_OP_CLEAR`).*/ PalStoreOp storeOp; /**< (eg. `PAL_STORE_OP_STORE`).*/ PalLoadOp stencilLoadOp; /**< (eg. `PAL_LOAD_OP_DONT_CARE`).*/ @@ -1968,7 +1968,7 @@ typedef struct { * @since 2.0 */ typedef struct { - void* userData; /**< Optional user provided data. Can be nullptr.*/ + void* userData; /**< Optional user provided data. Can be `nullptr`.*/ PalDebugCallback callback; /**< Debug callback function.*/ PalBool denyGeneral; /**< Do not recieve general messages.*/ PalBool denyValidation; /**< Do not recieve validation messages.*/ @@ -2006,7 +2006,7 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t sampleMask; /**< Set to nullptr to use default.*/ + uint64_t sampleMask; /**< Set to `nullptr` to use default.*/ PalBool enableSampleShading; /**< `PAL_TRUE` to enable sample shading.*/ PalBool enableAlphaToCoverage; /**< `PAL_TRUE` to enable alpha to coverage.*/ PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_4`).*/ @@ -2166,9 +2166,9 @@ typedef struct { typedef struct { PalAccelerationStructure* dst; /**< Destination aceleration structure.*/ PalAccelerationStructure* src; /**< Source aceleration structure. Used for updates.*/ - PalGeometry* geometries; /**< BLAS geometries. nullptr for TLAS*/ + PalGeometry* geometries; /**< BLAS geometries. `nullptr` for TLAS*/ PalDeviceAddress scratchBufferAddress; /**< Address of scratch buffer.*/ - PalDeviceAddress instanceBufferAddress; /**< Address of instance buffer. nullptr for BLAS.*/ + PalDeviceAddress instanceBufferAddress; /**< Address of instance buffer. `nullptr` for BLAS.*/ PalAccelerationStructureBuildHints buildHints; /**< Might be ignored by driver.*/ PalAccelerationStructureType type; /**< (eg. `PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL`).*/ PalAccelerationStructureBuildMode buildMode; /**< Build or update.*/ @@ -2377,7 +2377,7 @@ typedef struct { * @since 2.0 */ typedef struct { - void* localData; /**< Must not be nullptr if `localDataSize` is not 0.*/ + void* localData; /**< Must not be `nullptr` if `localDataSize` is not 0.*/ uint32_t groupIndex; /**< Index into the shader groups used to create the pipeline.*/ uint32_t localDataSize; /**< Must not be greater than the data size of the group.*/ } PalShaderBindingTableRecordInfo; @@ -2391,7 +2391,7 @@ typedef struct { * @since 2.0 */ typedef struct { - const char* entryName; /**< Must not be nullptr.*/ + const char* entryName; /**< Must not be `nullptr`.*/ PalShaderStage stage; /**< (eg. `PAL_SHADER_STAGE_VERTEX`).*/ uint32_t patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ } PalShaderEntryInfo; @@ -3976,9 +3976,9 @@ typedef struct { * * The debugger, allocator and custom backends will not not copied, therefore the pointers must * remain valid until the graphics system is shutdown. Set the debugger or - * PalGraphicsDebugger::callback to nullptr to disable debugging and validation layers. + * PalGraphicsDebugger::callback to `nullptr` to disable debugging and validation layers. * - * If `debugger` is not nullptr and there is no debug layers, this function will not fail but + * If `debugger` is not `nullptr` and there is no debug layers, this function will not fail but * debugging will be disabled. * * All backends must have their vtable functions fully set according to the version requirements. @@ -3986,9 +3986,9 @@ typedef struct { * returned by the appropriate function. This is validated at initialization and will fail and * return `PAL_RESULT_INVALID_ARGUMENT`. * - * @param[in] debugger Optional debugger. Set to nullptr to disable debugging and validation + * @param[in] debugger Optional debugger. Set to `nullptr` to disable debugging and validation * layers. - * @param[in] allocator Optional user-provided allocator. Set to nullptr to use default. + * @param[in] allocator Optional user-provided allocator. Set to `nullptr` to use default. * @param[in] customBackendCount The number of custom backends in `customBackends`. * @param[in] customBackends Pointer to an array of custom backends. * @@ -4029,7 +4029,7 @@ PAL_API void PAL_CALL palShutdownGraphics(); * of them in the list. Use PalAdapterInfo::backendName to differentiate between custom and * internal backend. the backend name for internal backend is `PAL`. * - * Call this function first with PalAdapter array set to nullptr to get the number of adapters. + * Call this function first with PalAdapter array set to `nullptr` to get the number of adapters. * Allocate memory for the PalAdapter array and passed in the count and the allocated array. If * the count of the array is less than the number of adapters, PAL will write upto that limit. * @@ -4139,7 +4139,7 @@ PAL_API uint32_t PAL_CALL palGetHighestSupportedShaderTarget( * * @param[in] adapter Adapter that creates the device. * @param[in] features Adapter features to enable. Must be supported. - * @param[out] outDevice Pointer to a PalDevice to recieve the created device. Must not be nullptr. + * @param[out] outDevice Pointer to a PalDevice to recieve the created device. Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -4158,7 +4158,7 @@ PAL_API PalResult PAL_CALL palCreateDevice( * @brief Destroy a device. * * The graphics system must be initialized before this call. - * If the provided device is invalid or nullptr, this function returns + * If the provided device is invalid or `nullptr`, this function returns * silently. * * @param[in] device Pointer to the device to destroy. @@ -4205,7 +4205,7 @@ PAL_API PalResult PAL_CALL palAllocateMemory( * @brief Free GPU memory allocated by palAllocateMemory. * * The graphics system must be initialized before this call. - * If `memory` is nullptr, this function will return silently. + * If `memory` is `nullptr`, this function will return silently. * * @param[in] device Pointer to device to free memory on. * @param[in] memory Pointer to memory to free. @@ -4431,7 +4431,7 @@ PAL_API PalResult PAL_CALL palCreateQueue( * @brief Destroy a queue. * * The graphics system must be initialized before this call. - * If the provided queue is invalid or nullptr, this function returns + * If the provided queue is invalid or `nullptr`, this function returns * silently. * * @param[in] queue Queue to destroy. @@ -4491,7 +4491,7 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); * associated with the format. This is a handy way of selecting a format based on the image * usages. Use palIsFormatSupported() to check for a specific format. * - * Call this function first with PalFormatInfo array set to nullptr to get the number of formats. + * Call this function first with PalFormatInfo array set to `nullptr` to get the number of formats. * Allocate memory for the PalFormatInfo array and passed in the count and the allocated array. If * the count of the array is less than the number of formats, PAL will write upto that limit. * @@ -4583,7 +4583,7 @@ PAL_API PalSampleCount PAL_CALL palQueryFormatSampleCount( * * @param[in] device Device that creates the image. * @param[in] info Pointer to a PalImageCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outImage Pointer to a PalImage to recieve the created image. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4603,7 +4603,7 @@ PAL_API PalResult PAL_CALL palCreateImage( * @brief Destroy an image. * * The graphics system must be initialized before this call. - * If the provided image is invalid or nullptr, this function returns + * If the provided image is invalid or `nullptr`, this function returns * silently. * * @param[in] image Image to destroy. @@ -4664,7 +4664,7 @@ PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( * Get the requirements with palGetImageMemoryRequirements(). * * @param[in] image Image to bind memory to. - * @param[in] memory Memory to bind. Must not be nullptr. + * @param[in] memory Memory to bind. Must not be `nullptr`. * @param[in] offset Starting point within the memory. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4742,7 +4742,7 @@ PAL_API void PAL_CALL palUnmapImageMemory(PalImage* image); * @param[in] device Device that creates the image view. * @param[in] image Image to create the image view with. * @param[in] info Pointer to a PalImageViewCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outImageView Pointer to a PalImageView to recieve the created image view. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4763,7 +4763,7 @@ PAL_API PalResult PAL_CALL palCreateImageView( * @brief Destroy an image view. * * The graphics system must be initialized before this call. - * If the provided image view is invalid or nullptr, this function returns + * If the provided image view is invalid or `nullptr`, this function returns * silently. * * @param[in] imageView Image view to destroy. @@ -4785,7 +4785,7 @@ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); * * @param[in] device Device that creates the sampler. * @param[in] info Pointer to a PalSamplerCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outSampler Pointer to a PalSampler to recieve the created sampler. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4805,7 +4805,7 @@ PAL_API PalResult PAL_CALL palCreateSampler( * @brief Destroy a sampler. * * The graphics system must be initialized before this call. - * If the provided sampler is invalid or nullptr, this function returns + * If the provided sampler is invalid or `nullptr`, this function returns * silently. * * @param[in] sampler Sampler to destroy. @@ -4851,7 +4851,7 @@ PAL_API PalResult PAL_CALL palCreateSurface( * @brief Destroy a surface. * * The graphics system must be initialized before this call. - * If the provided surface is invalid or nullptr, this function returns + * If the provided surface is invalid or `nullptr`, this function returns * silently. * * @param[in] surface Surface to destroy. @@ -4900,7 +4900,7 @@ PAL_API PalResult PAL_CALL palGetSurfaceCapabilities( * @param[in] queue Queue to create swapchain with. This must be a graphics queue. * @param[in] surface Surface to create swapchain with. * @param[in] info Pointer to a PalSwapchainCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outSwapchain Pointer to a PalSwapchain to recieve the created swapchain. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4922,7 +4922,7 @@ PAL_API PalResult PAL_CALL palCreateSwapchain( * @brief Destroy a swapchain. * * The graphics system must be initialized before this call. - * If the provided swapchain is invalid or nullptr, this function returns + * If the provided swapchain is invalid or `nullptr`, this function returns * silently. * * @param[in] swapchain Swapchain to destroy. @@ -4943,7 +4943,7 @@ PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); * @param[in] swapchain Swapchain to get image from. * @param[in] index Index of image in the list. Must not be greater than the image count. * - * @return A pointer to the image on success otherwise nullptr on failure. + * @return A pointer to the image on success otherwise `nullptr` on failure. * * Thread safety: Thread safe. * @@ -4961,7 +4961,7 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( * * @param[in] swapchain Swapchain to get image index from. * @param[in] info Pointer to a PalSwapchainNextImageInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outIndex Pointer to a uint32_t to recieve the next image index. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4984,7 +4984,7 @@ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( * * @param[in] swapchain Swapchain to present. * @param[in] info Pointer to a PalSwapchainPresentInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5043,7 +5043,7 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * * @param[in] device Device that creates the shader. * @param[in] info Pointer to a PalShaderCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outShader Pointer to a PalShader to recieve the created shader. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -5065,7 +5065,7 @@ PAL_API PalResult PAL_CALL palCreateShader( * @brief Destroy a shader. * * The graphics system must be initialized before this call. - * If the provided shader is invalid or nullptr, this function returns + * If the provided shader is invalid or `nullptr`, this function returns * silently. * * @param[in] shader Shader to destroy. @@ -5105,7 +5105,7 @@ PAL_API PalResult PAL_CALL palCreateFence( * @brief Destroy a fence. * * The graphics system must be initialized before this call. - * If the provided fence is invalid or nullptr, this function returns + * If the provided fence is invalid or `nullptr`, this function returns * silently. * * @param[in] fence Fence to destroy. @@ -5205,7 +5205,7 @@ PAL_API PalResult PAL_CALL palCreateSemaphore( * @brief Destroy a semaphore. * * The graphics system must be initialized before this call. - * If the provided semaphore is invalid or nullptr, this function returns + * If the provided semaphore is invalid or `nullptr`, this function returns * silently. * * @param[in] semaphore Semaphore to destroy. @@ -5320,7 +5320,7 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( * @brief Destroy a command pool. * * The graphics system must be initialized before this call. - * If the provided command pool is invalid or nullptr, this function returns + * If the provided command pool is invalid or `nullptr`, this function returns * silently. * * Destroying a command pool frees all command buffers automatically. @@ -5379,7 +5379,7 @@ PAL_API PalResult PAL_CALL palAllocateCommandBuffer( * @brief Free an allocated command buffer. * * The graphics system must be initialized before this call. - * If the provided command buffer is invalid or nullptr, this function returns + * If the provided command buffer is invalid or `nullptr`, this function returns * silently. * * @param[in] cmdBuffer Command buffer to free. @@ -5416,7 +5416,7 @@ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); * * @param[in] queue Queue to execute the command buffer. * @param[in] info Pointer to a PalCommandBufferSubmitInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5496,7 +5496,7 @@ PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] state Pointer to a PalFragmentShadingRateState struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5610,7 +5610,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] info Pointer to a PalAccelerationStructureBuildInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5630,7 +5630,7 @@ PAL_API PalResult PAL_CALL palCmdBuildAccelerationStructure( * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] info Pointer to a PalRenderingInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5668,10 +5668,10 @@ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); * @param[in] dst Destination buffer. * @param[in] src Source buffer. * @param[in] copyInfo Pointer to a PalBufferCopyInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * Pointer to a PalImageCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5695,7 +5695,7 @@ PAL_API PalResult PAL_CALL palCmdCopyBuffer( * @param[in] dstImage Destination image. * @param[in] srcBuffer Source buffer. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5719,7 +5719,7 @@ PAL_API PalResult PAL_CALL palCmdCopyBufferToImage( * @param[in] dst Destination image. * @param[in] src Source image. * @param[in] copyInfo Pointer to a PalImageCopyInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5743,7 +5743,7 @@ PAL_API PalResult PAL_CALL palCmdCopyImage( * @param[in] dstBuffer Destination buffer. * @param[in] srcImage Source image. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6255,7 +6255,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be nullptr. + * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6315,7 +6315,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] raygenIndex Index of the raygen shader to execute. * @param[in] sbt The shader binding table to use. - * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be nullptr. + * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6538,7 +6538,7 @@ PAL_API PalResult PAL_CALL palCmdSetStencilOp( * * @param[in] device Device that creates the acceleration structure. * @param[in] info Pointer to a PalAccelerationStructureCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outAs Pointer to a PalAccelerationStructure to recieve the created acceleration * structure. * @@ -6562,7 +6562,7 @@ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( * @brief Destroy an acceleration structure. * * The graphics system must be initialized before this call. - * If the provided acceleration structure is invalid or nullptr, this function returns + * If the provided acceleration structure is invalid or `nullptr`, this function returns * silently. * * @param[in] as Acceleration structure to destroy. @@ -6580,14 +6580,14 @@ PAL_API void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* * * The graphics system must be initialized before this call. * PalAccelerationStructureBuildInfo::dst, PalAccelerationStructureBuildInfo::scratchBufferAddress - * and PalAccelerationStructureBuildInfo::src must be set to nullptr. + * and PalAccelerationStructureBuildInfo::src must be set to `nullptr`. * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * * @param[in] device Device to query. * @param[in] info Pointer to a PalAccelerationStructureBuildInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] size Pointer to a PalAccelerationStructureBuildSize to recieve the build size. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6619,7 +6619,7 @@ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( * * @param[in] device Device that creates the buffer. * @param[in] info Pointer to a PalBufferCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outBuffer Pointer to a PalBuffer to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6639,7 +6639,7 @@ PAL_API PalResult PAL_CALL palCreateBuffer( * @brief Destroy a buffer. * * The graphics system must be initialized before this call. - * If the provided buffer is invalid or nullptr, this function returns + * If the provided buffer is invalid or `nullptr`, this function returns * silently. * * @param[in] buffer buffer to destroy. @@ -6716,7 +6716,7 @@ PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( * @param[in] device Device to compute image copy staging buffer requirements with. * @param[in] imageFormat Destination image format. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outBufferRowLength Pointer to a uint32_t to recieve the required buffer row length. * @param[out] outBufferImageHeight Pointer to a uint32_t to recieve the required buffer imag * height. @@ -6771,7 +6771,7 @@ PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( * @param[out] srcData Pointer to the CPU visible memory with the data. * @param[in] imageFormat Destination image format. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6795,7 +6795,7 @@ PAL_API PalResult PAL_CALL palWriteToImageCopyStagingBuffer( * Get the requirements with palGetBufferMemoryRequirements(). * * @param[in] buffer Buffer to bind memory to. - * @param[in] memory Memory to bind. Must not be nullptr. + * @param[in] memory Memory to bind. Must not be `nullptr`. * @param[in] offset Starting point within the memory. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6887,7 +6887,7 @@ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); * * @param[in] device Device that creates the descriptor set layout. * @param[in] info Pointer to a PalDescriptorSetLayoutCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outLayout Pointer to a PalDescriptorSetLayout to recieve the created descriptor * set layout. * @@ -6908,7 +6908,7 @@ PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( * @brief Destroy a descriptor set layout. * * The graphics system must be initialized before this call. - * If the provided descriptor set layout is invalid or nullptr, this function returns + * If the provided descriptor set layout is invalid or `nullptr`, this function returns * silently. * * @param[in] layout Descriptor set layout to destroy. @@ -6928,7 +6928,7 @@ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layo * * @param[in] device Device that creates the descriptor pool. * @param[in] info Pointer to a PalDescriptorPoolCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outPool Pointer to a PalDescriptorPool to recieve the created descriptor pool. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6948,7 +6948,7 @@ PAL_API PalResult PAL_CALL palCreateDescriptorPool( * @brief Destroy a descriptor pool. * * The graphics system must be initialized before this call. - * If the provided descriptor pool is invalid or nullptr, this function returns + * If the provided descriptor pool is invalid or `nullptr`, this function returns * silently. * * @param[in] pool Descriptor pool to destroy. @@ -7038,7 +7038,7 @@ PAL_API PalResult PAL_CALL palUpdateDescriptorSet( * * @param[in] device Device that creates the pipeline layout. * @param[in] info Pointer to a PalPipelineLayoutCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outLayout Pointer to a PalPipelineLayout to recieve the created pipeline layout. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -7058,7 +7058,7 @@ PAL_API PalResult PAL_CALL palCreatePipelineLayout( * @brief Destroy a pipeline layout. * * The graphics system must be initialized before this call. - * If the provided pipeline layout is invalid or nullptr, this function returns + * If the provided pipeline layout is invalid or `nullptr`, this function returns * silently. * * @param[in] layout Pipeline layout to destroy. @@ -7078,7 +7078,7 @@ PAL_API void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout); * * @param[in] device Device that creates the graphics pipeline. * @param[in] info Pointer to a PalGraphicsPipelineCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -7101,7 +7101,7 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( * * @param[in] device Device that creates the compute pipeline. * @param[in] info Pointer to a PalComputePipelineCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -7129,7 +7129,7 @@ PAL_API PalResult PAL_CALL palCreateComputePipeline( * * @param[in] device Device that creates the ray tracing pipeline. * @param[in] info Pointer to a PalRayTracingPipelineCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -7151,7 +7151,7 @@ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( * @brief Destroy a pipeline. * * The graphics system must be initialized before this call. - * If the provided pipeline is invalid or nullptr, this function returns + * If the provided pipeline is invalid or `nullptr`, this function returns * silently. * * @param[in] pipeline Pipeline to destroy. @@ -7179,7 +7179,7 @@ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); * * @param[in] device Device that creates the shader binding table. * @param[in] info Pointer to a PalShaderBindingTableCreateInfo struct that specifies parameters. - * Must not be nullptr. + * Must not be `nullptr`. * @param[out] outSbt Pointer to a PalShaderBindingTable to recieve the created shader binding * table. * @@ -7202,7 +7202,7 @@ PAL_API PalResult PAL_CALL palCreateShaderBindingTable( * @brief Destroy a shader binding table. * * The graphics system must be initialized before this call. - * If the provided shader binding table is invalid or nullptr, this function returns + * If the provided shader binding table is invalid or `nullptr`, this function returns * silently. * * @param[in] sbt Shader binding table to destroy. @@ -7243,12 +7243,12 @@ PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( /** * @brief Build work group info(s) from work inputs specified in pixels, vertices etc. * - * Call this function first with PalWorkGroupInfo array set to nullptr to get the number of work + * Call this function first with PalWorkGroupInfo array set to `nullptr` to get the number of work * group infos. Allocate memory for the PalWorkGroupInfo array and passed in the count and the * allocated array. If the count of the array is less than the number of work group infos, PAL will * write upto that limit. * - * If the count is 0 and the PalWorkGroupInfo array is nullptr, the function fails + * If the count is 0 and the PalWorkGroupInfo array is `nullptr`, the function fails * and returns `PAL_FALSE`. * * This function works the maths for how many work groups to dispatch in each axis and how many diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index a6581580..1cb06154 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -181,8 +181,8 @@ typedef struct { * @since 1.0 */ typedef struct { - void* instance; /**< Must not be nullptr. (HINSTANCE on Win32 or wl_display on Wayland)*/ - void* window; /**< Must not be nullptr. (egl_wl_window on Wayland)*/ + void* instance; /**< Must not be `nullptr`. (HINSTANCE on Win32 or wl_display on Wayland)*/ + void* window; /**< Must not be `nullptr`. (egl_wl_window on Wayland)*/ } PalGLWindow; /** @@ -194,9 +194,9 @@ typedef struct { * @since 1.0 */ typedef struct { - const PalGLWindow* window; /**< Window to create context for. Must not be nullptr.*/ - const PalGLFBConfig* fbConfig; /**< The framebuffer config to use. Must not be nullptr.*/ - PalGLContext* shareContext; /**< Can be nullptr.*/ + const PalGLWindow* window; /**< Window to create context for. Must not be `nullptr`.*/ + const PalGLFBConfig* fbConfig; /**< The framebuffer config to use. Must not be `nullptr`.*/ + PalGLContext* shareContext; /**< Can be `nullptr`.*/ PalGLProfile profile; /**< (eg. `PAL_GL_PROFILE_CORE`).*/ PalGLContextReset reset; /**< (eg. `PAL_GL_CONTEXT_RESET_LOSE_CONTEXT`).*/ PalGLReleaseBehavior release; /**< (eg. `PAL_GL_RELEASE_BEHAVIOR_FLUSH`).*/ @@ -216,7 +216,7 @@ typedef struct { * The allocator will not not copied, therefore the pointer must remain valid * until the opengl system is shutdown. * - * `instance` must not be nullptr and will not be freed by the opengl system. It must be valid until + * `instance` must not be `nullptr` and will not be freed by the opengl system. It must be valid until * palShutdownGL() is called. * `Linux`: This is the Display associated with the connection. * `Windows`: This is the HINSTANCE of the process. @@ -224,8 +224,8 @@ typedef struct { * @param[in] api The api to use. (eg. `PAL_GL_API_OPENGL`). Call `palGetSupportedGLAPIs()` to check * if an api is supported on `instance`. * @param[in] instance The instance the opengl system will be tied to (eg. XDisplay). - * Must not be nullptr. - * @param[in] allocator Optional user-provided allocator. Set to nullptr to use + * Must not be `nullptr`. + * @param[in] allocator Optional user-provided allocator. Set to `nullptr` to use * default. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -260,7 +260,7 @@ PAL_API void PAL_CALL palShutdownGL(); * The opengl system must be initialized before this call. The returned * PalGLInfo pointer must not be freed. * - * @return A pointer to a PalGLInfo on success or nullptr on failure. + * @return A pointer to a PalGLInfo on success or `nullptr` on failure. * * Thread safety: Thread-safe. * @@ -273,7 +273,7 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); * * The opengl system must be initialized before this call. * - * Call this function first with PalGLFBConfig array set to nullptr to get the + * Call this function first with PalGLFBConfig array set to `nullptr` to get the * number of supported PalGLFBConfig. Allocate memory for the PalGLFBConfig * array and passed in the count and the allocated array. If the count of the * array is less than the number of supported PalGLFBConfigs, PAL will write @@ -303,14 +303,14 @@ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( * * The count must be the number of PalGLFBConfig in the * array of PalGLFBConfig. If the count is less than or equal to 0 or the - * desired PalGLFBConfig or the PalGLFBConfig array is nullptr, this function - * fails and returns nullptr. + * desired PalGLFBConfig or the PalGLFBConfig array is `nullptr`, this function + * fails and returns `nullptr`. * * @param[in] configs Pointer to the array of PalGLFBConfig. * @param[in] count Capacity of the PalGLFBConfig array. * @param[in] desired The desired PalGLFBConfig. * - * @return The closest PalGLFBConfig on success or nullptr on failure. + * @return The closest PalGLFBConfig on success or `nullptr` on failure. * * Thread safety: Thread safe. * @@ -335,9 +335,9 @@ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( * not the wl_surface. * * @param[in] info Pointer to a PalGLContextCreateInfo struct that specifies - * parameters. Must not be nullptr. + * parameters. Must not be `nullptr`. * @param[out] outContext Pointer to a PalGLContext to recieve the created - * context. Must not be nullptr. + * context. Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -356,7 +356,7 @@ PAL_API PalResult PAL_CALL palCreateGLContext( * * The opengl system must be initialized before this call. * - * If the provided context is invalid or nullptr, this function returns + * If the provided context is invalid or `nullptr`, this function returns * silently. The context must not be current in any thread before this call. * * @param[in] context Pointer to the context to destroy. @@ -400,7 +400,7 @@ PAL_API PalResult PAL_CALL palMakeContextCurrent( * * @param[in] name UTF-8 string for the function name. * - * @return the pointer to the function on success or nullptr on failure. + * @return the pointer to the function on success or `nullptr` on failure. * * Thread safety: Thread safe. * @@ -457,7 +457,7 @@ PAL_API PalResult PAL_CALL palSetSwapInterval(int32_t interval); * * @param[in] instance The instance (eg. HINSTANCE or XDisplay). * - * @return An array of bools or nullptr on failure. + * @return An array of bools or `nullptr` on failure. * * Thread safety: Must only be called from the main thread. * diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index 1debeeaa..89c5e605 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -155,7 +155,7 @@ PAL_API PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info); /** * @brief Get CPU information. * - * @param[in] allocator Optional user provided allocator. Set to nullptr to + * @param[in] allocator Optional user provided allocator. Set to `nullptr` to * use default. * @param[out] info Pointer to a PalCPUInfo to receive the CPU info. * diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index bce08ab7..49d94257 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -84,7 +84,7 @@ typedef uint32_t PalThreadPriority; * @typedef PalThreadFn * @brief Function pointer type used for thread entry function. * - * @param[in] arg Optional pointer to user data. Can be nullptr. + * @param[in] arg Optional pointer to user data. Can be `nullptr`. * * @return The return value of the thread as a pointer. * @@ -96,9 +96,9 @@ typedef void* (*PalThreadFn)(void* arg); * @typedef PaTlsDestructorFn * @brief Function pointer type used for TLS. * - * This is called when the TLS is destroyed and its value is not nullptr. + * This is called when the TLS is destroyed and its value is not `nullptr`. * - * @param[in] userData Optional pointer to user data. Can be nullptr. + * @param[in] userData Optional pointer to user data. Can be `nullptr`. * * @since 1.0 */ @@ -114,9 +114,9 @@ typedef void (*PaTlsDestructorFn)(void* userData); */ typedef struct { uint64_t stackSize; /**< Set to 0 to use default*/ - const PalAllocator* allocator; /**< Set to nullptr to use default.*/ - PalThreadFn entry; /**< Thread entry function. Must not be nullptr*/ - void* arg; /**< Optional user-provided data. Can be nullptr.*/ + const PalAllocator* allocator; /**< Set to `nullptr` to use default.*/ + PalThreadFn entry; /**< Thread entry function. Must not be `nullptr`*/ + void* arg; /**< Optional user-provided data. Can be `nullptr`.*/ } PalThreadCreateInfo; /** @@ -131,9 +131,9 @@ typedef struct { * until the entry function has finished executing or its detached. * * @param[in] info Pointer to a PalThreadCreateInfo struct that specifies - * parameters. Must not be nullptr. + * parameters. Must not be `nullptr`. * @param[out] outThread Pointer to a PalThread to recieve the created - * thread. Must not be nullptr. + * thread. Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -174,7 +174,7 @@ PAL_API PalResult PAL_CALL palJoinThread( * * Must be called when the thread is done executing. * After this call, the thread cannot be attached or used anymore. - * If the thread is invalid or nullptr, this function returns silently. + * If the thread is invalid or `nullptr`, this function returns silently. * * This must not be called on a thread that has been attached. * @@ -210,7 +210,7 @@ PAL_API void PAL_CALL palYield(); /** * @brief Get the current executing thread. * - * @return The current thread on success or nullptr on failure. + * @return The current thread on success or `nullptr` on failure. * * Thread safety: Thread safe. * @@ -266,7 +266,7 @@ PAL_API uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread); * @brief Get the name of the provided thread. * * `PAL_THREAD_FEATURE_NAME` must be supported. - * fails. Set the buffer to nullptr to get the size of the thread name in bytes. + * fails. Set the buffer to `nullptr` to get the size of the thread name in bytes. * * If the size of the provided buffer is less than the actual size of thread * name, PAL will write upto that limit. @@ -276,7 +276,7 @@ PAL_API uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread); * @param[in] bufferSize Size of the provided buffer in bytes. * @param[out] outSize The actual size of the thread name in bytes. * @param[out] outBuffer Pointer to a user provided buffer to recieve the name. - * Can be nullptr. + * Can be `nullptr`. * * Thread safety: Thread safe. * @@ -379,7 +379,7 @@ PAL_API PalResult PAL_CALL palSetThreadName( * the TLS has a valid value. * * @param[in] destructor Pointer to the TLS destructor function. Can be - * nullptr. + * `nullptr`. * * @return The TLS on success or 0 on failure. * @@ -407,7 +407,7 @@ PAL_API void PAL_CALL palDestroyTLS(PalTLSId id); * * @param[in] id The TLS to query value. * - * @return the value on success or nullptr on failure. + * @return the value on success or `nullptr` on failure. * * Thread safety: Thread safe. * @@ -434,10 +434,10 @@ PAL_API void PAL_CALL palSetTLS( /** * @brief Create a mutex. * - * @param[in] allocator Optional user-provided allocator. Set to nullptr to use + * @param[in] allocator Optional user-provided allocator. Set to `nullptr` to use * default. * @param[out] outMutex Pointer to a PalMutex to recieve the created mutex. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -497,7 +497,7 @@ PAL_API void PAL_CALL palUnlockMutex(PalMutex* mutex); /** * @brief Create a condition variable. * - * @param[in] allocator Optional user-provided allocator. Set to nullptr to use + * @param[in] allocator Optional user-provided allocator. Set to `nullptr` to use * default. * @param[out] outCondVar Pointer to a PalCondVar to recieve the created * condition variable. diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 1b7e750b..600b594d 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -565,9 +565,9 @@ typedef struct { */ typedef struct { const char* title; /**< Title in UTF-8 encoding.*/ - PalMonitor* monitor; /**< Set to nullptr to use primary monitor.*/ - const char* appName; /**< If nullptr, `PAL` will be used.*/ - const char* instanceName; /**< If nullptr, `title` will be used.*/ + PalMonitor* monitor; /**< Set to `nullptr` to use primary monitor.*/ + const char* appName; /**< If `nullptr`, `PAL` will be used.*/ + const char* instanceName; /**< If `nullptr`, `title` will be used.*/ PalFBConfigBackend fbConfigBackend; /**< Will be used if `fbConfigIndex` is not 0.*/ int32_t fbConfigIndex; /**< Set to 0 to create the window with no pixel format.*/ uint32_t width; /**< Width in pixels.*/ @@ -588,16 +588,16 @@ typedef struct { * until the video system is shutdown. The event driver must be valid to recieve * video events. * - * If `preferredInstance` is nullptr, the video system creates one and control its lifetime. + * If `preferredInstance` is `nullptr`, the video system creates one and control its lifetime. * The provided instance will not be freed by the video system. * `Linux`: This is the Display associated with the connection. * `Windows`: This is the HINSTANCE of the process. * - * @param[in] allocator Optional user-provided allocator. Set to nullptr to use + * @param[in] allocator Optional user-provided allocator. Set to `nullptr` to use * default. * @param[in] eventDriver Optional user-provided event driver. This is needed to - * push video events. Set to nullptr to use default. - * @param[in] preferredInstance User-provided instance (eg. HINSTANCE). Can be nullptr. + * push video events. Set to `nullptr` to use default. + * @param[in] preferredInstance User-provided instance (eg. HINSTANCE). Can be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -658,7 +658,7 @@ PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures(); * * The video system must be initialized before this call. * - * Call this function first with PalMonitor array set to nullptr to get the + * Call this function first with PalMonitor array set to `nullptr` to get the * number of connected monitors. Allocate memory for the PalMonitor * array and passed in the count and the allocated array. If the count of the * array is less than the number of connected monitors, PAL will write upto that @@ -734,7 +734,7 @@ PAL_API PalResult PAL_CALL palGetMonitorInfo( * * The video system must be initialized before this call. * - * Call this function first with PalMonitorMode array set to nullptr to get the + * Call this function first with PalMonitorMode array set to `nullptr` to get the * number of supported monitor display modes. Allocate memory for the * PalMonitorMode array and passed in the count and the allocated array. If the * count of the array is less than the number of supported monitor display @@ -867,9 +867,9 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * one requested. * * @param[in] info Pointer to a PalWindowCreateInfo struct that specifies - * parameters. Must not be nullptr. + * parameters. Must not be `nullptr`. * @param[out] outWindow Pointer to a PalWindow to recieve the created - * window. Must not be nullptr. + * window. Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -895,7 +895,7 @@ PAL_API PalResult PAL_CALL palCreateWindow( * @brief Destroy the provided window. * * The video system must be initialized before this call. - * If the provided window is invalid or nullptr, this function returns + * If the provided window is invalid or `nullptr`, this function returns * silently. This only destroys windows created by PAL. * * @param[in] window Pointer to the window to destroy. @@ -1080,7 +1080,7 @@ PAL_API PalResult PAL_CALL palGetWindowMonitor( * The video system must be initialized before this call. * `PAL_VIDEO_FEATURE_WINDOW_GET_TITLE` must be supported. * - * Set the buffer to nullptr to get the size of the window name in bytes. + * Set the buffer to `nullptr` to get the size of the window name in bytes. * If the size of the provided buffer is less than the actual size of window * title, PAL will write upto that limit. * @@ -1088,7 +1088,7 @@ PAL_API PalResult PAL_CALL palGetWindowMonitor( * @param[in] bufferSize Size of the provided buffer in bytes. * @param[out] outSize The actual size of the window title in bytes. * @param[out] outBuffer Pointer to a user provided buffer to recieve the title. - * Can be nullptr. + * Can be `nullptr`. * * Thread safety: Must only be called from the main thread. * @@ -1108,8 +1108,8 @@ PAL_API PalResult PAL_CALL palGetWindowTitle( * `PAL_VIDEO_FEATURE_WINDOW_GET_POS` must be supported. * * @param[in] window Pointer to the window. - * @param[out] x Pointer to recieve the window x position. Can be nullptr. - * @param[out] y Pointer to recieve the window y position. Can be nullptr. + * @param[out] x Pointer to recieve the window x position. Can be `nullptr`. + * @param[out] y Pointer to recieve the window y position. Can be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1131,8 +1131,8 @@ PAL_API PalResult PAL_CALL palGetWindowPos( * `PAL_VIDEO_FEATURE_WINDOW_GET_SIZE` must be supported. * * @param[in] window Pointer to the window. - * @param[out] width Pointer to recieve the width. Can be nullptr. - * @param[out] height Pointer to recieve the height. Can be nullptr. + * @param[out] width Pointer to recieve the width. Can be `nullptr`. + * @param[out] height Pointer to recieve the height. Can be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1177,7 +1177,7 @@ PAL_API PalResult PAL_CALL palGetWindowState( * palUpdateVideo() is called. The array must be index with PalKeycodes and * not exceed `PAL_KEYCODE_COUNT`. * - * @return A pointer to the keycodes array on success or nullptr on failure. + * @return A pointer to the keycodes array on success or `nullptr` on failure. * * Thread safety: Thread-safe. * @@ -1195,7 +1195,7 @@ PAL_API const PalBool* PAL_CALL palGetKeycodeState(); * palUpdateVideo() is called. The array must be index with PalScancodes and * not exceed PAL_SCANCODE_COUNT. * - * @return A pointer to the scancodes array on success or nullptr on failure. + * @return A pointer to the scancodes array on success or `nullptr` on failure. * * Thread safety: Thread-safe. * @@ -1212,7 +1212,7 @@ PAL_API const PalBool* PAL_CALL palGetScancodeState(); * palUpdateVideo() is called. The array must be index with PalMouseButton and * not exceed `PAL_MOUSE_BUTTON_COUNT`. * - * @return A pointer to the mouse button array on success or nullptr on failure. + * @return A pointer to the mouse button array on success or `nullptr` on failure. * * @Thread safety: Thread-safe. * @@ -1227,9 +1227,9 @@ PAL_API const PalBool* PAL_CALL palGetMouseState(); * The relative movement will be updated when palUpdateVideo() is called. * * @param[in] dx Pointer to recieve the mouse relative movement x. Can be - * nullptr. + * `nullptr`. * @param[in] dy Pointer to recieve the mouse relative movement y. Can be - * nullptr. + * `nullptr`. * * Thread safety: Thread-safe if `dx` and `dy` are thread * local. @@ -1246,8 +1246,8 @@ PAL_API void PAL_CALL palGetMouseDelta( * The video system must be initialized before this call. * The wheel delta will be updated when palUpdateVideo() is called. * - * @param[in] dx Pointer to recieve the mouse wheel delta x. Can be nullptr. - * @param[in] dy Pointer to recieve the mouse wheel delta y. Can be nullptr. + * @param[in] dx Pointer to recieve the mouse wheel delta x. Can be `nullptr`. + * @param[in] dy Pointer to recieve the mouse wheel delta y. Can be `nullptr`. * * Thread safety: Thread-safe if `dx` and `dy` are thread * local. @@ -1280,7 +1280,7 @@ PAL_API PalBool PAL_CALL palIsWindowVisible(PalWindow* window); * The video system must be initialized before this call. * `PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS` must be supported. * - * @return The current input-focused window on success or nullptr on + * @return The current input-focused window on success or `nullptr` on * failure. * * Thread safety: Must only be called from the main thread. @@ -1448,9 +1448,9 @@ PAL_API PalResult PAL_CALL palSetFocusWindow(PalWindow* window); * `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported. * * @param[in] info Pointer to a PalIconCreateInfo struct that specifies - * parameters. Must not be nullptr. + * parameters. Must not be `nullptr`. * @param[out] outIcon Pointer to a PalIcon to recieve the created - * icon. Must not be nullptr. + * icon. Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1469,7 +1469,7 @@ PAL_API PalResult PAL_CALL palCreateIcon( * * The video system must be initialized before this call. * - * If the provided icon is invalid or nullptr, this function returns + * If the provided icon is invalid or `nullptr`, this function returns * silently. * * @param[in] icon Pointer to the icon to destroy. @@ -1488,7 +1488,7 @@ PAL_API void PAL_CALL palDestroyIcon(PalIcon* icon); * `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported. * * @param[in] window Pointer to the window. - * @param[in] icon Pointer to the icon. Set to nullptr to revert. + * @param[in] icon Pointer to the icon. Set to `nullptr` to revert. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1507,9 +1507,9 @@ PAL_API PalResult PAL_CALL palSetWindowIcon( * The video system must be initialized before this call. * * @param[in] info Pointer to a PalCursorCreateInfo struct that specifies - * parameters. Must not be nullptr. + * parameters. Must not be `nullptr`. * @param[out] outCursor Pointer to a PalCursor to recieve the created - * cursor. Must not be nullptr. + * cursor. Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1528,9 +1528,9 @@ PAL_API PalResult PAL_CALL palCreateCursor( * * The video system must be initialized before this call. * - * @param[in] type The system cursor type to create. Must not be nullptr. + * @param[in] type The system cursor type to create. Must not be `nullptr`. * @param[out] outCursor Pointer to a PalCursor to recieve the created - * cursor. Must not be nullptr. + * cursor. Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1549,7 +1549,7 @@ PAL_API PalResult PAL_CALL palCreateCursorFrom( * * The video system must be initialized before this call. * - * If the provided icon is invalid or nullptr, this function returns + * If the provided icon is invalid or `nullptr`, this function returns * silently. * * @param[in] cursor Pointer to the cursor to destroy. @@ -1611,9 +1611,9 @@ PAL_API PalResult PAL_CALL palClipCursor( * * @param[in] window Pointer to the window. * @param[out] x Pointer to recieve the x position. Can be - * nullptr. + * `nullptr`. * @param[out] y Pointer to recieve the y position. Can be - * nullptr. + * `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1656,7 +1656,7 @@ PAL_API PalResult PAL_CALL palSetCursorPos( * The video system must be initialized before this call. * * @param[in] window Pointer to the window. - * @param[in] cursor Pointer to the cursor. Set to nullptr to revert. + * @param[in] cursor Pointer to the cursor. Set to `nullptr` to revert. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1681,7 +1681,7 @@ PAL_API PalResult PAL_CALL palSetWindowCursor( * On Windows: This is the HINSTANCE of the process. * - * @return The instance or display on success or nullptr on failure. + * @return The instance or display on success or `nullptr` on failure. * * Thread safety: Thread safe. * @@ -1715,7 +1715,7 @@ PAL_API void* PAL_CALL palGetInstance(); * * @param[in] windowHandle Pointer to the foreign or native window. * @param[out] outWindow Pointer to a PalWindow to recieve the attached window. - * Must not be nullptr. + * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1749,9 +1749,9 @@ PAL_API PalResult PAL_CALL palAttachWindow( * Give back the PalWindow returned at palAttachWindow() * and get back your native window. * - * @param[in] window Pointer to the PalWindow to detach. Must not be nullptr. + * @param[in] window Pointer to the PalWindow to detach. Must not be `nullptr`. * @param[out] outWindowHandle Pointer to recieve the native window. Can be - * nullptr. + * `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. diff --git a/tests/tests_main.c b/tests/tests_main.c index 5d4e2f46..a52597dd 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -8,7 +8,7 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - // registerTest(loggerTest, "Logger Test"); + registerTest(loggerTest, "Logger Test"); // registerTest(timeTest, "Time Test"); // event From 24dfb0544225c53462ab5e6a29012f1c95158e22 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 28 Jun 2026 15:53:21 +0000 Subject: [PATCH 301/372] update event system and tests --- pal.lua | 4 +-- src/event/pal_default_queue.c | 4 +-- src/event/pal_event.c | 57 ++++----------------------------- tests/event/event_test.c | 8 ++--- tests/event/user_event_test.c | 8 ++--- tests/tests.lua | 4 +-- tests/tests_main.c | 4 +-- tools/abi_dump/event_abi_dump.c | 16 ++++----- 8 files changed, 31 insertions(+), 74 deletions(-) diff --git a/pal.lua b/pal.lua index daf48814..cff4e389 100644 --- a/pal.lua +++ b/pal.lua @@ -25,8 +25,8 @@ project "PAL" "src/core/pal_version.c", -- event - -- "src/event/pal_default_queue.c", - -- "src/event/pal_event.c" + "src/event/pal_default_queue.c", + "src/event/pal_event.c" } filter {"system:windows", "configurations:*"} diff --git a/src/event/pal_default_queue.c b/src/event/pal_default_queue.c index 18a64022..ebff10b9 100644 --- a/src/event/pal_default_queue.c +++ b/src/event/pal_default_queue.c @@ -8,8 +8,8 @@ #include "pal_default_queue.h" typedef struct { - uint8_t head; - uint8_t tail; + uint32_t head; + uint32_t tail; PalEvent data[MAX_EVENTS]; } QueueData; diff --git a/src/event/pal_event.c b/src/event/pal_event.c index 84afd588..f3ed774a 100644 --- a/src/event/pal_event.c +++ b/src/event/pal_event.c @@ -6,39 +6,8 @@ */ #include "pal_default_queue.h" -#include "pal_shared.h" #include -#ifdef _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN - -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -// set unicode -#ifndef UNICODE -#define UNICODE -#endif // UNICODE - -#include -#define PLATFORM_SOURCE PAL_RESULT_SOURCE_WINDOWS -#elif defined(__linux__) -#include -#define PLATFORM_SOURCE PAL_RESULT_SOURCE_LINUX -#endif // _WIN32 - -static inline uint32_t getLastErrorCode() -{ -#ifdef _WIN32 - return (uint32_t)GetLastError(); -#elif defined(__linux__) - return (uint32_t)errno; -#endif // _WIN32 -} - struct PalEventDriver { PalBool freeQueue; PalEventQueue* queue; @@ -53,28 +22,19 @@ PalResult PAL_CALL palCreateEventDriver( PalEventDriver** outEventDriver) { if (!info || !outEventDriver) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PLATFORM_SOURCE, - getLastErrorCode()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (info->allocator) { if (!info->allocator->allocate && !info->allocator->free) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PLATFORM_SOURCE, - getLastErrorCode()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } } PalEventDriver* driver = nullptr; driver = palAllocate(info->allocator, sizeof(PalEventDriver), 0); if (!driver) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PLATFORM_SOURCE, - getLastErrorCode()); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } memset(driver, 0, sizeof(PalEventDriver)); @@ -92,10 +52,7 @@ PalResult PAL_CALL palCreateEventDriver( PalEventQueue* queue = createDefaultEventQueue(info->allocator); if (!queue) { palFree(info->allocator, driver); - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PLATFORM_SOURCE, - getLastErrorCode()); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } driver->queue = queue; @@ -136,7 +93,7 @@ PalDispatchMode PAL_CALL palGetEventDispatchMode( PalEventType type) { if (!eventDriver) { - return PAL_DISPATCH_NONE; + return PAL_DISPATCH_MODE_NONE; } return eventDriver->modes[type]; } @@ -151,14 +108,14 @@ void PAL_CALL palPushEvent( // get the event mode PalDispatchMode mode = eventDriver->modes[event->type]; - if (mode == PAL_DISPATCH_CALLBACK) { + if (mode == PAL_DISPATCH_MODE_CALLBACK) { if (eventDriver->callback) { eventDriver->callback(eventDriver->userData, event); } return; // we have dispatched the event } - if (mode == PAL_DISPATCH_POLL) { + if (mode == PAL_DISPATCH_MODE_POLL) { eventDriver->queue->push(eventDriver->queue, event); } } diff --git a/tests/event/event_test.c b/tests/event/event_test.c index 75b82597..05b85727 100644 --- a/tests/event/event_test.c +++ b/tests/event/event_test.c @@ -42,12 +42,12 @@ static inline PalBool eventDispatchTest(PalBool poll) } // set dispatch mode - PalDispatchMode mode = PAL_DISPATCH_CALLBACK; + PalDispatchMode mode = PAL_DISPATCH_MODE_CALLBACK; if (poll) { - mode = PAL_DISPATCH_POLL; + mode = PAL_DISPATCH_MODE_POLL; } - for (uint32_t e = 0; e < PAL_EVENT_MAX; e++) { + for (uint32_t e = 0; e < PAL_EVENT_TYPE_COUNT; e++) { palSetEventDispatchMode(driver, e, mode); } @@ -55,7 +55,7 @@ static inline PalBool eventDispatchTest(PalBool poll) while (counter < MAX_EVENTS) { // push all types of event up to max for (int32_t i = 0; i < MAX_EVENTS; i++) { - PalEventType type = i % PAL_EVENT_MAX; + PalEventType type = i % PAL_EVENT_TYPE_COUNT; PalEvent event = {0}; event.type = type; palPushEvent(driver, &event); diff --git a/tests/event/user_event_test.c b/tests/event/user_event_test.c index c03f80bd..fcd61c1e 100644 --- a/tests/event/user_event_test.c +++ b/tests/event/user_event_test.c @@ -38,7 +38,7 @@ PalBool userEventTest() return PAL_FALSE; } - palSetEventDispatchMode(eventDriver, PAL_EVENT_USER, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_USER, PAL_DISPATCH_MODE_POLL); // create and set the frequency and start time for time related calculations MyTimer timer; @@ -53,7 +53,7 @@ PalBool userEventTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_USER: { + case PAL_EVENT_TYPE_USER: { // a user event. USe another switch to check which event // using the user Id switch (event.userId) { @@ -84,7 +84,7 @@ PalBool userEventTest() if (timePassed > 5.0) { PalEvent event = {0}; event.userId = USER_PRINT_EVENT_ID; - event.type = PAL_EVENT_USER; + event.type = PAL_EVENT_TYPE_USER; palPushEvent(eventDriver, &event); } @@ -92,7 +92,7 @@ PalBool userEventTest() if (timePassed > 10.0) { PalEvent event = {0}; event.userId = USER_CLOSE_EVENT_ID; - event.type = PAL_EVENT_USER; + event.type = PAL_EVENT_TYPE_USER; palPushEvent(eventDriver, &event); } } diff --git a/tests/tests.lua b/tests/tests.lua index f065d7ea..ca867607 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -14,8 +14,8 @@ project "tests" "core/time_test.c", -- event - -- "event/user_event_test.c", - -- "event/event_test.c" + "event/user_event_test.c", + "event/event_test.c" } if (PAL_BUILD_SYSTEM_MODULE) then diff --git a/tests/tests_main.c b/tests/tests_main.c index a52597dd..e8cb42b2 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -8,12 +8,12 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - registerTest(loggerTest, "Logger Test"); + // registerTest(loggerTest, "Logger Test"); // registerTest(timeTest, "Time Test"); // event // registerTest(eventTest, "Event test"); - // registerTest(userEventTest, "User Event Test"); + registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE == 1 // registerTest(platformTest, "Platform Test"); diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index b7ec75f0..534bf2c5 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -10,19 +10,19 @@ static void eventDump(PalBool verbose) { - uint32_t xSize = 32; + uint32_t xSize = 24; uint32_t xAlign = 8; uint32_t xOffset1 = 0; uint32_t xOffset2 = 8; uint32_t xOffset3 = 16; - uint32_t xOffset4 = 24; + uint32_t xOffset4 = 20; uint32_t xPadding = 0; uint32_t ySize = sizeof(PalEvent); uint32_t yAlign = PAL_ALIGNOF(PalEvent); - uint32_t yOffset1 = offsetof(PalEvent, userId); - uint32_t yOffset2 = offsetof(PalEvent, data); - uint32_t yOffset3 = offsetof(PalEvent, data2); + uint32_t yOffset1 = offsetof(PalEvent, data); + uint32_t yOffset2 = offsetof(PalEvent, data2); + uint32_t yOffset3 = offsetof(PalEvent, userId); uint32_t yOffset4 = offsetof(PalEvent, type); uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; @@ -48,9 +48,9 @@ static void eventDump(PalBool verbose) palLog(nullptr, "size %u %u", xSize, ySize); palLog(nullptr, "align %u %u", xAlign, yAlign); palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "userId @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "data @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "data2 @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "data @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "data2 @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "userId @ %u %u", xOffset3, yOffset3); palLog(nullptr, "type @ %u %u", xOffset4, yOffset4); palLog(nullptr, "==========================================="); } From 6f0ff030ba7a5707441aecd48c84e938b377f134 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 28 Jun 2026 16:03:30 +0000 Subject: [PATCH 302/372] update system (cpu and platform) and tests --- pal_config.lua | 2 +- src/system/linux/pal_cpu_linux.c | 21 ++++----------------- src/system/linux/pal_platform_linux.c | 24 +++++++----------------- tests/system/platform_test.c | 16 ++++++++-------- tests/tests_main.c | 6 +++--- 5 files changed, 23 insertions(+), 46 deletions(-) diff --git a/pal_config.lua b/pal_config.lua index 78d521da..095be764 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -9,7 +9,7 @@ PAL_BUILD_TEST_APPLICATION = true PAL_BUILD_ABI_DUMP = true -- build system module -PAL_BUILD_SYSTEM_MODULE = false +PAL_BUILD_SYSTEM_MODULE = true -- build thread module PAL_BUILD_THREAD_MODULE = false diff --git a/src/system/linux/pal_cpu_linux.c b/src/system/linux/pal_cpu_linux.c index 87857477..7dcb0451 100644 --- a/src/system/linux/pal_cpu_linux.c +++ b/src/system/linux/pal_cpu_linux.c @@ -6,7 +6,6 @@ #ifdef __linux__ #define _POSIX_C_SOURCE 200112L -#include "pal_shared.h" #include "pal/pal_system.h" #include #include @@ -40,26 +39,17 @@ PalResult PAL_CALL palGetCPUInfo( PalCPUInfo* info) { if (!info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } // check invalid allocator if (allocator && (!allocator->allocate || !allocator->free)) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } FILE* file = fopen("/proc/cpuinfo", "r"); if (!file) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } char line[1024]; @@ -138,10 +128,7 @@ PalResult PAL_CALL palGetCPUInfo( // get architecture struct utsname arch; if (uname(&arch) != 0) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } if (strcmp(arch.machine, "x86_64") == 0) { diff --git a/src/system/linux/pal_platform_linux.c b/src/system/linux/pal_platform_linux.c index 070ff79e..28dd1388 100644 --- a/src/system/linux/pal_platform_linux.c +++ b/src/system/linux/pal_platform_linux.c @@ -6,7 +6,6 @@ #ifdef __linux__ #define _POSIX_C_SOURCE 200112L -#include "pal_shared.h" #include "pal/pal_system.h" #include #include @@ -17,31 +16,25 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) { if (!info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } - info->type = PAL_PLATFORM_LINUX; + info->type = PAL_PLATFORM_TYPE_LINUX; const char* session = getenv("XDG_SESSION_TYPE"); if (session) { if (strcmp(session, "wayland") == 0) { - info->apiType = PAL_PLATFORM_API_WAYLAND; + info->apiType = PAL_PLATFORM_API_TYPE_WAYLAND; } else { - info->apiType = PAL_PLATFORM_API_X11; + info->apiType = PAL_PLATFORM_API_TYPE_X11; } } else { // default - info->apiType = PAL_PLATFORM_API_X11; + info->apiType = PAL_PLATFORM_API_TYPE_X11; } FILE* file = fopen("/etc/os-release", "r"); if (!file) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } char line[256]; @@ -69,10 +62,7 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) struct statvfs stats; if (statvfs("/", &stats) != 0) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } uint64_t size = (stats.f_blocks * stats.f_frsize) / (1024 * 1024 * 1024); diff --git a/tests/system/platform_test.c b/tests/system/platform_test.c index f964e4f6..05f918b5 100644 --- a/tests/system/platform_test.c +++ b/tests/system/platform_test.c @@ -5,19 +5,19 @@ static inline const char* platformToString(PalPlatformType type) { switch (type) { - case PAL_PLATFORM_WINDOWS: + case PAL_PLATFORM_TYPE_WINDOWS: return "Windows"; - case PAL_PLATFORM_LINUX: + case PAL_PLATFORM_TYPE_LINUX: return "Linux"; - case PAL_PLATFORM_MACOS: + case PAL_PLATFORM_TYPE_MACOS: return "MacOs"; - case PAL_PLATFORM_ANDROID: + case PAL_PLATFORM_TYPE_ANDROID: return "Android"; - case PAL_PLATFORM_IOS: + case PAL_PLATFORM_TYPE_IOS: return "Ios"; } return nullptr; @@ -26,13 +26,13 @@ static inline const char* platformToString(PalPlatformType type) static inline const char* platformApiToString(PalPlatformApiType type) { switch (type) { - case PAL_PLATFORM_API_WIN32: + case PAL_PLATFORM_API_TYPE_WIN32: return "Win32"; - case PAL_PLATFORM_API_X11: + case PAL_PLATFORM_API_TYPE_X11: return "X11"; - case PAL_PLATFORM_API_WAYLAND: + case PAL_PLATFORM_API_TYPE_WAYLAND: return "Wayland"; } return nullptr; diff --git a/tests/tests_main.c b/tests/tests_main.c index e8cb42b2..aa8e7350 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -13,11 +13,11 @@ int main(int argc, char** argv) // event // registerTest(eventTest, "Event test"); - registerTest(userEventTest, "User Event Test"); + //registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE == 1 - // registerTest(platformTest, "Platform Test"); - // registerTest(cpuTest, "CPU Test"); + registerTest(platformTest, "Platform Test"); + registerTest(cpuTest, "CPU Test"); #endif // PAL_HAS_SYSTEM_MODULE #if PAL_HAS_THREAD_MODULE == 1 From 2cb958a096124d20b6883255969e2b8c99824e25 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 28 Jun 2026 16:41:45 +0000 Subject: [PATCH 303/372] update thread system and tests --- pal.lua | 8 +- pal_config.lua | 4 +- .../pal_condvar_posix.c} | 49 +++------- .../pal_mutex_posix.c} | 24 ++--- .../pal_thread_posix.c} | 98 ++++++++----------- .../pal_thread_posix.h} | 6 +- .../pal_tls_linux.c => posix/pal_tls_posix.c} | 6 +- tests/tests_main.c | 2 +- 8 files changed, 77 insertions(+), 120 deletions(-) rename src/thread/{linux/pal_condvar_linux.c => posix/pal_condvar_posix.c} (62%) rename src/thread/{linux/pal_mutex_linux.c => posix/pal_mutex_posix.c} (66%) rename src/thread/{linux/pal_thread_linux.c => posix/pal_thread_posix.c} (73%) rename src/thread/{linux/pal_thread_linux.h => posix/pal_thread_posix.h} (88%) rename src/thread/{linux/pal_tls_linux.c => posix/pal_tls_posix.c} (91%) diff --git a/pal.lua b/pal.lua index cff4e389..24277730 100644 --- a/pal.lua +++ b/pal.lua @@ -74,10 +74,10 @@ project "PAL" filter {"system:linux", "configurations:*"} files { - "src/thread/linux/pal_condvar_linux.c", - "src/thread/linux/pal_mutex_linux.c", - "src/thread/linux/pal_tls_linux.c", - "src/thread/linux/pal_thread_linux.c" + "src/thread/posix/pal_condvar_posix.c", + "src/thread/posix/pal_mutex_posix.c", + "src/thread/posix/pal_tls_posix.c", + "src/thread/posix/pal_thread_posix.c" } filter {} diff --git a/pal_config.lua b/pal_config.lua index 095be764..3ab92dff 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -9,10 +9,10 @@ PAL_BUILD_TEST_APPLICATION = true PAL_BUILD_ABI_DUMP = true -- build system module -PAL_BUILD_SYSTEM_MODULE = true +PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD_MODULE = false +PAL_BUILD_THREAD_MODULE = true -- build video module PAL_BUILD_VIDEO_MODULE = false diff --git a/src/thread/linux/pal_condvar_linux.c b/src/thread/posix/pal_condvar_posix.c similarity index 62% rename from src/thread/linux/pal_condvar_linux.c rename to src/thread/posix/pal_condvar_posix.c index 1066dcfa..589dbd95 100644 --- a/src/thread/linux/pal_condvar_linux.c +++ b/src/thread/posix/pal_condvar_posix.c @@ -5,36 +5,28 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ -#include "pal_thread_linux.h" -#include "pal_shared.h" +#include "pal_posix.h" + +#if _PAL_ON_POSIX +#include "pal_thread_posix.h" PalResult PAL_CALL palCreateCondVar( const PalAllocator* allocator, PalCondVar** outCondVar) { if (!outCondVar) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (allocator) { if (!allocator->allocate && !allocator->free) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } } PalCondVar* condVar = palAllocate(allocator, sizeof(PalCondVar), 0); if (!condVar) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } pthread_cond_init(&condVar->handle, nullptr); @@ -56,10 +48,7 @@ PalResult PAL_CALL palWaitCondVar( PalMutex* mutex) { if (!condVar || !mutex) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } int ret = pthread_cond_wait(&condVar->handle, &mutex->handle); @@ -67,16 +56,10 @@ PalResult PAL_CALL palWaitCondVar( return PAL_RESULT_SUCCESS; } else if (ret == ETIMEDOUT) { - return palMakeResult( - PAL_RESULT_TIMEOUT, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_TIMEOUT, PAL_RESULT_SOURCE_POSIX, errno); } else { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } } @@ -86,10 +69,7 @@ PalResult PAL_CALL palWaitCondVarTimeout( uint64_t milliseconds) { if (!condVar || !mutex) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } struct timespec ts; @@ -103,10 +83,7 @@ PalResult PAL_CALL palWaitCondVarTimeout( } if (pthread_cond_timedwait(&condVar->handle, &mutex->handle, &ts) != 0) { - return palMakeResult( - PAL_RESULT_TIMEOUT, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_TIMEOUT, PAL_RESULT_SOURCE_POSIX, errno); } return PAL_RESULT_SUCCESS; @@ -126,4 +103,4 @@ void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) } } -#endif // __linux__ \ No newline at end of file +#endif // _PAL_ON_POSIX \ No newline at end of file diff --git a/src/thread/linux/pal_mutex_linux.c b/src/thread/posix/pal_mutex_posix.c similarity index 66% rename from src/thread/linux/pal_mutex_linux.c rename to src/thread/posix/pal_mutex_posix.c index 6328102c..b301079a 100644 --- a/src/thread/linux/pal_mutex_linux.c +++ b/src/thread/posix/pal_mutex_posix.c @@ -5,36 +5,28 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ -#include "pal_thread_linux.h" -#include "pal_shared.h" +#include "pal_posix.h" + +#if _PAL_ON_POSIX +#include "pal_thread_posix.h" PalResult PAL_CALL palCreateMutex( const PalAllocator* allocator, PalMutex** outMutex) { if (!outMutex) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (allocator) { if (!allocator->allocate && !allocator->free) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } } PalMutex* mutex = palAllocate(allocator, sizeof(PalMutex), 0); if (!mutex) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } pthread_mutex_init(&mutex->handle, nullptr); @@ -65,4 +57,4 @@ void PAL_CALL palUnlockMutex(PalMutex* mutex) } } -#endif // __linux__ \ No newline at end of file +#endif // _PAL_ON_POSIX \ No newline at end of file diff --git a/src/thread/linux/pal_thread_linux.c b/src/thread/posix/pal_thread_posix.c similarity index 73% rename from src/thread/linux/pal_thread_linux.c rename to src/thread/posix/pal_thread_posix.c index e500d354..9951f96e 100644 --- a/src/thread/linux/pal_thread_linux.c +++ b/src/thread/posix/pal_thread_posix.c @@ -5,10 +5,13 @@ Licensed under the Zlib license. See LICENSE file in root. */ +#include "pal_posix.h" #ifdef __linux__ #define _GNU_SOURCE -#include "pal_thread_linux.h" -#include "pal_shared.h" +#endif // __linux__ + +#if _PAL_ON_POSIX +#include "pal_thread_posix.h" #include #include #include @@ -21,28 +24,19 @@ PalResult PAL_CALL palCreateThread( PalThread** outThread) { if (!info || !outThread) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (info->allocator) { if (!info->allocator->allocate && !info->allocator->free) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } } pthread_t thread; if (info->stackSize == 0) { if (pthread_create(&thread, nullptr, info->entry, info->arg) != 0) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } } else { @@ -51,10 +45,7 @@ PalResult PAL_CALL palCreateThread( pthread_attr_setstacksize(&attr, info->stackSize); if (pthread_create(&thread, nullptr, info->entry, info->arg) != 0) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } pthread_attr_destroy(&attr); } @@ -68,10 +59,7 @@ PalResult PAL_CALL palJoinThread( void** retval) { if (!thread) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } int ret = 0; @@ -86,10 +74,7 @@ PalResult PAL_CALL palJoinThread( return PAL_RESULT_SUCCESS; } else { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } } @@ -120,8 +105,12 @@ PalThreadFeatures PAL_CALL palGetThreadFeatures() PalThreadFeatures features = 0; features |= PAL_THREAD_FEATURE_STACK_SIZE; features |= PAL_THREAD_FEATURE_PRIORITY; + +#ifdef __linux__ features |= PAL_THREAD_FEATURE_AFFINITY; features |= PAL_THREAD_FEATURE_NAME; +#endif // __linux__ + return features; } @@ -158,6 +147,7 @@ uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) return 0; } +#ifdef __linux__ cpu_set_t cpuset; CPU_ZERO(&cpuset); pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); @@ -172,6 +162,9 @@ uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) } } return mask; +#endif // __linux__ + + return 0; } PalResult PAL_CALL palGetThreadName( @@ -181,24 +174,22 @@ PalResult PAL_CALL palGetThreadName( char* outBuffer) { if (!thread) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } +#ifdef __linux__ // see if user provided a buffer and write to it if (outBuffer && bufferSize > 0) { pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); if (pthread_getname_np(_thread, outBuffer, bufferSize) != 0) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_INVALID_HANDLE, PAL_RESULT_SOURCE_POSIX, errno); } } return PAL_RESULT_SUCCESS; +#endif // __linux__ + + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult PAL_CALL palSetThreadPriority( @@ -206,10 +197,7 @@ PalResult PAL_CALL palSetThreadPriority( PalThreadPriority priority) { if (!thread) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } switch (priority) { @@ -230,8 +218,8 @@ PalResult PAL_CALL palSetThreadPriority( int ret = pthread_setschedparam(_thread, SCHED_FIFO, ¶m); if (ret == EPERM) { return palMakeResult( - PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_SOURCE_LINUX, + PAL_RESULT_CODE_INVALID_OPERATION, + PAL_RESULT_SOURCE_POSIX, errno); } } @@ -245,12 +233,10 @@ PalResult PAL_CALL palSetThreadAffinity( uint64_t mask) { if (!thread) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } +#ifdef __linux__ cpu_set_t cpuset; CPU_ZERO(&cpuset); for (int i = 0; i < 64; ++i) { @@ -266,11 +252,11 @@ PalResult PAL_CALL palSetThreadAffinity( return PAL_RESULT_SUCCESS; } else { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_INVALID_HANDLE, PAL_RESULT_SOURCE_POSIX, errno); } +#endif // __linux__ + + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult PAL_CALL palSetThreadName( @@ -278,23 +264,21 @@ PalResult PAL_CALL palSetThreadName( const char* name) { if (!thread || !name) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } +#ifdef __linux__ pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); int ret = pthread_setname_np(_thread, name); if (ret == 0) { return PAL_RESULT_SUCCESS; } else { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_INVALID_HANDLE, PAL_RESULT_SOURCE_POSIX, errno); } +#endif // __linux__ + + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } -#endif // __linux__ \ No newline at end of file +#endif // _PAL_ON_POSIX \ No newline at end of file diff --git a/src/thread/linux/pal_thread_linux.h b/src/thread/posix/pal_thread_posix.h similarity index 88% rename from src/thread/linux/pal_thread_linux.h rename to src/thread/posix/pal_thread_posix.h index 912749d9..169b02ab 100644 --- a/src/thread/linux/pal_thread_linux.h +++ b/src/thread/posix/pal_thread_posix.h @@ -7,7 +7,9 @@ #ifndef _PAL_THREAD_LINUX_H #define _PAL_THREAD_LINUX_H -#ifdef __linux__ + +#include "pal_posix.h" +#if _PAL_ON_POSIX #define _POSIX_C_SOURCE 200112L #include "pal/pal_thread.h" @@ -25,5 +27,5 @@ struct PalMutex { pthread_mutex_t handle; }; -#endif // __linux__ +#endif // _PAL_ON_POSIX #endif // _PAL_THREAD_LINUX_H \ No newline at end of file diff --git a/src/thread/linux/pal_tls_linux.c b/src/thread/posix/pal_tls_posix.c similarity index 91% rename from src/thread/linux/pal_tls_linux.c rename to src/thread/posix/pal_tls_posix.c index 771b5177..cf7f0671 100644 --- a/src/thread/linux/pal_tls_linux.c +++ b/src/thread/posix/pal_tls_posix.c @@ -5,7 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ +#include "pal_posix.h" + +#if _PAL_ON_POSIX #include "pal/pal_thread.h" #include @@ -35,4 +37,4 @@ void PAL_CALL palSetTLS( pthread_setspecific((pthread_key_t)id, data); } -#endif // __linux__ \ No newline at end of file +#endif // _PAL_ON_POSIX \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index aa8e7350..66c274f0 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -24,7 +24,7 @@ int main(int argc, char** argv) // registerTest(threadTest, "Thread Test"); // registerTest(tlsTest, "TLS Test"); // registerTest(mutexTest, "Mutex Test"); - // registerTest(condvarTest, "Condvar Test"); + registerTest(condvarTest, "Condvar Test"); #endif // PAL_HAS_THREAD_MODULE #if PAL_HAS_VIDEO_MODULE == 1 From 4fef984c4e378307bd766f552373b512296ba926 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 28 Jun 2026 22:44:01 +0000 Subject: [PATCH 304/372] update video system and tests --- pal.lua | 26 +- pal_config.lua | 4 +- src/video/linux/pal_backends_linux.h | 232 --- src/video/linux/pal_video_linux.c | 1243 ----------------- src/video/linux/pal_video_linux.h | 343 ----- src/video/pal_video.c | 820 +++++++++++ src/video/pal_video_backends.h | 446 ++++++ src/video/pal_video_egl.h | 81 ++ .../{linux => }/wayland/pal_cursor_wayland.c | 77 +- .../{linux => }/wayland/pal_icon_wayland.c | 16 +- .../{linux => }/wayland/pal_monitor_wayland.c | 53 +- .../{linux => }/wayland/pal_video_wayland.c | 637 ++++++--- src/video/{linux => }/wayland/pal_wayland.h | 68 +- .../wayland/pal_wayland_protocols.c | 5 +- .../wayland/pal_wayland_protocols.h | 4 +- .../{linux => }/wayland/pal_window_wayland.c | 218 +-- src/video/win32/pal_video_win32.c | 73 +- src/video/{linux => }/x11/pal_cursor_x11.c | 47 +- src/video/{linux => }/x11/pal_icon_x11.c | 21 +- src/video/{linux => }/x11/pal_monitor_x11.c | 123 +- src/video/{linux => }/x11/pal_video_x11.c | 501 +++++-- src/video/{linux => }/x11/pal_window_x11.c | 270 +--- src/video/{linux => }/x11/pal_x11.h | 49 +- tests/tests_main.c | 2 +- tests/video/attach_window_test.c | 16 +- tests/video/char_event_test.c | 14 +- tests/video/cursor_test.c | 8 +- tests/video/custom_decoration_test.c | 28 +- tests/video/icon_test.c | 8 +- tests/video/input_window_test.c | 50 +- tests/video/native_instance_test.c | 8 +- tests/video/native_integration_test.c | 14 +- tests/video/system_cursor_test.c | 10 +- tests/video/window_test.c | 56 +- tools/abi_dump/video_abi_dump.c | 76 +- 35 files changed, 2713 insertions(+), 2934 deletions(-) delete mode 100644 src/video/linux/pal_backends_linux.h delete mode 100644 src/video/linux/pal_video_linux.c delete mode 100644 src/video/linux/pal_video_linux.h create mode 100644 src/video/pal_video.c create mode 100644 src/video/pal_video_backends.h create mode 100644 src/video/pal_video_egl.h rename src/video/{linux => }/wayland/pal_cursor_wayland.c (59%) rename src/video/{linux => }/wayland/pal_icon_wayland.c (54%) rename src/video/{linux => }/wayland/pal_monitor_wayland.c (64%) rename src/video/{linux => }/wayland/pal_video_wayland.c (71%) rename src/video/{linux => }/wayland/pal_wayland.h (82%) rename src/video/{linux => }/wayland/pal_wayland_protocols.c (98%) rename src/video/{linux => }/wayland/pal_wayland_protocols.h (99%) rename src/video/{linux => }/wayland/pal_window_wayland.c (62%) rename src/video/{linux => }/x11/pal_cursor_x11.c (78%) rename src/video/{linux => }/x11/pal_icon_x11.c (81%) rename src/video/{linux => }/x11/pal_monitor_x11.c (78%) rename src/video/{linux => }/x11/pal_video_x11.c (70%) rename src/video/{linux => }/x11/pal_window_x11.c (79%) rename src/video/{linux => }/x11/pal_x11.h (91%) diff --git a/pal.lua b/pal.lua index 24277730..04cc19d3 100644 --- a/pal.lua +++ b/pal.lua @@ -141,22 +141,22 @@ project "PAL" filter {"system:linux", "configurations:*"} files { + "src/video/pal_video.c", + -- X11 - "src/video/linux/x11/pal_cursor_x11.c", - "src/video/linux/x11/pal_icon_x11.c", - "src/video/linux/x11/pal_monitor_x11.c", - "src/video/linux/x11/pal_window_x11.c", - "src/video/linux/x11/pal_video_x11.c", + "src/video/x11/pal_cursor_x11.c", + "src/video/x11/pal_icon_x11.c", + "src/video/x11/pal_monitor_x11.c", + "src/video/x11/pal_window_x11.c", + "src/video/x11/pal_video_x11.c", -- Wayland - "src/video/linux/wayland/pal_cursor_wayland.c", - "src/video/linux/wayland/pal_icon_wayland.c", - "src/video/linux/wayland/pal_monitor_wayland.c", - "src/video/linux/wayland/pal_window_wayland.c", - "src/video/linux/wayland/pal_wayland_protocols.c", - "src/video/linux/wayland/pal_video_wayland.c", - - "src/video/linux/pal_video_linux.c" + "src/video/wayland/pal_cursor_wayland.c", + "src/video/wayland/pal_icon_wayland.c", + "src/video/wayland/pal_monitor_wayland.c", + "src/video/wayland/pal_window_wayland.c", + "src/video/wayland/pal_wayland_protocols.c", + "src/video/wayland/pal_video_wayland.c" } filter {} diff --git a/pal_config.lua b/pal_config.lua index 3ab92dff..07bf5d26 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -12,10 +12,10 @@ PAL_BUILD_ABI_DUMP = true PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD_MODULE = true +PAL_BUILD_THREAD_MODULE = false -- build video module -PAL_BUILD_VIDEO_MODULE = false +PAL_BUILD_VIDEO_MODULE = true -- build opengl module PAL_BUILD_OPENGL_MODULE = false diff --git a/src/video/linux/pal_backends_linux.h b/src/video/linux/pal_backends_linux.h deleted file mode 100644 index cff79c1c..00000000 --- a/src/video/linux/pal_backends_linux.h +++ /dev/null @@ -1,232 +0,0 @@ -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifndef _PAL_BACKENDS_LINUX_H -#define _PAL_BACKENDS_LINUX_H -#ifdef __linux__ - -#include "pal_video_linux.h" - -// ================================================== -// X11 -// ================================================== - -PalResult xInitVideo(); -void xShutdownVideo(); -void xUpdateVideo(); - -PalResult xEnumerateMonitors(int32_t*, PalMonitor**); -PalResult xGetPrimaryMonitor(PalMonitor**); -PalResult xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); -PalResult xEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); -PalResult xGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult xSetMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult xValidateMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult xSetMonitorOrientation(PalMonitor*, PalOrientation); - -PalResult xCreateWindow(const PalWindowCreateInfo*, PalWindow**); -void xDestroyWindow(PalWindow*); -PalResult xMaximizeWindow(PalWindow*); -PalResult xMinimizeWindow(PalWindow*); -PalResult xRestoreWindow(PalWindow*); -PalResult xShowWindow(PalWindow*); -PalResult xHideWindow(PalWindow*); -PalResult xFlashWindow(PalWindow*, const PalFlashInfo*); -PalResult xGetWindowStyle(PalWindow*, PalWindowStyle*); -PalResult xGetWindowMonitor(PalWindow*, PalMonitor**); -PalResult xGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); -PalResult xGetWindowPos(PalWindow*, int32_t*, int32_t*); -PalResult xGetWindowSize(PalWindow*, uint32_t*, uint32_t*); -PalResult xGetWindowState(PalWindow*, PalWindowState*); -PalBool xIsWindowVisible(PalWindow*); -PalWindow* xGetFocusWindow(); -PalResult xGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); -PalResult xSetWindowOpacity(PalWindow*, float); -PalResult xSetWindowStyle(PalWindow*, PalWindowStyle); -PalResult xSetWindowTitle(PalWindow*, const char*); -PalResult xSetWindowPos(PalWindow*, int32_t, int32_t); -PalResult xSetWindowSize(PalWindow*, uint32_t, uint32_t); -PalResult xSetFocusWindow(PalWindow*); - -PalResult xCreateIcon(const PalIconCreateInfo*, PalIcon**); -void xDestroyIcon(PalIcon*); -PalResult xSetWindowIcon(PalWindow*, PalIcon*); - -PalResult xCreateCursor(const PalCursorCreateInfo*, PalCursor**); -PalResult xCreateCursorFrom(PalCursorType, PalCursor**); -void xDestroyCursor(PalCursor*); -void xShowCursor(PalBool); -PalResult xClipCursor(PalWindow*, PalBool); -PalResult xGetCursorPos(PalWindow*, int32_t*, int32_t*); -PalResult xSetCursorPos(PalWindow*, int32_t, int32_t); -PalResult xSetWindowCursor(PalWindow*, PalCursor*); - -PalResult xAttachWindow(void*, PalWindow**); -PalResult xDetachWindow(PalWindow*, void**); - -static Backend s_XBackend = { - .shutdownVideo = xShutdownVideo, - .updateVideo = xUpdateVideo, - .enumerateMonitors = xEnumerateMonitors, - .getMonitorInfo = xGetMonitorInfo, - .getPrimaryMonitor = xGetPrimaryMonitor, - .enumerateMonitorModes = xEnumerateMonitorModes, - .getCurrentMonitorMode = xGetCurrentMonitorMode, - .setMonitorMode = xSetMonitorMode, - .validateMonitorMode = xValidateMonitorMode, - .setMonitorOrientation = xSetMonitorOrientation, - - .createWindow = xCreateWindow, - .destroyWindow = xDestroyWindow, - .maximizeWindow = xMaximizeWindow, - .minimizeWindow = xMinimizeWindow, - .restoreWindow = xRestoreWindow, - .showWindow = xShowWindow, - .hideWindow = xHideWindow, - .flashWindow = xFlashWindow, - .getWindowStyle = xGetWindowStyle, - .getWindowMonitor = xGetWindowMonitor, - .getWindowTitle = xGetWindowTitle, - .getWindowPos = xGetWindowPos, - .getWindowSize = xGetWindowSize, - .getWindowState = xGetWindowState, - .isWindowVisible = xIsWindowVisible, - .getFocusWindow = xGetFocusWindow, - .getWindowHandleInfo = xGetWindowHandleInfo, - .setWindowOpacity = xSetWindowOpacity, - .setWindowStyle = xSetWindowStyle, - .setWindowTitle = xSetWindowTitle, - .setWindowPos = xSetWindowPos, - .setWindowSize = xSetWindowSize, - .setFocusWindow = xSetFocusWindow, - - .createIcon = xCreateIcon, - .destroyIcon = xDestroyIcon, - .setWindowIcon = xSetWindowIcon, - - .createCursor = xCreateCursor, - .createCursorFrom = xCreateCursorFrom, - .destroyCursor = xDestroyCursor, - .showCursor = xShowCursor, - .clipCursor = xClipCursor, - .getCursorPos = xGetCursorPos, - .setCursorPos = xSetCursorPos, - .setWindowCursor = xSetWindowCursor, - - .attachWindow = xAttachWindow, - .detachWindow = xDetachWindow}; - -// ================================================== -// Wayland -// ================================================== - -PalResult wlInitVideo(); -void wlShutdownVideo(); -void wlUpdateVideo(); - -PalResult wlEnumerateMonitors(int32_t*, PalMonitor**); -PalResult wlGetPrimaryMonitor(PalMonitor**); -PalResult wlGetMonitorInfo(PalMonitor*, PalMonitorInfo*); -PalResult wlEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); -PalResult wlGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult wlSetMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult wlValidateMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult wlSetMonitorOrientation(PalMonitor*, PalOrientation); - -PalResult wlCreateWindow(const PalWindowCreateInfo*, PalWindow**); -void wlDestroyWindow(PalWindow*); -PalResult wlMaximizeWindow(PalWindow*); -PalResult wlMinimizeWindow(PalWindow*); -PalResult wlRestoreWindow(PalWindow*); -PalResult wlShowWindow(PalWindow*); -PalResult wlHideWindow(PalWindow*); -PalResult wlFlashWindow(PalWindow*, const PalFlashInfo*); -PalResult wlGetWindowStyle(PalWindow*, PalWindowStyle*); -PalResult wlGetWindowMonitor(PalWindow*, PalMonitor**); -PalResult wlGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); -PalResult wlGetWindowPos(PalWindow*, int32_t*, int32_t*); -PalResult wlGetWindowSize(PalWindow*, uint32_t*, uint32_t*); -PalResult wlGetWindowState(PalWindow*, PalWindowState*); -PalBool wlIsWindowVisible(PalWindow*); -PalWindow* wlGetFocusWindow(); -PalResult wlGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); -PalResult wlSetWindowOpacity(PalWindow*, float); -PalResult wlSetWindowStyle(PalWindow*, PalWindowStyle); -PalResult wlSetWindowTitle(PalWindow*, const char*); -PalResult wlSetWindowPos(PalWindow*, int32_t, int32_t); -PalResult wlSetWindowSize(PalWindow*, uint32_t, uint32_t); -PalResult wlSetFocusWindow(PalWindow*); - -PalResult wlCreateIcon(const PalIconCreateInfo*, PalIcon**); -void wlDestroyIcon(PalIcon*); -PalResult wlSetWindowIcon(PalWindow*, PalIcon*); - -PalResult wlCreateCursor(const PalCursorCreateInfo*, PalCursor**); -PalResult wlCreateCursorFrom(PalCursorType, PalCursor**); -void wlDestroyCursor(PalCursor*); -void wlShowCursor(PalBool); -PalResult wlClipCursor(PalWindow*, PalBool); -PalResult wlGetCursorPos(PalWindow*, int32_t*, int32_t*); -PalResult wlSetCursorPos(PalWindow*, int32_t, int32_t); -PalResult wlSetWindowCursor(PalWindow*, PalCursor*); - -PalResult wlAttachWindow(void*, PalWindow**); -PalResult wlDetachWindow(PalWindow*, void**); - -static Backend s_wlBackend = { - .shutdownVideo = wlShutdownVideo, - .updateVideo = wlUpdateVideo, - .enumerateMonitors = wlEnumerateMonitors, - .getMonitorInfo = wlGetMonitorInfo, - .getPrimaryMonitor = wlGetPrimaryMonitor, - .enumerateMonitorModes = wlEnumerateMonitorModes, - .getCurrentMonitorMode = wlGetCurrentMonitorMode, - .setMonitorMode = wlSetMonitorMode, - .validateMonitorMode = wlValidateMonitorMode, - .setMonitorOrientation = wlSetMonitorOrientation, - - .createWindow = wlCreateWindow, - .destroyWindow = wlDestroyWindow, - .maximizeWindow = wlMaximizeWindow, - .minimizeWindow = wlMinimizeWindow, - .restoreWindow = wlRestoreWindow, - .showWindow = wlShowWindow, - .hideWindow = wlHideWindow, - .flashWindow = wlFlashWindow, - .getWindowStyle = wlGetWindowStyle, - .getWindowMonitor = wlGetWindowMonitor, - .getWindowTitle = wlGetWindowTitle, - .getWindowPos = wlGetWindowPos, - .getWindowSize = wlGetWindowSize, - .getWindowState = wlGetWindowState, - .isWindowVisible = wlIsWindowVisible, - .getFocusWindow = wlGetFocusWindow, - .getWindowHandleInfo = wlGetWindowHandleInfo, - .setWindowOpacity = wlSetWindowOpacity, - .setWindowStyle = wlSetWindowStyle, - .setWindowTitle = wlSetWindowTitle, - .setWindowPos = wlSetWindowPos, - .setWindowSize = wlSetWindowSize, - .setFocusWindow = wlSetFocusWindow, - - .createIcon = wlCreateIcon, - .destroyIcon = wlDestroyIcon, - .setWindowIcon = wlSetWindowIcon, - - .createCursor = wlCreateCursor, - .createCursorFrom = wlCreateCursorFrom, - .destroyCursor = wlDestroyCursor, - .showCursor = wlShowCursor, - .clipCursor = wlClipCursor, - .getCursorPos = wlGetCursorPos, - .setCursorPos = wlSetCursorPos, - .setWindowCursor = wlSetWindowCursor, - - .attachWindow = wlAttachWindow, - .detachWindow = wlDetachWindow}; - -#endif // __linux__ -#endif // _PAL_BACKENDS_LINUX_H \ No newline at end of file diff --git a/src/video/linux/pal_video_linux.c b/src/video/linux/pal_video_linux.c deleted file mode 100644 index 848f5e0f..00000000 --- a/src/video/linux/pal_video_linux.c +++ /dev/null @@ -1,1243 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifdef __linux__ -#include "pal_backends_linux.h" -#include "pal_shared.h" -#include -#include - -EGL s_Egl = {0}; -VideoLinux s_Video = {0}; -Mouse s_Mouse = {0}; -Keyboard s_Keyboard = {0}; - -static int compareModes( - const void* a, - const void* b) -{ - const PalMonitorMode* mode1 = (const PalMonitorMode*)a; - const PalMonitorMode* mode2 = (const PalMonitorMode*)b; - - // compare fields - if (mode1->width != mode2->width) { - return mode1->width - mode2->width; - } - - if (mode1->height != mode2->height) { - return mode1->height - mode2->height; - } - - if (mode1->refreshRate != mode2->refreshRate) { - return mode1->refreshRate - mode2->refreshRate; - } - - if (mode1->bpp != mode2->bpp) { - return mode1->bpp - mode2->bpp; - } -} - -static void createScancodeTable() -{ - // Letters - s_Keyboard.scancodes[0x01E] = PAL_SCANCODE_A; - s_Keyboard.scancodes[0x030] = PAL_SCANCODE_B; - s_Keyboard.scancodes[0x02E] = PAL_SCANCODE_C; - s_Keyboard.scancodes[0x020] = PAL_SCANCODE_D; - s_Keyboard.scancodes[0x012] = PAL_SCANCODE_E; - s_Keyboard.scancodes[0x021] = PAL_SCANCODE_F; - s_Keyboard.scancodes[0x022] = PAL_SCANCODE_G; - s_Keyboard.scancodes[0x023] = PAL_SCANCODE_H; - s_Keyboard.scancodes[0x017] = PAL_SCANCODE_I; - s_Keyboard.scancodes[0x024] = PAL_SCANCODE_J; - s_Keyboard.scancodes[0x025] = PAL_SCANCODE_K; - s_Keyboard.scancodes[0x026] = PAL_SCANCODE_L; - s_Keyboard.scancodes[0x032] = PAL_SCANCODE_M; - s_Keyboard.scancodes[0x031] = PAL_SCANCODE_N; - s_Keyboard.scancodes[0x018] = PAL_SCANCODE_O; - s_Keyboard.scancodes[0x019] = PAL_SCANCODE_P; - s_Keyboard.scancodes[0x010] = PAL_SCANCODE_Q; - s_Keyboard.scancodes[0x013] = PAL_SCANCODE_R; - s_Keyboard.scancodes[0x01F] = PAL_SCANCODE_S; - s_Keyboard.scancodes[0x014] = PAL_SCANCODE_T; - s_Keyboard.scancodes[0x016] = PAL_SCANCODE_U; - s_Keyboard.scancodes[0x02F] = PAL_SCANCODE_V; - s_Keyboard.scancodes[0x011] = PAL_SCANCODE_W; - s_Keyboard.scancodes[0x02D] = PAL_SCANCODE_X; - s_Keyboard.scancodes[0x015] = PAL_SCANCODE_Y; - s_Keyboard.scancodes[0x02C] = PAL_SCANCODE_Z; - - // Numbers (top row) - s_Keyboard.scancodes[0x00B] = PAL_SCANCODE_0; - s_Keyboard.scancodes[0x002] = PAL_SCANCODE_1; - s_Keyboard.scancodes[0x003] = PAL_SCANCODE_2; - s_Keyboard.scancodes[0x004] = PAL_SCANCODE_3; - s_Keyboard.scancodes[0x005] = PAL_SCANCODE_4; - s_Keyboard.scancodes[0x006] = PAL_SCANCODE_5; - s_Keyboard.scancodes[0x007] = PAL_SCANCODE_6; - s_Keyboard.scancodes[0x008] = PAL_SCANCODE_7; - s_Keyboard.scancodes[0x009] = PAL_SCANCODE_8; - s_Keyboard.scancodes[0x00A] = PAL_SCANCODE_9; - - // Function - s_Keyboard.scancodes[0x03B] = PAL_SCANCODE_F1; - s_Keyboard.scancodes[0x03C] = PAL_SCANCODE_F2; - s_Keyboard.scancodes[0x03D] = PAL_SCANCODE_F3; - s_Keyboard.scancodes[0x03E] = PAL_SCANCODE_F4; - s_Keyboard.scancodes[0x03F] = PAL_SCANCODE_F5; - s_Keyboard.scancodes[0x040] = PAL_SCANCODE_F6; - s_Keyboard.scancodes[0x041] = PAL_SCANCODE_F7; - s_Keyboard.scancodes[0x042] = PAL_SCANCODE_F8; - s_Keyboard.scancodes[0x043] = PAL_SCANCODE_F9; - s_Keyboard.scancodes[0x044] = PAL_SCANCODE_F10; - s_Keyboard.scancodes[0x057] = PAL_SCANCODE_F11; - s_Keyboard.scancodes[0x058] = PAL_SCANCODE_F12; - - // Control - s_Keyboard.scancodes[0x001] = PAL_SCANCODE_ESCAPE; - s_Keyboard.scancodes[0x01C] = PAL_SCANCODE_ENTER; - s_Keyboard.scancodes[0x00F] = PAL_SCANCODE_TAB; - s_Keyboard.scancodes[0x00E] = PAL_SCANCODE_BACKSPACE; - s_Keyboard.scancodes[0x039] = PAL_SCANCODE_SPACE; - s_Keyboard.scancodes[0x03A] = PAL_SCANCODE_CAPSLOCK; - s_Keyboard.scancodes[0x045] = PAL_SCANCODE_NUMLOCK; - s_Keyboard.scancodes[0x046] = PAL_SCANCODE_SCROLLLOCK; - s_Keyboard.scancodes[0x02A] = PAL_SCANCODE_LSHIFT; - s_Keyboard.scancodes[0x036] = PAL_SCANCODE_RSHIFT; - s_Keyboard.scancodes[0x01D] = PAL_SCANCODE_LCTRL; - s_Keyboard.scancodes[0x061] = PAL_SCANCODE_RCTRL; - s_Keyboard.scancodes[0x038] = PAL_SCANCODE_LALT; - s_Keyboard.scancodes[0x064] = PAL_SCANCODE_RALT; - - // Arrows - s_Keyboard.scancodes[0x069] = PAL_SCANCODE_LEFT; - s_Keyboard.scancodes[0x06A] = PAL_SCANCODE_RIGHT; - s_Keyboard.scancodes[0x067] = PAL_SCANCODE_UP; - s_Keyboard.scancodes[0x06C] = PAL_SCANCODE_DOWN; - - // Navigation - s_Keyboard.scancodes[0x06E] = PAL_SCANCODE_INSERT; - s_Keyboard.scancodes[0x06F] = PAL_SCANCODE_DELETE; - s_Keyboard.scancodes[0x066] = PAL_SCANCODE_HOME; - s_Keyboard.scancodes[0x067] = PAL_SCANCODE_END; - s_Keyboard.scancodes[0x068] = PAL_SCANCODE_PAGEUP; - s_Keyboard.scancodes[0x06D] = PAL_SCANCODE_PAGEDOWN; - - // Keypad - s_Keyboard.scancodes[0x052] = PAL_SCANCODE_KP_0; - s_Keyboard.scancodes[0x04F] = PAL_SCANCODE_KP_1; - s_Keyboard.scancodes[0x050] = PAL_SCANCODE_KP_2; - s_Keyboard.scancodes[0x051] = PAL_SCANCODE_KP_3; - s_Keyboard.scancodes[0x04B] = PAL_SCANCODE_KP_4; - s_Keyboard.scancodes[0x04C] = PAL_SCANCODE_KP_5; - s_Keyboard.scancodes[0x04D] = PAL_SCANCODE_KP_6; - s_Keyboard.scancodes[0x047] = PAL_SCANCODE_KP_7; - s_Keyboard.scancodes[0x048] = PAL_SCANCODE_KP_8; - s_Keyboard.scancodes[0x049] = PAL_SCANCODE_KP_9; - s_Keyboard.scancodes[0x060] = PAL_SCANCODE_KP_ENTER; - s_Keyboard.scancodes[0x04E] = PAL_SCANCODE_KP_ADD; - s_Keyboard.scancodes[0x04A] = PAL_SCANCODE_KP_SUBTRACT; - s_Keyboard.scancodes[0x037] = PAL_SCANCODE_KP_MULTIPLY; - s_Keyboard.scancodes[0x062] = PAL_SCANCODE_KP_DIVIDE; - s_Keyboard.scancodes[0x053] = PAL_SCANCODE_KP_DECIMAL; - - // Misc - s_Keyboard.scancodes[0x063] = PAL_SCANCODE_PRINTSCREEN; - s_Keyboard.scancodes[0x066] = PAL_SCANCODE_PAUSE; - s_Keyboard.scancodes[0x07F] = PAL_SCANCODE_MENU; - s_Keyboard.scancodes[0x028] = PAL_SCANCODE_APOSTROPHE; - s_Keyboard.scancodes[0x02B] = PAL_SCANCODE_BACKSLASH; - s_Keyboard.scancodes[0x033] = PAL_SCANCODE_COMMA; - s_Keyboard.scancodes[0x00D] = PAL_SCANCODE_EQUAL; - s_Keyboard.scancodes[0x029] = PAL_SCANCODE_GRAVEACCENT; - s_Keyboard.scancodes[0x00C] = PAL_SCANCODE_SUBTRACT; - s_Keyboard.scancodes[0x034] = PAL_SCANCODE_PERIOD; - s_Keyboard.scancodes[0x027] = PAL_SCANCODE_SEMICOLON; - s_Keyboard.scancodes[0x035] = PAL_SCANCODE_SLASH; - s_Keyboard.scancodes[0x01A] = PAL_SCANCODE_LBRACKET; - s_Keyboard.scancodes[0x01B] = PAL_SCANCODE_RBRACKET; - s_Keyboard.scancodes[0x07D] = PAL_SCANCODE_LSUPER; - s_Keyboard.scancodes[0x07E] = PAL_SCANCODE_RSUPER; -} - -PalResult PAL_CALL palInitVideo( - const PalAllocator* allocator, - PalEventDriver* eventDriver, - void* preferredInstance) -{ - if (s_Video.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - // get backend type - PalBool x11 = PAL_TRUE; - const char* session = getenv("XDG_SESSION_TYPE"); - if (session) { - if (strcmp(session, "wayland") == 0) { - x11 = PAL_FALSE; - } - } - - s_Video.maxMonitorData = 16; // initial size - s_Video.maxWindowData = 32; // initial size - uint32_t windowDataSize = sizeof(WindowData) * s_Video.maxWindowData; - uint32_t monitorDataSize = sizeof(MonitorData) * s_Video.maxMonitorData; - - s_Video.windowData = palAllocate(s_Video.allocator, windowDataSize, 0); - s_Video.monitorData = palAllocate(s_Video.allocator, monitorDataSize, 0); - if (!s_Video.monitorData || !s_Video.windowData) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - // user provided instance - if (preferredInstance) { - s_Video.display = preferredInstance; - } - - s_Video.className = "PAL"; - if (x11) { -#if PAL_HAS_X11_BACKEND == 1 - PalResult ret = xInitVideo(); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - s_Video.backend = &s_XBackend; -#else - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); -#endif // PAL_HAS_X11_BACKEND - - } else { -#if PAL_HAS_WAYLAND_BACKEND == 1 - PalResult ret = wlInitVideo(); - if (ret != PAL_RESULT_SUCCESS) { - return ret; - } - s_Video.backend = &s_wlBackend; -#else - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); -#endif // PAL_HAS_WAYLAND_BACKEND - } - - createScancodeTable(); - - // we load EGL as well - s_Egl.handle = dlopen("libEGL.so", RTLD_LAZY); - if (s_Egl.handle) { - eglGetProcAddressFn load = nullptr; - load = (eglGetProcAddressFn)dlsym(s_Egl.handle, "eglGetProcAddress"); - - s_Egl.eglInitialize = (eglInitializeFn)load("eglInitialize"); - s_Egl.eglTerminate = (eglTerminateFn)load("eglTerminate"); - s_Egl.eglGetDisplay = (eglGetDisplayFn)load("eglGetDisplay"); - s_Egl.eglChooseConfig = (eglChooseConfigFn)load("eglChooseConfig"); - s_Egl.eglGetError = (eglGetErrorFn)load("eglGetError"); - s_Egl.eglBindAPI = (eglBindAPIFn)load("eglBindAPI"); - s_Egl.eglGetConfigs = (eglGetConfigsFn)load("eglGetConfigs"); - s_Egl.eglGetConfigAttrib = (eglGetConfigAttribFn)load("eglGetConfigAttrib"); - } - - s_Video.allocator = allocator; - s_Video.eventDriver = eventDriver; - s_Video.initialized = PAL_TRUE; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palShutdownVideo() -{ - if (s_Video.initialized) { - s_Video.backend->shutdownVideo(); - palFree(s_Video.allocator, s_Video.windowData); - palFree(s_Video.allocator, s_Video.monitorData); - - if (s_Egl.handle) { - dlclose(s_Egl.handle); - } - - memset(&s_Keyboard, 0, sizeof(Keyboard)); - memset(&s_Mouse, 0, sizeof(Mouse)); - memset(&s_Video, 0, sizeof(VideoLinux)); - s_Video.initialized = PAL_FALSE; - } -} - -void PAL_CALL palUpdateVideo() -{ - if (s_Video.initialized) { - s_Video.backend->updateVideo(); - } -} - -PalVideoFeatures PAL_CALL palGetVideoFeatures() -{ - if (!s_Video.initialized) { - return 0; - } - - return s_Video.features; -} - -PalResult PAL_CALL palEnumerateMonitors( - int32_t* count, - PalMonitor** outMonitors) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!count || *count == 0 && outMonitors) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->enumerateMonitors(count, outMonitors); -} - -PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!outMonitor) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->getPrimaryMonitor(outMonitor); -} - -PalResult PAL_CALL palGetMonitorInfo( - PalMonitor* monitor, - PalMonitorInfo* info) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->getMonitorInfo(monitor, info); -} - -PalResult PAL_CALL palEnumerateMonitorModes( - PalMonitor* monitor, - int32_t* count, - PalMonitorMode* modes) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!monitor || !count || *count == 0 && modes) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - PalResult ret = s_Video.backend->enumerateMonitorModes(monitor, count, modes); - if (ret == PAL_RESULT_SUCCESS && modes) { - // sort the modes so that they are lowest to highest - qsort(modes, *count, sizeof(PalMonitorMode), compareModes); - } - - return ret; -} - -PalResult PAL_CALL palGetCurrentMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!monitor || !mode) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->getCurrentMonitorMode(monitor, mode); -} - -PalResult PAL_CALL palSetMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!monitor || !mode) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setMonitorMode(monitor, mode); -} - -PalResult PAL_CALL palValidateMonitorMode( - PalMonitor* monitor, - PalMonitorMode* mode) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!monitor || !mode) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->validateMonitorMode(monitor, mode); -} - -PalResult PAL_CALL palSetMonitorOrientation( - PalMonitor* monitor, - PalOrientation orientation) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!monitor) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setMonitorOrientation(monitor, orientation); -} - -PalResult PAL_CALL palCreateWindow( - const PalWindowCreateInfo* info, - PalWindow** outWindow) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!info || !outWindow) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (info->style & PAL_WINDOW_STYLE_NO_MINIMIZEBOX) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (info->style & PAL_WINDOW_STYLE_NO_MAXIMIZEBOX) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->createWindow(info, outWindow); -} - -void PAL_CALL palDestroyWindow(PalWindow* window) -{ - if (s_Video.initialized && window) { - return s_Video.backend->destroyWindow(window); - } -} - -PalResult PAL_CALL palMinimizeWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->maximizeWindow(window); -} - -PalResult PAL_CALL palMaximizeWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->minimizeWindow(window); -} - -PalResult PAL_CALL palRestoreWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->restoreWindow(window); -} - -PalResult PAL_CALL palShowWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->showWindow(window); -} - -PalResult PAL_CALL palHideWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->hideWindow(window); -} - -PalResult PAL_CALL palFlashWindow( - PalWindow* window, - const PalFlashInfo* info) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window || !info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->flashWindow(window, info); -} - -PalResult PAL_CALL palGetWindowStyle( - PalWindow* window, - PalWindowStyle* outStyle) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window || !outStyle) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->getWindowStyle(window, outStyle); -} - -PalResult PAL_CALL palGetWindowMonitor( - PalWindow* window, - PalMonitor** outMonitor) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window || !outMonitor) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->getWindowMonitor(window, outMonitor); -} - -PalResult PAL_CALL palGetWindowTitle( - PalWindow* window, - uint64_t bufferSize, - uint64_t* outSize, - char* outBuffer) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window || !outBuffer) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->getWindowTitle(window, bufferSize, outSize, outBuffer); -} - -PalResult PAL_CALL palGetWindowPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->getWindowPos(window, x, y); -} - -PalResult PAL_CALL palGetWindowSize( - PalWindow* window, - uint32_t* width, - uint32_t* height) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->getWindowSize(window, width, height); -} - -PalResult PAL_CALL palGetWindowState( - PalWindow* window, - PalWindowState* outState) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window || !outState) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->getWindowState(window, outState); -} - -const PalBool* PAL_CALL palGetKeycodeState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Keyboard.keycodeState; -} - -const PalBool* PAL_CALL palGetScancodeState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Keyboard.scancodeState; -} - -const PalBool* PAL_CALL palGetMouseState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Mouse.state; -} - -void PAL_CALL palGetMouseDelta( - float* dx, - float* dy) -{ - if (!s_Video.initialized) { - return; - } - - if (dx) { - *dx = s_Mouse.dx; - } - - if (dy) { - *dy = s_Mouse.dy; - } -} - -void PAL_CALL palGetMouseWheelDelta( - float* dx, - float* dy) -{ - if (!s_Video.initialized) { - return; - } - - if (dx) { - *dx = (float)s_Mouse.tmpScrollX; - } - - if (dy) { - *dy = (float)s_Mouse.tmpScrollY; - } -} - -PalBool PAL_CALL palIsWindowVisible(PalWindow* window) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->isWindowVisible(window); -} - -PalWindow* PAL_CALL palGetFocusWindow() -{ - if (!s_Video.initialized) { - return nullptr; - } - - return s_Video.backend->getFocusWindow(); -} - -PalResult PAL_CALL palGetWindowHandleInfo( - PalWindow* window, - PalWindowHandleInfo* info) -{ - if (s_Video.initialized) { - return s_Video.backend->getWindowHandleInfo(window, info); - } - - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); -} - -PalResult PAL_CALL palSetWindowOpacity( - PalWindow* window, - float opacity) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!(s_Video.features & PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW)) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (opacity < 0.0f) { - opacity = 0.0f; - } - - if (opacity > 1.0f) { - opacity = 1.0f; - } - - return s_Video.backend->setWindowOpacity(window, opacity); -} - -PalResult PAL_CALL palSetWindowStyle( - PalWindow* window, - PalWindowStyle style) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setWindowStyle(window, style); -} - -PalResult PAL_CALL palSetWindowTitle( - PalWindow* window, - const char* title) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window || !title) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setWindowTitle(window, title); -} - -PalResult PAL_CALL palSetWindowPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setWindowPos(window, x, y); -} - -PalResult PAL_CALL palSetWindowSize( - PalWindow* window, - uint32_t width, - uint32_t height) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setWindowSize(window, width, height); -} - -PalResult PAL_CALL palSetFocusWindow(PalWindow* window) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setFocusWindow(window); -} - -PalResult PAL_CALL palCreateIcon( - const PalIconCreateInfo* info, - PalIcon** outIcon) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!info || !outIcon) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->createIcon(info, outIcon); -} - -void PAL_CALL palDestroyIcon(PalIcon* icon) -{ - if (s_Video.initialized && icon) { - s_Video.backend->destroyIcon(icon); - } -} - -PalResult PAL_CALL palSetWindowIcon( - PalWindow* window, - PalIcon* icon) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setWindowIcon(window, icon); -} - -PalResult PAL_CALL palCreateCursor( - const PalCursorCreateInfo* info, - PalCursor** outCursor) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!info || !outCursor) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->createCursor(info, outCursor); -} - -PalResult PAL_CALL palCreateCursorFrom( - PalCursorType type, - PalCursor** outCursor) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!outCursor) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->createCursorFrom(type, outCursor); -} - -void PAL_CALL palDestroyCursor(PalCursor* cursor) -{ - if (s_Video.initialized && cursor) { - s_Video.backend->destroyCursor(cursor); - } -} - -void PAL_CALL palShowCursor(PalBool show) -{ - if (s_Video.initialized) { - s_Video.backend->showCursor(show); - } -} - -PalResult PAL_CALL palClipCursor( - PalWindow* window, - PalBool clip) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->clipCursor(window, clip); -} - -PalResult PAL_CALL palGetCursorPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->getCursorPos(window, x, y); -} - -PalResult PAL_CALL palSetCursorPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setCursorPos(window, x, y); -} - -PalResult PAL_CALL palSetWindowCursor( - PalWindow* window, - PalCursor* cursor) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->setWindowCursor(window, cursor); -} - -void* PAL_CALL palGetInstance() -{ - if (!s_Video.initialized) { - return nullptr; - } - - return s_Video.display; -} - -PalResult PAL_CALL palAttachWindow( - void* windowHandle, - PalWindow** outWindow) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!windowHandle) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->attachWindow(windowHandle, outWindow); -} - -PalResult PAL_CALL palDetachWindow( - PalWindow* window, - void** outWindowHandle) -{ - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - return s_Video.backend->detachWindow(window, outWindowHandle); -} - -#endif // __linux__ diff --git a/src/video/linux/pal_video_linux.h b/src/video/linux/pal_video_linux.h deleted file mode 100644 index c1e33c42..00000000 --- a/src/video/linux/pal_video_linux.h +++ /dev/null @@ -1,343 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifndef _PAL_VIDEO_LINUX_H -#define _PAL_VIDEO_LINUX_H -#ifdef __linux__ -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L -#include "pal/pal_video.h" -#include - -#define NULL_BUTTON_SERIAL 0xffffffffU -#define MAX_SPAN_MONITORS 4 - -#define TO_PAL_HANDLE(type, val) ((type*)(uintptr_t)(val)) -#define FROM_PAL_HANDLE(type, handle) ((type)(uintptr_t)(handle)) - -#define EGL_CAST(type, value) ((type)(value)) -#define EGL_OPENGL_API 0x30A2 -#define EGL_OPENGL_BIT 0x0008 -#define EGL_OPENGL_ES_BIT 0x0001 -#define EGL_OPENGL_ES_API 0x30A0 -#define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0) -#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0) -#define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0) -#define EGL_NATIVE_VISUAL_ID 0x302E - -typedef void* EGLConfig; -typedef void* EGLSurface; -typedef void* EGLContext; -typedef void* EGLDisplay; -typedef void* EGLNativeDisplayType; - -typedef int32_t EGLint; -typedef unsigned int EGLBoolean; -typedef unsigned int EGLenum; - -typedef void* (*eglGetProcAddressFn)(const char*); - -typedef EGLBoolean (*eglInitializeFn)( - EGLDisplay, - EGLint*, - EGLint*); - -typedef EGLBoolean (*eglTerminateFn)(EGLDisplay); - -typedef EGLDisplay (*eglGetDisplayFn)(void*); - -typedef EGLBoolean (*eglChooseConfigFn)( - EGLDisplay, - const EGLint*, - EGLConfig*, - EGLint, - EGLint*); - -typedef EGLBoolean (*eglGetConfigAttribFn)( - EGLDisplay, - EGLConfig, - EGLint, - EGLint*); - -typedef EGLint (*eglGetErrorFn)(void); - -typedef EGLBoolean (*eglBindAPIFn)(EGLenum); - -typedef EGLBoolean (*eglGetConfigsFn)( - EGLDisplay, - EGLConfig*, - EGLint, - EGLint*); - -typedef struct { - PalBool pendingScroll; - int32_t lastX; - int32_t lastY; - int32_t dx; - int32_t dy; - int32_t WheelX; - int32_t WheelY; - float WheelXf; - float WheelYf; - PalBool state[PAL_MOUSE_BUTTON_MAX]; - double tmpScrollX; - double tmpScrollY; - double accumScrollX; - double accumScrollY; -} Mouse; - -typedef struct { - PalBool scancodeState[PAL_SCANCODE_MAX]; - PalBool keycodeState[PAL_KEYCODE_MAX]; - int repeatRate; - int repeatDelay; - int repeatKey; - int repeatScancode; - int scancodes[512]; - int keycodes[256]; - uint64_t timer; - uint64_t frequency; -} Keyboard; - -typedef struct { - void* handle; - eglInitializeFn eglInitialize; - eglTerminateFn eglTerminate; - eglGetDisplayFn eglGetDisplay; - eglChooseConfigFn eglChooseConfig; - eglGetConfigAttribFn eglGetConfigAttrib; - eglGetErrorFn eglGetError; - eglBindAPIFn eglBindAPI; - eglGetConfigsFn eglGetConfigs; -} EGL; - -typedef struct { - // clang-format off - void (*shutdownVideo)(); - void (*updateVideo)(); - PalResult (*enumerateMonitors)(int32_t*, PalMonitor**); - PalResult (*getPrimaryMonitor)(PalMonitor**); - PalResult (*getMonitorInfo)(PalMonitor*, PalMonitorInfo*); - PalResult (*enumerateMonitorModes)(PalMonitor*, int32_t*, PalMonitorMode*); - PalResult (*getCurrentMonitorMode)(PalMonitor*, PalMonitorMode*); - PalResult (*setMonitorMode)(PalMonitor*, PalMonitorMode*); - PalResult (*validateMonitorMode)(PalMonitor*, PalMonitorMode*); - PalResult (*setMonitorOrientation)(PalMonitor*, PalOrientation); - - PalResult (*createWindow)(const PalWindowCreateInfo*, PalWindow**); - void (*destroyWindow)(PalWindow*); - PalResult (*maximizeWindow)(PalWindow*); - PalResult (*minimizeWindow)(PalWindow*); - PalResult (*restoreWindow)(PalWindow*); - PalResult (*showWindow)(PalWindow*); - PalResult (*hideWindow)(PalWindow*); - PalResult (*flashWindow)(PalWindow*, const PalFlashInfo*); - PalResult (*getWindowStyle)(PalWindow*, PalWindowStyle*); - PalResult (*getWindowMonitor)(PalWindow*, PalMonitor**); - PalResult (*getWindowTitle)(PalWindow*, uint64_t, uint64_t*, char*); - PalResult (*getWindowPos)(PalWindow*, int32_t*, int32_t*); - PalResult (*getWindowSize)(PalWindow*, uint32_t*, uint32_t*); - PalResult (*getWindowState)(PalWindow*, PalWindowState*); - PalBool (*isWindowVisible)(PalWindow*); - PalWindow* (*getFocusWindow)(); - PalResult (*getWindowHandleInfo)(PalWindow*, PalWindowHandleInfo*); - PalResult (*setWindowOpacity)(PalWindow*, float); - PalResult (*setWindowStyle)(PalWindow*, PalWindowStyle); - PalResult (*setWindowTitle)(PalWindow*, const char*); - PalResult (*setWindowPos)(PalWindow*, int32_t, int32_t); - PalResult (*setWindowSize)(PalWindow*, uint32_t, uint32_t); - PalResult (*setFocusWindow)(PalWindow*); - - PalResult (*createIcon)(const PalIconCreateInfo*, PalIcon**); - void (*destroyIcon)(PalIcon*); - PalResult (*setWindowIcon)(PalWindow*, PalIcon*); - - PalResult (*createCursor)(const PalCursorCreateInfo*, PalCursor**); - PalResult (*createCursorFrom)(PalCursorType, PalCursor**); - void (*destroyCursor)(PalCursor*); - void (*showCursor)(PalBool); - PalResult (*clipCursor)(PalWindow*, PalBool); - PalResult (*getCursorPos)(PalWindow*, int32_t*, int32_t*); - PalResult (*setCursorPos)(PalWindow*, int32_t, int32_t); - PalResult (*setWindowCursor)(PalWindow*, PalCursor*); - - PalResult (*attachWindow)(void*, PalWindow**); - PalResult (*detachWindow)(PalWindow*, void**); - // clang-format on -} Backend; - -typedef struct { - void* monitor; - int dpi; -} SpanMonitor; - -typedef struct { - PalBool skipConfigure; - PalBool skipState; - PalBool used; - PalBool isAttached; - PalBool skipIfAttached; - PalBool focused; - PalBool pushConfigureEvent; - PalBool pushStateEvent; - int x; - int y; - uint32_t w; - int dpi; - int monitorCount; - uint32_t h; - PalWindowState state; - PalWindow* window; - - // X11 only - void* ic; - unsigned long colormap; - - // Wayland only - void* xdgSurface; - void* xdgToplevel; - void* buffer; - void* decoration; - void* cursor; - void* eglWindow; - SpanMonitor monitors[MAX_SPAN_MONITORS]; -} WindowData; - -typedef struct { - PalBool used; - int dpi; - int x; - int y; - uint32_t w; - uint32_t h; - uint32_t refreshRate; - uint32_t wlName; - PalOrientation orientation; - PalMonitor* monitor; - PalMonitorMode mode; // wayland only sends current - char name[32]; -} MonitorData; - -typedef struct { - PalBool initialized; - int32_t maxWindowData; - int32_t maxMonitorData; - int32_t pixelFormat; - PalVideoFeatures features; - const PalAllocator* allocator; - PalEventDriver* eventDriver; - const Backend* backend; - WindowData* windowData; - MonitorData* monitorData; - const char* className; - void* display; -} VideoLinux; - -extern VideoLinux s_Video; -extern Mouse s_Mouse; -extern Keyboard s_Keyboard; -extern EGL s_Egl; - -static WindowData* getFreeWindowData() -{ - for (int i = 0; i < s_Video.maxWindowData; ++i) { - if (!s_Video.windowData[i].used) { - s_Video.windowData[i].used = PAL_TRUE; - return &s_Video.windowData[i]; - } - } - - // resize the data array - // It is rare for a user to create and manage - // 32 windows at the same time - WindowData* data = nullptr; - int count = s_Video.maxWindowData * 2; // double the size - int freeIndex = s_Video.maxWindowData + 1; - data = palAllocate(s_Video.allocator, sizeof(WindowData) * count, 0); - if (data) { - memcpy(data, s_Video.windowData, s_Video.maxWindowData * sizeof(WindowData)); - - palFree(s_Video.allocator, s_Video.windowData); - s_Video.windowData = data; - s_Video.maxWindowData = count; - - s_Video.windowData[freeIndex].used = PAL_TRUE; - return &s_Video.windowData[freeIndex]; - } - return nullptr; -} - -static WindowData* findWindowData(PalWindow* window) -{ - for (int i = 0; i < s_Video.maxWindowData; ++i) { - if (s_Video.windowData[i].used && s_Video.windowData[i].window == window) { - return &s_Video.windowData[i]; - } - } - return nullptr; -} - -static void resetMonitorData() -{ - memset(s_Video.monitorData, 0, s_Video.maxMonitorData * sizeof(MonitorData)); -} - -static MonitorData* getFreeMonitorData() -{ - for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (!s_Video.monitorData[i].used) { - s_Video.monitorData[i].used = PAL_TRUE; - return &s_Video.monitorData[i]; - } - } - - // resize the data array - // this will almost not reach here since most setups are 1-4 monitors - MonitorData* data = nullptr; - int count = s_Video.maxMonitorData * 2; // double the size - int freeIndex = s_Video.maxMonitorData + 1; - data = palAllocate(s_Video.allocator, sizeof(MonitorData) * count, 0); - if (data) { - memcpy(data, s_Video.monitorData, s_Video.maxMonitorData * sizeof(MonitorData)); - - palFree(s_Video.allocator, s_Video.monitorData); - s_Video.monitorData = data; - s_Video.maxWindowData = count; - - s_Video.monitorData[freeIndex].used = PAL_TRUE; - return &s_Video.monitorData[freeIndex]; - } - return nullptr; -} - -static MonitorData* findMonitorData(PalMonitor* monitor) -{ - for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (s_Video.monitorData[i].used && s_Video.monitorData[i].monitor == monitor) { - return &s_Video.monitorData[i]; - } - } - return nullptr; -} - -static void freeMonitorData(PalMonitor* monitor) -{ - for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (s_Video.monitorData[i].used && s_Video.monitorData[i].monitor == monitor) { - s_Video.monitorData[i].used = PAL_FALSE; - } - } -} - -static inline uint64_t getCurrentTime() -{ - uint64_t now = palGetPerformanceCounter(); - return (now * 1000) / s_Keyboard.frequency; -} - -#endif // __linux__ -#endif // _PAL_VIDEO_LINUX_H \ No newline at end of file diff --git a/src/video/pal_video.c b/src/video/pal_video.c new file mode 100644 index 00000000..4f56d736 --- /dev/null +++ b/src/video/pal_video.c @@ -0,0 +1,820 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal_video_backends.h" +#include "pal_video_egl.h" +#include + +typedef struct { + PalBool initialized; + const Backend* backend; +} Video; + +EGL s_Egl = {0}; +static Video s_Video = {0}; + +static int compareModes( + const void* a, + const void* b) +{ + const PalMonitorMode* mode1 = (const PalMonitorMode*)a; + const PalMonitorMode* mode2 = (const PalMonitorMode*)b; + + // compare width + if (mode1->width > mode2->width) { + return -1; + } + + if (mode1->width < mode2->width) { + return 1; + } + + // compare height + if (mode1->height > mode2->height) { + return -1; + } + + if (mode1->height < mode2->height) { + return 1; + } + + // compare refresh rate + if (mode1->refreshRate > mode2->refreshRate) { + return -1; + } + + if (mode1->refreshRate < mode2->refreshRate) { + return 1; + } + + // compare bpp + if (mode1->bpp > mode2->bpp) { + return -1; + } + + if (mode1->bpp < mode2->bpp) { + return 1; + } + + return 0; +} + +PalResult PAL_CALL palInitVideo( + const PalAllocator* allocator, + PalEventDriver* eventDriver, + void* preferredInstance) +{ + if (s_Video.initialized) { + return PAL_RESULT_SUCCESS; + } + + if (allocator && (!allocator->allocate || !allocator->free)) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + // check if x11 or wayland is active + PalBool x11 = PAL_FALSE; + PalBool wayland = PAL_FALSE; + const char* session = getenv("XDG_SESSION_TYPE"); + if (session) { + if (strcmp(session, "wayland") == 0) { + wayland = PAL_TRUE; + } else { + x11 = PAL_TRUE; + } + } + + // initialize the backends +#ifdef _WIN32 + PalResult result = win32InitVideo(allocator, eventDriver, preferredInstance); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + s_Video.backend = &s_Win32Backend; +#endif // _WIN32 + + if (x11) { +#if PAL_HAS_X11_BACKEND == 1 + PalResult result = xInitVideo(allocator, eventDriver, preferredInstance); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + s_Video.backend = &s_XBackend; +#endif // PAL_HAS_X11_BACKEND + + } else if (wayland) { +#if PAL_HAS_WAYLAND_BACKEND == 1 + PalResult result = wlInitVideo(allocator, eventDriver, preferredInstance); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + s_Video.backend = &s_wlBackend; +#endif // PAL_HAS_WAYLAND_BACKEND + } + + // check if we found a backend + if (!s_Video.backend) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + + s_Video.initialized = PAL_TRUE; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palShutdownVideo() +{ + if (s_Video.initialized) { + s_Video.backend->shutdownVideo(); + s_Video.initialized = PAL_FALSE; + } +} + +void PAL_CALL palUpdateVideo() +{ + if (s_Video.initialized) { + s_Video.backend->updateVideo(); + } +} + +PalVideoFeatures PAL_CALL palGetVideoFeatures() +{ + if (s_Video.initialized) { + s_Video.backend->getVideoFeatures(); + } +} + +PalResult PAL_CALL palEnumerateMonitors( + int32_t* count, + PalMonitor** outMonitors) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!count || *count == 0 && outMonitors) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->enumerateMonitors(count, outMonitors); +} + +PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!outMonitor) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->getPrimaryMonitor(outMonitor); +} + +PalResult PAL_CALL palGetMonitorInfo( + PalMonitor* monitor, + PalMonitorInfo* info) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!info) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->getMonitorInfo(monitor, info); +} + +PalResult PAL_CALL palEnumerateMonitorModes( + PalMonitor* monitor, + int32_t* count, + PalMonitorMode* modes) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!monitor || !count || *count == 0 && modes) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + PalResult result = s_Video.backend->enumerateMonitorModes(monitor, count, modes); + if (result == PAL_RESULT_SUCCESS && modes) { + // sort the modes so that they are highest to lowest + qsort(modes, *count, sizeof(PalMonitorMode), compareModes); + } +} + +PalResult PAL_CALL palGetCurrentMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!monitor || !mode) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->getCurrentMonitorMode(monitor, mode); +} + +PalResult PAL_CALL palSetMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!monitor || !mode) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->setMonitorMode(monitor, mode); +} + +PalResult PAL_CALL palValidateMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!monitor || !mode) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->validateMonitorMode(monitor, mode); +} + +PalResult PAL_CALL palSetMonitorOrientation( + PalMonitor* monitor, + PalOrientation orientation) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!monitor) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->setMonitorOrientation(monitor, orientation); +} + +PalResult PAL_CALL palCreateWindow( + const PalWindowCreateInfo* info, + PalWindow** outWindow) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!info || !outWindow) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->createWindow(info, outWindow); +} + +void PAL_CALL palDestroyWindow(PalWindow* window) +{ + if (s_Video.initialized && window) { + return s_Video.backend->destroyWindow(window); + } +} + +PalResult PAL_CALL palMinimizeWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->maximizeWindow(window); +} + +PalResult PAL_CALL palMaximizeWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->minimizeWindow(window); +} + +PalResult PAL_CALL palRestoreWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->restoreWindow(window); +} + +PalResult PAL_CALL palShowWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->showWindow(window); +} + +PalResult PAL_CALL palHideWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->hideWindow(window); +} + +PalResult PAL_CALL palFlashWindow( + PalWindow* window, + const PalFlashInfo* info) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window || !info) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->flashWindow(window, info); +} + +PalResult PAL_CALL palGetWindowStyle( + PalWindow* window, + PalWindowStyle* outStyle) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window || !outStyle) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->getWindowStyle(window, outStyle); +} + +PalResult PAL_CALL palGetWindowMonitor( + PalWindow* window, + PalMonitor** outMonitor) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window || !outMonitor) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->getWindowMonitor(window, outMonitor); +} + +PalResult PAL_CALL palGetWindowTitle( + PalWindow* window, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window || !outBuffer) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->getWindowTitle(window, bufferSize, outSize, outBuffer); +} + +PalResult PAL_CALL palGetWindowPos( + PalWindow* window, + int32_t* x, + int32_t* y) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->getWindowPos(window, x, y); +} + +PalResult PAL_CALL palGetWindowSize( + PalWindow* window, + uint32_t* width, + uint32_t* height) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->getWindowSize(window, width, height); +} + +PalResult PAL_CALL palGetWindowState( + PalWindow* window, + PalWindowState* outState) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window || !outState) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->getWindowState(window, outState); +} + +const PalBool* PAL_CALL palGetKeycodeState() +{ + if (s_Video.initialized) { + return s_Video.backend->getKeycodeState(); + } + return nullptr; +} + +const PalBool* PAL_CALL palGetScancodeState() +{ + if (s_Video.initialized) { + return s_Video.backend->getScancodeState(); + } + return nullptr; +} + +const PalBool* PAL_CALL palGetMouseState() +{ + if (s_Video.initialized) { + return s_Video.backend->getMouseState(); + } + return nullptr; +} + +void PAL_CALL palGetMouseDelta( + float* dx, + float* dy) +{ + if (s_Video.initialized) { + return s_Video.backend->getMouseDelta(dx, dy); + } +} + +void PAL_CALL palGetMouseWheelDelta( + float* dx, + float* dy) +{ + if (s_Video.initialized) { + return s_Video.backend->getMouseWheelDelta(dx, dy); + } +} + +PalBool PAL_CALL palIsWindowVisible(PalWindow* window) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->isWindowVisible(window); +} + +PalWindow* PAL_CALL palGetFocusWindow() +{ + if (!s_Video.initialized) { + return nullptr; + } + + return s_Video.backend->getFocusWindow(); +} + +PalResult PAL_CALL palGetWindowHandleInfo( + PalWindow* window, + PalWindowHandleInfo* info) +{ + if (s_Video.initialized) { + return s_Video.backend->getWindowHandleInfo(window, info); + } + return PAL_RESULT_CODE_NOT_INITIALIZED; +} + +PalResult PAL_CALL palSetWindowOpacity( + PalWindow* window, + float opacity) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (opacity < 0.0f) { + opacity = 0.0f; + } + + if (opacity > 1.0f) { + opacity = 1.0f; + } + + return s_Video.backend->setWindowOpacity(window, opacity); +} + +PalResult PAL_CALL palSetWindowStyle( + PalWindow* window, + PalWindowStyle style) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->setWindowStyle(window, style); +} + +PalResult PAL_CALL palSetWindowTitle( + PalWindow* window, + const char* title) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window || !title) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->setWindowTitle(window, title); +} + +PalResult PAL_CALL palSetWindowPos( + PalWindow* window, + int32_t x, + int32_t y) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->setWindowPos(window, x, y); +} + +PalResult PAL_CALL palSetWindowSize( + PalWindow* window, + uint32_t width, + uint32_t height) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->setWindowSize(window, width, height); +} + +PalResult PAL_CALL palSetFocusWindow(PalWindow* window) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->setFocusWindow(window); +} + +PalResult PAL_CALL palCreateIcon( + const PalIconCreateInfo* info, + PalIcon** outIcon) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!info || !outIcon) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->createIcon(info, outIcon); +} + +void PAL_CALL palDestroyIcon(PalIcon* icon) +{ + if (s_Video.initialized && icon) { + s_Video.backend->destroyIcon(icon); + } +} + +PalResult PAL_CALL palSetWindowIcon( + PalWindow* window, + PalIcon* icon) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->setWindowIcon(window, icon); +} + +PalResult PAL_CALL palCreateCursor( + const PalCursorCreateInfo* info, + PalCursor** outCursor) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!info || !outCursor) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->createCursor(info, outCursor); +} + +PalResult PAL_CALL palCreateCursorFrom( + PalCursorType type, + PalCursor** outCursor) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!outCursor) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->createCursorFrom(type, outCursor); +} + +void PAL_CALL palDestroyCursor(PalCursor* cursor) +{ + if (s_Video.initialized && cursor) { + s_Video.backend->destroyCursor(cursor); + } +} + +void PAL_CALL palShowCursor(PalBool show) +{ + if (s_Video.initialized) { + s_Video.backend->showCursor(show); + } +} + +PalResult PAL_CALL palClipCursor( + PalWindow* window, + PalBool clip) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->clipCursor(window, clip); +} + +PalResult PAL_CALL palGetCursorPos( + PalWindow* window, + int32_t* x, + int32_t* y) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->getCursorPos(window, x, y); +} + +PalResult PAL_CALL palSetCursorPos( + PalWindow* window, + int32_t x, + int32_t y) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->setCursorPos(window, x, y); +} + +PalResult PAL_CALL palSetWindowCursor( + PalWindow* window, + PalCursor* cursor) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->setWindowCursor(window, cursor); +} + +PalResult PAL_CALL palAttachWindow( + void* windowHandle, + PalWindow** outWindow) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!windowHandle) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->attachWindow(windowHandle, outWindow); +} + +PalResult PAL_CALL palDetachWindow( + PalWindow* window, + void** outWindowHandle) +{ + if (!s_Video.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!window) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Video.backend->detachWindow(window, outWindowHandle); +} + +void* PAL_CALL palGetInstance() +{ + if (s_Video.initialized) { + return s_Video.backend->getInstance(); + } + return nullptr; +} \ No newline at end of file diff --git a/src/video/pal_video_backends.h b/src/video/pal_video_backends.h new file mode 100644 index 00000000..b4852773 --- /dev/null +++ b/src/video/pal_video_backends.h @@ -0,0 +1,446 @@ +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_BACKENDS_LINUX_H +#define _PAL_BACKENDS_LINUX_H + +#include "pal/pal_video.h" + +typedef struct { + // clang-format off + void (*shutdownVideo)(); + void (*updateVideo)(); + PalVideoFeatures (*getVideoFeatures)(); + PalResult (*enumerateMonitors)(int32_t*, PalMonitor**); + PalResult (*getPrimaryMonitor)(PalMonitor**); + PalResult (*getMonitorInfo)(PalMonitor*, PalMonitorInfo*); + PalResult (*enumerateMonitorModes)(PalMonitor*, int32_t*, PalMonitorMode*); + PalResult (*getCurrentMonitorMode)(PalMonitor*, PalMonitorMode*); + PalResult (*setMonitorMode)(PalMonitor*, PalMonitorMode*); + PalResult (*validateMonitorMode)(PalMonitor*, PalMonitorMode*); + PalResult (*setMonitorOrientation)(PalMonitor*, PalOrientation); + + PalResult (*createWindow)(const PalWindowCreateInfo*, PalWindow**); + void (*destroyWindow)(PalWindow*); + PalResult (*maximizeWindow)(PalWindow*); + PalResult (*minimizeWindow)(PalWindow*); + PalResult (*restoreWindow)(PalWindow*); + PalResult (*showWindow)(PalWindow*); + PalResult (*hideWindow)(PalWindow*); + PalResult (*flashWindow)(PalWindow*, const PalFlashInfo*); + PalResult (*getWindowStyle)(PalWindow*, PalWindowStyle*); + PalResult (*getWindowMonitor)(PalWindow*, PalMonitor**); + PalResult (*getWindowTitle)(PalWindow*, uint64_t, uint64_t*, char*); + PalResult (*getWindowPos)(PalWindow*, int32_t*, int32_t*); + PalResult (*getWindowSize)(PalWindow*, uint32_t*, uint32_t*); + PalResult (*getWindowState)(PalWindow*, PalWindowState*); + const PalBool* (*getKeycodeState)(); + const PalBool* (*getScancodeState)(); + const PalBool* (*getMouseState)(); + void (*getMouseDelta)(float*, float*); + void (*getMouseWheelDelta)(float*, float*); + PalBool (*isWindowVisible)(PalWindow*); + PalWindow* (*getFocusWindow)(); + PalResult (*getWindowHandleInfo)(PalWindow*, PalWindowHandleInfo*); + PalResult (*setWindowOpacity)(PalWindow*, float); + PalResult (*setWindowStyle)(PalWindow*, PalWindowStyle); + PalResult (*setWindowTitle)(PalWindow*, const char*); + PalResult (*setWindowPos)(PalWindow*, int32_t, int32_t); + PalResult (*setWindowSize)(PalWindow*, uint32_t, uint32_t); + PalResult (*setFocusWindow)(PalWindow*); + + PalResult (*createIcon)(const PalIconCreateInfo*, PalIcon**); + void (*destroyIcon)(PalIcon*); + PalResult (*setWindowIcon)(PalWindow*, PalIcon*); + + PalResult (*createCursor)(const PalCursorCreateInfo*, PalCursor**); + PalResult (*createCursorFrom)(PalCursorType, PalCursor**); + void (*destroyCursor)(PalCursor*); + void (*showCursor)(PalBool); + PalResult (*clipCursor)(PalWindow*, PalBool); + PalResult (*getCursorPos)(PalWindow*, int32_t*, int32_t*); + PalResult (*setCursorPos)(PalWindow*, int32_t, int32_t); + PalResult (*setWindowCursor)(PalWindow*, PalCursor*); + PalResult (*attachWindow)(void*, PalWindow**); + PalResult (*detachWindow)(PalWindow*, void**); + void* (*getInstance)(); + // clang-format on +} Backend; + +// ================================================== +// WIN32 +// ================================================== + +#ifdef _WIN32 +PalResult win32InitVideo(const PalAllocator*, PalEventDriver*, void*); +void win32ShutdownVideo(); +void win32UpdateVideo(); +PalVideoFeatures win32GetVideoFeatures(); + +PalResult win32EnumerateMonitors(int32_t*, PalMonitor**); +PalResult win32GetPrimaryMonitor(PalMonitor**); +PalResult win32GetMonitorInfo(PalMonitor*, PalMonitorInfo*); +PalResult win32EnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); +PalResult win32GetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult win32SetMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult win32ValidateMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult win32SetMonitorOrientation(PalMonitor*, PalOrientation); + +PalResult win32CreateWindow(const PalWindowCreateInfo*, PalWindow**); +void win32DestroyWindow(PalWindow*); +PalResult win32MaximizeWindow(PalWindow*); +PalResult win32MinimizeWindow(PalWindow*); +PalResult win32RestoreWindow(PalWindow*); +PalResult win32ShowWindow(PalWindow*); +PalResult win32HideWindow(PalWindow*); +PalResult win32FlashWindow(PalWindow*, const PalFlashInfo*); +PalResult win32GetWindowStyle(PalWindow*, PalWindowStyle*); +PalResult win32GetWindowMonitor(PalWindow*, PalMonitor**); +PalResult win32GetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); +PalResult win32GetWindowPos(PalWindow*, int32_t*, int32_t*); +PalResult win32GetWindowSize(PalWindow*, uint32_t*, uint32_t*); +PalResult win32GetWindowState(PalWindow*, PalWindowState*); +const PalBool* win32GetKeycodeState(); +const PalBool* win32GetScancodeState(); +const PalBool* win32GetMouseState(); +void win32GetMouseDelta(float*, float*); +void win32GetMouseWheelDelta(float*, float*); +PalBool win32IsWindowVisible(PalWindow*); +PalWindow* win32GetFocusWindow(); +PalResult win32GetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); +PalResult win32SetWindowOpacity(PalWindow*, float); +PalResult win32SetWindowStyle(PalWindow*, PalWindowStyle); +PalResult win32SetWindowTitle(PalWindow*, const char*); +PalResult win32SetWindowPos(PalWindow*, int32_t, int32_t); +PalResult win32SetWindowSize(PalWindow*, uint32_t, uint32_t); +PalResult win32SetFocusWindow(PalWindow*); + +PalResult win32CreateIcon(const PalIconCreateInfo*, PalIcon**); +void win32DestroyIcon(PalIcon*); +PalResult win32SetWindowIcon(PalWindow*, PalIcon*); + +PalResult win32CreateCursor(const PalCursorCreateInfo*, PalCursor**); +PalResult win32CreateCursorFrom(PalCursorType, PalCursor**); +void win32DestroyCursor(PalCursor*); +void win32ShowCursor(PalBool); +PalResult win32ClipCursor(PalWindow*, PalBool); +PalResult win32GetCursorPos(PalWindow*, int32_t*, int32_t*); +PalResult win32SetCursorPos(PalWindow*, int32_t, int32_t); +PalResult win32SetWindowCursor(PalWindow*, PalCursor*); +PalResult win32AttachWindow(void*, PalWindow**); +PalResult win32DetachWindow(PalWindow*, void**); +void* win32GetInstance(); + +static Backend s_Win32Backend = { + .shutdownVideo = win32ShutdownVideo, + .updateVideo = win32UpdateVideo, + .getVideoFeatures = win32GetVideoFeatures, + .enumerateMonitors = win32EnumerateMonitors, + .getMonitorInfo = win32GetMonitorInfo, + .getPrimaryMonitor = win32GetPrimaryMonitor, + .enumerateMonitorModes = win32EnumerateMonitorModes, + .getCurrentMonitorMode = win32GetCurrentMonitorMode, + .setMonitorMode = win32SetMonitorMode, + .validateMonitorMode = win32ValidateMonitorMode, + .setMonitorOrientation = win32SetMonitorOrientation, + + .createWindow = win32CreateWindow, + .destroyWindow = win32DestroyWindow, + .maximizeWindow = win32MaximizeWindow, + .minimizeWindow = win32MinimizeWindow, + .restoreWindow = win32RestoreWindow, + .showWindow = win32ShowWindow, + .hideWindow = win32HideWindow, + .flashWindow = win32FlashWindow, + .getWindowStyle = win32GetWindowStyle, + .getWindowMonitor = win32GetWindowMonitor, + .getWindowTitle = win32GetWindowTitle, + .getWindowPos = win32GetWindowPos, + .getWindowSize = win32GetWindowSize, + .getWindowState = win32GetWindowState, + .getKeycodeState = win32GetKeycodeState, + .getScancodeState = win32GetScancodeState, + .getMouseState = win32GetMouseState, + .getMouseDelta = win32GetMouseDelta, + .getMouseWheelDelta = win32GetMouseWheelDelta, + .isWindowVisible = win32IsWindowVisible, + .getFocusWindow = win32GetFocusWindow, + .getWindowHandleInfo = win32GetWindowHandleInfo, + .setWindowOpacity = win32SetWindowOpacity, + .setWindowStyle = win32SetWindowStyle, + .setWindowTitle = win32SetWindowTitle, + .setWindowPos = win32SetWindowPos, + .setWindowSize = win32SetWindowSize, + .setFocusWindow = win32SetFocusWindow, + + .createIcon = win32CreateIcon, + .destroyIcon = win32DestroyIcon, + .setWindowIcon = win32SetWindowIcon, + + .createCursor = win32CreateCursor, + .createCursorFrom = win32CreateCursorFrom, + .destroyCursor = win32DestroyCursor, + .showCursor = win32ShowCursor, + .clipCursor = win32ClipCursor, + .getCursorPos = win32GetCursorPos, + .setCursorPos = win32SetCursorPos, + .setWindowCursor = win32SetWindowCursor, + .attachWindow = win32AttachWindow, + .getInstance = win32GetInstance, + .detachWindow = win32DetachWindow}; + +#endif // _WIN32 + +// ================================================== +// X11 +// ================================================== + +#if PAL_HAS_X11_BACKEND == 1 +PalResult xInitVideo(const PalAllocator*, PalEventDriver*, void*); +void xShutdownVideo(); +void xUpdateVideo(); +PalVideoFeatures xGetVideoFeatures(); + +PalResult xEnumerateMonitors(int32_t*, PalMonitor**); +PalResult xGetPrimaryMonitor(PalMonitor**); +PalResult xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); +PalResult xEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); +PalResult xGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult xSetMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult xValidateMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult xSetMonitorOrientation(PalMonitor*, PalOrientation); + +PalResult xCreateWindow(const PalWindowCreateInfo*, PalWindow**); +void xDestroyWindow(PalWindow*); +PalResult xMaximizeWindow(PalWindow*); +PalResult xMinimizeWindow(PalWindow*); +PalResult xRestoreWindow(PalWindow*); +PalResult xShowWindow(PalWindow*); +PalResult xHideWindow(PalWindow*); +PalResult xFlashWindow(PalWindow*, const PalFlashInfo*); +PalResult xGetWindowStyle(PalWindow*, PalWindowStyle*); +PalResult xGetWindowMonitor(PalWindow*, PalMonitor**); +PalResult xGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); +PalResult xGetWindowPos(PalWindow*, int32_t*, int32_t*); +PalResult xGetWindowSize(PalWindow*, uint32_t*, uint32_t*); +PalResult xGetWindowState(PalWindow*, PalWindowState*); +const PalBool* xGetKeycodeState(); +const PalBool* xGetScancodeState(); +const PalBool* xGetMouseState(); +void xGetMouseDelta(float*, float*); +void xGetMouseWheelDelta(float*, float*); +PalBool xIsWindowVisible(PalWindow*); +PalWindow* xGetFocusWindow(); +PalResult xGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); +PalResult xSetWindowOpacity(PalWindow*, float); +PalResult xSetWindowStyle(PalWindow*, PalWindowStyle); +PalResult xSetWindowTitle(PalWindow*, const char*); +PalResult xSetWindowPos(PalWindow*, int32_t, int32_t); +PalResult xSetWindowSize(PalWindow*, uint32_t, uint32_t); +PalResult xSetFocusWindow(PalWindow*); + +PalResult xCreateIcon(const PalIconCreateInfo*, PalIcon**); +void xDestroyIcon(PalIcon*); +PalResult xSetWindowIcon(PalWindow*, PalIcon*); + +PalResult xCreateCursor(const PalCursorCreateInfo*, PalCursor**); +PalResult xCreateCursorFrom(PalCursorType, PalCursor**); +void xDestroyCursor(PalCursor*); +void xShowCursor(PalBool); +PalResult xClipCursor(PalWindow*, PalBool); +PalResult xGetCursorPos(PalWindow*, int32_t*, int32_t*); +PalResult xSetCursorPos(PalWindow*, int32_t, int32_t); +PalResult xSetWindowCursor(PalWindow*, PalCursor*); +PalResult xAttachWindow(void*, PalWindow**); +PalResult xDetachWindow(PalWindow*, void**); +void* xGetInstance(); + +static Backend s_XBackend = { + .shutdownVideo = xShutdownVideo, + .updateVideo = xUpdateVideo, + .getVideoFeatures = xGetVideoFeatures, + .enumerateMonitors = xEnumerateMonitors, + .getMonitorInfo = xGetMonitorInfo, + .getPrimaryMonitor = xGetPrimaryMonitor, + .enumerateMonitorModes = xEnumerateMonitorModes, + .getCurrentMonitorMode = xGetCurrentMonitorMode, + .setMonitorMode = xSetMonitorMode, + .validateMonitorMode = xValidateMonitorMode, + .setMonitorOrientation = xSetMonitorOrientation, + + .createWindow = xCreateWindow, + .destroyWindow = xDestroyWindow, + .maximizeWindow = xMaximizeWindow, + .minimizeWindow = xMinimizeWindow, + .restoreWindow = xRestoreWindow, + .showWindow = xShowWindow, + .hideWindow = xHideWindow, + .flashWindow = xFlashWindow, + .getWindowStyle = xGetWindowStyle, + .getWindowMonitor = xGetWindowMonitor, + .getWindowTitle = xGetWindowTitle, + .getWindowPos = xGetWindowPos, + .getWindowSize = xGetWindowSize, + .getWindowState = xGetWindowState, + .getKeycodeState = xGetKeycodeState, + .getScancodeState = xGetScancodeState, + .getMouseState = xGetMouseState, + .getMouseDelta = xGetMouseDelta, + .getMouseWheelDelta = xGetMouseWheelDelta, + .isWindowVisible = xIsWindowVisible, + .getFocusWindow = xGetFocusWindow, + .getWindowHandleInfo = xGetWindowHandleInfo, + .setWindowOpacity = xSetWindowOpacity, + .setWindowStyle = xSetWindowStyle, + .setWindowTitle = xSetWindowTitle, + .setWindowPos = xSetWindowPos, + .setWindowSize = xSetWindowSize, + .setFocusWindow = xSetFocusWindow, + + .createIcon = xCreateIcon, + .destroyIcon = xDestroyIcon, + .setWindowIcon = xSetWindowIcon, + + .createCursor = xCreateCursor, + .createCursorFrom = xCreateCursorFrom, + .destroyCursor = xDestroyCursor, + .showCursor = xShowCursor, + .clipCursor = xClipCursor, + .getCursorPos = xGetCursorPos, + .setCursorPos = xSetCursorPos, + .setWindowCursor = xSetWindowCursor, + .attachWindow = xAttachWindow, + .getInstance = xGetInstance, + .detachWindow = xDetachWindow}; + +#endif // PAL_HAS_X11_BACKEND + +// ================================================== +// Wayland +// ================================================== + +#if PAL_HAS_WAYLAND_BACKEND == 1 +PalResult wlInitVideo(const PalAllocator*, PalEventDriver*, void*); +void wlShutdownVideo(); +void wlUpdateVideo(); +void wlUpdateVideo(); +PalVideoFeatures wlGetVideoFeatures(); + +PalResult wlEnumerateMonitors(int32_t*, PalMonitor**); +PalResult wlGetPrimaryMonitor(PalMonitor**); +PalResult wlGetMonitorInfo(PalMonitor*, PalMonitorInfo*); +PalResult wlEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); +PalResult wlGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult wlSetMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult wlValidateMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult wlSetMonitorOrientation(PalMonitor*, PalOrientation); + +PalResult wlCreateWindow(const PalWindowCreateInfo*, PalWindow**); +void wlDestroyWindow(PalWindow*); +PalResult wlMaximizeWindow(PalWindow*); +PalResult wlMinimizeWindow(PalWindow*); +PalResult wlRestoreWindow(PalWindow*); +PalResult wlShowWindow(PalWindow*); +PalResult wlHideWindow(PalWindow*); +PalResult wlFlashWindow(PalWindow*, const PalFlashInfo*); +PalResult wlGetWindowStyle(PalWindow*, PalWindowStyle*); +PalResult wlGetWindowMonitor(PalWindow*, PalMonitor**); +PalResult wlGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); +PalResult wlGetWindowPos(PalWindow*, int32_t*, int32_t*); +PalResult wlGetWindowSize(PalWindow*, uint32_t*, uint32_t*); +PalResult wlGetWindowState(PalWindow*, PalWindowState*); +const PalBool* wlGetKeycodeState(); +const PalBool* wlGetScancodeState(); +const PalBool* wlGetMouseState(); +void wlGetMouseDelta(float*, float*); +void wlGetMouseWheelDelta(float*, float*); +PalBool wlIsWindowVisible(PalWindow*); +PalWindow* wlGetFocusWindow(); +PalResult wlGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); +PalResult wlSetWindowOpacity(PalWindow*, float); +PalResult wlSetWindowStyle(PalWindow*, PalWindowStyle); +PalResult wlSetWindowTitle(PalWindow*, const char*); +PalResult wlSetWindowPos(PalWindow*, int32_t, int32_t); +PalResult wlSetWindowSize(PalWindow*, uint32_t, uint32_t); +PalResult wlSetFocusWindow(PalWindow*); + +PalResult wlCreateIcon(const PalIconCreateInfo*, PalIcon**); +void wlDestroyIcon(PalIcon*); +PalResult wlSetWindowIcon(PalWindow*, PalIcon*); + +PalResult wlCreateCursor(const PalCursorCreateInfo*, PalCursor**); +PalResult wlCreateCursorFrom(PalCursorType, PalCursor**); +void wlDestroyCursor(PalCursor*); +void wlShowCursor(PalBool); +PalResult wlClipCursor(PalWindow*, PalBool); +PalResult wlGetCursorPos(PalWindow*, int32_t*, int32_t*); +PalResult wlSetCursorPos(PalWindow*, int32_t, int32_t); +PalResult wlSetWindowCursor(PalWindow*, PalCursor*); +PalResult wlAttachWindow(void*, PalWindow**); +PalResult wlDetachWindow(PalWindow*, void**); +void* wlGetInstance(); + +static Backend s_wlBackend = { + .shutdownVideo = wlShutdownVideo, + .updateVideo = wlUpdateVideo, + .getVideoFeatures = wlGetVideoFeatures, + .enumerateMonitors = wlEnumerateMonitors, + .getMonitorInfo = wlGetMonitorInfo, + .getPrimaryMonitor = wlGetPrimaryMonitor, + .enumerateMonitorModes = wlEnumerateMonitorModes, + .getCurrentMonitorMode = wlGetCurrentMonitorMode, + .setMonitorMode = wlSetMonitorMode, + .validateMonitorMode = wlValidateMonitorMode, + .setMonitorOrientation = wlSetMonitorOrientation, + + .createWindow = wlCreateWindow, + .destroyWindow = wlDestroyWindow, + .maximizeWindow = wlMaximizeWindow, + .minimizeWindow = wlMinimizeWindow, + .restoreWindow = wlRestoreWindow, + .showWindow = wlShowWindow, + .hideWindow = wlHideWindow, + .flashWindow = wlFlashWindow, + .getWindowStyle = wlGetWindowStyle, + .getWindowMonitor = wlGetWindowMonitor, + .getWindowTitle = wlGetWindowTitle, + .getWindowPos = wlGetWindowPos, + .getWindowSize = wlGetWindowSize, + .getWindowState = wlGetWindowState, + .getKeycodeState = wlGetKeycodeState, + .getScancodeState = wlGetScancodeState, + .getMouseState = wlGetMouseState, + .getMouseDelta = wlGetMouseDelta, + .getMouseWheelDelta = wlGetMouseWheelDelta, + .isWindowVisible = wlIsWindowVisible, + .getFocusWindow = wlGetFocusWindow, + .getWindowHandleInfo = wlGetWindowHandleInfo, + .setWindowOpacity = wlSetWindowOpacity, + .setWindowStyle = wlSetWindowStyle, + .setWindowTitle = wlSetWindowTitle, + .setWindowPos = wlSetWindowPos, + .setWindowSize = wlSetWindowSize, + .setFocusWindow = wlSetFocusWindow, + + .createIcon = wlCreateIcon, + .destroyIcon = wlDestroyIcon, + .setWindowIcon = wlSetWindowIcon, + + .createCursor = wlCreateCursor, + .createCursorFrom = wlCreateCursorFrom, + .destroyCursor = wlDestroyCursor, + .showCursor = wlShowCursor, + .clipCursor = wlClipCursor, + .getCursorPos = wlGetCursorPos, + .setCursorPos = wlSetCursorPos, + .setWindowCursor = wlSetWindowCursor, + .attachWindow = wlAttachWindow, + .getInstance = wlGetInstance, + .detachWindow = wlDetachWindow}; + +#endif // PAL_HAS_WAYLAND_BACKEND + +#endif // _PAL_BACKENDS_LINUX_H \ No newline at end of file diff --git a/src/video/pal_video_egl.h b/src/video/pal_video_egl.h new file mode 100644 index 00000000..0ae5e47e --- /dev/null +++ b/src/video/pal_video_egl.h @@ -0,0 +1,81 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_VIDEO_EGL_H +#define _PAL_VIDEO_EGL_H + +#include + +#define EGL_CAST(type, value) ((type)(value)) +#define EGL_OPENGL_API 0x30A2 +#define EGL_OPENGL_BIT 0x0008 +#define EGL_OPENGL_ES_BIT 0x0001 +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0) +#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0) +#define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0) +#define EGL_NATIVE_VISUAL_ID 0x302E + +typedef void* EGLConfig; +typedef void* EGLSurface; +typedef void* EGLContext; +typedef void* EGLDisplay; +typedef void* EGLNativeDisplayType; + +typedef int32_t EGLint; +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; + +typedef void* (*eglGetProcAddressFn)(const char*); + +typedef EGLBoolean (*eglInitializeFn)( + EGLDisplay, + EGLint*, + EGLint*); + +typedef EGLBoolean (*eglTerminateFn)(EGLDisplay); + +typedef EGLDisplay (*eglGetDisplayFn)(void*); + +typedef EGLBoolean (*eglChooseConfigFn)( + EGLDisplay, + const EGLint*, + EGLConfig*, + EGLint, + EGLint*); + +typedef EGLBoolean (*eglGetConfigAttribFn)( + EGLDisplay, + EGLConfig, + EGLint, + EGLint*); + +typedef EGLint (*eglGetErrorFn)(void); + +typedef EGLBoolean (*eglBindAPIFn)(EGLenum); + +typedef EGLBoolean (*eglGetConfigsFn)( + EGLDisplay, + EGLConfig*, + EGLint, + EGLint*); + +typedef struct { + void* handle; + eglInitializeFn eglInitialize; + eglTerminateFn eglTerminate; + eglGetDisplayFn eglGetDisplay; + eglChooseConfigFn eglChooseConfig; + eglGetConfigAttribFn eglGetConfigAttrib; + eglGetErrorFn eglGetError; + eglBindAPIFn eglBindAPI; + eglGetConfigsFn eglGetConfigs; +} EGL; + +extern EGL s_Egl; + +#endif // _PAL_VIDEO_EGL_H \ No newline at end of file diff --git a/src/video/linux/wayland/pal_cursor_wayland.c b/src/video/wayland/pal_cursor_wayland.c similarity index 59% rename from src/video/linux/wayland/pal_cursor_wayland.c rename to src/video/wayland/pal_cursor_wayland.c index b849eac0..0d6d4e49 100644 --- a/src/video/linux/wayland/pal_cursor_wayland.c +++ b/src/video/wayland/pal_cursor_wayland.c @@ -5,40 +5,29 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_WAYLAND_BACKEND == 1 - #include "pal_wayland.h" #include "pal_wayland_protocols.h" -#include "pal_shared.h" +#include PalResult wlCreateCursor( const PalCursorCreateInfo* info, PalCursor** outCursor) { WaylandCursor* cursor = nullptr; - cursor = palAllocate(s_Video.allocator, sizeof(WaylandCursor), 0); + cursor = palAllocate(s_Wl.allocator, sizeof(WaylandCursor), 0); if (!cursor) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } cursor->surface = wlCompositorCreateSurface(s_Wl.compositor); if (!cursor->surface) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } cursor->buffer = createShmBuffer(info->width, info->height, info->pixels, PAL_TRUE); if (!cursor->buffer) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } wlSurfaceAttach(cursor->surface, cursor->buffer, 0, 0); @@ -56,27 +45,27 @@ PalResult wlCreateCursorFrom( { const char* cursorType = nullptr; switch (type) { - case PAL_CURSOR_ARROW: { + case PAL_CURSOR_TYPE_ARROW: { cursorType = "left_ptr"; break; } - case PAL_CURSOR_HAND: { + case PAL_CURSOR_TYPE_HAND: { cursorType = "hand1"; break; } - case PAL_CURSOR_CROSS: { + case PAL_CURSOR_TYPE_CROSS: { cursorType = "crosshair"; break; } - case PAL_CURSOR_IBEAM: { + case PAL_CURSOR_TYPE_IBEAM: { cursorType = "text"; break; } - case PAL_CURSOR_WAIT: { + case PAL_CURSOR_TYPE_WAIT: { cursorType = "wait"; break; } @@ -85,27 +74,18 @@ PalResult wlCreateCursorFrom( struct wl_cursor* wlCursor = nullptr; wlCursor = s_Wl.cursorThemeGetCursor(s_Wl.cursorTheme, cursorType); if (!wlCursor) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } WaylandCursor* cursor = nullptr; - cursor = palAllocate(s_Video.allocator, sizeof(WaylandCursor), 0); + cursor = palAllocate(s_Wl.allocator, sizeof(WaylandCursor), 0); if (!cursor) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } cursor->surface = wlCompositorCreateSurface(s_Wl.compositor); if (!cursor->surface) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } cursor->buffer = s_Wl.cursorImageGetBuffer(wlCursor->images[0]); @@ -123,7 +103,7 @@ void wlDestroyCursor(PalCursor* cursor) WaylandCursor* waylandCursor = (WaylandCursor*)cursor; wlBufferDestroy(waylandCursor->buffer); wlSurfaceDestroy(waylandCursor->surface); - palFree(s_Video.allocator, waylandCursor); + palFree(s_Wl.allocator, waylandCursor); } void wlShowCursor(PalBool show) @@ -136,11 +116,8 @@ PalResult wlClipCursor( PalWindow* window, PalBool clip) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_CLIP_CURSOR)) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + if (!(s_Wl.features & PAL_VIDEO_FEATURE_CLIP_CURSOR)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } return PAL_RESULT_SUCCESS; @@ -151,10 +128,7 @@ PalResult wlGetCursorPos( int32_t* x, int32_t* y) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlSetCursorPos( @@ -162,27 +136,20 @@ PalResult wlSetCursorPos( int32_t x, int32_t y) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlSetWindowCursor( PalWindow* window, PalCursor* cursor) { - WindowData* data = findWindowData(window); + WindowData* data = wlFindWindowData(window); if (!data) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } data->cursor = cursor; return PAL_RESULT_SUCCESS; } -#endif // PAL_HAS_WAYLAND_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_WAYLAND_BACKEND \ No newline at end of file diff --git a/src/video/linux/wayland/pal_icon_wayland.c b/src/video/wayland/pal_icon_wayland.c similarity index 54% rename from src/video/linux/wayland/pal_icon_wayland.c rename to src/video/wayland/pal_icon_wayland.c index 6e8ec782..d0ade19d 100644 --- a/src/video/linux/wayland/pal_icon_wayland.c +++ b/src/video/wayland/pal_icon_wayland.c @@ -5,20 +5,14 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_WAYLAND_BACKEND == 1 - #include "pal_wayland.h" -#include "pal_shared.h" PalResult wlCreateIcon( const PalIconCreateInfo* info, PalIcon** outIcon) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } void wlDestroyIcon(PalIcon* icon) @@ -30,11 +24,7 @@ PalResult wlSetWindowIcon( PalWindow* window, PalIcon* icon) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } -#endif // PAL_HAS_WAYLAND_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_WAYLAND_BACKEND \ No newline at end of file diff --git a/src/video/linux/wayland/pal_monitor_wayland.c b/src/video/wayland/pal_monitor_wayland.c similarity index 64% rename from src/video/linux/wayland/pal_monitor_wayland.c rename to src/video/wayland/pal_monitor_wayland.c index 0c59909b..2511b33c 100644 --- a/src/video/linux/wayland/pal_monitor_wayland.c +++ b/src/video/wayland/pal_monitor_wayland.c @@ -5,11 +5,8 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_WAYLAND_BACKEND == 1 - #include "pal_wayland.h" -#include "pal_shared.h" PalResult wlEnumerateMonitors( int32_t* count, @@ -17,11 +14,11 @@ PalResult wlEnumerateMonitors( { if (outMonitors) { int index = 0; - int maxCount = s_Video.maxMonitorData; + int maxCount = s_Wl.maxMonitorData; for (int i = 0; i < maxCount && index < *count; i++) { - if (s_Video.monitorData[i].used) { + if (s_Wl.monitorData[i].used) { // found a monitor - PalMonitor* monitor = s_Video.monitorData[index].monitor; + PalMonitor* monitor = s_Wl.monitorData[index].monitor; outMonitors[index++] = monitor; } } @@ -36,22 +33,16 @@ PalResult wlEnumerateMonitors( PalResult wlGetPrimaryMonitor(PalMonitor** outMonitor) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlGetMonitorInfo( PalMonitor* monitor, PalMonitorInfo* info) { - MonitorData* monitorData = findMonitorData(monitor); + MonitorData* monitorData = wlFindMonitorData(monitor); if (!monitorData) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } info->dpi = monitorData->dpi; @@ -73,12 +64,9 @@ PalResult wlEnumerateMonitorModes( int32_t* count, PalMonitorMode* modes) { - MonitorData* monitorData = findMonitorData(monitor); + MonitorData* monitorData = wlFindMonitorData(monitor); if (!monitorData) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (modes && *count > 0) { @@ -100,12 +88,9 @@ PalResult wlGetCurrentMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - MonitorData* monitorData = findMonitorData(monitor); + MonitorData* monitorData = wlFindMonitorData(monitor); if (!monitorData) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // this is the same as the current mode @@ -121,31 +106,21 @@ PalResult wlSetMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlValidateMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlSetMonitorOrientation( PalMonitor* monitor, PalOrientation orientation) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } -#endif // PAL_HAS_WAYLAND_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_WAYLAND_BACKEND \ No newline at end of file diff --git a/src/video/linux/wayland/pal_video_wayland.c b/src/video/wayland/pal_video_wayland.c similarity index 71% rename from src/video/linux/wayland/pal_video_wayland.c rename to src/video/wayland/pal_video_wayland.c index c7ab71aa..df1ba846 100644 --- a/src/video/linux/wayland/pal_video_wayland.c +++ b/src/video/wayland/pal_video_wayland.c @@ -5,17 +5,48 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_WAYLAND_BACKEND == 1 - +#define _POSIX_C_SOURCE 200112L +#define _GNU_SOURCE #include "pal_wayland.h" #include "pal_wayland_protocols.h" -#include "pal_shared.h" +#include "video/pal_video_egl.h" #include #include #include +#include + +typedef struct { + PalBool pendingScroll; + int32_t lastX; + int32_t lastY; + int32_t dx; + int32_t dy; + int32_t WheelX; + int32_t WheelY; + PalBool state[PAL_MOUSE_BUTTON_COUNT]; + double tmpScrollX; + double tmpScrollY; + double accumScrollX; + double accumScrollY; +} Mouse; + +typedef struct { + PalBool scancodeState[PAL_SCANCODE_COUNT]; + PalBool keycodeState[PAL_KEYCODE_COUNT]; + int repeatRate; + int repeatDelay; + int repeatKey; + int repeatScancode; + int scancodes[512]; + int keycodes[256]; + uint64_t timer; + uint64_t frequency; +} Keyboard; Wayland s_Wl = {0}; +static Mouse s_Mouse = {0}; +static Keyboard s_Keyboard = {0}; // ================================================== // Helpers @@ -99,6 +130,279 @@ struct wl_buffer* createShmBuffer( return buffer; } +static void createScancodeTable() +{ + // Letters + s_Keyboard.scancodes[0x01E] = PAL_SCANCODE_A; + s_Keyboard.scancodes[0x030] = PAL_SCANCODE_B; + s_Keyboard.scancodes[0x02E] = PAL_SCANCODE_C; + s_Keyboard.scancodes[0x020] = PAL_SCANCODE_D; + s_Keyboard.scancodes[0x012] = PAL_SCANCODE_E; + s_Keyboard.scancodes[0x021] = PAL_SCANCODE_F; + s_Keyboard.scancodes[0x022] = PAL_SCANCODE_G; + s_Keyboard.scancodes[0x023] = PAL_SCANCODE_H; + s_Keyboard.scancodes[0x017] = PAL_SCANCODE_I; + s_Keyboard.scancodes[0x024] = PAL_SCANCODE_J; + s_Keyboard.scancodes[0x025] = PAL_SCANCODE_K; + s_Keyboard.scancodes[0x026] = PAL_SCANCODE_L; + s_Keyboard.scancodes[0x032] = PAL_SCANCODE_M; + s_Keyboard.scancodes[0x031] = PAL_SCANCODE_N; + s_Keyboard.scancodes[0x018] = PAL_SCANCODE_O; + s_Keyboard.scancodes[0x019] = PAL_SCANCODE_P; + s_Keyboard.scancodes[0x010] = PAL_SCANCODE_Q; + s_Keyboard.scancodes[0x013] = PAL_SCANCODE_R; + s_Keyboard.scancodes[0x01F] = PAL_SCANCODE_S; + s_Keyboard.scancodes[0x014] = PAL_SCANCODE_T; + s_Keyboard.scancodes[0x016] = PAL_SCANCODE_U; + s_Keyboard.scancodes[0x02F] = PAL_SCANCODE_V; + s_Keyboard.scancodes[0x011] = PAL_SCANCODE_W; + s_Keyboard.scancodes[0x02D] = PAL_SCANCODE_X; + s_Keyboard.scancodes[0x015] = PAL_SCANCODE_Y; + s_Keyboard.scancodes[0x02C] = PAL_SCANCODE_Z; + + // Numbers (top row) + s_Keyboard.scancodes[0x00B] = PAL_SCANCODE_0; + s_Keyboard.scancodes[0x002] = PAL_SCANCODE_1; + s_Keyboard.scancodes[0x003] = PAL_SCANCODE_2; + s_Keyboard.scancodes[0x004] = PAL_SCANCODE_3; + s_Keyboard.scancodes[0x005] = PAL_SCANCODE_4; + s_Keyboard.scancodes[0x006] = PAL_SCANCODE_5; + s_Keyboard.scancodes[0x007] = PAL_SCANCODE_6; + s_Keyboard.scancodes[0x008] = PAL_SCANCODE_7; + s_Keyboard.scancodes[0x009] = PAL_SCANCODE_8; + s_Keyboard.scancodes[0x00A] = PAL_SCANCODE_9; + + // Function + s_Keyboard.scancodes[0x03B] = PAL_SCANCODE_F1; + s_Keyboard.scancodes[0x03C] = PAL_SCANCODE_F2; + s_Keyboard.scancodes[0x03D] = PAL_SCANCODE_F3; + s_Keyboard.scancodes[0x03E] = PAL_SCANCODE_F4; + s_Keyboard.scancodes[0x03F] = PAL_SCANCODE_F5; + s_Keyboard.scancodes[0x040] = PAL_SCANCODE_F6; + s_Keyboard.scancodes[0x041] = PAL_SCANCODE_F7; + s_Keyboard.scancodes[0x042] = PAL_SCANCODE_F8; + s_Keyboard.scancodes[0x043] = PAL_SCANCODE_F9; + s_Keyboard.scancodes[0x044] = PAL_SCANCODE_F10; + s_Keyboard.scancodes[0x057] = PAL_SCANCODE_F11; + s_Keyboard.scancodes[0x058] = PAL_SCANCODE_F12; + + // Control + s_Keyboard.scancodes[0x001] = PAL_SCANCODE_ESCAPE; + s_Keyboard.scancodes[0x01C] = PAL_SCANCODE_ENTER; + s_Keyboard.scancodes[0x00F] = PAL_SCANCODE_TAB; + s_Keyboard.scancodes[0x00E] = PAL_SCANCODE_BACKSPACE; + s_Keyboard.scancodes[0x039] = PAL_SCANCODE_SPACE; + s_Keyboard.scancodes[0x03A] = PAL_SCANCODE_CAPSLOCK; + s_Keyboard.scancodes[0x045] = PAL_SCANCODE_NUMLOCK; + s_Keyboard.scancodes[0x046] = PAL_SCANCODE_SCROLLLOCK; + s_Keyboard.scancodes[0x02A] = PAL_SCANCODE_LSHIFT; + s_Keyboard.scancodes[0x036] = PAL_SCANCODE_RSHIFT; + s_Keyboard.scancodes[0x01D] = PAL_SCANCODE_LCTRL; + s_Keyboard.scancodes[0x061] = PAL_SCANCODE_RCTRL; + s_Keyboard.scancodes[0x038] = PAL_SCANCODE_LALT; + s_Keyboard.scancodes[0x064] = PAL_SCANCODE_RALT; + + // Arrows + s_Keyboard.scancodes[0x069] = PAL_SCANCODE_LEFT; + s_Keyboard.scancodes[0x06A] = PAL_SCANCODE_RIGHT; + s_Keyboard.scancodes[0x067] = PAL_SCANCODE_UP; + s_Keyboard.scancodes[0x06C] = PAL_SCANCODE_DOWN; + + // Navigation + s_Keyboard.scancodes[0x06E] = PAL_SCANCODE_INSERT; + s_Keyboard.scancodes[0x06F] = PAL_SCANCODE_DELETE; + s_Keyboard.scancodes[0x066] = PAL_SCANCODE_HOME; + s_Keyboard.scancodes[0x067] = PAL_SCANCODE_END; + s_Keyboard.scancodes[0x068] = PAL_SCANCODE_PAGEUP; + s_Keyboard.scancodes[0x06D] = PAL_SCANCODE_PAGEDOWN; + + // Keypad + s_Keyboard.scancodes[0x052] = PAL_SCANCODE_KP_0; + s_Keyboard.scancodes[0x04F] = PAL_SCANCODE_KP_1; + s_Keyboard.scancodes[0x050] = PAL_SCANCODE_KP_2; + s_Keyboard.scancodes[0x051] = PAL_SCANCODE_KP_3; + s_Keyboard.scancodes[0x04B] = PAL_SCANCODE_KP_4; + s_Keyboard.scancodes[0x04C] = PAL_SCANCODE_KP_5; + s_Keyboard.scancodes[0x04D] = PAL_SCANCODE_KP_6; + s_Keyboard.scancodes[0x047] = PAL_SCANCODE_KP_7; + s_Keyboard.scancodes[0x048] = PAL_SCANCODE_KP_8; + s_Keyboard.scancodes[0x049] = PAL_SCANCODE_KP_9; + s_Keyboard.scancodes[0x060] = PAL_SCANCODE_KP_ENTER; + s_Keyboard.scancodes[0x04E] = PAL_SCANCODE_KP_ADD; + s_Keyboard.scancodes[0x04A] = PAL_SCANCODE_KP_SUBTRACT; + s_Keyboard.scancodes[0x037] = PAL_SCANCODE_KP_MULTIPLY; + s_Keyboard.scancodes[0x062] = PAL_SCANCODE_KP_DIVIDE; + s_Keyboard.scancodes[0x053] = PAL_SCANCODE_KP_DECIMAL; + + // Misc + s_Keyboard.scancodes[0x063] = PAL_SCANCODE_PRINTSCREEN; + s_Keyboard.scancodes[0x066] = PAL_SCANCODE_PAUSE; + s_Keyboard.scancodes[0x07F] = PAL_SCANCODE_MENU; + s_Keyboard.scancodes[0x028] = PAL_SCANCODE_APOSTROPHE; + s_Keyboard.scancodes[0x02B] = PAL_SCANCODE_BACKSLASH; + s_Keyboard.scancodes[0x033] = PAL_SCANCODE_COMMA; + s_Keyboard.scancodes[0x00D] = PAL_SCANCODE_EQUAL; + s_Keyboard.scancodes[0x029] = PAL_SCANCODE_GRAVEACCENT; + s_Keyboard.scancodes[0x00C] = PAL_SCANCODE_SUBTRACT; + s_Keyboard.scancodes[0x034] = PAL_SCANCODE_PERIOD; + s_Keyboard.scancodes[0x027] = PAL_SCANCODE_SEMICOLON; + s_Keyboard.scancodes[0x035] = PAL_SCANCODE_SLASH; + s_Keyboard.scancodes[0x01A] = PAL_SCANCODE_LBRACKET; + s_Keyboard.scancodes[0x01B] = PAL_SCANCODE_RBRACKET; + s_Keyboard.scancodes[0x07D] = PAL_SCANCODE_LSUPER; + s_Keyboard.scancodes[0x07E] = PAL_SCANCODE_RSUPER; +} + +static void createKeycodeTable() +{ + // Tis is for only printable and text input keys + + // Letters + s_Keyboard.keycodes[XKB_KEY_a] = PAL_KEYCODE_A; + s_Keyboard.keycodes[XKB_KEY_b] = PAL_KEYCODE_B; + s_Keyboard.keycodes[XKB_KEY_c] = PAL_KEYCODE_C; + s_Keyboard.keycodes[XKB_KEY_d] = PAL_KEYCODE_D; + s_Keyboard.keycodes[XKB_KEY_e] = PAL_KEYCODE_E; + s_Keyboard.keycodes[XKB_KEY_f] = PAL_KEYCODE_F; + s_Keyboard.keycodes[XKB_KEY_g] = PAL_KEYCODE_G; + s_Keyboard.keycodes[XKB_KEY_h] = PAL_KEYCODE_H; + s_Keyboard.keycodes[XKB_KEY_i] = PAL_KEYCODE_I; + s_Keyboard.keycodes[XKB_KEY_j] = PAL_KEYCODE_J; + s_Keyboard.keycodes[XKB_KEY_k] = PAL_KEYCODE_K; + s_Keyboard.keycodes[XKB_KEY_l] = PAL_KEYCODE_L; + s_Keyboard.keycodes[XKB_KEY_m] = PAL_KEYCODE_M; + s_Keyboard.keycodes[XKB_KEY_n] = PAL_KEYCODE_N; + s_Keyboard.keycodes[XKB_KEY_o] = PAL_KEYCODE_O; + s_Keyboard.keycodes[XKB_KEY_p] = PAL_KEYCODE_P; + s_Keyboard.keycodes[XKB_KEY_q] = PAL_KEYCODE_Q; + s_Keyboard.keycodes[XKB_KEY_r] = PAL_KEYCODE_R; + s_Keyboard.keycodes[XKB_KEY_s] = PAL_KEYCODE_S; + s_Keyboard.keycodes[XKB_KEY_t] = PAL_KEYCODE_T; + s_Keyboard.keycodes[XKB_KEY_u] = PAL_KEYCODE_U; + s_Keyboard.keycodes[XKB_KEY_v] = PAL_KEYCODE_V; + s_Keyboard.keycodes[XKB_KEY_w] = PAL_KEYCODE_W; + s_Keyboard.keycodes[XKB_KEY_x] = PAL_KEYCODE_X; + s_Keyboard.keycodes[XKB_KEY_y] = PAL_KEYCODE_Y; + s_Keyboard.keycodes[XKB_KEY_z] = PAL_KEYCODE_Z; + + // Control + s_Keyboard.keycodes[XKB_KEY_space] = PAL_KEYCODE_SPACE; + + // Misc + s_Keyboard.keycodes[XKB_KEY_apostrophe] = PAL_KEYCODE_APOSTROPHE; + s_Keyboard.keycodes[XKB_KEY_backslash] = PAL_KEYCODE_BACKSLASH; + s_Keyboard.keycodes[XKB_KEY_comma] = PAL_KEYCODE_COMMA; + s_Keyboard.keycodes[XKB_KEY_equal] = PAL_KEYCODE_EQUAL; + s_Keyboard.keycodes[XKB_KEY_grave] = PAL_KEYCODE_GRAVEACCENT; + s_Keyboard.keycodes[XKB_KEY_minus] = PAL_KEYCODE_SUBTRACT; + s_Keyboard.keycodes[XKB_KEY_period] = PAL_KEYCODE_PERIOD; + s_Keyboard.keycodes[XKB_KEY_semicolon] = PAL_KEYCODE_SEMICOLON; + s_Keyboard.keycodes[XKB_KEY_slash] = PAL_KEYCODE_SLASH; + s_Keyboard.keycodes[XKB_KEY_bracketleft] = PAL_KEYCODE_LBRACKET; + s_Keyboard.keycodes[XKB_KEY_bracketright] = PAL_KEYCODE_RBRACKET; +} + +MonitorData* wlGetFreeMonitorData() +{ + for (int i = 0; i < s_Wl.maxMonitorData; ++i) { + if (!s_Wl.monitorData[i].used) { + s_Wl.monitorData[i].used = PAL_TRUE; + return &s_Wl.monitorData[i]; + } + } + + // resize the data array + // this will almost not reach here since most setups are 1-4 monitors + MonitorData* data = nullptr; + int count = s_Wl.maxMonitorData * 2; // double the size + int freeIndex = s_Wl.maxMonitorData + 1; + data = palAllocate(s_Wl.allocator, sizeof(MonitorData) * count, 0); + if (data) { + memcpy( + data, + s_Wl.monitorData, + s_Wl.maxMonitorData * sizeof(MonitorData)); + + palFree(s_Wl.allocator, s_Wl.monitorData); + s_Wl.monitorData = data; + s_Wl.maxWindowData = count; + + s_Wl.monitorData[freeIndex].used = PAL_TRUE; + return &s_Wl.monitorData[freeIndex]; + } + return nullptr; +} + +MonitorData* wlFindMonitorData(PalMonitor* monitor) +{ + for (int i = 0; i < s_Wl.maxMonitorData; ++i) { + if (s_Wl.monitorData[i].used && + s_Wl.monitorData[i].monitor == monitor) { + return &s_Wl.monitorData[i]; + } + } + return nullptr; +} + +void wlFreeMonitorData(PalMonitor* monitor) +{ + for (int i = 0; i < s_Wl.maxMonitorData; ++i) { + if (s_Wl.monitorData[i].used && + s_Wl.monitorData[i].monitor == monitor) { + s_Wl.monitorData[i].used = PAL_FALSE; + } + } +} + +WindowData* wlGetFreeWindowData() +{ + for (int i = 0; i < s_Wl.maxWindowData; ++i) { + if (!s_Wl.windowData[i].used) { + s_Wl.windowData[i].used = PAL_TRUE; + return &s_Wl.windowData[i]; + } + } + + // resize the data array + // It is rare for a user to create and manage + // 32 windows at the same time + WindowData* data = nullptr; + int count = s_Wl.maxWindowData * 2; // double the size + int freeIndex = s_Wl.maxWindowData + 1; + data = palAllocate(s_Wl.allocator, sizeof(WindowData) * count, 0); + if (data) { + memcpy( + data, + s_Wl.windowData, + s_Wl.maxWindowData * sizeof(WindowData)); + + palFree(s_Wl.allocator, s_Wl.windowData); + s_Wl.windowData = data; + s_Wl.maxWindowData = count; + + s_Wl.windowData[freeIndex].used = PAL_TRUE; + return &s_Wl.windowData[freeIndex]; + } + return nullptr; +} + +WindowData* wlFindWindowData(PalWindow* window) +{ + for (int i = 0; i < s_Wl.maxWindowData; ++i) { + if (s_Wl.windowData[i].used && + s_Wl.windowData[i].window == window) { + return &s_Wl.windowData[i]; + } + } + return nullptr; +} + +static inline uint64_t getCurrentTime() +{ + uint64_t now = palGetPerformanceCounter(); + return (now * 1000) / s_Keyboard.frequency; +} + // ================================================== // Registry // ================================================== @@ -124,7 +428,7 @@ static void globalHandle( features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; features |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; - s_Video.features = features; + s_Wl.features = features; s_Wl.checkFeatures = PAL_FALSE; } @@ -148,13 +452,13 @@ static void globalHandle( s_Wl.decorationManager = wlRegistryBind(registry, name, &zxdg_decoration_manager_v1_interface, 1); - s_Video.features |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; + s_Wl.features |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; } else if (strcmp(interface, "wl_output") == 0) { // wayland does not let use query monitors directly // so we enumerate and store at init and update the // cache when a monitor is added or removed - MonitorData* monitorData = getFreeMonitorData(); + MonitorData* monitorData = wlGetFreeMonitorData(); if (!monitorData) { return; } @@ -174,9 +478,9 @@ static void globalRemove( struct wl_registry* registry, uint32_t name) { - for (int i = 0; i < s_Video.maxMonitorData; ++i) { - if (s_Video.monitorData[i].used && s_Video.monitorData[i].wlName == name) { - MonitorData* data = &s_Video.monitorData[i]; + for (int i = 0; i < s_Wl.maxMonitorData; ++i) { + if (s_Wl.monitorData[i].used && s_Wl.monitorData[i].wlName == name) { + MonitorData* data = &s_Wl.monitorData[i]; data->used = PAL_FALSE; s_Wl.proxyDestroy((struct wl_proxy*)data->monitor); s_Wl.monitorCount--; @@ -281,7 +585,7 @@ static void surfaceHandleEnter( struct wl_output* output) { WindowData* data = userData; - MonitorData* monitorData = findMonitorData((PalMonitor*)output); + MonitorData* monitorData = wlFindMonitorData((PalMonitor*)output); if (!monitorData) { return; } @@ -324,15 +628,15 @@ static void surfaceHandleEnter( // the code below should be skipped if users are not // interested in DPI changed events - PalDispatchMode mode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_MONITOR_DPI_CHANGED; - if (!s_Video.eventDriver) { + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; + PalEventType type = PAL_EVENT_TYPE_MONITOR_DPI_CHANGED; + if (!s_Wl.eventDriver) { return; } - PalEventDriver* driver = s_Video.eventDriver; + PalEventDriver* driver = s_Wl.eventDriver; mode = palGetEventDispatchMode(driver, type); - if (mode == PAL_DISPATCH_NONE) { + if (mode == PAL_DISPATCH_MODE_NONE) { return; } @@ -368,7 +672,7 @@ static void surfaceHandleLeave( { // remove the monitor from our span monitor list WindowData* data = userData; - MonitorData* monitorData = findMonitorData((PalMonitor*)output); + MonitorData* monitorData = wlFindMonitorData((PalMonitor*)output); if (!monitorData) { return; } @@ -397,7 +701,7 @@ static void pointerHandleEnter( wl_fixed_t surface_x, wl_fixed_t surface_y) { - WindowData* data = findWindowData((PalWindow*)surface); + WindowData* data = wlFindWindowData((PalWindow*)surface); if (!data) { return; } @@ -440,14 +744,14 @@ static void pointerHandleMotion( const int dx = x - s_Mouse.lastX; const int dy = y - s_Mouse.lastY; - PalDispatchMode mode = PAL_DISPATCH_NONE; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; PalWindow* window = (PalWindow*)s_Wl.pointerSurface; - if (s_Video.eventDriver && window) { + if (s_Wl.eventDriver && window) { // we only push a mouse move only if we are on a window - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MOUSE_MOVE; + PalEventDriver* driver = s_Wl.eventDriver; + PalEventType type = PAL_EVENT_TYPE_MOUSE_MOVE; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackInt32(x, y); @@ -456,9 +760,9 @@ static void pointerHandleMotion( } // push a mouse delta event - type = PAL_EVENT_MOUSE_DELTA; + type = PAL_EVENT_TYPE_MOUSE_DELTA; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackFloat((float)dx, (float)dy); @@ -492,7 +796,7 @@ static void pointerHandleButton( PalBool pressed = state == WL_POINTER_BUTTON_STATE_PRESSED; PalMouseButton _button = 0; - PalEventType type = PAL_EVENT_MOUSE_BUTTONUP; + PalEventType type = PAL_EVENT_TYPE_MOUSE_BUTTONUP; if (button == BTN_LEFT) { _button = PAL_MOUSE_BUTTON_LEFT; @@ -511,15 +815,15 @@ static void pointerHandleButton( } if (pressed) { - type = PAL_EVENT_MOUSE_BUTTONDOWN; + type = PAL_EVENT_TYPE_MOUSE_BUTTONDOWN; } s_Mouse.state[_button] = pressed; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; + if (s_Wl.eventDriver) { + PalEventDriver* driver = s_Wl.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; @@ -591,12 +895,12 @@ static void pointerHandleFrame( const int dx = (int)s_Mouse.accumScrollX; const int dy = (int)s_Mouse.accumScrollY; - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_MOUSE_WHEEL; - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; + if (s_Wl.eventDriver) { + PalEventType type = PAL_EVENT_TYPE_MOUSE_WHEEL; + PalEventDriver* driver = s_Wl.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackFloat((float)dx, (float)dy); @@ -725,8 +1029,8 @@ static void keyboardHandleKey( PalScancode scancode = 0; PalKeycode keycode = 0; PalBool pressed = (state == WL_KEYBOARD_KEY_STATE_PRESSED); - PalEventType type = PAL_EVENT_KEYUP; - PalDispatchMode mode = PAL_DISPATCH_NONE; + PalEventType type = PAL_EVENT_TYPE_KEYUP; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; xkb_keysym_t keySym = s_Wl.xkbStateKeyGetOneSym(s_Wl.state, key + 8); // special handling @@ -779,7 +1083,7 @@ static void keyboardHandleKey( s_Keyboard.repeatKey = 0; } - type = PAL_EVENT_KEYDOWN; + type = PAL_EVENT_TYPE_KEYDOWN; } else { // key release @@ -788,10 +1092,10 @@ static void keyboardHandleKey( } } - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; + if (s_Wl.eventDriver) { + PalEventDriver* driver = s_Wl.eventDriver; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackUint32(keycode, scancode); @@ -800,9 +1104,9 @@ static void keyboardHandleKey( } // check for char event if enabled - type = PAL_EVENT_KEYCHAR; + type = PAL_EVENT_TYPE_KEYCHAR; mode = palGetEventDispatchMode(driver, type); - if (mode == PAL_DISPATCH_NONE) { + if (mode == PAL_DISPATCH_MODE_NONE) { return; } @@ -920,15 +1224,13 @@ static void xdgSurfaceHandleConfigure( } else { // create a new buffer with the new size struct wl_buffer* buffer = nullptr; - buffer = - createShmBuffer(winData->w, winData->h, nullptr, PAL_FALSE); + buffer = createShmBuffer(winData->w, winData->h, nullptr, PAL_FALSE); if (!buffer) { return; } struct wl_surface* _surface = nullptr; _surface = (struct wl_surface*)winData->window; - wlSurfaceAttach(_surface, buffer, 0, 0); wlSurfaceDamageBuffer(_surface, 0, 0, winData->w, winData->h); wlSurfaceCommit(_surface); @@ -939,16 +1241,16 @@ static void xdgSurfaceHandleConfigure( } // push a window resize event - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_WINDOW_SIZE; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(s_Video.eventDriver, type); - if (mode != PAL_DISPATCH_NONE) { + if (s_Wl.eventDriver) { + PalEventType type = PAL_EVENT_TYPE_WINDOW_SIZE; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; + mode = palGetEventDispatchMode(s_Wl.eventDriver, type); + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackUint32(winData->w, winData->h); event.data2 = palPackPointer(winData->window); - palPushEvent(s_Video.eventDriver, &event); + palPushEvent(s_Wl.eventDriver, &event); } } @@ -965,16 +1267,16 @@ static void xdgSurfaceHandleConfigure( // push a window state event // we dont recreate buffers over here // since we already create the buffer with the new size - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_WINDOW_STATE; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(s_Video.eventDriver, type); - if (mode != PAL_DISPATCH_NONE) { + if (s_Wl.eventDriver) { + PalEventType type = PAL_EVENT_TYPE_WINDOW_STATE; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; + mode = palGetEventDispatchMode(s_Wl.eventDriver, type); + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = winData->state; event.data2 = palPackPointer(winData->window); - palPushEvent(s_Video.eventDriver, &event); + palPushEvent(s_Wl.eventDriver, &event); } } @@ -1029,13 +1331,13 @@ static void xdgToplevelHandleConfigure( return; } - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_WINDOW_FOCUS; + if (s_Wl.eventDriver) { + PalEventDriver* driver = s_Wl.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; + PalEventType type = PAL_EVENT_TYPE_WINDOW_FOCUS; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = winData->focused; @@ -1050,15 +1352,15 @@ static void xdgToplevelHandleClose( struct xdg_toplevel* toplevel) { WindowData* winData = (WindowData*)data; - if (s_Video.eventDriver) { - PalEventType type = PAL_EVENT_WINDOW_CLOSE; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(s_Video.eventDriver, type); - if (mode != PAL_DISPATCH_NONE) { + if (s_Wl.eventDriver) { + PalEventType type = PAL_EVENT_TYPE_WINDOW_CLOSE; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; + mode = palGetEventDispatchMode(s_Wl.eventDriver, type); + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data2 = palPackPointer(winData->window); - palPushEvent(s_Video.eventDriver, &event); + palPushEvent(s_Wl.eventDriver, &event); } } } @@ -1072,13 +1374,13 @@ void zxdgDecorationHandleConfigure( struct zxdg_toplevel_decoration_v1* dec, uint32_t mode) { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode dispatchMode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_WINDOW_DECORATION_MODE; + if (s_Wl.eventDriver) { + PalEventDriver* driver = s_Wl.eventDriver; + PalDispatchMode dispatchMode = PAL_DISPATCH_MODE_NONE; + PalEventType type = PAL_EVENT_TYPE_WINDOW_DECORATION_MODE; dispatchMode = palGetEventDispatchMode(driver, type); - if (dispatchMode != PAL_DISPATCH_NONE) { + if (dispatchMode != PAL_DISPATCH_MODE_NONE) { PalDecorationMode decorMode = PAL_DECORATION_MODE_SERVER_SIDE; if (mode == 0 || mode == 1) { // client side decoration @@ -1094,56 +1396,10 @@ void zxdgDecorationHandleConfigure( } } -static void createKeycodeTable() -{ - // Tis is for only printable and text input keys - - // Letters - s_Keyboard.keycodes[XKB_KEY_a] = PAL_KEYCODE_A; - s_Keyboard.keycodes[XKB_KEY_b] = PAL_KEYCODE_B; - s_Keyboard.keycodes[XKB_KEY_c] = PAL_KEYCODE_C; - s_Keyboard.keycodes[XKB_KEY_d] = PAL_KEYCODE_D; - s_Keyboard.keycodes[XKB_KEY_e] = PAL_KEYCODE_E; - s_Keyboard.keycodes[XKB_KEY_f] = PAL_KEYCODE_F; - s_Keyboard.keycodes[XKB_KEY_g] = PAL_KEYCODE_G; - s_Keyboard.keycodes[XKB_KEY_h] = PAL_KEYCODE_H; - s_Keyboard.keycodes[XKB_KEY_i] = PAL_KEYCODE_I; - s_Keyboard.keycodes[XKB_KEY_j] = PAL_KEYCODE_J; - s_Keyboard.keycodes[XKB_KEY_k] = PAL_KEYCODE_K; - s_Keyboard.keycodes[XKB_KEY_l] = PAL_KEYCODE_L; - s_Keyboard.keycodes[XKB_KEY_m] = PAL_KEYCODE_M; - s_Keyboard.keycodes[XKB_KEY_n] = PAL_KEYCODE_N; - s_Keyboard.keycodes[XKB_KEY_o] = PAL_KEYCODE_O; - s_Keyboard.keycodes[XKB_KEY_p] = PAL_KEYCODE_P; - s_Keyboard.keycodes[XKB_KEY_q] = PAL_KEYCODE_Q; - s_Keyboard.keycodes[XKB_KEY_r] = PAL_KEYCODE_R; - s_Keyboard.keycodes[XKB_KEY_s] = PAL_KEYCODE_S; - s_Keyboard.keycodes[XKB_KEY_t] = PAL_KEYCODE_T; - s_Keyboard.keycodes[XKB_KEY_u] = PAL_KEYCODE_U; - s_Keyboard.keycodes[XKB_KEY_v] = PAL_KEYCODE_V; - s_Keyboard.keycodes[XKB_KEY_w] = PAL_KEYCODE_W; - s_Keyboard.keycodes[XKB_KEY_x] = PAL_KEYCODE_X; - s_Keyboard.keycodes[XKB_KEY_y] = PAL_KEYCODE_Y; - s_Keyboard.keycodes[XKB_KEY_z] = PAL_KEYCODE_Z; - - // Control - s_Keyboard.keycodes[XKB_KEY_space] = PAL_KEYCODE_SPACE; - - // Misc - s_Keyboard.keycodes[XKB_KEY_apostrophe] = PAL_KEYCODE_APOSTROPHE; - s_Keyboard.keycodes[XKB_KEY_backslash] = PAL_KEYCODE_BACKSLASH; - s_Keyboard.keycodes[XKB_KEY_comma] = PAL_KEYCODE_COMMA; - s_Keyboard.keycodes[XKB_KEY_equal] = PAL_KEYCODE_EQUAL; - s_Keyboard.keycodes[XKB_KEY_grave] = PAL_KEYCODE_GRAVEACCENT; - s_Keyboard.keycodes[XKB_KEY_minus] = PAL_KEYCODE_SUBTRACT; - s_Keyboard.keycodes[XKB_KEY_period] = PAL_KEYCODE_PERIOD; - s_Keyboard.keycodes[XKB_KEY_semicolon] = PAL_KEYCODE_SEMICOLON; - s_Keyboard.keycodes[XKB_KEY_slash] = PAL_KEYCODE_SLASH; - s_Keyboard.keycodes[XKB_KEY_bracketleft] = PAL_KEYCODE_LBRACKET; - s_Keyboard.keycodes[XKB_KEY_bracketright] = PAL_KEYCODE_RBRACKET; -} - -PalResult wlInitVideo() +PalResult wlInitVideo( + const PalAllocator* allocator, + PalEventDriver* eventDriver, + void* preferredInstance) { // load wayland libray s_Wl.handle = dlopen("libwayland-client.so.0", RTLD_LAZY); @@ -1157,8 +1413,8 @@ PalResult wlInitVideo() !s_Wl.libCursor || !s_Wl.libWaylandEgl) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_POSIX, errno); } @@ -1308,28 +1564,31 @@ PalResult wlInitVideo() "wl_egl_window_resize"); // clang-format on + s_Wl.maxMonitorData = 16; // initial size + s_Wl.maxWindowData = 32; // initial size + s_Wl.windowData = palAllocate(s_Wl.allocator, sizeof(WindowData) * s_Wl.maxWindowData, 0); + s_Wl.monitorData = palAllocate(s_Wl.allocator,sizeof(MonitorData) * s_Wl.maxMonitorData,0); + if (!s_Wl.monitorData || !s_Wl.windowData) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + // initialize wayland s_Wl.checkFeatures = PAL_TRUE; s_Wl.monitorCount = 0; setupProtocols(); // check if user supplied their own display - if (s_Video.display) { - s_Wl.display = (struct wl_display*)s_Video.display; + if (preferredInstance) { + s_Wl.display = (struct wl_display*)preferredInstance; } else { s_Wl.display = s_Wl.displayConnect(nullptr); - s_Video.display = nullptr; - } - - if (!s_Wl.display) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + if (!s_Wl.display) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } } - s_Video.display = (void*)s_Wl.display; + s_Wl.display = (void*)s_Wl.display; s_Wl.registry = wlDisplayGetRegistry(s_Wl.display); wlRegistryAddListener(s_Wl.registry, &s_RegistryListener, nullptr); s_Wl.displayRoundtrip(s_Wl.display); @@ -1338,33 +1597,42 @@ PalResult wlInitVideo() s_Wl.displayRoundtrip(s_Wl.display); if (!s_Wl.compositor || !s_Wl.xdgBase || !s_Wl.shm) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } // create an input context s_Wl.inputContext = s_Wl.xkbContextNew(XKB_CONTEXT_NO_FLAGS); if (!s_Wl.inputContext) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } // get the current theme s_Wl.cursorTheme = s_Wl.cursorThemeLoad(nullptr, 32, s_Wl.shm); if (!s_Wl.cursorTheme) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + + // load EGL + s_Egl.handle = dlopen("libEGL.so", RTLD_LAZY); + if (s_Egl.handle) { + eglGetProcAddressFn load = nullptr; + load = (eglGetProcAddressFn)dlsym(s_Egl.handle, "eglGetProcAddress"); + + s_Egl.eglInitialize = (eglInitializeFn)load("eglInitialize"); + s_Egl.eglTerminate = (eglTerminateFn)load("eglTerminate"); + s_Egl.eglGetDisplay = (eglGetDisplayFn)load("eglGetDisplay"); + s_Egl.eglChooseConfig = (eglChooseConfigFn)load("eglChooseConfig"); + s_Egl.eglGetError = (eglGetErrorFn)load("eglGetError"); + s_Egl.eglBindAPI = (eglBindAPIFn)load("eglBindAPI"); + s_Egl.eglGetConfigs = (eglGetConfigsFn)load("eglGetConfigs"); + s_Egl.eglGetConfigAttrib = (eglGetConfigAttribFn)load("eglGetConfigAttrib"); } createKeycodeTable(); + createScancodeTable(); - s_Video.display = (void*)s_Wl.display; + s_Wl.allocator = allocator; + s_Wl.eventDriver = eventDriver; return PAL_RESULT_SUCCESS; } @@ -1385,7 +1653,7 @@ void wlShutdownVideo() s_Wl.proxyDestroy((struct wl_proxy*)s_Wl.seat); } - if (!s_Video.display) { + if (!s_Wl.display) { // opened by PAL s_Wl.displayDisconnect(s_Wl.display); @@ -1395,6 +1663,12 @@ void wlShutdownVideo() dlclose(s_Wl.handle); } + palFree(s_Wl.allocator, s_Wl.windowData); + palFree(s_Wl.allocator, s_Wl.monitorData); + if (s_Egl.handle) { + dlclose(s_Egl.handle); + } + memset(&s_Wl, 0, sizeof(Wayland)); } @@ -1406,11 +1680,11 @@ void wlUpdateVideo() // push key repeats // we only do this if the user wants key repeat events - if (s_Keyboard.repeatKey != 0 && s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - mode = palGetEventDispatchMode(driver, PAL_EVENT_KEYREPEAT); - if (mode != PAL_DISPATCH_NONE) { + if (s_Keyboard.repeatKey != 0 && s_Wl.eventDriver) { + PalEventDriver* driver = s_Wl.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_KEYREPEAT); + if (mode != PAL_DISPATCH_MODE_NONE) { // get now time and check with the key repeat time uint64_t now = getCurrentTime(); if (now >= s_Keyboard.timer) { @@ -1419,7 +1693,7 @@ void wlUpdateVideo() PalScancode scancode = s_Keyboard.repeatScancode; PalEvent event = {0}; - event.type = PAL_EVENT_KEYREPEAT; + event.type = PAL_EVENT_TYPE_KEYREPEAT; event.data = palPackUint32(key, scancode); event.data2 = palPackPointer(window); palPushEvent(driver, &event); @@ -1447,6 +1721,52 @@ void wlUpdateVideo() s_Wl.dispatchPending(s_Wl.display); } +PalVideoFeatures wlGetVideoFeatures() +{ + return s_Wl.features; +} + +const PalBool* wlGetKeycodeState() +{ + return s_Keyboard.keycodeState; +} + +const PalBool* wlGetScancodeState() +{ + return s_Keyboard.scancodeState; +} + +const PalBool* wlGetMouseState() +{ + return s_Mouse.state; +} + +void wlGetMouseDelta( + float* dx, + float* dy) +{ + if (dx) { + *dx = (float)s_Mouse.dx; + } + + if (dy) { + *dy = (float)s_Mouse.dy; + } +} + +void wlGetMouseWheelDelta( + float* dx, + float* dy) +{ + if (dx) { + *dx = (float)s_Mouse.WheelX; + } + + if (dy) { + *dy = (float)s_Mouse.WheelY; + } +} + void* wlGetInstance() { return (void*)s_Wl.display; @@ -1523,5 +1843,4 @@ struct xdg_toplevel_listener s_XdgToplevelListener = { .wm_capabilities = nullptr }; -#endif // PAL_HAS_WAYLAND_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_WAYLAND_BACKEND \ No newline at end of file diff --git a/src/video/linux/wayland/pal_wayland.h b/src/video/wayland/pal_wayland.h similarity index 82% rename from src/video/linux/wayland/pal_wayland.h rename to src/video/wayland/pal_wayland.h index ed4854e9..fd75ba90 100644 --- a/src/video/linux/wayland/pal_wayland.h +++ b/src/video/wayland/pal_wayland.h @@ -7,10 +7,13 @@ #ifndef _PAL_WAYLAND_H #define _PAL_WAYLAND_H -#ifdef __linux__ + #if PAL_HAS_WAYLAND_BACKEND == 1 -#include "video/linux/pal_video_linux.h" +#define MAX_SPAN_MONITORS 4 + +#include "pal/pal_video.h" +#include "video/pal_video_egl.h" #include #include #include @@ -131,9 +134,63 @@ typedef struct { int hotspotY; } WaylandCursor; +typedef struct { + void* monitor; + int dpi; +} SpanMonitor; + +typedef struct { + PalBool used; + int dpi; + int x; + int y; + uint32_t w; + uint32_t h; + uint32_t refreshRate; + uint32_t wlName; + PalOrientation orientation; + PalMonitor* monitor; + PalMonitorMode mode; // wayland only sends current + char name[32]; +} MonitorData; + +typedef struct { + PalBool skipConfigure; + PalBool skipState; + PalBool used; + PalBool isAttached; + PalBool skipIfAttached; + PalBool focused; + PalBool pushConfigureEvent; + PalBool pushStateEvent; + int x; + int y; + uint32_t w; + uint32_t h; + int dpi; + int monitorCount; + PalWindowState state; + PalWindow* window; + + struct xdg_surface* xdgSurface; + struct xdg_toplevel* xdgToplevel; + struct wl_buffer* buffer; + struct zxdg_toplevel_decoration_v1* decoration; + void* cursor; + struct wl_egl_window* eglWindow; + SpanMonitor monitors[MAX_SPAN_MONITORS]; +} WindowData; + typedef struct { PalBool checkFeatures; int monitorCount; + int32_t maxWindowData; + int32_t maxMonitorData; + PalVideoFeatures features; + const PalAllocator* allocator; + PalEventDriver* eventDriver; + WindowData* windowData; + MonitorData* monitorData; void* handle; void* xkbCommon; @@ -229,6 +286,11 @@ struct wl_buffer* createShmBuffer( const uint8_t* pixels, PalBool cursor); +MonitorData* wlGetFreeMonitorData(); +MonitorData* wlFindMonitorData(PalMonitor* monitor); +void wlFreeMonitorData(PalMonitor* monitor); +WindowData* wlGetFreeWindowData(); +WindowData* wlFindWindowData(PalWindow* window); + #endif // PAL_HAS_WAYLAND_BACKEND -#endif // __linux__ #endif // _PAL_WAYLAND_H \ No newline at end of file diff --git a/src/video/linux/wayland/pal_wayland_protocols.c b/src/video/wayland/pal_wayland_protocols.c similarity index 98% rename from src/video/linux/wayland/pal_wayland_protocols.c rename to src/video/wayland/pal_wayland_protocols.c index b61427f4..52a8d340 100644 --- a/src/video/linux/wayland/pal_wayland_protocols.c +++ b/src/video/wayland/pal_wayland_protocols.c @@ -5,9 +5,7 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_WAYLAND_BACKEND == 1 - #include "pal_wayland_protocols.h" // ================================================== @@ -210,5 +208,4 @@ void setupProtocols() xdg_shell_types[25] = NULL; } -#endif // PAL_HAS_WAYLAND_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_WAYLAND_BACKEND \ No newline at end of file diff --git a/src/video/linux/wayland/pal_wayland_protocols.h b/src/video/wayland/pal_wayland_protocols.h similarity index 99% rename from src/video/linux/wayland/pal_wayland_protocols.h rename to src/video/wayland/pal_wayland_protocols.h index 2468e84c..b14c5b63 100644 --- a/src/video/linux/wayland/pal_wayland_protocols.h +++ b/src/video/wayland/pal_wayland_protocols.h @@ -7,9 +7,8 @@ #ifndef _PAL_WAYLAND_PROTOCOLS_H #define _PAL_WAYLAND_PROTOCOLS_H -#ifdef __linux__ -#if PAL_HAS_WAYLAND_BACKEND == 1 +#if PAL_HAS_WAYLAND_BACKEND == 1 #include "pal_wayland.h" // ================================================== @@ -676,5 +675,4 @@ static inline void zxdgToplevelDecorationV1SetMode( } #endif // PAL_HAS_WAYLAND_BACKEND -#endif // __linux__ #endif // _PAL_WAYLAND_PROTOCOLS_H \ No newline at end of file diff --git a/src/video/linux/wayland/pal_window_wayland.c b/src/video/wayland/pal_window_wayland.c similarity index 62% rename from src/video/linux/wayland/pal_window_wayland.c rename to src/video/wayland/pal_window_wayland.c index 8b0083e2..1dc378c4 100644 --- a/src/video/linux/wayland/pal_window_wayland.c +++ b/src/video/wayland/pal_window_wayland.c @@ -5,13 +5,11 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_WAYLAND_BACKEND == 1 - #include "pal_wayland.h" #include "pal_wayland_protocols.h" -#include "pal_shared.h" #include +#include EGLConfig eglWlBackend(const int fbConfigIndex) { @@ -27,7 +25,7 @@ EGLConfig eglWlBackend(const int fbConfigIndex) } EGLint configSize = sizeof(EGLConfig) * numConfigs; - EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); + EGLConfig* eglConfigs = palAllocate(s_Wl.allocator, configSize, 0); if (!eglConfigs) { return nullptr; } @@ -45,42 +43,27 @@ PalResult wlCreateWindow( struct xdg_toplevel* xdgToplevel = nullptr; if (info->style & PAL_WINDOW_STYLE_TOPMOST) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } if (info->style & PAL_WINDOW_STYLE_TRANSPARENT) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } if (info->style & PAL_WINDOW_STYLE_TOOL) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } if (!(info->style & PAL_WINDOW_STYLE_BORDERLESS)) { if (!s_Wl.decorationManager) { // user wants decorated window but its not supported - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } } - WindowData* data = getFreeWindowData(); + WindowData* data = wlGetFreeWindowData(); if (!data) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } memset(data, 0, sizeof(WindowData)); @@ -90,33 +73,24 @@ PalResult wlCreateWindow( // create surface surface = wlCompositorCreateSurface(s_Wl.compositor); if (!surface) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } wlSurfaceAddListener(surface, &s_SurfaceListener, data); xdgSurface = xdgWmBaseGetXdgSurface(s_Wl.xdgBase, surface); if (!xdgSurface) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } xdgToplevel = xdgSurfaceGetToplevel(xdgSurface); if (!xdgSurface) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } // set APP id const char* appID = info->appName; if (!appID || strlen(appID) == 0) { - appID = s_Video.className; + appID = "PAL"; } const char* title = info->title; @@ -144,7 +118,7 @@ PalResult wlCreateWindow( wlSurfaceCommit(surface); s_Wl.displayRoundtrip(s_Wl.display); - if (info->maximized && info->show) { + if (info->state == PAL_WINDOW_STATE_MAXIMIZED && info->show) { // we need the maximized size the compositor will use // and use that to create the buffer xdgToplevelSetMaximized(xdgToplevel); @@ -166,7 +140,7 @@ PalResult wlCreateWindow( // minimize // This is just a requeest, the compositor might ignore it - if (info->minimized) { + if (info->state == PAL_WINDOW_STATE_MINIMIZED) { xdgToplevelSetMinimized(xdgToplevel); wlSurfaceCommit(surface); data->state = PAL_WINDOW_STATE_MINIMIZED; @@ -177,26 +151,22 @@ PalResult wlCreateWindow( PalFBConfigBackend backend = info->fbConfigBackend; EGLConfig config = nullptr; - if (backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { - backend = PAL_CONFIG_BACKEND_EGL; + if (backend == PAL_FBCONFIG_BACKEND_PAL_OPENGL) { + backend = PAL_FBCONFIG_BACKEND_EGL; } - if (backend == PAL_CONFIG_BACKEND_EGL) { + if (backend == PAL_FBCONFIG_BACKEND_EGL) { config = eglWlBackend(info->fbConfigIndex); - } else { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } data->eglWindow = s_Wl.eglWindowCreate(surface, data->w, data->h); if (!data->eglWindow) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_EGL, + s_Egl.eglGetError()); } } else { @@ -204,10 +174,7 @@ PalResult wlCreateWindow( struct wl_buffer* buffer = nullptr; buffer = createShmBuffer(data->w, data->h, nullptr, PAL_FALSE); if (!buffer) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } wlSurfaceAttach(surface, buffer, 0, 0); @@ -225,13 +192,13 @@ PalResult wlCreateWindow( } s_Wl.displayRoundtrip(s_Wl.display); - if (!s_Wl.decorationManager && s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalDispatchMode mode = PAL_DISPATCH_NONE; - PalEventType type = PAL_EVENT_WINDOW_DECORATION_MODE; + if (!s_Wl.decorationManager && s_Wl.eventDriver) { + PalEventDriver* driver = s_Wl.eventDriver; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; + PalEventType type = PAL_EVENT_TYPE_WINDOW_DECORATION_MODE; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = PAL_DECORATION_MODE_CLIENT_SIDE; @@ -252,7 +219,7 @@ PalResult wlCreateWindow( void wlDestroyWindow(PalWindow* window) { - WindowData* data = findWindowData(window); + WindowData* data = wlFindWindowData(window); if (!data || (data && data->isAttached)) { return; } @@ -275,12 +242,9 @@ void wlDestroyWindow(PalWindow* window) PalResult wlMinimizeWindow(PalWindow* window) { - WindowData* data = findWindowData(window); + WindowData* data = wlFindWindowData(window); if (!data) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } xdgToplevelSetMinimized(data->xdgToplevel); @@ -289,12 +253,9 @@ PalResult wlMinimizeWindow(PalWindow* window) PalResult wlMaximizeWindow(PalWindow* window) { - WindowData* data = findWindowData(window); + WindowData* data = wlFindWindowData(window); if (!data) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } xdgToplevelSetMaximized(data->xdgToplevel); @@ -303,12 +264,9 @@ PalResult wlMaximizeWindow(PalWindow* window) PalResult wlRestoreWindow(PalWindow* window) { - WindowData* data = findWindowData(window); + WindowData* data = wlFindWindowData(window); if (!data) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // we can only restore from a maximized state @@ -318,48 +276,33 @@ PalResult wlRestoreWindow(PalWindow* window) PalResult wlShowWindow(PalWindow* window) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlHideWindow(PalWindow* window) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlFlashWindow( PalWindow* window, const PalFlashInfo* info) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlGetWindowStyle( PalWindow* window, PalWindowStyle* outStyle) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlGetWindowMonitor( PalWindow* window, PalMonitor** outMonitor) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlGetWindowTitle( @@ -368,10 +311,7 @@ PalResult wlGetWindowTitle( uint64_t* outSize, char* outBuffer) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlGetWindowPos( @@ -379,10 +319,7 @@ PalResult wlGetWindowPos( int32_t* x, int32_t* y) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlGetWindowSize( @@ -390,20 +327,14 @@ PalResult wlGetWindowSize( uint32_t* width, uint32_t* height) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlGetWindowState( PalWindow* window, PalWindowState* outState) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalBool wlIsWindowVisible(PalWindow* window) @@ -421,23 +352,13 @@ PalResult wlGetWindowHandleInfo( PalWindow* window, PalWindowHandleInfo* info) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - if (!window || !info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } - WindowData* data = findWindowData(window); + WindowData* data = wlFindWindowData(window); if (data) { - info->nativeDisplay = (void*)s_Wl.display; + info->nativeInstance = (void*)s_Wl.display; info->nativeWindow = (void*)window; info->nativeHandle1 = data->xdgSurface; info->nativeHandle2 = data->xdgToplevel; @@ -451,32 +372,23 @@ PalResult wlSetWindowOpacity( PalWindow* window, float opacity) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlSetWindowStyle( PalWindow* window, PalWindowStyle style) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlSetWindowTitle( PalWindow* window, const char* title) { - WindowData* data = findWindowData(window); + WindowData* data = wlFindWindowData(window); if (!data) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } xdgToplevelSetTitle(data->xdgToplevel, title); @@ -489,10 +401,7 @@ PalResult wlSetWindowPos( int32_t x, int32_t y) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlSetWindowSize( @@ -500,12 +409,9 @@ PalResult wlSetWindowSize( uint32_t width, uint32_t height) { - WindowData* data = findWindowData(window); + WindowData* data = wlFindWindowData(window); if (!data) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } xdgToplevelSetMinSize(data->xdgToplevel, width, height); @@ -516,31 +422,21 @@ PalResult wlSetWindowSize( PalResult wlSetFocusWindow(PalWindow* window) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlAttachWindow( void* windowHandle, PalWindow** outWindow) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult wlDetachWindow( PalWindow* window, void** outWindowHandle) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } -#endif // PAL_HAS_WAYLAND_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_WAYLAND_BACKEND \ No newline at end of file diff --git a/src/video/win32/pal_video_win32.c b/src/video/win32/pal_video_win32.c index 3439c535..cdc522fe 100644 --- a/src/video/win32/pal_video_win32.c +++ b/src/video/win32/pal_video_win32.c @@ -27,8 +27,8 @@ typedef struct { typedef struct { int32_t pendingHighSurrogate; - PalBool scancodeState[PAL_SCANCODE_MAX]; - PalBool keycodeState[PAL_KEYCODE_MAX]; + PalBool scancodeState[PAL_SCANCODE_COUNT]; + PalBool keycodeState[PAL_KEYCODE_COUNT]; int scancodes[512]; int keycodes[256]; } Keyboard; @@ -39,7 +39,7 @@ typedef struct { int32_t dy; int32_t WheelX; int32_t WheelY; - PalBool state[PAL_MOUSE_BUTTON_MAX]; + PalBool state[PAL_MOUSE_BUTTON_COUNT]; } Mouse; static PendingEvent s_Event; @@ -1006,73 +1006,6 @@ void PAL_CALL palUpdateVideo() } } -PalVideoFeatures PAL_CALL palGetVideoFeatures() -{ - if (!s_Video.initialized) { - return 0; - } - - return s_Video.features; -} - -const PalBool* PAL_CALL palGetKeycodeState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Keyboard.keycodeState; -} - -const PalBool* PAL_CALL palGetScancodeState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Keyboard.scancodeState; -} - -const PalBool* PAL_CALL palGetMouseState() -{ - if (!s_Video.initialized) { - return nullptr; - } - return s_Mouse.state; -} - -void PAL_CALL palGetMouseDelta( - float* dx, - float* dy) -{ - if (!s_Video.initialized) { - return; - } - - if (dx) { - *dx = (float)s_Mouse.dx; - } - - if (dy) { - *dy = (float)s_Mouse.dy; - } -} - -void PAL_CALL palGetMouseWheelDelta( - float* dx, - float* dy) -{ - if (!s_Video.initialized) { - return; - } - - if (dx) { - *dx = (float)s_Mouse.WheelX; - } - - if (dy) { - *dy = (float)s_Mouse.WheelY; - } -} - void* PAL_CALL palGetInstance() { if (!s_Video.initialized) { diff --git a/src/video/linux/x11/pal_cursor_x11.c b/src/video/x11/pal_cursor_x11.c similarity index 78% rename from src/video/linux/x11/pal_cursor_x11.c rename to src/video/x11/pal_cursor_x11.c index 1b41f9af..65a9aa40 100644 --- a/src/video/linux/x11/pal_cursor_x11.c +++ b/src/video/x11/pal_cursor_x11.c @@ -5,11 +5,8 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_X11_BACKEND == 1 - #include "pal_x11.h" -#include "pal_shared.h" PalResult xCreateCursor( const PalCursorCreateInfo* info, @@ -36,10 +33,7 @@ PalResult xCreateCursor( Cursor cursor = s_X11.cursorImageLoadCursor(s_X11.display, image); if (!cursor) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } s_X11.cursorImageDestroy(image); @@ -54,27 +48,27 @@ PalResult xCreateCursorFrom( int shape; Cursor cursor; switch (type) { - case PAL_CURSOR_ARROW: { + case PAL_CURSOR_TYPE_ARROW: { shape = XC_left_ptr; break; } - case PAL_CURSOR_HAND: { + case PAL_CURSOR_TYPE_HAND: { shape = XC_hand2; break; } - case PAL_CURSOR_CROSS: { + case PAL_CURSOR_TYPE_CROSS: { shape = XC_cross; break; } - case PAL_CURSOR_IBEAM: { + case PAL_CURSOR_TYPE_IBEAM: { shape = XC_xterm; break; } - case PAL_CURSOR_WAIT: { + case PAL_CURSOR_TYPE_WAIT: { shape = XC_watch; break; } @@ -103,10 +97,7 @@ PalResult xClipCursor( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (clip) { @@ -136,17 +127,13 @@ PalResult xGetCursorPos( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } - Window root, rootChild; + Window root, child; int rootX, rootY, winX, winY; unsigned int mask; - s_X11.queryPointer(s_X11.display, xWin, &root, &rootChild, &rootX, &rootY, &winX, &winY, &mask); - + s_X11.queryPointer(s_X11.display, xWin, &root, &child, &rootX, &rootY, &winX, &winY, &mask); if (x) { *x = winX; } @@ -166,14 +153,10 @@ PalResult xSetCursorPos( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } s_X11.warpPointer(s_X11.display, None, xWin, 0, 0, 0, 0, x, y); - s_X11.flush(s_X11.display); return PAL_RESULT_SUCCESS; } @@ -185,10 +168,7 @@ PalResult xSetWindowCursor( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } Window xCursor = FROM_PAL_HANDLE(Cursor, cursor); @@ -203,5 +183,4 @@ PalResult xSetWindowCursor( return PAL_RESULT_SUCCESS; } -#endif // PAL_HAS_X11_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_X11_BACKEND \ No newline at end of file diff --git a/src/video/linux/x11/pal_icon_x11.c b/src/video/x11/pal_icon_x11.c similarity index 81% rename from src/video/linux/x11/pal_icon_x11.c rename to src/video/x11/pal_icon_x11.c index 05391ac3..1da531f4 100644 --- a/src/video/linux/x11/pal_icon_x11.c +++ b/src/video/x11/pal_icon_x11.c @@ -5,11 +5,8 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_X11_BACKEND == 1 - #include "pal_x11.h" -#include "pal_shared.h" PalResult xCreateIcon( const PalIconCreateInfo* info, @@ -17,13 +14,9 @@ PalResult xCreateIcon( { uint64_t totalPixels = 2 + (uint64_t)(info->width * info->height); uint64_t totalBytes = sizeof(unsigned long) * totalPixels; - - unsigned long* icon = palAllocate(s_Video.allocator, totalBytes, 0); + unsigned long* icon = palAllocate(s_X11.allocator, totalBytes, 0); if (!icon) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } // store width and height and populate data with icon pixels @@ -53,7 +46,7 @@ PalResult xCreateIcon( void xDestroyIcon(PalIcon* icon) { if (icon) { - palFree(s_Video.allocator, icon); + palFree(s_X11.allocator, icon); } } @@ -65,10 +58,7 @@ PalResult xSetWindowIcon( Window xWin = FROM_PAL_HANDLE(Window, window); s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&winData); if (!winData) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } unsigned long* iconData = FROM_PAL_HANDLE(unsigned long*, icon); @@ -87,5 +77,4 @@ PalResult xSetWindowIcon( return PAL_RESULT_SUCCESS; } -#endif // PAL_HAS_X11_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_X11_BACKEND \ No newline at end of file diff --git a/src/video/linux/x11/pal_monitor_x11.c b/src/video/x11/pal_monitor_x11.c similarity index 78% rename from src/video/linux/x11/pal_monitor_x11.c rename to src/video/x11/pal_monitor_x11.c index 27e4554a..f737cbe0 100644 --- a/src/video/linux/x11/pal_monitor_x11.c +++ b/src/video/x11/pal_monitor_x11.c @@ -5,11 +5,8 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_X11_BACKEND == 1 - #include "pal_x11.h" -#include "pal_shared.h" #include PalResult xEnumerateMonitors( @@ -46,11 +43,7 @@ PalResult xGetPrimaryMonitor(PalMonitor** outMonitor) *outMonitor = TO_PAL_HANDLE(PalMonitor, primary); return PAL_RESULT_SUCCESS; } - - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } PalResult xGetMonitorInfo( @@ -58,32 +51,23 @@ PalResult xGetMonitorInfo( PalMonitorInfo* info) { XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); - + RROutput output = FROM_PAL_HANDLE(RROutput, monitor); + XRROutputInfo* outputInfo = s_X11.getOutputInfo(s_X11.display, resources, output); if (!outputInfo) { // invalid monitor s_X11.freeScreenResources(resources); - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (outputInfo->connection != RR_Connected) { // invalid monitor s_X11.freeScreenResources(resources); - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } - strcpy(info->name, outputInfo->name); - // check if its primary monitor + strcpy(info->name, outputInfo->name); RROutput primary = s_X11.getOutputPrimary(s_X11.display, s_X11.root); - if (monitor == TO_PAL_HANDLE(PalMonitor, primary)) { info->primary = PAL_TRUE; } else { @@ -152,7 +136,6 @@ PalResult xGetMonitorInfo( } info->dpi = (uint32_t)(closest * 96.0f); - s_X11.freeCrtcInfo(crtc); s_X11.freeOutputInfo(outputInfo); s_X11.freeScreenResources(resources); @@ -170,25 +153,18 @@ PalResult xEnumerateMonitorModes( XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); // get the monitor info - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); - + RROutput output = FROM_PAL_HANDLE(RROutput, monitor); + XRROutputInfo* outputInfo = s_X11.getOutputInfo(s_X11.display, resources, output); if (!outputInfo) { // invalid monitor s_X11.freeScreenResources(resources); - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (outputInfo->connection != RR_Connected) { // invalid monitor s_X11.freeScreenResources(resources); - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // get supported display modes @@ -221,7 +197,6 @@ PalResult xEnumerateMonitorModes( s_X11.freeOutputInfo(outputInfo); s_X11.freeScreenResources(resources); - return PAL_RESULT_SUCCESS; } @@ -232,30 +207,23 @@ PalResult xGetCurrentMonitorMode( XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); // get the monitor info - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); + RROutput output = FROM_PAL_HANDLE(RROutput, monitor); + XRROutputInfo* outputInfo =s_X11.getOutputInfo(s_X11.display, resources, output); if (!outputInfo) { // invalid monitor s_X11.freeScreenResources(resources); - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (outputInfo->connection != RR_Connected) { // invalid monitor s_X11.freeScreenResources(resources); - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // get the current display mode XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - // find the display mode XRRModeInfo* info = nullptr; for (int i = 0; i < resources->nmode; ++i) { @@ -290,25 +258,19 @@ PalResult xSetMonitorMode( XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); // get the monitor info - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); + RROutput output = FROM_PAL_HANDLE(RROutput, monitor); + XRROutputInfo* outputInfo = s_X11.getOutputInfo(s_X11.display, resources, output); if (!outputInfo) { // invalid monitor s_X11.freeScreenResources(resources); - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (outputInfo->connection != RR_Connected) { // invalid monitor s_X11.freeScreenResources(resources); - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // find the monitor display mode @@ -316,17 +278,11 @@ PalResult xSetMonitorMode( if (displayMode == None) { s_X11.freeOutputInfo(outputInfo); s_X11.freeScreenResources(resources); - - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // apply the display mode XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - - RROutput output = FROM_PAL_HANDLE(RROutput, monitor); int ret = s_X11.setCrtcConfig( s_X11.display, resources, @@ -342,12 +298,8 @@ PalResult xSetMonitorMode( s_X11.freeCrtcInfo(crtc); s_X11.freeOutputInfo(outputInfo); s_X11.freeScreenResources(resources); - if (ret != Success) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } return PAL_RESULT_SUCCESS; @@ -357,10 +309,7 @@ PalResult xValidateMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult xSetMonitorOrientation( @@ -370,25 +319,18 @@ PalResult xSetMonitorOrientation( XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); // get the monitor info - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); - + RROutput output = FROM_PAL_HANDLE(RROutput, monitor); + XRROutputInfo* outputInfo = s_X11.getOutputInfo(s_X11.display, resources, output); if (!outputInfo) { // invalid monitor s_X11.freeScreenResources(resources); - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (outputInfo->connection != RR_Connected) { // invalid monitor s_X11.freeScreenResources(resources); - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // get the current display mode @@ -419,13 +361,9 @@ PalResult xSetMonitorOrientation( } if (!(crtc->rotations & rotation)) { - return palMakeResult( - PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_OPERATION; } - RROutput output = FROM_PAL_HANDLE(RROutput, monitor); int ret = s_X11.setCrtcConfig( s_X11.display, resources, @@ -441,16 +379,11 @@ PalResult xSetMonitorOrientation( s_X11.freeCrtcInfo(crtc); s_X11.freeOutputInfo(outputInfo); s_X11.freeScreenResources(resources); - if (ret != Success) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } return PAL_RESULT_SUCCESS; } -#endif // PAL_HAS_X11_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_X11_BACKEND \ No newline at end of file diff --git a/src/video/linux/x11/pal_video_x11.c b/src/video/x11/pal_video_x11.c similarity index 70% rename from src/video/linux/x11/pal_video_x11.c rename to src/video/x11/pal_video_x11.c index e01c0e2d..0969d19f 100644 --- a/src/video/linux/x11/pal_video_x11.c +++ b/src/video/x11/pal_video_x11.c @@ -5,16 +5,40 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_X11_BACKEND == 1 - #include "pal_x11.h" -#include "pal_shared.h" #include #include +#include + +#define NULL_BUTTON_SERIAL 0xffffffffU + +typedef struct { + int32_t lastX; + int32_t lastY; + int32_t dx; + int32_t dy; + int32_t WheelX; + int32_t WheelY; + PalBool state[PAL_MOUSE_BUTTON_COUNT]; +} Mouse; + +typedef struct { + PalBool scancodeState[PAL_SCANCODE_COUNT]; + PalBool keycodeState[PAL_KEYCODE_COUNT]; + int scancodes[512]; + int keycodes[256]; +} Keyboard; X11 s_X11 = {0}; X11Atoms s_X11Atoms = {0}; +static Mouse s_Mouse = {0}; +static Keyboard s_Keyboard = {0}; + +static void resetMonitorData() +{ + memset(s_X11.monitorData, 0, s_X11.maxMonitorData * sizeof(MonitorData)); +} RRMode findMode( XRRScreenResources* resources, @@ -22,7 +46,6 @@ RRMode findMode( { for (int i = 0; i < resources->nmode; ++i) { XRRModeInfo* info = &resources->modes[i]; - double tmp = (double)info->hTotal * (double)info->vTotal; double rate = (double)info->dotClock / tmp; @@ -142,7 +165,7 @@ static void checkFeatures() features |= PAL_VIDEO_FEATURE_FOREIGN_WINDOWS; features |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; - s_Video.features = features; + s_X11.features = features; s_X11.free(supportedAtoms); } @@ -199,7 +222,7 @@ static void cacheMonitors() // get monitor data and update info PalMonitor* monitor = TO_PAL_HANDLE(PalMonitor, output); MonitorData* data = nullptr; - data = getFreeMonitorData(); + data = xGetFreeMonitorData(); if (!data) { return; } @@ -242,13 +265,13 @@ static int getWindowMonitorDPI(WindowData* data) int winX = data->x + data->w / 2; int winY = data->y + data->w / 2; // get the DPI from our cached monitor - for (int i = 0; i < s_Video.maxMonitorData; i++) { - if (!s_Video.monitorData->used) { + for (int i = 0; i < s_X11.maxMonitorData; i++) { + if (!s_X11.monitorData->used) { continue; } // we found a monitor, check the monitor bounds with the window - MonitorData* info = &s_Video.monitorData[i]; + MonitorData* info = &s_X11.monitorData[i]; if (winX >= info->x && winX < info->x + info->w && winY >= info->y && winY < info->y + info->h) { // found monitor @@ -291,6 +314,129 @@ void sendWMEvent( &e); } +static void createScancodeTable() +{ + // Letters + s_Keyboard.scancodes[0x01E] = PAL_SCANCODE_A; + s_Keyboard.scancodes[0x030] = PAL_SCANCODE_B; + s_Keyboard.scancodes[0x02E] = PAL_SCANCODE_C; + s_Keyboard.scancodes[0x020] = PAL_SCANCODE_D; + s_Keyboard.scancodes[0x012] = PAL_SCANCODE_E; + s_Keyboard.scancodes[0x021] = PAL_SCANCODE_F; + s_Keyboard.scancodes[0x022] = PAL_SCANCODE_G; + s_Keyboard.scancodes[0x023] = PAL_SCANCODE_H; + s_Keyboard.scancodes[0x017] = PAL_SCANCODE_I; + s_Keyboard.scancodes[0x024] = PAL_SCANCODE_J; + s_Keyboard.scancodes[0x025] = PAL_SCANCODE_K; + s_Keyboard.scancodes[0x026] = PAL_SCANCODE_L; + s_Keyboard.scancodes[0x032] = PAL_SCANCODE_M; + s_Keyboard.scancodes[0x031] = PAL_SCANCODE_N; + s_Keyboard.scancodes[0x018] = PAL_SCANCODE_O; + s_Keyboard.scancodes[0x019] = PAL_SCANCODE_P; + s_Keyboard.scancodes[0x010] = PAL_SCANCODE_Q; + s_Keyboard.scancodes[0x013] = PAL_SCANCODE_R; + s_Keyboard.scancodes[0x01F] = PAL_SCANCODE_S; + s_Keyboard.scancodes[0x014] = PAL_SCANCODE_T; + s_Keyboard.scancodes[0x016] = PAL_SCANCODE_U; + s_Keyboard.scancodes[0x02F] = PAL_SCANCODE_V; + s_Keyboard.scancodes[0x011] = PAL_SCANCODE_W; + s_Keyboard.scancodes[0x02D] = PAL_SCANCODE_X; + s_Keyboard.scancodes[0x015] = PAL_SCANCODE_Y; + s_Keyboard.scancodes[0x02C] = PAL_SCANCODE_Z; + + // Numbers (top row) + s_Keyboard.scancodes[0x00B] = PAL_SCANCODE_0; + s_Keyboard.scancodes[0x002] = PAL_SCANCODE_1; + s_Keyboard.scancodes[0x003] = PAL_SCANCODE_2; + s_Keyboard.scancodes[0x004] = PAL_SCANCODE_3; + s_Keyboard.scancodes[0x005] = PAL_SCANCODE_4; + s_Keyboard.scancodes[0x006] = PAL_SCANCODE_5; + s_Keyboard.scancodes[0x007] = PAL_SCANCODE_6; + s_Keyboard.scancodes[0x008] = PAL_SCANCODE_7; + s_Keyboard.scancodes[0x009] = PAL_SCANCODE_8; + s_Keyboard.scancodes[0x00A] = PAL_SCANCODE_9; + + // Function + s_Keyboard.scancodes[0x03B] = PAL_SCANCODE_F1; + s_Keyboard.scancodes[0x03C] = PAL_SCANCODE_F2; + s_Keyboard.scancodes[0x03D] = PAL_SCANCODE_F3; + s_Keyboard.scancodes[0x03E] = PAL_SCANCODE_F4; + s_Keyboard.scancodes[0x03F] = PAL_SCANCODE_F5; + s_Keyboard.scancodes[0x040] = PAL_SCANCODE_F6; + s_Keyboard.scancodes[0x041] = PAL_SCANCODE_F7; + s_Keyboard.scancodes[0x042] = PAL_SCANCODE_F8; + s_Keyboard.scancodes[0x043] = PAL_SCANCODE_F9; + s_Keyboard.scancodes[0x044] = PAL_SCANCODE_F10; + s_Keyboard.scancodes[0x057] = PAL_SCANCODE_F11; + s_Keyboard.scancodes[0x058] = PAL_SCANCODE_F12; + + // Control + s_Keyboard.scancodes[0x001] = PAL_SCANCODE_ESCAPE; + s_Keyboard.scancodes[0x01C] = PAL_SCANCODE_ENTER; + s_Keyboard.scancodes[0x00F] = PAL_SCANCODE_TAB; + s_Keyboard.scancodes[0x00E] = PAL_SCANCODE_BACKSPACE; + s_Keyboard.scancodes[0x039] = PAL_SCANCODE_SPACE; + s_Keyboard.scancodes[0x03A] = PAL_SCANCODE_CAPSLOCK; + s_Keyboard.scancodes[0x045] = PAL_SCANCODE_NUMLOCK; + s_Keyboard.scancodes[0x046] = PAL_SCANCODE_SCROLLLOCK; + s_Keyboard.scancodes[0x02A] = PAL_SCANCODE_LSHIFT; + s_Keyboard.scancodes[0x036] = PAL_SCANCODE_RSHIFT; + s_Keyboard.scancodes[0x01D] = PAL_SCANCODE_LCTRL; + s_Keyboard.scancodes[0x061] = PAL_SCANCODE_RCTRL; + s_Keyboard.scancodes[0x038] = PAL_SCANCODE_LALT; + s_Keyboard.scancodes[0x064] = PAL_SCANCODE_RALT; + + // Arrows + s_Keyboard.scancodes[0x069] = PAL_SCANCODE_LEFT; + s_Keyboard.scancodes[0x06A] = PAL_SCANCODE_RIGHT; + s_Keyboard.scancodes[0x067] = PAL_SCANCODE_UP; + s_Keyboard.scancodes[0x06C] = PAL_SCANCODE_DOWN; + + // Navigation + s_Keyboard.scancodes[0x06E] = PAL_SCANCODE_INSERT; + s_Keyboard.scancodes[0x06F] = PAL_SCANCODE_DELETE; + s_Keyboard.scancodes[0x066] = PAL_SCANCODE_HOME; + s_Keyboard.scancodes[0x067] = PAL_SCANCODE_END; + s_Keyboard.scancodes[0x068] = PAL_SCANCODE_PAGEUP; + s_Keyboard.scancodes[0x06D] = PAL_SCANCODE_PAGEDOWN; + + // Keypad + s_Keyboard.scancodes[0x052] = PAL_SCANCODE_KP_0; + s_Keyboard.scancodes[0x04F] = PAL_SCANCODE_KP_1; + s_Keyboard.scancodes[0x050] = PAL_SCANCODE_KP_2; + s_Keyboard.scancodes[0x051] = PAL_SCANCODE_KP_3; + s_Keyboard.scancodes[0x04B] = PAL_SCANCODE_KP_4; + s_Keyboard.scancodes[0x04C] = PAL_SCANCODE_KP_5; + s_Keyboard.scancodes[0x04D] = PAL_SCANCODE_KP_6; + s_Keyboard.scancodes[0x047] = PAL_SCANCODE_KP_7; + s_Keyboard.scancodes[0x048] = PAL_SCANCODE_KP_8; + s_Keyboard.scancodes[0x049] = PAL_SCANCODE_KP_9; + s_Keyboard.scancodes[0x060] = PAL_SCANCODE_KP_ENTER; + s_Keyboard.scancodes[0x04E] = PAL_SCANCODE_KP_ADD; + s_Keyboard.scancodes[0x04A] = PAL_SCANCODE_KP_SUBTRACT; + s_Keyboard.scancodes[0x037] = PAL_SCANCODE_KP_MULTIPLY; + s_Keyboard.scancodes[0x062] = PAL_SCANCODE_KP_DIVIDE; + s_Keyboard.scancodes[0x053] = PAL_SCANCODE_KP_DECIMAL; + + // Misc + s_Keyboard.scancodes[0x063] = PAL_SCANCODE_PRINTSCREEN; + s_Keyboard.scancodes[0x066] = PAL_SCANCODE_PAUSE; + s_Keyboard.scancodes[0x07F] = PAL_SCANCODE_MENU; + s_Keyboard.scancodes[0x028] = PAL_SCANCODE_APOSTROPHE; + s_Keyboard.scancodes[0x02B] = PAL_SCANCODE_BACKSLASH; + s_Keyboard.scancodes[0x033] = PAL_SCANCODE_COMMA; + s_Keyboard.scancodes[0x00D] = PAL_SCANCODE_EQUAL; + s_Keyboard.scancodes[0x029] = PAL_SCANCODE_GRAVEACCENT; + s_Keyboard.scancodes[0x00C] = PAL_SCANCODE_SUBTRACT; + s_Keyboard.scancodes[0x034] = PAL_SCANCODE_PERIOD; + s_Keyboard.scancodes[0x027] = PAL_SCANCODE_SEMICOLON; + s_Keyboard.scancodes[0x035] = PAL_SCANCODE_SLASH; + s_Keyboard.scancodes[0x01A] = PAL_SCANCODE_LBRACKET; + s_Keyboard.scancodes[0x01B] = PAL_SCANCODE_RBRACKET; + s_Keyboard.scancodes[0x07D] = PAL_SCANCODE_LSUPER; + s_Keyboard.scancodes[0x07E] = PAL_SCANCODE_RSUPER; +} + static void createKeycodeTable() { // Tis is for only printable and text input keys @@ -340,27 +486,116 @@ static void createKeycodeTable() s_Keyboard.keycodes[XK_bracketright] = PAL_KEYCODE_RBRACKET; } -PalResult xInitVideo() +MonitorData* xGetFreeMonitorData() { - // load X11 library - s_X11.handle = dlopen("libX11.so", RTLD_LAZY); - if (!s_X11.handle) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + for (int i = 0; i < s_X11.maxMonitorData; ++i) { + if (!s_X11.monitorData[i].used) { + s_X11.monitorData[i].used = PAL_TRUE; + return &s_X11.monitorData[i]; + } } - // libXCursor is needed + // resize the data array + // this will almost not reach here since most setups are 1-4 monitors + MonitorData* data = nullptr; + int count = s_X11.maxMonitorData * 2; // double the size + int freeIndex = s_X11.maxMonitorData + 1; + data = palAllocate(s_X11.allocator, sizeof(MonitorData) * count, 0); + if (data) { + memcpy( + data, + s_X11.monitorData, + s_X11.maxMonitorData * sizeof(MonitorData)); + + palFree(s_X11.allocator, s_X11.monitorData); + s_X11.monitorData = data; + s_X11.maxWindowData = count; + + s_X11.monitorData[freeIndex].used = PAL_TRUE; + return &s_X11.monitorData[freeIndex]; + } + return nullptr; +} + +MonitorData* xFindMonitorData(PalMonitor* monitor) +{ + for (int i = 0; i < s_X11.maxMonitorData; ++i) { + if (s_X11.monitorData[i].used && + s_X11.monitorData[i].monitor == monitor) { + return &s_X11.monitorData[i]; + } + } + return nullptr; +} + +void xFreeMonitorData(PalMonitor* monitor) +{ + for (int i = 0; i < s_X11.maxMonitorData; ++i) { + if (s_X11.monitorData[i].used && + s_X11.monitorData[i].monitor == monitor) { + s_X11.monitorData[i].used = PAL_FALSE; + } + } +} + +WindowData* xGetFreeWindowData() +{ + for (int i = 0; i < s_X11.maxWindowData; ++i) { + if (!s_X11.windowData[i].used) { + s_X11.windowData[i].used = PAL_TRUE; + return &s_X11.windowData[i]; + } + } + + // resize the data array + // It is rare for a user to create and manage + // 32 windows at the same time + WindowData* data = nullptr; + int count = s_X11.maxWindowData * 2; // double the size + int freeIndex = s_X11.maxWindowData + 1; + data = palAllocate(s_X11.allocator, sizeof(WindowData) * count, 0); + if (data) { + memcpy( + data, + s_X11.windowData, + s_X11.maxWindowData * sizeof(WindowData)); + + palFree(s_X11.allocator, s_X11.windowData); + s_X11.windowData = data; + s_X11.maxWindowData = count; + + s_X11.windowData[freeIndex].used = PAL_TRUE; + return &s_X11.windowData[freeIndex]; + } + return nullptr; +} + +WindowData* xFindWindowData(PalWindow* window) +{ + for (int i = 0; i < s_X11.maxWindowData; ++i) { + if (s_X11.windowData[i].used && + s_X11.windowData[i].window == window) { + return &s_X11.windowData[i]; + } + } + return nullptr; +} + +PalResult xInitVideo( + const PalAllocator* allocator, + PalEventDriver* eventDriver, + void* preferredInstance) +{ + // load X11 dependencies + s_X11.handle = dlopen("libX11.so", RTLD_LAZY); s_X11.libCursor = dlopen("libXcursor.so", RTLD_LAZY); - if (!s_X11.libCursor) { + if (!s_X11.handle || !s_X11.libCursor) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_POSIX, errno); } - // Xrandr is needed s_X11.xrandr = dlopen("libXrandr.so.2", RTLD_LAZY); if (!s_X11.xrandr) { s_X11.xrandr = dlopen("libXrandr.so", RTLD_LAZY); @@ -667,30 +902,31 @@ PalResult xInitVideo() "Xutf8LookupString"); // clang-format on + s_X11.maxMonitorData = 16; // initial size + s_X11.maxWindowData = 32; // initial size + s_X11.windowData = palAllocate(s_X11.allocator, sizeof(WindowData) * s_X11.maxWindowData, 0); + s_X11.monitorData = palAllocate(s_X11.allocator,sizeof(MonitorData) * s_X11.maxMonitorData, 0); + if (!s_X11.monitorData || !s_X11.windowData) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + // X11 server - if (s_Video.display) { - s_X11.display = (Display*)s_Video.display; + if (preferredInstance) { + s_X11.display = (Display*)preferredInstance; } else { s_X11.display = s_X11.openDisplay(nullptr); - s_Video.display = nullptr; - } - - if (!s_X11.display) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + if (!s_X11.display) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } } s_X11.root = DefaultRootWindow(s_X11.display); s_X11.screen = DefaultScreen(s_X11.display); - checkFeatures(); // subscribe for monitor events s_X11.selectRRInput(s_X11.display, s_X11.root, RRScreenChangeNotifyMask | RRNotify); - int eventBase, errorBase = 0; s_X11.queryRRExtension(s_X11.display, &eventBase, &errorBase); s_X11.rrEventBase = eventBase; @@ -702,9 +938,6 @@ PalResult xInitVideo() s_X11.monitorCount = 0; cacheMonitors(); - // since X11 supports both EGL and GLX - // we try to load them and resolve the needed functions - // we load GLX s_X11.glxHandle = dlopen("libGL.so.1", RTLD_LAZY); if (s_X11.glxHandle) { @@ -716,7 +949,24 @@ PalResult xInitVideo() (GLXGetVisualFromFBConfigFn)load("glXGetVisualFromFBConfig"); } + // load EGL + s_Egl.handle = dlopen("libEGL.so", RTLD_LAZY); + if (s_Egl.handle) { + eglGetProcAddressFn load = nullptr; + load = (eglGetProcAddressFn)dlsym(s_Egl.handle, "eglGetProcAddress"); + + s_Egl.eglInitialize = (eglInitializeFn)load("eglInitialize"); + s_Egl.eglTerminate = (eglTerminateFn)load("eglTerminate"); + s_Egl.eglGetDisplay = (eglGetDisplayFn)load("eglGetDisplay"); + s_Egl.eglChooseConfig = (eglChooseConfigFn)load("eglChooseConfig"); + s_Egl.eglGetError = (eglGetErrorFn)load("eglGetError"); + s_Egl.eglBindAPI = (eglBindAPIFn)load("eglBindAPI"); + s_Egl.eglGetConfigs = (eglGetConfigsFn)load("eglGetConfigs"); + s_Egl.eglGetConfigAttrib = (eglGetConfigAttribFn)load("eglGetConfigAttrib"); + } + createKeycodeTable(); + createScancodeTable(); // disable auto key repeats int supported; @@ -726,30 +976,34 @@ PalResult xInitVideo() s_X11.setLocaleModifiers(""); s_X11.im = s_X11.openIM(s_X11.display, nullptr, nullptr, nullptr); if (s_X11.im == None) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } - s_Video.display = (void*)s_X11.display; + s_X11.allocator = allocator; + s_X11.eventDriver = eventDriver; return PAL_RESULT_SUCCESS; } void xShutdownVideo() { s_X11.closeIM(s_X11.im); - if (!s_Video.display) { + if (!s_X11.display) { // opened by PAL s_X11.closeDisplay(s_X11.display); dlclose(s_X11.handle); dlclose(s_X11.xrandr); dlclose(s_X11.libCursor); + } - if (s_X11.glxHandle) { - dlclose(s_X11.glxHandle); - } + palFree(s_X11.allocator, s_X11.windowData); + palFree(s_X11.allocator, s_X11.monitorData); + if (s_Egl.handle) { + dlclose(s_Egl.handle); + } + + if (s_X11.glxHandle) { + dlclose(s_X11.glxHandle); } memset(&s_X11, 0, sizeof(X11)); @@ -759,7 +1013,7 @@ void xShutdownVideo() void xUpdateVideo() { XEvent event; - PalDispatchMode mode = PAL_DISPATCH_NONE; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; while (s_X11.pending(s_X11.display)) { s_X11.nextEvent(s_X11.display, &event); @@ -777,11 +1031,11 @@ void xUpdateVideo() // check for window close Atom windowClose = event.xclient.data.l[0]; if (windowClose == s_X11Atoms.WM_DELETE_WINDOW) { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_CLOSE; + if (s_X11.eventDriver) { + PalEventDriver* driver = s_X11.eventDriver; + PalEventType type = PAL_EVENT_TYPE_WINDOW_CLOSE; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data2 = palPackPointer(window); @@ -806,18 +1060,18 @@ void xUpdateVideo() } // real configure event - if (s_Video.eventDriver) { + if (s_X11.eventDriver) { // check if its a resize event if (data->w != event.xconfigure.width || data->h != event.xconfigure.height) { data->w = event.xconfigure.width; data->h = event.xconfigure.height; // push a resize event - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_SIZE; + PalEventDriver* driver = s_X11.eventDriver; + PalEventType type = PAL_EVENT_TYPE_WINDOW_SIZE; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackUint32(data->w, data->h); @@ -841,11 +1095,11 @@ void xUpdateVideo() data->y = event.xconfigure.y; // push a move event - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_MOVE; + PalEventDriver* driver = s_X11.eventDriver; + PalEventType type = PAL_EVENT_TYPE_WINDOW_MOVE; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackInt32(data->x, data->y); @@ -864,10 +1118,10 @@ void xUpdateVideo() data->dpi = monitorDPI; // push a DPI event - type = PAL_EVENT_MONITOR_DPI_CHANGED; + type = PAL_EVENT_TYPE_MONITOR_DPI_CHANGED; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = monitorDPI; @@ -882,17 +1136,17 @@ void xUpdateVideo() case FocusIn: { // window has gained focus - if (s_Video.eventDriver) { + if (s_X11.eventDriver) { int mode = event.xfocus.mode; if (mode == NotifyGrab || mode == NotifyUngrab) { // ignore dragging and popup focus events break; } - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_FOCUS; + PalEventDriver* driver = s_X11.eventDriver; + PalEventType type = PAL_EVENT_TYPE_WINDOW_FOCUS; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = PAL_TRUE; @@ -905,17 +1159,17 @@ void xUpdateVideo() case FocusOut: { // window has lost focus - if (s_Video.eventDriver) { + if (s_X11.eventDriver) { int mode = event.xfocus.mode; if (mode == NotifyGrab || mode == NotifyUngrab) { // ignore dragging and popup focus events break; } - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_FOCUS; + PalEventDriver* driver = s_X11.eventDriver; + PalEventType type = PAL_EVENT_TYPE_WINDOW_FOCUS; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = PAL_FALSE; @@ -941,11 +1195,11 @@ void xUpdateVideo() } // push event - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_STATE; + PalEventDriver* driver = s_X11.eventDriver; + PalEventType type = PAL_EVENT_TYPE_WINDOW_STATE; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = data->state; @@ -971,11 +1225,11 @@ void xUpdateVideo() if (oldCount != s_X11.monitorCount) { // a monitor has been added or removed - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MONITOR_LIST_CHANGED; + if (s_X11.eventDriver) { + PalEventDriver* driver = s_X11.eventDriver; + PalEventType type = PAL_EVENT_TYPE_MONITOR_LIST_CHANGED; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data2 = palPackPointer(window); @@ -993,11 +1247,11 @@ void xUpdateVideo() const int dx = x - s_Mouse.lastX; const int dy = y - s_Mouse.lastY; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MOUSE_MOVE; + if (s_X11.eventDriver) { + PalEventDriver* driver = s_X11.eventDriver; + PalEventType type = PAL_EVENT_TYPE_MOUSE_MOVE; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackInt32(x, y); @@ -1006,9 +1260,9 @@ void xUpdateVideo() } // push a mouse delta event - type = PAL_EVENT_MOUSE_DELTA; + type = PAL_EVENT_TYPE_MOUSE_DELTA; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackFloat((float)dx, (float)dy); @@ -1040,16 +1294,16 @@ void xUpdateVideo() } s_Mouse.state[button] = pressed; - if (s_Video.eventDriver && button != 0) { - PalEventDriver* driver = s_Video.eventDriver; + if (s_X11.eventDriver && button != 0) { + PalEventDriver* driver = s_X11.eventDriver; if (pressed) { - type = PAL_EVENT_MOUSE_BUTTONDOWN; + type = PAL_EVENT_TYPE_MOUSE_BUTTONDOWN; } else { - type = PAL_EVENT_MOUSE_BUTTONUP; + type = PAL_EVENT_TYPE_MOUSE_BUTTONUP; } mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackUint32(button, NULL_BUTTON_SERIAL); @@ -1076,12 +1330,12 @@ void xUpdateVideo() s_Mouse.WheelX = scrollX; s_Mouse.WheelY = scrollY; - if (s_Video.eventDriver && (scrollX || scrollY)) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_WHEEL); - if (mode != PAL_DISPATCH_NONE) { + if (s_X11.eventDriver && (scrollX || scrollY)) { + PalEventDriver* driver = s_X11.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_MOUSE_WHEEL); + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; - event.type = PAL_EVENT_MOUSE_WHEEL; + event.type = PAL_EVENT_TYPE_MOUSE_WHEEL; event.data = palPackFloat((float)scrollX, (float)scrollY); event.data2 = palPackPointer(window); palPushEvent(driver, &event); @@ -1141,18 +1395,18 @@ void xUpdateVideo() if (pressed) { if (repeat) { - type = PAL_EVENT_KEYREPEAT; + type = PAL_EVENT_TYPE_KEYREPEAT; } else { - type = PAL_EVENT_KEYDOWN; + type = PAL_EVENT_TYPE_KEYDOWN; } } else { - type = PAL_EVENT_KEYUP; + type = PAL_EVENT_TYPE_KEYUP; } - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; + if (s_X11.eventDriver) { + PalEventDriver* driver = s_X11.eventDriver; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackUint32(keycode, scancode); @@ -1161,9 +1415,9 @@ void xUpdateVideo() } // check for char event if enabled - type = PAL_EVENT_KEYCHAR; + type = PAL_EVENT_TYPE_KEYCHAR; mode = palGetEventDispatchMode(driver, type); - if (mode == PAL_DISPATCH_NONE) { + if (mode == PAL_DISPATCH_MODE_NONE) { break; } @@ -1223,10 +1477,55 @@ void xUpdateVideo() s_X11.flush(s_X11.display); } +PalVideoFeatures xGetVideoFeatures() +{ + return s_X11.features; +} + +const PalBool* xGetKeycodeState() +{ + return s_Keyboard.keycodeState; +} + +const PalBool* xGetScancodeState() +{ + return s_Keyboard.scancodeState; +} + +const PalBool* xGetMouseState() +{ + return s_Mouse.state; +} + +void xGetMouseDelta( + float* dx, + float* dy) +{ + if (dx) { + *dx = (float)s_Mouse.dx; + } + + if (dy) { + *dy = (float)s_Mouse.dy; + } +} + +void xGetMouseWheelDelta( + float* dx, + float* dy) +{ + if (dx) { + *dx = (float)s_Mouse.WheelX; + } + + if (dy) { + *dy = (float)s_Mouse.WheelY; + } +} + void* xGetInstance() { return (void*)s_X11.display; } -#endif // PAL_HAS_X11_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_X11_BACKEND \ No newline at end of file diff --git a/src/video/linux/x11/pal_window_x11.c b/src/video/x11/pal_window_x11.c similarity index 79% rename from src/video/linux/x11/pal_window_x11.c rename to src/video/x11/pal_window_x11.c index 3578dc0e..dc339195 100644 --- a/src/video/linux/x11/pal_window_x11.c +++ b/src/video/x11/pal_window_x11.c @@ -5,14 +5,12 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifdef __linux__ #if PAL_HAS_X11_BACKEND == 1 - #include "pal_x11.h" -#include "pal_shared.h" #include #include #include +#include static int xErrorHandler( Display*, @@ -55,7 +53,7 @@ static XVisualInfo* eglXBackend(int fbConfigIndex) } EGLint configSize = sizeof(EGLConfig) * numConfigs; - EGLConfig* eglConfigs = palAllocate(s_Video.allocator, configSize, 0); + EGLConfig* eglConfigs = palAllocate(s_X11.allocator, configSize, 0); if (!eglConfigs) { return nullptr; } @@ -80,7 +78,7 @@ static XVisualInfo* eglXBackend(int fbConfigIndex) return nullptr; } - palFree(s_Video.allocator, eglConfigs); + palFree(s_X11.allocator, eglConfigs); return visualInfo; } @@ -92,12 +90,9 @@ PalResult xCreateWindow( PalMonitor* monitor = nullptr; PalMonitorInfo monitorInfo; - WindowData* data = getFreeWindowData(); + WindowData* data = xGetFreeWindowData(); if (!data) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } Visual* visual = nullptr; @@ -111,18 +106,18 @@ PalResult xCreateWindow( PalFBConfigBackend backend = info->fbConfigBackend; XVisualInfo* visualInfo = nullptr; - if (backend == PAL_CONFIG_BACKEND_PAL_OPENGL) { - backend = PAL_CONFIG_BACKEND_EGL; + if (backend == PAL_FBCONFIG_BACKEND_PAL_OPENGL) { + backend = PAL_FBCONFIG_BACKEND_EGL; } - if (backend == PAL_CONFIG_BACKEND_EGL) { + if (backend == PAL_FBCONFIG_BACKEND_EGL) { visualInfo = eglXBackend(info->fbConfigIndex); + } else if (backend == PAL_FBCONFIG_BACKEND_GLX) { + visualInfo = glxBackend(info->fbConfigIndex); + } else { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } // create a colormap from the visual info @@ -131,12 +126,8 @@ PalResult xCreateWindow( bgPixel = 0; borderPixel = 0; colormap = s_X11.createColormap(s_X11.display, s_X11.root, visual, AllocNone); - if (!colormap) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } data->colormap = colormap; @@ -184,8 +175,7 @@ PalResult xCreateWindow( resources = s_X11.getScreenResources(s_X11.display, s_X11.root); for (int i = 0; i < resources->noutput; ++i) { RROutput output = resources->outputs[i]; - XRROutputInfo* outputInfo = - s_X11.getOutputInfo(s_X11.display, resources, FROM_PAL_HANDLE(RROutput, monitor)); + XRROutputInfo* outputInfo = s_X11.getOutputInfo(s_X11.display, resources, output); // check if its a monitor if (outputInfo->connection != RR_Connected || outputInfo->crtc == None) { @@ -194,7 +184,6 @@ PalResult xCreateWindow( } XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - monitorX = crtc->x; monitorY = crtc->y; monitorW = crtc->width; @@ -215,7 +204,6 @@ PalResult xCreateWindow( } dpi = (uint32_t)(closest * 96.0f); - s_X11.freeCrtcInfo(crtc); s_X11.freeOutputInfo(outputInfo); break; @@ -237,13 +225,9 @@ PalResult xCreateWindow( // check and set transparency if (info->style & PAL_WINDOW_STYLE_TRANSPARENT) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW)) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + if (!(s_X11.features & PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } - // we dont need to set any flag } @@ -278,10 +262,7 @@ PalResult xCreateWindow( &attrs); if (window == None) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } // set pid property @@ -307,7 +288,7 @@ PalResult xCreateWindow( } if (!resClass || strlen(resClass) == 0) { - resClass = s_Video.className; + resClass = "PAL"; } hints->res_name = (char*)resName; @@ -335,12 +316,9 @@ PalResult xCreateWindow( // borderless if (info->style & PAL_WINDOW_STYLE_BORDERLESS) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_BORDERLESS_WINDOW)) { + if (!(s_X11.features & PAL_VIDEO_FEATURE_BORDERLESS_WINDOW)) { s_X11.destroyWindow(s_X11.display, window); - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } s_X11.changeProperty( @@ -356,13 +334,9 @@ PalResult xCreateWindow( // tool window if (info->style & PAL_WINDOW_STYLE_TOOL) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_TOOL_WINDOW)) { + if (!(s_X11.features & PAL_VIDEO_FEATURE_TOOL_WINDOW)) { s_X11.destroyWindow(s_X11.display, window); - - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } s_X11.changeProperty( @@ -421,13 +395,10 @@ PalResult xCreateWindow( PalBool windowMapped = attr.map_state = IsViewable; // maximize - if (info->maximized) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { + if (info->state == PAL_WINDOW_STATE_MAXIMIZED) { + if (!(s_X11.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { s_X11.destroyWindow(s_X11.display, window); - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } // if the window is not mapped, we wait till its mapped @@ -454,13 +425,10 @@ PalResult xCreateWindow( } // minimize - if (info->minimized) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { + if (info->state == PAL_WINDOW_STATE_MINIMIZED) { + if (!(s_X11.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { s_X11.destroyWindow(s_X11.display, window); - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } // if the window is not mapped, we wait till its mapped @@ -501,10 +469,7 @@ PalResult xCreateWindow( nullptr); if (!data->ic) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } *outWindow = TO_PAL_HANDLE(PalWindow, window); @@ -534,20 +499,14 @@ void xDestroyWindow(PalWindow* window) PalResult xMinimizeWindow(PalWindow* window) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + if (!(s_X11.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } s_X11.iconifyWindow(s_X11.display, xWin, s_X11.screen); @@ -556,20 +515,14 @@ PalResult xMinimizeWindow(PalWindow* window) PalResult xMaximizeWindow(PalWindow* window) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + if (!(s_X11.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } sendWMEvent( @@ -586,20 +539,14 @@ PalResult xMaximizeWindow(PalWindow* window) PalResult xRestoreWindow(PalWindow* window) { - if (!(s_Video.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + if (!(s_X11.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // since we have no fixed way to restore the window @@ -623,10 +570,7 @@ PalResult xShowWindow(PalWindow* window) Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } s_X11.mapWindow(s_X11.display, xWin); @@ -638,10 +582,7 @@ PalResult xHideWindow(PalWindow* window) Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } s_X11.unmapWindow(s_X11.display, xWin); @@ -652,24 +593,18 @@ PalResult xFlashWindow( PalWindow* window, const PalFlashInfo* info) { - if (info->flags & PAL_FLASH_CAPTION) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + if (info->flags & PAL_FLASH_FLAG_CAPTION) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } PalBool add = PAL_FALSE; - if (info->flags & PAL_FLASH_TRAY) { + if (info->flags & PAL_FLASH_FLAG_TRAY) { add = PAL_TRUE; } @@ -691,8 +626,8 @@ PalResult xFlashWindow( hints = s_X11.allocWMHints(); if (!hints) { return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, + PAL_RESULT_CODE_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_POSIX, errno); } @@ -714,20 +649,14 @@ PalResult xGetWindowStyle( PalWindowStyle* outStyle) { // Window Manager quirks - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult xGetWindowMonitor( PalWindow* window, PalMonitor** outMonitor) { - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult xGetWindowTitle( @@ -739,17 +668,11 @@ PalResult xGetWindowTitle( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (!outBuffer || bufferSize <= 0) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (s_X11Atoms.unicodeTitle) { @@ -782,10 +705,7 @@ PalResult xGetWindowTitle( } else { XTextProperty text; if (!s_X11.getWMName(s_X11.display, xWin, &text)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (bufferSize >= text.nitems) { @@ -808,10 +728,7 @@ PalResult xGetWindowPos( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (x) { @@ -833,10 +750,7 @@ PalResult xGetWindowSize( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (width) { @@ -857,10 +771,7 @@ PalResult xGetWindowState( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } Atom type; @@ -929,21 +840,11 @@ PalResult xGetWindowHandleInfo( PalWindow* window, PalWindowHandleInfo* info) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - if (!window || !info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } - info->nativeDisplay = (void*)s_X11.display; + info->nativeInstance = (void*)s_X11.display; info->nativeWindow = (void*)window; info->nativeHandle1 = nullptr; info->nativeHandle2 = nullptr; @@ -973,10 +874,7 @@ PalResult xSetWindowOpacity( s_X11.setErrorHandler(old); if (s_X11.error) { // technically, this is the only error that can occur - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } return PAL_RESULT_SUCCESS; @@ -987,10 +885,7 @@ PalResult xSetWindowStyle( PalWindowStyle style) { // Window Manager quirks - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult xSetWindowTitle( @@ -1000,10 +895,7 @@ PalResult xSetWindowTitle( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (s_X11Atoms.unicodeTitle) { @@ -1033,10 +925,7 @@ PalResult xSetWindowPos( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } s_X11.moveWindow(s_X11.display, xWin, x, y); @@ -1052,10 +941,7 @@ PalResult xSetWindowSize( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // X11 does not allow users resize programaticaly @@ -1091,16 +977,11 @@ PalResult xSetFocusWindow(PalWindow* window) Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (s_X11Atoms._NET_ACTIVE_WINDOW) { - sendWMEvent(xWin, s_X11Atoms._NET_ACTIVE_WINDOW, CurrentTime, 0, 0, 0, - PAL_TRUE); // 1 - + sendWMEvent(xWin, s_X11Atoms._NET_ACTIVE_WINDOW, CurrentTime, 0, 0, 0, PAL_TRUE); // 1 } else { s_X11.setInputFocus(s_X11.display, xWin, RevertToParent, CurrentTime); } @@ -1115,20 +996,14 @@ PalResult xAttachWindow( Window xWin = FROM_PAL_HANDLE(Window, windowHandle); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // get a free slot and set the window handle to it // we also set a flag to make sure we know this is an attached window - WindowData* data = getFreeWindowData(); + WindowData* data = xGetFreeWindowData(); if (!data) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } PalWindow* window = TO_PAL_HANDLE(PalWindow, xWin); @@ -1181,18 +1056,12 @@ PalResult xDetachWindow( WindowData* data = nullptr; s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&data); if (!data) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } if (data->isAttached == PAL_FALSE) { // window was created by PAL - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); + return PAL_RESULT_CODE_INVALID_HANDLE; } // detach the window @@ -1208,5 +1077,4 @@ PalResult xDetachWindow( return PAL_RESULT_SUCCESS; } -#endif // PAL_HAS_X11_BACKEND -#endif // __linux__ \ No newline at end of file +#endif // PAL_HAS_X11_BACKEND \ No newline at end of file diff --git a/src/video/linux/x11/pal_x11.h b/src/video/x11/pal_x11.h similarity index 91% rename from src/video/linux/x11/pal_x11.h rename to src/video/x11/pal_x11.h index d1e48be2..08952a75 100644 --- a/src/video/linux/x11/pal_x11.h +++ b/src/video/x11/pal_x11.h @@ -7,10 +7,14 @@ #ifndef _PAL_X11_H #define _PAL_X11_H -#ifdef __linux__ + #if PAL_HAS_X11_BACKEND == 1 -#include "video/linux/pal_video_linux.h" +#define TO_PAL_HANDLE(type, val) ((type*)(uintptr_t)(val)) +#define FROM_PAL_HANDLE(type, handle) ((type)(uintptr_t)(handle)) + +#include "pal/pal_video.h" +#include "video/pal_video_egl.h" #include #include #include @@ -450,6 +454,33 @@ typedef struct { Atom _NET_WM_ICON; } X11Atoms; +typedef struct { + PalBool skipConfigure; + PalBool skipState; + PalBool used; + PalBool isAttached; + PalBool skipIfAttached; + int x; + int y; + uint32_t w; + int dpi; + uint32_t h; + PalWindowState state; + PalWindow* window; + void* ic; + unsigned long colormap; +} WindowData; + +typedef struct { + PalBool used; + int dpi; + int x; + int y; + uint32_t w; + uint32_t h; + PalMonitor* monitor; +} MonitorData; + typedef struct { PalBool error; PalBool skipScreenEvent; @@ -467,6 +498,14 @@ typedef struct { Window root; XContext dataID; + int32_t maxWindowData; + int32_t maxMonitorData; + PalVideoFeatures features; + const PalAllocator* allocator; + PalEventDriver* eventDriver; + WindowData* windowData; + MonitorData* monitorData; + XOpenDisplayFn openDisplay; XCloseDisplayFn closeDisplay; XGetWindowAttributesFn getWindowAttributes; @@ -571,7 +610,11 @@ void sendWMEvent( PalBool add); PalResult xGetPrimaryMonitor(PalMonitor**); +MonitorData* xGetFreeMonitorData(); +MonitorData* xFindMonitorData(PalMonitor* monitor); +void xFreeMonitorData(PalMonitor* monitor); +WindowData* xGetFreeWindowData(); +WindowData* xFindWindowData(PalWindow* window); #endif // PAL_HAS_X11_BACKEND -#endif // __linux__ #endif // _PAL_X11_H \ No newline at end of file diff --git a/tests/tests_main.c b/tests/tests_main.c index 66c274f0..e8c73f51 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -40,7 +40,7 @@ int main(int argc, char** argv) // registerTest(charEventTest, "Char Event Test"); // registerTest(nativeIntegrationTest, "Native Integration Test"); // registerTest(nativeInstanceTest, "Native Instance Test"); - // registerTest(customDecorationTest, "Custom Decoration Test"); + registerTest(customDecorationTest, "Custom Decoration Test"); #endif // PAL_HAS_VIDEO_MODULE // This test can run without video system so long as your have a valid window diff --git a/tests/video/attach_window_test.c b/tests/video/attach_window_test.c index f49d0756..9b9c419a 100644 --- a/tests/video/attach_window_test.c +++ b/tests/video/attach_window_test.c @@ -244,12 +244,12 @@ PalBool attachWindowTest() } // we are interested in move and close events - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_MOVE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_MOVE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // we listen for key release events to attach and detach the window - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYUP, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYUP, PAL_DISPATCH_MODE_POLL); // PAL allows users create any kind of window not currently or will not // be supported by PAL and just attach the window. @@ -291,7 +291,7 @@ PalBool attachWindowTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { // we check if its really our attached window PalWindow* window = palUnpackPointer(event.data2); if (window == myWindow) { @@ -300,7 +300,7 @@ PalBool attachWindowTest() break; } - case PAL_EVENT_WINDOW_MOVE: { + case PAL_EVENT_TYPE_WINDOW_MOVE: { // this will be triggered for our attached window int32_t x, y; // x == low, y == high palUnpackInt32(event.data, &x, &y); @@ -308,7 +308,7 @@ PalBool attachWindowTest() break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -317,7 +317,7 @@ PalBool attachWindowTest() break; } - case PAL_EVENT_KEYUP: { + case PAL_EVENT_TYPE_KEYUP: { // we detach the window after keyup // since if the window is detached, // we wont recieve the key up event diff --git a/tests/video/char_event_test.c b/tests/video/char_event_test.c index 0a62cc06..30ef2a82 100644 --- a/tests/video/char_event_test.c +++ b/tests/video/char_event_test.c @@ -54,10 +54,10 @@ PalBool charEventTest() return PAL_FALSE; } - // we only neeed PAL_EVENT_KEYCHAR and PAL_EVENT_WINDOW_CLOSE - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYCHAR, PAL_DISPATCH_POLL); + // we only neeed PAL_EVENT_TYPE_KEYCHAR and PAL_EVENT_TYPE_WINDOW_CLOSE + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYCHAR, PAL_DISPATCH_MODE_POLL); PalBool running = PAL_TRUE; while (running) { @@ -67,12 +67,12 @@ PalBool charEventTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYCHAR: { + case PAL_EVENT_TYPE_KEYCHAR: { uint32_t codepoint = (uint32_t)event.data; PalWindow* window = palUnpackPointer(event.data2); @@ -89,7 +89,7 @@ PalBool charEventTest() break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { diff --git a/tests/video/cursor_test.c b/tests/video/cursor_test.c index dcaa9d0e..6b887a54 100644 --- a/tests/video/cursor_test.c +++ b/tests/video/cursor_test.c @@ -101,8 +101,8 @@ PalBool cursorTest() } // set the dispatch mode for window close event to recieve it - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // set the cursor palSetWindowCursor(window, cursor); @@ -115,12 +115,12 @@ PalBool cursorTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index 4959e447..24cf9cd6 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -787,7 +787,7 @@ static void PAL_CALL onEvent( void* userData, const PalEvent* event) { - if (event->type == PAL_EVENT_MOUSE_BUTTONDOWN) { + if (event->type == PAL_EVENT_TYPE_MOUSE_BUTTONDOWN) { uint32_t button, serial; palUnpackUint32(event->data, &button, &serial); @@ -817,18 +817,18 @@ static void PAL_CALL onEvent( PalEvent event = {0}; event.data2 = palPackPointer(s_WinHandle.nativeWindow); - event.type = PAL_EVENT_WINDOW_CLOSE; + event.type = PAL_EVENT_TYPE_WINDOW_CLOSE; palPushEvent(s_Decoration.driver, &event); } } - } else if (event->type == PAL_EVENT_MOUSE_MOVE) { + } else if (event->type == PAL_EVENT_TYPE_MOUSE_MOVE) { int32_t x, y; palUnpackInt32(event->data, &x, &y); s_Decoration.mouseX = x; s_Decoration.mouseY = y; - } else if (event->type == PAL_EVENT_MONITOR_DPI_CHANGED) { + } else if (event->type == PAL_EVENT_TYPE_MONITOR_DPI_CHANGED) { palLog(nullptr, "Monitor DPI: %d", event->data); } } @@ -865,15 +865,15 @@ PalBool customDecorationTest() return PAL_FALSE; } - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_DECORATION_MODE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_DECORATION_MODE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); - // we use PAL_DISPATCH_CALLBACK for the mouse button to get + // we use PAL_DISPATCH_MODE_CALLBACK for the mouse button to get // real time events which we then use for moving and resizing - palSetEventDispatchMode(eventDriver, PAL_EVENT_MOUSE_BUTTONDOWN, PAL_DISPATCH_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_MOUSE_MOVE, PAL_DISPATCH_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_MONITOR_DPI_CHANGED, PAL_DISPATCH_CALLBACK); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_MOUSE_BUTTONDOWN, PAL_DISPATCH_MODE_CALLBACK); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_MOUSE_MOVE, PAL_DISPATCH_MODE_CALLBACK); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_MONITOR_DPI_CHANGED, PAL_DISPATCH_MODE_CALLBACK); // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must @@ -917,12 +917,12 @@ PalBool customDecorationTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -931,7 +931,7 @@ PalBool customDecorationTest() break; } - case PAL_EVENT_WINDOW_DECORATION_MODE: { + case PAL_EVENT_TYPE_WINDOW_DECORATION_MODE: { if (event.data == PAL_DECORATION_MODE_CLIENT_SIDE) { palLog(nullptr, "Window Decoration Mode: Client Side"); diff --git a/tests/video/icon_test.c b/tests/video/icon_test.c index 0379f4f2..8bca2285 100644 --- a/tests/video/icon_test.c +++ b/tests/video/icon_test.c @@ -92,8 +92,8 @@ PalBool iconTest() } // set the dispatch mode for window close event to recieve it - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // set the icon result = palSetWindowIcon(window, icon); @@ -110,12 +110,12 @@ PalBool iconTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { diff --git a/tests/video/input_window_test.c b/tests/video/input_window_test.c index 3693df68..93656f8f 100644 --- a/tests/video/input_window_test.c +++ b/tests/video/input_window_test.c @@ -4,7 +4,7 @@ #define DISPATCH_MODE_POLL 0 -static const char* s_KeyNames[PAL_KEYCODE_MAX] = { +static const char* s_KeyNames[PAL_KEYCODE_COUNT] = { [PAL_KEYCODE_UNKNOWN] = "Unknown", @@ -131,7 +131,7 @@ static const char* s_KeyNames[PAL_KEYCODE_MAX] = { [PAL_KEYCODE_RSUPER] = "RightSuper", }; -static const char* s_ScancodeNames[PAL_SCANCODE_MAX] = { +static const char* s_ScancodeNames[PAL_SCANCODE_COUNT] = { [PAL_SCANCODE_UNKNOWN] = "Unknown", @@ -256,7 +256,7 @@ static const char* s_ScancodeNames[PAL_SCANCODE_MAX] = { [PAL_SCANCODE_LSUPER] = "LeftSuper", [PAL_SCANCODE_RSUPER] = "RightSuper"}; -static const char* s_MouseButtonNames[PAL_MOUSE_BUTTON_MAX] = { +static const char* s_MouseButtonNames[PAL_MOUSE_BUTTON_COUNT] = { [PAL_MOUSE_BUTTON_UNKNOWN] = "Unknown", @@ -365,28 +365,28 @@ static void PAL_CALL onEvent( void* userData, const PalEvent* event) { - if (event->type == PAL_EVENT_KEYDOWN) { + if (event->type == PAL_EVENT_TYPE_KEYDOWN) { onKeydown(event); - } else if (event->type == PAL_EVENT_KEYREPEAT) { + } else if (event->type == PAL_EVENT_TYPE_KEYREPEAT) { onKeyrepeat(event); - } else if (event->type == PAL_EVENT_KEYUP) { + } else if (event->type == PAL_EVENT_TYPE_KEYUP) { onKeyup(event); - } else if (event->type == PAL_EVENT_MOUSE_BUTTONDOWN) { + } else if (event->type == PAL_EVENT_TYPE_MOUSE_BUTTONDOWN) { onMouseButtondown(event); - } else if (event->type == PAL_EVENT_MOUSE_BUTTONUP) { + } else if (event->type == PAL_EVENT_TYPE_MOUSE_BUTTONUP) { onMouseButtonup(event); - } else if (event->type == PAL_EVENT_MOUSE_MOVE) { + } else if (event->type == PAL_EVENT_TYPE_MOUSE_MOVE) { onMouseMove(event); - } else if (event->type == PAL_EVENT_MOUSE_DELTA) { + } else if (event->type == PAL_EVENT_TYPE_MOUSE_DELTA) { onMouseDelta(event); - } else if (event->type == PAL_EVENT_MOUSE_WHEEL) { + } else if (event->type == PAL_EVENT_TYPE_MOUSE_WHEEL) { onMouseWheel(event); } } @@ -445,17 +445,17 @@ PalBool inputWindowTest() } // we set window close to poll - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); - PalDispatchMode dispatchMode = PAL_DISPATCH_NONE; + PalDispatchMode dispatchMode = PAL_DISPATCH_MODE_NONE; #if DISPATCH_MODE_POLL - dispatchMode = PAL_DISPATCH_POLL; + dispatchMode = PAL_DISPATCH_MODE_POLL; #else - dispatchMode = PAL_DISPATCH_CALLBACK; + dispatchMode = PAL_DISPATCH_MODE_CALLBACK; #endif // DISPATCH_MODE_POLL // set dispatch mode for all events. - for (uint32_t e = PAL_EVENT_KEYDOWN; e < PAL_EVENT_USER; e++) { + for (uint32_t e = PAL_EVENT_TYPE_KEYDOWN; e < PAL_EVENT_TYPE_USER; e++) { palSetEventDispatchMode(eventDriver, e, dispatchMode); } @@ -467,47 +467,47 @@ PalBool inputWindowTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { s_Running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { onKeydown(&event); break; } - case PAL_EVENT_KEYREPEAT: { + case PAL_EVENT_TYPE_KEYREPEAT: { onKeyrepeat(&event); break; } - case PAL_EVENT_KEYUP: { + case PAL_EVENT_TYPE_KEYUP: { onKeyup(&event); break; } - case PAL_EVENT_MOUSE_BUTTONDOWN: { + case PAL_EVENT_TYPE_MOUSE_BUTTONDOWN: { onMouseButtondown(&event); break; } - case PAL_EVENT_MOUSE_BUTTONUP: { + case PAL_EVENT_TYPE_MOUSE_BUTTONUP: { onMouseButtonup(&event); break; } - case PAL_EVENT_MOUSE_MOVE: { + case PAL_EVENT_TYPE_MOUSE_MOVE: { onMouseMove(&event); break; } - case PAL_EVENT_MOUSE_DELTA: { + case PAL_EVENT_TYPE_MOUSE_DELTA: { onMouseDelta(&event); break; } - case PAL_EVENT_MOUSE_WHEEL: { + case PAL_EVENT_TYPE_MOUSE_WHEEL: { onMouseWheel(&event); break; } diff --git a/tests/video/native_instance_test.c b/tests/video/native_instance_test.c index c03f31a7..b6b55e9b 100644 --- a/tests/video/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -366,8 +366,8 @@ PalBool nativeInstanceTest() } // we set window close to poll - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); PalBool running = PAL_TRUE; while (running) { @@ -377,12 +377,12 @@ PalBool nativeInstanceTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { diff --git a/tests/video/native_integration_test.c b/tests/video/native_integration_test.c index d90cacc0..3ad31129 100644 --- a/tests/video/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -160,7 +160,7 @@ void setWindowTitleX11(PalWindowHandleInfo* windowInfo) "XFree"); // clang-format on - Display* display = (Display*)windowInfo->nativeDisplay; + Display* display = (Display*)windowInfo->nativeInstance; Window window = (Window)(uintptr_t)windowInfo->nativeWindow; s_NET_WM_NAME = s_XInternAtom(display, "_NET_WM_NAME", False); @@ -189,7 +189,7 @@ void setWindowTitleX11(PalWindowHandleInfo* windowInfo) void getWindowTitleX11(PalWindowHandleInfo* windowInfo) { #ifdef __linux__ - Display* display = (Display*)windowInfo->nativeDisplay; + Display* display = (Display*)windowInfo->nativeInstance; Window window = (Window)(uintptr_t)windowInfo->nativeWindow; if (s_NET_WM_NAME) { @@ -243,7 +243,7 @@ void setWindowTitleWayland(PalWindowHandleInfo* windowInfo) struct xdg_toplevel* toplevel = nullptr; struct wl_display* display = nullptr; - display = (struct wl_display*)windowInfo->nativeDisplay; + display = (struct wl_display*)windowInfo->nativeInstance; toplevel = (struct xdg_toplevel*)windowInfo->nativeHandle2; xdgToplevelSetTitle(toplevel, "Hello from native Wayland API"); @@ -364,8 +364,8 @@ PalBool nativeIntegrationTest() } // we set window close to poll - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // set the window title using native APIs PalWindowHandleInfo windowInfo = {0}; @@ -402,12 +402,12 @@ PalBool nativeIntegrationTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { diff --git a/tests/video/system_cursor_test.c b/tests/video/system_cursor_test.c index db611c36..afa883f1 100644 --- a/tests/video/system_cursor_test.c +++ b/tests/video/system_cursor_test.c @@ -41,7 +41,7 @@ PalBool systemCursorTest() // create system cursor PalCursor* cursor = nullptr; - result = palCreateCursorFrom(PAL_CURSOR_CROSS, &cursor); + result = palCreateCursorFrom(PAL_CURSOR_TYPE_CROSS, &cursor); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create window cursor"); return PAL_FALSE; @@ -72,8 +72,8 @@ PalBool systemCursorTest() } // set the dispatch mode for window close event to recieve it - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // set the cursor palSetWindowCursor(window, cursor); @@ -86,12 +86,12 @@ PalBool systemCursorTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { diff --git a/tests/video/window_test.c b/tests/video/window_test.c index d58fc07a..f25b0063 100644 --- a/tests/video/window_test.c +++ b/tests/video/window_test.c @@ -110,31 +110,31 @@ static void PAL_CALL onEvent( void* userData, const PalEvent* event) { - if (event->type == PAL_EVENT_WINDOW_SIZE) { + if (event->type == PAL_EVENT_TYPE_WINDOW_SIZE) { onWindowResize(event); - } else if (event->type == PAL_EVENT_WINDOW_MOVE) { + } else if (event->type == PAL_EVENT_TYPE_WINDOW_MOVE) { onWindowMove(event); - } else if (event->type == PAL_EVENT_WINDOW_VISIBILITY) { + } else if (event->type == PAL_EVENT_TYPE_WINDOW_VISIBILITY) { onWindowVisibility(event); - } else if (event->type == PAL_EVENT_WINDOW_FOCUS) { + } else if (event->type == PAL_EVENT_TYPE_WINDOW_FOCUS) { onWindowFocus(event); - } else if (event->type == PAL_EVENT_WINDOW_STATE) { + } else if (event->type == PAL_EVENT_TYPE_WINDOW_STATE) { onWindowState(event); - } else if (event->type == PAL_EVENT_WINDOW_MODAL_BEGIN) { + } else if (event->type == PAL_EVENT_TYPE_WINDOW_MODAL_BEGIN) { onWindowModalBegin(event); - } else if (event->type == PAL_EVENT_WINDOW_MODAL_END) { + } else if (event->type == PAL_EVENT_TYPE_WINDOW_MODAL_END) { onWindowModalEnd(event); - } else if (event->type == PAL_EVENT_MONITOR_DPI_CHANGED) { + } else if (event->type == PAL_EVENT_TYPE_MONITOR_DPI_CHANGED) { onMonitorDPI(event); - } else if (event->type == PAL_EVENT_MONITOR_LIST_CHANGED) { + } else if (event->type == PAL_EVENT_TYPE_MONITOR_LIST_CHANGED) { onMonitorList(event); } else { @@ -161,27 +161,27 @@ PalBool windowTest() return PAL_FALSE; } - PalDispatchMode dispatchMode = PAL_DISPATCH_NONE; + PalDispatchMode dispatchMode = PAL_DISPATCH_MODE_NONE; #if DISPATCH_MODE_POLL - dispatchMode = PAL_DISPATCH_POLL; + dispatchMode = PAL_DISPATCH_MODE_POLL; #else - dispatchMode = PAL_DISPATCH_CALLBACK; + dispatchMode = PAL_DISPATCH_MODE_CALLBACK; #endif // DISPATCH_MODE_POLL // set dispatch mode for all events. - for (uint32_t e = 0; e < PAL_EVENT_KEYDOWN; e++) { + for (uint32_t e = 0; e < PAL_EVENT_TYPE_KEYDOWN; e++) { palSetEventDispatchMode(eventDriver, e, dispatchMode); } // we set window close to poll - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // we set callback mode for modal begin and end. Since we want to capture // that instantly - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_MODAL_BEGIN, PAL_DISPATCH_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_MODAL_END, PAL_DISPATCH_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_DECORATION_MODE, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_MODAL_BEGIN, PAL_DISPATCH_MODE_CALLBACK); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_MODAL_END, PAL_DISPATCH_MODE_CALLBACK); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_DECORATION_MODE, PAL_DISPATCH_MODE_POLL); // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must @@ -271,47 +271,47 @@ PalBool windowTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_WINDOW_SIZE: { + case PAL_EVENT_TYPE_WINDOW_SIZE: { onWindowResize(&event); break; } - case PAL_EVENT_WINDOW_MOVE: { + case PAL_EVENT_TYPE_WINDOW_MOVE: { onWindowMove(&event); break; } - case PAL_EVENT_WINDOW_VISIBILITY: { + case PAL_EVENT_TYPE_WINDOW_VISIBILITY: { onWindowVisibility(&event); break; } - case PAL_EVENT_WINDOW_STATE: { + case PAL_EVENT_TYPE_WINDOW_STATE: { onWindowState(&event); break; } - case PAL_EVENT_WINDOW_FOCUS: { + case PAL_EVENT_TYPE_WINDOW_FOCUS: { onWindowFocus(&event); break; } - case PAL_EVENT_MONITOR_DPI_CHANGED: { + case PAL_EVENT_TYPE_MONITOR_DPI_CHANGED: { onMonitorDPI(&event); break; } - case PAL_EVENT_MONITOR_LIST_CHANGED: { + case PAL_EVENT_TYPE_MONITOR_LIST_CHANGED: { onMonitorList(&event); break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -320,7 +320,7 @@ PalBool windowTest() break; } - case PAL_EVENT_WINDOW_DECORATION_MODE: { + case PAL_EVENT_TYPE_WINDOW_DECORATION_MODE: { if (event.data == PAL_DECORATION_MODE_CLIENT_SIDE) { palLog(nullptr, "Window Decoration Mode: Client Side"); } else { diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index 7a3f1866..8ff2e795 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -132,11 +132,11 @@ static void monitorModeDump(PalBool verbose) static void flashDump(PalBool verbose) { - uint32_t xSize = 16; - uint32_t xAlign = 8; + uint32_t xSize = 12; + uint32_t xAlign = 4; uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 12; + uint32_t xOffset2 = 4; + uint32_t xOffset3 = 8; uint32_t xPadding = 0; uint32_t ySize = sizeof(PalFlashInfo); @@ -169,7 +169,7 @@ static void flashDump(PalBool verbose) palLog(nullptr, "padding %u %u", xPadding, yPadding); palLog(nullptr, "flags @ %u %u", xOffset1, yOffset1); palLog(nullptr, "interval @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "count @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "count @ %u %u", xOffset3, yOffset3); palLog(nullptr, "==========================================="); } @@ -336,36 +336,36 @@ static void windowInfoDump(PalBool verbose) static void windowDump(PalBool verbose) { - uint32_t xSize = 72; + uint32_t xSize = 64; uint32_t xAlign = 8; uint32_t xOffset1 = 0; uint32_t xOffset2 = 8; uint32_t xOffset3 = 16; uint32_t xOffset4 = 24; uint32_t xOffset5 = 32; - uint32_t xOffset6 = 40; - uint32_t xOffset7 = 44; - uint32_t xOffset8 = 48; - uint32_t xOffset9 = 52; - uint32_t xOffset10 = 56; - uint32_t xOffset11 = 60; - uint32_t xOffset12 = 64; - uint32_t xOffset13 = 68; + uint32_t xOffset6 = 36; + uint32_t xOffset7 = 40; + uint32_t xOffset8 = 44; + uint32_t xOffset9 = 48; + uint32_t xOffset10 = 52; + uint32_t xOffset11 = 56; + uint32_t xOffset12 = 60; uint32_t xPadding = 0; uint32_t ySize = sizeof(PalWindowCreateInfo); uint32_t yAlign = PAL_ALIGNOF(PalWindowCreateInfo); - uint32_t yOffset1 = offsetof(PalWindowCreateInfo, style); - uint32_t yOffset2 = offsetof(PalWindowCreateInfo, title); - uint32_t yOffset3 = offsetof(PalWindowCreateInfo, monitor); - uint32_t yOffset4 = offsetof(PalWindowCreateInfo, appName); - uint32_t yOffset5 = offsetof(PalWindowCreateInfo, instanceName); - uint32_t yOffset6 = offsetof(PalWindowCreateInfo, fbConfigBackend); - uint32_t yOffset7 = offsetof(PalWindowCreateInfo, fbConfigIndex); - uint32_t yOffset8 = offsetof(PalWindowCreateInfo, width); - uint32_t yOffset9 = offsetof(PalWindowCreateInfo, height); - uint32_t yOffset10 = offsetof(PalWindowCreateInfo, show); - uint32_t yOffset13 = offsetof(PalWindowCreateInfo, center); + uint32_t yOffset1 = offsetof(PalWindowCreateInfo, title); + uint32_t yOffset2 = offsetof(PalWindowCreateInfo, monitor); + uint32_t yOffset3 = offsetof(PalWindowCreateInfo, appName); + uint32_t yOffset4 = offsetof(PalWindowCreateInfo, instanceName); + uint32_t yOffset5 = offsetof(PalWindowCreateInfo, fbConfigBackend); + uint32_t yOffset6 = offsetof(PalWindowCreateInfo, fbConfigIndex); + uint32_t yOffset7 = offsetof(PalWindowCreateInfo, width); + uint32_t yOffset8 = offsetof(PalWindowCreateInfo, height); + uint32_t yOffset9 = offsetof(PalWindowCreateInfo, show); + uint32_t yOffset10 = offsetof(PalWindowCreateInfo, style); + uint32_t yOffset11 = offsetof(PalWindowCreateInfo, state); + uint32_t yOffset12 = offsetof(PalWindowCreateInfo, center); uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; const char* result = s_FailedString; @@ -382,7 +382,8 @@ static void windowDump(PalBool verbose) xOffset8 == yOffset8 && xOffset9 == yOffset9 && xOffset10 == yOffset10 && - xOffset13 == yOffset13 && + xOffset11 == yOffset11 && + xOffset12 == yOffset12 && xPadding == yPadding) { result = s_PassedString; } @@ -397,17 +398,18 @@ static void windowDump(PalBool verbose) palLog(nullptr, "size %u %u", xSize, ySize); palLog(nullptr, "align %u %u", xAlign, yAlign); palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "style @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "title @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "monitor @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "appName @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "instanceName @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "fbConfigBackend @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "fbConfigIndex @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "width @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "height @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "show @ %u %u", xOffset10, yOffset10); - palLog(nullptr, "center @ %u %u", xOffset13, yOffset13); + palLog(nullptr, "title @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "monitor @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "appName @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "instanceName @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "fbConfigBackend @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "fbConfigIndex @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "width @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "height @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "show @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "style @ %u %u", xOffset10, yOffset10); + palLog(nullptr, "state @ %u %u", xOffset11, yOffset11); + palLog(nullptr, "center @ %u %u", xOffset12, yOffset12); palLog(nullptr, "==========================================="); } From 10d4d4b5b270b7c9ef13d3b9e9fdbb58c02e207e Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 29 Jun 2026 16:44:45 +0000 Subject: [PATCH 305/372] update opengl system and tests --- pal.lua | 10 +- pal_config.lua | 4 +- src/core/posix/pal_log_posix.c | 6 +- src/core/posix/pal_memory_posix.c | 6 +- src/core/posix/pal_result_posix.c | 6 +- src/core/posix/pal_time_posix.c | 6 +- src/opengl/egl/pal_context_egl.c | 356 ++++++++++ src/opengl/egl/pal_egl.c | 493 +++++++++++++ .../pal_opengl_linux.h => egl/pal_egl.h} | 60 +- src/opengl/linux/pal_context_linux.c | 420 ------------ src/opengl/linux/pal_opengl_linux.c | 649 ------------------ src/opengl/pal_opengl.c | 255 +++++++ src/opengl/pal_opengl_backends.h | 91 +++ src/opengl/pal_opengl_shared.c | 94 --- src/{pal_posix.h => pal_platform.h} | 20 +- src/thread/posix/pal_condvar_posix.c | 6 +- src/thread/posix/pal_mutex_posix.c | 6 +- src/thread/posix/pal_thread_posix.c | 6 +- src/thread/posix/pal_thread_posix.h | 6 +- src/thread/posix/pal_tls_posix.c | 6 +- src/video/pal_video.c | 4 +- src/video/pal_video_backends.h | 14 +- src/video/pal_video_egl.h | 22 +- src/video/wayland/pal_video_wayland.c | 26 +- src/video/wayland/pal_window_wayland.c | 8 +- src/video/x11/pal_video_x11.c | 28 +- src/video/x11/pal_window_x11.c | 8 +- tests/opengl/multi_thread_opengl_test.c | 36 +- tests/opengl/opengl_context_test.c | 14 +- tests/opengl/opengl_multi_context_test.c | 18 +- tests/tests_main.c | 4 +- tests/video/custom_decoration_test.c | 6 +- 32 files changed, 1370 insertions(+), 1324 deletions(-) create mode 100644 src/opengl/egl/pal_context_egl.c create mode 100644 src/opengl/egl/pal_egl.c rename src/opengl/{linux/pal_opengl_linux.h => egl/pal_egl.h} (81%) delete mode 100644 src/opengl/linux/pal_context_linux.c delete mode 100644 src/opengl/linux/pal_opengl_linux.c create mode 100644 src/opengl/pal_opengl.c create mode 100644 src/opengl/pal_opengl_backends.h delete mode 100644 src/opengl/pal_opengl_shared.c rename src/{pal_posix.h => pal_platform.h} (53%) diff --git a/pal.lua b/pal.lua index 04cc19d3..09099fe7 100644 --- a/pal.lua +++ b/pal.lua @@ -84,6 +84,8 @@ project "PAL" end if (PAL_BUILD_VIDEO_MODULE) then + files { "src/video/pal_video.c" } + if (os.target() == "linux") then -- check for wayland support. This is cross compiler local waylandPaths = { @@ -141,8 +143,6 @@ project "PAL" filter {"system:linux", "configurations:*"} files { - "src/video/pal_video.c", - -- X11 "src/video/x11/pal_cursor_x11.c", "src/video/x11/pal_icon_x11.c", @@ -163,7 +163,7 @@ project "PAL" end if (PAL_BUILD_OPENGL_MODULE) then - files { "src/opengl/pal_opengl_shared.c" } + files { "src/opengl/pal_opengl.c" } filter {"system:windows", "configurations:*"} files { @@ -173,8 +173,8 @@ project "PAL" filter {"system:linux", "configurations:*"} files { - "src/opengl/linux/pal_context_linux.c", - "src/opengl/linux/pal_opengl_linux.c" + "src/opengl/egl/pal_context_egl.c", + "src/opengl/egl/pal_egl.c" } filter {} diff --git a/pal_config.lua b/pal_config.lua index 07bf5d26..9ecc849e 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -12,13 +12,13 @@ PAL_BUILD_ABI_DUMP = true PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD_MODULE = false +PAL_BUILD_THREAD_MODULE = true -- build video module PAL_BUILD_VIDEO_MODULE = true -- build opengl module -PAL_BUILD_OPENGL_MODULE = false +PAL_BUILD_OPENGL_MODULE = true -- build graphics module PAL_BUILD_GRAPHICS_MODULE = false diff --git a/src/core/posix/pal_log_posix.c b/src/core/posix/pal_log_posix.c index 4035e1e4..44ed0cd3 100644 --- a/src/core/posix/pal_log_posix.c +++ b/src/core/posix/pal_log_posix.c @@ -5,9 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal_posix.h" +#include "pal_platform.h" -#if _PAL_ON_POSIX +#if _PAL_HAS_POSIX #include "core/pal_format.h" #include #include @@ -88,4 +88,4 @@ void PAL_CALL palLog( pthread_setspecific(s_TLSID, data); } -#endif // _PAL_ON_POSIX \ No newline at end of file +#endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/core/posix/pal_memory_posix.c b/src/core/posix/pal_memory_posix.c index 41435689..b72f3a85 100644 --- a/src/core/posix/pal_memory_posix.c +++ b/src/core/posix/pal_memory_posix.c @@ -5,9 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal_posix.h" +#include "pal_platform.h" -#if _PAL_ON_POSIX +#if _PAL_HAS_POSIX #define _POSIX_C_SOURCE 200112L #include "pal/pal_core.h" #include @@ -47,4 +47,4 @@ void PAL_CALL palFree( } } -#endif // _PAL_ON_POSIX \ No newline at end of file +#endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/core/posix/pal_result_posix.c b/src/core/posix/pal_result_posix.c index ecae1010..ae23c474 100644 --- a/src/core/posix/pal_result_posix.c +++ b/src/core/posix/pal_result_posix.c @@ -5,9 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal_posix.h" +#include "pal_platform.h" -#if _PAL_ON_POSIX +#if _PAL_HAS_POSIX #define _POSIX_C_SOURCE 200112L #include "core/pal_format.h" #include "core/pal_result.h" @@ -29,4 +29,4 @@ void PAL_CALL palFormatResult( } } -#endif // _PAL_ON_POSIX \ No newline at end of file +#endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/core/posix/pal_time_posix.c b/src/core/posix/pal_time_posix.c index 3013b572..4e8f7923 100644 --- a/src/core/posix/pal_time_posix.c +++ b/src/core/posix/pal_time_posix.c @@ -5,9 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal_posix.h" +#include "pal_platform.h" -#if _PAL_ON_POSIX +#if _PAL_HAS_POSIX #define _POSIX_C_SOURCE 200112L #include "pal/pal_core.h" #include @@ -24,4 +24,4 @@ uint64_t PAL_CALL palGetPerformanceFrequency() return 1000000000LL; } -#endif // _PAL_ON_POSIX \ No newline at end of file +#endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/opengl/egl/pal_context_egl.c b/src/opengl/egl/pal_context_egl.c new file mode 100644 index 00000000..242d3198 --- /dev/null +++ b/src/opengl/egl/pal_context_egl.c @@ -0,0 +1,356 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal_platform.h" + +#if _PAL_HAS_EGL +#include "pal_egl.h" + +static ContextData* getFreeContextData() +{ + for (int i = 0; i < s_Egl.maxContextData; ++i) { + if (!s_Egl.contextData[i].used) { + s_Egl.contextData[i].used = PAL_TRUE; + return &s_Egl.contextData[i]; + } + } + + // resize the data array + // this will almost not reach here since most setups are 1-4 monitors + ContextData* data = nullptr; + int count = s_Egl.maxContextData * 2; // double the size + int freeIndex = s_Egl.maxContextData + 1; + data = palAllocate(s_Egl.allocator, sizeof(ContextData) * count, 0); + if (data) { + memcpy(data, s_Egl.contextData, s_Egl.maxContextData * sizeof(ContextData)); + + palFree(s_Egl.allocator, s_Egl.contextData); + s_Egl.contextData = data; + s_Egl.maxContextData = count; + + s_Egl.contextData[freeIndex].used = PAL_TRUE; + return &s_Egl.contextData[freeIndex]; + } + return nullptr; +} + +static ContextData* findContextData(PalGLContext* context) +{ + for (int i = 0; i < s_Egl.maxContextData; ++i) { + if (s_Egl.contextData[i].used && s_Egl.contextData[i].context == context) { + return &s_Egl.contextData[i]; + } + } +} + +static void freeContextData(PalGLContext* context) +{ + for (int i = 0; i < s_Egl.maxContextData; ++i) { + if (s_Egl.contextData[i].used && s_Egl.contextData[i].context == context) { + s_Egl.contextData[i].used = PAL_FALSE; + } + } +} + +PalResult eglCreateGLContext( + const PalGLContextCreateInfo* info, + PalGLContext** outContext) +{ + if (!info || !outContext) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (!info->window || !info->fbConfig) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + // check if the window was created with the same instance + // the opengl system is using + if (info->window->instance != s_Egl.instance) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + // check support for requested features + if (info->profile != PAL_GL_PROFILE_NONE) { + if (!(s_Egl.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + if (info->forward) { + if (!(s_Egl.info.extensions & PAL_GL_EXTENSION_CREATE_CONTEXT)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { + if (!(s_Egl.info.extensions & PAL_GL_EXTENSION_ROBUSTNESS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + if (info->noError) { + if (!(s_Egl.info.extensions & PAL_GL_EXTENSION_NO_ERROR)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { + if (!(s_Egl.info.extensions & PAL_GL_EXTENSION_FLUSH_CONTROL)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + // check version + // clang-format off + PalBool valid = info->major < s_Egl.info.major || + (info->major == s_Egl.info.major && info->minor <= s_Egl.info.minor); + // clang-format on + + if (!valid) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + ContextData* data = getFreeContextData(); + if (!data) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + // we need to get the EGL config from the user supplied index + EGLint numConfigs = 0; + if (!s_Egl.getConfigs(s_Egl.display, nullptr, 0, &numConfigs)) { + return palMakeResult( + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_EGL, + s_Egl.getError()); + } + + EGLint configSize = sizeof(EGLConfig) * numConfigs; + EGLConfig* eglConfigs = palAllocate(s_Egl.allocator, configSize, 0); + if (!eglConfigs) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + s_Egl.getConfigs(s_Egl.display, eglConfigs, numConfigs, &numConfigs); + EGLConfig config = eglConfigs[info->fbConfig->index]; + EGLContext* share = nullptr; + if (info->shareContext) { + share = (EGLContext)info->shareContext; + } else { + share = EGL_NO_CONTEXT; + } + + int32_t attribs[40]; + int32_t index = 0; + int32_t profile = 0; + int32_t flags = 0; + + // set context attributes + // the first element is the key and the second is the value + if (s_Egl.apiType == EGL_OPENGL_API) { + // set version + attribs[index++] = EGL_CONTEXT_MAJOR_VERSION_KHR; // key + attribs[index++] = info->major; // value + + attribs[index++] = EGL_CONTEXT_MINOR_VERSION_KHR; + attribs[index++] = info->minor; + + // set profile mask + if (info->profile != PAL_GL_PROFILE_NONE) { + attribs[index++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; + + if (info->profile == PAL_GL_PROFILE_COMPATIBILITY) { + profile = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; + } else if (info->profile == PAL_GL_PROFILE_CORE) { + profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; + } + + attribs[index++] = info->profile; + } + + // set forward flag + if (info->forward) { + flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; + } + + } else { + attribs[index++] = EGL_CONTEXT_CLIENT_VERSION; + // our configs support EGL_OPENGL_ES2_BIT and EGL_OPENGL_ES3_BIT + attribs[index++] = info->major; + } + + // set debug flag + if (info->debug) { + flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; + } + + // set robustness + if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { + flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; + attribs[index++] = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR; + + if (info->reset == PAL_GL_CONTEXT_RESET_LOSE_CONTEXT) { + attribs[index++] = EGL_LOSE_CONTEXT_ON_RESET_KHR; + + } else if (info->reset == PAL_GL_CONTEXT_RESET_NO_NOTIFICATION) { + attribs[index++] = EGL_NO_RESET_NOTIFICATION_KHR; + } + } + + // set no error + if (info->noError) { + attribs[index++] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR; + attribs[index++] = PAL_TRUE; + } + + // release + if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { + attribs[index++] = EGL_CONTEXT_RELEASE_BEHAVIOR_KHR; + attribs[index++] = EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR; + } + + if (flags) { + attribs[index++] = EGL_CONTEXT_FLAGS_KHR; + attribs[index++] = flags; + } + attribs[index++] = EGL_NONE; + + // create context + EGLContext context = s_Egl.createContext(s_Egl.display, config, share, attribs); + if (context == EGL_NO_CONTEXT) { + EGLint error = s_Egl.getError(); + if (error == EGL_BAD_CONFIG || error == EGL_BAD_ATTRIBUTE) { + return palMakeResult(PAL_RESULT_CODE_INVALID_ARGUMENT, PAL_RESULT_SOURCE_EGL, error); + + } else { + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + } + + // create a window surface + // The only attrib we want is colorspace + EGLint surfaceAttribs[3]; + surfaceAttribs[0] = EGL_GL_COLORSPACE; + if (info->fbConfig->sRGB) { + surfaceAttribs[1] = EGL_GL_COLORSPACE_SRGB_KHR; + } else { + surfaceAttribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; + } + surfaceAttribs[2] = EGL_NONE; + + EGLSurface surface = s_Egl.createWindowSurface( + s_Egl.display, + config, + (EGLNativeWindowType)info->window->window, + surfaceAttribs); + + if (surface == EGL_NO_SURFACE) { + EGLint error = s_Egl.getError(); + if (error == EGL_BAD_CONFIG) { + return palMakeResult(PAL_RESULT_CODE_INVALID_ARGUMENT, PAL_RESULT_SOURCE_EGL, error); + + } else { + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + } + + // make the context current and swap for the first time + // this will make the window visible + if (s_Egl.makeCurrent(s_Egl.display, surface, surface, context)) { + s_Egl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + s_Egl.glClear(0x00004000); + s_Egl.swapBuffers(s_Egl.display, surface); + + // revert + s_Egl.makeCurrent(s_Egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + + palFree(s_Egl.allocator, eglConfigs); + data->context = (PalGLContext*)context; + data->surface = surface; + + *outContext = (PalGLContext*)context; + return PAL_RESULT_SUCCESS; +} + +void eglDestroyGLContext(PalGLContext* context) +{ + if (context) { + ContextData* data = findContextData(context); + if (data) { + // make it not current if it was current + s_Egl.makeCurrent(s_Egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + s_Egl.destroyContext(s_Egl.display, (EGLContext)context); + s_Egl.destroySurface(s_Egl.display, data->surface); + data->used = PAL_FALSE; + } + } +} + +PalResult eglMakeContextCurrent( + PalGLWindow* glWindow, + PalGLContext* context) +{ + if ((!glWindow && context) || (glWindow && !context)) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (context && glWindow) { + ContextData* data = findContextData(context); + if (!data) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + EGLint ret; + ret = s_Egl.makeCurrent(s_Egl.display, data->surface, data->surface, (EGLConfig)context); + if (!ret) { + EGLint error = s_Egl.getError(); + if (error == EGL_BAD_CONTEXT || error == EGL_BAD_SURFACE) { + return palMakeResult(PAL_RESULT_CODE_INVALID_HANDLE, PAL_RESULT_SOURCE_EGL, error); + + } else { + return palMakeResult( + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_EGL, + error); + } + } + + } else if (!context && !glWindow) { + s_Egl.makeCurrent(s_Egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult eglSwapBuffers( + PalGLWindow* glWindow, + PalGLContext* context) +{ + if (!context || !glWindow) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + ContextData* data = findContextData(context); + if (!data) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + if (!s_Egl.swapBuffers(s_Egl.display, data->surface)) { + EGLint error = s_Egl.getError(); + if (error == EGL_BAD_CONTEXT || error == EGL_BAD_SURFACE) { + return palMakeResult(PAL_RESULT_CODE_INVALID_HANDLE, PAL_RESULT_SOURCE_EGL, error); + + } else { + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + } + + return PAL_RESULT_SUCCESS; +} + +#endif // _PAL_HAS_EGL \ No newline at end of file diff --git a/src/opengl/egl/pal_egl.c b/src/opengl/egl/pal_egl.c new file mode 100644 index 00000000..b3eed2c7 --- /dev/null +++ b/src/opengl/egl/pal_egl.c @@ -0,0 +1,493 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal_platform.h" + +#if _PAL_HAS_EGL +#include "pal_egl.h" +#include "opengl/pal_opengl_shared.h" +#include +#include +#include + +EGL s_Egl = {0}; +static PalBool s_SupportedAPIs[2] = {0}; + +PalResult PAL_CALL eglInitGL( + PalGLAPI api, + void* instance, + const PalAllocator* allocator) +{ + s_Egl.maxContextData = 16; // initial size + s_Egl.contextData = palAllocate( + s_Egl.allocator, + sizeof(ContextData) * s_Egl.maxContextData, + 0); + + if (!s_Egl.maxContextData) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + s_Egl.handle = dlopen("libEGL.so", RTLD_LAZY); + if (!s_Egl.handle) { + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); + } + + // clang-format off + s_Egl.getProcAddress = (eglGetProcAddressFn)dlsym( + s_Egl.handle, + "eglGetProcAddress"); + + s_Egl.createPbufferSurface = (eglCreatePbufferSurfaceFn)s_Egl.getProcAddress( + "eglCreatePbufferSurface"); + + s_Egl.createWindowSurface = (eglCreateWindowSurfaceFn)s_Egl.getProcAddress( + "eglCreateWindowSurface"); + + s_Egl.createContext = (eglCreateContextFn)s_Egl.getProcAddress("eglCreateContext"); + s_Egl.destroyContext = (eglDestroyContextFn)s_Egl.getProcAddress("eglDestroyContext"); + s_Egl.destroySurface = (eglDestroySurfaceFn)s_Egl.getProcAddress("eglDestroySurface"); + s_Egl.makeCurrent = (eglMakeCurrentFn)s_Egl.getProcAddress("eglMakeCurrent"); + s_Egl.swapBuffers = (eglSwapBuffersFn)s_Egl.getProcAddress("eglSwapBuffers"); + s_Egl.swapInterval = (eglSwapIntervalFn)s_Egl.getProcAddress("eglSwapInterval"); + s_Egl.initialize = (eglInitializeFn)s_Egl.getProcAddress("eglInitialize"); + s_Egl.terminate = (eglTerminateFn)s_Egl.getProcAddress("eglTerminate"); + s_Egl.getDisplay = (eglGetDisplayFn)s_Egl.getProcAddress("eglGetDisplay"); + s_Egl.chooseConfig = (eglChooseConfigFn)s_Egl.getProcAddress("eglChooseConfig"); + + s_Egl.getConfigAttrib = (eglGetConfigAttribFn)s_Egl.getProcAddress("eglGetConfigAttrib"); + s_Egl.getError = (eglGetErrorFn)s_Egl.getProcAddress("eglGetError"); + s_Egl.bindAPI = (eglBindAPIFn)s_Egl.getProcAddress("eglBindAPI"); + s_Egl.queryString = (eglQueryStringFn)s_Egl.getProcAddress("eglQueryString"); + s_Egl.getConfigs = (eglGetConfigsFn)s_Egl.getProcAddress("eglGetConfigs"); + s_Egl.glClearColor = (glClearColorFn)s_Egl.getProcAddress("glClearColor"); + s_Egl.glClear = (glClearFn)s_Egl.getProcAddress("glClear"); + + if (!s_Egl.bindAPI || + !s_Egl.chooseConfig || + !s_Egl.createContext || + !s_Egl.createPbufferSurface || + !s_Egl.destroyContext || + !s_Egl.destroySurface || + !s_Egl.getConfigAttrib || + !s_Egl.getDisplay || + !s_Egl.getError || + !s_Egl.getProcAddress || + !s_Egl.initialize || + !s_Egl.makeCurrent || + !s_Egl.swapBuffers || + !s_Egl.swapInterval || + !s_Egl.terminate || + !s_Egl.queryString || + !s_Egl.getConfigs || + !s_Egl.createWindowSurface) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + // clang-format on + + // get api type + if (api == PAL_GL_API_OPENGL) { + s_Egl.apiType = EGL_OPENGL_API; + s_Egl.apiTypeBit = EGL_OPENGL_BIT; + + } else { + s_Egl.apiType = EGL_OPENGL_ES_API; + s_Egl.apiTypeBit = EGL_OPENGL_ES2_BIT; // default + } + + EGLint error = 0; + if (!s_Egl.bindAPI(s_Egl.apiType)) { + error = s_Egl.getError(); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + + EGLDisplay display = s_Egl.getDisplay(instance); + EGLDisplay* tmpDisplay = EGL_NO_DISPLAY; + if (display == EGL_NO_DISPLAY) { + error = s_Egl.getError(); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + + if (!s_Egl.initialize(display, nullptr, nullptr)) { + error = s_Egl.getError(); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + + // use a simple FBConfig + EGLConfig config; + int numConfigs; + EGLint type; + + // clang-format off + EGLint attribs[] = { + EGL_RENDERABLE_TYPE, + s_Egl.apiTypeBit, + EGL_SURFACE_TYPE, + EGL_PBUFFER_BIT, + EGL_NONE + }; + // clang-format on + + s_Egl.chooseConfig(display, attribs, &config, 1, &numConfigs); + if (!config || numConfigs == 0) { + // API bind type might not support puffer + // create a default display and use that + tmpDisplay = s_Egl.getDisplay(EGL_DEFAULT_DISPLAY); + if (display == EGL_NO_DISPLAY) { + error = s_Egl.getError(); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + + if (!s_Egl.initialize(tmpDisplay, nullptr, nullptr)) { + error = s_Egl.getError(); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + } else { + // set the tmp display to our display + tmpDisplay = display; + } + + s_Egl.chooseConfig(tmpDisplay, attribs, &config, 1, &numConfigs); + if (!config) { + error = s_Egl.getError(); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + + s_Egl.getConfigAttrib(tmpDisplay, config, EGL_RENDERABLE_TYPE, &type); + if (!(type & s_Egl.apiTypeBit)) { + // we must support the required API + error = s_Egl.getError(); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + + EGLSurface surface = EGL_NO_SURFACE; + EGLint pBufferAttribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; + surface = s_Egl.createPbufferSurface(tmpDisplay, config, pBufferAttribs); + if (surface == EGL_NO_SURFACE) { + error = s_Egl.getError(); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + + // create a dummy context + EGLContext context = EGL_NO_CONTEXT; + if (s_Egl.apiType == EGL_OPENGL_API) { + // clang-format off + EGLint contextAttrib[] = { + EGL_CONTEXT_MAJOR_VERSION, + 2, + EGL_CONTEXT_MINOR_VERSION, + 1, + EGL_NONE + }; + // clang-format on + context = s_Egl.createContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); + + } else { + EGLint contextAttrib[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + context = s_Egl.createContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); + } + + if (context == EGL_NO_CONTEXT) { + error = s_Egl.getError(); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + + s_Egl.makeCurrent(tmpDisplay, surface, surface, context); + s_Egl.glGetString = (glGetStringFn)s_Egl.getProcAddress("glGetString"); + const char* version = (const char*)s_Egl.glGetString(GL_VERSION); + if (version) { + if (s_Egl.apiType == EGL_OPENGL_API) { + sscanf(version, "%d.%d", &s_Egl.info.major, &s_Egl.info.minor); + } else { + sscanf(version + 10, "%d.%d", &s_Egl.info.major, &s_Egl.info.minor); + } + } + + const char* renderer = (const char*)s_Egl.glGetString(GL_RENDERER); + const char* vendor = (const char*)s_Egl.glGetString(GL_VENDOR); + strcpy(s_Egl.info.vendor, vendor); + strcpy(s_Egl.info.version, version); + strcpy(s_Egl.info.graphicsCard, renderer); + + // EGL extensions can be queried without a bound context + // we just do that over here after making the context current + const char* extensions = s_Egl.queryString(tmpDisplay, EGL_EXTENSIONS); + if (extensions) { + // color space + if (checkString("EGL_KHR_gl_colorspace", extensions)) { + s_Egl.info.extensions |= PAL_GL_EXTENSION_COLORSPACE_SRGB; + } + + // create context + if (checkString("EGL_KHR_create_context", extensions)) { + s_Egl.info.extensions |= PAL_GL_EXTENSION_CREATE_CONTEXT; + s_Egl.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE; + } + + // robustness + if (checkString("EGL_EXT_create_context_robustness", extensions)) { + s_Egl.info.extensions |= PAL_GL_EXTENSION_ROBUSTNESS; + } + + // no error + if (checkString("EGL_KHR_create_context_no_error", extensions)) { + s_Egl.info.extensions |= PAL_GL_EXTENSION_NO_ERROR; + } + + // flush control + if (checkString("EGL_KHR_context_flush_control", extensions)) { + s_Egl.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; + } + + // swap control + if (checkString("EGL_EXT_swap_control", extensions)) { + s_Egl.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; + } + + if (checkString("EGL_EXT_swap_control_tear", extensions)) { + s_Egl.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; + } + } + + // part of the core API + s_Egl.info.extensions |= PAL_GL_EXTENSION_MULTISAMPLE; + if (type & EGL_OPENGL_ES_BIT || type & EGL_OPENGL_ES2_BIT) { + s_Egl.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; + } + + // check if we support the core swap interval + if (s_Egl.swapInterval) { + s_Egl.info.extensions |= PAL_GL_EXTENSION_SWAP_CONTROL; + } + + if (s_Egl.apiType != EGL_OPENGL_API) { + if (s_Egl.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE) { + s_Egl.info.extensions &= ~PAL_GL_EXTENSION_CONTEXT_PROFILE; + s_Egl.info.extensions &= ~PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; + } + + if (type & EGL_OPENGL_ES3_BIT) { + s_Egl.apiTypeBit = EGL_OPENGL_ES3_BIT; + } + } + + s_Egl.makeCurrent(tmpDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + s_Egl.destroyContext(tmpDisplay, context); + s_Egl.destroySurface(tmpDisplay, surface); + + s_Egl.info.api = api; + s_Egl.info.backend = PAL_GL_BACKEND_EGL; + s_Egl.allocator = allocator; + + if (tmpDisplay != display) { + // tmpDisplay is a seperate display + // terminate it + s_Egl.terminate(tmpDisplay); + } + + s_Egl.display = display; + s_Egl.instance = instance; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL eglShutdownGL() +{ + palFree(s_Egl.allocator, s_Egl.contextData); + if (s_Egl.display) { + s_Egl.terminate(s_Egl.display); + } + dlclose(s_Egl.handle); +} + +const PalGLInfo* PAL_CALL eglGetGLInfo() +{ + return &s_Egl.info; +} + +PalResult PAL_CALL eglEnumerateGLFBConfigs( + int32_t* count, + PalGLFBConfig* configs) +{ + if (!count || count == 0 && configs) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + int32_t configCount = 0; + int32_t maxConfigCount = 0; + if (configs) { + maxConfigCount = *count; + } + + // get the number of configs and filter the ones for opengl desktop + EGLint numConfigs = 0; + EGLint error = 0; + if (!s_Egl.getConfigs(s_Egl.display, nullptr, 0, &numConfigs)) { + error = s_Egl.getError(); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, error); + } + + EGLint configSize = sizeof(EGLConfig) * numConfigs; + EGLConfig* eglConfigs = palAllocate(s_Egl.allocator, configSize, 0); + if (!eglConfigs) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + s_Egl.getConfigs(s_Egl.display, eglConfigs, numConfigs, &numConfigs); + for (int i = 0; i < numConfigs; i++) { + // attributes we care about + EGLint surfaceType = 0, renderable = 0; + EGLint colorType = 0; + + EGLConfig config = eglConfigs[i]; + s_Egl.getConfigAttrib(s_Egl.display, config, EGL_SURFACE_TYPE, &surfaceType); + s_Egl.getConfigAttrib(s_Egl.display, config, EGL_RENDERABLE_TYPE, &renderable); + s_Egl.getConfigAttrib(s_Egl.display, config, EGL_COLOR_BUFFER_TYPE, &colorType); + + // we need only opengl API configs + if (colorType != EGL_RGB_BUFFER) { + continue; + } + + if (s_Egl.apiType == EGL_OPENGL_ES3_BIT) { + // EGL_OPENGL_ES2_BIT + if (!(renderable & EGL_OPENGL_ES2_BIT) && !(renderable & EGL_OPENGL_ES3_BIT)) { + continue; + } + + } else if (s_Egl.apiType == EGL_OPENGL_ES2_BIT) { + if (!(renderable & EGL_OPENGL_ES2_BIT)) { + continue; + } + + } else { + if (!(renderable & EGL_OPENGL_BIT)) { + continue; + } + } + + if (!(surfaceType & EGL_WINDOW_BIT)) { + continue; + } + + if (configs && configCount < maxConfigCount) { + // get this only if user supplied an output buffer (PalGLFBConfig*) + PalGLFBConfig* fbConfig = &configs[configCount]; + fbConfig->index = i; + + EGLint redBits, greenBits, blueBits, alphaBits; + EGLint depthBits, stencilBits, samples; + + s_Egl.getConfigAttrib(s_Egl.display, config, EGL_RED_SIZE, &redBits); + s_Egl.getConfigAttrib(s_Egl.display, config, EGL_GREEN_SIZE, &greenBits); + s_Egl.getConfigAttrib(s_Egl.display, config, EGL_BLUE_SIZE, &blueBits); + s_Egl.getConfigAttrib(s_Egl.display, config, EGL_ALPHA_SIZE, &alphaBits); + s_Egl.getConfigAttrib(s_Egl.display, config, EGL_DEPTH_SIZE, &depthBits); + s_Egl.getConfigAttrib(s_Egl.display, config, EGL_STENCIL_SIZE, &stencilBits); + s_Egl.getConfigAttrib(s_Egl.display, config, EGL_SAMPLES, &samples); + if (samples == 0) { + samples = 1; + } + + fbConfig->redBits = redBits; + fbConfig->greenBits = greenBits; + fbConfig->blueBits = blueBits; + fbConfig->alphaBits = alphaBits; + fbConfig->depthBits = depthBits; + fbConfig->stencilBits = stencilBits; + fbConfig->samples = samples; + + // True for EGL_WINDOW_BIT + fbConfig->doubleBuffer = PAL_TRUE; + fbConfig->stereo = PAL_FALSE; + + fbConfig->sRGB = PAL_FALSE; + if (s_Egl.info.extensions & PAL_GL_EXTENSION_COLORSPACE_SRGB) { + // since EGL does not have a bit to check SRGB support + // we check if all the color bits are greater than or equal to 8 + if (fbConfig->redBits >= 8 && fbConfig->greenBits >= 8 && fbConfig->blueBits >= 8) { + fbConfig->sRGB = PAL_TRUE; + } + } + } + configCount++; + } + + palFree(s_Egl.allocator, eglConfigs); + if (!configs) { + *count = configCount; + } + + return PAL_RESULT_SUCCESS; +} + +void* PAL_CALL eglGetGLProcAddress(const char* name) +{ + return s_Egl.getProcAddress(name); +} + +PalResult PAL_CALL eglSetSwapInterval(int32_t interval) +{ + if (!s_Egl.swapInterval) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + s_Egl.swapInterval(s_Egl.display, interval); + return PAL_RESULT_SUCCESS; +} + +const PalBool* PAL_CALL eglGetSupportedGLAPIs(void* instance) +{ + if (!instance) { + return nullptr; + } + + void* handle = dlopen("libEGL.so", RTLD_LAZY); + if (!handle) { + return nullptr; + } + + // clang-format off + eglGetProcAddressFn getProcAddress = (eglGetProcAddressFn)dlsym(handle, "eglGetProcAddress"); + eglInitializeFn initialize = (eglInitializeFn)getProcAddress("eglInitialize"); + eglTerminateFn terminate = (eglTerminateFn)getProcAddress("eglTerminate"); + eglGetDisplayFn getDisplay = (eglGetDisplayFn)getProcAddress("eglGetDisplay"); + eglQueryStringFn queryString = (eglQueryStringFn)getProcAddress("eglQueryString"); + if (!getProcAddress || !initialize || !terminate || !getDisplay || !queryString) { + return nullptr; + } + // clang-format on + + EGLDisplay display = getDisplay(instance); + if (display == EGL_NO_DISPLAY) { + return nullptr; + } + + if (!initialize(display, nullptr, nullptr)) { + return nullptr; + } + + const char* apis = queryString(display, EGL_CLIENT_APIS); + if (apis) { + if (checkString("OpenGL", apis)) { + s_SupportedAPIs[PAL_GL_API_OPENGL] = PAL_TRUE; + } else { + s_SupportedAPIs[PAL_GL_API_OPENGL] = PAL_FALSE; + } + + if (checkString("OpenGL_ES", apis)) { + s_SupportedAPIs[PAL_GL_API_OPENGL_ES] = PAL_TRUE; + } else { + s_SupportedAPIs[PAL_GL_API_OPENGL_ES] = PAL_FALSE; + } + } + + terminate(display); + dlclose(handle); + return s_SupportedAPIs; +} + +#endif // _PAL_HAS_EGL \ No newline at end of file diff --git a/src/opengl/linux/pal_opengl_linux.h b/src/opengl/egl/pal_egl.h similarity index 81% rename from src/opengl/linux/pal_opengl_linux.h rename to src/opengl/egl/pal_egl.h index 2a5d3c6f..101791e0 100644 --- a/src/opengl/linux/pal_opengl_linux.h +++ b/src/opengl/egl/pal_egl.h @@ -5,12 +5,10 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifndef _PAL_OPENGL_LINUX_H -#define _PAL_OPENGL_LINUX_H -#ifdef __linux__ - #include "pal/pal_opengl.h" -#include + +#ifndef _PAL_EGL_H +#define _PAL_EGL_H #ifndef GL_VENDOR #define GL_VENDOR 0x1F00 @@ -180,9 +178,9 @@ typedef EGLSurface (*eglCreateWindowSurfaceFn)( const EGLint*); typedef const GLubyte* (*glGetStringFn)(GLenum); -typedef void(PAL_GL_APIENTRY* glClearFn)(uint32_t); +typedef void(*glClearFn)(uint32_t); -typedef void(PAL_GL_APIENTRY* glClearColorFn)( +typedef void(*glClearColorFn)( float, float, float, @@ -195,30 +193,29 @@ typedef struct { } ContextData; typedef struct { - PalBool initialized; int32_t maxContextData; EGLenum apiType; int apiTypeBit; const PalAllocator* allocator; - eglGetProcAddressFn eglGetProcAddress; - eglCreateContextFn eglCreateContext; - eglDestroyContextFn eglDestroyContext; - eglMakeCurrentFn eglMakeCurrent; - eglSwapBuffersFn eglSwapBuffers; - eglSwapIntervalFn eglSwapInterval; - eglInitializeFn eglInitialize; - eglTerminateFn eglTerminate; - eglGetDisplayFn eglGetDisplay; - eglDestroySurfaceFn eglDestroySurface; - eglCreatePbufferSurfaceFn eglCreatePbufferSurface; - eglChooseConfigFn eglChooseConfig; - eglGetConfigAttribFn eglGetConfigAttrib; - eglGetErrorFn eglGetError; - eglBindAPIFn eglBindAPI; - eglQueryStringFn eglQueryString; - eglGetConfigsFn eglGetConfigs; - eglCreateWindowSurfaceFn eglCreateWindowSurface; + eglGetProcAddressFn getProcAddress; + eglCreateContextFn createContext; + eglDestroyContextFn destroyContext; + eglMakeCurrentFn makeCurrent; + eglSwapBuffersFn swapBuffers; + eglSwapIntervalFn swapInterval; + eglInitializeFn initialize; + eglTerminateFn terminate; + eglGetDisplayFn getDisplay; + eglDestroySurfaceFn destroySurface; + eglCreatePbufferSurfaceFn createPbufferSurface; + eglChooseConfigFn chooseConfig; + eglGetConfigAttribFn getConfigAttrib; + eglGetErrorFn getError; + eglBindAPIFn bindAPI; + eglQueryStringFn queryString; + eglGetConfigsFn getConfigs; + eglCreateWindowSurfaceFn createWindowSurface; glGetStringFn glGetString; glClearColorFn glClearColor; @@ -229,13 +226,8 @@ typedef struct { ContextData* contextData; EGLDisplay display; PalGLInfo info; -} GLLinux; - -extern GLLinux s_GL; +} EGL; -ContextData* getFreeContextData(); -ContextData* findContextData(PalGLContext* context); -void freeContextData(PalGLContext* context); +extern EGL s_Egl; -#endif // __linux__ -#endif // _PAL_OPENGL_LINUX_H \ No newline at end of file +#endif // _PAL_EGL_H \ No newline at end of file diff --git a/src/opengl/linux/pal_context_linux.c b/src/opengl/linux/pal_context_linux.c deleted file mode 100644 index 497b8cf0..00000000 --- a/src/opengl/linux/pal_context_linux.c +++ /dev/null @@ -1,420 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifdef __linux__ -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L - -#include "pal_opengl_linux.h" -#include "pal_shared.h" - -PalResult PAL_CALL palCreateGLContext( - const PalGLContextCreateInfo* info, - PalGLContext** outContext) -{ - if (!s_GL.initialized) { - palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!info || !outContext) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!info->window || !info->fbConfig) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - // check if the window was created with the same display - // the opengl system is using - if (info->window->display != s_GL.instance) { - palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - // check support for requested features - if (info->profile != PAL_GL_PROFILE_NONE) { - if (!(s_GL.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE)) { - palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } - - if (info->forward) { - if (!(s_GL.info.extensions & PAL_GL_EXTENSION_CREATE_CONTEXT)) { - palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } - - if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { - if (!(s_GL.info.extensions & PAL_GL_EXTENSION_ROBUSTNESS)) { - palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } - - if (info->noError) { - if (!(s_GL.info.extensions & PAL_GL_EXTENSION_NO_ERROR)) { - palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } - - if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { - if (!(s_GL.info.extensions & PAL_GL_EXTENSION_FLUSH_CONTROL)) { - palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } - - // check version - PalBool valid = info->major < s_GL.info.major || - (info->major == s_GL.info.major && info->minor <= s_GL.info.minor); - - if (!valid) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - ContextData* data = getFreeContextData(); - if (!data) { - palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - // we need to get the EGL config from the user supplied index - EGLint numConfigs = 0; - if (!s_GL.eglGetConfigs(s_GL.display, nullptr, 0, &numConfigs)) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLint configSize = sizeof(EGLConfig) * numConfigs; - EGLConfig* eglConfigs = palAllocate(s_GL.allocator, configSize, 0); - if (!eglConfigs) { - palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_GL.eglGetConfigs(s_GL.display, eglConfigs, numConfigs, &numConfigs); - EGLConfig config = eglConfigs[info->fbConfig->index]; - - EGLContext* share = nullptr; - if (info->shareContext) { - share = (EGLContext)info->shareContext; - } else { - share = EGL_NO_CONTEXT; - } - - int32_t attribs[40]; - int32_t index = 0; - int32_t profile = 0; - int32_t flags = 0; - - // set context attributes - // the first element is the key and the second is the value - if (s_GL.apiType == EGL_OPENGL_API) { - // set version - attribs[index++] = EGL_CONTEXT_MAJOR_VERSION_KHR; // key - attribs[index++] = info->major; // value - - attribs[index++] = EGL_CONTEXT_MINOR_VERSION_KHR; - attribs[index++] = info->minor; - - // set profile mask - if (info->profile != PAL_GL_PROFILE_NONE) { - attribs[index++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR; - - if (info->profile == PAL_GL_PROFILE_COMPATIBILITY) { - profile = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; - } else if (info->profile == PAL_GL_PROFILE_CORE) { - profile = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR; - } - - attribs[index++] = info->profile; - } - - // set forward flag - if (info->forward) { - flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; - } - - } else { - attribs[index++] = EGL_CONTEXT_CLIENT_VERSION; - // our configs support EGL_OPENGL_ES2_BIT and EGL_OPENGL_ES3_BIT - attribs[index++] = info->major; - } - - // set debug flag - if (info->debug) { - flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; - } - - // set robustness - if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { - flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; - attribs[index++] = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR; - - if (info->reset == PAL_GL_CONTEXT_RESET_LOSE_CONTEXT) { - attribs[index++] = EGL_LOSE_CONTEXT_ON_RESET_KHR; - - } else if (info->reset == PAL_GL_CONTEXT_RESET_NO_NOTIFICATION) { - attribs[index++] = EGL_NO_RESET_NOTIFICATION_KHR; - } - } - - // set no error - if (info->noError) { - attribs[index++] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR; - attribs[index++] = PAL_TRUE; - } - - // release - if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { - attribs[index++] = EGL_CONTEXT_RELEASE_BEHAVIOR_KHR; - attribs[index++] = EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR; - } - - if (flags) { - attribs[index++] = EGL_CONTEXT_FLAGS_KHR; - attribs[index++] = flags; - } - attribs[index++] = EGL_NONE; - - // create context - EGLContext context = s_GL.eglCreateContext(s_GL.display, config, share, attribs); - if (context == EGL_NO_CONTEXT) { - EGLint error = s_GL.eglGetError(); - if (error == EGL_BAD_CONFIG) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - - } else if (error == EGL_BAD_ATTRIBUTE) { - // we just return invalid version - // it could be invalid profile - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - - } else { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } - - // create a window surface - // The only attrib we want is colorspace - EGLint surfaceAttribs[3]; - surfaceAttribs[0] = EGL_GL_COLORSPACE; - if (info->fbConfig->sRGB) { - surfaceAttribs[1] = EGL_GL_COLORSPACE_SRGB_KHR; - } else { - surfaceAttribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR; - } - surfaceAttribs[2] = EGL_NONE; - - EGLSurface surface = s_GL.eglCreateWindowSurface( - s_GL.display, - config, - (EGLNativeWindowType)info->window->window, - surfaceAttribs); - - if (surface == EGL_NO_SURFACE) { - EGLint error = s_GL.eglGetError(); - if (error == EGL_BAD_CONFIG) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - - } else { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } - - // make the context current and swap for the first time - // this will make the window visible - if (s_GL.eglMakeCurrent(s_GL.display, surface, surface, context)) { - s_GL.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - s_GL.glClear(0x00004000); - s_GL.eglSwapBuffers(s_GL.display, surface); - - // revert - s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - - palFree(s_GL.allocator, eglConfigs); - data->context = (PalGLContext*)context; - data->surface = surface; - - *outContext = (PalGLContext*)context; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palDestroyGLContext(PalGLContext* context) -{ - if (s_GL.initialized && context) { - ContextData* data = findContextData(context); - if (data) { - // make it not current if it was current - s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - s_GL.eglDestroyContext(s_GL.display, (EGLContext)context); - s_GL.eglDestroySurface(s_GL.display, data->surface); - data->used = PAL_FALSE; - } - } -} - -PalResult PAL_CALL palMakeContextCurrent( - PalGLWindow* glWindow, - PalGLContext* context) -{ - if (!s_GL.initialized) { - palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if ((!glWindow && context) || (glWindow && !context)) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (context && glWindow) { - ContextData* data = findContextData(context); - if (!data) { - palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLint ret; - ret = s_GL.eglMakeCurrent(s_GL.display, data->surface, data->surface, (EGLConfig)context); - if (!ret) { - EGLint error = s_GL.eglGetError(); - if (error == EGL_BAD_CONTEXT) { - palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - - } else if (error == EGL_BAD_SURFACE) { - // since we always create a window surface - palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - - } else { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } - - } else if (!context && !glWindow) { - s_GL.eglMakeCurrent(s_GL.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL palSwapBuffers( - PalGLWindow* glWindow, - PalGLContext* context) -{ - if (!s_GL.initialized) { - palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!context || !glWindow) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - ContextData* data = findContextData(context); - if (!data) { - palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!s_GL.eglSwapBuffers(s_GL.display, data->surface)) { - EGLint error = s_GL.eglGetError(); - if (error == EGL_BAD_CONTEXT) { - palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - - } else if (error == EGL_BAD_SURFACE) { - // since we always create a window surface - palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_LINUX, - errno); - - } else { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } - - return PAL_RESULT_SUCCESS; -} - -#endif // __linux__ \ No newline at end of file diff --git a/src/opengl/linux/pal_opengl_linux.c b/src/opengl/linux/pal_opengl_linux.c deleted file mode 100644 index 49bccaea..00000000 --- a/src/opengl/linux/pal_opengl_linux.c +++ /dev/null @@ -1,649 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifdef __linux__ -#define _GNU_SOURCE -#define _POSIX_C_SOURCE 200112L -#include "pal_opengl_linux.h" -#include "opengl/pal_opengl_shared.h" -#include "pal_shared.h" - -#include -#include -#include -#include - -#include - -GLLinux s_GL = {0}; -static PalBool s_SupportedAPIs[2] = {0}; - -ContextData* getFreeContextData() -{ - for (int i = 0; i < s_GL.maxContextData; ++i) { - if (!s_GL.contextData[i].used) { - s_GL.contextData[i].used = PAL_TRUE; - return &s_GL.contextData[i]; - } - } - - // resize the data array - // this will almost not reach here since most setups are 1-4 monitors - ContextData* data = nullptr; - int count = s_GL.maxContextData * 2; // double the size - int freeIndex = s_GL.maxContextData + 1; - data = palAllocate(s_GL.allocator, sizeof(ContextData) * count, 0); - if (data) { - memcpy(data, s_GL.contextData, s_GL.maxContextData * sizeof(ContextData)); - - palFree(s_GL.allocator, s_GL.contextData); - s_GL.contextData = data; - s_GL.maxContextData = count; - - s_GL.contextData[freeIndex].used = PAL_TRUE; - return &s_GL.contextData[freeIndex]; - } - return nullptr; -} - -ContextData* findContextData(PalGLContext* context) -{ - for (int i = 0; i < s_GL.maxContextData; ++i) { - if (s_GL.contextData[i].used && s_GL.contextData[i].context == context) { - return &s_GL.contextData[i]; - } - } -} - -void freeContextData(PalGLContext* context) -{ - for (int i = 0; i < s_GL.maxContextData; ++i) { - if (s_GL.contextData[i].used && s_GL.contextData[i].context == context) { - s_GL.contextData[i].used = PAL_FALSE; - } - } -} - -PalResult PAL_CALL palInitGL( - PalGLAPI api, - void* instance, - const PalAllocator* allocator) -{ - if (s_GL.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (!instance) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_GL.maxContextData = 16; // initial size - s_GL.contextData = palAllocate(s_GL.allocator, sizeof(ContextData) * s_GL.maxContextData, 0); - if (!s_GL.maxContextData) { - palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_GL.handle = dlopen("libEGL.so", RTLD_LAZY); - if (!s_GL.handle) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - // clang-format off - s_GL.eglGetProcAddress = (eglGetProcAddressFn)dlsym( - s_GL.handle, - "eglGetProcAddress"); - - s_GL.eglCreateContext = (eglCreateContextFn)s_GL.eglGetProcAddress( - "eglCreateContext"); - - s_GL.eglDestroyContext = (eglDestroyContextFn)s_GL.eglGetProcAddress( - "eglDestroyContext"); - - s_GL.eglDestroySurface = (eglDestroySurfaceFn)s_GL.eglGetProcAddress( - "eglDestroySurface"); - - s_GL.eglMakeCurrent = (eglMakeCurrentFn)s_GL.eglGetProcAddress( - "eglMakeCurrent"); - - s_GL.eglSwapBuffers = (eglSwapBuffersFn)s_GL.eglGetProcAddress( - "eglSwapBuffers"); - - s_GL.eglSwapInterval = (eglSwapIntervalFn)s_GL.eglGetProcAddress( - "eglSwapInterval"); - - s_GL.eglInitialize = (eglInitializeFn)s_GL.eglGetProcAddress( - "eglInitialize"); - - s_GL.eglTerminate = (eglTerminateFn)s_GL.eglGetProcAddress("eglTerminate"); - - s_GL.eglGetDisplay = (eglGetDisplayFn)s_GL.eglGetProcAddress( - "eglGetDisplay"); - - s_GL.eglCreatePbufferSurface = (eglCreatePbufferSurfaceFn)s_GL.eglGetProcAddress( - "eglCreatePbufferSurface"); - - s_GL.eglChooseConfig = (eglChooseConfigFn)s_GL.eglGetProcAddress( - "eglChooseConfig"); - - s_GL.eglGetConfigAttrib = (eglGetConfigAttribFn)s_GL.eglGetProcAddress( - "eglGetConfigAttrib"); - - s_GL.eglGetError = (eglGetErrorFn)s_GL.eglGetProcAddress("eglGetError"); - s_GL.eglBindAPI = (eglBindAPIFn)s_GL.eglGetProcAddress("eglBindAPI"); - - s_GL.eglQueryString = (eglQueryStringFn)s_GL.eglGetProcAddress( - "eglQueryString"); - - s_GL.eglGetConfigs = (eglGetConfigsFn)s_GL.eglGetProcAddress( - "eglGetConfigs"); - - s_GL.eglCreateWindowSurface = (eglCreateWindowSurfaceFn)s_GL.eglGetProcAddress( - "eglCreateWindowSurface"); - - s_GL.glClearColor = (glClearColorFn)s_GL.eglGetProcAddress("glClearColor"); - s_GL.glClear = (glClearFn)s_GL.eglGetProcAddress("glClear"); - - if (!s_GL.eglBindAPI || - !s_GL.eglChooseConfig || - !s_GL.eglCreateContext || - !s_GL.eglCreatePbufferSurface || - !s_GL.eglDestroyContext || - !s_GL.eglDestroySurface || - !s_GL.eglGetConfigAttrib || - !s_GL.eglGetDisplay || - !s_GL.eglGetError || - !s_GL.eglGetProcAddress || - !s_GL.eglInitialize || - !s_GL.eglMakeCurrent || - !s_GL.eglSwapBuffers || - !s_GL.eglSwapInterval || - !s_GL.eglTerminate || - !s_GL.eglQueryString || - !s_GL.eglGetConfigs || - !s_GL.eglCreateWindowSurface) { - - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - // clang-format on - - // get api type - if (api == PAL_GL_API_OPENGL) { - s_GL.apiType = EGL_OPENGL_API; - s_GL.apiTypeBit = EGL_OPENGL_BIT; - - } else { - s_GL.apiType = EGL_OPENGL_ES_API; - s_GL.apiTypeBit = EGL_OPENGL_ES2_BIT; // default - } - - if (!s_GL.eglBindAPI(s_GL.apiType)) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLDisplay display = s_GL.eglGetDisplay(instance); - EGLDisplay* tmpDisplay = EGL_NO_DISPLAY; - if (display == EGL_NO_DISPLAY) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!s_GL.eglInitialize(display, nullptr, nullptr)) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - // use a simple FBConfig - EGLConfig config; - int numConfigs; - EGLint type; - - // clang-format off - EGLint attribs[] = { - EGL_RENDERABLE_TYPE, - s_GL.apiTypeBit, - EGL_SURFACE_TYPE, - EGL_PBUFFER_BIT, - EGL_NONE - }; - // clang-format on - - s_GL.eglChooseConfig(display, attribs, &config, 1, &numConfigs); - if (!config || numConfigs == 0) { - // API bind type might not support puffer - // create a default display and use that - tmpDisplay = s_GL.eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (display == EGL_NO_DISPLAY) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!s_GL.eglInitialize(tmpDisplay, nullptr, nullptr)) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - } else { - // set the tmp display to our display - tmpDisplay = display; - } - - s_GL.eglChooseConfig(tmpDisplay, attribs, &config, 1, &numConfigs); - if (!config) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_GL.eglGetConfigAttrib(tmpDisplay, config, EGL_RENDERABLE_TYPE, &type); - if (!(type & s_GL.apiTypeBit)) { - // we must support the required API - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLSurface surface = EGL_NO_SURFACE; - EGLint pBufferAttribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; - surface = s_GL.eglCreatePbufferSurface(tmpDisplay, config, pBufferAttribs); - if (surface == EGL_NO_SURFACE) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - // create a dummy context - EGLContext context = EGL_NO_CONTEXT; - if (s_GL.apiType == EGL_OPENGL_API) { - // clang-format off - EGLint contextAttrib[] = { - EGL_CONTEXT_MAJOR_VERSION, - 2, - EGL_CONTEXT_MINOR_VERSION, - 1, - EGL_NONE - }; - // clang-format on - - context = s_GL.eglCreateContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); - - } else { - EGLint contextAttrib[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; - context = s_GL.eglCreateContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); - } - - if (context == EGL_NO_CONTEXT) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_GL.eglMakeCurrent(tmpDisplay, surface, surface, context); - s_GL.glGetString = (glGetStringFn)s_GL.eglGetProcAddress("glGetString"); - - const char* version = (const char*)s_GL.glGetString(GL_VERSION); - if (version) { - if (s_GL.apiType == EGL_OPENGL_API) { - sscanf(version, "%d.%d", &s_GL.info.major, &s_GL.info.minor); - } else { - sscanf(version + 10, "%d.%d", &s_GL.info.major, &s_GL.info.minor); - } - } - - const char* renderer = (const char*)s_GL.glGetString(GL_RENDERER); - const char* vendor = (const char*)s_GL.glGetString(GL_VENDOR); - strcpy(s_GL.info.vendor, vendor); - strcpy(s_GL.info.version, version); - strcpy(s_GL.info.graphicsCard, renderer); - - // EGL extensions can be queried without a bound context - // we just do that over here after making the context current - const char* extensions = s_GL.eglQueryString(tmpDisplay, EGL_EXTENSIONS); - if (extensions) { - // color space - if (checkString("EGL_KHR_gl_colorspace", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_COLORSPACE_SRGB; - } - - // create context - if (checkString("EGL_KHR_create_context", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_CREATE_CONTEXT; - s_GL.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE; - } - - // robustness - if (checkString("EGL_EXT_create_context_robustness", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_ROBUSTNESS; - } - - // no error - if (checkString("EGL_KHR_create_context_no_error", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_NO_ERROR; - } - - // flush control - if (checkString("EGL_KHR_context_flush_control", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; - } - - // swap control - if (checkString("EGL_EXT_swap_control", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; - } - - if (checkString("EGL_EXT_swap_control_tear", extensions)) { - s_GL.info.extensions |= PAL_GL_EXTENSION_FLUSH_CONTROL; - } - } - - // part of the core API - s_GL.info.extensions |= PAL_GL_EXTENSION_MULTISAMPLE; - if (type & EGL_OPENGL_ES_BIT || type & EGL_OPENGL_ES2_BIT) { - s_GL.info.extensions |= PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; - } - - // check if we support the core swap interval - if (s_GL.eglSwapInterval) { - s_GL.info.extensions |= PAL_GL_EXTENSION_SWAP_CONTROL; - } - - if (s_GL.apiType != EGL_OPENGL_API) { - if (s_GL.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE) { - s_GL.info.extensions &= ~PAL_GL_EXTENSION_CONTEXT_PROFILE; - s_GL.info.extensions &= ~PAL_GL_EXTENSION_CONTEXT_PROFILE_ES2; - } - - if (type & EGL_OPENGL_ES3_BIT) { - s_GL.apiTypeBit = EGL_OPENGL_ES3_BIT; - } - } - - s_GL.eglMakeCurrent(tmpDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - s_GL.eglDestroyContext(tmpDisplay, context); - s_GL.eglDestroySurface(tmpDisplay, surface); - - s_GL.info.api = api; - s_GL.info.backend = PAL_GL_BACKEND_EGL; - s_GL.allocator = allocator; - s_GL.initialized = PAL_TRUE; - - if (tmpDisplay != display) { - // tmpDisplay is a seperate display - // terminate it - s_GL.eglTerminate(tmpDisplay); - } - - s_GL.display = display; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL palShutdownGL() -{ - if (!s_GL.initialized) { - return; - } - - palFree(s_GL.allocator, s_GL.contextData); - if (s_GL.display) { - s_GL.eglTerminate(s_GL.display); - } - - dlclose(s_GL.handle); - s_GL.initialized = PAL_FALSE; -} - -const PalGLInfo* PAL_CALL palGetGLInfo() -{ - if (!s_GL.initialized) { - return nullptr; - } - return &s_GL.info; -} - -PalResult PAL_CALL palEnumerateGLFBConfigs( - int32_t* count, - PalGLFBConfig* configs) -{ - if (!s_GL.initialized) { - palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!count || count == 0 && configs) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - int32_t configCount = 0; - int32_t maxConfigCount = 0; - if (configs) { - maxConfigCount = *count; - } - - // get the number of configs and filter the ones for opengl desktop - EGLint numConfigs = 0; - if (!s_GL.eglGetConfigs(s_GL.display, nullptr, 0, &numConfigs)) { - palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - EGLint configSize = sizeof(EGLConfig) * numConfigs; - EGLConfig* eglConfigs = palAllocate(s_GL.allocator, configSize, 0); - if (!eglConfigs) { - palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_GL.eglGetConfigs(s_GL.display, eglConfigs, numConfigs, &numConfigs); - for (int i = 0; i < numConfigs; i++) { - // attributes we care about - EGLint surfaceType = 0, renderable = 0; - EGLint colorType = 0; - - EGLConfig config = eglConfigs[i]; - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_SURFACE_TYPE, &surfaceType); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_RENDERABLE_TYPE, &renderable); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_COLOR_BUFFER_TYPE, &colorType); - - // we need only opengl API configs - if (colorType != EGL_RGB_BUFFER) { - continue; - } - - if (s_GL.apiType == EGL_OPENGL_ES3_BIT) { - // EGL_OPENGL_ES2_BIT - if (!(renderable & EGL_OPENGL_ES2_BIT) && !(renderable & EGL_OPENGL_ES3_BIT)) { - continue; - } - - } else if (s_GL.apiType == EGL_OPENGL_ES2_BIT) { - if (!(renderable & EGL_OPENGL_ES2_BIT)) { - continue; - } - - } else { - if (!(renderable & EGL_OPENGL_BIT)) { - continue; - } - } - - if (!(surfaceType & EGL_WINDOW_BIT)) { - continue; - } - - if (configs && configCount < maxConfigCount) { - // get this only if user supplied an output buffer (PalGLFBConfig*) - PalGLFBConfig* fbConfig = &configs[configCount]; - fbConfig->index = i; - - EGLint redBits, greenBits, blueBits, alphaBits; - EGLint depthBits, stencilBits, samples; - - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_RED_SIZE, &redBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_GREEN_SIZE, &greenBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_BLUE_SIZE, &blueBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_ALPHA_SIZE, &alphaBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_DEPTH_SIZE, &depthBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_STENCIL_SIZE, &stencilBits); - s_GL.eglGetConfigAttrib(s_GL.display, config, EGL_SAMPLES, &samples); - if (samples == 0) { - samples = 1; - } - - fbConfig->redBits = redBits; - fbConfig->greenBits = greenBits; - fbConfig->blueBits = blueBits; - fbConfig->alphaBits = alphaBits; - fbConfig->depthBits = depthBits; - fbConfig->stencilBits = stencilBits; - fbConfig->samples = samples; - - // True for EGL_WINDOW_BIT - fbConfig->doubleBuffer = PAL_TRUE; - fbConfig->stereo = PAL_FALSE; - - fbConfig->sRGB = PAL_FALSE; - if (s_GL.info.extensions & PAL_GL_EXTENSION_COLORSPACE_SRGB) { - // since EGL does not have a bit to check SRGB support - // we check if all the color bits are greater than or equal to 8 - if (fbConfig->redBits >= 8 && fbConfig->greenBits >= 8 && fbConfig->blueBits >= 8) { - fbConfig->sRGB = PAL_TRUE; - } - } - } - configCount++; - } - - palFree(s_GL.allocator, eglConfigs); - if (!configs) { - *count = configCount; - } - - return PAL_RESULT_SUCCESS; -} - -void* PAL_CALL palGetGLProcAddress(const char* name) -{ - if (!s_GL.initialized) { - return nullptr; - } - - return s_GL.eglGetProcAddress(name); -} - -PalResult PAL_CALL palSetSwapInterval(int32_t interval) -{ - if (!s_GL.initialized) { - palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - if (!s_GL.eglSwapInterval) { - palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_LINUX, - errno); - } - - s_GL.eglSwapInterval(s_GL.display, interval); - return PAL_RESULT_SUCCESS; -} - -const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance) -{ - if (!instance) { - return nullptr; - } - - void* handle = dlopen("libEGL.so", RTLD_LAZY); - if (!handle) { - return nullptr; - } - - // clang-format off - eglGetProcAddressFn getProcAddress = (eglGetProcAddressFn)dlsym(handle, "eglGetProcAddress"); - eglInitializeFn initialize = (eglInitializeFn)getProcAddress("eglInitialize"); - eglTerminateFn terminate = (eglTerminateFn)getProcAddress("eglTerminate"); - eglGetDisplayFn getDisplay = (eglGetDisplayFn)getProcAddress("eglGetDisplay"); - eglQueryStringFn queryString = (eglQueryStringFn)getProcAddress("eglQueryString"); - if (!getProcAddress || !initialize || !terminate || !getDisplay || !queryString) { - return nullptr; - } - // clang-format on - - EGLDisplay display = getDisplay(instance); - if (display == EGL_NO_DISPLAY) { - return nullptr; - } - - if (!initialize(display, nullptr, nullptr)) { - return nullptr; - } - - const char* apis = queryString(display, EGL_CLIENT_APIS); - if (apis) { - if (checkString("OpenGL", apis)) { - s_SupportedAPIs[PAL_GL_API_OPENGL] = PAL_TRUE; - } else { - s_SupportedAPIs[PAL_GL_API_OPENGL] = PAL_FALSE; - } - - if (checkString("OpenGL_ES", apis)) { - s_SupportedAPIs[PAL_GL_API_OPENGL_ES] = PAL_TRUE; - } else { - s_SupportedAPIs[PAL_GL_API_OPENGL_ES] = PAL_FALSE; - } - } - - terminate(display); - dlclose(handle); - return s_SupportedAPIs; -} - -#endif // __linux__ \ No newline at end of file diff --git a/src/opengl/pal_opengl.c b/src/opengl/pal_opengl.c new file mode 100644 index 00000000..94f3856f --- /dev/null +++ b/src/opengl/pal_opengl.c @@ -0,0 +1,255 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "pal/pal_opengl.h" +#include "pal_opengl_backends.h" +#include + +typedef struct { + PalBool initialized; + const OpenglBackend* backend; +} Opengl; + +static Opengl s_Gl = {0}; + +PalBool checkString( + const char* string, + const char* strings) +{ + const char* start = strings; + size_t stringLen = strlen(string); + + for (;;) { + const char* where = nullptr; + const char* terminator = nullptr; + + where = strstr(start, string); + if (!where) { + return PAL_FALSE; + } + + // the string was found, we find the terminator by adding the sizeof the strings + terminator = where + stringLen; + if (where == start || *(where - 1) == ' ') { + if (*terminator == ' ' || *terminator == '\0') { + return PAL_TRUE; + } + } + + start = terminator; + } +} + +PalResult PAL_CALL palInitGL( + PalGLAPI api, + void* instance, + const PalAllocator* allocator) +{ + if (s_Gl.initialized) { + return PAL_RESULT_SUCCESS; + } + + if (!instance) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (allocator && (!allocator->allocate || !allocator->free)) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + // initialize the backends +#ifdef _WIN32 + PalResult result = wglInitGL(api, instance, allocator); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + s_Gl.backend = &s_WglBackend; +#endif // _WIN32 + +#if _PAL_HAS_EGL + PalResult result = eglInitGL(api, instance, allocator); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + s_Gl.backend = &s_EglBackend; +#endif // _PAL_HAS_EGL + + // check if we found a backend + if (!s_Gl.backend) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + + s_Gl.initialized = PAL_TRUE; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL palShutdownGL() +{ + if (s_Gl.initialized) { + s_Gl.backend->shutdownGL(); + s_Gl.initialized = PAL_FALSE; + } +} + +const PalGLInfo* PAL_CALL palGetGLInfo() +{ + if (s_Gl.initialized) { + return s_Gl.backend->getGLInfo(); + } + return nullptr; +} + +PalResult PAL_CALL palEnumerateGLFBConfigs( + int32_t* count, + PalGLFBConfig* configs) +{ + if (!s_Gl.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!count || *count == 0 && configs) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Gl.backend->enumerateGLFBConfigs(count, configs); +} + +const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( + PalGLFBConfig* configs, + int32_t count, + const PalGLFBConfig* desired) +{ + if (!configs || !desired) { + return nullptr; + } + + if (count == 0) { + return nullptr; + } + + int32_t score = 0; + int32_t bestScore = 0x7FFFFFFF; + PalGLFBConfig* best = nullptr; + for (int32_t i = 0; i < count; i++) { + PalGLFBConfig* tmp = &configs[i]; + + // filter out hard constraints + if (desired->doubleBuffer && !tmp->doubleBuffer) { + continue; + } + + if (desired->stereo && !tmp->stereo) { + continue; + } + + score = 0; + + // score color bits + score += abs(tmp->redBits - desired->redBits); + score += abs(tmp->greenBits - desired->greenBits); + score += abs(tmp->blueBits - desired->blueBits); + score += abs(tmp->alphaBits - desired->alphaBits); + score += abs(tmp->depthBits - desired->depthBits); + score += abs(tmp->stencilBits - desired->stencilBits); + + // score soft constraints + if (desired->samples != tmp->samples) { + score += 1000; + } + + if (desired->sRGB != tmp->sRGB) { + score += 500; + } + + if (score < bestScore) { + bestScore = score; + best = &configs[i]; + } + } + + return best; +} + +PalResult PAL_CALL palCreateGLContext( + const PalGLContextCreateInfo* info, + PalGLContext** outContext) +{ + if (!s_Gl.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!info || !outContext) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Gl.backend->createGLContext(info, outContext); +} + +void PAL_CALL palDestroyGLContext(PalGLContext* context) +{ + if (s_Gl.initialized && context) { + s_Gl.backend->destroyGLContext(context); + } +} + +PalResult PAL_CALL palMakeContextCurrent( + PalGLWindow* glWindow, + PalGLContext* context) +{ + if (!s_Gl.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!glWindow || !context) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Gl.backend->makeContextCurrent(glWindow, context); +} + +void* PAL_CALL palGetGLProcAddress(const char* name) +{ + if (s_Gl.initialized && name) { + return s_Gl.backend->getGLProcAddress(name); + } + return nullptr; +} + +PalResult PAL_CALL palSwapBuffers( + PalGLWindow* glWindow, + PalGLContext* context) +{ + if (!s_Gl.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + + if (!glWindow || !context) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + return s_Gl.backend->swapBuffers(glWindow, context); +} + +PalResult PAL_CALL palSetSwapInterval(int32_t interval) +{ + if (!s_Gl.initialized) { + return PAL_RESULT_CODE_NOT_INITIALIZED; + } + return s_Gl.backend->setSwapInterval(interval); +} + +const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance) +{ + if (instance) { +#if _PAL_HAS_EGL + return eglGetSupportedGLAPIs(instance); +#elif defined(_WIN32) + return wglGetSupportedGLAPIs(instance); +#endif // _PAL_HAS_EGL + } + return nullptr; +} \ No newline at end of file diff --git a/src/opengl/pal_opengl_backends.h b/src/opengl/pal_opengl_backends.h new file mode 100644 index 00000000..e8cc7e7b --- /dev/null +++ b/src/opengl/pal_opengl_backends.h @@ -0,0 +1,91 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_OPENGL_BACKENDS_H +#define _PAL_OPENGL_BACKENDS_H + +#include "pal_platform.h" +#include "pal/pal_opengl.h" + +typedef struct { + // clang-format off + void (*shutdownGL)(); + const PalGLInfo* (*getGLInfo)(); + PalResult (*enumerateGLFBConfigs)(int32_t*, PalGLFBConfig*); + PalResult (*createGLContext)(const PalGLContextCreateInfo*, PalGLContext**); + void (*destroyGLContext)(PalGLContext* context); + PalResult (*makeContextCurrent)(PalGLWindow*, PalGLContext*); + void* (*getGLProcAddress)(const char*); + PalResult (*swapBuffers)(PalGLWindow*, PalGLContext*); + PalResult (*setSwapInterval)(int32_t); + const PalBool* (*GetSupportedGLAPIs)(void*); + // clang-format on +} OpenglBackend; + +// ================================================== +// WGL +// ================================================== + +#ifdef _WIN32 +PalResult wglInitGL(PalGLAPI api, void* instance, const PalAllocator* allocator); +void wglShutdownGL(); +const PalGLInfo* wglGetGLInfo(); +PalResult wglEnumerateGLFBConfigs(int32_t* count, PalGLFBConfig* configs); +PalResult wglCreateGLContext(const PalGLContextCreateInfo* info, PalGLContext** outContext); +void wglDestroyGLContext(PalGLContext* context); +PalResult wglMakeContextCurrent(PalGLWindow* glWindow, PalGLContext* context); +void* wglGetGLProcAddress(const char* name); +PalResult wglSwapBuffers(PalGLWindow* glWindow, PalGLContext* context); +PalResult wglSetSwapInterval(int32_t interval); +const PalBool* wglGetSupportedGLAPIs(void* instance); + +static OpenglBackend s_WglBackend = { + .shutdownGL = wglShutdownGL, + .getGLInfo = wglGetGLInfo, + .enumerateGLFBConfigs = wglEnumerateGLFBConfigs, + .createGLContext = wglCreateGLContext, + .destroyGLContext = wglDestroyGLContext, + .makeContextCurrent = wglMakeContextCurrent, + .getGLProcAddress = wglGetGLProcAddress, + .swapBuffers = wglSwapBuffers, + .setSwapInterval = wglSetSwapInterval, + .GetSupportedGLAPIs = wglGetSupportedGLAPIs}; + +#endif // _WIN32 + +// ================================================== +// EGL +// ================================================== + +#if _PAL_HAS_EGL +PalResult eglInitGL(PalGLAPI api, void* instance, const PalAllocator* allocator); +void eglShutdownGL(); +const PalGLInfo* eglGetGLInfo(); +PalResult eglEnumerateGLFBConfigs(int32_t* count, PalGLFBConfig* configs); +PalResult eglCreateGLContext(const PalGLContextCreateInfo* info, PalGLContext** outContext); +void eglDestroyGLContext(PalGLContext* context); +PalResult eglMakeContextCurrent(PalGLWindow* glWindow, PalGLContext* context); +void* eglGetGLProcAddress(const char* name); +PalResult eglSwapBuffers(PalGLWindow* glWindow, PalGLContext* context); +PalResult eglSetSwapInterval(int32_t interval); +const PalBool* eglGetSupportedGLAPIs(void* instance); + +static OpenglBackend s_EglBackend = { + .shutdownGL = eglShutdownGL, + .getGLInfo = eglGetGLInfo, + .enumerateGLFBConfigs = eglEnumerateGLFBConfigs, + .createGLContext = eglCreateGLContext, + .destroyGLContext = eglDestroyGLContext, + .makeContextCurrent = eglMakeContextCurrent, + .getGLProcAddress = eglGetGLProcAddress, + .swapBuffers = eglSwapBuffers, + .setSwapInterval = eglSetSwapInterval, + .GetSupportedGLAPIs = eglGetSupportedGLAPIs}; + +#endif // _PAL_HAS_EGL + +#endif // _PAL_OPENGL_BACKENDS_H \ No newline at end of file diff --git a/src/opengl/pal_opengl_shared.c b/src/opengl/pal_opengl_shared.c deleted file mode 100644 index 6616b4ee..00000000 --- a/src/opengl/pal_opengl_shared.c +++ /dev/null @@ -1,94 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#include "pal/pal_opengl.h" -#include "pal_opengl_shared.h" -#include - -PalBool checkString( - const char* string, - const char* strings) -{ - const char* start = strings; - size_t stringLen = strlen(string); - - for (;;) { - const char* where = nullptr; - const char* terminator = nullptr; - - where = strstr(start, string); - if (!where) { - return PAL_FALSE; - } - - // the string was found, we find the terminator by adding the sizeof the strings - terminator = where + stringLen; - if (where == start || *(where - 1) == ' ') { - if (*terminator == ' ' || *terminator == '\0') { - return PAL_TRUE; - } - } - - start = terminator; - } -} - -const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( - PalGLFBConfig* configs, - int32_t count, - const PalGLFBConfig* desired) -{ - if (!configs || !desired) { - return nullptr; - } - - if (count == 0) { - return nullptr; - } - - int32_t score = 0; - int32_t bestScore = 0x7FFFFFFF; - PalGLFBConfig* best = nullptr; - for (int32_t i = 0; i < count; i++) { - PalGLFBConfig* tmp = &configs[i]; - - // filter out hard constraints - if (desired->doubleBuffer && !tmp->doubleBuffer) { - continue; - } - - if (desired->stereo && !tmp->stereo) { - continue; - } - - score = 0; - - // score color bits - score += abs(tmp->redBits - desired->redBits); - score += abs(tmp->greenBits - desired->greenBits); - score += abs(tmp->blueBits - desired->blueBits); - score += abs(tmp->alphaBits - desired->alphaBits); - score += abs(tmp->depthBits - desired->depthBits); - score += abs(tmp->stencilBits - desired->stencilBits); - - // score soft constraints - if (desired->samples != tmp->samples) { - score += 1000; - } - - if (desired->sRGB != tmp->sRGB) { - score += 500; - } - - if (score < bestScore) { - bestScore = score; - best = &configs[i]; - } - } - - return best; -} \ No newline at end of file diff --git a/src/pal_posix.h b/src/pal_platform.h similarity index 53% rename from src/pal_posix.h rename to src/pal_platform.h index b330b6f5..d512ce23 100644 --- a/src/pal_posix.h +++ b/src/pal_platform.h @@ -5,16 +5,24 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifndef _PAL_POSIX_H -#define _PAL_POSIX_H +#ifndef _PAL_PLATFORM_H +#define _PAL_PLATFORM_H // clang-format off + #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) \ || defined(__NetBSD) || defined(__OpenBSD) -#define _PAL_ON_POSIX 1 +#define _PAL_HAS_POSIX 1 +#else +#define _PAL_HAS_POSIX 0 +#endif // _PAL_HAS_POSIX + +#if defined(__linux__) || defined(__ANDROID__) +#define _PAL_HAS_EGL 1 #else -#define _PAL_ON_POSIX 0 -#endif // _PAL_ON_POSIX +#define _PAL_HAS_EGL 0 +#endif // _PAL_HAS_EGL + // clang-format on -#endif // _PAL_POSIX_H \ No newline at end of file +#endif // _PAL_PLATFORM_H \ No newline at end of file diff --git a/src/thread/posix/pal_condvar_posix.c b/src/thread/posix/pal_condvar_posix.c index 589dbd95..41de3547 100644 --- a/src/thread/posix/pal_condvar_posix.c +++ b/src/thread/posix/pal_condvar_posix.c @@ -5,9 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal_posix.h" +#include "pal_platform.h" -#if _PAL_ON_POSIX +#if _PAL_HAS_POSIX #include "pal_thread_posix.h" PalResult PAL_CALL palCreateCondVar( @@ -103,4 +103,4 @@ void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) } } -#endif // _PAL_ON_POSIX \ No newline at end of file +#endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/thread/posix/pal_mutex_posix.c b/src/thread/posix/pal_mutex_posix.c index b301079a..af51aebc 100644 --- a/src/thread/posix/pal_mutex_posix.c +++ b/src/thread/posix/pal_mutex_posix.c @@ -5,9 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal_posix.h" +#include "pal_platform.h" -#if _PAL_ON_POSIX +#if _PAL_HAS_POSIX #include "pal_thread_posix.h" PalResult PAL_CALL palCreateMutex( @@ -57,4 +57,4 @@ void PAL_CALL palUnlockMutex(PalMutex* mutex) } } -#endif // _PAL_ON_POSIX \ No newline at end of file +#endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/thread/posix/pal_thread_posix.c b/src/thread/posix/pal_thread_posix.c index 9951f96e..abf8177a 100644 --- a/src/thread/posix/pal_thread_posix.c +++ b/src/thread/posix/pal_thread_posix.c @@ -5,12 +5,12 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal_posix.h" +#include "pal_platform.h" #ifdef __linux__ #define _GNU_SOURCE #endif // __linux__ -#if _PAL_ON_POSIX +#if _PAL_HAS_POSIX #include "pal_thread_posix.h" #include #include @@ -281,4 +281,4 @@ PalResult PAL_CALL palSetThreadName( return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } -#endif // _PAL_ON_POSIX \ No newline at end of file +#endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/thread/posix/pal_thread_posix.h b/src/thread/posix/pal_thread_posix.h index 169b02ab..a8a993e7 100644 --- a/src/thread/posix/pal_thread_posix.h +++ b/src/thread/posix/pal_thread_posix.h @@ -8,8 +8,8 @@ #ifndef _PAL_THREAD_LINUX_H #define _PAL_THREAD_LINUX_H -#include "pal_posix.h" -#if _PAL_ON_POSIX +#include "pal_platform.h" +#if _PAL_HAS_POSIX #define _POSIX_C_SOURCE 200112L #include "pal/pal_thread.h" @@ -27,5 +27,5 @@ struct PalMutex { pthread_mutex_t handle; }; -#endif // _PAL_ON_POSIX +#endif // _PAL_HAS_POSIX #endif // _PAL_THREAD_LINUX_H \ No newline at end of file diff --git a/src/thread/posix/pal_tls_posix.c b/src/thread/posix/pal_tls_posix.c index cf7f0671..d2a3b4d3 100644 --- a/src/thread/posix/pal_tls_posix.c +++ b/src/thread/posix/pal_tls_posix.c @@ -5,9 +5,9 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal_posix.h" +#include "pal_platform.h" -#if _PAL_ON_POSIX +#if _PAL_HAS_POSIX #include "pal/pal_thread.h" #include @@ -37,4 +37,4 @@ void PAL_CALL palSetTLS( pthread_setspecific((pthread_key_t)id, data); } -#endif // _PAL_ON_POSIX \ No newline at end of file +#endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/video/pal_video.c b/src/video/pal_video.c index 4f56d736..7774858e 100644 --- a/src/video/pal_video.c +++ b/src/video/pal_video.c @@ -11,10 +11,10 @@ typedef struct { PalBool initialized; - const Backend* backend; + const VideoBackend* backend; } Video; -EGL s_Egl = {0}; +VideoEGL s_VideoEgl = {0}; static Video s_Video = {0}; static int compareModes( diff --git a/src/video/pal_video_backends.h b/src/video/pal_video_backends.h index b4852773..4763d798 100644 --- a/src/video/pal_video_backends.h +++ b/src/video/pal_video_backends.h @@ -4,8 +4,8 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifndef _PAL_BACKENDS_LINUX_H -#define _PAL_BACKENDS_LINUX_H +#ifndef _PAL_VIDEO_BACKENDS_H +#define _PAL_VIDEO_BACKENDS_H #include "pal/pal_video.h" @@ -68,7 +68,7 @@ typedef struct { PalResult (*detachWindow)(PalWindow*, void**); void* (*getInstance)(); // clang-format on -} Backend; +} VideoBackend; // ================================================== // WIN32 @@ -134,7 +134,7 @@ PalResult win32AttachWindow(void*, PalWindow**); PalResult win32DetachWindow(PalWindow*, void**); void* win32GetInstance(); -static Backend s_Win32Backend = { +static VideoBackend s_Win32Backend = { .shutdownVideo = win32ShutdownVideo, .updateVideo = win32UpdateVideo, .getVideoFeatures = win32GetVideoFeatures, @@ -258,7 +258,7 @@ PalResult xAttachWindow(void*, PalWindow**); PalResult xDetachWindow(PalWindow*, void**); void* xGetInstance(); -static Backend s_XBackend = { +static VideoBackend s_XBackend = { .shutdownVideo = xShutdownVideo, .updateVideo = xUpdateVideo, .getVideoFeatures = xGetVideoFeatures, @@ -383,7 +383,7 @@ PalResult wlAttachWindow(void*, PalWindow**); PalResult wlDetachWindow(PalWindow*, void**); void* wlGetInstance(); -static Backend s_wlBackend = { +static VideoBackend s_wlBackend = { .shutdownVideo = wlShutdownVideo, .updateVideo = wlUpdateVideo, .getVideoFeatures = wlGetVideoFeatures, @@ -443,4 +443,4 @@ static Backend s_wlBackend = { #endif // PAL_HAS_WAYLAND_BACKEND -#endif // _PAL_BACKENDS_LINUX_H \ No newline at end of file +#endif // _PAL_VIDEO_BACKENDS_H \ No newline at end of file diff --git a/src/video/pal_video_egl.h b/src/video/pal_video_egl.h index 0ae5e47e..68d4b4fa 100644 --- a/src/video/pal_video_egl.h +++ b/src/video/pal_video_egl.h @@ -66,16 +66,16 @@ typedef EGLBoolean (*eglGetConfigsFn)( typedef struct { void* handle; - eglInitializeFn eglInitialize; - eglTerminateFn eglTerminate; - eglGetDisplayFn eglGetDisplay; - eglChooseConfigFn eglChooseConfig; - eglGetConfigAttribFn eglGetConfigAttrib; - eglGetErrorFn eglGetError; - eglBindAPIFn eglBindAPI; - eglGetConfigsFn eglGetConfigs; -} EGL; - -extern EGL s_Egl; + eglInitializeFn initialize; + eglTerminateFn terminate; + eglGetDisplayFn getDisplay; + eglChooseConfigFn chooseConfig; + eglGetConfigAttribFn getConfigAttrib; + eglGetErrorFn getError; + eglBindAPIFn bindAPI; + eglGetConfigsFn getConfigs; +} VideoEGL; + +extern VideoEGL s_VideoEgl; #endif // _PAL_VIDEO_EGL_H \ No newline at end of file diff --git a/src/video/wayland/pal_video_wayland.c b/src/video/wayland/pal_video_wayland.c index df1ba846..d7367bc6 100644 --- a/src/video/wayland/pal_video_wayland.c +++ b/src/video/wayland/pal_video_wayland.c @@ -1613,19 +1613,19 @@ PalResult wlInitVideo( } // load EGL - s_Egl.handle = dlopen("libEGL.so", RTLD_LAZY); - if (s_Egl.handle) { + s_VideoEgl.handle = dlopen("libEGL.so", RTLD_LAZY); + if (s_VideoEgl.handle) { eglGetProcAddressFn load = nullptr; - load = (eglGetProcAddressFn)dlsym(s_Egl.handle, "eglGetProcAddress"); + load = (eglGetProcAddressFn)dlsym(s_VideoEgl.handle, "eglGetProcAddress"); - s_Egl.eglInitialize = (eglInitializeFn)load("eglInitialize"); - s_Egl.eglTerminate = (eglTerminateFn)load("eglTerminate"); - s_Egl.eglGetDisplay = (eglGetDisplayFn)load("eglGetDisplay"); - s_Egl.eglChooseConfig = (eglChooseConfigFn)load("eglChooseConfig"); - s_Egl.eglGetError = (eglGetErrorFn)load("eglGetError"); - s_Egl.eglBindAPI = (eglBindAPIFn)load("eglBindAPI"); - s_Egl.eglGetConfigs = (eglGetConfigsFn)load("eglGetConfigs"); - s_Egl.eglGetConfigAttrib = (eglGetConfigAttribFn)load("eglGetConfigAttrib"); + s_VideoEgl.initialize = (eglInitializeFn)load("eglInitialize"); + s_VideoEgl.terminate = (eglTerminateFn)load("eglTerminate"); + s_VideoEgl.getDisplay = (eglGetDisplayFn)load("eglGetDisplay"); + s_VideoEgl.chooseConfig = (eglChooseConfigFn)load("eglChooseConfig"); + s_VideoEgl.getError = (eglGetErrorFn)load("eglGetError"); + s_VideoEgl.bindAPI = (eglBindAPIFn)load("eglBindAPI"); + s_VideoEgl.getConfigs = (eglGetConfigsFn)load("eglGetConfigs"); + s_VideoEgl.getConfigAttrib = (eglGetConfigAttribFn)load("eglGetConfigAttrib"); } createKeycodeTable(); @@ -1665,8 +1665,8 @@ void wlShutdownVideo() palFree(s_Wl.allocator, s_Wl.windowData); palFree(s_Wl.allocator, s_Wl.monitorData); - if (s_Egl.handle) { - dlclose(s_Egl.handle); + if (s_VideoEgl.handle) { + dlclose(s_VideoEgl.handle); } memset(&s_Wl, 0, sizeof(Wayland)); diff --git a/src/video/wayland/pal_window_wayland.c b/src/video/wayland/pal_window_wayland.c index 1dc378c4..5c0fc6a0 100644 --- a/src/video/wayland/pal_window_wayland.c +++ b/src/video/wayland/pal_window_wayland.c @@ -14,13 +14,13 @@ EGLConfig eglWlBackend(const int fbConfigIndex) { EGLDisplay display = EGL_NO_DISPLAY; - display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_Wl.display); + display = s_VideoEgl.getDisplay((EGLNativeDisplayType)s_Wl.display); if (display == EGL_NO_DISPLAY) { return nullptr; } EGLint numConfigs = 0; - if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { + if (!s_VideoEgl.getConfigs(display, nullptr, 0, &numConfigs)) { return nullptr; } @@ -30,7 +30,7 @@ EGLConfig eglWlBackend(const int fbConfigIndex) return nullptr; } - s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); + s_VideoEgl.getConfigs(display, eglConfigs, numConfigs, &numConfigs); return eglConfigs[fbConfigIndex]; } @@ -166,7 +166,7 @@ PalResult wlCreateWindow( return palMakeResult( PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_EGL, - s_Egl.eglGetError()); + s_VideoEgl.getError()); } } else { diff --git a/src/video/x11/pal_video_x11.c b/src/video/x11/pal_video_x11.c index 0969d19f..a8876e16 100644 --- a/src/video/x11/pal_video_x11.c +++ b/src/video/x11/pal_video_x11.c @@ -950,19 +950,19 @@ PalResult xInitVideo( } // load EGL - s_Egl.handle = dlopen("libEGL.so", RTLD_LAZY); - if (s_Egl.handle) { + s_VideoEgl.handle = dlopen("libEGL.so", RTLD_LAZY); + if (s_VideoEgl.handle) { eglGetProcAddressFn load = nullptr; - load = (eglGetProcAddressFn)dlsym(s_Egl.handle, "eglGetProcAddress"); - - s_Egl.eglInitialize = (eglInitializeFn)load("eglInitialize"); - s_Egl.eglTerminate = (eglTerminateFn)load("eglTerminate"); - s_Egl.eglGetDisplay = (eglGetDisplayFn)load("eglGetDisplay"); - s_Egl.eglChooseConfig = (eglChooseConfigFn)load("eglChooseConfig"); - s_Egl.eglGetError = (eglGetErrorFn)load("eglGetError"); - s_Egl.eglBindAPI = (eglBindAPIFn)load("eglBindAPI"); - s_Egl.eglGetConfigs = (eglGetConfigsFn)load("eglGetConfigs"); - s_Egl.eglGetConfigAttrib = (eglGetConfigAttribFn)load("eglGetConfigAttrib"); + load = (eglGetProcAddressFn)dlsym(s_VideoEgl.handle, "eglGetProcAddress"); + + s_VideoEgl.initialize = (eglInitializeFn)load("eglInitialize"); + s_VideoEgl.terminate = (eglTerminateFn)load("eglTerminate"); + s_VideoEgl.getDisplay = (eglGetDisplayFn)load("eglGetDisplay"); + s_VideoEgl.chooseConfig = (eglChooseConfigFn)load("eglChooseConfig"); + s_VideoEgl.getError = (eglGetErrorFn)load("eglGetError"); + s_VideoEgl.bindAPI = (eglBindAPIFn)load("eglBindAPI"); + s_VideoEgl.getConfigs = (eglGetConfigsFn)load("eglGetConfigs"); + s_VideoEgl.getConfigAttrib = (eglGetConfigAttribFn)load("eglGetConfigAttrib"); } createKeycodeTable(); @@ -998,8 +998,8 @@ void xShutdownVideo() palFree(s_X11.allocator, s_X11.windowData); palFree(s_X11.allocator, s_X11.monitorData); - if (s_Egl.handle) { - dlclose(s_Egl.handle); + if (s_VideoEgl.handle) { + dlclose(s_VideoEgl.handle); } if (s_X11.glxHandle) { diff --git a/src/video/x11/pal_window_x11.c b/src/video/x11/pal_window_x11.c index dc339195..c7664782 100644 --- a/src/video/x11/pal_window_x11.c +++ b/src/video/x11/pal_window_x11.c @@ -42,13 +42,13 @@ static XVisualInfo* glxBackend(const int fbConfigIndex) static XVisualInfo* eglXBackend(int fbConfigIndex) { EGLDisplay display = EGL_NO_DISPLAY; - display = s_Egl.eglGetDisplay((EGLNativeDisplayType)s_X11.display); + display = s_VideoEgl.getDisplay((EGLNativeDisplayType)s_X11.display); if (display == EGL_NO_DISPLAY) { return nullptr; } EGLint numConfigs = 0; - if (!s_Egl.eglGetConfigs(display, nullptr, 0, &numConfigs)) { + if (!s_VideoEgl.getConfigs(display, nullptr, 0, &numConfigs)) { return nullptr; } @@ -58,12 +58,12 @@ static XVisualInfo* eglXBackend(int fbConfigIndex) return nullptr; } - s_Egl.eglGetConfigs(display, eglConfigs, numConfigs, &numConfigs); + s_VideoEgl.getConfigs(display, eglConfigs, numConfigs, &numConfigs); EGLConfig config = eglConfigs[fbConfigIndex]; // we get a visual info from the config EGLint visualID; - s_Egl.eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualID); + s_VideoEgl.getConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visualID); if (visualID == 0) { return nullptr; } diff --git a/tests/opengl/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c index 6830e6d6..c75dd438 100644 --- a/tests/opengl/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -66,12 +66,26 @@ static void* PAL_CALL eventDriverWorker(void* arg) } // set dispatch modes. opengl needs only window resize - palSetEventDispatchMode(shared->openglEventDriver, PAL_EVENT_WINDOW_SIZE, PAL_DISPATCH_POLL); + palSetEventDispatchMode( + shared->openglEventDriver, + PAL_EVENT_TYPE_WINDOW_SIZE, + PAL_DISPATCH_MODE_POLL); // video needs window close and resize - palSetEventDispatchMode(shared->videoEventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(shared->videoEventDriver, PAL_EVENT_WINDOW_SIZE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(shared->videoEventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode( + shared->videoEventDriver, + PAL_EVENT_TYPE_WINDOW_CLOSE, + PAL_DISPATCH_MODE_POLL); + + palSetEventDispatchMode( + shared->videoEventDriver, + PAL_EVENT_TYPE_WINDOW_SIZE, + PAL_DISPATCH_MODE_POLL); + + palSetEventDispatchMode( + shared->videoEventDriver, + PAL_EVENT_TYPE_KEYDOWN, + PAL_DISPATCH_MODE_POLL); // we are done shared->driverCreated = PAL_TRUE; @@ -124,7 +138,7 @@ static void* PAL_CALL rendererWorkder(void* arg) PalEvent event; while (palPollEvent(shared->openglEventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_SIZE: { + case PAL_EVENT_TYPE_WINDOW_SIZE: { uint32_t width, height; palUnpackUint32(event.data, &width, &height); palLog(nullptr, "Video event driver sent a resize event (%d, %d)", width, height); @@ -298,9 +312,9 @@ PalBool multiThreadOpenGlTest() windowCreateInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } - // set the backend and the fbConfig. We use PAL_CONFIG_BACKEND_PAL_OPENGL + // set the backend and the fbConfig. We use PAL_FBCONFIG_BACKEND_PAL_OPENGL // because we are using both pal_video and pal_opengl - windowCreateInfo.fbConfigBackend = PAL_CONFIG_BACKEND_PAL_OPENGL; + windowCreateInfo.fbConfigBackend = PAL_FBCONFIG_BACKEND_PAL_OPENGL; windowCreateInfo.fbConfigIndex = closest->index; PalWindow* window = nullptr; @@ -321,7 +335,7 @@ PalBool multiThreadOpenGlTest() return PAL_FALSE; } - shared->window.display = winHandle.nativeDisplay; + shared->window.instance = winHandle.nativeInstance; // On Wayland the window is the wl_egl_window if (winHandle.nativeHandle3) { // the window has a valid wl_egl_window @@ -380,12 +394,12 @@ PalBool multiThreadOpenGlTest() PalEvent event; while (palPollEvent(shared->videoEventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { shared->running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -394,7 +408,7 @@ PalBool multiThreadOpenGlTest() break; } - case PAL_EVENT_WINDOW_SIZE: { + case PAL_EVENT_TYPE_WINDOW_SIZE: { // tell the opengl driver about our size change palPushEvent(shared->openglEventDriver, &event); break; diff --git a/tests/opengl/opengl_context_test.c b/tests/opengl/opengl_context_test.c index 72b8e0da..ccf95d4c 100644 --- a/tests/opengl/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -145,9 +145,9 @@ PalBool openglContextTest() createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } - // set the backend and the fbConfig. We use PAL_CONFIG_BACKEND_PAL_OPENGL + // set the backend and the fbConfig. We use PAL_FBCONFIG_BACKEND_PAL_OPENGL // because we are using both pal_video and pal_opengl - createInfo.fbConfigBackend = PAL_CONFIG_BACKEND_PAL_OPENGL; + createInfo.fbConfigBackend = PAL_FBCONFIG_BACKEND_PAL_OPENGL; createInfo.fbConfigIndex = closest->index; // create the window with the create info struct @@ -159,8 +159,8 @@ PalBool openglContextTest() } // we set window close to poll - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // get window handle. You can use any window from any library // so long as you can get the window handle and display (if on X11, wayland) @@ -174,7 +174,7 @@ PalBool openglContextTest() // PalGLWindow is just a struct to hold native handles PalGLWindow glWindow = {0}; - glWindow.display = winHandle.nativeDisplay; + glWindow.instance = winHandle.nativeInstance; // On Wayland the window is the wl_egl_window if (winHandle.nativeHandle3) { @@ -250,12 +250,12 @@ PalBool openglContextTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { diff --git a/tests/opengl/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c index 4faaba95..5e0361bd 100644 --- a/tests/opengl/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -145,9 +145,9 @@ PalBool openglMultiContextTest() createInfo.style |= PAL_WINDOW_STYLE_BORDERLESS; } - // set the backend and the fbConfig. We use PAL_CONFIG_BACKEND_PAL_OPENGL + // set the backend and the fbConfig. We use PAL_FBCONFIG_BACKEND_PAL_OPENGL // because we are using both pal_video and pal_opengl - createInfo.fbConfigBackend = PAL_CONFIG_BACKEND_PAL_OPENGL; + createInfo.fbConfigBackend = PAL_FBCONFIG_BACKEND_PAL_OPENGL; createInfo.fbConfigIndex = closest->index; // create the window with the create info struct @@ -159,8 +159,8 @@ PalBool openglMultiContextTest() } // we set window close to poll - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // get window handle. You can use any window from any library // so long as you can get the window handle and display (if on X11, wayland) @@ -174,7 +174,7 @@ PalBool openglMultiContextTest() // PalGLWindow is just a struct to hold native handles PalGLWindow glWindow = {0}; - glWindow.display = winHandle.nativeDisplay; + glWindow.instance = winHandle.nativeInstance; // On Wayland the window is the wl_egl_window if (winHandle.nativeHandle3) { @@ -250,12 +250,12 @@ PalBool openglMultiContextTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -304,12 +304,12 @@ PalBool openglMultiContextTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { diff --git a/tests/tests_main.c b/tests/tests_main.c index e8c73f51..aa8e7350 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -24,7 +24,7 @@ int main(int argc, char** argv) // registerTest(threadTest, "Thread Test"); // registerTest(tlsTest, "TLS Test"); // registerTest(mutexTest, "Mutex Test"); - registerTest(condvarTest, "Condvar Test"); + // registerTest(condvarTest, "Condvar Test"); #endif // PAL_HAS_THREAD_MODULE #if PAL_HAS_VIDEO_MODULE == 1 @@ -40,7 +40,7 @@ int main(int argc, char** argv) // registerTest(charEventTest, "Char Event Test"); // registerTest(nativeIntegrationTest, "Native Integration Test"); // registerTest(nativeInstanceTest, "Native Instance Test"); - registerTest(customDecorationTest, "Custom Decoration Test"); + // registerTest(customDecorationTest, "Custom Decoration Test"); #endif // PAL_HAS_VIDEO_MODULE // This test can run without video system so long as your have a valid window diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index 24cf9cd6..f276762d 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -840,9 +840,6 @@ static void PAL_CALL onEvent( PalBool customDecorationTest() { #ifdef __linux__ - palLog(nullptr, "Press Escape or click close button to close Test"); - palLog(nullptr, "This only implements close and window movement for simplicity"); - openDisplayWayland(); if (!s_Display) { // not on wayland @@ -850,6 +847,9 @@ PalBool customDecorationTest() return PAL_FALSE; } + palLog(nullptr, "Press Escape or click close button to close Test"); + palLog(nullptr, "This only implements close and window movement for simplicity"); + // fill the event driver create info PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator From eea3581babac1d8419a9f8f81d5c057d95a1a42c Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 29 Jun 2026 18:47:28 -0700 Subject: [PATCH 306/372] update systems and tests win32 --- CHANGELOG.md | 6 +- pal.lua | 4 +- .../pal_context_wgl.c} | 155 ++--- .../pal_opengl_win32.c => wgl/pal_wgl.c} | 169 ++--- .../pal_opengl_win32.h => wgl/pal_wgl.h} | 33 +- src/system/win32/pal_cpu_win32.c | 21 +- src/system/win32/pal_platform_win32.c | 14 +- src/thread/win32/pal_condvar_win32.c | 42 +- src/thread/win32/pal_mutex_win32.c | 15 +- src/thread/win32/pal_thread_win32.c | 120 ++-- src/video/pal_video.c | 2 + src/video/win32/pal_cursor_win32.c | 162 ++--- src/video/win32/pal_icon_win32.c | 67 +- src/video/win32/pal_monitor_win32.c | 192 ++---- src/video/win32/pal_video_win32.c | 470 +++++++------- src/video/win32/pal_video_win32.h | 3 +- src/video/win32/pal_window_win32.c | 587 ++++-------------- tests/tests_main.c | 6 +- 18 files changed, 674 insertions(+), 1394 deletions(-) rename src/opengl/{win32/pal_context_win32.c => wgl/pal_context_wgl.c} (59%) rename src/opengl/{win32/pal_opengl_win32.c => wgl/pal_wgl.c} (73%) rename src/opengl/{win32/pal_opengl_win32.h => wgl/pal_wgl.h} (85%) diff --git a/CHANGELOG.md b/CHANGELOG.md index da8e1f94..13820c5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,7 +58,7 @@ - Renamed platform api type constants from `PAL_PLATFORM_API_**` to `PAL_PLATFORM_API_TYPE_**`. - Renamed cursor type constants from `PAL_CURSOR_**` to `PAL_CURSOR_TYPE_**`. - Renamed flash flag constants from `PAL_FLASH_**` to `PAL_FLASH_FLAG_**`. -- Renamed fbConfig backend type constants from `PAL_CONFIG_BACKEND_**` to `PAL_FBCONFIG_BACKEND_**`. +- Renamed fbConfig backend type constants from `PAL_FBCONFIG_BACKEND_**` to `PAL_FBCONFIG_BACKEND_**`. - Renamed `PalFlashFlag` to `PalFlashFlags`. - `palInitGL()` now takes two additional parameters. - `palEnumerateGLFBConfigs()` no longer takes the `glWindow` parameter. @@ -73,7 +73,7 @@ - Removed `palGetRawMouseWheelDelta()` function. - Removed `palSetPreferredInstance()` function. - Removed `palSetFBConfig()` function. -- Removed `PAL_CONFIG_BACKEND_GLES`. +- Removed `PAL_FBCONFIG_BACKEND_GLES`. - `palGetWindowHandleInfo()` now returns `PalResult` and takes a pointer to the struct. - `PalGLInfo` now has `backend` and `api` fields. - Renamed `nativeDisplay` to `nativeInstance` in `PalWindowHandleInfo`. @@ -93,7 +93,7 @@ - **Video:** Added **palGetVideoFeaturesEx()** to check old and extended supported features. - **Video:** Added **palGetWindowHandleInfoEx()** to get extended window handles. - **Video:** Added **palGetRawMouseWheelDelta()** to get raw mouse wheel delta. -- **Video:** Added **PAL_CONFIG_BACKEND_GLES** to `PalFBConfigBackend` enum. +- **Video:** Added **PAL_FBCONFIG_BACKEND_GLES** to `PalFBConfigBackend` enum. - **Video:** Added **palSetPreferredInstance()** to set the native instance or display PAL video should use rather than creating a new one. - **Core:** Added **palPackFloat()** to combine two floats into a single int64_t integer. diff --git a/pal.lua b/pal.lua index 09099fe7..7a8d435d 100644 --- a/pal.lua +++ b/pal.lua @@ -167,8 +167,8 @@ project "PAL" filter {"system:windows", "configurations:*"} files { - "src/opengl/win32/pal_context_win32.c", - "src/opengl/win32/pal_opengl_win32.c" + "src/opengl/wgl/pal_context_wgl.c", + "src/opengl/wgl/pal_wgl.c" } filter {"system:linux", "configurations:*"} diff --git a/src/opengl/win32/pal_context_win32.c b/src/opengl/wgl/pal_context_wgl.c similarity index 59% rename from src/opengl/win32/pal_context_win32.c rename to src/opengl/wgl/pal_context_wgl.c index 9d813bef..866a318f 100644 --- a/src/opengl/win32/pal_context_win32.c +++ b/src/opengl/wgl/pal_context_wgl.c @@ -6,91 +6,58 @@ */ #ifdef _WIN32 -#include "pal_opengl_win32.h" -#include "pal_shared.h" +#include "pal_wgl.h" -PalResult PAL_CALL palCreateGLContext( +PalResult wglCreateGLContext( const PalGLContextCreateInfo* info, PalGLContext** outContext) { - if (!s_Wgl.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!info || !outContext || (info && (!info->window || !info->fbConfig))) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - // check support for requested features if (info->profile != PAL_GL_PROFILE_NONE) { if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_CONTEXT_PROFILE)) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } } if (info->forward) { if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_CREATE_CONTEXT)) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } } if (info->reset != PAL_GL_CONTEXT_RESET_NONE) { if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_ROBUSTNESS)) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } } if (info->noError) { if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_NO_ERROR)) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } } if (info->release != PAL_GL_RELEASE_BEHAVIOR_NONE) { if (!(s_Wgl.info.extensions & PAL_GL_EXTENSION_FLUSH_CONTROL)) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } } + // check version // clang-format off - // check version PalBool valid = info->major < s_Wgl.info.major || - (info->major == s_Wgl.info.major && info->minor <= s_Wgl.info.minor); + (info->major == s_Wgl.info.major && info->minor <= s_Wgl.info.minor); // clang-format on if (!valid) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } HDC hdc = GetDC((HWND)info->window->window); if (!hdc) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -98,8 +65,8 @@ PalResult PAL_CALL palCreateGLContext( // check if the provided pixel format is the same as the window if (s_Gdi.getPixelFormat(hdc) != info->fbConfig->index) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -109,7 +76,7 @@ PalResult PAL_CALL palCreateGLContext( } HGLRC context = nullptr; - if (s_Wgl.wglCreateContextAttribsARB) { + if (s_Wgl.createContextAttribsARB) { // create context with modern wgl functions int32_t attribs[40]; int32_t index = 0; @@ -180,42 +147,41 @@ PalResult PAL_CALL palCreateGLContext( } attribs[index++] = 0; - context = s_Wgl.wglCreateContextAttribsARB(hdc, share, attribs); + context = s_Wgl.createContextAttribsARB(hdc, share, attribs); if (!context) { DWORD error = GetLastError(); if (error == ERROR_INVALID_PROFILE_ARB) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } } else { // create context with legacy wgl functions - context = s_Wgl.wglCreateContext(hdc); + context = s_Wgl.createContext(hdc); if (!context) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } // share context if (share) { - if (!s_Wgl.wglShareLists(share, context)) { - s_Wgl.wglDeleteContext(context); + if (!s_Wgl.shareLists(share, context)) { + s_Wgl.deleteContext(context); ReleaseDC((HWND)info->window->window, hdc); - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } } @@ -226,90 +192,59 @@ PalResult PAL_CALL palCreateGLContext( return PAL_RESULT_SUCCESS; } -void PAL_CALL palDestroyGLContext(PalGLContext* context) +void wglDestroyGLContext(PalGLContext* context) { - if (!s_Wgl.initialized || !context) { - return; - } - s_Wgl.wglDeleteContext((HGLRC)context); + s_Wgl.deleteContext((HGLRC)context); } -PalResult PAL_CALL palMakeContextCurrent( +PalResult wglMakeContextCurrent( PalGLWindow* glWindow, PalGLContext* context) { - if (!s_Wgl.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if ((!glWindow && context) || (glWindow && !context)) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (context && glWindow) { // get hdc HDC hdc = GetDC((HWND)glWindow->window); if (!hdc) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } - if (!s_Wgl.wglMakeCurrent(hdc, (HGLRC)context)) { + if (!s_Wgl.makeCurrent(hdc, (HGLRC)context)) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } ReleaseDC((HWND)glWindow->window, hdc); } else if (!context && !glWindow) { - s_Wgl.wglMakeCurrent(nullptr, nullptr); + s_Wgl.makeCurrent(nullptr, nullptr); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palSwapBuffers( +PalResult wglSwapBuffers( PalGLWindow* glWindow, PalGLContext* context) { - if (!s_Wgl.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!context || !glWindow) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - // get hdc HDC hdc = GetDC((HWND)glWindow->window); if (!hdc) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -317,14 +252,14 @@ PalResult PAL_CALL palSwapBuffers( DWORD error = GetLastError(); if (error == ERROR_INVALID_PIXEL_FORMAT) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } diff --git a/src/opengl/win32/pal_opengl_win32.c b/src/opengl/wgl/pal_wgl.c similarity index 73% rename from src/opengl/win32/pal_opengl_win32.c rename to src/opengl/wgl/pal_wgl.c index 7400b1ed..e479ac8d 100644 --- a/src/opengl/win32/pal_opengl_win32.c +++ b/src/opengl/wgl/pal_wgl.c @@ -6,9 +6,8 @@ */ #ifdef _WIN32 -#include "pal_opengl_win32.h" +#include "pal_wgl.h" #include "opengl/pal_opengl_shared.h" -#include "pal_shared.h" #include #include @@ -16,34 +15,13 @@ Gdi s_Gdi = {0}; Wgl s_Wgl = {0}; static PalBool s_SupportedAPIs[2] = {0}; -PalResult PAL_CALL palInitGL( +PalResult wglInitGL( PalGLAPI api, void* instance, const PalAllocator* allocator) { - if (s_Wgl.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (!instance) { - palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (api != PAL_GL_API_OPENGL) { - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } // register class @@ -58,8 +36,8 @@ PalResult PAL_CALL palInitGL( // denied if (!RegisterClassExW(&wc)) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -80,8 +58,8 @@ PalResult PAL_CALL palInitGL( if (!s_Wgl.window) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -89,8 +67,8 @@ PalResult PAL_CALL palInitGL( s_Wgl.opengl = LoadLibraryA("opengl32.dll"); if (!s_Gdi.handle || !s_Wgl.opengl) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -117,23 +95,23 @@ PalResult PAL_CALL palInitGL( "SwapBuffers"); // load wgl function pointers - s_Wgl.wglGetProcAddress = (wglGetProcAddressFn)GetProcAddress( + s_Wgl.getProcAddress = (wglGetProcAddressFn)GetProcAddress( s_Wgl.opengl, "wglGetProcAddress"); - s_Wgl.wglCreateContext = (wglCreateContextFn)GetProcAddress( + s_Wgl.createContext = (wglCreateContextFn)GetProcAddress( s_Wgl.opengl, "wglCreateContext"); - s_Wgl.wglDeleteContext = (wglDeleteContextFn)GetProcAddress( + s_Wgl.deleteContext = (wglDeleteContextFn)GetProcAddress( s_Wgl.opengl, "wglDeleteContext"); - s_Wgl.wglMakeCurrent = (wglMakeCurrentFn)GetProcAddress( + s_Wgl.makeCurrent = (wglMakeCurrentFn)GetProcAddress( s_Wgl.opengl, "wglMakeCurrent"); - s_Wgl.wglShareLists = (wglShareListsFn)GetProcAddress( + s_Wgl.shareLists = (wglShareListsFn)GetProcAddress( s_Wgl.opengl, "wglShareLists"); @@ -141,22 +119,14 @@ PalResult PAL_CALL palInitGL( !s_Gdi.describePixelFormat || !s_Gdi.swapBuffers || !s_Gdi.setPixelFormat) { - - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_PLATFORM_FAILURE; } - if (!s_Wgl.wglGetProcAddress || - !s_Wgl.wglCreateContext || - !s_Wgl.wglDeleteContext || - !s_Wgl.wglMakeCurrent) { - - return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + if (!s_Wgl.getProcAddress || + !s_Wgl.createContext || + !s_Wgl.deleteContext || + !s_Wgl.makeCurrent) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; } // clang-format on @@ -174,33 +144,33 @@ PalResult PAL_CALL palInitGL( int32_t pixelFormat = s_Gdi.choosePixelFormat(s_Wgl.hdc, &pfd); s_Gdi.setPixelFormat(s_Wgl.hdc, pixelFormat, &pfd); - s_Wgl.context = s_Wgl.wglCreateContext(s_Wgl.hdc); + s_Wgl.context = s_Wgl.createContext(s_Wgl.hdc); - if (!s_Wgl.wglMakeCurrent(s_Wgl.hdc, s_Wgl.context)) { + if (!s_Wgl.makeCurrent(s_Wgl.hdc, s_Wgl.context)) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } // clang-format off // load wgl extension function pointers - s_Wgl.wglChoosePixelFormatARB = (wglChoosePixelFormatARBFn)s_Wgl.wglGetProcAddress( + s_Wgl.choosePixelFormatARB = (wglChoosePixelFormatARBFn)s_Wgl.getProcAddress( "wglChoosePixelFormatARB"); - s_Wgl.wglGetPixelFormatAttribivARB = (wglGetPixelFormatAttribivARBFn)s_Wgl.wglGetProcAddress( + s_Wgl.getPixelFormatAttribivARB = (wglGetPixelFormatAttribivARBFn)s_Wgl.getProcAddress( "wglGetPixelFormatAttribivARB"); - s_Wgl.wglCreateContextAttribsARB = (wglCreateContextAttribsARBFn)s_Wgl.wglGetProcAddress( + s_Wgl.createContextAttribsARB = (wglCreateContextAttribsARBFn)s_Wgl.getProcAddress( "wglCreateContextAttribsARB"); - s_Wgl.wglSwapIntervalEXT = (wglSwapIntervalEXTFn)s_Wgl.wglGetProcAddress( + s_Wgl.swapIntervalEXT = (wglSwapIntervalEXTFn)s_Wgl.getProcAddress( "wglSwapIntervalEXT"); - s_Wgl.wglGetExtensionsStringARB = (wglGetExtensionsStringARBFn)s_Wgl.wglGetProcAddress( + s_Wgl.getExtensionsStringARB = (wglGetExtensionsStringARBFn)s_Wgl.getProcAddress( "wglGetExtensionsStringARB"); - s_Wgl.wglGetExtensionsStringEXT = (wglGetExtensionsStringEXTFn)s_Wgl.wglGetProcAddress( + s_Wgl.getExtensionsStringEXT = (wglGetExtensionsStringEXTFn)s_Wgl.getProcAddress( "wglGetExtensionsStringEXT"); // load gl functions @@ -226,11 +196,11 @@ PalResult PAL_CALL palInitGL( // check available extensions const char* extensions = nullptr; - if (s_Wgl.wglGetExtensionsStringARB) { - extensions = s_Wgl.wglGetExtensionsStringARB(s_Wgl.hdc); + if (s_Wgl.getExtensionsStringARB) { + extensions = s_Wgl.getExtensionsStringARB(s_Wgl.hdc); - } else if (s_Wgl.wglGetExtensionsStringEXT) { - extensions = s_Wgl.wglGetExtensionsStringEXT(); + } else if (s_Wgl.getExtensionsStringEXT) { + extensions = s_Wgl.getExtensionsStringEXT(); } if (extensions) { @@ -305,18 +275,13 @@ PalResult PAL_CALL palInitGL( s_Wgl.info.api = PAL_GL_API_OPENGL; s_Wgl.info.backend = PAL_GL_BACKEND_WGL; - s_Wgl.initialized = PAL_TRUE; return PAL_RESULT_SUCCESS; } -void PAL_CALL palShutdownGL() +void wglShutdownGL() { - if (!s_Wgl.initialized) { - return; - } - - s_Wgl.wglMakeCurrent(s_Wgl.hdc, nullptr); - s_Wgl.wglDeleteContext(s_Wgl.context); + s_Wgl.makeCurrent(s_Wgl.hdc, nullptr); + s_Wgl.deleteContext(s_Wgl.context); ReleaseDC(s_Wgl.window, s_Wgl.hdc); DestroyWindow(s_Wgl.window); UnregisterClassW(PAL_GL_CLASS, s_Wgl.instance); @@ -325,35 +290,17 @@ void PAL_CALL palShutdownGL() FreeLibrary(s_Gdi.handle); memset(&s_Wgl, 0, sizeof(Wgl)); - s_Wgl.initialized = PAL_FALSE; } -const PalGLInfo* PAL_CALL palGetGLInfo() +const PalGLInfo* wglGetGLInfo() { - if (!s_Wgl.initialized) { - return nullptr; - } return &s_Wgl.info; } -PalResult PAL_CALL palEnumerateGLFBConfigs( +PalResult wglEnumerateGLFBConfigs( int32_t* count, PalGLFBConfig* configs) { - if (!s_Wgl.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!count || *count == 0 && configs) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - int32_t configCount = 0; int32_t maxConfigCount = 0; int32_t nativeCount = 0; @@ -364,12 +311,12 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( } // check if we support modern extention - if (s_Wgl.wglGetPixelFormatAttribivARB) { + if (s_Wgl.getPixelFormatAttribivARB) { // get framebuffer config with extensions - if (!s_Wgl.wglGetPixelFormatAttribivARB(s_Wgl.hdc, 0, 0, 1, &configAttrib, &nativeCount)) { + if (!s_Wgl.getPixelFormatAttribivARB(s_Wgl.hdc, 0, 0, 1, &configAttrib, &nativeCount)) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -392,7 +339,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( int32_t values[sizeof(attributes) / sizeof(attributes[0])]; for (int32_t i = 1; i <= nativeCount; i++) { - if (!s_Wgl.wglGetPixelFormatAttribivARB( + if (!s_Wgl.getPixelFormatAttribivARB( s_Wgl.hdc, i, 0, @@ -496,40 +443,26 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( return PAL_RESULT_SUCCESS; } -void* PAL_CALL palGetGLProcAddress(const char* name) +void* wglGetGLProcAddress(const char* name) { - if (!s_Wgl.initialized) { - return nullptr; - } - - void* proc = s_Wgl.wglGetProcAddress(name); + void* proc = s_Wgl.getProcAddress(name); if (!proc) { proc = (void*)GetProcAddress(s_Wgl.opengl, name); } return proc; } -PalResult PAL_CALL palSetSwapInterval(int32_t interval) +PalResult wglSetSwapInterval(int32_t interval) { - if (!s_Wgl.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!s_Wgl.wglSwapIntervalEXT) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + if (!s_Wgl.swapIntervalEXT) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } - s_Wgl.wglSwapIntervalEXT(interval); + s_Wgl.swapIntervalEXT(interval); return PAL_RESULT_SUCCESS; } -const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance) +const PalBool* wglGetSupportedGLAPIs(void* instance) { if (!instance) { return nullptr; diff --git a/src/opengl/win32/pal_opengl_win32.h b/src/opengl/wgl/pal_wgl.h similarity index 85% rename from src/opengl/win32/pal_opengl_win32.h rename to src/opengl/wgl/pal_wgl.h index fdfff139..5e7a297e 100644 --- a/src/opengl/win32/pal_opengl_win32.h +++ b/src/opengl/wgl/pal_wgl.h @@ -5,10 +5,10 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#ifndef _PAL_OPENGL_WIN32_H -#define _PAL_OPENGL_WIN32_H -#ifdef _WIN32 +#ifndef _PAL_WGL_H +#define _PAL_WGL_H +#ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif // WIN32_LEAN_AND_MEAN @@ -36,7 +36,6 @@ #endif // GL_VENDOR #ifndef WGL_NUMBER_PIXEL_FORMATS_ARB - #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 #define WGL_ACCELERATION_ARB 0x2003 #define WGL_RED_BITS_ARB 0x2015 @@ -74,7 +73,6 @@ #define WGL_CONTEXT_FLAGS_ARB 0x2094 #define ERROR_INVALID_PROFILE_ARB 0x2096 - #endif // WGL_NUMBER_PIXEL_FORMATS_ARB typedef unsigned int GLenum; @@ -156,20 +154,19 @@ typedef struct { } Gdi; typedef struct { - PalBool initialized; - wglGetProcAddressFn wglGetProcAddress; - wglCreateContextFn wglCreateContext; - wglDeleteContextFn wglDeleteContext; - wglMakeCurrentFn wglMakeCurrent; - wglShareListsFn wglShareLists; + wglGetProcAddressFn getProcAddress; + wglCreateContextFn createContext; + wglDeleteContextFn deleteContext; + wglMakeCurrentFn makeCurrent; + wglShareListsFn shareLists; glGetStringFn glGetString; - wglCreateContextAttribsARBFn wglCreateContextAttribsARB; - wglChoosePixelFormatARBFn wglChoosePixelFormatARB; - wglSwapIntervalEXTFn wglSwapIntervalEXT; - wglGetExtensionsStringEXTFn wglGetExtensionsStringEXT; - wglGetExtensionsStringARBFn wglGetExtensionsStringARB; - wglGetPixelFormatAttribivARBFn wglGetPixelFormatAttribivARB; + wglCreateContextAttribsARBFn createContextAttribsARB; + wglChoosePixelFormatARBFn choosePixelFormatARB; + wglSwapIntervalEXTFn swapIntervalEXT; + wglGetExtensionsStringEXTFn getExtensionsStringEXT; + wglGetExtensionsStringARBFn getExtensionsStringARB; + wglGetPixelFormatAttribivARBFn getPixelFormatAttribivARB; const PalAllocator* allocator; HINSTANCE opengl; @@ -184,4 +181,4 @@ extern Gdi s_Gdi; extern Wgl s_Wgl; #endif // _WIN32 -#endif // _PAL_OPENGL_WIN32_H \ No newline at end of file +#endif // _PAL_WGL_H \ No newline at end of file diff --git a/src/system/win32/pal_cpu_win32.c b/src/system/win32/pal_cpu_win32.c index 5ae30d4a..2690e979 100644 --- a/src/system/win32/pal_cpu_win32.c +++ b/src/system/win32/pal_cpu_win32.c @@ -20,7 +20,6 @@ #endif // UNICODE #include "pal/pal_system.h" -#include "pal_shared.h" #include #include @@ -48,18 +47,12 @@ PalResult PAL_CALL palGetCPUInfo( PalCPUInfo* info) { if (!info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } // check invalid allocator if (allocator && (!allocator->allocate || !allocator->free)) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } memset(info, 0, sizeof(PalCPUInfo)); @@ -118,22 +111,18 @@ PalResult PAL_CALL palGetCPUInfo( // get cpu info DWORD len = 0; GetLogicalProcessorInformationEx(RelationAll, nullptr, &len); - SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* buffer = nullptr; buffer = palAllocate(allocator, len, 16); if (!buffer) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } BOOL ret = GetLogicalProcessorInformationEx(RelationAll, buffer, &len); if (!ret) { palFree(allocator, buffer); return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/system/win32/pal_platform_win32.c b/src/system/win32/pal_platform_win32.c index 8f1f0c5a..57d4b6c8 100644 --- a/src/system/win32/pal_platform_win32.c +++ b/src/system/win32/pal_platform_win32.c @@ -20,7 +20,6 @@ #endif // UNICODE #include "pal/pal_system.h" -#include "pal_shared.h" #include #include @@ -74,20 +73,17 @@ static inline PalBool isVersionWin32( PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) { if (!info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } - info->apiType = PAL_PLATFORM_API_WIN32; - info->type = PAL_PLATFORM_WINDOWS; + info->apiType = PAL_PLATFORM_API_TYPE_WIN32; + info->type = PAL_PLATFORM_TYPE_WINDOWS; // get windows build, version and combine them if (!getVersionWin32(&info->version)) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/thread/win32/pal_condvar_win32.c b/src/thread/win32/pal_condvar_win32.c index 11009abc..87258492 100644 --- a/src/thread/win32/pal_condvar_win32.c +++ b/src/thread/win32/pal_condvar_win32.c @@ -7,34 +7,24 @@ #ifdef _WIN32 #include "pal_thread_win32.h" -#include "pal_shared.h" PalResult PAL_CALL palCreateCondVar( const PalAllocator* allocator, PalCondVar** outCondVar) { if (!outCondVar) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (allocator) { if (!allocator->allocate && !allocator->free) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } } PalCondVar* condVar = palAllocate(allocator, sizeof(PalCondVar), 0); if (!condVar) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } InitializeConditionVariable(&condVar->cv); @@ -55,10 +45,7 @@ PalResult PAL_CALL palWaitCondVar( PalMutex* mutex) { if (!condVar || !mutex) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } BOOL ret = SleepConditionVariableCS(&condVar->cv, &mutex->sc, INFINITE); @@ -66,14 +53,14 @@ PalResult PAL_CALL palWaitCondVar( DWORD error = GetLastError(); if (error == ERROR_TIMEOUT) { return palMakeResult( - PAL_RESULT_TIMEOUT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_TIMEOUT, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -86,10 +73,7 @@ PalResult PAL_CALL palWaitCondVarTimeout( uint64_t milliseconds) { if (!condVar || !mutex) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } BOOL ret = SleepConditionVariableCS(&condVar->cv, &mutex->sc, (DWORD)milliseconds); @@ -97,14 +81,14 @@ PalResult PAL_CALL palWaitCondVarTimeout( DWORD error = GetLastError(); if (error == ERROR_TIMEOUT) { return palMakeResult( - PAL_RESULT_TIMEOUT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_TIMEOUT, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } diff --git a/src/thread/win32/pal_mutex_win32.c b/src/thread/win32/pal_mutex_win32.c index c1432f46..61050a77 100644 --- a/src/thread/win32/pal_mutex_win32.c +++ b/src/thread/win32/pal_mutex_win32.c @@ -7,33 +7,26 @@ #ifdef _WIN32 #include "pal_thread_win32.h" -#include "pal_shared.h" PalResult PAL_CALL palCreateMutex( const PalAllocator* allocator, PalMutex** outMutex) { if (!outMutex) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (allocator) { if (!allocator->allocate && !allocator->free) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } } PalMutex* mutex = palAllocate(allocator, sizeof(PalMutex), 0); if (!mutex) { return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/thread/win32/pal_thread_win32.c b/src/thread/win32/pal_thread_win32.c index b1dd8a0b..e344e1fe 100644 --- a/src/thread/win32/pal_thread_win32.c +++ b/src/thread/win32/pal_thread_win32.c @@ -7,7 +7,6 @@ #ifdef _WIN32 #include "pal_thread_win32.h" -#include "pal_shared.h" typedef HRESULT(WINAPI* SetThreadDescriptionFn)( HANDLE, @@ -36,28 +35,19 @@ PalResult PAL_CALL palCreateThread( PalThread** outThread) { if (!info || !outThread) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (info->allocator) { if (!info->allocator->allocate && !info->allocator->free) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } } // create thread ThreadData* data = palAllocate(info->allocator, sizeof(ThreadData), 0); if (!data) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } data->arg = info->arg; @@ -70,26 +60,26 @@ PalResult PAL_CALL palCreateThread( DWORD error = GetLastError(); if (error == ERROR_NOT_ENOUGH_MEMORY) { return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WIN32, error); } else if (error == ERROR_INVALID_PARAMETER) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, error); } else if (error == ERROR_ACCESS_DENIED) { return palMakeResult( - PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_OPERATION, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -103,10 +93,7 @@ PalResult PAL_CALL palJoinThread( void** retval) { if (!thread) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } DWORD wait = WaitForSingleObject((HANDLE)thread, INFINITE); @@ -121,8 +108,8 @@ PalResult PAL_CALL palJoinThread( } else if (wait == WAIT_FAILED) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -216,10 +203,7 @@ PalResult PAL_CALL palGetThreadName( char* outBuffer) { if (!thread) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); @@ -231,19 +215,15 @@ PalResult PAL_CALL palGetThreadName( if (!getThreadDescription) { // not supported - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } wchar_t* buffer = nullptr; HRESULT hr = getThreadDescription((HANDLE)thread, &buffer); - if (!SUCCEEDED(hr)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, hr); } @@ -268,10 +248,7 @@ PalResult PAL_CALL palSetThreadPriority( PalThreadPriority priority) { if (!thread) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } int _priority = 0; @@ -293,20 +270,20 @@ PalResult PAL_CALL palSetThreadPriority( DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else if (error == ERROR_ACCESS_DENIED) { return palMakeResult( - PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_OPERATION, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -319,30 +296,21 @@ PalResult PAL_CALL palSetThreadAffinity( uint64_t mask) { if (!thread) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (!SetThreadAffinityMask((HANDLE)thread, mask)) { DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, - error); - - } else if (error == ERROR_INVALID_PARAMETER) { + if (error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_PARAMETER) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -355,10 +323,7 @@ PalResult PAL_CALL palSetThreadName( const char* name) { if (!thread || !name) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); @@ -370,10 +335,7 @@ PalResult PAL_CALL palSetThreadName( if (!setThreadDescription) { // not supported - return palMakeResult( - PAL_RESULT_FEATURE_NOT_SUPPORTED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } wchar_t buffer[128] = {0}; @@ -386,26 +348,26 @@ PalResult PAL_CALL palSetThreadName( } else { if (hr == E_INVALIDARG) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, hr); } else if (hr == E_OUTOFMEMORY) { return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_OUT_OF_MEMORY, + PAL_RESULT_SOURCE_WIN32, hr); } else if (hr == E_ACCESSDENIED) { return palMakeResult( - PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_OPERATION, + PAL_RESULT_SOURCE_WIN32, hr); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, hr); } } diff --git a/src/video/pal_video.c b/src/video/pal_video.c index 7774858e..1eeffc0c 100644 --- a/src/video/pal_video.c +++ b/src/video/pal_video.c @@ -208,6 +208,8 @@ PalResult PAL_CALL palEnumerateMonitorModes( // sort the modes so that they are highest to lowest qsort(modes, *count, sizeof(PalMonitorMode), compareModes); } + + return result; } PalResult PAL_CALL palGetCurrentMonitorMode( diff --git a/src/video/win32/pal_cursor_win32.c b/src/video/win32/pal_cursor_win32.c index a402be5b..e11f3dd4 100644 --- a/src/video/win32/pal_cursor_win32.c +++ b/src/video/win32/pal_cursor_win32.c @@ -7,26 +7,11 @@ #ifdef _WIN32 #include "pal_video_win32.h" -#include "pal_shared.h" -PalResult PAL_CALL palCreateCursor( +PalResult win32CreateCursor( const PalCursorCreateInfo* info, PalCursor** outCursor) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!info || !outCursor) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - // describe the icon pixels BITMAPV5HEADER bitInfo = {0}; bitInfo.bV5Size = sizeof(BITMAPV5HEADER); @@ -46,16 +31,21 @@ PalResult PAL_CALL palCreateCursor( void* dibPixels = nullptr; // create dib section - HBITMAP bitmap = nullptr; - bitmap = - s_Video - .createDIBSection(hdc, (BITMAPINFO*)&bitInfo, DIB_RGB_COLORS, &dibPixels, nullptr, 0); + // clang-format off + HBITMAP bitmap = s_Win32.createDIBSection( + hdc, + (BITMAPINFO*)&bitInfo, + DIB_RGB_COLORS, + &dibPixels, + nullptr, + 0); + // clang-format on if (!bitmap) { ReleaseDC(nullptr, hdc); return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } ReleaseDC(nullptr, hdc); @@ -93,59 +83,45 @@ PalResult PAL_CALL palCreateCursor( // create the cursor with the iconinfo HCURSOR cursor = CreateIconIndirect(&iconInfo); if (!cursor) { - s_Video.deleteObject(bitmap); + s_Win32.deleteObject(bitmap); return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } - s_Video.deleteObject(bitmap); + s_Win32.deleteObject(bitmap); *outCursor = (PalCursor*)cursor; return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palCreateCursorFrom( +PalResult win32CreateCursorFrom( PalCursorType type, PalCursor** outCursor) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!outCursor) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - HCURSOR cursor = nullptr; switch (type) { - case PAL_CURSOR_ARROW: { + case PAL_CURSOR_TYPE_ARROW: { cursor = LoadCursorW(nullptr, IDC_ARROW); break; } - case PAL_CURSOR_HAND: { + case PAL_CURSOR_TYPE_HAND: { cursor = LoadCursorW(nullptr, IDC_HAND); break; } - case PAL_CURSOR_CROSS: { + case PAL_CURSOR_TYPE_CROSS: { cursor = LoadCursorW(nullptr, IDC_CROSS); break; } - case PAL_CURSOR_IBEAM: { + case PAL_CURSOR_TYPE_IBEAM: { cursor = LoadCursorW(nullptr, IDC_IBEAM); break; } - case PAL_CURSOR_WAIT: { + case PAL_CURSOR_TYPE_WAIT: { cursor = LoadCursorW(nullptr, IDC_WAIT); break; } @@ -153,8 +129,8 @@ PalResult PAL_CALL palCreateCursorFrom( if (!cursor) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -162,44 +138,26 @@ PalResult PAL_CALL palCreateCursorFrom( return PAL_RESULT_SUCCESS; } -void PAL_CALL palDestroyCursor(PalCursor* cursor) +void win32DestroyCursor(PalCursor* cursor) { - if (s_Video.initialized && cursor) { - DestroyCursor((HCURSOR)cursor); - } + DestroyCursor((HCURSOR)cursor); } -void PAL_CALL palShowCursor(PalBool show) +void win32ShowCursor(PalBool show) { - if (s_Video.initialized) { - ShowCursor(show); - } + ShowCursor(show); } -PalResult PAL_CALL palClipCursor( +PalResult win32ClipCursor( PalWindow* window, PalBool clip) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (clip) { RECT rect; if (!GetClientRect((HWND)window, &rect)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -219,25 +177,11 @@ PalResult PAL_CALL palClipCursor( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetCursorPos( +PalResult win32GetCursorPos( PalWindow* window, int32_t* x, int32_t* y) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - POINT pos; GetCursorPos(&pos); if (ScreenToClient((HWND)window, &pos)) { @@ -253,36 +197,22 @@ PalResult PAL_CALL palGetCursorPos( } else { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } } -PalResult PAL_CALL palSetCursorPos( +PalResult win32SetCursorPos( PalWindow* window, int32_t x, int32_t y) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - POINT pos = {x, y}; if (!ClientToScreen((HWND)window, &pos)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -290,7 +220,7 @@ PalResult PAL_CALL palSetCursorPos( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palSetWindowCursor( +PalResult win32SetWindowCursor( PalWindow* window, PalCursor* cursor) { @@ -299,8 +229,8 @@ PalResult PAL_CALL palSetWindowCursor( WindowData* data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); if (!data) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -311,21 +241,21 @@ PalResult PAL_CALL palSetWindowCursor( } else if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } else { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } } diff --git a/src/video/win32/pal_icon_win32.c b/src/video/win32/pal_icon_win32.c index 742befaa..8f06a14e 100644 --- a/src/video/win32/pal_icon_win32.c +++ b/src/video/win32/pal_icon_win32.c @@ -7,26 +7,11 @@ #ifdef _WIN32 #include "pal_video_win32.h" -#include "pal_shared.h" -PalResult PAL_CALL palCreateIcon( +PalResult win32CreateIcon( const PalIconCreateInfo* info, PalIcon** outIcon) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!info || !outIcon) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - // describe the icon pixels BITMAPV5HEADER bitInfo = {0}; bitInfo.bV5Size = sizeof(BITMAPV5HEADER); @@ -46,14 +31,21 @@ PalResult PAL_CALL palCreateIcon( void* dibPixels = nullptr; // create dib section - HBITMAP bitmap = nullptr; - bitmap = s_Video.createDIBSection(hdc, (BITMAPINFO*)&bitInfo, DIB_RGB_COLORS, &dibPixels, nullptr, 0); + // clang-format off + HBITMAP bitmap = s_Win32.createDIBSection( + hdc, + (BITMAPINFO*)&bitInfo, + DIB_RGB_COLORS, + &dibPixels, + nullptr, + 0); + // clang-format on if (!bitmap) { ReleaseDC(nullptr, hdc); return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } ReleaseDC(nullptr, hdc); @@ -89,48 +81,29 @@ PalResult PAL_CALL palCreateIcon( // create the icon with the icon info HICON icon = CreateIconIndirect(&iconInfo); if (!icon) { - s_Video.deleteObject(bitmap); + s_Win32.deleteObject(bitmap); return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } - s_Video.deleteObject(bitmap); + s_Win32.deleteObject(bitmap); *outIcon = (PalIcon*)icon; return PAL_RESULT_SUCCESS; } -void PAL_CALL palDestroyIcon(PalIcon* icon) +void win32DestroyIcon(PalIcon* icon) { - if (s_Video.initialized && icon) { - DestroyIcon((HICON)icon); - } + DestroyIcon((HICON)icon); } -PalResult PAL_CALL palSetWindowIcon( +PalResult win32SetWindowIcon( PalWindow* window, PalIcon* icon) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (!IsWindow((HWND)window)) { - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_HANDLE; } SendMessageW((HWND)window, WM_SETICON, ICON_BIG, (LPARAM)icon); diff --git a/src/video/win32/pal_monitor_win32.c b/src/video/win32/pal_monitor_win32.c index 3459fe28..c1cc995f 100644 --- a/src/video/win32/pal_monitor_win32.c +++ b/src/video/win32/pal_monitor_win32.c @@ -7,7 +7,6 @@ #ifdef _WIN32 #include "pal_video_win32.h" -#include "pal_shared.h" #define MONITOR_DPI 0 #define MAX_MODE_COUNT 128 @@ -77,27 +76,20 @@ static inline PalResult setMonitorMode( PalMonitorMode* mode, PalBool test) { - if (!monitor || !mode) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - MONITORINFOEXW mi = {0}; mi.cbSize = sizeof(MONITORINFOEXW); if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -125,8 +117,8 @@ static inline PalResult setMonitorMode( } else { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } } @@ -162,24 +154,10 @@ static inline void addMonitorMode( *count += 1; } -PalResult PAL_CALL palEnumerateMonitors( +PalResult win32EnumerateMonitors( int32_t* count, PalMonitor** outMonitors) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!count || *count == 0 && outMonitors) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - MonitorData data; data.count = 0; data.monitors = outMonitors; @@ -192,28 +170,14 @@ PalResult PAL_CALL palEnumerateMonitors( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) +PalResult win32GetPrimaryMonitor(PalMonitor** outMonitor) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!outMonitor) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - HMONITOR monitor = nullptr; monitor = MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); if (!monitor) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -221,38 +185,24 @@ PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetMonitorInfo( +PalResult win32GetMonitorInfo( PalMonitor* monitor, PalMonitorInfo* info) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!monitor || !info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - MONITORINFOEXW mi = {0}; mi.cbSize = sizeof(MONITORINFOEXW); if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -273,8 +223,8 @@ PalResult PAL_CALL palGetMonitorInfo( // get dpi scale UINT dpiX, dpiY; - if (s_Video.getDpiForMonitor) { - s_Video.getDpiForMonitor((HMONITOR)monitor, MONITOR_DPI, &dpiX, &dpiY); + if (s_Win32.getDpiForMonitor) { + s_Win32.getDpiForMonitor((HMONITOR)monitor, MONITOR_DPI, &dpiX, &dpiY); } else { dpiX = 96; @@ -295,25 +245,11 @@ PalResult PAL_CALL palGetMonitorInfo( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palEnumerateMonitorModes( +PalResult win32EnumerateMonitorModes( PalMonitor* monitor, int32_t* count, PalMonitorMode* modes) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!monitor || !count || *count == 0 && modes) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - int32_t modeCount = 0; int32_t maxModes = 0; PalMonitorMode* monitorModes = nullptr; @@ -324,14 +260,14 @@ PalResult PAL_CALL palEnumerateMonitorModes( DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -339,12 +275,9 @@ PalResult PAL_CALL palEnumerateMonitorModes( if (!modes) { // allocate and store tmp monitor modesand check for the interested // fields. - monitorModes = palAllocate(s_Video.allocator, sizeof(PalMonitorMode) * MAX_MODE_COUNT, 0); + monitorModes = palAllocate(s_Win32.allocator, sizeof(PalMonitorMode) * MAX_MODE_COUNT, 0); if (!monitorModes) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } memset(monitorModes, 0, sizeof(PalMonitorMode) * MAX_MODE_COUNT); @@ -373,44 +306,30 @@ PalResult PAL_CALL palEnumerateMonitorModes( if (!modes) { *count = modeCount; - palFree(s_Video.allocator, monitorModes); + palFree(s_Win32.allocator, monitorModes); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetCurrentMonitorMode( +PalResult win32GetCurrentMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!monitor || !mode) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - MONITORINFOEXW mi = {0}; mi.cbSize = sizeof(MONITORINFOEXW); if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -426,58 +345,27 @@ PalResult PAL_CALL palGetCurrentMonitorMode( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palSetMonitorMode( +PalResult win32SetMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - return setMonitorMode(monitor, mode, PAL_FALSE); } -PalResult PAL_CALL palValidateMonitorMode( +PalResult win32ValidateMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - return setMonitorMode(monitor, mode, PAL_TRUE); } -PalResult PAL_CALL palSetMonitorOrientation( +PalResult win32SetMonitorOrientation( PalMonitor* monitor, PalOrientation orientation) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!monitor) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - DWORD win32Orientation = orientationToin32(orientation); if (orientation == NULL_ORIENTATION) { - return palMakeResult( - PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_OPERATION; } MONITORINFOEXW mi = {0}; @@ -486,14 +374,14 @@ PalResult PAL_CALL palSetMonitorOrientation( DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -527,8 +415,8 @@ PalResult PAL_CALL palSetMonitorOrientation( } else { return palMakeResult( - PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_OPERATION, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } } diff --git a/src/video/win32/pal_video_win32.c b/src/video/win32/pal_video_win32.c index cdc522fe..da55aa9c 100644 --- a/src/video/win32/pal_video_win32.c +++ b/src/video/win32/pal_video_win32.c @@ -7,7 +7,6 @@ #ifdef _WIN32 #include "pal_video_win32.h" -#include "pal_shared.h" #include #define PROCESS_DPI_AWARE 2 @@ -34,7 +33,7 @@ typedef struct { } Keyboard; typedef struct { - PalBool push; + PalBool pushMouseDelta; int32_t dx; int32_t dy; int32_t WheelX; @@ -42,11 +41,11 @@ typedef struct { PalBool state[PAL_MOUSE_BUTTON_COUNT]; } Mouse; -static PendingEvent s_Event; +static PendingEvent s_Event = {0}; static BYTE s_RawBuffer[4096] = {0}; static Mouse s_Mouse = {0}; static Keyboard s_Keyboard = {0}; -VideoWin32 s_Video = {0}; +VideoWin32 s_Win32 = {0}; LRESULT CALLBACK videoProc( HWND hwnd, @@ -61,15 +60,15 @@ LRESULT CALLBACK videoProc( return DefWindowProcW(hwnd, msg, wParam, lParam); } - PalDispatchMode mode = PAL_DISPATCH_NONE; + PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; switch (msg) { case WM_CLOSE: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_CLOSE); - if (mode != PAL_DISPATCH_NONE) { + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_WINDOW_CLOSE); + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_CLOSE; + event.type = PAL_EVENT_TYPE_WINDOW_CLOSE; event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); } @@ -78,20 +77,20 @@ LRESULT CALLBACK videoProc( } case WM_SIZE: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_SIZE); + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_WINDOW_SIZE); uint32_t width = (uint32_t)LOWORD(lParam); uint32_t height = (uint32_t)HIWORD(lParam); - if (mode == PAL_DISPATCH_CALLBACK) { + if (mode == PAL_DISPATCH_MODE_CALLBACK) { PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_SIZE; + event.type = PAL_EVENT_TYPE_WINDOW_SIZE; event.data = palPackUint32(width, height); event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); - } else if (mode == PAL_DISPATCH_POLL) { + } else if (mode == PAL_DISPATCH_MODE_POLL) { s_Event.pendingResize = PAL_TRUE; s_Event.width = width; s_Event.height = height; @@ -99,9 +98,9 @@ LRESULT CALLBACK videoProc( } // trigger state event - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_STATE); + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_WINDOW_STATE); PalWindowState state = PAL_WINDOW_STATE_RESTORED; - if (mode == PAL_DISPATCH_NONE) { + if (mode == PAL_DISPATCH_MODE_NONE) { return 0; } @@ -122,14 +121,14 @@ LRESULT CALLBACK videoProc( return 0; } - if (mode == PAL_DISPATCH_CALLBACK) { + if (mode == PAL_DISPATCH_MODE_CALLBACK) { PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_STATE; + event.type = PAL_EVENT_TYPE_WINDOW_STATE; event.data = state; event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); - } else if (mode == PAL_DISPATCH_POLL) { + } else if (mode == PAL_DISPATCH_MODE_POLL) { s_Event.pendingState = PAL_TRUE; s_Event.state = state; } @@ -140,15 +139,15 @@ LRESULT CALLBACK videoProc( } case WM_MOVE: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_MOVE); + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_WINDOW_MOVE); int32_t x = GET_X_LPARAM(lParam); int32_t y = GET_Y_LPARAM(lParam); - if (mode == PAL_DISPATCH_CALLBACK) { + if (mode == PAL_DISPATCH_MODE_CALLBACK) { PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_MOVE; + event.type = PAL_EVENT_TYPE_WINDOW_MOVE; event.data = palPackInt32(x, y); event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); @@ -165,11 +164,11 @@ LRESULT CALLBACK videoProc( } case WM_SHOWWINDOW: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_VISIBILITY; + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + PalEventType type = PAL_EVENT_TYPE_WINDOW_VISIBILITY; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = (PalBool)wParam; @@ -181,12 +180,12 @@ LRESULT CALLBACK videoProc( } case WM_SETFOCUS: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_FOCUS); - if (mode != PAL_DISPATCH_NONE) { + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_WINDOW_FOCUS); + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_FOCUS; + event.type = PAL_EVENT_TYPE_WINDOW_FOCUS; event.data = PAL_TRUE; event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); @@ -196,12 +195,12 @@ LRESULT CALLBACK videoProc( } case WM_KILLFOCUS: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_WINDOW_FOCUS); - if (mode != PAL_DISPATCH_NONE) { + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_WINDOW_FOCUS); + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_FOCUS; + event.type = PAL_EVENT_TYPE_WINDOW_FOCUS; event.data = PAL_FALSE; event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); @@ -211,12 +210,12 @@ LRESULT CALLBACK videoProc( } case WM_ENTERSIZEMOVE: { - s_Mouse.push = PAL_FALSE; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_MODAL_BEGIN; + s_Mouse.pushMouseDelta = PAL_FALSE; + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + PalEventType type = PAL_EVENT_TYPE_WINDOW_MODAL_BEGIN; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data2 = palPackPointer((PalWindow*)hwnd); @@ -227,12 +226,12 @@ LRESULT CALLBACK videoProc( } case WM_EXITSIZEMOVE: { - s_Mouse.push = PAL_TRUE; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_WINDOW_MODAL_END; + s_Mouse.pushMouseDelta = PAL_TRUE; + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + PalEventType type = PAL_EVENT_TYPE_WINDOW_MODAL_END; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data2 = palPackPointer((PalWindow*)hwnd); @@ -243,11 +242,11 @@ LRESULT CALLBACK videoProc( } case WM_DPICHANGED: { - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MONITOR_DPI_CHANGED; + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + PalEventType type = PAL_EVENT_TYPE_MONITOR_DPI_CHANGED; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = HIWORD(wParam); @@ -264,11 +263,11 @@ LRESULT CALLBACK videoProc( return 0; } - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MONITOR_LIST_CHANGED; + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + PalEventType type = PAL_EVENT_TYPE_MONITOR_LIST_CHANGED; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data2 = palPackPointer((PalWindow*)hwnd); @@ -282,12 +281,12 @@ LRESULT CALLBACK videoProc( int32_t delta = GET_WHEEL_DELTA_WPARAM(wParam); s_Mouse.WheelX = delta / WHEEL_DELTA; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_WHEEL); - if (mode != PAL_DISPATCH_NONE) { + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_MOUSE_WHEEL); + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; - event.type = PAL_EVENT_MOUSE_WHEEL; + event.type = PAL_EVENT_TYPE_MOUSE_WHEEL; event.data = palPackFloat(s_Mouse.WheelX, 0); event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); @@ -300,12 +299,12 @@ LRESULT CALLBACK videoProc( int32_t delta = GET_WHEEL_DELTA_WPARAM(wParam); s_Mouse.WheelY = delta / WHEEL_DELTA; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_WHEEL); - if (mode != PAL_DISPATCH_NONE) { + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_MOUSE_WHEEL); + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; - event.type = PAL_EVENT_MOUSE_WHEEL; + event.type = PAL_EVENT_TYPE_MOUSE_WHEEL; event.data = palPackFloat(0, s_Mouse.WheelY); event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); @@ -318,12 +317,12 @@ LRESULT CALLBACK videoProc( const int32_t x = GET_X_LPARAM(lParam); const int32_t y = GET_Y_LPARAM(lParam); - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_MOUSE_MOVE); - if (mode != PAL_DISPATCH_NONE) { + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_MOUSE_MOVE); + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; - event.type = PAL_EVENT_MOUSE_MOVE; + event.type = PAL_EVENT_TYPE_MOUSE_MOVE; event.data = palPackInt32(x, y); event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); @@ -348,18 +347,18 @@ LRESULT CALLBACK videoProc( RAWINPUT* raw = (RAWINPUT*)s_RawBuffer; RAWMOUSE* mouse = &raw->data.mouse; // push only if we are not rresizing or moving with the mouse - if (s_Mouse.push && (mouse->lLastX || mouse->lLastY)) { + if (s_Mouse.pushMouseDelta && (mouse->lLastX || mouse->lLastY)) { s_Mouse.dx += mouse->lLastX; s_Mouse.dy += mouse->lLastY; float dx = (float)s_Mouse.dx; float dy = (float)s_Mouse.dy; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - PalEventType type = PAL_EVENT_MOUSE_DELTA; + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + PalEventType type = PAL_EVENT_TYPE_MOUSE_DELTA; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackFloat(dx, dy); @@ -409,11 +408,11 @@ LRESULT CALLBACK videoProc( msg == WM_MBUTTONDOWN || msg == WM_XBUTTONDOWN) { pressed = PAL_TRUE; - type = PAL_EVENT_MOUSE_BUTTONDOWN; + type = PAL_EVENT_TYPE_MOUSE_BUTTONDOWN; } else { pressed = PAL_FALSE; - type = PAL_EVENT_MOUSE_BUTTONUP; + type = PAL_EVENT_TYPE_MOUSE_BUTTONUP; } // clang-format on @@ -426,10 +425,10 @@ LRESULT CALLBACK videoProc( } s_Mouse.state[button] = pressed; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackUint32(button, NULL_BUTTON_SERIAL); @@ -479,13 +478,13 @@ LRESULT CALLBACK videoProc( if (win32Keycode == VK_SNAPSHOT) { // printscreen since the platform does not get us a keydown, we // do that ourselves - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; - mode = palGetEventDispatchMode(driver, PAL_EVENT_KEYDOWN); + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; + mode = palGetEventDispatchMode(driver, PAL_EVENT_TYPE_KEYDOWN); keycode = PAL_KEYCODE_PRINTSCREEN; - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; - event.type = PAL_EVENT_KEYDOWN; + event.type = PAL_EVENT_TYPE_KEYDOWN; event.data = palPackUint32(keycode, scancode); event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); @@ -500,21 +499,21 @@ LRESULT CALLBACK videoProc( s_Keyboard.keycodeState[keycode] = PAL_TRUE; s_Keyboard.scancodeState[scancode] = PAL_TRUE; - type = PAL_EVENT_KEYDOWN; + type = PAL_EVENT_TYPE_KEYDOWN; if (repeat) { - type = PAL_EVENT_KEYREPEAT; + type = PAL_EVENT_TYPE_KEYREPEAT; } } else { s_Keyboard.keycodeState[keycode] = PAL_FALSE; s_Keyboard.scancodeState[scancode] = PAL_FALSE; - type = PAL_EVENT_KEYUP; + type = PAL_EVENT_TYPE_KEYUP; } - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; mode = palGetEventDispatchMode(driver, type); - if (mode != PAL_DISPATCH_NONE) { + if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = type; event.data = palPackUint32(keycode, scancode); @@ -535,7 +534,7 @@ LRESULT CALLBACK videoProc( SetCursor(data->cursor); } else { // no cursor, use default - SetCursor(s_Video.defaultCursor); + SetCursor(s_Win32.defaultCursor); } return PAL_TRUE; } @@ -543,12 +542,12 @@ LRESULT CALLBACK videoProc( } case WM_CHAR: { - PalEventType type = PAL_EVENT_KEYCHAR; + PalEventType type = PAL_EVENT_TYPE_KEYCHAR; uint32_t codepoint = 0; - if (s_Video.eventDriver) { - PalEventDriver* driver = s_Video.eventDriver; + if (s_Win32.eventDriver) { + PalEventDriver* driver = s_Win32.eventDriver; mode = palGetEventDispatchMode(driver, type); - if (mode == PAL_DISPATCH_NONE) { + if (mode == PAL_DISPATCH_MODE_NONE) { break; } } @@ -577,7 +576,7 @@ LRESULT CALLBACK videoProc( event.type = type; event.data = codepoint; event.data2 = palPackPointer((PalWindow*)hwnd); - palPushEvent(s_Video.eventDriver, &event); + palPushEvent(s_Win32.eventDriver, &event); } } @@ -759,56 +758,44 @@ static void createScancodeTable() s_Keyboard.scancodes[0x15C] = PAL_SCANCODE_RSUPER; } -PalResult PAL_CALL palInitVideo( +PalResult win32InitVideo( const PalAllocator* allocator, PalEventDriver* eventDriver, void* preferredInstance) { - if (s_Video.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - s_Video.maxWindowData = 32; - s_Video.windowData = - palAllocate(s_Video.allocator, sizeof(WindowData) * s_Video.maxWindowData, 0); + s_Win32.maxWindowData = 32; + s_Win32.windowData = palAllocate(s_Win32.allocator, sizeof(WindowData) * s_Win32.maxWindowData, 0); // user provided instance if (preferredInstance) { - s_Video.instance = preferredInstance; + s_Win32.instance = preferredInstance; } else { - s_Video.instance = GetModuleHandleW(nullptr); + s_Win32.instance = GetModuleHandleW(nullptr); } // load default cursor - s_Video.defaultCursor = LoadCursorW(NULL, IDC_ARROW); + s_Win32.defaultCursor = LoadCursorW(NULL, IDC_ARROW); // register class WNDCLASSEXW wc = {0}; wc.cbSize = sizeof(WNDCLASSEXW); - wc.hCursor = s_Video.defaultCursor; + wc.hCursor = s_Win32.defaultCursor; wc.hIcon = LoadIconW(NULL, IDI_APPLICATION); wc.hIconSm = LoadIconW(NULL, IDI_APPLICATION); - wc.hInstance = s_Video.instance; + wc.hInstance = s_Win32.instance; wc.lpfnWndProc = videoProc; wc.lpszClassName = PAL_VIDEO_CLASS; wc.style = CS_OWNDC; if (!RegisterClassExW(&wc)) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } // create hidden window - s_Video.hiddenWindow = CreateWindowExW( + s_Win32.hiddenWindow = CreateWindowExW( 0, PAL_VIDEO_CLASS, L"HiddenWindow", @@ -819,29 +806,29 @@ PalResult PAL_CALL palInitVideo( 8, nullptr, nullptr, - s_Video.instance, + s_Win32.instance, nullptr); - if (!s_Video.hiddenWindow) { + if (!s_Win32.hiddenWindow) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } // set a flag to check if the window has been created - SetPropW(s_Video.hiddenWindow, PAL_VIDEO_PROP, &s_Event); + SetPropW(s_Win32.hiddenWindow, PAL_VIDEO_PROP, &s_Event); // register raw input for mice to get delta RAWINPUTDEVICE rid = {0}; rid.dwFlags = RIDEV_INPUTSINK; - rid.hwndTarget = s_Video.hiddenWindow; + rid.hwndTarget = s_Win32.hiddenWindow; rid.usUsage = 0x02; rid.usUsagePage = 0x01; if (!RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE))) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -851,123 +838,114 @@ PalResult PAL_CALL palInitVideo( // load shared libraries // shcore - s_Video.shcore = LoadLibraryA("shcore.dll"); - if (s_Video.shcore) { - s_Video.getDpiForMonitor = - (GetDpiForMonitorFn)GetProcAddress(s_Video.shcore, "GetDpiForMonitor"); + s_Win32.shcore = LoadLibraryA("shcore.dll"); + if (s_Win32.shcore) { + s_Win32.getDpiForMonitor = + (GetDpiForMonitorFn)GetProcAddress(s_Win32.shcore, "GetDpiForMonitor"); - s_Video.setProcessAwareness = - (SetProcessAwarenessFn)GetProcAddress(s_Video.shcore, "SetProcessDpiAwareness"); + s_Win32.setProcessAwareness = + (SetProcessAwarenessFn)GetProcAddress(s_Win32.shcore, "SetProcessDpiAwareness"); } // clang-format off // gdi functios - s_Video.gdi = LoadLibraryA("gdi32.dll"); - if (s_Video.gdi) { - s_Video.createDIBSection = (CreateDIBSectionFn)GetProcAddress( - s_Video.gdi, + s_Win32.gdi = LoadLibraryA("gdi32.dll"); + if (s_Win32.gdi) { + s_Win32.createDIBSection = (CreateDIBSectionFn)GetProcAddress( + s_Win32.gdi, "CreateDIBSection"); - s_Video.createBitmap = (CreateBitmapFn)GetProcAddress( - s_Video.gdi, + s_Win32.createBitmap = (CreateBitmapFn)GetProcAddress( + s_Win32.gdi, "CreateBitmap"); - s_Video.deleteObject = (DeleteObjectFn)GetProcAddress( - s_Video.gdi, + s_Win32.deleteObject = (DeleteObjectFn)GetProcAddress( + s_Win32.gdi, "DeleteObject"); - s_Video.describePixelFormat = (DescribePixelFormatFn)GetProcAddress( - s_Video.gdi, + s_Win32.describePixelFormat = (DescribePixelFormatFn)GetProcAddress( + s_Win32.gdi, "DescribePixelFormat"); - s_Video.setPixelFormat = (SetPixelFormatFn)GetProcAddress( - s_Video.gdi, + s_Win32.setPixelFormat = (SetPixelFormatFn)GetProcAddress( + s_Win32.gdi, "SetPixelFormat"); } // clang-format on // set features - s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION; - s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; - s_Video.features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; - s_Video.features |= PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW; - s_Video.features |= PAL_VIDEO_FEATURE_TOOL_WINDOW; - s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_SET_MODE; - s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; - s_Video.features |= PAL_VIDEO_FEATURE_MULTI_MONITORS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_SIZE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_POS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_POS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_STATE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_TITLE; - s_Video.features |= PAL_VIDEO_FEATURE_NO_MAXIMIZEBOX; - s_Video.features |= PAL_VIDEO_FEATURE_NO_MINIMIZEBOX; - s_Video.features |= PAL_VIDEO_FEATURE_CLIP_CURSOR; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_INTERVAL; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_STYLE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_STYLE; - s_Video.features |= PAL_VIDEO_FEATURE_CURSOR_SET_POS; - s_Video.features |= PAL_VIDEO_FEATURE_CURSOR_GET_POS; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_ICON; - - s_Video.features |= PAL_VIDEO_FEATURE_TOPMOST_WINDOW; - s_Video.features |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; - s_Video.features |= PAL_VIDEO_FEATURE_CURSOR_SET_VISIBILITY; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_GET_MONITOR; - s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY; - s_Video.features |= PAL_VIDEO_FEATURE_FOREIGN_WINDOWS; - s_Video.features |= PAL_VIDEO_FEATURE_MONITOR_VALIDATE_MODE; - s_Video.features |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; - - if (s_Video.getDpiForMonitor && s_Video.setProcessAwareness) { - s_Video.features |= PAL_VIDEO_FEATURE_HIGH_DPI; - s_Video.setProcessAwareness(PROCESS_DPI_AWARE); + s_Win32.features |= PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION; + s_Win32.features |= PAL_VIDEO_FEATURE_MONITOR_GET_ORIENTATION; + s_Win32.features |= PAL_VIDEO_FEATURE_BORDERLESS_WINDOW; + s_Win32.features |= PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW; + s_Win32.features |= PAL_VIDEO_FEATURE_TOOL_WINDOW; + s_Win32.features |= PAL_VIDEO_FEATURE_MONITOR_SET_MODE; + s_Win32.features |= PAL_VIDEO_FEATURE_MONITOR_GET_MODE; + s_Win32.features |= PAL_VIDEO_FEATURE_MULTI_MONITORS; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_SET_SIZE; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_GET_SIZE; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_SET_POS; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_GET_POS; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_SET_STATE; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_GET_STATE; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_SET_TITLE; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_GET_TITLE; + s_Win32.features |= PAL_VIDEO_FEATURE_NO_MAXIMIZEBOX; + s_Win32.features |= PAL_VIDEO_FEATURE_NO_MINIMIZEBOX; + s_Win32.features |= PAL_VIDEO_FEATURE_CLIP_CURSOR; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_TRAY; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_FLASH_INTERVAL; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_SET_STYLE; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_GET_STYLE; + s_Win32.features |= PAL_VIDEO_FEATURE_CURSOR_SET_POS; + s_Win32.features |= PAL_VIDEO_FEATURE_CURSOR_GET_POS; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_SET_ICON; + + s_Win32.features |= PAL_VIDEO_FEATURE_TOPMOST_WINDOW; + s_Win32.features |= PAL_VIDEO_FEATURE_DECORATED_WINDOW; + s_Win32.features |= PAL_VIDEO_FEATURE_CURSOR_SET_VISIBILITY; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_GET_MONITOR; + s_Win32.features |= PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY; + s_Win32.features |= PAL_VIDEO_FEATURE_FOREIGN_WINDOWS; + s_Win32.features |= PAL_VIDEO_FEATURE_MONITOR_VALIDATE_MODE; + s_Win32.features |= PAL_VIDEO_FEATURE_WINDOW_SET_CURSOR; + + if (s_Win32.getDpiForMonitor && s_Win32.setProcessAwareness) { + s_Win32.features |= PAL_VIDEO_FEATURE_HIGH_DPI; + s_Win32.setProcessAwareness(PROCESS_DPI_AWARE); } - s_Video.initialized = PAL_TRUE; - s_Video.allocator = allocator; - s_Video.eventDriver = eventDriver; + s_Win32.allocator = allocator; + s_Win32.eventDriver = eventDriver; + s_Mouse.pushMouseDelta = PAL_TRUE; return PAL_RESULT_SUCCESS; } -void PAL_CALL palShutdownVideo() +void win32ShutdownVideo() { - if (!s_Video.initialized) { - return; - } - - if (s_Video.shcore) { - FreeLibrary(s_Video.shcore); + if (s_Win32.shcore) { + FreeLibrary(s_Win32.shcore); } - FreeLibrary(s_Video.gdi); - DestroyWindow(s_Video.hiddenWindow); - UnregisterClassW(PAL_VIDEO_CLASS, s_Video.instance); - palFree(s_Video.allocator, s_Video.windowData); + FreeLibrary(s_Win32.gdi); + DestroyWindow(s_Win32.hiddenWindow); + UnregisterClassW(PAL_VIDEO_CLASS, s_Win32.instance); + palFree(s_Win32.allocator, s_Win32.windowData); - memset(&s_Video, 0, sizeof(VideoWin32)); + memset(&s_Win32, 0, sizeof(VideoWin32)); memset(&s_Keyboard, 0, sizeof(Keyboard)); memset(&s_Mouse, 0, sizeof(Mouse)); - s_Video.windowData = nullptr; - s_Video.initialized = PAL_FALSE; + s_Win32.windowData = nullptr; } -void PAL_CALL palUpdateVideo() +void win32UpdateVideo() { - if (!s_Video.initialized) { - return; - } - s_Mouse.dx = 0; s_Mouse.dy = 0; @@ -980,17 +958,17 @@ void PAL_CALL palUpdateVideo() // push pending move and reszie events if (s_Event.pendingResize) { PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_SIZE; + event.type = PAL_EVENT_TYPE_WINDOW_SIZE; event.data = palPackUint32(s_Event.width, s_Event.height); event.data2 = palPackPointer(s_Event.window); - palPushEvent(s_Video.eventDriver, &event); + palPushEvent(s_Win32.eventDriver, &event); if (s_Event.pendingState) { PalEvent event = {0}; event.data = s_Event.state; event.data2 = palPackPointer(s_Event.window); - event.type = PAL_EVENT_WINDOW_STATE; - palPushEvent(s_Video.eventDriver, &event); + event.type = PAL_EVENT_TYPE_WINDOW_STATE; + palPushEvent(s_Win32.eventDriver, &event); s_Event.pendingState = PAL_FALSE; } @@ -998,21 +976,63 @@ void PAL_CALL palUpdateVideo() } else if (s_Event.pendingMove) { PalEvent event = {0}; - event.type = PAL_EVENT_WINDOW_MOVE; + event.type = PAL_EVENT_TYPE_WINDOW_MOVE; event.data = palPackInt32(s_Event.x, s_Event.y); event.data2 = palPackPointer(s_Event.window); - palPushEvent(s_Video.eventDriver, &event); + palPushEvent(s_Win32.eventDriver, &event); s_Event.pendingMove = PAL_FALSE; } } -void* PAL_CALL palGetInstance() +PalVideoFeatures win32GetVideoFeatures() +{ + return s_Win32.features; +} + +const PalBool* win32GetKeycodeState() +{ + return s_Keyboard.keycodeState; +} + +const PalBool* win32GetScancodeState() +{ + return s_Keyboard.scancodeState; +} + +const PalBool* win32GetMouseState() +{ + return s_Mouse.state; +} + +void win32GetMouseDelta( + float* dx, + float* dy) +{ + if (dx) { + *dx = (float)s_Mouse.dx; + } + + if (dy) { + *dy = (float)s_Mouse.dy; + } +} + +void win32GetMouseWheelDelta( + float* dx, + float* dy) { - if (!s_Video.initialized) { - return nullptr; + if (dx) { + *dx = (float)s_Mouse.WheelX; } - return (void*)s_Video.instance; + if (dy) { + *dy = (float)s_Mouse.WheelY; + } +} + +void* win32GetInstance() +{ + return (void*)s_Win32.instance; } #endif // _WIN32 \ No newline at end of file diff --git a/src/video/win32/pal_video_win32.h b/src/video/win32/pal_video_win32.h index 890457aa..3f3aa980 100644 --- a/src/video/win32/pal_video_win32.h +++ b/src/video/win32/pal_video_win32.h @@ -80,7 +80,6 @@ typedef struct { } WindowData; typedef struct { - PalBool initialized; int32_t maxWindowData; PalVideoFeatures features; const PalAllocator* allocator; @@ -102,7 +101,7 @@ typedef struct { WindowData* windowData; } VideoWin32; -extern VideoWin32 s_Video; +extern VideoWin32 s_Win32; #endif // _WIN32 #endif // _PAL_VIDEO_WIN32_H \ No newline at end of file diff --git a/src/video/win32/pal_window_win32.c b/src/video/win32/pal_window_win32.c index 1aac7cfb..e926c96f 100644 --- a/src/video/win32/pal_window_win32.c +++ b/src/video/win32/pal_window_win32.c @@ -7,14 +7,13 @@ #ifdef _WIN32 #include "pal_video_win32.h" -#include "pal_shared.h" static WindowData* getFreeWindowData() { - for (int i = 0; i < s_Video.maxWindowData; ++i) { - if (!s_Video.windowData[i].used) { - s_Video.windowData[i].used = PAL_TRUE; - return &s_Video.windowData[i]; + for (int i = 0; i < s_Win32.maxWindowData; ++i) { + if (!s_Win32.windowData[i].used) { + s_Win32.windowData[i].used = PAL_TRUE; + return &s_Win32.windowData[i]; } } @@ -22,46 +21,29 @@ static WindowData* getFreeWindowData() // It is rare for a user to create and manage // 32 windows at the same time WindowData* data = nullptr; - int count = s_Video.maxWindowData * 2; // double the size - int freeIndex = s_Video.maxWindowData + 1; - data = palAllocate(s_Video.allocator, sizeof(WindowData) * count, 0); + int count = s_Win32.maxWindowData * 2; // double the size + int freeIndex = s_Win32.maxWindowData + 1; + data = palAllocate(s_Win32.allocator, sizeof(WindowData) * count, 0); if (data) { - memcpy(data, s_Video.windowData, s_Video.maxWindowData * sizeof(WindowData)); + memcpy(data, s_Win32.windowData, s_Win32.maxWindowData * sizeof(WindowData)); - palFree(s_Video.allocator, s_Video.windowData); - s_Video.windowData = data; - s_Video.maxWindowData = count; + palFree(s_Win32.allocator, s_Win32.windowData); + s_Win32.windowData = data; + s_Win32.maxWindowData = count; - s_Video.windowData[freeIndex].used = PAL_TRUE; - return &s_Video.windowData[freeIndex]; + s_Win32.windowData[freeIndex].used = PAL_TRUE; + return &s_Win32.windowData[freeIndex]; } return nullptr; } -PalResult PAL_CALL palCreateWindow( +PalResult win32CreateWindow( const PalWindowCreateInfo* info, PalWindow** outWindow) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!info || !outWindow) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - WindowData* data = getFreeWindowData(); if (!data) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } HWND handle = nullptr; @@ -114,8 +96,8 @@ PalResult PAL_CALL palCreateWindow( monitor = (PalMonitor*)MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); if (!monitor) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } } @@ -160,24 +142,24 @@ PalResult PAL_CALL palCreateWindow( rect.bottom - rect.top, nullptr, nullptr, - s_Video.instance, + s_Win32.instance, nullptr); if (!handle) { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } // set the pixel format is set if (info->fbConfigIndex) { // clang-format off - if (info->fbConfigBackend == PAL_CONFIG_BACKEND_EGL || - info->fbConfigBackend == PAL_CONFIG_BACKEND_GLX) { + if (info->fbConfigBackend == PAL_FBCONFIG_BACKEND_EGL || + info->fbConfigBackend == PAL_FBCONFIG_BACKEND_GLX) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } // clang-format on @@ -187,31 +169,31 @@ PalResult PAL_CALL palCreateWindow( // we ask the OS (platform) to fill the pfd struct for us from that // index PIXELFORMATDESCRIPTOR pfd; - if (!s_Video.describePixelFormat( + if (!s_Win32.describePixelFormat( hdc, info->fbConfigIndex, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } - s_Video.setPixelFormat(hdc, info->fbConfigIndex, &pfd); + s_Win32.setPixelFormat(hdc, info->fbConfigIndex, &pfd); ReleaseDC(handle, hdc); } // show, maximize and minimize int32_t showFlag = SW_HIDE; // maximize - if (info->maximized) { + if (info->state == PAL_WINDOW_STATE_MAXIMIZED) { showFlag = SW_MAXIMIZE; data->state = PAL_WINDOW_STATE_MAXIMIZED; } // minimized - if (info->minimized) { + if (info->state == PAL_WINDOW_STATE_MINIMIZED) { showFlag = SW_MINIMIZE; data->state = PAL_WINDOW_STATE_MINIMIZED; } @@ -252,172 +234,86 @@ PalResult PAL_CALL palCreateWindow( return PAL_RESULT_SUCCESS; } -void PAL_CALL palDestroyWindow(PalWindow* window) +void win32DestroyWindow(PalWindow* window) { - if (s_Video.initialized && window) { - WindowData* data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); - // destroy only PAL created window - if (data->isAttached) { - return; - } - - DestroyWindow((HWND)window); - data->used = PAL_FALSE; + WindowData* data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); + // destroy only PAL created window + if (data->isAttached) { + return; } + + DestroyWindow((HWND)window); + data->used = PAL_FALSE; } -PalResult PAL_CALL palMinimizeWindow(PalWindow* window) +PalResult win32MinimizeWindow(PalWindow* window) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (!ShowWindow((HWND)window, SW_MINIMIZE)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palMaximizeWindow(PalWindow* window) +PalResult win32MaximizeWindow(PalWindow* window) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (!ShowWindow((HWND)window, SW_MAXIMIZE)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palRestoreWindow(PalWindow* window) +PalResult win32RestoreWindow(PalWindow* window) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (!ShowWindow((HWND)window, SW_RESTORE)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palShowWindow(PalWindow* window) +PalResult win32ShowWindow(PalWindow* window) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (!ShowWindow((HWND)window, SW_SHOW)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palHideWindow(PalWindow* window) +PalResult win32HideWindow(PalWindow* window) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (!ShowWindow((HWND)window, SW_HIDE)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palFlashWindow( +PalResult win32FlashWindow( PalWindow* window, const PalFlashInfo* info) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window || !info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - DWORD flags = 0; - if (info->flags == PAL_FLASH_STOP) { + if (info->flags == PAL_FLASH_FLAG_STOP) { flags = FLASHW_STOP; } else { - if (info->flags & PAL_FLASH_CAPTION) { + if (info->flags & PAL_FLASH_FLAG_CAPTION) { flags |= FLASHW_CAPTION; } - if (info->flags & PAL_FLASH_TRAY) { + if (info->flags & PAL_FLASH_FLAG_TRAY) { flags |= FLASHW_TRAY; flags |= FLASHW_TIMERNOFG; } @@ -435,14 +331,14 @@ PalResult PAL_CALL palFlashWindow( DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -450,32 +346,18 @@ PalResult PAL_CALL palFlashWindow( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetWindowStyle( +PalResult win32GetWindowStyle( PalWindow* window, PalWindowStyle* outStyle) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window || !outStyle) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - PalWindowStyle windowStyle = 0; DWORD style = (DWORD)GetWindowLongPtrW((HWND)window, GWL_STYLE); DWORD exStyle = (DWORD)GetWindowLongPtrW((HWND)window, GWL_EXSTYLE); if (!style) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -522,38 +404,24 @@ PalResult PAL_CALL palGetWindowStyle( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetWindowMonitor( +PalResult win32GetWindowMonitor( PalWindow* window, PalMonitor** outMonitor) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window || !outMonitor) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - HMONITOR monitor = nullptr; monitor = MonitorFromWindow((HWND)window, MONITOR_DEFAULTTONEAREST); if (!monitor) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -562,31 +430,17 @@ PalResult PAL_CALL palGetWindowMonitor( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetWindowTitle( +PalResult win32GetWindowTitle( PalWindow* window, uint64_t bufferSize, uint64_t* outSize, char* outBuffer) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window || !outBuffer) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - wchar_t buffer[WINDOW_NAME_SIZE]; if (GetWindowTextW((HWND)window, buffer, WINDOW_NAME_SIZE) == 0) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -605,30 +459,16 @@ PalResult PAL_CALL palGetWindowTitle( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetWindowPos( +PalResult win32GetWindowPos( PalWindow* window, int32_t* x, int32_t* y) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - RECT rect; if (!GetWindowRect((HWND)window, &rect)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -642,30 +482,16 @@ PalResult PAL_CALL palGetWindowPos( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetWindowSize( +PalResult win32GetWindowSize( PalWindow* window, uint32_t* width, uint32_t* height) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - RECT rect; if (!GetWindowRect((HWND)window, &rect)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -679,29 +505,15 @@ PalResult PAL_CALL palGetWindowSize( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetWindowState( +PalResult win32GetWindowState( PalWindow* window, PalWindowState* outState) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window || !outState) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - WINDOWPLACEMENT wp = {0}; if (!GetWindowPlacement((HWND)window, &wp)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -718,42 +530,21 @@ PalResult PAL_CALL palGetWindowState( return PAL_RESULT_SUCCESS; } -PalBool PAL_CALL palIsWindowVisible(PalWindow* window) +PalBool win32IsWindowVisible(PalWindow* window) { - if (!s_Video.initialized || !window) { - return PAL_FALSE; - } - return IsWindowVisible((HWND)window); } -PalWindow* PAL_CALL palGetFocusWindow() +PalWindow* win32GetFocusWindow() { - if (!s_Video.initialized) { - return nullptr; - } return (PalWindow*)GetFocus(); } -PalResult PAL_CALL palGetWindowHandleInfo( +PalResult win32GetWindowHandleInfo( PalWindow* window, PalWindowHandleInfo* info) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window || !info) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - info->nativeDisplay = (void*)s_Video.instance; + info->nativeInstance = (void*)s_Win32.instance; info->nativeWindow = (void*)window; info->nativeHandle1 = nullptr; info->nativeHandle2 = nullptr; @@ -762,24 +553,10 @@ PalResult PAL_CALL palGetWindowHandleInfo( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palSetWindowOpacity( +PalResult win32SetWindowOpacity( PalWindow* window, float opacity) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (opacity < 0.0f) { opacity = 0.0f; } @@ -793,20 +570,20 @@ PalResult PAL_CALL palSetWindowOpacity( DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else if (error == ERROR_INVALID_PARAMETER) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -814,24 +591,10 @@ PalResult PAL_CALL palSetWindowOpacity( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palSetWindowStyle( +PalResult win32SetWindowStyle( PalWindow* window, PalWindowStyle style) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - // convert our style to win32 styles and exStyles // all windows have this styles DWORD win32Style = WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED; @@ -895,109 +658,73 @@ PalResult PAL_CALL palSetWindowStyle( DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } } -PalResult PAL_CALL palSetWindowTitle( +PalResult win32SetWindowTitle( PalWindow* window, const char* title) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window || !title) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - wchar_t buffer[WINDOW_NAME_SIZE]; MultiByteToWideChar(CP_UTF8, 0, title, -1, buffer, 256); if (!SetWindowTextW((HWND)window, buffer)) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palSetWindowPos( +PalResult win32SetWindowPos( PalWindow* window, int32_t x, int32_t y) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - PalBool success = - SetWindowPos((HWND)window, nullptr, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); + PalBool success = SetWindowPos( + (HWND)window, + nullptr, + x, + y, + 0, + 0, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); if (!success) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palSetWindowSize( +PalResult win32SetWindowSize( PalWindow* window, uint32_t width, uint32_t height) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - PalBool success = SetWindowPos( (HWND)window, HWND_TOP, @@ -1011,90 +738,59 @@ PalResult PAL_CALL palSetWindowSize( DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else if (error == ERROR_INVALID_PARAMETER) { return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palSetFocusWindow(PalWindow* window) +PalResult win32SetFocusWindow(PalWindow* window) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - if (!SetActiveWindow((HWND)window)) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, error); } else if (error == ERROR_ACCESS_DENIED) { return palMakeResult( - PAL_RESULT_INVALID_OPERATION, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_OPERATION, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palAttachWindow( +PalResult win32AttachWindow( void* windowHandle, PalWindow** outWindow) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!windowHandle || !outWindow) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - WindowData* data = getFreeWindowData(); if (!data) { - return palMakeResult( - PAL_RESULT_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_OUT_OF_MEMORY; } PalWindow* window = (PalWindow*)windowHandle; @@ -1113,39 +809,22 @@ PalResult PAL_CALL palAttachWindow( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palDetachWindow( +PalResult win32DetachWindow( PalWindow* window, void** outWindowHandle) { - if (!s_Video.initialized) { - return palMakeResult( - PAL_RESULT_NOT_INITIALIZED, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - - if (!window) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); - } - WindowData* data = nullptr; data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); if (!data) { return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } if (data->isAttached == PAL_FALSE) { // window is owned by PAL - return palMakeResult( - PAL_RESULT_INVALID_HANDLE, - PAL_RESULT_SOURCE_WINDOWS, - GetLastError()); + return PAL_RESULT_CODE_INVALID_HANDLE; } data->used = PAL_FALSE; diff --git a/tests/tests_main.c b/tests/tests_main.c index aa8e7350..5d4e2f46 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -13,11 +13,11 @@ int main(int argc, char** argv) // event // registerTest(eventTest, "Event test"); - //registerTest(userEventTest, "User Event Test"); + // registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE == 1 - registerTest(platformTest, "Platform Test"); - registerTest(cpuTest, "CPU Test"); + // registerTest(platformTest, "Platform Test"); + // registerTest(cpuTest, "CPU Test"); #endif // PAL_HAS_SYSTEM_MODULE #if PAL_HAS_THREAD_MODULE == 1 From 196d196befdcc954549fbda0c200c04e1aa38aae Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 29 Jun 2026 20:38:44 -0700 Subject: [PATCH 307/372] add graphics backends header --- src/graphics/pal_graphics_backends.h | 159 +++++++ src/graphics/pal_graphics_vtable.h | 611 --------------------------- src/opengl/pal_opengl_backends.h | 36 +- 3 files changed, 177 insertions(+), 629 deletions(-) create mode 100644 src/graphics/pal_graphics_backends.h delete mode 100644 src/graphics/pal_graphics_vtable.h diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h new file mode 100644 index 00000000..698bbba0 --- /dev/null +++ b/src/graphics/pal_graphics_backends.h @@ -0,0 +1,159 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_GRAPHICS_BACKENDS_H +#define _PAL_GRAPHICS_BACKENDS_H + +#include "pal/pal_graphics.h" + +typedef struct { + // clang-format off + PalResult (PAL_CALL *enumerateAdapters)(int32_t*, PalAdapter**); + PalResult (PAL_CALL *getAdapterInfo)(PalAdapter*, PalAdapterInfo*); + PalResult (PAL_CALL *getAdapterCapabilities)(PalAdapter*, PalAdapterCapabilities*); + PalAdapterFeatures (PAL_CALL *getAdapterFeatures)(PalAdapter*); + uint32_t (PAL_CALL *getHighestSupportedShaderTarget)(PalAdapter*, PalShaderFormats); + PalResult (PAL_CALL *createDevice)(PalAdapter*, PalAdapterFeatures, PalDevice**); + void (PAL_CALL *destroyDevice)(PalDevice*); + PalResult (PAL_CALL *allocateMemory)(PalDevice*, PalMemoryType, uint64_t, uint64_t, PalMemory**); + void (PAL_CALL *freeMemory)(PalDevice*, PalMemory*); + PalResult (PAL_CALL *querySamplerAnisotropyCapabilities)(PalDevice*, PalSamplerAnisotropyCapabilities*); + PalResult (PAL_CALL *queryMultiViewCapabilities)(PalDevice*, PalMultiViewCapabilities*); + PalResult (PAL_CALL *queryMultiViewportCapabilities)(PalDevice*, PalMultiViewportCapabilities*); + PalResult (PAL_CALL *queryDepthStencilCapabilities)(PalDevice*, PalDepthStencilCapabilities*); + PalResult (PAL_CALL *queryFragmentShadingRateCapabilities)(PalDevice*, PalFragmentShadingRateCapabilities*); + PalResult (PAL_CALL *queryMeshShaderCapabilities)(PalDevice*, PalMeshShaderCapabilities*); + PalResult (PAL_CALL *queryRayTracingCapabilities)(PalDevice*, PalRayTracingCapabilities*); + PalResult (PAL_CALL *queryDescriptorIndexingCapabilities)(PalDevice*, PalDescriptorIndexingCapabilities*); + + PalResult (PAL_CALL *createQueue)(PalDevice*, PalQueueType, PalQueue**); + void (PAL_CALL *destroyQueue)(PalQueue*); + PalBool (PAL_CALL *canQueuePresent)(PalQueue*, PalSurface*); + PalResult (PAL_CALL *waitQueue)(PalQueue*); + PalResult (PAL_CALL *enumerateFormats)(PalAdapter*, int32_t*, PalFormatInfo*); + PalBool (PAL_CALL *isFormatSupported)(PalAdapter*, PalFormat); + PalImageUsages (PAL_CALL *queryFormatImageUsages)(PalAdapter*, PalFormat); + PalSampleCount (PAL_CALL *queryFormatSampleCount)(PalAdapter*, PalFormat); + PalResult (PAL_CALL *createImage)(PalDevice*, const PalImageCreateInfo*, PalImage**); + void (PAL_CALL *destroyImage)(PalImage*); + PalResult (PAL_CALL *getImageInfo)(PalImage*, PalImageInfo*); + PalResult (PAL_CALL *getImageMemoryRequirements)(PalImage*, PalMemoryRequirements*); + PalResult (PAL_CALL *bindImageMemory)(PalImage*, PalMemory*, uint64_t); + PalResult (PAL_CALL *mapImageMemory)(PalImage*, uint64_t, uint64_t, void**); + void (PAL_CALL *unmapImageMemory)(PalImage*); + PalResult (PAL_CALL *createImageView)(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); + void (PAL_CALL *destroyImageView)(PalImageView*); + + PalResult (PAL_CALL *createSampler)(PalDevice*, const PalSamplerCreateInfo*, PalSampler**); + void (PAL_CALL *destroySampler)(PalSampler*); + PalResult (PAL_CALL *createSurface)(PalDevice*, void*, void*, PalWindowInstanceType, PalSurface**); + void (PAL_CALL *destroySurface)(PalSurface*); + PalResult (PAL_CALL *getSurfaceCapabilities)(PalDevice*, PalSurface*, PalSurfaceCapabilities*); + PalResult (PAL_CALL *createSwapchain)(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); + void (PAL_CALL *destroySwapchain)(PalSwapchain*); + PalImage* (PAL_CALL *getSwapchainImage)(PalSwapchain*, int32_t); + PalResult (PAL_CALL *getNextSwapchainImage)(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t*); + PalResult (PAL_CALL *presentSwapchain)(PalSwapchain*, PalSwapchainPresentInfo*); + PalResult (PAL_CALL *resizeSwapchain)(PalSwapchain*, uint32_t, uint32_t); + PalResult (PAL_CALL *createShader)(PalDevice*, const PalShaderCreateInfo*, PalShader**); + void (PAL_CALL *destroyShader)(PalShader*); + PalResult (PAL_CALL *createFence)(PalDevice*, PalBool, PalFence**); + void (PAL_CALL *destroyFence)(PalFence*); + PalResult (PAL_CALL *waitFence)(PalFence*, uint64_t); + PalResult (PAL_CALL *resetFence)(PalFence*); + PalBool (PAL_CALL *isFenceSignaled)(PalFence*); + + PalResult (PAL_CALL *createSemaphore)(PalDevice*, PalBool, PalSemaphore**); + void (PAL_CALL *destroySemaphore)(PalSemaphore*); + PalResult (PAL_CALL *waitSemaphore)(PalSemaphore*, uint64_t, uint64_t); + PalResult (PAL_CALL *signalSemaphore)(PalSemaphore*, PalQueue*, uint64_t); + PalResult (PAL_CALL *getSemaphoreValue)(PalSemaphore*, uint64_t*); + PalResult (PAL_CALL *createCommandPool)(PalDevice*, PalQueue*, PalCommandPool**); + void (PAL_CALL *destroyCommandPool)(PalCommandPool*); + PalResult (PAL_CALL *resetCommandPool)(PalCommandPool*); + PalResult (PAL_CALL *allocateCommandBuffer)(PalDevice*, PalCommandPool*, PalCommandBufferType, PalCommandBuffer**); + void (PAL_CALL *freeCommandBuffer)(PalCommandBuffer*); + PalResult (PAL_CALL *resetCommandBuffer)(PalCommandBuffer*); + PalResult (PAL_CALL *submitCommandBuffer)(PalQueue*, PalCommandBufferSubmitInfo*); + + PalResult (PAL_CALL *cmdBegin)(PalCommandBuffer*, PalRenderingLayoutInfo*); + PalResult (PAL_CALL *cmdEnd)(PalCommandBuffer*); + PalResult (PAL_CALL *cmdExecuteCommandBuffer)(PalCommandBuffer*, PalCommandBuffer*); + PalResult (PAL_CALL *cmdSetFragmentShadingRate)(PalCommandBuffer*, PalFragmentShadingRateState*); + PalResult (PAL_CALL *cmdDrawMeshTasks)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); + PalResult (PAL_CALL *cmdDrawMeshTasksIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); + PalResult (PAL_CALL *cmdDrawMeshTasksIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); + PalResult (PAL_CALL *cmdBuildAccelerationStructure)(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); + PalResult (PAL_CALL *cmdBeginRendering)(PalCommandBuffer*, PalRenderingInfo*); + PalResult (PAL_CALL *cmdEndRendering)(PalCommandBuffer*); + PalResult (PAL_CALL *cmdCopyBuffer)(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); + PalResult (PAL_CALL *cmdCopyBufferToImage)(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); + PalResult (PAL_CALL *cmdCopyImage)(PalCommandBuffer*, PalImage*,PalImage*, PalImageCopyInfo*); + PalResult (PAL_CALL *cmdCopyImageToBuffer)(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); + PalResult (PAL_CALL *cmdBindPipeline)(PalCommandBuffer*, PalPipeline*); + PalResult (PAL_CALL *cmdSetViewport)(PalCommandBuffer*, uint32_t, PalViewport*); + PalResult (PAL_CALL *cmdSetScissors)(PalCommandBuffer*, uint32_t, PalRect2D*); + PalResult (PAL_CALL *cmdBindVertexBuffers)(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); + PalResult (PAL_CALL *cmdBindIndexBuffer)(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); + PalResult (PAL_CALL *cmdDraw)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); + PalResult (PAL_CALL *cmdDrawIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); + PalResult (PAL_CALL *cmdDrawIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); + PalResult (PAL_CALL *cmdDrawIndexed)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); + PalResult (PAL_CALL *cmdDrawIndexedIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); + PalResult (PAL_CALL *cmdDrawIndexedIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); + PalResult (PAL_CALL *cmdAccelerationStructureBarrier)(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); + PalResult (PAL_CALL *cmdImageBarrier)(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); + PalResult (PAL_CALL *cmdBufferBarrier)(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); + PalResult (PAL_CALL *cmdDispatch)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); + PalResult (PAL_CALL *cmdDispatchBase)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); + PalResult (PAL_CALL *cmdDispatchIndirect)(PalCommandBuffer*, PalBuffer*); + PalResult (PAL_CALL *cmdTraceRays)(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); + PalResult (PAL_CALL *cmdTraceRaysIndirect)(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); + PalResult (PAL_CALL *cmdBindDescriptorSet)(PalCommandBuffer*, uint32_t, PalDescriptorSet*); + PalResult (PAL_CALL *cmdPushConstants)(PalCommandBuffer*, uint32_t, uint32_t, const void*); + PalResult (PAL_CALL *cmdSetCullMode)(PalCommandBuffer*, PalCullMode); + PalResult (PAL_CALL *cmdSetFrontFace)(PalCommandBuffer*, PalFrontFace); + PalResult (PAL_CALL *cmdSetPrimitiveTopology)(PalCommandBuffer*, PalPrimitiveTopology); + PalResult (PAL_CALL *cmdSetDepthTestEnable)(PalCommandBuffer*, PalBool); + PalResult (PAL_CALL *cmdSetDepthWriteEnable)(PalCommandBuffer*, PalBool); + PalResult (PAL_CALL *cmdSetStencilOp)(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); + + PalResult (PAL_CALL *createAccelerationstructure)(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); + void (PAL_CALL *destroyAccelerationstructure)(PalAccelerationStructure*); + PalResult (PAL_CALL *getAccelerationStructureBuildSize)(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); + PalResult (PAL_CALL *createBuffer)(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); + void (PAL_CALL *destroyBuffer)(PalBuffer*); + PalResult (PAL_CALL *getBufferMemoryRequirements)(PalBuffer*, PalMemoryRequirements*); + PalResult (PAL_CALL *computeInstanceBufferRequirements)(PalDevice*, uint32_t, uint64_t*); + PalResult (PAL_CALL *computeImageCopyStagingBufferRequirements)(PalDevice*, PalFormat, PalBufferImageCopyInfo*, uint32_t*, uint32_t*, uint64_t*); + PalResult (PAL_CALL *writeToInstanceBuffer)(PalDevice*, void*, PalAccelerationStructureInstance*, uint32_t); + PalResult (PAL_CALL *writeToImageCopyStagingBuffer)(PalDevice*, void*, void*, PalFormat, PalBufferImageCopyInfo*); + PalResult (PAL_CALL *bindBufferMemory)(PalBuffer*, PalMemory*, uint64_t); + PalResult (PAL_CALL *mapBufferMemory)(PalBuffer*, uint64_t, uint64_t, void**); + void (PAL_CALL *unmapBufferMemory)(PalBuffer*); + PalDeviceAddress (PAL_CALL *getBufferDeviceAddress)(PalBuffer*); + + PalResult (PAL_CALL *createDescriptorSetLayout)(PalDevice*, const PalDescriptorSetLayoutCreateInfo*, PalDescriptorSetLayout**); + void (PAL_CALL *destroyDescriptorSetLayout)(PalDescriptorSetLayout*); + PalResult (PAL_CALL *createDescriptorPool)(PalDevice*, const PalDescriptorPoolCreateInfo*, PalDescriptorPool**); + void (PAL_CALL *destroyDescriptorPool)(PalDescriptorPool*); + PalResult (PAL_CALL *resetDescriptorPool)(PalDescriptorPool*); + PalResult (PAL_CALL *allocateDescriptorSet)(PalDevice*, PalDescriptorPool*, PalDescriptorSetLayout*, PalDescriptorSet**); + PalResult (PAL_CALL *updateDescriptorSet)(PalDevice*, uint32_t, PalDescriptorSetWriteInfo*); + + PalResult (PAL_CALL *createPipelineLayout)(PalDevice*, const PalPipelineLayoutCreateInfo*, PalPipelineLayout**); + void (PAL_CALL *destroyPipelineLayout)(PalPipelineLayout*); + PalResult (PAL_CALL *createGraphicsPipeline)(PalDevice*, const PalGraphicsPipelineCreateInfo*, PalPipeline**); + PalResult (PAL_CALL *createComputePipeline)(PalDevice*, const PalComputePipelineCreateInfo*, PalPipeline**); + PalResult (PAL_CALL *createRayTracingPipeline)(PalDevice*, const PalRayTracingPipelineCreateInfo*, PalPipeline**); + void (PAL_CALL *destroyPipeline)(PalPipeline*); + PalResult (PAL_CALL *createShaderBindingTable)(PalDevice*, const PalShaderBindingTableCreateInfo*, PalShaderBindingTable**); + void (PAL_CALL *destroyShaderBindingTable)(PalShaderBindingTable*); + PalResult (PAL_CALL *updateShaderBindingTable)(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); +} PalGraphicsVtable; + +#endif // _PAL_GRAPHICS_BACKENDS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics_vtable.h b/src/graphics/pal_graphics_vtable.h deleted file mode 100644 index 8135d369..00000000 --- a/src/graphics/pal_graphics_vtable.h +++ /dev/null @@ -1,611 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifndef _PAL_GRAPHICS_VTABLE_H -#define _PAL_GRAPHICS_VTABLE_H - -#include "pal/pal_graphics.h" - -typedef struct { - PalResult (PAL_CALL *enumerateAdapters)( - int32_t* count, - PalAdapter** outAdapters); - - PalResult (PAL_CALL *getAdapterInfo)( - PalAdapter* adapter, - PalAdapterInfo* info); - - PalResult (PAL_CALL *getAdapterCapabilities)( - PalAdapter* adapter, - PalAdapterCapabilities* caps); - - PalAdapterFeatures (PAL_CALL *getAdapterFeatures)(PalAdapter* adapter); - - uint32_t (PAL_CALL *getHighestSupportedShaderTarget)( - PalAdapter* adapter, - PalShaderFormats shaderFormat); - - PalResult (PAL_CALL *createDevice)( - PalAdapter* adapter, - PalAdapterFeatures features, - PalDevice** outDevice); - - void (PAL_CALL *destroyDevice)(PalDevice* device); - - PalResult (PAL_CALL *allocateMemory)( - PalDevice* device, - PalMemoryType type, - uint64_t memoryMask, - uint64_t size, - PalMemory** outMemory); - - void (PAL_CALL *freeMemory)( - PalDevice* device, - PalMemory* memory); - - PalResult (PAL_CALL *querySamplerAnisotropyCapabilities)( - PalDevice* device, - PalSamplerAnisotropyCapabilities* caps); - - PalResult (PAL_CALL *queryMultiViewCapabilities)( - PalDevice* device, - PalMultiViewCapabilities* caps); - - PalResult (PAL_CALL *queryMultiViewportCapabilities)( - PalDevice* device, - PalMultiViewportCapabilities* caps); - - PalResult (PAL_CALL *queryDepthStencilCapabilities)( - PalDevice* device, - PalDepthStencilCapabilities* caps); - PalResult (PAL_CALL *queryFragmentShadingRateCapabilities)( - PalDevice* device, - PalFragmentShadingRateCapabilities* caps); - - PalResult (PAL_CALL *queryMeshShaderCapabilities)( - PalDevice* device, - PalMeshShaderCapabilities* caps); - - PalResult (PAL_CALL *queryRayTracingCapabilities)( - PalDevice* device, - PalRayTracingCapabilities* caps); - - PalResult (PAL_CALL *queryDescriptorIndexingCapabilities)( - PalDevice* device, - PalDescriptorIndexingCapabilities* caps); - - PalResult (PAL_CALL *createQueue)( - PalDevice* device, - PalQueueType type, - PalQueue** outQueue); - - void (PAL_CALL *destroyQueue)(PalQueue* queue); - - PalBool (PAL_CALL *canQueuePresent)( - PalQueue* queue, - PalSurface* surface); - - PalResult (PAL_CALL *waitQueue)(PalQueue* queue); - - PalResult (PAL_CALL *enumerateFormats)( - PalAdapter* adapter, - int32_t* count, - PalFormatInfo* outFormats); - - PalBool (PAL_CALL *isFormatSupported)( - PalAdapter* adapter, - PalFormat format); - - PalImageUsages (PAL_CALL *queryFormatImageUsages)( - PalAdapter* adapter, - PalFormat format); - - PalSampleCount (PAL_CALL *queryFormatSampleCount)( - PalAdapter* adapter, - PalFormat format); - - PalResult (PAL_CALL *createImage)( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage); - - void (PAL_CALL *destroyImage)(PalImage* image); - - PalResult (PAL_CALL *getImageInfo)( - PalImage* image, - PalImageInfo* info); - - PalResult (PAL_CALL *getImageMemoryRequirements)( - PalImage* image, - PalMemoryRequirements* requirements); - - PalResult (PAL_CALL *bindImageMemory)( - PalImage* image, - PalMemory* memory, - uint64_t offset); - - PalResult (PAL_CALL *mapImageMemory)( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr); - - void (PAL_CALL *unmapImageMemory)(PalImage* image); - - PalResult (PAL_CALL *createImageView)( - PalDevice* device, - PalImage* image, - const PalImageViewCreateInfo* info, - PalImageView** outImageView); - - void (PAL_CALL *destroyImageView)(PalImageView* imageView); - - PalResult (PAL_CALL *createSampler)( - PalDevice* device, - const PalSamplerCreateInfo* info, - PalSampler** outSampler); - - void (PAL_CALL *destroySampler)(PalSampler* sampler); - - PalResult (PAL_CALL *createSurface)( - PalDevice* device, - void* window, - void* windowInstance, - PalWindowInstanceType instanceType, - PalSurface** outSurface); - - void (PAL_CALL *destroySurface)(PalSurface* surface); - - PalResult (PAL_CALL *getSurfaceCapabilities)( - PalDevice* device, - PalSurface* surface, - PalSurfaceCapabilities* caps); - - PalResult (PAL_CALL *createSwapchain)( - PalDevice* device, - PalQueue* queue, - PalSurface* surface, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain); - - void (PAL_CALL *destroySwapchain)(PalSwapchain* swapchain); - - PalImage* (PAL_CALL *getSwapchainImage)( - PalSwapchain* swapchain, - int32_t index); - - PalResult (PAL_CALL *getNextSwapchainImage)( - PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, - uint32_t* outIndex); - - PalResult (PAL_CALL *presentSwapchain)( - PalSwapchain* swapchain, - PalSwapchainPresentInfo* info); - - PalResult (PAL_CALL *resizeSwapchain)( - PalSwapchain* swapchain, - uint32_t newWidth, - uint32_t newHeight); - - PalResult (PAL_CALL *createShader)( - PalDevice* device, - const PalShaderCreateInfo* info, - PalShader** outShader); - - void (PAL_CALL *destroyShader)(PalShader* shader); - - PalResult (PAL_CALL *createFence)( - PalDevice* device, - PalBool signaled, - PalFence** outFence); - - void (PAL_CALL *destroyFence)(PalFence* fence); - - PalResult (PAL_CALL *waitFence)( - PalFence* fence, - uint64_t timeout); - - PalResult (PAL_CALL *resetFence)(PalFence* fence); - - PalBool (PAL_CALL *isFenceSignaled)(PalFence* fence); - - PalResult (PAL_CALL *createSemaphore)( - PalDevice* device, - PalBool enableTimeline, - PalSemaphore** outSemaphore); - - void (PAL_CALL *destroySemaphore)(PalSemaphore* semaphore); - - PalResult (PAL_CALL *waitSemaphore)( - PalSemaphore* semaphore, - uint64_t value, - uint64_t timeout); - - PalResult (PAL_CALL *signalSemaphore)( - PalSemaphore* semaphore, - PalQueue* queue, - uint64_t value); - - PalResult (PAL_CALL *getSemaphoreValue)( - PalSemaphore* semaphore, - uint64_t* outValue); - - PalResult (PAL_CALL *createCommandPool)( - PalDevice* device, - PalQueue* queue, - PalCommandPool** outPool); - - void (PAL_CALL *destroyCommandPool)(PalCommandPool* pool); - - PalResult (PAL_CALL *resetCommandPool)(PalCommandPool* pool); - - PalResult (PAL_CALL *allocateCommandBuffer)( - PalDevice* device, - PalCommandPool* pool, - PalCommandBufferType type, - PalCommandBuffer** outCmdBuffer); - - void (PAL_CALL *freeCommandBuffer)(PalCommandBuffer* cmdBuffer); - - PalResult (PAL_CALL *resetCommandBuffer)(PalCommandBuffer* cmdBuffer); - - PalResult (PAL_CALL *submitCommandBuffer)( - PalQueue* queue, - PalCommandBufferSubmitInfo* info); - - PalResult (PAL_CALL *cmdBegin)( - PalCommandBuffer* cmdBuffer, - PalRenderingLayoutInfo* info); - - PalResult (PAL_CALL *cmdEnd)(PalCommandBuffer* cmdBuffer); - - PalResult (PAL_CALL *cmdExecuteCommandBuffer)( - PalCommandBuffer* primaryCmdBuffer, - PalCommandBuffer* secondaryCmdBuffer); - - PalResult (PAL_CALL *cmdSetFragmentShadingRate)( - PalCommandBuffer* cmdBuffer, - PalFragmentShadingRateState* state); - - PalResult (PAL_CALL *cmdDrawMeshTasks)( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - - PalResult (PAL_CALL *cmdDrawMeshTasksIndirect)( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t drawCount); - - PalResult (PAL_CALL *cmdDrawMeshTasksIndirectCount)( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - - PalResult (PAL_CALL *cmdBuildAccelerationStructure)( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructureBuildInfo* info); - - PalResult (PAL_CALL *cmdBeginRendering)( - PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info); - - PalResult (PAL_CALL *cmdEndRendering)(PalCommandBuffer* cmdBuffer); - - PalResult (PAL_CALL *cmdCopyBuffer)( - PalCommandBuffer* cmdBuffer, - PalBuffer* dst, - PalBuffer* src, - PalBufferCopyInfo* copyInfo); - - PalResult (PAL_CALL *cmdCopyBufferToImage)( - PalCommandBuffer* cmdBuffer, - PalImage* dstImage, - PalBuffer* srcBuffer, - PalBufferImageCopyInfo* copyInfo); - - PalResult (PAL_CALL *cmdCopyImage)( - PalCommandBuffer* cmdBuffer, - PalImage* dst, - PalImage* src, - PalImageCopyInfo* copyInfo); - - PalResult (PAL_CALL *cmdCopyImageToBuffer)( - PalCommandBuffer* cmdBuffer, - PalBuffer* dstBuffer, - PalImage* srcImage, - PalBufferImageCopyInfo* copyInfo); - - PalResult (PAL_CALL *cmdBindPipeline)( - PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline); - - PalResult (PAL_CALL *cmdSetViewport)( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalViewport* viewports); - - PalResult (PAL_CALL *cmdSetScissors)( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalRect2D* scissors); - - PalResult (PAL_CALL *cmdBindVertexBuffers)( - PalCommandBuffer* cmdBuffer, - uint32_t firstSlot, - uint32_t count, - PalBuffer** buffers, - uint64_t* offsets); - - PalResult (PAL_CALL *cmdBindIndexBuffer)( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint64_t offset, - PalIndexType type); - - PalResult (PAL_CALL *cmdDraw)( - PalCommandBuffer* cmdBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance); - - PalResult (PAL_CALL *cmdDrawIndirect)( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - - PalResult (PAL_CALL *cmdDrawIndirectCount)( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t count); - - PalResult (PAL_CALL *cmdDrawIndexed)( - PalCommandBuffer* cmdBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance); - - PalResult (PAL_CALL *cmdDrawIndexedIndirect)( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - - PalResult (PAL_CALL *cmdDrawIndexedIndirectCount)( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t count); - - PalResult (PAL_CALL *cmdAccelerationStructureBarrier)( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructure* as, - PalUsageState oldUsageState, - PalUsageState newUsageState); - - PalResult (PAL_CALL *cmdImageBarrier)( - PalCommandBuffer* cmdBuffer, - PalImage* image, - PalImageSubresourceRange* subresourceRange, - PalUsageState oldUsageState, - PalUsageState newUsageState); - - PalResult (PAL_CALL *cmdBufferBarrier)( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState); - - PalResult (PAL_CALL *cmdDispatch)( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - - PalResult (PAL_CALL *cmdDispatchBase)( - PalCommandBuffer* cmdBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - - PalResult (PAL_CALL *cmdDispatchIndirect)( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer); - - PalResult (PAL_CALL *cmdTraceRays)( - PalCommandBuffer* cmdBuffer, - PalShaderBindingTable* sbt, - uint32_t raygenIndex, - uint32_t width, - uint32_t height, - uint32_t depth); - - PalResult (PAL_CALL *cmdTraceRaysIndirect)( - PalCommandBuffer* cmdBuffer, - uint32_t raygenIndex, - PalShaderBindingTable* sbt, - PalBuffer* buffer); - - PalResult (PAL_CALL *cmdBindDescriptorSet)( - PalCommandBuffer* cmdBuffer, - uint32_t setIndex, - PalDescriptorSet* set); - - PalResult (PAL_CALL *cmdPushConstants)( - PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, - uint32_t offset, - uint32_t size, - const void* value); - - PalResult (PAL_CALL *cmdSetCullMode)( - PalCommandBuffer* cmdBuffer, - PalCullMode cullMode); - - PalResult (PAL_CALL *cmdSetFrontFace)( - PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace); - - PalResult (PAL_CALL *cmdSetPrimitiveTopology)( - PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology); - - PalResult (PAL_CALL *cmdSetDepthTestEnable)( - PalCommandBuffer* cmdBuffer, - PalBool enable); - - PalResult (PAL_CALL *cmdSetDepthWriteEnable)( - PalCommandBuffer* cmdBuffer, - PalBool enable); - - PalResult (PAL_CALL *cmdSetStencilOp)( - PalCommandBuffer* cmdBuffer, - PalStencilFaceFlags faceMask, - PalStencilOp failOp, - PalStencilOp passOp, - PalStencilOp depthFailOp, - PalCompareOp compareOp); - - PalResult (PAL_CALL *createAccelerationstructure)( - PalDevice* device, - const PalAccelerationStructureCreateInfo* info, - PalAccelerationStructure** outAs); - - void (PAL_CALL *destroyAccelerationstructure)(PalAccelerationStructure* as); - - PalResult (PAL_CALL *getAccelerationStructureBuildSize)( - PalDevice* device, - PalAccelerationStructureBuildInfo* info, - PalAccelerationStructureBuildSize* size); - - PalResult (PAL_CALL *createBuffer)( - PalDevice* device, - const PalBufferCreateInfo* info, - PalBuffer** outBuffer); - - void (PAL_CALL *destroyBuffer)(PalBuffer* buffer); - - PalResult (PAL_CALL *getBufferMemoryRequirements)( - PalBuffer* buffer, - PalMemoryRequirements* requirements); - - PalResult (PAL_CALL *computeInstanceBufferRequirements)( - PalDevice* device, - uint32_t instanceCount, - uint64_t* outSize); - - PalResult (PAL_CALL *computeImageCopyStagingBufferRequirements)( - PalDevice* device, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize); - - PalResult (PAL_CALL *writeToInstanceBuffer)( - PalDevice* device, - void* ptr, - PalAccelerationStructureInstance* instances, - uint32_t instanceCount); - - PalResult (PAL_CALL *writeToImageCopyStagingBuffer)( - PalDevice* device, - void* ptr, - void* srcData, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo); - - PalResult (PAL_CALL *bindBufferMemory)( - PalBuffer* buffer, - PalMemory* memory, - uint64_t offset); - - PalResult (PAL_CALL *mapBufferMemory)( - PalBuffer* buffer, - uint64_t offset, - uint64_t size, - void** outPtr); - - void (PAL_CALL *unmapBufferMemory)(PalBuffer* buffer); - - PalDeviceAddress (PAL_CALL *getBufferDeviceAddress)(PalBuffer* buffer); - - PalResult (PAL_CALL *createDescriptorSetLayout)( - PalDevice* device, - const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout); - - void (PAL_CALL *destroyDescriptorSetLayout)(PalDescriptorSetLayout* layout); - - PalResult (PAL_CALL *createDescriptorPool)( - PalDevice* device, - const PalDescriptorPoolCreateInfo* info, - PalDescriptorPool** outPool); - - void (PAL_CALL *destroyDescriptorPool)(PalDescriptorPool* pool); - - PalResult (PAL_CALL *resetDescriptorPool)(PalDescriptorPool* pool); - - PalResult (PAL_CALL *allocateDescriptorSet)( - PalDevice* device, - PalDescriptorPool* pool, - PalDescriptorSetLayout* layout, - PalDescriptorSet** outSet); - - PalResult (PAL_CALL *updateDescriptorSet)( - PalDevice* device, - uint32_t count, - PalDescriptorSetWriteInfo* infos); - - PalResult (PAL_CALL *createPipelineLayout)( - PalDevice* device, - const PalPipelineLayoutCreateInfo* info, - PalPipelineLayout** outLayout); - - void (PAL_CALL *destroyPipelineLayout)(PalPipelineLayout* layout); - - PalResult (PAL_CALL *createGraphicsPipeline)( - PalDevice* device, - const PalGraphicsPipelineCreateInfo* info, - PalPipeline** outPipeline); - - PalResult (PAL_CALL *createComputePipeline)( - PalDevice* device, - const PalComputePipelineCreateInfo* info, - PalPipeline** outPipeline); - - PalResult (PAL_CALL *createRayTracingPipeline)( - PalDevice* device, - const PalRayTracingPipelineCreateInfo* info, - PalPipeline** outPipeline); - - void (PAL_CALL *destroyPipeline)(PalPipeline* pipeline); - - PalResult (PAL_CALL *createShaderBindingTable)( - PalDevice* device, - const PalShaderBindingTableCreateInfo* info, - PalShaderBindingTable** outSbt); - - void (PAL_CALL *destroyShaderBindingTable)(PalShaderBindingTable* sbt); - - PalResult (PAL_CALL *updateShaderBindingTable)( - PalShaderBindingTable* sbt, - uint32_t count, - PalShaderBindingTableRecordInfo* infos); -} PalGraphicsVtable; - -#endif // _PAL_GRAPHICS_VTABLE_H \ No newline at end of file diff --git a/src/opengl/pal_opengl_backends.h b/src/opengl/pal_opengl_backends.h index e8cc7e7b..71679a83 100644 --- a/src/opengl/pal_opengl_backends.h +++ b/src/opengl/pal_opengl_backends.h @@ -31,17 +31,17 @@ typedef struct { // ================================================== #ifdef _WIN32 -PalResult wglInitGL(PalGLAPI api, void* instance, const PalAllocator* allocator); +PalResult wglInitGL(PalGLAPI, void*, const PalAllocator*); void wglShutdownGL(); const PalGLInfo* wglGetGLInfo(); -PalResult wglEnumerateGLFBConfigs(int32_t* count, PalGLFBConfig* configs); -PalResult wglCreateGLContext(const PalGLContextCreateInfo* info, PalGLContext** outContext); -void wglDestroyGLContext(PalGLContext* context); -PalResult wglMakeContextCurrent(PalGLWindow* glWindow, PalGLContext* context); -void* wglGetGLProcAddress(const char* name); -PalResult wglSwapBuffers(PalGLWindow* glWindow, PalGLContext* context); -PalResult wglSetSwapInterval(int32_t interval); -const PalBool* wglGetSupportedGLAPIs(void* instance); +PalResult wglEnumerateGLFBConfigs(int32_t*, PalGLFBConfig*); +PalResult wglCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); +void wglDestroyGLContext(PalGLContext*); +PalResult wglMakeContextCurrent(PalGLWindow*, PalGLContext*); +void* wglGetGLProcAddress(const char*); +PalResult wglSwapBuffers(PalGLWindow*, PalGLContext*); +PalResult wglSetSwapInterval(int32_t); +const PalBool* wglGetSupportedGLAPIs(void*); static OpenglBackend s_WglBackend = { .shutdownGL = wglShutdownGL, @@ -62,17 +62,17 @@ static OpenglBackend s_WglBackend = { // ================================================== #if _PAL_HAS_EGL -PalResult eglInitGL(PalGLAPI api, void* instance, const PalAllocator* allocator); +PalResult eglInitGL(PalGLAPI, void*, const PalAllocator*); void eglShutdownGL(); const PalGLInfo* eglGetGLInfo(); -PalResult eglEnumerateGLFBConfigs(int32_t* count, PalGLFBConfig* configs); -PalResult eglCreateGLContext(const PalGLContextCreateInfo* info, PalGLContext** outContext); -void eglDestroyGLContext(PalGLContext* context); -PalResult eglMakeContextCurrent(PalGLWindow* glWindow, PalGLContext* context); -void* eglGetGLProcAddress(const char* name); -PalResult eglSwapBuffers(PalGLWindow* glWindow, PalGLContext* context); -PalResult eglSetSwapInterval(int32_t interval); -const PalBool* eglGetSupportedGLAPIs(void* instance); +PalResult eglEnumerateGLFBConfigs(int32_t*, PalGLFBConfig*); +PalResult eglCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); +void eglDestroyGLContext(PalGLContext*); +PalResult eglMakeContextCurrent(PalGLWindow*, PalGLContext*); +void* eglGetGLProcAddress(const char*); +PalResult eglSwapBuffers(PalGLWindow*, PalGLContext*); +PalResult eglSetSwapInterval(int32_t); +const PalBool* eglGetSupportedGLAPIs(void*); static OpenglBackend s_EglBackend = { .shutdownGL = eglShutdownGL, From 583dd2f4b7e264c553ad67ee17fb51b3c08df5d1 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 30 Jun 2026 13:39:45 +0000 Subject: [PATCH 308/372] change function API: graphics --- include/pal/pal_graphics.h | 2 +- src/graphics/pal_backends_graphics.h | 1759 -------------------------- src/graphics/pal_graphics.c | 493 ++++---- src/graphics/pal_graphics_backends.h | 1313 ++++++++++++++++++- src/opengl/pal_opengl_backends.h | 5 +- src/video/pal_video_backends.h | 5 +- 6 files changed, 1545 insertions(+), 2032 deletions(-) delete mode 100644 src/graphics/pal_backends_graphics.h diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index f1c639e9..541be411 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1571,7 +1571,7 @@ typedef struct { uint32_t supportedDepthResolveModes; /**< Masks of supported depth resolve modes.*/ uint32_t supportedStencilResolveModes; /**< Masks of supported stencil resolve modes.*/ - /** If `PAL_TRUE`, depth/stencil can have seperate resolve modes.*/ + /** If `PAL_TRUE`, depth and stencil can have seperate resolve modes.*/ PalBool supportsIndependentResolve; /**If `PAL_TRUE`, depth/stencil can be `PAL_RESOLVE_MODE_NONE` while the other is resolved.*/ diff --git a/src/graphics/pal_backends_graphics.h b/src/graphics/pal_backends_graphics.h deleted file mode 100644 index 593d3372..00000000 --- a/src/graphics/pal_backends_graphics.h +++ /dev/null @@ -1,1759 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -#ifndef _PAL_BACKENDS_GRAPHICS_H -#define _PAL_BACKENDS_GRAPHICS_H - -#include "pal_graphics_vtable.h" - -// ================================================== -// Vulkan -// ================================================== - -PalResult PAL_CALL initGraphicsVk( - const PalGraphicsDebugger* debugger, - const PalAllocator* allocator); - -void PAL_CALL shutdownGraphicsVk(); - -PalResult PAL_CALL enumerateAdaptersVk( - int32_t* count, - PalAdapter** outAdapters); - -PalResult PAL_CALL getAdapterInfoVk( - PalAdapter* adapter, - PalAdapterInfo* info); - -PalResult PAL_CALL getAdapterCapabilitiesVk( - PalAdapter* adapter, - PalAdapterCapabilities* caps); - -PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter); - -uint32_t PAL_CALL getHighestSupportedShaderTargetVk( - PalAdapter* adapter, - PalShaderFormats shaderFormat); - -// ================================================== -// Device -// ================================================== - -PalResult PAL_CALL createDeviceVk( - PalAdapter* adapter, - PalAdapterFeatures features, - PalDevice** outDevice); - -void PAL_CALL destroyDeviceVk(PalDevice* device); - -PalResult PAL_CALL waitDeviceVk(PalDevice* device); - -// ================================================== -// Memory -// ================================================== - -PalResult PAL_CALL allocateMemoryVk( - PalDevice* device, - PalMemoryType type, - uint64_t memoryMask, - uint64_t size, - PalMemory** outMemory); - -void PAL_CALL freeMemoryVk( - PalDevice* device, - PalMemory* memory); - -// ================================================== -// Extended Adapter Features -// ================================================== - -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk( - PalDevice* device, - PalSamplerAnisotropyCapabilities* caps); - -PalResult PAL_CALL queryMultiViewCapabilitiesVk( - PalDevice* device, - PalMultiViewCapabilities* caps); - -PalResult PAL_CALL queryMultiViewportCapabilitiesVk( - PalDevice* device, - PalMultiViewportCapabilities* caps); - -PalResult PAL_CALL queryDepthStencilCapabilitiesVk( - PalDevice* device, - PalDepthStencilCapabilities* caps); - -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk( - PalDevice* device, - PalFragmentShadingRateCapabilities* caps); - -PalResult PAL_CALL queryMeshShaderCapabilitiesVk( - PalDevice* device, - PalMeshShaderCapabilities* caps); - -PalResult PAL_CALL queryRayTracingCapabilitiesVk( - PalDevice* device, - PalRayTracingCapabilities* caps); - -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( - PalDevice* device, - PalDescriptorIndexingCapabilities* caps); - -// ================================================== -// Queue -// ================================================== - -PalResult PAL_CALL createQueueVk( - PalDevice* device, - PalQueueType type, - PalQueue** outQueue); - -void PAL_CALL destroyQueueVk(PalQueue* queue); - -PalResult PAL_CALL waitQueueVk(PalQueue* queue); - -PalBool PAL_CALL canQueuePresentVk( - PalQueue* queue, - PalSurface* surface); - -// ================================================== -// Formats -// ================================================== - -PalResult PAL_CALL enumerateFormatsVk( - PalAdapter* adapter, - int32_t* count, - PalFormatInfo* outFormats); - -PalBool PAL_CALL isFormatSupportedVk( - PalAdapter* adapter, - PalFormat format); - -PalImageUsages PAL_CALL queryFormatImageUsagesVk( - PalAdapter* adapter, - PalFormat format); - -PalSampleCount PAL_CALL queryFormatSampleCountVk( - PalAdapter* adapter, - PalFormat format); - -// ================================================== -// Image -// ================================================== - -PalResult PAL_CALL createImageVk( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage); - -void PAL_CALL destroyImageVk(PalImage* image); - -PalResult PAL_CALL getImageInfoVk( - PalImage* image, - PalImageInfo* info); - -PalResult PAL_CALL getImageMemoryRequirementsVk( - PalImage* image, - PalMemoryRequirements* requirements); - -PalResult PAL_CALL bindImageMemoryVk( - PalImage* image, - PalMemory* memory, - uint64_t offset); - -PalResult PAL_CALL mapImageMemoryVk( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr); - -void PAL_CALL unmapImageMemoryVk(PalImage* image); - -// ================================================== -// Image View -// ================================================== - -PalResult PAL_CALL createImageViewVk( - PalDevice* device, - PalImage* image, - const PalImageViewCreateInfo* info, - PalImageView** outImageView); - -void PAL_CALL destroyImageViewVk(PalImageView* imageView); - -// ================================================== -// Sampler -// ================================================== - -PalResult PAL_CALL createSamplerVk( - PalDevice* device, - const PalSamplerCreateInfo* info, - PalSampler** outSampler); - -void PAL_CALL destroySamplerVk(PalSampler* sampler); - -// ================================================== -// Surface -// ================================================== - -PalResult PAL_CALL createSurfaceVk( - PalDevice* device, - void* window, - void* windowInstance, - PalWindowInstanceType instanceType, - PalSurface** outSurface); - -void PAL_CALL destroySurfaceVk(PalSurface* surface); - -PalResult PAL_CALL getSurfaceCapabilitiesVk( - PalDevice* device, - PalSurface* surface, - PalSurfaceCapabilities* caps); - -// ================================================== -// Swapchain -// ================================================== - -PalResult PAL_CALL createSwapchainVk( - PalDevice* device, - PalQueue* queue, - PalSurface* surface, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain); - -void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain); - -PalImage* PAL_CALL getSwapchainImageVk( - PalSwapchain* swapchain, - int32_t index); - -PalResult PAL_CALL getNextSwapchainImageVk( - PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, - uint32_t* outIndex); - -PalResult PAL_CALL presentSwapchainVk( - PalSwapchain* swapchain, - PalSwapchainPresentInfo* info); - -PalResult PAL_CALL resizeSwapchainVk( - PalSwapchain* swapchain, - uint32_t newWidth, - uint32_t newHeight); - -// ================================================== -// Shader -// ================================================== - -PalResult PAL_CALL createShaderVk( - PalDevice* device, - const PalShaderCreateInfo* info, - PalShader** outShader); - -void PAL_CALL destroyShaderVk(PalShader* shader); - -// ================================================== -// Fence -// ================================================== - -PalResult PAL_CALL createFenceVk( - PalDevice* device, - PalBool signaled, - PalFence** outFence); - -void PAL_CALL destroyFenceVk(PalFence* fence); - -PalResult PAL_CALL waitFenceVk( - PalFence* fence, - uint64_t timeout); - -PalResult PAL_CALL resetFenceVk(PalFence* fence); - -PalBool PAL_CALL isFenceSignaledVk(PalFence* fence); - -// ================================================== -// Semaphore -// ================================================== - -PalResult PAL_CALL createSemaphoreVk( - PalDevice* device, - PalBool enableTimeline, - PalSemaphore** outSemaphore); - -void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore); - -PalResult PAL_CALL waitSemaphoreVk( - PalSemaphore* semaphore, - uint64_t value, - uint64_t timeout); - -PalResult PAL_CALL signalSemaphoreVk( - PalSemaphore* semaphore, - PalQueue* queue, - uint64_t value); - -PalResult PAL_CALL getSemaphoreValueVk( - PalSemaphore* semaphore, - uint64_t* outValue); - -// ================================================== -// Command Pool And Buffer -// ================================================== - -PalResult PAL_CALL createCommandPoolVk( - PalDevice* device, - PalQueue* queue, - PalCommandPool** outPool); - -void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool); - -PalResult PAL_CALL resetCommandPoolVk(PalCommandPool* pool); - -PalResult PAL_CALL allocateCommandBufferVk( - PalDevice* device, - PalCommandPool* pool, - PalCommandBufferType type, - PalCommandBuffer** outCmdBuffer); - -void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL submitCommandBufferVk( - PalQueue* queue, - PalCommandBufferSubmitInfo* info); - -// ================================================== -// Command Recording -// ================================================== - -PalResult PAL_CALL cmdBeginVk( - PalCommandBuffer* cmdBuffer, - PalRenderingLayoutInfo* info); - -PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL cmdExecuteCommandBufferVk( - PalCommandBuffer* primaryCmdBuffer, - PalCommandBuffer* secondaryCmdBuffer); - -PalResult PAL_CALL cmdSetFragmentShadingRateVk( - PalCommandBuffer* cmdBuffer, - PalFragmentShadingRateState* state); - -PalResult PAL_CALL cmdDrawMeshTasksVk( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t drawCount); - -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdBuildAccelerationStructureVk( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructureBuildInfo* info); - -PalResult PAL_CALL cmdBeginRenderingVk( - PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info); - -PalResult PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL cmdCopyBufferVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* dst, - PalBuffer* src, - PalBufferCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyBufferToImageVk( - PalCommandBuffer* cmdBuffer, - PalImage* dstImage, - PalBuffer* srcBuffer, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyImageVk( - PalCommandBuffer* cmdBuffer, - PalImage* dst, - PalImage* src, - PalImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyImageToBufferVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* dstBuffer, - PalImage* srcImage, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdBindPipelineVk( - PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline); - -PalResult PAL_CALL cmdSetViewportVk( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalViewport* viewports); - -PalResult PAL_CALL cmdSetScissorsVk( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalRect2D* scissors); - -PalResult PAL_CALL cmdBindVertexBuffersVk( - PalCommandBuffer* cmdBuffer, - uint32_t firstSlot, - uint32_t count, - PalBuffer** buffers, - uint64_t* offsets); - -PalResult PAL_CALL cmdBindIndexBufferVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint64_t offset, - PalIndexType type); - -PalResult PAL_CALL cmdDrawVk( - PalCommandBuffer* cmdBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance); - -PalResult PAL_CALL cmdDrawIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - -PalResult PAL_CALL cmdDrawIndirectCountVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdDrawIndexedVk( - PalCommandBuffer* cmdBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance); - -PalResult PAL_CALL cmdDrawIndexedIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - -PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdAccelerationStructureBarrierVk( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructure* as, - PalUsageState oldUsageState, - PalUsageState newUsageState); - -PalResult PAL_CALL cmdImageBarrierVk( - PalCommandBuffer* cmdBuffer, - PalImage* image, - PalImageSubresourceRange* subresourceRange, - PalUsageState oldUsageState, - PalUsageState newUsageState); - -PalResult PAL_CALL cmdBufferBarrierVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState); - -PalResult PAL_CALL cmdDispatchVk( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDispatchBaseVk( - PalCommandBuffer* cmdBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDispatchIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer); - -PalResult PAL_CALL cmdTraceRaysVk( - PalCommandBuffer* cmdBuffer, - PalShaderBindingTable* sbt, - uint32_t raygenIndex, - uint32_t width, - uint32_t height, - uint32_t depth); - -PalResult PAL_CALL cmdTraceRaysIndirectVk( - PalCommandBuffer* cmdBuffer, - uint32_t raygenIndex, - PalShaderBindingTable* sbt, - PalBuffer* buffer); - -PalResult PAL_CALL cmdBindDescriptorSetVk( - PalCommandBuffer* cmdBuffer, - uint32_t setIndex, - PalDescriptorSet* set); - -PalResult PAL_CALL cmdPushConstantsVk( - PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, - uint32_t offset, - uint32_t size, - const void* value); - -PalResult PAL_CALL cmdSetCullModeVk( - PalCommandBuffer* cmdBuffer, - PalCullMode cullMode); - -PalResult PAL_CALL cmdSetFrontFaceVk( - PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace); - -PalResult PAL_CALL cmdSetPrimitiveTopologyVk( - PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology); - -PalResult PAL_CALL cmdSetDepthTestEnableVk( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -PalResult PAL_CALL cmdSetDepthWriteEnableVk( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -PalResult PAL_CALL cmdSetStencilOpVk( - PalCommandBuffer* cmdBuffer, - PalStencilFaceFlags faceMask, - PalStencilOp failOp, - PalStencilOp passOp, - PalStencilOp depthFailOp, - PalCompareOp compareOp); - -// ================================================== -// Acceleration Structure -// ================================================== - -PalResult PAL_CALL createAccelerationstructureVk( - PalDevice* device, - const PalAccelerationStructureCreateInfo* info, - PalAccelerationStructure** outAs); - -void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as); - -PalResult PAL_CALL getAccelerationStructureBuildSizeVk( - PalDevice* device, - PalAccelerationStructureBuildInfo* info, - PalAccelerationStructureBuildSize* size); - -// ================================================== -// Buffer -// ================================================== - -PalResult PAL_CALL createBufferVk( - PalDevice* device, - const PalBufferCreateInfo* info, - PalBuffer** outBuffer); - -void PAL_CALL destroyBufferVk(PalBuffer* buffer); - -PalResult PAL_CALL getBufferMemoryRequirementsVk( - PalBuffer* buffer, - PalMemoryRequirements* requirements); - -PalResult PAL_CALL computeInstanceBufferRequirementsVk( - PalDevice* device, - uint32_t instanceCount, - uint64_t* outSize); - -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( - PalDevice* device, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize); - -PalResult PAL_CALL writeToInstanceBufferVk( - PalDevice* device, - void* ptr, - PalAccelerationStructureInstance* instances, - uint32_t instanceCount); - -PalResult PAL_CALL writeToImageCopyStagingBufferVk( - PalDevice* device, - void* ptr, - void* srcData, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL bindBufferMemoryVk( - PalBuffer* buffer, - PalMemory* memory, - uint64_t offset); - -PalResult PAL_CALL mapBufferMemoryVk( - PalBuffer* buffer, - uint64_t offset, - uint64_t size, - void** outPtr); - -void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer); - -PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer); - -// ================================================== -// Descriptor Pool, Set and Layout -// ================================================== - -PalResult PAL_CALL createDescriptorSetLayoutVk( - PalDevice* device, - const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout); - -void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout); - -PalResult PAL_CALL createDescriptorPoolVk( - PalDevice* device, - const PalDescriptorPoolCreateInfo* info, - PalDescriptorPool** outPool); - -void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool); - -PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool); - -PalResult PAL_CALL allocateDescriptorSetVk( - PalDevice* device, - PalDescriptorPool* pool, - PalDescriptorSetLayout* layout, - PalDescriptorSet** outSet); - -PalResult PAL_CALL updateDescriptorSetVk( - PalDevice* device, - uint32_t count, - PalDescriptorSetWriteInfo* infos); - -// ================================================== -// Pipeline Layout -// ================================================== - -PalResult PAL_CALL createPipelineLayoutVk( - PalDevice* device, - const PalPipelineLayoutCreateInfo* info, - PalPipelineLayout** outLayout); - -void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout); - -// ================================================== -// Pipeline -// ================================================== - -PalResult PAL_CALL createGraphicsPipelineVk( - PalDevice* device, - const PalGraphicsPipelineCreateInfo* info, - PalPipeline** outPipeline); - -PalResult PAL_CALL createComputePipelineVk( - PalDevice* device, - const PalComputePipelineCreateInfo* info, - PalPipeline** outPipeline); - -PalResult PAL_CALL createRayTracingPipelineVk( - PalDevice* device, - const PalRayTracingPipelineCreateInfo* info, - PalPipeline** outPipeline); - -void PAL_CALL destroyPipelineVk(PalPipeline* pipeline); - -// ================================================== -// Shader Binding Table -// ================================================== - -PalResult PAL_CALL createShaderBindingTableVk( - PalDevice* device, - const PalShaderBindingTableCreateInfo* info, - PalShaderBindingTable** outSbt); - -void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt); - -PalResult PAL_CALL updateShaderBindingTableVk( - PalShaderBindingTable* sbt, - uint32_t count, - PalShaderBindingTableRecordInfo* infos); - -static PalGraphicsVtable s_VkBackend = { - // adapter - .enumerateAdapters = enumerateAdaptersVk, - .getAdapterInfo = getAdapterInfoVk, - .getAdapterCapabilities = getAdapterCapabilitiesVk, - .getAdapterFeatures = getAdapterFeaturesVk, - .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetVk, - - // device - .createDevice = createDeviceVk, - .destroyDevice = destroyDeviceVk, - - // memory - .allocateMemory = allocateMemoryVk, - .freeMemory = freeMemoryVk, - - // extended adapter features - .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesVk, - .queryMultiViewCapabilities = queryMultiViewCapabilitiesVk, - .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesVk, - .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesVk, - .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesVk, - .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesVk, - .queryRayTracingCapabilities = queryRayTracingCapabilitiesVk, - .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesVk, - - // queue - .createQueue = createQueueVk, - .destroyQueue = destroyQueueVk, - .waitQueue = waitQueueVk, - .canQueuePresent = canQueuePresentVk, - - // format - .enumerateFormats = enumerateFormatsVk, - .isFormatSupported = isFormatSupportedVk, - .queryFormatImageUsages = queryFormatImageUsagesVk, - .queryFormatSampleCount = queryFormatSampleCountVk, - - // image - .createImage = createImageVk, - .destroyImage = destroyImageVk, - .getImageInfo = getImageInfoVk, - .getImageMemoryRequirements = getImageMemoryRequirementsVk, - .bindImageMemory = bindImageMemoryVk, - .mapImageMemory = mapImageMemoryVk, - .unmapImageMemory = unmapImageMemoryVk, - - // image view - .createImageView = createImageViewVk, - .destroyImageView = destroyImageViewVk, - - // sampler - .createSampler = createSamplerVk, - .destroySampler = destroySamplerVk, - - // surface - .createSurface = createSurfaceVk, - .destroySurface = destroySurfaceVk, - .getSurfaceCapabilities = getSurfaceCapabilitiesVk, - - // swapchain - .createSwapchain = createSwapchainVk, - .destroySwapchain = destroySwapchainVk, - .getSwapchainImage = getSwapchainImageVk, - .getNextSwapchainImage = getNextSwapchainImageVk, - .presentSwapchain = presentSwapchainVk, - .resizeSwapchain = resizeSwapchainVk, - - // shader - .createShader = createShaderVk, - .destroyShader = destroyShaderVk, - - // fence - .createFence = createFenceVk, - .destroyFence = destroyFenceVk, - .waitFence = waitFenceVk, - .resetFence = resetFenceVk, - .isFenceSignaled = isFenceSignaledVk, - - // semaphore - .createSemaphore = createSemaphoreVk, - .destroySemaphore = destroySemaphoreVk, - .waitSemaphore = waitSemaphoreVk, - .signalSemaphore = signalSemaphoreVk, - .getSemaphoreValue = getSemaphoreValueVk, - - // command pool and command buffer - .createCommandPool = createCommandPoolVk, - .destroyCommandPool = destroyCommandPoolVk, - .resetCommandPool = resetCommandPoolVk, - .allocateCommandBuffer = allocateCommandBufferVk, - .freeCommandBuffer = freeCommandBufferVk, - .resetCommandBuffer = resetCommandBufferVk, - .submitCommandBuffer = submitCommandBufferVk, - - // command recording - .cmdBegin = cmdBeginVk, - .cmdEnd = cmdEndVk, - .cmdExecuteCommandBuffer = cmdExecuteCommandBufferVk, - .cmdSetFragmentShadingRate = cmdSetFragmentShadingRateVk, - .cmdDrawMeshTasks = cmdDrawMeshTasksVk, - .cmdDrawMeshTasksIndirect = cmdDrawMeshTasksIndirectVk, - .cmdDrawMeshTasksIndirectCount = cmdDrawMeshTasksIndirectCountVk, - .cmdBuildAccelerationStructure = cmdBuildAccelerationStructureVk, - .cmdBeginRendering = cmdBeginRenderingVk, - .cmdEndRendering = cmdEndRenderingVk, - .cmdCopyBuffer = cmdCopyBufferVk, - .cmdCopyBufferToImage = cmdCopyBufferToImageVk, - .cmdCopyImage = cmdCopyImageVk, - .cmdCopyImageToBuffer = cmdCopyImageToBufferVk, - .cmdBindPipeline = cmdBindPipelineVk, - .cmdSetViewport = cmdSetViewportVk, - .cmdSetScissors = cmdSetScissorsVk, - .cmdBindVertexBuffers = cmdBindVertexBuffersVk, - .cmdBindIndexBuffer = cmdBindIndexBufferVk, - .cmdDraw = cmdDrawVk, - .cmdDrawIndirect = cmdDrawIndirectVk, - .cmdDrawIndirectCount = cmdDrawIndirectCountVk, - .cmdDrawIndexed = cmdDrawIndexedVk, - .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectVk, - .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountVk, - .cmdAccelerationStructureBarrier = cmdAccelerationStructureBarrierVk, - .cmdImageBarrier = cmdImageBarrierVk, - .cmdBufferBarrier = cmdBufferBarrierVk, - .cmdDispatch = cmdDispatchVk, - .cmdDispatchBase = cmdDispatchBaseVk, - .cmdDispatchIndirect = cmdDispatchIndirectVk, - .cmdTraceRays = cmdTraceRaysVk, - .cmdTraceRaysIndirect = cmdTraceRaysIndirectVk, - .cmdBindDescriptorSet = cmdBindDescriptorSetVk, - .cmdPushConstants = cmdPushConstantsVk, - .cmdSetCullMode = cmdSetCullModeVk, - .cmdSetFrontFace = cmdSetFrontFaceVk, - .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyVk, - .cmdSetDepthTestEnable = cmdSetDepthTestEnableVk, - .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableVk, - .cmdSetStencilOp = cmdSetStencilOpVk, - - // acceleration structure - .createAccelerationstructure = createAccelerationstructureVk, - .destroyAccelerationstructure = destroyAccelerationstructureVk, - .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeVk, - - // buffer - .createBuffer = createBufferVk, - .destroyBuffer = destroyBufferVk, - .getBufferMemoryRequirements = getBufferMemoryRequirementsVk, - .computeInstanceBufferRequirements = computeInstanceBufferRequirementsVk, - .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsVk, - .writeToInstanceBuffer = writeToInstanceBufferVk, - .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferVk, - .bindBufferMemory = bindBufferMemoryVk, - .getBufferDeviceAddress = getBufferDeviceAddressVk, - .mapBufferMemory = mapBufferMemoryVk, - .unmapBufferMemory = unmapBufferMemoryVk, - - // descriptor set layout, descriptor pool and descriptor set - .createDescriptorSetLayout = createDescriptorSetLayoutVk, - .destroyDescriptorSetLayout = destroyDescriptorSetLayoutVk, - .createDescriptorPool = createDescriptorPoolVk, - .destroyDescriptorPool = destroyDescriptorPoolVk, - .resetDescriptorPool = resetDescriptorPoolVk, - .allocateDescriptorSet = allocateDescriptorSetVk, - .updateDescriptorSet = updateDescriptorSetVk, - - // pipeline layout - .createPipelineLayout = createPipelineLayoutVk, - .destroyPipelineLayout = destroyPipelineLayoutVk, - - // pipeline - .createGraphicsPipeline = createGraphicsPipelineVk, - .createComputePipeline = createComputePipelineVk, - .createRayTracingPipeline = createRayTracingPipelineVk, - .destroyPipeline = destroyPipelineVk, - - // shader binding table - .createShaderBindingTable = createShaderBindingTableVk, - .destroyShaderBindingTable = destroyShaderBindingTableVk, - .updateShaderBindingTable = updateShaderBindingTableVk}; - -// ================================================== -// D3D12 -// ================================================== - -PalResult PAL_CALL initGraphicsD3D12( - const PalGraphicsDebugger* debugger, - const PalAllocator* allocator); - -void PAL_CALL shutdownGraphicsD3D12(); - -PalResult PAL_CALL enumerateAdaptersD3D12( - int32_t* count, - PalAdapter** outAdapters); - -PalResult PAL_CALL getAdapterInfoD3D12( - PalAdapter* adapter, - PalAdapterInfo* info); - -PalResult PAL_CALL getAdapterCapabilitiesD3D12( - PalAdapter* adapter, - PalAdapterCapabilities* caps); - -PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); - -uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( - PalAdapter* adapter, - PalShaderFormats shaderFormat); - -// ================================================== -// Device -// ================================================== - -PalResult PAL_CALL createDeviceD3D12( - PalAdapter* adapter, - PalAdapterFeatures features, - PalDevice** outDevice); - -void PAL_CALL destroyDeviceD3D12(PalDevice* device); - -PalResult PAL_CALL waitDeviceD3D12(PalDevice* device); - -// ================================================== -// Memory -// ================================================== - -PalResult PAL_CALL allocateMemoryD3D12( - PalDevice* device, - PalMemoryType type, - uint64_t memoryMask, - uint64_t size, - PalMemory** outMemory); - -void PAL_CALL freeMemoryD3D12( - PalDevice* device, - PalMemory* memory); - -// ================================================== -// Extended Adapter Features -// ================================================== - -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( - PalDevice* device, - PalSamplerAnisotropyCapabilities* caps); - -PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( - PalDevice* device, - PalMultiViewCapabilities* caps); - -PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( - PalDevice* device, - PalMultiViewportCapabilities* caps); - -PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( - PalDevice* device, - PalDepthStencilCapabilities* caps); - -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( - PalDevice* device, - PalFragmentShadingRateCapabilities* caps); - -PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( - PalDevice* device, - PalMeshShaderCapabilities* caps); - -PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( - PalDevice* device, - PalRayTracingCapabilities* caps); - -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( - PalDevice* device, - PalDescriptorIndexingCapabilities* caps); - -// ================================================== -// Queue -// ================================================== - -PalResult PAL_CALL createQueueD3D12( - PalDevice* device, - PalQueueType type, - PalQueue** outQueue); - -void PAL_CALL destroyQueueD3D12(PalQueue* queue); - -PalResult PAL_CALL waitQueueD3D12(PalQueue* queue); - -PalBool PAL_CALL canQueuePresentD3D12( - PalQueue* queue, - PalSurface* surface); - -// ================================================== -// Formats -// ================================================== - -PalResult PAL_CALL enumerateFormatsD3D12( - PalAdapter* adapter, - int32_t* count, - PalFormatInfo* outFormats); - -PalBool PAL_CALL isFormatSupportedD3D12( - PalAdapter* adapter, - PalFormat format); - -PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( - PalAdapter* adapter, - PalFormat format); - -PalSampleCount PAL_CALL queryFormatSampleCountD3D12( - PalAdapter* adapter, - PalFormat format); - -// ================================================== -// Image -// ================================================== - -PalResult PAL_CALL createImageD3D12( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage); - -void PAL_CALL destroyImageD3D12(PalImage* image); - -PalResult PAL_CALL getImageInfoD3D12( - PalImage* image, - PalImageInfo* info); - -PalResult PAL_CALL getImageMemoryRequirementsD3D12( - PalImage* image, - PalMemoryRequirements* requirements); - -PalResult PAL_CALL bindImageMemoryD3D12( - PalImage* image, - PalMemory* memory, - uint64_t offset); - -PalResult PAL_CALL mapImageMemoryD3D12( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr); - -void PAL_CALL unmapImageMemoryD3D12(PalImage* image); - -// ================================================== -// Image View -// ================================================== - -PalResult PAL_CALL createImageViewD3D12( - PalDevice* device, - PalImage* image, - const PalImageViewCreateInfo* info, - PalImageView** outImageView); - -void PAL_CALL destroyImageViewD3D12(PalImageView* imageView); - -// ================================================== -// Sampler -// ================================================== - -PalResult PAL_CALL createSamplerD3D12( - PalDevice* device, - const PalSamplerCreateInfo* info, - PalSampler** outSampler); - -void PAL_CALL destroySamplerD3D12(PalSampler* sampler); - -// ================================================== -// Surface -// ================================================== - -PalResult PAL_CALL createSurfaceD3D12( - PalDevice* device, - void* window, - void* windowInstance, - PalWindowInstanceType instanceType, - PalSurface** outSurface); - -void PAL_CALL destroySurfaceD3D12(PalSurface* surface); - -PalResult PAL_CALL getSurfaceCapabilitiesD3D12( - PalDevice* device, - PalSurface* surface, - PalSurfaceCapabilities* caps); - -// ================================================== -// Swapchain -// ================================================== - -PalResult PAL_CALL createSwapchainD3D12( - PalDevice* device, - PalQueue* queue, - PalSurface* surface, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain); - -void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain); - -PalImage* PAL_CALL getSwapchainImageD3D12( - PalSwapchain* swapchain, - int32_t index); - -PalResult PAL_CALL getNextSwapchainImageD3D12( - PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, - uint32_t* outIndex); - -PalResult PAL_CALL presentSwapchainD3D12( - PalSwapchain* swapchain, - PalSwapchainPresentInfo* info); - -PalResult PAL_CALL resizeSwapchainD3D12( - PalSwapchain* swapchain, - uint32_t newWidth, - uint32_t newHeight); - -// ================================================== -// Shader -// ================================================== - -PalResult PAL_CALL createShaderD3D12( - PalDevice* device, - const PalShaderCreateInfo* info, - PalShader** outShader); - -void PAL_CALL destroyShaderD3D12(PalShader* shader); - -// ================================================== -// Fence -// ================================================== - -PalResult PAL_CALL createFenceD3D12( - PalDevice* device, - PalBool signaled, - PalFence** outFence); - -void PAL_CALL destroyFenceD3D12(PalFence* fence); - -PalResult PAL_CALL waitFenceD3D12( - PalFence* fence, - uint64_t timeout); - -PalResult PAL_CALL resetFenceD3D12(PalFence* fence); - -PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence); - -// ================================================== -// Semaphore -// ================================================== - -PalResult PAL_CALL createSemaphoreD3D12( - PalDevice* device, - PalBool enableTimeline, - PalSemaphore** outSemaphore); - -void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); - -PalResult PAL_CALL waitSemaphoreD3D12( - PalSemaphore* semaphore, - uint64_t value, - uint64_t timeout); - -PalResult PAL_CALL signalSemaphoreD3D12( - PalSemaphore* semaphore, - PalQueue* queue, - uint64_t value); - -PalResult PAL_CALL getSemaphoreValueD3D12( - PalSemaphore* semaphore, - uint64_t* outValue); - -// ================================================== -// Command Pool And Buffer -// ================================================== - -PalResult PAL_CALL createCommandPoolD3D12( - PalDevice* device, - PalQueue* queue, - PalCommandPool** outPool); - -void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool); - -PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool); - -PalResult PAL_CALL allocateCommandBufferD3D12( - PalDevice* device, - PalCommandPool* pool, - PalCommandBufferType type, - PalCommandBuffer** outCmdBuffer); - -void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL submitCommandBufferD3D12( - PalQueue* queue, - PalCommandBufferSubmitInfo* info); - -// ================================================== -// Command Recording -// ================================================== - -PalResult PAL_CALL cmdBeginD3D12( - PalCommandBuffer* cmdBuffer, - PalRenderingLayoutInfo* info); - -PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL cmdExecuteCommandBufferD3D12( - PalCommandBuffer* primaryCmdBuffer, - PalCommandBuffer* secondaryCmdBuffer); - -PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( - PalCommandBuffer* cmdBuffer, - PalFragmentShadingRateState* state); - -PalResult PAL_CALL cmdDrawMeshTasksD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t drawCount); - -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructureBuildInfo* info); - -PalResult PAL_CALL cmdBeginRenderingD3D12( - PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info); - -PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL cmdCopyBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* dst, - PalBuffer* src, - PalBufferCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyBufferToImageD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* dstImage, - PalBuffer* srcBuffer, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyImageD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* dst, - PalImage* src, - PalImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyImageToBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* dstBuffer, - PalImage* srcImage, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdBindPipelineD3D12( - PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline); - -PalResult PAL_CALL cmdSetViewportD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalViewport* viewports); - -PalResult PAL_CALL cmdSetScissorsD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalRect2D* scissors); - -PalResult PAL_CALL cmdBindVertexBuffersD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t firstSlot, - uint32_t count, - PalBuffer** buffers, - uint64_t* offsets); - -PalResult PAL_CALL cmdBindIndexBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint64_t offset, - PalIndexType type); - -PalResult PAL_CALL cmdDrawD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance); - -PalResult PAL_CALL cmdDrawIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - -PalResult PAL_CALL cmdDrawIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdDrawIndexedD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance); - -PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - -PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructure* as, - PalUsageState oldUsageState, - PalUsageState newUsageState); - -PalResult PAL_CALL cmdImageBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* image, - PalImageSubresourceRange* subresourceRange, - PalUsageState oldUsageState, - PalUsageState newUsageState); - -PalResult PAL_CALL cmdBufferBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState); - -PalResult PAL_CALL cmdDispatchD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDispatchBaseD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDispatchIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer); - -PalResult PAL_CALL cmdTraceRaysD3D12( - PalCommandBuffer* cmdBuffer, - PalShaderBindingTable* sbt, - uint32_t raygenIndex, - uint32_t width, - uint32_t height, - uint32_t depth); - -PalResult PAL_CALL cmdTraceRaysIndirectD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t raygenIndex, - PalShaderBindingTable* sbt, - PalBuffer* buffer); - -PalResult PAL_CALL cmdBindDescriptorSetD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t setIndex, - PalDescriptorSet* set); - -PalResult PAL_CALL cmdPushConstantsD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, - uint32_t offset, - uint32_t size, - const void* value); - -PalResult PAL_CALL cmdSetCullModeD3D12( - PalCommandBuffer* cmdBuffer, - PalCullMode cullMode); - -PalResult PAL_CALL cmdSetFrontFaceD3D12( - PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace); - -PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( - PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology); - -PalResult PAL_CALL cmdSetDepthTestEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -PalResult PAL_CALL cmdSetStencilOpD3D12( - PalCommandBuffer* cmdBuffer, - PalStencilFaceFlags faceMask, - PalStencilOp failOp, - PalStencilOp passOp, - PalStencilOp depthFailOp, - PalCompareOp compareOp); - -// ================================================== -// Acceleration Structure -// ================================================== - -PalResult PAL_CALL createAccelerationstructureD3D12( - PalDevice* device, - const PalAccelerationStructureCreateInfo* info, - PalAccelerationStructure** outAs); - -void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as); - -PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( - PalDevice* device, - PalAccelerationStructureBuildInfo* info, - PalAccelerationStructureBuildSize* size); - -// ================================================== -// Buffer -// ================================================== - -PalResult PAL_CALL createBufferD3D12( - PalDevice* device, - const PalBufferCreateInfo* info, - PalBuffer** outBuffer); - -void PAL_CALL destroyBufferD3D12(PalBuffer* buffer); - -PalResult PAL_CALL getBufferMemoryRequirementsD3D12( - PalBuffer* buffer, - PalMemoryRequirements* requirements); - -PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( - PalDevice* device, - uint32_t instanceCount, - uint64_t* outSize); - -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( - PalDevice* device, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize); - -PalResult PAL_CALL writeToInstanceBufferD3D12( - PalDevice* device, - void* ptr, - PalAccelerationStructureInstance* instances, - uint32_t instanceCount); - -PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( - PalDevice* device, - void* ptr, - void* srcData, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL bindBufferMemoryD3D12( - PalBuffer* buffer, - PalMemory* memory, - uint64_t offset); - -PalResult PAL_CALL mapBufferMemoryD3D12( - PalBuffer* buffer, - uint64_t offset, - uint64_t size, - void** outPtr); - -void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer); - -PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); - -// ================================================== -// Descriptor Pool, Set and Layout -// ================================================== - -PalResult PAL_CALL createDescriptorSetLayoutD3D12( - PalDevice* device, - const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout); - -void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout); - -PalResult PAL_CALL createDescriptorPoolD3D12( - PalDevice* device, - const PalDescriptorPoolCreateInfo* info, - PalDescriptorPool** outPool); - -void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool); - -PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool); - -PalResult PAL_CALL allocateDescriptorSetD3D12( - PalDevice* device, - PalDescriptorPool* pool, - PalDescriptorSetLayout* layout, - PalDescriptorSet** outSet); - -PalResult PAL_CALL updateDescriptorSetD3D12( - PalDevice* device, - uint32_t count, - PalDescriptorSetWriteInfo* infos); - -// ================================================== -// Pipeline Layout -// ================================================== - -PalResult PAL_CALL createPipelineLayoutD3D12( - PalDevice* device, - const PalPipelineLayoutCreateInfo* info, - PalPipelineLayout** outLayout); - -void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout); - -// ================================================== -// Pipeline -// ================================================== - -PalResult PAL_CALL createGraphicsPipelineD3D12( - PalDevice* device, - const PalGraphicsPipelineCreateInfo* info, - PalPipeline** outPipeline); - -PalResult PAL_CALL createComputePipelineD3D12( - PalDevice* device, - const PalComputePipelineCreateInfo* info, - PalPipeline** outPipeline); - -PalResult PAL_CALL createRayTracingPipelineD3D12( - PalDevice* device, - const PalRayTracingPipelineCreateInfo* info, - PalPipeline** outPipeline); - -void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline); - -// ================================================== -// Shader Binding Table -// ================================================== - -PalResult PAL_CALL createShaderBindingTableD3D12( - PalDevice* device, - const PalShaderBindingTableCreateInfo* info, - PalShaderBindingTable** outSbt); - -void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); - -PalResult PAL_CALL updateShaderBindingTableD3D12( - PalShaderBindingTable* sbt, - uint32_t count, - PalShaderBindingTableRecordInfo* infos); - -static PalGraphicsVtable s_D3D12Backend = { - // adapter - .enumerateAdapters = enumerateAdaptersD3D12, - .getAdapterInfo = getAdapterInfoD3D12, - .getAdapterCapabilities = getAdapterCapabilitiesD3D12, - .getAdapterFeatures = getAdapterFeaturesD3D12, - .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetD3D12, - - // device - .createDevice = createDeviceD3D12, - .destroyDevice = destroyDeviceD3D12, - - // memory - .allocateMemory = allocateMemoryD3D12, - .freeMemory = freeMemoryD3D12, - - // extended adapter features - .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesD3D12, - .queryMultiViewCapabilities = queryMultiViewCapabilitiesD3D12, - .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesD3D12, - .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesD3D12, - .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesD3D12, - .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesD3D12, - .queryRayTracingCapabilities = queryRayTracingCapabilitiesD3D12, - .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesD3D12, - - // queue - .createQueue = createQueueD3D12, - .destroyQueue = destroyQueueD3D12, - .waitQueue = waitQueueD3D12, - .canQueuePresent = canQueuePresentD3D12, - - // format - .enumerateFormats = enumerateFormatsD3D12, - .isFormatSupported = isFormatSupportedD3D12, - .queryFormatImageUsages = queryFormatImageUsagesD3D12, - .queryFormatSampleCount = queryFormatSampleCountD3D12, - - // image - .createImage = createImageD3D12, - .destroyImage = destroyImageD3D12, - .getImageInfo = getImageInfoD3D12, - .getImageMemoryRequirements = getImageMemoryRequirementsD3D12, - .bindImageMemory = bindImageMemoryD3D12, - .mapImageMemory = mapImageMemoryD3D12, - .unmapImageMemory = unmapImageMemoryD3D12, - - // image view - .createImageView = createImageViewD3D12, - .destroyImageView = destroyImageViewD3D12, - - // sampler - .createSampler = createSamplerD3D12, - .destroySampler = destroySamplerD3D12, - - // surface - .createSurface = createSurfaceD3D12, - .destroySurface = destroySurfaceD3D12, - .getSurfaceCapabilities = getSurfaceCapabilitiesD3D12, - - // swapchain - .createSwapchain = createSwapchainD3D12, - .destroySwapchain = destroySwapchainD3D12, - .getSwapchainImage = getSwapchainImageD3D12, - .getNextSwapchainImage = getNextSwapchainImageD3D12, - .presentSwapchain = presentSwapchainD3D12, - .resizeSwapchain = resizeSwapchainD3D12, - - // shader - .createShader = createShaderD3D12, - .destroyShader = destroyShaderD3D12, - - // fence - .createFence = createFenceD3D12, - .destroyFence = destroyFenceD3D12, - .waitFence = waitFenceD3D12, - .resetFence = resetFenceD3D12, - .isFenceSignaled = isFenceSignaledD3D12, - - // semaphore - .createSemaphore = createSemaphoreD3D12, - .destroySemaphore = destroySemaphoreD3D12, - .waitSemaphore = waitSemaphoreD3D12, - .signalSemaphore = signalSemaphoreD3D12, - .getSemaphoreValue = getSemaphoreValueD3D12, - - // command pool and command buffer - .createCommandPool = createCommandPoolD3D12, - .destroyCommandPool = destroyCommandPoolD3D12, - .resetCommandPool = resetCommandPoolD3D12, - .allocateCommandBuffer = allocateCommandBufferD3D12, - .freeCommandBuffer = freeCommandBufferD3D12, - .resetCommandBuffer = resetCommandBufferD3D12, - .submitCommandBuffer = submitCommandBufferD3D12, - - // command recording - .cmdBegin = cmdBeginD3D12, - .cmdEnd = cmdEndD3D12, - .cmdExecuteCommandBuffer = cmdExecuteCommandBufferD3D12, - .cmdSetFragmentShadingRate = cmdSetFragmentShadingRateD3D12, - .cmdDrawMeshTasks = cmdDrawMeshTasksD3D12, - .cmdDrawMeshTasksIndirect = cmdDrawMeshTasksIndirectD3D12, - .cmdDrawMeshTasksIndirectCount = cmdDrawMeshTasksIndirectCountD3D12, - .cmdBuildAccelerationStructure = cmdBuildAccelerationStructureD3D12, - .cmdBeginRendering = cmdBeginRenderingD3D12, - .cmdEndRendering = cmdEndRenderingD3D12, - .cmdCopyBuffer = cmdCopyBufferD3D12, - .cmdCopyBufferToImage = cmdCopyBufferToImageD3D12, - .cmdCopyImage = cmdCopyImageD3D12, - .cmdCopyImageToBuffer = cmdCopyImageToBufferD3D12, - .cmdBindPipeline = cmdBindPipelineD3D12, - .cmdSetViewport = cmdSetViewportD3D12, - .cmdSetScissors = cmdSetScissorsD3D12, - .cmdBindVertexBuffers = cmdBindVertexBuffersD3D12, - .cmdBindIndexBuffer = cmdBindIndexBufferD3D12, - .cmdDraw = cmdDrawD3D12, - .cmdDrawIndirect = cmdDrawIndirectD3D12, - .cmdDrawIndirectCount = cmdDrawIndirectCountD3D12, - .cmdDrawIndexed = cmdDrawIndexedD3D12, - .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectD3D12, - .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountD3D12, - .cmdAccelerationStructureBarrier = cmdAccelerationStructureBarrierD3D12, - .cmdImageBarrier = cmdImageBarrierD3D12, - .cmdBufferBarrier = cmdBufferBarrierD3D12, - .cmdDispatch = cmdDispatchD3D12, - .cmdDispatchBase = cmdDispatchBaseD3D12, - .cmdDispatchIndirect = cmdDispatchIndirectD3D12, - .cmdTraceRays = cmdTraceRaysD3D12, - .cmdTraceRaysIndirect = cmdTraceRaysIndirectD3D12, - .cmdBindDescriptorSet = cmdBindDescriptorSetD3D12, - .cmdPushConstants = cmdPushConstantsD3D12, - .cmdSetCullMode = cmdSetCullModeD3D12, - .cmdSetFrontFace = cmdSetFrontFaceD3D12, - .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyD3D12, - .cmdSetDepthTestEnable = cmdSetDepthTestEnableD3D12, - .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableD3D12, - .cmdSetStencilOp = cmdSetStencilOpD3D12, - - // acceleration structure - .createAccelerationstructure = createAccelerationstructureD3D12, - .destroyAccelerationstructure = destroyAccelerationstructureD3D12, - .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeD3D12, - - // buffer - .createBuffer = createBufferD3D12, - .destroyBuffer = destroyBufferD3D12, - .getBufferMemoryRequirements = getBufferMemoryRequirementsD3D12, - .computeInstanceBufferRequirements = computeInstanceBufferRequirementsD3D12, - .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsD3D12, - .writeToInstanceBuffer = writeToInstanceBufferD3D12, - .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferD3D12, - .bindBufferMemory = bindBufferMemoryD3D12, - .getBufferDeviceAddress = getBufferDeviceAddressD3D12, - .mapBufferMemory = mapBufferMemoryD3D12, - .unmapBufferMemory = unmapBufferMemoryD3D12, - - // descriptor set layout, descriptor pool and descriptor set - .createDescriptorSetLayout = createDescriptorSetLayoutD3D12, - .destroyDescriptorSetLayout = destroyDescriptorSetLayoutD3D12, - .createDescriptorPool = createDescriptorPoolD3D12, - .destroyDescriptorPool = destroyDescriptorPoolD3D12, - .resetDescriptorPool = resetDescriptorPoolD3D12, - .allocateDescriptorSet = allocateDescriptorSetD3D12, - .updateDescriptorSet = updateDescriptorSetD3D12, - - // pipeline layout - .createPipelineLayout = createPipelineLayoutD3D12, - .destroyPipelineLayout = destroyPipelineLayoutD3D12, - - // pipeline - .createGraphicsPipeline = createGraphicsPipelineD3D12, - .createComputePipeline = createComputePipelineD3D12, - .createRayTracingPipeline = createRayTracingPipelineD3D12, - .destroyPipeline = destroyPipelineD3D12, - - // shader binding tables - .createShaderBindingTable = createShaderBindingTableD3D12, - .destroyShaderBindingTable = destroyShaderBindingTableD3D12, - .updateShaderBindingTable = updateShaderBindingTableD3D12}; - -#endif // _PAL_BACKENDS_GRAPHICS_H \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 430215f5..55104a52 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -5,29 +5,7 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal_backends_graphics.h" -#include "pal_shared.h" - -#ifdef _WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // WIN32_LEAN_AND_MEAN - -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -// set unicode -#ifndef UNICODE -#define UNICODE -#endif // UNICODE - -#include -#define PLATFORM_SOURCE PAL_RESULT_SOURCE_WINDOWS -#elif defined(__linux__) -#include -#define PLATFORM_SOURCE PAL_RESULT_SOURCE_LINUX -#endif // _WIN32 +#include "pal_graphics_backends.h" #define MAX_BACKENDS (PAL_MAX_CUSTOM_BACKENDS + 2) #define PAL_HANDLE(name) \ @@ -476,15 +454,6 @@ static void addBackend(PalGraphicsBackendInfo* backendInfo) } } -static inline uint32_t getLastErrorCode() -{ -#ifdef _WIN32 - return (uint32_t)GetLastError(); -#elif defined(__linux__) - return (uint32_t)errno; -#endif // _WIN32 -} - PalResult PAL_CALL palInitGraphics( const PalGraphicsDebugger* debugger, const PalAllocator* allocator, @@ -495,11 +464,12 @@ PalResult PAL_CALL palInitGraphics( return PAL_RESULT_SUCCESS; } + if (customBackendCount == 0) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + if (allocator && (!allocator->allocate || !allocator->free)) { - return palMakeResult( - PAL_RESULT_INVALID_ARGUMENT, - PLATFORM_SOURCE, - getLastErrorCode()); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -594,11 +564,11 @@ PalResult PAL_CALL palEnumerateAdapters( { // enumerate all adapters for both custom and PAL backends if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!count || *count == 0 && outAdapters) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -648,11 +618,11 @@ PalResult PAL_CALL palGetAdapterInfo( PalAdapterInfo* info) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!adapter || !info) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return adapter->backend->getAdapterInfo(adapter, info); @@ -663,11 +633,11 @@ PalResult PAL_CALL palGetAdapterCapabilities( PalAdapterCapabilities* caps) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!adapter || !caps) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return adapter->backend->getAdapterCapabilities(adapter, caps); @@ -678,7 +648,6 @@ PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) if (!s_Graphics.initialized || !adapter) { return 0; } - return adapter->backend->getAdapterFeatures(adapter); } @@ -702,11 +671,11 @@ PalResult PAL_CALL palCreateDevice( PalDevice** outDevice) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!outDevice) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalDevice* device = nullptr; @@ -736,11 +705,11 @@ PalResult PAL_CALL palAllocateMemory( PalMemory** outMemory) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!outMemory || !device) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->allocateMemory(device, type, memoryMask, size, outMemory); @@ -764,11 +733,11 @@ PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( PalSamplerAnisotropyCapabilities* caps) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !caps) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->querySamplerAnisotropyCapabilities(device, caps); @@ -779,11 +748,11 @@ PalResult PAL_CALL palQueryMultiViewCapabilities( PalMultiViewCapabilities* caps) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !caps) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->queryMultiViewCapabilities(device, caps); @@ -794,11 +763,11 @@ PalResult PAL_CALL palQueryMultiViewportCapabilities( PalMultiViewportCapabilities* caps) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !caps) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->queryMultiViewportCapabilities(device, caps); @@ -809,11 +778,11 @@ PalResult PAL_CALL palQueryDepthStencilCapabilities( PalDepthStencilCapabilities* caps) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !caps) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->queryDepthStencilCapabilities(device, caps); @@ -824,11 +793,11 @@ PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( PalFragmentShadingRateCapabilities* caps) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !caps) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->queryFragmentShadingRateCapabilities(device, caps); @@ -839,11 +808,11 @@ PalResult PAL_CALL palQueryMeshShaderCapabilities( PalMeshShaderCapabilities* caps) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !caps) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->queryMeshShaderCapabilities(device, caps); @@ -854,11 +823,11 @@ PalResult PAL_CALL palQueryRayTracingCapabilities( PalRayTracingCapabilities* caps) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !caps) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->queryRayTracingCapabilities(device, caps); @@ -869,11 +838,11 @@ PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( PalDescriptorIndexingCapabilities* caps) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !caps) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->queryDescriptorIndexingCapabilities(device, caps); @@ -889,11 +858,11 @@ PalResult PAL_CALL palCreateQueue( PalQueue** outQueue) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !outQueue) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalQueue* queue = nullptr; @@ -928,11 +897,11 @@ PalBool PAL_CALL palCanQueuePresent( PalResult PAL_CALL palWaitQueue(PalQueue* queue) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!queue) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return queue->backend->waitQueue(queue); @@ -948,11 +917,11 @@ PalResult PAL_CALL palEnumerateFormats( PalFormatInfo* outFormats) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!adapter || !count || *count == 0 && outFormats) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return adapter->backend->enumerateFormats(adapter, count, outFormats); @@ -1001,11 +970,11 @@ PalResult PAL_CALL palCreateImage( PalImage** outImage) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outImage) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalImage* image = nullptr; @@ -1032,11 +1001,11 @@ PalResult PAL_CALL palGetImageInfo( PalImageInfo* info) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!image || !info) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return image->backend->getImageInfo(image, info); @@ -1047,11 +1016,11 @@ PalResult PAL_CALL palGetImageMemoryRequirements( PalMemoryRequirements* requirements) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!image) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return image->backend->getImageMemoryRequirements(image, requirements); @@ -1063,11 +1032,11 @@ PalResult PAL_CALL palBindImageMemory( uint64_t offset) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!image || !memory) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return image->backend->bindImageMemory(image, memory, offset); @@ -1080,11 +1049,11 @@ PalResult PAL_CALL palMapImageMemory( void** outPtr) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!image) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return image->backend->mapImageMemory(image, offset, size, outPtr); @@ -1108,11 +1077,11 @@ PalResult PAL_CALL palCreateImageView( PalImageView** outImageView) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !image || !info || !outImageView) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalImageView* imageView = nullptr; @@ -1144,11 +1113,11 @@ PalResult PAL_CALL palCreateSampler( PalSampler** outSampler) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outSampler) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalSampler* sampler = nullptr; @@ -1182,11 +1151,11 @@ PalResult PAL_CALL palCreateSurface( PalSurface** outSurface) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !window || !outSurface) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalSurface* surface = nullptr; @@ -1214,11 +1183,11 @@ PalResult PAL_CALL palGetSurfaceCapabilities( PalSurfaceCapabilities* caps) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !surface || !caps) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->getSurfaceCapabilities(device, surface, caps); @@ -1236,11 +1205,11 @@ PalResult PAL_CALL palCreateSwapchain( PalSwapchain** outSwapchain) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !queue || !surface || !info || !outSwapchain) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -1285,11 +1254,11 @@ PalResult PAL_CALL palGetNextSwapchainImage( uint32_t* outIndex) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!swapchain || !info) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return swapchain->backend->getNextSwapchainImage(swapchain, info, outIndex); @@ -1300,11 +1269,11 @@ PalResult PAL_CALL palPresentSwapchain( PalSwapchainPresentInfo* info) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!swapchain || !info) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return swapchain->backend->presentSwapchain(swapchain, info); @@ -1316,11 +1285,11 @@ PalResult PAL_CALL palResizeSwapchain( uint32_t newHeight) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!swapchain) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return swapchain->backend->resizeSwapchain(swapchain, newWidth, newHeight); @@ -1336,11 +1305,11 @@ PalResult PAL_CALL palCreateShader( PalShader** outShader) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outShader) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalShader* shader = nullptr; @@ -1372,11 +1341,11 @@ PalResult PAL_CALL palCreateFence( PalFence** outFence) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !outFence) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalFence* fence = nullptr; @@ -1403,11 +1372,11 @@ PalResult PAL_CALL palWaitFence( uint64_t timeout) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!fence) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return fence->backend->waitFence(fence, timeout); @@ -1416,11 +1385,11 @@ PalResult PAL_CALL palWaitFence( PalResult PAL_CALL palResetFence(PalFence* fence) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!fence) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return fence->backend->resetFence(fence); @@ -1444,11 +1413,11 @@ PalResult PAL_CALL palCreateSemaphore( PalSemaphore** outSemaphore) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !outSemaphore) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalSemaphore* semaphore = nullptr; @@ -1476,11 +1445,11 @@ PalResult PAL_CALL palWaitSemaphore( uint64_t timeout) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!semaphore) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return semaphore->backend->waitSemaphore(semaphore, value, timeout); @@ -1492,11 +1461,11 @@ PalResult PAL_CALL palSignalSemaphore( uint64_t value) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!semaphore || !queue) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return semaphore->backend->signalSemaphore(semaphore, queue, value); @@ -1507,11 +1476,11 @@ PalResult PAL_CALL palGetSemaphoreValue( uint64_t* outValue) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!semaphore || !outValue) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return semaphore->backend->getSemaphoreValue(semaphore, outValue); @@ -1527,11 +1496,11 @@ PalResult PAL_CALL palCreateCommandPool( PalCommandPool** outPool) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !queue || !outPool) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalCommandPool* pool = nullptr; @@ -1556,11 +1525,11 @@ void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!pool) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return pool->backend->resetCommandPool(pool); @@ -1573,11 +1542,11 @@ PalResult PAL_CALL palAllocateCommandBuffer( PalCommandBuffer** outCmdBuffer) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !pool || !outCmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalCommandBuffer* cmdBuffer = nullptr; @@ -1602,11 +1571,11 @@ void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->resetCommandBuffer(cmdBuffer); @@ -1617,11 +1586,11 @@ PalResult PAL_CALL palSubmitCommandBuffer( PalCommandBufferSubmitInfo* info) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!queue || !info) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return queue->backend->submitCommandBuffer(queue, info); @@ -1636,11 +1605,11 @@ PalResult PAL_CALL palCmdBegin( PalRenderingLayoutInfo* info) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdBegin(cmdBuffer, info); @@ -1649,11 +1618,11 @@ PalResult PAL_CALL palCmdBegin( PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdEnd(cmdBuffer); @@ -1664,11 +1633,11 @@ PalResult PAL_CALL palCmdExecuteCommandBuffer( PalCommandBuffer* secondaryCmdBuffer) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!primaryCmdBuffer || !secondaryCmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return primaryCmdBuffer->backend->cmdExecuteCommandBuffer(primaryCmdBuffer, secondaryCmdBuffer); @@ -1679,11 +1648,11 @@ PalResult PAL_CALL palCmdSetFragmentShadingRate( PalFragmentShadingRateState* state) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !state) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdSetFragmentShadingRate(cmdBuffer, state); @@ -1696,11 +1665,11 @@ PalResult PAL_CALL palCmdDrawMeshTasks( uint32_t groupCountZ) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdDrawMeshTasks(cmdBuffer, groupCountX, groupCountY, groupCountZ); @@ -1712,11 +1681,11 @@ PalResult PAL_CALL palCmdDrawMeshTasksIndirect( uint32_t drawCount) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !buffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdDrawMeshTasksIndirect(cmdBuffer, buffer, drawCount); @@ -1729,11 +1698,11 @@ PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( uint32_t maxDrawCount) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !buffer || !countBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend @@ -1745,15 +1714,15 @@ PalResult PAL_CALL palCmdBuildAccelerationStructure( PalAccelerationStructureBuildInfo* info) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } - if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + if (!cmdBuffer || !info) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (!info->dst || info->scratchBufferAddress == 0) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdBuildAccelerationStructure(cmdBuffer, info); @@ -1764,11 +1733,11 @@ PalResult PAL_CALL palCmdBeginRendering( PalRenderingInfo* info) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !info) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdBeginRendering(cmdBuffer, info); @@ -1777,11 +1746,11 @@ PalResult PAL_CALL palCmdBeginRendering( PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdEndRendering(cmdBuffer); @@ -1794,11 +1763,11 @@ PalResult PAL_CALL palCmdCopyBuffer( PalBufferCopyInfo* copyInfo) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !dst || !src || !copyInfo) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdCopyBuffer(cmdBuffer, dst, src, copyInfo); @@ -1811,11 +1780,11 @@ PalResult PAL_CALL palCmdCopyBufferToImage( PalBufferImageCopyInfo* copyInfo) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !dstImage || !srcBuffer || !copyInfo) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdCopyBufferToImage(cmdBuffer, dstImage, srcBuffer, copyInfo); @@ -1828,11 +1797,11 @@ PalResult PAL_CALL palCmdCopyImage( PalImageCopyInfo* copyInfo) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !dst || !src || !copyInfo) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdCopyImage(cmdBuffer, dst, src, copyInfo); @@ -1845,11 +1814,11 @@ PalResult PAL_CALL palCmdCopyImageToBuffer( PalBufferImageCopyInfo* copyInfo) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !dstBuffer || !srcImage || !copyInfo) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdCopyImageToBuffer(cmdBuffer, dstBuffer, srcImage, copyInfo); @@ -1860,11 +1829,11 @@ PalResult PAL_CALL palCmdBindPipeline( PalPipeline* pipeline) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !pipeline) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdBindPipeline(cmdBuffer, pipeline); @@ -1876,11 +1845,11 @@ PalResult PAL_CALL palCmdSetViewport( PalViewport* viewports) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !viewports || !count) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdSetViewport(cmdBuffer, count, viewports); @@ -1892,11 +1861,11 @@ PalResult PAL_CALL palCmdSetScissors( PalRect2D* scissors) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !scissors || !count) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdSetScissors(cmdBuffer, count, scissors); @@ -1910,11 +1879,11 @@ PalResult PAL_CALL palCmdBindVertexBuffers( uint64_t* offsets) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !buffers || !offsets) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdBindVertexBuffers(cmdBuffer, firstSlot, count, buffers, offsets); @@ -1927,11 +1896,11 @@ PalResult PAL_CALL palCmdBindIndexBuffer( PalIndexType type) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !buffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdBindIndexBuffer(cmdBuffer, buffer, offset, type); @@ -1945,11 +1914,11 @@ PalResult PAL_CALL palCmdDraw( uint32_t firstInstance) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend @@ -1962,11 +1931,11 @@ PalResult PAL_CALL palCmdDrawIndirect( uint32_t count) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !buffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdDrawIndirect(cmdBuffer, buffer, count); @@ -1979,11 +1948,11 @@ PalResult PAL_CALL palCmdDrawIndirectCount( uint32_t maxDrawCount) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !buffer || !countBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdDrawIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); @@ -1998,11 +1967,11 @@ PalResult PAL_CALL palCmdDrawIndexed( uint32_t firstInstance) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdDrawIndexed( @@ -2020,11 +1989,11 @@ PalResult PAL_CALL palCmdDrawIndexedIndirect( uint32_t count) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !buffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdDrawIndexedIndirect(cmdBuffer, buffer, count); @@ -2037,11 +2006,11 @@ PalResult PAL_CALL palCmdDrawIndexedIndirectCount( uint32_t maxDrawCount) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !buffer || !countBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend @@ -2055,11 +2024,11 @@ PalResult PAL_CALL palCmdAccelerationStructureBarrier( PalUsageState newUsageState) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !as) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend @@ -2074,11 +2043,11 @@ PalResult PAL_CALL palCmdImageBarrier( PalUsageState newUsageState) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !image || !subresourceRange) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend @@ -2092,11 +2061,11 @@ PalResult PAL_CALL palCmdBufferBarrier( PalUsageState newUsageState) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !buffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend @@ -2110,11 +2079,11 @@ PalResult PAL_CALL palCmdDispatch( uint32_t groupCountZ) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); @@ -2130,11 +2099,11 @@ PalResult PAL_CALL palCmdDispatchBase( uint32_t groupCountZ) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdDispatchBase( @@ -2152,11 +2121,11 @@ PalResult PAL_CALL palCmdDispatchIndirect( PalBuffer* buffer) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !buffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdDispatchIndirect(cmdBuffer, buffer); @@ -2171,11 +2140,11 @@ PalResult PAL_CALL palCmdTraceRays( uint32_t depth) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !sbt) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdTraceRays(cmdBuffer, sbt, raygenIndex, width, height, depth); @@ -2188,11 +2157,11 @@ PalResult PAL_CALL palCmdTraceRaysIndirect( PalBuffer* buffer) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !sbt || !buffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdTraceRaysIndirect(cmdBuffer, raygenIndex, sbt, buffer); @@ -2204,11 +2173,11 @@ PalResult PAL_CALL palCmdBindDescriptorSet( PalDescriptorSet* set) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer || !set) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdBindDescriptorSet(cmdBuffer, setIndex, set); @@ -2216,29 +2185,19 @@ PalResult PAL_CALL palCmdBindDescriptorSet( PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, uint32_t offset, uint32_t size, const void* value) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } - if (!cmdBuffer || !shaderStages || !value) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + if (!cmdBuffer || !value) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; } - // clang-format off - return cmdBuffer->backend->cmdPushConstants( - cmdBuffer, - shaderStageCount, - shaderStages, - offset, - size, - value); - // clang-format on + return cmdBuffer->backend->cmdPushConstants(cmdBuffer, offset, size, value); } PalResult PAL_CALL palCmdSetCullMode( @@ -2246,11 +2205,11 @@ PalResult PAL_CALL palCmdSetCullMode( PalCullMode cullMode) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdSetCullMode(cmdBuffer, cullMode); @@ -2261,11 +2220,11 @@ PalResult PAL_CALL palCmdSetFrontFace( PalFrontFace frontFace) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdSetFrontFace(cmdBuffer, frontFace); @@ -2276,11 +2235,11 @@ PalResult PAL_CALL palCmdSetPrimitiveTopology( PalPrimitiveTopology topology) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdSetPrimitiveTopology(cmdBuffer, topology); @@ -2291,11 +2250,11 @@ PalResult PAL_CALL palCmdSetDepthTestEnable( PalBool enable) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdSetDepthTestEnable(cmdBuffer, enable); @@ -2306,11 +2265,11 @@ PalResult PAL_CALL palCmdSetDepthWriteEnable( PalBool enable) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend->cmdSetDepthWriteEnable(cmdBuffer, enable); @@ -2325,11 +2284,11 @@ PalResult PAL_CALL palCmdSetStencilOp( PalCompareOp compareOp) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!cmdBuffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return cmdBuffer->backend @@ -2346,15 +2305,15 @@ PalResult PAL_CALL palCreateAccelerationstructure( PalAccelerationStructure** outAs) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outAs) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (!info->buffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -2382,11 +2341,11 @@ PalResult PAL_CALL palGetAccelerationStructureBuildSize( PalAccelerationStructureBuildSize* size) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !size) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->getAccelerationStructureBuildSize(device, info, size); @@ -2402,11 +2361,11 @@ PalResult PAL_CALL palCreateBuffer( PalBuffer** outBuffer) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -2433,11 +2392,11 @@ PalResult PAL_CALL palGetBufferMemoryRequirements( PalMemoryRequirements* requirements) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!buffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return buffer->backend->getBufferMemoryRequirements(buffer, requirements); @@ -2449,11 +2408,11 @@ PalResult PAL_CALL palComputeInstanceBufferRequirements( uint64_t* outSize) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !outSize) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->computeInstanceBufferRequirements(device, instanceCount, outSize); @@ -2468,19 +2427,19 @@ PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( uint64_t* outSize) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !outBufferRowLength || !outBufferImageHeight || !outSize) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (copyInfo->bufferRowLength < copyInfo->imageWidth && copyInfo->bufferRowLength) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (copyInfo->bufferImageHeight < copyInfo->imageHeight && copyInfo->bufferImageHeight) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->computeImageCopyStagingBufferRequirements( @@ -2499,11 +2458,11 @@ PalResult PAL_CALL palWriteToInstanceBuffer( uint32_t instanceCount) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !ptr || !instances || instanceCount == 0) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } // since all tlas have backend pointer, we use the first one @@ -2518,19 +2477,19 @@ PalResult PAL_CALL palWriteToImageCopyStagingBuffer( PalBufferImageCopyInfo* copyInfo) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !ptr || !srcData || !copyInfo) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (copyInfo->bufferRowLength < copyInfo->imageWidth && copyInfo->bufferRowLength) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (copyInfo->bufferImageHeight < copyInfo->imageHeight && copyInfo->bufferImageHeight) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend @@ -2543,11 +2502,11 @@ PalResult PAL_CALL palBindBufferMemory( uint64_t offset) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!buffer || !memory) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return buffer->backend->bindBufferMemory(buffer, memory, offset); @@ -2560,11 +2519,11 @@ PalResult PAL_CALL palMapBufferMemory( void** outPtr) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!buffer) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return buffer->backend->mapBufferMemory(buffer, offset, size, outPtr); @@ -2595,11 +2554,11 @@ PalResult PAL_CALL palCreateDescriptorSetLayout( PalDescriptorSetLayout** outLayout) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outLayout) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -2627,15 +2586,15 @@ PalResult PAL_CALL palCreateDescriptorPool( PalDescriptorPool** outPool) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outPool) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (!info->maxDescriptorSets) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -2660,11 +2619,11 @@ void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool) PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!pool) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return pool->backend->resetDescriptorPool(pool); @@ -2677,11 +2636,11 @@ PalResult PAL_CALL palAllocateDescriptorSet( PalDescriptorSet** outSet) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !pool || !layout || !outSet) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -2702,11 +2661,11 @@ PalResult PAL_CALL palUpdateDescriptorSet( PalDescriptorSetWriteInfo* infos) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !infos || count == 0 && infos) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return device->backend->updateDescriptorSet(device, count, infos); @@ -2722,11 +2681,11 @@ PalResult PAL_CALL palCreatePipelineLayout( PalPipelineLayout** outLayout) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outLayout) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -2758,15 +2717,15 @@ PalResult PAL_CALL palCreateGraphicsPipeline( PalPipeline** outPipeline) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outPipeline) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (!info->renderingLayout) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -2787,11 +2746,11 @@ PalResult PAL_CALL palCreateComputePipeline( PalPipeline** outPipeline) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outPipeline) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -2812,11 +2771,11 @@ PalResult PAL_CALL palCreateRayTracingPipeline( PalPipeline** outPipeline) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outPipeline) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -2848,15 +2807,15 @@ PalResult PAL_CALL palCreateShaderBindingTable( PalShaderBindingTable** outSbt) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!device || !info || !outSbt) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (!info->rayTracingPipeline) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } PalResult result; @@ -2884,11 +2843,11 @@ PalResult PAL_CALL palUpdateShaderBindingTable( PalShaderBindingTableRecordInfo* infos) { if (!s_Graphics.initialized) { - return palMakeResult(PAL_RESULT_NOT_INITIALIZED, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_NOT_INITIALIZED; } if (!sbt || !infos || count == 0 && infos) { - return palMakeResult(PAL_RESULT_INVALID_ARGUMENT, PLATFORM_SOURCE, 0); + return PAL_RESULT_CODE_INVALID_ARGUMENT; } return sbt->backend->updateShaderBindingTable(sbt, count, infos); diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index 698bbba0..21c6dde3 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -10,8 +10,8 @@ #include "pal/pal_graphics.h" +// clang-format off typedef struct { - // clang-format off PalResult (PAL_CALL *enumerateAdapters)(int32_t*, PalAdapter**); PalResult (PAL_CALL *getAdapterInfo)(PalAdapter*, PalAdapterInfo*); PalResult (PAL_CALL *getAdapterCapabilities)(PalAdapter*, PalAdapterCapabilities*); @@ -156,4 +156,1315 @@ typedef struct { PalResult (PAL_CALL *updateShaderBindingTable)(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); } PalGraphicsVtable; +// ================================================== +// Vulkan +// ================================================== + +PalResult PAL_CALL initGraphicsVk(const PalGraphicsDebugger*, const PalAllocator*); +void PAL_CALL shutdownGraphicsVk(); +PalResult PAL_CALL enumerateAdaptersVk(int32_t*, PalAdapter**); +PalResult PAL_CALL getAdapterInfoVk(PalAdapter*, PalAdapterInfo*); +PalResult PAL_CALL getAdapterCapabilitiesVk(PalAdapter*, PalAdapterCapabilities*); +PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter*); +uint32_t PAL_CALL getHighestSupportedShaderTargetVk(PalAdapter*, PalShaderFormats); +PalResult PAL_CALL createDeviceVk(PalAdapter*, PalAdapterFeatures, PalDevice**); +void PAL_CALL destroyDeviceVk(PalDevice*); +PalResult PAL_CALL waitDeviceVk(PalDevice*); +PalResult PAL_CALL allocateMemoryVk(PalDevice*, PalMemoryType, uint64_t, uint64_t, PalMemory**); +void PAL_CALL freeMemoryVk(PalDevice*, PalMemory*); +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk(PalDevice*, PalSamplerAnisotropyCapabilities*); +PalResult PAL_CALL queryMultiViewCapabilitiesVk(PalDevice*, PalMultiViewCapabilities*); +PalResult PAL_CALL queryMultiViewportCapabilitiesVk(PalDevice*, PalMultiViewportCapabilities*); +PalResult PAL_CALL queryDepthStencilCapabilitiesVk(PalDevice*, PalDepthStencilCapabilities*); +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk(PalDevice*, PalFragmentShadingRateCapabilities*); +PalResult PAL_CALL queryMeshShaderCapabilitiesVk(PalDevice*, PalMeshShaderCapabilities*); +PalResult PAL_CALL queryRayTracingCapabilitiesVk(PalDevice*, PalRayTracingCapabilities*); +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk(PalDevice*, PalDescriptorIndexingCapabilities*); + +PalResult PAL_CALL createQueueVk(PalDevice*, PalQueueType, PalQueue**); +void PAL_CALL destroyQueueVk(PalQueue*); +PalResult PAL_CALL waitQueueVk(PalQueue*); +PalBool PAL_CALL canQueuePresentVk(PalQueue*, PalSurface*); +PalResult PAL_CALL enumerateFormatsVk(PalAdapter*, int32_t*, PalFormatInfo*); +PalBool PAL_CALL isFormatSupportedVk(PalAdapter*, PalFormat); +PalImageUsages PAL_CALL queryFormatImageUsagesVk(PalAdapter*, PalFormat); +PalSampleCount PAL_CALL queryFormatSampleCountVk(PalAdapter*, PalFormat); +PalResult PAL_CALL createImageVk(PalDevice*, const PalImageCreateInfo*, PalImage**); +void PAL_CALL destroyImageVk(PalImage*); +PalResult PAL_CALL getImageInfoVk(PalImage*, PalImageInfo*); +PalResult PAL_CALL getImageMemoryRequirementsVk(PalImage*, PalMemoryRequirements*); +PalResult PAL_CALL bindImageMemoryVk(PalImage*, PalMemory*, uint64_t); +PalResult PAL_CALL mapImageMemoryVk(PalImage*, uint64_t, uint64_t, void**); +void PAL_CALL unmapImageMemoryVk(PalImage*); +PalResult PAL_CALL createImageViewVk(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); +void PAL_CALL destroyImageViewVk(PalImageView*); + +PalResult PAL_CALL createSamplerVk(PalDevice*, const PalSamplerCreateInfo*, PalSampler**); +void PAL_CALL destroySamplerVk(PalSampler*); +PalResult PAL_CALL createSurfaceVk(PalDevice*, void*, void*, PalWindowInstanceType, PalSurface**); +void PAL_CALL destroySurfaceVk(PalSurface*); +PalResult PAL_CALL getSurfaceCapabilitiesVk(PalDevice*, PalSurface*, PalSurfaceCapabilities*); +PalResult PAL_CALL createSwapchainVk(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); +void PAL_CALL destroySwapchainVk(PalSwapchain*); +PalImage* PAL_CALL getSwapchainImageVk(PalSwapchain*, uint32_t); +PalResult PAL_CALL getNextSwapchainImageVk(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t); +PalResult PAL_CALL presentSwapchainVk(PalSwapchain*, PalSwapchainPresentInfo*); +PalResult PAL_CALL resizeSwapchainVk(PalSwapchain*, uint32_t, uint32_t); +PalResult PAL_CALL createShaderVk(PalDevice*, const PalShaderCreateInfo*, PalShader**); +void PAL_CALL destroyShaderVk(PalShader*); + +PalResult PAL_CALL createFenceVk(PalDevice*, PalBool, PalFence**); +void PAL_CALL destroyFenceVk(PalFence*); +PalResult PAL_CALL waitFenceVk(PalFence*, uint64_t); +PalResult PAL_CALL resetFenceVk(PalFence*); +PalBool PAL_CALL isFenceSignaledVk(PalFence*); +PalResult PAL_CALL createSemaphoreVk(PalDevice*, PalBool, PalSemaphore**); +void PAL_CALL destroySemaphoreVk(PalSemaphore*); +PalResult PAL_CALL waitSemaphoreVk(PalSemaphore*, uint64_t, uint64_t); +PalResult PAL_CALL signalSemaphoreVk(PalSemaphore*, PalQueue*, uint64_t); +PalResult PAL_CALL getSemaphoreValueVk(PalSemaphore*, uint64_t*); +PalResult PAL_CALL createCommandPoolVk(PalDevice*, PalQueue*, PalCommandPool**); +void PAL_CALL destroyCommandPoolVk(PalCommandPool*); +PalResult PAL_CALL resetCommandPoolVk(PalCommandPool*); +PalResult PAL_CALL allocateCommandBufferVk(PalDevice*, PalCommandPool*, PalCommandBufferType, PalCommandBuffer**); +void PAL_CALL freeCommandBufferVk(PalCommandBuffer*); +PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer*); +PalResult PAL_CALL submitCommandBufferVk(PalQueue*, PalCommandBufferSubmitInfo*); + +PalResult PAL_CALL cmdBeginVk(PalCommandBuffer*, PalRenderingLayoutInfo*); +PalResult PAL_CALL cmdEndVk(PalCommandBuffer*); +PalResult PAL_CALL cmdExecuteCommandBufferVk(PalCommandBuffer*, PalCommandBuffer*); +PalResult PAL_CALL cmdSetFragmentShadingRateVk(PalCommandBuffer*, PalFragmentShadingRateState*); +PalResult PAL_CALL cmdDrawMeshTasksVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); +PalResult PAL_CALL cmdDrawMeshTasksIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdBuildAccelerationStructureVk(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); +PalResult PAL_CALL cmdBeginRenderingVk(PalCommandBuffer*, PalRenderingInfo*); +PalResult PAL_CALL cmdEndRenderingVk(PalCommandBuffer*); +PalResult PAL_CALL cmdCopyBufferVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); +PalResult PAL_CALL cmdCopyBufferToImageVk(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); +PalResult PAL_CALL cmdCopyImageVk(PalCommandBuffer*, PalImage*, PalImage*, PalImageCopyInfo*); +PalResult PAL_CALL cmdCopyImageToBufferVk(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); +PalResult PAL_CALL cmdBindPipelineVk(PalCommandBuffer*, PalPipeline*); +PalResult PAL_CALL cmdSetViewportVk(PalCommandBuffer*, uint32_t, PalViewport*); +PalResult PAL_CALL cmdSetScissorsVk(PalCommandBuffer*, uint32_t, PalRect2D*); +PalResult PAL_CALL cmdBindVertexBuffersVk(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); +PalResult PAL_CALL cmdBindIndexBufferVk(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); +PalResult PAL_CALL cmdDrawVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); +PalResult PAL_CALL cmdDrawIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdDrawIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdDrawIndexedVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); +PalResult PAL_CALL cmdDrawIndexedIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdDrawIndexedIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdAccelerationStructureBarrierVk(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); +PalResult PAL_CALL cmdImageBarrierVk(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); +PalResult PAL_CALL cmdBufferBarrierVk(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); +PalResult PAL_CALL cmdDispatchVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); +PalResult PAL_CALL cmdDispatchBaseVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); +PalResult PAL_CALL cmdDispatchIndirectVk(PalCommandBuffer*, PalBuffer*); +PalResult PAL_CALL cmdTraceRaysVk(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); +PalResult PAL_CALL cmdTraceRaysIndirectVk(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); +PalResult PAL_CALL cmdBindDescriptorSetVk(PalCommandBuffer*, uint32_t, PalDescriptorSet*); +PalResult PAL_CALL cmdPushConstantsVk(PalCommandBuffer*, uint32_t, uint32_t, const void*); +PalResult PAL_CALL cmdSetCullModeVk(PalCommandBuffer*, PalCullMode); +PalResult PAL_CALL cmdSetFrontFaceVk(PalCommandBuffer*, PalFrontFace); +PalResult PAL_CALL cmdSetPrimitiveTopologyVk(PalCommandBuffer*, PalPrimitiveTopology); +PalResult PAL_CALL cmdSetDepthTestEnableVk(PalCommandBuffer*, PalBool); +PalResult PAL_CALL cmdSetDepthWriteEnableVk(PalCommandBuffer*, PalBool); +PalResult PAL_CALL cmdSetStencilOpVk(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); + +PalResult PAL_CALL createAccelerationstructureVk(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); +void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure*); +PalResult PAL_CALL getAccelerationStructureBuildSizeVk(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); + +// ================================================== +// Buffer +// ================================================== + +PalResult PAL_CALL createBufferVk( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + +void PAL_CALL destroyBufferVk(PalBuffer* buffer); + +PalResult PAL_CALL getBufferMemoryRequirementsVk( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL computeInstanceBufferRequirementsVk( + PalDevice* device, + uint32_t instanceCount, + uint64_t* outSize); + +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( + PalDevice* device, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo, + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize); + +PalResult PAL_CALL writeToInstanceBufferVk( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + uint32_t instanceCount); + +PalResult PAL_CALL writeToImageCopyStagingBufferVk( + PalDevice* device, + void* ptr, + void* srcData, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL bindBufferMemoryVk( + PalBuffer* buffer, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL mapBufferMemoryVk( + PalBuffer* buffer, + uint64_t offset, + uint64_t size, + void** outPtr); + +void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer); + +PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer); + +// ================================================== +// Descriptor Pool, Set and Layout +// ================================================== + +PalResult PAL_CALL createDescriptorSetLayoutVk( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + +void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout); + +PalResult PAL_CALL createDescriptorPoolVk( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + +void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool); + +PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool); + +PalResult PAL_CALL allocateDescriptorSetVk( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + +PalResult PAL_CALL updateDescriptorSetVk( + PalDevice* device, + uint32_t count, + PalDescriptorSetWriteInfo* infos); + +// ================================================== +// Pipeline Layout +// ================================================== + +PalResult PAL_CALL createPipelineLayoutVk( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + +void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout); + +// ================================================== +// Pipeline +// ================================================== + +PalResult PAL_CALL createGraphicsPipelineVk( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createComputePipelineVk( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createRayTracingPipelineVk( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + +void PAL_CALL destroyPipelineVk(PalPipeline* pipeline); + +// ================================================== +// Shader Binding Table +// ================================================== + +PalResult PAL_CALL createShaderBindingTableVk( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + +void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt); + +PalResult PAL_CALL updateShaderBindingTableVk( + PalShaderBindingTable* sbt, + uint32_t count, + PalShaderBindingTableRecordInfo* infos); + +static PalGraphicsVtable s_VkBackend = { + // adapter + .enumerateAdapters = enumerateAdaptersVk, + .getAdapterInfo = getAdapterInfoVk, + .getAdapterCapabilities = getAdapterCapabilitiesVk, + .getAdapterFeatures = getAdapterFeaturesVk, + .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetVk, + + // device + .createDevice = createDeviceVk, + .destroyDevice = destroyDeviceVk, + + // memory + .allocateMemory = allocateMemoryVk, + .freeMemory = freeMemoryVk, + + // extended adapter features + .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesVk, + .queryMultiViewCapabilities = queryMultiViewCapabilitiesVk, + .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesVk, + .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesVk, + .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesVk, + .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesVk, + .queryRayTracingCapabilities = queryRayTracingCapabilitiesVk, + .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesVk, + + // queue + .createQueue = createQueueVk, + .destroyQueue = destroyQueueVk, + .waitQueue = waitQueueVk, + .canQueuePresent = canQueuePresentVk, + + // format + .enumerateFormats = enumerateFormatsVk, + .isFormatSupported = isFormatSupportedVk, + .queryFormatImageUsages = queryFormatImageUsagesVk, + .queryFormatSampleCount = queryFormatSampleCountVk, + + // image + .createImage = createImageVk, + .destroyImage = destroyImageVk, + .getImageInfo = getImageInfoVk, + .getImageMemoryRequirements = getImageMemoryRequirementsVk, + .bindImageMemory = bindImageMemoryVk, + .mapImageMemory = mapImageMemoryVk, + .unmapImageMemory = unmapImageMemoryVk, + + // image view + .createImageView = createImageViewVk, + .destroyImageView = destroyImageViewVk, + + // sampler + .createSampler = createSamplerVk, + .destroySampler = destroySamplerVk, + + // surface + .createSurface = createSurfaceVk, + .destroySurface = destroySurfaceVk, + .getSurfaceCapabilities = getSurfaceCapabilitiesVk, + + // swapchain + .createSwapchain = createSwapchainVk, + .destroySwapchain = destroySwapchainVk, + .getSwapchainImage = getSwapchainImageVk, + .getNextSwapchainImage = getNextSwapchainImageVk, + .presentSwapchain = presentSwapchainVk, + .resizeSwapchain = resizeSwapchainVk, + + // shader + .createShader = createShaderVk, + .destroyShader = destroyShaderVk, + + // fence + .createFence = createFenceVk, + .destroyFence = destroyFenceVk, + .waitFence = waitFenceVk, + .resetFence = resetFenceVk, + .isFenceSignaled = isFenceSignaledVk, + + // semaphore + .createSemaphore = createSemaphoreVk, + .destroySemaphore = destroySemaphoreVk, + .waitSemaphore = waitSemaphoreVk, + .signalSemaphore = signalSemaphoreVk, + .getSemaphoreValue = getSemaphoreValueVk, + + // command pool and command buffer + .createCommandPool = createCommandPoolVk, + .destroyCommandPool = destroyCommandPoolVk, + .resetCommandPool = resetCommandPoolVk, + .allocateCommandBuffer = allocateCommandBufferVk, + .freeCommandBuffer = freeCommandBufferVk, + .resetCommandBuffer = resetCommandBufferVk, + .submitCommandBuffer = submitCommandBufferVk, + + // command recording + .cmdBegin = cmdBeginVk, + .cmdEnd = cmdEndVk, + .cmdExecuteCommandBuffer = cmdExecuteCommandBufferVk, + .cmdSetFragmentShadingRate = cmdSetFragmentShadingRateVk, + .cmdDrawMeshTasks = cmdDrawMeshTasksVk, + .cmdDrawMeshTasksIndirect = cmdDrawMeshTasksIndirectVk, + .cmdDrawMeshTasksIndirectCount = cmdDrawMeshTasksIndirectCountVk, + .cmdBuildAccelerationStructure = cmdBuildAccelerationStructureVk, + .cmdBeginRendering = cmdBeginRenderingVk, + .cmdEndRendering = cmdEndRenderingVk, + .cmdCopyBuffer = cmdCopyBufferVk, + .cmdCopyBufferToImage = cmdCopyBufferToImageVk, + .cmdCopyImage = cmdCopyImageVk, + .cmdCopyImageToBuffer = cmdCopyImageToBufferVk, + .cmdBindPipeline = cmdBindPipelineVk, + .cmdSetViewport = cmdSetViewportVk, + .cmdSetScissors = cmdSetScissorsVk, + .cmdBindVertexBuffers = cmdBindVertexBuffersVk, + .cmdBindIndexBuffer = cmdBindIndexBufferVk, + .cmdDraw = cmdDrawVk, + .cmdDrawIndirect = cmdDrawIndirectVk, + .cmdDrawIndirectCount = cmdDrawIndirectCountVk, + .cmdDrawIndexed = cmdDrawIndexedVk, + .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectVk, + .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountVk, + .cmdAccelerationStructureBarrier = cmdAccelerationStructureBarrierVk, + .cmdImageBarrier = cmdImageBarrierVk, + .cmdBufferBarrier = cmdBufferBarrierVk, + .cmdDispatch = cmdDispatchVk, + .cmdDispatchBase = cmdDispatchBaseVk, + .cmdDispatchIndirect = cmdDispatchIndirectVk, + .cmdTraceRays = cmdTraceRaysVk, + .cmdTraceRaysIndirect = cmdTraceRaysIndirectVk, + .cmdBindDescriptorSet = cmdBindDescriptorSetVk, + .cmdPushConstants = cmdPushConstantsVk, + .cmdSetCullMode = cmdSetCullModeVk, + .cmdSetFrontFace = cmdSetFrontFaceVk, + .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyVk, + .cmdSetDepthTestEnable = cmdSetDepthTestEnableVk, + .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableVk, + .cmdSetStencilOp = cmdSetStencilOpVk, + + // acceleration structure + .createAccelerationstructure = createAccelerationstructureVk, + .destroyAccelerationstructure = destroyAccelerationstructureVk, + .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeVk, + + // buffer + .createBuffer = createBufferVk, + .destroyBuffer = destroyBufferVk, + .getBufferMemoryRequirements = getBufferMemoryRequirementsVk, + .computeInstanceBufferRequirements = computeInstanceBufferRequirementsVk, + .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsVk, + .writeToInstanceBuffer = writeToInstanceBufferVk, + .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferVk, + .bindBufferMemory = bindBufferMemoryVk, + .getBufferDeviceAddress = getBufferDeviceAddressVk, + .mapBufferMemory = mapBufferMemoryVk, + .unmapBufferMemory = unmapBufferMemoryVk, + + // descriptor set layout, descriptor pool and descriptor set + .createDescriptorSetLayout = createDescriptorSetLayoutVk, + .destroyDescriptorSetLayout = destroyDescriptorSetLayoutVk, + .createDescriptorPool = createDescriptorPoolVk, + .destroyDescriptorPool = destroyDescriptorPoolVk, + .resetDescriptorPool = resetDescriptorPoolVk, + .allocateDescriptorSet = allocateDescriptorSetVk, + .updateDescriptorSet = updateDescriptorSetVk, + + // pipeline layout + .createPipelineLayout = createPipelineLayoutVk, + .destroyPipelineLayout = destroyPipelineLayoutVk, + + // pipeline + .createGraphicsPipeline = createGraphicsPipelineVk, + .createComputePipeline = createComputePipelineVk, + .createRayTracingPipeline = createRayTracingPipelineVk, + .destroyPipeline = destroyPipelineVk, + + // shader binding table + .createShaderBindingTable = createShaderBindingTableVk, + .destroyShaderBindingTable = destroyShaderBindingTableVk, + .updateShaderBindingTable = updateShaderBindingTableVk}; + +// ================================================== +// D3D12 +// ================================================== + +PalResult PAL_CALL initGraphicsD3D12( + const PalGraphicsDebugger* debugger, + const PalAllocator* allocator); + +void PAL_CALL shutdownGraphicsD3D12(); + +PalResult PAL_CALL enumerateAdaptersD3D12( + int32_t* count, + PalAdapter** outAdapters); + +PalResult PAL_CALL getAdapterInfoD3D12( + PalAdapter* adapter, + PalAdapterInfo* info); + +PalResult PAL_CALL getAdapterCapabilitiesD3D12( + PalAdapter* adapter, + PalAdapterCapabilities* caps); + +PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); + +uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( + PalAdapter* adapter, + PalShaderFormats shaderFormat); + +// ================================================== +// Device +// ================================================== + +PalResult PAL_CALL createDeviceD3D12( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); + +void PAL_CALL destroyDeviceD3D12(PalDevice* device); + +PalResult PAL_CALL waitDeviceD3D12(PalDevice* device); + +// ================================================== +// Memory +// ================================================== + +PalResult PAL_CALL allocateMemoryD3D12( + PalDevice* device, + PalMemoryType type, + uint64_t memoryMask, + uint64_t size, + PalMemory** outMemory); + +void PAL_CALL freeMemoryD3D12( + PalDevice* device, + PalMemory* memory); + +// ================================================== +// Extended Adapter Features +// ================================================== + +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps); + +PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( + PalDevice* device, + PalMultiViewCapabilities* caps); + +PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( + PalDevice* device, + PalMultiViewportCapabilities* caps); + +PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( + PalDevice* device, + PalDepthStencilCapabilities* caps); + +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); + +PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( + PalDevice* device, + PalMeshShaderCapabilities* caps); + +PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( + PalDevice* device, + PalRayTracingCapabilities* caps); + +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); + +// ================================================== +// Queue +// ================================================== + +PalResult PAL_CALL createQueueD3D12( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); + +void PAL_CALL destroyQueueD3D12(PalQueue* queue); + +PalResult PAL_CALL waitQueueD3D12(PalQueue* queue); + +PalBool PAL_CALL canQueuePresentD3D12( + PalQueue* queue, + PalSurface* surface); + +// ================================================== +// Formats +// ================================================== + +PalResult PAL_CALL enumerateFormatsD3D12( + PalAdapter* adapter, + int32_t* count, + PalFormatInfo* outFormats); + +PalBool PAL_CALL isFormatSupportedD3D12( + PalAdapter* adapter, + PalFormat format); + +PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( + PalAdapter* adapter, + PalFormat format); + +PalSampleCount PAL_CALL queryFormatSampleCountD3D12( + PalAdapter* adapter, + PalFormat format); + +// ================================================== +// Image +// ================================================== + +PalResult PAL_CALL createImageD3D12( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + +void PAL_CALL destroyImageD3D12(PalImage* image); + +PalResult PAL_CALL getImageInfoD3D12( + PalImage* image, + PalImageInfo* info); + +PalResult PAL_CALL getImageMemoryRequirementsD3D12( + PalImage* image, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL bindImageMemoryD3D12( + PalImage* image, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL mapImageMemoryD3D12( + PalImage* image, + uint64_t offset, + uint64_t size, + void** outPtr); + +void PAL_CALL unmapImageMemoryD3D12(PalImage* image); + +// ================================================== +// Image View +// ================================================== + +PalResult PAL_CALL createImageViewD3D12( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + +void PAL_CALL destroyImageViewD3D12(PalImageView* imageView); + +// ================================================== +// Sampler +// ================================================== + +PalResult PAL_CALL createSamplerD3D12( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler); + +void PAL_CALL destroySamplerD3D12(PalSampler* sampler); + +// ================================================== +// Surface +// ================================================== + +PalResult PAL_CALL createSurfaceD3D12( + PalDevice* device, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, + PalSurface** outSurface); + +void PAL_CALL destroySurfaceD3D12(PalSurface* surface); + +PalResult PAL_CALL getSurfaceCapabilitiesD3D12( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps); + +// ================================================== +// Swapchain +// ================================================== + +PalResult PAL_CALL createSwapchainD3D12( + PalDevice* device, + PalQueue* queue, + PalSurface* surface, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + +void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain); + +PalImage* PAL_CALL getSwapchainImageD3D12( + PalSwapchain* swapchain, + int32_t index); + +PalResult PAL_CALL getNextSwapchainImageD3D12( + PalSwapchain* swapchain, + PalSwapchainNextImageInfo* info, + uint32_t* outIndex); + +PalResult PAL_CALL presentSwapchainD3D12( + PalSwapchain* swapchain, + PalSwapchainPresentInfo* info); + +PalResult PAL_CALL resizeSwapchainD3D12( + PalSwapchain* swapchain, + uint32_t newWidth, + uint32_t newHeight); + +// ================================================== +// Shader +// ================================================== + +PalResult PAL_CALL createShaderD3D12( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + +void PAL_CALL destroyShaderD3D12(PalShader* shader); + +// ================================================== +// Fence +// ================================================== + +PalResult PAL_CALL createFenceD3D12( + PalDevice* device, + PalBool signaled, + PalFence** outFence); + +void PAL_CALL destroyFenceD3D12(PalFence* fence); + +PalResult PAL_CALL waitFenceD3D12( + PalFence* fence, + uint64_t timeout); + +PalResult PAL_CALL resetFenceD3D12(PalFence* fence); + +PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence); + +// ================================================== +// Semaphore +// ================================================== + +PalResult PAL_CALL createSemaphoreD3D12( + PalDevice* device, + PalBool enableTimeline, + PalSemaphore** outSemaphore); + +void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); + +PalResult PAL_CALL waitSemaphoreD3D12( + PalSemaphore* semaphore, + uint64_t value, + uint64_t timeout); + +PalResult PAL_CALL signalSemaphoreD3D12( + PalSemaphore* semaphore, + PalQueue* queue, + uint64_t value); + +PalResult PAL_CALL getSemaphoreValueD3D12( + PalSemaphore* semaphore, + uint64_t* outValue); + +// ================================================== +// Command Pool And Buffer +// ================================================== + +PalResult PAL_CALL createCommandPoolD3D12( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool); + +void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool); + +PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool); + +PalResult PAL_CALL allocateCommandBufferD3D12( + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outCmdBuffer); + +void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL submitCommandBufferD3D12( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + +// ================================================== +// Command Recording +// ================================================== + +PalResult PAL_CALL cmdBeginD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info); + +PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdExecuteCommandBufferD3D12( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + +PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + +PalResult PAL_CALL cmdDrawMeshTasksD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t drawCount); + +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); + +PalResult PAL_CALL cmdBeginRenderingD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info); + +PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL cmdCopyBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyBufferToImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdCopyImageToBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL cmdBindPipelineD3D12( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline); + +PalResult PAL_CALL cmdSetViewportD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalViewport* viewports); + +PalResult PAL_CALL cmdSetScissorsD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalRect2D* scissors); + +PalResult PAL_CALL cmdBindVertexBuffersD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t firstSlot, + uint32_t count, + PalBuffer** buffers, + uint64_t* offsets); + +PalResult PAL_CALL cmdBindIndexBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint64_t offset, + PalIndexType type); + +PalResult PAL_CALL cmdDrawD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + +PalResult PAL_CALL cmdDrawIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + +PalResult PAL_CALL cmdDrawIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +PalResult PAL_CALL cmdDrawIndexedD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + +PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + +PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PalResult PAL_CALL cmdImageBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PalResult PAL_CALL cmdBufferBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState); + +PalResult PAL_CALL cmdDispatchD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +PalResult PAL_CALL cmdDispatchBaseD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +PalResult PAL_CALL cmdDispatchIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer); + +PalResult PAL_CALL cmdTraceRaysD3D12( + PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth); + +PalResult PAL_CALL cmdTraceRaysIndirectD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t raygenIndex, + PalShaderBindingTable* sbt, + PalBuffer* buffer); + +PalResult PAL_CALL cmdBindDescriptorSetD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t setIndex, + PalDescriptorSet* set); + +PalResult PAL_CALL cmdPushConstantsD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t shaderStageCount, + PalShaderStage* shaderStages, + uint32_t offset, + uint32_t size, + const void* value); + +PalResult PAL_CALL cmdSetCullModeD3D12( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + +PalResult PAL_CALL cmdSetFrontFaceD3D12( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + +PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + +PalResult PAL_CALL cmdSetDepthTestEnableD3D12( + PalCommandBuffer* cmdBuffer, + PalBool enable); + +PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( + PalCommandBuffer* cmdBuffer, + PalBool enable); + +PalResult PAL_CALL cmdSetStencilOpD3D12( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); + +// ================================================== +// Acceleration Structure +// ================================================== + +PalResult PAL_CALL createAccelerationstructureD3D12( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + +void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as); + +PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + +// ================================================== +// Buffer +// ================================================== + +PalResult PAL_CALL createBufferD3D12( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + +void PAL_CALL destroyBufferD3D12(PalBuffer* buffer); + +PalResult PAL_CALL getBufferMemoryRequirementsD3D12( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( + PalDevice* device, + uint32_t instanceCount, + uint64_t* outSize); + +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( + PalDevice* device, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo, + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize); + +PalResult PAL_CALL writeToInstanceBufferD3D12( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + uint32_t instanceCount); + +PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( + PalDevice* device, + void* ptr, + void* srcData, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo); + +PalResult PAL_CALL bindBufferMemoryD3D12( + PalBuffer* buffer, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL mapBufferMemoryD3D12( + PalBuffer* buffer, + uint64_t offset, + uint64_t size, + void** outPtr); + +void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer); + +PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); + +// ================================================== +// Descriptor Pool, Set and Layout +// ================================================== + +PalResult PAL_CALL createDescriptorSetLayoutD3D12( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + +void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout); + +PalResult PAL_CALL createDescriptorPoolD3D12( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + +void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool); + +PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool); + +PalResult PAL_CALL allocateDescriptorSetD3D12( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + +PalResult PAL_CALL updateDescriptorSetD3D12( + PalDevice* device, + uint32_t count, + PalDescriptorSetWriteInfo* infos); + +// ================================================== +// Pipeline Layout +// ================================================== + +PalResult PAL_CALL createPipelineLayoutD3D12( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + +void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout); + +// ================================================== +// Pipeline +// ================================================== + +PalResult PAL_CALL createGraphicsPipelineD3D12( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createComputePipelineD3D12( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createRayTracingPipelineD3D12( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + +void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline); + +// ================================================== +// Shader Binding Table +// ================================================== + +PalResult PAL_CALL createShaderBindingTableD3D12( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + +void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); + +PalResult PAL_CALL updateShaderBindingTableD3D12( + PalShaderBindingTable* sbt, + uint32_t count, + PalShaderBindingTableRecordInfo* infos); + +static PalGraphicsVtable s_D3D12Backend = { + // adapter + .enumerateAdapters = enumerateAdaptersD3D12, + .getAdapterInfo = getAdapterInfoD3D12, + .getAdapterCapabilities = getAdapterCapabilitiesD3D12, + .getAdapterFeatures = getAdapterFeaturesD3D12, + .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetD3D12, + + // device + .createDevice = createDeviceD3D12, + .destroyDevice = destroyDeviceD3D12, + + // memory + .allocateMemory = allocateMemoryD3D12, + .freeMemory = freeMemoryD3D12, + + // extended adapter features + .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesD3D12, + .queryMultiViewCapabilities = queryMultiViewCapabilitiesD3D12, + .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesD3D12, + .queryDepthStencilCapabilities = queryDepthStencilCapabilitiesD3D12, + .queryFragmentShadingRateCapabilities = queryFragmentShadingRateCapabilitiesD3D12, + .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesD3D12, + .queryRayTracingCapabilities = queryRayTracingCapabilitiesD3D12, + .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesD3D12, + + // queue + .createQueue = createQueueD3D12, + .destroyQueue = destroyQueueD3D12, + .waitQueue = waitQueueD3D12, + .canQueuePresent = canQueuePresentD3D12, + + // format + .enumerateFormats = enumerateFormatsD3D12, + .isFormatSupported = isFormatSupportedD3D12, + .queryFormatImageUsages = queryFormatImageUsagesD3D12, + .queryFormatSampleCount = queryFormatSampleCountD3D12, + + // image + .createImage = createImageD3D12, + .destroyImage = destroyImageD3D12, + .getImageInfo = getImageInfoD3D12, + .getImageMemoryRequirements = getImageMemoryRequirementsD3D12, + .bindImageMemory = bindImageMemoryD3D12, + .mapImageMemory = mapImageMemoryD3D12, + .unmapImageMemory = unmapImageMemoryD3D12, + + // image view + .createImageView = createImageViewD3D12, + .destroyImageView = destroyImageViewD3D12, + + // sampler + .createSampler = createSamplerD3D12, + .destroySampler = destroySamplerD3D12, + + // surface + .createSurface = createSurfaceD3D12, + .destroySurface = destroySurfaceD3D12, + .getSurfaceCapabilities = getSurfaceCapabilitiesD3D12, + + // swapchain + .createSwapchain = createSwapchainD3D12, + .destroySwapchain = destroySwapchainD3D12, + .getSwapchainImage = getSwapchainImageD3D12, + .getNextSwapchainImage = getNextSwapchainImageD3D12, + .presentSwapchain = presentSwapchainD3D12, + .resizeSwapchain = resizeSwapchainD3D12, + + // shader + .createShader = createShaderD3D12, + .destroyShader = destroyShaderD3D12, + + // fence + .createFence = createFenceD3D12, + .destroyFence = destroyFenceD3D12, + .waitFence = waitFenceD3D12, + .resetFence = resetFenceD3D12, + .isFenceSignaled = isFenceSignaledD3D12, + + // semaphore + .createSemaphore = createSemaphoreD3D12, + .destroySemaphore = destroySemaphoreD3D12, + .waitSemaphore = waitSemaphoreD3D12, + .signalSemaphore = signalSemaphoreD3D12, + .getSemaphoreValue = getSemaphoreValueD3D12, + + // command pool and command buffer + .createCommandPool = createCommandPoolD3D12, + .destroyCommandPool = destroyCommandPoolD3D12, + .resetCommandPool = resetCommandPoolD3D12, + .allocateCommandBuffer = allocateCommandBufferD3D12, + .freeCommandBuffer = freeCommandBufferD3D12, + .resetCommandBuffer = resetCommandBufferD3D12, + .submitCommandBuffer = submitCommandBufferD3D12, + + // command recording + .cmdBegin = cmdBeginD3D12, + .cmdEnd = cmdEndD3D12, + .cmdExecuteCommandBuffer = cmdExecuteCommandBufferD3D12, + .cmdSetFragmentShadingRate = cmdSetFragmentShadingRateD3D12, + .cmdDrawMeshTasks = cmdDrawMeshTasksD3D12, + .cmdDrawMeshTasksIndirect = cmdDrawMeshTasksIndirectD3D12, + .cmdDrawMeshTasksIndirectCount = cmdDrawMeshTasksIndirectCountD3D12, + .cmdBuildAccelerationStructure = cmdBuildAccelerationStructureD3D12, + .cmdBeginRendering = cmdBeginRenderingD3D12, + .cmdEndRendering = cmdEndRenderingD3D12, + .cmdCopyBuffer = cmdCopyBufferD3D12, + .cmdCopyBufferToImage = cmdCopyBufferToImageD3D12, + .cmdCopyImage = cmdCopyImageD3D12, + .cmdCopyImageToBuffer = cmdCopyImageToBufferD3D12, + .cmdBindPipeline = cmdBindPipelineD3D12, + .cmdSetViewport = cmdSetViewportD3D12, + .cmdSetScissors = cmdSetScissorsD3D12, + .cmdBindVertexBuffers = cmdBindVertexBuffersD3D12, + .cmdBindIndexBuffer = cmdBindIndexBufferD3D12, + .cmdDraw = cmdDrawD3D12, + .cmdDrawIndirect = cmdDrawIndirectD3D12, + .cmdDrawIndirectCount = cmdDrawIndirectCountD3D12, + .cmdDrawIndexed = cmdDrawIndexedD3D12, + .cmdDrawIndexedIndirect = cmdDrawIndexedIndirectD3D12, + .cmdDrawIndexedIndirectCount = cmdDrawIndexedIndirectCountD3D12, + .cmdAccelerationStructureBarrier = cmdAccelerationStructureBarrierD3D12, + .cmdImageBarrier = cmdImageBarrierD3D12, + .cmdBufferBarrier = cmdBufferBarrierD3D12, + .cmdDispatch = cmdDispatchD3D12, + .cmdDispatchBase = cmdDispatchBaseD3D12, + .cmdDispatchIndirect = cmdDispatchIndirectD3D12, + .cmdTraceRays = cmdTraceRaysD3D12, + .cmdTraceRaysIndirect = cmdTraceRaysIndirectD3D12, + .cmdBindDescriptorSet = cmdBindDescriptorSetD3D12, + .cmdPushConstants = cmdPushConstantsD3D12, + .cmdSetCullMode = cmdSetCullModeD3D12, + .cmdSetFrontFace = cmdSetFrontFaceD3D12, + .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyD3D12, + .cmdSetDepthTestEnable = cmdSetDepthTestEnableD3D12, + .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableD3D12, + .cmdSetStencilOp = cmdSetStencilOpD3D12, + + // acceleration structure + .createAccelerationstructure = createAccelerationstructureD3D12, + .destroyAccelerationstructure = destroyAccelerationstructureD3D12, + .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeD3D12, + + // buffer + .createBuffer = createBufferD3D12, + .destroyBuffer = destroyBufferD3D12, + .getBufferMemoryRequirements = getBufferMemoryRequirementsD3D12, + .computeInstanceBufferRequirements = computeInstanceBufferRequirementsD3D12, + .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsD3D12, + .writeToInstanceBuffer = writeToInstanceBufferD3D12, + .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferD3D12, + .bindBufferMemory = bindBufferMemoryD3D12, + .getBufferDeviceAddress = getBufferDeviceAddressD3D12, + .mapBufferMemory = mapBufferMemoryD3D12, + .unmapBufferMemory = unmapBufferMemoryD3D12, + + // descriptor set layout, descriptor pool and descriptor set + .createDescriptorSetLayout = createDescriptorSetLayoutD3D12, + .destroyDescriptorSetLayout = destroyDescriptorSetLayoutD3D12, + .createDescriptorPool = createDescriptorPoolD3D12, + .destroyDescriptorPool = destroyDescriptorPoolD3D12, + .resetDescriptorPool = resetDescriptorPoolD3D12, + .allocateDescriptorSet = allocateDescriptorSetD3D12, + .updateDescriptorSet = updateDescriptorSetD3D12, + + // pipeline layout + .createPipelineLayout = createPipelineLayoutD3D12, + .destroyPipelineLayout = destroyPipelineLayoutD3D12, + + // pipeline + .createGraphicsPipeline = createGraphicsPipelineD3D12, + .createComputePipeline = createComputePipelineD3D12, + .createRayTracingPipeline = createRayTracingPipelineD3D12, + .destroyPipeline = destroyPipelineD3D12, + + // shader binding tables + .createShaderBindingTable = createShaderBindingTableD3D12, + .destroyShaderBindingTable = destroyShaderBindingTableD3D12, + .updateShaderBindingTable = updateShaderBindingTableD3D12}; + +// clang-format on + #endif // _PAL_GRAPHICS_BACKENDS_H \ No newline at end of file diff --git a/src/opengl/pal_opengl_backends.h b/src/opengl/pal_opengl_backends.h index 71679a83..a77e0068 100644 --- a/src/opengl/pal_opengl_backends.h +++ b/src/opengl/pal_opengl_backends.h @@ -11,8 +11,8 @@ #include "pal_platform.h" #include "pal/pal_opengl.h" +// clang-format off typedef struct { - // clang-format off void (*shutdownGL)(); const PalGLInfo* (*getGLInfo)(); PalResult (*enumerateGLFBConfigs)(int32_t*, PalGLFBConfig*); @@ -23,7 +23,6 @@ typedef struct { PalResult (*swapBuffers)(PalGLWindow*, PalGLContext*); PalResult (*setSwapInterval)(int32_t); const PalBool* (*GetSupportedGLAPIs)(void*); - // clang-format on } OpenglBackend; // ================================================== @@ -86,6 +85,8 @@ static OpenglBackend s_EglBackend = { .setSwapInterval = eglSetSwapInterval, .GetSupportedGLAPIs = eglGetSupportedGLAPIs}; +// clang-format on + #endif // _PAL_HAS_EGL #endif // _PAL_OPENGL_BACKENDS_H \ No newline at end of file diff --git a/src/video/pal_video_backends.h b/src/video/pal_video_backends.h index 4763d798..9ecc44b7 100644 --- a/src/video/pal_video_backends.h +++ b/src/video/pal_video_backends.h @@ -9,8 +9,8 @@ #include "pal/pal_video.h" +// clang-format off typedef struct { - // clang-format off void (*shutdownVideo)(); void (*updateVideo)(); PalVideoFeatures (*getVideoFeatures)(); @@ -67,7 +67,6 @@ typedef struct { PalResult (*attachWindow)(void*, PalWindow**); PalResult (*detachWindow)(PalWindow*, void**); void* (*getInstance)(); - // clang-format on } VideoBackend; // ================================================== @@ -441,6 +440,8 @@ static VideoBackend s_wlBackend = { .getInstance = wlGetInstance, .detachWindow = wlDetachWindow}; +// clang-format on + #endif // PAL_HAS_WAYLAND_BACKEND #endif // _PAL_VIDEO_BACKENDS_H \ No newline at end of file From 0485234dd9ae5d011aa8fa108f54fddd8e472aaf Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 30 Jun 2026 22:32:37 +0000 Subject: [PATCH 309/372] start vulkan backend rework --- include/pal/pal_graphics.h | 27 +- pal_config.lua | 6 +- src/graphics/pal_graphics_backends.h | 1085 +----- src/graphics/pal_vulkan.c | 3066 +---------------- src/graphics/vulkan/pal_as_vulkan.c | 144 + src/graphics/vulkan/pal_buffer_vulkan.c | 473 +++ src/graphics/vulkan/pal_command_pool_vulkan.c | 231 ++ src/graphics/vulkan/pal_commands_vulkan.c | 1382 ++++++++ src/graphics/vulkan/pal_descriptors_vulkan.c | 11 + src/graphics/vulkan/pal_device_vulkan.c | 11 + src/graphics/vulkan/pal_image_vulkan.c | 11 + src/graphics/vulkan/pal_pipeline_vulkan.c | 11 + src/graphics/vulkan/pal_sbt_vulkan.c | 410 +++ src/graphics/vulkan/pal_sync_vulkan.c | 11 + src/graphics/vulkan/pal_vulkan.h | 493 +++ 15 files changed, 3417 insertions(+), 3955 deletions(-) create mode 100644 src/graphics/vulkan/pal_as_vulkan.c create mode 100644 src/graphics/vulkan/pal_buffer_vulkan.c create mode 100644 src/graphics/vulkan/pal_command_pool_vulkan.c create mode 100644 src/graphics/vulkan/pal_commands_vulkan.c create mode 100644 src/graphics/vulkan/pal_descriptors_vulkan.c create mode 100644 src/graphics/vulkan/pal_device_vulkan.c create mode 100644 src/graphics/vulkan/pal_image_vulkan.c create mode 100644 src/graphics/vulkan/pal_pipeline_vulkan.c create mode 100644 src/graphics/vulkan/pal_sbt_vulkan.c create mode 100644 src/graphics/vulkan/pal_sync_vulkan.c create mode 100644 src/graphics/vulkan/pal_vulkan.h diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 541be411..2d721dd5 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -445,7 +445,7 @@ #define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE (1U << 0) #define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE (1U << 1) -#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CU_DISABLE (1U << 2) +#define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE (1U << 2) #define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE (1U << 3) #define ePAL_ACCELERATION_STRUCTURE_CREATE_FLAG_NONE 0 @@ -538,6 +538,10 @@ #define PAL_IMAGE_MEMORY_USAGE_AUTO_GPU_ONLY 1 #define PAL_IMAGE_MEMORY_USAGE_COUNT 2 +#define PAL_RENDERING_FLAG_NONE 0 +#define PAL_RENDERING_FLAG_SUSPENDING (1U << 0) +#define PAL_RENDERING_FLAG_RESUMING (1U << 1) + #define PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1 0 /** @@ -1397,6 +1401,17 @@ typedef uint32_t PalBufferMemoryUsage; */ typedef uint32_t PalImageMemoryUsage; +/** + * @typedef PalRenderingFlags + * @brief Rendering flags. + * + * All rendering flags follow the format `PAL_RENDERING_FLAG_**` + * for consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalRenderingFlags; + /** * @typedef PalGraphicsBackendVtableVersion * @brief Graphics backend vtable versions. @@ -1850,6 +1865,8 @@ typedef struct { PalFormat* colorAttachmentsFormat; /**< Color attachments formats.*/ uint32_t colorAttachentCount; /**< Number of color attachment formats.*/ uint32_t viewCount; /**< View count. Set to 1 for default.*/ + PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_4`).*/ + PalRenderingFlags flags; /**< (eg. `PAL_RENDERING_FLAG_NONE`).*/ PalFormat depthStencilAttachmentFormat; /**< Depth/Stencil attachment format.*/ PalFormat fragmentShadingRateAttachmentFormat; /**< Fragment shading rate attachment format.*/ } PalRenderingLayoutInfo; @@ -3628,8 +3645,6 @@ typedef struct { */ PalResult(PAL_CALL* cmdPushConstants)( PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, uint32_t offset, uint32_t size, const void* value); @@ -6365,8 +6380,6 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( * The graphics system must be initialized before this call. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] shaderStageCount Capacity of the PalShaderStage array. - * @param[in] shaderStages Array of shader stages that can access the push constant. * @param[in] offset Offset in bytes into the push constant range. * @param[in] size Size of `value` in bytes. * @param[in] value Pointer to the push constant range data to write. @@ -6382,8 +6395,6 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( */ PAL_API PalResult PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, uint32_t offset, uint32_t size, const void* value); @@ -7300,7 +7311,7 @@ static inline PalBool PAL_CALL palIsSupported( uint32_t mask, uint32_t value) { - return (mask & (1ULL << value)) != 0; + return (mask & (1U << value)) != 0; } /** @} */ diff --git a/pal_config.lua b/pal_config.lua index 9ecc849e..0bc62726 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -12,13 +12,13 @@ PAL_BUILD_ABI_DUMP = true PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD_MODULE = true +PAL_BUILD_THREAD_MODULE = false -- build video module PAL_BUILD_VIDEO_MODULE = true -- build opengl module -PAL_BUILD_OPENGL_MODULE = true +PAL_BUILD_OPENGL_MODULE = false -- build graphics module -PAL_BUILD_GRAPHICS_MODULE = false +PAL_BUILD_GRAPHICS_MODULE = true diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index 21c6dde3..a6169bf3 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -160,6 +160,7 @@ typedef struct { // Vulkan // ================================================== +#if PAL_HAS_VULKAN_BACKEND PalResult PAL_CALL initGraphicsVk(const PalGraphicsDebugger*, const PalAllocator*); void PAL_CALL shutdownGraphicsVk(); PalResult PAL_CALL enumerateAdaptersVk(int32_t*, PalAdapter**); @@ -276,159 +277,45 @@ PalResult PAL_CALL cmdSetStencilOpVk(PalCommandBuffer*, PalStencilFaceFlags, Pal PalResult PAL_CALL createAccelerationstructureVk(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure*); PalResult PAL_CALL getAccelerationStructureBuildSizeVk(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); - -// ================================================== -// Buffer -// ================================================== - -PalResult PAL_CALL createBufferVk( - PalDevice* device, - const PalBufferCreateInfo* info, - PalBuffer** outBuffer); - -void PAL_CALL destroyBufferVk(PalBuffer* buffer); - -PalResult PAL_CALL getBufferMemoryRequirementsVk( - PalBuffer* buffer, - PalMemoryRequirements* requirements); - -PalResult PAL_CALL computeInstanceBufferRequirementsVk( - PalDevice* device, - uint32_t instanceCount, - uint64_t* outSize); - -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( - PalDevice* device, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize); - -PalResult PAL_CALL writeToInstanceBufferVk( - PalDevice* device, - void* ptr, - PalAccelerationStructureInstance* instances, - uint32_t instanceCount); - -PalResult PAL_CALL writeToImageCopyStagingBufferVk( - PalDevice* device, - void* ptr, - void* srcData, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL bindBufferMemoryVk( - PalBuffer* buffer, - PalMemory* memory, - uint64_t offset); - -PalResult PAL_CALL mapBufferMemoryVk( - PalBuffer* buffer, - uint64_t offset, - uint64_t size, - void** outPtr); - -void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer); - -PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer); - -// ================================================== -// Descriptor Pool, Set and Layout -// ================================================== - -PalResult PAL_CALL createDescriptorSetLayoutVk( - PalDevice* device, - const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout); - -void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout); - -PalResult PAL_CALL createDescriptorPoolVk( - PalDevice* device, - const PalDescriptorPoolCreateInfo* info, - PalDescriptorPool** outPool); - -void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool); - -PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool); - -PalResult PAL_CALL allocateDescriptorSetVk( - PalDevice* device, - PalDescriptorPool* pool, - PalDescriptorSetLayout* layout, - PalDescriptorSet** outSet); - -PalResult PAL_CALL updateDescriptorSetVk( - PalDevice* device, - uint32_t count, - PalDescriptorSetWriteInfo* infos); - -// ================================================== -// Pipeline Layout -// ================================================== - -PalResult PAL_CALL createPipelineLayoutVk( - PalDevice* device, - const PalPipelineLayoutCreateInfo* info, - PalPipelineLayout** outLayout); - -void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout); - -// ================================================== -// Pipeline -// ================================================== - -PalResult PAL_CALL createGraphicsPipelineVk( - PalDevice* device, - const PalGraphicsPipelineCreateInfo* info, - PalPipeline** outPipeline); - -PalResult PAL_CALL createComputePipelineVk( - PalDevice* device, - const PalComputePipelineCreateInfo* info, - PalPipeline** outPipeline); - -PalResult PAL_CALL createRayTracingPipelineVk( - PalDevice* device, - const PalRayTracingPipelineCreateInfo* info, - PalPipeline** outPipeline); - -void PAL_CALL destroyPipelineVk(PalPipeline* pipeline); - -// ================================================== -// Shader Binding Table -// ================================================== - -PalResult PAL_CALL createShaderBindingTableVk( - PalDevice* device, - const PalShaderBindingTableCreateInfo* info, - PalShaderBindingTable** outSbt); - -void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt); - -PalResult PAL_CALL updateShaderBindingTableVk( - PalShaderBindingTable* sbt, - uint32_t count, - PalShaderBindingTableRecordInfo* infos); +PalResult PAL_CALL createBufferVk(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); +void PAL_CALL destroyBufferVk(PalBuffer*); +PalResult PAL_CALL getBufferMemoryRequirementsVk(PalBuffer*, PalMemoryRequirements*); +PalResult PAL_CALL computeInstanceBufferRequirementsVk(PalDevice*, uint32_t, uint64_t*); +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk(PalDevice*, PalFormat, PalBufferImageCopyInfo*, uint32_t*, uint32_t*, uint64_t*); +PalResult PAL_CALL writeToInstanceBufferVk(PalDevice*, void*, PalAccelerationStructureInstance*, uint32_t); +PalResult PAL_CALL writeToImageCopyStagingBufferVk(PalDevice*, void*, void*, PalFormat, PalBufferImageCopyInfo*); +PalResult PAL_CALL bindBufferMemoryVk(PalBuffer*, PalMemory*, uint64_t); +PalResult PAL_CALL mapBufferMemoryVk(PalBuffer*, uint64_t, uint64_t, void**); +void PAL_CALL unmapBufferMemoryVk(PalBuffer*); +PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer*); +PalResult PAL_CALL createDescriptorSetLayoutVk(PalDevice*, const PalDescriptorSetLayoutCreateInfo*, PalDescriptorSetLayout**); +void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout*); +PalResult PAL_CALL createDescriptorPoolVk(PalDevice*, const PalDescriptorPoolCreateInfo*, PalDescriptorPool**); +void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool*); +PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool*); +PalResult PAL_CALL allocateDescriptorSetVk(PalDevice*, PalDescriptorPool*, PalDescriptorSetLayout*, PalDescriptorSet**); +PalResult PAL_CALL updateDescriptorSetVk(PalDevice*, uint32_t, PalDescriptorSetWriteInfo*); + +PalResult PAL_CALL createPipelineLayoutVk(PalDevice*, const PalPipelineLayoutCreateInfo*, PalPipelineLayout**); +void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout*); +PalResult PAL_CALL createGraphicsPipelineVk(PalDevice*, const PalGraphicsPipelineCreateInfo*, PalPipeline**); +PalResult PAL_CALL createComputePipelineVk(PalDevice*, const PalComputePipelineCreateInfo*, PalPipeline**); +PalResult PAL_CALL createRayTracingPipelineVk(PalDevice*, const PalRayTracingPipelineCreateInfo*, PalPipeline**); +void PAL_CALL destroyPipelineVk(PalPipeline*); +PalResult PAL_CALL createShaderBindingTableVk(PalDevice*, const PalShaderBindingTableCreateInfo*, PalShaderBindingTable**); +void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable*); +PalResult PAL_CALL updateShaderBindingTableVk(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); static PalGraphicsVtable s_VkBackend = { - // adapter .enumerateAdapters = enumerateAdaptersVk, .getAdapterInfo = getAdapterInfoVk, .getAdapterCapabilities = getAdapterCapabilitiesVk, .getAdapterFeatures = getAdapterFeaturesVk, .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetVk, - - // device .createDevice = createDeviceVk, .destroyDevice = destroyDeviceVk, - - // memory .allocateMemory = allocateMemoryVk, .freeMemory = freeMemoryVk, - - // extended adapter features .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesVk, .queryMultiViewCapabilities = queryMultiViewCapabilitiesVk, .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesVk, @@ -437,20 +324,14 @@ static PalGraphicsVtable s_VkBackend = { .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesVk, .queryRayTracingCapabilities = queryRayTracingCapabilitiesVk, .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesVk, - - // queue .createQueue = createQueueVk, .destroyQueue = destroyQueueVk, .waitQueue = waitQueueVk, .canQueuePresent = canQueuePresentVk, - - // format .enumerateFormats = enumerateFormatsVk, .isFormatSupported = isFormatSupportedVk, .queryFormatImageUsages = queryFormatImageUsagesVk, .queryFormatSampleCount = queryFormatSampleCountVk, - - // image .createImage = createImageVk, .destroyImage = destroyImageVk, .getImageInfo = getImageInfoVk, @@ -458,47 +339,31 @@ static PalGraphicsVtable s_VkBackend = { .bindImageMemory = bindImageMemoryVk, .mapImageMemory = mapImageMemoryVk, .unmapImageMemory = unmapImageMemoryVk, - - // image view .createImageView = createImageViewVk, .destroyImageView = destroyImageViewVk, - - // sampler .createSampler = createSamplerVk, .destroySampler = destroySamplerVk, - - // surface .createSurface = createSurfaceVk, .destroySurface = destroySurfaceVk, .getSurfaceCapabilities = getSurfaceCapabilitiesVk, - - // swapchain .createSwapchain = createSwapchainVk, .destroySwapchain = destroySwapchainVk, .getSwapchainImage = getSwapchainImageVk, .getNextSwapchainImage = getNextSwapchainImageVk, .presentSwapchain = presentSwapchainVk, .resizeSwapchain = resizeSwapchainVk, - - // shader .createShader = createShaderVk, .destroyShader = destroyShaderVk, - - // fence .createFence = createFenceVk, .destroyFence = destroyFenceVk, .waitFence = waitFenceVk, .resetFence = resetFenceVk, .isFenceSignaled = isFenceSignaledVk, - - // semaphore .createSemaphore = createSemaphoreVk, .destroySemaphore = destroySemaphoreVk, .waitSemaphore = waitSemaphoreVk, .signalSemaphore = signalSemaphoreVk, .getSemaphoreValue = getSemaphoreValueVk, - - // command pool and command buffer .createCommandPool = createCommandPoolVk, .destroyCommandPool = destroyCommandPoolVk, .resetCommandPool = resetCommandPoolVk, @@ -506,8 +371,6 @@ static PalGraphicsVtable s_VkBackend = { .freeCommandBuffer = freeCommandBufferVk, .resetCommandBuffer = resetCommandBufferVk, .submitCommandBuffer = submitCommandBufferVk, - - // command recording .cmdBegin = cmdBeginVk, .cmdEnd = cmdEndVk, .cmdExecuteCommandBuffer = cmdExecuteCommandBufferVk, @@ -549,13 +412,9 @@ static PalGraphicsVtable s_VkBackend = { .cmdSetDepthTestEnable = cmdSetDepthTestEnableVk, .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableVk, .cmdSetStencilOp = cmdSetStencilOpVk, - - // acceleration structure .createAccelerationstructure = createAccelerationstructureVk, .destroyAccelerationstructure = destroyAccelerationstructureVk, .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeVk, - - // buffer .createBuffer = createBufferVk, .destroyBuffer = destroyBufferVk, .getBufferMemoryRequirements = getBufferMemoryRequirementsVk, @@ -567,8 +426,6 @@ static PalGraphicsVtable s_VkBackend = { .getBufferDeviceAddress = getBufferDeviceAddressVk, .mapBufferMemory = mapBufferMemoryVk, .unmapBufferMemory = unmapBufferMemoryVk, - - // descriptor set layout, descriptor pool and descriptor set .createDescriptorSetLayout = createDescriptorSetLayoutVk, .destroyDescriptorSetLayout = destroyDescriptorSetLayoutVk, .createDescriptorPool = createDescriptorPoolVk, @@ -576,732 +433,178 @@ static PalGraphicsVtable s_VkBackend = { .resetDescriptorPool = resetDescriptorPoolVk, .allocateDescriptorSet = allocateDescriptorSetVk, .updateDescriptorSet = updateDescriptorSetVk, - - // pipeline layout .createPipelineLayout = createPipelineLayoutVk, .destroyPipelineLayout = destroyPipelineLayoutVk, - - // pipeline .createGraphicsPipeline = createGraphicsPipelineVk, .createComputePipeline = createComputePipelineVk, .createRayTracingPipeline = createRayTracingPipelineVk, .destroyPipeline = destroyPipelineVk, - - // shader binding table .createShaderBindingTable = createShaderBindingTableVk, .destroyShaderBindingTable = destroyShaderBindingTableVk, .updateShaderBindingTable = updateShaderBindingTableVk}; +#endif // PAL_HAS_VULKAN_BACKEND + // ================================================== // D3D12 // ================================================== -PalResult PAL_CALL initGraphicsD3D12( - const PalGraphicsDebugger* debugger, - const PalAllocator* allocator); - +#if PAL_HAS_D3D12_BACKEND +PalResult PAL_CALL initGraphicsD3D12(const PalGraphicsDebugger*, const PalAllocator*); void PAL_CALL shutdownGraphicsD3D12(); - -PalResult PAL_CALL enumerateAdaptersD3D12( - int32_t* count, - PalAdapter** outAdapters); - -PalResult PAL_CALL getAdapterInfoD3D12( - PalAdapter* adapter, - PalAdapterInfo* info); - -PalResult PAL_CALL getAdapterCapabilitiesD3D12( - PalAdapter* adapter, - PalAdapterCapabilities* caps); - -PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); - -uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( - PalAdapter* adapter, - PalShaderFormats shaderFormat); - -// ================================================== -// Device -// ================================================== - -PalResult PAL_CALL createDeviceD3D12( - PalAdapter* adapter, - PalAdapterFeatures features, - PalDevice** outDevice); - -void PAL_CALL destroyDeviceD3D12(PalDevice* device); - -PalResult PAL_CALL waitDeviceD3D12(PalDevice* device); - -// ================================================== -// Memory -// ================================================== - -PalResult PAL_CALL allocateMemoryD3D12( - PalDevice* device, - PalMemoryType type, - uint64_t memoryMask, - uint64_t size, - PalMemory** outMemory); - -void PAL_CALL freeMemoryD3D12( - PalDevice* device, - PalMemory* memory); - -// ================================================== -// Extended Adapter Features -// ================================================== - -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( - PalDevice* device, - PalSamplerAnisotropyCapabilities* caps); - -PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( - PalDevice* device, - PalMultiViewCapabilities* caps); - -PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( - PalDevice* device, - PalMultiViewportCapabilities* caps); - -PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( - PalDevice* device, - PalDepthStencilCapabilities* caps); - -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( - PalDevice* device, - PalFragmentShadingRateCapabilities* caps); - -PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( - PalDevice* device, - PalMeshShaderCapabilities* caps); - -PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( - PalDevice* device, - PalRayTracingCapabilities* caps); - -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( - PalDevice* device, - PalDescriptorIndexingCapabilities* caps); - -// ================================================== -// Queue -// ================================================== - -PalResult PAL_CALL createQueueD3D12( - PalDevice* device, - PalQueueType type, - PalQueue** outQueue); - -void PAL_CALL destroyQueueD3D12(PalQueue* queue); - -PalResult PAL_CALL waitQueueD3D12(PalQueue* queue); - -PalBool PAL_CALL canQueuePresentD3D12( - PalQueue* queue, - PalSurface* surface); - -// ================================================== -// Formats -// ================================================== - -PalResult PAL_CALL enumerateFormatsD3D12( - PalAdapter* adapter, - int32_t* count, - PalFormatInfo* outFormats); - -PalBool PAL_CALL isFormatSupportedD3D12( - PalAdapter* adapter, - PalFormat format); - -PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( - PalAdapter* adapter, - PalFormat format); - -PalSampleCount PAL_CALL queryFormatSampleCountD3D12( - PalAdapter* adapter, - PalFormat format); - -// ================================================== -// Image -// ================================================== - -PalResult PAL_CALL createImageD3D12( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage); - -void PAL_CALL destroyImageD3D12(PalImage* image); - -PalResult PAL_CALL getImageInfoD3D12( - PalImage* image, - PalImageInfo* info); - -PalResult PAL_CALL getImageMemoryRequirementsD3D12( - PalImage* image, - PalMemoryRequirements* requirements); - -PalResult PAL_CALL bindImageMemoryD3D12( - PalImage* image, - PalMemory* memory, - uint64_t offset); - -PalResult PAL_CALL mapImageMemoryD3D12( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr); - -void PAL_CALL unmapImageMemoryD3D12(PalImage* image); - -// ================================================== -// Image View -// ================================================== - -PalResult PAL_CALL createImageViewD3D12( - PalDevice* device, - PalImage* image, - const PalImageViewCreateInfo* info, - PalImageView** outImageView); - -void PAL_CALL destroyImageViewD3D12(PalImageView* imageView); - -// ================================================== -// Sampler -// ================================================== - -PalResult PAL_CALL createSamplerD3D12( - PalDevice* device, - const PalSamplerCreateInfo* info, - PalSampler** outSampler); - -void PAL_CALL destroySamplerD3D12(PalSampler* sampler); - -// ================================================== -// Surface -// ================================================== - -PalResult PAL_CALL createSurfaceD3D12( - PalDevice* device, - void* window, - void* windowInstance, - PalWindowInstanceType instanceType, - PalSurface** outSurface); - -void PAL_CALL destroySurfaceD3D12(PalSurface* surface); - -PalResult PAL_CALL getSurfaceCapabilitiesD3D12( - PalDevice* device, - PalSurface* surface, - PalSurfaceCapabilities* caps); - -// ================================================== -// Swapchain -// ================================================== - -PalResult PAL_CALL createSwapchainD3D12( - PalDevice* device, - PalQueue* queue, - PalSurface* surface, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain); - -void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain); - -PalImage* PAL_CALL getSwapchainImageD3D12( - PalSwapchain* swapchain, - int32_t index); - -PalResult PAL_CALL getNextSwapchainImageD3D12( - PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, - uint32_t* outIndex); - -PalResult PAL_CALL presentSwapchainD3D12( - PalSwapchain* swapchain, - PalSwapchainPresentInfo* info); - -PalResult PAL_CALL resizeSwapchainD3D12( - PalSwapchain* swapchain, - uint32_t newWidth, - uint32_t newHeight); - -// ================================================== -// Shader -// ================================================== - -PalResult PAL_CALL createShaderD3D12( - PalDevice* device, - const PalShaderCreateInfo* info, - PalShader** outShader); - -void PAL_CALL destroyShaderD3D12(PalShader* shader); - -// ================================================== -// Fence -// ================================================== - -PalResult PAL_CALL createFenceD3D12( - PalDevice* device, - PalBool signaled, - PalFence** outFence); - -void PAL_CALL destroyFenceD3D12(PalFence* fence); - -PalResult PAL_CALL waitFenceD3D12( - PalFence* fence, - uint64_t timeout); - -PalResult PAL_CALL resetFenceD3D12(PalFence* fence); - -PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence); - -// ================================================== -// Semaphore -// ================================================== - -PalResult PAL_CALL createSemaphoreD3D12( - PalDevice* device, - PalBool enableTimeline, - PalSemaphore** outSemaphore); - -void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); - -PalResult PAL_CALL waitSemaphoreD3D12( - PalSemaphore* semaphore, - uint64_t value, - uint64_t timeout); - -PalResult PAL_CALL signalSemaphoreD3D12( - PalSemaphore* semaphore, - PalQueue* queue, - uint64_t value); - -PalResult PAL_CALL getSemaphoreValueD3D12( - PalSemaphore* semaphore, - uint64_t* outValue); - -// ================================================== -// Command Pool And Buffer -// ================================================== - -PalResult PAL_CALL createCommandPoolD3D12( - PalDevice* device, - PalQueue* queue, - PalCommandPool** outPool); - -void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool); - -PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool); - -PalResult PAL_CALL allocateCommandBufferD3D12( - PalDevice* device, - PalCommandPool* pool, - PalCommandBufferType type, - PalCommandBuffer** outCmdBuffer); - -void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL submitCommandBufferD3D12( - PalQueue* queue, - PalCommandBufferSubmitInfo* info); - -// ================================================== -// Command Recording -// ================================================== - -PalResult PAL_CALL cmdBeginD3D12( - PalCommandBuffer* cmdBuffer, - PalRenderingLayoutInfo* info); - -PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL cmdExecuteCommandBufferD3D12( - PalCommandBuffer* primaryCmdBuffer, - PalCommandBuffer* secondaryCmdBuffer); - -PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( - PalCommandBuffer* cmdBuffer, - PalFragmentShadingRateState* state); - -PalResult PAL_CALL cmdDrawMeshTasksD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t drawCount); - -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructureBuildInfo* info); - -PalResult PAL_CALL cmdBeginRenderingD3D12( - PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info); - -PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer); - -PalResult PAL_CALL cmdCopyBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* dst, - PalBuffer* src, - PalBufferCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyBufferToImageD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* dstImage, - PalBuffer* srcBuffer, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyImageD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* dst, - PalImage* src, - PalImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdCopyImageToBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* dstBuffer, - PalImage* srcImage, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL cmdBindPipelineD3D12( - PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline); - -PalResult PAL_CALL cmdSetViewportD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalViewport* viewports); - -PalResult PAL_CALL cmdSetScissorsD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalRect2D* scissors); - -PalResult PAL_CALL cmdBindVertexBuffersD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t firstSlot, - uint32_t count, - PalBuffer** buffers, - uint64_t* offsets); - -PalResult PAL_CALL cmdBindIndexBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint64_t offset, - PalIndexType type); - -PalResult PAL_CALL cmdDrawD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance); - -PalResult PAL_CALL cmdDrawIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - -PalResult PAL_CALL cmdDrawIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdDrawIndexedD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance); - -PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count); - -PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount); - -PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructure* as, - PalUsageState oldUsageState, - PalUsageState newUsageState); - -PalResult PAL_CALL cmdImageBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* image, - PalImageSubresourceRange* subresourceRange, - PalUsageState oldUsageState, - PalUsageState newUsageState); - -PalResult PAL_CALL cmdBufferBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState); - -PalResult PAL_CALL cmdDispatchD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDispatchBaseD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - -PalResult PAL_CALL cmdDispatchIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer); - -PalResult PAL_CALL cmdTraceRaysD3D12( - PalCommandBuffer* cmdBuffer, - PalShaderBindingTable* sbt, - uint32_t raygenIndex, - uint32_t width, - uint32_t height, - uint32_t depth); - -PalResult PAL_CALL cmdTraceRaysIndirectD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t raygenIndex, - PalShaderBindingTable* sbt, - PalBuffer* buffer); - -PalResult PAL_CALL cmdBindDescriptorSetD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t setIndex, - PalDescriptorSet* set); - -PalResult PAL_CALL cmdPushConstantsD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, - uint32_t offset, - uint32_t size, - const void* value); - -PalResult PAL_CALL cmdSetCullModeD3D12( - PalCommandBuffer* cmdBuffer, - PalCullMode cullMode); - -PalResult PAL_CALL cmdSetFrontFaceD3D12( - PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace); - -PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( - PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology); - -PalResult PAL_CALL cmdSetDepthTestEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -PalResult PAL_CALL cmdSetStencilOpD3D12( - PalCommandBuffer* cmdBuffer, - PalStencilFaceFlags faceMask, - PalStencilOp failOp, - PalStencilOp passOp, - PalStencilOp depthFailOp, - PalCompareOp compareOp); - -// ================================================== -// Acceleration Structure -// ================================================== - -PalResult PAL_CALL createAccelerationstructureD3D12( - PalDevice* device, - const PalAccelerationStructureCreateInfo* info, - PalAccelerationStructure** outAs); - -void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as); - -PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( - PalDevice* device, - PalAccelerationStructureBuildInfo* info, - PalAccelerationStructureBuildSize* size); - -// ================================================== -// Buffer -// ================================================== - -PalResult PAL_CALL createBufferD3D12( - PalDevice* device, - const PalBufferCreateInfo* info, - PalBuffer** outBuffer); - -void PAL_CALL destroyBufferD3D12(PalBuffer* buffer); - -PalResult PAL_CALL getBufferMemoryRequirementsD3D12( - PalBuffer* buffer, - PalMemoryRequirements* requirements); - -PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( - PalDevice* device, - uint32_t instanceCount, - uint64_t* outSize); - -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( - PalDevice* device, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize); - -PalResult PAL_CALL writeToInstanceBufferD3D12( - PalDevice* device, - void* ptr, - PalAccelerationStructureInstance* instances, - uint32_t instanceCount); - -PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( - PalDevice* device, - void* ptr, - void* srcData, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo); - -PalResult PAL_CALL bindBufferMemoryD3D12( - PalBuffer* buffer, - PalMemory* memory, - uint64_t offset); - -PalResult PAL_CALL mapBufferMemoryD3D12( - PalBuffer* buffer, - uint64_t offset, - uint64_t size, - void** outPtr); - -void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer); - -PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); - -// ================================================== -// Descriptor Pool, Set and Layout -// ================================================== - -PalResult PAL_CALL createDescriptorSetLayoutD3D12( - PalDevice* device, - const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout); - -void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout); - -PalResult PAL_CALL createDescriptorPoolD3D12( - PalDevice* device, - const PalDescriptorPoolCreateInfo* info, - PalDescriptorPool** outPool); - -void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool); - -PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool); - -PalResult PAL_CALL allocateDescriptorSetD3D12( - PalDevice* device, - PalDescriptorPool* pool, - PalDescriptorSetLayout* layout, - PalDescriptorSet** outSet); - -PalResult PAL_CALL updateDescriptorSetD3D12( - PalDevice* device, - uint32_t count, - PalDescriptorSetWriteInfo* infos); - -// ================================================== -// Pipeline Layout -// ================================================== - -PalResult PAL_CALL createPipelineLayoutD3D12( - PalDevice* device, - const PalPipelineLayoutCreateInfo* info, - PalPipelineLayout** outLayout); - -void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout); - -// ================================================== -// Pipeline -// ================================================== - -PalResult PAL_CALL createGraphicsPipelineD3D12( - PalDevice* device, - const PalGraphicsPipelineCreateInfo* info, - PalPipeline** outPipeline); - -PalResult PAL_CALL createComputePipelineD3D12( - PalDevice* device, - const PalComputePipelineCreateInfo* info, - PalPipeline** outPipeline); - -PalResult PAL_CALL createRayTracingPipelineD3D12( - PalDevice* device, - const PalRayTracingPipelineCreateInfo* info, - PalPipeline** outPipeline); - -void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline); - -// ================================================== -// Shader Binding Table -// ================================================== - -PalResult PAL_CALL createShaderBindingTableD3D12( - PalDevice* device, - const PalShaderBindingTableCreateInfo* info, - PalShaderBindingTable** outSbt); - -void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); - -PalResult PAL_CALL updateShaderBindingTableD3D12( - PalShaderBindingTable* sbt, - uint32_t count, - PalShaderBindingTableRecordInfo* infos); +PalResult PAL_CALL enumerateAdaptersD3D12(int32_t*, PalAdapter**); +PalResult PAL_CALL getAdapterInfoD3D12(PalAdapter*, PalAdapterInfo*); +PalResult PAL_CALL getAdapterCapabilitiesD3D12(PalAdapter*, PalAdapterCapabilities*); +PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter*); +uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12(PalAdapter*, PalShaderFormats); +PalResult PAL_CALL createDeviceD3D12(PalAdapter*, PalAdapterFeatures, PalDevice**); +void PAL_CALL destroyDeviceD3D12(PalDevice*); +PalResult PAL_CALL waitDeviceD3D12(PalDevice*); +PalResult PAL_CALL allocateMemoryD3D12(PalDevice*, PalMemoryType, uint64_t, uint64_t, PalMemory**); +void PAL_CALL freeMemoryD3D12(PalDevice*, PalMemory*); +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12(PalDevice*, PalSamplerAnisotropyCapabilities*); +PalResult PAL_CALL queryMultiViewCapabilitiesD3D12(PalDevice*, PalMultiViewCapabilities*); +PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12(PalDevice*, PalMultiViewportCapabilities*); +PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12(PalDevice*, PalDepthStencilCapabilities*); +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12(PalDevice*, PalFragmentShadingRateCapabilities*); +PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12(PalDevice*, PalMeshShaderCapabilities*); +PalResult PAL_CALL queryRayTracingCapabilitiesD3D12(PalDevice*, PalRayTracingCapabilities*); +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12(PalDevice*, PalDescriptorIndexingCapabilities*); + +PalResult PAL_CALL createQueueD3D12(PalDevice*, PalQueueType, PalQueue**); +void PAL_CALL destroyQueueD3D12(PalQueue*); +PalResult PAL_CALL waitQueueD3D12(PalQueue*); +PalBool PAL_CALL canQueuePresentD3D12(PalQueue*, PalSurface*); +PalResult PAL_CALL enumerateFormatsD3D12(PalAdapter*, int32_t*, PalFormatInfo*); +PalBool PAL_CALL isFormatSupportedD3D12(PalAdapter*, PalFormat); +PalImageUsages PAL_CALL queryFormatImageUsagesD3D12(PalAdapter*, PalFormat); +PalSampleCount PAL_CALL queryFormatSampleCountD3D12(PalAdapter*, PalFormat); +PalResult PAL_CALL createImageD3D12(PalDevice*, const PalImageCreateInfo*, PalImage**); +void PAL_CALL destroyImageD3D12(PalImage*); +PalResult PAL_CALL getImageInfoD3D12(PalImage*, PalImageInfo*); +PalResult PAL_CALL getImageMemoryRequirementsD3D12(PalImage*, PalMemoryRequirements*); +PalResult PAL_CALL bindImageMemoryD3D12(PalImage*, PalMemory*, uint64_t); +PalResult PAL_CALL mapImageMemoryD3D12(PalImage*, uint64_t, uint64_t, void**); +void PAL_CALL unmapImageMemoryD3D12(PalImage*); +PalResult PAL_CALL createImageViewD3D12(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); +void PAL_CALL destroyImageViewD3D12(PalImageView*); + +PalResult PAL_CALL createSamplerD3D12(PalDevice*, const PalSamplerCreateInfo*, PalSampler**); +void PAL_CALL destroySamplerD3D12(PalSampler*); +PalResult PAL_CALL createSurfaceD3D12(PalDevice*, void*, void*, PalWindowInstanceType, PalSurface**); +void PAL_CALL destroySurfaceD3D12(PalSurface*); +PalResult PAL_CALL getSurfaceCapabilitiesD3D12(PalDevice*, PalSurface*, PalSurfaceCapabilities*); +PalResult PAL_CALL createSwapchainD3D12(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); +void PAL_CALL destroySwapchainD3D12(PalSwapchain*); +PalImage* PAL_CALL getSwapchainImageD3D12(PalSwapchain*, uint32_t); +PalResult PAL_CALL getNextSwapchainImageD3D12(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t); +PalResult PAL_CALL presentSwapchainD3D12(PalSwapchain*, PalSwapchainPresentInfo*); +PalResult PAL_CALL resizeSwapchainD3D12(PalSwapchain*, uint32_t, uint32_t); +PalResult PAL_CALL createShaderD3D12(PalDevice*, const PalShaderCreateInfo*, PalShader**); +void PAL_CALL destroyShaderD3D12(PalShader*); + +PalResult PAL_CALL createFenceD3D12(PalDevice*, PalBool, PalFence**); +void PAL_CALL destroyFenceD3D12(PalFence*); +PalResult PAL_CALL waitFenceD3D12(PalFence*, uint64_t); +PalResult PAL_CALL resetFenceD3D12(PalFence*); +PalBool PAL_CALL isFenceSignaledD3D12(PalFence*); +PalResult PAL_CALL createSemaphoreD3D12(PalDevice*, PalBool, PalSemaphore**); +void PAL_CALL destroySemaphoreD3D12(PalSemaphore*); +PalResult PAL_CALL waitSemaphoreD3D12(PalSemaphore*, uint64_t, uint64_t); +PalResult PAL_CALL signalSemaphoreD3D12(PalSemaphore*, PalQueue*, uint64_t); +PalResult PAL_CALL getSemaphoreValueD3D12(PalSemaphore*, uint64_t*); +PalResult PAL_CALL createCommandPoolD3D12(PalDevice*, PalQueue*, PalCommandPool**); +void PAL_CALL destroyCommandPoolD3D12(PalCommandPool*); +PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool*); +PalResult PAL_CALL allocateCommandBufferD3D12(PalDevice*, PalCommandPool*, PalCommandBufferType, PalCommandBuffer**); +void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer*); +PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer*); +PalResult PAL_CALL submitCommandBufferD3D12(PalQueue*, PalCommandBufferSubmitInfo*); + +PalResult PAL_CALL cmdBeginD3D12(PalCommandBuffer*, PalRenderingLayoutInfo*); +PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer*); +PalResult PAL_CALL cmdExecuteCommandBufferD3D12(PalCommandBuffer*, PalCommandBuffer*); +PalResult PAL_CALL cmdSetFragmentShadingRateD3D12(PalCommandBuffer*, PalFragmentShadingRateState*); +PalResult PAL_CALL cmdDrawMeshTasksD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); +PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdBuildAccelerationStructureD3D12(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); +PalResult PAL_CALL cmdBeginRenderingD3D12(PalCommandBuffer*, PalRenderingInfo*); +PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer*); +PalResult PAL_CALL cmdCopyBufferD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); +PalResult PAL_CALL cmdCopyBufferToImageD3D12(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); +PalResult PAL_CALL cmdCopyImageD3D12(PalCommandBuffer*, PalImage*, PalImage*, PalImageCopyInfo*); +PalResult PAL_CALL cmdCopyImageToBufferD3D12(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); +PalResult PAL_CALL cmdBindPipelineD3D12(PalCommandBuffer*, PalPipeline*); +PalResult PAL_CALL cmdSetViewportD3D12(PalCommandBuffer*, uint32_t, PalViewport*); +PalResult PAL_CALL cmdSetScissorsD3D12(PalCommandBuffer*, uint32_t, PalRect2D*); +PalResult PAL_CALL cmdBindVertexBuffersD3D12(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); +PalResult PAL_CALL cmdBindIndexBufferD3D12(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); +PalResult PAL_CALL cmdDrawD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); +PalResult PAL_CALL cmdDrawIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdDrawIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdDrawIndexedD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); +PalResult PAL_CALL cmdDrawIndexedIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); +PalResult PAL_CALL cmdImageBarrierD3D12(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); +PalResult PAL_CALL cmdBufferBarrierD3D12(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); +PalResult PAL_CALL cmdDispatchD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); +PalResult PAL_CALL cmdDispatchBaseD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); +PalResult PAL_CALL cmdDispatchIndirectD3D12(PalCommandBuffer*, PalBuffer*); +PalResult PAL_CALL cmdTraceRaysD3D12(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); +PalResult PAL_CALL cmdTraceRaysIndirectD3D12(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); +PalResult PAL_CALL cmdBindDescriptorSetD3D12(PalCommandBuffer*, uint32_t, PalDescriptorSet*); +PalResult PAL_CALL cmdPushConstantsD3D12(PalCommandBuffer*, uint32_t, uint32_t, const void*); +PalResult PAL_CALL cmdSetCullModeD3D12(PalCommandBuffer*, PalCullMode); +PalResult PAL_CALL cmdSetFrontFaceD3D12(PalCommandBuffer*, PalFrontFace); +PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12(PalCommandBuffer*, PalPrimitiveTopology); +PalResult PAL_CALL cmdSetDepthTestEnableD3D12(PalCommandBuffer*, PalBool); +PalResult PAL_CALL cmdSetDepthWriteEnableD3D12(PalCommandBuffer*, PalBool); +PalResult PAL_CALL cmdSetStencilOpD3D12(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); + +PalResult PAL_CALL createAccelerationstructureD3D12(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); +void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure*); +PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); +PalResult PAL_CALL createBufferD3D12(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); +void PAL_CALL destroyBufferD3D12(PalBuffer*); +PalResult PAL_CALL getBufferMemoryRequirementsD3D12(PalBuffer*, PalMemoryRequirements*); +PalResult PAL_CALL computeInstanceBufferRequirementsD3D12(PalDevice*, uint32_t, uint64_t*); +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12(PalDevice*, PalFormat, PalBufferImageCopyInfo*, uint32_t*, uint32_t*, uint64_t*); +PalResult PAL_CALL writeToInstanceBufferD3D12(PalDevice*, void*, PalAccelerationStructureInstance*, uint32_t); +PalResult PAL_CALL writeToImageCopyStagingBufferD3D12(PalDevice*, void*, void*, PalFormat, PalBufferImageCopyInfo*); +PalResult PAL_CALL bindBufferMemoryD3D12(PalBuffer*, PalMemory*, uint64_t); +PalResult PAL_CALL mapBufferMemoryD3D12(PalBuffer*, uint64_t, uint64_t, void**); +void PAL_CALL unmapBufferMemoryD3D12(PalBuffer*); +PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer*); +PalResult PAL_CALL createDescriptorSetLayoutD3D12(PalDevice*, const PalDescriptorSetLayoutCreateInfo*, PalDescriptorSetLayout**); +void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout*); +PalResult PAL_CALL createDescriptorPoolD3D12(PalDevice*, const PalDescriptorPoolCreateInfo*, PalDescriptorPool**); +void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool*); +PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool*); +PalResult PAL_CALL allocateDescriptorSetD3D12(PalDevice*, PalDescriptorPool*, PalDescriptorSetLayout*, PalDescriptorSet**); +PalResult PAL_CALL updateDescriptorSetD3D12(PalDevice*, uint32_t, PalDescriptorSetWriteInfo*); + +PalResult PAL_CALL createPipelineLayoutD3D12(PalDevice*, const PalPipelineLayoutCreateInfo*, PalPipelineLayout**); +void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout*); +PalResult PAL_CALL createGraphicsPipelineD3D12(PalDevice*, const PalGraphicsPipelineCreateInfo*, PalPipeline**); +PalResult PAL_CALL createComputePipelineD3D12(PalDevice*, const PalComputePipelineCreateInfo*, PalPipeline**); +PalResult PAL_CALL createRayTracingPipelineD3D12(PalDevice*, const PalRayTracingPipelineCreateInfo*, PalPipeline**); +void PAL_CALL destroyPipelineD3D12(PalPipeline*); +PalResult PAL_CALL createShaderBindingTableD3D12(PalDevice*, const PalShaderBindingTableCreateInfo*, PalShaderBindingTable**); +void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable*); +PalResult PAL_CALL updateShaderBindingTableD3D12(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); static PalGraphicsVtable s_D3D12Backend = { - // adapter .enumerateAdapters = enumerateAdaptersD3D12, .getAdapterInfo = getAdapterInfoD3D12, .getAdapterCapabilities = getAdapterCapabilitiesD3D12, .getAdapterFeatures = getAdapterFeaturesD3D12, .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetD3D12, - - // device .createDevice = createDeviceD3D12, .destroyDevice = destroyDeviceD3D12, - - // memory .allocateMemory = allocateMemoryD3D12, .freeMemory = freeMemoryD3D12, - - // extended adapter features .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesD3D12, .queryMultiViewCapabilities = queryMultiViewCapabilitiesD3D12, .queryMultiViewportCapabilities = queryMultiViewportCapabilitiesD3D12, @@ -1310,20 +613,14 @@ static PalGraphicsVtable s_D3D12Backend = { .queryMeshShaderCapabilities = queryMeshShaderCapabilitiesD3D12, .queryRayTracingCapabilities = queryRayTracingCapabilitiesD3D12, .queryDescriptorIndexingCapabilities = queryDescriptorIndexingCapabilitiesD3D12, - - // queue .createQueue = createQueueD3D12, .destroyQueue = destroyQueueD3D12, .waitQueue = waitQueueD3D12, .canQueuePresent = canQueuePresentD3D12, - - // format .enumerateFormats = enumerateFormatsD3D12, .isFormatSupported = isFormatSupportedD3D12, .queryFormatImageUsages = queryFormatImageUsagesD3D12, .queryFormatSampleCount = queryFormatSampleCountD3D12, - - // image .createImage = createImageD3D12, .destroyImage = destroyImageD3D12, .getImageInfo = getImageInfoD3D12, @@ -1331,47 +628,31 @@ static PalGraphicsVtable s_D3D12Backend = { .bindImageMemory = bindImageMemoryD3D12, .mapImageMemory = mapImageMemoryD3D12, .unmapImageMemory = unmapImageMemoryD3D12, - - // image view .createImageView = createImageViewD3D12, .destroyImageView = destroyImageViewD3D12, - - // sampler .createSampler = createSamplerD3D12, .destroySampler = destroySamplerD3D12, - - // surface .createSurface = createSurfaceD3D12, .destroySurface = destroySurfaceD3D12, .getSurfaceCapabilities = getSurfaceCapabilitiesD3D12, - - // swapchain .createSwapchain = createSwapchainD3D12, .destroySwapchain = destroySwapchainD3D12, .getSwapchainImage = getSwapchainImageD3D12, .getNextSwapchainImage = getNextSwapchainImageD3D12, .presentSwapchain = presentSwapchainD3D12, .resizeSwapchain = resizeSwapchainD3D12, - - // shader .createShader = createShaderD3D12, .destroyShader = destroyShaderD3D12, - - // fence .createFence = createFenceD3D12, .destroyFence = destroyFenceD3D12, .waitFence = waitFenceD3D12, .resetFence = resetFenceD3D12, .isFenceSignaled = isFenceSignaledD3D12, - - // semaphore .createSemaphore = createSemaphoreD3D12, .destroySemaphore = destroySemaphoreD3D12, .waitSemaphore = waitSemaphoreD3D12, .signalSemaphore = signalSemaphoreD3D12, .getSemaphoreValue = getSemaphoreValueD3D12, - - // command pool and command buffer .createCommandPool = createCommandPoolD3D12, .destroyCommandPool = destroyCommandPoolD3D12, .resetCommandPool = resetCommandPoolD3D12, @@ -1379,8 +660,6 @@ static PalGraphicsVtable s_D3D12Backend = { .freeCommandBuffer = freeCommandBufferD3D12, .resetCommandBuffer = resetCommandBufferD3D12, .submitCommandBuffer = submitCommandBufferD3D12, - - // command recording .cmdBegin = cmdBeginD3D12, .cmdEnd = cmdEndD3D12, .cmdExecuteCommandBuffer = cmdExecuteCommandBufferD3D12, @@ -1422,13 +701,9 @@ static PalGraphicsVtable s_D3D12Backend = { .cmdSetDepthTestEnable = cmdSetDepthTestEnableD3D12, .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableD3D12, .cmdSetStencilOp = cmdSetStencilOpD3D12, - - // acceleration structure .createAccelerationstructure = createAccelerationstructureD3D12, .destroyAccelerationstructure = destroyAccelerationstructureD3D12, .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeD3D12, - - // buffer .createBuffer = createBufferD3D12, .destroyBuffer = destroyBufferD3D12, .getBufferMemoryRequirements = getBufferMemoryRequirementsD3D12, @@ -1440,8 +715,6 @@ static PalGraphicsVtable s_D3D12Backend = { .getBufferDeviceAddress = getBufferDeviceAddressD3D12, .mapBufferMemory = mapBufferMemoryD3D12, .unmapBufferMemory = unmapBufferMemoryD3D12, - - // descriptor set layout, descriptor pool and descriptor set .createDescriptorSetLayout = createDescriptorSetLayoutD3D12, .destroyDescriptorSetLayout = destroyDescriptorSetLayoutD3D12, .createDescriptorPool = createDescriptorPoolD3D12, @@ -1449,22 +722,18 @@ static PalGraphicsVtable s_D3D12Backend = { .resetDescriptorPool = resetDescriptorPoolD3D12, .allocateDescriptorSet = allocateDescriptorSetD3D12, .updateDescriptorSet = updateDescriptorSetD3D12, - - // pipeline layout .createPipelineLayout = createPipelineLayoutD3D12, .destroyPipelineLayout = destroyPipelineLayoutD3D12, - - // pipeline .createGraphicsPipeline = createGraphicsPipelineD3D12, .createComputePipeline = createComputePipelineD3D12, .createRayTracingPipeline = createRayTracingPipelineD3D12, .destroyPipeline = destroyPipelineD3D12, - - // shader binding tables .createShaderBindingTable = createShaderBindingTableD3D12, .destroyShaderBindingTable = destroyShaderBindingTableD3D12, .updateShaderBindingTable = updateShaderBindingTableD3D12}; +#endif // PAL_HAS_D3D12_BACKEND + // clang-format on #endif // _PAL_GRAPHICS_BACKENDS_H \ No newline at end of file diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index a07de74d..f7fa02a9 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -34,8 +34,6 @@ // Typedefs, enums and structs // ================================================== -#define MAX_ATTACHMENTS 32 - #pragma region Video struct wl_display; @@ -192,436 +190,8 @@ typedef struct _SECURITY_ATTRIBUTES { } SECURITY_ATTRIBUTES; #endif // _MINWINBASE_ -#include -#include -#include -#include - #pragma endregion -typedef struct { - const PalGraphicsBackend* backend; - - VkPhysicalDevice handle; -} Adapter; - -typedef struct { - PalBool useCache; - void* handle; - Adapter* adapters; - VkInstance instance; - VkDebugUtilsMessengerEXT messenger; - PalDebugCallback callback; - - void* libX; - XGetWindowAttributesFn XGetWindowAttributes; - XVisualIDFromVisualFn XVisualIDFromVisual; - - void* libXcb; - xcb_get_window_attributes_fn xcbGetWindowAttributes; - xcb_get_window_attributes_reply_fn xcbGetWindowAttributesReply; - - PFN_vkEnumerateInstanceVersion enumerateInstanceVersion; - PFN_vkEnumerateInstanceExtensionProperties enumerateInstanceExtensionProperties; - PFN_vkDestroyInstance destroyInstance; - PFN_vkCreateInstance createInstance; - PFN_vkEnumeratePhysicalDevices enumeratePhysicalDevices; - PFN_vkGetPhysicalDeviceProperties getPhysicalDeviceProperties; - PFN_vkGetPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties; - PFN_vkEnumerateInstanceLayerProperties enumerateInstanceLayerProperties; - PFN_vkGetPhysicalDeviceQueueFamilyProperties getPhysicalDeviceQueueFamilyProperties; - PFN_vkEnumerateDeviceExtensionProperties enumerateDeviceExtensionProperties; - PFN_vkGetPhysicalDeviceFeatures getPhysicalDeviceFeatures; - PFN_vkGetPhysicalDeviceFeatures2 getPhysicalDeviceFeatures2; - PFN_vkGetInstanceProcAddr getInstanceProcAddr; - PFN_vkCreateImageView createImageView; - PFN_vkDestroyImageView destroyImageView; - PFN_vkGetPhysicalDeviceProperties2 getPhysicalDeviceProperties2; - PFN_vkGetPhysicalDeviceFormatProperties getPhysicalDeviceFormatProperties; - PFN_vkGetPhysicalDeviceImageFormatProperties getPhysicalDeviceImageFormatProperties; - PFN_vkGetImageMemoryRequirements getImageMemoryRequirements; - PFN_vkAllocateMemory allocateMemory; - PFN_vkFreeMemory freeMemory; - PFN_vkBindImageMemory bindImageMemory; - - PFN_vkCreateDevice createDevice; - PFN_vkDestroyDevice destroyDevice; - PFN_vkGetDeviceQueue getDeviceQueue; - PFN_vkQueueSubmit queueSubmit; - PFN_vkGetDeviceProcAddr getDeviceProcAddr; - PFN_vkCreateImage createImage; - PFN_vkDestroyImage destroyImage; - PFN_vkCreateShaderModule createShader; - PFN_vkDestroyShaderModule destroyShader; - PFN_vkCreateSampler createSampler; - PFN_vkDestroySampler destroySampler; - - PFN_vkCreateCommandPool createCommandPool; - PFN_vkDestroyCommandPool destroyCommandPool; - PFN_vkAllocateCommandBuffers allocateCommandBuffer; - PFN_vkFreeCommandBuffers freeCommandBuffer; - PFN_vkCreateFence createFence; - PFN_vkDestroyFence destroyFence; - PFN_vkResetFences resetFence; - PFN_vkWaitForFences waitFence; - PFN_vkGetFenceStatus isFenceSignaled; - PFN_vkCreateSemaphore createSemaphore; - PFN_vkDestroySemaphore destroySemaphore; - - PFN_vkBeginCommandBuffer cmdBegin; - PFN_vkEndCommandBuffer cmdEnd; - PFN_vkResetCommandPool resetCommandPool; - PFN_vkResetCommandBuffer resetCommandBuffer; - PFN_vkCmdExecuteCommands cmdExecuteCommandBuffer; - PFN_vkCmdCopyBuffer cmdCopyBuffer; - PFN_vkCmdCopyBufferToImage cmdCopyBufferToImage; - PFN_vkCmdCopyImage cmdCopyImage; - PFN_vkCmdCopyImageToBuffer cmdCopyImageToBuffer; - PFN_vkCmdBindPipeline cmdBindPipeline; - PFN_vkCmdSetViewport cmdSetViewports; - PFN_vkCmdSetScissor cmdSetScissors; - PFN_vkCmdBindVertexBuffers cmdBindVertexBuffers; - PFN_vkCmdBindIndexBuffer cmdBindIndexBuffer; - PFN_vkCmdDraw cmdDraw; - PFN_vkCmdDrawIndirect cmdDrawIndirect; - PFN_vkCmdDrawIndexed cmdDrawIndexed; - PFN_vkCmdDrawIndexedIndirect cmdDrawIndexedIndirect; - PFN_vkCmdDispatch cmdDispatch; - PFN_vkCmdDispatchIndirect cmdDispatchIndirect; - PFN_vkCmdBindDescriptorSets cmdBindDescriptorSets; - PFN_vkCmdPushConstants cmdPushConstants; - - PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; - PFN_vkCreateXlibSurfaceKHR createXlibSurface; - PFN_vkCreateXcbSurfaceKHR createXcbSurface; - PFN_vkCreateWin32SurfaceKHR createWin32Surface; - - PFN_vkDestroySurfaceKHR destroySurface; - PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR getSurfaceCapabilities; - PFN_vkGetPhysicalDeviceSurfaceFormatsKHR getSurfaceFormats; - PFN_vkGetPhysicalDeviceSurfacePresentModesKHR getSurfacePresentModes; - PFN_vkGetPhysicalDeviceSurfaceSupportKHR checkSurfaceSupport; - - PFN_vkCreateBuffer createBuffer; - PFN_vkDestroyBuffer destroyBuffer; - PFN_vkGetBufferMemoryRequirements getBufferMemoryRequirements; - PFN_vkBindBufferMemory bindBufferMemory; - PFN_vkMapMemory mapMemory; - PFN_vkUnmapMemory unmapMemory; - PFN_vkGetBufferDeviceAddress getBufferDeviceAddress; - - PFN_vkCreateDescriptorSetLayout createDescriptorSetLayout; - PFN_vkDestroyDescriptorSetLayout destroyDescriptorSetLayout; - PFN_vkCreateDescriptorPool createDescriptorPool; - PFN_vkDestroyDescriptorPool destroyDescriptorPool; - PFN_vkResetDescriptorPool resetDescriptorPool; - PFN_vkAllocateDescriptorSets allocateDescriptorSet; - PFN_vkUpdateDescriptorSets updateDescriptorSet; - - PFN_vkCreatePipelineLayout createPipelineLayout; - PFN_vkDestroyPipelineLayout destroyPipelineLayout; - PFN_vkCreateGraphicsPipelines createGraphicsPipeline; - PFN_vkCreateComputePipelines createComputePipeline; - PFN_vkDestroyPipeline destroyPipeline; - PFN_vkCreateDebugUtilsMessengerEXT createMessenger; - PFN_vkDestroyDebugUtilsMessengerEXT destroyMessenger; - PFN_vkQueueWaitIdle waitQueue; - - VkAllocationCallbacks vkAllocator; - const PalAllocator* allocator; -} Vulkan; - -typedef struct { - int32_t familyIndex; - VkPhysicalDevice phyDevice; - VkQueue handle; - VkQueueFlags usages; - VkQueueFlags usedUsages; -} PhysicalQueue; - -// Limits we must enforce ourselves -typedef struct { - uint32_t maxPayloadSize; -} DeviceLimits; - -typedef struct { - const PalGraphicsBackend* backend; - - PalAdapterFeatures features; - int32_t phyQueueCount; - int32_t phyQueueIndex; - int32_t queueFamilyCount; - uint32_t memoryClassMask[3]; - VkPhysicalDevice phyDevice; - VkDevice handle; - PhysicalQueue* phyQueues; - PFN_vkGetBufferDeviceAddress getBufferrAddress; - PFN_vkCmdDispatchBase cmdDispatchBase; - - // draw indirect - PFN_vkCmdDrawIndirectCount cmdDrawIndirectCount; - PFN_vkCmdDrawIndexedIndirectCount cmdDrawIndexedIndirectCount; - - // swapchain - PFN_vkCreateSwapchainKHR createSwapchain; - PFN_vkDestroySwapchainKHR destroySwapchain; - PFN_vkGetSwapchainImagesKHR getSwapchainImages; - PFN_vkAcquireNextImageKHR acquireNextImage; - PFN_vkQueuePresentKHR queuePresent; - - // semaphore - PFN_vkWaitSemaphores waitSemaphore; - PFN_vkSignalSemaphore signalSemaphore; - PFN_vkGetSemaphoreCounterValue getSemaphoreValue; - - // fragment shading rate - PFN_vkCmdSetFragmentShadingRateKHR cmdSetFragmentShadingRate; - - // mesh shader - PFN_vkCmdDrawMeshTasksEXT cmdDrawMeshTask; - PFN_vkCmdDrawMeshTasksIndirectEXT cmdDrawMeshTaskIndirect; - PFN_vkCmdDrawMeshTasksIndirectCountEXT cmdDrawMeshTaskIndirectCount; - - // ray tracing - PFN_vkCreateAccelerationStructureKHR createAccelerationStructure; - PFN_vkDestroyAccelerationStructureKHR destroyAccelerationStructure; - PFN_vkGetAccelerationStructureBuildSizesKHR getAccelerationBuildsize; - PFN_vkCmdBuildAccelerationStructuresKHR cmdBuildAccelerationStructures; - PFN_vkGetAccelerationStructureDeviceAddressKHR getAccelerationDeviceAddress; - - PFN_vkCmdTraceRaysKHR cmdTraceRays; - PFN_vkCreateRayTracingPipelinesKHR createRayTracingPipeline; - PFN_vkCmdTraceRaysIndirectKHR cmdTraceRaysIndirect; - PFN_vkGetRayTracingShaderGroupHandlesKHR getRayTracingShaderGroupHandles; - - // dynamic rendering - PFN_vkCmdBeginRendering cmdBeginRendering; - PFN_vkCmdEndRendering cmdEndRendering; - PFN_vkCmdPipelineBarrier2 cmdPipelineBarrier; - PFN_vkQueueSubmit2 queueSubmit; - - // dynamic states - PFN_vkCmdSetCullMode cmdSetCullMode; - PFN_vkCmdSetFrontFace cmdSetFrontFace; - PFN_vkCmdSetPrimitiveTopology cmdSetPrimitiveTopology; - - PFN_vkCmdSetDepthTestEnable cmdSetDepthTestEnable; - PFN_vkCmdSetDepthWriteEnable cmdSetDepthWriteEnable; - PFN_vkCmdSetStencilOp cmdSetStencilOp; - - DeviceLimits limits; -} Device; - -typedef struct { - const PalGraphicsBackend* backend; - - VkQueueFlags usage; - Device* device; - PhysicalQueue* phyQueue; -} Queue; - -typedef struct { - PalMemoryType type; - VkDeviceMemory handle; -} Memory; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool belongsToSwapchain; - Device* device; - Memory* memory; - VkImage handle; - PalImageInfo info; -} Image; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t layerCount; - Device* device; - Image* image; - VkImageView handle; -} ImageView; - -typedef struct { - const PalGraphicsBackend* backend; - - Device* device; - VkSurfaceKHR handle; -} Surface; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t imageCount; - Device* device; - Queue* queue; - VkSwapchainKHR handle; - Image* images; -} Swapchain; - -typedef struct { - uint32_t patchControlPoints; - VkShaderStageFlagBits stage; - char entryName[PAL_SHADER_ENTRY_NAME_SIZE]; -} ShaderEntry; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t entryCount; - ShaderEntry* entries; - Device* device; - VkShaderModule handle; -} Shader; - -typedef struct { - const PalGraphicsBackend* backend; - - Device* device; - VkCommandPool handle; -} CommandPool; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool primary; - Device* device; - CommandPool* pool; - void* pipeline; - VkBuffer buffer; - VkDeviceMemory bufferMemory; - VkCommandBuffer handle; -} CommandBuffer; - -typedef struct { - const PalGraphicsBackend* backend; - - Device* device; - VkFence handle; -} Fence; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool isTimeline; - Device* device; - VkSemaphore handle; -} Semaphore; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBufferUsages usages; - Memory* memory; - Device* device; - VkBuffer handle; -} Buffer; - -typedef struct { - const PalGraphicsBackend* backend; - - VkDeviceAddress address; - VkBuffer buffer; - VkDeviceMemory bufferMemory; - VkDeviceAddress bufferAddress; - Device* device; - VkAccelerationStructureKHR handle; -} AccelerationStructure; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool hasDescriptorIndexing; - Device* device; - VkDescriptorSetLayout handle; -} DescriptorSetLayout; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool hasDescriptorIndexing; - Device* device; - VkDescriptorPool handle; -} DescriptorPool; - -typedef struct { - const PalGraphicsBackend* backend; - - Device* device; - DescriptorPool* pool; - VkDescriptorSet handle; -} DescriptorSet; - -typedef struct { - const PalGraphicsBackend* backend; - - Device* device; - VkSampler handle; -} Sampler; - -typedef struct { - const PalGraphicsBackend* backend; - - Device* device; - VkPipelineLayout handle; -} PipelineLayout; - -typedef struct { - uint32_t raygenCount; - uint32_t raygenDataSize; - uint32_t missCount; - uint32_t missDataSize; - uint32_t hitCount; - uint32_t hitDataSize; - uint32_t callableCount; - uint32_t callableDataSize; -} ShaderBindingTableInfo; - -typedef struct { - const PalGraphicsBackend* backend; - - VkPipelineBindPoint bindPoint; - Device* device; - VkPipeline handle; - VkPipelineLayout layout; - ShaderBindingTableInfo sbtInfo; -} Pipeline; - -typedef struct { - uint32_t startIndex; - uint32_t offset; - VkStridedDeviceAddressRegionKHR region; -} AddressRegion; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool isDirty; - uint32_t stagingBufferSize; - uint32_t handleSize; - Device* device; - VkBuffer buffer; - VkBuffer stagingBuffer; - VkDeviceMemory bufferMemory; - VkDeviceMemory stagingBufferMemory; - VkDeviceAddress baseAddress; - Pipeline* pipeline; - - AddressRegion raygen; - AddressRegion miss; - AddressRegion hit; - AddressRegion callable; -} ShaderBindingTable; - -typedef struct { - VkPipelineStageFlags2 stages; - VkPipelineStageFlags2 dstStages; - VkAccessFlags2 access; - VkImageLayout layout; -} Barrier; - static Vulkan s_Vk = {0}; // ================================================== @@ -655,6 +225,24 @@ static void* loadProc(void* lib, const char* name) #endif } +VkRenderingFlags renderingFlagToVk(PalRenderingFlags flags) +{ + VkRenderingFlags renderingFlags = 0; + if (flags == PAL_RENDERING_FLAG_NONE) { + renderingFlags = 0; + } + + if (flags & PAL_RENDERING_FLAG_RESUMING) { + renderingFlags |= VK_RENDERING_RESUMING_BIT; + } + + if (flags & PAL_RENDERING_FLAG_SUSPENDING) { + renderingFlags |= VK_RENDERING_SUSPENDING_BIT; + } + + return renderingFlags; +} + static PalResult resultFromVk(VkResult result) { switch (result) { @@ -1456,55 +1044,6 @@ static VkFormat vertexTypeToVk(PalVertexType type) return VK_FORMAT_UNDEFINED; } -static VkBufferUsageFlags bufferUsageToVk(PalBufferUsages usages) -{ - VkBufferUsageFlags flags = 0; - if (usages & PAL_BUFFER_USAGE_VERTEX) { - flags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - } - - if (usages & PAL_BUFFER_USAGE_INDEX) { - flags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - } - - if (usages & PAL_BUFFER_USAGE_UNIFORM) { - flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - } - - if (usages & PAL_BUFFER_USAGE_STORAGE) { - flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - } - - if (usages & PAL_BUFFER_USAGE_TRANSFER_SRC) { - flags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - } - - if (usages & PAL_BUFFER_USAGE_TRANSFER_DST) { - flags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - } - - if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR; - } - - if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { - flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - } - - if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT) { - flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; - } - - if (usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - } - - if (usages & PAL_BUFFER_USAGE_INDIRECT) { - flags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; - } - - return flags; -} static uint32_t getVertexTypeSizeVk(PalVertexType type) { @@ -2460,114 +1999,7 @@ static void fillBuildInfoVk( buildInfo->scratchData = scratchData; } -static uint32_t getFormatSizeVk(PalFormat format) -{ - switch (format) { - case PAL_FORMAT_R8_UNORM: - case PAL_FORMAT_R8_SNORM: - case PAL_FORMAT_R8_UINT: - case PAL_FORMAT_R8_SINT: - case PAL_FORMAT_R8_SRGB: - case PAL_FORMAT_S8_UINT: - return 1; - - case PAL_FORMAT_R16_UNORM: - case PAL_FORMAT_R16_SNORM: - case PAL_FORMAT_R16_UINT: - case PAL_FORMAT_R16_SINT: - case PAL_FORMAT_R16_SFLOAT: - case PAL_FORMAT_R8G8_UNORM: - case PAL_FORMAT_R8G8_SNORM: - case PAL_FORMAT_R8G8_UINT: - case PAL_FORMAT_R8G8_SINT: - case PAL_FORMAT_R8G8_SRGB: - case PAL_FORMAT_D16_UNORM: - return 2; - - case PAL_FORMAT_R8G8B8_UNORM: - case PAL_FORMAT_R8G8B8_SNORM: - case PAL_FORMAT_R8G8B8_UINT: - case PAL_FORMAT_R8G8B8_SINT: - case PAL_FORMAT_R8G8B8_SRGB: - case PAL_FORMAT_B8G8R8_UNORM: - case PAL_FORMAT_B8G8R8_SNORM: - case PAL_FORMAT_B8G8R8_UINT: - case PAL_FORMAT_B8G8R8_SINT: - case PAL_FORMAT_B8G8R8_SRGB: - case PAL_FORMAT_D16_UNORM_S8_UINT: - return 3; - - case PAL_FORMAT_R32_UINT: - case PAL_FORMAT_R32_SINT: - case PAL_FORMAT_R32_SFLOAT: - case PAL_FORMAT_R16G16_UNORM: - case PAL_FORMAT_R16G16_SNORM: - case PAL_FORMAT_R16G16_UINT: - case PAL_FORMAT_R16G16_SINT: - case PAL_FORMAT_R16G16_SFLOAT: - case PAL_FORMAT_R8G8B8A8_UNORM: - case PAL_FORMAT_R8G8B8A8_SNORM: - case PAL_FORMAT_R8G8B8A8_UINT: - case PAL_FORMAT_R8G8B8A8_SINT: - case PAL_FORMAT_R8G8B8A8_SRGB: - case PAL_FORMAT_B8G8R8A8_UNORM: - case PAL_FORMAT_B8G8R8A8_SNORM: - case PAL_FORMAT_B8G8R8A8_UINT: - case PAL_FORMAT_B8G8R8A8_SINT: - case PAL_FORMAT_B8G8R8A8_SRGB: - case PAL_FORMAT_D32_SFLOAT: - case PAL_FORMAT_D24_UNORM_S8_UINT: - return 4; - - case PAL_FORMAT_D32_SFLOAT_S8_UINT: - return 5; - - case PAL_FORMAT_R16G16B16_UNORM: - case PAL_FORMAT_R16G16B16_SNORM: - case PAL_FORMAT_R16G16B16_UINT: - case PAL_FORMAT_R16G16B16_SINT: - case PAL_FORMAT_R16G16B16_SFLOAT: - return 6; - - case PAL_FORMAT_R64_UINT: - case PAL_FORMAT_R64_SINT: - case PAL_FORMAT_R64_SFLOAT: - case PAL_FORMAT_R32G32_UINT: - case PAL_FORMAT_R32G32_SINT: - case PAL_FORMAT_R32G32_SFLOAT: - case PAL_FORMAT_R16G16B16A16_UNORM: - case PAL_FORMAT_R16G16B16A16_SNORM: - case PAL_FORMAT_R16G16B16A16_UINT: - case PAL_FORMAT_R16G16B16A16_SINT: - case PAL_FORMAT_R16G16B16A16_SFLOAT: - return 8; - - case PAL_FORMAT_R32G32B32_UINT: - case PAL_FORMAT_R32G32B32_SINT: - case PAL_FORMAT_R32G32B32_SFLOAT: - return 12; - - case PAL_FORMAT_R64G64_UINT: - case PAL_FORMAT_R64G64_SINT: - case PAL_FORMAT_R64G64_SFLOAT: - case PAL_FORMAT_R32G32B32A32_UINT: - case PAL_FORMAT_R32G32B32A32_SINT: - case PAL_FORMAT_R32G32B32A32_SFLOAT: - return 16; - - case PAL_FORMAT_R64G64B64_UINT: - case PAL_FORMAT_R64G64B64_SINT: - case PAL_FORMAT_R64G64B64_SFLOAT: - return 24; - - case PAL_FORMAT_R64G64B64A64_UINT: - case PAL_FORMAT_R64G64B64A64_SINT: - case PAL_FORMAT_R64G64B64A64_SFLOAT: - return 32; - } - return 0; -} static VkImageAspectFlags imageAspectToVk(PalImageAspect aspect) { @@ -2588,64 +2020,6 @@ static VkImageAspectFlags imageAspectToVk(PalImageAspect aspect) return VK_IMAGE_ASPECT_COLOR_BIT; } -static VkGeometryInstanceFlagsKHR instanceFlagsToVk(PalAccelerationStructureInstanceFlags flags) -{ - VkGeometryInstanceFlagsKHR instanceFlags = 0; - if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE) { - instanceFlags |= VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR; - } - - if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE) { - instanceFlags |= VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR; - } - - if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE) { - instanceFlags |= VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - } - - if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE) { - instanceFlags |= VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR; - } - - return instanceFlags; -} - -static void commitShaderbindingTableUpdateVk( - CommandBuffer* cmdBuffer, - ShaderBindingTable* sbt) -{ - if (!sbt->isDirty) { - return; - } - - // begin upload buffer copy to gpu buffer - VkBufferCopy copyRegion = {0}; - copyRegion.size = sbt->stagingBufferSize; - s_Vk.cmdCopyBuffer(cmdBuffer->handle, sbt->stagingBuffer, sbt->buffer, 1, ©Region); - - // put a memory barrier - VkBufferMemoryBarrier2KHR barrier = {0}; - barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; - - barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR; - barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; - - barrier.dstStageMask = VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; - barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT_KHR; - - barrier.buffer = sbt->buffer; - barrier.offset = 0; - barrier.size = VK_WHOLE_SIZE; - - VkDependencyInfo dependencyInfo = {0}; - dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; - dependencyInfo.bufferMemoryBarrierCount = 1; - dependencyInfo.pBufferMemoryBarriers = &barrier; - - cmdBuffer->device->cmdPipelineBarrier(cmdBuffer->handle, &dependencyInfo); - sbt->isDirty = PAL_FALSE; -} - // ================================================== // Adapter // ================================================== @@ -6472,1997 +5846,25 @@ PalResult PAL_CALL getSemaphoreValueVk( } // ================================================== -// Command Pool And Buffer +// Descriptor Pool, Set and Layout // ================================================== -PalResult PAL_CALL createCommandPoolVk( +PalResult PAL_CALL createDescriptorSetLayoutVk( PalDevice* device, - PalQueue* queue, - PalCommandPool** outPool) + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout) { VkResult result; - CommandPool* pool = nullptr; Device* vkDevice = (Device*)device; - Queue* vkQueue = (Queue*)queue; - PhysicalQueue* phyQueue = vkQueue->phyQueue; + VkDescriptorSetLayoutBinding* bindings = nullptr; + VkDescriptorBindingFlags* bindingFlags = nullptr; + DescriptorSetLayout* layout = nullptr; + uint32_t count = info->bindingCount; + VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsCreateInfo = {0}; - pool = palAllocate(s_Vk.allocator, sizeof(CommandPool), 0); - if (!pool) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkCommandPoolCreateInfo cInfo = {0}; - cInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - cInfo.queueFamilyIndex = phyQueue->familyIndex; - cInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - - result = s_Vk.createCommandPool(vkDevice->handle, &cInfo, &s_Vk.vkAllocator, &pool->handle); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pool); - return resultFromVk(result); - } - - pool->device = vkDevice; - *outPool = (PalCommandPool*)pool; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool) -{ - CommandPool* vkPool = (CommandPool*)pool; - s_Vk.destroyCommandPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, vkPool); -} - -PalResult PAL_CALL resetCommandPoolVk(PalCommandPool* pool) -{ - CommandPool* vkCmdPool = (CommandPool*)pool; - s_Vk.resetCommandPool(vkCmdPool->device->handle, vkCmdPool->handle, 0); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL allocateCommandBufferVk( - PalDevice* device, - PalCommandPool* pool, - PalCommandBufferType type, - PalCommandBuffer** outCmdBuffer) -{ - VkResult result; - CommandBuffer* cmdBuffer = nullptr; - Device* vkDevice = (Device*)device; - CommandPool* vkPool = (CommandPool*)pool; - - cmdBuffer = palAllocate(s_Vk.allocator, sizeof(CommandBuffer), 0); - if (!cmdBuffer) { - PAL_RESULT_OUT_OF_MEMORY; - } - - VkCommandBufferAllocateInfo allocateInfo = {0}; - allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocateInfo.commandBufferCount = 1; - allocateInfo.commandPool = vkPool->handle; - - allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - cmdBuffer->primary = PAL_TRUE; - if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { - allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; - cmdBuffer->primary = PAL_FALSE; - } - - result = s_Vk.allocateCommandBuffer(vkDevice->handle, &allocateInfo, &cmdBuffer->handle); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, cmdBuffer); - return resultFromVk(result); - } - - // create a gpu buffer if ray tracing is enabled - if (vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - VkBufferCreateInfo bufCreateInfo = {0}; - bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufCreateInfo.size = sizeof(VkTraceRaysIndirectCommandKHR); - bufCreateInfo.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; - bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - result = s_Vk.createBuffer( - vkDevice->handle, - &bufCreateInfo, - &s_Vk.vkAllocator, - &cmdBuffer->buffer); - - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - - // allocate CPU upload memory and bind - VkMemoryRequirements memReq = {0}; - s_Vk.getBufferMemoryRequirements(vkDevice->handle, cmdBuffer->buffer, &memReq); - - VkMemoryAllocateInfo allocateInfo = {0}; - allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.allocationSize = memReq.size; - - uint32_t mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; - uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); - allocateInfo.memoryTypeIndex = memoryIndex; - - result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, - &cmdBuffer->bufferMemory); - - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - - s_Vk.bindBufferMemory(vkDevice->handle, cmdBuffer->buffer, cmdBuffer->bufferMemory, 0); - } - - cmdBuffer->device = vkDevice; - cmdBuffer->pool = vkPool; - *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - s_Vk.freeCommandBuffer( - vkCmdBuffer->device->handle, - vkCmdBuffer->pool->handle, - 1, - &vkCmdBuffer->handle); - - if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - s_Vk.destroyBuffer(vkCmdBuffer->device->handle, vkCmdBuffer->buffer, &s_Vk.vkAllocator); - s_Vk.freeMemory(vkCmdBuffer->device->handle, vkCmdBuffer->bufferMemory, &s_Vk.vkAllocator); - } - - palFree(s_Vk.allocator, vkCmdBuffer); -} - -PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL submitCommandBufferVk( - PalQueue* queue, - PalCommandBufferSubmitInfo* info) -{ - VkResult result; - int32_t waitSemaphoreCount = 0; - int32_t signalSemaphoreCount = 0; - VkFence fenceHandle = nullptr; - VkSemaphore waitSemaphoreHandle = nullptr; - VkSemaphore signalSemaphoreHandle = nullptr; - Queue* vkQueue = (Queue*)queue; - CommandBuffer* vkCmdBuffer = (CommandBuffer*)info->cmdBuffer; - PhysicalQueue* phyQueue = vkQueue->phyQueue; - - if (info->waitSemaphore) { - Semaphore* tmp = (Semaphore*)info->waitSemaphore; - waitSemaphoreHandle = tmp->handle; - waitSemaphoreCount = 1; - } - - if (info->signalSemaphore) { - Semaphore* tmp = (Semaphore*)info->signalSemaphore; - signalSemaphoreHandle = tmp->handle; - signalSemaphoreCount = 1; - } - - if (info->fence) { - Fence* tmp = (Fence*)info->fence; - fenceHandle = tmp->handle; - } - - VkCommandBufferSubmitInfoKHR cmdBufferSubmitInfo = {0}; - cmdBufferSubmitInfo.commandBuffer = vkCmdBuffer->handle; - cmdBufferSubmitInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR; - - VkSemaphoreSubmitInfoKHR waitSubmitInfo = {0}; - waitSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; - waitSubmitInfo.semaphore = waitSemaphoreHandle; - waitSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - - VkSemaphoreSubmitInfoKHR signalSubmitInfo = {0}; - signalSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; - signalSubmitInfo.semaphore = signalSemaphoreHandle; - signalSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - - if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - waitSubmitInfo.value = info->waitValue; - signalSubmitInfo.value = info->signalValue; - } - - VkSubmitInfo2KHR submitInfo = {0}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR; - submitInfo.commandBufferInfoCount = 1; - submitInfo.pCommandBufferInfos = &cmdBufferSubmitInfo; - submitInfo.pSignalSemaphoreInfos = &signalSubmitInfo; - submitInfo.pWaitSemaphoreInfos = &waitSubmitInfo; - submitInfo.waitSemaphoreInfoCount = waitSemaphoreCount; - submitInfo.signalSemaphoreInfoCount = signalSemaphoreCount; - - result = vkCmdBuffer->device->queueSubmit(phyQueue->handle, 1, &submitInfo, fenceHandle); - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Command Recording -// ================================================== - -PalResult PAL_CALL cmdBeginVk( - PalCommandBuffer* cmdBuffer, - PalRenderingLayoutInfo* info) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - VkCommandBufferBeginInfo beginInfo = {0}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - - VkCommandBufferInheritanceInfo inheritanceInfo = {0}; - inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; - VkCommandBufferInheritanceRenderingInfoKHR layout = {0}; - layout.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; - - VkFormat format = VK_FORMAT_UNDEFINED; - VkFormat colorAttachments[MAX_ATTACHMENTS]; - - if (!vkCmdBuffer->primary) { - // secondary command buffer - for (int i = 0; i < info->colorAttachentCount; i++) { - format = formatToVk(info->colorAttachmentsFormat[i]); - colorAttachments[i] = format; - } - layout.colorAttachmentCount = info->colorAttachentCount; - layout.pColorAttachmentFormats = colorAttachments; - - // depth stencil attachment - format = formatToVk(info->depthStencilAttachmentFormat); - layout.depthAttachmentFormat = format; - layout.stencilAttachmentFormat = format; - - layout.rasterizationSamples = samplesToVk(info->multisampleCount); - if (info->viewCount == 1) { - layout.viewMask = 0; - } else { - layout.viewMask = (1 << info->viewCount) - 1; - } - - inheritanceInfo.pNext = &layout; - beginInfo.pNext = &inheritanceInfo; - } - - VkResult result = s_Vk.cmdBegin(vkCmdBuffer->handle, &beginInfo); - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - VkResult result = s_Vk.cmdEnd(vkCmdBuffer->handle); - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdExecuteCommandBufferVk( - PalCommandBuffer* primaryCmdBuffer, - PalCommandBuffer* secondaryCmdBuffer) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)primaryCmdBuffer; - CommandBuffer* vkCmdBuffer2 = (CommandBuffer*)secondaryCmdBuffer; - - s_Vk.cmdExecuteCommandBuffer(vkCmdBuffer->handle, 1, &vkCmdBuffer2->handle); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetFragmentShadingRateVk( - PalCommandBuffer* cmdBuffer, - PalFragmentShadingRateState* state) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkExtent2D size = getShadingRateSizeVk(state->rate); - VkFragmentShadingRateCombinerOpKHR combinerOps[2]; - for (int i = 0; i < 2; i++) { - combinerOps[i] = combinerOpsToVk(state->combinerOps[i]); - } - - device->cmdSetFragmentShadingRate(vkCmdBuffer->handle, &size, combinerOps); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawMeshTasksVk( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - device->cmdDrawMeshTask(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t drawCount) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - Buffer* vkBuffer = (Buffer*)buffer; - - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); - device->cmdDrawMeshTaskIndirect( - vkCmdBuffer->handle, - vkBuffer->handle, - 0, - drawCount, - stride); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - Buffer* vkBuffer = (Buffer*)buffer; - Buffer* vkCountBuffer = (Buffer*)countBuffer; - - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); - device->cmdDrawMeshTaskIndirectCount( - vkCmdBuffer->handle, - vkBuffer->handle, - 0, - vkCountBuffer->handle, - 0, - maxDrawCount, - stride); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBuildAccelerationStructureVk( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructureBuildInfo* info) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - VkAccelerationStructureGeometryKHR* geometries = nullptr; - VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; - AccelerationStructure* tmpAs = (AccelerationStructure*)info->src; - AccelerationStructure* dstAs = (AccelerationStructure*)info->dst; - VkAccelerationStructureKHR srcAs = nullptr; - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - - if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - // cache these for top level as - VkAccelerationStructureBuildRangeInfoKHR cachedRangeInfo = {0}; - VkAccelerationStructureGeometryKHR cachedGeometries = {0}; - uint32_t geometryCount = info->geometryCount; - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { - geometryCount = 1; - rangeInfos = &cachedRangeInfo; - geometries = &cachedGeometries; - } - - if (tmpAs) { - srcAs = tmpAs->handle; - } - - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - geometries = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureGeometryKHR) * geometryCount, - 0); - - rangeInfos = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureBuildRangeInfoKHR) * geometryCount, - 0); - - if (!rangeInfos || !geometries) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * geometryCount); - memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * geometryCount); - } - - fillBuildInfoVk( - geometryCount, - info, - nullptr, - geometries, - srcAs, - dstAs->handle, - rangeInfos, - &buildInfo); - - const VkAccelerationStructureBuildRangeInfoKHR* tmp[1]; - tmp[0] = rangeInfos; - vkCmdBuffer->device->cmdBuildAccelerationStructures(vkCmdBuffer->handle, 1, &buildInfo, tmp); - - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - palFree(s_Vk.allocator, geometries); - palFree(s_Vk.allocator, rangeInfos); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBeginRenderingVk( - PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - VkRenderingInfoKHR rendering = {0}; - rendering.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR; - - VkRenderingAttachmentInfoKHR depthAttachment = {0}; - VkRenderingAttachmentInfoKHR stencilAttachment = {0}; - VkRenderingAttachmentInfoKHR colorAttachments[MAX_ATTACHMENTS]; - - VkRenderingAttachmentInfoKHR* attachment = nullptr; - PalAttachmentDesc* desc = nullptr; - ImageView* imageView = nullptr; - ImageView* resolveImageView = nullptr; - VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL; - - VkRenderingFragmentShadingRateAttachmentInfoKHR fsrInfo = {0}; - fsrInfo.sType = VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; - - uint32_t layerCount = UINT32_MAX; - uint32_t renderWidth = UINT32_MAX; - uint32_t renderHeight = UINT32_MAX; - for (int i = 0; i < info->colorAttachentCount; i++) { - attachment = &colorAttachments[i]; - desc = &info->colorAttachments[i]; - imageView = (ImageView*)desc->imageView; - resolveImageView = (ImageView*)desc->resolveImageView; - - attachment->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; - attachment->pNext = nullptr; - layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachment->resolveImageView = nullptr; - attachment->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - attachment->clearValue.color.float32[0] = desc->clearValue.color[0]; - attachment->clearValue.color.float32[1] = desc->clearValue.color[1]; - attachment->clearValue.color.float32[2] = desc->clearValue.color[2]; - attachment->clearValue.color.float32[3] = desc->clearValue.color[3]; - - attachment->imageView = imageView->handle; - if (resolveImageView) { - attachment->resolveImageView = resolveImageView->handle; - attachment->resolveImageLayout = layout; - } - - // load op - if (desc->loadOp == PAL_LOAD_OP_CLEAR) { - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - - } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - - } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } - - // store op - if (desc->storeOp == PAL_STORE_OP_STORE) { - attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; - - } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { - attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - - attachment->resolveMode = resolveModeToVk(desc->resolveMode); - attachment->imageLayout = layout; - - // compute layer count and render area - layerCount = minVk(layerCount, imageView->layerCount); - renderWidth = minVk(renderWidth, imageView->image->info.width); - renderHeight = minVk(renderHeight, imageView->image->info.height); - - if (resolveImageView) { - layerCount = minVk(layerCount, resolveImageView->layerCount); - renderWidth = minVk(renderWidth, resolveImageView->image->info.width); - renderHeight = minVk(renderHeight, resolveImageView->image->info.height); - } - } - - rendering.colorAttachmentCount = info->colorAttachentCount; - rendering.pColorAttachments = colorAttachments; - - // depth attachment - if (info->depthStencilAttachment) { - attachment = &depthAttachment; - desc = info->depthStencilAttachment; - imageView = (ImageView*)desc->imageView; - resolveImageView = (ImageView*)desc->resolveImageView; - - attachment->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; - attachment->pNext = nullptr; - attachment->resolveImageView = nullptr; - attachment->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - stencilAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; - stencilAttachment.pNext = nullptr; - stencilAttachment.resolveImageView = nullptr; - stencilAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - attachment->clearValue.depthStencil.depth = desc->clearValue.depth; - stencilAttachment.clearValue.depthStencil.stencil = desc->clearValue.stencil; - - attachment->imageView = imageView->handle; - stencilAttachment.imageView = imageView->handle; - if (resolveImageView) { - attachment->resolveImageView = resolveImageView->handle; - attachment->resolveImageLayout = layout; - - stencilAttachment.resolveImageView = resolveImageView->handle; - stencilAttachment.resolveImageLayout = layout; - } - - // load op - if (desc->loadOp == PAL_LOAD_OP_CLEAR) { - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - - } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - - } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } - - // store op - if (desc->storeOp == PAL_STORE_OP_STORE) { - attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; - - } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { - attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - - // stencil load op - if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { - stencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - - } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { - stencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - - } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { - stencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } - - // stencil store op - if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { - stencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - - } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { - stencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - - attachment->resolveMode = resolveModeToVk(desc->resolveMode); - attachment->imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - stencilAttachment.resolveMode = resolveModeToVk(desc->resolveMode); - stencilAttachment.imageLayout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; - - rendering.pDepthAttachment = &depthAttachment; - rendering.pStencilAttachment = &stencilAttachment; - - // compute layer count and render area - layerCount = minVk(layerCount, imageView->layerCount); - renderWidth = minVk(renderWidth, imageView->image->info.width); - renderHeight = minVk(renderHeight, imageView->image->info.height); - - if (resolveImageView) { - layerCount = minVk(layerCount, resolveImageView->layerCount); - renderWidth = minVk(renderWidth, resolveImageView->image->info.width); - renderHeight = minVk(renderHeight, resolveImageView->image->info.height); - } - } - - // fragment shading rate attachment - if (info->fragmentShadingRateAttachment) { - imageView = (ImageView*)info->fragmentShadingRateAttachment->imageView; - fsrInfo.imageView = imageView->handle; - - fsrInfo.shadingRateAttachmentTexelSize.width = - info->fragmentShadingRateAttachment->texelWidth; - - fsrInfo.shadingRateAttachmentTexelSize.height = - info->fragmentShadingRateAttachment->texelHeight; - - fsrInfo.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; - rendering.pNext = &fsrInfo; - - // compute layer count and render area - layerCount = minVk(layerCount, imageView->layerCount); - renderWidth = minVk(renderWidth, imageView->image->info.width); - renderHeight = minVk(renderHeight, imageView->image->info.height); - } - - rendering.layerCount = layerCount; - rendering.renderArea.offset.x = 0; - rendering.renderArea.offset.y = 0; - rendering.renderArea.extent.width = renderWidth; - rendering.renderArea.extent.height = renderHeight; - - if (info->viewCount == 1) { - rendering.viewMask = 0; - } else { - rendering.viewMask = (1 << info->viewCount) - 1; - } - - vkCmdBuffer->device->cmdBeginRendering(vkCmdBuffer->handle, &rendering); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - vkCmdBuffer->device->cmdEndRendering(vkCmdBuffer->handle); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdCopyBufferVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* dst, - PalBuffer* src, - PalBufferCopyInfo* copyInfo) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* dstbuffer = (Buffer*)dst; - Buffer* srcBuffer = (Buffer*)src; - - VkBufferCopy copyRegion = {0}; - copyRegion.size = copyInfo->size; - copyRegion.dstOffset = copyInfo->dstOffset; - copyRegion.srcOffset = copyInfo->srcOffset; - s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, srcBuffer->handle, dstbuffer->handle, 1, ©Region); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdCopyBufferToImageVk( - PalCommandBuffer* cmdBuffer, - PalImage* dstImage, - PalBuffer* srcBuffer, - PalBufferImageCopyInfo* copyInfo) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Image* dst = (Image*)dstImage; - Buffer* src = (Buffer*)srcBuffer; - - VkBufferImageCopy copyRegion = {0}; - copyRegion.bufferImageHeight = copyInfo->bufferImageHeight; - copyRegion.bufferOffset = copyInfo->bufferOffset; - copyRegion.bufferRowLength = copyInfo->bufferRowLength; - - copyRegion.imageOffset.x = copyInfo->imageOffsetX; - copyRegion.imageOffset.y = copyInfo->imageOffsetY; - copyRegion.imageOffset.z = copyInfo->imageOffsetZ; - - copyRegion.imageExtent.width = copyInfo->imageWidth; - copyRegion.imageExtent.height = copyInfo->imageHeight; - copyRegion.imageExtent.depth = copyInfo->imageDepth; - - copyRegion.imageSubresource.aspectMask = imageAspectToVk(copyInfo->imageAspect); - copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; - copyRegion.imageSubresource.layerCount = copyInfo->ImageArrayLayerCount; - copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; - - s_Vk.cmdCopyBufferToImage( - vkCmdBuffer->handle, - src->handle, - dst->handle, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - ©Region); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdCopyImageVk( - PalCommandBuffer* cmdBuffer, - PalImage* dst, - PalImage* src, - PalImageCopyInfo* copyInfo) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Image* dstImage = (Image*)dst; - Image* srcImage = (Image*)src; - - VkImageCopy copyRegion = {0}; - copyRegion.dstOffset.x = copyInfo->dstOffsetX; - copyRegion.dstOffset.y = copyInfo->dstOffsetY; - copyRegion.dstOffset.z = copyInfo->dstOffsetZ; - - copyRegion.srcOffset.x = copyInfo->srcOffsetX; - copyRegion.srcOffset.y = copyInfo->srcOffsetY; - copyRegion.srcOffset.z = copyInfo->srcOffsetZ; - - copyRegion.extent.width = copyInfo->width; - copyRegion.extent.height = copyInfo->height; - copyRegion.extent.depth = copyInfo->depth; - - copyRegion.dstSubresource.aspectMask = imageAspectToVk(copyInfo->aspect); - copyRegion.dstSubresource.baseArrayLayer = copyInfo->dstStartArrayLayer; - copyRegion.dstSubresource.layerCount = copyInfo->arrayLayerCount; - copyRegion.dstSubresource.mipLevel = copyInfo->dstMipLevel; - - copyRegion.srcSubresource.aspectMask = imageAspectToVk(copyInfo->aspect); - copyRegion.srcSubresource.baseArrayLayer = copyInfo->srcStartArrayLayer; - copyRegion.srcSubresource.layerCount = copyInfo->arrayLayerCount; - copyRegion.srcSubresource.mipLevel = copyInfo->srcMipLevel; - - s_Vk.cmdCopyImage( - vkCmdBuffer->handle, - srcImage->handle, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dstImage->handle, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, - ©Region); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdCopyImageToBufferVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* dstBuffer, - PalImage* srcImage, - PalBufferImageCopyInfo* copyInfo) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* dst = (Buffer*)dstBuffer; - Image* src = (Image*)srcImage; - - VkBufferImageCopy copyRegion = {0}; - copyRegion.bufferImageHeight = copyInfo->bufferImageHeight; - copyRegion.bufferOffset = copyInfo->bufferOffset; - copyRegion.bufferRowLength = copyInfo->bufferRowLength; - - copyRegion.imageOffset.x = copyInfo->imageOffsetX; - copyRegion.imageOffset.y = copyInfo->imageOffsetY; - copyRegion.imageOffset.z = copyInfo->imageOffsetZ; - - copyRegion.imageExtent.width = copyInfo->imageWidth; - copyRegion.imageExtent.height = copyInfo->imageHeight; - copyRegion.imageExtent.depth = copyInfo->imageDepth; - - copyRegion.imageSubresource.aspectMask = imageAspectToVk(copyInfo->imageAspect); - copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; - copyRegion.imageSubresource.layerCount = copyInfo->ImageArrayLayerCount; - copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; - - s_Vk.cmdCopyImageToBuffer( - vkCmdBuffer->handle, - src->handle, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - dst->handle, - 1, - ©Region); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBindPipelineVk( - PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Pipeline* vkPipeline = (Pipeline*)pipeline; - s_Vk.cmdBindPipeline(vkCmdBuffer->handle, vkPipeline->bindPoint, vkPipeline->handle); - - vkCmdBuffer->pipeline = vkPipeline; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetViewportVk( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalViewport* viewports) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - VkViewport cachedViewport; - VkViewport* vkViewports = nullptr; - - if (count > 1) { - vkViewports = palAllocate(s_Vk.allocator, sizeof(VkViewport) * count, 0); - if (!vkViewports) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - } else { - vkViewports = &cachedViewport; - } - - for (int i = 0; i < count; i++) { - VkViewport* tmp = &vkViewports[i]; - tmp->x = viewports[i].x; - tmp->y = viewports[i].y; - tmp->width = viewports[i].width; - tmp->height = viewports[i].height; - tmp->minDepth = viewports[i].minDepth; - tmp->maxDepth = viewports[i].maxDepth; - } - - s_Vk.cmdSetViewports(vkCmdBuffer->handle, 0, count, vkViewports); - if (count > 1) { - palFree(s_Vk.allocator, vkViewports); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetScissorsVk( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalRect2D* scissors) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - VkRect2D cachedScissor; - VkRect2D* vkScissors = nullptr; - - if (count > 1) { - vkScissors = palAllocate(s_Vk.allocator, sizeof(VkRect2D) * count, 0); - if (!vkScissors) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - } else { - vkScissors = &cachedScissor; - } - - for (int i = 0; i < count; i++) { - VkRect2D* tmp = &vkScissors[i]; - tmp->offset.x = scissors[i].x; - tmp->offset.y = scissors[i].y; - tmp->extent.width = scissors[i].width; - tmp->extent.height = scissors[i].height; - } - - s_Vk.cmdSetScissors(vkCmdBuffer->handle, 0, count, vkScissors); - if (count > 1) { - palFree(s_Vk.allocator, vkScissors); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBindVertexBuffersVk( - PalCommandBuffer* cmdBuffer, - uint32_t firstSlot, - uint32_t count, - PalBuffer** buffers, - uint64_t* offsets) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - VkBuffer cachedbuffer = nullptr; - VkBuffer* vkBuffers = nullptr; - - if (count > 1) { - vkBuffers = palAllocate(s_Vk.allocator, sizeof(VkBuffer) * count, 0); - if (!vkBuffers) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - } else { - vkBuffers = &cachedbuffer; - } - - for (int i = 0; i < count; i++) { - Buffer* tmp = (Buffer*)buffers[i]; - vkBuffers[i] = tmp->handle; - } - - s_Vk.cmdBindVertexBuffers(vkCmdBuffer->handle, firstSlot, count, vkBuffers, offsets); - if (count > 1) { - palFree(s_Vk.allocator, vkBuffers); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBindIndexBufferVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint64_t offset, - PalIndexType type) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* vkBuffer = (Buffer*)buffer; - VkIndexType bufferType = VK_INDEX_TYPE_UINT32; - if (type == PAL_INDEX_TYPE_UINT16) { - bufferType = VK_INDEX_TYPE_UINT16; - } - - s_Vk.cmdBindIndexBuffer(vkCmdBuffer->handle, vkBuffer->handle, offset, bufferType); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawVk( - PalCommandBuffer* cmdBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - s_Vk.cmdDraw(vkCmdBuffer->handle, vertexCount, instanceCount, firstVertex, firstInstance); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* vkBuffer = (Buffer*)buffer; - uint32_t stride = sizeof(VkDrawIndirectCommand); - - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - s_Vk.cmdDrawIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawIndirectCountVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* vkBuffer = (Buffer*)buffer; - Buffer* vkCountBuffer = (Buffer*)countBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - uint32_t stride = sizeof(VkDrawIndirectCommand); - device->cmdDrawIndirectCount( - vkCmdBuffer->handle, - vkBuffer->handle, - 0, - vkCountBuffer->handle, - 0, - maxDrawCount, - stride); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawIndexedVk( - PalCommandBuffer* cmdBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - s_Vk.cmdDrawIndexed( - vkCmdBuffer->handle, - indexCount, - instanceCount, - firstIndex, - vertexOffset, - firstInstance); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawIndexedIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* vkBuffer = (Buffer*)buffer; - uint32_t stride = sizeof(VkDrawIndexedIndirectCommand); - - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - s_Vk.cmdDrawIndexedIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* vkBuffer = (Buffer*)buffer; - Buffer* vkCountBuffer = (Buffer*)countBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - uint32_t stride = sizeof(VkDrawIndexedIndirectCommand); - device->cmdDrawIndexedIndirectCount( - vkCmdBuffer->handle, - vkBuffer->handle, - 0, - vkCountBuffer->handle, - 0, - maxDrawCount, - stride); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdAccelerationStructureBarrierVk( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructure* as, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkMemoryBarrier2KHR barrier = {0}; - barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR; - - Barrier old, new; - old = barrierToVk( - oldUsageStateInfo->shaderStageCount, - oldUsageStateInfo->usageState, - oldUsageStateInfo->shaderStages); - - new = barrierToVk( - newUsageStateInfo->shaderStageCount, - newUsageStateInfo->usageState, - newUsageStateInfo->shaderStages); - - barrier.srcStageMask = old.stages; - barrier.srcAccessMask = old.access; - - barrier.dstStageMask = new.stages; - barrier.dstAccessMask = new.access; - - VkDependencyInfo dependencyInfo = {0}; - dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; - dependencyInfo.memoryBarrierCount = 1; - dependencyInfo.pMemoryBarriers = &barrier; - - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdImageBarrierVk( - PalCommandBuffer* cmdBuffer, - PalImage* image, - PalImageSubresourceRange* subresourceRange, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Image* vkImage = (Image*)image; - VkImageMemoryBarrier2KHR barrier = {0}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR; - - Barrier old, new; - old = barrierToVk( - oldUsageStateInfo->shaderStageCount, - oldUsageStateInfo->usageState, - oldUsageStateInfo->shaderStages); - - new = barrierToVk( - newUsageStateInfo->shaderStageCount, - newUsageStateInfo->usageState, - newUsageStateInfo->shaderStages); - - barrier.srcStageMask = old.stages; - barrier.srcAccessMask = old.access; - barrier.oldLayout = old.layout; - - barrier.dstStageMask = new.stages; - barrier.dstAccessMask = new.access; - barrier.newLayout = new.layout; - - barrier.image = vkImage->handle; - barrier.subresourceRange.aspectMask = imageAspectToVk(subresourceRange->aspect); - barrier.subresourceRange.baseArrayLayer = subresourceRange->startArrayLayer; - barrier.subresourceRange.baseMipLevel = subresourceRange->startMipLevel; - barrier.subresourceRange.layerCount = subresourceRange->layerArrayCount; - barrier.subresourceRange.levelCount = subresourceRange->mipLevelCount; - - VkDependencyInfo dependencyInfo = {0}; - dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; - dependencyInfo.imageMemoryBarrierCount = 1; - dependencyInfo.pImageMemoryBarriers = &barrier; - - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBufferBarrierVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* vkBuffer = (Buffer*)buffer; - VkBufferMemoryBarrier2KHR barrier = {0}; - barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; - - Barrier old, new; - old = barrierToVk( - oldUsageStateInfo->shaderStageCount, - oldUsageStateInfo->usageState, - oldUsageStateInfo->shaderStages); - - new = barrierToVk( - newUsageStateInfo->shaderStageCount, - newUsageStateInfo->usageState, - newUsageStateInfo->shaderStages); - - barrier.srcStageMask = old.stages; - barrier.srcAccessMask = old.access; - - barrier.dstStageMask = new.stages; - barrier.dstAccessMask = new.access; - - barrier.buffer = vkBuffer->handle; - barrier.offset = 0; - barrier.size = VK_WHOLE_SIZE; - - VkDependencyInfo dependencyInfo = {0}; - dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; - dependencyInfo.bufferMemoryBarrierCount = 1; - dependencyInfo.pBufferMemoryBarriers = &barrier; - - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDispatchVk( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - s_Vk.cmdDispatch(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDispatchBaseVk( - PalCommandBuffer* cmdBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_DISPATCH_BASE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - device->cmdDispatchBase( - vkCmdBuffer->handle, - baseGroupX, - baseGroupY, - baseGroupZ, - groupCountX, - groupCountY, - groupCountZ); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDispatchIndirectVk( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* vkBuffer = (Buffer*)buffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - s_Vk.cmdDispatchIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdTraceRaysVk( - PalCommandBuffer* cmdBuffer, - PalShaderBindingTable* sbt, - uint32_t raygenIndex, - uint32_t width, - uint32_t height, - uint32_t depth) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - ShaderBindingTable* vkSbt = (ShaderBindingTable*)sbt; - - if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkStridedDeviceAddressRegionKHR raygenAddress = {0}; - raygenAddress.size = vkSbt->raygen.region.size; - raygenAddress.stride = vkSbt->raygen.region.stride; - raygenAddress.deviceAddress = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; - - // we need to make sure the SBT is up to date - commitShaderbindingTableUpdateVk(vkCmdBuffer, vkSbt); - - vkCmdBuffer->device->cmdTraceRays( - vkCmdBuffer->handle, - &raygenAddress, - &vkSbt->miss.region, - &vkSbt->hit.region, - &vkSbt->callable.region, - width, - height, - depth); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdTraceRaysIndirectVk( - PalCommandBuffer* cmdBuffer, - uint32_t raygenIndex, - PalShaderBindingTable* sbt, - PalBuffer* buffer) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - ShaderBindingTable* vkSbt = (ShaderBindingTable*)sbt; - Buffer* vkBuffer = (Buffer*)buffer; - - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_INVALID_BUFFER; - } - - PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; - vkSbt->raygen.region.deviceAddress = address; - - // we need to make sure the SBT is up to date - commitShaderbindingTableUpdateVk(vkCmdBuffer, vkSbt); - - // copy users buffer data into a tmp gpu buffer abd execute with it - VkBufferCopy copyRegion = {0}; - copyRegion.size = sizeof(VkTraceRaysIndirectCommandKHR); - s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, vkBuffer->handle, vkCmdBuffer->buffer, 1, ©Region); - - // put a memory barrier - VkBufferMemoryBarrier2KHR barrier = {0}; - barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; - barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR; - barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; - barrier.dstStageMask = VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; - barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT_KHR; - - barrier.buffer = vkCmdBuffer->buffer; - barrier.offset = 0; - barrier.size = VK_WHOLE_SIZE; - - VkDependencyInfo dependencyInfo = {0}; - dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; - dependencyInfo.bufferMemoryBarrierCount = 1; - dependencyInfo.pBufferMemoryBarriers = &barrier; - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - - VkDeviceAddress bufAddress = 0; - VkBufferDeviceAddressInfoKHR bufferInfo = {0}; - bufferInfo.buffer = vkCmdBuffer->buffer; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; - bufAddress = vkCmdBuffer->device->getBufferrAddress(vkCmdBuffer->device->handle, &bufferInfo); - - vkCmdBuffer->device->cmdTraceRaysIndirect( - vkCmdBuffer->handle, - &vkSbt->raygen.region, - &vkSbt->miss.region, - &vkSbt->hit.region, - &vkSbt->callable.region, - bufAddress); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBindDescriptorSetVk( - PalCommandBuffer* cmdBuffer, - uint32_t setIndex, - PalDescriptorSet* set) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Pipeline* pipeline = vkCmdBuffer->pipeline; - DescriptorSet* vkSet = (DescriptorSet*)set; - - s_Vk.cmdBindDescriptorSets( - vkCmdBuffer->handle, - pipeline->bindPoint, - pipeline->layout, - setIndex, - 1, - &vkSet->handle, - 0, - nullptr); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdPushConstantsVk( - PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, - uint64_t offset, - uint64_t size, - const void* value) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Pipeline* pipeline = vkCmdBuffer->pipeline; - VkShaderStageFlags stages = 0; - - for (int i = 0; i < shaderStageCount; i++) { - VkShaderStageFlagBits bit = shaderStageToVK(shaderStages[i]); - stages |= bit; - } - - s_Vk.cmdPushConstants( - vkCmdBuffer->handle, - pipeline->layout, - stages, - offset, - size, - value); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetCullModeVk( - PalCommandBuffer* cmdBuffer, - PalCullMode cullMode) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkCullModeFlags vkCullMode = 0; - switch (cullMode) { - case PAL_CULL_MODE_BACK: - vkCullMode = VK_CULL_MODE_BACK_BIT; - - case PAL_CULL_MODE_FRONT: - vkCullMode = VK_CULL_MODE_FRONT_BIT; - - case PAL_CULL_MODE_NONE: - vkCullMode = VK_CULL_MODE_NONE; - } - - device->cmdSetCullMode(vkCmdBuffer->handle, vkCullMode); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetFrontFaceVk( - PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkFrontFace vkFrontFace = 0; - switch (frontFace) { - case PAL_FRONT_FACE_CLOCKWISE: - vkFrontFace = VK_FRONT_FACE_CLOCKWISE; - - case PAL_FRONT_FACE_COUNTER_CLOCKWISE: - vkFrontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - } - - device->cmdSetFrontFace(vkCmdBuffer->handle, vkFrontFace); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetPrimitiveTopologyVk( - PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkPrimitiveTopology vkTopology = 0; - switch (topology) { - case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { - vkTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { - vkTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_LINE_LIST: { - vkTopology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP: { - vkTopology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_POINT_LIST: { - vkTopology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; - break; - } - } - - device->cmdSetPrimitiveTopology(vkCmdBuffer->handle, vkTopology); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetDepthTestEnableVk( - PalCommandBuffer* cmdBuffer, - PalBool enable) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - device->cmdSetDepthTestEnable(vkCmdBuffer->handle, enable); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetDepthWriteEnableVk( - PalCommandBuffer* cmdBuffer, - PalBool enable) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - device->cmdSetDepthWriteEnable(vkCmdBuffer->handle, enable); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetStencilOpVk( - PalCommandBuffer* cmdBuffer, - PalStencilFaceFlags faceMask, - PalStencilOp failOp, - PalStencilOp passOp, - PalStencilOp depthFailOp, - PalCompareOp compareOp) -{ - CommandBuffer* vkCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = vkCmdBuffer->device; - - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkStencilFaceFlags faceFlags = 0; - if (faceMask & PAL_STENCIL_FACE_BACK) { - faceFlags |= VK_STENCIL_FACE_BACK_BIT; - } - - if (faceMask & PAL_STENCIL_FACE_FRONT) { - faceFlags |= VK_STENCIL_FACE_FRONT_BIT; - } - - VkStencilOp vkFailOp = stencilOpToVk(failOp); - VkStencilOp vkPassOp = stencilOpToVk(passOp); - VkStencilOp vkDepthFailOp = stencilOpToVk(depthFailOp); - VkCompareOp vkCompareOp = compareOpToVk(compareOp); - - device->cmdSetStencilOp( - vkCmdBuffer->handle, - faceFlags, - failOp, - passOp, - depthFailOp, - compareOp); - - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Acceleration Structure -// ================================================== - -PalResult PAL_CALL createAccelerationstructureVk( - PalDevice* device, - const PalAccelerationStructureCreateInfo* info, - PalAccelerationStructure** outAs) -{ - VkResult result; - AccelerationStructure* as = nullptr; - Device* vkDevice = (Device*)device; - Buffer* buffer = (Buffer*)info->buffer; - - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - as = palAllocate(s_Vk.allocator, sizeof(AccelerationStructure), 0); - if (!as) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkAccelerationStructureCreateInfoKHR createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; - createInfo.offset = (VkDeviceSize)info->offset; - createInfo.size = (VkDeviceSize)info->size; - createInfo.buffer = buffer->handle; - createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - } - - result = vkDevice->createAccelerationStructure( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &as->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, as); - return resultFromVk(result); - } - - // get and cache address - VkAccelerationStructureDeviceAddressInfoKHR addressInfo = {0}; - addressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; - addressInfo.accelerationStructure = as->handle; - as->address = vkDevice->getAccelerationDeviceAddress(vkDevice->handle, &addressInfo); - - as->device = vkDevice; - *outAs = (PalAccelerationStructure*)as; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as) -{ - AccelerationStructure* vkAs = (AccelerationStructure*)as; - vkAs->device->destroyAccelerationStructure( - vkAs->device->handle, - vkAs->handle, - &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, vkAs); -} - -PalResult PAL_CALL getAccelerationStructureBuildSizeVk( - PalDevice* device, - PalAccelerationStructureBuildInfo* info, - PalAccelerationStructureBuildSize* size) -{ - uint32_t* maxPrimities = nullptr; - VkAccelerationStructureGeometryKHR* geometries = nullptr; - Device* vkDevice = (Device*)device; - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - // cache these for top level as - VkAccelerationStructureGeometryKHR cachedGeometries = {0}; - uint32_t cachedPrimitives = 0; - uint32_t geometryCount = info->geometryCount; - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { - geometryCount = 1; - geometries = &cachedGeometries; - maxPrimities = &cachedPrimitives; - } - - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - geometries = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureGeometryKHR) * geometryCount, - 0); - - maxPrimities = palAllocate(s_Vk.allocator, sizeof(uint32_t) * geometryCount, 0); - if (!maxPrimities || !geometries) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * geometryCount); - memset(maxPrimities, 0, sizeof(uint32_t) * geometryCount); - } - - fillBuildInfoVk( - geometryCount, - info, - maxPrimities, - geometries, - nullptr, - nullptr, - nullptr, - &buildInfo); - - VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; - sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; - - vkDevice->getAccelerationBuildsize( - vkDevice->handle, - VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, - &buildInfo, - maxPrimities, - &sizeInfo); - - size->accelerationStructureSize = sizeInfo.accelerationStructureSize; - size->scratchBufferSize = sizeInfo.buildScratchSize; - size->updateScratchBufferSize = sizeInfo.updateScratchSize; - - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - palFree(s_Vk.allocator, geometries); - palFree(s_Vk.allocator, maxPrimities); - } - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Buffer -// ================================================== - -PalResult PAL_CALL createBufferVk( - PalDevice* device, - const PalBufferCreateInfo* info, - PalBuffer** outBuffer) -{ - VkResult result; - Buffer* buffer = nullptr; - Device* vkDevice = (Device*)device; - - if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - buffer = palAllocate(s_Vk.allocator, sizeof(Buffer), 0); - if (!buffer) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkBufferCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - createInfo.size = info->size; - createInfo.usage = bufferUsageToVk(info->usages); - - result = s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &buffer->handle); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, buffer); - return resultFromVk(result); - } - - buffer->usages = info->usages; - buffer->device = vkDevice; - buffer->memory = nullptr; - *outBuffer = (PalBuffer*)buffer; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyBufferVk(PalBuffer* buffer) -{ - Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.destroyBuffer(vkBuffer->device->handle, vkBuffer->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, buffer); -} - -PalResult PAL_CALL getBufferMemoryRequirementsVk( - PalBuffer* buffer, - PalMemoryRequirements* requirements) -{ - Buffer* vkBuffer = (Buffer*)buffer; - Device* device = vkBuffer->device; - VkMemoryRequirements memReq = {0}; - s_Vk.getBufferMemoryRequirements(device->handle, vkBuffer->handle, &memReq); - - requirements->alignment = (uint64_t)memReq.alignment; - requirements->size = (uint64_t)memReq.size; - requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, vkBuffer->usages); - - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = PAL_FALSE; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = PAL_FALSE; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = PAL_FALSE; - - for (int i = 0; i < PAL_MEMORY_TYPE_MAX; i++) { - requirements->memoryTypes[i] = (memReq.memoryTypeBits & device->memoryClassMask[i]) != 0; - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL computeInstanceBufferRequirementsVk( - PalDevice* device, - uint32_t instanceCount, - uint64_t* outSize) -{ - *outSize = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( - PalDevice* device, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize) -{ - uint32_t imageFormatSize = getFormatSizeVk(imageFormat); - uint32_t length = 0; - uint32_t height = 0; - length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; - height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; - uint32_t rowPitch = length * imageFormatSize; - - *outBufferRowLength = length; - *outBufferImageHeight = height; - *outSize = (uint64_t)rowPitch * length * copyInfo->imageDepth; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL writeToInstanceBufferVk( - PalDevice* device, - void* ptr, - PalAccelerationStructureInstance* instances, - uint32_t instanceCount) -{ - VkAccelerationStructureInstanceKHR* data = ptr; - for (int i = 0; i < instanceCount; i++) { - PalAccelerationStructureInstance* src = &instances[i]; - VkAccelerationStructureInstanceKHR* dst = &data[i]; - AccelerationStructure* as = (AccelerationStructure*)src->blas; - - dst->mask = src->mask & 0xFF; - dst->instanceCustomIndex = src->instanceId & 0xFFFFFF; - dst->accelerationStructureReference = as->address; - dst->instanceShaderBindingTableRecordOffset = src->hitGroupOffset & 0xFFFFFF; - dst->flags = instanceFlagsToVk(src->flags); - memcpy(dst->transform.matrix, src->transform, sizeof(float) * 12); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL writeToImageCopyStagingBufferVk( - PalDevice* device, - void* ptr, - void* srcData, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo) -{ - uint32_t imageFormatSize = getFormatSizeVk(imageFormat); - uint32_t dstRowPitch = copyInfo->bufferRowLength * imageFormatSize; - uint32_t srcRowPitch = copyInfo->imageWidth * imageFormatSize; - const uint32_t dstSlicePitch = dstRowPitch * copyInfo->bufferImageHeight; - const uint32_t srcSlicePitch = srcRowPitch * copyInfo->imageHeight; - - // manually offset the buffer with the provided offset - uint8_t* dst = (uint8_t*)ptr + copyInfo->bufferOffset; - const uint8_t* src = (const uint8_t*)srcData; - - // write to destination pointer - for (uint32_t z = 0; z < copyInfo->imageDepth; z++) { - for (uint32_t y = 0; y < copyInfo->imageHeight; y++) { - memcpy( - dst + z * dstSlicePitch + y * dstRowPitch, - src + z * srcSlicePitch + y * srcRowPitch, - srcRowPitch); - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL bindBufferMemoryVk( - PalBuffer* buffer, - PalMemory* memory, - uint64_t offset) -{ - VkResult result; - Memory* vkMemory = (Memory*)memory; - Buffer* vkBuffer = (Buffer*)buffer; - - if (vkBuffer->memory) { - return PAL_RESULT_INVALID_OPERATION; - } - - result = s_Vk.bindBufferMemory( - vkBuffer->device->handle, - vkBuffer->handle, - vkMemory->handle, - offset); - - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - - vkBuffer->memory = vkMemory; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL mapBufferMemoryVk( - PalBuffer* buffer, - uint64_t offset, - uint64_t size, - void** outPtr) -{ - VkResult result; - Buffer* vkBuffer = (Buffer*)buffer; - Device* device = vkBuffer->device; - - if (vkBuffer->memory->type == PAL_MEMORY_TYPE_GPU_ONLY) { - return PAL_RESULT_MEMORY_MAP_FAILED; - } - - result = s_Vk.mapMemory(device->handle, vkBuffer->memory->handle, offset, size, 0, outPtr); - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer) -{ - Buffer* vkBuffer = (Buffer*)buffer; - s_Vk.unmapMemory(vkBuffer->device->handle, vkBuffer->memory->handle); -} - -PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer) -{ - Buffer* vkBuffer = (Buffer*)buffer; - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS)) { - return 0; - } - - VkBufferDeviceAddressInfoKHR bufferInfo = {0}; - bufferInfo.buffer = vkBuffer->handle; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; - return vkBuffer->device->getBufferrAddress(vkBuffer->device->handle, &bufferInfo); -} - -// ================================================== -// Descriptor Pool, Set and Layout -// ================================================== - -PalResult PAL_CALL createDescriptorSetLayoutVk( - PalDevice* device, - const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout) -{ - VkResult result; - Device* vkDevice = (Device*)device; - VkDescriptorSetLayoutBinding* bindings = nullptr; - VkDescriptorBindingFlags* bindingFlags = nullptr; - DescriptorSetLayout* layout = nullptr; - uint32_t count = info->bindingCount; - VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsCreateInfo = {0}; - - PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } layout = palAllocate(s_Vk.allocator, sizeof(DescriptorSetLayout), 0); @@ -9608,412 +7010,4 @@ void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) palFree(s_Vk.allocator, pipeline); } -// ================================================== -// Shader Binding Table -// ================================================== - -PalResult PAL_CALL createShaderBindingTableVk( - PalDevice* device, - const PalShaderBindingTableCreateInfo* info, - PalShaderBindingTable** outSbt) -{ - VkResult result; - Device* vkDevice = (Device*)device; - ShaderBindingTable* sbt = nullptr; - Pipeline* pipeline = (Pipeline*)info->rayTracingPipeline; - ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; - - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - uint32_t totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; - totalGroups += sbtInfo->missCount + sbtInfo->callableCount; - if (info->recordCount != totalGroups) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - sbt = palAllocate(s_Vk.allocator, sizeof(ShaderBindingTable), 0); - if (!sbt) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // create SBT buffer - VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayProps = {0}; - rayProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; - - VkPhysicalDeviceProperties2KHR props = {0}; - props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; - props.pNext = &rayProps; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &props); - - uint32_t groupHandleSize = rayProps.shaderGroupHandleSize; - uint32_t groupHandleAlignment = rayProps.shaderGroupHandleAlignment; - uint32_t groupBaseAlignment = rayProps.shaderGroupBaseAlignment; - - // get the max local data size - for (int i = 0; i < info->recordCount; i++) { - PalShaderBindingTableRecordInfo* record = &info->records[i]; - uint32_t index = record->groupIndex; - - if (index < sbtInfo->raygenCount) { - // raygen group - if (record->localDataSize > sbtInfo->raygenDataSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { - // miss group - if (record->localDataSize > sbtInfo->missDataSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { - // hit group - if (record->localDataSize > sbtInfo->hitDataSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - } else { - // callable group - if (record->localDataSize > sbtInfo->callableDataSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - } - } - - // get strides - uint32_t callableStride = 0; - uint32_t raygenStride = alignVk(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); - uint32_t missStride = alignVk(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); - uint32_t hitStride = alignVk(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); - callableStride = alignVk(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); - - // get region size - uint32_t raygenRegionSize = raygenStride * sbtInfo->raygenCount; - uint32_t missRegionSize = missStride * sbtInfo->missCount; - uint32_t hitRegionSize = hitStride * sbtInfo->hitCount; - uint32_t callableRegionSize = callableStride * sbtInfo->callableCount; - - // get offsets - uint32_t offset = 0; - uint32_t raygenOffset = 0; - uint32_t missOffset = 0; - uint32_t hitOffset = 0; - uint32_t callableOffset = 0; - - raygenOffset = alignVk(offset, groupBaseAlignment); - offset = raygenOffset + raygenRegionSize; - - missOffset = alignVk(offset, groupBaseAlignment); - offset = missOffset + missRegionSize; - - hitOffset = alignVk(offset, groupBaseAlignment); - offset = hitOffset + hitRegionSize; - - callableOffset = alignVk(offset, groupBaseAlignment); - offset = callableOffset + callableRegionSize; - - uint32_t bufferSize = alignVk(offset, groupBaseAlignment); - - // create gpu buffer - VkBufferCreateInfo bufCreateInfo = {0}; - bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufCreateInfo.size = bufferSize; - bufCreateInfo.usage = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR; - bufCreateInfo.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; - bufCreateInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; - bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, sbt); - return resultFromVk(result); - } - - // create staging buffer - bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - sbt->stagingBufferSize = bufferSize; - result = s_Vk.createBuffer( - vkDevice->handle, - &bufCreateInfo, - &s_Vk.vkAllocator, - &sbt->stagingBuffer); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, sbt); - return resultFromVk(result); - } - - // allocate CPU upload memory and bind - VkMemoryRequirements memReq = {0}; - s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->buffer, &memReq); - - VkMemoryAllocateInfo allocateInfo = {0}; - allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.allocationSize = memReq.size; - - uint32_t mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; - uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); - allocateInfo.memoryTypeIndex = memoryIndex; - - VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; - allocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; - allocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; - allocateInfo.pNext = &allocateFlagsInfo; - - result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, - &sbt->bufferMemory); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, sbt); - return resultFromVk(result); - } - - // allocate memory for staging buffer - s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->stagingBuffer, &memReq); - allocateInfo.allocationSize = memReq.size; - - mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] & memReq.memoryTypeBits; - memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); - allocateInfo.memoryTypeIndex = memoryIndex; - allocateInfo.pNext = nullptr; // we dont need the address - - result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, - &sbt->stagingBufferMemory); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, sbt); - return resultFromVk(result); - } - - s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); - s_Vk.bindBufferMemory(vkDevice->handle, sbt->stagingBuffer, sbt->stagingBufferMemory, 0); - - // get shader group handles - uint32_t handlesSize = totalGroups * groupHandleSize; - uint8_t* handles = palAllocate(s_Vk.allocator, handlesSize, 0); - if (!handles) { - palFree(s_Vk.allocator, sbt); - return PAL_RESULT_OUT_OF_MEMORY; - } - - result = vkDevice->getRayTracingShaderGroupHandles( - vkDevice->handle, - pipeline->handle, - 0, - totalGroups, - handlesSize, - handles); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, sbt); - return resultFromVk(result); - } - - // copy handles into the buffer - void* ptr = nullptr; - result = s_Vk.mapMemory(vkDevice->handle, sbt->stagingBufferMemory, 0, VK_WHOLE_SIZE, 0, &ptr); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, sbt); - return resultFromVk(result); - } - - offset = 0; // reuse variable - uint8_t* srcPtr = (uint8_t*)handles; - - // raygen - for (int i = 0; i < sbtInfo->raygenCount; i++) { - uint8_t* dstPtr = (uint8_t*)ptr + (i * raygenStride); - PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; - - memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); - if (record->localDataSize) { - // this record has local data - memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); - } - } - - offset += sbtInfo->raygenCount; - srcPtr += (groupHandleSize * sbtInfo->raygenCount); - - // miss - for (int i = 0; i < sbtInfo->missCount; i++) { - uint8_t* dstPtr = (uint8_t*)ptr + missOffset + (i * missStride); - PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; - - memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); - if (record->localDataSize) { - // this record has local data - memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); - } - } - - offset += sbtInfo->missCount; - srcPtr += (groupHandleSize * sbtInfo->missCount); - - // hit - for (int i = 0; i < sbtInfo->hitCount; i++) { - uint8_t* dstPtr = (uint8_t*)ptr + hitOffset + (i * hitStride); - PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; - - memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); - if (record->localDataSize) { - // this record has local data - memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); - } - } - - offset += sbtInfo->hitCount; - srcPtr += (groupHandleSize * sbtInfo->hitCount); - - // callable - for (int i = 0; i < sbtInfo->callableCount; i++) { - uint8_t* dstPtr = (uint8_t*)ptr + callableOffset + (i * callableStride); - PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; - - memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); - if (record->localDataSize) { - // this record has local data - memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); - } - } - - s_Vk.unmapMemory(vkDevice->handle, sbt->stagingBufferMemory); - - // cache SBT fields and offsets address - // we know the layout so we can prepare the strided address before we copy to the gpu buffer - VkBufferDeviceAddressInfo bufferAddressInfo = {0}; - bufferAddressInfo.buffer = sbt->buffer; - bufferAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - sbt->baseAddress = s_Vk.getBufferDeviceAddress(vkDevice->handle, &bufferAddressInfo); - - // raygen - sbt->raygen.region.deviceAddress = sbt->baseAddress; - sbt->raygen.offset = 0; // always - sbt->raygen.startIndex = 0; // always - sbt->raygen.region.size = raygenRegionSize; - sbt->raygen.region.stride = raygenStride; - - // miss - sbt->miss.offset = missOffset; - sbt->miss.startIndex = sbtInfo->raygenCount; - sbt->miss.region.deviceAddress = sbt->baseAddress + missOffset; - sbt->miss.region.size = missRegionSize; - sbt->miss.region.stride = missStride; - - // hit - sbt->hit.offset = hitOffset; - sbt->hit.startIndex = sbtInfo->raygenCount + sbtInfo->missCount; - sbt->hit.region.deviceAddress = sbt->baseAddress + hitOffset; - sbt->hit.region.size = hitRegionSize; - sbt->hit.region.stride = hitStride; - - // callable - sbt->callable.offset = callableOffset; - sbt->callable.startIndex = sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount; - sbt->callable.region.deviceAddress = sbt->baseAddress + callableOffset; - sbt->callable.region.size = callableRegionSize; - sbt->callable.region.stride = callableStride; - - palFree(s_Vk.allocator, handles); - sbt->device = vkDevice; - sbt->handleSize = groupHandleSize; - sbt->pipeline = pipeline; - - sbt->isDirty = PAL_TRUE; // we need to copy from the staging to the gpu buffer - *outSbt = (PalShaderBindingTable*)sbt; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt) -{ - ShaderBindingTable* vkSbt = (ShaderBindingTable*)sbt; - Device* device = vkSbt->device; - - s_Vk.destroyBuffer(device->handle, vkSbt->buffer, &s_Vk.vkAllocator); - s_Vk.destroyBuffer(device->handle, vkSbt->stagingBuffer, &s_Vk.vkAllocator); - s_Vk.freeMemory(device->handle, vkSbt->bufferMemory, &s_Vk.vkAllocator); - s_Vk.freeMemory(device->handle, vkSbt->stagingBufferMemory, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkSbt); -} - -PalResult PAL_CALL updateShaderBindingTableVk( - PalShaderBindingTable* sbt, - uint32_t count, - PalShaderBindingTableRecordInfo* infos) -{ - VkResult result; - ShaderBindingTable* vkSbt = (ShaderBindingTable*)sbt; - Device* vkDevice = vkSbt->device; - Pipeline* pipeline = vkSbt->pipeline; - ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; - - void* data = nullptr; - result = s_Vk.mapMemory( - vkDevice->handle, - vkSbt->stagingBufferMemory, - 0, - VK_WHOLE_SIZE, - 0, - &data); - - if (result != VK_SUCCESS) { - return resultFromVk(result); - } - - uint32_t stride = 0; - uint32_t offset = 0; - uint32_t startIndex = 0; - - for (int i = 0; i < count; i++) { - PalShaderBindingTableRecordInfo* info = &infos[i]; - if (!info->localDataSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - // find the group the record belongs to - uint32_t index = info->groupIndex; - if (index < sbtInfo->raygenCount) { - // raygen group - offset = 0; - stride = vkSbt->raygen.region.stride; - startIndex = vkSbt->raygen.startIndex; - - } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { - // miss group - offset = vkSbt->miss.offset; - stride = vkSbt->miss.region.stride; - startIndex = vkSbt->miss.startIndex; - - } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { - // hit group - offset = vkSbt->hit.offset; - stride = vkSbt->hit.region.stride; - startIndex = vkSbt->hit.startIndex; - - } else { - // callable group - offset = vkSbt->callable.offset; - stride = vkSbt->callable.region.stride; - startIndex = vkSbt->callable.startIndex; - } - - // write payload - uint32_t localIndex = index - startIndex; - uint8_t* dst = (uint8_t*)data + offset + (localIndex * stride); - memcpy(dst + vkSbt->handleSize, info->localData, info->localDataSize); - } - - s_Vk.unmapMemory(vkDevice->handle, vkSbt->stagingBufferMemory); - vkSbt->isDirty = PAL_TRUE; - return PAL_RESULT_SUCCESS; -} - #endif // PAL_HAS_VULKAN_BACKEND diff --git a/src/graphics/vulkan/pal_as_vulkan.c b/src/graphics/vulkan/pal_as_vulkan.c new file mode 100644 index 00000000..6ac3c978 --- /dev/null +++ b/src/graphics/vulkan/pal_as_vulkan.c @@ -0,0 +1,144 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +PalResult PAL_CALL createAccelerationstructureVk( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs) +{ + VkResult result; + AccelerationStructureVk* as = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + BufferVk* buffer = (BufferVk*)info->buffer; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + as = palAllocate(s_Vk.allocator, sizeof(AccelerationStructureVk), 0); + if (!as) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkAccelerationStructureCreateInfoKHR createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR; + createInfo.offset = (VkDeviceSize)info->offset; + createInfo.size = (VkDeviceSize)info->size; + createInfo.buffer = buffer->handle; + createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + } + + result = vkDevice->createAccelerationStructure( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &as->handle); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + // get and cache address + VkAccelerationStructureDeviceAddressInfoKHR addressInfo = {0}; + addressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; + addressInfo.accelerationStructure = as->handle; + as->address = vkDevice->getAccelerationDeviceAddress(vkDevice->handle, &addressInfo); + + as->device = vkDevice; + as->reserved = PAL_BACKEND_KEY; + *outAs = (PalAccelerationStructure*)as; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as) +{ + AccelerationStructureVk* vkAs = (AccelerationStructureVk*)as; + vkAs->device->destroyAccelerationStructure( + vkAs->device->handle, + vkAs->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, vkAs); +} + +PalResult PAL_CALL getAccelerationStructureBuildSizeVk( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size) +{ + uint32_t* maxPrimities = nullptr; + VkAccelerationStructureGeometryKHR* geometries = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + // cache these for top level as + VkAccelerationStructureGeometryKHR cachedGeometries = {0}; + uint32_t cachedPrimitives = 0; + uint32_t geometryCount = info->count; + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { + geometryCount = 1; + geometries = &cachedGeometries; + maxPrimities = &cachedPrimitives; + } + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + geometries = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureGeometryKHR) * geometryCount, + 0); + + maxPrimities = palAllocate(s_Vk.allocator, sizeof(uint32_t) * geometryCount, 0); + if (!maxPrimities || !geometries) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * geometryCount); + memset(maxPrimities, 0, sizeof(uint32_t) * geometryCount); + } + + fillBuildInfoVk( + geometryCount, + info, + maxPrimities, + geometries, + nullptr, + nullptr, + nullptr, + &buildInfo); + + VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; + sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; + + vkDevice->getAccelerationBuildsize( + vkDevice->handle, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + &buildInfo, + maxPrimities, + &sizeInfo); + + size->accelerationStructureSize = sizeInfo.accelerationStructureSize; + size->scratchBufferSize = sizeInfo.buildScratchSize; + size->updateScratchBufferSize = sizeInfo.updateScratchSize; + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + palFree(s_Vk.allocator, geometries); + palFree(s_Vk.allocator, maxPrimities); + } + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_buffer_vulkan.c b/src/graphics/vulkan/pal_buffer_vulkan.c new file mode 100644 index 00000000..40325357 --- /dev/null +++ b/src/graphics/vulkan/pal_buffer_vulkan.c @@ -0,0 +1,473 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +static VkBufferUsageFlags bufferUsageToVk(PalBufferUsages usages) +{ + VkBufferUsageFlags flags = 0; + if (usages & PAL_BUFFER_USAGE_VERTEX) { + flags |= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + } + + if (usages & PAL_BUFFER_USAGE_INDEX) { + flags |= VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + } + + if (usages & PAL_BUFFER_USAGE_UNIFORM) { + flags |= VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + } + + if (usages & PAL_BUFFER_USAGE_STORAGE) { + flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + } + + if (usages & PAL_BUFFER_USAGE_TRANSFER_SRC) { + flags |= VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + } + + if (usages & PAL_BUFFER_USAGE_TRANSFER_DST) { + flags |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + } + + if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { + flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR; + } + + if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { + flags |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + } + + if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT) { + flags |= VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR; + } + + if (usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + flags |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; + } + + if (usages & PAL_BUFFER_USAGE_INDIRECT) { + flags |= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; + } + + return flags; +} + +static uint32_t getFormatSize(PalFormat format) +{ + switch (format) { + case PAL_FORMAT_R8_UNORM: + case PAL_FORMAT_R8_SNORM: + case PAL_FORMAT_R8_UINT: + case PAL_FORMAT_R8_SINT: + case PAL_FORMAT_R8_SRGB: + case PAL_FORMAT_S8_UINT: + return 1; + + case PAL_FORMAT_R16_UNORM: + case PAL_FORMAT_R16_SNORM: + case PAL_FORMAT_R16_UINT: + case PAL_FORMAT_R16_SINT: + case PAL_FORMAT_R16_SFLOAT: + case PAL_FORMAT_R8G8_UNORM: + case PAL_FORMAT_R8G8_SNORM: + case PAL_FORMAT_R8G8_UINT: + case PAL_FORMAT_R8G8_SINT: + case PAL_FORMAT_R8G8_SRGB: + case PAL_FORMAT_D16_UNORM: + return 2; + + case PAL_FORMAT_R8G8B8_UNORM: + case PAL_FORMAT_R8G8B8_SNORM: + case PAL_FORMAT_R8G8B8_UINT: + case PAL_FORMAT_R8G8B8_SINT: + case PAL_FORMAT_R8G8B8_SRGB: + case PAL_FORMAT_B8G8R8_UNORM: + case PAL_FORMAT_B8G8R8_SNORM: + case PAL_FORMAT_B8G8R8_UINT: + case PAL_FORMAT_B8G8R8_SINT: + case PAL_FORMAT_B8G8R8_SRGB: + case PAL_FORMAT_D16_UNORM_S8_UINT: + return 3; + + case PAL_FORMAT_R32_UINT: + case PAL_FORMAT_R32_SINT: + case PAL_FORMAT_R32_SFLOAT: + case PAL_FORMAT_R16G16_UNORM: + case PAL_FORMAT_R16G16_SNORM: + case PAL_FORMAT_R16G16_UINT: + case PAL_FORMAT_R16G16_SINT: + case PAL_FORMAT_R16G16_SFLOAT: + case PAL_FORMAT_R8G8B8A8_UNORM: + case PAL_FORMAT_R8G8B8A8_SNORM: + case PAL_FORMAT_R8G8B8A8_UINT: + case PAL_FORMAT_R8G8B8A8_SINT: + case PAL_FORMAT_R8G8B8A8_SRGB: + case PAL_FORMAT_B8G8R8A8_UNORM: + case PAL_FORMAT_B8G8R8A8_SNORM: + case PAL_FORMAT_B8G8R8A8_UINT: + case PAL_FORMAT_B8G8R8A8_SINT: + case PAL_FORMAT_B8G8R8A8_SRGB: + case PAL_FORMAT_D32_SFLOAT: + case PAL_FORMAT_D24_UNORM_S8_UINT: + return 4; + + case PAL_FORMAT_D32_SFLOAT_S8_UINT: + return 5; + + case PAL_FORMAT_R16G16B16_UNORM: + case PAL_FORMAT_R16G16B16_SNORM: + case PAL_FORMAT_R16G16B16_UINT: + case PAL_FORMAT_R16G16B16_SINT: + case PAL_FORMAT_R16G16B16_SFLOAT: + return 6; + + case PAL_FORMAT_R64_UINT: + case PAL_FORMAT_R64_SINT: + case PAL_FORMAT_R64_SFLOAT: + case PAL_FORMAT_R32G32_UINT: + case PAL_FORMAT_R32G32_SINT: + case PAL_FORMAT_R32G32_SFLOAT: + case PAL_FORMAT_R16G16B16A16_UNORM: + case PAL_FORMAT_R16G16B16A16_SNORM: + case PAL_FORMAT_R16G16B16A16_UINT: + case PAL_FORMAT_R16G16B16A16_SINT: + case PAL_FORMAT_R16G16B16A16_SFLOAT: + return 8; + + case PAL_FORMAT_R32G32B32_UINT: + case PAL_FORMAT_R32G32B32_SINT: + case PAL_FORMAT_R32G32B32_SFLOAT: + return 12; + + case PAL_FORMAT_R64G64_UINT: + case PAL_FORMAT_R64G64_SINT: + case PAL_FORMAT_R64G64_SFLOAT: + case PAL_FORMAT_R32G32B32A32_UINT: + case PAL_FORMAT_R32G32B32A32_SINT: + case PAL_FORMAT_R32G32B32A32_SFLOAT: + return 16; + + case PAL_FORMAT_R64G64B64_UINT: + case PAL_FORMAT_R64G64B64_SINT: + case PAL_FORMAT_R64G64B64_SFLOAT: + return 24; + + case PAL_FORMAT_R64G64B64A64_UINT: + case PAL_FORMAT_R64G64B64A64_SINT: + case PAL_FORMAT_R64G64B64A64_SFLOAT: + return 32; + } + + return 0; +} + +static VkGeometryInstanceFlagsKHR instanceFlagsToVk(PalAccelerationStructureInstanceFlags flags) +{ + VkGeometryInstanceFlagsKHR instanceFlags = 0; + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE) { + instanceFlags |= VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR; + } + + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE) { + instanceFlags |= VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR; + } + + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE) { + instanceFlags |= VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; + } + + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE) { + instanceFlags |= VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR; + } + + return instanceFlags; +} + +PalResult PAL_CALL createBufferVk( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer) +{ + VkResult result; + BufferVk* buffer = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + + if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + buffer = palAllocate(s_Vk.allocator, sizeof(BufferVk), 0); + if (!buffer) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkBufferCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.size = info->size; + createInfo.usage = bufferUsageToVk(info->usages); + + result = s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &buffer->handle); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + buffer->memory = nullptr; + buffer->isMemoryManaged = PAL_FALSE; + if (info->memoryUsage != PAL_BUFFER_MEMORY_USAGE_MANUAL) { + PalMemoryType memoryType = PAL_MEMORY_TYPE_GPU_ONLY; + if (info->memoryUsage == PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD) { + memoryType = PAL_MEMORY_TYPE_CPU_UPLOAD; + + } else if (info->memoryUsage == PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK) { + memoryType = PAL_MEMORY_TYPE_CPU_READBACK; + } + + // allocate and manage memory + VkMemoryRequirements memReq = {0}; + s_Vk.getBufferMemoryRequirements(vkDevice->handle, buffer->handle, &memReq); + + VkMemoryAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = (VkDeviceSize)memReq.size; + VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; + + uint32_t memoryMask = vkDevice->memoryClassMask[memoryType] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, memoryMask); + if (!(memoryMask & (1u << memoryIndex))) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + + allocateInfo.memoryTypeIndex = memoryIndex; + if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + allocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + allocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + allocateInfo.pNext = &allocateFlagsInfo; + } + + VkDeviceMemory memory = nullptr; + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &memory); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + buffer->isMemoryManaged = PAL_TRUE; + buffer->memory = (MemoryVk*)memory; + } + + buffer->usages = info->usages; + buffer->device = vkDevice; + buffer->reserved = PAL_BACKEND_KEY; + *outBuffer = (PalBuffer*)buffer; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyBufferVk(PalBuffer* buffer) +{ + BufferVk* vkBuffer = (BufferVk*)buffer; + s_Vk.destroyBuffer(vkBuffer->device->handle, vkBuffer->handle, &s_Vk.vkAllocator); + + if (vkBuffer->isMemoryManaged) { + VkDeviceMemory memory = (VkDeviceMemory)vkBuffer->memory; + s_Vk.freeMemory(vkBuffer->device->handle, memory, &s_Vk.vkAllocator); + } + palFree(s_Vk.allocator, buffer); +} + +PalResult PAL_CALL getBufferMemoryRequirementsVk( + PalBuffer* buffer, + PalMemoryRequirements* requirements) +{ + BufferVk* vkBuffer = (BufferVk*)buffer; + DeviceVk* device = vkBuffer->device; + VkMemoryRequirements memReq = {0}; + s_Vk.getBufferMemoryRequirements(device->handle, vkBuffer->handle, &memReq); + + requirements->alignment = (uint64_t)memReq.alignment; + requirements->size = (uint64_t)memReq.size; + requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, vkBuffer->usages); + requirements->supportedMemoryTypes = 0; + + if ((memReq.memoryTypeBits & device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY]) != 0) { + requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); + } + + if ((memReq.memoryTypeBits & device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD]) != 0) { + requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_CPU_UPLOAD); + } + + if ((memReq.memoryTypeBits & device->memoryClassMask[PAL_MEMORY_TYPE_CPU_READBACK]) != 0) { + requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_CPU_READBACK); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL computeInstanceBufferRequirementsVk( + PalDevice* device, + uint32_t instanceCount, + uint64_t* outSize) +{ + *outSize = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( + PalDevice* device, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo, + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize) +{ + uint32_t imageFormatSize = getFormatSize(imageFormat); + uint32_t length = 0; + uint32_t height = 0; + length = copyInfo->bufferRowLength ? copyInfo->bufferRowLength : copyInfo->imageWidth; + height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; + uint32_t rowPitch = length * imageFormatSize; + + *outBufferRowLength = length; + *outBufferImageHeight = height; + *outSize = (uint64_t)rowPitch * length * copyInfo->imageDepth; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL writeToInstanceBufferVk( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + uint32_t instanceCount) +{ + VkAccelerationStructureInstanceKHR* data = ptr; + for (int i = 0; i < instanceCount; i++) { + PalAccelerationStructureInstance* src = &instances[i]; + VkAccelerationStructureInstanceKHR* dst = &data[i]; + AccelerationStructureVk* as = (AccelerationStructureVk*)src->blas; + + dst->mask = src->mask & 0xFF; + dst->instanceCustomIndex = src->instanceId & 0xFFFFFF; + dst->accelerationStructureReference = as->address; + dst->instanceShaderBindingTableRecordOffset = src->hitGroupOffset & 0xFFFFFF; + dst->flags = instanceFlagsToVk(src->flags); + memcpy(dst->transform.matrix, src->transform, sizeof(float) * 12); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL writeToImageCopyStagingBufferVk( + PalDevice* device, + void* ptr, + void* srcData, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo) +{ + uint32_t imageFormatSize = getFormatSize(imageFormat); + uint32_t dstRowPitch = copyInfo->bufferRowLength * imageFormatSize; + uint32_t srcRowPitch = copyInfo->imageWidth * imageFormatSize; + const uint32_t dstSlicePitch = dstRowPitch * copyInfo->bufferImageHeight; + const uint32_t srcSlicePitch = srcRowPitch * copyInfo->imageHeight; + + // manually offset the buffer with the provided offset + uint8_t* dst = (uint8_t*)ptr + copyInfo->bufferOffset; + const uint8_t* src = (const uint8_t*)srcData; + + // write to destination pointer + for (uint32_t z = 0; z < copyInfo->imageDepth; z++) { + for (uint32_t y = 0; y < copyInfo->imageHeight; y++) { + memcpy( + dst + z * dstSlicePitch + y * dstRowPitch, + src + z * srcSlicePitch + y * srcRowPitch, + srcRowPitch); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL bindBufferMemoryVk( + PalBuffer* buffer, + PalMemory* memory, + uint64_t offset) +{ + VkResult result; + MemoryVk* vkMemory = (MemoryVk*)memory; + BufferVk* vkBuffer = (BufferVk*)buffer; + + if (vkBuffer->memory) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + result = s_Vk.bindBufferMemory( + vkBuffer->device->handle, + vkBuffer->handle, + vkMemory->handle, + offset); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + vkBuffer->memory = vkMemory; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL mapBufferMemoryVk( + PalBuffer* buffer, + uint64_t offset, + uint64_t size, + void** outPtr) +{ + VkResult result; + BufferVk* vkBuffer = (BufferVk*)buffer; + DeviceVk* device = vkBuffer->device; + + if (vkBuffer->memory->type == PAL_MEMORY_TYPE_GPU_ONLY) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + result = s_Vk.mapMemory(device->handle, vkBuffer->memory->handle, offset, size, 0, outPtr); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer) +{ + BufferVk* vkBuffer = (BufferVk*)buffer; + s_Vk.unmapMemory(vkBuffer->device->handle, vkBuffer->memory->handle); +} + +PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer) +{ + BufferVk* vkBuffer = (BufferVk*)buffer; + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS)) { + return 0; + } + + VkBufferDeviceAddressInfoKHR bufferInfo = {0}; + bufferInfo.buffer = vkBuffer->handle; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; + return vkBuffer->device->getBufferrAddress(vkBuffer->device->handle, &bufferInfo); +} + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_command_pool_vulkan.c b/src/graphics/vulkan/pal_command_pool_vulkan.c new file mode 100644 index 00000000..cc912e93 --- /dev/null +++ b/src/graphics/vulkan/pal_command_pool_vulkan.c @@ -0,0 +1,231 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +PalResult PAL_CALL createCommandPoolVk( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool) +{ + VkResult result; + CommandPoolVk* pool = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + QueueVk* vkQueue = (QueueVk*)queue; + PhysicalQueue* phyQueue = vkQueue->phyQueue; + + pool = palAllocate(s_Vk.allocator, sizeof(CommandPoolVk), 0); + if (!pool) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkCommandPoolCreateInfo cInfo = {0}; + cInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cInfo.queueFamilyIndex = phyQueue->familyIndex; + cInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + result = s_Vk.createCommandPool(vkDevice->handle, &cInfo, &s_Vk.vkAllocator, &pool->handle); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + pool->device = vkDevice; + pool->reserved = PAL_BACKEND_KEY; + *outPool = (PalCommandPool*)pool; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool) +{ + CommandPoolVk* vkPool = (CommandPoolVk*)pool; + s_Vk.destroyCommandPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkPool); +} + +PalResult PAL_CALL resetCommandPoolVk(PalCommandPool* pool) +{ + CommandPoolVk* vkCmdPool = (CommandPoolVk*)pool; + s_Vk.resetCommandPool(vkCmdPool->device->handle, vkCmdPool->handle, 0); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL allocateCommandBufferVk( + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outCmdBuffer) +{ + VkResult result; + CommandBufferVk* cmdBuffer = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + CommandPoolVk* vkPool = (CommandPoolVk*)pool; + + cmdBuffer = palAllocate(s_Vk.allocator, sizeof(CommandBufferVk), 0); + if (!cmdBuffer) { + PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkCommandBufferAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.commandBufferCount = 1; + allocateInfo.commandPool = vkPool->handle; + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + + cmdBuffer->primary = PAL_TRUE; + if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + cmdBuffer->primary = PAL_FALSE; + } + + result = s_Vk.allocateCommandBuffer(vkDevice->handle, &allocateInfo, &cmdBuffer->handle); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, cmdBuffer); + return makeResultVk(result); + } + + // create a gpu buffer if ray tracing is enabled + if (vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + VkBufferCreateInfo bufCreateInfo = {0}; + bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufCreateInfo.size = sizeof(VkTraceRaysIndirectCommandKHR); + bufCreateInfo.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; + bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + result = s_Vk.createBuffer( + vkDevice->handle, + &bufCreateInfo, + &s_Vk.vkAllocator, + &cmdBuffer->buffer); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + // allocate CPU upload memory and bind + VkMemoryRequirements memReq = {0}; + s_Vk.getBufferMemoryRequirements(vkDevice->handle, cmdBuffer->buffer, &memReq); + + VkMemoryAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = memReq.size; + + uint32_t mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + allocateInfo.memoryTypeIndex = memoryIndex; + + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &cmdBuffer->bufferMemory); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + s_Vk.bindBufferMemory(vkDevice->handle, cmdBuffer->buffer, cmdBuffer->bufferMemory, 0); + } + + cmdBuffer->device = vkDevice; + cmdBuffer->pool = vkPool; + cmdBuffer->reserved = PAL_BACKEND_KEY; + *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + s_Vk.freeCommandBuffer( + vkCmdBuffer->device->handle, + vkCmdBuffer->pool->handle, + 1, + &vkCmdBuffer->handle); + + if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + s_Vk.destroyBuffer(vkCmdBuffer->device->handle, vkCmdBuffer->buffer, &s_Vk.vkAllocator); + s_Vk.freeMemory(vkCmdBuffer->device->handle, vkCmdBuffer->bufferMemory, &s_Vk.vkAllocator); + } + + palFree(s_Vk.allocator, vkCmdBuffer); +} + +PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL submitCommandBufferVk( + PalQueue* queue, + PalCommandBufferSubmitInfo* info) +{ + VkResult result; + int32_t waitSemaphoreCount = 0; + int32_t signalSemaphoreCount = 0; + VkFence fenceHandle = nullptr; + VkSemaphore waitSemaphoreHandle = nullptr; + VkSemaphore signalSemaphoreHandle = nullptr; + QueueVk* vkQueue = (QueueVk*)queue; + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)info->cmdBuffer; + PhysicalQueue* phyQueue = vkQueue->phyQueue; + + if (info->waitSemaphore) { + SemaphoreVk* tmp = (SemaphoreVk*)info->waitSemaphore; + waitSemaphoreHandle = tmp->handle; + waitSemaphoreCount = 1; + } + + if (info->signalSemaphore) { + SemaphoreVk* tmp = (SemaphoreVk*)info->signalSemaphore; + signalSemaphoreHandle = tmp->handle; + signalSemaphoreCount = 1; + } + + if (info->fence) { + FenceVk* tmp = (FenceVk*)info->fence; + fenceHandle = tmp->handle; + } + + VkCommandBufferSubmitInfoKHR cmdBufferSubmitInfo = {0}; + cmdBufferSubmitInfo.commandBuffer = vkCmdBuffer->handle; + cmdBufferSubmitInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR; + + VkSemaphoreSubmitInfoKHR waitSubmitInfo = {0}; + waitSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; + waitSubmitInfo.semaphore = waitSemaphoreHandle; + waitSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + + VkSemaphoreSubmitInfoKHR signalSubmitInfo = {0}; + signalSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; + signalSubmitInfo.semaphore = signalSemaphoreHandle; + signalSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + + if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + waitSubmitInfo.value = info->waitValue; + signalSubmitInfo.value = info->signalValue; + } + + VkSubmitInfo2KHR submitInfo = {0}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR; + submitInfo.commandBufferInfoCount = 1; + submitInfo.pCommandBufferInfos = &cmdBufferSubmitInfo; + submitInfo.pSignalSemaphoreInfos = &signalSubmitInfo; + submitInfo.pWaitSemaphoreInfos = &waitSubmitInfo; + submitInfo.waitSemaphoreInfoCount = waitSemaphoreCount; + submitInfo.signalSemaphoreInfoCount = signalSemaphoreCount; + + result = vkCmdBuffer->device->queueSubmit(phyQueue->handle, 1, &submitInfo, fenceHandle); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c new file mode 100644 index 00000000..c572f5f9 --- /dev/null +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -0,0 +1,1382 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +#define MAX_ATTACHMENTS 32 + +static void commitShaderbindingTableUpdate( + CommandBufferVk* cmdBuffer, + ShaderBindingTableVk* sbt) +{ + if (!sbt->isDirty) { + return; + } + + // begin upload buffer copy to gpu buffer + VkBufferCopy copyRegion = {0}; + copyRegion.size = sbt->stagingBufferSize; + s_Vk.cmdCopyBuffer(cmdBuffer->handle, sbt->stagingBuffer, sbt->buffer, 1, ©Region); + + // put a memory barrier + VkBufferMemoryBarrier2KHR barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; + + barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR; + barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; + + barrier.dstStageMask = VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; + barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT_KHR; + + barrier.buffer = sbt->buffer; + barrier.offset = 0; + barrier.size = VK_WHOLE_SIZE; + + VkDependencyInfo dependencyInfo = {0}; + dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependencyInfo.bufferMemoryBarrierCount = 1; + dependencyInfo.pBufferMemoryBarriers = &barrier; + + cmdBuffer->device->cmdPipelineBarrier(cmdBuffer->handle, &dependencyInfo); + sbt->isDirty = PAL_FALSE; +} + +PalResult PAL_CALL cmdBeginVk( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + VkCommandBufferBeginInfo beginInfo = {0}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + + VkCommandBufferInheritanceInfo inheritanceInfo = {0}; + inheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + VkCommandBufferInheritanceRenderingInfoKHR layout = {0}; + layout.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; + + VkFormat format = VK_FORMAT_UNDEFINED; + VkFormat colorAttachments[MAX_ATTACHMENTS]; + if (!vkCmdBuffer->primary) { + // secondary command buffer + for (int i = 0; i < info->colorAttachentCount; i++) { + format = formatToVk(info->colorAttachmentsFormat[i]); + colorAttachments[i] = format; + } + layout.colorAttachmentCount = info->colorAttachentCount; + layout.pColorAttachmentFormats = colorAttachments; + + // depth stencil attachment + format = formatToVk(info->depthStencilAttachmentFormat); + layout.depthAttachmentFormat = format; + layout.stencilAttachmentFormat = format; + + layout.rasterizationSamples = samplesToVk(info->sampleCount); + layout.flags = renderingFlagToVk(info->flags); + if (info->viewCount == 1) { + layout.viewMask = 0; + } else { + layout.viewMask = (1 << info->viewCount) - 1; + } + + inheritanceInfo.pNext = &layout; + beginInfo.pNext = &inheritanceInfo; + } + + VkResult result = s_Vk.cmdBegin(vkCmdBuffer->handle, &beginInfo); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + VkResult result = s_Vk.cmdEnd(vkCmdBuffer->handle); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdExecuteCommandBufferVk( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)primaryCmdBuffer; + CommandBufferVk* vkCmdBuffer2 = (CommandBufferVk*)secondaryCmdBuffer; + s_Vk.cmdExecuteCommandBuffer(vkCmdBuffer->handle, 1, &vkCmdBuffer2->handle); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetFragmentShadingRateVk( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkExtent2D size = getShadingRateSizeVk(state->rate); + VkFragmentShadingRateCombinerOpKHR combinerOps[2]; + for (int i = 0; i < 2; i++) { + combinerOps[i] = combinerOpsToVk(state->combinerOps[i]); + } + + device->cmdSetFragmentShadingRate(vkCmdBuffer->handle, &size, combinerOps); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawMeshTasksVk( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + device->cmdDrawMeshTask(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t drawCount) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + BufferVk* vkBuffer = (BufferVk*)buffer; + + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); + device->cmdDrawMeshTaskIndirect( + vkCmdBuffer->handle, + vkBuffer->handle, + 0, + drawCount, + stride); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + BufferVk* vkBuffer = (BufferVk*)buffer; + BufferVk* vkCountBuffer = (BufferVk*)countBuffer; + + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); + device->cmdDrawMeshTaskIndirectCount( + vkCmdBuffer->handle, + vkBuffer->handle, + 0, + vkCountBuffer->handle, + 0, + maxDrawCount, + stride); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBuildAccelerationStructureVk( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + VkAccelerationStructureGeometryKHR* geometries = nullptr; + VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; + AccelerationStructureVk* tmpAs = (AccelerationStructureVk*)info->src; + AccelerationStructureVk* dstAs = (AccelerationStructureVk*)info->dst; + VkAccelerationStructureKHR srcAs = nullptr; + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + + if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + // cache these for top level as + VkAccelerationStructureBuildRangeInfoKHR cachedRangeInfo = {0}; + VkAccelerationStructureGeometryKHR cachedGeometries = {0}; + uint32_t geometryCount = info->count; + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { + geometryCount = 1; + rangeInfos = &cachedRangeInfo; + geometries = &cachedGeometries; + } + + if (tmpAs) { + srcAs = tmpAs->handle; + } + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + geometries = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureGeometryKHR) * geometryCount, + 0); + + rangeInfos = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureBuildRangeInfoKHR) * geometryCount, + 0); + + if (!rangeInfos || !geometries) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * geometryCount); + memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * geometryCount); + } + + fillBuildInfoVk( + geometryCount, + info, + nullptr, + geometries, + srcAs, + dstAs->handle, + rangeInfos, + &buildInfo); + + const VkAccelerationStructureBuildRangeInfoKHR* tmp[1]; + tmp[0] = rangeInfos; + vkCmdBuffer->device->cmdBuildAccelerationStructures(vkCmdBuffer->handle, 1, &buildInfo, tmp); + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + palFree(s_Vk.allocator, geometries); + palFree(s_Vk.allocator, rangeInfos); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBeginRenderingVk( + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + VkRenderingInfoKHR rendering = {0}; + rendering.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR; + + VkRenderingAttachmentInfoKHR depthAttachment = {0}; + VkRenderingAttachmentInfoKHR stencilAttachment = {0}; + VkRenderingAttachmentInfoKHR colorAttachments[MAX_ATTACHMENTS]; + + VkRenderingAttachmentInfoKHR* attachment = nullptr; + PalAttachmentDesc* desc = nullptr; + ImageViewVk* imageView = nullptr; + ImageViewVk* resolveImageView = nullptr; + VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL; + + VkRenderingFragmentShadingRateAttachmentInfoKHR fsrInfo = {0}; + fsrInfo.sType = VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; + + uint32_t layerCount = UINT32_MAX; + uint32_t renderWidth = UINT32_MAX; + uint32_t renderHeight = UINT32_MAX; + for (int i = 0; i < info->colorAttachentCount; i++) { + attachment = &colorAttachments[i]; + desc = &info->colorAttachments[i]; + imageView = (ImageViewVk*)desc->imageView; + resolveImageView = (ImageViewVk*)desc->resolveImageView; + + attachment->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; + attachment->pNext = nullptr; + layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment->resolveImageView = nullptr; + attachment->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + attachment->clearValue.color.float32[0] = desc->clearValue.color[0]; + attachment->clearValue.color.float32[1] = desc->clearValue.color[1]; + attachment->clearValue.color.float32[2] = desc->clearValue.color[2]; + attachment->clearValue.color.float32[3] = desc->clearValue.color[3]; + + attachment->imageView = imageView->handle; + if (resolveImageView) { + attachment->resolveImageView = resolveImageView->handle; + attachment->resolveImageLayout = layout; + } + + // load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + // store op + if (desc->storeOp == PAL_STORE_OP_STORE) { + attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + + } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { + attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + + attachment->resolveMode = resolveModeToVk(desc->resolveMode); + attachment->imageLayout = layout; + + // compute layer count and render area + layerCount = minVk(layerCount, imageView->layerCount); + renderWidth = minVk(renderWidth, imageView->image->info.width); + renderHeight = minVk(renderHeight, imageView->image->info.height); + + if (resolveImageView) { + layerCount = minVk(layerCount, resolveImageView->layerCount); + renderWidth = minVk(renderWidth, resolveImageView->image->info.width); + renderHeight = minVk(renderHeight, resolveImageView->image->info.height); + } + } + + rendering.colorAttachmentCount = info->colorAttachentCount; + rendering.pColorAttachments = colorAttachments; + + // depth attachment + if (info->depthStencilAttachment) { + attachment = &depthAttachment; + desc = info->depthStencilAttachment; + imageView = (ImageViewVk*)desc->imageView; + resolveImageView = (ImageViewVk*)desc->resolveImageView; + + attachment->sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; + attachment->pNext = nullptr; + attachment->resolveImageView = nullptr; + attachment->resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + stencilAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR; + stencilAttachment.pNext = nullptr; + stencilAttachment.resolveImageView = nullptr; + stencilAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + attachment->clearValue.depthStencil.depth = desc->clearValue.depth; + stencilAttachment.clearValue.depthStencil.stencil = desc->clearValue.stencil; + + attachment->imageView = imageView->handle; + stencilAttachment.imageView = imageView->handle; + if (resolveImageView) { + attachment->resolveImageView = resolveImageView->handle; + attachment->resolveImageLayout = layout; + + stencilAttachment.resolveImageView = resolveImageView->handle; + stencilAttachment.resolveImageLayout = layout; + } + + // load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + attachment->loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + // store op + if (desc->storeOp == PAL_STORE_OP_STORE) { + attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE; + + } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { + attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + + // stencil load op + if (desc->stencilLoadOp == PAL_LOAD_OP_CLEAR) { + stencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + + } else if (desc->stencilLoadOp == PAL_LOAD_OP_LOAD) { + stencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + + } else if (desc->stencilLoadOp == PAL_LOAD_OP_DONT_CARE) { + stencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + } + + // stencil store op + if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { + stencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + + } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { + stencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + + attachment->resolveMode = resolveModeToVk(desc->resolveMode); + attachment->imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + stencilAttachment.resolveMode = resolveModeToVk(desc->resolveMode); + stencilAttachment.imageLayout = VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL; + + rendering.pDepthAttachment = &depthAttachment; + rendering.pStencilAttachment = &stencilAttachment; + + // compute layer count and render area + layerCount = minVk(layerCount, imageView->layerCount); + renderWidth = minVk(renderWidth, imageView->image->info.width); + renderHeight = minVk(renderHeight, imageView->image->info.height); + + if (resolveImageView) { + layerCount = minVk(layerCount, resolveImageView->layerCount); + renderWidth = minVk(renderWidth, resolveImageView->image->info.width); + renderHeight = minVk(renderHeight, resolveImageView->image->info.height); + } + } + + // fragment shading rate attachment + if (info->fragmentShadingRateAttachment) { + imageView = (ImageViewVk*)info->fragmentShadingRateAttachment->imageView; + fsrInfo.imageView = imageView->handle; + + fsrInfo.shadingRateAttachmentTexelSize.width = + info->fragmentShadingRateAttachment->texelWidth; + + fsrInfo.shadingRateAttachmentTexelSize.height = + info->fragmentShadingRateAttachment->texelHeight; + + fsrInfo.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + rendering.pNext = &fsrInfo; + + // compute layer count and render area + layerCount = minVk(layerCount, imageView->layerCount); + renderWidth = minVk(renderWidth, imageView->image->info.width); + renderHeight = minVk(renderHeight, imageView->image->info.height); + } + + rendering.layerCount = layerCount; + rendering.renderArea.offset.x = 0; + rendering.renderArea.offset.y = 0; + rendering.renderArea.extent.width = renderWidth; + rendering.renderArea.extent.height = renderHeight; + + if (info->viewCount == 1) { + rendering.viewMask = 0; + } else { + rendering.viewMask = (1 << info->viewCount) - 1; + } + + vkCmdBuffer->device->cmdBeginRendering(vkCmdBuffer->handle, &rendering); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + vkCmdBuffer->device->cmdEndRendering(vkCmdBuffer->handle); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdCopyBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + BufferVk* dstBuffer = (BufferVk*)dst; + BufferVk* srcBuffer = (BufferVk*)src; + + VkBufferCopy copyRegion = {0}; + copyRegion.size = copyInfo->size; + copyRegion.dstOffset = copyInfo->dstOffset; + copyRegion.srcOffset = copyInfo->srcOffset; + s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, srcBuffer->handle, dstBuffer->handle, 1, ©Region); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdCopyBufferToImageVk( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + ImageVk* dst = (ImageVk*)dstImage; + BufferVk* src = (BufferVk*)srcBuffer; + + VkBufferImageCopy copyRegion = {0}; + copyRegion.bufferImageHeight = copyInfo->bufferImageHeight; + copyRegion.bufferOffset = copyInfo->bufferOffset; + copyRegion.bufferRowLength = copyInfo->bufferRowLength; + + copyRegion.imageOffset.x = copyInfo->imageOffsetX; + copyRegion.imageOffset.y = copyInfo->imageOffsetY; + copyRegion.imageOffset.z = copyInfo->imageOffsetZ; + + copyRegion.imageExtent.width = copyInfo->imageWidth; + copyRegion.imageExtent.height = copyInfo->imageHeight; + copyRegion.imageExtent.depth = copyInfo->imageDepth; + + copyRegion.imageSubresource.aspectMask = imageAspectToVk(copyInfo->imageAspect); + copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; + copyRegion.imageSubresource.layerCount = copyInfo->ImageArrayLayerCount; + copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; + + s_Vk.cmdCopyBufferToImage( + vkCmdBuffer->handle, + src->handle, + dst->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ©Region); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdCopyImageVk( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + ImageVk* dstImage = (ImageVk*)dst; + ImageVk* srcImage = (ImageVk*)src; + + VkImageCopy copyRegion = {0}; + copyRegion.dstOffset.x = copyInfo->dstOffsetX; + copyRegion.dstOffset.y = copyInfo->dstOffsetY; + copyRegion.dstOffset.z = copyInfo->dstOffsetZ; + + copyRegion.srcOffset.x = copyInfo->srcOffsetX; + copyRegion.srcOffset.y = copyInfo->srcOffsetY; + copyRegion.srcOffset.z = copyInfo->srcOffsetZ; + + copyRegion.extent.width = copyInfo->width; + copyRegion.extent.height = copyInfo->height; + copyRegion.extent.depth = copyInfo->depth; + + copyRegion.dstSubresource.aspectMask = imageAspectToVk(copyInfo->aspect); + copyRegion.dstSubresource.baseArrayLayer = copyInfo->dstStartArrayLayer; + copyRegion.dstSubresource.layerCount = copyInfo->arrayLayerCount; + copyRegion.dstSubresource.mipLevel = copyInfo->dstMipLevel; + + copyRegion.srcSubresource.aspectMask = imageAspectToVk(copyInfo->aspect); + copyRegion.srcSubresource.baseArrayLayer = copyInfo->srcStartArrayLayer; + copyRegion.srcSubresource.layerCount = copyInfo->arrayLayerCount; + copyRegion.srcSubresource.mipLevel = copyInfo->srcMipLevel; + + s_Vk.cmdCopyImage( + vkCmdBuffer->handle, + srcImage->handle, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dstImage->handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + ©Region); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdCopyImageToBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + BufferVk* dst = (BufferVk*)dstBuffer; + ImageVk* src = (ImageVk*)srcImage; + + VkBufferImageCopy copyRegion = {0}; + copyRegion.bufferImageHeight = copyInfo->bufferImageHeight; + copyRegion.bufferOffset = copyInfo->bufferOffset; + copyRegion.bufferRowLength = copyInfo->bufferRowLength; + + copyRegion.imageOffset.x = copyInfo->imageOffsetX; + copyRegion.imageOffset.y = copyInfo->imageOffsetY; + copyRegion.imageOffset.z = copyInfo->imageOffsetZ; + + copyRegion.imageExtent.width = copyInfo->imageWidth; + copyRegion.imageExtent.height = copyInfo->imageHeight; + copyRegion.imageExtent.depth = copyInfo->imageDepth; + + copyRegion.imageSubresource.aspectMask = imageAspectToVk(copyInfo->imageAspect); + copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; + copyRegion.imageSubresource.layerCount = copyInfo->ImageArrayLayerCount; + copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; + + s_Vk.cmdCopyImageToBuffer( + vkCmdBuffer->handle, + src->handle, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + dst->handle, + 1, + ©Region); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBindPipelineVk( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + PipelineVk* vkPipeline = (PipelineVk*)pipeline; + s_Vk.cmdBindPipeline(vkCmdBuffer->handle, vkPipeline->bindPoint, vkPipeline->handle); + + vkCmdBuffer->pipeline = vkPipeline; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetViewportVk( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalViewport* viewports) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + VkViewport cachedViewport; + VkViewport* vkViewports = nullptr; + if (count > 1) { + vkViewports = palAllocate(s_Vk.allocator, sizeof(VkViewport) * count, 0); + if (!vkViewports) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + } else { + vkViewports = &cachedViewport; + } + + for (int i = 0; i < count; i++) { + VkViewport* tmp = &vkViewports[i]; + tmp->x = viewports[i].x; + tmp->y = viewports[i].y; + tmp->width = viewports[i].width; + tmp->height = viewports[i].height; + tmp->minDepth = viewports[i].minDepth; + tmp->maxDepth = viewports[i].maxDepth; + } + + s_Vk.cmdSetViewports(vkCmdBuffer->handle, 0, count, vkViewports); + if (count > 1) { + palFree(s_Vk.allocator, vkViewports); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetScissorsVk( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalRect2D* scissors) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + VkRect2D cachedScissor; + VkRect2D* vkScissors = nullptr; + if (count > 1) { + vkScissors = palAllocate(s_Vk.allocator, sizeof(VkRect2D) * count, 0); + if (!vkScissors) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + } else { + vkScissors = &cachedScissor; + } + + for (int i = 0; i < count; i++) { + VkRect2D* tmp = &vkScissors[i]; + tmp->offset.x = scissors[i].x; + tmp->offset.y = scissors[i].y; + tmp->extent.width = scissors[i].width; + tmp->extent.height = scissors[i].height; + } + + s_Vk.cmdSetScissors(vkCmdBuffer->handle, 0, count, vkScissors); + if (count > 1) { + palFree(s_Vk.allocator, vkScissors); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBindVertexBuffersVk( + PalCommandBuffer* cmdBuffer, + uint32_t firstSlot, + uint32_t count, + PalBuffer** buffers, + uint64_t* offsets) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + VkBuffer cachedbuffer = nullptr; + VkBuffer* vkBuffers = nullptr; + if (count > 1) { + vkBuffers = palAllocate(s_Vk.allocator, sizeof(VkBuffer) * count, 0); + if (!vkBuffers) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + } else { + vkBuffers = &cachedbuffer; + } + + for (int i = 0; i < count; i++) { + DeviceVk* tmp = (DeviceVk*)buffers[i]; + vkBuffers[i] = tmp->handle; + } + + s_Vk.cmdBindVertexBuffers(vkCmdBuffer->handle, firstSlot, count, vkBuffers, offsets); + if (count > 1) { + palFree(s_Vk.allocator, vkBuffers); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBindIndexBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint64_t offset, + PalIndexType type) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + BufferVk* vkBuffer = (BufferVk*)buffer; + VkIndexType bufferType = VK_INDEX_TYPE_UINT32; + if (type == PAL_INDEX_TYPE_UINT16) { + bufferType = VK_INDEX_TYPE_UINT16; + } + + s_Vk.cmdBindIndexBuffer(vkCmdBuffer->handle, vkBuffer->handle, offset, bufferType); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawVk( + PalCommandBuffer* cmdBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + s_Vk.cmdDraw(vkCmdBuffer->handle, vertexCount, instanceCount, firstVertex, firstInstance); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + BufferVk* vkBuffer = (BufferVk*)buffer; + uint32_t stride = sizeof(VkDrawIndirectCommand); + + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + s_Vk.cmdDrawIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + BufferVk* vkBuffer = (BufferVk*)buffer; + BufferVk* vkCountBuffer = (BufferVk*)countBuffer; + DeviceVk* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + uint32_t stride = sizeof(VkDrawIndirectCommand); + device->cmdDrawIndirectCount( + vkCmdBuffer->handle, + vkBuffer->handle, + 0, + vkCountBuffer->handle, + 0, + maxDrawCount, + stride); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawIndexedVk( + PalCommandBuffer* cmdBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + s_Vk.cmdDrawIndexed( + vkCmdBuffer->handle, + indexCount, + instanceCount, + firstIndex, + vertexOffset, + firstInstance); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawIndexedIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + BufferVk* vkBuffer = (BufferVk*)buffer; + uint32_t stride = sizeof(VkDrawIndexedIndirectCommand); + + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + s_Vk.cmdDrawIndexedIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + BufferVk* vkBuffer = (BufferVk*)buffer; + BufferVk* vkCountBuffer = (BufferVk*)countBuffer; + DeviceVk* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + uint32_t stride = sizeof(VkDrawIndexedIndirectCommand); + device->cmdDrawIndexedIndirectCount( + vkCmdBuffer->handle, + vkBuffer->handle, + 0, + vkCountBuffer->handle, + 0, + maxDrawCount, + stride); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdAccelerationStructureBarrierVk( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, + PalUsageState oldUsageState, + PalUsageState newUsageState) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipeline = vkCmdBuffer->pipeline; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkMemoryBarrier2KHR barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR; + Barrier old = barrierToVk(oldUsageState); + Barrier new = barrierToVk(oldUsageState); + + barrier.srcStageMask = pipeline->stages; + barrier.srcAccessMask = old.access; + barrier.dstStageMask = pipeline->stages; + barrier.dstAccessMask = new.access; + + VkDependencyInfo dependencyInfo = {0}; + dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependencyInfo.memoryBarrierCount = 1; + dependencyInfo.pMemoryBarriers = &barrier; + + vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdImageBarrierVk( + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalUsageState oldUsageState, + PalUsageState newUsageState) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipeline = vkCmdBuffer->pipeline; + ImageVk* vkImage = (ImageVk*)image; + VkImageMemoryBarrier2KHR barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR; + Barrier old = barrierToVk(oldUsageState); + Barrier new = barrierToVk(oldUsageState); + + barrier.srcStageMask = pipeline->stages; + barrier.srcAccessMask = old.access; + barrier.oldLayout = old.layout; + barrier.dstStageMask = pipeline->stages; + barrier.dstAccessMask = new.access; + barrier.newLayout = new.layout; + + barrier.image = vkImage->handle; + barrier.subresourceRange.aspectMask = imageAspectToVk(subresourceRange->aspect); + barrier.subresourceRange.baseArrayLayer = subresourceRange->startArrayLayer; + barrier.subresourceRange.baseMipLevel = subresourceRange->startMipLevel; + barrier.subresourceRange.layerCount = subresourceRange->layerArrayCount; + barrier.subresourceRange.levelCount = subresourceRange->mipLevelCount; + + VkDependencyInfo dependencyInfo = {0}; + dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependencyInfo.imageMemoryBarrierCount = 1; + dependencyInfo.pImageMemoryBarriers = &barrier; + + vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBufferBarrierVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipeline = vkCmdBuffer->pipeline; + BufferVk* vkBuffer = (BufferVk*)buffer; + VkBufferMemoryBarrier2KHR barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; + Barrier old = barrierToVk(oldUsageState); + Barrier new = barrierToVk(oldUsageState); + + barrier.srcStageMask = pipeline->stages; + barrier.srcAccessMask = old.access; + barrier.dstStageMask = pipeline->stages; + barrier.dstAccessMask = new.access; + + barrier.buffer = vkBuffer->handle; + barrier.offset = 0; + barrier.size = VK_WHOLE_SIZE; + + VkDependencyInfo dependencyInfo = {0}; + dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependencyInfo.bufferMemoryBarrierCount = 1; + dependencyInfo.pBufferMemoryBarriers = &barrier; + + vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDispatchVk( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + s_Vk.cmdDispatch(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDispatchBaseVk( + PalCommandBuffer* cmdBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_DISPATCH_BASE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + device->cmdDispatchBase( + vkCmdBuffer->handle, + baseGroupX, + baseGroupY, + baseGroupZ, + groupCountX, + groupCountY, + groupCountZ); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDispatchIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + BufferVk* vkBuffer = (BufferVk*)buffer; + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + s_Vk.cmdDispatchIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdTraceRaysVk( + PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; + + if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkStridedDeviceAddressRegionKHR raygenAddress = {0}; + raygenAddress.size = vkSbt->raygen.region.size; + raygenAddress.stride = vkSbt->raygen.region.stride; + raygenAddress.deviceAddress = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; + + // we need to make sure the SBT is up to date + commitShaderbindingTableUpdate(vkCmdBuffer, vkSbt); + + vkCmdBuffer->device->cmdTraceRays( + vkCmdBuffer->handle, + &raygenAddress, + &vkSbt->miss.region, + &vkSbt->hit.region, + &vkSbt->callable.region, + width, + height, + depth); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdTraceRaysIndirectVk( + PalCommandBuffer* cmdBuffer, + uint32_t raygenIndex, + PalShaderBindingTable* sbt, + PalBuffer* buffer) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; + BufferVk* vkBuffer = (BufferVk*)buffer; + + if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; + vkSbt->raygen.region.deviceAddress = address; + + // we need to make sure the SBT is up to date + commitShaderbindingTableUpdate(vkCmdBuffer, vkSbt); + + // copy users buffer data into a tmp gpu buffer abd execute with it + VkBufferCopy copyRegion = {0}; + copyRegion.size = sizeof(VkTraceRaysIndirectCommandKHR); + s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, vkBuffer->handle, vkCmdBuffer->buffer, 1, ©Region); + + // put a memory barrier + VkBufferMemoryBarrier2KHR barrier = {0}; + barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; + barrier.srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT_KHR; + barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; + barrier.dstStageMask = VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; + barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT_KHR; + + barrier.buffer = vkCmdBuffer->buffer; + barrier.offset = 0; + barrier.size = VK_WHOLE_SIZE; + + VkDependencyInfo dependencyInfo = {0}; + dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + dependencyInfo.bufferMemoryBarrierCount = 1; + dependencyInfo.pBufferMemoryBarriers = &barrier; + vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); + + VkDeviceAddress bufAddress = 0; + VkBufferDeviceAddressInfoKHR bufferInfo = {0}; + bufferInfo.buffer = vkCmdBuffer->buffer; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; + bufAddress = vkCmdBuffer->device->getBufferrAddress(vkCmdBuffer->device->handle, &bufferInfo); + + vkCmdBuffer->device->cmdTraceRaysIndirect( + vkCmdBuffer->handle, + &vkSbt->raygen.region, + &vkSbt->miss.region, + &vkSbt->hit.region, + &vkSbt->callable.region, + bufAddress); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBindDescriptorSetVk( + PalCommandBuffer* cmdBuffer, + uint32_t setIndex, + PalDescriptorSet* set) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipeline = vkCmdBuffer->pipeline; + DescriptorSetVk* vkSet = (DescriptorSetVk*)set; + + s_Vk.cmdBindDescriptorSets( + vkCmdBuffer->handle, + pipeline->bindPoint, + pipeline->layout, + setIndex, + 1, + &vkSet->handle, + 0, + nullptr); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdPushConstantsVk( + PalCommandBuffer* cmdBuffer, + uint64_t offset, + uint64_t size, + const void* value) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipeline = vkCmdBuffer->pipeline; + + s_Vk.cmdPushConstants( + vkCmdBuffer->handle, + pipeline->layout, + pipeline->shaderStages, + offset, + size, + value); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetCullModeVk( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkCullModeFlags vkCullMode = 0; + switch (cullMode) { + case PAL_CULL_MODE_BACK: + vkCullMode = VK_CULL_MODE_BACK_BIT; + + case PAL_CULL_MODE_FRONT: + vkCullMode = VK_CULL_MODE_FRONT_BIT; + + case PAL_CULL_MODE_NONE: + vkCullMode = VK_CULL_MODE_NONE; + } + + device->cmdSetCullMode(vkCmdBuffer->handle, vkCullMode); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetFrontFaceVk( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkFrontFace vkFrontFace = 0; + switch (frontFace) { + case PAL_FRONT_FACE_CLOCKWISE: + vkFrontFace = VK_FRONT_FACE_CLOCKWISE; + + case PAL_FRONT_FACE_COUNTER_CLOCKWISE: + vkFrontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + } + + device->cmdSetFrontFace(vkCmdBuffer->handle, vkFrontFace); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetPrimitiveTopologyVk( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkPrimitiveTopology vkTopology = 0; + switch (topology) { + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { + vkTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { + vkTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_LIST: { + vkTopology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP: { + vkTopology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_POINT_LIST: { + vkTopology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + break; + } + } + + device->cmdSetPrimitiveTopology(vkCmdBuffer->handle, vkTopology); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetDepthTestEnableVk( + PalCommandBuffer* cmdBuffer, + PalBool enable) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + device->cmdSetDepthTestEnable(vkCmdBuffer->handle, enable); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetDepthWriteEnableVk( + PalCommandBuffer* cmdBuffer, + PalBool enable) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + device->cmdSetDepthWriteEnable(vkCmdBuffer->handle, enable); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetStencilOpVk( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp) +{ + CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = vkCmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkStencilFaceFlags faceFlags = 0; + if (faceMask & PAL_STENCIL_FACE_FLAG_BACK) { + faceFlags |= VK_STENCIL_FACE_BACK_BIT; + } + + if (faceMask & PAL_STENCIL_FACE_FLAG_FRONT) { + faceFlags |= VK_STENCIL_FACE_FRONT_BIT; + } + + VkStencilOp vkFailOp = stencilOpToVk(failOp); + VkStencilOp vkPassOp = stencilOpToVk(passOp); + VkStencilOp vkDepthFailOp = stencilOpToVk(depthFailOp); + VkCompareOp vkCompareOp = compareOpToVk(compareOp); + + device->cmdSetStencilOp( + vkCmdBuffer->handle, + faceFlags, + failOp, + passOp, + depthFailOp, + compareOp); + + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_descriptors_vulkan.c b/src/graphics/vulkan/pal_descriptors_vulkan.c new file mode 100644 index 00000000..2857f1d7 --- /dev/null +++ b/src/graphics/vulkan/pal_descriptors_vulkan.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_device_vulkan.c b/src/graphics/vulkan/pal_device_vulkan.c new file mode 100644 index 00000000..2857f1d7 --- /dev/null +++ b/src/graphics/vulkan/pal_device_vulkan.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_image_vulkan.c b/src/graphics/vulkan/pal_image_vulkan.c new file mode 100644 index 00000000..2857f1d7 --- /dev/null +++ b/src/graphics/vulkan/pal_image_vulkan.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_pipeline_vulkan.c b/src/graphics/vulkan/pal_pipeline_vulkan.c new file mode 100644 index 00000000..2857f1d7 --- /dev/null +++ b/src/graphics/vulkan/pal_pipeline_vulkan.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_sbt_vulkan.c b/src/graphics/vulkan/pal_sbt_vulkan.c new file mode 100644 index 00000000..6dceda5e --- /dev/null +++ b/src/graphics/vulkan/pal_sbt_vulkan.c @@ -0,0 +1,410 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +#define align(v, a) (v + a - 1) & ~(a - 1) + +PalResult PAL_CALL createShaderBindingTableVk( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt) +{ + VkResult result; + DeviceVk* vkDevice = (DeviceVk*)device; + ShaderBindingTableVk* sbt = nullptr; + PipelineVk* pipeline = (PipelineVk*)info->rayTracingPipeline; + ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + uint32_t totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; + totalGroups += sbtInfo->missCount + sbtInfo->callableCount; + if (info->recordCount != totalGroups) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + sbt = palAllocate(s_Vk.allocator, sizeof(ShaderBindingTableVk), 0); + if (!sbt) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + // create SBT buffer + VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayProps = {0}; + rayProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; + + VkPhysicalDeviceProperties2KHR props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; + props.pNext = &rayProps; + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &props); + + uint32_t groupHandleSize = rayProps.shaderGroupHandleSize; + uint32_t groupHandleAlignment = rayProps.shaderGroupHandleAlignment; + uint32_t groupBaseAlignment = rayProps.shaderGroupBaseAlignment; + + // get the max local data size + for (int i = 0; i < info->recordCount; i++) { + PalShaderBindingTableRecordInfo* record = &info->records[i]; + uint32_t index = record->groupIndex; + + if (index < sbtInfo->raygenCount) { + // raygen group + if (record->localDataSize > sbtInfo->raygenDataSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { + // miss group + if (record->localDataSize > sbtInfo->missDataSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { + // hit group + if (record->localDataSize > sbtInfo->hitDataSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + } else { + // callable group + if (record->localDataSize > sbtInfo->callableDataSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + } + } + + // get strides + uint32_t callableStride = 0; + uint32_t raygenStride = align(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); + uint32_t missStride = align(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); + uint32_t hitStride = align(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); + callableStride = align(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); + + // get region size + uint32_t raygenRegionSize = raygenStride * sbtInfo->raygenCount; + uint32_t missRegionSize = missStride * sbtInfo->missCount; + uint32_t hitRegionSize = hitStride * sbtInfo->hitCount; + uint32_t callableRegionSize = callableStride * sbtInfo->callableCount; + + // get offsets + uint32_t offset = 0; + uint32_t raygenOffset = 0; + uint32_t missOffset = 0; + uint32_t hitOffset = 0; + uint32_t callableOffset = 0; + + raygenOffset = align(offset, groupBaseAlignment); + offset = raygenOffset + raygenRegionSize; + + missOffset = align(offset, groupBaseAlignment); + offset = missOffset + missRegionSize; + + hitOffset = align(offset, groupBaseAlignment); + offset = hitOffset + hitRegionSize; + + callableOffset = align(offset, groupBaseAlignment); + offset = callableOffset + callableRegionSize; + + uint32_t bufferSize = align(offset, groupBaseAlignment); + + // create gpu buffer + VkBufferCreateInfo bufCreateInfo = {0}; + bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufCreateInfo.size = bufferSize; + bufCreateInfo.usage = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR; + bufCreateInfo.usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_KHR; + bufCreateInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; + bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + // create staging buffer + bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + sbt->stagingBufferSize = bufferSize; + result = s_Vk.createBuffer( + vkDevice->handle, + &bufCreateInfo, + &s_Vk.vkAllocator, + &sbt->stagingBuffer); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + // allocate CPU upload memory and bind + VkMemoryRequirements memReq = {0}; + s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->buffer, &memReq); + + VkMemoryAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = memReq.size; + + uint32_t mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + allocateInfo.memoryTypeIndex = memoryIndex; + + VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; + allocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + allocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + allocateInfo.pNext = &allocateFlagsInfo; + + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &sbt->bufferMemory); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + // allocate memory for staging buffer + s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->stagingBuffer, &memReq); + allocateInfo.allocationSize = memReq.size; + + mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] & memReq.memoryTypeBits; + memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + allocateInfo.memoryTypeIndex = memoryIndex; + allocateInfo.pNext = nullptr; // we dont need the address + + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &sbt->stagingBufferMemory); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); + s_Vk.bindBufferMemory(vkDevice->handle, sbt->stagingBuffer, sbt->stagingBufferMemory, 0); + + // get shader group handles + uint32_t handlesSize = totalGroups * groupHandleSize; + uint8_t* handles = palAllocate(s_Vk.allocator, handlesSize, 0); + if (!handles) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + result = vkDevice->getRayTracingShaderGroupHandles( + vkDevice->handle, + pipeline->handle, + 0, + totalGroups, + handlesSize, + handles); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + // copy handles into the buffer + void* ptr = nullptr; + result = s_Vk.mapMemory(vkDevice->handle, sbt->stagingBufferMemory, 0, VK_WHOLE_SIZE, 0, &ptr); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + offset = 0; // reuse variable + uint8_t* srcPtr = (uint8_t*)handles; + + // raygen + for (int i = 0; i < sbtInfo->raygenCount; i++) { + uint8_t* dstPtr = (uint8_t*)ptr + (i * raygenStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } + } + + offset += sbtInfo->raygenCount; + srcPtr += (groupHandleSize * sbtInfo->raygenCount); + + // miss + for (int i = 0; i < sbtInfo->missCount; i++) { + uint8_t* dstPtr = (uint8_t*)ptr + missOffset + (i * missStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } + } + + offset += sbtInfo->missCount; + srcPtr += (groupHandleSize * sbtInfo->missCount); + + // hit + for (int i = 0; i < sbtInfo->hitCount; i++) { + uint8_t* dstPtr = (uint8_t*)ptr + hitOffset + (i * hitStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } + } + + offset += sbtInfo->hitCount; + srcPtr += (groupHandleSize * sbtInfo->hitCount); + + // callable + for (int i = 0; i < sbtInfo->callableCount; i++) { + uint8_t* dstPtr = (uint8_t*)ptr + callableOffset + (i * callableStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, srcPtr + (i * groupHandleSize), groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } + } + + s_Vk.unmapMemory(vkDevice->handle, sbt->stagingBufferMemory); + + // cache SBT fields and offsets address + // we know the layout so we can prepare the strided address before we copy to the gpu buffer + VkBufferDeviceAddressInfo bufferAddressInfo = {0}; + bufferAddressInfo.buffer = sbt->buffer; + bufferAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; + sbt->baseAddress = s_Vk.getBufferDeviceAddress(vkDevice->handle, &bufferAddressInfo); + + // raygen + sbt->raygen.region.deviceAddress = sbt->baseAddress; + sbt->raygen.offset = 0; // always + sbt->raygen.startIndex = 0; // always + sbt->raygen.region.size = raygenRegionSize; + sbt->raygen.region.stride = raygenStride; + + // miss + sbt->miss.offset = missOffset; + sbt->miss.startIndex = sbtInfo->raygenCount; + sbt->miss.region.deviceAddress = sbt->baseAddress + missOffset; + sbt->miss.region.size = missRegionSize; + sbt->miss.region.stride = missStride; + + // hit + sbt->hit.offset = hitOffset; + sbt->hit.startIndex = sbtInfo->raygenCount + sbtInfo->missCount; + sbt->hit.region.deviceAddress = sbt->baseAddress + hitOffset; + sbt->hit.region.size = hitRegionSize; + sbt->hit.region.stride = hitStride; + + // callable + sbt->callable.offset = callableOffset; + sbt->callable.startIndex = sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount; + sbt->callable.region.deviceAddress = sbt->baseAddress + callableOffset; + sbt->callable.region.size = callableRegionSize; + sbt->callable.region.stride = callableStride; + + palFree(s_Vk.allocator, handles); + sbt->device = vkDevice; + sbt->handleSize = groupHandleSize; + sbt->pipeline = pipeline; + + sbt->isDirty = PAL_TRUE; // we need to copy from the staging to the gpu buffer + sbt->reserved = PAL_BACKEND_KEY; + *outSbt = (PalShaderBindingTable*)sbt; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt) +{ + ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; + DeviceVk* device = vkSbt->device; + s_Vk.destroyBuffer(device->handle, vkSbt->buffer, &s_Vk.vkAllocator); + s_Vk.destroyBuffer(device->handle, vkSbt->stagingBuffer, &s_Vk.vkAllocator); + s_Vk.freeMemory(device->handle, vkSbt->bufferMemory, &s_Vk.vkAllocator); + s_Vk.freeMemory(device->handle, vkSbt->stagingBufferMemory, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkSbt); +} + +PalResult PAL_CALL updateShaderBindingTableVk( + PalShaderBindingTable* sbt, + uint32_t count, + PalShaderBindingTableRecordInfo* infos) +{ + VkResult result; + ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; + DeviceVk* vkDevice = vkSbt->device; + PipelineVk* pipeline = vkSbt->pipeline; + ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; + + void* data = nullptr; + result = s_Vk.mapMemory( + vkDevice->handle, + vkSbt->stagingBufferMemory, + 0, + VK_WHOLE_SIZE, + 0, + &data); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + uint32_t stride = 0; + uint32_t offset = 0; + uint32_t startIndex = 0; + + for (int i = 0; i < count; i++) { + PalShaderBindingTableRecordInfo* info = &infos[i]; + if (!info->localDataSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + // find the group the record belongs to + uint32_t index = info->groupIndex; + if (index < sbtInfo->raygenCount) { + // raygen group + offset = 0; + stride = vkSbt->raygen.region.stride; + startIndex = vkSbt->raygen.startIndex; + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { + // miss group + offset = vkSbt->miss.offset; + stride = vkSbt->miss.region.stride; + startIndex = vkSbt->miss.startIndex; + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { + // hit group + offset = vkSbt->hit.offset; + stride = vkSbt->hit.region.stride; + startIndex = vkSbt->hit.startIndex; + + } else { + // callable group + offset = vkSbt->callable.offset; + stride = vkSbt->callable.region.stride; + startIndex = vkSbt->callable.startIndex; + } + + // write payload + uint32_t localIndex = index - startIndex; + uint8_t* dst = (uint8_t*)data + offset + (localIndex * stride); + memcpy(dst + vkSbt->handleSize, info->localData, info->localDataSize); + } + + s_Vk.unmapMemory(vkDevice->handle, vkSbt->stagingBufferMemory); + vkSbt->isDirty = PAL_TRUE; + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_sync_vulkan.c b/src/graphics/vulkan/pal_sync_vulkan.c new file mode 100644 index 00000000..2857f1d7 --- /dev/null +++ b/src/graphics/vulkan/pal_sync_vulkan.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h new file mode 100644 index 00000000..410c8e7e --- /dev/null +++ b/src/graphics/vulkan/pal_vulkan.h @@ -0,0 +1,493 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_VULKAN_H +#define _PAL_VULKAN_H + +#if PAL_HAS_VULKAN_BACKEND +#include "pal/pal_graphics.h" +#include + +typedef struct _XDisplay Display; +typedef unsigned long Window; +typedef struct xcb_connection_t xcb_connection_t; +typedef uint32_t xcb_window_t; +typedef struct HINSTANCE__ *HINSTANCE; +typedef struct HWND__ *HWND; + +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; +typedef VkFlags VkXlibSurfaceCreateFlagsKHR; +typedef VkFlags VkXcbSurfaceCreateFlagsKHR; +typedef VkFlags VkWin32SurfaceCreateFlagsKHR; + +typedef struct VkWaylandSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display* display; + struct wl_surface* surface; +} VkWaylandSurfaceCreateInfoKHR; + +typedef struct VkXlibSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; +} VkXlibSurfaceCreateInfoKHR; + +typedef struct VkXcbSurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; +} VkXcbSurfaceCreateInfoKHR; + +typedef struct VkWin32SurfaceCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)( + VkInstance, + const VkWaylandSurfaceCreateInfoKHR*, + const VkAllocationCallbacks*, + VkSurfaceKHR*); + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)( + VkInstance, + const VkXlibSurfaceCreateInfoKHR*, + const VkAllocationCallbacks*, + VkSurfaceKHR*); + +typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)( + VkInstance, + const VkXcbSurfaceCreateInfoKHR*, + const VkAllocationCallbacks*, + VkSurfaceKHR*); + +typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)( + VkInstance, + const VkWin32SurfaceCreateInfoKHR*, + const VkAllocationCallbacks*, + VkSurfaceKHR*); + +typedef struct { + int32_t familyIndex; + VkPhysicalDevice phyDevice; + VkQueue handle; + VkQueueFlags usages; + VkQueueFlags usedUsages; +} PhysicalQueue; + +typedef struct { + uint32_t maxPayloadSize; +} DeviceLimits; + +typedef struct { + uint32_t patchControlPoints; + VkShaderStageFlagBits stage; + char entryName[PAL_SHADER_ENTRY_NAME_SIZE]; +} ShaderEntry; + +typedef struct { + uint32_t raygenCount; + uint32_t raygenDataSize; + uint32_t missCount; + uint32_t missDataSize; + uint32_t hitCount; + uint32_t hitDataSize; + uint32_t callableCount; + uint32_t callableDataSize; +} ShaderBindingTableInfo; + +typedef struct { + uint32_t startIndex; + uint32_t offset; + VkStridedDeviceAddressRegionKHR region; +} AddressRegion; + +typedef struct { + VkAccessFlags2 access; + VkImageLayout layout; +} Barrier; + +typedef struct { + void* reserved; + VkPhysicalDevice handle; +} AdapterVk; + +typedef struct { + void* reserved; + PalAdapterFeatures features; + int32_t phyQueueCount; + int32_t phyQueueIndex; + int32_t queueFamilyCount; + uint32_t memoryClassMask[3]; + VkPhysicalDevice phyDevice; + VkDevice handle; + PhysicalQueue* phyQueues; + PFN_vkGetBufferDeviceAddress getBufferrAddress; + PFN_vkCmdDispatchBase cmdDispatchBase; + + // draw indirect + PFN_vkCmdDrawIndirectCount cmdDrawIndirectCount; + PFN_vkCmdDrawIndexedIndirectCount cmdDrawIndexedIndirectCount; + + // swapchain + PFN_vkCreateSwapchainKHR createSwapchain; + PFN_vkDestroySwapchainKHR destroySwapchain; + PFN_vkGetSwapchainImagesKHR getSwapchainImages; + PFN_vkAcquireNextImageKHR acquireNextImage; + PFN_vkQueuePresentKHR queuePresent; + + // semaphore + PFN_vkWaitSemaphores waitSemaphore; + PFN_vkSignalSemaphore signalSemaphore; + PFN_vkGetSemaphoreCounterValue getSemaphoreValue; + + // fragment shading rate + PFN_vkCmdSetFragmentShadingRateKHR cmdSetFragmentShadingRate; + + // mesh shader + PFN_vkCmdDrawMeshTasksEXT cmdDrawMeshTask; + PFN_vkCmdDrawMeshTasksIndirectEXT cmdDrawMeshTaskIndirect; + PFN_vkCmdDrawMeshTasksIndirectCountEXT cmdDrawMeshTaskIndirectCount; + + // ray tracing + PFN_vkCreateAccelerationStructureKHR createAccelerationStructure; + PFN_vkDestroyAccelerationStructureKHR destroyAccelerationStructure; + PFN_vkGetAccelerationStructureBuildSizesKHR getAccelerationBuildsize; + PFN_vkCmdBuildAccelerationStructuresKHR cmdBuildAccelerationStructures; + PFN_vkGetAccelerationStructureDeviceAddressKHR getAccelerationDeviceAddress; + PFN_vkCmdTraceRaysKHR cmdTraceRays; + PFN_vkCreateRayTracingPipelinesKHR createRayTracingPipeline; + PFN_vkCmdTraceRaysIndirectKHR cmdTraceRaysIndirect; + PFN_vkGetRayTracingShaderGroupHandlesKHR getRayTracingShaderGroupHandles; + + // dynamic rendering + PFN_vkCmdBeginRendering cmdBeginRendering; + PFN_vkCmdEndRendering cmdEndRendering; + PFN_vkCmdPipelineBarrier2 cmdPipelineBarrier; + PFN_vkQueueSubmit2 queueSubmit; + + // dynamic states + PFN_vkCmdSetCullMode cmdSetCullMode; + PFN_vkCmdSetFrontFace cmdSetFrontFace; + PFN_vkCmdSetPrimitiveTopology cmdSetPrimitiveTopology; + PFN_vkCmdSetDepthTestEnable cmdSetDepthTestEnable; + PFN_vkCmdSetDepthWriteEnable cmdSetDepthWriteEnable; + PFN_vkCmdSetStencilOp cmdSetStencilOp; + + DeviceLimits limits; +} DeviceVk; + +typedef struct { + void* reserved; + VkQueueFlags usage; + DeviceVk* device; + PhysicalQueue* phyQueue; +} QueueVk; + +typedef struct { + void* reserved; + PalMemoryType type; + VkDeviceMemory handle; +} MemoryVk; + +typedef struct { + void* reserved; + DeviceVk* device; + MemoryVk* memory; + VkImage handle; + PalImageInfo info; +} ImageVk; + +typedef struct { + void* reserved; + uint32_t layerCount; + DeviceVk* device; + ImageVk* image; + VkImageView handle; +} ImageViewVk; + +typedef struct { + void* reserved; + DeviceVk* device; + VkSurfaceKHR handle; +} SurfaceVk; + +typedef struct { + void* reserved; + uint32_t imageCount; + DeviceVk* device; + QueueVk* queue; + VkSwapchainKHR handle; + ImageVk* images; +} SwapchainVk; + +typedef struct { + void* reserved; + uint32_t entryCount; + ShaderEntry* entries; + DeviceVk* device; + VkShaderModule handle; +} ShaderVk; + +typedef struct { + void* reserved; + DeviceVk* device; + VkCommandPool handle; +} CommandPoolVk; + +typedef struct { + void* reserved; + PalBool primary; + DeviceVk* device; + CommandPoolVk* pool; + void* pipeline; + VkBuffer buffer; + VkDeviceMemory bufferMemory; + VkCommandBuffer handle; +} CommandBufferVk; + +typedef struct { + void* reserved; + DeviceVk* device; + VkFence handle; +} FenceVk; + +typedef struct { + void* reserved; + PalBool isTimeline; + DeviceVk* device; + VkSemaphore handle; +} SemaphoreVk; + +typedef struct { + void* reserved; + PalBool isMemoryManaged; + PalBufferUsages usages; + MemoryVk* memory; + DeviceVk* device; + VkBuffer handle; +} BufferVk; + +typedef struct { + void* reserved; + VkDeviceAddress address; + VkBuffer buffer; + VkDeviceMemory bufferMemory; + VkDeviceAddress bufferAddress; + DeviceVk* device; + VkAccelerationStructureKHR handle; +} AccelerationStructureVk; + +typedef struct { + void* reserved; + PalDescriptorIndexingFlags flags; + DeviceVk* device; + VkDescriptorSetLayout handle; +} DescriptorSetLayoutVk; + +typedef struct { + void* reserved; + PalDescriptorIndexingFlags flags; + DeviceVk* device; + VkDescriptorPool handle; +} DescriptorPoolVk; + +typedef struct { + void* reserved; + DeviceVk* device; + DescriptorPoolVk* pool; + VkDescriptorSet handle; +} DescriptorSetVk; + +typedef struct { + void* reserved; + DeviceVk* device; + VkSampler handle; +} SamplerVk; + +typedef struct { + void* reserved; + DeviceVk* device; + VkPipelineLayout handle; +} PipelineLayoutVk; + +typedef struct { + void* reserved; + VkPipelineBindPoint bindPoint; + VkPipelineStageFlags2 stages; + VkShaderStageFlags shaderStages; + DeviceVk* device; + VkPipeline handle; + VkPipelineLayout layout; + ShaderBindingTableInfo sbtInfo; +} PipelineVk; + +typedef struct { + void* reserved; + PalBool isDirty; + uint32_t stagingBufferSize; + uint32_t handleSize; + DeviceVk* device; + VkBuffer buffer; + VkBuffer stagingBuffer; + VkDeviceMemory bufferMemory; + VkDeviceMemory stagingBufferMemory; + VkDeviceAddress baseAddress; + PipelineVk* pipeline; + AddressRegion raygen; + AddressRegion miss; + AddressRegion hit; + AddressRegion callable; +} ShaderBindingTableVk; + +typedef struct { + PFN_vkEnumerateInstanceVersion enumerateInstanceVersion; + PFN_vkEnumerateInstanceExtensionProperties enumerateInstanceExtensionProperties; + PFN_vkDestroyInstance destroyInstance; + PFN_vkCreateInstance createInstance; + PFN_vkEnumeratePhysicalDevices enumeratePhysicalDevices; + PFN_vkGetPhysicalDeviceProperties getPhysicalDeviceProperties; + PFN_vkGetPhysicalDeviceMemoryProperties getPhysicalDeviceMemoryProperties; + PFN_vkEnumerateInstanceLayerProperties enumerateInstanceLayerProperties; + PFN_vkGetPhysicalDeviceQueueFamilyProperties getPhysicalDeviceQueueFamilyProperties; + PFN_vkEnumerateDeviceExtensionProperties enumerateDeviceExtensionProperties; + PFN_vkGetPhysicalDeviceFeatures getPhysicalDeviceFeatures; + PFN_vkGetPhysicalDeviceFeatures2 getPhysicalDeviceFeatures2; + PFN_vkGetInstanceProcAddr getInstanceProcAddr; + PFN_vkCreateImageView createImageView; + PFN_vkDestroyImageView destroyImageView; + PFN_vkGetPhysicalDeviceProperties2 getPhysicalDeviceProperties2; + PFN_vkGetPhysicalDeviceFormatProperties getPhysicalDeviceFormatProperties; + PFN_vkGetPhysicalDeviceImageFormatProperties getPhysicalDeviceImageFormatProperties; + PFN_vkGetImageMemoryRequirements getImageMemoryRequirements; + PFN_vkAllocateMemory allocateMemory; + PFN_vkFreeMemory freeMemory; + PFN_vkBindImageMemory bindImageMemory; + PFN_vkCreateDevice createDevice; + PFN_vkDestroyDevice destroyDevice; + PFN_vkGetDeviceQueue getDeviceQueue; + PFN_vkQueueSubmit queueSubmit; + PFN_vkGetDeviceProcAddr getDeviceProcAddr; + PFN_vkCreateImage createImage; + PFN_vkDestroyImage destroyImage; + PFN_vkCreateShaderModule createShader; + PFN_vkDestroyShaderModule destroyShader; + PFN_vkCreateSampler createSampler; + PFN_vkDestroySampler destroySampler; + PFN_vkCreateCommandPool createCommandPool; + PFN_vkDestroyCommandPool destroyCommandPool; + PFN_vkAllocateCommandBuffers allocateCommandBuffer; + PFN_vkFreeCommandBuffers freeCommandBuffer; + PFN_vkCreateFence createFence; + PFN_vkDestroyFence destroyFence; + PFN_vkResetFences resetFence; + PFN_vkWaitForFences waitFence; + PFN_vkGetFenceStatus isFenceSignaled; + PFN_vkCreateSemaphore createSemaphore; + PFN_vkDestroySemaphore destroySemaphore; + PFN_vkBeginCommandBuffer cmdBegin; + PFN_vkEndCommandBuffer cmdEnd; + PFN_vkResetCommandPool resetCommandPool; + PFN_vkResetCommandBuffer resetCommandBuffer; + PFN_vkCmdExecuteCommands cmdExecuteCommandBuffer; + PFN_vkCmdCopyBuffer cmdCopyBuffer; + PFN_vkCmdCopyBufferToImage cmdCopyBufferToImage; + PFN_vkCmdCopyImage cmdCopyImage; + PFN_vkCmdCopyImageToBuffer cmdCopyImageToBuffer; + PFN_vkCmdBindPipeline cmdBindPipeline; + PFN_vkCmdSetViewport cmdSetViewports; + PFN_vkCmdSetScissor cmdSetScissors; + PFN_vkCmdBindVertexBuffers cmdBindVertexBuffers; + PFN_vkCmdBindIndexBuffer cmdBindIndexBuffer; + PFN_vkCmdDraw cmdDraw; + PFN_vkCmdDrawIndirect cmdDrawIndirect; + PFN_vkCmdDrawIndexed cmdDrawIndexed; + PFN_vkCmdDrawIndexedIndirect cmdDrawIndexedIndirect; + PFN_vkCmdDispatch cmdDispatch; + PFN_vkCmdDispatchIndirect cmdDispatchIndirect; + PFN_vkCmdBindDescriptorSets cmdBindDescriptorSets; + PFN_vkCmdPushConstants cmdPushConstants; + PFN_vkCreateWaylandSurfaceKHR createWaylandSurface; + PFN_vkCreateXlibSurfaceKHR createXlibSurface; + PFN_vkCreateXcbSurfaceKHR createXcbSurface; + PFN_vkCreateWin32SurfaceKHR createWin32Surface; + PFN_vkDestroySurfaceKHR destroySurface; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR getSurfaceCapabilities; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR getSurfaceFormats; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR getSurfacePresentModes; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR checkSurfaceSupport; + PFN_vkCreateBuffer createBuffer; + PFN_vkDestroyBuffer destroyBuffer; + PFN_vkGetBufferMemoryRequirements getBufferMemoryRequirements; + PFN_vkBindBufferMemory bindBufferMemory; + PFN_vkMapMemory mapMemory; + PFN_vkUnmapMemory unmapMemory; + PFN_vkGetBufferDeviceAddress getBufferDeviceAddress; + PFN_vkCreateDescriptorSetLayout createDescriptorSetLayout; + PFN_vkDestroyDescriptorSetLayout destroyDescriptorSetLayout; + PFN_vkCreateDescriptorPool createDescriptorPool; + PFN_vkDestroyDescriptorPool destroyDescriptorPool; + PFN_vkResetDescriptorPool resetDescriptorPool; + PFN_vkAllocateDescriptorSets allocateDescriptorSet; + PFN_vkUpdateDescriptorSets updateDescriptorSet; + PFN_vkCreatePipelineLayout createPipelineLayout; + PFN_vkDestroyPipelineLayout destroyPipelineLayout; + PFN_vkCreateGraphicsPipelines createGraphicsPipeline; + PFN_vkCreateComputePipelines createComputePipeline; + PFN_vkDestroyPipeline destroyPipeline; + PFN_vkCreateDebugUtilsMessengerEXT createMessenger; + PFN_vkDestroyDebugUtilsMessengerEXT destroyMessenger; + PFN_vkQueueWaitIdle waitQueue; + + void* handle; + VkInstance instance; + VkDebugUtilsMessengerEXT messenger; + PalDebugCallback callback; + const PalAllocator* allocator; + AdapterVk* adapters; + VkAllocationCallbacks vkAllocator; +} Vulkan; + +extern Vulkan s_Vk; + +PalResult makeResultVk(VkResult result); +VkFormat formatToVk(PalFormat format); +VkSampleCountFlags samplesToVk(PalSampleCount count); +VkExtent2D getShadingRateSizeVk(PalFragmentShadingRate rate); + +VkFragmentShadingRateCombinerOpKHR combinerOpsToVk(PalFragmentShadingRateCombinerOp op); +VkImageAspectFlags imageAspectToVk(PalImageAspect aspect); +Barrier barrierToVk(PalUsageState state); +VkStencilOp stencilOpToVk(PalStencilOp op); +VkCompareOp compareOpToVk(PalCompareOp op); +VkRenderingFlags renderingFlagToVk(PalRenderingFlags flags); + +uint32_t findBestMemoryIndexVk( + VkPhysicalDevice phyDevice, + uint32_t memoryMask); + +void fillBuildInfoVk( + uint32_t count, + PalAccelerationStructureBuildInfo* info, + uint32_t* maxPrimities, + VkAccelerationStructureGeometryKHR* geometries, + VkAccelerationStructureKHR srcAs, + VkAccelerationStructureKHR dstAs, + VkAccelerationStructureBuildRangeInfoKHR* rangeInfos, + VkAccelerationStructureBuildGeometryInfoKHR* buildInfo); + +#endif // PAL_HAS_VULKAN_BACKEND +#endif // _PAL_VULKAN_H \ No newline at end of file From 829b12e690ff13e42c3431542811714688b3f2be Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 2 Jul 2026 14:41:55 +0000 Subject: [PATCH 310/372] vulkan rework: add pipelines and images --- include/pal/pal_graphics.h | 11 +- src/graphics/pal_vulkan.c | 1685 +----------------- src/graphics/vulkan/pal_commands_vulkan.c | 2 - src/graphics/vulkan/pal_descriptors_vulkan.c | 410 +++++ src/graphics/vulkan/pal_image_vulkan.c | 326 ++++ src/graphics/vulkan/pal_pipeline_vulkan.c | 935 ++++++++++ src/graphics/vulkan/pal_vulkan.h | 7 +- 7 files changed, 1704 insertions(+), 1672 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 2d721dd5..bab2a74f 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -384,7 +384,8 @@ #define PAL_BLEND_OP_SUBTRACT 1 #define PAL_BLEND_OP_REVERSE_SUBTRACT 2 #define PAL_BLEND_OP_MIN 3 -#define PAL_BLEND_OP_COUNT 4 +#define PAL_BLEND_OP_MAX 4 +#define PAL_BLEND_OP_COUNT 5 #define PAL_BLEND_FACTOR_ZERO 0 #define PAL_BLEND_FACTOR_ONE 1 @@ -397,10 +398,10 @@ #define PAL_BLEND_FACTOR_DST_ALPHA 8 #define PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA 9 #define PAL_BLEND_FACTOR_CONSTANT_COLOR 10 -#define PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR 10 -#define PAL_BLEND_FACTOR_CONSTANT_ALPHA 11 -#define PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA 12 -#define PAL_BLEND_FACTOR_COUNT 13 +#define PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR 11 +#define PAL_BLEND_FACTOR_CONSTANT_ALPHA 12 +#define PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA 13 +#define PAL_BLEND_FACTOR_COUNT 14 #define PAL_COLOR_MASK_NONE 0 #define PAL_COLOR_MASK_RED (1U << 0) diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c index f7fa02a9..4c0ba572 100644 --- a/src/graphics/pal_vulkan.c +++ b/src/graphics/pal_vulkan.c @@ -243,7 +243,7 @@ VkRenderingFlags renderingFlagToVk(PalRenderingFlags flags) return renderingFlags; } -static PalResult resultFromVk(VkResult result) +static PalResult resultFromVknnn(VkResult result) { switch (result) { case VK_ERROR_FEATURE_NOT_PRESENT: @@ -288,36 +288,6 @@ static PalResult resultFromVk(VkResult result) return PAL_RESULT_PLATFORM_FAILURE; } -static VkImageUsageFlags imageUsageToVk(PalImageUsages usages) -{ - VkImageUsageFlags flags = 0; - if (usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { - flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - } - - if (usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { - flags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - } - - if (usages & PAL_IMAGE_USAGE_TRANSFER_SRC) { - flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - } - - if (usages & PAL_IMAGE_USAGE_TRANSFER_DST) { - flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - } - - if (usages & PAL_IMAGE_USAGE_STORAGE) { - flags |= VK_IMAGE_USAGE_STORAGE_BIT; - } - - if (usages & PAL_IMAGE_USAGE_SAMPLED) { - flags |= VK_IMAGE_USAGE_SAMPLED_BIT; - } - - return flags; -} - static VkFormat formatToVk(PalFormat format) { switch (format) { @@ -1045,58 +1015,7 @@ static VkFormat vertexTypeToVk(PalVertexType type) } -static uint32_t getVertexTypeSizeVk(PalVertexType type) -{ - // count x sizeof type returned as size - switch (type) { - case PAL_VERTEX_TYPE_INT8_2: - case PAL_VERTEX_TYPE_UINT8_2: - case PAL_VERTEX_TYPE_INT8_2NORM: - case PAL_VERTEX_TYPE_UINT8_2NORM: { - return 2; - } - - case PAL_VERTEX_TYPE_INT32: - case PAL_VERTEX_TYPE_UINT32: - case PAL_VERTEX_TYPE_INT8_4: - case PAL_VERTEX_TYPE_INT8_4NORM: - case PAL_VERTEX_TYPE_UINT8_4: - case PAL_VERTEX_TYPE_UINT8_4NORM: - case PAL_VERTEX_TYPE_INT16_2NORM: - case PAL_VERTEX_TYPE_INT16_2: - case PAL_VERTEX_TYPE_UINT16_2: - case PAL_VERTEX_TYPE_UINT16_2NORM: - case PAL_VERTEX_TYPE_FLOAT: - case PAL_VERTEX_TYPE_HALF_FLOAT16_2: { - return 4; - } - - case PAL_VERTEX_TYPE_INT32_2: - case PAL_VERTEX_TYPE_UINT32_2: - case PAL_VERTEX_TYPE_INT16_4: - case PAL_VERTEX_TYPE_UINT16_4: - case PAL_VERTEX_TYPE_UINT16_4NORM: - case PAL_VERTEX_TYPE_INT16_4NORM: - case PAL_VERTEX_TYPE_FLOAT2: - case PAL_VERTEX_TYPE_HALF_FLOAT16_4: { - return 8; - } - - case PAL_VERTEX_TYPE_INT32_3: - case PAL_VERTEX_TYPE_UINT32_3: - case PAL_VERTEX_TYPE_FLOAT3: { - return 12; - } - - case PAL_VERTEX_TYPE_INT32_4: - case PAL_VERTEX_TYPE_UINT32_4: - case PAL_VERTEX_TYPE_FLOAT4: { - return 16; - } - } - return 0; -} static VkStencilOp stencilOpToVk(PalStencilOp op) { @@ -1160,98 +1079,9 @@ static VkCompareOp compareOpToVk(PalCompareOp op) return VK_COMPARE_OP_NEVER; } -static VkBlendOp blendOpToVk(PalBlendOp op) -{ - switch (op) { - case PAL_BLEND_OP_ADD: - return VK_BLEND_OP_ADD; - - case PAL_BLEND_OP_SUBTRACT: - return VK_BLEND_OP_SUBTRACT; - - case PAL_BLEND_OP_REVERSE_SUBTRACT: - return VK_BLEND_OP_REVERSE_SUBTRACT; - - case PAL_BLEND_OP_MIN: - return VK_BLEND_OP_MIN; - - case PAL_BLEND_OP_MAX: - return VK_BLEND_OP_MAX; - } - - return VK_BLEND_OP_ADD; -} - -static VkBlendFactor blendFactorToVk(PalBlendFactor op) -{ - switch (op) { - case PAL_BLEND_FACTOR_ZERO: - return VK_BLEND_FACTOR_ZERO; - - case PAL_BLEND_FACTOR_ONE: - return VK_BLEND_FACTOR_ONE; - - case PAL_BLEND_FACTOR_SRC_COLOR: - return VK_BLEND_FACTOR_SRC_COLOR; - - case PAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: - return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; - - case PAL_BLEND_FACTOR_DST_COLOR: - return VK_BLEND_FACTOR_DST_COLOR; - - case PAL_BLEND_FACTOR_ONE_MINUX_DST_COLOR: - return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; - - case PAL_BLEND_FACTOR_SRC_ALPHA: - return VK_BLEND_FACTOR_SRC_ALPHA; - - case PAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: - return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - - case PAL_BLEND_FACTOR_DST_ALPHA: - return VK_BLEND_FACTOR_DST_ALPHA; - - case PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: - return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; - - case PAL_BLEND_FACTOR_CONSTANT_COLOR: - return VK_BLEND_FACTOR_CONSTANT_COLOR; - - case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR: - return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; - - case PAL_BLEND_FACTOR_CONSTANT_ALPHA: - return VK_BLEND_FACTOR_CONSTANT_ALPHA; - - case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: - return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; - } - return VK_BLEND_FACTOR_ZERO; -} - -static VkFragmentShadingRateCombinerOpKHR combinerOpsToVk(PalFragmentShadingRateCombinerOp op) -{ - switch (op) { - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP: - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE: - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN: - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR; - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX: - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR; - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL: - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR; - } - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; -} static VkResolveModeFlags resolveModeToVk(PalResolveMode mode) { @@ -1271,45 +1101,6 @@ static VkResolveModeFlags resolveModeToVk(PalResolveMode mode) return VK_RESOLVE_MODE_NONE_KHR; } - -static VkPipelineStageFlags2 pipelineStageToVk(PalShaderStage stage) -{ - switch (stage) { - case PAL_SHADER_STAGE_VERTEX: - return VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT; - - case PAL_SHADER_STAGE_FRAGMENT: - return VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; - - case PAL_SHADER_STAGE_COMPUTE: - return VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; - - case PAL_SHADER_STAGE_GEOMETRY: - return VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT; - - case PAL_SHADER_STAGE_MESH: - return VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT; - - case PAL_SHADER_STAGE_TASK: - return VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT; - - case PAL_SHADER_STAGE_TESSELLATION_CONTROL: - return VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT; - - case PAL_SHADER_STAGE_TESSELLATION_EVALUATION: - return VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT; - - case PAL_SHADER_STAGE_RAYGEN: - case PAL_SHADER_STAGE_CLOSEST_HIT: - case PAL_SHADER_STAGE_ANY_HIT: - case PAL_SHADER_STAGE_MISS: - case PAL_SHADER_STAGE_INTERSECTION: - case PAL_SHADER_STAGE_CALLABLE: { - return VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; - } - } - return 0; -} static VkFilter filterToVk(PalFilterMode mode) { @@ -2555,7 +2346,7 @@ PalResult PAL_CALL initGraphicsVk( VkInstance instance = nullptr; result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.vkAllocator, &instance); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } // clang-format off @@ -3710,7 +3501,7 @@ PalResult PAL_CALL createDeviceVk( palFree(s_Vk.allocator, queueCreateInfos); palFree(s_Vk.allocator, device->phyQueues); palFree(s_Vk.allocator, device); - return resultFromVk(result); + return makeResultVk(result); } device->phyQueueIndex = 0; @@ -4148,7 +3939,7 @@ PalResult PAL_CALL allocateMemoryVk( &memory->handle); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } memory->type = type; @@ -4583,7 +4374,7 @@ PalResult PAL_CALL waitQueueVk(PalQueue* queue) Queue* vkQueue = (Queue*)queue; VkResult result = s_Vk.waitQueue(vkQueue->phyQueue->handle); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } return PAL_RESULT_SUCCESS; @@ -4732,276 +4523,7 @@ PalSampleCount PAL_CALL queryFormatSampleCountVk( // Image // ================================================== -PalResult PAL_CALL createImageVk( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage) -{ - VkResult result; - Image* image = nullptr; - Device* vkDevice = (Device*)device; - - image = palAllocate(s_Vk.allocator, sizeof(Image), 0); - if (!image) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkImageCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - createInfo.extent.width = info->width; - createInfo.extent.height = info->height; - createInfo.mipLevels = info->mipLevelCount; - - createInfo.format = formatToVk(info->format); - createInfo.samples = samplesToVk(info->sampleCount); - createInfo.usage = imageUsageToVk(info->usages); - createInfo.arrayLayers = info->depthOrArraySize; - createInfo.extent.depth = 1; - - createInfo.imageType = VK_IMAGE_TYPE_2D; - if (info->type == PAL_IMAGE_TYPE_3D) { - createInfo.arrayLayers = 1; - createInfo.extent.depth = info->depthOrArraySize; - createInfo.imageType = VK_IMAGE_TYPE_3D; - - } else if (info->type == PAL_IMAGE_TYPE_1D) { - createInfo.imageType = VK_IMAGE_TYPE_1D; - } - - result = s_Vk.createImage(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &image->handle); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, image); - return resultFromVk(result); - } - - image->belongsToSwapchain = PAL_FALSE; - image->device = vkDevice; - image->info.depthOrArraySize = info->depthOrArraySize; - image->info.type = info->type; - image->info.format = info->format; - image->info.usages = info->usages; - image->info.height = info->height; - image->info.mipLevelCount = info->mipLevelCount; - image->info.sampleCount = info->sampleCount; - image->info.width = info->width; - - image->memory = nullptr; - *outImage = (PalImage*)image; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyImageVk(PalImage* image) -{ - Image* vkImage = (Image*)image; - if (vkImage->belongsToSwapchain) { - return; - } - - s_Vk.destroyImage(vkImage->device->handle, vkImage->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkImage); -} - -PalResult PAL_CALL getImageInfoVk( - PalImage* image, - PalImageInfo* info) -{ - Image* vkImage = (Image*)image; - *info = vkImage->info; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL getImageMemoryRequirementsVk( - PalImage* image, - PalMemoryRequirements* requirements) -{ - Image* vkImage = (Image*)image; - if (vkImage->belongsToSwapchain) { - return PAL_RESULT_INVALID_OPERATION; - } - - // TODO: support only GPU memory - - Device* device = vkImage->device; - VkMemoryRequirements memReq = {0}; - s_Vk.getImageMemoryRequirements(device->handle, vkImage->handle, &memReq); - requirements->alignment = (uint64_t)memReq.alignment; - requirements->size = (uint64_t)memReq.size; - requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, 0); - - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = PAL_FALSE; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = PAL_FALSE; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = PAL_FALSE; - - for (int i = 0; i < PAL_MEMORY_TYPE_MAX; i++) { - requirements->memoryTypes[i] = (memReq.memoryTypeBits & device->memoryClassMask[i]) != 0; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL bindImageMemoryVk( - PalImage* image, - PalMemory* memory, - uint64_t offset) -{ - Image* vkImage = (Image*)image; - if (vkImage->belongsToSwapchain) { - return PAL_RESULT_INVALID_OPERATION; - } - - if (vkImage->memory) { - return PAL_RESULT_INVALID_OPERATION; - } - - Memory* vkMemory = (Memory*)memory; - s_Vk.bindImageMemory(vkImage->device->handle, vkImage->handle, vkMemory->handle, offset); - vkImage->memory = vkMemory; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL mapImageMemoryVk( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr) -{ - return PAL_RESULT_INVALID_OPERATION; -} - -void PAL_CALL unmapImageMemoryVk(PalImage* image) -{ - // do nothing. -} - -// ================================================== -// Image View -// ================================================== - -PalResult PAL_CALL createImageViewVk( - PalDevice* device, - PalImage* image, - const PalImageViewCreateInfo* info, - PalImageView** outImageView) -{ - VkResult result = VK_SUCCESS; - ImageView* imageView = nullptr; - Device* vkDevice = (Device*)device; - Image* vkImage = (Image*)image; - - if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - imageView = palAllocate(s_Vk.allocator, sizeof(ImageView), 0); - if (!imageView) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkImageViewCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.format = formatToVk(info->format); - createInfo.image = vkImage->handle; - createInfo.viewType = imageViewTypeToVk(info->type); - - createInfo.subresourceRange.aspectMask = imageAspectToVk(info->subresourceRange.aspect); - createInfo.subresourceRange.baseArrayLayer = info->subresourceRange.startArrayLayer; - createInfo.subresourceRange.baseMipLevel = info->subresourceRange.startMipLevel; - createInfo.subresourceRange.levelCount = info->subresourceRange.mipLevelCount; - createInfo.subresourceRange.layerCount = info->subresourceRange.layerArrayCount; - - result = s_Vk.createImageView( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &imageView->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, imageView); - return resultFromVk(result); - } - - imageView->device = vkDevice; - imageView->image = vkImage; - imageView->layerCount = createInfo.subresourceRange.layerCount; - - *outImageView = (PalImageView*)imageView; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyImageViewVk(PalImageView* imageView) -{ - ImageView* vkImageView = (ImageView*)imageView; - s_Vk.destroyImageView(vkImageView->device->handle, vkImageView->handle, &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, vkImageView); -} - -// ================================================== -// Sampler -// ================================================== - -PalResult PAL_CALL createSamplerVk( - PalDevice* device, - const PalSamplerCreateInfo* info, - PalSampler** outSampler) -{ - VkResult result = VK_SUCCESS; - Sampler* sampler = nullptr; - Device* vkDevice = (Device*)device; - - sampler = palAllocate(s_Vk.allocator, sizeof(Sampler), 0); - if (!sampler) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkSamplerCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - createInfo.anisotropyEnable = info->enableAnisotropy; - createInfo.compareEnable = info->enableCompare; - - createInfo.mipLodBias = info->mipLodBias; - createInfo.minLod = info->minLod; - createInfo.maxLod = info->maxLod; - createInfo.maxAnisotropy = info->maxAnisotropy; - createInfo.compareOp = compareOpToVk(info->compareOp); - - createInfo.minFilter = filterToVk(info->minFilterMode); - createInfo.magFilter = filterToVk(info->magFilterMode); - createInfo.mipmapMode = mipmapModeToVk(info->mipmapMode); - - createInfo.addressModeU = addressModeToVk(info->addressModeU); - createInfo.addressModeV = addressModeToVk(info->addressModeV); - createInfo.addressModeW = addressModeToVk(info->addressModeW); - createInfo.borderColor = borderColorToVk(info->borderColor); - - result = s_Vk.createSampler( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &sampler->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, sampler); - return resultFromVk(result); - } - - sampler->device = vkDevice; - *outSampler = (PalSampler*)sampler; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroySamplerVk(PalSampler* sampler) -{ - Sampler* vkSampler = (Sampler*)sampler; - s_Vk.destroySampler(vkSampler->device->handle, vkSampler->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkSampler); -} // ================================================== // Surface @@ -5034,7 +4556,7 @@ PalResult PAL_CALL createSurfaceVk( VkSurfaceKHR tmp = nullptr; result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } surface->device = vkDevice; @@ -5058,7 +4580,7 @@ PalResult PAL_CALL createSurfaceVk( VkSurfaceKHR tmp = nullptr; result = s_Vk.createWaylandSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } surface->device = vkDevice; @@ -5079,7 +4601,7 @@ PalResult PAL_CALL createSurfaceVk( VkSurfaceKHR tmp = nullptr; result = s_Vk.createXlibSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } surface->device = vkDevice; @@ -5099,7 +4621,7 @@ PalResult PAL_CALL createSurfaceVk( VkSurfaceKHR tmp = nullptr; result = s_Vk.createXcbSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } surface->device = vkDevice; @@ -5329,7 +4851,7 @@ PalResult PAL_CALL createSwapchainVk( if (result != VK_SUCCESS) { palFree(s_Vk.allocator, swapchain); - return resultFromVk(result); + return makeResultVk(result); } // get and cache all images @@ -5433,7 +4955,7 @@ PalResult PAL_CALL getNextSwapchainImageVk( &index); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } *outIndex = index; @@ -5464,7 +4986,7 @@ PalResult PAL_CALL presentSwapchainVk( result = vkSwapchain->device->queuePresent(vkSwapchain->queue->phyQueue->handle, &presentInfo); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } return PAL_RESULT_SUCCESS; @@ -5494,7 +5016,7 @@ PalResult PAL_CALL resizeSwapchainVk( &vkSwapchain->handle); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } uint32_t count = vkSwapchain->imageCount; @@ -5589,7 +5111,7 @@ PalResult PAL_CALL createShaderVk( result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, shader); - return resultFromVk(result); + return makeResultVk(result); } shader->device = vkDevice; @@ -5634,7 +5156,7 @@ PalResult PAL_CALL createFenceVk( result = s_Vk.createFence(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &fence->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, fence); - return resultFromVk(result); + return makeResultVk(result); } fence->device = vkDevice; @@ -5668,7 +5190,7 @@ PalResult PAL_CALL waitFenceVk( result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, PAL_TRUE, timeInNanoseconds); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } return PAL_RESULT_SUCCESS; @@ -5683,7 +5205,7 @@ PalResult PAL_CALL resetFenceVk(PalFence* fence) VkResult result = s_Vk.resetFence(vkFence->device->handle, 1, &vkFence->handle); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } return PAL_RESULT_SUCCESS; @@ -5746,7 +5268,7 @@ PalResult PAL_CALL createSemaphoreVk( if (result != VK_SUCCESS) { palFree(s_Vk.allocator, semaphore); - return resultFromVk(result); + return makeResultVk(result); } semaphore->device = vkDevice; @@ -5794,7 +5316,7 @@ PalResult PAL_CALL waitSemaphoreVk( timeInNanoseconds); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } return PAL_RESULT_SUCCESS; @@ -5818,7 +5340,7 @@ PalResult PAL_CALL signalSemaphoreVk( result = vkSemaphore->device->signalSemaphore(vkSemaphore->device->handle, &signalInfo); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } return PAL_RESULT_SUCCESS; @@ -5839,1175 +5361,10 @@ PalResult PAL_CALL getSemaphoreValueVk( outValue); if (result != VK_SUCCESS) { - return resultFromVk(result); + return makeResultVk(result); } return PAL_RESULT_SUCCESS; } -// ================================================== -// Descriptor Pool, Set and Layout -// ================================================== - -PalResult PAL_CALL createDescriptorSetLayoutVk( - PalDevice* device, - const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout) -{ - VkResult result; - Device* vkDevice = (Device*)device; - VkDescriptorSetLayoutBinding* bindings = nullptr; - VkDescriptorBindingFlags* bindingFlags = nullptr; - DescriptorSetLayout* layout = nullptr; - uint32_t count = info->bindingCount; - VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsCreateInfo = {0}; - - PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - layout = palAllocate(s_Vk.allocator, sizeof(DescriptorSetLayout), 0); - bindings = palAllocate(s_Vk.allocator, sizeof(VkDescriptorSetLayoutBinding) * count, 0); - if (!layout || !bindings) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (info->enableDescriptorIndexing) { - bindingFlags = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBindingFlags) * count, 0); - if (!bindingFlags) { - return PAL_RESULT_OUT_OF_MEMORY; - } - } - - VkDescriptorSetLayoutCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - createInfo.bindingCount = count; - createInfo.pBindings = bindings; - - VkShaderStageFlags stageFlags = 0; - for (int i = 0; i < info->shaderStageCount; i++) { - VkShaderStageFlagBits bit = shaderStageToVK(info->shaderStages[i]); - stageFlags |= bit; - } - - uint32_t bindingIndex = 0; - for (int i = 0; i < count; i++) { - VkDescriptorSetLayoutBinding* binding = &bindings[i]; - binding->binding = bindingIndex++; - binding->descriptorCount = info->bindings[i].descriptorCount; - binding->descriptorType = descriptortypeToVk(info->bindings[i].descriptorType); - - binding->pImmutableSamplers = nullptr; - binding->stageFlags = stageFlags; - if (bindingFlags) { - bindingFlags[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; - bindingFlags[i] |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; - bindingFlags[i] |= VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT; - } - } - - if (info->enableDescriptorIndexing) { - bindingFlagsCreateInfo.sType = - VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; - - bindingFlagsCreateInfo.bindingCount = count; - bindingFlagsCreateInfo.pBindingFlags = bindingFlags; - createInfo.pNext = &bindingFlagsCreateInfo; - createInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; - } - - result = s_Vk.createDescriptorSetLayout( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &layout->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, layout); - palFree(s_Vk.allocator, bindings); - return resultFromVk(result); - } - - layout->device = vkDevice; - layout->hasDescriptorIndexing = info->enableDescriptorIndexing; - palFree(s_Vk.allocator, bindings); - *outLayout = (PalDescriptorSetLayout*)layout; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout) -{ - DescriptorSetLayout* vkLayout = (DescriptorSetLayout*)layout; - s_Vk.destroyDescriptorSetLayout( - vkLayout->device->handle, - vkLayout->handle, - &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, layout); -} - -PalResult PAL_CALL createDescriptorPoolVk( - PalDevice* device, - const PalDescriptorPoolCreateInfo* info, - PalDescriptorPool** outPool) -{ - VkResult result; - Device* vkDevice = (Device*)device; - DescriptorPool* pool = nullptr; - VkDescriptorPoolSize* poolSizes = nullptr; - uint32_t maxBindings = info->maxDescriptorBindingSizes; - VkDescriptorPoolCreateInfo createInfo = {0}; - - PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (info->enableDescriptorIndexing) { - createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; - } - - pool = palAllocate(s_Vk.allocator, sizeof(DescriptorPool), 0); - poolSizes = palAllocate(s_Vk.allocator, sizeof(VkDescriptorPoolSize) * maxBindings, 0); - if (!pool || !poolSizes) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - for (int i = 0; i < maxBindings; i++) { - VkDescriptorPoolSize* poolSize = &poolSizes[i]; - poolSize->descriptorCount = info->bindingSizes[i].bindingCount; - poolSize->type = descriptortypeToVk(info->bindingSizes[i].descriptorType); - } - - createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - createInfo.maxSets = info->maxDescriptorSets; - createInfo.poolSizeCount = maxBindings; - createInfo.pPoolSizes = poolSizes; - - result = s_Vk.createDescriptorPool( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &pool->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pool); - palFree(s_Vk.allocator, poolSizes); - return resultFromVk(result); - } - - pool->device = vkDevice; - pool->hasDescriptorIndexing = info->enableDescriptorIndexing; - palFree(s_Vk.allocator, poolSizes); - *outPool = (PalDescriptorPool*)pool; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool) -{ - DescriptorPool* vkPool = (DescriptorPool*)pool; - s_Vk.destroyDescriptorPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, pool); -} - -PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool) -{ - DescriptorPool* vkPool = (DescriptorPool*)pool; - s_Vk.resetDescriptorPool(vkPool->device->handle, vkPool->handle, 0); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL allocateDescriptorSetVk( - PalDevice* device, - PalDescriptorPool* pool, - PalDescriptorSetLayout* layout, - PalDescriptorSet** outSet) -{ - VkResult result; - Device* vkDevice = (Device*)device; - DescriptorPool* vkPool = (DescriptorPool*)pool; - DescriptorSetLayout* vkLayout = (DescriptorSetLayout*)layout; - DescriptorSet* set = nullptr; - - if (vkPool->hasDescriptorIndexing != vkLayout->hasDescriptorIndexing) { - return PAL_RESULT_INVALID_OPERATION; - } - - set = palAllocate(s_Vk.allocator, sizeof(DescriptorSet), 0); - if (!set) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkDescriptorSetAllocateInfo allocateInfo = {0}; - allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocateInfo.descriptorPool = vkPool->handle; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &vkLayout->handle; - - result = s_Vk.allocateDescriptorSet(vkDevice->handle, &allocateInfo, &set->handle); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, set); - return resultFromVk(result); - } - - set->pool = vkPool; - set->device = vkDevice; - *outSet = (PalDescriptorSet*)set; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL updateDescriptorSetVk( - PalDevice* device, - uint32_t count, - PalDescriptorSetWriteInfo* infos) -{ - VkResult result; - Device* vkDevice = (Device*)device; - VkWriteDescriptorSet* writes = nullptr; - VkDescriptorBufferInfo* bufferInfos = nullptr; - VkDescriptorImageInfo* imageInfos = nullptr; - VkAccelerationStructureKHR* tlas = nullptr; - VkWriteDescriptorSetAccelerationStructureKHR* tlasInfos = nullptr; - - uint32_t bufferCount = 0; - uint32_t imageCount = 0; - uint32_t tlasCount = 0; - uint32_t tlasInfoCount = 0; - - for (int i = 0; i < count; i++) { - if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || - infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - bufferCount += infos[i].descriptorCount; - - } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - tlasCount += infos[i].descriptorCount; - tlasInfoCount++; - - } else { - imageCount += infos[i].descriptorCount; - } - } - - writes = palAllocate(s_Vk.allocator, sizeof(VkWriteDescriptorSet) * count, 0); - if (!writes) { - return PAL_RESULT_OUT_OF_MEMORY; - } - memset(writes, 0, sizeof(VkWriteDescriptorSet) * count); - - if (bufferCount) { - bufferInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBufferInfo) * bufferCount, 0); - if (!bufferInfos) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(bufferInfos, 0, sizeof(VkDescriptorBufferInfo) * bufferCount); - } - - - if (imageCount) { - imageInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorImageInfo) * imageCount, 0); - if (!imageInfos) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(imageInfos, 0, sizeof(VkDescriptorImageInfo) * imageCount); - } - - if (tlasCount) { - uint32_t tlasInfoSize = sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasInfoCount; - tlasInfos = palAllocate(s_Vk.allocator, tlasInfoSize, 0); - tlas = palAllocate(s_Vk.allocator, sizeof(VkAccelerationStructureKHR) * count, 0); - if (!tlasInfos || !tlas) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(tlasInfos, 0, tlasInfoSize); - memset(tlas, 0, sizeof(VkAccelerationStructureKHR) * tlasCount); - } - - // reset and reuse - bufferCount = 0; - imageCount = 0; - tlasCount = 0; - tlasInfoCount = 0; - - for (int i = 0; i < count; i++) { - VkWriteDescriptorSet* write = &writes[i]; - PalDescriptorSetWriteInfo* info = &infos[i]; - - write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write->dstArrayElement = info->arrayElement; - write->dstBinding = info->layoutBindingIndex; - write->descriptorCount = info->descriptorCount; - write->descriptorType = descriptortypeToVk(info->descriptorType); - - DescriptorSet* set = (DescriptorSet*)info->descriptorSet; - write->dstSet = set->handle; - - for (int j = 0; j < write->descriptorCount; j++) { - if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || - info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - VkDescriptorBufferInfo* bufferInfo = &bufferInfos[bufferCount + j]; - - if (info->bufferInfos) { - PalDescriptorBufferInfo* tmp = &info->bufferInfos[j]; - Buffer* vkBuffer = (Buffer*)tmp->buffer; - - bufferInfo->buffer = vkBuffer->handle; - bufferInfo->offset = tmp->offset; - bufferInfo->range = tmp->size; - - } else { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - if (info->tlasInfos) { - PalDescriptorTLASInfo* tmp = &info->tlasInfos[j]; - AccelerationStructure* as = (AccelerationStructure*)tmp->tlas; - tlas[tlasCount + j] = as->handle; - - } else { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - } else { - VkDescriptorImageInfo* imageInfo = &imageInfos[imageCount + j]; - - if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { - if (info->samplerInfos) { - PalDescriptorSamplerInfo* tmp = &info->samplerInfos[j]; - Sampler* vkSampler = (Sampler*)tmp->sampler; - imageInfo->sampler = vkSampler->handle; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - } else { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - if (info->imageViewInfos) { - PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; - ImageView* vkImageView = (ImageView*)tmp->imageView; - - imageInfo->sampler = nullptr; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo->imageView = vkImageView->handle; - - } else { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - if (info->imageViewInfos) { - PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; - ImageView* vkImageView = (ImageView*)tmp->imageView; - - imageInfo->sampler = nullptr; - imageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo->imageView = vkImageView->handle; - - } else { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - } - } - } - - if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || - info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - write->pBufferInfo = &bufferInfos[bufferCount]; - bufferCount += write->descriptorCount; - - } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - VkWriteDescriptorSetAccelerationStructureKHR* tlasInfo = &tlasInfos[tlasInfoCount]; - tlasInfo->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; - tlasInfo->accelerationStructureCount = info->descriptorCount; - tlasInfo->pAccelerationStructures = &tlas[tlasCount]; - - write->pNext = &tlasInfos[tlasInfoCount++]; - tlasCount += write->descriptorCount; - - } else { - write->pImageInfo = &imageInfos[imageCount]; - imageCount += write->descriptorCount; - } - } - - s_Vk.updateDescriptorSet(vkDevice->handle, count, writes, 0, nullptr); - palFree(s_Vk.allocator, writes); - palFree(s_Vk.allocator, bufferInfos); - palFree(s_Vk.allocator, imageInfos); - palFree(s_Vk.allocator, tlasInfos); - palFree(s_Vk.allocator, tlas); - - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Pipeline Layout -// ================================================== - -PalResult PAL_CALL createPipelineLayoutVk( - PalDevice* device, - const PalPipelineLayoutCreateInfo* info, - PalPipelineLayout** outLayout) -{ - VkResult result; - Device* vkDevice = (Device*)device; - PipelineLayout* layout = nullptr; - VkPushConstantRange* pushConstants = nullptr; - VkDescriptorSetLayout* descriptorLayouts = nullptr; - uint32_t pushConstantSize = sizeof(VkPushConstantRange) * info->pushConstantRangeCount; - uint32_t setLayoutSize = sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount; - - layout = palAllocate(s_Vk.allocator, sizeof(PipelineLayout), 0); - pushConstants = palAllocate(s_Vk.allocator, pushConstantSize, 0); - descriptorLayouts = palAllocate(s_Vk.allocator, setLayoutSize, 0); - if (!layout || !pushConstants || !descriptorLayouts) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - for (int i = 0; i < info->descriptorSetLayoutCount; i++) { - DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; - descriptorLayouts[i] = tmp->handle; - } - - for (int i = 0; i < info->pushConstantRangeCount; i++) { - VkPushConstantRange* range = &pushConstants[i]; - range->offset = info->pushConstantRanges[i].offset; - range->size = info->pushConstantRanges[i].size; - range->stageFlags = 0; - - range->offset = info->pushConstantRanges[i].offset; - for (int j = 0; j < info->pushConstantRanges[i].shaderStageCount; j++) { - VkShaderStageFlags bit = shaderStageToVK(info->pushConstantRanges[i].shaderStages[j]); - range->stageFlags |= bit; - } - } - - VkPipelineLayoutCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - createInfo.setLayoutCount = info->descriptorSetLayoutCount; - createInfo.pSetLayouts = descriptorLayouts; - createInfo.pPushConstantRanges = pushConstants; - createInfo.pushConstantRangeCount = info->pushConstantRangeCount; - - result = s_Vk.createPipelineLayout( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &layout->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, descriptorLayouts); - palFree(s_Vk.allocator, pushConstants); - palFree(s_Vk.allocator, layout); - return resultFromVk(result); - } - - palFree(s_Vk.allocator, descriptorLayouts); - palFree(s_Vk.allocator, pushConstants); - layout->device = vkDevice; - *outLayout = (PalPipelineLayout*)layout; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout) -{ - PipelineLayout* pipelineLayout = (PipelineLayout*)layout; - s_Vk.destroyPipelineLayout( - pipelineLayout->device->handle, - pipelineLayout->handle, - &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, layout); -} - -// ================================================== -// Pipeline -// ================================================== - -PalResult PAL_CALL createGraphicsPipelineVk( - PalDevice* device, - const PalGraphicsPipelineCreateInfo* info, - PalPipeline** outPipeline) -{ - VkResult result; - Pipeline* pipeline = nullptr; - Device* vkDevice = (Device*)device; - PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - - VkPipelineShaderStageCreateInfo* shaderStages = nullptr; - VkDynamicState dynamicStates[16]; - VkVertexInputBindingDescription* bindingDescs = nullptr; - VkVertexInputAttributeDescription* attribDescs = nullptr; - VkPipelineColorBlendAttachmentState* blendattachments = nullptr; - - VkPipelineVertexInputStateCreateInfo vertexInputState = {0}; - vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {0}; - inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - - VkPipelineDynamicStateCreateInfo dynamicState = {0}; - dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - - VkPipelineRasterizationStateCreateInfo rasterizerState = {0}; - rasterizerState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - - VkPipelineMultisampleStateCreateInfo multisampleState = {0}; - multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - - VkPipelineDepthStencilStateCreateInfo depthStencilState = {0}; - depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - - VkPipelineColorBlendStateCreateInfo colorBlendState = {0}; - colorBlendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - - VkPipelineTessellationStateCreateInfo tessellationState = {0}; - tessellationState.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - - VkPipelineViewportStateCreateInfo viewportState = {0}; - viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - - VkPipelineFragmentShadingRateStateCreateInfoKHR fsrState = {0}; - fsrState.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; - - VkPipelineRenderingCreateInfoKHR dynRendering = {0}; - dynRendering.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR; - - VkGraphicsPipelineCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - createInfo.renderPass = VK_NULL_HANDLE; - createInfo.layout = layout->handle; - - // find the total number of shader stages - uint32_t stageCount = 0; - for (int i = 0; i < info->shaderCount; i++) { - Shader* shader = (Shader*)info->shaders[i]; - stageCount += shader->entryCount; - } - - pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); - shaderStages = palAllocate( - s_Vk.allocator, - sizeof(VkPipelineShaderStageCreateInfo) * stageCount, - 0); - - if (!pipeline || !shaderStages) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // shaders - uint32_t stageIndex = 0; - memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stageCount); - for (int i = 0; i < info->shaderCount; i++) { - Shader* tmp = (Shader*)info->shaders[i]; - - for (int j = 0; j < tmp->entryCount; j++) { - ShaderEntry* entry = &tmp->entries[j]; - VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex++]; - - if (entry->patchControlPoints) { - tessellationState.patchControlPoints = entry->patchControlPoints; - createInfo.pTessellationState = &tessellationState; - - if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { - palFree(s_Vk.allocator, pipeline); - return PAL_RESULT_INVALID_OPERATION; - } - } - - stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo->module = tmp->handle; - stageInfo->pName = entry->entryName; - stageInfo->stage = entry->stage; - } - } - - createInfo.stageCount = stageCount; - createInfo.pStages = shaderStages; - - // Vertex input state - // get the max size of vertex attributes in all layouts - uint32_t vertexCount = 0; - for (int i = 0; i < info->vertexLayoutCount; i++) { - PalVertexLayout* layout = &info->vertexLayouts[i]; - vertexCount += layout->attributeCount; - } - - if (vertexCount) { - uint32_t tmpBindingSize = sizeof(VkVertexInputBindingDescription) * info->vertexLayoutCount; - uint32_t tmpAttribSize = sizeof(VkVertexInputAttributeDescription) * vertexCount; - bindingDescs = palAllocate(s_Vk.allocator, tmpBindingSize, 0); - attribDescs = palAllocate(s_Vk.allocator, tmpAttribSize, 0); - if (!bindingDescs || !attribDescs) { - palFree(s_Vk.allocator, pipeline); - return PAL_RESULT_OUT_OF_MEMORY; - } - - uint32_t location = 0; - for (int i = 0; i < info->vertexLayoutCount; i++) { - PalVertexLayout* layout = &info->vertexLayouts[i]; - VkVertexInputBindingDescription* bindingDesc = &bindingDescs[i]; - - bindingDesc->binding = layout->binding; - if (layout->type == PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE) { - bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; - } else { - bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - } - - // find the stride and offset of the layout - bindingDesc->stride = 0; - uint32_t offset = 0; - for (int j = 0; j < layout->attributeCount; j++) { - PalVertexAttribute* vertexAttrib = &layout->attributes[j]; - VkVertexInputAttributeDescription* attribDesc = &attribDescs[j]; - - attribDesc->format = vertexTypeToVk(vertexAttrib->type); - attribDesc->binding = bindingDesc->binding; - attribDesc->location = location++; - - // build offsets and stride - uint32_t size = getVertexTypeSizeVk(vertexAttrib->type); - attribDesc->offset = offset; - offset += size; - bindingDesc->stride += size; - } - } - - vertexInputState.pVertexAttributeDescriptions = attribDescs; - vertexInputState.vertexAttributeDescriptionCount = vertexCount; - vertexInputState.pVertexBindingDescriptions = bindingDescs; - vertexInputState.vertexBindingDescriptionCount = info->vertexLayoutCount; - } - createInfo.pVertexInputState = &vertexInputState; - - // Input assembly - VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - switch (info->topology) { - case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { - topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { - topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_LINE_LIST: { - topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP: { - topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_POINT_LIST: { - topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; - break; - } - } - inputAssemblyState.topology = topology; - inputAssemblyState.primitiveRestartEnable = info->primitiveRestartEnable; - createInfo.pInputAssemblyState = &inputAssemblyState; - - // Dynamic states - uint32_t dynCount = 0; - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_VIEWPORT; - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_SCISSOR; - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_LINE_WIDTH; - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS; - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_BIAS; - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; - - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_CULL_MODE_EXT; - } - - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_FRONT_FACE_EXT; - } - - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT; - } - - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT; - } - - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT; - } - - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_STENCIL_OP_EXT; - } - - if (info->fragmentShadingRateState) { - dynamicStates[dynCount++] = VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR; - } - - dynamicState.dynamicStateCount = dynCount; - dynamicState.pDynamicStates = dynamicStates; - createInfo.pDynamicState = &dynamicState; - - // Rasterizer state - rasterizerState.frontFace = VK_FRONT_FACE_CLOCKWISE; - if (info->rasterizerState) { - PalRasterizerState* state = info->rasterizerState; - if (state->cullMode == PAL_CULL_MODE_NONE) { - rasterizerState.cullMode = VK_CULL_MODE_NONE; - - } else if (state->cullMode == PAL_CULL_MODE_BACK) { - rasterizerState.cullMode = VK_CULL_MODE_BACK_BIT; - - } else if (state->cullMode == PAL_CULL_MODE_FRONT) { - rasterizerState.cullMode = VK_CULL_MODE_FRONT_BIT; - } - - if (state->polygonMode == PAL_POLYGON_MODE_FILL) { - rasterizerState.polygonMode = VK_POLYGON_MODE_FILL; - - } else { - rasterizerState.polygonMode = VK_POLYGON_MODE_LINE; - } - - if (state->frontFace == PAL_FRONT_FACE_CLOCKWISE) { - rasterizerState.frontFace = VK_FRONT_FACE_CLOCKWISE; - - } else { - rasterizerState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - } - - rasterizerState.depthBiasEnable = state->enableDepthBias; - rasterizerState.depthClampEnable = state->enableDepthClamp; - rasterizerState.depthBiasConstantFactor = state->depthBiasConstant; - rasterizerState.depthBiasSlopeFactor = state->depthBiasSlope; - rasterizerState.depthBiasClamp = state->depthBiasClamp; - } - - rasterizerState.lineWidth = 1.0f; - createInfo.pRasterizationState = &rasterizerState; - - // Multisample state - uint32_t sampleMask[2] = {0}; // PAL supports upto 64 samples - multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampleState.pSampleMask = nullptr; - if (info->multisampleState) { - PalMultisampleState* state = info->multisampleState; - multisampleState.alphaToCoverageEnable = state->enableAlphaToCoverage; - multisampleState.minSampleShading = state->minSampleShading; - multisampleState.sampleShadingEnable = state->enableSampleShading; - multisampleState.rasterizationSamples = samplesToVk(state->sampleCount); - - // clang-format off - if (state->sampleMask) { - if (state->sampleCount == PAL_SAMPLE_COUNT_1 || - state->sampleCount == PAL_SAMPLE_COUNT_2 || - state->sampleCount == PAL_SAMPLE_COUNT_4 || - state->sampleCount == PAL_SAMPLE_COUNT_8 || - state->sampleCount == PAL_SAMPLE_COUNT_16 || - state->sampleCount == PAL_SAMPLE_COUNT_32) { - sampleMask[0] = (uint32_t)(state->sampleMask & 0xFFFFFFFFULL); - - } else { - sampleMask[0] = (uint32_t)(state->sampleMask & 0xFFFFFFFFULL); - sampleMask[1] = (uint32_t)((state->sampleMask >> 32) & 0xFFFFFFFFULL); - } - multisampleState.pSampleMask = sampleMask; - - } else { - multisampleState.pSampleMask = nullptr; - } - // clang-format on - } - createInfo.pMultisampleState = &multisampleState; - - // Depth stencil state - if (info->depthStencilState) { - PalDepthStencilState* state = info->depthStencilState; - PalStencilOpState* back = &state->backStencilOpState; - PalStencilOpState* front = &state->frontStencilOpState; - - VkStencilOpState* vkBack = &depthStencilState.back; - VkStencilOpState* vkFront = &depthStencilState.front; - - vkBack->compareOp = compareOpToVk(back->compareOp); - vkBack->depthFailOp = stencilOpToVk(back->depthFailOp); - vkBack->failOp = stencilOpToVk(back->failOp); - vkBack->passOp = stencilOpToVk(back->passOp); - - vkFront->compareOp = compareOpToVk(front->compareOp); - vkFront->depthFailOp = stencilOpToVk(front->depthFailOp); - vkFront->failOp = stencilOpToVk(front->failOp); - vkFront->passOp = stencilOpToVk(front->passOp); - - depthStencilState.depthCompareOp = compareOpToVk(state->compareOp); - depthStencilState.depthTestEnable = state->enableDepthTest; - depthStencilState.depthWriteEnable = state->enableDepthWrite; - depthStencilState.stencilTestEnable = state->enableStencilTest; - } - createInfo.pDepthStencilState = &depthStencilState; - - // Color blend state - if (info->colorBlendAttachmentCount) { - uint32_t count = info->colorBlendAttachmentCount; - uint32_t size = sizeof(VkPipelineColorBlendAttachmentState) * count; - blendattachments = palAllocate(s_Vk.allocator, size, 0); - if (!blendattachments) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - for (int i = 0; i < count; i++) { - VkPipelineColorBlendAttachmentState* tmp = &blendattachments[i]; - PalColorBlendAttachment* desc = &info->colorBlendAttachments[i]; - - tmp->blendEnable = desc->enableBlend; - tmp->alphaBlendOp = blendOpToVk(desc->alphaBlendOp); - tmp->colorBlendOp = blendOpToVk(desc->colorBlendOp); - - tmp->srcAlphaBlendFactor = blendFactorToVk(desc->srcAlphaBlendFactor); - tmp->srcColorBlendFactor = blendFactorToVk(desc->srcColorBlendFactor); - - tmp->dstAlphaBlendFactor = blendFactorToVk(desc->dstAlphaBlendFactor); - tmp->dstColorBlendFactor = blendFactorToVk(desc->dstColorBlendFactor); - - // blend color write mask - tmp->colorWriteMask = 0; - if (desc->colorWriteMask & PAL_COLOR_MASK_RED) { - tmp->colorWriteMask |= VK_COLOR_COMPONENT_R_BIT; - } - - if (desc->colorWriteMask & PAL_COLOR_MASK_GREEN) { - tmp->colorWriteMask |= VK_COLOR_COMPONENT_G_BIT; - } - - if (desc->colorWriteMask & PAL_COLOR_MASK_BLUE) { - tmp->colorWriteMask |= VK_COLOR_COMPONENT_B_BIT; - } - - if (desc->colorWriteMask & PAL_COLOR_MASK_ALPHA) { - tmp->colorWriteMask |= VK_COLOR_COMPONENT_A_BIT; - } - } - - colorBlendState.attachmentCount = count; - colorBlendState.pAttachments = blendattachments; - } - createInfo.pColorBlendState = &colorBlendState; - - // viewport state - viewportState.viewportCount = 1; - viewportState.scissorCount = 1; - createInfo.pViewportState = &viewportState; - - // Fragment shading rate - if (info->fragmentShadingRateState) { - PalFragmentShadingRateState* state = info->fragmentShadingRateState; - for (int i = 0; i < 2; i++) { - VkFragmentShadingRateCombinerOpKHR combinerOp; - combinerOp = combinerOpsToVk(state->combinerOps[i]); - fsrState.combinerOps[i] = combinerOp; - } - - VkExtent2D size = getShadingRateSizeVk(state->rate); - fsrState.fragmentSize = size; - createInfo.pNext = &fsrState; - } - - // layout info - VkFormat format = VK_FORMAT_UNDEFINED; - VkFormat colorAttachments[MAX_ATTACHMENTS]; - PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; - - // color attachments - for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { - format = formatToVk(renderingLayout->colorAttachmentsFormat[i]); - colorAttachments[i] = format; - } - dynRendering.colorAttachmentCount = renderingLayout->colorAttachentCount; - dynRendering.pColorAttachmentFormats = colorAttachments; - - // depth stencil attachment - format = formatToVk(renderingLayout->depthStencilAttachmentFormat); - dynRendering.depthAttachmentFormat = format; - dynRendering.stencilAttachmentFormat = format; - - if (renderingLayout->viewCount == 1) { - dynRendering.viewMask = 0; - } else { - dynRendering.viewMask = (1 << renderingLayout->viewCount) - 1; - } - createInfo.pNext = &dynRendering; - - result = s_Vk.createGraphicsPipeline( - vkDevice->handle, - 0, - 1, - &createInfo, - &s_Vk.vkAllocator, - &pipeline->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - return resultFromVk(result); - } - - palFree(s_Vk.allocator, shaderStages); - if (info->vertexLayoutCount) { - palFree(s_Vk.allocator, bindingDescs); - palFree(s_Vk.allocator, attribDescs); - } - - if (info->colorBlendAttachmentCount) { - palFree(s_Vk.allocator, blendattachments); - } - - pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - pipeline->device = vkDevice; - pipeline->layout = layout->handle; - *outPipeline = (PalPipeline*)pipeline; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL createComputePipelineVk( - PalDevice* device, - const PalComputePipelineCreateInfo* info, - PalPipeline** outPipeline) -{ - Device* vkDevice = (Device*)device; - PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - Shader* shader = (Shader*)info->computeShader; - Pipeline* pipeline = nullptr; - - pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); - if (!pipeline) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkComputePipelineCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; - createInfo.layout = layout->handle; - - createInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - createInfo.stage.module = shader->handle; - createInfo.stage.stage = shader->entries[0].stage; - createInfo.stage.pName = shader->entries[0].entryName; - - VkResult result = s_Vk.createComputePipeline( - vkDevice->handle, - nullptr, - 1, - &createInfo, - &s_Vk.vkAllocator, - &pipeline->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - return resultFromVk(result); - } - - pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; - pipeline->device = vkDevice; - pipeline->layout = layout->handle; - *outPipeline = (PalPipeline*)pipeline; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL createRayTracingPipelineVk( - PalDevice* device, - const PalRayTracingPipelineCreateInfo* info, - PalPipeline** outPipeline) -{ - VkResult result; - Device* vkDevice = (Device*)device; - PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - Pipeline* pipeline = nullptr; - VkPipelineShaderStageCreateInfo* shaderStages = nullptr; - VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; - - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (info->maxPayloadSize > vkDevice->limits.maxPayloadSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - VkRayTracingPipelineCreateInfoKHR createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; - - // find the total number of shader stages - uint32_t stageCount = 0; - for (int i = 0; i < info->shaderCount; i++) { - Shader* shader = (Shader*)info->shaders[i]; - stageCount += shader->entryCount; - } - - pipeline = palAllocate(s_Vk.allocator, sizeof(Pipeline), 0); - groups = palAllocate( - s_Vk.allocator, - sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount, - 0); - - shaderStages = palAllocate( - s_Vk.allocator, - sizeof(VkPipelineShaderStageCreateInfo) * stageCount, - 0); - - if (!pipeline || !groups || !shaderStages) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(pipeline, 0, sizeof(Pipeline)); - - // shaders - uint32_t stageIndex = 0; - memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stageCount); - for (int i = 0; i < info->shaderCount; i++) { - Shader* tmp = (Shader*)info->shaders[i]; - - for (int j = 0; j < tmp->entryCount; j++) { - ShaderEntry* entry = &tmp->entries[j]; - VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex++]; - - stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - stageInfo->module = tmp->handle; - stageInfo->pName = entry->entryName; - stageInfo->stage = entry->stage; - } - } - - createInfo.stageCount = stageCount; - createInfo.pStages = shaderStages; - - ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; - for (int i = 0; i < info->shaderGroupCount; i++) { - VkRayTracingShaderGroupCreateInfoKHR* group = &groups[i]; - PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; - - group->sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; - group->pShaderGroupCaptureReplayHandle = nullptr; - group->pNext = nullptr; - - if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { - // check if its raygen, miss or callable - Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; - ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; - - switch (entry->stage) { - case VK_SHADER_STAGE_RAYGEN_BIT_KHR: { - sbtInfo->raygenCount++; - sbtInfo->raygenDataSize = maxVk(sbtInfo->raygenDataSize, tmp->maxDataSize); - break; - } - - case VK_SHADER_STAGE_MISS_BIT_KHR: { - sbtInfo->missCount++; - sbtInfo->missDataSize = maxVk(sbtInfo->missDataSize, tmp->maxDataSize); - break; - } - - case VK_SHADER_STAGE_CALLABLE_BIT_KHR: { - sbtInfo->callableCount++; - sbtInfo->callableDataSize = maxVk(sbtInfo->callableDataSize, tmp->maxDataSize); - break; - } - } - - group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; - group->generalShader = tmp->generalShaderEntryIndex; - group->anyHitShader = VK_SHADER_UNUSED_KHR; - group->closestHitShader = VK_SHADER_UNUSED_KHR; - group->intersectionShader = VK_SHADER_UNUSED_KHR; - - } else { - sbtInfo->hitCount++; - sbtInfo->hitDataSize = maxVk(sbtInfo->hitDataSize, tmp->maxDataSize); - - group->generalShader = VK_SHADER_UNUSED_KHR; - if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - group->anyHitShader = tmp->anyHitShaderEntryIndex; - - } else { - group->anyHitShader = VK_SHADER_UNUSED_KHR; - } - - if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - group->closestHitShader = tmp->closestHitShaderEntryIndex; - - } else { - group->closestHitShader = VK_SHADER_UNUSED_KHR; - } - - if (tmp->intersectionShaderIndex!= PAL_UNUSED_SHADER_INDEX) { - group->intersectionShader = tmp->intersectionShaderEntryIndex; - - } else { - group->intersectionShader = VK_SHADER_UNUSED_KHR; - } - - if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { - group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; - - } else { - group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; - } - } - } - - createInfo.pGroups = groups; - createInfo.groupCount = info->shaderGroupCount; - createInfo.maxPipelineRayRecursionDepth = info->maxRecursionDepth; - createInfo.layout = layout->handle; - - result = vkDevice->createRayTracingPipeline( - vkDevice->handle, - nullptr, - nullptr, - 1, - &createInfo, - &s_Vk.vkAllocator, - &pipeline->handle); - - palFree(s_Vk.allocator, groups); - palFree(s_Vk.allocator, shaderStages); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, pipeline); - return resultFromVk(result); - } - - pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; - pipeline->device = vkDevice; - pipeline->layout = layout->handle; - *outPipeline = (PalPipeline*)pipeline; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) -{ - Pipeline* vkPipeline = (Pipeline*)pipeline; - s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, pipeline); -} - #endif // PAL_HAS_VULKAN_BACKEND diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c index c572f5f9..668662dc 100644 --- a/src/graphics/vulkan/pal_commands_vulkan.c +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -8,8 +8,6 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" -#define MAX_ATTACHMENTS 32 - static void commitShaderbindingTableUpdate( CommandBufferVk* cmdBuffer, ShaderBindingTableVk* sbt) diff --git a/src/graphics/vulkan/pal_descriptors_vulkan.c b/src/graphics/vulkan/pal_descriptors_vulkan.c index 2857f1d7..c71ea6dc 100644 --- a/src/graphics/vulkan/pal_descriptors_vulkan.c +++ b/src/graphics/vulkan/pal_descriptors_vulkan.c @@ -8,4 +8,414 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" +PalResult PAL_CALL createDescriptorSetLayoutVk( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout) +{ + VkResult result; + DeviceVk* vkDevice = (DeviceVk*)device; + VkDescriptorSetLayoutBinding* bindings = nullptr; + VkDescriptorBindingFlags* bindingFlags = nullptr; + DescriptorSetLayoutVk* layout = nullptr; + uint32_t count = info->bindingCount; + VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flagsCreateInfo = {0}; + flagsCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; + + PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + if (info->descriptorIndexingFlags != 0 && hasDescriptorIndexing) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + layout = palAllocate(s_Vk.allocator, sizeof(DescriptorSetLayoutVk), 0); + bindings = palAllocate(s_Vk.allocator, sizeof(VkDescriptorSetLayoutBinding) * count, 0); + if (!layout || !bindings) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + if (info->descriptorIndexingFlags != 0) { + bindingFlags = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBindingFlags) * count, 0); + if (!bindingFlags) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + } + + VkDescriptorSetLayoutCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + createInfo.bindingCount = count; + createInfo.pBindings = bindings; + + uint32_t bindingIndex = 0; + for (int i = 0; i < count; i++) { + VkDescriptorSetLayoutBinding* binding = &bindings[i]; + binding->binding = bindingIndex++; + binding->descriptorCount = info->bindings[i].descriptorCount; + binding->descriptorType = descriptortypeToVk(info->bindings[i].descriptorType); + + binding->pImmutableSamplers = nullptr; + binding->stageFlags = vkDevice->shaderStages; + + // set descriptor indexing flags + if (info->descriptorIndexingFlags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND) { + bindingFlags[i] |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; + bindingFlags[i] |= VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT; + } + + if (info->descriptorIndexingFlags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { + bindingFlags[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; + } + } + + if (info->descriptorIndexingFlags != 0) { + flagsCreateInfo.bindingCount = count; + flagsCreateInfo.pBindingFlags = bindingFlags; + createInfo.pNext = &flagsCreateInfo; + createInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; + } + + result = s_Vk.createDescriptorSetLayout( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &layout->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, layout); + palFree(s_Vk.allocator, bindings); + return makeResultVk(result); + } + + palFree(s_Vk.allocator, bindings); + + layout->device = vkDevice; + layout->flags = info->descriptorIndexingFlags; + layout->reserved = PAL_BACKEND_KEY; + *outLayout = (PalDescriptorSetLayout*)layout; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout) +{ + DescriptorSetLayoutVk* vkLayout = (DescriptorSetLayoutVk*)layout; + s_Vk.destroyDescriptorSetLayout( + vkLayout->device->handle, + vkLayout->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, layout); +} + +PalResult PAL_CALL createDescriptorPoolVk( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool) +{ + VkResult result; + DeviceVk* vkDevice = (DeviceVk*)device; + DescriptorPoolVk* pool = nullptr; + VkDescriptorPoolSize* poolSizes = nullptr; + uint32_t bindingSizeCount = info->bindingSizeCount; + VkDescriptorPoolCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + + PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + if (info->descriptorIndexingFlags != 0 && hasDescriptorIndexing) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (info->descriptorIndexingFlags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { + createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; + } + + pool = palAllocate(s_Vk.allocator, sizeof(DescriptorPoolVk), 0); + poolSizes = palAllocate(s_Vk.allocator, sizeof(VkDescriptorPoolSize) * bindingSizeCount, 0); + if (!pool || !poolSizes) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + for (int i = 0; i < bindingSizeCount; i++) { + VkDescriptorPoolSize* poolSize = &poolSizes[i]; + poolSize->descriptorCount = info->bindingSizes[i].bindingCount; + poolSize->type = descriptortypeToVk(info->bindingSizes[i].descriptorType); + } + + createInfo.maxSets = info->maxDescriptorSets; + createInfo.poolSizeCount = bindingSizeCount; + createInfo.pPoolSizes = poolSizes; + + result = s_Vk.createDescriptorPool( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &pool->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pool); + palFree(s_Vk.allocator, poolSizes); + return makeResultVk(result); + } + + palFree(s_Vk.allocator, poolSizes); + pool->device = vkDevice; + pool->flags = info->descriptorIndexingFlags; + pool->reserved = PAL_BACKEND_KEY; + *outPool = (PalDescriptorPool*)pool; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool) +{ + DescriptorPoolVk* vkPool = (DescriptorPoolVk*)pool; + s_Vk.destroyDescriptorPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, pool); +} + +PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool) +{ + DescriptorPoolVk* vkPool = (DescriptorPoolVk*)pool; + s_Vk.resetDescriptorPool(vkPool->device->handle, vkPool->handle, 0); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL allocateDescriptorSetVk( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet) +{ + VkResult result; + DeviceVk* vkDevice = (DeviceVk*)device; + DescriptorPoolVk* vkPool = (DescriptorPoolVk*)pool; + DescriptorSetLayoutVk* vkLayout = (DescriptorSetLayoutVk*)layout; + DescriptorSetVk* set = nullptr; + + PalBool isPoolValid = vkPool->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; + PalBool isLayoutValid = vkLayout->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; + if (isPoolValid != isLayoutValid) { + // we check if both are true or false + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + set = palAllocate(s_Vk.allocator, sizeof(DescriptorSetVk), 0); + if (!set) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkDescriptorSetAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocateInfo.descriptorPool = vkPool->handle; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &vkLayout->handle; + + result = s_Vk.allocateDescriptorSet(vkDevice->handle, &allocateInfo, &set->handle); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, set); + return makeResultVk(result); + } + + set->pool = vkPool; + set->device = vkDevice; + set->reserved = PAL_BACKEND_KEY; + *outSet = (PalDescriptorSet*)set; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL updateDescriptorSetVk( + PalDevice* device, + uint32_t count, + PalDescriptorSetWriteInfo* infos) +{ + VkResult result; + DeviceVk* vkDevice = (DeviceVk*)device; + VkWriteDescriptorSet* writes = nullptr; + VkDescriptorBufferInfo* bufferInfos = nullptr; + VkDescriptorImageInfo* imageInfos = nullptr; + VkAccelerationStructureKHR* tlas = nullptr; + VkWriteDescriptorSetAccelerationStructureKHR* tlasInfos = nullptr; + + uint32_t bufferCount = 0; + uint32_t imageCount = 0; + uint32_t tlasCount = 0; + uint32_t tlasInfoCount = 0; + + for (int i = 0; i < count; i++) { + if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || + infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + bufferCount += infos[i].descriptorCount; + + } else if (infos[i].descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + tlasCount += infos[i].descriptorCount; + tlasInfoCount++; + + } else { + imageCount += infos[i].descriptorCount; + } + } + + writes = palAllocate(s_Vk.allocator, sizeof(VkWriteDescriptorSet) * count, 0); + if (!writes) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + memset(writes, 0, sizeof(VkWriteDescriptorSet) * count); + + if (bufferCount) { + bufferInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBufferInfo) * bufferCount, 0); + if (!bufferInfos) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(bufferInfos, 0, sizeof(VkDescriptorBufferInfo) * bufferCount); + } + + + if (imageCount) { + imageInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorImageInfo) * imageCount, 0); + if (!imageInfos) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(imageInfos, 0, sizeof(VkDescriptorImageInfo) * imageCount); + } + + if (tlasCount) { + uint32_t tlasInfoSize = sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasInfoCount; + tlasInfos = palAllocate(s_Vk.allocator, tlasInfoSize, 0); + tlas = palAllocate(s_Vk.allocator, sizeof(VkAccelerationStructureKHR) * count, 0); + if (!tlasInfos || !tlas) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(tlasInfos, 0, tlasInfoSize); + memset(tlas, 0, sizeof(VkAccelerationStructureKHR) * tlasCount); + } + + // reset and reuse + bufferCount = 0; + imageCount = 0; + tlasCount = 0; + tlasInfoCount = 0; + + for (int i = 0; i < count; i++) { + VkWriteDescriptorSet* write = &writes[i]; + PalDescriptorSetWriteInfo* info = &infos[i]; + + write->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write->dstArrayElement = info->arrayElement; + write->dstBinding = info->layoutBindingIndex; + write->descriptorCount = info->descriptorCount; + write->descriptorType = descriptortypeToVk(info->descriptorType); + + DescriptorSetVk* set = (DescriptorSetVk*)info->descriptorSet; + write->dstSet = set->handle; + + for (int j = 0; j < write->descriptorCount; j++) { + if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || + info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + VkDescriptorBufferInfo* bufferInfo = &bufferInfos[bufferCount + j]; + + if (info->bufferInfos) { + PalDescriptorBufferInfo* tmp = &info->bufferInfos[j]; + BufferVk* vkBuffer = (BufferVk*)tmp->buffer; + + bufferInfo->buffer = vkBuffer->handle; + bufferInfo->offset = tmp->offset; + bufferInfo->range = tmp->size; + + } else { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + if (info->tlasInfos) { + PalDescriptorTLASInfo* tmp = &info->tlasInfos[j]; + AccelerationStructureVk* as = (AccelerationStructureVk*)tmp->tlas; + tlas[tlasCount + j] = as->handle; + + } else { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + } else { + VkDescriptorImageInfo* imageInfo = &imageInfos[imageCount + j]; + + if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { + if (info->samplerInfos) { + PalDescriptorSamplerInfo* tmp = &info->samplerInfos[j]; + SamplerVk* vkSampler = (SamplerVk*)tmp->sampler; + imageInfo->sampler = vkSampler->handle; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + } else { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { + if (info->imageViewInfos) { + PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; + ImageViewVk* vkImageView = (ImageViewVk*)tmp->imageView; + + imageInfo->sampler = nullptr; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; + imageInfo->imageView = vkImageView->handle; + + } else { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + if (info->imageViewInfos) { + PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; + ImageViewVk* vkImageView = (ImageViewVk*)tmp->imageView; + + imageInfo->sampler = nullptr; + imageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo->imageView = vkImageView->handle; + + } else { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + } + } + } + + if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER || + info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + write->pBufferInfo = &bufferInfos[bufferCount]; + bufferCount += write->descriptorCount; + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + VkWriteDescriptorSetAccelerationStructureKHR* tlasInfo = &tlasInfos[tlasInfoCount]; + tlasInfo->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; + tlasInfo->accelerationStructureCount = info->descriptorCount; + tlasInfo->pAccelerationStructures = &tlas[tlasCount]; + + write->pNext = &tlasInfos[tlasInfoCount++]; + tlasCount += write->descriptorCount; + + } else { + write->pImageInfo = &imageInfos[imageCount]; + imageCount += write->descriptorCount; + } + } + + s_Vk.updateDescriptorSet(vkDevice->handle, count, writes, 0, nullptr); + palFree(s_Vk.allocator, writes); + palFree(s_Vk.allocator, bufferInfos); + palFree(s_Vk.allocator, imageInfos); + palFree(s_Vk.allocator, tlasInfos); + palFree(s_Vk.allocator, tlas); + + return PAL_RESULT_SUCCESS; +} + #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_image_vulkan.c b/src/graphics/vulkan/pal_image_vulkan.c index 2857f1d7..f86e4ce4 100644 --- a/src/graphics/vulkan/pal_image_vulkan.c +++ b/src/graphics/vulkan/pal_image_vulkan.c @@ -8,4 +8,330 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" +static VkImageUsageFlags imageUsageToVk(PalImageUsages usages) +{ + VkImageUsageFlags flags = 0; + if (usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { + flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + + if (usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { + flags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } + + if (usages & PAL_IMAGE_USAGE_TRANSFER_SRC) { + flags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } + + if (usages & PAL_IMAGE_USAGE_TRANSFER_DST) { + flags |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + + if (usages & PAL_IMAGE_USAGE_STORAGE) { + flags |= VK_IMAGE_USAGE_STORAGE_BIT; + } + + if (usages & PAL_IMAGE_USAGE_SAMPLED) { + flags |= VK_IMAGE_USAGE_SAMPLED_BIT; + } + + return flags; +} + +PalResult PAL_CALL createImageVk( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage) +{ + VkResult result; + ImageVk* image = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + + image = palAllocate(s_Vk.allocator, sizeof(ImageVk), 0); + if (!image) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkImageCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + createInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + createInfo.extent.width = info->width; + createInfo.extent.height = info->height; + createInfo.extent.depth = info->depth; + + createInfo.arrayLayers = info->arrayLayerCount; + createInfo.mipLevels = info->mipLevelCount; + createInfo.format = formatToVk(info->format); + createInfo.samples = samplesToVk(info->sampleCount); + createInfo.usage = imageUsageToVk(info->usages); + + createInfo.imageType = VK_IMAGE_TYPE_2D; + if (info->type == PAL_IMAGE_TYPE_3D) { + createInfo.imageType = VK_IMAGE_TYPE_3D; + + } else if (info->type == PAL_IMAGE_TYPE_1D) { + createInfo.imageType = VK_IMAGE_TYPE_1D; + } + + result = s_Vk.createImage(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &image->handle); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, image); + return makeResultVk(result); + } + + image->memory = nullptr; + image->isMemoryManaged = PAL_FALSE; + if (info->memoryUsage != PAL_IMAGE_MEMORY_USAGE_MANUAL) { + PalMemoryType memoryType = PAL_MEMORY_TYPE_GPU_ONLY; + + // allocate and manage memory + VkMemoryRequirements memReq = {0}; + s_Vk.getImageMemoryRequirements(vkDevice->handle, image->handle, &memReq); + + VkMemoryAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = (VkDeviceSize)memReq.size; + + uint32_t memoryMask = vkDevice->memoryClassMask[memoryType] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, memoryMask); + if (!(memoryMask & (1u << memoryIndex))) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + + allocateInfo.memoryTypeIndex = memoryIndex; + VkDeviceMemory memory = nullptr; + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &memory); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + image->isMemoryManaged = PAL_TRUE; + image->memory = (MemoryVk*)memory; + } + + image->device = vkDevice; + image->info.type = info->type; + image->info.format = info->format; + image->info.usages = info->usages; + image->info.height = info->height; + image->info.mipLevelCount = info->mipLevelCount; + image->info.sampleCount = info->sampleCount; + image->info.width = info->width; + image->info.depth = info->depth; + image->info.arrayLayerCount = info->arrayLayerCount; + image->info.belongsToSwapcchain = PAL_FALSE; + + image->reserved = PAL_BACKEND_KEY; + *outImage = (PalImage*)image; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyImageVk(PalImage* image) +{ + ImageVk* vkImage = (ImageVk*)image; + if (vkImage->info.belongsToSwapcchain) { + return; + } + + s_Vk.destroyImage(vkImage->device->handle, vkImage->handle, &s_Vk.vkAllocator); + if (vkImage->isMemoryManaged) { + VkDeviceMemory memory = (VkDeviceMemory)vkImage->memory; + s_Vk.freeMemory(vkImage->device->handle, memory, &s_Vk.vkAllocator); + } + + palFree(s_Vk.allocator, vkImage); +} + +PalResult PAL_CALL getImageInfoVk( + PalImage* image, + PalImageInfo* info) +{ + ImageVk* vkImage = (ImageVk*)image; + *info = vkImage->info; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL getImageMemoryRequirementsVk( + PalImage* image, + PalMemoryRequirements* requirements) +{ + ImageVk* vkImage = (ImageVk*)image; + if (vkImage->info.belongsToSwapcchain) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + DeviceVk* device = vkImage->device; + VkMemoryRequirements memReq = {0}; + s_Vk.getImageMemoryRequirements(device->handle, vkImage->handle, &memReq); + requirements->alignment = (uint64_t)memReq.alignment; + requirements->size = (uint64_t)memReq.size; + requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, 0); + requirements->supportedMemoryTypes = 0; + + if ((memReq.memoryTypeBits & device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY]) != 0) { + requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL bindImageMemoryVk( + PalImage* image, + PalMemory* memory, + uint64_t offset) +{ + ImageVk* vkImage = (ImageVk*)image; + if (vkImage->info.belongsToSwapcchain) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + if (vkImage->memory) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + MemoryVk* vkMemory = (MemoryVk*)memory; + s_Vk.bindImageMemory(vkImage->device->handle, vkImage->handle, vkMemory->handle, offset); + vkImage->memory = vkMemory; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL mapImageMemoryVk( + PalImage* image, + uint64_t offset, + uint64_t size, + void** outPtr) +{ + return PAL_RESULT_CODE_INVALID_OPERATION; +} + +void PAL_CALL unmapImageMemoryVk(PalImage* image) +{ + // do nothing. +} + +PalResult PAL_CALL createImageViewVk( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView) +{ + VkResult result = VK_SUCCESS; + ImageViewVk* imageView = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + ImageVk* vkImage = (ImageVk*)image; + + if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + imageView = palAllocate(s_Vk.allocator, sizeof(ImageViewVk), 0); + if (!imageView) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkImageViewCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.format = formatToVk(info->format); + createInfo.image = vkImage->handle; + createInfo.viewType = imageViewTypeToVk(info->type); + + createInfo.subresourceRange.aspectMask = imageAspectToVk(info->subresourceRange.aspect); + createInfo.subresourceRange.baseArrayLayer = info->subresourceRange.startArrayLayer; + createInfo.subresourceRange.baseMipLevel = info->subresourceRange.startMipLevel; + createInfo.subresourceRange.levelCount = info->subresourceRange.mipLevelCount; + createInfo.subresourceRange.layerCount = info->subresourceRange.layerArrayCount; + + result = s_Vk.createImageView( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &imageView->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, imageView); + return makeResultVk(result); + } + + imageView->device = vkDevice; + imageView->image = vkImage; + imageView->layerCount = createInfo.subresourceRange.layerCount; + imageView->reserved = PAL_BACKEND_KEY; + *outImageView = (PalImageView*)imageView; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyImageViewVk(PalImageView* imageView) +{ + ImageViewVk* vkImageView = (ImageViewVk*)imageView; + s_Vk.destroyImageView(vkImageView->device->handle, vkImageView->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkImageView); +} + +PalResult PAL_CALL createSamplerVk( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler) +{ + VkResult result = VK_SUCCESS; + SamplerVk* sampler = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + + sampler = palAllocate(s_Vk.allocator, sizeof(SamplerVk), 0); + if (!sampler) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkSamplerCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + createInfo.anisotropyEnable = info->enableAnisotropy; + createInfo.compareEnable = info->enableCompare; + + createInfo.mipLodBias = info->mipLodBias; + createInfo.minLod = info->minLod; + createInfo.maxLod = info->maxLod; + createInfo.maxAnisotropy = info->maxAnisotropy; + createInfo.compareOp = compareOpToVk(info->compareOp); + + createInfo.minFilter = filterToVk(info->minFilterMode); + createInfo.magFilter = filterToVk(info->magFilterMode); + createInfo.mipmapMode = mipmapModeToVk(info->mipmapMode); + + createInfo.addressModeU = addressModeToVk(info->addressModeU); + createInfo.addressModeV = addressModeToVk(info->addressModeV); + createInfo.addressModeW = addressModeToVk(info->addressModeW); + createInfo.borderColor = borderColorToVk(info->borderColor); + + result = s_Vk.createSampler( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &sampler->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, sampler); + return makeResultVk(result); + } + + sampler->device = vkDevice; + sampler->reserved = PAL_BACKEND_KEY; + *outSampler = (PalSampler*)sampler; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroySamplerVk(PalSampler* sampler) +{ + SamplerVk* vkSampler = (SamplerVk*)sampler; + s_Vk.destroySampler(vkSampler->device->handle, vkSampler->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkSampler); +} + #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_pipeline_vulkan.c b/src/graphics/vulkan/pal_pipeline_vulkan.c index 2857f1d7..a6e4b673 100644 --- a/src/graphics/vulkan/pal_pipeline_vulkan.c +++ b/src/graphics/vulkan/pal_pipeline_vulkan.c @@ -8,4 +8,939 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" +static VkPipelineStageFlags2 pipelineStageToVk(VkShaderStageFlagBits stage) +{ + switch (stage) { + case VK_SHADER_STAGE_VERTEX_BIT: + return VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT; + + case VK_SHADER_STAGE_FRAGMENT_BIT: + return VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; + + case VK_SHADER_STAGE_COMPUTE_BIT: + return VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + + case VK_SHADER_STAGE_GEOMETRY_BIT: + return VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT; + + case VK_SHADER_STAGE_MESH_BIT_EXT: + return VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT; + + case VK_SHADER_STAGE_TASK_BIT_EXT: + return VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT; + + case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: + return VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT; + + case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: + return VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT; + + case VK_SHADER_STAGE_RAYGEN_BIT_KHR: + case VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR: + case VK_SHADER_STAGE_ANY_HIT_BIT_KHR: + case VK_SHADER_STAGE_MISS_BIT_KHR: + case VK_SHADER_STAGE_INTERSECTION_BIT_KHR: + case VK_SHADER_STAGE_CALLABLE_BIT_KHR: { + return VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; + } + } + return 0; +} + +static VkBlendOp blendOpToVk(PalBlendOp op) +{ + switch (op) { + case PAL_BLEND_OP_ADD: + return VK_BLEND_OP_ADD; + + case PAL_BLEND_OP_SUBTRACT: + return VK_BLEND_OP_SUBTRACT; + + case PAL_BLEND_OP_REVERSE_SUBTRACT: + return VK_BLEND_OP_REVERSE_SUBTRACT; + + case PAL_BLEND_OP_MIN: + return VK_BLEND_OP_MIN; + + case PAL_BLEND_OP_MAX: + return VK_BLEND_OP_MAX; + } + + return VK_BLEND_OP_ADD; +} + +static VkBlendFactor blendFactorToVk(PalBlendFactor op) +{ + switch (op) { + case PAL_BLEND_FACTOR_ZERO: + return VK_BLEND_FACTOR_ZERO; + + case PAL_BLEND_FACTOR_ONE: + return VK_BLEND_FACTOR_ONE; + + case PAL_BLEND_FACTOR_SRC_COLOR: + return VK_BLEND_FACTOR_SRC_COLOR; + + case PAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: + return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; + + case PAL_BLEND_FACTOR_DST_COLOR: + return VK_BLEND_FACTOR_DST_COLOR; + + case PAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR: + return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; + + case PAL_BLEND_FACTOR_SRC_ALPHA: + return VK_BLEND_FACTOR_SRC_ALPHA; + + case PAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: + return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; + + case PAL_BLEND_FACTOR_DST_ALPHA: + return VK_BLEND_FACTOR_DST_ALPHA; + + case PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: + return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; + + case PAL_BLEND_FACTOR_CONSTANT_COLOR: + return VK_BLEND_FACTOR_CONSTANT_COLOR; + + case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR: + return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; + + case PAL_BLEND_FACTOR_CONSTANT_ALPHA: + return VK_BLEND_FACTOR_CONSTANT_ALPHA; + + case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: + return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA; + } + + return VK_BLEND_FACTOR_ZERO; +} + +static VkFragmentShadingRateCombinerOpKHR combinerOpsToVk(PalFragmentShadingRateCombinerOp op) +{ + switch (op) { + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR; + } + + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; +} + +static uint32_t getVertexTypeSizeVk(PalVertexType type) +{ + // count x sizeof type returned as size + switch (type) { + case PAL_VERTEX_TYPE_INT8_2: + case PAL_VERTEX_TYPE_UINT8_2: + case PAL_VERTEX_TYPE_INT8_2NORM: + case PAL_VERTEX_TYPE_UINT8_2NORM: { + return 2; + } + + case PAL_VERTEX_TYPE_INT32: + case PAL_VERTEX_TYPE_UINT32: + case PAL_VERTEX_TYPE_INT8_4: + case PAL_VERTEX_TYPE_INT8_4NORM: + case PAL_VERTEX_TYPE_UINT8_4: + case PAL_VERTEX_TYPE_UINT8_4NORM: + case PAL_VERTEX_TYPE_INT16_2NORM: + case PAL_VERTEX_TYPE_INT16_2: + case PAL_VERTEX_TYPE_UINT16_2: + case PAL_VERTEX_TYPE_UINT16_2NORM: + case PAL_VERTEX_TYPE_FLOAT: + case PAL_VERTEX_TYPE_HALF_FLOAT16_2: { + return 4; + } + + case PAL_VERTEX_TYPE_INT32_2: + case PAL_VERTEX_TYPE_UINT32_2: + case PAL_VERTEX_TYPE_INT16_4: + case PAL_VERTEX_TYPE_UINT16_4: + case PAL_VERTEX_TYPE_UINT16_4NORM: + case PAL_VERTEX_TYPE_INT16_4NORM: + case PAL_VERTEX_TYPE_FLOAT2: + case PAL_VERTEX_TYPE_HALF_FLOAT16_4: { + return 8; + } + + case PAL_VERTEX_TYPE_INT32_3: + case PAL_VERTEX_TYPE_UINT32_3: + case PAL_VERTEX_TYPE_FLOAT3: { + return 12; + } + + case PAL_VERTEX_TYPE_INT32_4: + case PAL_VERTEX_TYPE_UINT32_4: + case PAL_VERTEX_TYPE_FLOAT4: { + return 16; + } + } + + return 0; +} + +PalResult PAL_CALL createPipelineLayoutVk( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout) +{ + VkResult result; + DeviceVk* vkDevice = (DeviceVk*)device; + PipelineLayoutVk* layout = nullptr; + VkPushConstantRange* pushConstants = nullptr; + VkDescriptorSetLayout* descriptorLayouts = nullptr; + uint32_t pushConstantSize = sizeof(VkPushConstantRange) * info->pushConstantRangeCount; + uint32_t setLayoutSize = sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount; + + layout = palAllocate(s_Vk.allocator, sizeof(PipelineLayoutVk), 0); + pushConstants = palAllocate(s_Vk.allocator, pushConstantSize, 0); + descriptorLayouts = palAllocate(s_Vk.allocator, setLayoutSize, 0); + if (!layout || !pushConstants || !descriptorLayouts) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + for (int i = 0; i < info->descriptorSetLayoutCount; i++) { + DescriptorSetLayoutVk* tmp = (DescriptorSetLayoutVk*)info->descriptorSetLayouts[i]; + descriptorLayouts[i] = tmp->handle; + } + + for (int i = 0; i < info->pushConstantRangeCount; i++) { + VkPushConstantRange* range = &pushConstants[i]; + range->offset = info->pushConstantRanges[i].offset; + range->size = info->pushConstantRanges[i].size; + range->stageFlags = vkDevice->shaderStages; + range->offset = info->pushConstantRanges[i].offset; + } + + VkPipelineLayoutCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + createInfo.setLayoutCount = info->descriptorSetLayoutCount; + createInfo.pSetLayouts = descriptorLayouts; + createInfo.pPushConstantRanges = pushConstants; + createInfo.pushConstantRangeCount = info->pushConstantRangeCount; + + result = s_Vk.createPipelineLayout( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &layout->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, descriptorLayouts); + palFree(s_Vk.allocator, pushConstants); + palFree(s_Vk.allocator, layout); + return makeResultVk(result); + } + + palFree(s_Vk.allocator, descriptorLayouts); + palFree(s_Vk.allocator, pushConstants); + + layout->device = vkDevice; + layout->reserved = PAL_BACKEND_KEY; + *outLayout = (PalPipelineLayout*)layout; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout) +{ + PipelineLayoutVk* pipelineLayout = (PipelineLayoutVk*)layout; + s_Vk.destroyPipelineLayout( + pipelineLayout->device->handle, + pipelineLayout->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, layout); +} + +PalResult PAL_CALL createGraphicsPipelineVk( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + VkResult result; + PipelineVk* pipeline = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + PipelineLayoutVk* layout = (PipelineLayoutVk*)info->pipelineLayout; + + VkPipelineShaderStageCreateInfo* shaderStages = nullptr; + VkDynamicState dynamicStates[16]; + VkVertexInputBindingDescription* bindingDescs = nullptr; + VkVertexInputAttributeDescription* attribDescs = nullptr; + VkPipelineColorBlendAttachmentState* blendattachments = nullptr; + + VkPipelineVertexInputStateCreateInfo vertexInputState = {0}; + vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {0}; + inputAssemblyState.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + + VkPipelineDynamicStateCreateInfo dynamicState = {0}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + + VkPipelineRasterizationStateCreateInfo rasterizerState = {0}; + rasterizerState.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + + VkPipelineMultisampleStateCreateInfo multisampleState = {0}; + multisampleState.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + + VkPipelineDepthStencilStateCreateInfo depthStencilState = {0}; + depthStencilState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + + VkPipelineColorBlendStateCreateInfo colorBlendState = {0}; + colorBlendState.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + + VkPipelineTessellationStateCreateInfo tessellationState = {0}; + tessellationState.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + + VkPipelineViewportStateCreateInfo viewportState = {0}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + + VkPipelineFragmentShadingRateStateCreateInfoKHR fsrState = {0}; + fsrState.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR; + + VkPipelineRenderingCreateInfoKHR dynRendering = {0}; + dynRendering.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR; + + VkGraphicsPipelineCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + createInfo.renderPass = VK_NULL_HANDLE; + createInfo.layout = layout->handle; + + // find the total number of shader stages + uint32_t stageCount = 0; + for (int i = 0; i < info->shaderCount; i++) { + ShaderVk* shader = (ShaderVk*)info->shaders[i]; + stageCount += shader->entryCount; + } + + pipeline = palAllocate(s_Vk.allocator, sizeof(PipelineVk), 0); + shaderStages = palAllocate( + s_Vk.allocator, + sizeof(VkPipelineShaderStageCreateInfo) * stageCount, + 0); + + if (!pipeline || !shaderStages) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + // shaders + uint32_t stageIndex = 0; + pipeline->stages = VK_PIPELINE_STAGE_2_NONE; + memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stageCount); + for (int i = 0; i < info->shaderCount; i++) { + ShaderVk* tmp = (ShaderVk*)info->shaders[i]; + + for (int j = 0; j < tmp->entryCount; j++) { + ShaderEntry* entry = &tmp->entries[j]; + VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex++]; + + if (entry->patchControlPoints) { + tessellationState.patchControlPoints = entry->patchControlPoints; + createInfo.pTessellationState = &tessellationState; + + if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { + palFree(s_Vk.allocator, pipeline); + return PAL_RESULT_CODE_INVALID_OPERATION; + } + } + + stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageInfo->module = tmp->handle; + stageInfo->pName = entry->entryName; + stageInfo->stage = entry->stage; + pipeline->stages |= pipelineStageToVk(entry->stage); + } + } + + createInfo.stageCount = stageCount; + createInfo.pStages = shaderStages; + + // Vertex input state + // get the max size of vertex attributes in all layouts + uint32_t vertexCount = 0; + for (int i = 0; i < info->vertexLayoutCount; i++) { + PalVertexLayout* layout = &info->vertexLayouts[i]; + vertexCount += layout->attributeCount; + } + + if (vertexCount) { + uint32_t tmpBindingSize = sizeof(VkVertexInputBindingDescription) * info->vertexLayoutCount; + uint32_t tmpAttribSize = sizeof(VkVertexInputAttributeDescription) * vertexCount; + bindingDescs = palAllocate(s_Vk.allocator, tmpBindingSize, 0); + attribDescs = palAllocate(s_Vk.allocator, tmpAttribSize, 0); + if (!bindingDescs || !attribDescs) { + palFree(s_Vk.allocator, pipeline); + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + uint32_t location = 0; + for (int i = 0; i < info->vertexLayoutCount; i++) { + PalVertexLayout* layout = &info->vertexLayouts[i]; + VkVertexInputBindingDescription* bindingDesc = &bindingDescs[i]; + + bindingDesc->binding = layout->binding; + if (layout->type == PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE) { + bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; + } else { + bindingDesc->inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + } + + // find the stride and offset of the layout + bindingDesc->stride = 0; + uint32_t offset = 0; + for (int j = 0; j < layout->attributeCount; j++) { + PalVertexAttribute* vertexAttrib = &layout->attributes[j]; + VkVertexInputAttributeDescription* attribDesc = &attribDescs[j]; + + attribDesc->format = vertexTypeToVk(vertexAttrib->type); + attribDesc->binding = bindingDesc->binding; + attribDesc->location = location++; + + // build offsets and stride + uint32_t size = getVertexTypeSizeVk(vertexAttrib->type); + attribDesc->offset = offset; + offset += size; + bindingDesc->stride += size; + } + } + + vertexInputState.pVertexAttributeDescriptions = attribDescs; + vertexInputState.vertexAttributeDescriptionCount = vertexCount; + vertexInputState.pVertexBindingDescriptions = bindingDescs; + vertexInputState.vertexBindingDescriptionCount = info->vertexLayoutCount; + } + createInfo.pVertexInputState = &vertexInputState; + + // Input assembly + VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + switch (info->topology) { + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { + topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { + topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_LIST: { + topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP: { + topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_POINT_LIST: { + topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + break; + } + } + inputAssemblyState.topology = topology; + inputAssemblyState.primitiveRestartEnable = info->primitiveRestartEnable; + createInfo.pInputAssemblyState = &inputAssemblyState; + + // Dynamic states + uint32_t dynCount = 0; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_VIEWPORT; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_SCISSOR; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_LINE_WIDTH; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_BIAS; + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_CULL_MODE_EXT; + } + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_FRONT_FACE_EXT; + } + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT; + } + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT; + } + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT; + } + + if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_STENCIL_OP_EXT; + } + + if (info->fragmentShadingRateState) { + dynamicStates[dynCount++] = VK_DYNAMIC_STATE_FRAGMENT_SHADING_RATE_KHR; + } + + dynamicState.dynamicStateCount = dynCount; + dynamicState.pDynamicStates = dynamicStates; + createInfo.pDynamicState = &dynamicState; + + // Rasterizer state + rasterizerState.frontFace = VK_FRONT_FACE_CLOCKWISE; + if (info->rasterizerState) { + PalRasterizerState* state = info->rasterizerState; + if (state->cullMode == PAL_CULL_MODE_NONE) { + rasterizerState.cullMode = VK_CULL_MODE_NONE; + + } else if (state->cullMode == PAL_CULL_MODE_BACK) { + rasterizerState.cullMode = VK_CULL_MODE_BACK_BIT; + + } else if (state->cullMode == PAL_CULL_MODE_FRONT) { + rasterizerState.cullMode = VK_CULL_MODE_FRONT_BIT; + } + + if (state->polygonMode == PAL_POLYGON_MODE_FILL) { + rasterizerState.polygonMode = VK_POLYGON_MODE_FILL; + + } else { + rasterizerState.polygonMode = VK_POLYGON_MODE_LINE; + } + + if (state->frontFace == PAL_FRONT_FACE_CLOCKWISE) { + rasterizerState.frontFace = VK_FRONT_FACE_CLOCKWISE; + + } else { + rasterizerState.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + } + + rasterizerState.depthBiasEnable = state->enableDepthBias; + rasterizerState.depthClampEnable = state->enableDepthClamp; + rasterizerState.depthBiasConstantFactor = state->depthBiasConstant; + rasterizerState.depthBiasSlopeFactor = state->depthBiasSlope; + rasterizerState.depthBiasClamp = state->depthBiasClamp; + } + + rasterizerState.lineWidth = 1.0f; + createInfo.pRasterizationState = &rasterizerState; + + // Multisample state + uint32_t sampleMask[2] = {0}; // PAL supports upto 64 samples + multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampleState.pSampleMask = nullptr; + if (info->multisampleState) { + PalMultisampleState* state = info->multisampleState; + multisampleState.alphaToCoverageEnable = state->enableAlphaToCoverage; + multisampleState.minSampleShading = state->minSampleShading; + multisampleState.sampleShadingEnable = state->enableSampleShading; + multisampleState.rasterizationSamples = samplesToVk(state->sampleCount); + + // clang-format off + if (state->sampleMask) { + if (state->sampleCount == PAL_SAMPLE_COUNT_1 || + state->sampleCount == PAL_SAMPLE_COUNT_2 || + state->sampleCount == PAL_SAMPLE_COUNT_4 || + state->sampleCount == PAL_SAMPLE_COUNT_8 || + state->sampleCount == PAL_SAMPLE_COUNT_16 || + state->sampleCount == PAL_SAMPLE_COUNT_32) { + sampleMask[0] = (uint32_t)(state->sampleMask & 0xFFFFFFFFULL); + + } else { + sampleMask[0] = (uint32_t)(state->sampleMask & 0xFFFFFFFFULL); + sampleMask[1] = (uint32_t)((state->sampleMask >> 32) & 0xFFFFFFFFULL); + } + multisampleState.pSampleMask = sampleMask; + + } else { + multisampleState.pSampleMask = nullptr; + } + // clang-format on + } + createInfo.pMultisampleState = &multisampleState; + + // Depth stencil state + if (info->depthStencilState) { + PalDepthStencilState* state = info->depthStencilState; + PalStencilOpState* back = &state->backStencilOpState; + PalStencilOpState* front = &state->frontStencilOpState; + + VkStencilOpState* vkBack = &depthStencilState.back; + VkStencilOpState* vkFront = &depthStencilState.front; + + vkBack->compareOp = compareOpToVk(back->compareOp); + vkBack->depthFailOp = stencilOpToVk(back->depthFailOp); + vkBack->failOp = stencilOpToVk(back->failOp); + vkBack->passOp = stencilOpToVk(back->passOp); + + vkFront->compareOp = compareOpToVk(front->compareOp); + vkFront->depthFailOp = stencilOpToVk(front->depthFailOp); + vkFront->failOp = stencilOpToVk(front->failOp); + vkFront->passOp = stencilOpToVk(front->passOp); + + depthStencilState.depthCompareOp = compareOpToVk(state->compareOp); + depthStencilState.depthTestEnable = state->enableDepthTest; + depthStencilState.depthWriteEnable = state->enableDepthWrite; + depthStencilState.stencilTestEnable = state->enableStencilTest; + } + createInfo.pDepthStencilState = &depthStencilState; + + // Color blend state + if (info->colorBlendAttachmentCount) { + uint32_t count = info->colorBlendAttachmentCount; + uint32_t size = sizeof(VkPipelineColorBlendAttachmentState) * count; + blendattachments = palAllocate(s_Vk.allocator, size, 0); + if (!blendattachments) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + for (int i = 0; i < count; i++) { + VkPipelineColorBlendAttachmentState* tmp = &blendattachments[i]; + PalColorBlendAttachment* desc = &info->colorBlendAttachments[i]; + + tmp->blendEnable = desc->enableBlend; + tmp->alphaBlendOp = blendOpToVk(desc->alphaBlendOp); + tmp->colorBlendOp = blendOpToVk(desc->colorBlendOp); + + tmp->srcAlphaBlendFactor = blendFactorToVk(desc->srcAlphaBlendFactor); + tmp->srcColorBlendFactor = blendFactorToVk(desc->srcColorBlendFactor); + + tmp->dstAlphaBlendFactor = blendFactorToVk(desc->dstAlphaBlendFactor); + tmp->dstColorBlendFactor = blendFactorToVk(desc->dstColorBlendFactor); + + // blend color write mask + tmp->colorWriteMask = 0; + if (desc->colorWriteMask & PAL_COLOR_MASK_RED) { + tmp->colorWriteMask |= VK_COLOR_COMPONENT_R_BIT; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_GREEN) { + tmp->colorWriteMask |= VK_COLOR_COMPONENT_G_BIT; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_BLUE) { + tmp->colorWriteMask |= VK_COLOR_COMPONENT_B_BIT; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_ALPHA) { + tmp->colorWriteMask |= VK_COLOR_COMPONENT_A_BIT; + } + } + + colorBlendState.attachmentCount = count; + colorBlendState.pAttachments = blendattachments; + } + createInfo.pColorBlendState = &colorBlendState; + + // viewport state + viewportState.viewportCount = 1; + viewportState.scissorCount = 1; + createInfo.pViewportState = &viewportState; + + // Fragment shading rate + if (info->fragmentShadingRateState) { + PalFragmentShadingRateState* state = info->fragmentShadingRateState; + for (int i = 0; i < 2; i++) { + VkFragmentShadingRateCombinerOpKHR combinerOp; + combinerOp = combinerOpsToVk(state->combinerOps[i]); + fsrState.combinerOps[i] = combinerOp; + } + + VkExtent2D size = getShadingRateSizeVk(state->rate); + fsrState.fragmentSize = size; + createInfo.pNext = &fsrState; + } + + // layout info + VkFormat format = VK_FORMAT_UNDEFINED; + VkFormat colorAttachments[MAX_ATTACHMENTS]; + PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; + + // color attachments + for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { + format = formatToVk(renderingLayout->colorAttachmentsFormat[i]); + colorAttachments[i] = format; + } + dynRendering.colorAttachmentCount = renderingLayout->colorAttachentCount; + dynRendering.pColorAttachmentFormats = colorAttachments; + + // depth stencil attachment + format = formatToVk(renderingLayout->depthStencilAttachmentFormat); + dynRendering.depthAttachmentFormat = format; + dynRendering.stencilAttachmentFormat = format; + + if (renderingLayout->viewCount == 1) { + dynRendering.viewMask = 0; + } else { + dynRendering.viewMask = (1 << renderingLayout->viewCount) - 1; + } + createInfo.pNext = &dynRendering; + + result = s_Vk.createGraphicsPipeline( + vkDevice->handle, + 0, + 1, + &createInfo, + &s_Vk.vkAllocator, + &pipeline->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + return makeResultVk(result); + } + + palFree(s_Vk.allocator, shaderStages); + if (info->vertexLayoutCount) { + palFree(s_Vk.allocator, bindingDescs); + palFree(s_Vk.allocator, attribDescs); + } + + if (info->colorBlendAttachmentCount) { + palFree(s_Vk.allocator, blendattachments); + } + + pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + pipeline->device = vkDevice; + pipeline->layout = layout->handle; + pipeline->reserved = PAL_BACKEND_KEY; + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL createComputePipelineVk( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + PipelineLayoutVk* layout = (PipelineLayoutVk*)info->pipelineLayout; + ShaderVk* shader = (ShaderVk*)info->computeShader; + PipelineVk* pipeline = nullptr; + + pipeline = palAllocate(s_Vk.allocator, sizeof(PipelineVk), 0); + if (!pipeline) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkComputePipelineCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + createInfo.layout = layout->handle; + + createInfo.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + createInfo.stage.module = shader->handle; + createInfo.stage.stage = shader->entries[0].stage; + createInfo.stage.pName = shader->entries[0].entryName; + + VkResult result = s_Vk.createComputePipeline( + vkDevice->handle, + nullptr, + 1, + &createInfo, + &s_Vk.vkAllocator, + &pipeline->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + return makeResultVk(result); + } + + pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; + pipeline->device = vkDevice; + pipeline->layout = layout->handle; + pipeline->stages = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + pipeline->reserved = PAL_BACKEND_KEY; + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL createRayTracingPipelineVk( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + VkResult result; + DeviceVk* vkDevice = (DeviceVk*)device; + PipelineLayoutVk* layout = (PipelineLayoutVk*)info->pipelineLayout; + PipelineVk* pipeline = nullptr; + VkPipelineShaderStageCreateInfo* shaderStages = nullptr; + VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (info->maxPayloadSize > vkDevice->limits.maxPayloadSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + VkRayTracingPipelineCreateInfoKHR createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR; + + // find the total number of shader stages + uint32_t stageCount = 0; + for (int i = 0; i < info->shaderCount; i++) { + ShaderVk* shader = (ShaderVk*)info->shaders[i]; + stageCount += shader->entryCount; + } + + pipeline = palAllocate(s_Vk.allocator, sizeof(PipelineVk), 0); + groups = palAllocate( + s_Vk.allocator, + sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount, + 0); + + shaderStages = palAllocate( + s_Vk.allocator, + sizeof(VkPipelineShaderStageCreateInfo) * stageCount, + 0); + + if (!pipeline || !groups || !shaderStages) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(pipeline, 0, sizeof(PipelineVk)); + + // shaders + uint32_t stageIndex = 0; + pipeline->stages = VK_PIPELINE_STAGE_2_NONE; + memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stageCount); + for (int i = 0; i < info->shaderCount; i++) { + ShaderVk* tmp = (ShaderVk*)info->shaders[i]; + + for (int j = 0; j < tmp->entryCount; j++) { + ShaderEntry* entry = &tmp->entries[j]; + VkPipelineShaderStageCreateInfo* stageInfo = &shaderStages[stageIndex++]; + + stageInfo->sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageInfo->module = tmp->handle; + stageInfo->pName = entry->entryName; + stageInfo->stage = entry->stage; + pipeline->stages |= pipelineStageToVk(entry->stage); + } + } + + createInfo.stageCount = stageCount; + createInfo.pStages = shaderStages; + + ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; + for (int i = 0; i < info->shaderGroupCount; i++) { + VkRayTracingShaderGroupCreateInfoKHR* group = &groups[i]; + PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; + + group->sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR; + group->pShaderGroupCaptureReplayHandle = nullptr; + group->pNext = nullptr; + + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { + // check if its raygen, miss or callable + ShaderVk* shader = (ShaderVk*)info->shaders[tmp->generalShaderIndex]; + ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; + + switch (entry->stage) { + case VK_SHADER_STAGE_RAYGEN_BIT_KHR: { + sbtInfo->raygenCount++; + sbtInfo->raygenDataSize = maxVk(sbtInfo->raygenDataSize, tmp->maxDataSize); + break; + } + + case VK_SHADER_STAGE_MISS_BIT_KHR: { + sbtInfo->missCount++; + sbtInfo->missDataSize = maxVk(sbtInfo->missDataSize, tmp->maxDataSize); + break; + } + + case VK_SHADER_STAGE_CALLABLE_BIT_KHR: { + sbtInfo->callableCount++; + sbtInfo->callableDataSize = maxVk(sbtInfo->callableDataSize, tmp->maxDataSize); + break; + } + } + + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR; + group->generalShader = tmp->generalShaderEntryIndex; + group->anyHitShader = VK_SHADER_UNUSED_KHR; + group->closestHitShader = VK_SHADER_UNUSED_KHR; + group->intersectionShader = VK_SHADER_UNUSED_KHR; + + } else { + sbtInfo->hitCount++; + sbtInfo->hitDataSize = maxVk(sbtInfo->hitDataSize, tmp->maxDataSize); + + group->generalShader = VK_SHADER_UNUSED_KHR; + if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { + group->anyHitShader = tmp->anyHitShaderEntryIndex; + + } else { + group->anyHitShader = VK_SHADER_UNUSED_KHR; + } + + if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { + group->closestHitShader = tmp->closestHitShaderEntryIndex; + + } else { + group->closestHitShader = VK_SHADER_UNUSED_KHR; + } + + if (tmp->intersectionShaderIndex!= PAL_UNUSED_SHADER_INDEX) { + group->intersectionShader = tmp->intersectionShaderEntryIndex; + + } else { + group->intersectionShader = VK_SHADER_UNUSED_KHR; + } + + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR; + + } else { + group->type = VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR; + } + } + } + + createInfo.pGroups = groups; + createInfo.groupCount = info->shaderGroupCount; + createInfo.maxPipelineRayRecursionDepth = info->maxRecursionDepth; + createInfo.layout = layout->handle; + + result = vkDevice->createRayTracingPipeline( + vkDevice->handle, + nullptr, + nullptr, + 1, + &createInfo, + &s_Vk.vkAllocator, + &pipeline->handle); + + palFree(s_Vk.allocator, groups); + palFree(s_Vk.allocator, shaderStages); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, pipeline); + return makeResultVk(result); + } + + pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; + pipeline->device = vkDevice; + pipeline->layout = layout->handle; + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) +{ + PipelineVk* vkPipeline = (PipelineVk*)pipeline; + s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, pipeline); +} + #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h index 410c8e7e..e80dae58 100644 --- a/src/graphics/vulkan/pal_vulkan.h +++ b/src/graphics/vulkan/pal_vulkan.h @@ -12,6 +12,8 @@ #include "pal/pal_graphics.h" #include +#define MAX_ATTACHMENTS 32 + typedef struct _XDisplay Display; typedef unsigned long Window; typedef struct xcb_connection_t xcb_connection_t; @@ -136,6 +138,7 @@ typedef struct { VkDevice handle; PhysicalQueue* phyQueues; PFN_vkGetBufferDeviceAddress getBufferrAddress; + VkShaderStageFlags shaderStages; PFN_vkCmdDispatchBase cmdDispatchBase; // draw indirect @@ -205,6 +208,7 @@ typedef struct { typedef struct { void* reserved; + PalBool isMemoryManaged; DeviceVk* device; MemoryVk* memory; VkImage handle; @@ -328,7 +332,6 @@ typedef struct { void* reserved; VkPipelineBindPoint bindPoint; VkPipelineStageFlags2 stages; - VkShaderStageFlags shaderStages; DeviceVk* device; VkPipeline handle; VkPipelineLayout layout; @@ -473,7 +476,9 @@ VkImageAspectFlags imageAspectToVk(PalImageAspect aspect); Barrier barrierToVk(PalUsageState state); VkStencilOp stencilOpToVk(PalStencilOp op); VkCompareOp compareOpToVk(PalCompareOp op); + VkRenderingFlags renderingFlagToVk(PalRenderingFlags flags); +VkFormat vertexTypeToVk(PalVertexType type); uint32_t findBestMemoryIndexVk( VkPhysicalDevice phyDevice, From 49b165d966d0fd1580ed06e619a00c5c313634d6 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 2 Jul 2026 18:25:53 +0000 Subject: [PATCH 311/372] vulkan rework: add adapter and swapchain --- include/pal/pal_graphics.h | 31 +- pal.lua | 37 +- pal_config.lua | 2 +- src/graphics/pal_d3d12.c | 9 +- src/graphics/pal_graphics.c | 33 +- src/graphics/pal_graphics_backends.h | 12 +- src/graphics/pal_vulkan.c | 5370 ------------------ src/graphics/vulkan/pal_adapter_vulkan.c | 828 +++ src/graphics/vulkan/pal_commands_vulkan.c | 263 +- src/graphics/vulkan/pal_descriptors_vulkan.c | 25 + src/graphics/vulkan/pal_device_vulkan.c | 1389 +++++ src/graphics/vulkan/pal_image_vulkan.c | 116 +- src/graphics/vulkan/pal_pipeline_vulkan.c | 129 +- src/graphics/vulkan/pal_swapchain_vulkan.c | 488 ++ src/graphics/vulkan/pal_sync_vulkan.c | 230 + src/graphics/vulkan/pal_vulkan.c | 1435 +++++ src/graphics/vulkan/pal_vulkan.h | 5 +- tests/tests.lua | 20 +- tests/tests_main.c | 2 +- 19 files changed, 4922 insertions(+), 5502 deletions(-) delete mode 100644 src/graphics/pal_vulkan.c create mode 100644 src/graphics/vulkan/pal_adapter_vulkan.c create mode 100644 src/graphics/vulkan/pal_swapchain_vulkan.c create mode 100644 src/graphics/vulkan/pal_vulkan.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index bab2a74f..b50b6a01 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1710,7 +1710,7 @@ typedef struct { PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_8`).*/ PalImageType type; /**< (eg. `PAL_IMAGE_TYPE_2D`).*/ PalFormat format; /**< (eg. `PAL_FORMAT_R8G8B8A8_UNORM`).*/ - PalBool belongsToSwapcchain; /**< If `PAL_TRUE`, the image belongs to a swapchain.*/ + PalBool belongsToSwapchain; /**< If `PAL_TRUE`, the image belongs to a swapchain.*/ } PalImageInfo; /** @@ -1818,25 +1818,10 @@ typedef struct { */ typedef struct { uint64_t timeout; /**< Timeout in milliseconds.*/ - uint64_t signalValue; /**< Timeline semaphore value to signal.*/ PalSemaphore* signalSemaphore; /**< Timeline semaphore value to signal.*/ PalFence* fence; /**< Fence to signal.*/ } PalSwapchainNextImageInfo; -/** - * @struct PalSwapchainPresentInfo - * @brief Present information of a swapchain. - * - * Uninitialized fields may result in undefined behavior. - * - * @since 2.0 - */ -typedef struct { - uint64_t imageIndex; /**< Image index to present.*/ - uint64_t waitValue; /**< Timeline semaphore value to wait on.*/ - PalSemaphore* waitSemaphore; /**< Wait semaphore.*/ -} PalSwapchainPresentInfo; - /** * @struct PalRenderingInfo * @brief Information about how rendering should be done in graphics pipeline. @@ -3091,7 +3076,7 @@ typedef struct { */ PalImage*(PAL_CALL* getSwapchainImage)( PalSwapchain* swapchain, - int32_t index); + uint32_t index); /** * Backend implementation of ::palGetNextSwapchainImage. @@ -3110,7 +3095,8 @@ typedef struct { */ PalResult(PAL_CALL* presentSwapchain)( PalSwapchain* swapchain, - PalSwapchainPresentInfo* info); + uint32_t imageIndex, + PalSemaphore* waitSemaphore); /** * Backend implementation of ::palResizeSwapchain. @@ -4968,7 +4954,7 @@ PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); */ PAL_API PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, - int32_t index); + uint32_t index); /** * @brief Get the next available image from the swapchain image list. @@ -4999,8 +4985,8 @@ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( * The graphics system must be initialized before this call. * * @param[in] swapchain Swapchain to present. - * @param[in] info Pointer to a PalSwapchainPresentInfo struct that specifies parameters. - * Must not be `nullptr`. + * @param[in] imageIndex Swapchain image index to present. + * @param[in] waitSemaphore The semaphore to wait for. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5011,7 +4997,8 @@ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( */ PAL_API PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, - PalSwapchainPresentInfo* info); + uint32_t imageIndex, + PalSemaphore* waitSemaphore); /** * @brief Resize the provided swapchain. diff --git a/pal.lua b/pal.lua index 7a8d435d..c9219a59 100644 --- a/pal.lua +++ b/pal.lua @@ -233,20 +233,27 @@ project "PAL" -- base graphics file files { "src/graphics/pal_graphics.c" } + if (hasVulkan) then + files { + "src/graphics/vulkan/pal_adapter_vulkan.c", + "src/graphics/vulkan/pal_as_vulkan.c", + "src/graphics/vulkan/pal_buffer_vulkan.c", + "src/graphics/vulkan/pal_command_pool_vulkan.c", + "src/graphics/vulkan/pal_commands_vulkan.c", + "src/graphics/vulkan/pal_descriptors_vulkan.c", + "src/graphics/vulkan/pal_device_vulkan.c", + "src/graphics/vulkan/pal_image_vulkan.c", + "src/graphics/vulkan/pal_pipeline_vulkan.c", + "src/graphics/vulkan/pal_sbt_vulkan.c", + "src/graphics/vulkan/pal_swapchain_vulkan.c", + "src/graphics/vulkan/pal_sync_vulkan.c", + "src/graphics/vulkan/pal_vulkan.c" + } + end - filter {"system:windows", "configurations:*"} - if (hasVulkan) then - files { "src/graphics/pal_vulkan.c" } - end - - if (hasD3D12) then - files { "src/graphics/pal_d3d12.c" } - end - - filter {"system:linux", "configurations:*"} - if (hasVulkan) then - files { "src/graphics/pal_vulkan.c" } - end - - filter {} + if (hasD3D12) then + files { + -- "src/graphics/pal_d3d12.c" + } + end end diff --git a/pal_config.lua b/pal_config.lua index 0bc62726..821efe2d 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -15,7 +15,7 @@ PAL_BUILD_SYSTEM_MODULE = false PAL_BUILD_THREAD_MODULE = false -- build video module -PAL_BUILD_VIDEO_MODULE = true +PAL_BUILD_VIDEO_MODULE = false -- build opengl module PAL_BUILD_OPENGL_MODULE = false diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 0180be19..cc5c9f02 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -4199,7 +4199,7 @@ void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) PalImage* PAL_CALL getSwapchainImageD3D12( PalSwapchain* swapchain, - int32_t index) + uint32_t index) { Swapchain* d3dSwapchain = (Swapchain*)swapchain; if (index > d3dSwapchain->imageCount) { @@ -4240,14 +4240,15 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( PalResult PAL_CALL presentSwapchainD3D12( PalSwapchain* swapchain, - PalSwapchainPresentInfo* info) + uint32_t imageIndex, + PalSemaphore* waitSemaphore) { HRESULT result; Swapchain* d3dSwapchain = (Swapchain*)swapchain; ID3D12CommandQueue* queue = d3dSwapchain->queue; - if (info->waitSemaphore) { - Semaphore* semaphore = (Semaphore*)info->waitSemaphore; + if (waitSemaphore) { + Semaphore* semaphore = (Semaphore*)waitSemaphore; if (semaphore->isTimeline) { queue->lpVtbl->Wait(queue, semaphore->handle, info->waitValue); } else { diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 55104a52..f8f07b9f 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -477,15 +477,15 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN_BACKEND - // result = initGraphicsVk(debugger, allocator); - // if (result != PAL_RESULT_SUCCESS) { - // return result; - // } - - // attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - // attachedBackend->base = &s_VkBackend; - // attachedBackend->startIndex = 0; - // attachedBackend->count = 0; + result = initGraphicsVk(debugger, allocator); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + attachedBackend->base = s_VkBackend; + attachedBackend->startIndex = 0; + attachedBackend->count = 0; #endif // PAL_HAS_VULKAN_BACKEND // D3D12 @@ -496,7 +496,7 @@ PalResult PAL_CALL palInitGraphics( } attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base = &s_D3D12Backend; + attachedBackend->base = s_D3D12Backend; attachedBackend->startIndex = 0; attachedBackend->count = 0; #endif // PAL_HAS_D3D12_BACKEND @@ -510,7 +510,7 @@ PalResult PAL_CALL palInitGraphics( } attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base = &s_VkBackend; + attachedBackend->base = s_VkBackend; attachedBackend->startIndex = 0; attachedBackend->count = 0; #endif // PAL_HAS_VULKAN_BACKEND @@ -532,7 +532,7 @@ void PAL_CALL palShutdownGraphics() #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN_BACKEND - // shutdownGraphicsVk(); + shutdownGraphicsVk(); #endif // PAL_HAS_VULKAN_BACKEND // D3D12 @@ -1239,7 +1239,7 @@ void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, - int32_t index) + uint32_t index) { if (!s_Graphics.initialized || !swapchain || index < 0) { return nullptr; @@ -1266,17 +1266,18 @@ PalResult PAL_CALL palGetNextSwapchainImage( PalResult PAL_CALL palPresentSwapchain( PalSwapchain* swapchain, - PalSwapchainPresentInfo* info) + uint32_t imageIndex, + PalSemaphore* waitSemaphore) { if (!s_Graphics.initialized) { return PAL_RESULT_CODE_NOT_INITIALIZED; } - if (!swapchain || !info) { + if (!swapchain) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return swapchain->backend->presentSwapchain(swapchain, info); + return swapchain->backend->presentSwapchain(swapchain, imageIndex, waitSemaphore); } PalResult PAL_CALL palResizeSwapchain( diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index a6169bf3..e26093ce 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -55,9 +55,9 @@ typedef struct { PalResult (PAL_CALL *getSurfaceCapabilities)(PalDevice*, PalSurface*, PalSurfaceCapabilities*); PalResult (PAL_CALL *createSwapchain)(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); void (PAL_CALL *destroySwapchain)(PalSwapchain*); - PalImage* (PAL_CALL *getSwapchainImage)(PalSwapchain*, int32_t); + PalImage* (PAL_CALL *getSwapchainImage)(PalSwapchain*, uint32_t); PalResult (PAL_CALL *getNextSwapchainImage)(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t*); - PalResult (PAL_CALL *presentSwapchain)(PalSwapchain*, PalSwapchainPresentInfo*); + PalResult (PAL_CALL *presentSwapchain)(PalSwapchain*, uint32_t, PalSemaphore*); PalResult (PAL_CALL *resizeSwapchain)(PalSwapchain*, uint32_t, uint32_t); PalResult (PAL_CALL *createShader)(PalDevice*, const PalShaderCreateInfo*, PalShader**); void (PAL_CALL *destroyShader)(PalShader*); @@ -208,8 +208,8 @@ PalResult PAL_CALL getSurfaceCapabilitiesVk(PalDevice*, PalSurface*, PalSurfaceC PalResult PAL_CALL createSwapchainVk(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); void PAL_CALL destroySwapchainVk(PalSwapchain*); PalImage* PAL_CALL getSwapchainImageVk(PalSwapchain*, uint32_t); -PalResult PAL_CALL getNextSwapchainImageVk(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t); -PalResult PAL_CALL presentSwapchainVk(PalSwapchain*, PalSwapchainPresentInfo*); +PalResult PAL_CALL getNextSwapchainImageVk(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t*); +PalResult PAL_CALL presentSwapchainVk(PalSwapchain*, uint32_t, PalSemaphore*); PalResult PAL_CALL resizeSwapchainVk(PalSwapchain*, uint32_t, uint32_t); PalResult PAL_CALL createShaderVk(PalDevice*, const PalShaderCreateInfo*, PalShader**); void PAL_CALL destroyShaderVk(PalShader*); @@ -497,8 +497,8 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12(PalDevice*, PalSurface*, PalSurfa PalResult PAL_CALL createSwapchainD3D12(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); void PAL_CALL destroySwapchainD3D12(PalSwapchain*); PalImage* PAL_CALL getSwapchainImageD3D12(PalSwapchain*, uint32_t); -PalResult PAL_CALL getNextSwapchainImageD3D12(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t); -PalResult PAL_CALL presentSwapchainD3D12(PalSwapchain*, PalSwapchainPresentInfo*); +PalResult PAL_CALL getNextSwapchainImageD3D12(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t*); +PalResult PAL_CALL presentSwapchainD3D12(PalSwapchain*, uint32_t, PalSemaphore*); PalResult PAL_CALL resizeSwapchainD3D12(PalSwapchain*, uint32_t, uint32_t); PalResult PAL_CALL createShaderD3D12(PalDevice*, const PalShaderCreateInfo*, PalShader**); void PAL_CALL destroyShaderD3D12(PalShader*); diff --git a/src/graphics/pal_vulkan.c b/src/graphics/pal_vulkan.c deleted file mode 100644 index 4c0ba572..00000000 --- a/src/graphics/pal_vulkan.c +++ /dev/null @@ -1,5370 +0,0 @@ - -/** - PAL - Prime Abstraction Layer - Copyright (C) 2025 - Licensed under the Zlib license. See LICENSE file in root. - */ - -// ================================================== -// Includes -// ================================================== - -#include -#include -#include - -#include "pal/pal_graphics.h" - -#if PAL_HAS_VULKAN_BACKEND -#include - -// HACK: Needed to determine display type if on linux -#ifdef _WIN32 -#include -#define VK_LIB_NAME "vulkan-1.dll" -#elif defined(__linux__) -#include -#define VK_LIB_NAME "libvulkan.so" -#else -// Android -#define VK_LIB_NAME "" -#endif // _WIN32 - -// ================================================== -// Typedefs, enums and structs -// ================================================== - -#pragma region Video - -struct wl_display; -struct wl_surface; -typedef struct _XDisplay Display; -typedef unsigned long Window; -typedef unsigned long VisualID; -typedef unsigned long Colormap; -typedef char *XPointer; -typedef struct _XGC *GC; - -typedef struct _XExtData { - int number; - struct _XExtData *next; - int (*free_private)( - struct _XExtData *extension - ); - XPointer private_data; -} XExtData; - -typedef struct { - XExtData *ext_data; - VisualID visualid; - int class; - unsigned long red_mask, green_mask, blue_mask; - int bits_per_rgb; - int map_entries; -} Visual; - -typedef struct { - int depth; - int nvisuals; - Visual *visuals; -} Depth; - -typedef struct { - XExtData *ext_data; - struct _XDisplay *display; - Window root; - int width, height; - int mwidth, mheight; - int ndepths; - Depth *depths; - int root_depth; - Visual *root_visual; - GC default_gc; - Colormap cmap; - unsigned long white_pixel; - unsigned long black_pixel; - int max_maps, min_maps; - int backing_store; - int save_unders; - long root_input_mask; -} Screen; - -typedef struct { - int x, y; - int width, height; - int border_width; - int depth; - Visual *visual; - Window root; - int class; - int bit_gravity; - int win_gravity; - int backing_store; - unsigned long backing_planes; - unsigned long backing_pixel; - int save_under; - Colormap colormap; - int map_installed; - int map_state; - long all_event_masks; - long your_event_mask; - long do_not_propagate_mask; - int override_redirect; - Screen *screen; -} XWindowAttributes; - -typedef int (*XGetWindowAttributesFn)( - Display*, - Window, - XWindowAttributes*); - -typedef VisualID (*XVisualIDFromVisualFn)(Visual*); - -typedef struct xcb_connection_t xcb_connection_t; -typedef uint32_t xcb_window_t; -typedef uint32_t xcb_visualid_t; -typedef uint32_t xcb_colormap_t; - -typedef struct xcb_get_window_attributes_cookie_t { - unsigned int sequence; -} xcb_get_window_attributes_cookie_t; - -typedef struct xcb_get_window_attributes_reply_t { - uint8_t response_type; - uint8_t backing_store; - uint16_t sequence; - uint32_t length; - xcb_visualid_t visual; - uint16_t _class; - uint8_t bit_gravity; - uint8_t win_gravity; - uint32_t backing_planes; - uint32_t backing_pixel; - uint8_t save_under; - uint8_t map_is_installed; - uint8_t map_state; - uint8_t override_redirect; - xcb_colormap_t colormap; - uint32_t all_event_masks; - uint32_t your_event_mask; - uint16_t do_not_propagate_mask; - uint8_t pad0[2]; -} xcb_get_window_attributes_reply_t; - -typedef struct { - uint8_t response_type; - uint8_t error_code; - uint16_t sequence; - uint32_t resource_id; - uint16_t minor_code; - uint8_t major_code; - uint8_t pad0; - uint32_t pad[5]; - uint32_t full_sequence; -} xcb_generic_error_t; - -typedef xcb_get_window_attributes_cookie_t (*xcb_get_window_attributes_fn)( - xcb_connection_t*, - xcb_window_t); - -typedef xcb_get_window_attributes_reply_t* (*xcb_get_window_attributes_reply_fn)( - xcb_connection_t*, - xcb_get_window_attributes_cookie_t, - xcb_generic_error_t**); - -typedef unsigned long DWORD; -typedef int WINBOOL; -typedef void *LPVOID; -typedef const wchar_t *LPCWSTR,*PCWSTR; -typedef void *HANDLE; -typedef struct HINSTANCE__ *HINSTANCE; -typedef struct HWND__ *HWND; -typedef struct HMONITOR__ *HMONITOR; - -// only define the struct if not on windows -#ifndef _MINWINBASE_ -typedef struct _SECURITY_ATTRIBUTES { - DWORD nLength; - LPVOID ipSecurityDescriptor; - WINBOOL bInheritHandle; -} SECURITY_ATTRIBUTES; -#endif // _MINWINBASE_ - -#pragma endregion - -static Vulkan s_Vk = {0}; - -// ================================================== -// Helper Functions -// ================================================== - -static void* loadLibrary(const char* name) -{ -#ifdef _WIN32 - return LoadLibraryA(name); -#elif defined (__linux__) - return dlopen(name, RTLD_LAZY); -#endif -} - -static void freeLibrary(void* lib) -{ -#ifdef _WIN32 - FreeLibrary((HMODULE)lib); -#elif defined (__linux__) - dlclose(lib); -#endif -} - -static void* loadProc(void* lib, const char* name) -{ -#ifdef _WIN32 - return GetProcAddress((HMODULE)lib, name); -#elif defined (__linux__) - return dlsym(lib, name); -#endif -} - -VkRenderingFlags renderingFlagToVk(PalRenderingFlags flags) -{ - VkRenderingFlags renderingFlags = 0; - if (flags == PAL_RENDERING_FLAG_NONE) { - renderingFlags = 0; - } - - if (flags & PAL_RENDERING_FLAG_RESUMING) { - renderingFlags |= VK_RENDERING_RESUMING_BIT; - } - - if (flags & PAL_RENDERING_FLAG_SUSPENDING) { - renderingFlags |= VK_RENDERING_SUSPENDING_BIT; - } - - return renderingFlags; -} - -static PalResult resultFromVknnn(VkResult result) -{ - switch (result) { - case VK_ERROR_FEATURE_NOT_PRESENT: - case VK_ERROR_EXTENSION_NOT_PRESENT: { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - case VK_ERROR_OUT_OF_HOST_MEMORY: - case VK_ERROR_TOO_MANY_OBJECTS: - case VK_ERROR_OUT_OF_DEVICE_MEMORY: { - return PAL_RESULT_OUT_OF_MEMORY; - } - - case VK_ERROR_INITIALIZATION_FAILED: - return PAL_RESULT_PLATFORM_FAILURE; - - case VK_ERROR_INCOMPATIBLE_DRIVER: - return PAL_RESULT_INVALID_DRIVER; - - case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: { - return PAL_RESULT_INVALID_WINDOW; - } - - case VK_TIMEOUT: - return PAL_RESULT_TIMEOUT; - - case VK_ERROR_MEMORY_MAP_FAILED: - return PAL_RESULT_MEMORY_MAP_FAILED; - - case VK_ERROR_DEVICE_LOST: - return PAL_RESULT_DEVICE_LOST; - - case VK_ERROR_SURFACE_LOST_KHR: - return PAL_RESULT_SURFACE_LOST; - - case VK_ERROR_OUT_OF_DATE_KHR: - return PAL_RESULT_SWAPCHAIN_OUT_OF_DATE; - - default: - return PAL_RESULT_PLATFORM_FAILURE; - } - return PAL_RESULT_PLATFORM_FAILURE; -} - -static VkFormat formatToVk(PalFormat format) -{ - switch (format) { - case PAL_FORMAT_R8_UNORM: - return VK_FORMAT_R8_UNORM; - - case PAL_FORMAT_R8_SNORM: - return VK_FORMAT_R8_SNORM; - - case PAL_FORMAT_R8_UINT: - return VK_FORMAT_R8_UINT; - - case PAL_FORMAT_R8_SINT: - return VK_FORMAT_R8_SINT; - - case PAL_FORMAT_R8_SRGB: - return VK_FORMAT_R8_SRGB; - - case PAL_FORMAT_R16_UNORM: - return VK_FORMAT_R16_UNORM; - - case PAL_FORMAT_R16_SNORM: - return VK_FORMAT_R16_SNORM; - - case PAL_FORMAT_R16_UINT: - return VK_FORMAT_R16_UINT; - - case PAL_FORMAT_R16_SINT: - return VK_FORMAT_R16_SINT; - - case PAL_FORMAT_R16_SFLOAT: - return VK_FORMAT_R16_SFLOAT; - - case PAL_FORMAT_R32_UINT: - return VK_FORMAT_R32_UINT; - - case PAL_FORMAT_R32_SINT: - return VK_FORMAT_R32_SINT; - - case PAL_FORMAT_R32_SFLOAT: - return VK_FORMAT_R32_SFLOAT; - - case PAL_FORMAT_R64_UINT: - return VK_FORMAT_R64_UINT; - - case PAL_FORMAT_R64_SINT: - return VK_FORMAT_R64_SINT; - - case PAL_FORMAT_R64_SFLOAT: - return VK_FORMAT_R64_SFLOAT; - - case PAL_FORMAT_R8G8_UNORM: - return VK_FORMAT_R8G8_UNORM; - - case PAL_FORMAT_R8G8_SNORM: - return VK_FORMAT_R8G8_SNORM; - - case PAL_FORMAT_R8G8_UINT: - return VK_FORMAT_R8G8_UINT; - - case PAL_FORMAT_R8G8_SINT: - return VK_FORMAT_R8G8_SINT; - - case PAL_FORMAT_R8G8_SRGB: - return VK_FORMAT_R8G8_SRGB; - - case PAL_FORMAT_R16G16_UNORM: - return VK_FORMAT_R16G16_UNORM; - - case PAL_FORMAT_R16G16_SNORM: - return VK_FORMAT_R16G16_SNORM; - - case PAL_FORMAT_R16G16_UINT: - return VK_FORMAT_R16G16_UINT; - - case PAL_FORMAT_R16G16_SINT: - return VK_FORMAT_R16G16_SINT; - - case PAL_FORMAT_R16G16_SFLOAT: - return VK_FORMAT_R16G16_SFLOAT; - - case PAL_FORMAT_R32G32_UINT: - return VK_FORMAT_R32G32_UINT; - - case PAL_FORMAT_R32G32_SINT: - return VK_FORMAT_R32G32_SINT; - - case PAL_FORMAT_R32G32_SFLOAT: - return VK_FORMAT_R32G32_SFLOAT; - - case PAL_FORMAT_R64G64_UINT: - return VK_FORMAT_R64G64_UINT; - - case PAL_FORMAT_R64G64_SINT: - return VK_FORMAT_R64G64_SINT; - - case PAL_FORMAT_R64G64_SFLOAT: - return VK_FORMAT_R64G64_SFLOAT; - - case PAL_FORMAT_R8G8B8_UNORM: - return VK_FORMAT_R8G8B8_UNORM; - - case PAL_FORMAT_R8G8B8_SNORM: - return VK_FORMAT_R8G8B8_SNORM; - - case PAL_FORMAT_R8G8B8_UINT: - return VK_FORMAT_R8G8B8_UINT; - - case PAL_FORMAT_R8G8B8_SINT: - return VK_FORMAT_R8G8B8_SINT; - - case PAL_FORMAT_R8G8B8_SRGB: - return VK_FORMAT_R8G8B8_SRGB; - - case PAL_FORMAT_R16G16B16_UNORM: - return VK_FORMAT_R16G16B16_UNORM; - - case PAL_FORMAT_R16G16B16_SNORM: - return VK_FORMAT_R16G16B16_SNORM; - - case PAL_FORMAT_R16G16B16_UINT: - return VK_FORMAT_R16G16B16_UINT; - - case PAL_FORMAT_R16G16B16_SINT: - return VK_FORMAT_R16G16B16_SINT; - - case PAL_FORMAT_R16G16B16_SFLOAT: - return VK_FORMAT_R16G16B16_SFLOAT; - - case PAL_FORMAT_R32G32B32_UINT: - return VK_FORMAT_R32G32B32_UINT; - - case PAL_FORMAT_R32G32B32_SINT: - return VK_FORMAT_R32G32B32_SINT; - - case PAL_FORMAT_R32G32B32_SFLOAT: - return VK_FORMAT_R32G32B32_SFLOAT; - - case PAL_FORMAT_R64G64B64_UINT: - return VK_FORMAT_R64G64B64_UINT; - - case PAL_FORMAT_R64G64B64_SINT: - return VK_FORMAT_R64G64B64_SINT; - - case PAL_FORMAT_R64G64B64_SFLOAT: - return VK_FORMAT_R64G64B64_SFLOAT; - - case PAL_FORMAT_B8G8R8_UNORM: - return VK_FORMAT_B8G8R8_UNORM; - - case PAL_FORMAT_B8G8R8_SNORM: - return VK_FORMAT_B8G8R8_SNORM; - - case PAL_FORMAT_B8G8R8_UINT: - return VK_FORMAT_B8G8R8_UINT; - - case PAL_FORMAT_B8G8R8_SINT: - return VK_FORMAT_B8G8R8_SINT; - - case PAL_FORMAT_B8G8R8_SRGB: - return VK_FORMAT_B8G8R8_SRGB; - - case PAL_FORMAT_R8G8B8A8_UNORM: - return VK_FORMAT_R8G8B8A8_UNORM; - - case PAL_FORMAT_R8G8B8A8_SNORM: - return VK_FORMAT_R8G8B8A8_SNORM; - - case PAL_FORMAT_R8G8B8A8_UINT: - return VK_FORMAT_R8G8B8A8_UINT; - - case PAL_FORMAT_R8G8B8A8_SINT: - return VK_FORMAT_R8G8B8A8_SINT; - - case PAL_FORMAT_R8G8B8A8_SRGB: - return VK_FORMAT_R8G8B8A8_SRGB; - - case PAL_FORMAT_R16G16B16A16_UNORM: - return VK_FORMAT_R16G16B16A16_UNORM; - - case PAL_FORMAT_R16G16B16A16_SNORM: - return VK_FORMAT_R16G16B16A16_SNORM; - - case PAL_FORMAT_R16G16B16A16_UINT: - return VK_FORMAT_R16G16B16A16_UINT; - - case PAL_FORMAT_R16G16B16A16_SINT: - return VK_FORMAT_R16G16B16A16_SINT; - - case PAL_FORMAT_R16G16B16A16_SFLOAT: - return VK_FORMAT_R16G16B16A16_SFLOAT; - - case PAL_FORMAT_R32G32B32A32_UINT: - return VK_FORMAT_R32G32B32A32_UINT; - - case PAL_FORMAT_R32G32B32A32_SINT: - return VK_FORMAT_R32G32B32A32_SINT; - - case PAL_FORMAT_R32G32B32A32_SFLOAT: - return VK_FORMAT_R32G32B32A32_SFLOAT; - - case PAL_FORMAT_R64G64B64A64_UINT: - return VK_FORMAT_R64G64B64A64_UINT; - - case PAL_FORMAT_R64G64B64A64_SINT: - return VK_FORMAT_R64G64B64A64_SINT; - - case PAL_FORMAT_R64G64B64A64_SFLOAT: - return VK_FORMAT_R64G64B64A64_SFLOAT; - - case PAL_FORMAT_B8G8R8A8_UNORM: - return VK_FORMAT_B8G8R8A8_UNORM; - - case PAL_FORMAT_B8G8R8A8_SNORM: - return VK_FORMAT_B8G8R8A8_SNORM; - - case PAL_FORMAT_B8G8R8A8_UINT: - return VK_FORMAT_B8G8R8A8_UINT; - - case PAL_FORMAT_B8G8R8A8_SINT: - return VK_FORMAT_B8G8R8A8_SINT; - - case PAL_FORMAT_B8G8R8A8_SRGB: - return VK_FORMAT_B8G8R8A8_SRGB; - - case PAL_FORMAT_S8_UINT: - return VK_FORMAT_S8_UINT; - - case PAL_FORMAT_D16_UNORM: - return VK_FORMAT_D16_UNORM; - - case PAL_FORMAT_D32_SFLOAT: - return VK_FORMAT_D32_SFLOAT; - - case PAL_FORMAT_D32_SFLOAT_S8_UINT: - return VK_FORMAT_D32_SFLOAT_S8_UINT; - - case PAL_FORMAT_D16_UNORM_S8_UINT: - return VK_FORMAT_D16_UNORM_S8_UINT; - - case PAL_FORMAT_D24_UNORM_S8_UINT: - return VK_FORMAT_D24_UNORM_S8_UINT; - } - - return VK_FORMAT_UNDEFINED; -} - -static VkSampleCountFlags samplesToVk(PalSampleCount count) -{ - switch (count) { - case PAL_SAMPLE_COUNT_2: - return VK_SAMPLE_COUNT_2_BIT; - - case PAL_SAMPLE_COUNT_4: - return VK_SAMPLE_COUNT_4_BIT; - - case PAL_SAMPLE_COUNT_8: - return VK_SAMPLE_COUNT_8_BIT; - - case PAL_SAMPLE_COUNT_16: - return VK_SAMPLE_COUNT_16_BIT; - - case PAL_SAMPLE_COUNT_32: - return VK_SAMPLE_COUNT_32_BIT; - - case PAL_SAMPLE_COUNT_64: - return VK_SAMPLE_COUNT_64_BIT; - } - - return VK_SAMPLE_COUNT_1_BIT; -} - -static PalSampleCount samplesFromVk(VkSampleCountFlags count) -{ - if (count & VK_SAMPLE_COUNT_2_BIT) { - return PAL_SAMPLE_COUNT_2; - - } else if (count & VK_SAMPLE_COUNT_4_BIT) { - return PAL_SAMPLE_COUNT_4; - - } else if (count & VK_SAMPLE_COUNT_8_BIT) { - return PAL_SAMPLE_COUNT_8; - - } else if (count & VK_SAMPLE_COUNT_16_BIT) { - return PAL_SAMPLE_COUNT_16; - - } else if (count & VK_SAMPLE_COUNT_32_BIT) { - return PAL_SAMPLE_COUNT_32; - - } else if (count & VK_SAMPLE_COUNT_64_BIT) { - return PAL_SAMPLE_COUNT_64; - } - - return PAL_SAMPLE_COUNT_1; -} - -static PalFormat formatFromVk(VkFormat format) -{ - switch (format) { - case VK_FORMAT_R8_UNORM: - return PAL_FORMAT_R8_UNORM; - - case VK_FORMAT_R8_SNORM: - return PAL_FORMAT_R8_SNORM; - - case VK_FORMAT_R8_UINT: - return PAL_FORMAT_R8_UINT; - - case VK_FORMAT_R8_SINT: - return PAL_FORMAT_R8_SINT; - - case VK_FORMAT_R8_SRGB: - return PAL_FORMAT_R8_SRGB; - - case VK_FORMAT_R16_UNORM: - return PAL_FORMAT_R16_UNORM; - - case VK_FORMAT_R16_SNORM: - return PAL_FORMAT_R16_SNORM; - - case VK_FORMAT_R16_UINT: - return PAL_FORMAT_R16_UINT; - - case VK_FORMAT_R16_SINT: - return PAL_FORMAT_R16_SINT; - - case VK_FORMAT_R16_SFLOAT: - return PAL_FORMAT_R16_SFLOAT; - - case VK_FORMAT_R32_UINT: - return PAL_FORMAT_R32_UINT; - - case VK_FORMAT_R32_SINT: - return PAL_FORMAT_R32_SINT; - - case VK_FORMAT_R32_SFLOAT: - return PAL_FORMAT_R32_SFLOAT; - - case VK_FORMAT_R64_UINT: - return PAL_FORMAT_R64_UINT; - - case VK_FORMAT_R64_SINT: - return PAL_FORMAT_R64_SINT; - - case VK_FORMAT_R64_SFLOAT: - return PAL_FORMAT_R64_SFLOAT; - - case VK_FORMAT_R8G8_UNORM: - return PAL_FORMAT_R8G8_UNORM; - - case VK_FORMAT_R8G8_SNORM: - return PAL_FORMAT_R8G8_SNORM; - - case VK_FORMAT_R8G8_UINT: - return PAL_FORMAT_R8G8_UINT; - - case VK_FORMAT_R8G8_SINT: - return PAL_FORMAT_R8G8_SINT; - - case VK_FORMAT_R8G8_SRGB: - return PAL_FORMAT_R8G8_SRGB; - - case VK_FORMAT_R16G16_UNORM: - return PAL_FORMAT_R16G16_UNORM; - - case VK_FORMAT_R16G16_SNORM: - return PAL_FORMAT_R16G16_SNORM; - - case VK_FORMAT_R16G16_UINT: - return PAL_FORMAT_R16G16_UINT; - - case VK_FORMAT_R16G16_SINT: - return PAL_FORMAT_R16G16_SINT; - - case VK_FORMAT_R16G16_SFLOAT: - return PAL_FORMAT_R16G16_SFLOAT; - - case VK_FORMAT_R32G32_UINT: - return PAL_FORMAT_R32G32_UINT; - - case VK_FORMAT_R32G32_SINT: - return PAL_FORMAT_R32G32_SINT; - - case VK_FORMAT_R32G32_SFLOAT: - return PAL_FORMAT_R32G32_SFLOAT; - - case VK_FORMAT_R64G64_UINT: - return PAL_FORMAT_R64G64_UINT; - - case VK_FORMAT_R64G64_SINT: - return PAL_FORMAT_R64G64_SINT; - - case VK_FORMAT_R64G64_SFLOAT: - return PAL_FORMAT_R64G64_SFLOAT; - - case VK_FORMAT_R8G8B8_UNORM: - return PAL_FORMAT_R8G8B8_UNORM; - - case VK_FORMAT_R8G8B8_SNORM: - return PAL_FORMAT_R8G8B8_SNORM; - - case VK_FORMAT_R8G8B8_UINT: - return PAL_FORMAT_R8G8B8_UINT; - - case VK_FORMAT_R8G8B8_SINT: - return PAL_FORMAT_R8G8B8_SINT; - - case VK_FORMAT_R8G8B8_SRGB: - return PAL_FORMAT_R8G8B8_SRGB; - - case VK_FORMAT_R16G16B16_UNORM: - return PAL_FORMAT_R16G16B16_UNORM; - - case VK_FORMAT_R16G16B16_SNORM: - return PAL_FORMAT_R16G16B16_SNORM; - - case VK_FORMAT_R16G16B16_UINT: - return PAL_FORMAT_R16G16B16_UINT; - - case VK_FORMAT_R16G16B16_SINT: - return PAL_FORMAT_R16G16B16_SINT; - - case VK_FORMAT_R16G16B16_SFLOAT: - return PAL_FORMAT_R16G16B16_SFLOAT; - - case VK_FORMAT_R32G32B32_UINT: - return PAL_FORMAT_R32G32B32_UINT; - - case VK_FORMAT_R32G32B32_SINT: - return PAL_FORMAT_R32G32B32_SINT; - - case VK_FORMAT_R32G32B32_SFLOAT: - return PAL_FORMAT_R32G32B32_SFLOAT; - - case VK_FORMAT_R64G64B64_UINT: - return PAL_FORMAT_R64G64B64_UINT; - - case VK_FORMAT_R64G64B64_SINT: - return PAL_FORMAT_R64G64B64_SINT; - - case VK_FORMAT_R64G64B64_SFLOAT: - return PAL_FORMAT_R64G64B64_SFLOAT; - - case VK_FORMAT_B8G8R8_UNORM: - return PAL_FORMAT_B8G8R8_UNORM; - - case VK_FORMAT_B8G8R8_SNORM: - return PAL_FORMAT_B8G8R8_SNORM; - - case VK_FORMAT_B8G8R8_UINT: - return PAL_FORMAT_B8G8R8_UINT; - - case VK_FORMAT_B8G8R8_SINT: - return PAL_FORMAT_B8G8R8_SINT; - - case VK_FORMAT_B8G8R8_SRGB: - return PAL_FORMAT_B8G8R8_SRGB; - - case VK_FORMAT_R8G8B8A8_UNORM: - return PAL_FORMAT_R8G8B8A8_UNORM; - - case VK_FORMAT_R8G8B8A8_SNORM: - return PAL_FORMAT_R8G8B8A8_SNORM; - - case VK_FORMAT_R8G8B8A8_UINT: - return PAL_FORMAT_R8G8B8A8_UINT; - - case VK_FORMAT_R8G8B8A8_SINT: - return PAL_FORMAT_R8G8B8A8_SINT; - - case VK_FORMAT_R8G8B8A8_SRGB: - return PAL_FORMAT_R8G8B8A8_SRGB; - - case VK_FORMAT_R16G16B16A16_UNORM: - return PAL_FORMAT_R16G16B16A16_UNORM; - - case VK_FORMAT_R16G16B16A16_SNORM: - return PAL_FORMAT_R16G16B16A16_SNORM; - - case VK_FORMAT_R16G16B16A16_UINT: - return PAL_FORMAT_R16G16B16A16_UINT; - - case VK_FORMAT_R16G16B16A16_SINT: - return PAL_FORMAT_R16G16B16A16_SINT; - - case VK_FORMAT_R16G16B16A16_SFLOAT: - return PAL_FORMAT_R16G16B16A16_SFLOAT; - - case VK_FORMAT_R32G32B32A32_UINT: - return PAL_FORMAT_R32G32B32A32_UINT; - - case VK_FORMAT_R32G32B32A32_SINT: - return PAL_FORMAT_R32G32B32A32_SINT; - - case VK_FORMAT_R32G32B32A32_SFLOAT: - return PAL_FORMAT_R32G32B32A32_SFLOAT; - - case VK_FORMAT_R64G64B64A64_UINT: - return PAL_FORMAT_R64G64B64A64_UINT; - - case VK_FORMAT_R64G64B64A64_SINT: - return PAL_FORMAT_R64G64B64A64_SINT; - - case VK_FORMAT_R64G64B64A64_SFLOAT: - return PAL_FORMAT_R64G64B64A64_SFLOAT; - - case VK_FORMAT_B8G8R8A8_UNORM: - return PAL_FORMAT_B8G8R8A8_UNORM; - - case VK_FORMAT_B8G8R8A8_SNORM: - return PAL_FORMAT_B8G8R8A8_SNORM; - - case VK_FORMAT_B8G8R8A8_UINT: - return PAL_FORMAT_B8G8R8A8_UINT; - - case VK_FORMAT_B8G8R8A8_SINT: - return PAL_FORMAT_B8G8R8A8_SINT; - - case VK_FORMAT_B8G8R8A8_SRGB: - return PAL_FORMAT_B8G8R8A8_SRGB; - - case VK_FORMAT_S8_UINT: - return PAL_FORMAT_S8_UINT; - - case VK_FORMAT_D16_UNORM: - return PAL_FORMAT_D16_UNORM; - - case VK_FORMAT_D32_SFLOAT: - return PAL_FORMAT_D32_SFLOAT; - - case VK_FORMAT_D32_SFLOAT_S8_UINT: - return PAL_FORMAT_D32_SFLOAT_S8_UINT; - - case VK_FORMAT_D16_UNORM_S8_UINT: - return PAL_FORMAT_D16_UNORM_S8_UINT; - - case VK_FORMAT_D24_UNORM_S8_UINT: - return PAL_FORMAT_D24_UNORM_S8_UINT; - } - - return PAL_FORMAT_UNDEFINED; -} - -static PalImageUsages ImageUsageFromVk(VkFormatFeatureFlags flags) -{ - PalImageUsages usages = 0; - if (flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { - usages |= PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; - } - - if (flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { - usages |= PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT; - } - - if (flags & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) { - usages |= PAL_IMAGE_USAGE_TRANSFER_SRC; - } - - if (flags & VK_FORMAT_FEATURE_TRANSFER_DST_BIT) { - usages |= PAL_IMAGE_USAGE_TRANSFER_DST; - } - - if (flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) { - usages |= VK_IMAGE_USAGE_STORAGE_BIT; - } - - if (flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { - usages |= PAL_IMAGE_USAGE_SAMPLED; - } - - return usages; -} - -static VkImageViewType imageViewTypeToVk(PalImageViewType type) -{ - switch (type) { - case PAL_IMAGE_VIEW_TYPE_1D: - return VK_IMAGE_VIEW_TYPE_1D; - - case PAL_IMAGE_VIEW_TYPE_1D_ARRAY: - return VK_IMAGE_VIEW_TYPE_1D_ARRAY; - - case PAL_IMAGE_VIEW_TYPE_2D: - return VK_IMAGE_VIEW_TYPE_2D; - - case PAL_IMAGE_VIEW_TYPE_2D_ARRAY: - return VK_IMAGE_VIEW_TYPE_2D_ARRAY; - - case PAL_IMAGE_VIEW_TYPE_3D: - return VK_IMAGE_VIEW_TYPE_3D; - - case PAL_IMAGE_VIEW_TYPE_CUBE: - return VK_IMAGE_VIEW_TYPE_CUBE; - - case PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY: - return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; - } - - return VK_IMAGE_VIEW_TYPE_2D; -} - -static VkExtent2D getShadingRateSizeVk(PalFragmentShadingRate rate) -{ - switch (rate) { - case PAL_FRAGMENT_SHADING_RATE_1X1: - return (VkExtent2D){1, 1}; - - case PAL_FRAGMENT_SHADING_RATE_1X2: - return (VkExtent2D){1, 2}; - - case PAL_FRAGMENT_SHADING_RATE_2X1: - return (VkExtent2D){2, 1}; - - case PAL_FRAGMENT_SHADING_RATE_2X2: - return (VkExtent2D){2, 2}; - - case PAL_FRAGMENT_SHADING_RATE_2X4: - return (VkExtent2D){2, 4}; - - case PAL_FRAGMENT_SHADING_RATE_4X2: - return (VkExtent2D){4, 2}; - - case PAL_FRAGMENT_SHADING_RATE_4X4: - return (VkExtent2D){4, 4}; - } - - return (VkExtent2D){0, 0}; -} - -static VkFormat vertexTypeToVk(PalVertexType type) -{ - switch (type) { - case PAL_VERTEX_TYPE_INT32: - return VK_FORMAT_R32_SINT; - - case PAL_VERTEX_TYPE_INT32_2: - return VK_FORMAT_R32G32_SINT; - - case PAL_VERTEX_TYPE_INT32_3: - return VK_FORMAT_R32G32B32_SINT; - - case PAL_VERTEX_TYPE_INT32_4: - return VK_FORMAT_R32G32B32A32_SINT; - - case PAL_VERTEX_TYPE_UINT32: - return VK_FORMAT_R32_UINT; - - case PAL_VERTEX_TYPE_UINT32_2: - return VK_FORMAT_R32G32_UINT; - - case PAL_VERTEX_TYPE_UINT32_3: - return VK_FORMAT_R32G32B32_UINT; - - case PAL_VERTEX_TYPE_UINT32_4: - return VK_FORMAT_R32G32B32A32_UINT; - - case PAL_VERTEX_TYPE_INT8_2: - return VK_FORMAT_R8G8_SINT; - - case PAL_VERTEX_TYPE_INT8_4: - return VK_FORMAT_R8G8B8A8_SINT; - - case PAL_VERTEX_TYPE_UINT8_2: - return VK_FORMAT_R8G8_UINT; - - case PAL_VERTEX_TYPE_UINT8_4: - return VK_FORMAT_R8G8B8A8_UINT; - - case PAL_VERTEX_TYPE_INT8_2NORM: - return VK_FORMAT_R8G8_SNORM; - - case PAL_VERTEX_TYPE_INT8_4NORM: - return VK_FORMAT_R8G8B8A8_SNORM; - - case PAL_VERTEX_TYPE_UINT8_2NORM: - return VK_FORMAT_R8G8_UNORM; - - case PAL_VERTEX_TYPE_UINT8_4NORM: - return VK_FORMAT_R8G8B8A8_UNORM; - - case PAL_VERTEX_TYPE_INT16_2: - return VK_FORMAT_R16G16_SINT; - - case PAL_VERTEX_TYPE_INT16_4: - return VK_FORMAT_R16G16B16A16_SINT; - - case PAL_VERTEX_TYPE_UINT16_2: - return VK_FORMAT_R16G16_UINT; - - case PAL_VERTEX_TYPE_UINT16_4: - return VK_FORMAT_R16G16B16A16_UINT; - - case PAL_VERTEX_TYPE_INT16_2NORM: - return VK_FORMAT_R16G16_SNORM; - - case PAL_VERTEX_TYPE_INT16_4NORM: - return VK_FORMAT_R16G16B16A16_SNORM; - - case PAL_VERTEX_TYPE_UINT16_2NORM: - return VK_FORMAT_R16G16_UNORM; - - case PAL_VERTEX_TYPE_UINT16_4NORM: - return VK_FORMAT_R16G16B16A16_UNORM; - - case PAL_VERTEX_TYPE_FLOAT: - return VK_FORMAT_R32_SFLOAT; - - case PAL_VERTEX_TYPE_FLOAT2: - return VK_FORMAT_R32G32_SFLOAT; - - case PAL_VERTEX_TYPE_FLOAT3: - return VK_FORMAT_R32G32B32_SFLOAT; - - case PAL_VERTEX_TYPE_FLOAT4: - return VK_FORMAT_R32G32B32A32_SFLOAT; - - case PAL_VERTEX_TYPE_HALF_FLOAT16_2: - return VK_FORMAT_R16G16_SFLOAT; - - case PAL_VERTEX_TYPE_HALF_FLOAT16_4: - return VK_FORMAT_R16G16B16A16_SFLOAT; - } - - return VK_FORMAT_UNDEFINED; -} - - - - -static VkStencilOp stencilOpToVk(PalStencilOp op) -{ - switch (op) { - case PAL_STENCIL_OP_KEEP: - return VK_STENCIL_OP_KEEP; - - case PAL_STENCIL_OP_ZERO: - return VK_STENCIL_OP_ZERO; - - case PAL_STENCIL_OP_REPLACE: - return VK_STENCIL_OP_REPLACE; - - case PAL_STENCIL_OP_INCREMENT_AND_CLAMP: - return VK_STENCIL_OP_INCREMENT_AND_CLAMP; - - case PAL_STENCIL_OP_DECREMENT_AND_CLAMP: - return VK_STENCIL_OP_DECREMENT_AND_CLAMP; - - case PAL_STENCIL_OP_INVERT: - return VK_STENCIL_OP_INVERT; - - case PAL_STENCIL_OP_INCREMENT_AND_WRAP: - return VK_STENCIL_OP_INCREMENT_AND_WRAP; - - case PAL_STENCIL_OP_DECREMENT_AND_WRAP: - return VK_STENCIL_OP_DECREMENT_AND_WRAP; - } - - return VK_STENCIL_OP_KEEP; -} - -static VkCompareOp compareOpToVk(PalCompareOp op) -{ - switch (op) { - case PAL_COMPARE_OP_NEVER: - return VK_COMPARE_OP_NEVER; - - case PAL_COMPARE_OP_LESS: - return VK_COMPARE_OP_LESS; - - case PAL_COMPARE_OP_EQUAL: - return VK_COMPARE_OP_EQUAL; - - case PAL_COMPARE_OP_LESS_OR_EQUAL: - return VK_COMPARE_OP_LESS_OR_EQUAL; - - case PAL_COMPARE_OP_GREATER: - return VK_COMPARE_OP_GREATER; - - case PAL_COMPARE_OP_NOT_EQUAL: - return VK_COMPARE_OP_NOT_EQUAL; - - case PAL_COMPARE_OP_GREATER_OR_EQUAL: - return VK_COMPARE_OP_GREATER_OR_EQUAL; - - case PAL_COMPARE_OP_ALWAYS: - return VK_COMPARE_OP_ALWAYS; - } - - return VK_COMPARE_OP_NEVER; -} - - - - - -static VkResolveModeFlags resolveModeToVk(PalResolveMode mode) -{ - switch (mode) { - case PAL_RESOLVE_MODE_SAMPLE_ZERO: - return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; - - case PAL_RESOLVE_MODE_AVERAGE: - return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; - - case PAL_RESOLVE_MODE_MIN: - return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; - - case PAL_RESOLVE_MODE_MAX: - return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; - } - - return VK_RESOLVE_MODE_NONE_KHR; -} - -static VkFilter filterToVk(PalFilterMode mode) -{ - switch (mode) { - case PAL_FILTER_MODE_NEAREST: { - return VK_FILTER_NEAREST; - } - - case PAL_FILTER_MODE_LINEAR: { - return VK_FILTER_LINEAR; - } - } - return VK_FILTER_NEAREST; -} - -static VkSamplerMipmapMode mipmapModeToVk(PalSamplerMipmapMode mode) -{ - switch (mode) { - case PAL_SAMPLER_MIPMAP_MODE_NEAREST: { - return VK_SAMPLER_MIPMAP_MODE_NEAREST; - } - - case PAL_SAMPLER_MIPMAP_MODE_LINEAR: { - return VK_SAMPLER_MIPMAP_MODE_LINEAR; - } - } - return VK_SAMPLER_MIPMAP_MODE_NEAREST; -} - -static VkSamplerAddressMode addressModeToVk(PalSamplerAddressMode mode) -{ - switch (mode) { - case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { - return VK_SAMPLER_ADDRESS_MODE_REPEAT; - } - - case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { - return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; - - } - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { - return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - - } - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { - return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - } - } - return VK_SAMPLER_ADDRESS_MODE_REPEAT; -} - -static VkBorderColor borderColorToVk(PalBorderColor color) -{ - switch (color) { - case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: { - return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; - } - - case PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK: { - return VK_BORDER_COLOR_INT_TRANSPARENT_BLACK; - } - - case PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK: { - return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; - } - - case PAL_BORDER_COLOR_INT_OPAQUE_BLACK: { - return VK_BORDER_COLOR_INT_OPAQUE_BLACK; - } - - case PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE: { - return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - } - - case PAL_BORDER_COLOR_INT_OPAQUE_WHITE: { - return VK_BORDER_COLOR_INT_OPAQUE_WHITE; - } - } - return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; -} - -static Barrier barrierToVk( - uint32_t stageCount, - PalUsageState state, - PalShaderStage* shaderStages) -{ - Barrier barrier = {0}; - switch (state) { - case PAL_USAGE_STATE_UNDEFINED: { - barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; - barrier.access = 0; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; - } - - case PAL_USAGE_STATE_PRESENT: { - barrier.stages = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; - barrier.access = 0; - barrier.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - return barrier; - } - - case PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE: { - barrier.stages = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; - barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - return barrier; - } - - case PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; - barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - return barrier; - } - - case PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE: { - barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; - barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - return barrier; - } - - case PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; - barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - return barrier; - } - - case PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE: { - barrier.stages = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.stages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; - barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - return barrier; - } - - case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; - barrier.access = VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; - return barrier; - } - - case PAL_USAGE_STATE_TRANSFER_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; - barrier.access = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - return barrier; - } - - case PAL_USAGE_STATE_TRANSFER_WRITE: { - barrier.stages = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; - barrier.access = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - return barrier; - } - - case PAL_USAGE_STATE_VERTEX_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR; - barrier.access = VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; - } - - case PAL_USAGE_STATE_INDEX_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR; - barrier.access = VK_ACCESS_2_INDEX_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; - } - - case PAL_USAGE_STATE_INDIRECT_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR; - barrier.access = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; - } - - case PAL_USAGE_STATE_UNIFORM_READ: { - for (int i = 0; i < stageCount; i++) { - barrier.stages |= pipelineStageToVk(shaderStages[i]); - } - - if (barrier.stages == 0) { - barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - } - - barrier.access = VK_ACCESS_2_UNIFORM_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; - } - - case PAL_USAGE_STATE_SHADER_READ: { - for (int i = 0; i < stageCount; i++) { - barrier.stages |= pipelineStageToVk(shaderStages[i]); - } - - if (barrier.stages == 0) { - barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - } - - barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - return barrier; - } - - case PAL_USAGE_STATE_SHADER_WRITE: { - for (int i = 0; i < stageCount; i++) { - barrier.stages |= pipelineStageToVk(shaderStages[i]); - } - - if (barrier.stages == 0) { - barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - } - - barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_GENERAL; - return barrier; - } - - case PAL_USAGE_STATE_STORAGE_READ: { - for (int i = 0; i < stageCount; i++) { - barrier.stages |= pipelineStageToVk(shaderStages[i]); - } - - if (barrier.stages == 0) { - barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - } - - barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_GENERAL; - return barrier; - } - - case PAL_USAGE_STATE_STORAGE_WRITE: { - for (int i = 0; i < stageCount; i++) { - barrier.stages |= pipelineStageToVk(shaderStages[i]); - } - - if (barrier.stages == 0) { - barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - } - - barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_GENERAL; - return barrier; - } - - case PAL_USAGE_STATE_HOST_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; - barrier.access = VK_ACCESS_2_HOST_READ_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; - } - - case PAL_USAGE_STATE_HOST_WRITE: { - barrier.stages = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; - barrier.access = VK_ACCESS_2_HOST_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; - } - - case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: { - barrier.stages = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; - barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR; - - // HACK: small performance lost for the case of a single scratch buffer used for - // BLAS and TLAS builds. - barrier.access |= VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; - - for (int i = 0; i < stageCount; i++) { - if (i == 0) { - barrier.stages = 0; - } - - barrier.stages |= pipelineStageToVk(shaderStages[i]); - barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR; - } - - if (barrier.stages == 0) { - barrier.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - } - - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; - } - - case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE: { - barrier.stages = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; - barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; - } - } - - barrier.stages = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; - barrier.access = 0; - barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; - return barrier; -} - -static VkDescriptorType descriptortypeToVk(PalDescriptorType type) -{ - switch (type) { - case PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER: - return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - - case PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: - return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - - case PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: - return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - - case PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE: - return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - - case PAL_DESCRIPTOR_TYPE_SAMPLER: - return VK_DESCRIPTOR_TYPE_SAMPLER; - - case PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE: - return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; - } - - return 0; -} - -static VkShaderStageFlags shaderStageToVK(PalShaderStage stage) -{ - switch (stage) { - case PAL_SHADER_STAGE_VERTEX: - return VK_SHADER_STAGE_VERTEX_BIT; - - case PAL_SHADER_STAGE_FRAGMENT: - return VK_SHADER_STAGE_FRAGMENT_BIT; - - case PAL_SHADER_STAGE_COMPUTE: - return VK_SHADER_STAGE_COMPUTE_BIT; - - case PAL_SHADER_STAGE_GEOMETRY: - return VK_SHADER_STAGE_GEOMETRY_BIT; - - case PAL_SHADER_STAGE_MESH: - return VK_SHADER_STAGE_MESH_BIT_EXT; - - case PAL_SHADER_STAGE_TASK: - return VK_SHADER_STAGE_TASK_BIT_EXT; - - case PAL_SHADER_STAGE_TESSELLATION_CONTROL: - return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; - - case PAL_SHADER_STAGE_TESSELLATION_EVALUATION: - return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; - - case PAL_SHADER_STAGE_RAYGEN: - return VK_SHADER_STAGE_RAYGEN_BIT_KHR; - - case PAL_SHADER_STAGE_CLOSEST_HIT: - return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; - - case PAL_SHADER_STAGE_ANY_HIT: - return VK_SHADER_STAGE_ANY_HIT_BIT_KHR; - - case PAL_SHADER_STAGE_MISS: - return VK_SHADER_STAGE_MISS_BIT_KHR; - - case PAL_SHADER_STAGE_INTERSECTION: - return VK_SHADER_STAGE_INTERSECTION_BIT_KHR; - - case PAL_SHADER_STAGE_CALLABLE: - return VK_SHADER_STAGE_CALLABLE_BIT_KHR; - } - - return 0; -} - -static inline void* alignedRealloc( - void* memory, - uint64_t size, - uint64_t alignment) -{ -#if defined(_MSC_VER) || defined(__MINGW32__) - return _aligned_realloc(memory, size, alignment); -#else - return realloc(memory, size); -#endif // _MSC_VER -} - -static inline void alignedFree(void* ptr) -{ -#if defined(_MSC_VER) || defined(__MINGW32__) - _aligned_free(ptr); -#else - free(ptr); -#endif // _MSC_VER -} - -static void* VKAPI_CALL allocateVk( - void* pUserData, - size_t size, - size_t alignment, - VkSystemAllocationScope allocationScope) -{ - return palAllocate(s_Vk.allocator, size, alignment); -} - -static void VKAPI_CALL freeVk( - void* pUserData, - void* ptr) -{ - palFree(s_Vk.allocator, ptr); -} - -static void* VKAPI_CALL reallocVk( - void* pUserData, - void* pOriginal, - size_t size, - size_t alignment, - VkSystemAllocationScope allocationScope) -{ - // Note: This is a hack which could cost performance but - // realloc is not really called that much so it should be fine - // this is because we dont know the old size - void* block = alignedRealloc(pOriginal, size, alignment); - if (block) { - void* memory = palAllocate(s_Vk.allocator, size, alignment); - if (!memory) { - alignedFree(block); - return nullptr; - } - - memcpy(memory, block, size); - alignedFree(block); - return memory; - } - return nullptr; -} - -VkBool32 VKAPI_CALL debugCallbackVk( - VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagBitsEXT type, - const VkDebugUtilsMessengerCallbackDataEXT* data, - void* userData) -{ - if (!s_Vk.callback) { - return VK_FALSE; - } - - PalDebugMessageSeverity debugSeverity = 0; - PalDebugMessageType debugType = 0; - if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) { - debugType = PAL_DEBUG_MESSAGE_TYPE_GENERAL; - } - - if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) { - debugType = PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE; - } - - if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) { - debugType = PAL_DEBUG_MESSAGE_TYPE_VALIDATION; - } - - if (type & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { - debugSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; - } - - if (type & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { - debugSeverity = PAL_DEBUG_MESSAGE_SEVERITY_WARNING; - } - - if (type & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { - debugSeverity = PAL_DEBUG_MESSAGE_SEVERITY_ERROR; - } - - s_Vk.callback(userData, debugSeverity, debugType, data->pMessage); - return VK_FALSE; -} - -static uint32_t findBestMemoryIndexVk( - VkPhysicalDevice phyDevice, - uint32_t memoryMask) -{ - int bestScore = -1; - uint32_t bestIndex = UINT32_MAX; - VkPhysicalDeviceMemoryProperties memProps = {0}; - s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); - - for (int i = 0; i < memProps.memoryTypeCount; i++) { - if (!(memoryMask & (1u << i))) { - continue; - } - - int score = 0; - VkMemoryPropertyFlags flags = memProps.memoryTypes[i].propertyFlags; - - // GPU only memory - if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { - score += 100; - } - - // CPU memory - if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { - score += 50; - } - - if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { - score += 25; - } - - if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { - score += 10; - } - - if (score > bestScore) { - bestIndex = i; - } - } - - return bestIndex; -} - -static inline uint32_t alignVk( - uint32_t value, - uint32_t alignment) -{ - return (value + alignment - 1) & ~(alignment - 1); -} - -static inline uint32_t maxVk( - uint32_t a, - uint32_t b) -{ - return (a > b) ? a : b; -} - -static inline uint32_t minVk( - uint32_t a, - uint32_t b) -{ - return (a < b) ? a : b; -} - -static void fillBuildInfoVk( - uint32_t count, - PalAccelerationStructureBuildInfo* info, - uint32_t* maxPrimities, - VkAccelerationStructureGeometryKHR* geometries, - VkAccelerationStructureKHR srcAs, - VkAccelerationStructureKHR dstAs, - VkAccelerationStructureBuildRangeInfoKHR* rangeInfos, - VkAccelerationStructureBuildGeometryInfoKHR* buildInfo) -{ - for (int i = 0; i < count; i++) { - // fill vulkan geometry struct - VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; - tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - tmp->flags = 0; - - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { - tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; - data = &tmp->geometry.instances; - data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; - data->arrayOfPointers = PAL_FALSE; - - VkDeviceOrHostAddressConstKHR address = {0}; - address.deviceAddress = info->instanceBufferAddress; - data->data = address; - - if (maxPrimities) { - maxPrimities[i] = info->instanceCount; - } - - // range info - if (rangeInfos) { - VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; - rangeInfo->primitiveCount = info->instanceCount; - rangeInfo->firstVertex = 0; // PAL does not allow setting this - rangeInfo->primitiveOffset = 0; // PAL does not allow setting this - rangeInfo->transformOffset = 0; // PAL does not allow setting this - } - break; - - } else { - if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_OPAQUE) { - tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; - } - - if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT) { - tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; - } - - if (maxPrimities) { - maxPrimities[i] = info->geometries[i].primitiveCount; - } - - // range info - if (rangeInfos) { - VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; - rangeInfo->primitiveCount = info->geometries[i].primitiveCount; - rangeInfo->firstVertex = 0; // PAL does not allow setting this - rangeInfo->primitiveOffset = 0; // PAL does not allow setting this - rangeInfo->transformOffset = 0; // PAL does not allow setting this - } - } - - if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { - tmp->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; - data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; - - VkDeviceOrHostAddressConstKHR vertexAddress = {0}; - VkDeviceOrHostAddressConstKHR indexAddress = {0}; - PalGeometryDataTriangle* tmpData = info->geometries[i].data; - - vertexAddress.deviceAddress = tmpData->vertexBufferAddress; - data->vertexData = vertexAddress; - data->maxVertex = tmpData->vertexCount - 1; - data->vertexFormat = vertexTypeToVk(tmpData->vertexType); - data->vertexStride = tmpData->vertexStride; - - indexAddress.deviceAddress = tmpData->indexBufferAddress; - data->indexData = indexAddress; - if (tmpData->indexType == PAL_INDEX_TYPE_UINT32) { - data->indexType = VK_INDEX_TYPE_UINT32; - } else { - data->indexType = VK_INDEX_TYPE_UINT16; - } - - // set to none if there is no index buffer address - if (!tmpData->indexBufferAddress) { - data->indexType = VK_INDEX_TYPE_NONE_KHR; - } - - } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { - tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; - VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; - data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; - - VkDeviceOrHostAddressConstKHR address = {0}; - PalGeometryDataAABBS* tmpData = info->geometries[i].data; - address.deviceAddress = tmpData->bufferAddress; - data->data = address; - data->stride = tmpData->stride; - } - } - - buildInfo->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - buildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - } else { - buildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - } - - // build mode - if (info->buildMode == PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD) { - buildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - } else { - buildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR; - } - - // build hints - buildInfo->flags = 0; - if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD) { - buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; - } - - if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE) { - buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - } - - if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY) { - buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; - } - - buildInfo->geometryCount = count; - buildInfo->srcAccelerationStructure = srcAs; - buildInfo->dstAccelerationStructure = dstAs; - buildInfo->pGeometries = geometries; - - VkDeviceOrHostAddressKHR scratchData = {0}; - scratchData.deviceAddress = info->scratchBufferAddress; - buildInfo->scratchData = scratchData; -} - - - -static VkImageAspectFlags imageAspectToVk(PalImageAspect aspect) -{ - switch (aspect) { - case PAL_IMAGE_ASPECT_COLOR: - return VK_IMAGE_ASPECT_COLOR_BIT; - - case PAL_IMAGE_ASPECT_DEPTH: - return VK_IMAGE_ASPECT_DEPTH_BIT; - - case PAL_IMAGE_ASPECT_STENCIL: - return VK_IMAGE_ASPECT_STENCIL_BIT; - - case PAL_IMAGE_ASPECT_DEPTH_STENCIL: - return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - } - - return VK_IMAGE_ASPECT_COLOR_BIT; -} - -// ================================================== -// Adapter -// ================================================== - -PalResult PAL_CALL initGraphicsVk( - const PalGraphicsDebugger* debugger, - const PalAllocator* allocator) -{ - // load vulkan - s_Vk.handle = loadLibrary(VK_LIB_NAME); - if (!s_Vk.handle) { - return PAL_RESULT_PLATFORM_FAILURE; - } - - // clang-format off - s_Vk.enumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)loadProc( - s_Vk.handle, - "vkEnumerateInstanceVersion"); - - s_Vk.enumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)loadProc( - s_Vk.handle, - "vkEnumerateInstanceExtensionProperties"); - - s_Vk.createInstance = (PFN_vkCreateInstance)loadProc( - s_Vk.handle, - "vkCreateInstance"); - - s_Vk.destroyInstance = (PFN_vkDestroyInstance)loadProc( - s_Vk.handle, - "vkDestroyInstance"); - - s_Vk.enumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)loadProc( - s_Vk.handle, - "vkEnumeratePhysicalDevices"); - - s_Vk.getPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)loadProc( - s_Vk.handle, - "vkGetPhysicalDeviceProperties"); - - s_Vk.getPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)loadProc( - s_Vk.handle, - "vkGetPhysicalDeviceMemoryProperties"); - - s_Vk.enumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)loadProc( - s_Vk.handle, - "vkEnumerateInstanceLayerProperties"); - - s_Vk.getPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)loadProc( - s_Vk.handle, - "vkGetPhysicalDeviceQueueFamilyProperties"); - - s_Vk.enumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)loadProc( - s_Vk.handle, - "vkEnumerateDeviceExtensionProperties"); - - s_Vk.getPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)loadProc( - s_Vk.handle, - "vkGetPhysicalDeviceFeatures"); - - s_Vk.getPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)loadProc( - s_Vk.handle, - "vkGetPhysicalDeviceFeatures2"); - - s_Vk.getInstanceProcAddr = (PFN_vkGetInstanceProcAddr)loadProc( - s_Vk.handle, - "vkGetInstanceProcAddr"); - - s_Vk.createImage = (PFN_vkCreateImage)loadProc( - s_Vk.handle, - "vkCreateImage"); - - s_Vk.destroyImage = (PFN_vkDestroyImage)loadProc( - s_Vk.handle, - "vkDestroyImage"); - - s_Vk.createImageView = (PFN_vkCreateImageView)loadProc( - s_Vk.handle, - "vkCreateImageView"); - - s_Vk.destroyImageView = (PFN_vkDestroyImageView)loadProc( - s_Vk.handle, - "vkDestroyImageView"); - - s_Vk.createShader = (PFN_vkCreateShaderModule)loadProc( - s_Vk.handle, - "vkCreateShaderModule"); - - s_Vk.destroyShader = (PFN_vkDestroyShaderModule)loadProc( - s_Vk.handle, - "vkDestroyShaderModule"); - - s_Vk.createSampler = (PFN_vkCreateSampler)loadProc( - s_Vk.handle, - "vkCreateSampler"); - - s_Vk.destroySampler = (PFN_vkDestroySampler)loadProc( - s_Vk.handle, - "vkDestroySampler"); - - s_Vk.getPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)loadProc( - s_Vk.handle, - "vkGetPhysicalDeviceProperties2"); - - s_Vk.getPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)loadProc( - s_Vk.handle, - "vkGetPhysicalDeviceFormatProperties"); - - s_Vk.getPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties)loadProc( - s_Vk.handle, - "vkGetPhysicalDeviceImageFormatProperties"); - - s_Vk.createDevice = (PFN_vkCreateDevice)loadProc( - s_Vk.handle, - "vkCreateDevice"); - - s_Vk.destroyDevice = (PFN_vkDestroyDevice)loadProc( - s_Vk.handle, - "vkDestroyDevice"); - - s_Vk.getDeviceQueue = (PFN_vkGetDeviceQueue)loadProc( - s_Vk.handle, - "vkGetDeviceQueue"); - - s_Vk.queueSubmit = (PFN_vkQueueSubmit)loadProc( - s_Vk.handle, - "vkQueueSubmit"); - - s_Vk.getDeviceProcAddr = (PFN_vkGetDeviceProcAddr)loadProc( - s_Vk.handle, - "vkGetDeviceProcAddr"); - - s_Vk.getImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)loadProc( - s_Vk.handle, - "vkGetImageMemoryRequirements"); - - s_Vk.allocateMemory = (PFN_vkAllocateMemory)loadProc( - s_Vk.handle, - "vkAllocateMemory"); - - s_Vk.freeMemory = (PFN_vkFreeMemory)loadProc( - s_Vk.handle, - "vkFreeMemory"); - - s_Vk.bindImageMemory = (PFN_vkBindImageMemory)loadProc( - s_Vk.handle, - "vkBindImageMemory"); - - s_Vk.createCommandPool = (PFN_vkCreateCommandPool)loadProc( - s_Vk.handle, - "vkCreateCommandPool"); - - s_Vk.destroyCommandPool = (PFN_vkDestroyCommandPool)loadProc( - s_Vk.handle, - "vkDestroyCommandPool"); - - s_Vk.allocateCommandBuffer = (PFN_vkAllocateCommandBuffers)loadProc( - s_Vk.handle, - "vkAllocateCommandBuffers"); - - s_Vk.freeCommandBuffer = (PFN_vkFreeCommandBuffers)loadProc( - s_Vk.handle, - "vkFreeCommandBuffers"); - - s_Vk.createFence = (PFN_vkCreateFence)loadProc( - s_Vk.handle, - "vkCreateFence"); - - s_Vk.destroyFence = (PFN_vkDestroyFence)loadProc( - s_Vk.handle, - "vkDestroyFence"); - - s_Vk.resetFence = (PFN_vkResetFences)loadProc( - s_Vk.handle, - "vkResetFences"); - - s_Vk.waitFence = (PFN_vkWaitForFences)loadProc( - s_Vk.handle, - "vkWaitForFences"); - - s_Vk.isFenceSignaled = (PFN_vkGetFenceStatus)loadProc( - s_Vk.handle, - "vkGetFenceStatus"); - - s_Vk.createSemaphore = (PFN_vkCreateSemaphore)loadProc( - s_Vk.handle, - "vkCreateSemaphore"); - - s_Vk.destroySemaphore = (PFN_vkDestroySemaphore)loadProc( - s_Vk.handle, - "vkDestroySemaphore"); - - s_Vk.cmdBegin = (PFN_vkBeginCommandBuffer)loadProc( - s_Vk.handle, - "vkBeginCommandBuffer"); - - s_Vk.cmdEnd = (PFN_vkEndCommandBuffer)loadProc( - s_Vk.handle, - "vkEndCommandBuffer"); - - s_Vk.resetCommandPool = (PFN_vkResetCommandPool)loadProc( - s_Vk.handle, - "vkResetCommandPool"); - - s_Vk.resetCommandBuffer = (PFN_vkResetCommandBuffer)loadProc( - s_Vk.handle, - "vkResetCommandBuffer"); - - s_Vk.cmdExecuteCommandBuffer = (PFN_vkCmdExecuteCommands)loadProc( - s_Vk.handle, - "vkCmdExecuteCommands"); - - s_Vk.cmdCopyBuffer = (PFN_vkCmdCopyBuffer)loadProc( - s_Vk.handle, - "vkCmdCopyBuffer"); - - s_Vk.cmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)loadProc( - s_Vk.handle, - "vkCmdCopyBufferToImage"); - - s_Vk.cmdCopyImage = (PFN_vkCmdCopyImage)loadProc( - s_Vk.handle, - "vkCmdCopyImage"); - - s_Vk.cmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)loadProc( - s_Vk.handle, - "vkCmdCopyImageToBuffer"); - - s_Vk.cmdBindPipeline = (PFN_vkCmdBindPipeline)loadProc( - s_Vk.handle, - "vkCmdBindPipeline"); - - s_Vk.cmdSetViewports = (PFN_vkCmdSetViewport)loadProc( - s_Vk.handle, - "vkCmdSetViewport"); - - s_Vk.cmdSetScissors = (PFN_vkCmdSetScissor)loadProc( - s_Vk.handle, - "vkCmdSetScissor"); - - s_Vk.cmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)loadProc( - s_Vk.handle, - "vkCmdBindVertexBuffers"); - - s_Vk.cmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)loadProc( - s_Vk.handle, - "vkCmdBindIndexBuffer"); - - s_Vk.cmdDraw = (PFN_vkCmdDraw)loadProc( - s_Vk.handle, - "vkCmdDraw"); - - s_Vk.cmdDrawIndirect = (PFN_vkCmdDrawIndirect)loadProc( - s_Vk.handle, - "vkCmdDrawIndirect"); - - s_Vk.cmdDrawIndexed = (PFN_vkCmdDrawIndexed)loadProc( - s_Vk.handle, - "vkCmdDrawIndexed"); - - s_Vk.cmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)loadProc( - s_Vk.handle, - "vkCmdDrawIndexedIndirect"); - - s_Vk.cmdDispatch = (PFN_vkCmdDispatch)loadProc( - s_Vk.handle, - "vkCmdDispatch"); - - s_Vk.cmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)loadProc( - s_Vk.handle, - "vkCmdDispatchIndirect"); - - s_Vk.cmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)loadProc( - s_Vk.handle, - "vkCmdBindDescriptorSets"); - - s_Vk.cmdPushConstants = (PFN_vkCmdPushConstants)loadProc( - s_Vk.handle, - "vkCmdPushConstants"); - - s_Vk.createBuffer = (PFN_vkCreateBuffer)loadProc( - s_Vk.handle, - "vkCreateBuffer"); - - s_Vk.destroyBuffer = (PFN_vkDestroyBuffer)loadProc( - s_Vk.handle, - "vkDestroyBuffer"); - - s_Vk.mapMemory = (PFN_vkMapMemory)loadProc( - s_Vk.handle, - "vkMapMemory"); - - s_Vk.unmapMemory = (PFN_vkUnmapMemory)loadProc( - s_Vk.handle, - "vkUnmapMemory"); - - s_Vk.getBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)loadProc( - s_Vk.handle, - "vkGetBufferDeviceAddress"); - - s_Vk.getBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)loadProc( - s_Vk.handle, - "vkGetBufferMemoryRequirements"); - - s_Vk.bindBufferMemory = (PFN_vkBindBufferMemory)loadProc( - s_Vk.handle, - "vkBindBufferMemory"); - - s_Vk.createDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)loadProc( - s_Vk.handle, - "vkCreateDescriptorSetLayout"); - - s_Vk.destroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)loadProc( - s_Vk.handle, - "vkDestroyDescriptorSetLayout"); - - s_Vk.createDescriptorPool = (PFN_vkCreateDescriptorPool)loadProc( - s_Vk.handle, - "vkCreateDescriptorPool"); - - s_Vk.destroyDescriptorPool = (PFN_vkDestroyDescriptorPool)loadProc( - s_Vk.handle, - "vkDestroyDescriptorPool"); - - s_Vk.resetDescriptorPool = (PFN_vkResetDescriptorPool)loadProc( - s_Vk.handle, - "vkResetDescriptorPool"); - - s_Vk.allocateDescriptorSet = (PFN_vkAllocateDescriptorSets)loadProc( - s_Vk.handle, - "vkAllocateDescriptorSets"); - - s_Vk.updateDescriptorSet = (PFN_vkUpdateDescriptorSets)loadProc( - s_Vk.handle, - "vkUpdateDescriptorSets"); - - s_Vk.createPipelineLayout = (PFN_vkCreatePipelineLayout)loadProc( - s_Vk.handle, - "vkCreatePipelineLayout"); - - s_Vk.destroyPipelineLayout = (PFN_vkDestroyPipelineLayout)loadProc( - s_Vk.handle, - "vkDestroyPipelineLayout"); - - s_Vk.createGraphicsPipeline = (PFN_vkCreateGraphicsPipelines)loadProc( - s_Vk.handle, - "vkCreateGraphicsPipelines"); - - s_Vk.createComputePipeline = (PFN_vkCreateComputePipelines)loadProc( - s_Vk.handle, - "vkCreateComputePipelines"); - - s_Vk.destroyPipeline = (PFN_vkDestroyPipeline)loadProc( - s_Vk.handle, - "vkDestroyPipeline"); - - s_Vk.waitQueue = (PFN_vkQueueWaitIdle)loadProc( - s_Vk.handle, - "vkQueueWaitIdle"); - // clang-format on - - // get version - PalBool versionFallback = PAL_FALSE; - uint32_t version = 0; - if (s_Vk.enumerateInstanceVersion) { - s_Vk.enumerateInstanceVersion(&version); - if (version <= VK_API_VERSION_1_0) { - versionFallback = PAL_TRUE; - } - } - - VkResult result; - uint32_t layerCount = 0; - PalBool hasValidationLayer = PAL_FALSE; - s_Vk.messenger = nullptr; - s_Vk.allocator = allocator; - VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {0}; - debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - - if (debugger && debugger->callback) { - // layers - result = s_Vk.enumerateInstanceLayerProperties(&layerCount, nullptr); - if (result == VK_SUCCESS) { - VkLayerProperties* props = nullptr; - props = palAllocate(s_Vk.allocator, sizeof(VkLayerProperties) * layerCount, 0); - if (!props) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_Vk.enumerateInstanceLayerProperties(&layerCount, props); - for (int i = 0; i < layerCount; i++) { - const char* name = props[i].layerName; - if (strcmp(name, "VK_LAYER_KHRONOS_validation") == 0) { - hasValidationLayer = PAL_TRUE; - break; - } - } - palFree(s_Vk.allocator, props); - - // message types - if (!debugger->denyGeneral) { - debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; - } - - if (!debugger->denyPerformance) { - debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - } - - if (!debugger->denyValidation) { - debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; - } - - // message severities - if (!debugger->denyInfoSeverity) { - debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; - } - - if (!debugger->denyWarningSeverity) { - debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; - } - - if (!debugger->denyErrorSeverity) { - debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - } - - debugCreateInfo.pUserData = debugger->userData; - debugCreateInfo.pfnUserCallback = debugCallbackVk; - s_Vk.callback = debugger->callback; - } - } - - // extensions - uint32_t extCount = 0; - const char* extensions[8]; - result = s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, nullptr); - if (result != VK_SUCCESS) { - return PAL_RESULT_PLATFORM_FAILURE; - } - - VkExtensionProperties* extensionProps = nullptr; - extensionProps = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extCount, 0); - if (!extensionProps) { - return PAL_RESULT_SUCCESS; - } - - PalBool hasXlib = PAL_FALSE; - PalBool hasXcb = PAL_FALSE; - PalBool hasWayland = PAL_FALSE; - PalBool hasWin32 = PAL_FALSE; - PalBool hasSurface = PAL_FALSE; - PalBool hasExtDebug = PAL_FALSE; - s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, extensionProps); - - for (int i = 0; i < extCount; i++) { - VkExtensionProperties* prop = &extensionProps[i]; - if (strcmp(prop->extensionName, "VK_KHR_xlib_surface") == 0) { - hasXlib = PAL_TRUE; - - } else if (strcmp(prop->extensionName, "VK_KHR_xcb_surface") == 0) { - hasXcb = PAL_TRUE; - - } else if (strcmp(prop->extensionName, "VK_KHR_wayland_surface") == 0) { - hasWayland = PAL_TRUE; - - } else if (strcmp(prop->extensionName, "VK_KHR_win32_surface") == 0) { - hasWin32 = PAL_TRUE; - - } else if (strcmp(prop->extensionName, "VK_KHR_surface") == 0) { - hasSurface = PAL_TRUE; - - } else if (strcmp(prop->extensionName, "VK_EXT_debug_utils") == 0) { - hasExtDebug = PAL_TRUE; - } - } - palFree(s_Vk.allocator, extensionProps); - - int extensionCount = 0; - if (hasSurface) { - extensions[extensionCount++] = "VK_KHR_surface"; - if (hasWayland) { - extensions[extensionCount++] = "VK_KHR_wayland_surface"; - } - - if (hasXlib) { - extensions[extensionCount++] = "VK_KHR_xlib_surface"; - } - - if (hasXcb) { - extensions[extensionCount++] = "VK_KHR_xcb_surface"; - } - - if (hasWin32) { - extensions[extensionCount++] = "VK_KHR_win32_surface"; - } - } - - const char* layers[2]; - layerCount = 0; - if (hasValidationLayer && hasExtDebug) { - extensions[extensionCount++] = "VK_EXT_debug_utils"; - layers[layerCount++] = "VK_LAYER_KHRONOS_validation"; - } - - if (versionFallback) { - const char* name = "VK_KHR_get_physical_device_properties2"; - extensions[extensionCount++] = name; - } - - VkApplicationInfo appInfo = {0}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.apiVersion = version; - appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.pEngineName = "Engine"; - appInfo.pApplicationName = "App"; - appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - - VkInstanceCreateInfo instanceCreateInfo = {0}; - instanceCreateInfo.pApplicationInfo = &appInfo; - instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instanceCreateInfo.enabledExtensionCount = extensionCount; - instanceCreateInfo.enabledLayerCount = layerCount; - instanceCreateInfo.ppEnabledExtensionNames = extensions; - instanceCreateInfo.ppEnabledLayerNames = layers; - - if (debugger && debugger->callback) { - instanceCreateInfo.pNext = &debugCreateInfo; - } - - // vk allocator - s_Vk.vkAllocator.pfnAllocation = allocateVk; - s_Vk.vkAllocator.pfnFree = freeVk; - s_Vk.vkAllocator.pfnReallocation = reallocVk; - - VkInstance instance = nullptr; - result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.vkAllocator, &instance); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - // clang-format off - if (versionFallback) { - // load get physical device properties2 proc if we are on version 1.0 - s_Vk.getPhysicalDeviceFeatures2 = - (PFN_vkGetPhysicalDeviceFeatures2KHR)s_Vk.getInstanceProcAddr( - s_Vk.handle, - "vkGetPhysicalDeviceFeatures2KHR"); - } - - // load surface creation function pointers - s_Vk.createWaylandSurface = nullptr; - s_Vk.createXlibSurface = nullptr; - s_Vk.createXcbSurface = nullptr; - s_Vk.createWin32Surface = nullptr; - - if (hasWayland) { - s_Vk.createWaylandSurface = (PFN_vkCreateWaylandSurfaceKHR)s_Vk.getInstanceProcAddr( - instance, - "vkCreateWaylandSurfaceKHR"); - } - - if (hasXlib) { - s_Vk.libX = loadLibrary("libX11.so"); - if (s_Vk.libX) { - s_Vk.XGetWindowAttributes = (XGetWindowAttributesFn)loadProc( - s_Vk.libX, - "XGetWindowAttributes"); - - s_Vk.XVisualIDFromVisual = (XVisualIDFromVisualFn)loadProc( - s_Vk.libX, - "XVisualIDFromVisual"); - } - - s_Vk.createXlibSurface = (PFN_vkCreateXlibSurfaceKHR)s_Vk.getInstanceProcAddr( - instance, - "vkCreateXlibSurfaceKHR"); - } - - if (hasXcb) { - s_Vk.libXcb = loadLibrary("libxcb.so.1"); - if (s_Vk.libXcb) { - s_Vk.xcbGetWindowAttributes = (xcb_get_window_attributes_fn)loadProc( - s_Vk.libXcb, - "xcb_get_window_attributes"); - - s_Vk.xcbGetWindowAttributesReply = (xcb_get_window_attributes_reply_fn)loadProc( - s_Vk.libXcb, - "xcb_get_window_attributes_reply"); - } - - s_Vk.createXcbSurface = (PFN_vkCreateXcbSurfaceKHR)s_Vk.getInstanceProcAddr( - instance, - "vkCreateXcbSurfaceKHR"); - } - - if (hasWin32) { - s_Vk.createWin32Surface = (PFN_vkCreateWin32SurfaceKHR)s_Vk.getInstanceProcAddr( - instance, - "vkCreateWin32SurfaceKHR"); - } - - // remaining function procs - s_Vk.destroySurface = (PFN_vkDestroySurfaceKHR)s_Vk.getInstanceProcAddr( - instance, - "vkDestroySurfaceKHR"); - - s_Vk.getSurfaceCapabilities = - (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)s_Vk.getInstanceProcAddr( - instance, - "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); - - s_Vk.getSurfacePresentModes = - (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)s_Vk.getInstanceProcAddr( - instance, - "vkGetPhysicalDeviceSurfacePresentModesKHR"); - - s_Vk.getSurfaceFormats = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)s_Vk.getInstanceProcAddr( - instance, - "vkGetPhysicalDeviceSurfaceFormatsKHR"); - - s_Vk.checkSurfaceSupport = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)s_Vk.getInstanceProcAddr( - instance, - "vkGetPhysicalDeviceSurfaceSupportKHR"); - - if (debugger) { - s_Vk.createMessenger = - (PFN_vkCreateDebugUtilsMessengerEXT)s_Vk.getInstanceProcAddr( - instance, - "vkCreateDebugUtilsMessengerEXT"); - - s_Vk.destroyMessenger = - (PFN_vkDestroyDebugUtilsMessengerEXT)s_Vk.getInstanceProcAddr( - instance, - "vkDestroyDebugUtilsMessengerEXT"); - - s_Vk.createMessenger(instance, &debugCreateInfo, &s_Vk.vkAllocator, &s_Vk.messenger); - } - // clang-format on - - s_Vk.adapters = nullptr; - s_Vk.instance = instance; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL shutdownGraphicsVk() -{ - if (s_Vk.messenger) { - s_Vk.destroyMessenger(s_Vk.instance, s_Vk.messenger, &s_Vk.vkAllocator); - } - - s_Vk.destroyInstance(s_Vk.instance, &s_Vk.vkAllocator); - freeLibrary(s_Vk.handle); - - if (s_Vk.libX) { - freeLibrary(s_Vk.libX); - } - - if (s_Vk.libXcb) { - freeLibrary(s_Vk.libXcb); - } - - if (s_Vk.adapters) { - palFree(s_Vk.allocator, s_Vk.adapters); - } - memset(&s_Vk, 0, sizeof(s_Vk)); -} - -PalResult PAL_CALL enumerateAdaptersVk( - int32_t* count, - PalAdapter** outAdapters) -{ - int deviceCount = 0; - int adapterCount = 0; - int extCount = 0; - VkResult ret; - VkExtensionProperties* exts = nullptr; - VkPhysicalDeviceProperties props = {0}; - - ret = s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, nullptr); - if (ret != VK_SUCCESS) { - return PAL_RESULT_PLATFORM_FAILURE; - } - - if (s_Vk.adapters) { - palFree(s_Vk.allocator, s_Vk.adapters); - } - - VkPhysicalDevice* devices = nullptr; - devices = palAllocate(s_Vk.allocator, sizeof(VkPhysicalDevice) * deviceCount, 0); - s_Vk.adapters = palAllocate(s_Vk.allocator, sizeof(Adapter) * deviceCount, 0); - if (!devices || !s_Vk.adapters) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, devices); - for (int i = 0; i < deviceCount; i++) { - VkPhysicalDevice phyDevice = devices[i]; - s_Vk.getPhysicalDeviceProperties(phyDevice, &props); - if (props.apiVersion < VK_API_VERSION_1_3) { - // check extension - ret = s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extCount, nullptr); - exts = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extCount, 0); - if (!exts) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - PalBool found = PAL_FALSE; - s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extCount, exts); - - for (int i = 0; i < extCount; i++) { - const char* ext = exts[i].extensionName; - if (strcmp(ext, "VK_KHR_dynamic_rendering") == 0) { - found = PAL_TRUE; - break; - } - } - - palFree(s_Vk.allocator, exts); - if (!found) { - continue; - } - } - - VkPhysicalDeviceDynamicRenderingFeaturesKHR required = {0}; - required.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; - - VkPhysicalDeviceFeatures2KHR features = {0}; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; - features.pNext = &required; - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - - if (!required.dynamicRendering) { - continue; - } - - if (outAdapters) { - if (adapterCount < *count) { - Adapter* tmp = &s_Vk.adapters[adapterCount]; - tmp->handle = devices[i]; - outAdapters[adapterCount] = (PalAdapter*)tmp; - } - } - adapterCount++; - } - - if (!outAdapters) { - *count = adapterCount; - } - - palFree(s_Vk.allocator, devices); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL getAdapterInfoVk( - PalAdapter* adapter, - PalAdapterInfo* info) -{ - Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; - VkPhysicalDeviceProperties props = {0}; - VkPhysicalDeviceMemoryProperties memProps = {0}; - - s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); - s_Vk.getPhysicalDeviceProperties(phyDevice, &props); - - info->apiType = PAL_ADAPTER_API_TYPE_VULKAN; - info->shaderFormats = PAL_SHADER_FORMAT_SPIRV; - info->deviceId = props.deviceID; - info->vendorId = props.vendorID; - strcpy(info->name, props.deviceName); - strcpy(info->backendName, "PAL"); - - info->vram = 0; - info->sharedMemory = 0; - for (int i = 0; i < memProps.memoryHeapCount; i++) { - if (memProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { - info->vram += memProps.memoryHeaps[i].size; - } else { - info->sharedMemory += memProps.memoryHeaps[i].size; - } - } - - // get device type - switch (props.deviceType) { - case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { - info->type = PAL_ADAPTER_TYPE_INTEGRATED; - break; - } - - case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { - info->type = PAL_ADAPTER_TYPE_DISCRETE; - break; - } - - case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { - info->type = PAL_ADAPTER_TYPE_VIRTUAL; - break; - } - - case VK_PHYSICAL_DEVICE_TYPE_CPU: { - info->type = PAL_ADAPTER_TYPE_CPU; - break; - } - - default: { - info->type = PAL_ADAPTER_TYPE_UNKNOWN; - break; - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL getAdapterCapabilitiesVk( - PalAdapter* adapter, - PalAdapterCapabilities* caps) -{ - VkResult result = VK_SUCCESS; - Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; - - VkPhysicalDeviceProperties props = {0}; - s_Vk.getPhysicalDeviceProperties(phyDevice, &props); - VkPhysicalDeviceLimits* limits = &props.limits; - - VkPhysicalDeviceFeatures fts = {0}; - s_Vk.getPhysicalDeviceFeatures(phyDevice, &fts); - - VkPhysicalDeviceProperties2 properties2 = {0}; - properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - - VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; - accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; - properties2.pNext = &accProps; - s_Vk.getPhysicalDeviceProperties2(phyDevice, &properties2); - - PalViewportCapabilities* viewportCaps = &caps->viewportCaps; - PalImageCapabilities* imageCaps = &caps->imageCaps; - PalResourceCapabilities* resourceCaps = &caps->resourceCaps; - PalComputeCapabilities* computeCaps = &caps->computeCaps; - - // get supported queue commands - uint32_t count = 0; - s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &count, nullptr); - - VkQueueFamilyProperties* queueProps = nullptr; - queueProps = palAllocate(s_Vk.allocator, sizeof(VkQueueFamilyProperties) * count, 0); - s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &count, queueProps); - - caps->maxComputeQueues = 0; - caps->maxGraphicsQueues = 0; - caps->maxCopyQueues = 0; - - for (int i = 0; i < count; i++) { - if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { - caps->maxComputeQueues += queueProps->queueCount; - } - - if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - caps->maxGraphicsQueues += queueProps->queueCount; - } - - if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { - caps->maxCopyQueues += queueProps->queueCount; - } - } - - caps->maxColorAttachments = limits->maxColorAttachments; - caps->maxUniformBufferSize = limits->maxUniformBufferRange; - caps->maxStorageBufferSize = limits->maxStorageBufferRange; - caps->maxPushConstantSize = limits->maxPushConstantsSize; - - caps->maxVertexLayouts = limits->maxVertexInputBindings; - caps->maxVertexAttributes = limits->maxVertexInputAttributes; - caps->maxTessellationPatchPoint = limits->maxTessellationPatchSize; - - // viewport limits - viewportCaps->maxWidth = limits->maxViewportDimensions[0]; - viewportCaps->maxHeight = limits->maxViewportDimensions[1]; - viewportCaps->minBoundsRange = limits->viewportBoundsRange[0]; - viewportCaps->maxBoundsRange = limits->viewportBoundsRange[1]; - - // image limits - imageCaps->maxWidth = limits->maxImageDimension2D; - imageCaps->maxHeight = limits->maxImageDimension2D; - imageCaps->maxDepth = limits->maxImageDimension3D; - imageCaps->maxArrayLayers = limits->maxImageArrayLayers; - - // vulkan does not give this but we calculate from the max width and width - uint32_t a = imageCaps->maxWidth; - uint32_t b = imageCaps->maxHeight; - uint32_t c = imageCaps->maxDepth; - - uint32_t tmp = a > b ? a : b; - uint32_t size = tmp > c ? tmp : c; - uint32_t levels = 0; - while (size > 0) { - // divide by two - size = size / 2; - levels++; - } - imageCaps->maxMipLevels = levels; - - // resource limits - resourceCaps->sampledImageDynamicArrayIndexing = fts.shaderSampledImageArrayDynamicIndexing; - resourceCaps->storageImageDynamicArrayIndexing = fts.shaderStorageImageArrayDynamicIndexing; - resourceCaps->storageBufferDynamicArrayIndexing = fts.shaderStorageBufferArrayDynamicIndexing; - resourceCaps->uniformBufferDynamicArrayIndexing = fts.shaderUniformBufferArrayDynamicIndexing; - - resourceCaps->maxPerStageSampledImages = limits->maxPerStageDescriptorSampledImages; - resourceCaps->maxPerSetSampledImages = limits->maxDescriptorSetSampledImages; - resourceCaps->maxPerStageStorageImages = limits->maxPerStageDescriptorStorageImages; - resourceCaps->maxPerSetStorageImages = limits->maxDescriptorSetStorageImages; - - resourceCaps->maxPerStageSamplers = limits->maxPerStageDescriptorSamplers; - resourceCaps->maxPerSetSamplers = limits->maxDescriptorSetSamplers; - resourceCaps->maxPerStageStorageBuffers = limits->maxPerStageDescriptorStorageBuffers; - resourceCaps->maxPerSetStorageBuffers = limits->maxDescriptorSetStorageBuffers; - - resourceCaps->maxPerStageUniformBuffers = limits->maxPerStageDescriptorUniformBuffers; - resourceCaps->maxPerSetUniformBuffers = limits->maxDescriptorSetUniformBuffers; - - tmp = accProps.maxPerStageDescriptorAccelerationStructures; - resourceCaps->maxPerStageAccelerationStructure = tmp; - resourceCaps->maxPerSetAccelerationStructure = accProps.maxDescriptorSetAccelerationStructures; - resourceCaps->maxBoundSets = limits->maxBoundDescriptorSets; - - // compute limits - computeCaps->maxWorkGroupInvocations = limits->maxComputeWorkGroupInvocations; - computeCaps->maxWorkGroupCount[0] = limits->maxComputeWorkGroupCount[0]; - computeCaps->maxWorkGroupCount[1] = limits->maxComputeWorkGroupCount[1]; - computeCaps->maxWorkGroupCount[2] = limits->maxComputeWorkGroupCount[2]; - computeCaps->maxWorkGroupSize[0] = limits->maxComputeWorkGroupSize[0]; - computeCaps->maxWorkGroupSize[1] = limits->maxComputeWorkGroupSize[1]; - computeCaps->maxWorkGroupSize[2] = limits->maxComputeWorkGroupSize[2]; - - palFree(s_Vk.allocator, queueProps); - return PAL_RESULT_SUCCESS; -} - -PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) -{ - VkResult result; - PalAdapterFeatures adapterFeatures = 0; - uint32_t extensionCount = 0; - VkPhysicalDeviceProperties props = {0}; - - Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; - - // get supported extensions - s_Vk.getPhysicalDeviceProperties(phyDevice, &props); - result = s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, nullptr); - if (result != VK_SUCCESS) { - // we just return without any modern features which is rare - return 0; - } - - VkExtensionProperties* extensionProps = nullptr; - extensionProps = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extensionCount, 0); - if (!extensionProps) { - return 0; - } - - // check extensions - PalBool rayTracing = PAL_FALSE; - PalBool accelerationStructure = PAL_FALSE; - PalBool meshShader = PAL_FALSE; - PalBool fragmentRateShading = PAL_FALSE; - PalBool timelineSemaphore = PAL_FALSE; - PalBool descriptorIndexing = PAL_FALSE; - PalBool shaderFloat16 = PAL_FALSE; - PalBool multiiView = PAL_FALSE; - PalBool dynamicstate = PAL_FALSE; - PalBool bufferDeviceAddress = PAL_FALSE; - PalBool shaderParameters = PAL_FALSE; - PalBool nullDescriptors = PAL_FALSE; - PalBool rayQuery = PAL_FALSE; - s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, extensionProps); - - // clang-format off - // check if the extensions are present - for (int i = 0; i < extensionCount; i++) { - VkExtensionProperties* props = &extensionProps[i]; - if (strcmp(props->extensionName, "VK_KHR_ray_tracing_pipeline") == 0) { - rayTracing = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_KHR_acceleration_structure") == 0) { - accelerationStructure = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_EXT_mesh_shader") == 0) { - meshShader = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_KHR_fragment_shading_rate") == 0) { - fragmentRateShading = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_EXT_descriptor_indexing") == 0) { - descriptorIndexing = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_KHR_swapchain") == 0) { - adapterFeatures |= PAL_ADAPTER_FEATURE_SWAPCHAIN; - - } else if (strcmp(props->extensionName, "VK_KHR_shader_float16_int8") == 0) { - shaderFloat16 = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_KHR_timeline_semaphore") == 0) { - timelineSemaphore = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_KHR_multiview") == 0) { - multiiView = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_EXT_extended_dynamic_state") == 0) { - dynamicstate = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_EXT_extended_dynamic_state2") == 0) { - VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynState2 = {0}; - dynState2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &dynState2; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (dynState2.extendedDynamicState2) { - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE; - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE; - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP; - } - - } else if (strcmp(props->extensionName, "VK_KHR_depth_stencil_resolve") == 0) { - adapterFeatures |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; - - } else if (strcmp(props->extensionName, "VK_KHR_draw_indirect_count") == 0) { - adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; - - } else if (strcmp(props->extensionName, "VK_KHR_draw_mesh_tasks_indirect_count") == 0) { - adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT; - - } else if (strcmp(props->extensionName, "VK_KHR_buffer_device_address") == 0) { - bufferDeviceAddress = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_KHR_shader_draw_parameters") == 0) { - shaderParameters = PAL_TRUE; - - } else if (strcmp(props->extensionName, "VK_EXT_robustness2") == 0) { - nullDescriptors = PAL_TRUE; - } - } - - // features that require additional checks - if (rayTracing && accelerationStructure) { - VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; - VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; - - ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - - ray.pNext = &acc; - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &ray; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (ray.rayTracingPipeline && acc.accelerationStructure) { - adapterFeatures |= PAL_ADAPTER_FEATURE_RAY_TRACING; - } - - if (ray.rayTracingPipelineTraceRaysIndirect) { - adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING; - } - } - - if (meshShader) { - VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; - mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &mesh; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (mesh.meshShader && mesh.taskShader) { - adapterFeatures |= PAL_ADAPTER_FEATURE_MESH_SHADER; - adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH; - } - } - - if (fragmentRateShading) { - VkPhysicalDeviceFragmentShadingRateFeaturesKHR frag = {0}; - frag.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &frag; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (frag.pipelineFragmentShadingRate) { - adapterFeatures |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE; - } - - if (frag.attachmentFragmentShadingRate) { - adapterFeatures |= - PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT; - } - } - - if (props.apiVersion >= VK_API_VERSION_1_2 || descriptorIndexing) { - VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; - desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &desc; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - // core features we need - if (desc.runtimeDescriptorArray || - desc.descriptorBindingUpdateUnusedWhilePending) { - adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - } - - if (desc.descriptorBindingPartiallyBound) { - adapterFeatures |= PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; - } - } - - if (props.apiVersion >= VK_API_VERSION_1_2 || timelineSemaphore) { - VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline = {0}; - timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &timeline; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (timeline.timelineSemaphore) { - adapterFeatures |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; - } - } - - if (props.apiVersion >= VK_API_VERSION_1_2 || shaderFloat16) { - VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; - shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &shader16; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (shader16.shaderFloat16) { - adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_FLOAT16; - } - } - - if (props.apiVersion >= VK_API_VERSION_1_1 || multiiView) { - VkPhysicalDeviceMultiviewFeaturesKHR multiView = {0}; - multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &multiView; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (multiView.multiview) { - adapterFeatures |= PAL_ADAPTER_FEATURE_MULTI_VIEW; - } - } - - if (props.apiVersion >= VK_API_VERSION_1_3 || dynamicstate) { - VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynState = {0}; - dynState.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &dynState; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (dynState.extendedDynamicState) { - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE; - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE; - adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY; - } - } - - if (props.apiVersion >= VK_API_VERSION_1_2 || bufferDeviceAddress) { - VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; - bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &bufferAddress; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (bufferAddress.bufferDeviceAddress) { - adapterFeatures |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; - } - } - - if (props.apiVersion >= VK_API_VERSION_1_2) { - VkPhysicalDeviceVulkan12Features features12 = {0}; - features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &features12; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (features12.drawIndirectCount) { - adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; - } - } - - if (props.apiVersion >= VK_API_VERSION_1_2 || shaderParameters) { - VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {0}; - drawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &drawParameters; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (drawParameters.shaderDrawParameters) { - adapterFeatures |= PAL_ADAPTER_FEATURE_DISPATCH_BASE; - } - } - - if (nullDescriptors) { - VkPhysicalDeviceRobustness2FeaturesEXT nullDescriptors = {0}; - nullDescriptors.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &nullDescriptors; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (nullDescriptors.nullDescriptor) { - adapterFeatures |= PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS; - } - } - - if (rayQuery) { - VkPhysicalDeviceRayQueryFeaturesKHR query = {0}; - query.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &query; - - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - if (query.rayQuery) { - adapterFeatures |= PAL_ADAPTER_FEATURE_RAY_QUERY; - } - } - // clang-format on - - VkPhysicalDeviceFeatures features; - s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); - - // check for additional features - if (features.multiViewport) { - adapterFeatures |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; - } - - if (features.samplerAnisotropy) { - adapterFeatures |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; - } - - if (features.sampleRateShading) { - adapterFeatures |= PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING; - } - - if (features.shaderFloat64) { - adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_FLOAT64; - } - - if (features.shaderInt64) { - adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_INT64; - } - - if (features.shaderInt16) { - adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_INT16; - } - - if (features.geometryShader) { - adapterFeatures |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; - } - - if (features.tessellationShader) { - adapterFeatures |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; - } - - if (features.fillModeNonSolid) { - adapterFeatures |= PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE; - } - - // this features are supported on vulkan - adapterFeatures |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; - adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; - adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; - adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH; - - palFree(s_Vk.allocator, extensionProps); - return adapterFeatures; -} - -uint32_t PAL_CALL getHighestSupportedShaderTargetVk( - PalAdapter* adapter, - PalShaderFormats shaderFormat) -{ - if (shaderFormat != PAL_SHADER_FORMAT_SPIRV) { - return 0; - } - - Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDeviceProperties props = {0}; - s_Vk.getPhysicalDeviceProperties(vkAdapter->handle, &props); - - if (props.apiVersion >= VK_API_VERSION_1_3) { - return PAL_MAKE_SHADER_TARGET(1, 6); - - } else if (props.apiVersion >= VK_API_VERSION_1_2) { - return PAL_MAKE_SHADER_TARGET(1, 5); - - } else if (props.apiVersion >= VK_API_VERSION_1_1) { - return PAL_MAKE_SHADER_TARGET(1, 4); - - } else if (props.apiVersion >= VK_API_VERSION_1_0) { - return PAL_MAKE_SHADER_TARGET(1, 2); - } - - return 0; -} - -// ================================================== -// Device -// ================================================== - -PalResult PAL_CALL createDeviceVk( - PalAdapter* adapter, - PalAdapterFeatures features, - PalDevice** outDevice) -{ - float priority = 1.0f; - uint32_t phyQueueCount = 0; - uint32_t queueFamilyCount = 0; - VkResult result = VK_SUCCESS; - Device* device = nullptr; - VkPhysicalDeviceProperties props = {0}; - - Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; - s_Vk.getPhysicalDeviceProperties(phyDevice, &props); - - VkQueueFamilyProperties* queueFamilyProps = nullptr; - VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; - s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueFamilyCount, nullptr); - - uint32_t queueFamilySize = sizeof(VkQueueFamilyProperties) * queueFamilyCount; - uint32_t queueCreateInfosSize = sizeof(VkDeviceQueueCreateInfo) * queueFamilyCount; - - queueFamilyProps = palAllocate(s_Vk.allocator, queueFamilySize, 0); - queueCreateInfos = palAllocate(s_Vk.allocator, queueCreateInfosSize, 0); - device = palAllocate(s_Vk.allocator, sizeof(Device), 0); - if (!queueFamilyProps || !queueCreateInfos || !device) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(device, 0, sizeof(Device)); - device->phyDevice = phyDevice; - s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueFamilyCount, queueFamilyProps); - for (int i = 0; i < queueFamilyCount; i++) { - queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfos[i].pNext = nullptr; - queueCreateInfos[i].pQueuePriorities = &priority; - queueCreateInfos[i].queueFamilyIndex = i; - queueCreateInfos[i].queueCount = queueFamilyProps[i].queueCount; - queueCreateInfos[i].flags = 0; - - // we need the total number of physical queues - phyQueueCount += queueFamilyProps[i].queueCount; - } - - device->phyQueues = palAllocate(s_Vk.allocator, sizeof(PhysicalQueue) * phyQueueCount, 0); - if (!device->phyQueues) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // build features and extensions capabilities - VkPhysicalDeviceFeatures phyDeviceFeatures = {0}; - s_Vk.getPhysicalDeviceFeatures(phyDevice, &phyDeviceFeatures); - - VkPhysicalDeviceFeatures coreFeatures = {0}; - if (features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { - coreFeatures.samplerAnisotropy = PAL_TRUE; - } - - if (features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { - coreFeatures.sampleRateShading = PAL_TRUE; - } - - if (features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { - coreFeatures.multiViewport = PAL_TRUE; - } - - if (features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { - coreFeatures.tessellationShader = PAL_TRUE; - } - - if (features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { - coreFeatures.geometryShader = PAL_TRUE; - } - - if (features & PAL_ADAPTER_FEATURE_SHADER_INT16) { - coreFeatures.shaderInt16 = PAL_TRUE; - } - - if (features & PAL_ADAPTER_FEATURE_SHADER_INT64) { - coreFeatures.shaderInt64 = PAL_TRUE; - } - - if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT64) { - coreFeatures.shaderFloat64 = PAL_TRUE; - } - - // clang-format off - coreFeatures.shaderSampledImageArrayDynamicIndexing = phyDeviceFeatures.shaderSampledImageArrayDynamicIndexing; - coreFeatures.shaderStorageImageArrayDynamicIndexing = phyDeviceFeatures.shaderStorageImageArrayDynamicIndexing; - coreFeatures.shaderStorageBufferArrayDynamicIndexing = phyDeviceFeatures.shaderStorageBufferArrayDynamicIndexing; - coreFeatures.shaderUniformBufferArrayDynamicIndexing = phyDeviceFeatures.shaderUniformBufferArrayDynamicIndexing; - // clang-format on - - // extensions and features2 - void* next = nullptr; - int extCount = 0; - const char* extensions[32] = {0}; - - VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline = {0}; - timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; - - VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; - shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; - - VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; - mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; - - VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; - VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; - ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - - VkPhysicalDeviceFragmentShadingRateFeaturesKHR fsr = {0}; - fsr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; - - VkPhysicalDeviceDescriptorIndexingFeatures descIndex = {0}; - descIndex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; - - VkPhysicalDeviceMultiviewFeatures multiView = {0}; - multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - - VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamicState = {0}; - dynamicState.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; - - VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynamicState2 = {0}; - dynamicState2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; - - VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; - bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; - - VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRendering = {0}; - dynamicRendering.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; - - VkPhysicalDeviceSynchronization2FeaturesKHR sync2 = {0}; - sync2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR; - - VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {0}; - drawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; - - VkPhysicalDeviceRobustness2FeaturesEXT nullDescriptors = {0}; - nullDescriptors.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; - - if (props.apiVersion < VK_API_VERSION_1_3) { - extensions[extCount++] = "VK_KHR_dynamic_rendering"; - extensions[extCount++] = "VK_KHR_synchronization2"; - } - - dynamicRendering.dynamicRendering = PAL_TRUE; - sync2.synchronization2 = PAL_TRUE; - - dynamicRendering.pNext = next; - sync2.pNext = &dynamicRendering; - next = &sync2; - - if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { - extensions[extCount++] = "VK_KHR_swapchain"; - } - - if (features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE) { - extensions[extCount++] = "VK_KHR_depth_stencil_resolve"; - } - - if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_KHR_timeline_semaphore"; - } - timeline.timelineSemaphore = PAL_TRUE; - - timeline.pNext = next; - next = &timeline; - } - - if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_KHR_shader_float16_int8"; - } - shader16.shaderFloat16 = PAL_TRUE; - - shader16.pNext = next; - next = &shader16; - } - - if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; - extensions[extCount++] = "VK_KHR_acceleration_structure"; - extensions[extCount++] = "VK_KHR_deferred_host_operations"; - ray.rayTracingPipeline = PAL_TRUE; - acc.accelerationStructure = PAL_TRUE; - - ray.pNext = next; - acc.pNext = &ray; - next = &acc; - } - - if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { - extensions[extCount++] = "VK_EXT_mesh_shader"; - mesh.meshShader = PAL_TRUE; - mesh.taskShader = PAL_TRUE; - - // mesh shader needs geometry feature for primitives - coreFeatures.geometryShader = PAL_TRUE; - - // msh draw indirect count - if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT) { - extensions[extCount++] = "VK_KHR_draw_mesh_tasks_indirect_count"; - } - - mesh.pNext = next; - next = &mesh; - } - - if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_KHR_draw_indirect_count"; - } - } - - if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || - (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { - extensions[extCount++] = "VK_KHR_fragment_shading_rate"; - fsr.pipelineFragmentShadingRate = PAL_TRUE; - - // fragment shading rate attachment needs this - if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { - fsr.attachmentFragmentShadingRate = PAL_TRUE; - } - - fsr.pNext = next; - next = &fsr; - } - - if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_EXT_descriptor_indexing"; - } - - // check support for sub features - VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; - desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features.pNext = &desc; - s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - - // clang-format off - descIndex.runtimeDescriptorArray = desc.runtimeDescriptorArray; - descIndex.descriptorBindingUpdateUnusedWhilePending = desc.descriptorBindingUpdateUnusedWhilePending; - - descIndex.shaderSampledImageArrayNonUniformIndexing = desc.shaderSampledImageArrayNonUniformIndexing; - descIndex.descriptorBindingSampledImageUpdateAfterBind = desc.descriptorBindingSampledImageUpdateAfterBind; - - descIndex.shaderStorageImageArrayNonUniformIndexing = desc.shaderStorageImageArrayNonUniformIndexing; - descIndex.descriptorBindingStorageImageUpdateAfterBind = desc.descriptorBindingStorageImageUpdateAfterBind; - - descIndex.shaderStorageBufferArrayNonUniformIndexing = desc.shaderStorageBufferArrayNonUniformIndexing; - descIndex.descriptorBindingStorageBufferUpdateAfterBind = desc.descriptorBindingStorageBufferUpdateAfterBind; - - descIndex.shaderUniformBufferArrayNonUniformIndexing = desc.shaderUniformBufferArrayNonUniformIndexing; - descIndex.descriptorBindingUniformBufferUpdateAfterBind = desc.descriptorBindingUniformBufferUpdateAfterBind; - // clang-format on - - descIndex.pNext = next; - next = &descIndex; - } - - if (features & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS) { - if (!(features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_EXT_descriptor_indexing"; - } - - descIndex.pNext = next; - next = &descIndex; - } - - descIndex.descriptorBindingPartiallyBound = PAL_TRUE; - } - - if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_KHR_multiview"; - } - multiView.multiview = PAL_TRUE; - - multiView.pNext = next; - next = &multiView; - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE || - features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE || - features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { - if (props.apiVersion < VK_API_VERSION_1_3) { - extensions[extCount++] = "VK_EXT_extended_dynamic_state"; - } - dynamicState.extendedDynamicState = PAL_TRUE; - - dynamicState.pNext = next; - next = &dynamicState; - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE || - features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE || - features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { - extensions[extCount++] = "VK_EXT_extended_dynamic_state2"; - dynamicState2.extendedDynamicState2 = PAL_TRUE; - - dynamicState2.pNext = next; - next = &dynamicState2; - } - - if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_KHR_buffer_device_address"; - } - bufferAddress.bufferDeviceAddress = PAL_TRUE; - - bufferAddress.pNext = next; - next = &bufferAddress; - } - - if (features & PAL_ADAPTER_FEATURE_DISPATCH_BASE) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_KHR_shader_draw_parameters"; - } - drawParameters.shaderDrawParameters = PAL_TRUE; - - drawParameters.pNext = next; - next = &drawParameters; - } - - if (features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS) { - extensions[extCount++] = "VK_EXT_robustness2"; - nullDescriptors.nullDescriptor = PAL_TRUE; - - nullDescriptors.pNext = next; - next = &nullDescriptors; - } - - VkDeviceCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - createInfo.pEnabledFeatures = &coreFeatures; - createInfo.enabledExtensionCount = extCount; - createInfo.ppEnabledExtensionNames = extensions; - createInfo.pQueueCreateInfos = queueCreateInfos; - createInfo.queueCreateInfoCount = queueFamilyCount; - createInfo.pNext = next; - - result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.vkAllocator, &device->handle); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, queueFamilyProps); - palFree(s_Vk.allocator, queueCreateInfos); - palFree(s_Vk.allocator, device->phyQueues); - palFree(s_Vk.allocator, device); - return makeResultVk(result); - } - - device->phyQueueIndex = 0; - device->queueFamilyCount = queueFamilyCount; - device->phyQueueCount = phyQueueCount; - device->features = features; - - // get queues - for (int i = 0; i < queueFamilyCount; i++) { - VkQueueFamilyProperties* data = &queueFamilyProps[i]; - for (int j = 0; j < data->queueCount; j++) { - PhysicalQueue* queue = &device->phyQueues[i]; - s_Vk.getDeviceQueue(device->handle, i, j, &queue->handle); - queue->usages = data->queueFlags; - queue->usedUsages = 0; - queue->familyIndex = i; - queue->phyDevice = phyDevice; - } - } - - // cache memory type indices - VkPhysicalDeviceMemoryProperties memProps = {0}; - s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); - - memset(device->memoryClassMask, 0, sizeof(uint32_t) * 3); - for (int i = 0; i < memProps.memoryTypeCount; i++) { - VkMemoryPropertyFlags flags = memProps.memoryTypes[i].propertyFlags; - - uint32_t bit = (1u << i); - if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) && - !(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { - device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] |= bit; - } - - if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { - device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] |= bit; - } - - if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && - (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)) { - device->memoryClassMask[PAL_MEMORY_TYPE_CPU_READBACK] |= bit; - } - } - - // HACK: most CPU drivers dont have a vram so we set the vram to system memory - if (device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] == 0) { - device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] = - device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD]; - } - - // clang-format off - // swapchain procs - if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { - device->acquireNextImage = (PFN_vkAcquireNextImageKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkAcquireNextImageKHR"); - - device->createSwapchain = (PFN_vkCreateSwapchainKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCreateSwapchainKHR"); - - device->destroySwapchain = (PFN_vkDestroySwapchainKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkDestroySwapchainKHR"); - - device->getSwapchainImages = (PFN_vkGetSwapchainImagesKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetSwapchainImagesKHR"); - - device->queuePresent = (PFN_vkQueuePresentKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkQueuePresentKHR"); - } - - // semaphore procs - if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - device->waitSemaphore = (PFN_vkWaitSemaphores)s_Vk.getDeviceProcAddr( - device->handle, - "vkWaitSemaphores"); - - device->signalSemaphore = (PFN_vkSignalSemaphore)s_Vk.getDeviceProcAddr( - device->handle, - "vkSignalSemaphore"); - - device->getSemaphoreValue = (PFN_vkGetSemaphoreCounterValue)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetSemaphoreCounterValue"); - - if (!device->waitSemaphore) { - device->waitSemaphore = (PFN_vkWaitSemaphoresKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkWaitSemaphoresKHR"); - - device->signalSemaphore = (PFN_vkSignalSemaphoreKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkSignalSemaphoreKHR"); - - device->getSemaphoreValue = (PFN_vkGetSemaphoreCounterValueKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetSemaphoreCounterValueKHR"); - } - } - - // fragment shading rate procs - if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { - device->cmdSetFragmentShadingRate = - (PFN_vkCmdSetFragmentShadingRateKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdSetFragmentShadingRateKHR"); - } - - // mesh shader procs - if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { - device->cmdDrawMeshTask = (PFN_vkCmdDrawMeshTasksEXT)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdDrawMeshTasksEXT"); - - device->cmdDrawMeshTaskIndirect = - (PFN_vkCmdDrawMeshTasksIndirectEXT)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdDrawMeshTasksIndirectEXT"); - - device->cmdDrawMeshTaskIndirectCount = - (PFN_vkCmdDrawMeshTasksIndirectCountEXT)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdDrawMeshTasksIndirectCountEXT"); - } - - // ray tracing procs - device->limits.maxPayloadSize = 0; - if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - device->limits.maxPayloadSize = 64; - - device->createAccelerationStructure = - (PFN_vkCreateAccelerationStructureKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCreateAccelerationStructureKHR"); - - device->destroyAccelerationStructure = - (PFN_vkDestroyAccelerationStructureKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkDestroyAccelerationStructureKHR"); - - device->getAccelerationBuildsize = - (PFN_vkGetAccelerationStructureBuildSizesKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetAccelerationStructureBuildSizesKHR"); - - device->cmdBuildAccelerationStructures = - (PFN_vkCmdBuildAccelerationStructuresKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdBuildAccelerationStructuresKHR"); - - device->getAccelerationDeviceAddress = - (PFN_vkGetAccelerationStructureDeviceAddressKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetAccelerationStructureDeviceAddressKHR"); - - device->cmdTraceRays = - (PFN_vkCmdTraceRaysKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdTraceRaysKHR"); - - device->createRayTracingPipeline = - (PFN_vkCreateRayTracingPipelinesKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCreateRayTracingPipelinesKHR"); - - device->cmdTraceRaysIndirect = - (PFN_vkCmdTraceRaysIndirectKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdTraceRaysIndirectKHR"); - - device->getRayTracingShaderGroupHandles = - (PFN_vkGetRayTracingShaderGroupHandlesKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetRayTracingShaderGroupHandlesKHR"); - } - - // buffer address procs - if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { - device->getBufferrAddress = - (PFN_vkGetBufferDeviceAddress)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetBufferDeviceAddress"); - - if (!device->getBufferrAddress) { - device->getBufferrAddress = - (PFN_vkGetBufferDeviceAddressKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkGetBufferDeviceAddressKHR"); - } - } - - // indirect draw count procs - if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { - device->cmdDrawIndirectCount = - (PFN_vkCmdDrawIndirectCount)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdDrawIndirectCount"); - - device->cmdDrawIndexedIndirectCount = - (PFN_vkCmdDrawIndexedIndirectCount)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdDrawIndexedIndirectCount"); - - if (!device->cmdDrawIndirectCount) { - device->cmdDrawIndirectCount = - (PFN_vkCmdDrawIndirectCountKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdDrawIndirectCountKHR"); - - device->cmdDrawIndexedIndirectCount = - (PFN_vkCmdDrawIndexedIndirectCountKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdDrawIndexedIndirectCountKHR"); - } - } - - // dispatch base procs - if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { - device->cmdDispatchBase = - (PFN_vkCmdDispatchBase)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdDispatchBase"); - - if (!device->cmdDispatchBase) { - device->cmdDispatchBase = - (PFN_vkCmdDispatchBaseKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdDispatchBaseKHR"); - } - } - - // dynamic rendering procs - device->cmdBeginRendering = - (PFN_vkCmdBeginRendering)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdBeginRendering"); - - device->cmdEndRendering = - (PFN_vkCmdEndRendering)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdEndRendering"); - - device->cmdPipelineBarrier = - (PFN_vkCmdPipelineBarrier2)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdPipelineBarrier2"); - - device->queueSubmit = - (PFN_vkQueueSubmit2)s_Vk.getDeviceProcAddr( - device->handle, - "vkQueueSubmit2"); - - if (!device->cmdBeginRendering) { - device->cmdBeginRendering = - (PFN_vkCmdBeginRenderingKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdBeginRenderingKHR"); - - device->cmdEndRendering = - (PFN_vkCmdEndRenderingKHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdEndRenderingKHR"); - - device->cmdPipelineBarrier = - (PFN_vkCmdPipelineBarrier2KHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdPipelineBarrier2KHR"); - - device->queueSubmit = - (PFN_vkQueueSubmit2KHR)s_Vk.getDeviceProcAddr( - device->handle, - "vkQueueSubmit2KHR"); - } - - // dynamic states - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { - device->cmdSetCullMode = - (PFN_vkCmdSetCullMode)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdSetCullMode"); - - if (!device->cmdSetCullMode) { - device->cmdSetCullMode = - (PFN_vkCmdSetCullModeEXT)s_Vk.getDeviceProcAddr( - device->handle, - "vkCmdSetCullModeEXT"); - } - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { - device->cmdSetFrontFace = - (PFN_vkCmdSetFrontFace)s_Vk.getDeviceProcAddr( - device->handle, - "vkcmdSetFrontFace"); - - if (!device->cmdSetFrontFace) { - device->cmdSetFrontFace = - (PFN_vkCmdSetFrontFaceEXT)s_Vk.getDeviceProcAddr( - device->handle, - "vkcmdSetFrontFaceEXT"); - } - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { - device->cmdSetPrimitiveTopology = - (PFN_vkCmdSetPrimitiveTopology)s_Vk.getDeviceProcAddr( - device->handle, - "vkcmdSetPrimitiveTopology"); - - if (!device->cmdSetPrimitiveTopology) { - device->cmdSetPrimitiveTopology = - (PFN_vkCmdSetPrimitiveTopologyEXT)s_Vk.getDeviceProcAddr( - device->handle, - "vkcmdSetPrimitiveTopologyEXT"); - } - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { - device->cmdSetDepthTestEnable = - (PFN_vkCmdSetDepthTestEnable)s_Vk.getDeviceProcAddr( - device->handle, - "vkcmdSetDepthTestEnable"); - - if (!device->cmdSetDepthTestEnable) { - device->cmdSetDepthTestEnable = - (PFN_vkCmdSetDepthTestEnableEXT)s_Vk.getDeviceProcAddr( - device->handle, - "vkcmdSetDepthTestEnableEXT"); - } - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { - device->cmdSetDepthWriteEnable = - (PFN_vkCmdSetDepthWriteEnable)s_Vk.getDeviceProcAddr( - device->handle, - "vkcmdSetDepthWriteEnable"); - - if (!device->cmdSetDepthWriteEnable) { - device->cmdSetDepthWriteEnable = - (PFN_vkCmdSetDepthWriteEnableEXT)s_Vk.getDeviceProcAddr( - device->handle, - "vkcmdSetDepthWriteEnableEXT"); - } - } - - if (features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { - device->cmdSetStencilOp = - (PFN_vkCmdSetStencilOp)s_Vk.getDeviceProcAddr( - device->handle, - "vkcmdSetStencilOp"); - - if (!device->cmdSetStencilOp) { - device->cmdSetStencilOp = - (PFN_vkCmdSetStencilOpEXT)s_Vk.getDeviceProcAddr( - device->handle, - "vkcmdSetStencilOpEXT"); - } - } - - // clang-format on - - palFree(s_Vk.allocator, queueFamilyProps); - palFree(s_Vk.allocator, queueCreateInfos); - - *outDevice = (PalDevice*)device; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyDeviceVk(PalDevice* device) -{ - Device* vkDevice = (Device*)device; - s_Vk.destroyDevice(vkDevice->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkDevice->phyQueues); - palFree(s_Vk.allocator, vkDevice); -} - -// ================================================== -// Memory -// ================================================== - -PalResult PAL_CALL allocateMemoryVk( - PalDevice* device, - PalMemoryType type, - uint64_t memoryMask, - uint64_t size, - PalMemory** outMemory) -{ - VkResult result; - Memory* memory = nullptr; - Device* vkDevice = (Device*)device; - VkMemoryAllocateInfo allocateInfo = {0}; - allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.allocationSize = (VkDeviceSize)size; - VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; - - memory = palAllocate(s_Vk.allocator, sizeof(Memory), 0); - if (!memory) { - return PAL_RESULT_NULL_POINTER; - } - - uint32_t memoryTypeMask = 0; - uint32_t usages = 0; - palUnpackUint32(memoryMask, &memoryTypeMask, &usages); - uint32_t memoryClassMask = vkDevice->memoryClassMask[type] & memoryTypeMask; - if (memoryClassMask == 0) { - return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; - } - - // pick an index using the scoring system - uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, memoryClassMask); - if (memoryIndex == UINT32_MAX) { - return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; - } - - // check if the memory index is valid - if (!(memoryClassMask & (1u << memoryIndex))) { - return PAL_RESULT_MEMORY_TYPE_NOT_SUPPORTED; - } - - allocateInfo.memoryTypeIndex = memoryIndex; - if (usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - allocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; - allocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; - allocateInfo.pNext = &allocateFlagsInfo; - } - - result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, - &memory->handle); - - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - memory->type = type; - *outMemory = (PalMemory*)memory; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL freeMemoryVk( - PalDevice* device, - PalMemory* memory) -{ - Device* vkDevice = (Device*)device; - Memory* vkMemory = (Memory*)memory; - s_Vk.freeMemory(vkDevice->handle, vkMemory->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkMemory); -} - -// ================================================== -// Extended Adapter Features -// ================================================== - -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk( - PalDevice* device, - PalSamplerAnisotropyCapabilities* caps) -{ - Device* vkDevice = (Device*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkPhysicalDeviceProperties props = {0}; - s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); - - caps->maxAnisotropy = props.limits.maxSamplerAnisotropy; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryMultiViewCapabilitiesVk( - PalDevice* device, - PalMultiViewCapabilities* caps) -{ - Device* vkDevice = (Device*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkPhysicalDeviceMultiviewPropertiesKHR props = {0}; - VkPhysicalDeviceProperties2 properties2 = {0}; - props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; - - properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - - caps->maxViewCount = props.maxMultiviewViewCount; - if (caps->maxViewCount == 0) { - caps->maxViewCount = 1; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryMultiViewportCapabilitiesVk( - PalDevice* device, - PalMultiViewportCapabilities* caps) -{ - Device* vkDevice = (Device*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkPhysicalDeviceProperties props = {0}; - s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); - - caps->maxCount = props.limits.maxViewports; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryDepthStencilCapabilitiesVk( - PalDevice* device, - PalDepthStencilCapabilities* caps) -{ - Device* vkDevice = (Device*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkPhysicalDeviceProperties2 properties2 = {0}; - properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - - VkPhysicalDeviceDepthStencilResolvePropertiesKHR props = {0}; - props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR; - - properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - - caps->independentResolve = props.independentResolve; - if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { - caps->depthResolves[PAL_RESOLVE_MODE_AVERAGE] = PAL_TRUE; - } - - if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { - caps->depthResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = PAL_TRUE; - } - - if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_MIN_BIT_KHR) { - caps->depthResolves[PAL_RESOLVE_MODE_MIN] = PAL_TRUE; - } - - if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { - caps->depthResolves[PAL_RESOLVE_MODE_MAX] = PAL_TRUE; - } - - // stencil - if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { - caps->stencilResolves[PAL_RESOLVE_MODE_AVERAGE] = PAL_TRUE; - } - - if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { - caps->stencilResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = PAL_TRUE; - } - - if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MIN_BIT_KHR) { - caps->stencilResolves[PAL_RESOLVE_MODE_MIN] = PAL_TRUE; - } - - if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { - caps->stencilResolves[PAL_RESOLVE_MODE_MAX] = PAL_TRUE; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk( - PalDevice* device, - PalFragmentShadingRateCapabilities* caps) -{ - Device* vkDevice = (Device*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkPhysicalDeviceProperties2 properties2 = {0}; - properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - - VkPhysicalDeviceFragmentShadingRatePropertiesKHR props = {0}; - props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; - - properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - - memset(caps, 0, sizeof(PalFragmentShadingRateCapabilities)); - for (int i = 0; i < PAL_FRAGMENT_SHADING_RATE_MAX; i++) { - VkExtent2D size = getShadingRateSizeVk((PalFragmentShadingRate)i); - - // check against the max size - if (size.width <= props.maxFragmentSize.width || - size.height <= props.maxFragmentSize.height) { - caps->shadingRates[i] = PAL_TRUE; - } - } - - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP] = PAL_TRUE; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE] = PAL_TRUE; - if (props.fragmentShadingRateNonTrivialCombinerOps) { - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN] = PAL_TRUE; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX] = PAL_TRUE; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL] = PAL_TRUE; - } - - VkExtent2D size = props.minFragmentShadingRateAttachmentTexelSize; - caps->minTexelWidth = size.width; - caps->minTexelHeight = size.height; - - size = props.maxFragmentShadingRateAttachmentTexelSize; - caps->maxTexelWidth = size.width; - caps->maxTexelHeight = size.height; - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryMeshShaderCapabilitiesVk( - PalDevice* device, - PalMeshShaderCapabilities* caps) -{ - Device* vkDevice = (Device*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkPhysicalDeviceProperties2 properties2 = {0}; - properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - - VkPhysicalDeviceMeshShaderPropertiesEXT props = {0}; - props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT; - properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - - caps->maxOutputPrimitives = props.maxMeshOutputPrimitives; - caps->maxOutputVertices = props.maxMeshOutputVertices; - caps->maxTaskWorkGroupInvocations = props.maxTaskWorkGroupInvocations; - caps->maxWorkGroupInvocations = props.maxMeshWorkGroupInvocations; - - caps->maxTaskWorkGroupCount[0] = props.maxTaskWorkGroupCount[0]; - caps->maxTaskWorkGroupCount[1] = props.maxTaskWorkGroupCount[1]; - caps->maxTaskWorkGroupCount[2] = props.maxTaskWorkGroupCount[2]; - - caps->maxWorkGroupCount[0] = props.maxMeshWorkGroupCount[0]; - caps->maxWorkGroupCount[1] = props.maxMeshWorkGroupCount[1]; - caps->maxWorkGroupCount[2] = props.maxMeshWorkGroupCount[2]; - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryRayTracingCapabilitiesVk( - PalDevice* device, - PalRayTracingCapabilities* caps) -{ - Device* vkDevice = (Device*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkPhysicalDeviceProperties2 properties2 = {0}; - properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - - VkPhysicalDeviceRayTracingPipelinePropertiesKHR props = {0}; - props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; - - VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; - accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; - - props.pNext = &accProps; - properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - - caps->maxRecursionDepth = props.maxRayRecursionDepth; - caps->maxHitAttributeSize = props.maxRayHitAttributeSize; - caps->maxInstanceCount = accProps.maxInstanceCount; - caps->maxPrimitiveCount = accProps.maxPrimitiveCount; - caps->maxGeometryCount = accProps.maxGeometryCount; - - caps->maxPayloadSize = 64; // safe - caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( - PalDevice* device, - PalDescriptorIndexingCapabilities* caps) -{ - Device* vkDevice = (Device*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; - desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; - - VkPhysicalDeviceProperties2 properties2 = {0}; - properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - - VkPhysicalDeviceDescriptorIndexingPropertiesEXT props = {0}; - props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT; - - VkPhysicalDeviceFeatures2 features; - features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - - VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; - accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; - - features.pNext = &desc; - props.pNext = &accProps; - properties2.pNext = &props; - s_Vk.getPhysicalDeviceFeatures2(vkDevice->phyDevice, &features); - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - - // check sub feature for sampled image - if (desc.shaderSampledImageArrayNonUniformIndexing) { - caps->sampledImageNonUniformIndexing = PAL_TRUE; - } - - if (desc.descriptorBindingSampledImageUpdateAfterBind) { - caps->sampledImageUpdateAfterBind = PAL_TRUE; - } - - // check sub feature for storage image - if (desc.shaderStorageImageArrayNonUniformIndexing) { - caps->storageImageNonUniformIndexing = PAL_TRUE; - } - - if (desc.descriptorBindingStorageImageUpdateAfterBind) { - caps->storageImageUpdateAfterBind = PAL_TRUE; - } - - // check sub feature for storage buffer - if (desc.shaderStorageBufferArrayNonUniformIndexing) { - caps->storageBufferNonUniformIndexing = PAL_TRUE; - } - - if (desc.descriptorBindingStorageBufferUpdateAfterBind) { - caps->storageBufferUpdateAfterBind = PAL_TRUE; - } - - // check sub feature for uniform buffer - if (desc.shaderUniformBufferArrayNonUniformIndexing) { - caps->uniformBufferNonUniformIndexing = PAL_TRUE; - } - - if (desc.descriptorBindingUniformBufferUpdateAfterBind) { - caps->uniformBufferUpdateAfterBind = PAL_TRUE; - } - - caps->maxPerStageSampledImages = props.maxPerStageDescriptorUpdateAfterBindSampledImages; - caps->maxPerSetSampledImages = props.maxDescriptorSetUpdateAfterBindSampledImages; - caps->maxPerStageStorageImages = props.maxPerStageDescriptorUpdateAfterBindStorageImages; - caps->maxPerSetStorageImages = props.maxDescriptorSetUpdateAfterBindStorageImages; - - caps->maxPerStageSamplers = props.maxPerStageDescriptorUpdateAfterBindSamplers; - caps->maxPerSetSamplers = props.maxDescriptorSetUpdateAfterBindSamplers; - caps->maxPerStageStorageBuffers = props.maxPerStageDescriptorUpdateAfterBindStorageBuffers; - caps->maxPerSetStorageBuffers = props.maxDescriptorSetUpdateAfterBindStorageBuffers; - - caps->maxPerStageUniformBuffers = props.maxPerStageDescriptorUpdateAfterBindUniformBuffers; - caps->maxPerSetUniformBuffers = props.maxDescriptorSetUpdateAfterBindUniformBuffers; - - uint32_t tmp = accProps.maxPerStageDescriptorUpdateAfterBindAccelerationStructures; - uint32_t tmp2 = accProps.maxDescriptorSetUpdateAfterBindAccelerationStructures; - caps->maxPerStageAccelerationStructure = tmp; - caps->maxPerSetAccelerationStructure = tmp2; - - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Queue -// ================================================== - -PalResult PAL_CALL createQueueVk( - PalDevice* device, - PalQueueType type, - PalQueue** outQueue) -{ - Device* vkDevice = (Device*)device; - VkQueueFlags queueFlag = 0; - Queue* queue = nullptr; - - if (vkDevice->phyQueueCount == 0) { - return PAL_RESULT_OUT_OF_QUEUE; - } - - switch (type) { - case PAL_QUEUE_TYPE_COMPUTE: { - queueFlag = VK_QUEUE_COMPUTE_BIT; - break; - } - - case PAL_QUEUE_TYPE_GRAPHICS: { - queueFlag = VK_QUEUE_GRAPHICS_BIT; - break; - } - - case PAL_QUEUE_TYPE_COPY: { - queueFlag = VK_QUEUE_TRANSFER_BIT; - break; - } - } - - // we index the for loop so we dont always start at the beginning, this way - // we cycle through all queue families each time we create a queue - PhysicalQueue* phyQueue = nullptr; - for (int i = vkDevice->phyQueueIndex; i < vkDevice->phyQueueCount; i++) { - PhysicalQueue* pq = &vkDevice->phyQueues[i]; - // check if the physical queue supports the requested operation - // and if its not already used - if (pq->usages & queueFlag && pq->usedUsages != queueFlag) { - pq->usedUsages |= queueFlag; - phyQueue = pq; - break; - } - } - - if (!phyQueue) { - // we didnt get any queue, we check if we started the loop at the beginning or mid way - if (vkDevice->phyQueueIndex == 0) { - // we searched all queue families - return PAL_RESULT_OUT_OF_QUEUE; - - } else { - // we start at the beginning and go through the queue families again - vkDevice->phyQueueIndex = 0; - for (int i = vkDevice->phyQueueIndex; i < vkDevice->phyQueueCount; i++) { - PhysicalQueue* pq = &vkDevice->phyQueues[i]; - if (pq->usages & queueFlag && pq->usedUsages != queueFlag) { - pq->usedUsages |= queueFlag; - phyQueue = pq; - break; - } - } - - if (!phyQueue) { - return PAL_RESULT_OUT_OF_QUEUE; - } - } - } - - queue = palAllocate(s_Vk.allocator, sizeof(Queue), 0); - if (!queue) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - vkDevice->phyQueueIndex = (vkDevice->phyQueueIndex + 1) % vkDevice->phyQueueCount; - queue->phyQueue = phyQueue; - queue->usage = queueFlag; - queue->device = vkDevice; - - *outQueue = (PalQueue*)queue; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyQueueVk(PalQueue* queue) -{ - Queue* vkQueue = (Queue*)queue; - PhysicalQueue* phyQueue = vkQueue->phyQueue; - phyQueue->usedUsages &= ~vkQueue->usage; - palFree(s_Vk.allocator, vkQueue); -} - -PalResult PAL_CALL waitQueueVk(PalQueue* queue) -{ - Queue* vkQueue = (Queue*)queue; - VkResult result = s_Vk.waitQueue(vkQueue->phyQueue->handle); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - return PAL_RESULT_SUCCESS; -} - -PalBool PAL_CALL canQueuePresentVk( - PalQueue* queue, - PalSurface* surface) -{ - VkResult result; - Queue* vkQueue = (Queue*)queue; - PhysicalQueue* phyQueue = vkQueue->phyQueue; - Surface* vkSurface = (Surface*)surface; - - // check if the queue is a graphics queue before we check its family - // index for presentation support. - if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { - return PAL_FALSE; - } - - VkBool32 supported = PAL_FALSE; - result = s_Vk.checkSurfaceSupport( - phyQueue->phyDevice, - phyQueue->familyIndex, - vkSurface->handle, - &supported); - - if (result == VK_SUCCESS && supported) { - return PAL_TRUE; - } - - return PAL_FALSE; -} - -// ================================================== -// Formats -// ================================================== - -PalResult PAL_CALL enumerateFormatsVk( - PalAdapter* adapter, - int32_t* count, - PalFormatInfo* outFormats) -{ - int32_t fmtCount = 0; - Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; - VkFormatProperties props = {0}; - - for (int i = 0; i < PAL_FORMAT_MAX; i++) { - VkFormat fmt = formatToVk((PalFormat)i); - s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); - if (props.optimalTilingFeatures != 0) { - // format supported - if (outFormats) { - if (fmtCount < *count) { - PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; - fmtInfo->format = (PalFormat)i; - fmtInfo->usages = ImageUsageFromVk(props.optimalTilingFeatures); - } - - } else { - fmtCount++; - } - } - } - if (!outFormats) { - *count = fmtCount; - } - return PAL_RESULT_SUCCESS; -} - -PalBool PAL_CALL isFormatSupportedVk( - PalAdapter* adapter, - PalFormat format) -{ - Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; - VkFormatProperties props = {0}; - - VkFormat fmt = formatToVk(format); - s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); - if (props.optimalTilingFeatures != 0) { - return PAL_TRUE; - } - return PAL_FALSE; -} - -PalImageUsages PAL_CALL queryFormatImageUsagesVk( - PalAdapter* adapter, - PalFormat format) -{ - Adapter* vkAdapter = (Adapter*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; - VkFormatProperties props = {0}; - - VkFormat fmt = formatToVk(format); - s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); - if (props.optimalTilingFeatures == 0) { - return PAL_IMAGE_USAGE_UNDEFINED; - } - - return ImageUsageFromVk(props.optimalTilingFeatures); -} - -PalSampleCount PAL_CALL queryFormatSampleCountVk( - PalAdapter* adapter, - PalFormat format) -{ - VkResult result; - Adapter* vkAdapter = (Adapter*)adapter; - VkFormatProperties props = {0}; - VkImageFormatProperties formatProps = {0}; - - VkFormat fmt = formatToVk(format); - s_Vk.getPhysicalDeviceFormatProperties(vkAdapter->handle, fmt, &props); - if (props.optimalTilingFeatures == 0) { - return PAL_SAMPLE_COUNT_1; - } - - VkImageUsageFlags vkImageUsage = 0; - PalImageUsages imageUsages = ImageUsageFromVk(props.optimalTilingFeatures); - PalBool isDepth = (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) != 0; - if (isDepth) { - vkImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - } else { - vkImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - } - - result = s_Vk.getPhysicalDeviceImageFormatProperties( - vkAdapter->handle, - fmt, - VK_IMAGE_TYPE_2D, - VK_IMAGE_TILING_OPTIMAL, - vkImageUsage, - 0, - &formatProps); - - if (result != VK_SUCCESS) { - return PAL_SAMPLE_COUNT_1; - } - - return samplesFromVk(formatProps.sampleCounts); -} - -// ================================================== -// Image -// ================================================== - - - -// ================================================== -// Surface -// ================================================== - -PalResult PAL_CALL createSurfaceVk( - PalDevice* device, - PalGraphicsWindow* window, - PalSurface** outSurface) -{ - VkResult result; - Surface* surface = nullptr; - Device* vkDevice = (Device*)device; - - surface = palAllocate(s_Vk.allocator, sizeof(Surface), 0); - if (!surface) { - return PAL_RESULT_OUT_OF_MEMORY; - } - -#ifdef _WIN32 - if (!s_Vk.createWin32Surface) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkWin32SurfaceCreateInfoKHR cInfo = {0}; - cInfo.hinstance = GetModuleHandle(nullptr); - cInfo.hwnd = window->window; - cInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - - VkSurfaceKHR tmp = nullptr; - result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - surface->device = vkDevice; - surface->handle = tmp; - *outSurface = (PalSurface*)surface; - return PAL_RESULT_SUCCESS; - -#else - if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND) { - if (!s_Vk.createWaylandSurface) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkWaylandSurfaceCreateInfoKHR cInfo = {0}; - cInfo.display = window->display; - cInfo.pNext = nullptr; - cInfo.flags = 0; - cInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; - cInfo.surface = window->window; - - VkSurfaceKHR tmp = nullptr; - result = s_Vk.createWaylandSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - surface->device = vkDevice; - surface->handle = tmp; - *outSurface = (PalSurface*)surface; - return PAL_RESULT_SUCCESS; - - } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11) { - if (!s_Vk.createXlibSurface) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkXlibSurfaceCreateInfoKHR cInfo = {0}; - cInfo.dpy = window->display; - cInfo.window = (Window)(uintptr_t)(window->window); - cInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - - VkSurfaceKHR tmp = nullptr; - result = s_Vk.createXlibSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - surface->device = vkDevice; - surface->handle = tmp; - *outSurface = (PalSurface*)surface; - return PAL_RESULT_SUCCESS; - - } else if (window->displayType == PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB) { - if (!s_Vk.createXcbSurface) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkXcbSurfaceCreateInfoKHR cInfo = {0}; - cInfo.connection = window->display; - cInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; - - VkSurfaceKHR tmp = nullptr; - result = s_Vk.createXcbSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - surface->device = vkDevice; - surface->handle = tmp; - *outSurface = (PalSurface*)surface; - return PAL_RESULT_SUCCESS; - } - -#endif // _WIN32 -} - -void PAL_CALL destroySurfaceVk(PalSurface* surface) -{ - Surface* vkSurface = (Surface*)surface; - s_Vk.destroySurface(s_Vk.instance, vkSurface->handle, &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, vkSurface); -} - -PalResult PAL_CALL getSurfaceCapabilitiesVk( - PalDevice* device, - PalSurface* surface, - PalSurfaceCapabilities* caps) -{ - int32_t formatCount = 0; - int32_t modeCount = 0; - Surface* vkSurface = (Surface*)surface; - VkSurfaceFormatKHR* formats = nullptr; - VkPresentModeKHR* modes = nullptr; - - Device* vkDevice = (Device*)device; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkDevice->phyDevice; - - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - s_Vk.getSurfacePresentModes(phyDevice, vkSurface->handle, &modeCount, nullptr); - s_Vk.getSurfaceFormats(phyDevice, vkSurface->handle, &formatCount, nullptr); - - modes = palAllocate(s_Vk.allocator, sizeof(VkPresentModeKHR) * modeCount, 0); - formats = palAllocate(s_Vk.allocator, sizeof(VkSurfaceFormatKHR) * formatCount, 0); - if (!modes || !formats) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - s_Vk.getSurfacePresentModes(phyDevice, vkSurface->handle, &modeCount, modes); - s_Vk.getSurfaceFormats(phyDevice, vkSurface->handle, &formatCount, formats); - - VkSurfaceCapabilitiesKHR surfaceCaps; - s_Vk.getSurfaceCapabilities(phyDevice, vkSurface->handle, &surfaceCaps); - - caps->minImageWidth = surfaceCaps.minImageExtent.width; - caps->minImageHeight = surfaceCaps.minImageExtent.height; - caps->maxImageWidth = surfaceCaps.maxImageExtent.width; - caps->maxImageHeight = surfaceCaps.maxImageExtent.height; - - caps->maxImageCount = surfaceCaps.maxImageCount; - caps->minImageCount = surfaceCaps.minImageCount; - caps->maxImageArrayLayers = surfaceCaps.maxImageArrayLayers; - - if (caps->maxImageCount == 0) { - caps->maxImageCount = 8; // safe - } - - // get supported composite alphas - VkCompositeAlphaFlagsKHR alpha = surfaceCaps.supportedCompositeAlpha; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = PAL_TRUE; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = PAL_FALSE; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = PAL_FALSE; - - if (alpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = PAL_TRUE; - } - - if (alpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = PAL_TRUE; - } - - // present modes - caps->presentModes[PAL_PRESENT_MODE_FIFO] = PAL_TRUE; - caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_FALSE; - caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_FALSE; - - for (int i = 0; i < modeCount; i++) { - if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { - caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_TRUE; - } - - if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { - caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_TRUE; - } - } - - // get format and colorspace - caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_FALSE; - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_FALSE; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; - - for (int i = 0; i < formatCount; i++) { - VkSurfaceFormatKHR* fmt = &formats[i]; - if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { - // find its supported colorspace - if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; - } - - } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { - // find its supported colorspace - if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_TRUE; - } - - } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { - // find its supported colorspace - if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; - } - - } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { - // find its supported colorspace - if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { - caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_TRUE; - } - } - } - - palFree(s_Vk.allocator, formats); - palFree(s_Vk.allocator, modes); - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Swapchain -// ================================================== - -PalResult PAL_CALL createSwapchainVk( - PalDevice* device, - PalQueue* queue, - PalSurface* surface, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain) -{ - PalFormat imageFormat = 0; - Swapchain* swapchain = nullptr; - VkImage* images = nullptr; - - Device* vkDevice = (Device*)device; - Queue* vkQueue = (Queue*)queue; - PhysicalQueue* phyQueue = vkQueue->phyQueue; - Surface* vkSurface = (Surface*)surface; - - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - // check if the queue is a graphics queue before we check its family - // index for presentation support. - if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { - return PAL_RESULT_INVALID_QUEUE; - } - - swapchain = palAllocate(s_Vk.allocator, sizeof(Swapchain), 0); - if (!swapchain) { - return PAL_RESULT_OUT_OF_MEMORY; - } - memset(swapchain, 0, sizeof(Swapchain)); - - VkSwapchainCreateInfoKHR createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.surface = vkSurface->handle; - createInfo.imageArrayLayers = info->imageArrayLayerCount; - createInfo.imageExtent.width = info->width; - createInfo.imageExtent.height = info->height; - createInfo.minImageCount = info->imageCount; - createInfo.clipped = info->clipped; - createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - - // present modes - createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; - if (info->presentMode == PAL_PRESENT_MODE_IMMEDIATE) { - createInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; - - } else if (info->presentMode == PAL_PRESENT_MODE_MAILBOX) { - createInfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR; - } - - // composite alpha - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_POST_MULTIPLIED) { - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; - - } else if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED) { - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; - } - - // format and colorspace - createInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; - createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - imageFormat = PAL_FORMAT_B8G8R8A8_UNORM; - - if (info->format == PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR) { - createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; - createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - imageFormat = PAL_FORMAT_B8G8R8A8_SRGB; - - } else if (info->format == PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR) { - createInfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; - createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - imageFormat = PAL_FORMAT_R8G8B8A8_UNORM; - - } else if (info->format == PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10) { - createInfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; - createInfo.imageColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; - imageFormat = PAL_FORMAT_R16G16B16A16_SFLOAT; - } - - // create swapchain - VkResult result = vkDevice->createSwapchain( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &swapchain->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, swapchain); - return makeResultVk(result); - } - - // get and cache all images - int32_t count = 0; - result = vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, nullptr); - - swapchain->images = palAllocate(s_Vk.allocator, sizeof(Image) * count, 0); - images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); - if (!swapchain->images || !images) { - vkDevice->destroySwapchain(vkDevice->handle, swapchain->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, swapchain); - return PAL_RESULT_OUT_OF_MEMORY; - } - vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, images); - - // fill all images with the creatio info - for (int i = 0; i < count; i++) { - Image* image = &swapchain->images[i]; - image->belongsToSwapchain = PAL_TRUE; - image->device = vkDevice; - image->handle = images[i]; - - image->info.depthOrArraySize = createInfo.imageArrayLayers; - image->info.format = imageFormat; - image->info.usages = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; - image->info.height = createInfo.imageExtent.height; - image->info.width = createInfo.imageExtent.width; - image->info.mipLevelCount = 1; - image->info.sampleCount = PAL_SAMPLE_COUNT_1; // swapchain images are not multisampled - image->info.type = PAL_IMAGE_TYPE_2D; - } - - palFree(s_Vk.allocator, images); - swapchain->device = vkDevice; - swapchain->queue = vkQueue; - swapchain->imageCount = count; - - *outSwapchain = (PalSwapchain*)swapchain; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain) -{ - Swapchain* vkSwapchain = (Swapchain*)swapchain; - vkSwapchain->device->destroySwapchain( - vkSwapchain->device->handle, - vkSwapchain->handle, - &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, vkSwapchain->images); - palFree(s_Vk.allocator, vkSwapchain); -} - -PalImage* PAL_CALL getSwapchainImageVk( - PalSwapchain* swapchain, - int32_t index) -{ - Swapchain* vkSwapchain = (Swapchain*)swapchain; - if (index > vkSwapchain->imageCount) { - return nullptr; - } - return (PalImage*)&vkSwapchain->images[index]; -} - -PalResult PAL_CALL getNextSwapchainImageVk( - PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, - uint32_t* outIndex) -{ - VkResult result; - uint32_t index = 0; - uint64_t timeInNanoseconds = 0; - VkFence fenceHandle = nullptr; - VkSemaphore semaphoreHandle = nullptr; - Swapchain* vkSwapchain = (Swapchain*)swapchain; - - if (info->fence) { - Fence* vkFence = (Fence*)info->fence; - fenceHandle = vkFence->handle; - } - - if (info->signalSemaphore) { - Semaphore* vkSemaphore = (Semaphore*)info->signalSemaphore; - semaphoreHandle = vkSemaphore->handle; - } - - if (info->timeout) { - if (info->timeout == PAL_INFINITE) { - timeInNanoseconds = UINT64_MAX; - } else { - timeInNanoseconds = info->timeout * 1000000; - } - } - - result = vkSwapchain->device->acquireNextImage( - vkSwapchain->device->handle, - vkSwapchain->handle, - timeInNanoseconds, - semaphoreHandle, - fenceHandle, - &index); - - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - *outIndex = index; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL presentSwapchainVk( - PalSwapchain* swapchain, - PalSwapchainPresentInfo* info) -{ - Swapchain* vkSwapchain = (Swapchain*)swapchain; - int32_t semaphoreCount = 0; - VkSemaphore semaphoreHandle = nullptr; - if (info->waitSemaphore) { - Semaphore* vkSemaphore = (Semaphore*)info->waitSemaphore; - semaphoreHandle = vkSemaphore->handle; - semaphoreCount = 1; - } - - VkResult result; - VkPresentInfoKHR presentInfo = {0}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &vkSwapchain->handle; - presentInfo.pImageIndices = &info->imageIndex; - presentInfo.pWaitSemaphores = &semaphoreHandle; - presentInfo.waitSemaphoreCount = semaphoreCount; - - result = vkSwapchain->device->queuePresent(vkSwapchain->queue->phyQueue->handle, &presentInfo); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL resizeSwapchainVk( - PalSwapchain* swapchain, - uint32_t newWidth, - uint32_t newHeight) -{ - VkResult result; - Swapchain* vkSwapchain = (Swapchain*)swapchain; - VkSwapchainKHR oldSwapchain = vkSwapchain->handle; - Device* device = vkSwapchain->device; - VkImage* images = nullptr; - - VkSwapchainCreateInfoKHR createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.oldSwapchain = oldSwapchain; - createInfo.imageExtent.width = newWidth; - createInfo.imageExtent.height = newHeight; - - result = device->createSwapchain( - device->handle, - &createInfo, - &s_Vk.vkAllocator, - &vkSwapchain->handle); - - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - uint32_t count = vkSwapchain->imageCount; - images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); - if (!images) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - device->destroySwapchain(device->handle, oldSwapchain, &s_Vk.vkAllocator); - device->getSwapchainImages(device->handle, vkSwapchain->handle, &count, images); - - // fill all images with the creatio info - for (int i = 0; i < count; i++) { - Image* image = &vkSwapchain->images[i]; - image->handle = images[i]; - image->info.height = createInfo.imageExtent.height; - image->info.width = createInfo.imageExtent.width; - } - - palFree(s_Vk.allocator, images); - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Shader -// ================================================== - -PalResult PAL_CALL createShaderVk( - PalDevice* device, - const PalShaderCreateInfo* info, - PalShader** outShader) -{ - VkResult result; - Shader* shader = nullptr; - Device* vkDevice = (Device*)device; - - shader = palAllocate(s_Vk.allocator, sizeof(Shader), 0); - if (!shader) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // allocate entries array - shader->entries = palAllocate(s_Vk.allocator, sizeof(ShaderEntry) * info->entryCount, 0); - if (!shader->entries) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - for (int i = 0; i < info->entryCount; i++) { - ShaderEntry* entry = &shader->entries[i]; - - // clang-format off - if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || - info->entries[i].stage == PAL_SHADER_STAGE_TASK) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_GEOMETRY) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || - info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || - info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_MISS || - info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || - info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - // clang-format on - - strncpy(entry->entryName, info->entries[i].entryName, PAL_SHADER_ENTRY_NAME_SIZE); - entry->entryName[PAL_SHADER_ENTRY_NAME_SIZE - 1] = '\0'; - entry->patchControlPoints = info->entries[i].patchControlPoints; - entry->stage = shaderStageToVK(info->entries[i].stage); - } - - VkShaderModuleCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = info->bytecodeSize; - createInfo.pCode = (const uint32_t*)info->bytecode; - - result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, shader); - return makeResultVk(result); - } - - shader->device = vkDevice; - shader->entryCount = info->entryCount; - *outShader = (PalShader*)shader; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyShaderVk(PalShader* shader) -{ - Shader* vkShader = (Shader*)shader; - s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, vkShader->entries); - palFree(s_Vk.allocator, vkShader); -} - -// ================================================== -// Fence -// ================================================== - -PalResult PAL_CALL createFenceVk( - PalDevice* device, - PalBool signaled, - PalFence** outFence) -{ - VkResult result; - Fence* fence = nullptr; - Device* vkDevice = (Device*)device; - - fence = palAllocate(s_Vk.allocator, sizeof(Fence), 0); - if (!fence) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkFenceCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - if (signaled) { - createInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - } - - result = s_Vk.createFence(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &fence->handle); - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, fence); - return makeResultVk(result); - } - - fence->device = vkDevice; - *outFence = (PalFence*)fence; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyFenceVk(PalFence* fence) -{ - Fence* vkFence = (Fence*)fence; - s_Vk.destroyFence(vkFence->device->handle, vkFence->handle, &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, vkFence); -} - -PalResult PAL_CALL waitFenceVk( - PalFence* fence, - uint64_t timeout) -{ - Fence* vkFence = (Fence*)fence; - VkResult result; - uint64_t timeInNanoseconds = 0; - - if (timeout) { - if (timeout == PAL_INFINITE) { - timeInNanoseconds = UINT64_MAX; - } else { - timeInNanoseconds = timeout * 1000000; - } - } - - result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, PAL_TRUE, timeInNanoseconds); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL resetFenceVk(PalFence* fence) -{ - Fence* vkFence = (Fence*)fence; - if (!(vkFence->device->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkResult result = s_Vk.resetFence(vkFence->device->handle, 1, &vkFence->handle); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - return PAL_RESULT_SUCCESS; -} - -PalBool PAL_CALL isFenceSignaledVk(PalFence* fence) -{ - Fence* vkFence = (Fence*)fence; - VkResult result = s_Vk.isFenceSignaled(vkFence->device->handle, vkFence->handle); - if (result == VK_SUCCESS) { - return PAL_TRUE; - } else { - return PAL_FALSE; - } -} - -// ================================================== -// Semaphore -// ================================================== - -PalResult PAL_CALL createSemaphoreVk( - PalDevice* device, - PalBool enableTimeline, - PalSemaphore** outSemaphore) -{ - VkResult result; - Semaphore* semaphore = nullptr; - Device* vkDevice = (Device*)device; - PalBool hasTimeline = vkDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; - - semaphore = palAllocate(s_Vk.allocator, sizeof(Semaphore), 0); - if (!semaphore) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - VkSemaphoreTypeCreateInfo timelineCreateInfo = {0}; - timelineCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; - timelineCreateInfo.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; - - VkSemaphoreCreateInfo createInfo = {0}; - createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - - const void* next = nullptr; - semaphore->isTimeline = PAL_FALSE; - if (enableTimeline && !hasTimeline) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (enableTimeline) { - next = &timelineCreateInfo; - semaphore->isTimeline = PAL_TRUE; - } - - createInfo.pNext = next; - result = s_Vk.createSemaphore( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &semaphore->handle); - - if (result != VK_SUCCESS) { - palFree(s_Vk.allocator, semaphore); - return makeResultVk(result); - } - - semaphore->device = vkDevice; - *outSemaphore = (PalSemaphore*)semaphore; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore) -{ - Semaphore* vkSemaphore = (Semaphore*)semaphore; - s_Vk.destroySemaphore(vkSemaphore->device->handle, vkSemaphore->handle, &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, vkSemaphore); -} - -PalResult PAL_CALL waitSemaphoreVk( - PalSemaphore* semaphore, - uint64_t value, - uint64_t timeout) -{ - VkResult result; - uint64_t timeInNanoseconds = 0; - Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!vkSemaphore->isTimeline) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (timeout) { - if (timeout == PAL_INFINITE) { - timeInNanoseconds = UINT64_MAX; - } else { - timeInNanoseconds = timeout * 1000000; - } - } - - VkSemaphoreWaitInfo waitInfo = {0}; - waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; - waitInfo.semaphoreCount = 1; - waitInfo.pSemaphores = &vkSemaphore->handle; - waitInfo.pValues = &value; - - result = vkSemaphore->device->waitSemaphore( - vkSemaphore->device->handle, - &waitInfo, - timeInNanoseconds); - - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL signalSemaphoreVk( - PalSemaphore* semaphore, - PalQueue* queue, - uint64_t value) -{ - VkResult result; - Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!vkSemaphore->isTimeline) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkSemaphoreSignalInfo signalInfo = {0}; - signalInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; - signalInfo.semaphore = vkSemaphore->handle; - signalInfo.value = value; - - result = vkSemaphore->device->signalSemaphore(vkSemaphore->device->handle, &signalInfo); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL getSemaphoreValueVk( - PalSemaphore* semaphore, - uint64_t* outValue) -{ - Semaphore* vkSemaphore = (Semaphore*)semaphore; - if (!vkSemaphore->isTimeline) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - VkResult result = vkSemaphore->device->getSemaphoreValue( - vkSemaphore->device->handle, - vkSemaphore->handle, - outValue); - - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - return PAL_RESULT_SUCCESS; -} - -#endif // PAL_HAS_VULKAN_BACKEND diff --git a/src/graphics/vulkan/pal_adapter_vulkan.c b/src/graphics/vulkan/pal_adapter_vulkan.c new file mode 100644 index 00000000..62d0d4a9 --- /dev/null +++ b/src/graphics/vulkan/pal_adapter_vulkan.c @@ -0,0 +1,828 @@ +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +static PalSampleCount samplesFromVk(VkSampleCountFlags count) +{ + if (count & VK_SAMPLE_COUNT_2_BIT) { + return PAL_SAMPLE_COUNT_2; + + } else if (count & VK_SAMPLE_COUNT_4_BIT) { + return PAL_SAMPLE_COUNT_4; + + } else if (count & VK_SAMPLE_COUNT_8_BIT) { + return PAL_SAMPLE_COUNT_8; + + } else if (count & VK_SAMPLE_COUNT_16_BIT) { + return PAL_SAMPLE_COUNT_16; + + } else if (count & VK_SAMPLE_COUNT_32_BIT) { + return PAL_SAMPLE_COUNT_32; + + } else if (count & VK_SAMPLE_COUNT_64_BIT) { + return PAL_SAMPLE_COUNT_64; + } + + return PAL_SAMPLE_COUNT_1; +} + +static PalImageUsages ImageUsageFromVk(VkFormatFeatureFlags flags) +{ + PalImageUsages usages = 0; + if (flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { + usages |= PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; + } + + if (flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { + usages |= PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT; + } + + if (flags & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) { + usages |= PAL_IMAGE_USAGE_TRANSFER_SRC; + } + + if (flags & VK_FORMAT_FEATURE_TRANSFER_DST_BIT) { + usages |= PAL_IMAGE_USAGE_TRANSFER_DST; + } + + if (flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) { + usages |= VK_IMAGE_USAGE_STORAGE_BIT; + } + + if (flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) { + usages |= PAL_IMAGE_USAGE_SAMPLED; + } + + return usages; +} + +PalResult PAL_CALL enumerateAdaptersVk( + int32_t* count, + PalAdapter** outAdapters) +{ + int deviceCount = 0; + int adapterCount = 0; + int extCount = 0; + VkResult ret; + VkExtensionProperties* exts = nullptr; + VkPhysicalDeviceProperties props = {0}; + + ret = s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, nullptr); + if (ret != VK_SUCCESS) { + return makeResultVk(ret); + } + + if (s_Vk.adapters) { + palFree(s_Vk.allocator, s_Vk.adapters); + } + + VkPhysicalDevice* devices = nullptr; + devices = palAllocate(s_Vk.allocator, sizeof(VkPhysicalDevice) * deviceCount, 0); + s_Vk.adapters = palAllocate(s_Vk.allocator, sizeof(AdapterVk) * deviceCount, 0); + if (!devices || !s_Vk.adapters) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + s_Vk.enumeratePhysicalDevices(s_Vk.instance, &deviceCount, devices); + for (int i = 0; i < deviceCount; i++) { + VkPhysicalDevice phyDevice = devices[i]; + s_Vk.getPhysicalDeviceProperties(phyDevice, &props); + if (props.apiVersion < VK_API_VERSION_1_3) { + // check extension + ret = s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extCount, nullptr); + exts = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extCount, 0); + if (!exts) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + PalBool found = PAL_FALSE; + s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extCount, exts); + + for (int i = 0; i < extCount; i++) { + const char* ext = exts[i].extensionName; + if (strcmp(ext, "VK_KHR_dynamic_rendering") == 0) { + found = PAL_TRUE; + break; + } + } + + palFree(s_Vk.allocator, exts); + if (!found) { + continue; + } + } + + VkPhysicalDeviceDynamicRenderingFeaturesKHR required = {0}; + required.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; + + VkPhysicalDeviceFeatures2KHR features = {0}; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR; + features.pNext = &required; + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + + if (!required.dynamicRendering) { + continue; + } + + if (outAdapters) { + if (adapterCount < *count) { + AdapterVk* tmp = &s_Vk.adapters[adapterCount]; + tmp->handle = devices[i]; + outAdapters[adapterCount] = (PalAdapter*)tmp; + } + } + adapterCount++; + } + + if (!outAdapters) { + *count = adapterCount; + } + + palFree(s_Vk.allocator, devices); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL getAdapterInfoVk( + PalAdapter* adapter, + PalAdapterInfo* info) +{ + AdapterVk* vkAdapter = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + VkPhysicalDeviceProperties props = {0}; + VkPhysicalDeviceMemoryProperties memProps = {0}; + + s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); + s_Vk.getPhysicalDeviceProperties(phyDevice, &props); + + info->apiType = PAL_ADAPTER_API_TYPE_VULKAN; + info->shaderFormats = PAL_SHADER_FORMAT_SPIRV; + info->deviceId = props.deviceID; + info->vendorId = props.vendorID; + strcpy(info->name, props.deviceName); + strcpy(info->backendName, "PAL"); + + info->vram = 0; + info->sharedMemory = 0; + for (int i = 0; i < memProps.memoryHeapCount; i++) { + if (memProps.memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { + info->vram += memProps.memoryHeaps[i].size; + } else { + info->sharedMemory += memProps.memoryHeaps[i].size; + } + } + + // get device type + switch (props.deviceType) { + case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: { + info->type = PAL_ADAPTER_TYPE_INTEGRATED; + break; + } + + case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: { + info->type = PAL_ADAPTER_TYPE_DISCRETE; + break; + } + + case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: { + info->type = PAL_ADAPTER_TYPE_VIRTUAL; + break; + } + + case VK_PHYSICAL_DEVICE_TYPE_CPU: { + info->type = PAL_ADAPTER_TYPE_CPU; + break; + } + + default: { + info->type = PAL_ADAPTER_TYPE_UNKNOWN; + break; + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL getAdapterCapabilitiesVk( + PalAdapter* adapter, + PalAdapterCapabilities* caps) +{ + VkResult result = VK_SUCCESS; + AdapterVk* vkAdapter = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + + VkPhysicalDeviceProperties props = {0}; + s_Vk.getPhysicalDeviceProperties(phyDevice, &props); + VkPhysicalDeviceLimits* limits = &props.limits; + + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + + VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; + accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; + properties2.pNext = &accProps; + s_Vk.getPhysicalDeviceProperties2(phyDevice, &properties2); + + PalViewportCapabilities* viewportCaps = &caps->viewportCaps; + PalImageCapabilities* imageCaps = &caps->imageCaps; + PalResourceCapabilities* resourceCaps = &caps->resourceCaps; + PalComputeCapabilities* computeCaps = &caps->computeCaps; + + // get supported queue commands + uint32_t count = 0; + s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &count, nullptr); + + VkQueueFamilyProperties* queueProps = nullptr; + queueProps = palAllocate(s_Vk.allocator, sizeof(VkQueueFamilyProperties) * count, 0); + s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &count, queueProps); + + caps->maxComputeQueues = 0; + caps->maxGraphicsQueues = 0; + caps->maxCopyQueues = 0; + + for (int i = 0; i < count; i++) { + if (queueProps[i].queueFlags & VK_QUEUE_COMPUTE_BIT) { + caps->maxComputeQueues += queueProps->queueCount; + } + + if (queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + caps->maxGraphicsQueues += queueProps->queueCount; + } + + if (queueProps[i].queueFlags & VK_QUEUE_TRANSFER_BIT) { + caps->maxCopyQueues += queueProps->queueCount; + } + } + + caps->maxColorAttachments = limits->maxColorAttachments; + caps->maxUniformBufferSize = limits->maxUniformBufferRange; + caps->maxStorageBufferSize = limits->maxStorageBufferRange; + caps->maxPushConstantSize = limits->maxPushConstantsSize; + + caps->maxVertexLayouts = limits->maxVertexInputBindings; + caps->maxVertexAttributes = limits->maxVertexInputAttributes; + caps->maxTessellationPatchPoint = limits->maxTessellationPatchSize; + + // viewport limits + viewportCaps->maxWidth = limits->maxViewportDimensions[0]; + viewportCaps->maxHeight = limits->maxViewportDimensions[1]; + viewportCaps->minBoundsRange = limits->viewportBoundsRange[0]; + viewportCaps->maxBoundsRange = limits->viewportBoundsRange[1]; + + // image limits + imageCaps->maxWidth = limits->maxImageDimension2D; + imageCaps->maxHeight = limits->maxImageDimension2D; + imageCaps->maxDepth = limits->maxImageDimension3D; + imageCaps->maxArrayLayers = limits->maxImageArrayLayers; + + // vulkan does not give this but we calculate from the max width and width + uint32_t a = imageCaps->maxWidth; + uint32_t b = imageCaps->maxHeight; + uint32_t c = imageCaps->maxDepth; + + uint32_t tmp = a > b ? a : b; + uint32_t size = tmp > c ? tmp : c; + uint32_t levels = 0; + while (size > 0) { + // divide by two + size = size / 2; + levels++; + } + imageCaps->maxMipLevels = levels; + + // resource limits + resourceCaps->maxPerStageSampledImages = limits->maxPerStageDescriptorSampledImages; + resourceCaps->maxPerSetSampledImages = limits->maxDescriptorSetSampledImages; + resourceCaps->maxPerStageStorageImages = limits->maxPerStageDescriptorStorageImages; + resourceCaps->maxPerSetStorageImages = limits->maxDescriptorSetStorageImages; + + resourceCaps->maxPerStageSamplers = limits->maxPerStageDescriptorSamplers; + resourceCaps->maxPerSetSamplers = limits->maxDescriptorSetSamplers; + resourceCaps->maxPerStageStorageBuffers = limits->maxPerStageDescriptorStorageBuffers; + resourceCaps->maxPerSetStorageBuffers = limits->maxDescriptorSetStorageBuffers; + + resourceCaps->maxPerStageUniformBuffers = limits->maxPerStageDescriptorUniformBuffers; + resourceCaps->maxPerSetUniformBuffers = limits->maxDescriptorSetUniformBuffers; + + tmp = accProps.maxPerStageDescriptorAccelerationStructures; + resourceCaps->maxPerStageAccelerationStructure = tmp; + resourceCaps->maxPerSetAccelerationStructure = accProps.maxDescriptorSetAccelerationStructures; + resourceCaps->maxBoundSets = limits->maxBoundDescriptorSets; + + // compute limits + computeCaps->maxWorkGroupInvocations = limits->maxComputeWorkGroupInvocations; + computeCaps->maxWorkGroupCount[0] = limits->maxComputeWorkGroupCount[0]; + computeCaps->maxWorkGroupCount[1] = limits->maxComputeWorkGroupCount[1]; + computeCaps->maxWorkGroupCount[2] = limits->maxComputeWorkGroupCount[2]; + computeCaps->maxWorkGroupSize[0] = limits->maxComputeWorkGroupSize[0]; + computeCaps->maxWorkGroupSize[1] = limits->maxComputeWorkGroupSize[1]; + computeCaps->maxWorkGroupSize[2] = limits->maxComputeWorkGroupSize[2]; + + palFree(s_Vk.allocator, queueProps); + return PAL_RESULT_SUCCESS; +} + +PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) +{ + VkResult result; + PalAdapterFeatures adapterFeatures = 0; + uint32_t extensionCount = 0; + VkPhysicalDeviceProperties props = {0}; + + AdapterVk* vkAdapter = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + + // get supported extensions + s_Vk.getPhysicalDeviceProperties(phyDevice, &props); + result = s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, nullptr); + if (result != VK_SUCCESS) { + // we just return without any modern features which is rare + return 0; + } + + VkExtensionProperties* extensionProps = nullptr; + extensionProps = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extensionCount, 0); + if (!extensionProps) { + return 0; + } + + // check extensions + PalBool hasRayTracing = PAL_FALSE; + PalBool hasAccelerationStructure = PAL_FALSE; + PalBool hasMeshShader = PAL_FALSE; + PalBool hasFragmentRateShading = PAL_FALSE; + PalBool hasTimelineSemaphore = PAL_FALSE; + PalBool hasDescriptorIndexing = PAL_FALSE; + PalBool hasShaderFloat16 = PAL_FALSE; + PalBool hasMultiiView = PAL_FALSE; + PalBool hasDynamicstate = PAL_FALSE; + PalBool hasBufferDeviceAddress = PAL_FALSE; + PalBool hasShaderParameters = PAL_FALSE; + PalBool hasNullDescriptors = PAL_FALSE; + PalBool hasRayQuery = PAL_FALSE; + s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extensionCount, extensionProps); + + // clang-format off + // check if the extensions are present + for (int i = 0; i < extensionCount; i++) { + VkExtensionProperties* props = &extensionProps[i]; + if (strcmp(props->extensionName, "VK_KHR_ray_tracing_pipeline") == 0) { + hasRayTracing = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_KHR_acceleration_structure") == 0) { + hasAccelerationStructure = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_EXT_mesh_shader") == 0) { + hasMeshShader = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_KHR_fragment_shading_rate") == 0) { + hasFragmentRateShading = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_EXT_descriptor_indexing") == 0) { + hasDescriptorIndexing = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_KHR_swapchain") == 0) { + adapterFeatures |= PAL_ADAPTER_FEATURE_SWAPCHAIN; + + } else if (strcmp(props->extensionName, "VK_KHR_shader_float16_int8") == 0) { + hasShaderFloat16 = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_KHR_timeline_semaphore") == 0) { + hasTimelineSemaphore = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_KHR_multiview") == 0) { + hasMultiiView = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_EXT_extended_dynamic_state") == 0) { + hasDynamicstate = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_EXT_extended_dynamic_state2") == 0) { + VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynState2 = {0}; + dynState2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &dynState2; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (dynState2.extendedDynamicState2) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP; + } + + } else if (strcmp(props->extensionName, "VK_KHR_depth_stencil_resolve") == 0) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; + + } else if (strcmp(props->extensionName, "VK_KHR_draw_indirect_count") == 0) { + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; + + } else if (strcmp(props->extensionName, "VK_KHR_draw_mesh_tasks_indirect_count") == 0) { + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT; + + } else if (strcmp(props->extensionName, "VK_KHR_buffer_device_address") == 0) { + hasBufferDeviceAddress = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_KHR_shader_draw_parameters") == 0) { + hasShaderParameters = PAL_TRUE; + + } else if (strcmp(props->extensionName, "VK_EXT_robustness2") == 0) { + hasNullDescriptors = PAL_TRUE; + } + } + + // features that require additional checks + if (hasRayTracing && hasAccelerationStructure) { + VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; + VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; + + ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; + acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + + ray.pNext = &acc; + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &ray; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (ray.rayTracingPipeline && acc.accelerationStructure) { + adapterFeatures |= PAL_ADAPTER_FEATURE_RAY_TRACING; + } + + if (ray.rayTracingPipelineTraceRaysIndirect) { + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING; + } + } + + if (hasMeshShader) { + VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; + mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &mesh; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (mesh.meshShader && mesh.taskShader) { + adapterFeatures |= PAL_ADAPTER_FEATURE_MESH_SHADER; + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH; + } + } + + if (hasFragmentRateShading) { + VkPhysicalDeviceFragmentShadingRateFeaturesKHR frag = {0}; + frag.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &frag; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (frag.pipelineFragmentShadingRate) { + adapterFeatures |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE; + } + + if (frag.attachmentFragmentShadingRate) { + adapterFeatures |= + PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT; + } + } + + if (props.apiVersion >= VK_API_VERSION_1_2 || hasDescriptorIndexing) { + VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; + desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &desc; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + // core features we need + if (desc.runtimeDescriptorArray || + desc.descriptorBindingUpdateUnusedWhilePending) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + } + + if (desc.descriptorBindingPartiallyBound) { + adapterFeatures |= PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; + } + } + + if (props.apiVersion >= VK_API_VERSION_1_2 || hasTimelineSemaphore) { + VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline = {0}; + timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &timeline; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (timeline.timelineSemaphore) { + adapterFeatures |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; + } + } + + if (props.apiVersion >= VK_API_VERSION_1_2 || hasShaderFloat16) { + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; + shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &shader16; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (shader16.shaderFloat16) { + adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_FLOAT16; + } + } + + if (props.apiVersion >= VK_API_VERSION_1_1 || hasMultiiView) { + VkPhysicalDeviceMultiviewFeaturesKHR multiView = {0}; + multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &multiView; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (multiView.multiview) { + adapterFeatures |= PAL_ADAPTER_FEATURE_MULTI_VIEW; + } + } + + if (props.apiVersion >= VK_API_VERSION_1_3 || hasDynamicstate) { + VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynState = {0}; + dynState.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &dynState; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (dynState.extendedDynamicState) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE; + adapterFeatures |= PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY; + } + } + + if (props.apiVersion >= VK_API_VERSION_1_2 || hasBufferDeviceAddress) { + VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; + bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &bufferAddress; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (bufferAddress.bufferDeviceAddress) { + adapterFeatures |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; + } + } + + if (props.apiVersion >= VK_API_VERSION_1_2) { + VkPhysicalDeviceVulkan12Features features12 = {0}; + features12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &features12; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (features12.drawIndirectCount) { + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; + } + } + + if (props.apiVersion >= VK_API_VERSION_1_2 || hasShaderParameters) { + VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {0}; + drawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &drawParameters; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (drawParameters.shaderDrawParameters) { + adapterFeatures |= PAL_ADAPTER_FEATURE_DISPATCH_BASE; + } + } + + if (hasNullDescriptors) { + VkPhysicalDeviceRobustness2FeaturesEXT nullDescriptors = {0}; + nullDescriptors.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &nullDescriptors; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (nullDescriptors.nullDescriptor) { + adapterFeatures |= PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS; + } + } + + if (hasRayQuery) { + VkPhysicalDeviceRayQueryFeaturesKHR query = {0}; + query.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &query; + + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + if (query.rayQuery) { + adapterFeatures |= PAL_ADAPTER_FEATURE_RAY_QUERY; + } + } + // clang-format on + + VkPhysicalDeviceFeatures features; + s_Vk.getPhysicalDeviceFeatures(phyDevice, &features); + + // check for additional features + if (features.multiViewport) { + adapterFeatures |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; + } + + if (features.samplerAnisotropy) { + adapterFeatures |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; + } + + if (features.sampleRateShading) { + adapterFeatures |= PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING; + } + + if (features.shaderFloat64) { + adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_FLOAT64; + } + + if (features.shaderInt64) { + adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_INT64; + } + + if (features.shaderInt16) { + adapterFeatures |= PAL_ADAPTER_FEATURE_SHADER_INT16; + } + + if (features.geometryShader) { + adapterFeatures |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; + } + + if (features.tessellationShader) { + adapterFeatures |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; + } + + if (features.fillModeNonSolid) { + adapterFeatures |= PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE; + } + + // this features are supported on vulkan + adapterFeatures |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; + adapterFeatures |= PAL_ADAPTER_FEATURE_FENCE_RESET; + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; + adapterFeatures |= PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH; + + palFree(s_Vk.allocator, extensionProps); + return adapterFeatures; +} + +uint32_t PAL_CALL getHighestSupportedShaderTargetVk( + PalAdapter* adapter, + PalShaderFormats shaderFormat) +{ + if (shaderFormat != PAL_SHADER_FORMAT_SPIRV) { + return 0; + } + + AdapterVk* vkAdapter = (AdapterVk*)adapter; + VkPhysicalDeviceProperties props = {0}; + s_Vk.getPhysicalDeviceProperties(vkAdapter->handle, &props); + + if (props.apiVersion >= VK_API_VERSION_1_3) { + return PAL_MAKE_SHADER_TARGET(1, 6); + + } else if (props.apiVersion >= VK_API_VERSION_1_2) { + return PAL_MAKE_SHADER_TARGET(1, 5); + + } else if (props.apiVersion >= VK_API_VERSION_1_1) { + return PAL_MAKE_SHADER_TARGET(1, 4); + + } else if (props.apiVersion >= VK_API_VERSION_1_0) { + return PAL_MAKE_SHADER_TARGET(1, 2); + } + + return 0; +} + +PalResult PAL_CALL enumerateFormatsVk( + PalAdapter* adapter, + int32_t* count, + PalFormatInfo* outFormats) +{ + int32_t fmtCount = 0; + AdapterVk* vkAdapter = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + VkFormatProperties props = {0}; + + for (int i = 0; i < PAL_FORMAT_COUNT; i++) { + VkFormat fmt = formatToVk((PalFormat)i); + s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); + if (props.optimalTilingFeatures != 0) { + // format supported + if (outFormats) { + if (fmtCount < *count) { + PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; + fmtInfo->format = (PalFormat)i; + fmtInfo->usages = ImageUsageFromVk(props.optimalTilingFeatures); + } + + } else { + fmtCount++; + } + } + } + if (!outFormats) { + *count = fmtCount; + } + return PAL_RESULT_SUCCESS; +} + +PalBool PAL_CALL isFormatSupportedVk( + PalAdapter* adapter, + PalFormat format) +{ + AdapterVk* vkAdapter = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + VkFormatProperties props = {0}; + + VkFormat fmt = formatToVk(format); + s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); + if (props.optimalTilingFeatures != 0) { + return PAL_TRUE; + } + return PAL_FALSE; +} + +PalImageUsages PAL_CALL queryFormatImageUsagesVk( + PalAdapter* adapter, + PalFormat format) +{ + AdapterVk* vkAdapter = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + VkFormatProperties props = {0}; + + VkFormat fmt = formatToVk(format); + s_Vk.getPhysicalDeviceFormatProperties(phyDevice, fmt, &props); + if (props.optimalTilingFeatures == 0) { + return PAL_IMAGE_USAGE_UNDEFINED; + } + + return ImageUsageFromVk(props.optimalTilingFeatures); +} + +PalSampleCount PAL_CALL queryFormatSampleCountVk( + PalAdapter* adapter, + PalFormat format) +{ + VkResult result; + AdapterVk* vkAdapter = (AdapterVk*)adapter; + VkFormatProperties props = {0}; + VkImageFormatProperties formatProps = {0}; + + VkFormat fmt = formatToVk(format); + s_Vk.getPhysicalDeviceFormatProperties(vkAdapter->handle, fmt, &props); + if (props.optimalTilingFeatures == 0) { + return PAL_SAMPLE_COUNT_1; + } + + VkImageUsageFlags vkImageUsage = 0; + PalImageUsages imageUsages = ImageUsageFromVk(props.optimalTilingFeatures); + PalBool isDepth = (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) != 0; + if (isDepth) { + vkImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + } else { + vkImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + } + + result = s_Vk.getPhysicalDeviceImageFormatProperties( + vkAdapter->handle, + fmt, + VK_IMAGE_TYPE_2D, + VK_IMAGE_TILING_OPTIMAL, + vkImageUsage, + 0, + &formatProps); + + if (result != VK_SUCCESS) { + return PAL_SAMPLE_COUNT_1; + } + + return samplesFromVk(formatProps.sampleCounts); +} + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c index 668662dc..023a4a1d 100644 --- a/src/graphics/vulkan/pal_commands_vulkan.c +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -8,6 +8,8 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" +#define min(a, b) (a < b) ? a : b + static void commitShaderbindingTableUpdate( CommandBufferVk* cmdBuffer, ShaderBindingTableVk* sbt) @@ -44,6 +46,205 @@ static void commitShaderbindingTableUpdate( sbt->isDirty = PAL_FALSE; } +static Barrier barrierToVk(PalUsageState state) +{ + Barrier barrier = {0}; + switch (state) { + case PAL_USAGE_STATE_PRESENT: { + barrier.stage = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; + barrier.access = 0; + barrier.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + return barrier; + } + + case PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE: { + barrier.stage = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; + barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + return barrier; + } + + case PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ: { + barrier.stage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; + barrier.stage |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + return barrier; + } + + case PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE: { + barrier.stage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; + barrier.stage |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + return barrier; + } + + case PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ: { + barrier.stage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; + barrier.stage |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + return barrier; + } + + case PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE: { + barrier.stage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; + barrier.stage |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; + barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + return barrier; + } + + case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ: { + barrier.stage = VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; + barrier.access = VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; + return barrier; + } + + case PAL_USAGE_STATE_TRANSFER_READ: { + barrier.stage = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; + barrier.access = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + return barrier; + } + + case PAL_USAGE_STATE_TRANSFER_WRITE: { + barrier.stage = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; + barrier.access = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + return barrier; + } + + case PAL_USAGE_STATE_VERTEX_READ: { + barrier.stage = VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR; + barrier.access = VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + + case PAL_USAGE_STATE_INDEX_READ: { + barrier.stage = VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR; + barrier.access = VK_ACCESS_2_INDEX_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + + case PAL_USAGE_STATE_INDIRECT_READ: { + barrier.stage = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR; + barrier.access = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + + case PAL_USAGE_STATE_UNIFORM_READ: { + barrier.stage = 0; + barrier.access = VK_ACCESS_2_UNIFORM_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + + case PAL_USAGE_STATE_SHADER_READ: { + barrier.stage = 0; + barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + return barrier; + } + + case PAL_USAGE_STATE_SHADER_WRITE: { + barrier.stage = 0; + barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_GENERAL; + return barrier; + } + + case PAL_USAGE_STATE_STORAGE_READ: { + barrier.stage = 0; + barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_GENERAL; + return barrier; + } + + case PAL_USAGE_STATE_STORAGE_WRITE: { + barrier.stage = 0; + barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_GENERAL; + return barrier; + } + + case PAL_USAGE_STATE_HOST_READ: { + barrier.stage = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; + barrier.access = VK_ACCESS_2_HOST_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + + case PAL_USAGE_STATE_HOST_WRITE: { + barrier.stage = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; + barrier.access = VK_ACCESS_2_HOST_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + + case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: { + barrier.stage = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; + barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + + case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE: { + barrier.stage = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; + barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; + } + } + + barrier.stage = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; + barrier.access = 0; + barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; + return barrier; +} + +static VkRenderingFlags renderingFlagToVk(PalRenderingFlags flags) +{ + VkRenderingFlags renderingFlags = 0; + if (flags == PAL_RENDERING_FLAG_NONE) { + renderingFlags = 0; + } + + if (flags & PAL_RENDERING_FLAG_RESUMING) { + renderingFlags |= VK_RENDERING_RESUMING_BIT; + } + + if (flags & PAL_RENDERING_FLAG_SUSPENDING) { + renderingFlags |= VK_RENDERING_SUSPENDING_BIT; + } + + return renderingFlags; +} + +static VkResolveModeFlags resolveModeToVk(PalResolveMode mode) +{ + switch (mode) { + case PAL_RESOLVE_MODE_SAMPLE_ZERO: + return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + + case PAL_RESOLVE_MODE_AVERAGE: + return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + + case PAL_RESOLVE_MODE_MIN: + return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + + case PAL_RESOLVE_MODE_MAX: + return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + } + + return VK_RESOLVE_MODE_NONE_KHR; +} + PalResult PAL_CALL cmdBeginVk( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) @@ -355,14 +556,14 @@ PalResult PAL_CALL cmdBeginRenderingVk( attachment->imageLayout = layout; // compute layer count and render area - layerCount = minVk(layerCount, imageView->layerCount); - renderWidth = minVk(renderWidth, imageView->image->info.width); - renderHeight = minVk(renderHeight, imageView->image->info.height); + layerCount = min(layerCount, imageView->layerCount); + renderWidth = min(renderWidth, imageView->image->info.width); + renderHeight = min(renderHeight, imageView->image->info.height); if (resolveImageView) { - layerCount = minVk(layerCount, resolveImageView->layerCount); - renderWidth = minVk(renderWidth, resolveImageView->image->info.width); - renderHeight = minVk(renderHeight, resolveImageView->image->info.height); + layerCount = min(layerCount, resolveImageView->layerCount); + renderWidth = min(renderWidth, resolveImageView->image->info.width); + renderHeight = min(renderHeight, resolveImageView->image->info.height); } } @@ -446,14 +647,14 @@ PalResult PAL_CALL cmdBeginRenderingVk( rendering.pStencilAttachment = &stencilAttachment; // compute layer count and render area - layerCount = minVk(layerCount, imageView->layerCount); - renderWidth = minVk(renderWidth, imageView->image->info.width); - renderHeight = minVk(renderHeight, imageView->image->info.height); + layerCount = min(layerCount, imageView->layerCount); + renderWidth = min(renderWidth, imageView->image->info.width); + renderHeight = min(renderHeight, imageView->image->info.height); if (resolveImageView) { - layerCount = minVk(layerCount, resolveImageView->layerCount); - renderWidth = minVk(renderWidth, resolveImageView->image->info.width); - renderHeight = minVk(renderHeight, resolveImageView->image->info.height); + layerCount = min(layerCount, resolveImageView->layerCount); + renderWidth = min(renderWidth, resolveImageView->image->info.width); + renderHeight = min(renderHeight, resolveImageView->image->info.height); } } @@ -472,9 +673,9 @@ PalResult PAL_CALL cmdBeginRenderingVk( rendering.pNext = &fsrInfo; // compute layer count and render area - layerCount = minVk(layerCount, imageView->layerCount); - renderWidth = minVk(renderWidth, imageView->image->info.width); - renderHeight = minVk(renderHeight, imageView->image->info.height); + layerCount = min(layerCount, imageView->layerCount); + renderWidth = min(renderWidth, imageView->image->info.width); + renderHeight = min(renderHeight, imageView->image->info.height); } rendering.layerCount = layerCount; @@ -743,7 +944,7 @@ PalResult PAL_CALL cmdBindVertexBuffersVk( } for (int i = 0; i < count; i++) { - DeviceVk* tmp = (DeviceVk*)buffers[i]; + BufferVk* tmp = (BufferVk*)buffers[i]; vkBuffers[i] = tmp->handle; } @@ -934,9 +1135,9 @@ PalResult PAL_CALL cmdAccelerationStructureBarrierVk( Barrier old = barrierToVk(oldUsageState); Barrier new = barrierToVk(oldUsageState); - barrier.srcStageMask = pipeline->stages; + barrier.srcStageMask = old.stage; barrier.srcAccessMask = old.access; - barrier.dstStageMask = pipeline->stages; + barrier.dstStageMask = new.stage; barrier.dstAccessMask = new.access; VkDependencyInfo dependencyInfo = {0}; @@ -963,10 +1164,18 @@ PalResult PAL_CALL cmdImageBarrierVk( Barrier old = barrierToVk(oldUsageState); Barrier new = barrierToVk(oldUsageState); - barrier.srcStageMask = pipeline->stages; + if (old.stage == 0) { + old.stage = pipeline->stages; + } + + if (new.stage == 0) { + new.stage = pipeline->stages; + } + + barrier.srcStageMask = old.stage; barrier.srcAccessMask = old.access; barrier.oldLayout = old.layout; - barrier.dstStageMask = pipeline->stages; + barrier.dstStageMask = new.stage; barrier.dstAccessMask = new.access; barrier.newLayout = new.layout; @@ -1000,9 +1209,17 @@ PalResult PAL_CALL cmdBufferBarrierVk( Barrier old = barrierToVk(oldUsageState); Barrier new = barrierToVk(oldUsageState); - barrier.srcStageMask = pipeline->stages; + if (old.stage == 0) { + old.stage = pipeline->stages; + } + + if (new.stage == 0) { + new.stage = pipeline->stages; + } + + barrier.srcStageMask = old.stage; barrier.srcAccessMask = old.access; - barrier.dstStageMask = pipeline->stages; + barrier.dstStageMask = new.stage; barrier.dstAccessMask = new.access; barrier.buffer = vkBuffer->handle; @@ -1209,7 +1426,7 @@ PalResult PAL_CALL cmdPushConstantsVk( s_Vk.cmdPushConstants( vkCmdBuffer->handle, pipeline->layout, - pipeline->shaderStages, + vkCmdBuffer->device->shaderStages, offset, size, value); diff --git a/src/graphics/vulkan/pal_descriptors_vulkan.c b/src/graphics/vulkan/pal_descriptors_vulkan.c index c71ea6dc..6ecf38d0 100644 --- a/src/graphics/vulkan/pal_descriptors_vulkan.c +++ b/src/graphics/vulkan/pal_descriptors_vulkan.c @@ -8,6 +8,31 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" +static VkDescriptorType descriptortypeToVk(PalDescriptorType type) +{ + switch (type) { + case PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER: + return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + + case PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + + case PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: + return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; + + case PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE: + return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + + case PAL_DESCRIPTOR_TYPE_SAMPLER: + return VK_DESCRIPTOR_TYPE_SAMPLER; + + case PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE: + return VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR; + } + + return 0; +} + PalResult PAL_CALL createDescriptorSetLayoutVk( PalDevice* device, const PalDescriptorSetLayoutCreateInfo* info, diff --git a/src/graphics/vulkan/pal_device_vulkan.c b/src/graphics/vulkan/pal_device_vulkan.c index 2857f1d7..54e83262 100644 --- a/src/graphics/vulkan/pal_device_vulkan.c +++ b/src/graphics/vulkan/pal_device_vulkan.c @@ -8,4 +8,1393 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" +static void fillDescriptorIndexingFeatures( + VkPhysicalDeviceDescriptorIndexingFeaturesEXT* feature, + VkPhysicalDevice phyDevice) +{ + VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; + desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + features.pNext = &desc; + s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); + + // clang-format off + feature->runtimeDescriptorArray = PAL_TRUE; + feature->descriptorBindingPartiallyBound = desc.descriptorBindingPartiallyBound; + + feature->descriptorBindingUpdateUnusedWhilePending = desc.descriptorBindingUpdateUnusedWhilePending; + feature->shaderSampledImageArrayNonUniformIndexing = desc.shaderSampledImageArrayNonUniformIndexing; + feature->descriptorBindingSampledImageUpdateAfterBind = desc.descriptorBindingSampledImageUpdateAfterBind; + feature->shaderStorageImageArrayNonUniformIndexing = desc.shaderStorageImageArrayNonUniformIndexing; + feature->descriptorBindingStorageImageUpdateAfterBind = desc.descriptorBindingStorageImageUpdateAfterBind; + + feature->shaderStorageBufferArrayNonUniformIndexing = desc.shaderStorageBufferArrayNonUniformIndexing; + feature->descriptorBindingStorageBufferUpdateAfterBind = desc.descriptorBindingStorageBufferUpdateAfterBind; + feature->shaderUniformBufferArrayNonUniformIndexing = desc.shaderUniformBufferArrayNonUniformIndexing; + feature->descriptorBindingUniformBufferUpdateAfterBind = desc.descriptorBindingUniformBufferUpdateAfterBind; + // clang-format on +} + +static void loadFeatureProcs( + PalAdapterFeatures features, + DeviceVk* device) +{ + // clang-format off + // swapchain procs + if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { + device->acquireNextImage = (PFN_vkAcquireNextImageKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkAcquireNextImageKHR"); + + device->createSwapchain = (PFN_vkCreateSwapchainKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateSwapchainKHR"); + + device->destroySwapchain = (PFN_vkDestroySwapchainKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkDestroySwapchainKHR"); + + device->getSwapchainImages = (PFN_vkGetSwapchainImagesKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetSwapchainImagesKHR"); + + device->queuePresent = (PFN_vkQueuePresentKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkQueuePresentKHR"); + } + + // semaphore procs + if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + device->waitSemaphore = (PFN_vkWaitSemaphores)s_Vk.getDeviceProcAddr( + device->handle, + "vkWaitSemaphores"); + + device->signalSemaphore = (PFN_vkSignalSemaphore)s_Vk.getDeviceProcAddr( + device->handle, + "vkSignalSemaphore"); + + device->getSemaphoreValue = (PFN_vkGetSemaphoreCounterValue)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetSemaphoreCounterValue"); + + if (!device->waitSemaphore) { + device->waitSemaphore = (PFN_vkWaitSemaphoresKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkWaitSemaphoresKHR"); + + device->signalSemaphore = (PFN_vkSignalSemaphoreKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkSignalSemaphoreKHR"); + + device->getSemaphoreValue = (PFN_vkGetSemaphoreCounterValueKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetSemaphoreCounterValueKHR"); + } + } + + // fragment shading rate procs + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { + device->cmdSetFragmentShadingRate = + (PFN_vkCmdSetFragmentShadingRateKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdSetFragmentShadingRateKHR"); + } + + // mesh shader procs + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + device->cmdDrawMeshTask = (PFN_vkCmdDrawMeshTasksEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawMeshTasksEXT"); + + device->cmdDrawMeshTaskIndirect = + (PFN_vkCmdDrawMeshTasksIndirectEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawMeshTasksIndirectEXT"); + + device->cmdDrawMeshTaskIndirectCount = + (PFN_vkCmdDrawMeshTasksIndirectCountEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawMeshTasksIndirectCountEXT"); + } + + // ray tracing procs + device->limits.maxPayloadSize = 0; + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + device->limits.maxPayloadSize = 64; + + device->createAccelerationStructure = + (PFN_vkCreateAccelerationStructureKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateAccelerationStructureKHR"); + + device->destroyAccelerationStructure = + (PFN_vkDestroyAccelerationStructureKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkDestroyAccelerationStructureKHR"); + + device->getAccelerationBuildsize = + (PFN_vkGetAccelerationStructureBuildSizesKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetAccelerationStructureBuildSizesKHR"); + + device->cmdBuildAccelerationStructures = + (PFN_vkCmdBuildAccelerationStructuresKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdBuildAccelerationStructuresKHR"); + + device->getAccelerationDeviceAddress = + (PFN_vkGetAccelerationStructureDeviceAddressKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetAccelerationStructureDeviceAddressKHR"); + + device->cmdTraceRays = + (PFN_vkCmdTraceRaysKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdTraceRaysKHR"); + + device->createRayTracingPipeline = + (PFN_vkCreateRayTracingPipelinesKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCreateRayTracingPipelinesKHR"); + + device->cmdTraceRaysIndirect = + (PFN_vkCmdTraceRaysIndirectKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdTraceRaysIndirectKHR"); + + device->getRayTracingShaderGroupHandles = + (PFN_vkGetRayTracingShaderGroupHandlesKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetRayTracingShaderGroupHandlesKHR"); + } + + // buffer address procs + if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { + device->getBufferrAddress = + (PFN_vkGetBufferDeviceAddress)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetBufferDeviceAddress"); + + if (!device->getBufferrAddress) { + device->getBufferrAddress = + (PFN_vkGetBufferDeviceAddressKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkGetBufferDeviceAddressKHR"); + } + } + + // indirect draw count procs + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { + device->cmdDrawIndirectCount = + (PFN_vkCmdDrawIndirectCount)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawIndirectCount"); + + device->cmdDrawIndexedIndirectCount = + (PFN_vkCmdDrawIndexedIndirectCount)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawIndexedIndirectCount"); + + if (!device->cmdDrawIndirectCount) { + device->cmdDrawIndirectCount = + (PFN_vkCmdDrawIndirectCountKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawIndirectCountKHR"); + + device->cmdDrawIndexedIndirectCount = + (PFN_vkCmdDrawIndexedIndirectCountKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDrawIndexedIndirectCountKHR"); + } + } + + // dispatch base procs + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { + device->cmdDispatchBase = + (PFN_vkCmdDispatchBase)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDispatchBase"); + + if (!device->cmdDispatchBase) { + device->cmdDispatchBase = + (PFN_vkCmdDispatchBaseKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdDispatchBaseKHR"); + } + } + + // dynamic rendering procs + device->cmdBeginRendering = + (PFN_vkCmdBeginRendering)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdBeginRendering"); + + device->cmdEndRendering = + (PFN_vkCmdEndRendering)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdEndRendering"); + + device->cmdPipelineBarrier = + (PFN_vkCmdPipelineBarrier2)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdPipelineBarrier2"); + + device->queueSubmit = + (PFN_vkQueueSubmit2)s_Vk.getDeviceProcAddr( + device->handle, + "vkQueueSubmit2"); + + if (!device->cmdBeginRendering) { + device->cmdBeginRendering = + (PFN_vkCmdBeginRenderingKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdBeginRenderingKHR"); + + device->cmdEndRendering = + (PFN_vkCmdEndRenderingKHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdEndRenderingKHR"); + + device->cmdPipelineBarrier = + (PFN_vkCmdPipelineBarrier2KHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdPipelineBarrier2KHR"); + + device->queueSubmit = + (PFN_vkQueueSubmit2KHR)s_Vk.getDeviceProcAddr( + device->handle, + "vkQueueSubmit2KHR"); + } + + // dynamic states + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { + device->cmdSetCullMode = + (PFN_vkCmdSetCullMode)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdSetCullMode"); + + if (!device->cmdSetCullMode) { + device->cmdSetCullMode = + (PFN_vkCmdSetCullModeEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkCmdSetCullModeEXT"); + } + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { + device->cmdSetFrontFace = + (PFN_vkCmdSetFrontFace)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetFrontFace"); + + if (!device->cmdSetFrontFace) { + device->cmdSetFrontFace = + (PFN_vkCmdSetFrontFaceEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetFrontFaceEXT"); + } + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { + device->cmdSetPrimitiveTopology = + (PFN_vkCmdSetPrimitiveTopology)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetPrimitiveTopology"); + + if (!device->cmdSetPrimitiveTopology) { + device->cmdSetPrimitiveTopology = + (PFN_vkCmdSetPrimitiveTopologyEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetPrimitiveTopologyEXT"); + } + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { + device->cmdSetDepthTestEnable = + (PFN_vkCmdSetDepthTestEnable)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetDepthTestEnable"); + + if (!device->cmdSetDepthTestEnable) { + device->cmdSetDepthTestEnable = + (PFN_vkCmdSetDepthTestEnableEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetDepthTestEnableEXT"); + } + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { + device->cmdSetDepthWriteEnable = + (PFN_vkCmdSetDepthWriteEnable)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetDepthWriteEnable"); + + if (!device->cmdSetDepthWriteEnable) { + device->cmdSetDepthWriteEnable = + (PFN_vkCmdSetDepthWriteEnableEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetDepthWriteEnableEXT"); + } + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { + device->cmdSetStencilOp = + (PFN_vkCmdSetStencilOp)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetStencilOp"); + + if (!device->cmdSetStencilOp) { + device->cmdSetStencilOp = + (PFN_vkCmdSetStencilOpEXT)s_Vk.getDeviceProcAddr( + device->handle, + "vkcmdSetStencilOpEXT"); + } + } + + // clang-format on + +} + +static VkShaderStageFlags shaderStageToVK(PalShaderStage stage) +{ + switch (stage) { + case PAL_SHADER_STAGE_VERTEX: + return VK_SHADER_STAGE_VERTEX_BIT; + + case PAL_SHADER_STAGE_FRAGMENT: + return VK_SHADER_STAGE_FRAGMENT_BIT; + + case PAL_SHADER_STAGE_COMPUTE: + return VK_SHADER_STAGE_COMPUTE_BIT; + + case PAL_SHADER_STAGE_GEOMETRY: + return VK_SHADER_STAGE_GEOMETRY_BIT; + + case PAL_SHADER_STAGE_MESH: + return VK_SHADER_STAGE_MESH_BIT_EXT; + + case PAL_SHADER_STAGE_TASK: + return VK_SHADER_STAGE_TASK_BIT_EXT; + + case PAL_SHADER_STAGE_TESSELLATION_CONTROL: + return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + + case PAL_SHADER_STAGE_TESSELLATION_EVALUATION: + return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + + case PAL_SHADER_STAGE_RAYGEN: + return VK_SHADER_STAGE_RAYGEN_BIT_KHR; + + case PAL_SHADER_STAGE_CLOSEST_HIT: + return VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + + case PAL_SHADER_STAGE_ANY_HIT: + return VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + + case PAL_SHADER_STAGE_MISS: + return VK_SHADER_STAGE_MISS_BIT_KHR; + + case PAL_SHADER_STAGE_INTERSECTION: + return VK_SHADER_STAGE_INTERSECTION_BIT_KHR; + + case PAL_SHADER_STAGE_CALLABLE: + return VK_SHADER_STAGE_CALLABLE_BIT_KHR; + } + + return 0; +} + +PalResult PAL_CALL createDeviceVk( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice) +{ + float priority = 1.0f; + uint32_t phyQueueCount = 0; + uint32_t queueFamilyCount = 0; + VkResult result = VK_SUCCESS; + DeviceVk* device = nullptr; + VkPhysicalDeviceProperties props = {0}; + + AdapterVk* vkAdapter = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + s_Vk.getPhysicalDeviceProperties(phyDevice, &props); + + VkQueueFamilyProperties* queueFamilyProps = nullptr; + VkDeviceQueueCreateInfo* queueCreateInfos = nullptr; + s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueFamilyCount, nullptr); + + uint32_t queueFamilySize = sizeof(VkQueueFamilyProperties) * queueFamilyCount; + uint32_t queueCreateInfosSize = sizeof(VkDeviceQueueCreateInfo) * queueFamilyCount; + + queueFamilyProps = palAllocate(s_Vk.allocator, queueFamilySize, 0); + queueCreateInfos = palAllocate(s_Vk.allocator, queueCreateInfosSize, 0); + device = palAllocate(s_Vk.allocator, sizeof(DeviceVk), 0); + if (!queueFamilyProps || !queueCreateInfos || !device) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(device, 0, sizeof(DeviceVk)); + device->phyDevice = phyDevice; + s_Vk.getPhysicalDeviceQueueFamilyProperties(phyDevice, &queueFamilyCount, queueFamilyProps); + for (int i = 0; i < queueFamilyCount; i++) { + queueCreateInfos[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfos[i].pNext = nullptr; + queueCreateInfos[i].pQueuePriorities = &priority; + queueCreateInfos[i].queueFamilyIndex = i; + queueCreateInfos[i].queueCount = queueFamilyProps[i].queueCount; + queueCreateInfos[i].flags = 0; + + // we need the total number of physical queues + phyQueueCount += queueFamilyProps[i].queueCount; + } + + device->phyQueues = palAllocate(s_Vk.allocator, sizeof(PhysicalQueue) * phyQueueCount, 0); + if (!device->phyQueues) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + // build features and extensions capabilities + VkPhysicalDeviceFeatures phyDeviceFeatures = {0}; + s_Vk.getPhysicalDeviceFeatures(phyDevice, &phyDeviceFeatures); + + VkPhysicalDeviceFeatures coreFeatures = {0}; + if (features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { + coreFeatures.samplerAnisotropy = PAL_TRUE; + } + + if (features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { + coreFeatures.sampleRateShading = PAL_TRUE; + } + + if (features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { + coreFeatures.multiViewport = PAL_TRUE; + } + + if (features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { + coreFeatures.tessellationShader = PAL_TRUE; + } + + if (features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { + coreFeatures.geometryShader = PAL_TRUE; + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_INT16) { + coreFeatures.shaderInt16 = PAL_TRUE; + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_INT64) { + coreFeatures.shaderInt64 = PAL_TRUE; + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT64) { + coreFeatures.shaderFloat64 = PAL_TRUE; + } + + // extensions and features2 + void* next = nullptr; + int extCount = 0; + const char* extensions[32] = {0}; + + VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timeline = {0}; + timeline.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; + + VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader16 = {0}; + shader16.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR; + + VkPhysicalDeviceMeshShaderFeaturesEXT mesh = {0}; + mesh.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT; + + VkPhysicalDeviceRayTracingPipelineFeaturesKHR ray = {0}; + VkPhysicalDeviceAccelerationStructureFeaturesKHR acc = {0}; + ray.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; + acc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + + VkPhysicalDeviceFragmentShadingRateFeaturesKHR fsr = {0}; + fsr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; + + VkPhysicalDeviceDescriptorIndexingFeatures descIndex = {0}; + descIndex.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + + VkPhysicalDeviceMultiviewFeatures multiView = {0}; + multiView.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; + + VkPhysicalDeviceExtendedDynamicStateFeaturesEXT dynamicState = {0}; + dynamicState.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; + + VkPhysicalDeviceExtendedDynamicState2FeaturesEXT dynamicState2 = {0}; + dynamicState2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; + + VkPhysicalDeviceBufferDeviceAddressFeaturesKHR bufferAddress = {0}; + bufferAddress.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR; + + VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamicRendering = {0}; + dynamicRendering.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR; + + VkPhysicalDeviceSynchronization2FeaturesKHR sync2 = {0}; + sync2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR; + + VkPhysicalDeviceShaderDrawParametersFeatures drawParameters = {0}; + drawParameters.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES; + + VkPhysicalDeviceRobustness2FeaturesEXT nullDescriptors = {0}; + nullDescriptors.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT; + + if (props.apiVersion < VK_API_VERSION_1_3) { + extensions[extCount++] = "VK_KHR_dynamic_rendering"; + extensions[extCount++] = "VK_KHR_synchronization2"; + } + + dynamicRendering.dynamicRendering = PAL_TRUE; + sync2.synchronization2 = PAL_TRUE; + + dynamicRendering.pNext = next; + sync2.pNext = &dynamicRendering; + next = &sync2; + + if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { + extensions[extCount++] = "VK_KHR_swapchain"; + } + + if (features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE) { + extensions[extCount++] = "VK_KHR_depth_stencil_resolve"; + } + + if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_timeline_semaphore"; + } + timeline.timelineSemaphore = PAL_TRUE; + + timeline.pNext = next; + next = &timeline; + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_shader_float16_int8"; + } + shader16.shaderFloat16 = PAL_TRUE; + + shader16.pNext = next; + next = &shader16; + } + + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + extensions[extCount++] = "VK_KHR_ray_tracing_pipeline"; + extensions[extCount++] = "VK_KHR_acceleration_structure"; + extensions[extCount++] = "VK_KHR_deferred_host_operations"; + ray.rayTracingPipeline = PAL_TRUE; + acc.accelerationStructure = PAL_TRUE; + + ray.pNext = next; + acc.pNext = &ray; + next = &acc; + } + + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + extensions[extCount++] = "VK_EXT_mesh_shader"; + mesh.meshShader = PAL_TRUE; + mesh.taskShader = PAL_TRUE; + + // mesh shader needs geometry feature for primitives + coreFeatures.geometryShader = PAL_TRUE; + + // msh draw indirect count + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT) { + extensions[extCount++] = "VK_KHR_draw_mesh_tasks_indirect_count"; + } + + mesh.pNext = next; + next = &mesh; + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_draw_indirect_count"; + } + } + + if ((features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) || + (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT)) { + extensions[extCount++] = "VK_KHR_fragment_shading_rate"; + fsr.pipelineFragmentShadingRate = PAL_TRUE; + + // fragment shading rate attachment needs this + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { + fsr.attachmentFragmentShadingRate = PAL_TRUE; + } + + fsr.pNext = next; + next = &fsr; + } + + if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_EXT_descriptor_indexing"; + } + + fillDescriptorIndexingFeatures(&descIndex, phyDevice); + descIndex.pNext = next; + next = &descIndex; + } + + if (features & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS) { + if (!(features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_EXT_descriptor_indexing"; + } + + descIndex.pNext = next; + next = &descIndex; + } + + descIndex.descriptorBindingPartiallyBound = PAL_TRUE; + } + + if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_multiview"; + } + multiView.multiview = PAL_TRUE; + + multiView.pNext = next; + next = &multiView; + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE || + features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE || + features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { + if (props.apiVersion < VK_API_VERSION_1_3) { + extensions[extCount++] = "VK_EXT_extended_dynamic_state"; + } + dynamicState.extendedDynamicState = PAL_TRUE; + + dynamicState.pNext = next; + next = &dynamicState; + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE || + features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE || + features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { + extensions[extCount++] = "VK_EXT_extended_dynamic_state2"; + dynamicState2.extendedDynamicState2 = PAL_TRUE; + + dynamicState2.pNext = next; + next = &dynamicState2; + } + + if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_buffer_device_address"; + } + bufferAddress.bufferDeviceAddress = PAL_TRUE; + + bufferAddress.pNext = next; + next = &bufferAddress; + } + + if (features & PAL_ADAPTER_FEATURE_DISPATCH_BASE) { + if (props.apiVersion < VK_API_VERSION_1_2) { + extensions[extCount++] = "VK_KHR_shader_draw_parameters"; + } + drawParameters.shaderDrawParameters = PAL_TRUE; + + drawParameters.pNext = next; + next = &drawParameters; + } + + if (features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS) { + extensions[extCount++] = "VK_EXT_robustness2"; + nullDescriptors.nullDescriptor = PAL_TRUE; + + nullDescriptors.pNext = next; + next = &nullDescriptors; + } + + VkDeviceCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + createInfo.pEnabledFeatures = &coreFeatures; + createInfo.enabledExtensionCount = extCount; + createInfo.ppEnabledExtensionNames = extensions; + createInfo.pQueueCreateInfos = queueCreateInfos; + createInfo.queueCreateInfoCount = queueFamilyCount; + createInfo.pNext = next; + + result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.vkAllocator, &device->handle); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, queueFamilyProps); + palFree(s_Vk.allocator, queueCreateInfos); + palFree(s_Vk.allocator, device->phyQueues); + palFree(s_Vk.allocator, device); + return makeResultVk(result); + } + + device->phyQueueIndex = 0; + device->queueFamilyCount = queueFamilyCount; + device->phyQueueCount = phyQueueCount; + device->features = features; + + // get queues + for (int i = 0; i < queueFamilyCount; i++) { + VkQueueFamilyProperties* data = &queueFamilyProps[i]; + for (int j = 0; j < data->queueCount; j++) { + PhysicalQueue* queue = &device->phyQueues[i]; + s_Vk.getDeviceQueue(device->handle, i, j, &queue->handle); + queue->usages = data->queueFlags; + queue->usedUsages = 0; + queue->familyIndex = i; + queue->phyDevice = phyDevice; + } + } + + // cache memory type indices + VkPhysicalDeviceMemoryProperties memProps = {0}; + s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); + + memset(device->memoryClassMask, 0, sizeof(uint32_t) * 3); + for (int i = 0; i < memProps.memoryTypeCount; i++) { + VkMemoryPropertyFlags flags = memProps.memoryTypes[i].propertyFlags; + + uint32_t bit = (1u << i); + if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) && + !(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)) { + device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] |= bit; + } + + if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) { + device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] |= bit; + } + + if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && + (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)) { + device->memoryClassMask[PAL_MEMORY_TYPE_CPU_READBACK] |= bit; + } + } + + // HACK: most CPU drivers dont have a vram so we set the vram to system memory + if (device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] == 0) { + device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] = + device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD]; + } + + // cache shader stages + device->shaderStages |= VK_SHADER_STAGE_VERTEX_BIT; + device->shaderStages |= VK_SHADER_STAGE_FRAGMENT_BIT; + device->shaderStages |= VK_SHADER_STAGE_COMPUTE_BIT; + + if (features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { + device->shaderStages |= VK_SHADER_STAGE_GEOMETRY_BIT; + } + + if (features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { + device->shaderStages |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + device->shaderStages |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + } + + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + device->shaderStages |= VK_SHADER_STAGE_TASK_BIT_EXT; + device->shaderStages |= VK_SHADER_STAGE_MESH_BIT_EXT; + } + + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + device->shaderStages |= VK_SHADER_STAGE_RAYGEN_BIT_KHR; + device->shaderStages |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR; + device->shaderStages |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR; + device->shaderStages |= VK_SHADER_STAGE_MISS_BIT_KHR; + device->shaderStages |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR; + device->shaderStages |= VK_SHADER_STAGE_CALLABLE_BIT_KHR; + } + + loadFeatureProcs(features, device); + palFree(s_Vk.allocator, queueFamilyProps); + palFree(s_Vk.allocator, queueCreateInfos); + + device->reserved = PAL_BACKEND_KEY; + *outDevice = (PalDevice*)device; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyDeviceVk(PalDevice* device) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + s_Vk.destroyDevice(vkDevice->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkDevice->phyQueues); + palFree(s_Vk.allocator, vkDevice); +} + +PalResult PAL_CALL allocateMemoryVk( + PalDevice* device, + PalMemoryType type, + uint64_t memoryMask, + uint64_t size, + PalMemory** outMemory) +{ + VkResult result; + MemoryVk* memory = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + VkMemoryAllocateInfo allocateInfo = {0}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = (VkDeviceSize)size; + VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; + + memory = palAllocate(s_Vk.allocator, sizeof(MemoryVk), 0); + if (!memory) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + uint32_t memoryTypeMask = 0; + uint32_t usages = 0; + palUnpackUint32(memoryMask, &memoryTypeMask, &usages); + uint32_t memoryClassMask = vkDevice->memoryClassMask[type] & memoryTypeMask; + + // pick an index using the scoring system and check if the memory index is valid + uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, memoryClassMask); + if (!(memoryClassMask & (1u << memoryIndex))) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + + allocateInfo.memoryTypeIndex = memoryIndex; + if (usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + allocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO; + allocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + allocateInfo.pNext = &allocateFlagsInfo; + } + + result = s_Vk.allocateMemory( + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, + &memory->handle); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + memory->type = type; + memory->reserved = PAL_BACKEND_KEY; + *outMemory = (PalMemory*)memory; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL freeMemoryVk( + PalDevice* device, + PalMemory* memory) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + MemoryVk* vkMemory = (MemoryVk*)memory; + s_Vk.freeMemory(vkDevice->handle, vkMemory->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkMemory); +} + +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceProperties props = {0}; + s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); + caps->maxAnisotropy = props.limits.maxSamplerAnisotropy; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryMultiViewCapabilitiesVk( + PalDevice* device, + PalMultiViewCapabilities* caps) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceMultiviewPropertiesKHR props = {0}; + VkPhysicalDeviceProperties2 properties2 = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + + caps->maxViewCount = props.maxMultiviewViewCount; + if (caps->maxViewCount == 0) { + caps->maxViewCount = 1; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryMultiViewportCapabilitiesVk( + PalDevice* device, + PalMultiViewportCapabilities* caps) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceProperties props = {0}; + s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); + caps->maxCount = props.limits.maxViewports; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryDepthStencilCapabilitiesVk( + PalDevice* device, + PalDepthStencilCapabilities* caps) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + VkPhysicalDeviceDepthStencilResolvePropertiesKHR props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR; + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + + caps->supportsIndependentResolve = props.independentResolve; + caps->supportsIndependentResolveNone = props.independentResolveNone; + + // depth + if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { + caps->supportedDepthResolveModes |= (1u << PAL_RESOLVE_MODE_AVERAGE); + } + + if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { + caps->supportedDepthResolveModes |= (1u << PAL_RESOLVE_MODE_SAMPLE_ZERO); + } + + if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_MIN_BIT_KHR) { + caps->supportedDepthResolveModes |= (1u << PAL_RESOLVE_MODE_MIN); + } + + if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { + caps->supportedDepthResolveModes |= (1u << PAL_RESOLVE_MODE_MAX); + } + + // stencil + if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { + caps->supportedStencilResolveModes |= (1u << PAL_RESOLVE_MODE_AVERAGE); + } + + if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR) { + caps->supportedStencilResolveModes |= (1u << PAL_RESOLVE_MODE_SAMPLE_ZERO); + } + + if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MIN_BIT_KHR) { + caps->supportedStencilResolveModes |= (1u << PAL_RESOLVE_MODE_MIN); + } + + if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { + caps->supportedStencilResolveModes |= (1u << PAL_RESOLVE_MODE_MAX); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + VkPhysicalDeviceFragmentShadingRatePropertiesKHR props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + + memset(caps, 0, sizeof(PalFragmentShadingRateCapabilities)); + for (int i = 0; i < PAL_FRAGMENT_SHADING_RATE_COUNT; i++) { + VkExtent2D size = getShadingRateSizeVk((PalFragmentShadingRate)i); + + // check against the max size + if (size.width <= props.maxFragmentSize.width || + size.height <= props.maxFragmentSize.height) { + caps->supportedShadingRates |= (1u << i); + } + } + + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP); + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE); + if (props.fragmentShadingRateNonTrivialCombinerOps) { + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN); + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX); + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL); + } + + VkExtent2D size = props.minFragmentShadingRateAttachmentTexelSize; + caps->minTexelWidth = size.width; + caps->minTexelHeight = size.height; + size = props.maxFragmentShadingRateAttachmentTexelSize; + caps->maxTexelWidth = size.width; + caps->maxTexelHeight = size.height; + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryMeshShaderCapabilitiesVk( + PalDevice* device, + PalMeshShaderCapabilities* caps) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + VkPhysicalDeviceMeshShaderPropertiesEXT props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT; + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + + caps->maxOutputPrimitives = props.maxMeshOutputPrimitives; + caps->maxOutputVertices = props.maxMeshOutputVertices; + caps->maxTaskWorkGroupInvocations = props.maxTaskWorkGroupInvocations; + caps->maxWorkGroupInvocations = props.maxMeshWorkGroupInvocations; + + caps->maxTaskWorkGroupCount[0] = props.maxTaskWorkGroupCount[0]; + caps->maxTaskWorkGroupCount[1] = props.maxTaskWorkGroupCount[1]; + caps->maxTaskWorkGroupCount[2] = props.maxTaskWorkGroupCount[2]; + + caps->maxWorkGroupCount[0] = props.maxMeshWorkGroupCount[0]; + caps->maxWorkGroupCount[1] = props.maxMeshWorkGroupCount[1]; + caps->maxWorkGroupCount[2] = props.maxMeshWorkGroupCount[2]; + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryRayTracingCapabilitiesVk( + PalDevice* device, + PalRayTracingCapabilities* caps) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + VkPhysicalDeviceRayTracingPipelinePropertiesKHR props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR; + VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; + accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; + props.pNext = &accProps; + properties2.pNext = &props; + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + + caps->maxRecursionDepth = props.maxRayRecursionDepth; + caps->maxHitAttributeSize = props.maxRayHitAttributeSize; + caps->maxInstanceCount = accProps.maxInstanceCount; + caps->maxPrimitiveCount = accProps.maxPrimitiveCount; + caps->maxGeometryCount = accProps.maxGeometryCount; + + caps->maxPayloadSize = 64; // safe + caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; + desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; + + VkPhysicalDeviceProperties2 properties2 = {0}; + properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + + VkPhysicalDeviceDescriptorIndexingPropertiesEXT props = {0}; + props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT; + + VkPhysicalDeviceFeatures2 features; + features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; + + VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; + accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; + + features.pNext = &desc; + props.pNext = &accProps; + properties2.pNext = &props; + s_Vk.getPhysicalDeviceFeatures2(vkDevice->phyDevice, &features); + s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + + PalDescriptorIndexingFlags flags = 0; + if (desc.descriptorBindingPartiallyBound) { + flags |= PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND; + } + + // clang-format off + if (desc.descriptorBindingUpdateUnusedWhilePending && + desc.descriptorBindingSampledImageUpdateAfterBind && + desc.descriptorBindingStorageImageUpdateAfterBind && + desc.descriptorBindingStorageBufferUpdateAfterBind && + desc.descriptorBindingUniformBufferUpdateAfterBind) { + flags |= PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; + } + + if (desc.shaderSampledImageArrayNonUniformIndexing && + desc.shaderStorageImageArrayNonUniformIndexing && + desc.shaderStorageBufferArrayNonUniformIndexing && + desc.shaderUniformBufferArrayNonUniformIndexing) { + flags |= PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING; + } + // clang-format on + + caps->maxPerStageSampledImages = props.maxPerStageDescriptorUpdateAfterBindSampledImages; + caps->maxPerSetSampledImages = props.maxDescriptorSetUpdateAfterBindSampledImages; + caps->maxPerStageStorageImages = props.maxPerStageDescriptorUpdateAfterBindStorageImages; + caps->maxPerSetStorageImages = props.maxDescriptorSetUpdateAfterBindStorageImages; + + caps->maxPerStageSamplers = props.maxPerStageDescriptorUpdateAfterBindSamplers; + caps->maxPerSetSamplers = props.maxDescriptorSetUpdateAfterBindSamplers; + caps->maxPerStageStorageBuffers = props.maxPerStageDescriptorUpdateAfterBindStorageBuffers; + caps->maxPerSetStorageBuffers = props.maxDescriptorSetUpdateAfterBindStorageBuffers; + + caps->maxPerStageUniformBuffers = props.maxPerStageDescriptorUpdateAfterBindUniformBuffers; + caps->maxPerSetUniformBuffers = props.maxDescriptorSetUpdateAfterBindUniformBuffers; + + uint32_t tmp = accProps.maxPerStageDescriptorUpdateAfterBindAccelerationStructures; + uint32_t tmp2 = accProps.maxDescriptorSetUpdateAfterBindAccelerationStructures; + caps->maxPerStageAccelerationStructure = tmp; + caps->maxPerSetAccelerationStructure = tmp2; + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL createQueueVk( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue) +{ + DeviceVk* vkDevice = (DeviceVk*)device; + VkQueueFlags queueFlag = 0; + QueueVk* queue = nullptr; + + if (vkDevice->phyQueueCount == 0) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + switch (type) { + case PAL_QUEUE_TYPE_COMPUTE: { + queueFlag = VK_QUEUE_COMPUTE_BIT; + break; + } + + case PAL_QUEUE_TYPE_GRAPHICS: { + queueFlag = VK_QUEUE_GRAPHICS_BIT; + break; + } + + case PAL_QUEUE_TYPE_COPY: { + queueFlag = VK_QUEUE_TRANSFER_BIT; + break; + } + } + + // we index the for loop so we dont always start at the beginning, this way + // we cycle through all queue families each time we create a queue + PhysicalQueue* phyQueue = nullptr; + for (int i = vkDevice->phyQueueIndex; i < vkDevice->phyQueueCount; i++) { + PhysicalQueue* pq = &vkDevice->phyQueues[i]; + // check if the physical queue supports the requested operation + // and if its not already used + if (pq->usages & queueFlag && pq->usedUsages != queueFlag) { + pq->usedUsages |= queueFlag; + phyQueue = pq; + break; + } + } + + if (!phyQueue) { + // we didnt get any queue, we check if we started the loop at the beginning or mid way + if (vkDevice->phyQueueIndex == 0) { + // we searched all queue families + return PAL_RESULT_CODE_OUT_OF_MEMORY; + + } else { + // we start at the beginning and go through the queue families again + vkDevice->phyQueueIndex = 0; + for (int i = vkDevice->phyQueueIndex; i < vkDevice->phyQueueCount; i++) { + PhysicalQueue* pq = &vkDevice->phyQueues[i]; + if (pq->usages & queueFlag && pq->usedUsages != queueFlag) { + pq->usedUsages |= queueFlag; + phyQueue = pq; + break; + } + } + + if (!phyQueue) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + } + } + + queue = palAllocate(s_Vk.allocator, sizeof(QueueVk), 0); + if (!queue) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + vkDevice->phyQueueIndex = (vkDevice->phyQueueIndex + 1) % vkDevice->phyQueueCount; + queue->phyQueue = phyQueue; + queue->usage = queueFlag; + queue->device = vkDevice; + queue->reserved = PAL_BACKEND_KEY; + *outQueue = (PalQueue*)queue; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyQueueVk(PalQueue* queue) +{ + QueueVk* vkQueue = (QueueVk*)queue; + PhysicalQueue* phyQueue = vkQueue->phyQueue; + phyQueue->usedUsages &= ~vkQueue->usage; + palFree(s_Vk.allocator, vkQueue); +} + +PalResult PAL_CALL waitQueueVk(PalQueue* queue) +{ + QueueVk* vkQueue = (QueueVk*)queue; + VkResult result = s_Vk.waitQueue(vkQueue->phyQueue->handle); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalBool PAL_CALL canQueuePresentVk( + PalQueue* queue, + PalSurface* surface) +{ + VkResult result; + QueueVk* vkQueue = (QueueVk*)queue; + PhysicalQueue* phyQueue = vkQueue->phyQueue; + SurfaceVk* vkSurface = (SurfaceVk*)surface; + + // check if the queue is a graphics queue before we check its family + // index for presentation support. + if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { + return PAL_FALSE; + } + + VkBool32 supported = PAL_FALSE; + result = s_Vk.checkSurfaceSupport( + phyQueue->phyDevice, + phyQueue->familyIndex, + vkSurface->handle, + &supported); + + if (result == VK_SUCCESS && supported) { + return PAL_TRUE; + } + + return PAL_FALSE; +} + +PalResult PAL_CALL createShaderVk( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader) +{ + VkResult result; + ShaderVk* shader = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + + shader = palAllocate(s_Vk.allocator, sizeof(ShaderVk), 0); + if (!shader) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + // allocate entries array + shader->entries = palAllocate(s_Vk.allocator, sizeof(ShaderEntry) * info->entryCount, 0); + if (!shader->entries) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + for (int i = 0; i < info->entryCount; i++) { + ShaderEntry* entry = &shader->entries[i]; + + // clang-format off + if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || + info->entries[i].stage == PAL_SHADER_STAGE_TASK) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + } else if (info->entries[i].stage == PAL_SHADER_STAGE_GEOMETRY) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + } else if (info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || + info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || + info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_MISS || + info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || + info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + // clang-format on + + strncpy(entry->entryName, info->entries[i].entryName, PAL_SHADER_ENTRY_NAME_SIZE); + entry->entryName[PAL_SHADER_ENTRY_NAME_SIZE - 1] = '\0'; + entry->patchControlPoints = info->entries[i].patchControlPoints; + entry->stage = shaderStageToVK(info->entries[i].stage); + } + + VkShaderModuleCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = info->bytecodeSize; + createInfo.pCode = (const uint32_t*)info->bytecode; + + result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, shader); + return makeResultVk(result); + } + + shader->device = vkDevice; + shader->entryCount = info->entryCount; + shader->reserved = PAL_BACKEND_KEY; + *outShader = (PalShader*)shader; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyShaderVk(PalShader* shader) +{ + ShaderVk* vkShader = (ShaderVk*)shader; + s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkShader->entries); + palFree(s_Vk.allocator, vkShader); +} + + #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_image_vulkan.c b/src/graphics/vulkan/pal_image_vulkan.c index f86e4ce4..16985f8d 100644 --- a/src/graphics/vulkan/pal_image_vulkan.c +++ b/src/graphics/vulkan/pal_image_vulkan.c @@ -38,6 +38,114 @@ static VkImageUsageFlags imageUsageToVk(PalImageUsages usages) return flags; } +static VkImageViewType imageViewTypeToVk(PalImageViewType type) +{ + switch (type) { + case PAL_IMAGE_VIEW_TYPE_1D: + return VK_IMAGE_VIEW_TYPE_1D; + + case PAL_IMAGE_VIEW_TYPE_1D_ARRAY: + return VK_IMAGE_VIEW_TYPE_1D_ARRAY; + + case PAL_IMAGE_VIEW_TYPE_2D: + return VK_IMAGE_VIEW_TYPE_2D; + + case PAL_IMAGE_VIEW_TYPE_2D_ARRAY: + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + + case PAL_IMAGE_VIEW_TYPE_3D: + return VK_IMAGE_VIEW_TYPE_3D; + + case PAL_IMAGE_VIEW_TYPE_CUBE: + return VK_IMAGE_VIEW_TYPE_CUBE; + + case PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY: + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + } + + return VK_IMAGE_VIEW_TYPE_2D; +} + +static VkFilter filterToVk(PalFilterMode mode) +{ + switch (mode) { + case PAL_FILTER_MODE_NEAREST: { + return VK_FILTER_NEAREST; + } + + case PAL_FILTER_MODE_LINEAR: { + return VK_FILTER_LINEAR; + } + } + return VK_FILTER_NEAREST; +} + +static VkSamplerMipmapMode mipmapModeToVk(PalSamplerMipmapMode mode) +{ + switch (mode) { + case PAL_SAMPLER_MIPMAP_MODE_NEAREST: { + return VK_SAMPLER_MIPMAP_MODE_NEAREST; + } + + case PAL_SAMPLER_MIPMAP_MODE_LINEAR: { + return VK_SAMPLER_MIPMAP_MODE_LINEAR; + } + } + return VK_SAMPLER_MIPMAP_MODE_NEAREST; +} + +static VkSamplerAddressMode addressModeToVk(PalSamplerAddressMode mode) +{ + switch (mode) { + case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { + return VK_SAMPLER_ADDRESS_MODE_REPEAT; + } + + case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { + return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + + } + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + + } + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { + return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + } + } + return VK_SAMPLER_ADDRESS_MODE_REPEAT; +} + +static VkBorderColor borderColorToVk(PalBorderColor color) +{ + switch (color) { + case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: { + return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + } + + case PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK: { + return VK_BORDER_COLOR_INT_TRANSPARENT_BLACK; + } + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK: { + return VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + } + + case PAL_BORDER_COLOR_INT_OPAQUE_BLACK: { + return VK_BORDER_COLOR_INT_OPAQUE_BLACK; + } + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE: { + return VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + } + + case PAL_BORDER_COLOR_INT_OPAQUE_WHITE: { + return VK_BORDER_COLOR_INT_OPAQUE_WHITE; + } + } + return VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; +} + PalResult PAL_CALL createImageVk( PalDevice* device, const PalImageCreateInfo* info, @@ -126,7 +234,7 @@ PalResult PAL_CALL createImageVk( image->info.width = info->width; image->info.depth = info->depth; image->info.arrayLayerCount = info->arrayLayerCount; - image->info.belongsToSwapcchain = PAL_FALSE; + image->info.belongsToSwapchain = PAL_FALSE; image->reserved = PAL_BACKEND_KEY; *outImage = (PalImage*)image; @@ -136,7 +244,7 @@ PalResult PAL_CALL createImageVk( void PAL_CALL destroyImageVk(PalImage* image) { ImageVk* vkImage = (ImageVk*)image; - if (vkImage->info.belongsToSwapcchain) { + if (vkImage->info.belongsToSwapchain) { return; } @@ -163,7 +271,7 @@ PalResult PAL_CALL getImageMemoryRequirementsVk( PalMemoryRequirements* requirements) { ImageVk* vkImage = (ImageVk*)image; - if (vkImage->info.belongsToSwapcchain) { + if (vkImage->info.belongsToSwapchain) { return PAL_RESULT_CODE_INVALID_OPERATION; } @@ -188,7 +296,7 @@ PalResult PAL_CALL bindImageMemoryVk( uint64_t offset) { ImageVk* vkImage = (ImageVk*)image; - if (vkImage->info.belongsToSwapcchain) { + if (vkImage->info.belongsToSwapchain) { return PAL_RESULT_CODE_INVALID_OPERATION; } diff --git a/src/graphics/vulkan/pal_pipeline_vulkan.c b/src/graphics/vulkan/pal_pipeline_vulkan.c index a6e4b673..bad7daa5 100644 --- a/src/graphics/vulkan/pal_pipeline_vulkan.c +++ b/src/graphics/vulkan/pal_pipeline_vulkan.c @@ -8,6 +8,8 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" +#define max(a, b) (a > b) ? a : b + static VkPipelineStageFlags2 pipelineStageToVk(VkShaderStageFlagBits stage) { switch (stage) { @@ -118,28 +120,6 @@ static VkBlendFactor blendFactorToVk(PalBlendFactor op) return VK_BLEND_FACTOR_ZERO; } -static VkFragmentShadingRateCombinerOpKHR combinerOpsToVk(PalFragmentShadingRateCombinerOp op) -{ - switch (op) { - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP: - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE: - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN: - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR; - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX: - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR; - - case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL: - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR; - } - - return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; -} - static uint32_t getVertexTypeSizeVk(PalVertexType type) { // count x sizeof type returned as size @@ -193,6 +173,103 @@ static uint32_t getVertexTypeSizeVk(PalVertexType type) return 0; } +static VkFormat vertexTypeToVk(PalVertexType type) +{ + switch (type) { + case PAL_VERTEX_TYPE_INT32: + return VK_FORMAT_R32_SINT; + + case PAL_VERTEX_TYPE_INT32_2: + return VK_FORMAT_R32G32_SINT; + + case PAL_VERTEX_TYPE_INT32_3: + return VK_FORMAT_R32G32B32_SINT; + + case PAL_VERTEX_TYPE_INT32_4: + return VK_FORMAT_R32G32B32A32_SINT; + + case PAL_VERTEX_TYPE_UINT32: + return VK_FORMAT_R32_UINT; + + case PAL_VERTEX_TYPE_UINT32_2: + return VK_FORMAT_R32G32_UINT; + + case PAL_VERTEX_TYPE_UINT32_3: + return VK_FORMAT_R32G32B32_UINT; + + case PAL_VERTEX_TYPE_UINT32_4: + return VK_FORMAT_R32G32B32A32_UINT; + + case PAL_VERTEX_TYPE_INT8_2: + return VK_FORMAT_R8G8_SINT; + + case PAL_VERTEX_TYPE_INT8_4: + return VK_FORMAT_R8G8B8A8_SINT; + + case PAL_VERTEX_TYPE_UINT8_2: + return VK_FORMAT_R8G8_UINT; + + case PAL_VERTEX_TYPE_UINT8_4: + return VK_FORMAT_R8G8B8A8_UINT; + + case PAL_VERTEX_TYPE_INT8_2NORM: + return VK_FORMAT_R8G8_SNORM; + + case PAL_VERTEX_TYPE_INT8_4NORM: + return VK_FORMAT_R8G8B8A8_SNORM; + + case PAL_VERTEX_TYPE_UINT8_2NORM: + return VK_FORMAT_R8G8_UNORM; + + case PAL_VERTEX_TYPE_UINT8_4NORM: + return VK_FORMAT_R8G8B8A8_UNORM; + + case PAL_VERTEX_TYPE_INT16_2: + return VK_FORMAT_R16G16_SINT; + + case PAL_VERTEX_TYPE_INT16_4: + return VK_FORMAT_R16G16B16A16_SINT; + + case PAL_VERTEX_TYPE_UINT16_2: + return VK_FORMAT_R16G16_UINT; + + case PAL_VERTEX_TYPE_UINT16_4: + return VK_FORMAT_R16G16B16A16_UINT; + + case PAL_VERTEX_TYPE_INT16_2NORM: + return VK_FORMAT_R16G16_SNORM; + + case PAL_VERTEX_TYPE_INT16_4NORM: + return VK_FORMAT_R16G16B16A16_SNORM; + + case PAL_VERTEX_TYPE_UINT16_2NORM: + return VK_FORMAT_R16G16_UNORM; + + case PAL_VERTEX_TYPE_UINT16_4NORM: + return VK_FORMAT_R16G16B16A16_UNORM; + + case PAL_VERTEX_TYPE_FLOAT: + return VK_FORMAT_R32_SFLOAT; + + case PAL_VERTEX_TYPE_FLOAT2: + return VK_FORMAT_R32G32_SFLOAT; + + case PAL_VERTEX_TYPE_FLOAT3: + return VK_FORMAT_R32G32B32_SFLOAT; + + case PAL_VERTEX_TYPE_FLOAT4: + return VK_FORMAT_R32G32B32A32_SFLOAT; + + case PAL_VERTEX_TYPE_HALF_FLOAT16_2: + return VK_FORMAT_R16G16_SFLOAT; + + case PAL_VERTEX_TYPE_HALF_FLOAT16_4: + return VK_FORMAT_R16G16B16A16_SFLOAT; + } + + return VK_FORMAT_UNDEFINED; +} + PalResult PAL_CALL createPipelineLayoutVk( PalDevice* device, const PalPipelineLayoutCreateInfo* info, @@ -850,19 +927,19 @@ PalResult PAL_CALL createRayTracingPipelineVk( switch (entry->stage) { case VK_SHADER_STAGE_RAYGEN_BIT_KHR: { sbtInfo->raygenCount++; - sbtInfo->raygenDataSize = maxVk(sbtInfo->raygenDataSize, tmp->maxDataSize); + sbtInfo->raygenDataSize = max(sbtInfo->raygenDataSize, tmp->maxDataSize); break; } case VK_SHADER_STAGE_MISS_BIT_KHR: { sbtInfo->missCount++; - sbtInfo->missDataSize = maxVk(sbtInfo->missDataSize, tmp->maxDataSize); + sbtInfo->missDataSize = max(sbtInfo->missDataSize, tmp->maxDataSize); break; } case VK_SHADER_STAGE_CALLABLE_BIT_KHR: { sbtInfo->callableCount++; - sbtInfo->callableDataSize = maxVk(sbtInfo->callableDataSize, tmp->maxDataSize); + sbtInfo->callableDataSize = max(sbtInfo->callableDataSize, tmp->maxDataSize); break; } } @@ -875,7 +952,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( } else { sbtInfo->hitCount++; - sbtInfo->hitDataSize = maxVk(sbtInfo->hitDataSize, tmp->maxDataSize); + sbtInfo->hitDataSize = max(sbtInfo->hitDataSize, tmp->maxDataSize); group->generalShader = VK_SHADER_UNUSED_KHR; if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { diff --git a/src/graphics/vulkan/pal_swapchain_vulkan.c b/src/graphics/vulkan/pal_swapchain_vulkan.c new file mode 100644 index 00000000..a54f30ee --- /dev/null +++ b/src/graphics/vulkan/pal_swapchain_vulkan.c @@ -0,0 +1,488 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" + +PalResult PAL_CALL createSurfaceVk( + PalDevice* device, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, + PalSurface** outSurface) +{ + VkResult result; + SurfaceVk* surface = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + VkSurfaceKHR tmp = nullptr; + + surface = palAllocate(s_Vk.allocator, sizeof(SurfaceVk), 0); + if (!surface) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + +#ifdef _WIN32 + if (instanceType != PAL_WINDOW_INSTANCE_TYPE_WIN32) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (!s_Vk.createWin32Surface) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + + VkWin32SurfaceCreateInfoKHR cInfo = {0}; + cInfo.hinstance = windowInstance; + cInfo.hwnd = window; + cInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + +#else + if (instanceType == PAL_WINDOW_INSTANCE_TYPE_WIN32) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (instanceType == PAL_WINDOW_INSTANCE_TYPE_WAYLAND) { + if (!s_Vk.createWaylandSurface) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + + VkWaylandSurfaceCreateInfoKHR cInfo = {0}; + cInfo.display = windowInstance; + cInfo.pNext = nullptr; + cInfo.flags = 0; + cInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; + cInfo.surface = window; + result = s_Vk.createWaylandSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + + } else if (instanceType == PAL_WINDOW_INSTANCE_TYPE_X11) { + if (!s_Vk.createXlibSurface) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + + VkXlibSurfaceCreateInfoKHR cInfo = {0}; + cInfo.dpy = windowInstance; + cInfo.window = (Window)(uintptr_t)(window); + cInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; + result = s_Vk.createXlibSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + + } else if (instanceType == PAL_WINDOW_INSTANCE_TYPE_XCB) { + if (!s_Vk.createXcbSurface) { + return PAL_RESULT_CODE_PLATFORM_FAILURE; + } + + VkXcbSurfaceCreateInfoKHR cInfo = {0}; + cInfo.connection = windowInstance; + cInfo.window = (xcb_window_t)(uintptr_t)(window); + cInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; + result = s_Vk.createXcbSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + } +#endif // _WIN32 + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, surface); + return makeResultVk(result); + } + + surface->device = vkDevice; + surface->handle = tmp; + surface->reserved = PAL_BACKEND_KEY; + *outSurface = (PalSurface*)surface; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroySurfaceVk(PalSurface* surface) +{ + SurfaceVk* vkSurface = (SurfaceVk*)surface; + s_Vk.destroySurface(s_Vk.instance, vkSurface->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkSurface); +} + +PalResult PAL_CALL getSurfaceCapabilitiesVk( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps) +{ + int32_t formatCount = 0; + int32_t modeCount = 0; + SurfaceVk* vkSurface = (SurfaceVk*)surface; + VkSurfaceFormatKHR* formats = nullptr; + VkPresentModeKHR* modes = nullptr; + + DeviceVk* vkDevice = (DeviceVk*)device; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkDevice->phyDevice; + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + memset(caps, 0, sizeof(PalSurfaceCapabilities)); + s_Vk.getSurfacePresentModes(phyDevice, vkSurface->handle, &modeCount, nullptr); + s_Vk.getSurfaceFormats(phyDevice, vkSurface->handle, &formatCount, nullptr); + + modes = palAllocate(s_Vk.allocator, sizeof(VkPresentModeKHR) * modeCount, 0); + formats = palAllocate(s_Vk.allocator, sizeof(VkSurfaceFormatKHR) * formatCount, 0); + if (!modes || !formats) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + s_Vk.getSurfacePresentModes(phyDevice, vkSurface->handle, &modeCount, modes); + s_Vk.getSurfaceFormats(phyDevice, vkSurface->handle, &formatCount, formats); + + VkSurfaceCapabilitiesKHR surfaceCaps; + s_Vk.getSurfaceCapabilities(phyDevice, vkSurface->handle, &surfaceCaps); + caps->minImageWidth = surfaceCaps.minImageExtent.width; + caps->minImageHeight = surfaceCaps.minImageExtent.height; + caps->maxImageWidth = surfaceCaps.maxImageExtent.width; + caps->maxImageHeight = surfaceCaps.maxImageExtent.height; + + caps->maxImageCount = surfaceCaps.maxImageCount; + caps->minImageCount = surfaceCaps.minImageCount; + caps->maxImageArrayLayers = surfaceCaps.maxImageArrayLayers; + + if (caps->maxImageCount == 0) { + caps->maxImageCount = 8; // safe + } + + // get supported composite alphas + VkCompositeAlphaFlagsKHR alpha = surfaceCaps.supportedCompositeAlpha; + caps->supportedCompositeAlphas |= (1u << PAL_COMPOSITE_ALPHA_OPAQUE); + if (alpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { + caps->supportedCompositeAlphas |= (1u << PAL_COMPOSITE_ALPHA_POST_MULTIPLIED); + } + + if (alpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { + caps->supportedCompositeAlphas |= (1u << PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED); + } + + // present modes + caps->supportedPresentModes |= (1u << PAL_PRESENT_MODE_FIFO); + for (int i = 0; i < modeCount; i++) { + if (modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { + caps->supportedPresentModes |= (1u << PAL_PRESENT_MODE_IMMEDIATE); + } + + if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { + caps->supportedPresentModes |= (1u << PAL_PRESENT_MODE_MAILBOX); + } + } + + // get format and colorspace + for (int i = 0; i < formatCount; i++) { + VkSurfaceFormatKHR* fmt = &formats[i]; + if (fmt->format == VK_FORMAT_B8G8R8A8_UNORM) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + caps->supportedFormats |= (1u << PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR); + } + + } else if (fmt->format == VK_FORMAT_B8G8R8A8_SRGB) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + caps->supportedFormats |= (1u << PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR); + } + + } else if (fmt->format == VK_FORMAT_R8G8B8A8_UNORM) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + caps->supportedFormats |= (1u << PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR); + } + + } else if (fmt->format == VK_FORMAT_R16G16B16A16_SFLOAT) { + // find its supported colorspace + if (fmt->colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) { + caps->supportedFormats |= (1u << PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10); + } + } + } + + palFree(s_Vk.allocator, formats); + palFree(s_Vk.allocator, modes); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL createSwapchainVk( + PalDevice* device, + PalQueue* queue, + PalSurface* surface, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain) +{ + PalFormat imageFormat = 0; + SwapchainVk* swapchain = nullptr; + VkImage* images = nullptr; + + DeviceVk* vkDevice = (DeviceVk*)device; + QueueVk* vkQueue = (QueueVk*)queue; + PhysicalQueue* phyQueue = vkQueue->phyQueue; + SurfaceVk* vkSurface = (SurfaceVk*)surface; + + if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + // check if the queue is a graphics queue before we check its family + // index for presentation support. + if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + swapchain = palAllocate(s_Vk.allocator, sizeof(SwapchainVk), 0); + if (!swapchain) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + memset(swapchain, 0, sizeof(SwapchainVk)); + + VkSwapchainCreateInfoKHR createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = vkSurface->handle; + createInfo.imageArrayLayers = info->imageArrayLayerCount; + createInfo.imageExtent.width = info->width; + createInfo.imageExtent.height = info->height; + createInfo.minImageCount = info->imageCount; + createInfo.clipped = info->clipped; + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + + // present modes + createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; + if (info->presentMode == PAL_PRESENT_MODE_IMMEDIATE) { + createInfo.presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + + } else if (info->presentMode == PAL_PRESENT_MODE_MAILBOX) { + createInfo.presentMode = VK_PRESENT_MODE_MAILBOX_KHR; + } + + // composite alpha + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_POST_MULTIPLIED) { + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; + + } else if (info->compositeAlpha == PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED) { + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; + } + + // format and colorspace + createInfo.imageFormat = VK_FORMAT_B8G8R8A8_UNORM; + createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + imageFormat = PAL_FORMAT_B8G8R8A8_UNORM; + + if (info->format == PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR) { + createInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; + createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + imageFormat = PAL_FORMAT_B8G8R8A8_SRGB; + + } else if (info->format == PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR) { + createInfo.imageFormat = VK_FORMAT_R8G8B8A8_UNORM; + createInfo.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + imageFormat = PAL_FORMAT_R8G8B8A8_UNORM; + + } else if (info->format == PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10) { + createInfo.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT; + createInfo.imageColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT; + imageFormat = PAL_FORMAT_R16G16B16A16_SFLOAT; + } + + // create swapchain + VkResult result = vkDevice->createSwapchain( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &swapchain->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, swapchain); + return makeResultVk(result); + } + + // get and cache all images + int32_t count = 0; + result = vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, nullptr); + + swapchain->images = palAllocate(s_Vk.allocator, sizeof(ImageVk) * count, 0); + images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); + if (!swapchain->images || !images) { + vkDevice->destroySwapchain(vkDevice->handle, swapchain->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, swapchain); + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, images); + + // fill all images with the creatio info + for (int i = 0; i < count; i++) { + ImageVk* image = &swapchain->images[i]; + image->device = vkDevice; + image->handle = images[i]; + + image->info.belongsToSwapchain = PAL_TRUE; + image->info.arrayLayerCount = createInfo.imageArrayLayers; + image->info.depth = 1; + image->info.format = imageFormat; + image->info.usages = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; + image->info.height = createInfo.imageExtent.height; + image->info.width = createInfo.imageExtent.width; + image->info.mipLevelCount = 1; + image->info.sampleCount = PAL_SAMPLE_COUNT_1; // swapchain images are not multisampled + image->info.type = PAL_IMAGE_TYPE_2D; + } + palFree(s_Vk.allocator, images); + + swapchain->device = vkDevice; + swapchain->queue = vkQueue; + swapchain->imageCount = count; + swapchain->reserved = PAL_BACKEND_KEY; + *outSwapchain = (PalSwapchain*)swapchain; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain) +{ + SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; + vkSwapchain->device->destroySwapchain( + vkSwapchain->device->handle, + vkSwapchain->handle, + &s_Vk.vkAllocator); + + palFree(s_Vk.allocator, vkSwapchain->images); + palFree(s_Vk.allocator, vkSwapchain); +} + +PalImage* PAL_CALL getSwapchainImageVk( + PalSwapchain* swapchain, + uint32_t index) +{ + SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; + if (index > vkSwapchain->imageCount) { + return nullptr; + } + return (PalImage*)&vkSwapchain->images[index]; +} + +PalResult PAL_CALL getNextSwapchainImageVk( + PalSwapchain* swapchain, + PalSwapchainNextImageInfo* info, + uint32_t* outIndex) +{ + VkResult result; + uint32_t index = 0; + uint64_t timeInNanoseconds = 0; + VkFence fenceHandle = nullptr; + VkSemaphore semaphoreHandle = nullptr; + SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; + + if (info->fence) { + FenceVk* vkFence = (FenceVk*)info->fence; + fenceHandle = vkFence->handle; + } + + if (info->signalSemaphore) { + SemaphoreVk* vkSemaphore = (SemaphoreVk*)info->signalSemaphore; + semaphoreHandle = vkSemaphore->handle; + } + + if (info->timeout) { + if (info->timeout == PAL_INFINITE) { + timeInNanoseconds = UINT64_MAX; + } else { + timeInNanoseconds = info->timeout * 1000000; + } + } + + result = vkSwapchain->device->acquireNextImage( + vkSwapchain->device->handle, + vkSwapchain->handle, + timeInNanoseconds, + semaphoreHandle, + fenceHandle, + &index); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + *outIndex = index; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL presentSwapchainVk( + PalSwapchain* swapchain, + uint32_t imageIndex, + PalSemaphore* waitSemaphore) +{ + SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; + int32_t semaphoreCount = 0; + VkSemaphore semaphoreHandle = nullptr; + if (waitSemaphore) { + SemaphoreVk* vkSemaphore = (SemaphoreVk*)waitSemaphore; + semaphoreHandle = vkSemaphore->handle; + semaphoreCount = 1; + } + + VkResult result; + VkPresentInfoKHR presentInfo = {0}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &vkSwapchain->handle; + presentInfo.pImageIndices = &imageIndex; + presentInfo.pWaitSemaphores = &semaphoreHandle; + presentInfo.waitSemaphoreCount = semaphoreCount; + + result = vkSwapchain->device->queuePresent(vkSwapchain->queue->phyQueue->handle, &presentInfo); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL resizeSwapchainVk( + PalSwapchain* swapchain, + uint32_t newWidth, + uint32_t newHeight) +{ + VkResult result; + SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; + VkSwapchainKHR oldSwapchain = vkSwapchain->handle; + DeviceVk* device = vkSwapchain->device; + VkImage* images = nullptr; + + VkSwapchainCreateInfoKHR createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.oldSwapchain = oldSwapchain; + createInfo.imageExtent.width = newWidth; + createInfo.imageExtent.height = newHeight; + + result = device->createSwapchain( + device->handle, + &createInfo, + &s_Vk.vkAllocator, + &vkSwapchain->handle); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + uint32_t count = vkSwapchain->imageCount; + images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); + if (!images) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + device->destroySwapchain(device->handle, oldSwapchain, &s_Vk.vkAllocator); + device->getSwapchainImages(device->handle, vkSwapchain->handle, &count, images); + // fill all images with the new create info + for (int i = 0; i < count; i++) { + ImageVk* image = &vkSwapchain->images[i]; + image->handle = images[i]; + image->info.height = createInfo.imageExtent.height; + image->info.width = createInfo.imageExtent.width; + } + + palFree(s_Vk.allocator, images); + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_sync_vulkan.c b/src/graphics/vulkan/pal_sync_vulkan.c index 2857f1d7..5ea50d0d 100644 --- a/src/graphics/vulkan/pal_sync_vulkan.c +++ b/src/graphics/vulkan/pal_sync_vulkan.c @@ -8,4 +8,234 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" +PalResult PAL_CALL createFenceVk( + PalDevice* device, + PalBool signaled, + PalFence** outFence) +{ + VkResult result; + FenceVk* fence = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + + fence = palAllocate(s_Vk.allocator, sizeof(FenceVk), 0); + if (!fence) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkFenceCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + if (signaled) { + createInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + } + + result = s_Vk.createFence(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &fence->handle); + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, fence); + return makeResultVk(result); + } + + fence->device = vkDevice; + fence->reserved = PAL_BACKEND_KEY; + *outFence = (PalFence*)fence; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyFenceVk(PalFence* fence) +{ + FenceVk* vkFence = (FenceVk*)fence; + s_Vk.destroyFence(vkFence->device->handle, vkFence->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkFence); +} + +PalResult PAL_CALL waitFenceVk( + PalFence* fence, + uint64_t timeout) +{ + FenceVk* vkFence = (FenceVk*)fence; + VkResult result; + uint64_t timeInNanoseconds = 0; + if (timeout) { + if (timeout == PAL_INFINITE) { + timeInNanoseconds = UINT64_MAX; + } else { + timeInNanoseconds = timeout * 1000000; + } + } + + result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, PAL_TRUE, timeInNanoseconds); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL resetFenceVk(PalFence* fence) +{ + FenceVk* vkFence = (FenceVk*)fence; + if (!(vkFence->device->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkResult result = s_Vk.resetFence(vkFence->device->handle, 1, &vkFence->handle); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalBool PAL_CALL isFenceSignaledVk(PalFence* fence) +{ + FenceVk* vkFence = (FenceVk*)fence; + VkResult result = s_Vk.isFenceSignaled(vkFence->device->handle, vkFence->handle); + if (result == VK_SUCCESS) { + return PAL_TRUE; + + } else { + return PAL_FALSE; + } +} + +PalResult PAL_CALL createSemaphoreVk( + PalDevice* device, + PalBool enableTimeline, + PalSemaphore** outSemaphore) +{ + VkResult result; + SemaphoreVk* semaphore = nullptr; + DeviceVk* vkDevice = (DeviceVk*)device; + PalBool hasTimeline = vkDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; + + semaphore = palAllocate(s_Vk.allocator, sizeof(SemaphoreVk), 0); + if (!semaphore) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + VkSemaphoreTypeCreateInfo timelineCreateInfo = {0}; + timelineCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO; + timelineCreateInfo.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE; + + VkSemaphoreCreateInfo createInfo = {0}; + createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + const void* next = nullptr; + semaphore->isTimeline = PAL_FALSE; + if (enableTimeline && !hasTimeline) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (enableTimeline) { + next = &timelineCreateInfo; + semaphore->isTimeline = PAL_TRUE; + } + + createInfo.pNext = next; + result = s_Vk.createSemaphore( + vkDevice->handle, + &createInfo, + &s_Vk.vkAllocator, + &semaphore->handle); + + if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, semaphore); + return makeResultVk(result); + } + + semaphore->device = vkDevice; + semaphore->reserved = PAL_BACKEND_KEY; + *outSemaphore = (PalSemaphore*)semaphore; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore) +{ + SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; + s_Vk.destroySemaphore(vkSemaphore->device->handle, vkSemaphore->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkSemaphore); +} + +PalResult PAL_CALL waitSemaphoreVk( + PalSemaphore* semaphore, + uint64_t value, + uint64_t timeout) +{ + VkResult result; + uint64_t timeInNanoseconds = 0; + SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; + if (!vkSemaphore->isTimeline) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (timeout) { + if (timeout == PAL_INFINITE) { + timeInNanoseconds = UINT64_MAX; + } else { + timeInNanoseconds = timeout * 1000000; + } + } + + VkSemaphoreWaitInfo waitInfo = {0}; + waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; + waitInfo.semaphoreCount = 1; + waitInfo.pSemaphores = &vkSemaphore->handle; + waitInfo.pValues = &value; + + result = vkSemaphore->device->waitSemaphore( + vkSemaphore->device->handle, + &waitInfo, + timeInNanoseconds); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL signalSemaphoreVk( + PalSemaphore* semaphore, + PalQueue* queue, + uint64_t value) +{ + VkResult result; + SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; + if (!vkSemaphore->isTimeline) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkSemaphoreSignalInfo signalInfo = {0}; + signalInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; + signalInfo.semaphore = vkSemaphore->handle; + signalInfo.value = value; + + result = vkSemaphore->device->signalSemaphore(vkSemaphore->device->handle, &signalInfo); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL getSemaphoreValueVk( + PalSemaphore* semaphore, + uint64_t* outValue) +{ + SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; + if (!vkSemaphore->isTimeline) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + VkResult result = vkSemaphore->device->getSemaphoreValue( + vkSemaphore->device->handle, + vkSemaphore->handle, + outValue); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + return PAL_RESULT_SUCCESS; +} + #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_vulkan.c b/src/graphics/vulkan/pal_vulkan.c new file mode 100644 index 00000000..b34a8ec4 --- /dev/null +++ b/src/graphics/vulkan/pal_vulkan.c @@ -0,0 +1,1435 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_VULKAN_BACKEND +#include "pal_vulkan.h" +#include "pal_platform.h" + +#ifdef _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN + +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX + +// set unicode +#ifndef UNICODE +#define UNICODE +#endif // UNICODE + +#include +#define VK_LIB_NAME "vulkan-1.dll" +#define RESULT_SOURCE PAL_RESULT_SOURCE_WIN32 +#elif defined(__linux__) +#include +#define VK_LIB_NAME "libvulkan.so" +#define RESULT_SOURCE PAL_RESULT_SOURCE_POSIX +#else +// Android +#define VK_LIB_NAME "" +#endif // _WIN32 + +#if _PAL_HAS_POSIX +#include +#endif // _PAL_HAS_POSIX + +Vulkan s_Vk = {0}; + +PalResult makeResultVk(VkResult result) +{ + PalResultCode code = PAL_RESULT_CODE_PLATFORM_FAILURE; + switch (result) { + case VK_ERROR_FEATURE_NOT_PRESENT: + case VK_ERROR_EXTENSION_NOT_PRESENT: { + code = PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + break; + } + + case VK_ERROR_OUT_OF_HOST_MEMORY: + case VK_ERROR_TOO_MANY_OBJECTS: + case VK_ERROR_OUT_OF_DEVICE_MEMORY: { + code = PAL_RESULT_CODE_OUT_OF_MEMORY; + break; + } + + case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: { + code = PAL_RESULT_CODE_INVALID_HANDLE; + break; + } + + case VK_TIMEOUT: { + code = PAL_RESULT_CODE_TIMEOUT; + break; + } + + case VK_ERROR_MEMORY_MAP_FAILED: { + code = PAL_RESULT_CODE_INVALID_OPERATION; + break; + } + + case VK_ERROR_DEVICE_LOST: { + code = PAL_RESULT_CODE_DEVICE_LOST; + break; + } + + case VK_ERROR_OUT_OF_DATE_KHR: { + code = PAL_RESULT_CODE_OUT_OF_DATE; + break; + } + } + + return palMakeResult(code, PAL_RESULT_SOURCE_VULKAN, (uint32_t)result); +} + +VkFormat formatToVk(PalFormat format) +{ + switch (format) { + case PAL_FORMAT_R8_UNORM: + return VK_FORMAT_R8_UNORM; + + case PAL_FORMAT_R8_SNORM: + return VK_FORMAT_R8_SNORM; + + case PAL_FORMAT_R8_UINT: + return VK_FORMAT_R8_UINT; + + case PAL_FORMAT_R8_SINT: + return VK_FORMAT_R8_SINT; + + case PAL_FORMAT_R8_SRGB: + return VK_FORMAT_R8_SRGB; + + case PAL_FORMAT_R16_UNORM: + return VK_FORMAT_R16_UNORM; + + case PAL_FORMAT_R16_SNORM: + return VK_FORMAT_R16_SNORM; + + case PAL_FORMAT_R16_UINT: + return VK_FORMAT_R16_UINT; + + case PAL_FORMAT_R16_SINT: + return VK_FORMAT_R16_SINT; + + case PAL_FORMAT_R16_SFLOAT: + return VK_FORMAT_R16_SFLOAT; + + case PAL_FORMAT_R32_UINT: + return VK_FORMAT_R32_UINT; + + case PAL_FORMAT_R32_SINT: + return VK_FORMAT_R32_SINT; + + case PAL_FORMAT_R32_SFLOAT: + return VK_FORMAT_R32_SFLOAT; + + case PAL_FORMAT_R64_UINT: + return VK_FORMAT_R64_UINT; + + case PAL_FORMAT_R64_SINT: + return VK_FORMAT_R64_SINT; + + case PAL_FORMAT_R64_SFLOAT: + return VK_FORMAT_R64_SFLOAT; + + case PAL_FORMAT_R8G8_UNORM: + return VK_FORMAT_R8G8_UNORM; + + case PAL_FORMAT_R8G8_SNORM: + return VK_FORMAT_R8G8_SNORM; + + case PAL_FORMAT_R8G8_UINT: + return VK_FORMAT_R8G8_UINT; + + case PAL_FORMAT_R8G8_SINT: + return VK_FORMAT_R8G8_SINT; + + case PAL_FORMAT_R8G8_SRGB: + return VK_FORMAT_R8G8_SRGB; + + case PAL_FORMAT_R16G16_UNORM: + return VK_FORMAT_R16G16_UNORM; + + case PAL_FORMAT_R16G16_SNORM: + return VK_FORMAT_R16G16_SNORM; + + case PAL_FORMAT_R16G16_UINT: + return VK_FORMAT_R16G16_UINT; + + case PAL_FORMAT_R16G16_SINT: + return VK_FORMAT_R16G16_SINT; + + case PAL_FORMAT_R16G16_SFLOAT: + return VK_FORMAT_R16G16_SFLOAT; + + case PAL_FORMAT_R32G32_UINT: + return VK_FORMAT_R32G32_UINT; + + case PAL_FORMAT_R32G32_SINT: + return VK_FORMAT_R32G32_SINT; + + case PAL_FORMAT_R32G32_SFLOAT: + return VK_FORMAT_R32G32_SFLOAT; + + case PAL_FORMAT_R64G64_UINT: + return VK_FORMAT_R64G64_UINT; + + case PAL_FORMAT_R64G64_SINT: + return VK_FORMAT_R64G64_SINT; + + case PAL_FORMAT_R64G64_SFLOAT: + return VK_FORMAT_R64G64_SFLOAT; + + case PAL_FORMAT_R8G8B8_UNORM: + return VK_FORMAT_R8G8B8_UNORM; + + case PAL_FORMAT_R8G8B8_SNORM: + return VK_FORMAT_R8G8B8_SNORM; + + case PAL_FORMAT_R8G8B8_UINT: + return VK_FORMAT_R8G8B8_UINT; + + case PAL_FORMAT_R8G8B8_SINT: + return VK_FORMAT_R8G8B8_SINT; + + case PAL_FORMAT_R8G8B8_SRGB: + return VK_FORMAT_R8G8B8_SRGB; + + case PAL_FORMAT_R16G16B16_UNORM: + return VK_FORMAT_R16G16B16_UNORM; + + case PAL_FORMAT_R16G16B16_SNORM: + return VK_FORMAT_R16G16B16_SNORM; + + case PAL_FORMAT_R16G16B16_UINT: + return VK_FORMAT_R16G16B16_UINT; + + case PAL_FORMAT_R16G16B16_SINT: + return VK_FORMAT_R16G16B16_SINT; + + case PAL_FORMAT_R16G16B16_SFLOAT: + return VK_FORMAT_R16G16B16_SFLOAT; + + case PAL_FORMAT_R32G32B32_UINT: + return VK_FORMAT_R32G32B32_UINT; + + case PAL_FORMAT_R32G32B32_SINT: + return VK_FORMAT_R32G32B32_SINT; + + case PAL_FORMAT_R32G32B32_SFLOAT: + return VK_FORMAT_R32G32B32_SFLOAT; + + case PAL_FORMAT_R64G64B64_UINT: + return VK_FORMAT_R64G64B64_UINT; + + case PAL_FORMAT_R64G64B64_SINT: + return VK_FORMAT_R64G64B64_SINT; + + case PAL_FORMAT_R64G64B64_SFLOAT: + return VK_FORMAT_R64G64B64_SFLOAT; + + case PAL_FORMAT_B8G8R8_UNORM: + return VK_FORMAT_B8G8R8_UNORM; + + case PAL_FORMAT_B8G8R8_SNORM: + return VK_FORMAT_B8G8R8_SNORM; + + case PAL_FORMAT_B8G8R8_UINT: + return VK_FORMAT_B8G8R8_UINT; + + case PAL_FORMAT_B8G8R8_SINT: + return VK_FORMAT_B8G8R8_SINT; + + case PAL_FORMAT_B8G8R8_SRGB: + return VK_FORMAT_B8G8R8_SRGB; + + case PAL_FORMAT_R8G8B8A8_UNORM: + return VK_FORMAT_R8G8B8A8_UNORM; + + case PAL_FORMAT_R8G8B8A8_SNORM: + return VK_FORMAT_R8G8B8A8_SNORM; + + case PAL_FORMAT_R8G8B8A8_UINT: + return VK_FORMAT_R8G8B8A8_UINT; + + case PAL_FORMAT_R8G8B8A8_SINT: + return VK_FORMAT_R8G8B8A8_SINT; + + case PAL_FORMAT_R8G8B8A8_SRGB: + return VK_FORMAT_R8G8B8A8_SRGB; + + case PAL_FORMAT_R16G16B16A16_UNORM: + return VK_FORMAT_R16G16B16A16_UNORM; + + case PAL_FORMAT_R16G16B16A16_SNORM: + return VK_FORMAT_R16G16B16A16_SNORM; + + case PAL_FORMAT_R16G16B16A16_UINT: + return VK_FORMAT_R16G16B16A16_UINT; + + case PAL_FORMAT_R16G16B16A16_SINT: + return VK_FORMAT_R16G16B16A16_SINT; + + case PAL_FORMAT_R16G16B16A16_SFLOAT: + return VK_FORMAT_R16G16B16A16_SFLOAT; + + case PAL_FORMAT_R32G32B32A32_UINT: + return VK_FORMAT_R32G32B32A32_UINT; + + case PAL_FORMAT_R32G32B32A32_SINT: + return VK_FORMAT_R32G32B32A32_SINT; + + case PAL_FORMAT_R32G32B32A32_SFLOAT: + return VK_FORMAT_R32G32B32A32_SFLOAT; + + case PAL_FORMAT_R64G64B64A64_UINT: + return VK_FORMAT_R64G64B64A64_UINT; + + case PAL_FORMAT_R64G64B64A64_SINT: + return VK_FORMAT_R64G64B64A64_SINT; + + case PAL_FORMAT_R64G64B64A64_SFLOAT: + return VK_FORMAT_R64G64B64A64_SFLOAT; + + case PAL_FORMAT_B8G8R8A8_UNORM: + return VK_FORMAT_B8G8R8A8_UNORM; + + case PAL_FORMAT_B8G8R8A8_SNORM: + return VK_FORMAT_B8G8R8A8_SNORM; + + case PAL_FORMAT_B8G8R8A8_UINT: + return VK_FORMAT_B8G8R8A8_UINT; + + case PAL_FORMAT_B8G8R8A8_SINT: + return VK_FORMAT_B8G8R8A8_SINT; + + case PAL_FORMAT_B8G8R8A8_SRGB: + return VK_FORMAT_B8G8R8A8_SRGB; + + case PAL_FORMAT_S8_UINT: + return VK_FORMAT_S8_UINT; + + case PAL_FORMAT_D16_UNORM: + return VK_FORMAT_D16_UNORM; + + case PAL_FORMAT_D32_SFLOAT: + return VK_FORMAT_D32_SFLOAT; + + case PAL_FORMAT_D32_SFLOAT_S8_UINT: + return VK_FORMAT_D32_SFLOAT_S8_UINT; + + case PAL_FORMAT_D16_UNORM_S8_UINT: + return VK_FORMAT_D16_UNORM_S8_UINT; + + case PAL_FORMAT_D24_UNORM_S8_UINT: + return VK_FORMAT_D24_UNORM_S8_UINT; + } + + return VK_FORMAT_UNDEFINED; +} + +VkSampleCountFlags samplesToVk(PalSampleCount count) +{ + switch (count) { + case PAL_SAMPLE_COUNT_2: + return VK_SAMPLE_COUNT_2_BIT; + + case PAL_SAMPLE_COUNT_4: + return VK_SAMPLE_COUNT_4_BIT; + + case PAL_SAMPLE_COUNT_8: + return VK_SAMPLE_COUNT_8_BIT; + + case PAL_SAMPLE_COUNT_16: + return VK_SAMPLE_COUNT_16_BIT; + + case PAL_SAMPLE_COUNT_32: + return VK_SAMPLE_COUNT_32_BIT; + + case PAL_SAMPLE_COUNT_64: + return VK_SAMPLE_COUNT_64_BIT; + } + + return VK_SAMPLE_COUNT_1_BIT; +} + +VkExtent2D getShadingRateSizeVk(PalFragmentShadingRate rate) +{ + switch (rate) { + case PAL_FRAGMENT_SHADING_RATE_1X1: + return (VkExtent2D){1, 1}; + + case PAL_FRAGMENT_SHADING_RATE_1X2: + return (VkExtent2D){1, 2}; + + case PAL_FRAGMENT_SHADING_RATE_2X1: + return (VkExtent2D){2, 1}; + + case PAL_FRAGMENT_SHADING_RATE_2X2: + return (VkExtent2D){2, 2}; + + case PAL_FRAGMENT_SHADING_RATE_2X4: + return (VkExtent2D){2, 4}; + + case PAL_FRAGMENT_SHADING_RATE_4X2: + return (VkExtent2D){4, 2}; + + case PAL_FRAGMENT_SHADING_RATE_4X4: + return (VkExtent2D){4, 4}; + } + + return (VkExtent2D){0, 0}; +} + +VkFragmentShadingRateCombinerOpKHR combinerOpsToVk(PalFragmentShadingRateCombinerOp op) +{ + switch (op) { + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX_KHR; + + case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL: + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL_KHR; + } + + return VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; +} + +VkImageAspectFlags imageAspectToVk(PalImageAspect aspect) +{ + switch (aspect) { + case PAL_IMAGE_ASPECT_COLOR: + return VK_IMAGE_ASPECT_COLOR_BIT; + + case PAL_IMAGE_ASPECT_DEPTH: + return VK_IMAGE_ASPECT_DEPTH_BIT; + + case PAL_IMAGE_ASPECT_STENCIL: + return VK_IMAGE_ASPECT_STENCIL_BIT; + + case PAL_IMAGE_ASPECT_DEPTH_STENCIL: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + } + + return VK_IMAGE_ASPECT_COLOR_BIT; +} + +VkStencilOp stencilOpToVk(PalStencilOp op) +{ + switch (op) { + case PAL_STENCIL_OP_KEEP: + return VK_STENCIL_OP_KEEP; + + case PAL_STENCIL_OP_ZERO: + return VK_STENCIL_OP_ZERO; + + case PAL_STENCIL_OP_REPLACE: + return VK_STENCIL_OP_REPLACE; + + case PAL_STENCIL_OP_INCREMENT_AND_CLAMP: + return VK_STENCIL_OP_INCREMENT_AND_CLAMP; + + case PAL_STENCIL_OP_DECREMENT_AND_CLAMP: + return VK_STENCIL_OP_DECREMENT_AND_CLAMP; + + case PAL_STENCIL_OP_INVERT: + return VK_STENCIL_OP_INVERT; + + case PAL_STENCIL_OP_INCREMENT_AND_WRAP: + return VK_STENCIL_OP_INCREMENT_AND_WRAP; + + case PAL_STENCIL_OP_DECREMENT_AND_WRAP: + return VK_STENCIL_OP_DECREMENT_AND_WRAP; + } + + return VK_STENCIL_OP_KEEP; +} + +VkCompareOp compareOpToVk(PalCompareOp op) +{ + switch (op) { + case PAL_COMPARE_OP_NEVER: + return VK_COMPARE_OP_NEVER; + + case PAL_COMPARE_OP_LESS: + return VK_COMPARE_OP_LESS; + + case PAL_COMPARE_OP_EQUAL: + return VK_COMPARE_OP_EQUAL; + + case PAL_COMPARE_OP_LESS_OR_EQUAL: + return VK_COMPARE_OP_LESS_OR_EQUAL; + + case PAL_COMPARE_OP_GREATER: + return VK_COMPARE_OP_GREATER; + + case PAL_COMPARE_OP_NOT_EQUAL: + return VK_COMPARE_OP_NOT_EQUAL; + + case PAL_COMPARE_OP_GREATER_OR_EQUAL: + return VK_COMPARE_OP_GREATER_OR_EQUAL; + + case PAL_COMPARE_OP_ALWAYS: + return VK_COMPARE_OP_ALWAYS; + } + + return VK_COMPARE_OP_NEVER; +} + +uint32_t findBestMemoryIndexVk( + VkPhysicalDevice phyDevice, + uint32_t memoryMask) +{ + int bestScore = -1; + uint32_t bestIndex = UINT32_MAX; + VkPhysicalDeviceMemoryProperties memProps = {0}; + s_Vk.getPhysicalDeviceMemoryProperties(phyDevice, &memProps); + + for (int i = 0; i < memProps.memoryTypeCount; i++) { + if (!(memoryMask & (1u << i))) { + continue; + } + + int score = 0; + VkMemoryPropertyFlags flags = memProps.memoryTypes[i].propertyFlags; + + // GPU only memory + if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + score += 100; + } + + // CPU memory + if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { + score += 50; + } + + if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { + score += 25; + } + + if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + score += 10; + } + + if (score > bestScore) { + bestIndex = i; + } + } + + return bestIndex; +} + +void fillBuildInfoVk( + uint32_t count, + PalAccelerationStructureBuildInfo* info, + uint32_t* maxPrimities, + VkAccelerationStructureGeometryKHR* geometries, + VkAccelerationStructureKHR srcAs, + VkAccelerationStructureKHR dstAs, + VkAccelerationStructureBuildRangeInfoKHR* rangeInfos, + VkAccelerationStructureBuildGeometryInfoKHR* buildInfo) +{ + for (int i = 0; i < count; i++) { + // fill vulkan geometry struct + VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; + tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + tmp->flags = 0; + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { + tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; + data = &tmp->geometry.instances; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; + data->arrayOfPointers = PAL_FALSE; + + VkDeviceOrHostAddressConstKHR address = {0}; + address.deviceAddress = info->instanceBufferAddress; + data->data = address; + + if (maxPrimities) { + maxPrimities[i] = info->count; + } + + // range info + if (rangeInfos) { + VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; + rangeInfo->primitiveCount = info->count; + rangeInfo->firstVertex = 0; // PAL does not allow setting this + rangeInfo->primitiveOffset = 0; // PAL does not allow setting this + rangeInfo->transformOffset = 0; // PAL does not allow setting this + } + break; + + } else { + if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_OPAQUE) { + tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; + } + + if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT) { + tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; + } + + if (maxPrimities) { + maxPrimities[i] = info->geometries[i].primitiveCount; + } + + // range info + if (rangeInfos) { + VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; + rangeInfo->primitiveCount = info->geometries[i].primitiveCount; + rangeInfo->firstVertex = 0; // PAL does not allow setting this + rangeInfo->primitiveOffset = 0; // PAL does not allow setting this + rangeInfo->transformOffset = 0; // PAL does not allow setting this + } + } + + if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { + tmp->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; + + VkDeviceOrHostAddressConstKHR vertexAddress = {0}; + VkDeviceOrHostAddressConstKHR indexAddress = {0}; + PalGeometryDataTriangle* tmpData = info->geometries[i].data; + + vertexAddress.deviceAddress = tmpData->vertexBufferAddress; + data->vertexData = vertexAddress; + data->maxVertex = tmpData->vertexCount - 1; + data->vertexFormat = vertexTypeToVk(tmpData->vertexType); + data->vertexStride = tmpData->vertexStride; + + indexAddress.deviceAddress = tmpData->indexBufferAddress; + data->indexData = indexAddress; + if (tmpData->indexType == PAL_INDEX_TYPE_UINT32) { + data->indexType = VK_INDEX_TYPE_UINT32; + } else { + data->indexType = VK_INDEX_TYPE_UINT16; + } + + // set to none if there is no index buffer address + if (!tmpData->indexBufferAddress) { + data->indexType = VK_INDEX_TYPE_NONE_KHR; + } + + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { + tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; + VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; + data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; + + VkDeviceOrHostAddressConstKHR address = {0}; + PalGeometryDataAABBS* tmpData = info->geometries[i].data; + address.deviceAddress = tmpData->bufferAddress; + data->data = address; + data->stride = tmpData->stride; + } + } + + buildInfo->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + buildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + } else { + buildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + } + + // build mode + if (info->buildMode == PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD) { + buildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + } else { + buildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR; + } + + // build hints + buildInfo->flags = 0; + if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD) { + buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; + } + + if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE) { + buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + } + + if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY) { + buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; + } + + buildInfo->geometryCount = count; + buildInfo->srcAccelerationStructure = srcAs; + buildInfo->dstAccelerationStructure = dstAs; + buildInfo->pGeometries = geometries; + + VkDeviceOrHostAddressKHR scratchData = {0}; + scratchData.deviceAddress = info->scratchBufferAddress; + buildInfo->scratchData = scratchData; +} + +static void* VKAPI_CALL allocateVk( + void* pUserData, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope) +{ + return palAllocate(s_Vk.allocator, size, alignment); +} + +static void VKAPI_CALL freeVk( + void* pUserData, + void* ptr) +{ + palFree(s_Vk.allocator, ptr); +} + +static void alignedFree(void* ptr) +{ +#if defined(_MSC_VER) || defined(__MINGW32__) + _aligned_free(ptr); +#else + free(ptr); +#endif // _MSC_VER +} + +static void* VKAPI_CALL reallocVk( + void* pUserData, + void* pOriginal, + size_t size, + size_t alignment, + VkSystemAllocationScope allocationScope) +{ + // Note: This is a hack which could cost performance but + // realloc is not really called that much so it should be fine + // this is because we dont know the old size + void* block = alignedRealloc(pOriginal, size, alignment); + if (block) { + void* memory = palAllocate(s_Vk.allocator, size, alignment); + if (!memory) { + alignedFree(block); + return nullptr; + } + + memcpy(memory, block, size); + alignedFree(block); + return memory; + } + return nullptr; +} + +static void* loadLibrary(const char* name) +{ +#ifdef _WIN32 + return LoadLibraryA(name); +#elif defined (__linux__) + return dlopen(name, RTLD_LAZY); +#endif +} + +static void freeLibrary(void* lib) +{ +#ifdef _WIN32 + FreeLibrary(lib); +#elif defined (__linux__) + dlclose(lib); +#endif +} + +static void* loadProc(void* lib, const char* name) +{ +#ifdef _WIN32 + return GetProcAddress(lib, name); +#elif defined (__linux__) + return dlsym(lib, name); +#endif +} + +static uint32_t getNativeCode() +{ +#ifdef _WIN32 + return GetLastError(); +#elif defined (__linux__) + return errno; +#endif +} + +VkBool32 VKAPI_CALL debugCallbackVk( + VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagBitsEXT type, + const VkDebugUtilsMessengerCallbackDataEXT* data, + void* userData) +{ + if (!s_Vk.callback) { + return VK_FALSE; + } + + PalDebugMessageSeverity debugSeverity = 0; + PalDebugMessageType debugType = 0; + if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) { + debugType = PAL_DEBUG_MESSAGE_TYPE_GENERAL; + } + + if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) { + debugType = PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE; + } + + if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT) { + debugType = PAL_DEBUG_MESSAGE_TYPE_VALIDATION; + } + + if (type & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { + debugSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; + } + + if (type & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { + debugSeverity = PAL_DEBUG_MESSAGE_SEVERITY_WARNING; + } + + if (type & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { + debugSeverity = PAL_DEBUG_MESSAGE_SEVERITY_ERROR; + } + + s_Vk.callback(userData, debugSeverity, debugType, data->pMessage); + return VK_FALSE; +} + +PalResult PAL_CALL initGraphicsVk( + const PalGraphicsDebugger* debugger, + const PalAllocator* allocator) +{ + // load vulkan + s_Vk.handle = loadLibrary(VK_LIB_NAME); + if (!s_Vk.handle) { + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, RESULT_SOURCE, getNativeCode()); + } + + // clang-format off + s_Vk.enumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)loadProc( + s_Vk.handle, + "vkEnumerateInstanceVersion"); + + s_Vk.enumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)loadProc( + s_Vk.handle, + "vkEnumerateInstanceExtensionProperties"); + + s_Vk.createInstance = (PFN_vkCreateInstance)loadProc( + s_Vk.handle, + "vkCreateInstance"); + + s_Vk.destroyInstance = (PFN_vkDestroyInstance)loadProc( + s_Vk.handle, + "vkDestroyInstance"); + + s_Vk.enumeratePhysicalDevices = (PFN_vkEnumeratePhysicalDevices)loadProc( + s_Vk.handle, + "vkEnumeratePhysicalDevices"); + + s_Vk.getPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties)loadProc( + s_Vk.handle, + "vkGetPhysicalDeviceProperties"); + + s_Vk.getPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties)loadProc( + s_Vk.handle, + "vkGetPhysicalDeviceMemoryProperties"); + + s_Vk.enumerateInstanceLayerProperties = (PFN_vkEnumerateInstanceLayerProperties)loadProc( + s_Vk.handle, + "vkEnumerateInstanceLayerProperties"); + + s_Vk.getPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties)loadProc( + s_Vk.handle, + "vkGetPhysicalDeviceQueueFamilyProperties"); + + s_Vk.enumerateDeviceExtensionProperties = (PFN_vkEnumerateDeviceExtensionProperties)loadProc( + s_Vk.handle, + "vkEnumerateDeviceExtensionProperties"); + + s_Vk.getPhysicalDeviceFeatures = (PFN_vkGetPhysicalDeviceFeatures)loadProc( + s_Vk.handle, + "vkGetPhysicalDeviceFeatures"); + + s_Vk.getPhysicalDeviceFeatures2 = (PFN_vkGetPhysicalDeviceFeatures2)loadProc( + s_Vk.handle, + "vkGetPhysicalDeviceFeatures2"); + + s_Vk.getInstanceProcAddr = (PFN_vkGetInstanceProcAddr)loadProc( + s_Vk.handle, + "vkGetInstanceProcAddr"); + + s_Vk.createImage = (PFN_vkCreateImage)loadProc( + s_Vk.handle, + "vkCreateImage"); + + s_Vk.destroyImage = (PFN_vkDestroyImage)loadProc( + s_Vk.handle, + "vkDestroyImage"); + + s_Vk.createImageView = (PFN_vkCreateImageView)loadProc( + s_Vk.handle, + "vkCreateImageView"); + + s_Vk.destroyImageView = (PFN_vkDestroyImageView)loadProc( + s_Vk.handle, + "vkDestroyImageView"); + + s_Vk.createShader = (PFN_vkCreateShaderModule)loadProc( + s_Vk.handle, + "vkCreateShaderModule"); + + s_Vk.destroyShader = (PFN_vkDestroyShaderModule)loadProc( + s_Vk.handle, + "vkDestroyShaderModule"); + + s_Vk.createSampler = (PFN_vkCreateSampler)loadProc( + s_Vk.handle, + "vkCreateSampler"); + + s_Vk.destroySampler = (PFN_vkDestroySampler)loadProc( + s_Vk.handle, + "vkDestroySampler"); + + s_Vk.getPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2)loadProc( + s_Vk.handle, + "vkGetPhysicalDeviceProperties2"); + + s_Vk.getPhysicalDeviceFormatProperties = (PFN_vkGetPhysicalDeviceFormatProperties)loadProc( + s_Vk.handle, + "vkGetPhysicalDeviceFormatProperties"); + + s_Vk.getPhysicalDeviceImageFormatProperties = (PFN_vkGetPhysicalDeviceImageFormatProperties)loadProc( + s_Vk.handle, + "vkGetPhysicalDeviceImageFormatProperties"); + + s_Vk.createDevice = (PFN_vkCreateDevice)loadProc( + s_Vk.handle, + "vkCreateDevice"); + + s_Vk.destroyDevice = (PFN_vkDestroyDevice)loadProc( + s_Vk.handle, + "vkDestroyDevice"); + + s_Vk.getDeviceQueue = (PFN_vkGetDeviceQueue)loadProc( + s_Vk.handle, + "vkGetDeviceQueue"); + + s_Vk.queueSubmit = (PFN_vkQueueSubmit)loadProc( + s_Vk.handle, + "vkQueueSubmit"); + + s_Vk.getDeviceProcAddr = (PFN_vkGetDeviceProcAddr)loadProc( + s_Vk.handle, + "vkGetDeviceProcAddr"); + + s_Vk.getImageMemoryRequirements = (PFN_vkGetImageMemoryRequirements)loadProc( + s_Vk.handle, + "vkGetImageMemoryRequirements"); + + s_Vk.allocateMemory = (PFN_vkAllocateMemory)loadProc( + s_Vk.handle, + "vkAllocateMemory"); + + s_Vk.freeMemory = (PFN_vkFreeMemory)loadProc( + s_Vk.handle, + "vkFreeMemory"); + + s_Vk.bindImageMemory = (PFN_vkBindImageMemory)loadProc( + s_Vk.handle, + "vkBindImageMemory"); + + s_Vk.createCommandPool = (PFN_vkCreateCommandPool)loadProc( + s_Vk.handle, + "vkCreateCommandPool"); + + s_Vk.destroyCommandPool = (PFN_vkDestroyCommandPool)loadProc( + s_Vk.handle, + "vkDestroyCommandPool"); + + s_Vk.allocateCommandBuffer = (PFN_vkAllocateCommandBuffers)loadProc( + s_Vk.handle, + "vkAllocateCommandBuffers"); + + s_Vk.freeCommandBuffer = (PFN_vkFreeCommandBuffers)loadProc( + s_Vk.handle, + "vkFreeCommandBuffers"); + + s_Vk.createFence = (PFN_vkCreateFence)loadProc( + s_Vk.handle, + "vkCreateFence"); + + s_Vk.destroyFence = (PFN_vkDestroyFence)loadProc( + s_Vk.handle, + "vkDestroyFence"); + + s_Vk.resetFence = (PFN_vkResetFences)loadProc( + s_Vk.handle, + "vkResetFences"); + + s_Vk.waitFence = (PFN_vkWaitForFences)loadProc( + s_Vk.handle, + "vkWaitForFences"); + + s_Vk.isFenceSignaled = (PFN_vkGetFenceStatus)loadProc( + s_Vk.handle, + "vkGetFenceStatus"); + + s_Vk.createSemaphore = (PFN_vkCreateSemaphore)loadProc( + s_Vk.handle, + "vkCreateSemaphore"); + + s_Vk.destroySemaphore = (PFN_vkDestroySemaphore)loadProc( + s_Vk.handle, + "vkDestroySemaphore"); + + s_Vk.cmdBegin = (PFN_vkBeginCommandBuffer)loadProc( + s_Vk.handle, + "vkBeginCommandBuffer"); + + s_Vk.cmdEnd = (PFN_vkEndCommandBuffer)loadProc( + s_Vk.handle, + "vkEndCommandBuffer"); + + s_Vk.resetCommandPool = (PFN_vkResetCommandPool)loadProc( + s_Vk.handle, + "vkResetCommandPool"); + + s_Vk.resetCommandBuffer = (PFN_vkResetCommandBuffer)loadProc( + s_Vk.handle, + "vkResetCommandBuffer"); + + s_Vk.cmdExecuteCommandBuffer = (PFN_vkCmdExecuteCommands)loadProc( + s_Vk.handle, + "vkCmdExecuteCommands"); + + s_Vk.cmdCopyBuffer = (PFN_vkCmdCopyBuffer)loadProc( + s_Vk.handle, + "vkCmdCopyBuffer"); + + s_Vk.cmdCopyBufferToImage = (PFN_vkCmdCopyBufferToImage)loadProc( + s_Vk.handle, + "vkCmdCopyBufferToImage"); + + s_Vk.cmdCopyImage = (PFN_vkCmdCopyImage)loadProc( + s_Vk.handle, + "vkCmdCopyImage"); + + s_Vk.cmdCopyImageToBuffer = (PFN_vkCmdCopyImageToBuffer)loadProc( + s_Vk.handle, + "vkCmdCopyImageToBuffer"); + + s_Vk.cmdBindPipeline = (PFN_vkCmdBindPipeline)loadProc( + s_Vk.handle, + "vkCmdBindPipeline"); + + s_Vk.cmdSetViewports = (PFN_vkCmdSetViewport)loadProc( + s_Vk.handle, + "vkCmdSetViewport"); + + s_Vk.cmdSetScissors = (PFN_vkCmdSetScissor)loadProc( + s_Vk.handle, + "vkCmdSetScissor"); + + s_Vk.cmdBindVertexBuffers = (PFN_vkCmdBindVertexBuffers)loadProc( + s_Vk.handle, + "vkCmdBindVertexBuffers"); + + s_Vk.cmdBindIndexBuffer = (PFN_vkCmdBindIndexBuffer)loadProc( + s_Vk.handle, + "vkCmdBindIndexBuffer"); + + s_Vk.cmdDraw = (PFN_vkCmdDraw)loadProc( + s_Vk.handle, + "vkCmdDraw"); + + s_Vk.cmdDrawIndirect = (PFN_vkCmdDrawIndirect)loadProc( + s_Vk.handle, + "vkCmdDrawIndirect"); + + s_Vk.cmdDrawIndexed = (PFN_vkCmdDrawIndexed)loadProc( + s_Vk.handle, + "vkCmdDrawIndexed"); + + s_Vk.cmdDrawIndexedIndirect = (PFN_vkCmdDrawIndexedIndirect)loadProc( + s_Vk.handle, + "vkCmdDrawIndexedIndirect"); + + s_Vk.cmdDispatch = (PFN_vkCmdDispatch)loadProc( + s_Vk.handle, + "vkCmdDispatch"); + + s_Vk.cmdDispatchIndirect = (PFN_vkCmdDispatchIndirect)loadProc( + s_Vk.handle, + "vkCmdDispatchIndirect"); + + s_Vk.cmdBindDescriptorSets = (PFN_vkCmdBindDescriptorSets)loadProc( + s_Vk.handle, + "vkCmdBindDescriptorSets"); + + s_Vk.cmdPushConstants = (PFN_vkCmdPushConstants)loadProc( + s_Vk.handle, + "vkCmdPushConstants"); + + s_Vk.createBuffer = (PFN_vkCreateBuffer)loadProc( + s_Vk.handle, + "vkCreateBuffer"); + + s_Vk.destroyBuffer = (PFN_vkDestroyBuffer)loadProc( + s_Vk.handle, + "vkDestroyBuffer"); + + s_Vk.mapMemory = (PFN_vkMapMemory)loadProc( + s_Vk.handle, + "vkMapMemory"); + + s_Vk.unmapMemory = (PFN_vkUnmapMemory)loadProc( + s_Vk.handle, + "vkUnmapMemory"); + + s_Vk.getBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress)loadProc( + s_Vk.handle, + "vkGetBufferDeviceAddress"); + + s_Vk.getBufferMemoryRequirements = (PFN_vkGetBufferMemoryRequirements)loadProc( + s_Vk.handle, + "vkGetBufferMemoryRequirements"); + + s_Vk.bindBufferMemory = (PFN_vkBindBufferMemory)loadProc( + s_Vk.handle, + "vkBindBufferMemory"); + + s_Vk.createDescriptorSetLayout = (PFN_vkCreateDescriptorSetLayout)loadProc( + s_Vk.handle, + "vkCreateDescriptorSetLayout"); + + s_Vk.destroyDescriptorSetLayout = (PFN_vkDestroyDescriptorSetLayout)loadProc( + s_Vk.handle, + "vkDestroyDescriptorSetLayout"); + + s_Vk.createDescriptorPool = (PFN_vkCreateDescriptorPool)loadProc( + s_Vk.handle, + "vkCreateDescriptorPool"); + + s_Vk.destroyDescriptorPool = (PFN_vkDestroyDescriptorPool)loadProc( + s_Vk.handle, + "vkDestroyDescriptorPool"); + + s_Vk.resetDescriptorPool = (PFN_vkResetDescriptorPool)loadProc( + s_Vk.handle, + "vkResetDescriptorPool"); + + s_Vk.allocateDescriptorSet = (PFN_vkAllocateDescriptorSets)loadProc( + s_Vk.handle, + "vkAllocateDescriptorSets"); + + s_Vk.updateDescriptorSet = (PFN_vkUpdateDescriptorSets)loadProc( + s_Vk.handle, + "vkUpdateDescriptorSets"); + + s_Vk.createPipelineLayout = (PFN_vkCreatePipelineLayout)loadProc( + s_Vk.handle, + "vkCreatePipelineLayout"); + + s_Vk.destroyPipelineLayout = (PFN_vkDestroyPipelineLayout)loadProc( + s_Vk.handle, + "vkDestroyPipelineLayout"); + + s_Vk.createGraphicsPipeline = (PFN_vkCreateGraphicsPipelines)loadProc( + s_Vk.handle, + "vkCreateGraphicsPipelines"); + + s_Vk.createComputePipeline = (PFN_vkCreateComputePipelines)loadProc( + s_Vk.handle, + "vkCreateComputePipelines"); + + s_Vk.destroyPipeline = (PFN_vkDestroyPipeline)loadProc( + s_Vk.handle, + "vkDestroyPipeline"); + + s_Vk.waitQueue = (PFN_vkQueueWaitIdle)loadProc( + s_Vk.handle, + "vkQueueWaitIdle"); + // clang-format on + + // get version + PalBool versionFallback = PAL_FALSE; + uint32_t version = 0; + if (s_Vk.enumerateInstanceVersion) { + s_Vk.enumerateInstanceVersion(&version); + if (version <= VK_API_VERSION_1_0) { + versionFallback = PAL_TRUE; + } + } + + VkResult result; + uint32_t layerCount = 0; + PalBool hasValidationLayer = PAL_FALSE; + s_Vk.messenger = nullptr; + s_Vk.allocator = allocator; + VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {0}; + debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + + if (debugger && debugger->callback) { + // layers + result = s_Vk.enumerateInstanceLayerProperties(&layerCount, nullptr); + if (result == VK_SUCCESS) { + VkLayerProperties* props = nullptr; + props = palAllocate(s_Vk.allocator, sizeof(VkLayerProperties) * layerCount, 0); + if (!props) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + s_Vk.enumerateInstanceLayerProperties(&layerCount, props); + for (int i = 0; i < layerCount; i++) { + const char* name = props[i].layerName; + if (strcmp(name, "VK_LAYER_KHRONOS_validation") == 0) { + hasValidationLayer = PAL_TRUE; + break; + } + } + palFree(s_Vk.allocator, props); + + // message types + if (!debugger->denyGeneral) { + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT; + } + + if (!debugger->denyPerformance) { + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + } + + if (!debugger->denyValidation) { + debugCreateInfo.messageType |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + } + + // message severities + if (!debugger->denyInfoSeverity) { + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + } + + if (!debugger->denyWarningSeverity) { + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + } + + if (!debugger->denyErrorSeverity) { + debugCreateInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + } + + debugCreateInfo.pUserData = debugger->userData; + debugCreateInfo.pfnUserCallback = debugCallbackVk; + s_Vk.callback = debugger->callback; + } + } + + // extensions + uint32_t extCount = 0; + const char* extensions[8]; + result = s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, nullptr); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + VkExtensionProperties* extensionProps = nullptr; + extensionProps = palAllocate(s_Vk.allocator, sizeof(VkExtensionProperties) * extCount, 0); + if (!extensionProps) { + return PAL_RESULT_SUCCESS; + } + + PalBool hasXlib = PAL_FALSE; + PalBool hasXcb = PAL_FALSE; + PalBool hasWayland = PAL_FALSE; + PalBool hasWin32 = PAL_FALSE; + PalBool hasSurface = PAL_FALSE; + PalBool hasExtDebug = PAL_FALSE; + s_Vk.enumerateInstanceExtensionProperties(nullptr, &extCount, extensionProps); + + for (int i = 0; i < extCount; i++) { + VkExtensionProperties* prop = &extensionProps[i]; + if (strcmp(prop->extensionName, "VK_KHR_xlib_surface") == 0) { + hasXlib = PAL_TRUE; + + } else if (strcmp(prop->extensionName, "VK_KHR_xcb_surface") == 0) { + hasXcb = PAL_TRUE; + + } else if (strcmp(prop->extensionName, "VK_KHR_wayland_surface") == 0) { + hasWayland = PAL_TRUE; + + } else if (strcmp(prop->extensionName, "VK_KHR_win32_surface") == 0) { + hasWin32 = PAL_TRUE; + + } else if (strcmp(prop->extensionName, "VK_KHR_surface") == 0) { + hasSurface = PAL_TRUE; + + } else if (strcmp(prop->extensionName, "VK_EXT_debug_utils") == 0) { + hasExtDebug = PAL_TRUE; + } + } + palFree(s_Vk.allocator, extensionProps); + + int extensionCount = 0; + if (hasSurface) { + extensions[extensionCount++] = "VK_KHR_surface"; + if (hasWayland) { + extensions[extensionCount++] = "VK_KHR_wayland_surface"; + } + + if (hasXlib) { + extensions[extensionCount++] = "VK_KHR_xlib_surface"; + } + + if (hasXcb) { + extensions[extensionCount++] = "VK_KHR_xcb_surface"; + } + + if (hasWin32) { + extensions[extensionCount++] = "VK_KHR_win32_surface"; + } + } + + const char* layers[2]; + layerCount = 0; + if (hasValidationLayer && hasExtDebug) { + extensions[extensionCount++] = "VK_EXT_debug_utils"; + layers[layerCount++] = "VK_LAYER_KHRONOS_validation"; + } + + if (versionFallback) { + const char* name = "VK_KHR_get_physical_device_properties2"; + extensions[extensionCount++] = name; + } + + VkApplicationInfo appInfo = {0}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.apiVersion = version; + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.pEngineName = "Engine"; + appInfo.pApplicationName = "App"; + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + + VkInstanceCreateInfo instanceCreateInfo = {0}; + instanceCreateInfo.pApplicationInfo = &appInfo; + instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instanceCreateInfo.enabledExtensionCount = extensionCount; + instanceCreateInfo.enabledLayerCount = layerCount; + instanceCreateInfo.ppEnabledExtensionNames = extensions; + instanceCreateInfo.ppEnabledLayerNames = layers; + + if (debugger && debugger->callback) { + instanceCreateInfo.pNext = &debugCreateInfo; + } + + // vk allocator + s_Vk.vkAllocator.pfnAllocation = allocateVk; + s_Vk.vkAllocator.pfnFree = freeVk; + s_Vk.vkAllocator.pfnReallocation = reallocVk; + + VkInstance instance = nullptr; + result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.vkAllocator, &instance); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + // clang-format off + if (versionFallback) { + // load get physical device properties2 proc if we are on version 1.0 + s_Vk.getPhysicalDeviceFeatures2 = + (PFN_vkGetPhysicalDeviceFeatures2KHR)s_Vk.getInstanceProcAddr( + s_Vk.handle, + "vkGetPhysicalDeviceFeatures2KHR"); + } + + // load surface creation function pointers + s_Vk.createWaylandSurface = nullptr; + s_Vk.createXlibSurface = nullptr; + s_Vk.createXcbSurface = nullptr; + s_Vk.createWin32Surface = nullptr; + + if (hasWayland) { + s_Vk.createWaylandSurface = (PFN_vkCreateWaylandSurfaceKHR)s_Vk.getInstanceProcAddr( + instance, + "vkCreateWaylandSurfaceKHR"); + } + + if (hasXlib) { + s_Vk.createXlibSurface = (PFN_vkCreateXlibSurfaceKHR)s_Vk.getInstanceProcAddr( + instance, + "vkCreateXlibSurfaceKHR"); + } + + if (hasXcb) { + s_Vk.createXcbSurface = (PFN_vkCreateXcbSurfaceKHR)s_Vk.getInstanceProcAddr( + instance, + "vkCreateXcbSurfaceKHR"); + } + + if (hasWin32) { + s_Vk.createWin32Surface = (PFN_vkCreateWin32SurfaceKHR)s_Vk.getInstanceProcAddr( + instance, + "vkCreateWin32SurfaceKHR"); + } + + // remaining function procs + s_Vk.destroySurface = (PFN_vkDestroySurfaceKHR)s_Vk.getInstanceProcAddr( + instance, + "vkDestroySurfaceKHR"); + + s_Vk.getSurfaceCapabilities = + (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); + + s_Vk.getSurfacePresentModes = + (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceSurfacePresentModesKHR"); + + s_Vk.getSurfaceFormats = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceSurfaceFormatsKHR"); + + s_Vk.checkSurfaceSupport = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)s_Vk.getInstanceProcAddr( + instance, + "vkGetPhysicalDeviceSurfaceSupportKHR"); + + if (debugger) { + s_Vk.createMessenger = + (PFN_vkCreateDebugUtilsMessengerEXT)s_Vk.getInstanceProcAddr( + instance, + "vkCreateDebugUtilsMessengerEXT"); + + s_Vk.destroyMessenger = + (PFN_vkDestroyDebugUtilsMessengerEXT)s_Vk.getInstanceProcAddr( + instance, + "vkDestroyDebugUtilsMessengerEXT"); + + s_Vk.createMessenger(instance, &debugCreateInfo, &s_Vk.vkAllocator, &s_Vk.messenger); + } + // clang-format on + + s_Vk.adapters = nullptr; + s_Vk.instance = instance; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL shutdownGraphicsVk() +{ + if (s_Vk.messenger) { + s_Vk.destroyMessenger(s_Vk.instance, s_Vk.messenger, &s_Vk.vkAllocator); + } + + s_Vk.destroyInstance(s_Vk.instance, &s_Vk.vkAllocator); + freeLibrary(s_Vk.handle); + if (s_Vk.adapters) { + palFree(s_Vk.allocator, s_Vk.adapters); + } + memset(&s_Vk, 0, sizeof(s_Vk)); +} + +#endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h index e80dae58..ee79716f 100644 --- a/src/graphics/vulkan/pal_vulkan.h +++ b/src/graphics/vulkan/pal_vulkan.h @@ -118,6 +118,7 @@ typedef struct { } AddressRegion; typedef struct { + VkPipelineStageFlags2 stage; VkAccessFlags2 access; VkImageLayout layout; } Barrier; @@ -473,13 +474,9 @@ VkExtent2D getShadingRateSizeVk(PalFragmentShadingRate rate); VkFragmentShadingRateCombinerOpKHR combinerOpsToVk(PalFragmentShadingRateCombinerOp op); VkImageAspectFlags imageAspectToVk(PalImageAspect aspect); -Barrier barrierToVk(PalUsageState state); VkStencilOp stencilOpToVk(PalStencilOp op); VkCompareOp compareOpToVk(PalCompareOp op); -VkRenderingFlags renderingFlagToVk(PalRenderingFlags flags); -VkFormat vertexTypeToVk(PalVertexType type); - uint32_t findBestMemoryIndexVk( VkPhysicalDevice phyDevice, uint32_t memoryMask); diff --git a/tests/tests.lua b/tests/tests.lua index ca867607..f151a4a1 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -70,21 +70,21 @@ project "tests" if (PAL_BUILD_GRAPHICS_MODULE) then files { "graphics/graphics_test.c", - "graphics/compute_test.c", - "graphics/ray_tracing_test.c", - "graphics/multi_descriptor_set_test.c" + -- "graphics/compute_test.c", + -- "graphics/ray_tracing_test.c", + -- "graphics/multi_descriptor_set_test.c" } end if (PAL_BUILD_GRAPHICS_MODULE and PAL_BUILD_VIDEO_MODULE) then files { - "graphics/clear_color_test.c", - "graphics/triangle_test.c", - "graphics/mesh_test.c", - "graphics/texture_test.c", - "graphics/geometry_test.c", - "graphics/indirect_draw_test.c", - "graphics/descriptor_indexing_test.c" + -- "graphics/clear_color_test.c", + -- "graphics/triangle_test.c", + -- "graphics/mesh_test.c", + -- "graphics/texture_test.c", + -- "graphics/geometry_test.c", + -- "graphics/indirect_draw_test.c", + -- "graphics/descriptor_indexing_test.c" } end diff --git a/tests/tests_main.c b/tests/tests_main.c index 5d4e2f46..34ee42d2 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -56,7 +56,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS_MODULE == 1 - // registerTest(graphicsTest, "Graphics Test"); + registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); From 8a5f1c03bee733a46168507a9dba2d3ee3531fee Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 3 Jul 2026 15:04:49 +0000 Subject: [PATCH 312/372] graphics rework: graphics test working --- include/pal/pal_graphics.h | 5 +- pal.lua | 2 +- src/core/pal_result.h | 2 +- src/graphics/pal_graphics.c | 2 +- src/graphics/vulkan/pal_device_vulkan.c | 8 +- src/graphics/vulkan/pal_pipeline_vulkan.c | 97 ----------- src/graphics/vulkan/pal_vulkan.c | 131 ++++++++++++-- src/graphics/vulkan/pal_vulkan.h | 1 + tests/graphics/graphics_test.c | 197 +++++++--------------- 9 files changed, 192 insertions(+), 253 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index b50b6a01..aa61e480 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -190,8 +190,9 @@ #define PAL_SHADER_FORMAT_SPIRV (1U << 0) #define PAL_SHADER_FORMAT_DXIL (1U << 1) -#define PAL_SHADER_FORMAT_MSL (1U << 2) -#define PAL_SHADER_FORMAT_CUSTOM (1U << 3) +#define PAL_SHADER_FORMAT_DXBC (1U << 2) +#define PAL_SHADER_FORMAT_MSL (1U << 3) +#define PAL_SHADER_FORMAT_CUSTOM (1U << 4) #define PAL_LOAD_OP_LOAD 0 #define PAL_LOAD_OP_CLEAR 1 diff --git a/pal.lua b/pal.lua index c9219a59..f988e941 100644 --- a/pal.lua +++ b/pal.lua @@ -226,7 +226,7 @@ project "PAL" d3d12Include } - defines { "PAL_HAS_D3D12_BACKEND=1" } + --defines { "PAL_HAS_D3D12_BACKEND=1" } else defines { "PAL_HAS_D3D12_BACKEND=0" } end diff --git a/src/core/pal_result.h b/src/core/pal_result.h index 4b97dc44..85d51191 100644 --- a/src/core/pal_result.h +++ b/src/core/pal_result.h @@ -109,7 +109,7 @@ static const char* resultSourceToString(PalResult result) return "METAL"; } - return ""; + return "NONE"; } static void formatResultMsg(PalResult result, char* buffer, char* msg) diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index f8f07b9f..9be7f28b 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -464,7 +464,7 @@ PalResult PAL_CALL palInitGraphics( return PAL_RESULT_SUCCESS; } - if (customBackendCount == 0) { + if (customBackendCount == 0 && customBackends) { return PAL_RESULT_CODE_PLATFORM_FAILURE; } diff --git a/src/graphics/vulkan/pal_device_vulkan.c b/src/graphics/vulkan/pal_device_vulkan.c index 54e83262..295db927 100644 --- a/src/graphics/vulkan/pal_device_vulkan.c +++ b/src/graphics/vulkan/pal_device_vulkan.c @@ -1138,9 +1138,9 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( s_Vk.getPhysicalDeviceFeatures2(vkDevice->phyDevice, &features); s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); - PalDescriptorIndexingFlags flags = 0; + caps->flags = 0; if (desc.descriptorBindingPartiallyBound) { - flags |= PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND; + caps->flags |= PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND; } // clang-format off @@ -1149,14 +1149,14 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( desc.descriptorBindingStorageImageUpdateAfterBind && desc.descriptorBindingStorageBufferUpdateAfterBind && desc.descriptorBindingUniformBufferUpdateAfterBind) { - flags |= PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; + caps->flags |= PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; } if (desc.shaderSampledImageArrayNonUniformIndexing && desc.shaderStorageImageArrayNonUniformIndexing && desc.shaderStorageBufferArrayNonUniformIndexing && desc.shaderUniformBufferArrayNonUniformIndexing) { - flags |= PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING; + caps->flags |= PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING; } // clang-format on diff --git a/src/graphics/vulkan/pal_pipeline_vulkan.c b/src/graphics/vulkan/pal_pipeline_vulkan.c index bad7daa5..aa6bb890 100644 --- a/src/graphics/vulkan/pal_pipeline_vulkan.c +++ b/src/graphics/vulkan/pal_pipeline_vulkan.c @@ -173,103 +173,6 @@ static uint32_t getVertexTypeSizeVk(PalVertexType type) return 0; } -static VkFormat vertexTypeToVk(PalVertexType type) -{ - switch (type) { - case PAL_VERTEX_TYPE_INT32: - return VK_FORMAT_R32_SINT; - - case PAL_VERTEX_TYPE_INT32_2: - return VK_FORMAT_R32G32_SINT; - - case PAL_VERTEX_TYPE_INT32_3: - return VK_FORMAT_R32G32B32_SINT; - - case PAL_VERTEX_TYPE_INT32_4: - return VK_FORMAT_R32G32B32A32_SINT; - - case PAL_VERTEX_TYPE_UINT32: - return VK_FORMAT_R32_UINT; - - case PAL_VERTEX_TYPE_UINT32_2: - return VK_FORMAT_R32G32_UINT; - - case PAL_VERTEX_TYPE_UINT32_3: - return VK_FORMAT_R32G32B32_UINT; - - case PAL_VERTEX_TYPE_UINT32_4: - return VK_FORMAT_R32G32B32A32_UINT; - - case PAL_VERTEX_TYPE_INT8_2: - return VK_FORMAT_R8G8_SINT; - - case PAL_VERTEX_TYPE_INT8_4: - return VK_FORMAT_R8G8B8A8_SINT; - - case PAL_VERTEX_TYPE_UINT8_2: - return VK_FORMAT_R8G8_UINT; - - case PAL_VERTEX_TYPE_UINT8_4: - return VK_FORMAT_R8G8B8A8_UINT; - - case PAL_VERTEX_TYPE_INT8_2NORM: - return VK_FORMAT_R8G8_SNORM; - - case PAL_VERTEX_TYPE_INT8_4NORM: - return VK_FORMAT_R8G8B8A8_SNORM; - - case PAL_VERTEX_TYPE_UINT8_2NORM: - return VK_FORMAT_R8G8_UNORM; - - case PAL_VERTEX_TYPE_UINT8_4NORM: - return VK_FORMAT_R8G8B8A8_UNORM; - - case PAL_VERTEX_TYPE_INT16_2: - return VK_FORMAT_R16G16_SINT; - - case PAL_VERTEX_TYPE_INT16_4: - return VK_FORMAT_R16G16B16A16_SINT; - - case PAL_VERTEX_TYPE_UINT16_2: - return VK_FORMAT_R16G16_UINT; - - case PAL_VERTEX_TYPE_UINT16_4: - return VK_FORMAT_R16G16B16A16_UINT; - - case PAL_VERTEX_TYPE_INT16_2NORM: - return VK_FORMAT_R16G16_SNORM; - - case PAL_VERTEX_TYPE_INT16_4NORM: - return VK_FORMAT_R16G16B16A16_SNORM; - - case PAL_VERTEX_TYPE_UINT16_2NORM: - return VK_FORMAT_R16G16_UNORM; - - case PAL_VERTEX_TYPE_UINT16_4NORM: - return VK_FORMAT_R16G16B16A16_UNORM; - - case PAL_VERTEX_TYPE_FLOAT: - return VK_FORMAT_R32_SFLOAT; - - case PAL_VERTEX_TYPE_FLOAT2: - return VK_FORMAT_R32G32_SFLOAT; - - case PAL_VERTEX_TYPE_FLOAT3: - return VK_FORMAT_R32G32B32_SFLOAT; - - case PAL_VERTEX_TYPE_FLOAT4: - return VK_FORMAT_R32G32B32A32_SFLOAT; - - case PAL_VERTEX_TYPE_HALF_FLOAT16_2: - return VK_FORMAT_R16G16_SFLOAT; - - case PAL_VERTEX_TYPE_HALF_FLOAT16_4: - return VK_FORMAT_R16G16B16A16_SFLOAT; - } - - return VK_FORMAT_UNDEFINED; -} - PalResult PAL_CALL createPipelineLayoutVk( PalDevice* device, const PalPipelineLayoutCreateInfo* info, diff --git a/src/graphics/vulkan/pal_vulkan.c b/src/graphics/vulkan/pal_vulkan.c index b34a8ec4..3a72a4bf 100644 --- a/src/graphics/vulkan/pal_vulkan.c +++ b/src/graphics/vulkan/pal_vulkan.c @@ -533,6 +533,103 @@ uint32_t findBestMemoryIndexVk( return bestIndex; } +VkFormat vertexTypeToVk(PalVertexType type) +{ + switch (type) { + case PAL_VERTEX_TYPE_INT32: + return VK_FORMAT_R32_SINT; + + case PAL_VERTEX_TYPE_INT32_2: + return VK_FORMAT_R32G32_SINT; + + case PAL_VERTEX_TYPE_INT32_3: + return VK_FORMAT_R32G32B32_SINT; + + case PAL_VERTEX_TYPE_INT32_4: + return VK_FORMAT_R32G32B32A32_SINT; + + case PAL_VERTEX_TYPE_UINT32: + return VK_FORMAT_R32_UINT; + + case PAL_VERTEX_TYPE_UINT32_2: + return VK_FORMAT_R32G32_UINT; + + case PAL_VERTEX_TYPE_UINT32_3: + return VK_FORMAT_R32G32B32_UINT; + + case PAL_VERTEX_TYPE_UINT32_4: + return VK_FORMAT_R32G32B32A32_UINT; + + case PAL_VERTEX_TYPE_INT8_2: + return VK_FORMAT_R8G8_SINT; + + case PAL_VERTEX_TYPE_INT8_4: + return VK_FORMAT_R8G8B8A8_SINT; + + case PAL_VERTEX_TYPE_UINT8_2: + return VK_FORMAT_R8G8_UINT; + + case PAL_VERTEX_TYPE_UINT8_4: + return VK_FORMAT_R8G8B8A8_UINT; + + case PAL_VERTEX_TYPE_INT8_2NORM: + return VK_FORMAT_R8G8_SNORM; + + case PAL_VERTEX_TYPE_INT8_4NORM: + return VK_FORMAT_R8G8B8A8_SNORM; + + case PAL_VERTEX_TYPE_UINT8_2NORM: + return VK_FORMAT_R8G8_UNORM; + + case PAL_VERTEX_TYPE_UINT8_4NORM: + return VK_FORMAT_R8G8B8A8_UNORM; + + case PAL_VERTEX_TYPE_INT16_2: + return VK_FORMAT_R16G16_SINT; + + case PAL_VERTEX_TYPE_INT16_4: + return VK_FORMAT_R16G16B16A16_SINT; + + case PAL_VERTEX_TYPE_UINT16_2: + return VK_FORMAT_R16G16_UINT; + + case PAL_VERTEX_TYPE_UINT16_4: + return VK_FORMAT_R16G16B16A16_UINT; + + case PAL_VERTEX_TYPE_INT16_2NORM: + return VK_FORMAT_R16G16_SNORM; + + case PAL_VERTEX_TYPE_INT16_4NORM: + return VK_FORMAT_R16G16B16A16_SNORM; + + case PAL_VERTEX_TYPE_UINT16_2NORM: + return VK_FORMAT_R16G16_UNORM; + + case PAL_VERTEX_TYPE_UINT16_4NORM: + return VK_FORMAT_R16G16B16A16_UNORM; + + case PAL_VERTEX_TYPE_FLOAT: + return VK_FORMAT_R32_SFLOAT; + + case PAL_VERTEX_TYPE_FLOAT2: + return VK_FORMAT_R32G32_SFLOAT; + + case PAL_VERTEX_TYPE_FLOAT3: + return VK_FORMAT_R32G32B32_SFLOAT; + + case PAL_VERTEX_TYPE_FLOAT4: + return VK_FORMAT_R32G32B32A32_SFLOAT; + + case PAL_VERTEX_TYPE_HALF_FLOAT16_2: + return VK_FORMAT_R16G16_SFLOAT; + + case PAL_VERTEX_TYPE_HALF_FLOAT16_4: + return VK_FORMAT_R16G16B16A16_SFLOAT; + } + + return VK_FORMAT_UNDEFINED; +} + void fillBuildInfoVk( uint32_t count, PalAccelerationStructureBuildInfo* info, @@ -604,7 +701,7 @@ void fillBuildInfoVk( VkDeviceOrHostAddressConstKHR vertexAddress = {0}; VkDeviceOrHostAddressConstKHR indexAddress = {0}; - PalGeometryDataTriangle* tmpData = info->geometries[i].data; + const PalGeometryDataTriangle* tmpData = info->geometries[i].data; vertexAddress.deviceAddress = tmpData->vertexBufferAddress; data->vertexData = vertexAddress; @@ -631,7 +728,7 @@ void fillBuildInfoVk( data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; VkDeviceOrHostAddressConstKHR address = {0}; - PalGeometryDataAABBS* tmpData = info->geometries[i].data; + const PalGeometryDataAABBS* tmpData = info->geometries[i].data; address.deviceAddress = tmpData->bufferAddress; data->data = address; data->stride = tmpData->stride; @@ -676,6 +773,27 @@ void fillBuildInfoVk( buildInfo->scratchData = scratchData; } +static void* alignedRealloc( + void* memory, + uint64_t size, + uint64_t alignment) +{ +#if defined(_MSC_VER) || defined(__MINGW32__) + return _aligned_realloc(memory, size, alignment); +#else + return realloc(memory, size); +#endif // _MSC_VER +} + +static void alignedFree(void* ptr) +{ +#if defined(_MSC_VER) || defined(__MINGW32__) + _aligned_free(ptr); +#else + free(ptr); +#endif // _MSC_VER +} + static void* VKAPI_CALL allocateVk( void* pUserData, size_t size, @@ -692,15 +810,6 @@ static void VKAPI_CALL freeVk( palFree(s_Vk.allocator, ptr); } -static void alignedFree(void* ptr) -{ -#if defined(_MSC_VER) || defined(__MINGW32__) - _aligned_free(ptr); -#else - free(ptr); -#endif // _MSC_VER -} - static void* VKAPI_CALL reallocVk( void* pUserData, void* pOriginal, diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h index ee79716f..5ca3c01c 100644 --- a/src/graphics/vulkan/pal_vulkan.h +++ b/src/graphics/vulkan/pal_vulkan.h @@ -481,6 +481,7 @@ uint32_t findBestMemoryIndexVk( VkPhysicalDevice phyDevice, uint32_t memoryMask); +VkFormat vertexTypeToVk(PalVertexType type); void fillBuildInfoVk( uint32_t count, PalAccelerationStructureBuildInfo* info, diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 8d1f4f36..64917ded 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -5,10 +5,9 @@ PalBool graphicsTest() { // initialize the graphics system - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -16,8 +15,7 @@ PalBool graphicsTest() int32_t count = 0; result = palEnumerateAdapters(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get query adapters"); return PAL_FALSE; } @@ -38,8 +36,7 @@ PalBool graphicsTest() result = palEnumerateAdapters(&count, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get query adapters"); return PAL_FALSE; } @@ -51,16 +48,14 @@ PalBool graphicsTest() PalAdapter* adapter = adapters[i]; result = palGetAdapterInfo(adapter, &info); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter information: %s", error); + logResult(result, "Failed to get adapter information"); palFree(nullptr, adapters); return PAL_FALSE; } result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -99,8 +94,7 @@ PalBool graphicsTest() result = palCreateDevice(adapter, deviceFeatures, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -190,35 +184,7 @@ PalBool graphicsTest() palLog(nullptr, ""); palLog(nullptr, " Resource Capabilities:"); PalResourceCapabilities* resourceCaps = &caps.resourceCaps; - - if (resourceCaps->sampledImageDynamicArrayIndexing) { - palLog(nullptr, " Sampled image dynamic array indexing: True"); - - } else { - palLog(nullptr, " Sampled image dynamic array indexing: False"); - } - - if (resourceCaps->storageImageDynamicArrayIndexing) { - palLog(nullptr, " Storage image dynamic array indexing: True"); - - } else { - palLog(nullptr, " Storage image dynamic array indexing: False"); - } - - if (resourceCaps->storageBufferDynamicArrayIndexing) { - palLog(nullptr, " Storage buffer dynamic array indexing: True"); - - } else { - palLog(nullptr, " Storage buffer dynamic array indexing: False"); - } - - if (resourceCaps->uniformBufferDynamicArrayIndexing) { - palLog(nullptr, " Uniform buffer dynamic array indexing: True"); - - } else { - palLog(nullptr, " Uniform buffer dynamic array indexing: False"); - } - + // clang-format off palLog(nullptr, " Max per stage sampled images: %u", resourceCaps->maxPerStageSampledImages); palLog(nullptr, " Max per set sampled images: %u", resourceCaps->maxPerSetSampledImages); @@ -293,13 +259,11 @@ PalBool graphicsTest() PalSamplerAnisotropyCapabilities tmp; result = palQuerySamplerAnisotropyCapabilities(device, &tmp); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get sampler anisotropy capabilities: %s", error); + logResult(result, "Failed to get sampler anisotropy capabilities"); return PAL_FALSE; } palLog(nullptr, " Max anisotropy: %u", tmp.maxAnisotropy); - palLog(nullptr, ""); } @@ -309,13 +273,11 @@ PalBool graphicsTest() PalMultiViewportCapabilities tmp; result = palQueryMultiViewportCapabilities(device, &tmp); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get multi viewport capabilities: %s", error); + logResult(result, "Failed to get viewport capabilities"); return PAL_FALSE; } palLog(nullptr, " Max count: %u", tmp.maxCount); - palLog(nullptr, ""); } @@ -325,8 +287,7 @@ PalBool graphicsTest() PalRayTracingCapabilities tmp; result = palQueryRayTracingCapabilities(device, &tmp); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get ray tracing capabilities: %s", error); + logResult(result, "Failed to get ray tracing capabilities"); return PAL_FALSE; } @@ -337,7 +298,6 @@ PalBool graphicsTest() palLog(nullptr, " Max geometry count: %u", tmp.maxGeometryCount); palLog(nullptr, " Max payload size: %u Bytes", tmp.maxPayloadSize); palLog(nullptr, " Max dispatch invocations: %u", tmp.maxDispatchInvocations); - palLog(nullptr, ""); } @@ -347,8 +307,7 @@ PalBool graphicsTest() PalMeshShaderCapabilities tmp; result = palQueryMeshShaderCapabilities(device, &tmp); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get mesh shader capabilities: %s", error); + logResult(result, "Failed to get mesh shader capabilities"); return PAL_FALSE; } @@ -363,7 +322,6 @@ PalBool graphicsTest() palLog(nullptr, " Max task work group count[0]: %u", tmp.maxTaskWorkGroupCount[0]); palLog(nullptr, " Max task work group count[1]: %u", tmp.maxTaskWorkGroupCount[1]); palLog(nullptr, " Max task work group count[2]: %u", tmp.maxTaskWorkGroupCount[2]); - palLog(nullptr, ""); } @@ -373,8 +331,7 @@ PalBool graphicsTest() PalFragmentShadingRateCapabilities tmp; result = palQueryFragmentShadingRateCapabilities(device, &tmp); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get FSR capabilities: %s", error); + logResult(result, "Failed to get fragment shading rate capabilities"); return PAL_FALSE; } @@ -383,56 +340,58 @@ PalBool graphicsTest() palLog(nullptr, " Max texel width: %u", tmp.minTexelHeight); palLog(nullptr, " Max texel height: %u", tmp.maxTexelHeight); - palLog(nullptr, " Support Shading Rates:"); - if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_1X1]) { + palLog(nullptr, " Supported Shading Rates:"); + if (palIsSupported(tmp.supportedShadingRates, PAL_FRAGMENT_SHADING_RATE_1X1)) { palLog(nullptr, " 1 X 1"); } - if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_1X2]) { + if (palIsSupported(tmp.supportedShadingRates, PAL_FRAGMENT_SHADING_RATE_1X2)) { palLog(nullptr, " 1 X 2"); } - if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_2X1]) { + if (palIsSupported(tmp.supportedShadingRates, PAL_FRAGMENT_SHADING_RATE_2X1)) { palLog(nullptr, " 2 X 1"); } - if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_2X2]) { + if (palIsSupported(tmp.supportedShadingRates, PAL_FRAGMENT_SHADING_RATE_2X2)) { palLog(nullptr, " 2 X 2"); } - if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_2X4]) { + if (palIsSupported(tmp.supportedShadingRates, PAL_FRAGMENT_SHADING_RATE_2X4)) { palLog(nullptr, " 2 X 4"); } - if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_4X2]) { + if (palIsSupported(tmp.supportedShadingRates, PAL_FRAGMENT_SHADING_RATE_4X2)) { palLog(nullptr, " 4 X 2"); } - if (tmp.shadingRates[PAL_FRAGMENT_SHADING_RATE_4X4]) { + if (palIsSupported(tmp.supportedShadingRates, PAL_FRAGMENT_SHADING_RATE_4X4)) { palLog(nullptr, " 4 X 4"); } - palLog(nullptr, " Support Combiner operations:"); - if (tmp.combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP]) { + palLog(nullptr, " Supported Combiner operations:"); + // clang-format off + if (palIsSupported(tmp.supportedCombinerOps, PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP)) { palLog(nullptr, " Keep"); } - if (tmp.combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE]) { + if (palIsSupported(tmp.supportedCombinerOps, PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE)) { palLog(nullptr, " Replace"); } - if (tmp.combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN]) { + if (palIsSupported(tmp.supportedCombinerOps, PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN)) { palLog(nullptr, " Min"); } - if (tmp.combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX]) { + if (palIsSupported(tmp.supportedCombinerOps, PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX)) { palLog(nullptr, " Max"); } - if (tmp.combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL]) { + if (palIsSupported(tmp.supportedCombinerOps, PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL)) { palLog(nullptr, " Mul"); } + // clang-format on palLog(nullptr, ""); } @@ -443,65 +402,27 @@ PalBool graphicsTest() PalDescriptorIndexingCapabilities tmp; result = palQueryDescriptorIndexingCapabilities(device, &tmp); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get descriptor indexing capabilities: %s", error); + logResult(result, "Failed to get descriptor indexing capabilities"); return PAL_FALSE; } - if (tmp.sampledImageNonUniformIndexing) { - palLog(nullptr, " Sampled image non uniform indexing: True"); - + palLog(nullptr, " Supported flags:"); + if (tmp.flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND) { + palLog(nullptr, " Update after bind: True"); } else { - palLog(nullptr, " Sampled image non uniform indexing: False"); + palLog(nullptr, " Update after bind: False"); } - if (tmp.sampledImageUpdateAfterBind) { - palLog(nullptr, " Sampled image update after bind: True"); - + if (tmp.flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { + palLog(nullptr, " Partially bound: True"); } else { - palLog(nullptr, " Sampled image update after bind: False"); + palLog(nullptr, " Partially bound: False"); } - if (tmp.storageImageNonUniformIndexing) { - palLog(nullptr, " Storage image non uniform indexing: True"); - + if (tmp.flags & PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING) { + palLog(nullptr, " Non uniform indexing: True"); } else { - palLog(nullptr, " Storage image non uniform indexing: False"); - } - - if (tmp.storageImageUpdateAfterBind) { - palLog(nullptr, " Storage image update after bind: True"); - - } else { - palLog(nullptr, " Storage image update after bind: False"); - } - - if (tmp.storageBufferNonUniformIndexing) { - palLog(nullptr, " Storage buffer non uniform indexing: True"); - - } else { - palLog(nullptr, " Storage buffer non uniform indexing: False"); - } - - if (tmp.storageBufferUpdateAfterBind) { - palLog(nullptr, " Storage buffer update after bind: True"); - - } else { - palLog(nullptr, " Storage buffer update after bind: False"); - } - - if (tmp.uniformBufferNonUniformIndexing) { - palLog(nullptr, " Uniform buffer non uniform indexing: True"); - - } else { - palLog(nullptr, " Uniform buffer non uniform indexing: False"); - } - - if (tmp.uniformBufferUpdateAfterBind) { - palLog(nullptr, " Uniform buffer update after bind: True"); - - } else { - palLog(nullptr, " Uniform buffer update after bind: False"); + palLog(nullptr, " Non uniform indexing: False"); } // clang-format off @@ -530,8 +451,7 @@ PalBool graphicsTest() PalMultiViewCapabilities tmp; result = palQueryMultiViewCapabilities(device, &tmp); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get multi view capabilities: %s", error); + logResult(result, "Failed to get multi view capabilities"); return PAL_FALSE; } @@ -545,48 +465,53 @@ PalBool graphicsTest() PalDepthStencilCapabilities tmp; result = palQueryDepthStencilCapabilities(device, &tmp); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get depth stencil capabilities: %s", error); + logResult(result, "Failed to get depth stenci capabilities"); return PAL_FALSE; } - if (tmp.independentResolve) { - palLog(nullptr, " Independent resource: True"); + if (tmp.supportsIndependentResolve) { + palLog(nullptr, " Independent resolve: True"); + } else { + palLog(nullptr, " Independent resolve: False"); + } + + if (tmp.supportsIndependentResolveNone) { + palLog(nullptr, " Independent resolve none: True"); } else { - palLog(nullptr, " Independent resource: False"); + palLog(nullptr, " Independent resolve none: False"); } - palLog(nullptr, " Supported Depth Resolves:"); - if (tmp.depthResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO]) { + palLog(nullptr, " Supported depth resolves modes:"); + if (palIsSupported(tmp.supportedDepthResolveModes, PAL_RESOLVE_MODE_SAMPLE_ZERO)) { palLog(nullptr, " Zero"); } - if (tmp.depthResolves[PAL_RESOLVE_MODE_AVERAGE]) { + if (palIsSupported(tmp.supportedDepthResolveModes, PAL_RESOLVE_MODE_AVERAGE)) { palLog(nullptr, " Average"); } - if (tmp.depthResolves[PAL_RESOLVE_MODE_MIN]) { + if (palIsSupported(tmp.supportedDepthResolveModes, PAL_RESOLVE_MODE_MIN)) { palLog(nullptr, " Min"); } - if (tmp.depthResolves[PAL_RESOLVE_MODE_MAX]) { + if (palIsSupported(tmp.supportedDepthResolveModes, PAL_RESOLVE_MODE_MAX)) { palLog(nullptr, " Max"); } - palLog(nullptr, " Supported Stencil Resolves:"); - if (tmp.stencilResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO]) { + palLog(nullptr, " Supported stencil resolve modes:"); + if (palIsSupported(tmp.supportedStencilResolveModes, PAL_RESOLVE_MODE_SAMPLE_ZERO)) { palLog(nullptr, " Zero"); } - if (tmp.stencilResolves[PAL_RESOLVE_MODE_AVERAGE]) { + if (palIsSupported(tmp.supportedStencilResolveModes, PAL_RESOLVE_MODE_AVERAGE)) { palLog(nullptr, " Average"); } - if (tmp.stencilResolves[PAL_RESOLVE_MODE_MIN]) { + if (palIsSupported(tmp.supportedStencilResolveModes, PAL_RESOLVE_MODE_MIN)) { palLog(nullptr, " Min"); } - if (tmp.stencilResolves[PAL_RESOLVE_MODE_MAX]) { + if (palIsSupported(tmp.supportedStencilResolveModes, PAL_RESOLVE_MODE_MAX)) { palLog(nullptr, " Max"); } From 303e33a521d5461a1fe51381d6134735d35fb49a Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 4 Jul 2026 14:12:40 +0000 Subject: [PATCH 313/372] graphics rework: fix errors --- README.md | 2 +- include/pal/pal_graphics.h | 94 +--- src/graphics/pal_d3d12.c | 18 +- src/graphics/pal_graphics.c | 44 +- src/graphics/pal_graphics_backends.h | 30 +- src/graphics/vulkan/pal_adapter_vulkan.c | 8 +- src/graphics/vulkan/pal_buffer_vulkan.c | 4 +- src/graphics/vulkan/pal_descriptors_vulkan.c | 18 +- src/graphics/vulkan/pal_device_vulkan.c | 13 - src/graphics/vulkan/pal_image_vulkan.c | 14 - tests/graphics/clear_color_test.c | 168 +++--- tests/graphics/compute_test.c | 188 ++----- tests/graphics/descriptor_indexing_test.c | 515 ++++++------------- tests/graphics/geometry_test.c | 199 +++---- tests/graphics/graphics_test.c | 8 - tests/graphics/indirect_draw_test.c | 428 +++++---------- tests/graphics/mesh_test.c | 194 +++---- tests/graphics/multi_descriptor_set_test.c | 188 ++----- tests/graphics/ray_tracing_test.c | 484 ++++------------- tests/graphics/texture_test.c | 450 +++++----------- tests/graphics/triangle_test.c | 317 ++++-------- tests/tests.lua | 20 +- 22 files changed, 947 insertions(+), 2457 deletions(-) diff --git a/README.md b/README.md index b27c340e..0ff63484 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ int main() { palUpdateVideo(); PalEvent e; while (palPollEvent(driver, &e)) { - if (e.type == PAL_EVENT_WINDOW_CLOSE) return 0; + if (e.type == PAL_EVENT_TYPE_WINDOW_CLOSE) return 0; } } } diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index aa61e480..97af0927 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -64,9 +64,8 @@ #define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH (1ULL << 33) #define PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT (1ULL << 34) #define PAL_ADAPTER_FEATURE_DISPATCH_BASE (1ULL << 35) -#define PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS (1ULL << 36) -#define PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS (1ULL << 37) -#define PAL_ADAPTER_FEATURE_RAY_QUERY (1ULL << 38) +#define PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS (1ULL << 36) +#define PAL_ADAPTER_FEATURE_RAY_QUERY (1ULL << 37) #define PAL_ADAPTER_TYPE_UNKNOWN 0 #define PAL_ADAPTER_TYPE_DISCRETE 1 @@ -2534,7 +2533,7 @@ typedef struct { */ typedef struct { PalDescriptorSetLayoutBinding* bindings; /**< Bindings.*/ - PalDescriptorIndexingFlags descriptorIndexingFlags; /**< See `PalDescriptorIndexingFlags`.*/ + PalDescriptorIndexingFlags flags; /**< See `PalDescriptorIndexingFlags`.*/ uint32_t bindingCount; /**< Number of bindings.*/ } PalDescriptorSetLayoutCreateInfo; @@ -2550,7 +2549,7 @@ typedef struct { PalDescriptorPoolBindingSize* bindingSizes; /**< Binding sizes.*/ uint64_t bindingSizeCount; /**< Number of bindings sizes.*/ uint32_t maxDescriptorSets; /**< Maximum number of descriptor sets that can be allocated.*/ - PalDescriptorIndexingFlags descriptorIndexingFlags; /**< See `PalDescriptorIndexingFlags`.*/ + PalDescriptorIndexingFlags flags; /**< See `PalDescriptorIndexingFlags`.*/ } PalDescriptorPoolCreateInfo; /** @@ -2969,24 +2968,6 @@ typedef struct { PalMemory* memory, uint64_t offset); - /** - * Backend implementation of ::palMapImageMemory. - * - * Must obey the rules and semantics documented in palMapImageMemory(). - */ - PalResult(PAL_CALL* mapImageMemory)( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr); - - /** - * Backend implementation of ::palUnmapImageMemory. - * - * Must obey the rules and semantics documented in palUnmapImageMemory(). - */ - void(PAL_CALL* unmapImageMemory)(PalImage* image); - /** * Backend implementation of ::palCreateImageView. * @@ -3806,22 +3787,22 @@ typedef struct { uint64_t offset); /** - * Backend implementation of ::palMapBufferMemory. + * Backend implementation of ::palMapBuffer. * - * Must obey the rules and semantics documented in palMapBufferMemory(). + * Must obey the rules and semantics documented in palMapBuffer(). */ - PalResult(PAL_CALL* mapBufferMemory)( + PalResult(PAL_CALL* mapBuffer)( PalBuffer* buffer, uint64_t offset, uint64_t size, void** outPtr); /** - * Backend implementation of ::palUnmapBufferMemory. + * Backend implementation of ::palUnmapBuffer. * - * Must obey the rules and semantics documented in palUnmapBufferMemory(). + * Must obey the rules and semantics documented in palUnmapBuffer(). */ - void(PAL_CALL* unmapBufferMemory)(PalBuffer* buffer); + void(PAL_CALL* unmapBuffer)(PalBuffer* buffer); /** * Backend implementation of ::palGetBufferDeviceAddress. @@ -4683,53 +4664,6 @@ PAL_API PalResult PAL_CALL palBindImageMemory( PalMemory* memory, uint64_t offset); -/** - * @brief Maps image to CPU visible address space. - * - * The graphics system must be initialized before this call. The image must have a valid - * memory bound to it before this call. - * - * Only `PAL_MEMORY_TYPE_CPU_UPLOAD` and `PAL_MEMORY_TYPE_CPU_READBACK` can be mapped to - * CPU visible space. Mapping `PAL_MEMORY_TYPE_GPU_ONLY` will fail and return - * `PAL_RESULT_MEMORY_MAP_FAILED`. - * - * @param[in] image Pointer to image to map. Memory must be bound. - * @param[in] offset Starting point within the image. - * @param[in] size Number of bytes to map from the offset. `offset + size` must not be - * greater than image size. - * @param[out] outPtr Pointer to a void* to recieved the mapped memory. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if `image` is externally synchronized. - * Mapping with different offsets into the same image is thread safe as long as `image` - * is externally synchronized. - * - * @since 2.0 - * @sa palUnmapImageMemory - */ -PAL_API PalResult PAL_CALL palMapImageMemory( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr); - -/** - * @brief Unmap image from CPU visible address space. - * - * The graphics system must be initialized before this call. The image must be mapped - * before this call. After this call, the CPU pointer must not be used anymore. - * - * @param[in] image Pointer to image to unmap. - * - * Thread safety: Thread safe if `image` is externally synchronized. - * - * @since 2.0 - * @sa palMapImageMemory - */ -PAL_API void PAL_CALL palUnmapImageMemory(PalImage* image); - /** * @brief Create an image view. * @@ -6835,9 +6769,9 @@ PAL_API PalResult PAL_CALL palBindBufferMemory( * is externally synchronized. * * @since 2.0 - * @sa palUnmapBufferMemory + * @sa palUnmapBuffer */ -PAL_API PalResult PAL_CALL palMapBufferMemory( +PAL_API PalResult PAL_CALL palMapBuffer( PalBuffer* buffer, uint64_t offset, uint64_t size, @@ -6854,9 +6788,9 @@ PAL_API PalResult PAL_CALL palMapBufferMemory( * Thread safety: Thread safe if `buffer` is externally synchronized. * * @since 2.0 - * @sa palMapBufferMemory + * @sa palMapBuffer */ -PAL_API void PAL_CALL palUnmapBufferMemory(PalBuffer* buffer); +PAL_API void PAL_CALL palUnmapBuffer(PalBuffer* buffer); /** * @brief Get the device address of the provided buffer. diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index cc5c9f02..96ceb274 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -3676,20 +3676,6 @@ PalResult PAL_CALL bindImageMemoryD3D12( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL mapImageMemoryD3D12( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr) -{ - return PAL_RESULT_INVALID_OPERATION; -} - -void PAL_CALL unmapImageMemoryD3D12(PalImage* image) -{ - // do nothing. -} - // ================================================== // Image View // ================================================== @@ -6660,7 +6646,7 @@ PalResult PAL_CALL bindBufferMemoryD3D12( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL mapBufferMemoryD3D12( +PalResult PAL_CALL mapBufferD3D12( PalBuffer* buffer, uint64_t offset, uint64_t size, @@ -6678,7 +6664,7 @@ PalResult PAL_CALL mapBufferMemoryD3D12( return PAL_RESULT_SUCCESS; } -void PAL_CALL unmapBufferMemoryD3D12(PalBuffer* buffer) +void PAL_CALL unmapBufferD3D12(PalBuffer* buffer) { Buffer* d3dBuffer = (Buffer*)buffer; d3dBuffer->handle->lpVtbl->Unmap(d3dBuffer->handle, 0, nullptr); diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 9be7f28b..a9256738 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -110,8 +110,6 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) !vtable1->getImageInfo || !vtable1->getImageMemoryRequirements || !vtable1->bindImageMemory || - !vtable1->mapImageMemory || - !vtable1->unmapImageMemory || // image view !vtable1->createImageView || @@ -219,8 +217,8 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) !vtable1->writeToImageCopyStagingBuffer || !vtable1->bindBufferMemory || !vtable1->getBufferDeviceAddress || - !vtable1->mapBufferMemory || - !vtable1->unmapBufferMemory || + !vtable1->mapBuffer || + !vtable1->unmapBuffer || // descriptors !vtable1->createDescriptorSetLayout || @@ -298,8 +296,6 @@ static void populateVtableVersion1( vtable->getImageInfo = vtable1->getImageInfo; vtable->getImageMemoryRequirements = vtable1->getImageMemoryRequirements; vtable->bindImageMemory = vtable1->bindImageMemory; - vtable->mapImageMemory = vtable1->mapImageMemory; - vtable->unmapImageMemory = vtable1->unmapImageMemory; // image view vtable->createImageView = vtable1->createImageView; @@ -408,8 +404,8 @@ static void populateVtableVersion1( vtable->writeToImageCopyStagingBuffer = vtable1->writeToImageCopyStagingBuffer; vtable->bindBufferMemory = vtable1->bindBufferMemory; vtable->getBufferDeviceAddress = vtable1->getBufferDeviceAddress; - vtable->mapBufferMemory = vtable1->mapBufferMemory; - vtable->unmapBufferMemory = vtable1->unmapBufferMemory; + vtable->mapBuffer = vtable1->mapBuffer; + vtable->unmapBuffer = vtable1->unmapBuffer; // descriptors vtable->createDescriptorSetLayout = vtable1->createDescriptorSetLayout; @@ -1042,30 +1038,6 @@ PalResult PAL_CALL palBindImageMemory( return image->backend->bindImageMemory(image, memory, offset); } -PalResult PAL_CALL palMapImageMemory( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr) -{ - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!image) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return image->backend->mapImageMemory(image, offset, size, outPtr); -} - -void PAL_CALL palUnmapImageMemory(PalImage* image) -{ - if (s_Graphics.initialized && image) { - image->backend->unmapImageMemory(image); - } -} - // ================================================== // Image View // ================================================== @@ -2513,7 +2485,7 @@ PalResult PAL_CALL palBindBufferMemory( return buffer->backend->bindBufferMemory(buffer, memory, offset); } -PalResult PAL_CALL palMapBufferMemory( +PalResult PAL_CALL palMapBuffer( PalBuffer* buffer, uint64_t offset, uint64_t size, @@ -2527,13 +2499,13 @@ PalResult PAL_CALL palMapBufferMemory( return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return buffer->backend->mapBufferMemory(buffer, offset, size, outPtr); + return buffer->backend->mapBuffer(buffer, offset, size, outPtr); } -void PAL_CALL palUnmapBufferMemory(PalBuffer* buffer) +void PAL_CALL palUnmapBuffer(PalBuffer* buffer) { if (s_Graphics.initialized && buffer) { - buffer->backend->unmapBufferMemory(buffer); + buffer->backend->unmapBuffer(buffer); } } diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index e26093ce..95565aaa 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -43,8 +43,6 @@ typedef struct { PalResult (PAL_CALL *getImageInfo)(PalImage*, PalImageInfo*); PalResult (PAL_CALL *getImageMemoryRequirements)(PalImage*, PalMemoryRequirements*); PalResult (PAL_CALL *bindImageMemory)(PalImage*, PalMemory*, uint64_t); - PalResult (PAL_CALL *mapImageMemory)(PalImage*, uint64_t, uint64_t, void**); - void (PAL_CALL *unmapImageMemory)(PalImage*); PalResult (PAL_CALL *createImageView)(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); void (PAL_CALL *destroyImageView)(PalImageView*); @@ -133,8 +131,8 @@ typedef struct { PalResult (PAL_CALL *writeToInstanceBuffer)(PalDevice*, void*, PalAccelerationStructureInstance*, uint32_t); PalResult (PAL_CALL *writeToImageCopyStagingBuffer)(PalDevice*, void*, void*, PalFormat, PalBufferImageCopyInfo*); PalResult (PAL_CALL *bindBufferMemory)(PalBuffer*, PalMemory*, uint64_t); - PalResult (PAL_CALL *mapBufferMemory)(PalBuffer*, uint64_t, uint64_t, void**); - void (PAL_CALL *unmapBufferMemory)(PalBuffer*); + PalResult (PAL_CALL *mapBuffer)(PalBuffer*, uint64_t, uint64_t, void**); + void (PAL_CALL *unmapBuffer)(PalBuffer*); PalDeviceAddress (PAL_CALL *getBufferDeviceAddress)(PalBuffer*); PalResult (PAL_CALL *createDescriptorSetLayout)(PalDevice*, const PalDescriptorSetLayoutCreateInfo*, PalDescriptorSetLayout**); @@ -195,8 +193,6 @@ void PAL_CALL destroyImageVk(PalImage*); PalResult PAL_CALL getImageInfoVk(PalImage*, PalImageInfo*); PalResult PAL_CALL getImageMemoryRequirementsVk(PalImage*, PalMemoryRequirements*); PalResult PAL_CALL bindImageMemoryVk(PalImage*, PalMemory*, uint64_t); -PalResult PAL_CALL mapImageMemoryVk(PalImage*, uint64_t, uint64_t, void**); -void PAL_CALL unmapImageMemoryVk(PalImage*); PalResult PAL_CALL createImageViewVk(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); void PAL_CALL destroyImageViewVk(PalImageView*); @@ -285,8 +281,8 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk(PalDevice*, PalFo PalResult PAL_CALL writeToInstanceBufferVk(PalDevice*, void*, PalAccelerationStructureInstance*, uint32_t); PalResult PAL_CALL writeToImageCopyStagingBufferVk(PalDevice*, void*, void*, PalFormat, PalBufferImageCopyInfo*); PalResult PAL_CALL bindBufferMemoryVk(PalBuffer*, PalMemory*, uint64_t); -PalResult PAL_CALL mapBufferMemoryVk(PalBuffer*, uint64_t, uint64_t, void**); -void PAL_CALL unmapBufferMemoryVk(PalBuffer*); +PalResult PAL_CALL mapBufferVk(PalBuffer*, uint64_t, uint64_t, void**); +void PAL_CALL unmapBufferVk(PalBuffer*); PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer*); PalResult PAL_CALL createDescriptorSetLayoutVk(PalDevice*, const PalDescriptorSetLayoutCreateInfo*, PalDescriptorSetLayout**); void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout*); @@ -337,8 +333,6 @@ static PalGraphicsVtable s_VkBackend = { .getImageInfo = getImageInfoVk, .getImageMemoryRequirements = getImageMemoryRequirementsVk, .bindImageMemory = bindImageMemoryVk, - .mapImageMemory = mapImageMemoryVk, - .unmapImageMemory = unmapImageMemoryVk, .createImageView = createImageViewVk, .destroyImageView = destroyImageViewVk, .createSampler = createSamplerVk, @@ -424,8 +418,8 @@ static PalGraphicsVtable s_VkBackend = { .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferVk, .bindBufferMemory = bindBufferMemoryVk, .getBufferDeviceAddress = getBufferDeviceAddressVk, - .mapBufferMemory = mapBufferMemoryVk, - .unmapBufferMemory = unmapBufferMemoryVk, + .mapBuffer = mapBufferVk, + .unmapBuffer = unmapBufferVk, .createDescriptorSetLayout = createDescriptorSetLayoutVk, .destroyDescriptorSetLayout = destroyDescriptorSetLayoutVk, .createDescriptorPool = createDescriptorPoolVk, @@ -484,8 +478,6 @@ void PAL_CALL destroyImageD3D12(PalImage*); PalResult PAL_CALL getImageInfoD3D12(PalImage*, PalImageInfo*); PalResult PAL_CALL getImageMemoryRequirementsD3D12(PalImage*, PalMemoryRequirements*); PalResult PAL_CALL bindImageMemoryD3D12(PalImage*, PalMemory*, uint64_t); -PalResult PAL_CALL mapImageMemoryD3D12(PalImage*, uint64_t, uint64_t, void**); -void PAL_CALL unmapImageMemoryD3D12(PalImage*); PalResult PAL_CALL createImageViewD3D12(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); void PAL_CALL destroyImageViewD3D12(PalImageView*); @@ -574,8 +566,8 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12(PalDevice*, Pa PalResult PAL_CALL writeToInstanceBufferD3D12(PalDevice*, void*, PalAccelerationStructureInstance*, uint32_t); PalResult PAL_CALL writeToImageCopyStagingBufferD3D12(PalDevice*, void*, void*, PalFormat, PalBufferImageCopyInfo*); PalResult PAL_CALL bindBufferMemoryD3D12(PalBuffer*, PalMemory*, uint64_t); -PalResult PAL_CALL mapBufferMemoryD3D12(PalBuffer*, uint64_t, uint64_t, void**); -void PAL_CALL unmapBufferMemoryD3D12(PalBuffer*); +PalResult PAL_CALL mapBufferD3D12(PalBuffer*, uint64_t, uint64_t, void**); +void PAL_CALL unmapBufferD3D12(PalBuffer*); PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer*); PalResult PAL_CALL createDescriptorSetLayoutD3D12(PalDevice*, const PalDescriptorSetLayoutCreateInfo*, PalDescriptorSetLayout**); void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout*); @@ -626,8 +618,6 @@ static PalGraphicsVtable s_D3D12Backend = { .getImageInfo = getImageInfoD3D12, .getImageMemoryRequirements = getImageMemoryRequirementsD3D12, .bindImageMemory = bindImageMemoryD3D12, - .mapImageMemory = mapImageMemoryD3D12, - .unmapImageMemory = unmapImageMemoryD3D12, .createImageView = createImageViewD3D12, .destroyImageView = destroyImageViewD3D12, .createSampler = createSamplerD3D12, @@ -713,8 +703,8 @@ static PalGraphicsVtable s_D3D12Backend = { .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferD3D12, .bindBufferMemory = bindBufferMemoryD3D12, .getBufferDeviceAddress = getBufferDeviceAddressD3D12, - .mapBufferMemory = mapBufferMemoryD3D12, - .unmapBufferMemory = unmapBufferMemoryD3D12, + .mapBuffer = mapBufferD3D12, + .unmapBuffer = unmapBufferD3D12, .createDescriptorSetLayout = createDescriptorSetLayoutD3D12, .destroyDescriptorSetLayout = destroyDescriptorSetLayoutD3D12, .createDescriptorPool = createDescriptorPoolD3D12, diff --git a/src/graphics/vulkan/pal_adapter_vulkan.c b/src/graphics/vulkan/pal_adapter_vulkan.c index 62d0d4a9..f0470d1a 100644 --- a/src/graphics/vulkan/pal_adapter_vulkan.c +++ b/src/graphics/vulkan/pal_adapter_vulkan.c @@ -501,15 +501,9 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) features.pNext = &desc; s_Vk.getPhysicalDeviceFeatures2(phyDevice, &features); - // core features we need - if (desc.runtimeDescriptorArray || - desc.descriptorBindingUpdateUnusedWhilePending) { + if (desc.runtimeDescriptorArray) { adapterFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } - - if (desc.descriptorBindingPartiallyBound) { - adapterFeatures |= PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; - } } if (props.apiVersion >= VK_API_VERSION_1_2 || hasTimelineSemaphore) { diff --git a/src/graphics/vulkan/pal_buffer_vulkan.c b/src/graphics/vulkan/pal_buffer_vulkan.c index 40325357..1724a4a5 100644 --- a/src/graphics/vulkan/pal_buffer_vulkan.c +++ b/src/graphics/vulkan/pal_buffer_vulkan.c @@ -430,7 +430,7 @@ PalResult PAL_CALL bindBufferMemoryVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL mapBufferMemoryVk( +PalResult PAL_CALL mapBufferVk( PalBuffer* buffer, uint64_t offset, uint64_t size, @@ -451,7 +451,7 @@ PalResult PAL_CALL mapBufferMemoryVk( return PAL_RESULT_SUCCESS; } -void PAL_CALL unmapBufferMemoryVk(PalBuffer* buffer) +void PAL_CALL unmapBufferVk(PalBuffer* buffer) { BufferVk* vkBuffer = (BufferVk*)buffer; s_Vk.unmapMemory(vkBuffer->device->handle, vkBuffer->memory->handle); diff --git a/src/graphics/vulkan/pal_descriptors_vulkan.c b/src/graphics/vulkan/pal_descriptors_vulkan.c index 6ecf38d0..35f06376 100644 --- a/src/graphics/vulkan/pal_descriptors_vulkan.c +++ b/src/graphics/vulkan/pal_descriptors_vulkan.c @@ -48,7 +48,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( flagsCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - if (info->descriptorIndexingFlags != 0 && hasDescriptorIndexing) { + if (info->flags != 0 && hasDescriptorIndexing) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } @@ -58,7 +58,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - if (info->descriptorIndexingFlags != 0) { + if (info->flags != 0) { bindingFlags = palAllocate(s_Vk.allocator, sizeof(VkDescriptorBindingFlags) * count, 0); if (!bindingFlags) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -81,17 +81,17 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( binding->stageFlags = vkDevice->shaderStages; // set descriptor indexing flags - if (info->descriptorIndexingFlags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND) { + if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND) { bindingFlags[i] |= VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; bindingFlags[i] |= VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT; } - if (info->descriptorIndexingFlags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { + if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { bindingFlags[i] = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT; } } - if (info->descriptorIndexingFlags != 0) { + if (info->flags != 0) { flagsCreateInfo.bindingCount = count; flagsCreateInfo.pBindingFlags = bindingFlags; createInfo.pNext = &flagsCreateInfo; @@ -113,7 +113,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( palFree(s_Vk.allocator, bindings); layout->device = vkDevice; - layout->flags = info->descriptorIndexingFlags; + layout->flags = info->flags; layout->reserved = PAL_BACKEND_KEY; *outLayout = (PalDescriptorSetLayout*)layout; return PAL_RESULT_SUCCESS; @@ -144,11 +144,11 @@ PalResult PAL_CALL createDescriptorPoolVk( createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - if (info->descriptorIndexingFlags != 0 && hasDescriptorIndexing) { + if (info->flags != 0 && hasDescriptorIndexing) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } - if (info->descriptorIndexingFlags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { + if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; } @@ -182,7 +182,7 @@ PalResult PAL_CALL createDescriptorPoolVk( palFree(s_Vk.allocator, poolSizes); pool->device = vkDevice; - pool->flags = info->descriptorIndexingFlags; + pool->flags = info->flags; pool->reserved = PAL_BACKEND_KEY; *outPool = (PalDescriptorPool*)pool; return PAL_RESULT_SUCCESS; diff --git a/src/graphics/vulkan/pal_device_vulkan.c b/src/graphics/vulkan/pal_device_vulkan.c index 295db927..534cd6b7 100644 --- a/src/graphics/vulkan/pal_device_vulkan.c +++ b/src/graphics/vulkan/pal_device_vulkan.c @@ -641,19 +641,6 @@ PalResult PAL_CALL createDeviceVk( next = &descIndex; } - if (features & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS) { - if (!(features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { - if (props.apiVersion < VK_API_VERSION_1_2) { - extensions[extCount++] = "VK_EXT_descriptor_indexing"; - } - - descIndex.pNext = next; - next = &descIndex; - } - - descIndex.descriptorBindingPartiallyBound = PAL_TRUE; - } - if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { if (props.apiVersion < VK_API_VERSION_1_2) { extensions[extCount++] = "VK_KHR_multiview"; diff --git a/src/graphics/vulkan/pal_image_vulkan.c b/src/graphics/vulkan/pal_image_vulkan.c index 16985f8d..5d44fd46 100644 --- a/src/graphics/vulkan/pal_image_vulkan.c +++ b/src/graphics/vulkan/pal_image_vulkan.c @@ -310,20 +310,6 @@ PalResult PAL_CALL bindImageMemoryVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL mapImageMemoryVk( - PalImage* image, - uint64_t offset, - uint64_t size, - void** outPtr) -{ - return PAL_RESULT_CODE_INVALID_OPERATION; -} - -void PAL_CALL unmapImageMemoryVk(PalImage* image) -{ - // do nothing. -} - PalResult PAL_CALL createImageViewVk( PalDevice* device, PalImage* image, diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index adc23240..3373abbc 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -22,7 +22,6 @@ PalBool clearColorTest() PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; - PalGraphicsWindow gfxWindow; PalAdapter* adapter = nullptr; PalDevice* device = nullptr; @@ -45,8 +44,8 @@ PalBool clearColorTest() return PAL_FALSE; } - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { @@ -71,40 +70,43 @@ PalBool clearColorTest() return PAL_FALSE; } - PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); - gfxWindow.display = winHandle.nativeDisplay; - gfxWindow.window = winHandle.nativeWindow; + // get window handle. You can use any window from any library + // so long as you can get the window handle and display (if on X11, wayland) + // If pal video system will not be used, there is no need to initialize it + PalWindowHandleInfo winHandle = {0}; + result = palGetWindowHandleInfo(window, &winHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } - // using pal_system.h will be easy to know the underlying windowing API - // or use typedefs. We will use the pal_system module. This is needed - // for systems which multiple windowing APIs (linux). + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; result = palGetPlatformInfo(&platformInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get platform information: %s", error); + logResult(result, "Failed to get platform information"); return PAL_FALSE; } - if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; + if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WAYLAND; - } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_X11) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_X11; - } else { - // automatically this is xcb - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WIN32) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WIN32; } PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -112,8 +114,7 @@ PalBool clearColorTest() int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -132,8 +133,7 @@ PalBool clearColorTest() result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -143,8 +143,7 @@ PalBool clearColorTest() adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -173,16 +172,20 @@ PalBool clearColorTest() result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); return PAL_FALSE; } // create surface - result = palCreateSurface(device, &gfxWindow, &surface); + result = palCreateSurface( + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, + &surface); + if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create surface: %s", error); + logResult(result, "Failed to create surface"); return PAL_FALSE; } @@ -191,8 +194,7 @@ PalBool clearColorTest() for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); + logResult(result, "Failed to create queue"); return PAL_FALSE; } @@ -215,8 +217,7 @@ PalBool clearColorTest() PalSurfaceCapabilities surfaceCaps = {0}; result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get surface capabilities: %s", error); + logResult(result, "Failed to get surface capabilities"); return PAL_FALSE; } @@ -251,8 +252,7 @@ PalBool clearColorTest() result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create swapchain: %s", error); + logResult(result, "Failed to create swapchain"); return PAL_FALSE; } @@ -269,8 +269,7 @@ PalBool clearColorTest() PalImageInfo imageInfo; result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); + logResult(result, "Failed to get image info"); return PAL_FALSE; } @@ -292,16 +291,14 @@ PalBool clearColorTest() result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); + logResult(result, "Failed to create image view"); return PAL_FALSE; } // create render finished semaphores result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } @@ -310,8 +307,7 @@ PalBool clearColorTest() result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); + logResult(result, "Failed to create command pool"); return PAL_FALSE; } @@ -319,15 +315,13 @@ PalBool clearColorTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } @@ -338,8 +332,7 @@ PalBool clearColorTest() &cmdBuffers[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); + logResult(result, "Failed to allocate command buffer"); return PAL_FALSE; } } @@ -354,12 +347,12 @@ PalBool clearColorTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -372,8 +365,7 @@ PalBool clearColorTest() result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -386,16 +378,14 @@ PalBool clearColorTest() uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); + logResult(result, "Failed to get next swapchain image"); return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -404,8 +394,7 @@ PalBool clearColorTest() if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -415,8 +404,7 @@ PalBool clearColorTest() result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -424,22 +412,19 @@ PalBool clearColorTest() // reset the command buffer result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to reset command buffer: %s", error); + logResult(result, "Failed to reset command buffer"); return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } // change the state of the image view to make it renderable - PalUsageStateInfo oldUsageStateInfo = {0}; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; + PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -452,12 +437,11 @@ PalBool clearColorTest() cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -480,38 +464,34 @@ PalBool clearColorTest() result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin rendering: %s", error); + logResult(result, "Failed to begin rendering"); return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end rendering: %s", error); + logResult(result, "Failed to end rendering"); return PAL_FALSE; } // change the state of the image view to make it presentable - oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + oldUsageState = newUsageState; + newUsageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -524,19 +504,14 @@ PalBool clearColorTest() result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // present - PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; - result = palPresentSwapchain(swapchain, &presentInfo); + result = palPresentSwapchain(swapchain, imageIndex, renderFinishedSemaphores[imageIndex]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to present swapchain: %s", error); + logResult(result, "Failed to present swapchain"); return PAL_FALSE; } @@ -545,8 +520,7 @@ PalBool clearColorTest() result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for queue: %s", error); + logResult(result, "Failed to wait queue"); return PAL_FALSE; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 19eea564..67cdc666 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -31,8 +31,6 @@ PalBool computeTest() PalShader* shader = nullptr; PalBuffer* buffer = nullptr; PalBuffer* stagingBuffer = nullptr; - PalMemory* bufferMemory = nullptr; - PalMemory* stagingBufferMemory = nullptr; PalDescriptorSetLayout* descriptorSetLayout = nullptr; PalDescriptorPool* descriptorPool = nullptr; @@ -45,10 +43,9 @@ PalBool computeTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -56,8 +53,7 @@ PalBool computeTest() int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -76,8 +72,7 @@ PalBool computeTest() result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -88,8 +83,7 @@ PalBool computeTest() adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -102,8 +96,7 @@ PalBool computeTest() // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + logResult(result, "Failed to get adapter info"); return PAL_FALSE; } @@ -136,23 +129,20 @@ PalBool computeTest() // create a device result = palCreateDevice(adapter, 0, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); return PAL_FALSE; } // create a compute command queue result = palCreateQueue(device, PAL_QUEUE_TYPE_COMPUTE, &queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); + logResult(result, "Failed to create queue"); return PAL_FALSE; } result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); + logResult(result, "Failed to create command pool"); return PAL_FALSE; } @@ -163,8 +153,7 @@ PalBool computeTest() &cmdBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); + logResult(result, "Failed to allocate command buffer"); return PAL_FALSE; } @@ -206,8 +195,7 @@ PalBool computeTest() result = palCreateShader(device, &shaderCreateInfo, &shader); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create compute shader: %s", error); + logResult(result, "Failed to create shader"); return PAL_FALSE; } @@ -218,80 +206,19 @@ PalBool computeTest() PalBufferCreateInfo bufferCreateInfo = {0}; bufferCreateInfo.size = bufferBytes; bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE | PAL_BUFFER_USAGE_TRANSFER_SRC; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; result = palCreateBuffer(device, &bufferCreateInfo, &buffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create buffer: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_DST; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK; result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create staging buffer: %s", error); - return PAL_FALSE; - } - - // get buffer memory requirement and allocate memory - PalMemoryRequirements bufferMemReq = {0}; - PalMemoryRequirements stagingBufferMemReq = {0}; - result = palGetBufferMemoryRequirements(buffer, &bufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - // we need to check if the memory type we want are supported - // but almost every GPU supports a GPU only memory - // and CPU writable memory - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - bufferMemReq.memoryMask, - bufferMemReq.size, - &bufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_READBACK, - stagingBufferMemReq.memoryMask, - stagingBufferMemReq.size, - &stagingBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - // bind memory - result = palBindBufferMemory(buffer, bufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } @@ -304,18 +231,13 @@ PalBool computeTest() descriptorSetLayoutcreateInfo.bindingCount = 1; descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; - PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_COMPUTE }; - descriptorSetLayoutcreateInfo.shaderStageCount = 1; - descriptorSetLayoutcreateInfo.shaderStages = shaderStages; - result = palCreateDescriptorSetLayout( device, &descriptorSetLayoutcreateInfo, &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor set layout: %s", error); + logResult(result, "Failed to create descriptor set layout"); return PAL_FALSE; } @@ -326,13 +248,12 @@ PalBool computeTest() PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set - descriptorPoolCreateInfo.maxDescriptorBindingSizes = 1; // one binding type + descriptorPoolCreateInfo.bindingSizeCount = 1; // one binding type descriptorPoolCreateInfo.bindingSizes = &storageBufferBindingsize; result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor pool: %s", error); + logResult(result, "Failed to create descriptor pool"); return PAL_FALSE; } @@ -340,8 +261,7 @@ PalBool computeTest() // using the layout we created above result = palAllocateDescriptorSet(device, descriptorPool, descriptorSetLayout, &descriptorSet); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate descriptor set: %s", error); + logResult(result, "Failed to allocate descriptor set"); return PAL_FALSE; } @@ -360,8 +280,7 @@ PalBool computeTest() result = palUpdateDescriptorSet(device, 1, &writeInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to update descriptor set: %s", error); + logResult(result, "Failed to update descriptor set"); return PAL_FALSE; } @@ -370,8 +289,6 @@ PalBool computeTest() PalPushConstantRange pushConstantRange = {0}; pushConstantRange.offset = 0; pushConstantRange.size = sizeof(PushConstant); // must match shader - pushConstantRange.shaderStageCount = 1; - pushConstantRange.shaderStages = shaderStages; // create pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; @@ -382,8 +299,7 @@ PalBool computeTest() result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); + logResult(result, "Failed to create pipeline layout"); return PAL_FALSE; } @@ -394,8 +310,7 @@ PalBool computeTest() result = palCreateComputePipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create compute pipeline: %s", error); + logResult(result, "Failed to create pipeline"); return PAL_FALSE; } @@ -404,16 +319,14 @@ PalBool computeTest() // create fence result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } // record commands result = palCmdBegin(cmdBuffer, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } @@ -427,29 +340,24 @@ PalBool computeTest() result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); + logResult(result, "Failed to bind pipeline"); return PAL_FALSE; } result = palCmdPushConstants( cmdBuffer, - 1, - shaderStages, 0, sizeof(PushConstant), &pushConstant); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to push constants: %s", error); + logResult(result, "Failed to push constants"); return PAL_FALSE; } result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind descriptor set: %s", error); + logResult(result, "Failed to bind descriptor set"); return PAL_FALSE; } @@ -497,46 +405,33 @@ PalBool computeTest() result = palCmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to dispatch: %s", error); + logResult(result, "Failed to issue dispatch command"); return PAL_FALSE; } } palFree(nullptr, workGroupInfos); // set a barrier so we only read from the buffer after the shader has written to it - PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; - oldUsageStateInfo.shaderStageCount = 1; - oldUsageStateInfo.shaderStages = shaderStages; - - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStageCount = 0; - newUsageStateInfo.shaderStages = nullptr; - newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; - - result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + PalUsageState oldUsageState = PAL_USAGE_STATE_SHADER_WRITE; + PalUsageState newUsageState = PAL_USAGE_STATE_TRANSFER_READ; + result = palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } // now we copy from the GPU buffer into the staging buffer PalBufferCopyInfo copyInfo = {0}; copyInfo.size = bufferBytes; - result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -546,26 +441,23 @@ PalBool computeTest() submitInfo.fence = fence; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // wait for the fence result = palWaitFence(fence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } // now our staging buffer has the contents of the GPU buffer // we map it and copy the contents to a ppm buffer and save it void* ptr = nullptr; - result = palMapBufferMemory(stagingBuffer, 0, bufferBytes, &ptr); + result = palMapBuffer(stagingBuffer, 0, bufferBytes, &ptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } @@ -587,7 +479,7 @@ PalBool computeTest() } fclose(file); - palUnmapBufferMemory(stagingBuffer); + palUnmapBuffer(stagingBuffer); palDestroyPipeline(pipeline); palDestroyPipelineLayout(pipelineLayout); @@ -599,8 +491,6 @@ PalBool computeTest() palDestroyBuffer(buffer); palDestroyBuffer(stagingBuffer); - palFreeMemory(device, bufferMemory); - palFreeMemory(device, stagingBufferMemory); palDestroyFence(fence); palDestroyQueue(queue); diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 55dd9722..d25bc483 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -54,7 +54,6 @@ PalBool descriptorIndexingTest() PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; - PalGraphicsWindow gfxWindow; PalAdapter* adapter = nullptr; PalDevice* device = nullptr; @@ -76,13 +75,10 @@ PalBool descriptorIndexingTest() PalBuffer* vertexBuffer = nullptr; PalBuffer* stagingBuffer = nullptr; - PalMemory* vertexBufferMemory = nullptr; - PalMemory* stagingBufferMemory = nullptr; - PalSampler* sampler = nullptr; PalImage* textures[4]; - PalMemory* textureMemories[4]; PalImageView* textureViews[4]; + PalBuffer* imageStagingBuffers[4]; PalDescriptorSetLayout* descriptorSetLayout = nullptr; PalDescriptorPool* descriptorPool = nullptr; @@ -95,8 +91,8 @@ PalBool descriptorIndexingTest() return PAL_FALSE; } - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { @@ -121,40 +117,43 @@ PalBool descriptorIndexingTest() return PAL_FALSE; } - PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); - gfxWindow.display = winHandle.nativeDisplay; - gfxWindow.window = winHandle.nativeWindow; + // get window handle. You can use any window from any library + // so long as you can get the window handle and display (if on X11, wayland) + // If pal video system will not be used, there is no need to initialize it + PalWindowHandleInfo winHandle = {0}; + result = palGetWindowHandleInfo(window, &winHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } - // using pal_system.h will be easy to know the underlying windowing API - // or use typedefs. We will use the pal_system module. This is needed - // for systems which multiple windowing APIs (linux). + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; result = palGetPlatformInfo(&platformInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get platform information: %s", error); + logResult(result, "Failed to get platform information"); return PAL_FALSE; } - if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; + if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WAYLAND; - } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_X11) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_X11; - } else { - // automatically this is xcb - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WIN32) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WIN32; } PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -162,8 +161,7 @@ PalBool descriptorIndexingTest() int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -182,8 +180,7 @@ PalBool descriptorIndexingTest() result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -194,8 +191,7 @@ PalBool descriptorIndexingTest() adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -214,8 +210,7 @@ PalBool descriptorIndexingTest() // We want an adapter that supports spirv 1.4 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + logResult(result, "Failed to get adapter info"); return PAL_FALSE; } @@ -252,27 +247,34 @@ PalBool descriptorIndexingTest() features |= PAL_ADAPTER_FEATURE_FENCE_RESET; } - // check if null descriptors or partially bound is supported - if (adapterFeatures & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS) { - features |= PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; - } - if (adapterFeatures & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS) { features |= PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS; } result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); + return PAL_FALSE; + } + + // get descriptor indexing capabilities + PalDescriptorIndexingCapabilities descriptorIndexingCaps = {0}; + result = palQueryDescriptorIndexingCapabilities(device, &descriptorIndexingCaps); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get descriptor indexing capabilities"); return PAL_FALSE; } // create surface - result = palCreateSurface(device, &gfxWindow, &surface); + result = palCreateSurface( + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, + &surface); + if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create surface: %s", error); + logResult(result, "Failed to create surface"); return PAL_FALSE; } @@ -281,8 +283,7 @@ PalBool descriptorIndexingTest() for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); + logResult(result, "Failed to create queue"); return PAL_FALSE; } @@ -305,8 +306,7 @@ PalBool descriptorIndexingTest() PalSurfaceCapabilities surfaceCaps = {0}; result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get surface capabilities: %s", error); + logResult(result, "Failed to get surface capabilities"); return PAL_FALSE; } @@ -341,8 +341,7 @@ PalBool descriptorIndexingTest() result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create swapchain: %s", error); + logResult(result, "Failed to create swapchain"); return PAL_FALSE; } @@ -359,8 +358,7 @@ PalBool descriptorIndexingTest() PalImageInfo imageInfo; result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); + logResult(result, "Failed to get image info"); return PAL_FALSE; } @@ -382,16 +380,14 @@ PalBool descriptorIndexingTest() result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); + logResult(result, "Failed to create image view"); return PAL_FALSE; } // create render finished semaphores result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } @@ -400,8 +396,7 @@ PalBool descriptorIndexingTest() result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); + logResult(result, "Failed to create command pool"); return PAL_FALSE; } @@ -409,15 +404,13 @@ PalBool descriptorIndexingTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } @@ -428,8 +421,7 @@ PalBool descriptorIndexingTest() &cmdBuffers[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); + logResult(result, "Failed to allocate command buffer"); return PAL_FALSE; } } @@ -450,106 +442,44 @@ PalBool descriptorIndexingTest() bufferCreateInfo.size = sizeof(vertices); bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create vertex buffer: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create staging buffer: %s", error); - return PAL_FALSE; - } - - // get buffer memory requirement and allocate memory - PalMemoryRequirements vertexBufferMemReq = {0}; - PalMemoryRequirements stagingBufferMemReq = {0}; - - result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - // we need to check if the memory type we want are supported - // but almost every GPU supports a GPU only memory - // and CPU writable memory - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - vertexBufferMemReq.memoryMask, - vertexBufferMemReq.size, - &vertexBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - stagingBufferMemReq.memoryMask, - stagingBufferMemReq.size, - &stagingBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - // bind memory - result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } // map the staging buffer and upload the vertices void* ptr = nullptr; - result = palMapBufferMemory(stagingBuffer, 0, sizeof(vertices), &ptr); + result = palMapBuffer(stagingBuffer, 0, sizeof(vertices), &ptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } memcpy(ptr, vertices, sizeof(vertices)); - palUnmapBufferMemory(stagingBuffer); + palUnmapBuffer(stagingBuffer); PalFence* fence = nullptr; result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } // create image for the textures PalImageCreateInfo imageCreateInfo = {0}; - imageCreateInfo.depthOrArraySize = 1; + imageCreateInfo.arrayLayerCount = 1; + imageCreateInfo.depth = 1; imageCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; imageCreateInfo.mipLevelCount = 1; // simple imageCreateInfo.sampleCount = PAL_SAMPLE_COUNT_1; // simple @@ -557,41 +487,12 @@ PalBool descriptorIndexingTest() imageCreateInfo.usages = PAL_IMAGE_USAGE_TRANSFER_DST | PAL_IMAGE_USAGE_SAMPLED; imageCreateInfo.width = TEXTURE_WIDTH; imageCreateInfo.height = TEXTURE_HEIGHT; + imageCreateInfo.memoryUsage = PAL_IMAGE_MEMORY_USAGE_AUTO_GPU_ONLY; for (int i = 0; i < 4; i++) { result = palCreateImage(device, &imageCreateInfo, &textures[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image: %s", error); - return PAL_FALSE; - } - - // allocate memory for the image - PalMemoryRequirements imageMemReq = {0}; - result = palGetImageMemoryRequirements(textures[i], &imageMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image memory requirement: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - imageMemReq.memoryMask, - imageMemReq.size, - &textureMemories[i]); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory: %s", error); - return PAL_FALSE; - } - - result = palBindImageMemory(textures[i], textureMemories[i], 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind image memory: %s", error); + logResult(result, "Failed to create image"); return PAL_FALSE; } } @@ -616,8 +517,7 @@ PalBool descriptorIndexingTest() &imageCopyStagingBufferSize); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to compute image copy staging buffer info: %s", error); + logResult(result, "Failed to compute buffer info"); return PAL_FALSE; } @@ -626,9 +526,6 @@ PalBool descriptorIndexingTest() bufferImageCopyInfo.bufferImageHeight = bufferImageHeight; // create staging buffers to transfer the data to the image - PalBuffer* imageStagingBuffers[4]; - PalMemory* imageStagingBufferMemories[4]; - uint32_t textureDatas[4][TEXTURE_WIDTH * TEXTURE_HEIGHT]; createFlatTexture(textureDatas[0], TEXTURE_WIDTH, TEXTURE_HEIGHT, 255, 0, 0); createFlatTexture(textureDatas[1], TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, 255, 0); @@ -638,54 +535,25 @@ PalBool descriptorIndexingTest() PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; imageStagingBufferCreateInfo.size = imageCopyStagingBufferSize; imageStagingBufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; + imageStagingBufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; for (int i = 0; i < 4; i++) { result = palCreateBuffer(device, &imageStagingBufferCreateInfo, &imageStagingBuffers[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image staging buffer: %s", error); - return PAL_FALSE; - } - - PalMemoryRequirements imageStagingBufferMemReq = {0}; - result = palGetBufferMemoryRequirements(imageStagingBuffers[i], &imageStagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image staging buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - imageStagingBufferMemReq.memoryMask, - imageStagingBufferMemReq.size, - &imageStagingBufferMemories[i]); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(imageStagingBuffers[i], imageStagingBufferMemories[i], 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind image staging buffer memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } // copy data void* data = nullptr; - result = palMapBufferMemory( + result = palMapBuffer( imageStagingBuffers[i], 0, imageCopyStagingBufferSize, &data); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } @@ -698,12 +566,11 @@ PalBool descriptorIndexingTest() &bufferImageCopyInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to write to image copy staging buffer: %s", error); + logResult(result, "Failed to write to buffer"); return PAL_FALSE; } - palUnmapBufferMemory(imageStagingBuffers[i]); + palUnmapBuffer(imageStagingBuffers[i]); } // use the first command buffer to upload the copy @@ -712,8 +579,7 @@ PalBool descriptorIndexingTest() // to see if we have to wait for the copy to be executed result = palCmdBegin(cmdBuffers[0], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } @@ -722,32 +588,18 @@ PalBool descriptorIndexingTest() result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } - PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; - PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStageCount = 1; - newUsageStateInfo.shaderStages = vertexShaderStage; - newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; - - result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); + PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; + PalUsageState newUsageState = PAL_USAGE_STATE_VERTEX_READ; + result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } - // copy image staging buffers to the images - // first the image must be in the correct layout - PalUsageStateInfo oldImageUsageState = {0}; - PalUsageStateInfo newImageUsageState = {0}; - // set a barrier on the image to transition it into transfer dst state PalImageSubresourceRange textureRange = {0}; textureRange.startMipLevel = 0; @@ -756,24 +608,17 @@ PalBool descriptorIndexingTest() textureRange.layerArrayCount = 1; for (int i = 0; i < 4; i++) { - oldImageUsageState.shaderStageCount = 0; - oldImageUsageState.shaderStages = nullptr; - oldImageUsageState.usageState = PAL_USAGE_STATE_UNDEFINED; - - newImageUsageState.shaderStageCount = 0; - newImageUsageState.shaderStages = nullptr; - newImageUsageState.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - + PalUsageState oldImageUsageState = PAL_USAGE_STATE_UNDEFINED; + PalUsageState newImageUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; result = palCmdImageBarrier( cmdBuffers[0], textures[i], &textureRange, - &oldImageUsageState, - &newImageUsageState); + oldImageUsageState, + newImageUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -784,37 +629,28 @@ PalBool descriptorIndexingTest() &bufferImageCopyInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer to image: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } - // we should transition the image into a shader read state so we dont do that - // in the main loop - PalShaderStage fragmentShaderStage[] = { PAL_SHADER_STAGE_FRAGMENT }; oldImageUsageState = newImageUsageState; - newImageUsageState.usageState = PAL_USAGE_STATE_SHADER_READ; - newImageUsageState.shaderStageCount = 1; - newImageUsageState.shaderStages = fragmentShaderStage; // fragment shader will read - + newImageUsageState = PAL_USAGE_STATE_SHADER_READ; result = palCmdImageBarrier( cmdBuffers[0], textures[i], &textureRange, - &oldImageUsageState, - &newImageUsageState); + oldImageUsageState, + newImageUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } } result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -823,8 +659,7 @@ PalBool descriptorIndexingTest() submitInfo.fence = fence; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } @@ -843,8 +678,7 @@ PalBool descriptorIndexingTest() &textureViews[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create checkerboard image view: %s", error); + logResult(result, "Failed to create image view"); return PAL_FALSE; } } @@ -869,8 +703,7 @@ PalBool descriptorIndexingTest() &sampler); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create sampler: %s", error); + logResult(result, "Failed to create sampler"); return PAL_FALSE; } @@ -929,8 +762,7 @@ PalBool descriptorIndexingTest() result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create shader: %s", error); + logResult(result, "Failed to create shader"); return PAL_FALSE; } @@ -950,12 +782,10 @@ PalBool descriptorIndexingTest() descriptorSetLayoutcreateInfo.bindingCount = 2; descriptorSetLayoutcreateInfo.bindings = descriptorBindings; - PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; - descriptorSetLayoutcreateInfo.shaderStageCount = 1; - descriptorSetLayoutcreateInfo.shaderStages = shaderStages; - - // we need to enable descriptor indexing for the descriptor set layout - descriptorSetLayoutcreateInfo.enableDescriptorIndexing = PAL_TRUE; + // we only need the partially bound feature if supported. + if (descriptorIndexingCaps.flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { + descriptorSetLayoutcreateInfo.flags |= PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND; + } result = palCreateDescriptorSetLayout( device, @@ -963,8 +793,7 @@ PalBool descriptorIndexingTest() &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor set layout: %s", error); + logResult(result, "Failed to create descriptor set layout"); return PAL_FALSE; } @@ -978,16 +807,12 @@ PalBool descriptorIndexingTest() PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set - descriptorPoolCreateInfo.maxDescriptorBindingSizes = 2; + descriptorPoolCreateInfo.bindingSizeCount = 2; descriptorPoolCreateInfo.bindingSizes = storageBufferBindingsizes; - // we need to enable descriptor indexing for the descriptor pool - descriptorPoolCreateInfo.enableDescriptorIndexing = PAL_TRUE; - result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor pool: %s", error); + logResult(result, "Failed to create descriptor pool"); return PAL_FALSE; } @@ -995,13 +820,13 @@ PalBool descriptorIndexingTest() // using the layout we created above result = palAllocateDescriptorSet(device, descriptorPool, descriptorSetLayout, &descriptorSet); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate descriptor set: %s", error); + logResult(result, "Failed to allocate descriptor set"); return PAL_FALSE; } // check if null descriptors was enabled and partially bound was not supported - PalBool hasPartiallyBound = adapterFeatures & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; + PalDescriptorIndexingFlags flags = descriptorIndexingCaps.flags; + PalBool hasPartiallyBound = flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND; if (adapterFeatures & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS && !hasPartiallyBound) { // write null descriptors into the slots PalDescriptorSetWriteInfo writeInfo = {0}; @@ -1018,8 +843,7 @@ PalBool descriptorIndexingTest() result = palUpdateDescriptorSet(device, 1, &writeInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to update descriptor set: %s", error); + logResult(result, "Failed to update descriptor set"); return PAL_FALSE; } @@ -1045,8 +869,7 @@ PalBool descriptorIndexingTest() result = palUpdateDescriptorSet(device, 1, &writeInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to update descriptor set: %s", error); + logResult(result, "Failed to update descriptor set"); return PAL_FALSE; } } @@ -1093,8 +916,7 @@ PalBool descriptorIndexingTest() result = palUpdateDescriptorSet(device, 5, writeInfos); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to update descriptor set: %s", error); + logResult(result, "Failed to update descriptor set"); return PAL_FALSE; } @@ -1104,8 +926,6 @@ PalBool descriptorIndexingTest() PalPushConstantRange pushConstantRange = {0}; pushConstantRange.offset = 0; pushConstantRange.size = sizeof(PushConstant); // must match shader - pushConstantRange.shaderStageCount = 1; - pushConstantRange.shaderStages = shaderStages; // create pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; @@ -1116,15 +936,14 @@ PalBool descriptorIndexingTest() result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); + logResult(result, "Failed to create pipeline layout"); return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; renderingLayoutInfo.colorAttachentCount = 1; renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; - renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.sampleCount = PAL_SAMPLE_COUNT_1; renderingLayoutInfo.viewCount = 1; // create graphics pipeline @@ -1134,12 +953,10 @@ PalBool descriptorIndexingTest() // position vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; - vertexAttributes[0].semanticName = nullptr; // use default vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; // texture coordinates vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_TEXCOORD; - vertexAttributes[1].semanticName = nullptr; // use default vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT2; vertexLayout.attributeCount = 2; @@ -1170,8 +987,7 @@ PalBool descriptorIndexingTest() result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create graphics pipeline: %s", error); + logResult(result, "Failed to create pipeline"); return PAL_FALSE; } @@ -1182,21 +998,13 @@ PalBool descriptorIndexingTest() // wait for the vertices copy to be done result = palWaitFence(fence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } // the vertices have been copied palDestroyFence(fence); palDestroyBuffer(stagingBuffer); - palFreeMemory(device, stagingBufferMemory); - - // we can destroy the image staging buffer - for (int i = 0; i < 4; i++) { - palDestroyBuffer(imageStagingBuffers[i]); - palFreeMemory(device, imageStagingBufferMemories[i]); - } // main loop uint32_t currentFrame = 0; @@ -1219,12 +1027,12 @@ PalBool descriptorIndexingTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -1237,8 +1045,7 @@ PalBool descriptorIndexingTest() result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -1251,16 +1058,14 @@ PalBool descriptorIndexingTest() uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); + logResult(result, "Failed to get next swapchain image"); return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -1269,8 +1074,7 @@ PalBool descriptorIndexingTest() if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -1280,8 +1084,7 @@ PalBool descriptorIndexingTest() result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -1289,22 +1092,19 @@ PalBool descriptorIndexingTest() // reset the command buffer result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to reset command buffer: %s", error); + logResult(result, "Failed to reset command buffer"); return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } // change the state of the image view to make it renderable - PalUsageStateInfo oldUsageStateInfo = {0}; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; + PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -1317,12 +1117,11 @@ PalBool descriptorIndexingTest() cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -1345,52 +1144,44 @@ PalBool descriptorIndexingTest() result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin rendering: %s", error); + logResult(result, "Failed to begin rendering"); return PAL_FALSE; } // bind pipeline result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); + logResult(result, "Failed to bind pipeline"); return PAL_FALSE; } result = palCmdPushConstants( cmdBuffers[currentFrame], - 1, - shaderStages, 0, sizeof(PushConstant), &pushConstant); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to push constants: %s", error); + logResult(result, "Failed to push constants"); return PAL_FALSE; } result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind descriptor set: %s", error); + logResult(result, "Failed to push constants"); return PAL_FALSE; } // set viewport and scissors result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set viewport: %s", error); + logResult(result, "Failed to set viewport"); return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set scissors: %s", error); + logResult(result, "Failed to set scissor"); return PAL_FALSE; } @@ -1404,45 +1195,40 @@ PalBool descriptorIndexingTest() offset); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind vertex buffer: %s", error); + logResult(result, "Failed to bind vertex buffer"); return PAL_FALSE; } result = palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to issue draw command: %s", error); + logResult(result, "Failed to issue draw command"); return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end rendering: %s", error); + logResult(result, "Failed to end rendering"); return PAL_FALSE; } // change the state of the image view to make it presentable - oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + oldUsageState = newUsageState; + newUsageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -1455,19 +1241,14 @@ PalBool descriptorIndexingTest() result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // present - PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; - result = palPresentSwapchain(swapchain, &presentInfo); + result = palPresentSwapchain(swapchain, imageIndex, renderFinishedSemaphores[imageIndex]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to present swapchain: %s", error); + logResult(result, "Failed to present swapchain"); return PAL_FALSE; } @@ -1476,8 +1257,7 @@ PalBool descriptorIndexingTest() result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for queue: %s", error); + logResult(result, "Failed to wait queue"); return PAL_FALSE; } @@ -1502,12 +1282,9 @@ PalBool descriptorIndexingTest() for (int i = 0; i < 4; i++) { palDestroyImageView(textureViews[i]); palDestroyImage(textures[i]); - palFreeMemory(device, textureMemories[i]); } palDestroyBuffer(vertexBuffer); - palFreeMemory(device, vertexBufferMemory); - palDestroyCommandPool(cmdPool); palDestroySwapchain(swapchain); palDestroySurface(surface); diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index d5c1b741..d4a2b7bb 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -22,7 +22,6 @@ PalBool geometryTest() PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; - PalGraphicsWindow gfxWindow; PalAdapter* adapter = nullptr; PalDevice* device = nullptr; @@ -49,8 +48,8 @@ PalBool geometryTest() return PAL_FALSE; } - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { @@ -75,40 +74,43 @@ PalBool geometryTest() return PAL_FALSE; } - PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); - gfxWindow.display = winHandle.nativeDisplay; - gfxWindow.window = winHandle.nativeWindow; - - // using pal_system.h will be easy to know the underlying windowing API - // or use typedefs. We will use the pal_system module. This is needed - // for systems which multiple windowing APIs (linux). + // get window handle. You can use any window from any library + // so long as you can get the window handle and display (if on X11, wayland) + // If pal video system will not be used, there is no need to initialize it + PalWindowHandleInfo winHandle = {0}; + result = palGetWindowHandleInfo(window, &winHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } + + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; result = palGetPlatformInfo(&platformInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get platform information: %s", error); + logResult(result, "Failed to get platform information"); return PAL_FALSE; } - if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; + if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WAYLAND; - } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_X11) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_X11; - } else { - // automatically this is xcb - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WIN32) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WIN32; } PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -116,8 +118,7 @@ PalBool geometryTest() int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -136,8 +137,7 @@ PalBool geometryTest() result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -148,8 +148,7 @@ PalBool geometryTest() adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -168,8 +167,7 @@ PalBool geometryTest() // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + logResult(result, "Failed to get adapter info"); return PAL_FALSE; } @@ -208,16 +206,20 @@ PalBool geometryTest() result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); return PAL_FALSE; } // create surface - result = palCreateSurface(device, &gfxWindow, &surface); + result = palCreateSurface( + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, + &surface); + if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create surface: %s", error); + logResult(result, "Failed to create surface"); return PAL_FALSE; } @@ -226,8 +228,7 @@ PalBool geometryTest() for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); + logResult(result, "Failed to create queue"); return PAL_FALSE; } @@ -250,8 +251,7 @@ PalBool geometryTest() PalSurfaceCapabilities surfaceCaps = {0}; result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get surface capabilities: %s", error); + logResult(result, "Failed to get surface capabilities"); return PAL_FALSE; } @@ -286,8 +286,7 @@ PalBool geometryTest() result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create swapchain: %s", error); + logResult(result, "Failed to create swapchain"); return PAL_FALSE; } @@ -304,8 +303,7 @@ PalBool geometryTest() PalImageInfo imageInfo; result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); + logResult(result, "Failed to get image info"); return PAL_FALSE; } @@ -327,16 +325,14 @@ PalBool geometryTest() result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); + logResult(result, "Failed to create image view"); return PAL_FALSE; } // create render finished semaphores result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } @@ -345,8 +341,7 @@ PalBool geometryTest() result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); + logResult(result, "Failed to create command pool"); return PAL_FALSE; } @@ -354,15 +349,13 @@ PalBool geometryTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } @@ -373,8 +366,7 @@ PalBool geometryTest() &cmdBuffers[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); + logResult(result, "Failed to allocate command buffer"); return PAL_FALSE; } } @@ -440,8 +432,7 @@ PalBool geometryTest() result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create shader: %s", error); + logResult(result, "Failed to create shader"); return PAL_FALSE; } @@ -452,15 +443,14 @@ PalBool geometryTest() PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); + logResult(result, "Failed to create pipeline layout"); return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; renderingLayoutInfo.colorAttachentCount = 1; renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; - renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.sampleCount = PAL_SAMPLE_COUNT_1; renderingLayoutInfo.viewCount = 1; // create graphics pipeline @@ -486,8 +476,7 @@ PalBool geometryTest() result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create graphics pipeline: %s", error); + logResult(result, "Failed to create pipeline"); return PAL_FALSE; } @@ -510,12 +499,12 @@ PalBool geometryTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -528,8 +517,7 @@ PalBool geometryTest() result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -542,16 +530,14 @@ PalBool geometryTest() uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); + logResult(result, "Failed to get next swapchain image"); return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -560,8 +546,7 @@ PalBool geometryTest() if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -571,8 +556,7 @@ PalBool geometryTest() result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -580,22 +564,19 @@ PalBool geometryTest() // reset the command buffer result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to reset command buffer: %s", error); + logResult(result, "Failed to reset command buffer"); return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } // change the state of the image view to make it renderable - PalUsageStateInfo oldUsageStateInfo = {0}; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; + PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -608,12 +589,11 @@ PalBool geometryTest() cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -636,74 +616,65 @@ PalBool geometryTest() result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin rendering: %s", error); + logResult(result, "Failed to begin rendering"); return PAL_FALSE; } // bind pipeline result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); + logResult(result, "Failed to bind pipeline"); return PAL_FALSE; } // set viewport and scissors result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set viewport: %s", error); + logResult(result, "Failed to set viewport"); return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set scissors: %s", error); + logResult(result, "Failed to set scissor"); return PAL_FALSE; } if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind vertex buffer: %s", error); + logResult(result, "Failed to bind vertex buffer"); return PAL_FALSE; } result = palCmdDraw(cmdBuffers[currentFrame], 3, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to issue draw command: %s", error); + logResult(result, "Failed to issue draw command"); return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end rendering: %s", error); + logResult(result, "Failed to end rendering"); return PAL_FALSE; } // change the state of the image view to make it presentable - oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + oldUsageState = newUsageState; + newUsageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -716,19 +687,14 @@ PalBool geometryTest() result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // present - PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; - result = palPresentSwapchain(swapchain, &presentInfo); + result = palPresentSwapchain(swapchain, imageIndex, renderFinishedSemaphores[imageIndex]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to present swapchain: %s", error); + logResult(result, "Failed to present swapchain"); return PAL_FALSE; } @@ -737,8 +703,7 @@ PalBool geometryTest() result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for queue: %s", error); + logResult(result, "Failed to wait queue"); return PAL_FALSE; } diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 64917ded..280b2e68 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -88,10 +88,6 @@ PalBool graphicsTest() deviceFeatures |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; } - if (features & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS) { - deviceFeatures |= PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS; - } - result = palCreateDevice(adapter, deviceFeatures, &device); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create device"); @@ -618,10 +614,6 @@ PalBool graphicsTest() palLog(nullptr, " Dispatch base"); } - if (features & PAL_ADAPTER_FEATURE_PARTIALLY_BOUND_DESCRIPTORS) { - palLog(nullptr, " Partially bound descriptors"); - } - if (features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS) { palLog(nullptr, " Null descriptors"); } diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 9ec969ee..ac1e0b42 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -29,7 +29,6 @@ PalBool indirectDrawTest() PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; - PalGraphicsWindow gfxWindow; PalAdapter* adapter = nullptr; PalDevice* device = nullptr; @@ -53,11 +52,6 @@ PalBool indirectDrawTest() PalBuffer* indexBuffer = nullptr; PalBuffer* indirectBuffer = nullptr; PalBuffer* stagingBuffer = nullptr; - - PalMemory* vertexBufferMemory = nullptr; - PalMemory* indexBufferMemory = nullptr; - PalMemory* indirectBufferMemory = nullptr; - PalMemory* stagingBufferMemory = nullptr; PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); @@ -66,8 +60,8 @@ PalBool indirectDrawTest() return PAL_FALSE; } - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { @@ -92,40 +86,43 @@ PalBool indirectDrawTest() return PAL_FALSE; } - PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); - gfxWindow.display = winHandle.nativeDisplay; - gfxWindow.window = winHandle.nativeWindow; + // get window handle. You can use any window from any library + // so long as you can get the window handle and display (if on X11, wayland) + // If pal video system will not be used, there is no need to initialize it + PalWindowHandleInfo winHandle = {0}; + result = palGetWindowHandleInfo(window, &winHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } - // using pal_system.h will be easy to know the underlying windowing API - // or use typedefs. We will use the pal_system module. This is needed - // for systems which multiple windowing APIs (linux). + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; result = palGetPlatformInfo(&platformInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get platform information: %s", error); + logResult(result, "Failed to get platform information"); return PAL_FALSE; } - if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; + if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WAYLAND; - } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_X11) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_X11; - } else { - // automatically this is xcb - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WIN32) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WIN32; } PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -133,8 +130,7 @@ PalBool indirectDrawTest() int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -153,8 +149,7 @@ PalBool indirectDrawTest() result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -165,8 +160,7 @@ PalBool indirectDrawTest() adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -185,8 +179,7 @@ PalBool indirectDrawTest() // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + logResult(result, "Failed to get adapter info"); return PAL_FALSE; } @@ -225,16 +218,20 @@ PalBool indirectDrawTest() result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); return PAL_FALSE; } // create surface - result = palCreateSurface(device, &gfxWindow, &surface); + result = palCreateSurface( + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, + &surface); + if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create surface: %s", error); + logResult(result, "Failed to create surface"); return PAL_FALSE; } @@ -243,8 +240,7 @@ PalBool indirectDrawTest() for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); + logResult(result, "Failed to create queue"); return PAL_FALSE; } @@ -267,8 +263,7 @@ PalBool indirectDrawTest() PalSurfaceCapabilities surfaceCaps = {0}; result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get surface capabilities: %s", error); + logResult(result, "Failed to get surface capabilities"); return PAL_FALSE; } @@ -303,8 +298,7 @@ PalBool indirectDrawTest() result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create swapchain: %s", error); + logResult(result, "Failed to create swapchain"); return PAL_FALSE; } @@ -321,8 +315,7 @@ PalBool indirectDrawTest() PalImageInfo imageInfo; result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); + logResult(result, "Failed to get image info"); return PAL_FALSE; } @@ -344,16 +337,14 @@ PalBool indirectDrawTest() result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); + logResult(result, "Failed to create image view"); return PAL_FALSE; } // create render finished semaphores result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } @@ -362,8 +353,7 @@ PalBool indirectDrawTest() result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); + logResult(result, "Failed to create command pool"); return PAL_FALSE; } @@ -371,15 +361,13 @@ PalBool indirectDrawTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } @@ -390,8 +378,7 @@ PalBool indirectDrawTest() &cmdBuffers[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); + logResult(result, "Failed to allocate command buffer"); return PAL_FALSE; } } @@ -413,10 +400,11 @@ PalBool indirectDrawTest() bufferCreateInfo.size = sizeof(vertices); bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create buffer: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } @@ -424,10 +412,10 @@ PalBool indirectDrawTest() bufferCreateInfo.size = sizeof(indices); bufferCreateInfo.usages = PAL_BUFFER_USAGE_INDEX; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; result = palCreateBuffer(device, &bufferCreateInfo, &indexBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create buffer: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } @@ -435,10 +423,10 @@ PalBool indirectDrawTest() bufferCreateInfo.size = sizeof(PalDrawIndexedIndirectData); bufferCreateInfo.usages = PAL_BUFFER_USAGE_INDIRECT; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; result = palCreateBuffer(device, &bufferCreateInfo, &indirectBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create buffer: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } @@ -459,144 +447,18 @@ PalBool indirectDrawTest() uint32_t stagingBufferSize = offset; bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send bufferCreateInfo.size = offset; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create buffer: %s", error); - return PAL_FALSE; - } - - // get buffer memory requirement and allocate memory - PalMemoryRequirements vertexBufferMemReq = {0}; - PalMemoryRequirements indexBufferMemReq = {0}; - PalMemoryRequirements indirectBufferMemReq = {0}; - PalMemoryRequirements stagingBufferMemReq = {0}; - - // get vertex buffer memory requirement - result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - // get index buffer memory requirement - result = palGetBufferMemoryRequirements(indexBuffer, &indexBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - // get indirect buffer memory requirement - result = palGetBufferMemoryRequirements(indirectBuffer, &indirectBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - // get staging buffer memory requirement - result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - // allocate memory for vertex buffer - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - vertexBufferMemReq.memoryMask, - vertexBufferMemReq.size, - &vertexBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - // allocate memory for index buffer - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - indexBufferMemReq.memoryMask, - indexBufferMemReq.size, - &indexBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - // allocate memory for indirect buffer - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - indirectBufferMemReq.memoryMask, - indirectBufferMemReq.size, - &indirectBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - stagingBufferMemReq.memoryMask, - stagingBufferMemReq.size, - &stagingBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - // bind memory for vertex buffer - result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); - return PAL_FALSE; - } - - // bind memory for index buffer - result = palBindBufferMemory(indexBuffer, indexBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); - return PAL_FALSE; - } - - // bind memory for indirect buffer - result = palBindBufferMemory(indirectBuffer, indirectBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); - return PAL_FALSE; - } - - // bind memory for staging buffer - result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } // map the staging buffer and upload the data void* ptr = nullptr; - result = palMapBufferMemory(stagingBuffer, 0, stagingBufferSize, &ptr); + result = palMapBuffer(stagingBuffer, 0, stagingBufferSize, &ptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } @@ -617,13 +479,12 @@ PalBool indirectDrawTest() // copy indices memcpy(dst + indexOffset, indices, sizeof(indices)); - palUnmapBufferMemory(stagingBuffer); + palUnmapBuffer(stagingBuffer); PalFence* fence = nullptr; result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } @@ -633,18 +494,12 @@ PalBool indirectDrawTest() // to see if we have to wait for the copy to be executed result = palCmdBegin(cmdBuffers[0], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } - PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; - - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStageCount = 0; - newUsageStateInfo.shaderStages = nullptr; - newUsageStateInfo.usageState = PAL_USAGE_STATE_INDIRECT_READ; + PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; + PalUsageState newUsageState = PAL_USAGE_STATE_INDIRECT_READ; // copy to indirect buffer PalBufferCopyInfo indirectCopyInfo = {0}; @@ -654,30 +509,22 @@ PalBool indirectDrawTest() result = palCmdCopyBuffer(cmdBuffers[0], indirectBuffer, stagingBuffer, &indirectCopyInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } result = palCmdBufferBarrier( cmdBuffers[0], indirectBuffer, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } - // copy to vertex buffer - PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; - - newUsageStateInfo.shaderStageCount = 1; - newUsageStateInfo.shaderStages = vertexShaderStage; - newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; - + newUsageState = PAL_USAGE_STATE_VERTEX_READ; PalBufferCopyInfo vertexCopyInfo = {0}; vertexCopyInfo.dstOffset = 0; vertexCopyInfo.size = sizeof(vertices); @@ -685,28 +532,23 @@ PalBool indirectDrawTest() result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, &vertexCopyInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } result = palCmdBufferBarrier( cmdBuffers[0], vertexBuffer, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } // copy to index buffer - newUsageStateInfo.shaderStageCount = 0; - newUsageStateInfo.shaderStages = nullptr; - newUsageStateInfo.usageState = PAL_USAGE_STATE_INDEX_READ; - + newUsageState = PAL_USAGE_STATE_INDEX_READ; PalBufferCopyInfo indexCopyInfo = {0}; indexCopyInfo.dstOffset = 0; indexCopyInfo.size = sizeof(indices); @@ -714,27 +556,24 @@ PalBool indirectDrawTest() result = palCmdCopyBuffer(cmdBuffers[0], indexBuffer, stagingBuffer, &indexCopyInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } result = palCmdBufferBarrier( cmdBuffers[0], indexBuffer, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -743,8 +582,7 @@ PalBool indirectDrawTest() submitInfo.fence = fence; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } @@ -803,8 +641,7 @@ PalBool indirectDrawTest() result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create shader: %s", error); + logResult(result, "Failed to create shader"); return PAL_FALSE; } @@ -815,15 +652,14 @@ PalBool indirectDrawTest() PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); + logResult(result, "Failed to create pipeline layout"); return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; renderingLayoutInfo.colorAttachentCount = 1; renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; - renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.sampleCount = PAL_SAMPLE_COUNT_1; renderingLayoutInfo.viewCount = 1; // create graphics pipeline @@ -833,12 +669,10 @@ PalBool indirectDrawTest() // position vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; - vertexAttributes[0].semanticName = nullptr; // use default vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; // color coordinates vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_COLOR; - vertexAttributes[1].semanticName = nullptr; // use default vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT3; vertexLayout.attributeCount = 2; @@ -869,8 +703,7 @@ PalBool indirectDrawTest() result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create graphics pipeline: %s", error); + logResult(result, "Failed to create pipeline"); return PAL_FALSE; } @@ -881,15 +714,13 @@ PalBool indirectDrawTest() // wait for the vertices copy to be done result = palWaitFence(fence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } // the vertices have been copied palDestroyFence(fence); palDestroyBuffer(stagingBuffer); - palFreeMemory(device, stagingBufferMemory); // main loop uint32_t currentFrame = 0; @@ -906,12 +737,12 @@ PalBool indirectDrawTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -924,8 +755,7 @@ PalBool indirectDrawTest() result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -938,16 +768,14 @@ PalBool indirectDrawTest() uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); + logResult(result, "Failed to get next swapchain image"); return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -956,8 +784,7 @@ PalBool indirectDrawTest() if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -967,8 +794,7 @@ PalBool indirectDrawTest() result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -976,22 +802,19 @@ PalBool indirectDrawTest() // reset the command buffer result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to reset command buffer: %s", error); + logResult(result, "Failed to reset command buffer"); return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } // change the state of the image view to make it renderable - PalUsageStateInfo oldUsageStateInfo = {0}; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; + PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -1004,12 +827,11 @@ PalBool indirectDrawTest() cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -1032,31 +854,27 @@ PalBool indirectDrawTest() result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin rendering: %s", error); + logResult(result, "Failed to begin rendering"); return PAL_FALSE; } // bind pipeline result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); + logResult(result, "Failed to bind pipeline"); return PAL_FALSE; } // set viewport and scissors result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set viewport: %s", error); + logResult(result, "Failed to set viewport"); return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set scissors: %s", error); + logResult(result, "Failed to set scissor"); return PAL_FALSE; } @@ -1070,8 +888,7 @@ PalBool indirectDrawTest() offset); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind vertex buffer: %s", error); + logResult(result, "Failed to bind vertex buffer"); return PAL_FALSE; } @@ -1083,45 +900,40 @@ PalBool indirectDrawTest() PAL_INDEX_TYPE_UINT32); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind index buffer: %s", error); + logResult(result, "Failed to bind index buffer"); return PAL_FALSE; } result = palCmdDrawIndexedIndirect(cmdBuffers[currentFrame], indirectBuffer, 1); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to issue draw indirect command: %s", error); + logResult(result, "Failed to issue draw command"); return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end rendering: %s", error); + logResult(result, "Failed to end rendering"); return PAL_FALSE; } // change the state of the image view to make it presentable - oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + oldUsageState = newUsageState; + newUsageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -1134,19 +946,14 @@ PalBool indirectDrawTest() result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // present - PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; - result = palPresentSwapchain(swapchain, &presentInfo); + result = palPresentSwapchain(swapchain, imageIndex, renderFinishedSemaphores[imageIndex]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to present swapchain: %s", error); + logResult(result, "Failed to present swapchain"); return PAL_FALSE; } @@ -1155,8 +962,7 @@ PalBool indirectDrawTest() result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for queue: %s", error); + logResult(result, "Failed to wait queue"); return PAL_FALSE; } @@ -1178,10 +984,6 @@ PalBool indirectDrawTest() palDestroyBuffer(vertexBuffer); palDestroyBuffer(indexBuffer); - palFreeMemory(device, indirectBufferMemory); - palFreeMemory(device, vertexBufferMemory); - palFreeMemory(device, indexBufferMemory); - palDestroyCommandPool(cmdPool); palDestroySwapchain(swapchain); palDestroySurface(surface); diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 29aff9ad..210de44b 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -22,7 +22,6 @@ PalBool meshTest() PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; - PalGraphicsWindow gfxWindow; PalAdapter* adapter = nullptr; PalDevice* device = nullptr; @@ -49,8 +48,8 @@ PalBool meshTest() return PAL_FALSE; } - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { @@ -75,40 +74,43 @@ PalBool meshTest() return PAL_FALSE; } - PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); - gfxWindow.display = winHandle.nativeDisplay; - gfxWindow.window = winHandle.nativeWindow; + // get window handle. You can use any window from any library + // so long as you can get the window handle and display (if on X11, wayland) + // If pal video system will not be used, there is no need to initialize it + PalWindowHandleInfo winHandle = {0}; + result = palGetWindowHandleInfo(window, &winHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } - // using pal_system.h will be easy to know the underlying windowing API - // or use typedefs. We will use the pal_system module. This is needed - // for systems which multiple windowing APIs (linux). + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; result = palGetPlatformInfo(&platformInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get platform information: %s", error); + logResult(result, "Failed to get platform information"); return PAL_FALSE; } - if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; + if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WAYLAND; - } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_X11) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_X11; - } else { - // automatically this is xcb - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WIN32) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WIN32; } PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -116,8 +118,7 @@ PalBool meshTest() int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -136,8 +137,7 @@ PalBool meshTest() result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -148,8 +148,7 @@ PalBool meshTest() adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -168,8 +167,7 @@ PalBool meshTest() // We want an adapter that supports spirv 1.5 or dxil 6.5 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + logResult(result, "Failed to get adapter info"); return PAL_FALSE; } @@ -208,16 +206,20 @@ PalBool meshTest() result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); return PAL_FALSE; } // create surface - result = palCreateSurface(device, &gfxWindow, &surface); + result = palCreateSurface( + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, + &surface); + if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create surface: %s", error); + logResult(result, "Failed to create surface"); return PAL_FALSE; } @@ -226,8 +228,7 @@ PalBool meshTest() for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); + logResult(result, "Failed to create queue"); return PAL_FALSE; } @@ -251,8 +252,7 @@ PalBool meshTest() result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get surface capabilities: %s", error); + logResult(result, "Failed to get surface capabilities"); return PAL_FALSE; } @@ -287,8 +287,7 @@ PalBool meshTest() result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create swapchain: %s", error); + logResult(result, "Failed to create swapchain"); return PAL_FALSE; } @@ -305,8 +304,7 @@ PalBool meshTest() PalImageInfo imageInfo; result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); + logResult(result, "Failed to get image info"); return PAL_FALSE; } @@ -328,16 +326,14 @@ PalBool meshTest() result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); + logResult(result, "Failed to create image view"); return PAL_FALSE; } // create render finished semaphores result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } @@ -346,8 +342,7 @@ PalBool meshTest() result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); + logResult(result, "Failed to create command pool"); return PAL_FALSE; } @@ -355,15 +350,13 @@ PalBool meshTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } @@ -374,8 +367,7 @@ PalBool meshTest() &cmdBuffers[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); + logResult(result, "Failed to allocate command buffer"); return PAL_FALSE; } } @@ -435,8 +427,7 @@ PalBool meshTest() result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create shader: %s", error); + logResult(result, "Failed to create shader"); return PAL_FALSE; } @@ -447,15 +438,14 @@ PalBool meshTest() PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); + logResult(result, "Failed to create pipeline layout"); return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; renderingLayoutInfo.colorAttachentCount = 1; renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; - renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.sampleCount = PAL_SAMPLE_COUNT_1; renderingLayoutInfo.viewCount = 1; // create graphics pipeline @@ -481,8 +471,7 @@ PalBool meshTest() result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create graphics pipeline: %s", error); + logResult(result, "Failed to create pipeline"); return PAL_FALSE; } @@ -505,12 +494,12 @@ PalBool meshTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -523,8 +512,7 @@ PalBool meshTest() result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -537,16 +525,14 @@ PalBool meshTest() uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); + logResult(result, "Failed to get next swapchain image"); return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -555,8 +541,7 @@ PalBool meshTest() if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -566,8 +551,7 @@ PalBool meshTest() result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -575,22 +559,19 @@ PalBool meshTest() // reset the command buffer result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to reset command buffer: %s", error); + logResult(result, "Failed to reset command buffer"); return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } // change the state of the image view to make it renderable - PalUsageStateInfo oldUsageStateInfo = {0}; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; + PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -603,12 +584,11 @@ PalBool meshTest() cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -631,31 +611,27 @@ PalBool meshTest() result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin rendering: %s", error); + logResult(result, "Failed to begin rendering"); return PAL_FALSE; } // bind pipeline result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); + logResult(result, "Failed to bind pipeline"); return PAL_FALSE; } // set viewport and scissors result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set viewport: %s", error); + logResult(result, "Failed to set viewport"); return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set scissors: %s", error); + logResult(result, "Failed to set scissor"); return PAL_FALSE; } @@ -665,38 +641,34 @@ PalBool meshTest() // workCount (image size, buffer size) result = palCmdDrawMeshTasks(cmdBuffers[currentFrame], 1, 1, 1); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to issue draw command: %s", error); + logResult(result, "Failed to issue draw command"); return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end rendering: %s", error); + logResult(result, "Failed to end rendering"); return PAL_FALSE; } // change the state of the image view to make it presentable - oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + oldUsageState = newUsageState; + newUsageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -709,19 +681,14 @@ PalBool meshTest() result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // present - PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; - result = palPresentSwapchain(swapchain, &presentInfo); + result = palPresentSwapchain(swapchain, imageIndex, renderFinishedSemaphores[imageIndex]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to present swapchain: %s", error); + logResult(result, "Failed to present swapchain"); return PAL_FALSE; } @@ -730,8 +697,7 @@ PalBool meshTest() result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for queue: %s", error); + logResult(result, "Failed to wait queue"); return PAL_FALSE; } diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index e46b7e6c..7591a66d 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -34,8 +34,6 @@ PalBool multiDescriptorSetTest() PalBuffer* buffers[3]; PalBuffer* stagingBuffers[3]; - PalMemory* bufferMemories[3]; - PalMemory* stagingBufferMemories[3]; PalDescriptorPool* descriptorPool = nullptr; PalDescriptorSetLayout* descriptorSetLayout; @@ -49,10 +47,9 @@ PalBool multiDescriptorSetTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -60,8 +57,7 @@ PalBool multiDescriptorSetTest() int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -80,8 +76,7 @@ PalBool multiDescriptorSetTest() result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -92,8 +87,7 @@ PalBool multiDescriptorSetTest() adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -118,8 +112,7 @@ PalBool multiDescriptorSetTest() // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + logResult(result, "Failed to get adapter info"); return PAL_FALSE; } @@ -152,23 +145,20 @@ PalBool multiDescriptorSetTest() // create a device result = palCreateDevice(adapter, 0, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); return PAL_FALSE; } // create a compute command queue result = palCreateQueue(device, PAL_QUEUE_TYPE_COMPUTE, &queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); + logResult(result, "Failed to create queue"); return PAL_FALSE; } result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); + logResult(result, "Failed to create command pool"); return PAL_FALSE; } @@ -179,8 +169,7 @@ PalBool multiDescriptorSetTest() &cmdBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); + logResult(result, "Failed to allocate command buffer"); return PAL_FALSE; } @@ -222,8 +211,7 @@ PalBool multiDescriptorSetTest() result = palCreateShader(device, &shaderCreateInfo, &shader); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create compute shader: %s", error); + logResult(result, "Failed to create shader"); return PAL_FALSE; } @@ -236,78 +224,18 @@ PalBool multiDescriptorSetTest() for (int i = 0; i < 3; i++) { bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE | PAL_BUFFER_USAGE_TRANSFER_SRC; - + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; result = palCreateBuffer(device, &bufferCreateInfo, &buffers[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create buffer: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_DST; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK; result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffers[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create buffer: %s", error); - return PAL_FALSE; - } - - // get buffer memory requirement and allocate memory - PalMemoryRequirements memReq = {0}; - PalMemoryRequirements stagingMemReq = {0}; - - result = palGetBufferMemoryRequirements(buffers[i], &memReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palGetBufferMemoryRequirements(stagingBuffers[i], &stagingMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - memReq.memoryMask, - memReq.size, - &bufferMemories[i]); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_READBACK, - stagingMemReq.memoryMask, - stagingMemReq.size, - &stagingBufferMemories[i]); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - // bind memory - result = palBindBufferMemory(buffers[i], bufferMemories[i], 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(stagingBuffers[i], stagingBufferMemories[i], 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } } @@ -321,18 +249,13 @@ PalBool multiDescriptorSetTest() descriptorSetLayoutcreateInfo.bindingCount = 1; descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; - PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_COMPUTE }; - descriptorSetLayoutcreateInfo.shaderStageCount = 1; - descriptorSetLayoutcreateInfo.shaderStages = shaderStages; - result = palCreateDescriptorSetLayout( device, &descriptorSetLayoutcreateInfo, &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor set layout: %s", error); + logResult(result, "Failed to create descriptor set layout"); return PAL_FALSE; } @@ -343,13 +266,12 @@ PalBool multiDescriptorSetTest() PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; descriptorPoolCreateInfo.maxDescriptorSets = 3; - descriptorPoolCreateInfo.maxDescriptorBindingSizes = 1; // one binding type + descriptorPoolCreateInfo.bindingSizeCount = 1; // one binding type descriptorPoolCreateInfo.bindingSizes = &storageBufferBindingsize; result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor pool: %s", error); + logResult(result, "Failed to create descriptor pool"); return PAL_FALSE; } @@ -362,8 +284,7 @@ PalBool multiDescriptorSetTest() &descriptorSets[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate descriptor set: %s", error); + logResult(result, "Failed to allocate descriptor set"); return PAL_FALSE; } } @@ -393,8 +314,7 @@ PalBool multiDescriptorSetTest() result = palUpdateDescriptorSet(device, 3, writeInfos); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to update descriptor set: %s", error); + logResult(result, "Failed to update descriptor set"); return PAL_FALSE; } @@ -403,8 +323,6 @@ PalBool multiDescriptorSetTest() PalPushConstantRange pushConstantRange = {0}; pushConstantRange.offset = 0; pushConstantRange.size = sizeof(PushConstant); // must match shader - pushConstantRange.shaderStageCount = 1; - pushConstantRange.shaderStages = shaderStages; // create pipeline layout // even if the descriptor set layout is identical, pipeline layout creation needs @@ -422,8 +340,7 @@ PalBool multiDescriptorSetTest() result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); + logResult(result, "Failed to create pipeline layout"); return PAL_FALSE; } @@ -434,8 +351,7 @@ PalBool multiDescriptorSetTest() result = palCreateComputePipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create compute pipeline: %s", error); + logResult(result, "Failed to create pipeline"); return PAL_FALSE; } @@ -444,16 +360,14 @@ PalBool multiDescriptorSetTest() // create fence result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } // record commands result = palCmdBegin(cmdBuffer, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } @@ -481,22 +395,18 @@ PalBool multiDescriptorSetTest() result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); + logResult(result, "Failed to bind pipeline"); return PAL_FALSE; } result = palCmdPushConstants( cmdBuffer, - 1, - shaderStages, 0, sizeof(PushConstant), &pushConstant); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to push constants: %s", error); + logResult(result, "Failed to push constant"); return PAL_FALSE; } @@ -504,8 +414,7 @@ PalBool multiDescriptorSetTest() for (int i = 0; i < 3; i++) { result = palCmdBindDescriptorSet(cmdBuffer, i, descriptorSets[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind descriptor set: %s", error); + logResult(result, "Failed to bind descriptor set"); return PAL_FALSE; } } @@ -554,34 +463,25 @@ PalBool multiDescriptorSetTest() result = palCmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to dispatch: %s", error); + logResult(result, "Failed to issue dispatch command"); return PAL_FALSE; } } palFree(nullptr, workGroupInfos); // set a barrier so we only read from the buffer after the shader has written to it - PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; - oldUsageStateInfo.shaderStageCount = 1; - oldUsageStateInfo.shaderStages = shaderStages; - - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStageCount = 0; - newUsageStateInfo.shaderStages = nullptr; - newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; + PalUsageState oldUsageState = PAL_USAGE_STATE_SHADER_WRITE; + PalUsageState newUsageState = PAL_USAGE_STATE_TRANSFER_READ; for (int i = 0; i < 3; i++) { result = palCmdBufferBarrier( cmdBuffer, buffers[i], - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -591,16 +491,14 @@ PalBool multiDescriptorSetTest() result = palCmdCopyBuffer(cmdBuffer, stagingBuffers[i], buffers[i], ©Info); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } } result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -610,16 +508,14 @@ PalBool multiDescriptorSetTest() submitInfo.fence = fence; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // wait for the fence result = palWaitFence(fence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -632,10 +528,9 @@ PalBool multiDescriptorSetTest() // now our staging buffer has the contents of the GPU buffer // we map it and copy the contents to a ppm buffer and save it void* ptr = nullptr; - result = palMapBufferMemory(stagingBuffers[i], 0, bufferBytes, &ptr); + result = palMapBuffer(stagingBuffers[i], 0, bufferBytes, &ptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } @@ -657,7 +552,7 @@ PalBool multiDescriptorSetTest() } fclose(file); - palUnmapBufferMemory(stagingBuffers[i]); + palUnmapBuffer(stagingBuffers[i]); } palDestroyPipeline(pipeline); @@ -670,10 +565,7 @@ PalBool multiDescriptorSetTest() for (int i = 0; i < 3; i++) { palDestroyBuffer(buffers[i]); - palFreeMemory(device, bufferMemories[i]); - palDestroyBuffer(stagingBuffers[i]); - palFreeMemory(device, stagingBufferMemories[i]); } palDestroyFence(fence); diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index c800c475..6fe95b9f 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -3,6 +3,7 @@ #include "tests.h" #define BUFFER_SIZE 400 +#define max(a, b) (a > b) ? a : b typedef struct { float color[3]; // closest hit and miss color @@ -17,13 +18,6 @@ static void PAL_CALL onGraphicsDebug( palLog(nullptr, msg); } -static inline uint32_t _max( - uint32_t a, - uint32_t b) -{ - return (a > b) ? a : b; -} - PalBool rayTracingTest() { PalAdapter* adapter = nullptr; @@ -42,14 +36,6 @@ PalBool rayTracingTest() PalBuffer* tlasBuffer = nullptr; PalBuffer* scratchBuffer = nullptr; - PalMemory* bufferMemory = nullptr; - PalMemory* stagingBufferMemory = nullptr; - PalMemory* vertexBufferMemory = nullptr; - PalMemory* instanceBufferMemory = nullptr; - PalMemory* blasBufferMemory = nullptr; - PalMemory* tlasBufferMemory = nullptr; - PalMemory* scratchBufferMemory = nullptr; - PalDescriptorSetLayout* descriptorSetLayout = nullptr; PalDescriptorPool* descriptorPool = nullptr; PalDescriptorSet* descriptorSet = nullptr; @@ -65,10 +51,9 @@ PalBool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -76,8 +61,7 @@ PalBool rayTracingTest() int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -96,8 +80,7 @@ PalBool rayTracingTest() result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -108,8 +91,7 @@ PalBool rayTracingTest() adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -134,8 +116,7 @@ PalBool rayTracingTest() // We want an adapter that supports spirv 1.4 or dxil 6.3 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + logResult(result, "Failed to get adapter info"); return PAL_FALSE; } @@ -170,23 +151,20 @@ PalBool rayTracingTest() features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); return PAL_FALSE; } // create a graphics command queue result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); + logResult(result, "Failed to create queue"); return PAL_FALSE; } result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); + logResult(result, "Failed to create command pool"); return PAL_FALSE; } @@ -197,8 +175,7 @@ PalBool rayTracingTest() &cmdBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); + logResult(result, "Failed to allocate command buffer"); return PAL_FALSE; } @@ -249,8 +226,7 @@ PalBool rayTracingTest() result = palCreateShader(device, &shaderCreateInfo, &rayTracingShader); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create shader: %s", error); + logResult(result, "Failed to create shader"); return PAL_FALSE; } @@ -260,83 +236,21 @@ PalBool rayTracingTest() PalBufferCreateInfo bufferCreateInfo = {0}; bufferCreateInfo.size = bufferBytes; bufferCreateInfo.usages = PAL_BUFFER_USAGE_STORAGE | PAL_BUFFER_USAGE_TRANSFER_SRC; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; result = palCreateBuffer(device, &bufferCreateInfo, &buffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create buffer: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } bufferCreateInfo.size = bufferBytes; bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_DST; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK; result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create staging buffer: %s", error); - return PAL_FALSE; - } - - // get buffer memory requirement and allocate memory - PalMemoryRequirements bufferMemReq = {0}; - PalMemoryRequirements stagingBufferMemReq = {0}; - - result = palGetBufferMemoryRequirements(buffer, &bufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - // we need to check if the memory type we want are supported - // but almost every GPU supports a GPU only memory - // and CPU writable memory - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - bufferMemReq.memoryMask, - bufferMemReq.size, - &bufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_READBACK, - stagingBufferMemReq.memoryMask, - stagingBufferMemReq.size, - &stagingBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - // bind memory - result = palBindBufferMemory(buffer, bufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } @@ -349,56 +263,24 @@ PalBool rayTracingTest() bufferCreateInfo.size = sizeof(vertices); bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create vertex buffer: %s", error); - return PAL_FALSE; - } - - // we dont create a staging buffer to copy the vertices - // since we just need the buffer to create the acceleration structure - // its still recommended to create a staging buffer so the vertex buffer - // is GPU memory only - result = palGetBufferMemoryRequirements(vertexBuffer, &bufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - bufferMemReq.memoryMask, - bufferMemReq.size, - &vertexBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } // copy vertices void* data = nullptr; - result = palMapBufferMemory(vertexBuffer, 0, sizeof(vertices), &data); + result = palMapBuffer(vertexBuffer, 0, sizeof(vertices), &data); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } memcpy(data, vertices, sizeof(vertices)); - palUnmapBufferMemory(vertexBuffer); + palUnmapBuffer(vertexBuffer); // fill BLAS and triangle geometry PalDeviceAddress vertexBufferAddress = palGetBufferDeviceAddress(vertexBuffer); @@ -415,7 +297,7 @@ PalBool rayTracingTest() PalAccelerationStructureBuildInfo blasBuildInfo = {0}; blasBuildInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; - blasBuildInfo.geometryCount = 1; + blasBuildInfo.count = 1; blasBuildInfo.geometries = &geometry; blasBuildInfo.buildHints = PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD; blasBuildInfo.buildMode = PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD; @@ -424,8 +306,7 @@ PalBool rayTracingTest() PalAccelerationStructureBuildSize buildSizes = {0}; result = palGetAccelerationStructureBuildSize(device, &blasBuildInfo, &buildSizes); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get blas build sizes: %s", error); + logResult(result, "Failed to get accleration structure build size"); return PAL_FALSE; } @@ -433,38 +314,11 @@ PalBool rayTracingTest() bufferCreateInfo.size = buildSizes.accelerationStructureSize; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; result = palCreateBuffer(device, &bufferCreateInfo, &blasBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create blas buffer: %s", error); - return PAL_FALSE; - } - - result = palGetBufferMemoryRequirements(blasBuffer, &bufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - bufferMemReq.memoryMask, - bufferMemReq.size, - &blasBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(blasBuffer, blasBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } @@ -475,8 +329,7 @@ PalBool rayTracingTest() result = palCreateAccelerationstructure(device, &asCreateInfo, &blas); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create blas: %s", error); + logResult(result, "Failed to create acceleration structure"); return PAL_FALSE; } @@ -501,78 +354,48 @@ PalBool rayTracingTest() &instanceBufferSize); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to compute instance buffer requirement: %s", error); + logResult(result, "Failed to compute buffer requirement"); return PAL_FALSE; } bufferCreateInfo.size = instanceBufferSize; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; result = palCreateBuffer(device, &bufferCreateInfo, &instanceBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create instance buffer: %s", error); - return PAL_FALSE; - } - - result = palGetBufferMemoryRequirements(instanceBuffer, &bufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - bufferMemReq.memoryMask, - bufferMemReq.size, - &instanceBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(instanceBuffer, instanceBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } // copy instance struct to the buffer data = nullptr; - result = palMapBufferMemory( + result = palMapBuffer( instanceBuffer, 0, instanceBufferSize, &data); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } // we can not use a direct memcpy for instance buffers result = palWriteToInstanceBuffer(device, data, &asInstance, 1); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to write instances to instance buffer: %s", error); + logResult(result, "Failed to write to buffer"); return PAL_FALSE; } - palUnmapBufferMemory(instanceBuffer); + palUnmapBuffer(instanceBuffer); // fill TLAS and instance geometry PalDeviceAddress instanceBufferAddress = palGetBufferDeviceAddress(instanceBuffer); PalAccelerationStructureBuildInfo tlasBuildInfo = {0}; tlasBuildInfo.type = PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; - tlasBuildInfo.instanceCount = 1; + tlasBuildInfo.count = 1; tlasBuildInfo.instanceBufferAddress = instanceBufferAddress; tlasBuildInfo.buildHints = PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD; tlasBuildInfo.buildMode = PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD; @@ -581,8 +404,7 @@ PalBool rayTracingTest() uint32_t blasScratchSize = buildSizes.scratchBufferSize; result = palGetAccelerationStructureBuildSize(device, &tlasBuildInfo, &buildSizes); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get tlas build sizes: %s", error); + logResult(result, "Failed to get accleration structure build size"); return PAL_FALSE; } @@ -590,38 +412,11 @@ PalBool rayTracingTest() bufferCreateInfo.size = buildSizes.accelerationStructureSize; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; result = palCreateBuffer(device, &bufferCreateInfo, &tlasBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create tlas buffer: %s", error); - return PAL_FALSE; - } - - result = palGetBufferMemoryRequirements(tlasBuffer, &bufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - bufferMemReq.memoryMask, - bufferMemReq.size, - &tlasBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(tlasBuffer, tlasBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } @@ -631,47 +426,19 @@ PalBool rayTracingTest() result = palCreateAccelerationstructure(device, &asCreateInfo, &tlas); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create tlas: %s", error); + logResult(result, "Failed to create acceleration structure"); return PAL_FALSE; } // create scratch buffer - bufferCreateInfo.size = _max(buildSizes.scratchBufferSize, blasScratchSize); + bufferCreateInfo.size = max(buildSizes.scratchBufferSize, blasScratchSize); bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; result = palCreateBuffer(device, &bufferCreateInfo, &scratchBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create scratch buffer: %s", error); - return PAL_FALSE; - } - - result = palGetBufferMemoryRequirements(scratchBuffer, &bufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - bufferMemReq.memoryMask, - bufferMemReq.size, - &scratchBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(scratchBuffer, scratchBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } @@ -687,18 +454,13 @@ PalBool rayTracingTest() descriptorSetLayoutcreateInfo.bindingCount = 2; descriptorSetLayoutcreateInfo.bindings = descriptorBindings; - PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_RAYGEN }; - descriptorSetLayoutcreateInfo.shaderStageCount = 1; - descriptorSetLayoutcreateInfo.shaderStages = shaderStages; - result = palCreateDescriptorSetLayout( device, &descriptorSetLayoutcreateInfo, &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor set layout: %s", error); + logResult(result, "Failed to create descriptor set layout"); return PAL_FALSE; } @@ -712,13 +474,12 @@ PalBool rayTracingTest() PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set - descriptorPoolCreateInfo.maxDescriptorBindingSizes = 2; // two binding type + descriptorPoolCreateInfo.bindingSizeCount = 2; // two binding type descriptorPoolCreateInfo.bindingSizes = bindingSizes; result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor pool: %s", error); + logResult(result, "Failed to create descriptor pool"); return PAL_FALSE; } @@ -726,8 +487,7 @@ PalBool rayTracingTest() // using the layout we created above result = palAllocateDescriptorSet(device, descriptorPool, descriptorSetLayout, &descriptorSet); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate descriptor set: %s", error); + logResult(result, "Failed to allocate descriptor set"); return PAL_FALSE; } @@ -761,8 +521,7 @@ PalBool rayTracingTest() result = palUpdateDescriptorSet(device, 2, writeInfos); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to update descriptor set: %s", error); + logResult(result, "Failed to update descriptor set"); return PAL_FALSE; } @@ -773,8 +532,7 @@ PalBool rayTracingTest() result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); + logResult(result, "Failed to create pipeline layout"); return PAL_FALSE; } @@ -823,8 +581,7 @@ PalBool rayTracingTest() result = palCreateRayTracingPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create ray tracing pipeline: %s", error); + logResult(result, "Failed to create pipeline"); return PAL_FALSE; } @@ -866,38 +623,33 @@ PalBool rayTracingTest() result = palCreateShaderBindingTable(device, &sbtCreateInfo, &sbt); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create shader binding table: %s", error); + logResult(result, "Failed to create shader binding table"); return PAL_FALSE; } // create fence result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } // record commands result = palCmdBegin(cmdBuffer, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); + logResult(result, "Failed to bind pipeline"); return PAL_FALSE; } result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind descriptor set: %s", error); + logResult(result, "Failed to bind descriptor set"); return PAL_FALSE; } @@ -911,75 +663,57 @@ PalBool rayTracingTest() result = palCmdBuildAccelerationStructure(cmdBuffer, &blasBuildInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to build blas: %s", error); + logResult(result, "Failed to build acceleration structure"); return PAL_FALSE; } // make sure the BLAS builds before the TLAS. We need this barrier because // BLAS and TLAS share the same scratch buffer - PalUsageStateInfo oldAsUsageStateInfo = {0}; - oldAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; - - PalUsageStateInfo newAsUsageStateInfo = {0}; - newAsUsageStateInfo.usageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; + PalUsageState oldAsUsageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; + PalUsageState newAsUsageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; result = palCmdAccelerationStructureBarrier( cmdBuffer, blas, - &oldAsUsageStateInfo, - &newAsUsageStateInfo); + oldAsUsageState, + newAsUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set memory barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdBuildAccelerationStructure(cmdBuffer, &tlasBuildInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to build tlas: %s", error); + logResult(result, "Failed to build acceleration structure"); return PAL_FALSE; } - newAsUsageStateInfo.shaderStageCount = 1; - newAsUsageStateInfo.shaderStages = shaderStages; - // make sure the TLAS builds before the tracing result = palCmdAccelerationStructureBarrier( cmdBuffer, tlas, - &oldAsUsageStateInfo, - &newAsUsageStateInfo); + oldAsUsageState, + newAsUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set memory barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to trace rays: %s", error); + logResult(result, "Failed to issue trace command"); return PAL_FALSE; } // set a barrier so we only read from the buffer after the shader has written to it - PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.shaderStageCount = 0; - oldUsageStateInfo.shaderStages = nullptr; + PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; + PalUsageState newUsageState = PAL_USAGE_STATE_TRANSFER_READ; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStageCount = 0; - newUsageStateInfo.shaderStages = nullptr; - newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; - - result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -989,15 +723,13 @@ PalBool rayTracingTest() result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -1007,26 +739,23 @@ PalBool rayTracingTest() submitInfo.fence = fence; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // wait for the fence result = palWaitFence(fence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } // now our staging buffer has the contents of the GPU buffer // we map it and copy the contents to a ppm buffer and save it void* ptr = nullptr; - result = palMapBufferMemory(stagingBuffer, 0, bufferBytes, &ptr); + result = palMapBuffer(stagingBuffer, 0, bufferBytes, &ptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } @@ -1068,8 +797,7 @@ PalBool rayTracingTest() // update records result = palUpdateShaderBindingTable(sbt, 2, updateRecords); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to update shader binding table: %s", error); + logResult(result, "Failed to update shader binding table"); return PAL_FALSE; } @@ -1080,68 +808,54 @@ PalBool rayTracingTest() result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } // record commands result = palCmdBegin(cmdBuffer, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } result = palCmdBindPipeline(cmdBuffer, pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); + logResult(result, "Failed to bind pipeline"); return PAL_FALSE; } result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind descriptor set: %s", error); + logResult(result, "Failed to bind descriptor set"); return PAL_FALSE; } // the previous trace transitioned the buffer to transfer read // we need it back to shader write before transfer read - oldUsageStateInfo.shaderStageCount = 0; - oldUsageStateInfo.shaderStages = nullptr; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; - - newUsageStateInfo.shaderStageCount = 1; - newUsageStateInfo.shaderStages = shaderStages; - newUsageStateInfo.usageState = PAL_USAGE_STATE_SHADER_WRITE; + oldUsageState = PAL_USAGE_STATE_TRANSFER_READ; + newUsageState = PAL_USAGE_STATE_SHADER_WRITE; - result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to trace rays: %s", error); + logResult(result, "Failed to issue trace command"); return PAL_FALSE; } // set a barrier to transition to transfer read so we can read from it after shader has // written to it - oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.shaderStageCount = 0; - newUsageStateInfo.shaderStages = nullptr; - newUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_READ; + oldUsageState = newUsageState; + newUsageState = PAL_USAGE_STATE_TRANSFER_READ; - result = palCmdBufferBarrier(cmdBuffer, buffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -1149,15 +863,13 @@ PalBool rayTracingTest() copyInfo.size = bufferBytes; result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -1166,16 +878,14 @@ PalBool rayTracingTest() submitInfo.fence = fence; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // wait for the fence result = palWaitFence(fence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -1197,7 +907,7 @@ PalBool rayTracingTest() } fclose(file); - palUnmapBufferMemory(stagingBuffer); + palUnmapBuffer(stagingBuffer); palDestroyAccelerationstructure(blas); palDestroyAccelerationstructure(tlas); @@ -1217,14 +927,6 @@ PalBool rayTracingTest() palDestroyBuffer(tlasBuffer); palDestroyBuffer(scratchBuffer); - palFreeMemory(device, bufferMemory); - palFreeMemory(device, stagingBufferMemory); - palFreeMemory(device, vertexBufferMemory); - palFreeMemory(device, instanceBufferMemory); - palFreeMemory(device, blasBufferMemory); - palFreeMemory(device, tlasBufferMemory); - palFreeMemory(device, scratchBufferMemory); - palFreeCommandBuffer(cmdBuffer); palDestroyCommandPool(cmdPool); palDestroyQueue(queue); diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 60aabe68..c80dd693 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -52,7 +52,6 @@ PalBool textureTest() PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; - PalGraphicsWindow gfxWindow; PalAdapter* adapter = nullptr; PalDevice* device = nullptr; @@ -74,8 +73,6 @@ PalBool textureTest() PalBuffer* vertexBuffer = nullptr; PalBuffer* stagingBuffer = nullptr; - PalMemory* vertexBufferMemory = nullptr; - PalMemory* stagingBufferMemory = nullptr; PalDescriptorSetLayout* descriptorSetLayout = nullptr; PalDescriptorPool* descriptorPool = nullptr; @@ -88,8 +85,8 @@ PalBool textureTest() return PAL_FALSE; } - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { @@ -114,40 +111,43 @@ PalBool textureTest() return PAL_FALSE; } - PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); - gfxWindow.display = winHandle.nativeDisplay; - gfxWindow.window = winHandle.nativeWindow; + // get window handle. You can use any window from any library + // so long as you can get the window handle and display (if on X11, wayland) + // If pal video system will not be used, there is no need to initialize it + PalWindowHandleInfo winHandle = {0}; + result = palGetWindowHandleInfo(window, &winHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } - // using pal_system.h will be easy to know the underlying windowing API - // or use typedefs. We will use the pal_system module. This is needed - // for systems which multiple windowing APIs (linux). + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; result = palGetPlatformInfo(&platformInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get platform information: %s", error); + logResult(result, "Failed to get platform information"); return PAL_FALSE; } - if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; + if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WAYLAND; - } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_X11) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_X11; - } else { - // automatically this is xcb - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WIN32) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WIN32; } PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -155,8 +155,7 @@ PalBool textureTest() int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -175,8 +174,7 @@ PalBool textureTest() result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -186,8 +184,7 @@ PalBool textureTest() adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -200,8 +197,7 @@ PalBool textureTest() // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + logResult(result, "Failed to get adapter info"); return PAL_FALSE; } @@ -240,16 +236,20 @@ PalBool textureTest() result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); return PAL_FALSE; } // create surface - result = palCreateSurface(device, &gfxWindow, &surface); + result = palCreateSurface( + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, + &surface); + if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create surface: %s", error); + logResult(result, "Failed to create surface"); return PAL_FALSE; } @@ -258,8 +258,7 @@ PalBool textureTest() for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); + logResult(result, "Failed to create queue"); return PAL_FALSE; } @@ -282,8 +281,7 @@ PalBool textureTest() PalSurfaceCapabilities surfaceCaps = {0}; result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get surface capabilities: %s", error); + logResult(result, "Failed to get surface capabilities"); return PAL_FALSE; } @@ -318,8 +316,7 @@ PalBool textureTest() result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create swapchain: %s", error); + logResult(result, "Failed to create swapchain"); return PAL_FALSE; } @@ -336,8 +333,7 @@ PalBool textureTest() PalImageInfo imageInfo; result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); + logResult(result, "Failed to get image info"); return PAL_FALSE; } @@ -359,16 +355,14 @@ PalBool textureTest() result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); + logResult(result, "Failed to create image view"); return PAL_FALSE; } // create render finished semaphores result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } @@ -377,8 +371,7 @@ PalBool textureTest() result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); + logResult(result, "Failed to create command pool"); return PAL_FALSE; } @@ -386,15 +379,13 @@ PalBool textureTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } @@ -405,8 +396,7 @@ PalBool textureTest() &cmdBuffers[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); + logResult(result, "Failed to allocate command buffer"); return PAL_FALSE; } } @@ -427,100 +417,37 @@ PalBool textureTest() bufferCreateInfo.size = sizeof(vertices); bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create vertex buffer: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create staging buffer: %s", error); - return PAL_FALSE; - } - - // get buffer memory requirement and allocate memory - PalMemoryRequirements vertexBufferMemReq = {0}; - PalMemoryRequirements stagingBufferMemReq = {0}; - - result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - // we need to check if the memory type we want are supported - // but almost every GPU supports a GPU only memory - // and CPU writable memory - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - vertexBufferMemReq.memoryMask, - vertexBufferMemReq.size, - &vertexBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - stagingBufferMemReq.memoryMask, - stagingBufferMemReq.size, - &stagingBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - // bind memory - result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } // map the staging buffer and upload the vertices void* ptr = nullptr; - result = palMapBufferMemory(stagingBuffer, 0, sizeof(vertices), &ptr); + result = palMapBuffer(stagingBuffer, 0, sizeof(vertices), &ptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } memcpy(ptr, vertices, sizeof(vertices)); - palUnmapBufferMemory(stagingBuffer); + palUnmapBuffer(stagingBuffer); PalFence* fence = nullptr; result = palCreateFence(device, PAL_FALSE, &fence); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } @@ -533,7 +460,8 @@ PalBool textureTest() // create image for the texture PalImage* checkerboard = nullptr; PalImageCreateInfo imageCreateInfo = {0}; - imageCreateInfo.depthOrArraySize = 1; + imageCreateInfo.arrayLayerCount = 1; + imageCreateInfo.depth = 1; imageCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; imageCreateInfo.mipLevelCount = 1; // simple imageCreateInfo.sampleCount = PAL_SAMPLE_COUNT_1; // simple @@ -541,41 +469,11 @@ PalBool textureTest() imageCreateInfo.usages = PAL_IMAGE_USAGE_TRANSFER_DST | PAL_IMAGE_USAGE_SAMPLED; imageCreateInfo.width = TEXTURE_WIDTH; imageCreateInfo.height = TEXTURE_HEIGHT; + imageCreateInfo.memoryUsage = PAL_IMAGE_MEMORY_USAGE_AUTO_GPU_ONLY; result = palCreateImage(device, &imageCreateInfo, &checkerboard); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image: %s", error); - return PAL_FALSE; - } - - // allocate memory for the image - PalMemoryRequirements imageMemReq = {0}; - result = palGetImageMemoryRequirements(checkerboard, &imageMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image memory requirement: %s", error); - return PAL_FALSE; - } - - PalMemory* checkerboardMemory = nullptr; - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - imageMemReq.memoryMask, - imageMemReq.size, - &checkerboardMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory: %s", error); - return PAL_FALSE; - } - - result = palBindImageMemory(checkerboard, checkerboardMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind image memory: %s", error); + logResult(result, "Failed to create image"); return PAL_FALSE; } @@ -599,8 +497,7 @@ PalBool textureTest() &imageCopyStagingBufferSize); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to compute image copy staging buffer info: %s", error); + logResult(result, "Failed to compute buffer info"); return PAL_FALSE; } @@ -613,54 +510,24 @@ PalBool textureTest() PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; imageStagingBufferCreateInfo.size = imageCopyStagingBufferSize; imageStagingBufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; result = palCreateBuffer(device, &imageStagingBufferCreateInfo, &imageStagingBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image staging buffer: %s", error); - return PAL_FALSE; - } - - PalMemoryRequirements imageStagingBufferMemReq = {0}; - result = palGetBufferMemoryRequirements(imageStagingBuffer, &imageStagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image staging buffer memory requirement: %s", error); - return PAL_FALSE; - } - - PalMemory* imageStagingBufferMemory = nullptr; - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - imageStagingBufferMemReq.memoryMask, - imageStagingBufferMemReq.size, - &imageStagingBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(imageStagingBuffer, imageStagingBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind image staging buffer memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } // copy data void* data = nullptr; - result = palMapBufferMemory( + result = palMapBuffer( imageStagingBuffer, 0, imageStagingBufferCreateInfo.size, &data); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } @@ -673,12 +540,11 @@ PalBool textureTest() &bufferImageCopyInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to write to image copy staging buffer: %s", error); + logResult(result, "Failed to write to buffer"); return PAL_FALSE; } - palUnmapBufferMemory(imageStagingBuffer); + palUnmapBuffer(imageStagingBuffer); // use the first command buffer to upload the copy // and reset it when done @@ -686,8 +552,7 @@ PalBool textureTest() // to see if we have to wait for the copy to be executed result = palCmdBegin(cmdBuffers[0], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } @@ -696,32 +561,23 @@ PalBool textureTest() result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } - PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; - PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; + PalUsageState newUsageState = PAL_USAGE_STATE_VERTEX_READ; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStageCount = 1; - newUsageStateInfo.shaderStages = vertexShaderStage; - newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; - - result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } // copy image staging buffer to the checkerboard image // first the image must be in the correct layout - PalUsageStateInfo oldImageUsageState = {0}; - PalUsageStateInfo newImageUsageState = {0}; - newImageUsageState.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + PalUsageState oldImageUsageState = PAL_USAGE_STATE_UNDEFINED; + PalUsageState newImageUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; // set a barrier on the image to transition it into transfer dst state PalImageSubresourceRange checkerboardRange = {0}; @@ -738,8 +594,7 @@ PalBool textureTest() &newImageUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -750,18 +605,12 @@ PalBool textureTest() &bufferImageCopyInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer to image: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } - // we should transition the image into a shader read state so we dont do that - // in the main loop - PalShaderStage fragmentShaderStage[] = { PAL_SHADER_STAGE_FRAGMENT }; oldImageUsageState = newImageUsageState; - newImageUsageState.usageState = PAL_USAGE_STATE_SHADER_READ; - newImageUsageState.shaderStageCount = 1; - newImageUsageState.shaderStages = fragmentShaderStage; // fragment shader will read + newImageUsageState = PAL_USAGE_STATE_SHADER_READ; result = palCmdImageBarrier( cmdBuffers[0], @@ -771,15 +620,13 @@ PalBool textureTest() &newImageUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -788,8 +635,7 @@ PalBool textureTest() submitInfo.fence = fence; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } @@ -808,8 +654,7 @@ PalBool textureTest() &checkerboardImageView); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create checkerboard image view: %s", error); + logResult(result, "Failed to create image view"); return PAL_FALSE; } @@ -833,8 +678,7 @@ PalBool textureTest() &sampler); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create sampler: %s", error); + logResult(result, "Failed to create sampler"); return PAL_FALSE; } @@ -893,8 +737,7 @@ PalBool textureTest() result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create shader: %s", error); + logResult(result, "Failed to create shader"); return PAL_FALSE; } @@ -913,18 +756,13 @@ PalBool textureTest() descriptorSetLayoutcreateInfo.bindingCount = 2; descriptorSetLayoutcreateInfo.bindings = descriptorBindings; - PalShaderStage shaderStages[] = { PAL_SHADER_STAGE_FRAGMENT }; - descriptorSetLayoutcreateInfo.shaderStageCount = 1; - descriptorSetLayoutcreateInfo.shaderStages = shaderStages; - result = palCreateDescriptorSetLayout( device, &descriptorSetLayoutcreateInfo, &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor set layout: %s", error); + logResult(result, "Failed to create descriptor set layout"); return PAL_FALSE; } @@ -938,13 +776,12 @@ PalBool textureTest() PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set - descriptorPoolCreateInfo.maxDescriptorBindingSizes = 2; + descriptorPoolCreateInfo.bindingSizeCount = 2; descriptorPoolCreateInfo.bindingSizes = storageBufferBindingsizes; result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create descriptor pool: %s", error); + logResult(result, "Failed to create descriptor pool"); return PAL_FALSE; } @@ -952,8 +789,7 @@ PalBool textureTest() // using the layout we created above result = palAllocateDescriptorSet(device, descriptorPool, descriptorSetLayout, &descriptorSet); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate descriptor set: %s", error); + logResult(result, "Failed to allocate descriptor set"); return PAL_FALSE; } @@ -989,8 +825,7 @@ PalBool textureTest() result = palUpdateDescriptorSet(device, 2, writeInfos); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to update descriptor set: %s", error); + logResult(result, "Failed to update descriptor set"); return PAL_FALSE; } @@ -1001,15 +836,14 @@ PalBool textureTest() result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); + logResult(result, "Failed to create pipeline layout"); return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; renderingLayoutInfo.colorAttachentCount = 1; renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; - renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.sampleCount = PAL_SAMPLE_COUNT_1; renderingLayoutInfo.viewCount = 1; // create graphics pipeline @@ -1019,12 +853,10 @@ PalBool textureTest() // position vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; - vertexAttributes[0].semanticName = nullptr; // use default vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; // texture coordinates vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_TEXCOORD; - vertexAttributes[1].semanticName = nullptr; // use default vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT2; vertexLayout.attributeCount = 2; @@ -1055,8 +887,7 @@ PalBool textureTest() result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create graphics pipeline: %s", error); + logResult(result, "Failed to create pipeline"); return PAL_FALSE; } @@ -1067,19 +898,14 @@ PalBool textureTest() // wait for the vertices copy to be done result = palWaitFence(fence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } // the vertices have been copied palDestroyFence(fence); palDestroyBuffer(stagingBuffer); - palFreeMemory(device, stagingBufferMemory); - - // we can destroy the image staging buffer palDestroyBuffer(imageStagingBuffer); - palFreeMemory(device, imageStagingBufferMemory); // main loop uint32_t currentFrame = 0; @@ -1096,12 +922,12 @@ PalBool textureTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -1114,8 +940,7 @@ PalBool textureTest() result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -1128,16 +953,14 @@ PalBool textureTest() uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); + logResult(result, "Failed to get next swapchain image"); return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -1146,8 +969,7 @@ PalBool textureTest() if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -1157,8 +979,7 @@ PalBool textureTest() result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -1166,22 +987,19 @@ PalBool textureTest() // reset the command buffer result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to reset command buffer: %s", error); + logResult(result, "Failed to reset command buffer"); return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } // change the state of the image view to make it renderable - PalUsageStateInfo oldUsageStateInfo = {0}; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; + PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -1194,12 +1012,11 @@ PalBool textureTest() cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -1222,38 +1039,33 @@ PalBool textureTest() result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin rendering: %s", error); + logResult(result, "Failed to begin rendering"); return PAL_FALSE; } // bind pipeline result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); + logResult(result, "Failed to bind pipeline"); return PAL_FALSE; } result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind descriptor set: %s", error); + logResult(result, "Failed to bind descriptor set"); return PAL_FALSE; } // set viewport and scissors result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set viewport: %s", error); + logResult(result, "Failed to set viewport"); return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set scissors: %s", error); + logResult(result, "Failed to set scissor"); return PAL_FALSE; } @@ -1267,45 +1079,40 @@ PalBool textureTest() offset); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind vertex buffer: %s", error); + logResult(result, "Failed to bind vertex buffer"); return PAL_FALSE; } result = palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to issue draw command: %s", error); + logResult(result, "Failed to issue draw command"); return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end rendering: %s", error); + logResult(result, "Failed to end rendering"); return PAL_FALSE; } // change the state of the image view to make it presentable - oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + oldUsageState = newUsageState; + newUsageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -1318,19 +1125,14 @@ PalBool textureTest() result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // present - PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; - result = palPresentSwapchain(swapchain, &presentInfo); + result = palPresentSwapchain(swapchain, imageIndex, renderFinishedSemaphores[imageIndex]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to present swapchain: %s", error); + logResult(result, "Failed to present swapchain"); return PAL_FALSE; } @@ -1339,8 +1141,7 @@ PalBool textureTest() result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for queue: %s", error); + logResult(result, "Failed to wait queue"); return PAL_FALSE; } @@ -1364,10 +1165,7 @@ PalBool textureTest() palDestroySampler(sampler); palDestroyImageView(checkerboardImageView); palDestroyImage(checkerboard); - palFreeMemory(device, checkerboardMemory); - palDestroyBuffer(vertexBuffer); - palFreeMemory(device, vertexBufferMemory); palDestroyCommandPool(cmdPool); palDestroySwapchain(swapchain); diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index dcb4598b..2e68e09c 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -22,7 +22,6 @@ PalBool triangleTest() PalResult result; PalWindow* window = nullptr; PalEventDriver* eventDriver = nullptr; - PalGraphicsWindow gfxWindow; PalAdapter* adapter = nullptr; PalDevice* device = nullptr; @@ -44,8 +43,6 @@ PalBool triangleTest() PalBuffer* vertexBuffer = nullptr; PalBuffer* stagingBuffer = nullptr; - PalMemory* vertexBufferMemory = nullptr; - PalMemory* stagingBufferMemory = nullptr; PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); @@ -54,8 +51,8 @@ PalBool triangleTest() return PAL_FALSE; } - palSetEventDispatchMode(eventDriver, PAL_EVENT_WINDOW_CLOSE, PAL_DISPATCH_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_KEYDOWN, PAL_DISPATCH_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); result = palInitVideo(nullptr, eventDriver, nullptr); if (result != PAL_RESULT_SUCCESS) { @@ -80,40 +77,43 @@ PalBool triangleTest() return PAL_FALSE; } - PalWindowHandleInfo winHandle = palGetWindowHandleInfo(window); - gfxWindow.display = winHandle.nativeDisplay; - gfxWindow.window = winHandle.nativeWindow; - - // using pal_system.h will be easy to know the underlying windowing API - // or use typedefs. We will use the pal_system module. This is needed - // for systems which multiple windowing APIs (linux). + // get window handle. You can use any window from any library + // so long as you can get the window handle and display (if on X11, wayland) + // If pal video system will not be used, there is no need to initialize it + PalWindowHandleInfo winHandle = {0}; + result = palGetWindowHandleInfo(window, &winHandle); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get window handle info"); + return PAL_FALSE; + } + + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; result = palGetPlatformInfo(&platformInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get platform information: %s", error); + logResult(result, "Failed to get platform information"); return PAL_FALSE; } - if (platformInfo.apiType == PAL_PLATFORM_API_WAYLAND) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_WAYLAND; + PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; + if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WAYLAND; - } else if (platformInfo.apiType == PAL_PLATFORM_API_X11) { - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_X11; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_X11) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_X11; - } else { - // automatically this is xcb - gfxWindow.displayType = PAL_GRAPHICS_WINDOW_DISPLAY_TYPE_XCB; + } else if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WIN32) { + windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_WIN32; } PalGraphicsDebugger debugger = {0}; debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - result = palInitGraphics(nullptr, nullptr); + result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to initialize graphics: %s", error); + logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } @@ -121,8 +121,7 @@ PalBool triangleTest() int32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -141,8 +140,7 @@ PalBool triangleTest() result = palEnumerateAdapters(&adapterCount, adapters); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get query adapters: %s", error); + logResult(result, "Failed to get adapters"); return PAL_FALSE; } @@ -152,8 +150,7 @@ PalBool triangleTest() adapter = adapters[i]; result = palGetAdapterCapabilities(adapter, &caps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter capabilities: %s", error); + logResult(result, "Failed to get adapter capabilities"); palFree(nullptr, adapters); return PAL_FALSE; } @@ -166,8 +163,7 @@ PalBool triangleTest() // We want an adapter that supports spirv 1.0 or dxil 6.0 result = palGetAdapterInfo(adapter, &adapterInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get adapter info: %s", error); + logResult(result, "Failed to get adapter info"); return PAL_FALSE; } @@ -206,16 +202,20 @@ PalBool triangleTest() result = palCreateDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create device: %s", error); + logResult(result, "Failed to create device"); return PAL_FALSE; } // create surface - result = palCreateSurface(device, &gfxWindow, &surface); + result = palCreateSurface( + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, + &surface); + if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create surface: %s", error); + logResult(result, "Failed to create surface"); return PAL_FALSE; } @@ -224,8 +224,7 @@ PalBool triangleTest() for (int i = 0; i < caps.maxGraphicsQueues; i++) { result = palCreateQueue(device, PAL_QUEUE_TYPE_GRAPHICS, &queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create queue: %s", error); + logResult(result, "Failed to create queue"); return PAL_FALSE; } @@ -248,8 +247,7 @@ PalBool triangleTest() PalSurfaceCapabilities surfaceCaps = {0}; result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get surface capabilities: %s", error); + logResult(result, "Failed to get surface capabilities"); return PAL_FALSE; } @@ -284,8 +282,7 @@ PalBool triangleTest() result = palCreateSwapchain(device, queue, surface, &swapchainCreateInfo, &swapchain); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create swapchain: %s", error); + logResult(result, "Failed to create swapchain"); return PAL_FALSE; } @@ -302,8 +299,7 @@ PalBool triangleTest() PalImageInfo imageInfo; result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get image info: %s", error); + logResult(result, "Failed to get image info"); return PAL_FALSE; } @@ -325,16 +321,14 @@ PalBool triangleTest() result = palCreateImageView(device, image, &imageViewCreateInfo, &imageViews[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create image view: %s", error); + logResult(result, "Failed to create image view"); return PAL_FALSE; } // create render finished semaphores result = palCreateSemaphore(device, PAL_FALSE, &renderFinishedSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } @@ -343,8 +337,7 @@ PalBool triangleTest() result = palCreateCommandPool(device, queue, &cmdPool); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create command pool: %s", error); + logResult(result, "Failed to create command pool"); return PAL_FALSE; } @@ -352,15 +345,13 @@ PalBool triangleTest() for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { result = palCreateSemaphore(device, PAL_FALSE, &imageAvailableSemaphores[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create semaphore: %s", error); + logResult(result, "Failed to create semaphore"); return PAL_FALSE; } result = palCreateFence(device, PAL_TRUE, &inFlightFences[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } @@ -371,8 +362,7 @@ PalBool triangleTest() &cmdBuffers[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate command buffer: %s", error); + logResult(result, "Failed to allocate command buffer"); return PAL_FALSE; } } @@ -390,100 +380,37 @@ PalBool triangleTest() bufferCreateInfo.size = sizeof(vertices); bufferCreateInfo.usages = PAL_BUFFER_USAGE_VERTEX; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_TRANSFER_DST; // will recieve + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; + result = palCreateBuffer(device, &bufferCreateInfo, &vertexBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create vertex buffer: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } bufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; // will send + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; result = palCreateBuffer(device, &bufferCreateInfo, &stagingBuffer); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create staging buffer: %s", error); - return PAL_FALSE; - } - - // get buffer memory requirement and allocate memory - PalMemoryRequirements vertexBufferMemReq = {0}; - PalMemoryRequirements stagingBufferMemReq = {0}; - - result = palGetBufferMemoryRequirements(vertexBuffer, &vertexBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - result = palGetBufferMemoryRequirements(stagingBuffer, &stagingBufferMemReq); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get buffer memory requirement: %s", error); - return PAL_FALSE; - } - - // we need to check if the memory type we want are supported - // but almost every GPU supports a GPU only memory - // and CPU writable memory - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_GPU_ONLY, - vertexBufferMemReq.memoryMask, - vertexBufferMemReq.size, - &vertexBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - result = palAllocateMemory( - device, - PAL_MEMORY_TYPE_CPU_UPLOAD, - stagingBufferMemReq.memoryMask, - stagingBufferMemReq.size, - &stagingBufferMemory); - - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to allocate memory for buffer: %s", error); - return PAL_FALSE; - } - - // bind memory - result = palBindBufferMemory(vertexBuffer, vertexBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); - return PAL_FALSE; - } - - result = palBindBufferMemory(stagingBuffer, stagingBufferMemory, 0); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind memory: %s", error); + logResult(result, "Failed to create buffer"); return PAL_FALSE; } // map the staging buffer and upload the vertices void* ptr = nullptr; - result = palMapBufferMemory(stagingBuffer, 0, sizeof(vertices), &ptr); + result = palMapBuffer(stagingBuffer, 0, sizeof(vertices), &ptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to map buffer memory: %s", error); + logResult(result, "Failed to map memory"); return PAL_FALSE; } memcpy(ptr, vertices, sizeof(vertices)); - palUnmapBufferMemory(stagingBuffer); + palUnmapBuffer(stagingBuffer); PalFence* tmpFence = nullptr; result = palCreateFence(device, PAL_FALSE, &tmpFence); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create fence: %s", error); + logResult(result, "Failed to create fence"); return PAL_FALSE; } @@ -493,8 +420,7 @@ PalBool triangleTest() // to see if we have to wait for the copy to be executed result = palCmdBegin(cmdBuffers[0], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } @@ -503,31 +429,22 @@ PalBool triangleTest() result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to copy buffer: %s", error); + logResult(result, "Failed to copy buffer"); return PAL_FALSE; } - PalShaderStage vertexShaderStage[] = { PAL_SHADER_STAGE_VERTEX }; - PalUsageStateInfo oldUsageStateInfo = {0}; - oldUsageStateInfo.usageState = PAL_USAGE_STATE_TRANSFER_WRITE; + PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; + PalUsageState newUsageState = PAL_USAGE_STATE_VERTEX_READ; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.shaderStageCount = 1; - newUsageStateInfo.shaderStages = vertexShaderStage; - newUsageStateInfo.usageState = PAL_USAGE_STATE_VERTEX_READ; - - result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageStateInfo, &newUsageStateInfo); + result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageState, &newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set buffer barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -536,8 +453,7 @@ PalBool triangleTest() submitInfo.fence = tmpFence; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } @@ -596,8 +512,7 @@ PalBool triangleTest() result = palCreateShader(device, &shaderCreateInfo, &shaders[i]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create shader: %s", error); + logResult(result, "Failed to create shader"); return PAL_FALSE; } @@ -608,15 +523,14 @@ PalBool triangleTest() PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create pipeline layout: %s", error); + logResult(result, "Failed to create pipeline layout"); return PAL_FALSE; } PalRenderingLayoutInfo renderingLayoutInfo = {0}; renderingLayoutInfo.colorAttachentCount = 1; renderingLayoutInfo.colorAttachmentsFormat = &imageInfo.format; - renderingLayoutInfo.multisampleCount = PAL_SAMPLE_COUNT_1; + renderingLayoutInfo.sampleCount = PAL_SAMPLE_COUNT_1; renderingLayoutInfo.viewCount = 1; // create graphics pipeline @@ -626,12 +540,10 @@ PalBool triangleTest() // position vertexAttributes[0].semanticID = PAL_VERTEX_SEMANTIC_ID_POSITION; - vertexAttributes[0].semanticName = nullptr; // use default vertexAttributes[0].type = PAL_VERTEX_TYPE_FLOAT2; // color vertexAttributes[1].semanticID = PAL_VERTEX_SEMANTIC_ID_COLOR; - vertexAttributes[1].semanticName = nullptr; // use default vertexAttributes[1].type = PAL_VERTEX_TYPE_FLOAT3; vertexLayout.attributeCount = 2; @@ -662,8 +574,7 @@ PalBool triangleTest() result = palCreateGraphicsPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to create graphics pipeline: %s", error); + logResult(result, "Failed to create pipeline"); return PAL_FALSE; } @@ -674,15 +585,13 @@ PalBool triangleTest() // wait for the vertices copy to be done result = palWaitFence(tmpFence, PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } // the vertices have been copied palDestroyFence(tmpFence); palDestroyBuffer(stagingBuffer); - palFreeMemory(device, stagingBufferMemory); // main loop uint32_t currentFrame = 0; @@ -699,12 +608,12 @@ PalBool triangleTest() PalEvent event; while (palPollEvent(eventDriver, &event)) { switch (event.type) { - case PAL_EVENT_WINDOW_CLOSE: { + case PAL_EVENT_TYPE_WINDOW_CLOSE: { running = PAL_FALSE; break; } - case PAL_EVENT_KEYDOWN: { + case PAL_EVENT_TYPE_KEYDOWN: { PalKeycode keycode = 0; palUnpackUint32(event.data, &keycode, nullptr); if (keycode == PAL_KEYCODE_ESCAPE) { @@ -717,8 +626,7 @@ PalBool triangleTest() result = palWaitFence(inFlightFences[currentFrame], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -731,16 +639,14 @@ PalBool triangleTest() uint32_t imageIndex = 0; result = palGetNextSwapchainImage(swapchain, &nextImageInfo, &imageIndex); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to get next swapchain image: %s", error); + logResult(result, "Failed to get next swapchain image"); return PAL_FALSE; } if (inFlightImages[imageIndex] != nullptr) { result = palWaitFence(inFlightImages[imageIndex], PAL_INFINITE); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -749,8 +655,7 @@ PalBool triangleTest() if (adapterFeatures & PAL_ADAPTER_FEATURE_FENCE_RESET) { result = palResetFence(inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } @@ -760,8 +665,7 @@ PalBool triangleTest() result = palCreateFence(device, PAL_FALSE, &inFlightFences[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait fence: %s", error); + logResult(result, "Failed to wait fence"); return PAL_FALSE; } } @@ -769,22 +673,19 @@ PalBool triangleTest() // reset the command buffer result = palResetCommandBuffer(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to reset command buffer: %s", error); + logResult(result, "Failed to reset command buffer"); return PAL_FALSE; } result = palCmdBegin(cmdBuffers[currentFrame], nullptr); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin command buffer: %s", error); + logResult(result, "Failed to begin command buffer"); return PAL_FALSE; } // change the state of the image view to make it renderable - PalUsageStateInfo oldUsageStateInfo = {0}; - PalUsageStateInfo newUsageStateInfo = {0}; - newUsageStateInfo.usageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; + PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -797,12 +698,11 @@ PalBool triangleTest() cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } @@ -825,31 +725,27 @@ PalBool triangleTest() result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to begin rendering: %s", error); + logResult(result, "Failed to begin rendering"); return PAL_FALSE; } // bind pipeline result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind pipeline: %s", error); + logResult(result, "Failed to bind pipeline"); return PAL_FALSE; } // set viewport and scissors result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set viewport: %s", error); + logResult(result, "Failed to set viewport"); return PAL_FALSE; } result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set scissors: %s", error); + logResult(result, "Failed to set scissor"); return PAL_FALSE; } @@ -863,45 +759,40 @@ PalBool triangleTest() offset); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to bind vertex buffer: %s", error); + logResult(result, "Failed to bind vertex buffer"); return PAL_FALSE; } result = palCmdDraw(cmdBuffers[currentFrame], 3, 1, 0, 0); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to issue draw command: %s", error); + logResult(result, "Failed to issue draw command"); return PAL_FALSE; } result = palCmdEndRendering(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end rendering: %s", error); + logResult(result, "Failed to end rendering"); return PAL_FALSE; } // change the state of the image view to make it presentable - oldUsageStateInfo = newUsageStateInfo; - newUsageStateInfo.usageState = PAL_USAGE_STATE_PRESENT; + oldUsageState = newUsageState; + newUsageState = PAL_USAGE_STATE_PRESENT; result = palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, - &oldUsageStateInfo, - &newUsageStateInfo); + oldUsageState, + newUsageState); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set image view barrier: %s", error); + logResult(result, "Failed to set barrier"); return PAL_FALSE; } result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to end command buffer: %s", error); + logResult(result, "Failed to end command buffer"); return PAL_FALSE; } @@ -914,19 +805,14 @@ PalBool triangleTest() result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to submit command buffer: %s", error); + logResult(result, "Failed to submit command buffer"); return PAL_FALSE; } // present - PalSwapchainPresentInfo presentInfo = {0}; - presentInfo.imageIndex = imageIndex; - presentInfo.waitSemaphore = renderFinishedSemaphores[imageIndex]; - result = palPresentSwapchain(swapchain, &presentInfo); + result = palPresentSwapchain(swapchain, imageIndex, renderFinishedSemaphores[imageIndex]); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to present swapchain: %s", error); + logResult(result, "Failed to present swapchain"); return PAL_FALSE; } @@ -935,8 +821,7 @@ PalBool triangleTest() result = palWaitQueue(queue); if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to wait for queue: %s", error); + logResult(result, "Failed to wait queue"); return PAL_FALSE; } @@ -955,8 +840,6 @@ PalBool triangleTest() } palDestroyBuffer(vertexBuffer); - palFreeMemory(device, vertexBufferMemory); - palDestroyCommandPool(cmdPool); palDestroySwapchain(swapchain); palDestroySurface(surface); diff --git a/tests/tests.lua b/tests/tests.lua index f151a4a1..ca867607 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -70,21 +70,21 @@ project "tests" if (PAL_BUILD_GRAPHICS_MODULE) then files { "graphics/graphics_test.c", - -- "graphics/compute_test.c", - -- "graphics/ray_tracing_test.c", - -- "graphics/multi_descriptor_set_test.c" + "graphics/compute_test.c", + "graphics/ray_tracing_test.c", + "graphics/multi_descriptor_set_test.c" } end if (PAL_BUILD_GRAPHICS_MODULE and PAL_BUILD_VIDEO_MODULE) then files { - -- "graphics/clear_color_test.c", - -- "graphics/triangle_test.c", - -- "graphics/mesh_test.c", - -- "graphics/texture_test.c", - -- "graphics/geometry_test.c", - -- "graphics/indirect_draw_test.c", - -- "graphics/descriptor_indexing_test.c" + "graphics/clear_color_test.c", + "graphics/triangle_test.c", + "graphics/mesh_test.c", + "graphics/texture_test.c", + "graphics/geometry_test.c", + "graphics/indirect_draw_test.c", + "graphics/descriptor_indexing_test.c" } end From 56854c51e2c240e553f27b38347142a210d88ca6 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 6 Jul 2026 10:52:46 +0000 Subject: [PATCH 314/372] graphics rework: compute test working vulkan --- CHANGELOG.md | 1 + include/pal/pal_core.h | 5 +- src/core/pal_result.h | 6 ++ src/graphics/pal_graphics.c | 104 +++++++++++++++++++++++- src/graphics/vulkan/pal_buffer_vulkan.c | 24 ++++-- src/graphics/vulkan/pal_device_vulkan.c | 1 - src/graphics/vulkan/pal_image_vulkan.c | 23 ++++-- tests/graphics/compute_test.c | 2 +- tests/tests_main.c | 4 +- 9 files changed, 149 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 13820c5b..85c2bcb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ - `PAL_RESULT_CODE_INVALID_OPERATION` - `PAL_RESULT_CODE_DEVICE_LOST` - `PAL_RESULT_CODE_OUT_OF_DATE` + - `PAL_RESULT_CODE_INVALID_DRIVER` - Added type `PalResultSource` with values: - `PAL_RESULT_SOURCE_NONE` - `PAL_RESULT_SOURCE_WIN32` diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index a28c854d..70be6229 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -70,8 +70,8 @@ #define PAL_RESULT_CODE_INVALID_OPERATION 8 #define PAL_RESULT_CODE_DEVICE_LOST 9 #define PAL_RESULT_CODE_OUT_OF_DATE 10 - -#define PAL_RESULT_CODE_COUNT 11 +#define PAL_RESULT_CODE_INVALID_DRIVER 11 +#define PAL_RESULT_CODE_COUNT 12 #define PAL_RESULT_SOURCE_NONE 0 #define PAL_RESULT_SOURCE_WIN32 1 @@ -80,7 +80,6 @@ #define PAL_RESULT_SOURCE_VULKAN 4 #define PAL_RESULT_SOURCE_DIRECTX12 5 #define PAL_RESULT_SOURCE_METAL 6 - #define PAL_RESULT_SOURCE_COUNT 7 /** diff --git a/src/core/pal_result.h b/src/core/pal_result.h index 85d51191..39698011 100644 --- a/src/core/pal_result.h +++ b/src/core/pal_result.h @@ -43,6 +43,9 @@ static const char* resultCodeToString(PalResult result) case PAL_RESULT_CODE_OUT_OF_DATE: return "PAL_RESULT_CODE_OUT_OF_DATE"; + + case PAL_RESULT_CODE_INVALID_DRIVER: + return "PAL_RESULT_CODE_INVALID_DRIVER"; } return ""; @@ -81,6 +84,9 @@ static const char* resultCodeToDescription(PalResult result) case PAL_RESULT_CODE_OUT_OF_DATE: return "Out of date"; + + case PAL_RESULT_CODE_INVALID_DRIVER: + return "Invalid driver"; } return nullptr; diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index a9256738..f2de821e 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -16,6 +16,7 @@ PAL_HANDLE(PalAdapter) PAL_HANDLE(PalDevice) PAL_HANDLE(PalQueue) +PAL_HANDLE(PalMemory) PAL_HANDLE(PalSwapchain) PAL_HANDLE(PalImage) PAL_HANDLE(PalImageView) @@ -681,6 +682,10 @@ PalResult PAL_CALL palCreateDevice( return result; } + if (device->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + device->backend = adapter->backend; *outDevice = device; return PAL_RESULT_SUCCESS; @@ -708,7 +713,20 @@ PalResult PAL_CALL palAllocateMemory( return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return device->backend->allocateMemory(device, type, memoryMask, size, outMemory); + PalMemory* memory = nullptr; + PalResult result; + result = device->backend->allocateMemory(device, type, memoryMask, size, &memory); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + if (memory->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + + memory->backend = device->backend; + *outMemory = memory; + return PAL_RESULT_SUCCESS; } void PAL_CALL palFreeMemory( @@ -868,6 +886,10 @@ PalResult PAL_CALL palCreateQueue( return result; } + if (queue->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + queue->backend = device->backend; *outQueue = queue; return PAL_RESULT_SUCCESS; @@ -980,6 +1002,10 @@ PalResult PAL_CALL palCreateImage( return result; } + if (image->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + image->backend = device->backend; *outImage = image; return PAL_RESULT_SUCCESS; @@ -1063,6 +1089,10 @@ PalResult PAL_CALL palCreateImageView( return result; } + if (imageView->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + imageView->backend = device->backend; *outImageView = imageView; return PAL_RESULT_SUCCESS; @@ -1099,6 +1129,10 @@ PalResult PAL_CALL palCreateSampler( return result; } + if (sampler->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + sampler->backend = device->backend; *outSampler = sampler; return PAL_RESULT_SUCCESS; @@ -1137,6 +1171,10 @@ PalResult PAL_CALL palCreateSurface( return result; } + if (surface->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + surface->backend = device->backend; *outSurface = surface; return PAL_RESULT_SUCCESS; @@ -1191,6 +1229,10 @@ PalResult PAL_CALL palCreateSwapchain( return result; } + if (swapchain->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + // set the backend for all swapchain images for (int i = 0; i < info->imageCount; i++) { PalImage* image = device->backend->getSwapchainImage(swapchain, i); @@ -1292,6 +1334,10 @@ PalResult PAL_CALL palCreateShader( return result; } + if (shader->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + shader->backend = device->backend; *outShader = shader; return PAL_RESULT_SUCCESS; @@ -1328,6 +1374,10 @@ PalResult PAL_CALL palCreateFence( return result; } + if (fence->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + fence->backend = device->backend; *outFence = fence; return PAL_RESULT_SUCCESS; @@ -1400,6 +1450,10 @@ PalResult PAL_CALL palCreateSemaphore( return result; } + if (semaphore->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + semaphore->backend = device->backend; *outSemaphore = semaphore; return PAL_RESULT_SUCCESS; @@ -1483,6 +1537,10 @@ PalResult PAL_CALL palCreateCommandPool( return result; } + if (pool->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + pool->backend = device->backend; *outPool = pool; return PAL_RESULT_SUCCESS; @@ -1529,6 +1587,10 @@ PalResult PAL_CALL palAllocateCommandBuffer( return result; } + if (cmdBuffer->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + cmdBuffer->backend = device->backend; *outCmdBuffer = cmdBuffer; return PAL_RESULT_SUCCESS; @@ -2296,6 +2358,10 @@ PalResult PAL_CALL palCreateAccelerationstructure( return result; } + if (as->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + as->backend = device->backend; *outAs = as; return PAL_RESULT_SUCCESS; @@ -2348,6 +2414,10 @@ PalResult PAL_CALL palCreateBuffer( return result; } + if (buffer->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + buffer->backend = device->backend; *outBuffer = buffer; return PAL_RESULT_SUCCESS; @@ -2541,6 +2611,10 @@ PalResult PAL_CALL palCreateDescriptorSetLayout( return result; } + if (layout->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + layout->backend = device->backend; *outLayout = layout; return PAL_RESULT_SUCCESS; @@ -2577,6 +2651,10 @@ PalResult PAL_CALL palCreateDescriptorPool( return result; } + if (pool->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + pool->backend = device->backend; *outPool = pool; return PAL_RESULT_SUCCESS; @@ -2623,6 +2701,10 @@ PalResult PAL_CALL palAllocateDescriptorSet( return result; } + if (set->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + set->backend = device->backend; *outSet = set; return PAL_RESULT_SUCCESS; @@ -2668,6 +2750,10 @@ PalResult PAL_CALL palCreatePipelineLayout( return result; } + if (layout->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + layout->backend = device->backend; *outLayout = layout; return PAL_RESULT_SUCCESS; @@ -2708,6 +2794,10 @@ PalResult PAL_CALL palCreateGraphicsPipeline( return result; } + if (pipeline->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + pipeline->backend = device->backend; *outPipeline = pipeline; return PAL_RESULT_SUCCESS; @@ -2733,6 +2823,10 @@ PalResult PAL_CALL palCreateComputePipeline( return result; } + if (pipeline->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + pipeline->backend = device->backend; *outPipeline = pipeline; return PAL_RESULT_SUCCESS; @@ -2758,6 +2852,10 @@ PalResult PAL_CALL palCreateRayTracingPipeline( return result; } + if (pipeline->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + pipeline->backend = device->backend; *outPipeline = pipeline; return PAL_RESULT_SUCCESS; @@ -2798,6 +2896,10 @@ PalResult PAL_CALL palCreateShaderBindingTable( return result; } + if (sbt->backend != PAL_BACKEND_KEY) { + return PAL_RESULT_CODE_INVALID_DRIVER; + } + sbt->backend = device->backend; *outSbt = sbt; return PAL_RESULT_SUCCESS; diff --git a/src/graphics/vulkan/pal_buffer_vulkan.c b/src/graphics/vulkan/pal_buffer_vulkan.c index 1724a4a5..57a729e7 100644 --- a/src/graphics/vulkan/pal_buffer_vulkan.c +++ b/src/graphics/vulkan/pal_buffer_vulkan.c @@ -197,6 +197,7 @@ PalResult PAL_CALL createBufferVk( VkResult result; BufferVk* buffer = nullptr; DeviceVk* vkDevice = (DeviceVk*)device; + MemoryVk* memory = nullptr; if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { @@ -214,6 +215,13 @@ PalResult PAL_CALL createBufferVk( return PAL_RESULT_CODE_OUT_OF_MEMORY; } + if (info->memoryUsage != PAL_BUFFER_MEMORY_USAGE_MANUAL) { + memory = palAllocate(s_Vk.allocator, sizeof(MemoryVk), 0); + if (!memory) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + } + VkBufferCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; @@ -225,7 +233,6 @@ PalResult PAL_CALL createBufferVk( return makeResultVk(result); } - buffer->memory = nullptr; buffer->isMemoryManaged = PAL_FALSE; if (info->memoryUsage != PAL_BUFFER_MEMORY_USAGE_MANUAL) { PalMemoryType memoryType = PAL_MEMORY_TYPE_GPU_ONLY; @@ -258,21 +265,25 @@ PalResult PAL_CALL createBufferVk( allocateInfo.pNext = &allocateFlagsInfo; } - VkDeviceMemory memory = nullptr; result = s_Vk.allocateMemory( vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, - &memory); + &memory->handle); if (result != VK_SUCCESS) { return makeResultVk(result); } + result = s_Vk.bindBufferMemory(vkDevice->handle, buffer->handle, memory->handle, 0); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + buffer->isMemoryManaged = PAL_TRUE; - buffer->memory = (MemoryVk*)memory; } + buffer->memory = memory; buffer->usages = info->usages; buffer->device = vkDevice; buffer->reserved = PAL_BACKEND_KEY; @@ -284,10 +295,9 @@ void PAL_CALL destroyBufferVk(PalBuffer* buffer) { BufferVk* vkBuffer = (BufferVk*)buffer; s_Vk.destroyBuffer(vkBuffer->device->handle, vkBuffer->handle, &s_Vk.vkAllocator); - if (vkBuffer->isMemoryManaged) { - VkDeviceMemory memory = (VkDeviceMemory)vkBuffer->memory; - s_Vk.freeMemory(vkBuffer->device->handle, memory, &s_Vk.vkAllocator); + s_Vk.freeMemory(vkBuffer->device->handle, vkBuffer->memory->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkBuffer->memory); } palFree(s_Vk.allocator, buffer); } diff --git a/src/graphics/vulkan/pal_device_vulkan.c b/src/graphics/vulkan/pal_device_vulkan.c index 534cd6b7..13f79762 100644 --- a/src/graphics/vulkan/pal_device_vulkan.c +++ b/src/graphics/vulkan/pal_device_vulkan.c @@ -1383,5 +1383,4 @@ void PAL_CALL destroyShaderVk(PalShader* shader) palFree(s_Vk.allocator, vkShader); } - #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_image_vulkan.c b/src/graphics/vulkan/pal_image_vulkan.c index 5d44fd46..b29eb4c5 100644 --- a/src/graphics/vulkan/pal_image_vulkan.c +++ b/src/graphics/vulkan/pal_image_vulkan.c @@ -154,12 +154,20 @@ PalResult PAL_CALL createImageVk( VkResult result; ImageVk* image = nullptr; DeviceVk* vkDevice = (DeviceVk*)device; + MemoryVk* memory = nullptr; image = palAllocate(s_Vk.allocator, sizeof(ImageVk), 0); if (!image) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } + if (info->memoryUsage != PAL_IMAGE_MEMORY_USAGE_MANUAL) { + memory = palAllocate(s_Vk.allocator, sizeof(MemoryVk), 0); + if (!memory) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + } + VkImageCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; @@ -189,7 +197,6 @@ PalResult PAL_CALL createImageVk( return makeResultVk(result); } - image->memory = nullptr; image->isMemoryManaged = PAL_FALSE; if (info->memoryUsage != PAL_IMAGE_MEMORY_USAGE_MANUAL) { PalMemoryType memoryType = PAL_MEMORY_TYPE_GPU_ONLY; @@ -209,19 +216,22 @@ PalResult PAL_CALL createImageVk( } allocateInfo.memoryTypeIndex = memoryIndex; - VkDeviceMemory memory = nullptr; result = s_Vk.allocateMemory( vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, - &memory); + &memory->handle); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + result = s_Vk.bindImageMemory(vkDevice->handle, image->handle, memory->handle, 0); if (result != VK_SUCCESS) { return makeResultVk(result); } image->isMemoryManaged = PAL_TRUE; - image->memory = (MemoryVk*)memory; } image->device = vkDevice; @@ -236,6 +246,7 @@ PalResult PAL_CALL createImageVk( image->info.arrayLayerCount = info->arrayLayerCount; image->info.belongsToSwapchain = PAL_FALSE; + image->memory = memory; image->reserved = PAL_BACKEND_KEY; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; @@ -250,8 +261,8 @@ void PAL_CALL destroyImageVk(PalImage* image) s_Vk.destroyImage(vkImage->device->handle, vkImage->handle, &s_Vk.vkAllocator); if (vkImage->isMemoryManaged) { - VkDeviceMemory memory = (VkDeviceMemory)vkImage->memory; - s_Vk.freeMemory(vkImage->device->handle, memory, &s_Vk.vkAllocator); + s_Vk.freeMemory(vkImage->device->handle, vkImage->memory->handle, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, vkImage->memory); } palFree(s_Vk.allocator, vkImage); diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 67cdc666..583c3c25 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -43,7 +43,7 @@ PalBool computeTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr, 0, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize graphics"); return PAL_FALSE; diff --git a/tests/tests_main.c b/tests/tests_main.c index 34ee42d2..e5144d95 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -56,8 +56,8 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS_MODULE == 1 - registerTest(graphicsTest, "Graphics Test"); - // registerTest(computeTest, "Compute Test"); + // registerTest(graphicsTest, "Graphics Test"); + registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS_MODULE From 3770e2e973ce1bb1f18682dd1df0c453ab2f7925 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 6 Jul 2026 15:57:55 +0000 Subject: [PATCH 315/372] graphics rework: ray tracing test working --- include/pal/pal_graphics.h | 8 +- src/core/posix/pal_memory_posix.c | 15 +-- src/core/win32/pal_memory_win32.c | 15 +-- src/graphics/vulkan/pal_as_vulkan.c | 55 +++------ src/graphics/vulkan/pal_commands_vulkan.c | 78 +++++------- src/graphics/vulkan/pal_pipeline_vulkan.c | 49 ++++---- src/graphics/vulkan/pal_vulkan.c | 133 +++++++++++---------- src/graphics/vulkan/pal_vulkan.h | 10 +- tests/graphics/compute_test.c | 13 +- tests/graphics/descriptor_indexing_test.c | 12 +- tests/graphics/multi_descriptor_set_test.c | 11 +- tests/graphics/ray_tracing_test.c | 5 +- tests/tests_main.c | 4 +- 13 files changed, 175 insertions(+), 233 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 97af0927..79255088 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -2277,7 +2277,7 @@ typedef struct { } PalDescriptorSetWriteInfo; /** - * @struct PalPushConstantRange + * @struct PalPushConstantInfo * @brief Push constant range. * * Uninitialized fields may result in undefined behavior. @@ -2287,7 +2287,7 @@ typedef struct { typedef struct { uint32_t offset; /**< Offset in bytes.*/ uint32_t size; /**< Size in bytes.*/ -} PalPushConstantRange; +} PalPushConstantInfo; /** * @struct PalImageSubresourceRange @@ -2562,9 +2562,9 @@ typedef struct { */ typedef struct { PalDescriptorSetLayout** descriptorSetLayouts; /**< Descriptor set layouts.*/ - PalPushConstantRange* pushConstantRanges; /**< Push constant ranges.*/ + PalPushConstantInfo pushConstantInfo; /**< Push constant info.*/ uint32_t descriptorSetLayoutCount; /**< Number of descriptor set layouts.*/ - uint32_t pushConstantRangeCount; /**< Number of push constant ranges.*/ + PalBool usePushConstant; /**< `PAL_TRUE` to use push constant.*/ } PalPipelineLayoutCreateInfo; /** diff --git a/src/core/posix/pal_memory_posix.c b/src/core/posix/pal_memory_posix.c index b72f3a85..baf9d53e 100644 --- a/src/core/posix/pal_memory_posix.c +++ b/src/core/posix/pal_memory_posix.c @@ -17,10 +17,6 @@ void* PAL_CALL palAllocate( uint64_t size, uint64_t alignment) { - if (size == 0) { - return nullptr; - } - uint64_t align = alignment; if (align == 0) { align = 16; // default @@ -39,11 +35,12 @@ void PAL_CALL palFree( const PalAllocator* allocator, void* ptr) { - if (allocator && allocator->free && ptr) { - allocator->free(allocator->userData, ptr); - - } else { - free(ptr); + if (ptr) { + if (allocator && allocator->free) { + allocator->free(allocator->userData, ptr); + } else { + free(ptr); + } } } diff --git a/src/core/win32/pal_memory_win32.c b/src/core/win32/pal_memory_win32.c index 363274fa..50249141 100644 --- a/src/core/win32/pal_memory_win32.c +++ b/src/core/win32/pal_memory_win32.c @@ -17,10 +17,6 @@ void* PAL_CALL palAllocate( uint64_t size, uint64_t alignment) { - if (size == 0) { - return nullptr; - } - uint64_t align = alignment; if (align == 0) { align = 16; // default @@ -37,11 +33,12 @@ void PAL_CALL palFree( const PalAllocator* allocator, void* ptr) { - if (allocator && allocator->free && ptr) { - allocator->free(allocator->userData, ptr); - - } else { - _aligned_free(ptr); + if (ptr) { + if (allocator && allocator->free) { + allocator->free(allocator->userData, ptr); + } else { + _aligned_free(ptr); + } } } diff --git a/src/graphics/vulkan/pal_as_vulkan.c b/src/graphics/vulkan/pal_as_vulkan.c index 6ac3c978..35e90831 100644 --- a/src/graphics/vulkan/pal_as_vulkan.c +++ b/src/graphics/vulkan/pal_as_vulkan.c @@ -76,53 +76,28 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { - uint32_t* maxPrimities = nullptr; - VkAccelerationStructureGeometryKHR* geometries = nullptr; DeviceVk* vkDevice = (DeviceVk*)device; - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } - // cache these for top level as - VkAccelerationStructureGeometryKHR cachedGeometries = {0}; - uint32_t cachedPrimitives = 0; - uint32_t geometryCount = info->count; - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { - geometryCount = 1; - geometries = &cachedGeometries; - maxPrimities = &cachedPrimitives; - } + VkAccelerationStructureGeometryKHR* geometries = nullptr; + uint32_t* maxPrimities = nullptr; + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; + uint32_t geometriesSize = sizeof(VkAccelerationStructureGeometryKHR) * info->count; - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - geometries = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureGeometryKHR) * geometryCount, - 0); - - maxPrimities = palAllocate(s_Vk.allocator, sizeof(uint32_t) * geometryCount, 0); - if (!maxPrimities || !geometries) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } - - memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * geometryCount); - memset(maxPrimities, 0, sizeof(uint32_t) * geometryCount); + geometries = palAllocate(s_Vk.allocator, geometriesSize, 0); + maxPrimities = palAllocate(s_Vk.allocator, sizeof(uint32_t) * info->count, 0); + if (!maxPrimities || !geometries) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; } - fillBuildInfoVk( - geometryCount, - info, - maxPrimities, - geometries, - nullptr, - nullptr, - nullptr, - &buildInfo); - + memset(geometries, 0, geometriesSize); + memset(maxPrimities, 0, sizeof(uint32_t) * info->count); + fillBuildInfoVk(PAL_TRUE, info, geometries, &buildInfo, maxPrimities); + VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; - vkDevice->getAccelerationBuildsize( vkDevice->handle, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, @@ -134,10 +109,8 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( size->scratchBufferSize = sizeInfo.buildScratchSize; size->updateScratchBufferSize = sizeInfo.updateScratchSize; - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - palFree(s_Vk.allocator, geometries); - palFree(s_Vk.allocator, maxPrimities); - } + palFree(s_Vk.allocator, geometries); + palFree(s_Vk.allocator, maxPrimities); return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c index 023a4a1d..d8859568 100644 --- a/src/graphics/vulkan/pal_commands_vulkan.c +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -421,68 +421,46 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - VkAccelerationStructureGeometryKHR* geometries = nullptr; - VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; - AccelerationStructureVk* tmpAs = (AccelerationStructureVk*)info->src; - AccelerationStructureVk* dstAs = (AccelerationStructureVk*)info->dst; - VkAccelerationStructureKHR srcAs = nullptr; - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } - // cache these for top level as - VkAccelerationStructureBuildRangeInfoKHR cachedRangeInfo = {0}; - VkAccelerationStructureGeometryKHR cachedGeometries = {0}; - uint32_t geometryCount = info->count; - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { - geometryCount = 1; - rangeInfos = &cachedRangeInfo; - geometries = &cachedGeometries; - } + VkAccelerationStructureGeometryKHR* geometries = nullptr; + VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; + const VkAccelerationStructureBuildRangeInfoKHR** tmpRangeInfos = nullptr; + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - if (tmpAs) { - srcAs = tmpAs->handle; - } + tmpRangeInfos = palAllocate(s_Vk.allocator, sizeof(void*) * info->count, 0); + geometries = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureGeometryKHR) * info->count, + 0); - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - geometries = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureGeometryKHR) * geometryCount, - 0); + rangeInfos = palAllocate( + s_Vk.allocator, + sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->count, + 0); - rangeInfos = palAllocate( - s_Vk.allocator, - sizeof(VkAccelerationStructureBuildRangeInfoKHR) * geometryCount, - 0); + if (!tmpRangeInfos || !rangeInfos || !geometries) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } - if (!rangeInfos || !geometries) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } + memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->count); + memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->count); + fillBuildInfoVk(PAL_FALSE, info, geometries, &buildInfo, rangeInfos); - memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * geometryCount); - memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * geometryCount); + for (int i = 0; i < info->count; i++) { + tmpRangeInfos[i] = &rangeInfos[i]; } - fillBuildInfoVk( - geometryCount, - info, - nullptr, - geometries, - srcAs, - dstAs->handle, - rangeInfos, - &buildInfo); - - const VkAccelerationStructureBuildRangeInfoKHR* tmp[1]; - tmp[0] = rangeInfos; - vkCmdBuffer->device->cmdBuildAccelerationStructures(vkCmdBuffer->handle, 1, &buildInfo, tmp); + vkCmdBuffer->device->cmdBuildAccelerationStructures( + vkCmdBuffer->handle, + 1, + &buildInfo, + tmpRangeInfos); - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - palFree(s_Vk.allocator, geometries); - palFree(s_Vk.allocator, rangeInfos); - } + palFree(s_Vk.allocator, geometries); + palFree(s_Vk.allocator, rangeInfos); return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/vulkan/pal_pipeline_vulkan.c b/src/graphics/vulkan/pal_pipeline_vulkan.c index aa6bb890..02d38cf2 100644 --- a/src/graphics/vulkan/pal_pipeline_vulkan.c +++ b/src/graphics/vulkan/pal_pipeline_vulkan.c @@ -181,37 +181,42 @@ PalResult PAL_CALL createPipelineLayoutVk( VkResult result; DeviceVk* vkDevice = (DeviceVk*)device; PipelineLayoutVk* layout = nullptr; - VkPushConstantRange* pushConstants = nullptr; + VkPushConstantRange pushConstantRange = {0}; VkDescriptorSetLayout* descriptorLayouts = nullptr; - uint32_t pushConstantSize = sizeof(VkPushConstantRange) * info->pushConstantRangeCount; - uint32_t setLayoutSize = sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount; - + layout = palAllocate(s_Vk.allocator, sizeof(PipelineLayoutVk), 0); - pushConstants = palAllocate(s_Vk.allocator, pushConstantSize, 0); - descriptorLayouts = palAllocate(s_Vk.allocator, setLayoutSize, 0); - if (!layout || !pushConstants || !descriptorLayouts) { + if (!layout) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } + if (info->descriptorSetLayoutCount) { + descriptorLayouts = palAllocate( + s_Vk.allocator, + sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount, + 0); + + if (!descriptorLayouts) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + } + for (int i = 0; i < info->descriptorSetLayoutCount; i++) { DescriptorSetLayoutVk* tmp = (DescriptorSetLayoutVk*)info->descriptorSetLayouts[i]; descriptorLayouts[i] = tmp->handle; } - for (int i = 0; i < info->pushConstantRangeCount; i++) { - VkPushConstantRange* range = &pushConstants[i]; - range->offset = info->pushConstantRanges[i].offset; - range->size = info->pushConstantRanges[i].size; - range->stageFlags = vkDevice->shaderStages; - range->offset = info->pushConstantRanges[i].offset; - } - VkPipelineLayoutCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; createInfo.setLayoutCount = info->descriptorSetLayoutCount; createInfo.pSetLayouts = descriptorLayouts; - createInfo.pPushConstantRanges = pushConstants; - createInfo.pushConstantRangeCount = info->pushConstantRangeCount; + + if (info->usePushConstant) { + pushConstantRange.size = info->pushConstantInfo.size; + pushConstantRange.stageFlags = vkDevice->shaderStages; + pushConstantRange.offset = info->pushConstantInfo.offset; + createInfo.pushConstantRangeCount = 1; + createInfo.pPushConstantRanges = &pushConstantRange; + } result = s_Vk.createPipelineLayout( vkDevice->handle, @@ -219,16 +224,15 @@ PalResult PAL_CALL createPipelineLayoutVk( &s_Vk.vkAllocator, &layout->handle); - if (result != VK_SUCCESS) { + if (info->descriptorSetLayoutCount) { palFree(s_Vk.allocator, descriptorLayouts); - palFree(s_Vk.allocator, pushConstants); + } + + if (result != VK_SUCCESS) { palFree(s_Vk.allocator, layout); return makeResultVk(result); } - palFree(s_Vk.allocator, descriptorLayouts); - palFree(s_Vk.allocator, pushConstants); - layout->device = vkDevice; layout->reserved = PAL_BACKEND_KEY; *outLayout = (PalPipelineLayout*)layout; @@ -912,6 +916,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; pipeline->device = vkDevice; pipeline->layout = layout->handle; + pipeline->reserved = PAL_BACKEND_KEY; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/vulkan/pal_vulkan.c b/src/graphics/vulkan/pal_vulkan.c index 3a72a4bf..0607b56a 100644 --- a/src/graphics/vulkan/pal_vulkan.c +++ b/src/graphics/vulkan/pal_vulkan.c @@ -631,25 +631,31 @@ VkFormat vertexTypeToVk(PalVertexType type) } void fillBuildInfoVk( - uint32_t count, + PalBool getBuildSize, PalAccelerationStructureBuildInfo* info, - uint32_t* maxPrimities, VkAccelerationStructureGeometryKHR* geometries, - VkAccelerationStructureKHR srcAs, - VkAccelerationStructureKHR dstAs, - VkAccelerationStructureBuildRangeInfoKHR* rangeInfos, - VkAccelerationStructureBuildGeometryInfoKHR* buildInfo) + VkAccelerationStructureBuildGeometryInfoKHR* outBuildInfo, + void* outData) { - for (int i = 0; i < count; i++) { + for (int i = 0; i < info->count; i++) { // fill vulkan geometry struct - VkAccelerationStructureGeometryKHR* tmp = &geometries[i]; - tmp->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; - tmp->flags = 0; + VkAccelerationStructureBuildRangeInfoKHR* range = nullptr; + uint32_t* maxPrimitives = nullptr; + VkAccelerationStructureGeometryKHR* geometry = &geometries[i]; + if (getBuildSize) { + maxPrimitives = outData; + } else { + VkAccelerationStructureBuildRangeInfoKHR* tmp = outData; + range = &tmp[i]; + } + + geometry->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR; + geometry->flags = 0; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { - tmp->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + geometry->geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; VkAccelerationStructureGeometryInstancesDataKHR* data = nullptr; - data = &tmp->geometry.instances; + data = &geometry->geometry.instances; data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR; data->arrayOfPointers = PAL_FALSE; @@ -657,74 +663,65 @@ void fillBuildInfoVk( address.deviceAddress = info->instanceBufferAddress; data->data = address; - if (maxPrimities) { - maxPrimities[i] = info->count; - } - - // range info - if (rangeInfos) { - VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; - rangeInfo->primitiveCount = info->count; - rangeInfo->firstVertex = 0; // PAL does not allow setting this - rangeInfo->primitiveOffset = 0; // PAL does not allow setting this - rangeInfo->transformOffset = 0; // PAL does not allow setting this + if (getBuildSize) { + maxPrimitives[i] = info->count; + + } else { + range->primitiveCount = info->count; + range->firstVertex = 0; // PAL does not allow setting this + range->primitiveOffset = 0; // PAL does not allow setting this + range->transformOffset = 0; // PAL does not allow setting this } break; } else { if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_OPAQUE) { - tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; + geometry->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; } if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT) { - tmp->flags |= VK_GEOMETRY_OPAQUE_BIT_KHR; - } - - if (maxPrimities) { - maxPrimities[i] = info->geometries[i].primitiveCount; + geometry->flags |= VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; } - // range info - if (rangeInfos) { - VkAccelerationStructureBuildRangeInfoKHR* rangeInfo = &rangeInfos[i]; - rangeInfo->primitiveCount = info->geometries[i].primitiveCount; - rangeInfo->firstVertex = 0; // PAL does not allow setting this - rangeInfo->primitiveOffset = 0; // PAL does not allow setting this - rangeInfo->transformOffset = 0; // PAL does not allow setting this + if (getBuildSize) { + maxPrimitives[i] = info->geometries[i].primitiveCount; + + } else { + range->primitiveCount = info->geometries[i].primitiveCount; + range->firstVertex = 0; // PAL does not allow setting this + range->primitiveOffset = 0; // PAL does not allow setting this + range->transformOffset = 0; // PAL does not allow setting this } } if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { - tmp->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - VkAccelerationStructureGeometryTrianglesDataKHR* data = &tmp->geometry.triangles; + geometry->geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + VkAccelerationStructureGeometryTrianglesDataKHR* data = &geometry->geometry.triangles; data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR; - - VkDeviceOrHostAddressConstKHR vertexAddress = {0}; - VkDeviceOrHostAddressConstKHR indexAddress = {0}; const PalGeometryDataTriangle* tmpData = info->geometries[i].data; - vertexAddress.deviceAddress = tmpData->vertexBufferAddress; - data->vertexData = vertexAddress; + data->vertexData.deviceAddress = tmpData->vertexBufferAddress; data->maxVertex = tmpData->vertexCount - 1; data->vertexFormat = vertexTypeToVk(tmpData->vertexType); data->vertexStride = tmpData->vertexStride; - indexAddress.deviceAddress = tmpData->indexBufferAddress; - data->indexData = indexAddress; + data->transformData.deviceAddress = tmpData->transformBufferAddress; + + data->indexData.deviceAddress = tmpData->indexBufferAddress; if (tmpData->indexType == PAL_INDEX_TYPE_UINT32) { data->indexType = VK_INDEX_TYPE_UINT32; + } else { data->indexType = VK_INDEX_TYPE_UINT16; } - // set to none if there is no index buffer address if (!tmpData->indexBufferAddress) { data->indexType = VK_INDEX_TYPE_NONE_KHR; } } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { - tmp->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; - VkAccelerationStructureGeometryAabbsDataKHR* data = &tmp->geometry.aabbs; + geometry->geometryType = VK_GEOMETRY_TYPE_AABBS_KHR; + VkAccelerationStructureGeometryAabbsDataKHR* data = &geometry->geometry.aabbs; data->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR; VkDeviceOrHostAddressConstKHR address = {0}; @@ -735,42 +732,54 @@ void fillBuildInfoVk( } } - buildInfo->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; + outBuildInfo->sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - buildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + outBuildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; } else { - buildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + outBuildInfo->type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; } // build mode if (info->buildMode == PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD) { - buildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + outBuildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; } else { - buildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR; + outBuildInfo->mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_UPDATE_KHR; } // build hints - buildInfo->flags = 0; + outBuildInfo->flags = 0; if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD) { - buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; + outBuildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; } if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE) { - buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + outBuildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; } if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY) { - buildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; + outBuildInfo->flags |= VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; + } + + AccelerationStructureVk* dstAs = (AccelerationStructureVk*)info->dst; + AccelerationStructureVk* srcAs = (AccelerationStructureVk*)info->src; + VkAccelerationStructureKHR dstAsHandle = nullptr; + if (dstAs) { + dstAsHandle = dstAs->handle; + } + + VkAccelerationStructureKHR srcAsHandle = nullptr; + if (srcAs) { + srcAsHandle = srcAs->handle; } - buildInfo->geometryCount = count; - buildInfo->srcAccelerationStructure = srcAs; - buildInfo->dstAccelerationStructure = dstAs; - buildInfo->pGeometries = geometries; + outBuildInfo->geometryCount = info->count; + outBuildInfo->dstAccelerationStructure = dstAsHandle; + outBuildInfo->srcAccelerationStructure = srcAsHandle; + outBuildInfo->pGeometries = geometries; VkDeviceOrHostAddressKHR scratchData = {0}; scratchData.deviceAddress = info->scratchBufferAddress; - buildInfo->scratchData = scratchData; + outBuildInfo->scratchData = scratchData; } static void* alignedRealloc( diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h index 5ca3c01c..813e6b2f 100644 --- a/src/graphics/vulkan/pal_vulkan.h +++ b/src/graphics/vulkan/pal_vulkan.h @@ -482,15 +482,13 @@ uint32_t findBestMemoryIndexVk( uint32_t memoryMask); VkFormat vertexTypeToVk(PalVertexType type); + void fillBuildInfoVk( - uint32_t count, + PalBool getBuildSize, PalAccelerationStructureBuildInfo* info, - uint32_t* maxPrimities, VkAccelerationStructureGeometryKHR* geometries, - VkAccelerationStructureKHR srcAs, - VkAccelerationStructureKHR dstAs, - VkAccelerationStructureBuildRangeInfoKHR* rangeInfos, - VkAccelerationStructureBuildGeometryInfoKHR* buildInfo); + VkAccelerationStructureBuildGeometryInfoKHR* outBuildInfo, + void* outData); #endif // PAL_HAS_VULKAN_BACKEND #endif // _PAL_VULKAN_H \ No newline at end of file diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 583c3c25..9e25985b 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -43,7 +43,7 @@ PalBool computeTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr, 0, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize graphics"); return PAL_FALSE; @@ -284,18 +284,13 @@ PalBool computeTest() return PAL_FALSE; } - // push constants - // size must be less than the max size from the adapter capabilities struct - PalPushConstantRange pushConstantRange = {0}; - pushConstantRange.offset = 0; - pushConstantRange.size = sizeof(PushConstant); // must match shader - // create pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; pipelineLayoutCreateInfo.descriptorSetLayoutCount = 1; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; pipelineLayoutCreateInfo.descriptorSetLayouts = &descriptorSetLayout; - pipelineLayoutCreateInfo.pushConstantRanges = &pushConstantRange; + pipelineLayoutCreateInfo.usePushConstant = PAL_TRUE; + pipelineLayoutCreateInfo.pushConstantInfo.offset = 0; + pipelineLayoutCreateInfo.pushConstantInfo.size = sizeof(PushConstant); // must match shader result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index d25bc483..449b1893 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -920,19 +920,13 @@ PalBool descriptorIndexingTest() return PAL_FALSE; } - - // push constants - // size must be less than the max size from the adapter capabilities struct - PalPushConstantRange pushConstantRange = {0}; - pushConstantRange.offset = 0; - pushConstantRange.size = sizeof(PushConstant); // must match shader - // create pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; pipelineLayoutCreateInfo.descriptorSetLayoutCount = 1; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; pipelineLayoutCreateInfo.descriptorSetLayouts = &descriptorSetLayout; - pipelineLayoutCreateInfo.pushConstantRanges = &pushConstantRange; + pipelineLayoutCreateInfo.usePushConstant = PAL_TRUE; + pipelineLayoutCreateInfo.pushConstantInfo.offset = 0; + pipelineLayoutCreateInfo.pushConstantInfo.size = sizeof(PushConstant); // must match shader result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 7591a66d..9cb67c75 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -318,12 +318,6 @@ PalBool multiDescriptorSetTest() return PAL_FALSE; } - // push constants - // size must be less than the max size from the adapter capabilities struct - PalPushConstantRange pushConstantRange = {0}; - pushConstantRange.offset = 0; - pushConstantRange.size = sizeof(PushConstant); // must match shader - // create pipeline layout // even if the descriptor set layout is identical, pipeline layout creation needs // a descriptor set layout per set (3) @@ -334,9 +328,10 @@ PalBool multiDescriptorSetTest() PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; pipelineLayoutCreateInfo.descriptorSetLayoutCount = 3; - pipelineLayoutCreateInfo.pushConstantRangeCount = 1; pipelineLayoutCreateInfo.descriptorSetLayouts = descriptorSetLayouts; - pipelineLayoutCreateInfo.pushConstantRanges = &pushConstantRange; + pipelineLayoutCreateInfo.usePushConstant = PAL_TRUE; + pipelineLayoutCreateInfo.pushConstantInfo.offset = 0; + pipelineLayoutCreateInfo.pushConstantInfo.size = sizeof(PushConstant); // must match shader result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 6fe95b9f..e32125a2 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -51,7 +51,8 @@ PalBool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(nullptr, nullptr, 0, nullptr); + PalResult result = palInitGraphics(&debugger, nullptr, 0, nullptr); + // PalResult result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize graphics"); return PAL_FALSE; @@ -361,7 +362,7 @@ PalBool rayTracingTest() bufferCreateInfo.size = instanceBufferSize; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT; bufferCreateInfo.usages |= PAL_BUFFER_USAGE_DEVICE_ADDRESS; - bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY; + bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; result = palCreateBuffer(device, &bufferCreateInfo, &instanceBuffer); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/tests_main.c b/tests/tests_main.c index e5144d95..a252707d 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -57,8 +57,8 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS_MODULE == 1 // registerTest(graphicsTest, "Graphics Test"); - registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(computeTest, "Compute Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS_MODULE From 6a3ff0e008a0064a342bb652778e07af8b9ccbbb Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 6 Jul 2026 19:10:12 +0000 Subject: [PATCH 316/372] graphics rework: all tests working vulkan --- pal_config.lua | 4 ++-- src/graphics/vulkan/pal_buffer_vulkan.c | 2 ++ src/graphics/vulkan/pal_descriptors_vulkan.c | 23 ++++++++++++-------- src/graphics/vulkan/pal_image_vulkan.c | 2 ++ src/graphics/vulkan/pal_vulkan.c | 1 + tests/graphics/compute_test.c | 2 +- tests/graphics/descriptor_indexing_test.c | 4 ++-- tests/graphics/indirect_draw_test.c | 2 +- tests/graphics/multi_descriptor_set_test.c | 2 +- tests/graphics/ray_tracing_test.c | 9 ++++---- tests/graphics/texture_test.c | 14 ++++++------ tests/graphics/triangle_test.c | 4 ++-- tests/tests.lua | 2 +- tests/tests_main.c | 6 ++--- 14 files changed, 43 insertions(+), 34 deletions(-) diff --git a/pal_config.lua b/pal_config.lua index 821efe2d..f5c2621f 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -9,13 +9,13 @@ PAL_BUILD_TEST_APPLICATION = true PAL_BUILD_ABI_DUMP = true -- build system module -PAL_BUILD_SYSTEM_MODULE = false +PAL_BUILD_SYSTEM_MODULE = true -- build thread module PAL_BUILD_THREAD_MODULE = false -- build video module -PAL_BUILD_VIDEO_MODULE = false +PAL_BUILD_VIDEO_MODULE = true -- build opengl module PAL_BUILD_OPENGL_MODULE = false diff --git a/src/graphics/vulkan/pal_buffer_vulkan.c b/src/graphics/vulkan/pal_buffer_vulkan.c index 57a729e7..a783559b 100644 --- a/src/graphics/vulkan/pal_buffer_vulkan.c +++ b/src/graphics/vulkan/pal_buffer_vulkan.c @@ -280,6 +280,8 @@ PalResult PAL_CALL createBufferVk( return makeResultVk(result); } + memory->type = memoryType; + memory->reserved = PAL_BACKEND_KEY; buffer->isMemoryManaged = PAL_TRUE; } diff --git a/src/graphics/vulkan/pal_descriptors_vulkan.c b/src/graphics/vulkan/pal_descriptors_vulkan.c index 35f06376..7eec3f89 100644 --- a/src/graphics/vulkan/pal_descriptors_vulkan.c +++ b/src/graphics/vulkan/pal_descriptors_vulkan.c @@ -47,8 +47,12 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flagsCreateInfo = {0}; flagsCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; - PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - if (info->flags != 0 && hasDescriptorIndexing) { + PalBool hasDescriptorIndexing = PAL_FALSE; + if (vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + hasDescriptorIndexing = PAL_TRUE; + } + + if (info->flags != 0 && !hasDescriptorIndexing) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } @@ -104,14 +108,12 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( &s_Vk.vkAllocator, &layout->handle); + palFree(s_Vk.allocator, bindings); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, layout); - palFree(s_Vk.allocator, bindings); return makeResultVk(result); } - palFree(s_Vk.allocator, bindings); - layout->device = vkDevice; layout->flags = info->flags; layout->reserved = PAL_BACKEND_KEY; @@ -143,8 +145,12 @@ PalResult PAL_CALL createDescriptorPoolVk( VkDescriptorPoolCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - PalBool hasDescriptorIndexing = vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - if (info->flags != 0 && hasDescriptorIndexing) { + PalBool hasDescriptorIndexing = PAL_FALSE; + if (vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + hasDescriptorIndexing = PAL_TRUE; + } + + if (info->flags != 0 && !hasDescriptorIndexing) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } @@ -174,13 +180,12 @@ PalResult PAL_CALL createDescriptorPoolVk( &s_Vk.vkAllocator, &pool->handle); + palFree(s_Vk.allocator, poolSizes); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, pool); - palFree(s_Vk.allocator, poolSizes); return makeResultVk(result); } - palFree(s_Vk.allocator, poolSizes); pool->device = vkDevice; pool->flags = info->flags; pool->reserved = PAL_BACKEND_KEY; diff --git a/src/graphics/vulkan/pal_image_vulkan.c b/src/graphics/vulkan/pal_image_vulkan.c index b29eb4c5..099b0aea 100644 --- a/src/graphics/vulkan/pal_image_vulkan.c +++ b/src/graphics/vulkan/pal_image_vulkan.c @@ -231,6 +231,8 @@ PalResult PAL_CALL createImageVk( return makeResultVk(result); } + memory->type = memoryType; + memory->reserved = PAL_BACKEND_KEY; image->isMemoryManaged = PAL_TRUE; } diff --git a/src/graphics/vulkan/pal_vulkan.c b/src/graphics/vulkan/pal_vulkan.c index 0607b56a..2b7b7313 100644 --- a/src/graphics/vulkan/pal_vulkan.c +++ b/src/graphics/vulkan/pal_vulkan.c @@ -8,6 +8,7 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" #include "pal_platform.h" +#include #ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 9e25985b..62fe37d6 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -452,7 +452,7 @@ PalBool computeTest() void* ptr = nullptr; result = palMapBuffer(stagingBuffer, 0, bufferBytes, &ptr); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 449b1893..28f910d8 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -462,7 +462,7 @@ PalBool descriptorIndexingTest() void* ptr = nullptr; result = palMapBuffer(stagingBuffer, 0, sizeof(vertices), &ptr); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } @@ -553,7 +553,7 @@ PalBool descriptorIndexingTest() &data); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index ac1e0b42..11377555 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -458,7 +458,7 @@ PalBool indirectDrawTest() void* ptr = nullptr; result = palMapBuffer(stagingBuffer, 0, stagingBufferSize, &ptr); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 9cb67c75..a2fb7bf2 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -525,7 +525,7 @@ PalBool multiDescriptorSetTest() void* ptr = nullptr; result = palMapBuffer(stagingBuffers[i], 0, bufferBytes, &ptr); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index e32125a2..7cb6dc14 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -51,8 +51,7 @@ PalBool rayTracingTest() debugger.callback = onGraphicsDebug; debugger.userData = nullptr; - PalResult result = palInitGraphics(&debugger, nullptr, 0, nullptr); - // PalResult result = palInitGraphics(nullptr, nullptr, 0, nullptr); + PalResult result = palInitGraphics(nullptr, nullptr, 0, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize graphics"); return PAL_FALSE; @@ -276,7 +275,7 @@ PalBool rayTracingTest() void* data = nullptr; result = palMapBuffer(vertexBuffer, 0, sizeof(vertices), &data); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } @@ -379,7 +378,7 @@ PalBool rayTracingTest() &data); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } @@ -756,7 +755,7 @@ PalBool rayTracingTest() void* ptr = nullptr; result = palMapBuffer(stagingBuffer, 0, bufferBytes, &ptr); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index c80dd693..71f46a72 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -437,7 +437,7 @@ PalBool textureTest() void* ptr = nullptr; result = palMapBuffer(stagingBuffer, 0, sizeof(vertices), &ptr); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } @@ -510,7 +510,7 @@ PalBool textureTest() PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; imageStagingBufferCreateInfo.size = imageCopyStagingBufferSize; imageStagingBufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; - bufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; + imageStagingBufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; result = palCreateBuffer(device, &imageStagingBufferCreateInfo, &imageStagingBuffer); if (result != PAL_RESULT_SUCCESS) { @@ -527,7 +527,7 @@ PalBool textureTest() &data); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } @@ -590,8 +590,8 @@ PalBool textureTest() cmdBuffers[0], checkerboard, &checkerboardRange, - &oldImageUsageState, - &newImageUsageState); + oldImageUsageState, + newImageUsageState); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to set barrier"); @@ -616,8 +616,8 @@ PalBool textureTest() cmdBuffers[0], checkerboard, &checkerboardRange, - &oldImageUsageState, - &newImageUsageState); + oldImageUsageState, + newImageUsageState); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to set barrier"); diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 2e68e09c..84aba370 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -400,7 +400,7 @@ PalBool triangleTest() void* ptr = nullptr; result = palMapBuffer(stagingBuffer, 0, sizeof(vertices), &ptr); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to map memory"); + logResult(result, "Failed to map buffer"); return PAL_FALSE; } @@ -436,7 +436,7 @@ PalBool triangleTest() PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; PalUsageState newUsageState = PAL_USAGE_STATE_VERTEX_READ; - result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &oldUsageState, &newUsageState); + result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to set barrier"); return PAL_FALSE; diff --git a/tests/tests.lua b/tests/tests.lua index ca867607..2f011832 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -76,7 +76,7 @@ project "tests" } end - if (PAL_BUILD_GRAPHICS_MODULE and PAL_BUILD_VIDEO_MODULE) then + if (PAL_BUILD_GRAPHICS_MODULE and PAL_BUILD_VIDEO_MODULE and PAL_BUILD_SYSTEM_MODULE) then files { "graphics/clear_color_test.c", "graphics/triangle_test.c", diff --git a/tests/tests_main.c b/tests/tests_main.c index a252707d..7842a582 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -58,18 +58,18 @@ int main(int argc, char** argv) #if PAL_HAS_GRAPHICS_MODULE == 1 // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); - registerTest(rayTracingTest, "Ray Tracing Test"); + // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS_MODULE -#if PAL_HAS_GRAPHICS_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 +#if PAL_HAS_GRAPHICS_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 && PAL_HAS_SYSTEM_MODULE == 1 // registerTest(clearColorTest, "Clear Color Test"); // registerTest(triangleTest, "Triangle Test"); // registerTest(meshTest, "Mesh Test"); // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); - // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); + registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From 6e374c668229548796f8e5b029489824e2d6ad35 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 6 Jul 2026 22:24:40 -0700 Subject: [PATCH 317/372] start d3d12 backend rework --- pal.lua | 16 +- src/graphics/d3d12/pal_adapter_d3d12.c | 636 +++++ src/graphics/d3d12/pal_as_d3d12.c | 95 + src/graphics/d3d12/pal_buffer_d3d12.c | 11 + src/graphics/d3d12/pal_command_pool_d3d12.c | 11 + src/graphics/d3d12/pal_commands_d3d12.c | 11 + src/graphics/d3d12/pal_d3d12.h | 405 ++++ src/graphics/d3d12/pal_descriptors_d3d12.c | 11 + src/graphics/d3d12/pal_device_d3d12.c | 11 + src/graphics/d3d12/pal_image_d3d12.c | 11 + src/graphics/d3d12/pal_pipeline_d3d12.c | 11 + src/graphics/d3d12/pal_sbt_d3d12.c | 429 ++++ src/graphics/d3d12/pal_swapchain_d3d12.c | 11 + src/graphics/d3d12/pal_sync_d3d12.c | 236 ++ src/graphics/pal_d3d12.c | 2417 +++---------------- 15 files changed, 2229 insertions(+), 2093 deletions(-) create mode 100644 src/graphics/d3d12/pal_adapter_d3d12.c create mode 100644 src/graphics/d3d12/pal_as_d3d12.c create mode 100644 src/graphics/d3d12/pal_buffer_d3d12.c create mode 100644 src/graphics/d3d12/pal_command_pool_d3d12.c create mode 100644 src/graphics/d3d12/pal_commands_d3d12.c create mode 100644 src/graphics/d3d12/pal_d3d12.h create mode 100644 src/graphics/d3d12/pal_descriptors_d3d12.c create mode 100644 src/graphics/d3d12/pal_device_d3d12.c create mode 100644 src/graphics/d3d12/pal_image_d3d12.c create mode 100644 src/graphics/d3d12/pal_pipeline_d3d12.c create mode 100644 src/graphics/d3d12/pal_sbt_d3d12.c create mode 100644 src/graphics/d3d12/pal_swapchain_d3d12.c create mode 100644 src/graphics/d3d12/pal_sync_d3d12.c diff --git a/pal.lua b/pal.lua index f988e941..86d8ce83 100644 --- a/pal.lua +++ b/pal.lua @@ -226,7 +226,7 @@ project "PAL" d3d12Include } - --defines { "PAL_HAS_D3D12_BACKEND=1" } + defines { "PAL_HAS_D3D12_BACKEND=1" } else defines { "PAL_HAS_D3D12_BACKEND=0" } end @@ -253,7 +253,19 @@ project "PAL" if (hasD3D12) then files { - -- "src/graphics/pal_d3d12.c" + "src/graphics/d3d12/pal_adapter_d3d12.c", + "src/graphics/d3d12/pal_as_d3d12.c", + "src/graphics/d3d12/pal_buffer_d3d12.c", + "src/graphics/d3d12/pal_command_pool_d3d12.c", + "src/graphics/d3d12/pal_commands_d3d12.c", + "src/graphics/d3d12/pal_descriptors_d3d12.c", + "src/graphics/d3d12/pal_device_d3d12.c", + "src/graphics/d3d12/pal_image_d3d12.c", + "src/graphics/d3d12/pal_pipeline_d3d12.c", + "src/graphics/d3d12/pal_sbt_d3d12.c", + "src/graphics/d3d12/pal_swapchain_d3d12.c", + "src/graphics/d3d12/pal_sync_d3d12.c", + "src/graphics/d3d12/pal_d3d12.c" } end end diff --git a/src/graphics/d3d12/pal_adapter_d3d12.c b/src/graphics/d3d12/pal_adapter_d3d12.c new file mode 100644 index 00000000..e77b4487 --- /dev/null +++ b/src/graphics/d3d12/pal_adapter_d3d12.c @@ -0,0 +1,636 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" + +// From Agility SDK +#ifndef D3D_SHADER_MODEL_6_8 +#define D3D_SHADER_MODEL_6_8 0x68 +#endif // D3D_SHADER_MODEL_6_8 + +#ifndef D3D_SHADER_MODEL_6_9 +#define D3D_SHADER_MODEL_6_9 0x69 +#endif // D3D_SHADER_MODEL_6_9 + +#ifndef D3D_SHADER_MODEL_6_10 +#define D3D_SHADER_MODEL_6_10 0x6a +#endif // D3D_SHADER_MODEL_6_10 + +const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; +const IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0xd2,0x4e}; + +PalResult PAL_CALL enumerateAdaptersD3D12( + int32_t* count, + PalAdapter** outAdapters) +{ + uint32_t adapterCount = 0; + IDXGIAdapter* adapter = nullptr; + IDXGIAdapter4* dxAdapters[32]; + ID3D12Device* devices[32]; + D3D_FEATURE_LEVEL deviceLevels[32]; + + D3D_FEATURE_LEVEL levels[] = { + D3D_FEATURE_LEVEL_12_2, + D3D_FEATURE_LEVEL_12_1, + D3D_FEATURE_LEVEL_12_0, + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0 + }; + + if (s_D3D12.adapters) { + palFree(s_D3D12.allocator, s_D3D12.adapters); + } + + while (SUCCEEDED(IDXGIFactory6_EnumAdapters(s_D3D12.factory, adapterCount, &adapter))) { + if (outAdapters) { + IDXGIAdapter4* tmp = nullptr; + if (SUCCEEDED(IDXGIAdapter_QueryInterface(adapter, &IID_Adapter, (void**)&tmp))) { + dxAdapters[adapterCount] = tmp; + } + + // create a temp device for every adapter to use as an instance to check features. + ID3D12Device* device = nullptr; + for (int i = 0; i < 5; i++) { + HRESULT result = s_D3D12.createDevice( + (IUnknown*)tmp, + levels[i], + &IID_Device, + (void**)&device); + + if (SUCCEEDED(result)) { + deviceLevels[adapterCount] = levels[i]; + devices[adapterCount] = device; + break; + } + } + } + adapter->lpVtbl->Release(adapter); + adapterCount++; + } + + if (outAdapters) { + s_D3D12.adapters = palAllocate(s_D3D12.allocator, sizeof(AdapterD3D12) * adapterCount, 0); + if (!s_D3D12.adapters) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + // fill the array with AdapterD3D12 structs + for (int i = 0; i < *count; i++) { + AdapterD3D12* tmp = &s_D3D12.adapters[i]; + tmp->handle = dxAdapters[i]; + tmp->tmpDevice = devices[i]; + tmp->level = deviceLevels[i]; + tmp->reserved = PAL_BACKEND_KEY; + outAdapters[i] = (PalAdapter*)tmp; + } + s_D3D12.adapterCount = *count; + + } else { + *count = adapterCount; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL getAdapterInfoD3D12( + PalAdapter* adapter, + PalAdapterInfo* info) +{ + AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + DXGI_ADAPTER_DESC3 desc; + D3D12_FEATURE_DATA_ARCHITECTURE1 arch = {0}; + ID3D12Device* device = d3d12Adapter->tmpDevice; + + D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; + shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; + + HRESULT result = IDXGIAdapter4_GetDesc3(d3d12Adapter->handle, &desc); + if (FAILED(result)) { + return makeResultD3D12(result); + } + + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + info->shaderFormats = PAL_SHADER_FORMAT_DXBC; + if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0 && result == S_OK) { + info->shaderFormats |= PAL_SHADER_FORMAT_DXIL; + } + + info->vendorId = desc.VendorId; + info->deviceId= desc.DeviceId; + info->apiType = PAL_ADAPTER_API_TYPE_D3D12; + info->sharedMemory = desc.SharedSystemMemory; + strcpy(info->backendName, "PAL"); + + WideCharToMultiByte( + CP_UTF8, + 0, + desc.Description, + -1, + info->name, + PAL_ADAPTER_NAME_SIZE, + nullptr, + nullptr); + + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_ARCHITECTURE1, + &arch, + sizeof(arch)); + + if (arch.UMA == PAL_TRUE) { + info->type = PAL_ADAPTER_TYPE_INTEGRATED; + + } else { + info->type = PAL_ADAPTER_TYPE_DISCRETE; + } + + if (desc.Flags & DXGI_ADAPTER_FLAG3_SOFTWARE) { + info->type = PAL_ADAPTER_TYPE_CPU; + } + + if (desc.DedicatedVideoMemory > 0) { + info->vram = desc.DedicatedVideoMemory; + + } else if (desc.DedicatedVideoMemory == 0 && desc.DedicatedSystemMemory > 0) { + info->vram = desc.DedicatedSystemMemory; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL getAdapterCapabilitiesD3D12( + PalAdapter* adapter, + PalAdapterCapabilities* caps) +{ + AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + if (!d3d12Adapter->handle) { + return PAL_RESULT_CODE_INVALID_HANDLE; + } + + PalViewportCapabilities* viewportCaps = &caps->viewportCaps; + PalImageCapabilities* imageCaps = &caps->imageCaps; + PalResourceCapabilities* resourceCaps = &caps->resourceCaps; + PalComputeCapabilities* computeCaps = &caps->computeCaps; + + caps->maxComputeQueues = 2; // safe default + caps->maxGraphicsQueues = 2; // safe default + caps->maxCopyQueues = 2; // safe default + + caps->maxColorAttachments = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; + caps->maxUniformBufferSize = D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT * 16; + caps->maxStorageBufferSize = 2147483648; // 2 GIB + caps->maxPushConstantSize = 256; + + caps->maxVertexLayouts = 32; // safe + caps->maxVertexAttributes = 32; // safe + caps->maxTessellationPatchPoint = 32; + + // viewport limits + viewportCaps->maxWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + viewportCaps->maxHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + viewportCaps->minBoundsRange = (float)D3D12_VIEWPORT_BOUNDS_MIN; + viewportCaps->maxBoundsRange = (float)D3D12_VIEWPORT_BOUNDS_MAX; + + // image limits + imageCaps->maxWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + imageCaps->maxHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + imageCaps->maxDepth = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; + imageCaps->maxArrayLayers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; + + // d3d12 does not give this but we calculate from the max width and width + uint32_t a = imageCaps->maxWidth; + uint32_t b = imageCaps->maxHeight; + uint32_t c = imageCaps->maxDepth; + + uint32_t tmp = a > b ? a : b; + uint32_t size = tmp > c ? tmp : c; + uint32_t levels = 0; + while (size > 0) { + // divide by two + size = size / 2; + levels++; + } + imageCaps->maxMipLevels = levels; + + // resource limits + // always supported + getDescriptorTierLimitsD3D12(d3d12Adapter->tmpDevice, resourceCaps, nullptr); + resourceCaps->maxBoundSets = 32; + + // compute limits + computeCaps->maxWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; + computeCaps->maxWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + computeCaps->maxWorkGroupCount[1] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + computeCaps->maxWorkGroupCount[2] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; + computeCaps->maxWorkGroupSize[0] = D3D12_CS_THREAD_GROUP_MAX_X; + computeCaps->maxWorkGroupSize[1] = D3D12_CS_THREAD_GROUP_MAX_Y; + computeCaps->maxWorkGroupSize[2] = D3D12_CS_THREAD_GROUP_MAX_Z; + + return PAL_RESULT_SUCCESS; +} + +PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) +{ + HRESULT result; + AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + PalAdapterFeatures features = 0; + ID3D12Device* device = d3d12Adapter->tmpDevice; + + D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; + D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {0}; + D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = {0}; + D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {0}; + D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = {0}; + D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; + + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS, + &options, + sizeof(options)); + + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS3, + &options3, + sizeof(options3)); + + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS5, + &options5, + sizeof(options5)); + + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS6, + &options6, + sizeof(options6)); + + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_D3D12_OPTIONS7, + &options7, + sizeof(options7)); + + shaderModel.HighestShaderModel = D3D_SHADER_MODEL_5_1; + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_5_1 && result == S_OK) { + features |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; + features |= PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING; + features |= PAL_ADAPTER_FEATURE_SHADER_FLOAT64; + } + + shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_2; + result = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_2 && result == S_OK) { + features |= PAL_ADAPTER_FEATURE_SHADER_FLOAT16; + features |= PAL_ADAPTER_FEATURE_SHADER_INT16; + } + + shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; + result = device->lpVtbl->CheckFeatureSupport( + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0 && result == S_OK) { + features |= PAL_ADAPTER_FEATURE_SHADER_INT64; + } + + if (options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED) { + features |= PAL_ADAPTER_FEATURE_MULTI_VIEW; + } + + if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED) { + features |= PAL_ADAPTER_FEATURE_RAY_TRACING; + features |= PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING; + } + + if (options5.RaytracingTier >= D3D12_RAYTRACING_TIER_1_1) { + features |= PAL_ADAPTER_FEATURE_RAY_QUERY; + } + + if (options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED) { + features |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE; + features |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT; + } + + if (options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED) { + features |= PAL_ADAPTER_FEATURE_MESH_SHADER; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT; + } + + if (!(options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1)) { + features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + } + + // this features are supported on d3d12 + features |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; + features |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; + features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; + features |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; + features |= PAL_ADAPTER_FEATURE_SWAPCHAIN; + features |= PAL_ADAPTER_FEATURE_FENCE_RESET; + features |= PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE; + features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH; + features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; + features |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; + features |= PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS; + + if (d3d12Adapter->level >= D3D_FEATURE_LEVEL_12_0) { + features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; + } + return features; +} + +uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( + PalAdapter* adapter, + PalShaderFormats shaderFormat) +{ + if (shaderFormat != PAL_SHADER_FORMAT_DXIL && shaderFormat != PAL_SHADER_FORMAT_DXBC) { + return 0; + } + + if (shaderFormat == PAL_SHADER_FORMAT_DXBC) { + return PAL_MAKE_SHADER_TARGET(5, 1); + } + + AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; + + D3D_SHADER_MODEL models[11]; + models[0] = D3D_SHADER_MODEL_6_10; + models[1] = D3D_SHADER_MODEL_6_9; + models[2] = D3D_SHADER_MODEL_6_8; + models[3] = D3D_SHADER_MODEL_6_7; + models[4] = D3D_SHADER_MODEL_6_6; + models[5] = D3D_SHADER_MODEL_6_5; + models[6] = D3D_SHADER_MODEL_6_4; + models[7] = D3D_SHADER_MODEL_6_3; + models[8] = D3D_SHADER_MODEL_6_2; + models[9] = D3D_SHADER_MODEL_6_1; + models[10] = D3D_SHADER_MODEL_6_0; + + // find the highest supported shader model + HRESULT result = 0; + D3D_SHADER_MODEL highestModel = D3D_SHADER_MODEL_5_1; + for (int i = 0; i < 11; i++) { + shaderModel.HighestShaderModel = models[i]; + result = ID3D12Device_CheckFeatureSupport( + d3d12Adapter->tmpDevice, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, + sizeof(shaderModel)); + + if (shaderModel.HighestShaderModel >= models[i] && result == S_OK) { + highestModel = models[i]; + break; + } + } + + if (highestModel == D3D_SHADER_MODEL_5_1) { + return 0; + } + + if (highestModel >= D3D_SHADER_MODEL_6_10) { + return PAL_MAKE_SHADER_TARGET(6, 10); + + } else if (highestModel >= D3D_SHADER_MODEL_6_9) { + return PAL_MAKE_SHADER_TARGET(6, 9); + + } else if (highestModel >= D3D_SHADER_MODEL_6_8) { + return PAL_MAKE_SHADER_TARGET(6, 8); + + } else if (highestModel >= D3D_SHADER_MODEL_6_6) { + return PAL_MAKE_SHADER_TARGET(6, 6); + + } else if (highestModel >= D3D_SHADER_MODEL_6_5) { + return PAL_MAKE_SHADER_TARGET(6, 5); + + } else if (highestModel >= D3D_SHADER_MODEL_6_4) { + return PAL_MAKE_SHADER_TARGET(6, 4); + + } else if (highestModel >= D3D_SHADER_MODEL_6_3) { + return PAL_MAKE_SHADER_TARGET(6, 3); + + } else if (highestModel >= D3D_SHADER_MODEL_6_2) { + return PAL_MAKE_SHADER_TARGET(6, 2); + + } else if (highestModel >= D3D_SHADER_MODEL_6_1) { + return PAL_MAKE_SHADER_TARGET(6, 1); + + } else if (highestModel >= D3D_SHADER_MODEL_6_0) { + return PAL_MAKE_SHADER_TARGET(6, 0); + } + + return 0; +} + +PalResult PAL_CALL enumerateFormatsD3D12( + PalAdapter* adapter, + int32_t* count, + PalFormatInfo* outFormats) +{ + int32_t fmtCount = 0; + HRESULT result; + AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + ID3D12Device* device = d3d12Adapter->tmpDevice; + D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; + + for (int i = 0; i < PAL_FORMAT_COUNT; i++) { + DXGI_FORMAT fmt = formatToD3D12((PalFormat)i); + if (fmt == DXGI_FORMAT_UNKNOWN) { + continue; + } + + support.Format = fmt; + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, + sizeof(support)); + + if (SUCCEEDED(result)) { + if (support.Support1 == 0 && support.Support2 == 0) { + // format not supported + continue; + } + + if (outFormats) { + if (fmtCount < *count) { + PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; + fmtInfo->format = (PalFormat)i; + fmtInfo->usages = ImageUsageFromD3D12(support.Support1); + } + + } else { + fmtCount++; + } + } + } + if (!outFormats) { + *count = fmtCount; + } + return PAL_RESULT_SUCCESS; +} + +PalBool PAL_CALL isFormatSupportedD3D12( + PalAdapter* adapter, + PalFormat format) +{ + HRESULT result; + AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + ID3D12Device* device = d3d12Adapter->tmpDevice; + D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; + + DXGI_FORMAT fmt = formatToD3D12(format); + if (fmt == DXGI_FORMAT_UNKNOWN) { + return PAL_FALSE; + } + + support.Format = fmt; + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, + sizeof(support)); + + if (FAILED(result) || (support.Support1 == 0 && support.Support2 == 0)) { + return PAL_FALSE; + } + + return PAL_TRUE; +} + +PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( + PalAdapter* adapter, + PalFormat format) +{ + HRESULT result; + AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + ID3D12Device* device = d3d12Adapter->tmpDevice; + D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; + + DXGI_FORMAT fmt = formatToD3D12(format); + if (fmt == DXGI_FORMAT_UNKNOWN) { + return 0; + } + + support.Format = fmt; + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, + sizeof(support)); + + if (FAILED(result)) { + return 0; + } + + if (support.Support1 == 0 && support.Support2 == 0) { + // format not supported + return 0; + } + + PalImageUsages usages = ImageUsageFromD3D12(support.Support1); + if (support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE || + support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD) { + usages |= PAL_IMAGE_USAGE_STORAGE; + } + + return usages; +} + +PalSampleCount PAL_CALL queryFormatSampleCountD3D12( + PalAdapter* adapter, + PalFormat format) +{ + HRESULT result; + AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + ID3D12Device* device = d3d12Adapter->tmpDevice; + D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; + + DXGI_FORMAT fmt = formatToD3D12(format); + if (fmt == DXGI_FORMAT_UNKNOWN) { + return PAL_FALSE; + } + + support.Format = fmt; + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, + sizeof(support)); + + if (FAILED(result)) { + return PAL_FALSE; + } + + if (support.Support1 == 0 && support.Support2 == 0) { + // format not supported + return PAL_FALSE; + } + + // check sample count + UINT sampleCounts[] = {64, 32, 16, 8, 4, 2}; + D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS samples = {0}; + samples.Format = fmt; + + uint32_t tmp = 0; + for (int i = 0; i < 6; i++) { + samples.SampleCount = sampleCounts[i]; + result = ID3D12Device_CheckFeatureSupport( + device, + D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, + &samples, + sizeof(samples)); + + if (SUCCEEDED(result) && samples.NumQualityLevels > 0) { + tmp = samples.SampleCount; + break; + } + } + + if (tmp == 64) { + return PAL_SAMPLE_COUNT_64; + } else if (tmp == 32) { + return PAL_SAMPLE_COUNT_32; + } else if (tmp == 16) { + return PAL_SAMPLE_COUNT_16; + } else if (tmp == 8) { + return PAL_SAMPLE_COUNT_8; + } else if (tmp == 4) { + return PAL_SAMPLE_COUNT_4; + } else if (tmp == 2) { + return PAL_SAMPLE_COUNT_2; + } else { + return PAL_SAMPLE_COUNT_1; + } +} + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_as_d3d12.c b/src/graphics/d3d12/pal_as_d3d12.c new file mode 100644 index 00000000..8dae7b1d --- /dev/null +++ b/src/graphics/d3d12/pal_as_d3d12.c @@ -0,0 +1,95 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" + +PalResult PAL_CALL createAccelerationstructureD3D12( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs) +{ + HRESULT result; + AccelerationStructureD3D12* as = nullptr; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + BufferD3D12* d3dBuffer = (BufferD3D12*)info->buffer; + + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + as = palAllocate(s_D3D12.allocator, sizeof(AccelerationStructureD3D12), 0); + if (!as) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + as->type = info->type; + as->handle = d3dBuffer->handle; + as->address = as->handle->lpVtbl->GetGPUVirtualAddress(as->handle); + as->address += info->offset; + + as->reserved = PAL_BACKEND_KEY; + *outAs = (PalAccelerationStructure*)as; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as) +{ + AccelerationStructureD3D12* d3dAs = (AccelerationStructureD3D12*)as; + palFree(s_D3D12.allocator, d3dAs); +} + +PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO sizeInfo = {0}; + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; + geometries = palAllocate( + s_D3D12.allocator, + sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count, + 0); + + if (!geometries) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count); + fillBuildInfoD3D12(PAL_TRUE, info, geometries, &buildInfo); + + ID3D12Device5_GetRaytracingAccelerationStructurePrebuildInfo( + d3d12Device->handle, + &buildInfo.Inputs, + &sizeInfo); + + palFree(s_D3D12.allocator, geometries); + + } else { + fillBuildInfoD3D12(PAL_TRUE, info, nullptr, &buildInfo); + + ID3D12Device5_GetRaytracingAccelerationStructurePrebuildInfo( + d3d12Device->handle, + &buildInfo.Inputs, + &sizeInfo); + } + + size->accelerationStructureSize = sizeInfo.ResultDataMaxSizeInBytes; + size->scratchBufferSize = sizeInfo.ScratchDataSizeInBytes; + size->updateScratchBufferSize = sizeInfo.UpdateScratchDataSizeInBytes; + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_buffer_d3d12.c b/src/graphics/d3d12/pal_buffer_d3d12.c new file mode 100644 index 00000000..31b70783 --- /dev/null +++ b/src/graphics/d3d12/pal_buffer_d3d12.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND + + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_command_pool_d3d12.c b/src/graphics/d3d12/pal_command_pool_d3d12.c new file mode 100644 index 00000000..31b70783 --- /dev/null +++ b/src/graphics/d3d12/pal_command_pool_d3d12.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND + + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c new file mode 100644 index 00000000..31b70783 --- /dev/null +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND + + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_d3d12.h b/src/graphics/d3d12/pal_d3d12.h new file mode 100644 index 00000000..81a02861 --- /dev/null +++ b/src/graphics/d3d12/pal_d3d12.h @@ -0,0 +1,405 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_D3D12_H +#define _PAL_D3D12_H + +#if PAL_HAS_D3D12_BACKEND +#define COBJMACROS +#include "pal/pal_graphics.h" +#include +#include +#include +#include + +#define MAX_RTV 1024 +#define MAX_DSV 512 + +typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( + UINT, + REFIID, + void**); + +typedef HRESULT (__stdcall *PFN_D3D12SerializeVersionedRootSignature)( + const D3D12_VERSIONED_ROOT_SIGNATURE_DESC*, + ID3DBlob**, + ID3DBlob**); + +typedef struct { + uint32_t incrementSize; + uint32_t freeTop; + uint64_t baseOffset; + ID3D12DescriptorHeap* heap; + uint32_t freeList[MAX_RTV]; +} RTVHeapAllocator; + +typedef struct { + uint32_t incrementSize; + uint32_t freeTop; + uint64_t baseOffset; + ID3D12DescriptorHeap* heap; + uint32_t freeList[MAX_DSV]; +} DSVHeapAllocator; + +typedef struct { + uint32_t freeComputeQueues; + uint32_t freeGraphicsQueues; + uint32_t freeCopyQueues; + uint32_t maxVertexLayouts; + uint32_t maxVertexAttributes; + + uint32_t maxAnisotropy; + uint32_t maxPushConstantSize; + uint32_t maxTessellationPatchPoint; + + uint32_t maxDescriptorSampledImages; + uint32_t maxDescriptorStorageImages; + uint32_t maxDescriptorSamplers; + uint32_t maxDescriptorStorageBuffers; + uint32_t maxDescriptorUniformBuffers; + uint32_t maxBoundDescriptorSets; + + uint32_t maxRecursionDepth; + uint32_t maxHitAttributeSize; + uint32_t maxPayloadSize; + uint32_t maxDispatchInvocations; + uint32_t maxDescriptorAccelerationStructures; +} DeviceLimits; + +typedef struct { + uint32_t patchControlPoints; + PalShaderStage stage; + wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; +} ShaderEntry; + +typedef struct { + PalBool isHitGroup; + PalShaderStage stage; + wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; +} ShaderExport; + +typedef struct { + wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; + D3D12_HIT_GROUP_DESC desc; +} RayHitGroup; + +typedef struct { + uint32_t raygenCount; + uint32_t raygenDataSize; + uint32_t missCount; + uint32_t missDataSize; + uint32_t hitCount; + uint32_t hitDataSize; + uint32_t callableCount; + uint32_t callableDataSize; +} ShaderBindingTableInfo; + +typedef struct { + uint32_t incrementSize; + uint32_t nextOffset; + uint64_t cpuBase; + uint64_t gpuBase; + ID3D12DescriptorHeap* handle; +} DescriptorHeap; + +typedef struct { + uint32_t maxUniformBuffers; + uint32_t maxSampledImages; + uint32_t maxStorageBuffers; + uint32_t maxSamplers; + uint32_t maxStorageImages; + uint32_t maxAs; + + uint32_t usedUniformBuffers; + uint32_t usedSampledImages; + uint32_t usedStorageBuffers; + uint32_t usedSamplers; + uint32_t usedStorageImages; + uint32_t usedAs; +} DescriptorHeapLimits; + +typedef struct { + uint32_t incrementSize; + uint32_t nextOffset; + uint64_t cpuBase; + uint64_t gpuBase; + ID3D12DescriptorHeap* handle; +} DescriptorHeap; + +typedef struct { + uint32_t maxUniformBuffers; + uint32_t maxSampledImages; + uint32_t maxStorageBuffers; + uint32_t maxSamplers; + uint32_t maxStorageImages; + uint32_t maxAs; + + uint32_t usedUniformBuffers; + uint32_t usedSampledImages; + uint32_t usedStorageBuffers; + uint32_t usedSamplers; + uint32_t usedStorageImages; + uint32_t usedAs; +} DescriptorHeapLimits; + +typedef struct { + PalDescriptorType type; + D3D12_DESCRIPTOR_RANGE1 range; +} DescriptorSetBinding; + +typedef struct { + uint32_t startIndex; + uint32_t offset; + D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE region; +} AddressRegion; + +typedef struct { + void* reserved; + D3D_FEATURE_LEVEL level; + ID3D12Device* tmpDevice; + IDXGIAdapter4* handle; +} AdapterD3D12; + +typedef struct { + void* reserved; + uint32_t shaderModel; + PalAdapterFeatures features; + IDXGIAdapter4* adapter; + ID3D12CommandSignature* meshSignature; + ID3D12CommandSignature* drawIndexedSignature; + ID3D12CommandSignature* drawSignature; + ID3D12CommandSignature* dispatchSignature; + ID3D12CommandSignature* raySignature; + ID3D12InfoQueue* infoQueue; + ID3D12CommandQueue* queue; + ID3D12Device5* handle; + RTVHeapAllocator rtvAllocator; + DSVHeapAllocator dsvAllocator; + DeviceLimits limits; +} DeviceD3D12; + +typedef struct { + void* reserved; + uint32_t fenceValue; + PalQueueType type; + ID3D12Fence* fence; + ID3D12CommandQueue* handle; +} QueueD3D12; + +typedef struct { + void* reserved; + HWND handle; +} SurfaceD3D12; + +typedef struct { + void* reserved; + DeviceD3D12* device; + ID3D12Resource* handle; + PalImageInfo info; + D3D12_RESOURCE_DESC desc; +} ImageD3D12; + +typedef struct { + void* reserved; + uint32_t heapIndex; + PalImageViewType type; + DXGI_FORMAT format; + ImageD3D12* image; + DeviceD3D12* device; + PalImageSubresourceRange range; +} ImageViewD3D12; + +typedef struct { + void* reserved; + D3D12_SAMPLER_DESC desc; +} SamplerD3D12; + +typedef struct { + void* reserved; + uint32_t imageCount; + uint32_t syncInterval; + uint32_t windowWidth; + uint32_t windowHeight; + uint32_t flags; + DXGI_FORMAT format; + DXGI_FEATURE presentFlags; + SurfaceD3D12* surface; + ImageD3D12* images; + DeviceD3D12* device; + ID3D12CommandQueue* queue; + IDXGISwapChain3* handle; +} SwapchainD3D12; + +typedef struct { + void* reserved; + PalBool isTimeline; + PalBool canReset; + UINT64 value; + ID3D12Fence* handle; + HANDLE event; +} FenceD3D12, SemaphoreD3D12; + +typedef struct { + void* reserved; + uint32_t entryCount; + D3D12_SHADER_BYTECODE byteCode; + ShaderEntry* entries; +} ShaderD3D12; + +typedef struct { + void* reserved; + PalBool primary; + void* pool; // CommandPool + DeviceD3D12* device; + ID3D12Resource* stagingBuffer; + ID3D12Resource* buffer; + ID3D12CommandAllocator* allocator; + void* pipeline; + ID3D12GraphicsCommandList6* handle; +} CommandBufferD3D12; + +typedef struct { + PalBool used; + CommandBufferD3D12* cmdBuffer; +} CommandBufferData; + +typedef struct { + void* reserved; + uint32_t size; + D3D12_COMMAND_LIST_TYPE type; + CommandBufferData* cmdBuffersData; +} CommandPoolD3D12; + +typedef struct { + void* reserved; + PalBool supportsAddress; + PalBool canChangeState; + PalBool hasIndirect; + PalBool isAccelerationStructure; + PalBool isScratch; + uint64_t size; + ID3D12Resource* handle; + DeviceD3D12* device; + D3D12_RESOURCE_DESC desc; +} BufferD3D12; + +typedef struct { + void* reserved; + PalAccelerationStructureType type; + D3D12_GPU_VIRTUAL_ADDRESS address; + ID3D12Resource* handle; +} AccelerationStructureD3D12; + +typedef struct { + void* reserved; + uint32_t constantIndex; + ID3D12RootSignature* handle; +} PipelineLayoutD3D12; + +typedef struct { + void* reserved; + PalBool hasFsr; + uint32_t type; + uint32_t shaderExportCount; + D3D12_SHADING_RATE shadingRate; + D3D_PRIMITIVE_TOPOLOGY topology; + uint32_t* strides; + void* handle; + ShaderExport* shaderExports; + PipelineLayoutD3D12* layout; + ID3D12RootSignature* localRootSignature; + D3D12_SHADING_RATE_COMBINER combinerOps[2]; + ShaderBindingTableInfo sbtInfo; +} PipelineD3D12; + +typedef struct { + void* reserved; + PalBool isDirty; + uint32_t stagingBufferSize; + uint32_t handleSize; + ID3D12Resource* buffer; + ID3D12Resource* stagingBuffer; + D3D12_GPU_VIRTUAL_ADDRESS baseAddress; + PipelineD3D12* pipeline; + + AddressRegion raygen; + AddressRegion miss; + AddressRegion hit; + AddressRegion callable; +} ShaderBindingTableD3D12; + +typedef struct { + void* reserved; + PalDescriptorIndexingFlags flags; + uint32_t bindingCount; + uint32_t samplerCount; + DescriptorSetBinding* bindings; +} DescriptorSetLayoutD3D12; + +typedef struct { + void* reserved; + uint32_t resourceOffset; + uint32_t samplerOffset; + DescriptorSetLayoutD3D12* layout; + void* pool; // DescriptorPool +} DescriptorSetD3D12; + +typedef struct { + void* reserved; + PalDescriptorIndexingFlags flags; + PalBool hasResourceHeap; + PalBool hasSamplerHeap; + uint32_t maxSets; + uint32_t usedSets; + DescriptorHeapLimits limits; + DescriptorHeap resourceHeap; + DescriptorHeap samplerHeap; + DescriptorSetD3D12* sets; +} DescriptorPoolD3D12; + +typedef struct { + PalBool debugLayer; + uint32_t adapterCount; + uint32_t severityCount; + uint32_t categoryCount; + HMODULE handle; + HMODULE dxgi; + AdapterD3D12* adapters; + IDXGIFactory6* factory; + + PFN_D3D12_CREATE_DEVICE createDevice; + PFN_CreateDXGIFactory2 createDXGIFactory; + PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface; + PFN_D3D12SerializeVersionedRootSignature serializeVersionedRootSignature; + + PalDebugCallback debugCallback; + void* debugUserData; + const PalAllocator* allocator; + D3D12_MESSAGE_SEVERITY severities[6]; + D3D12_MESSAGE_CATEGORY categories[12]; +} D3D12; + +PalResult makeResultD3D12(HRESULT result); +void pollMessagesD3D12(DeviceD3D12* device); +DXGI_FORMAT formatToD3D12(PalFormat format); +PalImageUsages ImageUsageFromD3D12(D3D12_FORMAT_SUPPORT1 flags); + +void fillBuildInfoD3D12( + PalBool getBuildSize, + PalAccelerationStructureBuildInfo* info, + D3D12_RAYTRACING_GEOMETRY_DESC* geometries, + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC* buildInfo); + +void getDescriptorTierLimitsD3D12( + void* device, + PalResourceCapabilities* caps, + PalDescriptorIndexingCapabilities* descCaps); + +extern D3D12 s_D3D12; + +#endif // PAL_HAS_D3D12_BACKEND +#endif // _PAL_D3D12_H \ No newline at end of file diff --git a/src/graphics/d3d12/pal_descriptors_d3d12.c b/src/graphics/d3d12/pal_descriptors_d3d12.c new file mode 100644 index 00000000..31b70783 --- /dev/null +++ b/src/graphics/d3d12/pal_descriptors_d3d12.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND + + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c new file mode 100644 index 00000000..31b70783 --- /dev/null +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND + + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_image_d3d12.c b/src/graphics/d3d12/pal_image_d3d12.c new file mode 100644 index 00000000..31b70783 --- /dev/null +++ b/src/graphics/d3d12/pal_image_d3d12.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND + + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_pipeline_d3d12.c b/src/graphics/d3d12/pal_pipeline_d3d12.c new file mode 100644 index 00000000..31b70783 --- /dev/null +++ b/src/graphics/d3d12/pal_pipeline_d3d12.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND + + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_sbt_d3d12.c b/src/graphics/d3d12/pal_sbt_d3d12.c new file mode 100644 index 00000000..9032c814 --- /dev/null +++ b/src/graphics/d3d12/pal_sbt_d3d12.c @@ -0,0 +1,429 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" + +#define align(v, a) (v + a - 1) & ~(a - 1) + +// clang-format +const IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad}; +const IID IID_StateObjectProps = {0xde5fa827, 0x9bf9, 0x4f26, 0x89,0xff, 0xd7,0xf5,0x6f,0xde,0x38,0x60}; +// clang-format on + +PalResult PAL_CALL createShaderBindingTableD3D12( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt) +{ + HRESULT result; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + ShaderBindingTableD3D12* sbt = nullptr; + PipelineD3D12* pipeline = (PipelineD3D12*)info->rayTracingPipeline; + ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; + + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + uint32_t totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; + totalGroups += sbtInfo->missCount + sbtInfo->callableCount; + if (info->recordCount != totalGroups) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + void** raygenHandles = nullptr; + void** missHandles = nullptr; + void** hitHandles = nullptr; + void** callableHandles = nullptr; + + sbt = palAllocate(s_D3D12.allocator, sizeof(ShaderBindingTableD3D12), 0); + if (!sbt) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(sbt, 0, sizeof(ShaderBindingTableD3D12)); + if (sbtInfo->raygenCount) { + raygenHandles = palAllocate(s_D3D12.allocator, sizeof(void*) * sbtInfo->raygenCount, 0); + if (!raygenHandles) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + } + + if (sbtInfo->missCount) { + missHandles = palAllocate(s_D3D12.allocator, sizeof(void*) * sbtInfo->missCount, 0); + if (!missHandles) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + } + + if (sbtInfo->hitCount) { + hitHandles = palAllocate(s_D3D12.allocator, sizeof(void*) * sbtInfo->hitCount, 0); + if (!hitHandles) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + } + + if (sbtInfo->callableCount) { + callableHandles = palAllocate(s_D3D12.allocator, sizeof(void*) * sbtInfo->callableCount, 0); + if (!callableHandles) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + } + + // create SBT buffer + ID3D12StateObject* handle = pipeline->handle; + ID3D12StateObjectProperties* props = NULL; + result = ID3D12StateObject_QueryInterface(handle, &IID_StateObjectProps, (void**)&props); + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + return makeResultD3D12(result); + } + + uint32_t groupHandleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; + uint32_t groupHandleAlignment = D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT; + uint32_t groupBaseAlignment = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; + + // get the max local data size + for (int i = 0; i < info->recordCount; i++) { + PalShaderBindingTableRecordInfo* record = &info->records[i]; + uint32_t index = record->groupIndex; + + if (index < sbtInfo->raygenCount) { + // raygen group + if (record->localDataSize > sbtInfo->raygenDataSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { + // miss group + if (record->localDataSize > sbtInfo->missDataSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { + // hit group + if (record->localDataSize > sbtInfo->hitDataSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + } else { + // callable group + if (record->localDataSize > sbtInfo->callableDataSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + } + } + + // get strides + uint32_t raygenStride = 0; + uint32_t missStride = 0; + uint32_t hitStride = 0; + uint32_t callableStride = 0; + + raygenStride = align(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); + missStride = align(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); + hitStride = align(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); + callableStride = align(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); + + // get region size + uint32_t raygenRegionSize = raygenStride * sbtInfo->raygenCount; + uint32_t missRegionSize = missStride * sbtInfo->missCount; + uint32_t hitRegionSize = hitStride * sbtInfo->hitCount; + uint32_t callableRegionSize = callableStride * sbtInfo->callableCount; + + // get offsets + uint32_t offset = 0; + uint32_t raygenOffset = 0; + uint32_t missOffset = 0; + uint32_t hitOffset = 0; + uint32_t callableOffset = 0; + + raygenOffset = align(offset, groupBaseAlignment); + offset = raygenOffset + raygenRegionSize; + + missOffset = align(offset, groupBaseAlignment); + offset = missOffset + missRegionSize; + + hitOffset = align(offset, groupBaseAlignment); + offset = hitOffset + hitRegionSize; + + callableOffset = align(offset, groupBaseAlignment); + offset = callableOffset + callableRegionSize; + uint32_t bufferSize = align(offset, groupBaseAlignment); + + // create gpu buffer + D3D12_HEAP_PROPERTIES heapProps = {0}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + + D3D12_RESOURCE_DESC bufferDesc = {0}; + bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + bufferDesc.Width = bufferSize; + bufferDesc.Height = 1; + bufferDesc.DepthOrArraySize = 1; + bufferDesc.MipLevels = 1; + bufferDesc.SampleDesc.Count = 1; + bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + + result = ID3D12Device5_CreateCommittedResource( + d3d12Device->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + &IID_Resource, + (void**)&sbt->buffer); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + // create staging buffer + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + result = ID3D12Device5_CreateCommittedResource( + d3d12Device->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + &IID_Resource, + (void**)&sbt->stagingBuffer); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + // get shader group handles + uint32_t raygenIndex = 0; + uint32_t missIndex = 0; + uint32_t hitIndex = 0; + uint32_t callableIndex = 0; + + for (int i = 0; i < pipeline->shaderExportCount; i++) { + ShaderExport* tmp = &pipeline->shaderExports[i]; + PalShaderStage stage = tmp->stage; + + // skip any hit, closest hit, intersection shaders without isHitGroup PalBool + PalBool isHitGroup = PAL_FALSE; + if (stage == PAL_SHADER_STAGE_ANY_HIT || + stage == PAL_SHADER_STAGE_CLOSEST_HIT || + stage == PAL_SHADER_STAGE_INTERSECTION) { + if (tmp->isHitGroup) { + isHitGroup = PAL_TRUE; + + } else { + continue; + } + } + + void* handle = ID3D12StateObjectProperties_GetShaderIdentifier(props, tmp->entryName); + if (stage == PAL_SHADER_STAGE_RAYGEN) { + raygenHandles[raygenIndex++] = handle; + + } else if (stage == PAL_SHADER_STAGE_MISS) { + missHandles[missIndex++] = handle; + + } else if (isHitGroup) { + hitHandles[hitIndex++] = handle; + + } else if (stage == PAL_SHADER_STAGE_CALLABLE) { + callableHandles[callableIndex++] = handle; + } + } + + // copy handles into the buffer + offset = 0; // reuse variable + void* ptr = nullptr; + result = ID3D12Resource_Map(sbt->stagingBuffer, 0, nullptr, &ptr); + if (FAILED(result)) { + return makeResultD3D12(result); + } + + // raygen + for (int i = 0; i < sbtInfo->raygenCount; i++) { + uint8_t* dstPtr = (uint8_t*)ptr + (i * raygenStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, raygenHandles[i], groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } + } + offset += sbtInfo->raygenCount; + + // miss + for (int i = 0; i < sbtInfo->missCount; i++) { + uint8_t* dstPtr = (uint8_t*)ptr + missOffset + (i * missStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, missHandles[i], groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } + } + offset += sbtInfo->missCount; + + // hit group + for (int i = 0; i < sbtInfo->hitCount; i++) { + uint8_t* dstPtr = (uint8_t*)ptr + hitOffset + (i * hitStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, hitHandles[i], groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } + } + offset += sbtInfo->hitCount; + + // callable + for (int i = 0; i < sbtInfo->callableCount; i++) { + uint8_t* dstPtr = (uint8_t*)ptr + callableOffset + (i * callableStride); + PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; + + memcpy(dstPtr, callableHandles[i], groupHandleSize); + if (record->localDataSize) { + // this record has local data + memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); + } + } + + ID3D12Resource_Unmap(sbt->stagingBuffer, 0, nullptr); + sbt->baseAddress = ID3D12Resource_GetGPUVirtualAddress(sbt->buffer); + + // raygen + if (sbtInfo->raygenCount) { + sbt->raygen.region.StartAddress = sbt->baseAddress; + sbt->raygen.offset = 0; // always + sbt->raygen.startIndex = 0; // always + sbt->raygen.region.SizeInBytes = raygenRegionSize; + sbt->raygen.region.StrideInBytes = raygenStride; + + palFree(s_D3D12.allocator, raygenHandles); + } + + // miss + if (sbtInfo->missCount) { + sbt->miss.offset = missOffset; + sbt->miss.startIndex = sbtInfo->raygenCount; + sbt->miss.region.StartAddress = sbt->baseAddress + missOffset; + sbt->miss.region.SizeInBytes = missRegionSize; + sbt->miss.region.StrideInBytes = missStride; + + palFree(s_D3D12.allocator, missHandles); + } + + // hit + if (sbtInfo->hitCount) { + sbt->hit.offset = hitOffset; + sbt->hit.startIndex = sbtInfo->raygenCount + sbtInfo->missCount; + sbt->hit.region.StartAddress = sbt->baseAddress + hitOffset; + sbt->hit.region.SizeInBytes = hitRegionSize; + sbt->hit.region.StrideInBytes = hitStride; + + palFree(s_D3D12.allocator, hitHandles); + } + + // callable + if (sbtInfo->callableCount) { + sbt->callable.offset = callableOffset; + sbt->callable.startIndex = sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount; + sbt->callable.region.StartAddress = sbt->baseAddress + callableOffset; + sbt->callable.region.SizeInBytes = callableRegionSize; + sbt->callable.region.StrideInBytes = callableStride; + + palFree(s_D3D12.allocator, callableHandles); + } + + ID3D12StateObjectProperties_Release(props); + sbt->handleSize = groupHandleSize; + sbt->stagingBufferSize = bufferSize; + sbt->pipeline = pipeline; + + sbt->reserved = PAL_BACKEND_KEY; + sbt->isDirty = PAL_TRUE; // we need to copy from the staging to the gpu buffer + *outSbt = (PalShaderBindingTable*)sbt; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) +{ + ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; + ID3D12Resource_Release(d3d12Sbt->buffer); + ID3D12Resource_Release(d3d12Sbt->stagingBuffer); + palFree(s_D3D12.allocator, d3d12Sbt); +} + +PalResult PAL_CALL updateShaderBindingTableD3D12( + PalShaderBindingTable* sbt, + uint32_t count, + PalShaderBindingTableRecordInfo* infos) +{ + HRESULT result; + ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; + PipelineD3D12* pipeline = d3d12Sbt->pipeline; + ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; + + void* data = nullptr; + result = ID3D12Resource_Map(d3d12Sbt->stagingBuffer, 0, nullptr, &data); + if (FAILED(result)) { + return makeResultD3D12(result); + } + + uint64_t stride = 0; + uint64_t offset = 0; + uint32_t startIndex = 0; + + for (int i = 0; i < count; i++) { + PalShaderBindingTableRecordInfo* info = &infos[i]; + if (!info->localDataSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + // find the group the record belongs to + uint32_t index = info->groupIndex; + if (index < sbtInfo->raygenCount) { + // raygen group + offset = 0; + stride = d3d12Sbt->raygen.region.StrideInBytes; + startIndex = d3d12Sbt->raygen.startIndex; + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { + // miss group + offset = d3d12Sbt->miss.offset; + stride = d3d12Sbt->miss.region.StrideInBytes; + startIndex = d3d12Sbt->miss.startIndex; + + } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { + // hit group + offset = d3d12Sbt->hit.offset; + stride = d3d12Sbt->hit.region.StrideInBytes; + startIndex = d3d12Sbt->hit.startIndex; + + } else { + // callable group + offset = d3d12Sbt->callable.offset; + stride = d3d12Sbt->callable.region.StrideInBytes; + startIndex = d3d12Sbt->callable.startIndex; + } + + // write payload + uint32_t localIndex = index - startIndex; + uint8_t* dst = (uint8_t*)data + offset + (localIndex * stride); + memcpy(dst + d3d12Sbt->handleSize, info->localData, info->localDataSize); + } + + ID3D12Resource_Unmap(d3d12Sbt->stagingBuffer, 0, nullptr); + d3d12Sbt->isDirty = PAL_TRUE; + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_swapchain_d3d12.c b/src/graphics/d3d12/pal_swapchain_d3d12.c new file mode 100644 index 00000000..31b70783 --- /dev/null +++ b/src/graphics/d3d12/pal_swapchain_d3d12.c @@ -0,0 +1,11 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND + + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_sync_d3d12.c b/src/graphics/d3d12/pal_sync_d3d12.c new file mode 100644 index 00000000..39cf0bce --- /dev/null +++ b/src/graphics/d3d12/pal_sync_d3d12.c @@ -0,0 +1,236 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" + +const IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; + +PalResult PAL_CALL createFenceD3D12( + PalDevice* device, + PalBool signaled, + PalFence** outFence) +{ + HRESULT result; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + FenceD3D12* fence = nullptr; + + fence = palAllocate(s_D3D12.allocator, sizeof(FenceD3D12), 0); + if (!fence) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + result = ID3D12Device5_CreateFence(d3d12Device->handle, 0, 0, &IID_Fence, &fence->handle); + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + palFree(s_D3D12.allocator, fence); + return makeResultD3D12(result); + } + + // create event + fence->event = CreateEvent(nullptr, PAL_FALSE, PAL_FALSE, nullptr); + if (!fence->event) { + return palMakeResult( + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, + GetLastError()); + } + + fence->canReset = PAL_FALSE; + if (d3d12Device->features & PAL_ADAPTER_FEATURE_FENCE_RESET) { + fence->canReset = PAL_TRUE; + } + + fence->isTimeline = PAL_FALSE; // for sempaphores + fence->value = 0; + fence->reserved = PAL_BACKEND_KEY; + *outFence = (PalFence*)fence; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyFenceD3D12(PalFence* fence) +{ + FenceD3D12* d3d12Fence = (FenceD3D12*)fence; + ID3D12Fence_Release(d3d12Fence->handle); + CloseHandle(d3d12Fence->event); + palFree(s_D3D12.allocator, d3d12Fence); +} + +PalResult PAL_CALL waitFenceD3D12( + PalFence* fence, + uint64_t timeout) +{ + HRESULT result; + FenceD3D12* d3d12Fence = (FenceD3D12*)fence; + DWORD ret = 0; + uint64_t value = d3d12Fence->value; + HANDLE event = d3d12Fence->event; + + if (ID3D12Fence_GetCompletedValue(d3d12Fence->handle) < value) { + result = ID3D12Fence_SetEventOnCompletion(d3d12Fence->handle, value, event); + if (FAILED(result)) { + return makeResultD3D12(result); + } + + if (timeout == PAL_INFINITE) { + ret = WaitForSingleObject(event, INFINITE); + } else { + ret = WaitForSingleObject(event, (DWORD)timeout); + } + } + + if (ret == WAIT_TIMEOUT) { + return PAL_RESULT_CODE_TIMEOUT; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL resetFenceD3D12(PalFence* fence) +{ + FenceD3D12* d3d12Fence = (FenceD3D12*)fence; + if (!d3d12Fence->canReset) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + ID3D12Fence_Signal(d3d12Fence->handle, 0); + d3d12Fence->value = 0; + return PAL_RESULT_SUCCESS; +} + +PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence) +{ + FenceD3D12* d3d12Fence = (FenceD3D12*)fence; + if (ID3D12Fence_GetCompletedValue(d3d12Fence->handle) == 0) { + return PAL_FALSE; + } + return PAL_TRUE; +} + +PalResult PAL_CALL createSemaphoreD3D12( + PalDevice* device, + PalBool enableTimeline, + PalSemaphore** outSemaphore) +{ + HRESULT result; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + SemaphoreD3D12* semaphore = nullptr; + + PalBool hasTimeline = PAL_FALSE; + if (d3d12Device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + hasTimeline = PAL_TRUE; + } + + semaphore = palAllocate(s_D3D12.allocator, sizeof(SemaphoreD3D12), 0); + if (!semaphore) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + if (enableTimeline && !hasTimeline) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (enableTimeline) { + semaphore->isTimeline = PAL_TRUE; + } + + result = ID3D12Device5_CreateFence(d3d12Device->handle, 0, 0, &IID_Fence, &semaphore->handle); + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + palFree(s_D3D12.allocator, semaphore); + return makeResultD3D12(result); + } + + // create event + semaphore->event = CreateEvent(nullptr, PAL_FALSE, PAL_FALSE, nullptr); + if (!semaphore->event) { + return palMakeResult( + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, + GetLastError()); + } + + semaphore->canReset = PAL_FALSE; + semaphore->value = 0; + semaphore->reserved = PAL_BACKEND_KEY; + *outSemaphore = (PalSemaphore*)semaphore; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore) +{ + SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; + ID3D12Fence_Release(d3d12Semaphore->handle); + CloseHandle(d3d12Semaphore->event); + palFree(s_D3D12.allocator, d3d12Semaphore); +} + +PalResult PAL_CALL waitSemaphoreD3D12( + PalSemaphore* semaphore, + uint64_t value, + uint64_t timeout) +{ + HRESULT result; + DWORD ret = 0; + SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; + if (!d3d12Semaphore->isTimeline) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + HANDLE event = d3d12Semaphore->event; + if (ID3D12Fence_GetCompletedValue(d3d12Semaphore->handle) < value) { + result = ID3D12Fence_SetEventOnCompletion(d3d12Semaphore->handle, value, event); + if (FAILED(result)) { + return makeResultD3D12(result); + } + + if (timeout == PAL_INFINITE) { + ret = WaitForSingleObject(event, INFINITE); + } else { + ret = WaitForSingleObject(event, (DWORD)timeout); + } + } + + if (ret == WAIT_TIMEOUT) { + return PAL_RESULT_CODE_TIMEOUT; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL signalSemaphoreD3D12( + PalSemaphore* semaphore, + PalQueue* queue, + uint64_t value) +{ + SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; + if (!d3d12Semaphore->isTimeline) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + HRESULT result = ID3D12Fence_Signal(d3d12Semaphore->handle, value); + if (FAILED(result)) { + return makeResultD3D12(result); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL getSemaphoreValueD3D12( + PalSemaphore* semaphore, + uint64_t* outValue) +{ + SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; + if (!d3d12Semaphore->isTimeline) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + UINT64 tmp = ID3D12Fence_GetCompletedValue(d3d12Semaphore->handle); + *outValue = tmp; + return PAL_RESULT_SUCCESS; +} + +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 96ceb274..1c04c3da 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -19,23 +19,6 @@ #include #include -// ================================================== -// Typedefs, enums and structs -// ================================================== - -// From Agility SDK -#ifndef D3D_SHADER_MODEL_6_8 -#define D3D_SHADER_MODEL_6_8 0x68 -#endif // D3D_SHADER_MODEL_6_8 - -#ifndef D3D_SHADER_MODEL_6_9 -#define D3D_SHADER_MODEL_6_9 0x69 -#endif // D3D_SHADER_MODEL_6_9 - -#ifndef D3D_SHADER_MODEL_6_10 -#define D3D_SHADER_MODEL_6_10 0x6a -#endif // D3D_SHADER_MODEL_6_10 - // on older SDKs, D3D_FEATURE_LEVEL_12_2 is not defined #ifndef D3D_FEATURE_LEVEL_12_2 #define D3D_FEATURE_LEVEL_12_2 0xc200 @@ -43,8 +26,6 @@ #define MAX_ATTACHMENTS 32 #define TEXTURE_PITCH 256 -#define MAX_RTV 1024 -#define MAX_DSV 512 #define MAX_MESSAGE_SIZE 4096 #define GRAPHICS_PIPELINE 1220 @@ -67,16 +48,13 @@ // clang-format off // IIDS -const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; -const IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0xd2,0x4e}; + const IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0,0x3c, 0x77,0x90,0x0a,0x0a,0x1d,0x17}; const IID IID_DebugController = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0}; const IID IID_DebugController1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; const IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4,0xe6,0x14,0x58}; const IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3}; const IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed}; -const IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; -const IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad}; const IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1}; const IID IID_CommandAllocator = {0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73,0xf0,0x9b,0x24}; const IID IID_CommandList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5}; @@ -87,371 +65,8 @@ const IID IID_RootSignature = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46, const IID IID_Device5 = {0x8b4f173b, 0x2fea, 0x4b80, 0x8f,0x58, 0x43,0x07,0x19,0x1a,0xb9,0x5d}; const IID IID_PipelineState = {0x765a30f3, 0xf624, 0x4c6f, 0xa8,0x28, 0xac,0xe9,0x48,0x62,0x24,0x45}; const IID IID_StateObject = {0x47016943, 0xfca8, 0x4594, 0x93,0xea, 0xaf,0x25,0x8b,0x55,0x34,0x6d}; -const IID IID_StateObjectProps = {0xde5fa827, 0x9bf9, 0x4f26, 0x89,0xff, 0xd7,0xf5,0x6f,0xde,0x38,0x60}; // clang-format on -typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( - UINT, - REFIID, - void**); - -typedef HRESULT (__stdcall *PFN_D3D12SerializeVersionedRootSignature)( - const D3D12_VERSIONED_ROOT_SIGNATURE_DESC*, - ID3DBlob**, - ID3DBlob**); - -typedef struct { - const PalGraphicsBackend* backend; - - D3D_FEATURE_LEVEL level; - ID3D12Device* tmpDevice; - IDXGIAdapter4* handle; -} Adapter; - -typedef struct { - PalBool debugLayer; - uint32_t adapterCount; - uint32_t severityCount; - uint32_t categoryCount; - HMODULE handle; - HMODULE dxgi; - Adapter* adapters; - IDXGIFactory6* factory; - - PFN_D3D12_CREATE_DEVICE createDevice; - PFN_CreateDXGIFactory2 createDXGIFactory; - PFN_D3D12_GET_DEBUG_INTERFACE getDebugInterface; - PFN_D3D12SerializeVersionedRootSignature serializeVersionedRootSignature; - - PalDebugCallback debugCallback; - void* debugUserData; - const PalAllocator* allocator; - D3D12_MESSAGE_SEVERITY severities[6]; - D3D12_MESSAGE_CATEGORY categories[12]; -} D3D12; - -typedef struct { - uint32_t incrementSize; - uint32_t freeTop; - uint64_t baseOffset; - ID3D12DescriptorHeap* heap; - uint32_t freeList[MAX_RTV]; -} RTVHeapAllocator; - -typedef struct { - uint32_t incrementSize; - uint32_t freeTop; - uint64_t baseOffset; - ID3D12DescriptorHeap* heap; - uint32_t freeList[MAX_DSV]; -} DSVHeapAllocator; - -// Limits we must enforce ourselves -typedef struct { - uint32_t freeComputeQueues; - uint32_t freeGraphicsQueues; - uint32_t freeCopyQueues; - uint32_t maxVertexLayouts; - uint32_t maxVertexAttributes; - - uint32_t maxAnisotropy; - uint32_t maxPushConstantSize; - uint32_t maxTessellationPatchPoint; - - uint32_t maxDescriptorSampledImages; - uint32_t maxDescriptorStorageImages; - uint32_t maxDescriptorSamplers; - uint32_t maxDescriptorStorageBuffers; - uint32_t maxDescriptorUniformBuffers; - uint32_t maxBoundDescriptorSets; - - uint32_t maxRecursionDepth; - uint32_t maxHitAttributeSize; - uint32_t maxPayloadSize; - uint32_t maxDispatchInvocations; - uint32_t maxDescriptorAccelerationStructures; -} DeviceLimits; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t shaderModel; - PalAdapterFeatures features; - IDXGIAdapter4* adapter; - ID3D12CommandSignature* meshSignature; - ID3D12CommandSignature* drawIndexedSignature; - ID3D12CommandSignature* drawSignature; - ID3D12CommandSignature* dispatchSignature; - ID3D12CommandSignature* raySignature; - ID3D12InfoQueue* infoQueue; - ID3D12CommandQueue* queue; - ID3D12Device5* handle; - RTVHeapAllocator rtvAllocator; - DSVHeapAllocator dsvAllocator; - DeviceLimits limits; -} Device; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t fenceValue; - PalQueueType type; - ID3D12Fence* fence; - ID3D12CommandQueue* handle; -} Queue; - -typedef struct { - const PalGraphicsBackend* backend; - - HWND handle; -} Surface; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool belongsToSwapchain; - Device* device; - ID3D12Resource* handle; - PalImageInfo info; - D3D12_RESOURCE_DESC desc; -} Image; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t heapIndex; - PalImageViewType type; - DXGI_FORMAT format; - Image* image; - Device* device; - PalImageSubresourceRange range; -} ImageView; - -typedef struct { - const PalGraphicsBackend* backend; - - D3D12_SAMPLER_DESC desc; -} Sampler; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t imageCount; - uint32_t syncInterval; - uint32_t windowWidth; - uint32_t windowHeight; - uint32_t flags; - DXGI_FORMAT format; - DXGI_FEATURE presentFlags; - Surface* surface; - Image* images; - Device* device; - ID3D12CommandQueue* queue; - IDXGISwapChain3* handle; -} Swapchain; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool isTimeline; - PalBool canReset; - UINT64 value; - ID3D12Fence* handle; -} Fence, Semaphore; - -typedef struct { - uint32_t patchControlPoints; - PalShaderStage stage; - wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; -} ShaderEntry; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t entryCount; - D3D12_SHADER_BYTECODE byteCode; - ShaderEntry* entries; -} Shader; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool primary; - void* pool; // CommandPool - Device* device; - ID3D12Resource* stagingBuffer; - ID3D12Resource* buffer; - ID3D12CommandAllocator* allocator; - void* pipeline; - ID3D12GraphicsCommandList6* handle; -} CommandBuffer; - -typedef struct { - PalBool used; - CommandBuffer* cmdBuffer; -} CommandBufferData; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t size; - D3D12_COMMAND_LIST_TYPE type; - CommandBufferData* cmdBuffersData; -} CommandPool; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool supportsAddress; - PalBool canChangeState; - PalBool hasIndirect; - PalBool isAccelerationStructure; - PalBool isScratch; - uint64_t size; - ID3D12Resource* handle; - Device* device; - D3D12_RESOURCE_DESC desc; -} Buffer; - -typedef struct { - const PalGraphicsBackend* backend; - - PalAccelerationStructureType type; - D3D12_GPU_VIRTUAL_ADDRESS address; - ID3D12Resource* handle; -} AccelerationStructure; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t constantIndex; - ID3D12RootSignature* handle; -} PipelineLayout; - -typedef struct { - PalBool isHitGroup; - PalShaderStage stage; - wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; -} ShaderExport; - -typedef struct { - wchar_t entryName[PAL_SHADER_ENTRY_NAME_SIZE]; - D3D12_HIT_GROUP_DESC desc; -} RayHitGroup; - -typedef struct { - uint32_t raygenCount; - uint32_t raygenDataSize; - uint32_t missCount; - uint32_t missDataSize; - uint32_t hitCount; - uint32_t hitDataSize; - uint32_t callableCount; - uint32_t callableDataSize; -} ShaderBindingTableInfo; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool hasFsr; - uint32_t type; - uint32_t shaderExportCount; - D3D12_SHADING_RATE shadingRate; - D3D_PRIMITIVE_TOPOLOGY topology; - uint32_t* strides; - void* handle; - ShaderExport* shaderExports; - PipelineLayout* layout; - ID3D12RootSignature* localRootSignature; - D3D12_SHADING_RATE_COMBINER combinerOps[2]; - ShaderBindingTableInfo sbtInfo; -} Pipeline; - -typedef struct { - uint32_t startIndex; - uint32_t offset; - D3D12_GPU_VIRTUAL_ADDRESS_RANGE_AND_STRIDE region; -} AddressRegion; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool isDirty; - uint32_t stagingBufferSize; - uint32_t handleSize; - ID3D12Resource* buffer; - ID3D12Resource* stagingBuffer; - D3D12_GPU_VIRTUAL_ADDRESS baseAddress; - Pipeline* pipeline; - - AddressRegion raygen; - AddressRegion miss; - AddressRegion hit; - AddressRegion callable; -} ShaderBindingTable; - -typedef struct { - PalDescriptorType type; - D3D12_DESCRIPTOR_RANGE1 range; -} DescriptorSetBinding; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool hasDescriptorIndexing; - uint32_t bindingCount; - uint32_t samplerCount; - D3D12_SHADER_VISIBILITY visibility; - DescriptorSetBinding* bindings; -} DescriptorSetLayout; - -typedef struct { - uint32_t incrementSize; - uint32_t nextOffset; - uint64_t cpuBase; - uint64_t gpuBase; - ID3D12DescriptorHeap* handle; -} DescriptorHeap; - -typedef struct { - uint32_t maxUniformBuffers; - uint32_t maxSampledImages; - uint32_t maxStorageBuffers; - uint32_t maxSamplers; - uint32_t maxStorageImages; - uint32_t maxAs; - - uint32_t usedUniformBuffers; - uint32_t usedSampledImages; - uint32_t usedStorageBuffers; - uint32_t usedSamplers; - uint32_t usedStorageImages; - uint32_t usedAs; -} DescriptorHeapLimits; - -typedef struct { - const PalGraphicsBackend* backend; - - uint32_t resourceOffset; - uint32_t samplerOffset; - DescriptorSetLayout* layout; - void* pool; // DescriptorPool -} DescriptorSet; - -typedef struct { - const PalGraphicsBackend* backend; - - PalBool hasDescriptorIndexing; - PalBool hasResourceHeap; - PalBool hasSamplerHeap; - uint32_t maxSets; - uint32_t usedSets; - DescriptorHeapLimits limits; - DescriptorHeap resourceHeap; - DescriptorHeap samplerHeap; - DescriptorSet* sets; -} DescriptorPool; - typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; ID3D12RootSignature* root; @@ -533,7 +148,7 @@ typedef struct { ShaderStream shaders[7]; // 7 shader types for graphics pipeline } GraphicsPipelineStreamDesc; -static D3D12 s_D3D = {0}; +static D3D12 s_D3D12 = {0}; // ================================================== // Helper Functions @@ -1088,11 +703,11 @@ static CommandBufferData* getFreeCmdBufferData(CommandPool* pool) int count = pool->size * 2; // double the size int freeIndex = pool->size + 1; - data = palAllocate(s_D3D.allocator, sizeof(CommandBufferData) * count, 0); + data = palAllocate(s_D3D12.allocator, sizeof(CommandBufferData) * count, 0); if (data) { memcpy(data, pool->cmdBuffersData, pool->size * sizeof(CommandBufferData)); - palFree(s_D3D.allocator, pool->cmdBuffersData); + palFree(s_D3D12.allocator, pool->cmdBuffersData); pool->cmdBuffersData = data; pool->size = count; @@ -1921,7 +1536,7 @@ static void pollMessagesD3D12(Device* device) SIZE_T size = 0; queue->lpVtbl->GetMessage(queue, i, nullptr, &size); - uint8_t* buffer = palAllocate(s_D3D.allocator, size, 0); + uint8_t* buffer = palAllocate(s_D3D12.allocator, size, 0); if (!buffer) { return; } @@ -1974,8 +1589,8 @@ static void pollMessagesD3D12(Device* device) } } - s_D3D.debugCallback(s_D3D.debugUserData, msgSeverity, msgType, message); - palFree(s_D3D.allocator, buffer); + s_D3D12.debugCallback(s_D3D12.debugUserData, msgSeverity, msgType, message); + palFree(s_D3D12.allocator, buffer); } queue->lpVtbl->ClearStoredMessages(queue); } @@ -2112,42 +1727,42 @@ PalResult PAL_CALL initGraphicsD3D12( const PalAllocator* allocator) { // load d3d12 - s_D3D.handle = LoadLibraryA("d3d12.dll"); - s_D3D.dxgi = LoadLibraryA("dxgi.dll"); - if (!s_D3D.handle || !s_D3D.dxgi) { + s_D3D12.handle = LoadLibraryA("d3d12.dll"); + s_D3D12.dxgi = LoadLibraryA("dxgi.dll"); + if (!s_D3D12.handle || !s_D3D12.dxgi) { return PAL_RESULT_PLATFORM_FAILURE; } // clang-format off - s_D3D.createDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress( - s_D3D.handle, + s_D3D12.createDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress( + s_D3D12.handle, "D3D12CreateDevice"); - s_D3D.createDXGIFactory = (PFN_CreateDXGIFactory2)GetProcAddress( - s_D3D.dxgi, + s_D3D12.createDXGIFactory = (PFN_CreateDXGIFactory2)GetProcAddress( + s_D3D12.dxgi, "CreateDXGIFactory2"); - s_D3D.serializeVersionedRootSignature = (PFN_D3D12SerializeVersionedRootSignature)GetProcAddress( - s_D3D.handle, + s_D3D12.serializeVersionedRootSignature = (PFN_D3D12SerializeVersionedRootSignature)GetProcAddress( + s_D3D12.handle, "D3D12SerializeVersionedRootSignature"); if (debugger && debugger->callback) { - s_D3D.getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress( - s_D3D.handle, + s_D3D12.getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress( + s_D3D12.handle, "D3D12GetDebugInterface"); - if (s_D3D.getDebugInterface) { + if (s_D3D12.getDebugInterface) { HRESULT hr; ID3D12Debug* debugController = nullptr; ID3D12Debug1* debugController1 = nullptr; - hr = s_D3D.getDebugInterface(&IID_DebugController, (void**)&debugController); + hr = s_D3D12.getDebugInterface(&IID_DebugController, (void**)&debugController); if (SUCCEEDED(hr)) { debugController->lpVtbl->EnableDebugLayer(debugController); debugController->lpVtbl->Release(debugController); } - hr = s_D3D.getDebugInterface(&IID_DebugController1, (void**)&debugController1); + hr = s_D3D12.getDebugInterface(&IID_DebugController1, (void**)&debugController1); if (SUCCEEDED(hr)) { debugController1->lpVtbl->SetEnableGPUBasedValidation( debugController1, @@ -2157,505 +1772,71 @@ PalResult PAL_CALL initGraphicsD3D12( // message types if (!debugger->denyGeneral) { - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED; - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_INITIALIZATION; - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_SETTING; - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_INITIALIZATION; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_SETTING; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION; } if (!debugger->denyPerformance) { - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_CREATION; - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_EXECUTION; - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_SETTING; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_CREATION; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_EXECUTION; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_SETTING; } if (!debugger->denyValidation) { - s_D3D.categories[s_D3D.categoryCount++] = D3D12_MESSAGE_CATEGORY_SHADER; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_SHADER; } // message severities if (!debugger->denyInfoSeverity) { - s_D3D.severities[s_D3D.severityCount++] = D3D12_MESSAGE_SEVERITY_INFO; + s_D3D12.severities[s_D3D12.severityCount++] = D3D12_MESSAGE_SEVERITY_INFO; } if (!debugger->denyWarningSeverity) { - s_D3D.severities[s_D3D.severityCount++] = D3D12_MESSAGE_SEVERITY_WARNING; + s_D3D12.severities[s_D3D12.severityCount++] = D3D12_MESSAGE_SEVERITY_WARNING; } if (!debugger->denyErrorSeverity) { - s_D3D.severities[s_D3D.severityCount++] = D3D12_MESSAGE_SEVERITY_ERROR; - s_D3D.severities[s_D3D.severityCount++] = D3D12_MESSAGE_SEVERITY_CORRUPTION; + s_D3D12.severities[s_D3D12.severityCount++] = D3D12_MESSAGE_SEVERITY_ERROR; + s_D3D12.severities[s_D3D12.severityCount++] = D3D12_MESSAGE_SEVERITY_CORRUPTION; } } - s_D3D.debugLayer = PAL_TRUE; - s_D3D.debugCallback = debugger->callback; + s_D3D12.debugLayer = PAL_TRUE; + s_D3D12.debugCallback = debugger->callback; } } // clang-format on - s_D3D.factory = nullptr; - s_D3D.adapters = nullptr; - s_D3D.adapterCount = 0; - HRESULT result = s_D3D.createDXGIFactory(0, &IID_Factory, (void**)&s_D3D.factory); + s_D3D12.factory = nullptr; + s_D3D12.adapters = nullptr; + s_D3D12.adapterCount = 0; + HRESULT result = s_D3D12.createDXGIFactory(0, &IID_Factory, (void**)&s_D3D12.factory); if (FAILED(result)) { return PAL_RESULT_PLATFORM_FAILURE; } - s_D3D.allocator = allocator; + s_D3D12.allocator = allocator; return PAL_RESULT_SUCCESS; } void PAL_CALL shutdownGraphicsD3D12() { - for (int i = 0; i < s_D3D.adapterCount; i++) { - s_D3D.adapters[i].handle->lpVtbl->Release(s_D3D.adapters[i].handle); - } - - s_D3D.factory->lpVtbl->Release(s_D3D.factory); - FreeLibrary(s_D3D.handle); - FreeLibrary(s_D3D.dxgi); - - if (s_D3D.adapters) { - palFree(s_D3D.allocator, s_D3D.adapters); - } - memset(&s_D3D, 0, sizeof(s_D3D)); -} - -PalResult PAL_CALL enumerateAdaptersD3D12( - int32_t* count, - PalAdapter** outAdapters) -{ - uint32_t adapterCount = 0; - IDXGIAdapter* adapter = nullptr; - IDXGIAdapter4* dxAdapters[32]; // should be more than enough - ID3D12Device* devices[32]; // should be more than enough - D3D_FEATURE_LEVEL deviceLevels[32]; // should be more than enough - - D3D_FEATURE_LEVEL levels[] = { - D3D_FEATURE_LEVEL_12_2, - D3D_FEATURE_LEVEL_12_1, - D3D_FEATURE_LEVEL_12_0, - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0 - }; - - if (s_D3D.adapters) { - palFree(s_D3D.allocator, s_D3D.adapters); - } - - while (SUCCEEDED(s_D3D.factory->lpVtbl->EnumAdapters( - s_D3D.factory, - adapterCount, - &adapter))) { - if (outAdapters) { - IDXGIAdapter4* tmp = nullptr; - if SUCCEEDED((adapter->lpVtbl->QueryInterface(adapter, &IID_Adapter, (void**)&tmp))) { - dxAdapters[adapterCount] = tmp; - } - - // create a temp device for every adapter to use as an instance to check features, - // capabilities etc. - ID3D12Device* device = nullptr; - for (int i = 0; i < 5; i++) { - HRESULT result = s_D3D.createDevice( - (IUnknown*)tmp, - levels[i], - &IID_Device, - (void**)&device); - - if (SUCCEEDED(result)) { - deviceLevels[adapterCount] = levels[i]; - devices[adapterCount] = device; - break; - } - } - } - adapter->lpVtbl->Release(adapter); - adapterCount++; - } - - if (outAdapters) { - s_D3D.adapters = palAllocate(s_D3D.allocator, sizeof(Adapter) * adapterCount, 0); - if (!s_D3D.adapters) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // fill the array with Adapter structs - for (int i = 0; i < *count; i++) { - Adapter* tmp = &s_D3D.adapters[i]; - tmp->handle = dxAdapters[i]; - tmp->tmpDevice = devices[i]; - tmp->level = deviceLevels[i]; - outAdapters[i] = (PalAdapter*)tmp; - } - s_D3D.adapterCount = *count; - - } else { - *count = adapterCount; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL getAdapterInfoD3D12( - PalAdapter* adapter, - PalAdapterInfo* info) -{ - Adapter* d3dAdapter = (Adapter*)adapter; - IDXGIAdapter4* adapterHandle = d3dAdapter->handle; - DXGI_ADAPTER_DESC3 desc; - D3D12_FEATURE_DATA_ARCHITECTURE1 arch = {0}; - ID3D12Device* device = d3dAdapter->tmpDevice; - - D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; - shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; - - HRESULT result = adapterHandle->lpVtbl->GetDesc3(adapterHandle, &desc); - if (FAILED(result)) { - return PAL_RESULT_INVALID_ADAPTER; - } - - result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, - sizeof(shaderModel)); - - info->shaderFormats = PAL_SHADER_FORMAT_DXBC; - if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0 && result == S_OK) { - info->shaderFormats |= PAL_SHADER_FORMAT_DXIL; - } - - info->vendorId = desc.VendorId; - info->deviceId= desc.DeviceId; - info->apiType = PAL_ADAPTER_API_TYPE_D3D12; - info->sharedMemory = desc.SharedSystemMemory; - strcpy(info->backendName, "PAL"); - - WideCharToMultiByte( - CP_UTF8, - 0, - desc.Description, - -1, - info->name, - PAL_ADAPTER_NAME_SIZE, - nullptr, - nullptr); - - device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_ARCHITECTURE1, - &arch, - sizeof(arch)); - - if (arch.UMA == PAL_TRUE) { - info->type = PAL_ADAPTER_TYPE_INTEGRATED; - - } else { - info->type = PAL_ADAPTER_TYPE_DISCRETE; - } - - if (desc.Flags & DXGI_ADAPTER_FLAG3_SOFTWARE) { - info->type = PAL_ADAPTER_TYPE_CPU; - } - - if (desc.DedicatedVideoMemory > 0) { - info->vram = desc.DedicatedVideoMemory; - - } else if (desc.DedicatedVideoMemory == 0 && desc.DedicatedSystemMemory > 0) { - info->vram = desc.DedicatedSystemMemory; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL getAdapterCapabilitiesD3D12( - PalAdapter* adapter, - PalAdapterCapabilities* caps) -{ - Adapter* d3dAdapter = (Adapter*)adapter; - if (!d3dAdapter->handle) { - return PAL_RESULT_INVALID_ADAPTER; - } - - PalViewportCapabilities* viewportCaps = &caps->viewportCaps; - PalImageCapabilities* imageCaps = &caps->imageCaps; - PalResourceCapabilities* resourceCaps = &caps->resourceCaps; - PalComputeCapabilities* computeCaps = &caps->computeCaps; - - caps->maxComputeQueues = 2; // safe default - caps->maxGraphicsQueues = 2; // safe default - caps->maxCopyQueues = 2; // safe default - - caps->maxColorAttachments = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; - caps->maxUniformBufferSize = D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT * 16; - caps->maxStorageBufferSize = 2147483648; // 2 GIB - caps->maxPushConstantSize = 256; - - caps->maxVertexLayouts = 32; // safe - caps->maxVertexAttributes = 32; // safe - caps->maxTessellationPatchPoint = 32; - - // viewport limits - viewportCaps->maxWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; - viewportCaps->maxHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; - viewportCaps->minBoundsRange = (float)D3D12_VIEWPORT_BOUNDS_MIN; - viewportCaps->maxBoundsRange = (float)D3D12_VIEWPORT_BOUNDS_MAX; - - // image limits - imageCaps->maxWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; - imageCaps->maxHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; - imageCaps->maxDepth = D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION; - imageCaps->maxArrayLayers = D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION; - - // d3d12 does not give this but we calculate from the max width and width - uint32_t a = imageCaps->maxWidth; - uint32_t b = imageCaps->maxHeight; - uint32_t c = imageCaps->maxDepth; - - uint32_t tmp = a > b ? a : b; - uint32_t size = tmp > c ? tmp : c; - uint32_t levels = 0; - while (size > 0) { - // divide by two - size = size / 2; - levels++; - } - imageCaps->maxMipLevels = levels; - - // resource limits - // always supported - getDescriptorTierLimitsD3D12(d3dAdapter->tmpDevice, resourceCaps, nullptr); - resourceCaps->maxBoundSets = 32; - resourceCaps->sampledImageDynamicArrayIndexing = PAL_TRUE; - resourceCaps->storageImageDynamicArrayIndexing = PAL_TRUE; - resourceCaps->storageBufferDynamicArrayIndexing = PAL_TRUE; - resourceCaps->uniformBufferDynamicArrayIndexing = PAL_TRUE; - - // compute limits - computeCaps->maxWorkGroupInvocations = D3D12_CS_THREAD_GROUP_MAX_THREADS_PER_GROUP; - computeCaps->maxWorkGroupCount[0] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; - computeCaps->maxWorkGroupCount[1] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; - computeCaps->maxWorkGroupCount[2] = D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION; - computeCaps->maxWorkGroupSize[0] = D3D12_CS_THREAD_GROUP_MAX_X; - computeCaps->maxWorkGroupSize[1] = D3D12_CS_THREAD_GROUP_MAX_Y; - computeCaps->maxWorkGroupSize[2] = D3D12_CS_THREAD_GROUP_MAX_Z; - - return PAL_RESULT_SUCCESS; -} - -PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) -{ - HRESULT result; - Adapter* d3dAdapter = (Adapter*)adapter; - IDXGIAdapter4* adapterHandle = d3dAdapter->handle; - PalAdapterFeatures features = 0; - ID3D12Device* device = d3dAdapter->tmpDevice; - - D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; - D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {0}; - D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = {0}; - D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {0}; - D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = {0}; - D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; - - device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS, - &options, - sizeof(options)); - - device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS3, - &options3, - sizeof(options3)); - - device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS5, - &options5, - sizeof(options5)); - - device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS6, - &options6, - sizeof(options6)); - - device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS7, - &options7, - sizeof(options7)); - - shaderModel.HighestShaderModel = D3D_SHADER_MODEL_5_1; - HRESULT hr = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, - sizeof(shaderModel)); - - if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_5_1 && hr == S_OK) { - features |= PAL_ADAPTER_FEATURE_TESSELLATION_SHADER; - features |= PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING; - features |= PAL_ADAPTER_FEATURE_SHADER_FLOAT64; - } - - shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_2; - hr = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, - sizeof(shaderModel)); - - if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_2 && hr == S_OK) { - features |= PAL_ADAPTER_FEATURE_SHADER_FLOAT16; - features |= PAL_ADAPTER_FEATURE_SHADER_INT16; + for (int i = 0; i < s_D3D12.adapterCount; i++) { + s_D3D12.adapters[i].handle->lpVtbl->Release(s_D3D12.adapters[i].handle); } - shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; - hr = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, - sizeof(shaderModel)); - - if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0 && hr == S_OK) { - features |= PAL_ADAPTER_FEATURE_SHADER_INT64; - } + s_D3D12.factory->lpVtbl->Release(s_D3D12.factory); + FreeLibrary(s_D3D12.handle); + FreeLibrary(s_D3D12.dxgi); - if (options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED) { - features |= PAL_ADAPTER_FEATURE_MULTI_VIEW; + if (s_D3D12.adapters) { + palFree(s_D3D12.allocator, s_D3D12.adapters); } - - if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED) { - features |= PAL_ADAPTER_FEATURE_RAY_TRACING; - features |= PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING; - } - - if (options5.RaytracingTier >= D3D12_RAYTRACING_TIER_1_1) { - features |= PAL_ADAPTER_FEATURE_RAY_QUERY; - } - - if (options6.VariableShadingRateTier != D3D12_VARIABLE_SHADING_RATE_TIER_NOT_SUPPORTED) { - features |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE; - features |= PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT; - } - - if (options7.MeshShaderTier != D3D12_MESH_SHADER_TIER_NOT_SUPPORTED) { - features |= PAL_ADAPTER_FEATURE_MESH_SHADER; - features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH; - features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT; - } - - if (!(options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1)) { - features |= PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - } - - // this features are supported on d3d12 - features |= PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; - features |= PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; - features |= PAL_ADAPTER_FEATURE_MULTI_VIEWPORT; - features |= PAL_ADAPTER_FEATURE_GEOMETRY_SHADER; - features |= PAL_ADAPTER_FEATURE_SWAPCHAIN; - features |= PAL_ADAPTER_FEATURE_FENCE_RESET; - features |= PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE; - features |= PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS; - features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW; - features |= PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH; - features |= PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT; - features |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; - features |= PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS; - - if (d3dAdapter->level >= D3D_FEATURE_LEVEL_12_0) { - features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; - } - return features; + memset(&s_D3D12, 0, sizeof(s_D3D12)); } -uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( - PalAdapter* adapter, - PalShaderFormats shaderFormat) -{ - if (shaderFormat != PAL_SHADER_FORMAT_DXIL && shaderFormat != PAL_SHADER_FORMAT_DXBC) { - return 0; - } - - if (shaderFormat == PAL_SHADER_FORMAT_DXBC) { - return PAL_MAKE_SHADER_TARGET(5, 1); - } - - Adapter* d3dAdapter = (Adapter*)adapter; - D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; - - D3D_SHADER_MODEL models[11]; - models[0] = D3D_SHADER_MODEL_6_10; - models[1] = D3D_SHADER_MODEL_6_9; - models[2] = D3D_SHADER_MODEL_6_8; - models[3] = D3D_SHADER_MODEL_6_7; - models[4] = D3D_SHADER_MODEL_6_6; - models[5] = D3D_SHADER_MODEL_6_5; - models[6] = D3D_SHADER_MODEL_6_4; - models[7] = D3D_SHADER_MODEL_6_3; - models[8] = D3D_SHADER_MODEL_6_2; - models[9] = D3D_SHADER_MODEL_6_1; - models[10] = D3D_SHADER_MODEL_6_0; - - // find the highest supported shader model - HRESULT result = 0; - D3D_SHADER_MODEL highestModel = D3D_SHADER_MODEL_5_1; - for (int i = 0; i < 11; i++) { - shaderModel.HighestShaderModel = models[i]; - result = d3dAdapter->tmpDevice->lpVtbl->CheckFeatureSupport( - d3dAdapter->tmpDevice, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, - sizeof(shaderModel)); - - if (shaderModel.HighestShaderModel >= models[i] && result == S_OK) { - highestModel = models[i]; - break; - } - } - - if (highestModel == D3D_SHADER_MODEL_5_1) { - return 0; - } - - if (highestModel >= D3D_SHADER_MODEL_6_10) { - return PAL_MAKE_SHADER_TARGET(6, 10); - - } else if (highestModel >= D3D_SHADER_MODEL_6_9) { - return PAL_MAKE_SHADER_TARGET(6, 9); - - } else if (highestModel >= D3D_SHADER_MODEL_6_8) { - return PAL_MAKE_SHADER_TARGET(6, 8); - - } else if (highestModel >= D3D_SHADER_MODEL_6_6) { - return PAL_MAKE_SHADER_TARGET(6, 6); - - } else if (highestModel >= D3D_SHADER_MODEL_6_5) { - return PAL_MAKE_SHADER_TARGET(6, 5); - - } else if (highestModel >= D3D_SHADER_MODEL_6_4) { - return PAL_MAKE_SHADER_TARGET(6, 4); - - } else if (highestModel >= D3D_SHADER_MODEL_6_3) { - return PAL_MAKE_SHADER_TARGET(6, 3); - - } else if (highestModel >= D3D_SHADER_MODEL_6_2) { - return PAL_MAKE_SHADER_TARGET(6, 2); - - } else if (highestModel >= D3D_SHADER_MODEL_6_1) { - return PAL_MAKE_SHADER_TARGET(6, 1); - } else if (highestModel >= D3D_SHADER_MODEL_6_0) { - return PAL_MAKE_SHADER_TARGET(6, 0); - } - - return 0; -} // ================================================== // Device @@ -2677,7 +1858,7 @@ PalResult PAL_CALL createDeviceD3D12( return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - device = palAllocate(s_D3D.allocator, sizeof(Device), 0); + device = palAllocate(s_D3D12.allocator, sizeof(Device), 0); if (!device) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2689,14 +1870,14 @@ PalResult PAL_CALL createDeviceD3D12( // get and cache highest shader model device->shaderModel = getHighestSupportedShaderTargetD3D12(adapter, PAL_SHADER_FORMAT_DXIL); - result = s_D3D.createDevice( + result = s_D3D12.createDevice( (IUnknown*)d3dAdapter->handle, d3dAdapter->level, &IID_Device, (void**)&tmpDevice); if (FAILED(result)) { - palFree(s_D3D.allocator, device); + palFree(s_D3D12.allocator, device); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -2709,7 +1890,7 @@ PalResult PAL_CALL createDeviceD3D12( (void**)&device->handle); tmpDevice->lpVtbl->Release(tmpDevice); - if (s_D3D.debugLayer) { + if (s_D3D12.debugLayer) { result = device->handle->lpVtbl->QueryInterface( device->handle, &IID_InfoQueue, @@ -2718,10 +1899,10 @@ PalResult PAL_CALL createDeviceD3D12( if (SUCCEEDED(result)) { D3D12_MESSAGE_ID denyIDs[] = { D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE }; D3D12_INFO_QUEUE_FILTER filter = {0}; - filter.AllowList.NumSeverities = s_D3D.severityCount; - filter.AllowList.pSeverityList = s_D3D.severities; - filter.AllowList.NumCategories = s_D3D.categoryCount; - filter.AllowList.pCategoryList = s_D3D.categories; + filter.AllowList.NumSeverities = s_D3D12.severityCount; + filter.AllowList.pSeverityList = s_D3D12.severities; + filter.AllowList.NumCategories = s_D3D12.categoryCount; + filter.AllowList.pCategoryList = s_D3D12.categories; filter.DenyList.NumIDs = 1; filter.DenyList.pIDList = denyIDs; @@ -2956,37 +2137,37 @@ PalResult PAL_CALL createDeviceD3D12( void PAL_CALL destroyDeviceD3D12(PalDevice* device) { - Device* d3dDevice = (Device*)device; - if (d3dDevice->meshSignature) { - d3dDevice->meshSignature->lpVtbl->Release(d3dDevice->meshSignature); + Device* d3d12Device = (Device*)device; + if (d3d12Device->meshSignature) { + d3d12Device->meshSignature->lpVtbl->Release(d3d12Device->meshSignature); } - if (d3dDevice->raySignature) { - d3dDevice->raySignature->lpVtbl->Release(d3dDevice->raySignature); + if (d3d12Device->raySignature) { + d3d12Device->raySignature->lpVtbl->Release(d3d12Device->raySignature); } - if (d3dDevice->dispatchSignature) { - d3dDevice->dispatchSignature->lpVtbl->Release(d3dDevice->dispatchSignature); + if (d3d12Device->dispatchSignature) { + d3d12Device->dispatchSignature->lpVtbl->Release(d3d12Device->dispatchSignature); } - if (d3dDevice->drawIndexedSignature) { - d3dDevice->drawIndexedSignature->lpVtbl->Release(d3dDevice->drawIndexedSignature); + if (d3d12Device->drawIndexedSignature) { + d3d12Device->drawIndexedSignature->lpVtbl->Release(d3d12Device->drawIndexedSignature); } - if (d3dDevice->drawSignature) { - d3dDevice->drawSignature->lpVtbl->Release(d3dDevice->drawSignature); + if (d3d12Device->drawSignature) { + d3d12Device->drawSignature->lpVtbl->Release(d3d12Device->drawSignature); } - d3dDevice->rtvAllocator.heap->lpVtbl->Release(d3dDevice->rtvAllocator.heap); - d3dDevice->dsvAllocator.heap->lpVtbl->Release(d3dDevice->dsvAllocator.heap); + d3d12Device->rtvAllocator.heap->lpVtbl->Release(d3d12Device->rtvAllocator.heap); + d3d12Device->dsvAllocator.heap->lpVtbl->Release(d3d12Device->dsvAllocator.heap); - d3dDevice->queue->lpVtbl->Release(d3dDevice->queue); - d3dDevice->handle->lpVtbl->Release(d3dDevice->handle); - if (d3dDevice->infoQueue) { - d3dDevice->infoQueue->lpVtbl->Release(d3dDevice->infoQueue); + d3d12Device->queue->lpVtbl->Release(d3d12Device->queue); + d3d12Device->handle->lpVtbl->Release(d3d12Device->handle); + if (d3d12Device->infoQueue) { + d3d12Device->infoQueue->lpVtbl->Release(d3d12Device->infoQueue); } - palFree(s_D3D.allocator, d3dDevice); + palFree(s_D3D12.allocator, d3d12Device); } // ================================================== @@ -3001,7 +2182,7 @@ PalResult PAL_CALL allocateMemoryD3D12( PalMemory** outMemory) { HRESULT result; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; ID3D12Heap* memory = nullptr; D3D12_HEAP_DESC desc = {0}; @@ -3015,14 +2196,14 @@ PalResult PAL_CALL allocateMemoryD3D12( desc.Properties.Type = D3D12_HEAP_TYPE_UPLOAD; } - result = d3dDevice->handle->lpVtbl->CreateHeap( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateHeap( + d3d12Device->handle, &desc, &IID_Heap, (void**)&memory); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); return PAL_RESULT_OUT_OF_MEMORY; } @@ -3046,8 +2227,8 @@ PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( PalDevice* device, PalSamplerAnisotropyCapabilities* caps) { - Device* d3dDevice = (Device*)device; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3059,8 +2240,8 @@ PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( PalDevice* device, PalMultiViewCapabilities* caps) { - Device* d3dDevice = (Device*)device; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3072,8 +2253,8 @@ PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( PalDevice* device, PalMultiViewportCapabilities* caps) { - Device* d3dDevice = (Device*)device; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3085,8 +2266,8 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( PalDevice* device, PalDepthStencilCapabilities* caps) { - Device* d3dDevice = (Device*)device; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3108,8 +2289,8 @@ PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { - Device* d3dDevice = (Device*)device; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3120,8 +2301,8 @@ PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X2] = PAL_TRUE; D3D12_FEATURE_DATA_D3D12_OPTIONS6 options = {0}; - d3dDevice->handle->lpVtbl->CheckFeatureSupport( - d3dDevice->handle, + d3d12Device->handle->lpVtbl->CheckFeatureSupport( + d3d12Device->handle, D3D12_FEATURE_D3D12_OPTIONS6, &options, sizeof(options)); @@ -3156,8 +2337,8 @@ PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( PalDevice* device, PalMeshShaderCapabilities* caps) { - Device* d3dDevice = (Device*)device; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3181,8 +2362,8 @@ PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( PalDevice* device, PalRayTracingCapabilities* caps) { - Device* d3dDevice = (Device*)device; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3202,8 +2383,8 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( PalDevice* device, PalDescriptorIndexingCapabilities* caps) { - Device* d3dDevice = (Device*)device; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3217,7 +2398,7 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( caps->uniformBufferNonUniformIndexing = PAL_TRUE; caps->uniformBufferUpdateAfterBind = PAL_TRUE; - getDescriptorTierLimitsD3D12(d3dDevice->handle, nullptr, caps); + getDescriptorTierLimitsD3D12(d3d12Device->handle, nullptr, caps); return PAL_RESULT_SUCCESS; } @@ -3231,7 +2412,7 @@ PalResult PAL_CALL createQueueD3D12( PalQueue** outQueue) { HRESULT result; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; Queue* queue = nullptr; D3D12_COMMAND_QUEUE_DESC desc = {0}; @@ -3239,48 +2420,48 @@ PalResult PAL_CALL createQueueD3D12( case PAL_QUEUE_TYPE_COMPUTE: { desc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; - if (!d3dDevice->limits.freeComputeQueues) { + if (!d3d12Device->limits.freeComputeQueues) { return PAL_RESULT_OUT_OF_QUEUE; } - d3dDevice->limits.freeComputeQueues--; + d3d12Device->limits.freeComputeQueues--; break; } case PAL_QUEUE_TYPE_GRAPHICS: { desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - if (!d3dDevice->limits.freeGraphicsQueues) { + if (!d3d12Device->limits.freeGraphicsQueues) { return PAL_RESULT_OUT_OF_QUEUE; } - d3dDevice->limits.freeGraphicsQueues--; + d3d12Device->limits.freeGraphicsQueues--; break; } case PAL_QUEUE_TYPE_COPY: { desc.Type = D3D12_COMMAND_LIST_TYPE_COPY; - if (!d3dDevice->limits.freeCopyQueues) { + if (!d3d12Device->limits.freeCopyQueues) { return PAL_RESULT_OUT_OF_QUEUE; } - d3dDevice->limits.freeCopyQueues--; + d3d12Device->limits.freeCopyQueues--; break; } } - queue = palAllocate(s_D3D.allocator, sizeof(Queue), 0); + queue = palAllocate(s_D3D12.allocator, sizeof(Queue), 0); if (!queue) { return PAL_RESULT_OUT_OF_MEMORY; } - result = d3dDevice->handle->lpVtbl->CreateCommandQueue( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateCommandQueue( + d3d12Device->handle, &desc, &IID_Queue, (void**)&queue->handle); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); - palFree(s_D3D.allocator, queue); + pollMessagesD3D12(d3d12Device); + palFree(s_D3D12.allocator, queue); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3288,16 +2469,16 @@ PalResult PAL_CALL createQueueD3D12( } // create fence used for queue wait - result = d3dDevice->handle->lpVtbl->CreateFence( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateFence( + d3d12Device->handle, 0, 0, &IID_Fence, (void**)&queue->fence); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); - palFree(s_D3D.allocator, queue); + pollMessagesD3D12(d3d12Device); + palFree(s_D3D12.allocator, queue); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3315,7 +2496,7 @@ void PAL_CALL destroyQueueD3D12(PalQueue* queue) Queue* d3dQueue = (Queue*)queue; d3dQueue->fence->lpVtbl->Release(d3dQueue->fence); d3dQueue->handle->lpVtbl->Release(d3dQueue->handle); - palFree(s_D3D.allocator, d3dQueue); + palFree(s_D3D12.allocator, d3dQueue); } PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) @@ -3348,187 +2529,7 @@ PalBool PAL_CALL canQueuePresentD3D12( // Formats // ================================================== -PalResult PAL_CALL enumerateFormatsD3D12( - PalAdapter* adapter, - int32_t* count, - PalFormatInfo* outFormats) -{ - int32_t fmtCount = 0; - HRESULT result; - Adapter* d3dAdapter = (Adapter*)adapter; - ID3D12Device* device = d3dAdapter->tmpDevice; - D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; - - for (int i = 0; i < PAL_FORMAT_MAX; i++) { - DXGI_FORMAT fmt = formatToD3D12((PalFormat)i); - if (fmt == DXGI_FORMAT_UNKNOWN) { - continue; - } - support.Format = fmt; - result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, - sizeof(support)); - - if (SUCCEEDED(result)) { - if (support.Support1 == 0 && support.Support2 == 0) { - // format not supported - continue; - } - - if (outFormats) { - if (fmtCount < *count) { - PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; - fmtInfo->format = (PalFormat)i; - fmtInfo->usages = ImageUsageFromD3D12(support.Support1); - } - - } else { - fmtCount++; - } - } - } - if (!outFormats) { - *count = fmtCount; - } - return PAL_RESULT_SUCCESS; -} - -PalBool PAL_CALL isFormatSupportedD3D12( - PalAdapter* adapter, - PalFormat format) -{ - HRESULT result; - Adapter* d3dAdapter = (Adapter*)adapter; - ID3D12Device* device = d3dAdapter->tmpDevice; - D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; - - DXGI_FORMAT fmt = formatToD3D12(format); - if (fmt == DXGI_FORMAT_UNKNOWN) { - return PAL_FALSE; - } - - support.Format = fmt; - result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, - sizeof(support)); - - if (FAILED(result) || (support.Support1 == 0 && support.Support2 == 0)) { - return PAL_FALSE; - } - - return PAL_TRUE; -} - -PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( - PalAdapter* adapter, - PalFormat format) -{ - HRESULT result; - Adapter* d3dAdapter = (Adapter*)adapter; - ID3D12Device* device = d3dAdapter->tmpDevice; - D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; - - DXGI_FORMAT fmt = formatToD3D12(format); - if (fmt == DXGI_FORMAT_UNKNOWN) { - return 0; - } - - support.Format = fmt; - result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, - sizeof(support)); - - if (FAILED(result)) { - return 0; - } - - if (support.Support1 == 0 && support.Support2 == 0) { - // format not supported - return 0; - } - - PalImageUsages usages = ImageUsageFromD3D12(support.Support1); - if (support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE || - support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD) { - usages |= PAL_IMAGE_USAGE_STORAGE; - } - - return usages; -} - -PalSampleCount PAL_CALL queryFormatSampleCountD3D12( - PalAdapter* adapter, - PalFormat format) -{ - HRESULT result; - Adapter* d3dAdapter = (Adapter*)adapter; - ID3D12Device* device = d3dAdapter->tmpDevice; - D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; - - DXGI_FORMAT fmt = formatToD3D12(format); - if (fmt == DXGI_FORMAT_UNKNOWN) { - return PAL_FALSE; - } - - support.Format = fmt; - result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, - sizeof(support)); - - if (FAILED(result)) { - return PAL_FALSE; - } - - if (support.Support1 == 0 && support.Support2 == 0) { - // format not supported - return PAL_FALSE; - } - - // check sample count - UINT sampleCounts[] = {64, 32, 16, 8, 4, 2}; - D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS samples = {0}; - samples.Format = fmt; - - uint32_t tmp = 0; - for (int i = 0; i < 6; i++) { - samples.SampleCount = sampleCounts[i]; - result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, - &samples, - sizeof(samples)); - - if (SUCCEEDED(result) && samples.NumQualityLevels > 0) { - tmp = samples.SampleCount; - break; - } - } - - if (tmp == 64) { - return PAL_SAMPLE_COUNT_64; - } else if (tmp == 32) { - return PAL_SAMPLE_COUNT_32; - } else if (tmp == 16) { - return PAL_SAMPLE_COUNT_16; - } else if (tmp == 8) { - return PAL_SAMPLE_COUNT_8; - } else if (tmp == 4) { - return PAL_SAMPLE_COUNT_4; - } else if (tmp == 2) { - return PAL_SAMPLE_COUNT_2; - } else { - return PAL_SAMPLE_COUNT_1; - } -} // ================================================== // Image @@ -3541,9 +2542,9 @@ PalResult PAL_CALL createImageD3D12( { HRESULT result; Image* image = nullptr; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; - image = palAllocate(s_D3D.allocator, sizeof(Image), 0); + image = palAllocate(s_D3D12.allocator, sizeof(Image), 0); if (!image) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3587,7 +2588,7 @@ PalResult PAL_CALL createImageD3D12( image->info.sampleCount = info->sampleCount; image->info.width = info->width; - image->device = d3dDevice; + image->device = d3d12Device; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } @@ -3599,7 +2600,7 @@ void PAL_CALL destroyImageD3D12(PalImage* image) if (d3dImage->handle) { d3dImage->handle->lpVtbl->Release(d3dImage->handle); } - palFree(s_D3D.allocator, d3dImage); + palFree(s_D3D12.allocator, d3dImage); } PalResult PAL_CALL getImageInfoD3D12( @@ -3688,16 +2689,16 @@ PalResult PAL_CALL createImageViewD3D12( { HRESULT result; ImageView* imageView = nullptr; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; Image* d3dImage = (Image*)image; if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } - imageView = palAllocate(s_D3D.allocator, sizeof(ImageView), 0); + imageView = palAllocate(s_D3D12.allocator, sizeof(ImageView), 0); if (!imageView) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3708,7 +2709,7 @@ PalResult PAL_CALL createImageViewD3D12( imageView->format = formatToD3D12(info->format); if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR && hasRTV) { - RTVHeapAllocator* allocator = &d3dDevice->rtvAllocator; + RTVHeapAllocator* allocator = &d3d12Device->rtvAllocator; uint32_t index = allocator->freeTop; allocator->freeTop = allocator->freeList[index]; @@ -3726,14 +2727,14 @@ PalResult PAL_CALL createImageViewD3D12( nullptr); imageView->heapIndex = index; - d3dDevice->handle->lpVtbl->CreateRenderTargetView( - d3dDevice->handle, + d3d12Device->handle->lpVtbl->CreateRenderTargetView( + d3d12Device->handle, d3dImage->handle, &desc, dst); } else if (info->subresourceRange.aspect != PAL_IMAGE_ASPECT_COLOR && hasDSV) { - DSVHeapAllocator* allocator = &d3dDevice->dsvAllocator; + DSVHeapAllocator* allocator = &d3d12Device->dsvAllocator; uint32_t index = allocator->freeTop; allocator->freeTop = allocator->freeList[index]; @@ -3751,8 +2752,8 @@ PalResult PAL_CALL createImageViewD3D12( nullptr); imageView->heapIndex = index; - d3dDevice->handle->lpVtbl->CreateDepthStencilView( - d3dDevice->handle, + d3d12Device->handle->lpVtbl->CreateDepthStencilView( + d3d12Device->handle, d3dImage->handle, &desc, dst); @@ -3762,7 +2763,7 @@ PalResult PAL_CALL createImageViewD3D12( imageView->type = info->type; imageView->image = d3dImage; - imageView->device = d3dDevice; + imageView->device = d3d12Device; *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; } @@ -3785,7 +2786,7 @@ void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) allocator->freeTop = d3dImageView->heapIndex; } } - palFree(s_D3D.allocator, d3dImageView); + palFree(s_D3D12.allocator, d3dImageView); } // ================================================== @@ -3797,13 +2798,13 @@ PalResult PAL_CALL createSamplerD3D12( const PalSamplerCreateInfo* info, PalSampler** outSampler) { - Device* d3dDevice = (Device*)device; - if (info->maxAnisotropy > d3dDevice->limits.maxAnisotropy) { + Device* d3d12Device = (Device*)device; + if (info->maxAnisotropy > d3d12Device->limits.maxAnisotropy) { return PAL_RESULT_INVALID_ARGUMENT; } Sampler* sampler = nullptr; - sampler = palAllocate(s_D3D.allocator, sizeof(Sampler), 0); + sampler = palAllocate(s_D3D12.allocator, sizeof(Sampler), 0); if (!sampler) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3840,7 +2841,7 @@ PalResult PAL_CALL createSamplerD3D12( void PAL_CALL destroySamplerD3D12(PalSampler* sampler) { Sampler* d3dSampler = (Sampler*)sampler; - palFree(s_D3D.allocator, d3dSampler); + palFree(s_D3D12.allocator, d3dSampler); } // ================================================== @@ -3852,13 +2853,13 @@ PalResult PAL_CALL createSurfaceD3D12( PalGraphicsWindow* window, PalSurface** outSurface) { - Device* d3dDevice = (Device*)device; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } Surface* surface = nullptr; - surface = palAllocate(s_D3D.allocator, sizeof(Surface), 0); + surface = palAllocate(s_D3D12.allocator, sizeof(Surface), 0); if (!surface) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3876,7 +2877,7 @@ PalResult PAL_CALL createSurfaceD3D12( void PAL_CALL destroySurfaceD3D12(PalSurface* surface) { Surface* d3dSurface = (Surface*)surface; - palFree(s_D3D.allocator, d3dSurface); + palFree(s_D3D12.allocator, d3dSurface); } PalResult PAL_CALL getSurfaceCapabilitiesD3D12( @@ -3886,12 +2887,12 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( { HRESULT result; Surface* d3dSurface = (Surface*)surface; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; PalBool supportHDR10 = PAL_FALSE; IDXGISwapChain1* swapchain1 = nullptr; IDXGISwapChain3* swapchain3 = nullptr; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -3905,9 +2906,9 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - result = s_D3D.factory->lpVtbl->CreateSwapChainForHwnd( - s_D3D.factory, - (IUnknown*)d3dDevice->queue, + result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( + s_D3D12.factory, + (IUnknown*)d3d12Device->queue, d3dSurface->handle, &desc, nullptr, @@ -3915,7 +2916,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( &swapchain1); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -3937,8 +2938,8 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( } BOOL allowTearing = PAL_FALSE; - s_D3D.factory->lpVtbl->CheckFeatureSupport( - s_D3D.factory, + s_D3D12.factory->lpVtbl->CheckFeatureSupport( + s_D3D12.factory, DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing)); @@ -3981,8 +2982,8 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( for (int i = 0; i < PAL_SURFACE_FORMAT_MAX; i++) { formatSupport.Format = baseFormats[i]; - result = d3dDevice->handle->lpVtbl->CheckFeatureSupport( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CheckFeatureSupport( + d3d12Device->handle, D3D12_FEATURE_FORMAT_SUPPORT, &formatSupport, sizeof(formatSupport)); @@ -4026,12 +3027,12 @@ PalResult PAL_CALL createSwapchainD3D12( { HRESULT result; Surface* d3dSurface = (Surface*)surface; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; Queue* d3dQueue = (Queue*)queue; Swapchain* swapchain = nullptr; PalBool isHDRColorspace = PAL_FALSE; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -4051,7 +3052,7 @@ PalResult PAL_CALL createSwapchainD3D12( return PAL_RESULT_INVALID_ARGUMENT; } - swapchain = palAllocate(s_D3D.allocator, sizeof(Swapchain), 0); + swapchain = palAllocate(s_D3D12.allocator, sizeof(Swapchain), 0); if (!swapchain) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4104,8 +3105,8 @@ PalResult PAL_CALL createSwapchainD3D12( swapchain->format = desc.Format; swapchain->flags = desc.Flags; - result = s_D3D.factory->lpVtbl->CreateSwapChainForHwnd( - s_D3D.factory, + result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( + s_D3D12.factory, (IUnknown*)d3dQueue->handle, d3dSurface->handle, &desc, @@ -4114,7 +3115,7 @@ PalResult PAL_CALL createSwapchainD3D12( &swapchain1); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } else if (result == E_INVALIDARG) { @@ -4137,7 +3138,7 @@ PalResult PAL_CALL createSwapchainD3D12( // get and cache swapchain images swapchain->images = nullptr; - swapchain->images = palAllocate(s_D3D.allocator, sizeof(Image) * info->imageCount, 0); + swapchain->images = palAllocate(s_D3D12.allocator, sizeof(Image) * info->imageCount, 0); if (!swapchain->imageCount) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4149,7 +3150,7 @@ PalResult PAL_CALL createSwapchainD3D12( Image* image = &swapchain->images[i]; image->belongsToSwapchain = PAL_TRUE; - image->device = d3dDevice; + image->device = d3d12Device; image->handle = tmp; image->info.depthOrArraySize = 1; // always 1 @@ -4168,7 +3169,7 @@ PalResult PAL_CALL createSwapchainD3D12( swapchain->windowWidth = windowRect.right - windowRect.left; swapchain->windowWidth = windowRect.bottom - windowRect.top; - swapchain->device = d3dDevice; + swapchain->device = d3d12Device; swapchain->queue = d3dQueue->handle; swapchain->imageCount = info->imageCount; *outSwapchain = (PalSwapchain*)swapchain; @@ -4179,8 +3180,8 @@ void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) { Swapchain* d3dSwapchain = (Swapchain*)swapchain; d3dSwapchain->handle->lpVtbl->Release(d3dSwapchain->handle); - palFree(s_D3D.allocator, d3dSwapchain->images); - palFree(s_D3D.allocator, d3dSwapchain); + palFree(s_D3D12.allocator, d3dSwapchain->images); + palFree(s_D3D12.allocator, d3dSwapchain); } PalImage* PAL_CALL getSwapchainImageD3D12( @@ -4334,17 +3335,17 @@ PalResult PAL_CALL createShaderD3D12( PalShader** outShader) { Shader* shader = nullptr; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; void* bytecode = nullptr; - shader = palAllocate(s_D3D.allocator, sizeof(Shader), 0); - bytecode = palAllocate(s_D3D.allocator, info->bytecodeSize, 0); + shader = palAllocate(s_D3D12.allocator, sizeof(Shader), 0); + bytecode = palAllocate(s_D3D12.allocator, info->bytecodeSize, 0); if (!shader || !bytecode) { return PAL_RESULT_OUT_OF_MEMORY; } // allocate entries array - shader->entries = palAllocate(s_D3D.allocator, sizeof(ShaderEntry) * info->entryCount, 0); + shader->entries = palAllocate(s_D3D12.allocator, sizeof(ShaderEntry) * info->entryCount, 0); if (!shader->entries) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4355,18 +3356,18 @@ PalResult PAL_CALL createShaderD3D12( // clang-format off if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || info->entries[i].stage == PAL_SHADER_STAGE_TASK) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } else if (info->entries[i].stage == PAL_SHADER_STAGE_GEOMETRY) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } else if (info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -4376,273 +3377,32 @@ PalResult PAL_CALL createShaderD3D12( info->entries[i].stage == PAL_SHADER_STAGE_MISS || info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } // clang-format on - convertToWcharD3D12(info->entries[i].entryName, entry->entryName); - entry->patchControlPoints = info->entries[i].patchControlPoints; - entry->stage = info->entries[i].stage; - } - - memcpy(bytecode, info->bytecode, info->bytecodeSize); - shader->byteCode.pShaderBytecode = bytecode; - shader->byteCode.BytecodeLength = info->bytecodeSize; - - shader->entryCount = info->entryCount; - *outShader = (PalShader*)shader; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyShaderD3D12(PalShader* shader) -{ - Shader* d3dShader = (Shader*)shader; - palFree(s_D3D.allocator, (void*)d3dShader->byteCode.pShaderBytecode); - palFree(s_D3D.allocator, d3dShader->entries); - palFree(s_D3D.allocator, d3dShader); -} - -// ================================================== -// Fence -// ================================================== - -PalResult PAL_CALL createFenceD3D12( - PalDevice* device, - PalBool signaled, - PalFence** outFence) -{ - HRESULT result; - Device* d3dDevice = (Device*)device; - Fence* fence = nullptr; - - fence = palAllocate(s_D3D.allocator, sizeof(Fence), 0); - if (!fence) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - result = d3dDevice->handle->lpVtbl->CreateFence( - d3dDevice->handle, - 0, - 0, - &IID_Fence, - (void**)&fence->handle); - - if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); - palFree(s_D3D.allocator, fence); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - fence->canReset = PAL_FALSE; - if (d3dDevice->features & PAL_ADAPTER_FEATURE_FENCE_RESET) { - fence->canReset = PAL_TRUE; - } - - fence->isTimeline = PAL_FALSE; // for sempaphores - fence->value = 0; - *outFence = (PalFence*)fence; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyFenceD3D12(PalFence* fence) -{ - Fence* d3dFence = (Fence*)fence; - d3dFence->handle->lpVtbl->Release(d3dFence->handle); - palFree(s_D3D.allocator, d3dFence); -} - -PalResult PAL_CALL waitFenceD3D12( - PalFence* fence, - uint64_t timeout) -{ - HRESULT result; - Fence* d3dFence = (Fence*)fence; - DWORD ret = 0; - uint64_t value = d3dFence->value; - - if (d3dFence->handle->lpVtbl->GetCompletedValue(d3dFence->handle) < value) { - HANDLE event = CreateEvent(nullptr, PAL_FALSE, PAL_FALSE, nullptr); - result = d3dFence->handle->lpVtbl->SetEventOnCompletion( - d3dFence->handle, - value, - event); - - if (FAILED(result)) { - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_FENCE; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - if (timeout == PAL_INFINITE) { - ret = WaitForSingleObject(event, INFINITE); - } else { - ret = WaitForSingleObject(event, (DWORD)timeout); - } - CloseHandle(event); - } - - if (ret == WAIT_TIMEOUT) { - return PAL_RESULT_TIMEOUT; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL resetFenceD3D12(PalFence* fence) -{ - Fence* d3dFence = (Fence*)fence; - if (!d3dFence->canReset) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - d3dFence->handle->lpVtbl->Signal(d3dFence->handle, 0); - d3dFence->value = 0; - return PAL_RESULT_SUCCESS; -} - -PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence) -{ - Fence* d3dFence = (Fence*)fence; - if (d3dFence->handle->lpVtbl->GetCompletedValue(d3dFence->handle) == 0) { - return PAL_FALSE; - } - return PAL_TRUE; -} - -// ================================================== -// Semaphore -// ================================================== - -PalResult PAL_CALL createSemaphoreD3D12( - PalDevice* device, - PalBool enableTimeline, - PalSemaphore** outSemaphore) -{ - HRESULT result; - Device* d3dDevice = (Device*)device; - Semaphore* semaphore = nullptr; - PalBool hasTimeline = d3dDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; - - semaphore = palAllocate(s_D3D.allocator, sizeof(Semaphore), 0); - if (!semaphore) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (enableTimeline && !hasTimeline) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (enableTimeline) { - semaphore->isTimeline = PAL_TRUE; - } - - result = d3dDevice->handle->lpVtbl->CreateFence( - d3dDevice->handle, - 0, - 0, - &IID_Fence, - (void**)&semaphore->handle); - - if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); - palFree(s_D3D.allocator, semaphore); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - semaphore->canReset = PAL_FALSE; - semaphore->value = 0; - *outSemaphore = (PalSemaphore*)semaphore; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore) -{ - Semaphore* d3dSemaphore = (Semaphore*)semaphore; - d3dSemaphore->handle->lpVtbl->Release(d3dSemaphore->handle); - palFree(s_D3D.allocator, d3dSemaphore); -} - -PalResult PAL_CALL waitSemaphoreD3D12( - PalSemaphore* semaphore, - uint64_t value, - uint64_t timeout) -{ - HRESULT result; - DWORD ret = 0; - Semaphore* d3dSemaphore = (Semaphore*)semaphore; - if (!d3dSemaphore->isTimeline) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (d3dSemaphore->handle->lpVtbl->GetCompletedValue(d3dSemaphore->handle) < value) { - HANDLE event = CreateEvent(nullptr, PAL_FALSE, PAL_FALSE, nullptr); - result = d3dSemaphore->handle->lpVtbl->SetEventOnCompletion( - d3dSemaphore->handle, - value, - event); - - if (FAILED(result)) { - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_SEMAPHORE; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - if (timeout == PAL_INFINITE) { - ret = WaitForSingleObject(event, INFINITE); - } else { - ret = WaitForSingleObject(event, (DWORD)timeout); - } - CloseHandle(event); - } - - if (ret == WAIT_TIMEOUT) { - return PAL_RESULT_TIMEOUT; + convertToWcharD3D12(info->entries[i].entryName, entry->entryName); + entry->patchControlPoints = info->entries[i].patchControlPoints; + entry->stage = info->entries[i].stage; } - return PAL_RESULT_SUCCESS; -} -PalResult PAL_CALL signalSemaphoreD3D12( - PalSemaphore* semaphore, - PalQueue* queue, - uint64_t value) -{ - Semaphore* d3dSemaphore = (Semaphore*)semaphore; - if (!d3dSemaphore->isTimeline) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } + memcpy(bytecode, info->bytecode, info->bytecodeSize); + shader->byteCode.pShaderBytecode = bytecode; + shader->byteCode.BytecodeLength = info->bytecodeSize; - HRESULT result = d3dSemaphore->handle->lpVtbl->Signal(d3dSemaphore->handle, value); - if (FAILED(result)) { - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_SEMAPHORE; - } - return PAL_RESULT_PLATFORM_FAILURE; - } + shader->entryCount = info->entryCount; + *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getSemaphoreValueD3D12( - PalSemaphore* semaphore, - uint64_t* outValue) +void PAL_CALL destroyShaderD3D12(PalShader* shader) { - Semaphore* d3dSemaphore = (Semaphore*)semaphore; - if (!d3dSemaphore->isTimeline) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - UINT64 tmp = d3dSemaphore->handle->lpVtbl->GetCompletedValue(d3dSemaphore->handle); - *outValue = tmp; - return PAL_RESULT_SUCCESS; + Shader* d3dShader = (Shader*)shader; + palFree(s_D3D12.allocator, (void*)d3dShader->byteCode.pShaderBytecode); + palFree(s_D3D12.allocator, d3dShader->entries); + palFree(s_D3D12.allocator, d3dShader); } // ================================================== @@ -4658,7 +3418,7 @@ PalResult PAL_CALL createCommandPoolD3D12( CommandPool* pool = nullptr; Queue* d3dQueue = (Queue*)queue; - pool = palAllocate(s_D3D.allocator, sizeof(CommandPool), 0); + pool = palAllocate(s_D3D12.allocator, sizeof(CommandPool), 0); if (!pool) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4666,7 +3426,7 @@ PalResult PAL_CALL createCommandPoolD3D12( pool->size = 8; pool->cmdBuffersData = nullptr; uint32_t size = sizeof(CommandBufferData) * pool->size; - pool->cmdBuffersData = palAllocate(s_D3D.allocator, size, 0); + pool->cmdBuffersData = palAllocate(s_D3D12.allocator, size, 0); if (!pool->cmdBuffersData) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4705,8 +3465,8 @@ void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) cmdBuffer->allocator->lpVtbl->Release(cmdBuffer->allocator); } - palFree(s_D3D.allocator, cmdPool->cmdBuffersData); - palFree(s_D3D.allocator, cmdPool); + palFree(s_D3D12.allocator, cmdPool->cmdBuffersData); + palFree(s_D3D12.allocator, cmdPool); } PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool) @@ -4730,11 +3490,11 @@ PalResult PAL_CALL allocateCommandBufferD3D12( PalCommandBuffer** outCmdBuffer) { HRESULT result; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; CommandBuffer* cmdBuffer = nullptr; CommandPool* cmdPool = (CommandPool*)pool; - cmdBuffer = palAllocate(s_D3D.allocator, sizeof(CommandBuffer), 0); + cmdBuffer = palAllocate(s_D3D12.allocator, sizeof(CommandBuffer), 0); if (!cmdBuffer) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4749,14 +3509,14 @@ PalResult PAL_CALL allocateCommandBufferD3D12( } // create an allocator - result = d3dDevice->handle->lpVtbl->CreateCommandAllocator( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateCommandAllocator( + d3d12Device->handle, cmdBufferType, &IID_CommandAllocator, (void**)&cmdBuffer->allocator); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4765,8 +3525,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( // create the command list ID3D12GraphicsCommandList* cmdList = nullptr; - result = d3dDevice->handle->lpVtbl->CreateCommandList( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateCommandList( + d3d12Device->handle, 0, cmdBufferType, cmdBuffer->allocator, @@ -4775,7 +3535,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdList); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -4783,7 +3543,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( } // we need a tmp staging and gpu buffer if ray tracing is enabled - if (d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + if (d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { D3D12_HEAP_PROPERTIES heapProps = {0}; heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; heapProps.VisibleNodeMask = 1; @@ -4798,8 +3558,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( bufferDesc.SampleDesc.Count = 1; bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - result = d3dDevice->handle->lpVtbl->CreateCommittedResource( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateCommittedResource( + d3d12Device->handle, &heapProps, 0, &bufferDesc, @@ -4817,8 +3577,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( // create staging buffer heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - result = d3dDevice->handle->lpVtbl->CreateCommittedResource( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateCommittedResource( + d3d12Device->handle, &heapProps, 0, &bufferDesc, @@ -4848,7 +3608,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( cmdBuffer->handle->lpVtbl->Close(cmdBuffer->handle); cmdBuffer->pool = cmdPool; - cmdBuffer->device = d3dDevice; + cmdBuffer->device = d3d12Device; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; } @@ -4867,7 +3627,7 @@ void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) d3dCmdBuffer->stagingBuffer->lpVtbl->Release(d3dCmdBuffer->stagingBuffer); } - palFree(s_D3D.allocator, cmdBuffer); + palFree(s_D3D12.allocator, cmdBuffer); data->cmdBuffer = nullptr; data->used = PAL_FALSE; } @@ -5116,7 +3876,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { geometries = palAllocate( - s_D3D.allocator, + s_D3D12.allocator, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount, 0); @@ -5142,7 +3902,7 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( 0, nullptr); - palFree(s_D3D.allocator, geometries); + palFree(s_D3D12.allocator, geometries); } else { PalBool success = fillBuildInfoD3D12( @@ -5525,7 +4285,7 @@ PalResult PAL_CALL cmdSetViewportD3D12( D3D12_VIEWPORT* d3dViewports = nullptr; if (count > 1) { - d3dViewports = palAllocate(s_D3D.allocator, sizeof(D3D12_VIEWPORT) * count, 0); + d3dViewports = palAllocate(s_D3D12.allocator, sizeof(D3D12_VIEWPORT) * count, 0); if (!d3dViewports) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -5546,7 +4306,7 @@ PalResult PAL_CALL cmdSetViewportD3D12( d3dCmdBuffer->handle->lpVtbl->RSSetViewports(d3dCmdBuffer->handle, count, d3dViewports); if (count > 1) { - palFree(s_D3D.allocator, d3dViewports); + palFree(s_D3D12.allocator, d3dViewports); } return PAL_RESULT_SUCCESS; } @@ -5561,7 +4321,7 @@ PalResult PAL_CALL cmdSetScissorsD3D12( D3D12_RECT* d3dScissors = nullptr; if (count > 1) { - d3dScissors = palAllocate(s_D3D.allocator, sizeof(D3D12_RECT) * count, 0); + d3dScissors = palAllocate(s_D3D12.allocator, sizeof(D3D12_RECT) * count, 0); if (!d3dScissors) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -5580,7 +4340,7 @@ PalResult PAL_CALL cmdSetScissorsD3D12( d3dCmdBuffer->handle->lpVtbl->RSSetScissorRects(d3dCmdBuffer->handle, count, d3dScissors); if (count > 1) { - palFree(s_D3D.allocator, d3dScissors); + palFree(s_D3D12.allocator, d3dScissors); } return PAL_RESULT_SUCCESS; } @@ -5602,7 +4362,7 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( } if (count > 1) { - views = palAllocate(s_D3D.allocator, sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, 0); + views = palAllocate(s_D3D12.allocator, sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, 0); if (!views) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -5626,7 +4386,7 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( views); if (count > 1) { - palFree(s_D3D.allocator, views); + palFree(s_D3D12.allocator, views); } return PAL_RESULT_SUCCESS; } @@ -5897,7 +4657,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( return PAL_RESULT_SUCCESS; } - barriers = palAllocate(s_D3D.allocator, sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, 0); + barriers = palAllocate(s_D3D12.allocator, sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, 0); if (!barriers) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -5919,7 +4679,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( } d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, barrierCount, barriers); - palFree(s_D3D.allocator, barriers); + palFree(s_D3D12.allocator, barriers); return PAL_RESULT_SUCCESS; } @@ -6302,107 +5062,6 @@ PalResult PAL_CALL cmdSetStencilOpD3D12( // Acceleration Structure // ================================================== -PalResult PAL_CALL createAccelerationstructureD3D12( - PalDevice* device, - const PalAccelerationStructureCreateInfo* info, - PalAccelerationStructure** outAs) -{ - HRESULT result; - AccelerationStructure* as = nullptr; - Device* d3dDevice = (Device*)device; - Buffer* d3dBuffer = (Buffer*)info->buffer; - - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - as = palAllocate(s_D3D.allocator, sizeof(AccelerationStructure), 0); - if (!as) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - as->type = info->type; - as->handle = d3dBuffer->handle; - as->address = as->handle->lpVtbl->GetGPUVirtualAddress(as->handle); - as->address += info->offset; - - *outAs = (PalAccelerationStructure*)as; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as) -{ - AccelerationStructure* d3dAs = (AccelerationStructure*)as; - palFree(s_D3D.allocator, d3dAs); -} - -PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( - PalDevice* device, - PalAccelerationStructureBuildInfo* info, - PalAccelerationStructureBuildSize* size) -{ - Device* d3dDevice = (Device*)device; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; - D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO sizeInfo = {0}; - - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - geometries = palAllocate( - s_D3D.allocator, - sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount, - 0); - - if (!geometries) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); - PalBool success = fillBuildInfoD3D12( - info, - geometries, - 0, - 0, - &buildInfo); - - if (!success) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - d3dDevice->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( - d3dDevice->handle, - &buildInfo.Inputs, - &sizeInfo); - - palFree(s_D3D.allocator, geometries); - - } else { - PalBool success = fillBuildInfoD3D12( - info, - nullptr, - 0, - 0, - &buildInfo); - - if (!success) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - d3dDevice->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( - d3dDevice->handle, - &buildInfo.Inputs, - &sizeInfo); - } - - size->accelerationStructureSize = (UINT)sizeInfo.ResultDataMaxSizeInBytes; - size->scratchBufferSize = (UINT)sizeInfo.ScratchDataSizeInBytes; - size->updateScratchBufferSize = (UINT)sizeInfo.UpdateScratchDataSizeInBytes; - return PAL_RESULT_SUCCESS; -} - // ================================================== // Buffer // ================================================== @@ -6414,20 +5073,20 @@ PalResult PAL_CALL createBufferD3D12( { HRESULT result; Buffer* buffer = nullptr; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } - buffer = palAllocate(s_D3D.allocator, sizeof(Buffer), 0); + buffer = palAllocate(s_D3D12.allocator, sizeof(Buffer), 0); if (!buffer) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -6464,7 +5123,7 @@ PalResult PAL_CALL createBufferD3D12( buffer->hasIndirect = PAL_TRUE; } - buffer->device = d3dDevice; + buffer->device = d3d12Device; buffer->size = info->size; *outBuffer = (PalBuffer*)buffer; return PAL_RESULT_SUCCESS; @@ -6477,7 +5136,7 @@ void PAL_CALL destroyBufferD3D12(PalBuffer* buffer) if (d3dBuffer->handle) { d3dBuffer->handle->lpVtbl->Release(d3dBuffer->handle); } - palFree(s_D3D.allocator, d3dBuffer); + palFree(s_D3D12.allocator, d3dBuffer); } PalResult PAL_CALL getBufferMemoryRequirementsD3D12( @@ -6690,18 +5349,18 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( PalDescriptorSetLayout** outLayout) { HRESULT result; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; DescriptorSetLayout* layout = nullptr; DescriptorSetBinding* bindings = nullptr; uint32_t count = info->bindingCount; - PalBool hasDescriptorIndexing = d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + PalBool hasDescriptorIndexing = d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - layout = palAllocate(s_D3D.allocator, sizeof(DescriptorSetLayout), 0); - bindings = palAllocate(s_D3D.allocator, sizeof(DescriptorSetBinding) * count, 0); + layout = palAllocate(s_D3D12.allocator, sizeof(DescriptorSetLayout), 0); + bindings = palAllocate(s_D3D12.allocator, sizeof(DescriptorSetBinding) * count, 0); if (!layout || !bindings) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -6857,27 +5516,27 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( } // check limits - if (sampledImageCount > d3dDevice->limits.maxDescriptorSampledImages) { + if (sampledImageCount > d3d12Device->limits.maxDescriptorSampledImages) { return PAL_RESULT_INVALID_ARGUMENT; } - if (storageImageCount > d3dDevice->limits.maxDescriptorStorageImages) { + if (storageImageCount > d3d12Device->limits.maxDescriptorStorageImages) { return PAL_RESULT_INVALID_ARGUMENT; } - if (storageBufferCount > d3dDevice->limits.maxDescriptorStorageBuffers) { + if (storageBufferCount > d3d12Device->limits.maxDescriptorStorageBuffers) { return PAL_RESULT_INVALID_ARGUMENT; } - if (uniformBufferCount > d3dDevice->limits.maxDescriptorUniformBuffers) { + if (uniformBufferCount > d3d12Device->limits.maxDescriptorUniformBuffers) { return PAL_RESULT_INVALID_ARGUMENT; } - if (tlasCount > d3dDevice->limits.maxDescriptorAccelerationStructures) { + if (tlasCount > d3d12Device->limits.maxDescriptorAccelerationStructures) { return PAL_RESULT_INVALID_ARGUMENT; } - if (samplerCount > d3dDevice->limits.maxDescriptorSamplers) { + if (samplerCount > d3d12Device->limits.maxDescriptorSamplers) { return PAL_RESULT_INVALID_ARGUMENT; } @@ -6892,8 +5551,8 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout) { DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; - palFree(s_D3D.allocator, d3dLayout->bindings); - palFree(s_D3D.allocator, d3dLayout); + palFree(s_D3D12.allocator, d3dLayout->bindings); + palFree(s_D3D12.allocator, d3dLayout); } PalResult PAL_CALL createDescriptorPoolD3D12( @@ -6902,21 +5561,21 @@ PalResult PAL_CALL createDescriptorPoolD3D12( PalDescriptorPool** outPool) { HRESULT result; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; DescriptorPool* pool = nullptr; - PalBool hasDescriptorIndexing = d3dDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; + PalBool hasDescriptorIndexing = d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - pool = palAllocate(s_D3D.allocator, sizeof(DescriptorPool), 0); + pool = palAllocate(s_D3D12.allocator, sizeof(DescriptorPool), 0); if (!pool) { return PAL_RESULT_OUT_OF_MEMORY; } memset(pool, 0, sizeof(DescriptorPool)); - pool->sets = palAllocate(s_D3D.allocator, sizeof(DescriptorSet) * info->maxDescriptorSets, 0); + pool->sets = palAllocate(s_D3D12.allocator, sizeof(DescriptorSet) * info->maxDescriptorSets, 0); if (!pool->sets) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -6961,14 +5620,14 @@ PalResult PAL_CALL createDescriptorPoolD3D12( desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; desc.NumDescriptors = resourceCount; - result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateDescriptorHeap( + d3d12Device->handle, &desc, &IID_DescriptorHeap, (void**)&heap->handle); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_OUTOFMEMORY) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -6976,8 +5635,8 @@ PalResult PAL_CALL createDescriptorPoolD3D12( } // get increment size - heap->incrementSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( - d3dDevice->handle, + heap->incrementSize = d3d12Device->handle->lpVtbl->GetDescriptorHandleIncrementSize( + d3d12Device->handle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); // get base CPU and GPU base pointer @@ -7005,23 +5664,23 @@ PalResult PAL_CALL createDescriptorPoolD3D12( desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; desc.NumDescriptors = limits->maxSamplers; - result = d3dDevice->handle->lpVtbl->CreateDescriptorHeap( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateDescriptorHeap( + d3d12Device->handle, &desc, &IID_DescriptorHeap, (void**)&heap->handle); if (FAILED(result)) { if (result == E_OUTOFMEMORY) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); return PAL_RESULT_OUT_OF_MEMORY; } return PAL_RESULT_PLATFORM_FAILURE; } // get increment size - heap->incrementSize = d3dDevice->handle->lpVtbl->GetDescriptorHandleIncrementSize( - d3dDevice->handle, + heap->incrementSize = d3d12Device->handle->lpVtbl->GetDescriptorHandleIncrementSize( + d3d12Device->handle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); // get base CPU and GPU base pointer @@ -7055,8 +5714,8 @@ void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) d3dPool->samplerHeap.handle->lpVtbl->Release(d3dPool->samplerHeap.handle); } - palFree(s_D3D.allocator, d3dPool->sets); - palFree(s_D3D.allocator, d3dPool); + palFree(s_D3D12.allocator, d3dPool->sets); + palFree(s_D3D12.allocator, d3dPool); } PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool) @@ -7081,7 +5740,7 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( PalDescriptorSetLayout* layout, PalDescriptorSet** outSet) { - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; DescriptorPool* d3dPool = (DescriptorPool*)pool; DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; DescriptorSet* set = nullptr; @@ -7180,7 +5839,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( uint32_t count, PalDescriptorSetWriteInfo* infos) { - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; for (int i = 0; i < count; i++) { PalDescriptorSetWriteInfo* info = &infos[i]; DescriptorSet* set = (DescriptorSet*)info->descriptorSet; @@ -7212,10 +5871,10 @@ PalResult PAL_CALL updateDescriptorSetD3D12( if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { if (info->samplerInfos) { Sampler* sampler = (Sampler*)info->samplerInfos[j].sampler; - d3dDevice->handle->lpVtbl->CreateSampler(d3dDevice->handle, &sampler->desc, dst); + d3d12Device->handle->lpVtbl->CreateSampler(d3d12Device->handle, &sampler->desc, dst); } else { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7228,7 +5887,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; - d3dDevice->handle->lpVtbl->CreateSampler(d3dDevice->handle, &desc, dst); + d3d12Device->handle->lpVtbl->CreateSampler(d3d12Device->handle, &desc, dst); } } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { @@ -7242,13 +5901,13 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.RaytracingAccelerationStructure.Location = tlas->address; } else { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } - d3dDevice->handle->lpVtbl->CreateShaderResourceView( - d3dDevice->handle, + d3d12Device->handle->lpVtbl->CreateShaderResourceView( + d3d12Device->handle, nullptr, &desc, dst); @@ -7269,7 +5928,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( handle = imageView->image->handle; } else { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7288,8 +5947,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( &desc, nullptr); - d3dDevice->handle->lpVtbl->CreateShaderResourceView( - d3dDevice->handle, + d3d12Device->handle->lpVtbl->CreateShaderResourceView( + d3d12Device->handle, handle, &desc, dst); @@ -7308,7 +5967,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( handle = imageView->image->handle; } else { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } @@ -7327,8 +5986,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( nullptr, &desc); - d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( - d3dDevice->handle, + d3d12Device->handle->lpVtbl->CreateUnorderedAccessView( + d3d12Device->handle, handle, nullptr, &desc, @@ -7346,13 +6005,13 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.BufferLocation = address + bufferInfo->offset; } else { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } - d3dDevice->handle->lpVtbl->CreateConstantBufferView( - d3dDevice->handle, + d3d12Device->handle->lpVtbl->CreateConstantBufferView( + d3d12Device->handle, &desc, dst); @@ -7380,13 +6039,13 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.Buffer.NumElements = bufferInfo->size / stride; } else { - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } } - d3dDevice->handle->lpVtbl->CreateUnorderedAccessView( - d3dDevice->handle, + d3d12Device->handle->lpVtbl->CreateUnorderedAccessView( + d3d12Device->handle, handle, nullptr, &desc, @@ -7406,7 +6065,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout) { - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; PipelineLayout* layout = nullptr; uint32_t resourceCount = 0; uint32_t samplerCount = 0; @@ -7423,11 +6082,11 @@ PalResult PAL_CALL createPipelineLayoutD3D12( D3D12_ROOT_SIGNATURE_FLAGS rootFlags = 0; rootFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; - if (info->descriptorSetLayoutCount > d3dDevice->limits.maxBoundDescriptorSets) { + if (info->descriptorSetLayoutCount > d3d12Device->limits.maxBoundDescriptorSets) { return PAL_RESULT_INVALID_ARGUMENT; } - if (d3dDevice->shaderModel >= PAL_MAKE_SHADER_TARGET(6, 6)) { + if (d3d12Device->shaderModel >= PAL_MAKE_SHADER_TARGET(6, 6)) { rootFlags |= D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED; rootFlags |= D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED; } @@ -7455,11 +6114,11 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } } - if (pushConstantSize > d3dDevice->limits.maxPushConstantSize) { + if (pushConstantSize > d3d12Device->limits.maxPushConstantSize) { return PAL_RESULT_INVALID_ARGUMENT; } - layout = palAllocate(s_D3D.allocator, sizeof(PipelineLayout), 0); + layout = palAllocate(s_D3D12.allocator, sizeof(PipelineLayout), 0); if (!layout) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7470,7 +6129,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( if (parameterCount) { uint32_t paramtersSize = sizeof(D3D12_ROOT_PARAMETER1) * parameterCount; - parameters = palAllocate(s_D3D.allocator, paramtersSize, 0); + parameters = palAllocate(s_D3D12.allocator, paramtersSize, 0); if (!parameters) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7479,14 +6138,14 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } if (resourceCount) { - ranges = palAllocate(s_D3D.allocator, sizeInBytes * resourceCount, 0); + ranges = palAllocate(s_D3D12.allocator, sizeInBytes * resourceCount, 0); if (!ranges) { return PAL_RESULT_OUT_OF_MEMORY; } } if (samplerCount) { - samplerRanges = palAllocate(s_D3D.allocator, sizeInBytes * samplerCount, 0); + samplerRanges = palAllocate(s_D3D12.allocator, sizeInBytes * samplerCount, 0); if (!samplerRanges) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7567,17 +6226,17 @@ PalResult PAL_CALL createPipelineLayoutD3D12( rootDesc.Desc_1_1.Flags = rootFlags; ID3DBlob* blob = nullptr; - HRESULT result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); + HRESULT result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } return PAL_RESULT_PLATFORM_FAILURE; } - result = d3dDevice->handle->lpVtbl->CreateRootSignature( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateRootSignature( + d3d12Device->handle, 0, blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), @@ -7585,7 +6244,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( (void**)&layout->handle); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } else if (result == E_OUTOFMEMORY) { @@ -7595,15 +6254,15 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } if (resourceCount) { - palFree(s_D3D.allocator, ranges); + palFree(s_D3D12.allocator, ranges); } if (samplerCount) { - palFree(s_D3D.allocator, samplerRanges); + palFree(s_D3D12.allocator, samplerRanges); } if (parameterCount) { - palFree(s_D3D.allocator, parameters); + palFree(s_D3D12.allocator, parameters); } blob->lpVtbl->Release(blob); @@ -7615,7 +6274,7 @@ void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout) { PipelineLayout* d3dLayout = (PipelineLayout*)layout; d3dLayout->handle->lpVtbl->Release(d3dLayout->handle); - palFree(s_D3D.allocator, d3dLayout); + palFree(s_D3D12.allocator, d3dLayout); } // ================================================== @@ -7632,7 +6291,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( uint32_t totalSize = 0; PalBool alphaToCoverageEnable = PAL_FALSE; Pipeline* pipeline = nullptr; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; D3D12_INPUT_ELEMENT_DESC* elementDescs = nullptr; @@ -7641,7 +6300,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( GraphicsPipelineStreamDesc graphicsStreamDesc = {0}; memset(&graphicsStreamDesc, 0, sizeof(GraphicsPipelineStreamDesc)); - pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); + pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); if (!pipeline) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -7649,7 +6308,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( if (info->renderingLayout->viewCount > 1) { viewLocations = palAllocate( - s_D3D.allocator, + s_D3D12.allocator, sizeof(D3D12_VIEW_INSTANCE_LOCATION) * info->renderingLayout->viewCount, 0); @@ -7675,7 +6334,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( if (entry->patchControlPoints) { patchControlPoints = entry->patchControlPoints; if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { - palFree(s_D3D.allocator, pipeline); + palFree(s_D3D12.allocator, pipeline); return PAL_RESULT_INVALID_OPERATION; } } @@ -7716,11 +6375,11 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( vertexCount += layout->attributeCount; } - if (info->vertexLayoutCount > d3dDevice->limits.maxVertexLayouts) { + if (info->vertexLayoutCount > d3d12Device->limits.maxVertexLayouts) { return PAL_RESULT_INVALID_ARGUMENT; } - if (vertexCount > d3dDevice->limits.maxVertexAttributes) { + if (vertexCount > d3d12Device->limits.maxVertexAttributes) { return PAL_RESULT_INVALID_ARGUMENT; } @@ -7730,18 +6389,18 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( pipeline->strides = nullptr; if (vertexCount) { - pipeline->strides = palAllocate(s_D3D.allocator, sizeof(uint32_t) * 8, 0); + pipeline->strides = palAllocate(s_D3D12.allocator, sizeof(uint32_t) * 8, 0); if (!pipeline->strides) { return PAL_RESULT_OUT_OF_MEMORY; } elementDescs = palAllocate( - s_D3D.allocator, + s_D3D12.allocator, sizeof(D3D12_INPUT_ELEMENT_DESC) * vertexCount, 0); if (!elementDescs) { - palFree(s_D3D.allocator, elementDescs); + palFree(s_D3D12.allocator, elementDescs); return PAL_RESULT_OUT_OF_MEMORY; } @@ -8060,14 +6719,14 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( streamDesc.pPipelineStateSubobjectStream = &graphicsStreamDesc; streamDesc.SizeInBytes = totalSize; - result = d3dDevice->handle->lpVtbl->CreatePipelineState( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreatePipelineState( + d3d12Device->handle, &streamDesc, &IID_PipelineState, &pipeline->handle); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } else if (result == E_OUTOFMEMORY) { @@ -8077,11 +6736,11 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( } if (info->vertexLayoutCount) { - palFree(s_D3D.allocator, elementDescs); + palFree(s_D3D12.allocator, elementDescs); } if (info->renderingLayout->viewCount > 1) { - palFree(s_D3D.allocator, viewLocations); + palFree(s_D3D12.allocator, viewLocations); } pipeline->topology = topology; @@ -8099,12 +6758,12 @@ PalResult PAL_CALL createComputePipelineD3D12( const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline) { - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; Shader* shader = (Shader*)info->computeShader; Pipeline* pipeline = nullptr; - pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); + pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); if (!pipeline) { return PAL_RESULT_OUT_OF_MEMORY; } @@ -8113,14 +6772,14 @@ PalResult PAL_CALL createComputePipelineD3D12( desc.CS = shader->byteCode; desc.pRootSignature = layout->handle; - HRESULT result = d3dDevice->handle->lpVtbl->CreateComputePipelineState( - d3dDevice->handle, + HRESULT result = d3d12Device->handle->lpVtbl->CreateComputePipelineState( + d3d12Device->handle, &desc, &IID_PipelineState, &pipeline->handle); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } else if (result == E_OUTOFMEMORY) { @@ -8146,23 +6805,23 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( PalPipeline** outPipeline) { HRESULT result; - Device* d3dDevice = (Device*)device; + Device* d3d12Device = (Device*)device; PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; Pipeline* pipeline = nullptr; - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; } - if (info->maxAttributeSize > d3dDevice->limits.maxHitAttributeSize) { + if (info->maxAttributeSize > d3d12Device->limits.maxHitAttributeSize) { return PAL_RESULT_INVALID_ARGUMENT; } - if (info->maxPayloadSize > d3dDevice->limits.maxPayloadSize) { + if (info->maxPayloadSize > d3d12Device->limits.maxPayloadSize) { return PAL_RESULT_INVALID_ARGUMENT; } - if (info->maxRecursionDepth> d3dDevice->limits.maxRecursionDepth) { + if (info->maxRecursionDepth> d3d12Device->limits.maxRecursionDepth) { return PAL_RESULT_INVALID_ARGUMENT; } @@ -8238,35 +6897,35 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( subObjectCount += 2; } - pipeline = palAllocate(s_D3D.allocator, sizeof(Pipeline), 0); + pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); if (!pipeline) { return PAL_RESULT_OUT_OF_MEMORY; } pipeline->shaderExportCount = exportCount + sbtInfo.hitCount; - subObjects = palAllocate(s_D3D.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); - hitGroups = palAllocate(s_D3D.allocator, sizeof(RayHitGroup) * sbtInfo.hitCount, 0); + subObjects = palAllocate(s_D3D12.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); + hitGroups = palAllocate(s_D3D12.allocator, sizeof(RayHitGroup) * sbtInfo.hitCount, 0); if (!subObjects || !hitGroups) { return PAL_RESULT_OUT_OF_MEMORY; } libraryDescs = palAllocate( - s_D3D.allocator, + s_D3D12.allocator, sizeof(D3D12_DXIL_LIBRARY_DESC) * info->shaderCount, 0); exportDescs = palAllocate( - s_D3D.allocator, + s_D3D12.allocator, sizeof(D3D12_EXPORT_DESC) * exportCount, 0); pipeline->shaderExports = palAllocate( - s_D3D.allocator, + s_D3D12.allocator, sizeof(ShaderExport) * pipeline->shaderExportCount, 0); localExports = palAllocate( - s_D3D.allocator, + s_D3D12.allocator, sizeof(wchar_t*) * localExportCount, 0); @@ -8420,17 +7079,17 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( rootDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; ID3DBlob* blob = nullptr; - result = s_D3D.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); + result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } return PAL_RESULT_PLATFORM_FAILURE; } - result = d3dDevice->handle->lpVtbl->CreateRootSignature( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateRootSignature( + d3d12Device->handle, 0, blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), @@ -8438,7 +7097,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( (void**)&pipeline->localRootSignature); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } else if (result == E_OUTOFMEMORY) { @@ -8467,14 +7126,14 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( desc.NumSubobjects = subObjectCount; desc.pSubobjects = subObjects; - result = d3dDevice->handle->lpVtbl->CreateStateObject( - d3dDevice->handle, + result = d3d12Device->handle->lpVtbl->CreateStateObject( + d3d12Device->handle, &desc, &IID_StateObject, &pipeline->handle); if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); + pollMessagesD3D12(d3d12Device); if (result == E_INVALIDARG) { return PAL_RESULT_INVALID_ARGUMENT; } else if (result == E_OUTOFMEMORY) { @@ -8483,11 +7142,11 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_PLATFORM_FAILURE; } - palFree(s_D3D.allocator, hitGroups); - palFree(s_D3D.allocator, subObjects); - palFree(s_D3D.allocator, libraryDescs); - palFree(s_D3D.allocator, exportDescs); - palFree(s_D3D.allocator, localExports); + palFree(s_D3D12.allocator, hitGroups); + palFree(s_D3D12.allocator, subObjects); + palFree(s_D3D12.allocator, libraryDescs); + palFree(s_D3D12.allocator, exportDescs); + palFree(s_D3D12.allocator, localExports); pipeline->type = RAY_TRACING_PIPELINE; pipeline->strides = nullptr; @@ -8516,445 +7175,21 @@ void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) } if (d3dPipeline->strides) { - palFree(s_D3D.allocator, d3dPipeline->strides); + palFree(s_D3D12.allocator, d3dPipeline->strides); } if (d3dPipeline->shaderExports) { - palFree(s_D3D.allocator, d3dPipeline->shaderExports); + palFree(s_D3D12.allocator, d3dPipeline->shaderExports); } - palFree(s_D3D.allocator, d3dPipeline); + palFree(s_D3D12.allocator, d3dPipeline); } // ================================================== // Shader Binding Table // ================================================== -PalResult PAL_CALL createShaderBindingTableD3D12( - PalDevice* device, - const PalShaderBindingTableCreateInfo* info, - PalShaderBindingTable** outSbt) -{ - HRESULT result; - Device* d3dDevice = (Device*)device; - ShaderBindingTable* sbt = nullptr; - Pipeline* pipeline = (Pipeline*)info->rayTracingPipeline; - ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; - - if (!(d3dDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - uint32_t totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; - totalGroups += sbtInfo->missCount + sbtInfo->callableCount; - if (info->recordCount != totalGroups) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - void** raygenHandles = nullptr; - void** missHandles = nullptr; - void** hitHandles = nullptr; - void** callableHandles = nullptr; - - sbt = palAllocate(s_D3D.allocator, sizeof(ShaderBindingTable), 0); - if (!sbt) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(sbt, 0, sizeof(ShaderBindingTable)); - if (sbtInfo->raygenCount) { - raygenHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->raygenCount, 0); - if (!raygenHandles) { - return PAL_RESULT_OUT_OF_MEMORY; - } - } - - if (sbtInfo->missCount) { - missHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->missCount, 0); - if (!missHandles) { - return PAL_RESULT_OUT_OF_MEMORY; - } - } - - if (sbtInfo->hitCount) { - hitHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->hitCount, 0); - if (!hitHandles) { - return PAL_RESULT_OUT_OF_MEMORY; - } - } - - if (sbtInfo->callableCount) { - callableHandles = palAllocate(s_D3D.allocator, sizeof(void*) * sbtInfo->callableCount, 0); - if (!callableHandles) { - return PAL_RESULT_OUT_OF_MEMORY; - } - } - - // create SBT buffer - ID3D12StateObject* pipelineHandle = pipeline->handle; - ID3D12StateObjectProperties* props = NULL; - result = pipelineHandle->lpVtbl->QueryInterface( - pipelineHandle, - &IID_StateObjectProps, - (void**)&props); - - if (FAILED(result)) { - pollMessagesD3D12(d3dDevice); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_PIPELINE; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - uint32_t groupHandleSize = D3D12_SHADER_IDENTIFIER_SIZE_IN_BYTES; - uint32_t groupHandleAlignment = D3D12_RAYTRACING_SHADER_RECORD_BYTE_ALIGNMENT; - uint32_t groupBaseAlignment = D3D12_RAYTRACING_SHADER_TABLE_BYTE_ALIGNMENT; - - // get the max local data size - for (int i = 0; i < info->recordCount; i++) { - PalShaderBindingTableRecordInfo* record = &info->records[i]; - uint32_t index = record->groupIndex; - - if (index < sbtInfo->raygenCount) { - // raygen group - if (record->localDataSize > sbtInfo->raygenDataSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { - // miss group - if (record->localDataSize > sbtInfo->missDataSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { - // hit group - if (record->localDataSize > sbtInfo->hitDataSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - } else { - // callable group - if (record->localDataSize > sbtInfo->callableDataSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - } - } - - // get strides - uint32_t raygenStride = 0; - uint32_t missStride = 0; - uint32_t hitStride = 0; - uint32_t callableStride = 0; - - raygenStride = alignD3D12(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); - missStride = alignD3D12(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); - hitStride = alignD3D12(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); - callableStride = alignD3D12(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); - - // get region size - uint32_t raygenRegionSize = raygenStride * sbtInfo->raygenCount; - uint32_t missRegionSize = missStride * sbtInfo->missCount; - uint32_t hitRegionSize = hitStride * sbtInfo->hitCount; - uint32_t callableRegionSize = callableStride * sbtInfo->callableCount; - - // get offsets - uint32_t offset = 0; - uint32_t raygenOffset = 0; - uint32_t missOffset = 0; - uint32_t hitOffset = 0; - uint32_t callableOffset = 0; - - raygenOffset = alignD3D12(offset, groupBaseAlignment); - offset = raygenOffset + raygenRegionSize; - - missOffset = alignD3D12(offset, groupBaseAlignment); - offset = missOffset + missRegionSize; - - hitOffset = alignD3D12(offset, groupBaseAlignment); - offset = hitOffset + hitRegionSize; - - callableOffset = alignD3D12(offset, groupBaseAlignment); - offset = callableOffset + callableRegionSize; - - uint32_t bufferSize = alignD3D12(offset, groupBaseAlignment); - - // create gpu buffer - D3D12_HEAP_PROPERTIES heapProps = {0}; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - - D3D12_RESOURCE_DESC bufferDesc = {0}; - bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - bufferDesc.Width = bufferSize; - bufferDesc.Height = 1; - bufferDesc.DepthOrArraySize = 1; - bufferDesc.MipLevels = 1; - bufferDesc.SampleDesc.Count = 1; - bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - - result = d3dDevice->handle->lpVtbl->CreateCommittedResource( - d3dDevice->handle, - &heapProps, - 0, - &bufferDesc, - D3D12_RESOURCE_STATE_COPY_DEST, - nullptr, - &IID_Resource, - (void**)&sbt->buffer); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // create staging buffer - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - result = d3dDevice->handle->lpVtbl->CreateCommittedResource( - d3dDevice->handle, - &heapProps, - 0, - &bufferDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - &IID_Resource, - (void**)&sbt->stagingBuffer); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // get shader group handles - uint32_t raygenIndex = 0; - uint32_t missIndex = 0; - uint32_t hitIndex = 0; - uint32_t callableIndex = 0; - - for (int i = 0; i < pipeline->shaderExportCount; i++) { - ShaderExport* tmp = &pipeline->shaderExports[i]; - PalShaderStage stage = tmp->stage; - - // skip any hit, closest hit, intersection shaders without isHitGroup PalBool - PalBool isHitGroup = PAL_FALSE; - if (stage == PAL_SHADER_STAGE_ANY_HIT || - stage == PAL_SHADER_STAGE_CLOSEST_HIT || - stage == PAL_SHADER_STAGE_INTERSECTION) { - if (tmp->isHitGroup) { - isHitGroup = PAL_TRUE; - - } else { - continue; - } - } - - void* handle = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); - if (stage == PAL_SHADER_STAGE_RAYGEN) { - raygenHandles[raygenIndex++] = handle; - - } else if (stage == PAL_SHADER_STAGE_MISS) { - missHandles[missIndex++] = handle; - - } else if (isHitGroup) { - hitHandles[hitIndex++] = handle; - - } else if (stage == PAL_SHADER_STAGE_CALLABLE) { - callableHandles[callableIndex++] = handle; - } - } - - // copy handles into the buffer - offset = 0; // reuse variable - void* ptr = nullptr; - result = sbt->stagingBuffer->lpVtbl->Map(sbt->stagingBuffer, 0, nullptr, &ptr); - if (FAILED(result)) { - return PAL_RESULT_PLATFORM_FAILURE; - } - - // raygen - for (int i = 0; i < sbtInfo->raygenCount; i++) { - uint8_t* dstPtr = (uint8_t*)ptr + (i * raygenStride); - PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; - - memcpy(dstPtr, raygenHandles[i], groupHandleSize); - if (record->localDataSize) { - // this record has local data - memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); - } - } - offset += sbtInfo->raygenCount; - - // miss - for (int i = 0; i < sbtInfo->missCount; i++) { - uint8_t* dstPtr = (uint8_t*)ptr + missOffset + (i * missStride); - PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; - - memcpy(dstPtr, missHandles[i], groupHandleSize); - if (record->localDataSize) { - // this record has local data - memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); - } - } - offset += sbtInfo->missCount; - - // hit group - for (int i = 0; i < sbtInfo->hitCount; i++) { - uint8_t* dstPtr = (uint8_t*)ptr + hitOffset + (i * hitStride); - PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; - - memcpy(dstPtr, hitHandles[i], groupHandleSize); - if (record->localDataSize) { - // this record has local data - memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); - } - } - offset += sbtInfo->hitCount; - - // callable - for (int i = 0; i < sbtInfo->callableCount; i++) { - uint8_t* dstPtr = (uint8_t*)ptr + callableOffset + (i * callableStride); - PalShaderBindingTableRecordInfo* record = &info->records[offset + i]; - - memcpy(dstPtr, callableHandles[i], groupHandleSize); - if (record->localDataSize) { - // this record has local data - memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); - } - } - - sbt->stagingBuffer->lpVtbl->Unmap(sbt->stagingBuffer, 0, nullptr); - - // cache SBT fields and offsets address - sbt->baseAddress = sbt->buffer->lpVtbl->GetGPUVirtualAddress(sbt->buffer); - - // raygen - if (sbtInfo->raygenCount) { - sbt->raygen.region.StartAddress = sbt->baseAddress; - sbt->raygen.offset = 0; // always - sbt->raygen.startIndex = 0; // always - sbt->raygen.region.SizeInBytes = raygenRegionSize; - sbt->raygen.region.StrideInBytes = raygenStride; - - palFree(s_D3D.allocator, raygenHandles); - } - - // miss - if (sbtInfo->missCount) { - sbt->miss.offset = missOffset; - sbt->miss.startIndex = sbtInfo->raygenCount; - sbt->miss.region.StartAddress = sbt->baseAddress + missOffset; - sbt->miss.region.SizeInBytes = missRegionSize; - sbt->miss.region.StrideInBytes = missStride; - - palFree(s_D3D.allocator, missHandles); - } - - // hit - if (sbtInfo->hitCount) { - sbt->hit.offset = hitOffset; - sbt->hit.startIndex = sbtInfo->raygenCount + sbtInfo->missCount; - sbt->hit.region.StartAddress = sbt->baseAddress + hitOffset; - sbt->hit.region.SizeInBytes = hitRegionSize; - sbt->hit.region.StrideInBytes = hitStride; - - palFree(s_D3D.allocator, hitHandles); - } - - // callable - if (sbtInfo->callableCount) { - sbt->callable.offset = callableOffset; - sbt->callable.startIndex = sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount; - sbt->callable.region.StartAddress = sbt->baseAddress + callableOffset; - sbt->callable.region.SizeInBytes = callableRegionSize; - sbt->callable.region.StrideInBytes = callableStride; - - palFree(s_D3D.allocator, callableHandles); - } - - props->lpVtbl->Release(props); - sbt->handleSize = groupHandleSize; - sbt->stagingBufferSize = bufferSize; - sbt->pipeline = pipeline; - - sbt->isDirty = PAL_TRUE; // we need to copy from the staging to the gpu buffer - *outSbt = (PalShaderBindingTable*)sbt; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) -{ - ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; - d3dSbt->buffer->lpVtbl->Release(d3dSbt->buffer); - d3dSbt->stagingBuffer->lpVtbl->Release(d3dSbt->stagingBuffer); - palFree(s_D3D.allocator, d3dSbt); -} - -PalResult PAL_CALL updateShaderBindingTableD3D12( - PalShaderBindingTable* sbt, - uint32_t count, - PalShaderBindingTableRecordInfo* infos) -{ - HRESULT result; - ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; - Pipeline* pipeline = d3dSbt->pipeline; - ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; - - void* data = nullptr; - result = d3dSbt->stagingBuffer->lpVtbl->Map(d3dSbt->stagingBuffer, 0, nullptr, &data); - if (FAILED(result)) { - return PAL_RESULT_PLATFORM_FAILURE; - } - - uint64_t stride = 0; - uint64_t offset = 0; - uint32_t startIndex = 0; - - for (int i = 0; i < count; i++) { - PalShaderBindingTableRecordInfo* info = &infos[i]; - if (!info->localDataSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - // find the group the record belongs to - uint32_t index = info->groupIndex; - if (index < sbtInfo->raygenCount) { - // raygen group - offset = 0; - stride = d3dSbt->raygen.region.StrideInBytes; - startIndex = d3dSbt->raygen.startIndex; - - } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { - // miss group - offset = d3dSbt->miss.offset; - stride = d3dSbt->miss.region.StrideInBytes; - startIndex = d3dSbt->miss.startIndex; - } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { - // hit group - offset = d3dSbt->hit.offset; - stride = d3dSbt->hit.region.StrideInBytes; - startIndex = d3dSbt->hit.startIndex; - - } else { - // callable group - offset = d3dSbt->callable.offset; - stride = d3dSbt->callable.region.StrideInBytes; - startIndex = d3dSbt->callable.startIndex; - } - - // write payload - uint32_t localIndex = index - startIndex; - uint8_t* dst = (uint8_t*)data + offset + (localIndex * stride); - memcpy(dst + d3dSbt->handleSize, info->localData, info->localDataSize); - } - - d3dSbt->stagingBuffer->lpVtbl->Unmap(d3dSbt->stagingBuffer, 0, nullptr); - d3dSbt->isDirty = PAL_TRUE; - return PAL_RESULT_SUCCESS; -} #endif // PAL_HAS_D3D12_BACKEND From 6730ec0eddfd14dd447e280aa7ca6cf27c955213 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 7 Jul 2026 16:50:42 +0000 Subject: [PATCH 318/372] graphics rework: split d3d12 backend --- include/pal/pal_graphics.h | 11 +- src/graphics/d3d12/pal_adapter_d3d12.c | 41 +- src/graphics/d3d12/pal_as_d3d12.c | 8 +- src/graphics/d3d12/pal_buffer_d3d12.c | 295 + src/graphics/d3d12/pal_command_pool_d3d12.c | 328 ++ src/graphics/d3d12/pal_commands_d3d12.c | 1432 +++++ src/graphics/d3d12/pal_d3d12.h | 43 +- src/graphics/d3d12/pal_descriptors_d3d12.c | 679 +++ src/graphics/d3d12/pal_device_d3d12.c | 722 +++ src/graphics/d3d12/pal_image_d3d12.c | 305 ++ src/graphics/d3d12/pal_pipeline_d3d12.c | 1125 ++++ src/graphics/d3d12/pal_sbt_d3d12.c | 29 +- src/graphics/d3d12/pal_swapchain_d3d12.c | 477 ++ src/graphics/d3d12/pal_sync_d3d12.c | 46 +- src/graphics/pal_d3d12.c | 5406 +------------------ src/graphics/pal_graphics.c | 21 +- src/graphics/vulkan/pal_commands_vulkan.c | 83 +- src/graphics/vulkan/pal_device_vulkan.c | 2 +- src/graphics/vulkan/pal_pipeline_vulkan.c | 12 +- src/graphics/vulkan/pal_vulkan.h | 2 - 20 files changed, 5556 insertions(+), 5511 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 79255088..237431a7 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1745,8 +1745,6 @@ typedef struct { PalStoreOp stencilStoreOp; /**< (eg. `PAL_STORE_OP_DONT_CARE`).*/ PalResolveMode resolveMode; /**< Used if resolveImageView is set.*/ PalResolveMode stencilResolveMode; /**< Used if resolveImageView is set.*/ - uint32_t texelWidth; /**< Texel width for fragment shading rate attachment.*/ - uint32_t texelHeight; /**< Texel height for fragment shading rate attachment.*/ PalClearValue clearValue; /**< Clear value for color and depth/stencil attachments.*/ } PalAttachmentDesc; @@ -1832,9 +1830,14 @@ typedef struct { */ typedef struct { PalAttachmentDesc* colorAttachments; /**< Color attachments.*/ - PalAttachmentDesc* depthStencilAttachment; /**< Depth/Stencil attachment.*/ - PalAttachmentDesc* fragmentShadingRateAttachment; /**< Fragment shading rate attachment.*/ + PalAttachmentDesc* depthStencilAttachment; /**< Depth/Stencil attachment.*/ + PalImageView* fragmentShadingRateImageView; /**< Fragment shading rate image view.*/ + PalRect2D renderArea; /**< Rendering area of the attachments.*/ + PalRenderingFlags flags; /**< (eg. `PAL_RENDERING_FLAG_NONE`).*/ + uint32_t fragmentShadingRateTexelWidth; /**< Texel width for fragment shading rate.*/ + uint32_t fragmentShadingRateTexelHeight; /**< Texel height for fragment shading rate.*/ uint32_t viewCount; /**< View count. Set to 1 for default.*/ + uint32_t arrayLayerCount; /**< Number of array layers for rendering.*/ uint32_t colorAttachentCount; /**< Number of color attachments.*/ } PalRenderingInfo; diff --git a/src/graphics/d3d12/pal_adapter_d3d12.c b/src/graphics/d3d12/pal_adapter_d3d12.c index e77b4487..392b3f6c 100644 --- a/src/graphics/d3d12/pal_adapter_d3d12.c +++ b/src/graphics/d3d12/pal_adapter_d3d12.c @@ -8,6 +8,11 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" +// on older SDKs, D3D_FEATURE_LEVEL_12_2 is not defined +#ifndef D3D_FEATURE_LEVEL_12_2 +#define D3D_FEATURE_LEVEL_12_2 0xc200 +#endif // D3D_FEATURE_LEVEL_12_2 + // From Agility SDK #ifndef D3D_SHADER_MODEL_6_8 #define D3D_SHADER_MODEL_6_8 0x68 @@ -21,9 +26,6 @@ #define D3D_SHADER_MODEL_6_10 0x6a #endif // D3D_SHADER_MODEL_6_10 -const IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; -const IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0xd2,0x4e}; - PalResult PAL_CALL enumerateAdaptersD3D12( int32_t* count, PalAdapter** outAdapters) @@ -46,10 +48,13 @@ PalResult PAL_CALL enumerateAdaptersD3D12( palFree(s_D3D12.allocator, s_D3D12.adapters); } - while (SUCCEEDED(IDXGIFactory6_EnumAdapters(s_D3D12.factory, adapterCount, &adapter))) { + while (SUCCEEDED(s_D3D12.factory->lpVtbl->EnumAdapters( + s_D3D12.factory, + adapterCount, + &adapter))) { if (outAdapters) { IDXGIAdapter4* tmp = nullptr; - if (SUCCEEDED(IDXGIAdapter_QueryInterface(adapter, &IID_Adapter, (void**)&tmp))) { + if (SUCCEEDED(adapter->lpVtbl->QueryInterface(adapter, &IID_Adapter, (void**)&tmp))) { dxAdapters[adapterCount] = tmp; } @@ -114,7 +119,7 @@ PalResult PAL_CALL getAdapterInfoD3D12( return makeResultD3D12(result); } - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_SHADER_MODEL, &shaderModel, @@ -141,7 +146,7 @@ PalResult PAL_CALL getAdapterInfoD3D12( nullptr, nullptr); - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_ARCHITECTURE1, &arch, @@ -253,38 +258,38 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7 = {0}; D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3)); - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_D3D12_OPTIONS5, &options5, sizeof(options5)); - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_D3D12_OPTIONS6, &options6, sizeof(options6)); - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_D3D12_OPTIONS7, &options7, sizeof(options7)); shaderModel.HighestShaderModel = D3D_SHADER_MODEL_5_1; - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_SHADER_MODEL, &shaderModel, @@ -401,7 +406,7 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( D3D_SHADER_MODEL highestModel = D3D_SHADER_MODEL_5_1; for (int i = 0; i < 11; i++) { shaderModel.HighestShaderModel = models[i]; - result = ID3D12Device_CheckFeatureSupport( + result = d3d12Adapter->tmpDevice->lpVtbl->CheckFeatureSupport( d3d12Adapter->tmpDevice, D3D12_FEATURE_SHADER_MODEL, &shaderModel, @@ -469,7 +474,7 @@ PalResult PAL_CALL enumerateFormatsD3D12( } support.Format = fmt; - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_FORMAT_SUPPORT, &support, @@ -514,7 +519,7 @@ PalBool PAL_CALL isFormatSupportedD3D12( } support.Format = fmt; - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_FORMAT_SUPPORT, &support, @@ -542,7 +547,7 @@ PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( } support.Format = fmt; - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_FORMAT_SUPPORT, &support, @@ -581,7 +586,7 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( } support.Format = fmt; - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_FORMAT_SUPPORT, &support, diff --git a/src/graphics/d3d12/pal_as_d3d12.c b/src/graphics/d3d12/pal_as_d3d12.c index 8dae7b1d..562216cd 100644 --- a/src/graphics/d3d12/pal_as_d3d12.c +++ b/src/graphics/d3d12/pal_as_d3d12.c @@ -16,7 +16,7 @@ PalResult PAL_CALL createAccelerationstructureD3D12( HRESULT result; AccelerationStructureD3D12* as = nullptr; DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - BufferD3D12* d3dBuffer = (BufferD3D12*)info->buffer; + BufferD3D12* d3d12Buffer = (BufferD3D12*)info->buffer; if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; @@ -28,7 +28,7 @@ PalResult PAL_CALL createAccelerationstructureD3D12( } as->type = info->type; - as->handle = d3dBuffer->handle; + as->handle = d3d12Buffer->handle; as->address = as->handle->lpVtbl->GetGPUVirtualAddress(as->handle); as->address += info->offset; @@ -70,7 +70,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count); fillBuildInfoD3D12(PAL_TRUE, info, geometries, &buildInfo); - ID3D12Device5_GetRaytracingAccelerationStructurePrebuildInfo( + d3d12Device->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( d3d12Device->handle, &buildInfo.Inputs, &sizeInfo); @@ -80,7 +80,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( } else { fillBuildInfoD3D12(PAL_TRUE, info, nullptr, &buildInfo); - ID3D12Device5_GetRaytracingAccelerationStructurePrebuildInfo( + d3d12Device->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( d3d12Device->handle, &buildInfo.Inputs, &sizeInfo); diff --git a/src/graphics/d3d12/pal_buffer_d3d12.c b/src/graphics/d3d12/pal_buffer_d3d12.c index 31b70783..e6275ac2 100644 --- a/src/graphics/d3d12/pal_buffer_d3d12.c +++ b/src/graphics/d3d12/pal_buffer_d3d12.c @@ -6,6 +6,301 @@ */ #if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" +#define align(v, a) (v + a - 1) & ~(a - 1) + +PalResult PAL_CALL createBufferD3D12( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer) +{ + HRESULT result; + BufferD3D12* buffer = nullptr; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + + if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + buffer = palAllocate(s_D3D12.allocator, sizeof(BufferD3D12), 0); + if (!buffer) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(buffer, 0, sizeof(BufferD3D12)); + buffer->desc.Width = info->size; + buffer->desc.Height = 1; + buffer->desc.DepthOrArraySize = 1; + buffer->desc.MipLevels = 1; + buffer->desc.SampleDesc.Count = 1; + buffer->desc.SampleDesc.Quality = 0; + buffer->desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + buffer->desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + + if (info->usages & PAL_BUFFER_USAGE_STORAGE) { + buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + } + + if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { + buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + } + + if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { + buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + } + + buffer->isMemoryManaged = PAL_FALSE; + if (info->memoryUsage != PAL_BUFFER_MEMORY_USAGE_MANUAL) { + + D3D12_HEAP_PROPERTIES heapProps = {0}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON; + + if (info->memoryUsage != PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD) { + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + state = D3D12_RESOURCE_STATE_GENERIC_READ; + + } else if (info->memoryUsage != PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK) { + heapProps.Type = D3D12_HEAP_TYPE_READBACK; + state = D3D12_RESOURCE_STATE_COPY_DEST; + } + + result = d3d12Device->handle->lpVtbl->CreateCommittedResource( + d3d12Device->handle, + &heapProps, + 0, + &buffer->desc, + state, + nullptr, + &IID_Resource, + (void**)&buffer->handle); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + buffer->isMemoryManaged = PAL_TRUE; + } + + buffer->usages = info->usages; + buffer->device = d3d12Device; + buffer->size = info->size; + buffer->reserved = PAL_BACKEND_KEY; + *outBuffer = (PalBuffer*)buffer; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyBufferD3D12(PalBuffer* buffer) +{ + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + if (d3d12Buffer->isMemoryManaged) { + d3d12Buffer->handle->lpVtbl->Release(d3d12Buffer->handle); + } + palFree(s_D3D12.allocator, d3d12Buffer); +} + +PalResult PAL_CALL getBufferMemoryRequirementsD3D12( + PalBuffer* buffer, + PalMemoryRequirements* requirements) +{ + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + ID3D12Device5* device = d3d12Buffer->device->handle; + + D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; + D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; + allocationInfo = *device->lpVtbl->GetResourceAllocationInfo( + device, + &__ret, + 0, + 1, + &d3d12Buffer->desc); + + // d3d12 allows buffers to be used with all memory heap types + requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); + requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_CPU_UPLOAD); + requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_CPU_READBACK); + + requirements->alignment = allocationInfo.Alignment; + requirements->size = allocationInfo.SizeInBytes; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( + PalDevice* device, + uint32_t instanceCount, + uint64_t* outSize) +{ + *outSize = sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * instanceCount; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( + PalDevice* device, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo, + uint32_t* outBufferRowLength, + uint32_t* outBufferImageHeight, + uint64_t* outSize) +{ + uint32_t imageFormatSize = getFormatSizeD3D12(imageFormat); + uint32_t rowPitch = align((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + uint32_t bufferImageHeight = 0; + + if (copyInfo->bufferImageHeight) { + bufferImageHeight = copyInfo->bufferImageHeight; + } else { + bufferImageHeight = copyInfo->imageHeight; + } + + *outBufferRowLength = rowPitch; + *outBufferImageHeight = bufferImageHeight; + *outSize = (uint64_t)rowPitch * bufferImageHeight * copyInfo->imageDepth; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL writeToInstanceBufferD3D12( + PalDevice* device, + void* ptr, + PalAccelerationStructureInstance* instances, + uint32_t instanceCount) +{ + D3D12_RAYTRACING_INSTANCE_DESC* data = ptr; + for (int i = 0; i < instanceCount; i++) { + PalAccelerationStructureInstance* src = &instances[i]; + D3D12_RAYTRACING_INSTANCE_DESC* dst = &data[i]; + AccelerationStructureD3D12* as = (AccelerationStructureD3D12*)src->blas; + + dst->InstanceMask = src->mask; + dst->InstanceID = src->instanceId; + dst->AccelerationStructure = as->address; + dst->InstanceContributionToHitGroupIndex = src->hitGroupOffset; + dst->Flags = instanceFlagsToD3D12(src->flags); + memcpy(dst->Transform, src->transform, sizeof(float) * 12); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( + PalDevice* device, + void* ptr, + void* srcData, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo) +{ + uint32_t imageFormatSize = getFormatSizeD3D12(imageFormat); + uint32_t srcRowPitch = copyInfo->imageWidth * imageFormatSize; + const uint32_t dstSlicePitch = copyInfo->bufferRowLength * copyInfo->bufferImageHeight; + const uint32_t srcSlicePitch = srcRowPitch * copyInfo->imageHeight; + + // manually offset the buffer with the provided offset + uint8_t* dst = (uint8_t*)ptr + copyInfo->bufferOffset; + const uint8_t* src = (const uint8_t*)srcData; + + // write to destination pointer + for (uint32_t z = 0; z < copyInfo->imageDepth; z++) { + for (uint32_t y = 0; y < copyInfo->imageHeight; y++) { + memcpy( + dst + z * dstSlicePitch + y * copyInfo->bufferRowLength, + src + z * srcSlicePitch + y * srcRowPitch, + srcRowPitch); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL bindBufferMemoryD3D12( + PalBuffer* buffer, + PalMemory* memory, + uint64_t offset) +{ + HRESULT result; + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + ID3D12Device5* device = d3d12Buffer->device->handle; + MemoryD3D12* d3d12Memory = (MemoryD3D12*)memory; + + if (d3d12Buffer->isMemoryManaged) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + D3D12_RESOURCE_STATES state = 0; + d3d12Buffer->canStateChange = PAL_TRUE; + if (d3d12Memory->type == PAL_MEMORY_TYPE_CPU_UPLOAD) { + state = D3D12_RESOURCE_STATE_GENERIC_READ; + d3d12Buffer->canStateChange = PAL_FALSE; + + } else if (d3d12Memory->type == PAL_MEMORY_TYPE_CPU_UPLOAD) { + state = D3D12_RESOURCE_STATE_COPY_DEST; + d3d12Buffer->canStateChange = PAL_FALSE; + } + + if (d3d12Buffer->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { + state = D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; + d3d12Buffer->canStateChange = PAL_FALSE; + } + + if (d3d12Buffer->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { + state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + } + + result = device->lpVtbl->CreatePlacedResource( + device, + d3d12Memory->handle, + offset, + &d3d12Buffer->desc, + state, + nullptr, + &IID_Resource, + (void**)&d3d12Buffer->handle); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Buffer->device); + return makeResultD3D12(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL mapBufferD3D12( + PalBuffer* buffer, + uint64_t offset, + uint64_t size, + void** outPtr) +{ + + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + void* ptr = nullptr; + HRESULT result = d3d12Buffer->handle->lpVtbl->Map(d3d12Buffer->handle, 0, nullptr, &ptr); + if (FAILED(result)) { + pollMessagesD3D12(d3d12Buffer->device); + return makeResultD3D12(result); + } + + *outPtr = (uint8_t*)ptr + offset; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL unmapBufferD3D12(PalBuffer* buffer) +{ + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + d3d12Buffer->handle->lpVtbl->Unmap(d3d12Buffer->handle, 0, nullptr); +} + +PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer) +{ + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + if (d3d12Buffer->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + return d3d12Buffer->handle->lpVtbl->GetGPUVirtualAddress(d3d12Buffer->handle); + } + return 0; +} #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_command_pool_d3d12.c b/src/graphics/d3d12/pal_command_pool_d3d12.c index 31b70783..fa699883 100644 --- a/src/graphics/d3d12/pal_command_pool_d3d12.c +++ b/src/graphics/d3d12/pal_command_pool_d3d12.c @@ -6,6 +6,334 @@ */ #if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" +PalResult PAL_CALL createCommandPoolD3D12( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool) +{ + HRESULT result; + CommandPoolD3D12* pool = nullptr; + QueueD3D12* d3d12Queue = (QueueD3D12*)queue; + + pool = palAllocate(s_D3D12.allocator, sizeof(CommandPoolD3D12), 0); + if (!pool) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + pool->size = 8; // initial size + pool->cmdBuffersData = nullptr; + pool->cmdBuffersData = palAllocate( + s_D3D12.allocator, + sizeof(CommandBufferData) * pool->size, + 0); + + if (!pool->cmdBuffersData) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + switch (d3d12Queue->type) { + case PAL_QUEUE_TYPE_COMPUTE: { + pool->type = D3D12_COMMAND_LIST_TYPE_COMPUTE; + break; + } + + case PAL_QUEUE_TYPE_GRAPHICS: { + pool->type = D3D12_COMMAND_LIST_TYPE_DIRECT; + break; + } + + case PAL_QUEUE_TYPE_COPY: { + pool->type = D3D12_COMMAND_LIST_TYPE_COPY; + break; + } + } + + pool->reserved = PAL_BACKEND_KEY; + *outPool = (PalCommandPool*)pool; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) +{ + CommandPoolD3D12* cmdPool = (CommandPoolD3D12*)pool; + for (int i = 0; i < cmdPool->size; i++) { + if (!cmdPool->cmdBuffersData[i].used) { + continue; + } + + CommandBufferD3D12* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; + cmdBuffer->handle->lpVtbl->Release(cmdBuffer->handle); + cmdBuffer->allocator->lpVtbl->Release(cmdBuffer->allocator); + } + + palFree(s_D3D12.allocator, cmdPool->cmdBuffersData); + palFree(s_D3D12.allocator, cmdPool); +} + +PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool) +{ + CommandPoolD3D12* cmdPool = (CommandPoolD3D12*)pool; + for (int i = 0; i < cmdPool->size; i++) { + if (!cmdPool->cmdBuffersData[i].used) { + continue; + } + + HRESULT ret; + CommandBufferD3D12* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; + ret = cmdBuffer->handle->lpVtbl->Reset(cmdBuffer->handle, cmdBuffer->allocator, nullptr); + if (FAILED(ret)) { + return makeResultD3D12(ret); + } + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL allocateCommandBufferD3D12( + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outCmdBuffer) +{ + HRESULT result; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + CommandBufferD3D12* cmdBuffer = nullptr; + CommandPoolD3D12* cmdPool = (CommandPoolD3D12*)pool; + + cmdBuffer = palAllocate(s_D3D12.allocator, sizeof(CommandBufferD3D12), 0); + if (!cmdBuffer) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(cmdBuffer, 0, sizeof(CommandBufferD3D12)); + cmdBuffer->primary = PAL_TRUE; + + D3D12_COMMAND_LIST_TYPE cmdBufferType = cmdPool->type; + if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { + cmdBufferType = D3D12_COMMAND_LIST_TYPE_BUNDLE; + cmdBuffer->primary = PAL_FALSE; + } + + // create an allocator + result = d3d12Device->handle->lpVtbl->CreateCommandAllocator( + d3d12Device->handle, + cmdBufferType, + &IID_CommandAllocator, + (void**)&cmdBuffer->allocator); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + return makeResultD3D12(result); + } + + // create the command list + ID3D12GraphicsCommandList* cmdList = nullptr; + result = d3d12Device->handle->lpVtbl->CreateCommandList( + d3d12Device->handle, + 0, + cmdBufferType, + cmdBuffer->allocator, + nullptr, + &IID_CommandList, + (void**)&cmdList); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + return makeResultD3D12(result); + } + + // we need a tmp staging and gpu buffer if ray tracing is enabled + if (d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + D3D12_HEAP_PROPERTIES heapProps = {0}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.VisibleNodeMask = 1; + heapProps.CreationNodeMask = 1; + + D3D12_RESOURCE_DESC bufferDesc = {0}; + bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + bufferDesc.Width = sizeof(D3D12_DISPATCH_RAYS_DESC); + bufferDesc.Height = 1; + bufferDesc.DepthOrArraySize = 1; + bufferDesc.MipLevels = 1; + bufferDesc.SampleDesc.Count = 1; + bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + + result = d3d12Device->handle->lpVtbl->CreateCommittedResource( + d3d12Device->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + &IID_Resource, + (void**)&cmdBuffer->buffer); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + // create staging buffer + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + result = d3d12Device->handle->lpVtbl->CreateCommittedResource( + d3d12Device->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + &IID_Resource, + (void**)&cmdBuffer->stagingBuffer); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + } + + result = cmdList->lpVtbl->QueryInterface( + cmdList, + &IID_CommandList6, + (void**)&cmdBuffer->handle); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + cmdList->lpVtbl->Release(cmdList); + cmdBuffer->handle->lpVtbl->Close(cmdBuffer->handle); + + cmdBuffer->pool = cmdPool; + cmdBuffer->device = d3d12Device; + cmdBuffer->reserved = PAL_BACKEND_KEY; + *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + CommandPoolD3D12* pool = d3d12CmdBuffer->pool; + CommandBufferData* data = findCmdBufferData(pool, d3d12CmdBuffer); + if (data) { + d3d12CmdBuffer->handle->lpVtbl->Release(d3d12CmdBuffer->handle); + d3d12CmdBuffer->allocator->lpVtbl->Release(d3d12CmdBuffer->allocator); + + if (d3d12CmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + d3d12CmdBuffer->buffer->lpVtbl->Release(d3d12CmdBuffer->buffer); + d3d12CmdBuffer->stagingBuffer->lpVtbl->Release(d3d12CmdBuffer->stagingBuffer); + } + + palFree(s_D3D12.allocator, cmdBuffer); + data->cmdBuffer = nullptr; + data->used = PAL_FALSE; + } +} + +PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) +{ + HRESULT result; + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + result = d3d12CmdBuffer->allocator->lpVtbl->Reset(d3d12CmdBuffer->allocator); + if (FAILED(result)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(result); + } + + result = d3d12CmdBuffer->handle->lpVtbl->Reset( + d3d12CmdBuffer->handle, + d3d12CmdBuffer->allocator, + nullptr); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(result); + } + + result = d3d12CmdBuffer->handle->lpVtbl->Close(d3d12CmdBuffer->handle); + if (FAILED(result)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(result); + } + + d3d12CmdBuffer->pipeline = nullptr; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL submitCommandBufferD3D12( + PalQueue* queue, + PalCommandBufferSubmitInfo* info) +{ + HRESULT ret; + QueueD3D12* d3d12Queue = (QueueD3D12*)queue; + ID3D12CommandQueue* queueHandle = d3d12Queue->handle; + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)info->cmdBuffer; + + // wait semaphore + if (info->waitSemaphore) { + SemaphoreD3D12* semaphore = (SemaphoreD3D12*)info->waitSemaphore; + if (semaphore->isTimeline) { + ret = queueHandle->lpVtbl->Wait(queueHandle, semaphore->handle, info->waitValue); + if (FAILED(ret)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(ret); + } + + } else { + queueHandle->lpVtbl->Wait(queueHandle, semaphore->handle, semaphore->value); + if (FAILED(ret)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(ret); + } + + semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); + if (FAILED(ret)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(ret); + } + + semaphore->value = 0; + } + } + + ID3D12CommandList* cmdLists[1] = { (ID3D12CommandList*)d3d12CmdBuffer->handle }; + queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, cmdLists); + + d3d12Queue->fenceValue++; + ret = queueHandle->lpVtbl->Signal(queueHandle, d3d12Queue->fence, d3d12Queue->fenceValue); + if (FAILED(ret)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(ret); + } + + if (info->fence) { + FenceD3D12* fence = (FenceD3D12*)info->fence; + fence->value++; + ret = queueHandle->lpVtbl->Signal(queueHandle, fence->handle, fence->value); + if (FAILED(ret)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(ret); + } + } + + if (info->signalSemaphore) { + SemaphoreD3D12* semaphore = (SemaphoreD3D12*)info->signalSemaphore; + if (semaphore->isTimeline) { + ret = queueHandle->lpVtbl->Signal(queueHandle, semaphore->handle, info->signalValue); + if (FAILED(ret)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(ret); + } + } else { + semaphore->value = 1; + ret = queueHandle->lpVtbl->Signal(queueHandle, semaphore->handle, semaphore->value); + if (FAILED(ret)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(ret); + } + } + } + + return PAL_RESULT_SUCCESS; +} #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index 31b70783..ddc4949a 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -6,6 +6,1438 @@ */ #if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" +#define align(v, a) (v + a - 1) & ~(a - 1) +#define GRAPHICS_PIPELINE 1220 +#define COMPUTE_PIPELINE 1221 +#define RAY_TRACING_PIPELINE 1222 + +static D3D12_RENDER_PASS_FLAGS renderingFlagToD3D12(PalRenderingFlags flags) +{ + D3D12_RENDER_PASS_FLAGS renderingFlags = 0; + if (flags == PAL_RENDERING_FLAG_NONE) { + renderingFlags = D3D12_RENDER_PASS_FLAG_NONE; + } + + if (flags & PAL_RENDERING_FLAG_RESUMING) { + renderingFlags |= D3D12_RENDER_PASS_FLAG_RESUMING_PASS; + } + + if (flags & PAL_RENDERING_FLAG_SUSPENDING) { + renderingFlags |= D3D12_RENDER_PASS_FLAG_SUSPENDING_PASS; + } + + return renderingFlags; +} + +PalResult PAL_CALL cmdBeginD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info) +{ + HRESULT result; + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + result = d3d12CmdBuffer->allocator->lpVtbl->Reset(d3d12CmdBuffer->allocator); + if (FAILED(result)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(result); + } + + result = d3d12CmdBuffer->handle->lpVtbl->Reset( + d3d12CmdBuffer->handle, + d3d12CmdBuffer->allocator, + nullptr); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + HRESULT result = d3d12CmdBuffer->handle->lpVtbl->Close(d3d12CmdBuffer->handle); + if (FAILED(result)) { + pollMessagesD3D12(d3d12CmdBuffer->device); + return makeResultD3D12(result); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdExecuteCommandBufferD3D12( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer) +{ + CommandBufferD3D12* d3dPrimaryCmdBuffer = (CommandBufferD3D12*)primaryCmdBuffer; + CommandBufferD3D12* d3dSecondaryCmdBuffer = (CommandBufferD3D12*)secondaryCmdBuffer; + + d3dPrimaryCmdBuffer->handle->lpVtbl->ExecuteBundle( + d3dPrimaryCmdBuffer->handle, + (ID3D12GraphicsCommandList*)d3dSecondaryCmdBuffer->handle); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state) +{ + HRESULT result; + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + D3D12_SHADING_RATE shadingRate = shadingRateToD3D12(state->rate); + D3D12_SHADING_RATE_COMBINER combinerOps[2]; + for (int i = 0; i < 2; i++) { + combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); + } + + d3d12CmdBuffer->handle->lpVtbl->RSSetShadingRate( + d3d12CmdBuffer->handle, + shadingRate, + combinerOps); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawMeshTasksD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + d3d12CmdBuffer->handle->lpVtbl->DispatchMesh( + d3d12CmdBuffer->handle, + groupCountX, + groupCountY, + groupCountZ); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t drawCount) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3d12CmdBuffer->handle, + device->meshSignature, + drawCount, + d3d12Buffer->handle, + 0, + nullptr, + 0); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + BufferD3D12* d3d12CountBuffer = (BufferD3D12*)countBuffer; + if (!(d3d12CountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3d12CmdBuffer->handle, + device->meshSignature, + maxDrawCount, + d3d12Buffer->handle, + 0, + d3d12CountBuffer->handle, + 0); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; + geometries = palAllocate( + s_D3D12.allocator, + sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count, + 0); + + if (!geometries) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count); + fillBuildInfoD3D12(PAL_FALSE, info, geometries, &buildInfo); + + d3d12CmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( + d3d12CmdBuffer->handle, + &buildInfo, + 0, + nullptr); + + palFree(s_D3D12.allocator, geometries); + + } else { + fillBuildInfoD3D12(PAL_FALSE, info, nullptr, &buildInfo); + + d3d12CmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( + d3d12CmdBuffer->handle, + &buildInfo, + 0, + nullptr); + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBeginRenderingD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + D3D12_RENDER_PASS_RENDER_TARGET_DESC colorAttachments[MAX_ATTACHMENTS]; + D3D12_RENDER_PASS_DEPTH_STENCIL_DESC depthStencilAttachment = {0}; + D3D12_CPU_DESCRIPTOR_HANDLE colorCpuHandle[MAX_ATTACHMENTS]; + D3D12_CPU_DESCRIPTOR_HANDLE depthStencilCpuHandle; + + PalAttachmentDesc* desc = nullptr; + ImageViewD3D12* imageView = nullptr; + ImageViewD3D12* resolveImageView = nullptr; + memset(colorAttachments, 0, sizeof(D3D12_RENDER_PASS_RENDER_TARGET_DESC) * MAX_ATTACHMENTS); + + for (int i = 0; i < info->colorAttachentCount; i++) { + D3D12_RENDER_PASS_RENDER_TARGET_DESC* attachment = &colorAttachments[i]; + desc = &info->colorAttachments[i]; + imageView = (ImageViewD3D12*)desc->imageView; + resolveImageView = (ImageViewD3D12*)desc->resolveImageView; + + RTVHeapAllocator* allocator = &imageView->device->rtvAllocator; + uint32_t size = allocator->incrementSize; + uint64_t base = allocator->baseOffset; + colorCpuHandle[i].ptr = getDescriptorHandleD3D12(imageView->heapIndex, size, base); + + attachment->BeginningAccess.Clear.ClearValue.Color[0] = desc->clearValue.color[0]; + attachment->BeginningAccess.Clear.ClearValue.Color[1] = desc->clearValue.color[1]; + attachment->BeginningAccess.Clear.ClearValue.Color[2] = desc->clearValue.color[2]; + attachment->BeginningAccess.Clear.ClearValue.Color[3] = desc->clearValue.color[3]; + + // load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + attachment->BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR; + + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + attachment->BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE; + + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + attachment->BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD; + } + + // store op + if (desc->storeOp == PAL_STORE_OP_STORE) { + attachment->EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE; + + } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { + attachment->EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD; + } + + attachment->cpuDescriptor = colorCpuHandle[i]; + if (resolveImageView) { + attachment->EndingAccess.Resolve.pDstResource = resolveImageView->image->handle; + attachment->EndingAccess.Resolve.Format = formatToD3D12(resolveImageView->format); + attachment->EndingAccess.Resolve.ResolveMode = resolveModeToVk(desc->resolveMode); + attachment->EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE; + } + } + + // depth attachment + if (info->depthStencilAttachment) { + desc = &info->depthStencilAttachment; + imageView = (ImageViewD3D12*)desc->imageView; + resolveImageView = (ImageViewD3D12*)desc->resolveImageView; + + DSVHeapAllocator* allocator = &imageView->device->rtvAllocator; + uint32_t size = allocator->incrementSize; + uint64_t base = allocator->baseOffset; + depthStencilCpuHandle.ptr = getDescriptorHandleD3D12(imageView->heapIndex, size, base); + + D3D12_RENDER_PASS_BEGINNING_ACCESS* depthBegin = nullptr; + D3D12_RENDER_PASS_BEGINNING_ACCESS* stencilBegin = nullptr; + D3D12_RENDER_PASS_ENDING_ACCESS* depthEnd = nullptr; + D3D12_RENDER_PASS_ENDING_ACCESS* stencilEnd = nullptr; + + depthBegin = &depthStencilAttachment.DepthBeginningAccess; + stencilBegin = &depthStencilAttachment.StencilBeginningAccess; + depthEnd = &depthStencilAttachment.DepthEndingAccess; + stencilEnd = &depthStencilAttachment.StencilEndingAccess; + + depthBegin->Clear.ClearValue.DepthStencil.Depth = desc->clearValue.depth; + depthBegin->Clear.ClearValue.DepthStencil.Stencil = desc->clearValue.stencil; + stencilBegin->Clear.ClearValue.DepthStencil.Depth = desc->clearValue.depth; + stencilBegin->Clear.ClearValue.DepthStencil.Stencil = desc->clearValue.stencil; + + // load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + depthBegin->Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR; + + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + depthBegin->Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE; + + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + depthBegin->Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD; + } + + // store op + if (desc->storeOp == PAL_STORE_OP_STORE) { + depthEnd->Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE; + + } else if (desc->storeOp == PAL_STORE_OP_DONT_CARE) { + depthEnd->Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD; + } + + // stencil load op + if (desc->loadOp == PAL_LOAD_OP_CLEAR) { + stencilBegin->Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR; + + } else if (desc->loadOp == PAL_LOAD_OP_LOAD) { + stencilBegin->Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE; + + } else if (desc->loadOp == PAL_LOAD_OP_DONT_CARE) { + stencilBegin->Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD; + } + + // stencil store op + if (desc->stencilStoreOp == PAL_STORE_OP_STORE) { + stencilEnd->Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE; + + } else if (desc->stencilStoreOp == PAL_STORE_OP_DONT_CARE) { + stencilEnd->Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD; + } + + depthStencilAttachment.cpuDescriptor = depthStencilCpuHandle; + if (resolveImageView) { + depthEnd->Resolve.pDstResource = resolveImageView->image->handle; + depthEnd->Resolve.Format = formatToD3D12(resolveImageView->format); + depthEnd->Resolve.ResolveMode = resolveModeToVk(desc->resolveMode); + depthEnd->Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE; + + stencilEnd->Resolve.pDstResource = depthEnd->Resolve.pDstResource; + stencilEnd->Resolve.Format = depthEnd->Resolve.Format; + stencilEnd->Resolve.ResolveMode = depthEnd->Resolve.ResolveMode; + stencilEnd->Type = depthEnd->Type; + } + } + + D3D12_CPU_DESCRIPTOR_HANDLE* tmpCpuHandle = nullptr; + D3D12_RENDER_PASS_DEPTH_STENCIL_DESC* tmpDesc = nullptr; + if (info->depthStencilAttachment) { + tmpCpuHandle = &depthStencilCpuHandle; + tmpDesc = &depthStencilAttachment; + } + + d3d12CmdBuffer->handle->lpVtbl->OMSetRenderTargets( + d3d12CmdBuffer->handle, + info->colorAttachentCount, + colorAttachments, + PAL_FALSE, + tmpCpuHandle); + + D3D12_RENDER_PASS_FLAGS flags = renderingFlagToD3D12(info->flags); + d3d12CmdBuffer->handle->lpVtbl->BeginRenderPass( + d3d12CmdBuffer->handle, + info->colorAttachentCount, + colorAttachments, + tmpDesc, + flags); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + d3d12CmdBuffer->handle->lpVtbl->EndRenderPass(d3d12CmdBuffer->handle); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdCopyBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + BufferD3D12* dstbuffer = (BufferD3D12*)dst; + BufferD3D12* srcBuffer = (BufferD3D12*)src; + + d3d12CmdBuffer->handle->lpVtbl->CopyBufferRegion( + d3d12CmdBuffer->handle, + dstbuffer->handle, + copyInfo->dstOffset, + srcBuffer->handle, + copyInfo->srcOffset, + copyInfo->size); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdCopyBufferToImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + ImageD3D12* dst = (ImageD3D12*)dstImage; + BufferD3D12* src = (BufferD3D12*)srcBuffer; + + D3D12_TEXTURE_COPY_LOCATION dstLocation = {0}; + dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstLocation.pResource = dst->handle; + + D3D12_TEXTURE_COPY_LOCATION srcLocation = {0}; + srcLocation.pResource = src->handle; + srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT* footPrint = &srcLocation.PlacedFootprint; + + footPrint->Offset = copyInfo->bufferOffset; + footPrint->Footprint.Width = copyInfo->imageWidth; + footPrint->Footprint.Height = copyInfo->imageHeight; + footPrint->Footprint.Depth = copyInfo->imageDepth; + footPrint->Footprint.Format = formatToD3D12(dst->info.format); + + uint32_t imageFormatSize = getFormatSizeD3D12(dst->info.format); + uint64_t rowPitch = align((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + footPrint->Footprint.RowPitch = (UINT)rowPitch; + + uint32_t planeCount = 1; + if (copyInfo->imageAspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { + planeCount = 2; + } + + D3D12_BOX box = {0}; + box.right = copyInfo->imageWidth; + box.bottom = copyInfo->imageHeight; + box.back = copyInfo->imageDepth; + + uint32_t level = copyInfo->ImageMipLevel; + uint32_t startLayer = copyInfo->ImageStartArrayLayer; + uint32_t layerCount = copyInfo->ImageArrayLayerCount; + uint32_t maxLayers = dst->info.arrayLayerCount; + uint32_t maxLevels = dst->info.mipLevelCount; + + for (uint32_t plane = 0; plane < planeCount; plane++) { + for (uint32_t layer = startLayer; layer < startLayer + layerCount; layer++) { + uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); + + dstLocation.SubresourceIndex = index; + d3d12CmdBuffer->handle->lpVtbl->CopyTextureRegion( + d3d12CmdBuffer->handle, + &dstLocation, + copyInfo->imageOffsetX, + copyInfo->imageOffsetY, + copyInfo->imageOffsetZ, + &srcLocation, + &box); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdCopyImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + ImageD3D12* dstImage = (ImageD3D12*)dst; + ImageD3D12* srcImage = (ImageD3D12*)src; + + D3D12_TEXTURE_COPY_LOCATION dstLocation = {0}; + dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstLocation.pResource = dstImage->handle; + + D3D12_TEXTURE_COPY_LOCATION srcLocation = {0}; + srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + srcLocation.pResource = srcImage->handle; + + D3D12_BOX box = {0}; + box.left = copyInfo->srcOffsetX; + box.top = copyInfo->srcOffsetY; + box.front = copyInfo->srcOffsetZ; + box.right = copyInfo->srcOffsetX + copyInfo->width; + box.bottom = copyInfo->srcOffsetY + copyInfo->height; + box.back = copyInfo->srcOffsetZ + copyInfo->depth; + + uint32_t planeCount = 1; + uint32_t layerCount = copyInfo->arrayLayerCount; + if (copyInfo->aspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { + planeCount = 2; + } + + uint32_t dstLevel = copyInfo->dstMipLevel; + uint32_t dstStartLayer = copyInfo->dstStartArrayLayer; + uint32_t dstMaxLayers = dstImage->info.arrayLayerCount; + uint32_t dstMaxLevels = dstImage->info.mipLevelCount; + + uint32_t srcLevel = copyInfo->srcMipLevel; + uint32_t srcStartLayer = copyInfo->srcStartArrayLayer; + uint32_t srcMaxLayers = srcImage->info.arrayLayerCount; + uint32_t srcMaxLevels = srcImage->info.mipLevelCount; + + for (uint32_t plane = 0; plane < planeCount; plane++) { + for (uint32_t layer = 0; layer + layerCount; layer++) { + // clang-format off + uint32_t dstIndex = dstLevel + (dstStartLayer + layer * dstMaxLevels) + (plane * dstMaxLevels * dstMaxLayers); + uint32_t srcIndex = srcLevel + (srcStartLayer + layer * srcMaxLevels) + (plane * srcMaxLevels * srcMaxLayers); + // clang-format on + + dstLocation.SubresourceIndex = dstIndex; + srcLocation.SubresourceIndex = srcIndex; + + d3d12CmdBuffer->handle->lpVtbl->CopyTextureRegion( + d3d12CmdBuffer->handle, + &dstLocation, + copyInfo->dstOffsetX, + copyInfo->dstOffsetY, + copyInfo->dstOffsetZ, + &srcLocation, + &box); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdCopyImageToBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + BufferD3D12* dst = (BufferD3D12*)dstBuffer; + ImageD3D12* src = (ImageD3D12*)srcImage; + + D3D12_TEXTURE_COPY_LOCATION dstLocation = {0}; + dstLocation.pResource = dst->handle; + dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + D3D12_PLACED_SUBRESOURCE_FOOTPRINT* footPrint = &dstLocation.PlacedFootprint; + footPrint->Offset = copyInfo->bufferOffset; + footPrint->Footprint.Width = copyInfo->imageWidth; + footPrint->Footprint.Height = copyInfo->imageHeight; + footPrint->Footprint.Depth = copyInfo->imageDepth; + footPrint->Footprint.Format = formatToD3D12(src->info.format); + + D3D12_TEXTURE_COPY_LOCATION srcLocation = {0}; + srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + srcLocation.pResource = src->handle; + + uint32_t imageFormatSize = getFormatSizeD3D12(src->info.format); + uint64_t rowPitch = align((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + footPrint->Footprint.RowPitch = (UINT)rowPitch; + + D3D12_BOX box = {0}; + box.left = copyInfo->imageOffsetX; + box.top = copyInfo->imageOffsetY; + box.front = copyInfo->imageOffsetZ; + box.right = copyInfo->imageOffsetX + copyInfo->imageWidth; + box.bottom = copyInfo->imageOffsetY + copyInfo->imageHeight; + box.back = copyInfo->imageOffsetX + copyInfo->imageDepth; + + uint32_t planeCount = 1; + if (copyInfo->imageAspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { + planeCount = 2; + } + + uint32_t level = copyInfo->ImageMipLevel; + uint32_t startLayer = copyInfo->ImageStartArrayLayer; + uint32_t layerCount = copyInfo->ImageArrayLayerCount; + uint32_t maxLayers = src->info.arrayLayerCount; + uint32_t maxLevels = src->info.mipLevelCount; + + for (uint32_t plane = 0; plane < planeCount; plane++) { + for (uint32_t layer = startLayer; layer < startLayer + layerCount; layer++) { + uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); + + srcLocation.SubresourceIndex = index; + d3d12CmdBuffer->handle->lpVtbl->CopyTextureRegion( + d3d12CmdBuffer->handle, + &dstLocation, + 0, + 0, + 0, + &srcLocation, + &box); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBindPipelineD3D12( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + PipelineD3D12* d3dPipeline = (PipelineD3D12*)pipeline; + + if (d3dPipeline->type == RAY_TRACING_PIPELINE) { + d3d12CmdBuffer->handle->lpVtbl->SetPipelineState1( + d3d12CmdBuffer->handle, + d3dPipeline->handle); + + d3d12CmdBuffer->handle->lpVtbl->SetComputeRootSignature( + d3d12CmdBuffer->handle, + d3dPipeline->layout->handle); + + } else { + d3d12CmdBuffer->handle->lpVtbl->SetPipelineState( + d3d12CmdBuffer->handle, + d3dPipeline->handle); + + if (d3dPipeline->type == GRAPHICS_PIPELINE) { + d3d12CmdBuffer->handle->lpVtbl->IASetPrimitiveTopology( + d3d12CmdBuffer->handle, + d3dPipeline->topology); + + d3d12CmdBuffer->handle->lpVtbl->SetGraphicsRootSignature( + d3d12CmdBuffer->handle, + d3dPipeline->layout->handle); + + if (d3dPipeline->hasFsr) { + d3d12CmdBuffer->handle->lpVtbl->RSSetShadingRate( + d3d12CmdBuffer->handle, + d3dPipeline->shadingRate, + d3dPipeline->combinerOps); + } + } + } + + d3d12CmdBuffer->pipeline = d3dPipeline; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetViewportD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalViewport* viewports) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + D3D12_VIEWPORT cachedViewport; + D3D12_VIEWPORT* d3dViewports = nullptr; + + if (count > 1) { + d3dViewports = palAllocate(s_D3D12.allocator, sizeof(D3D12_VIEWPORT) * count, 0); + if (!d3dViewports) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + } else { + d3dViewports = &cachedViewport; + } + + for (int i = 0; i < count; i++) { + D3D12_VIEWPORT* tmp = &d3dViewports[i]; + tmp->TopLeftX = viewports[i].x; + tmp->TopLeftY = viewports[i].y; + tmp->Width = viewports[i].width; + tmp->Height = viewports[i].height; + tmp->MinDepth = viewports[i].minDepth; + tmp->MaxDepth = viewports[i].maxDepth; + } + + d3d12CmdBuffer->handle->lpVtbl->RSSetViewports(d3d12CmdBuffer->handle, count, d3dViewports); + if (count > 1) { + palFree(s_D3D12.allocator, d3dViewports); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetScissorsD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalRect2D* scissors) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + D3D12_RECT cachedScissor; + D3D12_RECT* d3dScissors = nullptr; + + if (count > 1) { + d3dScissors = palAllocate(s_D3D12.allocator, sizeof(D3D12_RECT) * count, 0); + if (!d3dScissors) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + } else { + d3dScissors = &cachedScissor; + } + + for (int i = 0; i < count; i++) { + D3D12_RECT* tmp = &d3dScissors[i]; + tmp->left = scissors[i].x; + tmp->top = scissors[i].y; + tmp->right = scissors[i].width; + tmp->bottom = scissors[i].height; + } + + d3d12CmdBuffer->handle->lpVtbl->RSSetScissorRects(d3d12CmdBuffer->handle, count, d3dScissors); + if (count > 1) { + palFree(s_D3D12.allocator, d3dScissors); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBindVertexBuffersD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t firstSlot, + uint32_t count, + PalBuffer** buffers, + uint64_t* offsets) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + PipelineD3D12* pipeline = d3d12CmdBuffer->pipeline; + D3D12_VERTEX_BUFFER_VIEW cachedView = {0}; + D3D12_VERTEX_BUFFER_VIEW* views = nullptr; + + if (!pipeline) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + if (count > 1) { + views = palAllocate(s_D3D12.allocator, sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, 0); + if (!views) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + } else { + views = &cachedView; + } + + for (int i = 0; i < count; i++) { + BufferD3D12* tmp = (BufferD3D12*)buffers[i]; + views[i].BufferLocation = tmp->handle->lpVtbl->GetGPUVirtualAddress(tmp->handle); + views[i].BufferLocation = views[i].BufferLocation + offsets[i]; + views[i].SizeInBytes = (UINT)tmp->size; + views[i].StrideInBytes = pipeline->strides[i]; + } + + d3d12CmdBuffer->handle->lpVtbl->IASetVertexBuffers( + d3d12CmdBuffer->handle, + firstSlot, + count, + views); + + if (count > 1) { + palFree(s_D3D12.allocator, views); + } + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBindIndexBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint64_t offset, + PalIndexType type) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + D3D12_INDEX_BUFFER_VIEW view = {0}; + BufferD3D12* indexBuffer = (BufferD3D12*)buffer; + + view.BufferLocation = indexBuffer->handle->lpVtbl->GetGPUVirtualAddress(indexBuffer->handle); + view.BufferLocation = view.BufferLocation + offset; + view.SizeInBytes = (UINT)indexBuffer->size; + if (type == PAL_INDEX_TYPE_UINT16) { + view.Format = DXGI_FORMAT_R16_UINT; + } else { + view.Format = DXGI_FORMAT_R32_UINT; + } + + d3d12CmdBuffer->handle->lpVtbl->IASetIndexBuffer(d3d12CmdBuffer->handle, &view); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + d3d12CmdBuffer->handle->lpVtbl->DrawInstanced( + d3d12CmdBuffer->handle, + vertexCount, + instanceCount, + firstVertex, + firstInstance); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3d12CmdBuffer->handle, + device->drawSignature, + count, + d3d12Buffer->handle, + 0, + nullptr, + 0); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + BufferD3D12* d3d12CountBuffer = (BufferD3D12*)countBuffer; + if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3d12CmdBuffer->handle, + device->drawSignature, + maxDrawCount, + d3d12Buffer->handle, + 0, + d3d12CountBuffer->handle, + 0); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawIndexedD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + d3d12CmdBuffer->handle->lpVtbl->DrawIndexedInstanced( + d3d12CmdBuffer->handle, + indexCount, + instanceCount, + firstIndex, + vertexOffset, + firstInstance); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3d12CmdBuffer->handle, + device->drawIndexedSignature, + count, + d3d12Buffer->handle, + 0, + nullptr, + 0); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + BufferD3D12* d3d12CountBuffer = (BufferD3D12*)countBuffer; + if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3d12CmdBuffer->handle, + device->drawIndexedSignature, + maxDrawCount, + d3d12Buffer->handle, + 0, + d3d12CountBuffer->handle, + 0); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, + PalUsageState oldUsageState, + PalUsageState newUsageState) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + if (!(d3d12CmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + AccelerationStructureD3D12* d3dAs = (AccelerationStructureD3D12*)as; + D3D12_RESOURCE_BARRIER barrier = {0}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrier.UAV.pResource = d3dAs->handle; + + d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdImageBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalUsageState oldUsageState, + PalUsageState newUsageState) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + ImageD3D12* d3dImage = (ImageD3D12*)image; + D3D12_RESOURCE_STATES old, new; + D3D12_RESOURCE_BARRIER barrier = {0}; + + old = barrierToD3D12(oldUsageState); + new = barrierToD3D12(newUsageState); + + // read/write barrier without transition + if (old == new && old == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrier.UAV.pResource = d3dImage->handle; + d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + return PAL_RESULT_SUCCESS; + } + + uint32_t planeCount = 1; // for color or depth + if (subresourceRange->aspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { + planeCount = 2; + } + + D3D12_RESOURCE_BARRIER* barriers = nullptr; + uint32_t levelCount = subresourceRange->mipLevelCount; + uint32_t layerCount = subresourceRange->layerArrayCount; + + uint32_t startLevel = subresourceRange->startMipLevel; + uint32_t startLayer = subresourceRange->startArrayLayer; + uint32_t maxLevels = d3dImage->info.mipLevelCount; + uint32_t maxLayers = d3dImage->info.arrayLayerCount; + uint32_t barrierCount = layerCount * levelCount * planeCount; + + if (startLevel == 0 && levelCount == maxLevels && startLayer == 0 && layerCount == maxLayers) { + // full resource + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = d3dImage->handle; + barrier.Transition.StateBefore = old; + barrier.Transition.StateAfter = new; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + + d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + return PAL_RESULT_SUCCESS; + } + + if (layerCount == 1 && layerCount == 1 && planeCount == 1) { + // single plane + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = d3dImage->handle; + barrier.Transition.StateBefore = old; + barrier.Transition.StateAfter = new; + barrier.Transition.Subresource = startLevel + startLayer * maxLevels; + + d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + return PAL_RESULT_SUCCESS; + } + + barriers = palAllocate(s_D3D12.allocator, sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, 0); + if (!barriers) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + uint32_t count = 0; + for (uint32_t plane = 0; plane < planeCount; plane++) { + for (uint32_t layer = startLayer; layer < startLayer + layerCount; layer++) { + for (uint32_t level = startLevel; level < startLevel + levelCount; level++) { + uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); + + D3D12_RESOURCE_BARRIER* tmp = &barriers[count++]; + tmp->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + tmp->Transition.pResource = d3dImage->handle; + tmp->Transition.StateBefore = old; + tmp->Transition.StateAfter = new; + tmp->Transition.Subresource = index; + } + } + } + + d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, barrierCount, barriers); + palFree(s_D3D12.allocator, barriers); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBufferBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalUsageState oldUsageState, + PalUsageState newUsageState) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + D3D12_RESOURCE_STATES old, new; + if (!d3d12Buffer->canStateChange) { + return PAL_RESULT_SUCCESS; + } + + old = barrierToD3D12(oldUsageState); + new = barrierToD3D12(newUsageState); + + D3D12_RESOURCE_BARRIER barrier = {0}; + if (old == new && D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrier.UAV.pResource = d3d12Buffer->handle; + } else { + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = d3d12Buffer->handle; + barrier.Transition.StateBefore = old; + barrier.Transition.StateAfter = new; + } + + d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDispatchD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + d3d12CmdBuffer->handle->lpVtbl->Dispatch( + d3d12CmdBuffer->handle, + groupCountX, + groupCountY, + groupCountZ); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdDispatchBaseD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) +{ + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; +} + +PalResult PAL_CALL cmdDispatchIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3d12CmdBuffer->handle, + device->dispatchSignature, + 1, // one dispatch + d3d12Buffer->handle, + 0, + nullptr, + 0); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdTraceRaysD3D12( + PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; + if (!(d3d12CmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + uint64_t stride = d3d12Sbt->raygen.region.StrideInBytes; + D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; + raygenAddress.SizeInBytes = d3d12Sbt->raygen.region.SizeInBytes; + raygenAddress.StartAddress = d3d12Sbt->baseAddress + raygenIndex * stride; + + // we need to make sure the SBT is up to date + commitShaderbindingTableUpdateD3D12(d3d12CmdBuffer, d3d12Sbt); + + D3D12_DISPATCH_RAYS_DESC desc = {0}; + desc.Width = width; + desc.Height = height; + desc.Depth = depth; + desc.RayGenerationShaderRecord = raygenAddress; + desc.HitGroupTable = d3d12Sbt->hit.region; + desc.MissShaderTable = d3d12Sbt->miss.region; + desc.CallableShaderTable = d3d12Sbt->callable.region; + + d3d12CmdBuffer->handle->lpVtbl->DispatchRays(d3d12CmdBuffer->handle, &desc); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdTraceRaysIndirectD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t raygenIndex, + PalShaderBindingTable* sbt, + PalBuffer* buffer) +{ + HRESULT result; + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; + BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + DeviceD3D12* device = (DeviceD3D12*)d3d12CmdBuffer->device; + D3D12_DISPATCH_RAYS_DESC desc = {0}; + + if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + // we need to make sure the SBT is up to date + commitShaderbindingTableUpdateD3D12(d3d12CmdBuffer, d3d12Sbt); + + // BufferD3D12 is mappable + void* ptr = nullptr; + result = d3d12Buffer->handle->lpVtbl->Map(d3d12Buffer->handle, 0, nullptr, &ptr); + if (FAILED(result)) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + // copy indirect parameters from the buffer + PalDispatchIndirectData data = {0}; + memcpy(&data, ptr, sizeof(PalDispatchIndirectData)); + d3d12Buffer->handle->lpVtbl->Unmap(d3d12Buffer->handle, 0, nullptr); + + desc.Width = data.groupCountXOrWidth; + desc.Height = data.groupCountXOrHeight; + desc.Depth = data.groupCountXOrDepth; + + uint64_t stride = d3d12Sbt->raygen.region.StrideInBytes; + D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; + raygenAddress.SizeInBytes = d3d12Sbt->raygen.region.SizeInBytes; + raygenAddress.StartAddress = d3d12Sbt->baseAddress + raygenIndex * stride; + + desc.RayGenerationShaderRecord = raygenAddress; + desc.HitGroupTable = d3d12Sbt->hit.region; + desc.MissShaderTable = d3d12Sbt->miss.region; + desc.CallableShaderTable = d3d12Sbt->callable.region; + + // fill the data into the tmp upload buffer of the command buffer + ptr = nullptr; + d3d12CmdBuffer->stagingBuffer->lpVtbl->Map(d3d12CmdBuffer->stagingBuffer, 0, nullptr, &ptr); + memcpy(ptr, &desc, sizeof(D3D12_DISPATCH_RAYS_DESC)); + d3d12CmdBuffer->stagingBuffer->lpVtbl->Unmap(d3d12CmdBuffer->stagingBuffer, 0, nullptr); + + // copy to the gpu tmp buffer of the command buffer and execute with that + d3d12CmdBuffer->handle->lpVtbl->CopyBufferRegion( + d3d12CmdBuffer->handle, + d3d12CmdBuffer->buffer, + 0, + d3d12CmdBuffer->stagingBuffer, + 0, + sizeof(D3D12_DISPATCH_RAYS_DESC)); + + // put a memory barrier + D3D12_RESOURCE_BARRIER barrier = {0}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.pResource = d3d12CmdBuffer->buffer; + d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + + d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( + d3d12CmdBuffer->handle, + device->raySignature, + 1, + d3d12CmdBuffer->buffer, + 0, + nullptr, + 0); + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdBindDescriptorSetD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t setIndex, + PalDescriptorSet* set) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + PipelineD3D12* pipeline = d3d12CmdBuffer->pipeline; + DescriptorSetD3D12* d3dSet = (DescriptorSetD3D12*)set; + DescriptorPoolD3D12* pool = d3dSet->pool; + + // bind heaps + uint32_t heapCount = 0; + ID3D12DescriptorHeap* heaps[2]; + if (pool->hasResourceHeap) { + heaps[heapCount++] = pool->resourceHeap.handle; + } + + if (pool->hasSamplerHeap) { + heaps[heapCount++] = pool->samplerHeap.handle; + } + d3d12CmdBuffer->handle->lpVtbl->SetDescriptorHeaps(d3d12CmdBuffer->handle, heapCount, heaps); + + // bind resource descriptor table + uint32_t resourceCount = d3dSet->layout->bindingCount - d3dSet->layout->samplerCount; + uint32_t baseIndex = setIndex; + if (pipeline->layout->constantIndex != UINT32_MAX) { + // If push constant was used to create the pipeline layout + // slot 0 will be reserve for it + baseIndex++; + } + + if (resourceCount) { + D3D12_GPU_DESCRIPTOR_HANDLE base; + base.ptr = getDescriptorHandleD3D12( + d3dSet->resourceOffset, + pool->resourceHeap.incrementSize, + pool->resourceHeap.gpuBase); + + if (pipeline->type == GRAPHICS_PIPELINE) { + d3d12CmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( + d3d12CmdBuffer->handle, + baseIndex, // base set index is resource first before sampler + base); + + } else { + // ray tracing uses the compute path + d3d12CmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( + d3d12CmdBuffer->handle, + baseIndex, // base set index is resource first before sampler + base); + } + + baseIndex++; + } + + // bind sampler descriptor table + if (d3dSet->layout->samplerCount) { + D3D12_GPU_DESCRIPTOR_HANDLE base; + base.ptr = getDescriptorHandleD3D12( + d3dSet->samplerOffset, + pool->samplerHeap.incrementSize, + pool->samplerHeap.gpuBase); + + if (pipeline->type == GRAPHICS_PIPELINE) { + d3d12CmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( + d3d12CmdBuffer->handle, + baseIndex, + base); + + } else { + // ray tracing uses the compute path + d3d12CmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( + d3d12CmdBuffer->handle, + baseIndex, + base); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdPushConstantsD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t offset, + uint32_t size, + const void* value) +{ + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + PipelineD3D12* pipeline = d3d12CmdBuffer->pipeline; + + if (pipeline->layout->constantIndex != UINT32_MAX) { + if (pipeline->type == GRAPHICS_PIPELINE) { + d3d12CmdBuffer->handle->lpVtbl->SetGraphicsRoot32BitConstants( + d3d12CmdBuffer->handle, + pipeline->layout->constantIndex, + size / 4, + value, + offset / 4); + + } else { + // ray tracing uses the compute path + d3d12CmdBuffer->handle->lpVtbl->SetComputeRoot32BitConstants( + d3d12CmdBuffer->handle, + pipeline->layout->constantIndex, + size / 4, + value, + offset / 4); + } + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL cmdSetCullModeD3D12( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode) +{ + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; +} + +PalResult PAL_CALL cmdSetFrontFaceD3D12( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace) +{ + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; +} + +PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology) +{ + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; +} + +PalResult PAL_CALL cmdSetDepthTestEnableD3D12( + PalCommandBuffer* cmdBuffer, + PalBool enable) +{ + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; +} + +PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( + PalCommandBuffer* cmdBuffer, + PalBool enable) +{ + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; +} + +PalResult PAL_CALL cmdSetStencilOpD3D12( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp) +{ + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; +} #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_d3d12.h b/src/graphics/d3d12/pal_d3d12.h index 81a02861..adae9912 100644 --- a/src/graphics/d3d12/pal_d3d12.h +++ b/src/graphics/d3d12/pal_d3d12.h @@ -9,7 +9,6 @@ #define _PAL_D3D12_H #if PAL_HAS_D3D12_BACKEND -#define COBJMACROS #include "pal/pal_graphics.h" #include #include @@ -18,6 +17,8 @@ #define MAX_RTV 1024 #define MAX_DSV 512 +#define TEXTURE_PITCH 256 +#define MAX_ATTACHMENTS 8 typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -187,9 +188,16 @@ typedef struct { uint32_t fenceValue; PalQueueType type; ID3D12Fence* fence; + HANDLE fenceEvent; ID3D12CommandQueue* handle; } QueueD3D12; +typedef struct { + void* reserved; + PalMemoryType type; + ID3D12Heap* handle; +} MemoryD3D12; + typedef struct { void* reserved; HWND handle; @@ -276,11 +284,9 @@ typedef struct { typedef struct { void* reserved; - PalBool supportsAddress; - PalBool canChangeState; - PalBool hasIndirect; - PalBool isAccelerationStructure; - PalBool isScratch; + PalBool isMemoryManaged; + PalBool canStateChange; + PalBufferUsages usages; uint64_t size; ID3D12Resource* handle; DeviceD3D12* device; @@ -399,6 +405,31 @@ void getDescriptorTierLimitsD3D12( PalResourceCapabilities* caps, PalDescriptorIndexingCapabilities* descCaps); +uint32_t getFormatSizeD3D12(PalFormat format); + +// IIDs +extern IID IID_Device; +extern IID IID_Adapter; +extern IID IID_Factory; +extern IID IID_DebugController; +extern IID IID_DebugController1; +extern IID IID_InfoQueue; +extern IID IID_Heap; +extern IID IID_Queue; +extern IID IID_Swapchain; +extern IID IID_CommandAllocator; +extern IID IID_CommandList; +extern IID IID_CommandList6; +extern IID IID_CommandSignature; +extern IID IID_DescriptorHeap; +extern IID IID_RootSignature; +extern IID IID_Device5; +extern IID IID_PipelineState; +extern IID IID_StateObject; +extern IID IID_Resource; +extern IID IID_StateObjectProps; +extern IID IID_Fence; + extern D3D12 s_D3D12; #endif // PAL_HAS_D3D12_BACKEND diff --git a/src/graphics/d3d12/pal_descriptors_d3d12.c b/src/graphics/d3d12/pal_descriptors_d3d12.c index 31b70783..9b5b3eed 100644 --- a/src/graphics/d3d12/pal_descriptors_d3d12.c +++ b/src/graphics/d3d12/pal_descriptors_d3d12.c @@ -6,6 +6,685 @@ */ #if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" +PalResult PAL_CALL createDescriptorSetLayoutD3D12( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout) +{ + HRESULT result; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DescriptorSetLayoutD3D12* layout = nullptr; + DescriptorSetBinding* bindings = nullptr; + uint32_t count = info->bindingCount; + + PalBool hasDescriptorIndexing = PAL_FALSE; + if (d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + hasDescriptorIndexing = PAL_TRUE; + } + + if (info->flags != 0 && !hasDescriptorIndexing) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + // partially bound is not supported + if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + layout = palAllocate(s_D3D12.allocator, sizeof(DescriptorSetLayoutD3D12), 0); + bindings = palAllocate(s_D3D12.allocator, sizeof(DescriptorSetBinding) * count, 0); + if (!layout || !bindings) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + D3D12_DESCRIPTOR_RANGE_FLAGS rangeFlags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; + if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND) { + rangeFlags = D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE; + } + + uint32_t resourceOffset = 0; + uint32_t samplerOffset = 0; + uint32_t SRVRegister = 0; + uint32_t UAVRegister = 0; + uint32_t CBVRegister = 0; + + uint32_t sampledImageCount = 0; + uint32_t storageImageCount = 0; + uint32_t storageBufferCount = 0; + uint32_t uniformBufferCount = 0; + uint32_t tlasCount = 0; + uint32_t samplerCount = 0; + + for (int i = 0; i < count; i++) { + DescriptorSetBinding* binding = &bindings[i]; + binding->type = info->bindings[i].descriptorType; + + binding->range.NumDescriptors = info->bindings[i].descriptorCount; + binding->range.Flags = rangeFlags; + binding->range.RegisterSpace = 0; + + switch (info->bindings[i].descriptorType) { + case PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + binding->range.BaseShaderRegister = SRVRegister; + + binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; + resourceOffset += info->bindings[i].descriptorCount; + tlasCount += info->bindings[i].descriptorCount; + SRVRegister += info->bindings[i].descriptorCount; + + break; + } + + case PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + binding->range.BaseShaderRegister = SRVRegister; + + binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; + resourceOffset += info->bindings[i].descriptorCount; + sampledImageCount += info->bindings[i].descriptorCount; + SRVRegister += info->bindings[i].descriptorCount; + break; + } + + case PAL_DESCRIPTOR_TYPE_SAMPLER: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + binding->range.BaseShaderRegister = samplerCount; + + binding->range.OffsetInDescriptorsFromTableStart = samplerOffset; + samplerOffset += info->bindings[i].descriptorCount; + samplerCount += info->bindings[i].descriptorCount; + break; + } + + case PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + binding->range.BaseShaderRegister = UAVRegister; + + binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; + resourceOffset += info->bindings[i].descriptorCount; + storageBufferCount += info->bindings[i].descriptorCount; + UAVRegister += info->bindings[i].descriptorCount; + break; + } + + case PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + binding->range.BaseShaderRegister = UAVRegister; + + binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; + resourceOffset += info->bindings[i].descriptorCount; + storageImageCount += info->bindings[i].descriptorCount; + UAVRegister += info->bindings[i].descriptorCount; + break; + } + + case PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { + binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; + binding->range.BaseShaderRegister = CBVRegister; + + binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; + resourceOffset += info->bindings[i].descriptorCount; + uniformBufferCount += info->bindings[i].descriptorCount; + CBVRegister += info->bindings[i].descriptorCount; + break; + } + } + } + + // check limits + if (sampledImageCount > d3d12Device->limits.maxDescriptorSampledImages) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (storageImageCount > d3d12Device->limits.maxDescriptorStorageImages) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (storageBufferCount > d3d12Device->limits.maxDescriptorStorageBuffers) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (uniformBufferCount > d3d12Device->limits.maxDescriptorUniformBuffers) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (tlasCount > d3d12Device->limits.maxDescriptorAccelerationStructures) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + if (samplerCount > d3d12Device->limits.maxDescriptorSamplers) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + layout->flags = info->flags; + layout->bindingCount = info->bindingCount; + layout->samplerCount = samplerCount; + layout->bindings = bindings; + layout->reserved = PAL_BACKEND_KEY; + *outLayout = (PalDescriptorSetLayout*)layout; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout) +{ + DescriptorSetLayoutD3D12* d3d12Layout = (DescriptorSetLayoutD3D12*)layout; + palFree(s_D3D12.allocator, d3d12Layout->bindings); + palFree(s_D3D12.allocator, d3d12Layout); +} + +PalResult PAL_CALL createDescriptorPoolD3D12( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool) +{ + HRESULT result; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DescriptorPoolD3D12* pool = nullptr; + + PalBool hasDescriptorIndexing = PAL_FALSE; + if (d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + hasDescriptorIndexing = PAL_TRUE; + } + + if (info->flags != 0 && !hasDescriptorIndexing) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + // partially bound is not supported + if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + pool = palAllocate(s_D3D12.allocator, sizeof(DescriptorPoolD3D12), 0); + if (!pool) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + memset(pool, 0, sizeof(DescriptorPoolD3D12)); + pool->sets = palAllocate( + s_D3D12.allocator, + sizeof(DescriptorSetD3D12) * info->maxDescriptorSets, + 0); + + if (!pool->sets) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + uint32_t resourceCount = 0; + DescriptorHeapLimits* limits = &pool->limits; + for (int i = 0; i < info->bindingSizeCount; i++) { + PalDescriptorPoolBindingSize* bindingSize = &info->bindingSizes[i]; + if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { + limits->maxSamplers += bindingSize->bindingCount; + + } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + limits->maxUniformBuffers += bindingSize->bindingCount; + resourceCount += bindingSize->bindingCount; + + } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER) { + limits->maxStorageBuffers += bindingSize->bindingCount; + resourceCount += bindingSize->bindingCount; + + } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + limits->maxSampledImages += bindingSize->bindingCount; + resourceCount += bindingSize->bindingCount; + + } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { + limits->maxStorageImages += bindingSize->bindingCount; + resourceCount += bindingSize->bindingCount; + + } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + limits->maxAs += bindingSize->bindingCount; + resourceCount += bindingSize->bindingCount; + } + } + + // resource heap + if (resourceCount) { + DescriptorHeap* heap = &pool->resourceHeap; + D3D12_CPU_DESCRIPTOR_HANDLE __ret, handle; + D3D12_GPU_DESCRIPTOR_HANDLE __gpuRet, gpuHandle; + + D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + desc.NumDescriptors = resourceCount; + + result = d3d12Device->handle->lpVtbl->CreateDescriptorHeap( + d3d12Device->handle, + &desc, + &IID_DescriptorHeap, + (void**)&heap->handle); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + return makeResultD3D12(result); + } + + // get increment size + heap->incrementSize = d3d12Device->handle->lpVtbl->GetDescriptorHandleIncrementSize( + d3d12Device->handle, + D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + // get base CPU and GPU base pointer + handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( + heap->handle, + &__ret); + heap->cpuBase = handle.ptr; + + gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( + heap->handle, + &__gpuRet); + heap->gpuBase = gpuHandle.ptr; + + pool->hasResourceHeap = PAL_TRUE; + } + + // sampler heap + if (limits->maxSamplers) { + DescriptorHeap* heap = &pool->samplerHeap; + D3D12_CPU_DESCRIPTOR_HANDLE __ret, handle; + D3D12_GPU_DESCRIPTOR_HANDLE __gpuRet, gpuHandle; + + D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; + desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; + desc.NumDescriptors = limits->maxSamplers; + + result = d3d12Device->handle->lpVtbl->CreateDescriptorHeap( + d3d12Device->handle, + &desc, + &IID_DescriptorHeap, + (void**)&heap->handle); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + // get increment size + heap->incrementSize = d3d12Device->handle->lpVtbl->GetDescriptorHandleIncrementSize( + d3d12Device->handle, + D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + + // get base CPU and GPU base pointer + handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( + heap->handle, + &__ret); + heap->cpuBase = handle.ptr; + + gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( + heap->handle, + &__gpuRet); + heap->gpuBase = gpuHandle.ptr; + + pool->hasSamplerHeap = PAL_TRUE; + } + + pool->flags = info->flags; + pool->maxSets = info->maxDescriptorSets; + pool->reserved = PAL_BACKEND_KEY; + *outPool = (PalDescriptorPool*)pool; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) +{ + DescriptorPoolD3D12* d3d12Pool = (DescriptorPoolD3D12*)pool; + if (d3d12Pool->hasResourceHeap) { + d3d12Pool->resourceHeap.handle->lpVtbl->Release(d3d12Pool->resourceHeap.handle); + } + + if (d3d12Pool->hasSamplerHeap) { + d3d12Pool->samplerHeap.handle->lpVtbl->Release(d3d12Pool->samplerHeap.handle); + } + + palFree(s_D3D12.allocator, d3d12Pool->sets); + palFree(s_D3D12.allocator, d3d12Pool); +} + +PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool) +{ + DescriptorPoolD3D12* d3d12Pool = (DescriptorPoolD3D12*)pool; + d3d12Pool->resourceHeap.nextOffset = 0; + d3d12Pool->samplerHeap.nextOffset = 0; + d3d12Pool->usedSets = 0; + + d3d12Pool->limits.usedAs = 0; + d3d12Pool->limits.usedSampledImages = 0; + d3d12Pool->limits.usedSamplers = 0; + d3d12Pool->limits.usedStorageBuffers = 0; + d3d12Pool->limits.usedStorageImages = 0; + d3d12Pool->limits.usedUniformBuffers = 0; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL allocateDescriptorSetD3D12( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DescriptorPoolD3D12* d3d12Pool = (DescriptorPoolD3D12*)pool; + DescriptorSetLayoutD3D12* d3d12Layout = (DescriptorSetLayoutD3D12*)layout; + DescriptorSetD3D12* set = nullptr; + + uint32_t storageImageCount = 0; + uint32_t samplerCount = 0; + uint32_t storageBufferCount = 0; + uint32_t uniformBufferCount = 0; + uint32_t sampledImageCount = 0; + uint32_t tlasCount = 0; + + PalBool isPoolValid = d3d12Pool->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; + PalBool isLayoutValid = d3d12Layout->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; + if (isPoolValid != isLayoutValid) { + // we check if both are true or false + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + // get requirements for the sets using the provided layout + for (int i = 0; i < d3d12Layout->bindingCount; i++) { + DescriptorSetBinding* binding = &d3d12Layout->bindings[i]; + + if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { + samplerCount += binding->range.NumDescriptors; + + } else if (binding->type == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER) { + storageBufferCount += binding->range.NumDescriptors; + + } else if (binding->type == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { + storageImageCount += binding->range.NumDescriptors; + + } else if (binding->type == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + uniformBufferCount += binding->range.NumDescriptors; + + } else if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + sampledImageCount += binding->range.NumDescriptors; + + } else if (binding->type == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + tlasCount += binding->range.NumDescriptors; + } + } + + // validate descriptor sets limits + if (d3d12Pool->usedSets + 1 > d3d12Pool->maxSets) { + // all sets are used + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + // check descriptor limits + DescriptorHeapLimits* limits = &d3d12Pool->limits; + if (limits->usedAs + tlasCount > limits->maxAs) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + if (limits->usedSampledImages + sampledImageCount > limits->maxSampledImages) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + if (limits->usedSamplers + samplerCount > limits->maxSamplers) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + if (limits->usedStorageBuffers + storageBufferCount > limits->maxStorageBuffers) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + if (limits->usedStorageImages + storageImageCount > limits->maxStorageImages) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + if (limits->usedUniformBuffers + uniformBufferCount > limits->maxUniformBuffers) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + // assign offset base to the set so we know where to start and end for each set. + set = &d3d12Pool->sets[d3d12Pool->usedSets++]; + set->resourceOffset = d3d12Pool->resourceHeap.nextOffset; + set->samplerOffset = d3d12Pool->samplerHeap.nextOffset; + set->layout = d3d12Layout; + set->pool = d3d12Pool; + + uint32_t totalDescriptors = tlasCount + storageBufferCount + uniformBufferCount; + totalDescriptors += sampledImageCount + storageImageCount; + d3d12Pool->resourceHeap.nextOffset += totalDescriptors; + d3d12Pool->samplerHeap.nextOffset += samplerCount; + + limits->usedAs += tlasCount; + limits->usedSampledImages += sampledImageCount; + limits->usedSamplers += samplerCount; + limits->usedStorageBuffers += storageBufferCount; + limits->usedUniformBuffers += uniformBufferCount; + + set->reserved = PAL_BACKEND_KEY; + *outSet = (PalDescriptorSet*)set; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL updateDescriptorSetD3D12( + PalDevice* device, + uint32_t count, + PalDescriptorSetWriteInfo* infos) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + for (int i = 0; i < count; i++) { + PalDescriptorSetWriteInfo* info = &infos[i]; + DescriptorSetD3D12* set = (DescriptorSetD3D12*)info->descriptorSet; + DescriptorPoolD3D12* pool = set->pool; + DescriptorSetLayoutD3D12* layout = set->layout; + + if (info->layoutBindingIndex > layout->bindingCount) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + DescriptorSetBinding* binding = &layout->bindings[info->layoutBindingIndex]; + DescriptorHeap* heap = nullptr; + uint32_t index = 0; + uint32_t bindingOffset = binding->range.OffsetInDescriptorsFromTableStart; + + if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { + heap = &pool->samplerHeap; + index = set->samplerOffset + bindingOffset + info->arrayElement; + + } else { + heap = &pool->resourceHeap; + index = set->resourceOffset + bindingOffset + info->arrayElement; + } + + for (int j = 0; j < info->descriptorCount; j++) { + D3D12_CPU_DESCRIPTOR_HANDLE dst; + dst.ptr = getDescriptorHandleD3D12(index + j, heap->incrementSize, heap->cpuBase); + + if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { + if (info->samplerInfos) { + SamplerD3D12* sampler = (SamplerD3D12*)info->samplerInfos[j].sampler; + d3d12Device->handle->lpVtbl->CreateSampler(d3d12Device->handle, &sampler->desc, dst); + + } else { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + D3D12_SAMPLER_DESC desc = {0}; + desc.MaxAnisotropy = 1; + desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; + desc.BorderColor[3] = 1.0f; + + desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; + d3d12Device->handle->lpVtbl->CreateSampler(d3d12Device->handle, &desc, dst); + } + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { + D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; + desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + desc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; + + if (info->tlasInfos) { + AccelerationStructureD3D12* tlas = nullptr; + tlas = (AccelerationStructureD3D12*)info->tlasInfos[j].tlas; + desc.RaytracingAccelerationStructure.Location = tlas->address; + + } else { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + d3d12Device->handle->lpVtbl->CreateShaderResourceView( + d3d12Device->handle, + nullptr, + &desc, + dst); + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { + D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; + desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + + PalImageSubresourceRange range = {0}; + PalImageViewType type; + ID3D12Resource* handle = nullptr; + + if (info->imageViewInfos) { + ImageViewD3D12* imageView = (ImageViewD3D12*)info->imageViewInfos[j].imageView; + desc.Format = imageView->format; + type = imageView->type; + range = imageView->range; + handle = imageView->image->handle; + + } else { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + type = PAL_IMAGE_VIEW_TYPE_2D; + range.mipLevelCount = 1; + range.layerArrayCount = 1; + range.aspect = PAL_IMAGE_ASPECT_COLOR; + } + + fillSubresourceD3D12( + type, + &range, + nullptr, + nullptr, + &desc, + nullptr); + + d3d12Device->handle->lpVtbl->CreateShaderResourceView( + d3d12Device->handle, + handle, + &desc, + dst); + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { + D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; + PalImageSubresourceRange range = {0}; + PalImageViewType type; + ID3D12Resource* handle = nullptr; + + if (info->imageViewInfos) { + ImageViewD3D12* imageView = (ImageViewD3D12*)info->imageViewInfos[j].imageView; + desc.Format = imageView->format; + type = imageView->type; + range = imageView->range; + handle = imageView->image->handle; + + } else { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + type = PAL_IMAGE_VIEW_TYPE_2D; + range.mipLevelCount = 1; + range.layerArrayCount = 1; + range.aspect = PAL_IMAGE_ASPECT_COLOR; + } + + fillSubresourceD3D12( + type, + &range, + nullptr, + nullptr, + nullptr, + &desc); + + d3d12Device->handle->lpVtbl->CreateUnorderedAccessView( + d3d12Device->handle, + handle, + nullptr, + &desc, + dst); + + } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { + D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {0}; + D3D12_GPU_VIRTUAL_ADDRESS address = 0; + + if (info->bufferInfos) { + PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; + BufferD3D12* buffer = (BufferD3D12*)bufferInfo->buffer; + desc.SizeInBytes = bufferInfo->size; + address = buffer->handle->lpVtbl->GetGPUVirtualAddress(buffer->handle); + desc.BufferLocation = address + bufferInfo->offset; + + } else { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + d3d12Device->handle->lpVtbl->CreateConstantBufferView( + d3d12Device->handle, + &desc, + dst); + + } else { + // storage buffer + D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; + desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + + ID3D12Resource* handle = nullptr; + if (info->bufferInfos) { + PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; + BufferD3D12* buffer = (BufferD3D12*)bufferInfo->buffer; + + uint32_t stride = 4; + if (bufferInfo->stride) { + stride = bufferInfo->stride; + desc.Buffer.StructureByteStride = bufferInfo->stride; + } else { + desc.Format = DXGI_FORMAT_R32_TYPELESS; + desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; + } + + handle = buffer->handle; + desc.Buffer.FirstElement = bufferInfo->offset / stride; + desc.Buffer.NumElements = bufferInfo->size / stride; + + } else { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + + d3d12Device->handle->lpVtbl->CreateUnorderedAccessView( + d3d12Device->handle, + handle, + nullptr, + &desc, + dst); + } + } + } + return PAL_RESULT_SUCCESS; +} #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c index 31b70783..1eca78a8 100644 --- a/src/graphics/d3d12/pal_device_d3d12.c +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -6,6 +6,728 @@ */ #if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" +PalResult PAL_CALL createDeviceD3D12( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice) +{ + HRESULT result; + DeviceD3D12* device = nullptr; + AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + + // check if any of the features are not supported + PalAdapterFeatures adapterFeatures = getAdapterFeaturesD3D12(adapter); + PalBool valid = (adapterFeatures & features) == features; + if (!valid) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + device = palAllocate(s_D3D12.allocator, sizeof(DeviceD3D12), 0); + if (!device) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + ID3D12Device* tmpDevice = nullptr; + memset(device, 0, sizeof(DeviceD3D12)); + DeviceLimits* limits = &device->limits; + + // get and cache highest shader model + device->shaderModel = getHighestSupportedShaderTargetD3D12(adapter, PAL_SHADER_FORMAT_DXIL); + + result = s_D3D12.createDevice( + (IUnknown*)d3d12Adapter->handle, + d3d12Adapter->level, + &IID_Device, + (void**)&tmpDevice); + + if (FAILED(result)) { + palFree(s_D3D12.allocator, device); + return makeResultD3D12(result); + } + + result = tmpDevice->lpVtbl->QueryInterface( + tmpDevice, + &IID_Device5, + (void**)&device->handle); + + tmpDevice->lpVtbl->Release(tmpDevice); + if (s_D3D12.debugLayer) { + result = device->handle->lpVtbl->QueryInterface( + device->handle, + &IID_InfoQueue, + (void**)&device->infoQueue); + + if (SUCCEEDED(result)) { + D3D12_MESSAGE_ID denyIDs[] = { D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE }; + D3D12_INFO_QUEUE_FILTER filter = {0}; + filter.AllowList.NumSeverities = s_D3D12.severityCount; + filter.AllowList.pSeverityList = s_D3D12.severities; + filter.AllowList.NumCategories = s_D3D12.categoryCount; + filter.AllowList.pCategoryList = s_D3D12.categories; + filter.DenyList.NumIDs = 1; + filter.DenyList.pIDList = denyIDs; + + device->infoQueue->lpVtbl->PushStorageFilter(device->infoQueue, &filter); + } + } + + // create a temporary graphics queue + D3D12_COMMAND_QUEUE_DESC desc = {0}; + desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + + result = device->handle->lpVtbl->CreateCommandQueue( + device->handle, + &desc, + &IID_Queue, + (void**)&device->queue); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + // create command signatures + D3D12_INDIRECT_ARGUMENT_DESC argumentDesc = {0}; + D3D12_COMMAND_SIGNATURE_DESC signatureDesc = {0}; + signatureDesc.NumArgumentDescs = 1; + signatureDesc.pArgumentDescs = &argumentDesc; + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH) { + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH; + signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_MESH_ARGUMENTS); + + result = device->handle->lpVtbl->CreateCommandSignature( + device->handle, + &signatureDesc, + nullptr, + &IID_CommandSignature, + (void**)&device->meshSignature); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + } + + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_RAYS; + signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_RAYS_DESC); + + result = device->handle->lpVtbl->CreateCommandSignature( + device->handle, + &signatureDesc, + nullptr, + &IID_CommandSignature, + (void**)&device->raySignature); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW) { + // draw indexed + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; + signatureDesc.ByteStride = sizeof(D3D12_DRAW_INDEXED_ARGUMENTS); + + result = device->handle->lpVtbl->CreateCommandSignature( + device->handle, + &signatureDesc, + nullptr, + &IID_CommandSignature, + (void**)&device->drawIndexedSignature); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + // draw + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; + signatureDesc.ByteStride = sizeof(D3D12_DRAW_ARGUMENTS); + + result = device->handle->lpVtbl->CreateCommandSignature( + device->handle, + &signatureDesc, + nullptr, + &IID_CommandSignature, + (void**)&device->drawSignature); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH) { + argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; + signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS); + + result = device->handle->lpVtbl->CreateCommandSignature( + device->handle, + &signatureDesc, + nullptr, + &IID_CommandSignature, + (void**)&device->dispatchSignature); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + } + + // create an internal heap for RTV and DSV + D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {0}; + heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + heapDesc.NumDescriptors = MAX_RTV; + + result = device->handle->lpVtbl->CreateDescriptorHeap( + device->handle, + &heapDesc, + &IID_DescriptorHeap, + (void**)&device->rtvAllocator.heap); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; + heapDesc.NumDescriptors = MAX_DSV; + result = device->handle->lpVtbl->CreateDescriptorHeap( + device->handle, + &heapDesc, + &IID_DescriptorHeap, + (void**)&device->dsvAllocator.heap); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + for (int i = 0; i < MAX_RTV; i++) { + device->rtvAllocator.freeList[i] = i + 1; + } + + for (int i = 0; i < MAX_DSV; i++) { + device->dsvAllocator.freeList[i] = i + 1; + } + + device->rtvAllocator.freeTop = 0; + device->rtvAllocator.incrementSize = device->handle->lpVtbl->GetDescriptorHandleIncrementSize( + device->handle, + D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + + device->dsvAllocator.freeTop = 0; + device->dsvAllocator.incrementSize = device->handle->lpVtbl->GetDescriptorHandleIncrementSize( + device->handle, + D3D12_DESCRIPTOR_HEAP_TYPE_DSV); + + // get base CPU pointer + D3D12_CPU_DESCRIPTOR_HANDLE __ret, dst; + dst = *device->rtvAllocator.heap->lpVtbl->GetCPUDescriptorHandleForHeapStart( + device->rtvAllocator.heap, + &__ret + ); + device->rtvAllocator.baseOffset = dst.ptr; + + dst = *device->dsvAllocator.heap->lpVtbl->GetCPUDescriptorHandleForHeapStart( + device->dsvAllocator.heap, + &__ret + ); + device->dsvAllocator.baseOffset = dst.ptr; + + // API enforced limits + limits->freeComputeQueues = 2; + limits->freeGraphicsQueues = 2; + limits->freeCopyQueues = 2; + limits->maxVertexLayouts = 30; + limits->maxVertexAttributes = 30; + + limits->maxAnisotropy = 16; + limits->maxPushConstantSize = 256; + limits->maxTessellationPatchPoint = 32; + limits->maxBoundDescriptorSets = 30; + + if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + limits->maxDescriptorSampledImages = 4096; + limits->maxDescriptorStorageImages = 1024; + limits->maxDescriptorSamplers = 512; + limits->maxDescriptorStorageBuffers = 2048; + limits->maxDescriptorUniformBuffers = 256; + + } else { + limits->maxDescriptorSampledImages = 1024; + limits->maxDescriptorStorageImages = 512; + limits->maxDescriptorSamplers = 256; + limits->maxDescriptorStorageBuffers = 512; + limits->maxDescriptorUniformBuffers = 256; + limits->maxBoundDescriptorSets = 30; + } + + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + limits->maxRecursionDepth = 31; + limits->maxHitAttributeSize = 32; + limits->maxPayloadSize = 64; + limits->maxDispatchInvocations = 16000000; + limits->maxDescriptorAccelerationStructures = 4; + } + + device->adapter = d3d12Adapter->handle; + device->features = features; + *outDevice = (PalDevice*)device; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyDeviceD3D12(PalDevice* device) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + if (d3d12Device->meshSignature) { + d3d12Device->meshSignature->lpVtbl->Release(d3d12Device->meshSignature); + } + + if (d3d12Device->raySignature) { + d3d12Device->raySignature->lpVtbl->Release(d3d12Device->raySignature); + } + + if (d3d12Device->dispatchSignature) { + d3d12Device->dispatchSignature->lpVtbl->Release(d3d12Device->dispatchSignature); + } + + if (d3d12Device->drawIndexedSignature) { + d3d12Device->drawIndexedSignature->lpVtbl->Release(d3d12Device->drawIndexedSignature); + } + + if (d3d12Device->drawSignature) { + d3d12Device->drawSignature->lpVtbl->Release(d3d12Device->drawSignature); + } + + d3d12Device->rtvAllocator.heap->lpVtbl->Release(d3d12Device->rtvAllocator.heap); + d3d12Device->dsvAllocator.heap->lpVtbl->Release(d3d12Device->dsvAllocator.heap); + + d3d12Device->queue->lpVtbl->Release(d3d12Device->queue); + d3d12Device->handle->lpVtbl->Release(d3d12Device->handle); + if (d3d12Device->infoQueue) { + d3d12Device->infoQueue->lpVtbl->Release(d3d12Device->infoQueue); + } + + palFree(s_D3D12.allocator, d3d12Device); +} + +PalResult PAL_CALL allocateMemoryD3D12( + PalDevice* device, + PalMemoryType type, + uint64_t memoryMask, + uint64_t size, + PalMemory** outMemory) +{ + HRESULT result; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + MemoryD3D12* memory = nullptr; + + memory = palAllocate(s_D3D12.allocator, sizeof(MemoryD3D12), 0); + if (!memory) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + D3D12_HEAP_DESC desc = {0}; + desc.SizeInBytes = size; + + desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; + if (type == PAL_MEMORY_TYPE_CPU_READBACK) { + desc.Properties.Type = D3D12_HEAP_TYPE_READBACK; + + } else if (type == PAL_MEMORY_TYPE_CPU_UPLOAD) { + desc.Properties.Type = D3D12_HEAP_TYPE_UPLOAD; + } + + result = d3d12Device->handle->lpVtbl->CreateHeap( + d3d12Device->handle, + &desc, + &IID_Heap, + (void**)&memory->handle); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + return makeResultD3D12(result); + } + + memory->type = type; + memory->reserved = PAL_BACKEND_KEY; + *outMemory = (PalMemory*)memory; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL freeMemoryD3D12( + PalDevice* device, + PalMemory* memory) +{ + MemoryD3D12* d3d12Memory = (MemoryD3D12*)memory; + d3d12Memory->handle->lpVtbl->Release(d3d12Memory->handle); + palFree(s_D3D12.allocator, d3d12Memory); +} + +PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + caps->maxAnisotropy = 16; // default on most d3d12 hardwares + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( + PalDevice* device, + PalMultiViewCapabilities* caps) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + caps->maxViewCount = D3D12_MAX_VIEW_INSTANCE_COUNT; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( + PalDevice* device, + PalMultiViewportCapabilities* caps) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + caps->maxCount = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( + PalDevice* device, + PalDepthStencilCapabilities* caps) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + // depth resolve modes + caps->supportedDepthResolveModes |= (1u << PAL_RESOLVE_MODE_AVERAGE); + caps->supportedDepthResolveModes |= (1u << PAL_RESOLVE_MODE_MIN); + caps->supportedDepthResolveModes |= (1u << PAL_RESOLVE_MODE_MAX); + + // stencil resolve modes + caps->supportedStencilResolveModes |= (1u << PAL_RESOLVE_MODE_MIN); + caps->supportedStencilResolveModes |= (1u << PAL_RESOLVE_MODE_MAX); + + caps->supportsIndependentResolve = PAL_FALSE; + caps->supportsIndependentResolveNone = PAL_FALSE; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + // these are supported if fragment shading rate feature is + caps->supportedShadingRates = 0; + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_1X1); + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_1X2); + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_2X1); + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_2X2); + + D3D12_FEATURE_DATA_D3D12_OPTIONS6 options = {0}; + d3d12Device->handle->lpVtbl->CheckFeatureSupport( + d3d12Device->handle, + D3D12_FEATURE_D3D12_OPTIONS6, + &options, + sizeof(options)); + + if (options.AdditionalShadingRatesSupported) { + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_2X4); + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_4X2); + caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_4X4); + } + + // there are supported if fragment shading rate feature is + caps->supportedCombinerOps = 0; + caps->supportedCombinerOps |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP); + caps->supportedCombinerOps |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE); + caps->supportedCombinerOps |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN); + caps->supportedCombinerOps |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX); + caps->supportedCombinerOps |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL); + + caps->minTexelWidth = 1; // safe default + caps->minTexelHeight = 1; // safe default + caps->maxTexelWidth = options.ShadingRateImageTileSize; + caps->maxTexelHeight = options.ShadingRateImageTileSize; + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( + PalDevice* device, + PalMeshShaderCapabilities* caps) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + // these are not exposed by d3d12. We use the offical mesh shader spec + caps->maxOutputPrimitives = 256; + caps->maxOutputVertices = 256; + caps->maxWorkGroupInvocations = 128; + caps->maxTaskWorkGroupInvocations = 128; + + caps->maxWorkGroupCount[0] = 65535; + caps->maxWorkGroupCount[1] = 65535; + caps->maxWorkGroupCount[2] = 65535; + + caps->maxTaskWorkGroupCount[0] = 65535; + caps->maxTaskWorkGroupCount[1] = 65535; + caps->maxTaskWorkGroupCount[2] = 65535; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( + PalDevice* device, + PalRayTracingCapabilities* caps) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + // these are safe defaults. D3d12 does not expose them. + caps->maxRecursionDepth = 31; + caps->maxHitAttributeSize = 32; + caps->maxInstanceCount = 1000000; + caps->maxPrimitiveCount = 10000000; + caps->maxGeometryCount = 100000; + caps->maxPayloadSize = 64; + caps->maxDispatchInvocations = 16000000; + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps) +{ + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + caps->flags = PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING; + caps->flags |= PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; + getDescriptorTierLimitsD3D12(d3d12Device->handle, nullptr, caps); + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL createQueueD3D12( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue) +{ + HRESULT result; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + QueueD3D12* queue = nullptr; + D3D12_COMMAND_QUEUE_DESC desc = {0}; + + switch (type) { + case PAL_QUEUE_TYPE_COMPUTE: { + desc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; + + if (!d3d12Device->limits.freeComputeQueues) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + d3d12Device->limits.freeComputeQueues--; + break; + } + + case PAL_QUEUE_TYPE_GRAPHICS: { + desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + + if (!d3d12Device->limits.freeGraphicsQueues) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + d3d12Device->limits.freeGraphicsQueues--; + break; + } + + case PAL_QUEUE_TYPE_COPY: { + desc.Type = D3D12_COMMAND_LIST_TYPE_COPY; + + if (!d3d12Device->limits.freeCopyQueues) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + d3d12Device->limits.freeCopyQueues--; + break; + } + } + + queue = palAllocate(s_D3D12.allocator, sizeof(QueueD3D12), 0); + if (!queue) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + result = d3d12Device->handle->lpVtbl->CreateCommandQueue( + d3d12Device->handle, + &desc, + &IID_Queue, + (void**)&queue->handle); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + palFree(s_D3D12.allocator, queue); + return makeResultD3D12(result); + } + + // create fence used for queue wait + result = d3d12Device->handle->lpVtbl->CreateFence( + d3d12Device->handle, + 0, + 0, + &IID_Fence, + (void**)&queue->fence); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + palFree(s_D3D12.allocator, queue); + return makeResultD3D12(result); + } + + // create event + queue->fenceEvent = CreateEvent(nullptr, PAL_FALSE, PAL_FALSE, nullptr); + if (!queue->fenceEvent) { + return palMakeResult( + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, + GetLastError()); + } + + queue->fenceValue = 0; + queue->type = type; + queue->reserved = PAL_BACKEND_KEY; + *outQueue = (PalQueue*)queue; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyQueueD3D12(PalQueue* queue) +{ + QueueD3D12* d3d12Queue = (QueueD3D12*)queue; + d3d12Queue->fence->lpVtbl->Release(d3d12Queue->fence); + d3d12Queue->handle->lpVtbl->Release(d3d12Queue->handle); + CloseHandle(d3d12Queue->fenceEvent); + palFree(s_D3D12.allocator, d3d12Queue); +} + +PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) +{ + QueueD3D12* d3d12Queue = (QueueD3D12*)queue; + ID3D12Fence* fence = d3d12Queue->fence; + HANDLE event = d3d12Queue->fenceEvent; + + // wait on the fence if the submited work is not done + if (fence->lpVtbl->GetCompletedValue(fence) < d3d12Queue->fenceValue) { + fence->lpVtbl->SetEventOnCompletion(fence, d3d12Queue->fenceValue, event); + WaitForSingleObject(event, INFINITE); + CloseHandle(event); + } + return PAL_RESULT_SUCCESS; +} + +PalBool PAL_CALL canQueuePresentD3D12( + PalQueue* queue, + PalSurface* surface) +{ + QueueD3D12* d3d12Queue = (QueueD3D12*)queue; + if (d3d12Queue->type == PAL_QUEUE_TYPE_GRAPHICS) { + return PAL_TRUE; // all graphics queues support presentation + } + return PAL_FALSE; +} + +PalResult PAL_CALL createShaderD3D12( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader) +{ + ShaderD3D12* shader = nullptr; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + void* bytecode = nullptr; + + shader = palAllocate(s_D3D12.allocator, sizeof(ShaderD3D12), 0); + bytecode = palAllocate(s_D3D12.allocator, info->bytecodeSize, 0); + if (!shader || !bytecode) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + // allocate entries array + shader->entries = palAllocate(s_D3D12.allocator, sizeof(ShaderEntry) * info->entryCount, 0); + if (!shader->entries) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + for (int i = 0; i < info->entryCount; i++) { + ShaderEntry* entry = &shader->entries[i]; + + // clang-format off + if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || + info->entries[i].stage == PAL_SHADER_STAGE_TASK) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + } else if (info->entries[i].stage == PAL_SHADER_STAGE_GEOMETRY) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + } else if (info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || + info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + + } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || + info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || + info->entries[i].stage == PAL_SHADER_STAGE_MISS || + info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || + info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + } + } + // clang-format on + + convertToWcharD3D12(info->entries[i].entryName, entry->entryName); + entry->patchControlPoints = info->entries[i].patchControlPoints; + entry->stage = info->entries[i].stage; + } + + memcpy(bytecode, info->bytecode, info->bytecodeSize); + shader->byteCode.pShaderBytecode = bytecode; + shader->byteCode.BytecodeLength = info->bytecodeSize; + + shader->entryCount = info->entryCount; + *outShader = (PalShader*)shader; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyShaderD3D12(PalShader* shader) +{ + ShaderD3D12* d3dShader = (ShaderD3D12*)shader; + palFree(s_D3D12.allocator, (void*)d3dShader->byteCode.pShaderBytecode); + palFree(s_D3D12.allocator, d3dShader->entries); + palFree(s_D3D12.allocator, d3dShader); +} #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_image_d3d12.c b/src/graphics/d3d12/pal_image_d3d12.c index 31b70783..3c361eea 100644 --- a/src/graphics/d3d12/pal_image_d3d12.c +++ b/src/graphics/d3d12/pal_image_d3d12.c @@ -6,6 +6,311 @@ */ #if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" +PalResult PAL_CALL createImageD3D12( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage) +{ + HRESULT result; + Image* image = nullptr; + Device* d3d12Device = (Device*)device; + + image = palAllocate(s_D3D12.allocator, sizeof(Image), 0); + if (!image) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(image, 0, sizeof(Image)); + image->desc.Width = (UINT64)info->width; + image->desc.Height = (UINT64)info->height; + image->desc.DepthOrArraySize = (UINT16)info->depthOrArraySize; + image->desc.MipLevels = (UINT16)info->mipLevelCount; + image->desc.Format = formatToD3D12(info->format); + image->desc.SampleDesc.Count = samplesToD3D12(info->sampleCount); + image->desc.SampleDesc.Quality = 0; + + image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + if (info->type == PAL_IMAGE_TYPE_3D) { + image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + + } else if (info->type == PAL_IMAGE_TYPE_1D) { + image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D; + } + + if (info->usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { + image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + } + + if (info->usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { + image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + } + + if (info->usages & PAL_IMAGE_USAGE_STORAGE) { + image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + } + + image->belongsToSwapchain = PAL_FALSE; + image->info.depthOrArraySize = info->depthOrArraySize; + image->info.type = info->type; + image->info.format = info->format; + image->info.usages = info->usages; + image->info.height = info->height; + image->info.mipLevelCount = info->mipLevelCount; + image->info.sampleCount = info->sampleCount; + image->info.width = info->width; + + image->device = d3d12Device; + *outImage = (PalImage*)image; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyImageD3D12(PalImage* image) +{ + Image* d3dImage = (Image*)image; + // check if memory has been attached to the image + if (d3dImage->handle) { + d3dImage->handle->lpVtbl->Release(d3dImage->handle); + } + palFree(s_D3D12.allocator, d3dImage); +} + +PalResult PAL_CALL getImageInfoD3D12( + PalImage* image, + PalImageInfo* info) +{ + Image* d3dImage = (Image*)image; + *info = d3dImage->info; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL getImageMemoryRequirementsD3D12( + PalImage* image, + PalMemoryRequirements* requirements) +{ + Image* d3dImage = (Image*)image; + ID3D12Device5* device = d3dImage->device->handle; + if (d3dImage->belongsToSwapchain) { + return PAL_RESULT_INVALID_OPERATION; + } + + D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; + D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; + allocationInfo = *device->lpVtbl->GetResourceAllocationInfo( + device, + &__ret, + 0, + 1, + &d3dImage->desc); + + // d3d12 allows images to be used with only GPU only heap + requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = PAL_TRUE; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = PAL_FALSE; + requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = PAL_FALSE; + + requirements->alignment = allocationInfo.Alignment; + requirements->size = allocationInfo.SizeInBytes; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL bindImageMemoryD3D12( + PalImage* image, + PalMemory* memory, + uint64_t offset) +{ + HRESULT result; + Image* d3dImage = (Image*)image; + ID3D12Device5* device = d3dImage->device->handle; + if (d3dImage->belongsToSwapchain) { + return PAL_RESULT_INVALID_OPERATION; + } + + ID3D12Heap* mem = (ID3D12Heap*)memory; + result = device->lpVtbl->CreatePlacedResource( + device, + mem, + offset, + &d3dImage->desc, + 0, + nullptr, + &IID_Resource, + (void**)&d3dImage->handle); + + if (FAILED(result)) { + pollMessagesD3D12(d3dImage->device); + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } else if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + return PAL_RESULT_SUCCESS; +} + +// ================================================== +// Image View +// ================================================== + +PalResult PAL_CALL createImageViewD3D12( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView) +{ + HRESULT result; + ImageView* imageView = nullptr; + Device* d3d12Device = (Device*)device; + Image* d3dImage = (Image*)image; + + if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + } + + imageView = palAllocate(s_D3D12.allocator, sizeof(ImageView), 0); + if (!imageView) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + imageView->heapIndex = UINT32_MAX; + PalBool hasRTV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); + PalBool hasDSV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); + + imageView->format = formatToD3D12(info->format); + if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR && hasRTV) { + RTVHeapAllocator* allocator = &d3d12Device->rtvAllocator; + uint32_t index = allocator->freeTop; + allocator->freeTop = allocator->freeList[index]; + + D3D12_CPU_DESCRIPTOR_HANDLE dst; + dst.ptr = getDescriptorHandleD3D12(index, allocator->incrementSize, allocator->baseOffset); + + D3D12_RENDER_TARGET_VIEW_DESC desc = {0}; + desc.Format = imageView->format; + fillSubresourceD3D12( + info->type, + &info->subresourceRange, + &desc, + nullptr, + nullptr, + nullptr); + + imageView->heapIndex = index; + d3d12Device->handle->lpVtbl->CreateRenderTargetView( + d3d12Device->handle, + d3dImage->handle, + &desc, + dst); + + } else if (info->subresourceRange.aspect != PAL_IMAGE_ASPECT_COLOR && hasDSV) { + DSVHeapAllocator* allocator = &d3d12Device->dsvAllocator; + uint32_t index = allocator->freeTop; + allocator->freeTop = allocator->freeList[index]; + + D3D12_CPU_DESCRIPTOR_HANDLE dst; + dst.ptr = getDescriptorHandleD3D12(index, allocator->incrementSize, allocator->baseOffset); + + D3D12_DEPTH_STENCIL_VIEW_DESC desc = {0}; + desc.Format = imageView->format; + fillSubresourceD3D12( + info->type, + &info->subresourceRange, + nullptr, + &desc, + nullptr, + nullptr); + + imageView->heapIndex = index; + d3d12Device->handle->lpVtbl->CreateDepthStencilView( + d3d12Device->handle, + d3dImage->handle, + &desc, + dst); + } + + imageView->range = info->subresourceRange; + imageView->type = info->type; + imageView->image = d3dImage; + + imageView->device = d3d12Device; + *outImageView = (PalImageView*)imageView; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) +{ + ImageView* d3dImageView = (ImageView*)imageView; + Device* device = d3dImageView->device; + RTVHeapAllocator* allocator = nullptr; + + if (d3dImageView->heapIndex != UINT32_MAX) { + if (d3dImageView->range.aspect == PAL_IMAGE_ASPECT_COLOR) { + RTVHeapAllocator* allocator = &device->rtvAllocator; + allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; + allocator->freeTop = d3dImageView->heapIndex; + + } else { + DSVHeapAllocator* allocator = &device->dsvAllocator; + allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; + allocator->freeTop = d3dImageView->heapIndex; + } + } + palFree(s_D3D12.allocator, d3dImageView); +} + +PalResult PAL_CALL createSamplerD3D12( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler) +{ + Device* d3d12Device = (Device*)device; + if (info->maxAnisotropy > d3d12Device->limits.maxAnisotropy) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + Sampler* sampler = nullptr; + sampler = palAllocate(s_D3D12.allocator, sizeof(Sampler), 0); + if (!sampler) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(sampler, 0, sizeof(Sampler)); + sampler->desc.MaxLOD = info->maxLod; + sampler->desc.MinLOD = info->minLod; + sampler->desc.MipLODBias = info->mipLodBias; + + sampler->desc.MaxAnisotropy = 1; + if (info->enableAnisotropy) { + sampler->desc.MaxAnisotropy = (UINT)info->maxAnisotropy; + } + + sampler->desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; + if (info->enableCompare) { + sampler->desc.ComparisonFunc = compareOpToD3D12(info->compareOp); + } + + borderColorToD3D12(info->borderColor, sampler->desc.BorderColor); + sampler->desc.AddressU = addressModeToD3D12(info->addressModeU); + sampler->desc.AddressV = addressModeToD3D12(info->addressModeV); + sampler->desc.AddressW = addressModeToD3D12(info->addressModeW); + + sampler->desc.Filter = filterToD3D12( + info->minFilterMode, + info->magFilterMode, + info->mipmapMode); + + *outSampler = (PalSampler*)sampler; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroySamplerD3D12(PalSampler* sampler) +{ + Sampler* d3dSampler = (Sampler*)sampler; + palFree(s_D3D12.allocator, d3dSampler); +} #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_pipeline_d3d12.c b/src/graphics/d3d12/pal_pipeline_d3d12.c index 31b70783..cc319a61 100644 --- a/src/graphics/d3d12/pal_pipeline_d3d12.c +++ b/src/graphics/d3d12/pal_pipeline_d3d12.c @@ -6,6 +6,1131 @@ */ #if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" +PalResult PAL_CALL createPipelineLayoutD3D12( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout) +{ + Device* d3d12Device = (Device*)device; + PipelineLayout* layout = nullptr; + uint32_t resourceCount = 0; + uint32_t samplerCount = 0; + uint64_t pushConstantSize = 0; + uint32_t sizeInBytes = sizeof(D3D12_DESCRIPTOR_RANGE1); + + uint32_t rangesOffset = 0; + uint32_t samplerRangesOffset = 0; + D3D12_DESCRIPTOR_RANGE1* ranges = nullptr; + D3D12_DESCRIPTOR_RANGE1* samplerRanges = nullptr; + + uint32_t parameterCount = 0; + D3D12_ROOT_PARAMETER1* parameters = nullptr; + D3D12_ROOT_SIGNATURE_FLAGS rootFlags = 0; + rootFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + if (info->descriptorSetLayoutCount > d3d12Device->limits.maxBoundDescriptorSets) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (d3d12Device->shaderModel >= PAL_MAKE_SHADER_TARGET(6, 6)) { + rootFlags |= D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED; + rootFlags |= D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED; + } + + // get the total resource and sampler ranges for all provided descriptor set layouts + for (int i = 0; i < info->descriptorSetLayoutCount; i++) { + DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; + resourceCount += tmp->bindingCount - tmp->samplerCount; + samplerCount += tmp->samplerCount; + + if (tmp->bindingCount - tmp->samplerCount >= 1) { + parameterCount++; + } + + if (tmp->samplerCount >= 1) { + parameterCount++; + } + } + + // get the total size needed for all provided push constant range + for (int i = 0; i < info->pushConstantRangeCount; i++) { + PalPushConstantRange* tmp = &info->pushConstantRanges[i]; + if (tmp->offset + tmp->size > pushConstantSize) { + pushConstantSize = tmp->offset + tmp->size; + } + } + + if (pushConstantSize > d3d12Device->limits.maxPushConstantSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + layout = palAllocate(s_D3D12.allocator, sizeof(PipelineLayout), 0); + if (!layout) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + if (pushConstantSize) { + parameterCount++; + } + + if (parameterCount) { + uint32_t paramtersSize = sizeof(D3D12_ROOT_PARAMETER1) * parameterCount; + parameters = palAllocate(s_D3D12.allocator, paramtersSize, 0); + if (!parameters) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + memset(parameters, 0, paramtersSize); + } + + if (resourceCount) { + ranges = palAllocate(s_D3D12.allocator, sizeInBytes * resourceCount, 0); + if (!ranges) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } + + if (samplerCount) { + samplerRanges = palAllocate(s_D3D12.allocator, sizeInBytes * samplerCount, 0); + if (!samplerRanges) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } + + // write root constant first if its provided + parameterCount = 0; // reset and reuse the same variable + layout->constantIndex = UINT32_MAX; + if (pushConstantSize) { + D3D12_ROOT_PARAMETER1* parameter = ¶meters[parameterCount]; + parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + parameter->Constants.Num32BitValues = (UINT)pushConstantSize / 4; + parameter->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + layout->constantIndex = parameterCount; + parameterCount++; + } + + uint32_t registerSpace = 0; + for (int i = 0; i < info->descriptorSetLayoutCount; i++) { + DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; + D3D12_ROOT_PARAMETER1* parameter = nullptr; + + // reset and reuse same variable + resourceCount = tmp->bindingCount - tmp->samplerCount; + samplerCount = tmp->samplerCount; + + uint32_t samplerIndex = samplerRangesOffset; + uint32_t rangeIndex = rangesOffset; + + // seperate the samplers from the remaining descriptors + for (int j = 0; j < tmp->bindingCount; j++) { + DescriptorSetBinding* binding = &tmp->bindings[j]; + D3D12_DESCRIPTOR_RANGE1* tmpRange = nullptr; + + if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { + tmpRange = &samplerRanges[samplerIndex++]; + } else { + tmpRange = &ranges[rangeIndex++]; + } + + *tmpRange = binding->range; + tmpRange->RegisterSpace = registerSpace; + } + + // resource ranges + if (resourceCount) { + parameter = ¶meters[parameterCount]; + parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + parameter->DescriptorTable.NumDescriptorRanges = resourceCount; + parameter->DescriptorTable.pDescriptorRanges = &ranges[rangesOffset]; + parameter->ShaderVisibility = tmp->visibility; + + rangesOffset += resourceCount; + parameterCount++; + } + + // sampler ranges + if (samplerCount) { + parameter = ¶meters[parameterCount]; + parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + parameter->DescriptorTable.NumDescriptorRanges = samplerCount; + parameter->DescriptorTable.pDescriptorRanges = &samplerRanges[samplerRangesOffset]; + parameter->ShaderVisibility = tmp->visibility; + + samplerRangesOffset += samplerCount; + parameterCount++; + } + + registerSpace++; + } + + // create root signature + D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; + rootDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; + rootDesc.Desc_1_1.NumParameters = parameterCount; + rootDesc.Desc_1_1.pParameters = parameters; + rootDesc.Desc_1_1.Flags = rootFlags; + + ID3DBlob* blob = nullptr; + HRESULT result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + result = d3d12Device->handle->lpVtbl->CreateRootSignature( + d3d12Device->handle, + 0, + blob->lpVtbl->GetBufferPointer(blob), + blob->lpVtbl->GetBufferSize(blob), + &IID_RootSignature, + (void**)&layout->handle); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + if (resourceCount) { + palFree(s_D3D12.allocator, ranges); + } + + if (samplerCount) { + palFree(s_D3D12.allocator, samplerRanges); + } + + if (parameterCount) { + palFree(s_D3D12.allocator, parameters); + } + + blob->lpVtbl->Release(blob); + *outLayout = (PalPipelineLayout*)layout; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout) +{ + PipelineLayout* d3d12Layout = (PipelineLayout*)layout; + d3d12Layout->handle->lpVtbl->Release(d3d12Layout->handle); + palFree(s_D3D12.allocator, d3d12Layout); +} + +// ================================================== +// Pipeline +// ================================================== + +PalResult PAL_CALL createGraphicsPipelineD3D12( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + HRESULT result; + uint32_t patchControlPoints = 0; + uint32_t totalSize = 0; + PalBool alphaToCoverageEnable = PAL_FALSE; + Pipeline* pipeline = nullptr; + Device* d3d12Device = (Device*)device; + PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; + + D3D12_INPUT_ELEMENT_DESC* elementDescs = nullptr; + D3D12_VIEW_INSTANCE_LOCATION* viewLocations = nullptr; + + GraphicsPipelineStreamDesc graphicsStreamDesc = {0}; + memset(&graphicsStreamDesc, 0, sizeof(GraphicsPipelineStreamDesc)); + + pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); + if (!pipeline) { + return PAL_RESULT_OUT_OF_MEMORY; + } + memset(pipeline, 0, sizeof(Pipeline)); + + if (info->renderingLayout->viewCount > 1) { + viewLocations = palAllocate( + s_D3D12.allocator, + sizeof(D3D12_VIEW_INSTANCE_LOCATION) * info->renderingLayout->viewCount, + 0); + + if (!viewLocations) { + return PAL_RESULT_OUT_OF_MEMORY; + } + } + + // Root signature + RootSignatureStream* rootSignatureStream = &graphicsStreamDesc.layout; + totalSize += sizeof(RootSignatureStream); + rootSignatureStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE; + rootSignatureStream->root = layout->handle; + + // shaders + for (int i = 0; i < info->shaderCount; i++) { + Shader* tmp = (Shader*)info->shaders[i]; + ShaderStream* shaderStream = &graphicsStreamDesc.shaders[i]; + totalSize += sizeof(ShaderStream); + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + + ShaderEntry* entry = &tmp->entries[0]; + if (entry->patchControlPoints) { + patchControlPoints = entry->patchControlPoints; + if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { + palFree(s_D3D12.allocator, pipeline); + return PAL_RESULT_INVALID_OPERATION; + } + } + + if (entry->stage == PAL_SHADER_STAGE_VERTEX) { + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS; + + } else if (entry->stage == PAL_SHADER_STAGE_FRAGMENT) { + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS; + + } else if (entry->stage == PAL_SHADER_STAGE_GEOMETRY) { + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS; + + } else if (entry->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS; + + } else if (entry->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS; + + } else if (entry->stage == PAL_SHADER_STAGE_TASK) { + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS; + + } else { + // mesh shader + type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS; + } + + shaderStream->type = type; + shaderStream->desc = tmp->byteCode; + } + + // Vertex input state + // get the max size of vertex attributes in all layouts + uint32_t vertexCount = 0; + uint32_t vertexLayoutCount = info->vertexLayoutCount; + for (int i = 0; i < vertexLayoutCount; i++) { + PalVertexLayout* layout = &info->vertexLayouts[i]; + vertexCount += layout->attributeCount; + } + + if (info->vertexLayoutCount > d3d12Device->limits.maxVertexLayouts) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (vertexCount > d3d12Device->limits.maxVertexAttributes) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + InputLayoutStream* inputLayoutStream = &graphicsStreamDesc.inputLayout; + totalSize += sizeof(InputLayoutStream); + inputLayoutStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT; + + pipeline->strides = nullptr; + if (vertexCount) { + pipeline->strides = palAllocate(s_D3D12.allocator, sizeof(uint32_t) * 8, 0); + if (!pipeline->strides) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + elementDescs = palAllocate( + s_D3D12.allocator, + sizeof(D3D12_INPUT_ELEMENT_DESC) * vertexCount, + 0); + + if (!elementDescs) { + palFree(s_D3D12.allocator, elementDescs); + return PAL_RESULT_OUT_OF_MEMORY; + } + + uint32_t positionIndex = 0; + uint32_t colorIndex = 0; + uint32_t texCoordIndex = 0; + uint32_t normalIndex = 0; + uint32_t tangentIndex = 0; + + for (int i = 0; i < info->vertexLayoutCount; i++) { + PalVertexLayout* layout = &info->vertexLayouts[i]; + uint32_t stride = 0; + uint32_t offset = 0; + + for (int j = 0; j < layout->attributeCount; j++) { + PalVertexAttribute* vertexAttrib = &layout->attributes[j]; + D3D12_INPUT_ELEMENT_DESC* elementDesc = &elementDescs[j]; + + elementDesc->Format = vertexTypeToD3D12(vertexAttrib->type); + elementDesc->InputSlot = layout->binding; + if (vertexAttrib->semanticName) { + elementDesc->SemanticName = vertexAttrib->semanticName; + } else { + elementDesc->SemanticName = semanticIDToStringD3D12(vertexAttrib->semanticID); + } + + if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_POSITION) { + elementDesc->SemanticIndex = positionIndex++; + + } else if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_COLOR) { + elementDesc->SemanticIndex = colorIndex++; + + } else if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_TEXCOORD) { + elementDesc->SemanticIndex = texCoordIndex++; + + } else if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_NORMAL) { + elementDesc->SemanticIndex = normalIndex++; + + } else { + // tangent + elementDesc->SemanticIndex = tangentIndex++; + } + + if (layout->type == PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE) { + elementDesc->InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA; + elementDesc->InstanceDataStepRate = 1; + } else { + elementDesc->InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; + elementDesc->InstanceDataStepRate = 0; + } + + // build offsets and stride + uint32_t size = getVertexTypeSizeD3D12(vertexAttrib->type); + elementDesc->AlignedByteOffset = offset; + offset += size; + stride += size; + } + + // cache the computed stride to be used later by the vertex buffer + pipeline->strides[i] = stride; + } + + inputLayoutStream->desc.NumElements = vertexCount; + inputLayoutStream->desc.pInputElementDescs = elementDescs; + } + + // Primitive Topology + D3D12_PRIMITIVE_TOPOLOGY_TYPE topologyType = 0; + D3D_PRIMITIVE_TOPOLOGY topology = 0; + switch (info->topology) { + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_LIST: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_POINT_LIST: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; + topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; + break; + } + + case PAL_PRIMITIVE_TOPOLOGY_PATCH: { + topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH; + topology = getPatchTopology(patchControlPoints); + break; + } + } + + TopologyStream* topologyStream = &graphicsStreamDesc.topology; + totalSize += sizeof(TopologyStream); + topologyStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY; + topologyStream->topology = topologyType; + + // IB Strip Cut + IBStripCutStream* inStripCutStream = &graphicsStreamDesc.ibStripCut; + totalSize += sizeof(IBStripCutStream); + inStripCutStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE; + if (info->primitiveRestartEnable == PAL_FALSE) { + inStripCutStream->value = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + + } else { + if (info->indexType == PAL_INDEX_TYPE_UINT16) { + inStripCutStream->value = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; + } else { + inStripCutStream->value = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF; + } + } + + // Rasterizer + RasterizerStream* rasterizerStream = &graphicsStreamDesc.rasterizer; + totalSize += sizeof(RasterizerStream); + rasterizerStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER; + + rasterizerStream->desc.CullMode = D3D12_CULL_MODE_NONE; + rasterizerStream->desc.FillMode = D3D12_FILL_MODE_SOLID; + rasterizerStream->desc.FrontCounterClockwise = PAL_FALSE; + rasterizerStream->desc.DepthClipEnable = TRUE; + + if (info->rasterizerState) { + PalRasterizerState* state = info->rasterizerState; + if (state->cullMode == PAL_CULL_MODE_NONE) { + rasterizerStream->desc.CullMode = D3D12_CULL_MODE_NONE; + + } else if (state->cullMode == PAL_CULL_MODE_BACK) { + rasterizerStream->desc.CullMode = D3D12_CULL_MODE_BACK; + + } else if (state->cullMode == PAL_CULL_MODE_FRONT) { + rasterizerStream->desc.CullMode = D3D12_CULL_MODE_FRONT; + } + + if (state->polygonMode == PAL_POLYGON_MODE_FILL) { + rasterizerStream->desc.FillMode = D3D12_FILL_MODE_SOLID; + + } else { + rasterizerStream->desc.FillMode = D3D12_FILL_MODE_WIREFRAME; + } + + if (state->frontFace == PAL_FRONT_FACE_CLOCKWISE) { + rasterizerStream->desc.FrontCounterClockwise = PAL_FALSE; + + } else { + rasterizerStream->desc.FrontCounterClockwise = TRUE; + } + + rasterizerStream->desc.DepthClipEnable = !state->enableDepthClamp; + rasterizerStream->desc.DepthBias = (INT)state->depthBiasConstant; + rasterizerStream->desc.SlopeScaledDepthBias = state->depthBiasSlope; + rasterizerStream->desc.DepthBiasClamp = state->depthBiasClamp; + } + + // Sample Desc + SampleDescStream* sampleDescStream = &graphicsStreamDesc.sampleDesc; + totalSize += sizeof(SampleDescStream); + sampleDescStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC; + sampleDescStream->desc.Quality = 0; + sampleDescStream->desc.Count = 1; + + // Sample Mask + SampleMaskStream* sampleMaskStream = &graphicsStreamDesc.sampleMask; + totalSize += sizeof(SampleMaskStream); + sampleMaskStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK; + sampleMaskStream->mask = UINT_MAX; + + if (info->multisampleState) { + PalMultisampleState* state = info->multisampleState; + if (state->sampleMask) { + sampleMaskStream->mask = (UINT)state->sampleMask; + } + + sampleDescStream->desc.Count = samplesToD3D12(state->sampleCount); + alphaToCoverageEnable = state->enableAlphaToCoverage; + } + + // Depth stencil + DepthStencilStream* depthStencilStream = &graphicsStreamDesc.depthStencil; + totalSize += sizeof(DepthStencilStream); + depthStencilStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL; + depthStencilStream->desc.DepthEnable = PAL_FALSE; + depthStencilStream->desc.StencilEnable = PAL_FALSE; + + if (info->depthStencilState) { + PalDepthStencilState* state = info->depthStencilState; + PalStencilOpState* back = &state->backStencilOpState; + PalStencilOpState* front = &state->frontStencilOpState; + + D3D12_DEPTH_STENCILOP_DESC* d3dBack = &depthStencilStream->desc.BackFace; + D3D12_DEPTH_STENCILOP_DESC* d3dFront = &depthStencilStream->desc.FrontFace; + + d3dBack->StencilFunc = compareOpToD3D12(back->compareOp); + d3dBack->StencilDepthFailOp = stencilOpToD3D12(back->depthFailOp); + d3dBack->StencilFailOp = stencilOpToD3D12(back->failOp); + d3dBack->StencilPassOp = stencilOpToD3D12(back->passOp); + + d3dFront->StencilFunc = compareOpToD3D12(front->compareOp); + d3dFront->StencilDepthFailOp = stencilOpToD3D12(front->depthFailOp); + d3dFront->StencilFailOp = stencilOpToD3D12(front->failOp); + d3dFront->StencilPassOp = stencilOpToD3D12(front->passOp); + + depthStencilStream->desc.DepthFunc = compareOpToD3D12(state->compareOp); + depthStencilStream->desc.DepthEnable = state->enableDepthTest; + depthStencilStream->desc.StencilEnable = state->enableStencilTest; + if (state->enableDepthWrite) { + depthStencilStream->desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + } else { + depthStencilStream->desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + } + } + + // Blend + BlendStream* blendStream = &graphicsStreamDesc.blend; + totalSize += sizeof(BlendStream); + blendStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND; + blendStream->desc.IndependentBlendEnable = TRUE; + blendStream->desc.AlphaToCoverageEnable = alphaToCoverageEnable; + + if (info->colorBlendAttachmentCount) { + for (int i = 0; i < info->colorBlendAttachmentCount; i++) { + D3D12_RENDER_TARGET_BLEND_DESC* tmp = &blendStream->desc.RenderTarget[i]; + PalColorBlendAttachment* desc = &info->colorBlendAttachments[i]; + + tmp->BlendEnable = desc->enableBlend; + tmp->BlendOpAlpha = blendOpToD3D12(desc->alphaBlendOp); + tmp->BlendOp = blendOpToD3D12(desc->colorBlendOp); + + tmp->SrcBlendAlpha = blendFactorToD3D12(desc->srcAlphaBlendFactor); + tmp->SrcBlend = blendFactorToD3D12(desc->srcColorBlendFactor); + + tmp->DestBlendAlpha = blendFactorToD3D12(desc->dstAlphaBlendFactor); + tmp->DestBlend = blendFactorToD3D12(desc->dstColorBlendFactor); + + // blend color write mask + tmp->RenderTargetWriteMask = 0; + if (desc->colorWriteMask & PAL_COLOR_MASK_RED) { + tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_GREEN) { + tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_GREEN; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_BLUE) { + tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_BLUE; + } + + if (desc->colorWriteMask & PAL_COLOR_MASK_ALPHA) { + tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA; + } + } + } + + // Fragment shading rate + pipeline->hasFsr = PAL_FALSE; + if (info->fragmentShadingRateState) { + PalFragmentShadingRateState* state = info->fragmentShadingRateState; + pipeline->shadingRate = shadingRateToD3D12(state->rate); + for (int i = 0; i < 2; i++) { + pipeline->combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); + } + } + + // RTV Formats + RTVStream* rtvStream = &graphicsStreamDesc.RTV; + totalSize += sizeof(RTVStream); + rtvStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS; + + DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; + rtvStream->data.NumRenderTargets = info->renderingLayout->colorAttachentCount; + for (int i = 0; i < info->renderingLayout->colorAttachentCount; i++) { + format = formatToD3D12(info->renderingLayout->colorAttachmentsFormat[i]); + rtvStream->data.RTFormats[i] = format; + } + + // DSV Format + DSVStream* dsvStream = &graphicsStreamDesc.DSV; + totalSize += sizeof(DSVStream); + dsvStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT; + dsvStream->format = formatToD3D12(info->renderingLayout->depthStencilAttachmentFormat); + + // View Instancing + ViewInstancingStream* viewInstacingStream = &graphicsStreamDesc.viewInstancing; + totalSize += sizeof(ViewInstancingStream); + viewInstacingStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING; + + viewInstacingStream->desc.ViewInstanceCount = 0; + viewInstacingStream->desc.pViewInstanceLocations = nullptr; + if (info->renderingLayout->viewCount > 1) { + for (int i = 0; i < info->renderingLayout->viewCount; i++) { + viewLocations[i].RenderTargetArrayIndex = i; + viewLocations[i].ViewportArrayIndex = i; + } + + viewInstacingStream->desc.ViewInstanceCount = info->renderingLayout->viewCount; + viewInstacingStream->desc.pViewInstanceLocations = viewLocations; + } + + D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {0}; + streamDesc.pPipelineStateSubobjectStream = &graphicsStreamDesc; + streamDesc.SizeInBytes = totalSize; + + result = d3d12Device->handle->lpVtbl->CreatePipelineState( + d3d12Device->handle, + &streamDesc, + &IID_PipelineState, + &pipeline->handle); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + if (info->vertexLayoutCount) { + palFree(s_D3D12.allocator, elementDescs); + } + + if (info->renderingLayout->viewCount > 1) { + palFree(s_D3D12.allocator, viewLocations); + } + + pipeline->topology = topology; + pipeline->type = GRAPHICS_PIPELINE; + pipeline->layout = layout; + pipeline->shaderExports = nullptr; + pipeline->localRootSignature = nullptr; + + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL createComputePipelineD3D12( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + Device* d3d12Device = (Device*)device; + PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; + Shader* shader = (Shader*)info->computeShader; + Pipeline* pipeline = nullptr; + + pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); + if (!pipeline) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + D3D12_COMPUTE_PIPELINE_STATE_DESC desc = {0}; + desc.CS = shader->byteCode; + desc.pRootSignature = layout->handle; + + HRESULT result = d3d12Device->handle->lpVtbl->CreateComputePipelineState( + d3d12Device->handle, + &desc, + &IID_PipelineState, + &pipeline->handle); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + pipeline->type = COMPUTE_PIPELINE; + pipeline->strides = nullptr; + pipeline->hasFsr = PAL_FALSE; + pipeline->layout = layout; + pipeline->shaderExports = nullptr; + pipeline->localRootSignature = nullptr; + + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL createRayTracingPipelineD3D12( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline) +{ + HRESULT result; + Device* d3d12Device = (Device*)device; + PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; + Pipeline* pipeline = nullptr; + + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + if (info->maxAttributeSize > d3d12Device->limits.maxHitAttributeSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (info->maxPayloadSize > d3d12Device->limits.maxPayloadSize) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (info->maxRecursionDepth> d3d12Device->limits.maxRecursionDepth) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + D3D12_EXPORT_DESC* exportDescs = nullptr; + D3D12_DXIL_LIBRARY_DESC* libraryDescs = nullptr; + RayHitGroup* hitGroups = nullptr; + D3D12_STATE_SUBOBJECT* subObjects = nullptr; + const wchar_t** localExports = nullptr; + + // find the total number of exports + uint32_t exportCount = 0; + for (int i = 0; i < info->shaderCount; i++) { + Shader* shader = (Shader*)info->shaders[i]; + exportCount += shader->entryCount; + } + + uint32_t subObjectCount = 0; + uint32_t localExportCount = 0; + ShaderBindingTableInfo sbtInfo = {0}; + + for (int i = 0; i < info->shaderGroupCount; i++) { + PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { + // check if its raygen, miss or callable + Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; + ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; + switch (entry->stage) { + case PAL_SHADER_STAGE_RAYGEN: { + sbtInfo.raygenCount++; + sbtInfo.raygenDataSize = max(sbtInfo.raygenDataSize, tmp->maxDataSize); + break; + } + + case PAL_SHADER_STAGE_MISS: { + sbtInfo.missCount++; + sbtInfo.missDataSize = max(sbtInfo.missDataSize, tmp->maxDataSize); + break; + } + + case PAL_SHADER_STAGE_CALLABLE: { + sbtInfo.callableCount++; + sbtInfo.callableDataSize = max(sbtInfo.callableDataSize, tmp->maxDataSize); + break; + } + } + + } else { + sbtInfo.hitDataSize = max(sbtInfo.hitDataSize, tmp->maxDataSize); + sbtInfo.hitCount++; + } + + if (tmp->maxDataSize) { + localExportCount++; + } + } + + // find the max data size across all shader groups + uint32_t localRootSize = 0; + localRootSize = max(localRootSize, sbtInfo.raygenDataSize); + localRootSize = max(localRootSize, sbtInfo.missDataSize); + localRootSize = max(localRootSize, sbtInfo.hitDataSize); + localRootSize = max(localRootSize, sbtInfo.callableDataSize); + + // // D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE + // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG + // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG + subObjectCount += info->shaderCount + 3; + + subObjectCount += sbtInfo.hitCount; + if (localRootSize) { + // D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE + // D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION + subObjectCount += 2; + } + + pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); + if (!pipeline) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + pipeline->shaderExportCount = exportCount + sbtInfo.hitCount; + subObjects = palAllocate(s_D3D12.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); + hitGroups = palAllocate(s_D3D12.allocator, sizeof(RayHitGroup) * sbtInfo.hitCount, 0); + if (!subObjects || !hitGroups) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + libraryDescs = palAllocate( + s_D3D12.allocator, + sizeof(D3D12_DXIL_LIBRARY_DESC) * info->shaderCount, + 0); + + exportDescs = palAllocate( + s_D3D12.allocator, + sizeof(D3D12_EXPORT_DESC) * exportCount, + 0); + + pipeline->shaderExports = palAllocate( + s_D3D12.allocator, + sizeof(ShaderExport) * pipeline->shaderExportCount, + 0); + + localExports = palAllocate( + s_D3D12.allocator, + sizeof(wchar_t*) * localExportCount, + 0); + + if (!libraryDescs || !exportDescs || !pipeline->shaderExports || !localExports) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // global root signature + uint32_t subObjectIndex = 0; + D3D12_GLOBAL_ROOT_SIGNATURE globalRootSignature = {0}; + globalRootSignature.pGlobalRootSignature = layout->handle; + + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE; + subObjects[subObjectIndex].pDesc = &globalRootSignature; + subObjectIndex++; + + // ray tracing config + D3D12_RAYTRACING_SHADER_CONFIG shaderConfig = {0}; + shaderConfig.MaxAttributeSizeInBytes = info->maxAttributeSize; + shaderConfig.MaxPayloadSizeInBytes = info->maxPayloadSize; + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG; + subObjects[subObjectIndex].pDesc = &shaderConfig; + subObjectIndex++; + + D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = {0}; + pipelineConfig.MaxTraceRecursionDepth = info->maxRecursionDepth; + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG; + subObjects[subObjectIndex].pDesc = &pipelineConfig; + subObjectIndex++; + + // shaders + uint32_t exportsOffset = 0; + for (int i = 0; i < info->shaderCount; i++) { + Shader* tmp = (Shader*)info->shaders[i]; + D3D12_DXIL_LIBRARY_DESC* libraryDesc = &libraryDescs[i]; + libraryDesc->DXILLibrary = tmp->byteCode; + + for (int j = 0; j < tmp->entryCount; j++) { + D3D12_EXPORT_DESC* exportDesc = &exportDescs[exportsOffset + j]; + ShaderExport* shaderExport = &pipeline->shaderExports[exportsOffset + j]; + ShaderEntry* entry = &tmp->entries[j]; + + shaderExport->isHitGroup = PAL_FALSE; + shaderExport->stage = entry->stage; + wcscpy(shaderExport->entryName, entry->entryName); + + exportDesc->ExportToRename = nullptr; + exportDesc->Flags = D3D12_EXPORT_FLAG_NONE; + exportDesc->Name = shaderExport->entryName; + } + + libraryDesc->pExports = &exportDescs[exportsOffset]; + libraryDesc->NumExports = tmp->entryCount; + + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; + subObjects[subObjectIndex].pDesc = libraryDesc; + subObjectIndex++; + exportsOffset += tmp->entryCount; + } + + // hit groups + uint32_t localExportIndex = 0; + uint32_t hitGroupIndex = 0; + for (int i = 0; i < info->shaderGroupCount; i++) { + const wchar_t* exportName = nullptr; + PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { + if (tmp->maxDataSize) { + Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; + ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; + localExports[localExportIndex++] = entry->entryName; + } + + continue; + } + + D3D12_HIT_GROUP_DESC* group = &hitGroups[hitGroupIndex].desc; + getHitGroupNameD3D12(hitGroupIndex, hitGroups[hitGroupIndex].entryName); + + ShaderExport* hitGroupExport = &pipeline->shaderExports[exportCount++]; + wcscpy(hitGroupExport->entryName, hitGroups[hitGroupIndex].entryName); + hitGroupExport->isHitGroup = PAL_TRUE; + hitGroupExport->stage = PAL_SHADER_STAGE_CLOSEST_HIT; // to identify + + group->AnyHitShaderImport = nullptr; + group->ClosestHitShaderImport = nullptr; + group->IntersectionShaderImport = nullptr; + group->HitGroupExport = hitGroups[hitGroupIndex].entryName; + + if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { + group->Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; + + } else if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT) { + group->Type = D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE; + } + + // Any hit shader + if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { + Shader* shader = (Shader*)info->shaders[tmp->anyHitShaderIndex]; + ShaderEntry* entry = &shader->entries[tmp->anyHitShaderEntryIndex]; + group->AnyHitShaderImport = entry->entryName; + + } else { + group->AnyHitShaderImport = nullptr; + } + + // Closest hit shader + if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { + Shader* shader = (Shader*)info->shaders[tmp->closestHitShaderIndex]; + ShaderEntry* entry = &shader->entries[tmp->closestHitShaderEntryIndex]; + group->ClosestHitShaderImport = entry->entryName; + + } else { + group->ClosestHitShaderImport = nullptr; + } + + // IntersectionShader shader + if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { + Shader* shader = (Shader*)info->shaders[tmp->intersectionShaderIndex]; + ShaderEntry* entry = &shader->entries[tmp->intersectionShaderEntryIndex]; + group->IntersectionShaderImport = entry->entryName; + + } else { + group->IntersectionShaderImport = nullptr; + } + + if (tmp->maxDataSize) { + localExports[localExportIndex] = group->HitGroupExport; + } + + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP; + subObjects[subObjectIndex].pDesc = group; + subObjectIndex++; + hitGroupIndex++; + localExportIndex++; + } + + // check if we need a local root signature + D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION localExportAssociation = {0}; + D3D12_LOCAL_ROOT_SIGNATURE localRootSignature = {0}; + if (localRootSize) { + D3D12_ROOT_PARAMETER1 parameter = {0}; + parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + parameter.Constants.Num32BitValues = alignD3D12(localRootSize, 4) / 4; + parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + + D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; + rootDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; + rootDesc.Desc_1_1.NumParameters = 1; + rootDesc.Desc_1_1.pParameters = ¶meter; + rootDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; + + ID3DBlob* blob = nullptr; + result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + result = d3d12Device->handle->lpVtbl->CreateRootSignature( + d3d12Device->handle, + 0, + blob->lpVtbl->GetBufferPointer(blob), + blob->lpVtbl->GetBufferSize(blob), + &IID_RootSignature, + (void**)&pipeline->localRootSignature); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + localRootSignature.pLocalRootSignature = pipeline->localRootSignature; + subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE; + subObjects[subObjectIndex].pDesc = &localRootSignature; + + localExportAssociation.pSubobjectToAssociate = &subObjects[subObjectIndex]; + localExportAssociation.pExports = localExports; + localExportAssociation.NumExports = localExportCount; + subObjectIndex++; + + D3D12_STATE_SUBOBJECT_TYPE t = D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION; + subObjects[subObjectIndex].Type = t; + subObjects[subObjectIndex].pDesc = &localExportAssociation; + subObjectIndex++; + } + + D3D12_STATE_OBJECT_DESC desc = {0}; + desc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; + desc.NumSubobjects = subObjectCount; + desc.pSubobjects = subObjects; + + result = d3d12Device->handle->lpVtbl->CreateStateObject( + d3d12Device->handle, + &desc, + &IID_StateObject, + &pipeline->handle); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } else if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + palFree(s_D3D12.allocator, hitGroups); + palFree(s_D3D12.allocator, subObjects); + palFree(s_D3D12.allocator, libraryDescs); + palFree(s_D3D12.allocator, exportDescs); + palFree(s_D3D12.allocator, localExports); + + pipeline->type = RAY_TRACING_PIPELINE; + pipeline->strides = nullptr; + pipeline->hasFsr = PAL_FALSE; + pipeline->layout = layout; + + pipeline->sbtInfo = sbtInfo; + *outPipeline = (PalPipeline*)pipeline; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) +{ + Pipeline* d3dPipeline = (Pipeline*)pipeline; + if (d3dPipeline->type == RAY_TRACING_PIPELINE) { + ID3D12StateObject* handle = d3dPipeline->handle; + handle->lpVtbl->Release(handle); + + } else { + ID3D12PipelineState* handle = d3dPipeline->handle; + handle->lpVtbl->Release(handle); + } + + if (d3dPipeline->localRootSignature) { + d3dPipeline->localRootSignature->lpVtbl->Release(d3dPipeline->localRootSignature); + } + + if (d3dPipeline->strides) { + palFree(s_D3D12.allocator, d3dPipeline->strides); + } + + if (d3dPipeline->shaderExports) { + palFree(s_D3D12.allocator, d3dPipeline->shaderExports); + } + + palFree(s_D3D12.allocator, d3dPipeline); +} #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_sbt_d3d12.c b/src/graphics/d3d12/pal_sbt_d3d12.c index 9032c814..9d8b95e0 100644 --- a/src/graphics/d3d12/pal_sbt_d3d12.c +++ b/src/graphics/d3d12/pal_sbt_d3d12.c @@ -10,11 +10,6 @@ #define align(v, a) (v + a - 1) & ~(a - 1) -// clang-format -const IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad}; -const IID IID_StateObjectProps = {0xde5fa827, 0x9bf9, 0x4f26, 0x89,0xff, 0xd7,0xf5,0x6f,0xde,0x38,0x60}; -// clang-format on - PalResult PAL_CALL createShaderBindingTableD3D12( PalDevice* device, const PalShaderBindingTableCreateInfo* info, @@ -78,7 +73,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // create SBT buffer ID3D12StateObject* handle = pipeline->handle; ID3D12StateObjectProperties* props = NULL; - result = ID3D12StateObject_QueryInterface(handle, &IID_StateObjectProps, (void**)&props); + result = handle->lpVtbl->QueryInterface(handle, &IID_StateObjectProps, (void**)&props); if (FAILED(result)) { pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); @@ -169,7 +164,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( bufferDesc.SampleDesc.Count = 1; bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - result = ID3D12Device5_CreateCommittedResource( + result = d3d12Device->handle->lpVtbl->CreateCommittedResource( d3d12Device->handle, &heapProps, 0, @@ -185,7 +180,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // create staging buffer heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - result = ID3D12Device5_CreateCommittedResource( + result = d3d12Device->handle->lpVtbl->CreateCommittedResource( d3d12Device->handle, &heapProps, 0, @@ -222,7 +217,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( } } - void* handle = ID3D12StateObjectProperties_GetShaderIdentifier(props, tmp->entryName); + void* handle = props->lpVtbl->GetShaderIdentifier(props, tmp->entryName); if (stage == PAL_SHADER_STAGE_RAYGEN) { raygenHandles[raygenIndex++] = handle; @@ -240,7 +235,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // copy handles into the buffer offset = 0; // reuse variable void* ptr = nullptr; - result = ID3D12Resource_Map(sbt->stagingBuffer, 0, nullptr, &ptr); + result = sbt->stagingBuffer->lpVtbl->Map(sbt->stagingBuffer, 0, nullptr, &ptr); if (FAILED(result)) { return makeResultD3D12(result); } @@ -296,8 +291,8 @@ PalResult PAL_CALL createShaderBindingTableD3D12( } } - ID3D12Resource_Unmap(sbt->stagingBuffer, 0, nullptr); - sbt->baseAddress = ID3D12Resource_GetGPUVirtualAddress(sbt->buffer); + sbt->stagingBuffer->lpVtbl->Unmap(sbt->stagingBuffer, 0, nullptr); + sbt->baseAddress = sbt->buffer->lpVtbl->GetGPUVirtualAddress(sbt->buffer); // raygen if (sbtInfo->raygenCount) { @@ -343,7 +338,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( palFree(s_D3D12.allocator, callableHandles); } - ID3D12StateObjectProperties_Release(props); + props->lpVtbl->Release(props); sbt->handleSize = groupHandleSize; sbt->stagingBufferSize = bufferSize; sbt->pipeline = pipeline; @@ -357,8 +352,8 @@ PalResult PAL_CALL createShaderBindingTableD3D12( void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) { ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; - ID3D12Resource_Release(d3d12Sbt->buffer); - ID3D12Resource_Release(d3d12Sbt->stagingBuffer); + d3d12Sbt->buffer->lpVtbl->Release(d3d12Sbt->buffer); + d3d12Sbt->stagingBuffer->lpVtbl->Release(d3d12Sbt->stagingBuffer); palFree(s_D3D12.allocator, d3d12Sbt); } @@ -373,7 +368,7 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; void* data = nullptr; - result = ID3D12Resource_Map(d3d12Sbt->stagingBuffer, 0, nullptr, &data); + d3d12Sbt->stagingBuffer->lpVtbl->Map(d3d12Sbt->stagingBuffer, 0, nullptr, &data); if (FAILED(result)) { return makeResultD3D12(result); } @@ -421,7 +416,7 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( memcpy(dst + d3d12Sbt->handleSize, info->localData, info->localDataSize); } - ID3D12Resource_Unmap(d3d12Sbt->stagingBuffer, 0, nullptr); + d3d12Sbt->stagingBuffer->lpVtbl->Unmap(d3d12Sbt->stagingBuffer, 0, nullptr); d3d12Sbt->isDirty = PAL_TRUE; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/d3d12/pal_swapchain_d3d12.c b/src/graphics/d3d12/pal_swapchain_d3d12.c index 31b70783..4f9f869d 100644 --- a/src/graphics/d3d12/pal_swapchain_d3d12.c +++ b/src/graphics/d3d12/pal_swapchain_d3d12.c @@ -6,6 +6,483 @@ */ #if PAL_HAS_D3D12_BACKEND +#include "pal_d3d12.h" +PalResult PAL_CALL createSurfaceD3D12( + PalDevice* device, + PalGraphicsWindow* window, + PalSurface** outSurface) +{ + Device* d3d12Device = (Device*)device; + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + Surface* surface = nullptr; + surface = palAllocate(s_D3D12.allocator, sizeof(Surface), 0); + if (!surface) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // validate if the window is valid + if (!IsWindow((HWND)window->window)) { + return PAL_RESULT_INVALID_GRAPHICS_WINDOW; + } + + surface->handle = window->window; + *outSurface = (PalSurface*)surface; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroySurfaceD3D12(PalSurface* surface) +{ + Surface* d3dSurface = (Surface*)surface; + palFree(s_D3D12.allocator, d3dSurface); +} + +PalResult PAL_CALL getSurfaceCapabilitiesD3D12( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps) +{ + HRESULT result; + Surface* d3dSurface = (Surface*)surface; + Device* d3d12Device = (Device*)device; + PalBool supportHDR10 = PAL_FALSE; + IDXGISwapChain1* swapchain1 = nullptr; + IDXGISwapChain3* swapchain3 = nullptr; + + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + DXGI_SWAP_CHAIN_DESC1 desc = {0}; + desc.Width = 8; + desc.Height = 8; + desc.SampleDesc.Count = 1; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.BufferCount = 2; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + + result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( + s_D3D12.factory, + (IUnknown*)d3d12Device->queue, + d3dSurface->handle, + &desc, + nullptr, + nullptr, + &swapchain1); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + swapchain1->lpVtbl->QueryInterface(swapchain1, &IID_Swapchain, (void**)&swapchain3); + swapchain1->lpVtbl->Release(swapchain1); + + // check for HDR10 color space support + UINT flags = 0; + result = swapchain3->lpVtbl->CheckColorSpaceSupport( + swapchain3, + DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, + &flags); + + if (SUCCEEDED(result) && (flags & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) { + supportHDR10 = PAL_TRUE; + } + + BOOL allowTearing = PAL_FALSE; + s_D3D12.factory->lpVtbl->CheckFeatureSupport( + s_D3D12.factory, + DXGI_FEATURE_PRESENT_ALLOW_TEARING, + &allowTearing, + sizeof(allowTearing)); + + caps->presentModes[PAL_PRESENT_MODE_FIFO] = PAL_TRUE; + if (allowTearing) { + caps->minImageCount = 3; + caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_TRUE; + caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_TRUE; + + } else { + caps->minImageCount = 2; + caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_FALSE; + caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_FALSE; + } + + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = PAL_TRUE; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = PAL_FALSE; + caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = PAL_FALSE; + + caps->maxImageCount = 8; // safe default + caps->minImageWidth = 1; + caps->minImageHeight = 1; + caps->maxImageWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + caps->maxImageHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; + caps->maxImageArrayLayers = 1; + + // check support for the base format + D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport = {0}; + DXGI_FORMAT baseFormats[PAL_SURFACE_FORMAT_MAX]; + baseFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM; + baseFormats[1] = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + baseFormats[2] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + baseFormats[3] = DXGI_FORMAT_R16G16B16A16_FLOAT; + + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_FALSE; + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; + caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_FALSE; + + for (int i = 0; i < PAL_SURFACE_FORMAT_MAX; i++) { + formatSupport.Format = baseFormats[i]; + result = d3d12Device->handle->lpVtbl->CheckFeatureSupport( + d3d12Device->handle, + D3D12_FEATURE_FORMAT_SUPPORT, + &formatSupport, + sizeof(formatSupport)); + + if (SUCCEEDED(result) && (formatSupport.Support1 != 0 || formatSupport.Support2 != 0)) { + if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM) { + caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; + } + + if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) { + caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_TRUE; + } + + if (baseFormats[i] == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) { + caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; + } + + if (baseFormats[i] == DXGI_FORMAT_R16G16B16A16_FLOAT) { + // check HDR10 color space + if (supportHDR10) { + caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_TRUE; + } + } + } + } + + swapchain3->lpVtbl->Release(swapchain3); + return PAL_RESULT_SUCCESS; +} + +// ================================================== +// Swapchain +// ================================================== + +PalResult PAL_CALL createSwapchainD3D12( + PalDevice* device, + PalQueue* queue, + PalSurface* surface, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain) +{ + HRESULT result; + Surface* d3dSurface = (Surface*)surface; + Device* d3d12Device = (Device*)device; + Queue* d3d12Queue = (Queue*)queue; + Swapchain* swapchain = nullptr; + PalBool isHDRColorspace = PAL_FALSE; + + if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { + return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + } + + if (d3d12Queue->type != PAL_QUEUE_TYPE_GRAPHICS) { + return PAL_RESULT_INVALID_QUEUE; + } + + if (info->compositeAlpha != PAL_COMPOSITE_ALPHA_OPAQUE) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (info->presentMode == PAL_PRESENT_MODE_MAILBOX && info->imageCount < 3) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + if (info->imageCount > 8) { + return PAL_RESULT_INVALID_ARGUMENT; + } + + swapchain = palAllocate(s_D3D12.allocator, sizeof(Swapchain), 0); + if (!swapchain) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + IDXGISwapChain1* swapchain1 = nullptr; + DXGI_SWAP_CHAIN_DESC1 desc = {0}; + desc.Width = info->width; + desc.Height = info->height; + desc.SampleDesc.Count = 1; + desc.BufferCount = info->imageCount; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + desc.Stereo = PAL_FALSE; + desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; + desc.Scaling = DXGI_SCALING_NONE; + + desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + if (info->presentMode == PAL_PRESENT_MODE_FIFO) { + swapchain->presentFlags = 0; + swapchain->syncInterval = 1; + + } else if (info->presentMode == PAL_PRESENT_MODE_IMMEDIATE) { + desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + swapchain->presentFlags = DXGI_PRESENT_ALLOW_TEARING; + swapchain->syncInterval = 0; + + } else { + desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + swapchain->presentFlags = DXGI_PRESENT_ALLOW_TEARING; + swapchain->syncInterval = 0; + } + + PalFormat imageFormat; + if (info->format == PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR) { + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + imageFormat = PAL_FORMAT_B8G8R8A8_UNORM; + + } else if (info->format == PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR) { + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + imageFormat = PAL_FORMAT_B8G8R8A8_SRGB; + + } else if (info->format == PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR) { + desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + imageFormat = PAL_FORMAT_R8G8B8A8_SRGB; + + } else if (info->format == PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10) { + desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; + imageFormat = PAL_FORMAT_R16G16B16A16_SFLOAT; + isHDRColorspace = PAL_TRUE; + } + + swapchain->format = desc.Format; + swapchain->flags = desc.Flags; + result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( + s_D3D12.factory, + (IUnknown*)d3d12Queue->handle, + d3dSurface->handle, + &desc, + nullptr, + nullptr, + &swapchain1); + + if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); + if (result == E_OUTOFMEMORY) { + return PAL_RESULT_OUT_OF_MEMORY; + } else if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + swapchain1->lpVtbl->QueryInterface(swapchain1, &IID_Swapchain, (void**)&swapchain->handle); + swapchain1->lpVtbl->Release(swapchain1); + + if (isHDRColorspace) { + swapchain->handle->lpVtbl->SetColorSpace1( + swapchain->handle, + DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); + } else { + swapchain->handle->lpVtbl->SetColorSpace1( + swapchain->handle, DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709); + } + + // get and cache swapchain images + swapchain->images = nullptr; + swapchain->images = palAllocate(s_D3D12.allocator, sizeof(Image) * info->imageCount, 0); + if (!swapchain->imageCount) { + return PAL_RESULT_OUT_OF_MEMORY; + } + + // fill all images with the creatio info + for (int i = 0; i < info->imageCount; i++) { + ID3D12Resource* tmp = nullptr; + swapchain->handle->lpVtbl->GetBuffer(swapchain->handle, i, &IID_Resource, (void**)&tmp); + + Image* image = &swapchain->images[i]; + image->belongsToSwapchain = PAL_TRUE; + image->device = d3d12Device; + image->handle = tmp; + + image->info.depthOrArraySize = 1; // always 1 + image->info.format = imageFormat; + image->info.usages = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; + image->info.height = info->height; + image->info.width = info->width; + image->info.mipLevelCount = 1; + image->info.sampleCount = PAL_SAMPLE_COUNT_1; // swapchain images are not multisampled + image->info.type = PAL_IMAGE_TYPE_2D; + } + + // get and cache window size for swapchain out of date error + RECT windowRect; + GetClientRect((HWND)d3dSurface->handle, &windowRect); + swapchain->windowWidth = windowRect.right - windowRect.left; + swapchain->windowWidth = windowRect.bottom - windowRect.top; + + swapchain->device = d3d12Device; + swapchain->queue = d3d12Queue->handle; + swapchain->imageCount = info->imageCount; + *outSwapchain = (PalSwapchain*)swapchain; + return PAL_RESULT_SUCCESS; +} + +void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) +{ + Swapchain* d3dSwapchain = (Swapchain*)swapchain; + d3dSwapchain->handle->lpVtbl->Release(d3dSwapchain->handle); + palFree(s_D3D12.allocator, d3dSwapchain->images); + palFree(s_D3D12.allocator, d3dSwapchain); +} + +PalImage* PAL_CALL getSwapchainImageD3D12( + PalSwapchain* swapchain, + uint32_t index) +{ + Swapchain* d3dSwapchain = (Swapchain*)swapchain; + if (index > d3dSwapchain->imageCount) { + return nullptr; + } + return (PalImage*)&d3dSwapchain->images[index]; +} + +PalResult PAL_CALL getNextSwapchainImageD3D12( + PalSwapchain* swapchain, + PalSwapchainNextImageInfo* info, + uint32_t* outIndex) +{ + uint32_t index = 0; + Swapchain* d3dSwapchain = (Swapchain*)swapchain; + ID3D12CommandQueue* queue = d3dSwapchain->queue; + + index = d3dSwapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3dSwapchain->handle); + if (info->fence) { + Fence* fence = (Fence*)info->fence; + fence->value++; + queue->lpVtbl->Signal(queue, fence->handle, fence->value); + } + + if (info->signalSemaphore) { + Semaphore* semaphore = (Semaphore*)info->signalSemaphore; + if (semaphore->isTimeline) { + queue->lpVtbl->Signal(queue, semaphore->handle, info->signalValue); + } else { + semaphore->value = 1; + queue->lpVtbl->Signal(queue, semaphore->handle, semaphore->value); + } + } + + *outIndex = index; + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL presentSwapchainD3D12( + PalSwapchain* swapchain, + uint32_t imageIndex, + PalSemaphore* waitSemaphore) +{ + HRESULT result; + Swapchain* d3dSwapchain = (Swapchain*)swapchain; + ID3D12CommandQueue* queue = d3dSwapchain->queue; + + if (waitSemaphore) { + Semaphore* semaphore = (Semaphore*)waitSemaphore; + if (semaphore->isTimeline) { + queue->lpVtbl->Wait(queue, semaphore->handle, info->waitValue); + } else { + queue->lpVtbl->Wait(queue, semaphore->handle, semaphore->value); + semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); + semaphore->value = 0; + } + } + + result = d3dSwapchain->handle->lpVtbl->Present( + d3dSwapchain->handle, + d3dSwapchain->syncInterval, + d3dSwapchain->presentFlags); + + if (FAILED(result)) { + pollMessagesD3D12(d3dSwapchain->device); + if (result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET) { + return PAL_RESULT_DEVICE_LOST; + } + + // check if swapchain needs to be resize + RECT windowRect; + PalBool ret = GetClientRect((HWND)d3dSwapchain->surface->handle, &windowRect); + uint32_t w = windowRect.right - windowRect.left; + uint32_t h = windowRect.bottom - windowRect.top; + + if (!ret) { + return PAL_RESULT_SURFACE_LOST; + } + + if (w != d3dSwapchain->windowWidth || h != d3dSwapchain->windowHeight) { + return PAL_RESULT_SWAPCHAIN_OUT_OF_DATE; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + return PAL_RESULT_SUCCESS; +} + +PalResult PAL_CALL resizeSwapchainD3D12( + PalSwapchain* swapchain, + uint32_t newWidth, + uint32_t newHeight) +{ + HRESULT result; + Swapchain* d3dSwapchain = (Swapchain*)swapchain; + result = d3dSwapchain->handle->lpVtbl->ResizeBuffers( + d3dSwapchain->handle, + d3dSwapchain->imageCount, + newWidth, + newHeight, + d3dSwapchain->format, + d3dSwapchain->flags); + + if (FAILED(result)) { + pollMessagesD3D12(d3dSwapchain->device); + if (result == E_INVALIDARG) { + return PAL_RESULT_INVALID_ARGUMENT; + } + return PAL_RESULT_PLATFORM_FAILURE; + } + + // fill all images with the creatio info + for (int i = 0; i < d3dSwapchain->imageCount; i++) { + ID3D12Resource* tmp = nullptr; + d3dSwapchain->handle->lpVtbl->GetBuffer( + d3dSwapchain->handle, + i, + &IID_Resource, + (void**)&tmp); + + Image* image = &d3dSwapchain->images[i]; + image->handle = tmp; + image->info.height = newHeight; + image->info.width = newWidth; + } + + // get and cache window size for swapchain out of date error + RECT windowRect; + Surface* surface = d3dSwapchain->surface; + if (!GetClientRect((HWND)surface->handle, &windowRect)) { + return PAL_RESULT_SURFACE_LOST; + } + + d3dSwapchain->windowWidth = windowRect.right - windowRect.left; + d3dSwapchain->windowWidth = windowRect.bottom - windowRect.top; + return PAL_RESULT_SUCCESS; +} #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_sync_d3d12.c b/src/graphics/d3d12/pal_sync_d3d12.c index 39cf0bce..5469a576 100644 --- a/src/graphics/d3d12/pal_sync_d3d12.c +++ b/src/graphics/d3d12/pal_sync_d3d12.c @@ -8,8 +8,6 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" -const IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; - PalResult PAL_CALL createFenceD3D12( PalDevice* device, PalBool signaled, @@ -24,7 +22,13 @@ PalResult PAL_CALL createFenceD3D12( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - result = ID3D12Device5_CreateFence(d3d12Device->handle, 0, 0, &IID_Fence, &fence->handle); + result = d3d12Device->handle->lpVtbl->CreateFence( + d3d12Device->handle, + 0, + 0, + &IID_Fence, + &fence->handle); + if (FAILED(result)) { pollMessagesD3D12(d3d12Device); palFree(s_D3D12.allocator, fence); @@ -55,7 +59,7 @@ PalResult PAL_CALL createFenceD3D12( void PAL_CALL destroyFenceD3D12(PalFence* fence) { FenceD3D12* d3d12Fence = (FenceD3D12*)fence; - ID3D12Fence_Release(d3d12Fence->handle); + d3d12Fence->handle->lpVtbl->Release(d3d12Fence->handle); CloseHandle(d3d12Fence->event); palFree(s_D3D12.allocator, d3d12Fence); } @@ -70,8 +74,12 @@ PalResult PAL_CALL waitFenceD3D12( uint64_t value = d3d12Fence->value; HANDLE event = d3d12Fence->event; - if (ID3D12Fence_GetCompletedValue(d3d12Fence->handle) < value) { - result = ID3D12Fence_SetEventOnCompletion(d3d12Fence->handle, value, event); + if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) < value) { + result = d3d12Fence->handle->lpVtbl->SetEventOnCompletion( + d3d12Fence->handle, + value, + event); + if (FAILED(result)) { return makeResultD3D12(result); } @@ -97,7 +105,7 @@ PalResult PAL_CALL resetFenceD3D12(PalFence* fence) return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } - ID3D12Fence_Signal(d3d12Fence->handle, 0); + d3d12Fence->handle->lpVtbl->Signal(d3d12Fence->handle, 0); d3d12Fence->value = 0; return PAL_RESULT_SUCCESS; } @@ -105,7 +113,7 @@ PalResult PAL_CALL resetFenceD3D12(PalFence* fence) PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence) { FenceD3D12* d3d12Fence = (FenceD3D12*)fence; - if (ID3D12Fence_GetCompletedValue(d3d12Fence->handle) == 0) { + if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) == 0) { return PAL_FALSE; } return PAL_TRUE; @@ -138,7 +146,13 @@ PalResult PAL_CALL createSemaphoreD3D12( semaphore->isTimeline = PAL_TRUE; } - result = ID3D12Device5_CreateFence(d3d12Device->handle, 0, 0, &IID_Fence, &semaphore->handle); + result = d3d12Device->handle->lpVtbl->CreateFence( + d3d12Device->handle, + 0, + 0, + &IID_Fence, + &semaphore->handle); + if (FAILED(result)) { pollMessagesD3D12(d3d12Device); palFree(s_D3D12.allocator, semaphore); @@ -164,7 +178,7 @@ PalResult PAL_CALL createSemaphoreD3D12( void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore) { SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; - ID3D12Fence_Release(d3d12Semaphore->handle); + d3d12Semaphore->handle->lpVtbl->Release(d3d12Semaphore->handle); CloseHandle(d3d12Semaphore->event); palFree(s_D3D12.allocator, d3d12Semaphore); } @@ -182,8 +196,12 @@ PalResult PAL_CALL waitSemaphoreD3D12( } HANDLE event = d3d12Semaphore->event; - if (ID3D12Fence_GetCompletedValue(d3d12Semaphore->handle) < value) { - result = ID3D12Fence_SetEventOnCompletion(d3d12Semaphore->handle, value, event); + if (d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle) < value) { + result = d3d12Semaphore->handle->lpVtbl->SetEventOnCompletion( + d3d12Semaphore->handle, + value, + event); + if (FAILED(result)) { return makeResultD3D12(result); } @@ -212,7 +230,7 @@ PalResult PAL_CALL signalSemaphoreD3D12( return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } - HRESULT result = ID3D12Fence_Signal(d3d12Semaphore->handle, value); + HRESULT result = d3d12Semaphore->handle->lpVtbl->Signal(d3d12Semaphore->handle, value); if (FAILED(result)) { return makeResultD3D12(result); } @@ -228,7 +246,7 @@ PalResult PAL_CALL getSemaphoreValueD3D12( return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } - UINT64 tmp = ID3D12Fence_GetCompletedValue(d3d12Semaphore->handle); + UINT64 tmp = d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle); *outValue = tmp; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 1c04c3da..518e6abb 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -19,19 +19,8 @@ #include #include -// on older SDKs, D3D_FEATURE_LEVEL_12_2 is not defined -#ifndef D3D_FEATURE_LEVEL_12_2 -#define D3D_FEATURE_LEVEL_12_2 0xc200 -#endif // D3D_FEATURE_LEVEL_12_2 - -#define MAX_ATTACHMENTS 32 -#define TEXTURE_PITCH 256 #define MAX_MESSAGE_SIZE 4096 -#define GRAPHICS_PIPELINE 1220 -#define COMPUTE_PIPELINE 1221 -#define RAY_TRACING_PIPELINE 1222 - #if INTPTR_MAX == INT64_MAX #define PTR_SIZE 8 #else @@ -46,26 +35,28 @@ #define ALIGN_STREAM #endif // _MSC_VER -// clang-format off // IIDS - -const IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0,0x3c, 0x77,0x90,0x0a,0x0a,0x1d,0x17}; -const IID IID_DebugController = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0}; -const IID IID_DebugController1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; -const IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4,0xe6,0x14,0x58}; -const IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3}; -const IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed}; -const IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1}; -const IID IID_CommandAllocator = {0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73,0xf0,0x9b,0x24}; -const IID IID_CommandList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5}; -const IID IID_CommandList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96,0xcf, 0x56,0x89,0xa9,0x37,0x0f,0x80}; -const IID IID_CommandSignature = {0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1}; -const IID IID_DescriptorHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51}; -const IID IID_RootSignature = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14}; -const IID IID_Device5 = {0x8b4f173b, 0x2fea, 0x4b80, 0x8f,0x58, 0x43,0x07,0x19,0x1a,0xb9,0x5d}; -const IID IID_PipelineState = {0x765a30f3, 0xf624, 0x4c6f, 0xa8,0x28, 0xac,0xe9,0x48,0x62,0x24,0x45}; -const IID IID_StateObject = {0x47016943, 0xfca8, 0x4594, 0x93,0xea, 0xaf,0x25,0x8b,0x55,0x34,0x6d}; -// clang-format on +IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; +IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0xd2,0x4e}; +IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0,0x3c, 0x77,0x90,0x0a,0x0a,0x1d,0x17}; +IID IID_DebugController = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0}; +IID IID_DebugController1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; +IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4,0xe6,0x14,0x58}; +IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3}; +IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed}; +IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1}; +IID IID_CommandAllocator = {0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73,0xf0,0x9b,0x24}; +IID IID_CommandList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5}; +IID IID_CommandList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96,0xcf, 0x56,0x89,0xa9,0x37,0x0f,0x80}; +IID IID_CommandSignature = {0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1}; +IID IID_DescriptorHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51}; +IID IID_RootSignature = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14}; +IID IID_Device5 = {0x8b4f173b, 0x2fea, 0x4b80, 0x8f,0x58, 0x43,0x07,0x19,0x1a,0xb9,0x5d}; +IID IID_PipelineState = {0x765a30f3, 0xf624, 0x4c6f, 0xa8,0x28, 0xac,0xe9,0x48,0x62,0x24,0x45}; +IID IID_StateObject = {0x47016943, 0xfca8, 0x4594, 0x93,0xea, 0xaf,0x25,0x8b,0x55,0x34,0x6d}; +IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad}; +IID IID_StateObjectProps = {0xde5fa827, 0x9bf9, 0x4f26, 0x89,0xff, 0xd7,0xf5,0x6f,0xde,0x38,0x60}; +IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; typedef ALIGN_STREAM struct { D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; @@ -1836,5361 +1827,6 @@ void PAL_CALL shutdownGraphicsD3D12() memset(&s_D3D12, 0, sizeof(s_D3D12)); } - - -// ================================================== -// Device -// ================================================== - -PalResult PAL_CALL createDeviceD3D12( - PalAdapter* adapter, - PalAdapterFeatures features, - PalDevice** outDevice) -{ - HRESULT result; - Device* device = nullptr; - Adapter* d3dAdapter = (Adapter*)adapter; - - // check if any of the features are not supported - PalAdapterFeatures adapterFeatures = getAdapterFeaturesD3D12(adapter); - PalBool valid = (adapterFeatures & features) == features; - if (!valid) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - device = palAllocate(s_D3D12.allocator, sizeof(Device), 0); - if (!device) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - ID3D12Device* tmpDevice = nullptr; - memset(device, 0, sizeof(Device)); - DeviceLimits* limits = &device->limits; - - // get and cache highest shader model - device->shaderModel = getHighestSupportedShaderTargetD3D12(adapter, PAL_SHADER_FORMAT_DXIL); - - result = s_D3D12.createDevice( - (IUnknown*)d3dAdapter->handle, - d3dAdapter->level, - &IID_Device, - (void**)&tmpDevice); - - if (FAILED(result)) { - palFree(s_D3D12.allocator, device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_INVALID_DRIVER; - } - - result = tmpDevice->lpVtbl->QueryInterface( - tmpDevice, - &IID_Device5, - (void**)&device->handle); - - tmpDevice->lpVtbl->Release(tmpDevice); - if (s_D3D12.debugLayer) { - result = device->handle->lpVtbl->QueryInterface( - device->handle, - &IID_InfoQueue, - (void**)&device->infoQueue); - - if (SUCCEEDED(result)) { - D3D12_MESSAGE_ID denyIDs[] = { D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE }; - D3D12_INFO_QUEUE_FILTER filter = {0}; - filter.AllowList.NumSeverities = s_D3D12.severityCount; - filter.AllowList.pSeverityList = s_D3D12.severities; - filter.AllowList.NumCategories = s_D3D12.categoryCount; - filter.AllowList.pCategoryList = s_D3D12.categories; - filter.DenyList.NumIDs = 1; - filter.DenyList.pIDList = denyIDs; - - device->infoQueue->lpVtbl->PushStorageFilter(device->infoQueue, &filter); - } - } - - // create a temporary graphics queue - D3D12_COMMAND_QUEUE_DESC desc = {0}; - desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - - result = device->handle->lpVtbl->CreateCommandQueue( - device->handle, - &desc, - &IID_Queue, - (void**)&device->queue); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // create command signatures - D3D12_INDIRECT_ARGUMENT_DESC argumentDesc = {0}; - D3D12_COMMAND_SIGNATURE_DESC signatureDesc = {0}; - signatureDesc.NumArgumentDescs = 1; - signatureDesc.pArgumentDescs = &argumentDesc; - - if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH) { - argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_MESH; - signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_MESH_ARGUMENTS); - - result = device->handle->lpVtbl->CreateCommandSignature( - device->handle, - &signatureDesc, - nullptr, - &IID_CommandSignature, - (void**)&device->meshSignature); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH_RAYS; - signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_RAYS_DESC); - - result = device->handle->lpVtbl->CreateCommandSignature( - device->handle, - &signatureDesc, - nullptr, - &IID_CommandSignature, - (void**)&device->raySignature); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW) { - // draw indexed - argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; - signatureDesc.ByteStride = sizeof(D3D12_DRAW_INDEXED_ARGUMENTS); - - result = device->handle->lpVtbl->CreateCommandSignature( - device->handle, - &signatureDesc, - nullptr, - &IID_CommandSignature, - (void**)&device->drawIndexedSignature); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // draw - argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; - signatureDesc.ByteStride = sizeof(D3D12_DRAW_ARGUMENTS); - - result = device->handle->lpVtbl->CreateCommandSignature( - device->handle, - &signatureDesc, - nullptr, - &IID_CommandSignature, - (void**)&device->drawSignature); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - if (features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH) { - argumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; - signatureDesc.ByteStride = sizeof(D3D12_DISPATCH_ARGUMENTS); - - result = device->handle->lpVtbl->CreateCommandSignature( - device->handle, - &signatureDesc, - nullptr, - &IID_CommandSignature, - (void**)&device->dispatchSignature); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - // create an internal heap for RTV and DSV - D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {0}; - heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; - heapDesc.NumDescriptors = MAX_RTV; - - result = device->handle->lpVtbl->CreateDescriptorHeap( - device->handle, - &heapDesc, - &IID_DescriptorHeap, - (void**)&device->rtvAllocator.heap); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; - heapDesc.NumDescriptors = MAX_DSV; - result = device->handle->lpVtbl->CreateDescriptorHeap( - device->handle, - &heapDesc, - &IID_DescriptorHeap, - (void**)&device->dsvAllocator.heap); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - for (int i = 0; i < MAX_RTV; i++) { - device->rtvAllocator.freeList[i] = i + 1; - } - - for (int i = 0; i < MAX_DSV; i++) { - device->dsvAllocator.freeList[i] = i + 1; - } - - device->rtvAllocator.freeTop = 0; - device->rtvAllocator.incrementSize = device->handle->lpVtbl->GetDescriptorHandleIncrementSize( - device->handle, - D3D12_DESCRIPTOR_HEAP_TYPE_RTV); - - device->dsvAllocator.freeTop = 0; - device->dsvAllocator.incrementSize = device->handle->lpVtbl->GetDescriptorHandleIncrementSize( - device->handle, - D3D12_DESCRIPTOR_HEAP_TYPE_DSV); - - // get base CPU pointer - D3D12_CPU_DESCRIPTOR_HANDLE __ret, dst; - dst = *device->rtvAllocator.heap->lpVtbl->GetCPUDescriptorHandleForHeapStart( - device->rtvAllocator.heap, - &__ret - ); - device->rtvAllocator.baseOffset = dst.ptr; - - dst = *device->dsvAllocator.heap->lpVtbl->GetCPUDescriptorHandleForHeapStart( - device->dsvAllocator.heap, - &__ret - ); - device->dsvAllocator.baseOffset = dst.ptr; - - // API enforced limits - limits->freeComputeQueues = 2; - limits->freeGraphicsQueues = 2; - limits->freeCopyQueues = 2; - limits->maxVertexLayouts = 30; - limits->maxVertexAttributes = 30; - - limits->maxAnisotropy = 16; - limits->maxPushConstantSize = 256; - limits->maxTessellationPatchPoint = 32; - limits->maxBoundDescriptorSets = 30; - - if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - limits->maxDescriptorSampledImages = 4096; - limits->maxDescriptorStorageImages = 1024; - limits->maxDescriptorSamplers = 512; - limits->maxDescriptorStorageBuffers = 2048; - limits->maxDescriptorUniformBuffers = 256; - - } else { - limits->maxDescriptorSampledImages = 1024; - limits->maxDescriptorStorageImages = 512; - limits->maxDescriptorSamplers = 256; - limits->maxDescriptorStorageBuffers = 512; - limits->maxDescriptorUniformBuffers = 256; - limits->maxBoundDescriptorSets = 30; - } - - if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - limits->maxRecursionDepth = 31; - limits->maxHitAttributeSize = 32; - limits->maxPayloadSize = 64; - limits->maxDispatchInvocations = 16000000; - limits->maxDescriptorAccelerationStructures = 4; - } - - device->adapter = d3dAdapter->handle; - device->features = features; - *outDevice = (PalDevice*)device; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyDeviceD3D12(PalDevice* device) -{ - Device* d3d12Device = (Device*)device; - if (d3d12Device->meshSignature) { - d3d12Device->meshSignature->lpVtbl->Release(d3d12Device->meshSignature); - } - - if (d3d12Device->raySignature) { - d3d12Device->raySignature->lpVtbl->Release(d3d12Device->raySignature); - } - - if (d3d12Device->dispatchSignature) { - d3d12Device->dispatchSignature->lpVtbl->Release(d3d12Device->dispatchSignature); - } - - if (d3d12Device->drawIndexedSignature) { - d3d12Device->drawIndexedSignature->lpVtbl->Release(d3d12Device->drawIndexedSignature); - } - - if (d3d12Device->drawSignature) { - d3d12Device->drawSignature->lpVtbl->Release(d3d12Device->drawSignature); - } - - d3d12Device->rtvAllocator.heap->lpVtbl->Release(d3d12Device->rtvAllocator.heap); - d3d12Device->dsvAllocator.heap->lpVtbl->Release(d3d12Device->dsvAllocator.heap); - - d3d12Device->queue->lpVtbl->Release(d3d12Device->queue); - d3d12Device->handle->lpVtbl->Release(d3d12Device->handle); - if (d3d12Device->infoQueue) { - d3d12Device->infoQueue->lpVtbl->Release(d3d12Device->infoQueue); - } - - palFree(s_D3D12.allocator, d3d12Device); -} - -// ================================================== -// Memory -// ================================================== - -PalResult PAL_CALL allocateMemoryD3D12( - PalDevice* device, - PalMemoryType type, - uint64_t memoryMask, - uint64_t size, - PalMemory** outMemory) -{ - HRESULT result; - Device* d3d12Device = (Device*)device; - ID3D12Heap* memory = nullptr; - - D3D12_HEAP_DESC desc = {0}; - desc.SizeInBytes = size; - - desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; - if (type == PAL_MEMORY_TYPE_CPU_READBACK) { - desc.Properties.Type = D3D12_HEAP_TYPE_READBACK; - - } else if (type == PAL_MEMORY_TYPE_CPU_UPLOAD) { - desc.Properties.Type = D3D12_HEAP_TYPE_UPLOAD; - } - - result = d3d12Device->handle->lpVtbl->CreateHeap( - d3d12Device->handle, - &desc, - &IID_Heap, - (void**)&memory); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - return PAL_RESULT_OUT_OF_MEMORY; - } - - *outMemory = (PalMemory*)memory; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL freeMemoryD3D12( - PalDevice* device, - PalMemory* memory) -{ - ID3D12Heap* mem = (ID3D12Heap*)memory; - mem->lpVtbl->Release(mem); -} - -// ================================================== -// Extended Adapter Features -// ================================================== - -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( - PalDevice* device, - PalSamplerAnisotropyCapabilities* caps) -{ - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - caps->maxAnisotropy = 16; // default on most d3d12 hardwares - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( - PalDevice* device, - PalMultiViewCapabilities* caps) -{ - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - caps->maxViewCount = D3D12_MAX_VIEW_INSTANCE_COUNT; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( - PalDevice* device, - PalMultiViewportCapabilities* caps) -{ - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - caps->maxCount = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( - PalDevice* device, - PalDepthStencilCapabilities* caps) -{ - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - caps->depthResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = PAL_TRUE; - caps->depthResolves[PAL_RESOLVE_MODE_AVERAGE] = PAL_TRUE; - caps->depthResolves[PAL_RESOLVE_MODE_MIN] = PAL_TRUE; - caps->depthResolves[PAL_RESOLVE_MODE_MAX] = PAL_TRUE; - - caps->stencilResolves[PAL_RESOLVE_MODE_SAMPLE_ZERO] = PAL_TRUE; - caps->stencilResolves[PAL_RESOLVE_MODE_AVERAGE] = PAL_FALSE; - caps->stencilResolves[PAL_RESOLVE_MODE_MIN] = PAL_TRUE; - caps->stencilResolves[PAL_RESOLVE_MODE_MAX] = PAL_TRUE; - - caps->independentResolve = PAL_TRUE; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( - PalDevice* device, - PalFragmentShadingRateCapabilities* caps) -{ - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - // these are supported if fragment shading rate feature is - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_1X1] = PAL_TRUE; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_1X2] = PAL_TRUE; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X1] = PAL_TRUE; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X2] = PAL_TRUE; - - D3D12_FEATURE_DATA_D3D12_OPTIONS6 options = {0}; - d3d12Device->handle->lpVtbl->CheckFeatureSupport( - d3d12Device->handle, - D3D12_FEATURE_D3D12_OPTIONS6, - &options, - sizeof(options)); - - if (options.AdditionalShadingRatesSupported) { - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X4] = PAL_TRUE; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X2] = PAL_TRUE; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X4] = PAL_TRUE; - - } else { - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_2X4] = PAL_FALSE; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X2] = PAL_FALSE; - caps->shadingRates[PAL_FRAGMENT_SHADING_RATE_4X4] = PAL_FALSE; - } - - // there are supported if fragment shading rate feature is - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP] = PAL_TRUE; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE] = PAL_TRUE; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MIN] = PAL_TRUE; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX] = PAL_TRUE; - caps->combinerOps[PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL] = PAL_TRUE; - - caps->minTexelWidth = 1; // safe default - caps->minTexelHeight = 1; // safe default - caps->maxTexelWidth = options.ShadingRateImageTileSize; - caps->maxTexelHeight = options.ShadingRateImageTileSize; - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( - PalDevice* device, - PalMeshShaderCapabilities* caps) -{ - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - // these are not exposed by d3d12. We use the offical mesh shader spec - caps->maxOutputPrimitives = 256; - caps->maxOutputVertices = 256; - caps->maxWorkGroupInvocations = 128; - caps->maxTaskWorkGroupInvocations = 128; - - caps->maxWorkGroupCount[0] = 65535; - caps->maxWorkGroupCount[1] = 65535; - caps->maxWorkGroupCount[2] = 65535; - - caps->maxTaskWorkGroupCount[0] = 65535; - caps->maxTaskWorkGroupCount[1] = 65535; - caps->maxTaskWorkGroupCount[2] = 65535; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( - PalDevice* device, - PalRayTracingCapabilities* caps) -{ - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - // these are safe defaults. D3d12 does not expose them. - caps->maxRecursionDepth = 31; - caps->maxHitAttributeSize = 32; - caps->maxInstanceCount = 1000000; - caps->maxPrimitiveCount = 10000000; - caps->maxGeometryCount = 100000; - caps->maxPayloadSize = 64; - caps->maxDispatchInvocations = 16000000; - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( - PalDevice* device, - PalDescriptorIndexingCapabilities* caps) -{ - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - // always supported - caps->sampledImageNonUniformIndexing = PAL_TRUE; - caps->sampledImageUpdateAfterBind = PAL_TRUE; - caps->storageImageNonUniformIndexing = PAL_TRUE; - caps->storageImageUpdateAfterBind = PAL_TRUE; - caps->storageBufferNonUniformIndexing = PAL_TRUE; - caps->storageBufferUpdateAfterBind = PAL_TRUE; - caps->uniformBufferNonUniformIndexing = PAL_TRUE; - caps->uniformBufferUpdateAfterBind = PAL_TRUE; - - getDescriptorTierLimitsD3D12(d3d12Device->handle, nullptr, caps); - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Queue -// ================================================== - -PalResult PAL_CALL createQueueD3D12( - PalDevice* device, - PalQueueType type, - PalQueue** outQueue) -{ - HRESULT result; - Device* d3d12Device = (Device*)device; - Queue* queue = nullptr; - D3D12_COMMAND_QUEUE_DESC desc = {0}; - - switch (type) { - case PAL_QUEUE_TYPE_COMPUTE: { - desc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; - - if (!d3d12Device->limits.freeComputeQueues) { - return PAL_RESULT_OUT_OF_QUEUE; - } - d3d12Device->limits.freeComputeQueues--; - break; - } - - case PAL_QUEUE_TYPE_GRAPHICS: { - desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - - if (!d3d12Device->limits.freeGraphicsQueues) { - return PAL_RESULT_OUT_OF_QUEUE; - } - d3d12Device->limits.freeGraphicsQueues--; - break; - } - - case PAL_QUEUE_TYPE_COPY: { - desc.Type = D3D12_COMMAND_LIST_TYPE_COPY; - - if (!d3d12Device->limits.freeCopyQueues) { - return PAL_RESULT_OUT_OF_QUEUE; - } - d3d12Device->limits.freeCopyQueues--; - break; - } - } - - queue = palAllocate(s_D3D12.allocator, sizeof(Queue), 0); - if (!queue) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - result = d3d12Device->handle->lpVtbl->CreateCommandQueue( - d3d12Device->handle, - &desc, - &IID_Queue, - (void**)&queue->handle); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - palFree(s_D3D12.allocator, queue); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // create fence used for queue wait - result = d3d12Device->handle->lpVtbl->CreateFence( - d3d12Device->handle, - 0, - 0, - &IID_Fence, - (void**)&queue->fence); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - palFree(s_D3D12.allocator, queue); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - queue->fenceValue = 0; - queue->type = type; - *outQueue = (PalQueue*)queue; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyQueueD3D12(PalQueue* queue) -{ - Queue* d3dQueue = (Queue*)queue; - d3dQueue->fence->lpVtbl->Release(d3dQueue->fence); - d3dQueue->handle->lpVtbl->Release(d3dQueue->handle); - palFree(s_D3D12.allocator, d3dQueue); -} - -PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) -{ - Queue* d3dQueue = (Queue*)queue; - ID3D12Fence* fence = d3dQueue->fence; - - // wait on the fence if the submited work is not done - if (fence->lpVtbl->GetCompletedValue(fence) < d3dQueue->fenceValue) { - HANDLE event = CreateEvent(nullptr, PAL_FALSE, PAL_FALSE, nullptr); - fence->lpVtbl->SetEventOnCompletion(fence, d3dQueue->fenceValue, event); - WaitForSingleObject(event, INFINITE); - CloseHandle(event); - } - return PAL_RESULT_SUCCESS; -} - -PalBool PAL_CALL canQueuePresentD3D12( - PalQueue* queue, - PalSurface* surface) -{ - Queue* d3dQueue = (Queue*)queue; - if (d3dQueue->type == PAL_QUEUE_TYPE_GRAPHICS) { - return PAL_TRUE; // all graphics queues support presentation - } - return PAL_FALSE; -} - -// ================================================== -// Formats -// ================================================== - - - -// ================================================== -// Image -// ================================================== - -PalResult PAL_CALL createImageD3D12( - PalDevice* device, - const PalImageCreateInfo* info, - PalImage** outImage) -{ - HRESULT result; - Image* image = nullptr; - Device* d3d12Device = (Device*)device; - - image = palAllocate(s_D3D12.allocator, sizeof(Image), 0); - if (!image) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(image, 0, sizeof(Image)); - image->desc.Width = (UINT64)info->width; - image->desc.Height = (UINT64)info->height; - image->desc.DepthOrArraySize = (UINT16)info->depthOrArraySize; - image->desc.MipLevels = (UINT16)info->mipLevelCount; - image->desc.Format = formatToD3D12(info->format); - image->desc.SampleDesc.Count = samplesToD3D12(info->sampleCount); - image->desc.SampleDesc.Quality = 0; - - image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - if (info->type == PAL_IMAGE_TYPE_3D) { - image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - - } else if (info->type == PAL_IMAGE_TYPE_1D) { - image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D; - } - - if (info->usages & PAL_IMAGE_USAGE_COLOR_ATTACHEMENT) { - image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - } - - if (info->usages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) { - image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - } - - if (info->usages & PAL_IMAGE_USAGE_STORAGE) { - image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - } - - image->belongsToSwapchain = PAL_FALSE; - image->info.depthOrArraySize = info->depthOrArraySize; - image->info.type = info->type; - image->info.format = info->format; - image->info.usages = info->usages; - image->info.height = info->height; - image->info.mipLevelCount = info->mipLevelCount; - image->info.sampleCount = info->sampleCount; - image->info.width = info->width; - - image->device = d3d12Device; - *outImage = (PalImage*)image; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyImageD3D12(PalImage* image) -{ - Image* d3dImage = (Image*)image; - // check if memory has been attached to the image - if (d3dImage->handle) { - d3dImage->handle->lpVtbl->Release(d3dImage->handle); - } - palFree(s_D3D12.allocator, d3dImage); -} - -PalResult PAL_CALL getImageInfoD3D12( - PalImage* image, - PalImageInfo* info) -{ - Image* d3dImage = (Image*)image; - *info = d3dImage->info; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL getImageMemoryRequirementsD3D12( - PalImage* image, - PalMemoryRequirements* requirements) -{ - Image* d3dImage = (Image*)image; - ID3D12Device5* device = d3dImage->device->handle; - if (d3dImage->belongsToSwapchain) { - return PAL_RESULT_INVALID_OPERATION; - } - - D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; - D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; - allocationInfo = *device->lpVtbl->GetResourceAllocationInfo( - device, - &__ret, - 0, - 1, - &d3dImage->desc); - - // d3d12 allows images to be used with only GPU only heap - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = PAL_TRUE; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = PAL_FALSE; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = PAL_FALSE; - - requirements->alignment = allocationInfo.Alignment; - requirements->size = allocationInfo.SizeInBytes; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL bindImageMemoryD3D12( - PalImage* image, - PalMemory* memory, - uint64_t offset) -{ - HRESULT result; - Image* d3dImage = (Image*)image; - ID3D12Device5* device = d3dImage->device->handle; - if (d3dImage->belongsToSwapchain) { - return PAL_RESULT_INVALID_OPERATION; - } - - ID3D12Heap* mem = (ID3D12Heap*)memory; - result = device->lpVtbl->CreatePlacedResource( - device, - mem, - offset, - &d3dImage->desc, - 0, - nullptr, - &IID_Resource, - (void**)&d3dImage->handle); - - if (FAILED(result)) { - pollMessagesD3D12(d3dImage->device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } else if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Image View -// ================================================== - -PalResult PAL_CALL createImageViewD3D12( - PalDevice* device, - PalImage* image, - const PalImageViewCreateInfo* info, - PalImageView** outImageView) -{ - HRESULT result; - ImageView* imageView = nullptr; - Device* d3d12Device = (Device*)device; - Image* d3dImage = (Image*)image; - - if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - imageView = palAllocate(s_D3D12.allocator, sizeof(ImageView), 0); - if (!imageView) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - imageView->heapIndex = UINT32_MAX; - PalBool hasRTV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); - PalBool hasDSV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); - - imageView->format = formatToD3D12(info->format); - if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR && hasRTV) { - RTVHeapAllocator* allocator = &d3d12Device->rtvAllocator; - uint32_t index = allocator->freeTop; - allocator->freeTop = allocator->freeList[index]; - - D3D12_CPU_DESCRIPTOR_HANDLE dst; - dst.ptr = getDescriptorHandleD3D12(index, allocator->incrementSize, allocator->baseOffset); - - D3D12_RENDER_TARGET_VIEW_DESC desc = {0}; - desc.Format = imageView->format; - fillSubresourceD3D12( - info->type, - &info->subresourceRange, - &desc, - nullptr, - nullptr, - nullptr); - - imageView->heapIndex = index; - d3d12Device->handle->lpVtbl->CreateRenderTargetView( - d3d12Device->handle, - d3dImage->handle, - &desc, - dst); - - } else if (info->subresourceRange.aspect != PAL_IMAGE_ASPECT_COLOR && hasDSV) { - DSVHeapAllocator* allocator = &d3d12Device->dsvAllocator; - uint32_t index = allocator->freeTop; - allocator->freeTop = allocator->freeList[index]; - - D3D12_CPU_DESCRIPTOR_HANDLE dst; - dst.ptr = getDescriptorHandleD3D12(index, allocator->incrementSize, allocator->baseOffset); - - D3D12_DEPTH_STENCIL_VIEW_DESC desc = {0}; - desc.Format = imageView->format; - fillSubresourceD3D12( - info->type, - &info->subresourceRange, - nullptr, - &desc, - nullptr, - nullptr); - - imageView->heapIndex = index; - d3d12Device->handle->lpVtbl->CreateDepthStencilView( - d3d12Device->handle, - d3dImage->handle, - &desc, - dst); - } - - imageView->range = info->subresourceRange; - imageView->type = info->type; - imageView->image = d3dImage; - - imageView->device = d3d12Device; - *outImageView = (PalImageView*)imageView; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) -{ - ImageView* d3dImageView = (ImageView*)imageView; - Device* device = d3dImageView->device; - RTVHeapAllocator* allocator = nullptr; - - if (d3dImageView->heapIndex != UINT32_MAX) { - if (d3dImageView->range.aspect == PAL_IMAGE_ASPECT_COLOR) { - RTVHeapAllocator* allocator = &device->rtvAllocator; - allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; - allocator->freeTop = d3dImageView->heapIndex; - - } else { - DSVHeapAllocator* allocator = &device->dsvAllocator; - allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; - allocator->freeTop = d3dImageView->heapIndex; - } - } - palFree(s_D3D12.allocator, d3dImageView); -} - -// ================================================== -// Sampler -// ================================================== - -PalResult PAL_CALL createSamplerD3D12( - PalDevice* device, - const PalSamplerCreateInfo* info, - PalSampler** outSampler) -{ - Device* d3d12Device = (Device*)device; - if (info->maxAnisotropy > d3d12Device->limits.maxAnisotropy) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - Sampler* sampler = nullptr; - sampler = palAllocate(s_D3D12.allocator, sizeof(Sampler), 0); - if (!sampler) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(sampler, 0, sizeof(Sampler)); - sampler->desc.MaxLOD = info->maxLod; - sampler->desc.MinLOD = info->minLod; - sampler->desc.MipLODBias = info->mipLodBias; - - sampler->desc.MaxAnisotropy = 1; - if (info->enableAnisotropy) { - sampler->desc.MaxAnisotropy = (UINT)info->maxAnisotropy; - } - - sampler->desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; - if (info->enableCompare) { - sampler->desc.ComparisonFunc = compareOpToD3D12(info->compareOp); - } - - borderColorToD3D12(info->borderColor, sampler->desc.BorderColor); - sampler->desc.AddressU = addressModeToD3D12(info->addressModeU); - sampler->desc.AddressV = addressModeToD3D12(info->addressModeV); - sampler->desc.AddressW = addressModeToD3D12(info->addressModeW); - - sampler->desc.Filter = filterToD3D12( - info->minFilterMode, - info->magFilterMode, - info->mipmapMode); - - *outSampler = (PalSampler*)sampler; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroySamplerD3D12(PalSampler* sampler) -{ - Sampler* d3dSampler = (Sampler*)sampler; - palFree(s_D3D12.allocator, d3dSampler); -} - -// ================================================== -// Surface -// ================================================== - -PalResult PAL_CALL createSurfaceD3D12( - PalDevice* device, - PalGraphicsWindow* window, - PalSurface** outSurface) -{ - Device* d3d12Device = (Device*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - Surface* surface = nullptr; - surface = palAllocate(s_D3D12.allocator, sizeof(Surface), 0); - if (!surface) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // validate if the window is valid - if (!IsWindow((HWND)window->window)) { - return PAL_RESULT_INVALID_GRAPHICS_WINDOW; - } - - surface->handle = window->window; - *outSurface = (PalSurface*)surface; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroySurfaceD3D12(PalSurface* surface) -{ - Surface* d3dSurface = (Surface*)surface; - palFree(s_D3D12.allocator, d3dSurface); -} - -PalResult PAL_CALL getSurfaceCapabilitiesD3D12( - PalDevice* device, - PalSurface* surface, - PalSurfaceCapabilities* caps) -{ - HRESULT result; - Surface* d3dSurface = (Surface*)surface; - Device* d3d12Device = (Device*)device; - PalBool supportHDR10 = PAL_FALSE; - IDXGISwapChain1* swapchain1 = nullptr; - IDXGISwapChain3* swapchain3 = nullptr; - - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - DXGI_SWAP_CHAIN_DESC1 desc = {0}; - desc.Width = 8; - desc.Height = 8; - desc.SampleDesc.Count = 1; - desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.BufferCount = 2; - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; - desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - - result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( - s_D3D12.factory, - (IUnknown*)d3d12Device->queue, - d3dSurface->handle, - &desc, - nullptr, - nullptr, - &swapchain1); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - swapchain1->lpVtbl->QueryInterface(swapchain1, &IID_Swapchain, (void**)&swapchain3); - swapchain1->lpVtbl->Release(swapchain1); - - // check for HDR10 color space support - UINT flags = 0; - result = swapchain3->lpVtbl->CheckColorSpaceSupport( - swapchain3, - DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, - &flags); - - if (SUCCEEDED(result) && (flags & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) { - supportHDR10 = PAL_TRUE; - } - - BOOL allowTearing = PAL_FALSE; - s_D3D12.factory->lpVtbl->CheckFeatureSupport( - s_D3D12.factory, - DXGI_FEATURE_PRESENT_ALLOW_TEARING, - &allowTearing, - sizeof(allowTearing)); - - caps->presentModes[PAL_PRESENT_MODE_FIFO] = PAL_TRUE; - if (allowTearing) { - caps->minImageCount = 3; - caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_TRUE; - caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_TRUE; - - } else { - caps->minImageCount = 2; - caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_FALSE; - caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_FALSE; - } - - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = PAL_TRUE; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = PAL_FALSE; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = PAL_FALSE; - - caps->maxImageCount = 8; // safe default - caps->minImageWidth = 1; - caps->minImageHeight = 1; - caps->maxImageWidth = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; - caps->maxImageHeight = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION; - caps->maxImageArrayLayers = 1; - - // check support for the base format - D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport = {0}; - DXGI_FORMAT baseFormats[PAL_SURFACE_FORMAT_MAX]; - baseFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM; - baseFormats[1] = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; - baseFormats[2] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - baseFormats[3] = DXGI_FORMAT_R16G16B16A16_FLOAT; - - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_FALSE; - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; - caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_FALSE; - - for (int i = 0; i < PAL_SURFACE_FORMAT_MAX; i++) { - formatSupport.Format = baseFormats[i]; - result = d3d12Device->handle->lpVtbl->CheckFeatureSupport( - d3d12Device->handle, - D3D12_FEATURE_FORMAT_SUPPORT, - &formatSupport, - sizeof(formatSupport)); - - if (SUCCEEDED(result) && (formatSupport.Support1 != 0 || formatSupport.Support2 != 0)) { - if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; - } - - if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_TRUE; - } - - if (baseFormats[i] == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) { - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; - } - - if (baseFormats[i] == DXGI_FORMAT_R16G16B16A16_FLOAT) { - // check HDR10 color space - if (supportHDR10) { - caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_TRUE; - } - } - } - } - - swapchain3->lpVtbl->Release(swapchain3); - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Swapchain -// ================================================== - -PalResult PAL_CALL createSwapchainD3D12( - PalDevice* device, - PalQueue* queue, - PalSurface* surface, - const PalSwapchainCreateInfo* info, - PalSwapchain** outSwapchain) -{ - HRESULT result; - Surface* d3dSurface = (Surface*)surface; - Device* d3d12Device = (Device*)device; - Queue* d3dQueue = (Queue*)queue; - Swapchain* swapchain = nullptr; - PalBool isHDRColorspace = PAL_FALSE; - - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (d3dQueue->type != PAL_QUEUE_TYPE_GRAPHICS) { - return PAL_RESULT_INVALID_QUEUE; - } - - if (info->compositeAlpha != PAL_COMPOSITE_ALPHA_OPAQUE) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (info->presentMode == PAL_PRESENT_MODE_MAILBOX && info->imageCount < 3) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (info->imageCount > 8) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - swapchain = palAllocate(s_D3D12.allocator, sizeof(Swapchain), 0); - if (!swapchain) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - IDXGISwapChain1* swapchain1 = nullptr; - DXGI_SWAP_CHAIN_DESC1 desc = {0}; - desc.Width = info->width; - desc.Height = info->height; - desc.SampleDesc.Count = 1; - desc.BufferCount = info->imageCount; - desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - desc.Stereo = PAL_FALSE; - desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; - desc.Scaling = DXGI_SCALING_NONE; - - desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - if (info->presentMode == PAL_PRESENT_MODE_FIFO) { - swapchain->presentFlags = 0; - swapchain->syncInterval = 1; - - } else if (info->presentMode == PAL_PRESENT_MODE_IMMEDIATE) { - desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - swapchain->presentFlags = DXGI_PRESENT_ALLOW_TEARING; - swapchain->syncInterval = 0; - - } else { - desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - swapchain->presentFlags = DXGI_PRESENT_ALLOW_TEARING; - swapchain->syncInterval = 0; - } - - PalFormat imageFormat; - if (info->format == PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR) { - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - imageFormat = PAL_FORMAT_B8G8R8A8_UNORM; - - } else if (info->format == PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR) { - desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; - imageFormat = PAL_FORMAT_B8G8R8A8_SRGB; - - } else if (info->format == PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR) { - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; - imageFormat = PAL_FORMAT_R8G8B8A8_SRGB; - - } else if (info->format == PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10) { - desc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; - imageFormat = PAL_FORMAT_R16G16B16A16_SFLOAT; - isHDRColorspace = PAL_TRUE; - } - - swapchain->format = desc.Format; - swapchain->flags = desc.Flags; - result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( - s_D3D12.factory, - (IUnknown*)d3dQueue->handle, - d3dSurface->handle, - &desc, - nullptr, - nullptr, - &swapchain1); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } else if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - swapchain1->lpVtbl->QueryInterface(swapchain1, &IID_Swapchain, (void**)&swapchain->handle); - swapchain1->lpVtbl->Release(swapchain1); - - if (isHDRColorspace) { - swapchain->handle->lpVtbl->SetColorSpace1( - swapchain->handle, - DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); - } else { - swapchain->handle->lpVtbl->SetColorSpace1( - swapchain->handle, DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709); - } - - // get and cache swapchain images - swapchain->images = nullptr; - swapchain->images = palAllocate(s_D3D12.allocator, sizeof(Image) * info->imageCount, 0); - if (!swapchain->imageCount) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // fill all images with the creatio info - for (int i = 0; i < info->imageCount; i++) { - ID3D12Resource* tmp = nullptr; - swapchain->handle->lpVtbl->GetBuffer(swapchain->handle, i, &IID_Resource, (void**)&tmp); - - Image* image = &swapchain->images[i]; - image->belongsToSwapchain = PAL_TRUE; - image->device = d3d12Device; - image->handle = tmp; - - image->info.depthOrArraySize = 1; // always 1 - image->info.format = imageFormat; - image->info.usages = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; - image->info.height = info->height; - image->info.width = info->width; - image->info.mipLevelCount = 1; - image->info.sampleCount = PAL_SAMPLE_COUNT_1; // swapchain images are not multisampled - image->info.type = PAL_IMAGE_TYPE_2D; - } - - // get and cache window size for swapchain out of date error - RECT windowRect; - GetClientRect((HWND)d3dSurface->handle, &windowRect); - swapchain->windowWidth = windowRect.right - windowRect.left; - swapchain->windowWidth = windowRect.bottom - windowRect.top; - - swapchain->device = d3d12Device; - swapchain->queue = d3dQueue->handle; - swapchain->imageCount = info->imageCount; - *outSwapchain = (PalSwapchain*)swapchain; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) -{ - Swapchain* d3dSwapchain = (Swapchain*)swapchain; - d3dSwapchain->handle->lpVtbl->Release(d3dSwapchain->handle); - palFree(s_D3D12.allocator, d3dSwapchain->images); - palFree(s_D3D12.allocator, d3dSwapchain); -} - -PalImage* PAL_CALL getSwapchainImageD3D12( - PalSwapchain* swapchain, - uint32_t index) -{ - Swapchain* d3dSwapchain = (Swapchain*)swapchain; - if (index > d3dSwapchain->imageCount) { - return nullptr; - } - return (PalImage*)&d3dSwapchain->images[index]; -} - -PalResult PAL_CALL getNextSwapchainImageD3D12( - PalSwapchain* swapchain, - PalSwapchainNextImageInfo* info, - uint32_t* outIndex) -{ - uint32_t index = 0; - Swapchain* d3dSwapchain = (Swapchain*)swapchain; - ID3D12CommandQueue* queue = d3dSwapchain->queue; - - index = d3dSwapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3dSwapchain->handle); - if (info->fence) { - Fence* fence = (Fence*)info->fence; - fence->value++; - queue->lpVtbl->Signal(queue, fence->handle, fence->value); - } - - if (info->signalSemaphore) { - Semaphore* semaphore = (Semaphore*)info->signalSemaphore; - if (semaphore->isTimeline) { - queue->lpVtbl->Signal(queue, semaphore->handle, info->signalValue); - } else { - semaphore->value = 1; - queue->lpVtbl->Signal(queue, semaphore->handle, semaphore->value); - } - } - - *outIndex = index; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL presentSwapchainD3D12( - PalSwapchain* swapchain, - uint32_t imageIndex, - PalSemaphore* waitSemaphore) -{ - HRESULT result; - Swapchain* d3dSwapchain = (Swapchain*)swapchain; - ID3D12CommandQueue* queue = d3dSwapchain->queue; - - if (waitSemaphore) { - Semaphore* semaphore = (Semaphore*)waitSemaphore; - if (semaphore->isTimeline) { - queue->lpVtbl->Wait(queue, semaphore->handle, info->waitValue); - } else { - queue->lpVtbl->Wait(queue, semaphore->handle, semaphore->value); - semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); - semaphore->value = 0; - } - } - - result = d3dSwapchain->handle->lpVtbl->Present( - d3dSwapchain->handle, - d3dSwapchain->syncInterval, - d3dSwapchain->presentFlags); - - if (FAILED(result)) { - pollMessagesD3D12(d3dSwapchain->device); - if (result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET) { - return PAL_RESULT_DEVICE_LOST; - } - - // check if swapchain needs to be resize - RECT windowRect; - PalBool ret = GetClientRect((HWND)d3dSwapchain->surface->handle, &windowRect); - uint32_t w = windowRect.right - windowRect.left; - uint32_t h = windowRect.bottom - windowRect.top; - - if (!ret) { - return PAL_RESULT_SURFACE_LOST; - } - - if (w != d3dSwapchain->windowWidth || h != d3dSwapchain->windowHeight) { - return PAL_RESULT_SWAPCHAIN_OUT_OF_DATE; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL resizeSwapchainD3D12( - PalSwapchain* swapchain, - uint32_t newWidth, - uint32_t newHeight) -{ - HRESULT result; - Swapchain* d3dSwapchain = (Swapchain*)swapchain; - result = d3dSwapchain->handle->lpVtbl->ResizeBuffers( - d3dSwapchain->handle, - d3dSwapchain->imageCount, - newWidth, - newHeight, - d3dSwapchain->format, - d3dSwapchain->flags); - - if (FAILED(result)) { - pollMessagesD3D12(d3dSwapchain->device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // fill all images with the creatio info - for (int i = 0; i < d3dSwapchain->imageCount; i++) { - ID3D12Resource* tmp = nullptr; - d3dSwapchain->handle->lpVtbl->GetBuffer( - d3dSwapchain->handle, - i, - &IID_Resource, - (void**)&tmp); - - Image* image = &d3dSwapchain->images[i]; - image->handle = tmp; - image->info.height = newHeight; - image->info.width = newWidth; - } - - // get and cache window size for swapchain out of date error - RECT windowRect; - Surface* surface = d3dSwapchain->surface; - if (!GetClientRect((HWND)surface->handle, &windowRect)) { - return PAL_RESULT_SURFACE_LOST; - } - - d3dSwapchain->windowWidth = windowRect.right - windowRect.left; - d3dSwapchain->windowWidth = windowRect.bottom - windowRect.top; - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Shader -// ================================================== - -PalResult PAL_CALL createShaderD3D12( - PalDevice* device, - const PalShaderCreateInfo* info, - PalShader** outShader) -{ - Shader* shader = nullptr; - Device* d3d12Device = (Device*)device; - void* bytecode = nullptr; - - shader = palAllocate(s_D3D12.allocator, sizeof(Shader), 0); - bytecode = palAllocate(s_D3D12.allocator, info->bytecodeSize, 0); - if (!shader || !bytecode) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // allocate entries array - shader->entries = palAllocate(s_D3D12.allocator, sizeof(ShaderEntry) * info->entryCount, 0); - if (!shader->entries) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - for (int i = 0; i < info->entryCount; i++) { - ShaderEntry* entry = &shader->entries[i]; - - // clang-format off - if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || - info->entries[i].stage == PAL_SHADER_STAGE_TASK) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_GEOMETRY) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || - info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || - info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_MISS || - info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || - info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - // clang-format on - - convertToWcharD3D12(info->entries[i].entryName, entry->entryName); - entry->patchControlPoints = info->entries[i].patchControlPoints; - entry->stage = info->entries[i].stage; - } - - memcpy(bytecode, info->bytecode, info->bytecodeSize); - shader->byteCode.pShaderBytecode = bytecode; - shader->byteCode.BytecodeLength = info->bytecodeSize; - - shader->entryCount = info->entryCount; - *outShader = (PalShader*)shader; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyShaderD3D12(PalShader* shader) -{ - Shader* d3dShader = (Shader*)shader; - palFree(s_D3D12.allocator, (void*)d3dShader->byteCode.pShaderBytecode); - palFree(s_D3D12.allocator, d3dShader->entries); - palFree(s_D3D12.allocator, d3dShader); -} - -// ================================================== -// Command Pool And Buffer -// ================================================== - -PalResult PAL_CALL createCommandPoolD3D12( - PalDevice* device, - PalQueue* queue, - PalCommandPool** outPool) -{ - HRESULT result; - CommandPool* pool = nullptr; - Queue* d3dQueue = (Queue*)queue; - - pool = palAllocate(s_D3D12.allocator, sizeof(CommandPool), 0); - if (!pool) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - pool->size = 8; - pool->cmdBuffersData = nullptr; - uint32_t size = sizeof(CommandBufferData) * pool->size; - pool->cmdBuffersData = palAllocate(s_D3D12.allocator, size, 0); - if (!pool->cmdBuffersData) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - switch (d3dQueue->type) { - case PAL_QUEUE_TYPE_COMPUTE: { - pool->type = D3D12_COMMAND_LIST_TYPE_COMPUTE; - break; - } - - case PAL_QUEUE_TYPE_GRAPHICS: { - pool->type = D3D12_COMMAND_LIST_TYPE_DIRECT; - break; - } - - case PAL_QUEUE_TYPE_COPY: { - pool->type = D3D12_COMMAND_LIST_TYPE_COPY; - break; - } - } - - *outPool = (PalCommandPool*)pool; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) -{ - CommandPool* cmdPool = (CommandPool*)pool; - for (int i = 0; i < cmdPool->size; i++) { - if (!cmdPool->cmdBuffersData[i].used) { - continue; - } - - CommandBuffer* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; - cmdBuffer->handle->lpVtbl->Release(cmdBuffer->handle); - cmdBuffer->allocator->lpVtbl->Release(cmdBuffer->allocator); - } - - palFree(s_D3D12.allocator, cmdPool->cmdBuffersData); - palFree(s_D3D12.allocator, cmdPool); -} - -PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool) -{ - CommandPool* cmdPool = (CommandPool*)pool; - for (int i = 0; i < cmdPool->size; i++) { - if (!cmdPool->cmdBuffersData[i].used) { - continue; - } - - CommandBuffer* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; - cmdBuffer->handle->lpVtbl->Reset(cmdBuffer->handle, cmdBuffer->allocator, nullptr); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL allocateCommandBufferD3D12( - PalDevice* device, - PalCommandPool* pool, - PalCommandBufferType type, - PalCommandBuffer** outCmdBuffer) -{ - HRESULT result; - Device* d3d12Device = (Device*)device; - CommandBuffer* cmdBuffer = nullptr; - CommandPool* cmdPool = (CommandPool*)pool; - - cmdBuffer = palAllocate(s_D3D12.allocator, sizeof(CommandBuffer), 0); - if (!cmdBuffer) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(cmdBuffer, 0, sizeof(CommandBuffer)); - cmdBuffer->primary = PAL_TRUE; - - D3D12_COMMAND_LIST_TYPE cmdBufferType = cmdPool->type; - if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { - cmdBufferType = D3D12_COMMAND_LIST_TYPE_BUNDLE; - cmdBuffer->primary = PAL_FALSE; - } - - // create an allocator - result = d3d12Device->handle->lpVtbl->CreateCommandAllocator( - d3d12Device->handle, - cmdBufferType, - &IID_CommandAllocator, - (void**)&cmdBuffer->allocator); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // create the command list - ID3D12GraphicsCommandList* cmdList = nullptr; - result = d3d12Device->handle->lpVtbl->CreateCommandList( - d3d12Device->handle, - 0, - cmdBufferType, - cmdBuffer->allocator, - nullptr, - &IID_CommandList, - (void**)&cmdList); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // we need a tmp staging and gpu buffer if ray tracing is enabled - if (d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - D3D12_HEAP_PROPERTIES heapProps = {0}; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.VisibleNodeMask = 1; - heapProps.CreationNodeMask = 1; - - D3D12_RESOURCE_DESC bufferDesc = {0}; - bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - bufferDesc.Width = sizeof(D3D12_DISPATCH_RAYS_DESC); - bufferDesc.Height = 1; - bufferDesc.DepthOrArraySize = 1; - bufferDesc.MipLevels = 1; - bufferDesc.SampleDesc.Count = 1; - bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - - result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, - &heapProps, - 0, - &bufferDesc, - D3D12_RESOURCE_STATE_COMMON, - nullptr, - &IID_Resource, - (void**)&cmdBuffer->buffer); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // create staging buffer - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, - &heapProps, - 0, - &bufferDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - &IID_Resource, - (void**)&cmdBuffer->stagingBuffer); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - } - - result = cmdList->lpVtbl->QueryInterface( - cmdList, - &IID_CommandList6, - (void**)&cmdBuffer->handle); - - if (FAILED(result)) { - return PAL_RESULT_PLATFORM_FAILURE; - } - - cmdList->lpVtbl->Release(cmdList); - cmdBuffer->handle->lpVtbl->Close(cmdBuffer->handle); - - cmdBuffer->pool = cmdPool; - cmdBuffer->device = d3d12Device; - *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - CommandPool* pool = d3dCmdBuffer->pool; - CommandBufferData* data = findCmdBufferData(pool, d3dCmdBuffer); - if (data) { - d3dCmdBuffer->handle->lpVtbl->Release(d3dCmdBuffer->handle); - d3dCmdBuffer->allocator->lpVtbl->Release(d3dCmdBuffer->allocator); - - if (d3dCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - d3dCmdBuffer->buffer->lpVtbl->Release(d3dCmdBuffer->buffer); - d3dCmdBuffer->stagingBuffer->lpVtbl->Release(d3dCmdBuffer->stagingBuffer); - } - - palFree(s_D3D12.allocator, cmdBuffer); - data->cmdBuffer = nullptr; - data->used = PAL_FALSE; - } -} - -PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) -{ - HRESULT result; - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - result = d3dCmdBuffer->allocator->lpVtbl->Reset(d3dCmdBuffer->allocator); - if (FAILED(result)) { - pollMessagesD3D12(d3dCmdBuffer->device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - d3dCmdBuffer->handle->lpVtbl->Reset( - d3dCmdBuffer->handle, - d3dCmdBuffer->allocator, - nullptr); - - d3dCmdBuffer->handle->lpVtbl->Close(d3dCmdBuffer->handle); - d3dCmdBuffer->pipeline = nullptr; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL submitCommandBufferD3D12( - PalQueue* queue, - PalCommandBufferSubmitInfo* info) -{ - HRESULT result; - Queue* d3dQueue = (Queue*)queue; - ID3D12CommandQueue* queueHandle = d3dQueue->handle; - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)info->cmdBuffer; - - // wait semaphore - if (info->waitSemaphore) { - Semaphore* semaphore = (Semaphore*)info->waitSemaphore; - if (semaphore->isTimeline) { - queueHandle->lpVtbl->Wait(queueHandle, semaphore->handle, info->waitValue); - } else { - queueHandle->lpVtbl->Wait(queueHandle, semaphore->handle, semaphore->value); - semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); - semaphore->value = 0; - } - } - - - ID3D12CommandList* cmdLists[1] = { (ID3D12CommandList*)d3dCmdBuffer->handle }; - queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, cmdLists); - d3dQueue->fenceValue++; - queueHandle->lpVtbl->Signal(queueHandle, d3dQueue->fence, d3dQueue->fenceValue); - - if (info->fence) { - Fence* fence = (Fence*)info->fence; - fence->value++; - queueHandle->lpVtbl->Signal(queueHandle, fence->handle, fence->value); - } - - if (info->signalSemaphore) { - Semaphore* semaphore = (Semaphore*)info->signalSemaphore; - if (semaphore->isTimeline) { - queueHandle->lpVtbl->Signal(queueHandle, semaphore->handle, info->signalValue); - } else { - semaphore->value = 1; - queueHandle->lpVtbl->Signal(queueHandle, semaphore->handle, semaphore->value); - } - } - - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Command Recording -// ================================================== - -PalResult PAL_CALL cmdBeginD3D12( - PalCommandBuffer* cmdBuffer, - PalRenderingLayoutInfo* info) -{ - HRESULT result; - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - result = d3dCmdBuffer->allocator->lpVtbl->Reset(d3dCmdBuffer->allocator); - if (FAILED(result)) { - pollMessagesD3D12(d3dCmdBuffer->device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_COMMAND_BUFFER; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - d3dCmdBuffer->handle->lpVtbl->Reset( - d3dCmdBuffer->handle, - d3dCmdBuffer->allocator, - nullptr); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - d3dCmdBuffer->handle->lpVtbl->Close(d3dCmdBuffer->handle); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdExecuteCommandBufferD3D12( - PalCommandBuffer* primaryCmdBuffer, - PalCommandBuffer* secondaryCmdBuffer) -{ - CommandBuffer* d3dPrimaryCmdBuffer = (CommandBuffer*)primaryCmdBuffer; - CommandBuffer* d3dSecondaryCmdBuffer = (CommandBuffer*)secondaryCmdBuffer; - - d3dPrimaryCmdBuffer->handle->lpVtbl->ExecuteBundle( - d3dPrimaryCmdBuffer->handle, - (ID3D12GraphicsCommandList*)d3dSecondaryCmdBuffer->handle); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( - PalCommandBuffer* cmdBuffer, - PalFragmentShadingRateState* state) -{ - HRESULT result; - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3dCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - D3D12_SHADING_RATE shadingRate = shadingRateToD3D12(state->rate); - D3D12_SHADING_RATE_COMBINER combinerOps[2]; - for (int i = 0; i < 2; i++) { - combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); - } - - d3dCmdBuffer->handle->lpVtbl->RSSetShadingRate( - d3dCmdBuffer->handle, - shadingRate, - combinerOps); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawMeshTasksD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3dCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - d3dCmdBuffer->handle->lpVtbl->DispatchMesh( - d3dCmdBuffer->handle, - groupCountX, - groupCountY, - groupCountZ); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t drawCount) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3dCmdBuffer->device; - Buffer* d3dBuffer = (Buffer*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!d3dBuffer->hasIndirect) { - return PAL_RESULT_INVALID_BUFFER; - } - - d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->meshSignature, - drawCount, - d3dBuffer->handle, - 0, - nullptr, - 0); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3dCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - Buffer* d3dBuffer = (Buffer*)buffer; - Buffer* d3dCountBuffer = (Buffer*)countBuffer; - if (!d3dBuffer->hasIndirect || !d3dCountBuffer->hasIndirect) { - return PAL_RESULT_INVALID_BUFFER; - } - - d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->meshSignature, - maxDrawCount, - d3dBuffer->handle, - 0, - d3dCountBuffer->handle, - 0); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructureBuildInfo* info) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3dCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; - AccelerationStructure* tmpAs = (AccelerationStructure*)info->src; - AccelerationStructure* dstAs = (AccelerationStructure*)info->dst; - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; - D3D12_GPU_VIRTUAL_ADDRESS srcAsAddress = 0; - - if (tmpAs) { - srcAsAddress = tmpAs->address; - } - - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - geometries = palAllocate( - s_D3D12.allocator, - sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount, - 0); - - if (!geometries) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->geometryCount); - PalBool success = fillBuildInfoD3D12( - info, - geometries, - srcAsAddress, - dstAs->address, - &buildInfo); - - if (!success) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - d3dCmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( - d3dCmdBuffer->handle, - &buildInfo, - 0, - nullptr); - - palFree(s_D3D12.allocator, geometries); - - } else { - PalBool success = fillBuildInfoD3D12( - info, - nullptr, - srcAsAddress, - dstAs->address, - &buildInfo); - - if (!success) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - d3dCmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( - d3dCmdBuffer->handle, - &buildInfo, - 0, - nullptr); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBeginRenderingD3D12( - PalCommandBuffer* cmdBuffer, - PalRenderingInfo* info) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - D3D12_CPU_DESCRIPTOR_HANDLE colorAttachments[MAX_ATTACHMENTS]; - D3D12_CPU_DESCRIPTOR_HANDLE depthStencilAttachment; - D3D12_CPU_DESCRIPTOR_HANDLE* depthStencil = nullptr; - D3D12_CPU_DESCRIPTOR_HANDLE fsrAttachment; - - for (int i = 0; i < info->colorAttachentCount; i++) { - ImageView* tmp = (ImageView*)info->colorAttachments[i].imageView; - - RTVHeapAllocator* allocator = &tmp->device->rtvAllocator; - uint32_t size = allocator->incrementSize; - uint64_t base = allocator->baseOffset; - colorAttachments[i].ptr = getDescriptorHandleD3D12(tmp->heapIndex, size, base); - } - - if (info->depthStencilAttachment) { - ImageView* tmp = (ImageView*)info->depthStencilAttachment->imageView; - DSVHeapAllocator* allocator = &tmp->device->dsvAllocator; - uint32_t size = allocator->incrementSize; - uint64_t base = allocator->baseOffset; - depthStencilAttachment.ptr = getDescriptorHandleD3D12(tmp->heapIndex, size, base); - depthStencil = &depthStencilAttachment; - } - - d3dCmdBuffer->handle->lpVtbl->OMSetRenderTargets( - d3dCmdBuffer->handle, - info->colorAttachentCount, - colorAttachments, - PAL_FALSE, - depthStencil); - - for (int i = 0; i < info->colorAttachentCount; i++) { - if (info->colorAttachments[i].loadOp == PAL_LOAD_OP_CLEAR) { - float color[4]; - color[0] = info->colorAttachments[i].clearValue.color[0]; - color[1] = info->colorAttachments[i].clearValue.color[1]; - color[2] = info->colorAttachments[i].clearValue.color[2]; - color[3] = info->colorAttachments[i].clearValue.color[3]; - - d3dCmdBuffer->handle->lpVtbl->ClearRenderTargetView( - d3dCmdBuffer->handle, - colorAttachments[i], color, 0, nullptr); - } - } - - if (info->depthStencilAttachment) { - D3D12_CLEAR_FLAGS clearFlags = 0; - UINT8 stencil = 0; - float depth = 0; - - if (info->depthStencilAttachment->loadOp == PAL_LOAD_OP_CLEAR) { - depth = info->depthStencilAttachment->clearValue.depth; - clearFlags |= D3D12_CLEAR_FLAG_DEPTH; - } - - if (info->depthStencilAttachment->stencilLoadOp == PAL_LOAD_OP_CLEAR) { - stencil = (UINT8)info->depthStencilAttachment->clearValue.stencil; - clearFlags |= D3D12_CLEAR_FLAG_STENCIL; - } - - d3dCmdBuffer->handle->lpVtbl->ClearDepthStencilView( - d3dCmdBuffer->handle, - depthStencilAttachment, - clearFlags, - depth, - stencil, - 0, - nullptr); - } - - if (info->fragmentShadingRateAttachment) { - ImageView* tmp = (ImageView*)info->fragmentShadingRateAttachment->imageView; - d3dCmdBuffer->handle->lpVtbl->RSSetShadingRateImage( - d3dCmdBuffer->handle, - tmp->image->handle); - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer) -{ - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdCopyBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* dst, - PalBuffer* src, - PalBufferCopyInfo* copyInfo) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* dstbuffer = (Buffer*)dst; - Buffer* srcBuffer = (Buffer*)src; - - d3dCmdBuffer->handle->lpVtbl->CopyBufferRegion( - d3dCmdBuffer->handle, - dstbuffer->handle, - copyInfo->dstOffset, - srcBuffer->handle, - copyInfo->srcOffset, - copyInfo->size); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdCopyBufferToImageD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* dstImage, - PalBuffer* srcBuffer, - PalBufferImageCopyInfo* copyInfo) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Image* dst = (Image*)dstImage; - Buffer* src = (Buffer*)srcBuffer; - - D3D12_TEXTURE_COPY_LOCATION dstLocation = {0}; - dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dstLocation.pResource = dst->handle; - - D3D12_TEXTURE_COPY_LOCATION srcLocation = {0}; - srcLocation.pResource = src->handle; - srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - D3D12_PLACED_SUBRESOURCE_FOOTPRINT* footPrint = &srcLocation.PlacedFootprint; - - footPrint->Offset = copyInfo->bufferOffset; - footPrint->Footprint.Width = copyInfo->imageWidth; - footPrint->Footprint.Height = copyInfo->imageHeight; - footPrint->Footprint.Depth = copyInfo->imageDepth; - footPrint->Footprint.Format = formatToD3D12(dst->info.format); - - uint32_t imageFormatSize = getFormatSizeD3D12(dst->info.format); - uint64_t rowPitch = alignD3D12((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); - footPrint->Footprint.RowPitch = (UINT)rowPitch; - - uint32_t planeCount = 1; - if (copyInfo->imageAspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { - planeCount = 2; - } - - D3D12_BOX box = {0}; - box.right = copyInfo->imageWidth; - box.bottom = copyInfo->imageHeight; - box.back = copyInfo->imageDepth; - - uint32_t level = copyInfo->ImageMipLevel; - uint32_t startLayer = copyInfo->ImageStartArrayLayer; - uint32_t layerCount = copyInfo->ImageArrayLayerCount; - uint32_t maxLayers = dst->info.depthOrArraySize; - uint32_t maxLevels = dst->info.mipLevelCount; - - for (uint32_t plane = 0; plane < planeCount; plane++) { - for (uint32_t layer = startLayer; layer < startLayer + layerCount; layer++) { - uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); - - dstLocation.SubresourceIndex = index; - d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle, - &dstLocation, - copyInfo->imageOffsetX, - copyInfo->imageOffsetY, - copyInfo->imageOffsetZ, - &srcLocation, - &box); - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdCopyImageD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* dst, - PalImage* src, - PalImageCopyInfo* copyInfo) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Image* dstImage = (Image*)dst; - Image* srcImage = (Image*)src; - - D3D12_TEXTURE_COPY_LOCATION dstLocation = {0}; - dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dstLocation.pResource = dstImage->handle; - - D3D12_TEXTURE_COPY_LOCATION srcLocation = {0}; - srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - srcLocation.pResource = srcImage->handle; - - D3D12_BOX box = {0}; - box.left = copyInfo->srcOffsetX; - box.top = copyInfo->srcOffsetY; - box.front = copyInfo->srcOffsetZ; - box.right = copyInfo->srcOffsetX + copyInfo->width; - box.bottom = copyInfo->srcOffsetY + copyInfo->height; - box.back = copyInfo->srcOffsetZ + copyInfo->depth; - - uint32_t planeCount = 1; - uint32_t layerCount = copyInfo->arrayLayerCount; - if (copyInfo->aspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { - planeCount = 2; - } - - uint32_t dstLevel = copyInfo->dstMipLevel; - uint32_t dstStartLayer = copyInfo->dstStartArrayLayer; - uint32_t dstMaxLayers = dstImage->info.depthOrArraySize; - uint32_t dstMaxLevels = dstImage->info.mipLevelCount; - - uint32_t srcLevel = copyInfo->srcMipLevel; - uint32_t srcStartLayer = copyInfo->srcStartArrayLayer; - uint32_t srcMaxLayers = srcImage->info.depthOrArraySize; - uint32_t srcMaxLevels = srcImage->info.mipLevelCount; - - for (uint32_t plane = 0; plane < planeCount; plane++) { - for (uint32_t layer = 0; layer + layerCount; layer++) { - // clang-format off - uint32_t dstIndex = dstLevel + (dstStartLayer + layer * dstMaxLevels) + (plane * dstMaxLevels * dstMaxLayers); - uint32_t srcIndex = srcLevel + (srcStartLayer + layer * srcMaxLevels) + (plane * srcMaxLevels * srcMaxLayers); - // clang-format on - - dstLocation.SubresourceIndex = dstIndex; - srcLocation.SubresourceIndex = srcIndex; - - d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle, - &dstLocation, - copyInfo->dstOffsetX, - copyInfo->dstOffsetY, - copyInfo->dstOffsetZ, - &srcLocation, - &box); - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdCopyImageToBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* dstBuffer, - PalImage* srcImage, - PalBufferImageCopyInfo* copyInfo) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* dst = (Buffer*)dstBuffer; - Image* src = (Image*)srcImage; - - D3D12_TEXTURE_COPY_LOCATION dstLocation = {0}; - dstLocation.pResource = dst->handle; - dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - D3D12_PLACED_SUBRESOURCE_FOOTPRINT* footPrint = &dstLocation.PlacedFootprint; - footPrint->Offset = copyInfo->bufferOffset; - footPrint->Footprint.Width = copyInfo->imageWidth; - footPrint->Footprint.Height = copyInfo->imageHeight; - footPrint->Footprint.Depth = copyInfo->imageDepth; - footPrint->Footprint.Format = formatToD3D12(src->info.format); - - D3D12_TEXTURE_COPY_LOCATION srcLocation = {0}; - srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - srcLocation.pResource = src->handle; - - uint32_t imageFormatSize = getFormatSizeD3D12(src->info.format); - uint64_t rowPitch = alignD3D12((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); - footPrint->Footprint.RowPitch = (UINT)rowPitch; - - D3D12_BOX box = {0}; - box.left = copyInfo->imageOffsetX; - box.top = copyInfo->imageOffsetY; - box.front = copyInfo->imageOffsetZ; - box.right = copyInfo->imageOffsetX + copyInfo->imageWidth; - box.bottom = copyInfo->imageOffsetY + copyInfo->imageHeight; - box.back = copyInfo->imageOffsetX + copyInfo->imageDepth; - - uint32_t planeCount = 1; - if (copyInfo->imageAspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { - planeCount = 2; - } - - uint32_t level = copyInfo->ImageMipLevel; - uint32_t startLayer = copyInfo->ImageStartArrayLayer; - uint32_t layerCount = copyInfo->ImageArrayLayerCount; - uint32_t maxLayers = src->info.depthOrArraySize; - uint32_t maxLevels = src->info.mipLevelCount; - - for (uint32_t plane = 0; plane < planeCount; plane++) { - for (uint32_t layer = startLayer; layer < startLayer + layerCount; layer++) { - uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); - - srcLocation.SubresourceIndex = index; - d3dCmdBuffer->handle->lpVtbl->CopyTextureRegion( - d3dCmdBuffer->handle, - &dstLocation, - 0, - 0, - 0, - &srcLocation, - &box); - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBindPipelineD3D12( - PalCommandBuffer* cmdBuffer, - PalPipeline* pipeline) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Pipeline* d3dPipeline = (Pipeline*)pipeline; - - if (d3dPipeline->type == RAY_TRACING_PIPELINE) { - d3dCmdBuffer->handle->lpVtbl->SetPipelineState1( - d3dCmdBuffer->handle, - d3dPipeline->handle); - - d3dCmdBuffer->handle->lpVtbl->SetComputeRootSignature( - d3dCmdBuffer->handle, - d3dPipeline->layout->handle); - - } else { - d3dCmdBuffer->handle->lpVtbl->SetPipelineState( - d3dCmdBuffer->handle, - d3dPipeline->handle); - - if (d3dPipeline->type == GRAPHICS_PIPELINE) { - d3dCmdBuffer->handle->lpVtbl->IASetPrimitiveTopology( - d3dCmdBuffer->handle, - d3dPipeline->topology); - - d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootSignature( - d3dCmdBuffer->handle, - d3dPipeline->layout->handle); - - if (d3dPipeline->hasFsr) { - d3dCmdBuffer->handle->lpVtbl->RSSetShadingRate( - d3dCmdBuffer->handle, - d3dPipeline->shadingRate, - d3dPipeline->combinerOps); - } - } - } - - d3dCmdBuffer->pipeline = d3dPipeline; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetViewportD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalViewport* viewports) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - D3D12_VIEWPORT cachedViewport; - D3D12_VIEWPORT* d3dViewports = nullptr; - - if (count > 1) { - d3dViewports = palAllocate(s_D3D12.allocator, sizeof(D3D12_VIEWPORT) * count, 0); - if (!d3dViewports) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - } else { - d3dViewports = &cachedViewport; - } - - for (int i = 0; i < count; i++) { - D3D12_VIEWPORT* tmp = &d3dViewports[i]; - tmp->TopLeftX = viewports[i].x; - tmp->TopLeftY = viewports[i].y; - tmp->Width = viewports[i].width; - tmp->Height = viewports[i].height; - tmp->MinDepth = viewports[i].minDepth; - tmp->MaxDepth = viewports[i].maxDepth; - } - - d3dCmdBuffer->handle->lpVtbl->RSSetViewports(d3dCmdBuffer->handle, count, d3dViewports); - if (count > 1) { - palFree(s_D3D12.allocator, d3dViewports); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetScissorsD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t count, - PalRect2D* scissors) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - D3D12_RECT cachedScissor; - D3D12_RECT* d3dScissors = nullptr; - - if (count > 1) { - d3dScissors = palAllocate(s_D3D12.allocator, sizeof(D3D12_RECT) * count, 0); - if (!d3dScissors) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - } else { - d3dScissors = &cachedScissor; - } - - for (int i = 0; i < count; i++) { - D3D12_RECT* tmp = &d3dScissors[i]; - tmp->left = scissors[i].x; - tmp->top = scissors[i].y; - tmp->right = scissors[i].width; - tmp->bottom = scissors[i].height; - } - - d3dCmdBuffer->handle->lpVtbl->RSSetScissorRects(d3dCmdBuffer->handle, count, d3dScissors); - if (count > 1) { - palFree(s_D3D12.allocator, d3dScissors); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBindVertexBuffersD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t firstSlot, - uint32_t count, - PalBuffer** buffers, - uint64_t* offsets) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Pipeline* pipeline = d3dCmdBuffer->pipeline; - D3D12_VERTEX_BUFFER_VIEW cachedView = {0}; - D3D12_VERTEX_BUFFER_VIEW* views = nullptr; - - if (!pipeline) { - return PAL_RESULT_INVALID_OPERATION; - } - - if (count > 1) { - views = palAllocate(s_D3D12.allocator, sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, 0); - if (!views) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - } else { - views = &cachedView; - } - - for (int i = 0; i < count; i++) { - Buffer* tmp = (Buffer*)buffers[i]; - views[i].BufferLocation = tmp->handle->lpVtbl->GetGPUVirtualAddress(tmp->handle); - views[i].BufferLocation = views[i].BufferLocation + offsets[i]; - views[i].SizeInBytes = (UINT)tmp->size; - views[i].StrideInBytes = pipeline->strides[i]; - } - - d3dCmdBuffer->handle->lpVtbl->IASetVertexBuffers( - d3dCmdBuffer->handle, - firstSlot, - count, - views); - - if (count > 1) { - palFree(s_D3D12.allocator, views); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBindIndexBufferD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint64_t offset, - PalIndexType type) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - D3D12_INDEX_BUFFER_VIEW view = {0}; - Buffer* indexBuffer = (Buffer*)buffer; - - view.BufferLocation = indexBuffer->handle->lpVtbl->GetGPUVirtualAddress(indexBuffer->handle); - view.BufferLocation = view.BufferLocation + offset; - view.SizeInBytes = (UINT)indexBuffer->size; - if (type == PAL_INDEX_TYPE_UINT16) { - view.Format = DXGI_FORMAT_R16_UINT; - } else { - view.Format = DXGI_FORMAT_R32_UINT; - } - - d3dCmdBuffer->handle->lpVtbl->IASetIndexBuffer(d3dCmdBuffer->handle, &view); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t vertexCount, - uint32_t instanceCount, - uint32_t firstVertex, - uint32_t firstInstance) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - d3dCmdBuffer->handle->lpVtbl->DrawInstanced( - d3dCmdBuffer->handle, - vertexCount, - instanceCount, - firstVertex, - firstInstance); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3dCmdBuffer->device; - Buffer* d3dBuffer = (Buffer*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!d3dBuffer->hasIndirect) { - return PAL_RESULT_INVALID_BUFFER; - } - - d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->drawSignature, - count, - d3dBuffer->handle, - 0, - nullptr, - 0); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3dCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - Buffer* d3dBuffer = (Buffer*)buffer; - Buffer* d3dCountBuffer = (Buffer*)countBuffer; - if (!d3dBuffer->hasIndirect || !d3dCountBuffer->hasIndirect) { - return PAL_RESULT_INVALID_BUFFER; - } - - d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->drawSignature, - maxDrawCount, - d3dBuffer->handle, - 0, - d3dCountBuffer->handle, - 0); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawIndexedD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t indexCount, - uint32_t instanceCount, - uint32_t firstIndex, - int32_t vertexOffset, - uint32_t firstInstance) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - d3dCmdBuffer->handle->lpVtbl->DrawIndexedInstanced( - d3dCmdBuffer->handle, - indexCount, - instanceCount, - firstIndex, - vertexOffset, - firstInstance); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - uint32_t count) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3dCmdBuffer->device; - Buffer* d3dBuffer = (Buffer*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!d3dBuffer->hasIndirect) { - return PAL_RESULT_INVALID_BUFFER; - } - - d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->drawIndexedSignature, - count, - d3dBuffer->handle, - 0, - nullptr, - 0); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalBuffer* countBuffer, - uint32_t maxDrawCount) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3dCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - Buffer* d3dBuffer = (Buffer*)buffer; - Buffer* d3dCountBuffer = (Buffer*)countBuffer; - if (!d3dBuffer->hasIndirect || !d3dCountBuffer->hasIndirect) { - return PAL_RESULT_INVALID_BUFFER; - } - - d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->drawIndexedSignature, - maxDrawCount, - d3dBuffer->handle, - 0, - d3dCountBuffer->handle, - 0); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalAccelerationStructure* as, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - if (!(d3dCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - AccelerationStructure* d3dAs = (AccelerationStructure*)as; - D3D12_RESOURCE_BARRIER barrier = {0}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrier.UAV.pResource = d3dAs->handle; - - d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdImageBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalImage* image, - PalImageSubresourceRange* subresourceRange, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Image* d3dImage = (Image*)image; - D3D12_RESOURCE_STATES old, new; - D3D12_RESOURCE_BARRIER barrier = {0}; - - old = barrierToD3D12( - oldUsageStateInfo->shaderStageCount, - oldUsageStateInfo->usageState, - oldUsageStateInfo->shaderStages); - - new = barrierToD3D12( - newUsageStateInfo->shaderStageCount, - newUsageStateInfo->usageState, - newUsageStateInfo->shaderStages); - - // read/write barrier without transition - if (old == new && old == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrier.UAV.pResource = d3dImage->handle; - d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); - return PAL_RESULT_SUCCESS; - } - - uint32_t planeCount = 1; // for color or depth - if (subresourceRange->aspect == PAL_IMAGE_ASPECT_DEPTH_STENCIL) { - planeCount = 2; - } - - D3D12_RESOURCE_BARRIER* barriers = nullptr; - uint32_t levelCount = subresourceRange->mipLevelCount; - uint32_t layerCount = subresourceRange->layerArrayCount; - - uint32_t startLevel = subresourceRange->startMipLevel; - uint32_t startLayer = subresourceRange->startArrayLayer; - uint32_t maxLevels = d3dImage->info.mipLevelCount; - uint32_t maxLayers = d3dImage->info.depthOrArraySize; - uint32_t barrierCount = layerCount * levelCount * planeCount; - - if (startLevel == 0 && levelCount == maxLevels && startLayer == 0 && layerCount == maxLayers) { - // full resource - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = d3dImage->handle; - barrier.Transition.StateBefore = old; - barrier.Transition.StateAfter = new; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - - d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); - return PAL_RESULT_SUCCESS; - } - - if (layerCount == 1 && layerCount == 1 && planeCount == 1) { - // single plane - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = d3dImage->handle; - barrier.Transition.StateBefore = old; - barrier.Transition.StateAfter = new; - barrier.Transition.Subresource = startLevel + startLayer * maxLevels; - - d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); - return PAL_RESULT_SUCCESS; - } - - barriers = palAllocate(s_D3D12.allocator, sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, 0); - if (!barriers) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - uint32_t count = 0; - for (uint32_t plane = 0; plane < planeCount; plane++) { - for (uint32_t layer = startLayer; layer < startLayer + layerCount; layer++) { - for (uint32_t level = startLevel; level < startLevel + levelCount; level++) { - uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); - - D3D12_RESOURCE_BARRIER* tmp = &barriers[count++]; - tmp->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - tmp->Transition.pResource = d3dImage->handle; - tmp->Transition.StateBefore = old; - tmp->Transition.StateAfter = new; - tmp->Transition.Subresource = index; - } - } - } - - d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, barrierCount, barriers); - palFree(s_D3D12.allocator, barriers); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBufferBarrierD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer, - PalUsageStateInfo* oldUsageStateInfo, - PalUsageStateInfo* newUsageStateInfo) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Buffer* d3dBuffer = (Buffer*)buffer; - D3D12_RESOURCE_STATES old, new; - if (!d3dBuffer->canChangeState) { - return PAL_RESULT_SUCCESS; - } - - old = barrierToD3D12( - oldUsageStateInfo->shaderStageCount, - oldUsageStateInfo->usageState, - oldUsageStateInfo->shaderStages); - - new = barrierToD3D12( - newUsageStateInfo->shaderStageCount, - newUsageStateInfo->usageState, - newUsageStateInfo->shaderStages); - - D3D12_RESOURCE_BARRIER barrier = {0}; - if (old == new && D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrier.UAV.pResource = d3dBuffer->handle; - } else { - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = d3dBuffer->handle; - barrier.Transition.StateBefore = old; - barrier.Transition.StateAfter = new; - } - - d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDispatchD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - d3dCmdBuffer->handle->lpVtbl->Dispatch( - d3dCmdBuffer->handle, - groupCountX, - groupCountY, - groupCountZ); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdDispatchBaseD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ) -{ - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdDispatchIndirectD3D12( - PalCommandBuffer* cmdBuffer, - PalBuffer* buffer) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Device* device = d3dCmdBuffer->device; - Buffer* d3dBuffer = (Buffer*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!d3dBuffer->hasIndirect) { - return PAL_RESULT_INVALID_BUFFER; - } - - d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->dispatchSignature, - 1, // one dispatch - d3dBuffer->handle, - 0, - nullptr, - 0); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdTraceRaysD3D12( - PalCommandBuffer* cmdBuffer, - PalShaderBindingTable* sbt, - uint32_t raygenIndex, - uint32_t width, - uint32_t height, - uint32_t depth) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; - if (!(d3dCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - uint64_t stride = d3dSbt->raygen.region.StrideInBytes; - D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; - raygenAddress.SizeInBytes = d3dSbt->raygen.region.SizeInBytes; - raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * stride; - - // we need to make sure the SBT is up to date - commitShaderbindingTableUpdateD3D12(d3dCmdBuffer, d3dSbt); - - D3D12_DISPATCH_RAYS_DESC desc = {0}; - desc.Width = width; - desc.Height = height; - desc.Depth = depth; - desc.RayGenerationShaderRecord = raygenAddress; - desc.HitGroupTable = d3dSbt->hit.region; - desc.MissShaderTable = d3dSbt->miss.region; - desc.CallableShaderTable = d3dSbt->callable.region; - - d3dCmdBuffer->handle->lpVtbl->DispatchRays(d3dCmdBuffer->handle, &desc); - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdTraceRaysIndirectD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t raygenIndex, - PalShaderBindingTable* sbt, - PalBuffer* buffer) -{ - HRESULT result; - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - ShaderBindingTable* d3dSbt = (ShaderBindingTable*)sbt; - Buffer* d3dBuffer = (Buffer*)buffer; - Device* device = (Device*)d3dCmdBuffer->device; - D3D12_DISPATCH_RAYS_DESC desc = {0}; - - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (!d3dBuffer->hasIndirect) { - return PAL_RESULT_INVALID_BUFFER; - } - - // we need to make sure the SBT is up to date - commitShaderbindingTableUpdateD3D12(d3dCmdBuffer, d3dSbt); - - // Buffer is mappable - void* ptr = nullptr; - result = d3dBuffer->handle->lpVtbl->Map(d3dBuffer->handle, 0, nullptr, &ptr); - if (FAILED(result)) { - return PAL_RESULT_MEMORY_MAP_FAILED; - } - - // copy indirect parameters from the buffer - PalDispatchIndirectData data = {0}; - memcpy(&data, ptr, sizeof(PalDispatchIndirectData)); - d3dBuffer->handle->lpVtbl->Unmap(d3dBuffer->handle, 0, nullptr); - - desc.Width = data.groupCountXOrWidth; - desc.Height = data.groupCountXOrHeight; - desc.Depth = data.groupCountXOrDepth; - - uint64_t stride = d3dSbt->raygen.region.StrideInBytes; - D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; - raygenAddress.SizeInBytes = d3dSbt->raygen.region.SizeInBytes; - raygenAddress.StartAddress = d3dSbt->baseAddress + raygenIndex * stride; - - desc.RayGenerationShaderRecord = raygenAddress; - desc.HitGroupTable = d3dSbt->hit.region; - desc.MissShaderTable = d3dSbt->miss.region; - desc.CallableShaderTable = d3dSbt->callable.region; - - // fill the data into the tmp upload buffer of the command buffer - ptr = nullptr; - d3dCmdBuffer->stagingBuffer->lpVtbl->Map(d3dCmdBuffer->stagingBuffer, 0, nullptr, &ptr); - memcpy(ptr, &desc, sizeof(D3D12_DISPATCH_RAYS_DESC)); - d3dCmdBuffer->stagingBuffer->lpVtbl->Unmap(d3dCmdBuffer->stagingBuffer, 0, nullptr); - - // copy to the gpu tmp buffer of the command buffer and execute with that - d3dCmdBuffer->handle->lpVtbl->CopyBufferRegion( - d3dCmdBuffer->handle, - d3dCmdBuffer->buffer, - 0, - d3dCmdBuffer->stagingBuffer, - 0, - sizeof(D3D12_DISPATCH_RAYS_DESC)); - - // put a memory barrier - D3D12_RESOURCE_BARRIER barrier = {0}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - barrier.Transition.pResource = d3dCmdBuffer->buffer; - d3dCmdBuffer->handle->lpVtbl->ResourceBarrier(d3dCmdBuffer->handle, 1, &barrier); - - d3dCmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3dCmdBuffer->handle, - device->raySignature, - 1, - d3dCmdBuffer->buffer, - 0, - nullptr, - 0); - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdBindDescriptorSetD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t setIndex, - PalDescriptorSet* set) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Pipeline* pipeline = d3dCmdBuffer->pipeline; - DescriptorSet* d3dSet = (DescriptorSet*)set; - DescriptorPool* pool = d3dSet->pool; - - // bind heaps - uint32_t heapCount = 0; - ID3D12DescriptorHeap* heaps[2]; - if (pool->hasResourceHeap) { - heaps[heapCount++] = pool->resourceHeap.handle; - } - - if (pool->hasSamplerHeap) { - heaps[heapCount++] = pool->samplerHeap.handle; - } - d3dCmdBuffer->handle->lpVtbl->SetDescriptorHeaps(d3dCmdBuffer->handle, heapCount, heaps); - - // bind resource descriptor table - uint32_t resourceCount = d3dSet->layout->bindingCount - d3dSet->layout->samplerCount; - uint32_t baseIndex = setIndex; - if (pipeline->layout->constantIndex != UINT32_MAX) { - // If push constant was used to create the pipeline layout - // slot 0 will be reserve for it - baseIndex++; - } - - if (resourceCount) { - D3D12_GPU_DESCRIPTOR_HANDLE base; - base.ptr = getDescriptorHandleD3D12( - d3dSet->resourceOffset, - pool->resourceHeap.incrementSize, - pool->resourceHeap.gpuBase); - - if (pipeline->type == GRAPHICS_PIPELINE) { - d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( - d3dCmdBuffer->handle, - baseIndex, // base set index is resource first before sampler - base); - - } else { - // ray tracing uses the compute path - d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( - d3dCmdBuffer->handle, - baseIndex, // base set index is resource first before sampler - base); - } - - baseIndex++; - } - - // bind sampler descriptor table - if (d3dSet->layout->samplerCount) { - D3D12_GPU_DESCRIPTOR_HANDLE base; - base.ptr = getDescriptorHandleD3D12( - d3dSet->samplerOffset, - pool->samplerHeap.incrementSize, - pool->samplerHeap.gpuBase); - - if (pipeline->type == GRAPHICS_PIPELINE) { - d3dCmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( - d3dCmdBuffer->handle, - baseIndex, - base); - - } else { - // ray tracing uses the compute path - d3dCmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( - d3dCmdBuffer->handle, - baseIndex, - base); - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdPushConstantsD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t shaderStageCount, - PalShaderStage* shaderStages, - uint32_t offset, - uint32_t size, - const void* value) -{ - CommandBuffer* d3dCmdBuffer = (CommandBuffer*)cmdBuffer; - Pipeline* pipeline = d3dCmdBuffer->pipeline; - - if (pipeline->layout->constantIndex != UINT32_MAX) { - if (pipeline->type == GRAPHICS_PIPELINE) { - d3dCmdBuffer->handle->lpVtbl->SetGraphicsRoot32BitConstants( - d3dCmdBuffer->handle, - pipeline->layout->constantIndex, - size / 4, - value, - offset / 4); - - } else { - // ray tracing uses the compute path - d3dCmdBuffer->handle->lpVtbl->SetComputeRoot32BitConstants( - d3dCmdBuffer->handle, - pipeline->layout->constantIndex, - size / 4, - value, - offset / 4); - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetCullModeD3D12( - PalCommandBuffer* cmdBuffer, - PalCullMode cullMode) -{ - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdSetFrontFaceD3D12( - PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace) -{ - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( - PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology) -{ - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdSetDepthTestEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable) -{ - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable) -{ - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdSetStencilOpD3D12( - PalCommandBuffer* cmdBuffer, - PalStencilFaceFlags faceMask, - PalStencilOp failOp, - PalStencilOp passOp, - PalStencilOp depthFailOp, - PalCompareOp compareOp) -{ - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; -} - -// ================================================== -// Acceleration Structure -// ================================================== - -// ================================================== -// Buffer -// ================================================== - -PalResult PAL_CALL createBufferD3D12( - PalDevice* device, - const PalBufferCreateInfo* info, - PalBuffer** outBuffer) -{ - HRESULT result; - Buffer* buffer = nullptr; - Device* d3d12Device = (Device*)device; - - if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - buffer = palAllocate(s_D3D12.allocator, sizeof(Buffer), 0); - if (!buffer) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(buffer, 0, sizeof(Buffer)); - buffer->desc.Width = info->size; - buffer->desc.Height = 1; - buffer->desc.DepthOrArraySize = 1; - buffer->desc.MipLevels = 1; - buffer->desc.SampleDesc.Count = 1; - buffer->desc.SampleDesc.Quality = 0; - buffer->desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - buffer->desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - - if (info->usages & PAL_BUFFER_USAGE_STORAGE) { - buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - } - - if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - buffer->isAccelerationStructure = PAL_TRUE; - } - - if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { - buffer->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - buffer->isScratch = PAL_TRUE; - } - - if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - buffer->supportsAddress = PAL_TRUE; - } - - if (info->usages & PAL_BUFFER_USAGE_INDIRECT) { - buffer->hasIndirect = PAL_TRUE; - } - - buffer->device = d3d12Device; - buffer->size = info->size; - *outBuffer = (PalBuffer*)buffer; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyBufferD3D12(PalBuffer* buffer) -{ - Buffer* d3dBuffer = (Buffer*)buffer; - // check if memory has been attached to the buffer - if (d3dBuffer->handle) { - d3dBuffer->handle->lpVtbl->Release(d3dBuffer->handle); - } - palFree(s_D3D12.allocator, d3dBuffer); -} - -PalResult PAL_CALL getBufferMemoryRequirementsD3D12( - PalBuffer* buffer, - PalMemoryRequirements* requirements) -{ - Buffer* d3dBuffer = (Buffer*)buffer; - ID3D12Device5* device = d3dBuffer->device->handle; - - D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; - D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; - allocationInfo = *device->lpVtbl->GetResourceAllocationInfo( - device, - &__ret, - 0, - 1, - &d3dBuffer->desc); - - // d3d12 allows buffers to be used with all memory heap types - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = PAL_TRUE; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = PAL_TRUE; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = PAL_TRUE; - - requirements->alignment = allocationInfo.Alignment; - requirements->size = allocationInfo.SizeInBytes; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( - PalDevice* device, - uint32_t instanceCount, - uint64_t* outSize) -{ - *outSize = sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * instanceCount; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( - PalDevice* device, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize) -{ - uint32_t imageFormatSize = getFormatSizeD3D12(imageFormat); - uint32_t rowPitch = alignD3D12((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); - uint32_t bufferImageHeight = 0; - - if (copyInfo->bufferImageHeight) { - bufferImageHeight = copyInfo->bufferImageHeight; - } else { - bufferImageHeight = copyInfo->imageHeight; - } - - *outBufferRowLength = rowPitch; - *outBufferImageHeight = bufferImageHeight; - *outSize = (uint64_t)rowPitch * bufferImageHeight * copyInfo->imageDepth; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL writeToInstanceBufferD3D12( - PalDevice* device, - void* ptr, - PalAccelerationStructureInstance* instances, - uint32_t instanceCount) -{ - D3D12_RAYTRACING_INSTANCE_DESC* data = ptr; - for (int i = 0; i < instanceCount; i++) { - PalAccelerationStructureInstance* src = &instances[i]; - D3D12_RAYTRACING_INSTANCE_DESC* dst = &data[i]; - AccelerationStructure* as = (AccelerationStructure*)src->blas; - - dst->InstanceMask = src->mask; - dst->InstanceID = src->instanceId; - dst->AccelerationStructure = as->address; - dst->InstanceContributionToHitGroupIndex = src->hitGroupOffset; - dst->Flags = instanceFlagsToD3D12(src->flags); - memcpy(dst->Transform, src->transform, sizeof(float) * 12); - } - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( - PalDevice* device, - void* ptr, - void* srcData, - PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo) -{ - uint32_t imageFormatSize = getFormatSizeD3D12(imageFormat); - uint32_t srcRowPitch = copyInfo->imageWidth * imageFormatSize; - const uint32_t dstSlicePitch = copyInfo->bufferRowLength * copyInfo->bufferImageHeight; - const uint32_t srcSlicePitch = srcRowPitch * copyInfo->imageHeight; - - // manually offset the buffer with the provided offset - uint8_t* dst = (uint8_t*)ptr + copyInfo->bufferOffset; - const uint8_t* src = (const uint8_t*)srcData; - - // write to destination pointer - for (uint32_t z = 0; z < copyInfo->imageDepth; z++) { - for (uint32_t y = 0; y < copyInfo->imageHeight; y++) { - memcpy( - dst + z * dstSlicePitch + y * copyInfo->bufferRowLength, - src + z * srcSlicePitch + y * srcRowPitch, - srcRowPitch); - } - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL bindBufferMemoryD3D12( - PalBuffer* buffer, - PalMemory* memory, - uint64_t offset) -{ - HRESULT result; - Buffer* d3dBuffer = (Buffer*)buffer; - ID3D12Device5* device = d3dBuffer->device->handle; - - D3D12_RESOURCE_STATES state = 0; - ID3D12Heap* mem = (ID3D12Heap*)memory; - D3D12_HEAP_DESC __ret = {0}; - D3D12_HEAP_DESC heapProps = {0}; - heapProps = *mem->lpVtbl->GetDesc(mem, &__ret); - - d3dBuffer->canChangeState = PAL_TRUE; - if (heapProps.Properties.Type == D3D12_HEAP_TYPE_UPLOAD) { - state = D3D12_RESOURCE_STATE_GENERIC_READ; - d3dBuffer->canChangeState = PAL_FALSE; - - } else if (heapProps.Properties.Type == D3D12_HEAP_TYPE_READBACK) { - state = D3D12_RESOURCE_STATE_COPY_DEST; - d3dBuffer->canChangeState = PAL_FALSE; - } - - if (d3dBuffer->isAccelerationStructure) { - d3dBuffer->canChangeState = PAL_FALSE; - state = D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; - - } else if (d3dBuffer->isScratch) { - state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - } - - result = device->lpVtbl->CreatePlacedResource( - device, - mem, - offset, - &d3dBuffer->desc, - state, - nullptr, - &IID_Resource, - (void**)&d3dBuffer->handle); - - if (FAILED(result)) { - pollMessagesD3D12(d3dBuffer->device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } else if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL mapBufferD3D12( - PalBuffer* buffer, - uint64_t offset, - uint64_t size, - void** outPtr) -{ - void* ptr = nullptr; - Buffer* d3dBuffer = (Buffer*)buffer; - HRESULT result = d3dBuffer->handle->lpVtbl->Map(d3dBuffer->handle, 0, nullptr, &ptr); - if (FAILED(result)) { - pollMessagesD3D12(d3dBuffer->device); - return PAL_RESULT_MEMORY_MAP_FAILED; - } - - *outPtr = (uint8_t*)ptr + offset; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL unmapBufferD3D12(PalBuffer* buffer) -{ - Buffer* d3dBuffer = (Buffer*)buffer; - d3dBuffer->handle->lpVtbl->Unmap(d3dBuffer->handle, 0, nullptr); -} - -PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer) -{ - Buffer* d3dBuffer = (Buffer*)buffer; - if (!d3dBuffer->supportsAddress) { - return 0; - } - - return d3dBuffer->handle->lpVtbl->GetGPUVirtualAddress(d3dBuffer->handle); -} - -// ================================================== -// Descriptor Pool, Set and Layout -// ================================================== - -PalResult PAL_CALL createDescriptorSetLayoutD3D12( - PalDevice* device, - const PalDescriptorSetLayoutCreateInfo* info, - PalDescriptorSetLayout** outLayout) -{ - HRESULT result; - Device* d3d12Device = (Device*)device; - DescriptorSetLayout* layout = nullptr; - DescriptorSetBinding* bindings = nullptr; - uint32_t count = info->bindingCount; - - PalBool hasDescriptorIndexing = d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - layout = palAllocate(s_D3D12.allocator, sizeof(DescriptorSetLayout), 0); - bindings = palAllocate(s_D3D12.allocator, sizeof(DescriptorSetBinding) * count, 0); - if (!layout || !bindings) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - layout->visibility = 0; - if (info->shaderStageCount > 1) { - layout->visibility = D3D12_SHADER_VISIBILITY_ALL; - - } else { - switch (info->shaderStages[0]) { - case PAL_SHADER_STAGE_VERTEX: { - layout->visibility = D3D12_SHADER_VISIBILITY_VERTEX; - break; - } - - case PAL_SHADER_STAGE_FRAGMENT: { - layout->visibility = D3D12_SHADER_VISIBILITY_PIXEL; - break; - } - - case PAL_SHADER_STAGE_GEOMETRY: { - layout->visibility = D3D12_SHADER_VISIBILITY_GEOMETRY; - break; - } - - case PAL_SHADER_STAGE_MESH: { - layout->visibility = D3D12_SHADER_VISIBILITY_MESH; - break; - } - - case PAL_SHADER_STAGE_TASK: { - layout->visibility = D3D12_SHADER_VISIBILITY_AMPLIFICATION; - break; - } - - case PAL_SHADER_STAGE_TESSELLATION_CONTROL: { - layout->visibility = D3D12_SHADER_VISIBILITY_HULL; - break; - } - - case PAL_SHADER_STAGE_TESSELLATION_EVALUATION: { - layout->visibility = D3D12_SHADER_VISIBILITY_DOMAIN; - break; - } - - case PAL_SHADER_STAGE_COMPUTE: - case PAL_SHADER_STAGE_RAYGEN: - case PAL_SHADER_STAGE_CLOSEST_HIT: - case PAL_SHADER_STAGE_ANY_HIT: - case PAL_SHADER_STAGE_MISS: - case PAL_SHADER_STAGE_INTERSECTION: - case PAL_SHADER_STAGE_CALLABLE: { - layout->visibility = D3D12_SHADER_VISIBILITY_ALL; - break; - } - - } - } - - D3D12_DESCRIPTOR_RANGE_FLAGS rangeFlags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; - if (info->enableDescriptorIndexing) { - rangeFlags = D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_VOLATILE; - } - - uint32_t resourceOffset = 0; - uint32_t samplerOffset = 0; - uint32_t SRVRegister = 0; - uint32_t UAVRegister = 0; - uint32_t CBVRegister = 0; - - uint32_t sampledImageCount = 0; - uint32_t storageImageCount = 0; - uint32_t storageBufferCount = 0; - uint32_t uniformBufferCount = 0; - uint32_t tlasCount = 0; - uint32_t samplerCount = 0; - - for (int i = 0; i < count; i++) { - DescriptorSetBinding* binding = &bindings[i]; - binding->type = info->bindings[i].descriptorType; - - binding->range.NumDescriptors = info->bindings[i].descriptorCount; - binding->range.Flags = rangeFlags; - binding->range.RegisterSpace = 0; - - switch (info->bindings[i].descriptorType) { - case PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE: { - binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - binding->range.BaseShaderRegister = SRVRegister; - - binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; - resourceOffset += info->bindings[i].descriptorCount; - tlasCount += info->bindings[i].descriptorCount; - SRVRegister += info->bindings[i].descriptorCount; - - break; - } - - case PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE: { - binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - binding->range.BaseShaderRegister = SRVRegister; - - binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; - resourceOffset += info->bindings[i].descriptorCount; - sampledImageCount += info->bindings[i].descriptorCount; - SRVRegister += info->bindings[i].descriptorCount; - break; - } - - case PAL_DESCRIPTOR_TYPE_SAMPLER: { - binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - binding->range.BaseShaderRegister = samplerCount; - - binding->range.OffsetInDescriptorsFromTableStart = samplerOffset; - samplerOffset += info->bindings[i].descriptorCount; - samplerCount += info->bindings[i].descriptorCount; - break; - } - - case PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER: { - binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - binding->range.BaseShaderRegister = UAVRegister; - - binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; - resourceOffset += info->bindings[i].descriptorCount; - storageBufferCount += info->bindings[i].descriptorCount; - UAVRegister += info->bindings[i].descriptorCount; - break; - } - - case PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE: { - binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - binding->range.BaseShaderRegister = UAVRegister; - - binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; - resourceOffset += info->bindings[i].descriptorCount; - storageImageCount += info->bindings[i].descriptorCount; - UAVRegister += info->bindings[i].descriptorCount; - break; - } - - case PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { - binding->range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; - binding->range.BaseShaderRegister = CBVRegister; - - binding->range.OffsetInDescriptorsFromTableStart = resourceOffset; - resourceOffset += info->bindings[i].descriptorCount; - uniformBufferCount += info->bindings[i].descriptorCount; - CBVRegister += info->bindings[i].descriptorCount; - break; - } - } - } - - // check limits - if (sampledImageCount > d3d12Device->limits.maxDescriptorSampledImages) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (storageImageCount > d3d12Device->limits.maxDescriptorStorageImages) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (storageBufferCount > d3d12Device->limits.maxDescriptorStorageBuffers) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (uniformBufferCount > d3d12Device->limits.maxDescriptorUniformBuffers) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (tlasCount > d3d12Device->limits.maxDescriptorAccelerationStructures) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (samplerCount > d3d12Device->limits.maxDescriptorSamplers) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - layout->hasDescriptorIndexing = info->enableDescriptorIndexing; - layout->bindingCount = info->bindingCount; - layout->samplerCount = samplerCount; - layout->bindings = bindings; - *outLayout = (PalDescriptorSetLayout*)layout; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout) -{ - DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; - palFree(s_D3D12.allocator, d3dLayout->bindings); - palFree(s_D3D12.allocator, d3dLayout); -} - -PalResult PAL_CALL createDescriptorPoolD3D12( - PalDevice* device, - const PalDescriptorPoolCreateInfo* info, - PalDescriptorPool** outPool) -{ - HRESULT result; - Device* d3d12Device = (Device*)device; - DescriptorPool* pool = nullptr; - - PalBool hasDescriptorIndexing = d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING; - if (info->enableDescriptorIndexing && !hasDescriptorIndexing) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - pool = palAllocate(s_D3D12.allocator, sizeof(DescriptorPool), 0); - if (!pool) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(pool, 0, sizeof(DescriptorPool)); - pool->sets = palAllocate(s_D3D12.allocator, sizeof(DescriptorSet) * info->maxDescriptorSets, 0); - if (!pool->sets) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - uint32_t resourceCount = 0; - DescriptorHeapLimits* limits = &pool->limits; - for (int i = 0; i < info->maxDescriptorBindingSizes; i++) { - PalDescriptorPoolBindingSize* bindingSize = &info->bindingSizes[i]; - if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { - limits->maxSamplers += bindingSize->bindingCount; - - } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - limits->maxUniformBuffers += bindingSize->bindingCount; - resourceCount += bindingSize->bindingCount; - - } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER) { - limits->maxStorageBuffers += bindingSize->bindingCount; - resourceCount += bindingSize->bindingCount; - - } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - limits->maxSampledImages += bindingSize->bindingCount; - resourceCount += bindingSize->bindingCount; - - } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - limits->maxStorageImages += bindingSize->bindingCount; - resourceCount += bindingSize->bindingCount; - - } else if (bindingSize->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - limits->maxAs += bindingSize->bindingCount; - resourceCount += bindingSize->bindingCount; - } - } - - // resource heap - if (resourceCount) { - DescriptorHeap* heap = &pool->resourceHeap; - D3D12_CPU_DESCRIPTOR_HANDLE __ret, handle; - D3D12_GPU_DESCRIPTOR_HANDLE __gpuRet, gpuHandle; - - D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; - desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; - desc.NumDescriptors = resourceCount; - - result = d3d12Device->handle->lpVtbl->CreateDescriptorHeap( - d3d12Device->handle, - &desc, - &IID_DescriptorHeap, - (void**)&heap->handle); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // get increment size - heap->incrementSize = d3d12Device->handle->lpVtbl->GetDescriptorHandleIncrementSize( - d3d12Device->handle, - D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); - - // get base CPU and GPU base pointer - handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( - heap->handle, - &__ret); - heap->cpuBase = handle.ptr; - - gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( - heap->handle, - &__gpuRet); - heap->gpuBase = gpuHandle.ptr; - - pool->hasResourceHeap = PAL_TRUE; - } - - // sampler heap - if (limits->maxSamplers) { - DescriptorHeap* heap = &pool->samplerHeap; - D3D12_CPU_DESCRIPTOR_HANDLE __ret, handle; - D3D12_GPU_DESCRIPTOR_HANDLE __gpuRet, gpuHandle; - - D3D12_DESCRIPTOR_HEAP_DESC desc = {0}; - desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; - desc.NumDescriptors = limits->maxSamplers; - - result = d3d12Device->handle->lpVtbl->CreateDescriptorHeap( - d3d12Device->handle, - &desc, - &IID_DescriptorHeap, - (void**)&heap->handle); - - if (FAILED(result)) { - if (result == E_OUTOFMEMORY) { - pollMessagesD3D12(d3d12Device); - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - // get increment size - heap->incrementSize = d3d12Device->handle->lpVtbl->GetDescriptorHandleIncrementSize( - d3d12Device->handle, - D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); - - // get base CPU and GPU base pointer - handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( - heap->handle, - &__ret); - heap->cpuBase = handle.ptr; - - gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( - heap->handle, - &__gpuRet); - heap->gpuBase = gpuHandle.ptr; - - pool->hasSamplerHeap = PAL_TRUE; - } - - pool->hasDescriptorIndexing = info->enableDescriptorIndexing; - pool->maxSets = info->maxDescriptorSets; - *outPool = (PalDescriptorPool*)pool; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) -{ - DescriptorPool* d3dPool = (DescriptorPool*)pool; - if (d3dPool->hasResourceHeap) { - d3dPool->resourceHeap.handle->lpVtbl->Release(d3dPool->resourceHeap.handle); - } - - if (d3dPool->hasSamplerHeap) { - d3dPool->samplerHeap.handle->lpVtbl->Release(d3dPool->samplerHeap.handle); - } - - palFree(s_D3D12.allocator, d3dPool->sets); - palFree(s_D3D12.allocator, d3dPool); -} - -PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool) -{ - DescriptorPool* d3dPool = (DescriptorPool*)pool; - d3dPool->resourceHeap.nextOffset = 0; - d3dPool->samplerHeap.nextOffset = 0; - d3dPool->usedSets = 0; - - d3dPool->limits.usedAs = 0; - d3dPool->limits.usedSampledImages = 0; - d3dPool->limits.usedSamplers = 0; - d3dPool->limits.usedStorageBuffers = 0; - d3dPool->limits.usedStorageImages = 0; - d3dPool->limits.usedUniformBuffers = 0; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL allocateDescriptorSetD3D12( - PalDevice* device, - PalDescriptorPool* pool, - PalDescriptorSetLayout* layout, - PalDescriptorSet** outSet) -{ - Device* d3d12Device = (Device*)device; - DescriptorPool* d3dPool = (DescriptorPool*)pool; - DescriptorSetLayout* d3dLayout = (DescriptorSetLayout*)layout; - DescriptorSet* set = nullptr; - - uint32_t storageImageCount = 0; - uint32_t samplerCount = 0; - uint32_t storageBufferCount = 0; - uint32_t uniformBufferCount = 0; - uint32_t sampledImageCount = 0; - uint32_t tlasCount = 0; - - if (d3dPool->hasDescriptorIndexing != d3dLayout->hasDescriptorIndexing) { - return PAL_RESULT_INVALID_OPERATION; - } - - // get requirements for the sets using the provided layout - for (int i = 0; i < d3dLayout->bindingCount; i++) { - DescriptorSetBinding* binding = &d3dLayout->bindings[i]; - - if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { - samplerCount += binding->range.NumDescriptors; - - } else if (binding->type == PAL_DESCRIPTOR_TYPE_STORAGE_BUFFER) { - storageBufferCount += binding->range.NumDescriptors; - - } else if (binding->type == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - storageImageCount += binding->range.NumDescriptors; - - } else if (binding->type == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - uniformBufferCount += binding->range.NumDescriptors; - - } else if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - sampledImageCount += binding->range.NumDescriptors; - - } else if (binding->type == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - tlasCount += binding->range.NumDescriptors; - } - } - - // validate descriptor sets limits - if (d3dPool->usedSets + 1 > d3dPool->maxSets) { - // all sets are used - return PAL_RESULT_OUT_OF_MEMORY; - } - - // check descriptor limits - DescriptorHeapLimits* limits = &d3dPool->limits; - if (limits->usedAs + tlasCount > limits->maxAs) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (limits->usedSampledImages + sampledImageCount > limits->maxSampledImages) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (limits->usedSamplers + samplerCount > limits->maxSamplers) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (limits->usedStorageBuffers + storageBufferCount > limits->maxStorageBuffers) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (limits->usedStorageImages + storageImageCount > limits->maxStorageImages) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (limits->usedUniformBuffers + uniformBufferCount > limits->maxUniformBuffers) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // assign offset base to the set so we know where to start and end for each set. - set = &d3dPool->sets[d3dPool->usedSets++]; - set->resourceOffset = d3dPool->resourceHeap.nextOffset; - set->samplerOffset = d3dPool->samplerHeap.nextOffset; - set->layout = d3dLayout; - set->pool = d3dPool; - - uint32_t totalDescriptors = tlasCount + storageBufferCount + uniformBufferCount; - totalDescriptors += sampledImageCount + storageImageCount; - d3dPool->resourceHeap.nextOffset += totalDescriptors; - d3dPool->samplerHeap.nextOffset += samplerCount; - - limits->usedAs += tlasCount; - limits->usedSampledImages += sampledImageCount; - limits->usedSamplers += samplerCount; - limits->usedStorageBuffers += storageBufferCount; - limits->usedUniformBuffers += uniformBufferCount; - - *outSet = (PalDescriptorSet*)set; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL updateDescriptorSetD3D12( - PalDevice* device, - uint32_t count, - PalDescriptorSetWriteInfo* infos) -{ - Device* d3d12Device = (Device*)device; - for (int i = 0; i < count; i++) { - PalDescriptorSetWriteInfo* info = &infos[i]; - DescriptorSet* set = (DescriptorSet*)info->descriptorSet; - DescriptorPool* pool = set->pool; - DescriptorSetLayout* layout = set->layout; - - if (info->layoutBindingIndex > layout->bindingCount) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - DescriptorSetBinding* binding = &layout->bindings[info->layoutBindingIndex]; - DescriptorHeap* heap = nullptr; - uint32_t index = 0; - uint32_t bindingOffset = binding->range.OffsetInDescriptorsFromTableStart; - - if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { - heap = &pool->samplerHeap; - index = set->samplerOffset + bindingOffset + info->arrayElement; - - } else { - heap = &pool->resourceHeap; - index = set->resourceOffset + bindingOffset + info->arrayElement; - } - - for (int j = 0; j < info->descriptorCount; j++) { - D3D12_CPU_DESCRIPTOR_HANDLE dst; - dst.ptr = getDescriptorHandleD3D12(index + j, heap->incrementSize, heap->cpuBase); - - if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { - if (info->samplerInfos) { - Sampler* sampler = (Sampler*)info->samplerInfos[j].sampler; - d3d12Device->handle->lpVtbl->CreateSampler(d3d12Device->handle, &sampler->desc, dst); - - } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - D3D12_SAMPLER_DESC desc = {0}; - desc.MaxAnisotropy = 1; - desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; - desc.BorderColor[3] = 1.0f; - - desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; - desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; - desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; - desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; - d3d12Device->handle->lpVtbl->CreateSampler(d3d12Device->handle, &desc, dst); - } - - } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { - D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; - desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - desc.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE; - - if (info->tlasInfos) { - AccelerationStructure* tlas = nullptr; - tlas = (AccelerationStructure*)info->tlasInfos[j].tlas; - desc.RaytracingAccelerationStructure.Location = tlas->address; - - } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - d3d12Device->handle->lpVtbl->CreateShaderResourceView( - d3d12Device->handle, - nullptr, - &desc, - dst); - - } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { - D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; - desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - - PalImageSubresourceRange range = {0}; - PalImageViewType type; - ID3D12Resource* handle = nullptr; - - if (info->imageViewInfos) { - ImageView* imageView = (ImageView*)info->imageViewInfos[j].imageView; - desc.Format = imageView->format; - type = imageView->type; - range = imageView->range; - handle = imageView->image->handle; - - } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - type = PAL_IMAGE_VIEW_TYPE_2D; - range.mipLevelCount = 1; - range.layerArrayCount = 1; - range.aspect = PAL_IMAGE_ASPECT_COLOR; - } - - fillSubresourceD3D12( - type, - &range, - nullptr, - nullptr, - &desc, - nullptr); - - d3d12Device->handle->lpVtbl->CreateShaderResourceView( - d3d12Device->handle, - handle, - &desc, - dst); - - } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { - D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; - PalImageSubresourceRange range = {0}; - PalImageViewType type; - ID3D12Resource* handle = nullptr; - - if (info->imageViewInfos) { - ImageView* imageView = (ImageView*)info->imageViewInfos[j].imageView; - desc.Format = imageView->format; - type = imageView->type; - range = imageView->range; - handle = imageView->image->handle; - - } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; - type = PAL_IMAGE_VIEW_TYPE_2D; - range.mipLevelCount = 1; - range.layerArrayCount = 1; - range.aspect = PAL_IMAGE_ASPECT_COLOR; - } - - fillSubresourceD3D12( - type, - &range, - nullptr, - nullptr, - nullptr, - &desc); - - d3d12Device->handle->lpVtbl->CreateUnorderedAccessView( - d3d12Device->handle, - handle, - nullptr, - &desc, - dst); - - } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { - D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {0}; - D3D12_GPU_VIRTUAL_ADDRESS address = 0; - - if (info->bufferInfos) { - PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; - Buffer* buffer = (Buffer*)bufferInfo->buffer; - desc.SizeInBytes = bufferInfo->size; - address = buffer->handle->lpVtbl->GetGPUVirtualAddress(buffer->handle); - desc.BufferLocation = address + bufferInfo->offset; - - } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - d3d12Device->handle->lpVtbl->CreateConstantBufferView( - d3d12Device->handle, - &desc, - dst); - - } else { - // storage buffer - D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; - desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - - ID3D12Resource* handle = nullptr; - if (info->bufferInfos) { - PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; - Buffer* buffer = (Buffer*)bufferInfo->buffer; - - uint32_t stride = 4; - if (bufferInfo->stride) { - stride = bufferInfo->stride; - desc.Buffer.StructureByteStride = bufferInfo->stride; - } else { - desc.Format = DXGI_FORMAT_R32_TYPELESS; - desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; - } - - handle = buffer->handle; - desc.Buffer.FirstElement = bufferInfo->offset / stride; - desc.Buffer.NumElements = bufferInfo->size / stride; - - } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - } - - d3d12Device->handle->lpVtbl->CreateUnorderedAccessView( - d3d12Device->handle, - handle, - nullptr, - &desc, - dst); - } - } - } - return PAL_RESULT_SUCCESS; -} - -// ================================================== -// Pipeline Layout -// ================================================== - -PalResult PAL_CALL createPipelineLayoutD3D12( - PalDevice* device, - const PalPipelineLayoutCreateInfo* info, - PalPipelineLayout** outLayout) -{ - Device* d3d12Device = (Device*)device; - PipelineLayout* layout = nullptr; - uint32_t resourceCount = 0; - uint32_t samplerCount = 0; - uint64_t pushConstantSize = 0; - uint32_t sizeInBytes = sizeof(D3D12_DESCRIPTOR_RANGE1); - - uint32_t rangesOffset = 0; - uint32_t samplerRangesOffset = 0; - D3D12_DESCRIPTOR_RANGE1* ranges = nullptr; - D3D12_DESCRIPTOR_RANGE1* samplerRanges = nullptr; - - uint32_t parameterCount = 0; - D3D12_ROOT_PARAMETER1* parameters = nullptr; - D3D12_ROOT_SIGNATURE_FLAGS rootFlags = 0; - rootFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; - - if (info->descriptorSetLayoutCount > d3d12Device->limits.maxBoundDescriptorSets) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (d3d12Device->shaderModel >= PAL_MAKE_SHADER_TARGET(6, 6)) { - rootFlags |= D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED; - rootFlags |= D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED; - } - - // get the total resource and sampler ranges for all provided descriptor set layouts - for (int i = 0; i < info->descriptorSetLayoutCount; i++) { - DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; - resourceCount += tmp->bindingCount - tmp->samplerCount; - samplerCount += tmp->samplerCount; - - if (tmp->bindingCount - tmp->samplerCount >= 1) { - parameterCount++; - } - - if (tmp->samplerCount >= 1) { - parameterCount++; - } - } - - // get the total size needed for all provided push constant range - for (int i = 0; i < info->pushConstantRangeCount; i++) { - PalPushConstantRange* tmp = &info->pushConstantRanges[i]; - if (tmp->offset + tmp->size > pushConstantSize) { - pushConstantSize = tmp->offset + tmp->size; - } - } - - if (pushConstantSize > d3d12Device->limits.maxPushConstantSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - layout = palAllocate(s_D3D12.allocator, sizeof(PipelineLayout), 0); - if (!layout) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (pushConstantSize) { - parameterCount++; - } - - if (parameterCount) { - uint32_t paramtersSize = sizeof(D3D12_ROOT_PARAMETER1) * parameterCount; - parameters = palAllocate(s_D3D12.allocator, paramtersSize, 0); - if (!parameters) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - memset(parameters, 0, paramtersSize); - } - - if (resourceCount) { - ranges = palAllocate(s_D3D12.allocator, sizeInBytes * resourceCount, 0); - if (!ranges) { - return PAL_RESULT_OUT_OF_MEMORY; - } - } - - if (samplerCount) { - samplerRanges = palAllocate(s_D3D12.allocator, sizeInBytes * samplerCount, 0); - if (!samplerRanges) { - return PAL_RESULT_OUT_OF_MEMORY; - } - } - - // write root constant first if its provided - parameterCount = 0; // reset and reuse the same variable - layout->constantIndex = UINT32_MAX; - if (pushConstantSize) { - D3D12_ROOT_PARAMETER1* parameter = ¶meters[parameterCount]; - parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; - parameter->Constants.Num32BitValues = (UINT)pushConstantSize / 4; - parameter->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - - layout->constantIndex = parameterCount; - parameterCount++; - } - - uint32_t registerSpace = 0; - for (int i = 0; i < info->descriptorSetLayoutCount; i++) { - DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; - D3D12_ROOT_PARAMETER1* parameter = nullptr; - - // reset and reuse same variable - resourceCount = tmp->bindingCount - tmp->samplerCount; - samplerCount = tmp->samplerCount; - - uint32_t samplerIndex = samplerRangesOffset; - uint32_t rangeIndex = rangesOffset; - - // seperate the samplers from the remaining descriptors - for (int j = 0; j < tmp->bindingCount; j++) { - DescriptorSetBinding* binding = &tmp->bindings[j]; - D3D12_DESCRIPTOR_RANGE1* tmpRange = nullptr; - - if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { - tmpRange = &samplerRanges[samplerIndex++]; - } else { - tmpRange = &ranges[rangeIndex++]; - } - - *tmpRange = binding->range; - tmpRange->RegisterSpace = registerSpace; - } - - // resource ranges - if (resourceCount) { - parameter = ¶meters[parameterCount]; - parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - parameter->DescriptorTable.NumDescriptorRanges = resourceCount; - parameter->DescriptorTable.pDescriptorRanges = &ranges[rangesOffset]; - parameter->ShaderVisibility = tmp->visibility; - - rangesOffset += resourceCount; - parameterCount++; - } - - // sampler ranges - if (samplerCount) { - parameter = ¶meters[parameterCount]; - parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - parameter->DescriptorTable.NumDescriptorRanges = samplerCount; - parameter->DescriptorTable.pDescriptorRanges = &samplerRanges[samplerRangesOffset]; - parameter->ShaderVisibility = tmp->visibility; - - samplerRangesOffset += samplerCount; - parameterCount++; - } - - registerSpace++; - } - - // create root signature - D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; - rootDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; - rootDesc.Desc_1_1.NumParameters = parameterCount; - rootDesc.Desc_1_1.pParameters = parameters; - rootDesc.Desc_1_1.Flags = rootFlags; - - ID3DBlob* blob = nullptr; - HRESULT result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - result = d3d12Device->handle->lpVtbl->CreateRootSignature( - d3d12Device->handle, - 0, - blob->lpVtbl->GetBufferPointer(blob), - blob->lpVtbl->GetBufferSize(blob), - &IID_RootSignature, - (void**)&layout->handle); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - if (resourceCount) { - palFree(s_D3D12.allocator, ranges); - } - - if (samplerCount) { - palFree(s_D3D12.allocator, samplerRanges); - } - - if (parameterCount) { - palFree(s_D3D12.allocator, parameters); - } - - blob->lpVtbl->Release(blob); - *outLayout = (PalPipelineLayout*)layout; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout) -{ - PipelineLayout* d3dLayout = (PipelineLayout*)layout; - d3dLayout->handle->lpVtbl->Release(d3dLayout->handle); - palFree(s_D3D12.allocator, d3dLayout); -} - -// ================================================== -// Pipeline -// ================================================== - -PalResult PAL_CALL createGraphicsPipelineD3D12( - PalDevice* device, - const PalGraphicsPipelineCreateInfo* info, - PalPipeline** outPipeline) -{ - HRESULT result; - uint32_t patchControlPoints = 0; - uint32_t totalSize = 0; - PalBool alphaToCoverageEnable = PAL_FALSE; - Pipeline* pipeline = nullptr; - Device* d3d12Device = (Device*)device; - PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - - D3D12_INPUT_ELEMENT_DESC* elementDescs = nullptr; - D3D12_VIEW_INSTANCE_LOCATION* viewLocations = nullptr; - - GraphicsPipelineStreamDesc graphicsStreamDesc = {0}; - memset(&graphicsStreamDesc, 0, sizeof(GraphicsPipelineStreamDesc)); - - pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); - if (!pipeline) { - return PAL_RESULT_OUT_OF_MEMORY; - } - memset(pipeline, 0, sizeof(Pipeline)); - - if (info->renderingLayout->viewCount > 1) { - viewLocations = palAllocate( - s_D3D12.allocator, - sizeof(D3D12_VIEW_INSTANCE_LOCATION) * info->renderingLayout->viewCount, - 0); - - if (!viewLocations) { - return PAL_RESULT_OUT_OF_MEMORY; - } - } - - // Root signature - RootSignatureStream* rootSignatureStream = &graphicsStreamDesc.layout; - totalSize += sizeof(RootSignatureStream); - rootSignatureStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE; - rootSignatureStream->root = layout->handle; - - // shaders - for (int i = 0; i < info->shaderCount; i++) { - Shader* tmp = (Shader*)info->shaders[i]; - ShaderStream* shaderStream = &graphicsStreamDesc.shaders[i]; - totalSize += sizeof(ShaderStream); - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - - ShaderEntry* entry = &tmp->entries[0]; - if (entry->patchControlPoints) { - patchControlPoints = entry->patchControlPoints; - if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { - palFree(s_D3D12.allocator, pipeline); - return PAL_RESULT_INVALID_OPERATION; - } - } - - if (entry->stage == PAL_SHADER_STAGE_VERTEX) { - type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VS; - - } else if (entry->stage == PAL_SHADER_STAGE_FRAGMENT) { - type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PS; - - } else if (entry->stage == PAL_SHADER_STAGE_GEOMETRY) { - type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_GS; - - } else if (entry->stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL) { - type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_HS; - - } else if (entry->stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { - type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DS; - - } else if (entry->stage == PAL_SHADER_STAGE_TASK) { - type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_AS; - - } else { - // mesh shader - type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_MS; - } - - shaderStream->type = type; - shaderStream->desc = tmp->byteCode; - } - - // Vertex input state - // get the max size of vertex attributes in all layouts - uint32_t vertexCount = 0; - uint32_t vertexLayoutCount = info->vertexLayoutCount; - for (int i = 0; i < vertexLayoutCount; i++) { - PalVertexLayout* layout = &info->vertexLayouts[i]; - vertexCount += layout->attributeCount; - } - - if (info->vertexLayoutCount > d3d12Device->limits.maxVertexLayouts) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (vertexCount > d3d12Device->limits.maxVertexAttributes) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - InputLayoutStream* inputLayoutStream = &graphicsStreamDesc.inputLayout; - totalSize += sizeof(InputLayoutStream); - inputLayoutStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_INPUT_LAYOUT; - - pipeline->strides = nullptr; - if (vertexCount) { - pipeline->strides = palAllocate(s_D3D12.allocator, sizeof(uint32_t) * 8, 0); - if (!pipeline->strides) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - elementDescs = palAllocate( - s_D3D12.allocator, - sizeof(D3D12_INPUT_ELEMENT_DESC) * vertexCount, - 0); - - if (!elementDescs) { - palFree(s_D3D12.allocator, elementDescs); - return PAL_RESULT_OUT_OF_MEMORY; - } - - uint32_t positionIndex = 0; - uint32_t colorIndex = 0; - uint32_t texCoordIndex = 0; - uint32_t normalIndex = 0; - uint32_t tangentIndex = 0; - - for (int i = 0; i < info->vertexLayoutCount; i++) { - PalVertexLayout* layout = &info->vertexLayouts[i]; - uint32_t stride = 0; - uint32_t offset = 0; - - for (int j = 0; j < layout->attributeCount; j++) { - PalVertexAttribute* vertexAttrib = &layout->attributes[j]; - D3D12_INPUT_ELEMENT_DESC* elementDesc = &elementDescs[j]; - - elementDesc->Format = vertexTypeToD3D12(vertexAttrib->type); - elementDesc->InputSlot = layout->binding; - if (vertexAttrib->semanticName) { - elementDesc->SemanticName = vertexAttrib->semanticName; - } else { - elementDesc->SemanticName = semanticIDToStringD3D12(vertexAttrib->semanticID); - } - - if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_POSITION) { - elementDesc->SemanticIndex = positionIndex++; - - } else if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_COLOR) { - elementDesc->SemanticIndex = colorIndex++; - - } else if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_TEXCOORD) { - elementDesc->SemanticIndex = texCoordIndex++; - - } else if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_NORMAL) { - elementDesc->SemanticIndex = normalIndex++; - - } else { - // tangent - elementDesc->SemanticIndex = tangentIndex++; - } - - if (layout->type == PAL_VERTEX_LAYOUT_TYPE_PER_INSTANCE) { - elementDesc->InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA; - elementDesc->InstanceDataStepRate = 1; - } else { - elementDesc->InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA; - elementDesc->InstanceDataStepRate = 0; - } - - // build offsets and stride - uint32_t size = getVertexTypeSizeD3D12(vertexAttrib->type); - elementDesc->AlignedByteOffset = offset; - offset += size; - stride += size; - } - - // cache the computed stride to be used later by the vertex buffer - pipeline->strides[i] = stride; - } - - inputLayoutStream->desc.NumElements = vertexCount; - inputLayoutStream->desc.pInputElementDescs = elementDescs; - } - - // Primitive Topology - D3D12_PRIMITIVE_TOPOLOGY_TYPE topologyType = 0; - D3D_PRIMITIVE_TOPOLOGY topology = 0; - switch (info->topology) { - case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { - topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { - topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - topology = D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_LINE_LIST: { - topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; - topology = D3D_PRIMITIVE_TOPOLOGY_LINELIST; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP: { - topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; - topology = D3D_PRIMITIVE_TOPOLOGY_LINESTRIP; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_POINT_LIST: { - topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; - topology = D3D_PRIMITIVE_TOPOLOGY_POINTLIST; - break; - } - - case PAL_PRIMITIVE_TOPOLOGY_PATCH: { - topologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH; - topology = getPatchTopology(patchControlPoints); - break; - } - } - - TopologyStream* topologyStream = &graphicsStreamDesc.topology; - totalSize += sizeof(TopologyStream); - topologyStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_PRIMITIVE_TOPOLOGY; - topologyStream->topology = topologyType; - - // IB Strip Cut - IBStripCutStream* inStripCutStream = &graphicsStreamDesc.ibStripCut; - totalSize += sizeof(IBStripCutStream); - inStripCutStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_IB_STRIP_CUT_VALUE; - if (info->primitiveRestartEnable == PAL_FALSE) { - inStripCutStream->value = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; - - } else { - if (info->indexType == PAL_INDEX_TYPE_UINT16) { - inStripCutStream->value = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF; - } else { - inStripCutStream->value = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFFFFFF; - } - } - - // Rasterizer - RasterizerStream* rasterizerStream = &graphicsStreamDesc.rasterizer; - totalSize += sizeof(RasterizerStream); - rasterizerStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RASTERIZER; - - rasterizerStream->desc.CullMode = D3D12_CULL_MODE_NONE; - rasterizerStream->desc.FillMode = D3D12_FILL_MODE_SOLID; - rasterizerStream->desc.FrontCounterClockwise = PAL_FALSE; - rasterizerStream->desc.DepthClipEnable = TRUE; - - if (info->rasterizerState) { - PalRasterizerState* state = info->rasterizerState; - if (state->cullMode == PAL_CULL_MODE_NONE) { - rasterizerStream->desc.CullMode = D3D12_CULL_MODE_NONE; - - } else if (state->cullMode == PAL_CULL_MODE_BACK) { - rasterizerStream->desc.CullMode = D3D12_CULL_MODE_BACK; - - } else if (state->cullMode == PAL_CULL_MODE_FRONT) { - rasterizerStream->desc.CullMode = D3D12_CULL_MODE_FRONT; - } - - if (state->polygonMode == PAL_POLYGON_MODE_FILL) { - rasterizerStream->desc.FillMode = D3D12_FILL_MODE_SOLID; - - } else { - rasterizerStream->desc.FillMode = D3D12_FILL_MODE_WIREFRAME; - } - - if (state->frontFace == PAL_FRONT_FACE_CLOCKWISE) { - rasterizerStream->desc.FrontCounterClockwise = PAL_FALSE; - - } else { - rasterizerStream->desc.FrontCounterClockwise = TRUE; - } - - rasterizerStream->desc.DepthClipEnable = !state->enableDepthClamp; - rasterizerStream->desc.DepthBias = (INT)state->depthBiasConstant; - rasterizerStream->desc.SlopeScaledDepthBias = state->depthBiasSlope; - rasterizerStream->desc.DepthBiasClamp = state->depthBiasClamp; - } - - // Sample Desc - SampleDescStream* sampleDescStream = &graphicsStreamDesc.sampleDesc; - totalSize += sizeof(SampleDescStream); - sampleDescStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_DESC; - sampleDescStream->desc.Quality = 0; - sampleDescStream->desc.Count = 1; - - // Sample Mask - SampleMaskStream* sampleMaskStream = &graphicsStreamDesc.sampleMask; - totalSize += sizeof(SampleMaskStream); - sampleMaskStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_SAMPLE_MASK; - sampleMaskStream->mask = UINT_MAX; - - if (info->multisampleState) { - PalMultisampleState* state = info->multisampleState; - if (state->sampleMask) { - sampleMaskStream->mask = (UINT)state->sampleMask; - } - - sampleDescStream->desc.Count = samplesToD3D12(state->sampleCount); - alphaToCoverageEnable = state->enableAlphaToCoverage; - } - - // Depth stencil - DepthStencilStream* depthStencilStream = &graphicsStreamDesc.depthStencil; - totalSize += sizeof(DepthStencilStream); - depthStencilStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL; - depthStencilStream->desc.DepthEnable = PAL_FALSE; - depthStencilStream->desc.StencilEnable = PAL_FALSE; - - if (info->depthStencilState) { - PalDepthStencilState* state = info->depthStencilState; - PalStencilOpState* back = &state->backStencilOpState; - PalStencilOpState* front = &state->frontStencilOpState; - - D3D12_DEPTH_STENCILOP_DESC* d3dBack = &depthStencilStream->desc.BackFace; - D3D12_DEPTH_STENCILOP_DESC* d3dFront = &depthStencilStream->desc.FrontFace; - - d3dBack->StencilFunc = compareOpToD3D12(back->compareOp); - d3dBack->StencilDepthFailOp = stencilOpToD3D12(back->depthFailOp); - d3dBack->StencilFailOp = stencilOpToD3D12(back->failOp); - d3dBack->StencilPassOp = stencilOpToD3D12(back->passOp); - - d3dFront->StencilFunc = compareOpToD3D12(front->compareOp); - d3dFront->StencilDepthFailOp = stencilOpToD3D12(front->depthFailOp); - d3dFront->StencilFailOp = stencilOpToD3D12(front->failOp); - d3dFront->StencilPassOp = stencilOpToD3D12(front->passOp); - - depthStencilStream->desc.DepthFunc = compareOpToD3D12(state->compareOp); - depthStencilStream->desc.DepthEnable = state->enableDepthTest; - depthStencilStream->desc.StencilEnable = state->enableStencilTest; - if (state->enableDepthWrite) { - depthStencilStream->desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; - } else { - depthStencilStream->desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; - } - } - - // Blend - BlendStream* blendStream = &graphicsStreamDesc.blend; - totalSize += sizeof(BlendStream); - blendStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_BLEND; - blendStream->desc.IndependentBlendEnable = TRUE; - blendStream->desc.AlphaToCoverageEnable = alphaToCoverageEnable; - - if (info->colorBlendAttachmentCount) { - for (int i = 0; i < info->colorBlendAttachmentCount; i++) { - D3D12_RENDER_TARGET_BLEND_DESC* tmp = &blendStream->desc.RenderTarget[i]; - PalColorBlendAttachment* desc = &info->colorBlendAttachments[i]; - - tmp->BlendEnable = desc->enableBlend; - tmp->BlendOpAlpha = blendOpToD3D12(desc->alphaBlendOp); - tmp->BlendOp = blendOpToD3D12(desc->colorBlendOp); - - tmp->SrcBlendAlpha = blendFactorToD3D12(desc->srcAlphaBlendFactor); - tmp->SrcBlend = blendFactorToD3D12(desc->srcColorBlendFactor); - - tmp->DestBlendAlpha = blendFactorToD3D12(desc->dstAlphaBlendFactor); - tmp->DestBlend = blendFactorToD3D12(desc->dstColorBlendFactor); - - // blend color write mask - tmp->RenderTargetWriteMask = 0; - if (desc->colorWriteMask & PAL_COLOR_MASK_RED) { - tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED; - } - - if (desc->colorWriteMask & PAL_COLOR_MASK_GREEN) { - tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_GREEN; - } - - if (desc->colorWriteMask & PAL_COLOR_MASK_BLUE) { - tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_BLUE; - } - - if (desc->colorWriteMask & PAL_COLOR_MASK_ALPHA) { - tmp->RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA; - } - } - } - - // Fragment shading rate - pipeline->hasFsr = PAL_FALSE; - if (info->fragmentShadingRateState) { - PalFragmentShadingRateState* state = info->fragmentShadingRateState; - pipeline->shadingRate = shadingRateToD3D12(state->rate); - for (int i = 0; i < 2; i++) { - pipeline->combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); - } - } - - // RTV Formats - RTVStream* rtvStream = &graphicsStreamDesc.RTV; - totalSize += sizeof(RTVStream); - rtvStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_RENDER_TARGET_FORMATS; - - DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; - rtvStream->data.NumRenderTargets = info->renderingLayout->colorAttachentCount; - for (int i = 0; i < info->renderingLayout->colorAttachentCount; i++) { - format = formatToD3D12(info->renderingLayout->colorAttachmentsFormat[i]); - rtvStream->data.RTFormats[i] = format; - } - - // DSV Format - DSVStream* dsvStream = &graphicsStreamDesc.DSV; - totalSize += sizeof(DSVStream); - dsvStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_DEPTH_STENCIL_FORMAT; - dsvStream->format = formatToD3D12(info->renderingLayout->depthStencilAttachmentFormat); - - // View Instancing - ViewInstancingStream* viewInstacingStream = &graphicsStreamDesc.viewInstancing; - totalSize += sizeof(ViewInstancingStream); - viewInstacingStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_VIEW_INSTANCING; - - viewInstacingStream->desc.ViewInstanceCount = 0; - viewInstacingStream->desc.pViewInstanceLocations = nullptr; - if (info->renderingLayout->viewCount > 1) { - for (int i = 0; i < info->renderingLayout->viewCount; i++) { - viewLocations[i].RenderTargetArrayIndex = i; - viewLocations[i].ViewportArrayIndex = i; - } - - viewInstacingStream->desc.ViewInstanceCount = info->renderingLayout->viewCount; - viewInstacingStream->desc.pViewInstanceLocations = viewLocations; - } - - D3D12_PIPELINE_STATE_STREAM_DESC streamDesc = {0}; - streamDesc.pPipelineStateSubobjectStream = &graphicsStreamDesc; - streamDesc.SizeInBytes = totalSize; - - result = d3d12Device->handle->lpVtbl->CreatePipelineState( - d3d12Device->handle, - &streamDesc, - &IID_PipelineState, - &pipeline->handle); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - if (info->vertexLayoutCount) { - palFree(s_D3D12.allocator, elementDescs); - } - - if (info->renderingLayout->viewCount > 1) { - palFree(s_D3D12.allocator, viewLocations); - } - - pipeline->topology = topology; - pipeline->type = GRAPHICS_PIPELINE; - pipeline->layout = layout; - pipeline->shaderExports = nullptr; - pipeline->localRootSignature = nullptr; - - *outPipeline = (PalPipeline*)pipeline; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL createComputePipelineD3D12( - PalDevice* device, - const PalComputePipelineCreateInfo* info, - PalPipeline** outPipeline) -{ - Device* d3d12Device = (Device*)device; - PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - Shader* shader = (Shader*)info->computeShader; - Pipeline* pipeline = nullptr; - - pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); - if (!pipeline) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - D3D12_COMPUTE_PIPELINE_STATE_DESC desc = {0}; - desc.CS = shader->byteCode; - desc.pRootSignature = layout->handle; - - HRESULT result = d3d12Device->handle->lpVtbl->CreateComputePipelineState( - d3d12Device->handle, - &desc, - &IID_PipelineState, - &pipeline->handle); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - pipeline->type = COMPUTE_PIPELINE; - pipeline->strides = nullptr; - pipeline->hasFsr = PAL_FALSE; - pipeline->layout = layout; - pipeline->shaderExports = nullptr; - pipeline->localRootSignature = nullptr; - - *outPipeline = (PalPipeline*)pipeline; - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL createRayTracingPipelineD3D12( - PalDevice* device, - const PalRayTracingPipelineCreateInfo* info, - PalPipeline** outPipeline) -{ - HRESULT result; - Device* d3d12Device = (Device*)device; - PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - Pipeline* pipeline = nullptr; - - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; - } - - if (info->maxAttributeSize > d3d12Device->limits.maxHitAttributeSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (info->maxPayloadSize > d3d12Device->limits.maxPayloadSize) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - if (info->maxRecursionDepth> d3d12Device->limits.maxRecursionDepth) { - return PAL_RESULT_INVALID_ARGUMENT; - } - - D3D12_EXPORT_DESC* exportDescs = nullptr; - D3D12_DXIL_LIBRARY_DESC* libraryDescs = nullptr; - RayHitGroup* hitGroups = nullptr; - D3D12_STATE_SUBOBJECT* subObjects = nullptr; - const wchar_t** localExports = nullptr; - - // find the total number of exports - uint32_t exportCount = 0; - for (int i = 0; i < info->shaderCount; i++) { - Shader* shader = (Shader*)info->shaders[i]; - exportCount += shader->entryCount; - } - - uint32_t subObjectCount = 0; - uint32_t localExportCount = 0; - ShaderBindingTableInfo sbtInfo = {0}; - - for (int i = 0; i < info->shaderGroupCount; i++) { - PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; - if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { - // check if its raygen, miss or callable - Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; - ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; - switch (entry->stage) { - case PAL_SHADER_STAGE_RAYGEN: { - sbtInfo.raygenCount++; - sbtInfo.raygenDataSize = max(sbtInfo.raygenDataSize, tmp->maxDataSize); - break; - } - - case PAL_SHADER_STAGE_MISS: { - sbtInfo.missCount++; - sbtInfo.missDataSize = max(sbtInfo.missDataSize, tmp->maxDataSize); - break; - } - - case PAL_SHADER_STAGE_CALLABLE: { - sbtInfo.callableCount++; - sbtInfo.callableDataSize = max(sbtInfo.callableDataSize, tmp->maxDataSize); - break; - } - } - - } else { - sbtInfo.hitDataSize = max(sbtInfo.hitDataSize, tmp->maxDataSize); - sbtInfo.hitCount++; - } - - if (tmp->maxDataSize) { - localExportCount++; - } - } - - // find the max data size across all shader groups - uint32_t localRootSize = 0; - localRootSize = max(localRootSize, sbtInfo.raygenDataSize); - localRootSize = max(localRootSize, sbtInfo.missDataSize); - localRootSize = max(localRootSize, sbtInfo.hitDataSize); - localRootSize = max(localRootSize, sbtInfo.callableDataSize); - - // // D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE - // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG - // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG - subObjectCount += info->shaderCount + 3; - - subObjectCount += sbtInfo.hitCount; - if (localRootSize) { - // D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE - // D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION - subObjectCount += 2; - } - - pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); - if (!pipeline) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - pipeline->shaderExportCount = exportCount + sbtInfo.hitCount; - subObjects = palAllocate(s_D3D12.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); - hitGroups = palAllocate(s_D3D12.allocator, sizeof(RayHitGroup) * sbtInfo.hitCount, 0); - if (!subObjects || !hitGroups) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - libraryDescs = palAllocate( - s_D3D12.allocator, - sizeof(D3D12_DXIL_LIBRARY_DESC) * info->shaderCount, - 0); - - exportDescs = palAllocate( - s_D3D12.allocator, - sizeof(D3D12_EXPORT_DESC) * exportCount, - 0); - - pipeline->shaderExports = palAllocate( - s_D3D12.allocator, - sizeof(ShaderExport) * pipeline->shaderExportCount, - 0); - - localExports = palAllocate( - s_D3D12.allocator, - sizeof(wchar_t*) * localExportCount, - 0); - - if (!libraryDescs || !exportDescs || !pipeline->shaderExports || !localExports) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - // global root signature - uint32_t subObjectIndex = 0; - D3D12_GLOBAL_ROOT_SIGNATURE globalRootSignature = {0}; - globalRootSignature.pGlobalRootSignature = layout->handle; - - subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE; - subObjects[subObjectIndex].pDesc = &globalRootSignature; - subObjectIndex++; - - // ray tracing config - D3D12_RAYTRACING_SHADER_CONFIG shaderConfig = {0}; - shaderConfig.MaxAttributeSizeInBytes = info->maxAttributeSize; - shaderConfig.MaxPayloadSizeInBytes = info->maxPayloadSize; - subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG; - subObjects[subObjectIndex].pDesc = &shaderConfig; - subObjectIndex++; - - D3D12_RAYTRACING_PIPELINE_CONFIG pipelineConfig = {0}; - pipelineConfig.MaxTraceRecursionDepth = info->maxRecursionDepth; - subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG; - subObjects[subObjectIndex].pDesc = &pipelineConfig; - subObjectIndex++; - - // shaders - uint32_t exportsOffset = 0; - for (int i = 0; i < info->shaderCount; i++) { - Shader* tmp = (Shader*)info->shaders[i]; - D3D12_DXIL_LIBRARY_DESC* libraryDesc = &libraryDescs[i]; - libraryDesc->DXILLibrary = tmp->byteCode; - - for (int j = 0; j < tmp->entryCount; j++) { - D3D12_EXPORT_DESC* exportDesc = &exportDescs[exportsOffset + j]; - ShaderExport* shaderExport = &pipeline->shaderExports[exportsOffset + j]; - ShaderEntry* entry = &tmp->entries[j]; - - shaderExport->isHitGroup = PAL_FALSE; - shaderExport->stage = entry->stage; - wcscpy(shaderExport->entryName, entry->entryName); - - exportDesc->ExportToRename = nullptr; - exportDesc->Flags = D3D12_EXPORT_FLAG_NONE; - exportDesc->Name = shaderExport->entryName; - } - - libraryDesc->pExports = &exportDescs[exportsOffset]; - libraryDesc->NumExports = tmp->entryCount; - - subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_DXIL_LIBRARY; - subObjects[subObjectIndex].pDesc = libraryDesc; - subObjectIndex++; - exportsOffset += tmp->entryCount; - } - - // hit groups - uint32_t localExportIndex = 0; - uint32_t hitGroupIndex = 0; - for (int i = 0; i < info->shaderGroupCount; i++) { - const wchar_t* exportName = nullptr; - PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; - if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { - if (tmp->maxDataSize) { - Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; - ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; - localExports[localExportIndex++] = entry->entryName; - } - - continue; - } - - D3D12_HIT_GROUP_DESC* group = &hitGroups[hitGroupIndex].desc; - getHitGroupNameD3D12(hitGroupIndex, hitGroups[hitGroupIndex].entryName); - - ShaderExport* hitGroupExport = &pipeline->shaderExports[exportCount++]; - wcscpy(hitGroupExport->entryName, hitGroups[hitGroupIndex].entryName); - hitGroupExport->isHitGroup = PAL_TRUE; - hitGroupExport->stage = PAL_SHADER_STAGE_CLOSEST_HIT; // to identify - - group->AnyHitShaderImport = nullptr; - group->ClosestHitShaderImport = nullptr; - group->IntersectionShaderImport = nullptr; - group->HitGroupExport = hitGroups[hitGroupIndex].entryName; - - if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT) { - group->Type = D3D12_HIT_GROUP_TYPE_TRIANGLES; - - } else if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT) { - group->Type = D3D12_HIT_GROUP_TYPE_PROCEDURAL_PRIMITIVE; - } - - // Any hit shader - if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - Shader* shader = (Shader*)info->shaders[tmp->anyHitShaderIndex]; - ShaderEntry* entry = &shader->entries[tmp->anyHitShaderEntryIndex]; - group->AnyHitShaderImport = entry->entryName; - - } else { - group->AnyHitShaderImport = nullptr; - } - - // Closest hit shader - if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - Shader* shader = (Shader*)info->shaders[tmp->closestHitShaderIndex]; - ShaderEntry* entry = &shader->entries[tmp->closestHitShaderEntryIndex]; - group->ClosestHitShaderImport = entry->entryName; - - } else { - group->ClosestHitShaderImport = nullptr; - } - - // IntersectionShader shader - if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { - Shader* shader = (Shader*)info->shaders[tmp->intersectionShaderIndex]; - ShaderEntry* entry = &shader->entries[tmp->intersectionShaderEntryIndex]; - group->IntersectionShaderImport = entry->entryName; - - } else { - group->IntersectionShaderImport = nullptr; - } - - if (tmp->maxDataSize) { - localExports[localExportIndex] = group->HitGroupExport; - } - - subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_HIT_GROUP; - subObjects[subObjectIndex].pDesc = group; - subObjectIndex++; - hitGroupIndex++; - localExportIndex++; - } - - // check if we need a local root signature - D3D12_SUBOBJECT_TO_EXPORTS_ASSOCIATION localExportAssociation = {0}; - D3D12_LOCAL_ROOT_SIGNATURE localRootSignature = {0}; - if (localRootSize) { - D3D12_ROOT_PARAMETER1 parameter = {0}; - parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; - parameter.Constants.Num32BitValues = alignD3D12(localRootSize, 4) / 4; - parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - - D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; - rootDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; - rootDesc.Desc_1_1.NumParameters = 1; - rootDesc.Desc_1_1.pParameters = ¶meter; - rootDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_LOCAL_ROOT_SIGNATURE; - - ID3DBlob* blob = nullptr; - result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - result = d3d12Device->handle->lpVtbl->CreateRootSignature( - d3d12Device->handle, - 0, - blob->lpVtbl->GetBufferPointer(blob), - blob->lpVtbl->GetBufferSize(blob), - &IID_RootSignature, - (void**)&pipeline->localRootSignature); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - localRootSignature.pLocalRootSignature = pipeline->localRootSignature; - subObjects[subObjectIndex].Type = D3D12_STATE_SUBOBJECT_TYPE_LOCAL_ROOT_SIGNATURE; - subObjects[subObjectIndex].pDesc = &localRootSignature; - - localExportAssociation.pSubobjectToAssociate = &subObjects[subObjectIndex]; - localExportAssociation.pExports = localExports; - localExportAssociation.NumExports = localExportCount; - subObjectIndex++; - - D3D12_STATE_SUBOBJECT_TYPE t = D3D12_STATE_SUBOBJECT_TYPE_SUBOBJECT_TO_EXPORTS_ASSOCIATION; - subObjects[subObjectIndex].Type = t; - subObjects[subObjectIndex].pDesc = &localExportAssociation; - subObjectIndex++; - } - - D3D12_STATE_OBJECT_DESC desc = {0}; - desc.Type = D3D12_STATE_OBJECT_TYPE_RAYTRACING_PIPELINE; - desc.NumSubobjects = subObjectCount; - desc.pSubobjects = subObjects; - - result = d3d12Device->handle->lpVtbl->CreateStateObject( - d3d12Device->handle, - &desc, - &IID_StateObject, - &pipeline->handle); - - if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; - } - - palFree(s_D3D12.allocator, hitGroups); - palFree(s_D3D12.allocator, subObjects); - palFree(s_D3D12.allocator, libraryDescs); - palFree(s_D3D12.allocator, exportDescs); - palFree(s_D3D12.allocator, localExports); - - pipeline->type = RAY_TRACING_PIPELINE; - pipeline->strides = nullptr; - pipeline->hasFsr = PAL_FALSE; - pipeline->layout = layout; - - pipeline->sbtInfo = sbtInfo; - *outPipeline = (PalPipeline*)pipeline; - return PAL_RESULT_SUCCESS; -} - -void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) -{ - Pipeline* d3dPipeline = (Pipeline*)pipeline; - if (d3dPipeline->type == RAY_TRACING_PIPELINE) { - ID3D12StateObject* handle = d3dPipeline->handle; - handle->lpVtbl->Release(handle); - - } else { - ID3D12PipelineState* handle = d3dPipeline->handle; - handle->lpVtbl->Release(handle); - } - - if (d3dPipeline->localRootSignature) { - d3dPipeline->localRootSignature->lpVtbl->Release(d3dPipeline->localRootSignature); - } - - if (d3dPipeline->strides) { - palFree(s_D3D12.allocator, d3dPipeline->strides); - } - - if (d3dPipeline->shaderExports) { - palFree(s_D3D12.allocator, d3dPipeline->shaderExports); - } - - palFree(s_D3D12.allocator, d3dPipeline); -} - -// ================================================== -// Shader Binding Table -// ================================================== - - - #endif // PAL_HAS_D3D12_BACKEND #endif // _WIN32 diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index f2de821e..ba930875 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -474,15 +474,16 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN_BACKEND - result = initGraphicsVk(debugger, allocator); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - - attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base = s_VkBackend; - attachedBackend->startIndex = 0; - attachedBackend->count = 0; + // TODO: + // result = initGraphicsVk(debugger, allocator); + // if (result != PAL_RESULT_SUCCESS) { + // return result; + // } + + // attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + // attachedBackend->base = s_VkBackend; + // attachedBackend->startIndex = 0; + // attachedBackend->count = 0; #endif // PAL_HAS_VULKAN_BACKEND // D3D12 @@ -529,7 +530,7 @@ void PAL_CALL palShutdownGraphics() #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN_BACKEND - shutdownGraphicsVk(); + //TODO: shutdownGraphicsVk(); #endif // PAL_HAS_VULKAN_BACKEND // D3D12 diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c index d8859568..e7df0ea3 100644 --- a/src/graphics/vulkan/pal_commands_vulkan.c +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -8,8 +8,6 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" -#define min(a, b) (a < b) ? a : b - static void commitShaderbindingTableUpdate( CommandBufferVk* cmdBuffer, ShaderBindingTableVk* sbt) @@ -259,7 +257,16 @@ PalResult PAL_CALL cmdBeginVk( layout.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; VkFormat format = VK_FORMAT_UNDEFINED; - VkFormat colorAttachments[MAX_ATTACHMENTS]; + VkFormat* colorAttachments = nullptr; + colorAttachments = palAllocate( + s_Vk.allocator, + sizeof(VkFormat) * info->colorAttachentCount, + 0); + + if (!colorAttachments) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + if (!vkCmdBuffer->primary) { // secondary command buffer for (int i = 0; i < info->colorAttachentCount; i++) { @@ -291,6 +298,7 @@ PalResult PAL_CALL cmdBeginVk( return makeResultVk(result); } + palFree(s_Vk.allocator, colorAttachments); return PAL_RESULT_SUCCESS; } @@ -474,7 +482,16 @@ PalResult PAL_CALL cmdBeginRenderingVk( VkRenderingAttachmentInfoKHR depthAttachment = {0}; VkRenderingAttachmentInfoKHR stencilAttachment = {0}; - VkRenderingAttachmentInfoKHR colorAttachments[MAX_ATTACHMENTS]; + + VkRenderingAttachmentInfoKHR* colorAttachments = nullptr; + colorAttachments = palAllocate( + s_Vk.allocator, + sizeof(VkRenderingAttachmentInfoKHR) * info->colorAttachentCount, + 0); + + if (!colorAttachments) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } VkRenderingAttachmentInfoKHR* attachment = nullptr; PalAttachmentDesc* desc = nullptr; @@ -485,9 +502,6 @@ PalResult PAL_CALL cmdBeginRenderingVk( VkRenderingFragmentShadingRateAttachmentInfoKHR fsrInfo = {0}; fsrInfo.sType = VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR; - uint32_t layerCount = UINT32_MAX; - uint32_t renderWidth = UINT32_MAX; - uint32_t renderHeight = UINT32_MAX; for (int i = 0; i < info->colorAttachentCount; i++) { attachment = &colorAttachments[i]; desc = &info->colorAttachments[i]; @@ -532,17 +546,6 @@ PalResult PAL_CALL cmdBeginRenderingVk( attachment->resolveMode = resolveModeToVk(desc->resolveMode); attachment->imageLayout = layout; - - // compute layer count and render area - layerCount = min(layerCount, imageView->layerCount); - renderWidth = min(renderWidth, imageView->image->info.width); - renderHeight = min(renderHeight, imageView->image->info.height); - - if (resolveImageView) { - layerCount = min(layerCount, resolveImageView->layerCount); - renderWidth = min(renderWidth, resolveImageView->image->info.width); - renderHeight = min(renderHeight, resolveImageView->image->info.height); - } } rendering.colorAttachmentCount = info->colorAttachentCount; @@ -623,44 +626,23 @@ PalResult PAL_CALL cmdBeginRenderingVk( rendering.pDepthAttachment = &depthAttachment; rendering.pStencilAttachment = &stencilAttachment; - - // compute layer count and render area - layerCount = min(layerCount, imageView->layerCount); - renderWidth = min(renderWidth, imageView->image->info.width); - renderHeight = min(renderHeight, imageView->image->info.height); - - if (resolveImageView) { - layerCount = min(layerCount, resolveImageView->layerCount); - renderWidth = min(renderWidth, resolveImageView->image->info.width); - renderHeight = min(renderHeight, resolveImageView->image->info.height); - } } - // fragment shading rate attachment - if (info->fragmentShadingRateAttachment) { - imageView = (ImageViewVk*)info->fragmentShadingRateAttachment->imageView; + // fragment shading rate + if (info->fragmentShadingRateImageView) { + imageView = (ImageViewVk*)info->fragmentShadingRateImageView; fsrInfo.imageView = imageView->handle; - - fsrInfo.shadingRateAttachmentTexelSize.width = - info->fragmentShadingRateAttachment->texelWidth; - - fsrInfo.shadingRateAttachmentTexelSize.height = - info->fragmentShadingRateAttachment->texelHeight; - + fsrInfo.shadingRateAttachmentTexelSize.width = info->fragmentShadingRateTexelWidth; + fsrInfo.shadingRateAttachmentTexelSize.height = info->fragmentShadingRateTexelHeight; fsrInfo.imageLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; rendering.pNext = &fsrInfo; - - // compute layer count and render area - layerCount = min(layerCount, imageView->layerCount); - renderWidth = min(renderWidth, imageView->image->info.width); - renderHeight = min(renderHeight, imageView->image->info.height); } - rendering.layerCount = layerCount; - rendering.renderArea.offset.x = 0; - rendering.renderArea.offset.y = 0; - rendering.renderArea.extent.width = renderWidth; - rendering.renderArea.extent.height = renderHeight; + rendering.layerCount = info->arrayLayerCount; + rendering.renderArea.offset.x = info->renderArea.x; + rendering.renderArea.offset.y = info->renderArea.y; + rendering.renderArea.extent.width = info->renderArea.width; + rendering.renderArea.extent.height = info->renderArea.height; if (info->viewCount == 1) { rendering.viewMask = 0; @@ -668,7 +650,10 @@ PalResult PAL_CALL cmdBeginRenderingVk( rendering.viewMask = (1 << info->viewCount) - 1; } + rendering.flags = renderingFlagToVk(info->flags); vkCmdBuffer->device->cmdBeginRendering(vkCmdBuffer->handle, &rendering); + + palFree(s_Vk.allocator, colorAttachments); return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/vulkan/pal_device_vulkan.c b/src/graphics/vulkan/pal_device_vulkan.c index 13f79762..2587f085 100644 --- a/src/graphics/vulkan/pal_device_vulkan.c +++ b/src/graphics/vulkan/pal_device_vulkan.c @@ -622,7 +622,7 @@ PalResult PAL_CALL createDeviceVk( extensions[extCount++] = "VK_KHR_fragment_shading_rate"; fsr.pipelineFragmentShadingRate = PAL_TRUE; - // fragment shading rate attachment needs this + // fragment shading rate needs this if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { fsr.attachmentFragmentShadingRate = PAL_TRUE; } diff --git a/src/graphics/vulkan/pal_pipeline_vulkan.c b/src/graphics/vulkan/pal_pipeline_vulkan.c index 02d38cf2..fdaaa950 100644 --- a/src/graphics/vulkan/pal_pipeline_vulkan.c +++ b/src/graphics/vulkan/pal_pipeline_vulkan.c @@ -648,9 +648,18 @@ PalResult PAL_CALL createGraphicsPipelineVk( // layout info VkFormat format = VK_FORMAT_UNDEFINED; - VkFormat colorAttachments[MAX_ATTACHMENTS]; + VkFormat* colorAttachments = nullptr; PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; + colorAttachments = palAllocate( + s_Vk.allocator, + sizeof(VkFormat) * renderingLayout->colorAttachentCount, + 0); + + if (!colorAttachments) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + // color attachments for (int i = 0; i < renderingLayout->colorAttachentCount; i++) { format = formatToVk(renderingLayout->colorAttachmentsFormat[i]); @@ -684,6 +693,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( return makeResultVk(result); } + palFree(s_Vk.allocator, colorAttachments); palFree(s_Vk.allocator, shaderStages); if (info->vertexLayoutCount) { palFree(s_Vk.allocator, bindingDescs); diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h index 813e6b2f..fc2e1a4e 100644 --- a/src/graphics/vulkan/pal_vulkan.h +++ b/src/graphics/vulkan/pal_vulkan.h @@ -12,8 +12,6 @@ #include "pal/pal_graphics.h" #include -#define MAX_ATTACHMENTS 32 - typedef struct _XDisplay Display; typedef unsigned long Window; typedef struct xcb_connection_t xcb_connection_t; From 6a954dbb23771cd5468d625fe8e37b596dba69bb Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 7 Jul 2026 17:22:58 +0000 Subject: [PATCH 319/372] graphics rework: add image and pipeline d3d12 --- src/graphics/d3d12/pal_commands_d3d12.c | 17 +- src/graphics/d3d12/pal_d3d12.h | 4 + src/graphics/d3d12/pal_image_d3d12.c | 139 ++++++------ src/graphics/d3d12/pal_pipeline_d3d12.c | 279 ++++++++++++++---------- src/graphics/pal_d3d12.c | 95 -------- 5 files changed, 255 insertions(+), 279 deletions(-) diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index ddc4949a..cbf4234b 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -9,9 +9,6 @@ #include "pal_d3d12.h" #define align(v, a) (v + a - 1) & ~(a - 1) -#define GRAPHICS_PIPELINE 1220 -#define COMPUTE_PIPELINE 1221 -#define RAY_TRACING_PIPELINE 1222 static D3D12_RENDER_PASS_FLAGS renderingFlagToD3D12(PalRenderingFlags flags) { @@ -994,7 +991,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( PalUsageState newUsageState) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - ImageD3D12* d3dImage = (ImageD3D12*)image; + ImageD3D12* d3d12Image = (ImageD3D12*)image; D3D12_RESOURCE_STATES old, new; D3D12_RESOURCE_BARRIER barrier = {0}; @@ -1004,7 +1001,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( // read/write barrier without transition if (old == new && old == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrier.UAV.pResource = d3dImage->handle; + barrier.UAV.pResource = d3d12Image->handle; d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); return PAL_RESULT_SUCCESS; } @@ -1020,14 +1017,14 @@ PalResult PAL_CALL cmdImageBarrierD3D12( uint32_t startLevel = subresourceRange->startMipLevel; uint32_t startLayer = subresourceRange->startArrayLayer; - uint32_t maxLevels = d3dImage->info.mipLevelCount; - uint32_t maxLayers = d3dImage->info.arrayLayerCount; + uint32_t maxLevels = d3d12Image->info.mipLevelCount; + uint32_t maxLayers = d3d12Image->info.arrayLayerCount; uint32_t barrierCount = layerCount * levelCount * planeCount; if (startLevel == 0 && levelCount == maxLevels && startLayer == 0 && layerCount == maxLayers) { // full resource barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = d3dImage->handle; + barrier.Transition.pResource = d3d12Image->handle; barrier.Transition.StateBefore = old; barrier.Transition.StateAfter = new; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; @@ -1039,7 +1036,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( if (layerCount == 1 && layerCount == 1 && planeCount == 1) { // single plane barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = d3dImage->handle; + barrier.Transition.pResource = d3d12Image->handle; barrier.Transition.StateBefore = old; barrier.Transition.StateAfter = new; barrier.Transition.Subresource = startLevel + startLayer * maxLevels; @@ -1061,7 +1058,7 @@ PalResult PAL_CALL cmdImageBarrierD3D12( D3D12_RESOURCE_BARRIER* tmp = &barriers[count++]; tmp->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - tmp->Transition.pResource = d3dImage->handle; + tmp->Transition.pResource = d3d12Image->handle; tmp->Transition.StateBefore = old; tmp->Transition.StateAfter = new; tmp->Transition.Subresource = index; diff --git a/src/graphics/d3d12/pal_d3d12.h b/src/graphics/d3d12/pal_d3d12.h index adae9912..cc2a33b6 100644 --- a/src/graphics/d3d12/pal_d3d12.h +++ b/src/graphics/d3d12/pal_d3d12.h @@ -19,6 +19,9 @@ #define MAX_DSV 512 #define TEXTURE_PITCH 256 #define MAX_ATTACHMENTS 8 +#define GRAPHICS_PIPELINE 1220 +#define COMPUTE_PIPELINE 1221 +#define RAY_TRACING_PIPELINE 1222 typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, @@ -205,6 +208,7 @@ typedef struct { typedef struct { void* reserved; + PalBool isMemoryManaged; DeviceD3D12* device; ID3D12Resource* handle; PalImageInfo info; diff --git a/src/graphics/d3d12/pal_image_d3d12.c b/src/graphics/d3d12/pal_image_d3d12.c index 3c361eea..b9255c70 100644 --- a/src/graphics/d3d12/pal_image_d3d12.c +++ b/src/graphics/d3d12/pal_image_d3d12.c @@ -14,18 +14,18 @@ PalResult PAL_CALL createImageD3D12( PalImage** outImage) { HRESULT result; - Image* image = nullptr; - Device* d3d12Device = (Device*)device; + ImageD3D12* image = nullptr; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - image = palAllocate(s_D3D12.allocator, sizeof(Image), 0); + image = palAllocate(s_D3D12.allocator, sizeof(ImageD3D12), 0); if (!image) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } - memset(image, 0, sizeof(Image)); + memset(image, 0, sizeof(ImageD3D12)); image->desc.Width = (UINT64)info->width; image->desc.Height = (UINT64)info->height; - image->desc.DepthOrArraySize = (UINT16)info->depthOrArraySize; + image->desc.DepthOrArraySize = (UINT16)info->arrayLayerCount; image->desc.MipLevels = (UINT16)info->mipLevelCount; image->desc.Format = formatToD3D12(info->format); image->desc.SampleDesc.Count = samplesToD3D12(info->sampleCount); @@ -34,6 +34,7 @@ PalResult PAL_CALL createImageD3D12( image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; if (info->type == PAL_IMAGE_TYPE_3D) { image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + image->desc.DepthOrArraySize = (UINT16)info->depth; } else if (info->type == PAL_IMAGE_TYPE_1D) { image->desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE1D; @@ -51,8 +52,31 @@ PalResult PAL_CALL createImageD3D12( image->desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; } - image->belongsToSwapchain = PAL_FALSE; - image->info.depthOrArraySize = info->depthOrArraySize; + image->isMemoryManaged = PAL_FALSE; + if (info->memoryUsage != PAL_IMAGE_MEMORY_USAGE_MANUAL) { + D3D12_HEAP_PROPERTIES heapProps = {0}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + + result = d3d12Device->handle->lpVtbl->CreateCommittedResource( + d3d12Device->handle, + &heapProps, + 0, + &image->desc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + &IID_Resource, + (void**)&image->handle); + + if (FAILED(result)) { + return makeResultD3D12(result); + } + + image->isMemoryManaged = PAL_TRUE; + } + + image->info.depth = info->depth; + image->info.arrayLayerCount = info->arrayLayerCount; + image->info.belongsToSwapchain = PAL_FALSE; image->info.type = info->type; image->info.format = info->format; image->info.usages = info->usages; @@ -62,26 +86,26 @@ PalResult PAL_CALL createImageD3D12( image->info.width = info->width; image->device = d3d12Device; + image->reserved = PAL_BACKEND_KEY; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyImageD3D12(PalImage* image) { - Image* d3dImage = (Image*)image; - // check if memory has been attached to the image - if (d3dImage->handle) { - d3dImage->handle->lpVtbl->Release(d3dImage->handle); + ImageD3D12* d3d12Image = (ImageD3D12*)image; + if (d3d12Image->isMemoryManaged) { + d3d12Image->handle->lpVtbl->Release(d3d12Image->handle); } - palFree(s_D3D12.allocator, d3dImage); + palFree(s_D3D12.allocator, d3d12Image); } PalResult PAL_CALL getImageInfoD3D12( PalImage* image, PalImageInfo* info) { - Image* d3dImage = (Image*)image; - *info = d3dImage->info; + ImageD3D12* d3d12Image = (ImageD3D12*)image; + *info = d3d12Image->info; return PAL_RESULT_SUCCESS; } @@ -89,10 +113,10 @@ PalResult PAL_CALL getImageMemoryRequirementsD3D12( PalImage* image, PalMemoryRequirements* requirements) { - Image* d3dImage = (Image*)image; - ID3D12Device5* device = d3dImage->device->handle; - if (d3dImage->belongsToSwapchain) { - return PAL_RESULT_INVALID_OPERATION; + ImageD3D12* d3d12Image = (ImageD3D12*)image; + ID3D12Device5* device = d3d12Image->device->handle; + if (d3d12Image->info.belongsToSwapchain) { + return PAL_RESULT_CODE_INVALID_OPERATION; } D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; @@ -102,13 +126,9 @@ PalResult PAL_CALL getImageMemoryRequirementsD3D12( &__ret, 0, 1, - &d3dImage->desc); - - // d3d12 allows images to be used with only GPU only heap - requirements->memoryTypes[PAL_MEMORY_TYPE_GPU_ONLY] = PAL_TRUE; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_UPLOAD] = PAL_FALSE; - requirements->memoryTypes[PAL_MEMORY_TYPE_CPU_READBACK] = PAL_FALSE; + &d3d12Image->desc); + requirements->supportedMemoryTypes = (1u << PAL_MEMORY_TYPE_GPU_ONLY); requirements->alignment = allocationInfo.Alignment; requirements->size = allocationInfo.SizeInBytes; return PAL_RESULT_SUCCESS; @@ -120,10 +140,14 @@ PalResult PAL_CALL bindImageMemoryD3D12( uint64_t offset) { HRESULT result; - Image* d3dImage = (Image*)image; - ID3D12Device5* device = d3dImage->device->handle; - if (d3dImage->belongsToSwapchain) { - return PAL_RESULT_INVALID_OPERATION; + ImageD3D12* d3d12Image = (ImageD3D12*)image; + ID3D12Device5* device = d3d12Image->device->handle; + if (d3d12Image->info.belongsToSwapchain) { + return PAL_RESULT_CODE_INVALID_OPERATION; + } + + if (d3d12Image->isMemoryManaged) { + return PAL_RESULT_CODE_INVALID_OPERATION; } ID3D12Heap* mem = (ID3D12Heap*)memory; @@ -131,29 +155,20 @@ PalResult PAL_CALL bindImageMemoryD3D12( device, mem, offset, - &d3dImage->desc, + &d3d12Image->desc, 0, nullptr, &IID_Resource, - (void**)&d3dImage->handle); + (void**)&d3d12Image->handle); if (FAILED(result)) { - pollMessagesD3D12(d3dImage->device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } else if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; + pollMessagesD3D12(d3d12Image->device); + return makeResultD3D12(result); } return PAL_RESULT_SUCCESS; } -// ================================================== -// Image View -// ================================================== - PalResult PAL_CALL createImageViewD3D12( PalDevice* device, PalImage* image, @@ -161,24 +176,24 @@ PalResult PAL_CALL createImageViewD3D12( PalImageView** outImageView) { HRESULT result; - ImageView* imageView = nullptr; - Device* d3d12Device = (Device*)device; - Image* d3dImage = (Image*)image; + ImageViewD3D12* imageView = nullptr; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + ImageD3D12* d3d12Image = (ImageD3D12*)image; if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } } - imageView = palAllocate(s_D3D12.allocator, sizeof(ImageView), 0); + imageView = palAllocate(s_D3D12.allocator, sizeof(ImageViewD3D12), 0); if (!imageView) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } imageView->heapIndex = UINT32_MAX; - PalBool hasRTV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); - PalBool hasDSV = (d3dImage->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); + PalBool hasRTV = (d3d12Image->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); + PalBool hasDSV = (d3d12Image->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); imageView->format = formatToD3D12(info->format); if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR && hasRTV) { @@ -202,7 +217,7 @@ PalResult PAL_CALL createImageViewD3D12( imageView->heapIndex = index; d3d12Device->handle->lpVtbl->CreateRenderTargetView( d3d12Device->handle, - d3dImage->handle, + d3d12Image->handle, &desc, dst); @@ -227,14 +242,14 @@ PalResult PAL_CALL createImageViewD3D12( imageView->heapIndex = index; d3d12Device->handle->lpVtbl->CreateDepthStencilView( d3d12Device->handle, - d3dImage->handle, + d3d12Image->handle, &desc, dst); } imageView->range = info->subresourceRange; imageView->type = info->type; - imageView->image = d3dImage; + imageView->image = d3d12Image; imageView->device = d3d12Device; *outImageView = (PalImageView*)imageView; @@ -243,8 +258,8 @@ PalResult PAL_CALL createImageViewD3D12( void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) { - ImageView* d3dImageView = (ImageView*)imageView; - Device* device = d3dImageView->device; + ImageViewD3D12* d3dImageView = (ImageViewD3D12*)imageView; + DeviceD3D12* device = d3dImageView->device; RTVHeapAllocator* allocator = nullptr; if (d3dImageView->heapIndex != UINT32_MAX) { @@ -267,18 +282,18 @@ PalResult PAL_CALL createSamplerD3D12( const PalSamplerCreateInfo* info, PalSampler** outSampler) { - Device* d3d12Device = (Device*)device; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; if (info->maxAnisotropy > d3d12Device->limits.maxAnisotropy) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } - Sampler* sampler = nullptr; - sampler = palAllocate(s_D3D12.allocator, sizeof(Sampler), 0); + SamplerD3D12* sampler = nullptr; + sampler = palAllocate(s_D3D12.allocator, sizeof(SamplerD3D12), 0); if (!sampler) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } - memset(sampler, 0, sizeof(Sampler)); + memset(sampler, 0, sizeof(SamplerD3D12)); sampler->desc.MaxLOD = info->maxLod; sampler->desc.MinLOD = info->minLod; sampler->desc.MipLODBias = info->mipLodBias; @@ -309,7 +324,7 @@ PalResult PAL_CALL createSamplerD3D12( void PAL_CALL destroySamplerD3D12(PalSampler* sampler) { - Sampler* d3dSampler = (Sampler*)sampler; + SamplerD3D12* d3dSampler = (SamplerD3D12*)sampler; palFree(s_D3D12.allocator, d3dSampler); } diff --git a/src/graphics/d3d12/pal_pipeline_d3d12.c b/src/graphics/d3d12/pal_pipeline_d3d12.c index cc319a61..46d3db91 100644 --- a/src/graphics/d3d12/pal_pipeline_d3d12.c +++ b/src/graphics/d3d12/pal_pipeline_d3d12.c @@ -8,13 +8,108 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" +#if INTPTR_MAX == INT64_MAX +#define PTR_SIZE 8 +#else +#define PTR_SIZE 4 +#endif // INTPTR_MAX + +#if defined(_MSC_VER) +#define ALIGN_STREAM __declspec(align(PTR_SIZE)) +#elif defined(__GNUC__) || defined(__clang__) +#define ALIGN_STREAM __attribute__((aligned(PTR_SIZE))) +#else + #define ALIGN_STREAM +#endif // _MSC_VER + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + ID3D12RootSignature* root; +} RootSignatureStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_INPUT_LAYOUT_DESC desc; +} InputLayoutStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_PRIMITIVE_TOPOLOGY_TYPE topology; +} TopologyStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_INDEX_BUFFER_STRIP_CUT_VALUE value; +} IBStripCutStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_RASTERIZER_DESC desc; +} RasterizerStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + DXGI_SAMPLE_DESC desc; +} SampleDescStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + UINT mask; +} SampleMaskStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_DEPTH_STENCIL_DESC desc; +} DepthStencilStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_BLEND_DESC desc; +} BlendStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + struct D3D12_RT_FORMAT_ARRAY data; +} RTVStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + DXGI_FORMAT format; +} DSVStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_SHADER_BYTECODE desc; +} ShaderStream; + +typedef ALIGN_STREAM struct { + D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; + D3D12_VIEW_INSTANCING_DESC desc; +} ViewInstancingStream; + +typedef struct { + RootSignatureStream layout; + InputLayoutStream inputLayout; + TopologyStream topology; + IBStripCutStream ibStripCut; + RasterizerStream rasterizer; + SampleDescStream sampleDesc; + SampleMaskStream sampleMask; + DepthStencilStream depthStencil; + BlendStream blend; + RTVStream RTV; + DSVStream DSV; + ViewInstancingStream viewInstancing; + ShaderStream shaders[7]; // 7 shader types for graphics pipeline +} GraphicsPipelineStreamDesc; + PalResult PAL_CALL createPipelineLayoutD3D12( PalDevice* device, const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout) { - Device* d3d12Device = (Device*)device; - PipelineLayout* layout = nullptr; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + PipelineLayoutD3D12* layout = nullptr; uint32_t resourceCount = 0; uint32_t samplerCount = 0; uint64_t pushConstantSize = 0; @@ -31,7 +126,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( rootFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; if (info->descriptorSetLayoutCount > d3d12Device->limits.maxBoundDescriptorSets) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (d3d12Device->shaderModel >= PAL_MAKE_SHADER_TARGET(6, 6)) { @@ -41,7 +136,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( // get the total resource and sampler ranges for all provided descriptor set layouts for (int i = 0; i < info->descriptorSetLayoutCount; i++) { - DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; + DescriptorSetLayoutD3D12* tmp = (DescriptorSetLayoutD3D12*)info->descriptorSetLayouts[i]; resourceCount += tmp->bindingCount - tmp->samplerCount; samplerCount += tmp->samplerCount; @@ -54,32 +149,27 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } } - // get the total size needed for all provided push constant range - for (int i = 0; i < info->pushConstantRangeCount; i++) { - PalPushConstantRange* tmp = &info->pushConstantRanges[i]; - if (tmp->offset + tmp->size > pushConstantSize) { - pushConstantSize = tmp->offset + tmp->size; + if (info->usePushConstant) { + pushConstantSize = info->pushConstantInfo.offset + info->pushConstantInfo.size; + if (pushConstantSize > d3d12Device->limits.maxPushConstantSize) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; } - } - if (pushConstantSize > d3d12Device->limits.maxPushConstantSize) { - return PAL_RESULT_INVALID_ARGUMENT; + if (pushConstantSize) { + parameterCount++; + } } - layout = palAllocate(s_D3D12.allocator, sizeof(PipelineLayout), 0); + layout = palAllocate(s_D3D12.allocator, sizeof(PipelineLayoutD3D12), 0); if (!layout) { - return PAL_RESULT_OUT_OF_MEMORY; - } - - if (pushConstantSize) { - parameterCount++; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } if (parameterCount) { uint32_t paramtersSize = sizeof(D3D12_ROOT_PARAMETER1) * parameterCount; parameters = palAllocate(s_D3D12.allocator, paramtersSize, 0); if (!parameters) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } memset(parameters, 0, paramtersSize); @@ -88,21 +178,21 @@ PalResult PAL_CALL createPipelineLayoutD3D12( if (resourceCount) { ranges = palAllocate(s_D3D12.allocator, sizeInBytes * resourceCount, 0); if (!ranges) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } } if (samplerCount) { samplerRanges = palAllocate(s_D3D12.allocator, sizeInBytes * samplerCount, 0); if (!samplerRanges) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } } // write root constant first if its provided parameterCount = 0; // reset and reuse the same variable layout->constantIndex = UINT32_MAX; - if (pushConstantSize) { + if (pushConstantSize && info->usePushConstant) { D3D12_ROOT_PARAMETER1* parameter = ¶meters[parameterCount]; parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; parameter->Constants.Num32BitValues = (UINT)pushConstantSize / 4; @@ -114,7 +204,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( uint32_t registerSpace = 0; for (int i = 0; i < info->descriptorSetLayoutCount; i++) { - DescriptorSetLayout* tmp = (DescriptorSetLayout*)info->descriptorSetLayouts[i]; + DescriptorSetLayoutD3D12* tmp = (DescriptorSetLayoutD3D12*)info->descriptorSetLayouts[i]; D3D12_ROOT_PARAMETER1* parameter = nullptr; // reset and reuse same variable @@ -145,7 +235,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter->DescriptorTable.NumDescriptorRanges = resourceCount; parameter->DescriptorTable.pDescriptorRanges = &ranges[rangesOffset]; - parameter->ShaderVisibility = tmp->visibility; + parameter->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; rangesOffset += resourceCount; parameterCount++; @@ -157,7 +247,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( parameter->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; parameter->DescriptorTable.NumDescriptorRanges = samplerCount; parameter->DescriptorTable.pDescriptorRanges = &samplerRanges[samplerRangesOffset]; - parameter->ShaderVisibility = tmp->visibility; + parameter->ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; samplerRangesOffset += samplerCount; parameterCount++; @@ -177,10 +267,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( HRESULT result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } result = d3d12Device->handle->lpVtbl->CreateRootSignature( @@ -193,12 +280,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( if (FAILED(result)) { pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } if (resourceCount) { @@ -212,23 +294,20 @@ PalResult PAL_CALL createPipelineLayoutD3D12( if (parameterCount) { palFree(s_D3D12.allocator, parameters); } - blob->lpVtbl->Release(blob); + + layout->reserved = PAL_BACKEND_KEY; *outLayout = (PalPipelineLayout*)layout; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout) { - PipelineLayout* d3d12Layout = (PipelineLayout*)layout; + PipelineLayoutD3D12* d3d12Layout = (PipelineLayoutD3D12*)layout; d3d12Layout->handle->lpVtbl->Release(d3d12Layout->handle); palFree(s_D3D12.allocator, d3d12Layout); } -// ================================================== -// Pipeline -// ================================================== - PalResult PAL_CALL createGraphicsPipelineD3D12( PalDevice* device, const PalGraphicsPipelineCreateInfo* info, @@ -238,9 +317,9 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( uint32_t patchControlPoints = 0; uint32_t totalSize = 0; PalBool alphaToCoverageEnable = PAL_FALSE; - Pipeline* pipeline = nullptr; - Device* d3d12Device = (Device*)device; - PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; + PipelineD3D12* pipeline = nullptr; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + PipelineLayoutD3D12* layout = (PipelineLayoutD3D12*)info->pipelineLayout; D3D12_INPUT_ELEMENT_DESC* elementDescs = nullptr; D3D12_VIEW_INSTANCE_LOCATION* viewLocations = nullptr; @@ -248,11 +327,11 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( GraphicsPipelineStreamDesc graphicsStreamDesc = {0}; memset(&graphicsStreamDesc, 0, sizeof(GraphicsPipelineStreamDesc)); - pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); + pipeline = palAllocate(s_D3D12.allocator, sizeof(PipelineD3D12), 0); if (!pipeline) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } - memset(pipeline, 0, sizeof(Pipeline)); + memset(pipeline, 0, sizeof(PipelineD3D12)); if (info->renderingLayout->viewCount > 1) { viewLocations = palAllocate( @@ -261,7 +340,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( 0); if (!viewLocations) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } } @@ -273,7 +352,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( // shaders for (int i = 0; i < info->shaderCount; i++) { - Shader* tmp = (Shader*)info->shaders[i]; + ShaderD3D12* tmp = (ShaderD3D12*)info->shaders[i]; ShaderStream* shaderStream = &graphicsStreamDesc.shaders[i]; totalSize += sizeof(ShaderStream); D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; @@ -283,7 +362,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( patchControlPoints = entry->patchControlPoints; if (info->topology != PAL_PRIMITIVE_TOPOLOGY_PATCH) { palFree(s_D3D12.allocator, pipeline); - return PAL_RESULT_INVALID_OPERATION; + return PAL_RESULT_CODE_INVALID_OPERATION; } } @@ -324,11 +403,11 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( } if (info->vertexLayoutCount > d3d12Device->limits.maxVertexLayouts) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (vertexCount > d3d12Device->limits.maxVertexAttributes) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } InputLayoutStream* inputLayoutStream = &graphicsStreamDesc.inputLayout; @@ -339,7 +418,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( if (vertexCount) { pipeline->strides = palAllocate(s_D3D12.allocator, sizeof(uint32_t) * 8, 0); if (!pipeline->strides) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } elementDescs = palAllocate( @@ -349,7 +428,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( if (!elementDescs) { palFree(s_D3D12.allocator, elementDescs); - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } uint32_t positionIndex = 0; @@ -369,11 +448,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( elementDesc->Format = vertexTypeToD3D12(vertexAttrib->type); elementDesc->InputSlot = layout->binding; - if (vertexAttrib->semanticName) { - elementDesc->SemanticName = vertexAttrib->semanticName; - } else { - elementDesc->SemanticName = semanticIDToStringD3D12(vertexAttrib->semanticID); - } + elementDesc->SemanticName = semanticIDToStringD3D12(vertexAttrib->semanticID); if (vertexAttrib->semanticID == PAL_VERTEX_SEMANTIC_ID_POSITION) { elementDesc->SemanticIndex = positionIndex++; @@ -675,12 +750,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( if (FAILED(result)) { pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } if (info->vertexLayoutCount) { @@ -696,6 +766,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( pipeline->layout = layout; pipeline->shaderExports = nullptr; pipeline->localRootSignature = nullptr; + pipeline->reserved = PAL_BACKEND_KEY; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -706,14 +777,14 @@ PalResult PAL_CALL createComputePipelineD3D12( const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline) { - Device* d3d12Device = (Device*)device; - PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - Shader* shader = (Shader*)info->computeShader; - Pipeline* pipeline = nullptr; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + PipelineLayoutD3D12* layout = (PipelineLayoutD3D12*)info->pipelineLayout; + ShaderD3D12* shader = (ShaderD3D12*)info->computeShader; + PipelineD3D12* pipeline = nullptr; - pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); + pipeline = palAllocate(s_D3D12.allocator, sizeof(PipelineD3D12), 0); if (!pipeline) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } D3D12_COMPUTE_PIPELINE_STATE_DESC desc = {0}; @@ -728,12 +799,7 @@ PalResult PAL_CALL createComputePipelineD3D12( if (FAILED(result)) { pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } pipeline->type = COMPUTE_PIPELINE; @@ -742,6 +808,7 @@ PalResult PAL_CALL createComputePipelineD3D12( pipeline->layout = layout; pipeline->shaderExports = nullptr; pipeline->localRootSignature = nullptr; + pipeline->reserved = PAL_BACKEND_KEY; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -753,24 +820,24 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( PalPipeline** outPipeline) { HRESULT result; - Device* d3d12Device = (Device*)device; - PipelineLayout* layout = (PipelineLayout*)info->pipelineLayout; - Pipeline* pipeline = nullptr; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + PipelineLayoutD3D12* layout = (PipelineLayoutD3D12*)info->pipelineLayout; + PipelineD3D12* pipeline = nullptr; if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } if (info->maxAttributeSize > d3d12Device->limits.maxHitAttributeSize) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (info->maxPayloadSize > d3d12Device->limits.maxPayloadSize) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (info->maxRecursionDepth> d3d12Device->limits.maxRecursionDepth) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } D3D12_EXPORT_DESC* exportDescs = nullptr; @@ -782,7 +849,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // find the total number of exports uint32_t exportCount = 0; for (int i = 0; i < info->shaderCount; i++) { - Shader* shader = (Shader*)info->shaders[i]; + ShaderD3D12* shader = (ShaderD3D12*)info->shaders[i]; exportCount += shader->entryCount; } @@ -794,7 +861,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { // check if its raygen, miss or callable - Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; + ShaderD3D12* shader = (ShaderD3D12*)info->shaders[tmp->generalShaderIndex]; ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; switch (entry->stage) { case PAL_SHADER_STAGE_RAYGEN: { @@ -845,16 +912,16 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( subObjectCount += 2; } - pipeline = palAllocate(s_D3D12.allocator, sizeof(Pipeline), 0); + pipeline = palAllocate(s_D3D12.allocator, sizeof(PipelineD3D12), 0); if (!pipeline) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } pipeline->shaderExportCount = exportCount + sbtInfo.hitCount; subObjects = palAllocate(s_D3D12.allocator, sizeof(D3D12_STATE_SUBOBJECT) * subObjectCount, 0); hitGroups = palAllocate(s_D3D12.allocator, sizeof(RayHitGroup) * sbtInfo.hitCount, 0); if (!subObjects || !hitGroups) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } libraryDescs = palAllocate( @@ -878,7 +945,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( 0); if (!libraryDescs || !exportDescs || !pipeline->shaderExports || !localExports) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } // global root signature @@ -907,7 +974,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // shaders uint32_t exportsOffset = 0; for (int i = 0; i < info->shaderCount; i++) { - Shader* tmp = (Shader*)info->shaders[i]; + ShaderD3D12* tmp = (ShaderD3D12*)info->shaders[i]; D3D12_DXIL_LIBRARY_DESC* libraryDesc = &libraryDescs[i]; libraryDesc->DXILLibrary = tmp->byteCode; @@ -942,7 +1009,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( PalRayTracingShaderGroupCreateInfo* tmp = &info->shaderGroups[i]; if (tmp->type == PAL_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL) { if (tmp->maxDataSize) { - Shader* shader = (Shader*)info->shaders[tmp->generalShaderIndex]; + ShaderD3D12* shader = (ShaderD3D12*)info->shaders[tmp->generalShaderIndex]; ShaderEntry* entry = &shader->entries[tmp->generalShaderEntryIndex]; localExports[localExportIndex++] = entry->entryName; } @@ -972,7 +1039,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // Any hit shader if (tmp->anyHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - Shader* shader = (Shader*)info->shaders[tmp->anyHitShaderIndex]; + ShaderD3D12* shader = (ShaderD3D12*)info->shaders[tmp->anyHitShaderIndex]; ShaderEntry* entry = &shader->entries[tmp->anyHitShaderEntryIndex]; group->AnyHitShaderImport = entry->entryName; @@ -982,7 +1049,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // Closest hit shader if (tmp->closestHitShaderIndex != PAL_UNUSED_SHADER_INDEX) { - Shader* shader = (Shader*)info->shaders[tmp->closestHitShaderIndex]; + ShaderD3D12* shader = (ShaderD3D12*)info->shaders[tmp->closestHitShaderIndex]; ShaderEntry* entry = &shader->entries[tmp->closestHitShaderEntryIndex]; group->ClosestHitShaderImport = entry->entryName; @@ -992,7 +1059,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( // IntersectionShader shader if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { - Shader* shader = (Shader*)info->shaders[tmp->intersectionShaderIndex]; + ShaderD3D12* shader = (ShaderD3D12*)info->shaders[tmp->intersectionShaderIndex]; ShaderEntry* entry = &shader->entries[tmp->intersectionShaderEntryIndex]; group->IntersectionShaderImport = entry->entryName; @@ -1030,10 +1097,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } result = d3d12Device->handle->lpVtbl->CreateRootSignature( @@ -1046,12 +1110,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( if (FAILED(result)) { pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } localRootSignature.pLocalRootSignature = pipeline->localRootSignature; @@ -1082,12 +1141,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( if (FAILED(result)) { pollMessagesD3D12(d3d12Device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } else if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } palFree(s_D3D12.allocator, hitGroups); @@ -1100,6 +1154,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( pipeline->strides = nullptr; pipeline->hasFsr = PAL_FALSE; pipeline->layout = layout; + pipeline->reserved = PAL_BACKEND_KEY; pipeline->sbtInfo = sbtInfo; *outPipeline = (PalPipeline*)pipeline; @@ -1108,7 +1163,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) { - Pipeline* d3dPipeline = (Pipeline*)pipeline; + PipelineD3D12* d3dPipeline = (PipelineD3D12*)pipeline; if (d3dPipeline->type == RAY_TRACING_PIPELINE) { ID3D12StateObject* handle = d3dPipeline->handle; handle->lpVtbl->Release(handle); diff --git a/src/graphics/pal_d3d12.c b/src/graphics/pal_d3d12.c index 518e6abb..98355f6a 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/pal_d3d12.c @@ -21,20 +21,6 @@ #define MAX_MESSAGE_SIZE 4096 -#if INTPTR_MAX == INT64_MAX -#define PTR_SIZE 8 -#else -#define PTR_SIZE 4 -#endif // INTPTR_MAX - -#if defined(_MSC_VER) -#define ALIGN_STREAM __declspec(align(PTR_SIZE)) -#elif defined(__GNUC__) || defined(__clang__) -#define ALIGN_STREAM __attribute__((aligned(PTR_SIZE))) -#else - #define ALIGN_STREAM -#endif // _MSC_VER - // IIDS IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0xd2,0x4e}; @@ -58,87 +44,6 @@ IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0 IID IID_StateObjectProps = {0xde5fa827, 0x9bf9, 0x4f26, 0x89,0xff, 0xd7,0xf5,0x6f,0xde,0x38,0x60}; IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - ID3D12RootSignature* root; -} RootSignatureStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_INPUT_LAYOUT_DESC desc; -} InputLayoutStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_PRIMITIVE_TOPOLOGY_TYPE topology; -} TopologyStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_INDEX_BUFFER_STRIP_CUT_VALUE value; -} IBStripCutStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_RASTERIZER_DESC desc; -} RasterizerStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - DXGI_SAMPLE_DESC desc; -} SampleDescStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - UINT mask; -} SampleMaskStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_DEPTH_STENCIL_DESC desc; -} DepthStencilStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_BLEND_DESC desc; -} BlendStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - struct D3D12_RT_FORMAT_ARRAY data; -} RTVStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - DXGI_FORMAT format; -} DSVStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_SHADER_BYTECODE desc; -} ShaderStream; - -typedef ALIGN_STREAM struct { - D3D12_PIPELINE_STATE_SUBOBJECT_TYPE type; - D3D12_VIEW_INSTANCING_DESC desc; -} ViewInstancingStream; - -typedef struct { - RootSignatureStream layout; - InputLayoutStream inputLayout; - TopologyStream topology; - IBStripCutStream ibStripCut; - RasterizerStream rasterizer; - SampleDescStream sampleDesc; - SampleMaskStream sampleMask; - DepthStencilStream depthStencil; - BlendStream blend; - RTVStream RTV; - DSVStream DSV; - ViewInstancingStream viewInstancing; - ShaderStream shaders[7]; // 7 shader types for graphics pipeline -} GraphicsPipelineStreamDesc; - static D3D12 s_D3D12 = {0}; // ================================================== From c67c9dcdcb713583f19dfb1afba2106668d09014 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 7 Jul 2026 17:43:59 +0000 Subject: [PATCH 320/372] graphics rework: add swapchain d3d12 --- src/graphics/d3d12/pal_swapchain_d3d12.c | 195 ++++++++++----------- src/graphics/vulkan/pal_swapchain_vulkan.c | 2 +- 2 files changed, 97 insertions(+), 100 deletions(-) diff --git a/src/graphics/d3d12/pal_swapchain_d3d12.c b/src/graphics/d3d12/pal_swapchain_d3d12.c index 4f9f869d..e3e768b3 100644 --- a/src/graphics/d3d12/pal_swapchain_d3d12.c +++ b/src/graphics/d3d12/pal_swapchain_d3d12.c @@ -10,33 +10,36 @@ PalResult PAL_CALL createSurfaceD3D12( PalDevice* device, - PalGraphicsWindow* window, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, PalSurface** outSurface) { - Device* d3d12Device = (Device*)device; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } - Surface* surface = nullptr; - surface = palAllocate(s_D3D12.allocator, sizeof(Surface), 0); + SurfaceD3D12* surface = nullptr; + surface = palAllocate(s_D3D12.allocator, sizeof(SurfaceD3D12), 0); if (!surface) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } // validate if the window is valid - if (!IsWindow((HWND)window->window)) { - return PAL_RESULT_INVALID_GRAPHICS_WINDOW; + if (!IsWindow((HWND)window)) { + return PAL_RESULT_CODE_INVALID_HANDLE; } - surface->handle = window->window; + surface->handle = window; + surface->reserved = PAL_BACKEND_KEY; *outSurface = (PalSurface*)surface; return PAL_RESULT_SUCCESS; } void PAL_CALL destroySurfaceD3D12(PalSurface* surface) { - Surface* d3dSurface = (Surface*)surface; + SurfaceD3D12* d3dSurface = (SurfaceD3D12*)surface; palFree(s_D3D12.allocator, d3dSurface); } @@ -46,14 +49,14 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( PalSurfaceCapabilities* caps) { HRESULT result; - Surface* d3dSurface = (Surface*)surface; - Device* d3d12Device = (Device*)device; + SurfaceD3D12* d3dSurface = (SurfaceD3D12*)surface; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; PalBool supportHDR10 = PAL_FALSE; IDXGISwapChain1* swapchain1 = nullptr; IDXGISwapChain3* swapchain3 = nullptr; if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } DXGI_SWAP_CHAIN_DESC1 desc = {0}; @@ -77,10 +80,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( if (FAILED(result)) { pollMessagesD3D12(d3d12Device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } swapchain1->lpVtbl->QueryInterface(swapchain1, &IID_Swapchain, (void**)&swapchain3); @@ -104,21 +104,15 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( &allowTearing, sizeof(allowTearing)); - caps->presentModes[PAL_PRESENT_MODE_FIFO] = PAL_TRUE; + caps->minImageCount = 2; + caps->supportedPresentModes = (1u << PAL_PRESENT_MODE_FIFO); if (allowTearing) { caps->minImageCount = 3; - caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_TRUE; - caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_TRUE; - - } else { - caps->minImageCount = 2; - caps->presentModes[PAL_PRESENT_MODE_IMMEDIATE] = PAL_FALSE; - caps->presentModes[PAL_PRESENT_MODE_MAILBOX] = PAL_FALSE; + caps->supportedPresentModes |= (1u << PAL_PRESENT_MODE_IMMEDIATE); + caps->supportedPresentModes |= (1u << PAL_PRESENT_MODE_MAILBOX); } - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_OPAQUE] = PAL_TRUE; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_PRE_MULTIPLIED] = PAL_FALSE; - caps->compositeAlphas[PAL_COMPOSITE_ALPHA_POST_MULTIPLIED] = PAL_FALSE; + caps->supportedCompositeAlphas |= (1u << PAL_COMPOSITE_ALPHA_OPAQUE); caps->maxImageCount = 8; // safe default caps->minImageWidth = 1; @@ -128,19 +122,15 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( caps->maxImageArrayLayers = 1; // check support for the base format + caps->supportedFormats = 0; D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport = {0}; - DXGI_FORMAT baseFormats[PAL_SURFACE_FORMAT_MAX]; + DXGI_FORMAT baseFormats[PAL_SURFACE_FORMAT_COUNT]; baseFormats[0] = DXGI_FORMAT_B8G8R8A8_UNORM; baseFormats[1] = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; baseFormats[2] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; baseFormats[3] = DXGI_FORMAT_R16G16B16A16_FLOAT; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_FALSE; - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_FALSE; - caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_FALSE; - - for (int i = 0; i < PAL_SURFACE_FORMAT_MAX; i++) { + for (int i = 0; i < PAL_SURFACE_FORMAT_COUNT; i++) { formatSupport.Format = baseFormats[i]; result = d3d12Device->handle->lpVtbl->CheckFeatureSupport( d3d12Device->handle, @@ -150,21 +140,21 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( if (SUCCEEDED(result) && (formatSupport.Support1 != 0 || formatSupport.Support2 != 0)) { if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; + caps->supportedFormats |= (1u << PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR); } if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) { - caps->formats[PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR] = PAL_TRUE; + caps->supportedFormats |= (1u << PAL_SURFACE_FORMAT_BGRA8_SRGB_NONLINEAR); } if (baseFormats[i] == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) { - caps->formats[PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR] = PAL_TRUE; + caps->supportedFormats |= (1u << PAL_SURFACE_FORMAT_RGBA8_UNORM_SRGB_NONLINEAR); } if (baseFormats[i] == DXGI_FORMAT_R16G16B16A16_FLOAT) { // check HDR10 color space if (supportHDR10) { - caps->formats[PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10] = PAL_TRUE; + caps->supportedFormats |= (1u << PAL_SURFACE_FORMAT_RGBA16_FLOAT_HDR10); } } } @@ -174,10 +164,6 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( return PAL_RESULT_SUCCESS; } -// ================================================== -// Swapchain -// ================================================== - PalResult PAL_CALL createSwapchainD3D12( PalDevice* device, PalQueue* queue, @@ -186,35 +172,35 @@ PalResult PAL_CALL createSwapchainD3D12( PalSwapchain** outSwapchain) { HRESULT result; - Surface* d3dSurface = (Surface*)surface; - Device* d3d12Device = (Device*)device; - Queue* d3d12Queue = (Queue*)queue; - Swapchain* swapchain = nullptr; + SurfaceD3D12* d3dSurface = (SurfaceD3D12*)surface; + DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + QueueD3D12* d3d12Queue = (QueueD3D12*)queue; + SwapchainD3D12* swapchain = nullptr; PalBool isHDRColorspace = PAL_FALSE; if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED; + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } if (d3d12Queue->type != PAL_QUEUE_TYPE_GRAPHICS) { - return PAL_RESULT_INVALID_QUEUE; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (info->compositeAlpha != PAL_COMPOSITE_ALPHA_OPAQUE) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (info->presentMode == PAL_PRESENT_MODE_MAILBOX && info->imageCount < 3) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } if (info->imageCount > 8) { - return PAL_RESULT_INVALID_ARGUMENT; + return PAL_RESULT_CODE_INVALID_ARGUMENT; } - swapchain = palAllocate(s_D3D12.allocator, sizeof(Swapchain), 0); + swapchain = palAllocate(s_D3D12.allocator, sizeof(SwapchainD3D12), 0); if (!swapchain) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } IDXGISwapChain1* swapchain1 = nullptr; @@ -276,12 +262,7 @@ PalResult PAL_CALL createSwapchainD3D12( if (FAILED(result)) { pollMessagesD3D12(d3d12Device); - if (result == E_OUTOFMEMORY) { - return PAL_RESULT_OUT_OF_MEMORY; - } else if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } swapchain1->lpVtbl->QueryInterface(swapchain1, &IID_Swapchain, (void**)&swapchain->handle); @@ -293,27 +274,29 @@ PalResult PAL_CALL createSwapchainD3D12( DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); } else { swapchain->handle->lpVtbl->SetColorSpace1( - swapchain->handle, DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709); + swapchain->handle, + DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709); } // get and cache swapchain images swapchain->images = nullptr; - swapchain->images = palAllocate(s_D3D12.allocator, sizeof(Image) * info->imageCount, 0); + swapchain->images = palAllocate(s_D3D12.allocator, sizeof(ImageD3D12) * info->imageCount, 0); if (!swapchain->imageCount) { - return PAL_RESULT_OUT_OF_MEMORY; + return PAL_RESULT_CODE_OUT_OF_MEMORY; } - // fill all images with the creatio info + // fill all images with the creation info for (int i = 0; i < info->imageCount; i++) { ID3D12Resource* tmp = nullptr; swapchain->handle->lpVtbl->GetBuffer(swapchain->handle, i, &IID_Resource, (void**)&tmp); - Image* image = &swapchain->images[i]; - image->belongsToSwapchain = PAL_TRUE; + ImageD3D12* image = &swapchain->images[i]; image->device = d3d12Device; image->handle = tmp; - image->info.depthOrArraySize = 1; // always 1 + image->info.belongsToSwapchain = PAL_TRUE; + image->info.depth = 1; // always 1 + image->info.arrayLayerCount = 1; // always 1 image->info.format = imageFormat; image->info.usages = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; image->info.height = info->height; @@ -338,7 +321,7 @@ PalResult PAL_CALL createSwapchainD3D12( void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) { - Swapchain* d3dSwapchain = (Swapchain*)swapchain; + SwapchainD3D12* d3dSwapchain = (SwapchainD3D12*)swapchain; d3dSwapchain->handle->lpVtbl->Release(d3dSwapchain->handle); palFree(s_D3D12.allocator, d3dSwapchain->images); palFree(s_D3D12.allocator, d3dSwapchain); @@ -348,7 +331,7 @@ PalImage* PAL_CALL getSwapchainImageD3D12( PalSwapchain* swapchain, uint32_t index) { - Swapchain* d3dSwapchain = (Swapchain*)swapchain; + SwapchainD3D12* d3dSwapchain = (SwapchainD3D12*)swapchain; if (index > d3dSwapchain->imageCount) { return nullptr; } @@ -360,24 +343,29 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( PalSwapchainNextImageInfo* info, uint32_t* outIndex) { + HRESULT result; uint32_t index = 0; - Swapchain* d3dSwapchain = (Swapchain*)swapchain; + SwapchainD3D12* d3dSwapchain = (SwapchainD3D12*)swapchain; ID3D12CommandQueue* queue = d3dSwapchain->queue; index = d3dSwapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3dSwapchain->handle); if (info->fence) { - Fence* fence = (Fence*)info->fence; + FenceD3D12* fence = (FenceD3D12*)info->fence; fence->value++; - queue->lpVtbl->Signal(queue, fence->handle, fence->value); + result = queue->lpVtbl->Signal(queue, fence->handle, fence->value); + if (FAILED(result)) { + pollMessagesD3D12(d3dSwapchain->device); + return makeResultD3D12(result); + } } if (info->signalSemaphore) { - Semaphore* semaphore = (Semaphore*)info->signalSemaphore; - if (semaphore->isTimeline) { - queue->lpVtbl->Signal(queue, semaphore->handle, info->signalValue); - } else { - semaphore->value = 1; - queue->lpVtbl->Signal(queue, semaphore->handle, semaphore->value); + SemaphoreD3D12* semaphore = (SemaphoreD3D12*)info->signalSemaphore; + semaphore->value = 1; + result = queue->lpVtbl->Signal(queue, semaphore->handle, semaphore->value); + if (FAILED(result)) { + pollMessagesD3D12(d3dSwapchain->device); + return makeResultD3D12(result); } } @@ -391,17 +379,22 @@ PalResult PAL_CALL presentSwapchainD3D12( PalSemaphore* waitSemaphore) { HRESULT result; - Swapchain* d3dSwapchain = (Swapchain*)swapchain; + SwapchainD3D12* d3dSwapchain = (SwapchainD3D12*)swapchain; ID3D12CommandQueue* queue = d3dSwapchain->queue; if (waitSemaphore) { - Semaphore* semaphore = (Semaphore*)waitSemaphore; - if (semaphore->isTimeline) { - queue->lpVtbl->Wait(queue, semaphore->handle, info->waitValue); - } else { - queue->lpVtbl->Wait(queue, semaphore->handle, semaphore->value); - semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); - semaphore->value = 0; + SemaphoreD3D12* semaphore = (SemaphoreD3D12*)waitSemaphore; + result = queue->lpVtbl->Wait(queue, semaphore->handle, semaphore->value); + if (FAILED(result)) { + pollMessagesD3D12(d3dSwapchain->device); + return makeResultD3D12(result); + } + + semaphore->value = 0; + result = semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); + if (FAILED(result)) { + pollMessagesD3D12(d3dSwapchain->device); + return makeResultD3D12(result); } } @@ -413,7 +406,7 @@ PalResult PAL_CALL presentSwapchainD3D12( if (FAILED(result)) { pollMessagesD3D12(d3dSwapchain->device); if (result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET) { - return PAL_RESULT_DEVICE_LOST; + return makeResultD3D12(result); } // check if swapchain needs to be resize @@ -423,13 +416,17 @@ PalResult PAL_CALL presentSwapchainD3D12( uint32_t h = windowRect.bottom - windowRect.top; if (!ret) { - return PAL_RESULT_SURFACE_LOST; + return palMakeResult( + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, + GetLastError()); } if (w != d3dSwapchain->windowWidth || h != d3dSwapchain->windowHeight) { - return PAL_RESULT_SWAPCHAIN_OUT_OF_DATE; + return PAL_RESULT_CODE_OUT_OF_DATE; } - return PAL_RESULT_PLATFORM_FAILURE; + + return makeResultD3D12(result); } return PAL_RESULT_SUCCESS; @@ -441,7 +438,7 @@ PalResult PAL_CALL resizeSwapchainD3D12( uint32_t newHeight) { HRESULT result; - Swapchain* d3dSwapchain = (Swapchain*)swapchain; + SwapchainD3D12* d3dSwapchain = (SwapchainD3D12*)swapchain; result = d3dSwapchain->handle->lpVtbl->ResizeBuffers( d3dSwapchain->handle, d3dSwapchain->imageCount, @@ -452,13 +449,10 @@ PalResult PAL_CALL resizeSwapchainD3D12( if (FAILED(result)) { pollMessagesD3D12(d3dSwapchain->device); - if (result == E_INVALIDARG) { - return PAL_RESULT_INVALID_ARGUMENT; - } - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } - // fill all images with the creatio info + // fill all images with the creation info for (int i = 0; i < d3dSwapchain->imageCount; i++) { ID3D12Resource* tmp = nullptr; d3dSwapchain->handle->lpVtbl->GetBuffer( @@ -467,7 +461,7 @@ PalResult PAL_CALL resizeSwapchainD3D12( &IID_Resource, (void**)&tmp); - Image* image = &d3dSwapchain->images[i]; + ImageD3D12* image = &d3dSwapchain->images[i]; image->handle = tmp; image->info.height = newHeight; image->info.width = newWidth; @@ -475,9 +469,12 @@ PalResult PAL_CALL resizeSwapchainD3D12( // get and cache window size for swapchain out of date error RECT windowRect; - Surface* surface = d3dSwapchain->surface; + SurfaceD3D12* surface = d3dSwapchain->surface; if (!GetClientRect((HWND)surface->handle, &windowRect)) { - return PAL_RESULT_SURFACE_LOST; + return palMakeResult( + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, + GetLastError()); } d3dSwapchain->windowWidth = windowRect.right - windowRect.left; diff --git a/src/graphics/vulkan/pal_swapchain_vulkan.c b/src/graphics/vulkan/pal_swapchain_vulkan.c index a54f30ee..a9ce9666 100644 --- a/src/graphics/vulkan/pal_swapchain_vulkan.c +++ b/src/graphics/vulkan/pal_swapchain_vulkan.c @@ -311,7 +311,7 @@ PalResult PAL_CALL createSwapchainVk( } vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, images); - // fill all images with the creatio info + // fill all images with the creation info for (int i = 0; i < count; i++) { ImageVk* image = &swapchain->images[i]; image->device = vkDevice; From 492cc328a2e67d4543682b38ca4f495b60b76bf5 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 7 Jul 2026 20:59:54 -0700 Subject: [PATCH 321/372] graphics rework: fix all errors d3d12 --- CHANGELOG.md | 2 +- include/pal/pal_core.h | 2 +- src/core/pal_result.h | 2 +- src/graphics/d3d12/pal_adapter_d3d12.c | 24 +- src/graphics/d3d12/pal_command_pool_d3d12.c | 47 + src/graphics/d3d12/pal_commands_d3d12.c | 138 ++- src/graphics/{ => d3d12}/pal_d3d12.c | 1062 +++++-------------- src/graphics/d3d12/pal_d3d12.h | 47 +- src/graphics/d3d12/pal_device_d3d12.c | 14 + src/graphics/d3d12/pal_image_d3d12.c | 114 ++ src/graphics/d3d12/pal_pipeline_d3d12.c | 281 ++++- src/graphics/d3d12/pal_sync_d3d12.c | 6 +- src/graphics/vulkan/pal_commands_vulkan.c | 1 + 13 files changed, 887 insertions(+), 853 deletions(-) rename src/graphics/{ => d3d12}/pal_d3d12.c (63%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85c2bcb5..75bd9865 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,7 +30,7 @@ - `PAL_RESULT_SOURCE_POSIX` - `PAL_RESULT_SOURCE_EGL` - `PAL_RESULT_SOURCE_VULKAN` - - `PAL_RESULT_SOURCE_DIRECTX12` + - `PAL_RESULT_SOURCE_D3D12` - `PAL_RESULT_SOURCE_METAL` - Added type `PalGLBackend` with values: - `PAL_GL_BACKEND_EGL` diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 70be6229..0fbc5421 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -78,7 +78,7 @@ #define PAL_RESULT_SOURCE_POSIX 2 #define PAL_RESULT_SOURCE_EGL 3 #define PAL_RESULT_SOURCE_VULKAN 4 -#define PAL_RESULT_SOURCE_DIRECTX12 5 +#define PAL_RESULT_SOURCE_D3D12 5 #define PAL_RESULT_SOURCE_METAL 6 #define PAL_RESULT_SOURCE_COUNT 7 diff --git a/src/core/pal_result.h b/src/core/pal_result.h index 39698011..440061d2 100644 --- a/src/core/pal_result.h +++ b/src/core/pal_result.h @@ -108,7 +108,7 @@ static const char* resultSourceToString(PalResult result) case PAL_RESULT_SOURCE_VULKAN: return "VULKAN"; - case PAL_RESULT_SOURCE_DIRECTX12: + case PAL_RESULT_SOURCE_D3D12: return "DIRECTX12"; case PAL_RESULT_SOURCE_METAL: diff --git a/src/graphics/d3d12/pal_adapter_d3d12.c b/src/graphics/d3d12/pal_adapter_d3d12.c index 392b3f6c..42e0c6ab 100644 --- a/src/graphics/d3d12/pal_adapter_d3d12.c +++ b/src/graphics/d3d12/pal_adapter_d3d12.c @@ -26,6 +26,26 @@ #define D3D_SHADER_MODEL_6_10 0x6a #endif // D3D_SHADER_MODEL_6_10 +static PalImageUsages ImageUsageFromD3D12(D3D12_FORMAT_SUPPORT1 flags) +{ + PalImageUsages usages = 0; + if (flags & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) { + usages |= PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; + } + + if (flags & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) { + usages |= PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT; + } + + if (flags & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE) { + usages |= PAL_IMAGE_USAGE_SAMPLED; + } + + usages |= PAL_IMAGE_USAGE_TRANSFER_DST; + usages |= PAL_IMAGE_USAGE_TRANSFER_SRC; + return usages; +} + PalResult PAL_CALL enumerateAdaptersD3D12( int32_t* count, PalAdapter** outAdapters) @@ -114,7 +134,7 @@ PalResult PAL_CALL getAdapterInfoD3D12( D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; - HRESULT result = IDXGIAdapter4_GetDesc3(d3d12Adapter->handle, &desc); + HRESULT result = d3d12Adapter->handle->lpVtbl->GetDesc3(d3d12Adapter->handle, &desc); if (FAILED(result)) { return makeResultD3D12(result); } @@ -609,7 +629,7 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( uint32_t tmp = 0; for (int i = 0; i < 6; i++) { samples.SampleCount = sampleCounts[i]; - result = ID3D12Device_CheckFeatureSupport( + result = device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &samples, diff --git a/src/graphics/d3d12/pal_command_pool_d3d12.c b/src/graphics/d3d12/pal_command_pool_d3d12.c index fa699883..55c845bc 100644 --- a/src/graphics/d3d12/pal_command_pool_d3d12.c +++ b/src/graphics/d3d12/pal_command_pool_d3d12.c @@ -8,6 +8,46 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" +static CommandBufferData* getFreeCmdBufferData(CommandPoolD3D12* pool) +{ + for (int i = 0; i < pool->size; ++i) { + if (!pool->cmdBuffersData[i].used) { + pool->cmdBuffersData[i].used = PAL_TRUE; + return &pool->cmdBuffersData[i]; + } + } + + // resize the data array + CommandBufferData* data = nullptr; + int count = pool->size * 2; // double the size + int freeIndex = pool->size + 1; + + data = palAllocate(s_D3D12.allocator, sizeof(CommandBufferData) * count, 0); + if (data) { + memcpy(data, pool->cmdBuffersData, pool->size * sizeof(CommandBufferData)); + + palFree(s_D3D12.allocator, pool->cmdBuffersData); + pool->cmdBuffersData = data; + pool->size = count; + + pool->cmdBuffersData[freeIndex].used = PAL_TRUE; + return &pool->cmdBuffersData[freeIndex]; + } + return nullptr; +} + +static CommandBufferData* findCmdBufferData( + CommandPoolD3D12* pool, + CommandBufferD3D12* cmdBuffer) +{ + for (int i = 0; i < pool->size; ++i) { + if (pool->cmdBuffersData[i].used && pool->cmdBuffersData[i].cmdBuffer == cmdBuffer) { + return &pool->cmdBuffersData[i]; + } + } + return nullptr; +} + PalResult PAL_CALL createCommandPoolD3D12( PalDevice* device, PalQueue* queue, @@ -109,6 +149,12 @@ PalResult PAL_CALL allocateCommandBufferD3D12( memset(cmdBuffer, 0, sizeof(CommandBufferD3D12)); cmdBuffer->primary = PAL_TRUE; + // add it to the command pool list + CommandBufferData* cmdData = getFreeCmdBufferData(cmdPool); + if (!cmdData) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + D3D12_COMMAND_LIST_TYPE cmdBufferType = cmdPool->type; if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { cmdBufferType = D3D12_COMMAND_LIST_TYPE_BUNDLE; @@ -201,6 +247,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( cmdList->lpVtbl->Release(cmdList); cmdBuffer->handle->lpVtbl->Close(cmdBuffer->handle); + cmdData->cmdBuffer = cmdBuffer; cmdBuffer->pool = cmdPool; cmdBuffer->device = d3d12Device; diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index cbf4234b..1edf3bf8 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -28,6 +28,128 @@ static D3D12_RENDER_PASS_FLAGS renderingFlagToD3D12(PalRenderingFlags flags) return renderingFlags; } +static D3D12_RESOURCE_STATES barrierToD3D12(PalUsageState state) +{ + switch (state) { + case PAL_USAGE_STATE_UNDEFINED: { + return D3D12_RESOURCE_STATE_COMMON; + } + + case PAL_USAGE_STATE_PRESENT: { + return D3D12_RESOURCE_STATE_PRESENT; + } + + case PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE: { + return D3D12_RESOURCE_STATE_RENDER_TARGET; + } + + case PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ: + case PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ: { + return D3D12_RESOURCE_STATE_DEPTH_READ; + } + + case PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE: + case PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE: { + return D3D12_RESOURCE_STATE_DEPTH_WRITE; + } + + case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ: { + return D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE; + } + + case PAL_USAGE_STATE_TRANSFER_READ: { + return D3D12_RESOURCE_STATE_COPY_SOURCE; + } + + case PAL_USAGE_STATE_TRANSFER_WRITE: + case PAL_USAGE_STATE_HOST_READ: { + return D3D12_RESOURCE_STATE_COPY_DEST; + } + + case PAL_USAGE_STATE_VERTEX_READ: { + return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; + } + + case PAL_USAGE_STATE_INDEX_READ: { + return D3D12_RESOURCE_STATE_INDEX_BUFFER; + } + + case PAL_USAGE_STATE_INDIRECT_READ: { + return D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT; + } + + case PAL_USAGE_STATE_UNIFORM_READ: { + return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; + } + + case PAL_USAGE_STATE_SHADER_READ: { + return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; + } + + case PAL_USAGE_STATE_STORAGE_READ: + case PAL_USAGE_STATE_SHADER_WRITE: + case PAL_USAGE_STATE_STORAGE_WRITE: { + return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + } + + case PAL_USAGE_STATE_HOST_WRITE: { + return D3D12_RESOURCE_STATE_GENERIC_READ; + } + + case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: + case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE: { + return D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; + } + } + + return D3D12_RESOURCE_STATE_COMMON; +} + +static D3D12_RESOLVE_MODE resolveModeToD3D12(PalResolveMode mode) +{ + switch (mode) { + case PAL_RESOLVE_MODE_AVERAGE: + return D3D12_RESOLVE_MODE_AVERAGE; + + case PAL_RESOLVE_MODE_MIN: + return D3D12_RESOLVE_MODE_MIN; + + case PAL_RESOLVE_MODE_MAX: + return D3D12_RESOLVE_MODE_MAX; + } + + return D3D12_RESOLVE_MODE_DECOMPRESS; +} + +static void commitShaderbindingTableUpdateD3D12( + CommandBufferD3D12* cmdBuffer, + ShaderBindingTableD3D12* sbt) +{ + if (!sbt->isDirty) { + return; + } + + // begin upload buffer copy to gpu buffer + cmdBuffer->handle->lpVtbl->CopyBufferRegion( + cmdBuffer->handle, + sbt->buffer, + 0, + sbt->stagingBuffer, + 0, + sbt->stagingBufferSize); + + // put a memory barrier + D3D12_RESOURCE_BARRIER barrier = {0}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.Transition.pResource = sbt->buffer; + + cmdBuffer->handle->lpVtbl->ResourceBarrier(cmdBuffer->handle, 1, &barrier); + sbt->isDirty = PAL_FALSE; +} + PalResult PAL_CALL cmdBeginD3D12( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) @@ -240,7 +362,7 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; D3D12_RENDER_PASS_RENDER_TARGET_DESC colorAttachments[MAX_ATTACHMENTS]; D3D12_RENDER_PASS_DEPTH_STENCIL_DESC depthStencilAttachment = {0}; - D3D12_CPU_DESCRIPTOR_HANDLE colorCpuHandle[MAX_ATTACHMENTS]; + D3D12_CPU_DESCRIPTOR_HANDLE colorCpuHandles[MAX_ATTACHMENTS]; D3D12_CPU_DESCRIPTOR_HANDLE depthStencilCpuHandle; PalAttachmentDesc* desc = nullptr; @@ -257,7 +379,7 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( RTVHeapAllocator* allocator = &imageView->device->rtvAllocator; uint32_t size = allocator->incrementSize; uint64_t base = allocator->baseOffset; - colorCpuHandle[i].ptr = getDescriptorHandleD3D12(imageView->heapIndex, size, base); + colorCpuHandles[i].ptr = getDescriptorHandleD3D12(imageView->heapIndex, size, base); attachment->BeginningAccess.Clear.ClearValue.Color[0] = desc->clearValue.color[0]; attachment->BeginningAccess.Clear.ClearValue.Color[1] = desc->clearValue.color[1]; @@ -283,22 +405,22 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( attachment->EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD; } - attachment->cpuDescriptor = colorCpuHandle[i]; + attachment->cpuDescriptor = colorCpuHandles[i]; if (resolveImageView) { attachment->EndingAccess.Resolve.pDstResource = resolveImageView->image->handle; attachment->EndingAccess.Resolve.Format = formatToD3D12(resolveImageView->format); - attachment->EndingAccess.Resolve.ResolveMode = resolveModeToVk(desc->resolveMode); + attachment->EndingAccess.Resolve.ResolveMode = resolveModeToD3D12(desc->resolveMode); attachment->EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE; } } // depth attachment if (info->depthStencilAttachment) { - desc = &info->depthStencilAttachment; + desc = info->depthStencilAttachment; imageView = (ImageViewD3D12*)desc->imageView; resolveImageView = (ImageViewD3D12*)desc->resolveImageView; - DSVHeapAllocator* allocator = &imageView->device->rtvAllocator; + DSVHeapAllocator* allocator = &imageView->device->dsvAllocator; uint32_t size = allocator->incrementSize; uint64_t base = allocator->baseOffset; depthStencilCpuHandle.ptr = getDescriptorHandleD3D12(imageView->heapIndex, size, base); @@ -360,7 +482,7 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( if (resolveImageView) { depthEnd->Resolve.pDstResource = resolveImageView->image->handle; depthEnd->Resolve.Format = formatToD3D12(resolveImageView->format); - depthEnd->Resolve.ResolveMode = resolveModeToVk(desc->resolveMode); + depthEnd->Resolve.ResolveMode = resolveModeToD3D12(desc->resolveMode); depthEnd->Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE; stencilEnd->Resolve.pDstResource = depthEnd->Resolve.pDstResource; @@ -380,7 +502,7 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( d3d12CmdBuffer->handle->lpVtbl->OMSetRenderTargets( d3d12CmdBuffer->handle, info->colorAttachentCount, - colorAttachments, + colorCpuHandles, PAL_FALSE, tmpCpuHandle); diff --git a/src/graphics/pal_d3d12.c b/src/graphics/d3d12/pal_d3d12.c similarity index 63% rename from src/graphics/pal_d3d12.c rename to src/graphics/d3d12/pal_d3d12.c index 98355f6a..cf550c15 100644 --- a/src/graphics/pal_d3d12.c +++ b/src/graphics/d3d12/pal_d3d12.c @@ -5,21 +5,8 @@ Licensed under the Zlib license. See LICENSE file in root. */ -// ================================================== -// Includes -// ================================================== - -#include "pal/pal_graphics.h" - #if PAL_HAS_D3D12_BACKEND - -#ifdef _WIN32 -#include -#include -#include -#include - -#define MAX_MESSAGE_SIZE 4096 +#include "pal_d3d12.h" // IIDS IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; @@ -44,13 +31,45 @@ IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0 IID IID_StateObjectProps = {0xde5fa827, 0x9bf9, 0x4f26, 0x89,0xff, 0xd7,0xf5,0x6f,0xde,0x38,0x60}; IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; -static D3D12 s_D3D12 = {0}; +D3D12 s_D3D12 = {0}; + +PalResult makeResultD3D12(HRESULT result) +{ + PalResultCode code = PAL_RESULT_CODE_PLATFORM_FAILURE; + switch (result) { + case E_NOTIMPL: + case DXGI_ERROR_UNSUPPORTED: { + code = PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + break; + } + + case E_OUTOFMEMORY: { + code = PAL_RESULT_CODE_OUT_OF_MEMORY; + break; + } + + case E_ACCESSDENIED: { + code = PAL_RESULT_CODE_INVALID_OPERATION; + break; + } + + case DXGI_ERROR_DEVICE_HUNG: + case DXGI_ERROR_DEVICE_REMOVED: + case DXGI_ERROR_DEVICE_RESET: { + code = PAL_RESULT_CODE_DEVICE_LOST; + break; + } + + case E_INVALIDARG: { + code = PAL_RESULT_CODE_INVALID_ARGUMENT; + break; + } + } -// ================================================== -// Helper Functions -// ================================================== + return palMakeResult(code, PAL_RESULT_SOURCE_D3D12, (uint32_t)result); +} -static DXGI_FORMAT formatToD3D12(PalFormat format) +DXGI_FORMAT formatToD3D12(PalFormat format) { switch (format) { case PAL_FORMAT_R8_UNORM: @@ -297,27 +316,7 @@ static DXGI_FORMAT formatToD3D12(PalFormat format) return DXGI_FORMAT_UNKNOWN; } -static PalImageUsages ImageUsageFromD3D12(D3D12_FORMAT_SUPPORT1 flags) -{ - PalImageUsages usages = 0; - if (flags & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) { - usages |= PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; - } - - if (flags & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL) { - usages |= PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT; - } - - if (flags & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE) { - usages |= PAL_IMAGE_USAGE_SAMPLED; - } - - usages |= PAL_IMAGE_USAGE_TRANSFER_DST; - usages |= PAL_IMAGE_USAGE_TRANSFER_SRC; - return usages; -} - -static uint32_t samplesToD3D12(PalSampleCount count) +uint32_t samplesToD3D12(PalSampleCount count) { switch (count) { case PAL_SAMPLE_COUNT_2: @@ -342,7 +341,7 @@ static uint32_t samplesToD3D12(PalSampleCount count) return 1; } -static D3D12_COMPARISON_FUNC compareOpToD3D12(PalCompareOp op) +D3D12_COMPARISON_FUNC compareOpToD3D12(PalCompareOp op) { switch (op) { case PAL_COMPARE_OP_NEVER: @@ -373,259 +372,7 @@ static D3D12_COMPARISON_FUNC compareOpToD3D12(PalCompareOp op) return D3D12_COMPARISON_FUNC_NEVER; } -static D3D12_STENCIL_OP stencilOpToD3D12(PalStencilOp op) -{ - switch (op) { - case PAL_STENCIL_OP_KEEP: - return D3D12_STENCIL_OP_KEEP; - - case PAL_STENCIL_OP_ZERO: - return D3D12_STENCIL_OP_ZERO; - - case PAL_STENCIL_OP_REPLACE: - return D3D12_STENCIL_OP_REPLACE; - - case PAL_STENCIL_OP_INCREMENT_AND_CLAMP: - return D3D12_STENCIL_OP_INCR_SAT; - - case PAL_STENCIL_OP_DECREMENT_AND_CLAMP: - return D3D12_STENCIL_OP_DECR_SAT; - - case PAL_STENCIL_OP_INVERT: - return D3D12_STENCIL_OP_INVERT; - - case PAL_STENCIL_OP_INCREMENT_AND_WRAP: - return D3D12_STENCIL_OP_INCR; - - case PAL_STENCIL_OP_DECREMENT_AND_WRAP: - return D3D12_STENCIL_OP_DECR; - } - - return D3D12_STENCIL_OP_KEEP; -} - -static D3D12_BLEND_OP blendOpToD3D12(PalBlendOp op) -{ - switch (op) { - case PAL_BLEND_OP_ADD: - return D3D12_BLEND_OP_ADD; - - case PAL_BLEND_OP_SUBTRACT: - return D3D12_BLEND_OP_SUBTRACT; - - case PAL_BLEND_OP_REVERSE_SUBTRACT: - return D3D12_BLEND_OP_REV_SUBTRACT; - - case PAL_BLEND_OP_MIN: - return D3D12_BLEND_OP_MIN; - - case PAL_BLEND_OP_MAX: - return D3D12_BLEND_OP_MAX; - } - - return D3D12_BLEND_OP_ADD; -} - -static D3D12_BLEND blendFactorToD3D12(PalBlendFactor op) -{ - switch (op) { - case PAL_BLEND_FACTOR_ZERO: - return D3D12_BLEND_ZERO; - - case PAL_BLEND_FACTOR_ONE: - return D3D12_BLEND_ONE; - - case PAL_BLEND_FACTOR_SRC_COLOR: - return D3D12_BLEND_SRC_COLOR; - - case PAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: - return D3D12_BLEND_INV_SRC_COLOR; - - case PAL_BLEND_FACTOR_DST_COLOR: - return D3D12_BLEND_DEST_COLOR; - - case PAL_BLEND_FACTOR_ONE_MINUX_DST_COLOR: - return D3D12_BLEND_INV_DEST_COLOR; - - case PAL_BLEND_FACTOR_SRC_ALPHA: - return D3D12_BLEND_SRC_ALPHA; - - case PAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: - return D3D12_BLEND_INV_SRC_ALPHA; - - case PAL_BLEND_FACTOR_DST_ALPHA: - return D3D12_BLEND_DEST_ALPHA; - - case PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: - return D3D12_BLEND_INV_DEST_ALPHA; - - case PAL_BLEND_FACTOR_CONSTANT_COLOR: - case PAL_BLEND_FACTOR_CONSTANT_ALPHA: - return D3D12_BLEND_BLEND_FACTOR; - - case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR: - case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: - return D3D12_BLEND_INV_BLEND_FACTOR; - } - - return D3D12_BLEND_ZERO; -} - -static D3D12_FILTER filterToD3D12( - PalFilterMode minFilter, - PalFilterMode magFilter, - PalSamplerMipmapMode mode) -{ - // all the enums start with min so we start with min filter - switch (minFilter) { - case PAL_FILTER_MODE_NEAREST: { - switch (magFilter) { - case PAL_FILTER_MODE_NEAREST: { - // min and mag are nearest. Check sampler mipmap mode - if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { - return D3D12_FILTER_MIN_MAG_MIP_POINT; // sampler mode nearest - } else { - return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR; // sampler mode linear - } - } - - case PAL_FILTER_MODE_LINEAR: { - // min is nearest, mag is linear . Check sampler mipmap mode - if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { - return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; // sampler mode nearest - } else { - return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR; // sampler mode linear - } - } - } - } - - case PAL_FILTER_MODE_LINEAR: { - switch (magFilter) { - case PAL_FILTER_MODE_NEAREST: { - // min is linear, mag is nearest. Check sampler mipmap mode - if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { - return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT; // sampler mode nearest - } else { - return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; // sampler mode linear - } - } - - case PAL_FILTER_MODE_LINEAR: { - // min and mag are linear. Check sampler mipmap mode - if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { - return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; // sampler mode nearest - } else { - return D3D12_FILTER_MIN_MAG_MIP_LINEAR; // sampler mode linear - } - } - } - } - } - - return D3D12_FILTER_MIN_MAG_MIP_POINT; -} - -static D3D12_TEXTURE_ADDRESS_MODE addressModeToD3D12(PalSamplerAddressMode mode) -{ - switch (mode) { - case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { - return D3D12_TEXTURE_ADDRESS_MODE_WRAP; - } - - case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { - return D3D12_TEXTURE_ADDRESS_MODE_MIRROR; - - } - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { - return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - - } - case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { - return D3D12_TEXTURE_ADDRESS_MODE_BORDER; - } - } - return D3D12_TEXTURE_ADDRESS_MODE_WRAP; -} - -static void borderColorToD3D12(PalBorderColor color, float outColor[4]) -{ - switch (color) { - case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: - case PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK: { - outColor[0] = 0.0f; - outColor[1] = 0.0f; - outColor[2] = 0.0f; - outColor[3] = 0.0f; - break; - } - - case PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK: - case PAL_BORDER_COLOR_INT_OPAQUE_BLACK: { - outColor[0] = 0.0f; - outColor[1] = 0.0f; - outColor[2] = 0.0f; - outColor[3] = 1.0f; - break; - } - - case PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE: - case PAL_BORDER_COLOR_INT_OPAQUE_WHITE: { - outColor[0] = 1.0f; - outColor[1] = 1.0f; - outColor[2] = 1.0f; - outColor[3] = 1.0f; - break; - } - } - - outColor[0] = 0.0f; - outColor[1] = 0.0f; - outColor[2] = 0.0f; - outColor[3] = 0.0f; -} - -static CommandBufferData* getFreeCmdBufferData(CommandPool* pool) -{ - for (int i = 0; i < pool->size; ++i) { - if (!pool->cmdBuffersData[i].used) { - pool->cmdBuffersData[i].used = PAL_TRUE; - return &pool->cmdBuffersData[i]; - } - } - - // resize the data array - CommandBufferData* data = nullptr; - int count = pool->size * 2; // double the size - int freeIndex = pool->size + 1; - - data = palAllocate(s_D3D12.allocator, sizeof(CommandBufferData) * count, 0); - if (data) { - memcpy(data, pool->cmdBuffersData, pool->size * sizeof(CommandBufferData)); - - palFree(s_D3D12.allocator, pool->cmdBuffersData); - pool->cmdBuffersData = data; - pool->size = count; - - pool->cmdBuffersData[freeIndex].used = PAL_TRUE; - return &pool->cmdBuffersData[freeIndex]; - } - return nullptr; -} - -static CommandBufferData* findCmdBufferData( - CommandPool* pool, - CommandBuffer* cmdBuffer) -{ - for (int i = 0; i < pool->size; ++i) { - if (pool->cmdBuffersData[i].used && pool->cmdBuffersData[i].cmdBuffer == cmdBuffer) { - return &pool->cmdBuffersData[i]; - } - } - return nullptr; -} - -static D3D12_SHADING_RATE_COMBINER combinerOpsToD3D12(PalFragmentShadingRateCombinerOp op) +D3D12_SHADING_RATE_COMBINER combinerOpsToD3D12(PalFragmentShadingRateCombinerOp op) { switch (op) { case PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP: @@ -647,7 +394,7 @@ static D3D12_SHADING_RATE_COMBINER combinerOpsToD3D12(PalFragmentShadingRateComb return D3D12_SHADING_RATE_COMBINER_PASSTHROUGH; } -static D3D12_SHADING_RATE shadingRateToD3D12(PalFragmentShadingRate rate) +D3D12_SHADING_RATE shadingRateToD3D12(PalFragmentShadingRate rate) { switch (rate) { case PAL_FRAGMENT_SHADING_RATE_1X1: @@ -675,7 +422,116 @@ static D3D12_SHADING_RATE shadingRateToD3D12(PalFragmentShadingRate rate) return D3D12_SHADING_RATE_1X1; } -static DXGI_FORMAT vertexTypeToD3D12(PalVertexType type) +uint32_t getFormatSizeD3D12(PalFormat format) +{ + switch (format) { + case PAL_FORMAT_R8_UNORM: + case PAL_FORMAT_R8_SNORM: + case PAL_FORMAT_R8_UINT: + case PAL_FORMAT_R8_SINT: + case PAL_FORMAT_R8_SRGB: + case PAL_FORMAT_S8_UINT: + return 1; + + case PAL_FORMAT_R16_UNORM: + case PAL_FORMAT_R16_SNORM: + case PAL_FORMAT_R16_UINT: + case PAL_FORMAT_R16_SINT: + case PAL_FORMAT_R16_SFLOAT: + case PAL_FORMAT_R8G8_UNORM: + case PAL_FORMAT_R8G8_SNORM: + case PAL_FORMAT_R8G8_UINT: + case PAL_FORMAT_R8G8_SINT: + case PAL_FORMAT_R8G8_SRGB: + case PAL_FORMAT_D16_UNORM: + return 2; + + case PAL_FORMAT_R8G8B8_UNORM: + case PAL_FORMAT_R8G8B8_SNORM: + case PAL_FORMAT_R8G8B8_UINT: + case PAL_FORMAT_R8G8B8_SINT: + case PAL_FORMAT_R8G8B8_SRGB: + case PAL_FORMAT_B8G8R8_UNORM: + case PAL_FORMAT_B8G8R8_SNORM: + case PAL_FORMAT_B8G8R8_UINT: + case PAL_FORMAT_B8G8R8_SINT: + case PAL_FORMAT_B8G8R8_SRGB: + case PAL_FORMAT_D16_UNORM_S8_UINT: + return 3; + + case PAL_FORMAT_R32_UINT: + case PAL_FORMAT_R32_SINT: + case PAL_FORMAT_R32_SFLOAT: + case PAL_FORMAT_R16G16_UNORM: + case PAL_FORMAT_R16G16_SNORM: + case PAL_FORMAT_R16G16_UINT: + case PAL_FORMAT_R16G16_SINT: + case PAL_FORMAT_R16G16_SFLOAT: + case PAL_FORMAT_R8G8B8A8_UNORM: + case PAL_FORMAT_R8G8B8A8_SNORM: + case PAL_FORMAT_R8G8B8A8_UINT: + case PAL_FORMAT_R8G8B8A8_SINT: + case PAL_FORMAT_R8G8B8A8_SRGB: + case PAL_FORMAT_B8G8R8A8_UNORM: + case PAL_FORMAT_B8G8R8A8_SNORM: + case PAL_FORMAT_B8G8R8A8_UINT: + case PAL_FORMAT_B8G8R8A8_SINT: + case PAL_FORMAT_B8G8R8A8_SRGB: + case PAL_FORMAT_D32_SFLOAT: + case PAL_FORMAT_D24_UNORM_S8_UINT: + return 4; + + case PAL_FORMAT_D32_SFLOAT_S8_UINT: + return 5; + + case PAL_FORMAT_R16G16B16_UNORM: + case PAL_FORMAT_R16G16B16_SNORM: + case PAL_FORMAT_R16G16B16_UINT: + case PAL_FORMAT_R16G16B16_SINT: + case PAL_FORMAT_R16G16B16_SFLOAT: + return 6; + + case PAL_FORMAT_R64_UINT: + case PAL_FORMAT_R64_SINT: + case PAL_FORMAT_R64_SFLOAT: + case PAL_FORMAT_R32G32_UINT: + case PAL_FORMAT_R32G32_SINT: + case PAL_FORMAT_R32G32_SFLOAT: + case PAL_FORMAT_R16G16B16A16_UNORM: + case PAL_FORMAT_R16G16B16A16_SNORM: + case PAL_FORMAT_R16G16B16A16_UINT: + case PAL_FORMAT_R16G16B16A16_SINT: + case PAL_FORMAT_R16G16B16A16_SFLOAT: + return 8; + + case PAL_FORMAT_R32G32B32_UINT: + case PAL_FORMAT_R32G32B32_SINT: + case PAL_FORMAT_R32G32B32_SFLOAT: + return 12; + + case PAL_FORMAT_R64G64_UINT: + case PAL_FORMAT_R64G64_SINT: + case PAL_FORMAT_R64G64_SFLOAT: + case PAL_FORMAT_R32G32B32A32_UINT: + case PAL_FORMAT_R32G32B32A32_SINT: + case PAL_FORMAT_R32G32B32A32_SFLOAT: + return 16; + + case PAL_FORMAT_R64G64B64_UINT: + case PAL_FORMAT_R64G64B64_SINT: + case PAL_FORMAT_R64G64B64_SFLOAT: + return 24; + + case PAL_FORMAT_R64G64B64A64_UINT: + case PAL_FORMAT_R64G64B64A64_SINT: + case PAL_FORMAT_R64G64B64A64_SFLOAT: + return 32; + } + + return 0; +} + +DXGI_FORMAT vertexTypeToD3D12(PalVertexType type) { switch (type) { case PAL_VERTEX_TYPE_INT32: @@ -772,81 +628,104 @@ static DXGI_FORMAT vertexTypeToD3D12(PalVertexType type) return DXGI_FORMAT_UNKNOWN; } -static PalBool fillBuildInfoD3D12( - PalAccelerationStructureBuildInfo* info, - D3D12_RAYTRACING_GEOMETRY_DESC* geometries, - D3D12_GPU_VIRTUAL_ADDRESS srcAs, - D3D12_GPU_VIRTUAL_ADDRESS dstAs, - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC* buildInfo) +D3D12_RAYTRACING_INSTANCE_FLAGS instanceFlagsToD3D12(PalAccelerationStructureInstanceFlags flags) { - static uint32_t maxInstanceCount = 1000000; - static uint32_t maxPrimitiveCount = 10000000; - static uint32_t maxGeometryCount = 100000; + D3D12_RAYTRACING_INSTANCE_FLAGS instanceFlags = 0; + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE) { + instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_OPAQUE; + } - if (info->geometryCount > maxGeometryCount) { - return PAL_FALSE; + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE) { + instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_NON_OPAQUE; } - if (info->instanceCount > maxInstanceCount) { - return PAL_FALSE; + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE) { + instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_CULL_DISABLE; } - for (int i = 0; i < info->geometryCount; i++) { - if (info->geometries[i].primitiveCount > maxPrimitiveCount) { - return PAL_FALSE; - } + if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE) { + instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE; + } - D3D12_RAYTRACING_GEOMETRY_DESC* tmp = &geometries[i]; - tmp->Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; - if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT) { - tmp->Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION; + return instanceFlags; +} + +void fillBuildInfoD3D12( + PalBool getBuildSize, + PalAccelerationStructureBuildInfo* info, + D3D12_RAYTRACING_GEOMETRY_DESC* geometries, + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC* buildInfo) +{ + static uint32_t maxInstanceCount = 1000000; + static uint32_t maxPrimitiveCount = 10000000; + static uint32_t maxGeometryCount = 100000; + + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { + if (info->count > maxGeometryCount) { + return; } - if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { - tmp->Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; - PalGeometryDataTriangle* tmpData = info->geometries[i].data; + for (int i = 0; i < info->count; i++) { + if (info->geometries[i].primitiveCount > maxPrimitiveCount) { + return; + } - tmp->Triangles.VertexBuffer.StartAddress = tmpData->vertexBufferAddress; - tmp->Triangles.VertexBuffer.StrideInBytes = tmpData->vertexStride; - tmp->Triangles.VertexCount = tmpData->vertexCount; - tmp->Triangles.VertexFormat = vertexTypeToD3D12(tmpData->vertexType); + D3D12_RAYTRACING_GEOMETRY_DESC* tmp = &geometries[i]; + tmp->Flags = 0; + if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT) { + tmp->Flags |= D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION; + } - tmp->Triangles.IndexBuffer = tmpData->indexBufferAddress; - tmp->Triangles.IndexCount = tmpData->indexCount; - if (tmpData->indexType == PAL_INDEX_TYPE_UINT16) { - if (tmp->Triangles.IndexBuffer) { - tmp->Triangles.IndexFormat = DXGI_FORMAT_R16_FLOAT; - } - - } else { - if (tmp->Triangles.IndexBuffer) { - tmp->Triangles.IndexFormat = DXGI_FORMAT_R32_FLOAT; - } + if (info->geometries[i].flags & PAL_GEOMETRY_FLAG_OPAQUE) { + tmp->Flags |= D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; } - } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { - tmp->Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; - PalGeometryDataAABBS* tmpData = info->geometries[i].data; + if (info->geometries[i].type == PAL_GEOMETRY_TYPE_TRIANGLE) { + tmp->Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + const PalGeometryDataTriangle* tmpData = info->geometries[i].data; + + tmp->Triangles.VertexBuffer.StartAddress = tmpData->vertexBufferAddress; + tmp->Triangles.VertexBuffer.StrideInBytes = tmpData->vertexStride; + tmp->Triangles.VertexCount = tmpData->vertexCount; + tmp->Triangles.VertexFormat = vertexTypeToD3D12(tmpData->vertexType); - tmp->AABBs.AABBCount = info->geometries[i].primitiveCount; - tmp->AABBs.AABBs.StartAddress = tmpData->bufferAddress; - tmp->AABBs.AABBs.StrideInBytes = tmpData->stride; + tmp->Triangles.Transform3x4 = tmpData->transformBufferAddress; + + tmp->Triangles.IndexBuffer = tmpData->indexBufferAddress; + tmp->Triangles.IndexCount = info->geometries[i].primitiveCount * 3; + if (tmpData->indexType == PAL_INDEX_TYPE_UINT16) { + if (tmp->Triangles.IndexBuffer) { + tmp->Triangles.IndexFormat = DXGI_FORMAT_R16_FLOAT; + } + + } else { + if (tmp->Triangles.IndexBuffer) { + tmp->Triangles.IndexFormat = DXGI_FORMAT_R32_FLOAT; + } + } + + } else if (info->geometries[i].type == PAL_GEOMETRY_TYPE_AABBS) { + tmp->Type = D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; + const PalGeometryDataAABBS* tmpData = info->geometries[i].data; + + tmp->AABBs.AABBCount = info->geometries[i].primitiveCount; + tmp->AABBs.AABBs.StartAddress = tmpData->bufferAddress; + tmp->AABBs.AABBs.StrideInBytes = tmpData->stride; + } } - } - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL) { - buildInfo->Inputs.NumDescs = info->instanceCount; - buildInfo->Inputs.InstanceDescs = info->instanceBufferAddress; - } else { - buildInfo->Inputs.NumDescs = info->geometryCount; + buildInfo->Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; + buildInfo->Inputs.NumDescs = info->count; buildInfo->Inputs.pGeometryDescs = geometries; - } - buildInfo->Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; - if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { - buildInfo->Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL; } else { + if (info->count > maxInstanceCount) { + return; + } + buildInfo->Inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL; + buildInfo->Inputs.NumDescs = info->count; + buildInfo->Inputs.InstanceDescs = info->instanceBufferAddress; } // build mode @@ -868,218 +747,26 @@ static PalBool fillBuildInfoD3D12( buildInfo->Inputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_MINIMIZE_MEMORY; } - buildInfo->SourceAccelerationStructureData = srcAs; - buildInfo->DestAccelerationStructureData = dstAs; - buildInfo->ScratchAccelerationStructureData = info->scratchBufferAddress; - - return PAL_TRUE; -} - -static uint32_t getFormatSizeD3D12(PalFormat format) -{ - switch (format) { - case PAL_FORMAT_R8_UNORM: - case PAL_FORMAT_R8_SNORM: - case PAL_FORMAT_R8_UINT: - case PAL_FORMAT_R8_SINT: - case PAL_FORMAT_R8_SRGB: - case PAL_FORMAT_S8_UINT: - return 1; - - case PAL_FORMAT_R16_UNORM: - case PAL_FORMAT_R16_SNORM: - case PAL_FORMAT_R16_UINT: - case PAL_FORMAT_R16_SINT: - case PAL_FORMAT_R16_SFLOAT: - case PAL_FORMAT_R8G8_UNORM: - case PAL_FORMAT_R8G8_SNORM: - case PAL_FORMAT_R8G8_UINT: - case PAL_FORMAT_R8G8_SINT: - case PAL_FORMAT_R8G8_SRGB: - case PAL_FORMAT_D16_UNORM: - return 2; - - case PAL_FORMAT_R8G8B8_UNORM: - case PAL_FORMAT_R8G8B8_SNORM: - case PAL_FORMAT_R8G8B8_UINT: - case PAL_FORMAT_R8G8B8_SINT: - case PAL_FORMAT_R8G8B8_SRGB: - case PAL_FORMAT_B8G8R8_UNORM: - case PAL_FORMAT_B8G8R8_SNORM: - case PAL_FORMAT_B8G8R8_UINT: - case PAL_FORMAT_B8G8R8_SINT: - case PAL_FORMAT_B8G8R8_SRGB: - case PAL_FORMAT_D16_UNORM_S8_UINT: - return 3; - - case PAL_FORMAT_R32_UINT: - case PAL_FORMAT_R32_SINT: - case PAL_FORMAT_R32_SFLOAT: - case PAL_FORMAT_R16G16_UNORM: - case PAL_FORMAT_R16G16_SNORM: - case PAL_FORMAT_R16G16_UINT: - case PAL_FORMAT_R16G16_SINT: - case PAL_FORMAT_R16G16_SFLOAT: - case PAL_FORMAT_R8G8B8A8_UNORM: - case PAL_FORMAT_R8G8B8A8_SNORM: - case PAL_FORMAT_R8G8B8A8_UINT: - case PAL_FORMAT_R8G8B8A8_SINT: - case PAL_FORMAT_R8G8B8A8_SRGB: - case PAL_FORMAT_B8G8R8A8_UNORM: - case PAL_FORMAT_B8G8R8A8_SNORM: - case PAL_FORMAT_B8G8R8A8_UINT: - case PAL_FORMAT_B8G8R8A8_SINT: - case PAL_FORMAT_B8G8R8A8_SRGB: - case PAL_FORMAT_D32_SFLOAT: - case PAL_FORMAT_D24_UNORM_S8_UINT: - return 4; - - case PAL_FORMAT_D32_SFLOAT_S8_UINT: - return 5; - - case PAL_FORMAT_R16G16B16_UNORM: - case PAL_FORMAT_R16G16B16_SNORM: - case PAL_FORMAT_R16G16B16_UINT: - case PAL_FORMAT_R16G16B16_SINT: - case PAL_FORMAT_R16G16B16_SFLOAT: - return 6; - - case PAL_FORMAT_R64_UINT: - case PAL_FORMAT_R64_SINT: - case PAL_FORMAT_R64_SFLOAT: - case PAL_FORMAT_R32G32_UINT: - case PAL_FORMAT_R32G32_SINT: - case PAL_FORMAT_R32G32_SFLOAT: - case PAL_FORMAT_R16G16B16A16_UNORM: - case PAL_FORMAT_R16G16B16A16_SNORM: - case PAL_FORMAT_R16G16B16A16_UINT: - case PAL_FORMAT_R16G16B16A16_SINT: - case PAL_FORMAT_R16G16B16A16_SFLOAT: - return 8; - - case PAL_FORMAT_R32G32B32_UINT: - case PAL_FORMAT_R32G32B32_SINT: - case PAL_FORMAT_R32G32B32_SFLOAT: - return 12; - - case PAL_FORMAT_R64G64_UINT: - case PAL_FORMAT_R64G64_SINT: - case PAL_FORMAT_R64G64_SFLOAT: - case PAL_FORMAT_R32G32B32A32_UINT: - case PAL_FORMAT_R32G32B32A32_SINT: - case PAL_FORMAT_R32G32B32A32_SFLOAT: - return 16; + AccelerationStructureD3D12* dstAs = (AccelerationStructureD3D12*)info->dst; + AccelerationStructureD3D12* srcAs = (AccelerationStructureD3D12*)info->src; - case PAL_FORMAT_R64G64B64_UINT: - case PAL_FORMAT_R64G64B64_SINT: - case PAL_FORMAT_R64G64B64_SFLOAT: - return 24; - - case PAL_FORMAT_R64G64B64A64_UINT: - case PAL_FORMAT_R64G64B64A64_SINT: - case PAL_FORMAT_R64G64B64A64_SFLOAT: - return 32; + D3D12_GPU_VIRTUAL_ADDRESS dstAsHandle = 0; + if (dstAs) { + dstAsHandle = dstAs->address; } - return 0; -} - -static inline uint32_t alignD3D12( - uint32_t value, - uint32_t alignment) -{ - return (value + alignment - 1) & ~(alignment - 1); -} - -static D3D12_RESOURCE_STATES barrierToD3D12( - uint32_t stageCount, - PalUsageState state, - PalShaderStage* shaderStages) -{ - switch (state) { - case PAL_USAGE_STATE_UNDEFINED: { - return D3D12_RESOURCE_STATE_COMMON; - } - - case PAL_USAGE_STATE_PRESENT: { - return D3D12_RESOURCE_STATE_PRESENT; - } - - case PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE: { - return D3D12_RESOURCE_STATE_RENDER_TARGET; - } - - case PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ: - case PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ: { - return D3D12_RESOURCE_STATE_DEPTH_READ; - } - - case PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE: - case PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE: { - return D3D12_RESOURCE_STATE_DEPTH_WRITE; - } - - case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ: { - return D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE; - } - - case PAL_USAGE_STATE_TRANSFER_READ: { - return D3D12_RESOURCE_STATE_COPY_SOURCE; - } - - case PAL_USAGE_STATE_TRANSFER_WRITE: - case PAL_USAGE_STATE_HOST_READ: { - return D3D12_RESOURCE_STATE_COPY_DEST; - } - - case PAL_USAGE_STATE_VERTEX_READ: { - return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; - } - - case PAL_USAGE_STATE_INDEX_READ: { - return D3D12_RESOURCE_STATE_INDEX_BUFFER; - } - - case PAL_USAGE_STATE_INDIRECT_READ: { - return D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT; - } - - case PAL_USAGE_STATE_UNIFORM_READ: { - return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; - } - - case PAL_USAGE_STATE_SHADER_READ: { - if (stageCount == 1) { - if (shaderStages[0] == PAL_SHADER_STAGE_FRAGMENT) { - return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; - } else { - return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - } - } else { - return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; - } - } - - case PAL_USAGE_STATE_STORAGE_READ: - case PAL_USAGE_STATE_SHADER_WRITE: - case PAL_USAGE_STATE_STORAGE_WRITE: { - return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - } - - case PAL_USAGE_STATE_HOST_WRITE: { - return D3D12_RESOURCE_STATE_GENERIC_READ; - } - - case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: - case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE: { - return D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; - } + D3D12_GPU_VIRTUAL_ADDRESS srcAsHandle = 0; + if (srcAs) { + srcAsHandle = srcAs->address; } - return D3D12_RESOURCE_STATE_COMMON; + buildInfo->Inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY; + buildInfo->DestAccelerationStructureData = dstAsHandle; + buildInfo->SourceAccelerationStructureData = srcAsHandle; + buildInfo->ScratchAccelerationStructureData = info->scratchBufferAddress; } -static void fillSubresourceD3D12( +void fillSubresourceD3D12( PalImageViewType type, const PalImageSubresourceRange* range, D3D12_RENDER_TARGET_VIEW_DESC* rtvDesc, @@ -1220,7 +907,7 @@ static void fillSubresourceD3D12( } } -static inline uint64_t getDescriptorHandleD3D12( +uint64_t getDescriptorHandleD3D12( uint32_t index, uint32_t size, uint64_t baseOffset) @@ -1228,199 +915,7 @@ static inline uint64_t getDescriptorHandleD3D12( return baseOffset + index * size; } -static D3D12_RAYTRACING_INSTANCE_FLAGS instanceFlagsToD3D12( - PalAccelerationStructureInstanceFlags flags) -{ - D3D12_RAYTRACING_INSTANCE_FLAGS instanceFlags = 0; - if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_OPAQUE) { - instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_OPAQUE; - } - - if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_FORCE_NO_OPAQUE) { - instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_FORCE_NON_OPAQUE; - } - - if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE) { - instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_CULL_DISABLE; - } - - if (flags & PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE) { - instanceFlags |= D3D12_RAYTRACING_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE; - } - - return instanceFlags; -} - -static D3D_PRIMITIVE_TOPOLOGY getPatchTopology(uint32_t patch) -{ - switch (patch) { - case 1: - return D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST; - - case 2: - return D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST; - - case 3: - return D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST; - - case 4: - return D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST; - - case 5: - return D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST; - - case 6: - return D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST; - - case 7: - return D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST; - - case 8: - return D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST; - - case 9: - return D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST; - - case 10: - return D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST; - - case 11: - return D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST; - - case 12: - return D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST; - - case 13: - return D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST; - - case 14: - return D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST; - - case 15: - return D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST; - - case 16: - return D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST; - - case 17: - return D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST; - - case 18: - return D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST; - - case 19: - return D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST; - - case 20: - return D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST; - - case 21: - return D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST; - - case 22: - return D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST; - - case 23: - return D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST; - - case 24: - return D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST; - - case 25: - return D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST; - - case 26: - return D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST; - - case 27: - return D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST; - - case 28: - return D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST; - - case 29: - return D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST; - - case 30: - return D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST; - } - - return D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST; -} - -static uint32_t getVertexTypeSizeD3D12(PalVertexType type) -{ - // count x sizeof type returned as size - switch (type) { - case PAL_VERTEX_TYPE_INT8_2: - case PAL_VERTEX_TYPE_UINT8_2: - case PAL_VERTEX_TYPE_INT8_2NORM: - case PAL_VERTEX_TYPE_UINT8_2NORM: { - return 2; - } - - case PAL_VERTEX_TYPE_INT32: - case PAL_VERTEX_TYPE_UINT32: - case PAL_VERTEX_TYPE_INT8_4: - case PAL_VERTEX_TYPE_INT8_4NORM: - case PAL_VERTEX_TYPE_UINT8_4: - case PAL_VERTEX_TYPE_UINT8_4NORM: - case PAL_VERTEX_TYPE_INT16_2NORM: - case PAL_VERTEX_TYPE_INT16_2: - case PAL_VERTEX_TYPE_UINT16_2: - case PAL_VERTEX_TYPE_UINT16_2NORM: - case PAL_VERTEX_TYPE_FLOAT: - case PAL_VERTEX_TYPE_HALF_FLOAT16_2: { - return 4; - } - - case PAL_VERTEX_TYPE_INT32_2: - case PAL_VERTEX_TYPE_UINT32_2: - case PAL_VERTEX_TYPE_INT16_4: - case PAL_VERTEX_TYPE_UINT16_4: - case PAL_VERTEX_TYPE_UINT16_4NORM: - case PAL_VERTEX_TYPE_INT16_4NORM: - case PAL_VERTEX_TYPE_FLOAT2: - case PAL_VERTEX_TYPE_HALF_FLOAT16_4: { - return 8; - } - - case PAL_VERTEX_TYPE_INT32_3: - case PAL_VERTEX_TYPE_UINT32_3: - case PAL_VERTEX_TYPE_FLOAT3: { - return 12; - } - - case PAL_VERTEX_TYPE_INT32_4: - case PAL_VERTEX_TYPE_UINT32_4: - case PAL_VERTEX_TYPE_FLOAT4: { - return 16; - } - } - - return 0; -} - -static void convertToWcharD3D12( - const char* src, - wchar_t dst[PAL_SHADER_ENTRY_NAME_SIZE]) -{ - int i = 0; - for (; i < PAL_SHADER_ENTRY_NAME_SIZE - 1 && src[i]; i++) { - dst[i] = (wchar_t)src[i]; - } - dst[i] = L'\0'; -} - -static void getHitGroupNameD3D12( - uint32_t index, - wchar_t dst[PAL_SHADER_ENTRY_NAME_SIZE]) -{ - wcscpy(dst, L"HitGroup"); - _itow(index, dst + 8, 10); -} - -static void pollMessagesD3D12(Device* device) +void pollMessagesD3D12(DeviceD3D12* device) { ID3D12InfoQueue* queue = device->infoQueue; if (!queue) { @@ -1491,57 +986,7 @@ static void pollMessagesD3D12(Device* device) queue->lpVtbl->ClearStoredMessages(queue); } -static const char* semanticIDToStringD3D12(PalVertexSemanticID id) -{ - switch (id) { - case PAL_VERTEX_SEMANTIC_ID_POSITION: - return "POSITION"; - - case PAL_VERTEX_SEMANTIC_ID_COLOR: - return "COLOR"; - - case PAL_VERTEX_SEMANTIC_ID_TEXCOORD: - return "TEXCOORD"; - - case PAL_VERTEX_SEMANTIC_ID_NORMAL: - return "NORMAL"; - - case PAL_VERTEX_SEMANTIC_ID_TANGENT: - return "TANGENT"; - } - return nullptr; -} - -static void commitShaderbindingTableUpdateD3D12( - CommandBuffer* cmdBuffer, - ShaderBindingTable* sbt) -{ - if (!sbt->isDirty) { - return; - } - - // begin upload buffer copy to gpu buffer - cmdBuffer->handle->lpVtbl->CopyBufferRegion( - cmdBuffer->handle, - sbt->buffer, - 0, - sbt->stagingBuffer, - 0, - sbt->stagingBufferSize); - - // put a memory barrier - D3D12_RESOURCE_BARRIER barrier = {0}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - barrier.Transition.pResource = sbt->buffer; - - cmdBuffer->handle->lpVtbl->ResourceBarrier(cmdBuffer->handle, 1, &barrier); - sbt->isDirty = PAL_FALSE; -} - -static void getDescriptorTierLimitsD3D12( +void getDescriptorTierLimitsD3D12( void* device, PalResourceCapabilities* caps, PalDescriptorIndexingCapabilities* descCaps) @@ -1614,10 +1059,6 @@ static void getDescriptorTierLimitsD3D12( } } -// ================================================== -// Adapter -// ================================================== - PalResult PAL_CALL initGraphicsD3D12( const PalGraphicsDebugger* debugger, const PalAllocator* allocator) @@ -1626,7 +1067,10 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D12.handle = LoadLibraryA("d3d12.dll"); s_D3D12.dxgi = LoadLibraryA("dxgi.dll"); if (!s_D3D12.handle || !s_D3D12.dxgi) { - return PAL_RESULT_PLATFORM_FAILURE; + return palMakeResult( + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, + GetLastError()); } // clang-format off @@ -1709,7 +1153,7 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D12.adapterCount = 0; HRESULT result = s_D3D12.createDXGIFactory(0, &IID_Factory, (void**)&s_D3D12.factory); if (FAILED(result)) { - return PAL_RESULT_PLATFORM_FAILURE; + return makeResultD3D12(result); } s_D3D12.allocator = allocator; @@ -1732,6 +1176,4 @@ void PAL_CALL shutdownGraphicsD3D12() memset(&s_D3D12, 0, sizeof(s_D3D12)); } -#endif // PAL_HAS_D3D12_BACKEND - -#endif // _WIN32 +#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_d3d12.h b/src/graphics/d3d12/pal_d3d12.h index cc2a33b6..9b407c88 100644 --- a/src/graphics/d3d12/pal_d3d12.h +++ b/src/graphics/d3d12/pal_d3d12.h @@ -126,30 +126,6 @@ typedef struct { uint32_t usedAs; } DescriptorHeapLimits; -typedef struct { - uint32_t incrementSize; - uint32_t nextOffset; - uint64_t cpuBase; - uint64_t gpuBase; - ID3D12DescriptorHeap* handle; -} DescriptorHeap; - -typedef struct { - uint32_t maxUniformBuffers; - uint32_t maxSampledImages; - uint32_t maxStorageBuffers; - uint32_t maxSamplers; - uint32_t maxStorageImages; - uint32_t maxAs; - - uint32_t usedUniformBuffers; - uint32_t usedSampledImages; - uint32_t usedStorageBuffers; - uint32_t usedSamplers; - uint32_t usedStorageImages; - uint32_t usedAs; -} DescriptorHeapLimits; - typedef struct { PalDescriptorType type; D3D12_DESCRIPTOR_RANGE1 range; @@ -396,7 +372,15 @@ typedef struct { PalResult makeResultD3D12(HRESULT result); void pollMessagesD3D12(DeviceD3D12* device); DXGI_FORMAT formatToD3D12(PalFormat format); -PalImageUsages ImageUsageFromD3D12(D3D12_FORMAT_SUPPORT1 flags); +D3D12_COMPARISON_FUNC compareOpToD3D12(PalCompareOp op); + +D3D12_SHADING_RATE_COMBINER combinerOpsToD3D12(PalFragmentShadingRateCombinerOp op); +D3D12_SHADING_RATE shadingRateToD3D12(PalFragmentShadingRate rate); +uint32_t getFormatSizeD3D12(PalFormat format); +DXGI_FORMAT vertexTypeToD3D12(PalVertexType type); + +D3D12_RAYTRACING_INSTANCE_FLAGS instanceFlagsToD3D12(PalAccelerationStructureInstanceFlags flags); +uint32_t samplesToD3D12(PalSampleCount count); void fillBuildInfoD3D12( PalBool getBuildSize, @@ -409,7 +393,18 @@ void getDescriptorTierLimitsD3D12( PalResourceCapabilities* caps, PalDescriptorIndexingCapabilities* descCaps); -uint32_t getFormatSizeD3D12(PalFormat format); +void fillSubresourceD3D12( + PalImageViewType type, + const PalImageSubresourceRange* range, + D3D12_RENDER_TARGET_VIEW_DESC* rtvDesc, + D3D12_DEPTH_STENCIL_VIEW_DESC* dsvDesc, + D3D12_SHADER_RESOURCE_VIEW_DESC* srvDesc, + D3D12_UNORDERED_ACCESS_VIEW_DESC* uavDesc); + +uint64_t getDescriptorHandleD3D12( + uint32_t index, + uint32_t size, + uint64_t baseOffset); // IIDs extern IID IID_Device; diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c index 1eca78a8..a86d3ded 100644 --- a/src/graphics/d3d12/pal_device_d3d12.c +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -8,6 +8,20 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" +PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter*); +uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12(PalAdapter*, PalShaderFormats); + +static void convertToWcharD3D12( + const char* src, + wchar_t dst[PAL_SHADER_ENTRY_NAME_SIZE]) +{ + int i = 0; + for (; i < PAL_SHADER_ENTRY_NAME_SIZE - 1 && src[i]; i++) { + dst[i] = (wchar_t)src[i]; + } + dst[i] = L'\0'; +} + PalResult PAL_CALL createDeviceD3D12( PalAdapter* adapter, PalAdapterFeatures features, diff --git a/src/graphics/d3d12/pal_image_d3d12.c b/src/graphics/d3d12/pal_image_d3d12.c index b9255c70..4b608af4 100644 --- a/src/graphics/d3d12/pal_image_d3d12.c +++ b/src/graphics/d3d12/pal_image_d3d12.c @@ -8,6 +8,120 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" +static D3D12_FILTER filterToD3D12( + PalFilterMode minFilter, + PalFilterMode magFilter, + PalSamplerMipmapMode mode) +{ + // all the enums start with min so we start with min filter + switch (minFilter) { + case PAL_FILTER_MODE_NEAREST: { + switch (magFilter) { + case PAL_FILTER_MODE_NEAREST: { + // min and mag are nearest. Check sampler mipmap mode + if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { + return D3D12_FILTER_MIN_MAG_MIP_POINT; // sampler mode nearest + } else { + return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR; // sampler mode linear + } + } + + case PAL_FILTER_MODE_LINEAR: { + // min is nearest, mag is linear . Check sampler mipmap mode + if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { + return D3D12_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; // sampler mode nearest + } else { + return D3D12_FILTER_MIN_POINT_MAG_MIP_LINEAR; // sampler mode linear + } + } + } + } + + case PAL_FILTER_MODE_LINEAR: { + switch (magFilter) { + case PAL_FILTER_MODE_NEAREST: { + // min is linear, mag is nearest. Check sampler mipmap mode + if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { + return D3D12_FILTER_MIN_LINEAR_MAG_MIP_POINT; // sampler mode nearest + } else { + return D3D12_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; // sampler mode linear + } + } + + case PAL_FILTER_MODE_LINEAR: { + // min and mag are linear. Check sampler mipmap mode + if (mode == PAL_SAMPLER_MIPMAP_MODE_NEAREST) { + return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; // sampler mode nearest + } else { + return D3D12_FILTER_MIN_MAG_MIP_LINEAR; // sampler mode linear + } + } + } + } + } + + return D3D12_FILTER_MIN_MAG_MIP_POINT; +} + +static D3D12_TEXTURE_ADDRESS_MODE addressModeToD3D12(PalSamplerAddressMode mode) +{ + switch (mode) { + case PAL_SAMPLER_ADDRESS_MODE_REPEAT: { + return D3D12_TEXTURE_ADDRESS_MODE_WRAP; + } + + case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { + return D3D12_TEXTURE_ADDRESS_MODE_MIRROR; + + } + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { + return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + + } + case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { + return D3D12_TEXTURE_ADDRESS_MODE_BORDER; + } + } + return D3D12_TEXTURE_ADDRESS_MODE_WRAP; +} + +static void borderColorToD3D12(PalBorderColor color, float outColor[4]) +{ + switch (color) { + case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: + case PAL_BORDER_COLOR_INT_TRANSPARENT_BLACK: { + outColor[0] = 0.0f; + outColor[1] = 0.0f; + outColor[2] = 0.0f; + outColor[3] = 0.0f; + break; + } + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_BLACK: + case PAL_BORDER_COLOR_INT_OPAQUE_BLACK: { + outColor[0] = 0.0f; + outColor[1] = 0.0f; + outColor[2] = 0.0f; + outColor[3] = 1.0f; + break; + } + + case PAL_BORDER_COLOR_FLOAT_OPAQUE_WHITE: + case PAL_BORDER_COLOR_INT_OPAQUE_WHITE: { + outColor[0] = 1.0f; + outColor[1] = 1.0f; + outColor[2] = 1.0f; + outColor[3] = 1.0f; + break; + } + } + + outColor[0] = 0.0f; + outColor[1] = 0.0f; + outColor[2] = 0.0f; + outColor[3] = 0.0f; +} + PalResult PAL_CALL createImageD3D12( PalDevice* device, const PalImageCreateInfo* info, diff --git a/src/graphics/d3d12/pal_pipeline_d3d12.c b/src/graphics/d3d12/pal_pipeline_d3d12.c index 46d3db91..fcc771a3 100644 --- a/src/graphics/d3d12/pal_pipeline_d3d12.c +++ b/src/graphics/d3d12/pal_pipeline_d3d12.c @@ -8,6 +8,8 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" +#define align(v, a) (v + a - 1) & ~(a - 1) + #if INTPTR_MAX == INT64_MAX #define PTR_SIZE 8 #else @@ -103,6 +105,283 @@ typedef struct { ShaderStream shaders[7]; // 7 shader types for graphics pipeline } GraphicsPipelineStreamDesc; +static D3D12_STENCIL_OP stencilOpToD3D12(PalStencilOp op) +{ + switch (op) { + case PAL_STENCIL_OP_KEEP: + return D3D12_STENCIL_OP_KEEP; + + case PAL_STENCIL_OP_ZERO: + return D3D12_STENCIL_OP_ZERO; + + case PAL_STENCIL_OP_REPLACE: + return D3D12_STENCIL_OP_REPLACE; + + case PAL_STENCIL_OP_INCREMENT_AND_CLAMP: + return D3D12_STENCIL_OP_INCR_SAT; + + case PAL_STENCIL_OP_DECREMENT_AND_CLAMP: + return D3D12_STENCIL_OP_DECR_SAT; + + case PAL_STENCIL_OP_INVERT: + return D3D12_STENCIL_OP_INVERT; + + case PAL_STENCIL_OP_INCREMENT_AND_WRAP: + return D3D12_STENCIL_OP_INCR; + + case PAL_STENCIL_OP_DECREMENT_AND_WRAP: + return D3D12_STENCIL_OP_DECR; + } + + return D3D12_STENCIL_OP_KEEP; +} + +static D3D12_BLEND_OP blendOpToD3D12(PalBlendOp op) +{ + switch (op) { + case PAL_BLEND_OP_ADD: + return D3D12_BLEND_OP_ADD; + + case PAL_BLEND_OP_SUBTRACT: + return D3D12_BLEND_OP_SUBTRACT; + + case PAL_BLEND_OP_REVERSE_SUBTRACT: + return D3D12_BLEND_OP_REV_SUBTRACT; + + case PAL_BLEND_OP_MIN: + return D3D12_BLEND_OP_MIN; + + case PAL_BLEND_OP_MAX: + return D3D12_BLEND_OP_MAX; + } + + return D3D12_BLEND_OP_ADD; +} + +static D3D12_BLEND blendFactorToD3D12(PalBlendFactor op) +{ + switch (op) { + case PAL_BLEND_FACTOR_ZERO: + return D3D12_BLEND_ZERO; + + case PAL_BLEND_FACTOR_ONE: + return D3D12_BLEND_ONE; + + case PAL_BLEND_FACTOR_SRC_COLOR: + return D3D12_BLEND_SRC_COLOR; + + case PAL_BLEND_FACTOR_ONE_MINUS_SRC_COLOR: + return D3D12_BLEND_INV_SRC_COLOR; + + case PAL_BLEND_FACTOR_DST_COLOR: + return D3D12_BLEND_DEST_COLOR; + + case PAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR: + return D3D12_BLEND_INV_DEST_COLOR; + + case PAL_BLEND_FACTOR_SRC_ALPHA: + return D3D12_BLEND_SRC_ALPHA; + + case PAL_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA: + return D3D12_BLEND_INV_SRC_ALPHA; + + case PAL_BLEND_FACTOR_DST_ALPHA: + return D3D12_BLEND_DEST_ALPHA; + + case PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA: + return D3D12_BLEND_INV_DEST_ALPHA; + + case PAL_BLEND_FACTOR_CONSTANT_COLOR: + case PAL_BLEND_FACTOR_CONSTANT_ALPHA: + return D3D12_BLEND_BLEND_FACTOR; + + case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR: + case PAL_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA: + return D3D12_BLEND_INV_BLEND_FACTOR; + } + + return D3D12_BLEND_ZERO; +} + +static D3D_PRIMITIVE_TOPOLOGY getPatchTopology(uint32_t patch) +{ + switch (patch) { + case 1: + return D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST; + + case 2: + return D3D_PRIMITIVE_TOPOLOGY_2_CONTROL_POINT_PATCHLIST; + + case 3: + return D3D_PRIMITIVE_TOPOLOGY_3_CONTROL_POINT_PATCHLIST; + + case 4: + return D3D_PRIMITIVE_TOPOLOGY_4_CONTROL_POINT_PATCHLIST; + + case 5: + return D3D_PRIMITIVE_TOPOLOGY_5_CONTROL_POINT_PATCHLIST; + + case 6: + return D3D_PRIMITIVE_TOPOLOGY_6_CONTROL_POINT_PATCHLIST; + + case 7: + return D3D_PRIMITIVE_TOPOLOGY_7_CONTROL_POINT_PATCHLIST; + + case 8: + return D3D_PRIMITIVE_TOPOLOGY_8_CONTROL_POINT_PATCHLIST; + + case 9: + return D3D_PRIMITIVE_TOPOLOGY_9_CONTROL_POINT_PATCHLIST; + + case 10: + return D3D_PRIMITIVE_TOPOLOGY_10_CONTROL_POINT_PATCHLIST; + + case 11: + return D3D_PRIMITIVE_TOPOLOGY_11_CONTROL_POINT_PATCHLIST; + + case 12: + return D3D_PRIMITIVE_TOPOLOGY_12_CONTROL_POINT_PATCHLIST; + + case 13: + return D3D_PRIMITIVE_TOPOLOGY_13_CONTROL_POINT_PATCHLIST; + + case 14: + return D3D_PRIMITIVE_TOPOLOGY_14_CONTROL_POINT_PATCHLIST; + + case 15: + return D3D_PRIMITIVE_TOPOLOGY_15_CONTROL_POINT_PATCHLIST; + + case 16: + return D3D_PRIMITIVE_TOPOLOGY_16_CONTROL_POINT_PATCHLIST; + + case 17: + return D3D_PRIMITIVE_TOPOLOGY_17_CONTROL_POINT_PATCHLIST; + + case 18: + return D3D_PRIMITIVE_TOPOLOGY_18_CONTROL_POINT_PATCHLIST; + + case 19: + return D3D_PRIMITIVE_TOPOLOGY_19_CONTROL_POINT_PATCHLIST; + + case 20: + return D3D_PRIMITIVE_TOPOLOGY_20_CONTROL_POINT_PATCHLIST; + + case 21: + return D3D_PRIMITIVE_TOPOLOGY_21_CONTROL_POINT_PATCHLIST; + + case 22: + return D3D_PRIMITIVE_TOPOLOGY_22_CONTROL_POINT_PATCHLIST; + + case 23: + return D3D_PRIMITIVE_TOPOLOGY_23_CONTROL_POINT_PATCHLIST; + + case 24: + return D3D_PRIMITIVE_TOPOLOGY_24_CONTROL_POINT_PATCHLIST; + + case 25: + return D3D_PRIMITIVE_TOPOLOGY_25_CONTROL_POINT_PATCHLIST; + + case 26: + return D3D_PRIMITIVE_TOPOLOGY_26_CONTROL_POINT_PATCHLIST; + + case 27: + return D3D_PRIMITIVE_TOPOLOGY_27_CONTROL_POINT_PATCHLIST; + + case 28: + return D3D_PRIMITIVE_TOPOLOGY_28_CONTROL_POINT_PATCHLIST; + + case 29: + return D3D_PRIMITIVE_TOPOLOGY_29_CONTROL_POINT_PATCHLIST; + + case 30: + return D3D_PRIMITIVE_TOPOLOGY_30_CONTROL_POINT_PATCHLIST; + } + + return D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST; +} + +static uint32_t getVertexTypeSizeD3D12(PalVertexType type) +{ + // count x sizeof type returned as size + switch (type) { + case PAL_VERTEX_TYPE_INT8_2: + case PAL_VERTEX_TYPE_UINT8_2: + case PAL_VERTEX_TYPE_INT8_2NORM: + case PAL_VERTEX_TYPE_UINT8_2NORM: { + return 2; + } + + case PAL_VERTEX_TYPE_INT32: + case PAL_VERTEX_TYPE_UINT32: + case PAL_VERTEX_TYPE_INT8_4: + case PAL_VERTEX_TYPE_INT8_4NORM: + case PAL_VERTEX_TYPE_UINT8_4: + case PAL_VERTEX_TYPE_UINT8_4NORM: + case PAL_VERTEX_TYPE_INT16_2NORM: + case PAL_VERTEX_TYPE_INT16_2: + case PAL_VERTEX_TYPE_UINT16_2: + case PAL_VERTEX_TYPE_UINT16_2NORM: + case PAL_VERTEX_TYPE_FLOAT: + case PAL_VERTEX_TYPE_HALF_FLOAT16_2: { + return 4; + } + + case PAL_VERTEX_TYPE_INT32_2: + case PAL_VERTEX_TYPE_UINT32_2: + case PAL_VERTEX_TYPE_INT16_4: + case PAL_VERTEX_TYPE_UINT16_4: + case PAL_VERTEX_TYPE_UINT16_4NORM: + case PAL_VERTEX_TYPE_INT16_4NORM: + case PAL_VERTEX_TYPE_FLOAT2: + case PAL_VERTEX_TYPE_HALF_FLOAT16_4: { + return 8; + } + + case PAL_VERTEX_TYPE_INT32_3: + case PAL_VERTEX_TYPE_UINT32_3: + case PAL_VERTEX_TYPE_FLOAT3: { + return 12; + } + + case PAL_VERTEX_TYPE_INT32_4: + case PAL_VERTEX_TYPE_UINT32_4: + case PAL_VERTEX_TYPE_FLOAT4: { + return 16; + } + } + + return 0; +} + +static void getHitGroupNameD3D12( + uint32_t index, + wchar_t dst[PAL_SHADER_ENTRY_NAME_SIZE]) +{ + wcscpy(dst, L"HitGroup"); + _itow(index, dst + 8, 10); +} + +static const char* semanticIDToStringD3D12(PalVertexSemanticID id) +{ + switch (id) { + case PAL_VERTEX_SEMANTIC_ID_POSITION: + return "POSITION"; + + case PAL_VERTEX_SEMANTIC_ID_COLOR: + return "COLOR"; + + case PAL_VERTEX_SEMANTIC_ID_TEXCOORD: + return "TEXCOORD"; + + case PAL_VERTEX_SEMANTIC_ID_NORMAL: + return "NORMAL"; + + case PAL_VERTEX_SEMANTIC_ID_TANGENT: + return "TANGENT"; + } + return nullptr; +} + PalResult PAL_CALL createPipelineLayoutD3D12( PalDevice* device, const PalPipelineLayoutCreateInfo* info, @@ -1084,7 +1363,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( if (localRootSize) { D3D12_ROOT_PARAMETER1 parameter = {0}; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; - parameter.Constants.Num32BitValues = alignD3D12(localRootSize, 4) / 4; + parameter.Constants.Num32BitValues = align(localRootSize, 4) / 4; parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; diff --git a/src/graphics/d3d12/pal_sync_d3d12.c b/src/graphics/d3d12/pal_sync_d3d12.c index 5469a576..d6652eb0 100644 --- a/src/graphics/d3d12/pal_sync_d3d12.c +++ b/src/graphics/d3d12/pal_sync_d3d12.c @@ -26,8 +26,8 @@ PalResult PAL_CALL createFenceD3D12( d3d12Device->handle, 0, 0, - &IID_Fence, - &fence->handle); + &IID_Fence, + (void**)&fence->handle); if (FAILED(result)) { pollMessagesD3D12(d3d12Device); @@ -151,7 +151,7 @@ PalResult PAL_CALL createSemaphoreD3D12( 0, 0, &IID_Fence, - &semaphore->handle); + (void**)&semaphore->handle); if (FAILED(result)) { pollMessagesD3D12(d3d12Device); diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c index e7df0ea3..a1f8ca9c 100644 --- a/src/graphics/vulkan/pal_commands_vulkan.c +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -226,6 +226,7 @@ static VkRenderingFlags renderingFlagToVk(PalRenderingFlags flags) static VkResolveModeFlags resolveModeToVk(PalResolveMode mode) { + // TODO: fix switch (mode) { case PAL_RESOLVE_MODE_SAMPLE_ZERO: return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; From 57cdcd14ba26cdbe487b99f6763e8f39c81d9c54 Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 7 Jul 2026 21:03:18 -0700 Subject: [PATCH 322/372] graphics rework: graphics test working d3d12 --- src/graphics/d3d12/pal_device_d3d12.c | 1 + tests/tests_main.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c index a86d3ded..8ece53d2 100644 --- a/src/graphics/d3d12/pal_device_d3d12.c +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -284,6 +284,7 @@ PalResult PAL_CALL createDeviceD3D12( device->adapter = d3d12Adapter->handle; device->features = features; + device->reserved = PAL_BACKEND_KEY; *outDevice = (PalDevice*)device; return PAL_RESULT_SUCCESS; } diff --git a/tests/tests_main.c b/tests/tests_main.c index 7842a582..8d394503 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -52,11 +52,11 @@ int main(int argc, char** argv) #endif // PAL_HAS_OPENGL_MODULE #if PAL_HAS_OPENGL_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 && PAL_HAS_THREAD_MODULE == 1 - registerTest(multiThreadOpenGlTest, "Multi Thread Opengl Test"); + // registerTest(multiThreadOpenGlTest, "Multi Thread Opengl Test"); #endif #if PAL_HAS_GRAPHICS_MODULE == 1 - // registerTest(graphicsTest, "Graphics Test"); + registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); @@ -69,7 +69,7 @@ int main(int argc, char** argv) // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); - registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); + // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From b96c695fc631bd8f151978e10897cbdf9cae2957 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 9 Jul 2026 11:47:57 +0000 Subject: [PATCH 323/372] graphics rework: compute test working d3d12 --- src/graphics/d3d12/pal_buffer_d3d12.c | 62 ++++++++++++++++++--- src/graphics/d3d12/pal_command_pool_d3d12.c | 7 ++- src/graphics/d3d12/pal_commands_d3d12.c | 4 ++ src/graphics/d3d12/pal_device_d3d12.c | 1 + tests/tests_main.c | 4 +- 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/src/graphics/d3d12/pal_buffer_d3d12.c b/src/graphics/d3d12/pal_buffer_d3d12.c index e6275ac2..2acbe370 100644 --- a/src/graphics/d3d12/pal_buffer_d3d12.c +++ b/src/graphics/d3d12/pal_buffer_d3d12.c @@ -10,6 +10,41 @@ #define align(v, a) (v + a - 1) & ~(a - 1) +static uint32_t getSupportedMemoryTypes(PalBufferUsages usages) +{ + uint32_t masks = 0; + masks |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); + masks |= (1u << PAL_MEMORY_TYPE_CPU_UPLOAD); + masks |= (1u << PAL_MEMORY_TYPE_CPU_READBACK); + + if (usages & PAL_BUFFER_USAGE_STORAGE) { + masks &= ~PAL_MEMORY_TYPE_CPU_UPLOAD; + masks &= ~PAL_MEMORY_TYPE_CPU_READBACK; + } + + if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { + masks &= ~PAL_MEMORY_TYPE_CPU_UPLOAD; + masks &= ~PAL_MEMORY_TYPE_CPU_READBACK; + } + + if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { + masks &= ~PAL_MEMORY_TYPE_CPU_UPLOAD; + masks &= ~PAL_MEMORY_TYPE_CPU_READBACK; + } + + if (usages & PAL_BUFFER_USAGE_TRANSFER_DST) { + masks |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); + masks &= ~PAL_MEMORY_TYPE_CPU_UPLOAD; + } + + if (usages & PAL_BUFFER_USAGE_TRANSFER_SRC) { + masks |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); + masks &= ~PAL_MEMORY_TYPE_CPU_READBACK; + } + + return masks; +} + PalResult PAL_CALL createBufferD3D12( PalDevice* device, const PalBufferCreateInfo* info, @@ -63,14 +98,31 @@ PalResult PAL_CALL createBufferD3D12( D3D12_HEAP_PROPERTIES heapProps = {0}; heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; D3D12_RESOURCE_STATES state = D3D12_RESOURCE_STATE_COMMON; + buffer->canStateChange = PAL_TRUE; - if (info->memoryUsage != PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD) { + uint32_t masks = getSupportedMemoryTypes(info->usages); + if (info->memoryUsage == PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY) { + if (!(masks & (1u << PAL_MEMORY_TYPE_GPU_ONLY))) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + + } else if (info->memoryUsage == PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD) { heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; state = D3D12_RESOURCE_STATE_GENERIC_READ; + buffer->canStateChange = PAL_FALSE; + + if (!(masks & (1u << PAL_MEMORY_TYPE_CPU_UPLOAD))) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } - } else if (info->memoryUsage != PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK) { + } else if (info->memoryUsage == PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK) { heapProps.Type = D3D12_HEAP_TYPE_READBACK; state = D3D12_RESOURCE_STATE_COPY_DEST; + buffer->canStateChange = PAL_FALSE; + + if (!(masks & (1u << PAL_MEMORY_TYPE_CPU_READBACK))) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } } result = d3d12Device->handle->lpVtbl->CreateCommittedResource( @@ -123,11 +175,7 @@ PalResult PAL_CALL getBufferMemoryRequirementsD3D12( 1, &d3d12Buffer->desc); - // d3d12 allows buffers to be used with all memory heap types - requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); - requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_CPU_UPLOAD); - requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_CPU_READBACK); - + requirements->supportedMemoryTypes = getSupportedMemoryTypes(d3d12Buffer->usages); requirements->alignment = allocationInfo.Alignment; requirements->size = allocationInfo.SizeInBytes; return PAL_RESULT_SUCCESS; diff --git a/src/graphics/d3d12/pal_command_pool_d3d12.c b/src/graphics/d3d12/pal_command_pool_d3d12.c index 55c845bc..15a22e73 100644 --- a/src/graphics/d3d12/pal_command_pool_d3d12.c +++ b/src/graphics/d3d12/pal_command_pool_d3d12.c @@ -10,7 +10,7 @@ static CommandBufferData* getFreeCmdBufferData(CommandPoolD3D12* pool) { - for (int i = 0; i < pool->size; ++i) { + for (int i = 0; i < pool->size; i++) { if (!pool->cmdBuffersData[i].used) { pool->cmdBuffersData[i].used = PAL_TRUE; return &pool->cmdBuffersData[i]; @@ -40,7 +40,7 @@ static CommandBufferData* findCmdBufferData( CommandPoolD3D12* pool, CommandBufferD3D12* cmdBuffer) { - for (int i = 0; i < pool->size; ++i) { + for (int i = 0; i < pool->size; i++) { if (pool->cmdBuffersData[i].used && pool->cmdBuffersData[i].cmdBuffer == cmdBuffer) { return &pool->cmdBuffersData[i]; } @@ -73,6 +73,7 @@ PalResult PAL_CALL createCommandPoolD3D12( return PAL_RESULT_CODE_OUT_OF_MEMORY; } + memset(pool->cmdBuffersData, 0, sizeof(CommandBufferData) * pool->size); switch (d3d12Queue->type) { case PAL_QUEUE_TYPE_COMPUTE: { pool->type = D3D12_COMMAND_LIST_TYPE_COMPUTE; @@ -102,7 +103,6 @@ void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) if (!cmdPool->cmdBuffersData[i].used) { continue; } - CommandBufferD3D12* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; cmdBuffer->handle->lpVtbl->Release(cmdBuffer->handle); cmdBuffer->allocator->lpVtbl->Release(cmdBuffer->allocator); @@ -342,6 +342,7 @@ PalResult PAL_CALL submitCommandBufferD3D12( } } + // pollMessagesD3D12(d3d12CmdBuffer->device); ID3D12CommandList* cmdLists[1] = { (ID3D12CommandList*)d3d12CmdBuffer->handle }; queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, cmdLists); diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index 1edf3bf8..58e3071c 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -762,6 +762,10 @@ PalResult PAL_CALL cmdBindPipelineD3D12( d3d12CmdBuffer->handle, d3dPipeline->handle); + d3d12CmdBuffer->handle->lpVtbl->SetComputeRootSignature( + d3d12CmdBuffer->handle, + d3dPipeline->layout->handle); + if (d3dPipeline->type == GRAPHICS_PIPELINE) { d3d12CmdBuffer->handle->lpVtbl->IASetPrimitiveTopology( d3d12CmdBuffer->handle, diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c index 8ece53d2..f6c335a1 100644 --- a/src/graphics/d3d12/pal_device_d3d12.c +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -733,6 +733,7 @@ PalResult PAL_CALL createShaderD3D12( shader->byteCode.BytecodeLength = info->bytecodeSize; shader->entryCount = info->entryCount; + shader->reserved = PAL_BACKEND_KEY; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } diff --git a/tests/tests_main.c b/tests/tests_main.c index 8d394503..94edff6c 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -56,8 +56,8 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS_MODULE == 1 - registerTest(graphicsTest, "Graphics Test"); - // registerTest(computeTest, "Compute Test"); + // registerTest(graphicsTest, "Graphics Test"); + registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS_MODULE From a7de5797c2d151f4cdac4ee82926cbb3c5f30d4c Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 9 Jul 2026 16:16:10 +0000 Subject: [PATCH 324/372] graphics rework: make API changes --- CHANGELOG.md | 2 + include/pal/pal_graphics.h | 749 ++++++------------ include/pal/pal_video.h | 4 +- src/graphics/d3d12/pal_adapter_d3d12.c | 58 +- src/graphics/d3d12/pal_as_d3d12.c | 9 +- src/graphics/pal_graphics_backends.h | 16 +- src/graphics/vulkan/pal_adapter_vulkan.c | 11 +- src/graphics/vulkan/pal_as_vulkan.c | 7 +- src/graphics/vulkan/pal_buffer_vulkan.c | 12 +- src/graphics/vulkan/pal_command_pool_vulkan.c | 12 +- src/graphics/vulkan/pal_commands_vulkan.c | 2 +- src/graphics/vulkan/pal_device_vulkan.c | 2 +- src/video/pal_video.c | 4 +- src/video/wayland/pal_monitor_wayland.c | 4 +- src/video/win32/pal_monitor_win32.c | 4 +- src/video/x11/pal_monitor_x11.c | 4 +- 16 files changed, 328 insertions(+), 572 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75bd9865..b40685af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -65,6 +65,8 @@ - `palEnumerateGLFBConfigs()` no longer takes the `glWindow` parameter. - `palInitVideo()` now takes an additional parameter. - `palGetMouseDelta()` now takes `dx` and `dy` paramters as `float`. +- `palEnumerateMonitors()` now takes `count` paramter as `uint32_t`. +- `palEnumerateMonitorModes()` now takes `count` paramter as `uint32_t`. - `palGetMouseWheelDelta()` now takes `dx` and `dy` paramters as `float`. - `palJoinThread()` now takes `retval` paramters as `void**`. - Removed `palGLSetInstance()` function. diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 237431a7..1b10016b 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1886,6 +1886,20 @@ typedef struct { uint32_t workGroupCount[3]; /**< Workgroup count per dimension of a dispatch tile.*/ } PalWorkGroupInfo; +/** + * @struct PalImageStagingRequirements + * @brief Requirements for an image staging buffer. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 2.0 + */ +typedef struct { + uint64_t outSize; /**< Required buffer size.*/ + uint32_t bufferRowLength; /**< Required buffer row length.*/ + uint32_t bufferImageHeight; /**< Required buffer image height.*/ +} PalImageStagingRequirements; + /** * @struct PalDrawIndirectData * @brief Draw indirect data of a single draw call. @@ -2701,7 +2715,7 @@ typedef struct { * Must obey the rules and semantics documented in palEnumerateAdapters(). */ PalResult(PAL_CALL* enumerateAdapters)( - int32_t* count, + uint32_t* count, PalAdapter** outAdapters); /** @@ -2709,7 +2723,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetAdapterInfo(). */ - PalResult(PAL_CALL* getAdapterInfo)( + void(PAL_CALL* getAdapterInfo)( PalAdapter* adapter, PalAdapterInfo* info); @@ -2718,7 +2732,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetAdapterCapabilities(). */ - PalResult(PAL_CALL* getAdapterCapabilities)( + void(PAL_CALL* getAdapterCapabilities)( PalAdapter* adapter, PalAdapterCapabilities* caps); @@ -2772,9 +2786,7 @@ typedef struct { * * Must obey the rules and semantics documented in palFreeMemory(). */ - void(PAL_CALL* freeMemory)( - PalDevice* device, - PalMemory* memory); + void(PAL_CALL* freeMemory)(PalMemory* memory); /** * Backend implementation of ::palQuerySamplerAnisotropyCapabilities. @@ -2782,7 +2794,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQuerySamplerAnisotropyCapabilities(). */ - PalResult(PAL_CALL* querySamplerAnisotropyCapabilities)( + void(PAL_CALL* querySamplerAnisotropyCapabilities)( PalDevice* device, PalSamplerAnisotropyCapabilities* caps); @@ -2792,7 +2804,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryMultiViewCapabilities(). */ - PalResult(PAL_CALL* queryMultiViewCapabilities)( + void(PAL_CALL* queryMultiViewCapabilities)( PalDevice* device, PalMultiViewCapabilities* caps); @@ -2802,7 +2814,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryMultiViewportCapabilities(). */ - PalResult(PAL_CALL* queryMultiViewportCapabilities)( + void(PAL_CALL* queryMultiViewportCapabilities)( PalDevice* device, PalMultiViewportCapabilities* caps); @@ -2812,7 +2824,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryDepthStencilCapabilities(). */ - PalResult(PAL_CALL* queryDepthStencilCapabilities)( + void(PAL_CALL* queryDepthStencilCapabilities)( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -2822,7 +2834,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryFragmentShadingRateCapabilities(). */ - PalResult(PAL_CALL* queryFragmentShadingRateCapabilities)( + void(PAL_CALL* queryFragmentShadingRateCapabilities)( PalDevice* device, PalFragmentShadingRateCapabilities* caps); @@ -2832,7 +2844,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryMeshShaderCapabilities(). */ - PalResult(PAL_CALL* queryMeshShaderCapabilities)( + void(PAL_CALL* queryMeshShaderCapabilities)( PalDevice* device, PalMeshShaderCapabilities* caps); @@ -2842,7 +2854,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryRayTracingCapabilities(). */ - PalResult(PAL_CALL* queryRayTracingCapabilities)( + void(PAL_CALL* queryRayTracingCapabilities)( PalDevice* device, PalRayTracingCapabilities* caps); @@ -2852,7 +2864,7 @@ typedef struct { * Must obey the rules and semantics documented in * palQueryDescriptorIndexingCapabilities(). */ - PalResult(PAL_CALL* queryDescriptorIndexingCapabilities)( + void(PAL_CALL* queryDescriptorIndexingCapabilities)( PalDevice* device, PalDescriptorIndexingCapabilities* caps); @@ -2894,9 +2906,9 @@ typedef struct { * * Must obey the rules and semantics documented in palEnumerateFormats(). */ - PalResult(PAL_CALL* enumerateFormats)( + void(PAL_CALL* enumerateFormats)( PalAdapter* adapter, - int32_t* count, + uint32_t* count, PalFormatInfo* outFormats); /** @@ -2948,7 +2960,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetImageInfo(). */ - PalResult(PAL_CALL* getImageInfo)( + void(PAL_CALL* getImageInfo)( PalImage* image, PalImageInfo* info); @@ -2957,7 +2969,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetImageMemoryRequirements(). */ - PalResult(PAL_CALL* getImageMemoryRequirements)( + void(PAL_CALL* getImageMemoryRequirements)( PalImage* image, PalMemoryRequirements* requirements); @@ -3030,7 +3042,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetSurfaceCapabilities(). */ - PalResult(PAL_CALL* getSurfaceCapabilities)( + void(PAL_CALL* getSurfaceCapabilities)( PalDevice* device, PalSurface* surface, PalSurfaceCapabilities* caps); @@ -3275,7 +3287,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdExecuteCommandBuffer(). */ - PalResult(PAL_CALL* cmdExecuteCommandBuffer)( + void(PAL_CALL* cmdExecuteCommandBuffer)( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -3284,7 +3296,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetFragmentShadingRate(). */ - PalResult(PAL_CALL* cmdSetFragmentShadingRate)( + void(PAL_CALL* cmdSetFragmentShadingRate)( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state); @@ -3293,7 +3305,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawMeshTasks(). */ - PalResult(PAL_CALL* cmdDrawMeshTasks)( + void(PAL_CALL* cmdDrawMeshTasks)( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, @@ -3304,7 +3316,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawMeshTasksIndirect(). */ - PalResult(PAL_CALL* cmdDrawMeshTasksIndirect)( + void(PAL_CALL* cmdDrawMeshTasksIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t drawCount); @@ -3314,7 +3326,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawMeshTasksIndirectCount(). */ - PalResult(PAL_CALL* cmdDrawMeshTasksIndirectCount)( + void(PAL_CALL* cmdDrawMeshTasksIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -3325,7 +3337,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBuildAccelerationStructure(). */ - PalResult(PAL_CALL* cmdBuildAccelerationStructure)( + void(PAL_CALL* cmdBuildAccelerationStructure)( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); @@ -3334,7 +3346,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBeginRendering(). */ - PalResult(PAL_CALL* cmdBeginRendering)( + void(PAL_CALL* cmdBeginRendering)( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info); @@ -3343,14 +3355,14 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdEndRendering(). */ - PalResult(PAL_CALL* cmdEndRendering)(PalCommandBuffer* cmdBuffer); + void(PAL_CALL* cmdEndRendering)(PalCommandBuffer* cmdBuffer); /** * Backend implementation of ::palCmdCopyBuffer. * * Must obey the rules and semantics documented in palCmdCopyBuffer(). */ - PalResult(PAL_CALL* cmdCopyBuffer)( + void(PAL_CALL* cmdCopyBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -3361,7 +3373,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdCopyBufferToImage(). */ - PalResult(PAL_CALL* cmdCopyBufferToImage)( + void(PAL_CALL* cmdCopyBufferToImage)( PalCommandBuffer* cmdBuffer, PalImage* dstImage, PalBuffer* srcBuffer, @@ -3372,7 +3384,7 @@ typedef struct { * * Must obey the rules and semantics documented in cmdCopyImage(). */ - PalResult(PAL_CALL* cmdCopyImage)( + void(PAL_CALL* cmdCopyImage)( PalCommandBuffer* cmdBuffer, PalImage* dst, PalImage* src, @@ -3383,7 +3395,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdCopyImageToBuffer(). */ - PalResult(PAL_CALL* cmdCopyImageToBuffer)( + void(PAL_CALL* cmdCopyImageToBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, @@ -3394,7 +3406,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindPipeline(). */ - PalResult(PAL_CALL* cmdBindPipeline)( + void(PAL_CALL* cmdBindPipeline)( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline); @@ -3403,7 +3415,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetViewport(). */ - PalResult(PAL_CALL* cmdSetViewport)( + void(PAL_CALL* cmdSetViewport)( PalCommandBuffer* cmdBuffer, uint32_t count, PalViewport* viewports); @@ -3413,7 +3425,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetScissors(). */ - PalResult(PAL_CALL* cmdSetScissors)( + void(PAL_CALL* cmdSetScissors)( PalCommandBuffer* cmdBuffer, uint32_t count, PalRect2D* scissors); @@ -3423,7 +3435,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindVertexBuffers(). */ - PalResult(PAL_CALL* cmdBindVertexBuffers)( + void(PAL_CALL* cmdBindVertexBuffers)( PalCommandBuffer* cmdBuffer, uint32_t firstSlot, uint32_t count, @@ -3435,7 +3447,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindIndexBuffer(). */ - PalResult(PAL_CALL* cmdBindIndexBuffer)( + void(PAL_CALL* cmdBindIndexBuffer)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint64_t offset, @@ -3446,7 +3458,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDraw(). */ - PalResult(PAL_CALL* cmdDraw)( + void(PAL_CALL* cmdDraw)( PalCommandBuffer* cmdBuffer, uint32_t vertexCount, uint32_t instanceCount, @@ -3458,7 +3470,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndirect(). */ - PalResult(PAL_CALL* cmdDrawIndirect)( + void(PAL_CALL* cmdDrawIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count); @@ -3468,7 +3480,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndirectCount(). */ - PalResult(PAL_CALL* cmdDrawIndirectCount)( + void(PAL_CALL* cmdDrawIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -3479,7 +3491,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndexed(). */ - PalResult(PAL_CALL* cmdDrawIndexed)( + void(PAL_CALL* cmdDrawIndexed)( PalCommandBuffer* cmdBuffer, uint32_t indexCount, uint32_t instanceCount, @@ -3492,7 +3504,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndexedIndirect(). */ - PalResult(PAL_CALL* cmdDrawIndexedIndirect)( + void(PAL_CALL* cmdDrawIndexedIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count); @@ -3502,7 +3514,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDrawIndexedIndirectCount(). */ - PalResult(PAL_CALL* cmdDrawIndexedIndirectCount)( + void(PAL_CALL* cmdDrawIndexedIndirectCount)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -3513,7 +3525,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdAccelerationStructureBarrier(). */ - PalResult(PAL_CALL* cmdAccelerationStructureBarrier)( + void(PAL_CALL* cmdAccelerationStructureBarrier)( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, PalUsageState oldUsageState, @@ -3524,7 +3536,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdImageBarrier(). */ - PalResult(PAL_CALL* cmdImageBarrier)( + void(PAL_CALL* cmdImageBarrier)( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, @@ -3536,7 +3548,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBufferBarrier(). */ - PalResult(PAL_CALL* cmdBufferBarrier)( + void(PAL_CALL* cmdBufferBarrier)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageState oldUsageState, @@ -3547,7 +3559,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDispatch(). */ - PalResult(PAL_CALL* cmdDispatch)( + void(PAL_CALL* cmdDispatch)( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, @@ -3558,7 +3570,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDispatchBase(). */ - PalResult(PAL_CALL* cmdDispatchBase)( + void(PAL_CALL* cmdDispatchBase)( PalCommandBuffer* cmdBuffer, uint32_t baseGroupX, uint32_t baseGroupY, @@ -3572,7 +3584,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdDispatchIndirect(). */ - PalResult(PAL_CALL* cmdDispatchIndirect)( + void(PAL_CALL* cmdDispatchIndirect)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer); @@ -3581,7 +3593,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdTraceRays(). */ - PalResult(PAL_CALL* cmdTraceRays)( + void(PAL_CALL* cmdTraceRays)( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, uint32_t raygenIndex, @@ -3594,7 +3606,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdTraceRaysIndirect(). */ - PalResult(PAL_CALL* cmdTraceRaysIndirect)( + void(PAL_CALL* cmdTraceRaysIndirect)( PalCommandBuffer* cmdBuffer, uint32_t raygenIndex, PalShaderBindingTable* sbt, @@ -3605,7 +3617,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdBindDescriptorSet(). */ - PalResult(PAL_CALL* cmdBindDescriptorSet)( + void(PAL_CALL* cmdBindDescriptorSet)( PalCommandBuffer* cmdBuffer, uint32_t setIndex, PalDescriptorSet* set); @@ -3615,7 +3627,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdPushConstants(). */ - PalResult(PAL_CALL* cmdPushConstants)( + void(PAL_CALL* cmdPushConstants)( PalCommandBuffer* cmdBuffer, uint32_t offset, uint32_t size, @@ -3626,7 +3638,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetCullMode(). */ - PalResult(PAL_CALL* cmdSetCullMode)( + void(PAL_CALL* cmdSetCullMode)( PalCommandBuffer* cmdBuffer, PalCullMode cullMode); @@ -3635,7 +3647,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetFrontFace(). */ - PalResult(PAL_CALL* cmdSetFrontFace)( + void(PAL_CALL* cmdSetFrontFace)( PalCommandBuffer* cmdBuffer, PalFrontFace frontFace); @@ -3644,7 +3656,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetPrimitiveTopology(). */ - PalResult(PAL_CALL* cmdSetPrimitiveTopology)( + void(PAL_CALL* cmdSetPrimitiveTopology)( PalCommandBuffer* cmdBuffer, PalPrimitiveTopology topology); @@ -3653,7 +3665,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetDepthTestEnable(). */ - PalResult(PAL_CALL* cmdSetDepthTestEnable)( + void(PAL_CALL* cmdSetDepthTestEnable)( PalCommandBuffer* cmdBuffer, PalBool enable); @@ -3662,7 +3674,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetDepthWriteEnable(). */ - PalResult(PAL_CALL* cmdSetDepthWriteEnable)( + void(PAL_CALL* cmdSetDepthWriteEnable)( PalCommandBuffer* cmdBuffer, PalBool enable); @@ -3671,7 +3683,7 @@ typedef struct { * * Must obey the rules and semantics documented in palCmdSetStencilOp(). */ - PalResult(PAL_CALL* cmdSetStencilOp)( + void(PAL_CALL* cmdSetStencilOp)( PalCommandBuffer* cmdBuffer, PalStencilFaceFlags faceMask, PalStencilOp failOp, @@ -3701,7 +3713,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetAccelerationStructureBuildSize(). */ - PalResult(PAL_CALL* getAccelerationStructureBuildSize)( + void(PAL_CALL* getAccelerationStructureBuildSize)( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); @@ -3728,56 +3740,49 @@ typedef struct { * * Must obey the rules and semantics documented in palGetBufferMemoryRequirements(). */ - PalResult(PAL_CALL* getBufferMemoryRequirements)( + void(PAL_CALL* getBufferMemoryRequirements)( PalBuffer* buffer, PalMemoryRequirements* requirements); /** - * Backend implementation of ::palComputeInstanceBufferRequirements. + * Backend implementation of ::palComputeInstanceStagingSize. * - * Must obey the rules and semantics documented in palComputeInstanceBufferRequirements(). + * Must obey the rules and semantics documented in palComputeInstanceStagingSize(). */ - PalResult(PAL_CALL* computeInstanceBufferRequirements)( - PalDevice* device, - uint32_t instanceCount, + void(PAL_CALL* computeInstanceStagingSize)( + uint32_t instanceCount, uint64_t* outSize); /** - * Backend implementation of ::palComputeImageCopyStagingBufferRequirements. + * Backend implementation of ::palComputeImageStagingRequirements. * - * Must obey the rules and semantics documented in - * palComputeImageCopyStagingBufferRequirements(). + * Must obey the rules and semantics documented in palComputeImageStagingRequirements(). */ - PalResult(PAL_CALL* computeImageCopyStagingBufferRequirements)( - PalDevice* device, + void(PAL_CALL* computeImageStagingRequirements)( PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize); + const PalBufferImageCopyInfo* copyInfo, + PalImageStagingRequirements* outRequirements); /** - * Backend implementation of ::palWriteToInstanceBuffer. + * Backend implementation of ::palWriteInstanceStaging. * - * Must obey the rules and semantics documented in palWriteToInstanceBuffer(). + * Must obey the rules and semantics documented in palWriteInstanceStaging(). */ - PalResult(PAL_CALL* writeToInstanceBuffer)( - PalDevice* device, - void* ptr, + void(PAL_CALL* writeInstanceStaging)( + uint32_t instanceCount, PalAccelerationStructureInstance* instances, - uint32_t instanceCount); + void* ptr); /** - * Backend implementation of ::palWriteToImageCopyStagingBuffer. + * Backend implementation of ::palWriteImageStaging. * - * Must obey the rules and semantics documented in palWriteToImageCopyStagingBuffer(). + * Must obey the rules and semantics documented in palWriteImageStaging(). */ - PalResult(PAL_CALL* writeToImageCopyStagingBuffer)( - PalDevice* device, - void* ptr, - void* srcData, + void(PAL_CALL* writeImageStaging)( PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo); + PalBufferImageCopyInfo* copyInfo, + void* srcData, + void* ptr); /** * Backend implementation of ::palBindBufferMemory. @@ -3952,7 +3957,7 @@ typedef struct { * * Must obey the rules and semantics documented in palUpdateShaderBindingTable(). */ - PalResult(PAL_CALL* updateShaderBindingTable)( + void(PAL_CALL* updateShaderBindingTable)( PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos); @@ -3969,9 +3974,8 @@ typedef struct { * debugging will be disabled. * * All backends must have their vtable functions fully set according to the version requirements. - * If a feature is not supported by a backend, `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED` must be - * returned by the appropriate function. This is validated at initialization and will fail and - * return `PAL_RESULT_INVALID_ARGUMENT`. + * All required pointers must be set. If an optional feature is not supported, `nullptr` must be + * set and its appropriate feature bit (eg. `PAL_ADAPTER_FEATURE_RAY_TRACING`) must not be set. * * @param[in] debugger Optional debugger. Set to `nullptr` to disable debugging and validation * layers. @@ -4035,7 +4039,7 @@ PAL_API void PAL_CALL palShutdownGraphics(); * @since 2.0 */ PAL_API PalResult PAL_CALL palEnumerateAdapters( - int32_t* count, + uint32_t* count, PalAdapter** outAdapters); /** @@ -4046,15 +4050,12 @@ PAL_API PalResult PAL_CALL palEnumerateAdapters( * @param[in] adapter Adapter to query information on. * @param[out] info Pointer to a PalAdapterInfo to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `info` is per thread. * * @since 2.0 * @sa palEnumerateAdapters */ -PAL_API PalResult PAL_CALL palGetAdapterInfo( +PAL_API void PAL_CALL palGetAdapterInfo( PalAdapter* adapter, PalAdapterInfo* info); @@ -4066,15 +4067,12 @@ PAL_API PalResult PAL_CALL palGetAdapterInfo( * @param[in] adapter Adapter to query capabilities on. * @param[out] caps Pointer to a PalAdapterCapabilities to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `caps` is per thread. * * @since 2.0 * @sa palEnumerateAdapters */ -PAL_API PalResult PAL_CALL palGetAdapterCapabilities( +PAL_API void PAL_CALL palGetAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps); @@ -4118,9 +4116,9 @@ PAL_API uint32_t PAL_CALL palGetHighestSupportedShaderTarget( * @brief Create a device from an adapter (GPU). * * The graphics system must be initialized before this call. PAL does not enable any features - * implicitly not even common ones like `PAL_ADAPTER_FEATURE_SWAPCHAIN`. + * by default. * - * Every requested feature must be supported by the adapter. Use palGetAdapterFeatures to check + * Every requested feature must be supported by the adapter. Use `palGetAdapterFeatures` to check * the supported features of the adapter that can be enabled. Using a feature which is not * supported will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. * @@ -4213,19 +4211,16 @@ PAL_API void PAL_CALL palFreeMemory( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * device. Otherwise behavior is undefined. * * @param[in] device Device to query sampler anisotropy feature capabilities on. * @param[out] caps Pointer to a PalSamplerAnisotropyCapabilities to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `caps` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( +PAL_API void PAL_CALL palQuerySamplerAnisotropyCapabilities( PalDevice* device, PalSamplerAnisotropyCapabilities* caps); @@ -4235,19 +4230,16 @@ PAL_API PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * device. Otherwise behavior is undefined. * * @param[in] device Device to query multi view feature capabilities on. * @param[out] caps Pointer to a PalMultiViewCapabilities to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `caps` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palQueryMultiViewCapabilities( +PAL_API void PAL_CALL palQueryMultiViewCapabilities( PalDevice* device, PalMultiViewCapabilities* caps); @@ -4257,19 +4249,16 @@ PAL_API PalResult PAL_CALL palQueryMultiViewCapabilities( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_MULTI_VIEWPORT` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * device. Otherwise behavior is undefined. * * @param[in] device Device to query multi viewport feature capabilities on. * @param[out] caps Pointer to a PalMultiViewportCapabilities to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `caps` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palQueryMultiViewportCapabilities( +PAL_API void PAL_CALL palQueryMultiViewportCapabilities( PalDevice* device, PalMultiViewportCapabilities* caps); @@ -4279,19 +4268,16 @@ PAL_API PalResult PAL_CALL palQueryMultiViewportCapabilities( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * device. Otherwise behavior is undefined. * * @param[in] device Device to query depth stencil feature capabilities on. * @param[out] caps Pointer to a PalDepthStencilCapabilities to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `caps` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( +PAL_API void PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps); @@ -4301,19 +4287,16 @@ PAL_API PalResult PAL_CALL palQueryDepthStencilCapabilities( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * device. Otherwise behavior is undefined. * * @param[in] device Device to query fragment shading rate feature capabilities on. * @param[out] caps Pointer to a PalFragmentShadingRateCapabilities to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `caps` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( +PAL_API void PAL_CALL palQueryFragmentShadingRateCapabilities( PalDevice* device, PalFragmentShadingRateCapabilities* caps); @@ -4323,19 +4306,16 @@ PAL_API PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * device. Otherwise behavior is undefined. * * @param[in] device Device to query mesh shader feature capabilities on. * @param[out] caps Pointer to a PalMeshShaderCapabilities to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `caps` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( +PAL_API void PAL_CALL palQueryMeshShaderCapabilities( PalDevice* device, PalMeshShaderCapabilities* caps); @@ -4345,19 +4325,16 @@ PAL_API PalResult PAL_CALL palQueryMeshShaderCapabilities( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * device. Otherwise behavior is undefined. * * @param[in] device Device to query ray tracing feature capabilities on. * @param[out] caps Pointer to a PalRayTracingCapabilities to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `caps` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( +PAL_API void PAL_CALL palQueryRayTracingCapabilities( PalDevice* device, PalRayTracingCapabilities* caps); @@ -4367,19 +4344,16 @@ PAL_API PalResult PAL_CALL palQueryRayTracingCapabilities( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * device. Otherwise behavior is undefined. * * @param[in] device Device to query descriptor indexing feature capabilities on. * @param[out] caps Pointer to a PalDescriptorIndexingCapabilities to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `caps` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( +PAL_API void PAL_CALL palQueryDescriptorIndexingCapabilities( PalDevice* device, PalDescriptorIndexingCapabilities* caps); @@ -4486,17 +4460,14 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); * @param[in, out] count Capacity of the PalFormatInfo array. * @param[out] outFormats User allocated array of PalFormatInfo. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `outFormats` is per thread. * * @since 2.0 * @sa palIsFormatSupported */ -PAL_API PalResult PAL_CALL palEnumerateFormats( +PAL_API void PAL_CALL palEnumerateFormats( PalAdapter* adapter, - int32_t* count, + uint32_t* count, PalFormatInfo* outFormats); /** @@ -4612,15 +4583,12 @@ PAL_API void PAL_CALL palDestroyImage(PalImage* image); * @param[in] image Image to query information on. * @param[out] info Pointer to a PalImageInfo to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `info` is per thread. * * @since 2.0 * @sa palCreateImage */ -PAL_API PalResult PAL_CALL palGetImageInfo( +PAL_API void PAL_CALL palGetImageInfo( PalImage* image, PalImageInfo* info); @@ -4632,14 +4600,11 @@ PAL_API PalResult PAL_CALL palGetImageInfo( * @param[in] image Image to query memory requirements on. * @param[out] requirements Pointer to a PalMemoryRequirements to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `requirements` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palGetImageMemoryRequirements( +PAL_API void PAL_CALL palGetImageMemoryRequirements( PalImage* image, PalMemoryRequirements* requirements); @@ -4677,7 +4642,8 @@ PAL_API PalResult PAL_CALL palBindImageMemory( * `PAL_IMAGE_VIEW_TYPE_2D_ARRAY`. * * `PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY` must be supported and enabled by the device - * used to create the image view if `PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY` will be used. + * used to create the image view if `PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY` will be used. + * Otherwise behavior is undefined. * * @param[in] device Device that creates the image view. * @param[in] image Image to create the image view with. @@ -4763,8 +4729,8 @@ PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the device. + * Otherwise behavior is undefined. * * @param[in] device Device that creates the surface. * @param[in] window Window to create the surface for. @@ -4810,20 +4776,17 @@ PAL_API void PAL_CALL palDestroySurface(PalSurface* surface); * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * device. Otherwise behavior is undefined. * * @param[in] device Device to query surface feature capabilities on. * @param[in] surface Surface to query capabilities. * @param[out] caps Pointer to a PalSurfaceCapabilities to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `caps` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palGetSurfaceCapabilities( +PAL_API void PAL_CALL palGetSurfaceCapabilities( PalDevice* device, PalSurface* surface, PalSurfaceCapabilities* caps); @@ -4833,8 +4796,8 @@ PAL_API PalResult PAL_CALL palGetSurfaceCapabilities( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the device. + * Otherwise behavior is undefined. * * @param[in] device Device that creates the swapchain. * @param[in] queue Queue to create swapchain with. This must be a graphics queue. @@ -5088,7 +5051,7 @@ PAL_API PalResult PAL_CALL palWaitFence( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_FENCE_RESET` must be supported and enabled when creating the - * device. If not, this function fails and returns `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * device. Otherwise behavior is undefined. * * @param[in] fence Fence to reset. * @@ -5163,9 +5126,7 @@ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); * @brief Waits for a semaphore to reach the provided value. * * The graphics system must be initialized before this call. - * - * The provided semaphore must be a timeline semaphore If not, this function fails and returns - * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * The provided semaphore must be a timeline semaphore. Otherwise undefined behavior. * * @param[in] semaphore Semaphore to wait on. * @param[in] value Value to wait for. @@ -5189,9 +5150,7 @@ PAL_API PalResult PAL_CALL palWaitSemaphore( * @brief Signals a semaphore from the provided value. * * The graphics system must be initialized before this call. - * - * The provided semaphore must be a timeline semaphore If not, this function fails and returns - * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * The provided semaphore must be a timeline semaphore. Otherwise undefined behavior. * * @param[in] semaphore Semaphore to signal. * @param[in] queue Queue used to signal the semaphore. @@ -5215,9 +5174,7 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * @brief Get the value of a semaphore. * * The graphics system must be initialized before this call. - * - * The provided semaphore must be a timeline semaphore If not, this function fails and returns - * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + The provided semaphore must be a timeline semaphore. Otherwise undefined behavior. * * @param[in] semaphore Semaphore to get its value. * @param[out] outValue Pointer to a uint64_t to receive the semaphore value. @@ -5416,14 +5373,11 @@ PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); * @param[in] primaryCmdBuffer Primary command buffer. Must be in recording state. * @param[in] secondaryCmdBuffer Secondary command buffer. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `primaryCmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( +PAL_API void PAL_CALL palCmdExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer); @@ -5432,21 +5386,17 @@ PAL_API PalResult PAL_CALL palCmdExecuteCommandBuffer( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled by the device if not, - * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] state Pointer to a PalFragmentShadingRateState struct that specifies parameters. - * Must not be `nullptr`. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( +PAL_API void PAL_CALL palCmdSetFragmentShadingRate( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state); @@ -5455,17 +5405,14 @@ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] groupCountX Number of mesh shader groups to dispatch on the x axis. * @param[in] groupCountY Number of mesh shader groups to dispatch on the y axis. * @param[in] groupCountZ Number of mesh shader groups to dispatch on the z axis. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -5473,7 +5420,7 @@ PAL_API PalResult PAL_CALL palCmdSetFragmentShadingRate( * @since 2.0 * @sa palBuildWorkGroupInfo */ -PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( +PAL_API void PAL_CALL palCmdDrawMeshTasks( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, @@ -5485,17 +5432,12 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH` must be supported - * and enabled by the device if not, this function will fail and return - * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * and enabled by the device. Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. - * Can be a single struct. * @param[in] drawCount Number of draws to perform. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -5504,7 +5446,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasks( * @since 2.0 * @sa palBuildWorkGroupInfo */ -PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( +PAL_API void PAL_CALL palCmdDrawMeshTasksIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t drawCount); @@ -5515,18 +5457,13 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT` must be - * supported and enabled by the device if not, this function will fail and return - * `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * supported and enabled by the device. Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDispatchIndirectData structs. - * Can be a single struct. * @param[in] countBuffer Buffer containing a single `uint32_t` specifying the number of draws. * @param[in] maxDrawCount Maximum Number of draws to perform. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -5535,7 +5472,7 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirect( * @since 2.0 * @sa palBuildWorkGroupInfo */ -PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( +PAL_API void PAL_CALL palCmdDrawMeshTasksIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -5546,21 +5483,17 @@ PAL_API PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] info Pointer to a PalAccelerationStructureBuildInfo struct that specifies parameters. - * Must not be `nullptr`. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdBuildAccelerationStructure( +PAL_API void PAL_CALL palCmdBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info); @@ -5573,14 +5506,11 @@ PAL_API PalResult PAL_CALL palCmdBuildAccelerationStructure( * @param[in] info Pointer to a PalRenderingInfo struct that specifies parameters. * Must not be `nullptr`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdBeginRendering( +PAL_API void PAL_CALL palCmdBeginRendering( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info); @@ -5591,14 +5521,11 @@ PAL_API PalResult PAL_CALL palCmdBeginRendering( * * @param[in] cmdBuffer Command buffer being recorded. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); +PAL_API void PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); /** * @brief Copy data from one buffer to the other. @@ -5614,14 +5541,11 @@ PAL_API PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); * Pointer to a PalImageCreateInfo struct that specifies parameters. * Must not be `nullptr`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdCopyBuffer( +PAL_API void PAL_CALL palCmdCopyBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -5638,14 +5562,11 @@ PAL_API PalResult PAL_CALL palCmdCopyBuffer( * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * Must not be `nullptr`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdCopyBufferToImage( +PAL_API void PAL_CALL palCmdCopyBufferToImage( PalCommandBuffer* cmdBuffer, PalImage* dstImage, PalBuffer* srcBuffer, @@ -5662,14 +5583,11 @@ PAL_API PalResult PAL_CALL palCmdCopyBufferToImage( * @param[in] copyInfo Pointer to a PalImageCopyInfo struct that specifies parameters. * Must not be `nullptr`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdCopyImage( +PAL_API void PAL_CALL palCmdCopyImage( PalCommandBuffer* cmdBuffer, PalImage* dst, PalImage* src, @@ -5686,14 +5604,11 @@ PAL_API PalResult PAL_CALL palCmdCopyImage( * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * Must not be `nullptr`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( +PAL_API void PAL_CALL palCmdCopyImageToBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, @@ -5708,14 +5623,11 @@ PAL_API PalResult PAL_CALL palCmdCopyImageToBuffer( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] pipeline Pipeline to bind. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdBindPipeline( +PAL_API void PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline); @@ -5729,14 +5641,11 @@ PAL_API PalResult PAL_CALL palCmdBindPipeline( * @param[in] count Capacity of the PalViewport array. * @param[in] viewports Pointer to an array of viewports. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdSetViewport( +PAL_API void PAL_CALL palCmdSetViewport( PalCommandBuffer* cmdBuffer, uint32_t count, PalViewport* viewports); @@ -5751,14 +5660,11 @@ PAL_API PalResult PAL_CALL palCmdSetViewport( * @param[in] count Capacity of the PalRect2D array. * @param[in] scissors Pointer to an array of scissors. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdSetScissors( +PAL_API void PAL_CALL palCmdSetScissors( PalCommandBuffer* cmdBuffer, uint32_t count, PalRect2D* scissors); @@ -5773,17 +5679,14 @@ PAL_API PalResult PAL_CALL palCmdSetScissors( * @param[in] count Number of vertex buffers to bind. * @param[in] buffers Pointer to an array of vertex buffers. * @param[in] offsets Pointer to an array of offsets in bytes into each vertex buffer. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( +PAL_API void PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, uint32_t firstSlot, uint32_t count, @@ -5800,16 +5703,13 @@ PAL_API PalResult PAL_CALL palCmdBindVertexBuffers( * @param[in] offset Offset in bytes into the index buffer. * @param[in] type Type of indices stored in the index buffer. (eg. `PAL_INDEX_TYPE_UINT32`). * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( +PAL_API void PAL_CALL palCmdBindIndexBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint64_t offset, @@ -5826,9 +5726,6 @@ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( * @param[in] firstVertex Index of the first vertex to draw. * @param[in] firstInstance Index of the first instance to draw. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -5836,7 +5733,7 @@ PAL_API PalResult PAL_CALL palCmdBindIndexBuffer( * @since 2.0 * @sa palDrawIndexed */ -PAL_API PalResult PAL_CALL palCmdDraw( +PAL_API void PAL_CALL palCmdDraw( PalCommandBuffer* cmdBuffer, uint32_t vertexCount, uint32_t instanceCount, @@ -5848,17 +5745,14 @@ PAL_API PalResult PAL_CALL palCmdDraw( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. * Can be a single struct. * @param[in] count Number of draws to perform. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -5867,7 +5761,7 @@ PAL_API PalResult PAL_CALL palCmdDraw( * @since 2.0 * @sa palDrawIndexedIndirect */ -PAL_API PalResult PAL_CALL palCmdDrawIndirect( +PAL_API void PAL_CALL palCmdDrawIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count); @@ -5877,18 +5771,14 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirect( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device if not, - * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDrawIndirectData structs. - * Can be a single struct. * @param[in] countBuffer Buffer containing a single `uint32_t` specifying the number of draws. * @param[in] maxDrawCount Maximum Number of draws to perform. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -5897,7 +5787,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirect( * @since 2.0 * @sa palCmdDrawIndexedIndirectCount */ -PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( +PAL_API void PAL_CALL palCmdDrawIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -5915,17 +5805,14 @@ PAL_API PalResult PAL_CALL palCmdDrawIndirectCount( * @param[in] vertexOffset Added offset to vertex indices. * @param[in] firstInstance Index of the first instance to draw. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. * * @since 2.0 - * @sa palDraw + * @sa palCmdDraw */ -PAL_API PalResult PAL_CALL palCmdDrawIndexed( +PAL_API void PAL_CALL palCmdDrawIndexed( PalCommandBuffer* cmdBuffer, uint32_t indexCount, uint32_t instanceCount, @@ -5938,26 +5825,22 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexed( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. - * Can be a single struct. * @param[in] count Number of draws to perform. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. * @note The buffer must be created with `PAL_BUFFER_USAGE_INDIRECT` usage. * * @since 2.0 - * @sa palDrawIndirect + * @sa palCmdDrawIndirect */ -PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( +PAL_API void PAL_CALL palCmdDrawIndexedIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count); @@ -5967,18 +5850,14 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device if not, - * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing an array of PalDrawIndexedIndirectData structs. - * Can be a single struct. * @param[in] countBuffer Buffer containing a single `uint32_t` specifying the number of draws. * @param[in] maxDrawCount Maximum Number of draws to perform. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -5987,7 +5866,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirect( * @since 2.0 * @sa palCmdDrawIndirectCount */ -PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( +PAL_API void PAL_CALL palCmdDrawIndexedIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -5996,8 +5875,8 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( /** * @brief Transition an acceleration structure from one usage state to another. * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, - * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * The graphics system must be initialized before this call. This function defines a * dependency between `oldUsageState` and `newUsageState`. It ensures that all @@ -6026,9 +5905,6 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * @param[in] oldUsageState The old usage state. * @param[in] newUsageState The new usage state. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -6037,7 +5913,7 @@ PAL_API PalResult PAL_CALL palCmdDrawIndexedIndirectCount( * @sa palCmdImageBarrier * @sa palCmdBufferBarrier */ -PAL_API PalResult PAL_CALL palCmdAccelerationStructureBarrier( +PAL_API void PAL_CALL palCmdAccelerationStructureBarrier( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, PalUsageState oldUsageState, @@ -6070,16 +5946,13 @@ PAL_API PalResult PAL_CALL palCmdAccelerationStructureBarrier( * @param[in] oldUsageStateInfo The old usage state. * @param[in] newUsageStateInfo The new usage state. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 * @sa palCmdAccelerationStructureBarrier * @sa palCmdBufferBarrier */ -PAL_API PalResult PAL_CALL palCmdImageBarrier( +PAL_API void PAL_CALL palCmdImageBarrier( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, @@ -6111,16 +5984,13 @@ PAL_API PalResult PAL_CALL palCmdImageBarrier( * @param[in] oldUsageStateInfo The old usage state. * @param[in] newUsageStateInfo The new usage state. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 * @sa palCmdAccelerationStructureBarrier * @sa palCmdImageBarrier */ -PAL_API PalResult PAL_CALL palCmdBufferBarrier( +PAL_API void PAL_CALL palCmdBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageState oldUsageState, @@ -6136,9 +6006,6 @@ PAL_API PalResult PAL_CALL palCmdBufferBarrier( * @param[in] groupCountY Number of compute shader groups to dispatch on the y axis. * @param[in] groupCountZ Number of compute shader groups to dispatch on the z axis. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -6146,7 +6013,7 @@ PAL_API PalResult PAL_CALL palCmdBufferBarrier( * @since 2.0 * @sa palBuildWorkGroupInfo */ -PAL_API PalResult PAL_CALL palCmdDispatch( +PAL_API void PAL_CALL palCmdDispatch( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, @@ -6157,8 +6024,8 @@ PAL_API PalResult PAL_CALL palCmdDispatch( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_DISPATCH_BASE` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_DISPATCH_BASE` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] baseGroupX Base group offset on the x axis. @@ -6168,9 +6035,6 @@ PAL_API PalResult PAL_CALL palCmdDispatch( * @param[in] groupCountY Number of compute shader groups to dispatch on the y axis. * @param[in] groupCountZ Number of compute shader groups to dispatch on the z axis. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -6178,7 +6042,7 @@ PAL_API PalResult PAL_CALL palCmdDispatch( * @since 2.0 * @sa palBuildWorkGroupInfo */ -PAL_API PalResult PAL_CALL palCmdDispatchBase( +PAL_API void PAL_CALL palCmdDispatchBase( PalCommandBuffer* cmdBuffer, uint32_t baseGroupX, uint32_t baseGroupY, @@ -6192,15 +6056,12 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be `nullptr`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -6209,7 +6070,7 @@ PAL_API PalResult PAL_CALL palCmdDispatchBase( * @since 2.0 * @sa palBuildWorkGroupInfo */ -PAL_API PalResult PAL_CALL palCmdDispatchIndirect( +PAL_API void PAL_CALL palCmdDispatchIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer); @@ -6218,8 +6079,8 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, - * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] sbt The shader binding table to use. @@ -6228,16 +6089,13 @@ PAL_API PalResult PAL_CALL palCmdDispatchIndirect( * @param[in] height Number of rays to trace on the y axis. * @param[in] depth Number of rays to trace on the z axis. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdTraceRays( +PAL_API void PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, uint32_t raygenIndex, @@ -6250,20 +6108,17 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING` must be supported and enabled by the device if not, - * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] raygenIndex Index of the raygen shader to execute. * @param[in] sbt The shader binding table to use. * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be `nullptr`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @note The argument buffer memory must not be `PAL_MEMORY_TYPE_GPU_ONLY`. The implementation + * @note The argument buffer memory must not be `PAL_MEMORY_TYPE_CPU_UPLOAD`. The implementation * internally copies the data into a GPU buffer for execution. * * @note A pipeline must be bound before this call. @@ -6271,7 +6126,7 @@ PAL_API PalResult PAL_CALL palCmdTraceRays( * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( +PAL_API void PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, uint32_t raygenIndex, PalShaderBindingTable* sbt, @@ -6286,16 +6141,13 @@ PAL_API PalResult PAL_CALL palCmdTraceRaysIndirect( * @param[in] setIndex Index of the descriptor set to bind. * @param[in] set Descriptor set to bind. Must be compatible with `layout`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( +PAL_API void PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, uint32_t setIndex, PalDescriptorSet* set); @@ -6310,16 +6162,13 @@ PAL_API PalResult PAL_CALL palCmdBindDescriptorSet( * @param[in] size Size of `value` in bytes. * @param[in] value Pointer to the push constant range data to write. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdPushConstants( +PAL_API void PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, uint32_t offset, uint32_t size, @@ -6330,20 +6179,17 @@ PAL_API PalResult PAL_CALL palCmdPushConstants( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE` must be supported and enabled by the device if not, - * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] cullMode Cull mode to set. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdSetCullMode( +PAL_API void PAL_CALL palCmdSetCullMode( PalCommandBuffer* cmdBuffer, PalCullMode cullMode); @@ -6352,20 +6198,17 @@ PAL_API PalResult PAL_CALL palCmdSetCullMode( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE` must be supported and enabled by the device if not, - * this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] frontFace Front face to set. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdSetFrontFace( +PAL_API void PAL_CALL palCmdSetFrontFace( PalCommandBuffer* cmdBuffer, PalFrontFace frontFace); @@ -6374,20 +6217,17 @@ PAL_API PalResult PAL_CALL palCmdSetFrontFace( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY` must be supported and enabled by the device - * if not, this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY` must be supported and enabled by the device. +* Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] topology Topology to set. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdSetPrimitiveTopology( +PAL_API void PAL_CALL palCmdSetPrimitiveTopology( PalCommandBuffer* cmdBuffer, PalPrimitiveTopology topology); @@ -6396,20 +6236,17 @@ PAL_API PalResult PAL_CALL palCmdSetPrimitiveTopology( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE` must be supported and enabled by the device - * if not, this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE` must be supported and enabled by the device. +* Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] enable True to enable. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdSetDepthTestEnable( +PAL_API void PAL_CALL palCmdSetDepthTestEnable( PalCommandBuffer* cmdBuffer, PalBool enable); @@ -6418,20 +6255,17 @@ PAL_API PalResult PAL_CALL palCmdSetDepthTestEnable( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE` must be supported and enabled by the device - * if not, this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] enable True to enable. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdSetDepthWriteEnable( +PAL_API void PAL_CALL palCmdSetDepthWriteEnable( PalCommandBuffer* cmdBuffer, PalBool enable); @@ -6440,8 +6274,7 @@ PAL_API PalResult PAL_CALL palCmdSetDepthWriteEnable( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP` must be supported and enabled by the device - * if not, this function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP` must be supported and enabled by the device. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] faceMask Bitmask specifying faces to apply the stencil to. @@ -6450,14 +6283,11 @@ PAL_API PalResult PAL_CALL palCmdSetDepthWriteEnable( * @param[in] depthFailOp Stencil operation to perform when stencil passes but depth fails. * @param[in] compareOp Compare operation for stencil tests. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palCmdSetStencilOp( +PAL_API void PAL_CALL palCmdSetStencilOp( PalCommandBuffer* cmdBuffer, PalStencilFaceFlags faceMask, PalStencilOp failOp, @@ -6470,23 +6300,19 @@ PAL_API PalResult PAL_CALL palCmdSetStencilOp( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] device Device that creates the acceleration structure. - * @param[in] info Pointer to a PalAccelerationStructureCreateInfo struct that specifies parameters. - * Must not be `nullptr`. + * @param[in] info Pointer to a PalAccelerationStructureCreateInfo struct that specifies parameters * @param[out] outAs Pointer to a PalAccelerationStructure to recieve the created acceleration * structure. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `device` is externally synchronized. * - * @note The memory associated with PalAccelerationStructureCreateInfo::buffer must be - * `PAL_MEMORY_TYPE_GPU_ONLY`. - * * @since 2.0 * @sa palDestroyAccelerationstructure */ @@ -6519,22 +6345,18 @@ PAL_API void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* * PalAccelerationStructureBuildInfo::dst, PalAccelerationStructureBuildInfo::scratchBufferAddress * and PalAccelerationStructureBuildInfo::src must be set to `nullptr`. * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] device Device to query. * @param[in] info Pointer to a PalAccelerationStructureBuildInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] size Pointer to a PalAccelerationStructureBuildSize to recieve the build size. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( +PAL_API void PAL_CALL palGetAccelerationStructureBuildSize( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size); @@ -6544,8 +6366,8 @@ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS` must be supported and enabled by the device if - * `PAL_BUFFER_USAGE_DEVICE_ADDRESS` will be used. + * `PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS` must be supported and enabled by the devic. + * Otherwise behavior is undefined. * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if * `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE` or `PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH` @@ -6556,7 +6378,6 @@ PAL_API PalResult PAL_CALL palGetAccelerationStructureBuildSize( * * @param[in] device Device that creates the buffer. * @param[in] info Pointer to a PalBufferCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outBuffer Pointer to a PalBuffer to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6597,132 +6418,96 @@ PAL_API void PAL_CALL palDestroyBuffer(PalBuffer* buffer); * @param[in] buffer Buffer to query memory requirements on. * @param[out] requirements Pointer to a PalMemoryRequirements to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `requirements` is per thread. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palGetBufferMemoryRequirements( +PAL_API void PAL_CALL palGetBufferMemoryRequirements( PalBuffer* buffer, PalMemoryRequirements* requirements); /** - * @brief Compute size and alignment requirements for an instance buffer. + * @brief Compute size for an acceleration structure instance buffer. * * The graphics system must be initialized before this call. This does not allocate memory - * for the buffer. - * - * `outSize` must be the size that is used to create the instance buffer. It will be - * computed with regards to the provided `instanceCount`. This function must be used and required - * for all instance buffers. This is used with acceleration - * structure (`TLAS`). + * for the buffer. This function must is required for all acceleration structure instance buffers. * - * @param[in] device Device to compute instance buffer requirements with. * @param[in] instanceCount Number of instances the instance buffer will hold. * @param[out] outSize Pointer to a uint64_t to recieve the required size. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe. * * @since 2.0 + * @sa palWriteInstanceStaging */ -PAL_API PalResult PAL_CALL palComputeInstanceBufferRequirements( - PalDevice* device, - uint32_t instanceCount, +PAL_API void PAL_CALL palComputeInstanceStagingSize( + uint32_t instanceCount, uint64_t* outSize); /** - * @brief Compute size and alignment requirements for an image copy staging buffer. + * @brief Compute requirements for an image staging buffer. * * The graphics system must be initialized before this call. This does not allocate memory - * for the buffer. - * - * `outSize` must be the size that is used to create the image copy staging buffer. It will be - * computed with regards to the provided `imageFormat` and `copyInfo`. This function must be - * used and required for all image copy staging buffers. This is used with image copy commands. - * - * PalBufferImageCopyInfo::bufferRowLength and PalBufferImageCopyInfo::bufferImageHeight are hints. - * The driver might used it defaults if the requested is not supported. Check `outBufferRowLength` - * and `outBufferImageHeight` to see the values the driver used. Set the new values to - * `copyInfo` before writing to the buffer with `palWriteToImageCopyStagingBuffer()`. + * for the buffer. This function is required for all image copy staging buffers. + * + * `PalBufferImageCopyInfo::bufferRowLength` and `PalBufferImageCopyInfo::bufferImageHeight` + * are hints. The driver might used it defaults if the requested is not supported. After this call, + * set those values to the required ones from `outRequirements`. + * If the driver supports the proivded, the values will be the same. * - * @param[in] device Device to compute image copy staging buffer requirements with. * @param[in] imageFormat Destination image format. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. - * Must not be `nullptr`. - * @param[out] outBufferRowLength Pointer to a uint32_t to recieve the required buffer row length. - * @param[out] outBufferImageHeight Pointer to a uint32_t to recieve the required buffer imag - * height. - * @param[out] outSize Pointer to a uint64_t to recieve the required size. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. + * @param[out] outRequirements Pointer to a PalImageStagingRequirements to recieve the requirements * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe. * * @since 2.0 + * @sa palWriteImageStaging */ -PAL_API PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( - PalDevice* device, +PAL_API void PAL_CALL palComputeImageStagingRequirements( PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize); + const PalBufferImageCopyInfo* copyInfo, + PalImageStagingRequirements* outRequirements); /** - * @brief Update or write data to an instance buffer. + * @brief Write data to an instance staging buffer. * * The graphics system must be initialized before this call. * - * @param[in] device The device. Must match the one used to create the instance buffer. - * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. + * @param[in] instanceCount Number of instances. * @param[in] instances Array of PalAccelerationStructureInstance struct to write. - * Can be a single struct. - * @param[in] instanceCount Number of instances in `instances`. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. + * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe. * * @since 2.0 + * @sa palComputeInstanceStagingSize */ -PAL_API PalResult PAL_CALL palWriteToInstanceBuffer( - PalDevice* device, - void* ptr, +PAL_API void PAL_CALL palWriteInstanceStaging( + uint32_t instanceCount, PalAccelerationStructureInstance* instances, - uint32_t instanceCount); + void* ptr); /** - * @brief Update or write data to an image copy staging buffer. + * @brief Write data to an image staging buffer. * * The graphics system must be initialized before this call. * - * @param[in] device The device. Must match the one used to create the image copy staging buffer. - * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. - * @param[out] srcData Pointer to the CPU visible memory with the data. * @param[in] imageFormat Destination image format. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. - * Must not be `nullptr`. - * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. + * @param[out] srcData Pointer to the CPU visible memory with the data. + * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. * - * Thread safety: Thread safe if `device` is externally synchronized. + * Thread safety: Thread safe. * * @since 2.0 + * @sa palComputeImageStagingRequirements */ -PAL_API PalResult PAL_CALL palWriteToImageCopyStagingBuffer( - PalDevice* device, - void* ptr, - void* srcData, +PAL_API void PAL_CALL palWriteToImageCopyStagingBuffer( PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo); + PalBufferImageCopyInfo* copyInfo, + void* srcData, + void* ptr); /** * @brief Bind an allocated memory to a buffer. @@ -6948,8 +6733,7 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( * The graphics system must be initialized before this call. * * If the write info has no valid resource handle, then `PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS` - * must be supported and enabled when creating the device if not, this function will fail and - * return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * must be supported and enabled when creating the device. Otherwise behavior is undefined. * * @param[in] device The Device. Must match the one used to allocate descriptor set. * @param[in] count Capacity of the PalDescriptorSetWriteInfo array. @@ -7061,12 +6845,11 @@ PAL_API PalResult PAL_CALL palCreateComputePipeline( * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] device Device that creates the ray tracing pipeline. * @param[in] info Pointer to a PalRayTracingPipelineCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -7108,15 +6891,14 @@ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); * * The graphics system must be initialized before this call. * - * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device if not, this - * function will fail and return `PAL_RESULT_ADAPTER_FEATURE_NOT_SUPPORTED`. + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * PalShaderBindingTableCreateInfo::recordCount must match the shader group count of * PalShaderBindingTableCreateInfo::rayTracingPipeline. * * @param[in] device Device that creates the shader binding table. * @param[in] info Pointer to a PalShaderBindingTableCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outSbt Pointer to a PalShaderBindingTable to recieve the created shader binding * table. * @@ -7165,14 +6947,11 @@ PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); * @param[in] count Capacity of the PalShaderBindingTableRecordInfo array. * @param[in] infos Array of PalShaderBindingTableRecordInfo to update. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread safe if `sbt` is externally synchronized. * * @since 2.0 */ -PAL_API PalResult PAL_CALL palUpdateShaderBindingTable( +PAL_API void PAL_CALL palUpdateShaderBindingTable( PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos); diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 600b594d..3119aabe 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -680,7 +680,7 @@ PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures(); * @sa palGetPrimaryMonitor */ PAL_API PalResult PAL_CALL palEnumerateMonitors( - int32_t* count, + uint32_t* count, PalMonitor** outMonitors); /** @@ -753,7 +753,7 @@ PAL_API PalResult PAL_CALL palGetMonitorInfo( */ PAL_API PalResult PAL_CALL palEnumerateMonitorModes( PalMonitor* monitor, - int32_t* count, + uint32_t* count, PalMonitorMode* modes); /** diff --git a/src/graphics/d3d12/pal_adapter_d3d12.c b/src/graphics/d3d12/pal_adapter_d3d12.c index 42e0c6ab..cb1ce560 100644 --- a/src/graphics/d3d12/pal_adapter_d3d12.c +++ b/src/graphics/d3d12/pal_adapter_d3d12.c @@ -122,10 +122,11 @@ PalResult PAL_CALL enumerateAdaptersD3D12( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getAdapterInfoD3D12( +void PAL_CALL getAdapterInfoD3D12( PalAdapter* adapter, PalAdapterInfo* info) { + HRESULT result = 0; AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; DXGI_ADAPTER_DESC3 desc; D3D12_FEATURE_DATA_ARCHITECTURE1 arch = {0}; @@ -133,11 +134,7 @@ PalResult PAL_CALL getAdapterInfoD3D12( D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; - - HRESULT result = d3d12Adapter->handle->lpVtbl->GetDesc3(d3d12Adapter->handle, &desc); - if (FAILED(result)) { - return makeResultD3D12(result); - } + d3d12Adapter->handle->lpVtbl->GetDesc3(d3d12Adapter->handle, &desc); result = device->lpVtbl->CheckFeatureSupport( device, @@ -166,7 +163,7 @@ PalResult PAL_CALL getAdapterInfoD3D12( nullptr, nullptr); - result = device->lpVtbl->CheckFeatureSupport( + device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_ARCHITECTURE1, &arch, @@ -189,19 +186,13 @@ PalResult PAL_CALL getAdapterInfoD3D12( } else if (desc.DedicatedVideoMemory == 0 && desc.DedicatedSystemMemory > 0) { info->vram = desc.DedicatedSystemMemory; } - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getAdapterCapabilitiesD3D12( +void PAL_CALL getAdapterCapabilitiesD3D12( PalAdapter* adapter, PalAdapterCapabilities* caps) { AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; - if (!d3d12Adapter->handle) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - PalViewportCapabilities* viewportCaps = &caps->viewportCaps; PalImageCapabilities* imageCaps = &caps->imageCaps; PalResourceCapabilities* resourceCaps = &caps->resourceCaps; @@ -260,8 +251,6 @@ PalResult PAL_CALL getAdapterCapabilitiesD3D12( computeCaps->maxWorkGroupSize[0] = D3D12_CS_THREAD_GROUP_MAX_X; computeCaps->maxWorkGroupSize[1] = D3D12_CS_THREAD_GROUP_MAX_Y; computeCaps->maxWorkGroupSize[2] = D3D12_CS_THREAD_GROUP_MAX_Z; - - return PAL_RESULT_SUCCESS; } PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) @@ -476,13 +465,12 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( return 0; } -PalResult PAL_CALL enumerateFormatsD3D12( +void PAL_CALL enumerateFormatsD3D12( PalAdapter* adapter, int32_t* count, PalFormatInfo* outFormats) { int32_t fmtCount = 0; - HRESULT result; AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; ID3D12Device* device = d3d12Adapter->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; @@ -494,41 +482,37 @@ PalResult PAL_CALL enumerateFormatsD3D12( } support.Format = fmt; - result = device->lpVtbl->CheckFeatureSupport( + device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support)); + + if (support.Support1 == 0 && support.Support2 == 0) { + // format not supported + continue; + } - if (SUCCEEDED(result)) { - if (support.Support1 == 0 && support.Support2 == 0) { - // format not supported - continue; + if (outFormats) { + if (fmtCount < *count) { + PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; + fmtInfo->format = (PalFormat)i; + fmtInfo->usages = ImageUsageFromD3D12(support.Support1); } - if (outFormats) { - if (fmtCount < *count) { - PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; - fmtInfo->format = (PalFormat)i; - fmtInfo->usages = ImageUsageFromD3D12(support.Support1); - } - - } else { - fmtCount++; - } + } else { + fmtCount++; } } if (!outFormats) { *count = fmtCount; } - return PAL_RESULT_SUCCESS; } PalBool PAL_CALL isFormatSupportedD3D12( PalAdapter* adapter, PalFormat format) { - HRESULT result; AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; ID3D12Device* device = d3d12Adapter->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; @@ -539,13 +523,13 @@ PalBool PAL_CALL isFormatSupportedD3D12( } support.Format = fmt; - result = device->lpVtbl->CheckFeatureSupport( + device->lpVtbl->CheckFeatureSupport( device, D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support)); - if (FAILED(result) || (support.Support1 == 0 && support.Support2 == 0)) { + if (support.Support1 == 0 && support.Support2 == 0) { return PAL_FALSE; } diff --git a/src/graphics/d3d12/pal_as_d3d12.c b/src/graphics/d3d12/pal_as_d3d12.c index 562216cd..e6431cf4 100644 --- a/src/graphics/d3d12/pal_as_d3d12.c +++ b/src/graphics/d3d12/pal_as_d3d12.c @@ -43,16 +43,12 @@ void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as) palFree(s_D3D12.allocator, d3dAs); } -PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( +void PAL_CALL getAccelerationStructureBuildSizeD3D12( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO sizeInfo = {0}; @@ -64,7 +60,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( 0); if (!geometries) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; + return; } memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count); @@ -89,7 +85,6 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12( size->accelerationStructureSize = sizeInfo.ResultDataMaxSizeInBytes; size->scratchBufferSize = sizeInfo.ScratchDataSizeInBytes; size->updateScratchBufferSize = sizeInfo.UpdateScratchDataSizeInBytes; - return PAL_RESULT_SUCCESS; } #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index 95565aaa..674b0b5b 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -13,8 +13,8 @@ // clang-format off typedef struct { PalResult (PAL_CALL *enumerateAdapters)(int32_t*, PalAdapter**); - PalResult (PAL_CALL *getAdapterInfo)(PalAdapter*, PalAdapterInfo*); - PalResult (PAL_CALL *getAdapterCapabilities)(PalAdapter*, PalAdapterCapabilities*); + void (PAL_CALL *getAdapterInfo)(PalAdapter*, PalAdapterInfo*); + void (PAL_CALL *getAdapterCapabilities)(PalAdapter*, PalAdapterCapabilities*); PalAdapterFeatures (PAL_CALL *getAdapterFeatures)(PalAdapter*); uint32_t (PAL_CALL *getHighestSupportedShaderTarget)(PalAdapter*, PalShaderFormats); PalResult (PAL_CALL *createDevice)(PalAdapter*, PalAdapterFeatures, PalDevice**); @@ -34,7 +34,7 @@ typedef struct { void (PAL_CALL *destroyQueue)(PalQueue*); PalBool (PAL_CALL *canQueuePresent)(PalQueue*, PalSurface*); PalResult (PAL_CALL *waitQueue)(PalQueue*); - PalResult (PAL_CALL *enumerateFormats)(PalAdapter*, int32_t*, PalFormatInfo*); + void (PAL_CALL *enumerateFormats)(PalAdapter*, int32_t*, PalFormatInfo*); PalBool (PAL_CALL *isFormatSupported)(PalAdapter*, PalFormat); PalImageUsages (PAL_CALL *queryFormatImageUsages)(PalAdapter*, PalFormat); PalSampleCount (PAL_CALL *queryFormatSampleCount)(PalAdapter*, PalFormat); @@ -122,7 +122,7 @@ typedef struct { PalResult (PAL_CALL *createAccelerationstructure)(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); void (PAL_CALL *destroyAccelerationstructure)(PalAccelerationStructure*); - PalResult (PAL_CALL *getAccelerationStructureBuildSize)(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); + void (PAL_CALL *getAccelerationStructureBuildSize)(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); PalResult (PAL_CALL *createBuffer)(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); void (PAL_CALL *destroyBuffer)(PalBuffer*); PalResult (PAL_CALL *getBufferMemoryRequirements)(PalBuffer*, PalMemoryRequirements*); @@ -162,8 +162,8 @@ typedef struct { PalResult PAL_CALL initGraphicsVk(const PalGraphicsDebugger*, const PalAllocator*); void PAL_CALL shutdownGraphicsVk(); PalResult PAL_CALL enumerateAdaptersVk(int32_t*, PalAdapter**); -PalResult PAL_CALL getAdapterInfoVk(PalAdapter*, PalAdapterInfo*); -PalResult PAL_CALL getAdapterCapabilitiesVk(PalAdapter*, PalAdapterCapabilities*); +void PAL_CALL getAdapterInfoVk(PalAdapter*, PalAdapterInfo*); +void PAL_CALL getAdapterCapabilitiesVk(PalAdapter*, PalAdapterCapabilities*); PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter*); uint32_t PAL_CALL getHighestSupportedShaderTargetVk(PalAdapter*, PalShaderFormats); PalResult PAL_CALL createDeviceVk(PalAdapter*, PalAdapterFeatures, PalDevice**); @@ -184,7 +184,7 @@ PalResult PAL_CALL createQueueVk(PalDevice*, PalQueueType, PalQueue**); void PAL_CALL destroyQueueVk(PalQueue*); PalResult PAL_CALL waitQueueVk(PalQueue*); PalBool PAL_CALL canQueuePresentVk(PalQueue*, PalSurface*); -PalResult PAL_CALL enumerateFormatsVk(PalAdapter*, int32_t*, PalFormatInfo*); +void PAL_CALL enumerateFormatsVk(PalAdapter*, int32_t*, PalFormatInfo*); PalBool PAL_CALL isFormatSupportedVk(PalAdapter*, PalFormat); PalImageUsages PAL_CALL queryFormatImageUsagesVk(PalAdapter*, PalFormat); PalSampleCount PAL_CALL queryFormatSampleCountVk(PalAdapter*, PalFormat); @@ -469,7 +469,7 @@ PalResult PAL_CALL createQueueD3D12(PalDevice*, PalQueueType, PalQueue**); void PAL_CALL destroyQueueD3D12(PalQueue*); PalResult PAL_CALL waitQueueD3D12(PalQueue*); PalBool PAL_CALL canQueuePresentD3D12(PalQueue*, PalSurface*); -PalResult PAL_CALL enumerateFormatsD3D12(PalAdapter*, int32_t*, PalFormatInfo*); +void PAL_CALL enumerateFormatsD3D12(PalAdapter*, int32_t*, PalFormatInfo*); PalBool PAL_CALL isFormatSupportedD3D12(PalAdapter*, PalFormat); PalImageUsages PAL_CALL queryFormatImageUsagesD3D12(PalAdapter*, PalFormat); PalSampleCount PAL_CALL queryFormatSampleCountD3D12(PalAdapter*, PalFormat); diff --git a/src/graphics/vulkan/pal_adapter_vulkan.c b/src/graphics/vulkan/pal_adapter_vulkan.c index f0470d1a..8ddc8754 100644 --- a/src/graphics/vulkan/pal_adapter_vulkan.c +++ b/src/graphics/vulkan/pal_adapter_vulkan.c @@ -147,7 +147,7 @@ PalResult PAL_CALL enumerateAdaptersVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getAdapterInfoVk( +void PAL_CALL getAdapterInfoVk( PalAdapter* adapter, PalAdapterInfo* info) { @@ -203,15 +203,12 @@ PalResult PAL_CALL getAdapterInfoVk( break; } } - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getAdapterCapabilitiesVk( +void PAL_CALL getAdapterCapabilitiesVk( PalAdapter* adapter, PalAdapterCapabilities* caps) { - VkResult result = VK_SUCCESS; AdapterVk* vkAdapter = (AdapterVk*)adapter; VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; @@ -323,7 +320,6 @@ PalResult PAL_CALL getAdapterCapabilitiesVk( computeCaps->maxWorkGroupSize[2] = limits->maxComputeWorkGroupSize[2]; palFree(s_Vk.allocator, queueProps); - return PAL_RESULT_SUCCESS; } PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) @@ -713,7 +709,7 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetVk( return 0; } -PalResult PAL_CALL enumerateFormatsVk( +void PAL_CALL enumerateFormatsVk( PalAdapter* adapter, int32_t* count, PalFormatInfo* outFormats) @@ -743,7 +739,6 @@ PalResult PAL_CALL enumerateFormatsVk( if (!outFormats) { *count = fmtCount; } - return PAL_RESULT_SUCCESS; } PalBool PAL_CALL isFormatSupportedVk( diff --git a/src/graphics/vulkan/pal_as_vulkan.c b/src/graphics/vulkan/pal_as_vulkan.c index 35e90831..a03c2b39 100644 --- a/src/graphics/vulkan/pal_as_vulkan.c +++ b/src/graphics/vulkan/pal_as_vulkan.c @@ -71,14 +71,14 @@ void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as) palFree(s_Vk.allocator, vkAs); } -PalResult PAL_CALL getAccelerationStructureBuildSizeVk( +void PAL_CALL getAccelerationStructureBuildSizeVk( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { DeviceVk* vkDevice = (DeviceVk*)device; if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + return; } VkAccelerationStructureGeometryKHR* geometries = nullptr; @@ -89,7 +89,7 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( geometries = palAllocate(s_Vk.allocator, geometriesSize, 0); maxPrimities = palAllocate(s_Vk.allocator, sizeof(uint32_t) * info->count, 0); if (!maxPrimities || !geometries) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; + return; } memset(geometries, 0, geometriesSize); @@ -111,7 +111,6 @@ PalResult PAL_CALL getAccelerationStructureBuildSizeVk( palFree(s_Vk.allocator, geometries); palFree(s_Vk.allocator, maxPrimities); - return PAL_RESULT_SUCCESS; } #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_buffer_vulkan.c b/src/graphics/vulkan/pal_buffer_vulkan.c index a783559b..150df15b 100644 --- a/src/graphics/vulkan/pal_buffer_vulkan.c +++ b/src/graphics/vulkan/pal_buffer_vulkan.c @@ -304,7 +304,7 @@ void PAL_CALL destroyBufferVk(PalBuffer* buffer) palFree(s_Vk.allocator, buffer); } -PalResult PAL_CALL getBufferMemoryRequirementsVk( +void PAL_CALL getBufferMemoryRequirementsVk( PalBuffer* buffer, PalMemoryRequirements* requirements) { @@ -329,17 +329,11 @@ PalResult PAL_CALL getBufferMemoryRequirementsVk( if ((memReq.memoryTypeBits & device->memoryClassMask[PAL_MEMORY_TYPE_CPU_READBACK]) != 0) { requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_CPU_READBACK); } - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL computeInstanceBufferRequirementsVk( - PalDevice* device, - uint32_t instanceCount, - uint64_t* outSize) +uint64_t PAL_CALL computeInstanceBufferRequirementsVk(uint32_t instanceCount) { - *outSize = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; - return PAL_RESULT_SUCCESS; + return sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; } PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( diff --git a/src/graphics/vulkan/pal_command_pool_vulkan.c b/src/graphics/vulkan/pal_command_pool_vulkan.c index cc912e93..5416c2bc 100644 --- a/src/graphics/vulkan/pal_command_pool_vulkan.c +++ b/src/graphics/vulkan/pal_command_pool_vulkan.c @@ -49,7 +49,11 @@ void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool) PalResult PAL_CALL resetCommandPoolVk(PalCommandPool* pool) { CommandPoolVk* vkCmdPool = (CommandPoolVk*)pool; - s_Vk.resetCommandPool(vkCmdPool->device->handle, vkCmdPool->handle, 0); + VkResult result = s_Vk.resetCommandPool(vkCmdPool->device->handle, vkCmdPool->handle, 0); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + return PAL_RESULT_SUCCESS; } @@ -157,7 +161,11 @@ void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer) PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); + VkResult result = s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c index a1f8ca9c..171f00a8 100644 --- a/src/graphics/vulkan/pal_commands_vulkan.c +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -1316,7 +1316,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( // we need to make sure the SBT is up to date commitShaderbindingTableUpdate(vkCmdBuffer, vkSbt); - // copy users buffer data into a tmp gpu buffer abd execute with it + // copy user buffer data into a tmp gpu buffer abd execute with it VkBufferCopy copyRegion = {0}; copyRegion.size = sizeof(VkTraceRaysIndirectCommandKHR); s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, vkBuffer->handle, vkCmdBuffer->buffer, 1, ©Region); diff --git a/src/graphics/vulkan/pal_device_vulkan.c b/src/graphics/vulkan/pal_device_vulkan.c index 2587f085..9c1dd3b9 100644 --- a/src/graphics/vulkan/pal_device_vulkan.c +++ b/src/graphics/vulkan/pal_device_vulkan.c @@ -825,7 +825,7 @@ PalResult PAL_CALL allocateMemoryVk( DeviceVk* vkDevice = (DeviceVk*)device; VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.allocationSize = (VkDeviceSize)size; + allocateInfo.allocationSize = size; VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; memory = palAllocate(s_Vk.allocator, sizeof(MemoryVk), 0); diff --git a/src/video/pal_video.c b/src/video/pal_video.c index 1eeffc0c..5447beed 100644 --- a/src/video/pal_video.c +++ b/src/video/pal_video.c @@ -148,7 +148,7 @@ PalVideoFeatures PAL_CALL palGetVideoFeatures() } PalResult PAL_CALL palEnumerateMonitors( - int32_t* count, + uint32_t* count, PalMonitor** outMonitors) { if (!s_Video.initialized) { @@ -192,7 +192,7 @@ PalResult PAL_CALL palGetMonitorInfo( PalResult PAL_CALL palEnumerateMonitorModes( PalMonitor* monitor, - int32_t* count, + uint32_t* count, PalMonitorMode* modes) { if (!s_Video.initialized) { diff --git a/src/video/wayland/pal_monitor_wayland.c b/src/video/wayland/pal_monitor_wayland.c index 2511b33c..9975cd1d 100644 --- a/src/video/wayland/pal_monitor_wayland.c +++ b/src/video/wayland/pal_monitor_wayland.c @@ -9,7 +9,7 @@ #include "pal_wayland.h" PalResult wlEnumerateMonitors( - int32_t* count, + uint32_t* count, PalMonitor** outMonitors) { if (outMonitors) { @@ -61,7 +61,7 @@ PalResult wlGetMonitorInfo( PalResult wlEnumerateMonitorModes( PalMonitor* monitor, - int32_t* count, + uint32_t* count, PalMonitorMode* modes) { MonitorData* monitorData = wlFindMonitorData(monitor); diff --git a/src/video/win32/pal_monitor_win32.c b/src/video/win32/pal_monitor_win32.c index c1cc995f..d4a66b56 100644 --- a/src/video/win32/pal_monitor_win32.c +++ b/src/video/win32/pal_monitor_win32.c @@ -155,7 +155,7 @@ static inline void addMonitorMode( } PalResult win32EnumerateMonitors( - int32_t* count, + uint32_t* count, PalMonitor** outMonitors) { MonitorData data; @@ -247,7 +247,7 @@ PalResult win32GetMonitorInfo( PalResult win32EnumerateMonitorModes( PalMonitor* monitor, - int32_t* count, + uint32_t* count, PalMonitorMode* modes) { int32_t modeCount = 0; diff --git a/src/video/x11/pal_monitor_x11.c b/src/video/x11/pal_monitor_x11.c index f737cbe0..d6e4cdac 100644 --- a/src/video/x11/pal_monitor_x11.c +++ b/src/video/x11/pal_monitor_x11.c @@ -10,7 +10,7 @@ #include PalResult xEnumerateMonitors( - int32_t* count, + uint32_t* count, PalMonitor** outMonitors) { int _count = 0; @@ -145,7 +145,7 @@ PalResult xGetMonitorInfo( PalResult xEnumerateMonitorModes( PalMonitor* monitor, - int32_t* count, + uint32_t* count, PalMonitorMode* modes) { int32_t modeCount = 0; From 253b5b0abcb41f69ecb2f575fd23a50e652fc62c Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 10 Jul 2026 00:10:08 +0000 Subject: [PATCH 325/372] API rework --- CHANGELOG.md | 37 +- include/pal/pal_core.h | 9 +- include/pal/pal_graphics.h | 32 +- include/pal/pal_opengl.h | 3 +- include/pal/pal_system.h | 4 +- include/pal/pal_thread.h | 20 +- include/pal/pal_video.h | 201 +--- src/graphics/pal_graphics.c | 1532 ++++---------------------- src/graphics/pal_graphics_backends.h | 378 +++---- 9 files changed, 518 insertions(+), 1698 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b40685af..9d47817b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,11 +19,8 @@ - `PAL_RESULT_CODE_TIMEOUT` - `PAL_RESULT_CODE_INVALID_HANDLE` - `PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED` - - `PAL_RESULT_CODE_NOT_INITIALIZED` - `PAL_RESULT_CODE_INVALID_OPERATION` - `PAL_RESULT_CODE_DEVICE_LOST` - - `PAL_RESULT_CODE_OUT_OF_DATE` - - `PAL_RESULT_CODE_INVALID_DRIVER` - Added type `PalResultSource` with values: - `PAL_RESULT_SOURCE_NONE` - `PAL_RESULT_SOURCE_WIN32` @@ -62,7 +59,7 @@ - Renamed fbConfig backend type constants from `PAL_FBCONFIG_BACKEND_**` to `PAL_FBCONFIG_BACKEND_**`. - Renamed `PalFlashFlag` to `PalFlashFlags`. - `palInitGL()` now takes two additional parameters. -- `palEnumerateGLFBConfigs()` no longer takes the `glWindow` parameter. +- `palEnumerateGLFBConfigs()` no longer takes the `glWindow` and `count` now as `uint32_t` - `palInitVideo()` now takes an additional parameter. - `palGetMouseDelta()` now takes `dx` and `dy` paramters as `float`. - `palEnumerateMonitors()` now takes `count` paramter as `uint32_t`. @@ -85,6 +82,38 @@ - `PalWindowCreateInfo` now has `state`, `appName`, `instanceName`, `fbConfigBackend` and `fbConfigIndex` fields. - Removed `maximized` and `minimized` in `PalWindowCreateInfo`. +- These function now returns `void` instead of `PalResult`: + - `palGetPlatformInfo()` + - `palGetCPUInfo()` + - `palGetThreadName()` + - `palGetPrimaryMonitor()` + - `palGetMonitorInfo()` + - `palEnumerateMonitorModes()` + - `palMinimizeWindow()` + - `palMaximizeWindow()` + - `palRestoreWindow()` + - `palShowWindow()` + - `palHideWindow()` + - `palGetWindowStyle()` + - `palGetWindowMonitor()` + - `palGetWindowTitle()` + - `palGetWindowPos()` + - `palGetWindowSize()` + - `palGetWindowState()` + - `palGetWindowHandleInfo()` + - `palSetWindowStyle()` + - `palSetWindowTitle()` + - `palSetWindowPos()` + - `palSetWindowSize()` + - `palSetFocusWindow()` + - `palSetWindowIcon()` + - `palClipCursor()` + - `palGetCursorPos()` + - `palSetCursorPos()` + - `palSetWindowCursor()` + - `palSetWindowOpacity()` + - `palFlashWindow()` + diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 0fbc5421..27862974 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -66,12 +66,9 @@ #define PAL_RESULT_CODE_TIMEOUT 4 #define PAL_RESULT_CODE_INVALID_HANDLE 5 #define PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED 6 -#define PAL_RESULT_CODE_NOT_INITIALIZED 7 -#define PAL_RESULT_CODE_INVALID_OPERATION 8 -#define PAL_RESULT_CODE_DEVICE_LOST 9 -#define PAL_RESULT_CODE_OUT_OF_DATE 10 -#define PAL_RESULT_CODE_INVALID_DRIVER 11 -#define PAL_RESULT_CODE_COUNT 12 +#define PAL_RESULT_CODE_INVALID_OPERATION 7 +#define PAL_RESULT_CODE_DEVICE_LOST 8 +#define PAL_RESULT_CODE_COUNT 9 #define PAL_RESULT_SOURCE_NONE 0 #define PAL_RESULT_SOURCE_WIN32 1 diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 1b10016b..6faec99e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -20,8 +20,6 @@ #define PAL_ADAPTER_BACKEND_NAME_SIZE 32 #define PAL_SHADER_ENTRY_NAME_SIZE 32 #define PAL_UNUSED_SHADER_INDEX UINT32_MAX - -#define PAL_BACKEND_KEY ((void*)(uintptr_t)0x50414C48414E4453) #define PAL_MAX_CUSTOM_BACKENDS 16 #define PAL_MAKE_SHADER_TARGET(major, minor) ((uint32_t)((major) << 8) | (minor)) @@ -2699,12 +2697,7 @@ typedef struct { * Uninitialized fields may result in undefined behavior. * * All backend handle implementation (eg. struct CustomBuffer) must reserve its first field as - * a `void*` and set it to `PAL_BACKEND_KEY` at the handles creation function pointer - * (eg. createBufferCustom). This will be validated at the handle creation function - * (eg. palCreateBuffer). - * - * Pal trust thee backend author to not overwrite or use the reserve space. It is used by the - * graphics layer. + * a `void*`. This will be used by the graphics layer. * * @since 2.0 */ @@ -3750,6 +3743,7 @@ typedef struct { * Must obey the rules and semantics documented in palComputeInstanceStagingSize(). */ void(PAL_CALL* computeInstanceStagingSize)( + PalDevice* device, uint32_t instanceCount, uint64_t* outSize); @@ -3759,6 +3753,7 @@ typedef struct { * Must obey the rules and semantics documented in palComputeImageStagingRequirements(). */ void(PAL_CALL* computeImageStagingRequirements)( + PalDevice* device, PalFormat imageFormat, const PalBufferImageCopyInfo* copyInfo, PalImageStagingRequirements* outRequirements); @@ -3769,6 +3764,7 @@ typedef struct { * Must obey the rules and semantics documented in palWriteInstanceStaging(). */ void(PAL_CALL* writeInstanceStaging)( + PalDevice* device, uint32_t instanceCount, PalAccelerationStructureInstance* instances, void* ptr); @@ -3779,6 +3775,7 @@ typedef struct { * Must obey the rules and semantics documented in palWriteImageStaging(). */ void(PAL_CALL* writeImageStaging)( + PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, void* srcData, @@ -4192,7 +4189,6 @@ PAL_API PalResult PAL_CALL palAllocateMemory( * The graphics system must be initialized before this call. * If `memory` is `nullptr`, this function will return silently. * - * @param[in] device Pointer to device to free memory on. * @param[in] memory Pointer to memory to free. * * Thread safety: Thread safe if `device` is externally synchronized and @@ -4201,9 +4197,7 @@ PAL_API PalResult PAL_CALL palAllocateMemory( * @since 2.0 * @sa palAllocateMemory */ -PAL_API void PAL_CALL palFreeMemory( - PalDevice* device, - PalMemory* memory); +PAL_API void PAL_CALL palFreeMemory(PalMemory* memory); /** * @brief Get sampler anisotropy feature capabilites or limits about a device. @@ -6432,6 +6426,7 @@ PAL_API void PAL_CALL palGetBufferMemoryRequirements( * The graphics system must be initialized before this call. This does not allocate memory * for the buffer. This function must is required for all acceleration structure instance buffers. * + * @param[in] device The device to use. * @param[in] instanceCount Number of instances the instance buffer will hold. * @param[out] outSize Pointer to a uint64_t to recieve the required size. * @@ -6441,6 +6436,7 @@ PAL_API void PAL_CALL palGetBufferMemoryRequirements( * @sa palWriteInstanceStaging */ PAL_API void PAL_CALL palComputeInstanceStagingSize( + PalDevice* device, uint32_t instanceCount, uint64_t* outSize); @@ -6455,6 +6451,7 @@ PAL_API void PAL_CALL palComputeInstanceStagingSize( * set those values to the required ones from `outRequirements`. * If the driver supports the proivded, the values will be the same. * + * @param[in] device The device to use. * @param[in] imageFormat Destination image format. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * @param[out] outRequirements Pointer to a PalImageStagingRequirements to recieve the requirements @@ -6465,6 +6462,7 @@ PAL_API void PAL_CALL palComputeInstanceStagingSize( * @sa palWriteImageStaging */ PAL_API void PAL_CALL palComputeImageStagingRequirements( + PalDevice* device, PalFormat imageFormat, const PalBufferImageCopyInfo* copyInfo, PalImageStagingRequirements* outRequirements); @@ -6474,6 +6472,7 @@ PAL_API void PAL_CALL palComputeImageStagingRequirements( * * The graphics system must be initialized before this call. * + * @param[in] device The device to use. * @param[in] instanceCount Number of instances. * @param[in] instances Array of PalAccelerationStructureInstance struct to write. * @param[out] ptr Pointer to the CPU visible memory. Must be mapped. @@ -6484,6 +6483,7 @@ PAL_API void PAL_CALL palComputeImageStagingRequirements( * @sa palComputeInstanceStagingSize */ PAL_API void PAL_CALL palWriteInstanceStaging( + PalDevice* device, uint32_t instanceCount, PalAccelerationStructureInstance* instances, void* ptr); @@ -6493,6 +6493,7 @@ PAL_API void PAL_CALL palWriteInstanceStaging( * * The graphics system must be initialized before this call. * + * @param[in] device The device to use. * @param[in] imageFormat Destination image format. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. * @param[out] srcData Pointer to the CPU visible memory with the data. @@ -6504,6 +6505,7 @@ PAL_API void PAL_CALL palWriteInstanceStaging( * @sa palComputeImageStagingRequirements */ PAL_API void PAL_CALL palWriteToImageCopyStagingBuffer( + PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, void* srcData, @@ -6975,8 +6977,6 @@ PAL_API void PAL_CALL palUpdateShaderBindingTable( * @param[in, out] count Capacity of the PalWorkGroupInfo array. * @param[out] infos Pointer to an Array of PalWorkGroupInfo. * - * @return `PAL_TRUE` on success otherwise `PAL_FALSE`. - * * Thread safety: Must only be called from the main thread. * * @since 2.0 @@ -6986,9 +6986,9 @@ PAL_API void PAL_CALL palUpdateShaderBindingTable( * @sa palCmdDispatch * @sa palCmdDispatchBase */ -PAL_API PalBool PAL_CALL palBuildWorkGroupInfo( +PAL_API void PAL_CALL palBuildWorkGroupInfo( const PalWorkGroupBuildData* data, - int32_t* count, + uint32_t* count, PalWorkGroupInfo* info); /** diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 1cb06154..d79ad264 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -436,8 +436,7 @@ PAL_API PalResult PAL_CALL palSwapBuffers( * * The opengl system must be initialized before this call. * This affects the currently bound context on the calling thread. - * `PAL_GL_EXTENSION_SWAP_CONTROL` must be supported. Set interval to 1 for - * vsync. + * `PAL_GL_EXTENSION_SWAP_CONTROL` must be supported otherwise undefined behavoir. * * @param[in] interval The swap interval * diff --git a/include/pal/pal_system.h b/include/pal/pal_system.h index 89c5e605..596fedfa 100644 --- a/include/pal/pal_system.h +++ b/include/pal/pal_system.h @@ -150,7 +150,7 @@ typedef struct { * * @since 1.0 */ -PAL_API PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info); +PAL_API void PAL_CALL palGetPlatformInfo(PalPlatformInfo* info); /** * @brief Get CPU information. @@ -167,7 +167,7 @@ PAL_API PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info); * * @since 1.0 */ -PAL_API PalResult PAL_CALL palGetCPUInfo( +PAL_API void PAL_CALL palGetCPUInfo( const PalAllocator* allocator, PalCPUInfo* info); diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index 49d94257..efadbb7a 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -234,7 +234,7 @@ PAL_API PalThreadFeatures PAL_CALL palGetThreadFeatures(); /** * @brief Get the priority of the provided thread. * - * `PAL_THREAD_FEATURE_PRIORITY` must be supported. + * `PAL_THREAD_FEATURE_PRIORITY` must be supported otherwise undefined behavior. * * @param[in] thread The thread to query priority for. * @@ -249,8 +249,7 @@ PAL_API PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread); /** * @brief Get the affinity of the provided thread. * - * `PAL_THREAD_FEATURE_AFFINITY` must be supported. Thread affinity is the - * number of CPU cores the thread is allowed to be executed on. + * `PAL_THREAD_FEATURE_AFFINITY` must be supported otherwise undefined behavior. * * @param[in] thread The thread to query affinity for. * @@ -265,13 +264,12 @@ PAL_API uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread); /** * @brief Get the name of the provided thread. * - * `PAL_THREAD_FEATURE_NAME` must be supported. - * fails. Set the buffer to `nullptr` to get the size of the thread name in bytes. + * `PAL_THREAD_FEATURE_NAME` must be supported otherwise undefined behavior. + * Set the buffer to `nullptr` to get the size of the thread name in bytes. * * If the size of the provided buffer is less than the actual size of thread * name, PAL will write upto that limit. * - * * @param[in] thread The thread to query its name. * @param[in] bufferSize Size of the provided buffer in bytes. * @param[out] outSize The actual size of the thread name in bytes. @@ -289,7 +287,7 @@ PAL_API uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread); * @since 1.0 * @sa palSetThreadName */ -PAL_API PalResult PAL_CALL palGetThreadName( +PAL_API void PAL_CALL palGetThreadName( PalThread* thread, uint64_t bufferSize, uint64_t* outSize, @@ -298,7 +296,7 @@ PAL_API PalResult PAL_CALL palGetThreadName( /** * @brief Set the priority of the provided thread. * - * `PAL_THREAD_FEATURE_PRIORITY` must be supported. + * `PAL_THREAD_FEATURE_PRIORITY` must be supported otherwise undefined behavior. * * @param[in] thread The thread to set priority for. * @param[in] priority The new thread priority. @@ -319,9 +317,7 @@ PAL_API PalResult PAL_CALL palSetThreadPriority( /** * @brief Set the affinity of the provided thread. * - * `PAL_THREAD_FEATURE_AFFINITY` must be supported. - * Thread affinity is the number of CPU cores the thread is allowed to be - * executed on. + * `PAL_THREAD_FEATURE_AFFINITY` must be supported otherwise undefined behavior. * * To be safe, get the number of CPU cores and use that to build the CPU mask. * Example: we set a thread to the first and second CPU core. @@ -347,7 +343,7 @@ PAL_API PalResult PAL_CALL palSetThreadAffinity( /** * @brief Set the name of the provided thread. * - * `PAL_THREAD_FEATURE_NAME` must be supported. + * `PAL_THREAD_FEATURE_NAME` must be supported otherwise undefined behavior. * The thread name will be visible in debuggers and the Task Manager (Windows). * * @param[in] thread The thread diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 3119aabe..bb31840e 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -687,7 +687,7 @@ PAL_API PalResult PAL_CALL palEnumerateMonitors( * @brief Get the primary connected monitor. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY` must be supported. + * `PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY` must be supported otherwise undefined behavior. * * The monitor handle must not be freed by the user, they are managed by the * platform (OS). @@ -695,15 +695,12 @@ PAL_API PalResult PAL_CALL palEnumerateMonitors( * @param[out] outMonitor Pointer to a PalMonitor to recieve the primary * monitor. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 * @sa palEnumerateMonitors */ -PAL_API PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor); +PAL_API void PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor); /** * @brief Get information about a monitor. @@ -717,14 +714,11 @@ PAL_API PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor); * @param[in] monitor Monitor to query information on. * @param[out] info Pointer to a PalMonitorInfo to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palGetMonitorInfo( +PAL_API void PAL_CALL palGetMonitorInfo( PalMonitor* monitor, PalMonitorInfo* info); @@ -744,14 +738,11 @@ PAL_API PalResult PAL_CALL palGetMonitorInfo( * @param[in, out] count Capacity of the PalMonitorMode array. * @param[out] modes User allocated array of PalMonitorMode. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palEnumerateMonitorModes( +PAL_API void PAL_CALL palEnumerateMonitorModes( PalMonitor* monitor, uint32_t* count, PalMonitorMode* modes); @@ -760,21 +751,18 @@ PAL_API PalResult PAL_CALL palEnumerateMonitorModes( * @brief Get the current monitor display mode of the provided monitor. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_MONITOR_GET_MODE` must be supported. + * `PAL_VIDEO_FEATURE_MONITOR_GET_MODE` must be supported otherwise undefined behavior. * * @param[in] monitor Monitor to query its current display mode. * @param[out] mode Pointer to a PalMonitorMode to recieve the current monitor. * mode. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 * @sa palSetMonitorMode */ -PAL_API PalResult PAL_CALL palGetCurrentMonitorMode( +PAL_API void PAL_CALL palGetCurrentMonitorMode( PalMonitor* monitor, PalMonitorMode* mode); @@ -782,7 +770,7 @@ PAL_API PalResult PAL_CALL palGetCurrentMonitorMode( * @brief Set the active display monitor mode of the provided monitor. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_MONITOR_SET_MODE` Must be supported. + * `PAL_VIDEO_FEATURE_MONITOR_SET_MODE` Must be supported otherwise undefined behavior. * * PAL only validates the monitor display mode pointer not the values. To be * safe, users must get the monitor mode from palEnumerateMonitorModes() or call @@ -811,7 +799,7 @@ PAL_API PalResult PAL_CALL palSetMonitorMode( * @brief Check if a monitor display mode is valid on the provided monitor. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_MONITOR_VALIDATE_MODE` must be supported. + * `PAL_VIDEO_FEATURE_MONITOR_VALIDATE_MODE` must be supported otherwise undefined behavior. * * @param[in] monitor The monitor. * @param[in] mode Pointer to a PalMonitorMode to validate. @@ -831,7 +819,7 @@ PAL_API PalResult PAL_CALL palValidateMonitorMode( * @brief Set the orientation for a monitor. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION` must be supported. + * `PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION` must be supported otherwise undefined behavior. * * This change is temporary and is reset when the platform (OS) reboots. * @@ -911,54 +899,45 @@ PAL_API void PAL_CALL palDestroyWindow(PalWindow* window); * @brief Minimize a maximized or restored window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_STATE` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_STATE` must be supported otherwise undefined behavior. * If the window is already minimized, this functions does nothing. * * @param[in] window Window to minimize. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 * @sa palMaximizeWindow * @sa palRestoreWindow */ -PAL_API PalResult PAL_CALL palMinimizeWindow(PalWindow* window); +PAL_API void PAL_CALL palMinimizeWindow(PalWindow* window); /** * @brief Maximize a minimized or restored window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_STATE` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_STATE` must be supported otherwise undefined behavior. * If the window is already maximized, this functions does nothing. * * @param[in] window Window to maximize. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 * @sa palMinimizeWindow * @sa palRestoreWindow */ -PAL_API PalResult PAL_CALL palMaximizeWindow(PalWindow* window); +PAL_API void PAL_CALL palMaximizeWindow(PalWindow* window); /** * @brief Restores a window to it previous state. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_STATE` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_STATE` must be supported otherwise undefined behavior. * If the window is already restored, this functions does nothing. * * @param[in] window Window to restore. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @note Wayland does not support restoring a minimized windows. @@ -967,46 +946,40 @@ PAL_API PalResult PAL_CALL palMaximizeWindow(PalWindow* window); * @sa palMinimizeWindow * @sa palMaximizeWindow */ -PAL_API PalResult PAL_CALL palRestoreWindow(PalWindow* window); +PAL_API void PAL_CALL palRestoreWindow(PalWindow* window); /** * @brief Show the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY` must be supported otherwise undefined behavior. * All windows are created hidden if not explicitly shown. * This does nothing if the window is already shown. * * @param[in] window Window to show. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 * @sa palHideWindow */ -PAL_API PalResult PAL_CALL palShowWindow(PalWindow* window); +PAL_API void PAL_CALL palShowWindow(PalWindow* window); /** * @brief Hide the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY` must be supported otherwise undefined behavior. * This does nothing if the window is already hidden. * * @param[in] window Window to hide. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 * @sa palShowWindow */ -PAL_API PalResult PAL_CALL palHideWindow(PalWindow* window); +PAL_API void PAL_CALL palHideWindow(PalWindow* window); /** * @brief Request the platform (OS) to visually flash the provided window. @@ -1022,14 +995,11 @@ PAL_API PalResult PAL_CALL palHideWindow(PalWindow* window); * @param[in] window Pointer to the window. * @param[in] info Pointer to a PalFlashInfo struct with flash parameters. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palFlashWindow( +PAL_API void PAL_CALL palFlashWindow( PalWindow* window, const PalFlashInfo* info); @@ -1037,20 +1007,17 @@ PAL_API PalResult PAL_CALL palFlashWindow( * @brief Get the style of the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_GET_STYLE` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_GET_STYLE` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[out] outStyle Pointer to a PalWindowStyle to recieve the window style. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 * @sa palSetWindowStyle */ -PAL_API PalResult PAL_CALL palGetWindowStyle( +PAL_API void PAL_CALL palGetWindowStyle( PalWindow* window, PalWindowStyle* outStyle); @@ -1058,19 +1025,16 @@ PAL_API PalResult PAL_CALL palGetWindowStyle( * @brief Get the monitor the provided window is currently on. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_GET_MONITOR` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_GET_MONITOR` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[out] outMonitor Pointer to a PalMonitor to recieve the monitor. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palGetWindowMonitor( +PAL_API void PAL_CALL palGetWindowMonitor( PalWindow* window, PalMonitor** outMonitor); @@ -1078,7 +1042,7 @@ PAL_API PalResult PAL_CALL palGetWindowMonitor( * @brief Get the title of the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_GET_TITLE` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_GET_TITLE` must be supported otherwise undefined behavior. * * Set the buffer to `nullptr` to get the size of the window name in bytes. * If the size of the provided buffer is less than the actual size of window @@ -1095,7 +1059,7 @@ PAL_API PalResult PAL_CALL palGetWindowMonitor( * @since 1.0 * @sa palSetWindowTitle */ -PAL_API PalResult PAL_CALL palGetWindowTitle( +PAL_API void PAL_CALL palGetWindowTitle( PalWindow* window, uint64_t bufferSize, uint64_t* outSize, @@ -1105,21 +1069,18 @@ PAL_API PalResult PAL_CALL palGetWindowTitle( * @brief Get the position of the provided window in pixels. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_GET_POS` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_GET_POS` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[out] x Pointer to recieve the window x position. Can be `nullptr`. * @param[out] y Pointer to recieve the window y position. Can be `nullptr`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 * @sa palSetWindowPos */ -PAL_API PalResult PAL_CALL palGetWindowPos( +PAL_API void PAL_CALL palGetWindowPos( PalWindow* window, int32_t* x, int32_t* y); @@ -1128,21 +1089,18 @@ PAL_API PalResult PAL_CALL palGetWindowPos( * @brief Get the size of the provided window in pixels. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_GET_SIZE` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_GET_SIZE` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[out] width Pointer to recieve the width. Can be `nullptr`. * @param[out] height Pointer to recieve the height. Can be `nullptr`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 * @sa palSetWindowSize */ -PAL_API PalResult PAL_CALL palGetWindowSize( +PAL_API void PAL_CALL palGetWindowSize( PalWindow* window, uint32_t* width, uint32_t* height); @@ -1151,19 +1109,16 @@ PAL_API PalResult PAL_CALL palGetWindowSize( * @brief Get the state of the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_GET_STATE` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_GET_STATE` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[out] outState Pointer to a PalWindowState to recieve the window state. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palGetWindowState( +PAL_API void PAL_CALL palGetWindowState( PalWindow* window, PalWindowState* outState); @@ -1262,7 +1217,7 @@ PAL_API void PAL_CALL palGetMouseWheelDelta( * @brief Check if the provided window is visible. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @@ -1278,7 +1233,7 @@ PAL_API PalBool PAL_CALL palIsWindowVisible(PalWindow* window); * @brief Get the current input-focused window per application. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS` must be supported otherwise undefined behavior. * * @return The current input-focused window on success or `nullptr` on * failure. @@ -1300,14 +1255,11 @@ PAL_API PalWindow* PAL_CALL palGetFocusWindow(); * @param[in] window Pointer to the window. * @param[out] info Pointer to a PalWindowHandleInfo to fill. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Thread-safe. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palGetWindowHandleInfo( +PAL_API void PAL_CALL palGetWindowHandleInfo( PalWindow* window, PalWindowHandleInfo* info); @@ -1315,20 +1267,17 @@ PAL_API PalResult PAL_CALL palGetWindowHandleInfo( * @brief Set the opacity of the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW` must be supported. + * `PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW` must be supported otherwise undefined behavior. * The window must have `PAL_WINDOW_STYLE_TRANSPARENT` style. * * @param[in] window Pointer to the window. * @param[in] opacity Must be in the range 0.0 - 1.0. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palSetWindowOpacity( +PAL_API void PAL_CALL palSetWindowOpacity( PalWindow* window, float opacity); @@ -1336,20 +1285,17 @@ PAL_API PalResult PAL_CALL palSetWindowOpacity( * @brief Set the style of the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_STYLE` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_STYLE` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[in] style The style to set. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 * @sa palGetWindowStyle */ -PAL_API PalResult PAL_CALL palSetWindowStyle( +PAL_API void PAL_CALL palSetWindowStyle( PalWindow* window, PalWindowStyle style); @@ -1357,21 +1303,18 @@ PAL_API PalResult PAL_CALL palSetWindowStyle( * @brief Set the title of the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_TITLE` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_TITLE` must be supported otherwise undefined behavior. * The title must be a UTF-8 encoding null terminated string. * * @param[in] window Pointer to the window. * @param[in] title UTF-8 encoding null terminated string. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 * @sa palGetWindowTitle */ -PAL_API PalResult PAL_CALL palSetWindowTitle( +PAL_API void PAL_CALL palSetWindowTitle( PalWindow* window, const char* title); @@ -1379,21 +1322,18 @@ PAL_API PalResult PAL_CALL palSetWindowTitle( * @brief Set the position of the provided window in pixels. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_POS` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_POS` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[in] x The new x coordinate in pixels. * @param[in] y The new y coordinate in pixels. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 * @sa palGetWindowPos */ -PAL_API PalResult PAL_CALL palSetWindowPos( +PAL_API void PAL_CALL palSetWindowPos( PalWindow* window, int32_t x, int32_t y); @@ -1402,7 +1342,7 @@ PAL_API PalResult PAL_CALL palSetWindowPos( * @brief Set the size of the provided window in pixels. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_SIZE` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_SIZE` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[in] width The new width of the window in pixels. Must be greater than @@ -1410,15 +1350,12 @@ PAL_API PalResult PAL_CALL palSetWindowPos( * @param[in] height The new height of the window in pixels. Must be greater * than zero. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 * @sa palGetWindowSize */ -PAL_API PalResult PAL_CALL palSetWindowSize( +PAL_API void PAL_CALL palSetWindowSize( PalWindow* window, uint32_t width, uint32_t height); @@ -1427,25 +1364,22 @@ PAL_API PalResult PAL_CALL palSetWindowSize( * @brief Request input focus for the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 * @sa palGetFocusWindow */ -PAL_API PalResult PAL_CALL palSetFocusWindow(PalWindow* window); +PAL_API void PAL_CALL palSetFocusWindow(PalWindow* window); /** * @brief Create an icon. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported otherwise undefined behavior. * * @param[in] info Pointer to a PalIconCreateInfo struct that specifies * parameters. Must not be `nullptr`. @@ -1485,19 +1419,16 @@ PAL_API void PAL_CALL palDestroyIcon(PalIcon* icon); * @brief Set the icon for the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported. + * `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[in] icon Pointer to the icon. Set to `nullptr` to revert. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palSetWindowIcon( +PAL_API void PAL_CALL palSetWindowIcon( PalWindow* window, PalIcon* icon); @@ -1565,7 +1496,7 @@ PAL_API void PAL_CALL palDestroyCursor(PalCursor* cursor); * @brief Show or hide the cursor. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_CURSOR_SET_VISIBILITY` must be supported. + * `PAL_VIDEO_FEATURE_CURSOR_SET_VISIBILITY` must be supported otherwise undefined behavior. * * This affects all created cursors since the platform (OS) merges all cursors * into a single one on the screen. @@ -1582,7 +1513,7 @@ PAL_API void PAL_CALL palShowCursor(PalBool show); * @brief Clip the cursor to the provided window. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_CLIP_CURSOR` must be supported. + * `PAL_VIDEO_FEATURE_CLIP_CURSOR` must be supported otherwise undefined behavior. * * If the window is destroyed without unclipping the cursor, this cursor might * not reset depending on the platform (OS). To be safe, unclip the cursor from @@ -1591,14 +1522,11 @@ PAL_API void PAL_CALL palShowCursor(PalBool show); * @param[in] window Pointer to the window. * @param[in] clip True to clip to window or `PAL_FALSE` to unclip. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palClipCursor( +PAL_API void PAL_CALL palClipCursor( PalWindow* window, PalBool clip); @@ -1607,7 +1535,7 @@ PAL_API PalResult PAL_CALL palClipCursor( * pixels. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_CURSOR_GET_POS` must be supported. + * `PAL_VIDEO_FEATURE_CURSOR_GET_POS` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[out] x Pointer to recieve the x position. Can be @@ -1615,14 +1543,11 @@ PAL_API PalResult PAL_CALL palClipCursor( * @param[out] y Pointer to recieve the y position. Can be * `nullptr`. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palGetCursorPos( +PAL_API void PAL_CALL palGetCursorPos( PalWindow* window, int32_t* x, int32_t* y); @@ -1632,20 +1557,17 @@ PAL_API PalResult PAL_CALL palGetCursorPos( * pixels. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_CURSOR_SET_POS` must be supported. + * `PAL_VIDEO_FEATURE_CURSOR_SET_POS` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. * @param[in] x The new x coordinate of the cursor in pixels. * @param[in] y The new y coordinate of the cursor in pixels. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palSetCursorPos( +PAL_API void PAL_CALL palSetCursorPos( PalWindow* window, int32_t x, int32_t y); @@ -1658,14 +1580,11 @@ PAL_API PalResult PAL_CALL palSetCursorPos( * @param[in] window Pointer to the window. * @param[in] cursor Pointer to the cursor. Set to `nullptr` to revert. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must be called from the main thread. * * @since 1.0 */ -PAL_API PalResult PAL_CALL palSetWindowCursor( +PAL_API void PAL_CALL palSetWindowCursor( PalWindow* window, PalCursor* cursor); @@ -1695,7 +1614,7 @@ PAL_API void* PAL_CALL palGetInstance(); * @brief Attach a foreign or native window to PAL video system. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_FOREIGN_WINDOWS` must be supported. + * `PAL_VIDEO_FEATURE_FOREIGN_WINDOWS` must be supported otherwise undefined behavior. * * This function registers the provided window with PAL video system so it * can manage events and use its functionality/API for the provided window. @@ -1735,7 +1654,7 @@ PAL_API PalResult PAL_CALL palAttachWindow( * @brief Detach a foreign or native window from PAL video system. * * The video system must be initialized before this call. - * `PAL_VIDEO_FEATURE_FOREIGN_WINDOWS` must be supported. + * `PAL_VIDEO_FEATURE_FOREIGN_WINDOWS` must be supported otherwise undefined behavior. * * This function unregisters the provided window from PAL video system. * The window must not be owned by PAL otherwise the function fails diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index ba930875..b0ab2b9f 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -7,6 +7,9 @@ #include "pal_graphics_backends.h" +#define ceil(a, b) (a + b - 1) / b +#define min(a, b) (a < b) ? a : b + #define MAX_BACKENDS (PAL_MAX_CUSTOM_BACKENDS + 2) #define PAL_HANDLE(name) \ struct name { \ @@ -44,7 +47,6 @@ typedef struct { } BackendData; typedef struct { - PalBool initialized; int32_t backendCount; const PalAllocator* allocator; BackendData backends[MAX_BACKENDS]; @@ -52,22 +54,9 @@ typedef struct { static Graphics s_Graphics = {0}; -static inline uint32_t _ceil( - uint32_t a, - uint32_t b) -{ - return (a + b - 1) / b; -} - -static inline uint32_t _min( - uint32_t a, - uint32_t b) -{ - return (a < b) ? a : b; -} - static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) { + // validate required functions // clang-format off if (!vtable1->enumerateAdapters || !vtable1->getAdapterInfo || @@ -83,16 +72,6 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) !vtable1->allocateMemory || !vtable1->freeMemory || - // extended adapter features - !vtable1->querySamplerAnisotropyCapabilities || - !vtable1->queryMultiViewCapabilities || - !vtable1->queryMultiViewportCapabilities || - !vtable1->queryDepthStencilCapabilities || - !vtable1->queryFragmentShadingRateCapabilities || - !vtable1->queryMeshShaderCapabilities || - !vtable1->queryRayTracingCapabilities || - !vtable1->queryDescriptorIndexingCapabilities || - // queue !vtable1->createQueue || !vtable1->destroyQueue || @@ -120,19 +99,6 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) !vtable1->createSampler || !vtable1->destroySampler || - // surface - !vtable1->createSurface || - !vtable1->destroySurface || - !vtable1->getSurfaceCapabilities || - - // swapchain - !vtable1->createSwapchain || - !vtable1->destroySwapchain || - !vtable1->getSwapchainImage || - !vtable1->getNextSwapchainImage || - !vtable1->presentSwapchain || - !vtable1->resizeSwapchain || - // shader !vtable1->createShader || !vtable1->destroyShader || @@ -141,15 +107,11 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) !vtable1->createFence || !vtable1->destroyFence || !vtable1->waitFence || - !vtable1->resetFence || !vtable1->isFenceSignaled || // semaphore !vtable1->createSemaphore || !vtable1->destroySemaphore || - !vtable1->waitSemaphore || - !vtable1->signalSemaphore || - !vtable1->getSemaphoreValue || // command pool and command buffer !vtable1->createCommandPool || @@ -164,11 +126,6 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) !vtable1->cmdEnd || !vtable1->resetCommandBuffer || !vtable1->cmdExecuteCommandBuffer || - !vtable1->cmdSetFragmentShadingRate || - !vtable1->cmdDrawMeshTasks || - !vtable1->cmdDrawMeshTasksIndirect || - !vtable1->cmdDrawMeshTasksIndirectCount || - !vtable1->cmdBuildAccelerationStructure || !vtable1->cmdBeginRendering || !vtable1->cmdEndRendering || !vtable1->cmdCopyBuffer || @@ -181,43 +138,22 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) !vtable1->cmdBindVertexBuffers || !vtable1->cmdBindIndexBuffer || !vtable1->cmdDraw || - !vtable1->cmdDrawIndirect || - !vtable1->cmdDrawIndirectCount || !vtable1->cmdDrawIndexed || - !vtable1->cmdDrawIndexedIndirect || - !vtable1->cmdDrawIndexedIndirectCount || - !vtable1->cmdAccelerationStructureBarrier || !vtable1->cmdImageBarrier || !vtable1->cmdBufferBarrier || !vtable1->cmdDispatch || - !vtable1->cmdDispatchBase || - !vtable1->cmdDispatchIndirect || - !vtable1->cmdTraceRays || - !vtable1->cmdTraceRaysIndirect || !vtable1->cmdBindDescriptorSet || !vtable1->cmdPushConstants || - !vtable1->cmdSetCullMode || - !vtable1->cmdSetFrontFace || - !vtable1->cmdSetPrimitiveTopology || - !vtable1->cmdSetDepthTestEnable || - !vtable1->cmdSetDepthWriteEnable || - !vtable1->cmdSetStencilOp || - - // acceleration structure - !vtable1->createAccelerationstructure || - !vtable1->destroyAccelerationstructure || - !vtable1->getAccelerationStructureBuildSize || // buffer !vtable1->createBuffer || !vtable1->destroyBuffer || !vtable1->getBufferMemoryRequirements || - !vtable1->computeInstanceBufferRequirements || - !vtable1->computeImageCopyStagingBufferRequirements || - !vtable1->writeToInstanceBuffer || - !vtable1->writeToImageCopyStagingBuffer || + !vtable1->computeInstanceStagingSize || + !vtable1->computeImageStagingRequirements || + !vtable1->writeInstanceStaging || + !vtable1->writeImageStaging || !vtable1->bindBufferMemory || - !vtable1->getBufferDeviceAddress || !vtable1->mapBuffer || !vtable1->unmapBuffer || @@ -238,12 +174,7 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) !vtable1->createGraphicsPipeline || !vtable1->createComputePipeline || !vtable1->createRayTracingPipeline || - !vtable1->destroyPipeline || - - // shader binding table - !vtable1->createShaderBindingTable || - !vtable1->destroyShaderBindingTable || - !vtable1->updateShaderBindingTable) { + !vtable1->destroyPipeline) { return PAL_FALSE; } // clang-format on @@ -398,11 +329,10 @@ static void populateVtableVersion1( vtable->createBuffer = vtable1->createBuffer; vtable->destroyBuffer = vtable1->destroyBuffer; vtable->getBufferMemoryRequirements = vtable1->getBufferMemoryRequirements; - vtable->computeInstanceBufferRequirements = vtable1->computeInstanceBufferRequirements; - vtable->computeImageCopyStagingBufferRequirements = vtable1->computeImageCopyStagingBufferRequirements; - vtable->writeToInstanceBuffer = vtable1->writeToInstanceBuffer; - - vtable->writeToImageCopyStagingBuffer = vtable1->writeToImageCopyStagingBuffer; + vtable->computeInstanceStagingSize = vtable1->computeInstanceStagingSize; + vtable->computeImageStagingRequirements = vtable1->computeImageStagingRequirements; + vtable->writeInstanceStaging = vtable1->writeInstanceStaging; + vtable->writeImageStaging = vtable1->writeImageStaging; vtable->bindBufferMemory = vtable1->bindBufferMemory; vtable->getBufferDeviceAddress = vtable1->getBufferDeviceAddress; vtable->mapBuffer = vtable1->mapBuffer; @@ -442,7 +372,7 @@ static void addBackend(PalGraphicsBackendInfo* backendInfo) // populate our internal vtable if (backendInfo->version == PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1) { - // validate that all version 1 pointers are set + // validate that all version 1 required pointers are set const PalGraphicsBackendVtable1* vtable1 = (PalGraphicsBackendVtable1*)backendInfo->vtable; validateVtableVersion1(vtable1); @@ -457,18 +387,6 @@ PalResult PAL_CALL palInitGraphics( uint32_t customBackendCount, const PalGraphicsBackendInfo* customBackends) { - if (s_Graphics.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (customBackendCount == 0 && customBackends) { - return PAL_RESULT_CODE_PLATFORM_FAILURE; - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; BackendData* attachedBackend = nullptr; #ifdef _WIN32 @@ -517,16 +435,11 @@ PalResult PAL_CALL palInitGraphics( #endif // _WIN32 s_Graphics.allocator = allocator; - s_Graphics.initialized = PAL_TRUE; return PAL_RESULT_SUCCESS; } void PAL_CALL palShutdownGraphics() { - if (!s_Graphics.initialized) { - return; - } - #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN_BACKEND @@ -549,7 +462,6 @@ void PAL_CALL palShutdownGraphics() #endif // _WIN32 memset(&s_Graphics, 0, sizeof(s_Graphics)); - s_Graphics.initialized = PAL_FALSE; } // ================================================== @@ -557,19 +469,11 @@ void PAL_CALL palShutdownGraphics() // ================================================== PalResult PAL_CALL palEnumerateAdapters( - int32_t* count, + uint32_t* count, PalAdapter** outAdapters) { // enumerate all adapters for both custom and PAL backends - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!count || *count == 0 && outAdapters) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - PalResult result; + PalResult result = 0; int totalCount = 0; int index = 0; int _count = 0; @@ -611,41 +515,22 @@ PalResult PAL_CALL palEnumerateAdapters( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL palGetAdapterInfo( +void PAL_CALL palGetAdapterInfo( PalAdapter* adapter, PalAdapterInfo* info) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!adapter || !info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return adapter->backend->getAdapterInfo(adapter, info); + adapter->backend->getAdapterInfo(adapter, info); } -PalResult PAL_CALL palGetAdapterCapabilities( +void PAL_CALL palGetAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!adapter || !caps) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return adapter->backend->getAdapterCapabilities(adapter, caps); + adapter->backend->getAdapterCapabilities(adapter, caps); } PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) { - if (!s_Graphics.initialized || !adapter) { - return 0; - } return adapter->backend->getAdapterFeatures(adapter); } @@ -653,9 +538,6 @@ uint32_t PAL_CALL palGetHighestSupportedShaderTarget( PalAdapter* adapter, PalShaderFormats shaderFormat) { - if (!s_Graphics.initialized || !adapter) { - return 0; - } return adapter->backend->getHighestSupportedShaderTarget(adapter, shaderFormat); } @@ -668,14 +550,6 @@ PalResult PAL_CALL palCreateDevice( PalAdapterFeatures features, PalDevice** outDevice) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!outDevice) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalDevice* device = nullptr; PalResult result; result = adapter->backend->createDevice(adapter, features, &device); @@ -683,10 +557,6 @@ PalResult PAL_CALL palCreateDevice( return result; } - if (device->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - device->backend = adapter->backend; *outDevice = device; return PAL_RESULT_SUCCESS; @@ -694,9 +564,7 @@ PalResult PAL_CALL palCreateDevice( void PAL_CALL palDestroyDevice(PalDevice* device) { - if (s_Graphics.initialized && device) { - device->backend->destroyDevice(device); - } + device->backend->destroyDevice(device); } PalResult PAL_CALL palAllocateMemory( @@ -706,14 +574,6 @@ PalResult PAL_CALL palAllocateMemory( uint64_t size, PalMemory** outMemory) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!outMemory || !device) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalMemory* memory = nullptr; PalResult result; result = device->backend->allocateMemory(device, type, memoryMask, size, &memory); @@ -721,146 +581,74 @@ PalResult PAL_CALL palAllocateMemory( return result; } - if (memory->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - memory->backend = device->backend; *outMemory = memory; return PAL_RESULT_SUCCESS; } -void PAL_CALL palFreeMemory( - PalDevice* device, - PalMemory* memory) +void PAL_CALL palFreeMemory(PalMemory* memory) { - if (s_Graphics.initialized && device && memory) { - device->backend->freeMemory(device, memory); - } + memory->backend->freeMemory(memory); } // ================================================== // Extended Adapter Features // ================================================== -PalResult PAL_CALL palQuerySamplerAnisotropyCapabilities( +void PAL_CALL palQuerySamplerAnisotropyCapabilities( PalDevice* device, PalSamplerAnisotropyCapabilities* caps) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !caps) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->querySamplerAnisotropyCapabilities(device, caps); + device->backend->querySamplerAnisotropyCapabilities(device, caps); } -PalResult PAL_CALL palQueryMultiViewCapabilities( +void PAL_CALL palQueryMultiViewCapabilities( PalDevice* device, PalMultiViewCapabilities* caps) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !caps) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->queryMultiViewCapabilities(device, caps); + device->backend->queryMultiViewCapabilities(device, caps); } -PalResult PAL_CALL palQueryMultiViewportCapabilities( +void PAL_CALL palQueryMultiViewportCapabilities( PalDevice* device, PalMultiViewportCapabilities* caps) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !caps) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->queryMultiViewportCapabilities(device, caps); + device->backend->queryMultiViewportCapabilities(device, caps); } -PalResult PAL_CALL palQueryDepthStencilCapabilities( +void PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !caps) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->queryDepthStencilCapabilities(device, caps); + device->backend->queryDepthStencilCapabilities(device, caps); } -PalResult PAL_CALL palQueryFragmentShadingRateCapabilities( +void PAL_CALL palQueryFragmentShadingRateCapabilities( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !caps) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->queryFragmentShadingRateCapabilities(device, caps); + device->backend->queryFragmentShadingRateCapabilities(device, caps); } -PalResult PAL_CALL palQueryMeshShaderCapabilities( +void PAL_CALL palQueryMeshShaderCapabilities( PalDevice* device, PalMeshShaderCapabilities* caps) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !caps) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->queryMeshShaderCapabilities(device, caps); + device->backend->queryMeshShaderCapabilities(device, caps); } -PalResult PAL_CALL palQueryRayTracingCapabilities( +void PAL_CALL palQueryRayTracingCapabilities( PalDevice* device, PalRayTracingCapabilities* caps) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !caps) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->queryRayTracingCapabilities(device, caps); + device->backend->queryRayTracingCapabilities(device, caps); } -PalResult PAL_CALL palQueryDescriptorIndexingCapabilities( +void PAL_CALL palQueryDescriptorIndexingCapabilities( PalDevice* device, PalDescriptorIndexingCapabilities* caps) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !caps) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->queryDescriptorIndexingCapabilities(device, caps); + device->backend->queryDescriptorIndexingCapabilities(device, caps); } // ================================================== @@ -872,14 +660,6 @@ PalResult PAL_CALL palCreateQueue( PalQueueType type, PalQueue** outQueue) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !outQueue) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalQueue* queue = nullptr; PalResult result; result = device->backend->createQueue(device, type, &queue); @@ -887,10 +667,6 @@ PalResult PAL_CALL palCreateQueue( return result; } - if (queue->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - queue->backend = device->backend; *outQueue = queue; return PAL_RESULT_SUCCESS; @@ -898,31 +674,18 @@ PalResult PAL_CALL palCreateQueue( void PAL_CALL palDestroyQueue(PalQueue* queue) { - if (s_Graphics.initialized && queue) { - queue->backend->destroyQueue(queue); - } + queue->backend->destroyQueue(queue); } PalBool PAL_CALL palCanQueuePresent( PalQueue* queue, PalSurface* surface) { - if (s_Graphics.initialized && queue) { - return queue->backend->canQueuePresent(queue, surface); - } - return PAL_FALSE; + queue->backend->canQueuePresent(queue, surface); } PalResult PAL_CALL palWaitQueue(PalQueue* queue) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!queue) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return queue->backend->waitQueue(queue); } @@ -930,53 +693,33 @@ PalResult PAL_CALL palWaitQueue(PalQueue* queue) // Format And Usages // ================================================== -PalResult PAL_CALL palEnumerateFormats( +void PAL_CALL palEnumerateFormats( PalAdapter* adapter, - int32_t* count, + uint32_t* count, PalFormatInfo* outFormats) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!adapter || !count || *count == 0 && outFormats) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return adapter->backend->enumerateFormats(adapter, count, outFormats); + adapter->backend->enumerateFormats(adapter, count, outFormats); } PalBool PAL_CALL palIsFormatSupported( PalAdapter* adapter, PalFormat format) { - if (!s_Graphics.initialized || !adapter) { - return PAL_FALSE; - } - - return adapter->backend->isFormatSupported(adapter, format); + adapter->backend->isFormatSupported(adapter, format); } PalImageUsages PAL_CALL palQueryFormatImageUsages( PalAdapter* adapter, PalFormat format) { - if (!s_Graphics.initialized || !adapter) { - return PAL_IMAGE_USAGE_UNDEFINED; - } - - return adapter->backend->queryFormatImageUsages(adapter, format); + adapter->backend->queryFormatImageUsages(adapter, format); } PalSampleCount PAL_CALL palQueryFormatSampleCount( PalAdapter* adapter, PalFormat format) { - if (!s_Graphics.initialized || !adapter) { - return PAL_SAMPLE_COUNT_1; - } - - return adapter->backend->queryFormatSampleCount(adapter, format); + adapter->backend->queryFormatSampleCount(adapter, format); } // ================================================== @@ -988,14 +731,6 @@ PalResult PAL_CALL palCreateImage( const PalImageCreateInfo* info, PalImage** outImage) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outImage) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalImage* image = nullptr; PalResult result; result = device->backend->createImage(device, info, &image); @@ -1003,10 +738,6 @@ PalResult PAL_CALL palCreateImage( return result; } - if (image->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - image->backend = device->backend; *outImage = image; return PAL_RESULT_SUCCESS; @@ -1014,39 +745,21 @@ PalResult PAL_CALL palCreateImage( void PAL_CALL palDestroyImage(PalImage* image) { - if (s_Graphics.initialized && image) { - image->backend->destroyImage(image); - } + image->backend->destroyImage(image); } -PalResult PAL_CALL palGetImageInfo( +void PAL_CALL palGetImageInfo( PalImage* image, PalImageInfo* info) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!image || !info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return image->backend->getImageInfo(image, info); + image->backend->getImageInfo(image, info); } -PalResult PAL_CALL palGetImageMemoryRequirements( +void PAL_CALL palGetImageMemoryRequirements( PalImage* image, PalMemoryRequirements* requirements) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!image) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return image->backend->getImageMemoryRequirements(image, requirements); + image->backend->getImageMemoryRequirements(image, requirements); } PalResult PAL_CALL palBindImageMemory( @@ -1054,15 +767,7 @@ PalResult PAL_CALL palBindImageMemory( PalMemory* memory, uint64_t offset) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!image || !memory) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return image->backend->bindImageMemory(image, memory, offset); + image->backend->bindImageMemory(image, memory, offset); } // ================================================== @@ -1075,14 +780,6 @@ PalResult PAL_CALL palCreateImageView( const PalImageViewCreateInfo* info, PalImageView** outImageView) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !image || !info || !outImageView) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalImageView* imageView = nullptr; PalResult result; result = device->backend->createImageView(device, image, info, &imageView); @@ -1090,10 +787,6 @@ PalResult PAL_CALL palCreateImageView( return result; } - if (imageView->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - imageView->backend = device->backend; *outImageView = imageView; return PAL_RESULT_SUCCESS; @@ -1101,9 +794,7 @@ PalResult PAL_CALL palCreateImageView( void PAL_CALL palDestroyImageView(PalImageView* imageView) { - if (s_Graphics.initialized && imageView) { - imageView->backend->destroyImageView(imageView); - } + imageView->backend->destroyImageView(imageView); } // ================================================== @@ -1115,14 +806,6 @@ PalResult PAL_CALL palCreateSampler( const PalSamplerCreateInfo* info, PalSampler** outSampler) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outSampler) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalSampler* sampler = nullptr; PalResult result; result = device->backend->createSampler(device, info, &sampler); @@ -1130,10 +813,6 @@ PalResult PAL_CALL palCreateSampler( return result; } - if (sampler->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - sampler->backend = device->backend; *outSampler = sampler; return PAL_RESULT_SUCCESS; @@ -1141,9 +820,7 @@ PalResult PAL_CALL palCreateSampler( void PAL_CALL palDestroySampler(PalSampler* sampler) { - if (s_Graphics.initialized && sampler) { - sampler->backend->destroySampler(sampler); - } + sampler->backend->destroySampler(sampler); } // ================================================== @@ -1157,23 +834,11 @@ PalResult PAL_CALL palCreateSurface( PalWindowInstanceType instanceType, PalSurface** outSurface) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !window || !outSurface) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalSurface* surface = nullptr; - PalResult result; - result = device->backend->createSurface(device, window, windowInstance, instanceType, &surface); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - - if (surface->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; + PalResult ret; + ret = device->backend->createSurface(device, window, windowInstance, instanceType, &surface); + if (ret != PAL_RESULT_SUCCESS) { + return ret; } surface->backend = device->backend; @@ -1183,25 +848,15 @@ PalResult PAL_CALL palCreateSurface( void PAL_CALL palDestroySurface(PalSurface* surface) { - if (s_Graphics.initialized && surface) { - surface->backend->destroySurface(surface); - } + surface->backend->destroySurface(surface); } -PalResult PAL_CALL palGetSurfaceCapabilities( +void PAL_CALL palGetSurfaceCapabilities( PalDevice* device, PalSurface* surface, PalSurfaceCapabilities* caps) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !surface || !caps) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->getSurfaceCapabilities(device, surface, caps); + device->backend->getSurfaceCapabilities(device, surface, caps); } // ================================================== @@ -1215,14 +870,6 @@ PalResult PAL_CALL palCreateSwapchain( const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !queue || !surface || !info || !outSwapchain) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalSwapchain* swapchain = nullptr; result = device->backend->createSwapchain(device, queue, surface, info, &swapchain); @@ -1230,10 +877,6 @@ PalResult PAL_CALL palCreateSwapchain( return result; } - if (swapchain->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - // set the backend for all swapchain images for (int i = 0; i < info->imageCount; i++) { PalImage* image = device->backend->getSwapchainImage(swapchain, i); @@ -1247,19 +890,13 @@ PalResult PAL_CALL palCreateSwapchain( void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) { - if (s_Graphics.initialized && swapchain) { - swapchain->backend->destroySwapchain(swapchain); - } + swapchain->backend->destroySwapchain(swapchain); } PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, uint32_t index) { - if (!s_Graphics.initialized || !swapchain || index < 0) { - return nullptr; - } - return swapchain->backend->getSwapchainImage(swapchain, index); } @@ -1268,14 +905,6 @@ PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchainNextImageInfo* info, uint32_t* outIndex) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!swapchain || !info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return swapchain->backend->getNextSwapchainImage(swapchain, info, outIndex); } @@ -1284,14 +913,6 @@ PalResult PAL_CALL palPresentSwapchain( uint32_t imageIndex, PalSemaphore* waitSemaphore) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!swapchain) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return swapchain->backend->presentSwapchain(swapchain, imageIndex, waitSemaphore); } @@ -1300,14 +921,6 @@ PalResult PAL_CALL palResizeSwapchain( uint32_t newWidth, uint32_t newHeight) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!swapchain) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return swapchain->backend->resizeSwapchain(swapchain, newWidth, newHeight); } @@ -1320,14 +933,6 @@ PalResult PAL_CALL palCreateShader( const PalShaderCreateInfo* info, PalShader** outShader) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outShader) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalShader* shader = nullptr; PalResult result; result = device->backend->createShader(device, info, &shader); @@ -1335,10 +940,6 @@ PalResult PAL_CALL palCreateShader( return result; } - if (shader->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - shader->backend = device->backend; *outShader = shader; return PAL_RESULT_SUCCESS; @@ -1346,9 +947,7 @@ PalResult PAL_CALL palCreateShader( void PAL_CALL palDestroyShader(PalShader* shader) { - if (s_Graphics.initialized && shader) { - shader->backend->destroyShader(shader); - } + shader->backend->destroyShader(shader); } // ================================================== @@ -1360,14 +959,6 @@ PalResult PAL_CALL palCreateFence( PalBool signaled, PalFence** outFence) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !outFence) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalFence* fence = nullptr; PalResult result; result = device->backend->createFence(device, signaled, &fence); @@ -1375,10 +966,6 @@ PalResult PAL_CALL palCreateFence( return result; } - if (fence->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - fence->backend = device->backend; *outFence = fence; return PAL_RESULT_SUCCESS; @@ -1386,45 +973,24 @@ PalResult PAL_CALL palCreateFence( void PAL_CALL palDestroyFence(PalFence* fence) { - if (s_Graphics.initialized && fence) { - fence->backend->destroyFence(fence); - } + fence->backend->destroyFence(fence); } PalResult PAL_CALL palWaitFence( PalFence* fence, uint64_t timeout) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!fence) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return fence->backend->waitFence(fence, timeout); } PalResult PAL_CALL palResetFence(PalFence* fence) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!fence) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return fence->backend->resetFence(fence); } PalBool PAL_CALL palIsFenceSignaled(PalFence* fence) { - if (s_Graphics.initialized && fence) { - return fence->backend->isFenceSignaled(fence); - } - return PAL_FALSE; + return fence->backend->isFenceSignaled(fence); } // ================================================== @@ -1436,14 +1002,6 @@ PalResult PAL_CALL palCreateSemaphore( PalBool enableTimeline, PalSemaphore** outSemaphore) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !outSemaphore) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalSemaphore* semaphore = nullptr; PalResult result; result = device->backend->createSemaphore(device, enableTimeline, &semaphore); @@ -1451,10 +1009,6 @@ PalResult PAL_CALL palCreateSemaphore( return result; } - if (semaphore->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - semaphore->backend = device->backend; *outSemaphore = semaphore; return PAL_RESULT_SUCCESS; @@ -1462,9 +1016,7 @@ PalResult PAL_CALL palCreateSemaphore( void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore) { - if (s_Graphics.initialized && semaphore) { - semaphore->backend->destroySemaphore(semaphore); - } + semaphore->backend->destroySemaphore(semaphore); } PalResult PAL_CALL palWaitSemaphore( @@ -1472,14 +1024,6 @@ PalResult PAL_CALL palWaitSemaphore( uint64_t value, uint64_t timeout) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!semaphore) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return semaphore->backend->waitSemaphore(semaphore, value, timeout); } @@ -1488,14 +1032,6 @@ PalResult PAL_CALL palSignalSemaphore( PalQueue* queue, uint64_t value) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!semaphore || !queue) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return semaphore->backend->signalSemaphore(semaphore, queue, value); } @@ -1503,14 +1039,6 @@ PalResult PAL_CALL palGetSemaphoreValue( PalSemaphore* semaphore, uint64_t* outValue) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!semaphore || !outValue) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return semaphore->backend->getSemaphoreValue(semaphore, outValue); } @@ -1523,14 +1051,6 @@ PalResult PAL_CALL palCreateCommandPool( PalQueue* queue, PalCommandPool** outPool) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !queue || !outPool) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalCommandPool* pool = nullptr; PalResult result; result = device->backend->createCommandPool(device, queue, &pool); @@ -1538,10 +1058,6 @@ PalResult PAL_CALL palCreateCommandPool( return result; } - if (pool->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - pool->backend = device->backend; *outPool = pool; return PAL_RESULT_SUCCESS; @@ -1549,21 +1065,11 @@ PalResult PAL_CALL palCreateCommandPool( void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) { - if (s_Graphics.initialized && pool) { - pool->backend->destroyCommandPool(pool); - } + pool->backend->destroyCommandPool(pool); } PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!pool) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return pool->backend->resetCommandPool(pool); } @@ -1573,14 +1079,6 @@ PalResult PAL_CALL palAllocateCommandBuffer( PalCommandBufferType type, PalCommandBuffer** outCmdBuffer) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !pool || !outCmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalCommandBuffer* cmdBuffer = nullptr; PalResult result; result = device->backend->allocateCommandBuffer(device, pool, type, &cmdBuffer); @@ -1588,10 +1086,6 @@ PalResult PAL_CALL palAllocateCommandBuffer( return result; } - if (cmdBuffer->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - cmdBuffer->backend = device->backend; *outCmdBuffer = cmdBuffer; return PAL_RESULT_SUCCESS; @@ -1599,21 +1093,11 @@ PalResult PAL_CALL palAllocateCommandBuffer( void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer) { - if (s_Graphics.initialized && cmdBuffer) { - cmdBuffer->backend->freeCommandBuffer(cmdBuffer); - } + cmdBuffer->backend->freeCommandBuffer(cmdBuffer); } PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return cmdBuffer->backend->resetCommandBuffer(cmdBuffer); } @@ -1621,14 +1105,6 @@ PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!queue || !info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return queue->backend->submitCommandBuffer(queue, info); } @@ -1640,361 +1116,183 @@ PalResult PAL_CALL palCmdBegin( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdBegin(cmdBuffer, info); + cmdBuffer->backend->cmdBegin(cmdBuffer, info); } PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdEnd(cmdBuffer); + cmdBuffer->backend->cmdEnd(cmdBuffer); } -PalResult PAL_CALL palCmdExecuteCommandBuffer( +void PAL_CALL palCmdExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!primaryCmdBuffer || !secondaryCmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return primaryCmdBuffer->backend->cmdExecuteCommandBuffer(primaryCmdBuffer, secondaryCmdBuffer); + primaryCmdBuffer->backend->cmdExecuteCommandBuffer(primaryCmdBuffer, secondaryCmdBuffer); } -PalResult PAL_CALL palCmdSetFragmentShadingRate( +void PAL_CALL palCmdSetFragmentShadingRate( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } + cmdBuffer->backend->cmdSetFragmentShadingRate(cmdBuffer, state); +} - if (!cmdBuffer || !state) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdSetFragmentShadingRate(cmdBuffer, state); -} - -PalResult PAL_CALL palCmdDrawMeshTasks( +void PAL_CALL palCmdDrawMeshTasks( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdDrawMeshTasks(cmdBuffer, groupCountX, groupCountY, groupCountZ); + cmdBuffer->backend->cmdDrawMeshTasks(cmdBuffer, groupCountX, groupCountY, groupCountZ); } -PalResult PAL_CALL palCmdDrawMeshTasksIndirect( +void PAL_CALL palCmdDrawMeshTasksIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t drawCount) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !buffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdDrawMeshTasksIndirect(cmdBuffer, buffer, drawCount); + cmdBuffer->backend->cmdDrawMeshTasksIndirect(cmdBuffer, buffer, drawCount); } -PalResult PAL_CALL palCmdDrawMeshTasksIndirectCount( +void PAL_CALL palCmdDrawMeshTasksIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, uint32_t maxDrawCount) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !buffer || !countBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend - ->cmdDrawMeshTasksIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); + cmdBuffer->backend->cmdDrawMeshTasksIndirectCount( + cmdBuffer, + buffer, + countBuffer, + maxDrawCount); } -PalResult PAL_CALL palCmdBuildAccelerationStructure( +void PAL_CALL palCmdBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - if (!info->dst || info->scratchBufferAddress == 0) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdBuildAccelerationStructure(cmdBuffer, info); + cmdBuffer->backend->cmdBuildAccelerationStructure(cmdBuffer, info); } -PalResult PAL_CALL palCmdBeginRendering( +void PAL_CALL palCmdBeginRendering( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdBeginRendering(cmdBuffer, info); + cmdBuffer->backend->cmdBeginRendering(cmdBuffer, info); } -PalResult PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer) +void PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdEndRendering(cmdBuffer); + cmdBuffer->backend->cmdEndRendering(cmdBuffer); } -PalResult PAL_CALL palCmdCopyBuffer( +void PAL_CALL palCmdCopyBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, PalBufferCopyInfo* copyInfo) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !dst || !src || !copyInfo) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdCopyBuffer(cmdBuffer, dst, src, copyInfo); + cmdBuffer->backend->cmdCopyBuffer(cmdBuffer, dst, src, copyInfo); } -PalResult PAL_CALL palCmdCopyBufferToImage( +void PAL_CALL palCmdCopyBufferToImage( PalCommandBuffer* cmdBuffer, PalImage* dstImage, PalBuffer* srcBuffer, PalBufferImageCopyInfo* copyInfo) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !dstImage || !srcBuffer || !copyInfo) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdCopyBufferToImage(cmdBuffer, dstImage, srcBuffer, copyInfo); + cmdBuffer->backend->cmdCopyBufferToImage(cmdBuffer, dstImage, srcBuffer, copyInfo); } -PalResult PAL_CALL palCmdCopyImage( +void PAL_CALL palCmdCopyImage( PalCommandBuffer* cmdBuffer, PalImage* dst, PalImage* src, PalImageCopyInfo* copyInfo) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !dst || !src || !copyInfo) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdCopyImage(cmdBuffer, dst, src, copyInfo); + cmdBuffer->backend->cmdCopyImage(cmdBuffer, dst, src, copyInfo); } -PalResult PAL_CALL palCmdCopyImageToBuffer( +void PAL_CALL palCmdCopyImageToBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, PalBufferImageCopyInfo* copyInfo) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !dstBuffer || !srcImage || !copyInfo) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdCopyImageToBuffer(cmdBuffer, dstBuffer, srcImage, copyInfo); + cmdBuffer->backend->cmdCopyImageToBuffer(cmdBuffer, dstBuffer, srcImage, copyInfo); } -PalResult PAL_CALL palCmdBindPipeline( +void PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !pipeline) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdBindPipeline(cmdBuffer, pipeline); + cmdBuffer->backend->cmdBindPipeline(cmdBuffer, pipeline); } -PalResult PAL_CALL palCmdSetViewport( +void PAL_CALL palCmdSetViewport( PalCommandBuffer* cmdBuffer, uint32_t count, PalViewport* viewports) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !viewports || !count) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdSetViewport(cmdBuffer, count, viewports); + cmdBuffer->backend->cmdSetViewport(cmdBuffer, count, viewports); } -PalResult PAL_CALL palCmdSetScissors( +void PAL_CALL palCmdSetScissors( PalCommandBuffer* cmdBuffer, uint32_t count, PalRect2D* scissors) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !scissors || !count) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdSetScissors(cmdBuffer, count, scissors); + cmdBuffer->backend->cmdSetScissors(cmdBuffer, count, scissors); } -PalResult PAL_CALL palCmdBindVertexBuffers( +void PAL_CALL palCmdBindVertexBuffers( PalCommandBuffer* cmdBuffer, uint32_t firstSlot, uint32_t count, PalBuffer** buffers, uint64_t* offsets) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !buffers || !offsets) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdBindVertexBuffers(cmdBuffer, firstSlot, count, buffers, offsets); + cmdBuffer->backend->cmdBindVertexBuffers(cmdBuffer, firstSlot, count, buffers, offsets); } -PalResult PAL_CALL palCmdBindIndexBuffer( +void PAL_CALL palCmdBindIndexBuffer( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint64_t offset, PalIndexType type) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !buffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdBindIndexBuffer(cmdBuffer, buffer, offset, type); + cmdBuffer->backend->cmdBindIndexBuffer(cmdBuffer, buffer, offset, type); } -PalResult PAL_CALL palCmdDraw( +void PAL_CALL palCmdDraw( PalCommandBuffer* cmdBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend - ->cmdDraw(cmdBuffer, vertexCount, instanceCount, firstVertex, firstInstance); + cmdBuffer->backend->cmdDraw(cmdBuffer, vertexCount, instanceCount, firstVertex, firstInstance); } -PalResult PAL_CALL palCmdDrawIndirect( +void PAL_CALL palCmdDrawIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !buffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdDrawIndirect(cmdBuffer, buffer, count); + cmdBuffer->backend->cmdDrawIndirect(cmdBuffer, buffer, count); } -PalResult PAL_CALL palCmdDrawIndirectCount( +void PAL_CALL palCmdDrawIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, uint32_t maxDrawCount) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !buffer || !countBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdDrawIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); + cmdBuffer->backend->cmdDrawIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); } -PalResult PAL_CALL palCmdDrawIndexed( +void PAL_CALL palCmdDrawIndexed( PalCommandBuffer* cmdBuffer, uint32_t indexCount, uint32_t instanceCount, @@ -2002,15 +1300,7 @@ PalResult PAL_CALL palCmdDrawIndexed( int32_t vertexOffset, uint32_t firstInstance) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdDrawIndexed( + cmdBuffer->backend->cmdDrawIndexed( cmdBuffer, indexCount, instanceCount, @@ -2019,113 +1309,70 @@ PalResult PAL_CALL palCmdDrawIndexed( firstInstance); } -PalResult PAL_CALL palCmdDrawIndexedIndirect( +void PAL_CALL palCmdDrawIndexedIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !buffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdDrawIndexedIndirect(cmdBuffer, buffer, count); + cmdBuffer->backend->cmdDrawIndexedIndirect(cmdBuffer, buffer, count); } -PalResult PAL_CALL palCmdDrawIndexedIndirectCount( +void PAL_CALL palCmdDrawIndexedIndirectCount( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, uint32_t maxDrawCount) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !buffer || !countBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend - ->cmdDrawIndexedIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); + cmdBuffer->backend->cmdDrawIndexedIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); } -PalResult PAL_CALL palCmdAccelerationStructureBarrier( +void PAL_CALL palCmdAccelerationStructureBarrier( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, PalUsageState oldUsageState, PalUsageState newUsageState) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !as) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend - ->cmdAccelerationStructureBarrier(cmdBuffer, as, oldUsageState, newUsageState); + cmdBuffer->backend->cmdAccelerationStructureBarrier( + cmdBuffer, + as, + oldUsageState, + newUsageState); } -PalResult PAL_CALL palCmdImageBarrier( +void PAL_CALL palCmdImageBarrier( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, PalUsageState oldUsageState, PalUsageState newUsageState) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !image || !subresourceRange) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend - ->cmdImageBarrier(cmdBuffer, image, subresourceRange, oldUsageState, newUsageState); + cmdBuffer->backend->cmdImageBarrier( + cmdBuffer, + image, + subresourceRange, + oldUsageState, + newUsageState); } -PalResult PAL_CALL palCmdBufferBarrier( +void PAL_CALL palCmdBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageState oldUsageState, PalUsageState newUsageState) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !buffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend - ->cmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); + cmdBuffer->backend->cmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); } -PalResult PAL_CALL palCmdDispatch( +void PAL_CALL palCmdDispatch( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); + cmdBuffer->backend->cmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); } -PalResult PAL_CALL palCmdDispatchBase( +void PAL_CALL palCmdDispatchBase( PalCommandBuffer* cmdBuffer, uint32_t baseGroupX, uint32_t baseGroupY, @@ -2134,15 +1381,7 @@ PalResult PAL_CALL palCmdDispatchBase( uint32_t groupCountY, uint32_t groupCountZ) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdDispatchBase( + cmdBuffer->backend->cmdDispatchBase( cmdBuffer, baseGroupX, baseGroupY, @@ -2152,22 +1391,14 @@ PalResult PAL_CALL palCmdDispatchBase( groupCountZ); } -PalResult PAL_CALL palCmdDispatchIndirect( +void PAL_CALL palCmdDispatchIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !buffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdDispatchIndirect(cmdBuffer, buffer); + cmdBuffer->backend->cmdDispatchIndirect(cmdBuffer, buffer); } -PalResult PAL_CALL palCmdTraceRays( +void PAL_CALL palCmdTraceRays( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, uint32_t raygenIndex, @@ -2175,143 +1406,71 @@ PalResult PAL_CALL palCmdTraceRays( uint32_t height, uint32_t depth) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !sbt) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdTraceRays(cmdBuffer, sbt, raygenIndex, width, height, depth); + cmdBuffer->backend->cmdTraceRays(cmdBuffer, sbt, raygenIndex, width, height, depth); } -PalResult PAL_CALL palCmdTraceRaysIndirect( +void PAL_CALL palCmdTraceRaysIndirect( PalCommandBuffer* cmdBuffer, uint32_t raygenIndex, PalShaderBindingTable* sbt, PalBuffer* buffer) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !sbt || !buffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdTraceRaysIndirect(cmdBuffer, raygenIndex, sbt, buffer); + cmdBuffer->backend->cmdTraceRaysIndirect(cmdBuffer, raygenIndex, sbt, buffer); } -PalResult PAL_CALL palCmdBindDescriptorSet( +void PAL_CALL palCmdBindDescriptorSet( PalCommandBuffer* cmdBuffer, uint32_t setIndex, PalDescriptorSet* set) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !set) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdBindDescriptorSet(cmdBuffer, setIndex, set); + cmdBuffer->backend->cmdBindDescriptorSet(cmdBuffer, setIndex, set); } -PalResult PAL_CALL palCmdPushConstants( +void PAL_CALL palCmdPushConstants( PalCommandBuffer* cmdBuffer, uint32_t offset, uint32_t size, const void* value) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer || !value) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdPushConstants(cmdBuffer, offset, size, value); + cmdBuffer->backend->cmdPushConstants(cmdBuffer, offset, size, value); } -PalResult PAL_CALL palCmdSetCullMode( +void PAL_CALL palCmdSetCullMode( PalCommandBuffer* cmdBuffer, PalCullMode cullMode) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdSetCullMode(cmdBuffer, cullMode); + cmdBuffer->backend->cmdSetCullMode(cmdBuffer, cullMode); } -PalResult PAL_CALL palCmdSetFrontFace( +void PAL_CALL palCmdSetFrontFace( PalCommandBuffer* cmdBuffer, PalFrontFace frontFace) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdSetFrontFace(cmdBuffer, frontFace); + cmdBuffer->backend->cmdSetFrontFace(cmdBuffer, frontFace); } -PalResult PAL_CALL palCmdSetPrimitiveTopology( +void PAL_CALL palCmdSetPrimitiveTopology( PalCommandBuffer* cmdBuffer, PalPrimitiveTopology topology) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdSetPrimitiveTopology(cmdBuffer, topology); + cmdBuffer->backend->cmdSetPrimitiveTopology(cmdBuffer, topology); } -PalResult PAL_CALL palCmdSetDepthTestEnable( +void PAL_CALL palCmdSetDepthTestEnable( PalCommandBuffer* cmdBuffer, PalBool enable) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdSetDepthTestEnable(cmdBuffer, enable); + cmdBuffer->backend->cmdSetDepthTestEnable(cmdBuffer, enable); } -PalResult PAL_CALL palCmdSetDepthWriteEnable( +void PAL_CALL palCmdSetDepthWriteEnable( PalCommandBuffer* cmdBuffer, PalBool enable) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend->cmdSetDepthWriteEnable(cmdBuffer, enable); + cmdBuffer->backend->cmdSetDepthWriteEnable(cmdBuffer, enable); } -PalResult PAL_CALL palCmdSetStencilOp( +void PAL_CALL palCmdSetStencilOp( PalCommandBuffer* cmdBuffer, PalStencilFaceFlags faceMask, PalStencilOp failOp, @@ -2319,16 +1478,13 @@ PalResult PAL_CALL palCmdSetStencilOp( PalStencilOp depthFailOp, PalCompareOp compareOp) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!cmdBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return cmdBuffer->backend - ->cmdSetStencilOp(cmdBuffer, faceMask, failOp, passOp, depthFailOp, compareOp); + cmdBuffer->backend->cmdSetStencilOp( + cmdBuffer, + faceMask, + failOp, + passOp, + depthFailOp, + compareOp); } // ================================================== @@ -2340,18 +1496,6 @@ PalResult PAL_CALL palCreateAccelerationstructure( const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outAs) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - if (!info->buffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalAccelerationStructure* as = nullptr; result = device->backend->createAccelerationstructure(device, info, &as); @@ -2359,10 +1503,6 @@ PalResult PAL_CALL palCreateAccelerationstructure( return result; } - if (as->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - as->backend = device->backend; *outAs = as; return PAL_RESULT_SUCCESS; @@ -2370,25 +1510,15 @@ PalResult PAL_CALL palCreateAccelerationstructure( void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* as) { - if (s_Graphics.initialized && as) { - as->backend->destroyAccelerationstructure(as); - } + as->backend->destroyAccelerationstructure(as); } -PalResult PAL_CALL palGetAccelerationStructureBuildSize( +void PAL_CALL palGetAccelerationStructureBuildSize( PalDevice* device, PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !size) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->getAccelerationStructureBuildSize(device, info, size); + device->backend->getAccelerationStructureBuildSize(device, info, size); } // ================================================== @@ -2400,14 +1530,6 @@ PalResult PAL_CALL palCreateBuffer( const PalBufferCreateInfo* info, PalBuffer** outBuffer) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalBuffer* buffer = nullptr; result = device->backend->createBuffer(device, info, &buffer); @@ -2415,10 +1537,6 @@ PalResult PAL_CALL palCreateBuffer( return result; } - if (buffer->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - buffer->backend = device->backend; *outBuffer = buffer; return PAL_RESULT_SUCCESS; @@ -2426,118 +1544,54 @@ PalResult PAL_CALL palCreateBuffer( void PAL_CALL palDestroyBuffer(PalBuffer* buffer) { - if (s_Graphics.initialized && buffer) { - buffer->backend->destroyBuffer(buffer); - } + buffer->backend->destroyBuffer(buffer); } -PalResult PAL_CALL palGetBufferMemoryRequirements( +void PAL_CALL palGetBufferMemoryRequirements( PalBuffer* buffer, PalMemoryRequirements* requirements) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!buffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return buffer->backend->getBufferMemoryRequirements(buffer, requirements); + buffer->backend->getBufferMemoryRequirements(buffer, requirements); } -PalResult PAL_CALL palComputeInstanceBufferRequirements( +void PAL_CALL palComputeInstanceStagingSize( PalDevice* device, - uint32_t instanceCount, + uint32_t instanceCount, uint64_t* outSize) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !outSize) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->computeInstanceBufferRequirements(device, instanceCount, outSize); + device->backend->computeInstanceStagingSize(device, instanceCount, outSize); } -PalResult PAL_CALL palComputeImageCopyStagingBufferRequirements( +void PAL_CALL palComputeImageStagingRequirements( PalDevice* device, PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize) + const PalBufferImageCopyInfo* copyInfo, + PalImageStagingRequirements* outRequirements) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !outBufferRowLength || !outBufferImageHeight || !outSize) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - if (copyInfo->bufferRowLength < copyInfo->imageWidth && copyInfo->bufferRowLength) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - if (copyInfo->bufferImageHeight < copyInfo->imageHeight && copyInfo->bufferImageHeight) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend->computeImageCopyStagingBufferRequirements( + device->backend->computeImageStagingRequirements( device, imageFormat, copyInfo, - outBufferRowLength, - outBufferImageHeight, - outSize); + outRequirements); } -PalResult PAL_CALL palWriteToInstanceBuffer( +void PAL_CALL palWriteInstanceStaging( PalDevice* device, - void* ptr, + uint32_t instanceCount, PalAccelerationStructureInstance* instances, - uint32_t instanceCount) + void* ptr) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !ptr || !instances || instanceCount == 0) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - // since all tlas have backend pointer, we use the first one - return device->backend->writeToInstanceBuffer(device, ptr, instances, instanceCount); + device->backend->writeInstanceStaging(device, instanceCount, instances, ptr); } -PalResult PAL_CALL palWriteToImageCopyStagingBuffer( +void PAL_CALL palWriteImageStaging( PalDevice* device, - void* ptr, - void* srcData, PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo) + PalBufferImageCopyInfo* copyInfo, + void* srcData, + void* ptr) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !ptr || !srcData || !copyInfo) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - if (copyInfo->bufferRowLength < copyInfo->imageWidth && copyInfo->bufferRowLength) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - if (copyInfo->bufferImageHeight < copyInfo->imageHeight && copyInfo->bufferImageHeight) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return device->backend - ->writeToImageCopyStagingBuffer(device, ptr, srcData, imageFormat, copyInfo); + device->backend->writeImageStaging(device, imageFormat, copyInfo, srcData, ptr); } PalResult PAL_CALL palBindBufferMemory( @@ -2545,14 +1599,6 @@ PalResult PAL_CALL palBindBufferMemory( PalMemory* memory, uint64_t offset) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!buffer || !memory) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return buffer->backend->bindBufferMemory(buffer, memory, offset); } @@ -2562,29 +1608,16 @@ PalResult PAL_CALL palMapBuffer( uint64_t size, void** outPtr) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!buffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return buffer->backend->mapBuffer(buffer, offset, size, outPtr); } void PAL_CALL palUnmapBuffer(PalBuffer* buffer) { - if (s_Graphics.initialized && buffer) { - buffer->backend->unmapBuffer(buffer); - } + buffer->backend->unmapBuffer(buffer); } PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer) { - if (!s_Graphics.initialized || !buffer) { - return 0; - } return buffer->backend->getBufferDeviceAddress(buffer); } @@ -2597,14 +1630,6 @@ PalResult PAL_CALL palCreateDescriptorSetLayout( const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outLayout) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalDescriptorSetLayout* layout = nullptr; result = device->backend->createDescriptorSetLayout(device, info, &layout); @@ -2612,10 +1637,6 @@ PalResult PAL_CALL palCreateDescriptorSetLayout( return result; } - if (layout->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - layout->backend = device->backend; *outLayout = layout; return PAL_RESULT_SUCCESS; @@ -2623,9 +1644,7 @@ PalResult PAL_CALL palCreateDescriptorSetLayout( void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layout) { - if (s_Graphics.initialized && layout) { - layout->backend->destroyDescriptorSetLayout(layout); - } + layout->backend->destroyDescriptorSetLayout(layout); } PalResult PAL_CALL palCreateDescriptorPool( @@ -2633,18 +1652,6 @@ PalResult PAL_CALL palCreateDescriptorPool( const PalDescriptorPoolCreateInfo* info, PalDescriptorPool** outPool) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outPool) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - if (!info->maxDescriptorSets) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalDescriptorPool* pool = nullptr; result = device->backend->createDescriptorPool(device, info, &pool); @@ -2652,10 +1659,6 @@ PalResult PAL_CALL palCreateDescriptorPool( return result; } - if (pool->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - pool->backend = device->backend; *outPool = pool; return PAL_RESULT_SUCCESS; @@ -2663,21 +1666,11 @@ PalResult PAL_CALL palCreateDescriptorPool( void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool) { - if (s_Graphics.initialized && pool) { - pool->backend->destroyDescriptorPool(pool); - } + pool->backend->destroyDescriptorPool(pool); } PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!pool) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return pool->backend->resetDescriptorPool(pool); } @@ -2687,14 +1680,6 @@ PalResult PAL_CALL palAllocateDescriptorSet( PalDescriptorSetLayout* layout, PalDescriptorSet** outSet) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !pool || !layout || !outSet) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalDescriptorSet* set = nullptr; result = device->backend->allocateDescriptorSet(device, pool, layout, &set); @@ -2702,10 +1687,6 @@ PalResult PAL_CALL palAllocateDescriptorSet( return result; } - if (set->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - set->backend = device->backend; *outSet = set; return PAL_RESULT_SUCCESS; @@ -2716,14 +1697,6 @@ PalResult PAL_CALL palUpdateDescriptorSet( uint32_t count, PalDescriptorSetWriteInfo* infos) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !infos || count == 0 && infos) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - return device->backend->updateDescriptorSet(device, count, infos); } @@ -2736,14 +1709,6 @@ PalResult PAL_CALL palCreatePipelineLayout( const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outLayout) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalPipelineLayout* layout = nullptr; result = device->backend->createPipelineLayout(device, info, &layout); @@ -2751,10 +1716,6 @@ PalResult PAL_CALL palCreatePipelineLayout( return result; } - if (layout->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - layout->backend = device->backend; *outLayout = layout; return PAL_RESULT_SUCCESS; @@ -2762,9 +1723,7 @@ PalResult PAL_CALL palCreatePipelineLayout( void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout) { - if (s_Graphics.initialized && layout) { - layout->backend->destroyPipelineLayout(layout); - } + layout->backend->destroyPipelineLayout(layout); } // ================================================== @@ -2776,18 +1735,6 @@ PalResult PAL_CALL palCreateGraphicsPipeline( const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outPipeline) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - if (!info->renderingLayout) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalPipeline* pipeline = nullptr; result = device->backend->createGraphicsPipeline(device, info, &pipeline); @@ -2795,10 +1742,6 @@ PalResult PAL_CALL palCreateGraphicsPipeline( return result; } - if (pipeline->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - pipeline->backend = device->backend; *outPipeline = pipeline; return PAL_RESULT_SUCCESS; @@ -2809,14 +1752,6 @@ PalResult PAL_CALL palCreateComputePipeline( const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outPipeline) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalPipeline* pipeline = nullptr; result = device->backend->createComputePipeline(device, info, &pipeline); @@ -2824,10 +1759,6 @@ PalResult PAL_CALL palCreateComputePipeline( return result; } - if (pipeline->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - pipeline->backend = device->backend; *outPipeline = pipeline; return PAL_RESULT_SUCCESS; @@ -2838,14 +1769,6 @@ PalResult PAL_CALL palCreateRayTracingPipeline( const PalRayTracingPipelineCreateInfo* info, PalPipeline** outPipeline) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outPipeline) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalPipeline* pipeline = nullptr; result = device->backend->createRayTracingPipeline(device, info, &pipeline); @@ -2853,10 +1776,6 @@ PalResult PAL_CALL palCreateRayTracingPipeline( return result; } - if (pipeline->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - pipeline->backend = device->backend; *outPipeline = pipeline; return PAL_RESULT_SUCCESS; @@ -2864,9 +1783,7 @@ PalResult PAL_CALL palCreateRayTracingPipeline( void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) { - if (s_Graphics.initialized && pipeline) { - pipeline->backend->destroyPipeline(pipeline); - } + pipeline->backend->destroyPipeline(pipeline); } // ================================================== @@ -2878,18 +1795,6 @@ PalResult PAL_CALL palCreateShaderBindingTable( const PalShaderBindingTableCreateInfo* info, PalShaderBindingTable** outSbt) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!device || !info || !outSbt) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - if (!info->rayTracingPipeline) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - PalResult result; PalShaderBindingTable* sbt = nullptr; result = device->backend->createShaderBindingTable(device, info, &sbt); @@ -2897,10 +1802,6 @@ PalResult PAL_CALL palCreateShaderBindingTable( return result; } - if (sbt->backend != PAL_BACKEND_KEY) { - return PAL_RESULT_CODE_INVALID_DRIVER; - } - sbt->backend = device->backend; *outSbt = sbt; return PAL_RESULT_SUCCESS; @@ -2908,57 +1809,38 @@ PalResult PAL_CALL palCreateShaderBindingTable( void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt) { - if (s_Graphics.initialized && sbt) { - sbt->backend->destroyShaderBindingTable(sbt); - } + sbt->backend->destroyShaderBindingTable(sbt); } -PalResult PAL_CALL palUpdateShaderBindingTable( +void PAL_CALL palUpdateShaderBindingTable( PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos) { - if (!s_Graphics.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!sbt || !infos || count == 0 && infos) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return sbt->backend->updateShaderBindingTable(sbt, count, infos); + sbt->backend->updateShaderBindingTable(sbt, count, infos); } // ================================================== // Utils // ================================================== -PalBool PAL_CALL palBuildWorkGroupInfo( +void PAL_CALL palBuildWorkGroupInfo( const PalWorkGroupBuildData* data, - int32_t* count, + uint32_t* count, PalWorkGroupInfo* infos) { - if (!data) { - return PAL_FALSE; - } - - if (*count == 0 && infos) { - return PAL_FALSE; - } - uint32_t workGroupCount[3]; uint32_t groupInfoCount[3]; for (int i = 0; i < 3; i++) { - uint32_t tmp = _ceil(data->workCount[i], data->workGroupSize[i]); + uint32_t tmp = ceil(data->workCount[i], data->workGroupSize[i]); workGroupCount[i] = tmp; - groupInfoCount[i] = _ceil(tmp, data->workGroupCount[i]); + groupInfoCount[i] = ceil(tmp, data->workGroupCount[i]); } if (!infos) { // total number of group build info on all axis *count = groupInfoCount[0] * groupInfoCount[1] * groupInfoCount[2]; - ; - return PAL_TRUE; + return; } for (int i = 0; i < *count; i++) { @@ -2976,9 +1858,7 @@ PalBool PAL_CALL palBuildWorkGroupInfo( buildInfo->workGroupBase[j] = index[j] * data->workGroupCount[j]; uint32_t tmp = workGroupCount[j] - buildInfo->workGroupBase[j]; - buildInfo->workGroupCount[j] = _min(data->workGroupCount[j], tmp); + buildInfo->workGroupCount[j] = min(data->workGroupCount[j], tmp); } } - - return PAL_TRUE; } diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index 674b0b5b..16c0402e 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -12,7 +12,7 @@ // clang-format off typedef struct { - PalResult (PAL_CALL *enumerateAdapters)(int32_t*, PalAdapter**); + PalResult (PAL_CALL *enumerateAdapters)(uint32_t*, PalAdapter**); void (PAL_CALL *getAdapterInfo)(PalAdapter*, PalAdapterInfo*); void (PAL_CALL *getAdapterCapabilities)(PalAdapter*, PalAdapterCapabilities*); PalAdapterFeatures (PAL_CALL *getAdapterFeatures)(PalAdapter*); @@ -20,28 +20,28 @@ typedef struct { PalResult (PAL_CALL *createDevice)(PalAdapter*, PalAdapterFeatures, PalDevice**); void (PAL_CALL *destroyDevice)(PalDevice*); PalResult (PAL_CALL *allocateMemory)(PalDevice*, PalMemoryType, uint64_t, uint64_t, PalMemory**); - void (PAL_CALL *freeMemory)(PalDevice*, PalMemory*); - PalResult (PAL_CALL *querySamplerAnisotropyCapabilities)(PalDevice*, PalSamplerAnisotropyCapabilities*); - PalResult (PAL_CALL *queryMultiViewCapabilities)(PalDevice*, PalMultiViewCapabilities*); - PalResult (PAL_CALL *queryMultiViewportCapabilities)(PalDevice*, PalMultiViewportCapabilities*); - PalResult (PAL_CALL *queryDepthStencilCapabilities)(PalDevice*, PalDepthStencilCapabilities*); - PalResult (PAL_CALL *queryFragmentShadingRateCapabilities)(PalDevice*, PalFragmentShadingRateCapabilities*); - PalResult (PAL_CALL *queryMeshShaderCapabilities)(PalDevice*, PalMeshShaderCapabilities*); - PalResult (PAL_CALL *queryRayTracingCapabilities)(PalDevice*, PalRayTracingCapabilities*); - PalResult (PAL_CALL *queryDescriptorIndexingCapabilities)(PalDevice*, PalDescriptorIndexingCapabilities*); + void (PAL_CALL *freeMemory)(PalMemory*); + void (PAL_CALL *querySamplerAnisotropyCapabilities)(PalDevice*, PalSamplerAnisotropyCapabilities*); + void (PAL_CALL *queryMultiViewCapabilities)(PalDevice*, PalMultiViewCapabilities*); + void (PAL_CALL *queryMultiViewportCapabilities)(PalDevice*, PalMultiViewportCapabilities*); + void (PAL_CALL *queryDepthStencilCapabilities)(PalDevice*, PalDepthStencilCapabilities*); + void (PAL_CALL *queryFragmentShadingRateCapabilities)(PalDevice*, PalFragmentShadingRateCapabilities*); + void (PAL_CALL *queryMeshShaderCapabilities)(PalDevice*, PalMeshShaderCapabilities*); + void (PAL_CALL *queryRayTracingCapabilities)(PalDevice*, PalRayTracingCapabilities*); + void (PAL_CALL *queryDescriptorIndexingCapabilities)(PalDevice*, PalDescriptorIndexingCapabilities*); PalResult (PAL_CALL *createQueue)(PalDevice*, PalQueueType, PalQueue**); void (PAL_CALL *destroyQueue)(PalQueue*); PalBool (PAL_CALL *canQueuePresent)(PalQueue*, PalSurface*); PalResult (PAL_CALL *waitQueue)(PalQueue*); - void (PAL_CALL *enumerateFormats)(PalAdapter*, int32_t*, PalFormatInfo*); + void (PAL_CALL *enumerateFormats)(PalAdapter*, uint32_t*, PalFormatInfo*); PalBool (PAL_CALL *isFormatSupported)(PalAdapter*, PalFormat); PalImageUsages (PAL_CALL *queryFormatImageUsages)(PalAdapter*, PalFormat); PalSampleCount (PAL_CALL *queryFormatSampleCount)(PalAdapter*, PalFormat); PalResult (PAL_CALL *createImage)(PalDevice*, const PalImageCreateInfo*, PalImage**); void (PAL_CALL *destroyImage)(PalImage*); - PalResult (PAL_CALL *getImageInfo)(PalImage*, PalImageInfo*); - PalResult (PAL_CALL *getImageMemoryRequirements)(PalImage*, PalMemoryRequirements*); + void (PAL_CALL *getImageInfo)(PalImage*, PalImageInfo*); + void (PAL_CALL *getImageMemoryRequirements)(PalImage*, PalMemoryRequirements*); PalResult (PAL_CALL *bindImageMemory)(PalImage*, PalMemory*, uint64_t); PalResult (PAL_CALL *createImageView)(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); void (PAL_CALL *destroyImageView)(PalImageView*); @@ -50,7 +50,7 @@ typedef struct { void (PAL_CALL *destroySampler)(PalSampler*); PalResult (PAL_CALL *createSurface)(PalDevice*, void*, void*, PalWindowInstanceType, PalSurface**); void (PAL_CALL *destroySurface)(PalSurface*); - PalResult (PAL_CALL *getSurfaceCapabilities)(PalDevice*, PalSurface*, PalSurfaceCapabilities*); + void (PAL_CALL *getSurfaceCapabilities)(PalDevice*, PalSurface*, PalSurfaceCapabilities*); PalResult (PAL_CALL *createSwapchain)(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); void (PAL_CALL *destroySwapchain)(PalSwapchain*); PalImage* (PAL_CALL *getSwapchainImage)(PalSwapchain*, uint32_t); @@ -80,56 +80,56 @@ typedef struct { PalResult (PAL_CALL *cmdBegin)(PalCommandBuffer*, PalRenderingLayoutInfo*); PalResult (PAL_CALL *cmdEnd)(PalCommandBuffer*); - PalResult (PAL_CALL *cmdExecuteCommandBuffer)(PalCommandBuffer*, PalCommandBuffer*); - PalResult (PAL_CALL *cmdSetFragmentShadingRate)(PalCommandBuffer*, PalFragmentShadingRateState*); - PalResult (PAL_CALL *cmdDrawMeshTasks)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); - PalResult (PAL_CALL *cmdDrawMeshTasksIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); - PalResult (PAL_CALL *cmdDrawMeshTasksIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); - PalResult (PAL_CALL *cmdBuildAccelerationStructure)(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); - PalResult (PAL_CALL *cmdBeginRendering)(PalCommandBuffer*, PalRenderingInfo*); - PalResult (PAL_CALL *cmdEndRendering)(PalCommandBuffer*); - PalResult (PAL_CALL *cmdCopyBuffer)(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); - PalResult (PAL_CALL *cmdCopyBufferToImage)(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); - PalResult (PAL_CALL *cmdCopyImage)(PalCommandBuffer*, PalImage*,PalImage*, PalImageCopyInfo*); - PalResult (PAL_CALL *cmdCopyImageToBuffer)(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); - PalResult (PAL_CALL *cmdBindPipeline)(PalCommandBuffer*, PalPipeline*); - PalResult (PAL_CALL *cmdSetViewport)(PalCommandBuffer*, uint32_t, PalViewport*); - PalResult (PAL_CALL *cmdSetScissors)(PalCommandBuffer*, uint32_t, PalRect2D*); - PalResult (PAL_CALL *cmdBindVertexBuffers)(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); - PalResult (PAL_CALL *cmdBindIndexBuffer)(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); - PalResult (PAL_CALL *cmdDraw)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); - PalResult (PAL_CALL *cmdDrawIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); - PalResult (PAL_CALL *cmdDrawIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); - PalResult (PAL_CALL *cmdDrawIndexed)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); - PalResult (PAL_CALL *cmdDrawIndexedIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); - PalResult (PAL_CALL *cmdDrawIndexedIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); - PalResult (PAL_CALL *cmdAccelerationStructureBarrier)(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); - PalResult (PAL_CALL *cmdImageBarrier)(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); - PalResult (PAL_CALL *cmdBufferBarrier)(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); - PalResult (PAL_CALL *cmdDispatch)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); - PalResult (PAL_CALL *cmdDispatchBase)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); - PalResult (PAL_CALL *cmdDispatchIndirect)(PalCommandBuffer*, PalBuffer*); - PalResult (PAL_CALL *cmdTraceRays)(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); - PalResult (PAL_CALL *cmdTraceRaysIndirect)(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); - PalResult (PAL_CALL *cmdBindDescriptorSet)(PalCommandBuffer*, uint32_t, PalDescriptorSet*); - PalResult (PAL_CALL *cmdPushConstants)(PalCommandBuffer*, uint32_t, uint32_t, const void*); - PalResult (PAL_CALL *cmdSetCullMode)(PalCommandBuffer*, PalCullMode); - PalResult (PAL_CALL *cmdSetFrontFace)(PalCommandBuffer*, PalFrontFace); - PalResult (PAL_CALL *cmdSetPrimitiveTopology)(PalCommandBuffer*, PalPrimitiveTopology); - PalResult (PAL_CALL *cmdSetDepthTestEnable)(PalCommandBuffer*, PalBool); - PalResult (PAL_CALL *cmdSetDepthWriteEnable)(PalCommandBuffer*, PalBool); - PalResult (PAL_CALL *cmdSetStencilOp)(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); + void (PAL_CALL *cmdExecuteCommandBuffer)(PalCommandBuffer*, PalCommandBuffer*); + void (PAL_CALL *cmdSetFragmentShadingRate)(PalCommandBuffer*, PalFragmentShadingRateState*); + void (PAL_CALL *cmdDrawMeshTasks)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); + void (PAL_CALL *cmdDrawMeshTasksIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); + void (PAL_CALL *cmdDrawMeshTasksIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); + void (PAL_CALL *cmdBuildAccelerationStructure)(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); + void (PAL_CALL *cmdBeginRendering)(PalCommandBuffer*, PalRenderingInfo*); + void (PAL_CALL *cmdEndRendering)(PalCommandBuffer*); + void (PAL_CALL *cmdCopyBuffer)(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); + void (PAL_CALL *cmdCopyBufferToImage)(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); + void (PAL_CALL *cmdCopyImage)(PalCommandBuffer*, PalImage*,PalImage*, PalImageCopyInfo*); + void (PAL_CALL *cmdCopyImageToBuffer)(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); + void (PAL_CALL *cmdBindPipeline)(PalCommandBuffer*, PalPipeline*); + void (PAL_CALL *cmdSetViewport)(PalCommandBuffer*, uint32_t, PalViewport*); + void (PAL_CALL *cmdSetScissors)(PalCommandBuffer*, uint32_t, PalRect2D*); + void (PAL_CALL *cmdBindVertexBuffers)(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); + void (PAL_CALL *cmdBindIndexBuffer)(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); + void (PAL_CALL *cmdDraw)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); + void (PAL_CALL *cmdDrawIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); + void (PAL_CALL *cmdDrawIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); + void (PAL_CALL *cmdDrawIndexed)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); + void (PAL_CALL *cmdDrawIndexedIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); + void (PAL_CALL *cmdDrawIndexedIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); + void (PAL_CALL *cmdAccelerationStructureBarrier)(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); + void (PAL_CALL *cmdImageBarrier)(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); + void (PAL_CALL *cmdBufferBarrier)(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); + void (PAL_CALL *cmdDispatch)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); + void (PAL_CALL *cmdDispatchBase)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); + void (PAL_CALL *cmdDispatchIndirect)(PalCommandBuffer*, PalBuffer*); + void (PAL_CALL *cmdTraceRays)(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); + void (PAL_CALL *cmdTraceRaysIndirect)(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); + void (PAL_CALL *cmdBindDescriptorSet)(PalCommandBuffer*, uint32_t, PalDescriptorSet*); + void (PAL_CALL *cmdPushConstants)(PalCommandBuffer*, uint32_t, uint32_t, const void*); + void (PAL_CALL *cmdSetCullMode)(PalCommandBuffer*, PalCullMode); + void (PAL_CALL *cmdSetFrontFace)(PalCommandBuffer*, PalFrontFace); + void (PAL_CALL *cmdSetPrimitiveTopology)(PalCommandBuffer*, PalPrimitiveTopology); + void (PAL_CALL *cmdSetDepthTestEnable)(PalCommandBuffer*, PalBool); + void (PAL_CALL *cmdSetDepthWriteEnable)(PalCommandBuffer*, PalBool); + void (PAL_CALL *cmdSetStencilOp)(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); PalResult (PAL_CALL *createAccelerationstructure)(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); void (PAL_CALL *destroyAccelerationstructure)(PalAccelerationStructure*); void (PAL_CALL *getAccelerationStructureBuildSize)(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); PalResult (PAL_CALL *createBuffer)(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); void (PAL_CALL *destroyBuffer)(PalBuffer*); - PalResult (PAL_CALL *getBufferMemoryRequirements)(PalBuffer*, PalMemoryRequirements*); - PalResult (PAL_CALL *computeInstanceBufferRequirements)(PalDevice*, uint32_t, uint64_t*); - PalResult (PAL_CALL *computeImageCopyStagingBufferRequirements)(PalDevice*, PalFormat, PalBufferImageCopyInfo*, uint32_t*, uint32_t*, uint64_t*); - PalResult (PAL_CALL *writeToInstanceBuffer)(PalDevice*, void*, PalAccelerationStructureInstance*, uint32_t); - PalResult (PAL_CALL *writeToImageCopyStagingBuffer)(PalDevice*, void*, void*, PalFormat, PalBufferImageCopyInfo*); + void (PAL_CALL *getBufferMemoryRequirements)(PalBuffer*, PalMemoryRequirements*); + void(PAL_CALL* computeInstanceStagingSize)(PalDevice*, uint32_t, uint64_t*); + void(PAL_CALL* computeImageStagingRequirements)(PalDevice*, PalFormat, const PalBufferImageCopyInfo*, PalImageStagingRequirements*); + void(PAL_CALL* writeInstanceStaging)(PalDevice*, uint32_t, PalAccelerationStructureInstance*, void*); + void(PAL_CALL* writeImageStaging)(PalDevice*, PalFormat, PalBufferImageCopyInfo*, void*, void*); PalResult (PAL_CALL *bindBufferMemory)(PalBuffer*, PalMemory*, uint64_t); PalResult (PAL_CALL *mapBuffer)(PalBuffer*, uint64_t, uint64_t, void**); void (PAL_CALL *unmapBuffer)(PalBuffer*); @@ -151,7 +151,7 @@ typedef struct { void (PAL_CALL *destroyPipeline)(PalPipeline*); PalResult (PAL_CALL *createShaderBindingTable)(PalDevice*, const PalShaderBindingTableCreateInfo*, PalShaderBindingTable**); void (PAL_CALL *destroyShaderBindingTable)(PalShaderBindingTable*); - PalResult (PAL_CALL *updateShaderBindingTable)(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); + void (PAL_CALL *updateShaderBindingTable)(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); } PalGraphicsVtable; // ================================================== @@ -161,7 +161,7 @@ typedef struct { #if PAL_HAS_VULKAN_BACKEND PalResult PAL_CALL initGraphicsVk(const PalGraphicsDebugger*, const PalAllocator*); void PAL_CALL shutdownGraphicsVk(); -PalResult PAL_CALL enumerateAdaptersVk(int32_t*, PalAdapter**); +PalResult PAL_CALL enumerateAdaptersVk(uint32_t*, PalAdapter**); void PAL_CALL getAdapterInfoVk(PalAdapter*, PalAdapterInfo*); void PAL_CALL getAdapterCapabilitiesVk(PalAdapter*, PalAdapterCapabilities*); PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter*); @@ -170,28 +170,28 @@ PalResult PAL_CALL createDeviceVk(PalAdapter*, PalAdapterFeatures, PalDevice**); void PAL_CALL destroyDeviceVk(PalDevice*); PalResult PAL_CALL waitDeviceVk(PalDevice*); PalResult PAL_CALL allocateMemoryVk(PalDevice*, PalMemoryType, uint64_t, uint64_t, PalMemory**); -void PAL_CALL freeMemoryVk(PalDevice*, PalMemory*); -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk(PalDevice*, PalSamplerAnisotropyCapabilities*); -PalResult PAL_CALL queryMultiViewCapabilitiesVk(PalDevice*, PalMultiViewCapabilities*); -PalResult PAL_CALL queryMultiViewportCapabilitiesVk(PalDevice*, PalMultiViewportCapabilities*); -PalResult PAL_CALL queryDepthStencilCapabilitiesVk(PalDevice*, PalDepthStencilCapabilities*); -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk(PalDevice*, PalFragmentShadingRateCapabilities*); -PalResult PAL_CALL queryMeshShaderCapabilitiesVk(PalDevice*, PalMeshShaderCapabilities*); -PalResult PAL_CALL queryRayTracingCapabilitiesVk(PalDevice*, PalRayTracingCapabilities*); -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk(PalDevice*, PalDescriptorIndexingCapabilities*); +void PAL_CALL freeMemoryVk(PalMemory*); +void PAL_CALL querySamplerAnisotropyCapabilitiesVk(PalDevice*, PalSamplerAnisotropyCapabilities*); +void PAL_CALL queryMultiViewCapabilitiesVk(PalDevice*, PalMultiViewCapabilities*); +void PAL_CALL queryMultiViewportCapabilitiesVk(PalDevice*, PalMultiViewportCapabilities*); +void PAL_CALL queryDepthStencilCapabilitiesVk(PalDevice*, PalDepthStencilCapabilities*); +void PAL_CALL queryFragmentShadingRateCapabilitiesVk(PalDevice*, PalFragmentShadingRateCapabilities*); +void PAL_CALL queryMeshShaderCapabilitiesVk(PalDevice*, PalMeshShaderCapabilities*); +void PAL_CALL queryRayTracingCapabilitiesVk(PalDevice*, PalRayTracingCapabilities*); +void PAL_CALL queryDescriptorIndexingCapabilitiesVk(PalDevice*, PalDescriptorIndexingCapabilities*); PalResult PAL_CALL createQueueVk(PalDevice*, PalQueueType, PalQueue**); void PAL_CALL destroyQueueVk(PalQueue*); PalResult PAL_CALL waitQueueVk(PalQueue*); PalBool PAL_CALL canQueuePresentVk(PalQueue*, PalSurface*); -void PAL_CALL enumerateFormatsVk(PalAdapter*, int32_t*, PalFormatInfo*); +void PAL_CALL enumerateFormatsVk(PalAdapter*, uint32_t*, PalFormatInfo*); PalBool PAL_CALL isFormatSupportedVk(PalAdapter*, PalFormat); PalImageUsages PAL_CALL queryFormatImageUsagesVk(PalAdapter*, PalFormat); PalSampleCount PAL_CALL queryFormatSampleCountVk(PalAdapter*, PalFormat); PalResult PAL_CALL createImageVk(PalDevice*, const PalImageCreateInfo*, PalImage**); void PAL_CALL destroyImageVk(PalImage*); -PalResult PAL_CALL getImageInfoVk(PalImage*, PalImageInfo*); -PalResult PAL_CALL getImageMemoryRequirementsVk(PalImage*, PalMemoryRequirements*); +void PAL_CALL getImageInfoVk(PalImage*, PalImageInfo*); +void PAL_CALL getImageMemoryRequirementsVk(PalImage*, PalMemoryRequirements*); PalResult PAL_CALL bindImageMemoryVk(PalImage*, PalMemory*, uint64_t); PalResult PAL_CALL createImageViewVk(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); void PAL_CALL destroyImageViewVk(PalImageView*); @@ -200,7 +200,7 @@ PalResult PAL_CALL createSamplerVk(PalDevice*, const PalSamplerCreateInfo*, PalS void PAL_CALL destroySamplerVk(PalSampler*); PalResult PAL_CALL createSurfaceVk(PalDevice*, void*, void*, PalWindowInstanceType, PalSurface**); void PAL_CALL destroySurfaceVk(PalSurface*); -PalResult PAL_CALL getSurfaceCapabilitiesVk(PalDevice*, PalSurface*, PalSurfaceCapabilities*); +void PAL_CALL getSurfaceCapabilitiesVk(PalDevice*, PalSurface*, PalSurfaceCapabilities*); PalResult PAL_CALL createSwapchainVk(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); void PAL_CALL destroySwapchainVk(PalSwapchain*); PalImage* PAL_CALL getSwapchainImageVk(PalSwapchain*, uint32_t); @@ -230,56 +230,56 @@ PalResult PAL_CALL submitCommandBufferVk(PalQueue*, PalCommandBufferSubmitInfo*) PalResult PAL_CALL cmdBeginVk(PalCommandBuffer*, PalRenderingLayoutInfo*); PalResult PAL_CALL cmdEndVk(PalCommandBuffer*); -PalResult PAL_CALL cmdExecuteCommandBufferVk(PalCommandBuffer*, PalCommandBuffer*); -PalResult PAL_CALL cmdSetFragmentShadingRateVk(PalCommandBuffer*, PalFragmentShadingRateState*); -PalResult PAL_CALL cmdDrawMeshTasksVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); -PalResult PAL_CALL cmdDrawMeshTasksIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdBuildAccelerationStructureVk(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); -PalResult PAL_CALL cmdBeginRenderingVk(PalCommandBuffer*, PalRenderingInfo*); -PalResult PAL_CALL cmdEndRenderingVk(PalCommandBuffer*); -PalResult PAL_CALL cmdCopyBufferVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); -PalResult PAL_CALL cmdCopyBufferToImageVk(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); -PalResult PAL_CALL cmdCopyImageVk(PalCommandBuffer*, PalImage*, PalImage*, PalImageCopyInfo*); -PalResult PAL_CALL cmdCopyImageToBufferVk(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); -PalResult PAL_CALL cmdBindPipelineVk(PalCommandBuffer*, PalPipeline*); -PalResult PAL_CALL cmdSetViewportVk(PalCommandBuffer*, uint32_t, PalViewport*); -PalResult PAL_CALL cmdSetScissorsVk(PalCommandBuffer*, uint32_t, PalRect2D*); -PalResult PAL_CALL cmdBindVertexBuffersVk(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); -PalResult PAL_CALL cmdBindIndexBufferVk(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); -PalResult PAL_CALL cmdDrawVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); -PalResult PAL_CALL cmdDrawIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdDrawIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdDrawIndexedVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); -PalResult PAL_CALL cmdDrawIndexedIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdDrawIndexedIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdAccelerationStructureBarrierVk(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); -PalResult PAL_CALL cmdImageBarrierVk(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); -PalResult PAL_CALL cmdBufferBarrierVk(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); -PalResult PAL_CALL cmdDispatchVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); -PalResult PAL_CALL cmdDispatchBaseVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); -PalResult PAL_CALL cmdDispatchIndirectVk(PalCommandBuffer*, PalBuffer*); -PalResult PAL_CALL cmdTraceRaysVk(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); -PalResult PAL_CALL cmdTraceRaysIndirectVk(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); -PalResult PAL_CALL cmdBindDescriptorSetVk(PalCommandBuffer*, uint32_t, PalDescriptorSet*); -PalResult PAL_CALL cmdPushConstantsVk(PalCommandBuffer*, uint32_t, uint32_t, const void*); -PalResult PAL_CALL cmdSetCullModeVk(PalCommandBuffer*, PalCullMode); -PalResult PAL_CALL cmdSetFrontFaceVk(PalCommandBuffer*, PalFrontFace); -PalResult PAL_CALL cmdSetPrimitiveTopologyVk(PalCommandBuffer*, PalPrimitiveTopology); -PalResult PAL_CALL cmdSetDepthTestEnableVk(PalCommandBuffer*, PalBool); -PalResult PAL_CALL cmdSetDepthWriteEnableVk(PalCommandBuffer*, PalBool); -PalResult PAL_CALL cmdSetStencilOpVk(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); +void PAL_CALL cmdExecuteCommandBufferVk(PalCommandBuffer*, PalCommandBuffer*); +void PAL_CALL cmdSetFragmentShadingRateVk(PalCommandBuffer*, PalFragmentShadingRateState*); +void PAL_CALL cmdDrawMeshTasksVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); +void PAL_CALL cmdDrawMeshTasksIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdDrawMeshTasksIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdBuildAccelerationStructureVk(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); +void PAL_CALL cmdBeginRenderingVk(PalCommandBuffer*, PalRenderingInfo*); +void PAL_CALL cmdEndRenderingVk(PalCommandBuffer*); +void PAL_CALL cmdCopyBufferVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); +void PAL_CALL cmdCopyBufferToImageVk(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); +void PAL_CALL cmdCopyImageVk(PalCommandBuffer*, PalImage*, PalImage*, PalImageCopyInfo*); +void PAL_CALL cmdCopyImageToBufferVk(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); +void PAL_CALL cmdBindPipelineVk(PalCommandBuffer*, PalPipeline*); +void PAL_CALL cmdSetViewportVk(PalCommandBuffer*, uint32_t, PalViewport*); +void PAL_CALL cmdSetScissorsVk(PalCommandBuffer*, uint32_t, PalRect2D*); +void PAL_CALL cmdBindVertexBuffersVk(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); +void PAL_CALL cmdBindIndexBufferVk(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); +void PAL_CALL cmdDrawVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); +void PAL_CALL cmdDrawIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdDrawIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdDrawIndexedVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); +void PAL_CALL cmdDrawIndexedIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdDrawIndexedIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdAccelerationStructureBarrierVk(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); +void PAL_CALL cmdImageBarrierVk(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); +void PAL_CALL cmdBufferBarrierVk(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); +void PAL_CALL cmdDispatchVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); +void PAL_CALL cmdDispatchBaseVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); +void PAL_CALL cmdDispatchIndirectVk(PalCommandBuffer*, PalBuffer*); +void PAL_CALL cmdTraceRaysVk(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); +void PAL_CALL cmdTraceRaysIndirectVk(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); +void PAL_CALL cmdBindDescriptorSetVk(PalCommandBuffer*, uint32_t, PalDescriptorSet*); +void PAL_CALL cmdPushConstantsVk(PalCommandBuffer*, uint32_t, uint32_t, const void*); +void PAL_CALL cmdSetCullModeVk(PalCommandBuffer*, PalCullMode); +void PAL_CALL cmdSetFrontFaceVk(PalCommandBuffer*, PalFrontFace); +void PAL_CALL cmdSetPrimitiveTopologyVk(PalCommandBuffer*, PalPrimitiveTopology); +void PAL_CALL cmdSetDepthTestEnableVk(PalCommandBuffer*, PalBool); +void PAL_CALL cmdSetDepthWriteEnableVk(PalCommandBuffer*, PalBool); +void PAL_CALL cmdSetStencilOpVk(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); PalResult PAL_CALL createAccelerationstructureVk(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure*); PalResult PAL_CALL getAccelerationStructureBuildSizeVk(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); PalResult PAL_CALL createBufferVk(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); void PAL_CALL destroyBufferVk(PalBuffer*); -PalResult PAL_CALL getBufferMemoryRequirementsVk(PalBuffer*, PalMemoryRequirements*); -PalResult PAL_CALL computeInstanceBufferRequirementsVk(PalDevice*, uint32_t, uint64_t*); -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk(PalDevice*, PalFormat, PalBufferImageCopyInfo*, uint32_t*, uint32_t*, uint64_t*); -PalResult PAL_CALL writeToInstanceBufferVk(PalDevice*, void*, PalAccelerationStructureInstance*, uint32_t); -PalResult PAL_CALL writeToImageCopyStagingBufferVk(PalDevice*, void*, void*, PalFormat, PalBufferImageCopyInfo*); +void PAL_CALL getBufferMemoryRequirementsVk(PalBuffer*, PalMemoryRequirements*); +void PAL_CALL computeInstanceStagingSizeVk(PalDevice*, uint32_t, uint64_t*); +void PAL_CALL computeImageStagingRequirementsVk(PalDevice*, PalFormat, const PalBufferImageCopyInfo*, PalImageStagingRequirements*); +void PAL_CALL writeInstanceStagingVk(PalDevice*, uint32_t, PalAccelerationStructureInstance*, void*); +void PAL_CALL writeImageStagingVk(PalDevice*, PalFormat, PalBufferImageCopyInfo*, void*, void*); PalResult PAL_CALL bindBufferMemoryVk(PalBuffer*, PalMemory*, uint64_t); PalResult PAL_CALL mapBufferVk(PalBuffer*, uint64_t, uint64_t, void**); void PAL_CALL unmapBufferVk(PalBuffer*); @@ -300,7 +300,7 @@ PalResult PAL_CALL createRayTracingPipelineVk(PalDevice*, const PalRayTracingPip void PAL_CALL destroyPipelineVk(PalPipeline*); PalResult PAL_CALL createShaderBindingTableVk(PalDevice*, const PalShaderBindingTableCreateInfo*, PalShaderBindingTable**); void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable*); -PalResult PAL_CALL updateShaderBindingTableVk(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); +void PAL_CALL updateShaderBindingTableVk(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); static PalGraphicsVtable s_VkBackend = { .enumerateAdapters = enumerateAdaptersVk, @@ -412,10 +412,10 @@ static PalGraphicsVtable s_VkBackend = { .createBuffer = createBufferVk, .destroyBuffer = destroyBufferVk, .getBufferMemoryRequirements = getBufferMemoryRequirementsVk, - .computeInstanceBufferRequirements = computeInstanceBufferRequirementsVk, - .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsVk, - .writeToInstanceBuffer = writeToInstanceBufferVk, - .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferVk, + .computeInstanceStagingSize = computeInstanceStagingSizeVk, + .computeImageStagingRequirements = computeImageStagingRequirementsVk, + .writeInstanceStaging = writeInstanceStagingVk, + .writeImageStaging = writeImageStagingVk, .bindBufferMemory = bindBufferMemoryVk, .getBufferDeviceAddress = getBufferDeviceAddressVk, .mapBuffer = mapBufferVk, @@ -446,9 +446,9 @@ static PalGraphicsVtable s_VkBackend = { #if PAL_HAS_D3D12_BACKEND PalResult PAL_CALL initGraphicsD3D12(const PalGraphicsDebugger*, const PalAllocator*); void PAL_CALL shutdownGraphicsD3D12(); -PalResult PAL_CALL enumerateAdaptersD3D12(int32_t*, PalAdapter**); -PalResult PAL_CALL getAdapterInfoD3D12(PalAdapter*, PalAdapterInfo*); -PalResult PAL_CALL getAdapterCapabilitiesD3D12(PalAdapter*, PalAdapterCapabilities*); +PalResult PAL_CALL enumerateAdaptersD3D12(uint32_t*, PalAdapter**); +void PAL_CALL getAdapterInfoD3D12(PalAdapter*, PalAdapterInfo*); +void PAL_CALL getAdapterCapabilitiesD3D12(PalAdapter*, PalAdapterCapabilities*); PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter*); uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12(PalAdapter*, PalShaderFormats); PalResult PAL_CALL createDeviceD3D12(PalAdapter*, PalAdapterFeatures, PalDevice**); @@ -456,27 +456,27 @@ void PAL_CALL destroyDeviceD3D12(PalDevice*); PalResult PAL_CALL waitDeviceD3D12(PalDevice*); PalResult PAL_CALL allocateMemoryD3D12(PalDevice*, PalMemoryType, uint64_t, uint64_t, PalMemory**); void PAL_CALL freeMemoryD3D12(PalDevice*, PalMemory*); -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12(PalDevice*, PalSamplerAnisotropyCapabilities*); -PalResult PAL_CALL queryMultiViewCapabilitiesD3D12(PalDevice*, PalMultiViewCapabilities*); -PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12(PalDevice*, PalMultiViewportCapabilities*); -PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12(PalDevice*, PalDepthStencilCapabilities*); -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12(PalDevice*, PalFragmentShadingRateCapabilities*); -PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12(PalDevice*, PalMeshShaderCapabilities*); -PalResult PAL_CALL queryRayTracingCapabilitiesD3D12(PalDevice*, PalRayTracingCapabilities*); -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12(PalDevice*, PalDescriptorIndexingCapabilities*); +void PAL_CALL querySamplerAnisotropyCapabilitiesD3D12(PalDevice*, PalSamplerAnisotropyCapabilities*); +void PAL_CALL queryMultiViewCapabilitiesD3D12(PalDevice*, PalMultiViewCapabilities*); +void PAL_CALL queryMultiViewportCapabilitiesD3D12(PalDevice*, PalMultiViewportCapabilities*); +void PAL_CALL queryDepthStencilCapabilitiesD3D12(PalDevice*, PalDepthStencilCapabilities*); +void PAL_CALL queryFragmentShadingRateCapabilitiesD3D12(PalDevice*, PalFragmentShadingRateCapabilities*); +void PAL_CALL queryMeshShaderCapabilitiesD3D12(PalDevice*, PalMeshShaderCapabilities*); +void PAL_CALL queryRayTracingCapabilitiesD3D12(PalDevice*, PalRayTracingCapabilities*); +void PAL_CALL queryDescriptorIndexingCapabilitiesD3D12(PalDevice*, PalDescriptorIndexingCapabilities*); PalResult PAL_CALL createQueueD3D12(PalDevice*, PalQueueType, PalQueue**); void PAL_CALL destroyQueueD3D12(PalQueue*); PalResult PAL_CALL waitQueueD3D12(PalQueue*); PalBool PAL_CALL canQueuePresentD3D12(PalQueue*, PalSurface*); -void PAL_CALL enumerateFormatsD3D12(PalAdapter*, int32_t*, PalFormatInfo*); +void PAL_CALL enumerateFormatsD3D12(PalAdapter*, uint32_t*, PalFormatInfo*); PalBool PAL_CALL isFormatSupportedD3D12(PalAdapter*, PalFormat); PalImageUsages PAL_CALL queryFormatImageUsagesD3D12(PalAdapter*, PalFormat); PalSampleCount PAL_CALL queryFormatSampleCountD3D12(PalAdapter*, PalFormat); PalResult PAL_CALL createImageD3D12(PalDevice*, const PalImageCreateInfo*, PalImage**); void PAL_CALL destroyImageD3D12(PalImage*); -PalResult PAL_CALL getImageInfoD3D12(PalImage*, PalImageInfo*); -PalResult PAL_CALL getImageMemoryRequirementsD3D12(PalImage*, PalMemoryRequirements*); +void PAL_CALL getImageInfoD3D12(PalImage*, PalImageInfo*); +void PAL_CALL getImageMemoryRequirementsD3D12(PalImage*, PalMemoryRequirements*); PalResult PAL_CALL bindImageMemoryD3D12(PalImage*, PalMemory*, uint64_t); PalResult PAL_CALL createImageViewD3D12(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); void PAL_CALL destroyImageViewD3D12(PalImageView*); @@ -485,7 +485,7 @@ PalResult PAL_CALL createSamplerD3D12(PalDevice*, const PalSamplerCreateInfo*, P void PAL_CALL destroySamplerD3D12(PalSampler*); PalResult PAL_CALL createSurfaceD3D12(PalDevice*, void*, void*, PalWindowInstanceType, PalSurface**); void PAL_CALL destroySurfaceD3D12(PalSurface*); -PalResult PAL_CALL getSurfaceCapabilitiesD3D12(PalDevice*, PalSurface*, PalSurfaceCapabilities*); +void PAL_CALL getSurfaceCapabilitiesD3D12(PalDevice*, PalSurface*, PalSurfaceCapabilities*); PalResult PAL_CALL createSwapchainD3D12(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); void PAL_CALL destroySwapchainD3D12(PalSwapchain*); PalImage* PAL_CALL getSwapchainImageD3D12(PalSwapchain*, uint32_t); @@ -513,58 +513,58 @@ void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer*); PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer*); PalResult PAL_CALL submitCommandBufferD3D12(PalQueue*, PalCommandBufferSubmitInfo*); -PalResult PAL_CALL cmdBeginD3D12(PalCommandBuffer*, PalRenderingLayoutInfo*); -PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer*); -PalResult PAL_CALL cmdExecuteCommandBufferD3D12(PalCommandBuffer*, PalCommandBuffer*); -PalResult PAL_CALL cmdSetFragmentShadingRateD3D12(PalCommandBuffer*, PalFragmentShadingRateState*); -PalResult PAL_CALL cmdDrawMeshTasksD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); -PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdBuildAccelerationStructureD3D12(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); -PalResult PAL_CALL cmdBeginRenderingD3D12(PalCommandBuffer*, PalRenderingInfo*); -PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer*); -PalResult PAL_CALL cmdCopyBufferD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); -PalResult PAL_CALL cmdCopyBufferToImageD3D12(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); -PalResult PAL_CALL cmdCopyImageD3D12(PalCommandBuffer*, PalImage*, PalImage*, PalImageCopyInfo*); -PalResult PAL_CALL cmdCopyImageToBufferD3D12(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); -PalResult PAL_CALL cmdBindPipelineD3D12(PalCommandBuffer*, PalPipeline*); -PalResult PAL_CALL cmdSetViewportD3D12(PalCommandBuffer*, uint32_t, PalViewport*); -PalResult PAL_CALL cmdSetScissorsD3D12(PalCommandBuffer*, uint32_t, PalRect2D*); -PalResult PAL_CALL cmdBindVertexBuffersD3D12(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); -PalResult PAL_CALL cmdBindIndexBufferD3D12(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); -PalResult PAL_CALL cmdDrawD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); -PalResult PAL_CALL cmdDrawIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdDrawIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdDrawIndexedD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); -PalResult PAL_CALL cmdDrawIndexedIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); -PalResult PAL_CALL cmdImageBarrierD3D12(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); -PalResult PAL_CALL cmdBufferBarrierD3D12(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); -PalResult PAL_CALL cmdDispatchD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); -PalResult PAL_CALL cmdDispatchBaseD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); -PalResult PAL_CALL cmdDispatchIndirectD3D12(PalCommandBuffer*, PalBuffer*); -PalResult PAL_CALL cmdTraceRaysD3D12(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); -PalResult PAL_CALL cmdTraceRaysIndirectD3D12(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); -PalResult PAL_CALL cmdBindDescriptorSetD3D12(PalCommandBuffer*, uint32_t, PalDescriptorSet*); -PalResult PAL_CALL cmdPushConstantsD3D12(PalCommandBuffer*, uint32_t, uint32_t, const void*); -PalResult PAL_CALL cmdSetCullModeD3D12(PalCommandBuffer*, PalCullMode); -PalResult PAL_CALL cmdSetFrontFaceD3D12(PalCommandBuffer*, PalFrontFace); -PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12(PalCommandBuffer*, PalPrimitiveTopology); -PalResult PAL_CALL cmdSetDepthTestEnableD3D12(PalCommandBuffer*, PalBool); -PalResult PAL_CALL cmdSetDepthWriteEnableD3D12(PalCommandBuffer*, PalBool); -PalResult PAL_CALL cmdSetStencilOpD3D12(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); +void PAL_CALL cmdBeginD3D12(PalCommandBuffer*, PalRenderingLayoutInfo*); +void PAL_CALL cmdEndD3D12(PalCommandBuffer*); +void PAL_CALL cmdExecuteCommandBufferD3D12(PalCommandBuffer*, PalCommandBuffer*); +void PAL_CALL cmdSetFragmentShadingRateD3D12(PalCommandBuffer*, PalFragmentShadingRateState*); +void PAL_CALL cmdDrawMeshTasksD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); +void PAL_CALL cmdDrawMeshTasksIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdDrawMeshTasksIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdBuildAccelerationStructureD3D12(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); +void PAL_CALL cmdBeginRenderingD3D12(PalCommandBuffer*, PalRenderingInfo*); +void PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer*); +void PAL_CALL cmdCopyBufferD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); +void PAL_CALL cmdCopyBufferToImageD3D12(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); +void PAL_CALL cmdCopyImageD3D12(PalCommandBuffer*, PalImage*, PalImage*, PalImageCopyInfo*); +void PAL_CALL cmdCopyImageToBufferD3D12(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); +void PAL_CALL cmdBindPipelineD3D12(PalCommandBuffer*, PalPipeline*); +void PAL_CALL cmdSetViewportD3D12(PalCommandBuffer*, uint32_t, PalViewport*); +void PAL_CALL cmdSetScissorsD3D12(PalCommandBuffer*, uint32_t, PalRect2D*); +void PAL_CALL cmdBindVertexBuffersD3D12(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); +void PAL_CALL cmdBindIndexBufferD3D12(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); +void PAL_CALL cmdDrawD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); +void PAL_CALL cmdDrawIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdDrawIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdDrawIndexedD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); +void PAL_CALL cmdDrawIndexedIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdDrawIndexedIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); +void PAL_CALL cmdAccelerationStructureBarrierD3D12(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); +void PAL_CALL cmdImageBarrierD3D12(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); +void PAL_CALL cmdBufferBarrierD3D12(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); +void PAL_CALL cmdDispatchD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); +void PAL_CALL cmdDispatchBaseD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); +void PAL_CALL cmdDispatchIndirectD3D12(PalCommandBuffer*, PalBuffer*); +void PAL_CALL cmdTraceRaysD3D12(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); +void PAL_CALL cmdTraceRaysIndirectD3D12(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); +void PAL_CALL cmdBindDescriptorSetD3D12(PalCommandBuffer*, uint32_t, PalDescriptorSet*); +void PAL_CALL cmdPushConstantsD3D12(PalCommandBuffer*, uint32_t, uint32_t, const void*); +void PAL_CALL cmdSetCullModeD3D12(PalCommandBuffer*, PalCullMode); +void PAL_CALL cmdSetFrontFaceD3D12(PalCommandBuffer*, PalFrontFace); +void PAL_CALL cmdSetPrimitiveTopologyD3D12(PalCommandBuffer*, PalPrimitiveTopology); +void PAL_CALL cmdSetDepthTestEnableD3D12(PalCommandBuffer*, PalBool); +void PAL_CALL cmdSetDepthWriteEnableD3D12(PalCommandBuffer*, PalBool); +void PAL_CALL cmdSetStencilOpD3D12(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); PalResult PAL_CALL createAccelerationstructureD3D12(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure*); -PalResult PAL_CALL getAccelerationStructureBuildSizeD3D12(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); +void PAL_CALL getAccelerationStructureBuildSizeD3D12(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); PalResult PAL_CALL createBufferD3D12(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); void PAL_CALL destroyBufferD3D12(PalBuffer*); -PalResult PAL_CALL getBufferMemoryRequirementsD3D12(PalBuffer*, PalMemoryRequirements*); -PalResult PAL_CALL computeInstanceBufferRequirementsD3D12(PalDevice*, uint32_t, uint64_t*); -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12(PalDevice*, PalFormat, PalBufferImageCopyInfo*, uint32_t*, uint32_t*, uint64_t*); -PalResult PAL_CALL writeToInstanceBufferD3D12(PalDevice*, void*, PalAccelerationStructureInstance*, uint32_t); -PalResult PAL_CALL writeToImageCopyStagingBufferD3D12(PalDevice*, void*, void*, PalFormat, PalBufferImageCopyInfo*); +void PAL_CALL getBufferMemoryRequirementsD3D12(PalBuffer*, PalMemoryRequirements*); +void PAL_CALL computeInstanceStagingSizeD3D12(PalDevice*, uint32_t, uint64_t*); +void PAL_CALL computeImageStagingRequirementsD3D12(PalDevice*, PalFormat, const PalBufferImageCopyInfo*, PalImageStagingRequirements*); +void PAL_CALL writeInstanceStagingD3D12(PalDevice*, uint32_t, PalAccelerationStructureInstance*, void*); +void PAL_CALL writeImageStagingD3D12(PalDevice*, PalFormat, PalBufferImageCopyInfo*, void*, void*); PalResult PAL_CALL bindBufferMemoryD3D12(PalBuffer*, PalMemory*, uint64_t); PalResult PAL_CALL mapBufferD3D12(PalBuffer*, uint64_t, uint64_t, void**); void PAL_CALL unmapBufferD3D12(PalBuffer*); @@ -585,7 +585,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12(PalDevice*, const PalRayTracing void PAL_CALL destroyPipelineD3D12(PalPipeline*); PalResult PAL_CALL createShaderBindingTableD3D12(PalDevice*, const PalShaderBindingTableCreateInfo*, PalShaderBindingTable**); void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable*); -PalResult PAL_CALL updateShaderBindingTableD3D12(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); +void PAL_CALL updateShaderBindingTableD3D12(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); static PalGraphicsVtable s_D3D12Backend = { .enumerateAdapters = enumerateAdaptersD3D12, @@ -697,10 +697,10 @@ static PalGraphicsVtable s_D3D12Backend = { .createBuffer = createBufferD3D12, .destroyBuffer = destroyBufferD3D12, .getBufferMemoryRequirements = getBufferMemoryRequirementsD3D12, - .computeInstanceBufferRequirements = computeInstanceBufferRequirementsD3D12, - .computeImageCopyStagingBufferRequirements = computeImageCopyStagingBufferRequirementsD3D12, - .writeToInstanceBuffer = writeToInstanceBufferD3D12, - .writeToImageCopyStagingBuffer = writeToImageCopyStagingBufferD3D12, + .computeInstanceStagingSize = computeInstanceStagingSizeD3D12, + .computeImageStagingRequirements = computeImageStagingRequirementsD3D12, + .writeInstanceStaging = writeInstanceStagingD3D12, + .writeImageStaging = writeImageStagingD3D12, .bindBufferMemory = bindBufferMemoryD3D12, .getBufferDeviceAddress = getBufferDeviceAddressD3D12, .mapBuffer = mapBufferD3D12, From fe1f0730e3a703a482a74b937f9082cf810ec4dd Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 10 Jul 2026 00:16:39 +0000 Subject: [PATCH 326/372] fix system module --- src/system/linux/pal_cpu_linux.c | 18 +++--------------- src/system/linux/pal_platform_linux.c | 12 +++--------- src/system/win32/pal_cpu_win32.c | 19 +++---------------- src/system/win32/pal_platform_win32.c | 13 ++----------- 4 files changed, 11 insertions(+), 51 deletions(-) diff --git a/src/system/linux/pal_cpu_linux.c b/src/system/linux/pal_cpu_linux.c index 7dcb0451..4d98efee 100644 --- a/src/system/linux/pal_cpu_linux.c +++ b/src/system/linux/pal_cpu_linux.c @@ -7,7 +7,6 @@ #ifdef __linux__ #define _POSIX_C_SOURCE 200112L #include "pal/pal_system.h" -#include #include #include #include @@ -34,22 +33,13 @@ static uint32_t parseCache(const char* path) return cacheSize; } -PalResult PAL_CALL palGetCPUInfo( +void PAL_CALL palGetCPUInfo( const PalAllocator* allocator, PalCPUInfo* info) { - if (!info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - // check invalid allocator - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - FILE* file = fopen("/proc/cpuinfo", "r"); if (!file) { - return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); + return; } char line[1024]; @@ -128,7 +118,7 @@ PalResult PAL_CALL palGetCPUInfo( // get architecture struct utsname arch; if (uname(&arch) != 0) { - return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); + return; } if (strcmp(arch.machine, "x86_64") == 0) { @@ -150,8 +140,6 @@ PalResult PAL_CALL palGetCPUInfo( if (strcmp(arch.machine, "aarch64") == 0) { info->architecture = PAL_CPU_ARCH_ARM64; } - - return PAL_RESULT_SUCCESS; } #endif // __linux__ \ No newline at end of file diff --git a/src/system/linux/pal_platform_linux.c b/src/system/linux/pal_platform_linux.c index 28dd1388..8f000fdc 100644 --- a/src/system/linux/pal_platform_linux.c +++ b/src/system/linux/pal_platform_linux.c @@ -7,18 +7,13 @@ #ifdef __linux__ #define _POSIX_C_SOURCE 200112L #include "pal/pal_system.h" -#include #include #include #include #include -PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) +void PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) { - if (!info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - info->type = PAL_PLATFORM_TYPE_LINUX; const char* session = getenv("XDG_SESSION_TYPE"); if (session) { @@ -34,7 +29,7 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) FILE* file = fopen("/etc/os-release", "r"); if (!file) { - return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); + return; } char line[256]; @@ -62,12 +57,11 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) struct statvfs stats; if (statvfs("/", &stats) != 0) { - return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); + return; } uint64_t size = (stats.f_blocks * stats.f_frsize) / (1024 * 1024 * 1024); info->totalMemory = (uint32_t)size; - return PAL_RESULT_SUCCESS; } #endif // __linux__ \ No newline at end of file diff --git a/src/system/win32/pal_cpu_win32.c b/src/system/win32/pal_cpu_win32.c index 2690e979..9b1c3630 100644 --- a/src/system/win32/pal_cpu_win32.c +++ b/src/system/win32/pal_cpu_win32.c @@ -42,19 +42,10 @@ static inline void cpuid( #endif // _MSC_VER } -PalResult PAL_CALL palGetCPUInfo( +void PAL_CALL palGetCPUInfo( const PalAllocator* allocator, PalCPUInfo* info) { - if (!info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - // check invalid allocator - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - memset(info, 0, sizeof(PalCPUInfo)); // get cpu vendor @@ -114,16 +105,13 @@ PalResult PAL_CALL palGetCPUInfo( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* buffer = nullptr; buffer = palAllocate(allocator, len, 16); if (!buffer) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; + return; } BOOL ret = GetLogicalProcessorInformationEx(RelationAll, buffer, &len); if (!ret) { palFree(allocator, buffer); - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); + return; } char* ptr = (char*)buffer; @@ -211,7 +199,6 @@ PalResult PAL_CALL palGetCPUInfo( } info->features = features; - return PAL_RESULT_SUCCESS; } #endif // _WIN32 \ No newline at end of file diff --git a/src/system/win32/pal_platform_win32.c b/src/system/win32/pal_platform_win32.c index 57d4b6c8..9cbad3bb 100644 --- a/src/system/win32/pal_platform_win32.c +++ b/src/system/win32/pal_platform_win32.c @@ -70,21 +70,14 @@ static inline PalBool isVersionWin32( return osVersion->build >= build; } -PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) +void PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) { - if (!info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - info->apiType = PAL_PLATFORM_API_TYPE_WIN32; info->type = PAL_PLATFORM_TYPE_WINDOWS; // get windows build, version and combine them if (!getVersionWin32(&info->version)) { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); + return; } const char* name = nullptr; @@ -137,8 +130,6 @@ PalResult PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) if (GlobalMemoryStatusEx(&status)) { info->totalRAM = (uint32_t)(status.ullTotalPhys / (1024 * 1024)); } - - return PAL_RESULT_SUCCESS; } #endif // _WIN32 \ No newline at end of file From 2b6ab9b58bafa897d50ba6f7c99804907631a24b Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 10 Jul 2026 12:45:32 +0000 Subject: [PATCH 327/372] fix test applications --- CHANGELOG.md | 3 +- include/pal/pal_graphics.h | 4 +- src/graphics/vulkan/pal_swapchain_vulkan.c | 4 +- src/video/win32/pal_monitor_win32.c | 2 +- src/video/x11/pal_monitor_x11.c | 2 +- tests/graphics/clear_color_test.c | 54 +---- tests/graphics/compute_test.c | 66 +------ tests/graphics/descriptor_indexing_test.c | 220 ++++----------------- tests/graphics/geometry_test.c | 102 ++-------- tests/graphics/graphics_test.c | 65 ++---- tests/graphics/indirect_draw_test.c | 179 +++-------------- tests/graphics/mesh_test.c | 97 ++------- tests/graphics/multi_descriptor_set_test.c | 71 +------ tests/graphics/ray_tracing_test.c | 152 +++----------- tests/graphics/texture_test.c | 197 ++++-------------- tests/graphics/triangle_test.c | 122 ++---------- tests/opengl/multi_thread_opengl_test.c | 6 +- tests/opengl/opengl_context_test.c | 8 +- tests/opengl/opengl_multi_context_test.c | 6 +- tests/system/cpu_test.c | 7 +- tests/system/platform_test.c | 8 +- tests/tests_main.c | 4 +- tests/video/attach_window_test.c | 9 +- tests/video/custom_decoration_test.c | 7 +- tests/video/icon_test.c | 6 +- tests/video/monitor_mode_test.c | 24 +-- tests/video/monitor_test.c | 8 +- tests/video/native_integration_test.c | 6 +- tests/video/window_test.c | 7 +- 29 files changed, 239 insertions(+), 1207 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d47817b..3d5595ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -82,7 +82,8 @@ - `PalWindowCreateInfo` now has `state`, `appName`, `instanceName`, `fbConfigBackend` and `fbConfigIndex` fields. - Removed `maximized` and `minimized` in `PalWindowCreateInfo`. -- These function now returns `void` instead of `PalResult`: +- These function now returns `void` instead of `PalResult` and does not do runtime +validation anymore: invalid arguments, feature not supported results in undefined behavior: - `palGetPlatformInfo()` - `palGetCPUInfo()` - `palGetThreadName()` diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 6faec99e..f8640db7 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1893,7 +1893,7 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t outSize; /**< Required buffer size.*/ + uint64_t bufferSize; /**< Required buffer size.*/ uint32_t bufferRowLength; /**< Required buffer row length.*/ uint32_t bufferImageHeight; /**< Required buffer image height.*/ } PalImageStagingRequirements; @@ -6504,7 +6504,7 @@ PAL_API void PAL_CALL palWriteInstanceStaging( * @since 2.0 * @sa palComputeImageStagingRequirements */ -PAL_API void PAL_CALL palWriteToImageCopyStagingBuffer( +PAL_API void PAL_CALL palWriteImageStaging( PalDevice* device, PalFormat imageFormat, PalBufferImageCopyInfo* copyInfo, diff --git a/src/graphics/vulkan/pal_swapchain_vulkan.c b/src/graphics/vulkan/pal_swapchain_vulkan.c index a9ce9666..867d9df5 100644 --- a/src/graphics/vulkan/pal_swapchain_vulkan.c +++ b/src/graphics/vulkan/pal_swapchain_vulkan.c @@ -107,7 +107,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesVk( PalSurfaceCapabilities* caps) { int32_t formatCount = 0; - int32_t modeCount = 0; + uint32_t modeCount = 0; SurfaceVk* vkSurface = (SurfaceVk*)surface; VkSurfaceFormatKHR* formats = nullptr; VkPresentModeKHR* modes = nullptr; @@ -299,7 +299,7 @@ PalResult PAL_CALL createSwapchainVk( } // get and cache all images - int32_t count = 0; + uint32_t count = 0; result = vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, nullptr); swapchain->images = palAllocate(s_Vk.allocator, sizeof(ImageVk) * count, 0); diff --git a/src/video/win32/pal_monitor_win32.c b/src/video/win32/pal_monitor_win32.c index d4a66b56..ceec18ff 100644 --- a/src/video/win32/pal_monitor_win32.c +++ b/src/video/win32/pal_monitor_win32.c @@ -250,7 +250,7 @@ PalResult win32EnumerateMonitorModes( uint32_t* count, PalMonitorMode* modes) { - int32_t modeCount = 0; + uint32_t modeCount = 0; int32_t maxModes = 0; PalMonitorMode* monitorModes = nullptr; diff --git a/src/video/x11/pal_monitor_x11.c b/src/video/x11/pal_monitor_x11.c index d6e4cdac..7ec7bd9a 100644 --- a/src/video/x11/pal_monitor_x11.c +++ b/src/video/x11/pal_monitor_x11.c @@ -148,7 +148,7 @@ PalResult xEnumerateMonitorModes( uint32_t* count, PalMonitorMode* modes) { - int32_t modeCount = 0; + uint32_t modeCount = 0; int maxModeCount = modes ? *count : 0; XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index 3373abbc..fc2bb859 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -74,20 +74,12 @@ PalBool clearColorTest() // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it PalWindowHandleInfo winHandle = {0}; - result = palGetWindowHandleInfo(window, &winHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } + palGetWindowHandleInfo(window, &winHandle); // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; - result = palGetPlatformInfo(&platformInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get platform information"); - return PAL_FALSE; - } + palGetPlatformInfo(&platformInfo); PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { @@ -141,13 +133,7 @@ PalBool clearColorTest() PalAdapterInfo adapterInfo = {0}; for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } - + palGetAdapterCapabilities(adapter, &caps); if (caps.maxGraphicsQueues == 0) { adapter = nullptr; continue; @@ -215,11 +201,7 @@ PalBool clearColorTest() // create a swapchain with the graphics queue PalSurfaceCapabilities surfaceCaps = {0}; - result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get surface capabilities"); - return PAL_FALSE; - } + palGetSurfaceCapabilities(device, surface, &surfaceCaps); PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = PAL_TRUE; @@ -267,11 +249,7 @@ PalBool clearColorTest() } PalImageInfo imageInfo; - result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get image info"); - return PAL_FALSE; - } + palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; @@ -433,18 +411,13 @@ PalBool clearColorTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - PalClearValue clearValue; clearValue.color[0] = 0.2f; clearValue.color[1] = 0.2f; @@ -462,22 +435,13 @@ PalBool clearColorTest() renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to begin rendering"); - return PAL_FALSE; - } - - result = palCmdEndRendering(cmdBuffers[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to end rendering"); - return PAL_FALSE; - } + palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable oldUsageState = newUsageState; newUsageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 62fe37d6..947a88a5 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -81,24 +81,14 @@ PalBool computeTest() PalAdapterInfo adapterInfo = {0}; for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } - + palGetAdapterCapabilities(adapter, &caps); if (caps.maxComputeQueues == 0) { adapter = nullptr; continue; } // We want an adapter that supports spirv 1.0 or dxil 6.0 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter info"); - return PAL_FALSE; - } + palGetAdapterInfo(adapter, &adapterInfo); // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; @@ -333,28 +323,9 @@ PalBool computeTest() pushConstant.color[2] = 0.0f; pushConstant.color[3] = 1.0f; - result = palCmdBindPipeline(cmdBuffer, pipeline); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind pipeline"); - return PAL_FALSE; - } - - result = palCmdPushConstants( - cmdBuffer, - 0, - sizeof(PushConstant), - &pushConstant); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to push constants"); - return PAL_FALSE; - } - - result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind descriptor set"); - return PAL_FALSE; - } + palCmdBindPipeline(cmdBuffer, pipeline); + palCmdPushConstants(cmdBuffer, 0, sizeof(PushConstant), &pushConstant); + palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); // we will use a helper function to calculate the number of group count // we need on each axis. The workGroupSize on each axis must be less or equal @@ -375,12 +346,8 @@ PalBool computeTest() uint32_t workGroupInfoCount = 0; PalWorkGroupInfo* workGroupInfos = nullptr; - PalBool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); - if (!ret) { - palLog(nullptr, "Failed to build work group info"); - return PAL_FALSE; - } - + palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); + workGroupInfos = palAllocate(nullptr, sizeof(PalWorkGroupInfo) * workGroupInfoCount, 0); if (!workGroupInfos) { palLog(nullptr, "Failed to allocate memory"); @@ -397,32 +364,19 @@ PalBool computeTest() uint32_t groupCountX = workGroupInfos[i].workGroupCount[0]; uint32_t groupCountY = workGroupInfos[i].workGroupCount[1]; uint32_t groupCountZ = workGroupInfos[i].workGroupCount[2]; - - result = palCmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to issue dispatch command"); - return PAL_FALSE; - } + palCmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); } palFree(nullptr, workGroupInfos); // set a barrier so we only read from the buffer after the shader has written to it PalUsageState oldUsageState = PAL_USAGE_STATE_SHADER_WRITE; PalUsageState newUsageState = PAL_USAGE_STATE_TRANSFER_READ; - result = palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } + palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); // now we copy from the GPU buffer into the staging buffer PalBufferCopyInfo copyInfo = {0}; copyInfo.size = bufferBytes; - result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } + palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 28f910d8..c376aa5f 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -121,20 +121,12 @@ PalBool descriptorIndexingTest() // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it PalWindowHandleInfo winHandle = {0}; - result = palGetWindowHandleInfo(window, &winHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } + palGetWindowHandleInfo(window, &winHandle); // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; - result = palGetPlatformInfo(&platformInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get platform information"); - return PAL_FALSE; - } + palGetPlatformInfo(&platformInfo); PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { @@ -189,13 +181,7 @@ PalBool descriptorIndexingTest() PalAdapterFeatures adapterFeatures; for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } - + palGetAdapterCapabilities(adapter, &caps); if (caps.maxGraphicsQueues == 0) { adapter = nullptr; continue; @@ -208,11 +194,7 @@ PalBool descriptorIndexingTest() } // We want an adapter that supports spirv 1.4 or dxil 6.0 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter info"); - return PAL_FALSE; - } + palGetAdapterInfo(adapter, &adapterInfo); // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; @@ -259,11 +241,7 @@ PalBool descriptorIndexingTest() // get descriptor indexing capabilities PalDescriptorIndexingCapabilities descriptorIndexingCaps = {0}; - result = palQueryDescriptorIndexingCapabilities(device, &descriptorIndexingCaps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get descriptor indexing capabilities"); - return PAL_FALSE; - } + palQueryDescriptorIndexingCapabilities(device, &descriptorIndexingCaps); // create surface result = palCreateSurface( @@ -304,11 +282,7 @@ PalBool descriptorIndexingTest() // create a swapchain with the graphics queue PalSurfaceCapabilities surfaceCaps = {0}; - result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get surface capabilities"); - return PAL_FALSE; - } + palGetSurfaceCapabilities(device, surface, &surfaceCaps); PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = PAL_TRUE; @@ -356,11 +330,7 @@ PalBool descriptorIndexingTest() } PalImageInfo imageInfo; - result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get image info"); - return PAL_FALSE; - } + palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; @@ -504,26 +474,16 @@ PalBool descriptorIndexingTest() bufferImageCopyInfo.imageHeight = TEXTURE_HEIGHT; bufferImageCopyInfo.imageDepth = 1; // 2D image - uint64_t imageCopyStagingBufferSize = 0; - uint32_t bufferRowLength = 0; - uint32_t bufferImageHeight = 0; - - result = palComputeImageCopyStagingBufferRequirements( + PalImageStagingRequirements stagingReq = {0}; + palComputeImageStagingRequirements( device, - imageCreateInfo.format, - &bufferImageCopyInfo, - &bufferRowLength, - &bufferImageHeight, - &imageCopyStagingBufferSize); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to compute buffer info"); - return PAL_FALSE; - } + imageCreateInfo.format, + &bufferImageCopyInfo, + &stagingReq); // update our copy with the required buffer row length and buffer image height - bufferImageCopyInfo.bufferRowLength = bufferRowLength; - bufferImageCopyInfo.bufferImageHeight = bufferImageHeight; + bufferImageCopyInfo.bufferRowLength = stagingReq.bufferRowLength; + bufferImageCopyInfo.bufferImageHeight = stagingReq.bufferImageHeight; // create staging buffers to transfer the data to the image uint32_t textureDatas[4][TEXTURE_WIDTH * TEXTURE_HEIGHT]; @@ -533,7 +493,7 @@ PalBool descriptorIndexingTest() createFlatTexture(textureDatas[3], TEXTURE_WIDTH, TEXTURE_HEIGHT, 255, 255, 0); PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; - imageStagingBufferCreateInfo.size = imageCopyStagingBufferSize; + imageStagingBufferCreateInfo.size = stagingReq.bufferSize; imageStagingBufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; imageStagingBufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; @@ -546,30 +506,19 @@ PalBool descriptorIndexingTest() // copy data void* data = nullptr; - result = palMapBuffer( - imageStagingBuffers[i], - 0, - imageCopyStagingBufferSize, - &data); - + result = palMapBuffer(imageStagingBuffers[i], 0, stagingReq.bufferSize, &data); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to map buffer"); return PAL_FALSE; } - // write data to the mapped image copy staging buffer - result = palWriteToImageCopyStagingBuffer( - device, - data, - textureDatas[i], + palWriteImageStaging( + device, imageCreateInfo.format, - &bufferImageCopyInfo); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to write to buffer"); - return PAL_FALSE; - } - + &bufferImageCopyInfo, + textureDatas[i], + data); + palUnmapBuffer(imageStagingBuffers[i]); } @@ -585,20 +534,11 @@ PalBool descriptorIndexingTest() PalBufferCopyInfo copyInfo = {0}; copyInfo.size = sizeof(vertices); - - result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } + palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; PalUsageState newUsageState = PAL_USAGE_STATE_VERTEX_READ; - result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } + palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); // set a barrier on the image to transition it into transfer dst state PalImageSubresourceRange textureRange = {0}; @@ -610,42 +550,27 @@ PalBool descriptorIndexingTest() for (int i = 0; i < 4; i++) { PalUsageState oldImageUsageState = PAL_USAGE_STATE_UNDEFINED; PalUsageState newImageUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[0], textures[i], &textureRange, oldImageUsageState, newImageUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - - result = palCmdCopyBufferToImage( + palCmdCopyBufferToImage( cmdBuffers[0], textures[i], imageStagingBuffers[i], &bufferImageCopyInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } - oldImageUsageState = newImageUsageState; newImageUsageState = PAL_USAGE_STATE_SHADER_READ; - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[0], textures[i], &textureRange, oldImageUsageState, newImageUsageState); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } } result = palCmdEnd(cmdBuffers[0]); @@ -1107,18 +1032,13 @@ PalBool descriptorIndexingTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - PalClearValue clearValue; clearValue.color[0] = 0.2f; clearValue.color[1] = 0.2f; @@ -1136,90 +1056,28 @@ PalBool descriptorIndexingTest() renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to begin rendering"); - return PAL_FALSE; - } - - // bind pipeline - result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind pipeline"); - return PAL_FALSE; - } - - result = palCmdPushConstants( - cmdBuffers[currentFrame], - 0, - sizeof(PushConstant), - &pushConstant); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to push constants"); - return PAL_FALSE; - } - - result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to push constants"); - return PAL_FALSE; - } - - // set viewport and scissors - result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set viewport"); - return PAL_FALSE; - } - - result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set scissor"); - return PAL_FALSE; - } - - // bind vertex buffer + palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + palCmdPushConstants(cmdBuffers[currentFrame], 0, sizeof(PushConstant), &pushConstant); + palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); + palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); + palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); + uint64_t offset[] = {0}; - result = palCmdBindVertexBuffers( - cmdBuffers[currentFrame], - 0, - 1, - &vertexBuffer, - offset); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind vertex buffer"); - return PAL_FALSE; - } - - result = palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to issue draw command"); - return PAL_FALSE; - } - - result = palCmdEndRendering(cmdBuffers[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to end rendering"); - return PAL_FALSE; - } + palCmdBindVertexBuffers(cmdBuffers[currentFrame], 0, 1, &vertexBuffer, offset); + palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); + palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable oldUsageState = newUsageState; newUsageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to end command buffer"); diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index d4a2b7bb..c84ded5c 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -78,20 +78,12 @@ PalBool geometryTest() // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it PalWindowHandleInfo winHandle = {0}; - result = palGetWindowHandleInfo(window, &winHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } + palGetWindowHandleInfo(window, &winHandle); // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; - result = palGetPlatformInfo(&platformInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get platform information"); - return PAL_FALSE; - } + palGetPlatformInfo(&platformInfo); PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { @@ -146,13 +138,7 @@ PalBool geometryTest() PalAdapterFeatures adapterFeatures; for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } - + palGetAdapterCapabilities(adapter, &caps); if (caps.maxGraphicsQueues == 0) { adapter = nullptr; continue; @@ -165,11 +151,7 @@ PalBool geometryTest() } // We want an adapter that supports spirv 1.0 or dxil 6.0 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter info"); - return PAL_FALSE; - } + palGetAdapterInfo(adapter, &adapterInfo); // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; @@ -249,11 +231,7 @@ PalBool geometryTest() // create a swapchain with the graphics queue PalSurfaceCapabilities surfaceCaps = {0}; - result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get surface capabilities"); - return PAL_FALSE; - } + palGetSurfaceCapabilities(device, surface, &surfaceCaps); PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = PAL_TRUE; @@ -301,12 +279,8 @@ PalBool geometryTest() } PalImageInfo imageInfo; - result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get image info"); - return PAL_FALSE; - } - + palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); + PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.subresourceRange.layerArrayCount = 1; @@ -585,18 +559,13 @@ PalBool geometryTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - PalClearValue clearValue; clearValue.color[0] = 0.2f; clearValue.color[1] = 0.2f; @@ -614,64 +583,23 @@ PalBool geometryTest() renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to begin rendering"); - return PAL_FALSE; - } - - // bind pipeline - result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind pipeline"); - return PAL_FALSE; - } - - // set viewport and scissors - result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set viewport"); - return PAL_FALSE; - } - - result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set scissor"); - return PAL_FALSE; - } - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind vertex buffer"); - return PAL_FALSE; - } - - result = palCmdDraw(cmdBuffers[currentFrame], 3, 1, 0, 0); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to issue draw command"); - return PAL_FALSE; - } - - result = palCmdEndRendering(cmdBuffers[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to end rendering"); - return PAL_FALSE; - } + palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); + palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); + palCmdDraw(cmdBuffers[currentFrame], 3, 1, 0, 0); + palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable oldUsageState = newUsageState; newUsageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to end command buffer"); diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 280b2e68..69104dc2 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -12,7 +12,7 @@ PalBool graphicsTest() } // enumerate all available adapters - int32_t count = 0; + uint32_t count = 0; result = palEnumerateAdapters(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get query adapters"); @@ -46,19 +46,8 @@ PalBool graphicsTest() PalAdapterFeatures features = 0; for (int32_t i = 0; i < count; i++) { PalAdapter* adapter = adapters[i]; - result = palGetAdapterInfo(adapter, &info); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter information"); - palFree(nullptr, adapters); - return PAL_FALSE; - } - - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } + palGetAdapterInfo(adapter, &info); + palGetAdapterCapabilities(adapter, &caps); // create a device features = palGetAdapterFeatures(adapter); @@ -253,11 +242,7 @@ PalBool graphicsTest() palLog(nullptr, " Sampler Anisotropy"); PalSamplerAnisotropyCapabilities tmp; - result = palQuerySamplerAnisotropyCapabilities(device, &tmp); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get sampler anisotropy capabilities"); - return PAL_FALSE; - } + palQuerySamplerAnisotropyCapabilities(device, &tmp); palLog(nullptr, " Max anisotropy: %u", tmp.maxAnisotropy); palLog(nullptr, ""); @@ -267,11 +252,7 @@ PalBool graphicsTest() palLog(nullptr, " Multi viewport"); PalMultiViewportCapabilities tmp; - result = palQueryMultiViewportCapabilities(device, &tmp); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get viewport capabilities"); - return PAL_FALSE; - } + palQueryMultiViewportCapabilities(device, &tmp); palLog(nullptr, " Max count: %u", tmp.maxCount); palLog(nullptr, ""); @@ -281,11 +262,7 @@ PalBool graphicsTest() palLog(nullptr, " Ray tracing"); PalRayTracingCapabilities tmp; - result = palQueryRayTracingCapabilities(device, &tmp); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get ray tracing capabilities"); - return PAL_FALSE; - } + palQueryRayTracingCapabilities(device, &tmp); palLog(nullptr, " Max recursion depth: %u", tmp.maxRecursionDepth); palLog(nullptr, " Max hit attribute size: %u Bytes", tmp.maxHitAttributeSize); @@ -301,11 +278,7 @@ PalBool graphicsTest() palLog(nullptr, " Mesh and task shader"); PalMeshShaderCapabilities tmp; - result = palQueryMeshShaderCapabilities(device, &tmp); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get mesh shader capabilities"); - return PAL_FALSE; - } + palQueryMeshShaderCapabilities(device, &tmp); palLog(nullptr, " Max output primitives: %u", tmp.maxOutputPrimitives); palLog(nullptr, " Max output vertices: %u", tmp.maxOutputVertices); @@ -325,11 +298,7 @@ PalBool graphicsTest() palLog(nullptr, " Fragment shading rate"); PalFragmentShadingRateCapabilities tmp; - result = palQueryFragmentShadingRateCapabilities(device, &tmp); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get fragment shading rate capabilities"); - return PAL_FALSE; - } + palQueryFragmentShadingRateCapabilities(device, &tmp); palLog(nullptr, " Min texel width: %u", tmp.minTexelWidth); palLog(nullptr, " Min texel height: %u", tmp.maxTexelWidth); @@ -396,11 +365,7 @@ PalBool graphicsTest() palLog(nullptr, " Descriptor indexing"); PalDescriptorIndexingCapabilities tmp; - result = palQueryDescriptorIndexingCapabilities(device, &tmp); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get descriptor indexing capabilities"); - return PAL_FALSE; - } + palQueryDescriptorIndexingCapabilities(device, &tmp); palLog(nullptr, " Supported flags:"); if (tmp.flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND) { @@ -445,11 +410,7 @@ PalBool graphicsTest() palLog(nullptr, " Multiview"); PalMultiViewCapabilities tmp; - result = palQueryMultiViewCapabilities(device, &tmp); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get multi view capabilities"); - return PAL_FALSE; - } + palQueryMultiViewCapabilities(device, &tmp); palLog(nullptr, " Max view count: %u", tmp.maxViewCount); palLog(nullptr, ""); @@ -459,11 +420,7 @@ PalBool graphicsTest() palLog(nullptr, " Depth stencil resolve"); PalDepthStencilCapabilities tmp; - result = palQueryDepthStencilCapabilities(device, &tmp); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get depth stenci capabilities"); - return PAL_FALSE; - } + palQueryDepthStencilCapabilities(device, &tmp); if (tmp.supportsIndependentResolve) { palLog(nullptr, " Independent resolve: True"); diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 11377555..2683e02a 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -90,20 +90,12 @@ PalBool indirectDrawTest() // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it PalWindowHandleInfo winHandle = {0}; - result = palGetWindowHandleInfo(window, &winHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } + palGetWindowHandleInfo(window, &winHandle); // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; - result = palGetPlatformInfo(&platformInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get platform information"); - return PAL_FALSE; - } + palGetPlatformInfo(&platformInfo); PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { @@ -158,13 +150,7 @@ PalBool indirectDrawTest() PalAdapterFeatures adapterFeatures; for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } - + palGetAdapterCapabilities(adapter, &caps); if (caps.maxGraphicsQueues == 0) { adapter = nullptr; continue; @@ -177,11 +163,7 @@ PalBool indirectDrawTest() } // We want an adapter that supports spirv 1.0 or dxil 6.0 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter info"); - return PAL_FALSE; - } + palGetAdapterInfo(adapter, &adapterInfo); // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; @@ -261,11 +243,7 @@ PalBool indirectDrawTest() // create a swapchain with the graphics queue PalSurfaceCapabilities surfaceCaps = {0}; - result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get surface capabilities"); - return PAL_FALSE; - } + palGetSurfaceCapabilities(device, surface, &surfaceCaps); PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = PAL_TRUE; @@ -313,11 +291,7 @@ PalBool indirectDrawTest() } PalImageInfo imageInfo; - result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get image info"); - return PAL_FALSE; - } + palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; @@ -507,45 +481,16 @@ PalBool indirectDrawTest() indirectCopyInfo.size = sizeof(PalDrawIndexedIndirectData); indirectCopyInfo.srcOffset = indirectOffset; - result = palCmdCopyBuffer(cmdBuffers[0], indirectBuffer, stagingBuffer, &indirectCopyInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } - - result = palCmdBufferBarrier( - cmdBuffers[0], - indirectBuffer, - oldUsageState, - newUsageState); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } + palCmdCopyBuffer(cmdBuffers[0], indirectBuffer, stagingBuffer, &indirectCopyInfo); + palCmdBufferBarrier(cmdBuffers[0], indirectBuffer, oldUsageState, newUsageState); newUsageState = PAL_USAGE_STATE_VERTEX_READ; PalBufferCopyInfo vertexCopyInfo = {0}; vertexCopyInfo.dstOffset = 0; vertexCopyInfo.size = sizeof(vertices); vertexCopyInfo.srcOffset = vertexOffset; - - result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, &vertexCopyInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } - - result = palCmdBufferBarrier( - cmdBuffers[0], - vertexBuffer, - oldUsageState, - newUsageState); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } + palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, &vertexCopyInfo); + palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); // copy to index buffer newUsageState = PAL_USAGE_STATE_INDEX_READ; @@ -553,23 +498,8 @@ PalBool indirectDrawTest() indexCopyInfo.dstOffset = 0; indexCopyInfo.size = sizeof(indices); indexCopyInfo.srcOffset = indexOffset; - - result = palCmdCopyBuffer(cmdBuffers[0], indexBuffer, stagingBuffer, &indexCopyInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } - - result = palCmdBufferBarrier( - cmdBuffers[0], - indexBuffer, - oldUsageState, - newUsageState); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } + palCmdCopyBuffer(cmdBuffers[0], indexBuffer, stagingBuffer, &indexCopyInfo); + palCmdBufferBarrier(cmdBuffers[0], indexBuffer, oldUsageState, newUsageState); result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { @@ -823,18 +753,13 @@ PalBool indirectDrawTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - PalClearValue clearValue; clearValue.color[0] = 0.2f; clearValue.color[1] = 0.2f; @@ -852,85 +777,27 @@ PalBool indirectDrawTest() renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to begin rendering"); - return PAL_FALSE; - } - - // bind pipeline - result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind pipeline"); - return PAL_FALSE; - } - - // set viewport and scissors - result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set viewport"); - return PAL_FALSE; - } + palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); + palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set scissor"); - return PAL_FALSE; - } - - // bind vertex buffer uint64_t offset[] = {0}; - result = palCmdBindVertexBuffers( - cmdBuffers[currentFrame], - 0, - 1, - &vertexBuffer, - offset); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind vertex buffer"); - return PAL_FALSE; - } - - // bind index buffer - result = palCmdBindIndexBuffer( - cmdBuffers[currentFrame], - indexBuffer, - 0, - PAL_INDEX_TYPE_UINT32); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind index buffer"); - return PAL_FALSE; - } - - result = palCmdDrawIndexedIndirect(cmdBuffers[currentFrame], indirectBuffer, 1); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to issue draw command"); - return PAL_FALSE; - } - - result = palCmdEndRendering(cmdBuffers[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to end rendering"); - return PAL_FALSE; - } + palCmdBindVertexBuffers(cmdBuffers[currentFrame], 0, 1, &vertexBuffer, offset); + palCmdBindIndexBuffer(cmdBuffers[currentFrame], indexBuffer, 0, PAL_INDEX_TYPE_UINT32); + palCmdDrawIndexedIndirect(cmdBuffers[currentFrame], indirectBuffer, 1); + palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable oldUsageState = newUsageState; newUsageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - + result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to end command buffer"); diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 210de44b..c8a59e27 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -78,20 +78,12 @@ PalBool meshTest() // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it PalWindowHandleInfo winHandle = {0}; - result = palGetWindowHandleInfo(window, &winHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } + palGetWindowHandleInfo(window, &winHandle); // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; - result = palGetPlatformInfo(&platformInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get platform information"); - return PAL_FALSE; - } + palGetPlatformInfo(&platformInfo); PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { @@ -146,13 +138,7 @@ PalBool meshTest() PalAdapterInfo adapterInfo = {0}; for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } - + palGetAdapterCapabilities(adapter, &caps); if (caps.maxGraphicsQueues == 0) { adapter = nullptr; continue; @@ -165,12 +151,8 @@ PalBool meshTest() } // We want an adapter that supports spirv 1.5 or dxil 6.5 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter info"); - return PAL_FALSE; - } - + palGetAdapterInfo(adapter, &adapterInfo); + // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { @@ -249,12 +231,7 @@ PalBool meshTest() // create a swapchain with the graphics queue PalSurfaceCapabilities surfaceCaps = {0}; - result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get surface capabilities"); - return PAL_FALSE; - } + palGetSurfaceCapabilities(device, surface, &surfaceCaps); PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = PAL_TRUE; @@ -302,11 +279,7 @@ PalBool meshTest() } PalImageInfo imageInfo; - result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get image info"); - return PAL_FALSE; - } + palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; @@ -580,18 +553,13 @@ PalBool meshTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - PalClearValue clearValue; clearValue.color[0] = 0.2f; clearValue.color[1] = 0.2f; @@ -609,63 +577,28 @@ PalBool meshTest() renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to begin rendering"); - return PAL_FALSE; - } - - // bind pipeline - result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind pipeline"); - return PAL_FALSE; - } - - // set viewport and scissors - result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set viewport"); - return PAL_FALSE; - } - - result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set scissor"); - return PAL_FALSE; - } + palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); + palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); // draw a single triangle with the mesh shader // palBuildWorkGroupInfo() is a helper to build // the workgroup count per axis using normal // workCount (image size, buffer size) - result = palCmdDrawMeshTasks(cmdBuffers[currentFrame], 1, 1, 1); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to issue draw command"); - return PAL_FALSE; - } - - result = palCmdEndRendering(cmdBuffers[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to end rendering"); - return PAL_FALSE; - } + palCmdDrawMeshTasks(cmdBuffers[currentFrame], 1, 1, 1); + palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable oldUsageState = newUsageState; newUsageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to end command buffer"); diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index a2fb7bf2..407e8979 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -85,13 +85,7 @@ PalBool multiDescriptorSetTest() PalAdapterInfo adapterInfo = {0}; for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } - + palGetAdapterCapabilities(adapter, &caps); if (caps.maxComputeQueues == 0) { adapter = nullptr; continue; @@ -110,11 +104,7 @@ PalBool multiDescriptorSetTest() } // We want an adapter that supports spirv 1.0 or dxil 6.0 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter info"); - return PAL_FALSE; - } + palGetAdapterInfo(adapter, &adapterInfo); // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; @@ -388,30 +378,10 @@ PalBool multiDescriptorSetTest() pushConstant.set3Color[2] = 1.0f; pushConstant.set3Color[3] = 1.0f; - result = palCmdBindPipeline(cmdBuffer, pipeline); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind pipeline"); - return PAL_FALSE; - } - - result = palCmdPushConstants( - cmdBuffer, - 0, - sizeof(PushConstant), - &pushConstant); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to push constant"); - return PAL_FALSE; - } - - // bind descriptor sets + palCmdBindPipeline(cmdBuffer, pipeline); + palCmdPushConstants(cmdBuffer, 0, sizeof(PushConstant), &pushConstant); for (int i = 0; i < 3; i++) { - result = palCmdBindDescriptorSet(cmdBuffer, i, descriptorSets[i]); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind descriptor set"); - return PAL_FALSE; - } + palCmdBindDescriptorSet(cmdBuffer, i, descriptorSets[i]); } // we will use a helper function to calculate the number of group count @@ -433,11 +403,7 @@ PalBool multiDescriptorSetTest() uint32_t workGroupInfoCount = 0; PalWorkGroupInfo* workGroupInfos = nullptr; - PalBool ret = palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); - if (!ret) { - palLog(nullptr, "Failed to build work group info"); - return PAL_FALSE; - } + palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); workGroupInfos = palAllocate(nullptr, sizeof(PalWorkGroupInfo) * workGroupInfoCount, 0); if (!workGroupInfos) { @@ -455,12 +421,7 @@ PalBool multiDescriptorSetTest() uint32_t groupCountX = workGroupInfos[i].workGroupCount[0]; uint32_t groupCountY = workGroupInfos[i].workGroupCount[1]; uint32_t groupCountZ = workGroupInfos[i].workGroupCount[2]; - - result = palCmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to issue dispatch command"); - return PAL_FALSE; - } + palCmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); } palFree(nullptr, workGroupInfos); @@ -469,26 +430,12 @@ PalBool multiDescriptorSetTest() PalUsageState newUsageState = PAL_USAGE_STATE_TRANSFER_READ; for (int i = 0; i < 3; i++) { - result = palCmdBufferBarrier( - cmdBuffer, - buffers[i], - oldUsageState, - newUsageState); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } + palCmdBufferBarrier(cmdBuffer, buffers[i], oldUsageState, newUsageState); // now we copy from the GPU buffer into the staging buffer PalBufferCopyInfo copyInfo = {0}; copyInfo.size = bufferBytes; - - result = palCmdCopyBuffer(cmdBuffer, stagingBuffers[i], buffers[i], ©Info); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } + palCmdCopyBuffer(cmdBuffer, stagingBuffers[i], buffers[i], ©Info); } result = palCmdEnd(cmdBuffer); diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 7cb6dc14..450a9cad 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -89,12 +89,7 @@ PalBool rayTracingTest() PalAdapterFeatures adapterFeatures = 0; for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } + palGetAdapterCapabilities(adapter, &caps); // Ray tracing is generally implemented on the graphics queue if (caps.maxGraphicsQueues == 0) { @@ -114,11 +109,7 @@ PalBool rayTracingTest() } // We want an adapter that supports spirv 1.4 or dxil 6.3 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter info"); - return PAL_FALSE; - } + palGetAdapterInfo(adapter, &adapterInfo); // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; @@ -304,11 +295,7 @@ PalBool rayTracingTest() // get the build sizes for blas PalAccelerationStructureBuildSize buildSizes = {0}; - result = palGetAccelerationStructureBuildSize(device, &blasBuildInfo, &buildSizes); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get accleration structure build size"); - return PAL_FALSE; - } + palGetAccelerationStructureBuildSize(device, &blasBuildInfo, &buildSizes); // create the blas buffer and blas bufferCreateInfo.size = buildSizes.accelerationStructureSize; @@ -402,12 +389,8 @@ PalBool rayTracingTest() // get the build sizes for tlas uint32_t blasScratchSize = buildSizes.scratchBufferSize; - result = palGetAccelerationStructureBuildSize(device, &tlasBuildInfo, &buildSizes); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get accleration structure build size"); - return PAL_FALSE; - } - + palGetAccelerationStructureBuildSize(device, &tlasBuildInfo, &buildSizes); + // create the tlas buffer and tlas bufferCreateInfo.size = buildSizes.accelerationStructureSize; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; @@ -641,18 +624,9 @@ PalBool rayTracingTest() return PAL_FALSE; } - result = palCmdBindPipeline(cmdBuffer, pipeline); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind pipeline"); - return PAL_FALSE; - } - - result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind descriptor set"); - return PAL_FALSE; - } - + palCmdBindPipeline(cmdBuffer, pipeline); + palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); + // build the blas and tlas infos PalDeviceAddress scratchBufferAddress = palGetBufferDeviceAddress(scratchBuffer); blasBuildInfo.dst = blas; @@ -660,72 +634,26 @@ PalBool rayTracingTest() tlasBuildInfo.dst = tlas; tlasBuildInfo.scratchBufferAddress = scratchBufferAddress; - - result = palCmdBuildAccelerationStructure(cmdBuffer, &blasBuildInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to build acceleration structure"); - return PAL_FALSE; - } + palCmdBuildAccelerationStructure(cmdBuffer, &blasBuildInfo); // make sure the BLAS builds before the TLAS. We need this barrier because // BLAS and TLAS share the same scratch buffer PalUsageState oldAsUsageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; PalUsageState newAsUsageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; - - result = palCmdAccelerationStructureBarrier( - cmdBuffer, - blas, - oldAsUsageState, - newAsUsageState); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - - result = palCmdBuildAccelerationStructure(cmdBuffer, &tlasBuildInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to build acceleration structure"); - return PAL_FALSE; - } - - // make sure the TLAS builds before the tracing - result = palCmdAccelerationStructureBarrier( - cmdBuffer, - tlas, - oldAsUsageState, - newAsUsageState); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - - result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to issue trace command"); - return PAL_FALSE; - } + palCmdAccelerationStructureBarrier(cmdBuffer, blas, oldAsUsageState, newAsUsageState); + palCmdBuildAccelerationStructure(cmdBuffer, &tlasBuildInfo); + palCmdAccelerationStructureBarrier(cmdBuffer, tlas, oldAsUsageState, newAsUsageState); + palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); // set a barrier so we only read from the buffer after the shader has written to it PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; PalUsageState newUsageState = PAL_USAGE_STATE_TRANSFER_READ; - - result = palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - + palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); + // now we copy from the GPU buffer into the staging buffer PalBufferCopyInfo copyInfo = {0}; copyInfo.size = bufferBytes; - - result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } + palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { @@ -795,11 +723,7 @@ PalBool rayTracingTest() updateRecords[1] = records[2]; // closest hit // update records - result = palUpdateShaderBindingTable(sbt, 2, updateRecords); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to update shader binding table"); - return PAL_FALSE; - } + palUpdateShaderBindingTable(sbt, 2, updateRecords); // we dont need to rebuild the blas or tlas // we just delete and create the fence again for simplicity @@ -819,53 +743,25 @@ PalBool rayTracingTest() return PAL_FALSE; } - result = palCmdBindPipeline(cmdBuffer, pipeline); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind pipeline"); - return PAL_FALSE; - } - - result = palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind descriptor set"); - return PAL_FALSE; - } + palCmdBindPipeline(cmdBuffer, pipeline); + palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); // the previous trace transitioned the buffer to transfer read // we need it back to shader write before transfer read oldUsageState = PAL_USAGE_STATE_TRANSFER_READ; newUsageState = PAL_USAGE_STATE_SHADER_WRITE; + palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); + palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); - result = palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - - result = palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to issue trace command"); - return PAL_FALSE; - } - - // set a barrier to transition to transfer read so we can read from it after shader has + // set a barrier to transition to transfer read so we can read from it after shader has // written to it oldUsageState = newUsageState; newUsageState = PAL_USAGE_STATE_TRANSFER_READ; - - result = palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } + palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); // now we copy from the GPU buffer into the staging buffer copyInfo.size = bufferBytes; - result = palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } + palCmdCopyBuffer(cmdBuffer, stagingBuffer, buffer, ©Info); result = palCmdEnd(cmdBuffer); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 71f46a72..f3253a07 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -115,20 +115,12 @@ PalBool textureTest() // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it PalWindowHandleInfo winHandle = {0}; - result = palGetWindowHandleInfo(window, &winHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } + palGetWindowHandleInfo(window, &winHandle); // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; - result = palGetPlatformInfo(&platformInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get platform information"); - return PAL_FALSE; - } + palGetPlatformInfo(&platformInfo); PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { @@ -182,25 +174,15 @@ PalBool textureTest() PalAdapterInfo adapterInfo = {0}; for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } - + palGetAdapterCapabilities(adapter, &caps); if (caps.maxGraphicsQueues == 0) { adapter = nullptr; continue; } // We want an adapter that supports spirv 1.0 or dxil 6.0 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter info"); - return PAL_FALSE; - } - + palGetAdapterInfo(adapter, &adapterInfo); + // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { @@ -279,11 +261,7 @@ PalBool textureTest() // create a swapchain with the graphics queue PalSurfaceCapabilities surfaceCaps = {0}; - result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get surface capabilities"); - return PAL_FALSE; - } + palGetSurfaceCapabilities(device, surface, &surfaceCaps); PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = PAL_TRUE; @@ -331,11 +309,7 @@ PalBool textureTest() } PalImageInfo imageInfo; - result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get image info"); - return PAL_FALSE; - } + palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; @@ -484,31 +458,21 @@ PalBool textureTest() bufferImageCopyInfo.imageHeight = TEXTURE_HEIGHT; bufferImageCopyInfo.imageDepth = 1; // 2D image - uint64_t imageCopyStagingBufferSize = 0; - uint32_t bufferRowLength = 0; - uint32_t bufferImageHeight = 0; - - result = palComputeImageCopyStagingBufferRequirements( + PalImageStagingRequirements stagingReq = {0}; + palComputeImageStagingRequirements( device, - imageCreateInfo.format, - &bufferImageCopyInfo, - &bufferRowLength, - &bufferImageHeight, - &imageCopyStagingBufferSize); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to compute buffer info"); - return PAL_FALSE; - } + imageCreateInfo.format, + &bufferImageCopyInfo, + &stagingReq); // update our copy with the required buffer row length and buffer image height - bufferImageCopyInfo.bufferRowLength = bufferRowLength; - bufferImageCopyInfo.bufferImageHeight = bufferImageHeight; + bufferImageCopyInfo.bufferRowLength = stagingReq.bufferRowLength; + bufferImageCopyInfo.bufferImageHeight = stagingReq.bufferImageHeight; // create staging buffer to transfer the data to the image PalBuffer* imageStagingBuffer = nullptr; PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; - imageStagingBufferCreateInfo.size = imageCopyStagingBufferSize; + imageStagingBufferCreateInfo.size = stagingReq.bufferSize; imageStagingBufferCreateInfo.usages = PAL_BUFFER_USAGE_TRANSFER_SRC; imageStagingBufferCreateInfo.memoryUsage = PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD; @@ -531,18 +495,12 @@ PalBool textureTest() return PAL_FALSE; } - // write data to the mapped image copy staging buffer - result = palWriteToImageCopyStagingBuffer( - device, - data, - texture, + palWriteImageStaging( + device, imageCreateInfo.format, - &bufferImageCopyInfo); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to write to buffer"); - return PAL_FALSE; - } + &bufferImageCopyInfo, + texture, + data); palUnmapBuffer(imageStagingBuffer); @@ -558,21 +516,11 @@ PalBool textureTest() PalBufferCopyInfo copyInfo = {0}; copyInfo.size = sizeof(vertices); - - result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } + palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; PalUsageState newUsageState = PAL_USAGE_STATE_VERTEX_READ; - - result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } + palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); // copy image staging buffer to the checkerboard image // first the image must be in the correct layout @@ -586,44 +534,28 @@ PalBool textureTest() checkerboardRange.mipLevelCount = 1; checkerboardRange.layerArrayCount = 1; - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[0], checkerboard, &checkerboardRange, oldImageUsageState, newImageUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - - result = palCmdCopyBufferToImage( + palCmdCopyBufferToImage( cmdBuffers[0], checkerboard, imageStagingBuffer, &bufferImageCopyInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } - oldImageUsageState = newImageUsageState; newImageUsageState = PAL_USAGE_STATE_SHADER_READ; - - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[0], checkerboard, &checkerboardRange, oldImageUsageState, newImageUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to end command buffer"); @@ -1008,18 +940,13 @@ PalBool textureTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - PalClearValue clearValue; clearValue.color[0] = 0.2f; clearValue.color[1] = 0.2f; @@ -1037,79 +964,27 @@ PalBool textureTest() renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to begin rendering"); - return PAL_FALSE; - } - - // bind pipeline - result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind pipeline"); - return PAL_FALSE; - } - - result = palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind descriptor set"); - return PAL_FALSE; - } + palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); + palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); + palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - // set viewport and scissors - result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set viewport"); - return PAL_FALSE; - } - - result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set scissor"); - return PAL_FALSE; - } - - // bind vertex buffer uint64_t offset[] = {0}; - result = palCmdBindVertexBuffers( - cmdBuffers[currentFrame], - 0, - 1, - &vertexBuffer, - offset); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind vertex buffer"); - return PAL_FALSE; - } - - result = palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to issue draw command"); - return PAL_FALSE; - } - - result = palCmdEndRendering(cmdBuffers[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to end rendering"); - return PAL_FALSE; - } - + palCmdBindVertexBuffers(cmdBuffers[currentFrame], 0, 1, &vertexBuffer, offset); + palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); + palCmdEndRendering(cmdBuffers[currentFrame]); + // change the state of the image view to make it presentable oldUsageState = newUsageState; newUsageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to end command buffer"); diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 84aba370..8d796b94 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -81,20 +81,12 @@ PalBool triangleTest() // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it PalWindowHandleInfo winHandle = {0}; - result = palGetWindowHandleInfo(window, &winHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } + palGetWindowHandleInfo(window, &winHandle); // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; - result = palGetPlatformInfo(&platformInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get platform information"); - return PAL_FALSE; - } + palGetPlatformInfo(&platformInfo); PalWindowInstanceType windowInstanceType = PAL_WINDOW_INSTANCE_TYPE_XCB; if (platformInfo.apiType == PAL_PLATFORM_API_TYPE_WAYLAND) { @@ -148,24 +140,14 @@ PalBool triangleTest() PalAdapterInfo adapterInfo = {0}; for (int32_t i = 0; i < adapterCount; i++) { adapter = adapters[i]; - result = palGetAdapterCapabilities(adapter, &caps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter capabilities"); - palFree(nullptr, adapters); - return PAL_FALSE; - } - + palGetAdapterCapabilities(adapter, &caps); if (caps.maxGraphicsQueues == 0) { adapter = nullptr; continue; } // We want an adapter that supports spirv 1.0 or dxil 6.0 - result = palGetAdapterInfo(adapter, &adapterInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get adapter info"); - return PAL_FALSE; - } + palGetAdapterInfo(adapter, &adapterInfo); // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; @@ -245,11 +227,7 @@ PalBool triangleTest() // create a swapchain with the graphics queue PalSurfaceCapabilities surfaceCaps = {0}; - result = palGetSurfaceCapabilities(device, surface, &surfaceCaps); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get surface capabilities"); - return PAL_FALSE; - } + palGetSurfaceCapabilities(device, surface, &surfaceCaps); PalSwapchainCreateInfo swapchainCreateInfo = {0}; swapchainCreateInfo.clipped = PAL_TRUE; @@ -297,11 +275,7 @@ PalBool triangleTest() } PalImageInfo imageInfo; - result = palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get image info"); - return PAL_FALSE; - } + palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; @@ -426,21 +400,11 @@ PalBool triangleTest() PalBufferCopyInfo copyInfo = {0}; copyInfo.size = sizeof(vertices); - - result = palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to copy buffer"); - return PAL_FALSE; - } + palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; PalUsageState newUsageState = PAL_USAGE_STATE_VERTEX_READ; - - result = palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } + palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { @@ -694,18 +658,13 @@ PalBool triangleTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - PalClearValue clearValue; clearValue.color[0] = 0.2f; clearValue.color[1] = 0.2f; @@ -723,73 +682,26 @@ PalBool triangleTest() renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; - result = palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to begin rendering"); - return PAL_FALSE; - } - - // bind pipeline - result = palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind pipeline"); - return PAL_FALSE; - } - - // set viewport and scissors - result = palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set viewport"); - return PAL_FALSE; - } - - result = palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set scissor"); - return PAL_FALSE; - } + palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); + palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); + palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); + palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - // bind vertex buffer uint64_t offset[] = {0}; - result = palCmdBindVertexBuffers( - cmdBuffers[currentFrame], - 0, - 1, - &vertexBuffer, - offset); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to bind vertex buffer"); - return PAL_FALSE; - } - - result = palCmdDraw(cmdBuffers[currentFrame], 3, 1, 0, 0); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to issue draw command"); - return PAL_FALSE; - } - - result = palCmdEndRendering(cmdBuffers[currentFrame]); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to end rendering"); - return PAL_FALSE; - } + palCmdBindVertexBuffers(cmdBuffers[currentFrame], 0, 1, &vertexBuffer, offset); + palCmdDraw(cmdBuffers[currentFrame], 3, 1, 0, 0); + palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable oldUsageState = newUsageState; newUsageState = PAL_USAGE_STATE_PRESENT; - result = palCmdImageBarrier( + palCmdImageBarrier( cmdBuffers[currentFrame], image, &imageRange, oldUsageState, newUsageState); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } - result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to end command buffer"); diff --git a/tests/opengl/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c index c75dd438..ed072fd2 100644 --- a/tests/opengl/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -329,11 +329,7 @@ PalBool multiThreadOpenGlTest() // get the native handles of our created window PalWindowHandleInfo winHandle = {0}; - result = palGetWindowHandleInfo(window, &winHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } + palGetWindowHandleInfo(window, &winHandle); shared->window.instance = winHandle.nativeInstance; // On Wayland the window is the wl_egl_window diff --git a/tests/opengl/opengl_context_test.c b/tests/opengl/opengl_context_test.c index ccf95d4c..7dd9832e 100644 --- a/tests/opengl/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -166,12 +166,8 @@ PalBool openglContextTest() // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it PalWindowHandleInfo winHandle = {0}; - result = palGetWindowHandleInfo(window, &winHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } - + palGetWindowHandleInfo(window, &winHandle); + // PalGLWindow is just a struct to hold native handles PalGLWindow glWindow = {0}; glWindow.instance = winHandle.nativeInstance; diff --git a/tests/opengl/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c index 5e0361bd..59048148 100644 --- a/tests/opengl/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -166,11 +166,7 @@ PalBool openglMultiContextTest() // so long as you can get the window handle and display (if on X11, wayland) // If pal video system will not be used, there is no need to initialize it PalWindowHandleInfo winHandle = {0}; - result = palGetWindowHandleInfo(window, &winHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } + palGetWindowHandleInfo(window, &winHandle); // PalGLWindow is just a struct to hold native handles PalGLWindow glWindow = {0}; diff --git a/tests/system/cpu_test.c b/tests/system/cpu_test.c index 04eacbaa..64313a7e 100644 --- a/tests/system/cpu_test.c +++ b/tests/system/cpu_test.c @@ -30,12 +30,7 @@ PalBool cpuTest() PalCPUInfo cpuInfo; // user defined allocator, set to override the default one or nullptr for default - result = palGetCPUInfo(nullptr, &cpuInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get cpu information"); - return PAL_FALSE; - } - + palGetCPUInfo(nullptr, &cpuInfo); const char* archString = cpuArchToString(cpuInfo.architecture); int32_t processors = cpuInfo.numLogicalProcessors; diff --git a/tests/system/platform_test.c b/tests/system/platform_test.c index 05f918b5..a0813e13 100644 --- a/tests/system/platform_test.c +++ b/tests/system/platform_test.c @@ -44,12 +44,8 @@ PalBool platformTest() PalPlatformInfo platformInfo; // get the platform info. Users must cache this - result = palGetPlatformInfo(&platformInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get platform information"); - return PAL_FALSE; - } - + palGetPlatformInfo(&platformInfo); + palLog(nullptr, "Platform: %s", platformToString(platformInfo.type)); palLog(nullptr, " Name: %s", platformInfo.name); palLog(nullptr, " API: %s", platformApiToString(platformInfo.apiType)); diff --git a/tests/tests_main.c b/tests/tests_main.c index 94edff6c..8d394503 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -56,8 +56,8 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS_MODULE == 1 - // registerTest(graphicsTest, "Graphics Test"); - registerTest(computeTest, "Compute Test"); + registerTest(graphicsTest, "Graphics Test"); + // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); #endif // PAL_HAS_GRAPHICS_MODULE diff --git a/tests/video/attach_window_test.c b/tests/video/attach_window_test.c index 9b9c419a..3a141838 100644 --- a/tests/video/attach_window_test.c +++ b/tests/video/attach_window_test.c @@ -273,13 +273,8 @@ PalBool attachWindowTest() return PAL_FALSE; } - // now that the window is attached, we can use PAL video API - // to manager it - result = palSetWindowTitle(myWindow, WINDOW_TITLE); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set window title"); - return PAL_FALSE; - } + // now that the window is attached, we can use PAL video API to manager it + palSetWindowTitle(myWindow, WINDOW_TITLE); PalBool running = PAL_TRUE; PalBool detached = PAL_FALSE; diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index f276762d..c9080d1d 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -900,12 +900,7 @@ PalBool customDecorationTest() } // get native handles - result = palGetWindowHandleInfo(window, &s_WinHandle); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } - + palGetWindowHandleInfo(window, &s_WinHandle); s_Decoration.driver = eventDriver; createDecoration(); diff --git a/tests/video/icon_test.c b/tests/video/icon_test.c index 8bca2285..74d1af70 100644 --- a/tests/video/icon_test.c +++ b/tests/video/icon_test.c @@ -96,11 +96,7 @@ PalBool iconTest() palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // set the icon - result = palSetWindowIcon(window, icon); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set window icon"); - return PAL_FALSE; - } + palSetWindowIcon(window, icon); PalBool running = PAL_TRUE; while (running) { diff --git a/tests/video/monitor_mode_test.c b/tests/video/monitor_mode_test.c index 5ca1bc6a..92881c95 100644 --- a/tests/video/monitor_mode_test.c +++ b/tests/video/monitor_mode_test.c @@ -12,7 +12,7 @@ PalBool monitorModeTest() } // get the number of connected monitors - int32_t count = 0; + uint32_t count = 0; result = palEnumerateMonitors(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get query monitors"); @@ -46,7 +46,7 @@ PalBool monitorModeTest() PalMonitorInfo info = {0}; for (int32_t i = 0; i < count; i++) { PalMonitor* monitor = monitors[i]; - result = palGetMonitorInfo(monitor, &info); + palGetMonitorInfo(monitor, &info); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get monitor info"); return PAL_FALSE; @@ -56,12 +56,8 @@ PalBool monitorModeTest() palLog(nullptr, "Monitor Name: %s", info.name); // get number of monitor modes - int32_t modeCount = 0; - result = palEnumerateMonitorModes(monitor, &modeCount, nullptr); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get query monitor modes"); - return PAL_FALSE; - } + uint32_t modeCount = 0; + palEnumerateMonitorModes(monitor, &modeCount, nullptr); palLog(nullptr, "Monitor Mode Count: %d", modeCount); // allocate an array of monitor modes or use a fixed array @@ -75,11 +71,7 @@ PalBool monitorModeTest() } // get the monitor modes - result = palEnumerateMonitorModes(monitor, &modeCount, modes); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get query monitor modes"); - return PAL_FALSE; - } + palEnumerateMonitorModes(monitor, &modeCount, modes); for (int32_t i = 0; i < modeCount; i++) { // log monitor mode @@ -95,11 +87,7 @@ PalBool monitorModeTest() // get current monitor mode and log PalMonitorMode current; - result = palGetCurrentMonitorMode(monitor, ¤t); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get current monitor mode"); - return PAL_FALSE; - } + palGetCurrentMonitorMode(monitor, ¤t); palLog(nullptr, ""); palLog(nullptr, " Current Mode:"); diff --git a/tests/video/monitor_test.c b/tests/video/monitor_test.c index 8f3a9f2f..fed27c0c 100644 --- a/tests/video/monitor_test.c +++ b/tests/video/monitor_test.c @@ -12,7 +12,7 @@ PalBool monitorTest() } // get the number of connected monitors - int32_t count = 0; + uint32_t count = 0; result = palEnumerateMonitors(&count, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get query monitors"); @@ -46,11 +46,7 @@ PalBool monitorTest() PalMonitorInfo info = {0}; for (int32_t i = 0; i < count; i++) { PalMonitor* monitor = monitors[i]; - result = palGetMonitorInfo(monitor, &info); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get monitor info"); - return PAL_FALSE; - } + palGetMonitorInfo(monitor, &info); // log monitor info palLog(nullptr, "Monitor Name: %s", info.name); diff --git a/tests/video/native_integration_test.c b/tests/video/native_integration_test.c index 3ad31129..a604017c 100644 --- a/tests/video/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -369,11 +369,7 @@ PalBool nativeIntegrationTest() // set the window title using native APIs PalWindowHandleInfo windowInfo = {0}; - result = palGetWindowHandleInfo(window, &windowInfo); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to get window handle info"); - return PAL_FALSE; - } + palGetWindowHandleInfo(window, &windowInfo); palLog(nullptr, "Window title: %s", createInfo.title); palLog(nullptr, "Setting window title with native API"); diff --git a/tests/video/window_test.c b/tests/video/window_test.c index f25b0063..d7cdaa30 100644 --- a/tests/video/window_test.c +++ b/tests/video/window_test.c @@ -254,12 +254,7 @@ PalBool windowTest() #if MAKE_TRANSPARENT if (features & PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW) { - result = palSetWindowOpacity(window, OPACITY); - if (result != PAL_RESULT_SUCCESS) { - const char* error = palFormatResult(result); - palLog(nullptr, "Failed to set window opacity: %s", error); - return PAL_FALSE; - } + palSetWindowOpacity(window, OPACITY); } #endif // MAKE_TRANSPARENT From 4c8b0982af6fa1b8647a9223692388a5b6fe80b4 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 10 Jul 2026 14:29:31 +0000 Subject: [PATCH 328/372] fix module source layers --- CHANGELOG.md | 1 + include/pal/pal_event.h | 4 +- src/core/pal_version.c | 8 +- src/core/posix/pal_log_posix.c | 4 - src/core/posix/pal_memory_posix.c | 12 +- src/core/posix/pal_result_posix.c | 9 +- src/core/win32/pal_log_win32.c | 8 - src/core/win32/pal_memory_win32.c | 12 +- src/core/win32/pal_result_win32.c | 25 +- src/event/pal_event.c | 25 +- src/graphics/pal_graphics.c | 96 ++++++ src/opengl/pal_opengl.c | 92 +---- src/thread/posix/pal_thread_posix.c | 14 +- src/thread/win32/pal_thread_win32.c | 29 +- src/video/pal_video.c | 515 +++++----------------------- 15 files changed, 233 insertions(+), 621 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d5595ec..c095aeb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,7 @@ validation anymore: invalid arguments, feature not supported results in undefine - `palGetPrimaryMonitor()` - `palGetMonitorInfo()` - `palEnumerateMonitorModes()` + - `palGetCurrentMonitorMode()` - `palMinimizeWindow()` - `palMaximizeWindow()` - `palRestoreWindow()` diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 184b5274..02c44169 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -366,9 +366,9 @@ typedef struct { * longer needed. * * @param[in] info Pointer to a PalEventDriverCreateInfo struct that specifies - * parameters. Must not be `nullptr`. + * parameters. * @param[out] outEventDriver Pointer to a PalEventDriver to recieve the created - * event driver. Must not be `nullptr`. + * event driver. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. diff --git a/src/core/pal_version.c b/src/core/pal_version.c index 591d81a3..0534d934 100644 --- a/src/core/pal_version.c +++ b/src/core/pal_version.c @@ -14,11 +14,9 @@ void PAL_CALL palGetVersion(PalVersion* version) { - if (version) { - version->major = PAL_VERSION_MAJOR; - version->minor = PAL_VERSION_MINOR; - version->build = PAL_VERSION_BUILD; - } + version->major = PAL_VERSION_MAJOR; + version->minor = PAL_VERSION_MINOR; + version->build = PAL_VERSION_BUILD; } const char* PAL_CALL palGetVersionString() diff --git a/src/core/posix/pal_log_posix.c b/src/core/posix/pal_log_posix.c index 44ed0cd3..5e80d133 100644 --- a/src/core/posix/pal_log_posix.c +++ b/src/core/posix/pal_log_posix.c @@ -43,10 +43,6 @@ void PAL_CALL palLog( const char* fmt, ...) { - if (!fmt) { - return; - } - LogTLSData* data = pthread_getspecific(s_TLSID); if (!data) { data = palAllocate(nullptr, sizeof(LogTLSData), 0); diff --git a/src/core/posix/pal_memory_posix.c b/src/core/posix/pal_memory_posix.c index baf9d53e..66017faf 100644 --- a/src/core/posix/pal_memory_posix.c +++ b/src/core/posix/pal_memory_posix.c @@ -22,7 +22,7 @@ void* PAL_CALL palAllocate( align = 16; // default } - if (allocator && allocator->allocate) { + if (allocator) { return allocator->allocate(allocator->userData, size, align); } @@ -35,12 +35,10 @@ void PAL_CALL palFree( const PalAllocator* allocator, void* ptr) { - if (ptr) { - if (allocator && allocator->free) { - allocator->free(allocator->userData, ptr); - } else { - free(ptr); - } + if (allocator) { + allocator->free(allocator->userData, ptr); + } else { + free(ptr); } } diff --git a/src/core/posix/pal_result_posix.c b/src/core/posix/pal_result_posix.c index ae23c474..0791c359 100644 --- a/src/core/posix/pal_result_posix.c +++ b/src/core/posix/pal_result_posix.c @@ -20,13 +20,8 @@ void PAL_CALL palFormatResult( { char tmpBuffer[256]; uint32_t nativeCode = palGetResultNativeCode(result); - if (nativeCode != 0) { - strerror_r(nativeCode, tmpBuffer, 256); - formatResultMsg(result, buffer, tmpBuffer); - - } else { - formatResultMsg(result, buffer, nullptr); - } + strerror_r(nativeCode, tmpBuffer, 256); + formatResultMsg(result, buffer, tmpBuffer); } #endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/core/win32/pal_log_win32.c b/src/core/win32/pal_log_win32.c index 1ffa322b..f61d99e2 100644 --- a/src/core/win32/pal_log_win32.c +++ b/src/core/win32/pal_log_win32.c @@ -47,10 +47,6 @@ void PAL_CALL palLog( const char* fmt, ...) { - if (!fmt) { - return; - } - LogTLSData* data = FlsGetValue((DWORD)s_TlsID); if (!data) { data = palAllocate(nullptr, sizeof(LogTLSData), 0); @@ -95,10 +91,6 @@ void PAL_CALL palLog( // write to console HANDLE console = GetStdHandle(STD_ERROR_HANDLE); int len = MultiByteToWideChar(CP_UTF8, 0, data->buffer, -1, nullptr, 0); - if (!len) { - return; - } - MultiByteToWideChar(CP_UTF8, 0, data->buffer, -1, data->wideBuffer, len); if (console) { WriteConsoleW(console, data->wideBuffer, (DWORD)len - 1, NULL, 0); diff --git a/src/core/win32/pal_memory_win32.c b/src/core/win32/pal_memory_win32.c index 50249141..4f8c9bc8 100644 --- a/src/core/win32/pal_memory_win32.c +++ b/src/core/win32/pal_memory_win32.c @@ -22,7 +22,7 @@ void* PAL_CALL palAllocate( align = 16; // default } - if (allocator && allocator->allocate) { + if (allocator) { return allocator->allocate(allocator->userData, size, align); } @@ -33,12 +33,10 @@ void PAL_CALL palFree( const PalAllocator* allocator, void* ptr) { - if (ptr) { - if (allocator && allocator->free) { - allocator->free(allocator->userData, ptr); - } else { - _aligned_free(ptr); - } + if (allocator) { + allocator->free(allocator->userData, ptr); + } else { + _aligned_free(ptr); } } diff --git a/src/core/win32/pal_result_win32.c b/src/core/win32/pal_result_win32.c index 86c3c2c6..60f8cea8 100644 --- a/src/core/win32/pal_result_win32.c +++ b/src/core/win32/pal_result_win32.c @@ -31,21 +31,16 @@ void PAL_CALL palFormatResult( { char tmpBuffer[256]; uint32_t nativeCode = palGetResultNativeCode(result); - if (nativeCode != 0) { - FormatMessageA( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, - nativeCode, - 0, - tmpBuffer, - 256, - nullptr); - - formatResultMsg(result, buffer, tmpBuffer); - - } else { - formatResultMsg(result, buffer, nullptr); - } + FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + nativeCode, + 0, + tmpBuffer, + 256, + nullptr); + + formatResultMsg(result, buffer, tmpBuffer); } #endif // _WIN32 \ No newline at end of file diff --git a/src/event/pal_event.c b/src/event/pal_event.c index f3ed774a..9d5178f5 100644 --- a/src/event/pal_event.c +++ b/src/event/pal_event.c @@ -25,12 +25,6 @@ PalResult PAL_CALL palCreateEventDriver( return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (info->allocator) { - if (!info->allocator->allocate && !info->allocator->free) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - } - PalEventDriver* driver = nullptr; driver = palAllocate(info->allocator, sizeof(PalEventDriver), 0); if (!driver) { @@ -67,10 +61,6 @@ PalResult PAL_CALL palCreateEventDriver( void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver) { - if (!eventDriver) { - return; - } - const PalAllocator* allocator = eventDriver->allocator; if (eventDriver->freeQueue) { destroyDefaultEventQueue(allocator, eventDriver->queue); @@ -83,18 +73,13 @@ void PAL_CALL palSetEventDispatchMode( PalEventType type, PalDispatchMode mode) { - if (eventDriver) { - eventDriver->modes[type] = mode; - } + eventDriver->modes[type] = mode; } PalDispatchMode PAL_CALL palGetEventDispatchMode( PalEventDriver* eventDriver, PalEventType type) { - if (!eventDriver) { - return PAL_DISPATCH_MODE_NONE; - } return eventDriver->modes[type]; } @@ -102,10 +87,6 @@ void PAL_CALL palPushEvent( PalEventDriver* eventDriver, PalEvent* event) { - if (!eventDriver || !event) { - return; - } - // get the event mode PalDispatchMode mode = eventDriver->modes[event->type]; if (mode == PAL_DISPATCH_MODE_CALLBACK) { @@ -124,9 +105,5 @@ PalBool PAL_CALL palPollEvent( PalEventDriver* eventDriver, PalEvent* outEvent) { - if (!eventDriver || !outEvent) { - return PAL_FALSE; - } - return eventDriver->queue->poll(eventDriver->queue, outEvent); } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index b0ab2b9f..85a3319e 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -472,6 +472,10 @@ PalResult PAL_CALL palEnumerateAdapters( uint32_t* count, PalAdapter** outAdapters) { + if (!count) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + // enumerate all adapters for both custom and PAL backends PalResult result = 0; int totalCount = 0; @@ -550,6 +554,10 @@ PalResult PAL_CALL palCreateDevice( PalAdapterFeatures features, PalDevice** outDevice) { + if (!adapter || !outDevice) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalDevice* device = nullptr; PalResult result; result = adapter->backend->createDevice(adapter, features, &device); @@ -574,6 +582,10 @@ PalResult PAL_CALL palAllocateMemory( uint64_t size, PalMemory** outMemory) { + if (!device || !outMemory) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalMemory* memory = nullptr; PalResult result; result = device->backend->allocateMemory(device, type, memoryMask, size, &memory); @@ -660,6 +672,10 @@ PalResult PAL_CALL palCreateQueue( PalQueueType type, PalQueue** outQueue) { + if (!device || !outQueue) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalQueue* queue = nullptr; PalResult result; result = device->backend->createQueue(device, type, &queue); @@ -731,6 +747,10 @@ PalResult PAL_CALL palCreateImage( const PalImageCreateInfo* info, PalImage** outImage) { + if (!device || !info || !outImage) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalImage* image = nullptr; PalResult result; result = device->backend->createImage(device, info, &image); @@ -780,6 +800,10 @@ PalResult PAL_CALL palCreateImageView( const PalImageViewCreateInfo* info, PalImageView** outImageView) { + if (!device || !image || !info || !outImageView) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalImageView* imageView = nullptr; PalResult result; result = device->backend->createImageView(device, image, info, &imageView); @@ -806,6 +830,10 @@ PalResult PAL_CALL palCreateSampler( const PalSamplerCreateInfo* info, PalSampler** outSampler) { + if (!device || !info || !outSampler) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalSampler* sampler = nullptr; PalResult result; result = device->backend->createSampler(device, info, &sampler); @@ -834,6 +862,10 @@ PalResult PAL_CALL palCreateSurface( PalWindowInstanceType instanceType, PalSurface** outSurface) { + if (!device || !window || !windowInstance || !outSurface) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalSurface* surface = nullptr; PalResult ret; ret = device->backend->createSurface(device, window, windowInstance, instanceType, &surface); @@ -870,6 +902,10 @@ PalResult PAL_CALL palCreateSwapchain( const PalSwapchainCreateInfo* info, PalSwapchain** outSwapchain) { + if (!device || !queue || !surface || !info || !outSwapchain) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalSwapchain* swapchain = nullptr; result = device->backend->createSwapchain(device, queue, surface, info, &swapchain); @@ -933,6 +969,10 @@ PalResult PAL_CALL palCreateShader( const PalShaderCreateInfo* info, PalShader** outShader) { + if (!device || !info || !outShader) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalShader* shader = nullptr; PalResult result; result = device->backend->createShader(device, info, &shader); @@ -959,6 +999,10 @@ PalResult PAL_CALL palCreateFence( PalBool signaled, PalFence** outFence) { + if (!device || !outFence) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalFence* fence = nullptr; PalResult result; result = device->backend->createFence(device, signaled, &fence); @@ -1002,6 +1046,10 @@ PalResult PAL_CALL palCreateSemaphore( PalBool enableTimeline, PalSemaphore** outSemaphore) { + if (!device || !outSemaphore) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalSemaphore* semaphore = nullptr; PalResult result; result = device->backend->createSemaphore(device, enableTimeline, &semaphore); @@ -1051,6 +1099,10 @@ PalResult PAL_CALL palCreateCommandPool( PalQueue* queue, PalCommandPool** outPool) { + if (!device || !queue || !outPool) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalCommandPool* pool = nullptr; PalResult result; result = device->backend->createCommandPool(device, queue, &pool); @@ -1079,6 +1131,10 @@ PalResult PAL_CALL palAllocateCommandBuffer( PalCommandBufferType type, PalCommandBuffer** outCmdBuffer) { + if (!device || !pool || !outCmdBuffer) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalCommandBuffer* cmdBuffer = nullptr; PalResult result; result = device->backend->allocateCommandBuffer(device, pool, type, &cmdBuffer); @@ -1496,6 +1552,10 @@ PalResult PAL_CALL palCreateAccelerationstructure( const PalAccelerationStructureCreateInfo* info, PalAccelerationStructure** outAs) { + if (!device || !info || !outAs) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalAccelerationStructure* as = nullptr; result = device->backend->createAccelerationstructure(device, info, &as); @@ -1530,6 +1590,10 @@ PalResult PAL_CALL palCreateBuffer( const PalBufferCreateInfo* info, PalBuffer** outBuffer) { + if (!device || !info || !outBuffer) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalBuffer* buffer = nullptr; result = device->backend->createBuffer(device, info, &buffer); @@ -1630,6 +1694,10 @@ PalResult PAL_CALL palCreateDescriptorSetLayout( const PalDescriptorSetLayoutCreateInfo* info, PalDescriptorSetLayout** outLayout) { + if (!device || !info || !outLayout) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalDescriptorSetLayout* layout = nullptr; result = device->backend->createDescriptorSetLayout(device, info, &layout); @@ -1652,6 +1720,10 @@ PalResult PAL_CALL palCreateDescriptorPool( const PalDescriptorPoolCreateInfo* info, PalDescriptorPool** outPool) { + if (!device || !info || !outPool) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalDescriptorPool* pool = nullptr; result = device->backend->createDescriptorPool(device, info, &pool); @@ -1680,6 +1752,10 @@ PalResult PAL_CALL palAllocateDescriptorSet( PalDescriptorSetLayout* layout, PalDescriptorSet** outSet) { + if (!device || !pool || !layout || !outSet) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalDescriptorSet* set = nullptr; result = device->backend->allocateDescriptorSet(device, pool, layout, &set); @@ -1709,6 +1785,10 @@ PalResult PAL_CALL palCreatePipelineLayout( const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout) { + if (!device || !info || !outLayout) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalPipelineLayout* layout = nullptr; result = device->backend->createPipelineLayout(device, info, &layout); @@ -1735,6 +1815,10 @@ PalResult PAL_CALL palCreateGraphicsPipeline( const PalGraphicsPipelineCreateInfo* info, PalPipeline** outPipeline) { + if (!device || !info || !outPipeline) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalPipeline* pipeline = nullptr; result = device->backend->createGraphicsPipeline(device, info, &pipeline); @@ -1752,6 +1836,10 @@ PalResult PAL_CALL palCreateComputePipeline( const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline) { + if (!device || !info || !outPipeline) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalPipeline* pipeline = nullptr; result = device->backend->createComputePipeline(device, info, &pipeline); @@ -1769,6 +1857,10 @@ PalResult PAL_CALL palCreateRayTracingPipeline( const PalRayTracingPipelineCreateInfo* info, PalPipeline** outPipeline) { + if (!device || !info || !outPipeline) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalPipeline* pipeline = nullptr; result = device->backend->createRayTracingPipeline(device, info, &pipeline); @@ -1795,6 +1887,10 @@ PalResult PAL_CALL palCreateShaderBindingTable( const PalShaderBindingTableCreateInfo* info, PalShaderBindingTable** outSbt) { + if (!device || !info || !outSbt) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + PalResult result; PalShaderBindingTable* sbt = nullptr; result = device->backend->createShaderBindingTable(device, info, &sbt); diff --git a/src/opengl/pal_opengl.c b/src/opengl/pal_opengl.c index 94f3856f..cf502f64 100644 --- a/src/opengl/pal_opengl.c +++ b/src/opengl/pal_opengl.c @@ -9,12 +9,7 @@ #include "pal_opengl_backends.h" #include -typedef struct { - PalBool initialized; - const OpenglBackend* backend; -} Opengl; - -static Opengl s_Gl = {0}; +static OpenglBackend* s_Backend = nullptr; PalBool checkString( const char* string, @@ -49,25 +44,17 @@ PalResult PAL_CALL palInitGL( void* instance, const PalAllocator* allocator) { - if (s_Gl.initialized) { - return PAL_RESULT_SUCCESS; - } - if (!instance) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - // initialize the backends #ifdef _WIN32 PalResult result = wglInitGL(api, instance, allocator); if (result != PAL_RESULT_SUCCESS) { return result; } - s_Gl.backend = &s_WglBackend; + s_Backend = &s_WglBackend; #endif // _WIN32 #if _PAL_HAS_EGL @@ -75,47 +62,35 @@ PalResult PAL_CALL palInitGL( if (result != PAL_RESULT_SUCCESS) { return result; } - s_Gl.backend = &s_EglBackend; + s_Backend = &s_EglBackend; #endif // _PAL_HAS_EGL // check if we found a backend - if (!s_Gl.backend) { + if (!s_Backend) { return PAL_RESULT_CODE_PLATFORM_FAILURE; } - - s_Gl.initialized = PAL_TRUE; return PAL_RESULT_SUCCESS; } void PAL_CALL palShutdownGL() { - if (s_Gl.initialized) { - s_Gl.backend->shutdownGL(); - s_Gl.initialized = PAL_FALSE; - } + s_Backend->shutdownGL(); } const PalGLInfo* PAL_CALL palGetGLInfo() { - if (s_Gl.initialized) { - return s_Gl.backend->getGLInfo(); - } - return nullptr; + return s_Backend->getGLInfo(); } PalResult PAL_CALL palEnumerateGLFBConfigs( int32_t* count, PalGLFBConfig* configs) { - if (!s_Gl.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!count || *count == 0 && configs) { + if (!count) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return s_Gl.backend->enumerateGLFBConfigs(count, configs); + return s_Backend->enumerateGLFBConfigs(count, configs); } const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( @@ -123,14 +98,6 @@ const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( int32_t count, const PalGLFBConfig* desired) { - if (!configs || !desired) { - return nullptr; - } - - if (count == 0) { - return nullptr; - } - int32_t score = 0; int32_t bestScore = 0x7FFFFFFF; PalGLFBConfig* best = nullptr; @@ -178,78 +145,47 @@ PalResult PAL_CALL palCreateGLContext( const PalGLContextCreateInfo* info, PalGLContext** outContext) { - if (!s_Gl.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - if (!info || !outContext) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return s_Gl.backend->createGLContext(info, outContext); + return s_Backend->createGLContext(info, outContext); } void PAL_CALL palDestroyGLContext(PalGLContext* context) { - if (s_Gl.initialized && context) { - s_Gl.backend->destroyGLContext(context); - } + s_Backend->destroyGLContext(context); } PalResult PAL_CALL palMakeContextCurrent( PalGLWindow* glWindow, PalGLContext* context) { - if (!s_Gl.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!glWindow || !context) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Gl.backend->makeContextCurrent(glWindow, context); + return s_Backend->makeContextCurrent(glWindow, context); } void* PAL_CALL palGetGLProcAddress(const char* name) { - if (s_Gl.initialized && name) { - return s_Gl.backend->getGLProcAddress(name); - } - return nullptr; + return s_Backend->getGLProcAddress(name); } PalResult PAL_CALL palSwapBuffers( PalGLWindow* glWindow, PalGLContext* context) { - if (!s_Gl.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!glWindow || !context) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Gl.backend->swapBuffers(glWindow, context); + return s_Backend->swapBuffers(glWindow, context); } PalResult PAL_CALL palSetSwapInterval(int32_t interval) { - if (!s_Gl.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - return s_Gl.backend->setSwapInterval(interval); + return s_Backend->setSwapInterval(interval); } const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance) { - if (instance) { #if _PAL_HAS_EGL return eglGetSupportedGLAPIs(instance); #elif defined(_WIN32) return wglGetSupportedGLAPIs(instance); #endif // _PAL_HAS_EGL - } - return nullptr; } \ No newline at end of file diff --git a/src/thread/posix/pal_thread_posix.c b/src/thread/posix/pal_thread_posix.c index abf8177a..601183ee 100644 --- a/src/thread/posix/pal_thread_posix.c +++ b/src/thread/posix/pal_thread_posix.c @@ -167,29 +167,19 @@ uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) return 0; } -PalResult PAL_CALL palGetThreadName( +void PAL_CALL palGetThreadName( PalThread* thread, uint64_t bufferSize, uint64_t* outSize, char* outBuffer) { - if (!thread) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - #ifdef __linux__ // see if user provided a buffer and write to it if (outBuffer && bufferSize > 0) { pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); - if (pthread_getname_np(_thread, outBuffer, bufferSize) != 0) { - return palMakeResult(PAL_RESULT_CODE_INVALID_HANDLE, PAL_RESULT_SOURCE_POSIX, errno); - } + pthread_getname_np(_thread, outBuffer, bufferSize); } - - return PAL_RESULT_SUCCESS; #endif // __linux__ - - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalResult PAL_CALL palSetThreadPriority( diff --git a/src/thread/win32/pal_thread_win32.c b/src/thread/win32/pal_thread_win32.c index e344e1fe..ac226a2f 100644 --- a/src/thread/win32/pal_thread_win32.c +++ b/src/thread/win32/pal_thread_win32.c @@ -196,37 +196,18 @@ uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) return mask; } -PalResult PAL_CALL palGetThreadName( +void PAL_CALL palGetThreadName( PalThread* thread, uint64_t bufferSize, uint64_t* outSize, char* outBuffer) { - if (!thread) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); - GetThreadDescriptionFn getThreadDescription = nullptr; - if (kernel32) { - getThreadDescription = - (GetThreadDescriptionFn)GetProcAddress(kernel32, "GetThreadDescription"); - } - - if (!getThreadDescription) { - // not supported - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } + GetThreadDescriptionFn getThreadDesc = nullptr; + getThreadDesc = (GetThreadDescriptionFn)GetProcAddress(kernel32, "GetThreadDescription"); wchar_t* buffer = nullptr; - HRESULT hr = getThreadDescription((HANDLE)thread, &buffer); - if (!SUCCEEDED(hr)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - hr); - } - + getThreadDesc((HANDLE)thread, &buffer); int len = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, nullptr, 0, 0, 0); if (outSize) { *outSize = len - 1; @@ -239,8 +220,6 @@ PalResult PAL_CALL palGetThreadName( outBuffer[write < len - 1 ? write : len - 1] = '\0'; LocalFree(buffer); } - - return PAL_RESULT_SUCCESS; } PalResult PAL_CALL palSetThreadPriority( diff --git a/src/video/pal_video.c b/src/video/pal_video.c index 5447beed..7ad26305 100644 --- a/src/video/pal_video.c +++ b/src/video/pal_video.c @@ -9,13 +9,8 @@ #include "pal_video_egl.h" #include -typedef struct { - PalBool initialized; - const VideoBackend* backend; -} Video; - VideoEGL s_VideoEgl = {0}; -static Video s_Video = {0}; +static VideoBackend* s_Backend = nullptr; static int compareModes( const void* a, @@ -68,14 +63,6 @@ PalResult PAL_CALL palInitVideo( PalEventDriver* eventDriver, void* preferredInstance) { - if (s_Video.initialized) { - return PAL_RESULT_SUCCESS; - } - - if (allocator && (!allocator->allocate || !allocator->free)) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - // check if x11 or wayland is active PalBool x11 = PAL_FALSE; PalBool wayland = PAL_FALSE; @@ -94,7 +81,7 @@ PalResult PAL_CALL palInitVideo( if (result != PAL_RESULT_SUCCESS) { return result; } - s_Video.backend = &s_Win32Backend; + s_Backend = &s_Win32Backend; #endif // _WIN32 if (x11) { @@ -103,7 +90,7 @@ PalResult PAL_CALL palInitVideo( if (result != PAL_RESULT_SUCCESS) { return result; } - s_Video.backend = &s_XBackend; + s_Backend = &s_XBackend; #endif // PAL_HAS_X11_BACKEND } else if (wayland) { @@ -112,711 +99,385 @@ PalResult PAL_CALL palInitVideo( if (result != PAL_RESULT_SUCCESS) { return result; } - s_Video.backend = &s_wlBackend; + s_Backend = &s_wlBackend; #endif // PAL_HAS_WAYLAND_BACKEND } // check if we found a backend - if (!s_Video.backend) { + if (!s_Backend) { return PAL_RESULT_CODE_PLATFORM_FAILURE; } - - s_Video.initialized = PAL_TRUE; return PAL_RESULT_SUCCESS; } void PAL_CALL palShutdownVideo() { - if (s_Video.initialized) { - s_Video.backend->shutdownVideo(); - s_Video.initialized = PAL_FALSE; - } + s_Backend->shutdownVideo(); } void PAL_CALL palUpdateVideo() { - if (s_Video.initialized) { - s_Video.backend->updateVideo(); - } + s_Backend->updateVideo(); } PalVideoFeatures PAL_CALL palGetVideoFeatures() { - if (s_Video.initialized) { - s_Video.backend->getVideoFeatures(); - } + return s_Backend->getVideoFeatures(); } PalResult PAL_CALL palEnumerateMonitors( uint32_t* count, PalMonitor** outMonitors) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!count || *count == 0 && outMonitors) { + if (!count) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return s_Video.backend->enumerateMonitors(count, outMonitors); + return s_Backend->enumerateMonitors(count, outMonitors); } -PalResult PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) +void PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!outMonitor) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->getPrimaryMonitor(outMonitor); + return s_Backend->getPrimaryMonitor(outMonitor); } -PalResult PAL_CALL palGetMonitorInfo( +void PAL_CALL palGetMonitorInfo( PalMonitor* monitor, PalMonitorInfo* info) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->getMonitorInfo(monitor, info); + s_Backend->getMonitorInfo(monitor, info); } -PalResult PAL_CALL palEnumerateMonitorModes( +void PAL_CALL palEnumerateMonitorModes( PalMonitor* monitor, uint32_t* count, PalMonitorMode* modes) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!monitor || !count || *count == 0 && modes) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - PalResult result = s_Video.backend->enumerateMonitorModes(monitor, count, modes); - if (result == PAL_RESULT_SUCCESS && modes) { + s_Backend->enumerateMonitorModes(monitor, count, modes); + if (modes) { // sort the modes so that they are highest to lowest qsort(modes, *count, sizeof(PalMonitorMode), compareModes); } - - return result; } -PalResult PAL_CALL palGetCurrentMonitorMode( +void PAL_CALL palGetCurrentMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!monitor || !mode) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->getCurrentMonitorMode(monitor, mode); + return s_Backend->getCurrentMonitorMode(monitor, mode); } PalResult PAL_CALL palSetMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!monitor || !mode) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->setMonitorMode(monitor, mode); + return s_Backend->setMonitorMode(monitor, mode); } PalResult PAL_CALL palValidateMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!monitor || !mode) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->validateMonitorMode(monitor, mode); + return s_Backend->validateMonitorMode(monitor, mode); } PalResult PAL_CALL palSetMonitorOrientation( PalMonitor* monitor, PalOrientation orientation) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!monitor) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->setMonitorOrientation(monitor, orientation); + return s_Backend->setMonitorOrientation(monitor, orientation); } PalResult PAL_CALL palCreateWindow( const PalWindowCreateInfo* info, PalWindow** outWindow) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - if (!info || !outWindow) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return s_Video.backend->createWindow(info, outWindow); + return s_Backend->createWindow(info, outWindow); } void PAL_CALL palDestroyWindow(PalWindow* window) { - if (s_Video.initialized && window) { - return s_Video.backend->destroyWindow(window); - } + return s_Backend->destroyWindow(window); } -PalResult PAL_CALL palMinimizeWindow(PalWindow* window) +void PAL_CALL palMinimizeWindow(PalWindow* window) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->maximizeWindow(window); + s_Backend->maximizeWindow(window); } -PalResult PAL_CALL palMaximizeWindow(PalWindow* window) +void PAL_CALL palMaximizeWindow(PalWindow* window) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->minimizeWindow(window); + s_Backend->minimizeWindow(window); } -PalResult PAL_CALL palRestoreWindow(PalWindow* window) +void PAL_CALL palRestoreWindow(PalWindow* window) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->restoreWindow(window); + s_Backend->restoreWindow(window); } -PalResult PAL_CALL palShowWindow(PalWindow* window) +void PAL_CALL palShowWindow(PalWindow* window) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->showWindow(window); + s_Backend->showWindow(window); } -PalResult PAL_CALL palHideWindow(PalWindow* window) +void PAL_CALL palHideWindow(PalWindow* window) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->hideWindow(window); + s_Backend->hideWindow(window); } -PalResult PAL_CALL palFlashWindow( +void PAL_CALL palFlashWindow( PalWindow* window, const PalFlashInfo* info) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window || !info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->flashWindow(window, info); + s_Backend->flashWindow(window, info); } -PalResult PAL_CALL palGetWindowStyle( +void PAL_CALL palGetWindowStyle( PalWindow* window, PalWindowStyle* outStyle) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window || !outStyle) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->getWindowStyle(window, outStyle); + s_Backend->getWindowStyle(window, outStyle); } -PalResult PAL_CALL palGetWindowMonitor( +void PAL_CALL palGetWindowMonitor( PalWindow* window, PalMonitor** outMonitor) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window || !outMonitor) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->getWindowMonitor(window, outMonitor); + s_Backend->getWindowMonitor(window, outMonitor); } -PalResult PAL_CALL palGetWindowTitle( +void PAL_CALL palGetWindowTitle( PalWindow* window, uint64_t bufferSize, uint64_t* outSize, char* outBuffer) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window || !outBuffer) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->getWindowTitle(window, bufferSize, outSize, outBuffer); + s_Backend->getWindowTitle(window, bufferSize, outSize, outBuffer); } -PalResult PAL_CALL palGetWindowPos( +void PAL_CALL palGetWindowPos( PalWindow* window, int32_t* x, int32_t* y) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->getWindowPos(window, x, y); + s_Backend->getWindowPos(window, x, y); } -PalResult PAL_CALL palGetWindowSize( +void PAL_CALL palGetWindowSize( PalWindow* window, uint32_t* width, uint32_t* height) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->getWindowSize(window, width, height); + s_Backend->getWindowSize(window, width, height); } -PalResult PAL_CALL palGetWindowState( +void PAL_CALL palGetWindowState( PalWindow* window, PalWindowState* outState) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window || !outState) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->getWindowState(window, outState); + s_Backend->getWindowState(window, outState); } const PalBool* PAL_CALL palGetKeycodeState() { - if (s_Video.initialized) { - return s_Video.backend->getKeycodeState(); - } - return nullptr; + return s_Backend->getKeycodeState(); } const PalBool* PAL_CALL palGetScancodeState() { - if (s_Video.initialized) { - return s_Video.backend->getScancodeState(); - } - return nullptr; + return s_Backend->getScancodeState(); } const PalBool* PAL_CALL palGetMouseState() { - if (s_Video.initialized) { - return s_Video.backend->getMouseState(); - } - return nullptr; + return s_Backend->getMouseState(); } void PAL_CALL palGetMouseDelta( float* dx, float* dy) { - if (s_Video.initialized) { - return s_Video.backend->getMouseDelta(dx, dy); - } + s_Backend->getMouseDelta(dx, dy); } void PAL_CALL palGetMouseWheelDelta( float* dx, float* dy) { - if (s_Video.initialized) { - return s_Video.backend->getMouseWheelDelta(dx, dy); - } + s_Backend->getMouseWheelDelta(dx, dy); } PalBool PAL_CALL palIsWindowVisible(PalWindow* window) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->isWindowVisible(window); + return s_Backend->isWindowVisible(window); } PalWindow* PAL_CALL palGetFocusWindow() { - if (!s_Video.initialized) { - return nullptr; - } - - return s_Video.backend->getFocusWindow(); + return s_Backend->getFocusWindow(); } -PalResult PAL_CALL palGetWindowHandleInfo( +void PAL_CALL palGetWindowHandleInfo( PalWindow* window, PalWindowHandleInfo* info) { - if (s_Video.initialized) { - return s_Video.backend->getWindowHandleInfo(window, info); - } - return PAL_RESULT_CODE_NOT_INITIALIZED; + s_Backend->getWindowHandleInfo(window, info); } -PalResult PAL_CALL palSetWindowOpacity( +void PAL_CALL palSetWindowOpacity( PalWindow* window, float opacity) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - if (opacity < 0.0f) { - opacity = 0.0f; - } - - if (opacity > 1.0f) { - opacity = 1.0f; - } - - return s_Video.backend->setWindowOpacity(window, opacity); + s_Backend->setWindowOpacity(window, opacity); } -PalResult PAL_CALL palSetWindowStyle( +void PAL_CALL palSetWindowStyle( PalWindow* window, PalWindowStyle style) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->setWindowStyle(window, style); + s_Backend->setWindowStyle(window, style); } -PalResult PAL_CALL palSetWindowTitle( +void PAL_CALL palSetWindowTitle( PalWindow* window, const char* title) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window || !title) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->setWindowTitle(window, title); + s_Backend->setWindowTitle(window, title); } -PalResult PAL_CALL palSetWindowPos( +void PAL_CALL palSetWindowPos( PalWindow* window, int32_t x, int32_t y) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->setWindowPos(window, x, y); + s_Backend->setWindowPos(window, x, y); } -PalResult PAL_CALL palSetWindowSize( +void PAL_CALL palSetWindowSize( PalWindow* window, uint32_t width, uint32_t height) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->setWindowSize(window, width, height); + s_Backend->setWindowSize(window, width, height); } -PalResult PAL_CALL palSetFocusWindow(PalWindow* window) +void PAL_CALL palSetFocusWindow(PalWindow* window) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->setFocusWindow(window); + s_Backend->setFocusWindow(window); } PalResult PAL_CALL palCreateIcon( const PalIconCreateInfo* info, PalIcon** outIcon) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - if (!info || !outIcon) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return s_Video.backend->createIcon(info, outIcon); + return s_Backend->createIcon(info, outIcon); } void PAL_CALL palDestroyIcon(PalIcon* icon) { - if (s_Video.initialized && icon) { - s_Video.backend->destroyIcon(icon); - } + s_Backend->destroyIcon(icon); } -PalResult PAL_CALL palSetWindowIcon( +void PAL_CALL palSetWindowIcon( PalWindow* window, PalIcon* icon) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->setWindowIcon(window, icon); + s_Backend->setWindowIcon(window, icon); } PalResult PAL_CALL palCreateCursor( const PalCursorCreateInfo* info, PalCursor** outCursor) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - if (!info || !outCursor) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return s_Video.backend->createCursor(info, outCursor); + return s_Backend->createCursor(info, outCursor); } PalResult PAL_CALL palCreateCursorFrom( PalCursorType type, PalCursor** outCursor) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - if (!outCursor) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return s_Video.backend->createCursorFrom(type, outCursor); + return s_Backend->createCursorFrom(type, outCursor); } void PAL_CALL palDestroyCursor(PalCursor* cursor) { - if (s_Video.initialized && cursor) { - s_Video.backend->destroyCursor(cursor); - } + s_Backend->destroyCursor(cursor); } void PAL_CALL palShowCursor(PalBool show) { - if (s_Video.initialized) { - s_Video.backend->showCursor(show); - } + s_Backend->showCursor(show); } -PalResult PAL_CALL palClipCursor( +void PAL_CALL palClipCursor( PalWindow* window, PalBool clip) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->clipCursor(window, clip); + s_Backend->clipCursor(window, clip); } -PalResult PAL_CALL palGetCursorPos( +void PAL_CALL palGetCursorPos( PalWindow* window, int32_t* x, int32_t* y) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->getCursorPos(window, x, y); + s_Backend->getCursorPos(window, x, y); } -PalResult PAL_CALL palSetCursorPos( +void PAL_CALL palSetCursorPos( PalWindow* window, int32_t x, int32_t y) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->setCursorPos(window, x, y); + s_Backend->setCursorPos(window, x, y); } -PalResult PAL_CALL palSetWindowCursor( +void PAL_CALL palSetWindowCursor( PalWindow* window, PalCursor* cursor) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - - if (!window) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - - return s_Video.backend->setWindowCursor(window, cursor); + s_Backend->setWindowCursor(window, cursor); } PalResult PAL_CALL palAttachWindow( void* windowHandle, PalWindow** outWindow) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - if (!windowHandle) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return s_Video.backend->attachWindow(windowHandle, outWindow); + return s_Backend->attachWindow(windowHandle, outWindow); } PalResult PAL_CALL palDetachWindow( PalWindow* window, void** outWindowHandle) { - if (!s_Video.initialized) { - return PAL_RESULT_CODE_NOT_INITIALIZED; - } - if (!window) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - return s_Video.backend->detachWindow(window, outWindowHandle); + return s_Backend->detachWindow(window, outWindowHandle); } void* PAL_CALL palGetInstance() { - if (s_Video.initialized) { - return s_Video.backend->getInstance(); - } - return nullptr; + return s_Backend->getInstance(); } \ No newline at end of file From 26816368bbdc70d6a23c6a7ed5eb959f088f1405 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 10 Jul 2026 15:31:25 +0000 Subject: [PATCH 329/372] update docs with API changes --- include/pal/pal_core.h | 12 +++++------ include/pal/pal_event.h | 26 ++++++------------------ include/pal/pal_graphics.h | 41 +------------------------------------- include/pal/pal_opengl.h | 4 +--- include/pal/pal_video.h | 11 ++-------- 5 files changed, 15 insertions(+), 79 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 27862974..717a7b84 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -135,8 +135,8 @@ typedef uint16_t PalResultSource; * @brief Function pointer type used for memory allocations. * * @param[in] userData Optional pointer to user data. Can be `nullptr`. - * @param[in] size Number of bytes to allocate. Must not be 0. - * @param[in] alignment Must be power of two. Set to 0 to use default. + * @param[in] size Number of bytes to allocate. + * @param[in] alignment Must be power of two. Set to 0 to use implementation-defined default. * * @return Pointer to the allocated memory on success or `nullptr` on failure. * @@ -153,8 +153,7 @@ typedef void*(PAL_CALL* PalAllocateFn)( * @brief Function pointer type used for memory deallocations. * * @param[in] userData Optional pointer to user data. Can be `nullptr`. - * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must return safely if - * pointer is `nullptr`. + * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must not be `nullptr` * * @since 1.0 * @sa PalAllocateFn @@ -267,7 +266,7 @@ PAL_API const char* PAL_CALL palGetVersionString(); * * @param allocator The allocator to use. Set to `nullptr` to use default. * @param size Number of bytes to allocate. - * @param alignment Alignment in bytes. Must be a power of two. Set to 0 to use default. + * @param alignment Must be power of two. Set to 0 to use implementation-defined default. * * @return Pointer to allocated memory on success, or `nullptr` on failure. * @@ -287,8 +286,7 @@ PAL_API void* PAL_CALL palAllocate( * * @param allocator The allocator used to allocate the memory. Set to `nullptr` to * use default. - * @param ptr Pointer to memory to free. If `nullptr`, the function returns - * silently. + * @param ptr Pointer to memory to free. Must not be `nullptr`. * * Thread safety: Thread safe if the provided allocator is thread * safe. The default allocator is thread safe. diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 02c44169..593a509a 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -312,7 +312,7 @@ typedef void(PAL_CALL* PalPushFn)( * `PAL_TRUE`. * * @param[in] userData Optional pointer to user data. Can be `nullptr`. - * @param[out] event Pointer to the PalEvent to recieve the event. + * @param[out] outEvent Pointer to the PalEvent to recieve the event. * * @since 1.0 * @sa PalPushFn @@ -362,7 +362,7 @@ typedef struct { * * The allocator field in the provided PalEventDriverCreateInfo struct will not * be copied, therefore the pointer must remain valid until the event driver is - * destroyed. Destroy the event driver with palDestroyEventDriver() when no + * destroyed. Destroy the event driver with `palDestroyEventDriver()` when no * longer needed. * * @param[in] info Pointer to a PalEventDriverCreateInfo struct that specifies @@ -387,9 +387,6 @@ PAL_API PalResult PAL_CALL palCreateEventDriver( /** * @brief Destroy the provided event driver. * - * If the provided event driver is invalid or `nullptr`, this function returns - * silently. - * * @param[in] eventDriver Pointer to the event driver to destroy. * * Thread safety: Thread safe if the allocator used to create @@ -404,14 +401,10 @@ PAL_API void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver); * @brief Set the dispatch mode for an event type with the provided event * driver. * - * If the provided event driver is invalid or `nullptr`, this function returns - * silently. - * * If the dispatch mode is `PAL_DISPATCH_MODE_POLL`, the event will be dispatched * into the event drivers event queue. If the dispatch mode is - * `PAL_DISPATCH_MODE_CALLBACK` and the event driver has a valid callback function, - * the event will be dispatched to the callback function of the event driver - * otherwise the event will be discarded. + * `PAL_DISPATCH_MODE_CALLBACK`, the event driver must have a valid callback function otherwise + * undefined behavior. * * @param[in] eventDriver Pointer to the event driver. * @param[in] type Event type to set dispatch mode for. @@ -451,15 +444,11 @@ PAL_API PalDispatchMode PAL_CALL palGetEventDispatchMode( * @brief Push an event into the queue or callback function of the provided * event driver. * - * If the provided event driver is invalid or `nullptr`, this function returns - * silently. - * * If the dispatch mode for the event is `PAL_DISPATCH_MODE_POLL`, the event will be * pushed to the event queue. * - * If dispatch mode is `PAL_DISPATCH_MODE_CALLBACK` and the event driver has a valid - * event callback, the callback will be called otherwise the event will be - * discarded. + * If dispatch mode is `PAL_DISPATCH_MODE_CALLBACK`, the event driver must have a valid callback + * function otherwise undefined behavior. * * @param[in] eventDriver Pointer to the event driver. * @param[in] event Pointer to the event to push. @@ -479,9 +468,6 @@ PAL_API void PAL_CALL palPushEvent( * @brief Retrieve the next available event from the queue of the provided event * driver. * - * If the provided event driver is invalid or `nullptr`, this function returns - * silently. - * * This function retrieves the next pending event from the queue of the * provided event driver without blocking. If no events are available, it * returns `PAL_FALSE`. diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index f8640db7..24dbc93e 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -4140,8 +4140,6 @@ PAL_API PalResult PAL_CALL palCreateDevice( * @brief Destroy a device. * * The graphics system must be initialized before this call. - * If the provided device is invalid or `nullptr`, this function returns - * silently. * * @param[in] device Pointer to the device to destroy. * @@ -4386,8 +4384,6 @@ PAL_API PalResult PAL_CALL palCreateQueue( * @brief Destroy a queue. * * The graphics system must be initialized before this call. - * If the provided queue is invalid or `nullptr`, this function returns - * silently. * * @param[in] queue Queue to destroy. * @@ -4555,8 +4551,6 @@ PAL_API PalResult PAL_CALL palCreateImage( * @brief Destroy an image. * * The graphics system must be initialized before this call. - * If the provided image is invalid or `nullptr`, this function returns - * silently. * * @param[in] image Image to destroy. * @@ -4663,8 +4657,6 @@ PAL_API PalResult PAL_CALL palCreateImageView( * @brief Destroy an image view. * * The graphics system must be initialized before this call. - * If the provided image view is invalid or `nullptr`, this function returns - * silently. * * @param[in] imageView Image view to destroy. * @@ -4705,8 +4697,6 @@ PAL_API PalResult PAL_CALL palCreateSampler( * @brief Destroy a sampler. * * The graphics system must be initialized before this call. - * If the provided sampler is invalid or `nullptr`, this function returns - * silently. * * @param[in] sampler Sampler to destroy. * @@ -4751,8 +4741,6 @@ PAL_API PalResult PAL_CALL palCreateSurface( * @brief Destroy a surface. * * The graphics system must be initialized before this call. - * If the provided surface is invalid or `nullptr`, this function returns - * silently. * * @param[in] surface Surface to destroy. * @@ -4819,8 +4807,6 @@ PAL_API PalResult PAL_CALL palCreateSwapchain( * @brief Destroy a swapchain. * * The graphics system must be initialized before this call. - * If the provided swapchain is invalid or `nullptr`, this function returns - * silently. * * @param[in] swapchain Swapchain to destroy. * @@ -4963,8 +4949,6 @@ PAL_API PalResult PAL_CALL palCreateShader( * @brief Destroy a shader. * * The graphics system must be initialized before this call. - * If the provided shader is invalid or `nullptr`, this function returns - * silently. * * @param[in] shader Shader to destroy. * @@ -5003,8 +4987,6 @@ PAL_API PalResult PAL_CALL palCreateFence( * @brief Destroy a fence. * * The graphics system must be initialized before this call. - * If the provided fence is invalid or `nullptr`, this function returns - * silently. * * @param[in] fence Fence to destroy. * @@ -5103,8 +5085,6 @@ PAL_API PalResult PAL_CALL palCreateSemaphore( * @brief Destroy a semaphore. * * The graphics system must be initialized before this call. - * If the provided semaphore is invalid or `nullptr`, this function returns - * silently. * * @param[in] semaphore Semaphore to destroy. * @@ -5212,9 +5192,6 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( * @brief Destroy a command pool. * * The graphics system must be initialized before this call. - * If the provided command pool is invalid or `nullptr`, this function returns - * silently. - * * Destroying a command pool frees all command buffers automatically. * * @param[in] pool Command pool to destroy. @@ -5271,8 +5248,6 @@ PAL_API PalResult PAL_CALL palAllocateCommandBuffer( * @brief Free an allocated command buffer. * * The graphics system must be initialized before this call. - * If the provided command buffer is invalid or `nullptr`, this function returns - * silently. * * @param[in] cmdBuffer Command buffer to free. * @@ -6319,8 +6294,6 @@ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( * @brief Destroy an acceleration structure. * * The graphics system must be initialized before this call. - * If the provided acceleration structure is invalid or `nullptr`, this function returns - * silently. * * @param[in] as Acceleration structure to destroy. * @@ -6391,8 +6364,6 @@ PAL_API PalResult PAL_CALL palCreateBuffer( * @brief Destroy a buffer. * * The graphics system must be initialized before this call. - * If the provided buffer is invalid or `nullptr`, this function returns - * silently. * * @param[in] buffer buffer to destroy. * @@ -6632,8 +6603,6 @@ PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( * @brief Destroy a descriptor set layout. * * The graphics system must be initialized before this call. - * If the provided descriptor set layout is invalid or `nullptr`, this function returns - * silently. * * @param[in] layout Descriptor set layout to destroy. * @@ -6672,8 +6641,6 @@ PAL_API PalResult PAL_CALL palCreateDescriptorPool( * @brief Destroy a descriptor pool. * * The graphics system must be initialized before this call. - * If the provided descriptor pool is invalid or `nullptr`, this function returns - * silently. * * @param[in] pool Descriptor pool to destroy. * @@ -6781,8 +6748,6 @@ PAL_API PalResult PAL_CALL palCreatePipelineLayout( * @brief Destroy a pipeline layout. * * The graphics system must be initialized before this call. - * If the provided pipeline layout is invalid or `nullptr`, this function returns - * silently. * * @param[in] layout Pipeline layout to destroy. * @@ -6873,9 +6838,7 @@ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( * @brief Destroy a pipeline. * * The graphics system must be initialized before this call. - * If the provided pipeline is invalid or `nullptr`, this function returns - * silently. - * + * * @param[in] pipeline Pipeline to destroy. * * Thread safety: Thread safe if the device used to create the pipeline is @@ -6923,8 +6886,6 @@ PAL_API PalResult PAL_CALL palCreateShaderBindingTable( * @brief Destroy a shader binding table. * * The graphics system must be initialized before this call. - * If the provided shader binding table is invalid or `nullptr`, this function returns - * silently. * * @param[in] sbt Shader binding table to destroy. * diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index d79ad264..64e07053 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -355,9 +355,7 @@ PAL_API PalResult PAL_CALL palCreateGLContext( * @brief Destroy the provided opengl context. * * The opengl system must be initialized before this call. - * - * If the provided context is invalid or `nullptr`, this function returns - * silently. The context must not be current in any thread before this call. + * The context must not be current in any thread before this call. * * @param[in] context Pointer to the context to destroy. * diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index bb31840e..55b4d3f2 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -669,7 +669,7 @@ PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures(); * if monitors are added or removed. * * @param[in, out] count Capacity of the PalMonitor array. - * @param[out] monitors User allocated array of PalMonitor. + * @param[out] outMonitors User allocated array of PalMonitor. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -883,8 +883,7 @@ PAL_API PalResult PAL_CALL palCreateWindow( * @brief Destroy the provided window. * * The video system must be initialized before this call. - * If the provided window is invalid or `nullptr`, this function returns - * silently. This only destroys windows created by PAL. + * This only destroys windows created by PAL. * * @param[in] window Pointer to the window to destroy. * @@ -1403,9 +1402,6 @@ PAL_API PalResult PAL_CALL palCreateIcon( * * The video system must be initialized before this call. * - * If the provided icon is invalid or `nullptr`, this function returns - * silently. - * * @param[in] icon Pointer to the icon to destroy. * * Thread safety: Must be called from the main thread. @@ -1480,9 +1476,6 @@ PAL_API PalResult PAL_CALL palCreateCursorFrom( * * The video system must be initialized before this call. * - * If the provided icon is invalid or `nullptr`, this function returns - * silently. - * * @param[in] cursor Pointer to the cursor to destroy. * * Thread safety: Must be called from the main thread. From 58e42693cd2aeda86d32175cae6a4a3c78421c51 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 10 Jul 2026 15:58:48 +0000 Subject: [PATCH 330/372] fix core, event, opengl, system and thread modules --- src/event/pal_event.c | 5 +--- src/opengl/egl/pal_context_egl.c | 24 ++++----------- src/opengl/egl/pal_egl.c | 17 ++--------- src/opengl/pal_opengl.c | 8 ++--- src/opengl/pal_opengl_backends.h | 12 ++++---- src/opengl/wgl/pal_wgl.c | 13 ++------- src/system/win32/pal_platform_win32.c | 26 ++++++++--------- src/thread/posix/pal_condvar_posix.c | 22 +++----------- src/thread/posix/pal_mutex_posix.c | 14 +++------ src/thread/posix/pal_thread_posix.c | 28 +----------------- src/thread/win32/pal_condvar_win32.c | 20 ++----------- src/thread/win32/pal_mutex_win32.c | 14 +++------ src/thread/win32/pal_thread_win32.c | 42 +++------------------------ src/video/pal_video_backends.h | 10 +++---- 14 files changed, 59 insertions(+), 196 deletions(-) diff --git a/src/event/pal_event.c b/src/event/pal_event.c index 9d5178f5..2f0c2c33 100644 --- a/src/event/pal_event.c +++ b/src/event/pal_event.c @@ -87,12 +87,9 @@ void PAL_CALL palPushEvent( PalEventDriver* eventDriver, PalEvent* event) { - // get the event mode PalDispatchMode mode = eventDriver->modes[event->type]; if (mode == PAL_DISPATCH_MODE_CALLBACK) { - if (eventDriver->callback) { - eventDriver->callback(eventDriver->userData, event); - } + eventDriver->callback(eventDriver->userData, event); return; // we have dispatched the event } diff --git a/src/opengl/egl/pal_context_egl.c b/src/opengl/egl/pal_context_egl.c index 242d3198..f59c5b61 100644 --- a/src/opengl/egl/pal_context_egl.c +++ b/src/opengl/egl/pal_context_egl.c @@ -279,26 +279,18 @@ PalResult eglCreateGLContext( void eglDestroyGLContext(PalGLContext* context) { - if (context) { - ContextData* data = findContextData(context); - if (data) { - // make it not current if it was current - s_Egl.makeCurrent(s_Egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - s_Egl.destroyContext(s_Egl.display, (EGLContext)context); - s_Egl.destroySurface(s_Egl.display, data->surface); - data->used = PAL_FALSE; - } - } + ContextData* data = findContextData(context); + // make it not current if it was current + s_Egl.makeCurrent(s_Egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + s_Egl.destroyContext(s_Egl.display, (EGLContext)context); + s_Egl.destroySurface(s_Egl.display, data->surface); + data->used = PAL_FALSE; } PalResult eglMakeContextCurrent( PalGLWindow* glWindow, PalGLContext* context) { - if ((!glWindow && context) || (glWindow && !context)) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - if (context && glWindow) { ContextData* data = findContextData(context); if (!data) { @@ -331,10 +323,6 @@ PalResult eglSwapBuffers( PalGLWindow* glWindow, PalGLContext* context) { - if (!context || !glWindow) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - ContextData* data = findContextData(context); if (!data) { return PAL_RESULT_CODE_INVALID_HANDLE; diff --git a/src/opengl/egl/pal_egl.c b/src/opengl/egl/pal_egl.c index b3eed2c7..6b8213fc 100644 --- a/src/opengl/egl/pal_egl.c +++ b/src/opengl/egl/pal_egl.c @@ -309,13 +309,9 @@ const PalGLInfo* PAL_CALL eglGetGLInfo() } PalResult PAL_CALL eglEnumerateGLFBConfigs( - int32_t* count, + uint32_t* count, PalGLFBConfig* configs) { - if (!count || count == 0 && configs) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - int32_t configCount = 0; int32_t maxConfigCount = 0; if (configs) { @@ -429,22 +425,13 @@ void* PAL_CALL eglGetGLProcAddress(const char* name) return s_Egl.getProcAddress(name); } -PalResult PAL_CALL eglSetSwapInterval(int32_t interval) +void PAL_CALL eglSetSwapInterval(int32_t interval) { - if (!s_Egl.swapInterval) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - s_Egl.swapInterval(s_Egl.display, interval); - return PAL_RESULT_SUCCESS; } const PalBool* PAL_CALL eglGetSupportedGLAPIs(void* instance) { - if (!instance) { - return nullptr; - } - void* handle = dlopen("libEGL.so", RTLD_LAZY); if (!handle) { return nullptr; diff --git a/src/opengl/pal_opengl.c b/src/opengl/pal_opengl.c index cf502f64..90d607e3 100644 --- a/src/opengl/pal_opengl.c +++ b/src/opengl/pal_opengl.c @@ -83,7 +83,7 @@ const PalGLInfo* PAL_CALL palGetGLInfo() } PalResult PAL_CALL palEnumerateGLFBConfigs( - int32_t* count, + uint32_t* count, PalGLFBConfig* configs) { if (!count) { @@ -95,7 +95,7 @@ PalResult PAL_CALL palEnumerateGLFBConfigs( const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( PalGLFBConfig* configs, - int32_t count, + uint32_t count, const PalGLFBConfig* desired) { int32_t score = 0; @@ -176,9 +176,9 @@ PalResult PAL_CALL palSwapBuffers( return s_Backend->swapBuffers(glWindow, context); } -PalResult PAL_CALL palSetSwapInterval(int32_t interval) +void PAL_CALL palSetSwapInterval(int32_t interval) { - return s_Backend->setSwapInterval(interval); + s_Backend->setSwapInterval(interval); } const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance) diff --git a/src/opengl/pal_opengl_backends.h b/src/opengl/pal_opengl_backends.h index a77e0068..7374d97d 100644 --- a/src/opengl/pal_opengl_backends.h +++ b/src/opengl/pal_opengl_backends.h @@ -15,13 +15,13 @@ typedef struct { void (*shutdownGL)(); const PalGLInfo* (*getGLInfo)(); - PalResult (*enumerateGLFBConfigs)(int32_t*, PalGLFBConfig*); + PalResult (*enumerateGLFBConfigs)(uint32_t*, PalGLFBConfig*); PalResult (*createGLContext)(const PalGLContextCreateInfo*, PalGLContext**); void (*destroyGLContext)(PalGLContext* context); PalResult (*makeContextCurrent)(PalGLWindow*, PalGLContext*); void* (*getGLProcAddress)(const char*); PalResult (*swapBuffers)(PalGLWindow*, PalGLContext*); - PalResult (*setSwapInterval)(int32_t); + void (*setSwapInterval)(int32_t); const PalBool* (*GetSupportedGLAPIs)(void*); } OpenglBackend; @@ -33,13 +33,13 @@ typedef struct { PalResult wglInitGL(PalGLAPI, void*, const PalAllocator*); void wglShutdownGL(); const PalGLInfo* wglGetGLInfo(); -PalResult wglEnumerateGLFBConfigs(int32_t*, PalGLFBConfig*); +PalResult wglEnumerateGLFBConfigs(uint32_t*, PalGLFBConfig*); PalResult wglCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); void wglDestroyGLContext(PalGLContext*); PalResult wglMakeContextCurrent(PalGLWindow*, PalGLContext*); void* wglGetGLProcAddress(const char*); PalResult wglSwapBuffers(PalGLWindow*, PalGLContext*); -PalResult wglSetSwapInterval(int32_t); +void wglSetSwapInterval(int32_t); const PalBool* wglGetSupportedGLAPIs(void*); static OpenglBackend s_WglBackend = { @@ -64,13 +64,13 @@ static OpenglBackend s_WglBackend = { PalResult eglInitGL(PalGLAPI, void*, const PalAllocator*); void eglShutdownGL(); const PalGLInfo* eglGetGLInfo(); -PalResult eglEnumerateGLFBConfigs(int32_t*, PalGLFBConfig*); +PalResult eglEnumerateGLFBConfigs(uint32_t*, PalGLFBConfig*); PalResult eglCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); void eglDestroyGLContext(PalGLContext*); PalResult eglMakeContextCurrent(PalGLWindow*, PalGLContext*); void* eglGetGLProcAddress(const char*); PalResult eglSwapBuffers(PalGLWindow*, PalGLContext*); -PalResult eglSetSwapInterval(int32_t); +void eglSetSwapInterval(int32_t); const PalBool* eglGetSupportedGLAPIs(void*); static OpenglBackend s_EglBackend = { diff --git a/src/opengl/wgl/pal_wgl.c b/src/opengl/wgl/pal_wgl.c index e479ac8d..cbdb2fc4 100644 --- a/src/opengl/wgl/pal_wgl.c +++ b/src/opengl/wgl/pal_wgl.c @@ -298,7 +298,7 @@ const PalGLInfo* wglGetGLInfo() } PalResult wglEnumerateGLFBConfigs( - int32_t* count, + uint32_t* count, PalGLFBConfig* configs) { int32_t configCount = 0; @@ -452,22 +452,13 @@ void* wglGetGLProcAddress(const char* name) return proc; } -PalResult wglSetSwapInterval(int32_t interval) +void wglSetSwapInterval(int32_t interval) { - if (!s_Wgl.swapIntervalEXT) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - s_Wgl.swapIntervalEXT(interval); - return PAL_RESULT_SUCCESS; } const PalBool* wglGetSupportedGLAPIs(void* instance) { - if (!instance) { - return nullptr; - } - s_SupportedAPIs[PAL_GL_API_OPENGL] = PAL_TRUE; s_SupportedAPIs[PAL_GL_API_OPENGL_ES] = PAL_FALSE; return s_SupportedAPIs; diff --git a/src/system/win32/pal_platform_win32.c b/src/system/win32/pal_platform_win32.c index 9cbad3bb..7c078d18 100644 --- a/src/system/win32/pal_platform_win32.c +++ b/src/system/win32/pal_platform_win32.c @@ -75,6 +75,19 @@ void PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) info->apiType = PAL_PLATFORM_API_TYPE_WIN32; info->type = PAL_PLATFORM_TYPE_WINDOWS; + // get total disk memory (size) in GB + ULARGE_INTEGER free, total, available; + if (GetDiskFreeSpaceExW(L"C:\\", &available, &total, &free)) { + info->totalMemory = (uint32_t)(total.QuadPart / (1024 * 1024 * 1024)); + } + + // get ram (size) in MB + MEMORYSTATUSEX status = {0}; + status.dwLength = sizeof(MEMORYSTATUSEX); + if (GlobalMemoryStatusEx(&status)) { + info->totalRAM = (uint32_t)(status.ullTotalPhys / (1024 * 1024)); + } + // get windows build, version and combine them if (!getVersionWin32(&info->version)) { return; @@ -117,19 +130,6 @@ void PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) if (build) { strcat(info->name, build); } - - // get total disk memory (size) in GB - ULARGE_INTEGER free, total, available; - if (GetDiskFreeSpaceExW(L"C:\\", &available, &total, &free)) { - info->totalMemory = (uint32_t)(total.QuadPart / (1024 * 1024 * 1024)); - } - - // get ram (size) in MB - MEMORYSTATUSEX status = {0}; - status.dwLength = sizeof(MEMORYSTATUSEX); - if (GlobalMemoryStatusEx(&status)) { - info->totalRAM = (uint32_t)(status.ullTotalPhys / (1024 * 1024)); - } } #endif // _WIN32 \ No newline at end of file diff --git a/src/thread/posix/pal_condvar_posix.c b/src/thread/posix/pal_condvar_posix.c index 41de3547..0732d198 100644 --- a/src/thread/posix/pal_condvar_posix.c +++ b/src/thread/posix/pal_condvar_posix.c @@ -37,20 +37,14 @@ PalResult PAL_CALL palCreateCondVar( void PAL_CALL palDestroyCondVar(PalCondVar* condVar) { - if (condVar) { - pthread_cond_destroy(&condVar->handle); - palFree(condVar->allocator, condVar); - } + pthread_cond_destroy(&condVar->handle); + palFree(condVar->allocator, condVar); } PalResult PAL_CALL palWaitCondVar( PalCondVar* condVar, PalMutex* mutex) { - if (!condVar || !mutex) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - int ret = pthread_cond_wait(&condVar->handle, &mutex->handle); if (ret == 0) { return PAL_RESULT_SUCCESS; @@ -68,10 +62,6 @@ PalResult PAL_CALL palWaitCondVarTimeout( PalMutex* mutex, uint64_t milliseconds) { - if (!condVar || !mutex) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += milliseconds / 1000; @@ -91,16 +81,12 @@ PalResult PAL_CALL palWaitCondVarTimeout( void PAL_CALL palSignalCondVar(PalCondVar* condVar) { - if (condVar) { - pthread_cond_signal(&condVar->handle); - } + pthread_cond_signal(&condVar->handle); } void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) { - if (condVar) { - pthread_cond_broadcast(&condVar->handle); - } + pthread_cond_broadcast(&condVar->handle); } #endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/thread/posix/pal_mutex_posix.c b/src/thread/posix/pal_mutex_posix.c index af51aebc..37001d29 100644 --- a/src/thread/posix/pal_mutex_posix.c +++ b/src/thread/posix/pal_mutex_posix.c @@ -37,24 +37,18 @@ PalResult PAL_CALL palCreateMutex( void PAL_CALL palDestroyMutex(PalMutex* mutex) { - if (mutex) { - pthread_mutex_destroy(&mutex->handle); - palFree(mutex->allocator, mutex); - } + pthread_mutex_destroy(&mutex->handle); + palFree(mutex->allocator, mutex); } void PAL_CALL palLockMutex(PalMutex* mutex) { - if (mutex) { - pthread_mutex_lock(&mutex->handle); - } + pthread_mutex_lock(&mutex->handle); } void PAL_CALL palUnlockMutex(PalMutex* mutex) { - if (mutex) { - pthread_mutex_unlock(&mutex->handle); - } + pthread_mutex_unlock(&mutex->handle); } #endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/thread/posix/pal_thread_posix.c b/src/thread/posix/pal_thread_posix.c index 601183ee..8418b49c 100644 --- a/src/thread/posix/pal_thread_posix.c +++ b/src/thread/posix/pal_thread_posix.c @@ -58,10 +58,6 @@ PalResult PAL_CALL palJoinThread( PalThread* thread, void** retval) { - if (!thread) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - int ret = 0; pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); if (retval) { @@ -80,9 +76,7 @@ PalResult PAL_CALL palJoinThread( void PAL_CALL palDetachThread(PalThread* thread) { - if (thread) { - pthread_detach(FROM_PAL_HANDLE(pthread_t, thread)); - } + pthread_detach(FROM_PAL_HANDLE(pthread_t, thread)); } void PAL_CALL palSleep(uint64_t milliseconds) @@ -116,10 +110,6 @@ PalThreadFeatures PAL_CALL palGetThreadFeatures() PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread) { - if (!thread) { - return 0; - } - int policy; struct sched_param param; pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); @@ -143,10 +133,6 @@ PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread) uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) { - if (!thread) { - return 0; - } - #ifdef __linux__ cpu_set_t cpuset; CPU_ZERO(&cpuset); @@ -186,10 +172,6 @@ PalResult PAL_CALL palSetThreadPriority( PalThread* thread, PalThreadPriority priority) { - if (!thread) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - switch (priority) { case PAL_THREAD_PRIORITY_LOW: { setpriority(PRIO_PROCESS, 0, 10); @@ -222,10 +204,6 @@ PalResult PAL_CALL palSetThreadAffinity( PalThread* thread, uint64_t mask) { - if (!thread) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - #ifdef __linux__ cpu_set_t cpuset; CPU_ZERO(&cpuset); @@ -253,10 +231,6 @@ PalResult PAL_CALL palSetThreadName( PalThread* thread, const char* name) { - if (!thread || !name) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - #ifdef __linux__ pthread_t _thread = FROM_PAL_HANDLE(pthread_t, thread); int ret = pthread_setname_np(_thread, name); diff --git a/src/thread/win32/pal_condvar_win32.c b/src/thread/win32/pal_condvar_win32.c index 87258492..3b517842 100644 --- a/src/thread/win32/pal_condvar_win32.c +++ b/src/thread/win32/pal_condvar_win32.c @@ -35,19 +35,13 @@ PalResult PAL_CALL palCreateCondVar( void PAL_CALL palDestroyCondVar(PalCondVar* condVar) { - if (condVar) { - palFree(condVar->allocator, condVar); - } + palFree(condVar->allocator, condVar); } PalResult PAL_CALL palWaitCondVar( PalCondVar* condVar, PalMutex* mutex) { - if (!condVar || !mutex) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - BOOL ret = SleepConditionVariableCS(&condVar->cv, &mutex->sc, INFINITE); if (!ret) { DWORD error = GetLastError(); @@ -72,10 +66,6 @@ PalResult PAL_CALL palWaitCondVarTimeout( PalMutex* mutex, uint64_t milliseconds) { - if (!condVar || !mutex) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - BOOL ret = SleepConditionVariableCS(&condVar->cv, &mutex->sc, (DWORD)milliseconds); if (!ret) { DWORD error = GetLastError(); @@ -97,16 +87,12 @@ PalResult PAL_CALL palWaitCondVarTimeout( void PAL_CALL palSignalCondVar(PalCondVar* condVar) { - if (condVar) { - WakeConditionVariable(&condVar->cv); - } + WakeConditionVariable(&condVar->cv); } void PAL_CALL palBroadcastCondVar(PalCondVar* condVar) { - if (condVar) { - WakeAllConditionVariable(&condVar->cv); - } + WakeAllConditionVariable(&condVar->cv); } #endif // _WIN32 \ No newline at end of file diff --git a/src/thread/win32/pal_mutex_win32.c b/src/thread/win32/pal_mutex_win32.c index 61050a77..7a2f2c74 100644 --- a/src/thread/win32/pal_mutex_win32.c +++ b/src/thread/win32/pal_mutex_win32.c @@ -38,24 +38,18 @@ PalResult PAL_CALL palCreateMutex( void PAL_CALL palDestroyMutex(PalMutex* mutex) { - if (mutex) { - DeleteCriticalSection(&mutex->sc); - palFree(mutex->allocator, mutex); - } + DeleteCriticalSection(&mutex->sc); + palFree(mutex->allocator, mutex); } void PAL_CALL palLockMutex(PalMutex* mutex) { - if (mutex) { - EnterCriticalSection(&mutex->sc); - } + EnterCriticalSection(&mutex->sc); } void PAL_CALL palUnlockMutex(PalMutex* mutex) { - if (mutex) { - LeaveCriticalSection(&mutex->sc); - } + LeaveCriticalSection(&mutex->sc); } #endif // _WIN32 \ No newline at end of file diff --git a/src/thread/win32/pal_thread_win32.c b/src/thread/win32/pal_thread_win32.c index ac226a2f..e9d1317b 100644 --- a/src/thread/win32/pal_thread_win32.c +++ b/src/thread/win32/pal_thread_win32.c @@ -92,10 +92,6 @@ PalResult PAL_CALL palJoinThread( PalThread* thread, void** retval) { - if (!thread) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - DWORD wait = WaitForSingleObject((HANDLE)thread, INFINITE); if (wait == WAIT_OBJECT_0) { if (retval) { @@ -118,9 +114,7 @@ PalResult PAL_CALL palJoinThread( void PAL_CALL palDetachThread(PalThread* thread) { - if (thread) { - CloseHandle((HANDLE)thread); - } + CloseHandle((HANDLE)thread); } void PAL_CALL palSleep(uint64_t milliseconds) @@ -159,10 +153,6 @@ PalThreadFeatures PAL_CALL palGetThreadFeatures() PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread) { - if (!thread) { - return 0; - } - int priority = GetThreadPriority((HANDLE)thread); switch (priority) { case THREAD_PRIORITY_LOWEST: @@ -183,10 +173,6 @@ PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread) uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) { - if (!thread) { - return 0; - } - DWORD_PTR mask = SetThreadAffinityMask((HANDLE)thread, ~0ull); if (mask == 0) { return 0; @@ -226,10 +212,6 @@ PalResult PAL_CALL palSetThreadPriority( PalThread* thread, PalThreadPriority priority) { - if (!thread) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - int _priority = 0; switch (priority) { case PAL_THREAD_PRIORITY_LOW: @@ -274,10 +256,6 @@ PalResult PAL_CALL palSetThreadAffinity( PalThread* thread, uint64_t mask) { - if (!thread) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - if (!SetThreadAffinityMask((HANDLE)thread, mask)) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_PARAMETER) { @@ -301,25 +279,13 @@ PalResult PAL_CALL palSetThreadName( PalThread* thread, const char* name) { - if (!thread || !name) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - HINSTANCE kernel32 = GetModuleHandleW(L"kernel32.dll"); - SetThreadDescriptionFn setThreadDescription = nullptr; - if (kernel32) { - setThreadDescription = - (SetThreadDescriptionFn)GetProcAddress(kernel32, "SetThreadDescription"); - } - - if (!setThreadDescription) { - // not supported - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } + SetThreadDescriptionFn setThreadDesc = nullptr; + setThreadDesc = (SetThreadDescriptionFn)GetProcAddress(kernel32, "SetThreadDescription"); wchar_t buffer[128] = {0}; MultiByteToWideChar(CP_UTF8, 0, name, -1, buffer, 128); - HRESULT hr = setThreadDescription((HANDLE)thread, buffer); + HRESULT hr = setThreadDesc((HANDLE)thread, buffer); if (SUCCEEDED(hr)) { return PAL_RESULT_SUCCESS; diff --git a/src/video/pal_video_backends.h b/src/video/pal_video_backends.h index 9ecc44b7..1cf11f34 100644 --- a/src/video/pal_video_backends.h +++ b/src/video/pal_video_backends.h @@ -14,11 +14,11 @@ typedef struct { void (*shutdownVideo)(); void (*updateVideo)(); PalVideoFeatures (*getVideoFeatures)(); - PalResult (*enumerateMonitors)(int32_t*, PalMonitor**); - PalResult (*getPrimaryMonitor)(PalMonitor**); - PalResult (*getMonitorInfo)(PalMonitor*, PalMonitorInfo*); - PalResult (*enumerateMonitorModes)(PalMonitor*, int32_t*, PalMonitorMode*); - PalResult (*getCurrentMonitorMode)(PalMonitor*, PalMonitorMode*); + PalResult (*enumerateMonitors)(uint32_t*, PalMonitor**); + void (*getPrimaryMonitor)(PalMonitor**); + void (*getMonitorInfo)(PalMonitor*, PalMonitorInfo*); + void (*enumerateMonitorModes)(PalMonitor*, uint32_t*, PalMonitorMode*); + void (*getCurrentMonitorMode)(PalMonitor*, PalMonitorMode*); PalResult (*setMonitorMode)(PalMonitor*, PalMonitorMode*); PalResult (*validateMonitorMode)(PalMonitor*, PalMonitorMode*); PalResult (*setMonitorOrientation)(PalMonitor*, PalOrientation); From 2e693b5da0c6adb3fb13741ec2b5bd4de8aa96fa Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 10 Jul 2026 22:35:22 +0000 Subject: [PATCH 331/372] fix wayland and x11 backends --- include/pal/pal_opengl.h | 2 +- src/graphics/d3d12/pal_adapter_d3d12.c | 4 +- src/graphics/vulkan/pal_adapter_vulkan.c | 4 +- src/video/pal_video_backends.h | 255 ++++++++++------------- src/video/wayland/pal_cursor_wayland.c | 40 +--- src/video/wayland/pal_icon_wayland.c | 7 - src/video/wayland/pal_monitor_wayland.c | 29 +-- src/video/wayland/pal_window_wayland.c | 165 +-------------- src/video/win32/pal_monitor_win32.c | 2 +- src/video/x11/pal_cursor_x11.c | 33 +-- src/video/x11/pal_icon_x11.c | 6 +- src/video/x11/pal_monitor_x11.c | 37 +--- src/video/x11/pal_window_x11.c | 191 ++--------------- 13 files changed, 175 insertions(+), 600 deletions(-) diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 64e07053..8e6a0579 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -291,7 +291,7 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); * @sa palInitGL */ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( - int32_t* count, + uint32_t* count, PalGLFBConfig* configs); /** diff --git a/src/graphics/d3d12/pal_adapter_d3d12.c b/src/graphics/d3d12/pal_adapter_d3d12.c index cb1ce560..1d21b66d 100644 --- a/src/graphics/d3d12/pal_adapter_d3d12.c +++ b/src/graphics/d3d12/pal_adapter_d3d12.c @@ -47,7 +47,7 @@ static PalImageUsages ImageUsageFromD3D12(D3D12_FORMAT_SUPPORT1 flags) } PalResult PAL_CALL enumerateAdaptersD3D12( - int32_t* count, + uint32_t* count, PalAdapter** outAdapters) { uint32_t adapterCount = 0; @@ -467,7 +467,7 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( void PAL_CALL enumerateFormatsD3D12( PalAdapter* adapter, - int32_t* count, + uint32_t* count, PalFormatInfo* outFormats) { int32_t fmtCount = 0; diff --git a/src/graphics/vulkan/pal_adapter_vulkan.c b/src/graphics/vulkan/pal_adapter_vulkan.c index 8ddc8754..c5a5459a 100644 --- a/src/graphics/vulkan/pal_adapter_vulkan.c +++ b/src/graphics/vulkan/pal_adapter_vulkan.c @@ -62,7 +62,7 @@ static PalImageUsages ImageUsageFromVk(VkFormatFeatureFlags flags) } PalResult PAL_CALL enumerateAdaptersVk( - int32_t* count, + uint32_t* count, PalAdapter** outAdapters) { int deviceCount = 0; @@ -711,7 +711,7 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetVk( void PAL_CALL enumerateFormatsVk( PalAdapter* adapter, - int32_t* count, + uint32_t* count, PalFormatInfo* outFormats) { int32_t fmtCount = 0; diff --git a/src/video/pal_video_backends.h b/src/video/pal_video_backends.h index 1cf11f34..5fc71ddd 100644 --- a/src/video/pal_video_backends.h +++ b/src/video/pal_video_backends.h @@ -25,18 +25,18 @@ typedef struct { PalResult (*createWindow)(const PalWindowCreateInfo*, PalWindow**); void (*destroyWindow)(PalWindow*); - PalResult (*maximizeWindow)(PalWindow*); - PalResult (*minimizeWindow)(PalWindow*); - PalResult (*restoreWindow)(PalWindow*); - PalResult (*showWindow)(PalWindow*); - PalResult (*hideWindow)(PalWindow*); - PalResult (*flashWindow)(PalWindow*, const PalFlashInfo*); - PalResult (*getWindowStyle)(PalWindow*, PalWindowStyle*); - PalResult (*getWindowMonitor)(PalWindow*, PalMonitor**); - PalResult (*getWindowTitle)(PalWindow*, uint64_t, uint64_t*, char*); - PalResult (*getWindowPos)(PalWindow*, int32_t*, int32_t*); - PalResult (*getWindowSize)(PalWindow*, uint32_t*, uint32_t*); - PalResult (*getWindowState)(PalWindow*, PalWindowState*); + void (*maximizeWindow)(PalWindow*); + void (*minimizeWindow)(PalWindow*); + void (*restoreWindow)(PalWindow*); + void (*showWindow)(PalWindow*); + void (*hideWindow)(PalWindow*); + void (*flashWindow)(PalWindow*, const PalFlashInfo*); + void (*getWindowStyle)(PalWindow*, PalWindowStyle*); + void (*getWindowMonitor)(PalWindow*, PalMonitor**); + void (*getWindowTitle)(PalWindow*, uint64_t, uint64_t*, char*); + void (*getWindowPos)(PalWindow*, int32_t*, int32_t*); + void (*getWindowSize)(PalWindow*, uint32_t*, uint32_t*); + void (*getWindowState)(PalWindow*, PalWindowState*); const PalBool* (*getKeycodeState)(); const PalBool* (*getScancodeState)(); const PalBool* (*getMouseState)(); @@ -44,26 +44,26 @@ typedef struct { void (*getMouseWheelDelta)(float*, float*); PalBool (*isWindowVisible)(PalWindow*); PalWindow* (*getFocusWindow)(); - PalResult (*getWindowHandleInfo)(PalWindow*, PalWindowHandleInfo*); - PalResult (*setWindowOpacity)(PalWindow*, float); - PalResult (*setWindowStyle)(PalWindow*, PalWindowStyle); - PalResult (*setWindowTitle)(PalWindow*, const char*); - PalResult (*setWindowPos)(PalWindow*, int32_t, int32_t); - PalResult (*setWindowSize)(PalWindow*, uint32_t, uint32_t); - PalResult (*setFocusWindow)(PalWindow*); + void (*getWindowHandleInfo)(PalWindow*, PalWindowHandleInfo*); + void (*setWindowOpacity)(PalWindow*, float); + void (*setWindowStyle)(PalWindow*, PalWindowStyle); + void (*setWindowTitle)(PalWindow*, const char*); + void (*setWindowPos)(PalWindow*, int32_t, int32_t); + void (*setWindowSize)(PalWindow*, uint32_t, uint32_t); + void (*setFocusWindow)(PalWindow*); PalResult (*createIcon)(const PalIconCreateInfo*, PalIcon**); void (*destroyIcon)(PalIcon*); - PalResult (*setWindowIcon)(PalWindow*, PalIcon*); + void (*setWindowIcon)(PalWindow*, PalIcon*); PalResult (*createCursor)(const PalCursorCreateInfo*, PalCursor**); PalResult (*createCursorFrom)(PalCursorType, PalCursor**); void (*destroyCursor)(PalCursor*); void (*showCursor)(PalBool); - PalResult (*clipCursor)(PalWindow*, PalBool); - PalResult (*getCursorPos)(PalWindow*, int32_t*, int32_t*); - PalResult (*setCursorPos)(PalWindow*, int32_t, int32_t); - PalResult (*setWindowCursor)(PalWindow*, PalCursor*); + void (*clipCursor)(PalWindow*, PalBool); + void (*getCursorPos)(PalWindow*, int32_t*, int32_t*); + void (*setCursorPos)(PalWindow*, int32_t, int32_t); + void (*setWindowCursor)(PalWindow*, PalCursor*); PalResult (*attachWindow)(void*, PalWindow**); PalResult (*detachWindow)(PalWindow*, void**); void* (*getInstance)(); @@ -79,29 +79,29 @@ void win32ShutdownVideo(); void win32UpdateVideo(); PalVideoFeatures win32GetVideoFeatures(); -PalResult win32EnumerateMonitors(int32_t*, PalMonitor**); -PalResult win32GetPrimaryMonitor(PalMonitor**); -PalResult win32GetMonitorInfo(PalMonitor*, PalMonitorInfo*); -PalResult win32EnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); -PalResult win32GetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult win32EnumerateMonitors(uint32_t*, PalMonitor**); +void win32GetPrimaryMonitor(PalMonitor**); +void win32GetMonitorInfo(PalMonitor*, PalMonitorInfo*); +void win32EnumerateMonitorModes(PalMonitor*, uint32_t*, PalMonitorMode*); +void win32GetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); PalResult win32SetMonitorMode(PalMonitor*, PalMonitorMode*); PalResult win32ValidateMonitorMode(PalMonitor*, PalMonitorMode*); PalResult win32SetMonitorOrientation(PalMonitor*, PalOrientation); PalResult win32CreateWindow(const PalWindowCreateInfo*, PalWindow**); void win32DestroyWindow(PalWindow*); -PalResult win32MaximizeWindow(PalWindow*); -PalResult win32MinimizeWindow(PalWindow*); -PalResult win32RestoreWindow(PalWindow*); -PalResult win32ShowWindow(PalWindow*); -PalResult win32HideWindow(PalWindow*); -PalResult win32FlashWindow(PalWindow*, const PalFlashInfo*); -PalResult win32GetWindowStyle(PalWindow*, PalWindowStyle*); -PalResult win32GetWindowMonitor(PalWindow*, PalMonitor**); -PalResult win32GetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); -PalResult win32GetWindowPos(PalWindow*, int32_t*, int32_t*); -PalResult win32GetWindowSize(PalWindow*, uint32_t*, uint32_t*); -PalResult win32GetWindowState(PalWindow*, PalWindowState*); +void win32MaximizeWindow(PalWindow*); +void win32MinimizeWindow(PalWindow*); +void win32RestoreWindow(PalWindow*); +void win32ShowWindow(PalWindow*); +void win32HideWindow(PalWindow*); +void win32FlashWindow(PalWindow*, const PalFlashInfo*); +void win32GetWindowStyle(PalWindow*, PalWindowStyle*); +void win32GetWindowMonitor(PalWindow*, PalMonitor**); +void win32GetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); +void win32GetWindowPos(PalWindow*, int32_t*, int32_t*); +void win32GetWindowSize(PalWindow*, uint32_t*, uint32_t*); +void win32GetWindowState(PalWindow*, PalWindowState*); const PalBool* win32GetKeycodeState(); const PalBool* win32GetScancodeState(); const PalBool* win32GetMouseState(); @@ -109,26 +109,26 @@ void win32GetMouseDelta(float*, float*); void win32GetMouseWheelDelta(float*, float*); PalBool win32IsWindowVisible(PalWindow*); PalWindow* win32GetFocusWindow(); -PalResult win32GetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); -PalResult win32SetWindowOpacity(PalWindow*, float); -PalResult win32SetWindowStyle(PalWindow*, PalWindowStyle); -PalResult win32SetWindowTitle(PalWindow*, const char*); -PalResult win32SetWindowPos(PalWindow*, int32_t, int32_t); -PalResult win32SetWindowSize(PalWindow*, uint32_t, uint32_t); -PalResult win32SetFocusWindow(PalWindow*); +void win32GetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); +void win32SetWindowOpacity(PalWindow*, float); +void win32SetWindowStyle(PalWindow*, PalWindowStyle); +void win32SetWindowTitle(PalWindow*, const char*); +void win32SetWindowPos(PalWindow*, int32_t, int32_t); +void win32SetWindowSize(PalWindow*, uint32_t, uint32_t); +void win32SetFocusWindow(PalWindow*); PalResult win32CreateIcon(const PalIconCreateInfo*, PalIcon**); void win32DestroyIcon(PalIcon*); -PalResult win32SetWindowIcon(PalWindow*, PalIcon*); +void win32SetWindowIcon(PalWindow*, PalIcon*); PalResult win32CreateCursor(const PalCursorCreateInfo*, PalCursor**); PalResult win32CreateCursorFrom(PalCursorType, PalCursor**); void win32DestroyCursor(PalCursor*); void win32ShowCursor(PalBool); -PalResult win32ClipCursor(PalWindow*, PalBool); -PalResult win32GetCursorPos(PalWindow*, int32_t*, int32_t*); -PalResult win32SetCursorPos(PalWindow*, int32_t, int32_t); -PalResult win32SetWindowCursor(PalWindow*, PalCursor*); +void win32ClipCursor(PalWindow*, PalBool); +void win32GetCursorPos(PalWindow*, int32_t*, int32_t*); +void win32SetCursorPos(PalWindow*, int32_t, int32_t); +void win32SetWindowCursor(PalWindow*, PalCursor*); PalResult win32AttachWindow(void*, PalWindow**); PalResult win32DetachWindow(PalWindow*, void**); void* win32GetInstance(); @@ -203,29 +203,27 @@ void xShutdownVideo(); void xUpdateVideo(); PalVideoFeatures xGetVideoFeatures(); -PalResult xEnumerateMonitors(int32_t*, PalMonitor**); -PalResult xGetPrimaryMonitor(PalMonitor**); -PalResult xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); -PalResult xEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); -PalResult xGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult xEnumerateMonitors(uint32_t*, PalMonitor**); +void xGetPrimaryMonitor(PalMonitor**); +void xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); +void xEnumerateMonitorModes(PalMonitor*, uint32_t*, PalMonitorMode*); +void xGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); PalResult xSetMonitorMode(PalMonitor*, PalMonitorMode*); PalResult xValidateMonitorMode(PalMonitor*, PalMonitorMode*); PalResult xSetMonitorOrientation(PalMonitor*, PalOrientation); PalResult xCreateWindow(const PalWindowCreateInfo*, PalWindow**); void xDestroyWindow(PalWindow*); -PalResult xMaximizeWindow(PalWindow*); -PalResult xMinimizeWindow(PalWindow*); -PalResult xRestoreWindow(PalWindow*); -PalResult xShowWindow(PalWindow*); -PalResult xHideWindow(PalWindow*); -PalResult xFlashWindow(PalWindow*, const PalFlashInfo*); -PalResult xGetWindowStyle(PalWindow*, PalWindowStyle*); -PalResult xGetWindowMonitor(PalWindow*, PalMonitor**); -PalResult xGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); -PalResult xGetWindowPos(PalWindow*, int32_t*, int32_t*); -PalResult xGetWindowSize(PalWindow*, uint32_t*, uint32_t*); -PalResult xGetWindowState(PalWindow*, PalWindowState*); +void xMaximizeWindow(PalWindow*); +void xMinimizeWindow(PalWindow*); +void xRestoreWindow(PalWindow*); +void xShowWindow(PalWindow*); +void xHideWindow(PalWindow*); +void xFlashWindow(PalWindow*, const PalFlashInfo*); +void xGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); +void xGetWindowPos(PalWindow*, int32_t*, int32_t*); +void xGetWindowSize(PalWindow*, uint32_t*, uint32_t*); +void xGetWindowState(PalWindow*, PalWindowState*); const PalBool* xGetKeycodeState(); const PalBool* xGetScancodeState(); const PalBool* xGetMouseState(); @@ -233,26 +231,25 @@ void xGetMouseDelta(float*, float*); void xGetMouseWheelDelta(float*, float*); PalBool xIsWindowVisible(PalWindow*); PalWindow* xGetFocusWindow(); -PalResult xGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); -PalResult xSetWindowOpacity(PalWindow*, float); -PalResult xSetWindowStyle(PalWindow*, PalWindowStyle); -PalResult xSetWindowTitle(PalWindow*, const char*); -PalResult xSetWindowPos(PalWindow*, int32_t, int32_t); -PalResult xSetWindowSize(PalWindow*, uint32_t, uint32_t); -PalResult xSetFocusWindow(PalWindow*); +void xGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); +void xSetWindowOpacity(PalWindow*, float); +void xSetWindowTitle(PalWindow*, const char*); +void xSetWindowPos(PalWindow*, int32_t, int32_t); +void xSetWindowSize(PalWindow*, uint32_t, uint32_t); +void xSetFocusWindow(PalWindow*); PalResult xCreateIcon(const PalIconCreateInfo*, PalIcon**); void xDestroyIcon(PalIcon*); -PalResult xSetWindowIcon(PalWindow*, PalIcon*); +void xSetWindowIcon(PalWindow*, PalIcon*); PalResult xCreateCursor(const PalCursorCreateInfo*, PalCursor**); PalResult xCreateCursorFrom(PalCursorType, PalCursor**); void xDestroyCursor(PalCursor*); void xShowCursor(PalBool); -PalResult xClipCursor(PalWindow*, PalBool); -PalResult xGetCursorPos(PalWindow*, int32_t*, int32_t*); -PalResult xSetCursorPos(PalWindow*, int32_t, int32_t); -PalResult xSetWindowCursor(PalWindow*, PalCursor*); +void xClipCursor(PalWindow*, PalBool); +void xGetCursorPos(PalWindow*, int32_t*, int32_t*); +void xSetCursorPos(PalWindow*, int32_t, int32_t); +void xSetWindowCursor(PalWindow*, PalCursor*); PalResult xAttachWindow(void*, PalWindow**); PalResult xDetachWindow(PalWindow*, void**); void* xGetInstance(); @@ -278,8 +275,8 @@ static VideoBackend s_XBackend = { .showWindow = xShowWindow, .hideWindow = xHideWindow, .flashWindow = xFlashWindow, - .getWindowStyle = xGetWindowStyle, - .getWindowMonitor = xGetWindowMonitor, + .getWindowStyle = nullptr, + .getWindowMonitor = nullptr, .getWindowTitle = xGetWindowTitle, .getWindowPos = xGetWindowPos, .getWindowSize = xGetWindowSize, @@ -293,7 +290,7 @@ static VideoBackend s_XBackend = { .getFocusWindow = xGetFocusWindow, .getWindowHandleInfo = xGetWindowHandleInfo, .setWindowOpacity = xSetWindowOpacity, - .setWindowStyle = xSetWindowStyle, + .setWindowStyle = nullptr, .setWindowTitle = xSetWindowTitle, .setWindowPos = xSetWindowPos, .setWindowSize = xSetWindowSize, @@ -328,58 +325,36 @@ void wlUpdateVideo(); void wlUpdateVideo(); PalVideoFeatures wlGetVideoFeatures(); -PalResult wlEnumerateMonitors(int32_t*, PalMonitor**); -PalResult wlGetPrimaryMonitor(PalMonitor**); -PalResult wlGetMonitorInfo(PalMonitor*, PalMonitorInfo*); -PalResult wlEnumerateMonitorModes(PalMonitor*, int32_t*, PalMonitorMode*); -PalResult wlGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); +PalResult wlEnumerateMonitors(uint32_t*, PalMonitor**); +void wlGetMonitorInfo(PalMonitor*, PalMonitorInfo*); +void wlEnumerateMonitorModes(PalMonitor*, uint32_t*, PalMonitorMode*); +void wlGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); PalResult wlSetMonitorMode(PalMonitor*, PalMonitorMode*); PalResult wlValidateMonitorMode(PalMonitor*, PalMonitorMode*); PalResult wlSetMonitorOrientation(PalMonitor*, PalOrientation); PalResult wlCreateWindow(const PalWindowCreateInfo*, PalWindow**); void wlDestroyWindow(PalWindow*); -PalResult wlMaximizeWindow(PalWindow*); -PalResult wlMinimizeWindow(PalWindow*); -PalResult wlRestoreWindow(PalWindow*); -PalResult wlShowWindow(PalWindow*); -PalResult wlHideWindow(PalWindow*); -PalResult wlFlashWindow(PalWindow*, const PalFlashInfo*); -PalResult wlGetWindowStyle(PalWindow*, PalWindowStyle*); -PalResult wlGetWindowMonitor(PalWindow*, PalMonitor**); -PalResult wlGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); -PalResult wlGetWindowPos(PalWindow*, int32_t*, int32_t*); -PalResult wlGetWindowSize(PalWindow*, uint32_t*, uint32_t*); -PalResult wlGetWindowState(PalWindow*, PalWindowState*); +void wlMaximizeWindow(PalWindow*); +void wlMinimizeWindow(PalWindow*); +void wlRestoreWindow(PalWindow*); const PalBool* wlGetKeycodeState(); const PalBool* wlGetScancodeState(); const PalBool* wlGetMouseState(); void wlGetMouseDelta(float*, float*); void wlGetMouseWheelDelta(float*, float*); PalBool wlIsWindowVisible(PalWindow*); -PalWindow* wlGetFocusWindow(); -PalResult wlGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); -PalResult wlSetWindowOpacity(PalWindow*, float); -PalResult wlSetWindowStyle(PalWindow*, PalWindowStyle); -PalResult wlSetWindowTitle(PalWindow*, const char*); -PalResult wlSetWindowPos(PalWindow*, int32_t, int32_t); -PalResult wlSetWindowSize(PalWindow*, uint32_t, uint32_t); -PalResult wlSetFocusWindow(PalWindow*); +void wlGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); +void wlSetWindowTitle(PalWindow*, const char*); +void wlSetWindowSize(PalWindow*, uint32_t, uint32_t); PalResult wlCreateIcon(const PalIconCreateInfo*, PalIcon**); void wlDestroyIcon(PalIcon*); -PalResult wlSetWindowIcon(PalWindow*, PalIcon*); PalResult wlCreateCursor(const PalCursorCreateInfo*, PalCursor**); PalResult wlCreateCursorFrom(PalCursorType, PalCursor**); void wlDestroyCursor(PalCursor*); -void wlShowCursor(PalBool); -PalResult wlClipCursor(PalWindow*, PalBool); -PalResult wlGetCursorPos(PalWindow*, int32_t*, int32_t*); -PalResult wlSetCursorPos(PalWindow*, int32_t, int32_t); -PalResult wlSetWindowCursor(PalWindow*, PalCursor*); -PalResult wlAttachWindow(void*, PalWindow**); -PalResult wlDetachWindow(PalWindow*, void**); +void wlSetWindowCursor(PalWindow*, PalCursor*); void* wlGetInstance(); static VideoBackend s_wlBackend = { @@ -388,7 +363,7 @@ static VideoBackend s_wlBackend = { .getVideoFeatures = wlGetVideoFeatures, .enumerateMonitors = wlEnumerateMonitors, .getMonitorInfo = wlGetMonitorInfo, - .getPrimaryMonitor = wlGetPrimaryMonitor, + .getPrimaryMonitor = nullptr, .enumerateMonitorModes = wlEnumerateMonitorModes, .getCurrentMonitorMode = wlGetCurrentMonitorMode, .setMonitorMode = wlSetMonitorMode, @@ -400,45 +375,45 @@ static VideoBackend s_wlBackend = { .maximizeWindow = wlMaximizeWindow, .minimizeWindow = wlMinimizeWindow, .restoreWindow = wlRestoreWindow, - .showWindow = wlShowWindow, - .hideWindow = wlHideWindow, - .flashWindow = wlFlashWindow, - .getWindowStyle = wlGetWindowStyle, - .getWindowMonitor = wlGetWindowMonitor, - .getWindowTitle = wlGetWindowTitle, - .getWindowPos = wlGetWindowPos, - .getWindowSize = wlGetWindowSize, - .getWindowState = wlGetWindowState, + .showWindow = nullptr, + .hideWindow = nullptr, + .flashWindow = nullptr, + .getWindowStyle = nullptr, + .getWindowMonitor = nullptr, + .getWindowTitle = nullptr, + .getWindowPos = nullptr, + .getWindowSize = nullptr, + .getWindowState = nullptr, .getKeycodeState = wlGetKeycodeState, .getScancodeState = wlGetScancodeState, .getMouseState = wlGetMouseState, .getMouseDelta = wlGetMouseDelta, .getMouseWheelDelta = wlGetMouseWheelDelta, .isWindowVisible = wlIsWindowVisible, - .getFocusWindow = wlGetFocusWindow, + .getFocusWindow = nullptr, .getWindowHandleInfo = wlGetWindowHandleInfo, - .setWindowOpacity = wlSetWindowOpacity, - .setWindowStyle = wlSetWindowStyle, + .setWindowOpacity = nullptr, + .setWindowStyle = nullptr, .setWindowTitle = wlSetWindowTitle, - .setWindowPos = wlSetWindowPos, + .setWindowPos = nullptr, .setWindowSize = wlSetWindowSize, - .setFocusWindow = wlSetFocusWindow, + .setFocusWindow = nullptr, .createIcon = wlCreateIcon, .destroyIcon = wlDestroyIcon, - .setWindowIcon = wlSetWindowIcon, + .setWindowIcon = nullptr, .createCursor = wlCreateCursor, .createCursorFrom = wlCreateCursorFrom, .destroyCursor = wlDestroyCursor, - .showCursor = wlShowCursor, - .clipCursor = wlClipCursor, - .getCursorPos = wlGetCursorPos, - .setCursorPos = wlSetCursorPos, + .showCursor = nullptr, + .clipCursor = nullptr, + .getCursorPos = nullptr, + .setCursorPos = nullptr, .setWindowCursor = wlSetWindowCursor, - .attachWindow = wlAttachWindow, + .attachWindow = nullptr, .getInstance = wlGetInstance, - .detachWindow = wlDetachWindow}; + .detachWindow = nullptr}; // clang-format on diff --git a/src/video/wayland/pal_cursor_wayland.c b/src/video/wayland/pal_cursor_wayland.c index 0d6d4e49..fec80a89 100644 --- a/src/video/wayland/pal_cursor_wayland.c +++ b/src/video/wayland/pal_cursor_wayland.c @@ -106,50 +106,12 @@ void wlDestroyCursor(PalCursor* cursor) palFree(s_Wl.allocator, waylandCursor); } -void wlShowCursor(PalBool show) -{ - // not supported - return; -} - -PalResult wlClipCursor( - PalWindow* window, - PalBool clip) -{ - if (!(s_Wl.features & PAL_VIDEO_FEATURE_CLIP_CURSOR)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult wlGetCursorPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlSetCursorPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlSetWindowCursor( +void wlSetWindowCursor( PalWindow* window, PalCursor* cursor) { WindowData* data = wlFindWindowData(window); - if (!data) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - data->cursor = cursor; - return PAL_RESULT_SUCCESS; } #endif // PAL_HAS_WAYLAND_BACKEND \ No newline at end of file diff --git a/src/video/wayland/pal_icon_wayland.c b/src/video/wayland/pal_icon_wayland.c index d0ade19d..2f8eb1a3 100644 --- a/src/video/wayland/pal_icon_wayland.c +++ b/src/video/wayland/pal_icon_wayland.c @@ -20,11 +20,4 @@ void wlDestroyIcon(PalIcon* icon) return; } -PalResult wlSetWindowIcon( - PalWindow* window, - PalIcon* icon) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - #endif // PAL_HAS_WAYLAND_BACKEND \ No newline at end of file diff --git a/src/video/wayland/pal_monitor_wayland.c b/src/video/wayland/pal_monitor_wayland.c index 9975cd1d..0d043575 100644 --- a/src/video/wayland/pal_monitor_wayland.c +++ b/src/video/wayland/pal_monitor_wayland.c @@ -31,20 +31,11 @@ PalResult wlEnumerateMonitors( return PAL_RESULT_SUCCESS; } -PalResult wlGetPrimaryMonitor(PalMonitor** outMonitor) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetMonitorInfo( +void wlGetMonitorInfo( PalMonitor* monitor, PalMonitorInfo* info) { MonitorData* monitorData = wlFindMonitorData(monitor); - if (!monitorData) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - info->dpi = monitorData->dpi; info->x = monitorData->x; info->y = monitorData->y; @@ -55,20 +46,14 @@ PalResult wlGetMonitorInfo( info->primary = PAL_FALSE; // no way to query strcpy(info->name, monitorData->name); - - return PAL_RESULT_SUCCESS; } -PalResult wlEnumerateMonitorModes( +void wlEnumerateMonitorModes( PalMonitor* monitor, uint32_t* count, PalMonitorMode* modes) { MonitorData* monitorData = wlFindMonitorData(monitor); - if (!monitorData) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - if (modes && *count > 0) { PalMonitorMode* mode = &modes[0]; mode->bpp = monitorData->mode.bpp; @@ -80,26 +65,18 @@ PalResult wlEnumerateMonitorModes( if (!modes) { *count = 1; // wayland only gives the active mode } - - return PAL_RESULT_SUCCESS; } -PalResult wlGetCurrentMonitorMode( +void wlGetCurrentMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { MonitorData* monitorData = wlFindMonitorData(monitor); - if (!monitorData) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - // this is the same as the current mode mode->bpp = monitorData->mode.bpp; mode->width = monitorData->mode.width; mode->height = monitorData->mode.height; mode->refreshRate = monitorData->mode.refreshRate; - - return PAL_RESULT_SUCCESS; } PalResult wlSetMonitorMode( diff --git a/src/video/wayland/pal_window_wayland.c b/src/video/wayland/pal_window_wayland.c index 5c0fc6a0..a3101221 100644 --- a/src/video/wayland/pal_window_wayland.c +++ b/src/video/wayland/pal_window_wayland.c @@ -240,101 +240,23 @@ void wlDestroyWindow(PalWindow* window) data->used = PAL_FALSE; } -PalResult wlMinimizeWindow(PalWindow* window) +void wlMinimizeWindow(PalWindow* window) { WindowData* data = wlFindWindowData(window); - if (!data) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - xdgToplevelSetMinimized(data->xdgToplevel); - return PAL_RESULT_SUCCESS; } -PalResult wlMaximizeWindow(PalWindow* window) +void wlMaximizeWindow(PalWindow* window) { WindowData* data = wlFindWindowData(window); - if (!data) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - xdgToplevelSetMaximized(data->xdgToplevel); - return PAL_RESULT_SUCCESS; } -PalResult wlRestoreWindow(PalWindow* window) +void wlRestoreWindow(PalWindow* window) { WindowData* data = wlFindWindowData(window); - if (!data) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - // we can only restore from a maximized state xdgToplevelUnsetMaximized(data->xdgToplevel); - return PAL_RESULT_SUCCESS; -} - -PalResult wlShowWindow(PalWindow* window) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlHideWindow(PalWindow* window) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlFlashWindow( - PalWindow* window, - const PalFlashInfo* info) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowStyle( - PalWindow* window, - PalWindowStyle* outStyle) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowMonitor( - PalWindow* window, - PalMonitor** outMonitor) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowTitle( - PalWindow* window, - uint64_t bufferSize, - uint64_t* outSize, - char* outBuffer) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowPos( - PalWindow* window, - int32_t* x, - int32_t* y) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowSize( - PalWindow* window, - uint32_t* width, - uint32_t* height) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlGetWindowState( - PalWindow* window, - PalWindowState* outState) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } PalBool wlIsWindowVisible(PalWindow* window) @@ -342,101 +264,36 @@ PalBool wlIsWindowVisible(PalWindow* window) return PAL_FALSE; } -PalWindow* wlGetFocusWindow() -{ - // Wayland does not let client query focused window - return nullptr; -} - -PalResult wlGetWindowHandleInfo( +void wlGetWindowHandleInfo( PalWindow* window, PalWindowHandleInfo* info) { - if (!window || !info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - WindowData* data = wlFindWindowData(window); - if (data) { - info->nativeInstance = (void*)s_Wl.display; - info->nativeWindow = (void*)window; - info->nativeHandle1 = data->xdgSurface; - info->nativeHandle2 = data->xdgToplevel; - info->nativeHandle3 = data->eglWindow; - } - - return PAL_RESULT_SUCCESS; + info->nativeInstance = (void*)s_Wl.display; + info->nativeWindow = (void*)window; + info->nativeHandle1 = data->xdgSurface; + info->nativeHandle2 = data->xdgToplevel; + info->nativeHandle3 = data->eglWindow; } -PalResult wlSetWindowOpacity( - PalWindow* window, - float opacity) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlSetWindowStyle( - PalWindow* window, - PalWindowStyle style) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlSetWindowTitle( +void wlSetWindowTitle( PalWindow* window, const char* title) { WindowData* data = wlFindWindowData(window); - if (!data) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - xdgToplevelSetTitle(data->xdgToplevel, title); s_Wl.displayFlush(s_Wl.display); - return PAL_RESULT_SUCCESS; -} - -PalResult wlSetWindowPos( - PalWindow* window, - int32_t x, - int32_t y) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } -PalResult wlSetWindowSize( +void wlSetWindowSize( PalWindow* window, uint32_t width, uint32_t height) { WindowData* data = wlFindWindowData(window); - if (!data) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - xdgToplevelSetMinSize(data->xdgToplevel, width, height); xdgToplevelSetMaxSize(data->xdgToplevel, width, height); wlSurfaceCommit((struct wl_surface*)window); - return PAL_RESULT_SUCCESS; -} - -PalResult wlSetFocusWindow(PalWindow* window) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlAttachWindow( - void* windowHandle, - PalWindow** outWindow) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult wlDetachWindow( - PalWindow* window, - void** outWindowHandle) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } #endif // PAL_HAS_WAYLAND_BACKEND \ No newline at end of file diff --git a/src/video/win32/pal_monitor_win32.c b/src/video/win32/pal_monitor_win32.c index ceec18ff..8848f8df 100644 --- a/src/video/win32/pal_monitor_win32.c +++ b/src/video/win32/pal_monitor_win32.c @@ -139,7 +139,7 @@ static inline PalBool compareMonitorMode( static inline void addMonitorMode( PalMonitorMode* modes, const PalMonitorMode* mode, - int32_t* count) + uint32_t* count) { // check if we have a duplicate mode for (int32_t i = 0; i < *count; i++) { diff --git a/src/video/x11/pal_cursor_x11.c b/src/video/x11/pal_cursor_x11.c index 65a9aa40..ed580f87 100644 --- a/src/video/x11/pal_cursor_x11.c +++ b/src/video/x11/pal_cursor_x11.c @@ -90,16 +90,11 @@ void xShowCursor(PalBool show) return; } -PalResult xClipCursor( +void xClipCursor( PalWindow* window, PalBool clip) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - if (clip) { s_X11.grabPointer( s_X11.display, @@ -115,21 +110,14 @@ PalResult xClipCursor( } else { s_X11.ungrabPointer(s_X11.display, CurrentTime); } - - return PAL_RESULT_SUCCESS; } -PalResult xGetCursorPos( +void xGetCursorPos( PalWindow* window, int32_t* x, int32_t* y) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - Window root, child; int rootX, rootY, winX, winY; unsigned int mask; @@ -141,36 +129,24 @@ PalResult xGetCursorPos( if (y) { *y = winY; } - - return PAL_RESULT_SUCCESS; } -PalResult xSetCursorPos( +void xSetCursorPos( PalWindow* window, int32_t x, int32_t y) { Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - s_X11.warpPointer(s_X11.display, None, xWin, 0, 0, 0, 0, x, y); s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; } -PalResult xSetWindowCursor( +void xSetWindowCursor( PalWindow* window, PalCursor* cursor) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - Window xCursor = FROM_PAL_HANDLE(Cursor, cursor); if (xCursor) { s_X11.defineCursor(s_X11.display, xWin, xCursor); @@ -180,7 +156,6 @@ PalResult xSetWindowCursor( } s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; } #endif // PAL_HAS_X11_BACKEND \ No newline at end of file diff --git a/src/video/x11/pal_icon_x11.c b/src/video/x11/pal_icon_x11.c index 1da531f4..b03069cb 100644 --- a/src/video/x11/pal_icon_x11.c +++ b/src/video/x11/pal_icon_x11.c @@ -50,16 +50,13 @@ void xDestroyIcon(PalIcon* icon) } } -PalResult xSetWindowIcon( +void xSetWindowIcon( PalWindow* window, PalIcon* icon) { WindowData* winData = nullptr; Window xWin = FROM_PAL_HANDLE(Window, window); s_X11.findContext(s_X11.display, xWin, s_X11.dataID, (XPointer*)&winData); - if (!winData) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } unsigned long* iconData = FROM_PAL_HANDLE(unsigned long*, icon); uint64_t totalPixels = 2 + iconData[0] * iconData[1]; @@ -74,7 +71,6 @@ PalResult xSetWindowIcon( (int)totalPixels); s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; } #endif // PAL_HAS_X11_BACKEND \ No newline at end of file diff --git a/src/video/x11/pal_monitor_x11.c b/src/video/x11/pal_monitor_x11.c index 7ec7bd9a..277b5502 100644 --- a/src/video/x11/pal_monitor_x11.c +++ b/src/video/x11/pal_monitor_x11.c @@ -36,17 +36,15 @@ PalResult xEnumerateMonitors( return PAL_RESULT_SUCCESS; } -PalResult xGetPrimaryMonitor(PalMonitor** outMonitor) +void xGetPrimaryMonitor(PalMonitor** outMonitor) { RROutput primary = s_X11.getOutputPrimary(s_X11.display, s_X11.root); if (primary) { *outMonitor = TO_PAL_HANDLE(PalMonitor, primary); - return PAL_RESULT_SUCCESS; } - return PAL_RESULT_CODE_PLATFORM_FAILURE; } -PalResult xGetMonitorInfo( +void xGetMonitorInfo( PalMonitor* monitor, PalMonitorInfo* info) { @@ -56,13 +54,13 @@ PalResult xGetMonitorInfo( if (!outputInfo) { // invalid monitor s_X11.freeScreenResources(resources); - return PAL_RESULT_CODE_INVALID_HANDLE; + return; } if (outputInfo->connection != RR_Connected) { // invalid monitor s_X11.freeScreenResources(resources); - return PAL_RESULT_CODE_INVALID_HANDLE; + return; } // check if its primary monitor @@ -139,11 +137,9 @@ PalResult xGetMonitorInfo( s_X11.freeCrtcInfo(crtc); s_X11.freeOutputInfo(outputInfo); s_X11.freeScreenResources(resources); - - return PAL_RESULT_SUCCESS; } -PalResult xEnumerateMonitorModes( +void xEnumerateMonitorModes( PalMonitor* monitor, uint32_t* count, PalMonitorMode* modes) @@ -158,13 +154,13 @@ PalResult xEnumerateMonitorModes( if (!outputInfo) { // invalid monitor s_X11.freeScreenResources(resources); - return PAL_RESULT_CODE_INVALID_HANDLE; + return; } if (outputInfo->connection != RR_Connected) { // invalid monitor s_X11.freeScreenResources(resources); - return PAL_RESULT_CODE_INVALID_HANDLE; + return; } // get supported display modes @@ -197,38 +193,29 @@ PalResult xEnumerateMonitorModes( s_X11.freeOutputInfo(outputInfo); s_X11.freeScreenResources(resources); - return PAL_RESULT_SUCCESS; } -PalResult xGetCurrentMonitorMode( +void xGetCurrentMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { XRRScreenResources* resources = s_X11.getScreenResources(s_X11.display, s_X11.root); - - // get the monitor info RROutput output = FROM_PAL_HANDLE(RROutput, monitor); - XRROutputInfo* outputInfo =s_X11.getOutputInfo(s_X11.display, resources, output); - + XRROutputInfo* outputInfo = s_X11.getOutputInfo(s_X11.display, resources, output); if (!outputInfo) { - // invalid monitor s_X11.freeScreenResources(resources); - return PAL_RESULT_CODE_INVALID_HANDLE; + return; } if (outputInfo->connection != RR_Connected) { - // invalid monitor s_X11.freeScreenResources(resources); - return PAL_RESULT_CODE_INVALID_HANDLE; + return; } - // get the current display mode XRRCrtcInfo* crtc = s_X11.getCrtcInfo(s_X11.display, resources, outputInfo->crtc); - // find the display mode XRRModeInfo* info = nullptr; for (int i = 0; i < resources->nmode; ++i) { if (resources->modes[i].id == crtc->mode) { - // found info = &resources->modes[i]; break; } @@ -247,8 +234,6 @@ PalResult xGetCurrentMonitorMode( s_X11.freeCrtcInfo(crtc); s_X11.freeOutputInfo(outputInfo); s_X11.freeScreenResources(resources); - - return PAL_RESULT_SUCCESS; } PalResult xSetMonitorMode( diff --git a/src/video/x11/pal_window_x11.c b/src/video/x11/pal_window_x11.c index c7664782..cf2e054f 100644 --- a/src/video/x11/pal_window_x11.c +++ b/src/video/x11/pal_window_x11.c @@ -82,6 +82,8 @@ static XVisualInfo* eglXBackend(int fbConfigIndex) return visualInfo; } +void xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); + PalResult xCreateWindow( const PalWindowCreateInfo* info, PalWindow** outWindow) @@ -158,11 +160,7 @@ PalResult xCreateWindow( if (monitor) { // get monitor info - PalResult result = palGetMonitorInfo(monitor, &monitorInfo); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - + xGetMonitorInfo(monitor, &monitorInfo); monitorX = monitorInfo.x; monitorY = monitorInfo.y; monitorW = monitorInfo.width; @@ -497,34 +495,15 @@ void xDestroyWindow(PalWindow* window) data->used = PAL_FALSE; } -PalResult xMinimizeWindow(PalWindow* window) +void xMinimizeWindow(PalWindow* window) { - if (!(s_X11.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - s_X11.iconifyWindow(s_X11.display, xWin, s_X11.screen); - return PAL_RESULT_SUCCESS; } -PalResult xMaximizeWindow(PalWindow* window) +void xMaximizeWindow(PalWindow* window) { - if (!(s_X11.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - sendWMEvent( xWin, s_X11Atoms._NET_WM_STATE, @@ -533,22 +512,11 @@ PalResult xMaximizeWindow(PalWindow* window) 1, 0, PAL_TRUE); // _NET_WM_STATE_ADD - - return PAL_RESULT_SUCCESS; } -PalResult xRestoreWindow(PalWindow* window) +void xRestoreWindow(PalWindow* window) { - if (!(s_X11.features & PAL_VIDEO_FEATURE_WINDOW_SET_STATE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - // since we have no fixed way to restore the window // we just restore from minimized and maximized state sendWMEvent( @@ -561,48 +529,25 @@ PalResult xRestoreWindow(PalWindow* window) PAL_FALSE); // _NET_WM_STATE_REMOVE s_X11.mapRaised(s_X11.display, xWin); - - return PAL_RESULT_SUCCESS; } -PalResult xShowWindow(PalWindow* window) +void xShowWindow(PalWindow* window) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - s_X11.mapWindow(s_X11.display, xWin); - return PAL_RESULT_SUCCESS; } -PalResult xHideWindow(PalWindow* window) +void xHideWindow(PalWindow* window) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - s_X11.unmapWindow(s_X11.display, xWin); - return PAL_RESULT_SUCCESS; } -PalResult xFlashWindow( +void xFlashWindow( PalWindow* window, const PalFlashInfo* info) { - if (info->flags & PAL_FLASH_FLAG_CAPTION) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - PalBool add = PAL_FALSE; if (info->flags & PAL_FLASH_FLAG_TRAY) { add = PAL_TRUE; @@ -625,10 +570,7 @@ PalResult xFlashWindow( if (!hints) { hints = s_X11.allocWMHints(); if (!hints) { - return palMakeResult( - PAL_RESULT_CODE_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_POSIX, - errno); + return; } if (add) { @@ -640,41 +582,15 @@ PalResult xFlashWindow( s_X11.free(hints); } } - - return PAL_RESULT_SUCCESS; -} - -PalResult xGetWindowStyle( - PalWindow* window, - PalWindowStyle* outStyle) -{ - // Window Manager quirks - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } -PalResult xGetWindowMonitor( - PalWindow* window, - PalMonitor** outMonitor) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult xGetWindowTitle( +void xGetWindowTitle( PalWindow* window, uint64_t bufferSize, uint64_t* outSize, char* outBuffer) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - - if (!outBuffer || bufferSize <= 0) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - if (s_X11Atoms.unicodeTitle) { Atom type; int format; @@ -716,11 +632,9 @@ PalResult xGetWindowTitle( } s_X11.free(text.value); } - - return PAL_RESULT_SUCCESS; } -PalResult xGetWindowPos( +void xGetWindowPos( PalWindow* window, int32_t* x, int32_t* y) @@ -728,7 +642,7 @@ PalResult xGetWindowPos( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; + return; } if (x) { @@ -738,11 +652,9 @@ PalResult xGetWindowPos( if (y) { *y = attr.y; } - - return PAL_RESULT_SUCCESS; } -PalResult xGetWindowSize( +void xGetWindowSize( PalWindow* window, uint32_t* width, uint32_t* height) @@ -750,7 +662,7 @@ PalResult xGetWindowSize( Window xWin = FROM_PAL_HANDLE(Window, window); XWindowAttributes attr; if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; + return; } if (width) { @@ -760,20 +672,13 @@ PalResult xGetWindowSize( if (height) { *height = attr.height; } - - return PAL_RESULT_SUCCESS; } -PalResult xGetWindowState( +void xGetWindowState( PalWindow* window, PalWindowState* outState) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - Atom type; int format; unsigned long count, bytesAfter; @@ -809,7 +714,6 @@ PalResult xGetWindowState( s_X11.free(props); *outState = state; - return PAL_RESULT_SUCCESS; } PalBool xIsWindowVisible(PalWindow* window) @@ -829,37 +733,28 @@ PalWindow* xGetFocusWindow() int tmp; s_X11.getInputFocus(s_X11.display, &window, &tmp); Window xWin = FROM_PAL_HANDLE(Window, window); - if (xWin == s_X11.root) { return nullptr; } return TO_PAL_HANDLE(PalWindow, window); } -PalResult xGetWindowHandleInfo( +void xGetWindowHandleInfo( PalWindow* window, PalWindowHandleInfo* info) { - if (!window || !info) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - info->nativeInstance = (void*)s_X11.display; info->nativeWindow = (void*)window; info->nativeHandle1 = nullptr; info->nativeHandle2 = nullptr; info->nativeHandle3 = nullptr; - - return PAL_RESULT_SUCCESS; } -PalResult xSetWindowOpacity( +void xSetWindowOpacity( PalWindow* window, float opacity) { - XErrorHandler old = s_X11.setErrorHandler(xErrorHandler); unsigned long value = (unsigned long)(opacity * 0xFFFFFFFFUL + 0.5f); - s_X11.changeProperty( s_X11.display, FROM_PAL_HANDLE(Window, window), @@ -870,34 +765,14 @@ PalResult xSetWindowOpacity( (unsigned char*)&value, 1); - s_X11.sync(s_X11.display, False); - s_X11.setErrorHandler(old); - if (s_X11.error) { - // technically, this is the only error that can occur - return PAL_RESULT_CODE_INVALID_HANDLE; - } - - return PAL_RESULT_SUCCESS; -} - -PalResult xSetWindowStyle( - PalWindow* window, - PalWindowStyle style) -{ - // Window Manager quirks - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; + s_X11.flush(s_X11.display); } -PalResult xSetWindowTitle( +void xSetWindowTitle( PalWindow* window, const char* title) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - if (s_X11Atoms.unicodeTitle) { s_X11.changeProperty( s_X11.display, @@ -914,36 +789,24 @@ PalResult xSetWindowTitle( } s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; } -PalResult xSetWindowPos( +void xSetWindowPos( PalWindow* window, int32_t x, int32_t y) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - s_X11.moveWindow(s_X11.display, xWin, x, y); s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; } -PalResult xSetWindowSize( +void xSetWindowSize( PalWindow* window, uint32_t width, uint32_t height) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - // X11 does not allow users resize programaticaly // if the window is not resizable. // so we hack it by making the window resizable and resizing @@ -969,24 +832,16 @@ PalResult xSetWindowSize( } s_X11.flush(s_X11.display); - return PAL_RESULT_SUCCESS; } -PalResult xSetFocusWindow(PalWindow* window) +void xSetFocusWindow(PalWindow* window) { Window xWin = FROM_PAL_HANDLE(Window, window); - XWindowAttributes attr; - if (!s_X11.getWindowAttributes(s_X11.display, xWin, &attr)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - if (s_X11Atoms._NET_ACTIVE_WINDOW) { sendWMEvent(xWin, s_X11Atoms._NET_ACTIVE_WINDOW, CurrentTime, 0, 0, 0, PAL_TRUE); // 1 } else { s_X11.setInputFocus(s_X11.display, xWin, RevertToParent, CurrentTime); } - - return PAL_RESULT_SUCCESS; } PalResult xAttachWindow( From 8bd9741e8dda718b32b12eb535cbcabafca2f92e Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 11 Jul 2026 10:37:51 +0000 Subject: [PATCH 332/372] core, event, system, thread and opengl tests working with API changes --- CHANGELOG.md | 43 ++-- include/pal/pal_core.h | 13 +- include/pal/pal_event.h | 4 +- include/pal/pal_graphics.h | 37 +--- include/pal/pal_opengl.h | 37 ++-- include/pal/pal_thread.h | 10 +- include/pal/pal_video.h | 29 +-- pal_config.lua | 6 +- src/core/pal_result.h | 18 -- src/video/win32/pal_cursor_win32.c | 84 ++------ src/video/win32/pal_icon_win32.c | 7 +- src/video/win32/pal_monitor_win32.c | 103 ++-------- src/video/win32/pal_window_win32.c | 309 ++++------------------------ 13 files changed, 132 insertions(+), 568 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c095aeb2..c61143a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,13 +41,31 @@ ### Changes +- `palGetVersion()` now returns `void` and takes a pointer to the struct. +- `palFormatResult()` now takes two additional parameters - Converted all enum types to fixed-width integer types and their values to standalone constants (eg. `PalResult` to `uint64_t`). - Removed all previous `PalResult` values except: `PAL_RESULT_SUCCESS` +- Removed `palGLSetInstance()` function. +- Removed `palGLGetBackend()` function. +- Removed `palGetVideoFeaturesEx()` function and `PalVideoFeatures64` enum. +- Removed `palGetWindowHandleInfoEx()` function and `PalWindowHandleInfoEX` struct. +- Removed `palGetRawMouseWheelDelta()` function. +- Removed `palSetPreferredInstance()` function. +- Removed `palSetFBConfig()` function. +- Removed `PAL_FBCONFIG_BACKEND_GLES`. +- `palInitGL()` now takes two additional parameters. +- `palEnumerateGLFBConfigs()` no longer takes the `glWindow` and `count` now as `uint32_t` +- `palInitVideo()` now takes an additional parameter. +- `palGetWindowHandleInfo()` now returns `PalResult` and takes a pointer to the struct. +- `PalGLInfo` now has `backend` and `api` fields. +- Renamed `nativeDisplay` to `nativeInstance` in `PalWindowHandleInfo`. +- Renamed `display` to `instance` in `PalGLWindow`. +- `PalWindowHandleInfo` now has `nativeHandle1`, `nativeHandle2` and `nativeHandle3` fields. +- `PalWindowCreateInfo` now has `state`, `appName`, `instanceName`, `fbConfigBackend` and `fbConfigIndex` fields. +- Removed `maximized` and `minimized` in `PalWindowCreateInfo`. - Removed `UintXX` and `IntXX` types in favor of standard `uintXX_t` and `intXX_t`. - Removed `_MAX` constants from all type groups (eg. `PAL_EVENT_MAX`). - Replaced standard `bool` type and `true`/`false` constants with `PalBool` type and `PAL_TRUE`/`PAL_FALSE`. -- `palGetVersion()` now returns `void` and takes a pointer to the struct. -- `palFormatResult()` now takes two additional parameters. - Renamed `PalGLRelease` to `PalGLReleaseBehavior`. - Renamed `palGLGetProcAddress()` to `palGetGLProcAddress()`. - Renamed event type constants from `PAL_EVENT_**` to `PAL_EVENT_TYPE_**`. @@ -58,30 +76,12 @@ - Renamed flash flag constants from `PAL_FLASH_**` to `PAL_FLASH_FLAG_**`. - Renamed fbConfig backend type constants from `PAL_FBCONFIG_BACKEND_**` to `PAL_FBCONFIG_BACKEND_**`. - Renamed `PalFlashFlag` to `PalFlashFlags`. -- `palInitGL()` now takes two additional parameters. -- `palEnumerateGLFBConfigs()` no longer takes the `glWindow` and `count` now as `uint32_t` -- `palInitVideo()` now takes an additional parameter. - `palGetMouseDelta()` now takes `dx` and `dy` paramters as `float`. - `palEnumerateMonitors()` now takes `count` paramter as `uint32_t`. - `palEnumerateMonitorModes()` now takes `count` paramter as `uint32_t`. +- `palGetClosestGLFBConfig()` now takes `count` paramter as `uint32_t`. - `palGetMouseWheelDelta()` now takes `dx` and `dy` paramters as `float`. - `palJoinThread()` now takes `retval` paramters as `void**`. -- Removed `palGLSetInstance()` function. -- Removed `palGLGetBackend()` function. -- Removed `palGetVideoFeaturesEx()` function and `PalVideoFeatures64` enum. -- Removed `palGetWindowHandleInfoEx()` function and `PalWindowHandleInfoEX` struct. -- Removed `palGetRawMouseWheelDelta()` function. -- Removed `palSetPreferredInstance()` function. -- Removed `palSetFBConfig()` function. -- Removed `PAL_FBCONFIG_BACKEND_GLES`. -- `palGetWindowHandleInfo()` now returns `PalResult` and takes a pointer to the struct. -- `PalGLInfo` now has `backend` and `api` fields. -- Renamed `nativeDisplay` to `nativeInstance` in `PalWindowHandleInfo`. -- Renamed `display` to `instance` in `PalGLWindow`. -- `PalWindowHandleInfo` now has `nativeHandle1`, `nativeHandle2` and `nativeHandle3` fields. -- `PalWindowCreateInfo` now has `state`, `appName`, `instanceName`, `fbConfigBackend` and `fbConfigIndex` fields. -- Removed `maximized` and `minimized` in `PalWindowCreateInfo`. - - These function now returns `void` instead of `PalResult` and does not do runtime validation anymore: invalid arguments, feature not supported results in undefined behavior: - `palGetPlatformInfo()` @@ -115,6 +115,7 @@ validation anymore: invalid arguments, feature not supported results in undefine - `palSetWindowCursor()` - `palSetWindowOpacity()` - `palFlashWindow()` + - `palSetSwapInterval()` diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 717a7b84..ab1ee711 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -153,7 +153,7 @@ typedef void*(PAL_CALL* PalAllocateFn)( * @brief Function pointer type used for memory deallocations. * * @param[in] userData Optional pointer to user data. Can be `nullptr`. - * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. Must not be `nullptr` + * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. * * @since 1.0 * @sa PalAllocateFn @@ -199,8 +199,8 @@ typedef struct { * @since 1.0 */ typedef struct { - PalAllocateFn allocate; /**< Allocate function pointer. Must not be `nullptr`.*/ - PalFreeFn free; /**< Free function pointer. Must not be `nullptr`.*/ + PalAllocateFn allocate; /**< Allocate function pointer.*/ + PalFreeFn free; /**< Free function pointer.*/ void* userData; /**< Optional user-provided data. Can be `nullptr`.*/ } PalAllocator; @@ -215,7 +215,7 @@ typedef struct { * @since 1.0 */ typedef struct { - PalLogCallback callback; /**< Callback function pointer. Must not be `nullptr`.*/ + PalLogCallback callback; /**< Callback function pointer.*/ void* userData; /** Optional user-provided data. Can be `nullptr`.*/ } PalLogger; @@ -284,9 +284,8 @@ PAL_API void* PAL_CALL palAllocate( /** * Free memory allocated by palAllocate. * - * @param allocator The allocator used to allocate the memory. Set to `nullptr` to - * use default. - * @param ptr Pointer to memory to free. Must not be `nullptr`. + * @param allocator The allocator used to allocate the memory. Set to `nullptr` to use default. + * @param ptr Pointer to memory to free. * * Thread safety: Thread safe if the provided allocator is thread * safe. The default allocator is thread safe. diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 593a509a..fac2e276 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -337,8 +337,8 @@ struct PalEvent { * @since 1.0 */ typedef struct { - PalPushFn push; /**< Push function pointer. Must not be `nullptr`.*/ - PalPollFn poll; /**< Poll function pointer. Must not be `nullptr`.*/ + PalPushFn push; /**< Push function pointer.*/ + PalPollFn poll; /**< Poll function pointer.*/ void* userData; /**< Optional user-provided data. Can be `nullptr`.*/ } PalEventQueue; diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 24dbc93e..99404bf2 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1735,7 +1735,7 @@ typedef struct { * @since 2.0 */ typedef struct { - PalImageView* imageView; /**< Image view. Must not be `nullptr`.*/ + PalImageView* imageView; /**< Image view.*/ PalImageView* resolveImageView; /**< Resolve image view. Can be `nullptr`.*/ PalLoadOp loadOp; /**< (eg. `PAL_LOAD_OP_CLEAR`).*/ PalStoreOp storeOp; /**< (eg. `PAL_STORE_OP_STORE`).*/ @@ -2409,7 +2409,7 @@ typedef struct { * @since 2.0 */ typedef struct { - const char* entryName; /**< Must not be `nullptr`.*/ + const char* entryName; /**< Shader stage entry name.*/ PalShaderStage stage; /**< (eg. `PAL_SHADER_STAGE_VERTEX`).*/ uint32_t patchControlPoints; /**< For tessellation shaders. Will be ignored by other stages.*/ } PalShaderEntryInfo; @@ -4121,7 +4121,7 @@ PAL_API uint32_t PAL_CALL palGetHighestSupportedShaderTarget( * * @param[in] adapter Adapter that creates the device. * @param[in] features Adapter features to enable. Must be supported. - * @param[out] outDevice Pointer to a PalDevice to recieve the created device. Must not be `nullptr`. + * @param[out] outDevice Pointer to a PalDevice to recieve the created device. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -4531,7 +4531,6 @@ PAL_API PalSampleCount PAL_CALL palQueryFormatSampleCount( * * @param[in] device Device that creates the image. * @param[in] info Pointer to a PalImageCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outImage Pointer to a PalImage to recieve the created image. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4604,7 +4603,7 @@ PAL_API void PAL_CALL palGetImageMemoryRequirements( * Get the requirements with palGetImageMemoryRequirements(). * * @param[in] image Image to bind memory to. - * @param[in] memory Memory to bind. Must not be `nullptr`. + * @param[in] memory Memory to bind. * @param[in] offset Starting point within the memory. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4636,7 +4635,6 @@ PAL_API PalResult PAL_CALL palBindImageMemory( * @param[in] device Device that creates the image view. * @param[in] image Image to create the image view with. * @param[in] info Pointer to a PalImageViewCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outImageView Pointer to a PalImageView to recieve the created image view. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4677,7 +4675,6 @@ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); * * @param[in] device Device that creates the sampler. * @param[in] info Pointer to a PalSamplerCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outSampler Pointer to a PalSampler to recieve the created sampler. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4785,7 +4782,6 @@ PAL_API void PAL_CALL palGetSurfaceCapabilities( * @param[in] queue Queue to create swapchain with. This must be a graphics queue. * @param[in] surface Surface to create swapchain with. * @param[in] info Pointer to a PalSwapchainCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outSwapchain Pointer to a PalSwapchain to recieve the created swapchain. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4844,7 +4840,6 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( * * @param[in] swapchain Swapchain to get image index from. * @param[in] info Pointer to a PalSwapchainNextImageInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outIndex Pointer to a uint32_t to recieve the next image index. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -4927,7 +4922,6 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( * * @param[in] device Device that creates the shader. * @param[in] info Pointer to a PalShaderCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outShader Pointer to a PalShader to recieve the created shader. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -5283,7 +5277,6 @@ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); * * @param[in] queue Queue to execute the command buffer. * @param[in] info Pointer to a PalCommandBufferSubmitInfo struct that specifies parameters. - * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -5473,7 +5466,6 @@ PAL_API void PAL_CALL palCmdBuildAccelerationStructure( * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] info Pointer to a PalRenderingInfo struct that specifies parameters. - * Must not be `nullptr`. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * @@ -5505,10 +5497,6 @@ PAL_API void PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); * @param[in] dst Destination buffer. * @param[in] src Source buffer. * @param[in] copyInfo Pointer to a PalBufferCopyInfo struct that specifies parameters. - * Must not be `nullptr`. - * - * Pointer to a PalImageCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * @@ -5529,7 +5517,6 @@ PAL_API void PAL_CALL palCmdCopyBuffer( * @param[in] dstImage Destination image. * @param[in] srcBuffer Source buffer. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. - * Must not be `nullptr`. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * @@ -5550,7 +5537,6 @@ PAL_API void PAL_CALL palCmdCopyBufferToImage( * @param[in] dst Destination image. * @param[in] src Source image. * @param[in] copyInfo Pointer to a PalImageCopyInfo struct that specifies parameters. - * Must not be `nullptr`. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * @@ -5571,7 +5557,6 @@ PAL_API void PAL_CALL palCmdCopyImage( * @param[in] dstBuffer Destination buffer. * @param[in] srcImage Source image. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. - * Must not be `nullptr`. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * @@ -6029,7 +6014,7 @@ PAL_API void PAL_CALL palCmdDispatchBase( * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. - * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be `nullptr`. + * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * @@ -6083,7 +6068,7 @@ PAL_API void PAL_CALL palCmdTraceRays( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] raygenIndex Index of the raygen shader to execute. * @param[in] sbt The shader binding table to use. - * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. Must not be `nullptr`. + * @param[in] buffer Buffer containing the PalDispatchIndirectData struct. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * @@ -6490,7 +6475,7 @@ PAL_API void PAL_CALL palWriteImageStaging( * Get the requirements with palGetBufferMemoryRequirements(). * * @param[in] buffer Buffer to bind memory to. - * @param[in] memory Memory to bind. Must not be `nullptr`. + * @param[in] memory Memory to bind. * @param[in] offset Starting point within the memory. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6582,9 +6567,7 @@ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); * * @param[in] device Device that creates the descriptor set layout. * @param[in] info Pointer to a PalDescriptorSetLayoutCreateInfo struct that specifies parameters. - * Must not be `nullptr`. - * @param[out] outLayout Pointer to a PalDescriptorSetLayout to recieve the created descriptor - * set layout. + * @param[out] outLayout Pointer to a PalDescriptorSetLayout to recieve the created layout. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -6621,7 +6604,6 @@ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layo * * @param[in] device Device that creates the descriptor pool. * @param[in] info Pointer to a PalDescriptorPoolCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outPool Pointer to a PalDescriptorPool to recieve the created descriptor pool. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6728,7 +6710,6 @@ PAL_API PalResult PAL_CALL palUpdateDescriptorSet( * * @param[in] device Device that creates the pipeline layout. * @param[in] info Pointer to a PalPipelineLayoutCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outLayout Pointer to a PalPipelineLayout to recieve the created pipeline layout. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6766,7 +6747,6 @@ PAL_API void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout); * * @param[in] device Device that creates the graphics pipeline. * @param[in] info Pointer to a PalGraphicsPipelineCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on @@ -6789,7 +6769,6 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( * * @param[in] device Device that creates the compute pipeline. * @param[in] info Pointer to a PalComputePipelineCreateInfo struct that specifies parameters. - * Must not be `nullptr`. * @param[out] outPipeline Pointer to a PalPipeline to recieve the created buffer. * * @return `PAL_RESULT_SUCCESS` on success or a result code on diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 8e6a0579..0575b3e7 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -181,8 +181,8 @@ typedef struct { * @since 1.0 */ typedef struct { - void* instance; /**< Must not be `nullptr`. (HINSTANCE on Win32 or wl_display on Wayland)*/ - void* window; /**< Must not be `nullptr`. (egl_wl_window on Wayland)*/ + void* instance; /**< (HINSTANCE on Win32 or wl_display on Wayland)*/ + void* window; /**< (egl_wl_window on Wayland)*/ } PalGLWindow; /** @@ -194,8 +194,8 @@ typedef struct { * @since 1.0 */ typedef struct { - const PalGLWindow* window; /**< Window to create context for. Must not be `nullptr`.*/ - const PalGLFBConfig* fbConfig; /**< The framebuffer config to use. Must not be `nullptr`.*/ + const PalGLWindow* window; /**< Window to create context for.*/ + const PalGLFBConfig* fbConfig; /**< The framebuffer config to use.*/ PalGLContext* shareContext; /**< Can be `nullptr`.*/ PalGLProfile profile; /**< (eg. `PAL_GL_PROFILE_CORE`).*/ PalGLContextReset reset; /**< (eg. `PAL_GL_CONTEXT_RESET_LOSE_CONTEXT`).*/ @@ -210,8 +210,8 @@ typedef struct { /** * @brief Initialize the opengl system. * - * This must be called before any opengl function. The opengl system must be - * shutdown with palShutdownGL() when no longer needed. + * This must be called before any opengl function. Call `palGetSupportedGLAPIs()` to check + * if `api` is supported on `instance`. * * The allocator will not not copied, therefore the pointer must remain valid * until the opengl system is shutdown. @@ -221,12 +221,9 @@ typedef struct { * `Linux`: This is the Display associated with the connection. * `Windows`: This is the HINSTANCE of the process. * - * @param[in] api The api to use. (eg. `PAL_GL_API_OPENGL`). Call `palGetSupportedGLAPIs()` to check - * if an api is supported on `instance`. + * @param[in] api The api to use. (eg. `PAL_GL_API_OPENGL`). * @param[in] instance The instance the opengl system will be tied to (eg. XDisplay). - * Must not be `nullptr`. - * @param[in] allocator Optional user-provided allocator. Set to `nullptr` to use - * default. + * @param[in] allocator Optional user-provided allocator. Set to `nullptr` to use default. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -301,11 +298,6 @@ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( * The opengl system must be initialized before this call. * This function uses missing and score system to get the closest PalGLFBConfig. * - * The count must be the number of PalGLFBConfig in the - * array of PalGLFBConfig. If the count is less than or equal to 0 or the - * desired PalGLFBConfig or the PalGLFBConfig array is `nullptr`, this function - * fails and returns `nullptr`. - * * @param[in] configs Pointer to the array of PalGLFBConfig. * @param[in] count Capacity of the PalGLFBConfig array. * @param[in] desired The desired PalGLFBConfig. @@ -318,7 +310,7 @@ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( */ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( PalGLFBConfig* configs, - int32_t count, + uint32_t count, const PalGLFBConfig* desired); /** @@ -334,10 +326,8 @@ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( * On Wayland: PalGLContextCreateInfo::PalGLWindow::window is the wl_egl_window * not the wl_surface. * - * @param[in] info Pointer to a PalGLContextCreateInfo struct that specifies - * parameters. Must not be `nullptr`. - * @param[out] outContext Pointer to a PalGLContext to recieve the created - * context. Must not be `nullptr`. + * @param[in] info Pointer to a PalGLContextCreateInfo struct that specifies parameters. + * @param[out] outContext Pointer to a PalGLContext to recieve the created context. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -438,16 +428,13 @@ PAL_API PalResult PAL_CALL palSwapBuffers( * * @param[in] interval The swap interval * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. - * * Thread safety: Must only be called from a thread with a bound * context. * * @since 1.0 * @sa palMakeContextCurrent */ -PAL_API PalResult PAL_CALL palSetSwapInterval(int32_t interval); +PAL_API void PAL_CALL palSetSwapInterval(int32_t interval); /** * @brief Get supported opengl APIs diff --git a/include/pal/pal_thread.h b/include/pal/pal_thread.h index efadbb7a..e4d26c36 100644 --- a/include/pal/pal_thread.h +++ b/include/pal/pal_thread.h @@ -130,10 +130,8 @@ typedef struct { * The created thread starts executing from the entry function. The thread runs * until the entry function has finished executing or its detached. * - * @param[in] info Pointer to a PalThreadCreateInfo struct that specifies - * parameters. Must not be `nullptr`. - * @param[out] outThread Pointer to a PalThread to recieve the created - * thread. Must not be `nullptr`. + * @param[in] info Pointer to a PalThreadCreateInfo struct that specifies parameters. + * @param[out] outThread Pointer to a PalThread to recieve the created thread. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -430,10 +428,8 @@ PAL_API void PAL_CALL palSetTLS( /** * @brief Create a mutex. * - * @param[in] allocator Optional user-provided allocator. Set to `nullptr` to use - * default. + * @param[in] allocator Optional user-provided allocator. Set to `nullptr` to use default. * @param[out] outMutex Pointer to a PalMutex to recieve the created mutex. - * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 55b4d3f2..999ffc68 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -854,10 +854,8 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * the video system might still get a FBConfig but it will not be the * one requested. * - * @param[in] info Pointer to a PalWindowCreateInfo struct that specifies - * parameters. Must not be `nullptr`. - * @param[out] outWindow Pointer to a PalWindow to recieve the created - * window. Must not be `nullptr`. + * @param[in] info Pointer to a PalWindowCreateInfo struct that specifies parameters. + * @param[out] outWindow Pointer to a PalWindow to recieve the created window. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1380,10 +1378,8 @@ PAL_API void PAL_CALL palSetFocusWindow(PalWindow* window); * The video system must be initialized before this call. * `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported otherwise undefined behavior. * - * @param[in] info Pointer to a PalIconCreateInfo struct that specifies - * parameters. Must not be `nullptr`. - * @param[out] outIcon Pointer to a PalIcon to recieve the created - * icon. Must not be `nullptr`. + * @param[in] info Pointer to a PalIconCreateInfo struct that specifies parameters. + * @param[out] outIcon Pointer to a PalIcon to recieve the created icon. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1433,10 +1429,8 @@ PAL_API void PAL_CALL palSetWindowIcon( * * The video system must be initialized before this call. * - * @param[in] info Pointer to a PalCursorCreateInfo struct that specifies - * parameters. Must not be `nullptr`. - * @param[out] outCursor Pointer to a PalCursor to recieve the created - * cursor. Must not be `nullptr`. + * @param[in] info Pointer to a PalCursorCreateInfo struct that specifies parameters. + * @param[out] outCursor Pointer to a PalCursor to recieve the created cursor. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1455,9 +1449,8 @@ PAL_API PalResult PAL_CALL palCreateCursor( * * The video system must be initialized before this call. * - * @param[in] type The system cursor type to create. Must not be `nullptr`. - * @param[out] outCursor Pointer to a PalCursor to recieve the created - * cursor. Must not be `nullptr`. + * @param[in] type The system cursor type to create. + * @param[out] outCursor Pointer to a PalCursor to recieve the created cursor. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1627,7 +1620,6 @@ PAL_API void* PAL_CALL palGetInstance(); * * @param[in] windowHandle Pointer to the foreign or native window. * @param[out] outWindow Pointer to a PalWindow to recieve the attached window. - * Must not be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. @@ -1661,9 +1653,8 @@ PAL_API PalResult PAL_CALL palAttachWindow( * Give back the PalWindow returned at palAttachWindow() * and get back your native window. * - * @param[in] window Pointer to the PalWindow to detach. Must not be `nullptr`. - * @param[out] outWindowHandle Pointer to recieve the native window. Can be - * `nullptr`. + * @param[in] window Pointer to the PalWindow to detach. + * @param[out] outWindowHandle Pointer to recieve the native window. Can be `nullptr`. * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. diff --git a/pal_config.lua b/pal_config.lua index f5c2621f..f26dd621 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -12,13 +12,13 @@ PAL_BUILD_ABI_DUMP = true PAL_BUILD_SYSTEM_MODULE = true -- build thread module -PAL_BUILD_THREAD_MODULE = false +PAL_BUILD_THREAD_MODULE = true -- build video module PAL_BUILD_VIDEO_MODULE = true -- build opengl module -PAL_BUILD_OPENGL_MODULE = false +PAL_BUILD_OPENGL_MODULE = true -- build graphics module -PAL_BUILD_GRAPHICS_MODULE = true +PAL_BUILD_GRAPHICS_MODULE = false diff --git a/src/core/pal_result.h b/src/core/pal_result.h index 440061d2..52605aca 100644 --- a/src/core/pal_result.h +++ b/src/core/pal_result.h @@ -32,20 +32,11 @@ static const char* resultCodeToString(PalResult result) case PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED: return "PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED"; - case PAL_RESULT_CODE_NOT_INITIALIZED: - return "PAL_RESULT_CODE_NOT_INITIALIZED"; - case PAL_RESULT_CODE_INVALID_OPERATION: return "PAL_RESULT_CODE_INVALID_OPERATION"; case PAL_RESULT_CODE_DEVICE_LOST: return "PAL_RESULT_CODE_DEVICE_LOST"; - - case PAL_RESULT_CODE_OUT_OF_DATE: - return "PAL_RESULT_CODE_OUT_OF_DATE"; - - case PAL_RESULT_CODE_INVALID_DRIVER: - return "PAL_RESULT_CODE_INVALID_DRIVER"; } return ""; @@ -73,20 +64,11 @@ static const char* resultCodeToDescription(PalResult result) case PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED: return "Feature not supported"; - case PAL_RESULT_CODE_NOT_INITIALIZED: - return "Not initialized"; - case PAL_RESULT_CODE_INVALID_OPERATION: return "Invalid operation"; case PAL_RESULT_CODE_DEVICE_LOST: return "Device lost"; - - case PAL_RESULT_CODE_OUT_OF_DATE: - return "Out of date"; - - case PAL_RESULT_CODE_INVALID_DRIVER: - return "Invalid driver"; } return nullptr; diff --git a/src/video/win32/pal_cursor_win32.c b/src/video/win32/pal_cursor_win32.c index e11f3dd4..0a8990b9 100644 --- a/src/video/win32/pal_cursor_win32.c +++ b/src/video/win32/pal_cursor_win32.c @@ -148,19 +148,13 @@ void win32ShowCursor(PalBool show) ShowCursor(show); } -PalResult win32ClipCursor( +void win32ClipCursor( PalWindow* window, PalBool clip) { if (clip) { RECT rect; - if (!GetClientRect((HWND)window, &rect)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - + GetClientRect((HWND)window, &rect); POINT tmp = {rect.left, rect.top}; POINT tmp2 = {rect.right, rect.bottom}; @@ -173,91 +167,41 @@ PalResult win32ClipCursor( } else { ClipCursor(nullptr); } - - return PAL_RESULT_SUCCESS; } -PalResult win32GetCursorPos( +void win32GetCursorPos( PalWindow* window, int32_t* x, int32_t* y) { POINT pos; GetCursorPos(&pos); - if (ScreenToClient((HWND)window, &pos)) { - if (x) { - *x = pos.x; - } - - if (y) { - *y = pos.y; - } - - return PAL_RESULT_SUCCESS; + ScreenToClient((HWND)window, &pos); + if (x) { + *x = pos.x; + } - } else { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); + if (y) { + *y = pos.y; } } -PalResult win32SetCursorPos( +void win32SetCursorPos( PalWindow* window, int32_t x, int32_t y) { POINT pos = {x, y}; - if (!ClientToScreen((HWND)window, &pos)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - + ClientToScreen((HWND)window, &pos); SetCursorPos(pos.x, pos.y); - return PAL_RESULT_SUCCESS; } -PalResult win32SetWindowCursor( +void win32SetWindowCursor( PalWindow* window, PalCursor* cursor) { - if (window) { - SetLastError(0); - WindowData* data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); - if (!data) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - - data->cursor = (HCURSOR)cursor; - DWORD error = GetLastError(); - if (error == 0) { - return PAL_RESULT_SUCCESS; - - } else if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - - } else { - return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } + WindowData* data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); + data->cursor = (HCURSOR)cursor; } #endif // _WIN32 \ No newline at end of file diff --git a/src/video/win32/pal_icon_win32.c b/src/video/win32/pal_icon_win32.c index 8f06a14e..49e39dbc 100644 --- a/src/video/win32/pal_icon_win32.c +++ b/src/video/win32/pal_icon_win32.c @@ -98,17 +98,12 @@ void win32DestroyIcon(PalIcon* icon) DestroyIcon((HICON)icon); } -PalResult win32SetWindowIcon( +void win32SetWindowIcon( PalWindow* window, PalIcon* icon) { - if (!IsWindow((HWND)window)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - SendMessageW((HWND)window, WM_SETICON, ICON_BIG, (LPARAM)icon); SendMessageW((HWND)window, WM_SETICON, ICON_SMALL, (LPARAM)icon); - return PAL_RESULT_SUCCESS; } #endif // _WIN32 \ No newline at end of file diff --git a/src/video/win32/pal_monitor_win32.c b/src/video/win32/pal_monitor_win32.c index 8848f8df..3456b288 100644 --- a/src/video/win32/pal_monitor_win32.c +++ b/src/video/win32/pal_monitor_win32.c @@ -10,7 +10,6 @@ #define MONITOR_DPI 0 #define MAX_MODE_COUNT 128 -#define NULL_ORIENTATION 5 typedef struct { int32_t count; @@ -68,7 +67,7 @@ static inline DWORD orientationToin32(PalOrientation orientation) case PAL_ORIENTATION_PORTRAIT_FLIPPED: return DMDO_270; } - return NULL_ORIENTATION; + return 0; } static inline PalResult setMonitorMode( @@ -170,43 +169,19 @@ PalResult win32EnumerateMonitors( return PAL_RESULT_SUCCESS; } -PalResult win32GetPrimaryMonitor(PalMonitor** outMonitor) +void win32GetPrimaryMonitor(PalMonitor** outMonitor) { - HMONITOR monitor = nullptr; - monitor = MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); - if (!monitor) { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - + HMONITOR monitor = MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); *outMonitor = (PalMonitor*)monitor; - return PAL_RESULT_SUCCESS; } -PalResult win32GetMonitorInfo( +void win32GetMonitorInfo( PalMonitor* monitor, PalMonitorInfo* info) { MONITORINFOEXW mi = {0}; mi.cbSize = sizeof(MONITORINFOEXW); - if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } - + GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi); info->x = mi.rcMonitor.left; info->y = mi.rcMonitor.top; info->width = mi.rcMonitor.right - mi.rcMonitor.left; @@ -241,11 +216,9 @@ PalResult win32GetMonitorInfo( if (primary == (HMONITOR)monitor) { info->primary = PAL_TRUE; } - - return PAL_RESULT_SUCCESS; } -PalResult win32EnumerateMonitorModes( +void win32EnumerateMonitorModes( PalMonitor* monitor, uint32_t* count, PalMonitorMode* modes) @@ -256,28 +229,13 @@ PalResult win32EnumerateMonitorModes( MONITORINFOEXW mi = {0}; mi.cbSize = sizeof(MONITORINFOEXW); - if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } - + GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi); if (!modes) { // allocate and store tmp monitor modesand check for the interested // fields. monitorModes = palAllocate(s_Win32.allocator, sizeof(PalMonitorMode) * MAX_MODE_COUNT, 0); if (!monitorModes) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; + return; } memset(monitorModes, 0, sizeof(PalMonitorMode) * MAX_MODE_COUNT); @@ -308,31 +266,15 @@ PalResult win32EnumerateMonitorModes( *count = modeCount; palFree(s_Win32.allocator, monitorModes); } - - return PAL_RESULT_SUCCESS; } -PalResult win32GetCurrentMonitorMode( +void win32GetCurrentMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { MONITORINFOEXW mi = {0}; mi.cbSize = sizeof(MONITORINFOEXW); - if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } + GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi); DEVMODE devMode = {0}; devMode.dmSize = sizeof(DEVMODE); @@ -341,8 +283,6 @@ PalResult win32GetCurrentMonitorMode( mode->height = devMode.dmPelsHeight; mode->refreshRate = devMode.dmDisplayFrequency; mode->bpp = devMode.dmBitsPerPel; - - return PAL_RESULT_SUCCESS; } PalResult win32SetMonitorMode( @@ -364,27 +304,9 @@ PalResult win32SetMonitorOrientation( PalOrientation orientation) { DWORD win32Orientation = orientationToin32(orientation); - if (orientation == NULL_ORIENTATION) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } - MONITORINFOEXW mi = {0}; mi.cbSize = sizeof(MONITORINFOEXW); - if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } + GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi); DEVMODE devMode = {0}; devMode.dmSize = sizeof(DEVMODE); @@ -408,14 +330,13 @@ PalResult win32SetMonitorOrientation( devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYORIENTATION; devMode.dmDisplayOrientation = win32Orientation; - ULONG result = ChangeDisplaySettingsExW(mi.szDevice, &devMode, NULL, CDS_RESET, NULL); if (result == DISP_CHANGE_SUCCESSFUL) { return PAL_RESULT_SUCCESS; } else { return palMakeResult( - PAL_RESULT_CODE_INVALID_OPERATION, + PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/video/win32/pal_window_win32.c b/src/video/win32/pal_window_win32.c index e926c96f..6784f489 100644 --- a/src/video/win32/pal_window_win32.c +++ b/src/video/win32/pal_window_win32.c @@ -102,13 +102,8 @@ PalResult win32CreateWindow( } } - // get monitor info - PalResult result = palGetMonitorInfo(monitor, &monitorInfo); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - // compose position. + palGetMonitorInfo(monitor, &monitorInfo); int32_t x, y = 0; // the position and size must be scaled with the dpi before this call if (info->center) { @@ -246,62 +241,32 @@ void win32DestroyWindow(PalWindow* window) data->used = PAL_FALSE; } -PalResult win32MinimizeWindow(PalWindow* window) +void win32MinimizeWindow(PalWindow* window) { - if (!ShowWindow((HWND)window, SW_MINIMIZE)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - return PAL_RESULT_SUCCESS; + ShowWindow((HWND)window, SW_MINIMIZE); } -PalResult win32MaximizeWindow(PalWindow* window) +void win32MaximizeWindow(PalWindow* window) { - if (!ShowWindow((HWND)window, SW_MAXIMIZE)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - return PAL_RESULT_SUCCESS; + ShowWindow((HWND)window, SW_MAXIMIZE); } -PalResult win32RestoreWindow(PalWindow* window) +void win32RestoreWindow(PalWindow* window) { - if (!ShowWindow((HWND)window, SW_RESTORE)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - return PAL_RESULT_SUCCESS; + ShowWindow((HWND)window, SW_RESTORE); } -PalResult win32ShowWindow(PalWindow* window) +void win32ShowWindow(PalWindow* window) { - if (!ShowWindow((HWND)window, SW_SHOW)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - return PAL_RESULT_SUCCESS; + ShowWindow((HWND)window, SW_SHOW); } -PalResult win32HideWindow(PalWindow* window) +void win32HideWindow(PalWindow* window) { - if (!ShowWindow((HWND)window, SW_HIDE)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - return PAL_RESULT_SUCCESS; + ShowWindow((HWND)window, SW_HIDE); } -PalResult win32FlashWindow( +void win32FlashWindow( PalWindow* window, const PalFlashInfo* info) { @@ -325,28 +290,10 @@ PalResult win32FlashWindow( flashInfo.dwTimeout = info->interval; flashInfo.hwnd = (HWND)window; flashInfo.uCount = info->count; - - PalBool success = FlashWindowEx(&flashInfo); - if (!success) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } - - return PAL_RESULT_SUCCESS; + FlashWindowEx(&flashInfo); } -PalResult win32GetWindowStyle( +void win32GetWindowStyle( PalWindow* window, PalWindowStyle* outStyle) { @@ -354,13 +301,6 @@ PalResult win32GetWindowStyle( DWORD style = (DWORD)GetWindowLongPtrW((HWND)window, GWL_STYLE); DWORD exStyle = (DWORD)GetWindowLongPtrW((HWND)window, GWL_EXSTYLE); - if (!style) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - // check if we can resize if (style & WS_THICKFRAME) { windowStyle |= PAL_WINDOW_STYLE_RESIZABLE; @@ -401,49 +341,24 @@ PalResult win32GetWindowStyle( } *outStyle = windowStyle; - return PAL_RESULT_SUCCESS; } -PalResult win32GetWindowMonitor( +void win32GetWindowMonitor( PalWindow* window, PalMonitor** outMonitor) { - HMONITOR monitor = nullptr; - monitor = MonitorFromWindow((HWND)window, MONITOR_DEFAULTTONEAREST); - if (!monitor) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } - + HMONITOR monitor = MonitorFromWindow((HWND)window, MONITOR_DEFAULTTONEAREST); *outMonitor = (PalMonitor*)monitor; - return PAL_RESULT_SUCCESS; } -PalResult win32GetWindowTitle( +void win32GetWindowTitle( PalWindow* window, uint64_t bufferSize, uint64_t* outSize, char* outBuffer) { wchar_t buffer[WINDOW_NAME_SIZE]; - if (GetWindowTextW((HWND)window, buffer, WINDOW_NAME_SIZE) == 0) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - + GetWindowTextW((HWND)window, buffer, WINDOW_NAME_SIZE); int len = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, nullptr, 0, 0, 0); if (outSize) { *outSize = len - 1; @@ -455,23 +370,15 @@ PalResult win32GetWindowTitle( WideCharToMultiByte(CP_UTF8, 0, buffer, -1, outBuffer, write + 1, 0, 0); outBuffer[write < len - 1 ? write : len - 1] = '\0'; } - - return PAL_RESULT_SUCCESS; } -PalResult win32GetWindowPos( +void win32GetWindowPos( PalWindow* window, int32_t* x, int32_t* y) { RECT rect; - if (!GetWindowRect((HWND)window, &rect)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - + GetWindowRect((HWND)window, &rect); if (x) { *x = rect.left; } @@ -479,22 +386,15 @@ PalResult win32GetWindowPos( if (y) { *y = rect.top; } - return PAL_RESULT_SUCCESS; } -PalResult win32GetWindowSize( +void win32GetWindowSize( PalWindow* window, uint32_t* width, uint32_t* height) { RECT rect; - if (!GetWindowRect((HWND)window, &rect)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - + GetWindowRect((HWND)window, &rect); if (width) { *width = rect.right - rect.left; } @@ -502,21 +402,14 @@ PalResult win32GetWindowSize( if (height) { *height = rect.bottom - rect.top; } - return PAL_RESULT_SUCCESS; } -PalResult win32GetWindowState( +void win32GetWindowState( PalWindow* window, PalWindowState* outState) { WINDOWPLACEMENT wp = {0}; - if (!GetWindowPlacement((HWND)window, &wp)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - + GetWindowPlacement((HWND)window, &wp); if (wp.showCmd == SW_MINIMIZE) { *outState = PAL_WINDOW_STATE_MINIMIZED; @@ -526,8 +419,6 @@ PalResult win32GetWindowState( } else if (wp.showCmd == SW_RESTORE || wp.showCmd == SW_NORMAL) { *outState = PAL_WINDOW_STATE_RESTORED; } - - return PAL_RESULT_SUCCESS; } PalBool win32IsWindowVisible(PalWindow* window) @@ -540,7 +431,7 @@ PalWindow* win32GetFocusWindow() return (PalWindow*)GetFocus(); } -PalResult win32GetWindowHandleInfo( +void win32GetWindowHandleInfo( PalWindow* window, PalWindowHandleInfo* info) { @@ -549,54 +440,20 @@ PalResult win32GetWindowHandleInfo( info->nativeHandle1 = nullptr; info->nativeHandle2 = nullptr; info->nativeHandle3 = nullptr; - - return PAL_RESULT_SUCCESS; } -PalResult win32SetWindowOpacity( +void win32SetWindowOpacity( PalWindow* window, float opacity) { - if (opacity < 0.0f) { - opacity = 0.0f; - } - - if (opacity > 1.0f) { - opacity = 1.0f; - } - - PalBool ret = SetLayeredWindowAttributes((HWND)window, 0, (BYTE)(opacity * 255), LWA_ALPHA); - if (!ret) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else if (error == ERROR_INVALID_PARAMETER) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } - - return PAL_RESULT_SUCCESS; + SetLayeredWindowAttributes((HWND)window, 0, (BYTE)(opacity * 255), LWA_ALPHA); } -PalResult win32SetWindowStyle( +void win32SetWindowStyle( PalWindow* window, PalWindowStyle style) { - // convert our style to win32 styles and exStyles - // all windows have this styles + // convert our style to win32 styles and exStyles all windows have this styles DWORD win32Style = WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED; DWORD exStyle = 0; @@ -642,7 +499,7 @@ PalResult win32SetWindowStyle( SetWindowLongPtrW(hwnd, GWL_EXSTYLE, exStyle); // force a frame update - PalBool success = SetWindowPos( + SetWindowPos( hwnd, nullptr, 0, @@ -650,50 +507,23 @@ PalResult win32SetWindowStyle( 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED); - - if (success) { - return PAL_RESULT_SUCCESS; - - } else { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } } -PalResult win32SetWindowTitle( +void win32SetWindowTitle( PalWindow* window, const char* title) { wchar_t buffer[WINDOW_NAME_SIZE]; MultiByteToWideChar(CP_UTF8, 0, title, -1, buffer, 256); - - if (!SetWindowTextW((HWND)window, buffer)) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - GetLastError()); - } - - return PAL_RESULT_SUCCESS; + SetWindowTextW((HWND)window, buffer); } -PalResult win32SetWindowPos( +void win32SetWindowPos( PalWindow* window, int32_t x, int32_t y) { - PalBool success = SetWindowPos( + SetWindowPos( (HWND)window, nullptr, x, @@ -701,87 +531,26 @@ PalResult win32SetWindowPos( 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); - - if (!success) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } - return PAL_RESULT_SUCCESS; } -PalResult win32SetWindowSize( +void win32SetWindowSize( PalWindow* window, uint32_t width, uint32_t height) { - PalBool success = SetWindowPos( + SetWindowPos( (HWND)window, HWND_TOP, 0, 0, width, height, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); - - if (!success) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else if (error == ERROR_INVALID_PARAMETER) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } - return PAL_RESULT_SUCCESS; + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); } -PalResult win32SetFocusWindow(PalWindow* window) +void win32SetFocusWindow(PalWindow* window) { - if (!SetActiveWindow((HWND)window)) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); - - } else if (error == ERROR_ACCESS_DENIED) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_OPERATION, - PAL_RESULT_SOURCE_WIN32, - error); - - } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); - } - } - return PAL_RESULT_SUCCESS; + SetActiveWindow((HWND)window); } PalResult win32AttachWindow( From 5d163be57381a5d836cedc7097f4203cbba0b691 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 11 Jul 2026 13:46:01 +0000 Subject: [PATCH 333/372] change manual message polling to callback d3d12 --- include/pal/pal_graphics.h | 4 +- src/graphics/d3d12/pal_adapter_d3d12.c | 7 +- src/graphics/d3d12/pal_as_d3d12.c | 3 - src/graphics/d3d12/pal_buffer_d3d12.c | 4 - src/graphics/d3d12/pal_command_pool_d3d12.c | 14 --- src/graphics/d3d12/pal_commands_d3d12.c | 3 - src/graphics/d3d12/pal_d3d12.c | 85 +---------------- src/graphics/d3d12/pal_d3d12.h | 23 ++--- src/graphics/d3d12/pal_descriptors_d3d12.c | 1 - src/graphics/d3d12/pal_device_d3d12.c | 100 ++++++++++++++++++-- src/graphics/d3d12/pal_image_d3d12.c | 1 - src/graphics/d3d12/pal_pipeline_d3d12.c | 7 -- src/graphics/d3d12/pal_sbt_d3d12.c | 1 - src/graphics/d3d12/pal_swapchain_d3d12.c | 8 -- src/graphics/d3d12/pal_sync_d3d12.c | 2 - 15 files changed, 110 insertions(+), 153 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 99404bf2..814eef8b 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3964,8 +3964,8 @@ typedef struct { * @brief Initialize the graphics system. * * The debugger, allocator and custom backends will not not copied, therefore the pointers must - * remain valid until the graphics system is shutdown. Set the debugger or - * PalGraphicsDebugger::callback to `nullptr` to disable debugging and validation layers. + * remain valid until the graphics system is shutdown. Set the debugger to `nullptr` to disable + * debugging and validation layers. * * If `debugger` is not `nullptr` and there is no debug layers, this function will not fail but * debugging will be disabled. diff --git a/src/graphics/d3d12/pal_adapter_d3d12.c b/src/graphics/d3d12/pal_adapter_d3d12.c index 1d21b66d..fb5cd92c 100644 --- a/src/graphics/d3d12/pal_adapter_d3d12.c +++ b/src/graphics/d3d12/pal_adapter_d3d12.c @@ -26,7 +26,7 @@ #define D3D_SHADER_MODEL_6_10 0x6a #endif // D3D_SHADER_MODEL_6_10 -static PalImageUsages ImageUsageFromD3D12(D3D12_FORMAT_SUPPORT1 flags) +static PalImageUsages imageUsageFromD3D12(D3D12_FORMAT_SUPPORT1 flags) { PalImageUsages usages = 0; if (flags & D3D12_FORMAT_SUPPORT1_RENDER_TARGET) { @@ -110,7 +110,6 @@ PalResult PAL_CALL enumerateAdaptersD3D12( tmp->handle = dxAdapters[i]; tmp->tmpDevice = devices[i]; tmp->level = deviceLevels[i]; - tmp->reserved = PAL_BACKEND_KEY; outAdapters[i] = (PalAdapter*)tmp; } s_D3D12.adapterCount = *count; @@ -497,7 +496,7 @@ void PAL_CALL enumerateFormatsD3D12( if (fmtCount < *count) { PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; fmtInfo->format = (PalFormat)i; - fmtInfo->usages = ImageUsageFromD3D12(support.Support1); + fmtInfo->usages = imageUsageFromD3D12(support.Support1); } } else { @@ -566,7 +565,7 @@ PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( return 0; } - PalImageUsages usages = ImageUsageFromD3D12(support.Support1); + PalImageUsages usages = imageUsageFromD3D12(support.Support1); if (support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE || support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD) { usages |= PAL_IMAGE_USAGE_STORAGE; diff --git a/src/graphics/d3d12/pal_as_d3d12.c b/src/graphics/d3d12/pal_as_d3d12.c index e6431cf4..c4241f2e 100644 --- a/src/graphics/d3d12/pal_as_d3d12.c +++ b/src/graphics/d3d12/pal_as_d3d12.c @@ -17,7 +17,6 @@ PalResult PAL_CALL createAccelerationstructureD3D12( AccelerationStructureD3D12* as = nullptr; DeviceD3D12* d3d12Device = (DeviceD3D12*)device; BufferD3D12* d3d12Buffer = (BufferD3D12*)info->buffer; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } @@ -31,8 +30,6 @@ PalResult PAL_CALL createAccelerationstructureD3D12( as->handle = d3d12Buffer->handle; as->address = as->handle->lpVtbl->GetGPUVirtualAddress(as->handle); as->address += info->offset; - - as->reserved = PAL_BACKEND_KEY; *outAs = (PalAccelerationStructure*)as; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/d3d12/pal_buffer_d3d12.c b/src/graphics/d3d12/pal_buffer_d3d12.c index 2acbe370..385694de 100644 --- a/src/graphics/d3d12/pal_buffer_d3d12.c +++ b/src/graphics/d3d12/pal_buffer_d3d12.c @@ -53,7 +53,6 @@ PalResult PAL_CALL createBufferD3D12( HRESULT result; BufferD3D12* buffer = nullptr; DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; @@ -145,7 +144,6 @@ PalResult PAL_CALL createBufferD3D12( buffer->usages = info->usages; buffer->device = d3d12Device; buffer->size = info->size; - buffer->reserved = PAL_BACKEND_KEY; *outBuffer = (PalBuffer*)buffer; return PAL_RESULT_SUCCESS; } @@ -310,7 +308,6 @@ PalResult PAL_CALL bindBufferMemoryD3D12( (void**)&d3d12Buffer->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Buffer->device); return makeResultD3D12(result); } @@ -328,7 +325,6 @@ PalResult PAL_CALL mapBufferD3D12( void* ptr = nullptr; HRESULT result = d3d12Buffer->handle->lpVtbl->Map(d3d12Buffer->handle, 0, nullptr, &ptr); if (FAILED(result)) { - pollMessagesD3D12(d3d12Buffer->device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_command_pool_d3d12.c b/src/graphics/d3d12/pal_command_pool_d3d12.c index 15a22e73..35eb9149 100644 --- a/src/graphics/d3d12/pal_command_pool_d3d12.c +++ b/src/graphics/d3d12/pal_command_pool_d3d12.c @@ -169,7 +169,6 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdBuffer->allocator); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -185,7 +184,6 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdList); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -282,7 +280,6 @@ PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; result = d3d12CmdBuffer->allocator->lpVtbl->Reset(d3d12CmdBuffer->allocator); if (FAILED(result)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(result); } @@ -292,13 +289,11 @@ PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) nullptr); if (FAILED(result)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(result); } result = d3d12CmdBuffer->handle->lpVtbl->Close(d3d12CmdBuffer->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(result); } @@ -321,20 +316,17 @@ PalResult PAL_CALL submitCommandBufferD3D12( if (semaphore->isTimeline) { ret = queueHandle->lpVtbl->Wait(queueHandle, semaphore->handle, info->waitValue); if (FAILED(ret)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(ret); } } else { queueHandle->lpVtbl->Wait(queueHandle, semaphore->handle, semaphore->value); if (FAILED(ret)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(ret); } semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); if (FAILED(ret)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(ret); } @@ -342,14 +334,11 @@ PalResult PAL_CALL submitCommandBufferD3D12( } } - // pollMessagesD3D12(d3d12CmdBuffer->device); ID3D12CommandList* cmdLists[1] = { (ID3D12CommandList*)d3d12CmdBuffer->handle }; queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, cmdLists); - d3d12Queue->fenceValue++; ret = queueHandle->lpVtbl->Signal(queueHandle, d3d12Queue->fence, d3d12Queue->fenceValue); if (FAILED(ret)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(ret); } @@ -358,7 +347,6 @@ PalResult PAL_CALL submitCommandBufferD3D12( fence->value++; ret = queueHandle->lpVtbl->Signal(queueHandle, fence->handle, fence->value); if (FAILED(ret)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(ret); } } @@ -368,14 +356,12 @@ PalResult PAL_CALL submitCommandBufferD3D12( if (semaphore->isTimeline) { ret = queueHandle->lpVtbl->Signal(queueHandle, semaphore->handle, info->signalValue); if (FAILED(ret)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(ret); } } else { semaphore->value = 1; ret = queueHandle->lpVtbl->Signal(queueHandle, semaphore->handle, semaphore->value); if (FAILED(ret)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(ret); } } diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index 58e3071c..30d90fa1 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -158,7 +158,6 @@ PalResult PAL_CALL cmdBeginD3D12( CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; result = d3d12CmdBuffer->allocator->lpVtbl->Reset(d3d12CmdBuffer->allocator); if (FAILED(result)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(result); } @@ -168,7 +167,6 @@ PalResult PAL_CALL cmdBeginD3D12( nullptr); if (FAILED(result)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(result); } @@ -180,7 +178,6 @@ PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer) CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; HRESULT result = d3d12CmdBuffer->handle->lpVtbl->Close(d3d12CmdBuffer->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_d3d12.c b/src/graphics/d3d12/pal_d3d12.c index cf550c15..83e51b6e 100644 --- a/src/graphics/d3d12/pal_d3d12.c +++ b/src/graphics/d3d12/pal_d3d12.c @@ -14,7 +14,7 @@ IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0x IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0,0x3c, 0x77,0x90,0x0a,0x0a,0x1d,0x17}; IID IID_DebugController = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0}; IID IID_DebugController1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; -IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4,0xe6,0x14,0x58}; +IID IID_InfoQueue1 = {0x2852dd88, 0xb484, 0x4c0c, 0xb6,0xb1, 0x67,0x16,0x85,0x00,0xe6,0x00}; IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3}; IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed}; IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1}; @@ -767,12 +767,10 @@ void fillBuildInfoD3D12( } void fillSubresourceD3D12( + uint32_t descType, PalImageViewType type, const PalImageSubresourceRange* range, - D3D12_RENDER_TARGET_VIEW_DESC* rtvDesc, - D3D12_DEPTH_STENCIL_VIEW_DESC* dsvDesc, - D3D12_SHADER_RESOURCE_VIEW_DESC* srvDesc, - D3D12_UNORDERED_ACCESS_VIEW_DESC* uavDesc) + void* desc) { if (rtvDesc) { if (type == PAL_IMAGE_VIEW_TYPE_1D) { @@ -915,77 +913,6 @@ uint64_t getDescriptorHandleD3D12( return baseOffset + index * size; } -void pollMessagesD3D12(DeviceD3D12* device) -{ - ID3D12InfoQueue* queue = device->infoQueue; - if (!queue) { - return; - } - - UINT64 messageCount = queue->lpVtbl->GetNumStoredMessages(queue); - for (int i = 0; i < messageCount; i++) { - SIZE_T size = 0; - queue->lpVtbl->GetMessage(queue, i, nullptr, &size); - - uint8_t* buffer = palAllocate(s_D3D12.allocator, size, 0); - if (!buffer) { - return; - } - - queue->lpVtbl->GetMessage(queue, i, (D3D12_MESSAGE*)buffer, &size); - const char* message = ((D3D12_MESSAGE*)buffer)->pDescription; - D3D12_MESSAGE_CATEGORY category = ((D3D12_MESSAGE*)buffer)->Category; - D3D12_MESSAGE_SEVERITY severity = ((D3D12_MESSAGE*)buffer)->Severity; - - PalDebugMessageSeverity msgSeverity = 0; - PalDebugMessageType msgType = 0; - switch (category) { - case D3D12_MESSAGE_CATEGORY_INITIALIZATION: - case D3D12_MESSAGE_CATEGORY_CLEANUP: - case D3D12_MESSAGE_CATEGORY_COMPILATION: { - msgType = PAL_DEBUG_MESSAGE_TYPE_GENERAL; - break; - } - - case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: - case D3D12_MESSAGE_CATEGORY_EXECUTION: - case D3D12_MESSAGE_CATEGORY_SHADER: { - msgType = PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE; - break; - } - - case D3D12_MESSAGE_CATEGORY_STATE_CREATION: - case D3D12_MESSAGE_CATEGORY_STATE_GETTING: - case D3D12_MESSAGE_CATEGORY_STATE_SETTING: { - msgType = PAL_DEBUG_MESSAGE_TYPE_VALIDATION; - break; - } - } - - switch (severity) { - case D3D12_MESSAGE_SEVERITY_INFO: { - msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; - break; - } - - case D3D12_MESSAGE_SEVERITY_WARNING: { - msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; - break; - } - - case D3D12_MESSAGE_SEVERITY_ERROR: - case D3D12_MESSAGE_SEVERITY_CORRUPTION: { - msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_ERROR; - break; - } - } - - s_D3D12.debugCallback(s_D3D12.debugUserData, msgSeverity, msgType, message); - palFree(s_D3D12.allocator, buffer); - } - queue->lpVtbl->ClearStoredMessages(queue); -} - void getDescriptorTierLimitsD3D12( void* device, PalResourceCapabilities* caps, @@ -1086,7 +1013,7 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D12.handle, "D3D12SerializeVersionedRootSignature"); - if (debugger && debugger->callback) { + if (debugger) { s_D3D12.getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress( s_D3D12.handle, "D3D12GetDebugInterface"); @@ -1129,10 +1056,6 @@ PalResult PAL_CALL initGraphicsD3D12( } // message severities - if (!debugger->denyInfoSeverity) { - s_D3D12.severities[s_D3D12.severityCount++] = D3D12_MESSAGE_SEVERITY_INFO; - } - if (!debugger->denyWarningSeverity) { s_D3D12.severities[s_D3D12.severityCount++] = D3D12_MESSAGE_SEVERITY_WARNING; } diff --git a/src/graphics/d3d12/pal_d3d12.h b/src/graphics/d3d12/pal_d3d12.h index 9b407c88..d8182c53 100644 --- a/src/graphics/d3d12/pal_d3d12.h +++ b/src/graphics/d3d12/pal_d3d12.h @@ -23,6 +23,11 @@ #define COMPUTE_PIPELINE 1221 #define RAY_TRACING_PIPELINE 1222 +#define DESC_TYPE_RTV 0 +#define DESC_TYPE_DSV 1 +#define DESC_TYPE_SRV 2 +#define DESC_TYPE_UAV 3 + typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( UINT, REFIID, @@ -147,14 +152,14 @@ typedef struct { typedef struct { void* reserved; uint32_t shaderModel; - PalAdapterFeatures features; + DWORD debugCookie; IDXGIAdapter4* adapter; ID3D12CommandSignature* meshSignature; ID3D12CommandSignature* drawIndexedSignature; ID3D12CommandSignature* drawSignature; ID3D12CommandSignature* dispatchSignature; ID3D12CommandSignature* raySignature; - ID3D12InfoQueue* infoQueue; + ID3D12InfoQueue1* infoQueue; ID3D12CommandQueue* queue; ID3D12Device5* handle; RTVHeapAllocator rtvAllocator; @@ -185,7 +190,6 @@ typedef struct { typedef struct { void* reserved; PalBool isMemoryManaged; - DeviceD3D12* device; ID3D12Resource* handle; PalImageInfo info; D3D12_RESOURCE_DESC desc; @@ -197,7 +201,6 @@ typedef struct { PalImageViewType type; DXGI_FORMAT format; ImageD3D12* image; - DeviceD3D12* device; PalImageSubresourceRange range; } ImageViewD3D12; @@ -217,7 +220,6 @@ typedef struct { DXGI_FEATURE presentFlags; SurfaceD3D12* surface; ImageD3D12* images; - DeviceD3D12* device; ID3D12CommandQueue* queue; IDXGISwapChain3* handle; } SwapchainD3D12; @@ -242,7 +244,6 @@ typedef struct { void* reserved; PalBool primary; void* pool; // CommandPool - DeviceD3D12* device; ID3D12Resource* stagingBuffer; ID3D12Resource* buffer; ID3D12CommandAllocator* allocator; @@ -269,7 +270,6 @@ typedef struct { PalBufferUsages usages; uint64_t size; ID3D12Resource* handle; - DeviceD3D12* device; D3D12_RESOURCE_DESC desc; } BufferD3D12; @@ -370,7 +370,6 @@ typedef struct { } D3D12; PalResult makeResultD3D12(HRESULT result); -void pollMessagesD3D12(DeviceD3D12* device); DXGI_FORMAT formatToD3D12(PalFormat format); D3D12_COMPARISON_FUNC compareOpToD3D12(PalCompareOp op); @@ -394,12 +393,10 @@ void getDescriptorTierLimitsD3D12( PalDescriptorIndexingCapabilities* descCaps); void fillSubresourceD3D12( + uint32_t descType, PalImageViewType type, const PalImageSubresourceRange* range, - D3D12_RENDER_TARGET_VIEW_DESC* rtvDesc, - D3D12_DEPTH_STENCIL_VIEW_DESC* dsvDesc, - D3D12_SHADER_RESOURCE_VIEW_DESC* srvDesc, - D3D12_UNORDERED_ACCESS_VIEW_DESC* uavDesc); + void* desc); uint64_t getDescriptorHandleD3D12( uint32_t index, @@ -412,7 +409,7 @@ extern IID IID_Adapter; extern IID IID_Factory; extern IID IID_DebugController; extern IID IID_DebugController1; -extern IID IID_InfoQueue; +extern IID IID_InfoQueue1; extern IID IID_Heap; extern IID IID_Queue; extern IID IID_Swapchain; diff --git a/src/graphics/d3d12/pal_descriptors_d3d12.c b/src/graphics/d3d12/pal_descriptors_d3d12.c index 9b5b3eed..517fd8f4 100644 --- a/src/graphics/d3d12/pal_descriptors_d3d12.c +++ b/src/graphics/d3d12/pal_descriptors_d3d12.c @@ -260,7 +260,6 @@ PalResult PAL_CALL createDescriptorPoolD3D12( (void**)&heap->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c index f6c335a1..f0c92557 100644 --- a/src/graphics/d3d12/pal_device_d3d12.c +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -22,6 +22,54 @@ static void convertToWcharD3D12( dst[i] = L'\0'; } +static void __stdcall debugCallbackD3D12( + D3D12_MESSAGE_CATEGORY category, + D3D12_MESSAGE_SEVERITY severity, + D3D12_MESSAGE_ID id, + const char *description, + void *context) +{ + PalDebugMessageSeverity msgSeverity = 0; + PalDebugMessageType msgType = 0; + switch (category) { + case D3D12_MESSAGE_CATEGORY_INITIALIZATION: + case D3D12_MESSAGE_CATEGORY_CLEANUP: + case D3D12_MESSAGE_CATEGORY_COMPILATION: { + msgType = PAL_DEBUG_MESSAGE_TYPE_GENERAL; + break; + } + + case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: + case D3D12_MESSAGE_CATEGORY_EXECUTION: + case D3D12_MESSAGE_CATEGORY_SHADER: { + msgType = PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE; + break; + } + + case D3D12_MESSAGE_CATEGORY_STATE_CREATION: + case D3D12_MESSAGE_CATEGORY_STATE_GETTING: + case D3D12_MESSAGE_CATEGORY_STATE_SETTING: { + msgType = PAL_DEBUG_MESSAGE_TYPE_VALIDATION; + break; + } + } + + switch (severity) { + case D3D12_MESSAGE_SEVERITY_WARNING: { + msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; + break; + } + + case D3D12_MESSAGE_SEVERITY_ERROR: + case D3D12_MESSAGE_SEVERITY_CORRUPTION: { + msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_ERROR; + break; + } + } + + s_D3D12.debugCallback(s_D3D12.debugUserData, msgSeverity, msgType, description); +} + PalResult PAL_CALL createDeviceD3D12( PalAdapter* adapter, PalAdapterFeatures features, @@ -49,7 +97,6 @@ PalResult PAL_CALL createDeviceD3D12( // get and cache highest shader model device->shaderModel = getHighestSupportedShaderTargetD3D12(adapter, PAL_SHADER_FORMAT_DXIL); - result = s_D3D12.createDevice( (IUnknown*)d3d12Adapter->handle, d3d12Adapter->level, @@ -70,11 +117,47 @@ PalResult PAL_CALL createDeviceD3D12( if (s_D3D12.debugLayer) { result = device->handle->lpVtbl->QueryInterface( device->handle, - &IID_InfoQueue, + &IID_InfoQueue1, (void**)&device->infoQueue); if (SUCCEEDED(result)) { - D3D12_MESSAGE_ID denyIDs[] = { D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE }; + D3D12_MESSAGE_ID denyIDs[] = { + D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE, + D3D12_MESSAGE_ID_LIVE_OBJECT_SUMMARY, + D3D12_MESSAGE_ID_LIVE_DEVICE, + D3D12_MESSAGE_ID_LIVE_COMMANDQUEUE, + D3D12_MESSAGE_ID_LIVE_COMMANDALLOCATOR, + D3D12_MESSAGE_ID_LIVE_PIPELINESTATE, + D3D12_MESSAGE_ID_LIVE_COMMANDLIST12, + D3D12_MESSAGE_ID_LIVE_RESOURCE, + D3D12_MESSAGE_ID_LIVE_DESCRIPTORHEAP, + D3D12_MESSAGE_ID_LIVE_ROOTSIGNATURE, + D3D12_MESSAGE_ID_LIVE_LIBRARY, + D3D12_MESSAGE_ID_LIVE_HEAP, + D3D12_MESSAGE_ID_LIVE_MONITOREDFENCE, + D3D12_MESSAGE_ID_LIVE_QUERYHEAP, + D3D12_MESSAGE_ID_LIVE_COMMANDSIGNATURE, + D3D12_MESSAGE_ID_LIVE_COMMANDPOOL, + D3D12_MESSAGE_ID_LIVE_SWAPCHAIN + }; + + device->infoQueue->lpVtbl->SetBreakOnSeverity( + device->infoQueue, + D3D12_MESSAGE_SEVERITY_ERROR, + TRUE); + + device->infoQueue->lpVtbl->SetBreakOnSeverity( + device->infoQueue, + D3D12_MESSAGE_SEVERITY_CORRUPTION, + TRUE); + + device->infoQueue->lpVtbl->RegisterMessageCallback( + device->infoQueue, + debugCallbackD3D12, + D3D12_MESSAGE_CALLBACK_FLAG_NONE, + nullptr, + &device->debugCookie); + D3D12_INFO_QUEUE_FILTER filter = {0}; filter.AllowList.NumSeverities = s_D3D12.severityCount; filter.AllowList.pSeverityList = s_D3D12.severities; @@ -82,7 +165,6 @@ PalResult PAL_CALL createDeviceD3D12( filter.AllowList.pCategoryList = s_D3D12.categories; filter.DenyList.NumIDs = 1; filter.DenyList.pIDList = denyIDs; - device->infoQueue->lpVtbl->PushStorageFilter(device->infoQueue, &filter); } } @@ -283,8 +365,6 @@ PalResult PAL_CALL createDeviceD3D12( } device->adapter = d3d12Adapter->handle; - device->features = features; - device->reserved = PAL_BACKEND_KEY; *outDevice = (PalDevice*)device; return PAL_RESULT_SUCCESS; } @@ -317,7 +397,12 @@ void PAL_CALL destroyDeviceD3D12(PalDevice* device) d3d12Device->queue->lpVtbl->Release(d3d12Device->queue); d3d12Device->handle->lpVtbl->Release(d3d12Device->handle); + if (d3d12Device->infoQueue) { + d3d12Device->infoQueue->lpVtbl->UnregisterMessageCallback( + d3d12Device->infoQueue, + d3d12Device->debugCookie); + d3d12Device->infoQueue->lpVtbl->Release(d3d12Device->infoQueue); } @@ -358,7 +443,6 @@ PalResult PAL_CALL allocateMemoryD3D12( (void**)&memory->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -599,7 +683,6 @@ PalResult PAL_CALL createQueueD3D12( (void**)&queue->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); palFree(s_D3D12.allocator, queue); return makeResultD3D12(result); } @@ -613,7 +696,6 @@ PalResult PAL_CALL createQueueD3D12( (void**)&queue->fence); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); palFree(s_D3D12.allocator, queue); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_image_d3d12.c b/src/graphics/d3d12/pal_image_d3d12.c index 4b608af4..7e099de9 100644 --- a/src/graphics/d3d12/pal_image_d3d12.c +++ b/src/graphics/d3d12/pal_image_d3d12.c @@ -276,7 +276,6 @@ PalResult PAL_CALL bindImageMemoryD3D12( (void**)&d3d12Image->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Image->device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_pipeline_d3d12.c b/src/graphics/d3d12/pal_pipeline_d3d12.c index fcc771a3..99c4f6f7 100644 --- a/src/graphics/d3d12/pal_pipeline_d3d12.c +++ b/src/graphics/d3d12/pal_pipeline_d3d12.c @@ -545,7 +545,6 @@ PalResult PAL_CALL createPipelineLayoutD3D12( ID3DBlob* blob = nullptr; HRESULT result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -558,7 +557,6 @@ PalResult PAL_CALL createPipelineLayoutD3D12( (void**)&layout->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -1028,7 +1026,6 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( &pipeline->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -1077,7 +1074,6 @@ PalResult PAL_CALL createComputePipelineD3D12( &pipeline->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -1375,7 +1371,6 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( ID3DBlob* blob = nullptr; result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -1388,7 +1383,6 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( (void**)&pipeline->localRootSignature); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -1419,7 +1413,6 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( &pipeline->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_sbt_d3d12.c b/src/graphics/d3d12/pal_sbt_d3d12.c index 9d8b95e0..d7fdc821 100644 --- a/src/graphics/d3d12/pal_sbt_d3d12.c +++ b/src/graphics/d3d12/pal_sbt_d3d12.c @@ -75,7 +75,6 @@ PalResult PAL_CALL createShaderBindingTableD3D12( ID3D12StateObjectProperties* props = NULL; result = handle->lpVtbl->QueryInterface(handle, &IID_StateObjectProps, (void**)&props); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_swapchain_d3d12.c b/src/graphics/d3d12/pal_swapchain_d3d12.c index e3e768b3..ac891bb9 100644 --- a/src/graphics/d3d12/pal_swapchain_d3d12.c +++ b/src/graphics/d3d12/pal_swapchain_d3d12.c @@ -79,7 +79,6 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( &swapchain1); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -261,7 +260,6 @@ PalResult PAL_CALL createSwapchainD3D12( &swapchain1); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -354,7 +352,6 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( fence->value++; result = queue->lpVtbl->Signal(queue, fence->handle, fence->value); if (FAILED(result)) { - pollMessagesD3D12(d3dSwapchain->device); return makeResultD3D12(result); } } @@ -364,7 +361,6 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( semaphore->value = 1; result = queue->lpVtbl->Signal(queue, semaphore->handle, semaphore->value); if (FAILED(result)) { - pollMessagesD3D12(d3dSwapchain->device); return makeResultD3D12(result); } } @@ -386,14 +382,12 @@ PalResult PAL_CALL presentSwapchainD3D12( SemaphoreD3D12* semaphore = (SemaphoreD3D12*)waitSemaphore; result = queue->lpVtbl->Wait(queue, semaphore->handle, semaphore->value); if (FAILED(result)) { - pollMessagesD3D12(d3dSwapchain->device); return makeResultD3D12(result); } semaphore->value = 0; result = semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); if (FAILED(result)) { - pollMessagesD3D12(d3dSwapchain->device); return makeResultD3D12(result); } } @@ -404,7 +398,6 @@ PalResult PAL_CALL presentSwapchainD3D12( d3dSwapchain->presentFlags); if (FAILED(result)) { - pollMessagesD3D12(d3dSwapchain->device); if (result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET) { return makeResultD3D12(result); } @@ -448,7 +441,6 @@ PalResult PAL_CALL resizeSwapchainD3D12( d3dSwapchain->flags); if (FAILED(result)) { - pollMessagesD3D12(d3dSwapchain->device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_sync_d3d12.c b/src/graphics/d3d12/pal_sync_d3d12.c index d6652eb0..dddb29c4 100644 --- a/src/graphics/d3d12/pal_sync_d3d12.c +++ b/src/graphics/d3d12/pal_sync_d3d12.c @@ -30,7 +30,6 @@ PalResult PAL_CALL createFenceD3D12( (void**)&fence->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); palFree(s_D3D12.allocator, fence); return makeResultD3D12(result); } @@ -154,7 +153,6 @@ PalResult PAL_CALL createSemaphoreD3D12( (void**)&semaphore->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); palFree(s_D3D12.allocator, semaphore); return makeResultD3D12(result); } From 11e3a2e97b94726c3ea67a8b8ce20b95a2c27bc0 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 11 Jul 2026 15:10:37 +0000 Subject: [PATCH 334/372] start d3d12 backend fix with API changes --- CHANGELOG.md | 1 + include/pal/pal_core.h | 3 +- include/pal/pal_graphics.h | 22 +- src/core/pal_result.h | 6 + src/graphics/d3d12/pal_as_d3d12.c | 5 +- src/graphics/d3d12/pal_buffer_d3d12.c | 58 +--- src/graphics/d3d12/pal_command_pool_d3d12.c | 97 +++--- src/graphics/d3d12/pal_commands_d3d12.c | 351 +++----------------- src/graphics/d3d12/pal_d3d12.c | 19 +- src/graphics/d3d12/pal_d3d12.h | 6 + src/graphics/d3d12/pal_descriptors_d3d12.c | 73 +--- src/graphics/d3d12/pal_device_d3d12.c | 110 +----- src/graphics/d3d12/pal_image_d3d12.c | 40 +-- src/graphics/d3d12/pal_pipeline_d3d12.c | 8 - src/graphics/d3d12/pal_sbt_d3d12.c | 25 +- src/graphics/d3d12/pal_swapchain_d3d12.c | 38 +-- src/graphics/d3d12/pal_sync_d3d12.c | 37 +-- src/graphics/pal_graphics.c | 10 +- src/graphics/pal_graphics_backends.h | 25 +- src/graphics/vulkan/pal_sync_vulkan.c | 4 +- 20 files changed, 194 insertions(+), 744 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c61143a8..4f5b7e8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - `PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED` - `PAL_RESULT_CODE_INVALID_OPERATION` - `PAL_RESULT_CODE_DEVICE_LOST` + - `PAL_RESULT_CODE_OUT_OF_DATE` - Added type `PalResultSource` with values: - `PAL_RESULT_SOURCE_NONE` - `PAL_RESULT_SOURCE_WIN32` diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index ab1ee711..dcb7ba14 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -68,7 +68,8 @@ #define PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED 6 #define PAL_RESULT_CODE_INVALID_OPERATION 7 #define PAL_RESULT_CODE_DEVICE_LOST 8 -#define PAL_RESULT_CODE_COUNT 9 +#define PAL_RESULT_CODE_OUT_OF_DATE 9 +#define PAL_RESULT_CODE_COUNT 10 #define PAL_RESULT_SOURCE_NONE 0 #define PAL_RESULT_SOURCE_WIN32 1 diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 814eef8b..bb64f2aa 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3197,9 +3197,7 @@ typedef struct { * * Must obey the rules and semantics documented in palGetSemaphoreValue(). */ - PalResult(PAL_CALL* getSemaphoreValue)( - PalSemaphore* semaphore, - uint64_t* outValue); + uint64_t(PAL_CALL* getSemaphoreValue)(PalSemaphore* semaphore); /** * Backend implementation of ::palCreateCommandPool. @@ -3756,7 +3754,7 @@ typedef struct { PalDevice* device, PalFormat imageFormat, const PalBufferImageCopyInfo* copyInfo, - PalImageStagingRequirements* outRequirements); + PalImageStagingRequirements* requirements); /** * Backend implementation of ::palWriteInstanceStaging. @@ -5142,13 +5140,11 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * @brief Get the value of a semaphore. * * The graphics system must be initialized before this call. - The provided semaphore must be a timeline semaphore. Otherwise undefined behavior. + * The provided semaphore must be a timeline semaphore. Otherwise undefined behavior. * * @param[in] semaphore Semaphore to get its value. - * @param[out] outValue Pointer to a uint64_t to receive the semaphore value. * - * @return `PAL_RESULT_SUCCESS` on success or a result code on - * failure. Call palFormatResult() for more information. + * @return the timeline value. * * Thread safety: Thread safe if `semaphore` is externally synchronized. * @@ -5156,9 +5152,7 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * @sa palWaitSemaphore * @sa palSignalSemaphore */ -PAL_API PalResult PAL_CALL palGetSemaphoreValue( - PalSemaphore* semaphore, - uint64_t* outValue); +PAL_API uint64_t PAL_CALL palGetSemaphoreValue(PalSemaphore* semaphore); /** * @brief Create a command pool from a device. @@ -6404,13 +6398,13 @@ PAL_API void PAL_CALL palComputeInstanceStagingSize( * * `PalBufferImageCopyInfo::bufferRowLength` and `PalBufferImageCopyInfo::bufferImageHeight` * are hints. The driver might used it defaults if the requested is not supported. After this call, - * set those values to the required ones from `outRequirements`. + * set those values to the required ones from `requirements`. * If the driver supports the proivded, the values will be the same. * * @param[in] device The device to use. * @param[in] imageFormat Destination image format. * @param[in] copyInfo Pointer to a PalBufferImageCopyInfo struct that specifies parameters. - * @param[out] outRequirements Pointer to a PalImageStagingRequirements to recieve the requirements + * @param[out] requirements Pointer to a PalImageStagingRequirements to recieve the requirements * * Thread safety: Thread safe. * @@ -6421,7 +6415,7 @@ PAL_API void PAL_CALL palComputeImageStagingRequirements( PalDevice* device, PalFormat imageFormat, const PalBufferImageCopyInfo* copyInfo, - PalImageStagingRequirements* outRequirements); + PalImageStagingRequirements* requirements); /** * @brief Write data to an instance staging buffer. diff --git a/src/core/pal_result.h b/src/core/pal_result.h index 52605aca..3c896e80 100644 --- a/src/core/pal_result.h +++ b/src/core/pal_result.h @@ -37,6 +37,9 @@ static const char* resultCodeToString(PalResult result) case PAL_RESULT_CODE_DEVICE_LOST: return "PAL_RESULT_CODE_DEVICE_LOST"; + + case PAL_RESULT_CODE_OUT_OF_DATE: + return "PAL_RESULT_CODE_OUT_OF_DATE"; } return ""; @@ -69,6 +72,9 @@ static const char* resultCodeToDescription(PalResult result) case PAL_RESULT_CODE_DEVICE_LOST: return "Device lost"; + + case PAL_RESULT_CODE_OUT_OF_DATE: + return "Out of date"; } return nullptr; diff --git a/src/graphics/d3d12/pal_as_d3d12.c b/src/graphics/d3d12/pal_as_d3d12.c index c4241f2e..09348d62 100644 --- a/src/graphics/d3d12/pal_as_d3d12.c +++ b/src/graphics/d3d12/pal_as_d3d12.c @@ -17,10 +17,7 @@ PalResult PAL_CALL createAccelerationstructureD3D12( AccelerationStructureD3D12* as = nullptr; DeviceD3D12* d3d12Device = (DeviceD3D12*)device; BufferD3D12* d3d12Buffer = (BufferD3D12*)info->buffer; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - + as = palAllocate(s_D3D12.allocator, sizeof(AccelerationStructureD3D12), 0); if (!as) { return PAL_RESULT_CODE_OUT_OF_MEMORY; diff --git a/src/graphics/d3d12/pal_buffer_d3d12.c b/src/graphics/d3d12/pal_buffer_d3d12.c index 385694de..f3128696 100644 --- a/src/graphics/d3d12/pal_buffer_d3d12.c +++ b/src/graphics/d3d12/pal_buffer_d3d12.c @@ -53,17 +53,7 @@ PalResult PAL_CALL createBufferD3D12( HRESULT result; BufferD3D12* buffer = nullptr; DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - } - + buffer = palAllocate(s_D3D12.allocator, sizeof(BufferD3D12), 0); if (!buffer) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -142,7 +132,6 @@ PalResult PAL_CALL createBufferD3D12( } buffer->usages = info->usages; - buffer->device = d3d12Device; buffer->size = info->size; *outBuffer = (PalBuffer*)buffer; return PAL_RESULT_SUCCESS; @@ -157,12 +146,12 @@ void PAL_CALL destroyBufferD3D12(PalBuffer* buffer) palFree(s_D3D12.allocator, d3d12Buffer); } -PalResult PAL_CALL getBufferMemoryRequirementsD3D12( +void PAL_CALL getBufferMemoryRequirementsD3D12( PalBuffer* buffer, PalMemoryRequirements* requirements) { BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - ID3D12Device5* device = d3d12Buffer->device->handle; + ID3D12Device5* device = d3d12Buffer->device; D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; @@ -176,47 +165,41 @@ PalResult PAL_CALL getBufferMemoryRequirementsD3D12( requirements->supportedMemoryTypes = getSupportedMemoryTypes(d3d12Buffer->usages); requirements->alignment = allocationInfo.Alignment; requirements->size = allocationInfo.SizeInBytes; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL computeInstanceBufferRequirementsD3D12( +void PAL_CALL computeInstanceStagingSizeD3D12( PalDevice* device, uint32_t instanceCount, uint64_t* outSize) { *outSize = sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * instanceCount; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsD3D12( +void PAL_CALL computeImageStagingRequirementsD3D12( PalDevice* device, PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize) + const PalBufferImageCopyInfo* copyInfo, + PalImageStagingRequirements* requirements) { uint32_t imageFormatSize = getFormatSizeD3D12(imageFormat); uint32_t rowPitch = align((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); uint32_t bufferImageHeight = 0; - if (copyInfo->bufferImageHeight) { bufferImageHeight = copyInfo->bufferImageHeight; } else { bufferImageHeight = copyInfo->imageHeight; } - *outBufferRowLength = rowPitch; - *outBufferImageHeight = bufferImageHeight; - *outSize = (uint64_t)rowPitch * bufferImageHeight * copyInfo->imageDepth; - return PAL_RESULT_SUCCESS; + requirements->bufferRowLength = rowPitch; + requirements->bufferImageHeight = bufferImageHeight; + requirements->bufferSize = (uint64_t)rowPitch * bufferImageHeight * copyInfo->imageDepth; } -PalResult PAL_CALL writeToInstanceBufferD3D12( +void PAL_CALL writeInstanceStagingD3D12( PalDevice* device, - void* ptr, + uint32_t instanceCount, PalAccelerationStructureInstance* instances, - uint32_t instanceCount) + void* ptr) { D3D12_RAYTRACING_INSTANCE_DESC* data = ptr; for (int i = 0; i < instanceCount; i++) { @@ -231,15 +214,14 @@ PalResult PAL_CALL writeToInstanceBufferD3D12( dst->Flags = instanceFlagsToD3D12(src->flags); memcpy(dst->Transform, src->transform, sizeof(float) * 12); } - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( +void PAL_CALL writeImageStagingD3D12( PalDevice* device, - void* ptr, - void* srcData, PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo) + PalBufferImageCopyInfo* copyInfo, + void* srcData, + void* ptr) { uint32_t imageFormatSize = getFormatSizeD3D12(imageFormat); uint32_t srcRowPitch = copyInfo->imageWidth * imageFormatSize; @@ -259,8 +241,6 @@ PalResult PAL_CALL writeToImageCopyStagingBufferD3D12( srcRowPitch); } } - - return PAL_RESULT_SUCCESS; } PalResult PAL_CALL bindBufferMemoryD3D12( @@ -270,9 +250,8 @@ PalResult PAL_CALL bindBufferMemoryD3D12( { HRESULT result; BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - ID3D12Device5* device = d3d12Buffer->device->handle; + ID3D12Device5* device = d3d12Buffer->device; MemoryD3D12* d3d12Memory = (MemoryD3D12*)memory; - if (d3d12Buffer->isMemoryManaged) { return PAL_RESULT_CODE_INVALID_OPERATION; } @@ -320,7 +299,6 @@ PalResult PAL_CALL mapBufferD3D12( uint64_t size, void** outPtr) { - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; void* ptr = nullptr; HRESULT result = d3d12Buffer->handle->lpVtbl->Map(d3d12Buffer->handle, 0, nullptr, &ptr); diff --git a/src/graphics/d3d12/pal_command_pool_d3d12.c b/src/graphics/d3d12/pal_command_pool_d3d12.c index 35eb9149..2fc61161 100644 --- a/src/graphics/d3d12/pal_command_pool_d3d12.c +++ b/src/graphics/d3d12/pal_command_pool_d3d12.c @@ -91,7 +91,6 @@ PalResult PAL_CALL createCommandPoolD3D12( } } - pool->reserved = PAL_BACKEND_KEY; *outPool = (PalCommandPool*)pool; return PAL_RESULT_SUCCESS; } @@ -187,51 +186,49 @@ PalResult PAL_CALL allocateCommandBufferD3D12( return makeResultD3D12(result); } - // we need a tmp staging and gpu buffer if ray tracing is enabled - if (d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - D3D12_HEAP_PROPERTIES heapProps = {0}; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.VisibleNodeMask = 1; - heapProps.CreationNodeMask = 1; - - D3D12_RESOURCE_DESC bufferDesc = {0}; - bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - bufferDesc.Width = sizeof(D3D12_DISPATCH_RAYS_DESC); - bufferDesc.Height = 1; - bufferDesc.DepthOrArraySize = 1; - bufferDesc.MipLevels = 1; - bufferDesc.SampleDesc.Count = 1; - bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - - result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, - &heapProps, - 0, - &bufferDesc, - D3D12_RESOURCE_STATE_COMMON, - nullptr, - &IID_Resource, - (void**)&cmdBuffer->buffer); - - if (FAILED(result)) { - return makeResultD3D12(result); - } + // create a tmp gpu buffer + D3D12_HEAP_PROPERTIES heapProps = {0}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.VisibleNodeMask = 1; + heapProps.CreationNodeMask = 1; + + D3D12_RESOURCE_DESC bufferDesc = {0}; + bufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + bufferDesc.Width = sizeof(D3D12_DISPATCH_RAYS_DESC); + bufferDesc.Height = 1; + bufferDesc.DepthOrArraySize = 1; + bufferDesc.MipLevels = 1; + bufferDesc.SampleDesc.Count = 1; + bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + + result = d3d12Device->handle->lpVtbl->CreateCommittedResource( + d3d12Device->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + &IID_Resource, + (void**)&cmdBuffer->buffer); - // create staging buffer - heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, - &heapProps, - 0, - &bufferDesc, - D3D12_RESOURCE_STATE_GENERIC_READ, - nullptr, - &IID_Resource, - (void**)&cmdBuffer->stagingBuffer); - - if (FAILED(result)) { - return makeResultD3D12(result); - } + if (FAILED(result)) { + return makeResultD3D12(result); + } + + // create staging buffer + heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; + result = d3d12Device->handle->lpVtbl->CreateCommittedResource( + d3d12Device->handle, + &heapProps, + 0, + &bufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + &IID_Resource, + (void**)&cmdBuffer->stagingBuffer); + + if (FAILED(result)) { + return makeResultD3D12(result); } result = cmdList->lpVtbl->QueryInterface( @@ -247,9 +244,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( cmdBuffer->handle->lpVtbl->Close(cmdBuffer->handle); cmdData->cmdBuffer = cmdBuffer; - cmdBuffer->pool = cmdPool; cmdBuffer->device = d3d12Device; - cmdBuffer->reserved = PAL_BACKEND_KEY; + cmdBuffer->pool = cmdPool; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; } @@ -262,11 +258,8 @@ void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) if (data) { d3d12CmdBuffer->handle->lpVtbl->Release(d3d12CmdBuffer->handle); d3d12CmdBuffer->allocator->lpVtbl->Release(d3d12CmdBuffer->allocator); - - if (d3d12CmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - d3d12CmdBuffer->buffer->lpVtbl->Release(d3d12CmdBuffer->buffer); - d3d12CmdBuffer->stagingBuffer->lpVtbl->Release(d3d12CmdBuffer->stagingBuffer); - } + d3d12CmdBuffer->buffer->lpVtbl->Release(d3d12CmdBuffer->buffer); + d3d12CmdBuffer->stagingBuffer->lpVtbl->Release(d3d12CmdBuffer->stagingBuffer); palFree(s_D3D12.allocator, cmdBuffer); data->cmdBuffer = nullptr; diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index 30d90fa1..50d86cc8 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -184,7 +184,7 @@ PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer) return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdExecuteCommandBufferD3D12( +void PAL_CALL cmdExecuteCommandBufferD3D12( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { @@ -194,21 +194,13 @@ PalResult PAL_CALL cmdExecuteCommandBufferD3D12( d3dPrimaryCmdBuffer->handle->lpVtbl->ExecuteBundle( d3dPrimaryCmdBuffer->handle, (ID3D12GraphicsCommandList*)d3dSecondaryCmdBuffer->handle); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( +void PAL_CALL cmdSetFragmentShadingRateD3D12( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { - HRESULT result; - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; D3D12_SHADING_RATE shadingRate = shadingRateToD3D12(state->rate); D3D12_SHADING_RATE_COMBINER combinerOps[2]; for (int i = 0; i < 2; i++) { @@ -219,32 +211,23 @@ PalResult PAL_CALL cmdSetFragmentShadingRateD3D12( d3d12CmdBuffer->handle, shadingRate, combinerOps); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawMeshTasksD3D12( +void PAL_CALL cmdDrawMeshTasksD3D12( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - d3d12CmdBuffer->handle->lpVtbl->DispatchMesh( d3d12CmdBuffer->handle, groupCountX, groupCountY, groupCountZ); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( +void PAL_CALL cmdDrawMeshTasksIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t drawCount) @@ -252,14 +235,7 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; DeviceD3D12* device = d3d12CmdBuffer->device; BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } - d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( d3d12CmdBuffer->handle, device->meshSignature, @@ -268,11 +244,9 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectD3D12( 0, nullptr, 0); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( +void PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -280,19 +254,8 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; DeviceD3D12* device = d3d12CmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } - BufferD3D12* d3d12CountBuffer = (BufferD3D12*)countBuffer; - if (!(d3d12CountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( d3d12CmdBuffer->handle, @@ -302,20 +265,14 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( 0, d3d12CountBuffer->handle, 0); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( +void PAL_CALL cmdBuildAccelerationStructureD3D12( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { + // TODO: use a temp or arena buffer CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; @@ -330,7 +287,6 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count); fillBuildInfoD3D12(PAL_FALSE, info, geometries, &buildInfo); - d3d12CmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( d3d12CmdBuffer->handle, &buildInfo, @@ -341,18 +297,15 @@ PalResult PAL_CALL cmdBuildAccelerationStructureD3D12( } else { fillBuildInfoD3D12(PAL_FALSE, info, nullptr, &buildInfo); - d3d12CmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( d3d12CmdBuffer->handle, &buildInfo, 0, nullptr); } - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBeginRenderingD3D12( +void PAL_CALL cmdBeginRenderingD3D12( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { @@ -510,18 +463,15 @@ PalResult PAL_CALL cmdBeginRenderingD3D12( colorAttachments, tmpDesc, flags); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer) +void PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; d3d12CmdBuffer->handle->lpVtbl->EndRenderPass(d3d12CmdBuffer->handle); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdCopyBufferD3D12( +void PAL_CALL cmdCopyBufferD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -530,7 +480,6 @@ PalResult PAL_CALL cmdCopyBufferD3D12( CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; BufferD3D12* dstbuffer = (BufferD3D12*)dst; BufferD3D12* srcBuffer = (BufferD3D12*)src; - d3d12CmdBuffer->handle->lpVtbl->CopyBufferRegion( d3d12CmdBuffer->handle, dstbuffer->handle, @@ -538,11 +487,9 @@ PalResult PAL_CALL cmdCopyBufferD3D12( srcBuffer->handle, copyInfo->srcOffset, copyInfo->size); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdCopyBufferToImageD3D12( +void PAL_CALL cmdCopyBufferToImageD3D12( PalCommandBuffer* cmdBuffer, PalImage* dstImage, PalBuffer* srcBuffer, @@ -602,11 +549,9 @@ PalResult PAL_CALL cmdCopyBufferToImageD3D12( &box); } } - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdCopyImageD3D12( +void PAL_CALL cmdCopyImageD3D12( PalCommandBuffer* cmdBuffer, PalImage* dst, PalImage* src, @@ -668,11 +613,9 @@ PalResult PAL_CALL cmdCopyImageD3D12( &box); } } - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdCopyImageToBufferD3D12( +void PAL_CALL cmdCopyImageToBufferD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, @@ -734,17 +677,14 @@ PalResult PAL_CALL cmdCopyImageToBufferD3D12( &box); } } - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBindPipelineD3D12( +void PAL_CALL cmdBindPipelineD3D12( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; PipelineD3D12* d3dPipeline = (PipelineD3D12*)pipeline; - if (d3dPipeline->type == RAY_TRACING_PIPELINE) { d3d12CmdBuffer->handle->lpVtbl->SetPipelineState1( d3d12CmdBuffer->handle, @@ -782,28 +722,15 @@ PalResult PAL_CALL cmdBindPipelineD3D12( } d3d12CmdBuffer->pipeline = d3dPipeline; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetViewportD3D12( +void PAL_CALL cmdSetViewportD3D12( PalCommandBuffer* cmdBuffer, uint32_t count, PalViewport* viewports) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - D3D12_VIEWPORT cachedViewport; - D3D12_VIEWPORT* d3dViewports = nullptr; - - if (count > 1) { - d3dViewports = palAllocate(s_D3D12.allocator, sizeof(D3D12_VIEWPORT) * count, 0); - if (!d3dViewports) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } - - } else { - d3dViewports = &cachedViewport; - } - + D3D12_VIEWPORT d3dViewports[D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; for (int i = 0; i < count; i++) { D3D12_VIEWPORT* tmp = &d3dViewports[i]; tmp->TopLeftX = viewports[i].x; @@ -815,31 +742,15 @@ PalResult PAL_CALL cmdSetViewportD3D12( } d3d12CmdBuffer->handle->lpVtbl->RSSetViewports(d3d12CmdBuffer->handle, count, d3dViewports); - if (count > 1) { - palFree(s_D3D12.allocator, d3dViewports); - } - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetScissorsD3D12( +void PAL_CALL cmdSetScissorsD3D12( PalCommandBuffer* cmdBuffer, uint32_t count, PalRect2D* scissors) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - D3D12_RECT cachedScissor; - D3D12_RECT* d3dScissors = nullptr; - - if (count > 1) { - d3dScissors = palAllocate(s_D3D12.allocator, sizeof(D3D12_RECT) * count, 0); - if (!d3dScissors) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } - - } else { - d3dScissors = &cachedScissor; - } - + D3D12_RECT d3dScissors[D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; for (int i = 0; i < count; i++) { D3D12_RECT* tmp = &d3dScissors[i]; tmp->left = scissors[i].x; @@ -849,38 +760,19 @@ PalResult PAL_CALL cmdSetScissorsD3D12( } d3d12CmdBuffer->handle->lpVtbl->RSSetScissorRects(d3d12CmdBuffer->handle, count, d3dScissors); - if (count > 1) { - palFree(s_D3D12.allocator, d3dScissors); - } - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBindVertexBuffersD3D12( +void PAL_CALL cmdBindVertexBuffersD3D12( PalCommandBuffer* cmdBuffer, uint32_t firstSlot, uint32_t count, PalBuffer** buffers, uint64_t* offsets) { + // TODO: use a temp or arena buffer CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; PipelineD3D12* pipeline = d3d12CmdBuffer->pipeline; - D3D12_VERTEX_BUFFER_VIEW cachedView = {0}; D3D12_VERTEX_BUFFER_VIEW* views = nullptr; - - if (!pipeline) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } - - if (count > 1) { - views = palAllocate(s_D3D12.allocator, sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, 0); - if (!views) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } - - } else { - views = &cachedView; - } - for (int i = 0; i < count; i++) { BufferD3D12* tmp = (BufferD3D12*)buffers[i]; views[i].BufferLocation = tmp->handle->lpVtbl->GetGPUVirtualAddress(tmp->handle); @@ -894,14 +786,9 @@ PalResult PAL_CALL cmdBindVertexBuffersD3D12( firstSlot, count, views); - - if (count > 1) { - palFree(s_D3D12.allocator, views); - } - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBindIndexBufferD3D12( +void PAL_CALL cmdBindIndexBufferD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint64_t offset, @@ -921,10 +808,9 @@ PalResult PAL_CALL cmdBindIndexBufferD3D12( } d3d12CmdBuffer->handle->lpVtbl->IASetIndexBuffer(d3d12CmdBuffer->handle, &view); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawD3D12( +void PAL_CALL cmdDrawD3D12( PalCommandBuffer* cmdBuffer, uint32_t vertexCount, uint32_t instanceCount, @@ -938,11 +824,9 @@ PalResult PAL_CALL cmdDrawD3D12( instanceCount, firstVertex, firstInstance); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawIndirectD3D12( +void PAL_CALL cmdDrawIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count) @@ -950,13 +834,6 @@ PalResult PAL_CALL cmdDrawIndirectD3D12( CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; DeviceD3D12* device = d3d12CmdBuffer->device; BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( d3d12CmdBuffer->handle, @@ -966,11 +843,9 @@ PalResult PAL_CALL cmdDrawIndirectD3D12( 0, nullptr, 0); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawIndirectCountD3D12( +void PAL_CALL cmdDrawIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -978,19 +853,8 @@ PalResult PAL_CALL cmdDrawIndirectCountD3D12( { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; DeviceD3D12* device = d3d12CmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } - BufferD3D12* d3d12CountBuffer = (BufferD3D12*)countBuffer; - if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( d3d12CmdBuffer->handle, @@ -1000,11 +864,9 @@ PalResult PAL_CALL cmdDrawIndirectCountD3D12( 0, d3d12CountBuffer->handle, 0); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawIndexedD3D12( +void PAL_CALL cmdDrawIndexedD3D12( PalCommandBuffer* cmdBuffer, uint32_t indexCount, uint32_t instanceCount, @@ -1020,11 +882,9 @@ PalResult PAL_CALL cmdDrawIndexedD3D12( firstIndex, vertexOffset, firstInstance); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( +void PAL_CALL cmdDrawIndexedIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count) @@ -1032,13 +892,6 @@ PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; DeviceD3D12* device = d3d12CmdBuffer->device; BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( d3d12CmdBuffer->handle, @@ -1048,11 +901,9 @@ PalResult PAL_CALL cmdDrawIndexedIndirectD3D12( 0, nullptr, 0); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( +void PAL_CALL cmdDrawIndexedIndirectCountD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -1060,19 +911,8 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; DeviceD3D12* device = d3d12CmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } - BufferD3D12* d3d12CountBuffer = (BufferD3D12*)countBuffer; - if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( d3d12CmdBuffer->handle, @@ -1082,37 +922,30 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountD3D12( 0, d3d12CountBuffer->handle, 0); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdAccelerationStructureBarrierD3D12( +void PAL_CALL cmdAccelerationStructureBarrierD3D12( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, PalUsageState oldUsageState, PalUsageState newUsageState) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - if (!(d3d12CmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - AccelerationStructureD3D12* d3dAs = (AccelerationStructureD3D12*)as; D3D12_RESOURCE_BARRIER barrier = {0}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.UAV.pResource = d3dAs->handle; - d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdImageBarrierD3D12( +void PAL_CALL cmdImageBarrierD3D12( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, PalUsageState oldUsageState, PalUsageState newUsageState) { + // TODO: use a temp or arena buffer CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; ImageD3D12* d3d12Image = (ImageD3D12*)image; D3D12_RESOURCE_STATES old, new; @@ -1151,9 +984,8 @@ PalResult PAL_CALL cmdImageBarrierD3D12( barrier.Transition.StateBefore = old; barrier.Transition.StateAfter = new; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); - return PAL_RESULT_SUCCESS; + return; } if (layerCount == 1 && layerCount == 1 && planeCount == 1) { @@ -1163,14 +995,13 @@ PalResult PAL_CALL cmdImageBarrierD3D12( barrier.Transition.StateBefore = old; barrier.Transition.StateAfter = new; barrier.Transition.Subresource = startLevel + startLayer * maxLevels; - d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); - return PAL_RESULT_SUCCESS; + return; } barriers = palAllocate(s_D3D12.allocator, sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, 0); if (!barriers) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; + return; } uint32_t count = 0; @@ -1191,10 +1022,9 @@ PalResult PAL_CALL cmdImageBarrierD3D12( d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, barrierCount, barriers); palFree(s_D3D12.allocator, barriers); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBufferBarrierD3D12( +void PAL_CALL cmdBufferBarrierD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalUsageState oldUsageState, @@ -1204,7 +1034,7 @@ PalResult PAL_CALL cmdBufferBarrierD3D12( BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; D3D12_RESOURCE_STATES old, new; if (!d3d12Buffer->canStateChange) { - return PAL_RESULT_SUCCESS; + return; } old = barrierToD3D12(oldUsageState); @@ -1222,10 +1052,9 @@ PalResult PAL_CALL cmdBufferBarrierD3D12( } d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDispatchD3D12( +void PAL_CALL cmdDispatchD3D12( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, @@ -1237,36 +1066,15 @@ PalResult PAL_CALL cmdDispatchD3D12( groupCountX, groupCountY, groupCountZ); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDispatchBaseD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdDispatchIndirectD3D12( +void PAL_CALL cmdDispatchIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } + DeviceD3D12* device = d3d12CmdBuffer->device; d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( d3d12CmdBuffer->handle, @@ -1276,11 +1084,9 @@ PalResult PAL_CALL cmdDispatchIndirectD3D12( 0, nullptr, 0); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdTraceRaysD3D12( +void PAL_CALL cmdTraceRaysD3D12( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, uint32_t raygenIndex, @@ -1290,10 +1096,6 @@ PalResult PAL_CALL cmdTraceRaysD3D12( { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; - if (!(d3d12CmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - uint64_t stride = d3d12Sbt->raygen.region.StrideInBytes; D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; raygenAddress.SizeInBytes = d3d12Sbt->raygen.region.SizeInBytes; @@ -1310,12 +1112,10 @@ PalResult PAL_CALL cmdTraceRaysD3D12( desc.HitGroupTable = d3d12Sbt->hit.region; desc.MissShaderTable = d3d12Sbt->miss.region; desc.CallableShaderTable = d3d12Sbt->callable.region; - d3d12CmdBuffer->handle->lpVtbl->DispatchRays(d3d12CmdBuffer->handle, &desc); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdTraceRaysIndirectD3D12( +void PAL_CALL cmdTraceRaysIndirectD3D12( PalCommandBuffer* cmdBuffer, uint32_t raygenIndex, PalShaderBindingTable* sbt, @@ -1323,19 +1123,11 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( { HRESULT result; CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = d3d12CmdBuffer->device; ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - DeviceD3D12* device = (DeviceD3D12*)d3d12CmdBuffer->device; D3D12_DISPATCH_RAYS_DESC desc = {0}; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(d3d12Buffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } - // we need to make sure the SBT is up to date commitShaderbindingTableUpdateD3D12(d3d12CmdBuffer, d3d12Sbt); @@ -1343,7 +1135,7 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( void* ptr = nullptr; result = d3d12Buffer->handle->lpVtbl->Map(d3d12Buffer->handle, 0, nullptr, &ptr); if (FAILED(result)) { - return PAL_RESULT_CODE_INVALID_OPERATION; + return; } // copy indirect parameters from the buffer @@ -1397,11 +1189,9 @@ PalResult PAL_CALL cmdTraceRaysIndirectD3D12( 0, nullptr, 0); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBindDescriptorSetD3D12( +void PAL_CALL cmdBindDescriptorSetD3D12( PalCommandBuffer* cmdBuffer, uint32_t setIndex, PalDescriptorSet* set) @@ -1478,11 +1268,9 @@ PalResult PAL_CALL cmdBindDescriptorSetD3D12( base); } } - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdPushConstantsD3D12( +void PAL_CALL cmdPushConstantsD3D12( PalCommandBuffer* cmdBuffer, uint32_t offset, uint32_t size, @@ -1490,7 +1278,6 @@ PalResult PAL_CALL cmdPushConstantsD3D12( { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; PipelineD3D12* pipeline = d3d12CmdBuffer->pipeline; - if (pipeline->layout->constantIndex != UINT32_MAX) { if (pipeline->type == GRAPHICS_PIPELINE) { d3d12CmdBuffer->handle->lpVtbl->SetGraphicsRoot32BitConstants( @@ -1510,54 +1297,6 @@ PalResult PAL_CALL cmdPushConstantsD3D12( offset / 4); } } - - return PAL_RESULT_SUCCESS; -} - -PalResult PAL_CALL cmdSetCullModeD3D12( - PalCommandBuffer* cmdBuffer, - PalCullMode cullMode) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdSetFrontFaceD3D12( - PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdSetPrimitiveTopologyD3D12( - PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdSetDepthTestEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdSetDepthWriteEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; -} - -PalResult PAL_CALL cmdSetStencilOpD3D12( - PalCommandBuffer* cmdBuffer, - PalStencilFaceFlags faceMask, - PalStencilOp failOp, - PalStencilOp passOp, - PalStencilOp depthFailOp, - PalCompareOp compareOp) -{ - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_d3d12.c b/src/graphics/d3d12/pal_d3d12.c index 83e51b6e..dbad6eb1 100644 --- a/src/graphics/d3d12/pal_d3d12.c +++ b/src/graphics/d3d12/pal_d3d12.c @@ -772,7 +772,9 @@ void fillSubresourceD3D12( const PalImageSubresourceRange* range, void* desc) { - if (rtvDesc) { + if (descType == DESC_TYPE_RTV) { + D3D12_RENDER_TARGET_VIEW_DESC* rtvDesc = desc; + if (type == PAL_IMAGE_VIEW_TYPE_1D) { rtvDesc->Texture1D.MipSlice = range->startMipLevel; rtvDesc->ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D; @@ -799,9 +801,10 @@ void fillSubresourceD3D12( rtvDesc->Texture3D.WSize = range->layerArrayCount; rtvDesc->ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; } - return; - } else if (dsvDesc) { + } else if (descType == DESC_TYPE_DSV) { + D3D12_DEPTH_STENCIL_VIEW_DESC* dsvDesc = desc; + if (range->aspect == PAL_IMAGE_ASPECT_DEPTH) { dsvDesc->Flags = D3D12_DSV_FLAG_READ_ONLY_DEPTH; } else if (range->aspect == PAL_IMAGE_ASPECT_STENCIL) { @@ -828,9 +831,10 @@ void fillSubresourceD3D12( dsvDesc->Texture2DArray.ArraySize = range->layerArrayCount; dsvDesc->ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY; } - return; - } else if (srvDesc) { + } else if (descType == DESC_TYPE_SRV) { + D3D12_SHADER_RESOURCE_VIEW_DESC* srvDesc = desc; + if (type == PAL_IMAGE_VIEW_TYPE_1D) { srvDesc->Texture1D.MipLevels = range->mipLevelCount; srvDesc->Texture1D.MostDetailedMip = range->startMipLevel; @@ -872,9 +876,10 @@ void fillSubresourceD3D12( srvDesc->TextureCubeArray.NumCubes = range->layerArrayCount; srvDesc->ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; } - return; - } else if (uavDesc) { + } else if (descType == DESC_TYPE_UAV) { + D3D12_UNORDERED_ACCESS_VIEW_DESC* uavDesc = desc; + if (type == PAL_IMAGE_VIEW_TYPE_1D) { uavDesc->Texture1D.MipSlice = range->startMipLevel; uavDesc->ViewDimension = D3D12_UAV_DIMENSION_TEXTURE1D; diff --git a/src/graphics/d3d12/pal_d3d12.h b/src/graphics/d3d12/pal_d3d12.h index d8182c53..0d8bcf8d 100644 --- a/src/graphics/d3d12/pal_d3d12.h +++ b/src/graphics/d3d12/pal_d3d12.h @@ -153,6 +153,7 @@ typedef struct { void* reserved; uint32_t shaderModel; DWORD debugCookie; + PalBool canFenceReset; IDXGIAdapter4* adapter; ID3D12CommandSignature* meshSignature; ID3D12CommandSignature* drawIndexedSignature; @@ -190,6 +191,7 @@ typedef struct { typedef struct { void* reserved; PalBool isMemoryManaged; + ID3D12Device5* device; ID3D12Resource* handle; PalImageInfo info; D3D12_RESOURCE_DESC desc; @@ -201,6 +203,7 @@ typedef struct { PalImageViewType type; DXGI_FORMAT format; ImageD3D12* image; + DeviceD3D12* device; PalImageSubresourceRange range; } ImageViewD3D12; @@ -248,6 +251,7 @@ typedef struct { ID3D12Resource* buffer; ID3D12CommandAllocator* allocator; void* pipeline; + DeviceD3D12* device; ID3D12GraphicsCommandList6* handle; } CommandBufferD3D12; @@ -270,6 +274,7 @@ typedef struct { PalBufferUsages usages; uint64_t size; ID3D12Resource* handle; + ID3D12Device5* device; D3D12_RESOURCE_DESC desc; } BufferD3D12; @@ -304,6 +309,7 @@ typedef struct { typedef struct { void* reserved; + void* stagingPtr; PalBool isDirty; uint32_t stagingBufferSize; uint32_t handleSize; diff --git a/src/graphics/d3d12/pal_descriptors_d3d12.c b/src/graphics/d3d12/pal_descriptors_d3d12.c index 517fd8f4..236f6a02 100644 --- a/src/graphics/d3d12/pal_descriptors_d3d12.c +++ b/src/graphics/d3d12/pal_descriptors_d3d12.c @@ -19,15 +19,6 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( DescriptorSetBinding* bindings = nullptr; uint32_t count = info->bindingCount; - PalBool hasDescriptorIndexing = PAL_FALSE; - if (d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - hasDescriptorIndexing = PAL_TRUE; - } - - if (info->flags != 0 && !hasDescriptorIndexing) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - // partially bound is not supported if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; @@ -163,7 +154,6 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( layout->bindingCount = info->bindingCount; layout->samplerCount = samplerCount; layout->bindings = bindings; - layout->reserved = PAL_BACKEND_KEY; *outLayout = (PalDescriptorSetLayout*)layout; return PAL_RESULT_SUCCESS; } @@ -184,15 +174,6 @@ PalResult PAL_CALL createDescriptorPoolD3D12( DeviceD3D12* d3d12Device = (DeviceD3D12*)device; DescriptorPoolD3D12* pool = nullptr; - PalBool hasDescriptorIndexing = PAL_FALSE; - if (d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - hasDescriptorIndexing = PAL_TRUE; - } - - if (info->flags != 0 && !hasDescriptorIndexing) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - // partially bound is not supported if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; @@ -324,7 +305,6 @@ PalResult PAL_CALL createDescriptorPoolD3D12( pool->flags = info->flags; pool->maxSets = info->maxDescriptorSets; - pool->reserved = PAL_BACKEND_KEY; *outPool = (PalDescriptorPool*)pool; return PAL_RESULT_SUCCESS; } @@ -378,13 +358,6 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( uint32_t sampledImageCount = 0; uint32_t tlasCount = 0; - PalBool isPoolValid = d3d12Pool->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; - PalBool isLayoutValid = d3d12Layout->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; - if (isPoolValid != isLayoutValid) { - // we check if both are true or false - return PAL_RESULT_CODE_INVALID_OPERATION; - } - // get requirements for the sets using the provided layout for (int i = 0; i < d3d12Layout->bindingCount; i++) { DescriptorSetBinding* binding = &d3d12Layout->bindings[i]; @@ -459,7 +432,6 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( limits->usedStorageBuffers += storageBufferCount; limits->usedUniformBuffers += uniformBufferCount; - set->reserved = PAL_BACKEND_KEY; *outSet = (PalDescriptorSet*)set; return PAL_RESULT_SUCCESS; } @@ -504,10 +476,6 @@ PalResult PAL_CALL updateDescriptorSetD3D12( d3d12Device->handle->lpVtbl->CreateSampler(d3d12Device->handle, &sampler->desc, dst); } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - D3D12_SAMPLER_DESC desc = {0}; desc.MaxAnisotropy = 1; desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER; @@ -529,11 +497,6 @@ PalResult PAL_CALL updateDescriptorSetD3D12( AccelerationStructureD3D12* tlas = nullptr; tlas = (AccelerationStructureD3D12*)info->tlasInfos[j].tlas; desc.RaytracingAccelerationStructure.Location = tlas->address; - - } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } } d3d12Device->handle->lpVtbl->CreateShaderResourceView( @@ -558,10 +521,6 @@ PalResult PAL_CALL updateDescriptorSetD3D12( handle = imageView->image->handle; } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; type = PAL_IMAGE_VIEW_TYPE_2D; range.mipLevelCount = 1; @@ -569,14 +528,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( range.aspect = PAL_IMAGE_ASPECT_COLOR; } - fillSubresourceD3D12( - type, - &range, - nullptr, - nullptr, - &desc, - nullptr); - + fillSubresourceD3D12(DESC_TYPE_SRV, type, &range, &desc); d3d12Device->handle->lpVtbl->CreateShaderResourceView( d3d12Device->handle, handle, @@ -597,10 +549,6 @@ PalResult PAL_CALL updateDescriptorSetD3D12( handle = imageView->image->handle; } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; type = PAL_IMAGE_VIEW_TYPE_2D; range.mipLevelCount = 1; @@ -608,14 +556,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( range.aspect = PAL_IMAGE_ASPECT_COLOR; } - fillSubresourceD3D12( - type, - &range, - nullptr, - nullptr, - nullptr, - &desc); - + fillSubresourceD3D12(DESC_TYPE_UAV, type, &range, &desc); d3d12Device->handle->lpVtbl->CreateUnorderedAccessView( d3d12Device->handle, handle, @@ -633,11 +574,6 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.SizeInBytes = bufferInfo->size; address = buffer->handle->lpVtbl->GetGPUVirtualAddress(buffer->handle); desc.BufferLocation = address + bufferInfo->offset; - - } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } } d3d12Device->handle->lpVtbl->CreateConstantBufferView( @@ -667,11 +603,6 @@ PalResult PAL_CALL updateDescriptorSetD3D12( handle = buffer->handle; desc.Buffer.FirstElement = bufferInfo->offset / stride; desc.Buffer.NumElements = bufferInfo->size / stride; - - } else { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } } d3d12Device->handle->lpVtbl->CreateUnorderedAccessView( diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c index f0c92557..4888bb39 100644 --- a/src/graphics/d3d12/pal_device_d3d12.c +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -364,6 +364,10 @@ PalResult PAL_CALL createDeviceD3D12( limits->maxDescriptorAccelerationStructures = 4; } + if (features & PAL_ADAPTER_FEATURE_FENCE_RESET) { + device->canFenceReset = PAL_TRUE; + } + device->adapter = d3d12Adapter->handle; *outDevice = (PalDevice*)device; return PAL_RESULT_SUCCESS; @@ -427,7 +431,6 @@ PalResult PAL_CALL allocateMemoryD3D12( D3D12_HEAP_DESC desc = {0}; desc.SizeInBytes = size; - desc.Properties.Type = D3D12_HEAP_TYPE_DEFAULT; if (type == PAL_MEMORY_TYPE_CPU_READBACK) { desc.Properties.Type = D3D12_HEAP_TYPE_READBACK; @@ -447,7 +450,6 @@ PalResult PAL_CALL allocateMemoryD3D12( } memory->type = type; - memory->reserved = PAL_BACKEND_KEY; *outMemory = (PalMemory*)memory; return PAL_RESULT_SUCCESS; } @@ -461,54 +463,31 @@ void PAL_CALL freeMemoryD3D12( palFree(s_D3D12.allocator, d3d12Memory); } -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( +void PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( PalDevice* device, PalSamplerAnisotropyCapabilities* caps) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - caps->maxAnisotropy = 16; // default on most d3d12 hardwares - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryMultiViewCapabilitiesD3D12( +void PAL_CALL queryMultiViewCapabilitiesD3D12( PalDevice* device, PalMultiViewCapabilities* caps) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - caps->maxViewCount = D3D12_MAX_VIEW_INSTANCE_COUNT; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryMultiViewportCapabilitiesD3D12( +void PAL_CALL queryMultiViewportCapabilitiesD3D12( PalDevice* device, PalMultiViewportCapabilities* caps) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - caps->maxCount = D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( +void PAL_CALL queryDepthStencilCapabilitiesD3D12( PalDevice* device, PalDepthStencilCapabilities* caps) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - // depth resolve modes caps->supportedDepthResolveModes |= (1u << PAL_RESOLVE_MODE_AVERAGE); caps->supportedDepthResolveModes |= (1u << PAL_RESOLVE_MODE_MIN); @@ -520,21 +499,14 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesD3D12( caps->supportsIndependentResolve = PAL_FALSE; caps->supportsIndependentResolveNone = PAL_FALSE; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( +void PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - // these are supported if fragment shading rate feature is - caps->supportedShadingRates = 0; - caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_1X1); + caps->supportedShadingRates = (1u << PAL_FRAGMENT_SHADING_RATE_1X1); caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_1X2); caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_2X1); caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_2X2); @@ -564,19 +536,12 @@ PalResult PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( caps->minTexelHeight = 1; // safe default caps->maxTexelWidth = options.ShadingRateImageTileSize; caps->maxTexelHeight = options.ShadingRateImageTileSize; - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( +void PAL_CALL queryMeshShaderCapabilitiesD3D12( PalDevice* device, PalMeshShaderCapabilities* caps) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - // these are not exposed by d3d12. We use the offical mesh shader spec caps->maxOutputPrimitives = 256; caps->maxOutputVertices = 256; @@ -590,18 +555,12 @@ PalResult PAL_CALL queryMeshShaderCapabilitiesD3D12( caps->maxTaskWorkGroupCount[0] = 65535; caps->maxTaskWorkGroupCount[1] = 65535; caps->maxTaskWorkGroupCount[2] = 65535; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( +void PAL_CALL queryRayTracingCapabilitiesD3D12( PalDevice* device, PalRayTracingCapabilities* caps) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - // these are safe defaults. D3d12 does not expose them. caps->maxRecursionDepth = 31; caps->maxHitAttributeSize = 32; @@ -610,23 +569,16 @@ PalResult PAL_CALL queryRayTracingCapabilitiesD3D12( caps->maxGeometryCount = 100000; caps->maxPayloadSize = 64; caps->maxDispatchInvocations = 16000000; - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( +void PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( PalDevice* device, PalDescriptorIndexingCapabilities* caps) { DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - caps->flags = PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING; caps->flags |= PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; getDescriptorTierLimitsD3D12(d3d12Device->handle, nullptr, caps); - return PAL_RESULT_SUCCESS; } PalResult PAL_CALL createQueueD3D12( @@ -642,7 +594,6 @@ PalResult PAL_CALL createQueueD3D12( switch (type) { case PAL_QUEUE_TYPE_COMPUTE: { desc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; - if (!d3d12Device->limits.freeComputeQueues) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } @@ -652,7 +603,6 @@ PalResult PAL_CALL createQueueD3D12( case PAL_QUEUE_TYPE_GRAPHICS: { desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - if (!d3d12Device->limits.freeGraphicsQueues) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } @@ -662,7 +612,6 @@ PalResult PAL_CALL createQueueD3D12( case PAL_QUEUE_TYPE_COPY: { desc.Type = D3D12_COMMAND_LIST_TYPE_COPY; - if (!d3d12Device->limits.freeCopyQueues) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } @@ -711,7 +660,6 @@ PalResult PAL_CALL createQueueD3D12( queue->fenceValue = 0; queue->type = type; - queue->reserved = PAL_BACKEND_KEY; *outQueue = (PalQueue*)queue; return PAL_RESULT_SUCCESS; } @@ -774,37 +722,6 @@ PalResult PAL_CALL createShaderD3D12( for (int i = 0; i < info->entryCount; i++) { ShaderEntry* entry = &shader->entries[i]; - - // clang-format off - if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || - info->entries[i].stage == PAL_SHADER_STAGE_TASK) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_GEOMETRY) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || - info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || - info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_MISS || - info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || - info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - } - // clang-format on - convertToWcharD3D12(info->entries[i].entryName, entry->entryName); entry->patchControlPoints = info->entries[i].patchControlPoints; entry->stage = info->entries[i].stage; @@ -815,7 +732,6 @@ PalResult PAL_CALL createShaderD3D12( shader->byteCode.BytecodeLength = info->bytecodeSize; shader->entryCount = info->entryCount; - shader->reserved = PAL_BACKEND_KEY; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/d3d12/pal_image_d3d12.c b/src/graphics/d3d12/pal_image_d3d12.c index 7e099de9..d68db382 100644 --- a/src/graphics/d3d12/pal_image_d3d12.c +++ b/src/graphics/d3d12/pal_image_d3d12.c @@ -199,8 +199,7 @@ PalResult PAL_CALL createImageD3D12( image->info.sampleCount = info->sampleCount; image->info.width = info->width; - image->device = d3d12Device; - image->reserved = PAL_BACKEND_KEY; + image->device = d3d12Device->handle; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } @@ -214,24 +213,20 @@ void PAL_CALL destroyImageD3D12(PalImage* image) palFree(s_D3D12.allocator, d3d12Image); } -PalResult PAL_CALL getImageInfoD3D12( +void PAL_CALL getImageInfoD3D12( PalImage* image, PalImageInfo* info) { ImageD3D12* d3d12Image = (ImageD3D12*)image; *info = d3d12Image->info; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getImageMemoryRequirementsD3D12( +void PAL_CALL getImageMemoryRequirementsD3D12( PalImage* image, PalMemoryRequirements* requirements) { ImageD3D12* d3d12Image = (ImageD3D12*)image; - ID3D12Device5* device = d3d12Image->device->handle; - if (d3d12Image->info.belongsToSwapchain) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } + ID3D12Device5* device = d3d12Image->device; D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; @@ -245,7 +240,6 @@ PalResult PAL_CALL getImageMemoryRequirementsD3D12( requirements->supportedMemoryTypes = (1u << PAL_MEMORY_TYPE_GPU_ONLY); requirements->alignment = allocationInfo.Alignment; requirements->size = allocationInfo.SizeInBytes; - return PAL_RESULT_SUCCESS; } PalResult PAL_CALL bindImageMemoryD3D12( @@ -255,7 +249,7 @@ PalResult PAL_CALL bindImageMemoryD3D12( { HRESULT result; ImageD3D12* d3d12Image = (ImageD3D12*)image; - ID3D12Device5* device = d3d12Image->device->handle; + ID3D12Device5* device = d3d12Image->device; if (d3d12Image->info.belongsToSwapchain) { return PAL_RESULT_CODE_INVALID_OPERATION; } @@ -293,12 +287,6 @@ PalResult PAL_CALL createImageViewD3D12( DeviceD3D12* d3d12Device = (DeviceD3D12*)device; ImageD3D12* d3d12Image = (ImageD3D12*)image; - if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - } - imageView = palAllocate(s_D3D12.allocator, sizeof(ImageViewD3D12), 0); if (!imageView) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -319,14 +307,7 @@ PalResult PAL_CALL createImageViewD3D12( D3D12_RENDER_TARGET_VIEW_DESC desc = {0}; desc.Format = imageView->format; - fillSubresourceD3D12( - info->type, - &info->subresourceRange, - &desc, - nullptr, - nullptr, - nullptr); - + fillSubresourceD3D12(DESC_TYPE_RTV, info->type, &info->subresourceRange, &desc); imageView->heapIndex = index; d3d12Device->handle->lpVtbl->CreateRenderTargetView( d3d12Device->handle, @@ -344,14 +325,7 @@ PalResult PAL_CALL createImageViewD3D12( D3D12_DEPTH_STENCIL_VIEW_DESC desc = {0}; desc.Format = imageView->format; - fillSubresourceD3D12( - info->type, - &info->subresourceRange, - nullptr, - &desc, - nullptr, - nullptr); - + fillSubresourceD3D12(DESC_TYPE_DSV, info->type, &info->subresourceRange, &desc); imageView->heapIndex = index; d3d12Device->handle->lpVtbl->CreateDepthStencilView( d3d12Device->handle, diff --git a/src/graphics/d3d12/pal_pipeline_d3d12.c b/src/graphics/d3d12/pal_pipeline_d3d12.c index 99c4f6f7..7715dc86 100644 --- a/src/graphics/d3d12/pal_pipeline_d3d12.c +++ b/src/graphics/d3d12/pal_pipeline_d3d12.c @@ -573,7 +573,6 @@ PalResult PAL_CALL createPipelineLayoutD3D12( } blob->lpVtbl->Release(blob); - layout->reserved = PAL_BACKEND_KEY; *outLayout = (PalPipelineLayout*)layout; return PAL_RESULT_SUCCESS; } @@ -1042,7 +1041,6 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( pipeline->layout = layout; pipeline->shaderExports = nullptr; pipeline->localRootSignature = nullptr; - pipeline->reserved = PAL_BACKEND_KEY; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -1083,7 +1081,6 @@ PalResult PAL_CALL createComputePipelineD3D12( pipeline->layout = layout; pipeline->shaderExports = nullptr; pipeline->localRootSignature = nullptr; - pipeline->reserved = PAL_BACKEND_KEY; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -1099,10 +1096,6 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( PipelineLayoutD3D12* layout = (PipelineLayoutD3D12*)info->pipelineLayout; PipelineD3D12* pipeline = nullptr; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - if (info->maxAttributeSize > d3d12Device->limits.maxHitAttributeSize) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -1426,7 +1419,6 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( pipeline->strides = nullptr; pipeline->hasFsr = PAL_FALSE; pipeline->layout = layout; - pipeline->reserved = PAL_BACKEND_KEY; pipeline->sbtInfo = sbtInfo; *outPipeline = (PalPipeline*)pipeline; diff --git a/src/graphics/d3d12/pal_sbt_d3d12.c b/src/graphics/d3d12/pal_sbt_d3d12.c index d7fdc821..1e93d03d 100644 --- a/src/graphics/d3d12/pal_sbt_d3d12.c +++ b/src/graphics/d3d12/pal_sbt_d3d12.c @@ -21,10 +21,6 @@ PalResult PAL_CALL createShaderBindingTableD3D12( PipelineD3D12* pipeline = (PipelineD3D12*)info->rayTracingPipeline; ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - uint32_t totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; totalGroups += sbtInfo->missCount + sbtInfo->callableCount; if (info->recordCount != totalGroups) { @@ -290,7 +286,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( } } - sbt->stagingBuffer->lpVtbl->Unmap(sbt->stagingBuffer, 0, nullptr); + sbt->stagingPtr = ptr; sbt->baseAddress = sbt->buffer->lpVtbl->GetGPUVirtualAddress(sbt->buffer); // raygen @@ -342,7 +338,6 @@ PalResult PAL_CALL createShaderBindingTableD3D12( sbt->stagingBufferSize = bufferSize; sbt->pipeline = pipeline; - sbt->reserved = PAL_BACKEND_KEY; sbt->isDirty = PAL_TRUE; // we need to copy from the staging to the gpu buffer *outSbt = (PalShaderBindingTable*)sbt; return PAL_RESULT_SUCCESS; @@ -356,32 +351,22 @@ void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) palFree(s_D3D12.allocator, d3d12Sbt); } -PalResult PAL_CALL updateShaderBindingTableD3D12( +void PAL_CALL updateShaderBindingTableD3D12( PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos) { - HRESULT result; ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; PipelineD3D12* pipeline = d3d12Sbt->pipeline; ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; - void* data = nullptr; - d3d12Sbt->stagingBuffer->lpVtbl->Map(d3d12Sbt->stagingBuffer, 0, nullptr, &data); - if (FAILED(result)) { - return makeResultD3D12(result); - } - uint64_t stride = 0; uint64_t offset = 0; uint32_t startIndex = 0; for (int i = 0; i < count; i++) { PalShaderBindingTableRecordInfo* info = &infos[i]; - if (!info->localDataSize) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - + // find the group the record belongs to uint32_t index = info->groupIndex; if (index < sbtInfo->raygenCount) { @@ -411,13 +396,11 @@ PalResult PAL_CALL updateShaderBindingTableD3D12( // write payload uint32_t localIndex = index - startIndex; - uint8_t* dst = (uint8_t*)data + offset + (localIndex * stride); + uint8_t* dst = (uint8_t*)d3d12Sbt->stagingPtr + offset + (localIndex * stride); memcpy(dst + d3d12Sbt->handleSize, info->localData, info->localDataSize); } - d3d12Sbt->stagingBuffer->lpVtbl->Unmap(d3d12Sbt->stagingBuffer, 0, nullptr); d3d12Sbt->isDirty = PAL_TRUE; - return PAL_RESULT_SUCCESS; } #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_swapchain_d3d12.c b/src/graphics/d3d12/pal_swapchain_d3d12.c index ac891bb9..564a61a2 100644 --- a/src/graphics/d3d12/pal_swapchain_d3d12.c +++ b/src/graphics/d3d12/pal_swapchain_d3d12.c @@ -15,11 +15,6 @@ PalResult PAL_CALL createSurfaceD3D12( PalWindowInstanceType instanceType, PalSurface** outSurface) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - SurfaceD3D12* surface = nullptr; surface = palAllocate(s_D3D12.allocator, sizeof(SurfaceD3D12), 0); if (!surface) { @@ -32,7 +27,6 @@ PalResult PAL_CALL createSurfaceD3D12( } surface->handle = window; - surface->reserved = PAL_BACKEND_KEY; *outSurface = (PalSurface*)surface; return PAL_RESULT_SUCCESS; } @@ -43,22 +37,17 @@ void PAL_CALL destroySurfaceD3D12(PalSurface* surface) palFree(s_D3D12.allocator, d3dSurface); } -PalResult PAL_CALL getSurfaceCapabilitiesD3D12( +void PAL_CALL getSurfaceCapabilitiesD3D12( PalDevice* device, PalSurface* surface, PalSurfaceCapabilities* caps) { - HRESULT result; SurfaceD3D12* d3dSurface = (SurfaceD3D12*)surface; DeviceD3D12* d3d12Device = (DeviceD3D12*)device; PalBool supportHDR10 = PAL_FALSE; IDXGISwapChain1* swapchain1 = nullptr; IDXGISwapChain3* swapchain3 = nullptr; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - DXGI_SWAP_CHAIN_DESC1 desc = {0}; desc.Width = 8; desc.Height = 8; @@ -69,7 +58,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE; desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( + s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( s_D3D12.factory, (IUnknown*)d3d12Device->queue, d3dSurface->handle, @@ -78,21 +67,17 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( nullptr, &swapchain1); - if (FAILED(result)) { - return makeResultD3D12(result); - } - swapchain1->lpVtbl->QueryInterface(swapchain1, &IID_Swapchain, (void**)&swapchain3); swapchain1->lpVtbl->Release(swapchain1); // check for HDR10 color space support UINT flags = 0; - result = swapchain3->lpVtbl->CheckColorSpaceSupport( + swapchain3->lpVtbl->CheckColorSpaceSupport( swapchain3, DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, &flags); - if (SUCCEEDED(result) && (flags & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) { + if (flags & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) { supportHDR10 = PAL_TRUE; } @@ -131,13 +116,13 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( for (int i = 0; i < PAL_SURFACE_FORMAT_COUNT; i++) { formatSupport.Format = baseFormats[i]; - result = d3d12Device->handle->lpVtbl->CheckFeatureSupport( + d3d12Device->handle->lpVtbl->CheckFeatureSupport( d3d12Device->handle, D3D12_FEATURE_FORMAT_SUPPORT, &formatSupport, sizeof(formatSupport)); - if (SUCCEEDED(result) && (formatSupport.Support1 != 0 || formatSupport.Support2 != 0)) { + if (formatSupport.Support1 != 0 || formatSupport.Support2 != 0) { if (baseFormats[i] == DXGI_FORMAT_B8G8R8A8_UNORM) { caps->supportedFormats |= (1u << PAL_SURFACE_FORMAT_BGRA8_UNORM_SRGB_NONLINEAR); } @@ -160,7 +145,6 @@ PalResult PAL_CALL getSurfaceCapabilitiesD3D12( } swapchain3->lpVtbl->Release(swapchain3); - return PAL_RESULT_SUCCESS; } PalResult PAL_CALL createSwapchainD3D12( @@ -177,10 +161,6 @@ PalResult PAL_CALL createSwapchainD3D12( SwapchainD3D12* swapchain = nullptr; PalBool isHDRColorspace = PAL_FALSE; - if (!(d3d12Device->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - if (d3d12Queue->type != PAL_QUEUE_TYPE_GRAPHICS) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -193,10 +173,6 @@ PalResult PAL_CALL createSwapchainD3D12( return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (info->imageCount > 8) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } - swapchain = palAllocate(s_D3D12.allocator, sizeof(SwapchainD3D12), 0); if (!swapchain) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -310,7 +286,6 @@ PalResult PAL_CALL createSwapchainD3D12( swapchain->windowWidth = windowRect.right - windowRect.left; swapchain->windowWidth = windowRect.bottom - windowRect.top; - swapchain->device = d3d12Device; swapchain->queue = d3d12Queue->handle; swapchain->imageCount = info->imageCount; *outSwapchain = (PalSwapchain*)swapchain; @@ -407,7 +382,6 @@ PalResult PAL_CALL presentSwapchainD3D12( PalBool ret = GetClientRect((HWND)d3dSwapchain->surface->handle, &windowRect); uint32_t w = windowRect.right - windowRect.left; uint32_t h = windowRect.bottom - windowRect.top; - if (!ret) { return palMakeResult( PAL_RESULT_CODE_PLATFORM_FAILURE, diff --git a/src/graphics/d3d12/pal_sync_d3d12.c b/src/graphics/d3d12/pal_sync_d3d12.c index dddb29c4..c7696434 100644 --- a/src/graphics/d3d12/pal_sync_d3d12.c +++ b/src/graphics/d3d12/pal_sync_d3d12.c @@ -44,13 +44,12 @@ PalResult PAL_CALL createFenceD3D12( } fence->canReset = PAL_FALSE; - if (d3d12Device->features & PAL_ADAPTER_FEATURE_FENCE_RESET) { + if (d3d12Device->canFenceReset) { fence->canReset = PAL_TRUE; } fence->isTimeline = PAL_FALSE; // for sempaphores fence->value = 0; - fence->reserved = PAL_BACKEND_KEY; *outFence = (PalFence*)fence; return PAL_RESULT_SUCCESS; } @@ -100,10 +99,6 @@ PalResult PAL_CALL waitFenceD3D12( PalResult PAL_CALL resetFenceD3D12(PalFence* fence) { FenceD3D12* d3d12Fence = (FenceD3D12*)fence; - if (!d3d12Fence->canReset) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - d3d12Fence->handle->lpVtbl->Signal(d3d12Fence->handle, 0); d3d12Fence->value = 0; return PAL_RESULT_SUCCESS; @@ -127,20 +122,11 @@ PalResult PAL_CALL createSemaphoreD3D12( DeviceD3D12* d3d12Device = (DeviceD3D12*)device; SemaphoreD3D12* semaphore = nullptr; - PalBool hasTimeline = PAL_FALSE; - if (d3d12Device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - hasTimeline = PAL_TRUE; - } - semaphore = palAllocate(s_D3D12.allocator, sizeof(SemaphoreD3D12), 0); if (!semaphore) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } - if (enableTimeline && !hasTimeline) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - if (enableTimeline) { semaphore->isTimeline = PAL_TRUE; } @@ -168,7 +154,6 @@ PalResult PAL_CALL createSemaphoreD3D12( semaphore->canReset = PAL_FALSE; semaphore->value = 0; - semaphore->reserved = PAL_BACKEND_KEY; *outSemaphore = (PalSemaphore*)semaphore; return PAL_RESULT_SUCCESS; } @@ -189,9 +174,6 @@ PalResult PAL_CALL waitSemaphoreD3D12( HRESULT result; DWORD ret = 0; SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; - if (!d3d12Semaphore->isTimeline) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } HANDLE event = d3d12Semaphore->event; if (d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle) < value) { @@ -224,29 +206,18 @@ PalResult PAL_CALL signalSemaphoreD3D12( uint64_t value) { SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; - if (!d3d12Semaphore->isTimeline) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - HRESULT result = d3d12Semaphore->handle->lpVtbl->Signal(d3d12Semaphore->handle, value); if (FAILED(result)) { return makeResultD3D12(result); } + return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getSemaphoreValueD3D12( - PalSemaphore* semaphore, - uint64_t* outValue) +uint64_t PAL_CALL getSemaphoreValueD3D12(PalSemaphore* semaphore) { SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; - if (!d3d12Semaphore->isTimeline) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - UINT64 tmp = d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle); - *outValue = tmp; - return PAL_RESULT_SUCCESS; + return d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle); } #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 85a3319e..8ab9e238 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -1083,11 +1083,9 @@ PalResult PAL_CALL palSignalSemaphore( return semaphore->backend->signalSemaphore(semaphore, queue, value); } -PalResult PAL_CALL palGetSemaphoreValue( - PalSemaphore* semaphore, - uint64_t* outValue) +uint64_t PAL_CALL palGetSemaphoreValue(PalSemaphore* semaphore) { - return semaphore->backend->getSemaphoreValue(semaphore, outValue); + return semaphore->backend->getSemaphoreValue(semaphore); } // ================================================== @@ -1630,13 +1628,13 @@ void PAL_CALL palComputeImageStagingRequirements( PalDevice* device, PalFormat imageFormat, const PalBufferImageCopyInfo* copyInfo, - PalImageStagingRequirements* outRequirements) + PalImageStagingRequirements* requirements) { device->backend->computeImageStagingRequirements( device, imageFormat, copyInfo, - outRequirements); + requirements); } void PAL_CALL palWriteInstanceStaging( diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index 16c0402e..182562d9 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -69,7 +69,7 @@ typedef struct { void (PAL_CALL *destroySemaphore)(PalSemaphore*); PalResult (PAL_CALL *waitSemaphore)(PalSemaphore*, uint64_t, uint64_t); PalResult (PAL_CALL *signalSemaphore)(PalSemaphore*, PalQueue*, uint64_t); - PalResult (PAL_CALL *getSemaphoreValue)(PalSemaphore*, uint64_t*); + uint64_t (PAL_CALL *getSemaphoreValue)(PalSemaphore*); PalResult (PAL_CALL *createCommandPool)(PalDevice*, PalQueue*, PalCommandPool**); void (PAL_CALL *destroyCommandPool)(PalCommandPool*); PalResult (PAL_CALL *resetCommandPool)(PalCommandPool*); @@ -504,7 +504,7 @@ PalResult PAL_CALL createSemaphoreD3D12(PalDevice*, PalBool, PalSemaphore**); void PAL_CALL destroySemaphoreD3D12(PalSemaphore*); PalResult PAL_CALL waitSemaphoreD3D12(PalSemaphore*, uint64_t, uint64_t); PalResult PAL_CALL signalSemaphoreD3D12(PalSemaphore*, PalQueue*, uint64_t); -PalResult PAL_CALL getSemaphoreValueD3D12(PalSemaphore*, uint64_t*); +uint64_t PAL_CALL getSemaphoreValueD3D12(PalSemaphore*); PalResult PAL_CALL createCommandPoolD3D12(PalDevice*, PalQueue*, PalCommandPool**); void PAL_CALL destroyCommandPoolD3D12(PalCommandPool*); PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool*); @@ -542,18 +542,11 @@ void PAL_CALL cmdAccelerationStructureBarrierD3D12(PalCommandBuffer*, PalAcceler void PAL_CALL cmdImageBarrierD3D12(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); void PAL_CALL cmdBufferBarrierD3D12(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); void PAL_CALL cmdDispatchD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); -void PAL_CALL cmdDispatchBaseD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); void PAL_CALL cmdDispatchIndirectD3D12(PalCommandBuffer*, PalBuffer*); void PAL_CALL cmdTraceRaysD3D12(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); void PAL_CALL cmdTraceRaysIndirectD3D12(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); void PAL_CALL cmdBindDescriptorSetD3D12(PalCommandBuffer*, uint32_t, PalDescriptorSet*); void PAL_CALL cmdPushConstantsD3D12(PalCommandBuffer*, uint32_t, uint32_t, const void*); -void PAL_CALL cmdSetCullModeD3D12(PalCommandBuffer*, PalCullMode); -void PAL_CALL cmdSetFrontFaceD3D12(PalCommandBuffer*, PalFrontFace); -void PAL_CALL cmdSetPrimitiveTopologyD3D12(PalCommandBuffer*, PalPrimitiveTopology); -void PAL_CALL cmdSetDepthTestEnableD3D12(PalCommandBuffer*, PalBool); -void PAL_CALL cmdSetDepthWriteEnableD3D12(PalCommandBuffer*, PalBool); -void PAL_CALL cmdSetStencilOpD3D12(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); PalResult PAL_CALL createAccelerationstructureD3D12(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure*); @@ -679,18 +672,18 @@ static PalGraphicsVtable s_D3D12Backend = { .cmdImageBarrier = cmdImageBarrierD3D12, .cmdBufferBarrier = cmdBufferBarrierD3D12, .cmdDispatch = cmdDispatchD3D12, - .cmdDispatchBase = cmdDispatchBaseD3D12, + .cmdDispatchBase = nullptr, .cmdDispatchIndirect = cmdDispatchIndirectD3D12, .cmdTraceRays = cmdTraceRaysD3D12, .cmdTraceRaysIndirect = cmdTraceRaysIndirectD3D12, .cmdBindDescriptorSet = cmdBindDescriptorSetD3D12, .cmdPushConstants = cmdPushConstantsD3D12, - .cmdSetCullMode = cmdSetCullModeD3D12, - .cmdSetFrontFace = cmdSetFrontFaceD3D12, - .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyD3D12, - .cmdSetDepthTestEnable = cmdSetDepthTestEnableD3D12, - .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableD3D12, - .cmdSetStencilOp = cmdSetStencilOpD3D12, + .cmdSetCullMode = nullptr, + .cmdSetFrontFace = nullptr, + .cmdSetPrimitiveTopology = nullptr, + .cmdSetDepthTestEnable = nullptr, + .cmdSetDepthWriteEnable = nullptr, + .cmdSetStencilOp = nullptr, .createAccelerationstructure = createAccelerationstructureD3D12, .destroyAccelerationstructure = destroyAccelerationstructureD3D12, .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeD3D12, diff --git a/src/graphics/vulkan/pal_sync_vulkan.c b/src/graphics/vulkan/pal_sync_vulkan.c index 5ea50d0d..0250a1a0 100644 --- a/src/graphics/vulkan/pal_sync_vulkan.c +++ b/src/graphics/vulkan/pal_sync_vulkan.c @@ -217,9 +217,7 @@ PalResult PAL_CALL signalSemaphoreVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getSemaphoreValueVk( - PalSemaphore* semaphore, - uint64_t* outValue) +uint64_t PAL_CALL getSemaphoreValueVk(PalSemaphore* semaphore) { SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; if (!vkSemaphore->isTimeline) { From 49f88732c256346f56b43dfb578e65eefcc0a760 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 11 Jul 2026 18:01:43 +0000 Subject: [PATCH 335/372] add a linear allocator --- src/graphics/pal_linear_allocator.h | 45 +++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/graphics/pal_linear_allocator.h diff --git a/src/graphics/pal_linear_allocator.h b/src/graphics/pal_linear_allocator.h new file mode 100644 index 00000000..7a11b4d4 --- /dev/null +++ b/src/graphics/pal_linear_allocator.h @@ -0,0 +1,45 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#ifndef _PAL_LINEAR_ALLOCATOR_H +#define _PAL_LINEAR_ALLOCATOR_H + +#include "pal/pal_core.h" + +#define align(v, a) (v + a - 1) & ~(a - 1) + +typedef struct { + uint8_t* memory; + uint64_t size; + uint64_t offset; +} PalLinearAllocator; + +static void* palLinearAlloc( + PalLinearAllocator* allocator, + uint64_t size, + uint64_t alignment) +{ + uint64_t offset = align(allocator->offset, alignment); + if (offset + size > allocator->size) { + // allocate a bigger block + void* block = palAllocate(nullptr, allocator->size * 2, 0); + if (!block) { + return nullptr; + } + + memcpy(block, (const void*)allocator->memory, allocator->size); + palFree(nullptr, (void*)allocator->memory); + allocator->memory = (uint8_t*)block; + allocator->size = allocator->size * 2; + } + + void* ptr = allocator->memory + offset; + allocator->offset = offset + size; + return ptr; +} + +#endif // _PAL_LINEAR_ALLOCATOR_H \ No newline at end of file From 276785b870863e92e11fc9a08e2eb21c10be3ac9 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 12 Jul 2026 00:39:27 +0000 Subject: [PATCH 336/372] add pipeline stages API and fix graphics tests --- include/pal/pal_graphics.h | 92 +++- pal_config.lua | 2 +- src/graphics/d3d12/pal_commands_d3d12.c | 9 +- src/graphics/d3d12/pal_device_d3d12.c | 4 +- src/graphics/d3d12/pal_sbt_d3d12.c | 1 + src/graphics/d3d12/pal_sync_d3d12.c | 7 +- src/graphics/pal_graphics.c | 32 +- src/graphics/pal_graphics_backends.h | 24 +- src/graphics/pal_linear_allocator.h | 7 +- src/graphics/vulkan/pal_adapter_vulkan.c | 8 +- src/graphics/vulkan/pal_as_vulkan.c | 9 - src/graphics/vulkan/pal_buffer_vulkan.c | 58 +-- src/graphics/vulkan/pal_command_pool_vulkan.c | 110 ++--- src/graphics/vulkan/pal_commands_vulkan.c | 444 ++++-------------- src/graphics/vulkan/pal_descriptors_vulkan.c | 53 --- src/graphics/vulkan/pal_device_vulkan.c | 107 +---- src/graphics/vulkan/pal_image_vulkan.c | 19 +- src/graphics/vulkan/pal_pipeline_vulkan.c | 52 -- src/graphics/vulkan/pal_sbt_vulkan.c | 33 +- src/graphics/vulkan/pal_swapchain_vulkan.c | 17 +- src/graphics/vulkan/pal_sync_vulkan.c | 35 +- src/graphics/vulkan/pal_vulkan.c | 86 ++++ src/graphics/vulkan/pal_vulkan.h | 15 +- src/video/wayland/pal_window_wayland.c | 1 + src/video/x11/pal_window_x11.c | 2 +- src/video/x11/pal_x11.h | 2 +- tests/graphics/clear_color_test.c | 35 +- tests/graphics/compute_test.c | 10 +- tests/graphics/descriptor_indexing_test.c | 60 +-- tests/graphics/geometry_test.c | 30 +- tests/graphics/indirect_draw_test.c | 46 +- tests/graphics/mesh_test.c | 30 +- tests/graphics/multi_descriptor_set_test.c | 11 +- tests/graphics/ray_tracing_test.c | 65 +-- tests/graphics/texture_test.c | 62 +-- tests/graphics/triangle_test.c | 38 +- tests/video/native_integration_test.c | 13 +- 37 files changed, 599 insertions(+), 1030 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index bb64f2aa..b2a14c36 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -541,6 +541,27 @@ #define PAL_RENDERING_FLAG_SUSPENDING (1U << 0) #define PAL_RENDERING_FLAG_RESUMING (1U << 1) +#define PAL_PIPELINE_STAGE_NONE 0 +#define PAL_PIPELINE_STAGE_VERTEX_SHADER (1U << 1) +#define PAL_PIPELINE_STAGE_FRAGMENT_SHADER (1U << 2) +#define PAL_PIPELINE_STAGE_COMPUTE_SHADER (1U << 3) +#define PAL_PIPELINE_STAGE_GEOMETRY_SHADER (1U << 4) +#define PAL_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER (1U << 5) +#define PAL_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER (1U << 6) +#define PAL_PIPELINE_STAGE_RAY_TRACING_SHADER (1U << 7) +#define PAL_PIPELINE_STAGE_TASK_SHADER (1U << 8) +#define PAL_PIPELINE_STAGE_MESH_SHADER (1U << 9) +#define PAL_PIPELINE_STAGE_VERTEX_INPUT (1U << 10) +#define PAL_PIPELINE_STAGE_INDEX_INPUT (1U << 11) +#define PAL_PIPELINE_STAGE_EARLY_DEPTH_STENCIL (1U << 12) +#define PAL_PIPELINE_STAGE_LATE_DEPTH_STENCIL (1U << 13) +#define PAL_PIPELINE_STAGE_TRANSFER (1U << 14) +#define PAL_PIPELINE_STAGE_HOST (1U << 15) +#define PAL_PIPELINE_STAGE_COLOR_ATTACHMENT (1U << 16) +#define PAL_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT (1U << 17) +#define PAL_PIPELINE_STAGE_INDIRECT_INPUT (1U << 18) +#define PAL_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD (1U << 19) + #define PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1 0 /** @@ -1411,6 +1432,18 @@ typedef uint32_t PalImageMemoryUsage; */ typedef uint32_t PalRenderingFlags; +/** + * @typedef PalPipelineStages + * @brief Pipeline stages. Multiple pipeline usages can be OR'ed together using bitwise + * OR operator (`|`). + * + * All pipeline stages follow the format `PAL_PIPELINE_STAGE_**` + * for consistency and API use. + * + * @since 2.0 + */ +typedef uint32_t PalPipelineStages; + /** * @typedef PalGraphicsBackendVtableVersion * @brief Graphics backend vtable versions. @@ -1802,6 +1835,8 @@ typedef struct { PalSemaphore* waitSemaphore; /**< Wait semaphore.*/ PalSemaphore* signalSemaphore; /**< Signal semaphore.*/ PalFence* fence; /**< Fence to signal.*/ + PalPipelineStages waitStages; /**< (eg. `PAL_PIPELINE_STAGE_COLOR_ATTACHMENT`).*/ + PalPipelineStages signalStages; /**< (eg. `PAL_PIPELINE_STAGE_NONE`).*/ } PalCommandBufferSubmitInfo; /** @@ -2291,6 +2326,21 @@ typedef struct { uint32_t descriptorCount; /**< Number of descriptors to write.*/ } PalDescriptorSetWriteInfo; +/** + * @struct PalBarrierInfo + * @brief Information about a barrier. + * + * Uninitialized fields may result in undefined behavior. + * + * @since 2.0 + */ +typedef struct { + PalUsageState oldState; /**< (eg. `PAL_USAGE_STATE_COLOR_ATTACHMENT`).*/ + PalUsageState newState; /**< (eg. `PAL_USAGE_STATE_PRESENT`).*/ + PalPipelineStages srcStages; /**< (eg. `PAL_PIPELINE_STAGE_COLOR_ATTACHMENT`).*/ + PalPipelineStages dstStages; /**< (eg. `PAL_PIPELINE_STAGE_COLOR_OUTPUT`).*/ +} PalBarrierInfo; + /** * @struct PalPushConstantInfo * @brief Push constant range. @@ -3197,7 +3247,9 @@ typedef struct { * * Must obey the rules and semantics documented in palGetSemaphoreValue(). */ - uint64_t(PAL_CALL* getSemaphoreValue)(PalSemaphore* semaphore); + PalResult(PAL_CALL* getSemaphoreValue)( + PalSemaphore* semaphore, + uint64_t* value); /** * Backend implementation of ::palCreateCommandPool. @@ -3519,8 +3571,7 @@ typedef struct { void(PAL_CALL* cmdAccelerationStructureBarrier)( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalBarrierInfo* info); /** * Backend implementation of ::palCmdImageBarrier. @@ -3531,8 +3582,7 @@ typedef struct { PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalBarrierInfo* info); /** * Backend implementation of ::palCmdBufferBarrier. @@ -3542,8 +3592,7 @@ typedef struct { void(PAL_CALL* cmdBufferBarrier)( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalBarrierInfo* info); /** * Backend implementation of ::palCmdDispatch. @@ -5143,8 +5192,10 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * The provided semaphore must be a timeline semaphore. Otherwise undefined behavior. * * @param[in] semaphore Semaphore to get its value. + * @param[out] value The semaphore value. * - * @return the timeline value. + * @return `PAL_RESULT_SUCCESS` on success or a result code on + * failure. Call palFormatResult() for more information. * * Thread safety: Thread safe if `semaphore` is externally synchronized. * @@ -5152,7 +5203,9 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * @sa palWaitSemaphore * @sa palSignalSemaphore */ -PAL_API uint64_t PAL_CALL palGetSemaphoreValue(PalSemaphore* semaphore); +PAL_API PalResult PAL_CALL palGetSemaphoreValue( + PalSemaphore* semaphore, + uint64_t* value); /** * @brief Create a command pool from a device. @@ -5180,7 +5233,8 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( * @brief Destroy a command pool. * * The graphics system must be initialized before this call. - * Destroying a command pool frees all command buffers automatically. + * All command buffers allocated from the pool must be freed before this call, + * otherwise undefined behavior. * * @param[in] pool Command pool to destroy. * @@ -5850,8 +5904,7 @@ PAL_API void PAL_CALL palCmdDrawIndexedIndirectCount( * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] as Acceleration structure to set barrier on. - * @param[in] oldUsageState The old usage state. - * @param[in] newUsageState The new usage state. + * @param[in] info Pointer to a PalBarrierInfo struct that specifies parameters. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * @@ -5864,8 +5917,7 @@ PAL_API void PAL_CALL palCmdDrawIndexedIndirectCount( PAL_API void PAL_CALL palCmdAccelerationStructureBarrier( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalBarrierInfo* info); /** * @brief Transition an image from one usage state to another. @@ -5891,8 +5943,7 @@ PAL_API void PAL_CALL palCmdAccelerationStructureBarrier( * @param[in] cmdBuffer Command buffer being recorded. * @param[in] image Image to set barrier on. * @param[in] subresourceRange Subresource range of the image. - * @param[in] oldUsageStateInfo The old usage state. - * @param[in] newUsageStateInfo The new usage state. + * @param[in] info Pointer to a PalBarrierInfo struct that specifies parameters. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * @@ -5904,8 +5955,7 @@ PAL_API void PAL_CALL palCmdImageBarrier( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalBarrierInfo* info); /** * @brief Transition a buffer from one usage state to another. @@ -5929,8 +5979,7 @@ PAL_API void PAL_CALL palCmdImageBarrier( * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer to set barrier on. - * @param[in] oldUsageStateInfo The old usage state. - * @param[in] newUsageStateInfo The new usage state. + * @param[in] info Pointer to a PalBarrierInfo struct that specifies parameters. * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * @@ -5941,8 +5990,7 @@ PAL_API void PAL_CALL palCmdImageBarrier( PAL_API void PAL_CALL palCmdBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState); + PalBarrierInfo* info); /** * @brief Dispatch compute shader workgroups. diff --git a/pal_config.lua b/pal_config.lua index f26dd621..ed26914e 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -21,4 +21,4 @@ PAL_BUILD_VIDEO_MODULE = true PAL_BUILD_OPENGL_MODULE = true -- build graphics module -PAL_BUILD_GRAPHICS_MODULE = false +PAL_BUILD_GRAPHICS_MODULE = true diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index 50d86cc8..6fa4b004 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -927,8 +927,7 @@ void PAL_CALL cmdDrawIndexedIndirectCountD3D12( void PAL_CALL cmdAccelerationStructureBarrierD3D12( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalBarrierInfo* info) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; AccelerationStructureD3D12* d3dAs = (AccelerationStructureD3D12*)as; @@ -942,8 +941,7 @@ void PAL_CALL cmdImageBarrierD3D12( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalBarrierInfo* info) { // TODO: use a temp or arena buffer CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; @@ -1027,8 +1025,7 @@ void PAL_CALL cmdImageBarrierD3D12( void PAL_CALL cmdBufferBarrierD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalBarrierInfo* info) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c index 4888bb39..76a7575f 100644 --- a/src/graphics/d3d12/pal_device_d3d12.c +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -454,9 +454,7 @@ PalResult PAL_CALL allocateMemoryD3D12( return PAL_RESULT_SUCCESS; } -void PAL_CALL freeMemoryD3D12( - PalDevice* device, - PalMemory* memory) +void PAL_CALL freeMemoryD3D12(PalMemory* memory) { MemoryD3D12* d3d12Memory = (MemoryD3D12*)memory; d3d12Memory->handle->lpVtbl->Release(d3d12Memory->handle); diff --git a/src/graphics/d3d12/pal_sbt_d3d12.c b/src/graphics/d3d12/pal_sbt_d3d12.c index 1e93d03d..dd567032 100644 --- a/src/graphics/d3d12/pal_sbt_d3d12.c +++ b/src/graphics/d3d12/pal_sbt_d3d12.c @@ -345,6 +345,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) { + // TODO: unmap staging buffer before destroying ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; d3d12Sbt->buffer->lpVtbl->Release(d3d12Sbt->buffer); d3d12Sbt->stagingBuffer->lpVtbl->Release(d3d12Sbt->stagingBuffer); diff --git a/src/graphics/d3d12/pal_sync_d3d12.c b/src/graphics/d3d12/pal_sync_d3d12.c index c7696434..32bb5e2e 100644 --- a/src/graphics/d3d12/pal_sync_d3d12.c +++ b/src/graphics/d3d12/pal_sync_d3d12.c @@ -214,10 +214,13 @@ PalResult PAL_CALL signalSemaphoreD3D12( return PAL_RESULT_SUCCESS; } -uint64_t PAL_CALL getSemaphoreValueD3D12(PalSemaphore* semaphore) +PalResult PAL_CALL getSemaphoreValueD3D12( + PalSemaphore* semaphore, + uint64_t* value) { SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; - return d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle); + *value = d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle); + return PAL_RESULT_SUCCESS; } #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 8ab9e238..b3d1970e 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -392,7 +392,7 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN_BACKEND - // TODO: + // TODO: uncomment // result = initGraphicsVk(debugger, allocator); // if (result != PAL_RESULT_SUCCESS) { // return result; @@ -1083,9 +1083,11 @@ PalResult PAL_CALL palSignalSemaphore( return semaphore->backend->signalSemaphore(semaphore, queue, value); } -uint64_t PAL_CALL palGetSemaphoreValue(PalSemaphore* semaphore) +PalResult PAL_CALL palGetSemaphoreValue( + PalSemaphore* semaphore, + uint64_t* value) { - return semaphore->backend->getSemaphoreValue(semaphore); + return semaphore->backend->getSemaphoreValue(semaphore, value); } // ================================================== @@ -1383,38 +1385,26 @@ void PAL_CALL palCmdDrawIndexedIndirectCount( void PAL_CALL palCmdAccelerationStructureBarrier( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalBarrierInfo* info) { - cmdBuffer->backend->cmdAccelerationStructureBarrier( - cmdBuffer, - as, - oldUsageState, - newUsageState); + cmdBuffer->backend->cmdAccelerationStructureBarrier(cmdBuffer, as, info); } void PAL_CALL palCmdImageBarrier( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalBarrierInfo* info) { - cmdBuffer->backend->cmdImageBarrier( - cmdBuffer, - image, - subresourceRange, - oldUsageState, - newUsageState); + cmdBuffer->backend->cmdImageBarrier(cmdBuffer, image, subresourceRange, info); } void PAL_CALL palCmdBufferBarrier( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalBarrierInfo* info) { - cmdBuffer->backend->cmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); + cmdBuffer->backend->cmdBufferBarrier(cmdBuffer, buffer, info); } void PAL_CALL palCmdDispatch( diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index 182562d9..91775a6c 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -69,7 +69,7 @@ typedef struct { void (PAL_CALL *destroySemaphore)(PalSemaphore*); PalResult (PAL_CALL *waitSemaphore)(PalSemaphore*, uint64_t, uint64_t); PalResult (PAL_CALL *signalSemaphore)(PalSemaphore*, PalQueue*, uint64_t); - uint64_t (PAL_CALL *getSemaphoreValue)(PalSemaphore*); + PalResult (PAL_CALL *getSemaphoreValue)(PalSemaphore*, uint64_t*); PalResult (PAL_CALL *createCommandPool)(PalDevice*, PalQueue*, PalCommandPool**); void (PAL_CALL *destroyCommandPool)(PalCommandPool*); PalResult (PAL_CALL *resetCommandPool)(PalCommandPool*); @@ -103,9 +103,9 @@ typedef struct { void (PAL_CALL *cmdDrawIndexed)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); void (PAL_CALL *cmdDrawIndexedIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); void (PAL_CALL *cmdDrawIndexedIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); - void (PAL_CALL *cmdAccelerationStructureBarrier)(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); - void (PAL_CALL *cmdImageBarrier)(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); - void (PAL_CALL *cmdBufferBarrier)(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); + void (PAL_CALL *cmdAccelerationStructureBarrier)(PalCommandBuffer*, PalAccelerationStructure*, PalBarrierInfo*); + void (PAL_CALL *cmdImageBarrier)(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalBarrierInfo*); + void (PAL_CALL *cmdBufferBarrier)(PalCommandBuffer*, PalBuffer*, PalBarrierInfo*); void (PAL_CALL *cmdDispatch)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); void (PAL_CALL *cmdDispatchBase)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); void (PAL_CALL *cmdDispatchIndirect)(PalCommandBuffer*, PalBuffer*); @@ -253,9 +253,9 @@ void PAL_CALL cmdDrawIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, void PAL_CALL cmdDrawIndexedVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); void PAL_CALL cmdDrawIndexedIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); void PAL_CALL cmdDrawIndexedIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdAccelerationStructureBarrierVk(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); -void PAL_CALL cmdImageBarrierVk(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); -void PAL_CALL cmdBufferBarrierVk(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); +void PAL_CALL cmdAccelerationStructureBarrierVk(PalCommandBuffer*, PalAccelerationStructure*, PalBarrierInfo*); +void PAL_CALL cmdImageBarrierVk(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalBarrierInfo*); +void PAL_CALL cmdBufferBarrierVk(PalCommandBuffer*, PalBuffer*, PalBarrierInfo*); void PAL_CALL cmdDispatchVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); void PAL_CALL cmdDispatchBaseVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); void PAL_CALL cmdDispatchIndirectVk(PalCommandBuffer*, PalBuffer*); @@ -272,7 +272,7 @@ void PAL_CALL cmdSetStencilOpVk(PalCommandBuffer*, PalStencilFaceFlags, PalStenc PalResult PAL_CALL createAccelerationstructureVk(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure*); -PalResult PAL_CALL getAccelerationStructureBuildSizeVk(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); +void PAL_CALL getAccelerationStructureBuildSizeVk(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); PalResult PAL_CALL createBufferVk(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); void PAL_CALL destroyBufferVk(PalBuffer*); void PAL_CALL getBufferMemoryRequirementsVk(PalBuffer*, PalMemoryRequirements*); @@ -504,7 +504,7 @@ PalResult PAL_CALL createSemaphoreD3D12(PalDevice*, PalBool, PalSemaphore**); void PAL_CALL destroySemaphoreD3D12(PalSemaphore*); PalResult PAL_CALL waitSemaphoreD3D12(PalSemaphore*, uint64_t, uint64_t); PalResult PAL_CALL signalSemaphoreD3D12(PalSemaphore*, PalQueue*, uint64_t); -uint64_t PAL_CALL getSemaphoreValueD3D12(PalSemaphore*); +PalResult PAL_CALL getSemaphoreValueD3D12(PalSemaphore*, uint64_t*); PalResult PAL_CALL createCommandPoolD3D12(PalDevice*, PalQueue*, PalCommandPool**); void PAL_CALL destroyCommandPoolD3D12(PalCommandPool*); PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool*); @@ -538,9 +538,9 @@ void PAL_CALL cmdDrawIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer void PAL_CALL cmdDrawIndexedD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); void PAL_CALL cmdDrawIndexedIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); void PAL_CALL cmdDrawIndexedIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdAccelerationStructureBarrierD3D12(PalCommandBuffer*, PalAccelerationStructure*, PalUsageState, PalUsageState); -void PAL_CALL cmdImageBarrierD3D12(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalUsageState, PalUsageState); -void PAL_CALL cmdBufferBarrierD3D12(PalCommandBuffer*, PalBuffer*, PalUsageState, PalUsageState); +void PAL_CALL cmdAccelerationStructureBarrierD3D12(PalCommandBuffer*, PalAccelerationStructure*, PalBarrierInfo*); +void PAL_CALL cmdImageBarrierD3D12(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalBarrierInfo*); +void PAL_CALL cmdBufferBarrierD3D12(PalCommandBuffer*, PalBuffer*, PalBarrierInfo*); void PAL_CALL cmdDispatchD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); void PAL_CALL cmdDispatchIndirectD3D12(PalCommandBuffer*, PalBuffer*); void PAL_CALL cmdTraceRaysD3D12(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); diff --git a/src/graphics/pal_linear_allocator.h b/src/graphics/pal_linear_allocator.h index 7a11b4d4..f26a311c 100644 --- a/src/graphics/pal_linear_allocator.h +++ b/src/graphics/pal_linear_allocator.h @@ -23,7 +23,12 @@ static void* palLinearAlloc( uint64_t size, uint64_t alignment) { - uint64_t offset = align(allocator->offset, alignment); + uint64_t defAlign = alignment; + if (alignment == 0) { + defAlign = 16; + } + + uint64_t offset = align(allocator->offset, defAlign); if (offset + size > allocator->size) { // allocate a bigger block void* block = palAllocate(nullptr, allocator->size * 2, 0); diff --git a/src/graphics/vulkan/pal_adapter_vulkan.c b/src/graphics/vulkan/pal_adapter_vulkan.c index c5a5459a..db14b3ee 100644 --- a/src/graphics/vulkan/pal_adapter_vulkan.c +++ b/src/graphics/vulkan/pal_adapter_vulkan.c @@ -31,7 +31,7 @@ static PalSampleCount samplesFromVk(VkSampleCountFlags count) return PAL_SAMPLE_COUNT_1; } -static PalImageUsages ImageUsageFromVk(VkFormatFeatureFlags flags) +static PalImageUsages imageUsageFromVk(VkFormatFeatureFlags flags) { PalImageUsages usages = 0; if (flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) { @@ -728,7 +728,7 @@ void PAL_CALL enumerateFormatsVk( if (fmtCount < *count) { PalFormatInfo* fmtInfo = &outFormats[fmtCount++]; fmtInfo->format = (PalFormat)i; - fmtInfo->usages = ImageUsageFromVk(props.optimalTilingFeatures); + fmtInfo->usages = imageUsageFromVk(props.optimalTilingFeatures); } } else { @@ -771,7 +771,7 @@ PalImageUsages PAL_CALL queryFormatImageUsagesVk( return PAL_IMAGE_USAGE_UNDEFINED; } - return ImageUsageFromVk(props.optimalTilingFeatures); + return imageUsageFromVk(props.optimalTilingFeatures); } PalSampleCount PAL_CALL queryFormatSampleCountVk( @@ -790,7 +790,7 @@ PalSampleCount PAL_CALL queryFormatSampleCountVk( } VkImageUsageFlags vkImageUsage = 0; - PalImageUsages imageUsages = ImageUsageFromVk(props.optimalTilingFeatures); + PalImageUsages imageUsages = imageUsageFromVk(props.optimalTilingFeatures); PalBool isDepth = (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) != 0; if (isDepth) { vkImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; diff --git a/src/graphics/vulkan/pal_as_vulkan.c b/src/graphics/vulkan/pal_as_vulkan.c index a03c2b39..8331407d 100644 --- a/src/graphics/vulkan/pal_as_vulkan.c +++ b/src/graphics/vulkan/pal_as_vulkan.c @@ -18,10 +18,6 @@ PalResult PAL_CALL createAccelerationstructureVk( DeviceVk* vkDevice = (DeviceVk*)device; BufferVk* buffer = (BufferVk*)info->buffer; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - as = palAllocate(s_Vk.allocator, sizeof(AccelerationStructureVk), 0); if (!as) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -55,7 +51,6 @@ PalResult PAL_CALL createAccelerationstructureVk( as->address = vkDevice->getAccelerationDeviceAddress(vkDevice->handle, &addressInfo); as->device = vkDevice; - as->reserved = PAL_BACKEND_KEY; *outAs = (PalAccelerationStructure*)as; return PAL_RESULT_SUCCESS; } @@ -77,10 +72,6 @@ void PAL_CALL getAccelerationStructureBuildSizeVk( PalAccelerationStructureBuildSize* size) { DeviceVk* vkDevice = (DeviceVk*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return; - } - VkAccelerationStructureGeometryKHR* geometries = nullptr; uint32_t* maxPrimities = nullptr; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; diff --git a/src/graphics/vulkan/pal_buffer_vulkan.c b/src/graphics/vulkan/pal_buffer_vulkan.c index 150df15b..dcf0be99 100644 --- a/src/graphics/vulkan/pal_buffer_vulkan.c +++ b/src/graphics/vulkan/pal_buffer_vulkan.c @@ -199,17 +199,6 @@ PalResult PAL_CALL createBufferVk( DeviceVk* vkDevice = (DeviceVk*)device; MemoryVk* memory = nullptr; - if (info->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - } else if (info->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - } - buffer = palAllocate(s_Vk.allocator, sizeof(BufferVk), 0); if (!buffer) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -281,14 +270,12 @@ PalResult PAL_CALL createBufferVk( } memory->type = memoryType; - memory->reserved = PAL_BACKEND_KEY; buffer->isMemoryManaged = PAL_TRUE; } buffer->memory = memory; buffer->usages = info->usages; buffer->device = vkDevice; - buffer->reserved = PAL_BACKEND_KEY; *outBuffer = (PalBuffer*)buffer; return PAL_RESULT_SUCCESS; } @@ -331,18 +318,19 @@ void PAL_CALL getBufferMemoryRequirementsVk( } } -uint64_t PAL_CALL computeInstanceBufferRequirementsVk(uint32_t instanceCount) +void PAL_CALL computeInstanceStagingSizeVk( + PalDevice* device, + uint32_t instanceCount, + uint64_t* outSize) { - return sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; + *outSize = sizeof(VkAccelerationStructureInstanceKHR) * instanceCount; } -PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( +void PAL_CALL computeImageStagingRequirementsVk( PalDevice* device, PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo, - uint32_t* outBufferRowLength, - uint32_t* outBufferImageHeight, - uint64_t* outSize) + const PalBufferImageCopyInfo* copyInfo, + PalImageStagingRequirements* requirements) { uint32_t imageFormatSize = getFormatSize(imageFormat); uint32_t length = 0; @@ -351,17 +339,16 @@ PalResult PAL_CALL computeImageCopyStagingBufferRequirementsVk( height = copyInfo->bufferImageHeight ? copyInfo->bufferImageHeight : copyInfo->imageHeight; uint32_t rowPitch = length * imageFormatSize; - *outBufferRowLength = length; - *outBufferImageHeight = height; - *outSize = (uint64_t)rowPitch * length * copyInfo->imageDepth; - return PAL_RESULT_SUCCESS; + requirements->bufferRowLength = length; + requirements->bufferImageHeight = height; + requirements->bufferSize = (uint64_t)rowPitch * length * copyInfo->imageDepth; } -PalResult PAL_CALL writeToInstanceBufferVk( +void PAL_CALL writeInstanceStagingVk( PalDevice* device, - void* ptr, + uint32_t instanceCount, PalAccelerationStructureInstance* instances, - uint32_t instanceCount) + void* ptr) { VkAccelerationStructureInstanceKHR* data = ptr; for (int i = 0; i < instanceCount; i++) { @@ -376,15 +363,14 @@ PalResult PAL_CALL writeToInstanceBufferVk( dst->flags = instanceFlagsToVk(src->flags); memcpy(dst->transform.matrix, src->transform, sizeof(float) * 12); } - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL writeToImageCopyStagingBufferVk( +void PAL_CALL writeImageStagingVk( PalDevice* device, - void* ptr, - void* srcData, PalFormat imageFormat, - PalBufferImageCopyInfo* copyInfo) + PalBufferImageCopyInfo* copyInfo, + void* srcData, + void* ptr) { uint32_t imageFormatSize = getFormatSize(imageFormat); uint32_t dstRowPitch = copyInfo->bufferRowLength * imageFormatSize; @@ -405,8 +391,6 @@ PalResult PAL_CALL writeToImageCopyStagingBufferVk( srcRowPitch); } } - - return PAL_RESULT_SUCCESS; } PalResult PAL_CALL bindBufferMemoryVk( @@ -445,11 +429,7 @@ PalResult PAL_CALL mapBufferVk( VkResult result; BufferVk* vkBuffer = (BufferVk*)buffer; DeviceVk* device = vkBuffer->device; - - if (vkBuffer->memory->type == PAL_MEMORY_TYPE_GPU_ONLY) { - return PAL_RESULT_CODE_INVALID_OPERATION; - } - + result = s_Vk.mapMemory(device->handle, vkBuffer->memory->handle, offset, size, 0, outPtr); if (result != VK_SUCCESS) { return makeResultVk(result); diff --git a/src/graphics/vulkan/pal_command_pool_vulkan.c b/src/graphics/vulkan/pal_command_pool_vulkan.c index 5416c2bc..9d1e2f04 100644 --- a/src/graphics/vulkan/pal_command_pool_vulkan.c +++ b/src/graphics/vulkan/pal_command_pool_vulkan.c @@ -34,7 +34,6 @@ PalResult PAL_CALL createCommandPoolVk( } pool->device = vkDevice; - pool->reserved = PAL_BACKEND_KEY; *outPool = (PalCommandPool*)pool; return PAL_RESULT_SUCCESS; } @@ -73,6 +72,15 @@ PalResult PAL_CALL allocateCommandBufferVk( PAL_RESULT_CODE_OUT_OF_MEMORY; } + // allocate memory for the linear allocator. We first start with 4KB + cmdBuffer->allocator.memory = (uint8_t*)palAllocate(s_Vk.allocator, 4096, 0); + if (!cmdBuffer->allocator.memory) { + PAL_RESULT_CODE_OUT_OF_MEMORY; + } + + cmdBuffer->allocator.size = 4096; + cmdBuffer->allocator.offset = 0; + VkCommandBufferAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocateInfo.commandBufferCount = 1; @@ -87,56 +95,54 @@ PalResult PAL_CALL allocateCommandBufferVk( result = s_Vk.allocateCommandBuffer(vkDevice->handle, &allocateInfo, &cmdBuffer->handle); if (result != VK_SUCCESS) { + palFree(s_Vk.allocator, (void*)cmdBuffer->allocator.memory); palFree(s_Vk.allocator, cmdBuffer); return makeResultVk(result); } - // create a gpu buffer if ray tracing is enabled - if (vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - VkBufferCreateInfo bufCreateInfo = {0}; - bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufCreateInfo.size = sizeof(VkTraceRaysIndirectCommandKHR); - bufCreateInfo.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; - bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - result = s_Vk.createBuffer( - vkDevice->handle, - &bufCreateInfo, - &s_Vk.vkAllocator, - &cmdBuffer->buffer); - - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - // allocate CPU upload memory and bind - VkMemoryRequirements memReq = {0}; - s_Vk.getBufferMemoryRequirements(vkDevice->handle, cmdBuffer->buffer, &memReq); - - VkMemoryAllocateInfo allocateInfo = {0}; - allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.allocationSize = memReq.size; - - uint32_t mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; - uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); - allocateInfo.memoryTypeIndex = memoryIndex; - - result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, - &cmdBuffer->bufferMemory); - - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - s_Vk.bindBufferMemory(vkDevice->handle, cmdBuffer->buffer, cmdBuffer->bufferMemory, 0); + // create tmp buffer + VkBufferCreateInfo bufCreateInfo = {0}; + bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufCreateInfo.size = sizeof(VkTraceRaysIndirectCommandKHR); + bufCreateInfo.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; + bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + result = s_Vk.createBuffer( + vkDevice->handle, + &bufCreateInfo, + &s_Vk.vkAllocator, + &cmdBuffer->buffer); + + if (result != VK_SUCCESS) { + return makeResultVk(result); + } + + // allocate CPU upload memory and bind + VkMemoryRequirements memReq = {0}; + s_Vk.getBufferMemoryRequirements(vkDevice->handle, cmdBuffer->buffer, &memReq); + + VkMemoryAllocateInfo bufferAllocateInfo = {0}; + bufferAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + bufferAllocateInfo.allocationSize = memReq.size; + + uint32_t mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + bufferAllocateInfo.memoryTypeIndex = memoryIndex; + + result = s_Vk.allocateMemory( + vkDevice->handle, + &bufferAllocateInfo, + &s_Vk.vkAllocator, + &cmdBuffer->bufferMemory); + + if (result != VK_SUCCESS) { + return makeResultVk(result); } + s_Vk.bindBufferMemory(vkDevice->handle, cmdBuffer->buffer, cmdBuffer->bufferMemory, 0); + cmdBuffer->device = vkDevice; cmdBuffer->pool = vkPool; - cmdBuffer->reserved = PAL_BACKEND_KEY; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; } @@ -150,11 +156,10 @@ void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer) 1, &vkCmdBuffer->handle); - if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING) { - s_Vk.destroyBuffer(vkCmdBuffer->device->handle, vkCmdBuffer->buffer, &s_Vk.vkAllocator); - s_Vk.freeMemory(vkCmdBuffer->device->handle, vkCmdBuffer->bufferMemory, &s_Vk.vkAllocator); - } + s_Vk.destroyBuffer(vkCmdBuffer->device->handle, vkCmdBuffer->buffer, &s_Vk.vkAllocator); + s_Vk.freeMemory(vkCmdBuffer->device->handle, vkCmdBuffer->bufferMemory, &s_Vk.vkAllocator); + palFree(s_Vk.allocator, (void*)vkCmdBuffer->allocator.memory); palFree(s_Vk.allocator, vkCmdBuffer); } @@ -207,17 +212,14 @@ PalResult PAL_CALL submitCommandBufferVk( VkSemaphoreSubmitInfoKHR waitSubmitInfo = {0}; waitSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; waitSubmitInfo.semaphore = waitSemaphoreHandle; - waitSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; + waitSubmitInfo.stageMask = pipelineStagesToVk(info->waitStages); + waitSubmitInfo.value = info->waitValue; VkSemaphoreSubmitInfoKHR signalSubmitInfo = {0}; signalSubmitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR; signalSubmitInfo.semaphore = signalSemaphoreHandle; - signalSubmitInfo.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR; - - if (vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { - waitSubmitInfo.value = info->waitValue; - signalSubmitInfo.value = info->signalValue; - } + signalSubmitInfo.stageMask = pipelineStagesToVk(info->signalStages); + signalSubmitInfo.value = info->signalValue; VkSubmitInfo2KHR submitInfo = {0}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR; diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c index 171f00a8..29b8d79e 100644 --- a/src/graphics/vulkan/pal_commands_vulkan.c +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -8,6 +8,11 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" +typedef struct { + VkAccessFlags2 access; + VkImageLayout layout; +} BarrierInfo; + static void commitShaderbindingTableUpdate( CommandBufferVk* cmdBuffer, ShaderBindingTableVk* sbt) @@ -44,163 +49,137 @@ static void commitShaderbindingTableUpdate( sbt->isDirty = PAL_FALSE; } -static Barrier barrierToVk(PalUsageState state) +static BarrierInfo barrierToVk(PalUsageState state) { - Barrier barrier = {0}; + BarrierInfo barrier = {0}; switch (state) { case PAL_USAGE_STATE_PRESENT: { - barrier.stage = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR; barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; return barrier; } case PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE: { - barrier.stage = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR; barrier.access = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; return barrier; } case PAL_USAGE_STATE_DEPTH_ATTACHMENT_READ: { - barrier.stage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.stage |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; return barrier; } case PAL_USAGE_STATE_DEPTH_ATTACHMENT_WRITE: { - barrier.stage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.stage |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; return barrier; } case PAL_USAGE_STATE_STENCIL_ATTACHMENT_READ: { - barrier.stage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.stage |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; return barrier; } case PAL_USAGE_STATE_STENCIL_ATTACHMENT_WRITE: { - barrier.stage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR; - barrier.stage |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR; barrier.access = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; return barrier; } case PAL_USAGE_STATE_FRAGMENT_SHADING_RATE_ATTACHMENT_READ: { - barrier.stage = VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; barrier.access = VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR; return barrier; } case PAL_USAGE_STATE_TRANSFER_READ: { - barrier.stage = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; barrier.access = VK_ACCESS_2_TRANSFER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; return barrier; } case PAL_USAGE_STATE_TRANSFER_WRITE: { - barrier.stage = VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR; barrier.access = VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; return barrier; } case PAL_USAGE_STATE_VERTEX_READ: { - barrier.stage = VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR; barrier.access = VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_INDEX_READ: { - barrier.stage = VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR; barrier.access = VK_ACCESS_2_INDEX_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_INDIRECT_READ: { - barrier.stage = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR; barrier.access = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_UNIFORM_READ: { - barrier.stage = 0; barrier.access = VK_ACCESS_2_UNIFORM_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_SHADER_READ: { - barrier.stage = 0; barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; return barrier; } case PAL_USAGE_STATE_SHADER_WRITE: { - barrier.stage = 0; barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_GENERAL; return barrier; } case PAL_USAGE_STATE_STORAGE_READ: { - barrier.stage = 0; barrier.access = VK_ACCESS_2_SHADER_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_GENERAL; return barrier; } case PAL_USAGE_STATE_STORAGE_WRITE: { - barrier.stage = 0; barrier.access = VK_ACCESS_2_SHADER_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_GENERAL; return barrier; } case PAL_USAGE_STATE_HOST_READ: { - barrier.stage = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; barrier.access = VK_ACCESS_2_HOST_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_HOST_WRITE: { - barrier.stage = VK_PIPELINE_STAGE_2_HOST_BIT_KHR; barrier.access = VK_ACCESS_2_HOST_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ: { - barrier.stage = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } case PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE: { - barrier.stage = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; barrier.access = VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; } } - barrier.stage = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR; barrier.access = 0; barrier.layout = VK_IMAGE_LAYOUT_UNDEFINED; return barrier; @@ -226,19 +205,18 @@ static VkRenderingFlags renderingFlagToVk(PalRenderingFlags flags) static VkResolveModeFlags resolveModeToVk(PalResolveMode mode) { - // TODO: fix switch (mode) { case PAL_RESOLVE_MODE_SAMPLE_ZERO: return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; case PAL_RESOLVE_MODE_AVERAGE: - return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + return VK_RESOLVE_MODE_AVERAGE_BIT_KHR; case PAL_RESOLVE_MODE_MIN: - return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + return VK_RESOLVE_MODE_MIN_BIT_KHR; case PAL_RESOLVE_MODE_MAX: - return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR; + return VK_RESOLVE_MODE_MAX_BIT_KHR; } return VK_RESOLVE_MODE_NONE_KHR; @@ -257,19 +235,21 @@ PalResult PAL_CALL cmdBeginVk( VkCommandBufferInheritanceRenderingInfoKHR layout = {0}; layout.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; + vkCmdBuffer->allocator.offset = 0; // reset VkFormat format = VK_FORMAT_UNDEFINED; VkFormat* colorAttachments = nullptr; - colorAttachments = palAllocate( - s_Vk.allocator, - sizeof(VkFormat) * info->colorAttachentCount, - 0); - - if (!colorAttachments) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } if (!vkCmdBuffer->primary) { // secondary command buffer + colorAttachments = palLinearAlloc( + &vkCmdBuffer->allocator, + sizeof(VkFormat) * info->colorAttachentCount, + 0); + + if (!colorAttachments) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + for (int i = 0; i < info->colorAttachentCount; i++) { format = formatToVk(info->colorAttachmentsFormat[i]); colorAttachments[i] = format; @@ -298,8 +278,6 @@ PalResult PAL_CALL cmdBeginVk( if (result != VK_SUCCESS) { return makeResultVk(result); } - - palFree(s_Vk.allocator, colorAttachments); return PAL_RESULT_SUCCESS; } @@ -324,16 +302,12 @@ PalResult PAL_CALL cmdExecuteCommandBufferVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetFragmentShadingRateVk( +void PAL_CALL cmdSetFragmentShadingRateVk( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkExtent2D size = getShadingRateSizeVk(state->rate); VkFragmentShadingRateCombinerOpKHR combinerOps[2]; for (int i = 0; i < 2; i++) { @@ -341,10 +315,9 @@ PalResult PAL_CALL cmdSetFragmentShadingRateVk( } device->cmdSetFragmentShadingRate(vkCmdBuffer->handle, &size, combinerOps); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawMeshTasksVk( +void PAL_CALL cmdDrawMeshTasksVk( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, @@ -352,15 +325,10 @@ PalResult PAL_CALL cmdDrawMeshTasksVk( { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - device->cmdDrawMeshTask(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( +void PAL_CALL cmdDrawMeshTasksIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t drawCount) @@ -369,14 +337,6 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( DeviceVk* device = vkCmdBuffer->device; BufferVk* vkBuffer = (BufferVk*)buffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); device->cmdDrawMeshTaskIndirect( vkCmdBuffer->handle, @@ -384,11 +344,9 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectVk( 0, drawCount, stride); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( +void PAL_CALL cmdDrawMeshTasksIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -399,18 +357,6 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( BufferVk* vkBuffer = (BufferVk*)buffer; BufferVk* vkCountBuffer = (BufferVk*)countBuffer; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - - if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); device->cmdDrawMeshTaskIndirectCount( vkCmdBuffer->handle, @@ -420,38 +366,37 @@ PalResult PAL_CALL cmdDrawMeshTasksIndirectCountVk( 0, maxDrawCount, stride); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBuildAccelerationStructureVk( +void PAL_CALL cmdBuildAccelerationStructureVk( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - + VkAccelerationStructureGeometryKHR* geometries = nullptr; VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; const VkAccelerationStructureBuildRangeInfoKHR** tmpRangeInfos = nullptr; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - tmpRangeInfos = palAllocate(s_Vk.allocator, sizeof(void*) * info->count, 0); - geometries = palAllocate( - s_Vk.allocator, + tmpRangeInfos = palLinearAlloc( + &vkCmdBuffer->allocator, + sizeof(void*) * info->count, + 0); + + geometries = palLinearAlloc( + &vkCmdBuffer->allocator, sizeof(VkAccelerationStructureGeometryKHR) * info->count, 0); - rangeInfos = palAllocate( - s_Vk.allocator, + rangeInfos = palLinearAlloc( + &vkCmdBuffer->allocator, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->count, 0); if (!tmpRangeInfos || !rangeInfos || !geometries) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; + return; } memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->count); @@ -467,13 +412,9 @@ PalResult PAL_CALL cmdBuildAccelerationStructureVk( 1, &buildInfo, tmpRangeInfos); - - palFree(s_Vk.allocator, geometries); - palFree(s_Vk.allocator, rangeInfos); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBeginRenderingVk( +void PAL_CALL cmdBeginRenderingVk( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { @@ -485,13 +426,13 @@ PalResult PAL_CALL cmdBeginRenderingVk( VkRenderingAttachmentInfoKHR stencilAttachment = {0}; VkRenderingAttachmentInfoKHR* colorAttachments = nullptr; - colorAttachments = palAllocate( - s_Vk.allocator, + colorAttachments = palLinearAlloc( + &vkCmdBuffer->allocator, sizeof(VkRenderingAttachmentInfoKHR) * info->colorAttachentCount, 0); if (!colorAttachments) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; + return; } VkRenderingAttachmentInfoKHR* attachment = nullptr; @@ -653,19 +594,15 @@ PalResult PAL_CALL cmdBeginRenderingVk( rendering.flags = renderingFlagToVk(info->flags); vkCmdBuffer->device->cmdBeginRendering(vkCmdBuffer->handle, &rendering); - - palFree(s_Vk.allocator, colorAttachments); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer) +void PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; vkCmdBuffer->device->cmdEndRendering(vkCmdBuffer->handle); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdCopyBufferVk( +void PAL_CALL cmdCopyBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* dst, PalBuffer* src, @@ -680,11 +617,9 @@ PalResult PAL_CALL cmdCopyBufferVk( copyRegion.dstOffset = copyInfo->dstOffset; copyRegion.srcOffset = copyInfo->srcOffset; s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, srcBuffer->handle, dstBuffer->handle, 1, ©Region); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdCopyBufferToImageVk( +void PAL_CALL cmdCopyBufferToImageVk( PalCommandBuffer* cmdBuffer, PalImage* dstImage, PalBuffer* srcBuffer, @@ -719,11 +654,9 @@ PalResult PAL_CALL cmdCopyBufferToImageVk( VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdCopyImageVk( +void PAL_CALL cmdCopyImageVk( PalCommandBuffer* cmdBuffer, PalImage* dst, PalImage* src, @@ -764,11 +697,9 @@ PalResult PAL_CALL cmdCopyImageVk( VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdCopyImageToBufferVk( +void PAL_CALL cmdCopyImageToBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, PalImage* srcImage, @@ -803,40 +734,26 @@ PalResult PAL_CALL cmdCopyImageToBufferVk( dst->handle, 1, ©Region); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBindPipelineVk( +void PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; PipelineVk* vkPipeline = (PipelineVk*)pipeline; s_Vk.cmdBindPipeline(vkCmdBuffer->handle, vkPipeline->bindPoint, vkPipeline->handle); - vkCmdBuffer->pipeline = vkPipeline; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetViewportVk( +void PAL_CALL cmdSetViewportVk( PalCommandBuffer* cmdBuffer, uint32_t count, PalViewport* viewports) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - VkViewport cachedViewport; VkViewport* vkViewports = nullptr; - if (count > 1) { - vkViewports = palAllocate(s_Vk.allocator, sizeof(VkViewport) * count, 0); - if (!vkViewports) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } - - } else { - vkViewports = &cachedViewport; - } - + vkViewports = palLinearAlloc(&vkCmdBuffer->allocator, sizeof(VkViewport) * count, 0); for (int i = 0; i < count; i++) { VkViewport* tmp = &vkViewports[i]; tmp->x = viewports[i].x; @@ -848,30 +765,16 @@ PalResult PAL_CALL cmdSetViewportVk( } s_Vk.cmdSetViewports(vkCmdBuffer->handle, 0, count, vkViewports); - if (count > 1) { - palFree(s_Vk.allocator, vkViewports); - } - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetScissorsVk( +void PAL_CALL cmdSetScissorsVk( PalCommandBuffer* cmdBuffer, uint32_t count, PalRect2D* scissors) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - VkRect2D cachedScissor; VkRect2D* vkScissors = nullptr; - if (count > 1) { - vkScissors = palAllocate(s_Vk.allocator, sizeof(VkRect2D) * count, 0); - if (!vkScissors) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } - - } else { - vkScissors = &cachedScissor; - } - + vkScissors = palLinearAlloc(&vkCmdBuffer->allocator, sizeof(VkRect2D) * count, 0); for (int i = 0; i < count; i++) { VkRect2D* tmp = &vkScissors[i]; tmp->offset.x = scissors[i].x; @@ -881,13 +784,9 @@ PalResult PAL_CALL cmdSetScissorsVk( } s_Vk.cmdSetScissors(vkCmdBuffer->handle, 0, count, vkScissors); - if (count > 1) { - palFree(s_Vk.allocator, vkScissors); - } - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBindVertexBuffersVk( +void PAL_CALL cmdBindVertexBuffersVk( PalCommandBuffer* cmdBuffer, uint32_t firstSlot, uint32_t count, @@ -895,31 +794,17 @@ PalResult PAL_CALL cmdBindVertexBuffersVk( uint64_t* offsets) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - VkBuffer cachedbuffer = nullptr; VkBuffer* vkBuffers = nullptr; - if (count > 1) { - vkBuffers = palAllocate(s_Vk.allocator, sizeof(VkBuffer) * count, 0); - if (!vkBuffers) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } - - } else { - vkBuffers = &cachedbuffer; - } - + vkBuffers = palLinearAlloc(&vkCmdBuffer->allocator, sizeof(VkBuffer) * count, 0); for (int i = 0; i < count; i++) { BufferVk* tmp = (BufferVk*)buffers[i]; vkBuffers[i] = tmp->handle; } s_Vk.cmdBindVertexBuffers(vkCmdBuffer->handle, firstSlot, count, vkBuffers, offsets); - if (count > 1) { - palFree(s_Vk.allocator, vkBuffers); - } - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBindIndexBufferVk( +void PAL_CALL cmdBindIndexBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint64_t offset, @@ -933,10 +818,9 @@ PalResult PAL_CALL cmdBindIndexBufferVk( } s_Vk.cmdBindIndexBuffer(vkCmdBuffer->handle, vkBuffer->handle, offset, bufferType); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawVk( +void PAL_CALL cmdDrawVk( PalCommandBuffer* cmdBuffer, uint32_t vertexCount, uint32_t instanceCount, @@ -945,10 +829,9 @@ PalResult PAL_CALL cmdDrawVk( { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; s_Vk.cmdDraw(vkCmdBuffer->handle, vertexCount, instanceCount, firstVertex, firstInstance); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawIndirectVk( +void PAL_CALL cmdDrawIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count) @@ -956,20 +839,10 @@ PalResult PAL_CALL cmdDrawIndirectVk( CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; BufferVk* vkBuffer = (BufferVk*)buffer; uint32_t stride = sizeof(VkDrawIndirectCommand); - - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - s_Vk.cmdDrawIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawIndirectCountVk( +void PAL_CALL cmdDrawIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -980,18 +853,6 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( BufferVk* vkCountBuffer = (BufferVk*)countBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - - if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - uint32_t stride = sizeof(VkDrawIndirectCommand); device->cmdDrawIndirectCount( vkCmdBuffer->handle, @@ -1001,11 +862,9 @@ PalResult PAL_CALL cmdDrawIndirectCountVk( 0, maxDrawCount, stride); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawIndexedVk( +void PAL_CALL cmdDrawIndexedVk( PalCommandBuffer* cmdBuffer, uint32_t indexCount, uint32_t instanceCount, @@ -1021,11 +880,9 @@ PalResult PAL_CALL cmdDrawIndexedVk( firstIndex, vertexOffset, firstInstance); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawIndexedIndirectVk( +void PAL_CALL cmdDrawIndexedIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, uint32_t count) @@ -1033,20 +890,10 @@ PalResult PAL_CALL cmdDrawIndexedIndirectVk( CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; BufferVk* vkBuffer = (BufferVk*)buffer; uint32_t stride = sizeof(VkDrawIndexedIndirectCommand); - - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - s_Vk.cmdDrawIndexedIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( +void PAL_CALL cmdDrawIndexedIndirectCountVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, PalBuffer* countBuffer, @@ -1057,18 +904,6 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( BufferVk* vkCountBuffer = (BufferVk*)countBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - - if (!(vkCountBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - uint32_t stride = sizeof(VkDrawIndexedIndirectCommand); device->cmdDrawIndexedIndirectCount( vkCmdBuffer->handle, @@ -1078,68 +913,52 @@ PalResult PAL_CALL cmdDrawIndexedIndirectCountVk( 0, maxDrawCount, stride); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdAccelerationStructureBarrierVk( +void PAL_CALL cmdAccelerationStructureBarrierVk( PalCommandBuffer* cmdBuffer, PalAccelerationStructure* as, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalBarrierInfo* info) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; PipelineVk* pipeline = vkCmdBuffer->pipeline; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkMemoryBarrier2KHR barrier = {0}; barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR; - Barrier old = barrierToVk(oldUsageState); - Barrier new = barrierToVk(oldUsageState); - barrier.srcStageMask = old.stage; + BarrierInfo old = barrierToVk(info->oldState); + BarrierInfo new = barrierToVk(info->newState); + + barrier.srcStageMask = pipelineStagesToVk(info->srcStages); barrier.srcAccessMask = old.access; - barrier.dstStageMask = new.stage; + barrier.dstStageMask = pipelineStagesToVk(info->dstStages); barrier.dstAccessMask = new.access; VkDependencyInfo dependencyInfo = {0}; dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; dependencyInfo.memoryBarrierCount = 1; dependencyInfo.pMemoryBarriers = &barrier; - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdImageBarrierVk( +void PAL_CALL cmdImageBarrierVk( PalCommandBuffer* cmdBuffer, PalImage* image, PalImageSubresourceRange* subresourceRange, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalBarrierInfo* info) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; PipelineVk* pipeline = vkCmdBuffer->pipeline; ImageVk* vkImage = (ImageVk*)image; VkImageMemoryBarrier2KHR barrier = {0}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR; - Barrier old = barrierToVk(oldUsageState); - Barrier new = barrierToVk(oldUsageState); - if (old.stage == 0) { - old.stage = pipeline->stages; - } + BarrierInfo old = barrierToVk(info->oldState); + BarrierInfo new = barrierToVk(info->newState); - if (new.stage == 0) { - new.stage = pipeline->stages; - } - - barrier.srcStageMask = old.stage; + barrier.srcStageMask = pipelineStagesToVk(info->srcStages); barrier.srcAccessMask = old.access; barrier.oldLayout = old.layout; - barrier.dstStageMask = new.stage; + barrier.dstStageMask = pipelineStagesToVk(info->dstStages); barrier.dstAccessMask = new.access; barrier.newLayout = new.layout; @@ -1154,36 +973,26 @@ PalResult PAL_CALL cmdImageBarrierVk( dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; dependencyInfo.imageMemoryBarrierCount = 1; dependencyInfo.pImageMemoryBarriers = &barrier; - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBufferBarrierVk( +void PAL_CALL cmdBufferBarrierVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer, - PalUsageState oldUsageState, - PalUsageState newUsageState) + PalBarrierInfo* info) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; PipelineVk* pipeline = vkCmdBuffer->pipeline; BufferVk* vkBuffer = (BufferVk*)buffer; VkBufferMemoryBarrier2KHR barrier = {0}; barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; - Barrier old = barrierToVk(oldUsageState); - Barrier new = barrierToVk(oldUsageState); - - if (old.stage == 0) { - old.stage = pipeline->stages; - } - if (new.stage == 0) { - new.stage = pipeline->stages; - } + BarrierInfo old = barrierToVk(info->oldState); + BarrierInfo new = barrierToVk(info->newState); - barrier.srcStageMask = old.stage; + barrier.srcStageMask = pipelineStagesToVk(info->srcStages); barrier.srcAccessMask = old.access; - barrier.dstStageMask = new.stage; + barrier.dstStageMask = pipelineStagesToVk(info->dstStages); barrier.dstAccessMask = new.access; barrier.buffer = vkBuffer->handle; @@ -1194,12 +1003,10 @@ PalResult PAL_CALL cmdBufferBarrierVk( dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; dependencyInfo.bufferMemoryBarrierCount = 1; dependencyInfo.pBufferMemoryBarriers = &barrier; - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDispatchVk( +void PAL_CALL cmdDispatchVk( PalCommandBuffer* cmdBuffer, uint32_t groupCountX, uint32_t groupCountY, @@ -1207,10 +1014,9 @@ PalResult PAL_CALL cmdDispatchVk( { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; s_Vk.cmdDispatch(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDispatchBaseVk( +void PAL_CALL cmdDispatchBaseVk( PalCommandBuffer* cmdBuffer, uint32_t baseGroupX, uint32_t baseGroupY, @@ -1221,10 +1027,7 @@ PalResult PAL_CALL cmdDispatchBaseVk( { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_DISPATCH_BASE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - + device->cmdDispatchBase( vkCmdBuffer->handle, baseGroupX, @@ -1233,29 +1036,18 @@ PalResult PAL_CALL cmdDispatchBaseVk( groupCountX, groupCountY, groupCountZ); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdDispatchIndirectVk( +void PAL_CALL cmdDispatchIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; BufferVk* vkBuffer = (BufferVk*)buffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - s_Vk.cmdDispatchIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdTraceRaysVk( +void PAL_CALL cmdTraceRaysVk( PalCommandBuffer* cmdBuffer, PalShaderBindingTable* sbt, uint32_t raygenIndex, @@ -1267,10 +1059,6 @@ PalResult PAL_CALL cmdTraceRaysVk( DeviceVk* device = vkCmdBuffer->device; ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; - if (!(device->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkStridedDeviceAddressRegionKHR raygenAddress = {0}; raygenAddress.size = vkSbt->raygen.region.size; raygenAddress.stride = vkSbt->raygen.region.stride; @@ -1288,11 +1076,9 @@ PalResult PAL_CALL cmdTraceRaysVk( width, height, depth); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdTraceRaysIndirectVk( +void PAL_CALL cmdTraceRaysIndirectVk( PalCommandBuffer* cmdBuffer, uint32_t raygenIndex, PalShaderBindingTable* sbt, @@ -1302,14 +1088,6 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; BufferVk* vkBuffer = (BufferVk*)buffer; - if (!(vkCmdBuffer->device->features & PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_INDIRECT)) { - return PAL_RESULT_CODE_INVALID_HANDLE; - } - PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; vkSbt->raygen.region.deviceAddress = address; @@ -1352,11 +1130,9 @@ PalResult PAL_CALL cmdTraceRaysIndirectVk( &vkSbt->hit.region, &vkSbt->callable.region, bufAddress); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdBindDescriptorSetVk( +void PAL_CALL cmdBindDescriptorSetVk( PalCommandBuffer* cmdBuffer, uint32_t setIndex, PalDescriptorSet* set) @@ -1374,11 +1150,9 @@ PalResult PAL_CALL cmdBindDescriptorSetVk( &vkSet->handle, 0, nullptr); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdPushConstantsVk( +void PAL_CALL cmdPushConstantsVk( PalCommandBuffer* cmdBuffer, uint64_t offset, uint64_t size, @@ -1394,21 +1168,15 @@ PalResult PAL_CALL cmdPushConstantsVk( offset, size, value); - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetCullModeVk( +void PAL_CALL cmdSetCullModeVk( PalCommandBuffer* cmdBuffer, PalCullMode cullMode) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkCullModeFlags vkCullMode = 0; switch (cullMode) { case PAL_CULL_MODE_BACK: @@ -1422,20 +1190,15 @@ PalResult PAL_CALL cmdSetCullModeVk( } device->cmdSetCullMode(vkCmdBuffer->handle, vkCullMode); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetFrontFaceVk( +void PAL_CALL cmdSetFrontFaceVk( PalCommandBuffer* cmdBuffer, PalFrontFace frontFace) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkFrontFace vkFrontFace = 0; switch (frontFace) { case PAL_FRONT_FACE_CLOCKWISE: @@ -1446,19 +1209,15 @@ PalResult PAL_CALL cmdSetFrontFaceVk( } device->cmdSetFrontFace(vkCmdBuffer->handle, vkFrontFace); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetPrimitiveTopologyVk( +void PAL_CALL cmdSetPrimitiveTopologyVk( PalCommandBuffer* cmdBuffer, PalPrimitiveTopology topology) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - + VkPrimitiveTopology vkTopology = 0; switch (topology) { case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { @@ -1488,38 +1247,27 @@ PalResult PAL_CALL cmdSetPrimitiveTopologyVk( } device->cmdSetPrimitiveTopology(vkCmdBuffer->handle, vkTopology); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetDepthTestEnableVk( +void PAL_CALL cmdSetDepthTestEnableVk( PalCommandBuffer* cmdBuffer, PalBool enable) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - device->cmdSetDepthTestEnable(vkCmdBuffer->handle, enable); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetDepthWriteEnableVk( +void PAL_CALL cmdSetDepthWriteEnableVk( PalCommandBuffer* cmdBuffer, PalBool enable) { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - device->cmdSetDepthWriteEnable(vkCmdBuffer->handle, enable); - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL cmdSetStencilOpVk( +void PAL_CALL cmdSetStencilOpVk( PalCommandBuffer* cmdBuffer, PalStencilFaceFlags faceMask, PalStencilOp failOp, @@ -1529,10 +1277,6 @@ PalResult PAL_CALL cmdSetStencilOpVk( { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - if (!(device->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkStencilFaceFlags faceFlags = 0; if (faceMask & PAL_STENCIL_FACE_FLAG_BACK) { faceFlags |= VK_STENCIL_FACE_BACK_BIT; @@ -1554,8 +1298,6 @@ PalResult PAL_CALL cmdSetStencilOpVk( passOp, depthFailOp, compareOp); - - return PAL_RESULT_SUCCESS; } #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_descriptors_vulkan.c b/src/graphics/vulkan/pal_descriptors_vulkan.c index 7eec3f89..e5b64745 100644 --- a/src/graphics/vulkan/pal_descriptors_vulkan.c +++ b/src/graphics/vulkan/pal_descriptors_vulkan.c @@ -47,15 +47,6 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( VkDescriptorSetLayoutBindingFlagsCreateInfoEXT flagsCreateInfo = {0}; flagsCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT; - PalBool hasDescriptorIndexing = PAL_FALSE; - if (vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - hasDescriptorIndexing = PAL_TRUE; - } - - if (info->flags != 0 && !hasDescriptorIndexing) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - layout = palAllocate(s_Vk.allocator, sizeof(DescriptorSetLayoutVk), 0); bindings = palAllocate(s_Vk.allocator, sizeof(VkDescriptorSetLayoutBinding) * count, 0); if (!layout || !bindings) { @@ -116,7 +107,6 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( layout->device = vkDevice; layout->flags = info->flags; - layout->reserved = PAL_BACKEND_KEY; *outLayout = (PalDescriptorSetLayout*)layout; return PAL_RESULT_SUCCESS; } @@ -145,15 +135,6 @@ PalResult PAL_CALL createDescriptorPoolVk( VkDescriptorPoolCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - PalBool hasDescriptorIndexing = PAL_FALSE; - if (vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { - hasDescriptorIndexing = PAL_TRUE; - } - - if (info->flags != 0 && !hasDescriptorIndexing) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; } @@ -188,7 +169,6 @@ PalResult PAL_CALL createDescriptorPoolVk( pool->device = vkDevice; pool->flags = info->flags; - pool->reserved = PAL_BACKEND_KEY; *outPool = (PalDescriptorPool*)pool; return PAL_RESULT_SUCCESS; } @@ -219,13 +199,6 @@ PalResult PAL_CALL allocateDescriptorSetVk( DescriptorSetLayoutVk* vkLayout = (DescriptorSetLayoutVk*)layout; DescriptorSetVk* set = nullptr; - PalBool isPoolValid = vkPool->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; - PalBool isLayoutValid = vkLayout->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; - if (isPoolValid != isLayoutValid) { - // we check if both are true or false - return PAL_RESULT_CODE_INVALID_OPERATION; - } - set = palAllocate(s_Vk.allocator, sizeof(DescriptorSetVk), 0); if (!set) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -245,7 +218,6 @@ PalResult PAL_CALL allocateDescriptorSetVk( set->pool = vkPool; set->device = vkDevice; - set->reserved = PAL_BACKEND_KEY; *outSet = (PalDescriptorSet*)set; return PAL_RESULT_SUCCESS; } @@ -350,11 +322,6 @@ PalResult PAL_CALL updateDescriptorSetVk( bufferInfo->buffer = vkBuffer->handle; bufferInfo->offset = tmp->offset; bufferInfo->range = tmp->size; - - } else { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } } } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { @@ -362,11 +329,6 @@ PalResult PAL_CALL updateDescriptorSetVk( PalDescriptorTLASInfo* tmp = &info->tlasInfos[j]; AccelerationStructureVk* as = (AccelerationStructureVk*)tmp->tlas; tlas[tlasCount + j] = as->handle; - - } else { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } } } else { @@ -378,11 +340,6 @@ PalResult PAL_CALL updateDescriptorSetVk( SamplerVk* vkSampler = (SamplerVk*)tmp->sampler; imageInfo->sampler = vkSampler->handle; imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - } else { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } } } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { @@ -393,11 +350,6 @@ PalResult PAL_CALL updateDescriptorSetVk( imageInfo->sampler = nullptr; imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; imageInfo->imageView = vkImageView->handle; - - } else { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } } } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { @@ -408,11 +360,6 @@ PalResult PAL_CALL updateDescriptorSetVk( imageInfo->sampler = nullptr; imageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo->imageView = vkImageView->handle; - - } else { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } } } } diff --git a/src/graphics/vulkan/pal_device_vulkan.c b/src/graphics/vulkan/pal_device_vulkan.c index 9c1dd3b9..3178086e 100644 --- a/src/graphics/vulkan/pal_device_vulkan.c +++ b/src/graphics/vulkan/pal_device_vulkan.c @@ -722,7 +722,6 @@ PalResult PAL_CALL createDeviceVk( device->phyQueueIndex = 0; device->queueFamilyCount = queueFamilyCount; device->phyQueueCount = phyQueueCount; - device->features = features; // get queues for (int i = 0; i < queueFamilyCount; i++) { @@ -800,7 +799,7 @@ PalResult PAL_CALL createDeviceVk( palFree(s_Vk.allocator, queueFamilyProps); palFree(s_Vk.allocator, queueCreateInfos); - device->reserved = PAL_BACKEND_KEY; + device->features = features; *outDevice = (PalDevice*)device; return PAL_RESULT_SUCCESS; } @@ -861,46 +860,34 @@ PalResult PAL_CALL allocateMemoryVk( return makeResultVk(result); } + memory->device = vkDevice; memory->type = type; - memory->reserved = PAL_BACKEND_KEY; *outMemory = (PalMemory*)memory; return PAL_RESULT_SUCCESS; } -void PAL_CALL freeMemoryVk( - PalDevice* device, - PalMemory* memory) +void PAL_CALL freeMemoryVk(PalMemory* memory) { - DeviceVk* vkDevice = (DeviceVk*)device; MemoryVk* vkMemory = (MemoryVk*)memory; - s_Vk.freeMemory(vkDevice->handle, vkMemory->handle, &s_Vk.vkAllocator); + s_Vk.freeMemory(vkMemory->device->handle, vkMemory->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, vkMemory); } -PalResult PAL_CALL querySamplerAnisotropyCapabilitiesVk( +void PAL_CALL querySamplerAnisotropyCapabilitiesVk( PalDevice* device, PalSamplerAnisotropyCapabilities* caps) { DeviceVk* vkDevice = (DeviceVk*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkPhysicalDeviceProperties props = {0}; s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); caps->maxAnisotropy = props.limits.maxSamplerAnisotropy; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryMultiViewCapabilitiesVk( +void PAL_CALL queryMultiViewCapabilitiesVk( PalDevice* device, PalMultiViewCapabilities* caps) { DeviceVk* vkDevice = (DeviceVk*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkPhysicalDeviceMultiviewPropertiesKHR props = {0}; VkPhysicalDeviceProperties2 properties2 = {0}; props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; @@ -912,34 +899,23 @@ PalResult PAL_CALL queryMultiViewCapabilitiesVk( if (caps->maxViewCount == 0) { caps->maxViewCount = 1; } - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryMultiViewportCapabilitiesVk( +void PAL_CALL queryMultiViewportCapabilitiesVk( PalDevice* device, PalMultiViewportCapabilities* caps) { DeviceVk* vkDevice = (DeviceVk*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkPhysicalDeviceProperties props = {0}; s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); caps->maxCount = props.limits.maxViewports; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryDepthStencilCapabilitiesVk( +void PAL_CALL queryDepthStencilCapabilitiesVk( PalDevice* device, PalDepthStencilCapabilities* caps) { DeviceVk* vkDevice = (DeviceVk*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceDepthStencilResolvePropertiesKHR props = {0}; @@ -983,19 +959,13 @@ PalResult PAL_CALL queryDepthStencilCapabilitiesVk( if (props.supportedStencilResolveModes & VK_RESOLVE_MODE_MAX_BIT_KHR) { caps->supportedStencilResolveModes |= (1u << PAL_RESOLVE_MODE_MAX); } - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk( +void PAL_CALL queryFragmentShadingRateCapabilitiesVk( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { DeviceVk* vkDevice = (DeviceVk*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceFragmentShadingRatePropertiesKHR props = {0}; @@ -1028,19 +998,13 @@ PalResult PAL_CALL queryFragmentShadingRateCapabilitiesVk( size = props.maxFragmentShadingRateAttachmentTexelSize; caps->maxTexelWidth = size.width; caps->maxTexelHeight = size.height; - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryMeshShaderCapabilitiesVk( +void PAL_CALL queryMeshShaderCapabilitiesVk( PalDevice* device, PalMeshShaderCapabilities* caps) { DeviceVk* vkDevice = (DeviceVk*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceMeshShaderPropertiesEXT props = {0}; @@ -1060,19 +1024,13 @@ PalResult PAL_CALL queryMeshShaderCapabilitiesVk( caps->maxWorkGroupCount[0] = props.maxMeshWorkGroupCount[0]; caps->maxWorkGroupCount[1] = props.maxMeshWorkGroupCount[1]; caps->maxWorkGroupCount[2] = props.maxMeshWorkGroupCount[2]; - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryRayTracingCapabilitiesVk( +void PAL_CALL queryRayTracingCapabilitiesVk( PalDevice* device, PalRayTracingCapabilities* caps) { DeviceVk* vkDevice = (DeviceVk*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceRayTracingPipelinePropertiesKHR props = {0}; @@ -1091,19 +1049,13 @@ PalResult PAL_CALL queryRayTracingCapabilitiesVk( caps->maxPayloadSize = 64; // safe caps->maxDispatchInvocations = props.maxRayDispatchInvocationCount; - - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( +void PAL_CALL queryDescriptorIndexingCapabilitiesVk( PalDevice* device, PalDescriptorIndexingCapabilities* caps) { DeviceVk* vkDevice = (DeviceVk*)device; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; @@ -1164,8 +1116,6 @@ PalResult PAL_CALL queryDescriptorIndexingCapabilitiesVk( uint32_t tmp2 = accProps.maxDescriptorSetUpdateAfterBindAccelerationStructures; caps->maxPerStageAccelerationStructure = tmp; caps->maxPerSetAccelerationStructure = tmp2; - - return PAL_RESULT_SUCCESS; } PalResult PAL_CALL createQueueVk( @@ -1245,7 +1195,6 @@ PalResult PAL_CALL createQueueVk( queue->phyQueue = phyQueue; queue->usage = queueFlag; queue->device = vkDevice; - queue->reserved = PAL_BACKEND_KEY; *outQueue = (PalQueue*)queue; return PAL_RESULT_SUCCESS; } @@ -1320,37 +1269,6 @@ PalResult PAL_CALL createShaderVk( for (int i = 0; i < info->entryCount; i++) { ShaderEntry* entry = &shader->entries[i]; - - // clang-format off - if (info->entries[i].stage == PAL_SHADER_STAGE_MESH || - info->entries[i].stage == PAL_SHADER_STAGE_TASK) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_MESH_SHADER)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_GEOMETRY) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_CONTROL || - info->entries[i].stage == PAL_SHADER_STAGE_TESSELLATION_EVALUATION) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - - } else if (info->entries[i].stage == PAL_SHADER_STAGE_RAYGEN || - info->entries[i].stage == PAL_SHADER_STAGE_CLOSEST_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_ANY_HIT || - info->entries[i].stage == PAL_SHADER_STAGE_MISS || - info->entries[i].stage == PAL_SHADER_STAGE_INTERSECTION || - info->entries[i].stage == PAL_SHADER_STAGE_CALLABLE) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - } - // clang-format on - strncpy(entry->entryName, info->entries[i].entryName, PAL_SHADER_ENTRY_NAME_SIZE); entry->entryName[PAL_SHADER_ENTRY_NAME_SIZE - 1] = '\0'; entry->patchControlPoints = info->entries[i].patchControlPoints; @@ -1370,7 +1288,6 @@ PalResult PAL_CALL createShaderVk( shader->device = vkDevice; shader->entryCount = info->entryCount; - shader->reserved = PAL_BACKEND_KEY; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/vulkan/pal_image_vulkan.c b/src/graphics/vulkan/pal_image_vulkan.c index 099b0aea..7ce6fbf0 100644 --- a/src/graphics/vulkan/pal_image_vulkan.c +++ b/src/graphics/vulkan/pal_image_vulkan.c @@ -232,7 +232,6 @@ PalResult PAL_CALL createImageVk( } memory->type = memoryType; - memory->reserved = PAL_BACKEND_KEY; image->isMemoryManaged = PAL_TRUE; } @@ -249,7 +248,6 @@ PalResult PAL_CALL createImageVk( image->info.belongsToSwapchain = PAL_FALSE; image->memory = memory; - image->reserved = PAL_BACKEND_KEY; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } @@ -270,22 +268,21 @@ void PAL_CALL destroyImageVk(PalImage* image) palFree(s_Vk.allocator, vkImage); } -PalResult PAL_CALL getImageInfoVk( +void PAL_CALL getImageInfoVk( PalImage* image, PalImageInfo* info) { ImageVk* vkImage = (ImageVk*)image; *info = vkImage->info; - return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getImageMemoryRequirementsVk( +void PAL_CALL getImageMemoryRequirementsVk( PalImage* image, PalMemoryRequirements* requirements) { ImageVk* vkImage = (ImageVk*)image; if (vkImage->info.belongsToSwapchain) { - return PAL_RESULT_CODE_INVALID_OPERATION; + return; } DeviceVk* device = vkImage->device; @@ -299,8 +296,6 @@ PalResult PAL_CALL getImageMemoryRequirementsVk( if ((memReq.memoryTypeBits & device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY]) != 0) { requirements->supportedMemoryTypes |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); } - - return PAL_RESULT_SUCCESS; } PalResult PAL_CALL bindImageMemoryVk( @@ -334,12 +329,6 @@ PalResult PAL_CALL createImageViewVk( DeviceVk* vkDevice = (DeviceVk*)device; ImageVk* vkImage = (ImageVk*)image; - if (info->type == PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY) { - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - } - imageView = palAllocate(s_Vk.allocator, sizeof(ImageViewVk), 0); if (!imageView) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -371,7 +360,6 @@ PalResult PAL_CALL createImageViewVk( imageView->device = vkDevice; imageView->image = vkImage; imageView->layerCount = createInfo.subresourceRange.layerCount; - imageView->reserved = PAL_BACKEND_KEY; *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; } @@ -429,7 +417,6 @@ PalResult PAL_CALL createSamplerVk( } sampler->device = vkDevice; - sampler->reserved = PAL_BACKEND_KEY; *outSampler = (PalSampler*)sampler; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/vulkan/pal_pipeline_vulkan.c b/src/graphics/vulkan/pal_pipeline_vulkan.c index fdaaa950..e17894c0 100644 --- a/src/graphics/vulkan/pal_pipeline_vulkan.c +++ b/src/graphics/vulkan/pal_pipeline_vulkan.c @@ -10,45 +10,6 @@ #define max(a, b) (a > b) ? a : b -static VkPipelineStageFlags2 pipelineStageToVk(VkShaderStageFlagBits stage) -{ - switch (stage) { - case VK_SHADER_STAGE_VERTEX_BIT: - return VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT; - - case VK_SHADER_STAGE_FRAGMENT_BIT: - return VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; - - case VK_SHADER_STAGE_COMPUTE_BIT: - return VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; - - case VK_SHADER_STAGE_GEOMETRY_BIT: - return VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT; - - case VK_SHADER_STAGE_MESH_BIT_EXT: - return VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT; - - case VK_SHADER_STAGE_TASK_BIT_EXT: - return VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT; - - case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: - return VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT; - - case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: - return VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT; - - case VK_SHADER_STAGE_RAYGEN_BIT_KHR: - case VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR: - case VK_SHADER_STAGE_ANY_HIT_BIT_KHR: - case VK_SHADER_STAGE_MISS_BIT_KHR: - case VK_SHADER_STAGE_INTERSECTION_BIT_KHR: - case VK_SHADER_STAGE_CALLABLE_BIT_KHR: { - return VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; - } - } - return 0; -} - static VkBlendOp blendOpToVk(PalBlendOp op) { switch (op) { @@ -234,7 +195,6 @@ PalResult PAL_CALL createPipelineLayoutVk( } layout->device = vkDevice; - layout->reserved = PAL_BACKEND_KEY; *outLayout = (PalPipelineLayout*)layout; return PAL_RESULT_SUCCESS; } @@ -323,7 +283,6 @@ PalResult PAL_CALL createGraphicsPipelineVk( // shaders uint32_t stageIndex = 0; - pipeline->stages = VK_PIPELINE_STAGE_2_NONE; memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stageCount); for (int i = 0; i < info->shaderCount; i++) { ShaderVk* tmp = (ShaderVk*)info->shaders[i]; @@ -346,7 +305,6 @@ PalResult PAL_CALL createGraphicsPipelineVk( stageInfo->module = tmp->handle; stageInfo->pName = entry->entryName; stageInfo->stage = entry->stage; - pipeline->stages |= pipelineStageToVk(entry->stage); } } @@ -707,7 +665,6 @@ PalResult PAL_CALL createGraphicsPipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; pipeline->device = vkDevice; pipeline->layout = layout->handle; - pipeline->reserved = PAL_BACKEND_KEY; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -752,8 +709,6 @@ PalResult PAL_CALL createComputePipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; pipeline->device = vkDevice; pipeline->layout = layout->handle; - pipeline->stages = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; - pipeline->reserved = PAL_BACKEND_KEY; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } @@ -770,10 +725,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( VkPipelineShaderStageCreateInfo* shaderStages = nullptr; VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - if (info->maxPayloadSize > vkDevice->limits.maxPayloadSize) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -807,7 +758,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( // shaders uint32_t stageIndex = 0; - pipeline->stages = VK_PIPELINE_STAGE_2_NONE; memset(shaderStages, 0, sizeof(VkPipelineShaderStageCreateInfo) * stageCount); for (int i = 0; i < info->shaderCount; i++) { ShaderVk* tmp = (ShaderVk*)info->shaders[i]; @@ -820,7 +770,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( stageInfo->module = tmp->handle; stageInfo->pName = entry->entryName; stageInfo->stage = entry->stage; - pipeline->stages |= pipelineStageToVk(entry->stage); } } @@ -926,7 +875,6 @@ PalResult PAL_CALL createRayTracingPipelineVk( pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; pipeline->device = vkDevice; pipeline->layout = layout->handle; - pipeline->reserved = PAL_BACKEND_KEY; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/vulkan/pal_sbt_vulkan.c b/src/graphics/vulkan/pal_sbt_vulkan.c index 6dceda5e..5e7ff77c 100644 --- a/src/graphics/vulkan/pal_sbt_vulkan.c +++ b/src/graphics/vulkan/pal_sbt_vulkan.c @@ -21,10 +21,6 @@ PalResult PAL_CALL createShaderBindingTableVk( PipelineVk* pipeline = (PipelineVk*)info->rayTracingPipeline; ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_RAY_TRACING)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - uint32_t totalGroups = sbtInfo->raygenCount + sbtInfo->hitCount; totalGroups += sbtInfo->missCount + sbtInfo->callableCount; if (info->recordCount != totalGroups) { @@ -276,8 +272,7 @@ PalResult PAL_CALL createShaderBindingTableVk( } } - s_Vk.unmapMemory(vkDevice->handle, sbt->stagingBufferMemory); - + sbt->stagingPtr = ptr; // cache SBT fields and offsets address // we know the layout so we can prepare the strided address before we copy to the gpu buffer VkBufferDeviceAddressInfo bufferAddressInfo = {0}; @@ -319,7 +314,6 @@ PalResult PAL_CALL createShaderBindingTableVk( sbt->pipeline = pipeline; sbt->isDirty = PAL_TRUE; // we need to copy from the staging to the gpu buffer - sbt->reserved = PAL_BACKEND_KEY; *outSbt = (PalShaderBindingTable*)sbt; return PAL_RESULT_SUCCESS; } @@ -328,6 +322,8 @@ void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt) { ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; DeviceVk* device = vkSbt->device; + s_Vk.unmapMemory(device->handle, vkSbt->stagingBufferMemory); + s_Vk.destroyBuffer(device->handle, vkSbt->buffer, &s_Vk.vkAllocator); s_Vk.destroyBuffer(device->handle, vkSbt->stagingBuffer, &s_Vk.vkAllocator); s_Vk.freeMemory(device->handle, vkSbt->bufferMemory, &s_Vk.vkAllocator); @@ -335,39 +331,22 @@ void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt) palFree(s_Vk.allocator, vkSbt); } -PalResult PAL_CALL updateShaderBindingTableVk( +void PAL_CALL updateShaderBindingTableVk( PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos) { - VkResult result; ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; DeviceVk* vkDevice = vkSbt->device; PipelineVk* pipeline = vkSbt->pipeline; ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; - void* data = nullptr; - result = s_Vk.mapMemory( - vkDevice->handle, - vkSbt->stagingBufferMemory, - 0, - VK_WHOLE_SIZE, - 0, - &data); - - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - uint32_t stride = 0; uint32_t offset = 0; uint32_t startIndex = 0; for (int i = 0; i < count; i++) { PalShaderBindingTableRecordInfo* info = &infos[i]; - if (!info->localDataSize) { - return PAL_RESULT_CODE_INVALID_ARGUMENT; - } // find the group the record belongs to uint32_t index = info->groupIndex; @@ -398,13 +377,11 @@ PalResult PAL_CALL updateShaderBindingTableVk( // write payload uint32_t localIndex = index - startIndex; - uint8_t* dst = (uint8_t*)data + offset + (localIndex * stride); + uint8_t* dst = (uint8_t*)vkSbt->stagingPtr + offset + (localIndex * stride); memcpy(dst + vkSbt->handleSize, info->localData, info->localDataSize); } - s_Vk.unmapMemory(vkDevice->handle, vkSbt->stagingBufferMemory); vkSbt->isDirty = PAL_TRUE; - return PAL_RESULT_SUCCESS; } #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_swapchain_vulkan.c b/src/graphics/vulkan/pal_swapchain_vulkan.c index 867d9df5..23d45125 100644 --- a/src/graphics/vulkan/pal_swapchain_vulkan.c +++ b/src/graphics/vulkan/pal_swapchain_vulkan.c @@ -89,7 +89,6 @@ PalResult PAL_CALL createSurfaceVk( surface->device = vkDevice; surface->handle = tmp; - surface->reserved = PAL_BACKEND_KEY; *outSurface = (PalSurface*)surface; return PAL_RESULT_SUCCESS; } @@ -101,7 +100,7 @@ void PAL_CALL destroySurfaceVk(PalSurface* surface) palFree(s_Vk.allocator, vkSurface); } -PalResult PAL_CALL getSurfaceCapabilitiesVk( +void PAL_CALL getSurfaceCapabilitiesVk( PalDevice* device, PalSurface* surface, PalSurfaceCapabilities* caps) @@ -114,9 +113,6 @@ PalResult PAL_CALL getSurfaceCapabilitiesVk( DeviceVk* vkDevice = (DeviceVk*)device; VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkDevice->phyDevice; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } memset(caps, 0, sizeof(PalSurfaceCapabilities)); s_Vk.getSurfacePresentModes(phyDevice, vkSurface->handle, &modeCount, nullptr); @@ -125,7 +121,7 @@ PalResult PAL_CALL getSurfaceCapabilitiesVk( modes = palAllocate(s_Vk.allocator, sizeof(VkPresentModeKHR) * modeCount, 0); formats = palAllocate(s_Vk.allocator, sizeof(VkSurfaceFormatKHR) * formatCount, 0); if (!modes || !formats) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; + return; } s_Vk.getSurfacePresentModes(phyDevice, vkSurface->handle, &modeCount, modes); @@ -200,7 +196,6 @@ PalResult PAL_CALL getSurfaceCapabilitiesVk( palFree(s_Vk.allocator, formats); palFree(s_Vk.allocator, modes); - return PAL_RESULT_SUCCESS; } PalResult PAL_CALL createSwapchainVk( @@ -219,10 +214,6 @@ PalResult PAL_CALL createSwapchainVk( PhysicalQueue* phyQueue = vkQueue->phyQueue; SurfaceVk* vkSurface = (SurfaceVk*)surface; - if (!(vkDevice->features & PAL_ADAPTER_FEATURE_SWAPCHAIN)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - // check if the queue is a graphics queue before we check its family // index for presentation support. if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { @@ -333,7 +324,6 @@ PalResult PAL_CALL createSwapchainVk( swapchain->device = vkDevice; swapchain->queue = vkQueue; swapchain->imageCount = count; - swapchain->reserved = PAL_BACKEND_KEY; *outSwapchain = (PalSwapchain*)swapchain; return PAL_RESULT_SUCCESS; } @@ -355,9 +345,6 @@ PalImage* PAL_CALL getSwapchainImageVk( uint32_t index) { SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; - if (index > vkSwapchain->imageCount) { - return nullptr; - } return (PalImage*)&vkSwapchain->images[index]; } diff --git a/src/graphics/vulkan/pal_sync_vulkan.c b/src/graphics/vulkan/pal_sync_vulkan.c index 0250a1a0..fc882827 100644 --- a/src/graphics/vulkan/pal_sync_vulkan.c +++ b/src/graphics/vulkan/pal_sync_vulkan.c @@ -35,7 +35,6 @@ PalResult PAL_CALL createFenceVk( } fence->device = vkDevice; - fence->reserved = PAL_BACKEND_KEY; *outFence = (PalFence*)fence; return PAL_RESULT_SUCCESS; } @@ -53,16 +52,16 @@ PalResult PAL_CALL waitFenceVk( { FenceVk* vkFence = (FenceVk*)fence; VkResult result; - uint64_t timeInNanoseconds = 0; + uint64_t timeInNano = 0; if (timeout) { if (timeout == PAL_INFINITE) { - timeInNanoseconds = UINT64_MAX; + timeInNano = UINT64_MAX; } else { - timeInNanoseconds = timeout * 1000000; + timeInNano = timeout * 1000000; } } - result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, PAL_TRUE, timeInNanoseconds); + result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, PAL_TRUE, timeInNano); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -73,10 +72,6 @@ PalResult PAL_CALL waitFenceVk( PalResult PAL_CALL resetFenceVk(PalFence* fence) { FenceVk* vkFence = (FenceVk*)fence; - if (!(vkFence->device->features & PAL_ADAPTER_FEATURE_FENCE_RESET)) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkResult result = s_Vk.resetFence(vkFence->device->handle, 1, &vkFence->handle); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -105,7 +100,6 @@ PalResult PAL_CALL createSemaphoreVk( VkResult result; SemaphoreVk* semaphore = nullptr; DeviceVk* vkDevice = (DeviceVk*)device; - PalBool hasTimeline = vkDevice->features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE; semaphore = palAllocate(s_Vk.allocator, sizeof(SemaphoreVk), 0); if (!semaphore) { @@ -121,10 +115,6 @@ PalResult PAL_CALL createSemaphoreVk( const void* next = nullptr; semaphore->isTimeline = PAL_FALSE; - if (enableTimeline && !hasTimeline) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - if (enableTimeline) { next = &timelineCreateInfo; semaphore->isTimeline = PAL_TRUE; @@ -143,7 +133,6 @@ PalResult PAL_CALL createSemaphoreVk( } semaphore->device = vkDevice; - semaphore->reserved = PAL_BACKEND_KEY; *outSemaphore = (PalSemaphore*)semaphore; return PAL_RESULT_SUCCESS; } @@ -161,7 +150,7 @@ PalResult PAL_CALL waitSemaphoreVk( uint64_t timeout) { VkResult result; - uint64_t timeInNanoseconds = 0; + uint64_t timeInNano = 0; SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; if (!vkSemaphore->isTimeline) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; @@ -169,9 +158,9 @@ PalResult PAL_CALL waitSemaphoreVk( if (timeout) { if (timeout == PAL_INFINITE) { - timeInNanoseconds = UINT64_MAX; + timeInNano = UINT64_MAX; } else { - timeInNanoseconds = timeout * 1000000; + timeInNano = timeout * 1000000; } } @@ -184,7 +173,7 @@ PalResult PAL_CALL waitSemaphoreVk( result = vkSemaphore->device->waitSemaphore( vkSemaphore->device->handle, &waitInfo, - timeInNanoseconds); + timeInNano); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -217,17 +206,13 @@ PalResult PAL_CALL signalSemaphoreVk( return PAL_RESULT_SUCCESS; } -uint64_t PAL_CALL getSemaphoreValueVk(PalSemaphore* semaphore) +PalResult PAL_CALL getSemaphoreValueVk(PalSemaphore* semaphore, uint64_t* value) { SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; - if (!vkSemaphore->isTimeline) { - return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; - } - VkResult result = vkSemaphore->device->getSemaphoreValue( vkSemaphore->device->handle, vkSemaphore->handle, - outValue); + value); if (result != VK_SUCCESS) { return makeResultVk(result); diff --git a/src/graphics/vulkan/pal_vulkan.c b/src/graphics/vulkan/pal_vulkan.c index 2b7b7313..22c53d16 100644 --- a/src/graphics/vulkan/pal_vulkan.c +++ b/src/graphics/vulkan/pal_vulkan.c @@ -783,6 +783,92 @@ void fillBuildInfoVk( outBuildInfo->scratchData = scratchData; } +VkPipelineStageFlags2 pipelineStagesToVk(PalPipelineStages stages) +{ + if (stages == PAL_PIPELINE_STAGE_NONE) { + return VK_PIPELINE_STAGE_2_NONE; + } + + VkPipelineStageFlags2 vkStages = 0; + if (stages & PAL_PIPELINE_STAGE_VERTEX_SHADER) { + vkStages |= VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_FRAGMENT_SHADER) { + vkStages |= VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_COMPUTE_SHADER) { + vkStages |= VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_GEOMETRY_SHADER) { + vkStages |= VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER) { + vkStages |= VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER) { + vkStages |= VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_RAY_TRACING_SHADER) { + vkStages |= VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; + } + + if (stages & PAL_PIPELINE_STAGE_TASK_SHADER) { + vkStages |= VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT; + } + + if (stages & PAL_PIPELINE_STAGE_MESH_SHADER) { + vkStages |= VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT; + } + + if (stages & PAL_PIPELINE_STAGE_VERTEX_INPUT) { + vkStages |= VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_INDEX_INPUT) { + vkStages |= VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_EARLY_DEPTH_STENCIL) { + vkStages |= VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_LATE_DEPTH_STENCIL) { + vkStages |= VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_TRANSFER) { + vkStages |= VK_PIPELINE_STAGE_2_TRANSFER_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_HOST) { + vkStages |= VK_PIPELINE_STAGE_2_HOST_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_COLOR_ATTACHMENT) { + vkStages |= VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT) { + vkStages |= VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR; + } + + if (stages & PAL_PIPELINE_STAGE_INDIRECT_INPUT) { + vkStages |= VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT; + } + + if (stages & PAL_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD) { + vkStages |= VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR; + } + + return vkStages; +} + static void* alignedRealloc( void* memory, uint64_t size, diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h index fc2e1a4e..9536f1b9 100644 --- a/src/graphics/vulkan/pal_vulkan.h +++ b/src/graphics/vulkan/pal_vulkan.h @@ -11,6 +11,7 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal/pal_graphics.h" #include +#include "graphics/pal_linear_allocator.h" typedef struct _XDisplay Display; typedef unsigned long Window; @@ -115,12 +116,6 @@ typedef struct { VkStridedDeviceAddressRegionKHR region; } AddressRegion; -typedef struct { - VkPipelineStageFlags2 stage; - VkAccessFlags2 access; - VkImageLayout layout; -} Barrier; - typedef struct { void* reserved; VkPhysicalDevice handle; @@ -128,10 +123,10 @@ typedef struct { typedef struct { void* reserved; - PalAdapterFeatures features; int32_t phyQueueCount; int32_t phyQueueIndex; int32_t queueFamilyCount; + PalAdapterFeatures features; uint32_t memoryClassMask[3]; VkPhysicalDevice phyDevice; VkDevice handle; @@ -201,6 +196,7 @@ typedef struct { typedef struct { void* reserved; + DeviceVk* device; PalMemoryType type; VkDeviceMemory handle; } MemoryVk; @@ -260,6 +256,7 @@ typedef struct { VkBuffer buffer; VkDeviceMemory bufferMemory; VkCommandBuffer handle; + PalLinearAllocator allocator; } CommandBufferVk; typedef struct { @@ -330,7 +327,6 @@ typedef struct { typedef struct { void* reserved; VkPipelineBindPoint bindPoint; - VkPipelineStageFlags2 stages; DeviceVk* device; VkPipeline handle; VkPipelineLayout layout; @@ -339,6 +335,7 @@ typedef struct { typedef struct { void* reserved; + void* stagingPtr; PalBool isDirty; uint32_t stagingBufferSize; uint32_t handleSize; @@ -488,5 +485,7 @@ void fillBuildInfoVk( VkAccelerationStructureBuildGeometryInfoKHR* outBuildInfo, void* outData); +VkPipelineStageFlags2 pipelineStagesToVk(PalPipelineStages stages); + #endif // PAL_HAS_VULKAN_BACKEND #endif // _PAL_VULKAN_H \ No newline at end of file diff --git a/src/video/wayland/pal_window_wayland.c b/src/video/wayland/pal_window_wayland.c index a3101221..6dca9cb4 100644 --- a/src/video/wayland/pal_window_wayland.c +++ b/src/video/wayland/pal_window_wayland.c @@ -237,6 +237,7 @@ void wlDestroyWindow(PalWindow* window) xdgToplevelDestroy(data->xdgToplevel); xdgSurfaceDestroy(data->xdgSurface); wlSurfaceDestroy((struct wl_surface*)window); + s_Wl.displayFlush(s_Wl.display); data->used = PAL_FALSE; } diff --git a/src/video/x11/pal_window_x11.c b/src/video/x11/pal_window_x11.c index cf2e054f..17e00d4e 100644 --- a/src/video/x11/pal_window_x11.c +++ b/src/video/x11/pal_window_x11.c @@ -621,7 +621,7 @@ void xGetWindowTitle( } else { XTextProperty text; if (!s_X11.getWMName(s_X11.display, xWin, &text)) { - return PAL_RESULT_CODE_INVALID_HANDLE; + return; } if (bufferSize >= text.nitems) { diff --git a/src/video/x11/pal_x11.h b/src/video/x11/pal_x11.h index 08952a75..7849a36a 100644 --- a/src/video/x11/pal_x11.h +++ b/src/video/x11/pal_x11.h @@ -609,7 +609,7 @@ void sendWMEvent( long d, PalBool add); -PalResult xGetPrimaryMonitor(PalMonitor**); +void xGetPrimaryMonitor(PalMonitor**); MonitorData* xGetFreeMonitorData(); MonitorData* xFindMonitorData(PalMonitor* monitor); void xFreeMonitorData(PalMonitor* monitor); diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index fc2bb859..d334d6b2 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -401,8 +401,9 @@ PalBool clearColorTest() } // change the state of the image view to make it renderable - PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalBarrierInfo barrierInfo = {0}; + barrierInfo.newState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -411,12 +412,7 @@ PalBool clearColorTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); PalClearValue clearValue; clearValue.color[0] = 0.2f; @@ -434,24 +430,20 @@ PalBool clearColorTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.arrayLayerCount = 1; + renderingInfo.viewCount = 1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable - oldUsageState = newUsageState; - newUsageState = PAL_USAGE_STATE_PRESENT; - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to set barrier"); - return PAL_FALSE; - } + barrierInfo.oldState = barrierInfo.newState; + barrierInfo.srcStages = barrierInfo.dstStages; + barrierInfo.newState = PAL_USAGE_STATE_PRESENT; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_NONE; + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { @@ -465,6 +457,7 @@ PalBool clearColorTest() submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; + submitInfo.waitStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 947a88a5..7d87c450 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -369,9 +369,11 @@ PalBool computeTest() palFree(nullptr, workGroupInfos); // set a barrier so we only read from the buffer after the shader has written to it - PalUsageState oldUsageState = PAL_USAGE_STATE_SHADER_WRITE; - PalUsageState newUsageState = PAL_USAGE_STATE_TRANSFER_READ; - palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); + PalBarrierInfo barrierInfo = {0}; + barrierInfo.oldState = PAL_USAGE_STATE_SHADER_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; + palCmdBufferBarrier(cmdBuffer, buffer, &barrierInfo); // now we copy from the GPU buffer into the staging buffer PalBufferCopyInfo copyInfo = {0}; @@ -388,6 +390,8 @@ PalBool computeTest() PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffer; submitInfo.fence = fence; + submitInfo.waitStages = PAL_PIPELINE_STAGE_COMPUTE_SHADER; + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index c376aa5f..44bdbf1d 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -536,9 +536,10 @@ PalBool descriptorIndexingTest() copyInfo.size = sizeof(vertices); palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); - PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; - PalUsageState newUsageState = PAL_USAGE_STATE_VERTEX_READ; - palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); + PalBarrierInfo barrierInfo = {0}; + barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &barrierInfo); // set a barrier on the image to transition it into transfer dst state PalImageSubresourceRange textureRange = {0}; @@ -548,29 +549,13 @@ PalBool descriptorIndexingTest() textureRange.layerArrayCount = 1; for (int i = 0; i < 4; i++) { - PalUsageState oldImageUsageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageState newImageUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; - palCmdImageBarrier( - cmdBuffers[0], - textures[i], - &textureRange, - oldImageUsageState, - newImageUsageState); - + palCmdImageBarrier(cmdBuffers[0], textures[i], &textureRange, &barrierInfo); palCmdCopyBufferToImage( cmdBuffers[0], textures[i], imageStagingBuffers[i], &bufferImageCopyInfo); - - oldImageUsageState = newImageUsageState; - newImageUsageState = PAL_USAGE_STATE_SHADER_READ; - palCmdImageBarrier( - cmdBuffers[0], - textures[i], - &textureRange, - oldImageUsageState, - newImageUsageState); + palCmdImageBarrier(cmdBuffers[0], textures[i], &textureRange, &barrierInfo); } result = palCmdEnd(cmdBuffers[0]); @@ -582,6 +567,8 @@ PalBool descriptorIndexingTest() PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffers[0]; submitInfo.fence = fence; + submitInfo.waitStages = PAL_PIPELINE_STAGE_TRANSFER; + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); @@ -1022,8 +1009,9 @@ PalBool descriptorIndexingTest() } // change the state of the image view to make it renderable - PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalBarrierInfo barrierInfo = {0}; + barrierInfo.newState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -1032,12 +1020,7 @@ PalBool descriptorIndexingTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); PalClearValue clearValue; clearValue.color[0] = 0.2f; @@ -1055,6 +1038,10 @@ PalBool descriptorIndexingTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.arrayLayerCount = 1; + renderingInfo.viewCount = 1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); @@ -1069,14 +1056,12 @@ PalBool descriptorIndexingTest() palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable - oldUsageState = newUsageState; - newUsageState = PAL_USAGE_STATE_PRESENT; - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + // change the state of the image view to make it presentable + barrierInfo.oldState = barrierInfo.newState; + barrierInfo.srcStages = barrierInfo.dstStages; + barrierInfo.newState = PAL_USAGE_STATE_PRESENT; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_NONE; + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { @@ -1090,6 +1075,7 @@ PalBool descriptorIndexingTest() submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; + submitInfo.waitStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index c84ded5c..1b4dec86 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -549,8 +549,9 @@ PalBool geometryTest() } // change the state of the image view to make it renderable - PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalBarrierInfo barrierInfo = {0}; + barrierInfo.newState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -559,12 +560,7 @@ PalBool geometryTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); PalClearValue clearValue; clearValue.color[0] = 0.2f; @@ -582,6 +578,10 @@ PalBool geometryTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.arrayLayerCount = 1; + renderingInfo.viewCount = 1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); @@ -591,14 +591,11 @@ PalBool geometryTest() palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable - oldUsageState = newUsageState; - newUsageState = PAL_USAGE_STATE_PRESENT; - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + barrierInfo.oldState = barrierInfo.newState; + barrierInfo.srcStages = barrierInfo.dstStages; + barrierInfo.newState = PAL_USAGE_STATE_PRESENT; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_NONE; + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { @@ -612,6 +609,7 @@ PalBool geometryTest() submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; + submitInfo.waitStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 2683e02a..5b324453 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -472,8 +472,9 @@ PalBool indirectDrawTest() return PAL_FALSE; } - PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; - PalUsageState newUsageState = PAL_USAGE_STATE_INDIRECT_READ; + PalBarrierInfo barrierInfo = {0}; + barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; // copy to indirect buffer PalBufferCopyInfo indirectCopyInfo = {0}; @@ -482,24 +483,22 @@ PalBool indirectDrawTest() indirectCopyInfo.srcOffset = indirectOffset; palCmdCopyBuffer(cmdBuffers[0], indirectBuffer, stagingBuffer, &indirectCopyInfo); - palCmdBufferBarrier(cmdBuffers[0], indirectBuffer, oldUsageState, newUsageState); + palCmdBufferBarrier(cmdBuffers[0], indirectBuffer, &barrierInfo); - newUsageState = PAL_USAGE_STATE_VERTEX_READ; PalBufferCopyInfo vertexCopyInfo = {0}; vertexCopyInfo.dstOffset = 0; vertexCopyInfo.size = sizeof(vertices); vertexCopyInfo.srcOffset = vertexOffset; palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, &vertexCopyInfo); - palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); + palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &barrierInfo); // copy to index buffer - newUsageState = PAL_USAGE_STATE_INDEX_READ; PalBufferCopyInfo indexCopyInfo = {0}; indexCopyInfo.dstOffset = 0; indexCopyInfo.size = sizeof(indices); indexCopyInfo.srcOffset = indexOffset; palCmdCopyBuffer(cmdBuffers[0], indexBuffer, stagingBuffer, &indexCopyInfo); - palCmdBufferBarrier(cmdBuffers[0], indexBuffer, oldUsageState, newUsageState); + palCmdBufferBarrier(cmdBuffers[0], indexBuffer, &barrierInfo); result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { @@ -510,6 +509,8 @@ PalBool indirectDrawTest() PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffers[0]; submitInfo.fence = fence; + submitInfo.waitStages = PAL_PIPELINE_STAGE_TRANSFER; + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); @@ -743,8 +744,10 @@ PalBool indirectDrawTest() } // change the state of the image view to make it renderable - PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.oldState = PAL_USAGE_STATE_UNDEFINED; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_NONE; + barrierInfo.newState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -753,12 +756,7 @@ PalBool indirectDrawTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); PalClearValue clearValue; clearValue.color[0] = 0.2f; @@ -776,6 +774,10 @@ PalBool indirectDrawTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.arrayLayerCount = 1; + renderingInfo.viewCount = 1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); @@ -789,14 +791,11 @@ PalBool indirectDrawTest() palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable - oldUsageState = newUsageState; - newUsageState = PAL_USAGE_STATE_PRESENT; - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + barrierInfo.oldState = barrierInfo.newState; + barrierInfo.srcStages = barrierInfo.dstStages; + barrierInfo.newState = PAL_USAGE_STATE_PRESENT; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_NONE; + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { @@ -810,6 +809,7 @@ PalBool indirectDrawTest() submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; + submitInfo.waitStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index c8a59e27..6a09e5b9 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -543,8 +543,9 @@ PalBool meshTest() } // change the state of the image view to make it renderable - PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + PalBarrierInfo barrierInfo = {0}; + barrierInfo.newState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -553,12 +554,7 @@ PalBool meshTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); PalClearValue clearValue; clearValue.color[0] = 0.2f; @@ -576,6 +572,10 @@ PalBool meshTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.arrayLayerCount = 1; + renderingInfo.viewCount = 1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); @@ -590,14 +590,11 @@ PalBool meshTest() palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable - oldUsageState = newUsageState; - newUsageState = PAL_USAGE_STATE_PRESENT; - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + barrierInfo.oldState = barrierInfo.newState; + barrierInfo.srcStages = barrierInfo.dstStages; + barrierInfo.newState = PAL_USAGE_STATE_PRESENT; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_NONE; + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { @@ -611,6 +608,7 @@ PalBool meshTest() submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; + submitInfo.waitStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 407e8979..30ee02ae 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -426,13 +426,12 @@ PalBool multiDescriptorSetTest() palFree(nullptr, workGroupInfos); // set a barrier so we only read from the buffer after the shader has written to it - PalUsageState oldUsageState = PAL_USAGE_STATE_SHADER_WRITE; - PalUsageState newUsageState = PAL_USAGE_STATE_TRANSFER_READ; + PalBarrierInfo barrierInfo = {0}; + barrierInfo.oldState = PAL_USAGE_STATE_SHADER_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; for (int i = 0; i < 3; i++) { - palCmdBufferBarrier(cmdBuffer, buffers[i], oldUsageState, newUsageState); - - // now we copy from the GPU buffer into the staging buffer + palCmdBufferBarrier(cmdBuffer, buffers[i], &barrierInfo); PalBufferCopyInfo copyInfo = {0}; copyInfo.size = bufferBytes; palCmdCopyBuffer(cmdBuffer, stagingBuffers[i], buffers[i], ©Info); @@ -448,6 +447,8 @@ PalBool multiDescriptorSetTest() PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffer; submitInfo.fence = fence; + submitInfo.waitStages = PAL_PIPELINE_STAGE_TRANSFER; + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 450a9cad..db088fbc 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -335,15 +335,7 @@ PalBool rayTracingTest() memcpy(asInstance.transform, transform, sizeof(float) * 12); uint64_t instanceBufferSize = 0; - result = palComputeInstanceBufferRequirements( - device, - 1, - &instanceBufferSize); - - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to compute buffer requirement"); - return PAL_FALSE; - } + palComputeInstanceStagingSize(device, 1, &instanceBufferSize); bufferCreateInfo.size = instanceBufferSize; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT; @@ -370,12 +362,7 @@ PalBool rayTracingTest() } // we can not use a direct memcpy for instance buffers - result = palWriteToInstanceBuffer(device, data, &asInstance, 1); - if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to write to buffer"); - return PAL_FALSE; - } - + palWriteInstanceStaging(device, 1, &asInstance, data); palUnmapBuffer(instanceBuffer); // fill TLAS and instance geometry @@ -636,19 +623,29 @@ PalBool rayTracingTest() tlasBuildInfo.scratchBufferAddress = scratchBufferAddress; palCmdBuildAccelerationStructure(cmdBuffer, &blasBuildInfo); - // make sure the BLAS builds before the TLAS. We need this barrier because - // BLAS and TLAS share the same scratch buffer - PalUsageState oldAsUsageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; - PalUsageState newAsUsageState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; - palCmdAccelerationStructureBarrier(cmdBuffer, blas, oldAsUsageState, newAsUsageState); + // make sure the BLAS builds before the TLAS. + PalBarrierInfo barrierInfo = {0}; + barrierInfo.oldState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD; + + palCmdAccelerationStructureBarrier(cmdBuffer, blas, &barrierInfo); palCmdBuildAccelerationStructure(cmdBuffer, &tlasBuildInfo); - palCmdAccelerationStructureBarrier(cmdBuffer, tlas, oldAsUsageState, newAsUsageState); + + barrierInfo.oldState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_RAY_TRACING_SHADER; + palCmdAccelerationStructureBarrier(cmdBuffer, tlas, &barrierInfo); palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); // set a barrier so we only read from the buffer after the shader has written to it - PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageState newUsageState = PAL_USAGE_STATE_TRANSFER_READ; - palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); + barrierInfo.oldState = PAL_USAGE_STATE_SHADER_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_RAY_TRACING_SHADER; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; + palCmdBufferBarrier(cmdBuffer, buffer, &barrierInfo); // now we copy from the GPU buffer into the staging buffer PalBufferCopyInfo copyInfo = {0}; @@ -665,6 +662,8 @@ PalBool rayTracingTest() PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffer; submitInfo.fence = fence; + submitInfo.waitStages = PAL_PIPELINE_STAGE_RAY_TRACING_SHADER; + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); @@ -747,17 +746,20 @@ PalBool rayTracingTest() palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); // the previous trace transitioned the buffer to transfer read - // we need it back to shader write before transfer read - oldUsageState = PAL_USAGE_STATE_TRANSFER_READ; - newUsageState = PAL_USAGE_STATE_SHADER_WRITE; - palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); + barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_READ; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_TRANSFER; + barrierInfo.newState = PAL_USAGE_STATE_SHADER_WRITE; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_RAY_TRACING_SHADER; + palCmdBufferBarrier(cmdBuffer, buffer, &barrierInfo); palCmdTraceRays(cmdBuffer, sbt, 0, BUFFER_SIZE, BUFFER_SIZE, 1); // set a barrier to transition to transfer read so we can read from it after shader has // written to it - oldUsageState = newUsageState; - newUsageState = PAL_USAGE_STATE_TRANSFER_READ; - palCmdBufferBarrier(cmdBuffer, buffer, oldUsageState, newUsageState); + barrierInfo.oldState = PAL_USAGE_STATE_SHADER_WRITE; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_RAY_TRACING_SHADER; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; + palCmdBufferBarrier(cmdBuffer, buffer, &barrierInfo); // now we copy from the GPU buffer into the staging buffer copyInfo.size = bufferBytes; @@ -772,6 +774,7 @@ PalBool rayTracingTest() // submit the command buffer to the GPU submitInfo.cmdBuffer = cmdBuffer; submitInfo.fence = fence; + submitInfo.waitStages = PAL_PIPELINE_STAGE_RAY_TRACING_SHADER; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index f3253a07..7a346e3f 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -518,14 +518,15 @@ PalBool textureTest() copyInfo.size = sizeof(vertices); palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); - PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; - PalUsageState newUsageState = PAL_USAGE_STATE_VERTEX_READ; - palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); + PalBarrierInfo barrierInfo = {0}; + barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &barrierInfo); // copy image staging buffer to the checkerboard image // first the image must be in the correct layout - PalUsageState oldImageUsageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageState newImageUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.oldState = PAL_USAGE_STATE_UNDEFINED; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_WRITE; // set a barrier on the image to transition it into transfer dst state PalImageSubresourceRange checkerboardRange = {0}; @@ -534,27 +535,16 @@ PalBool textureTest() checkerboardRange.mipLevelCount = 1; checkerboardRange.layerArrayCount = 1; - palCmdImageBarrier( - cmdBuffers[0], - checkerboard, - &checkerboardRange, - oldImageUsageState, - newImageUsageState); - + palCmdImageBarrier(cmdBuffers[0], checkerboard, &checkerboardRange, &barrierInfo); palCmdCopyBufferToImage( cmdBuffers[0], checkerboard, imageStagingBuffer, &bufferImageCopyInfo); - oldImageUsageState = newImageUsageState; - newImageUsageState = PAL_USAGE_STATE_SHADER_READ; - palCmdImageBarrier( - cmdBuffers[0], - checkerboard, - &checkerboardRange, - oldImageUsageState, - newImageUsageState); + barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + palCmdImageBarrier(cmdBuffers[0], checkerboard, &checkerboardRange, &barrierInfo); result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { @@ -565,6 +555,8 @@ PalBool textureTest() PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffers[0]; submitInfo.fence = fence; + submitInfo.waitStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); @@ -930,8 +922,9 @@ PalBool textureTest() } // change the state of the image view to make it renderable - PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.oldState = PAL_USAGE_STATE_UNDEFINED; + barrierInfo.newState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -940,12 +933,7 @@ PalBool textureTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); PalClearValue clearValue; clearValue.color[0] = 0.2f; @@ -963,6 +951,10 @@ PalBool textureTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.arrayLayerCount = 1; + renderingInfo.viewCount = 1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); @@ -976,14 +968,11 @@ PalBool textureTest() palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable - oldUsageState = newUsageState; - newUsageState = PAL_USAGE_STATE_PRESENT; - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + barrierInfo.oldState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; + barrierInfo.newState = PAL_USAGE_STATE_PRESENT; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_NONE; + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { @@ -997,6 +986,7 @@ PalBool textureTest() submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; + submitInfo.waitStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 8d796b94..a2b89c06 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -402,9 +402,10 @@ PalBool triangleTest() copyInfo.size = sizeof(vertices); palCmdCopyBuffer(cmdBuffers[0], vertexBuffer, stagingBuffer, ©Info); - PalUsageState oldUsageState = PAL_USAGE_STATE_TRANSFER_WRITE; - PalUsageState newUsageState = PAL_USAGE_STATE_VERTEX_READ; - palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, oldUsageState, newUsageState); + PalBarrierInfo barrierInfo = {0}; + barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &barrierInfo); result = palCmdEnd(cmdBuffers[0]); if (result != PAL_RESULT_SUCCESS) { @@ -415,6 +416,8 @@ PalBool triangleTest() PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffers[0]; submitInfo.fence = tmpFence; + submitInfo.waitStages = PAL_PIPELINE_STAGE_TRANSFER; + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); @@ -648,8 +651,8 @@ PalBool triangleTest() } // change the state of the image view to make it renderable - PalUsageState oldUsageState = PAL_USAGE_STATE_UNDEFINED; - PalUsageState newUsageState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.newState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; PalImageSubresourceRange imageRange = {0}; imageRange.layerArrayCount = 1; @@ -658,12 +661,7 @@ PalBool triangleTest() imageRange.startMipLevel = 0; PalImage* image = palGetSwapchainImage(swapchain, imageIndex); - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); PalClearValue clearValue; clearValue.color[0] = 0.2f; @@ -681,6 +679,10 @@ PalBool triangleTest() renderingInfo.viewCount = 1; renderingInfo.colorAttachentCount = 1; renderingInfo.colorAttachments = &colorAttachment; + renderingInfo.arrayLayerCount = 1; + renderingInfo.viewCount = 1; + renderingInfo.renderArea.width = WINDOW_WIDTH; + renderingInfo.renderArea.height = WINDOW_HEIGHT; palCmdBeginRendering(cmdBuffers[currentFrame], &renderingInfo); palCmdBindPipeline(cmdBuffers[currentFrame], pipeline); @@ -693,14 +695,11 @@ PalBool triangleTest() palCmdEndRendering(cmdBuffers[currentFrame]); // change the state of the image view to make it presentable - oldUsageState = newUsageState; - newUsageState = PAL_USAGE_STATE_PRESENT; - palCmdImageBarrier( - cmdBuffers[currentFrame], - image, - &imageRange, - oldUsageState, - newUsageState); + barrierInfo.oldState = barrierInfo.newState; + barrierInfo.srcStages = barrierInfo.dstStages; + barrierInfo.newState = PAL_USAGE_STATE_PRESENT; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_NONE; + palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { @@ -714,6 +713,7 @@ PalBool triangleTest() submitInfo.fence = inFlightFences[currentFrame]; submitInfo.waitSemaphore = imageAvailableSemaphores[currentFrame]; submitInfo.signalSemaphore = renderFinishedSemaphores[imageIndex]; + submitInfo.waitStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { diff --git a/tests/video/native_integration_test.c b/tests/video/native_integration_test.c index a604017c..dc3e4327 100644 --- a/tests/video/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -257,7 +257,6 @@ void getWindowTitleWayland(PalWindowHandleInfo* windowInfo) #ifdef __linux__ // wayland does not support getting window title // so we just return the title we set through wayland - dlclose(s_WaylandLib); #endif // __linux__ } @@ -376,13 +375,19 @@ PalBool nativeIntegrationTest() setWindowTitle(&windowInfo); palLog(nullptr, "Getting window title with PAL API"); - palGetWindowTitle(window, sizeof(s_TitleBuffer), nullptr, s_TitleBuffer); + if (features & PAL_VIDEO_FEATURE_WINDOW_GET_TITLE) { + palGetWindowTitle(window, sizeof(s_TitleBuffer), nullptr, s_TitleBuffer); + } else { + memset(s_TitleBuffer, 0, sizeof(s_TitleBuffer)); + } palLog(nullptr, "Window title: %s", s_TitleBuffer); // set the title with PAL and retreive it with the native API palLog(nullptr, "Setting window title with PAL API"); - palSetWindowTitle(window, "Hello from PAL API"); - + if (features & PAL_VIDEO_FEATURE_WINDOW_SET_TITLE) { + palSetWindowTitle(window, "Hello from PAL API"); + } + palLog(nullptr, "Getting window title with native API"); getWindowTitle(&windowInfo); palLog(nullptr, "Window title: %s", s_TitleBuffer); From 9838af8f67afb5dbd002a448fc0a8f00d96d03ae Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 12 Jul 2026 13:36:37 +0000 Subject: [PATCH 337/372] all graphics tests working vulkan with API changes --- src/graphics/vulkan/pal_descriptors_vulkan.c | 7 +++++-- tests/graphics/compute_test.c | 1 + tests/graphics/descriptor_indexing_test.c | 20 ++++++++++++++++++-- tests/graphics/indirect_draw_test.c | 2 ++ tests/graphics/multi_descriptor_set_test.c | 2 ++ tests/graphics/texture_test.c | 12 ++++++++++-- tests/graphics/triangle_test.c | 4 ++++ tests/tests_main.c | 4 ++-- 8 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/graphics/vulkan/pal_descriptors_vulkan.c b/src/graphics/vulkan/pal_descriptors_vulkan.c index e5b64745..ad4af411 100644 --- a/src/graphics/vulkan/pal_descriptors_vulkan.c +++ b/src/graphics/vulkan/pal_descriptors_vulkan.c @@ -90,7 +90,10 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( flagsCreateInfo.bindingCount = count; flagsCreateInfo.pBindingFlags = bindingFlags; createInfo.pNext = &flagsCreateInfo; - createInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; + + if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND) { + createInfo.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; + } } result = s_Vk.createDescriptorSetLayout( @@ -135,7 +138,7 @@ PalResult PAL_CALL createDescriptorPoolVk( VkDescriptorPoolCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { + if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND) { createInfo.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT; } diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 7d87c450..0450f601 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -371,6 +371,7 @@ PalBool computeTest() // set a barrier so we only read from the buffer after the shader has written to it PalBarrierInfo barrierInfo = {0}; barrierInfo.oldState = PAL_USAGE_STATE_SHADER_WRITE; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_COMPUTE_SHADER; barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; palCmdBufferBarrier(cmdBuffer, buffer, &barrierInfo); diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 44bdbf1d..ab4518af 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -538,7 +538,9 @@ PalBool descriptorIndexingTest() PalBarrierInfo barrierInfo = {0}; barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_TRANSFER; barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &barrierInfo); // set a barrier on the image to transition it into transfer dst state @@ -549,12 +551,23 @@ PalBool descriptorIndexingTest() textureRange.layerArrayCount = 1; for (int i = 0; i < 4; i++) { + barrierInfo.oldState = PAL_USAGE_STATE_UNDEFINED; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_NONE; + barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; palCmdImageBarrier(cmdBuffers[0], textures[i], &textureRange, &barrierInfo); + palCmdCopyBufferToImage( cmdBuffers[0], textures[i], imageStagingBuffers[i], &bufferImageCopyInfo); + + // transition the image to shader read state + barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_TRANSFER; + barrierInfo.newState = PAL_USAGE_STATE_SHADER_READ; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_FRAGMENT_SHADER; palCmdImageBarrier(cmdBuffers[0], textures[i], &textureRange, &barrierInfo); } @@ -694,7 +707,7 @@ PalBool descriptorIndexingTest() descriptorSetLayoutcreateInfo.bindingCount = 2; descriptorSetLayoutcreateInfo.bindings = descriptorBindings; - // we only need the partially bound feature if supported. + // we only need the partially bound feature if supported. We dont use the other features if (descriptorIndexingCaps.flags & PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND) { descriptorSetLayoutcreateInfo.flags |= PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND; } @@ -721,6 +734,7 @@ PalBool descriptorIndexingTest() descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set descriptorPoolCreateInfo.bindingSizeCount = 2; descriptorPoolCreateInfo.bindingSizes = storageBufferBindingsizes; + descriptorPoolCreateInfo.flags = descriptorSetLayoutcreateInfo.flags; result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); if (result != PAL_RESULT_SUCCESS) { @@ -1009,7 +1023,8 @@ PalBool descriptorIndexingTest() } // change the state of the image view to make it renderable - PalBarrierInfo barrierInfo = {0}; + barrierInfo.oldState = PAL_USAGE_STATE_UNDEFINED; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_NONE; barrierInfo.newState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; barrierInfo.dstStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; @@ -1120,6 +1135,7 @@ PalBool descriptorIndexingTest() for (int i = 0; i < 4; i++) { palDestroyImageView(textureViews[i]); palDestroyImage(textures[i]); + palDestroyBuffer(imageStagingBuffers[i]); } palDestroyBuffer(vertexBuffer); diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 5b324453..053c1b45 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -474,7 +474,9 @@ PalBool indirectDrawTest() PalBarrierInfo barrierInfo = {0}; barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_TRANSFER; barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; // copy to indirect buffer PalBufferCopyInfo indirectCopyInfo = {0}; diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 30ee02ae..f1819f94 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -428,7 +428,9 @@ PalBool multiDescriptorSetTest() // set a barrier so we only read from the buffer after the shader has written to it PalBarrierInfo barrierInfo = {0}; barrierInfo.oldState = PAL_USAGE_STATE_SHADER_WRITE; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_COMPUTE_SHADER; barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; for (int i = 0; i < 3; i++) { palCmdBufferBarrier(cmdBuffer, buffers[i], &barrierInfo); diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 7a346e3f..e64d0b04 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -520,13 +520,17 @@ PalBool textureTest() PalBarrierInfo barrierInfo = {0}; barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_TRANSFER; barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &barrierInfo); // copy image staging buffer to the checkerboard image // first the image must be in the correct layout barrierInfo.oldState = PAL_USAGE_STATE_UNDEFINED; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_NONE; barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; // set a barrier on the image to transition it into transfer dst state PalImageSubresourceRange checkerboardRange = {0}; @@ -542,8 +546,11 @@ PalBool textureTest() imageStagingBuffer, &bufferImageCopyInfo); + // transition the image to shader read state barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; - barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_TRANSFER; + barrierInfo.newState = PAL_USAGE_STATE_SHADER_READ; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_FRAGMENT_SHADER; palCmdImageBarrier(cmdBuffers[0], checkerboard, &checkerboardRange, &barrierInfo); result = palCmdEnd(cmdBuffers[0]); @@ -555,7 +562,7 @@ PalBool textureTest() PalCommandBufferSubmitInfo submitInfo = {0}; submitInfo.cmdBuffer = cmdBuffers[0]; submitInfo.fence = fence; - submitInfo.waitStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; + submitInfo.waitStages = PAL_PIPELINE_STAGE_TRANSFER; result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { @@ -923,6 +930,7 @@ PalBool textureTest() // change the state of the image view to make it renderable barrierInfo.oldState = PAL_USAGE_STATE_UNDEFINED; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_NONE; barrierInfo.newState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; barrierInfo.dstStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index a2b89c06..c62338f6 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -404,7 +404,9 @@ PalBool triangleTest() PalBarrierInfo barrierInfo = {0}; barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; + barrierInfo.srcStages = PAL_PIPELINE_STAGE_TRANSFER; barrierInfo.newState = PAL_USAGE_STATE_TRANSFER_READ; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; palCmdBufferBarrier(cmdBuffers[0], vertexBuffer, &barrierInfo); result = palCmdEnd(cmdBuffers[0]); @@ -651,6 +653,8 @@ PalBool triangleTest() } // change the state of the image view to make it renderable + barrierInfo.oldState = PAL_USAGE_STATE_UNDEFINED; + barrierInfo.dstStages = PAL_PIPELINE_STAGE_NONE; barrierInfo.newState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; barrierInfo.dstStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; diff --git a/tests/tests_main.c b/tests/tests_main.c index 8d394503..269a186a 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -56,7 +56,7 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS_MODULE == 1 - registerTest(graphicsTest, "Graphics Test"); + // registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); @@ -69,7 +69,7 @@ int main(int argc, char** argv) // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); - // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); + registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); From f61490ddf05146ebc50350d0c7ff3877f9fb1c53 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 12 Jul 2026 18:33:27 -0700 Subject: [PATCH 338/372] all graphics tests working d2d12 with API changes --- include/pal/pal_graphics.h | 7 - src/core/pal_result.h | 2 +- src/core/posix/pal_result_posix.c | 6 +- src/core/win32/pal_result_win32.c | 22 +-- src/graphics/d3d12/pal_buffer_d3d12.c | 41 +++--- src/graphics/d3d12/pal_command_pool_d3d12.c | 127 ++++-------------- src/graphics/d3d12/pal_commands_d3d12.c | 43 +++--- src/graphics/d3d12/pal_d3d12.c | 115 ++++++++++++---- src/graphics/d3d12/pal_d3d12.h | 35 +++-- src/graphics/d3d12/pal_descriptors_d3d12.c | 2 + src/graphics/d3d12/pal_device_d3d12.c | 89 ++---------- src/graphics/d3d12/pal_image_d3d12.c | 8 +- src/graphics/d3d12/pal_pipeline_d3d12.c | 7 + src/graphics/d3d12/pal_sbt_d3d12.c | 6 +- src/graphics/d3d12/pal_swapchain_d3d12.c | 71 +++++----- src/graphics/d3d12/pal_sync_d3d12.c | 2 + src/graphics/pal_graphics.c | 28 ++-- src/graphics/pal_graphics_backends.h | 11 +- src/graphics/vulkan/pal_command_pool_vulkan.c | 11 -- src/graphics/vulkan/pal_commands_vulkan.c | 8 -- src/graphics/vulkan/pal_vulkan.c | 4 - src/graphics/vulkan/pal_vulkan.h | 1 - tests/graphics/clear_color_test.c | 2 +- 23 files changed, 283 insertions(+), 365 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index b2a14c36..2084484b 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -3268,13 +3268,6 @@ typedef struct { */ void(PAL_CALL* destroyCommandPool)(PalCommandPool* pool); - /** - * Backend implementation of ::palResetCommandPool. - * - * Must obey the rules and semantics documented in palResetCommandPool(). - */ - PalResult(PAL_CALL* resetCommandPool)(PalCommandPool* pool); - /** * Backend implementation of ::palAllocateCommandBuffer. * diff --git a/src/core/pal_result.h b/src/core/pal_result.h index 3c896e80..95d0e3c8 100644 --- a/src/core/pal_result.h +++ b/src/core/pal_result.h @@ -97,7 +97,7 @@ static const char* resultSourceToString(PalResult result) return "VULKAN"; case PAL_RESULT_SOURCE_D3D12: - return "DIRECTX12"; + return "D3D12"; case PAL_RESULT_SOURCE_METAL: return "METAL"; diff --git a/src/core/posix/pal_result_posix.c b/src/core/posix/pal_result_posix.c index 0791c359..7e0c9d09 100644 --- a/src/core/posix/pal_result_posix.c +++ b/src/core/posix/pal_result_posix.c @@ -20,8 +20,10 @@ void PAL_CALL palFormatResult( { char tmpBuffer[256]; uint32_t nativeCode = palGetResultNativeCode(result); - strerror_r(nativeCode, tmpBuffer, 256); - formatResultMsg(result, buffer, tmpBuffer); + if (nativeCode != 0) { + strerror_r(nativeCode, tmpBuffer, 256); + formatResultMsg(result, buffer, tmpBuffer); + } } #endif // _PAL_HAS_POSIX \ No newline at end of file diff --git a/src/core/win32/pal_result_win32.c b/src/core/win32/pal_result_win32.c index 60f8cea8..64d70806 100644 --- a/src/core/win32/pal_result_win32.c +++ b/src/core/win32/pal_result_win32.c @@ -31,16 +31,18 @@ void PAL_CALL palFormatResult( { char tmpBuffer[256]; uint32_t nativeCode = palGetResultNativeCode(result); - FormatMessageA( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, - nativeCode, - 0, - tmpBuffer, - 256, - nullptr); - - formatResultMsg(result, buffer, tmpBuffer); + if (nativeCode != 0) { + FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + nativeCode, + 0, + tmpBuffer, + 256, + nullptr); + + formatResultMsg(result, buffer, tmpBuffer); + } } #endif // _WIN32 \ No newline at end of file diff --git a/src/graphics/d3d12/pal_buffer_d3d12.c b/src/graphics/d3d12/pal_buffer_d3d12.c index f3128696..be61dd88 100644 --- a/src/graphics/d3d12/pal_buffer_d3d12.c +++ b/src/graphics/d3d12/pal_buffer_d3d12.c @@ -13,33 +13,37 @@ static uint32_t getSupportedMemoryTypes(PalBufferUsages usages) { uint32_t masks = 0; - masks |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); - masks |= (1u << PAL_MEMORY_TYPE_CPU_UPLOAD); - masks |= (1u << PAL_MEMORY_TYPE_CPU_READBACK); + uint32_t gpuBit = (1u << PAL_MEMORY_TYPE_GPU_ONLY); + uint32_t uploadBit = (1u << PAL_MEMORY_TYPE_CPU_UPLOAD); + uint32_t readBackBit = (1u << PAL_MEMORY_TYPE_CPU_READBACK); + + masks |= gpuBit; + masks |= uploadBit; + masks |= readBackBit; if (usages & PAL_BUFFER_USAGE_STORAGE) { - masks &= ~PAL_MEMORY_TYPE_CPU_UPLOAD; - masks &= ~PAL_MEMORY_TYPE_CPU_READBACK; + masks &= ~uploadBit; + masks &= ~readBackBit; } if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { - masks &= ~PAL_MEMORY_TYPE_CPU_UPLOAD; - masks &= ~PAL_MEMORY_TYPE_CPU_READBACK; + masks &= ~uploadBit; + masks &= ~readBackBit; } if (usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { - masks &= ~PAL_MEMORY_TYPE_CPU_UPLOAD; - masks &= ~PAL_MEMORY_TYPE_CPU_READBACK; + masks &= ~uploadBit; + masks &= ~readBackBit; } if (usages & PAL_BUFFER_USAGE_TRANSFER_DST) { - masks |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); - masks &= ~PAL_MEMORY_TYPE_CPU_UPLOAD; + masks |= (1u << gpuBit); + masks &= ~uploadBit; } if (usages & PAL_BUFFER_USAGE_TRANSFER_SRC) { - masks |= (1u << PAL_MEMORY_TYPE_GPU_ONLY); - masks &= ~PAL_MEMORY_TYPE_CPU_READBACK; + masks |= (1u << gpuBit); + masks &= ~readBackBit; } return masks; @@ -125,12 +129,14 @@ PalResult PAL_CALL createBufferD3D12( (void**)&buffer->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } buffer->isMemoryManaged = PAL_TRUE; } + buffer->device = d3d12Device; buffer->usages = info->usages; buffer->size = info->size; *outBuffer = (PalBuffer*)buffer; @@ -151,7 +157,7 @@ void PAL_CALL getBufferMemoryRequirementsD3D12( PalMemoryRequirements* requirements) { BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - ID3D12Device5* device = d3d12Buffer->device; + ID3D12Device5* device = d3d12Buffer->device->handle; D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; @@ -250,7 +256,7 @@ PalResult PAL_CALL bindBufferMemoryD3D12( { HRESULT result; BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - ID3D12Device5* device = d3d12Buffer->device; + DeviceD3D12* device = d3d12Buffer->device; MemoryD3D12* d3d12Memory = (MemoryD3D12*)memory; if (d3d12Buffer->isMemoryManaged) { return PAL_RESULT_CODE_INVALID_OPERATION; @@ -276,8 +282,8 @@ PalResult PAL_CALL bindBufferMemoryD3D12( state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } - result = device->lpVtbl->CreatePlacedResource( - device, + result = device->handle->lpVtbl->CreatePlacedResource( + device->handle, d3d12Memory->handle, offset, &d3d12Buffer->desc, @@ -287,6 +293,7 @@ PalResult PAL_CALL bindBufferMemoryD3D12( (void**)&d3d12Buffer->handle); if (FAILED(result)) { + pollMessagesD3D12(device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_command_pool_d3d12.c b/src/graphics/d3d12/pal_command_pool_d3d12.c index 2fc61161..62604a0f 100644 --- a/src/graphics/d3d12/pal_command_pool_d3d12.c +++ b/src/graphics/d3d12/pal_command_pool_d3d12.c @@ -8,46 +8,6 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" -static CommandBufferData* getFreeCmdBufferData(CommandPoolD3D12* pool) -{ - for (int i = 0; i < pool->size; i++) { - if (!pool->cmdBuffersData[i].used) { - pool->cmdBuffersData[i].used = PAL_TRUE; - return &pool->cmdBuffersData[i]; - } - } - - // resize the data array - CommandBufferData* data = nullptr; - int count = pool->size * 2; // double the size - int freeIndex = pool->size + 1; - - data = palAllocate(s_D3D12.allocator, sizeof(CommandBufferData) * count, 0); - if (data) { - memcpy(data, pool->cmdBuffersData, pool->size * sizeof(CommandBufferData)); - - palFree(s_D3D12.allocator, pool->cmdBuffersData); - pool->cmdBuffersData = data; - pool->size = count; - - pool->cmdBuffersData[freeIndex].used = PAL_TRUE; - return &pool->cmdBuffersData[freeIndex]; - } - return nullptr; -} - -static CommandBufferData* findCmdBufferData( - CommandPoolD3D12* pool, - CommandBufferD3D12* cmdBuffer) -{ - for (int i = 0; i < pool->size; i++) { - if (pool->cmdBuffersData[i].used && pool->cmdBuffersData[i].cmdBuffer == cmdBuffer) { - return &pool->cmdBuffersData[i]; - } - } - return nullptr; -} - PalResult PAL_CALL createCommandPoolD3D12( PalDevice* device, PalQueue* queue, @@ -62,18 +22,6 @@ PalResult PAL_CALL createCommandPoolD3D12( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - pool->size = 8; // initial size - pool->cmdBuffersData = nullptr; - pool->cmdBuffersData = palAllocate( - s_D3D12.allocator, - sizeof(CommandBufferData) * pool->size, - 0); - - if (!pool->cmdBuffersData) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } - - memset(pool->cmdBuffersData, 0, sizeof(CommandBufferData) * pool->size); switch (d3d12Queue->type) { case PAL_QUEUE_TYPE_COMPUTE: { pool->type = D3D12_COMMAND_LIST_TYPE_COMPUTE; @@ -98,37 +46,9 @@ PalResult PAL_CALL createCommandPoolD3D12( void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool) { CommandPoolD3D12* cmdPool = (CommandPoolD3D12*)pool; - for (int i = 0; i < cmdPool->size; i++) { - if (!cmdPool->cmdBuffersData[i].used) { - continue; - } - CommandBufferD3D12* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; - cmdBuffer->handle->lpVtbl->Release(cmdBuffer->handle); - cmdBuffer->allocator->lpVtbl->Release(cmdBuffer->allocator); - } - - palFree(s_D3D12.allocator, cmdPool->cmdBuffersData); palFree(s_D3D12.allocator, cmdPool); } -PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool* pool) -{ - CommandPoolD3D12* cmdPool = (CommandPoolD3D12*)pool; - for (int i = 0; i < cmdPool->size; i++) { - if (!cmdPool->cmdBuffersData[i].used) { - continue; - } - - HRESULT ret; - CommandBufferD3D12* cmdBuffer = cmdPool->cmdBuffersData[i].cmdBuffer; - ret = cmdBuffer->handle->lpVtbl->Reset(cmdBuffer->handle, cmdBuffer->allocator, nullptr); - if (FAILED(ret)) { - return makeResultD3D12(ret); - } - } - return PAL_RESULT_SUCCESS; -} - PalResult PAL_CALL allocateCommandBufferD3D12( PalDevice* device, PalCommandPool* pool, @@ -148,12 +68,14 @@ PalResult PAL_CALL allocateCommandBufferD3D12( memset(cmdBuffer, 0, sizeof(CommandBufferD3D12)); cmdBuffer->primary = PAL_TRUE; - // add it to the command pool list - CommandBufferData* cmdData = getFreeCmdBufferData(cmdPool); - if (!cmdData) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; + // allocate memory for the linear allocator. We first start with 4KB + cmdBuffer->linearAllocator.memory = (uint8_t*)palAllocate(s_D3D12.allocator, 4096, 0); + if (!cmdBuffer->linearAllocator.memory) { + PAL_RESULT_CODE_OUT_OF_MEMORY; } + cmdBuffer->linearAllocator.size = 4096; + cmdBuffer->linearAllocator.offset = 0; D3D12_COMMAND_LIST_TYPE cmdBufferType = cmdPool->type; if (type == PAL_COMMAND_BUFFER_TYPE_SECONDARY) { cmdBufferType = D3D12_COMMAND_LIST_TYPE_BUNDLE; @@ -168,6 +90,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdBuffer->allocator); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -183,6 +106,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdList); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -212,6 +136,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdBuffer->buffer); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -228,6 +153,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdBuffer->stagingBuffer); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -237,15 +163,14 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdBuffer->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } cmdList->lpVtbl->Release(cmdList); cmdBuffer->handle->lpVtbl->Close(cmdBuffer->handle); - cmdData->cmdBuffer = cmdBuffer; cmdBuffer->device = d3d12Device; - cmdBuffer->pool = cmdPool; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; } @@ -253,18 +178,13 @@ PalResult PAL_CALL allocateCommandBufferD3D12( void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - CommandPoolD3D12* pool = d3d12CmdBuffer->pool; - CommandBufferData* data = findCmdBufferData(pool, d3d12CmdBuffer); - if (data) { - d3d12CmdBuffer->handle->lpVtbl->Release(d3d12CmdBuffer->handle); - d3d12CmdBuffer->allocator->lpVtbl->Release(d3d12CmdBuffer->allocator); - d3d12CmdBuffer->buffer->lpVtbl->Release(d3d12CmdBuffer->buffer); - d3d12CmdBuffer->stagingBuffer->lpVtbl->Release(d3d12CmdBuffer->stagingBuffer); - - palFree(s_D3D12.allocator, cmdBuffer); - data->cmdBuffer = nullptr; - data->used = PAL_FALSE; - } + d3d12CmdBuffer->handle->lpVtbl->Release(d3d12CmdBuffer->handle); + d3d12CmdBuffer->allocator->lpVtbl->Release(d3d12CmdBuffer->allocator); + d3d12CmdBuffer->buffer->lpVtbl->Release(d3d12CmdBuffer->buffer); + d3d12CmdBuffer->stagingBuffer->lpVtbl->Release(d3d12CmdBuffer->stagingBuffer); + + palFree(s_D3D12.allocator, (void*)d3d12CmdBuffer->linearAllocator.memory); + palFree(s_D3D12.allocator, d3d12CmdBuffer); } PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) @@ -287,6 +207,7 @@ PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) result = d3d12CmdBuffer->handle->lpVtbl->Close(d3d12CmdBuffer->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(result); } @@ -303,6 +224,9 @@ PalResult PAL_CALL submitCommandBufferD3D12( ID3D12CommandQueue* queueHandle = d3d12Queue->handle; CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)info->cmdBuffer; + // poll pending messages + pollMessagesD3D12(d3d12CmdBuffer->device); + // wait semaphore if (info->waitSemaphore) { SemaphoreD3D12* semaphore = (SemaphoreD3D12*)info->waitSemaphore; @@ -313,12 +237,12 @@ PalResult PAL_CALL submitCommandBufferD3D12( } } else { - queueHandle->lpVtbl->Wait(queueHandle, semaphore->handle, semaphore->value); + ret = queueHandle->lpVtbl->Wait(queueHandle, semaphore->handle, semaphore->value); if (FAILED(ret)) { return makeResultD3D12(ret); } - semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); + ret = semaphore->handle->lpVtbl->Signal(semaphore->handle, 0); if (FAILED(ret)) { return makeResultD3D12(ret); } @@ -329,6 +253,8 @@ PalResult PAL_CALL submitCommandBufferD3D12( ID3D12CommandList* cmdLists[1] = { (ID3D12CommandList*)d3d12CmdBuffer->handle }; queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, cmdLists); + pollMessagesD3D12(d3d12CmdBuffer->device); + d3d12Queue->fenceValue++; ret = queueHandle->lpVtbl->Signal(queueHandle, d3d12Queue->fence, d3d12Queue->fenceValue); if (FAILED(ret)) { @@ -351,6 +277,7 @@ PalResult PAL_CALL submitCommandBufferD3D12( if (FAILED(ret)) { return makeResultD3D12(ret); } + } else { semaphore->value = 1; ret = queueHandle->lpVtbl->Signal(queueHandle, semaphore->handle, semaphore->value); diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index 6fa4b004..8ee6fc3c 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -158,6 +158,7 @@ PalResult PAL_CALL cmdBeginD3D12( CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; result = d3d12CmdBuffer->allocator->lpVtbl->Reset(d3d12CmdBuffer->allocator); if (FAILED(result)) { + pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(result); } @@ -167,9 +168,11 @@ PalResult PAL_CALL cmdBeginD3D12( nullptr); if (FAILED(result)) { + pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(result); } + d3d12CmdBuffer->linearAllocator.offset = 0; return PAL_RESULT_SUCCESS; } @@ -178,6 +181,7 @@ PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer) CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; HRESULT result = d3d12CmdBuffer->handle->lpVtbl->Close(d3d12CmdBuffer->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12CmdBuffer->device); return makeResultD3D12(result); } @@ -271,20 +275,15 @@ void PAL_CALL cmdBuildAccelerationStructureD3D12( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { - // TODO: use a temp or arena buffer CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; - geometries = palAllocate( - s_D3D12.allocator, - sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count, + geometries = palLinearAlloc( + &d3d12CmdBuffer->linearAllocator, + sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count, 0); - if (!geometries) { - return PAL_RESULT_CODE_OUT_OF_MEMORY; - } - memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count); fillBuildInfoD3D12(PAL_FALSE, info, geometries, &buildInfo); d3d12CmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( @@ -293,8 +292,6 @@ void PAL_CALL cmdBuildAccelerationStructureD3D12( 0, nullptr); - palFree(s_D3D12.allocator, geometries); - } else { fillBuildInfoD3D12(PAL_FALSE, info, nullptr, &buildInfo); d3d12CmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( @@ -769,10 +766,14 @@ void PAL_CALL cmdBindVertexBuffersD3D12( PalBuffer** buffers, uint64_t* offsets) { - // TODO: use a temp or arena buffer CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; PipelineD3D12* pipeline = d3d12CmdBuffer->pipeline; D3D12_VERTEX_BUFFER_VIEW* views = nullptr; + views = palLinearAlloc( + &d3d12CmdBuffer->linearAllocator, + sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, + 0); + for (int i = 0; i < count; i++) { BufferD3D12* tmp = (BufferD3D12*)buffers[i]; views[i].BufferLocation = tmp->handle->lpVtbl->GetGPUVirtualAddress(tmp->handle); @@ -943,21 +944,20 @@ void PAL_CALL cmdImageBarrierD3D12( PalImageSubresourceRange* subresourceRange, PalBarrierInfo* info) { - // TODO: use a temp or arena buffer CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; ImageD3D12* d3d12Image = (ImageD3D12*)image; D3D12_RESOURCE_STATES old, new; D3D12_RESOURCE_BARRIER barrier = {0}; - old = barrierToD3D12(oldUsageState); - new = barrierToD3D12(newUsageState); + old = barrierToD3D12(info->oldState); + new = barrierToD3D12(info->newState); // read/write barrier without transition if (old == new && old == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.UAV.pResource = d3d12Image->handle; d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); - return PAL_RESULT_SUCCESS; + return; } uint32_t planeCount = 1; // for color or depth @@ -997,10 +997,10 @@ void PAL_CALL cmdImageBarrierD3D12( return; } - barriers = palAllocate(s_D3D12.allocator, sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, 0); - if (!barriers) { - return; - } + barriers = palLinearAlloc( + &d3d12CmdBuffer->linearAllocator, + sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, + 0); uint32_t count = 0; for (uint32_t plane = 0; plane < planeCount; plane++) { @@ -1019,7 +1019,6 @@ void PAL_CALL cmdImageBarrierD3D12( } d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, barrierCount, barriers); - palFree(s_D3D12.allocator, barriers); } void PAL_CALL cmdBufferBarrierD3D12( @@ -1034,8 +1033,8 @@ void PAL_CALL cmdBufferBarrierD3D12( return; } - old = barrierToD3D12(oldUsageState); - new = barrierToD3D12(newUsageState); + old = barrierToD3D12(info->oldState); + new = barrierToD3D12(info->newState); D3D12_RESOURCE_BARRIER barrier = {0}; if (old == new && D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { diff --git a/src/graphics/d3d12/pal_d3d12.c b/src/graphics/d3d12/pal_d3d12.c index dbad6eb1..f7833855 100644 --- a/src/graphics/d3d12/pal_d3d12.c +++ b/src/graphics/d3d12/pal_d3d12.c @@ -14,7 +14,7 @@ IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0x IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0,0x3c, 0x77,0x90,0x0a,0x0a,0x1d,0x17}; IID IID_DebugController = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0}; IID IID_DebugController1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; -IID IID_InfoQueue1 = {0x2852dd88, 0xb484, 0x4c0c, 0xb6,0xb1, 0x67,0x16,0x85,0x00,0xe6,0x00}; +IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4,0xe6,0x14,0x58}; IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3}; IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed}; IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1}; @@ -991,6 +991,67 @@ void getDescriptorTierLimitsD3D12( } } +void pollMessagesD3D12(DeviceD3D12* device) +{ + ID3D12InfoQueue* queue = device->infoQueue; + if (!queue) { + return; + } + + UINT64 messageCount = queue->lpVtbl->GetNumStoredMessages(queue); + for (int i = 0; i < messageCount; i++) { + SIZE_T size = 16384; + uint8_t* buffer = device->scratchBuffer; + queue->lpVtbl->GetMessage(queue, i, (D3D12_MESSAGE*)buffer, &size); + + const char* message = ((D3D12_MESSAGE*)buffer)->pDescription; + D3D12_MESSAGE_CATEGORY category = ((D3D12_MESSAGE*)buffer)->Category; + D3D12_MESSAGE_SEVERITY severity = ((D3D12_MESSAGE*)buffer)->Severity; + + PalDebugMessageSeverity msgSeverity = 0; + PalDebugMessageType msgType = 0; + switch (category) { + case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED: + case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS: + case D3D12_MESSAGE_CATEGORY_COMPILATION: { + msgType = PAL_DEBUG_MESSAGE_TYPE_GENERAL; + break; + } + + case D3D12_MESSAGE_CATEGORY_INITIALIZATION: + case D3D12_MESSAGE_CATEGORY_SHADER: + case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: + case D3D12_MESSAGE_CATEGORY_EXECUTION: + case D3D12_MESSAGE_CATEGORY_STATE_GETTING: + case D3D12_MESSAGE_CATEGORY_STATE_SETTING: { + msgType = PAL_DEBUG_MESSAGE_TYPE_VALIDATION; + break; + } + } + + switch (severity) { + case D3D12_MESSAGE_SEVERITY_INFO: { + msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; + break; + } + + case D3D12_MESSAGE_SEVERITY_WARNING: { + msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; + break; + } + + case D3D12_MESSAGE_SEVERITY_ERROR: + case D3D12_MESSAGE_SEVERITY_CORRUPTION: { + msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_ERROR; + break; + } + } + + s_D3D12.debugCallback(s_D3D12.debugUserData, msgSeverity, msgType, message); + } + queue->lpVtbl->ClearStoredMessages(queue); +} + PalResult PAL_CALL initGraphicsD3D12( const PalGraphicsDebugger* debugger, const PalAllocator* allocator) @@ -1024,42 +1085,47 @@ PalResult PAL_CALL initGraphicsD3D12( "D3D12GetDebugInterface"); if (s_D3D12.getDebugInterface) { - HRESULT hr; ID3D12Debug* debugController = nullptr; ID3D12Debug1* debugController1 = nullptr; - - hr = s_D3D12.getDebugInterface(&IID_DebugController, (void**)&debugController); + HRESULT hr = s_D3D12.getDebugInterface(&IID_DebugController, (void**)&debugController); if (SUCCEEDED(hr)) { debugController->lpVtbl->EnableDebugLayer(debugController); - debugController->lpVtbl->Release(debugController); - } + hr = debugController->lpVtbl->QueryInterface( + debugController, + &IID_DebugController1, + (void**)&debugController1); - hr = s_D3D12.getDebugInterface(&IID_DebugController1, (void**)&debugController1); - if (SUCCEEDED(hr)) { - debugController1->lpVtbl->SetEnableGPUBasedValidation( - debugController1, - TRUE); + if (SUCCEEDED(hr)) { + debugController1->lpVtbl->SetEnableSynchronizedCommandQueueValidation( + debugController1, + TRUE); + + debugController1->lpVtbl->SetEnableGPUBasedValidation( + debugController1, + TRUE); - debugController1->lpVtbl->Release(debugController1); + debugController1->lpVtbl->Release(debugController1); + } + + debugController->lpVtbl->Release(debugController); + } + if (debugController) { // message types - if (!debugger->denyGeneral) { + if (!debugger->denyGeneral) s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_MISCELLANEOUS; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_COMPILATION; + + if (!debugger->denyValidation) { s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_INITIALIZATION; - s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_SETTING; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_SHADER; s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION; - } - - if (!debugger->denyPerformance) { - s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_CREATION; s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_EXECUTION; + s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_GETTING; s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_STATE_SETTING; } - if (!debugger->denyValidation) { - s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_SHADER; - } - // message severities if (!debugger->denyWarningSeverity) { s_D3D12.severities[s_D3D12.severityCount++] = D3D12_MESSAGE_SEVERITY_WARNING; @@ -1069,9 +1135,10 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D12.severities[s_D3D12.severityCount++] = D3D12_MESSAGE_SEVERITY_ERROR; s_D3D12.severities[s_D3D12.severityCount++] = D3D12_MESSAGE_SEVERITY_CORRUPTION; } + + s_D3D12.debugLayer = PAL_TRUE; + s_D3D12.debugCallback = debugger->callback; } - s_D3D12.debugLayer = PAL_TRUE; - s_D3D12.debugCallback = debugger->callback; } } // clang-format on diff --git a/src/graphics/d3d12/pal_d3d12.h b/src/graphics/d3d12/pal_d3d12.h index 0d8bcf8d..281a2502 100644 --- a/src/graphics/d3d12/pal_d3d12.h +++ b/src/graphics/d3d12/pal_d3d12.h @@ -14,6 +14,7 @@ #include #include #include +#include "graphics/pal_linear_allocator.h" #define MAX_RTV 1024 #define MAX_DSV 512 @@ -151,8 +152,8 @@ typedef struct { typedef struct { void* reserved; + void* scratchBuffer; uint32_t shaderModel; - DWORD debugCookie; PalBool canFenceReset; IDXGIAdapter4* adapter; ID3D12CommandSignature* meshSignature; @@ -160,7 +161,7 @@ typedef struct { ID3D12CommandSignature* drawSignature; ID3D12CommandSignature* dispatchSignature; ID3D12CommandSignature* raySignature; - ID3D12InfoQueue1* infoQueue; + ID3D12InfoQueue* infoQueue; ID3D12CommandQueue* queue; ID3D12Device5* handle; RTVHeapAllocator rtvAllocator; @@ -191,7 +192,7 @@ typedef struct { typedef struct { void* reserved; PalBool isMemoryManaged; - ID3D12Device5* device; + DeviceD3D12* device; ID3D12Resource* handle; PalImageInfo info; D3D12_RESOURCE_DESC desc; @@ -220,10 +221,11 @@ typedef struct { uint32_t windowHeight; uint32_t flags; DXGI_FORMAT format; - DXGI_FEATURE presentFlags; + UINT presentFlags; SurfaceD3D12* surface; ImageD3D12* images; ID3D12CommandQueue* queue; + DeviceD3D12* device; IDXGISwapChain3* handle; } SwapchainD3D12; @@ -243,30 +245,23 @@ typedef struct { ShaderEntry* entries; } ShaderD3D12; +typedef struct { + void* reserved; + D3D12_COMMAND_LIST_TYPE type; +} CommandPoolD3D12; + typedef struct { void* reserved; PalBool primary; - void* pool; // CommandPool ID3D12Resource* stagingBuffer; ID3D12Resource* buffer; ID3D12CommandAllocator* allocator; + PalLinearAllocator linearAllocator; void* pipeline; DeviceD3D12* device; ID3D12GraphicsCommandList6* handle; } CommandBufferD3D12; -typedef struct { - PalBool used; - CommandBufferD3D12* cmdBuffer; -} CommandBufferData; - -typedef struct { - void* reserved; - uint32_t size; - D3D12_COMMAND_LIST_TYPE type; - CommandBufferData* cmdBuffersData; -} CommandPoolD3D12; - typedef struct { void* reserved; PalBool isMemoryManaged; @@ -274,7 +269,7 @@ typedef struct { PalBufferUsages usages; uint64_t size; ID3D12Resource* handle; - ID3D12Device5* device; + DeviceD3D12* device; D3D12_RESOURCE_DESC desc; } BufferD3D12; @@ -409,13 +404,15 @@ uint64_t getDescriptorHandleD3D12( uint32_t size, uint64_t baseOffset); +void pollMessagesD3D12(DeviceD3D12* device); + // IIDs extern IID IID_Device; extern IID IID_Adapter; extern IID IID_Factory; extern IID IID_DebugController; extern IID IID_DebugController1; -extern IID IID_InfoQueue1; +extern IID IID_InfoQueue; extern IID IID_Heap; extern IID IID_Queue; extern IID IID_Swapchain; diff --git a/src/graphics/d3d12/pal_descriptors_d3d12.c b/src/graphics/d3d12/pal_descriptors_d3d12.c index 236f6a02..1b747cf8 100644 --- a/src/graphics/d3d12/pal_descriptors_d3d12.c +++ b/src/graphics/d3d12/pal_descriptors_d3d12.c @@ -241,6 +241,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( (void**)&heap->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -281,6 +282,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( (void**)&heap->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c index 76a7575f..2bb6ef11 100644 --- a/src/graphics/d3d12/pal_device_d3d12.c +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -22,54 +22,6 @@ static void convertToWcharD3D12( dst[i] = L'\0'; } -static void __stdcall debugCallbackD3D12( - D3D12_MESSAGE_CATEGORY category, - D3D12_MESSAGE_SEVERITY severity, - D3D12_MESSAGE_ID id, - const char *description, - void *context) -{ - PalDebugMessageSeverity msgSeverity = 0; - PalDebugMessageType msgType = 0; - switch (category) { - case D3D12_MESSAGE_CATEGORY_INITIALIZATION: - case D3D12_MESSAGE_CATEGORY_CLEANUP: - case D3D12_MESSAGE_CATEGORY_COMPILATION: { - msgType = PAL_DEBUG_MESSAGE_TYPE_GENERAL; - break; - } - - case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: - case D3D12_MESSAGE_CATEGORY_EXECUTION: - case D3D12_MESSAGE_CATEGORY_SHADER: { - msgType = PAL_DEBUG_MESSAGE_TYPE_PERFORMANCE; - break; - } - - case D3D12_MESSAGE_CATEGORY_STATE_CREATION: - case D3D12_MESSAGE_CATEGORY_STATE_GETTING: - case D3D12_MESSAGE_CATEGORY_STATE_SETTING: { - msgType = PAL_DEBUG_MESSAGE_TYPE_VALIDATION; - break; - } - } - - switch (severity) { - case D3D12_MESSAGE_SEVERITY_WARNING: { - msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_INFO; - break; - } - - case D3D12_MESSAGE_SEVERITY_ERROR: - case D3D12_MESSAGE_SEVERITY_CORRUPTION: { - msgSeverity = PAL_DEBUG_MESSAGE_SEVERITY_ERROR; - break; - } - } - - s_D3D12.debugCallback(s_D3D12.debugUserData, msgSeverity, msgType, description); -} - PalResult PAL_CALL createDeviceD3D12( PalAdapter* adapter, PalAdapterFeatures features, @@ -117,28 +69,19 @@ PalResult PAL_CALL createDeviceD3D12( if (s_D3D12.debugLayer) { result = device->handle->lpVtbl->QueryInterface( device->handle, - &IID_InfoQueue1, + &IID_InfoQueue, (void**)&device->infoQueue); if (SUCCEEDED(result)) { + // allocate a scratch buffer for messages. 16KB + device->scratchBuffer = palAllocate(s_D3D12.allocator, 16384, 0); + if (!device->scratchBuffer) { + return PAL_RESULT_CODE_OUT_OF_MEMORY; + } + D3D12_MESSAGE_ID denyIDs[] = { D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE, - D3D12_MESSAGE_ID_LIVE_OBJECT_SUMMARY, - D3D12_MESSAGE_ID_LIVE_DEVICE, - D3D12_MESSAGE_ID_LIVE_COMMANDQUEUE, - D3D12_MESSAGE_ID_LIVE_COMMANDALLOCATOR, - D3D12_MESSAGE_ID_LIVE_PIPELINESTATE, - D3D12_MESSAGE_ID_LIVE_COMMANDLIST12, - D3D12_MESSAGE_ID_LIVE_RESOURCE, - D3D12_MESSAGE_ID_LIVE_DESCRIPTORHEAP, - D3D12_MESSAGE_ID_LIVE_ROOTSIGNATURE, - D3D12_MESSAGE_ID_LIVE_LIBRARY, - D3D12_MESSAGE_ID_LIVE_HEAP, - D3D12_MESSAGE_ID_LIVE_MONITOREDFENCE, - D3D12_MESSAGE_ID_LIVE_QUERYHEAP, - D3D12_MESSAGE_ID_LIVE_COMMANDSIGNATURE, - D3D12_MESSAGE_ID_LIVE_COMMANDPOOL, - D3D12_MESSAGE_ID_LIVE_SWAPCHAIN + D3D12_MESSAGE_ID_LIVE_OBJECT_SUMMARY }; device->infoQueue->lpVtbl->SetBreakOnSeverity( @@ -151,19 +94,12 @@ PalResult PAL_CALL createDeviceD3D12( D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE); - device->infoQueue->lpVtbl->RegisterMessageCallback( - device->infoQueue, - debugCallbackD3D12, - D3D12_MESSAGE_CALLBACK_FLAG_NONE, - nullptr, - &device->debugCookie); - D3D12_INFO_QUEUE_FILTER filter = {0}; filter.AllowList.NumSeverities = s_D3D12.severityCount; filter.AllowList.pSeverityList = s_D3D12.severities; filter.AllowList.NumCategories = s_D3D12.categoryCount; filter.AllowList.pCategoryList = s_D3D12.categories; - filter.DenyList.NumIDs = 1; + filter.DenyList.NumIDs = sizeof(denyIDs) / sizeof(D3D12_MESSAGE_ID); filter.DenyList.pIDList = denyIDs; device->infoQueue->lpVtbl->PushStorageFilter(device->infoQueue, &filter); } @@ -403,11 +339,8 @@ void PAL_CALL destroyDeviceD3D12(PalDevice* device) d3d12Device->handle->lpVtbl->Release(d3d12Device->handle); if (d3d12Device->infoQueue) { - d3d12Device->infoQueue->lpVtbl->UnregisterMessageCallback( - d3d12Device->infoQueue, - d3d12Device->debugCookie); - d3d12Device->infoQueue->lpVtbl->Release(d3d12Device->infoQueue); + palFree(s_D3D12.allocator, d3d12Device->scratchBuffer); } palFree(s_D3D12.allocator, d3d12Device); @@ -446,6 +379,7 @@ PalResult PAL_CALL allocateMemoryD3D12( (void**)&memory->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -630,6 +564,7 @@ PalResult PAL_CALL createQueueD3D12( (void**)&queue->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); palFree(s_D3D12.allocator, queue); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_image_d3d12.c b/src/graphics/d3d12/pal_image_d3d12.c index d68db382..80167f98 100644 --- a/src/graphics/d3d12/pal_image_d3d12.c +++ b/src/graphics/d3d12/pal_image_d3d12.c @@ -182,6 +182,7 @@ PalResult PAL_CALL createImageD3D12( (void**)&image->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -199,7 +200,7 @@ PalResult PAL_CALL createImageD3D12( image->info.sampleCount = info->sampleCount; image->info.width = info->width; - image->device = d3d12Device->handle; + image->device = d3d12Device; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } @@ -226,7 +227,7 @@ void PAL_CALL getImageMemoryRequirementsD3D12( PalMemoryRequirements* requirements) { ImageD3D12* d3d12Image = (ImageD3D12*)image; - ID3D12Device5* device = d3d12Image->device; + ID3D12Device5* device = d3d12Image->device->handle; D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; @@ -249,7 +250,7 @@ PalResult PAL_CALL bindImageMemoryD3D12( { HRESULT result; ImageD3D12* d3d12Image = (ImageD3D12*)image; - ID3D12Device5* device = d3d12Image->device; + ID3D12Device5* device = d3d12Image->device->handle; if (d3d12Image->info.belongsToSwapchain) { return PAL_RESULT_CODE_INVALID_OPERATION; } @@ -270,6 +271,7 @@ PalResult PAL_CALL bindImageMemoryD3D12( (void**)&d3d12Image->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Image->device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_pipeline_d3d12.c b/src/graphics/d3d12/pal_pipeline_d3d12.c index 7715dc86..0b0f38ce 100644 --- a/src/graphics/d3d12/pal_pipeline_d3d12.c +++ b/src/graphics/d3d12/pal_pipeline_d3d12.c @@ -545,6 +545,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( ID3DBlob* blob = nullptr; HRESULT result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -557,6 +558,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( (void**)&layout->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -1025,6 +1027,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( &pipeline->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -1072,6 +1075,7 @@ PalResult PAL_CALL createComputePipelineD3D12( &pipeline->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -1364,6 +1368,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( ID3DBlob* blob = nullptr; result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -1376,6 +1381,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( (void**)&pipeline->localRootSignature); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -1406,6 +1412,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( &pipeline->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } diff --git a/src/graphics/d3d12/pal_sbt_d3d12.c b/src/graphics/d3d12/pal_sbt_d3d12.c index dd567032..c1feb723 100644 --- a/src/graphics/d3d12/pal_sbt_d3d12.c +++ b/src/graphics/d3d12/pal_sbt_d3d12.c @@ -71,6 +71,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( ID3D12StateObjectProperties* props = NULL; result = handle->lpVtbl->QueryInterface(handle, &IID_StateObjectProps, (void**)&props); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -170,6 +171,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( (void**)&sbt->buffer); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -186,6 +188,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( (void**)&sbt->stagingBuffer); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -232,6 +235,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( void* ptr = nullptr; result = sbt->stagingBuffer->lpVtbl->Map(sbt->stagingBuffer, 0, nullptr, &ptr); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -345,9 +349,9 @@ PalResult PAL_CALL createShaderBindingTableD3D12( void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) { - // TODO: unmap staging buffer before destroying ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; d3d12Sbt->buffer->lpVtbl->Release(d3d12Sbt->buffer); + d3d12Sbt->stagingBuffer->lpVtbl->Unmap(d3d12Sbt->stagingBuffer, 0, nullptr); d3d12Sbt->stagingBuffer->lpVtbl->Release(d3d12Sbt->stagingBuffer); palFree(s_D3D12.allocator, d3d12Sbt); } diff --git a/src/graphics/d3d12/pal_swapchain_d3d12.c b/src/graphics/d3d12/pal_swapchain_d3d12.c index 564a61a2..26ffb746 100644 --- a/src/graphics/d3d12/pal_swapchain_d3d12.c +++ b/src/graphics/d3d12/pal_swapchain_d3d12.c @@ -236,6 +236,7 @@ PalResult PAL_CALL createSwapchainD3D12( &swapchain1); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); return makeResultD3D12(result); } @@ -286,6 +287,7 @@ PalResult PAL_CALL createSwapchainD3D12( swapchain->windowWidth = windowRect.right - windowRect.left; swapchain->windowWidth = windowRect.bottom - windowRect.top; + swapchain->device = d3d12Device; swapchain->queue = d3d12Queue->handle; swapchain->imageCount = info->imageCount; *outSwapchain = (PalSwapchain*)swapchain; @@ -294,21 +296,21 @@ PalResult PAL_CALL createSwapchainD3D12( void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) { - SwapchainD3D12* d3dSwapchain = (SwapchainD3D12*)swapchain; - d3dSwapchain->handle->lpVtbl->Release(d3dSwapchain->handle); - palFree(s_D3D12.allocator, d3dSwapchain->images); - palFree(s_D3D12.allocator, d3dSwapchain); + SwapchainD3D12* d3d12Swapchain = (SwapchainD3D12*)swapchain; + d3d12Swapchain->handle->lpVtbl->Release(d3d12Swapchain->handle); + palFree(s_D3D12.allocator, d3d12Swapchain->images); + palFree(s_D3D12.allocator, d3d12Swapchain); } PalImage* PAL_CALL getSwapchainImageD3D12( PalSwapchain* swapchain, uint32_t index) { - SwapchainD3D12* d3dSwapchain = (SwapchainD3D12*)swapchain; - if (index > d3dSwapchain->imageCount) { + SwapchainD3D12* d3d12Swapchain = (SwapchainD3D12*)swapchain; + if (index > d3d12Swapchain->imageCount) { return nullptr; } - return (PalImage*)&d3dSwapchain->images[index]; + return (PalImage*)&d3d12Swapchain->images[index]; } PalResult PAL_CALL getNextSwapchainImageD3D12( @@ -318,15 +320,16 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( { HRESULT result; uint32_t index = 0; - SwapchainD3D12* d3dSwapchain = (SwapchainD3D12*)swapchain; - ID3D12CommandQueue* queue = d3dSwapchain->queue; + SwapchainD3D12* d3d12Swapchain = (SwapchainD3D12*)swapchain; + ID3D12CommandQueue* queue = d3d12Swapchain->queue; - index = d3dSwapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3dSwapchain->handle); + index = d3d12Swapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3d12Swapchain->handle); if (info->fence) { FenceD3D12* fence = (FenceD3D12*)info->fence; fence->value++; result = queue->lpVtbl->Signal(queue, fence->handle, fence->value); if (FAILED(result)) { + pollMessagesD3D12(d3d12Swapchain->device); return makeResultD3D12(result); } } @@ -350,8 +353,8 @@ PalResult PAL_CALL presentSwapchainD3D12( PalSemaphore* waitSemaphore) { HRESULT result; - SwapchainD3D12* d3dSwapchain = (SwapchainD3D12*)swapchain; - ID3D12CommandQueue* queue = d3dSwapchain->queue; + SwapchainD3D12* d3d12Swapchain = (SwapchainD3D12*)swapchain; + ID3D12CommandQueue* queue = d3d12Swapchain->queue; if (waitSemaphore) { SemaphoreD3D12* semaphore = (SemaphoreD3D12*)waitSemaphore; @@ -367,19 +370,24 @@ PalResult PAL_CALL presentSwapchainD3D12( } } - result = d3dSwapchain->handle->lpVtbl->Present( - d3dSwapchain->handle, - d3dSwapchain->syncInterval, - d3dSwapchain->presentFlags); + // poll pending messages + pollMessagesD3D12(d3d12Swapchain->device); + result = d3d12Swapchain->handle->lpVtbl->Present( + d3d12Swapchain->handle, + d3d12Swapchain->syncInterval, + d3d12Swapchain->presentFlags); + + pollMessagesD3D12(d3d12Swapchain->device); if (FAILED(result)) { if (result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET) { + pollMessagesD3D12(d3d12Swapchain->device); return makeResultD3D12(result); } // check if swapchain needs to be resize RECT windowRect; - PalBool ret = GetClientRect((HWND)d3dSwapchain->surface->handle, &windowRect); + PalBool ret = GetClientRect((HWND)d3d12Swapchain->surface->handle, &windowRect); uint32_t w = windowRect.right - windowRect.left; uint32_t h = windowRect.bottom - windowRect.top; if (!ret) { @@ -389,7 +397,7 @@ PalResult PAL_CALL presentSwapchainD3D12( GetLastError()); } - if (w != d3dSwapchain->windowWidth || h != d3dSwapchain->windowHeight) { + if (w != d3d12Swapchain->windowWidth || h != d3d12Swapchain->windowHeight) { return PAL_RESULT_CODE_OUT_OF_DATE; } @@ -405,29 +413,30 @@ PalResult PAL_CALL resizeSwapchainD3D12( uint32_t newHeight) { HRESULT result; - SwapchainD3D12* d3dSwapchain = (SwapchainD3D12*)swapchain; - result = d3dSwapchain->handle->lpVtbl->ResizeBuffers( - d3dSwapchain->handle, - d3dSwapchain->imageCount, + SwapchainD3D12* d3d12Swapchain = (SwapchainD3D12*)swapchain; + result = d3d12Swapchain->handle->lpVtbl->ResizeBuffers( + d3d12Swapchain->handle, + d3d12Swapchain->imageCount, newWidth, newHeight, - d3dSwapchain->format, - d3dSwapchain->flags); + d3d12Swapchain->format, + d3d12Swapchain->flags); if (FAILED(result)) { + pollMessagesD3D12(d3d12Swapchain->device); return makeResultD3D12(result); } // fill all images with the creation info - for (int i = 0; i < d3dSwapchain->imageCount; i++) { + for (int i = 0; i < d3d12Swapchain->imageCount; i++) { ID3D12Resource* tmp = nullptr; - d3dSwapchain->handle->lpVtbl->GetBuffer( - d3dSwapchain->handle, + d3d12Swapchain->handle->lpVtbl->GetBuffer( + d3d12Swapchain->handle, i, &IID_Resource, (void**)&tmp); - ImageD3D12* image = &d3dSwapchain->images[i]; + ImageD3D12* image = &d3d12Swapchain->images[i]; image->handle = tmp; image->info.height = newHeight; image->info.width = newWidth; @@ -435,7 +444,7 @@ PalResult PAL_CALL resizeSwapchainD3D12( // get and cache window size for swapchain out of date error RECT windowRect; - SurfaceD3D12* surface = d3dSwapchain->surface; + SurfaceD3D12* surface = d3d12Swapchain->surface; if (!GetClientRect((HWND)surface->handle, &windowRect)) { return palMakeResult( PAL_RESULT_CODE_PLATFORM_FAILURE, @@ -443,8 +452,8 @@ PalResult PAL_CALL resizeSwapchainD3D12( GetLastError()); } - d3dSwapchain->windowWidth = windowRect.right - windowRect.left; - d3dSwapchain->windowWidth = windowRect.bottom - windowRect.top; + d3d12Swapchain->windowWidth = windowRect.right - windowRect.left; + d3d12Swapchain->windowWidth = windowRect.bottom - windowRect.top; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/d3d12/pal_sync_d3d12.c b/src/graphics/d3d12/pal_sync_d3d12.c index 32bb5e2e..f0618d5b 100644 --- a/src/graphics/d3d12/pal_sync_d3d12.c +++ b/src/graphics/d3d12/pal_sync_d3d12.c @@ -30,6 +30,7 @@ PalResult PAL_CALL createFenceD3D12( (void**)&fence->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); palFree(s_D3D12.allocator, fence); return makeResultD3D12(result); } @@ -139,6 +140,7 @@ PalResult PAL_CALL createSemaphoreD3D12( (void**)&semaphore->handle); if (FAILED(result)) { + pollMessagesD3D12(d3d12Device); palFree(s_D3D12.allocator, semaphore); return makeResultD3D12(result); } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index b3d1970e..a0110d67 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -116,7 +116,6 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) // command pool and command buffer !vtable1->createCommandPool || !vtable1->destroyCommandPool || - !vtable1->resetCommandPool || !vtable1->allocateCommandBuffer || !vtable1->freeCommandBuffer || !vtable1->submitCommandBuffer || @@ -271,7 +270,6 @@ static void populateVtableVersion1( // command pool and command buffer vtable->createCommandPool = vtable1->createCommandPool; vtable->destroyCommandPool = vtable1->destroyCommandPool; - vtable->resetCommandPool = vtable1->resetCommandPool; vtable->allocateCommandBuffer = vtable1->allocateCommandBuffer; vtable->freeCommandBuffer = vtable1->freeCommandBuffer; vtable->submitCommandBuffer = vtable1->submitCommandBuffer; @@ -392,16 +390,15 @@ PalResult PAL_CALL palInitGraphics( #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN_BACKEND - // TODO: uncomment - // result = initGraphicsVk(debugger, allocator); - // if (result != PAL_RESULT_SUCCESS) { - // return result; - // } - - // attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - // attachedBackend->base = s_VkBackend; - // attachedBackend->startIndex = 0; - // attachedBackend->count = 0; + result = initGraphicsVk(debugger, allocator); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + + attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; + attachedBackend->base = s_VkBackend; + attachedBackend->startIndex = 0; + attachedBackend->count = 0; #endif // PAL_HAS_VULKAN_BACKEND // D3D12 @@ -443,7 +440,7 @@ void PAL_CALL palShutdownGraphics() #ifdef _WIN32 // vulkan #if PAL_HAS_VULKAN_BACKEND - //TODO: shutdownGraphicsVk(); + shutdownGraphicsVk(); #endif // PAL_HAS_VULKAN_BACKEND // D3D12 @@ -1120,11 +1117,6 @@ void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) pool->backend->destroyCommandPool(pool); } -PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool) -{ - return pool->backend->resetCommandPool(pool); -} - PalResult PAL_CALL palAllocateCommandBuffer( PalDevice* device, PalCommandPool* pool, diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index 91775a6c..ecbd7671 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -72,7 +72,6 @@ typedef struct { PalResult (PAL_CALL *getSemaphoreValue)(PalSemaphore*, uint64_t*); PalResult (PAL_CALL *createCommandPool)(PalDevice*, PalQueue*, PalCommandPool**); void (PAL_CALL *destroyCommandPool)(PalCommandPool*); - PalResult (PAL_CALL *resetCommandPool)(PalCommandPool*); PalResult (PAL_CALL *allocateCommandBuffer)(PalDevice*, PalCommandPool*, PalCommandBufferType, PalCommandBuffer**); void (PAL_CALL *freeCommandBuffer)(PalCommandBuffer*); PalResult (PAL_CALL *resetCommandBuffer)(PalCommandBuffer*); @@ -222,7 +221,6 @@ PalResult PAL_CALL signalSemaphoreVk(PalSemaphore*, PalQueue*, uint64_t); PalResult PAL_CALL getSemaphoreValueVk(PalSemaphore*, uint64_t*); PalResult PAL_CALL createCommandPoolVk(PalDevice*, PalQueue*, PalCommandPool**); void PAL_CALL destroyCommandPoolVk(PalCommandPool*); -PalResult PAL_CALL resetCommandPoolVk(PalCommandPool*); PalResult PAL_CALL allocateCommandBufferVk(PalDevice*, PalCommandPool*, PalCommandBufferType, PalCommandBuffer**); void PAL_CALL freeCommandBufferVk(PalCommandBuffer*); PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer*); @@ -360,7 +358,6 @@ static PalGraphicsVtable s_VkBackend = { .getSemaphoreValue = getSemaphoreValueVk, .createCommandPool = createCommandPoolVk, .destroyCommandPool = destroyCommandPoolVk, - .resetCommandPool = resetCommandPoolVk, .allocateCommandBuffer = allocateCommandBufferVk, .freeCommandBuffer = freeCommandBufferVk, .resetCommandBuffer = resetCommandBufferVk, @@ -455,7 +452,7 @@ PalResult PAL_CALL createDeviceD3D12(PalAdapter*, PalAdapterFeatures, PalDevice* void PAL_CALL destroyDeviceD3D12(PalDevice*); PalResult PAL_CALL waitDeviceD3D12(PalDevice*); PalResult PAL_CALL allocateMemoryD3D12(PalDevice*, PalMemoryType, uint64_t, uint64_t, PalMemory**); -void PAL_CALL freeMemoryD3D12(PalDevice*, PalMemory*); +void PAL_CALL freeMemoryD3D12(PalMemory*); void PAL_CALL querySamplerAnisotropyCapabilitiesD3D12(PalDevice*, PalSamplerAnisotropyCapabilities*); void PAL_CALL queryMultiViewCapabilitiesD3D12(PalDevice*, PalMultiViewCapabilities*); void PAL_CALL queryMultiViewportCapabilitiesD3D12(PalDevice*, PalMultiViewportCapabilities*); @@ -507,14 +504,13 @@ PalResult PAL_CALL signalSemaphoreD3D12(PalSemaphore*, PalQueue*, uint64_t); PalResult PAL_CALL getSemaphoreValueD3D12(PalSemaphore*, uint64_t*); PalResult PAL_CALL createCommandPoolD3D12(PalDevice*, PalQueue*, PalCommandPool**); void PAL_CALL destroyCommandPoolD3D12(PalCommandPool*); -PalResult PAL_CALL resetCommandPoolD3D12(PalCommandPool*); PalResult PAL_CALL allocateCommandBufferD3D12(PalDevice*, PalCommandPool*, PalCommandBufferType, PalCommandBuffer**); void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer*); PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer*); PalResult PAL_CALL submitCommandBufferD3D12(PalQueue*, PalCommandBufferSubmitInfo*); -void PAL_CALL cmdBeginD3D12(PalCommandBuffer*, PalRenderingLayoutInfo*); -void PAL_CALL cmdEndD3D12(PalCommandBuffer*); +PalResult PAL_CALL cmdBeginD3D12(PalCommandBuffer*, PalRenderingLayoutInfo*); +PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer*); void PAL_CALL cmdExecuteCommandBufferD3D12(PalCommandBuffer*, PalCommandBuffer*); void PAL_CALL cmdSetFragmentShadingRateD3D12(PalCommandBuffer*, PalFragmentShadingRateState*); void PAL_CALL cmdDrawMeshTasksD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); @@ -638,7 +634,6 @@ static PalGraphicsVtable s_D3D12Backend = { .getSemaphoreValue = getSemaphoreValueD3D12, .createCommandPool = createCommandPoolD3D12, .destroyCommandPool = destroyCommandPoolD3D12, - .resetCommandPool = resetCommandPoolD3D12, .allocateCommandBuffer = allocateCommandBufferD3D12, .freeCommandBuffer = freeCommandBufferD3D12, .resetCommandBuffer = resetCommandBufferD3D12, diff --git a/src/graphics/vulkan/pal_command_pool_vulkan.c b/src/graphics/vulkan/pal_command_pool_vulkan.c index 9d1e2f04..a9c7b9b9 100644 --- a/src/graphics/vulkan/pal_command_pool_vulkan.c +++ b/src/graphics/vulkan/pal_command_pool_vulkan.c @@ -45,17 +45,6 @@ void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool) palFree(s_Vk.allocator, vkPool); } -PalResult PAL_CALL resetCommandPoolVk(PalCommandPool* pool) -{ - CommandPoolVk* vkCmdPool = (CommandPoolVk*)pool; - VkResult result = s_Vk.resetCommandPool(vkCmdPool->device->handle, vkCmdPool->handle, 0); - if (result != VK_SUCCESS) { - return makeResultVk(result); - } - - return PAL_RESULT_SUCCESS; -} - PalResult PAL_CALL allocateCommandBufferVk( PalDevice* device, PalCommandPool* pool, diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c index 29b8d79e..6b2191e7 100644 --- a/src/graphics/vulkan/pal_commands_vulkan.c +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -395,10 +395,6 @@ void PAL_CALL cmdBuildAccelerationStructureVk( sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->count, 0); - if (!tmpRangeInfos || !rangeInfos || !geometries) { - return; - } - memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->count); memset(rangeInfos, 0, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->count); fillBuildInfoVk(PAL_FALSE, info, geometries, &buildInfo, rangeInfos); @@ -431,10 +427,6 @@ void PAL_CALL cmdBeginRenderingVk( sizeof(VkRenderingAttachmentInfoKHR) * info->colorAttachentCount, 0); - if (!colorAttachments) { - return; - } - VkRenderingAttachmentInfoKHR* attachment = nullptr; PalAttachmentDesc* desc = nullptr; ImageViewVk* imageView = nullptr; diff --git a/src/graphics/vulkan/pal_vulkan.c b/src/graphics/vulkan/pal_vulkan.c index 22c53d16..d7e621da 100644 --- a/src/graphics/vulkan/pal_vulkan.c +++ b/src/graphics/vulkan/pal_vulkan.c @@ -1202,10 +1202,6 @@ PalResult PAL_CALL initGraphicsVk( s_Vk.handle, "vkEndCommandBuffer"); - s_Vk.resetCommandPool = (PFN_vkResetCommandPool)loadProc( - s_Vk.handle, - "vkResetCommandPool"); - s_Vk.resetCommandBuffer = (PFN_vkResetCommandBuffer)loadProc( s_Vk.handle, "vkResetCommandBuffer"); diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h index 9536f1b9..75f60c4d 100644 --- a/src/graphics/vulkan/pal_vulkan.h +++ b/src/graphics/vulkan/pal_vulkan.h @@ -399,7 +399,6 @@ typedef struct { PFN_vkDestroySemaphore destroySemaphore; PFN_vkBeginCommandBuffer cmdBegin; PFN_vkEndCommandBuffer cmdEnd; - PFN_vkResetCommandPool resetCommandPool; PFN_vkResetCommandBuffer resetCommandBuffer; PFN_vkCmdExecuteCommands cmdExecuteCommandBuffer; PFN_vkCmdCopyBuffer cmdCopyBuffer; diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index d334d6b2..df46daab 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -443,7 +443,7 @@ PalBool clearColorTest() barrierInfo.srcStages = barrierInfo.dstStages; barrierInfo.newState = PAL_USAGE_STATE_PRESENT; barrierInfo.dstStages = PAL_PIPELINE_STAGE_NONE; - palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); + // palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { From 21e056eef1e7455ca6cc4674ac65fed48518623f Mon Sep 17 00:00:00 2001 From: nichcode Date: Tue, 14 Jul 2026 21:13:47 +0000 Subject: [PATCH 339/372] start graphics abi dump --- src/graphics/d3d12/pal_adapter_d3d12.c | 2 + src/graphics/vulkan/pal_adapter_vulkan.c | 1 + tests/graphics/graphics_test.c | 1 + tests/tests_main.c | 2 +- tools/abi_dump/abi_dump.lua | 1 + tools/abi_dump/abi_dump_main.c | 4 + tools/abi_dump/dumps.h | 1 + tools/abi_dump/graphics_abi_dump.c | 339 +++++++++++++++++++++++ 8 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 tools/abi_dump/graphics_abi_dump.c diff --git a/src/graphics/d3d12/pal_adapter_d3d12.c b/src/graphics/d3d12/pal_adapter_d3d12.c index fb5cd92c..c99f4574 100644 --- a/src/graphics/d3d12/pal_adapter_d3d12.c +++ b/src/graphics/d3d12/pal_adapter_d3d12.c @@ -152,6 +152,8 @@ void PAL_CALL getAdapterInfoD3D12( info->sharedMemory = desc.SharedSystemMemory; strcpy(info->backendName, "PAL"); + // TODO: add driver version + WideCharToMultiByte( CP_UTF8, 0, diff --git a/src/graphics/vulkan/pal_adapter_vulkan.c b/src/graphics/vulkan/pal_adapter_vulkan.c index db14b3ee..54d3d6fb 100644 --- a/src/graphics/vulkan/pal_adapter_vulkan.c +++ b/src/graphics/vulkan/pal_adapter_vulkan.c @@ -163,6 +163,7 @@ void PAL_CALL getAdapterInfoVk( info->shaderFormats = PAL_SHADER_FORMAT_SPIRV; info->deviceId = props.deviceID; info->vendorId = props.vendorID; + info->driverVersion = props.driverVersion; strcpy(info->name, props.deviceName); strcpy(info->backendName, "PAL"); diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 69104dc2..9250280c 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -91,6 +91,7 @@ PalBool graphicsTest() palLog(nullptr, " Backend Name: %s", info.backendName); palLog(nullptr, " Vendor Id: %u", info.vendorId); palLog(nullptr, " Device Id: %u", info.deviceId); + palLog(nullptr, " Driver Version: %u", info.driverVersion); palLog(nullptr, " Vram %u MB", vramMb); palLog(nullptr, " Shared Memory %u MB", sharedMemMb); diff --git a/tests/tests_main.c b/tests/tests_main.c index 269a186a..e7371f3e 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -69,7 +69,7 @@ int main(int argc, char** argv) // registerTest(textureTest, "Texture Test"); // registerTest(geometryTest, "Geometry Test"); // registerTest(indirectDrawTest, "Indirect Draw Test"); - registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); + // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); #endif // runTests(); diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index 4aac0393..e388448e 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -12,6 +12,7 @@ project "pal-abi-dump" "system_abi_dump.c", "video_abi_dump.c", "opengl_abi_dump.c", + "graphics_abi_dump.c", "abi_dump_main.c" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 507174b8..312327b4 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -101,6 +101,10 @@ int main(int argc, char** argv) openglABIDump(verbose); } + if (dumpGraphics) { + graphicsABIDump(verbose); + } + if (dumpVersion) { palLog(nullptr, "PAL ABI dump %s", VERSION); } diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 9eeca320..42756a4a 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -26,5 +26,6 @@ void threadABIDump(PalBool verbose); void systemABIDump(PalBool verbose); void videoABIDump(PalBool verbose); void openglABIDump(PalBool verbose); +void graphicsABIDump(PalBool verbose); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c new file mode 100644 index 00000000..36cc7351 --- /dev/null +++ b/tools/abi_dump/graphics_abi_dump.c @@ -0,0 +1,339 @@ + +/** + PAL - Prime Abstraction Layer + Copyright (C) 2025 + Licensed under the Zlib license. See LICENSE file in root. + */ + +#include "dumps.h" +#include "pal/pal_graphics.h" + +static void adapterInfoDump(PalBool verbose) +{ + uint32_t xSize = 200; + uint32_t xAlign = 8; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 8; + uint32_t xOffset3 = 16; + uint32_t xOffset4 = 20; + uint32_t xOffset5 = 24; + uint32_t xOffset6 = 28; + uint32_t xOffset7 = 32; + uint32_t xOffset8 = 36; + uint32_t xOffset9 = 40; + uint32_t xOffset10 = 168; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalAdapterInfo); + uint32_t yAlign = PAL_ALIGNOF(PalAdapterInfo); + uint32_t yOffset1 = offsetof(PalAdapterInfo, vram); + uint32_t yOffset2 = offsetof(PalAdapterInfo, sharedMemory); + uint32_t yOffset3 = offsetof(PalAdapterInfo, vendorId); + uint32_t yOffset4 = offsetof(PalAdapterInfo, deviceId); + uint32_t yOffset5 = offsetof(PalAdapterInfo, driverVersion); + uint32_t yOffset6 = offsetof(PalAdapterInfo, shaderFormats); + uint32_t yOffset7 = offsetof(PalAdapterInfo, type); + uint32_t yOffset8 = offsetof(PalAdapterInfo, apiType); + uint32_t yOffset9 = offsetof(PalAdapterInfo, name); + uint32_t yOffset10 = offsetof(PalAdapterInfo, backendName); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xOffset6 == yOffset6 && + xOffset7 == yOffset7 && + xOffset8 == yOffset8 && + xOffset9 == yOffset9 && + xOffset10 == yOffset10 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "struct: PalAdapterInfo"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "vram @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "sharedMemory @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "vendorId @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "deviceId @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "driverVersion @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "shaderFormats @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "type @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "apiType @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "name @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "backendName @ %u %u", xOffset10, yOffset10); + palLog(nullptr, "==========================================="); + } + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void imageCapDump(PalBool verbose) +{ + uint32_t xSize = 20; + uint32_t xAlign = 4; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 4; + uint32_t xOffset3 = 8; + uint32_t xOffset4 = 12; + uint32_t xOffset5 = 16; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalImageCapabilities); + uint32_t yAlign = PAL_ALIGNOF(PalImageCapabilities); + uint32_t yOffset1 = offsetof(PalImageCapabilities, maxWidth); + uint32_t yOffset2 = offsetof(PalImageCapabilities, maxHeight); + uint32_t yOffset3 = offsetof(PalImageCapabilities, maxDepth); + uint32_t yOffset4 = offsetof(PalImageCapabilities, maxArrayLayers); + uint32_t yOffset5 = offsetof(PalImageCapabilities, maxMipLevels); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "struct: PalImageCapabilities"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "maxWidth @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "maxHeight @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "maxDepth @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "maxArrayLayers @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "maxMipLevels @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "==========================================="); + } + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void resourceCapDump(PalBool verbose) +{ + uint32_t xSize = 52; + uint32_t xAlign = 4; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 4; + uint32_t xOffset3 = 8; + uint32_t xOffset4 = 12; + uint32_t xOffset5 = 16; + uint32_t xOffset6 = 20; + uint32_t xOffset7 = 24; + uint32_t xOffset8 = 28; + uint32_t xOffset9 = 32; + uint32_t xOffset10 = 36; + uint32_t xOffset11 = 40; + uint32_t xOffset12 = 44; + uint32_t xOffset13 = 48; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalResourceCapabilities); + uint32_t yAlign = PAL_ALIGNOF(PalResourceCapabilities); + uint32_t yOffset1 = offsetof(PalResourceCapabilities, maxPerStageSampledImages); + uint32_t yOffset2 = offsetof(PalResourceCapabilities, maxPerSetSampledImages); + uint32_t yOffset3 = offsetof(PalResourceCapabilities, maxPerStageStorageImages); + uint32_t yOffset4 = offsetof(PalResourceCapabilities, maxPerSetStorageImages); + uint32_t yOffset5 = offsetof(PalResourceCapabilities, maxPerStageSamplers); + uint32_t yOffset6 = offsetof(PalResourceCapabilities, maxPerSetSamplers); + uint32_t yOffset7 = offsetof(PalResourceCapabilities, maxPerStageStorageBuffers); + uint32_t yOffset8 = offsetof(PalResourceCapabilities, maxPerSetStorageBuffers); + uint32_t yOffset9 = offsetof(PalResourceCapabilities, maxPerStageUniformBuffers); + uint32_t yOffset10 = offsetof(PalResourceCapabilities, maxPerSetUniformBuffers); + uint32_t yOffset11 = offsetof(PalResourceCapabilities, maxPerStageAccelerationStructure); + uint32_t yOffset12 = offsetof(PalResourceCapabilities, maxPerSetAccelerationStructure); + uint32_t yOffset13 = offsetof(PalResourceCapabilities, maxBoundSets); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xOffset5 == yOffset5 && + xOffset6 == yOffset6 && + xOffset7 == yOffset7 && + xOffset8 == yOffset8 && + xOffset9 == yOffset9 && + xOffset10 == yOffset10 && + xOffset11 == yOffset11 && + xOffset12 == yOffset12 && + xOffset13 == yOffset13 && + xPadding == yPadding) { + result = s_PassedString; + } + + palLog(nullptr, "struct: PalResourceCapabilities"); + if (verbose) { + palLog(nullptr, "========================================================"); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "========================================================"); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "maxPerStageSampledImages @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "maxPerSetSampledImages @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "maxPerStageStorageImages @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "maxPerSetStorageImages @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "maxPerStageSamplers @ %u %u", xOffset5, yOffset5); + palLog(nullptr, "maxPerSetSamplers @ %u %u", xOffset6, yOffset6); + palLog(nullptr, "maxPerStageStorageBuffers @ %u %u", xOffset7, yOffset7); + palLog(nullptr, "maxPerSetStorageBuffers @ %u %u", xOffset8, yOffset8); + palLog(nullptr, "maxPerStageUniformBuffers @ %u %u", xOffset9, yOffset9); + palLog(nullptr, "maxPerSetUniformBuffers @ %u %u", xOffset10, yOffset10); + palLog(nullptr, "maxPerStageAccelerationStructure @ %u %u", xOffset11, yOffset11); + palLog(nullptr, "maxPerSetAccelerationStructure @ %u %u", xOffset12, yOffset12); + palLog(nullptr, "maxBoundSets @ %u %u", xOffset13, yOffset13); + palLog(nullptr, "==========================================="); + } + // clang-format on + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void computeCapDump(PalBool verbose) +{ + uint32_t xSize = 28; + uint32_t xAlign = 4; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 4; + uint32_t xOffset3 = 16; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalComputeCapabilities); + uint32_t yAlign = PAL_ALIGNOF(PalComputeCapabilities); + uint32_t yOffset1 = offsetof(PalComputeCapabilities, maxWorkGroupInvocations); + uint32_t yOffset2 = offsetof(PalComputeCapabilities, maxWorkGroupCount); + uint32_t yOffset3 = offsetof(PalComputeCapabilities, maxWorkGroupSize); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "struct: PalComputeCapabilities"); + if (verbose) { + palLog(nullptr, "============================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "=============================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "maxWorkGroupInvocations @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "maxWorkGroupCount[3] @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "maxWorkGroupSize[3] @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "==========================================="); + } + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +static void viewportCapDump(PalBool verbose) +{ + uint32_t xSize = 16; + uint32_t xAlign = 4; + uint32_t xOffset1 = 0; + uint32_t xOffset2 = 4; + uint32_t xOffset3 = 8; + uint32_t xOffset4 = 12; + uint32_t xPadding = 0; + + uint32_t ySize = sizeof(PalViewportCapabilities); + uint32_t yAlign = PAL_ALIGNOF(PalViewportCapabilities); + uint32_t yOffset1 = offsetof(PalViewportCapabilities, maxWidth); + uint32_t yOffset2 = offsetof(PalViewportCapabilities, maxHeight); + uint32_t yOffset3 = offsetof(PalViewportCapabilities, minBoundsRange); + uint32_t yOffset4 = offsetof(PalViewportCapabilities, maxBoundsRange); + uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; + + const char* result = s_FailedString; + // clang-format off + if (xSize == ySize && + xAlign == yAlign && + xOffset1 == yOffset1 && + xOffset2 == yOffset2 && + xOffset3 == yOffset3 && + xOffset4 == yOffset4 && + xPadding == yPadding) { + result = s_PassedString; + } + // clang-format on + + palLog(nullptr, "struct: PalViewportCapabilities"); + if (verbose) { + palLog(nullptr, "==========================================="); + palLog(nullptr, "Field Expected Actual"); + palLog(nullptr, "==========================================="); + + palLog(nullptr, "size %u %u", xSize, ySize); + palLog(nullptr, "align %u %u", xAlign, yAlign); + palLog(nullptr, "padding %u %u", xPadding, yPadding); + palLog(nullptr, "maxWidth @ %u %u", xOffset1, yOffset1); + palLog(nullptr, "maxHeight @ %u %u", xOffset2, yOffset2); + palLog(nullptr, "minBoundsRange @ %u %u", xOffset3, yOffset3); + palLog(nullptr, "maxBoundsRange @ %u %u", xOffset4, yOffset4); + palLog(nullptr, "==========================================="); + } + + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); +} + +void graphicsABIDump(PalBool verbose) +{ + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Graphics ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + + adapterInfoDump(verbose); + imageCapDump(verbose); + resourceCapDump(verbose); + computeCapDump(verbose); + viewportCapDump(verbose); +} \ No newline at end of file From af6b03d69f4f53d2607b550e1ad8dc5ff4c43321 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 15 Jul 2026 21:26:17 +0000 Subject: [PATCH 340/372] change abi dump tool log format --- pal_config.lua | 12 +- tools/abi_dump/abi_dump.lua | 12 +- tools/abi_dump/abi_dump_main.c | 36 +++++- tools/abi_dump/core_abi_dump.c | 198 +++++++++-------------------- tools/abi_dump/dumps.h | 124 ++++++++++++++++-- tools/abi_dump/event_abi_dump.c | 6 +- tools/abi_dump/graphics_abi_dump.c | 10 +- tools/abi_dump/opengl_abi_dump.c | 8 +- tools/abi_dump/system_abi_dump.c | 4 +- tools/abi_dump/thread_abi_dump.c | 2 +- tools/abi_dump/video_abi_dump.c | 14 +- 11 files changed, 237 insertions(+), 189 deletions(-) diff --git a/pal_config.lua b/pal_config.lua index ed26914e..d434cfa8 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -3,22 +3,22 @@ PAL_BUILD_STATIC_LIBRARY = false -- build PAL tests as a single application -PAL_BUILD_TEST_APPLICATION = true +PAL_BUILD_TEST_APPLICATION = false -- build PAL abi dump PAL_BUILD_ABI_DUMP = true -- build system module -PAL_BUILD_SYSTEM_MODULE = true +PAL_BUILD_SYSTEM_MODULE = false -- build thread module -PAL_BUILD_THREAD_MODULE = true +PAL_BUILD_THREAD_MODULE = false -- build video module -PAL_BUILD_VIDEO_MODULE = true +PAL_BUILD_VIDEO_MODULE = false -- build opengl module -PAL_BUILD_OPENGL_MODULE = true +PAL_BUILD_OPENGL_MODULE = false -- build graphics module -PAL_BUILD_GRAPHICS_MODULE = true +PAL_BUILD_GRAPHICS_MODULE = false diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index e388448e..6a0c102d 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -7,12 +7,12 @@ project "pal-abi-dump" files { "core_abi_dump.c", - "event_abi_dump.c", - "thread_abi_dump.c", - "system_abi_dump.c", - "video_abi_dump.c", - "opengl_abi_dump.c", - "graphics_abi_dump.c", + -- "event_abi_dump.c", + -- "thread_abi_dump.c", + -- "system_abi_dump.c", + -- "video_abi_dump.c", + -- "opengl_abi_dump.c", + -- "graphics_abi_dump.c", "abi_dump_main.c" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 312327b4..020c53e6 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -30,6 +30,7 @@ int main(int argc, char** argv) PalBool dumpVersion = PAL_FALSE; PalBool dumpHelp = PAL_FALSE; PalBool verbose = PAL_FALSE; + PalBool status = PAL_FALSE; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--all") == 0) { @@ -78,31 +79,52 @@ int main(int argc, char** argv) } if (dumpCore) { - coreABIDump(verbose); + status = coreABIDump(verbose); + if (status == PAL_FALSE) { + return -1; + } } if (dumpEvent) { - eventABIDump(verbose); + // status = eventABIDump(verbose); + // if (status == PAL_FALSE) { + // return -1; + // } } if (dumpThread) { - threadABIDump(verbose); + // status = threadABIDump(verbose); + // if (status == PAL_FALSE) { + // return -1; + // } } if (dumpSystem) { - systemABIDump(verbose); + // status = systemABIDump(verbose); + // if (status == PAL_FALSE) { + // return -1; + // } } if (dumpVideo) { - videoABIDump(verbose); + // status = videoABIDump(verbose); + // if (status == PAL_FALSE) { + // return -1; + // } } if (dumpOpengl) { - openglABIDump(verbose); + // status = openglABIDump(verbose); + // if (status == PAL_FALSE) { + // return -1; + // } } if (dumpGraphics) { - graphicsABIDump(verbose); + // status = graphicsABIDump(verbose); + // if (status == PAL_FALSE) { + // return -1; + // } } if (dumpVersion) { diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c index 467a3963..d3084e0c 100644 --- a/tools/abi_dump/core_abi_dump.c +++ b/tools/abi_dump/core_abi_dump.c @@ -7,152 +7,72 @@ #include "dumps.h" -static void versionDump(PalBool verbose) +PalBool coreABIDump(PalBool verbose) { - uint32_t xSize = 12; - uint32_t xAlign = 4; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 4; - uint32_t xOffset3 = 8; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalVersion); - uint32_t yAlign = PAL_ALIGNOF(PalVersion); - uint32_t yOffset1 = offsetof(PalVersion, major); - uint32_t yOffset2 = offsetof(PalVersion, minor); - uint32_t yOffset3 = offsetof(PalVersion, build); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalVersion"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "major @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "minor @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "build @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); -} - -static void allocatorDump(PalBool verbose) -{ - uint32_t xSize = 24; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 16; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalAllocator); - uint32_t yAlign = PAL_ALIGNOF(PalAllocator); - uint32_t yOffset1 = offsetof(PalAllocator, allocate); - uint32_t yOffset2 = offsetof(PalAllocator, free); - uint32_t yOffset3 = offsetof(PalAllocator, userData); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalAllocator"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "allocate @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "free @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "userData @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Core ABI Dump"); + palLog(nullptr, "==========================================="); palLog(nullptr, ""); -} - -static void loggerDump(PalBool verbose) -{ - uint32_t xSize = 16; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalLogger); - uint32_t yAlign = PAL_ALIGNOF(PalLogger); - uint32_t yOffset1 = offsetof(PalLogger, callback); - uint32_t yOffset2 = offsetof(PalLogger, userData); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xPadding == yPadding) { - result = s_PassedString; + FieldInfo versionFields[] = { + { "major", {0, 4}, FIELD(PalVersion, major) }, + { "minor", {4, 4}, FIELD(PalVersion, minor) }, + { "build", {8, 4}, FIELD(PalVersion, build) } + }; + + StructInfo versionInfo = {0}; + versionInfo.name = "PalVersion"; + versionInfo.fields = versionFields; + versionInfo.fieldCount = ARRAY_SIZE(versionFields); + versionInfo.expected.alignof = 4; + versionInfo.expected.size = 12; + versionInfo.expected.padding = 0; + versionInfo.actual = STRUCT(PalVersion); + + PalBool status = checkABI(&versionInfo, verbose); + if (status == PAL_FALSE) { + return status; } - // clang-format on - palLog(nullptr, "struct: PalLogger"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "allocate @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "userData @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "==========================================="); + FieldInfo allocatorFields[] = { + { "allocate", {0, 8}, FIELD(PalAllocator, allocate) }, + { "free", {8, 8}, FIELD(PalAllocator, free) }, + { "userData", {16, 8}, FIELD(PalAllocator, userData) } + }; + + StructInfo allocatorInfo = {0}; + allocatorInfo.name = "PalAllocator"; + allocatorInfo.fields = allocatorFields; + allocatorInfo.fieldCount = ARRAY_SIZE(allocatorFields); + allocatorInfo.expected.alignof = 8; + allocatorInfo.expected.size = 24; + allocatorInfo.expected.padding = 0; + allocatorInfo.actual = STRUCT(PalAllocator); + + status = checkABI(&allocatorInfo, verbose); + if (status == PAL_FALSE) { + return status; } - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -void coreABIDump(PalBool verbose) -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Core ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); + FieldInfo loggerFields[] = { + { "callback", {0, 8}, FIELD(PalLogger, callback) }, + { "userData", {8, 8}, FIELD(PalLogger, userData) } + }; + + StructInfo loggerInfo = {0}; + loggerInfo.name = "PalLogger"; + loggerInfo.fields = loggerFields; + loggerInfo.fieldCount = ARRAY_SIZE(loggerFields); + loggerInfo.expected.alignof = 8; + loggerInfo.expected.size = 16; + loggerInfo.expected.padding = 0; + loggerInfo.actual = STRUCT(PalLogger); + + status = checkABI(&loggerInfo, verbose); + if (status == PAL_FALSE) { + return status; + } - versionDump(verbose); - allocatorDump(verbose); - loggerDump(verbose); + return PAL_TRUE; } \ No newline at end of file diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 42756a4a..55756d31 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -15,17 +15,123 @@ static const char* s_FailedString = "FAILED"; static const char* s_PassedString = "PASSED"; #ifdef _MSC_VER -#define PAL_ALIGNOF(type) __alignof(type) +#define ALIGNOF(type) __alignof(type) #else -#define PAL_ALIGNOF(type) __alignof__(type) +#define ALIGNOF(type) __alignof__(type) #endif // _MSC_VER -void coreABIDump(PalBool verbose); -void eventABIDump(PalBool verbose); -void threadABIDump(PalBool verbose); -void systemABIDump(PalBool verbose); -void videoABIDump(PalBool verbose); -void openglABIDump(PalBool verbose); -void graphicsABIDump(PalBool verbose); +typedef struct { + uint32_t offset; + uint32_t size; +} FieldBase; + +typedef struct { + uint32_t alignof; + uint32_t size; + uint32_t padding; +} StructBase; + +typedef struct { + const char* name; + FieldBase expected; + FieldBase actual; +} FieldInfo; + +typedef struct { + const char* name; + FieldInfo* fields; + uint32_t fieldCount; + StructBase expected; + StructBase actual; +} StructInfo; + +static PalBool checkABI( + const StructInfo* info, + PalBool verbose) +{ + // find the size of the field column + uint32_t fieldSize = 0; + const uint32_t expectedSize = 12; + const uint32_t actualSize = 6; + char seperator[256]; + PalBool passed = PAL_TRUE; + const char* result = s_PassedString; + + if (info->expected.size != info->actual.size && + info->expected.alignof != info->actual.alignof && + info->expected.padding != info->actual.padding) { + passed = PAL_FALSE; + result = s_FailedString; + } + + for (uint32_t i = 0; i < info->fieldCount; i++) { + FieldInfo* field = &info->fields[i]; + uint32_t size = strlen(field->name); + if (size > fieldSize) { + fieldSize = size; + } + } + + fieldSize += 2; // add 6 spaces + palLog(nullptr, "%llu", fieldSize); + uint32_t seperatorSize = fieldSize + expectedSize + actualSize + 4; // add 4 spaces + for (int i = 0; i < seperatorSize; i++) { + seperator[i] = '='; + } + seperator[seperatorSize] = '\0'; + + palLog(nullptr, "Struct: %s", info->name); + if (verbose) { + palLog(nullptr, seperator); + palLog( + nullptr, + "%-*s %-*s %-*s", + fieldSize, + "Field", + expectedSize, + "Expected", + actualSize, + "Actual"); + palLog(nullptr, seperator); + } + + for (uint32_t i = 0; i < info->fieldCount; i++) { + FieldInfo* field = &info->fields[i]; + if (field->expected.offset != field->actual.offset && + field->expected.size != field->actual.size) { + passed = PAL_FALSE; + result = s_FailedString; + } + + if (verbose) { + palLog(nullptr, + "%-*s (%03zu, %02zu) (%03zu, %02zu)", + fieldSize, + field->name, + field->expected.offset, + field->expected.size, + field->actual.offset, + field->actual.size); + } + } + palLog(nullptr, seperator); + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); + + return passed; +} + +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#define FIELD(type, field) ((FieldBase){offsetof(type, field), sizeof(((type*)0)->field)}) +#define PADDING(type) (ALIGNOF(type) - sizeof(type) % ALIGNOF(type)) +#define STRUCT(type) ((StructBase){ALIGNOF(type), sizeof(type), PADDING(type)}) + +PalBool coreABIDump(PalBool verbose); +// PalBool eventABIDump(PalBool verbose); +// PalBool threadABIDump(PalBool verbose); +// PalBool systemABIDump(PalBool verbose); +// PalBool videoABIDump(PalBool verbose); +// PalBool openglABIDump(PalBool verbose); +// PalBool graphicsABIDump(PalBool verbose); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index 534bf2c5..7fb66a58 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -19,7 +19,7 @@ static void eventDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalEvent); - uint32_t yAlign = PAL_ALIGNOF(PalEvent); + uint32_t yAlign = ALIGNOF(PalEvent); uint32_t yOffset1 = offsetof(PalEvent, data); uint32_t yOffset2 = offsetof(PalEvent, data2); uint32_t yOffset3 = offsetof(PalEvent, userId); @@ -69,7 +69,7 @@ static void eventQueueDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalEventQueue); - uint32_t yAlign = PAL_ALIGNOF(PalEventQueue); + uint32_t yAlign = ALIGNOF(PalEventQueue); uint32_t yOffset1 = offsetof(PalEventQueue, push); uint32_t yOffset2 = offsetof(PalEventQueue, poll); uint32_t yOffset3 = offsetof(PalEventQueue, userData); @@ -117,7 +117,7 @@ static void eventCreateInfoDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalEventDriverCreateInfo); - uint32_t yAlign = PAL_ALIGNOF(PalEventDriverCreateInfo); + uint32_t yAlign = ALIGNOF(PalEventDriverCreateInfo); uint32_t yOffset1 = offsetof(PalEventDriverCreateInfo, allocator); uint32_t yOffset2 = offsetof(PalEventDriverCreateInfo, queue); uint32_t yOffset3 = offsetof(PalEventDriverCreateInfo, callback); diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index 36cc7351..c440b6d1 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -25,7 +25,7 @@ static void adapterInfoDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalAdapterInfo); - uint32_t yAlign = PAL_ALIGNOF(PalAdapterInfo); + uint32_t yAlign = ALIGNOF(PalAdapterInfo); uint32_t yOffset1 = offsetof(PalAdapterInfo, vram); uint32_t yOffset2 = offsetof(PalAdapterInfo, sharedMemory); uint32_t yOffset3 = offsetof(PalAdapterInfo, vendorId); @@ -95,7 +95,7 @@ static void imageCapDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalImageCapabilities); - uint32_t yAlign = PAL_ALIGNOF(PalImageCapabilities); + uint32_t yAlign = ALIGNOF(PalImageCapabilities); uint32_t yOffset1 = offsetof(PalImageCapabilities, maxWidth); uint32_t yOffset2 = offsetof(PalImageCapabilities, maxHeight); uint32_t yOffset3 = offsetof(PalImageCapabilities, maxDepth); @@ -158,7 +158,7 @@ static void resourceCapDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalResourceCapabilities); - uint32_t yAlign = PAL_ALIGNOF(PalResourceCapabilities); + uint32_t yAlign = ALIGNOF(PalResourceCapabilities); uint32_t yOffset1 = offsetof(PalResourceCapabilities, maxPerStageSampledImages); uint32_t yOffset2 = offsetof(PalResourceCapabilities, maxPerSetSampledImages); uint32_t yOffset3 = offsetof(PalResourceCapabilities, maxPerStageStorageImages); @@ -235,7 +235,7 @@ static void computeCapDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalComputeCapabilities); - uint32_t yAlign = PAL_ALIGNOF(PalComputeCapabilities); + uint32_t yAlign = ALIGNOF(PalComputeCapabilities); uint32_t yOffset1 = offsetof(PalComputeCapabilities, maxWorkGroupInvocations); uint32_t yOffset2 = offsetof(PalComputeCapabilities, maxWorkGroupCount); uint32_t yOffset3 = offsetof(PalComputeCapabilities, maxWorkGroupSize); @@ -283,7 +283,7 @@ static void viewportCapDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalViewportCapabilities); - uint32_t yAlign = PAL_ALIGNOF(PalViewportCapabilities); + uint32_t yAlign = ALIGNOF(PalViewportCapabilities); uint32_t yOffset1 = offsetof(PalViewportCapabilities, maxWidth); uint32_t yOffset2 = offsetof(PalViewportCapabilities, maxHeight); uint32_t yOffset3 = offsetof(PalViewportCapabilities, minBoundsRange); diff --git a/tools/abi_dump/opengl_abi_dump.c b/tools/abi_dump/opengl_abi_dump.c index 343a2df0..ef78d964 100644 --- a/tools/abi_dump/opengl_abi_dump.c +++ b/tools/abi_dump/opengl_abi_dump.c @@ -23,7 +23,7 @@ static void infoDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalGLInfo); - uint32_t yAlign = PAL_ALIGNOF(PalGLInfo); + uint32_t yAlign = ALIGNOF(PalGLInfo); uint32_t yOffset1 = offsetof(PalGLInfo, extensions); uint32_t yOffset2 = offsetof(PalGLInfo, major); uint32_t yOffset3 = offsetof(PalGLInfo, minor); @@ -93,7 +93,7 @@ static void configDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalGLFBConfig); - uint32_t yAlign = PAL_ALIGNOF(PalGLFBConfig); + uint32_t yAlign = ALIGNOF(PalGLFBConfig); uint32_t yOffset1 = offsetof(PalGLFBConfig, doubleBuffer); uint32_t yOffset2 = offsetof(PalGLFBConfig, stereo); uint32_t yOffset3 = offsetof(PalGLFBConfig, sRGB); @@ -163,7 +163,7 @@ static void windowDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalGLWindow); - uint32_t yAlign = PAL_ALIGNOF(PalGLWindow); + uint32_t yAlign = ALIGNOF(PalGLWindow); uint32_t yOffset1 = offsetof(PalGLWindow, instance); uint32_t yOffset2 = offsetof(PalGLWindow, window); uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; @@ -215,7 +215,7 @@ static void contextDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalGLContextCreateInfo); - uint32_t yAlign = PAL_ALIGNOF(PalGLContextCreateInfo); + uint32_t yAlign = ALIGNOF(PalGLContextCreateInfo); uint32_t yOffset1 = offsetof(PalGLContextCreateInfo, window); uint32_t yOffset2 = offsetof(PalGLContextCreateInfo, fbConfig); uint32_t yOffset3 = offsetof(PalGLContextCreateInfo, shareContext); diff --git a/tools/abi_dump/system_abi_dump.c b/tools/abi_dump/system_abi_dump.c index 6e9aca75..26c8cc76 100644 --- a/tools/abi_dump/system_abi_dump.c +++ b/tools/abi_dump/system_abi_dump.c @@ -21,7 +21,7 @@ static void platformDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalPlatformInfo); - uint32_t yAlign = PAL_ALIGNOF(PalPlatformInfo); + uint32_t yAlign = ALIGNOF(PalPlatformInfo); uint32_t yOffset1 = offsetof(PalPlatformInfo, type); uint32_t yOffset2 = offsetof(PalPlatformInfo, apiType); uint32_t yOffset3 = offsetof(PalPlatformInfo, totalMemory); @@ -83,7 +83,7 @@ static void cpuDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalCPUInfo); - uint32_t yAlign = PAL_ALIGNOF(PalCPUInfo); + uint32_t yAlign = ALIGNOF(PalCPUInfo); uint32_t yOffset1 = offsetof(PalCPUInfo, features); uint32_t yOffset2 = offsetof(PalCPUInfo, architecture); uint32_t yOffset3 = offsetof(PalCPUInfo, numCores); diff --git a/tools/abi_dump/thread_abi_dump.c b/tools/abi_dump/thread_abi_dump.c index dfd6ddf9..231f4d5a 100644 --- a/tools/abi_dump/thread_abi_dump.c +++ b/tools/abi_dump/thread_abi_dump.c @@ -24,7 +24,7 @@ void threadABIDump(PalBool verbose) uint32_t xOffset4 = 24; uint32_t ySize = sizeof(PalThreadCreateInfo); - uint32_t yAlign = PAL_ALIGNOF(PalThreadCreateInfo); + uint32_t yAlign = ALIGNOF(PalThreadCreateInfo); uint32_t yOffset1 = offsetof(PalThreadCreateInfo, stackSize); uint32_t yOffset2 = offsetof(PalThreadCreateInfo, allocator); uint32_t yOffset3 = offsetof(PalThreadCreateInfo, entry); diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index 8ff2e795..31d50c0c 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -24,7 +24,7 @@ static void monitorDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalMonitorInfo); - uint32_t yAlign = PAL_ALIGNOF(PalMonitorInfo); + uint32_t yAlign = ALIGNOF(PalMonitorInfo); uint32_t yOffset1 = offsetof(PalMonitorInfo, x); uint32_t yOffset2 = offsetof(PalMonitorInfo, y); uint32_t yOffset3 = offsetof(PalMonitorInfo, width); @@ -90,7 +90,7 @@ static void monitorModeDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalMonitorMode); - uint32_t yAlign = PAL_ALIGNOF(PalMonitorMode); + uint32_t yAlign = ALIGNOF(PalMonitorMode); uint32_t yOffset1 = offsetof(PalMonitorMode, bpp); uint32_t yOffset2 = offsetof(PalMonitorMode, refreshRate); uint32_t yOffset3 = offsetof(PalMonitorMode, width); @@ -140,7 +140,7 @@ static void flashDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalFlashInfo); - uint32_t yAlign = PAL_ALIGNOF(PalFlashInfo); + uint32_t yAlign = ALIGNOF(PalFlashInfo); uint32_t yOffset1 = offsetof(PalFlashInfo, flags); uint32_t yOffset2 = offsetof(PalFlashInfo, interval); uint32_t yOffset3 = offsetof(PalFlashInfo, count); @@ -187,7 +187,7 @@ static void iconDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalIconCreateInfo); - uint32_t yAlign = PAL_ALIGNOF(PalIconCreateInfo); + uint32_t yAlign = ALIGNOF(PalIconCreateInfo); uint32_t yOffset1 = offsetof(PalIconCreateInfo, pixels); uint32_t yOffset2 = offsetof(PalIconCreateInfo, width); uint32_t yOffset3 = offsetof(PalIconCreateInfo, height); @@ -236,7 +236,7 @@ static void cursorDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalCursorCreateInfo); - uint32_t yAlign = PAL_ALIGNOF(PalCursorCreateInfo); + uint32_t yAlign = ALIGNOF(PalCursorCreateInfo); uint32_t yOffset1 = offsetof(PalCursorCreateInfo, pixels); uint32_t yOffset2 = offsetof(PalCursorCreateInfo, width); uint32_t yOffset3 = offsetof(PalCursorCreateInfo, height); @@ -291,7 +291,7 @@ static void windowInfoDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalWindowHandleInfo); - uint32_t yAlign = PAL_ALIGNOF(PalWindowHandleInfo); + uint32_t yAlign = ALIGNOF(PalWindowHandleInfo); uint32_t yOffset1 = offsetof(PalWindowHandleInfo, nativeInstance); uint32_t yOffset2 = offsetof(PalWindowHandleInfo, nativeWindow); uint32_t yOffset3 = offsetof(PalWindowHandleInfo, nativeHandle1); @@ -353,7 +353,7 @@ static void windowDump(PalBool verbose) uint32_t xPadding = 0; uint32_t ySize = sizeof(PalWindowCreateInfo); - uint32_t yAlign = PAL_ALIGNOF(PalWindowCreateInfo); + uint32_t yAlign = ALIGNOF(PalWindowCreateInfo); uint32_t yOffset1 = offsetof(PalWindowCreateInfo, title); uint32_t yOffset2 = offsetof(PalWindowCreateInfo, monitor); uint32_t yOffset3 = offsetof(PalWindowCreateInfo, appName); From aca29822183d9e07533962d2d42c821a849622b7 Mon Sep 17 00:00:00 2001 From: nichcode Date: Wed, 15 Jul 2026 22:10:23 +0000 Subject: [PATCH 341/372] add event and thread abi dump --- tools/abi_dump/abi_dump.lua | 4 +- tools/abi_dump/abi_dump_main.c | 16 +-- tools/abi_dump/dumps.h | 13 +- tools/abi_dump/event_abi_dump.c | 213 +++++++++---------------------- tools/abi_dump/thread_abi_dump.c | 62 +++------ 5 files changed, 98 insertions(+), 210 deletions(-) diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index 6a0c102d..73226688 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -7,8 +7,8 @@ project "pal-abi-dump" files { "core_abi_dump.c", - -- "event_abi_dump.c", - -- "thread_abi_dump.c", + "event_abi_dump.c", + "thread_abi_dump.c", -- "system_abi_dump.c", -- "video_abi_dump.c", -- "opengl_abi_dump.c", diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 020c53e6..06f990db 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -86,17 +86,17 @@ int main(int argc, char** argv) } if (dumpEvent) { - // status = eventABIDump(verbose); - // if (status == PAL_FALSE) { - // return -1; - // } + status = eventABIDump(verbose); + if (status == PAL_FALSE) { + return -1; + } } if (dumpThread) { - // status = threadABIDump(verbose); - // if (status == PAL_FALSE) { - // return -1; - // } + status = threadABIDump(verbose); + if (status == PAL_FALSE) { + return -1; + } } if (dumpSystem) { diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 55756d31..c1007dff 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -73,7 +73,6 @@ static PalBool checkABI( } fieldSize += 2; // add 6 spaces - palLog(nullptr, "%llu", fieldSize); uint32_t seperatorSize = fieldSize + expectedSize + actualSize + 4; // add 4 spaces for (int i = 0; i < seperatorSize; i++) { seperator[i] = '='; @@ -82,7 +81,9 @@ static PalBool checkABI( palLog(nullptr, "Struct: %s", info->name); if (verbose) { + palLog(nullptr, "Field Format: %s", "(Offset, Size)"); palLog(nullptr, seperator); + palLog( nullptr, "%-*s %-*s %-*s", @@ -92,6 +93,7 @@ static PalBool checkABI( "Expected", actualSize, "Actual"); + palLog(nullptr, seperator); } @@ -114,7 +116,10 @@ static PalBool checkABI( field->actual.size); } } - palLog(nullptr, seperator); + if (verbose) { + palLog(nullptr, seperator); + } + palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); @@ -127,8 +132,8 @@ static PalBool checkABI( #define STRUCT(type) ((StructBase){ALIGNOF(type), sizeof(type), PADDING(type)}) PalBool coreABIDump(PalBool verbose); -// PalBool eventABIDump(PalBool verbose); -// PalBool threadABIDump(PalBool verbose); +PalBool eventABIDump(PalBool verbose); +PalBool threadABIDump(PalBool verbose); // PalBool systemABIDump(PalBool verbose); // PalBool videoABIDump(PalBool verbose); // PalBool openglABIDump(PalBool verbose); diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index 7fb66a58..2e3d036d 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -8,164 +8,73 @@ #include "dumps.h" #include "pal/pal_event.h" -static void eventDump(PalBool verbose) +PalBool eventABIDump(PalBool verbose) { - uint32_t xSize = 24; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 16; - uint32_t xOffset4 = 20; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalEvent); - uint32_t yAlign = ALIGNOF(PalEvent); - uint32_t yOffset1 = offsetof(PalEvent, data); - uint32_t yOffset2 = offsetof(PalEvent, data2); - uint32_t yOffset3 = offsetof(PalEvent, userId); - uint32_t yOffset4 = offsetof(PalEvent, type); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalEvent"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "data @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "data2 @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "userId @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "type @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); -} - -static void eventQueueDump(PalBool verbose) -{ - uint32_t xSize = 24; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 16; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalEventQueue); - uint32_t yAlign = ALIGNOF(PalEventQueue); - uint32_t yOffset1 = offsetof(PalEventQueue, push); - uint32_t yOffset2 = offsetof(PalEventQueue, poll); - uint32_t yOffset3 = offsetof(PalEventQueue, userData); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalEventQueue"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "push @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "poll @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "userData @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Event ABI Dump"); + palLog(nullptr, "==========================================="); palLog(nullptr, ""); -} - -static void eventCreateInfoDump(PalBool verbose) -{ - uint32_t xSize = 32; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 16; - uint32_t xOffset4 = 24; - uint32_t xPadding = 0; - uint32_t ySize = sizeof(PalEventDriverCreateInfo); - uint32_t yAlign = ALIGNOF(PalEventDriverCreateInfo); - uint32_t yOffset1 = offsetof(PalEventDriverCreateInfo, allocator); - uint32_t yOffset2 = offsetof(PalEventDriverCreateInfo, queue); - uint32_t yOffset3 = offsetof(PalEventDriverCreateInfo, callback); - uint32_t yOffset4 = offsetof(PalEventDriverCreateInfo, userData); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xPadding == yPadding) { - result = s_PassedString; + FieldInfo eventFields[] = { + { "data", {0, 8}, FIELD(PalEvent, data) }, + { "data2", {8, 8}, FIELD(PalEvent, data2) }, + { "userId", {16, 4}, FIELD(PalEvent, userId) }, + { "type", {20, 4}, FIELD(PalEvent, type) } + }; + + StructInfo eventInfo = {0}; + eventInfo.name = "PalEvent"; + eventInfo.fields = eventFields; + eventInfo.fieldCount = ARRAY_SIZE(eventFields); + eventInfo.expected.alignof = 8; + eventInfo.expected.size = 24; + eventInfo.expected.padding = 0; + eventInfo.actual = STRUCT(PalEvent); + + PalBool status = checkABI(&eventInfo, verbose); + if (status == PAL_FALSE) { + return status; } - // clang-format on - - palLog(nullptr, "struct: PalEventDriverCreateInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "allocator @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "queue @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "callback @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "userData @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "==========================================="); + FieldInfo eventQueueFields[] = { + { "push", {0, 8}, FIELD(PalEventQueue, push) }, + { "poll", {8, 8}, FIELD(PalEventQueue, poll) }, + { "userData", {16, 8}, FIELD(PalEventQueue, userData) } + }; + + StructInfo eventQueueInfo = {0}; + eventQueueInfo.name = "PalEventQueue"; + eventQueueInfo.fields = eventQueueFields; + eventQueueInfo.fieldCount = ARRAY_SIZE(eventQueueFields); + eventQueueInfo.expected.alignof = 8; + eventQueueInfo.expected.size = 24; + eventQueueInfo.expected.padding = 0; + eventQueueInfo.actual = STRUCT(PalEventQueue); + + status = checkABI(&eventQueueInfo, verbose); + if (status == PAL_FALSE) { + return status; } - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -void eventABIDump(PalBool verbose) -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Event ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - eventDump(verbose); - eventQueueDump(verbose); - eventCreateInfoDump(verbose); + FieldInfo eventDriverCreateInfoFields[] = { + { "allocator", {0, 8}, FIELD(PalEventDriverCreateInfo, allocator) }, + { "queue", {8, 8}, FIELD(PalEventDriverCreateInfo, queue) }, + { "callback", {16, 8}, FIELD(PalEventDriverCreateInfo, callback) }, + { "userData", {24, 8}, FIELD(PalEventDriverCreateInfo, userData) }, + }; + + StructInfo eventDriverCreateInfo = {0}; + eventDriverCreateInfo.name = "PalEventDriverCreateInfo"; + eventDriverCreateInfo.fields = eventDriverCreateInfoFields; + eventDriverCreateInfo.fieldCount = ARRAY_SIZE(eventDriverCreateInfoFields); + eventDriverCreateInfo.expected.alignof = 8; + eventDriverCreateInfo.expected.size = 24; + eventDriverCreateInfo.expected.padding = 0; + eventDriverCreateInfo.actual = STRUCT(PalEventDriverCreateInfo); + + status = checkABI(&eventDriverCreateInfo, verbose); + if (status == PAL_FALSE) { + return status; + } } \ No newline at end of file diff --git a/tools/abi_dump/thread_abi_dump.c b/tools/abi_dump/thread_abi_dump.c index 231f4d5a..bd78930b 100644 --- a/tools/abi_dump/thread_abi_dump.c +++ b/tools/abi_dump/thread_abi_dump.c @@ -8,7 +8,7 @@ #include "dumps.h" #include "pal/pal_thread.h" -void threadABIDump(PalBool verbose) +PalBool threadABIDump(PalBool verbose) { palLog(nullptr, ""); palLog(nullptr, "==========================================="); @@ -16,47 +16,21 @@ void threadABIDump(PalBool verbose) palLog(nullptr, "==========================================="); palLog(nullptr, ""); - uint32_t xSize = 32; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 16; - uint32_t xOffset4 = 24; - - uint32_t ySize = sizeof(PalThreadCreateInfo); - uint32_t yAlign = ALIGNOF(PalThreadCreateInfo); - uint32_t yOffset1 = offsetof(PalThreadCreateInfo, stackSize); - uint32_t yOffset2 = offsetof(PalThreadCreateInfo, allocator); - uint32_t yOffset3 = offsetof(PalThreadCreateInfo, entry); - uint32_t yOffset4 = offsetof(PalThreadCreateInfo, arg); - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalThreadCreateInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "stackSize @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "allocator @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "entry @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "arg @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); + FieldInfo threadCreateInfoFields[] = { + { "stackSize", {0, 8}, FIELD(PalThreadCreateInfo, stackSize) }, + { "allocator", {8, 8}, FIELD(PalThreadCreateInfo, allocator) }, + { "entry", {16, 8}, FIELD(PalThreadCreateInfo, entry) }, + { "arg", {24, 8}, FIELD(PalThreadCreateInfo, arg) } + }; + + StructInfo threadCreateInfo = {0}; + threadCreateInfo.name = "PalThreadCreateInfo"; + threadCreateInfo.fields = threadCreateInfoFields; + threadCreateInfo.fieldCount = ARRAY_SIZE(threadCreateInfoFields); + threadCreateInfo.expected.alignof = 8; + threadCreateInfo.expected.size = 32; + threadCreateInfo.expected.padding = 0; + threadCreateInfo.actual = STRUCT(PalThreadCreateInfo); + + return checkABI(&threadCreateInfo, verbose); } \ No newline at end of file From fe59b9c2ec8cc2c37bfc94d483344c7e92acb59e Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 16 Jul 2026 10:06:10 +0000 Subject: [PATCH 342/372] optimize abi-dump and add system abi dump --- premake5.lua | 49 +++++++-- tools/abi_dump/abi_dump.lua | 4 +- tools/abi_dump/abi_dump_main.c | 85 +++++++-------- tools/abi_dump/core_abi_dump.c | 41 ++++--- tools/abi_dump/dumps.h | 17 +-- tools/abi_dump/event_abi_dump.c | 47 ++++---- tools/abi_dump/system_abi_dump.c | 179 ++++++++----------------------- 7 files changed, 178 insertions(+), 244 deletions(-) diff --git a/premake5.lua b/premake5.lua index 73732541..d2e10a66 100644 --- a/premake5.lua +++ b/premake5.lua @@ -172,26 +172,49 @@ local function generateTasksJson() end end -local function writeLaunchConfiguration(file, isDebug) +local function writeLaunchConfiguration(file, app, isDebug) local name = "" local preLaunchTask = "" local dir = "" + local cwd = "" if isDebug then name = "launch debug" preLaunchTask = "build debug" dir = "Debug" - else name = "launch release" preLaunchTask = "build release" dir = "Release" end - if os.target() == "windows" then - program = "tests.exe" + if app == "tests" then + cwd = "tests" + if isDebug then + name = "launch tests debug" + else + name = "launch tests release" + end + + if os.target() == "windows" then + program = "tests.exe" + else + program = "tests" + end + else - program = "tests" + cwd = "tools/abi_dump" + if isDebug then + name = "launch abi-dump debug" + else + name = "launch abi-dump release" + end + + if os.target() == "windows" then + program = "abi-dump.exe" + else + program = "abi-dump" + end end file:write(" {\n") @@ -199,7 +222,7 @@ local function writeLaunchConfiguration(file, isDebug) file:write(' "type": "cppdbg",\n') file:write(' "request": "launch",\n') file:write(' "stopAtEntry": false,\n') - file:write(' "cwd": "${workspaceFolder}/tests",\n') + file:write(string.format(' "cwd": "${workspaceFolder}/%s",\n', cwd)) file:write(' "environment": [],\n') file:write(' "externalConsole": false,\n') @@ -236,11 +259,19 @@ local function generateLaunchJson() file:write('{\n') file:write(' "configurations": [\n') - writeLaunchConfiguration(file, true) + writeLaunchConfiguration(file, "tests", true) + file:write(" },\n") + file:write('\n') + + writeLaunchConfiguration(file, "tests", false) + file:write(" },\n") + file:write('\n') + + writeLaunchConfiguration(file, "abi-dump", true) file:write(" },\n") file:write('\n') - writeLaunchConfiguration(file, false) + writeLaunchConfiguration(file, "abi-dump", false) file:write(" }\n") file:write(" ],\n") @@ -277,7 +308,7 @@ workspace(workspaceName) if PAL_BUILD_TEST_APPLICATION then startproject("tests") else - startproject("pal-abi-dump") + startproject("abi-dump") end if PAL_BUILD_STATIC_LIBRARY then diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index 73226688..c0aa6d29 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -1,5 +1,5 @@ -project "pal-abi-dump" +project "abi-dump" kind "ConsoleApp" targetdir(targetDir) @@ -9,7 +9,7 @@ project "pal-abi-dump" "core_abi_dump.c", "event_abi_dump.c", "thread_abi_dump.c", - -- "system_abi_dump.c", + "system_abi_dump.c", -- "video_abi_dump.c", -- "opengl_abi_dump.c", -- "graphics_abi_dump.c", diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 06f990db..628e3569 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -10,128 +10,121 @@ #define VERSION "1.0" #ifdef _WIN32 -#define EXE_NAME "pal-abi-dump.exe" +#define EXE_NAME "abi-dump.exe" #else -#define EXE_NAME "pal-abi-dump" +#define EXE_NAME "abi-dump" #endif // _WIN32 +#define DUMP_FLAG_CORE (1u << 0) +#define DUMP_FLAG_EVENT (1u << 1) +#define DUMP_FLAG_THREAD (1u << 2) +#define DUMP_FLAG_OPENGL (1u << 3) +#define DUMP_FLAG_GRAPHICS (1u << 4) +#define DUMP_FLAG_SYSTEM (1u << 5) +#define DUMP_FLAG_VIDEO (1u << 6) +#define DUMP_FLAG_VERSION (1u << 7) +#define DUMP_FLAG_HELP (1u << 8) +#define DUMP_FLAG_ALL 0x7F + // clang-format off int main(int argc, char** argv) { // clang-format on - PalBool dumpAll = PAL_FALSE; - PalBool dumpCore = PAL_FALSE; - PalBool dumpEvent = PAL_FALSE; - PalBool dumpThread = PAL_FALSE; - PalBool dumpOpengl = PAL_FALSE; - PalBool dumpGraphics = PAL_FALSE; - PalBool dumpSystem = PAL_FALSE; - PalBool dumpVideo = PAL_FALSE; - PalBool dumpVersion = PAL_FALSE; - PalBool dumpHelp = PAL_FALSE; PalBool verbose = PAL_FALSE; PalBool status = PAL_FALSE; + uint32_t dumpFlags = 0; for (int i = 1; i < argc; i++) { - if (strcmp(argv[i], "--all") == 0) { - dumpAll = PAL_TRUE; - - } else if (strcmp(argv[i], "--core") == 0) { - dumpCore = PAL_TRUE; + if (strcmp(argv[i], "--core") == 0) { + dumpFlags |= DUMP_FLAG_CORE; } else if (strcmp(argv[i], "--event") == 0) { - dumpEvent = PAL_TRUE; + dumpFlags |= DUMP_FLAG_EVENT; } else if (strcmp(argv[i], "--graphics") == 0) { - dumpGraphics = PAL_TRUE; + dumpFlags |= DUMP_FLAG_GRAPHICS; } else if (strcmp(argv[i], "--opengl") == 0) { - dumpOpengl = PAL_TRUE; + dumpFlags |= DUMP_FLAG_OPENGL; } else if (strcmp(argv[i], "--system") == 0) { - dumpSystem = PAL_TRUE; + dumpFlags |= DUMP_FLAG_SYSTEM; } else if (strcmp(argv[i], "--thread") == 0) { - dumpThread = PAL_TRUE; + dumpFlags |= DUMP_FLAG_THREAD; } else if (strcmp(argv[i], "--video") == 0) { - dumpVideo = PAL_TRUE; + dumpFlags |= DUMP_FLAG_VIDEO; } else if (strcmp(argv[i], "--version") == 0) { - dumpVersion = PAL_TRUE; + dumpFlags |= DUMP_FLAG_VERSION; } else if (strcmp(argv[i], "--help") == 0) { - dumpHelp = PAL_TRUE; + dumpFlags |= DUMP_FLAG_HELP; } else if (strcmp(argv[i], "--verbose") == 0) { verbose = PAL_TRUE; } } - if (dumpAll) { - dumpCore = PAL_TRUE; - dumpEvent = PAL_TRUE; - dumpThread = PAL_TRUE; - dumpOpengl = PAL_TRUE; - dumpGraphics = PAL_TRUE; - dumpSystem = PAL_TRUE; - dumpVideo = PAL_TRUE; + if (dumpFlags == 0) { + dumpFlags |= DUMP_FLAG_ALL; } - if (dumpCore) { + if (dumpFlags & DUMP_FLAG_CORE) { status = coreABIDump(verbose); if (status == PAL_FALSE) { return -1; } } - if (dumpEvent) { + if (dumpFlags & DUMP_FLAG_EVENT) { status = eventABIDump(verbose); if (status == PAL_FALSE) { return -1; } } - if (dumpThread) { + if (dumpFlags & DUMP_FLAG_THREAD) { status = threadABIDump(verbose); if (status == PAL_FALSE) { return -1; } } - if (dumpSystem) { - // status = systemABIDump(verbose); - // if (status == PAL_FALSE) { - // return -1; - // } + if (dumpFlags & DUMP_FLAG_SYSTEM) { + status = systemABIDump(verbose); + if (status == PAL_FALSE) { + return -1; + } } - if (dumpVideo) { + if (dumpFlags & DUMP_FLAG_VIDEO) { // status = videoABIDump(verbose); // if (status == PAL_FALSE) { // return -1; // } } - if (dumpOpengl) { + if (dumpFlags & DUMP_FLAG_OPENGL) { // status = openglABIDump(verbose); // if (status == PAL_FALSE) { // return -1; // } } - if (dumpGraphics) { + if (dumpFlags & DUMP_FLAG_GRAPHICS) { // status = graphicsABIDump(verbose); // if (status == PAL_FALSE) { // return -1; // } } - if (dumpVersion) { + if (dumpFlags & DUMP_FLAG_VERSION) { palLog(nullptr, "PAL ABI dump %s", VERSION); } - if (dumpHelp) { + if (dumpFlags & DUMP_FLAG_HELP) { palLog(nullptr, "USAGE: %s [options]", EXE_NAME); palLog(nullptr, "Options:"); palLog(nullptr, " --help Display available options"); diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c index d3084e0c..b0447059 100644 --- a/tools/abi_dump/core_abi_dump.c +++ b/tools/abi_dump/core_abi_dump.c @@ -21,6 +21,17 @@ PalBool coreABIDump(PalBool verbose) { "build", {8, 4}, FIELD(PalVersion, build) } }; + FieldInfo allocatorFields[] = { + { "allocate", {0, 8}, FIELD(PalAllocator, allocate) }, + { "free", {8, 8}, FIELD(PalAllocator, free) }, + { "userData", {16, 8}, FIELD(PalAllocator, userData) } + }; + + FieldInfo loggerFields[] = { + { "callback", {0, 8}, FIELD(PalLogger, callback) }, + { "userData", {8, 8}, FIELD(PalLogger, userData) } + }; + StructInfo versionInfo = {0}; versionInfo.name = "PalVersion"; versionInfo.fields = versionFields; @@ -30,17 +41,6 @@ PalBool coreABIDump(PalBool verbose) versionInfo.expected.padding = 0; versionInfo.actual = STRUCT(PalVersion); - PalBool status = checkABI(&versionInfo, verbose); - if (status == PAL_FALSE) { - return status; - } - - FieldInfo allocatorFields[] = { - { "allocate", {0, 8}, FIELD(PalAllocator, allocate) }, - { "free", {8, 8}, FIELD(PalAllocator, free) }, - { "userData", {16, 8}, FIELD(PalAllocator, userData) } - }; - StructInfo allocatorInfo = {0}; allocatorInfo.name = "PalAllocator"; allocatorInfo.fields = allocatorFields; @@ -50,16 +50,6 @@ PalBool coreABIDump(PalBool verbose) allocatorInfo.expected.padding = 0; allocatorInfo.actual = STRUCT(PalAllocator); - status = checkABI(&allocatorInfo, verbose); - if (status == PAL_FALSE) { - return status; - } - - FieldInfo loggerFields[] = { - { "callback", {0, 8}, FIELD(PalLogger, callback) }, - { "userData", {8, 8}, FIELD(PalLogger, userData) } - }; - StructInfo loggerInfo = {0}; loggerInfo.name = "PalLogger"; loggerInfo.fields = loggerFields; @@ -69,10 +59,15 @@ PalBool coreABIDump(PalBool verbose) loggerInfo.expected.padding = 0; loggerInfo.actual = STRUCT(PalLogger); - status = checkABI(&loggerInfo, verbose); + PalBool status = checkABI(&versionInfo, verbose); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&allocatorInfo, verbose); if (status == PAL_FALSE) { return status; } - return PAL_TRUE; + return checkABI(&loggerInfo, verbose); } \ No newline at end of file diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index c1007dff..90d591cd 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -57,12 +57,14 @@ static PalBool checkABI( PalBool passed = PAL_TRUE; const char* result = s_PassedString; - if (info->expected.size != info->actual.size && - info->expected.alignof != info->actual.alignof && + // clang-format off + if (info->expected.size != info->actual.size || + info->expected.alignof != info->actual.alignof || info->expected.padding != info->actual.padding) { passed = PAL_FALSE; result = s_FailedString; } + // clang-format on for (uint32_t i = 0; i < info->fieldCount; i++) { FieldInfo* field = &info->fields[i]; @@ -99,15 +101,18 @@ static PalBool checkABI( for (uint32_t i = 0; i < info->fieldCount; i++) { FieldInfo* field = &info->fields[i]; - if (field->expected.offset != field->actual.offset && + + // clang-format off + if (field->expected.offset != field->actual.offset || field->expected.size != field->actual.size) { passed = PAL_FALSE; result = s_FailedString; } + // clang-format on if (verbose) { palLog(nullptr, - "%-*s (%03zu, %02zu) (%03zu, %02zu)", + "%-*s (%03u, %02u) (%03u, %02u)", fieldSize, field->name, field->expected.offset, @@ -128,13 +133,13 @@ static PalBool checkABI( #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) #define FIELD(type, field) ((FieldBase){offsetof(type, field), sizeof(((type*)0)->field)}) -#define PADDING(type) (ALIGNOF(type) - sizeof(type) % ALIGNOF(type)) +#define PADDING(type) (((ALIGNOF(type) - sizeof(type)) % ALIGNOF(type))) #define STRUCT(type) ((StructBase){ALIGNOF(type), sizeof(type), PADDING(type)}) PalBool coreABIDump(PalBool verbose); PalBool eventABIDump(PalBool verbose); PalBool threadABIDump(PalBool verbose); -// PalBool systemABIDump(PalBool verbose); +PalBool systemABIDump(PalBool verbose); // PalBool videoABIDump(PalBool verbose); // PalBool openglABIDump(PalBool verbose); // PalBool graphicsABIDump(PalBool verbose); diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index 2e3d036d..8f521ead 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -23,6 +23,19 @@ PalBool eventABIDump(PalBool verbose) { "type", {20, 4}, FIELD(PalEvent, type) } }; + FieldInfo eventQueueFields[] = { + { "push", {0, 8}, FIELD(PalEventQueue, push) }, + { "poll", {8, 8}, FIELD(PalEventQueue, poll) }, + { "userData", {16, 8}, FIELD(PalEventQueue, userData) } + }; + + FieldInfo eventDriverCreateInfoFields[] = { + { "allocator", {0, 8}, FIELD(PalEventDriverCreateInfo, allocator) }, + { "queue", {8, 8}, FIELD(PalEventDriverCreateInfo, queue) }, + { "callback", {16, 8}, FIELD(PalEventDriverCreateInfo, callback) }, + { "userData", {24, 8}, FIELD(PalEventDriverCreateInfo, userData) }, + }; + StructInfo eventInfo = {0}; eventInfo.name = "PalEvent"; eventInfo.fields = eventFields; @@ -32,17 +45,6 @@ PalBool eventABIDump(PalBool verbose) eventInfo.expected.padding = 0; eventInfo.actual = STRUCT(PalEvent); - PalBool status = checkABI(&eventInfo, verbose); - if (status == PAL_FALSE) { - return status; - } - - FieldInfo eventQueueFields[] = { - { "push", {0, 8}, FIELD(PalEventQueue, push) }, - { "poll", {8, 8}, FIELD(PalEventQueue, poll) }, - { "userData", {16, 8}, FIELD(PalEventQueue, userData) } - }; - StructInfo eventQueueInfo = {0}; eventQueueInfo.name = "PalEventQueue"; eventQueueInfo.fields = eventQueueFields; @@ -52,29 +54,24 @@ PalBool eventABIDump(PalBool verbose) eventQueueInfo.expected.padding = 0; eventQueueInfo.actual = STRUCT(PalEventQueue); - status = checkABI(&eventQueueInfo, verbose); - if (status == PAL_FALSE) { - return status; - } - - FieldInfo eventDriverCreateInfoFields[] = { - { "allocator", {0, 8}, FIELD(PalEventDriverCreateInfo, allocator) }, - { "queue", {8, 8}, FIELD(PalEventDriverCreateInfo, queue) }, - { "callback", {16, 8}, FIELD(PalEventDriverCreateInfo, callback) }, - { "userData", {24, 8}, FIELD(PalEventDriverCreateInfo, userData) }, - }; - StructInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.name = "PalEventDriverCreateInfo"; eventDriverCreateInfo.fields = eventDriverCreateInfoFields; eventDriverCreateInfo.fieldCount = ARRAY_SIZE(eventDriverCreateInfoFields); eventDriverCreateInfo.expected.alignof = 8; - eventDriverCreateInfo.expected.size = 24; + eventDriverCreateInfo.expected.size = 32; eventDriverCreateInfo.expected.padding = 0; eventDriverCreateInfo.actual = STRUCT(PalEventDriverCreateInfo); - status = checkABI(&eventDriverCreateInfo, verbose); + PalBool status = checkABI(&eventInfo, verbose); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&eventQueueInfo, verbose); if (status == PAL_FALSE) { return status; } + + return checkABI(&eventDriverCreateInfo, verbose); } \ No newline at end of file diff --git a/tools/abi_dump/system_abi_dump.c b/tools/abi_dump/system_abi_dump.c index 26c8cc76..981d6ab2 100644 --- a/tools/abi_dump/system_abi_dump.c +++ b/tools/abi_dump/system_abi_dump.c @@ -8,137 +8,7 @@ #include "dumps.h" #include "pal/pal_system.h" -static void platformDump(PalBool verbose) -{ - uint32_t xSize = 60; - uint32_t xAlign = 4; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 4; - uint32_t xOffset3 = 8; - uint32_t xOffset4 = 12; - uint32_t xOffset5 = 16; - uint32_t xOffset6 = 28; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalPlatformInfo); - uint32_t yAlign = ALIGNOF(PalPlatformInfo); - uint32_t yOffset1 = offsetof(PalPlatformInfo, type); - uint32_t yOffset2 = offsetof(PalPlatformInfo, apiType); - uint32_t yOffset3 = offsetof(PalPlatformInfo, totalMemory); - uint32_t yOffset4 = offsetof(PalPlatformInfo, totalRAM); - uint32_t yOffset5 = offsetof(PalPlatformInfo, version); - uint32_t yOffset6 = offsetof(PalPlatformInfo, name); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xOffset6 == yOffset6 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalPlatformInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "type @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "apiType @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "totalMemory @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "totalRAM @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "version @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "name @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -static void cpuDump(PalBool verbose) -{ - uint32_t xSize = 112; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 12; - uint32_t xOffset4 = 16; - uint32_t xOffset5 = 20; - uint32_t xOffset6 = 24; - uint32_t xOffset7 = 28; - uint32_t xOffset8 = 32; - uint32_t xOffset9 = 48; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalCPUInfo); - uint32_t yAlign = ALIGNOF(PalCPUInfo); - uint32_t yOffset1 = offsetof(PalCPUInfo, features); - uint32_t yOffset2 = offsetof(PalCPUInfo, architecture); - uint32_t yOffset3 = offsetof(PalCPUInfo, numCores); - uint32_t yOffset4 = offsetof(PalCPUInfo, cacheL1); - uint32_t yOffset5 = offsetof(PalCPUInfo, cacheL2); - uint32_t yOffset6 = offsetof(PalCPUInfo, cacheL3); - uint32_t yOffset7 = offsetof(PalCPUInfo, numLogicalProcessors); - uint32_t yOffset8 = offsetof(PalCPUInfo, vendor); - uint32_t yOffset9 = offsetof(PalCPUInfo, model); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xOffset6 == yOffset6 && - xOffset7 == yOffset7 && - xOffset8 == yOffset8 && - xOffset9 == yOffset9 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalCPUInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "features @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "architecture @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "numCores @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "cacheL1 @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "cacheL2 @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "cacheL3 @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "numLogicalProcessors @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "vendor @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "model @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -void systemABIDump(PalBool verbose) +PalBool systemABIDump(PalBool verbose) { palLog(nullptr, ""); palLog(nullptr, "==========================================="); @@ -146,6 +16,49 @@ void systemABIDump(PalBool verbose) palLog(nullptr, "==========================================="); palLog(nullptr, ""); - platformDump(verbose); - cpuDump(verbose); + FieldInfo platformInfoFields[] = { + { "type", {0, 4}, FIELD(PalPlatformInfo, type) }, + { "apiType", {4, 4}, FIELD(PalPlatformInfo, apiType) }, + { "totalMemory", {8, 4}, FIELD(PalPlatformInfo, totalMemory) }, + { "totalRAM", {12, 4}, FIELD(PalPlatformInfo, totalRAM) }, + { "version", {16, 12}, FIELD(PalPlatformInfo, version) }, + { "name", {28, 32}, FIELD(PalPlatformInfo, name) } + }; + + FieldInfo cpuInfoFields[] = { + { "features", {0, 8}, FIELD(PalCPUInfo, features) }, + { "architecture", {8, 4}, FIELD(PalCPUInfo, architecture) }, + { "numCores", {12, 4}, FIELD(PalCPUInfo, numCores) }, + { "cacheL1", {16, 4}, FIELD(PalCPUInfo, cacheL1) }, + { "cacheL2", {20, 4}, FIELD(PalCPUInfo, cacheL2) }, + { "cacheL3", {24, 4}, FIELD(PalCPUInfo, cacheL3) }, + { "numLogicalProcessors", {28, 4}, FIELD(PalCPUInfo, numLogicalProcessors) }, + { "vendor", {32, 16}, FIELD(PalCPUInfo, vendor) }, + { "model", {48, 64}, FIELD(PalCPUInfo, model) } + }; + + StructInfo platformInfo = {0}; + platformInfo.name = "PalPlatformInfo"; + platformInfo.fields = platformInfoFields; + platformInfo.fieldCount = ARRAY_SIZE(platformInfoFields); + platformInfo.expected.alignof = 4; + platformInfo.expected.size = 60; + platformInfo.expected.padding = 0; + platformInfo.actual = STRUCT(PalPlatformInfo); + + StructInfo cpuInfo = {0}; + cpuInfo.name = "PalCPUInfo"; + cpuInfo.fields = cpuInfoFields; + cpuInfo.fieldCount = ARRAY_SIZE(cpuInfoFields); + cpuInfo.expected.alignof = 8; + cpuInfo.expected.size = 112; + cpuInfo.expected.padding = 0; + cpuInfo.actual = STRUCT(PalCPUInfo); + + PalBool status = checkABI(&platformInfo, verbose); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&cpuInfo, verbose); } \ No newline at end of file From 37b7fdf0d96a3bf99db1e03443896f70201a8279 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 16 Jul 2026 13:01:10 +0000 Subject: [PATCH 343/372] add video and opengl abi dumps --- tools/abi_dump/abi_dump.lua | 4 +- tools/abi_dump/abi_dump_main.c | 16 +- tools/abi_dump/dumps.h | 19 +- tools/abi_dump/opengl_abi_dump.c | 364 ++++++-------------- tools/abi_dump/video_abi_dump.c | 556 ++++++++----------------------- 5 files changed, 265 insertions(+), 694 deletions(-) diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index c0aa6d29..9094b09b 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -10,8 +10,8 @@ project "abi-dump" "event_abi_dump.c", "thread_abi_dump.c", "system_abi_dump.c", - -- "video_abi_dump.c", - -- "opengl_abi_dump.c", + "video_abi_dump.c", + "opengl_abi_dump.c", -- "graphics_abi_dump.c", "abi_dump_main.c" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 628e3569..7e3781e9 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -100,17 +100,17 @@ int main(int argc, char** argv) } if (dumpFlags & DUMP_FLAG_VIDEO) { - // status = videoABIDump(verbose); - // if (status == PAL_FALSE) { - // return -1; - // } + status = videoABIDump(verbose); + if (status == PAL_FALSE) { + return -1; + } } if (dumpFlags & DUMP_FLAG_OPENGL) { - // status = openglABIDump(verbose); - // if (status == PAL_FALSE) { - // return -1; - // } + status = openglABIDump(verbose); + if (status == PAL_FALSE) { + return -1; + } } if (dumpFlags & DUMP_FLAG_GRAPHICS) { diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 90d591cd..ad6177f6 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -51,8 +51,8 @@ static PalBool checkABI( { // find the size of the field column uint32_t fieldSize = 0; - const uint32_t expectedSize = 12; - const uint32_t actualSize = 6; + const uint32_t expectedSize = 14; + const uint32_t actualSize = 8; char seperator[256]; PalBool passed = PAL_TRUE; const char* result = s_PassedString; @@ -83,7 +83,14 @@ static PalBool checkABI( palLog(nullptr, "Struct: %s", info->name); if (verbose) { - palLog(nullptr, "Field Format: %s", "(Offset, Size)"); + palLog(nullptr, ""); + palLog(nullptr, "Struct format: Property: (Expected, Actual)"); + palLog(nullptr, "Field format: (Offset, Size)"); + palLog(nullptr, ""); + + palLog(nullptr, "Size: (%03u, %03u)", info->expected.size, info->actual.size); + palLog(nullptr, "Alignment: (%u, %u)", info->expected.alignof, info->actual.alignof); + palLog(nullptr, "Padding: (%02u, %02u)", info->expected.padding, info->actual.padding); palLog(nullptr, seperator); palLog( @@ -112,7 +119,7 @@ static PalBool checkABI( if (verbose) { palLog(nullptr, - "%-*s (%03u, %02u) (%03u, %02u)", + "%-*s (%03u, %03u) (%03u, %03u)", fieldSize, field->name, field->expected.offset, @@ -140,8 +147,8 @@ PalBool coreABIDump(PalBool verbose); PalBool eventABIDump(PalBool verbose); PalBool threadABIDump(PalBool verbose); PalBool systemABIDump(PalBool verbose); -// PalBool videoABIDump(PalBool verbose); -// PalBool openglABIDump(PalBool verbose); +PalBool videoABIDump(PalBool verbose); +PalBool openglABIDump(PalBool verbose); // PalBool graphicsABIDump(PalBool verbose); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/opengl_abi_dump.c b/tools/abi_dump/opengl_abi_dump.c index ef78d964..dca084fe 100644 --- a/tools/abi_dump/opengl_abi_dump.c +++ b/tools/abi_dump/opengl_abi_dump.c @@ -8,284 +8,108 @@ #include "dumps.h" #include "pal/pal_opengl.h" -static void infoDump(PalBool verbose) +PalBool openglABIDump(PalBool verbose) { - uint32_t xSize = 184; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 12; - uint32_t xOffset4 = 16; - uint32_t xOffset5 = 20; - uint32_t xOffset6 = 24; - uint32_t xOffset7 = 56; - uint32_t xOffset8 = 120; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalGLInfo); - uint32_t yAlign = ALIGNOF(PalGLInfo); - uint32_t yOffset1 = offsetof(PalGLInfo, extensions); - uint32_t yOffset2 = offsetof(PalGLInfo, major); - uint32_t yOffset3 = offsetof(PalGLInfo, minor); - uint32_t yOffset4 = offsetof(PalGLInfo, backend); - uint32_t yOffset5 = offsetof(PalGLInfo, api); - uint32_t yOffset6 = offsetof(PalGLInfo, vendor); - uint32_t yOffset7 = offsetof(PalGLInfo, graphicsCard); - uint32_t yOffset8 = offsetof(PalGLInfo, version); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xOffset6 == yOffset6 && - xOffset7 == yOffset7 && - xOffset8 == yOffset8 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalGLInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "extensions @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "major @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "minor @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "backend @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "api @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "vendor @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "graphicsCard @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "version @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); -} - -static void configDump(PalBool verbose) -{ - uint32_t xSize = 28; - uint32_t xAlign = 4; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 4; - uint32_t xOffset3 = 8; - uint32_t xOffset4 = 12; - uint32_t xOffset5 = 14; - uint32_t xOffset6 = 16; - uint32_t xOffset7 = 18; - uint32_t xOffset8 = 20; - uint32_t xOffset9 = 22; - uint32_t xOffset10 = 24; - uint32_t xOffset11 = 26; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalGLFBConfig); - uint32_t yAlign = ALIGNOF(PalGLFBConfig); - uint32_t yOffset1 = offsetof(PalGLFBConfig, doubleBuffer); - uint32_t yOffset2 = offsetof(PalGLFBConfig, stereo); - uint32_t yOffset3 = offsetof(PalGLFBConfig, sRGB); - uint32_t yOffset4 = offsetof(PalGLFBConfig, index); - uint32_t yOffset5 = offsetof(PalGLFBConfig, redBits); - uint32_t yOffset6 = offsetof(PalGLFBConfig, greenBits); - uint32_t yOffset7 = offsetof(PalGLFBConfig, blueBits); - uint32_t yOffset8 = offsetof(PalGLFBConfig, alphaBits); - uint32_t yOffset9 = offsetof(PalGLFBConfig, depthBits); - uint32_t yOffset10 = offsetof(PalGLFBConfig, stencilBits); - uint32_t yOffset11 = offsetof(PalGLFBConfig, samples); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xOffset6 == yOffset6 && - xOffset7 == yOffset7 && - xOffset8 == yOffset8 && - xOffset9 == yOffset9 && - xOffset10 == yOffset10 && - xOffset11 == yOffset11 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalGLFBConfig"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "doubleBuffer @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "stereo @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "sRGB @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "index @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "redBits @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "greenBits @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "blueBits @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "alphaBits @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "depthBits @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "stencilBits @ %u %u", xOffset10, yOffset10); - palLog(nullptr, "samples @ %u %u", xOffset11, yOffset11); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Opengl ABI Dump"); + palLog(nullptr, "==========================================="); palLog(nullptr, ""); -} - -static void windowDump(PalBool verbose) -{ - uint32_t xSize = 16; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalGLWindow); - uint32_t yAlign = ALIGNOF(PalGLWindow); - uint32_t yOffset1 = offsetof(PalGLWindow, instance); - uint32_t yOffset2 = offsetof(PalGLWindow, window); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalGLWindow"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "instance @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "window @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "==========================================="); + FieldInfo glInfoFields[] = { + { "extensions", {0, 8}, FIELD(PalGLInfo, extensions) }, + { "major", {8, 4}, FIELD(PalGLInfo, major) }, + { "minor", {12, 4}, FIELD(PalGLInfo, minor) }, + { "backend", {16, 4}, FIELD(PalGLInfo, backend) }, + { "api", {20, 4}, FIELD(PalGLInfo, api) }, + { "vendor", {24, 32}, FIELD(PalGLInfo, vendor) }, + { "graphicsCard", {56, 64}, FIELD(PalGLInfo, graphicsCard) }, + { "version", {120, 64}, FIELD(PalGLInfo, version) } + }; + + FieldInfo fbConfigFields[] = { + { "doubleBuffer", {0, 4}, FIELD(PalGLFBConfig, doubleBuffer) }, + { "stereo", {4, 4}, FIELD(PalGLFBConfig, stereo) }, + { "sRGB", {8, 4}, FIELD(PalGLFBConfig, sRGB) }, + { "index", {12, 2}, FIELD(PalGLFBConfig, index) }, + { "redBits", {14, 2}, FIELD(PalGLFBConfig, redBits) }, + { "greenBits", {16, 2}, FIELD(PalGLFBConfig, greenBits) }, + { "blueBits", {18, 2}, FIELD(PalGLFBConfig, blueBits) }, + { "alphaBits", {20, 2}, FIELD(PalGLFBConfig, alphaBits) }, + { "depthBits", {22, 2}, FIELD(PalGLFBConfig, depthBits) }, + { "stencilBits", {24, 2}, FIELD(PalGLFBConfig, stencilBits) }, + { "samples", {26, 2}, FIELD(PalGLFBConfig, samples) } + }; + + FieldInfo windowFields[] = { + { "instance", {0, 8}, FIELD(PalGLWindow, instance) }, + { "window", {8, 8}, FIELD(PalGLWindow, window) } + }; + + FieldInfo contextCreateInfoFields[] = { + { "window", {0, 8}, FIELD(PalGLContextCreateInfo, window) }, + { "fbConfig", {8, 8}, FIELD(PalGLContextCreateInfo, fbConfig) }, + { "shareContext", {16, 8}, FIELD(PalGLContextCreateInfo, shareContext) }, + { "profile", {24, 4}, FIELD(PalGLContextCreateInfo, profile) }, + { "reset", {28, 4}, FIELD(PalGLContextCreateInfo, reset) }, + { "release", {32, 4}, FIELD(PalGLContextCreateInfo, release) }, + { "forward", {36, 4}, FIELD(PalGLContextCreateInfo, forward) }, + { "noError", {40, 4}, FIELD(PalGLContextCreateInfo, noError) }, + { "debug", {44, 4}, FIELD(PalGLContextCreateInfo, debug) }, + { "major", {48, 4}, FIELD(PalGLContextCreateInfo, major) }, + { "minor", {52, 4}, FIELD(PalGLContextCreateInfo, minor) } + }; + + StructInfo glInfo = {0}; + glInfo.name = "PalGLInfo"; + glInfo.fields = glInfoFields; + glInfo.fieldCount = ARRAY_SIZE(glInfoFields); + glInfo.expected.alignof = 8; + glInfo.expected.size = 184; + glInfo.expected.padding = 0; + glInfo.actual = STRUCT(PalGLInfo); + + StructInfo fbConfig = {0}; + fbConfig.name = "PalGLFBConfig"; + fbConfig.fields = fbConfigFields; + fbConfig.fieldCount = ARRAY_SIZE(fbConfigFields); + fbConfig.expected.alignof = 4; + fbConfig.expected.size = 28; + fbConfig.expected.padding = 0; + fbConfig.actual = STRUCT(PalGLFBConfig); + + StructInfo window = {0}; + window.name = "PalGLWindow"; + window.fields = windowFields; + window.fieldCount = ARRAY_SIZE(windowFields); + window.expected.alignof = 8; + window.expected.size = 16; + window.expected.padding = 0; + window.actual = STRUCT(PalGLWindow); + + StructInfo contextCreateInfo = {0}; + contextCreateInfo.name = "PalGLContextCreateInfo"; + contextCreateInfo.fields = contextCreateInfoFields; + contextCreateInfo.fieldCount = ARRAY_SIZE(contextCreateInfoFields); + contextCreateInfo.expected.alignof = 8; + contextCreateInfo.expected.size = 56; + contextCreateInfo.expected.padding = 0; + contextCreateInfo.actual = STRUCT(PalGLContextCreateInfo); + + PalBool status = checkABI(&glInfo, verbose); + if (status == PAL_FALSE) { + return status; } - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -static void contextDump(PalBool verbose) -{ - uint32_t xSize = 56; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 16; - uint32_t xOffset4 = 24; - uint32_t xOffset5 = 28; - uint32_t xOffset6 = 32; - uint32_t xOffset7 = 36; - uint32_t xOffset8 = 40; - uint32_t xOffset9 = 44; - uint32_t xOffset10 = 48; - uint32_t xOffset11 = 52; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalGLContextCreateInfo); - uint32_t yAlign = ALIGNOF(PalGLContextCreateInfo); - uint32_t yOffset1 = offsetof(PalGLContextCreateInfo, window); - uint32_t yOffset2 = offsetof(PalGLContextCreateInfo, fbConfig); - uint32_t yOffset3 = offsetof(PalGLContextCreateInfo, shareContext); - uint32_t yOffset4 = offsetof(PalGLContextCreateInfo, profile); - uint32_t yOffset5 = offsetof(PalGLContextCreateInfo, reset); - uint32_t yOffset6 = offsetof(PalGLContextCreateInfo, release); - uint32_t yOffset7 = offsetof(PalGLContextCreateInfo, forward); - uint32_t yOffset8 = offsetof(PalGLContextCreateInfo, noError); - uint32_t yOffset9 = offsetof(PalGLContextCreateInfo, debug); - uint32_t yOffset10 = offsetof(PalGLContextCreateInfo, major); - uint32_t yOffset11 = offsetof(PalGLContextCreateInfo, minor); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xOffset6 == yOffset6 && - xOffset7 == yOffset7 && - xOffset8 == yOffset8 && - xOffset9 == yOffset9 && - xOffset10 == yOffset10 && - xOffset11 == yOffset11 && - xPadding == yPadding) { - result = s_PassedString; + status = checkABI(&fbConfig, verbose); + if (status == PAL_FALSE) { + return status; } - // clang-format on - palLog(nullptr, "struct: PalGLContextCreateInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "window @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "fbConfig @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "shareContext @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "profile @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "reset @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "release @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "forward @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "noError @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "debug @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "major @ %u %u", xOffset10, yOffset10); - palLog(nullptr, "minor @ %u %u", xOffset11, yOffset11); - palLog(nullptr, "==========================================="); + status = checkABI(&window, verbose); + if (status == PAL_FALSE) { + return status; } - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -void openglABIDump(PalBool verbose) -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Opengl ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - infoDump(verbose); - configDump(verbose); - windowDump(verbose); - contextDump(verbose); + return checkABI(&contextCreateInfo, verbose); } \ No newline at end of file diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index 31d50c0c..6ca6c4f8 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -8,428 +8,168 @@ #include "dumps.h" #include "pal/pal_video.h" -static void monitorDump(PalBool verbose) +PalBool videoABIDump(PalBool verbose) { - uint32_t xSize = 64; - uint32_t xAlign = 4; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 4; - uint32_t xOffset3 = 8; - uint32_t xOffset4 = 12; - uint32_t xOffset5 = 16; - uint32_t xOffset6 = 20; - uint32_t xOffset7 = 24; - uint32_t xOffset8 = 28; - uint32_t xOffset9 = 32; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalMonitorInfo); - uint32_t yAlign = ALIGNOF(PalMonitorInfo); - uint32_t yOffset1 = offsetof(PalMonitorInfo, x); - uint32_t yOffset2 = offsetof(PalMonitorInfo, y); - uint32_t yOffset3 = offsetof(PalMonitorInfo, width); - uint32_t yOffset4 = offsetof(PalMonitorInfo, height); - uint32_t yOffset5 = offsetof(PalMonitorInfo, dpi); - uint32_t yOffset6 = offsetof(PalMonitorInfo, refreshRate); - uint32_t yOffset7 = offsetof(PalMonitorInfo, orientation); - uint32_t yOffset8 = offsetof(PalMonitorInfo, primary); - uint32_t yOffset9 = offsetof(PalMonitorInfo, name); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xOffset6 == yOffset6 && - xOffset7 == yOffset7 && - xOffset8 == yOffset8 && - xOffset9 == yOffset9 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalMonitorInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "x @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "y @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "width @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "height @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "dpi @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "refreshRate @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "orientation @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "primary @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "name @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -static void monitorModeDump(PalBool verbose) -{ - uint32_t xSize = 16; - uint32_t xAlign = 4; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 4; - uint32_t xOffset3 = 8; - uint32_t xOffset4 = 12; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalMonitorMode); - uint32_t yAlign = ALIGNOF(PalMonitorMode); - uint32_t yOffset1 = offsetof(PalMonitorMode, bpp); - uint32_t yOffset2 = offsetof(PalMonitorMode, refreshRate); - uint32_t yOffset3 = offsetof(PalMonitorMode, width); - uint32_t yOffset4 = offsetof(PalMonitorMode, height); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalMonitorMode"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "bpp @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "refreshRate @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "width @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "height @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -static void flashDump(PalBool verbose) -{ - uint32_t xSize = 12; - uint32_t xAlign = 4; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 4; - uint32_t xOffset3 = 8; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalFlashInfo); - uint32_t yAlign = ALIGNOF(PalFlashInfo); - uint32_t yOffset1 = offsetof(PalFlashInfo, flags); - uint32_t yOffset2 = offsetof(PalFlashInfo, interval); - uint32_t yOffset3 = offsetof(PalFlashInfo, count); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalFlashInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "flags @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "interval @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "count @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); palLog(nullptr, ""); -} - -static void iconDump(PalBool verbose) -{ - uint32_t xSize = 16; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 12; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalIconCreateInfo); - uint32_t yAlign = ALIGNOF(PalIconCreateInfo); - uint32_t yOffset1 = offsetof(PalIconCreateInfo, pixels); - uint32_t yOffset2 = offsetof(PalIconCreateInfo, width); - uint32_t yOffset3 = offsetof(PalIconCreateInfo, height); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalIconCreateInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "pixels @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "width @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "height @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Video ABI Dump"); + palLog(nullptr, "==========================================="); palLog(nullptr, ""); -} - -static void cursorDump(PalBool verbose) -{ - uint32_t xSize = 24; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 12; - uint32_t xOffset4 = 16; - uint32_t xOffset5 = 20; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalCursorCreateInfo); - uint32_t yAlign = ALIGNOF(PalCursorCreateInfo); - uint32_t yOffset1 = offsetof(PalCursorCreateInfo, pixels); - uint32_t yOffset2 = offsetof(PalCursorCreateInfo, width); - uint32_t yOffset3 = offsetof(PalCursorCreateInfo, height); - uint32_t yOffset4 = offsetof(PalCursorCreateInfo, xHotspot); - uint32_t yOffset5 = offsetof(PalCursorCreateInfo, yHotspot); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xPadding == yPadding) { - result = s_PassedString; + FieldInfo monitorInfoFields[] = { + { "x", {0, 4}, FIELD(PalMonitorInfo, x) }, + { "y", {4, 4}, FIELD(PalMonitorInfo, y) }, + { "width", {8, 4}, FIELD(PalMonitorInfo, width) }, + { "height", {12, 4}, FIELD(PalMonitorInfo, height) }, + { "dpi", {16, 4}, FIELD(PalMonitorInfo, dpi) }, + { "refreshRate", {20, 4}, FIELD(PalMonitorInfo, refreshRate) }, + { "orientation", {24, 4}, FIELD(PalMonitorInfo, orientation) }, + { "primary", {28, 4}, FIELD(PalMonitorInfo, primary) }, + { "name", {32, 32}, FIELD(PalMonitorInfo, name) } + }; + + FieldInfo monitorModeFields[] = { + { "bpp", {0, 4}, FIELD(PalMonitorMode, bpp) }, + { "refreshRate", {4, 4}, FIELD(PalMonitorMode, refreshRate) }, + { "width", {8, 4}, FIELD(PalMonitorMode, width) }, + { "height", {12, 4}, FIELD(PalMonitorMode, height) } + }; + + FieldInfo flashInfoFields[] = { + { "flags", {0, 4}, FIELD(PalFlashInfo, flags) }, + { "interval", {4, 4}, FIELD(PalFlashInfo, interval) }, + { "count", {8, 4}, FIELD(PalFlashInfo, count) } + }; + + FieldInfo iconCreateInfoFields[] = { + { "pixels", {0, 8}, FIELD(PalIconCreateInfo, pixels) }, + { "width", {8, 4}, FIELD(PalIconCreateInfo, width) }, + { "height", {12, 4}, FIELD(PalIconCreateInfo, height) } + }; + + FieldInfo cursorCreateInfoFields[] = { + { "pixels", {0, 8}, FIELD(PalCursorCreateInfo, pixels) }, + { "width", {8, 4}, FIELD(PalCursorCreateInfo, width) }, + { "height", {12, 4}, FIELD(PalCursorCreateInfo, height) }, + { "xHotspot", {16, 4}, FIELD(PalCursorCreateInfo, xHotspot) }, + { "yHotspot", {20, 4}, FIELD(PalCursorCreateInfo, yHotspot) } + }; + + FieldInfo windowHandleInfoFields[] = { + { "nativeInstance", {0, 8}, FIELD(PalWindowHandleInfo, nativeInstance) }, + { "nativeWindow", {8, 8}, FIELD(PalWindowHandleInfo, nativeWindow) }, + { "nativeHandle1", {16, 8}, FIELD(PalWindowHandleInfo, nativeHandle1) }, + { "nativeHandle2", {24, 8}, FIELD(PalWindowHandleInfo, nativeHandle2) }, + { "nativeHandle3", {32, 8}, FIELD(PalWindowHandleInfo, nativeHandle3) } + }; + + FieldInfo windowCreateInfoFields[] = { + { "title", {0, 8}, FIELD(PalWindowCreateInfo, title) }, + { "monitor", {8, 8}, FIELD(PalWindowCreateInfo, monitor) }, + { "appName", {16, 8}, FIELD(PalWindowCreateInfo, appName) }, + { "instanceName", {24, 8}, FIELD(PalWindowCreateInfo, instanceName) }, + { "fbConfigBackend", {32, 4}, FIELD(PalWindowCreateInfo, fbConfigBackend) }, + { "fbConfigIndex", {36, 4}, FIELD(PalWindowCreateInfo, fbConfigIndex) }, + { "width", {40, 4}, FIELD(PalWindowCreateInfo, width) }, + { "height", {44, 4}, FIELD(PalWindowCreateInfo, height) }, + { "show", {48, 4}, FIELD(PalWindowCreateInfo, show) }, + { "style", {52, 4}, FIELD(PalWindowCreateInfo, style) }, + { "state", {56, 4}, FIELD(PalWindowCreateInfo, state) }, + { "center", {60, 4}, FIELD(PalWindowCreateInfo, center) } + }; + + StructInfo monitorInfo = {0}; + monitorInfo.name = "PalMonitorInfo"; + monitorInfo.fields = monitorInfoFields; + monitorInfo.fieldCount = ARRAY_SIZE(monitorInfoFields); + monitorInfo.expected.alignof = 4; + monitorInfo.expected.size = 64; + monitorInfo.expected.padding = 0; + monitorInfo.actual = STRUCT(PalMonitorInfo); + + StructInfo monitorMode = {0}; + monitorMode.name = "PalMonitorMode"; + monitorMode.fields = monitorModeFields; + monitorMode.fieldCount = ARRAY_SIZE(monitorModeFields); + monitorMode.expected.alignof = 4; + monitorMode.expected.size = 16; + monitorMode.expected.padding = 0; + monitorMode.actual = STRUCT(PalMonitorMode); + + StructInfo flashInfo = {0}; + flashInfo.name = "PalFlashInfo"; + flashInfo.fields = flashInfoFields; + flashInfo.fieldCount = ARRAY_SIZE(flashInfoFields); + flashInfo.expected.alignof = 4; + flashInfo.expected.size = 12; + flashInfo.expected.padding = 0; + flashInfo.actual = STRUCT(PalFlashInfo); + + StructInfo iconCreateInfo = {0}; + iconCreateInfo.name = "PalIconCreateInfo"; + iconCreateInfo.fields = iconCreateInfoFields; + iconCreateInfo.fieldCount = ARRAY_SIZE(iconCreateInfoFields); + iconCreateInfo.expected.alignof = 8; + iconCreateInfo.expected.size = 16; + iconCreateInfo.expected.padding = 0; + iconCreateInfo.actual = STRUCT(PalIconCreateInfo); + + StructInfo cursorCreateInfo = {0}; + cursorCreateInfo.name = "PalCursorCreateInfo"; + cursorCreateInfo.fields = cursorCreateInfoFields; + cursorCreateInfo.fieldCount = ARRAY_SIZE(cursorCreateInfoFields); + cursorCreateInfo.expected.alignof = 8; + cursorCreateInfo.expected.size = 24; + cursorCreateInfo.expected.padding = 0; + cursorCreateInfo.actual = STRUCT(PalCursorCreateInfo); + + StructInfo windowHandleInfo = {0}; + windowHandleInfo.name = "PalWindowHandleInfo"; + windowHandleInfo.fields = windowHandleInfoFields; + windowHandleInfo.fieldCount = ARRAY_SIZE(windowHandleInfoFields); + windowHandleInfo.expected.alignof = 8; + windowHandleInfo.expected.size = 40; + windowHandleInfo.expected.padding = 0; + windowHandleInfo.actual = STRUCT(PalWindowHandleInfo); + + StructInfo windowCreateInfo = {0}; + windowCreateInfo.name = "PalWindowCreateInfo"; + windowCreateInfo.fields = windowCreateInfoFields; + windowCreateInfo.fieldCount = ARRAY_SIZE(windowCreateInfoFields); + windowCreateInfo.expected.alignof = 8; + windowCreateInfo.expected.size = 64; + windowCreateInfo.expected.padding = 0; + windowCreateInfo.actual = STRUCT(PalWindowCreateInfo); + + PalBool status = checkABI(&monitorInfo, verbose); + if (status == PAL_FALSE) { + return status; } - // clang-format on - palLog(nullptr, "struct: PalCursorCreateInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "pixels @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "width @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "height @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "xHotspot @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "yHotspot @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "==========================================="); + status = checkABI(&monitorMode, verbose); + if (status == PAL_FALSE) { + return status; } - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -static void windowInfoDump(PalBool verbose) -{ - uint32_t xSize = 40; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 16; - uint32_t xOffset4 = 24; - uint32_t xOffset5 = 32; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalWindowHandleInfo); - uint32_t yAlign = ALIGNOF(PalWindowHandleInfo); - uint32_t yOffset1 = offsetof(PalWindowHandleInfo, nativeInstance); - uint32_t yOffset2 = offsetof(PalWindowHandleInfo, nativeWindow); - uint32_t yOffset3 = offsetof(PalWindowHandleInfo, nativeHandle1); - uint32_t yOffset4 = offsetof(PalWindowHandleInfo, nativeHandle2); - uint32_t yOffset5 = offsetof(PalWindowHandleInfo, nativeHandle3); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xPadding == yPadding) { - result = s_PassedString; + status = checkABI(&flashInfo, verbose); + if (status == PAL_FALSE) { + return status; } - // clang-format on - palLog(nullptr, "struct: PalWindowHandleInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "nativeInstance @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "nativeWindow @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "nativeHandle1 @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "nativeHandle2 @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "nativeHandle3 @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "==========================================="); + status = checkABI(&iconCreateInfo, verbose); + if (status == PAL_FALSE) { + return status; } - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -static void windowDump(PalBool verbose) -{ - uint32_t xSize = 64; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 16; - uint32_t xOffset4 = 24; - uint32_t xOffset5 = 32; - uint32_t xOffset6 = 36; - uint32_t xOffset7 = 40; - uint32_t xOffset8 = 44; - uint32_t xOffset9 = 48; - uint32_t xOffset10 = 52; - uint32_t xOffset11 = 56; - uint32_t xOffset12 = 60; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalWindowCreateInfo); - uint32_t yAlign = ALIGNOF(PalWindowCreateInfo); - uint32_t yOffset1 = offsetof(PalWindowCreateInfo, title); - uint32_t yOffset2 = offsetof(PalWindowCreateInfo, monitor); - uint32_t yOffset3 = offsetof(PalWindowCreateInfo, appName); - uint32_t yOffset4 = offsetof(PalWindowCreateInfo, instanceName); - uint32_t yOffset5 = offsetof(PalWindowCreateInfo, fbConfigBackend); - uint32_t yOffset6 = offsetof(PalWindowCreateInfo, fbConfigIndex); - uint32_t yOffset7 = offsetof(PalWindowCreateInfo, width); - uint32_t yOffset8 = offsetof(PalWindowCreateInfo, height); - uint32_t yOffset9 = offsetof(PalWindowCreateInfo, show); - uint32_t yOffset10 = offsetof(PalWindowCreateInfo, style); - uint32_t yOffset11 = offsetof(PalWindowCreateInfo, state); - uint32_t yOffset12 = offsetof(PalWindowCreateInfo, center); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xOffset6 == yOffset6 && - xOffset7 == yOffset7 && - xOffset8 == yOffset8 && - xOffset9 == yOffset9 && - xOffset10 == yOffset10 && - xOffset11 == yOffset11 && - xOffset12 == yOffset12 && - xPadding == yPadding) { - result = s_PassedString; + status = checkABI(&cursorCreateInfo, verbose); + if (status == PAL_FALSE) { + return status; } - // clang-format on - palLog(nullptr, "struct: PalWindowCreateInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "title @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "monitor @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "appName @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "instanceName @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "fbConfigBackend @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "fbConfigIndex @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "width @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "height @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "show @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "style @ %u %u", xOffset10, yOffset10); - palLog(nullptr, "state @ %u %u", xOffset11, yOffset11); - palLog(nullptr, "center @ %u %u", xOffset12, yOffset12); - palLog(nullptr, "==========================================="); + status = checkABI(&windowHandleInfo, verbose); + if (status == PAL_FALSE) { + return status; } - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -void videoABIDump(PalBool verbose) -{ - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Video ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); - - monitorDump(verbose); - monitorModeDump(verbose); - flashDump(verbose); - iconDump(verbose); - cursorDump(verbose); - windowInfoDump(verbose); - windowDump(verbose); + return checkABI(&windowCreateInfo, verbose); } \ No newline at end of file From 9e1a5a87076c23f3aa435b52828525e6f5b165b7 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 17 Jul 2026 09:01:56 +0000 Subject: [PATCH 344/372] add graphics abi dump: adapter --- include/pal/pal_graphics.h | 6 +- tools/abi_dump/abi_dump.lua | 2 +- tools/abi_dump/abi_dump_main.c | 8 +- tools/abi_dump/dumps.h | 2 +- tools/abi_dump/graphics_abi_dump.c | 447 +++++++++-------------------- 5 files changed, 152 insertions(+), 313 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 2084484b..7fde4d14 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1562,9 +1562,9 @@ typedef struct { * @since 2.0 */ typedef struct { - uint32_t maxComputeQueues; /**< Max compute queues that can b created.*/ - uint32_t maxGraphicsQueues; /**< Max graphics queues that can b created.*/ - uint32_t maxCopyQueues; /**< Max copy queues that can b created.*/ + uint32_t maxComputeQueues; /**< Max compute queues that can be created.*/ + uint32_t maxGraphicsQueues; /**< Max graphics queues that can be created.*/ + uint32_t maxCopyQueues; /**< Max copy queues that can be created.*/ uint32_t maxColorAttachments; /**< Max number of simultaneous color attachments.*/ uint32_t maxUniformBufferSize; /**< Max uniform buffer size in bytes.*/ uint32_t maxStorageBufferSize; /**< Max storage buffer size in bytes.*/ diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index 9094b09b..a633bdfc 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -12,7 +12,7 @@ project "abi-dump" "system_abi_dump.c", "video_abi_dump.c", "opengl_abi_dump.c", - -- "graphics_abi_dump.c", + "graphics_abi_dump.c", "abi_dump_main.c" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 7e3781e9..e246cada 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -114,10 +114,10 @@ int main(int argc, char** argv) } if (dumpFlags & DUMP_FLAG_GRAPHICS) { - // status = graphicsABIDump(verbose); - // if (status == PAL_FALSE) { - // return -1; - // } + status = graphicsABIDump(verbose); + if (status == PAL_FALSE) { + return -1; + } } if (dumpFlags & DUMP_FLAG_VERSION) { diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index ad6177f6..8978387b 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -149,6 +149,6 @@ PalBool threadABIDump(PalBool verbose); PalBool systemABIDump(PalBool verbose); PalBool videoABIDump(PalBool verbose); PalBool openglABIDump(PalBool verbose); -// PalBool graphicsABIDump(PalBool verbose); +PalBool graphicsABIDump(PalBool verbose); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index c440b6d1..42494f98 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -8,322 +8,160 @@ #include "dumps.h" #include "pal/pal_graphics.h" -static void adapterInfoDump(PalBool verbose) +static PalBool adapterDump(PalBool verbose) { - uint32_t xSize = 200; - uint32_t xAlign = 8; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 8; - uint32_t xOffset3 = 16; - uint32_t xOffset4 = 20; - uint32_t xOffset5 = 24; - uint32_t xOffset6 = 28; - uint32_t xOffset7 = 32; - uint32_t xOffset8 = 36; - uint32_t xOffset9 = 40; - uint32_t xOffset10 = 168; - uint32_t xPadding = 0; + FieldInfo adapterInfoFields[] = { + { "vram", {0, 8}, FIELD(PalAdapterInfo, vram) }, + { "sharedMemory", {8, 8}, FIELD(PalAdapterInfo, sharedMemory) }, + { "vendorId", {16, 4}, FIELD(PalAdapterInfo, vendorId) }, + { "deviceId", {20, 4}, FIELD(PalAdapterInfo, deviceId) }, + { "driverVersion", {24, 4}, FIELD(PalAdapterInfo, driverVersion) }, + { "shaderFormats", {28, 4}, FIELD(PalAdapterInfo, shaderFormats) }, + { "type", {32, 4}, FIELD(PalAdapterInfo, type) }, + { "apiType", {36, 4}, FIELD(PalAdapterInfo, apiType) }, + { "name", {40, 128}, FIELD(PalAdapterInfo, name) }, + { "backendName", {168, 32}, FIELD(PalAdapterInfo, backendName) } + }; + + FieldInfo imageCapFields[] = { + { "maxWidth", {0, 4}, FIELD(PalImageCapabilities, maxWidth) }, + { "maxHeight", {4, 4}, FIELD(PalImageCapabilities, maxHeight) }, + { "maxDepth", {8, 4}, FIELD(PalImageCapabilities, maxDepth) }, + { "maxArrayLayers", {12, 4}, FIELD(PalImageCapabilities, maxArrayLayers) }, + { "maxMipLevels", {16, 4}, FIELD(PalImageCapabilities, maxMipLevels) } + }; - uint32_t ySize = sizeof(PalAdapterInfo); - uint32_t yAlign = ALIGNOF(PalAdapterInfo); - uint32_t yOffset1 = offsetof(PalAdapterInfo, vram); - uint32_t yOffset2 = offsetof(PalAdapterInfo, sharedMemory); - uint32_t yOffset3 = offsetof(PalAdapterInfo, vendorId); - uint32_t yOffset4 = offsetof(PalAdapterInfo, deviceId); - uint32_t yOffset5 = offsetof(PalAdapterInfo, driverVersion); - uint32_t yOffset6 = offsetof(PalAdapterInfo, shaderFormats); - uint32_t yOffset7 = offsetof(PalAdapterInfo, type); - uint32_t yOffset8 = offsetof(PalAdapterInfo, apiType); - uint32_t yOffset9 = offsetof(PalAdapterInfo, name); - uint32_t yOffset10 = offsetof(PalAdapterInfo, backendName); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xOffset6 == yOffset6 && - xOffset7 == yOffset7 && - xOffset8 == yOffset8 && - xOffset9 == yOffset9 && - xOffset10 == yOffset10 && - xPadding == yPadding) { - result = s_PassedString; - } + FieldInfo resourceCapFields[] = { + { "maxPerStageSampledImages", {0, 4}, FIELD(PalResourceCapabilities, maxPerStageSampledImages) }, + { "maxPerSetSampledImages", {4, 4}, FIELD(PalResourceCapabilities, maxPerSetSampledImages) }, + { "maxPerStageStorageImages", {8, 4}, FIELD(PalResourceCapabilities, maxPerStageStorageImages) }, + { "maxPerSetStorageImages", {12, 4}, FIELD(PalResourceCapabilities, maxPerSetStorageImages) }, + { "maxPerStageSamplers", {16, 4}, FIELD(PalResourceCapabilities, maxPerStageSamplers) }, + { "maxPerSetSamplers", {20, 4}, FIELD(PalResourceCapabilities, maxPerSetSamplers) }, + { "maxPerStageStorageBuffers", {24, 4}, FIELD(PalResourceCapabilities, maxPerStageStorageBuffers) }, + { "maxPerSetStorageBuffers", {28, 4}, FIELD(PalResourceCapabilities, maxPerSetStorageBuffers) }, + { "maxPerStageUniformBuffers", {32, 4}, FIELD(PalResourceCapabilities, maxPerStageUniformBuffers) }, + { "maxPerSetUniformBuffers", {36, 4}, FIELD(PalResourceCapabilities, maxPerSetUniformBuffers) }, + { "maxPerStageAccelerationStructure", {40, 4}, FIELD(PalResourceCapabilities, maxPerStageAccelerationStructure) }, + { "maxPerSetAccelerationStructure", {44, 4}, FIELD(PalResourceCapabilities, maxPerSetAccelerationStructure) }, + { "maxBoundSets", {48, 4}, FIELD(PalResourceCapabilities, maxBoundSets) }, + }; + + FieldInfo computeCapFields[] = { + { "maxWorkGroupInvocations", {0, 4}, FIELD(PalComputeCapabilities, maxWorkGroupInvocations) }, + { "maxWorkGroupCount", {4, 12}, FIELD(PalComputeCapabilities, maxWorkGroupCount) }, + { "maxWorkGroupSize", {16, 12}, FIELD(PalComputeCapabilities, maxWorkGroupSize) } + }; // clang-format on - palLog(nullptr, "struct: PalAdapterInfo"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "vram @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "sharedMemory @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "vendorId @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "deviceId @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "driverVersion @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "shaderFormats @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "type @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "apiType @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "name @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "backendName @ %u %u", xOffset10, yOffset10); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -static void imageCapDump(PalBool verbose) -{ - uint32_t xSize = 20; - uint32_t xAlign = 4; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 4; - uint32_t xOffset3 = 8; - uint32_t xOffset4 = 12; - uint32_t xOffset5 = 16; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalImageCapabilities); - uint32_t yAlign = ALIGNOF(PalImageCapabilities); - uint32_t yOffset1 = offsetof(PalImageCapabilities, maxWidth); - uint32_t yOffset2 = offsetof(PalImageCapabilities, maxHeight); - uint32_t yOffset3 = offsetof(PalImageCapabilities, maxDepth); - uint32_t yOffset4 = offsetof(PalImageCapabilities, maxArrayLayers); - uint32_t yOffset5 = offsetof(PalImageCapabilities, maxMipLevels); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xPadding == yPadding) { - result = s_PassedString; - } - // clang-format on - - palLog(nullptr, "struct: PalImageCapabilities"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "maxWidth @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "maxHeight @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "maxDepth @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "maxArrayLayers @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "maxMipLevels @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "==========================================="); - } - - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -static void resourceCapDump(PalBool verbose) -{ - uint32_t xSize = 52; - uint32_t xAlign = 4; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 4; - uint32_t xOffset3 = 8; - uint32_t xOffset4 = 12; - uint32_t xOffset5 = 16; - uint32_t xOffset6 = 20; - uint32_t xOffset7 = 24; - uint32_t xOffset8 = 28; - uint32_t xOffset9 = 32; - uint32_t xOffset10 = 36; - uint32_t xOffset11 = 40; - uint32_t xOffset12 = 44; - uint32_t xOffset13 = 48; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalResourceCapabilities); - uint32_t yAlign = ALIGNOF(PalResourceCapabilities); - uint32_t yOffset1 = offsetof(PalResourceCapabilities, maxPerStageSampledImages); - uint32_t yOffset2 = offsetof(PalResourceCapabilities, maxPerSetSampledImages); - uint32_t yOffset3 = offsetof(PalResourceCapabilities, maxPerStageStorageImages); - uint32_t yOffset4 = offsetof(PalResourceCapabilities, maxPerSetStorageImages); - uint32_t yOffset5 = offsetof(PalResourceCapabilities, maxPerStageSamplers); - uint32_t yOffset6 = offsetof(PalResourceCapabilities, maxPerSetSamplers); - uint32_t yOffset7 = offsetof(PalResourceCapabilities, maxPerStageStorageBuffers); - uint32_t yOffset8 = offsetof(PalResourceCapabilities, maxPerSetStorageBuffers); - uint32_t yOffset9 = offsetof(PalResourceCapabilities, maxPerStageUniformBuffers); - uint32_t yOffset10 = offsetof(PalResourceCapabilities, maxPerSetUniformBuffers); - uint32_t yOffset11 = offsetof(PalResourceCapabilities, maxPerStageAccelerationStructure); - uint32_t yOffset12 = offsetof(PalResourceCapabilities, maxPerSetAccelerationStructure); - uint32_t yOffset13 = offsetof(PalResourceCapabilities, maxBoundSets); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xOffset5 == yOffset5 && - xOffset6 == yOffset6 && - xOffset7 == yOffset7 && - xOffset8 == yOffset8 && - xOffset9 == yOffset9 && - xOffset10 == yOffset10 && - xOffset11 == yOffset11 && - xOffset12 == yOffset12 && - xOffset13 == yOffset13 && - xPadding == yPadding) { - result = s_PassedString; - } - - palLog(nullptr, "struct: PalResourceCapabilities"); - if (verbose) { - palLog(nullptr, "========================================================"); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "========================================================"); - - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "maxPerStageSampledImages @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "maxPerSetSampledImages @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "maxPerStageStorageImages @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "maxPerSetStorageImages @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "maxPerStageSamplers @ %u %u", xOffset5, yOffset5); - palLog(nullptr, "maxPerSetSamplers @ %u %u", xOffset6, yOffset6); - palLog(nullptr, "maxPerStageStorageBuffers @ %u %u", xOffset7, yOffset7); - palLog(nullptr, "maxPerSetStorageBuffers @ %u %u", xOffset8, yOffset8); - palLog(nullptr, "maxPerStageUniformBuffers @ %u %u", xOffset9, yOffset9); - palLog(nullptr, "maxPerSetUniformBuffers @ %u %u", xOffset10, yOffset10); - palLog(nullptr, "maxPerStageAccelerationStructure @ %u %u", xOffset11, yOffset11); - palLog(nullptr, "maxPerSetAccelerationStructure @ %u %u", xOffset12, yOffset12); - palLog(nullptr, "maxBoundSets @ %u %u", xOffset13, yOffset13); - palLog(nullptr, "==========================================="); + FieldInfo viewportCapFields[] = { + { "maxWidth", {0, 4}, FIELD(PalViewportCapabilities, maxWidth) }, + { "maxHeight", {4, 4}, FIELD(PalViewportCapabilities, maxHeight) }, + { "minBoundsRange", {8, 4}, FIELD(PalViewportCapabilities, minBoundsRange) }, + { "maxBoundsRange", {12, 4}, FIELD(PalViewportCapabilities, maxBoundsRange) } + }; + + FieldInfo adapterCapFields[] = { + { "maxComputeQueues", {0, 4}, FIELD(PalAdapterCapabilities, maxComputeQueues) }, + { "maxGraphicsQueues", {4, 4}, FIELD(PalAdapterCapabilities, maxGraphicsQueues) }, + { "maxCopyQueues", {8, 4}, FIELD(PalAdapterCapabilities, maxCopyQueues) }, + { "maxColorAttachments", {12, 4}, FIELD(PalAdapterCapabilities, maxColorAttachments) }, + { "maxUniformBufferSize", {16, 4}, FIELD(PalAdapterCapabilities, maxUniformBufferSize) }, + { "maxStorageBufferSize", {20, 4}, FIELD(PalAdapterCapabilities, maxStorageBufferSize) }, + { "maxPushConstantSize", {24, 4}, FIELD(PalAdapterCapabilities, maxPushConstantSize) }, + { "maxVertexLayouts", {28, 4}, FIELD(PalAdapterCapabilities, maxVertexLayouts) }, + { "maxVertexAttributes", {32, 4}, FIELD(PalAdapterCapabilities, maxVertexAttributes) }, + { "maxTessellationPatchPoint", {36, 4}, FIELD(PalAdapterCapabilities, maxTessellationPatchPoint) }, + { "viewportCaps", {40, 16}, FIELD(PalAdapterCapabilities, viewportCaps) }, + { "imageCaps", {56, 20}, FIELD(PalAdapterCapabilities, imageCaps) }, + { "resourceCaps", {76, 52}, FIELD(PalAdapterCapabilities, resourceCaps) }, + { "computeCaps", {128, 28}, FIELD(PalAdapterCapabilities, computeCaps) } + }; + + StructInfo adapterInfo = {0}; + adapterInfo.name = "PalAdapterInfo"; + adapterInfo.fields = adapterInfoFields; + adapterInfo.fieldCount = ARRAY_SIZE(adapterInfoFields); + adapterInfo.expected.alignof = 8; + adapterInfo.expected.size = 200; + adapterInfo.expected.padding = 0; + adapterInfo.actual = STRUCT(PalAdapterInfo); + + StructInfo imageCap = {0}; + imageCap.name = "PalImageCapabilities"; + imageCap.fields = imageCapFields; + imageCap.fieldCount = ARRAY_SIZE(imageCapFields); + imageCap.expected.alignof = 4; + imageCap.expected.size = 20; + imageCap.expected.padding = 0; + imageCap.actual = STRUCT(PalImageCapabilities); + + StructInfo resourceCap = {0}; + resourceCap.name = "PalResourceCapabilities"; + resourceCap.fields = resourceCapFields; + resourceCap.fieldCount = ARRAY_SIZE(resourceCapFields); + resourceCap.expected.alignof = 4; + resourceCap.expected.size = 52; + resourceCap.expected.padding = 0; + resourceCap.actual = STRUCT(PalResourceCapabilities); + + StructInfo computeCap = {0}; + computeCap.name = "PalComputeCapabilities"; + computeCap.fields = computeCapFields; + computeCap.fieldCount = ARRAY_SIZE(computeCapFields); + computeCap.expected.alignof = 4; + computeCap.expected.size = 28; + computeCap.expected.padding = 0; + computeCap.actual = STRUCT(PalComputeCapabilities); + + StructInfo viewportCap = {0}; + viewportCap.name = "PalViewportCapabilities"; + viewportCap.fields = viewportCapFields; + viewportCap.fieldCount = ARRAY_SIZE(viewportCapFields); + viewportCap.expected.alignof = 4; + viewportCap.expected.size = 16; + viewportCap.expected.padding = 0; + viewportCap.actual = STRUCT(PalViewportCapabilities); + + StructInfo adapterCap = {0}; + adapterCap.name = "PalAdapterCapabilities"; + adapterCap.fields = adapterCapFields; + adapterCap.fieldCount = ARRAY_SIZE(adapterCapFields); + adapterCap.expected.alignof = 4; + adapterCap.expected.size = 156; + adapterCap.expected.padding = 0; + adapterCap.actual = STRUCT(PalAdapterCapabilities); + + PalBool status = checkABI(&adapterInfo, verbose); + if (status == PAL_FALSE) { + return status; } - // clang-format on - - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} -static void computeCapDump(PalBool verbose) -{ - uint32_t xSize = 28; - uint32_t xAlign = 4; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 4; - uint32_t xOffset3 = 16; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalComputeCapabilities); - uint32_t yAlign = ALIGNOF(PalComputeCapabilities); - uint32_t yOffset1 = offsetof(PalComputeCapabilities, maxWorkGroupInvocations); - uint32_t yOffset2 = offsetof(PalComputeCapabilities, maxWorkGroupCount); - uint32_t yOffset3 = offsetof(PalComputeCapabilities, maxWorkGroupSize); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xPadding == yPadding) { - result = s_PassedString; + status = checkABI(&imageCap, verbose); + if (status == PAL_FALSE) { + return status; } - // clang-format on - - palLog(nullptr, "struct: PalComputeCapabilities"); - if (verbose) { - palLog(nullptr, "============================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "=============================================="); - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "maxWorkGroupInvocations @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "maxWorkGroupCount[3] @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "maxWorkGroupSize[3] @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "==========================================="); + status = checkABI(&resourceCap, verbose); + if (status == PAL_FALSE) { + return status; } - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); -} - -static void viewportCapDump(PalBool verbose) -{ - uint32_t xSize = 16; - uint32_t xAlign = 4; - uint32_t xOffset1 = 0; - uint32_t xOffset2 = 4; - uint32_t xOffset3 = 8; - uint32_t xOffset4 = 12; - uint32_t xPadding = 0; - - uint32_t ySize = sizeof(PalViewportCapabilities); - uint32_t yAlign = ALIGNOF(PalViewportCapabilities); - uint32_t yOffset1 = offsetof(PalViewportCapabilities, maxWidth); - uint32_t yOffset2 = offsetof(PalViewportCapabilities, maxHeight); - uint32_t yOffset3 = offsetof(PalViewportCapabilities, minBoundsRange); - uint32_t yOffset4 = offsetof(PalViewportCapabilities, maxBoundsRange); - uint32_t yPadding = (yAlign - (ySize % yAlign)) % yAlign; - - const char* result = s_FailedString; - // clang-format off - if (xSize == ySize && - xAlign == yAlign && - xOffset1 == yOffset1 && - xOffset2 == yOffset2 && - xOffset3 == yOffset3 && - xOffset4 == yOffset4 && - xPadding == yPadding) { - result = s_PassedString; + status = checkABI(&computeCap, verbose); + if (status == PAL_FALSE) { + return status; } - // clang-format on - - palLog(nullptr, "struct: PalViewportCapabilities"); - if (verbose) { - palLog(nullptr, "==========================================="); - palLog(nullptr, "Field Expected Actual"); - palLog(nullptr, "==========================================="); - palLog(nullptr, "size %u %u", xSize, ySize); - palLog(nullptr, "align %u %u", xAlign, yAlign); - palLog(nullptr, "padding %u %u", xPadding, yPadding); - palLog(nullptr, "maxWidth @ %u %u", xOffset1, yOffset1); - palLog(nullptr, "maxHeight @ %u %u", xOffset2, yOffset2); - palLog(nullptr, "minBoundsRange @ %u %u", xOffset3, yOffset3); - palLog(nullptr, "maxBoundsRange @ %u %u", xOffset4, yOffset4); - palLog(nullptr, "==========================================="); + status = checkABI(&viewportCap, verbose); + if (status == PAL_FALSE) { + return status; } - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); + return checkABI(&adapterCap, verbose); } -void graphicsABIDump(PalBool verbose) +PalBool graphicsABIDump(PalBool verbose) { palLog(nullptr, ""); palLog(nullptr, "==========================================="); @@ -331,9 +169,10 @@ void graphicsABIDump(PalBool verbose) palLog(nullptr, "==========================================="); palLog(nullptr, ""); - adapterInfoDump(verbose); - imageCapDump(verbose); - resourceCapDump(verbose); - computeCapDump(verbose); - viewportCapDump(verbose); + PalBool status = adapterDump(verbose); + if (status == PAL_FALSE) { + return status; + } + + return PAL_TRUE; } \ No newline at end of file From 0d3192f195e50ea0af2f4ffe26007aec28225a1f Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 17 Jul 2026 10:16:10 +0000 Subject: [PATCH 345/372] add graphics abi dump: device --- tools/abi_dump/graphics_abi_dump.c | 210 ++++++++++++++++++++++++++++- 1 file changed, 206 insertions(+), 4 deletions(-) diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index 42494f98..2e47a7c7 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -10,6 +10,7 @@ static PalBool adapterDump(PalBool verbose) { + // clang-format off FieldInfo adapterInfoFields[] = { { "vram", {0, 8}, FIELD(PalAdapterInfo, vram) }, { "sharedMemory", {8, 8}, FIELD(PalAdapterInfo, sharedMemory) }, @@ -31,7 +32,6 @@ static PalBool adapterDump(PalBool verbose) { "maxMipLevels", {16, 4}, FIELD(PalImageCapabilities, maxMipLevels) } }; - // clang-format off FieldInfo resourceCapFields[] = { { "maxPerStageSampledImages", {0, 4}, FIELD(PalResourceCapabilities, maxPerStageSampledImages) }, { "maxPerSetSampledImages", {4, 4}, FIELD(PalResourceCapabilities, maxPerSetSampledImages) }, @@ -53,8 +53,7 @@ static PalBool adapterDump(PalBool verbose) { "maxWorkGroupCount", {4, 12}, FIELD(PalComputeCapabilities, maxWorkGroupCount) }, { "maxWorkGroupSize", {16, 12}, FIELD(PalComputeCapabilities, maxWorkGroupSize) } }; - // clang-format on - + FieldInfo viewportCapFields[] = { { "maxWidth", {0, 4}, FIELD(PalViewportCapabilities, maxWidth) }, { "maxHeight", {4, 4}, FIELD(PalViewportCapabilities, maxHeight) }, @@ -79,6 +78,13 @@ static PalBool adapterDump(PalBool verbose) { "computeCaps", {128, 28}, FIELD(PalAdapterCapabilities, computeCaps) } }; + FieldInfo formatInfoFields[] = { + { "usages", {0, 4}, FIELD(PalFormatInfo, usages) }, + { "format", {4, 4}, FIELD(PalFormatInfo, format) }, + { "sampleCount", {8, 4}, FIELD(PalFormatInfo, sampleCount) } + }; + // clang-format on + StructInfo adapterInfo = {0}; adapterInfo.name = "PalAdapterInfo"; adapterInfo.fields = adapterInfoFields; @@ -133,6 +139,15 @@ static PalBool adapterDump(PalBool verbose) adapterCap.expected.padding = 0; adapterCap.actual = STRUCT(PalAdapterCapabilities); + StructInfo formatInfo = {0}; + formatInfo.name = "PalFormatInfo"; + formatInfo.fields = formatInfoFields; + formatInfo.fieldCount = ARRAY_SIZE(formatInfoFields); + formatInfo.expected.alignof = 4; + formatInfo.expected.size = 12; + formatInfo.expected.padding = 0; + formatInfo.actual = STRUCT(PalFormatInfo); + PalBool status = checkABI(&adapterInfo, verbose); if (status == PAL_FALSE) { return status; @@ -158,7 +173,189 @@ static PalBool adapterDump(PalBool verbose) return status; } - return checkABI(&adapterCap, verbose); + status = checkABI(&adapterCap, verbose); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&formatInfo, verbose); +} + +static PalBool deviceDump(PalBool verbose) +{ + // clang-format off + FieldInfo samplerAnisotropyCapFields[] = { + { "maxAnisotropy", {0, 4}, FIELD(PalSamplerAnisotropyCapabilities, maxAnisotropy) } + }; + + FieldInfo multiViewCapFields[] = { + { "maxViewCount", {0, 4}, FIELD(PalMultiViewCapabilities, maxViewCount) } + }; + + FieldInfo multiViewportCapFields[] = { + { "maxCount", {0, 4}, FIELD(PalMultiViewportCapabilities, maxCount) } + }; + + FieldInfo depthStencilCapFields[] = { + { "supportedDepthResolveModes", {0, 4}, FIELD(PalDepthStencilCapabilities, supportedDepthResolveModes) }, + { "supportedStencilResolveModes", {4, 4}, FIELD(PalDepthStencilCapabilities, supportedStencilResolveModes) }, + { "supportsIndependentResolve", {8, 4}, FIELD(PalDepthStencilCapabilities, supportsIndependentResolve) }, + { "supportsIndependentResolveNone", {12, 4}, FIELD(PalDepthStencilCapabilities, supportsIndependentResolveNone) } + }; + + FieldInfo fragmentShadingRateCapFields[] = { + { "supportedShadingRates", {0, 4}, FIELD(PalFragmentShadingRateCapabilities, supportedShadingRates) }, + { "supportedCombinerOps", {4, 4}, FIELD(PalFragmentShadingRateCapabilities, supportedCombinerOps) }, + { "minTexelWidth", {8, 4}, FIELD(PalFragmentShadingRateCapabilities, minTexelWidth) }, + { "minTexelHeight", {12, 4}, FIELD(PalFragmentShadingRateCapabilities, minTexelHeight) }, + { "maxTexelWidth", {16, 4}, FIELD(PalFragmentShadingRateCapabilities, maxTexelWidth) }, + { "maxTexelHeight", {20, 4}, FIELD(PalFragmentShadingRateCapabilities, maxTexelHeight) } + }; + + FieldInfo meshCapFields[] = { + { "maxOutputPrimitives", {0, 4}, FIELD(PalMeshShaderCapabilities, maxOutputPrimitives) }, + { "maxOutputVertices", {4, 4}, FIELD(PalMeshShaderCapabilities, maxOutputVertices) }, + { "maxWorkGroupInvocations", {8, 4}, FIELD(PalMeshShaderCapabilities, maxWorkGroupInvocations) }, + { "maxTaskWorkGroupInvocations", {12, 4}, FIELD(PalMeshShaderCapabilities, maxTaskWorkGroupInvocations) }, + { "maxWorkGroupCount", {16, 12}, FIELD(PalMeshShaderCapabilities, maxWorkGroupCount) }, + { "maxTaskWorkGroupCount", {28, 12}, FIELD(PalMeshShaderCapabilities, maxTaskWorkGroupCount) } + }; + + FieldInfo rayTracingCapFields[] = { + { "maxRecursionDepth", {0, 4}, FIELD(PalRayTracingCapabilities, maxRecursionDepth) }, + { "maxHitAttributeSize", {4, 4}, FIELD(PalRayTracingCapabilities, maxHitAttributeSize) }, + { "maxInstanceCount", {8, 4}, FIELD(PalRayTracingCapabilities, maxInstanceCount) }, + { "maxPrimitiveCount", {12, 4}, FIELD(PalRayTracingCapabilities, maxPrimitiveCount) }, + { "maxGeometryCount", {16, 4}, FIELD(PalRayTracingCapabilities, maxGeometryCount) }, + { "maxPayloadSize", {20, 4}, FIELD(PalRayTracingCapabilities, maxPayloadSize) }, + { "maxDispatchInvocations", {24, 4}, FIELD(PalRayTracingCapabilities, maxDispatchInvocations) } + }; + + FieldInfo descriptorIndexingCapFields[] = { + { "flags", {0, 4}, FIELD(PalDescriptorIndexingCapabilities, flags) }, + { "maxPerStageSampledImages", {4, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerStageSampledImages) }, + { "maxPerSetSampledImages", {8, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerSetSampledImages) }, + { "maxPerStageStorageImages", {12, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerStageStorageImages) }, + { "maxPerSetStorageImages", {16, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerSetStorageImages) }, + { "maxPerStageSamplers", {20, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerStageSamplers) }, + { "maxPerSetSamplers", {24, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerSetSamplers) }, + { "maxPerStageStorageBuffers", {28, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerStageStorageBuffers) }, + { "maxPerSetStorageBuffers", {32, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerSetStorageBuffers) }, + { "maxPerStageUniformBuffers", {36, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerStageUniformBuffers) }, + { "maxPerSetUniformBuffers", {40, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerSetUniformBuffers) }, + { "maxPerStageAccelerationStructure", {44, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerStageAccelerationStructure) }, + { "maxPerSetAccelerationStructure", {48, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerSetAccelerationStructure) } + }; + // clang-format on + + StructInfo samplerAnisotropyCap = {0}; + samplerAnisotropyCap.name = "PalSamplerAnisotropyCapabilities"; + samplerAnisotropyCap.fields = samplerAnisotropyCapFields; + samplerAnisotropyCap.fieldCount = ARRAY_SIZE(samplerAnisotropyCapFields); + samplerAnisotropyCap.expected.alignof = 4; + samplerAnisotropyCap.expected.size = 4; + samplerAnisotropyCap.expected.padding = 0; + samplerAnisotropyCap.actual = STRUCT(PalSamplerAnisotropyCapabilities); + + StructInfo multiViewCap = {0}; + multiViewCap.name = "PalMultiViewCapabilities"; + multiViewCap.fields = multiViewCapFields; + multiViewCap.fieldCount = ARRAY_SIZE(multiViewCapFields); + multiViewCap.expected.alignof = 4; + multiViewCap.expected.size = 4; + multiViewCap.expected.padding = 0; + multiViewCap.actual = STRUCT(PalMultiViewCapabilities); + + StructInfo multiViewportCap = {0}; + multiViewportCap.name = "PalMultiViewportCapabilities"; + multiViewportCap.fields = multiViewportCapFields; + multiViewportCap.fieldCount = ARRAY_SIZE(multiViewportCapFields); + multiViewportCap.expected.alignof = 4; + multiViewportCap.expected.size = 4; + multiViewportCap.expected.padding = 0; + multiViewportCap.actual = STRUCT(PalMultiViewportCapabilities); + + StructInfo depthStencilCap = {0}; + depthStencilCap.name = "PalDepthStencilCapabilities"; + depthStencilCap.fields = depthStencilCapFields; + depthStencilCap.fieldCount = ARRAY_SIZE(depthStencilCapFields); + depthStencilCap.expected.alignof = 4; + depthStencilCap.expected.size = 16; + depthStencilCap.expected.padding = 0; + depthStencilCap.actual = STRUCT(PalDepthStencilCapabilities); + + StructInfo fragmentShadingRateCap = {0}; + fragmentShadingRateCap.name = "PalFragmentShadingRateCapabilities"; + fragmentShadingRateCap.fields = fragmentShadingRateCapFields; + fragmentShadingRateCap.fieldCount = ARRAY_SIZE(fragmentShadingRateCapFields); + fragmentShadingRateCap.expected.alignof = 4; + fragmentShadingRateCap.expected.size = 24; + fragmentShadingRateCap.expected.padding = 0; + fragmentShadingRateCap.actual = STRUCT(PalFragmentShadingRateCapabilities); + + StructInfo meshCap = {0}; + meshCap.name = "PalMeshShaderCapabilities"; + meshCap.fields = meshCapFields; + meshCap.fieldCount = ARRAY_SIZE(meshCapFields); + meshCap.expected.alignof = 4; + meshCap.expected.size = 40; + meshCap.expected.padding = 0; + meshCap.actual = STRUCT(PalMeshShaderCapabilities); + + StructInfo rayTracingCap = {0}; + rayTracingCap.name = "PalRayTracingCapabilities"; + rayTracingCap.fields = rayTracingCapFields; + rayTracingCap.fieldCount = ARRAY_SIZE(rayTracingCapFields); + rayTracingCap.expected.alignof = 4; + rayTracingCap.expected.size = 28; + rayTracingCap.expected.padding = 0; + rayTracingCap.actual = STRUCT(PalRayTracingCapabilities); + + StructInfo descriptorIndexingCap = {0}; + descriptorIndexingCap.name = "PalDescriptorIndexingCapabilities"; + descriptorIndexingCap.fields = descriptorIndexingCapFields; + descriptorIndexingCap.fieldCount = ARRAY_SIZE(descriptorIndexingCapFields); + descriptorIndexingCap.expected.alignof = 4; + descriptorIndexingCap.expected.size = 52; + descriptorIndexingCap.expected.padding = 0; + descriptorIndexingCap.actual = STRUCT(PalDescriptorIndexingCapabilities); + + PalBool status = checkABI(&samplerAnisotropyCap, verbose); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&multiViewCap, verbose); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&multiViewportCap, verbose); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&depthStencilCap, verbose); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&fragmentShadingRateCap, verbose); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&meshCap, verbose); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&rayTracingCap, verbose); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&descriptorIndexingCap, verbose); } PalBool graphicsABIDump(PalBool verbose) @@ -174,5 +371,10 @@ PalBool graphicsABIDump(PalBool verbose) return status; } + status = deviceDump(verbose); + if (status == PAL_FALSE) { + return status; + } + return PAL_TRUE; } \ No newline at end of file From 3a4785cfa9e09f77d4d42d96b150de8dfdea71e4 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 17 Jul 2026 11:03:22 +0000 Subject: [PATCH 346/372] abi dump: all quick flag --- tools/abi_dump/abi_dump_main.c | 170 +++++++++++++++++++---------- tools/abi_dump/core_abi_dump.c | 20 ++-- tools/abi_dump/dumps.h | 57 ++++++---- tools/abi_dump/event_abi_dump.c | 20 ++-- tools/abi_dump/graphics_abi_dump.c | 52 ++++----- tools/abi_dump/opengl_abi_dump.c | 22 ++-- tools/abi_dump/system_abi_dump.c | 18 +-- tools/abi_dump/thread_abi_dump.c | 16 +-- tools/abi_dump/video_abi_dump.c | 28 ++--- 9 files changed, 248 insertions(+), 155 deletions(-) diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index e246cada..95b58f92 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -15,121 +15,172 @@ #define EXE_NAME "abi-dump" #endif // _WIN32 -#define DUMP_FLAG_CORE (1u << 0) -#define DUMP_FLAG_EVENT (1u << 1) -#define DUMP_FLAG_THREAD (1u << 2) -#define DUMP_FLAG_OPENGL (1u << 3) -#define DUMP_FLAG_GRAPHICS (1u << 4) -#define DUMP_FLAG_SYSTEM (1u << 5) -#define DUMP_FLAG_VIDEO (1u << 6) -#define DUMP_FLAG_VERSION (1u << 7) -#define DUMP_FLAG_HELP (1u << 8) -#define DUMP_FLAG_ALL 0x7F +static int logDumpStatus(PalBool status) +{ + int ret = -1; + const char* str = s_FailedString; + if (status) { + str = s_PassedString; + ret = 0; + } + + palLog(nullptr, "PAL ABI Dump Status: %s", str); + return ret; +} // clang-format off int main(int argc, char** argv) { // clang-format on - PalBool verbose = PAL_FALSE; PalBool status = PAL_FALSE; - uint32_t dumpFlags = 0; + uint32_t flags = 0; + uint32_t passed = 0; + uint32_t dumps = 0; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--core") == 0) { - dumpFlags |= DUMP_FLAG_CORE; + dumps |= DUMP_FLAG_CORE; } else if (strcmp(argv[i], "--event") == 0) { - dumpFlags |= DUMP_FLAG_EVENT; + dumps |= DUMP_FLAG_EVENT; } else if (strcmp(argv[i], "--graphics") == 0) { - dumpFlags |= DUMP_FLAG_GRAPHICS; + dumps |= DUMP_FLAG_GRAPHICS; } else if (strcmp(argv[i], "--opengl") == 0) { - dumpFlags |= DUMP_FLAG_OPENGL; + dumps |= DUMP_FLAG_OPENGL; } else if (strcmp(argv[i], "--system") == 0) { - dumpFlags |= DUMP_FLAG_SYSTEM; + dumps |= DUMP_FLAG_SYSTEM; } else if (strcmp(argv[i], "--thread") == 0) { - dumpFlags |= DUMP_FLAG_THREAD; + dumps |= DUMP_FLAG_THREAD; } else if (strcmp(argv[i], "--video") == 0) { - dumpFlags |= DUMP_FLAG_VIDEO; + dumps |= DUMP_FLAG_VIDEO; } else if (strcmp(argv[i], "--version") == 0) { - dumpFlags |= DUMP_FLAG_VERSION; + dumps |= DUMP_FLAG_VERSION; } else if (strcmp(argv[i], "--help") == 0) { - dumpFlags |= DUMP_FLAG_HELP; + dumps |= DUMP_FLAG_HELP; } else if (strcmp(argv[i], "--verbose") == 0) { - verbose = PAL_TRUE; + flags &= ~DUMP_FLAG_QUICK; + flags |= DUMP_FLAG_VERBOSE; + + } else if (strcmp(argv[i], "--quick") == 0) { + flags &= ~DUMP_FLAG_VERBOSE; + flags |= DUMP_FLAG_QUICK; } } - if (dumpFlags == 0) { - dumpFlags |= DUMP_FLAG_ALL; + if (dumps == 0) { + dumps |= DUMP_FLAG_ALL; } - if (dumpFlags & DUMP_FLAG_CORE) { - status = coreABIDump(verbose); - if (status == PAL_FALSE) { - return -1; + if (dumps & DUMP_FLAG_CORE) { + status = coreABIDump(flags); + if (status) { + passed |= DUMP_FLAG_CORE; + } else { + if (flags & DUMP_FLAG_QUICK) { + return logDumpStatus(status); + } else { + return -1; + } } } - if (dumpFlags & DUMP_FLAG_EVENT) { - status = eventABIDump(verbose); - if (status == PAL_FALSE) { - return -1; + if (dumps & DUMP_FLAG_EVENT) { + status = eventABIDump(flags); + if (status) { + passed |= DUMP_FLAG_EVENT; + } else { + if (flags & DUMP_FLAG_QUICK) { + return logDumpStatus(status); + } else { + return -1; + } } } - if (dumpFlags & DUMP_FLAG_THREAD) { - status = threadABIDump(verbose); - if (status == PAL_FALSE) { - return -1; + if (dumps & DUMP_FLAG_THREAD) { + status = threadABIDump(flags); + if (status) { + passed |= DUMP_FLAG_THREAD; + } else { + if (flags & DUMP_FLAG_QUICK) { + return logDumpStatus(status); + } else { + return -1; + } } } - if (dumpFlags & DUMP_FLAG_SYSTEM) { - status = systemABIDump(verbose); - if (status == PAL_FALSE) { - return -1; + if (dumps & DUMP_FLAG_SYSTEM) { + status = systemABIDump(flags); + if (status) { + passed |= DUMP_FLAG_SYSTEM; + } else { + if (flags & DUMP_FLAG_QUICK) { + return logDumpStatus(status); + } else { + return -1; + } } } - if (dumpFlags & DUMP_FLAG_VIDEO) { - status = videoABIDump(verbose); - if (status == PAL_FALSE) { - return -1; + if (dumps & DUMP_FLAG_VIDEO) { + status = videoABIDump(flags); + if (status) { + passed |= DUMP_FLAG_VIDEO; + } else { + if (flags & DUMP_FLAG_QUICK) { + return logDumpStatus(status); + } else { + return -1; + } } } - if (dumpFlags & DUMP_FLAG_OPENGL) { - status = openglABIDump(verbose); - if (status == PAL_FALSE) { - return -1; + if (dumps & DUMP_FLAG_OPENGL) { + if (status) { + status = openglABIDump(flags); + passed |= DUMP_FLAG_OPENGL; + } else { + if (flags & DUMP_FLAG_QUICK) { + return logDumpStatus(status); + } else { + return -1; + } } } - if (dumpFlags & DUMP_FLAG_GRAPHICS) { - status = graphicsABIDump(verbose); - if (status == PAL_FALSE) { - return -1; + if (dumps & DUMP_FLAG_GRAPHICS) { + status = graphicsABIDump(flags); + if (status) { + passed |= DUMP_FLAG_GRAPHICS; + } else { + if (flags & DUMP_FLAG_QUICK) { + return logDumpStatus(status); + } else { + return -1; + } } } - if (dumpFlags & DUMP_FLAG_VERSION) { + if (dumps & DUMP_FLAG_VERSION) { palLog(nullptr, "PAL ABI dump %s", VERSION); } - if (dumpFlags & DUMP_FLAG_HELP) { + if (dumps & DUMP_FLAG_HELP) { palLog(nullptr, "USAGE: %s [options]", EXE_NAME); palLog(nullptr, "Options:"); palLog(nullptr, " --help Display available options"); palLog(nullptr, " --version Display version"); - palLog(nullptr, " --verbose Display ABI dump information"); + palLog(nullptr, " --verbose Display Detailed ABI dump information"); + palLog(nullptr, " --quick Display only the final ABI status"); palLog(nullptr, " --all Check ABI for all PAL structs"); palLog(nullptr, " --core Check ABI for core PAL structs"); palLog(nullptr, " --event Check ABI for event PAL structs"); @@ -140,5 +191,14 @@ int main(int argc, char** argv) palLog(nullptr, " --video Check ABI for video PAL structs"); } + if (flags & DUMP_FLAG_QUICK) { + // check if all dumps that were executed passed + if (dumps == passed) { + return logDumpStatus(PAL_TRUE); + } else { + return logDumpStatus(PAL_FALSE); + } + } + return 0; } diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c index b0447059..03e2c27c 100644 --- a/tools/abi_dump/core_abi_dump.c +++ b/tools/abi_dump/core_abi_dump.c @@ -7,13 +7,15 @@ #include "dumps.h" -PalBool coreABIDump(PalBool verbose) +PalBool coreABIDump(uint32_t flags) { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Core ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); + if (!(flags & DUMP_FLAG_QUICK)) { + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Core ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + } FieldInfo versionFields[] = { { "major", {0, 4}, FIELD(PalVersion, major) }, @@ -59,15 +61,15 @@ PalBool coreABIDump(PalBool verbose) loggerInfo.expected.padding = 0; loggerInfo.actual = STRUCT(PalLogger); - PalBool status = checkABI(&versionInfo, verbose); + PalBool status = checkABI(&versionInfo, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&allocatorInfo, verbose); + status = checkABI(&allocatorInfo, flags); if (status == PAL_FALSE) { return status; } - return checkABI(&loggerInfo, verbose); + return checkABI(&loggerInfo, flags); } \ No newline at end of file diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 8978387b..9a724ec5 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -20,6 +20,22 @@ static const char* s_PassedString = "PASSED"; #define ALIGNOF(type) __alignof__(type) #endif // _MSC_VER +#define DUMP_FLAG_CORE (1u << 0) +#define DUMP_FLAG_EVENT (1u << 1) +#define DUMP_FLAG_THREAD (1u << 2) +#define DUMP_FLAG_OPENGL (1u << 3) +#define DUMP_FLAG_GRAPHICS (1u << 4) +#define DUMP_FLAG_SYSTEM (1u << 5) +#define DUMP_FLAG_VIDEO (1u << 6) +#define DUMP_FLAG_VERSION (1u << 7) +#define DUMP_FLAG_HELP (1u << 8) +#define DUMP_FLAG_VERBOSE (1u << 9) +#define DUMP_FLAG_QUICK (1u << 10) +#define DUMP_FLAG_ALL 0x7F + +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#define PADDING(type) (((ALIGNOF(type) - sizeof(type)) % ALIGNOF(type))) + typedef struct { uint32_t offset; uint32_t size; @@ -45,9 +61,12 @@ typedef struct { StructBase actual; } StructInfo; +#define FIELD(type, field) ((FieldBase){offsetof(type, field), sizeof(((type*)0)->field)}) +#define STRUCT(type) ((StructBase){ALIGNOF(type), sizeof(type), PADDING(type)}) + static PalBool checkABI( const StructInfo* info, - PalBool verbose) + uint32_t flags) { // find the size of the field column uint32_t fieldSize = 0; @@ -81,8 +100,11 @@ static PalBool checkABI( } seperator[seperatorSize] = '\0'; - palLog(nullptr, "Struct: %s", info->name); - if (verbose) { + if (!(flags & DUMP_FLAG_QUICK)) { + palLog(nullptr, "Struct: %s", info->name); + } + + if (flags & DUMP_FLAG_VERBOSE) { palLog(nullptr, ""); palLog(nullptr, "Struct format: Property: (Expected, Actual)"); palLog(nullptr, "Field format: (Offset, Size)"); @@ -117,7 +139,7 @@ static PalBool checkABI( } // clang-format on - if (verbose) { + if (flags & DUMP_FLAG_VERBOSE) { palLog(nullptr, "%-*s (%03u, %03u) (%03u, %03u)", fieldSize, @@ -128,27 +150,24 @@ static PalBool checkABI( field->actual.size); } } - if (verbose) { + if (flags & DUMP_FLAG_VERBOSE) { palLog(nullptr, seperator); } - palLog(nullptr, "Status: %s", result); - palLog(nullptr, ""); + if (!(flags & DUMP_FLAG_QUICK)) { + palLog(nullptr, "Status: %s", result); + palLog(nullptr, ""); + } return passed; } -#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) -#define FIELD(type, field) ((FieldBase){offsetof(type, field), sizeof(((type*)0)->field)}) -#define PADDING(type) (((ALIGNOF(type) - sizeof(type)) % ALIGNOF(type))) -#define STRUCT(type) ((StructBase){ALIGNOF(type), sizeof(type), PADDING(type)}) - -PalBool coreABIDump(PalBool verbose); -PalBool eventABIDump(PalBool verbose); -PalBool threadABIDump(PalBool verbose); -PalBool systemABIDump(PalBool verbose); -PalBool videoABIDump(PalBool verbose); -PalBool openglABIDump(PalBool verbose); -PalBool graphicsABIDump(PalBool verbose); +PalBool coreABIDump(uint32_t flags); +PalBool eventABIDump(uint32_t flags); +PalBool threadABIDump(uint32_t flags); +PalBool systemABIDump(uint32_t flags); +PalBool videoABIDump(uint32_t flags); +PalBool openglABIDump(uint32_t flags); +PalBool graphicsABIDump(uint32_t flags); #endif // _DUMPS_H \ No newline at end of file diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index 8f521ead..c6cb6107 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -8,13 +8,15 @@ #include "dumps.h" #include "pal/pal_event.h" -PalBool eventABIDump(PalBool verbose) +PalBool eventABIDump(uint32_t flags) { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Event ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); + if (!(flags & DUMP_FLAG_QUICK)) { + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Event ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + } FieldInfo eventFields[] = { { "data", {0, 8}, FIELD(PalEvent, data) }, @@ -63,15 +65,15 @@ PalBool eventABIDump(PalBool verbose) eventDriverCreateInfo.expected.padding = 0; eventDriverCreateInfo.actual = STRUCT(PalEventDriverCreateInfo); - PalBool status = checkABI(&eventInfo, verbose); + PalBool status = checkABI(&eventInfo, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&eventQueueInfo, verbose); + status = checkABI(&eventQueueInfo, flags); if (status == PAL_FALSE) { return status; } - return checkABI(&eventDriverCreateInfo, verbose); + return checkABI(&eventDriverCreateInfo, flags); } \ No newline at end of file diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index 2e47a7c7..381dd165 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -8,7 +8,7 @@ #include "dumps.h" #include "pal/pal_graphics.h" -static PalBool adapterDump(PalBool verbose) +static PalBool adapterDump(uint32_t flags) { // clang-format off FieldInfo adapterInfoFields[] = { @@ -148,40 +148,40 @@ static PalBool adapterDump(PalBool verbose) formatInfo.expected.padding = 0; formatInfo.actual = STRUCT(PalFormatInfo); - PalBool status = checkABI(&adapterInfo, verbose); + PalBool status = checkABI(&adapterInfo, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&imageCap, verbose); + status = checkABI(&imageCap, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&resourceCap, verbose); + status = checkABI(&resourceCap, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&computeCap, verbose); + status = checkABI(&computeCap, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&viewportCap, verbose); + status = checkABI(&viewportCap, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&adapterCap, verbose); + status = checkABI(&adapterCap, flags); if (status == PAL_FALSE) { return status; } - return checkABI(&formatInfo, verbose); + return checkABI(&formatInfo, flags); } -static PalBool deviceDump(PalBool verbose) +static PalBool deviceDump(uint32_t flags) { // clang-format off FieldInfo samplerAnisotropyCapFields[] = { @@ -320,58 +320,60 @@ static PalBool deviceDump(PalBool verbose) descriptorIndexingCap.expected.padding = 0; descriptorIndexingCap.actual = STRUCT(PalDescriptorIndexingCapabilities); - PalBool status = checkABI(&samplerAnisotropyCap, verbose); + PalBool status = checkABI(&samplerAnisotropyCap, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&multiViewCap, verbose); + status = checkABI(&multiViewCap, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&multiViewportCap, verbose); + status = checkABI(&multiViewportCap, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&depthStencilCap, verbose); + status = checkABI(&depthStencilCap, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&fragmentShadingRateCap, verbose); + status = checkABI(&fragmentShadingRateCap, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&meshCap, verbose); + status = checkABI(&meshCap, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&rayTracingCap, verbose); + status = checkABI(&rayTracingCap, flags); if (status == PAL_FALSE) { return status; } - return checkABI(&descriptorIndexingCap, verbose); + return checkABI(&descriptorIndexingCap, flags); } -PalBool graphicsABIDump(PalBool verbose) +PalBool graphicsABIDump(uint32_t flags) { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Graphics ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); + if (!(flags & DUMP_FLAG_QUICK)) { + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Graphics ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + } - PalBool status = adapterDump(verbose); + PalBool status = adapterDump(flags); if (status == PAL_FALSE) { return status; } - status = deviceDump(verbose); + status = deviceDump(flags); if (status == PAL_FALSE) { return status; } diff --git a/tools/abi_dump/opengl_abi_dump.c b/tools/abi_dump/opengl_abi_dump.c index dca084fe..e6c3ad41 100644 --- a/tools/abi_dump/opengl_abi_dump.c +++ b/tools/abi_dump/opengl_abi_dump.c @@ -8,13 +8,15 @@ #include "dumps.h" #include "pal/pal_opengl.h" -PalBool openglABIDump(PalBool verbose) +PalBool openglABIDump(uint32_t flags) { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Opengl ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); + if (!(flags & DUMP_FLAG_QUICK)) { + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Opengl ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + } FieldInfo glInfoFields[] = { { "extensions", {0, 8}, FIELD(PalGLInfo, extensions) }, @@ -96,20 +98,20 @@ PalBool openglABIDump(PalBool verbose) contextCreateInfo.expected.padding = 0; contextCreateInfo.actual = STRUCT(PalGLContextCreateInfo); - PalBool status = checkABI(&glInfo, verbose); + PalBool status = checkABI(&glInfo, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&fbConfig, verbose); + status = checkABI(&fbConfig, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&window, verbose); + status = checkABI(&window, flags); if (status == PAL_FALSE) { return status; } - return checkABI(&contextCreateInfo, verbose); + return checkABI(&contextCreateInfo, flags); } \ No newline at end of file diff --git a/tools/abi_dump/system_abi_dump.c b/tools/abi_dump/system_abi_dump.c index 981d6ab2..539bd6ca 100644 --- a/tools/abi_dump/system_abi_dump.c +++ b/tools/abi_dump/system_abi_dump.c @@ -8,13 +8,15 @@ #include "dumps.h" #include "pal/pal_system.h" -PalBool systemABIDump(PalBool verbose) +PalBool systemABIDump(uint32_t flags) { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "System ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); + if (!(flags & DUMP_FLAG_QUICK)) { + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "System ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + } FieldInfo platformInfoFields[] = { { "type", {0, 4}, FIELD(PalPlatformInfo, type) }, @@ -55,10 +57,10 @@ PalBool systemABIDump(PalBool verbose) cpuInfo.expected.padding = 0; cpuInfo.actual = STRUCT(PalCPUInfo); - PalBool status = checkABI(&platformInfo, verbose); + PalBool status = checkABI(&platformInfo, flags); if (status == PAL_FALSE) { return status; } - return checkABI(&cpuInfo, verbose); + return checkABI(&cpuInfo, flags); } \ No newline at end of file diff --git a/tools/abi_dump/thread_abi_dump.c b/tools/abi_dump/thread_abi_dump.c index bd78930b..8ed53078 100644 --- a/tools/abi_dump/thread_abi_dump.c +++ b/tools/abi_dump/thread_abi_dump.c @@ -8,13 +8,15 @@ #include "dumps.h" #include "pal/pal_thread.h" -PalBool threadABIDump(PalBool verbose) +PalBool threadABIDump(uint32_t flags) { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Thread ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); + if (!(flags & DUMP_FLAG_QUICK)) { + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Thread ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + } FieldInfo threadCreateInfoFields[] = { { "stackSize", {0, 8}, FIELD(PalThreadCreateInfo, stackSize) }, @@ -32,5 +34,5 @@ PalBool threadABIDump(PalBool verbose) threadCreateInfo.expected.padding = 0; threadCreateInfo.actual = STRUCT(PalThreadCreateInfo); - return checkABI(&threadCreateInfo, verbose); + return checkABI(&threadCreateInfo, flags); } \ No newline at end of file diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index 6ca6c4f8..5bab5793 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -8,13 +8,15 @@ #include "dumps.h" #include "pal/pal_video.h" -PalBool videoABIDump(PalBool verbose) +PalBool videoABIDump(uint32_t flags) { - palLog(nullptr, ""); - palLog(nullptr, "==========================================="); - palLog(nullptr, "Video ABI Dump"); - palLog(nullptr, "==========================================="); - palLog(nullptr, ""); + if (!(flags & DUMP_FLAG_QUICK)) { + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "Video ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + } FieldInfo monitorInfoFields[] = { { "x", {0, 4}, FIELD(PalMonitorInfo, x) }, @@ -141,35 +143,35 @@ PalBool videoABIDump(PalBool verbose) windowCreateInfo.expected.padding = 0; windowCreateInfo.actual = STRUCT(PalWindowCreateInfo); - PalBool status = checkABI(&monitorInfo, verbose); + PalBool status = checkABI(&monitorInfo, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&monitorMode, verbose); + status = checkABI(&monitorMode, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&flashInfo, verbose); + status = checkABI(&flashInfo, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&iconCreateInfo, verbose); + status = checkABI(&iconCreateInfo, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&cursorCreateInfo, verbose); + status = checkABI(&cursorCreateInfo, flags); if (status == PAL_FALSE) { return status; } - status = checkABI(&windowHandleInfo, verbose); + status = checkABI(&windowHandleInfo, flags); if (status == PAL_FALSE) { return status; } - return checkABI(&windowCreateInfo, verbose); + return checkABI(&windowCreateInfo, flags); } \ No newline at end of file From 91817df0d3468eeafa5cff9bc8af29671ed8d21f Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 17 Jul 2026 11:40:14 +0000 Subject: [PATCH 347/372] add graphics abi dump: swapchain --- include/pal/pal_graphics.h | 3 +- tools/abi_dump/graphics_abi_dump.c | 103 ++++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 7fde4d14..d1de1bbe 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1816,8 +1816,9 @@ typedef struct { typedef struct { uint64_t size; /**< Required size in bytes.*/ uint64_t alignment; /**< Required alignment in bytes.*/ + uint64_t memoryMask; /**< Memory masks used in allocations. Must not be changed.*/ uint32_t supportedMemoryTypes; /**< Masks of supported memory types.*/ - uint32_t memoryMask; /**< Memory masks used in allocations. Must not be changed.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalMemoryRequirements; /** diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index 381dd165..a3185c17 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -246,6 +246,14 @@ static PalBool deviceDump(uint32_t flags) { "maxPerStageAccelerationStructure", {44, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerStageAccelerationStructure) }, { "maxPerSetAccelerationStructure", {48, 4}, FIELD(PalDescriptorIndexingCapabilities, maxPerSetAccelerationStructure) } }; + + FieldInfo memoryRequirementFields[] = { + { "size", {0, 8}, FIELD(PalMemoryRequirements, size) }, + { "alignment", {8, 8}, FIELD(PalMemoryRequirements, alignment) }, + { "memoryMask", {16, 8}, FIELD(PalMemoryRequirements, memoryMask) }, + { "supportedMemoryTypes", {24, 4}, FIELD(PalMemoryRequirements, supportedMemoryTypes) }, + { "reserved", {28, 4}, FIELD(PalMemoryRequirements, reserved) } + }; // clang-format on StructInfo samplerAnisotropyCap = {0}; @@ -320,6 +328,15 @@ static PalBool deviceDump(uint32_t flags) descriptorIndexingCap.expected.padding = 0; descriptorIndexingCap.actual = STRUCT(PalDescriptorIndexingCapabilities); + StructInfo memoryRequirement = {0}; + memoryRequirement.name = "PalMemoryRequirements"; + memoryRequirement.fields = memoryRequirementFields; + memoryRequirement.fieldCount = ARRAY_SIZE(memoryRequirementFields); + memoryRequirement.expected.alignof = 8; + memoryRequirement.expected.size = 32; + memoryRequirement.expected.padding = 0; + memoryRequirement.actual = STRUCT(PalMemoryRequirements); + PalBool status = checkABI(&samplerAnisotropyCap, flags); if (status == PAL_FALSE) { return status; @@ -355,7 +372,86 @@ static PalBool deviceDump(uint32_t flags) return status; } - return checkABI(&descriptorIndexingCap, flags); + status = checkABI(&descriptorIndexingCap, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&memoryRequirement, flags); +} + +static PalBool swapchainDump(uint32_t flags) +{ + // clang-format off + FieldInfo surfaceCapFields[] = { + { "supportedPresentModes", {0, 4}, FIELD(PalSurfaceCapabilities, supportedPresentModes) }, + { "supportedCompositeAlphas", {4, 4}, FIELD(PalSurfaceCapabilities, supportedCompositeAlphas) }, + { "supportedFormats", {8, 4}, FIELD(PalSurfaceCapabilities, supportedFormats) }, + { "minImageCount", {12, 4}, FIELD(PalSurfaceCapabilities, minImageCount) }, + { "maxImageCount", {16, 4}, FIELD(PalSurfaceCapabilities, maxImageCount) }, + { "minImageWidth", {20, 4}, FIELD(PalSurfaceCapabilities, minImageWidth) }, + { "minImageHeight", {24, 4}, FIELD(PalSurfaceCapabilities, minImageHeight) }, + { "maxImageWidth", {28, 4}, FIELD(PalSurfaceCapabilities, maxImageWidth) }, + { "maxImageHeight", {32, 4}, FIELD(PalSurfaceCapabilities, maxImageHeight) }, + { "maxImageArrayLayers", {36, 4}, FIELD(PalSurfaceCapabilities, maxImageArrayLayers) } + }; + + FieldInfo swapchainNextImageInfoFields[] = { + { "timeout", {0, 8}, FIELD(PalSwapchainNextImageInfo, timeout) }, + { "signalSemaphore", {8, 8}, FIELD(PalSwapchainNextImageInfo, signalSemaphore) }, + { "fence", {16, 8}, FIELD(PalSwapchainNextImageInfo, fence) } + }; + + FieldInfo swapchainCreateInfoFields[] = { + { "clipped", {0, 4}, FIELD(PalSwapchainCreateInfo, clipped) }, + { "width", {4, 4}, FIELD(PalSwapchainCreateInfo, width) }, + { "height", {8, 4}, FIELD(PalSwapchainCreateInfo, height) }, + { "imageCount", {12, 4}, FIELD(PalSwapchainCreateInfo, imageCount) }, + { "imageArrayLayerCount", {16, 4}, FIELD(PalSwapchainCreateInfo, imageArrayLayerCount) }, + { "presentMode", {20, 4}, FIELD(PalSwapchainCreateInfo, presentMode) }, + { "compositeAlpha", {24, 4}, FIELD(PalSwapchainCreateInfo, compositeAlpha) }, + { "format", {28, 4}, FIELD(PalSwapchainCreateInfo, format) } + }; + // clang-format on + + StructInfo surfaceCap = {0}; + surfaceCap.name = "PalSurfaceCapabilities"; + surfaceCap.fields = surfaceCapFields; + surfaceCap.fieldCount = ARRAY_SIZE(surfaceCapFields); + surfaceCap.expected.alignof = 4; + surfaceCap.expected.size = 40; + surfaceCap.expected.padding = 0; + surfaceCap.actual = STRUCT(PalSurfaceCapabilities); + + StructInfo swapchainNextImageInfo = {0}; + swapchainNextImageInfo.name = "PalSwapchainNextImageInfo"; + swapchainNextImageInfo.fields = swapchainNextImageInfoFields; + swapchainNextImageInfo.fieldCount = ARRAY_SIZE(swapchainNextImageInfoFields); + swapchainNextImageInfo.expected.alignof = 8; + swapchainNextImageInfo.expected.size = 24; + swapchainNextImageInfo.expected.padding = 0; + swapchainNextImageInfo.actual = STRUCT(PalSwapchainNextImageInfo); + + StructInfo swapchainCreateInfo = {0}; + swapchainCreateInfo.name = "PalSwapchainCreateInfo"; + swapchainCreateInfo.fields = swapchainCreateInfoFields; + swapchainCreateInfo.fieldCount = ARRAY_SIZE(swapchainCreateInfoFields); + swapchainCreateInfo.expected.alignof = 4; + swapchainCreateInfo.expected.size = 32; + swapchainCreateInfo.expected.padding = 0; + swapchainCreateInfo.actual = STRUCT(PalSwapchainCreateInfo); + + PalBool status = checkABI(&surfaceCap, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&swapchainNextImageInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&swapchainCreateInfo, flags); } PalBool graphicsABIDump(uint32_t flags) @@ -378,5 +474,10 @@ PalBool graphicsABIDump(uint32_t flags) return status; } + status = swapchainDump(flags); + if (status == PAL_FALSE) { + return status; + } + return PAL_TRUE; } \ No newline at end of file From 93ceec3bbe0ef8cc1e900c643c5afc313844f7ba Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 17 Jul 2026 12:22:02 +0000 Subject: [PATCH 348/372] add graphics abi dump: image --- tools/abi_dump/graphics_abi_dump.c | 196 +++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index a3185c17..10c94164 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -454,6 +454,197 @@ static PalBool swapchainDump(uint32_t flags) return checkABI(&swapchainCreateInfo, flags); } +static PalBool imageDump(uint32_t flags) +{ + // clang-format off + FieldInfo imageInfoFields[] = { + { "usages", {0, 4}, FIELD(PalImageInfo, usages) }, + { "width", {4, 4}, FIELD(PalImageInfo, width) }, + { "height", {8, 4}, FIELD(PalImageInfo, height) }, + { "depth", {12, 4}, FIELD(PalImageInfo, depth) }, + { "arrayLayerCount", {16, 4}, FIELD(PalImageInfo, arrayLayerCount) }, + { "mipLevelCount", {20, 4}, FIELD(PalImageInfo, mipLevelCount) }, + { "sampleCount", {24, 4}, FIELD(PalImageInfo, sampleCount) }, + { "type", {28, 4}, FIELD(PalImageInfo, type) }, + { "format", {32, 4}, FIELD(PalImageInfo, format) }, + { "belongsToSwapchain", {36, 4}, FIELD(PalImageInfo, belongsToSwapchain) } + }; + + FieldInfo imageSubresourceRangeFields[] = { + { "aspect", {0, 4}, FIELD(PalImageSubresourceRange, aspect) }, + { "startMipLevel", {4, 4}, FIELD(PalImageSubresourceRange, startMipLevel) }, + { "mipLevelCount", {8, 4}, FIELD(PalImageSubresourceRange, mipLevelCount) }, + { "startArrayLayer", {12, 4}, FIELD(PalImageSubresourceRange, startArrayLayer) }, + { "layerArrayCount", {16, 4}, FIELD(PalImageSubresourceRange, layerArrayCount) } + }; + + FieldInfo bufferImageCopyInfoFields[] = { + { "bufferOffset", {0, 8}, FIELD(PalBufferImageCopyInfo, bufferOffset) }, + { "imageAspect", {8, 4}, FIELD(PalBufferImageCopyInfo, imageAspect) }, + { "bufferRowLength", {12, 4}, FIELD(PalBufferImageCopyInfo, bufferRowLength) }, + { "bufferImageHeight", {16, 4}, FIELD(PalBufferImageCopyInfo, bufferImageHeight) }, + { "ImageMipLevel", {20, 4}, FIELD(PalBufferImageCopyInfo, ImageMipLevel) }, + { "ImageStartArrayLayer", {24, 4}, FIELD(PalBufferImageCopyInfo, ImageStartArrayLayer) }, + { "ImageArrayLayerCount", {28, 4}, FIELD(PalBufferImageCopyInfo, ImageArrayLayerCount) }, + { "imageOffsetX", {32, 4}, FIELD(PalBufferImageCopyInfo, imageOffsetX) }, + { "imageOffsetY", {36, 4}, FIELD(PalBufferImageCopyInfo, imageOffsetY) }, + { "imageOffsetZ", {40, 4}, FIELD(PalBufferImageCopyInfo, imageOffsetZ) }, + { "imageWidth", {44, 4}, FIELD(PalBufferImageCopyInfo, imageWidth) }, + { "imageHeight", {48, 4}, FIELD(PalBufferImageCopyInfo, imageHeight) }, + { "imageDepth", {52, 4}, FIELD(PalBufferImageCopyInfo, imageDepth) } + }; + + FieldInfo imageCopyInfoFields[] = { + { "aspect", {0, 4}, FIELD(PalImageCopyInfo, aspect) }, + { "dstMipLevel", {4, 4}, FIELD(PalImageCopyInfo, dstMipLevel) }, + { "srcMipLevel", {8, 4}, FIELD(PalImageCopyInfo, srcMipLevel) }, + { "dstStartArrayLayer", {12, 4}, FIELD(PalImageCopyInfo, dstStartArrayLayer) }, + { "srcStartArrayLayer", {16, 4}, FIELD(PalImageCopyInfo, srcStartArrayLayer) }, + { "arrayLayerCount", {20, 4}, FIELD(PalImageCopyInfo, arrayLayerCount) }, + { "dstOffsetX", {24, 4}, FIELD(PalImageCopyInfo, dstOffsetX) }, + { "srcOffsetX", {28, 4}, FIELD(PalImageCopyInfo, srcOffsetX) }, + { "dstOffsetY", {32, 4}, FIELD(PalImageCopyInfo, dstOffsetY) }, + { "srcOffsetY", {36, 4}, FIELD(PalImageCopyInfo, srcOffsetY) }, + { "dstOffsetZ", {40, 4}, FIELD(PalImageCopyInfo, dstOffsetZ) }, + { "srcOffsetZ", {44, 4}, FIELD(PalImageCopyInfo, srcOffsetZ) }, + { "width", {48, 4}, FIELD(PalImageCopyInfo, width) }, + { "height", {52, 4}, FIELD(PalImageCopyInfo, height) }, + { "depth", {56, 4}, FIELD(PalImageCopyInfo, depth) } + }; + + FieldInfo imageCreateInfoFields[] = { + { "usages", {0, 4}, FIELD(PalImageCreateInfo, usages) }, + { "width", {4, 4}, FIELD(PalImageCreateInfo, width) }, + { "height", {8, 4}, FIELD(PalImageCreateInfo, height) }, + { "depth", {12, 4}, FIELD(PalImageCreateInfo, depth) }, + { "arrayLayerCount", {16, 4}, FIELD(PalImageCreateInfo, arrayLayerCount) }, + { "mipLevelCount", {20, 4}, FIELD(PalImageCreateInfo, mipLevelCount) }, + { "sampleCount", {24, 4}, FIELD(PalImageCreateInfo, sampleCount) }, + { "type", {28, 4}, FIELD(PalImageCreateInfo, type) }, + { "format", {32, 4}, FIELD(PalImageCreateInfo, format) }, + { "memoryUsage", {36, 4}, FIELD(PalImageCreateInfo, memoryUsage) } + }; + + FieldInfo imageViewCreateInfoFields[] = { + { "format", {0, 4}, FIELD(PalImageViewCreateInfo, format) }, + { "type", {4, 4}, FIELD(PalImageViewCreateInfo, type) }, + { "subresourceRange", {8, 20}, FIELD(PalImageViewCreateInfo, subresourceRange) } + }; + + FieldInfo samplerCreateInfoFields[] = { + { "enableCompare", {0, 4}, FIELD(PalSamplerCreateInfo, enableCompare) }, + { "enableAnisotropy", {4, 4}, FIELD(PalSamplerCreateInfo, enableAnisotropy) }, + { "mipLodBias", {8, 4}, FIELD(PalSamplerCreateInfo, mipLodBias) }, + { "minLod", {12, 4}, FIELD(PalSamplerCreateInfo, minLod) }, + { "maxLod", {16, 4}, FIELD(PalSamplerCreateInfo, maxLod) }, + { "maxAnisotropy", {20, 4}, FIELD(PalSamplerCreateInfo, maxAnisotropy) }, + { "minFilterMode", {24, 4}, FIELD(PalSamplerCreateInfo, minFilterMode) }, + { "magFilterMode", {28, 4}, FIELD(PalSamplerCreateInfo, magFilterMode) }, + { "mipmapMode", {32, 4}, FIELD(PalSamplerCreateInfo, mipmapMode) }, + { "addressModeU", {36, 4}, FIELD(PalSamplerCreateInfo, addressModeU) }, + { "addressModeV", {40, 4}, FIELD(PalSamplerCreateInfo, addressModeV) }, + { "addressModeW", {44, 4}, FIELD(PalSamplerCreateInfo, addressModeW) }, + { "compareOp", {48, 4}, FIELD(PalSamplerCreateInfo, compareOp) }, + { "borderColor", {52, 4}, FIELD(PalSamplerCreateInfo, borderColor) }, + }; + // clang-format on + + StructInfo imageInfo = {0}; + imageInfo.name = "PalImageInfo"; + imageInfo.fields = imageInfoFields; + imageInfo.fieldCount = ARRAY_SIZE(imageInfoFields); + imageInfo.expected.alignof = 4; + imageInfo.expected.size = 40; + imageInfo.expected.padding = 0; + imageInfo.actual = STRUCT(PalImageInfo); + + StructInfo imageSubresourceRange = {0}; + imageSubresourceRange.name = "PalImageSubresourceRange"; + imageSubresourceRange.fields = imageSubresourceRangeFields; + imageSubresourceRange.fieldCount = ARRAY_SIZE(imageSubresourceRangeFields); + imageSubresourceRange.expected.alignof = 4; + imageSubresourceRange.expected.size = 20; + imageSubresourceRange.expected.padding = 0; + imageSubresourceRange.actual = STRUCT(PalImageSubresourceRange); + + StructInfo bufferImageCopyInfo = {0}; + bufferImageCopyInfo.name = "PalBufferImageCopyInfo"; + bufferImageCopyInfo.fields = bufferImageCopyInfoFields; + bufferImageCopyInfo.fieldCount = ARRAY_SIZE(bufferImageCopyInfoFields); + bufferImageCopyInfo.expected.alignof = 8; + bufferImageCopyInfo.expected.size = 56; + bufferImageCopyInfo.expected.padding = 0; + bufferImageCopyInfo.actual = STRUCT(PalBufferImageCopyInfo); + + StructInfo imageCopyInfo = {0}; + imageCopyInfo.name = "PalImageCopyInfo"; + imageCopyInfo.fields = imageCopyInfoFields; + imageCopyInfo.fieldCount = ARRAY_SIZE(imageCopyInfoFields); + imageCopyInfo.expected.alignof = 4; + imageCopyInfo.expected.size = 60; + imageCopyInfo.expected.padding = 0; + imageCopyInfo.actual = STRUCT(PalImageCopyInfo); + + StructInfo imageCreateInfo = {0}; + imageCreateInfo.name = "PalImageCreateInfo"; + imageCreateInfo.fields = imageCreateInfoFields; + imageCreateInfo.fieldCount = ARRAY_SIZE(imageCreateInfoFields); + imageCreateInfo.expected.alignof = 4; + imageCreateInfo.expected.size = 40; + imageCreateInfo.expected.padding = 0; + imageCreateInfo.actual = STRUCT(PalImageCreateInfo); + + StructInfo imageViewCreateInfo = {0}; + imageViewCreateInfo.name = "PalImageViewCreateInfo"; + imageViewCreateInfo.fields = imageViewCreateInfoFields; + imageViewCreateInfo.fieldCount = ARRAY_SIZE(imageViewCreateInfoFields); + imageViewCreateInfo.expected.alignof = 4; + imageViewCreateInfo.expected.size = 28; + imageViewCreateInfo.expected.padding = 0; + imageViewCreateInfo.actual = STRUCT(PalImageViewCreateInfo); + + StructInfo samplerCreateInfo = {0}; + samplerCreateInfo.name = "PalSamplerCreateInfo"; + samplerCreateInfo.fields = samplerCreateInfoFields; + samplerCreateInfo.fieldCount = ARRAY_SIZE(samplerCreateInfoFields); + samplerCreateInfo.expected.alignof = 4; + samplerCreateInfo.expected.size = 56; + samplerCreateInfo.expected.padding = 0; + samplerCreateInfo.actual = STRUCT(PalSamplerCreateInfo); + + PalBool status = checkABI(&imageInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&imageSubresourceRange, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&bufferImageCopyInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&imageCopyInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&imageCreateInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&imageViewCreateInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&samplerCreateInfo, flags); +} + PalBool graphicsABIDump(uint32_t flags) { if (!(flags & DUMP_FLAG_QUICK)) { @@ -479,5 +670,10 @@ PalBool graphicsABIDump(uint32_t flags) return status; } + status = imageDump(flags); + if (status == PAL_FALSE) { + return status; + } + return PAL_TRUE; } \ No newline at end of file From 29914a5fed91de48ea0b53e0ce70c25990416782 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 17 Jul 2026 12:35:14 +0000 Subject: [PATCH 349/372] add graphics abi dump: buffer --- tools/abi_dump/graphics_abi_dump.c | 67 ++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index 10c94164..ecf3b06f 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -645,6 +645,68 @@ static PalBool imageDump(uint32_t flags) return checkABI(&samplerCreateInfo, flags); } +static PalBool bufferDump(uint32_t flags) +{ + // clang-format off + FieldInfo stagingRequirementFields[] = { + { "bufferSize", {0, 8}, FIELD(PalImageStagingRequirements, bufferSize) }, + { "bufferRowLength", {8, 4}, FIELD(PalImageStagingRequirements, bufferRowLength) }, + { "bufferImageHeight", {12, 4}, FIELD(PalImageStagingRequirements, bufferImageHeight) } + }; + + FieldInfo bufferCopyInfoFields[] = { + { "size", {0, 8}, FIELD(PalBufferCopyInfo, size) }, + { "dstOffset", {8, 8}, FIELD(PalBufferCopyInfo, dstOffset) }, + { "srcOffset", {16, 8}, FIELD(PalBufferCopyInfo, srcOffset) } + }; + + FieldInfo bufferCreateInfoFields[] = { + { "size", {0, 8}, FIELD(PalBufferCreateInfo, size) }, + { "usages", {8, 4}, FIELD(PalBufferCreateInfo, usages) }, + { "memoryUsage", {12, 4}, FIELD(PalBufferCreateInfo, memoryUsage) } + }; + // clang-format on + + StructInfo stagingRequirement = {0}; + stagingRequirement.name = "PalImageStagingRequirements"; + stagingRequirement.fields = stagingRequirementFields; + stagingRequirement.fieldCount = ARRAY_SIZE(stagingRequirementFields); + stagingRequirement.expected.alignof = 8; + stagingRequirement.expected.size = 16; + stagingRequirement.expected.padding = 0; + stagingRequirement.actual = STRUCT(PalImageStagingRequirements); + + StructInfo bufferCopyInfo = {0}; + bufferCopyInfo.name = "PalBufferCopyInfo"; + bufferCopyInfo.fields = bufferCopyInfoFields; + bufferCopyInfo.fieldCount = ARRAY_SIZE(bufferCopyInfoFields); + bufferCopyInfo.expected.alignof = 8; + bufferCopyInfo.expected.size = 24; + bufferCopyInfo.expected.padding = 0; + bufferCopyInfo.actual = STRUCT(PalBufferCopyInfo); + + StructInfo bufferCreateInfo = {0}; + bufferCreateInfo.name = "PalBufferCreateInfo"; + bufferCreateInfo.fields = bufferCreateInfoFields; + bufferCreateInfo.fieldCount = ARRAY_SIZE(bufferCreateInfoFields); + bufferCreateInfo.expected.alignof = 8; + bufferCreateInfo.expected.size = 16; + bufferCreateInfo.expected.padding = 0; + bufferCreateInfo.actual = STRUCT(PalBufferCreateInfo); + + PalBool status = checkABI(&stagingRequirement, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&bufferCopyInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&bufferCreateInfo, flags); +} + PalBool graphicsABIDump(uint32_t flags) { if (!(flags & DUMP_FLAG_QUICK)) { @@ -675,5 +737,10 @@ PalBool graphicsABIDump(uint32_t flags) return status; } + status = bufferDump(flags); + if (status == PAL_FALSE) { + return status; + } + return PAL_TRUE; } \ No newline at end of file From cfe39048a167f8cf95d5db5f7148946414510762 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 17 Jul 2026 13:05:55 +0000 Subject: [PATCH 350/372] add graphics abi dump: acceleration structure --- include/pal/pal_graphics.h | 16 +-- tools/abi_dump/graphics_abi_dump.c | 162 +++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 15 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index d1de1bbe..8768f7b3 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -447,8 +447,6 @@ #define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FACING_CULL_DISABLE (1U << 2) #define PAL_ACCELERATION_STRUCTURE_INSTANCE_FLAG_TRIANGLE_FRONT_COUNTERCLOCKWISE (1U << 3) -#define ePAL_ACCELERATION_STRUCTURE_CREATE_FLAG_NONE 0 - #define PAL_GEOMETRY_TYPE_TRIANGLE 0 #define PAL_GEOMETRY_TYPE_AABBS 1 #define PAL_GEOMETRY_TYPE_COUNT 2 @@ -1236,18 +1234,6 @@ typedef uint32_t PalFragmentShadingRateCombinerOp; */ typedef uint32_t PalAccelerationStructureType; -/** - * @typedef PalAccelerationStructureCreateFlags - * @brief Acceleration structure create flags. Multiple hints can be OR'ed together using - * bitwise OR operator (`|`). - * - * All acceleration structure create flags follow the format - * `PAL_ACCELERATION_STRUCTURE_CREATE_FLAG_**` for consistency and API use. - * - * @since 2.0 - */ -typedef uint32_t PalAccelerationStructureCreateFlags; - /** * @typedef PalAccelerationStructureBuildMode * @brief Acceleration structure build modes. @@ -2586,7 +2572,7 @@ typedef struct { uint64_t offset; /**< Size in bytes.*/ uint64_t size; /**< Offset in bytes.*/ PalAccelerationStructureType type; /**< (eg. `PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL`).*/ - PalAccelerationStructureCreateFlags createFlags; /**< Set to 0 for default.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalAccelerationStructureCreateInfo; /** diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index ecf3b06f..b4413006 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -707,6 +707,163 @@ static PalBool bufferDump(uint32_t flags) return checkABI(&bufferCreateInfo, flags); } +static PalBool accelerationStructureDump(uint32_t flags) +{ + // clang-format off + FieldInfo accelerationStructureInstanceFields[] = { + { "blas", {0, 8}, FIELD(PalAccelerationStructureInstance, blas) }, + { "flags", {8, 4}, FIELD(PalAccelerationStructureInstance, flags) }, + { "mask", {12, 4}, FIELD(PalAccelerationStructureInstance, mask) }, + { "instanceId", {16, 4}, FIELD(PalAccelerationStructureInstance, instanceId) }, + { "hitGroupOffset", {20, 4}, FIELD(PalAccelerationStructureInstance, hitGroupOffset) }, + { "transform", {24, 48}, FIELD(PalAccelerationStructureInstance, transform) } + }; + + FieldInfo accelerationStructureBuildSizeFields[] = { + { "accelerationStructureSize", {0, 8}, FIELD(PalAccelerationStructureBuildSize, accelerationStructureSize) }, + { "scratchBufferSize", {8, 8}, FIELD(PalAccelerationStructureBuildSize, scratchBufferSize) }, + { "updateScratchBufferSize", {16, 8}, FIELD(PalAccelerationStructureBuildSize, updateScratchBufferSize) } + }; + + FieldInfo geometryDataTriangleFields[] = { + { "vertexBufferAddress", {0, 8}, FIELD(PalGeometryDataTriangle, vertexBufferAddress) }, + { "indexBufferAddress", {8, 8}, FIELD(PalGeometryDataTriangle, indexBufferAddress) }, + { "transformBufferAddress", {16, 8}, FIELD(PalGeometryDataTriangle, transformBufferAddress) }, + { "vertexType", {24, 4}, FIELD(PalGeometryDataTriangle, vertexType) }, + { "indexType", {28, 4}, FIELD(PalGeometryDataTriangle, indexType) }, + { "vertexCount", {32, 4}, FIELD(PalGeometryDataTriangle, vertexCount) }, + { "vertexStride", {36, 4}, FIELD(PalGeometryDataTriangle, vertexStride) } + }; + + FieldInfo geometryDataAABBSFields[] = { + { "bufferAddress", {0, 8}, FIELD(PalGeometryDataAABBS, bufferAddress) }, + { "stride", {8, 8}, FIELD(PalGeometryDataAABBS, stride) } + }; + + FieldInfo geometryFields[] = { + { "data", {0, 8}, FIELD(PalGeometry, data) }, + { "primitiveCount", {8, 8}, FIELD(PalGeometry, primitiveCount) }, + { "flags", {16, 4}, FIELD(PalGeometry, flags) }, + { "type", {20, 4}, FIELD(PalGeometry, type) }, + }; + + FieldInfo accelerationStructureBuildInfoFields[] = { + { "dst", {0, 8}, FIELD(PalAccelerationStructureBuildInfo, dst) }, + { "src", {8, 8}, FIELD(PalAccelerationStructureBuildInfo, src) }, + { "geometries", {16, 8}, FIELD(PalAccelerationStructureBuildInfo, geometries) }, + { "scratchBufferAddress", {24, 8}, FIELD(PalAccelerationStructureBuildInfo, scratchBufferAddress) }, + { "instanceBufferAddress", {32, 8}, FIELD(PalAccelerationStructureBuildInfo, instanceBufferAddress) }, + { "buildHints", {40, 4}, FIELD(PalAccelerationStructureBuildInfo, buildHints) }, + { "type", {44, 4}, FIELD(PalAccelerationStructureBuildInfo, type) }, + { "buildMode", {48, 4}, FIELD(PalAccelerationStructureBuildInfo, buildMode) }, + { "count", {52, 4}, FIELD(PalAccelerationStructureBuildInfo, count) }, + }; + + FieldInfo accelerationStructureCreateInfoFields[] = { + { "buffer", {0, 8}, FIELD(PalAccelerationStructureCreateInfo, buffer) }, + { "offset", {8, 8}, FIELD(PalAccelerationStructureCreateInfo, offset) }, + { "size", {16, 8}, FIELD(PalAccelerationStructureCreateInfo, size) }, + { "type", {24, 4}, FIELD(PalAccelerationStructureCreateInfo, type) }, + { "reserved", {28, 4}, FIELD(PalAccelerationStructureCreateInfo, reserved) } + }; + // clang-format on + + StructInfo accelerationStructureInstance = {0}; + accelerationStructureInstance.name = "PalAccelerationStructureInstance"; + accelerationStructureInstance.fields = accelerationStructureInstanceFields; + accelerationStructureInstance.fieldCount = ARRAY_SIZE(accelerationStructureInstanceFields); + accelerationStructureInstance.expected.alignof = 8; + accelerationStructureInstance.expected.size = 72; + accelerationStructureInstance.expected.padding = 0; + accelerationStructureInstance.actual = STRUCT(PalAccelerationStructureInstance); + + StructInfo accelerationStructureBuildSize = {0}; + accelerationStructureBuildSize.name = "PalAccelerationStructureBuildSize"; + accelerationStructureBuildSize.fields = accelerationStructureBuildSizeFields; + accelerationStructureBuildSize.fieldCount = ARRAY_SIZE(accelerationStructureBuildSizeFields); + accelerationStructureBuildSize.expected.alignof = 8; + accelerationStructureBuildSize.expected.size = 24; + accelerationStructureBuildSize.expected.padding = 0; + accelerationStructureBuildSize.actual = STRUCT(PalAccelerationStructureBuildSize); + + StructInfo geometryDataTriangle = {0}; + geometryDataTriangle.name = "PalGeometryDataTriangle"; + geometryDataTriangle.fields = geometryDataTriangleFields; + geometryDataTriangle.fieldCount = ARRAY_SIZE(geometryDataTriangleFields); + geometryDataTriangle.expected.alignof = 8; + geometryDataTriangle.expected.size = 40; + geometryDataTriangle.expected.padding = 0; + geometryDataTriangle.actual = STRUCT(PalGeometryDataTriangle); + + StructInfo geometryDataAABBS = {0}; + geometryDataAABBS.name = "PalGeometryDataAABBS"; + geometryDataAABBS.fields = geometryDataAABBSFields; + geometryDataAABBS.fieldCount = ARRAY_SIZE(geometryDataAABBSFields); + geometryDataAABBS.expected.alignof = 8; + geometryDataAABBS.expected.size = 16; + geometryDataAABBS.expected.padding = 0; + geometryDataAABBS.actual = STRUCT(PalGeometryDataAABBS); + + StructInfo geometry = {0}; + geometry.name = "PalGeometry"; + geometry.fields = geometryFields; + geometry.fieldCount = ARRAY_SIZE(geometryFields); + geometry.expected.alignof = 8; + geometry.expected.size = 24; + geometry.expected.padding = 0; + geometry.actual = STRUCT(PalGeometry); + + StructInfo accelerationStructureBuildInfo = {0}; + accelerationStructureBuildInfo.name = "PalAccelerationStructureBuildInfo"; + accelerationStructureBuildInfo.fields = accelerationStructureBuildInfoFields; + accelerationStructureBuildInfo.fieldCount = ARRAY_SIZE(accelerationStructureBuildInfoFields); + accelerationStructureBuildInfo.expected.alignof = 8; + accelerationStructureBuildInfo.expected.size = 56; + accelerationStructureBuildInfo.expected.padding = 0; + accelerationStructureBuildInfo.actual = STRUCT(PalAccelerationStructureBuildInfo); + + StructInfo accelerationStructureCreateInfo = {0}; + accelerationStructureCreateInfo.name = "PalAccelerationStructureCreateInfo"; + accelerationStructureCreateInfo.fields = accelerationStructureCreateInfoFields; + accelerationStructureCreateInfo.fieldCount = ARRAY_SIZE(accelerationStructureCreateInfoFields); + accelerationStructureCreateInfo.expected.alignof = 8; + accelerationStructureCreateInfo.expected.size = 32; + accelerationStructureCreateInfo.expected.padding = 0; + accelerationStructureCreateInfo.actual = STRUCT(PalAccelerationStructureCreateInfo); + + PalBool status = checkABI(&accelerationStructureInstance, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&accelerationStructureBuildSize, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&geometryDataTriangle, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&geometryDataAABBS, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&geometry, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&accelerationStructureBuildInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&accelerationStructureCreateInfo, flags); +} + PalBool graphicsABIDump(uint32_t flags) { if (!(flags & DUMP_FLAG_QUICK)) { @@ -742,5 +899,10 @@ PalBool graphicsABIDump(uint32_t flags) return status; } + status = accelerationStructureDump(flags); + if (status == PAL_FALSE) { + return status; + } + return PAL_TRUE; } \ No newline at end of file From 2c8d77be45953717ea9775522f3849ba2883e831 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 17 Jul 2026 16:32:13 +0000 Subject: [PATCH 351/372] add graphics abi dump: pipeline --- include/pal/pal_graphics.h | 16 +- tools/abi_dump/graphics_abi_dump.c | 327 +++++++++++++++++++++++++++++ 2 files changed, 336 insertions(+), 7 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 8768f7b3..4bc952db 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1994,9 +1994,10 @@ typedef struct { */ typedef struct { PalVertexAttribute* attributes; /**< Vertex attributes.*/ - uint64_t attributeCount; /**< Number of vertex attributes.*/ + uint32_t attributeCount; /**< Number of vertex attributes.*/ PalVertexLayoutType type; /**< (eg. `PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX`).*/ uint32_t binding; /**< Vertex buffer binding slot.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalVertexLayout; /** @@ -2046,7 +2047,7 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t sampleMask; /**< Set to `nullptr` to use default.*/ + uint64_t sampleMask; /**< Set to 0 to use default.*/ PalBool enableSampleShading; /**< `PAL_TRUE` to enable sample shading.*/ PalBool enableAlphaToCoverage; /**< `PAL_TRUE` to enable alpha to coverage.*/ PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_4`).*/ @@ -2097,13 +2098,13 @@ typedef struct { * @since 2.0 */ typedef struct { - PalColorMask colorWriteMask; /**< (eg. `PAL_COLOR_MASK_RED` | `PAL_COLOR_MASK_RED`).*/ PalBool enableBlend; /**< `PAL_TRUE` to enable blending.*/ - PalBlendFactor srcColorBlendFactor; /**< (eg. `PAL_BLEND_FACTOR_SRC_ALPHA`).*/ + PalColorMask colorWriteMask; /**< (eg. `PAL_COLOR_MASK_RED` | `PAL_COLOR_MASK_RED`).*/ PalBlendFactor dstColorBlendFactor; /**< (eg. `PAL_BLEND_FACTOR_ONE_MINUS_DST_ALPHA`).*/ + PalBlendFactor srcColorBlendFactor; /**< (eg. `PAL_BLEND_FACTOR_SRC_ALPHA`).*/ PalBlendOp colorBlendOp; /**< (eg. `PAL_BLEND_OP_ADD`).*/ - PalBlendFactor srcAlphaBlendFactor; /**< (eg. `PAL_BLEND_FACTOR_SRC_COLOR`).*/ PalBlendFactor dstAlphaBlendFactor; /**< (eg. `PAL_BLEND_FACTOR_ONE_MINUS_DST_COLOR`).*/ + PalBlendFactor srcAlphaBlendFactor; /**< (eg. `PAL_BLEND_FACTOR_SRC_COLOR`).*/ PalBlendOp alphaBlendOp; /**< (eg. `PAL_BLEND_OP_SUBTRACT`).*/ } PalColorBlendAttachment; @@ -2642,7 +2643,7 @@ typedef struct { uint32_t colorBlendAttachmentCount; /**< Number of color attachments.*/ uint32_t shaderCount; /**< Number of shaders.*/ PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is `PAL_TRUE`.*/ - PalPrimitiveTopology topology; + PalPrimitiveTopology topology; /**< (eg. `PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST`).*/ } PalGraphicsPipelineCreateInfo; /** @@ -2693,11 +2694,12 @@ typedef struct { PalPipelineLayout* pipelineLayout; /**< Pipeline layout.*/ PalRayTracingShaderGroupCreateInfo* shaderGroups; /**< Shader groups.*/ PalShader** shaders; /**< Shaders.*/ - uint64_t shaderGroupCount; /**< Number of shader groups.*/ + uint32_t shaderGroupCount; /**< Number of shader groups.*/ uint32_t shaderCount; /**< Number of shaders.*/ uint32_t maxRecursionDepth; /**< Max number of ray recursion.*/ uint32_t maxAttributeSize; /**< Max attributes size in bytes.*/ uint32_t maxPayloadSize; /**< Max payload size in bytes.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalRayTracingPipelineCreateInfo; /** diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index b4413006..eb52a19d 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -864,6 +864,328 @@ static PalBool accelerationStructureDump(uint32_t flags) return checkABI(&accelerationStructureCreateInfo, flags); } +static PalBool pipelineDump(uint32_t flags) +{ + // clang-format off + FieldInfo vertexAttributeFields[] = { + { "semanticID", {0, 4}, FIELD(PalVertexAttribute, semanticID) }, + { "type", {4, 4}, FIELD(PalVertexAttribute, type) } + }; + + FieldInfo vertexLayoutFields[] = { + { "attributes", {0, 8}, FIELD(PalVertexLayout, attributes) }, + { "attributeCount", {8, 4}, FIELD(PalVertexLayout, attributeCount) }, + { "type", {12, 4}, FIELD(PalVertexLayout, type) }, + { "binding", {16, 4}, FIELD(PalVertexLayout, binding) }, + { "reserved", {20, 4}, FIELD(PalVertexLayout, reserved) } + }; + + FieldInfo rasterizerStateFields[] = { + { "enableDepthClamp", {0, 4}, FIELD(PalRasterizerState, enableDepthClamp) }, + { "enableDepthBias", {4, 4}, FIELD(PalRasterizerState, enableDepthBias) }, + { "depthBiasConstant", {8, 4}, FIELD(PalRasterizerState, depthBiasConstant) }, + { "depthBiasSlope", {12, 4}, FIELD(PalRasterizerState, depthBiasSlope) }, + { "depthBiasClamp", {16, 4}, FIELD(PalRasterizerState, depthBiasClamp) }, + { "polygonMode", {20, 4}, FIELD(PalRasterizerState, polygonMode) }, + { "cullMode", {24, 4}, FIELD(PalRasterizerState, cullMode) }, + { "frontFace", {28, 4}, FIELD(PalRasterizerState, frontFace) } + }; + + FieldInfo multisampleStateFields[] = { + { "sampleMask", {0, 8}, FIELD(PalMultisampleState, sampleMask) }, + { "enableSampleShading", {8, 4}, FIELD(PalMultisampleState, enableSampleShading) }, + { "enableAlphaToCoverage", {12, 4}, FIELD(PalMultisampleState, enableAlphaToCoverage) }, + { "sampleCount", {16, 4}, FIELD(PalMultisampleState, sampleCount) }, + { "minSampleShading", {20, 4}, FIELD(PalMultisampleState, minSampleShading) } + }; + + FieldInfo stencilOpStateFields[] = { + { "failOp", {0, 4}, FIELD(PalStencilOpState, failOp) }, + { "passOp", {4, 4}, FIELD(PalStencilOpState, passOp) }, + { "depthFailOp", {8, 4}, FIELD(PalStencilOpState, depthFailOp) }, + { "compareOp", {12, 4}, FIELD(PalStencilOpState, compareOp) } + }; + + FieldInfo depthStencilStateFields[] = { + { "enableDepthTest", {0, 4}, FIELD(PalDepthStencilState, enableDepthTest) }, + { "enableDepthWrite", {4, 4}, FIELD(PalDepthStencilState, enableDepthWrite) }, + { "enableStencilTest", {8, 4}, FIELD(PalDepthStencilState, enableStencilTest) }, + { "compareOp", {12, 4}, FIELD(PalDepthStencilState, compareOp) }, + { "frontStencilOpState", {16, 16}, FIELD(PalDepthStencilState, frontStencilOpState) }, + { "backStencilOpState", {32, 16}, FIELD(PalDepthStencilState, backStencilOpState) }, + }; + + FieldInfo colorBlendAttachmentFields[] = { + { "enableBlend", {0, 4}, FIELD(PalColorBlendAttachment, enableBlend) }, + { "colorWriteMask", {4, 4}, FIELD(PalColorBlendAttachment, colorWriteMask) }, + { "dstColorBlendFactor", {8, 4}, FIELD(PalColorBlendAttachment, dstColorBlendFactor) }, + { "srcColorBlendFactor", {12, 4}, FIELD(PalColorBlendAttachment, srcColorBlendFactor) }, + { "colorBlendOp", {16, 4}, FIELD(PalColorBlendAttachment, colorBlendOp) }, + { "dstAlphaBlendFactor", {20, 4}, FIELD(PalColorBlendAttachment, dstAlphaBlendFactor) }, + { "srcAlphaBlendFactor", {24, 4}, FIELD(PalColorBlendAttachment, srcAlphaBlendFactor) }, + { "alphaBlendOp", {28, 4}, FIELD(PalColorBlendAttachment, alphaBlendOp) } + }; + + FieldInfo fragmentShadingRateStateFields[] = { + { "rate", {0, 4}, FIELD(PalFragmentShadingRateState, rate) }, + { "combinerOps", {4, 8}, FIELD(PalFragmentShadingRateState, combinerOps) } + }; + + FieldInfo pushConstantInfoFields[] = { + { "offset", {0, 4}, FIELD(PalPushConstantInfo, offset) }, + { "size", {4, 4}, FIELD(PalPushConstantInfo, size) } + }; + + FieldInfo pipelineLayoutCreateInfoFields[] = { + { "descriptorSetLayouts", {0, 8}, FIELD(PalPipelineLayoutCreateInfo, descriptorSetLayouts) }, + { "pushConstantInfo", {8, 8}, FIELD(PalPipelineLayoutCreateInfo, pushConstantInfo) }, + { "descriptorSetLayoutCount", {16, 4}, FIELD(PalPipelineLayoutCreateInfo, descriptorSetLayoutCount) }, + { "usePushConstant", {20, 4}, FIELD(PalPipelineLayoutCreateInfo, usePushConstant) } + }; + + FieldInfo graphicsPipelineCreateInfoFields[] = { + { "pipelineLayout", {0, 8}, FIELD(PalGraphicsPipelineCreateInfo, pipelineLayout) }, + { "shaders", {8, 8}, FIELD(PalGraphicsPipelineCreateInfo, shaders) }, + { "vertexLayouts", {16, 8}, FIELD(PalGraphicsPipelineCreateInfo, vertexLayouts) }, + { "colorBlendAttachments", {24, 8}, FIELD(PalGraphicsPipelineCreateInfo, colorBlendAttachments) }, + { "rasterizerState", {32, 8}, FIELD(PalGraphicsPipelineCreateInfo, rasterizerState) }, + { "multisampleState", {40, 8}, FIELD(PalGraphicsPipelineCreateInfo, multisampleState) }, + { "depthStencilState", {48, 8}, FIELD(PalGraphicsPipelineCreateInfo, depthStencilState) }, + { "fragmentShadingRateState", {56, 8}, FIELD(PalGraphicsPipelineCreateInfo, fragmentShadingRateState) }, + { "renderingLayout", {64, 8}, FIELD(PalGraphicsPipelineCreateInfo, renderingLayout) }, + { "primitiveRestartEnable", {72, 4}, FIELD(PalGraphicsPipelineCreateInfo, primitiveRestartEnable) }, + { "vertexLayoutCount", {76, 4}, FIELD(PalGraphicsPipelineCreateInfo, vertexLayoutCount) }, + { "colorBlendAttachmentCount", {80, 4}, FIELD(PalGraphicsPipelineCreateInfo, colorBlendAttachmentCount) }, + { "shaderCount", {84, 4}, FIELD(PalGraphicsPipelineCreateInfo, shaderCount) }, + { "indexType", {88, 4}, FIELD(PalGraphicsPipelineCreateInfo, indexType) }, + { "topology", {92, 4}, FIELD(PalGraphicsPipelineCreateInfo, topology) } + }; + + FieldInfo computePipelineCreateInfoFields[] = { + { "pipelineLayout", {0, 8}, FIELD(PalComputePipelineCreateInfo, pipelineLayout) }, + { "computeShader", {8, 8}, FIELD(PalComputePipelineCreateInfo, computeShader) } + }; + + FieldInfo rayTracingShaderGroupCreateInfoFields[] = { + { "type", {0, 4}, FIELD(PalRayTracingShaderGroupCreateInfo, type) }, + { "anyHitShaderIndex", {4, 4}, FIELD(PalRayTracingShaderGroupCreateInfo, anyHitShaderIndex) }, + { "anyHitShaderEntryIndex", {8, 4}, FIELD(PalRayTracingShaderGroupCreateInfo, anyHitShaderEntryIndex) }, + { "closestHitShaderIndex", {12, 4}, FIELD(PalRayTracingShaderGroupCreateInfo, closestHitShaderIndex) }, + { "closestHitShaderEntryIndex", {16, 4}, FIELD(PalRayTracingShaderGroupCreateInfo, closestHitShaderEntryIndex) }, + { "generalShaderIndex", {20, 4}, FIELD(PalRayTracingShaderGroupCreateInfo, generalShaderIndex) }, + { "generalShaderEntryIndex", {24, 4}, FIELD(PalRayTracingShaderGroupCreateInfo, generalShaderEntryIndex) }, + { "intersectionShaderIndex", {28, 4}, FIELD(PalRayTracingShaderGroupCreateInfo, intersectionShaderIndex) }, + { "intersectionShaderEntryIndex", {32, 4}, FIELD(PalRayTracingShaderGroupCreateInfo, intersectionShaderEntryIndex) }, + { "maxDataSize", {36, 4}, FIELD(PalRayTracingShaderGroupCreateInfo, maxDataSize) } + }; + + FieldInfo rayTracingPipelineCreateInfoFields[] = { + { "pipelineLayout", {0, 8}, FIELD(PalRayTracingPipelineCreateInfo, pipelineLayout) }, + { "shaderGroups", {8, 8}, FIELD(PalRayTracingPipelineCreateInfo, shaderGroups) }, + { "shaders", {16, 8}, FIELD(PalRayTracingPipelineCreateInfo, shaders) }, + { "shaderGroupCount", {24, 4}, FIELD(PalRayTracingPipelineCreateInfo, shaderGroupCount) }, + { "shaderCount", {28, 4}, FIELD(PalRayTracingPipelineCreateInfo, shaderCount) }, + { "maxRecursionDepth", {32, 4}, FIELD(PalRayTracingPipelineCreateInfo, maxRecursionDepth) }, + { "maxAttributeSize", {36, 4}, FIELD(PalRayTracingPipelineCreateInfo, maxAttributeSize) }, + { "maxPayloadSize", {40, 4}, FIELD(PalRayTracingPipelineCreateInfo, maxPayloadSize) }, + { "reserved", {44, 4}, FIELD(PalRayTracingPipelineCreateInfo, reserved) } + }; + // clang-format on + + StructInfo vertexAttribute = {0}; + vertexAttribute.name = "PalVertexAttribute"; + vertexAttribute.fields = vertexAttributeFields; + vertexAttribute.fieldCount = ARRAY_SIZE(vertexAttributeFields); + vertexAttribute.expected.alignof = 4; + vertexAttribute.expected.size = 8; + vertexAttribute.expected.padding = 0; + vertexAttribute.actual = STRUCT(PalVertexAttribute); + + StructInfo vertexLayout = {0}; + vertexLayout.name = "PalVertexLayout"; + vertexLayout.fields = vertexLayoutFields; + vertexLayout.fieldCount = ARRAY_SIZE(vertexLayoutFields); + vertexLayout.expected.alignof = 8; + vertexLayout.expected.size = 24; + vertexLayout.expected.padding = 0; + vertexLayout.actual = STRUCT(PalVertexLayout); + + StructInfo rasterizerState = {0}; + rasterizerState.name = "PalRasterizerState"; + rasterizerState.fields = rasterizerStateFields; + rasterizerState.fieldCount = ARRAY_SIZE(rasterizerStateFields); + rasterizerState.expected.alignof = 4; + rasterizerState.expected.size = 32; + rasterizerState.expected.padding = 0; + rasterizerState.actual = STRUCT(PalRasterizerState); + + StructInfo multisampleState = {0}; + multisampleState.name = "PalMultisampleState"; + multisampleState.fields = multisampleStateFields; + multisampleState.fieldCount = ARRAY_SIZE(multisampleStateFields); + multisampleState.expected.alignof = 8; + multisampleState.expected.size = 24; + multisampleState.expected.padding = 0; + multisampleState.actual = STRUCT(PalMultisampleState); + + StructInfo stencilOpState = {0}; + stencilOpState.name = "PalStencilOpState"; + stencilOpState.fields = stencilOpStateFields; + stencilOpState.fieldCount = ARRAY_SIZE(stencilOpStateFields); + stencilOpState.expected.alignof = 4; + stencilOpState.expected.size = 16; + stencilOpState.expected.padding = 0; + stencilOpState.actual = STRUCT(PalStencilOpState); + + StructInfo depthStencilState = {0}; + depthStencilState.name = "PalDepthStencilState"; + depthStencilState.fields = depthStencilStateFields; + depthStencilState.fieldCount = ARRAY_SIZE(depthStencilStateFields); + depthStencilState.expected.alignof = 4; + depthStencilState.expected.size = 48; + depthStencilState.expected.padding = 0; + depthStencilState.actual = STRUCT(PalDepthStencilState); + + StructInfo colorBlendAttachment = {0}; + colorBlendAttachment.name = "PalColorBlendAttachment"; + colorBlendAttachment.fields = colorBlendAttachmentFields; + colorBlendAttachment.fieldCount = ARRAY_SIZE(colorBlendAttachmentFields); + colorBlendAttachment.expected.alignof = 4; + colorBlendAttachment.expected.size = 32; + colorBlendAttachment.expected.padding = 0; + colorBlendAttachment.actual = STRUCT(PalColorBlendAttachment); + + StructInfo fragmentShadingRateState = {0}; + fragmentShadingRateState.name = "PalFragmentShadingRateState"; + fragmentShadingRateState.fields = fragmentShadingRateStateFields; + fragmentShadingRateState.fieldCount = ARRAY_SIZE(fragmentShadingRateStateFields); + fragmentShadingRateState.expected.alignof = 4; + fragmentShadingRateState.expected.size = 12; + fragmentShadingRateState.expected.padding = 0; + fragmentShadingRateState.actual = STRUCT(PalFragmentShadingRateState); + + StructInfo pushConstantInfo = {0}; + pushConstantInfo.name = "PalPushConstantInfo"; + pushConstantInfo.fields = pushConstantInfoFields; + pushConstantInfo.fieldCount = ARRAY_SIZE(pushConstantInfoFields); + pushConstantInfo.expected.alignof = 4; + pushConstantInfo.expected.size = 8; + pushConstantInfo.expected.padding = 0; + pushConstantInfo.actual = STRUCT(PalPushConstantInfo); + + StructInfo pipelineLayoutCreateInfo = {0}; + pipelineLayoutCreateInfo.name = "PalPipelineLayoutCreateInfo"; + pipelineLayoutCreateInfo.fields = pipelineLayoutCreateInfoFields; + pipelineLayoutCreateInfo.fieldCount = ARRAY_SIZE(pipelineLayoutCreateInfoFields); + pipelineLayoutCreateInfo.expected.alignof = 8; + pipelineLayoutCreateInfo.expected.size = 24; + pipelineLayoutCreateInfo.expected.padding = 0; + pipelineLayoutCreateInfo.actual = STRUCT(PalPipelineLayoutCreateInfo); + + StructInfo graphicsPipelineCreateInfo = {0}; + graphicsPipelineCreateInfo.name = "PalGraphicsPipelineCreateInfo"; + graphicsPipelineCreateInfo.fields = graphicsPipelineCreateInfoFields; + graphicsPipelineCreateInfo.fieldCount = ARRAY_SIZE(graphicsPipelineCreateInfoFields); + graphicsPipelineCreateInfo.expected.alignof = 8; + graphicsPipelineCreateInfo.expected.size = 96; + graphicsPipelineCreateInfo.expected.padding = 0; + graphicsPipelineCreateInfo.actual = STRUCT(PalGraphicsPipelineCreateInfo); + + StructInfo computePipelineCreateInfo = {0}; + computePipelineCreateInfo.name = "PalComputePipelineCreateInfo"; + computePipelineCreateInfo.fields = computePipelineCreateInfoFields; + computePipelineCreateInfo.fieldCount = ARRAY_SIZE(computePipelineCreateInfoFields); + computePipelineCreateInfo.expected.alignof = 8; + computePipelineCreateInfo.expected.size = 16; + computePipelineCreateInfo.expected.padding = 0; + computePipelineCreateInfo.actual = STRUCT(PalComputePipelineCreateInfo); + + StructInfo rayTracingShaderGroupCreateInfo = {0}; + rayTracingShaderGroupCreateInfo.name = "PalRayTracingShaderGroupCreateInfo"; + rayTracingShaderGroupCreateInfo.fields = rayTracingShaderGroupCreateInfoFields; + rayTracingShaderGroupCreateInfo.fieldCount = ARRAY_SIZE(rayTracingShaderGroupCreateInfoFields); + rayTracingShaderGroupCreateInfo.expected.alignof = 4; + rayTracingShaderGroupCreateInfo.expected.size = 40; + rayTracingShaderGroupCreateInfo.expected.padding = 0; + rayTracingShaderGroupCreateInfo.actual = STRUCT(PalRayTracingShaderGroupCreateInfo); + + StructInfo rayTracingPipelineCreateInfo = {0}; + rayTracingPipelineCreateInfo.name = "PalRayTracingPipelineCreateInfo"; + rayTracingPipelineCreateInfo.fields = rayTracingPipelineCreateInfoFields; + rayTracingPipelineCreateInfo.fieldCount = ARRAY_SIZE(rayTracingPipelineCreateInfoFields); + rayTracingPipelineCreateInfo.expected.alignof = 8; + rayTracingPipelineCreateInfo.expected.size = 48; + rayTracingPipelineCreateInfo.expected.padding = 0; + rayTracingPipelineCreateInfo.actual = STRUCT(PalRayTracingPipelineCreateInfo); + + PalBool status = checkABI(&vertexAttribute, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&vertexLayout, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&rasterizerState, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&multisampleState, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&stencilOpState, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&depthStencilState, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&colorBlendAttachment, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&fragmentShadingRateState, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&pushConstantInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&pipelineLayoutCreateInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&graphicsPipelineCreateInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&computePipelineCreateInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&rayTracingShaderGroupCreateInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&rayTracingPipelineCreateInfo, flags); +} + PalBool graphicsABIDump(uint32_t flags) { if (!(flags & DUMP_FLAG_QUICK)) { @@ -904,5 +1226,10 @@ PalBool graphicsABIDump(uint32_t flags) return status; } + status = pipelineDump(flags); + if (status == PAL_FALSE) { + return status; + } + return PAL_TRUE; } \ No newline at end of file From 3dfda27f6b71ed896ff0a8c441e0e1f3ee04295e Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 18 Jul 2026 08:38:35 +0000 Subject: [PATCH 352/372] add graphics abi dump: descriptor --- include/pal/pal_graphics.h | 9 +- tools/abi_dump/graphics_abi_dump.c | 188 +++++++++++++++++++++++++++++ 2 files changed, 194 insertions(+), 3 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 4bc952db..92ceb5b4 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -1439,7 +1439,7 @@ typedef uint32_t PalPipelineStages; * * @since 2.0 */ -typedef uint64_t PalGraphicsBackendVtableVersion; +typedef uint32_t PalGraphicsBackendVtableVersion; /** * @typedef PalDebugCallback @@ -2600,9 +2600,10 @@ typedef struct { */ typedef struct { PalDescriptorPoolBindingSize* bindingSizes; /**< Binding sizes.*/ - uint64_t bindingSizeCount; /**< Number of bindings sizes.*/ + uint32_t bindingSizeCount; /**< Number of bindings sizes.*/ uint32_t maxDescriptorSets; /**< Maximum number of descriptor sets that can be allocated.*/ PalDescriptorIndexingFlags flags; /**< See `PalDescriptorIndexingFlags`.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalDescriptorPoolCreateInfo; /** @@ -2713,7 +2714,8 @@ typedef struct { typedef struct { PalShaderBindingTableRecordInfo* records; /**< Shader binding table records.*/ PalPipeline* rayTracingPipeline; /**< Ray tracing pipeline.*/ - uint64_t recordCount; /**< Number of shader binding table records.*/ + uint32_t recordCount; /**< Number of shader binding table records.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalShaderBindingTableCreateInfo; /** @@ -2727,6 +2729,7 @@ typedef struct { typedef struct { const void* vtable; /**< Pointer to the backend vtable.*/ PalGraphicsBackendVtableVersion version; /**< (eg. `PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1`).*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalGraphicsBackendInfo; /** diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index eb52a19d..f10b5349 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -1186,6 +1186,189 @@ static PalBool pipelineDump(uint32_t flags) return checkABI(&rayTracingPipelineCreateInfo, flags); } +static PalBool descriptorDump(uint32_t flags) +{ + // clang-format off + FieldInfo descriptorSetLayoutBindingFields[] = { + { "descriptorCount", {0, 4}, FIELD(PalDescriptorSetLayoutBinding, descriptorCount) }, + { "descriptorType", {4, 4}, FIELD(PalDescriptorSetLayoutBinding, descriptorType) } + }; + + FieldInfo descriptorPoolBindingSizeFields[] = { + { "bindingCount", {0, 4}, FIELD(PalDescriptorPoolBindingSize, bindingCount) }, + { "descriptorType", {4, 4}, FIELD(PalDescriptorPoolBindingSize, descriptorType) } + }; + + FieldInfo descriptorBufferInfoFields[] = { + { "buffer", {0, 8}, FIELD(PalDescriptorBufferInfo, buffer) }, + { "offset", {8, 8}, FIELD(PalDescriptorBufferInfo, offset) }, + { "size", {16, 8}, FIELD(PalDescriptorBufferInfo, size) }, + { "stride", {24, 8}, FIELD(PalDescriptorBufferInfo, stride) } + }; + + FieldInfo descriptorImageViewInfoFields[] = { + { "imageView", {0, 8}, FIELD(PalDescriptorImageViewInfo, imageView) } + }; + + FieldInfo descriptorSamplerInfoFields[] = { + { "sampler", {0, 8}, FIELD(PalDescriptorSamplerInfo, sampler) } + }; + + FieldInfo descriptorTLASInfoFields[] = { + { "tlas", {0, 8}, FIELD(PalDescriptorTLASInfo, tlas) } + }; + + FieldInfo descriptorSetWriteInfoFields[] = { + { "descriptorSet", {0, 8}, FIELD(PalDescriptorSetWriteInfo, descriptorSet) }, + { "bufferInfos", {8, 8}, FIELD(PalDescriptorSetWriteInfo, bufferInfos) }, + { "imageViewInfos", {16, 8}, FIELD(PalDescriptorSetWriteInfo, imageViewInfos) }, + { "samplerInfos", {24, 8}, FIELD(PalDescriptorSetWriteInfo, samplerInfos) }, + { "tlasInfos", {32, 8}, FIELD(PalDescriptorSetWriteInfo, tlasInfos) }, + { "descriptorType", {40, 4}, FIELD(PalDescriptorSetWriteInfo, descriptorType) }, + { "layoutBindingIndex", {44, 4}, FIELD(PalDescriptorSetWriteInfo, layoutBindingIndex) }, + { "arrayElement", {48, 4}, FIELD(PalDescriptorSetWriteInfo, arrayElement) }, + { "descriptorCount", {52, 4}, FIELD(PalDescriptorSetWriteInfo, descriptorCount) } + }; + + FieldInfo descriptorSetLayoutCreateInfoFields[] = { + { "bindings", {0, 8}, FIELD(PalDescriptorSetLayoutCreateInfo, bindings) }, + { "flags", {8, 4}, FIELD(PalDescriptorSetLayoutCreateInfo, flags) }, + { "bindingCount", {12, 4}, FIELD(PalDescriptorSetLayoutCreateInfo, bindingCount) } + }; + + FieldInfo descriptorPoolCreateInfoFields[] = { + { "bindingSizes", {0, 8}, FIELD(PalDescriptorPoolCreateInfo, bindingSizes) }, + { "bindingSizeCount", {8, 4}, FIELD(PalDescriptorPoolCreateInfo, bindingSizeCount) }, + { "maxDescriptorSets", {12, 4}, FIELD(PalDescriptorPoolCreateInfo, maxDescriptorSets) }, + { "flags", {16, 4}, FIELD(PalDescriptorPoolCreateInfo, flags) }, + { "reserved", {20, 4}, FIELD(PalDescriptorPoolCreateInfo, reserved) } + }; + // clang-format on + + StructInfo descriptorSetLayoutBinding = {0}; + descriptorSetLayoutBinding.name = "PalDescriptorSetLayoutBinding"; + descriptorSetLayoutBinding.fields = descriptorSetLayoutBindingFields; + descriptorSetLayoutBinding.fieldCount = ARRAY_SIZE(descriptorSetLayoutBindingFields); + descriptorSetLayoutBinding.expected.alignof = 4; + descriptorSetLayoutBinding.expected.size = 8; + descriptorSetLayoutBinding.expected.padding = 0; + descriptorSetLayoutBinding.actual = STRUCT(PalDescriptorSetLayoutBinding); + + StructInfo descriptorPoolBindingSize = {0}; + descriptorPoolBindingSize.name = "PalDescriptorPoolBindingSize"; + descriptorPoolBindingSize.fields = descriptorPoolBindingSizeFields; + descriptorPoolBindingSize.fieldCount = ARRAY_SIZE(descriptorPoolBindingSizeFields); + descriptorPoolBindingSize.expected.alignof = 4; + descriptorPoolBindingSize.expected.size = 8; + descriptorPoolBindingSize.expected.padding = 0; + descriptorPoolBindingSize.actual = STRUCT(PalDescriptorPoolBindingSize); + + StructInfo descriptorBufferInfo = {0}; + descriptorBufferInfo.name = "PalDescriptorBufferInfo"; + descriptorBufferInfo.fields = descriptorBufferInfoFields; + descriptorBufferInfo.fieldCount = ARRAY_SIZE(descriptorBufferInfoFields); + descriptorBufferInfo.expected.alignof = 8; + descriptorBufferInfo.expected.size = 32; + descriptorBufferInfo.expected.padding = 0; + descriptorBufferInfo.actual = STRUCT(PalDescriptorBufferInfo); + + StructInfo descriptorImageViewInfo = {0}; + descriptorImageViewInfo.name = "PalDescriptorImageViewInfo"; + descriptorImageViewInfo.fields = descriptorImageViewInfoFields; + descriptorImageViewInfo.fieldCount = ARRAY_SIZE(descriptorImageViewInfoFields); + descriptorImageViewInfo.expected.alignof = 8; + descriptorImageViewInfo.expected.size = 8; + descriptorImageViewInfo.expected.padding = 0; + descriptorImageViewInfo.actual = STRUCT(PalDescriptorImageViewInfo); + + StructInfo descriptorSamplerInfo = {0}; + descriptorSamplerInfo.name = "PalDescriptorSamplerInfo"; + descriptorSamplerInfo.fields = descriptorSamplerInfoFields; + descriptorSamplerInfo.fieldCount = ARRAY_SIZE(descriptorSamplerInfoFields); + descriptorSamplerInfo.expected.alignof = 8; + descriptorSamplerInfo.expected.size = 8; + descriptorSamplerInfo.expected.padding = 0; + descriptorSamplerInfo.actual = STRUCT(PalDescriptorSamplerInfo); + + StructInfo descriptorTLASInfo = {0}; + descriptorTLASInfo.name = "PalDescriptorTLASInfo"; + descriptorTLASInfo.fields = descriptorSamplerInfoFields; + descriptorTLASInfo.fieldCount = ARRAY_SIZE(descriptorSamplerInfoFields); + descriptorTLASInfo.expected.alignof = 8; + descriptorTLASInfo.expected.size = 8; + descriptorTLASInfo.expected.padding = 0; + descriptorTLASInfo.actual = STRUCT(PalDescriptorTLASInfo); + + StructInfo descriptorSetWriteInfo = {0}; + descriptorSetWriteInfo.name = "PalDescriptorSetWriteInfo"; + descriptorSetWriteInfo.fields = descriptorSetWriteInfoFields; + descriptorSetWriteInfo.fieldCount = ARRAY_SIZE(descriptorSetWriteInfoFields); + descriptorSetWriteInfo.expected.alignof = 8; + descriptorSetWriteInfo.expected.size = 56; + descriptorSetWriteInfo.expected.padding = 0; + descriptorSetWriteInfo.actual = STRUCT(PalDescriptorSetWriteInfo); + + StructInfo descriptorSetLayoutCreateInfo = {0}; + descriptorSetLayoutCreateInfo.name = "PalDescriptorSetLayoutCreateInfo"; + descriptorSetLayoutCreateInfo.fields = descriptorSetLayoutCreateInfoFields; + descriptorSetLayoutCreateInfo.fieldCount = ARRAY_SIZE(descriptorSetLayoutCreateInfoFields); + descriptorSetLayoutCreateInfo.expected.alignof = 8; + descriptorSetLayoutCreateInfo.expected.size = 16; + descriptorSetLayoutCreateInfo.expected.padding = 0; + descriptorSetLayoutCreateInfo.actual = STRUCT(PalDescriptorSetLayoutCreateInfo); + + StructInfo descriptorPoolCreateInfo = {0}; + descriptorPoolCreateInfo.name = "PalDescriptorPoolCreateInfo"; + descriptorPoolCreateInfo.fields = descriptorPoolCreateInfoFields; + descriptorPoolCreateInfo.fieldCount = ARRAY_SIZE(descriptorPoolCreateInfoFields); + descriptorPoolCreateInfo.expected.alignof = 8; + descriptorPoolCreateInfo.expected.size = 24; + descriptorPoolCreateInfo.expected.padding = 0; + descriptorPoolCreateInfo.actual = STRUCT(PalDescriptorPoolCreateInfo); + + PalBool status = checkABI(&descriptorSetLayoutBinding, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&descriptorPoolBindingSize, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&descriptorBufferInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&descriptorImageViewInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&descriptorSamplerInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&descriptorTLASInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&descriptorSetWriteInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&descriptorSetLayoutCreateInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&descriptorPoolCreateInfo, flags); +} + PalBool graphicsABIDump(uint32_t flags) { if (!(flags & DUMP_FLAG_QUICK)) { @@ -1231,5 +1414,10 @@ PalBool graphicsABIDump(uint32_t flags) return status; } + status = descriptorDump(flags); + if (status == PAL_FALSE) { + return status; + } + return PAL_TRUE; } \ No newline at end of file From 721a716408362e499b6dbe636654ee2c16610750 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 18 Jul 2026 08:51:01 +0000 Subject: [PATCH 353/372] add graphics abi dump: shader binding table --- tools/abi_dump/graphics_abi_dump.c | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index f10b5349..622cb025 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -1369,6 +1369,49 @@ static PalBool descriptorDump(uint32_t flags) return checkABI(&descriptorPoolCreateInfo, flags); } +static PalBool sbtDump(uint32_t flags) +{ + // clang-format off + FieldInfo shaderBindingTableRecordInfoFields[] = { + { "localData", {0, 8}, FIELD(PalShaderBindingTableRecordInfo, localData) }, + { "groupIndex", {8, 4}, FIELD(PalShaderBindingTableRecordInfo, groupIndex) }, + { "localDataSize", {12, 4}, FIELD(PalShaderBindingTableRecordInfo, localDataSize) } + }; + + FieldInfo shaderBindingTableCreateInfoFields[] = { + { "records", {0, 8}, FIELD(PalShaderBindingTableCreateInfo, records) }, + { "rayTracingPipeline", {8, 8}, FIELD(PalShaderBindingTableCreateInfo, rayTracingPipeline) }, + { "recordCount", {16, 4}, FIELD(PalShaderBindingTableCreateInfo, recordCount) }, + { "reserved", {20, 4}, FIELD(PalShaderBindingTableCreateInfo, reserved) } + }; + // clang-format on + + StructInfo shaderBindingTableRecordInfo = {0}; + shaderBindingTableRecordInfo.name = "PalShaderBindingTableRecordInfo"; + shaderBindingTableRecordInfo.fields = shaderBindingTableRecordInfoFields; + shaderBindingTableRecordInfo.fieldCount = ARRAY_SIZE(shaderBindingTableRecordInfoFields); + shaderBindingTableRecordInfo.expected.alignof = 8; + shaderBindingTableRecordInfo.expected.size = 16; + shaderBindingTableRecordInfo.expected.padding = 0; + shaderBindingTableRecordInfo.actual = STRUCT(PalShaderBindingTableRecordInfo); + + StructInfo shaderBindingTableCreateInfo = {0}; + shaderBindingTableCreateInfo.name = "PalShaderBindingTableCreateInfo"; + shaderBindingTableCreateInfo.fields = shaderBindingTableCreateInfoFields; + shaderBindingTableCreateInfo.fieldCount = ARRAY_SIZE(shaderBindingTableCreateInfoFields); + shaderBindingTableCreateInfo.expected.alignof = 8; + shaderBindingTableCreateInfo.expected.size = 24; + shaderBindingTableCreateInfo.expected.padding = 0; + shaderBindingTableCreateInfo.actual = STRUCT(PalShaderBindingTableCreateInfo); + + PalBool status = checkABI(&shaderBindingTableRecordInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&shaderBindingTableCreateInfo, flags); +} + PalBool graphicsABIDump(uint32_t flags) { if (!(flags & DUMP_FLAG_QUICK)) { @@ -1419,5 +1462,10 @@ PalBool graphicsABIDump(uint32_t flags) return status; } + status = sbtDump(flags); + if (status == PAL_FALSE) { + return status; + } + return PAL_TRUE; } \ No newline at end of file From fc4dd53ef01bc47a7355c377b8ec7aebcd97feec Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 18 Jul 2026 09:55:49 +0000 Subject: [PATCH 354/372] add graphics abi dump: command pool --- tools/abi_dump/graphics_abi_dump.c | 140 ++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 2 deletions(-) diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index 622cb025..715908c2 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -254,6 +254,19 @@ static PalBool deviceDump(uint32_t flags) { "supportedMemoryTypes", {24, 4}, FIELD(PalMemoryRequirements, supportedMemoryTypes) }, { "reserved", {28, 4}, FIELD(PalMemoryRequirements, reserved) } }; + + FieldInfo shaderEntryInfoFields[] = { + { "entryName", {0, 8}, FIELD(PalShaderEntryInfo, entryName) }, + { "stage", {8, 4}, FIELD(PalShaderEntryInfo, stage) }, + { "patchControlPoints", {12, 4}, FIELD(PalShaderEntryInfo, patchControlPoints) } + }; + + FieldInfo shaderCreateInfoFields[] = { + { "bytecode", {0, 8}, FIELD(PalShaderCreateInfo, bytecode) }, + { "entries", {8, 8}, FIELD(PalShaderCreateInfo, entries) }, + { "bytecodeSize", {16, 4}, FIELD(PalShaderCreateInfo, bytecodeSize) }, + { "entryCount", {20, 4}, FIELD(PalShaderCreateInfo, entryCount) } + }; // clang-format on StructInfo samplerAnisotropyCap = {0}; @@ -337,6 +350,24 @@ static PalBool deviceDump(uint32_t flags) memoryRequirement.expected.padding = 0; memoryRequirement.actual = STRUCT(PalMemoryRequirements); + StructInfo shaderEntryInfo = {0}; + shaderEntryInfo.name = "PalShaderEntryInfo"; + shaderEntryInfo.fields = shaderEntryInfoFields; + shaderEntryInfo.fieldCount = ARRAY_SIZE(shaderEntryInfoFields); + shaderEntryInfo.expected.alignof = 8; + shaderEntryInfo.expected.size = 16; + shaderEntryInfo.expected.padding = 0; + shaderEntryInfo.actual = STRUCT(PalShaderEntryInfo); + + StructInfo shaderCreateInfo = {0}; + shaderCreateInfo.name = "PalShaderCreateInfo"; + shaderCreateInfo.fields = shaderCreateInfoFields; + shaderCreateInfo.fieldCount = ARRAY_SIZE(shaderCreateInfoFields); + shaderCreateInfo.expected.alignof = 8; + shaderCreateInfo.expected.size = 24; + shaderCreateInfo.expected.padding = 0; + shaderCreateInfo.actual = STRUCT(PalShaderCreateInfo); + PalBool status = checkABI(&samplerAnisotropyCap, flags); if (status == PAL_FALSE) { return status; @@ -377,7 +408,17 @@ static PalBool deviceDump(uint32_t flags) return status; } - return checkABI(&memoryRequirement, flags); + status = checkABI(&memoryRequirement, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&shaderEntryInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&shaderCreateInfo, flags); } static PalBool swapchainDump(uint32_t flags) @@ -665,6 +706,27 @@ static PalBool bufferDump(uint32_t flags) { "usages", {8, 4}, FIELD(PalBufferCreateInfo, usages) }, { "memoryUsage", {12, 4}, FIELD(PalBufferCreateInfo, memoryUsage) } }; + + FieldInfo drawIndirectDataFields[] = { + { "vertexCount", {0, 4}, FIELD(PalDrawIndirectData, vertexCount) }, + { "instanceCount", {4, 4}, FIELD(PalDrawIndirectData, instanceCount) }, + { "firstVertex", {8, 4}, FIELD(PalDrawIndirectData, firstVertex) }, + { "firstInstance", {12, 4}, FIELD(PalDrawIndirectData, firstInstance) } + }; + + FieldInfo drawIndexedIndirectDataFields[] = { + { "indexCount", {0, 4}, FIELD(PalDrawIndexedIndirectData, indexCount) }, + { "instanceCount", {4, 4}, FIELD(PalDrawIndexedIndirectData, instanceCount) }, + { "firstIndex", {8, 4}, FIELD(PalDrawIndexedIndirectData, firstIndex) }, + { "vertexOffset", {12, 4}, FIELD(PalDrawIndexedIndirectData, vertexOffset) }, + { "firstInstance", {16, 4}, FIELD(PalDrawIndexedIndirectData, firstInstance) } + }; + + FieldInfo dispatchIndirectDataFields[] = { + { "groupCountXOrWidth", {0, 4}, FIELD(PalDispatchIndirectData, groupCountXOrWidth) }, + { "groupCountXOrHeight", {4, 4}, FIELD(PalDispatchIndirectData, groupCountXOrHeight) }, + { "groupCountXOrDepth", {8, 4}, FIELD(PalDispatchIndirectData, groupCountXOrDepth) } + }; // clang-format on StructInfo stagingRequirement = {0}; @@ -694,6 +756,33 @@ static PalBool bufferDump(uint32_t flags) bufferCreateInfo.expected.padding = 0; bufferCreateInfo.actual = STRUCT(PalBufferCreateInfo); + StructInfo drawIndirectData = {0}; + drawIndirectData.name = "PalDrawIndirectData"; + drawIndirectData.fields = drawIndirectDataFields; + drawIndirectData.fieldCount = ARRAY_SIZE(drawIndirectDataFields); + drawIndirectData.expected.alignof = 4; + drawIndirectData.expected.size = 16; + drawIndirectData.expected.padding = 0; + drawIndirectData.actual = STRUCT(PalDrawIndirectData); + + StructInfo drawIndexedIndirectData = {0}; + drawIndexedIndirectData.name = "PalDrawIndexedIndirectData"; + drawIndexedIndirectData.fields = drawIndexedIndirectDataFields; + drawIndexedIndirectData.fieldCount = ARRAY_SIZE(drawIndexedIndirectDataFields); + drawIndexedIndirectData.expected.alignof = 4; + drawIndexedIndirectData.expected.size = 20; + drawIndexedIndirectData.expected.padding = 0; + drawIndexedIndirectData.actual = STRUCT(PalDrawIndexedIndirectData); + + StructInfo dispatchIndirectData = {0}; + dispatchIndirectData.name = "PalDispatchIndirectData"; + dispatchIndirectData.fields = dispatchIndirectDataFields; + dispatchIndirectData.fieldCount = ARRAY_SIZE(dispatchIndirectDataFields); + dispatchIndirectData.expected.alignof = 4; + dispatchIndirectData.expected.size = 12; + dispatchIndirectData.expected.padding = 0; + dispatchIndirectData.actual = STRUCT(PalDispatchIndirectData); + PalBool status = checkABI(&stagingRequirement, flags); if (status == PAL_FALSE) { return status; @@ -704,7 +793,22 @@ static PalBool bufferDump(uint32_t flags) return status; } - return checkABI(&bufferCreateInfo, flags); + status = checkABI(&bufferCreateInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&drawIndirectData, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&drawIndexedIndirectData, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&dispatchIndirectData, flags); } static PalBool accelerationStructureDump(uint32_t flags) @@ -1412,6 +1516,33 @@ static PalBool sbtDump(uint32_t flags) return checkABI(&shaderBindingTableCreateInfo, flags); } +static PalBool commandPoolDump(uint32_t flags) +{ + // clang-format off + FieldInfo commandBufferSubmitInfoFields[] = { + { "waitValue", {0, 8}, FIELD(PalCommandBufferSubmitInfo, waitValue) }, + { "signalValue", {8, 8}, FIELD(PalCommandBufferSubmitInfo, signalValue) }, + { "cmdBuffer", {16, 8}, FIELD(PalCommandBufferSubmitInfo, cmdBuffer) }, + { "waitSemaphore", {24, 8}, FIELD(PalCommandBufferSubmitInfo, waitSemaphore) }, + { "signalSemaphore", {32, 8}, FIELD(PalCommandBufferSubmitInfo, signalSemaphore) }, + { "fence", {40, 8}, FIELD(PalCommandBufferSubmitInfo, fence) }, + { "waitStages", {48, 4}, FIELD(PalCommandBufferSubmitInfo, waitStages) }, + { "signalStages", {52, 4}, FIELD(PalCommandBufferSubmitInfo, signalStages) } + }; + // clang-format on + + StructInfo commandBufferSubmitInfo = {0}; + commandBufferSubmitInfo.name = "PalCommandBufferSubmitInfo"; + commandBufferSubmitInfo.fields = commandBufferSubmitInfoFields; + commandBufferSubmitInfo.fieldCount = ARRAY_SIZE(commandBufferSubmitInfoFields); + commandBufferSubmitInfo.expected.alignof = 8; + commandBufferSubmitInfo.expected.size = 56; + commandBufferSubmitInfo.expected.padding = 0; + commandBufferSubmitInfo.actual = STRUCT(PalCommandBufferSubmitInfo); + + return checkABI(&commandBufferSubmitInfo, flags); +} + PalBool graphicsABIDump(uint32_t flags) { if (!(flags & DUMP_FLAG_QUICK)) { @@ -1467,5 +1598,10 @@ PalBool graphicsABIDump(uint32_t flags) return status; } + status = commandPoolDump(flags); + if (status == PAL_FALSE) { + return status; + } + return PAL_TRUE; } \ No newline at end of file From d2f2beb94a0365437a5d8301902005f16bf5b930 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 18 Jul 2026 10:09:32 +0000 Subject: [PATCH 355/372] add graphics abi dump: debugger --- tools/abi_dump/graphics_abi_dump.c | 49 +++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index 715908c2..aed1b088 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -1553,7 +1553,54 @@ PalBool graphicsABIDump(uint32_t flags) palLog(nullptr, ""); } - PalBool status = adapterDump(flags); + // clang-format off + FieldInfo graphicsDebuggerFields[] = { + { "userData", {0, 8}, FIELD(PalGraphicsDebugger, userData) }, + { "callback", {8, 8}, FIELD(PalGraphicsDebugger, callback) }, + { "denyGeneral", {16, 4}, FIELD(PalGraphicsDebugger, denyGeneral) }, + { "denyValidation", {20, 4}, FIELD(PalGraphicsDebugger, denyValidation) }, + { "denyPerformance", {24, 4}, FIELD(PalGraphicsDebugger, denyPerformance) }, + { "denyInfoSeverity", {28, 4}, FIELD(PalGraphicsDebugger, denyInfoSeverity) }, + { "denyWarningSeverity", {32, 4}, FIELD(PalGraphicsDebugger, denyWarningSeverity) }, + { "denyErrorSeverity", {36, 4}, FIELD(PalGraphicsDebugger, denyErrorSeverity) } + }; + + FieldInfo graphicsBackendInfoFields[] = { + { "vtable", {0, 8}, FIELD(PalGraphicsBackendInfo, vtable) }, + { "version", {8, 4}, FIELD(PalGraphicsBackendInfo, version) }, + { "reserved", {12, 4}, FIELD(PalGraphicsBackendInfo, reserved) } + }; + // clang-format on + + StructInfo graphicsDebugger = {0}; + graphicsDebugger.name = "PalGraphicsDebugger"; + graphicsDebugger.fields = graphicsDebuggerFields; + graphicsDebugger.fieldCount = ARRAY_SIZE(graphicsDebuggerFields); + graphicsDebugger.expected.alignof = 8; + graphicsDebugger.expected.size = 40; + graphicsDebugger.expected.padding = 0; + graphicsDebugger.actual = STRUCT(PalGraphicsDebugger); + + StructInfo graphicsBackendInfo = {0}; + graphicsBackendInfo.name = "PalGraphicsBackendInfo"; + graphicsBackendInfo.fields = graphicsBackendInfoFields; + graphicsBackendInfo.fieldCount = ARRAY_SIZE(graphicsBackendInfoFields); + graphicsBackendInfo.expected.alignof = 8; + graphicsBackendInfo.expected.size = 16; + graphicsBackendInfo.expected.padding = 0; + graphicsBackendInfo.actual = STRUCT(PalGraphicsBackendInfo); + + PalBool status = checkABI(&graphicsDebugger, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&graphicsBackendInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = adapterDump(flags); if (status == PAL_FALSE) { return status; } From 2785ab527681763c7c75078455a4fffb7443fade Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 18 Jul 2026 12:19:54 +0000 Subject: [PATCH 356/372] add graphics abi dump: commands and remove all flag --- tools/abi_dump/abi_dump_main.c | 22 ++-- tools/abi_dump/dumps.h | 6 +- tools/abi_dump/graphics_abi_dump.c | 205 ++++++++++++++++++++++++++++- 3 files changed, 220 insertions(+), 13 deletions(-) diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index 95b58f92..cfe0c715 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -8,6 +8,7 @@ #include "dumps.h" #define VERSION "1.0" +#define LOG_NAME "PAL ABI Dump" #ifdef _WIN32 #define EXE_NAME "abi-dump.exe" @@ -24,7 +25,7 @@ static int logDumpStatus(PalBool status) ret = 0; } - palLog(nullptr, "PAL ABI Dump Status: %s", str); + palLog(nullptr, "%s %s: %s", LOG_NAME, "Status", str); return ret; } @@ -33,6 +34,8 @@ int main(int argc, char** argv) { // clang-format on PalBool status = PAL_FALSE; + PalBool dumpVersion = PAL_FALSE; + PalBool dumpHelp = PAL_FALSE; uint32_t flags = 0; uint32_t passed = 0; uint32_t dumps = 0; @@ -60,10 +63,10 @@ int main(int argc, char** argv) dumps |= DUMP_FLAG_VIDEO; } else if (strcmp(argv[i], "--version") == 0) { - dumps |= DUMP_FLAG_VERSION; + dumpVersion = PAL_TRUE; } else if (strcmp(argv[i], "--help") == 0) { - dumps |= DUMP_FLAG_HELP; + dumpHelp = PAL_TRUE; } else if (strcmp(argv[i], "--verbose") == 0) { flags &= ~DUMP_FLAG_QUICK; @@ -75,7 +78,7 @@ int main(int argc, char** argv) } } - if (dumps == 0) { + if (dumps == 0 && dumpHelp == PAL_FALSE && dumpVersion == PAL_FALSE) { dumps |= DUMP_FLAG_ALL; } @@ -170,18 +173,17 @@ int main(int argc, char** argv) } } - if (dumps & DUMP_FLAG_VERSION) { - palLog(nullptr, "PAL ABI dump %s", VERSION); + if (dumpVersion) { + palLog(nullptr, "%s %s", LOG_NAME, VERSION); } - if (dumps & DUMP_FLAG_HELP) { + if (dumpHelp) { palLog(nullptr, "USAGE: %s [options]", EXE_NAME); palLog(nullptr, "Options:"); palLog(nullptr, " --help Display available options"); palLog(nullptr, " --version Display version"); palLog(nullptr, " --verbose Display Detailed ABI dump information"); palLog(nullptr, " --quick Display only the final ABI status"); - palLog(nullptr, " --all Check ABI for all PAL structs"); palLog(nullptr, " --core Check ABI for core PAL structs"); palLog(nullptr, " --event Check ABI for event PAL structs"); palLog(nullptr, " --graphics Check ABI for graphics PAL structs"); @@ -192,6 +194,10 @@ int main(int argc, char** argv) } if (flags & DUMP_FLAG_QUICK) { + if (dumps == 0) { + return 0; + } + // check if all dumps that were executed passed if (dumps == passed) { return logDumpStatus(PAL_TRUE); diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 9a724ec5..39e0b969 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -27,10 +27,8 @@ static const char* s_PassedString = "PASSED"; #define DUMP_FLAG_GRAPHICS (1u << 4) #define DUMP_FLAG_SYSTEM (1u << 5) #define DUMP_FLAG_VIDEO (1u << 6) -#define DUMP_FLAG_VERSION (1u << 7) -#define DUMP_FLAG_HELP (1u << 8) -#define DUMP_FLAG_VERBOSE (1u << 9) -#define DUMP_FLAG_QUICK (1u << 10) +#define DUMP_FLAG_VERBOSE (1u << 7) +#define DUMP_FLAG_QUICK (1u << 8) #define DUMP_FLAG_ALL 0x7F #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index aed1b088..35b10be5 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -1543,6 +1543,209 @@ static PalBool commandPoolDump(uint32_t flags) return checkABI(&commandBufferSubmitInfo, flags); } +static PalBool commandsDump(uint32_t flags) +{ + // clang-format off + FieldInfo clearValueFields[] = { + { "color", {0, 16}, FIELD(PalClearValue, color) }, + { "depth", {16, 4}, FIELD(PalClearValue, depth) }, + { "stencil", {20, 4}, FIELD(PalClearValue, stencil) } + }; + + FieldInfo attachmentDescFields[] = { + { "imageView", {0, 8}, FIELD(PalAttachmentDesc, imageView) }, + { "resolveImageView", {8, 8}, FIELD(PalAttachmentDesc, resolveImageView) }, + { "loadOp", {16, 4}, FIELD(PalAttachmentDesc, loadOp) }, + { "storeOp", {20, 4}, FIELD(PalAttachmentDesc, storeOp) }, + { "stencilLoadOp", {24, 4}, FIELD(PalAttachmentDesc, stencilLoadOp) }, + { "stencilStoreOp", {28, 4}, FIELD(PalAttachmentDesc, stencilStoreOp) }, + { "resolveMode", {32, 4}, FIELD(PalAttachmentDesc, resolveMode) }, + { "stencilResolveMode", {36, 4}, FIELD(PalAttachmentDesc, stencilResolveMode) }, + { "clearValue", {40, 24}, FIELD(PalAttachmentDesc, clearValue) }, + }; + + FieldInfo viewportFields[] = { + { "x", {0, 4}, FIELD(PalViewport, x) }, + { "y", {4, 4}, FIELD(PalViewport, y) }, + { "width", {8, 4}, FIELD(PalViewport, width) }, + { "height", {12, 4}, FIELD(PalViewport, height) }, + { "minDepth", {16, 4}, FIELD(PalViewport, minDepth) }, + { "maxDepth", {20, 4}, FIELD(PalViewport, maxDepth) } + }; + + FieldInfo rect2DFields[] = { + { "x", {0, 4}, FIELD(PalRect2D, x) }, + { "y", {4, 4}, FIELD(PalRect2D, y) }, + { "width", {8, 4}, FIELD(PalRect2D, width) }, + { "height", {12, 4}, FIELD(PalRect2D, height) }, + }; + + FieldInfo renderingInfoFields[] = { + { "colorAttachments", {0, 8}, FIELD(PalRenderingInfo, colorAttachments) }, + { "depthStencilAttachment", {8, 8}, FIELD(PalRenderingInfo, depthStencilAttachment) }, + { "fragmentShadingRateImageView", {16, 8}, FIELD(PalRenderingInfo, fragmentShadingRateImageView) }, + { "renderArea", {24, 16}, FIELD(PalRenderingInfo, renderArea) }, + { "flags", {40, 4}, FIELD(PalRenderingInfo, flags) }, + { "fragmentShadingRateTexelWidth", {44, 4}, FIELD(PalRenderingInfo, fragmentShadingRateTexelWidth) }, + { "fragmentShadingRateTexelHeight", {48, 4}, FIELD(PalRenderingInfo, fragmentShadingRateTexelHeight) }, + { "viewCount", {52, 4}, FIELD(PalRenderingInfo, viewCount) }, + { "arrayLayerCount", {56, 4}, FIELD(PalRenderingInfo, arrayLayerCount) }, + { "colorAttachentCount", {60, 4}, FIELD(PalRenderingInfo, colorAttachentCount) } + }; + + FieldInfo renderingLayoutInfoFields[] = { + { "colorAttachmentsFormat", {0, 8}, FIELD(PalRenderingLayoutInfo, colorAttachmentsFormat) }, + { "colorAttachentCount", {8, 4}, FIELD(PalRenderingLayoutInfo, colorAttachentCount) }, + { "viewCount", {12, 4}, FIELD(PalRenderingLayoutInfo, viewCount) }, + { "sampleCount", {16, 4}, FIELD(PalRenderingLayoutInfo, sampleCount) }, + { "flags", {20, 4}, FIELD(PalRenderingLayoutInfo, flags) }, + { "depthStencilAttachmentFormat", {24, 4}, FIELD(PalRenderingLayoutInfo, depthStencilAttachmentFormat) }, + { "fragmentShadingRateAttachmentFormat", {28, 4}, FIELD(PalRenderingLayoutInfo, fragmentShadingRateAttachmentFormat) } + }; + + FieldInfo workGroupBuildDataFields[] = { + { "workCount", {0, 12}, FIELD(PalWorkGroupBuildData, workCount) }, + { "workGroupSize", {12, 12}, FIELD(PalWorkGroupBuildData, workGroupSize) }, + { "workGroupCount", {24, 12}, FIELD(PalWorkGroupBuildData, workGroupCount) } + }; + + FieldInfo workGroupInfoFields[] = { + { "workGroupBase", {0, 12}, FIELD(PalWorkGroupInfo, workGroupBase) }, + { "workGroupCount", {12, 12}, FIELD(PalWorkGroupInfo, workGroupCount) } + }; + + FieldInfo barrierInfoFields[] = { + { "oldState", {0, 4}, FIELD(PalBarrierInfo, oldState) }, + { "newState", {4, 4}, FIELD(PalBarrierInfo, newState) }, + { "srcStages", {8, 4}, FIELD(PalBarrierInfo, srcStages) }, + { "dstStages", {12, 4}, FIELD(PalBarrierInfo, dstStages) } + }; + // clang-format on + + StructInfo clearValue = {0}; + clearValue.name = "PalClearValue"; + clearValue.fields = clearValueFields; + clearValue.fieldCount = ARRAY_SIZE(clearValueFields); + clearValue.expected.alignof = 4; + clearValue.expected.size = 24; + clearValue.expected.padding = 0; + clearValue.actual = STRUCT(PalClearValue); + + StructInfo attachmentDesc = {0}; + attachmentDesc.name = "PalAttachmentDesc"; + attachmentDesc.fields = attachmentDescFields; + attachmentDesc.fieldCount = ARRAY_SIZE(attachmentDescFields); + attachmentDesc.expected.alignof = 8; + attachmentDesc.expected.size = 64; + attachmentDesc.expected.padding = 0; + attachmentDesc.actual = STRUCT(PalAttachmentDesc); + + StructInfo viewport = {0}; + viewport.name = "PalViewport"; + viewport.fields = viewportFields; + viewport.fieldCount = ARRAY_SIZE(viewportFields); + viewport.expected.alignof = 4; + viewport.expected.size = 24; + viewport.expected.padding = 0; + viewport.actual = STRUCT(PalViewport); + + StructInfo rect2D = {0}; + rect2D.name = "PalRect2D"; + rect2D.fields = rect2DFields; + rect2D.fieldCount = ARRAY_SIZE(rect2DFields); + rect2D.expected.alignof = 4; + rect2D.expected.size = 16; + rect2D.expected.padding = 0; + rect2D.actual = STRUCT(PalRect2D); + + StructInfo renderingInfo = {0}; + renderingInfo.name = "PalRenderingInfo"; + renderingInfo.fields = renderingInfoFields; + renderingInfo.fieldCount = ARRAY_SIZE(renderingInfoFields); + renderingInfo.expected.alignof = 8; + renderingInfo.expected.size = 64; + renderingInfo.expected.padding = 0; + renderingInfo.actual = STRUCT(PalRenderingInfo); + + StructInfo renderingLayoutInfo = {0}; + renderingLayoutInfo.name = "PalRenderingLayoutInfo"; + renderingLayoutInfo.fields = renderingLayoutInfoFields; + renderingLayoutInfo.fieldCount = ARRAY_SIZE(renderingLayoutInfoFields); + renderingLayoutInfo.expected.alignof = 8; + renderingLayoutInfo.expected.size = 32; + renderingLayoutInfo.expected.padding = 0; + renderingLayoutInfo.actual = STRUCT(PalRenderingLayoutInfo); + + StructInfo workGroupBuildData = {0}; + workGroupBuildData.name = "PalWorkGroupBuildData"; + workGroupBuildData.fields = workGroupBuildDataFields; + workGroupBuildData.fieldCount = ARRAY_SIZE(workGroupBuildDataFields); + workGroupBuildData.expected.alignof = 4; + workGroupBuildData.expected.size = 36; + workGroupBuildData.expected.padding = 0; + workGroupBuildData.actual = STRUCT(PalWorkGroupBuildData); + + StructInfo workGroupInfo = {0}; + workGroupInfo.name = "PalWorkGroupInfo"; + workGroupInfo.fields = workGroupInfoFields; + workGroupInfo.fieldCount = ARRAY_SIZE(workGroupInfoFields); + workGroupInfo.expected.alignof = 4; + workGroupInfo.expected.size = 24; + workGroupInfo.expected.padding = 0; + workGroupInfo.actual = STRUCT(PalWorkGroupInfo); + + StructInfo barrierInfo = {0}; + barrierInfo.name = "PalBarrierInfo"; + barrierInfo.fields = barrierInfoFields; + barrierInfo.fieldCount = ARRAY_SIZE(barrierInfoFields); + barrierInfo.expected.alignof = 4; + barrierInfo.expected.size = 16; + barrierInfo.expected.padding = 0; + barrierInfo.actual = STRUCT(PalBarrierInfo); + + PalBool status = checkABI(&clearValue, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&attachmentDesc, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&viewport, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&rect2D, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&renderingInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&renderingLayoutInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&workGroupBuildData, flags); + if (status == PAL_FALSE) { + return status; + } + + status = checkABI(&workGroupInfo, flags); + if (status == PAL_FALSE) { + return status; + } + + return checkABI(&barrierInfo, flags); +} + PalBool graphicsABIDump(uint32_t flags) { if (!(flags & DUMP_FLAG_QUICK)) { @@ -1650,5 +1853,5 @@ PalBool graphicsABIDump(uint32_t flags) return status; } - return PAL_TRUE; + return commandsDump(flags); } \ No newline at end of file From d181c1125d8d800b460a7fc521a50d3324d483ce Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 18 Jul 2026 13:11:34 +0000 Subject: [PATCH 357/372] start custom backend test --- include/pal/pal_graphics.h | 104 +++++++++++++++++++++++-- pal_config.lua | 4 +- src/graphics/d3d12/pal_adapter_d3d12.c | 15 +++- tests/graphics/custom_backend_test.c | 17 ++++ tests/graphics/graphics_test.c | 6 +- tests/tests.h | 1 + tests/tests.lua | 3 +- tools/abi_dump/graphics_abi_dump.c | 19 ++--- 8 files changed, 146 insertions(+), 23 deletions(-) create mode 100644 tests/graphics/custom_backend_test.c diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 92ceb5b4..dad1bd00 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -560,6 +560,95 @@ #define PAL_PIPELINE_STAGE_INDIRECT_INPUT (1U << 18) #define PAL_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD (1U << 19) +/** + * Required implementations: + * - palUnpackUint32() + * - palUnpackPointer() + * - enumerateAdapters + * - getAdapterInfo + * - getAdapterCapabilities + * - getAdapterFeatures + * - getHighestSupportedShaderTarget + * - createDevice + * - destroyDevice + * - allocateMemory + * - freeMemory + * - createQueue + * - destroyQueue + * - waitQueue + * - canQueuePresent + * - enumerateFormats + * - isFormatSupported + * - queryFormatImageUsages + * - queryFormatSampleCount + * - createImage + * - destroyImage + * - getImageInfo + * - getImageMemoryRequirements + * - bindImageMemory + * - createImageView + * - destroyImageView + * - createSampler + * - destroySampler + * - createShader + * - destroyShader + * - createFence + * - destroyFence + * - waitFence + * - isFenceSignaled + * - createSemaphore + * - destroySemaphore + * - createCommandPool + * - destroyCommandPool + * - allocateCommandBuffer + * - freeCommandBuffer + * - submitCommandBuffer + * - cmdBegin + * - cmdEnd + * - resetCommandBuffer + * - cmdExecuteCommandBuffer + * - cmdBeginRendering + * - cmdEndRendering + * - cmdCopyBuffer + * - cmdCopyBufferToImage + * - cmdCopyImage + * - cmdCopyImageToBuffer + * - cmdBindPipeline + * - cmdSetViewport + * - cmdSetScissors + * - cmdBindVertexBuffers + * - cmdBindIndexBuffer + * - cmdDraw + * - cmdDrawIndexed + * - cmdImageBarrier + * - cmdBufferBarrier + * - cmdDispatch + * - cmdBindDescriptorSet + * - cmdPushConstants + * - createBuffer + * - destroyBuffer + * - getBufferMemoryRequirements + * - computeInstanceStagingSize + * - computeImageStagingRequirements + * - writeInstanceStaging + * - writeImageStaging + * - bindBufferMemory + * - mapBuffer + * - unmapBuffer + * - createDescriptorSetLayout + * - destroyDescriptorSetLayout + * - createDescriptorPool + * - destroyDescriptorPool + * - resetDescriptorPool + * - allocateDescriptorSet + * - updateDescriptorSet + * - createPipelineLayout + * - destroyPipelineLayout + * - createGraphicsPipeline + * - createComputePipeline + * - createRayTracingPipeline + * - destroyPipeline + */ #define PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1 0 /** @@ -1470,14 +1559,15 @@ typedef void(PAL_CALL* PalDebugCallback)( typedef struct { uint64_t vram; /**< Total video memory in bytes*/ uint64_t sharedMemory; /**< Total shared memory in bytes*/ + uint64_t driverVersion; /**< Adapter version.*/ uint32_t vendorId; /**< Adapter vendor id.*/ uint32_t deviceId; /**< Adapter device id.*/ - uint32_t driverVersion; /**< Adapter version.*/ PalShaderFormats shaderFormats; /**< (eg. `PAL_SHADER_FORMAT_SPIRV`)*/ PalAdapterType type; /**< (eg. `PAL_ADAPTER_TYPE_DISCRETE`).*/ PalAdapterApiType apiType; /**< (eg. `PAL_ADAPTER_API_TYPE_VULKAN`).*/ char name[PAL_ADAPTER_NAME_SIZE]; /**< Adapter name.*/ char backendName[PAL_ADAPTER_BACKEND_NAME_SIZE]; /**< Adapter backend name.*/ + uint32_t reserved; /**< 0 for now.*/ } PalAdapterInfo; /** @@ -2720,9 +2810,16 @@ typedef struct { /** * @struct PalGraphicsBackendRegistrationInfo - * @brief Registration info of a graphics backend. + * @brief Custom graphics backend information. * * Uninitialized fields may result in undefined behavior. + * + * All backend handle implementation (eg. struct CustomBuffer) must reserve its first field as + * a `void*`. This will be used by the graphics layer. + * + * Each backend Vtable version (eg. `PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1`) has required functions + * that must be present implemented. This will be validated at initialization. See version constant + * for the required functions. Optional functions have their own requirements. * * @since 2.0 */ @@ -2738,9 +2835,6 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * All backend handle implementation (eg. struct CustomBuffer) must reserve its first field as - * a `void*`. This will be used by the graphics layer. - * * @since 2.0 */ typedef struct { diff --git a/pal_config.lua b/pal_config.lua index d434cfa8..821efe2d 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -3,7 +3,7 @@ PAL_BUILD_STATIC_LIBRARY = false -- build PAL tests as a single application -PAL_BUILD_TEST_APPLICATION = false +PAL_BUILD_TEST_APPLICATION = true -- build PAL abi dump PAL_BUILD_ABI_DUMP = true @@ -21,4 +21,4 @@ PAL_BUILD_VIDEO_MODULE = false PAL_BUILD_OPENGL_MODULE = false -- build graphics module -PAL_BUILD_GRAPHICS_MODULE = false +PAL_BUILD_GRAPHICS_MODULE = true diff --git a/src/graphics/d3d12/pal_adapter_d3d12.c b/src/graphics/d3d12/pal_adapter_d3d12.c index c99f4574..ac68dde7 100644 --- a/src/graphics/d3d12/pal_adapter_d3d12.c +++ b/src/graphics/d3d12/pal_adapter_d3d12.c @@ -146,14 +146,23 @@ void PAL_CALL getAdapterInfoD3D12( info->shaderFormats |= PAL_SHADER_FORMAT_DXIL; } + LARGE_INTEGER driverVersion = {0}; + info->driverVersion = 0; + result = d3d12Adapter->handle->lpVtbl->CheckInterfaceSupport( + d3d12Adapter->handle, + &IID_Adapter, + &driverVersion); + + if (SUCCEEDED(result)) { + info->driverVersion = (uint64_t)driverVersion.QuadPart; + } + info->vendorId = desc.VendorId; - info->deviceId= desc.DeviceId; + info->deviceId = desc.DeviceId; info->apiType = PAL_ADAPTER_API_TYPE_D3D12; info->sharedMemory = desc.SharedSystemMemory; strcpy(info->backendName, "PAL"); - // TODO: add driver version - WideCharToMultiByte( CP_UTF8, 0, diff --git a/tests/graphics/custom_backend_test.c b/tests/graphics/custom_backend_test.c new file mode 100644 index 00000000..8feb4a7e --- /dev/null +++ b/tests/graphics/custom_backend_test.c @@ -0,0 +1,17 @@ + +#include "pal/pal_graphics.h" +#include "tests.h" + +static void PAL_CALL onGraphicsDebug( + void* userData, + PalDebugMessageSeverity severity, + PalDebugMessageType type, + const char* msg) +{ + palLog(nullptr, msg); +} + +PalBool customBackendTest() +{ + return PAL_TRUE; +} \ No newline at end of file diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 9250280c..7607090e 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -89,11 +89,11 @@ PalBool graphicsTest() palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Backend Name: %s", info.backendName); - palLog(nullptr, " Vendor Id: %u", info.vendorId); - palLog(nullptr, " Device Id: %u", info.deviceId); - palLog(nullptr, " Driver Version: %u", info.driverVersion); + palLog(nullptr, " Driver Version: %llu", info.driverVersion); palLog(nullptr, " Vram %u MB", vramMb); palLog(nullptr, " Shared Memory %u MB", sharedMemMb); + palLog(nullptr, " Device Id: %u", info.deviceId); + palLog(nullptr, " Vendor Id: %u", info.vendorId); const char* typeString; switch (info.type) { diff --git a/tests/tests.h b/tests/tests.h index 7ea10268..7ea250a1 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -91,6 +91,7 @@ PalBool graphicsTest(); PalBool computeTest(); PalBool rayTracingTest(); PalBool multiDescriptorSetTest(); +PalBool customBackendTest(); // graphics and video PalBool clearColorTest(); diff --git a/tests/tests.lua b/tests/tests.lua index 2f011832..53917dc0 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -72,7 +72,8 @@ project "tests" "graphics/graphics_test.c", "graphics/compute_test.c", "graphics/ray_tracing_test.c", - "graphics/multi_descriptor_set_test.c" + "graphics/multi_descriptor_set_test.c", + "graphics/custom_backend_test.c" } end diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index 35b10be5..ce10e0bb 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -14,14 +14,15 @@ static PalBool adapterDump(uint32_t flags) FieldInfo adapterInfoFields[] = { { "vram", {0, 8}, FIELD(PalAdapterInfo, vram) }, { "sharedMemory", {8, 8}, FIELD(PalAdapterInfo, sharedMemory) }, - { "vendorId", {16, 4}, FIELD(PalAdapterInfo, vendorId) }, - { "deviceId", {20, 4}, FIELD(PalAdapterInfo, deviceId) }, - { "driverVersion", {24, 4}, FIELD(PalAdapterInfo, driverVersion) }, - { "shaderFormats", {28, 4}, FIELD(PalAdapterInfo, shaderFormats) }, - { "type", {32, 4}, FIELD(PalAdapterInfo, type) }, - { "apiType", {36, 4}, FIELD(PalAdapterInfo, apiType) }, - { "name", {40, 128}, FIELD(PalAdapterInfo, name) }, - { "backendName", {168, 32}, FIELD(PalAdapterInfo, backendName) } + { "driverVersion", {16, 8}, FIELD(PalAdapterInfo, driverVersion) }, + { "vendorId", {24, 4}, FIELD(PalAdapterInfo, vendorId) }, + { "deviceId", {28, 4}, FIELD(PalAdapterInfo, deviceId) }, + { "shaderFormats", {32, 4}, FIELD(PalAdapterInfo, shaderFormats) }, + { "type", {36, 4}, FIELD(PalAdapterInfo, type) }, + { "apiType", {40, 4}, FIELD(PalAdapterInfo, apiType) }, + { "name", {44, 128}, FIELD(PalAdapterInfo, name) }, + { "backendName", {172, 32}, FIELD(PalAdapterInfo, backendName) }, + { "reserved", {204, 4}, FIELD(PalAdapterInfo, reserved) } }; FieldInfo imageCapFields[] = { @@ -90,7 +91,7 @@ static PalBool adapterDump(uint32_t flags) adapterInfo.fields = adapterInfoFields; adapterInfo.fieldCount = ARRAY_SIZE(adapterInfoFields); adapterInfo.expected.alignof = 8; - adapterInfo.expected.size = 200; + adapterInfo.expected.size = 208; adapterInfo.expected.padding = 0; adapterInfo.actual = STRUCT(PalAdapterInfo); From 27dd61af64f4e707d2fd483c57e77dfd86bff132 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 18 Jul 2026 16:05:47 +0000 Subject: [PATCH 358/372] custom backend test: add function pointers --- include/pal/pal_graphics.h | 19 +- src/graphics/pal_graphics.c | 5 +- tests/graphics/custom_backend_test.c | 699 +++++++++++++++++++++++++++ 3 files changed, 711 insertions(+), 12 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index dad1bd00..e0ef8097 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -562,8 +562,6 @@ /** * Required implementations: - * - palUnpackUint32() - * - palUnpackPointer() * - enumerateAdapters * - getAdapterInfo * - getAdapterCapabilities @@ -603,9 +601,9 @@ * - allocateCommandBuffer * - freeCommandBuffer * - submitCommandBuffer + * - resetCommandBuffer * - cmdBegin * - cmdEnd - * - resetCommandBuffer * - cmdExecuteCommandBuffer * - cmdBeginRendering * - cmdEndRendering @@ -628,9 +626,7 @@ * - createBuffer * - destroyBuffer * - getBufferMemoryRequirements - * - computeInstanceStagingSize * - computeImageStagingRequirements - * - writeInstanceStaging * - writeImageStaging * - bindBufferMemory * - mapBuffer @@ -646,7 +642,6 @@ * - destroyPipelineLayout * - createGraphicsPipeline * - createComputePipeline - * - createRayTracingPipeline * - destroyPipeline */ #define PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1 0 @@ -6500,8 +6495,13 @@ PAL_API void PAL_CALL palGetBufferMemoryRequirements( /** * @brief Compute size for an acceleration structure instance buffer. * - * The graphics system must be initialized before this call. This does not allocate memory - * for the buffer. This function must is required for all acceleration structure instance buffers. + * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. + * Otherwise behavior is undefined. + * + * This does not allocate memory for the buffer. This function must is required for all + * acceleration structure instance buffers. * * @param[in] device The device to use. * @param[in] instanceCount Number of instances the instance buffer will hold. @@ -6548,6 +6548,9 @@ PAL_API void PAL_CALL palComputeImageStagingRequirements( * @brief Write data to an instance staging buffer. * * The graphics system must be initialized before this call. + * + * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. + * Otherwise behavior is undefined. * * @param[in] device The device to use. * @param[in] instanceCount Number of instances. diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index a0110d67..a7ae1a89 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -118,12 +118,12 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) !vtable1->destroyCommandPool || !vtable1->allocateCommandBuffer || !vtable1->freeCommandBuffer || + !vtable1->resetCommandBuffer || !vtable1->submitCommandBuffer || // command recording !vtable1->cmdBegin || !vtable1->cmdEnd || - !vtable1->resetCommandBuffer || !vtable1->cmdExecuteCommandBuffer || !vtable1->cmdBeginRendering || !vtable1->cmdEndRendering || @@ -148,9 +148,7 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) !vtable1->createBuffer || !vtable1->destroyBuffer || !vtable1->getBufferMemoryRequirements || - !vtable1->computeInstanceStagingSize || !vtable1->computeImageStagingRequirements || - !vtable1->writeInstanceStaging || !vtable1->writeImageStaging || !vtable1->bindBufferMemory || !vtable1->mapBuffer || @@ -172,7 +170,6 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) // pipeline !vtable1->createGraphicsPipeline || !vtable1->createComputePipeline || - !vtable1->createRayTracingPipeline || !vtable1->destroyPipeline) { return PAL_FALSE; } diff --git a/tests/graphics/custom_backend_test.c b/tests/graphics/custom_backend_test.c index 8feb4a7e..a9f10f16 100644 --- a/tests/graphics/custom_backend_test.c +++ b/tests/graphics/custom_backend_test.c @@ -2,6 +2,606 @@ #include "pal/pal_graphics.h" #include "tests.h" +static PalResult PAL_CALL enumerateAdapters( + uint32_t*, + PalAdapter**) +{ + +} + +static void PAL_CALL getAdapterInfo( + PalAdapter*, + PalAdapterInfo*) +{ + +} + +static void PAL_CALL getAdapterCapabilities( + PalAdapter*, + PalAdapterCapabilities*) +{ + +} + +static PalAdapterFeatures PAL_CALL getAdapterFeatures(PalAdapter*) +{ + +} + +static uint32_t PAL_CALL getHighestSupportedShaderTarget( + PalAdapter*, + PalShaderFormats) +{ + +} + +static PalResult PAL_CALL createDevice( + PalAdapter*, + PalAdapterFeatures, + PalDevice**) +{ + +} + +static void PAL_CALL destroyDevice(PalDevice*) +{ + +} + +static PalResult PAL_CALL waitDevice(PalDevice*) +{ + +} + +static PalResult PAL_CALL allocateMemory( + PalDevice*, + PalMemoryType, + uint64_t, + uint64_t, + PalMemory**) +{ + +} + +static void PAL_CALL freeMemory(PalMemory*) +{ + +} + +static void PAL_CALL querySamplerAnisotropyCapabilities( + PalDevice*, + PalSamplerAnisotropyCapabilities*) +{ + +} + +static PalResult PAL_CALL createQueue( + PalDevice*, + PalQueueType, + PalQueue**) +{ + +} + +static void PAL_CALL destroyQueue(PalQueue*) +{ + +} + +static PalResult PAL_CALL waitQueue(PalQueue*) +{ + +} + +static PalBool PAL_CALL canQueuePresent( + PalQueue*, + PalSurface*) +{ + +} + +static void PAL_CALL enumerateFormats( + PalAdapter*, + uint32_t*, + PalFormatInfo*) +{ + +} + +static PalBool PAL_CALL isFormatSupported( + PalAdapter*, + PalFormat) +{ + +} + +static PalImageUsages PAL_CALL queryFormatImageUsages( + PalAdapter*, + PalFormat) +{ + +} + +static PalSampleCount PAL_CALL queryFormatSampleCount( + PalAdapter*, + PalFormat) +{ + +} + +static PalResult PAL_CALL createImage( + PalDevice*, + const PalImageCreateInfo*, + PalImage**) +{ + +} + +static void PAL_CALL destroyImage(PalImage*) +{ + +} + +static void PAL_CALL getImageInfo( + PalImage*, + PalImageInfo*) +{ + +} + +static void PAL_CALL getImageMemoryRequirements( + PalImage*, + PalMemoryRequirements*) +{ + +} + +static PalResult PAL_CALL bindImageMemory( + PalImage*, + PalMemory*, + uint64_t) +{ + +} + +static PalResult PAL_CALL createImageView( + PalDevice*, + PalImage*, + const PalImageViewCreateInfo*, + PalImageView**) +{ + +} + +static void PAL_CALL destroyImageView(PalImageView*) +{ + +} + +static PalResult PAL_CALL createSampler( + PalDevice*, + const PalSamplerCreateInfo*, + PalSampler**) +{ + +} + +static void PAL_CALL destroySampler(PalSampler*) +{ + +} + +static PalResult PAL_CALL createShader( + PalDevice*, + const PalShaderCreateInfo*, + PalShader**) +{ + +} + +static void PAL_CALL destroyShader(PalShader*) +{ + +} + +static PalResult PAL_CALL createFence( + PalDevice*, + PalBool, + PalFence**) +{ + +} + +static void PAL_CALL destroyFence(PalFence*) +{ + +} + +static PalResult PAL_CALL waitFence( + PalFence*, + uint64_t) +{ + +} + +static PalResult PAL_CALL resetFence(PalFence*) +{ + +} + +static PalBool PAL_CALL isFenceSignaled(PalFence*) +{ + +} + +static PalResult PAL_CALL createSemaphore( + PalDevice*, + PalBool, + PalSemaphore**) +{ + +} + +static void PAL_CALL destroySemaphore(PalSemaphore*) +{ + +} + +static PalResult PAL_CALL createCommandPool( + PalDevice*, + PalQueue*, + PalCommandPool**) +{ + +} + +static void PAL_CALL destroyCommandPool(PalCommandPool*) +{ + +} + +static PalResult PAL_CALL allocateCommandBuffer( + PalDevice*, + PalCommandPool*, + PalCommandBufferType, + PalCommandBuffer**) +{ + +} + +static void PAL_CALL freeCommandBuffer(PalCommandBuffer*) +{ + +} + +static PalResult PAL_CALL resetCommandBuffer(PalCommandBuffer*) +{ + +} + +static PalResult PAL_CALL submitCommandBuffer( + PalQueue*, + PalCommandBufferSubmitInfo*) +{ + +} + +static PalResult PAL_CALL cmdBegin( + PalCommandBuffer*, + PalRenderingLayoutInfo*) +{ + +} + +static PalResult PAL_CALL cmdEnd(PalCommandBuffer*) +{ + +} + +static void PAL_CALL cmdExecuteCommandBuffer( + PalCommandBuffer*, + PalCommandBuffer*) +{ + +} + +static void PAL_CALL cmdBeginRendering( + PalCommandBuffer*, + PalRenderingInfo*) +{ + +} + +static void PAL_CALL cmdEndRendering(PalCommandBuffer*) +{ + +} + +static void PAL_CALL cmdCopyBuffer( + PalCommandBuffer*, + PalBuffer*, + PalBuffer*, + PalBufferCopyInfo*) +{ + +} + +static void PAL_CALL cmdCopyBufferToImage( + PalCommandBuffer*, + PalImage*, + PalBuffer*, + PalBufferImageCopyInfo*) +{ + +} + +static void PAL_CALL cmdCopyImage( + PalCommandBuffer*, + PalImage*, + PalImage*, + PalImageCopyInfo*) +{ + +} + +static void PAL_CALL cmdCopyImageToBuffer( + PalCommandBuffer*, + PalBuffer*, + PalImage*, + PalBufferImageCopyInfo*) +{ + +} + +static void PAL_CALL cmdBindPipeline( + PalCommandBuffer*, + PalPipeline*) +{ + +} + +static void PAL_CALL cmdSetViewport( + PalCommandBuffer*, + uint32_t, + PalViewport*) +{ + +} + +static void PAL_CALL cmdSetScissors( + PalCommandBuffer*, + uint32_t, + PalRect2D*) +{ + +} + +static void PAL_CALL cmdBindVertexBuffers( + PalCommandBuffer*, + uint32_t, + uint32_t, + PalBuffer**, + uint64_t*) +{ + +} + +static void PAL_CALL cmdBindIndexBuffer( + PalCommandBuffer*, + PalBuffer*, + uint64_t, + PalIndexType) +{ + +} + +static void PAL_CALL cmdDraw( + PalCommandBuffer*, + uint32_t, + uint32_t, + uint32_t, + uint32_t) +{ + +} + +static void PAL_CALL cmdDrawIndexed( + PalCommandBuffer*, + uint32_t, + uint32_t, + uint32_t, + int32_t, + uint32_t) +{ + +} + +static void PAL_CALL cmdImageBarrier( + PalCommandBuffer*, + PalImage*, + PalImageSubresourceRange*, + PalBarrierInfo*) +{ + +} + +static void PAL_CALL cmdBufferBarrier( + PalCommandBuffer*, + PalBuffer*, + PalBarrierInfo*) +{ + +} + +static void PAL_CALL cmdDispatch( + PalCommandBuffer*, + uint32_t, + uint32_t, + uint32_t) +{ + +} + +static void PAL_CALL cmdBindDescriptorSet( + PalCommandBuffer*, + uint32_t, + PalDescriptorSet*) +{ + +} + +static void PAL_CALL cmdPushConstants( + PalCommandBuffer*, + uint32_t, + uint32_t, + const void*) +{ + +} + +static PalResult PAL_CALL createBuffer( + PalDevice*, + const PalBufferCreateInfo*, + PalBuffer**) +{ + +} + +static void PAL_CALL destroyBuffer(PalBuffer*) +{ + +} + +static void PAL_CALL getBufferMemoryRequirements( + PalBuffer*, + PalMemoryRequirements*) +{ + +} + +static void PAL_CALL computeImageStagingRequirements( + PalDevice*, + PalFormat, + const PalBufferImageCopyInfo*, + PalImageStagingRequirements*) +{ + +} + +static void PAL_CALL writeImageStaging( + PalDevice*, + PalFormat, + PalBufferImageCopyInfo*, + void*, + void*) +{ + +} + +static PalResult PAL_CALL bindBufferMemory( + PalBuffer*, + PalMemory*, + uint64_t) +{ + +} + +static PalResult PAL_CALL mapBuffer( + PalBuffer*, + uint64_t, + uint64_t, + void**) +{ + +} + +static void PAL_CALL unmapBuffer(PalBuffer*) +{ + +} + +static PalResult PAL_CALL createDescriptorSetLayout( + PalDevice*, + const PalDescriptorSetLayoutCreateInfo*, + PalDescriptorSetLayout**) +{ + +} + +static void PAL_CALL destroyDescriptorSetLayout(PalDescriptorSetLayout*) +{ + +} + +static PalResult PAL_CALL createDescriptorPool( + PalDevice*, + const PalDescriptorPoolCreateInfo*, + PalDescriptorPool**) +{ + +} + +static void PAL_CALL destroyDescriptorPool(PalDescriptorPool*) +{ + +} + +static PalResult PAL_CALL resetDescriptorPool(PalDescriptorPool*) +{ + +} + +static PalResult PAL_CALL allocateDescriptorSet( + PalDevice*, + PalDescriptorPool*, + PalDescriptorSetLayout*, + PalDescriptorSet**) +{ + +} + +static PalResult PAL_CALL updateDescriptorSet( + PalDevice*, + uint32_t, + PalDescriptorSetWriteInfo*) +{ + +} + +static PalResult PAL_CALL createPipelineLayout( + PalDevice*, + const PalPipelineLayoutCreateInfo*, + PalPipelineLayout**) +{ + +} + +static void PAL_CALL destroyPipelineLayout(PalPipelineLayout*) +{ + +} + +static PalResult PAL_CALL createGraphicsPipeline( + PalDevice*, + const PalGraphicsPipelineCreateInfo*, + PalPipeline**) +{ + +} + +static PalResult PAL_CALL createComputePipeline( + PalDevice*, + const PalComputePipelineCreateInfo*, + PalPipeline**) +{ + +} + +static void PAL_CALL destroyPipeline(PalPipeline*) +{ + +} + static void PAL_CALL onGraphicsDebug( void* userData, PalDebugMessageSeverity severity, @@ -13,5 +613,104 @@ static void PAL_CALL onGraphicsDebug( PalBool customBackendTest() { + // build the vtable + PalGraphicsBackendVtable1 vtable = {0}; + vtable.enumerateAdapters = enumerateAdapters, + vtable.getAdapterInfo = getAdapterInfo, + vtable.getAdapterCapabilities = getAdapterCapabilities, + vtable.getAdapterFeatures = getAdapterFeatures, + vtable.getHighestSupportedShaderTarget = getHighestSupportedShaderTarget, + vtable.createDevice = createDevice, + vtable.destroyDevice = destroyDevice, + vtable.allocateMemory = allocateMemory, + vtable.freeMemory = freeMemory, + vtable.querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilities, + vtable.createQueue = createQueue, + vtable.destroyQueue = destroyQueue, + vtable.waitQueue = waitQueue, + vtable.canQueuePresent = canQueuePresent, + vtable.enumerateFormats = enumerateFormats, + vtable.isFormatSupported = isFormatSupported, + vtable.queryFormatImageUsages = queryFormatImageUsages, + vtable.queryFormatSampleCount = queryFormatSampleCount, + vtable.createImage = createImage, + vtable.destroyImage = destroyImage, + vtable.getImageInfo = getImageInfo, + vtable.getImageMemoryRequirements = getImageMemoryRequirements, + vtable.bindImageMemory = bindImageMemory, + vtable.createImageView = createImageView, + vtable.destroyImageView = destroyImageView, + vtable.createSampler = createSampler, + vtable.destroySampler = destroySampler, + vtable.createShader = createShader, + vtable.destroyShader = destroyShader, + vtable.createFence = createFence, + vtable.destroyFence = destroyFence, + vtable.waitFence = waitFence, + vtable.resetFence = resetFence, + vtable.isFenceSignaled = isFenceSignaled, + vtable.createSemaphore = createSemaphore, + vtable.destroySemaphore = destroySemaphore, + vtable.createCommandPool = createCommandPool, + vtable.destroyCommandPool = destroyCommandPool, + vtable.allocateCommandBuffer = allocateCommandBuffer, + vtable.freeCommandBuffer = freeCommandBuffer, + vtable.resetCommandBuffer = resetCommandBuffer, + vtable.submitCommandBuffer = submitCommandBuffer, + vtable.cmdBegin = cmdBegin, + vtable.cmdEnd = cmdEnd, + vtable.cmdExecuteCommandBuffer = cmdExecuteCommandBuffer, + vtable.cmdBeginRendering = cmdBeginRendering, + vtable.cmdEndRendering = cmdEndRendering, + vtable.cmdCopyBuffer = cmdCopyBuffer, + vtable.cmdCopyBufferToImage = cmdCopyBufferToImage, + vtable.cmdCopyImage = cmdCopyImage, + vtable.cmdCopyImageToBuffer = cmdCopyImageToBuffer, + vtable.cmdBindPipeline = cmdBindPipeline, + vtable.cmdSetViewport = cmdSetViewport, + vtable.cmdSetScissors = cmdSetScissors, + vtable.cmdBindVertexBuffers = cmdBindVertexBuffers, + vtable.cmdBindIndexBuffer = cmdBindIndexBuffer, + vtable.cmdDraw = cmdDraw, + vtable.cmdDrawIndexed = cmdDrawIndexed, + vtable.cmdImageBarrier = cmdImageBarrier, + vtable.cmdBufferBarrier = cmdBufferBarrier, + vtable.cmdDispatch = cmdDispatch, + vtable.cmdBindDescriptorSet = cmdBindDescriptorSet, + vtable.cmdPushConstants = cmdPushConstants, + vtable.createBuffer = createBuffer, + vtable.destroyBuffer = destroyBuffer, + vtable.getBufferMemoryRequirements = getBufferMemoryRequirements, + vtable.computeImageStagingRequirements = computeImageStagingRequirements, + vtable.writeImageStaging = writeImageStaging, + vtable.bindBufferMemory = bindBufferMemory, + vtable.mapBuffer = mapBuffer, + vtable.unmapBuffer = unmapBuffer, + vtable.createDescriptorSetLayout = createDescriptorSetLayout, + vtable.destroyDescriptorSetLayout = destroyDescriptorSetLayout, + vtable.createDescriptorPool = createDescriptorPool, + vtable.destroyDescriptorPool = destroyDescriptorPool, + vtable.resetDescriptorPool = resetDescriptorPool, + vtable.allocateDescriptorSet = allocateDescriptorSet, + vtable.updateDescriptorSet = updateDescriptorSet, + vtable.createPipelineLayout = createPipelineLayout, + vtable.destroyPipelineLayout = destroyPipelineLayout, + vtable.createGraphicsPipeline = createGraphicsPipeline, + vtable.createComputePipeline = createComputePipeline, + vtable.destroyPipeline = destroyPipeline; + + PalGraphicsBackendInfo backendInfo = {0}; + backendInfo.version = PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1; + backendInfo.vtable = &vtable; + + PalResult result = palInitGraphics(nullptr, nullptr, 1, &backendInfo); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to initialize graphics"); + return PAL_FALSE; + } + + // TODO: enumerate and select our adapter and do some work + palShutdownGraphics(); + return PAL_TRUE; } \ No newline at end of file From 2a6fe75880ecd1b3e1db90d44336a2bca7c696a8 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 18 Jul 2026 21:22:35 +0000 Subject: [PATCH 359/372] custom backend test working --- src/graphics/pal_graphics.c | 478 +++----- src/graphics/pal_graphics_backends.h | 1602 +++++++++++++++++++------- src/opengl/pal_opengl_backends.h | 109 +- src/video/pal_video_backends.h | 873 +++++++++++--- tests/graphics/custom_backend_test.c | 971 +++++++++++----- tests/graphics/graphics_test.c | 10 +- tests/tests_main.c | 1 + 7 files changed, 2828 insertions(+), 1216 deletions(-) diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index a7ae1a89..6c7115a0 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -13,7 +13,7 @@ #define MAX_BACKENDS (PAL_MAX_CUSTOM_BACKENDS + 2) #define PAL_HANDLE(name) \ struct name { \ - const PalGraphicsVtable* backend; \ + PalGraphicsVtable backend; \ }; PAL_HANDLE(PalAdapter) @@ -177,189 +177,7 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) return PAL_TRUE; } -static void populateVtableVersion1( - PalGraphicsVtable* vtable, - const PalGraphicsBackendVtable1* vtable1) -{ - // clang-format off - vtable->enumerateAdapters = vtable1->enumerateAdapters; - vtable->getAdapterInfo = vtable1->getAdapterInfo; - vtable->getAdapterCapabilities = vtable1->getAdapterCapabilities; - vtable->getAdapterFeatures = vtable1->getAdapterFeatures; - vtable->getHighestSupportedShaderTarget = vtable1->getHighestSupportedShaderTarget; - - // device - vtable->createDevice = vtable1->createDevice; - vtable->destroyDevice = vtable1->destroyDevice; - - // memory - vtable->allocateMemory = vtable1->allocateMemory; - vtable->freeMemory = vtable1->freeMemory; - - // extended adapter features - vtable->querySamplerAnisotropyCapabilities = vtable1->querySamplerAnisotropyCapabilities; - vtable->queryMultiViewCapabilities = vtable1->queryMultiViewCapabilities; - vtable->queryMultiViewportCapabilities = vtable1->queryMultiViewportCapabilities; - vtable->queryDepthStencilCapabilities = vtable1->queryDepthStencilCapabilities; - vtable->queryFragmentShadingRateCapabilities = vtable1->queryFragmentShadingRateCapabilities; - vtable->queryMeshShaderCapabilities = vtable1->queryMeshShaderCapabilities; - vtable->queryRayTracingCapabilities = vtable1->queryRayTracingCapabilities; - vtable->queryDescriptorIndexingCapabilities = vtable1->queryDescriptorIndexingCapabilities; - - // queue - vtable->createQueue = vtable1->createQueue; - vtable->destroyQueue = vtable1->destroyQueue; - vtable->waitQueue = vtable1->waitQueue; - vtable->canQueuePresent = vtable1->canQueuePresent; - - // formats - vtable->enumerateFormats = vtable1->enumerateFormats; - vtable->isFormatSupported = vtable1->isFormatSupported; - vtable->queryFormatImageUsages = vtable1->queryFormatImageUsages; - vtable->queryFormatSampleCount = vtable1->queryFormatSampleCount; - - // image - vtable->createImage = vtable1->createImage; - vtable->destroyImage = vtable1->destroyImage; - vtable->getImageInfo = vtable1->getImageInfo; - vtable->getImageMemoryRequirements = vtable1->getImageMemoryRequirements; - vtable->bindImageMemory = vtable1->bindImageMemory; - - // image view - vtable->createImageView = vtable1->createImageView; - vtable->destroyImageView = vtable1->destroyImageView; - - // sampler - vtable->createSampler = vtable1->createSampler; - vtable->destroySampler = vtable1->destroySampler; - - // surface - vtable->createSurface = vtable1->createSurface; - vtable->destroySurface = vtable1->destroySurface; - vtable->getSurfaceCapabilities = vtable1->getSurfaceCapabilities; - - // swapchain - vtable->createSwapchain = vtable1->createSwapchain; - vtable->destroySwapchain = vtable1->destroySwapchain; - vtable->getSwapchainImage = vtable1->getSwapchainImage; - vtable->getNextSwapchainImage = vtable1->getNextSwapchainImage; - vtable->presentSwapchain = vtable1->presentSwapchain; - vtable->resizeSwapchain = vtable1->resizeSwapchain; - - // shader - vtable->createShader = vtable1->createShader; - vtable->destroyShader = vtable1->destroyShader; - - // fence - vtable->createFence = vtable1->createFence; - vtable->destroyFence = vtable1->destroyFence; - vtable->waitFence = vtable1->waitFence; - vtable->resetFence = vtable1->resetFence; - vtable->isFenceSignaled = vtable1->isFenceSignaled; - - // semaphore - vtable->createSemaphore = vtable1->createSemaphore; - vtable->destroySemaphore = vtable1->destroySemaphore; - vtable->waitSemaphore = vtable1->waitSemaphore; - vtable->signalSemaphore = vtable1->signalSemaphore; - vtable->getSemaphoreValue = vtable1->getSemaphoreValue; - - // command pool and command buffer - vtable->createCommandPool = vtable1->createCommandPool; - vtable->destroyCommandPool = vtable1->destroyCommandPool; - vtable->allocateCommandBuffer = vtable1->allocateCommandBuffer; - vtable->freeCommandBuffer = vtable1->freeCommandBuffer; - vtable->submitCommandBuffer = vtable1->submitCommandBuffer; - - // command recording - vtable->cmdBegin = vtable1->cmdBegin; - vtable->cmdEnd = vtable1->cmdEnd; - vtable->resetCommandBuffer = vtable1->resetCommandBuffer; - vtable->cmdExecuteCommandBuffer = vtable1->cmdExecuteCommandBuffer; - vtable->cmdSetFragmentShadingRate = vtable1->cmdSetFragmentShadingRate; - vtable->cmdDrawMeshTasks = vtable1->cmdDrawMeshTasks; - vtable->cmdDrawMeshTasksIndirect = vtable1->cmdDrawMeshTasksIndirect; - vtable->cmdDrawMeshTasksIndirectCount = vtable1->cmdDrawMeshTasksIndirectCount; - vtable->cmdBuildAccelerationStructure = vtable1->cmdBuildAccelerationStructure; - vtable->cmdBeginRendering = vtable1->cmdBeginRendering; - vtable->cmdEndRendering = vtable1->cmdEndRendering; - vtable->cmdCopyBuffer = vtable1->cmdCopyBuffer; - vtable->cmdCopyBufferToImage = vtable1->cmdCopyBufferToImage; - vtable->cmdCopyImage = vtable1->cmdCopyImage; - vtable->cmdCopyImageToBuffer = vtable1->cmdCopyImageToBuffer; - vtable->cmdBindPipeline = vtable1->cmdBindPipeline; - vtable->cmdSetViewport = vtable1->cmdSetViewport; - vtable->cmdSetScissors = vtable1->cmdSetScissors; - vtable->cmdBindVertexBuffers = vtable1->cmdBindVertexBuffers; - vtable->cmdBindIndexBuffer = vtable1->cmdBindIndexBuffer; - vtable->cmdDraw = vtable1->cmdDraw; - vtable->cmdDrawIndirect = vtable1->cmdDrawIndirect; - vtable->cmdDrawIndirectCount = vtable1->cmdDrawIndirectCount; - vtable->cmdDrawIndexed = vtable1->cmdDrawIndexed; - vtable->cmdDrawIndexedIndirect = vtable1->cmdDrawIndexedIndirect; - vtable->cmdDrawIndexedIndirectCount = vtable1->cmdDrawIndexedIndirectCount; - vtable->cmdAccelerationStructureBarrier = vtable1->cmdAccelerationStructureBarrier; - vtable->cmdImageBarrier = vtable1->cmdImageBarrier; - vtable->cmdBufferBarrier = vtable1->cmdBufferBarrier; - vtable->cmdDispatch = vtable1->cmdDispatch; - vtable->cmdDispatchBase = vtable1->cmdDispatchBase; - vtable->cmdDispatchIndirect = vtable1->cmdDispatchIndirect; - vtable->cmdTraceRays = vtable1->cmdTraceRays; - vtable->cmdTraceRaysIndirect = vtable1->cmdTraceRaysIndirect; - vtable->cmdBindDescriptorSet = vtable1->cmdBindDescriptorSet; - vtable->cmdPushConstants = vtable1->cmdPushConstants; - vtable->cmdSetCullMode = vtable1->cmdSetCullMode; - vtable->cmdSetFrontFace = vtable1->cmdSetFrontFace; - vtable->cmdSetPrimitiveTopology = vtable1->cmdSetPrimitiveTopology; - vtable->cmdSetDepthTestEnable = vtable1->cmdSetDepthTestEnable; - vtable->cmdSetDepthWriteEnable = vtable1->cmdSetDepthWriteEnable; - vtable->cmdSetStencilOp = vtable1->cmdSetStencilOp; - - // acceleration structure - vtable->createAccelerationstructure = vtable1->createAccelerationstructure; - vtable->destroyAccelerationstructure = vtable1->destroyAccelerationstructure; - vtable->getAccelerationStructureBuildSize = vtable1->getAccelerationStructureBuildSize; - - // buffer - vtable->createBuffer = vtable1->createBuffer; - vtable->destroyBuffer = vtable1->destroyBuffer; - vtable->getBufferMemoryRequirements = vtable1->getBufferMemoryRequirements; - vtable->computeInstanceStagingSize = vtable1->computeInstanceStagingSize; - vtable->computeImageStagingRequirements = vtable1->computeImageStagingRequirements; - vtable->writeInstanceStaging = vtable1->writeInstanceStaging; - vtable->writeImageStaging = vtable1->writeImageStaging; - vtable->bindBufferMemory = vtable1->bindBufferMemory; - vtable->getBufferDeviceAddress = vtable1->getBufferDeviceAddress; - vtable->mapBuffer = vtable1->mapBuffer; - vtable->unmapBuffer = vtable1->unmapBuffer; - - // descriptors - vtable->createDescriptorSetLayout = vtable1->createDescriptorSetLayout; - vtable->destroyDescriptorSetLayout = vtable1->destroyDescriptorSetLayout; - vtable->createDescriptorPool = vtable1->createDescriptorPool; - vtable->destroyDescriptorPool = vtable1->destroyDescriptorPool; - vtable->resetDescriptorPool = vtable1->resetDescriptorPool; - vtable->allocateDescriptorSet = vtable1->allocateDescriptorSet; - vtable->updateDescriptorSet = vtable1->updateDescriptorSet; - - // pipeline layout - vtable->createPipelineLayout = vtable1->createPipelineLayout; - vtable->destroyPipelineLayout = vtable1->destroyPipelineLayout; - - // pipeline - vtable->createGraphicsPipeline = vtable1->createGraphicsPipeline; - vtable->createComputePipeline = vtable1->createComputePipeline; - vtable->createRayTracingPipeline = vtable1->createRayTracingPipeline; - vtable->destroyPipeline = vtable1->destroyPipeline; - - // shader binding table - vtable->createShaderBindingTable = vtable1->createShaderBindingTable; - vtable->destroyShaderBindingTable = vtable1->destroyShaderBindingTable; - vtable->updateShaderBindingTable = vtable1->updateShaderBindingTable; - // clang-format on -} - -static void addBackend(PalGraphicsBackendInfo* backendInfo) +static PalBool addBackend(const PalGraphicsBackendInfo* backendInfo) { BackendData* backendData = &s_Graphics.backends[s_Graphics.backendCount++]; backendData->startIndex = 0; @@ -369,11 +187,14 @@ static void addBackend(PalGraphicsBackendInfo* backendInfo) if (backendInfo->version == PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1) { // validate that all version 1 required pointers are set const PalGraphicsBackendVtable1* vtable1 = (PalGraphicsBackendVtable1*)backendInfo->vtable; - validateVtableVersion1(vtable1); - + if (!validateVtableVersion1(vtable1)) { + return PAL_FALSE; + } memset(&backendData->base, 0, sizeof(PalGraphicsVtable)); - populateVtableVersion1(&backendData->base, vtable1); + backendData->base.vtbl1 = vtable1; } + + return PAL_TRUE; } PalResult PAL_CALL palInitGraphics( @@ -393,7 +214,7 @@ PalResult PAL_CALL palInitGraphics( } attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base = s_VkBackend; + attachedBackend->base.vtbl1 = &s_VkBackend1; attachedBackend->startIndex = 0; attachedBackend->count = 0; #endif // PAL_HAS_VULKAN_BACKEND @@ -406,7 +227,7 @@ PalResult PAL_CALL palInitGraphics( } attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base = s_D3D12Backend; + attachedBackend->base.vtbl1 = &s_D3D12Backend; attachedBackend->startIndex = 0; attachedBackend->count = 0; #endif // PAL_HAS_D3D12_BACKEND @@ -420,7 +241,7 @@ PalResult PAL_CALL palInitGraphics( } attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base = s_VkBackend; + attachedBackend->base.vtbl1 = &s_VkBackend1; attachedBackend->startIndex = 0; attachedBackend->count = 0; #endif // PAL_HAS_VULKAN_BACKEND @@ -428,6 +249,13 @@ PalResult PAL_CALL palInitGraphics( // metal or andriod #endif // _WIN32 + // custom backends + for (uint32_t i = 0; i < customBackendCount; i++) { + if (!addBackend(&customBackends[i])) { + return PAL_RESULT_CODE_INVALID_ARGUMENT; + } + } + s_Graphics.allocator = allocator; return PAL_RESULT_SUCCESS; } @@ -482,7 +310,7 @@ PalResult PAL_CALL palEnumerateAdapters( // offset into the array so all backends write at the correct index PalAdapter** adapters = &outAdapters[backend->startIndex]; _count = backend->count; - result = backend->base.enumerateAdapters(&_count, adapters); + result = backend->base.vtbl1->enumerateAdapters(&_count, adapters); // break if a backend fails if (result != PAL_RESULT_SUCCESS) { return result; @@ -490,11 +318,11 @@ PalResult PAL_CALL palEnumerateAdapters( for (int j = 0; j < _count; j++) { PalAdapter* tmp = adapters[j]; - adapters[j]->backend = &backend->base; + tmp->backend.vtbl1 = backend->base.vtbl1; } } else { - result = backend->base.enumerateAdapters(&_count, nullptr); + result = backend->base.vtbl1->enumerateAdapters(&_count, nullptr); // break if a backend fails if (result != PAL_RESULT_SUCCESS) { return result; @@ -517,26 +345,26 @@ void PAL_CALL palGetAdapterInfo( PalAdapter* adapter, PalAdapterInfo* info) { - adapter->backend->getAdapterInfo(adapter, info); + adapter->backend.vtbl1->getAdapterInfo(adapter, info); } void PAL_CALL palGetAdapterCapabilities( PalAdapter* adapter, PalAdapterCapabilities* caps) { - adapter->backend->getAdapterCapabilities(adapter, caps); + adapter->backend.vtbl1->getAdapterCapabilities(adapter, caps); } PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter) { - return adapter->backend->getAdapterFeatures(adapter); + return adapter->backend.vtbl1->getAdapterFeatures(adapter); } uint32_t PAL_CALL palGetHighestSupportedShaderTarget( PalAdapter* adapter, PalShaderFormats shaderFormat) { - return adapter->backend->getHighestSupportedShaderTarget(adapter, shaderFormat); + return adapter->backend.vtbl1->getHighestSupportedShaderTarget(adapter, shaderFormat); } // ================================================== @@ -554,7 +382,7 @@ PalResult PAL_CALL palCreateDevice( PalDevice* device = nullptr; PalResult result; - result = adapter->backend->createDevice(adapter, features, &device); + result = adapter->backend.vtbl1->createDevice(adapter, features, &device); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -566,7 +394,7 @@ PalResult PAL_CALL palCreateDevice( void PAL_CALL palDestroyDevice(PalDevice* device) { - device->backend->destroyDevice(device); + device->backend.vtbl1->destroyDevice(device); } PalResult PAL_CALL palAllocateMemory( @@ -582,7 +410,7 @@ PalResult PAL_CALL palAllocateMemory( PalMemory* memory = nullptr; PalResult result; - result = device->backend->allocateMemory(device, type, memoryMask, size, &memory); + result = device->backend.vtbl1->allocateMemory(device, type, memoryMask, size, &memory); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -594,7 +422,7 @@ PalResult PAL_CALL palAllocateMemory( void PAL_CALL palFreeMemory(PalMemory* memory) { - memory->backend->freeMemory(memory); + memory->backend.vtbl1->freeMemory(memory); } // ================================================== @@ -605,56 +433,56 @@ void PAL_CALL palQuerySamplerAnisotropyCapabilities( PalDevice* device, PalSamplerAnisotropyCapabilities* caps) { - device->backend->querySamplerAnisotropyCapabilities(device, caps); + device->backend.vtbl1->querySamplerAnisotropyCapabilities(device, caps); } void PAL_CALL palQueryMultiViewCapabilities( PalDevice* device, PalMultiViewCapabilities* caps) { - device->backend->queryMultiViewCapabilities(device, caps); + device->backend.vtbl1->queryMultiViewCapabilities(device, caps); } void PAL_CALL palQueryMultiViewportCapabilities( PalDevice* device, PalMultiViewportCapabilities* caps) { - device->backend->queryMultiViewportCapabilities(device, caps); + device->backend.vtbl1->queryMultiViewportCapabilities(device, caps); } void PAL_CALL palQueryDepthStencilCapabilities( PalDevice* device, PalDepthStencilCapabilities* caps) { - device->backend->queryDepthStencilCapabilities(device, caps); + device->backend.vtbl1->queryDepthStencilCapabilities(device, caps); } void PAL_CALL palQueryFragmentShadingRateCapabilities( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { - device->backend->queryFragmentShadingRateCapabilities(device, caps); + device->backend.vtbl1->queryFragmentShadingRateCapabilities(device, caps); } void PAL_CALL palQueryMeshShaderCapabilities( PalDevice* device, PalMeshShaderCapabilities* caps) { - device->backend->queryMeshShaderCapabilities(device, caps); + device->backend.vtbl1->queryMeshShaderCapabilities(device, caps); } void PAL_CALL palQueryRayTracingCapabilities( PalDevice* device, PalRayTracingCapabilities* caps) { - device->backend->queryRayTracingCapabilities(device, caps); + device->backend.vtbl1->queryRayTracingCapabilities(device, caps); } void PAL_CALL palQueryDescriptorIndexingCapabilities( PalDevice* device, PalDescriptorIndexingCapabilities* caps) { - device->backend->queryDescriptorIndexingCapabilities(device, caps); + device->backend.vtbl1->queryDescriptorIndexingCapabilities(device, caps); } // ================================================== @@ -672,7 +500,7 @@ PalResult PAL_CALL palCreateQueue( PalQueue* queue = nullptr; PalResult result; - result = device->backend->createQueue(device, type, &queue); + result = device->backend.vtbl1->createQueue(device, type, &queue); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -684,19 +512,19 @@ PalResult PAL_CALL palCreateQueue( void PAL_CALL palDestroyQueue(PalQueue* queue) { - queue->backend->destroyQueue(queue); + queue->backend.vtbl1->destroyQueue(queue); } PalBool PAL_CALL palCanQueuePresent( PalQueue* queue, PalSurface* surface) { - queue->backend->canQueuePresent(queue, surface); + queue->backend.vtbl1->canQueuePresent(queue, surface); } PalResult PAL_CALL palWaitQueue(PalQueue* queue) { - return queue->backend->waitQueue(queue); + return queue->backend.vtbl1->waitQueue(queue); } // ================================================== @@ -708,28 +536,28 @@ void PAL_CALL palEnumerateFormats( uint32_t* count, PalFormatInfo* outFormats) { - adapter->backend->enumerateFormats(adapter, count, outFormats); + adapter->backend.vtbl1->enumerateFormats(adapter, count, outFormats); } PalBool PAL_CALL palIsFormatSupported( PalAdapter* adapter, PalFormat format) { - adapter->backend->isFormatSupported(adapter, format); + adapter->backend.vtbl1->isFormatSupported(adapter, format); } PalImageUsages PAL_CALL palQueryFormatImageUsages( PalAdapter* adapter, PalFormat format) { - adapter->backend->queryFormatImageUsages(adapter, format); + adapter->backend.vtbl1->queryFormatImageUsages(adapter, format); } PalSampleCount PAL_CALL palQueryFormatSampleCount( PalAdapter* adapter, PalFormat format) { - adapter->backend->queryFormatSampleCount(adapter, format); + adapter->backend.vtbl1->queryFormatSampleCount(adapter, format); } // ================================================== @@ -747,7 +575,7 @@ PalResult PAL_CALL palCreateImage( PalImage* image = nullptr; PalResult result; - result = device->backend->createImage(device, info, &image); + result = device->backend.vtbl1->createImage(device, info, &image); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -759,21 +587,21 @@ PalResult PAL_CALL palCreateImage( void PAL_CALL palDestroyImage(PalImage* image) { - image->backend->destroyImage(image); + image->backend.vtbl1->destroyImage(image); } void PAL_CALL palGetImageInfo( PalImage* image, PalImageInfo* info) { - image->backend->getImageInfo(image, info); + image->backend.vtbl1->getImageInfo(image, info); } void PAL_CALL palGetImageMemoryRequirements( PalImage* image, PalMemoryRequirements* requirements) { - image->backend->getImageMemoryRequirements(image, requirements); + image->backend.vtbl1->getImageMemoryRequirements(image, requirements); } PalResult PAL_CALL palBindImageMemory( @@ -781,7 +609,7 @@ PalResult PAL_CALL palBindImageMemory( PalMemory* memory, uint64_t offset) { - image->backend->bindImageMemory(image, memory, offset); + image->backend.vtbl1->bindImageMemory(image, memory, offset); } // ================================================== @@ -800,7 +628,7 @@ PalResult PAL_CALL palCreateImageView( PalImageView* imageView = nullptr; PalResult result; - result = device->backend->createImageView(device, image, info, &imageView); + result = device->backend.vtbl1->createImageView(device, image, info, &imageView); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -812,7 +640,7 @@ PalResult PAL_CALL palCreateImageView( void PAL_CALL palDestroyImageView(PalImageView* imageView) { - imageView->backend->destroyImageView(imageView); + imageView->backend.vtbl1->destroyImageView(imageView); } // ================================================== @@ -830,7 +658,7 @@ PalResult PAL_CALL palCreateSampler( PalSampler* sampler = nullptr; PalResult result; - result = device->backend->createSampler(device, info, &sampler); + result = device->backend.vtbl1->createSampler(device, info, &sampler); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -842,7 +670,7 @@ PalResult PAL_CALL palCreateSampler( void PAL_CALL palDestroySampler(PalSampler* sampler) { - sampler->backend->destroySampler(sampler); + sampler->backend.vtbl1->destroySampler(sampler); } // ================================================== @@ -862,7 +690,7 @@ PalResult PAL_CALL palCreateSurface( PalSurface* surface = nullptr; PalResult ret; - ret = device->backend->createSurface(device, window, windowInstance, instanceType, &surface); + ret = device->backend.vtbl1->createSurface(device, window, windowInstance, instanceType, &surface); if (ret != PAL_RESULT_SUCCESS) { return ret; } @@ -874,7 +702,7 @@ PalResult PAL_CALL palCreateSurface( void PAL_CALL palDestroySurface(PalSurface* surface) { - surface->backend->destroySurface(surface); + surface->backend.vtbl1->destroySurface(surface); } void PAL_CALL palGetSurfaceCapabilities( @@ -882,7 +710,7 @@ void PAL_CALL palGetSurfaceCapabilities( PalSurface* surface, PalSurfaceCapabilities* caps) { - device->backend->getSurfaceCapabilities(device, surface, caps); + device->backend.vtbl1->getSurfaceCapabilities(device, surface, caps); } // ================================================== @@ -902,14 +730,14 @@ PalResult PAL_CALL palCreateSwapchain( PalResult result; PalSwapchain* swapchain = nullptr; - result = device->backend->createSwapchain(device, queue, surface, info, &swapchain); + result = device->backend.vtbl1->createSwapchain(device, queue, surface, info, &swapchain); if (result != PAL_RESULT_SUCCESS) { return result; } // set the backend for all swapchain images for (int i = 0; i < info->imageCount; i++) { - PalImage* image = device->backend->getSwapchainImage(swapchain, i); + PalImage* image = device->backend.vtbl1->getSwapchainImage(swapchain, i); image->backend = device->backend; } @@ -920,14 +748,14 @@ PalResult PAL_CALL palCreateSwapchain( void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain) { - swapchain->backend->destroySwapchain(swapchain); + swapchain->backend.vtbl1->destroySwapchain(swapchain); } PalImage* PAL_CALL palGetSwapchainImage( PalSwapchain* swapchain, uint32_t index) { - return swapchain->backend->getSwapchainImage(swapchain, index); + return swapchain->backend.vtbl1->getSwapchainImage(swapchain, index); } PalResult PAL_CALL palGetNextSwapchainImage( @@ -935,7 +763,7 @@ PalResult PAL_CALL palGetNextSwapchainImage( PalSwapchainNextImageInfo* info, uint32_t* outIndex) { - return swapchain->backend->getNextSwapchainImage(swapchain, info, outIndex); + return swapchain->backend.vtbl1->getNextSwapchainImage(swapchain, info, outIndex); } PalResult PAL_CALL palPresentSwapchain( @@ -943,7 +771,7 @@ PalResult PAL_CALL palPresentSwapchain( uint32_t imageIndex, PalSemaphore* waitSemaphore) { - return swapchain->backend->presentSwapchain(swapchain, imageIndex, waitSemaphore); + return swapchain->backend.vtbl1->presentSwapchain(swapchain, imageIndex, waitSemaphore); } PalResult PAL_CALL palResizeSwapchain( @@ -951,7 +779,7 @@ PalResult PAL_CALL palResizeSwapchain( uint32_t newWidth, uint32_t newHeight) { - return swapchain->backend->resizeSwapchain(swapchain, newWidth, newHeight); + return swapchain->backend.vtbl1->resizeSwapchain(swapchain, newWidth, newHeight); } // ================================================== @@ -969,7 +797,7 @@ PalResult PAL_CALL palCreateShader( PalShader* shader = nullptr; PalResult result; - result = device->backend->createShader(device, info, &shader); + result = device->backend.vtbl1->createShader(device, info, &shader); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -981,7 +809,7 @@ PalResult PAL_CALL palCreateShader( void PAL_CALL palDestroyShader(PalShader* shader) { - shader->backend->destroyShader(shader); + shader->backend.vtbl1->destroyShader(shader); } // ================================================== @@ -999,7 +827,7 @@ PalResult PAL_CALL palCreateFence( PalFence* fence = nullptr; PalResult result; - result = device->backend->createFence(device, signaled, &fence); + result = device->backend.vtbl1->createFence(device, signaled, &fence); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1011,24 +839,24 @@ PalResult PAL_CALL palCreateFence( void PAL_CALL palDestroyFence(PalFence* fence) { - fence->backend->destroyFence(fence); + fence->backend.vtbl1->destroyFence(fence); } PalResult PAL_CALL palWaitFence( PalFence* fence, uint64_t timeout) { - return fence->backend->waitFence(fence, timeout); + return fence->backend.vtbl1->waitFence(fence, timeout); } PalResult PAL_CALL palResetFence(PalFence* fence) { - return fence->backend->resetFence(fence); + return fence->backend.vtbl1->resetFence(fence); } PalBool PAL_CALL palIsFenceSignaled(PalFence* fence) { - return fence->backend->isFenceSignaled(fence); + return fence->backend.vtbl1->isFenceSignaled(fence); } // ================================================== @@ -1046,7 +874,7 @@ PalResult PAL_CALL palCreateSemaphore( PalSemaphore* semaphore = nullptr; PalResult result; - result = device->backend->createSemaphore(device, enableTimeline, &semaphore); + result = device->backend.vtbl1->createSemaphore(device, enableTimeline, &semaphore); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1058,7 +886,7 @@ PalResult PAL_CALL palCreateSemaphore( void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore) { - semaphore->backend->destroySemaphore(semaphore); + semaphore->backend.vtbl1->destroySemaphore(semaphore); } PalResult PAL_CALL palWaitSemaphore( @@ -1066,7 +894,7 @@ PalResult PAL_CALL palWaitSemaphore( uint64_t value, uint64_t timeout) { - return semaphore->backend->waitSemaphore(semaphore, value, timeout); + return semaphore->backend.vtbl1->waitSemaphore(semaphore, value, timeout); } PalResult PAL_CALL palSignalSemaphore( @@ -1074,14 +902,14 @@ PalResult PAL_CALL palSignalSemaphore( PalQueue* queue, uint64_t value) { - return semaphore->backend->signalSemaphore(semaphore, queue, value); + return semaphore->backend.vtbl1->signalSemaphore(semaphore, queue, value); } PalResult PAL_CALL palGetSemaphoreValue( PalSemaphore* semaphore, uint64_t* value) { - return semaphore->backend->getSemaphoreValue(semaphore, value); + return semaphore->backend.vtbl1->getSemaphoreValue(semaphore, value); } // ================================================== @@ -1099,7 +927,7 @@ PalResult PAL_CALL palCreateCommandPool( PalCommandPool* pool = nullptr; PalResult result; - result = device->backend->createCommandPool(device, queue, &pool); + result = device->backend.vtbl1->createCommandPool(device, queue, &pool); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1111,7 +939,7 @@ PalResult PAL_CALL palCreateCommandPool( void PAL_CALL palDestroyCommandPool(PalCommandPool* pool) { - pool->backend->destroyCommandPool(pool); + pool->backend.vtbl1->destroyCommandPool(pool); } PalResult PAL_CALL palAllocateCommandBuffer( @@ -1126,7 +954,7 @@ PalResult PAL_CALL palAllocateCommandBuffer( PalCommandBuffer* cmdBuffer = nullptr; PalResult result; - result = device->backend->allocateCommandBuffer(device, pool, type, &cmdBuffer); + result = device->backend.vtbl1->allocateCommandBuffer(device, pool, type, &cmdBuffer); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1138,19 +966,19 @@ PalResult PAL_CALL palAllocateCommandBuffer( void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer) { - cmdBuffer->backend->freeCommandBuffer(cmdBuffer); + cmdBuffer->backend.vtbl1->freeCommandBuffer(cmdBuffer); } PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer) { - return cmdBuffer->backend->resetCommandBuffer(cmdBuffer); + return cmdBuffer->backend.vtbl1->resetCommandBuffer(cmdBuffer); } PalResult PAL_CALL palSubmitCommandBuffer( PalQueue* queue, PalCommandBufferSubmitInfo* info) { - return queue->backend->submitCommandBuffer(queue, info); + return queue->backend.vtbl1->submitCommandBuffer(queue, info); } // ================================================== @@ -1161,26 +989,26 @@ PalResult PAL_CALL palCmdBegin( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) { - cmdBuffer->backend->cmdBegin(cmdBuffer, info); + cmdBuffer->backend.vtbl1->cmdBegin(cmdBuffer, info); } PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer) { - cmdBuffer->backend->cmdEnd(cmdBuffer); + cmdBuffer->backend.vtbl1->cmdEnd(cmdBuffer); } void PAL_CALL palCmdExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { - primaryCmdBuffer->backend->cmdExecuteCommandBuffer(primaryCmdBuffer, secondaryCmdBuffer); + primaryCmdBuffer->backend.vtbl1->cmdExecuteCommandBuffer(primaryCmdBuffer, secondaryCmdBuffer); } void PAL_CALL palCmdSetFragmentShadingRate( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { - cmdBuffer->backend->cmdSetFragmentShadingRate(cmdBuffer, state); + cmdBuffer->backend.vtbl1->cmdSetFragmentShadingRate(cmdBuffer, state); } void PAL_CALL palCmdDrawMeshTasks( @@ -1189,7 +1017,7 @@ void PAL_CALL palCmdDrawMeshTasks( uint32_t groupCountY, uint32_t groupCountZ) { - cmdBuffer->backend->cmdDrawMeshTasks(cmdBuffer, groupCountX, groupCountY, groupCountZ); + cmdBuffer->backend.vtbl1->cmdDrawMeshTasks(cmdBuffer, groupCountX, groupCountY, groupCountZ); } void PAL_CALL palCmdDrawMeshTasksIndirect( @@ -1197,7 +1025,7 @@ void PAL_CALL palCmdDrawMeshTasksIndirect( PalBuffer* buffer, uint32_t drawCount) { - cmdBuffer->backend->cmdDrawMeshTasksIndirect(cmdBuffer, buffer, drawCount); + cmdBuffer->backend.vtbl1->cmdDrawMeshTasksIndirect(cmdBuffer, buffer, drawCount); } void PAL_CALL palCmdDrawMeshTasksIndirectCount( @@ -1206,7 +1034,7 @@ void PAL_CALL palCmdDrawMeshTasksIndirectCount( PalBuffer* countBuffer, uint32_t maxDrawCount) { - cmdBuffer->backend->cmdDrawMeshTasksIndirectCount( + cmdBuffer->backend.vtbl1->cmdDrawMeshTasksIndirectCount( cmdBuffer, buffer, countBuffer, @@ -1217,19 +1045,19 @@ void PAL_CALL palCmdBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { - cmdBuffer->backend->cmdBuildAccelerationStructure(cmdBuffer, info); + cmdBuffer->backend.vtbl1->cmdBuildAccelerationStructure(cmdBuffer, info); } void PAL_CALL palCmdBeginRendering( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { - cmdBuffer->backend->cmdBeginRendering(cmdBuffer, info); + cmdBuffer->backend.vtbl1->cmdBeginRendering(cmdBuffer, info); } void PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer) { - cmdBuffer->backend->cmdEndRendering(cmdBuffer); + cmdBuffer->backend.vtbl1->cmdEndRendering(cmdBuffer); } void PAL_CALL palCmdCopyBuffer( @@ -1238,7 +1066,7 @@ void PAL_CALL palCmdCopyBuffer( PalBuffer* src, PalBufferCopyInfo* copyInfo) { - cmdBuffer->backend->cmdCopyBuffer(cmdBuffer, dst, src, copyInfo); + cmdBuffer->backend.vtbl1->cmdCopyBuffer(cmdBuffer, dst, src, copyInfo); } void PAL_CALL palCmdCopyBufferToImage( @@ -1247,7 +1075,7 @@ void PAL_CALL palCmdCopyBufferToImage( PalBuffer* srcBuffer, PalBufferImageCopyInfo* copyInfo) { - cmdBuffer->backend->cmdCopyBufferToImage(cmdBuffer, dstImage, srcBuffer, copyInfo); + cmdBuffer->backend.vtbl1->cmdCopyBufferToImage(cmdBuffer, dstImage, srcBuffer, copyInfo); } void PAL_CALL palCmdCopyImage( @@ -1256,7 +1084,7 @@ void PAL_CALL palCmdCopyImage( PalImage* src, PalImageCopyInfo* copyInfo) { - cmdBuffer->backend->cmdCopyImage(cmdBuffer, dst, src, copyInfo); + cmdBuffer->backend.vtbl1->cmdCopyImage(cmdBuffer, dst, src, copyInfo); } void PAL_CALL palCmdCopyImageToBuffer( @@ -1265,14 +1093,14 @@ void PAL_CALL palCmdCopyImageToBuffer( PalImage* srcImage, PalBufferImageCopyInfo* copyInfo) { - cmdBuffer->backend->cmdCopyImageToBuffer(cmdBuffer, dstBuffer, srcImage, copyInfo); + cmdBuffer->backend.vtbl1->cmdCopyImageToBuffer(cmdBuffer, dstBuffer, srcImage, copyInfo); } void PAL_CALL palCmdBindPipeline( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline) { - cmdBuffer->backend->cmdBindPipeline(cmdBuffer, pipeline); + cmdBuffer->backend.vtbl1->cmdBindPipeline(cmdBuffer, pipeline); } void PAL_CALL palCmdSetViewport( @@ -1280,7 +1108,7 @@ void PAL_CALL palCmdSetViewport( uint32_t count, PalViewport* viewports) { - cmdBuffer->backend->cmdSetViewport(cmdBuffer, count, viewports); + cmdBuffer->backend.vtbl1->cmdSetViewport(cmdBuffer, count, viewports); } void PAL_CALL palCmdSetScissors( @@ -1288,7 +1116,7 @@ void PAL_CALL palCmdSetScissors( uint32_t count, PalRect2D* scissors) { - cmdBuffer->backend->cmdSetScissors(cmdBuffer, count, scissors); + cmdBuffer->backend.vtbl1->cmdSetScissors(cmdBuffer, count, scissors); } void PAL_CALL palCmdBindVertexBuffers( @@ -1298,7 +1126,7 @@ void PAL_CALL palCmdBindVertexBuffers( PalBuffer** buffers, uint64_t* offsets) { - cmdBuffer->backend->cmdBindVertexBuffers(cmdBuffer, firstSlot, count, buffers, offsets); + cmdBuffer->backend.vtbl1->cmdBindVertexBuffers(cmdBuffer, firstSlot, count, buffers, offsets); } void PAL_CALL palCmdBindIndexBuffer( @@ -1307,7 +1135,7 @@ void PAL_CALL palCmdBindIndexBuffer( uint64_t offset, PalIndexType type) { - cmdBuffer->backend->cmdBindIndexBuffer(cmdBuffer, buffer, offset, type); + cmdBuffer->backend.vtbl1->cmdBindIndexBuffer(cmdBuffer, buffer, offset, type); } void PAL_CALL palCmdDraw( @@ -1317,7 +1145,7 @@ void PAL_CALL palCmdDraw( uint32_t firstVertex, uint32_t firstInstance) { - cmdBuffer->backend->cmdDraw(cmdBuffer, vertexCount, instanceCount, firstVertex, firstInstance); + cmdBuffer->backend.vtbl1->cmdDraw(cmdBuffer, vertexCount, instanceCount, firstVertex, firstInstance); } void PAL_CALL palCmdDrawIndirect( @@ -1325,7 +1153,7 @@ void PAL_CALL palCmdDrawIndirect( PalBuffer* buffer, uint32_t count) { - cmdBuffer->backend->cmdDrawIndirect(cmdBuffer, buffer, count); + cmdBuffer->backend.vtbl1->cmdDrawIndirect(cmdBuffer, buffer, count); } void PAL_CALL palCmdDrawIndirectCount( @@ -1334,7 +1162,7 @@ void PAL_CALL palCmdDrawIndirectCount( PalBuffer* countBuffer, uint32_t maxDrawCount) { - cmdBuffer->backend->cmdDrawIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); + cmdBuffer->backend.vtbl1->cmdDrawIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); } void PAL_CALL palCmdDrawIndexed( @@ -1345,7 +1173,7 @@ void PAL_CALL palCmdDrawIndexed( int32_t vertexOffset, uint32_t firstInstance) { - cmdBuffer->backend->cmdDrawIndexed( + cmdBuffer->backend.vtbl1->cmdDrawIndexed( cmdBuffer, indexCount, instanceCount, @@ -1359,7 +1187,7 @@ void PAL_CALL palCmdDrawIndexedIndirect( PalBuffer* buffer, uint32_t count) { - cmdBuffer->backend->cmdDrawIndexedIndirect(cmdBuffer, buffer, count); + cmdBuffer->backend.vtbl1->cmdDrawIndexedIndirect(cmdBuffer, buffer, count); } void PAL_CALL palCmdDrawIndexedIndirectCount( @@ -1368,7 +1196,7 @@ void PAL_CALL palCmdDrawIndexedIndirectCount( PalBuffer* countBuffer, uint32_t maxDrawCount) { - cmdBuffer->backend->cmdDrawIndexedIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); + cmdBuffer->backend.vtbl1->cmdDrawIndexedIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); } void PAL_CALL palCmdAccelerationStructureBarrier( @@ -1376,7 +1204,7 @@ void PAL_CALL palCmdAccelerationStructureBarrier( PalAccelerationStructure* as, PalBarrierInfo* info) { - cmdBuffer->backend->cmdAccelerationStructureBarrier(cmdBuffer, as, info); + cmdBuffer->backend.vtbl1->cmdAccelerationStructureBarrier(cmdBuffer, as, info); } void PAL_CALL palCmdImageBarrier( @@ -1385,7 +1213,7 @@ void PAL_CALL palCmdImageBarrier( PalImageSubresourceRange* subresourceRange, PalBarrierInfo* info) { - cmdBuffer->backend->cmdImageBarrier(cmdBuffer, image, subresourceRange, info); + cmdBuffer->backend.vtbl1->cmdImageBarrier(cmdBuffer, image, subresourceRange, info); } void PAL_CALL palCmdBufferBarrier( @@ -1393,7 +1221,7 @@ void PAL_CALL palCmdBufferBarrier( PalBuffer* buffer, PalBarrierInfo* info) { - cmdBuffer->backend->cmdBufferBarrier(cmdBuffer, buffer, info); + cmdBuffer->backend.vtbl1->cmdBufferBarrier(cmdBuffer, buffer, info); } void PAL_CALL palCmdDispatch( @@ -1402,7 +1230,7 @@ void PAL_CALL palCmdDispatch( uint32_t groupCountY, uint32_t groupCountZ) { - cmdBuffer->backend->cmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); + cmdBuffer->backend.vtbl1->cmdDispatch(cmdBuffer, groupCountX, groupCountY, groupCountZ); } void PAL_CALL palCmdDispatchBase( @@ -1414,7 +1242,7 @@ void PAL_CALL palCmdDispatchBase( uint32_t groupCountY, uint32_t groupCountZ) { - cmdBuffer->backend->cmdDispatchBase( + cmdBuffer->backend.vtbl1->cmdDispatchBase( cmdBuffer, baseGroupX, baseGroupY, @@ -1428,7 +1256,7 @@ void PAL_CALL palCmdDispatchIndirect( PalCommandBuffer* cmdBuffer, PalBuffer* buffer) { - cmdBuffer->backend->cmdDispatchIndirect(cmdBuffer, buffer); + cmdBuffer->backend.vtbl1->cmdDispatchIndirect(cmdBuffer, buffer); } void PAL_CALL palCmdTraceRays( @@ -1439,7 +1267,7 @@ void PAL_CALL palCmdTraceRays( uint32_t height, uint32_t depth) { - cmdBuffer->backend->cmdTraceRays(cmdBuffer, sbt, raygenIndex, width, height, depth); + cmdBuffer->backend.vtbl1->cmdTraceRays(cmdBuffer, sbt, raygenIndex, width, height, depth); } void PAL_CALL palCmdTraceRaysIndirect( @@ -1448,7 +1276,7 @@ void PAL_CALL palCmdTraceRaysIndirect( PalShaderBindingTable* sbt, PalBuffer* buffer) { - cmdBuffer->backend->cmdTraceRaysIndirect(cmdBuffer, raygenIndex, sbt, buffer); + cmdBuffer->backend.vtbl1->cmdTraceRaysIndirect(cmdBuffer, raygenIndex, sbt, buffer); } void PAL_CALL palCmdBindDescriptorSet( @@ -1456,7 +1284,7 @@ void PAL_CALL palCmdBindDescriptorSet( uint32_t setIndex, PalDescriptorSet* set) { - cmdBuffer->backend->cmdBindDescriptorSet(cmdBuffer, setIndex, set); + cmdBuffer->backend.vtbl1->cmdBindDescriptorSet(cmdBuffer, setIndex, set); } void PAL_CALL palCmdPushConstants( @@ -1465,42 +1293,42 @@ void PAL_CALL palCmdPushConstants( uint32_t size, const void* value) { - cmdBuffer->backend->cmdPushConstants(cmdBuffer, offset, size, value); + cmdBuffer->backend.vtbl1->cmdPushConstants(cmdBuffer, offset, size, value); } void PAL_CALL palCmdSetCullMode( PalCommandBuffer* cmdBuffer, PalCullMode cullMode) { - cmdBuffer->backend->cmdSetCullMode(cmdBuffer, cullMode); + cmdBuffer->backend.vtbl1->cmdSetCullMode(cmdBuffer, cullMode); } void PAL_CALL palCmdSetFrontFace( PalCommandBuffer* cmdBuffer, PalFrontFace frontFace) { - cmdBuffer->backend->cmdSetFrontFace(cmdBuffer, frontFace); + cmdBuffer->backend.vtbl1->cmdSetFrontFace(cmdBuffer, frontFace); } void PAL_CALL palCmdSetPrimitiveTopology( PalCommandBuffer* cmdBuffer, PalPrimitiveTopology topology) { - cmdBuffer->backend->cmdSetPrimitiveTopology(cmdBuffer, topology); + cmdBuffer->backend.vtbl1->cmdSetPrimitiveTopology(cmdBuffer, topology); } void PAL_CALL palCmdSetDepthTestEnable( PalCommandBuffer* cmdBuffer, PalBool enable) { - cmdBuffer->backend->cmdSetDepthTestEnable(cmdBuffer, enable); + cmdBuffer->backend.vtbl1->cmdSetDepthTestEnable(cmdBuffer, enable); } void PAL_CALL palCmdSetDepthWriteEnable( PalCommandBuffer* cmdBuffer, PalBool enable) { - cmdBuffer->backend->cmdSetDepthWriteEnable(cmdBuffer, enable); + cmdBuffer->backend.vtbl1->cmdSetDepthWriteEnable(cmdBuffer, enable); } void PAL_CALL palCmdSetStencilOp( @@ -1511,7 +1339,7 @@ void PAL_CALL palCmdSetStencilOp( PalStencilOp depthFailOp, PalCompareOp compareOp) { - cmdBuffer->backend->cmdSetStencilOp( + cmdBuffer->backend.vtbl1->cmdSetStencilOp( cmdBuffer, faceMask, failOp, @@ -1535,7 +1363,7 @@ PalResult PAL_CALL palCreateAccelerationstructure( PalResult result; PalAccelerationStructure* as = nullptr; - result = device->backend->createAccelerationstructure(device, info, &as); + result = device->backend.vtbl1->createAccelerationstructure(device, info, &as); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1547,7 +1375,7 @@ PalResult PAL_CALL palCreateAccelerationstructure( void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* as) { - as->backend->destroyAccelerationstructure(as); + as->backend.vtbl1->destroyAccelerationstructure(as); } void PAL_CALL palGetAccelerationStructureBuildSize( @@ -1555,7 +1383,7 @@ void PAL_CALL palGetAccelerationStructureBuildSize( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { - device->backend->getAccelerationStructureBuildSize(device, info, size); + device->backend.vtbl1->getAccelerationStructureBuildSize(device, info, size); } // ================================================== @@ -1573,7 +1401,7 @@ PalResult PAL_CALL palCreateBuffer( PalResult result; PalBuffer* buffer = nullptr; - result = device->backend->createBuffer(device, info, &buffer); + result = device->backend.vtbl1->createBuffer(device, info, &buffer); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1585,14 +1413,14 @@ PalResult PAL_CALL palCreateBuffer( void PAL_CALL palDestroyBuffer(PalBuffer* buffer) { - buffer->backend->destroyBuffer(buffer); + buffer->backend.vtbl1->destroyBuffer(buffer); } void PAL_CALL palGetBufferMemoryRequirements( PalBuffer* buffer, PalMemoryRequirements* requirements) { - buffer->backend->getBufferMemoryRequirements(buffer, requirements); + buffer->backend.vtbl1->getBufferMemoryRequirements(buffer, requirements); } void PAL_CALL palComputeInstanceStagingSize( @@ -1600,7 +1428,7 @@ void PAL_CALL palComputeInstanceStagingSize( uint32_t instanceCount, uint64_t* outSize) { - device->backend->computeInstanceStagingSize(device, instanceCount, outSize); + device->backend.vtbl1->computeInstanceStagingSize(device, instanceCount, outSize); } void PAL_CALL palComputeImageStagingRequirements( @@ -1609,7 +1437,7 @@ void PAL_CALL palComputeImageStagingRequirements( const PalBufferImageCopyInfo* copyInfo, PalImageStagingRequirements* requirements) { - device->backend->computeImageStagingRequirements( + device->backend.vtbl1->computeImageStagingRequirements( device, imageFormat, copyInfo, @@ -1622,7 +1450,7 @@ void PAL_CALL palWriteInstanceStaging( PalAccelerationStructureInstance* instances, void* ptr) { - device->backend->writeInstanceStaging(device, instanceCount, instances, ptr); + device->backend.vtbl1->writeInstanceStaging(device, instanceCount, instances, ptr); } void PAL_CALL palWriteImageStaging( @@ -1632,7 +1460,7 @@ void PAL_CALL palWriteImageStaging( void* srcData, void* ptr) { - device->backend->writeImageStaging(device, imageFormat, copyInfo, srcData, ptr); + device->backend.vtbl1->writeImageStaging(device, imageFormat, copyInfo, srcData, ptr); } PalResult PAL_CALL palBindBufferMemory( @@ -1640,7 +1468,7 @@ PalResult PAL_CALL palBindBufferMemory( PalMemory* memory, uint64_t offset) { - return buffer->backend->bindBufferMemory(buffer, memory, offset); + return buffer->backend.vtbl1->bindBufferMemory(buffer, memory, offset); } PalResult PAL_CALL palMapBuffer( @@ -1649,17 +1477,17 @@ PalResult PAL_CALL palMapBuffer( uint64_t size, void** outPtr) { - return buffer->backend->mapBuffer(buffer, offset, size, outPtr); + return buffer->backend.vtbl1->mapBuffer(buffer, offset, size, outPtr); } void PAL_CALL palUnmapBuffer(PalBuffer* buffer) { - buffer->backend->unmapBuffer(buffer); + buffer->backend.vtbl1->unmapBuffer(buffer); } PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer) { - return buffer->backend->getBufferDeviceAddress(buffer); + return buffer->backend.vtbl1->getBufferDeviceAddress(buffer); } // ================================================== @@ -1677,7 +1505,7 @@ PalResult PAL_CALL palCreateDescriptorSetLayout( PalResult result; PalDescriptorSetLayout* layout = nullptr; - result = device->backend->createDescriptorSetLayout(device, info, &layout); + result = device->backend.vtbl1->createDescriptorSetLayout(device, info, &layout); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1689,7 +1517,7 @@ PalResult PAL_CALL palCreateDescriptorSetLayout( void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layout) { - layout->backend->destroyDescriptorSetLayout(layout); + layout->backend.vtbl1->destroyDescriptorSetLayout(layout); } PalResult PAL_CALL palCreateDescriptorPool( @@ -1703,7 +1531,7 @@ PalResult PAL_CALL palCreateDescriptorPool( PalResult result; PalDescriptorPool* pool = nullptr; - result = device->backend->createDescriptorPool(device, info, &pool); + result = device->backend.vtbl1->createDescriptorPool(device, info, &pool); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1715,12 +1543,12 @@ PalResult PAL_CALL palCreateDescriptorPool( void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool) { - pool->backend->destroyDescriptorPool(pool); + pool->backend.vtbl1->destroyDescriptorPool(pool); } PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool) { - return pool->backend->resetDescriptorPool(pool); + return pool->backend.vtbl1->resetDescriptorPool(pool); } PalResult PAL_CALL palAllocateDescriptorSet( @@ -1735,7 +1563,7 @@ PalResult PAL_CALL palAllocateDescriptorSet( PalResult result; PalDescriptorSet* set = nullptr; - result = device->backend->allocateDescriptorSet(device, pool, layout, &set); + result = device->backend.vtbl1->allocateDescriptorSet(device, pool, layout, &set); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1750,7 +1578,7 @@ PalResult PAL_CALL palUpdateDescriptorSet( uint32_t count, PalDescriptorSetWriteInfo* infos) { - return device->backend->updateDescriptorSet(device, count, infos); + return device->backend.vtbl1->updateDescriptorSet(device, count, infos); } // ================================================== @@ -1768,7 +1596,7 @@ PalResult PAL_CALL palCreatePipelineLayout( PalResult result; PalPipelineLayout* layout = nullptr; - result = device->backend->createPipelineLayout(device, info, &layout); + result = device->backend.vtbl1->createPipelineLayout(device, info, &layout); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1780,7 +1608,7 @@ PalResult PAL_CALL palCreatePipelineLayout( void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout) { - layout->backend->destroyPipelineLayout(layout); + layout->backend.vtbl1->destroyPipelineLayout(layout); } // ================================================== @@ -1798,7 +1626,7 @@ PalResult PAL_CALL palCreateGraphicsPipeline( PalResult result; PalPipeline* pipeline = nullptr; - result = device->backend->createGraphicsPipeline(device, info, &pipeline); + result = device->backend.vtbl1->createGraphicsPipeline(device, info, &pipeline); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1819,7 +1647,7 @@ PalResult PAL_CALL palCreateComputePipeline( PalResult result; PalPipeline* pipeline = nullptr; - result = device->backend->createComputePipeline(device, info, &pipeline); + result = device->backend.vtbl1->createComputePipeline(device, info, &pipeline); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1840,7 +1668,7 @@ PalResult PAL_CALL palCreateRayTracingPipeline( PalResult result; PalPipeline* pipeline = nullptr; - result = device->backend->createRayTracingPipeline(device, info, &pipeline); + result = device->backend.vtbl1->createRayTracingPipeline(device, info, &pipeline); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1852,7 +1680,7 @@ PalResult PAL_CALL palCreateRayTracingPipeline( void PAL_CALL palDestroyPipeline(PalPipeline* pipeline) { - pipeline->backend->destroyPipeline(pipeline); + pipeline->backend.vtbl1->destroyPipeline(pipeline); } // ================================================== @@ -1870,7 +1698,7 @@ PalResult PAL_CALL palCreateShaderBindingTable( PalResult result; PalShaderBindingTable* sbt = nullptr; - result = device->backend->createShaderBindingTable(device, info, &sbt); + result = device->backend.vtbl1->createShaderBindingTable(device, info, &sbt); if (result != PAL_RESULT_SUCCESS) { return result; } @@ -1882,7 +1710,7 @@ PalResult PAL_CALL palCreateShaderBindingTable( void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt) { - sbt->backend->destroyShaderBindingTable(sbt); + sbt->backend.vtbl1->destroyShaderBindingTable(sbt); } void PAL_CALL palUpdateShaderBindingTable( @@ -1890,7 +1718,7 @@ void PAL_CALL palUpdateShaderBindingTable( uint32_t count, PalShaderBindingTableRecordInfo* infos) { - sbt->backend->updateShaderBindingTable(sbt, count, infos); + sbt->backend.vtbl1->updateShaderBindingTable(sbt, count, infos); } // ================================================== diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index ecbd7671..3caf2d06 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -12,145 +12,7 @@ // clang-format off typedef struct { - PalResult (PAL_CALL *enumerateAdapters)(uint32_t*, PalAdapter**); - void (PAL_CALL *getAdapterInfo)(PalAdapter*, PalAdapterInfo*); - void (PAL_CALL *getAdapterCapabilities)(PalAdapter*, PalAdapterCapabilities*); - PalAdapterFeatures (PAL_CALL *getAdapterFeatures)(PalAdapter*); - uint32_t (PAL_CALL *getHighestSupportedShaderTarget)(PalAdapter*, PalShaderFormats); - PalResult (PAL_CALL *createDevice)(PalAdapter*, PalAdapterFeatures, PalDevice**); - void (PAL_CALL *destroyDevice)(PalDevice*); - PalResult (PAL_CALL *allocateMemory)(PalDevice*, PalMemoryType, uint64_t, uint64_t, PalMemory**); - void (PAL_CALL *freeMemory)(PalMemory*); - void (PAL_CALL *querySamplerAnisotropyCapabilities)(PalDevice*, PalSamplerAnisotropyCapabilities*); - void (PAL_CALL *queryMultiViewCapabilities)(PalDevice*, PalMultiViewCapabilities*); - void (PAL_CALL *queryMultiViewportCapabilities)(PalDevice*, PalMultiViewportCapabilities*); - void (PAL_CALL *queryDepthStencilCapabilities)(PalDevice*, PalDepthStencilCapabilities*); - void (PAL_CALL *queryFragmentShadingRateCapabilities)(PalDevice*, PalFragmentShadingRateCapabilities*); - void (PAL_CALL *queryMeshShaderCapabilities)(PalDevice*, PalMeshShaderCapabilities*); - void (PAL_CALL *queryRayTracingCapabilities)(PalDevice*, PalRayTracingCapabilities*); - void (PAL_CALL *queryDescriptorIndexingCapabilities)(PalDevice*, PalDescriptorIndexingCapabilities*); - - PalResult (PAL_CALL *createQueue)(PalDevice*, PalQueueType, PalQueue**); - void (PAL_CALL *destroyQueue)(PalQueue*); - PalBool (PAL_CALL *canQueuePresent)(PalQueue*, PalSurface*); - PalResult (PAL_CALL *waitQueue)(PalQueue*); - void (PAL_CALL *enumerateFormats)(PalAdapter*, uint32_t*, PalFormatInfo*); - PalBool (PAL_CALL *isFormatSupported)(PalAdapter*, PalFormat); - PalImageUsages (PAL_CALL *queryFormatImageUsages)(PalAdapter*, PalFormat); - PalSampleCount (PAL_CALL *queryFormatSampleCount)(PalAdapter*, PalFormat); - PalResult (PAL_CALL *createImage)(PalDevice*, const PalImageCreateInfo*, PalImage**); - void (PAL_CALL *destroyImage)(PalImage*); - void (PAL_CALL *getImageInfo)(PalImage*, PalImageInfo*); - void (PAL_CALL *getImageMemoryRequirements)(PalImage*, PalMemoryRequirements*); - PalResult (PAL_CALL *bindImageMemory)(PalImage*, PalMemory*, uint64_t); - PalResult (PAL_CALL *createImageView)(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); - void (PAL_CALL *destroyImageView)(PalImageView*); - - PalResult (PAL_CALL *createSampler)(PalDevice*, const PalSamplerCreateInfo*, PalSampler**); - void (PAL_CALL *destroySampler)(PalSampler*); - PalResult (PAL_CALL *createSurface)(PalDevice*, void*, void*, PalWindowInstanceType, PalSurface**); - void (PAL_CALL *destroySurface)(PalSurface*); - void (PAL_CALL *getSurfaceCapabilities)(PalDevice*, PalSurface*, PalSurfaceCapabilities*); - PalResult (PAL_CALL *createSwapchain)(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); - void (PAL_CALL *destroySwapchain)(PalSwapchain*); - PalImage* (PAL_CALL *getSwapchainImage)(PalSwapchain*, uint32_t); - PalResult (PAL_CALL *getNextSwapchainImage)(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t*); - PalResult (PAL_CALL *presentSwapchain)(PalSwapchain*, uint32_t, PalSemaphore*); - PalResult (PAL_CALL *resizeSwapchain)(PalSwapchain*, uint32_t, uint32_t); - PalResult (PAL_CALL *createShader)(PalDevice*, const PalShaderCreateInfo*, PalShader**); - void (PAL_CALL *destroyShader)(PalShader*); - PalResult (PAL_CALL *createFence)(PalDevice*, PalBool, PalFence**); - void (PAL_CALL *destroyFence)(PalFence*); - PalResult (PAL_CALL *waitFence)(PalFence*, uint64_t); - PalResult (PAL_CALL *resetFence)(PalFence*); - PalBool (PAL_CALL *isFenceSignaled)(PalFence*); - - PalResult (PAL_CALL *createSemaphore)(PalDevice*, PalBool, PalSemaphore**); - void (PAL_CALL *destroySemaphore)(PalSemaphore*); - PalResult (PAL_CALL *waitSemaphore)(PalSemaphore*, uint64_t, uint64_t); - PalResult (PAL_CALL *signalSemaphore)(PalSemaphore*, PalQueue*, uint64_t); - PalResult (PAL_CALL *getSemaphoreValue)(PalSemaphore*, uint64_t*); - PalResult (PAL_CALL *createCommandPool)(PalDevice*, PalQueue*, PalCommandPool**); - void (PAL_CALL *destroyCommandPool)(PalCommandPool*); - PalResult (PAL_CALL *allocateCommandBuffer)(PalDevice*, PalCommandPool*, PalCommandBufferType, PalCommandBuffer**); - void (PAL_CALL *freeCommandBuffer)(PalCommandBuffer*); - PalResult (PAL_CALL *resetCommandBuffer)(PalCommandBuffer*); - PalResult (PAL_CALL *submitCommandBuffer)(PalQueue*, PalCommandBufferSubmitInfo*); - - PalResult (PAL_CALL *cmdBegin)(PalCommandBuffer*, PalRenderingLayoutInfo*); - PalResult (PAL_CALL *cmdEnd)(PalCommandBuffer*); - void (PAL_CALL *cmdExecuteCommandBuffer)(PalCommandBuffer*, PalCommandBuffer*); - void (PAL_CALL *cmdSetFragmentShadingRate)(PalCommandBuffer*, PalFragmentShadingRateState*); - void (PAL_CALL *cmdDrawMeshTasks)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); - void (PAL_CALL *cmdDrawMeshTasksIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); - void (PAL_CALL *cmdDrawMeshTasksIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); - void (PAL_CALL *cmdBuildAccelerationStructure)(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); - void (PAL_CALL *cmdBeginRendering)(PalCommandBuffer*, PalRenderingInfo*); - void (PAL_CALL *cmdEndRendering)(PalCommandBuffer*); - void (PAL_CALL *cmdCopyBuffer)(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); - void (PAL_CALL *cmdCopyBufferToImage)(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); - void (PAL_CALL *cmdCopyImage)(PalCommandBuffer*, PalImage*,PalImage*, PalImageCopyInfo*); - void (PAL_CALL *cmdCopyImageToBuffer)(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); - void (PAL_CALL *cmdBindPipeline)(PalCommandBuffer*, PalPipeline*); - void (PAL_CALL *cmdSetViewport)(PalCommandBuffer*, uint32_t, PalViewport*); - void (PAL_CALL *cmdSetScissors)(PalCommandBuffer*, uint32_t, PalRect2D*); - void (PAL_CALL *cmdBindVertexBuffers)(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); - void (PAL_CALL *cmdBindIndexBuffer)(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); - void (PAL_CALL *cmdDraw)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); - void (PAL_CALL *cmdDrawIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); - void (PAL_CALL *cmdDrawIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); - void (PAL_CALL *cmdDrawIndexed)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); - void (PAL_CALL *cmdDrawIndexedIndirect)(PalCommandBuffer*, PalBuffer*, uint32_t); - void (PAL_CALL *cmdDrawIndexedIndirectCount)(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); - void (PAL_CALL *cmdAccelerationStructureBarrier)(PalCommandBuffer*, PalAccelerationStructure*, PalBarrierInfo*); - void (PAL_CALL *cmdImageBarrier)(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalBarrierInfo*); - void (PAL_CALL *cmdBufferBarrier)(PalCommandBuffer*, PalBuffer*, PalBarrierInfo*); - void (PAL_CALL *cmdDispatch)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); - void (PAL_CALL *cmdDispatchBase)(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); - void (PAL_CALL *cmdDispatchIndirect)(PalCommandBuffer*, PalBuffer*); - void (PAL_CALL *cmdTraceRays)(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); - void (PAL_CALL *cmdTraceRaysIndirect)(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); - void (PAL_CALL *cmdBindDescriptorSet)(PalCommandBuffer*, uint32_t, PalDescriptorSet*); - void (PAL_CALL *cmdPushConstants)(PalCommandBuffer*, uint32_t, uint32_t, const void*); - void (PAL_CALL *cmdSetCullMode)(PalCommandBuffer*, PalCullMode); - void (PAL_CALL *cmdSetFrontFace)(PalCommandBuffer*, PalFrontFace); - void (PAL_CALL *cmdSetPrimitiveTopology)(PalCommandBuffer*, PalPrimitiveTopology); - void (PAL_CALL *cmdSetDepthTestEnable)(PalCommandBuffer*, PalBool); - void (PAL_CALL *cmdSetDepthWriteEnable)(PalCommandBuffer*, PalBool); - void (PAL_CALL *cmdSetStencilOp)(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); - - PalResult (PAL_CALL *createAccelerationstructure)(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); - void (PAL_CALL *destroyAccelerationstructure)(PalAccelerationStructure*); - void (PAL_CALL *getAccelerationStructureBuildSize)(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); - PalResult (PAL_CALL *createBuffer)(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); - void (PAL_CALL *destroyBuffer)(PalBuffer*); - void (PAL_CALL *getBufferMemoryRequirements)(PalBuffer*, PalMemoryRequirements*); - void(PAL_CALL* computeInstanceStagingSize)(PalDevice*, uint32_t, uint64_t*); - void(PAL_CALL* computeImageStagingRequirements)(PalDevice*, PalFormat, const PalBufferImageCopyInfo*, PalImageStagingRequirements*); - void(PAL_CALL* writeInstanceStaging)(PalDevice*, uint32_t, PalAccelerationStructureInstance*, void*); - void(PAL_CALL* writeImageStaging)(PalDevice*, PalFormat, PalBufferImageCopyInfo*, void*, void*); - PalResult (PAL_CALL *bindBufferMemory)(PalBuffer*, PalMemory*, uint64_t); - PalResult (PAL_CALL *mapBuffer)(PalBuffer*, uint64_t, uint64_t, void**); - void (PAL_CALL *unmapBuffer)(PalBuffer*); - PalDeviceAddress (PAL_CALL *getBufferDeviceAddress)(PalBuffer*); - - PalResult (PAL_CALL *createDescriptorSetLayout)(PalDevice*, const PalDescriptorSetLayoutCreateInfo*, PalDescriptorSetLayout**); - void (PAL_CALL *destroyDescriptorSetLayout)(PalDescriptorSetLayout*); - PalResult (PAL_CALL *createDescriptorPool)(PalDevice*, const PalDescriptorPoolCreateInfo*, PalDescriptorPool**); - void (PAL_CALL *destroyDescriptorPool)(PalDescriptorPool*); - PalResult (PAL_CALL *resetDescriptorPool)(PalDescriptorPool*); - PalResult (PAL_CALL *allocateDescriptorSet)(PalDevice*, PalDescriptorPool*, PalDescriptorSetLayout*, PalDescriptorSet**); - PalResult (PAL_CALL *updateDescriptorSet)(PalDevice*, uint32_t, PalDescriptorSetWriteInfo*); - - PalResult (PAL_CALL *createPipelineLayout)(PalDevice*, const PalPipelineLayoutCreateInfo*, PalPipelineLayout**); - void (PAL_CALL *destroyPipelineLayout)(PalPipelineLayout*); - PalResult (PAL_CALL *createGraphicsPipeline)(PalDevice*, const PalGraphicsPipelineCreateInfo*, PalPipeline**); - PalResult (PAL_CALL *createComputePipeline)(PalDevice*, const PalComputePipelineCreateInfo*, PalPipeline**); - PalResult (PAL_CALL *createRayTracingPipeline)(PalDevice*, const PalRayTracingPipelineCreateInfo*, PalPipeline**); - void (PAL_CALL *destroyPipeline)(PalPipeline*); - PalResult (PAL_CALL *createShaderBindingTable)(PalDevice*, const PalShaderBindingTableCreateInfo*, PalShaderBindingTable**); - void (PAL_CALL *destroyShaderBindingTable)(PalShaderBindingTable*); - void (PAL_CALL *updateShaderBindingTable)(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); + const PalGraphicsBackendVtable1* vtbl1; } PalGraphicsVtable; // ================================================== @@ -158,149 +20,592 @@ typedef struct { // ================================================== #if PAL_HAS_VULKAN_BACKEND -PalResult PAL_CALL initGraphicsVk(const PalGraphicsDebugger*, const PalAllocator*); +PalResult PAL_CALL initGraphicsVk( + const PalGraphicsDebugger* debugger, + const PalAllocator* allocator); + void PAL_CALL shutdownGraphicsVk(); -PalResult PAL_CALL enumerateAdaptersVk(uint32_t*, PalAdapter**); -void PAL_CALL getAdapterInfoVk(PalAdapter*, PalAdapterInfo*); -void PAL_CALL getAdapterCapabilitiesVk(PalAdapter*, PalAdapterCapabilities*); -PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter*); -uint32_t PAL_CALL getHighestSupportedShaderTargetVk(PalAdapter*, PalShaderFormats); -PalResult PAL_CALL createDeviceVk(PalAdapter*, PalAdapterFeatures, PalDevice**); -void PAL_CALL destroyDeviceVk(PalDevice*); -PalResult PAL_CALL waitDeviceVk(PalDevice*); -PalResult PAL_CALL allocateMemoryVk(PalDevice*, PalMemoryType, uint64_t, uint64_t, PalMemory**); -void PAL_CALL freeMemoryVk(PalMemory*); -void PAL_CALL querySamplerAnisotropyCapabilitiesVk(PalDevice*, PalSamplerAnisotropyCapabilities*); -void PAL_CALL queryMultiViewCapabilitiesVk(PalDevice*, PalMultiViewCapabilities*); -void PAL_CALL queryMultiViewportCapabilitiesVk(PalDevice*, PalMultiViewportCapabilities*); -void PAL_CALL queryDepthStencilCapabilitiesVk(PalDevice*, PalDepthStencilCapabilities*); -void PAL_CALL queryFragmentShadingRateCapabilitiesVk(PalDevice*, PalFragmentShadingRateCapabilities*); -void PAL_CALL queryMeshShaderCapabilitiesVk(PalDevice*, PalMeshShaderCapabilities*); -void PAL_CALL queryRayTracingCapabilitiesVk(PalDevice*, PalRayTracingCapabilities*); -void PAL_CALL queryDescriptorIndexingCapabilitiesVk(PalDevice*, PalDescriptorIndexingCapabilities*); - -PalResult PAL_CALL createQueueVk(PalDevice*, PalQueueType, PalQueue**); -void PAL_CALL destroyQueueVk(PalQueue*); -PalResult PAL_CALL waitQueueVk(PalQueue*); -PalBool PAL_CALL canQueuePresentVk(PalQueue*, PalSurface*); -void PAL_CALL enumerateFormatsVk(PalAdapter*, uint32_t*, PalFormatInfo*); -PalBool PAL_CALL isFormatSupportedVk(PalAdapter*, PalFormat); -PalImageUsages PAL_CALL queryFormatImageUsagesVk(PalAdapter*, PalFormat); -PalSampleCount PAL_CALL queryFormatSampleCountVk(PalAdapter*, PalFormat); -PalResult PAL_CALL createImageVk(PalDevice*, const PalImageCreateInfo*, PalImage**); -void PAL_CALL destroyImageVk(PalImage*); -void PAL_CALL getImageInfoVk(PalImage*, PalImageInfo*); -void PAL_CALL getImageMemoryRequirementsVk(PalImage*, PalMemoryRequirements*); -PalResult PAL_CALL bindImageMemoryVk(PalImage*, PalMemory*, uint64_t); -PalResult PAL_CALL createImageViewVk(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); -void PAL_CALL destroyImageViewVk(PalImageView*); - -PalResult PAL_CALL createSamplerVk(PalDevice*, const PalSamplerCreateInfo*, PalSampler**); -void PAL_CALL destroySamplerVk(PalSampler*); -PalResult PAL_CALL createSurfaceVk(PalDevice*, void*, void*, PalWindowInstanceType, PalSurface**); -void PAL_CALL destroySurfaceVk(PalSurface*); -void PAL_CALL getSurfaceCapabilitiesVk(PalDevice*, PalSurface*, PalSurfaceCapabilities*); -PalResult PAL_CALL createSwapchainVk(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); -void PAL_CALL destroySwapchainVk(PalSwapchain*); -PalImage* PAL_CALL getSwapchainImageVk(PalSwapchain*, uint32_t); -PalResult PAL_CALL getNextSwapchainImageVk(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t*); -PalResult PAL_CALL presentSwapchainVk(PalSwapchain*, uint32_t, PalSemaphore*); -PalResult PAL_CALL resizeSwapchainVk(PalSwapchain*, uint32_t, uint32_t); -PalResult PAL_CALL createShaderVk(PalDevice*, const PalShaderCreateInfo*, PalShader**); -void PAL_CALL destroyShaderVk(PalShader*); - -PalResult PAL_CALL createFenceVk(PalDevice*, PalBool, PalFence**); -void PAL_CALL destroyFenceVk(PalFence*); -PalResult PAL_CALL waitFenceVk(PalFence*, uint64_t); -PalResult PAL_CALL resetFenceVk(PalFence*); -PalBool PAL_CALL isFenceSignaledVk(PalFence*); -PalResult PAL_CALL createSemaphoreVk(PalDevice*, PalBool, PalSemaphore**); -void PAL_CALL destroySemaphoreVk(PalSemaphore*); -PalResult PAL_CALL waitSemaphoreVk(PalSemaphore*, uint64_t, uint64_t); -PalResult PAL_CALL signalSemaphoreVk(PalSemaphore*, PalQueue*, uint64_t); -PalResult PAL_CALL getSemaphoreValueVk(PalSemaphore*, uint64_t*); -PalResult PAL_CALL createCommandPoolVk(PalDevice*, PalQueue*, PalCommandPool**); -void PAL_CALL destroyCommandPoolVk(PalCommandPool*); -PalResult PAL_CALL allocateCommandBufferVk(PalDevice*, PalCommandPool*, PalCommandBufferType, PalCommandBuffer**); -void PAL_CALL freeCommandBufferVk(PalCommandBuffer*); -PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer*); -PalResult PAL_CALL submitCommandBufferVk(PalQueue*, PalCommandBufferSubmitInfo*); - -PalResult PAL_CALL cmdBeginVk(PalCommandBuffer*, PalRenderingLayoutInfo*); -PalResult PAL_CALL cmdEndVk(PalCommandBuffer*); -void PAL_CALL cmdExecuteCommandBufferVk(PalCommandBuffer*, PalCommandBuffer*); -void PAL_CALL cmdSetFragmentShadingRateVk(PalCommandBuffer*, PalFragmentShadingRateState*); -void PAL_CALL cmdDrawMeshTasksVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); -void PAL_CALL cmdDrawMeshTasksIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdDrawMeshTasksIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdBuildAccelerationStructureVk(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); -void PAL_CALL cmdBeginRenderingVk(PalCommandBuffer*, PalRenderingInfo*); -void PAL_CALL cmdEndRenderingVk(PalCommandBuffer*); -void PAL_CALL cmdCopyBufferVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); -void PAL_CALL cmdCopyBufferToImageVk(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); -void PAL_CALL cmdCopyImageVk(PalCommandBuffer*, PalImage*, PalImage*, PalImageCopyInfo*); -void PAL_CALL cmdCopyImageToBufferVk(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); -void PAL_CALL cmdBindPipelineVk(PalCommandBuffer*, PalPipeline*); -void PAL_CALL cmdSetViewportVk(PalCommandBuffer*, uint32_t, PalViewport*); -void PAL_CALL cmdSetScissorsVk(PalCommandBuffer*, uint32_t, PalRect2D*); -void PAL_CALL cmdBindVertexBuffersVk(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); -void PAL_CALL cmdBindIndexBufferVk(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); -void PAL_CALL cmdDrawVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); -void PAL_CALL cmdDrawIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdDrawIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdDrawIndexedVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); -void PAL_CALL cmdDrawIndexedIndirectVk(PalCommandBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdDrawIndexedIndirectCountVk(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdAccelerationStructureBarrierVk(PalCommandBuffer*, PalAccelerationStructure*, PalBarrierInfo*); -void PAL_CALL cmdImageBarrierVk(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalBarrierInfo*); -void PAL_CALL cmdBufferBarrierVk(PalCommandBuffer*, PalBuffer*, PalBarrierInfo*); -void PAL_CALL cmdDispatchVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); -void PAL_CALL cmdDispatchBaseVk(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); -void PAL_CALL cmdDispatchIndirectVk(PalCommandBuffer*, PalBuffer*); -void PAL_CALL cmdTraceRaysVk(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); -void PAL_CALL cmdTraceRaysIndirectVk(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); -void PAL_CALL cmdBindDescriptorSetVk(PalCommandBuffer*, uint32_t, PalDescriptorSet*); -void PAL_CALL cmdPushConstantsVk(PalCommandBuffer*, uint32_t, uint32_t, const void*); -void PAL_CALL cmdSetCullModeVk(PalCommandBuffer*, PalCullMode); -void PAL_CALL cmdSetFrontFaceVk(PalCommandBuffer*, PalFrontFace); -void PAL_CALL cmdSetPrimitiveTopologyVk(PalCommandBuffer*, PalPrimitiveTopology); -void PAL_CALL cmdSetDepthTestEnableVk(PalCommandBuffer*, PalBool); -void PAL_CALL cmdSetDepthWriteEnableVk(PalCommandBuffer*, PalBool); -void PAL_CALL cmdSetStencilOpVk(PalCommandBuffer*, PalStencilFaceFlags, PalStencilOp, PalStencilOp, PalStencilOp, PalCompareOp); - -PalResult PAL_CALL createAccelerationstructureVk(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); -void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure*); -void PAL_CALL getAccelerationStructureBuildSizeVk(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); -PalResult PAL_CALL createBufferVk(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); -void PAL_CALL destroyBufferVk(PalBuffer*); -void PAL_CALL getBufferMemoryRequirementsVk(PalBuffer*, PalMemoryRequirements*); -void PAL_CALL computeInstanceStagingSizeVk(PalDevice*, uint32_t, uint64_t*); -void PAL_CALL computeImageStagingRequirementsVk(PalDevice*, PalFormat, const PalBufferImageCopyInfo*, PalImageStagingRequirements*); -void PAL_CALL writeInstanceStagingVk(PalDevice*, uint32_t, PalAccelerationStructureInstance*, void*); -void PAL_CALL writeImageStagingVk(PalDevice*, PalFormat, PalBufferImageCopyInfo*, void*, void*); -PalResult PAL_CALL bindBufferMemoryVk(PalBuffer*, PalMemory*, uint64_t); -PalResult PAL_CALL mapBufferVk(PalBuffer*, uint64_t, uint64_t, void**); -void PAL_CALL unmapBufferVk(PalBuffer*); -PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer*); -PalResult PAL_CALL createDescriptorSetLayoutVk(PalDevice*, const PalDescriptorSetLayoutCreateInfo*, PalDescriptorSetLayout**); -void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout*); -PalResult PAL_CALL createDescriptorPoolVk(PalDevice*, const PalDescriptorPoolCreateInfo*, PalDescriptorPool**); -void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool*); -PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool*); -PalResult PAL_CALL allocateDescriptorSetVk(PalDevice*, PalDescriptorPool*, PalDescriptorSetLayout*, PalDescriptorSet**); -PalResult PAL_CALL updateDescriptorSetVk(PalDevice*, uint32_t, PalDescriptorSetWriteInfo*); - -PalResult PAL_CALL createPipelineLayoutVk(PalDevice*, const PalPipelineLayoutCreateInfo*, PalPipelineLayout**); -void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout*); -PalResult PAL_CALL createGraphicsPipelineVk(PalDevice*, const PalGraphicsPipelineCreateInfo*, PalPipeline**); -PalResult PAL_CALL createComputePipelineVk(PalDevice*, const PalComputePipelineCreateInfo*, PalPipeline**); -PalResult PAL_CALL createRayTracingPipelineVk(PalDevice*, const PalRayTracingPipelineCreateInfo*, PalPipeline**); -void PAL_CALL destroyPipelineVk(PalPipeline*); -PalResult PAL_CALL createShaderBindingTableVk(PalDevice*, const PalShaderBindingTableCreateInfo*, PalShaderBindingTable**); -void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable*); -void PAL_CALL updateShaderBindingTableVk(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); - -static PalGraphicsVtable s_VkBackend = { + +PalResult PAL_CALL enumerateAdaptersVk( + uint32_t* count, + PalAdapter** outAdapters); + +void PAL_CALL getAdapterInfoVk( + PalAdapter* adapter, + PalAdapterInfo* info); + +void PAL_CALL getAdapterCapabilitiesVk( + PalAdapter* adapter, + PalAdapterCapabilities* caps); + +PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter); + +uint32_t PAL_CALL getHighestSupportedShaderTargetVk( + PalAdapter* adapter, + PalShaderFormats shaderFormat); + +PalResult PAL_CALL createDeviceVk( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); + +void PAL_CALL destroyDeviceVk(PalDevice* device); + +PalResult PAL_CALL allocateMemoryVk( + PalDevice* device, + PalMemoryType type, + uint64_t memoryMask, + uint64_t size, + PalMemory** outMemory); + +void PAL_CALL freeMemoryVk(PalMemory* memory); + +void PAL_CALL querySamplerAnisotropyCapabilitiesVk( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps); + +void PAL_CALL queryMultiViewCapabilitiesVk( + PalDevice* device, + PalMultiViewCapabilities* caps); + +void PAL_CALL queryMultiViewportCapabilitiesVk( + PalDevice* device, + PalMultiViewportCapabilities* caps); + +void PAL_CALL queryDepthStencilCapabilitiesVk( + PalDevice* device, + PalDepthStencilCapabilities* caps); + +void PAL_CALL queryFragmentShadingRateCapabilitiesVk( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); + +void PAL_CALL queryMeshShaderCapabilitiesVk( + PalDevice* device, + PalMeshShaderCapabilities* caps); + +void PAL_CALL queryRayTracingCapabilitiesVk( + PalDevice* device, + PalRayTracingCapabilities* caps); + +void PAL_CALL queryDescriptorIndexingCapabilitiesVk( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); + +PalResult PAL_CALL createQueueVk( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); + +void PAL_CALL destroyQueueVk(PalQueue* queue); + +PalBool PAL_CALL canQueuePresentVk( + PalQueue* queue, + PalSurface* surface); + +PalResult PAL_CALL waitQueueVk(PalQueue* queue); + +void PAL_CALL enumerateFormatsVk( + PalAdapter* adapter, + uint32_t* count, + PalFormatInfo* outFormats); + +PalBool PAL_CALL isFormatSupportedVk( + PalAdapter* adapter, + PalFormat format); + +PalImageUsages PAL_CALL queryFormatImageUsagesVk( + PalAdapter* adapter, + PalFormat format); + +PalSampleCount PAL_CALL queryFormatSampleCountVk( + PalAdapter* adapter, + PalFormat format); + +PalResult PAL_CALL createImageVk( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + +void PAL_CALL destroyImageVk(PalImage* image); + +void PAL_CALL getImageInfoVk( + PalImage* image, + PalImageInfo* info); + +void PAL_CALL getImageMemoryRequirementsVk( + PalImage* image, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL bindImageMemoryVk( + PalImage* image, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL createImageViewVk( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + +void PAL_CALL destroyImageViewVk(PalImageView* imageView); + +PalResult PAL_CALL createSamplerVk( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler); + +void PAL_CALL destroySamplerVk(PalSampler* sampler); + +PalResult PAL_CALL createSurfaceVk( + PalDevice* device, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, + PalSurface** outSurface); + +void PAL_CALL destroySurfaceVk(PalSurface* surface); + +void PAL_CALL getSurfaceCapabilitiesVk( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps); + +PalResult PAL_CALL createSwapchainVk( + PalDevice* device, + PalQueue* queue, + PalSurface* surface, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + +void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain); + +PalImage* PAL_CALL getSwapchainImageVk( + PalSwapchain* swapchain, + uint32_t index); + +PalResult PAL_CALL getNextSwapchainImageVk( + PalSwapchain* swapchain, + PalSwapchainNextImageInfo* info, + uint32_t* outIndex); + +PalResult PAL_CALL presentSwapchainVk( + PalSwapchain* swapchain, + uint32_t imageIndex, + PalSemaphore* waitSemaphore); + +PalResult PAL_CALL resizeSwapchainVk( + PalSwapchain* swapchain, + uint32_t newWidth, + uint32_t newHeight); + +PalResult PAL_CALL createShaderVk( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + +void PAL_CALL destroyShaderVk(PalShader* shader); + +PalResult PAL_CALL createFenceVk( + PalDevice* device, + PalBool signaled, + PalFence** outFence); + +void PAL_CALL destroyFenceVk(PalFence* fence); + +PalResult PAL_CALL waitFenceVk( + PalFence* fence, + uint64_t timeout); + +PalResult PAL_CALL resetFenceVk(PalFence* fence); + +PalBool PAL_CALL isFenceSignaledVk(PalFence* fence); + +PalResult PAL_CALL createSemaphoreVk( + PalDevice* device, + PalBool enableTimeline, + PalSemaphore** outSemaphore); + +void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore); + +PalResult PAL_CALL waitSemaphoreVk( + PalSemaphore* semaphore, + uint64_t value, + uint64_t timeout); + +PalResult PAL_CALL signalSemaphoreVk( + PalSemaphore* semaphore, + PalQueue* queue, + uint64_t value); + +PalResult PAL_CALL getSemaphoreValueVk( + PalSemaphore* semaphore, + uint64_t* value); + +PalResult PAL_CALL createCommandPoolVk( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool); + +void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool); + +PalResult PAL_CALL allocateCommandBufferVk( + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outCmdBuffer); + +void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL submitCommandBufferVk( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + +PalResult PAL_CALL cmdBeginVk( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info); + +PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer); + +void PAL_CALL cmdExecuteCommandBufferVk( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + +void PAL_CALL cmdSetFragmentShadingRateVk( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + +void PAL_CALL cmdDrawMeshTasksVk( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +void PAL_CALL cmdDrawMeshTasksIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t drawCount); + +void PAL_CALL cmdDrawMeshTasksIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +void PAL_CALL cmdBuildAccelerationStructureVk( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); + +void PAL_CALL cmdBeginRenderingVk( + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info); + +void PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer); + +void PAL_CALL cmdCopyBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo); + +void PAL_CALL cmdCopyBufferToImageVk( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + +void PAL_CALL cmdCopyImageVk( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + +void PAL_CALL cmdCopyImageToBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo); + +void PAL_CALL cmdBindPipelineVk( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline); + +void PAL_CALL cmdSetViewportVk( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalViewport* viewports); + +void PAL_CALL cmdSetScissorsVk( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalRect2D* scissors); + +void PAL_CALL cmdBindVertexBuffersVk( + PalCommandBuffer* cmdBuffer, + uint32_t firstSlot, + uint32_t count, + PalBuffer** buffers, + uint64_t* offsets); + +void PAL_CALL cmdBindIndexBufferVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint64_t offset, + PalIndexType type); + +void PAL_CALL cmdDrawVk( + PalCommandBuffer* cmdBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + +void PAL_CALL cmdDrawIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + +void PAL_CALL cmdDrawIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t count); + +void PAL_CALL cmdDrawIndexedVk( + PalCommandBuffer* cmdBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + +void PAL_CALL cmdDrawIndexedIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + +void PAL_CALL cmdDrawIndexedIndirectCountVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t count); + +void PAL_CALL cmdAccelerationStructureBarrierVk( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, + PalBarrierInfo* info); + +void PAL_CALL cmdImageBarrierVk( + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalBarrierInfo* info); + +void PAL_CALL cmdBufferBarrierVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBarrierInfo* info); + +void PAL_CALL cmdDispatchVk( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +void PAL_CALL cmdDispatchBaseVk( + PalCommandBuffer* cmdBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +void PAL_CALL cmdDispatchIndirectVk( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer); + +void PAL_CALL cmdTraceRaysVk( + PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth); + +void PAL_CALL cmdTraceRaysIndirectVk( + PalCommandBuffer* cmdBuffer, + uint32_t raygenIndex, + PalShaderBindingTable* sbt, + PalBuffer* buffer); + +void PAL_CALL cmdBindDescriptorSetVk( + PalCommandBuffer* cmdBuffer, + uint32_t setIndex, + PalDescriptorSet* set); + +void PAL_CALL cmdPushConstantsVk( + PalCommandBuffer* cmdBuffer, + uint32_t offset, + uint32_t size, + const void* value); + +void PAL_CALL cmdSetCullModeVk( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + +void PAL_CALL cmdSetFrontFaceVk( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + +void PAL_CALL cmdSetPrimitiveTopologyVk( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + +void PAL_CALL cmdSetDepthTestEnableVk( + PalCommandBuffer* cmdBuffer, + PalBool enable); + +void PAL_CALL cmdSetDepthWriteEnableVk( + PalCommandBuffer* cmdBuffer, + PalBool enable); + +void PAL_CALL cmdSetStencilOpVk( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); + +PalResult PAL_CALL createAccelerationstructureVk( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + +void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as); + +void PAL_CALL getAccelerationStructureBuildSizeVk( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + +PalResult PAL_CALL createBufferVk( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + +void PAL_CALL destroyBufferVk(PalBuffer* buffer); + +void PAL_CALL getBufferMemoryRequirementsVk( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + +void PAL_CALL computeInstanceStagingSizeVk( + PalDevice* device, + uint32_t instanceCount, + uint64_t* outSize); + +void PAL_CALL computeImageStagingRequirementsVk( + PalDevice* device, + PalFormat imageFormat, + const PalBufferImageCopyInfo* copyInfo, + PalImageStagingRequirements* requirements); + +void PAL_CALL writeInstanceStagingVk( + PalDevice* device, + uint32_t instanceCount, + PalAccelerationStructureInstance* instances, + void* ptr); + +void PAL_CALL writeImageStagingVk( + PalDevice* device, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo, + void* srcData, + void* ptr); + +PalResult PAL_CALL bindBufferMemoryVk( + PalBuffer* buffer, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL mapBufferVk( + PalBuffer* buffer, + uint64_t offset, + uint64_t size, + void** outPtr); + +void PAL_CALL unmapBufferVk(PalBuffer* buffer); + +PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer); + +PalResult PAL_CALL createDescriptorSetLayoutVk( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + +void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout); + +PalResult PAL_CALL createDescriptorPoolVk( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + +void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool); + +PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool); + +PalResult PAL_CALL allocateDescriptorSetVk( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + +PalResult PAL_CALL updateDescriptorSetVk( + PalDevice* device, + uint32_t count, + PalDescriptorSetWriteInfo* infos); + +PalResult PAL_CALL createPipelineLayoutVk( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + +void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout); + +PalResult PAL_CALL createGraphicsPipelineVk( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createComputePipelineVk( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createRayTracingPipelineVk( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + +void PAL_CALL destroyPipelineVk(PalPipeline* pipeline); + +PalResult PAL_CALL createShaderBindingTableVk( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + +void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt); + +void PAL_CALL updateShaderBindingTableVk( + PalShaderBindingTable* sbt, + uint32_t count, + PalShaderBindingTableRecordInfo* infos); + +static PalGraphicsBackendVtable1 s_VkBackend1 = { .enumerateAdapters = enumerateAdaptersVk, .getAdapterInfo = getAdapterInfoVk, .getAdapterCapabilities = getAdapterCapabilitiesVk, @@ -441,142 +746,592 @@ static PalGraphicsVtable s_VkBackend = { // ================================================== #if PAL_HAS_D3D12_BACKEND -PalResult PAL_CALL initGraphicsD3D12(const PalGraphicsDebugger*, const PalAllocator*); +PalResult PAL_CALL initGraphicsD3D12( + const PalGraphicsDebugger* debugger, + const PalAllocator* allocator); + void PAL_CALL shutdownGraphicsD3D12(); -PalResult PAL_CALL enumerateAdaptersD3D12(uint32_t*, PalAdapter**); -void PAL_CALL getAdapterInfoD3D12(PalAdapter*, PalAdapterInfo*); -void PAL_CALL getAdapterCapabilitiesD3D12(PalAdapter*, PalAdapterCapabilities*); -PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter*); -uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12(PalAdapter*, PalShaderFormats); -PalResult PAL_CALL createDeviceD3D12(PalAdapter*, PalAdapterFeatures, PalDevice**); -void PAL_CALL destroyDeviceD3D12(PalDevice*); -PalResult PAL_CALL waitDeviceD3D12(PalDevice*); -PalResult PAL_CALL allocateMemoryD3D12(PalDevice*, PalMemoryType, uint64_t, uint64_t, PalMemory**); -void PAL_CALL freeMemoryD3D12(PalMemory*); -void PAL_CALL querySamplerAnisotropyCapabilitiesD3D12(PalDevice*, PalSamplerAnisotropyCapabilities*); -void PAL_CALL queryMultiViewCapabilitiesD3D12(PalDevice*, PalMultiViewCapabilities*); -void PAL_CALL queryMultiViewportCapabilitiesD3D12(PalDevice*, PalMultiViewportCapabilities*); -void PAL_CALL queryDepthStencilCapabilitiesD3D12(PalDevice*, PalDepthStencilCapabilities*); -void PAL_CALL queryFragmentShadingRateCapabilitiesD3D12(PalDevice*, PalFragmentShadingRateCapabilities*); -void PAL_CALL queryMeshShaderCapabilitiesD3D12(PalDevice*, PalMeshShaderCapabilities*); -void PAL_CALL queryRayTracingCapabilitiesD3D12(PalDevice*, PalRayTracingCapabilities*); -void PAL_CALL queryDescriptorIndexingCapabilitiesD3D12(PalDevice*, PalDescriptorIndexingCapabilities*); - -PalResult PAL_CALL createQueueD3D12(PalDevice*, PalQueueType, PalQueue**); -void PAL_CALL destroyQueueD3D12(PalQueue*); -PalResult PAL_CALL waitQueueD3D12(PalQueue*); -PalBool PAL_CALL canQueuePresentD3D12(PalQueue*, PalSurface*); -void PAL_CALL enumerateFormatsD3D12(PalAdapter*, uint32_t*, PalFormatInfo*); -PalBool PAL_CALL isFormatSupportedD3D12(PalAdapter*, PalFormat); -PalImageUsages PAL_CALL queryFormatImageUsagesD3D12(PalAdapter*, PalFormat); -PalSampleCount PAL_CALL queryFormatSampleCountD3D12(PalAdapter*, PalFormat); -PalResult PAL_CALL createImageD3D12(PalDevice*, const PalImageCreateInfo*, PalImage**); -void PAL_CALL destroyImageD3D12(PalImage*); -void PAL_CALL getImageInfoD3D12(PalImage*, PalImageInfo*); -void PAL_CALL getImageMemoryRequirementsD3D12(PalImage*, PalMemoryRequirements*); -PalResult PAL_CALL bindImageMemoryD3D12(PalImage*, PalMemory*, uint64_t); -PalResult PAL_CALL createImageViewD3D12(PalDevice*, PalImage*, const PalImageViewCreateInfo*, PalImageView**); -void PAL_CALL destroyImageViewD3D12(PalImageView*); - -PalResult PAL_CALL createSamplerD3D12(PalDevice*, const PalSamplerCreateInfo*, PalSampler**); -void PAL_CALL destroySamplerD3D12(PalSampler*); -PalResult PAL_CALL createSurfaceD3D12(PalDevice*, void*, void*, PalWindowInstanceType, PalSurface**); -void PAL_CALL destroySurfaceD3D12(PalSurface*); -void PAL_CALL getSurfaceCapabilitiesD3D12(PalDevice*, PalSurface*, PalSurfaceCapabilities*); -PalResult PAL_CALL createSwapchainD3D12(PalDevice*, PalQueue*, PalSurface*, const PalSwapchainCreateInfo*, PalSwapchain**); -void PAL_CALL destroySwapchainD3D12(PalSwapchain*); -PalImage* PAL_CALL getSwapchainImageD3D12(PalSwapchain*, uint32_t); -PalResult PAL_CALL getNextSwapchainImageD3D12(PalSwapchain*, PalSwapchainNextImageInfo*, uint32_t*); -PalResult PAL_CALL presentSwapchainD3D12(PalSwapchain*, uint32_t, PalSemaphore*); -PalResult PAL_CALL resizeSwapchainD3D12(PalSwapchain*, uint32_t, uint32_t); -PalResult PAL_CALL createShaderD3D12(PalDevice*, const PalShaderCreateInfo*, PalShader**); -void PAL_CALL destroyShaderD3D12(PalShader*); - -PalResult PAL_CALL createFenceD3D12(PalDevice*, PalBool, PalFence**); -void PAL_CALL destroyFenceD3D12(PalFence*); -PalResult PAL_CALL waitFenceD3D12(PalFence*, uint64_t); -PalResult PAL_CALL resetFenceD3D12(PalFence*); -PalBool PAL_CALL isFenceSignaledD3D12(PalFence*); -PalResult PAL_CALL createSemaphoreD3D12(PalDevice*, PalBool, PalSemaphore**); -void PAL_CALL destroySemaphoreD3D12(PalSemaphore*); -PalResult PAL_CALL waitSemaphoreD3D12(PalSemaphore*, uint64_t, uint64_t); -PalResult PAL_CALL signalSemaphoreD3D12(PalSemaphore*, PalQueue*, uint64_t); -PalResult PAL_CALL getSemaphoreValueD3D12(PalSemaphore*, uint64_t*); -PalResult PAL_CALL createCommandPoolD3D12(PalDevice*, PalQueue*, PalCommandPool**); -void PAL_CALL destroyCommandPoolD3D12(PalCommandPool*); -PalResult PAL_CALL allocateCommandBufferD3D12(PalDevice*, PalCommandPool*, PalCommandBufferType, PalCommandBuffer**); -void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer*); -PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer*); -PalResult PAL_CALL submitCommandBufferD3D12(PalQueue*, PalCommandBufferSubmitInfo*); - -PalResult PAL_CALL cmdBeginD3D12(PalCommandBuffer*, PalRenderingLayoutInfo*); -PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer*); -void PAL_CALL cmdExecuteCommandBufferD3D12(PalCommandBuffer*, PalCommandBuffer*); -void PAL_CALL cmdSetFragmentShadingRateD3D12(PalCommandBuffer*, PalFragmentShadingRateState*); -void PAL_CALL cmdDrawMeshTasksD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); -void PAL_CALL cmdDrawMeshTasksIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdDrawMeshTasksIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdBuildAccelerationStructureD3D12(PalCommandBuffer*, PalAccelerationStructureBuildInfo*); -void PAL_CALL cmdBeginRenderingD3D12(PalCommandBuffer*, PalRenderingInfo*); -void PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer*); -void PAL_CALL cmdCopyBufferD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, PalBufferCopyInfo*); -void PAL_CALL cmdCopyBufferToImageD3D12(PalCommandBuffer*, PalImage*, PalBuffer*, PalBufferImageCopyInfo*); -void PAL_CALL cmdCopyImageD3D12(PalCommandBuffer*, PalImage*, PalImage*, PalImageCopyInfo*); -void PAL_CALL cmdCopyImageToBufferD3D12(PalCommandBuffer*, PalBuffer*, PalImage*, PalBufferImageCopyInfo*); -void PAL_CALL cmdBindPipelineD3D12(PalCommandBuffer*, PalPipeline*); -void PAL_CALL cmdSetViewportD3D12(PalCommandBuffer*, uint32_t, PalViewport*); -void PAL_CALL cmdSetScissorsD3D12(PalCommandBuffer*, uint32_t, PalRect2D*); -void PAL_CALL cmdBindVertexBuffersD3D12(PalCommandBuffer*, uint32_t, uint32_t, PalBuffer**, uint64_t*); -void PAL_CALL cmdBindIndexBufferD3D12(PalCommandBuffer*, PalBuffer*, uint64_t, PalIndexType); -void PAL_CALL cmdDrawD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, uint32_t); -void PAL_CALL cmdDrawIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdDrawIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdDrawIndexedD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t, int32_t, uint32_t); -void PAL_CALL cmdDrawIndexedIndirectD3D12(PalCommandBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdDrawIndexedIndirectCountD3D12(PalCommandBuffer*, PalBuffer*, PalBuffer*, uint32_t); -void PAL_CALL cmdAccelerationStructureBarrierD3D12(PalCommandBuffer*, PalAccelerationStructure*, PalBarrierInfo*); -void PAL_CALL cmdImageBarrierD3D12(PalCommandBuffer*, PalImage*, PalImageSubresourceRange*, PalBarrierInfo*); -void PAL_CALL cmdBufferBarrierD3D12(PalCommandBuffer*, PalBuffer*, PalBarrierInfo*); -void PAL_CALL cmdDispatchD3D12(PalCommandBuffer*, uint32_t, uint32_t, uint32_t); -void PAL_CALL cmdDispatchIndirectD3D12(PalCommandBuffer*, PalBuffer*); -void PAL_CALL cmdTraceRaysD3D12(PalCommandBuffer*, PalShaderBindingTable*, uint32_t, uint32_t, uint32_t, uint32_t); -void PAL_CALL cmdTraceRaysIndirectD3D12(PalCommandBuffer*, uint32_t, PalShaderBindingTable*, PalBuffer*); -void PAL_CALL cmdBindDescriptorSetD3D12(PalCommandBuffer*, uint32_t, PalDescriptorSet*); -void PAL_CALL cmdPushConstantsD3D12(PalCommandBuffer*, uint32_t, uint32_t, const void*); - -PalResult PAL_CALL createAccelerationstructureD3D12(PalDevice*, const PalAccelerationStructureCreateInfo*, PalAccelerationStructure**); -void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure*); -void PAL_CALL getAccelerationStructureBuildSizeD3D12(PalDevice*, PalAccelerationStructureBuildInfo*, PalAccelerationStructureBuildSize*); -PalResult PAL_CALL createBufferD3D12(PalDevice*, const PalBufferCreateInfo*, PalBuffer**); -void PAL_CALL destroyBufferD3D12(PalBuffer*); -void PAL_CALL getBufferMemoryRequirementsD3D12(PalBuffer*, PalMemoryRequirements*); -void PAL_CALL computeInstanceStagingSizeD3D12(PalDevice*, uint32_t, uint64_t*); -void PAL_CALL computeImageStagingRequirementsD3D12(PalDevice*, PalFormat, const PalBufferImageCopyInfo*, PalImageStagingRequirements*); -void PAL_CALL writeInstanceStagingD3D12(PalDevice*, uint32_t, PalAccelerationStructureInstance*, void*); -void PAL_CALL writeImageStagingD3D12(PalDevice*, PalFormat, PalBufferImageCopyInfo*, void*, void*); -PalResult PAL_CALL bindBufferMemoryD3D12(PalBuffer*, PalMemory*, uint64_t); -PalResult PAL_CALL mapBufferD3D12(PalBuffer*, uint64_t, uint64_t, void**); -void PAL_CALL unmapBufferD3D12(PalBuffer*); -PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer*); -PalResult PAL_CALL createDescriptorSetLayoutD3D12(PalDevice*, const PalDescriptorSetLayoutCreateInfo*, PalDescriptorSetLayout**); -void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout*); -PalResult PAL_CALL createDescriptorPoolD3D12(PalDevice*, const PalDescriptorPoolCreateInfo*, PalDescriptorPool**); -void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool*); -PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool*); -PalResult PAL_CALL allocateDescriptorSetD3D12(PalDevice*, PalDescriptorPool*, PalDescriptorSetLayout*, PalDescriptorSet**); -PalResult PAL_CALL updateDescriptorSetD3D12(PalDevice*, uint32_t, PalDescriptorSetWriteInfo*); - -PalResult PAL_CALL createPipelineLayoutD3D12(PalDevice*, const PalPipelineLayoutCreateInfo*, PalPipelineLayout**); -void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout*); -PalResult PAL_CALL createGraphicsPipelineD3D12(PalDevice*, const PalGraphicsPipelineCreateInfo*, PalPipeline**); -PalResult PAL_CALL createComputePipelineD3D12(PalDevice*, const PalComputePipelineCreateInfo*, PalPipeline**); -PalResult PAL_CALL createRayTracingPipelineD3D12(PalDevice*, const PalRayTracingPipelineCreateInfo*, PalPipeline**); -void PAL_CALL destroyPipelineD3D12(PalPipeline*); -PalResult PAL_CALL createShaderBindingTableD3D12(PalDevice*, const PalShaderBindingTableCreateInfo*, PalShaderBindingTable**); -void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable*); -void PAL_CALL updateShaderBindingTableD3D12(PalShaderBindingTable*, uint32_t, PalShaderBindingTableRecordInfo*); - -static PalGraphicsVtable s_D3D12Backend = { + +PalResult PAL_CALL enumerateAdaptersD3D12( + uint32_t* count, + PalAdapter** outAdapters); + +void PAL_CALL getAdapterInfoD3D12( + PalAdapter* adapter, + PalAdapterInfo* info); + +void PAL_CALL getAdapterCapabilitiesD3D12( + PalAdapter* adapter, + PalAdapterCapabilities* caps); + +PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter); + +uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( + PalAdapter* adapter, + PalShaderFormats shaderFormat); + +PalResult PAL_CALL createDeviceD3D12( + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice); + +void PAL_CALL destroyDeviceD3D12(PalDevice* device); + +PalResult PAL_CALL allocateMemoryD3D12( + PalDevice* device, + PalMemoryType type, + uint64_t memoryMask, + uint64_t size, + PalMemory** outMemory); + +void PAL_CALL freeMemoryD3D12(PalMemory* memory); + +void PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps); + +void PAL_CALL queryMultiViewCapabilitiesD3D12( + PalDevice* device, + PalMultiViewCapabilities* caps); + +void PAL_CALL queryMultiViewportCapabilitiesD3D12( + PalDevice* device, + PalMultiViewportCapabilities* caps); + +void PAL_CALL queryDepthStencilCapabilitiesD3D12( + PalDevice* device, + PalDepthStencilCapabilities* caps); + +void PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( + PalDevice* device, + PalFragmentShadingRateCapabilities* caps); + +void PAL_CALL queryMeshShaderCapabilitiesD3D12( + PalDevice* device, + PalMeshShaderCapabilities* caps); + +void PAL_CALL queryRayTracingCapabilitiesD3D12( + PalDevice* device, + PalRayTracingCapabilities* caps); + +void PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( + PalDevice* device, + PalDescriptorIndexingCapabilities* caps); + +PalResult PAL_CALL createQueueD3D12( + PalDevice* device, + PalQueueType type, + PalQueue** outQueue); + +void PAL_CALL destroyQueueD3D12(PalQueue* queue); + +PalBool PAL_CALL canQueuePresentD3D12( + PalQueue* queue, + PalSurface* surface); + +PalResult PAL_CALL waitQueueD3D12(PalQueue* queue); + +void PAL_CALL enumerateFormatsD3D12( + PalAdapter* adapter, + uint32_t* count, + PalFormatInfo* outFormats); + +PalBool PAL_CALL isFormatSupportedD3D12( + PalAdapter* adapter, + PalFormat format); + +PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( + PalAdapter* adapter, + PalFormat format); + +PalSampleCount PAL_CALL queryFormatSampleCountD3D12( + PalAdapter* adapter, + PalFormat format); + +PalResult PAL_CALL createImageD3D12( + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage); + +void PAL_CALL destroyImageD3D12(PalImage* image); + +void PAL_CALL getImageInfoD3D12( + PalImage* image, + PalImageInfo* info); + +void PAL_CALL getImageMemoryRequirementsD3D12( + PalImage* image, + PalMemoryRequirements* requirements); + +PalResult PAL_CALL bindImageMemoryD3D12( + PalImage* image, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL createImageViewD3D12( + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView); + +void PAL_CALL destroyImageViewD3D12(PalImageView* imageView); + +PalResult PAL_CALL createSamplerD3D12( + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler); + +void PAL_CALL destroySamplerD3D12(PalSampler* sampler); + +PalResult PAL_CALL createSurfaceD3D12( + PalDevice* device, + void* window, + void* windowInstance, + PalWindowInstanceType instanceType, + PalSurface** outSurface); + +void PAL_CALL destroySurfaceD3D12(PalSurface* surface); + +void PAL_CALL getSurfaceCapabilitiesD3D12( + PalDevice* device, + PalSurface* surface, + PalSurfaceCapabilities* caps); + +PalResult PAL_CALL createSwapchainD3D12( + PalDevice* device, + PalQueue* queue, + PalSurface* surface, + const PalSwapchainCreateInfo* info, + PalSwapchain** outSwapchain); + +void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain); + +PalImage* PAL_CALL getSwapchainImageD3D12( + PalSwapchain* swapchain, + uint32_t index); + +PalResult PAL_CALL getNextSwapchainImageD3D12( + PalSwapchain* swapchain, + PalSwapchainNextImageInfo* info, + uint32_t* outIndex); + +PalResult PAL_CALL presentSwapchainD3D12( + PalSwapchain* swapchain, + uint32_t imageIndex, + PalSemaphore* waitSemaphore); + +PalResult PAL_CALL resizeSwapchainD3D12( + PalSwapchain* swapchain, + uint32_t newWidth, + uint32_t newHeight); + +PalResult PAL_CALL createShaderD3D12( + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader); + +void PAL_CALL destroyShaderD3D12(PalShader* shader); + +PalResult PAL_CALL createFenceD3D12( + PalDevice* device, + PalBool signaled, + PalFence** outFence); + +void PAL_CALL destroyFenceD3D12(PalFence* fence); + +PalResult PAL_CALL waitFenceD3D12( + PalFence* fence, + uint64_t timeout); + +PalResult PAL_CALL resetFenceD3D12(PalFence* fence); + +PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence); + +PalResult PAL_CALL createSemaphoreD3D12( + PalDevice* device, + PalBool enableTimeline, + PalSemaphore** outSemaphore); + +void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore); + +PalResult PAL_CALL waitSemaphoreD3D12( + PalSemaphore* semaphore, + uint64_t value, + uint64_t timeout); + +PalResult PAL_CALL signalSemaphoreD3D12( + PalSemaphore* semaphore, + PalQueue* queue, + uint64_t value); + +PalResult PAL_CALL getSemaphoreValueD3D12( + PalSemaphore* semaphore, + uint64_t* value); + +PalResult PAL_CALL createCommandPoolD3D12( + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool); + +void PAL_CALL destroyCommandPoolD3D12(PalCommandPool* pool); + +PalResult PAL_CALL allocateCommandBufferD3D12( + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outCmdBuffer); + +void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer); + +PalResult PAL_CALL submitCommandBufferD3D12( + PalQueue* queue, + PalCommandBufferSubmitInfo* info); + +PalResult PAL_CALL cmdBeginD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info); + +PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer); + +void PAL_CALL cmdExecuteCommandBufferD3D12( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer); + +void PAL_CALL cmdSetFragmentShadingRateD3D12( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state); + +void PAL_CALL cmdDrawMeshTasksD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +void PAL_CALL cmdDrawMeshTasksIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t drawCount); + +void PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount); + +void PAL_CALL cmdBuildAccelerationStructureD3D12( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info); + +void PAL_CALL cmdBeginRenderingD3D12( + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info); + +void PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer); + +void PAL_CALL cmdCopyBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo); + +void PAL_CALL cmdCopyBufferToImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo); + +void PAL_CALL cmdCopyImageD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo); + +void PAL_CALL cmdCopyImageToBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo); + +void PAL_CALL cmdBindPipelineD3D12( + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline); + +void PAL_CALL cmdSetViewportD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalViewport* viewports); + +void PAL_CALL cmdSetScissorsD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalRect2D* scissors); + +void PAL_CALL cmdBindVertexBuffersD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t firstSlot, + uint32_t count, + PalBuffer** buffers, + uint64_t* offsets); + +void PAL_CALL cmdBindIndexBufferD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint64_t offset, + PalIndexType type); + +void PAL_CALL cmdDrawD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance); + +void PAL_CALL cmdDrawIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + +void PAL_CALL cmdDrawIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t count); + +void PAL_CALL cmdDrawIndexedD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance); + +void PAL_CALL cmdDrawIndexedIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t count); + +void PAL_CALL cmdDrawIndexedIndirectCountD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t count); + +void PAL_CALL cmdAccelerationStructureBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructure* as, + PalBarrierInfo* info); + +void PAL_CALL cmdImageBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalBarrierInfo* info); + +void PAL_CALL cmdBufferBarrierD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBarrierInfo* info); + +void PAL_CALL cmdDispatchD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +void PAL_CALL cmdDispatchBaseD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t baseGroupX, + uint32_t baseGroupY, + uint32_t baseGroupZ, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ); + +void PAL_CALL cmdDispatchIndirectD3D12( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer); + +void PAL_CALL cmdTraceRaysD3D12( + PalCommandBuffer* cmdBuffer, + PalShaderBindingTable* sbt, + uint32_t raygenIndex, + uint32_t width, + uint32_t height, + uint32_t depth); + +void PAL_CALL cmdTraceRaysIndirectD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t raygenIndex, + PalShaderBindingTable* sbt, + PalBuffer* buffer); + +void PAL_CALL cmdBindDescriptorSetD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t setIndex, + PalDescriptorSet* set); + +void PAL_CALL cmdPushConstantsD3D12( + PalCommandBuffer* cmdBuffer, + uint32_t offset, + uint32_t size, + const void* value); + +void PAL_CALL cmdSetCullModeD3D12( + PalCommandBuffer* cmdBuffer, + PalCullMode cullMode); + +void PAL_CALL cmdSetFrontFaceD3D12( + PalCommandBuffer* cmdBuffer, + PalFrontFace frontFace); + +void PAL_CALL cmdSetPrimitiveTopologyD3D12( + PalCommandBuffer* cmdBuffer, + PalPrimitiveTopology topology); + +void PAL_CALL cmdSetDepthTestEnableD3D12( + PalCommandBuffer* cmdBuffer, + PalBool enable); + +void PAL_CALL cmdSetDepthWriteEnableD3D12( + PalCommandBuffer* cmdBuffer, + PalBool enable); + +void PAL_CALL cmdSetStencilOpD3D12( + PalCommandBuffer* cmdBuffer, + PalStencilFaceFlags faceMask, + PalStencilOp failOp, + PalStencilOp passOp, + PalStencilOp depthFailOp, + PalCompareOp compareOp); + +PalResult PAL_CALL createAccelerationstructureD3D12( + PalDevice* device, + const PalAccelerationStructureCreateInfo* info, + PalAccelerationStructure** outAs); + +void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as); + +void PAL_CALL getAccelerationStructureBuildSizeD3D12( + PalDevice* device, + PalAccelerationStructureBuildInfo* info, + PalAccelerationStructureBuildSize* size); + +PalResult PAL_CALL createBufferD3D12( + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer); + +void PAL_CALL destroyBufferD3D12(PalBuffer* buffer); + +void PAL_CALL getBufferMemoryRequirementsD3D12( + PalBuffer* buffer, + PalMemoryRequirements* requirements); + +void PAL_CALL computeInstanceStagingSizeD3D12( + PalDevice* device, + uint32_t instanceCount, + uint64_t* outSize); + +void PAL_CALL computeImageStagingRequirementsD3D12( + PalDevice* device, + PalFormat imageFormat, + const PalBufferImageCopyInfo* copyInfo, + PalImageStagingRequirements* requirements); + +void PAL_CALL writeInstanceStagingD3D12( + PalDevice* device, + uint32_t instanceCount, + PalAccelerationStructureInstance* instances, + void* ptr); + +void PAL_CALL writeImageStagingD3D12( + PalDevice* device, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo, + void* srcData, + void* ptr); + +PalResult PAL_CALL bindBufferMemoryD3D12( + PalBuffer* buffer, + PalMemory* memory, + uint64_t offset); + +PalResult PAL_CALL mapBufferD3D12( + PalBuffer* buffer, + uint64_t offset, + uint64_t size, + void** outPtr); + +void PAL_CALL unmapBufferD3D12(PalBuffer* buffer); + +PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer); + +PalResult PAL_CALL createDescriptorSetLayoutD3D12( + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout); + +void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout); + +PalResult PAL_CALL createDescriptorPoolD3D12( + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool); + +void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool); + +PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool); + +PalResult PAL_CALL allocateDescriptorSetD3D12( + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet); + +PalResult PAL_CALL updateDescriptorSetD3D12( + PalDevice* device, + uint32_t count, + PalDescriptorSetWriteInfo* infos); + +PalResult PAL_CALL createPipelineLayoutD3D12( + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout); + +void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout); + +PalResult PAL_CALL createGraphicsPipelineD3D12( + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createComputePipelineD3D12( + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline); + +PalResult PAL_CALL createRayTracingPipelineD3D12( + PalDevice* device, + const PalRayTracingPipelineCreateInfo* info, + PalPipeline** outPipeline); + +void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline); + +PalResult PAL_CALL createShaderBindingTableD3D12( + PalDevice* device, + const PalShaderBindingTableCreateInfo* info, + PalShaderBindingTable** outSbt); + +void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt); + +void PAL_CALL updateShaderBindingTableD3D12( + PalShaderBindingTable* sbt, + uint32_t count, + PalShaderBindingTableRecordInfo* infos); + +static PalGraphicsBackendVtable1 s_D3D12Backend1 = { .enumerateAdapters = enumerateAdaptersD3D12, .getAdapterInfo = getAdapterInfoD3D12, .getAdapterCapabilities = getAdapterCapabilitiesD3D12, @@ -667,18 +1422,18 @@ static PalGraphicsVtable s_D3D12Backend = { .cmdImageBarrier = cmdImageBarrierD3D12, .cmdBufferBarrier = cmdBufferBarrierD3D12, .cmdDispatch = cmdDispatchD3D12, - .cmdDispatchBase = nullptr, + .cmdDispatchBase = cmdDispatchBaseD3D12, .cmdDispatchIndirect = cmdDispatchIndirectD3D12, .cmdTraceRays = cmdTraceRaysD3D12, .cmdTraceRaysIndirect = cmdTraceRaysIndirectD3D12, .cmdBindDescriptorSet = cmdBindDescriptorSetD3D12, .cmdPushConstants = cmdPushConstantsD3D12, - .cmdSetCullMode = nullptr, - .cmdSetFrontFace = nullptr, - .cmdSetPrimitiveTopology = nullptr, - .cmdSetDepthTestEnable = nullptr, - .cmdSetDepthWriteEnable = nullptr, - .cmdSetStencilOp = nullptr, + .cmdSetCullMode = cmdSetCullModeD3D12, + .cmdSetFrontFace = cmdSetFrontFaceD3D12, + .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyD3D12, + .cmdSetDepthTestEnable = cmdSetDepthTestEnableD3D12, + .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableD3D12, + .cmdSetStencilOp = cmdSetStencilOpD3D12, .createAccelerationstructure = createAccelerationstructureD3D12, .destroyAccelerationstructure = destroyAccelerationstructureD3D12, .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeD3D12, @@ -713,5 +1468,4 @@ static PalGraphicsVtable s_D3D12Backend = { #endif // PAL_HAS_D3D12_BACKEND // clang-format on - #endif // _PAL_GRAPHICS_BACKENDS_H \ No newline at end of file diff --git a/src/opengl/pal_opengl_backends.h b/src/opengl/pal_opengl_backends.h index 7374d97d..fdb6abd0 100644 --- a/src/opengl/pal_opengl_backends.h +++ b/src/opengl/pal_opengl_backends.h @@ -14,15 +14,32 @@ // clang-format off typedef struct { void (*shutdownGL)(); + const PalGLInfo* (*getGLInfo)(); - PalResult (*enumerateGLFBConfigs)(uint32_t*, PalGLFBConfig*); - PalResult (*createGLContext)(const PalGLContextCreateInfo*, PalGLContext**); + + PalResult (*enumerateGLFBConfigs)( + uint32_t* count, + PalGLFBConfig* configs); + + PalResult (*createGLContext)( + const PalGLContextCreateInfo* info, + PalGLContext** outContext); + void (*destroyGLContext)(PalGLContext* context); - PalResult (*makeContextCurrent)(PalGLWindow*, PalGLContext*); - void* (*getGLProcAddress)(const char*); - PalResult (*swapBuffers)(PalGLWindow*, PalGLContext*); - void (*setSwapInterval)(int32_t); - const PalBool* (*GetSupportedGLAPIs)(void*); + + PalResult (*makeContextCurrent)( + PalGLWindow* window, + PalGLContext* context); + + void* (*getGLProcAddress)(const char* name); + + PalResult (*swapBuffers)( + PalGLWindow* window, + PalGLContext* context); + + void (*setSwapInterval)(int32_t interval); + + const PalBool* (*GetSupportedGLAPIs)(void* instance); } OpenglBackend; // ================================================== @@ -30,17 +47,38 @@ typedef struct { // ================================================== #ifdef _WIN32 -PalResult wglInitGL(PalGLAPI, void*, const PalAllocator*); +PalResult wglInitGL( + PalGLAPI api, + void* instance, + const PalAllocator* allocator); + void wglShutdownGL(); + const PalGLInfo* wglGetGLInfo(); -PalResult wglEnumerateGLFBConfigs(uint32_t*, PalGLFBConfig*); -PalResult wglCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); -void wglDestroyGLContext(PalGLContext*); -PalResult wglMakeContextCurrent(PalGLWindow*, PalGLContext*); -void* wglGetGLProcAddress(const char*); -PalResult wglSwapBuffers(PalGLWindow*, PalGLContext*); -void wglSetSwapInterval(int32_t); -const PalBool* wglGetSupportedGLAPIs(void*); + +PalResult wglEnumerateGLFBConfigs( + uint32_t* count, + PalGLFBConfig* configs); + +PalResult wglCreateGLContext( + const PalGLContextCreateInfo* info, + PalGLContext** outContext); + +void wglDestroyGLContext(PalGLContext* context); + +PalResult wglMakeContextCurrent( + PalGLWindow* window, + PalGLContext* context); + +void* wglGetGLProcAddress(const char* name); + +PalResult wglSwapBuffers( + PalGLWindow* window, + PalGLContext* context); + +void wglSetSwapInterval(int32_t interval); + +const PalBool* wglGetSupportedGLAPIs(void* instance); static OpenglBackend s_WglBackend = { .shutdownGL = wglShutdownGL, @@ -61,17 +99,38 @@ static OpenglBackend s_WglBackend = { // ================================================== #if _PAL_HAS_EGL -PalResult eglInitGL(PalGLAPI, void*, const PalAllocator*); +PalResult eglInitGL( + PalGLAPI api, + void* instance, + const PalAllocator* allocator); + void eglShutdownGL(); + const PalGLInfo* eglGetGLInfo(); -PalResult eglEnumerateGLFBConfigs(uint32_t*, PalGLFBConfig*); -PalResult eglCreateGLContext(const PalGLContextCreateInfo*, PalGLContext**); -void eglDestroyGLContext(PalGLContext*); -PalResult eglMakeContextCurrent(PalGLWindow*, PalGLContext*); -void* eglGetGLProcAddress(const char*); -PalResult eglSwapBuffers(PalGLWindow*, PalGLContext*); -void eglSetSwapInterval(int32_t); -const PalBool* eglGetSupportedGLAPIs(void*); + +PalResult eglEnumerateGLFBConfigs( + uint32_t* count, + PalGLFBConfig* configs); + +PalResult eglCreateGLContext( + const PalGLContextCreateInfo* info, + PalGLContext** outContext); + +void eglDestroyGLContext(PalGLContext* context); + +PalResult eglMakeContextCurrent( + PalGLWindow* window, + PalGLContext* context); + +void* eglGetGLProcAddress(const char* name); + +PalResult eglSwapBuffers( + PalGLWindow* window, + PalGLContext* context); + +void eglSetSwapInterval(int32_t interval); + +const PalBool* eglGetSupportedGLAPIs(void* instance); static OpenglBackend s_EglBackend = { .shutdownGL = eglShutdownGL, diff --git a/src/video/pal_video_backends.h b/src/video/pal_video_backends.h index 5fc71ddd..868bc5e7 100644 --- a/src/video/pal_video_backends.h +++ b/src/video/pal_video_backends.h @@ -12,60 +12,184 @@ // clang-format off typedef struct { void (*shutdownVideo)(); + void (*updateVideo)(); + PalVideoFeatures (*getVideoFeatures)(); - PalResult (*enumerateMonitors)(uint32_t*, PalMonitor**); - void (*getPrimaryMonitor)(PalMonitor**); - void (*getMonitorInfo)(PalMonitor*, PalMonitorInfo*); - void (*enumerateMonitorModes)(PalMonitor*, uint32_t*, PalMonitorMode*); - void (*getCurrentMonitorMode)(PalMonitor*, PalMonitorMode*); - PalResult (*setMonitorMode)(PalMonitor*, PalMonitorMode*); - PalResult (*validateMonitorMode)(PalMonitor*, PalMonitorMode*); - PalResult (*setMonitorOrientation)(PalMonitor*, PalOrientation); - - PalResult (*createWindow)(const PalWindowCreateInfo*, PalWindow**); - void (*destroyWindow)(PalWindow*); - void (*maximizeWindow)(PalWindow*); - void (*minimizeWindow)(PalWindow*); - void (*restoreWindow)(PalWindow*); - void (*showWindow)(PalWindow*); - void (*hideWindow)(PalWindow*); - void (*flashWindow)(PalWindow*, const PalFlashInfo*); - void (*getWindowStyle)(PalWindow*, PalWindowStyle*); - void (*getWindowMonitor)(PalWindow*, PalMonitor**); - void (*getWindowTitle)(PalWindow*, uint64_t, uint64_t*, char*); - void (*getWindowPos)(PalWindow*, int32_t*, int32_t*); - void (*getWindowSize)(PalWindow*, uint32_t*, uint32_t*); - void (*getWindowState)(PalWindow*, PalWindowState*); + + PalResult (*enumerateMonitors)( + uint32_t* count, + PalMonitor** outMonitor); + + void (*getPrimaryMonitor)(PalMonitor** outMonitor); + + void (*getMonitorInfo)( + PalMonitor* monitor, + PalMonitorInfo* info); + + void (*enumerateMonitorModes)( + PalMonitor* monitor, + uint32_t* count, + PalMonitorMode* mode); + + void (*getCurrentMonitorMode)( + PalMonitor* monitor, + PalMonitorMode* mode); + + PalResult (*setMonitorMode)( + PalMonitor* monitor, + PalMonitorMode* mode); + + PalResult (*validateMonitorMode)( + PalMonitor* monitor, + PalMonitorMode* mode); + + PalResult (*setMonitorOrientation)( + PalMonitor* monitor, + PalOrientation orientation); + + PalResult (*createWindow)( + const PalWindowCreateInfo* info, + PalWindow** outWindow); + + void (*destroyWindow)(PalWindow* window); + + void (*maximizeWindow)(PalWindow* window); + + void (*minimizeWindow)(PalWindow* window); + + void (*restoreWindow)(PalWindow* window); + + void (*showWindow)(PalWindow* window); + + void (*hideWindow)(PalWindow* window); + + void (*flashWindow)( + PalWindow* window, + const PalFlashInfo* info); + + void (*getWindowStyle)( + PalWindow* window, + PalWindowStyle* style); + + void (*getWindowMonitor)( + PalWindow* window, + PalMonitor** outMonitor); + + void (*getWindowTitle)( + PalWindow* window, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer); + + void (*getWindowPos)( + PalWindow* window, + int32_t* x, + int32_t* y); + + void (*getWindowSize)( + PalWindow* window, + uint32_t* width, + uint32_t* height); + + void (*getWindowState)( + PalWindow* window, + PalWindowState* state); + const PalBool* (*getKeycodeState)(); + const PalBool* (*getScancodeState)(); + const PalBool* (*getMouseState)(); - void (*getMouseDelta)(float*, float*); - void (*getMouseWheelDelta)(float*, float*); - PalBool (*isWindowVisible)(PalWindow*); + + void (*getMouseDelta)( + float* dx, + float* dy); + + void (*getMouseWheelDelta)( + float* dx, + float* dy); + + PalBool (*isWindowVisible)(PalWindow* window); + PalWindow* (*getFocusWindow)(); - void (*getWindowHandleInfo)(PalWindow*, PalWindowHandleInfo*); - void (*setWindowOpacity)(PalWindow*, float); - void (*setWindowStyle)(PalWindow*, PalWindowStyle); - void (*setWindowTitle)(PalWindow*, const char*); - void (*setWindowPos)(PalWindow*, int32_t, int32_t); - void (*setWindowSize)(PalWindow*, uint32_t, uint32_t); - void (*setFocusWindow)(PalWindow*); - - PalResult (*createIcon)(const PalIconCreateInfo*, PalIcon**); - void (*destroyIcon)(PalIcon*); - void (*setWindowIcon)(PalWindow*, PalIcon*); - - PalResult (*createCursor)(const PalCursorCreateInfo*, PalCursor**); - PalResult (*createCursorFrom)(PalCursorType, PalCursor**); - void (*destroyCursor)(PalCursor*); - void (*showCursor)(PalBool); - void (*clipCursor)(PalWindow*, PalBool); - void (*getCursorPos)(PalWindow*, int32_t*, int32_t*); - void (*setCursorPos)(PalWindow*, int32_t, int32_t); - void (*setWindowCursor)(PalWindow*, PalCursor*); - PalResult (*attachWindow)(void*, PalWindow**); - PalResult (*detachWindow)(PalWindow*, void**); + + void (*getWindowHandleInfo)( + PalWindow* window, + PalWindowHandleInfo* info); + + void (*setWindowOpacity)( + PalWindow* window, + float opacity); + + void (*setWindowStyle)( + PalWindow* window, + PalWindowStyle style); + + void (*setWindowTitle)( + PalWindow* window, + const char* title); + + void (*setWindowPos)( + PalWindow* window, + int32_t x, + int32_t y); + + void (*setWindowSize)( + PalWindow* window, + uint32_t width, + uint32_t height); + + void (*setFocusWindow)(PalWindow* window); + + PalResult (*createIcon)( + const PalIconCreateInfo* info, + PalIcon** outIcon); + + void (*destroyIcon)(PalIcon* icon); + + void (*setWindowIcon)( + PalWindow* window, + PalIcon* icon); + + PalResult (*createCursor)( + const PalCursorCreateInfo* info, + PalCursor** outCursor); + + PalResult (*createCursorFrom)( + PalCursorType type, + PalCursor** outCursor); + + void (*destroyCursor)(PalCursor* cursor); + + void (*showCursor)(PalBool show); + + void (*clipCursor)( + PalWindow* window, + PalBool clip); + + void (*getCursorPos)( + PalWindow* window, + int32_t* x, + int32_t* y); + + void (*setCursorPos)( + PalWindow* window, + int32_t x, + int32_t y); + + void (*setWindowCursor)( + PalWindow* window, + PalCursor* cursor); + + PalResult (*attachWindow)( + void* windowHandle, + PalWindow** outWindow); + + PalResult (*detachWindow)( + PalWindow* window, + void** outWindowHandle); + void* (*getInstance)(); } VideoBackend; @@ -74,63 +198,190 @@ typedef struct { // ================================================== #ifdef _WIN32 -PalResult win32InitVideo(const PalAllocator*, PalEventDriver*, void*); +PalResult win32InitVideo( + const PalAllocator* allocator, + PalEventDriver* eventDriver, + void* preferredInstance); + void win32ShutdownVideo(); + void win32UpdateVideo(); + PalVideoFeatures win32GetVideoFeatures(); -PalResult win32EnumerateMonitors(uint32_t*, PalMonitor**); -void win32GetPrimaryMonitor(PalMonitor**); -void win32GetMonitorInfo(PalMonitor*, PalMonitorInfo*); -void win32EnumerateMonitorModes(PalMonitor*, uint32_t*, PalMonitorMode*); -void win32GetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult win32SetMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult win32ValidateMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult win32SetMonitorOrientation(PalMonitor*, PalOrientation); - -PalResult win32CreateWindow(const PalWindowCreateInfo*, PalWindow**); -void win32DestroyWindow(PalWindow*); -void win32MaximizeWindow(PalWindow*); -void win32MinimizeWindow(PalWindow*); -void win32RestoreWindow(PalWindow*); -void win32ShowWindow(PalWindow*); -void win32HideWindow(PalWindow*); -void win32FlashWindow(PalWindow*, const PalFlashInfo*); -void win32GetWindowStyle(PalWindow*, PalWindowStyle*); -void win32GetWindowMonitor(PalWindow*, PalMonitor**); -void win32GetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); -void win32GetWindowPos(PalWindow*, int32_t*, int32_t*); -void win32GetWindowSize(PalWindow*, uint32_t*, uint32_t*); -void win32GetWindowState(PalWindow*, PalWindowState*); +PalResult win32EnumerateMonitors( + uint32_t* count, + PalMonitor** outMonitor); + +void win32GetPrimaryMonitor(PalMonitor** outMonitor); + +void win32GetMonitorInfo( + PalMonitor* monitor, + PalMonitorInfo* info); + +void win32EnumerateMonitorModes( + PalMonitor* monitor, + uint32_t* count, + PalMonitorMode* mode); + +void win32GetCurrentMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode); + +PalResult win32SetMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode); + +PalResult win32ValidateMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode); + +PalResult win32SetMonitorOrientation( + PalMonitor* monitor, + PalOrientation orientation); + +PalResult win32CreateWindow( + const PalWindowCreateInfo* info, + PalWindow** outWindow); + +void win32DestroyWindow(PalWindow* window); + +void win32MaximizeWindow(PalWindow* window); + +void win32MinimizeWindow(PalWindow* window); + +void win32RestoreWindow(PalWindow* window); + +void win32ShowWindow(PalWindow* window); + +void win32HideWindow(PalWindow* window); + +void win32FlashWindow( + PalWindow* window, + const PalFlashInfo* info); + +void win32GetWindowStyle( + PalWindow* window, + PalWindowStyle* style); + +void win32GetWindowMonitor( + PalWindow* window, + PalMonitor** outMonitor); + +void win32GetWindowTitle( + PalWindow* window, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer); + +void win32GetWindowPos( + PalWindow* window, + int32_t* x, + int32_t* y); + +void win32GetWindowSize( + PalWindow* window, + uint32_t* width, + uint32_t* height); + +void win32GetWindowState( + PalWindow* window, + PalWindowState* state); + const PalBool* win32GetKeycodeState(); + const PalBool* win32GetScancodeState(); + const PalBool* win32GetMouseState(); -void win32GetMouseDelta(float*, float*); -void win32GetMouseWheelDelta(float*, float*); -PalBool win32IsWindowVisible(PalWindow*); + +void win32GetMouseDelta( + float* dx, + float* dy); + +void win32GetMouseWheelDelta( + float* dx, + float* dy); + +PalBool win32IsWindowVisible(PalWindow* window); + PalWindow* win32GetFocusWindow(); -void win32GetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); -void win32SetWindowOpacity(PalWindow*, float); -void win32SetWindowStyle(PalWindow*, PalWindowStyle); -void win32SetWindowTitle(PalWindow*, const char*); -void win32SetWindowPos(PalWindow*, int32_t, int32_t); -void win32SetWindowSize(PalWindow*, uint32_t, uint32_t); -void win32SetFocusWindow(PalWindow*); - -PalResult win32CreateIcon(const PalIconCreateInfo*, PalIcon**); -void win32DestroyIcon(PalIcon*); -void win32SetWindowIcon(PalWindow*, PalIcon*); - -PalResult win32CreateCursor(const PalCursorCreateInfo*, PalCursor**); -PalResult win32CreateCursorFrom(PalCursorType, PalCursor**); -void win32DestroyCursor(PalCursor*); -void win32ShowCursor(PalBool); -void win32ClipCursor(PalWindow*, PalBool); -void win32GetCursorPos(PalWindow*, int32_t*, int32_t*); -void win32SetCursorPos(PalWindow*, int32_t, int32_t); -void win32SetWindowCursor(PalWindow*, PalCursor*); -PalResult win32AttachWindow(void*, PalWindow**); -PalResult win32DetachWindow(PalWindow*, void**); + +void win32GetWindowHandleInfo( + PalWindow* window, + PalWindowHandleInfo* info); + +void win32SetWindowOpacity( + PalWindow* window, + float opacity); + +void win32SetWindowStyle( + PalWindow* window, + PalWindowStyle style); + +void win32SetWindowTitle( + PalWindow* window, + const char* title); + +void win32SetWindowPos( + PalWindow* window, + int32_t x, + int32_t y); + +void win32SetWindowSize( + PalWindow* window, + uint32_t width, + uint32_t height); + +void win32SetFocusWindow(PalWindow* window); + +PalResult win32CreateIcon( + const PalIconCreateInfo* info, + PalIcon** outIcon); + +void win32DestroyIcon(PalIcon* icon); + +void win32SetWindowIcon( + PalWindow* window, + PalIcon* icon); + +PalResult win32CreateCursor( + const PalCursorCreateInfo* info, + PalCursor** outCursor); + +PalResult win32CreateCursorFrom( + PalCursorType type, + PalCursor** outCursor); + +void win32DestroyCursor(PalCursor* cursor); + +void win32ShowCursor(PalBool show); + +void win32ClipCursor( + PalWindow* window, + PalBool clip); + +void win32GetCursorPos( + PalWindow* window, + int32_t* x, + int32_t* y); + +void win32SetCursorPos( + PalWindow* window, + int32_t x, + int32_t y); + +void win32SetWindowCursor( + PalWindow* window, + PalCursor* cursor); + +PalResult win32AttachWindow( + void* windowHandle, + PalWindow** outWindow); + +PalResult win32DetachWindow( + PalWindow* window, + void** outWindowHandle); + void* win32GetInstance(); static VideoBackend s_Win32Backend = { @@ -198,60 +449,190 @@ static VideoBackend s_Win32Backend = { // ================================================== #if PAL_HAS_X11_BACKEND == 1 -PalResult xInitVideo(const PalAllocator*, PalEventDriver*, void*); +PalResult xInitVideo( + const PalAllocator* allocator, + PalEventDriver* eventDriver, + void* preferredInstance); + void xShutdownVideo(); + void xUpdateVideo(); + PalVideoFeatures xGetVideoFeatures(); -PalResult xEnumerateMonitors(uint32_t*, PalMonitor**); -void xGetPrimaryMonitor(PalMonitor**); -void xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); -void xEnumerateMonitorModes(PalMonitor*, uint32_t*, PalMonitorMode*); -void xGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult xSetMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult xValidateMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult xSetMonitorOrientation(PalMonitor*, PalOrientation); - -PalResult xCreateWindow(const PalWindowCreateInfo*, PalWindow**); -void xDestroyWindow(PalWindow*); -void xMaximizeWindow(PalWindow*); -void xMinimizeWindow(PalWindow*); -void xRestoreWindow(PalWindow*); -void xShowWindow(PalWindow*); -void xHideWindow(PalWindow*); -void xFlashWindow(PalWindow*, const PalFlashInfo*); -void xGetWindowTitle(PalWindow*, uint64_t, uint64_t*, char*); -void xGetWindowPos(PalWindow*, int32_t*, int32_t*); -void xGetWindowSize(PalWindow*, uint32_t*, uint32_t*); -void xGetWindowState(PalWindow*, PalWindowState*); +PalResult xEnumerateMonitors( + uint32_t* count, + PalMonitor** outMonitor); + +void xGetPrimaryMonitor(PalMonitor** outMonitor); + +void xGetMonitorInfo( + PalMonitor* monitor, + PalMonitorInfo* info); + +void xEnumerateMonitorModes( + PalMonitor* monitor, + uint32_t* count, + PalMonitorMode* mode); + +void xGetCurrentMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode); + +PalResult xSetMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode); + +PalResult xValidateMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode); + +PalResult xSetMonitorOrientation( + PalMonitor* monitor, + PalOrientation orientation); + +PalResult xCreateWindow( + const PalWindowCreateInfo* info, + PalWindow** outWindow); + +void xDestroyWindow(PalWindow* window); + +void xMaximizeWindow(PalWindow* window); + +void xMinimizeWindow(PalWindow* window); + +void xRestoreWindow(PalWindow* window); + +void xShowWindow(PalWindow* window); + +void xHideWindow(PalWindow* window); + +void xFlashWindow( + PalWindow* window, + const PalFlashInfo* info); + +void xGetWindowStyle( + PalWindow* window, + PalWindowStyle* style); + +void xGetWindowMonitor( + PalWindow* window, + PalMonitor** outMonitor); + +void xGetWindowTitle( + PalWindow* window, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer); + +void xGetWindowPos( + PalWindow* window, + int32_t* x, + int32_t* y); + +void xGetWindowSize( + PalWindow* window, + uint32_t* width, + uint32_t* height); + +void xGetWindowState( + PalWindow* window, + PalWindowState* state); + const PalBool* xGetKeycodeState(); + const PalBool* xGetScancodeState(); + const PalBool* xGetMouseState(); -void xGetMouseDelta(float*, float*); -void xGetMouseWheelDelta(float*, float*); -PalBool xIsWindowVisible(PalWindow*); + +void xGetMouseDelta( + float* dx, + float* dy); + +void xGetMouseWheelDelta( + float* dx, + float* dy); + +PalBool xIsWindowVisible(PalWindow* window); + PalWindow* xGetFocusWindow(); -void xGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); -void xSetWindowOpacity(PalWindow*, float); -void xSetWindowTitle(PalWindow*, const char*); -void xSetWindowPos(PalWindow*, int32_t, int32_t); -void xSetWindowSize(PalWindow*, uint32_t, uint32_t); -void xSetFocusWindow(PalWindow*); - -PalResult xCreateIcon(const PalIconCreateInfo*, PalIcon**); -void xDestroyIcon(PalIcon*); -void xSetWindowIcon(PalWindow*, PalIcon*); - -PalResult xCreateCursor(const PalCursorCreateInfo*, PalCursor**); -PalResult xCreateCursorFrom(PalCursorType, PalCursor**); -void xDestroyCursor(PalCursor*); -void xShowCursor(PalBool); -void xClipCursor(PalWindow*, PalBool); -void xGetCursorPos(PalWindow*, int32_t*, int32_t*); -void xSetCursorPos(PalWindow*, int32_t, int32_t); -void xSetWindowCursor(PalWindow*, PalCursor*); -PalResult xAttachWindow(void*, PalWindow**); -PalResult xDetachWindow(PalWindow*, void**); + +void xGetWindowHandleInfo( + PalWindow* window, + PalWindowHandleInfo* info); + +void xSetWindowOpacity( + PalWindow* window, + float opacity); + +void xSetWindowStyle( + PalWindow* window, + PalWindowStyle style); + +void xSetWindowTitle( + PalWindow* window, + const char* title); + +void xSetWindowPos( + PalWindow* window, + int32_t x, + int32_t y); + +void xSetWindowSize( + PalWindow* window, + uint32_t width, + uint32_t height); + +void xSetFocusWindow(PalWindow* window); + +PalResult xCreateIcon( + const PalIconCreateInfo* info, + PalIcon** outIcon); + +void xDestroyIcon(PalIcon* icon); + +void xSetWindowIcon( + PalWindow* window, + PalIcon* icon); + +PalResult xCreateCursor( + const PalCursorCreateInfo* info, + PalCursor** outCursor); + +PalResult xCreateCursorFrom( + PalCursorType type, + PalCursor** outCursor); + +void xDestroyCursor(PalCursor* cursor); + +void xShowCursor(PalBool show); + +void xClipCursor( + PalWindow* window, + PalBool clip); + +void xGetCursorPos( + PalWindow* window, + int32_t* x, + int32_t* y); + +void xSetCursorPos( + PalWindow* window, + int32_t x, + int32_t y); + +void xSetWindowCursor( + PalWindow* window, + PalCursor* cursor); + +PalResult xAttachWindow( + void* windowHandle, + PalWindow** outWindow); + +PalResult xDetachWindow( + PalWindow* window, + void** outWindowHandle); + void* xGetInstance(); static VideoBackend s_XBackend = { @@ -319,42 +700,190 @@ static VideoBackend s_XBackend = { // ================================================== #if PAL_HAS_WAYLAND_BACKEND == 1 -PalResult wlInitVideo(const PalAllocator*, PalEventDriver*, void*); +PalResult wlInitVideo( + const PalAllocator* allocator, + PalEventDriver* eventDriver, + void* preferredInstance); + void wlShutdownVideo(); + void wlUpdateVideo(); -void wlUpdateVideo(); + PalVideoFeatures wlGetVideoFeatures(); -PalResult wlEnumerateMonitors(uint32_t*, PalMonitor**); -void wlGetMonitorInfo(PalMonitor*, PalMonitorInfo*); -void wlEnumerateMonitorModes(PalMonitor*, uint32_t*, PalMonitorMode*); -void wlGetCurrentMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult wlSetMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult wlValidateMonitorMode(PalMonitor*, PalMonitorMode*); -PalResult wlSetMonitorOrientation(PalMonitor*, PalOrientation); - -PalResult wlCreateWindow(const PalWindowCreateInfo*, PalWindow**); -void wlDestroyWindow(PalWindow*); -void wlMaximizeWindow(PalWindow*); -void wlMinimizeWindow(PalWindow*); -void wlRestoreWindow(PalWindow*); +PalResult wlEnumerateMonitors( + uint32_t* count, + PalMonitor** outMonitor); + +void wlGetPrimaryMonitor(PalMonitor** outMonitor); + +void wlGetMonitorInfo( + PalMonitor* monitor, + PalMonitorInfo* info); + +void wlEnumerateMonitorModes( + PalMonitor* monitor, + uint32_t* count, + PalMonitorMode* mode); + +void wlGetCurrentMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode); + +PalResult wlSetMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode); + +PalResult wlValidateMonitorMode( + PalMonitor* monitor, + PalMonitorMode* mode); + +PalResult wlSetMonitorOrientation( + PalMonitor* monitor, + PalOrientation orientation); + +PalResult wlCreateWindow( + const PalWindowCreateInfo* info, + PalWindow** outWindow); + +void wlDestroyWindow(PalWindow* window); + +void wlMaximizeWindow(PalWindow* window); + +void wlMinimizeWindow(PalWindow* window); + +void wlRestoreWindow(PalWindow* window); + +void wlShowWindow(PalWindow* window); + +void wlHideWindow(PalWindow* window); + +void wlFlashWindow( + PalWindow* window, + const PalFlashInfo* info); + +void wlGetWindowStyle( + PalWindow* window, + PalWindowStyle* style); + +void wlGetWindowMonitor( + PalWindow* window, + PalMonitor** outMonitor); + +void wlGetWindowTitle( + PalWindow* window, + uint64_t bufferSize, + uint64_t* outSize, + char* outBuffer); + +void wlGetWindowPos( + PalWindow* window, + int32_t* x, + int32_t* y); + +void wlGetWindowSize( + PalWindow* window, + uint32_t* width, + uint32_t* height); + +void wlGetWindowState( + PalWindow* window, + PalWindowState* state); + const PalBool* wlGetKeycodeState(); + const PalBool* wlGetScancodeState(); + const PalBool* wlGetMouseState(); -void wlGetMouseDelta(float*, float*); -void wlGetMouseWheelDelta(float*, float*); -PalBool wlIsWindowVisible(PalWindow*); -void wlGetWindowHandleInfo(PalWindow*, PalWindowHandleInfo*); -void wlSetWindowTitle(PalWindow*, const char*); -void wlSetWindowSize(PalWindow*, uint32_t, uint32_t); - -PalResult wlCreateIcon(const PalIconCreateInfo*, PalIcon**); -void wlDestroyIcon(PalIcon*); - -PalResult wlCreateCursor(const PalCursorCreateInfo*, PalCursor**); -PalResult wlCreateCursorFrom(PalCursorType, PalCursor**); -void wlDestroyCursor(PalCursor*); -void wlSetWindowCursor(PalWindow*, PalCursor*); + +void wlGetMouseDelta( + float* dx, + float* dy); + +void wlGetMouseWheelDelta( + float* dx, + float* dy); + +PalBool wlIsWindowVisible(PalWindow* window); + +PalWindow* wlGetFocusWindow(); + +void wlGetWindowHandleInfo( + PalWindow* window, + PalWindowHandleInfo* info); + +void wlSetWindowOpacity( + PalWindow* window, + float opacity); + +void wlSetWindowStyle( + PalWindow* window, + PalWindowStyle style); + +void wlSetWindowTitle( + PalWindow* window, + const char* title); + +void wlSetWindowPos( + PalWindow* window, + int32_t x, + int32_t y); + +void wlSetWindowSize( + PalWindow* window, + uint32_t width, + uint32_t height); + +void wlSetFocusWindow(PalWindow* window); + +PalResult wlCreateIcon( + const PalIconCreateInfo* info, + PalIcon** outIcon); + +void wlDestroyIcon(PalIcon* icon); + +void wlSetWindowIcon( + PalWindow* window, + PalIcon* icon); + +PalResult wlCreateCursor( + const PalCursorCreateInfo* info, + PalCursor** outCursor); + +PalResult wlCreateCursorFrom( + PalCursorType type, + PalCursor** outCursor); + +void wlDestroyCursor(PalCursor* cursor); + +void wlShowCursor(PalBool show); + +void wlClipCursor( + PalWindow* window, + PalBool clip); + +void wlGetCursorPos( + PalWindow* window, + int32_t* x, + int32_t* y); + +void wlSetCursorPos( + PalWindow* window, + int32_t x, + int32_t y); + +void wlSetWindowCursor( + PalWindow* window, + PalCursor* cursor); + +PalResult wlAttachWindow( + void* windowHandle, + PalWindow** outWindow); + +PalResult wlDetachWindow( + PalWindow* window, + void** outWindowHandle); + void* wlGetInstance(); static VideoBackend s_wlBackend = { diff --git a/tests/graphics/custom_backend_test.c b/tests/graphics/custom_backend_test.c index a9f10f16..f94011d8 100644 --- a/tests/graphics/custom_backend_test.c +++ b/tests/graphics/custom_backend_test.c @@ -2,615 +2,717 @@ #include "pal/pal_graphics.h" #include "tests.h" +// we use the same fields for each of our handles so we just typedef a base handle struct +typedef struct { + void* reserved; +} Adapter; + +// we will only expose a single adapter +static Adapter s_Adapter; +static PalAdapterInfo s_Info; +static PalAdapterCapabilities s_Cap; + +static void initBackend() +{ + s_Adapter.reserved = nullptr; + s_Info.apiType = PAL_ADAPTER_API_TYPE_CUSTOM; + strcpy(s_Info.backendName, "Custom"); + s_Info.deviceId = 1666; + s_Info.driverVersion = 1; + strcpy(s_Info.name, "GXR 7060"); + s_Info.shaderFormats = PAL_SHADER_FORMAT_CUSTOM; + s_Info.sharedMemory = (uint64_t)(1024 * 1024 * 1024) * (uint64_t)2; + s_Info.type = PAL_ADAPTER_TYPE_DISCRETE; + s_Info.vendorId = 20037; + s_Info.vram = (uint64_t)(1024 * 1024 * 1024) * (uint64_t)8; + + s_Cap.computeCaps.maxWorkGroupCount[0] = 65535; + s_Cap.computeCaps.maxWorkGroupCount[1] = 65535; + s_Cap.computeCaps.maxWorkGroupCount[2] = 65535; + s_Cap.computeCaps.maxWorkGroupSize[0] = 1024; + s_Cap.computeCaps.maxWorkGroupSize[1] = 1024; + s_Cap.computeCaps.maxWorkGroupSize[2] = 64; + s_Cap.computeCaps.maxWorkGroupInvocations = 1024; + + s_Cap.imageCaps.maxArrayLayers = 5; + s_Cap.imageCaps.maxDepth = 128; + s_Cap.imageCaps.maxHeight = 4800; + s_Cap.imageCaps.maxMipLevels = 12; + s_Cap.imageCaps.maxWidth = 4800; + + s_Cap.maxColorAttachments = 8; + s_Cap.maxComputeQueues = 2; + s_Cap.maxCopyQueues = 2; + s_Cap.maxGraphicsQueues = 2; + s_Cap.maxPushConstantSize = 128; + + s_Cap.maxStorageBufferSize = 65536; + s_Cap.maxTessellationPatchPoint = 8; + s_Cap.maxUniformBufferSize = 65536; + s_Cap.maxVertexAttributes = 14; + s_Cap.maxVertexLayouts = 4; + + s_Cap.resourceCaps.maxBoundSets = 2; + s_Cap.resourceCaps.maxPerSetAccelerationStructure = 2; + s_Cap.resourceCaps.maxPerSetSampledImages = 512; + s_Cap.resourceCaps.maxPerSetSamplers = 256; + s_Cap.resourceCaps.maxPerSetStorageBuffers = 720; + s_Cap.resourceCaps.maxPerSetStorageImages = 720; + s_Cap.resourceCaps.maxPerSetUniformBuffers = 100; + s_Cap.resourceCaps.maxPerStageAccelerationStructure = 10; + s_Cap.resourceCaps.maxPerStageSampledImages = 120; + s_Cap.resourceCaps.maxPerStageSamplers = 16; + s_Cap.resourceCaps.maxPerStageStorageBuffers = 50; + s_Cap.resourceCaps.maxPerStageStorageImages = 50; + s_Cap.resourceCaps.maxPerStageUniformBuffers = 50; + + s_Cap.viewportCaps.maxBoundsRange = 4800.0f; + s_Cap.viewportCaps.minBoundsRange = 4800.0f; + s_Cap.viewportCaps.maxWidth = 4800; + s_Cap.viewportCaps.maxHeight = 4800; +} + static PalResult PAL_CALL enumerateAdapters( - uint32_t*, - PalAdapter**) + uint32_t* count, + PalAdapter** outAdapters) { + if (outAdapters) { + outAdapters[0] = (PalAdapter*)&s_Adapter; + } else { + *count = 1; + } + return PAL_RESULT_SUCCESS; } static void PAL_CALL getAdapterInfo( - PalAdapter*, - PalAdapterInfo*) + PalAdapter* adapter, + PalAdapterInfo* info) { - + *info = s_Info; } static void PAL_CALL getAdapterCapabilities( - PalAdapter*, - PalAdapterCapabilities*) + PalAdapter* adapter, + PalAdapterCapabilities* caps) { - + *caps = s_Cap; } -static PalAdapterFeatures PAL_CALL getAdapterFeatures(PalAdapter*) +static PalAdapterFeatures PAL_CALL getAdapterFeatures(PalAdapter* adapter) { - + return PAL_ADAPTER_FEATURE_FENCE_RESET | PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY; } static uint32_t PAL_CALL getHighestSupportedShaderTarget( - PalAdapter*, - PalShaderFormats) + PalAdapter* adapter, + PalShaderFormats shaderFormat) { - + return PAL_MAKE_SHADER_TARGET(1, 0); } static PalResult PAL_CALL createDevice( - PalAdapter*, - PalAdapterFeatures, - PalDevice**) + PalAdapter* adapter, + PalAdapterFeatures features, + PalDevice** outDevice) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyDevice(PalDevice*) +static void PAL_CALL destroyDevice(PalDevice* device) { - -} - -static PalResult PAL_CALL waitDevice(PalDevice*) -{ - + } static PalResult PAL_CALL allocateMemory( - PalDevice*, - PalMemoryType, - uint64_t, - uint64_t, - PalMemory**) + PalDevice* device, + PalMemoryType type, + uint64_t memoryMask, + uint64_t size, + PalMemory** outMemory) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL freeMemory(PalMemory*) +static void PAL_CALL freeMemory(PalMemory* memory) { - + } static void PAL_CALL querySamplerAnisotropyCapabilities( - PalDevice*, - PalSamplerAnisotropyCapabilities*) + PalDevice* device, + PalSamplerAnisotropyCapabilities* caps) { - + } static PalResult PAL_CALL createQueue( - PalDevice*, - PalQueueType, - PalQueue**) + PalDevice* device, + PalQueueType type, + PalQueue** outQueue) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyQueue(PalQueue*) +static void PAL_CALL destroyQueue(PalQueue* queue) { - + } -static PalResult PAL_CALL waitQueue(PalQueue*) +static PalBool PAL_CALL canQueuePresent( + PalQueue* queue, + PalSurface* surface) { - + return PAL_FALSE; } -static PalBool PAL_CALL canQueuePresent( - PalQueue*, - PalSurface*) +static PalResult PAL_CALL waitQueue(PalQueue* queue) { - + return PAL_RESULT_SUCCESS; } static void PAL_CALL enumerateFormats( - PalAdapter*, - uint32_t*, - PalFormatInfo*) + PalAdapter* adapter, + uint32_t* count, + PalFormatInfo* outFormats) { } static PalBool PAL_CALL isFormatSupported( - PalAdapter*, - PalFormat) + PalAdapter* adapter, + PalFormat format) { - + return PAL_FALSE; } static PalImageUsages PAL_CALL queryFormatImageUsages( - PalAdapter*, - PalFormat) + PalAdapter* adapter, + PalFormat format) { - + return 0; } static PalSampleCount PAL_CALL queryFormatSampleCount( - PalAdapter*, - PalFormat) + PalAdapter* adapter, + PalFormat format) { - + return 0; } static PalResult PAL_CALL createImage( - PalDevice*, - const PalImageCreateInfo*, - PalImage**) + PalDevice* device, + const PalImageCreateInfo* info, + PalImage** outImage) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyImage(PalImage*) +static void PAL_CALL destroyImage(PalImage* image) { - + } static void PAL_CALL getImageInfo( - PalImage*, - PalImageInfo*) + PalImage* image, + PalImageInfo* info) { - + } static void PAL_CALL getImageMemoryRequirements( - PalImage*, - PalMemoryRequirements*) + PalImage* image, + PalMemoryRequirements* requirements) { - + } static PalResult PAL_CALL bindImageMemory( - PalImage*, - PalMemory*, - uint64_t) + PalImage* image, + PalMemory* memory, + uint64_t offset) { - + return PAL_RESULT_SUCCESS; } static PalResult PAL_CALL createImageView( - PalDevice*, - PalImage*, - const PalImageViewCreateInfo*, - PalImageView**) + PalDevice* device, + PalImage* image, + const PalImageViewCreateInfo* info, + PalImageView** outImageView) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyImageView(PalImageView*) +static void PAL_CALL destroyImageView(PalImageView* imageView) { } static PalResult PAL_CALL createSampler( - PalDevice*, - const PalSamplerCreateInfo*, - PalSampler**) + PalDevice* device, + const PalSamplerCreateInfo* info, + PalSampler** outSampler) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroySampler(PalSampler*) +static void PAL_CALL destroySampler(PalSampler* sampler) { } static PalResult PAL_CALL createShader( - PalDevice*, - const PalShaderCreateInfo*, - PalShader**) + PalDevice* device, + const PalShaderCreateInfo* info, + PalShader** outShader) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyShader(PalShader*) +static void PAL_CALL destroyShader(PalShader* shader) { } static PalResult PAL_CALL createFence( - PalDevice*, - PalBool, - PalFence**) + PalDevice* device, + PalBool signaled, + PalFence** outFence) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyFence(PalFence*) +static void PAL_CALL destroyFence(PalFence* fence) { } static PalResult PAL_CALL waitFence( - PalFence*, - uint64_t) + PalFence* fence, + uint64_t timeout) { - + return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL resetFence(PalFence*) +static PalResult PAL_CALL resetFence(PalFence* fence) { - + return PAL_RESULT_SUCCESS; } -static PalBool PAL_CALL isFenceSignaled(PalFence*) +static PalBool PAL_CALL isFenceSignaled(PalFence* fence) { - + return PAL_FALSE; } static PalResult PAL_CALL createSemaphore( - PalDevice*, - PalBool, - PalSemaphore**) + PalDevice* device, + PalBool enableTimeline, + PalSemaphore** outSemaphore) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroySemaphore(PalSemaphore*) +static void PAL_CALL destroySemaphore(PalSemaphore* semaphore) { } static PalResult PAL_CALL createCommandPool( - PalDevice*, - PalQueue*, - PalCommandPool**) + PalDevice* device, + PalQueue* queue, + PalCommandPool** outPool) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyCommandPool(PalCommandPool*) +static void PAL_CALL destroyCommandPool(PalCommandPool* pool) { } static PalResult PAL_CALL allocateCommandBuffer( - PalDevice*, - PalCommandPool*, - PalCommandBufferType, - PalCommandBuffer**) + PalDevice* device, + PalCommandPool* pool, + PalCommandBufferType type, + PalCommandBuffer** outCmdBuffer) +{ + return PAL_RESULT_SUCCESS; +} + +static void PAL_CALL freeCommandBuffer(PalCommandBuffer* cmdBuffer) { } -static void PAL_CALL freeCommandBuffer(PalCommandBuffer*) +static PalResult PAL_CALL resetCommandBuffer(PalCommandBuffer* cmdBuffer) { + return PAL_RESULT_SUCCESS; +} +static PalResult PAL_CALL submitCommandBuffer( + PalQueue* queue, + PalCommandBufferSubmitInfo* info) +{ + return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL resetCommandBuffer(PalCommandBuffer*) +static PalResult PAL_CALL cmdBegin( + PalCommandBuffer* cmdBuffer, + PalRenderingLayoutInfo* info) { + return PAL_RESULT_SUCCESS; +} +static PalResult PAL_CALL cmdEnd(PalCommandBuffer* cmdBuffer) +{ + return PAL_RESULT_SUCCESS; } -static PalResult PAL_CALL submitCommandBuffer( - PalQueue*, - PalCommandBufferSubmitInfo*) +static void PAL_CALL cmdExecuteCommandBuffer( + PalCommandBuffer* primaryCmdBuffer, + PalCommandBuffer* secondaryCmdBuffer) { } -static PalResult PAL_CALL cmdBegin( - PalCommandBuffer*, - PalRenderingLayoutInfo*) +static void PAL_CALL cmdSetFragmentShadingRate( + PalCommandBuffer* cmdBuffer, + PalFragmentShadingRateState* state) { } -static PalResult PAL_CALL cmdEnd(PalCommandBuffer*) +static void PAL_CALL cmdDrawMeshTasks( + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { } -static void PAL_CALL cmdExecuteCommandBuffer( - PalCommandBuffer*, - PalCommandBuffer*) +static void PAL_CALL cmdDrawMeshTasksIndirect( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint32_t drawCount) +{ + +} + +static void PAL_CALL cmdDrawMeshTasksIndirectCount( + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBuffer* countBuffer, + uint32_t maxDrawCount) +{ + +} + +static void PAL_CALL cmdBuildAccelerationStructure( + PalCommandBuffer* cmdBuffer, + PalAccelerationStructureBuildInfo* info) { } static void PAL_CALL cmdBeginRendering( - PalCommandBuffer*, - PalRenderingInfo*) + PalCommandBuffer* cmdBuffer, + PalRenderingInfo* info) { } -static void PAL_CALL cmdEndRendering(PalCommandBuffer*) +static void PAL_CALL cmdEndRendering(PalCommandBuffer* cmdBuffer) { } static void PAL_CALL cmdCopyBuffer( - PalCommandBuffer*, - PalBuffer*, - PalBuffer*, - PalBufferCopyInfo*) + PalCommandBuffer* cmdBuffer, + PalBuffer* dst, + PalBuffer* src, + PalBufferCopyInfo* copyInfo) { } static void PAL_CALL cmdCopyBufferToImage( - PalCommandBuffer*, - PalImage*, - PalBuffer*, - PalBufferImageCopyInfo*) + PalCommandBuffer* cmdBuffer, + PalImage* dstImage, + PalBuffer* srcBuffer, + PalBufferImageCopyInfo* copyInfo) { } static void PAL_CALL cmdCopyImage( - PalCommandBuffer*, - PalImage*, - PalImage*, - PalImageCopyInfo*) + PalCommandBuffer* cmdBuffer, + PalImage* dst, + PalImage* src, + PalImageCopyInfo* copyInfo) { } static void PAL_CALL cmdCopyImageToBuffer( - PalCommandBuffer*, - PalBuffer*, - PalImage*, - PalBufferImageCopyInfo*) + PalCommandBuffer* cmdBuffer, + PalBuffer* dstBuffer, + PalImage* srcImage, + PalBufferImageCopyInfo* copyInfo) { } static void PAL_CALL cmdBindPipeline( - PalCommandBuffer*, - PalPipeline*) + PalCommandBuffer* cmdBuffer, + PalPipeline* pipeline) { } static void PAL_CALL cmdSetViewport( - PalCommandBuffer*, - uint32_t, - PalViewport*) + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalViewport* viewports) { } static void PAL_CALL cmdSetScissors( - PalCommandBuffer*, - uint32_t, - PalRect2D*) + PalCommandBuffer* cmdBuffer, + uint32_t count, + PalRect2D* scissors) { } static void PAL_CALL cmdBindVertexBuffers( - PalCommandBuffer*, - uint32_t, - uint32_t, - PalBuffer**, - uint64_t*) + PalCommandBuffer* cmdBuffer, + uint32_t firstSlot, + uint32_t count, + PalBuffer** buffers, + uint64_t* offsets) { } static void PAL_CALL cmdBindIndexBuffer( - PalCommandBuffer*, - PalBuffer*, - uint64_t, - PalIndexType) + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + uint64_t offset, + PalIndexType type) { } static void PAL_CALL cmdDraw( - PalCommandBuffer*, - uint32_t, - uint32_t, - uint32_t, - uint32_t) + PalCommandBuffer* cmdBuffer, + uint32_t vertexCount, + uint32_t instanceCount, + uint32_t firstVertex, + uint32_t firstInstance) { } static void PAL_CALL cmdDrawIndexed( - PalCommandBuffer*, - uint32_t, - uint32_t, - uint32_t, - int32_t, - uint32_t) + PalCommandBuffer* cmdBuffer, + uint32_t indexCount, + uint32_t instanceCount, + uint32_t firstIndex, + int32_t vertexOffset, + uint32_t firstInstance) { } static void PAL_CALL cmdImageBarrier( - PalCommandBuffer*, - PalImage*, - PalImageSubresourceRange*, - PalBarrierInfo*) + PalCommandBuffer* cmdBuffer, + PalImage* image, + PalImageSubresourceRange* subresourceRange, + PalBarrierInfo* info) { } static void PAL_CALL cmdBufferBarrier( - PalCommandBuffer*, - PalBuffer*, - PalBarrierInfo*) + PalCommandBuffer* cmdBuffer, + PalBuffer* buffer, + PalBarrierInfo* info) { } static void PAL_CALL cmdDispatch( - PalCommandBuffer*, - uint32_t, - uint32_t, - uint32_t) + PalCommandBuffer* cmdBuffer, + uint32_t groupCountX, + uint32_t groupCountY, + uint32_t groupCountZ) { } static void PAL_CALL cmdBindDescriptorSet( - PalCommandBuffer*, - uint32_t, - PalDescriptorSet*) + PalCommandBuffer* cmdBuffer, + uint32_t setIndex, + PalDescriptorSet* set) { } static void PAL_CALL cmdPushConstants( - PalCommandBuffer*, - uint32_t, - uint32_t, - const void*) + PalCommandBuffer* cmdBuffer, + uint32_t offset, + uint32_t size, + const void* value) { } static PalResult PAL_CALL createBuffer( - PalDevice*, - const PalBufferCreateInfo*, - PalBuffer**) + PalDevice* device, + const PalBufferCreateInfo* info, + PalBuffer** outBuffer) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyBuffer(PalBuffer*) +static void PAL_CALL destroyBuffer(PalBuffer* buffer) { } static void PAL_CALL getBufferMemoryRequirements( - PalBuffer*, - PalMemoryRequirements*) + PalBuffer* buffer, + PalMemoryRequirements* requirements) { } static void PAL_CALL computeImageStagingRequirements( - PalDevice*, - PalFormat, - const PalBufferImageCopyInfo*, - PalImageStagingRequirements*) + PalDevice* device, + PalFormat imageFormat, + const PalBufferImageCopyInfo* copyInfo, + PalImageStagingRequirements* requirements) { } static void PAL_CALL writeImageStaging( - PalDevice*, - PalFormat, - PalBufferImageCopyInfo*, - void*, - void*) + PalDevice* device, + PalFormat imageFormat, + PalBufferImageCopyInfo* copyInfo, + void* srcData, + void* ptr) { } static PalResult PAL_CALL bindBufferMemory( - PalBuffer*, - PalMemory*, - uint64_t) + PalBuffer* buffer, + PalMemory* memory, + uint64_t offset) { - + return PAL_RESULT_SUCCESS; } static PalResult PAL_CALL mapBuffer( - PalBuffer*, - uint64_t, - uint64_t, - void**) + PalBuffer* buffer, + uint64_t offset, + uint64_t size, + void** outPtr) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL unmapBuffer(PalBuffer*) +static void PAL_CALL unmapBuffer(PalBuffer* buffer) { } static PalResult PAL_CALL createDescriptorSetLayout( - PalDevice*, - const PalDescriptorSetLayoutCreateInfo*, - PalDescriptorSetLayout**) + PalDevice* device, + const PalDescriptorSetLayoutCreateInfo* info, + PalDescriptorSetLayout** outLayout) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyDescriptorSetLayout(PalDescriptorSetLayout*) +static void PAL_CALL destroyDescriptorSetLayout(PalDescriptorSetLayout* layout) { } static PalResult PAL_CALL createDescriptorPool( - PalDevice*, - const PalDescriptorPoolCreateInfo*, - PalDescriptorPool**) + PalDevice* device, + const PalDescriptorPoolCreateInfo* info, + PalDescriptorPool** outPool) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyDescriptorPool(PalDescriptorPool*) +static void PAL_CALL destroyDescriptorPool(PalDescriptorPool* pool) { } -static PalResult PAL_CALL resetDescriptorPool(PalDescriptorPool*) +static PalResult PAL_CALL resetDescriptorPool(PalDescriptorPool* pool) { - + return PAL_RESULT_SUCCESS; } static PalResult PAL_CALL allocateDescriptorSet( - PalDevice*, - PalDescriptorPool*, - PalDescriptorSetLayout*, - PalDescriptorSet**) + PalDevice* device, + PalDescriptorPool* pool, + PalDescriptorSetLayout* layout, + PalDescriptorSet** outSet) { - + return PAL_RESULT_SUCCESS; } static PalResult PAL_CALL updateDescriptorSet( - PalDevice*, - uint32_t, - PalDescriptorSetWriteInfo*) + PalDevice* device, + uint32_t count, + PalDescriptorSetWriteInfo* infos) { - + return PAL_RESULT_SUCCESS; } static PalResult PAL_CALL createPipelineLayout( - PalDevice*, - const PalPipelineLayoutCreateInfo*, - PalPipelineLayout**) + PalDevice* device, + const PalPipelineLayoutCreateInfo* info, + PalPipelineLayout** outLayout) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyPipelineLayout(PalPipelineLayout*) +static void PAL_CALL destroyPipelineLayout(PalPipelineLayout* layout) { } static PalResult PAL_CALL createGraphicsPipeline( - PalDevice*, - const PalGraphicsPipelineCreateInfo*, - PalPipeline**) + PalDevice* device, + const PalGraphicsPipelineCreateInfo* info, + PalPipeline** outPipeline) { - + return PAL_RESULT_SUCCESS; } static PalResult PAL_CALL createComputePipeline( - PalDevice*, - const PalComputePipelineCreateInfo*, - PalPipeline**) + PalDevice* device, + const PalComputePipelineCreateInfo* info, + PalPipeline** outPipeline) { - + return PAL_RESULT_SUCCESS; } -static void PAL_CALL destroyPipeline(PalPipeline*) +static void PAL_CALL destroyPipeline(PalPipeline* pipeline) { } -static void PAL_CALL onGraphicsDebug( - void* userData, - PalDebugMessageSeverity severity, - PalDebugMessageType type, - const char* msg) -{ - palLog(nullptr, msg); -} - PalBool customBackendTest() { // build the vtable @@ -703,14 +805,353 @@ PalBool customBackendTest() backendInfo.version = PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1; backendInfo.vtable = &vtable; + // do any backend initialization before graphics init + initBackend(); + PalResult result = palInitGraphics(nullptr, nullptr, 1, &backendInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to initialize graphics"); return PAL_FALSE; } - // TODO: enumerate and select our adapter and do some work + // enumerate all available adapters + uint32_t count = 0; + result = palEnumerateAdapters(&count, nullptr); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get query adapters"); + return PAL_FALSE; + } + + if (count == 0) { + palLog(nullptr, "No adapters found"); + return PAL_FALSE; + } + palLog(nullptr, "Adapter count: %u", count); + + // allocate an array of adapters or use a fixed array + // Example: PalAdapter* adapters[12]; + PalAdapter** adapters = nullptr; + adapters = palAllocate(nullptr, sizeof(PalAdapter*) * count, 0); + if (!adapters) { + palLog(nullptr, "Failed to allocate memory"); + return PAL_FALSE; + } + + result = palEnumerateAdapters(&count, adapters); + if (result != PAL_RESULT_SUCCESS) { + logResult(result, "Failed to get query adapters"); + return PAL_FALSE; + } + + for (int32_t i = 0; i < count; i++) { + PalAdapter* adapter = adapters[i]; + + PalAdapterInfo info; + palGetAdapterInfo(adapter, &info); + + PalAdapterCapabilities caps; + palGetAdapterCapabilities(adapter, &caps); + PalAdapterFeatures features = palGetAdapterFeatures(adapter); + + uint64_t vramMib = (uint64_t)info.vram / (1024 * 1024); + uint64_t sharedMemMib = (uint64_t)info.sharedMemory /(1024 * 1024); + + palLog(nullptr, "GPU Name: %s", info.name); + palLog(nullptr, " Backend Name: %s", info.backendName); + palLog(nullptr, " Driver Version: %llu", info.driverVersion); + palLog(nullptr, " Vram %llu MIB", vramMib); + palLog(nullptr, " Shared Memory %llu MIB", sharedMemMib); + palLog(nullptr, " Device Id: %u", info.deviceId); + palLog(nullptr, " Vendor Id: %u", info.vendorId); + + const char* typeString; + switch (info.type) { + case PAL_ADAPTER_TYPE_INTEGRATED: { + typeString = "Integrated"; + break; + } + + case PAL_ADAPTER_TYPE_VIRTUAL: { + typeString = "Virtual"; + break; + } + + case PAL_ADAPTER_TYPE_DISCRETE: { + typeString = "Discrete"; + break; + } + + case PAL_ADAPTER_TYPE_CPU: { + typeString = "CPU"; + break; + } + } + palLog(nullptr, " Type: %s", typeString); + + const char* apiTypeString; + switch (info.apiType) { + case PAL_ADAPTER_API_TYPE_D3D12: { + apiTypeString = "D3D12"; + break; + } + + case PAL_ADAPTER_API_TYPE_VULKAN: { + apiTypeString = "Vulkan"; + break; + } + + case PAL_ADAPTER_API_TYPE_METAL: { + apiTypeString = "Metal"; + break; + } + + case PAL_ADAPTER_API_TYPE_CUSTOM: { + apiTypeString = "Custom"; + break; + } + } + palLog(nullptr, " API Type: %s", apiTypeString); + + palLog(nullptr, ""); + palLog(nullptr, " Capabilities:"); + palLog(nullptr, " Max compute queue: %u", caps.maxComputeQueues); + palLog(nullptr, " Max graphics queue: %u", caps.maxGraphicsQueues); + palLog(nullptr, " Max copy queue: %u", caps.maxCopyQueues); + palLog(nullptr, " Max color attachments: %u", caps.maxColorAttachments); + palLog(nullptr, " Max uniform buffer size: %u Bytes", caps.maxUniformBufferSize); + + palLog(nullptr, " Max storage buffer size: %u Bytes", caps.maxStorageBufferSize); + palLog(nullptr, " Max push constant size: %u Bytes", caps.maxPushConstantSize); + palLog(nullptr, " Max vertex layouts: %u", caps.maxVertexLayouts); + palLog(nullptr, " Max vertex attributes: %u", caps.maxVertexAttributes); + palLog(nullptr, " Max tessellation patch point: %u", caps.maxTessellationPatchPoint); + + palLog(nullptr, ""); + palLog(nullptr, " Viewport Capabilities:"); + palLog(nullptr, " Max width: %u", caps.viewportCaps.maxWidth); + palLog(nullptr, " Max height: %u", caps.viewportCaps.maxHeight); + palLog(nullptr, " Min bounds range: %.1f", caps.viewportCaps.minBoundsRange); + palLog(nullptr, " Max bounds range: %.1f", caps.viewportCaps.maxBoundsRange); + + palLog(nullptr, ""); + palLog(nullptr, " Image Capabilities:"); + palLog(nullptr, " Max width: %u", caps.imageCaps.maxWidth); + palLog(nullptr, " Max height: %u", caps.imageCaps.maxHeight); + palLog(nullptr, " Max depth: %u", caps.imageCaps.maxDepth); + palLog(nullptr, " Max array layers: %u", caps.imageCaps.maxArrayLayers); + palLog(nullptr, " Max mip levels: %u", caps.imageCaps.maxMipLevels); + + palLog(nullptr, ""); + palLog(nullptr, " Resource Capabilities:"); + PalResourceCapabilities* resourceCaps = &caps.resourceCaps; + + // clang-format off + palLog(nullptr, " Max per stage sampled images: %u", resourceCaps->maxPerStageSampledImages); + palLog(nullptr, " Max per set sampled images: %u", resourceCaps->maxPerSetSampledImages); + palLog(nullptr, " Max per stage storage images: %u", resourceCaps->maxPerStageStorageImages); + palLog(nullptr, " Max per set storage images: %u", resourceCaps->maxPerSetStorageImages); + + palLog(nullptr, " Max per stage samplers: %u", resourceCaps->maxPerStageSamplers); + palLog(nullptr, " Max per set samplers: %u", resourceCaps->maxPerSetSamplers); + palLog(nullptr, " Max per stage storage buffers: %u", resourceCaps->maxPerStageStorageBuffers); + palLog(nullptr, " Max per set storage buffers: %u", resourceCaps->maxPerSetStorageBuffers); + + palLog(nullptr, " Max per stage uniform buffers: %u", resourceCaps->maxPerStageUniformBuffers); + palLog(nullptr, " Max per set uniform buffers: %u", resourceCaps->maxPerSetUniformBuffers); + palLog(nullptr, " Max per stage acceleration structures: %u", resourceCaps->maxPerStageAccelerationStructure); + palLog(nullptr, " Max per set acceleration structures: %u", resourceCaps->maxPerSetAccelerationStructure); + palLog(nullptr, " Max bound sets: %u", resourceCaps->maxBoundSets); + // clang-format on + + palLog(nullptr, ""); + palLog(nullptr, " Compute Capabilities:"); + palLog(nullptr, " Max invocations: %u", caps.computeCaps.maxWorkGroupInvocations); + palLog(nullptr, " Max work group count[0]: %u", caps.computeCaps.maxWorkGroupCount[0]); + palLog(nullptr, " Max work group count[1]: %u", caps.computeCaps.maxWorkGroupCount[1]); + palLog(nullptr, " Max work group count[2]: %u", caps.computeCaps.maxWorkGroupCount[2]); + palLog(nullptr, " Max work group size[0]: %u", caps.computeCaps.maxWorkGroupSize[0]); + palLog(nullptr, " Max work group size[1]: %u", caps.computeCaps.maxWorkGroupSize[1]); + palLog(nullptr, " Max work group size[2]: %u", caps.computeCaps.maxWorkGroupSize[2]); + + // shader formats + uint32_t target; + uint32_t targetMajor = 0; + uint32_t targetMinor = 0; + + palLog(nullptr, ""); + palLog(nullptr, " Supported Shader Formats:"); + if (info.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { + palLog(nullptr, " SPIRV"); + } + + if (info.shaderFormats & PAL_SHADER_FORMAT_DXBC) { + palLog(nullptr, " DXBC"); + } + + if (info.shaderFormats & PAL_SHADER_FORMAT_DXIL) { + palLog(nullptr, " DXIL"); + } + + if (info.shaderFormats & PAL_SHADER_FORMAT_CUSTOM) { + palLog(nullptr, " Custom"); + } + + // features + palLog(nullptr, ""); + palLog(nullptr, " Supported Features:"); + if (features & PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY) { + palLog(nullptr, " Sampler Anisotropy"); + } + + if (features & PAL_ADAPTER_FEATURE_MULTI_VIEWPORT) { + palLog(nullptr, " Multi viewport"); + } + + if (features & PAL_ADAPTER_FEATURE_RAY_TRACING) { + palLog(nullptr, " Ray tracing"); + } + + if (features & PAL_ADAPTER_FEATURE_MESH_SHADER) { + palLog(nullptr, " Mesh and task shader"); + } + + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE) { + palLog(nullptr, " Fragment shading rate"); + } + + if (features & PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING) { + palLog(nullptr, " Descriptor indexing"); + } + + if (features & PAL_ADAPTER_FEATURE_MULTI_VIEW) { + palLog(nullptr, " Multiview"); + } + + if (features & PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE) { + palLog(nullptr, " Depth stencil resolve"); + } + + if (features & PAL_ADAPTER_FEATURE_SWAPCHAIN) { + palLog(nullptr, " Swapchain"); + } + + if (features & PAL_ADAPTER_FEATURE_SAMPLE_RATE_SHADING) { + palLog(nullptr, " Sample rate shading"); + } + + if (features & PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE) { + palLog(nullptr, " Timeline Semaphore"); + } + + if (features & PAL_ADAPTER_FEATURE_TESSELLATION_SHADER) { + palLog(nullptr, " Tesselation Shader"); + } + + if (features & PAL_ADAPTER_FEATURE_GEOMETRY_SHADER) { + palLog(nullptr, " Geometry shader"); + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT16) { + palLog(nullptr, " Shader float16"); + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_FLOAT64) { + palLog(nullptr, " Shader float64"); + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_INT16) { + palLog(nullptr, " Shader int16"); + } + + if (features & PAL_ADAPTER_FEATURE_SHADER_INT64) { + palLog(nullptr, " Shader int64"); + } + + if (features & PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY) { + palLog(nullptr, " Image view type Cube array"); + } + + if (features & PAL_ADAPTER_FEATURE_FENCE_RESET) { + palLog(nullptr, " Resetting fence"); + } + + if (features & PAL_ADAPTER_FEATURE_POLYGON_MODE_LINE) { + palLog(nullptr, " Polygon mode line"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { + palLog(nullptr, " Dynamic cull mode"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { + palLog(nullptr, " Dynamic front face"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { + palLog(nullptr, " Dynamic primitive topology"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { + palLog(nullptr, " Dynamic depth test enable"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { + palLog(nullptr, " Dynamic depth write enable"); + } + + if (features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { + palLog(nullptr, " Dynamic stencil op"); + } + + if (features & PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT) { + palLog(nullptr, " Fragment shading rate attachment"); + } + + if (features & PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS) { + palLog(nullptr, " Buffer device address"); + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW) { + palLog(nullptr, " Indirect draw"); + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT) { + palLog(nullptr, " Indirect draw count"); + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH) { + palLog(nullptr, " Indirect mesh draw"); + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT) { + palLog(nullptr, " Indirect mesh draw count"); + } + + if (features & PAL_ADAPTER_FEATURE_DISPATCH_BASE) { + palLog(nullptr, " Dispatch base"); + } + + if (features & PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS) { + palLog(nullptr, " Null descriptors"); + } + + if (features & PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING) { + palLog(nullptr, " Indirect ray tracing"); + } + + if (features & PAL_ADAPTER_FEATURE_RAY_QUERY) { + palLog(nullptr, " Ray query"); + } + + palLog(nullptr, ""); + } + + // shutdown the graphics system palShutdownGraphics(); + // do any shutdown of the backend after graphics shutdown + + palFree(nullptr, adapters); + return PAL_TRUE; } \ No newline at end of file diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 7607090e..0aae1eec 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -83,15 +83,15 @@ PalBool graphicsTest() palFree(nullptr, adapters); return PAL_FALSE; } - - uint32_t vramMb = (uint32_t)info.vram / (1024 * 1024); - uint32_t sharedMemMb = (uint32_t)info.sharedMemory /(1024 * 1024); + + uint64_t vramMib = (uint64_t)info.vram / (1024 * 1024); + uint64_t sharedMemMib = (uint64_t)info.sharedMemory /(1024 * 1024); palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Backend Name: %s", info.backendName); palLog(nullptr, " Driver Version: %llu", info.driverVersion); - palLog(nullptr, " Vram %u MB", vramMb); - palLog(nullptr, " Shared Memory %u MB", sharedMemMb); + palLog(nullptr, " Vram %llu MIB", vramMib); + palLog(nullptr, " Shared Memory %llu MIB", sharedMemMib); palLog(nullptr, " Device Id: %u", info.deviceId); palLog(nullptr, " Vendor Id: %u", info.vendorId); diff --git a/tests/tests_main.c b/tests/tests_main.c index e7371f3e..ca3fadf6 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -60,6 +60,7 @@ int main(int argc, char** argv) // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); + registerTest(customBackendTest, "Custom Backend Test"); #endif // PAL_HAS_GRAPHICS_MODULE #if PAL_HAS_GRAPHICS_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 && PAL_HAS_SYSTEM_MODULE == 1 From 81afa03da8f83d2ffbcab2be11e4c97601024789 Mon Sep 17 00:00:00 2001 From: nichcode Date: Mon, 20 Jul 2026 14:20:46 +0000 Subject: [PATCH 360/372] prepare for 2.0 release --- include/pal/pal_core.h | 22 +- include/pal/pal_graphics.h | 261 +++++++++--------- include/pal/pal_opengl.h | 5 +- include/pal/pal_video.h | 4 +- src/core/posix/pal_log_posix.c | 2 +- src/core/posix/pal_result_posix.c | 2 +- src/core/win32/pal_result_win32.c | 4 +- src/event/pal_default_queue.c | 2 +- src/graphics/d3d12/pal_adapter_d3d12.c | 114 ++++---- src/graphics/d3d12/pal_as_d3d12.c | 18 +- src/graphics/d3d12/pal_buffer_d3d12.c | 16 +- src/graphics/d3d12/pal_command_pool_d3d12.c | 12 +- src/graphics/d3d12/pal_commands_d3d12.c | 57 ++-- src/graphics/d3d12/pal_d3d12.c | 87 +++--- src/graphics/d3d12/pal_descriptors_d3d12.c | 63 ++--- src/graphics/d3d12/pal_device_d3d12.c | 62 ++--- src/graphics/d3d12/pal_image_d3d12.c | 40 +-- src/graphics/d3d12/pal_pipeline_d3d12.c | 50 ++-- src/graphics/d3d12/pal_sbt_d3d12.c | 27 +- src/graphics/d3d12/pal_swapchain_d3d12.c | 21 +- src/graphics/d3d12/pal_sync_d3d12.c | 31 +-- src/graphics/pal_graphics.c | 66 ++--- src/graphics/pal_graphics_backends.h | 51 +--- src/graphics/vulkan/pal_adapter_vulkan.c | 10 +- src/graphics/vulkan/pal_as_vulkan.c | 4 +- src/graphics/vulkan/pal_buffer_vulkan.c | 15 +- src/graphics/vulkan/pal_command_pool_vulkan.c | 9 +- src/graphics/vulkan/pal_commands_vulkan.c | 91 +++--- src/graphics/vulkan/pal_descriptors_vulkan.c | 20 +- src/graphics/vulkan/pal_device_vulkan.c | 30 +- src/graphics/vulkan/pal_image_vulkan.c | 27 +- src/graphics/vulkan/pal_pipeline_vulkan.c | 32 +-- src/graphics/vulkan/pal_sbt_vulkan.c | 22 +- src/graphics/vulkan/pal_swapchain_vulkan.c | 4 +- src/graphics/vulkan/pal_sync_vulkan.c | 18 +- src/graphics/vulkan/pal_vulkan.c | 20 +- src/opengl/egl/pal_context_egl.c | 8 +- src/opengl/egl/pal_egl.c | 11 +- src/opengl/pal_opengl.c | 4 +- src/opengl/wgl/pal_context_wgl.c | 53 ++-- src/opengl/wgl/pal_wgl.c | 20 +- src/system/linux/pal_platform_linux.c | 2 +- src/thread/posix/pal_thread_posix.c | 10 +- src/thread/win32/pal_condvar_win32.c | 20 +- src/thread/win32/pal_mutex_win32.c | 4 +- src/thread/win32/pal_thread_win32.c | 69 +---- src/video/pal_video.c | 22 +- src/video/wayland/pal_video_wayland.c | 110 +++----- src/video/wayland/pal_window_wayland.c | 8 +- src/video/win32/pal_cursor_win32.c | 12 +- src/video/win32/pal_icon_win32.c | 8 +- src/video/win32/pal_monitor_win32.c | 16 +- src/video/win32/pal_video_win32.c | 15 +- src/video/win32/pal_window_win32.c | 31 +-- src/video/x11/pal_video_x11.c | 36 +-- src/video/x11/pal_window_x11.c | 14 +- tests/graphics/clear_color_test.c | 21 +- tests/graphics/compute_test.c | 30 +- tests/graphics/custom_backend_test.c | 165 +++-------- tests/graphics/descriptor_indexing_test.c | 70 +++-- tests/graphics/geometry_test.c | 26 +- tests/graphics/graphics_test.c | 6 +- tests/graphics/indirect_draw_test.c | 30 +- tests/graphics/mesh_test.c | 26 +- tests/graphics/multi_descriptor_set_test.c | 34 +-- tests/graphics/ray_tracing_test.c | 63 ++--- tests/graphics/texture_test.c | 76 ++--- tests/graphics/triangle_test.c | 24 +- tests/opengl/multi_thread_opengl_test.c | 23 +- tests/opengl/opengl_context_test.c | 10 +- tests/opengl/opengl_multi_context_test.c | 8 +- tests/system/cpu_test.c | 2 +- tests/system/platform_test.c | 4 +- tests/tests.c | 6 +- tests/tests_main.c | 4 +- tests/thread/condvar_test.c | 2 +- tests/thread/mutex_test.c | 2 +- tests/thread/thread_test.c | 2 +- tests/thread/tls_test.c | 2 +- tests/video/attach_window_test.c | 2 +- tests/video/cursor_test.c | 2 +- tests/video/custom_decoration_test.c | 17 +- tests/video/native_instance_test.c | 2 +- tests/video/native_integration_test.c | 2 +- tests/video/window_test.c | 15 +- tools/abi_dump/core_abi_dump.c | 19 +- tools/abi_dump/event_abi_dump.c | 24 +- tools/abi_dump/graphics_abi_dump.c | 4 +- tools/abi_dump/opengl_abi_dump.c | 68 +++-- tools/abi_dump/system_abi_dump.c | 34 ++- tools/abi_dump/thread_abi_dump.c | 9 +- tools/abi_dump/video_abi_dump.c | 89 +++--- 92 files changed, 1125 insertions(+), 1590 deletions(-) diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index dcb7ba14..80c7c4cd 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -89,18 +89,18 @@ typedef uint32_t PalBool; /** * @typedef PalResult * @brief Value returned by most PAL functions. - * - * `PalResult` constains the PAL result code (eg. `PAL_RESULT_CODE_INVALID_HANDLE`), the native - * source (eg. `PAL_RESULT_SOURCE_POSIX`) and the native code itself. + * + * `PalResult` constains the PAL result code (eg. `PAL_RESULT_CODE_INVALID_HANDLE`), the native + * source (eg. `PAL_RESULT_SOURCE_POSIX`) and the native code itself. * The native code and the source are optional and both can be zero if not provided. - * + * * Only `PAL_RESULT_SUCCESS` is guarantee to be checked directly with the result value. * To check specific result codes for fast path error handling, * Call `palGetResultCode(result)` to get the PAL result code from the result value. - * - * Call `palGetResultSource(result)` and `palGetResultNativeCode(result)` to get the native + * + * Call `palGetResultSource(result)` and `palGetResultNativeCode(result)` to get the native * source and native code. The native source shows where the native code was retrieved from. - * Example: `PAL_RESULT_SOURCE_WIN32` means the native code was retrieved from win32 + * Example: `PAL_RESULT_SOURCE_WIN32` means the native code was retrieved from win32 * (`GetLastError()`). * * @since 1.0 @@ -110,9 +110,9 @@ typedef uint64_t PalResult; /** * @typedef PalResultCode * @brief Result codes that are extracted from `PalResult`. - * + * * `palGetResultCode(result)` to get the result code from a result value. - * + * * All result codes follow the format `PAL_RESULT_CODE_**` for consistency and API use. * * @since 2.0 @@ -122,9 +122,9 @@ typedef uint16_t PalResultCode; /** * @typedef PalResultSource * @brief Result sources that are extracted from `PalResult`. - * + * * `palGetResultSource(result)` to get the result source from a result value. - * + * * All result sources follow the format `PAL_RESULT_SOURCE_**` for consistency and API use. * * @since 2.0 diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index e0ef8097..31248abd 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -72,19 +72,23 @@ #define PAL_ADAPTER_TYPE_CPU 4 #define PAL_ADAPTER_TYPE_COUNT 5 -#define PAL_ADAPTER_API_TYPE_VULKAN 0 -#define PAL_ADAPTER_API_TYPE_D3D12 1 -#define PAL_ADAPTER_API_TYPE_METAL 2 -#define PAL_ADAPTER_API_TYPE_CUSTOM 3 -#define PAL_ADAPTER_API_TYPE_COUNT 4 +#define PAL_ADAPTER_API_TYPE_UNKNOWN 0 +#define PAL_ADAPTER_API_TYPE_VULKAN 1 +#define PAL_ADAPTER_API_TYPE_D3D12 2 +#define PAL_ADAPTER_API_TYPE_METAL 3 +#define PAL_ADAPTER_API_TYPE_D3D11 4 +#define PAL_ADAPTER_API_TYPE_D3D9 5 +#define PAL_ADAPTER_API_TYPE_OPENGL 6 +#define PAL_ADAPTER_API_TYPE_OPENGLES 7 +#define PAL_ADAPTER_API_TYPE_WEBGPU 8 +#define PAL_ADAPTER_API_TYPE_COUNT 9 #define PAL_QUEUE_TYPE_GRAPHICS 0 #define PAL_QUEUE_TYPE_COMPUTE 1 #define PAL_QUEUE_TYPE_COPY 2 #define PAL_QUEUE_TYPE_COUNT 3 -/** V-Sync.*/ -#define PAL_PRESENT_MODE_FIFO 0 +#define PAL_PRESENT_MODE_FIFO 0 /**< V-Sync.*/ #define PAL_PRESENT_MODE_IMMEDIATE 1 #define PAL_PRESENT_MODE_MAILBOX 2 #define PAL_PRESENT_MODE_COUNT 3 @@ -185,11 +189,15 @@ #define PAL_IMAGE_USAGE_STORAGE (1U << 4) #define PAL_IMAGE_USAGE_SAMPLED (1U << 5) +#define PAL_SHADER_FORMAT_UNKNOWN 0 #define PAL_SHADER_FORMAT_SPIRV (1U << 0) #define PAL_SHADER_FORMAT_DXIL (1U << 1) #define PAL_SHADER_FORMAT_DXBC (1U << 2) -#define PAL_SHADER_FORMAT_MSL (1U << 3) -#define PAL_SHADER_FORMAT_CUSTOM (1U << 4) +#define PAL_SHADER_FORMAT_METALLIB (1U << 3) +#define PAL_SHADER_FORMAT_MSL (1U << 4) +#define PAL_SHADER_FORMAT_GLSL (1U << 5) +#define PAL_SHADER_FORMAT_HLSL (1U << 6) +#define PAL_SHADER_FORMAT_WGSL (1U << 7) #define PAL_LOAD_OP_LOAD 0 #define PAL_LOAD_OP_CLEAR 1 @@ -311,34 +319,34 @@ #define PAL_STENCIL_FACE_FLAG_BOTH (PAL_STENCIL_FACE_FLAG_FRONT | PAL_STENCIL_FACE_FLAG_BACK) #define PAL_VERTEX_TYPE_UNDEFINED 0 -#define PAL_VERTEX_TYPE_INT32 1 -#define PAL_VERTEX_TYPE_INT32_2 2 -#define PAL_VERTEX_TYPE_INT32_3 3 -#define PAL_VERTEX_TYPE_INT32_4 4 -#define PAL_VERTEX_TYPE_UINT32 5 -#define PAL_VERTEX_TYPE_UINT32_2 6 -#define PAL_VERTEX_TYPE_UINT32_3 7 -#define PAL_VERTEX_TYPE_UINT32_4 8 -#define PAL_VERTEX_TYPE_INT8_2 9 -#define PAL_VERTEX_TYPE_INT8_4 10 -#define PAL_VERTEX_TYPE_UINT8_2 11 -#define PAL_VERTEX_TYPE_UINT8_4 12 -#define PAL_VERTEX_TYPE_INT8_2NORM 13 -#define PAL_VERTEX_TYPE_INT8_4NORM 14 -#define PAL_VERTEX_TYPE_UINT8_2NORM 15 -#define PAL_VERTEX_TYPE_UINT8_4NORM 16 -#define PAL_VERTEX_TYPE_INT16_2 17 -#define PAL_VERTEX_TYPE_INT16_4 18 -#define PAL_VERTEX_TYPE_UINT16_2 19 -#define PAL_VERTEX_TYPE_UINT16_4 20 -#define PAL_VERTEX_TYPE_INT16_2NORM 21 -#define PAL_VERTEX_TYPE_INT16_4NORM 22 -#define PAL_VERTEX_TYPE_UINT16_2NORM 23 -#define PAL_VERTEX_TYPE_UINT16_4NORM 24 -#define PAL_VERTEX_TYPE_FLOAT 25 -#define PAL_VERTEX_TYPE_FLOAT2 26 -#define PAL_VERTEX_TYPE_FLOAT3 27 -#define PAL_VERTEX_TYPE_FLOAT4 28 +#define PAL_VERTEX_TYPE_INT32 1 +#define PAL_VERTEX_TYPE_INT32_2 2 +#define PAL_VERTEX_TYPE_INT32_3 3 +#define PAL_VERTEX_TYPE_INT32_4 4 +#define PAL_VERTEX_TYPE_UINT32 5 +#define PAL_VERTEX_TYPE_UINT32_2 6 +#define PAL_VERTEX_TYPE_UINT32_3 7 +#define PAL_VERTEX_TYPE_UINT32_4 8 +#define PAL_VERTEX_TYPE_INT8_2 9 +#define PAL_VERTEX_TYPE_INT8_4 10 +#define PAL_VERTEX_TYPE_UINT8_2 11 +#define PAL_VERTEX_TYPE_UINT8_4 12 +#define PAL_VERTEX_TYPE_INT8_2NORM 13 +#define PAL_VERTEX_TYPE_INT8_4NORM 14 +#define PAL_VERTEX_TYPE_UINT8_2NORM 15 +#define PAL_VERTEX_TYPE_UINT8_4NORM 16 +#define PAL_VERTEX_TYPE_INT16_2 17 +#define PAL_VERTEX_TYPE_INT16_4 18 +#define PAL_VERTEX_TYPE_UINT16_2 19 +#define PAL_VERTEX_TYPE_UINT16_4 20 +#define PAL_VERTEX_TYPE_INT16_2NORM 21 +#define PAL_VERTEX_TYPE_INT16_4NORM 22 +#define PAL_VERTEX_TYPE_UINT16_2NORM 23 +#define PAL_VERTEX_TYPE_UINT16_4NORM 24 +#define PAL_VERTEX_TYPE_FLOAT 25 +#define PAL_VERTEX_TYPE_FLOAT2 26 +#define PAL_VERTEX_TYPE_FLOAT3 27 +#define PAL_VERTEX_TYPE_FLOAT4 28 #define PAL_VERTEX_TYPE_HALF_FLOAT16_2 29 #define PAL_VERTEX_TYPE_HALF_FLOAT16_4 30 #define PAL_VERTEX_TYPE_COUNT 31 @@ -1429,17 +1437,17 @@ typedef uint32_t PalRayTracingShaderGroupType; /** * @typedef PalDescriptorIndexingFlags * @brief Descriptor indexing subfeature flags. - * - * These flags show the capabilities of the descriptor indexing feature. Each flag determines + * + * These flags show the capabilities of the descriptor indexing feature. Each flag determines * the operations that are allowed. - * - * `PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND`: Descriptors in a descriptor set can be updated + * + * `PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND`: Descriptors in a descriptor set can be updated * after the descriptor set been bound in a command buffer. - * + * * `PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND`: Unused descriptors can be left uninitialized if * a shader never accesses them. - * - * `PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING`: Different threads can access different + * + * `PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING`: Different threads can access different * descriptors. * * All descriptor indexing flags follow the format `PAL_DESCRIPTOR_INDEXING_FLAG_**` @@ -1452,18 +1460,18 @@ typedef uint32_t PalDescriptorIndexingFlags; /** * @typedef PalBufferMemoryUsage * @brief Buffer memory usages. - * + * * `PAL_BUFFER_MEMORY_USAGE_MANUAL`: PAL does not allocate memory for the buffer. Users are required - * to get the required size and allocate memory for the buffer after the buffer has been created. + * to get the required size and allocate memory for the buffer after the buffer has been created. * The lifetime of the memory is the responsibility of the user. - * + * * `PAL_BUFFER_MEMORY_USAGE_AUTO_GPU_ONLY`: PAL allocates gpu only memory and manages the memory * for the user. This is ideal if a custom allocator will not be used by the user. - * - * `PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD`: PAL allocates cpu upload memory and manages the + * + * `PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_UPLOAD`: PAL allocates cpu upload memory and manages the * memory for the user. This is ideal if a custom allocator will not be used by the user. - * - * `PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK`: PAL allocates cpu readback memory and manages the + * + * `PAL_BUFFER_MEMORY_USAGE_AUTO_CPU_READBACK`: PAL allocates cpu readback memory and manages the * memory for the user. This is ideal if a custom allocator will not be used by the user. * * All buffer memory usages follow the format `PAL_BUFFER_MEMORY_USAGE_**` @@ -1476,11 +1484,11 @@ typedef uint32_t PalBufferMemoryUsage; /** * @typedef PalImageMemoryUsage * @brief Image memory usages. - * + * * `PAL_IMAGE_MEMORY_USAGE_MANUAL`: PAL does not allocate memory for the image. Users are required - * to get the required size and allocate memory for the image after the image has been created. + * to get the required size and allocate memory for the image after the image has been created. * The lifetime of the memory is the responsibility of the user. - * + * * `PAL_IMAGE_MEMORY_USAGE_AUTO_GPU_ONLY`: PAL allocates gpu only memory and manages the memory * for the user. This is ideal if a custom allocator will not be used by the user. * @@ -1494,7 +1502,7 @@ typedef uint32_t PalImageMemoryUsage; /** * @typedef PalRenderingFlags * @brief Rendering flags. - * + * * All rendering flags follow the format `PAL_RENDERING_FLAG_**` * for consistency and API use. * @@ -1506,7 +1514,7 @@ typedef uint32_t PalRenderingFlags; * @typedef PalPipelineStages * @brief Pipeline stages. Multiple pipeline usages can be OR'ed together using bitwise * OR operator (`|`). - * + * * All pipeline stages follow the format `PAL_PIPELINE_STAGE_**` * for consistency and API use. * @@ -1529,7 +1537,8 @@ typedef uint32_t PalGraphicsBackendVtableVersion; * @typedef PalDebugCallback * @brief Function pointer type used for debug callbacks. * - * @param userData Optional pointer to user data passed from ::PalGraphicsDebugger. Can be `nullptr`. + * @param userData Optional pointer to user data passed from ::PalGraphicsDebugger. Can be + * `nullptr`. * @param severity Severity of the message. (`PAL_DEBUG_MESSAGE_SEVERITY_INFO`, * `PAL_DEBUG_MESSAGE_SEVERITY_WARNING` and `PAL_DEBUG_MESSAGE_SEVERITY_ERROR`). * @param type Type of the message. (`PAL_DEBUG_MESSAGE_TYPE_GENERAL`, @@ -1562,7 +1571,7 @@ typedef struct { PalAdapterApiType apiType; /**< (eg. `PAL_ADAPTER_API_TYPE_VULKAN`).*/ char name[PAL_ADAPTER_NAME_SIZE]; /**< Adapter name.*/ char backendName[PAL_ADAPTER_BACKEND_NAME_SIZE]; /**< Adapter backend name.*/ - uint32_t reserved; /**< 0 for now.*/ + uint32_t reserved; /**< 0 for now.*/ } PalAdapterInfo; /** @@ -1803,15 +1812,15 @@ typedef struct { * @since 2.0 */ typedef struct { - PalImageUsages usages; /**< (eg. `PAL_IMAGE_USAGE_COLOR`).*/ - uint32_t width; /**< Width of the image in pixels.*/ - uint32_t height; /**< Height of the image in pixels.*/ - uint32_t depth; /**< Depth of the image in pixels.*/ - uint32_t arrayLayerCount; /**< Number of array layers.*/ - uint32_t mipLevelCount; /**< Number of mipmap levels.*/ - PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_8`).*/ - PalImageType type; /**< (eg. `PAL_IMAGE_TYPE_2D`).*/ - PalFormat format; /**< (eg. `PAL_FORMAT_R8G8B8A8_UNORM`).*/ + PalImageUsages usages; /**< (eg. `PAL_IMAGE_USAGE_COLOR`).*/ + uint32_t width; /**< Width of the image in pixels.*/ + uint32_t height; /**< Height of the image in pixels.*/ + uint32_t depth; /**< Depth of the image in pixels.*/ + uint32_t arrayLayerCount; /**< Number of array layers.*/ + uint32_t mipLevelCount; /**< Number of mipmap levels.*/ + PalSampleCount sampleCount; /**< (eg. `PAL_SAMPLE_COUNT_8`).*/ + PalImageType type; /**< (eg. `PAL_IMAGE_TYPE_2D`).*/ + PalFormat format; /**< (eg. `PAL_FORMAT_R8G8B8A8_UNORM`).*/ PalBool belongsToSwapchain; /**< If `PAL_TRUE`, the image belongs to a swapchain.*/ } PalImageInfo; @@ -1889,7 +1898,7 @@ typedef struct { uint64_t alignment; /**< Required alignment in bytes.*/ uint64_t memoryMask; /**< Memory masks used in allocations. Must not be changed.*/ uint32_t supportedMemoryTypes; /**< Masks of supported memory types.*/ - uint32_t reserved; /**< Must be set to 0.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalMemoryRequirements; /** @@ -1901,13 +1910,13 @@ typedef struct { * @since 2.0 */ typedef struct { - uint64_t waitValue; /**< Timeline semaphore value to wait on.*/ - uint64_t signalValue; /**< Timeline semaphore value to signal.*/ - PalCommandBuffer* cmdBuffer; /**< Command buffer to submit.*/ - PalSemaphore* waitSemaphore; /**< Wait semaphore.*/ - PalSemaphore* signalSemaphore; /**< Signal semaphore.*/ - PalFence* fence; /**< Fence to signal.*/ - PalPipelineStages waitStages; /**< (eg. `PAL_PIPELINE_STAGE_COLOR_ATTACHMENT`).*/ + uint64_t waitValue; /**< Timeline semaphore value to wait on.*/ + uint64_t signalValue; /**< Timeline semaphore value to signal.*/ + PalCommandBuffer* cmdBuffer; /**< Command buffer to submit.*/ + PalSemaphore* waitSemaphore; /**< Wait semaphore.*/ + PalSemaphore* signalSemaphore; /**< Signal semaphore.*/ + PalFence* fence; /**< Fence to signal.*/ + PalPipelineStages waitStages; /**< (eg. `PAL_PIPELINE_STAGE_COLOR_ATTACHMENT`).*/ PalPipelineStages signalStages; /**< (eg. `PAL_PIPELINE_STAGE_NONE`).*/ } PalCommandBufferSubmitInfo; @@ -1934,16 +1943,16 @@ typedef struct { * @since 2.0 */ typedef struct { - PalAttachmentDesc* colorAttachments; /**< Color attachments.*/ + PalAttachmentDesc* colorAttachments; /**< Color attachments.*/ PalAttachmentDesc* depthStencilAttachment; /**< Depth/Stencil attachment.*/ - PalImageView* fragmentShadingRateImageView; /**< Fragment shading rate image view.*/ - PalRect2D renderArea; /**< Rendering area of the attachments.*/ - PalRenderingFlags flags; /**< (eg. `PAL_RENDERING_FLAG_NONE`).*/ + PalImageView* fragmentShadingRateImageView; /**< Fragment shading rate image view.*/ + PalRect2D renderArea; /**< Rendering area of the attachments.*/ + PalRenderingFlags flags; /**< (eg. `PAL_RENDERING_FLAG_NONE`).*/ uint32_t fragmentShadingRateTexelWidth; /**< Texel width for fragment shading rate.*/ uint32_t fragmentShadingRateTexelHeight; /**< Texel height for fragment shading rate.*/ - uint32_t viewCount; /**< View count. Set to 1 for default.*/ + uint32_t viewCount; /**< View count. Set to 1 for default.*/ uint32_t arrayLayerCount; /**< Number of array layers for rendering.*/ - uint32_t colorAttachentCount; /**< Number of color attachments.*/ + uint32_t colorAttachentCount; /**< Number of color attachments.*/ } PalRenderingInfo; /** @@ -1994,14 +2003,14 @@ typedef struct { /** * @struct PalImageStagingRequirements * @brief Requirements for an image staging buffer. - * + * * Uninitialized fields may result in undefined behavior. * * @since 2.0 */ typedef struct { - uint64_t bufferSize; /**< Required buffer size.*/ - uint32_t bufferRowLength; /**< Required buffer row length.*/ + uint64_t bufferSize; /**< Required buffer size.*/ + uint32_t bufferRowLength; /**< Required buffer row length.*/ uint32_t bufferImageHeight; /**< Required buffer image height.*/ } PalImageStagingRequirements; @@ -2082,7 +2091,7 @@ typedef struct { uint32_t attributeCount; /**< Number of vertex attributes.*/ PalVertexLayoutType type; /**< (eg. `PAL_VERTEX_LAYOUT_TYPE_PER_VERTEX`).*/ uint32_t binding; /**< Vertex buffer binding slot.*/ - uint32_t reserved; /**< Must be set to 0.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalVertexLayout; /** @@ -2408,8 +2417,8 @@ typedef struct { * @since 2.0 */ typedef struct { - PalUsageState oldState; /**< (eg. `PAL_USAGE_STATE_COLOR_ATTACHMENT`).*/ - PalUsageState newState; /**< (eg. `PAL_USAGE_STATE_PRESENT`).*/ + PalUsageState oldState; /**< (eg. `PAL_USAGE_STATE_COLOR_ATTACHMENT`).*/ + PalUsageState newState; /**< (eg. `PAL_USAGE_STATE_PRESENT`).*/ PalPipelineStages srcStages; /**< (eg. `PAL_PIPELINE_STAGE_COLOR_ATTACHMENT`).*/ PalPipelineStages dstStages; /**< (eg. `PAL_PIPELINE_STAGE_COLOR_OUTPUT`).*/ } PalBarrierInfo; @@ -2625,9 +2634,9 @@ typedef struct { * @since 2.0 */ typedef struct { - void* bytecode; /**< Pointer to the shader bytecode.*/ + void* code; /**< Pointer to the shader code.*/ PalShaderEntryInfo* entries; /**< Shader entries.*/ - uint32_t bytecodeSize; /**< Size of `bytecode` in bytes.*/ + uint32_t codeSize; /**< Size of `code` in bytes.*/ uint32_t entryCount; /**< Number of shader entries.*/ } PalShaderCreateInfo; @@ -2658,7 +2667,7 @@ typedef struct { uint64_t offset; /**< Size in bytes.*/ uint64_t size; /**< Offset in bytes.*/ PalAccelerationStructureType type; /**< (eg. `PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL`).*/ - uint32_t reserved; /**< Must be set to 0.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalAccelerationStructureCreateInfo; /** @@ -2670,9 +2679,9 @@ typedef struct { * @since 2.0 */ typedef struct { - PalDescriptorSetLayoutBinding* bindings; /**< Bindings.*/ - PalDescriptorIndexingFlags flags; /**< See `PalDescriptorIndexingFlags`.*/ - uint32_t bindingCount; /**< Number of bindings.*/ + PalDescriptorSetLayoutBinding* bindings; /**< Bindings.*/ + PalDescriptorIndexingFlags flags; /**< See `PalDescriptorIndexingFlags`.*/ + uint32_t bindingCount; /**< Number of bindings.*/ } PalDescriptorSetLayoutCreateInfo; /** @@ -2688,7 +2697,7 @@ typedef struct { uint32_t bindingSizeCount; /**< Number of bindings sizes.*/ uint32_t maxDescriptorSets; /**< Maximum number of descriptor sets that can be allocated.*/ PalDescriptorIndexingFlags flags; /**< See `PalDescriptorIndexingFlags`.*/ - uint32_t reserved; /**< Must be set to 0.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalDescriptorPoolCreateInfo; /** @@ -2728,7 +2737,7 @@ typedef struct { uint32_t vertexLayoutCount; /**< Number of vertex layouts.*/ uint32_t colorBlendAttachmentCount; /**< Number of color attachments.*/ uint32_t shaderCount; /**< Number of shaders.*/ - PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is `PAL_TRUE`.*/ + PalIndexType indexType; /**< Will be used if `primitiveRestartEnable` is `PAL_TRUE`.*/ PalPrimitiveTopology topology; /**< (eg. `PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST`).*/ } PalGraphicsPipelineCreateInfo; @@ -2785,7 +2794,7 @@ typedef struct { uint32_t maxRecursionDepth; /**< Max number of ray recursion.*/ uint32_t maxAttributeSize; /**< Max attributes size in bytes.*/ uint32_t maxPayloadSize; /**< Max payload size in bytes.*/ - uint32_t reserved; /**< Must be set to 0.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalRayTracingPipelineCreateInfo; /** @@ -2800,7 +2809,7 @@ typedef struct { PalShaderBindingTableRecordInfo* records; /**< Shader binding table records.*/ PalPipeline* rayTracingPipeline; /**< Ray tracing pipeline.*/ uint32_t recordCount; /**< Number of shader binding table records.*/ - uint32_t reserved; /**< Must be set to 0.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalShaderBindingTableCreateInfo; /** @@ -2808,10 +2817,10 @@ typedef struct { * @brief Custom graphics backend information. * * Uninitialized fields may result in undefined behavior. - * + * * All backend handle implementation (eg. struct CustomBuffer) must reserve its first field as * a `void*`. This will be used by the graphics layer. - * + * * Each backend Vtable version (eg. `PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1`) has required functions * that must be present implemented. This will be validated at initialization. See version constant * for the required functions. Optional functions have their own requirements. @@ -2821,7 +2830,7 @@ typedef struct { typedef struct { const void* vtable; /**< Pointer to the backend vtable.*/ PalGraphicsBackendVtableVersion version; /**< (eg. `PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1`).*/ - uint32_t reserved; /**< Must be set to 0.*/ + uint32_t reserved; /**< Must be set to 0.*/ } PalGraphicsBackendInfo; /** @@ -3329,7 +3338,7 @@ typedef struct { * Must obey the rules and semantics documented in palGetSemaphoreValue(). */ PalResult(PAL_CALL* getSemaphoreValue)( - PalSemaphore* semaphore, + PalSemaphore* semaphore, uint64_t* value); /** @@ -3865,7 +3874,7 @@ typedef struct { */ void(PAL_CALL* computeInstanceStagingSize)( PalDevice* device, - uint32_t instanceCount, + uint32_t instanceCount, uint64_t* outSize); /** @@ -4085,7 +4094,7 @@ typedef struct { * @brief Initialize the graphics system. * * The debugger, allocator and custom backends will not not copied, therefore the pointers must - * remain valid until the graphics system is shutdown. Set the debugger to `nullptr` to disable + * remain valid until the graphics system is shutdown. Set the debugger to `nullptr` to disable * debugging and validation layers. * * If `debugger` is not `nullptr` and there is no debug layers, this function will not fail but @@ -4750,7 +4759,7 @@ PAL_API PalResult PAL_CALL palBindImageMemory( * `PAL_IMAGE_VIEW_TYPE_2D_ARRAY`. * * `PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY` must be supported and enabled by the device - * used to create the image view if `PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY` will be used. + * used to create the image view if `PAL_IMAGE_VIEW_TYPE_CUBE_ARRAY` will be used. * Otherwise behavior is undefined. * * @param[in] device Device that creates the image view. @@ -5278,7 +5287,7 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( * @sa palSignalSemaphore */ PAL_API PalResult PAL_CALL palGetSemaphoreValue( - PalSemaphore* semaphore, + PalSemaphore* semaphore, uint64_t* value); /** @@ -5307,7 +5316,7 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( * @brief Destroy a command pool. * * The graphics system must be initialized before this call. - * All command buffers allocated from the pool must be freed before this call, + * All command buffers allocated from the pool must be freed before this call, * otherwise undefined behavior. * * @param[in] pool Command pool to destroy. @@ -5755,7 +5764,7 @@ PAL_API void PAL_CALL palCmdSetScissors( * @param[in] count Number of vertex buffers to bind. * @param[in] buffers Pointer to an array of vertex buffers. * @param[in] offsets Pointer to an array of offsets in bytes into each vertex buffer. - * + * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * * @note A pipeline must be bound before this call. @@ -6288,7 +6297,7 @@ PAL_API void PAL_CALL palCmdSetFrontFace( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY` must be supported and enabled by the device. -* Otherwise behavior is undefined. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] topology Topology to set. @@ -6307,7 +6316,7 @@ PAL_API void PAL_CALL palCmdSetPrimitiveTopology( * The graphics system must be initialized before this call. * * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE` must be supported and enabled by the device. -* Otherwise behavior is undefined. + * Otherwise behavior is undefined. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] enable True to enable. @@ -6377,7 +6386,7 @@ PAL_API void PAL_CALL palCmdSetStencilOp( * @param[in] info Pointer to a PalAccelerationStructureCreateInfo struct that specifies parameters * @param[out] outAs Pointer to a PalAccelerationStructure to recieve the created acceleration * structure. - * + * * @return `PAL_RESULT_SUCCESS` on success or a result code on * failure. Call palFormatResult() for more information. * @@ -6495,12 +6504,12 @@ PAL_API void PAL_CALL palGetBufferMemoryRequirements( /** * @brief Compute size for an acceleration structure instance buffer. * - * The graphics system must be initialized before this call. - * + * The graphics system must be initialized before this call. + * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. - * - * This does not allocate memory for the buffer. This function must is required for all + * + * This does not allocate memory for the buffer. This function must is required for all * acceleration structure instance buffers. * * @param[in] device The device to use. @@ -6514,7 +6523,7 @@ PAL_API void PAL_CALL palGetBufferMemoryRequirements( */ PAL_API void PAL_CALL palComputeInstanceStagingSize( PalDevice* device, - uint32_t instanceCount, + uint32_t instanceCount, uint64_t* outSize); /** @@ -6522,10 +6531,10 @@ PAL_API void PAL_CALL palComputeInstanceStagingSize( * * The graphics system must be initialized before this call. This does not allocate memory * for the buffer. This function is required for all image copy staging buffers. - * - * `PalBufferImageCopyInfo::bufferRowLength` and `PalBufferImageCopyInfo::bufferImageHeight` + * + * `PalBufferImageCopyInfo::bufferRowLength` and `PalBufferImageCopyInfo::bufferImageHeight` * are hints. The driver might used it defaults if the requested is not supported. After this call, - * set those values to the required ones from `requirements`. + * set those values to the required ones from `requirements`. * If the driver supports the proivded, the values will be the same. * * @param[in] device The device to use. @@ -6548,7 +6557,7 @@ PAL_API void PAL_CALL palComputeImageStagingRequirements( * @brief Write data to an instance staging buffer. * * The graphics system must be initialized before this call. - * + * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. * @@ -6941,7 +6950,7 @@ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( * @brief Destroy a pipeline. * * The graphics system must be initialized before this call. - * + * * @param[in] pipeline Pipeline to destroy. * * Thread safety: Thread safe if the device used to create the pipeline is @@ -7057,14 +7066,14 @@ PAL_API void PAL_CALL palBuildWorkGroupInfo( /** * @brief Check if a constant is supported in a mask. - * + * * This function is used to check all masks in `supported_**` format in most of the capabilities - * query structs. - * + * query structs. + * * Example: - * - * To check if `PAL_PRESENT_MODE_IMMEDIATE` is supported after querying `PalSurfaceCapabilities` - * capabilities of a surface, PalSurfaceCapabilities::supportedPresentModes should be the `mask` + * + * To check if `PAL_PRESENT_MODE_IMMEDIATE` is supported after querying `PalSurfaceCapabilities` + * capabilities of a surface, PalSurfaceCapabilities::supportedPresentModes should be the `mask` * parameter and `PAL_PRESENT_MODE_IMMEDIATE` as the value parameter. * * @param[in] mask The supported mask. diff --git a/include/pal/pal_opengl.h b/include/pal/pal_opengl.h index 0575b3e7..ddb30664 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal/pal_opengl.h @@ -216,9 +216,8 @@ typedef struct { * The allocator will not not copied, therefore the pointer must remain valid * until the opengl system is shutdown. * - * `instance` must not be `nullptr` and will not be freed by the opengl system. It must be valid until - * palShutdownGL() is called. - * `Linux`: This is the Display associated with the connection. + * `instance` must not be `nullptr` and will not be freed by the opengl system. It must be valid + * until palShutdownGL() is called. `Linux`: This is the Display associated with the connection. * `Windows`: This is the HINSTANCE of the process. * * @param[in] api The api to use. (eg. `PAL_GL_API_OPENGL`). diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index 999ffc68..a7c26da5 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -507,8 +507,8 @@ typedef struct { */ typedef struct { PalFlashFlags flags; /**< (eg. `PAL_FLASH_FLAG_CAPTION`).*/ - uint32_t interval; /**< In milliseconds. Set to 0 for default.*/ - uint32_t count; /**< Set to 0 to flash until focused or cancelled.*/ + uint32_t interval; /**< In milliseconds. Set to 0 for default.*/ + uint32_t count; /**< Set to 0 to flash until focused or cancelled.*/ } PalFlashInfo; /** diff --git a/src/core/posix/pal_log_posix.c b/src/core/posix/pal_log_posix.c index 5e80d133..1984eeab 100644 --- a/src/core/posix/pal_log_posix.c +++ b/src/core/posix/pal_log_posix.c @@ -9,8 +9,8 @@ #if _PAL_HAS_POSIX #include "core/pal_format.h" -#include #include +#include #define MSG_SIZE 4096 diff --git a/src/core/posix/pal_result_posix.c b/src/core/posix/pal_result_posix.c index 7e0c9d09..b48eeb8a 100644 --- a/src/core/posix/pal_result_posix.c +++ b/src/core/posix/pal_result_posix.c @@ -14,7 +14,7 @@ #include void PAL_CALL palFormatResult( - PalResult result, + PalResult result, uint64_t bufferSize, char* buffer) { diff --git a/src/core/win32/pal_result_win32.c b/src/core/win32/pal_result_win32.c index 64d70806..006f2faa 100644 --- a/src/core/win32/pal_result_win32.c +++ b/src/core/win32/pal_result_win32.c @@ -25,8 +25,8 @@ #include void PAL_CALL palFormatResult( - PalResult result, - uint64_t bufferSize, + PalResult result, + uint64_t bufferSize, char* buffer) { char tmpBuffer[256]; diff --git a/src/event/pal_default_queue.c b/src/event/pal_default_queue.c index ebff10b9..87b4822f 100644 --- a/src/event/pal_default_queue.c +++ b/src/event/pal_default_queue.c @@ -61,7 +61,7 @@ PalEventQueue* createDefaultEventQueue(const PalAllocator* allocator) } void destroyDefaultEventQueue( - const PalAllocator* allocator, + const PalAllocator* allocator, PalEventQueue* queue) { palFree(allocator, queue->userData); diff --git a/src/graphics/d3d12/pal_adapter_d3d12.c b/src/graphics/d3d12/pal_adapter_d3d12.c index ac68dde7..aae4bb1a 100644 --- a/src/graphics/d3d12/pal_adapter_d3d12.c +++ b/src/graphics/d3d12/pal_adapter_d3d12.c @@ -61,17 +61,14 @@ PalResult PAL_CALL enumerateAdaptersD3D12( D3D_FEATURE_LEVEL_12_1, D3D_FEATURE_LEVEL_12_0, D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0 - }; + D3D_FEATURE_LEVEL_11_0}; if (s_D3D12.adapters) { palFree(s_D3D12.allocator, s_D3D12.adapters); } - while (SUCCEEDED(s_D3D12.factory->lpVtbl->EnumAdapters( - s_D3D12.factory, - adapterCount, - &adapter))) { + while ( + SUCCEEDED(s_D3D12.factory->lpVtbl->EnumAdapters(s_D3D12.factory, adapterCount, &adapter))) { if (outAdapters) { IDXGIAdapter4* tmp = nullptr; if (SUCCEEDED(adapter->lpVtbl->QueryInterface(adapter, &IID_Adapter, (void**)&tmp))) { @@ -81,11 +78,8 @@ PalResult PAL_CALL enumerateAdaptersD3D12( // create a temp device for every adapter to use as an instance to check features. ID3D12Device* device = nullptr; for (int i = 0; i < 5; i++) { - HRESULT result = s_D3D12.createDevice( - (IUnknown*)tmp, - levels[i], - &IID_Device, - (void**)&device); + HRESULT result = + s_D3D12.createDevice((IUnknown*)tmp, levels[i], &IID_Device, (void**)&device); if (SUCCEEDED(result)) { deviceLevels[adapterCount] = levels[i]; @@ -136,9 +130,9 @@ void PAL_CALL getAdapterInfoD3D12( d3d12Adapter->handle->lpVtbl->GetDesc3(d3d12Adapter->handle, &desc); result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, sizeof(shaderModel)); info->shaderFormats = PAL_SHADER_FORMAT_DXBC; @@ -149,7 +143,7 @@ void PAL_CALL getAdapterInfoD3D12( LARGE_INTEGER driverVersion = {0}; info->driverVersion = 0; result = d3d12Adapter->handle->lpVtbl->CheckInterfaceSupport( - d3d12Adapter->handle, + d3d12Adapter->handle, &IID_Adapter, &driverVersion); @@ -173,11 +167,7 @@ void PAL_CALL getAdapterInfoD3D12( nullptr, nullptr); - device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_ARCHITECTURE1, - &arch, - sizeof(arch)); + device->lpVtbl->CheckFeatureSupport(device, D3D12_FEATURE_ARCHITECTURE1, &arch, sizeof(arch)); if (arch.UMA == PAL_TRUE) { info->type = PAL_ADAPTER_TYPE_INTEGRATED; @@ -208,16 +198,16 @@ void PAL_CALL getAdapterCapabilitiesD3D12( PalResourceCapabilities* resourceCaps = &caps->resourceCaps; PalComputeCapabilities* computeCaps = &caps->computeCaps; - caps->maxComputeQueues = 2; // safe default + caps->maxComputeQueues = 2; // safe default caps->maxGraphicsQueues = 2; // safe default - caps->maxCopyQueues = 2; // safe default + caps->maxCopyQueues = 2; // safe default caps->maxColorAttachments = D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; caps->maxUniformBufferSize = D3D12_REQ_IMMEDIATE_CONSTANT_BUFFER_ELEMENT_COUNT * 16; caps->maxStorageBufferSize = 2147483648; // 2 GIB caps->maxPushConstantSize = 256; - caps->maxVertexLayouts = 32; // safe + caps->maxVertexLayouts = 32; // safe caps->maxVertexAttributes = 32; // safe caps->maxTessellationPatchPoint = 32; @@ -278,40 +268,40 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS, - &options, + device, + D3D12_FEATURE_D3D12_OPTIONS, + &options, sizeof(options)); result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS3, - &options3, + device, + D3D12_FEATURE_D3D12_OPTIONS3, + &options3, sizeof(options3)); result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS5, - &options5, + device, + D3D12_FEATURE_D3D12_OPTIONS5, + &options5, sizeof(options5)); result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS6, - &options6, + device, + D3D12_FEATURE_D3D12_OPTIONS6, + &options6, sizeof(options6)); result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_D3D12_OPTIONS7, - &options7, + device, + D3D12_FEATURE_D3D12_OPTIONS7, + &options7, sizeof(options7)); shaderModel.HighestShaderModel = D3D_SHADER_MODEL_5_1; result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, + device, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, sizeof(shaderModel)); if (shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_5_1 && result == S_OK) { @@ -393,7 +383,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) } uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( - PalAdapter* adapter, + PalAdapter* adapter, PalShaderFormats shaderFormat) { if (shaderFormat != PAL_SHADER_FORMAT_DXIL && shaderFormat != PAL_SHADER_FORMAT_DXBC) { @@ -426,9 +416,9 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( for (int i = 0; i < 11; i++) { shaderModel.HighestShaderModel = models[i]; result = d3d12Adapter->tmpDevice->lpVtbl->CheckFeatureSupport( - d3d12Adapter->tmpDevice, - D3D12_FEATURE_SHADER_MODEL, - &shaderModel, + d3d12Adapter->tmpDevice, + D3D12_FEATURE_SHADER_MODEL, + &shaderModel, sizeof(shaderModel)); if (shaderModel.HighestShaderModel >= models[i] && result == S_OK) { @@ -492,12 +482,9 @@ void PAL_CALL enumerateFormatsD3D12( } support.Format = fmt; - device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, - sizeof(support)); - + device->lpVtbl + ->CheckFeatureSupport(device, D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support)); + if (support.Support1 == 0 && support.Support2 == 0) { // format not supported continue; @@ -533,11 +520,8 @@ PalBool PAL_CALL isFormatSupportedD3D12( } support.Format = fmt; - device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, - sizeof(support)); + device->lpVtbl + ->CheckFeatureSupport(device, D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support)); if (support.Support1 == 0 && support.Support2 == 0) { return PAL_FALSE; @@ -562,9 +546,9 @@ PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( support.Format = fmt; result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, sizeof(support)); if (FAILED(result)) { @@ -601,9 +585,9 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( support.Format = fmt; result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_FORMAT_SUPPORT, - &support, + device, + D3D12_FEATURE_FORMAT_SUPPORT, + &support, sizeof(support)); if (FAILED(result)) { @@ -624,9 +608,9 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( for (int i = 0; i < 6; i++) { samples.SampleCount = sampleCounts[i]; result = device->lpVtbl->CheckFeatureSupport( - device, - D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, - &samples, + device, + D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, + &samples, sizeof(samples)); if (SUCCEEDED(result) && samples.NumQualityLevels > 0) { diff --git a/src/graphics/d3d12/pal_as_d3d12.c b/src/graphics/d3d12/pal_as_d3d12.c index 09348d62..f4633890 100644 --- a/src/graphics/d3d12/pal_as_d3d12.c +++ b/src/graphics/d3d12/pal_as_d3d12.c @@ -17,7 +17,7 @@ PalResult PAL_CALL createAccelerationstructureD3D12( AccelerationStructureD3D12* as = nullptr; DeviceD3D12* d3d12Device = (DeviceD3D12*)device; BufferD3D12* d3d12Buffer = (BufferD3D12*)info->buffer; - + as = palAllocate(s_D3D12.allocator, sizeof(AccelerationStructureD3D12), 0); if (!as) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -45,13 +45,11 @@ void PAL_CALL getAccelerationStructureBuildSizeD3D12( DeviceD3D12* d3d12Device = (DeviceD3D12*)device; D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO sizeInfo = {0}; - + if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; - geometries = palAllocate( - s_D3D12.allocator, - sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count, - 0); + geometries = + palAllocate(s_D3D12.allocator, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count, 0); if (!geometries) { return; @@ -61,8 +59,8 @@ void PAL_CALL getAccelerationStructureBuildSizeD3D12( fillBuildInfoD3D12(PAL_TRUE, info, geometries, &buildInfo); d3d12Device->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( - d3d12Device->handle, - &buildInfo.Inputs, + d3d12Device->handle, + &buildInfo.Inputs, &sizeInfo); palFree(s_D3D12.allocator, geometries); @@ -71,8 +69,8 @@ void PAL_CALL getAccelerationStructureBuildSizeD3D12( fillBuildInfoD3D12(PAL_TRUE, info, nullptr, &buildInfo); d3d12Device->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( - d3d12Device->handle, - &buildInfo.Inputs, + d3d12Device->handle, + &buildInfo.Inputs, &sizeInfo); } diff --git a/src/graphics/d3d12/pal_buffer_d3d12.c b/src/graphics/d3d12/pal_buffer_d3d12.c index be61dd88..d975263e 100644 --- a/src/graphics/d3d12/pal_buffer_d3d12.c +++ b/src/graphics/d3d12/pal_buffer_d3d12.c @@ -57,7 +57,7 @@ PalResult PAL_CALL createBufferD3D12( HRESULT result; BufferD3D12* buffer = nullptr; DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - + buffer = palAllocate(s_D3D12.allocator, sizeof(BufferD3D12), 0); if (!buffer) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -119,9 +119,9 @@ PalResult PAL_CALL createBufferD3D12( } result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, - &heapProps, - 0, + d3d12Device->handle, + &heapProps, + 0, &buffer->desc, state, nullptr, @@ -161,12 +161,8 @@ void PAL_CALL getBufferMemoryRequirementsD3D12( D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; - allocationInfo = *device->lpVtbl->GetResourceAllocationInfo( - device, - &__ret, - 0, - 1, - &d3d12Buffer->desc); + allocationInfo = + *device->lpVtbl->GetResourceAllocationInfo(device, &__ret, 0, 1, &d3d12Buffer->desc); requirements->supportedMemoryTypes = getSupportedMemoryTypes(d3d12Buffer->usages); requirements->alignment = allocationInfo.Alignment; diff --git a/src/graphics/d3d12/pal_command_pool_d3d12.c b/src/graphics/d3d12/pal_command_pool_d3d12.c index 62604a0f..6e89b319 100644 --- a/src/graphics/d3d12/pal_command_pool_d3d12.c +++ b/src/graphics/d3d12/pal_command_pool_d3d12.c @@ -132,7 +132,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( &bufferDesc, D3D12_RESOURCE_STATE_COMMON, nullptr, - &IID_Resource, + &IID_Resource, (void**)&cmdBuffer->buffer); if (FAILED(result)) { @@ -149,7 +149,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( &bufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, - &IID_Resource, + &IID_Resource, (void**)&cmdBuffer->stagingBuffer); if (FAILED(result)) { @@ -157,10 +157,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( return makeResultD3D12(result); } - result = cmdList->lpVtbl->QueryInterface( - cmdList, - &IID_CommandList6, - (void**)&cmdBuffer->handle); + result = + cmdList->lpVtbl->QueryInterface(cmdList, &IID_CommandList6, (void**)&cmdBuffer->handle); if (FAILED(result)) { pollMessagesD3D12(d3d12Device); @@ -251,7 +249,7 @@ PalResult PAL_CALL submitCommandBufferD3D12( } } - ID3D12CommandList* cmdLists[1] = { (ID3D12CommandList*)d3d12CmdBuffer->handle }; + ID3D12CommandList* cmdLists[1] = {(ID3D12CommandList*)d3d12CmdBuffer->handle}; queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, cmdLists); pollMessagesD3D12(d3d12CmdBuffer->device); diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index 8ee6fc3c..fe40f2b5 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -122,7 +122,7 @@ static D3D12_RESOLVE_MODE resolveModeToD3D12(PalResolveMode mode) } static void commitShaderbindingTableUpdateD3D12( - CommandBufferD3D12* cmdBuffer, + CommandBufferD3D12* cmdBuffer, ShaderBindingTableD3D12* sbt) { if (!sbt->isDirty) { @@ -204,7 +204,7 @@ void PAL_CALL cmdSetFragmentShadingRateD3D12( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; D3D12_SHADING_RATE shadingRate = shadingRateToD3D12(state->rate); D3D12_SHADING_RATE_COMBINER combinerOps[2]; for (int i = 0; i < 2; i++) { @@ -224,11 +224,8 @@ void PAL_CALL cmdDrawMeshTasksD3D12( uint32_t groupCountZ) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - d3d12CmdBuffer->handle->lpVtbl->DispatchMesh( - d3d12CmdBuffer->handle, - groupCountX, - groupCountY, - groupCountZ); + d3d12CmdBuffer->handle->lpVtbl + ->DispatchMesh(d3d12CmdBuffer->handle, groupCountX, groupCountY, groupCountZ); } void PAL_CALL cmdDrawMeshTasksIndirectD3D12( @@ -280,25 +277,19 @@ void PAL_CALL cmdBuildAccelerationStructureD3D12( if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; geometries = palLinearAlloc( - &d3d12CmdBuffer->linearAllocator, - sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count, + &d3d12CmdBuffer->linearAllocator, + sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count, 0); memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count); fillBuildInfoD3D12(PAL_FALSE, info, geometries, &buildInfo); - d3d12CmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( - d3d12CmdBuffer->handle, - &buildInfo, - 0, - nullptr); + d3d12CmdBuffer->handle->lpVtbl + ->BuildRaytracingAccelerationStructure(d3d12CmdBuffer->handle, &buildInfo, 0, nullptr); } else { fillBuildInfoD3D12(PAL_FALSE, info, nullptr, &buildInfo); - d3d12CmdBuffer->handle->lpVtbl->BuildRaytracingAccelerationStructure( - d3d12CmdBuffer->handle, - &buildInfo, - 0, - nullptr); + d3d12CmdBuffer->handle->lpVtbl + ->BuildRaytracingAccelerationStructure(d3d12CmdBuffer->handle, &buildInfo, 0, nullptr); } } @@ -688,7 +679,7 @@ void PAL_CALL cmdBindPipelineD3D12( d3dPipeline->handle); d3d12CmdBuffer->handle->lpVtbl->SetComputeRootSignature( - d3d12CmdBuffer->handle, + d3d12CmdBuffer->handle, d3dPipeline->layout->handle); } else { @@ -697,7 +688,7 @@ void PAL_CALL cmdBindPipelineD3D12( d3dPipeline->handle); d3d12CmdBuffer->handle->lpVtbl->SetComputeRootSignature( - d3d12CmdBuffer->handle, + d3d12CmdBuffer->handle, d3dPipeline->layout->handle); if (d3dPipeline->type == GRAPHICS_PIPELINE) { @@ -706,7 +697,7 @@ void PAL_CALL cmdBindPipelineD3D12( d3dPipeline->topology); d3d12CmdBuffer->handle->lpVtbl->SetGraphicsRootSignature( - d3d12CmdBuffer->handle, + d3d12CmdBuffer->handle, d3dPipeline->layout->handle); if (d3dPipeline->hasFsr) { @@ -770,8 +761,8 @@ void PAL_CALL cmdBindVertexBuffersD3D12( PipelineD3D12* pipeline = d3d12CmdBuffer->pipeline; D3D12_VERTEX_BUFFER_VIEW* views = nullptr; views = palLinearAlloc( - &d3d12CmdBuffer->linearAllocator, - sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, + &d3d12CmdBuffer->linearAllocator, + sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, 0); for (int i = 0; i < count; i++) { @@ -782,11 +773,8 @@ void PAL_CALL cmdBindVertexBuffersD3D12( views[i].StrideInBytes = pipeline->strides[i]; } - d3d12CmdBuffer->handle->lpVtbl->IASetVertexBuffers( - d3d12CmdBuffer->handle, - firstSlot, - count, - views); + d3d12CmdBuffer->handle->lpVtbl + ->IASetVertexBuffers(d3d12CmdBuffer->handle, firstSlot, count, views); } void PAL_CALL cmdBindIndexBufferD3D12( @@ -998,8 +986,8 @@ void PAL_CALL cmdImageBarrierD3D12( } barriers = palLinearAlloc( - &d3d12CmdBuffer->linearAllocator, - sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, + &d3d12CmdBuffer->linearAllocator, + sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, 0); uint32_t count = 0; @@ -1057,11 +1045,8 @@ void PAL_CALL cmdDispatchD3D12( uint32_t groupCountZ) { CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - d3d12CmdBuffer->handle->lpVtbl->Dispatch( - d3d12CmdBuffer->handle, - groupCountX, - groupCountY, - groupCountZ); + d3d12CmdBuffer->handle->lpVtbl + ->Dispatch(d3d12CmdBuffer->handle, groupCountX, groupCountY, groupCountZ); } void PAL_CALL cmdDispatchIndirectD3D12( diff --git a/src/graphics/d3d12/pal_d3d12.c b/src/graphics/d3d12/pal_d3d12.c index f7833855..8fb22379 100644 --- a/src/graphics/d3d12/pal_d3d12.c +++ b/src/graphics/d3d12/pal_d3d12.c @@ -9,27 +9,35 @@ #include "pal_d3d12.h" // IIDS -IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f,0x94, 0xf4,0x31,0xcb,0x56,0xc3,0xb8}; -IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8,0x2c, 0xaf,0x66,0xbf,0x7b,0xd2,0x4e}; -IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0,0x3c, 0x77,0x90,0x0a,0x0a,0x1d,0x17}; -IID IID_DebugController = {0x344488b7, 0x6846, 0x474b, 0xb9,0x89, 0xf0,0x27,0x44,0x82,0x45,0xe0}; -IID IID_DebugController1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8,0xad, 0x15,0x90,0x00,0xaf,0x43,0x04}; -IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9,0x46, 0x30,0xa7,0xe4,0xe6,0x14,0x58}; -IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90,0xee, 0x98,0x84,0x26,0x5e,0x8d,0xf3}; -IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c,0xfc, 0x5b,0xaa,0xe0,0x76,0x16,0xed}; -IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2,0x36, 0x7d,0xa0,0x17,0x0e,0xda,0xb1}; -IID IID_CommandAllocator = {0x6102dee4, 0xaf59, 0x4b09, 0xb9,0x99, 0xb4,0x4d,0x73,0xf0,0x9b,0x24}; -IID IID_CommandList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8,0xc6, 0xec,0x81,0x68,0xf4,0x37,0xe5}; -IID IID_CommandList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96,0xcf, 0x56,0x89,0xa9,0x37,0x0f,0x80}; -IID IID_CommandSignature = {0xc36a797c, 0xec80, 0x4f0a, 0x89,0x85, 0xa7,0xb2,0x47,0x50,0x82,0xd1}; -IID IID_DescriptorHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90,0xf7, 0x12,0x7b,0xb7,0x63,0xfa,0x51}; -IID IID_RootSignature = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b,0xe5, 0xa9,0x46,0xa1,0x42,0x92,0x14}; -IID IID_Device5 = {0x8b4f173b, 0x2fea, 0x4b80, 0x8f,0x58, 0x43,0x07,0x19,0x1a,0xb9,0x5d}; -IID IID_PipelineState = {0x765a30f3, 0xf624, 0x4c6f, 0xa8,0x28, 0xac,0xe9,0x48,0x62,0x24,0x45}; -IID IID_StateObject = {0x47016943, 0xfca8, 0x4594, 0x93,0xea, 0xaf,0x25,0x8b,0x55,0x34,0x6d}; -IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc,0x79, 0x5b,0x5c,0x98,0x04,0x0f,0xad}; -IID IID_StateObjectProps = {0xde5fa827, 0x9bf9, 0x4f26, 0x89,0xff, 0xd7,0xf5,0x6f,0xde,0x38,0x60}; -IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad,0xf6, 0xbe,0x5a,0x60,0xd9,0x5a,0x76}; +IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f, 0x94, 0xf4, 0x31, 0xcb, 0x56, 0xc3, 0xb8}; +IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8, 0x2c, 0xaf, 0x66, 0xbf, 0x7b, 0xd2, 0x4e}; +IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0, 0x3c, 0x77, 0x90, 0x0a, 0x0a, 0x1d, 0x17}; +IID IID_DebugController = + {0x344488b7, 0x6846, 0x474b, 0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0}; +IID IID_DebugController1 = + {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8, 0xad, 0x15, 0x90, 0x00, 0xaf, 0x43, 0x04}; +IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9, 0x46, 0x30, 0xa7, 0xe4, 0xe6, 0x14, 0x58}; +IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90, 0xee, 0x98, 0x84, 0x26, 0x5e, 0x8d, 0xf3}; +IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c, 0xfc, 0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed}; +IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2, 0x36, 0x7d, 0xa0, 0x17, 0x0e, 0xda, 0xb1}; +IID IID_CommandAllocator = + {0x6102dee4, 0xaf59, 0x4b09, 0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24}; +IID IID_CommandList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8, 0xc6, 0xec, 0x81, 0x68, 0xf4, 0x37, 0xe5}; +IID IID_CommandList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96, 0xcf, 0x56, 0x89, 0xa9, 0x37, 0x0f, 0x80}; +IID IID_CommandSignature = + {0xc36a797c, 0xec80, 0x4f0a, 0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1}; +IID IID_DescriptorHeap = + {0x8efb471d, 0x616c, 0x4f49, 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51}; +IID IID_RootSignature = + {0xc54a6b66, 0x72df, 0x4ee8, 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14}; +IID IID_Device5 = {0x8b4f173b, 0x2fea, 0x4b80, 0x8f, 0x58, 0x43, 0x07, 0x19, 0x1a, 0xb9, 0x5d}; +IID IID_PipelineState = + {0x765a30f3, 0xf624, 0x4c6f, 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45}; +IID IID_StateObject = {0x47016943, 0xfca8, 0x4594, 0x93, 0xea, 0xaf, 0x25, 0x8b, 0x55, 0x34, 0x6d}; +IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad}; +IID IID_StateObjectProps = + {0xde5fa827, 0x9bf9, 0x4f26, 0x89, 0xff, 0xd7, 0xf5, 0x6f, 0xde, 0x38, 0x60}; +IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76}; D3D12 s_D3D12 = {0}; @@ -697,7 +705,7 @@ void fillBuildInfoD3D12( if (tmp->Triangles.IndexBuffer) { tmp->Triangles.IndexFormat = DXGI_FORMAT_R16_FLOAT; } - + } else { if (tmp->Triangles.IndexBuffer) { tmp->Triangles.IndexFormat = DXGI_FORMAT_R32_FLOAT; @@ -736,15 +744,18 @@ void fillBuildInfoD3D12( // build hints if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_BUILD) { - buildInfo->Inputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; + buildInfo->Inputs.Flags |= + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; } if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_FAST_TRACE) { - buildInfo->Inputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; + buildInfo->Inputs.Flags |= + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; } if (info->buildHints & PAL_ACCELERATION_STRUCTURE_BUILD_HINT_LOW_MEMORY) { - buildInfo->Inputs.Flags |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_MINIMIZE_MEMORY; + buildInfo->Inputs.Flags |= + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_MINIMIZE_MEMORY; } AccelerationStructureD3D12* dstAs = (AccelerationStructureD3D12*)info->dst; @@ -919,24 +930,18 @@ uint64_t getDescriptorHandleD3D12( } void getDescriptorTierLimitsD3D12( - void* device, - PalResourceCapabilities* caps, + void* device, + PalResourceCapabilities* caps, PalDescriptorIndexingCapabilities* descCaps) { D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = {0}; ID3D12Device* handle = device; - handle->lpVtbl->CheckFeatureSupport( - handle, - D3D12_FEATURE_D3D12_OPTIONS, - &options, - sizeof(options)); - - handle->lpVtbl->CheckFeatureSupport( - handle, - D3D12_FEATURE_D3D12_OPTIONS5, - &options5, - sizeof(options5)); + handle->lpVtbl + ->CheckFeatureSupport(handle, D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options)); + + handle->lpVtbl + ->CheckFeatureSupport(handle, D3D12_FEATURE_D3D12_OPTIONS5, &options5, sizeof(options5)); uint32_t perStage = 0; if (options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED) { @@ -956,7 +961,7 @@ void getDescriptorTierLimitsD3D12( tmp.maxPerStageStorageBuffers = 4; tmp.maxPerStageUniformBuffers = 14; tmp.maxPerStageAccelerationStructure = perStage; - + } else { tmp.maxPerStageSampledImages = 705000 - perStage; tmp.maxPerStageStorageImages = 100000; @@ -1061,8 +1066,8 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D12.dxgi = LoadLibraryA("dxgi.dll"); if (!s_D3D12.handle || !s_D3D12.dxgi) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/graphics/d3d12/pal_descriptors_d3d12.c b/src/graphics/d3d12/pal_descriptors_d3d12.c index 1b747cf8..1bbeb5f8 100644 --- a/src/graphics/d3d12/pal_descriptors_d3d12.c +++ b/src/graphics/d3d12/pal_descriptors_d3d12.c @@ -185,10 +185,8 @@ PalResult PAL_CALL createDescriptorPoolD3D12( } memset(pool, 0, sizeof(DescriptorPoolD3D12)); - pool->sets = palAllocate( - s_D3D12.allocator, - sizeof(DescriptorSetD3D12) * info->maxDescriptorSets, - 0); + pool->sets = + palAllocate(s_D3D12.allocator, sizeof(DescriptorSetD3D12) * info->maxDescriptorSets, 0); if (!pool->sets) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -251,14 +249,11 @@ PalResult PAL_CALL createDescriptorPoolD3D12( D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); // get base CPU and GPU base pointer - handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( - heap->handle, - &__ret); + handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart(heap->handle, &__ret); heap->cpuBase = handle.ptr; - gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( - heap->handle, - &__gpuRet); + gpuHandle = + *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart(heap->handle, &__gpuRet); heap->gpuBase = gpuHandle.ptr; pool->hasResourceHeap = PAL_TRUE; @@ -292,14 +287,11 @@ PalResult PAL_CALL createDescriptorPoolD3D12( D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); // get base CPU and GPU base pointer - handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart( - heap->handle, - &__ret); + handle = *heap->handle->lpVtbl->GetCPUDescriptorHandleForHeapStart(heap->handle, &__ret); heap->cpuBase = handle.ptr; - gpuHandle = *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart( - heap->handle, - &__gpuRet); + gpuHandle = + *heap->handle->lpVtbl->GetGPUDescriptorHandleForHeapStart(heap->handle, &__gpuRet); heap->gpuBase = gpuHandle.ptr; pool->hasSamplerHeap = PAL_TRUE; @@ -475,7 +467,10 @@ PalResult PAL_CALL updateDescriptorSetD3D12( if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { if (info->samplerInfos) { SamplerD3D12* sampler = (SamplerD3D12*)info->samplerInfos[j].sampler; - d3d12Device->handle->lpVtbl->CreateSampler(d3d12Device->handle, &sampler->desc, dst); + d3d12Device->handle->lpVtbl->CreateSampler( + d3d12Device->handle, + &sampler->desc, + dst); } else { D3D12_SAMPLER_DESC desc = {0}; @@ -501,16 +496,13 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.RaytracingAccelerationStructure.Location = tlas->address; } - d3d12Device->handle->lpVtbl->CreateShaderResourceView( - d3d12Device->handle, - nullptr, - &desc, - dst); + d3d12Device->handle->lpVtbl + ->CreateShaderResourceView(d3d12Device->handle, nullptr, &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - + PalImageSubresourceRange range = {0}; PalImageViewType type; ID3D12Resource* handle = nullptr; @@ -531,11 +523,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } fillSubresourceD3D12(DESC_TYPE_SRV, type, &range, &desc); - d3d12Device->handle->lpVtbl->CreateShaderResourceView( - d3d12Device->handle, - handle, - &desc, - dst); + d3d12Device->handle->lpVtbl + ->CreateShaderResourceView(d3d12Device->handle, handle, &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; @@ -559,12 +548,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } fillSubresourceD3D12(DESC_TYPE_UAV, type, &range, &desc); - d3d12Device->handle->lpVtbl->CreateUnorderedAccessView( - d3d12Device->handle, - handle, - nullptr, - &desc, - dst); + d3d12Device->handle->lpVtbl + ->CreateUnorderedAccessView(d3d12Device->handle, handle, nullptr, &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {0}; @@ -605,14 +590,10 @@ PalResult PAL_CALL updateDescriptorSetD3D12( handle = buffer->handle; desc.Buffer.FirstElement = bufferInfo->offset / stride; desc.Buffer.NumElements = bufferInfo->size / stride; - } + } - d3d12Device->handle->lpVtbl->CreateUnorderedAccessView( - d3d12Device->handle, - handle, - nullptr, - &desc, - dst); + d3d12Device->handle->lpVtbl + ->CreateUnorderedAccessView(d3d12Device->handle, handle, nullptr, &desc, dst); } } } diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c index 2bb6ef11..061bc2fb 100644 --- a/src/graphics/d3d12/pal_device_d3d12.c +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -9,7 +9,9 @@ #include "pal_d3d12.h" PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter*); -uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12(PalAdapter*, PalShaderFormats); +uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( + PalAdapter*, + PalShaderFormats); static void convertToWcharD3D12( const char* src, @@ -60,10 +62,7 @@ PalResult PAL_CALL createDeviceD3D12( return makeResultD3D12(result); } - result = tmpDevice->lpVtbl->QueryInterface( - tmpDevice, - &IID_Device5, - (void**)&device->handle); + result = tmpDevice->lpVtbl->QueryInterface(tmpDevice, &IID_Device5, (void**)&device->handle); tmpDevice->lpVtbl->Release(tmpDevice); if (s_D3D12.debugLayer) { @@ -79,19 +78,18 @@ PalResult PAL_CALL createDeviceD3D12( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - D3D12_MESSAGE_ID denyIDs[] = { + D3D12_MESSAGE_ID denyIDs[] = { D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE, - D3D12_MESSAGE_ID_LIVE_OBJECT_SUMMARY - }; + D3D12_MESSAGE_ID_LIVE_OBJECT_SUMMARY}; device->infoQueue->lpVtbl->SetBreakOnSeverity( - device->infoQueue, - D3D12_MESSAGE_SEVERITY_ERROR, + device->infoQueue, + D3D12_MESSAGE_SEVERITY_ERROR, TRUE); device->infoQueue->lpVtbl->SetBreakOnSeverity( - device->infoQueue, - D3D12_MESSAGE_SEVERITY_CORRUPTION, + device->infoQueue, + D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE); D3D12_INFO_QUEUE_FILTER filter = {0}; @@ -109,11 +107,8 @@ PalResult PAL_CALL createDeviceD3D12( D3D12_COMMAND_QUEUE_DESC desc = {0}; desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - result = device->handle->lpVtbl->CreateCommandQueue( - device->handle, - &desc, - &IID_Queue, - (void**)&device->queue); + result = device->handle->lpVtbl + ->CreateCommandQueue(device->handle, &desc, &IID_Queue, (void**)&device->queue); if (FAILED(result)) { return makeResultD3D12(result); @@ -254,14 +249,12 @@ PalResult PAL_CALL createDeviceD3D12( D3D12_CPU_DESCRIPTOR_HANDLE __ret, dst; dst = *device->rtvAllocator.heap->lpVtbl->GetCPUDescriptorHandleForHeapStart( device->rtvAllocator.heap, - &__ret - ); + &__ret); device->rtvAllocator.baseOffset = dst.ptr; dst = *device->dsvAllocator.heap->lpVtbl->GetCPUDescriptorHandleForHeapStart( device->dsvAllocator.heap, - &__ret - ); + &__ret); device->dsvAllocator.baseOffset = dst.ptr; // API enforced limits @@ -372,11 +365,8 @@ PalResult PAL_CALL allocateMemoryD3D12( desc.Properties.Type = D3D12_HEAP_TYPE_UPLOAD; } - result = d3d12Device->handle->lpVtbl->CreateHeap( - d3d12Device->handle, - &desc, - &IID_Heap, - (void**)&memory->handle); + result = d3d12Device->handle->lpVtbl + ->CreateHeap(d3d12Device->handle, &desc, &IID_Heap, (void**)&memory->handle); if (FAILED(result)) { pollMessagesD3D12(d3d12Device); @@ -464,7 +454,7 @@ void PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( caps->supportedCombinerOps |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MAX); caps->supportedCombinerOps |= (1u << PAL_FRAGMENT_SHADING_RATE_COMBINER_OP_MUL); - caps->minTexelWidth = 1; // safe default + caps->minTexelWidth = 1; // safe default caps->minTexelHeight = 1; // safe default caps->maxTexelWidth = options.ShadingRateImageTileSize; caps->maxTexelHeight = options.ShadingRateImageTileSize; @@ -570,12 +560,8 @@ PalResult PAL_CALL createQueueD3D12( } // create fence used for queue wait - result = d3d12Device->handle->lpVtbl->CreateFence( - d3d12Device->handle, - 0, - 0, - &IID_Fence, - (void**)&queue->fence); + result = d3d12Device->handle->lpVtbl + ->CreateFence(d3d12Device->handle, 0, 0, &IID_Fence, (void**)&queue->fence); if (FAILED(result)) { palFree(s_D3D12.allocator, queue); @@ -587,7 +573,7 @@ PalResult PAL_CALL createQueueD3D12( if (!queue->fenceEvent) { return palMakeResult( PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -642,7 +628,7 @@ PalResult PAL_CALL createShaderD3D12( void* bytecode = nullptr; shader = palAllocate(s_D3D12.allocator, sizeof(ShaderD3D12), 0); - bytecode = palAllocate(s_D3D12.allocator, info->bytecodeSize, 0); + bytecode = palAllocate(s_D3D12.allocator, info->codeSize, 0); if (!shader || !bytecode) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } @@ -657,12 +643,12 @@ PalResult PAL_CALL createShaderD3D12( ShaderEntry* entry = &shader->entries[i]; convertToWcharD3D12(info->entries[i].entryName, entry->entryName); entry->patchControlPoints = info->entries[i].patchControlPoints; - entry->stage = info->entries[i].stage; + entry->stage = info->entries[i].stage; } - memcpy(bytecode, info->bytecode, info->bytecodeSize); + memcpy(bytecode, info->code, info->codeSize); shader->byteCode.pShaderBytecode = bytecode; - shader->byteCode.BytecodeLength = info->bytecodeSize; + shader->byteCode.BytecodeLength = info->codeSize; shader->entryCount = info->entryCount; *outShader = (PalShader*)shader; diff --git a/src/graphics/d3d12/pal_image_d3d12.c b/src/graphics/d3d12/pal_image_d3d12.c index 80167f98..8a244ebe 100644 --- a/src/graphics/d3d12/pal_image_d3d12.c +++ b/src/graphics/d3d12/pal_image_d3d12.c @@ -72,11 +72,9 @@ static D3D12_TEXTURE_ADDRESS_MODE addressModeToD3D12(PalSamplerAddressMode mode) case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { return D3D12_TEXTURE_ADDRESS_MODE_MIRROR; - } case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; - } case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { return D3D12_TEXTURE_ADDRESS_MODE_BORDER; @@ -85,7 +83,9 @@ static D3D12_TEXTURE_ADDRESS_MODE addressModeToD3D12(PalSamplerAddressMode mode) return D3D12_TEXTURE_ADDRESS_MODE_WRAP; } -static void borderColorToD3D12(PalBorderColor color, float outColor[4]) +static void borderColorToD3D12( + PalBorderColor color, + float outColor[4]) { switch (color) { case PAL_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK: @@ -172,9 +172,9 @@ PalResult PAL_CALL createImageD3D12( heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, - &heapProps, - 0, + d3d12Device->handle, + &heapProps, + 0, &image->desc, D3D12_RESOURCE_STATE_COMMON, nullptr, @@ -231,12 +231,8 @@ void PAL_CALL getImageMemoryRequirementsD3D12( D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; - allocationInfo = *device->lpVtbl->GetResourceAllocationInfo( - device, - &__ret, - 0, - 1, - &d3d12Image->desc); + allocationInfo = + *device->lpVtbl->GetResourceAllocationInfo(device, &__ret, 0, 1, &d3d12Image->desc); requirements->supportedMemoryTypes = (1u << PAL_MEMORY_TYPE_GPU_ONLY); requirements->alignment = allocationInfo.Alignment; @@ -311,11 +307,8 @@ PalResult PAL_CALL createImageViewD3D12( desc.Format = imageView->format; fillSubresourceD3D12(DESC_TYPE_RTV, info->type, &info->subresourceRange, &desc); imageView->heapIndex = index; - d3d12Device->handle->lpVtbl->CreateRenderTargetView( - d3d12Device->handle, - d3d12Image->handle, - &desc, - dst); + d3d12Device->handle->lpVtbl + ->CreateRenderTargetView(d3d12Device->handle, d3d12Image->handle, &desc, dst); } else if (info->subresourceRange.aspect != PAL_IMAGE_ASPECT_COLOR && hasDSV) { DSVHeapAllocator* allocator = &d3d12Device->dsvAllocator; @@ -329,11 +322,8 @@ PalResult PAL_CALL createImageViewD3D12( desc.Format = imageView->format; fillSubresourceD3D12(DESC_TYPE_DSV, info->type, &info->subresourceRange, &desc); imageView->heapIndex = index; - d3d12Device->handle->lpVtbl->CreateDepthStencilView( - d3d12Device->handle, - d3d12Image->handle, - &desc, - dst); + d3d12Device->handle->lpVtbl + ->CreateDepthStencilView(d3d12Device->handle, d3d12Image->handle, &desc, dst); } imageView->range = info->subresourceRange; @@ -402,10 +392,8 @@ PalResult PAL_CALL createSamplerD3D12( sampler->desc.AddressV = addressModeToD3D12(info->addressModeV); sampler->desc.AddressW = addressModeToD3D12(info->addressModeW); - sampler->desc.Filter = filterToD3D12( - info->minFilterMode, - info->magFilterMode, - info->mipmapMode); + sampler->desc.Filter = + filterToD3D12(info->minFilterMode, info->magFilterMode, info->mipmapMode); *outSampler = (PalSampler*)sampler; return PAL_RESULT_SUCCESS; diff --git a/src/graphics/d3d12/pal_pipeline_d3d12.c b/src/graphics/d3d12/pal_pipeline_d3d12.c index 0b0f38ce..b7cf2556 100644 --- a/src/graphics/d3d12/pal_pipeline_d3d12.c +++ b/src/graphics/d3d12/pal_pipeline_d3d12.c @@ -21,7 +21,7 @@ #elif defined(__GNUC__) || defined(__clang__) #define ALIGN_STREAM __attribute__((aligned(PTR_SIZE))) #else - #define ALIGN_STREAM +#define ALIGN_STREAM #endif // _MSC_VER typedef ALIGN_STREAM struct { @@ -89,7 +89,7 @@ typedef ALIGN_STREAM struct { D3D12_VIEW_INSTANCING_DESC desc; } ViewInstancingStream; -typedef struct { +typedef struct { RootSignatureStream layout; InputLayoutStream inputLayout; TopologyStream topology; @@ -366,7 +366,7 @@ static const char* semanticIDToStringD3D12(PalVertexSemanticID id) switch (id) { case PAL_VERTEX_SEMANTIC_ID_POSITION: return "POSITION"; - + case PAL_VERTEX_SEMANTIC_ID_COLOR: return "COLOR"; @@ -627,7 +627,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( totalSize += sizeof(RootSignatureStream); rootSignatureStream->type = D3D12_PIPELINE_STATE_SUBOBJECT_TYPE_ROOT_SIGNATURE; rootSignatureStream->root = layout->handle; - + // shaders for (int i = 0; i < info->shaderCount; i++) { ShaderD3D12* tmp = (ShaderD3D12*)info->shaders[i]; @@ -699,10 +699,8 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - elementDescs = palAllocate( - s_D3D12.allocator, - sizeof(D3D12_INPUT_ELEMENT_DESC) * vertexCount, - 0); + elementDescs = + palAllocate(s_D3D12.allocator, sizeof(D3D12_INPUT_ELEMENT_DESC) * vertexCount, 0); if (!elementDescs) { palFree(s_D3D12.allocator, elementDescs); @@ -977,7 +975,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( PalFragmentShadingRateState* state = info->fragmentShadingRateState; pipeline->shadingRate = shadingRateToD3D12(state->rate); for (int i = 0; i < 2; i++) { - pipeline->combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); + pipeline->combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); } } @@ -1108,7 +1106,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (info->maxRecursionDepth> d3d12Device->limits.maxRecursionDepth) { + if (info->maxRecursionDepth > d3d12Device->limits.maxRecursionDepth) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -1172,8 +1170,8 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( localRootSize = max(localRootSize, sbtInfo.hitDataSize); localRootSize = max(localRootSize, sbtInfo.callableDataSize); - // // D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE - // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG + // // D3D12_STATE_SUBOBJECT_TYPE_GLOBAL_ROOT_SIGNATURE + // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_PIPELINE_CONFIG // // D3D12_STATE_SUBOBJECT_TYPE_RAYTRACING_SHADER_CONFIG subObjectCount += info->shaderCount + 3; @@ -1196,25 +1194,15 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - libraryDescs = palAllocate( - s_D3D12.allocator, - sizeof(D3D12_DXIL_LIBRARY_DESC) * info->shaderCount, - 0); - - exportDescs = palAllocate( - s_D3D12.allocator, - sizeof(D3D12_EXPORT_DESC) * exportCount, - 0); - - pipeline->shaderExports = palAllocate( - s_D3D12.allocator, - sizeof(ShaderExport) * pipeline->shaderExportCount, - 0); - - localExports = palAllocate( - s_D3D12.allocator, - sizeof(wchar_t*) * localExportCount, - 0); + libraryDescs = + palAllocate(s_D3D12.allocator, sizeof(D3D12_DXIL_LIBRARY_DESC) * info->shaderCount, 0); + + exportDescs = palAllocate(s_D3D12.allocator, sizeof(D3D12_EXPORT_DESC) * exportCount, 0); + + pipeline->shaderExports = + palAllocate(s_D3D12.allocator, sizeof(ShaderExport) * pipeline->shaderExportCount, 0); + + localExports = palAllocate(s_D3D12.allocator, sizeof(wchar_t*) * localExportCount, 0); if (!libraryDescs || !exportDescs || !pipeline->shaderExports || !localExports) { return PAL_RESULT_CODE_OUT_OF_MEMORY; diff --git a/src/graphics/d3d12/pal_sbt_d3d12.c b/src/graphics/d3d12/pal_sbt_d3d12.c index c1feb723..adcbc24b 100644 --- a/src/graphics/d3d12/pal_sbt_d3d12.c +++ b/src/graphics/d3d12/pal_sbt_d3d12.c @@ -86,13 +86,13 @@ PalResult PAL_CALL createShaderBindingTableD3D12( if (index < sbtInfo->raygenCount) { // raygen group - if (record->localDataSize > sbtInfo->raygenDataSize) { + if (record->localDataSize > sbtInfo->raygenDataSize) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { // miss group - if (record->localDataSize > sbtInfo->missDataSize) { + if (record->localDataSize > sbtInfo->missDataSize) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -161,9 +161,9 @@ PalResult PAL_CALL createShaderBindingTableD3D12( bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, - &heapProps, - 0, + d3d12Device->handle, + &heapProps, + 0, &bufferDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, @@ -178,9 +178,9 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // create staging buffer heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, - &heapProps, - 0, + d3d12Device->handle, + &heapProps, + 0, &bufferDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, @@ -204,8 +204,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // skip any hit, closest hit, intersection shaders without isHitGroup PalBool PalBool isHitGroup = PAL_FALSE; - if (stage == PAL_SHADER_STAGE_ANY_HIT || - stage == PAL_SHADER_STAGE_CLOSEST_HIT || + if (stage == PAL_SHADER_STAGE_ANY_HIT || stage == PAL_SHADER_STAGE_CLOSEST_HIT || stage == PAL_SHADER_STAGE_INTERSECTION) { if (tmp->isHitGroup) { isHitGroup = PAL_TRUE; @@ -296,14 +295,14 @@ PalResult PAL_CALL createShaderBindingTableD3D12( // raygen if (sbtInfo->raygenCount) { sbt->raygen.region.StartAddress = sbt->baseAddress; - sbt->raygen.offset = 0; // always + sbt->raygen.offset = 0; // always sbt->raygen.startIndex = 0; // always sbt->raygen.region.SizeInBytes = raygenRegionSize; sbt->raygen.region.StrideInBytes = raygenStride; palFree(s_D3D12.allocator, raygenHandles); } - + // miss if (sbtInfo->missCount) { sbt->miss.offset = missOffset; @@ -357,7 +356,7 @@ void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) } void PAL_CALL updateShaderBindingTableD3D12( - PalShaderBindingTable* sbt, + PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos) { @@ -371,7 +370,7 @@ void PAL_CALL updateShaderBindingTableD3D12( for (int i = 0; i < count; i++) { PalShaderBindingTableRecordInfo* info = &infos[i]; - + // find the group the record belongs to uint32_t index = info->groupIndex; if (index < sbtInfo->raygenCount) { diff --git a/src/graphics/d3d12/pal_swapchain_d3d12.c b/src/graphics/d3d12/pal_swapchain_d3d12.c index 26ffb746..fbe1eb87 100644 --- a/src/graphics/d3d12/pal_swapchain_d3d12.c +++ b/src/graphics/d3d12/pal_swapchain_d3d12.c @@ -249,7 +249,7 @@ PalResult PAL_CALL createSwapchainD3D12( DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); } else { swapchain->handle->lpVtbl->SetColorSpace1( - swapchain->handle, + swapchain->handle, DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709); } @@ -270,7 +270,7 @@ PalResult PAL_CALL createSwapchainD3D12( image->handle = tmp; image->info.belongsToSwapchain = PAL_TRUE; - image->info.depth = 1; // always 1 + image->info.depth = 1; // always 1 image->info.arrayLayerCount = 1; // always 1 image->info.format = imageFormat; image->info.usages = PAL_IMAGE_USAGE_COLOR_ATTACHEMENT; @@ -349,7 +349,7 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( PalResult PAL_CALL presentSwapchainD3D12( PalSwapchain* swapchain, - uint32_t imageIndex, + uint32_t imageIndex, PalSemaphore* waitSemaphore) { HRESULT result; @@ -392,8 +392,8 @@ PalResult PAL_CALL presentSwapchainD3D12( uint32_t h = windowRect.bottom - windowRect.top; if (!ret) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -430,11 +430,8 @@ PalResult PAL_CALL resizeSwapchainD3D12( // fill all images with the creation info for (int i = 0; i < d3d12Swapchain->imageCount; i++) { ID3D12Resource* tmp = nullptr; - d3d12Swapchain->handle->lpVtbl->GetBuffer( - d3d12Swapchain->handle, - i, - &IID_Resource, - (void**)&tmp); + d3d12Swapchain->handle->lpVtbl + ->GetBuffer(d3d12Swapchain->handle, i, &IID_Resource, (void**)&tmp); ImageD3D12* image = &d3d12Swapchain->images[i]; image->handle = tmp; @@ -447,8 +444,8 @@ PalResult PAL_CALL resizeSwapchainD3D12( SurfaceD3D12* surface = d3d12Swapchain->surface; if (!GetClientRect((HWND)surface->handle, &windowRect)) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/graphics/d3d12/pal_sync_d3d12.c b/src/graphics/d3d12/pal_sync_d3d12.c index f0618d5b..c553f55f 100644 --- a/src/graphics/d3d12/pal_sync_d3d12.c +++ b/src/graphics/d3d12/pal_sync_d3d12.c @@ -22,12 +22,8 @@ PalResult PAL_CALL createFenceD3D12( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - result = d3d12Device->handle->lpVtbl->CreateFence( - d3d12Device->handle, - 0, - 0, - &IID_Fence, - (void**)&fence->handle); + result = d3d12Device->handle->lpVtbl + ->CreateFence(d3d12Device->handle, 0, 0, &IID_Fence, (void**)&fence->handle); if (FAILED(result)) { pollMessagesD3D12(d3d12Device); @@ -40,7 +36,7 @@ PalResult PAL_CALL createFenceD3D12( if (!fence->event) { return palMakeResult( PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -74,10 +70,7 @@ PalResult PAL_CALL waitFenceD3D12( HANDLE event = d3d12Fence->event; if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) < value) { - result = d3d12Fence->handle->lpVtbl->SetEventOnCompletion( - d3d12Fence->handle, - value, - event); + result = d3d12Fence->handle->lpVtbl->SetEventOnCompletion(d3d12Fence->handle, value, event); if (FAILED(result)) { return makeResultD3D12(result); @@ -132,12 +125,8 @@ PalResult PAL_CALL createSemaphoreD3D12( semaphore->isTimeline = PAL_TRUE; } - result = d3d12Device->handle->lpVtbl->CreateFence( - d3d12Device->handle, - 0, - 0, - &IID_Fence, - (void**)&semaphore->handle); + result = d3d12Device->handle->lpVtbl + ->CreateFence(d3d12Device->handle, 0, 0, &IID_Fence, (void**)&semaphore->handle); if (FAILED(result)) { pollMessagesD3D12(d3d12Device); @@ -150,7 +139,7 @@ PalResult PAL_CALL createSemaphoreD3D12( if (!semaphore->event) { return palMakeResult( PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -180,8 +169,8 @@ PalResult PAL_CALL waitSemaphoreD3D12( HANDLE event = d3d12Semaphore->event; if (d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle) < value) { result = d3d12Semaphore->handle->lpVtbl->SetEventOnCompletion( - d3d12Semaphore->handle, - value, + d3d12Semaphore->handle, + value, event); if (FAILED(result)) { @@ -217,7 +206,7 @@ PalResult PAL_CALL signalSemaphoreD3D12( } PalResult PAL_CALL getSemaphoreValueD3D12( - PalSemaphore* semaphore, + PalSemaphore* semaphore, uint64_t* value) { SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 6c7115a0..608a3aaf 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -13,7 +13,7 @@ #define MAX_BACKENDS (PAL_MAX_CUSTOM_BACKENDS + 2) #define PAL_HANDLE(name) \ struct name { \ - PalGraphicsVtable backend; \ + PalGraphicsVtable backend; \ }; PAL_HANDLE(PalAdapter) @@ -206,31 +206,29 @@ PalResult PAL_CALL palInitGraphics( PalResult result; BackendData* attachedBackend = nullptr; #ifdef _WIN32 - // vulkan -#if PAL_HAS_VULKAN_BACKEND - result = initGraphicsVk(debugger, allocator); +#if PAL_HAS_D3D12_BACKEND + result = initGraphicsD3D12(debugger, allocator); if (result != PAL_RESULT_SUCCESS) { return result; } attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base.vtbl1 = &s_VkBackend1; + attachedBackend->base.vtbl1 = &s_D3D12Backend1; attachedBackend->startIndex = 0; attachedBackend->count = 0; -#endif // PAL_HAS_VULKAN_BACKEND +#endif // PAL_HAS_D3D12_BACKEND - // D3D12 -#if PAL_HAS_D3D12_BACKEND - result = initGraphicsD3D12(debugger, allocator); +#if PAL_HAS_VULKAN_BACKEND + result = initGraphicsVk(debugger, allocator); if (result != PAL_RESULT_SUCCESS) { return result; } attachedBackend = &s_Graphics.backends[s_Graphics.backendCount++]; - attachedBackend->base.vtbl1 = &s_D3D12Backend; + attachedBackend->base.vtbl1 = &s_VkBackend1; attachedBackend->startIndex = 0; attachedBackend->count = 0; -#endif // PAL_HAS_D3D12_BACKEND +#endif // PAL_HAS_VULKAN_BACKEND #elif defined(__linux__) // vulkan @@ -263,16 +261,14 @@ PalResult PAL_CALL palInitGraphics( void PAL_CALL palShutdownGraphics() { #ifdef _WIN32 - // vulkan -#if PAL_HAS_VULKAN_BACKEND - shutdownGraphicsVk(); -#endif // PAL_HAS_VULKAN_BACKEND - - // D3D12 #if PAL_HAS_D3D12_BACKEND shutdownGraphicsD3D12(); #endif // PAL_HAS_D3D12_BACKEND +#if PAL_HAS_VULKAN_BACKEND + shutdownGraphicsVk(); +#endif // PAL_HAS_VULKAN_BACKEND + #elif defined(__linux__) // vulkan #if PAL_HAS_VULKAN_BACKEND @@ -690,7 +686,8 @@ PalResult PAL_CALL palCreateSurface( PalSurface* surface = nullptr; PalResult ret; - ret = device->backend.vtbl1->createSurface(device, window, windowInstance, instanceType, &surface); + ret = device->backend.vtbl1 + ->createSurface(device, window, windowInstance, instanceType, &surface); if (ret != PAL_RESULT_SUCCESS) { return ret; } @@ -906,7 +903,7 @@ PalResult PAL_CALL palSignalSemaphore( } PalResult PAL_CALL palGetSemaphoreValue( - PalSemaphore* semaphore, + PalSemaphore* semaphore, uint64_t* value) { return semaphore->backend.vtbl1->getSemaphoreValue(semaphore, value); @@ -1034,11 +1031,8 @@ void PAL_CALL palCmdDrawMeshTasksIndirectCount( PalBuffer* countBuffer, uint32_t maxDrawCount) { - cmdBuffer->backend.vtbl1->cmdDrawMeshTasksIndirectCount( - cmdBuffer, - buffer, - countBuffer, - maxDrawCount); + cmdBuffer->backend.vtbl1 + ->cmdDrawMeshTasksIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); } void PAL_CALL palCmdBuildAccelerationStructure( @@ -1145,7 +1139,8 @@ void PAL_CALL palCmdDraw( uint32_t firstVertex, uint32_t firstInstance) { - cmdBuffer->backend.vtbl1->cmdDraw(cmdBuffer, vertexCount, instanceCount, firstVertex, firstInstance); + cmdBuffer->backend.vtbl1 + ->cmdDraw(cmdBuffer, vertexCount, instanceCount, firstVertex, firstInstance); } void PAL_CALL palCmdDrawIndirect( @@ -1196,7 +1191,8 @@ void PAL_CALL palCmdDrawIndexedIndirectCount( PalBuffer* countBuffer, uint32_t maxDrawCount) { - cmdBuffer->backend.vtbl1->cmdDrawIndexedIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); + cmdBuffer->backend.vtbl1 + ->cmdDrawIndexedIndirectCount(cmdBuffer, buffer, countBuffer, maxDrawCount); } void PAL_CALL palCmdAccelerationStructureBarrier( @@ -1339,13 +1335,8 @@ void PAL_CALL palCmdSetStencilOp( PalStencilOp depthFailOp, PalCompareOp compareOp) { - cmdBuffer->backend.vtbl1->cmdSetStencilOp( - cmdBuffer, - faceMask, - failOp, - passOp, - depthFailOp, - compareOp); + cmdBuffer->backend.vtbl1 + ->cmdSetStencilOp(cmdBuffer, faceMask, failOp, passOp, depthFailOp, compareOp); } // ================================================== @@ -1425,7 +1416,7 @@ void PAL_CALL palGetBufferMemoryRequirements( void PAL_CALL palComputeInstanceStagingSize( PalDevice* device, - uint32_t instanceCount, + uint32_t instanceCount, uint64_t* outSize) { device->backend.vtbl1->computeInstanceStagingSize(device, instanceCount, outSize); @@ -1437,11 +1428,8 @@ void PAL_CALL palComputeImageStagingRequirements( const PalBufferImageCopyInfo* copyInfo, PalImageStagingRequirements* requirements) { - device->backend.vtbl1->computeImageStagingRequirements( - device, - imageFormat, - copyInfo, - requirements); + device->backend.vtbl1 + ->computeImageStagingRequirements(device, imageFormat, copyInfo, requirements); } void PAL_CALL palWriteInstanceStaging( diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index 3caf2d06..d1d83188 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -1140,15 +1140,6 @@ void PAL_CALL cmdDispatchD3D12( uint32_t groupCountY, uint32_t groupCountZ); -void PAL_CALL cmdDispatchBaseD3D12( - PalCommandBuffer* cmdBuffer, - uint32_t baseGroupX, - uint32_t baseGroupY, - uint32_t baseGroupZ, - uint32_t groupCountX, - uint32_t groupCountY, - uint32_t groupCountZ); - void PAL_CALL cmdDispatchIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer); @@ -1178,34 +1169,6 @@ void PAL_CALL cmdPushConstantsD3D12( uint32_t size, const void* value); -void PAL_CALL cmdSetCullModeD3D12( - PalCommandBuffer* cmdBuffer, - PalCullMode cullMode); - -void PAL_CALL cmdSetFrontFaceD3D12( - PalCommandBuffer* cmdBuffer, - PalFrontFace frontFace); - -void PAL_CALL cmdSetPrimitiveTopologyD3D12( - PalCommandBuffer* cmdBuffer, - PalPrimitiveTopology topology); - -void PAL_CALL cmdSetDepthTestEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -void PAL_CALL cmdSetDepthWriteEnableD3D12( - PalCommandBuffer* cmdBuffer, - PalBool enable); - -void PAL_CALL cmdSetStencilOpD3D12( - PalCommandBuffer* cmdBuffer, - PalStencilFaceFlags faceMask, - PalStencilOp failOp, - PalStencilOp passOp, - PalStencilOp depthFailOp, - PalCompareOp compareOp); - PalResult PAL_CALL createAccelerationstructureD3D12( PalDevice* device, const PalAccelerationStructureCreateInfo* info, @@ -1422,18 +1385,18 @@ static PalGraphicsBackendVtable1 s_D3D12Backend1 = { .cmdImageBarrier = cmdImageBarrierD3D12, .cmdBufferBarrier = cmdBufferBarrierD3D12, .cmdDispatch = cmdDispatchD3D12, - .cmdDispatchBase = cmdDispatchBaseD3D12, + .cmdDispatchBase = nullptr, .cmdDispatchIndirect = cmdDispatchIndirectD3D12, .cmdTraceRays = cmdTraceRaysD3D12, .cmdTraceRaysIndirect = cmdTraceRaysIndirectD3D12, .cmdBindDescriptorSet = cmdBindDescriptorSetD3D12, .cmdPushConstants = cmdPushConstantsD3D12, - .cmdSetCullMode = cmdSetCullModeD3D12, - .cmdSetFrontFace = cmdSetFrontFaceD3D12, - .cmdSetPrimitiveTopology = cmdSetPrimitiveTopologyD3D12, - .cmdSetDepthTestEnable = cmdSetDepthTestEnableD3D12, - .cmdSetDepthWriteEnable = cmdSetDepthWriteEnableD3D12, - .cmdSetStencilOp = cmdSetStencilOpD3D12, + .cmdSetCullMode = nullptr, + .cmdSetFrontFace = nullptr, + .cmdSetPrimitiveTopology = nullptr, + .cmdSetDepthTestEnable = nullptr, + .cmdSetDepthWriteEnable = nullptr, + .cmdSetStencilOp = nullptr, .createAccelerationstructure = createAccelerationstructureD3D12, .destroyAccelerationstructure = destroyAccelerationstructureD3D12, .getAccelerationStructureBuildSize = getAccelerationStructureBuildSizeD3D12, diff --git a/src/graphics/vulkan/pal_adapter_vulkan.c b/src/graphics/vulkan/pal_adapter_vulkan.c index 54d3d6fb..2f9652d2 100644 --- a/src/graphics/vulkan/pal_adapter_vulkan.c +++ b/src/graphics/vulkan/pal_adapter_vulkan.c @@ -683,7 +683,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) } uint32_t PAL_CALL getHighestSupportedShaderTargetVk( - PalAdapter* adapter, + PalAdapter* adapter, PalShaderFormats shaderFormat) { if (shaderFormat != PAL_SHADER_FORMAT_SPIRV) { @@ -694,7 +694,7 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetVk( VkPhysicalDeviceProperties props = {0}; s_Vk.getPhysicalDeviceProperties(vkAdapter->handle, &props); - if (props.apiVersion >= VK_API_VERSION_1_3) { + if (props.apiVersion >= VK_API_VERSION_1_3) { return PAL_MAKE_SHADER_TARGET(1, 6); } else if (props.apiVersion >= VK_API_VERSION_1_2) { @@ -702,7 +702,7 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetVk( } else if (props.apiVersion >= VK_API_VERSION_1_1) { return PAL_MAKE_SHADER_TARGET(1, 4); - + } else if (props.apiVersion >= VK_API_VERSION_1_0) { return PAL_MAKE_SHADER_TARGET(1, 2); } @@ -801,8 +801,8 @@ PalSampleCount PAL_CALL queryFormatSampleCountVk( result = s_Vk.getPhysicalDeviceImageFormatProperties( vkAdapter->handle, - fmt, - VK_IMAGE_TYPE_2D, + fmt, + VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, vkImageUsage, 0, diff --git a/src/graphics/vulkan/pal_as_vulkan.c b/src/graphics/vulkan/pal_as_vulkan.c index 8331407d..497f2299 100644 --- a/src/graphics/vulkan/pal_as_vulkan.c +++ b/src/graphics/vulkan/pal_as_vulkan.c @@ -17,7 +17,7 @@ PalResult PAL_CALL createAccelerationstructureVk( AccelerationStructureVk* as = nullptr; DeviceVk* vkDevice = (DeviceVk*)device; BufferVk* buffer = (BufferVk*)info->buffer; - + as = palAllocate(s_Vk.allocator, sizeof(AccelerationStructureVk), 0); if (!as) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -86,7 +86,7 @@ void PAL_CALL getAccelerationStructureBuildSizeVk( memset(geometries, 0, geometriesSize); memset(maxPrimities, 0, sizeof(uint32_t) * info->count); fillBuildInfoVk(PAL_TRUE, info, geometries, &buildInfo, maxPrimities); - + VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; vkDevice->getAccelerationBuildsize( diff --git a/src/graphics/vulkan/pal_buffer_vulkan.c b/src/graphics/vulkan/pal_buffer_vulkan.c index dcf0be99..25b7e5ec 100644 --- a/src/graphics/vulkan/pal_buffer_vulkan.c +++ b/src/graphics/vulkan/pal_buffer_vulkan.c @@ -255,9 +255,9 @@ PalResult PAL_CALL createBufferVk( } result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, &memory->handle); if (result != VK_SUCCESS) { @@ -406,11 +406,8 @@ PalResult PAL_CALL bindBufferMemoryVk( return PAL_RESULT_CODE_INVALID_OPERATION; } - result = s_Vk.bindBufferMemory( - vkBuffer->device->handle, - vkBuffer->handle, - vkMemory->handle, - offset); + result = + s_Vk.bindBufferMemory(vkBuffer->device->handle, vkBuffer->handle, vkMemory->handle, offset); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -429,7 +426,7 @@ PalResult PAL_CALL mapBufferVk( VkResult result; BufferVk* vkBuffer = (BufferVk*)buffer; DeviceVk* device = vkBuffer->device; - + result = s_Vk.mapMemory(device->handle, vkBuffer->memory->handle, offset, size, 0, outPtr); if (result != VK_SUCCESS) { return makeResultVk(result); diff --git a/src/graphics/vulkan/pal_command_pool_vulkan.c b/src/graphics/vulkan/pal_command_pool_vulkan.c index a9c7b9b9..198846f5 100644 --- a/src/graphics/vulkan/pal_command_pool_vulkan.c +++ b/src/graphics/vulkan/pal_command_pool_vulkan.c @@ -96,11 +96,8 @@ PalResult PAL_CALL allocateCommandBufferVk( bufCreateInfo.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - result = s_Vk.createBuffer( - vkDevice->handle, - &bufCreateInfo, - &s_Vk.vkAllocator, - &cmdBuffer->buffer); + result = + s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &cmdBuffer->buffer); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -159,7 +156,7 @@ PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer) if (result != VK_SUCCESS) { return makeResultVk(result); } - + return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c index 6b2191e7..cf1eca4b 100644 --- a/src/graphics/vulkan/pal_commands_vulkan.c +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -14,7 +14,7 @@ typedef struct { } BarrierInfo; static void commitShaderbindingTableUpdate( - CommandBufferVk* cmdBuffer, + CommandBufferVk* cmdBuffer, ShaderBindingTableVk* sbt) { if (!sbt->isDirty) { @@ -242,8 +242,8 @@ PalResult PAL_CALL cmdBeginVk( if (!vkCmdBuffer->primary) { // secondary command buffer colorAttachments = palLinearAlloc( - &vkCmdBuffer->allocator, - sizeof(VkFormat) * info->colorAttachentCount, + &vkCmdBuffer->allocator, + sizeof(VkFormat) * info->colorAttachentCount, 0); if (!colorAttachments) { @@ -338,12 +338,7 @@ void PAL_CALL cmdDrawMeshTasksIndirectVk( BufferVk* vkBuffer = (BufferVk*)buffer; uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); - device->cmdDrawMeshTaskIndirect( - vkCmdBuffer->handle, - vkBuffer->handle, - 0, - drawCount, - stride); + device->cmdDrawMeshTaskIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, drawCount, stride); } void PAL_CALL cmdDrawMeshTasksIndirectCountVk( @@ -374,25 +369,22 @@ void PAL_CALL cmdBuildAccelerationStructureVk( { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - + VkAccelerationStructureGeometryKHR* geometries = nullptr; VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; const VkAccelerationStructureBuildRangeInfoKHR** tmpRangeInfos = nullptr; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - tmpRangeInfos = palLinearAlloc( - &vkCmdBuffer->allocator, - sizeof(void*) * info->count, - 0); + tmpRangeInfos = palLinearAlloc(&vkCmdBuffer->allocator, sizeof(void*) * info->count, 0); geometries = palLinearAlloc( - &vkCmdBuffer->allocator, - sizeof(VkAccelerationStructureGeometryKHR) * info->count, + &vkCmdBuffer->allocator, + sizeof(VkAccelerationStructureGeometryKHR) * info->count, 0); rangeInfos = palLinearAlloc( - &vkCmdBuffer->allocator, - sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->count, + &vkCmdBuffer->allocator, + sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->count, 0); memset(geometries, 0, sizeof(VkAccelerationStructureGeometryKHR) * info->count); @@ -403,11 +395,8 @@ void PAL_CALL cmdBuildAccelerationStructureVk( tmpRangeInfos[i] = &rangeInfos[i]; } - vkCmdBuffer->device->cmdBuildAccelerationStructures( - vkCmdBuffer->handle, - 1, - &buildInfo, - tmpRangeInfos); + vkCmdBuffer->device + ->cmdBuildAccelerationStructures(vkCmdBuffer->handle, 1, &buildInfo, tmpRangeInfos); } void PAL_CALL cmdBeginRenderingVk( @@ -420,11 +409,11 @@ void PAL_CALL cmdBeginRenderingVk( VkRenderingAttachmentInfoKHR depthAttachment = {0}; VkRenderingAttachmentInfoKHR stencilAttachment = {0}; - + VkRenderingAttachmentInfoKHR* colorAttachments = nullptr; colorAttachments = palLinearAlloc( - &vkCmdBuffer->allocator, - sizeof(VkRenderingAttachmentInfoKHR) * info->colorAttachentCount, + &vkCmdBuffer->allocator, + sizeof(VkRenderingAttachmentInfoKHR) * info->colorAttachentCount, 0); VkRenderingAttachmentInfoKHR* attachment = nullptr; @@ -504,7 +493,7 @@ void PAL_CALL cmdBeginRenderingVk( attachment->clearValue.depthStencil.depth = desc->clearValue.depth; stencilAttachment.clearValue.depthStencil.stencil = desc->clearValue.stencil; - + attachment->imageView = imageView->handle; stencilAttachment.imageView = imageView->handle; if (resolveImageView) { @@ -638,10 +627,10 @@ void PAL_CALL cmdCopyBufferToImageVk( copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; copyRegion.imageSubresource.layerCount = copyInfo->ImageArrayLayerCount; copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; - + s_Vk.cmdCopyBufferToImage( - vkCmdBuffer->handle, - src->handle, + vkCmdBuffer->handle, + src->handle, dst->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, @@ -680,17 +669,17 @@ void PAL_CALL cmdCopyImageVk( copyRegion.srcSubresource.baseArrayLayer = copyInfo->srcStartArrayLayer; copyRegion.srcSubresource.layerCount = copyInfo->arrayLayerCount; copyRegion.srcSubresource.mipLevel = copyInfo->srcMipLevel; - + s_Vk.cmdCopyImage( - vkCmdBuffer->handle, - srcImage->handle, + vkCmdBuffer->handle, + srcImage->handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstImage->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); } - + void PAL_CALL cmdCopyImageToBufferVk( PalCommandBuffer* cmdBuffer, PalBuffer* dstBuffer, @@ -718,11 +707,11 @@ void PAL_CALL cmdCopyImageToBufferVk( copyRegion.imageSubresource.baseArrayLayer = copyInfo->ImageStartArrayLayer; copyRegion.imageSubresource.layerCount = copyInfo->ImageArrayLayerCount; copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; - + s_Vk.cmdCopyImageToBuffer( - vkCmdBuffer->handle, + vkCmdBuffer->handle, src->handle, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->handle, 1, ©Region); @@ -1019,7 +1008,7 @@ void PAL_CALL cmdDispatchBaseVk( { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - + device->cmdDispatchBase( vkCmdBuffer->handle, baseGroupX, @@ -1102,7 +1091,7 @@ void PAL_CALL cmdTraceRaysIndirectVk( barrier.buffer = vkCmdBuffer->buffer; barrier.offset = 0; barrier.size = VK_WHOLE_SIZE; - + VkDependencyInfo dependencyInfo = {0}; dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; dependencyInfo.bufferMemoryBarrierCount = 1; @@ -1152,13 +1141,13 @@ void PAL_CALL cmdPushConstantsVk( { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; PipelineVk* pipeline = vkCmdBuffer->pipeline; - + s_Vk.cmdPushConstants( - vkCmdBuffer->handle, - pipeline->layout, + vkCmdBuffer->handle, + pipeline->layout, vkCmdBuffer->device->shaderStages, - offset, - size, + offset, + size, value); } @@ -1180,7 +1169,7 @@ void PAL_CALL cmdSetCullModeVk( case PAL_CULL_MODE_NONE: vkCullMode = VK_CULL_MODE_NONE; } - + device->cmdSetCullMode(vkCmdBuffer->handle, vkCullMode); } @@ -1209,7 +1198,7 @@ void PAL_CALL cmdSetPrimitiveTopologyVk( { CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; DeviceVk* device = vkCmdBuffer->device; - + VkPrimitiveTopology vkTopology = 0; switch (topology) { case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { @@ -1282,14 +1271,8 @@ void PAL_CALL cmdSetStencilOpVk( VkStencilOp vkPassOp = stencilOpToVk(passOp); VkStencilOp vkDepthFailOp = stencilOpToVk(depthFailOp); VkCompareOp vkCompareOp = compareOpToVk(compareOp); - - device->cmdSetStencilOp( - vkCmdBuffer->handle, - faceFlags, - failOp, - passOp, - depthFailOp, - compareOp); + + device->cmdSetStencilOp(vkCmdBuffer->handle, faceFlags, failOp, passOp, depthFailOp, compareOp); } #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_descriptors_vulkan.c b/src/graphics/vulkan/pal_descriptors_vulkan.c index ad4af411..b3b9a8f5 100644 --- a/src/graphics/vulkan/pal_descriptors_vulkan.c +++ b/src/graphics/vulkan/pal_descriptors_vulkan.c @@ -117,10 +117,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout) { DescriptorSetLayoutVk* vkLayout = (DescriptorSetLayoutVk*)layout; - s_Vk.destroyDescriptorSetLayout( - vkLayout->device->handle, - vkLayout->handle, - &s_Vk.vkAllocator); + s_Vk.destroyDescriptorSetLayout(vkLayout->device->handle, vkLayout->handle, &s_Vk.vkAllocator); palFree(s_Vk.allocator, layout); } @@ -158,11 +155,8 @@ PalResult PAL_CALL createDescriptorPoolVk( createInfo.poolSizeCount = bindingSizeCount; createInfo.pPoolSizes = poolSizes; - result = s_Vk.createDescriptorPool( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &pool->handle); + result = + s_Vk.createDescriptorPool(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &pool->handle); palFree(s_Vk.allocator, poolSizes); if (result != VK_SUCCESS) { @@ -272,7 +266,6 @@ PalResult PAL_CALL updateDescriptorSetVk( memset(bufferInfos, 0, sizeof(VkDescriptorBufferInfo) * bufferCount); } - if (imageCount) { imageInfos = palAllocate(s_Vk.allocator, sizeof(VkDescriptorImageInfo) * imageCount, 0); if (!imageInfos) { @@ -283,7 +276,8 @@ PalResult PAL_CALL updateDescriptorSetVk( } if (tlasCount) { - uint32_t tlasInfoSize = sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasInfoCount; + uint32_t tlasInfoSize = + sizeof(VkWriteDescriptorSetAccelerationStructureKHR) * tlasInfoCount; tlasInfos = palAllocate(s_Vk.allocator, tlasInfoSize, 0); tlas = palAllocate(s_Vk.allocator, sizeof(VkAccelerationStructureKHR) * count, 0); if (!tlasInfos || !tlas) { @@ -343,7 +337,7 @@ PalResult PAL_CALL updateDescriptorSetVk( SamplerVk* vkSampler = (SamplerVk*)tmp->sampler; imageInfo->sampler = vkSampler->handle; imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - } + } } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { if (info->imageViewInfos) { @@ -378,7 +372,7 @@ PalResult PAL_CALL updateDescriptorSetVk( tlasInfo->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR; tlasInfo->accelerationStructureCount = info->descriptorCount; tlasInfo->pAccelerationStructures = &tlas[tlasCount]; - + write->pNext = &tlasInfos[tlasInfoCount++]; tlasCount += write->descriptorCount; diff --git a/src/graphics/vulkan/pal_device_vulkan.c b/src/graphics/vulkan/pal_device_vulkan.c index 3178086e..d5266bdc 100644 --- a/src/graphics/vulkan/pal_device_vulkan.c +++ b/src/graphics/vulkan/pal_device_vulkan.c @@ -9,7 +9,7 @@ #include "pal_vulkan.h" static void fillDescriptorIndexingFeatures( - VkPhysicalDeviceDescriptorIndexingFeaturesEXT* feature, + VkPhysicalDeviceDescriptorIndexingFeaturesEXT* feature, VkPhysicalDevice phyDevice) { VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; @@ -38,7 +38,7 @@ static void fillDescriptorIndexingFeatures( } static void loadFeatureProcs( - PalAdapterFeatures features, + PalAdapterFeatures features, DeviceVk* device) { // clang-format off @@ -354,7 +354,6 @@ static void loadFeatureProcs( } // clang-format on - } static VkShaderStageFlags shaderStageToVK(PalShaderStage stage) @@ -764,7 +763,7 @@ PalResult PAL_CALL createDeviceVk( // HACK: most CPU drivers dont have a vram so we set the vram to system memory if (device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] == 0) { device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] = - device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD]; + device->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD]; } // cache shader stages @@ -850,11 +849,8 @@ PalResult PAL_CALL allocateMemoryVk( allocateInfo.pNext = &allocateFlagsInfo; } - result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, - &memory->handle); + result = + s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &memory->handle); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -925,7 +921,7 @@ void PAL_CALL queryDepthStencilCapabilitiesVk( caps->supportsIndependentResolve = props.independentResolve; caps->supportsIndependentResolveNone = props.independentResolveNone; - + // depth if (props.supportedDepthResolveModes & VK_RESOLVE_MODE_AVERAGE_BIT_KHR) { caps->supportedDepthResolveModes |= (1u << PAL_RESOLVE_MODE_AVERAGE); @@ -1070,7 +1066,7 @@ void PAL_CALL queryDescriptorIndexingCapabilitiesVk( VkPhysicalDeviceAccelerationStructurePropertiesKHR accProps = {0}; accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; - + features.pNext = &desc; props.pNext = &accProps; properties2.pNext = &props; @@ -1235,9 +1231,9 @@ PalBool PAL_CALL canQueuePresentVk( VkBool32 supported = PAL_FALSE; result = s_Vk.checkSurfaceSupport( - phyQueue->phyDevice, - phyQueue->familyIndex, - vkSurface->handle, + phyQueue->phyDevice, + phyQueue->familyIndex, + vkSurface->handle, &supported); if (result == VK_SUCCESS && supported) { @@ -1272,13 +1268,13 @@ PalResult PAL_CALL createShaderVk( strncpy(entry->entryName, info->entries[i].entryName, PAL_SHADER_ENTRY_NAME_SIZE); entry->entryName[PAL_SHADER_ENTRY_NAME_SIZE - 1] = '\0'; entry->patchControlPoints = info->entries[i].patchControlPoints; - entry->stage = shaderStageToVK(info->entries[i].stage); + entry->stage = shaderStageToVK(info->entries[i].stage); } VkShaderModuleCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = info->bytecodeSize; - createInfo.pCode = (const uint32_t*)info->bytecode; + createInfo.codeSize = info->codeSize; + createInfo.pCode = (const uint32_t*)info->code; result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); if (result != VK_SUCCESS) { diff --git a/src/graphics/vulkan/pal_image_vulkan.c b/src/graphics/vulkan/pal_image_vulkan.c index 7ce6fbf0..7803a2d0 100644 --- a/src/graphics/vulkan/pal_image_vulkan.c +++ b/src/graphics/vulkan/pal_image_vulkan.c @@ -103,11 +103,9 @@ static VkSamplerAddressMode addressModeToVk(PalSamplerAddressMode mode) case PAL_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: { return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; - } case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: { return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - } case PAL_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER: { return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; @@ -177,12 +175,12 @@ PalResult PAL_CALL createImageVk( createInfo.extent.height = info->height; createInfo.extent.depth = info->depth; - createInfo.arrayLayers = info->arrayLayerCount; + createInfo.arrayLayers = info->arrayLayerCount; createInfo.mipLevels = info->mipLevelCount; createInfo.format = formatToVk(info->format); createInfo.samples = samplesToVk(info->sampleCount); createInfo.usage = imageUsageToVk(info->usages); - + createInfo.imageType = VK_IMAGE_TYPE_2D; if (info->type == PAL_IMAGE_TYPE_3D) { createInfo.imageType = VK_IMAGE_TYPE_3D; @@ -217,9 +215,9 @@ PalResult PAL_CALL createImageVk( allocateInfo.memoryTypeIndex = memoryIndex; result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, + vkDevice->handle, + &allocateInfo, + &s_Vk.vkAllocator, &memory->handle); if (result != VK_SUCCESS) { @@ -346,11 +344,8 @@ PalResult PAL_CALL createImageViewVk( createInfo.subresourceRange.levelCount = info->subresourceRange.mipLevelCount; createInfo.subresourceRange.layerCount = info->subresourceRange.layerArrayCount; - result = s_Vk.createImageView( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &imageView->handle); + result = + s_Vk.createImageView(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &imageView->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, imageView); @@ -384,7 +379,7 @@ PalResult PAL_CALL createSamplerVk( if (!sampler) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } - + VkSamplerCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; createInfo.anisotropyEnable = info->enableAnisotropy; @@ -405,11 +400,7 @@ PalResult PAL_CALL createSamplerVk( createInfo.addressModeW = addressModeToVk(info->addressModeW); createInfo.borderColor = borderColorToVk(info->borderColor); - result = s_Vk.createSampler( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &sampler->handle); + result = s_Vk.createSampler(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &sampler->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, sampler); diff --git a/src/graphics/vulkan/pal_pipeline_vulkan.c b/src/graphics/vulkan/pal_pipeline_vulkan.c index e17894c0..19cb8dfe 100644 --- a/src/graphics/vulkan/pal_pipeline_vulkan.c +++ b/src/graphics/vulkan/pal_pipeline_vulkan.c @@ -144,7 +144,7 @@ PalResult PAL_CALL createPipelineLayoutVk( PipelineLayoutVk* layout = nullptr; VkPushConstantRange pushConstantRange = {0}; VkDescriptorSetLayout* descriptorLayouts = nullptr; - + layout = palAllocate(s_Vk.allocator, sizeof(PipelineLayoutVk), 0); if (!layout) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -152,8 +152,8 @@ PalResult PAL_CALL createPipelineLayoutVk( if (info->descriptorSetLayoutCount) { descriptorLayouts = palAllocate( - s_Vk.allocator, - sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount, + s_Vk.allocator, + sizeof(VkDescriptorSetLayout) * info->descriptorSetLayoutCount, 0); if (!descriptorLayouts) { @@ -272,10 +272,8 @@ PalResult PAL_CALL createGraphicsPipelineVk( } pipeline = palAllocate(s_Vk.allocator, sizeof(PipelineVk), 0); - shaderStages = palAllocate( - s_Vk.allocator, - sizeof(VkPipelineShaderStageCreateInfo) * stageCount, - 0); + shaderStages = + palAllocate(s_Vk.allocator, sizeof(VkPipelineShaderStageCreateInfo) * stageCount, 0); if (!pipeline || !shaderStages) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -609,10 +607,8 @@ PalResult PAL_CALL createGraphicsPipelineVk( VkFormat* colorAttachments = nullptr; PalRenderingLayoutInfo* renderingLayout = info->renderingLayout; - colorAttachments = palAllocate( - s_Vk.allocator, - sizeof(VkFormat) * renderingLayout->colorAttachentCount, - 0); + colorAttachments = + palAllocate(s_Vk.allocator, sizeof(VkFormat) * renderingLayout->colorAttachentCount, 0); if (!colorAttachments) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -722,7 +718,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( DeviceVk* vkDevice = (DeviceVk*)device; PipelineLayoutVk* layout = (PipelineLayoutVk*)info->pipelineLayout; PipelineVk* pipeline = nullptr; - VkPipelineShaderStageCreateInfo* shaderStages = nullptr; + VkPipelineShaderStageCreateInfo* shaderStages = nullptr; VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; if (info->maxPayloadSize > vkDevice->limits.maxPayloadSize) { @@ -741,14 +737,12 @@ PalResult PAL_CALL createRayTracingPipelineVk( pipeline = palAllocate(s_Vk.allocator, sizeof(PipelineVk), 0); groups = palAllocate( - s_Vk.allocator, - sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount, + s_Vk.allocator, + sizeof(VkRayTracingShaderGroupCreateInfoKHR) * info->shaderGroupCount, 0); - shaderStages = palAllocate( - s_Vk.allocator, - sizeof(VkPipelineShaderStageCreateInfo) * stageCount, - 0); + shaderStages = + palAllocate(s_Vk.allocator, sizeof(VkPipelineShaderStageCreateInfo) * stageCount, 0); if (!pipeline || !groups || !shaderStages) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -835,7 +829,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( group->closestHitShader = VK_SHADER_UNUSED_KHR; } - if (tmp->intersectionShaderIndex!= PAL_UNUSED_SHADER_INDEX) { + if (tmp->intersectionShaderIndex != PAL_UNUSED_SHADER_INDEX) { group->intersectionShader = tmp->intersectionShaderEntryIndex; } else { diff --git a/src/graphics/vulkan/pal_sbt_vulkan.c b/src/graphics/vulkan/pal_sbt_vulkan.c index 5e7ff77c..7d492a0b 100644 --- a/src/graphics/vulkan/pal_sbt_vulkan.c +++ b/src/graphics/vulkan/pal_sbt_vulkan.c @@ -127,11 +127,8 @@ PalResult PAL_CALL createShaderBindingTableVk( // create staging buffer bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; sbt->stagingBufferSize = bufferSize; - result = s_Vk.createBuffer( - vkDevice->handle, - &bufCreateInfo, - &s_Vk.vkAllocator, - &sbt->stagingBuffer); + result = + s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->stagingBuffer); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -154,11 +151,8 @@ PalResult PAL_CALL createShaderBindingTableVk( allocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; allocateInfo.pNext = &allocateFlagsInfo; - result = s_Vk.allocateMemory( - vkDevice->handle, - &allocateInfo, - &s_Vk.vkAllocator, - &sbt->bufferMemory); + result = + s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &sbt->bufferMemory); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -241,7 +235,7 @@ PalResult PAL_CALL createShaderBindingTableVk( memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); } } - + offset += sbtInfo->missCount; srcPtr += (groupHandleSize * sbtInfo->missCount); @@ -256,7 +250,7 @@ PalResult PAL_CALL createShaderBindingTableVk( memcpy(dstPtr + groupHandleSize, record->localData, record->localDataSize); } } - + offset += sbtInfo->hitCount; srcPtr += (groupHandleSize * sbtInfo->hitCount); @@ -282,7 +276,7 @@ PalResult PAL_CALL createShaderBindingTableVk( // raygen sbt->raygen.region.deviceAddress = sbt->baseAddress; - sbt->raygen.offset = 0; // always + sbt->raygen.offset = 0; // always sbt->raygen.startIndex = 0; // always sbt->raygen.region.size = raygenRegionSize; sbt->raygen.region.stride = raygenStride; @@ -332,7 +326,7 @@ void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt) } void PAL_CALL updateShaderBindingTableVk( - PalShaderBindingTable* sbt, + PalShaderBindingTable* sbt, uint32_t count, PalShaderBindingTableRecordInfo* infos) { diff --git a/src/graphics/vulkan/pal_swapchain_vulkan.c b/src/graphics/vulkan/pal_swapchain_vulkan.c index 23d45125..655e056f 100644 --- a/src/graphics/vulkan/pal_swapchain_vulkan.c +++ b/src/graphics/vulkan/pal_swapchain_vulkan.c @@ -395,8 +395,8 @@ PalResult PAL_CALL getNextSwapchainImageVk( } PalResult PAL_CALL presentSwapchainVk( - PalSwapchain* swapchain, - uint32_t imageIndex, + PalSwapchain* swapchain, + uint32_t imageIndex, PalSemaphore* waitSemaphore) { SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; diff --git a/src/graphics/vulkan/pal_sync_vulkan.c b/src/graphics/vulkan/pal_sync_vulkan.c index fc882827..65203bc2 100644 --- a/src/graphics/vulkan/pal_sync_vulkan.c +++ b/src/graphics/vulkan/pal_sync_vulkan.c @@ -117,15 +117,12 @@ PalResult PAL_CALL createSemaphoreVk( semaphore->isTimeline = PAL_FALSE; if (enableTimeline) { next = &timelineCreateInfo; - semaphore->isTimeline = PAL_TRUE; + semaphore->isTimeline = PAL_TRUE; } createInfo.pNext = next; - result = s_Vk.createSemaphore( - vkDevice->handle, - &createInfo, - &s_Vk.vkAllocator, - &semaphore->handle); + result = + s_Vk.createSemaphore(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &semaphore->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, semaphore); @@ -170,10 +167,7 @@ PalResult PAL_CALL waitSemaphoreVk( waitInfo.pSemaphores = &vkSemaphore->handle; waitInfo.pValues = &value; - result = vkSemaphore->device->waitSemaphore( - vkSemaphore->device->handle, - &waitInfo, - timeInNano); + result = vkSemaphore->device->waitSemaphore(vkSemaphore->device->handle, &waitInfo, timeInNano); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -206,7 +200,9 @@ PalResult PAL_CALL signalSemaphoreVk( return PAL_RESULT_SUCCESS; } -PalResult PAL_CALL getSemaphoreValueVk(PalSemaphore* semaphore, uint64_t* value) +PalResult PAL_CALL getSemaphoreValueVk( + PalSemaphore* semaphore, + uint64_t* value) { SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; VkResult result = vkSemaphore->device->getSemaphoreValue( diff --git a/src/graphics/vulkan/pal_vulkan.c b/src/graphics/vulkan/pal_vulkan.c index d7e621da..f79599f7 100644 --- a/src/graphics/vulkan/pal_vulkan.c +++ b/src/graphics/vulkan/pal_vulkan.c @@ -666,7 +666,7 @@ void fillBuildInfoVk( if (getBuildSize) { maxPrimitives[i] = info->count; - + } else { range->primitiveCount = info->count; range->firstVertex = 0; // PAL does not allow setting this @@ -686,7 +686,7 @@ void fillBuildInfoVk( if (getBuildSize) { maxPrimitives[i] = info->geometries[i].primitiveCount; - + } else { range->primitiveCount = info->geometries[i].primitiveCount; range->firstVertex = 0; // PAL does not allow setting this @@ -870,8 +870,8 @@ VkPipelineStageFlags2 pipelineStagesToVk(PalPipelineStages stages) } static void* alignedRealloc( - void* memory, - uint64_t size, + void* memory, + uint64_t size, uint64_t alignment) { #if defined(_MSC_VER) || defined(__MINGW32__) @@ -935,7 +935,7 @@ static void* loadLibrary(const char* name) { #ifdef _WIN32 return LoadLibraryA(name); -#elif defined (__linux__) +#elif defined(__linux__) return dlopen(name, RTLD_LAZY); #endif } @@ -944,16 +944,18 @@ static void freeLibrary(void* lib) { #ifdef _WIN32 FreeLibrary(lib); -#elif defined (__linux__) +#elif defined(__linux__) dlclose(lib); #endif } -static void* loadProc(void* lib, const char* name) +static void* loadProc( + void* lib, + const char* name) { #ifdef _WIN32 return GetProcAddress(lib, name); -#elif defined (__linux__) +#elif defined(__linux__) return dlsym(lib, name); #endif } @@ -962,7 +964,7 @@ static uint32_t getNativeCode() { #ifdef _WIN32 return GetLastError(); -#elif defined (__linux__) +#elif defined(__linux__) return errno; #endif } diff --git a/src/opengl/egl/pal_context_egl.c b/src/opengl/egl/pal_context_egl.c index f59c5b61..be3c8b6e 100644 --- a/src/opengl/egl/pal_context_egl.c +++ b/src/opengl/egl/pal_context_egl.c @@ -124,8 +124,8 @@ PalResult eglCreateGLContext( EGLint numConfigs = 0; if (!s_Egl.getConfigs(s_Egl.display, nullptr, 0, &numConfigs)) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_EGL, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_EGL, s_Egl.getError()); } @@ -306,8 +306,8 @@ PalResult eglMakeContextCurrent( } else { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_EGL, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_EGL, error); } } diff --git a/src/opengl/egl/pal_egl.c b/src/opengl/egl/pal_egl.c index 6b8213fc..ef48c003 100644 --- a/src/opengl/egl/pal_egl.c +++ b/src/opengl/egl/pal_egl.c @@ -8,8 +8,8 @@ #include "pal_platform.h" #if _PAL_HAS_EGL -#include "pal_egl.h" #include "opengl/pal_opengl_shared.h" +#include "pal_egl.h" #include #include #include @@ -23,10 +23,7 @@ PalResult PAL_CALL eglInitGL( const PalAllocator* allocator) { s_Egl.maxContextData = 16; // initial size - s_Egl.contextData = palAllocate( - s_Egl.allocator, - sizeof(ContextData) * s_Egl.maxContextData, - 0); + s_Egl.contextData = palAllocate(s_Egl.allocator, sizeof(ContextData) * s_Egl.maxContextData, 0); if (!s_Egl.maxContextData) { return PAL_RESULT_CODE_OUT_OF_MEMORY; @@ -165,7 +162,7 @@ PalResult PAL_CALL eglInitGL( } EGLSurface surface = EGL_NO_SURFACE; - EGLint pBufferAttribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; + EGLint pBufferAttribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; surface = s_Egl.createPbufferSurface(tmpDisplay, config, pBufferAttribs); if (surface == EGL_NO_SURFACE) { error = s_Egl.getError(); @@ -187,7 +184,7 @@ PalResult PAL_CALL eglInitGL( context = s_Egl.createContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); } else { - EGLint contextAttrib[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; + EGLint contextAttrib[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; context = s_Egl.createContext(tmpDisplay, config, EGL_NO_CONTEXT, contextAttrib); } diff --git a/src/opengl/pal_opengl.c b/src/opengl/pal_opengl.c index 90d607e3..bdb1fc58 100644 --- a/src/opengl/pal_opengl.c +++ b/src/opengl/pal_opengl.c @@ -184,8 +184,8 @@ void PAL_CALL palSetSwapInterval(int32_t interval) const PalBool* PAL_CALL palGetSupportedGLAPIs(void* instance) { #if _PAL_HAS_EGL - return eglGetSupportedGLAPIs(instance); + return eglGetSupportedGLAPIs(instance); #elif defined(_WIN32) - return wglGetSupportedGLAPIs(instance); + return wglGetSupportedGLAPIs(instance); #endif // _PAL_HAS_EGL } \ No newline at end of file diff --git a/src/opengl/wgl/pal_context_wgl.c b/src/opengl/wgl/pal_context_wgl.c index 866a318f..e4d1acf1 100644 --- a/src/opengl/wgl/pal_context_wgl.c +++ b/src/opengl/wgl/pal_context_wgl.c @@ -43,7 +43,7 @@ PalResult wglCreateGLContext( } } - // check version + // check version // clang-format off PalBool valid = info->major < s_Wgl.info.major || (info->major == s_Wgl.info.major && info->minor <= s_Wgl.info.minor); @@ -56,17 +56,16 @@ PalResult wglCreateGLContext( HDC hdc = GetDC((HWND)info->window->window); if (!hdc) { return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); - } // check if the provided pixel format is the same as the window if (s_Gdi.getPixelFormat(hdc) != info->fbConfig->index) { return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -152,14 +151,14 @@ PalResult wglCreateGLContext( DWORD error = GetLastError(); if (error == ERROR_INVALID_PROFILE_ARB) { return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -169,8 +168,8 @@ PalResult wglCreateGLContext( context = s_Wgl.createContext(hdc); if (!context) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -180,8 +179,8 @@ PalResult wglCreateGLContext( s_Wgl.deleteContext(context); ReleaseDC((HWND)info->window->window, hdc); return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } } @@ -206,8 +205,8 @@ PalResult wglMakeContextCurrent( HDC hdc = GetDC((HWND)glWindow->window); if (!hdc) { return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -215,14 +214,14 @@ PalResult wglMakeContextCurrent( DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, error); } else { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, error); } } @@ -243,24 +242,18 @@ PalResult wglSwapBuffers( HDC hdc = GetDC((HWND)glWindow->window); if (!hdc) { return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } if (!s_Gdi.swapBuffers(hdc)) { DWORD error = GetLastError(); if (error == ERROR_INVALID_PIXEL_FORMAT) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_INVALID_ARGUMENT, PAL_RESULT_SOURCE_WIN32, error); } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_WIN32, error); } } diff --git a/src/opengl/wgl/pal_wgl.c b/src/opengl/wgl/pal_wgl.c index cbdb2fc4..2af5b4a3 100644 --- a/src/opengl/wgl/pal_wgl.c +++ b/src/opengl/wgl/pal_wgl.c @@ -36,8 +36,8 @@ PalResult wglInitGL( // denied if (!RegisterClassExW(&wc)) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -58,8 +58,8 @@ PalResult wglInitGL( if (!s_Wgl.window) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -67,8 +67,8 @@ PalResult wglInitGL( s_Wgl.opengl = LoadLibraryA("opengl32.dll"); if (!s_Gdi.handle || !s_Wgl.opengl) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -148,8 +148,8 @@ PalResult wglInitGL( if (!s_Wgl.makeCurrent(s_Wgl.hdc, s_Wgl.context)) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -315,8 +315,8 @@ PalResult wglEnumerateGLFBConfigs( // get framebuffer config with extensions if (!s_Wgl.getPixelFormatAttribivARB(s_Wgl.hdc, 0, 0, 1, &configAttrib, &nativeCount)) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/system/linux/pal_platform_linux.c b/src/system/linux/pal_platform_linux.c index 8f000fdc..09f23985 100644 --- a/src/system/linux/pal_platform_linux.c +++ b/src/system/linux/pal_platform_linux.c @@ -9,8 +9,8 @@ #include "pal/pal_system.h" #include #include -#include #include +#include void PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) { diff --git a/src/thread/posix/pal_thread_posix.c b/src/thread/posix/pal_thread_posix.c index 8418b49c..16027df1 100644 --- a/src/thread/posix/pal_thread_posix.c +++ b/src/thread/posix/pal_thread_posix.c @@ -12,9 +12,9 @@ #if _PAL_HAS_POSIX #include "pal_thread_posix.h" +#include #include #include -#include #define TO_PAL_HANDLE(type, val) ((type*)(uintptr_t)(val)) #define FROM_PAL_HANDLE(type, handle) ((type)(uintptr_t)(handle)) @@ -104,7 +104,7 @@ PalThreadFeatures PAL_CALL palGetThreadFeatures() features |= PAL_THREAD_FEATURE_AFFINITY; features |= PAL_THREAD_FEATURE_NAME; #endif // __linux__ - + return features; } @@ -190,8 +190,8 @@ PalResult PAL_CALL palSetThreadPriority( int ret = pthread_setschedparam(_thread, SCHED_FIFO, ¶m); if (ret == EPERM) { return palMakeResult( - PAL_RESULT_CODE_INVALID_OPERATION, - PAL_RESULT_SOURCE_POSIX, + PAL_RESULT_CODE_INVALID_OPERATION, + PAL_RESULT_SOURCE_POSIX, errno); } } @@ -241,7 +241,7 @@ PalResult PAL_CALL palSetThreadName( return palMakeResult(PAL_RESULT_CODE_INVALID_HANDLE, PAL_RESULT_SOURCE_POSIX, errno); } #endif // __linux__ - + return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } diff --git a/src/thread/win32/pal_condvar_win32.c b/src/thread/win32/pal_condvar_win32.c index 3b517842..b95575fc 100644 --- a/src/thread/win32/pal_condvar_win32.c +++ b/src/thread/win32/pal_condvar_win32.c @@ -46,16 +46,10 @@ PalResult PAL_CALL palWaitCondVar( if (!ret) { DWORD error = GetLastError(); if (error == ERROR_TIMEOUT) { - return palMakeResult( - PAL_RESULT_CODE_TIMEOUT, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_TIMEOUT, PAL_RESULT_SOURCE_WIN32, error); } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_WIN32, error); } } return PAL_RESULT_SUCCESS; @@ -70,16 +64,10 @@ PalResult PAL_CALL palWaitCondVarTimeout( if (!ret) { DWORD error = GetLastError(); if (error == ERROR_TIMEOUT) { - return palMakeResult( - PAL_RESULT_CODE_TIMEOUT, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_TIMEOUT, PAL_RESULT_SOURCE_WIN32, error); } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_WIN32, error); } } return PAL_RESULT_SUCCESS; diff --git a/src/thread/win32/pal_mutex_win32.c b/src/thread/win32/pal_mutex_win32.c index 7a2f2c74..e4c47967 100644 --- a/src/thread/win32/pal_mutex_win32.c +++ b/src/thread/win32/pal_mutex_win32.c @@ -25,8 +25,8 @@ PalResult PAL_CALL palCreateMutex( PalMutex* mutex = palAllocate(allocator, sizeof(PalMutex), 0); if (!mutex) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/thread/win32/pal_thread_win32.c b/src/thread/win32/pal_thread_win32.c index e9d1317b..20ed4dcc 100644 --- a/src/thread/win32/pal_thread_win32.c +++ b/src/thread/win32/pal_thread_win32.c @@ -59,28 +59,16 @@ PalResult PAL_CALL palCreateThread( // error DWORD error = GetLastError(); if (error == ERROR_NOT_ENOUGH_MEMORY) { - return palMakeResult( - PAL_RESULT_CODE_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_OUT_OF_MEMORY, PAL_RESULT_SOURCE_WIN32, error); } else if (error == ERROR_INVALID_PARAMETER) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_INVALID_ARGUMENT, PAL_RESULT_SOURCE_WIN32, error); } else if (error == ERROR_ACCESS_DENIED) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_OPERATION, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_INVALID_OPERATION, PAL_RESULT_SOURCE_WIN32, error); } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_WIN32, error); } } @@ -104,8 +92,8 @@ PalResult PAL_CALL palJoinThread( } else if (wait == WAIT_FAILED) { return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -230,22 +218,13 @@ PalResult PAL_CALL palSetThreadPriority( if (!SetThreadPriority((HANDLE)thread, _priority)) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_INVALID_HANDLE, PAL_RESULT_SOURCE_WIN32, error); } else if (error == ERROR_ACCESS_DENIED) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_OPERATION, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_INVALID_OPERATION, PAL_RESULT_SOURCE_WIN32, error); } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_WIN32, error); } } @@ -259,16 +238,10 @@ PalResult PAL_CALL palSetThreadAffinity( if (!SetThreadAffinityMask((HANDLE)thread, mask)) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE || error == ERROR_INVALID_PARAMETER) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_INVALID_ARGUMENT, PAL_RESULT_SOURCE_WIN32, error); } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_WIN32, error); } } @@ -292,28 +265,16 @@ PalResult PAL_CALL palSetThreadName( } else { if (hr == E_INVALIDARG) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - hr); + return palMakeResult(PAL_RESULT_CODE_INVALID_HANDLE, PAL_RESULT_SOURCE_WIN32, hr); } else if (hr == E_OUTOFMEMORY) { - return palMakeResult( - PAL_RESULT_CODE_OUT_OF_MEMORY, - PAL_RESULT_SOURCE_WIN32, - hr); + return palMakeResult(PAL_RESULT_CODE_OUT_OF_MEMORY, PAL_RESULT_SOURCE_WIN32, hr); } else if (hr == E_ACCESSDENIED) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_OPERATION, - PAL_RESULT_SOURCE_WIN32, - hr); + return palMakeResult(PAL_RESULT_CODE_INVALID_OPERATION, PAL_RESULT_SOURCE_WIN32, hr); } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - hr); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_WIN32, hr); } } } diff --git a/src/video/pal_video.c b/src/video/pal_video.c index 7ad26305..25d0e3d1 100644 --- a/src/video/pal_video.c +++ b/src/video/pal_video.c @@ -86,20 +86,20 @@ PalResult PAL_CALL palInitVideo( if (x11) { #if PAL_HAS_X11_BACKEND == 1 - PalResult result = xInitVideo(allocator, eventDriver, preferredInstance); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - s_Backend = &s_XBackend; + PalResult result = xInitVideo(allocator, eventDriver, preferredInstance); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + s_Backend = &s_XBackend; #endif // PAL_HAS_X11_BACKEND } else if (wayland) { #if PAL_HAS_WAYLAND_BACKEND == 1 - PalResult result = wlInitVideo(allocator, eventDriver, preferredInstance); - if (result != PAL_RESULT_SUCCESS) { - return result; - } - s_Backend = &s_wlBackend; + PalResult result = wlInitVideo(allocator, eventDriver, preferredInstance); + if (result != PAL_RESULT_SUCCESS) { + return result; + } + s_Backend = &s_wlBackend; #endif // PAL_HAS_WAYLAND_BACKEND } @@ -322,7 +322,7 @@ PalWindow* PAL_CALL palGetFocusWindow() } void PAL_CALL palGetWindowHandleInfo( - PalWindow* window, + PalWindow* window, PalWindowHandleInfo* info) { s_Backend->getWindowHandleInfo(window, info); diff --git a/src/video/wayland/pal_video_wayland.c b/src/video/wayland/pal_video_wayland.c index d7367bc6..05893183 100644 --- a/src/video/wayland/pal_video_wayland.c +++ b/src/video/wayland/pal_video_wayland.c @@ -12,9 +12,9 @@ #include "pal_wayland_protocols.h" #include "video/pal_video_egl.h" #include +#include #include #include -#include typedef struct { PalBool pendingScroll; @@ -318,10 +318,7 @@ MonitorData* wlGetFreeMonitorData() int freeIndex = s_Wl.maxMonitorData + 1; data = palAllocate(s_Wl.allocator, sizeof(MonitorData) * count, 0); if (data) { - memcpy( - data, - s_Wl.monitorData, - s_Wl.maxMonitorData * sizeof(MonitorData)); + memcpy(data, s_Wl.monitorData, s_Wl.maxMonitorData * sizeof(MonitorData)); palFree(s_Wl.allocator, s_Wl.monitorData); s_Wl.monitorData = data; @@ -336,8 +333,7 @@ MonitorData* wlGetFreeMonitorData() MonitorData* wlFindMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Wl.maxMonitorData; ++i) { - if (s_Wl.monitorData[i].used && - s_Wl.monitorData[i].monitor == monitor) { + if (s_Wl.monitorData[i].used && s_Wl.monitorData[i].monitor == monitor) { return &s_Wl.monitorData[i]; } } @@ -347,8 +343,7 @@ MonitorData* wlFindMonitorData(PalMonitor* monitor) void wlFreeMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_Wl.maxMonitorData; ++i) { - if (s_Wl.monitorData[i].used && - s_Wl.monitorData[i].monitor == monitor) { + if (s_Wl.monitorData[i].used && s_Wl.monitorData[i].monitor == monitor) { s_Wl.monitorData[i].used = PAL_FALSE; } } @@ -371,10 +366,7 @@ WindowData* wlGetFreeWindowData() int freeIndex = s_Wl.maxWindowData + 1; data = palAllocate(s_Wl.allocator, sizeof(WindowData) * count, 0); if (data) { - memcpy( - data, - s_Wl.windowData, - s_Wl.maxWindowData * sizeof(WindowData)); + memcpy(data, s_Wl.windowData, s_Wl.maxWindowData * sizeof(WindowData)); palFree(s_Wl.allocator, s_Wl.windowData); s_Wl.windowData = data; @@ -389,8 +381,7 @@ WindowData* wlGetFreeWindowData() WindowData* wlFindWindowData(PalWindow* window) { for (int i = 0; i < s_Wl.maxWindowData; ++i) { - if (s_Wl.windowData[i].used && - s_Wl.windowData[i].window == window) { + if (s_Wl.windowData[i].used && s_Wl.windowData[i].window == window) { return &s_Wl.windowData[i]; } } @@ -622,11 +613,11 @@ static void surfaceHandleEnter( if (data->dpi == 0) { // this is triggered when the window is created // we cache the DPI and skip the event - data->dpi = monitorData->dpi; + data->dpi = monitorData->dpi; return; } - // the code below should be skipped if users are not + // the code below should be skipped if users are not // interested in DPI changed events PalDispatchMode mode = PAL_DISPATCH_MODE_NONE; PalEventType type = PAL_EVENT_TYPE_MONITOR_DPI_CHANGED; @@ -709,12 +700,7 @@ static void pointerHandleEnter( if (data->cursor) { // our window WaylandCursor* cursor = data->cursor; - wlPointerSetCursor( - pointer, - serial, - cursor->surface, - cursor->hotspotX, - cursor->hotspotY); + wlPointerSetCursor(pointer, serial, cursor->surface, cursor->hotspotX, cursor->hotspotY); } // cache the surface the pointer is currently on @@ -793,7 +779,7 @@ static void pointerHandleButton( // cannot recieve events without a focused surface return; } - + PalBool pressed = state == WL_POINTER_BUTTON_STATE_PRESSED; PalMouseButton _button = 0; PalEventType type = PAL_EVENT_TYPE_MOUSE_BUTTONUP; @@ -853,7 +839,7 @@ static void pointerHandleAxis( s_Mouse.tmpScrollY += delta; s_Mouse.accumScrollY += delta; } - + s_Mouse.pendingScroll = PAL_TRUE; } @@ -871,7 +857,7 @@ static void pointerHandleAxisDiscrete( s_Mouse.tmpScrollY += discrete; s_Mouse.accumScrollY += discrete; } - + s_Mouse.pendingScroll = PAL_TRUE; } @@ -921,16 +907,14 @@ static void pointerHandleAxisSource( struct wl_pointer* pointer, uint32_t axis_source) { - } static void pointerHandleAxisStop( void* userData, struct wl_pointer* pointer, uint32_t time, - uint32_t axis) + uint32_t axis) { - } // ================================================== @@ -1042,7 +1026,7 @@ static void keyboardHandleKey( scancode = PAL_SCANCODE_UP; } else if (key == 102) { scancode = PAL_SCANCODE_HOME; - + } else { scancode = s_Keyboard.scancodes[key]; } @@ -1151,14 +1135,7 @@ static void keyboardHandleModifiers( uint32_t group) { if (s_Wl.state) { - s_Wl.xkbStateUpdateMask( - s_Wl.state, - mods_depressed, - mods_latched, - mods_locked, - group, - 0, - 0); + s_Wl.xkbStateUpdateMask(s_Wl.state, mods_depressed, mods_latched, mods_locked, group, 0, 0); } } @@ -1187,7 +1164,6 @@ static void seatHandleName( struct wl_seat* seat, const char* name) { - } // ================================================== @@ -1214,12 +1190,7 @@ static void xdgSurfaceHandleConfigure( if (!winData->skipConfigure) { if (winData->pushConfigureEvent) { if (winData->eglWindow) { - s_Wl.eglWindowResize( - winData->eglWindow, - winData->w, - winData->h, - 0, - 0); + s_Wl.eglWindowResize(winData->eglWindow, winData->w, winData->h, 0, 0); } else { // create a new buffer with the new size @@ -1397,8 +1368,8 @@ void zxdgDecorationHandleConfigure( } PalResult wlInitVideo( - const PalAllocator* allocator, - PalEventDriver* eventDriver, + const PalAllocator* allocator, + PalEventDriver* eventDriver, void* preferredInstance) { // load wayland libray @@ -1567,7 +1538,7 @@ PalResult wlInitVideo( s_Wl.maxMonitorData = 16; // initial size s_Wl.maxWindowData = 32; // initial size s_Wl.windowData = palAllocate(s_Wl.allocator, sizeof(WindowData) * s_Wl.maxWindowData, 0); - s_Wl.monitorData = palAllocate(s_Wl.allocator,sizeof(MonitorData) * s_Wl.maxMonitorData,0); + s_Wl.monitorData = palAllocate(s_Wl.allocator, sizeof(MonitorData) * s_Wl.maxMonitorData, 0); if (!s_Wl.monitorData || !s_Wl.windowData) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } @@ -1778,25 +1749,17 @@ void* wlGetInstance() struct wl_registry_listener s_RegistryListener = { .global = globalHandle, - .global_remove = globalRemove -}; + .global_remove = globalRemove}; -struct wl_output_listener s_OutputListener = { - .geometry = outputGeometry, - .mode = outputMode, - .done = outputDone, - .scale = outputScale}; +struct wl_output_listener s_OutputListener = + {.geometry = outputGeometry, .mode = outputMode, .done = outputDone, .scale = outputScale}; -struct wl_output_listener s_DefaultModeListener = { - .geometry = outputGeometry, - .mode = outputMode, - .done = outputDone, - .scale = outputScale}; +struct wl_output_listener s_DefaultModeListener = + {.geometry = outputGeometry, .mode = outputMode, .done = outputDone, .scale = outputScale}; struct wl_surface_listener s_SurfaceListener = { .enter = surfaceHandleEnter, - .leave = surfaceHandleLeave -}; + .leave = surfaceHandleLeave}; struct wl_pointer_listener s_PointerListener = { .enter = pointerHandleEnter, @@ -1807,8 +1770,7 @@ struct wl_pointer_listener s_PointerListener = { .axis_discrete = pointerHandleAxisDiscrete, .frame = pointerHandleFrame, .axis_source = pointerHandleAxisSource, - .axis_stop = pointerHandleAxisStop -}; + .axis_stop = pointerHandleAxisStop}; struct wl_keyboard_listener s_KeyboardListener = { .enter = keyboardHandleEnter, @@ -1816,31 +1778,23 @@ struct wl_keyboard_listener s_KeyboardListener = { .keymap = keyboardHandleRemap, .key = keyboardHandleKey, .repeat_info = keyboardHandleRepeatInfo, - .modifiers = keyboardHandleModifiers -}; + .modifiers = keyboardHandleModifiers}; struct zxdg_toplevel_decoration_v1_listener s_DecorationListener = { - .configure = zxdgDecorationHandleConfigure -}; + .configure = zxdgDecorationHandleConfigure}; struct wl_seat_listener s_SeatListener = { .capabilities = seatHandleCapabilities, - .name = seatHandleName -}; + .name = seatHandleName}; -struct xdg_wm_base_listener s_WmBaseListener = { - .ping = wmBaseHandlePing -}; +struct xdg_wm_base_listener s_WmBaseListener = {.ping = wmBaseHandlePing}; -struct xdg_surface_listener s_XdgSurfaceListener = { - .configure = xdgSurfaceHandleConfigure -}; +struct xdg_surface_listener s_XdgSurfaceListener = {.configure = xdgSurfaceHandleConfigure}; struct xdg_toplevel_listener s_XdgToplevelListener = { .configure = xdgToplevelHandleConfigure, .close = xdgToplevelHandleClose, .configure_bounds = nullptr, - .wm_capabilities = nullptr -}; + .wm_capabilities = nullptr}; #endif // PAL_HAS_WAYLAND_BACKEND \ No newline at end of file diff --git a/src/video/wayland/pal_window_wayland.c b/src/video/wayland/pal_window_wayland.c index 6dca9cb4..830c12d7 100644 --- a/src/video/wayland/pal_window_wayland.c +++ b/src/video/wayland/pal_window_wayland.c @@ -8,8 +8,8 @@ #if PAL_HAS_WAYLAND_BACKEND == 1 #include "pal_wayland.h" #include "pal_wayland_protocols.h" -#include #include +#include EGLConfig eglWlBackend(const int fbConfigIndex) { @@ -164,8 +164,8 @@ PalResult wlCreateWindow( data->eglWindow = s_Wl.eglWindowCreate(surface, data->w, data->h); if (!data->eglWindow) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_EGL, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_EGL, s_VideoEgl.getError()); } @@ -266,7 +266,7 @@ PalBool wlIsWindowVisible(PalWindow* window) } void wlGetWindowHandleInfo( - PalWindow* window, + PalWindow* window, PalWindowHandleInfo* info) { WindowData* data = wlFindWindowData(window); diff --git a/src/video/win32/pal_cursor_win32.c b/src/video/win32/pal_cursor_win32.c index 0a8990b9..382dba36 100644 --- a/src/video/win32/pal_cursor_win32.c +++ b/src/video/win32/pal_cursor_win32.c @@ -44,8 +44,8 @@ PalResult win32CreateCursor( if (!bitmap) { ReleaseDC(nullptr, hdc); return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } ReleaseDC(nullptr, hdc); @@ -85,8 +85,8 @@ PalResult win32CreateCursor( if (!cursor) { s_Win32.deleteObject(bitmap); return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -129,8 +129,8 @@ PalResult win32CreateCursorFrom( if (!cursor) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/video/win32/pal_icon_win32.c b/src/video/win32/pal_icon_win32.c index 49e39dbc..d2d86083 100644 --- a/src/video/win32/pal_icon_win32.c +++ b/src/video/win32/pal_icon_win32.c @@ -44,8 +44,8 @@ PalResult win32CreateIcon( if (!bitmap) { ReleaseDC(nullptr, hdc); return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } ReleaseDC(nullptr, hdc); @@ -83,8 +83,8 @@ PalResult win32CreateIcon( if (!icon) { s_Win32.deleteObject(bitmap); return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/video/win32/pal_monitor_win32.c b/src/video/win32/pal_monitor_win32.c index 3456b288..a63d7d5a 100644 --- a/src/video/win32/pal_monitor_win32.c +++ b/src/video/win32/pal_monitor_win32.c @@ -80,16 +80,10 @@ static inline PalResult setMonitorMode( if (!GetMonitorInfoW((HMONITOR)monitor, (MONITORINFO*)&mi)) { DWORD error = GetLastError(); if (error == ERROR_INVALID_HANDLE) { - return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_INVALID_HANDLE, PAL_RESULT_SOURCE_WIN32, error); } else { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, - error); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_WIN32, error); } } @@ -116,8 +110,8 @@ static inline PalResult setMonitorMode( } else { return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } } @@ -337,7 +331,7 @@ PalResult win32SetMonitorOrientation( } else { return palMakeResult( PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } } diff --git a/src/video/win32/pal_video_win32.c b/src/video/win32/pal_video_win32.c index da55aa9c..db071673 100644 --- a/src/video/win32/pal_video_win32.c +++ b/src/video/win32/pal_video_win32.c @@ -764,7 +764,8 @@ PalResult win32InitVideo( void* preferredInstance) { s_Win32.maxWindowData = 32; - s_Win32.windowData = palAllocate(s_Win32.allocator, sizeof(WindowData) * s_Win32.maxWindowData, 0); + s_Win32.windowData = + palAllocate(s_Win32.allocator, sizeof(WindowData) * s_Win32.maxWindowData, 0); // user provided instance if (preferredInstance) { @@ -789,8 +790,8 @@ PalResult win32InitVideo( if (!RegisterClassExW(&wc)) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -811,8 +812,8 @@ PalResult win32InitVideo( if (!s_Win32.hiddenWindow) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -827,8 +828,8 @@ PalResult win32InitVideo( rid.usUsagePage = 0x01; if (!RegisterRawInputDevices(&rid, 1, sizeof(RAWINPUTDEVICE))) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/video/win32/pal_window_win32.c b/src/video/win32/pal_window_win32.c index 6784f489..1291a896 100644 --- a/src/video/win32/pal_window_win32.c +++ b/src/video/win32/pal_window_win32.c @@ -96,8 +96,8 @@ PalResult win32CreateWindow( monitor = (PalMonitor*)MonitorFromPoint((POINT){0, 0}, MONITOR_DEFAULTTOPRIMARY); if (!monitor) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } } @@ -142,8 +142,8 @@ PalResult win32CreateWindow( if (!handle) { return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_PLATFORM_FAILURE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -170,8 +170,8 @@ PalResult win32CreateWindow( sizeof(PIXELFORMATDESCRIPTOR), &pfd)) { return palMakeResult( - PAL_RESULT_CODE_INVALID_ARGUMENT, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_INVALID_ARGUMENT, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } @@ -432,7 +432,7 @@ PalWindow* win32GetFocusWindow() } void win32GetWindowHandleInfo( - PalWindow* window, + PalWindow* window, PalWindowHandleInfo* info) { info->nativeInstance = (void*)s_Win32.instance; @@ -446,7 +446,7 @@ void win32SetWindowOpacity( PalWindow* window, float opacity) { - SetLayeredWindowAttributes((HWND)window, 0, (BYTE)(opacity * 255), LWA_ALPHA); + SetLayeredWindowAttributes((HWND)window, 0, (BYTE)(opacity * 255), LWA_ALPHA); } void win32SetWindowStyle( @@ -523,14 +523,7 @@ void win32SetWindowPos( int32_t x, int32_t y) { - SetWindowPos( - (HWND)window, - nullptr, - x, - y, - 0, - 0, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); + SetWindowPos((HWND)window, nullptr, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); } void win32SetWindowSize( @@ -545,7 +538,7 @@ void win32SetWindowSize( 0, width, height, - SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); + SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER); } void win32SetFocusWindow(PalWindow* window) @@ -586,8 +579,8 @@ PalResult win32DetachWindow( data = (WindowData*)GetPropW((HWND)window, PAL_VIDEO_PROP); if (!data) { return palMakeResult( - PAL_RESULT_CODE_INVALID_HANDLE, - PAL_RESULT_SOURCE_WIN32, + PAL_RESULT_CODE_INVALID_HANDLE, + PAL_RESULT_SOURCE_WIN32, GetLastError()); } diff --git a/src/video/x11/pal_video_x11.c b/src/video/x11/pal_video_x11.c index a8876e16..fca897ee 100644 --- a/src/video/x11/pal_video_x11.c +++ b/src/video/x11/pal_video_x11.c @@ -8,8 +8,8 @@ #if PAL_HAS_X11_BACKEND == 1 #include "pal_x11.h" #include -#include #include +#include #define NULL_BUTTON_SERIAL 0xffffffffU @@ -502,10 +502,7 @@ MonitorData* xGetFreeMonitorData() int freeIndex = s_X11.maxMonitorData + 1; data = palAllocate(s_X11.allocator, sizeof(MonitorData) * count, 0); if (data) { - memcpy( - data, - s_X11.monitorData, - s_X11.maxMonitorData * sizeof(MonitorData)); + memcpy(data, s_X11.monitorData, s_X11.maxMonitorData * sizeof(MonitorData)); palFree(s_X11.allocator, s_X11.monitorData); s_X11.monitorData = data; @@ -520,8 +517,7 @@ MonitorData* xGetFreeMonitorData() MonitorData* xFindMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_X11.maxMonitorData; ++i) { - if (s_X11.monitorData[i].used && - s_X11.monitorData[i].monitor == monitor) { + if (s_X11.monitorData[i].used && s_X11.monitorData[i].monitor == monitor) { return &s_X11.monitorData[i]; } } @@ -531,8 +527,7 @@ MonitorData* xFindMonitorData(PalMonitor* monitor) void xFreeMonitorData(PalMonitor* monitor) { for (int i = 0; i < s_X11.maxMonitorData; ++i) { - if (s_X11.monitorData[i].used && - s_X11.monitorData[i].monitor == monitor) { + if (s_X11.monitorData[i].used && s_X11.monitorData[i].monitor == monitor) { s_X11.monitorData[i].used = PAL_FALSE; } } @@ -555,10 +550,7 @@ WindowData* xGetFreeWindowData() int freeIndex = s_X11.maxWindowData + 1; data = palAllocate(s_X11.allocator, sizeof(WindowData) * count, 0); if (data) { - memcpy( - data, - s_X11.windowData, - s_X11.maxWindowData * sizeof(WindowData)); + memcpy(data, s_X11.windowData, s_X11.maxWindowData * sizeof(WindowData)); palFree(s_X11.allocator, s_X11.windowData); s_X11.windowData = data; @@ -573,8 +565,7 @@ WindowData* xGetFreeWindowData() WindowData* xFindWindowData(PalWindow* window) { for (int i = 0; i < s_X11.maxWindowData; ++i) { - if (s_X11.windowData[i].used && - s_X11.windowData[i].window == window) { + if (s_X11.windowData[i].used && s_X11.windowData[i].window == window) { return &s_X11.windowData[i]; } } @@ -582,18 +573,15 @@ WindowData* xFindWindowData(PalWindow* window) } PalResult xInitVideo( - const PalAllocator* allocator, - PalEventDriver* eventDriver, + const PalAllocator* allocator, + PalEventDriver* eventDriver, void* preferredInstance) { // load X11 dependencies s_X11.handle = dlopen("libX11.so", RTLD_LAZY); s_X11.libCursor = dlopen("libXcursor.so", RTLD_LAZY); if (!s_X11.handle || !s_X11.libCursor) { - return palMakeResult( - PAL_RESULT_CODE_PLATFORM_FAILURE, - PAL_RESULT_SOURCE_POSIX, - errno); + return palMakeResult(PAL_RESULT_CODE_PLATFORM_FAILURE, PAL_RESULT_SOURCE_POSIX, errno); } s_X11.xrandr = dlopen("libXrandr.so.2", RTLD_LAZY); @@ -905,7 +893,7 @@ PalResult xInitVideo( s_X11.maxMonitorData = 16; // initial size s_X11.maxWindowData = 32; // initial size s_X11.windowData = palAllocate(s_X11.allocator, sizeof(WindowData) * s_X11.maxWindowData, 0); - s_X11.monitorData = palAllocate(s_X11.allocator,sizeof(MonitorData) * s_X11.maxMonitorData, 0); + s_X11.monitorData = palAllocate(s_X11.allocator, sizeof(MonitorData) * s_X11.maxMonitorData, 0); if (!s_X11.monitorData || !s_X11.windowData) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } @@ -971,7 +959,7 @@ PalResult xInitVideo( // disable auto key repeats int supported; s_X11.setDetectableAutoRepeat(s_X11.display, True, &supported); - + // create an input method s_X11.setLocaleModifiers(""); s_X11.im = s_X11.openIM(s_X11.display, nullptr, nullptr, nullptr); @@ -1005,7 +993,7 @@ void xShutdownVideo() if (s_X11.glxHandle) { dlclose(s_X11.glxHandle); } - + memset(&s_X11, 0, sizeof(X11)); memset(&s_X11Atoms, 0, sizeof(X11Atoms)); } diff --git a/src/video/x11/pal_window_x11.c b/src/video/x11/pal_window_x11.c index 17e00d4e..de381527 100644 --- a/src/video/x11/pal_window_x11.c +++ b/src/video/x11/pal_window_x11.c @@ -7,10 +7,10 @@ #if PAL_HAS_X11_BACKEND == 1 #include "pal_x11.h" -#include +#include #include +#include #include -#include static int xErrorHandler( Display*, @@ -82,7 +82,9 @@ static XVisualInfo* eglXBackend(int fbConfigIndex) return visualInfo; } -void xGetMonitorInfo(PalMonitor*, PalMonitorInfo*); +void xGetMonitorInfo( + PalMonitor*, + PalMonitorInfo*); PalResult xCreateWindow( const PalWindowCreateInfo* info, @@ -117,7 +119,7 @@ PalResult xCreateWindow( } else if (backend == PAL_FBCONFIG_BACKEND_GLX) { visualInfo = glxBackend(info->fbConfigIndex); - + } else { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -451,7 +453,7 @@ PalResult xCreateWindow( data->skipConfigure = PAL_TRUE; data->skipState = PAL_TRUE; data->isAttached = PAL_FALSE; // PAL_TRUE for attached windows - data->dpi = dpi; // the current window monitor + data->dpi = dpi; // the current window monitor data->window = TO_PAL_HANDLE(PalWindow, window); s_X11.saveContext(s_X11.display, window, s_X11.dataID, (XPointer)data); @@ -740,7 +742,7 @@ PalWindow* xGetFocusWindow() } void xGetWindowHandleInfo( - PalWindow* window, + PalWindow* window, PalWindowHandleInfo* info) { info->nativeInstance = (void*)s_X11.display; diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index df46daab..fc46b9be 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -1,7 +1,7 @@ #include "pal/pal_graphics.h" -#include "pal/pal_video.h" #include "pal/pal_system.h" +#include "pal/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 @@ -35,7 +35,7 @@ PalBool clearColorTest() PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; PalSemaphore** renderFinishedSemaphores; // count of swapchain images - PalFence** inFlightImages; // count of swapchain images + PalFence** inFlightImages; // count of swapchain images PalEventDriverCreateInfo eventDriverCreateInfo = {0}; result = palCreateEventDriver(&eventDriverCreateInfo, &eventDriver); @@ -66,7 +66,8 @@ PalBool clearColorTest() result = palCreateWindow(&windowCreateInfo, &window); if (result != PAL_RESULT_SUCCESS) { - logResult(result, "Failed to create window");; + logResult(result, "Failed to create window"); + ; return PAL_FALSE; } @@ -76,7 +77,7 @@ PalBool clearColorTest() PalWindowHandleInfo winHandle = {0}; palGetWindowHandleInfo(window, &winHandle); - // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; palGetPlatformInfo(&platformInfo); @@ -164,10 +165,10 @@ PalBool clearColorTest() // create surface result = palCreateSurface( - device, - winHandle.nativeWindow, - winHandle.nativeInstance, - windowInstanceType, + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, &surface); if (result != PAL_RESULT_SUCCESS) { @@ -187,7 +188,7 @@ PalBool clearColorTest() if (!palCanQueuePresent(queue, surface)) { palDestroyQueue(queue); queue = nullptr; - } else { + } else { // found a queue foundQueue = PAL_TRUE; break; @@ -489,7 +490,7 @@ PalBool clearColorTest() for (int i = 0; i < imageCount; i++) { palDestroySemaphore(renderFinishedSemaphores[i]); - palDestroyImageView(imageViews[i]); + palDestroyImageView(imageViews[i]); } palDestroyCommandPool(cmdPool); diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 0450f601..73888c21 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -136,11 +136,7 @@ PalBool computeTest() return PAL_FALSE; } - result = palAllocateCommandBuffer( - device, - cmdPool, - PAL_COMMAND_BUFFER_TYPE_PRIMARY, - &cmdBuffer); + result = palAllocateCommandBuffer(device, cmdPool, PAL_COMMAND_BUFFER_TYPE_PRIMARY, &cmdBuffer); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to allocate command buffer"); @@ -178,8 +174,8 @@ PalBool computeTest() computeEntry.entryName = "main"; computeEntry.stage = PAL_SHADER_STAGE_COMPUTE; - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.code = bytecode; + shaderCreateInfo.codeSize = bytecodeSize; shaderCreateInfo.entries = &computeEntry; shaderCreateInfo.entryCount = 1; @@ -221,10 +217,8 @@ PalBool computeTest() descriptorSetLayoutcreateInfo.bindingCount = 1; descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; - result = palCreateDescriptorSetLayout( - device, - &descriptorSetLayoutcreateInfo, - &descriptorSetLayout); + result = + palCreateDescriptorSetLayout(device, &descriptorSetLayoutcreateInfo, &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create descriptor set layout"); @@ -238,7 +232,7 @@ PalBool computeTest() PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set - descriptorPoolCreateInfo.bindingSizeCount = 1; // one binding type + descriptorPoolCreateInfo.bindingSizeCount = 1; // one binding type descriptorPoolCreateInfo.bindingSizes = &storageBufferBindingsize; result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); @@ -337,7 +331,7 @@ PalBool computeTest() buildData.workGroupSize[0] = 16; // must match shader (local_size on glsl) buildData.workGroupSize[1] = 16; // must match shader (local_size on glsl) - buildData.workGroupSize[2] = 1; // must match shader (local_size on glsl) + buildData.workGroupSize[2] = 1; // must match shader (local_size on glsl) // device limits buildData.workGroupCount[0] = caps.computeCaps.maxWorkGroupCount[0]; @@ -347,7 +341,7 @@ PalBool computeTest() uint32_t workGroupInfoCount = 0; PalWorkGroupInfo* workGroupInfos = nullptr; palBuildWorkGroupInfo(&buildData, &workGroupInfoCount, nullptr); - + workGroupInfos = palAllocate(nullptr, sizeof(PalWorkGroupInfo) * workGroupInfoCount, 0); if (!workGroupInfos) { palLog(nullptr, "Failed to allocate memory"); @@ -392,7 +386,7 @@ PalBool computeTest() submitInfo.cmdBuffer = cmdBuffer; submitInfo.fence = fence; submitInfo.waitStages = PAL_PIPELINE_STAGE_COMPUTE_SHADER; - + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); @@ -425,9 +419,9 @@ PalBool computeTest() int index = row * BUFFER_SIZE + x; uint8_t rgb[3]; - rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; - rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; - rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255: 0; + rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255 : 0; + rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255 : 0; + rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255 : 0; fwrite(rgb, 1, 3, file); } } diff --git a/tests/graphics/custom_backend_test.c b/tests/graphics/custom_backend_test.c index f94011d8..0cd1132f 100644 --- a/tests/graphics/custom_backend_test.c +++ b/tests/graphics/custom_backend_test.c @@ -15,12 +15,12 @@ static PalAdapterCapabilities s_Cap; static void initBackend() { s_Adapter.reserved = nullptr; - s_Info.apiType = PAL_ADAPTER_API_TYPE_CUSTOM; + s_Info.apiType = PAL_ADAPTER_API_TYPE_VULKAN; strcpy(s_Info.backendName, "Custom"); s_Info.deviceId = 1666; s_Info.driverVersion = 1; strcpy(s_Info.name, "GXR 7060"); - s_Info.shaderFormats = PAL_SHADER_FORMAT_CUSTOM; + s_Info.shaderFormats = PAL_SHADER_FORMAT_SPIRV | PAL_SHADER_FORMAT_GLSL; s_Info.sharedMemory = (uint64_t)(1024 * 1024 * 1024) * (uint64_t)2; s_Info.type = PAL_ADAPTER_TYPE_DISCRETE; s_Info.vendorId = 20037; @@ -51,7 +51,7 @@ static void initBackend() s_Cap.maxUniformBufferSize = 65536; s_Cap.maxVertexAttributes = 14; s_Cap.maxVertexLayouts = 4; - + s_Cap.resourceCaps.maxBoundSets = 2; s_Cap.resourceCaps.maxPerSetAccelerationStructure = 2; s_Cap.resourceCaps.maxPerSetSampledImages = 512; @@ -121,7 +121,6 @@ static PalResult PAL_CALL createDevice( static void PAL_CALL destroyDevice(PalDevice* device) { - } static PalResult PAL_CALL allocateMemory( @@ -136,14 +135,12 @@ static PalResult PAL_CALL allocateMemory( static void PAL_CALL freeMemory(PalMemory* memory) { - } static void PAL_CALL querySamplerAnisotropyCapabilities( PalDevice* device, PalSamplerAnisotropyCapabilities* caps) { - } static PalResult PAL_CALL createQueue( @@ -156,7 +153,6 @@ static PalResult PAL_CALL createQueue( static void PAL_CALL destroyQueue(PalQueue* queue) { - } static PalBool PAL_CALL canQueuePresent( @@ -176,7 +172,6 @@ static void PAL_CALL enumerateFormats( uint32_t* count, PalFormatInfo* outFormats) { - } static PalBool PAL_CALL isFormatSupported( @@ -210,21 +205,18 @@ static PalResult PAL_CALL createImage( static void PAL_CALL destroyImage(PalImage* image) { - } static void PAL_CALL getImageInfo( PalImage* image, PalImageInfo* info) { - } static void PAL_CALL getImageMemoryRequirements( PalImage* image, PalMemoryRequirements* requirements) { - } static PalResult PAL_CALL bindImageMemory( @@ -246,7 +238,6 @@ static PalResult PAL_CALL createImageView( static void PAL_CALL destroyImageView(PalImageView* imageView) { - } static PalResult PAL_CALL createSampler( @@ -259,7 +250,6 @@ static PalResult PAL_CALL createSampler( static void PAL_CALL destroySampler(PalSampler* sampler) { - } static PalResult PAL_CALL createShader( @@ -272,7 +262,6 @@ static PalResult PAL_CALL createShader( static void PAL_CALL destroyShader(PalShader* shader) { - } static PalResult PAL_CALL createFence( @@ -285,7 +274,6 @@ static PalResult PAL_CALL createFence( static void PAL_CALL destroyFence(PalFence* fence) { - } static PalResult PAL_CALL waitFence( @@ -315,7 +303,6 @@ static PalResult PAL_CALL createSemaphore( static void PAL_CALL destroySemaphore(PalSemaphore* semaphore) { - } static PalResult PAL_CALL createCommandPool( @@ -328,7 +315,6 @@ static PalResult PAL_CALL createCommandPool( static void PAL_CALL destroyCommandPool(PalCommandPool* pool) { - } static PalResult PAL_CALL allocateCommandBuffer( @@ -342,7 +328,6 @@ static PalResult PAL_CALL allocateCommandBuffer( static void PAL_CALL freeCommandBuffer(PalCommandBuffer* cmdBuffer) { - } static PalResult PAL_CALL resetCommandBuffer(PalCommandBuffer* cmdBuffer) @@ -373,14 +358,12 @@ static void PAL_CALL cmdExecuteCommandBuffer( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { - } static void PAL_CALL cmdSetFragmentShadingRate( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { - } static void PAL_CALL cmdDrawMeshTasks( @@ -389,7 +372,6 @@ static void PAL_CALL cmdDrawMeshTasks( uint32_t groupCountY, uint32_t groupCountZ) { - } static void PAL_CALL cmdDrawMeshTasksIndirect( @@ -397,7 +379,6 @@ static void PAL_CALL cmdDrawMeshTasksIndirect( PalBuffer* buffer, uint32_t drawCount) { - } static void PAL_CALL cmdDrawMeshTasksIndirectCount( @@ -406,26 +387,22 @@ static void PAL_CALL cmdDrawMeshTasksIndirectCount( PalBuffer* countBuffer, uint32_t maxDrawCount) { - } static void PAL_CALL cmdBuildAccelerationStructure( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { - } static void PAL_CALL cmdBeginRendering( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { - } static void PAL_CALL cmdEndRendering(PalCommandBuffer* cmdBuffer) { - } static void PAL_CALL cmdCopyBuffer( @@ -434,7 +411,6 @@ static void PAL_CALL cmdCopyBuffer( PalBuffer* src, PalBufferCopyInfo* copyInfo) { - } static void PAL_CALL cmdCopyBufferToImage( @@ -443,7 +419,6 @@ static void PAL_CALL cmdCopyBufferToImage( PalBuffer* srcBuffer, PalBufferImageCopyInfo* copyInfo) { - } static void PAL_CALL cmdCopyImage( @@ -452,7 +427,6 @@ static void PAL_CALL cmdCopyImage( PalImage* src, PalImageCopyInfo* copyInfo) { - } static void PAL_CALL cmdCopyImageToBuffer( @@ -461,14 +435,12 @@ static void PAL_CALL cmdCopyImageToBuffer( PalImage* srcImage, PalBufferImageCopyInfo* copyInfo) { - } static void PAL_CALL cmdBindPipeline( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline) { - } static void PAL_CALL cmdSetViewport( @@ -476,7 +448,6 @@ static void PAL_CALL cmdSetViewport( uint32_t count, PalViewport* viewports) { - } static void PAL_CALL cmdSetScissors( @@ -484,7 +455,6 @@ static void PAL_CALL cmdSetScissors( uint32_t count, PalRect2D* scissors) { - } static void PAL_CALL cmdBindVertexBuffers( @@ -494,7 +464,6 @@ static void PAL_CALL cmdBindVertexBuffers( PalBuffer** buffers, uint64_t* offsets) { - } static void PAL_CALL cmdBindIndexBuffer( @@ -503,7 +472,6 @@ static void PAL_CALL cmdBindIndexBuffer( uint64_t offset, PalIndexType type) { - } static void PAL_CALL cmdDraw( @@ -513,7 +481,6 @@ static void PAL_CALL cmdDraw( uint32_t firstVertex, uint32_t firstInstance) { - } static void PAL_CALL cmdDrawIndexed( @@ -524,7 +491,6 @@ static void PAL_CALL cmdDrawIndexed( int32_t vertexOffset, uint32_t firstInstance) { - } static void PAL_CALL cmdImageBarrier( @@ -533,7 +499,6 @@ static void PAL_CALL cmdImageBarrier( PalImageSubresourceRange* subresourceRange, PalBarrierInfo* info) { - } static void PAL_CALL cmdBufferBarrier( @@ -541,7 +506,6 @@ static void PAL_CALL cmdBufferBarrier( PalBuffer* buffer, PalBarrierInfo* info) { - } static void PAL_CALL cmdDispatch( @@ -550,7 +514,6 @@ static void PAL_CALL cmdDispatch( uint32_t groupCountY, uint32_t groupCountZ) { - } static void PAL_CALL cmdBindDescriptorSet( @@ -558,7 +521,6 @@ static void PAL_CALL cmdBindDescriptorSet( uint32_t setIndex, PalDescriptorSet* set) { - } static void PAL_CALL cmdPushConstants( @@ -567,7 +529,6 @@ static void PAL_CALL cmdPushConstants( uint32_t size, const void* value) { - } static PalResult PAL_CALL createBuffer( @@ -580,14 +541,12 @@ static PalResult PAL_CALL createBuffer( static void PAL_CALL destroyBuffer(PalBuffer* buffer) { - } static void PAL_CALL getBufferMemoryRequirements( PalBuffer* buffer, PalMemoryRequirements* requirements) { - } static void PAL_CALL computeImageStagingRequirements( @@ -596,7 +555,6 @@ static void PAL_CALL computeImageStagingRequirements( const PalBufferImageCopyInfo* copyInfo, PalImageStagingRequirements* requirements) { - } static void PAL_CALL writeImageStaging( @@ -606,7 +564,6 @@ static void PAL_CALL writeImageStaging( void* srcData, void* ptr) { - } static PalResult PAL_CALL bindBufferMemory( @@ -628,7 +585,6 @@ static PalResult PAL_CALL mapBuffer( static void PAL_CALL unmapBuffer(PalBuffer* buffer) { - } static PalResult PAL_CALL createDescriptorSetLayout( @@ -641,7 +597,6 @@ static PalResult PAL_CALL createDescriptorSetLayout( static void PAL_CALL destroyDescriptorSetLayout(PalDescriptorSetLayout* layout) { - } static PalResult PAL_CALL createDescriptorPool( @@ -654,7 +609,6 @@ static PalResult PAL_CALL createDescriptorPool( static void PAL_CALL destroyDescriptorPool(PalDescriptorPool* pool) { - } static PalResult PAL_CALL resetDescriptorPool(PalDescriptorPool* pool) @@ -689,7 +643,6 @@ static PalResult PAL_CALL createPipelineLayout( static void PAL_CALL destroyPipelineLayout(PalPipelineLayout* layout) { - } static PalResult PAL_CALL createGraphicsPipeline( @@ -710,84 +663,52 @@ static PalResult PAL_CALL createComputePipeline( static void PAL_CALL destroyPipeline(PalPipeline* pipeline) { - } PalBool customBackendTest() { // build the vtable PalGraphicsBackendVtable1 vtable = {0}; - vtable.enumerateAdapters = enumerateAdapters, - vtable.getAdapterInfo = getAdapterInfo, + vtable.enumerateAdapters = enumerateAdapters, vtable.getAdapterInfo = getAdapterInfo, vtable.getAdapterCapabilities = getAdapterCapabilities, vtable.getAdapterFeatures = getAdapterFeatures, vtable.getHighestSupportedShaderTarget = getHighestSupportedShaderTarget, - vtable.createDevice = createDevice, - vtable.destroyDevice = destroyDevice, - vtable.allocateMemory = allocateMemory, - vtable.freeMemory = freeMemory, + vtable.createDevice = createDevice, vtable.destroyDevice = destroyDevice, + vtable.allocateMemory = allocateMemory, vtable.freeMemory = freeMemory, vtable.querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilities, - vtable.createQueue = createQueue, - vtable.destroyQueue = destroyQueue, - vtable.waitQueue = waitQueue, - vtable.canQueuePresent = canQueuePresent, - vtable.enumerateFormats = enumerateFormats, - vtable.isFormatSupported = isFormatSupported, + vtable.createQueue = createQueue, vtable.destroyQueue = destroyQueue, + vtable.waitQueue = waitQueue, vtable.canQueuePresent = canQueuePresent, + vtable.enumerateFormats = enumerateFormats, vtable.isFormatSupported = isFormatSupported, vtable.queryFormatImageUsages = queryFormatImageUsages, - vtable.queryFormatSampleCount = queryFormatSampleCount, - vtable.createImage = createImage, - vtable.destroyImage = destroyImage, - vtable.getImageInfo = getImageInfo, + vtable.queryFormatSampleCount = queryFormatSampleCount, vtable.createImage = createImage, + vtable.destroyImage = destroyImage, vtable.getImageInfo = getImageInfo, vtable.getImageMemoryRequirements = getImageMemoryRequirements, - vtable.bindImageMemory = bindImageMemory, - vtable.createImageView = createImageView, - vtable.destroyImageView = destroyImageView, - vtable.createSampler = createSampler, - vtable.destroySampler = destroySampler, - vtable.createShader = createShader, - vtable.destroyShader = destroyShader, - vtable.createFence = createFence, - vtable.destroyFence = destroyFence, - vtable.waitFence = waitFence, - vtable.resetFence = resetFence, - vtable.isFenceSignaled = isFenceSignaled, - vtable.createSemaphore = createSemaphore, - vtable.destroySemaphore = destroySemaphore, - vtable.createCommandPool = createCommandPool, - vtable.destroyCommandPool = destroyCommandPool, + vtable.bindImageMemory = bindImageMemory, vtable.createImageView = createImageView, + vtable.destroyImageView = destroyImageView, vtable.createSampler = createSampler, + vtable.destroySampler = destroySampler, vtable.createShader = createShader, + vtable.destroyShader = destroyShader, vtable.createFence = createFence, + vtable.destroyFence = destroyFence, vtable.waitFence = waitFence, + vtable.resetFence = resetFence, vtable.isFenceSignaled = isFenceSignaled, + vtable.createSemaphore = createSemaphore, vtable.destroySemaphore = destroySemaphore, + vtable.createCommandPool = createCommandPool, vtable.destroyCommandPool = destroyCommandPool, vtable.allocateCommandBuffer = allocateCommandBuffer, - vtable.freeCommandBuffer = freeCommandBuffer, - vtable.resetCommandBuffer = resetCommandBuffer, - vtable.submitCommandBuffer = submitCommandBuffer, - vtable.cmdBegin = cmdBegin, - vtable.cmdEnd = cmdEnd, - vtable.cmdExecuteCommandBuffer = cmdExecuteCommandBuffer, - vtable.cmdBeginRendering = cmdBeginRendering, - vtable.cmdEndRendering = cmdEndRendering, - vtable.cmdCopyBuffer = cmdCopyBuffer, - vtable.cmdCopyBufferToImage = cmdCopyBufferToImage, - vtable.cmdCopyImage = cmdCopyImage, - vtable.cmdCopyImageToBuffer = cmdCopyImageToBuffer, - vtable.cmdBindPipeline = cmdBindPipeline, - vtable.cmdSetViewport = cmdSetViewport, - vtable.cmdSetScissors = cmdSetScissors, - vtable.cmdBindVertexBuffers = cmdBindVertexBuffers, - vtable.cmdBindIndexBuffer = cmdBindIndexBuffer, - vtable.cmdDraw = cmdDraw, - vtable.cmdDrawIndexed = cmdDrawIndexed, - vtable.cmdImageBarrier = cmdImageBarrier, - vtable.cmdBufferBarrier = cmdBufferBarrier, - vtable.cmdDispatch = cmdDispatch, - vtable.cmdBindDescriptorSet = cmdBindDescriptorSet, - vtable.cmdPushConstants = cmdPushConstants, - vtable.createBuffer = createBuffer, - vtable.destroyBuffer = destroyBuffer, + vtable.freeCommandBuffer = freeCommandBuffer, vtable.resetCommandBuffer = resetCommandBuffer, + vtable.submitCommandBuffer = submitCommandBuffer, vtable.cmdBegin = cmdBegin, + vtable.cmdEnd = cmdEnd, vtable.cmdExecuteCommandBuffer = cmdExecuteCommandBuffer, + vtable.cmdBeginRendering = cmdBeginRendering, vtable.cmdEndRendering = cmdEndRendering, + vtable.cmdCopyBuffer = cmdCopyBuffer, vtable.cmdCopyBufferToImage = cmdCopyBufferToImage, + vtable.cmdCopyImage = cmdCopyImage, vtable.cmdCopyImageToBuffer = cmdCopyImageToBuffer, + vtable.cmdBindPipeline = cmdBindPipeline, vtable.cmdSetViewport = cmdSetViewport, + vtable.cmdSetScissors = cmdSetScissors, vtable.cmdBindVertexBuffers = cmdBindVertexBuffers, + vtable.cmdBindIndexBuffer = cmdBindIndexBuffer, vtable.cmdDraw = cmdDraw, + vtable.cmdDrawIndexed = cmdDrawIndexed, vtable.cmdImageBarrier = cmdImageBarrier, + vtable.cmdBufferBarrier = cmdBufferBarrier, vtable.cmdDispatch = cmdDispatch, + vtable.cmdBindDescriptorSet = cmdBindDescriptorSet, vtable.cmdPushConstants = cmdPushConstants, + vtable.createBuffer = createBuffer, vtable.destroyBuffer = destroyBuffer, vtable.getBufferMemoryRequirements = getBufferMemoryRequirements, vtable.computeImageStagingRequirements = computeImageStagingRequirements, - vtable.writeImageStaging = writeImageStaging, - vtable.bindBufferMemory = bindBufferMemory, - vtable.mapBuffer = mapBuffer, - vtable.unmapBuffer = unmapBuffer, + vtable.writeImageStaging = writeImageStaging, vtable.bindBufferMemory = bindBufferMemory, + vtable.mapBuffer = mapBuffer, vtable.unmapBuffer = unmapBuffer, vtable.createDescriptorSetLayout = createDescriptorSetLayout, vtable.destroyDescriptorSetLayout = destroyDescriptorSetLayout, vtable.createDescriptorPool = createDescriptorPool, @@ -798,8 +719,7 @@ PalBool customBackendTest() vtable.createPipelineLayout = createPipelineLayout, vtable.destroyPipelineLayout = destroyPipelineLayout, vtable.createGraphicsPipeline = createGraphicsPipeline, - vtable.createComputePipeline = createComputePipeline, - vtable.destroyPipeline = destroyPipeline; + vtable.createComputePipeline = createComputePipeline, vtable.destroyPipeline = destroyPipeline; PalGraphicsBackendInfo backendInfo = {0}; backendInfo.version = PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1; @@ -852,9 +772,9 @@ PalBool customBackendTest() PalAdapterCapabilities caps; palGetAdapterCapabilities(adapter, &caps); PalAdapterFeatures features = palGetAdapterFeatures(adapter); - + uint64_t vramMib = (uint64_t)info.vram / (1024 * 1024); - uint64_t sharedMemMib = (uint64_t)info.sharedMemory /(1024 * 1024); + uint64_t sharedMemMib = (uint64_t)info.sharedMemory / (1024 * 1024); palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Backend Name: %s", info.backendName); @@ -904,11 +824,6 @@ PalBool customBackendTest() apiTypeString = "Metal"; break; } - - case PAL_ADAPTER_API_TYPE_CUSTOM: { - apiTypeString = "Custom"; - break; - } } palLog(nullptr, " API Type: %s", apiTypeString); @@ -944,7 +859,7 @@ PalBool customBackendTest() palLog(nullptr, ""); palLog(nullptr, " Resource Capabilities:"); PalResourceCapabilities* resourceCaps = &caps.resourceCaps; - + // clang-format off palLog(nullptr, " Max per stage sampled images: %u", resourceCaps->maxPerStageSampledImages); palLog(nullptr, " Max per set sampled images: %u", resourceCaps->maxPerSetSampledImages); @@ -992,8 +907,8 @@ PalBool customBackendTest() palLog(nullptr, " DXIL"); } - if (info.shaderFormats & PAL_SHADER_FORMAT_CUSTOM) { - palLog(nullptr, " Custom"); + if (info.shaderFormats & PAL_SHADER_FORMAT_GLSL) { + palLog(nullptr, " GLSL"); } // features diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index ab4518af..5512f4ab 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -1,7 +1,7 @@ #include "pal/pal_graphics.h" -#include "pal/pal_video.h" #include "pal/pal_system.h" +#include "pal/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 @@ -67,7 +67,7 @@ PalBool descriptorIndexingTest() PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; PalSemaphore** renderFinishedSemaphores; // count of swapchain images - PalFence** inFlightImages; // count of swapchain images + PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -123,7 +123,7 @@ PalBool descriptorIndexingTest() PalWindowHandleInfo winHandle = {0}; palGetWindowHandleInfo(window, &winHandle); - // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; palGetPlatformInfo(&platformInfo); @@ -245,12 +245,12 @@ PalBool descriptorIndexingTest() // create surface result = palCreateSurface( - device, - winHandle.nativeWindow, - winHandle.nativeInstance, - windowInstanceType, + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, &surface); - + if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create surface"); return PAL_FALSE; @@ -268,7 +268,7 @@ PalBool descriptorIndexingTest() if (!palCanQueuePresent(queue, surface)) { palDestroyQueue(queue); queue = nullptr; - } else { + } else { // found a queue foundQueue = PAL_TRUE; break; @@ -451,7 +451,7 @@ PalBool descriptorIndexingTest() imageCreateInfo.arrayLayerCount = 1; imageCreateInfo.depth = 1; imageCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; - imageCreateInfo.mipLevelCount = 1; // simple + imageCreateInfo.mipLevelCount = 1; // simple imageCreateInfo.sampleCount = PAL_SAMPLE_COUNT_1; // simple imageCreateInfo.type = PAL_IMAGE_TYPE_2D; imageCreateInfo.usages = PAL_IMAGE_USAGE_TRANSFER_DST | PAL_IMAGE_USAGE_SAMPLED; @@ -476,7 +476,7 @@ PalBool descriptorIndexingTest() PalImageStagingRequirements stagingReq = {0}; palComputeImageStagingRequirements( - device, + device, imageCreateInfo.format, &bufferImageCopyInfo, &stagingReq); @@ -490,7 +490,7 @@ PalBool descriptorIndexingTest() createFlatTexture(textureDatas[0], TEXTURE_WIDTH, TEXTURE_HEIGHT, 255, 0, 0); createFlatTexture(textureDatas[1], TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, 255, 0); createFlatTexture(textureDatas[2], TEXTURE_WIDTH, TEXTURE_HEIGHT, 0, 0, 255); - createFlatTexture(textureDatas[3], TEXTURE_WIDTH, TEXTURE_HEIGHT, 255, 255, 0); + createFlatTexture(textureDatas[3], TEXTURE_WIDTH, TEXTURE_HEIGHT, 255, 255, 0); PalBufferCreateInfo imageStagingBufferCreateInfo = {0}; imageStagingBufferCreateInfo.size = stagingReq.bufferSize; @@ -518,7 +518,7 @@ PalBool descriptorIndexingTest() &bufferImageCopyInfo, textureDatas[i], data); - + palUnmapBuffer(imageStagingBuffers[i]); } @@ -558,9 +558,9 @@ PalBool descriptorIndexingTest() palCmdImageBarrier(cmdBuffers[0], textures[i], &textureRange, &barrierInfo); palCmdCopyBufferToImage( - cmdBuffers[0], - textures[i], - imageStagingBuffers[i], + cmdBuffers[0], + textures[i], + imageStagingBuffers[i], &bufferImageCopyInfo); // transition the image to shader read state @@ -597,9 +597,9 @@ PalBool descriptorIndexingTest() for (int i = 0; i < 4; i++) { result = palCreateImageView( - device, - textures[i], - &checkerboardImageViewCreateInfo, + device, + textures[i], + &checkerboardImageViewCreateInfo, &textureViews[i]); if (result != PAL_RESULT_SUCCESS) { @@ -622,10 +622,7 @@ PalBool descriptorIndexingTest() samplerCreateInfo.minFilterMode = PAL_FILTER_MODE_LINEAR; samplerCreateInfo.maxAnisotropy = 1.0f; - result = palCreateSampler( - device, - &samplerCreateInfo, - &sampler); + result = palCreateSampler(device, &samplerCreateInfo, &sampler); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create sampler"); @@ -680,8 +677,8 @@ PalBool descriptorIndexingTest() readFile(sources[i], bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.code = bytecode; + shaderCreateInfo.codeSize = bytecodeSize; shaderCreateInfo.entries = &entries[i]; shaderCreateInfo.entryCount = 1; @@ -699,7 +696,7 @@ PalBool descriptorIndexingTest() PalDescriptorSetLayoutBinding descriptorBindings[2]; descriptorBindings[0].descriptorCount = 100; descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - + descriptorBindings[1].descriptorCount = 1; // not an array descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; @@ -712,10 +709,8 @@ PalBool descriptorIndexingTest() descriptorSetLayoutcreateInfo.flags |= PAL_DESCRIPTOR_INDEXING_FLAG_PARTIALLY_BOUND; } - result = palCreateDescriptorSetLayout( - device, - &descriptorSetLayoutcreateInfo, - &descriptorSetLayout); + result = + palCreateDescriptorSetLayout(device, &descriptorSetLayoutcreateInfo, &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create descriptor set layout"); @@ -764,7 +759,7 @@ PalBool descriptorIndexingTest() writeInfo.arrayElement = 0; writeInfo.samplerInfos = nullptr; writeInfo.imageViewInfos = nullptr; - writeInfo.tlasInfos = nullptr; + writeInfo.tlasInfos = nullptr; writeInfo.bufferInfos = nullptr; result = palUpdateDescriptorSet(device, 1, &writeInfo); @@ -790,7 +785,7 @@ PalBool descriptorIndexingTest() writeInfo.arrayElement = 0; writeInfo.samplerInfos = nullptr; writeInfo.imageViewInfos = imageViewInfos; - writeInfo.tlasInfos = nullptr; + writeInfo.tlasInfos = nullptr; writeInfo.bufferInfos = nullptr; result = palUpdateDescriptorSet(device, 1, &writeInfo); @@ -800,9 +795,8 @@ PalBool descriptorIndexingTest() } } - // we only write 4 descriptors - uint32_t arrElements[] = { ARRAY_ELEMENT_0, ARRAY_ELEMENT_1, ARRAY_ELEMENT_2, ARRAY_ELEMENT_3 }; + uint32_t arrElements[] = {ARRAY_ELEMENT_0, ARRAY_ELEMENT_1, ARRAY_ELEMENT_2, ARRAY_ELEMENT_3}; PalDescriptorImageViewInfo descriptorImageInfos[4]; descriptorImageInfos[0].imageView = textureViews[0]; @@ -823,7 +817,7 @@ PalBool descriptorIndexingTest() writeInfos[0].arrayElement = 0; writeInfos[0].imageViewInfos = nullptr; - writeInfos[0].tlasInfos = nullptr; + writeInfos[0].tlasInfos = nullptr; writeInfos[0].bufferInfos = nullptr; // textures @@ -837,7 +831,7 @@ PalBool descriptorIndexingTest() writeInfos[i + 1].arrayElement = arrElements[i]; writeInfos[i + 1].bufferInfos = nullptr; writeInfos[i + 1].samplerInfos = nullptr; - writeInfos[i + 1].tlasInfos = nullptr; + writeInfos[i + 1].tlasInfos = nullptr; } result = palUpdateDescriptorSet(device, 5, writeInfos); @@ -1064,7 +1058,7 @@ PalBool descriptorIndexingTest() palCmdBindDescriptorSet(cmdBuffers[currentFrame], 0, descriptorSet); palCmdSetViewport(cmdBuffers[currentFrame], 1, &viewport); palCmdSetScissors(cmdBuffers[currentFrame], 1, &scissor); - + uint64_t offset[] = {0}; palCmdBindVertexBuffers(cmdBuffers[currentFrame], 0, 1, &vertexBuffer, offset); palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); @@ -1125,7 +1119,7 @@ PalBool descriptorIndexingTest() for (int i = 0; i < imageCount; i++) { palDestroySemaphore(renderFinishedSemaphores[i]); - palDestroyImageView(imageViews[i]); + palDestroyImageView(imageViews[i]); } palDestroyDescriptorPool(descriptorPool); diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index 1b4dec86..fc0ecba3 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -1,7 +1,7 @@ #include "pal/pal_graphics.h" -#include "pal/pal_video.h" #include "pal/pal_system.h" +#include "pal/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 @@ -35,7 +35,7 @@ PalBool geometryTest() PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; PalSemaphore** renderFinishedSemaphores; // count of swapchain images - PalFence** inFlightImages; // count of swapchain images + PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -80,7 +80,7 @@ PalBool geometryTest() PalWindowHandleInfo winHandle = {0}; palGetWindowHandleInfo(window, &winHandle); - // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; palGetPlatformInfo(&platformInfo); @@ -194,12 +194,12 @@ PalBool geometryTest() // create surface result = palCreateSurface( - device, - winHandle.nativeWindow, - winHandle.nativeInstance, - windowInstanceType, + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, &surface); - + if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create surface"); return PAL_FALSE; @@ -217,7 +217,7 @@ PalBool geometryTest() if (!palCanQueuePresent(queue, surface)) { palDestroyQueue(queue); queue = nullptr; - } else { + } else { // found a queue foundQueue = PAL_TRUE; break; @@ -280,7 +280,7 @@ PalBool geometryTest() PalImageInfo imageInfo; palGetImageInfo(palGetSwapchainImage(swapchain, 0), &imageInfo); - + PalImageViewCreateInfo imageViewCreateInfo = {0}; imageViewCreateInfo.type = PAL_IMAGE_VIEW_TYPE_2D; imageViewCreateInfo.subresourceRange.layerArrayCount = 1; @@ -399,8 +399,8 @@ PalBool geometryTest() readFile(sources[i], bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.code = bytecode; + shaderCreateInfo.codeSize = bytecodeSize; shaderCreateInfo.entries = &entries[i]; shaderCreateInfo.entryCount = 1; @@ -644,7 +644,7 @@ PalBool geometryTest() for (int i = 0; i < imageCount; i++) { palDestroySemaphore(renderFinishedSemaphores[i]); - palDestroyImageView(imageViews[i]); + palDestroyImageView(imageViews[i]); } palDestroyCommandPool(cmdPool); diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 0aae1eec..7e5e871f 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -85,7 +85,7 @@ PalBool graphicsTest() } uint64_t vramMib = (uint64_t)info.vram / (1024 * 1024); - uint64_t sharedMemMib = (uint64_t)info.sharedMemory /(1024 * 1024); + uint64_t sharedMemMib = (uint64_t)info.sharedMemory / (1024 * 1024); palLog(nullptr, "GPU Name: %s", info.name); palLog(nullptr, " Backend Name: %s", info.backendName); @@ -119,6 +119,7 @@ PalBool graphicsTest() } palLog(nullptr, " Type: %s", typeString); + // we check for types that are core to PAL since we are not adding any custom backends const char* apiTypeString; switch (info.apiType) { case PAL_ADAPTER_API_TYPE_D3D12: { @@ -170,7 +171,7 @@ PalBool graphicsTest() palLog(nullptr, ""); palLog(nullptr, " Resource Capabilities:"); PalResourceCapabilities* resourceCaps = &caps.resourceCaps; - + // clang-format off palLog(nullptr, " Max per stage sampled images: %u", resourceCaps->maxPerStageSampledImages); palLog(nullptr, " Max per set sampled images: %u", resourceCaps->maxPerSetSampledImages); @@ -329,7 +330,6 @@ PalBool graphicsTest() if (palIsSupported(tmp.supportedShadingRates, PAL_FRAGMENT_SHADING_RATE_4X2)) { palLog(nullptr, " 4 X 2"); - } if (palIsSupported(tmp.supportedShadingRates, PAL_FRAGMENT_SHADING_RATE_4X4)) { diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 053c1b45..18e0443a 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -1,7 +1,7 @@ #include "pal/pal_graphics.h" -#include "pal/pal_video.h" #include "pal/pal_system.h" +#include "pal/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 @@ -42,7 +42,7 @@ PalBool indirectDrawTest() PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; PalSemaphore** renderFinishedSemaphores; // count of swapchain images - PalFence** inFlightImages; // count of swapchain images + PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -92,7 +92,7 @@ PalBool indirectDrawTest() PalWindowHandleInfo winHandle = {0}; palGetWindowHandleInfo(window, &winHandle); - // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; palGetPlatformInfo(&platformInfo); @@ -206,12 +206,12 @@ PalBool indirectDrawTest() // create surface result = palCreateSurface( - device, - winHandle.nativeWindow, - winHandle.nativeInstance, - windowInstanceType, + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, &surface); - + if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create surface"); return PAL_FALSE; @@ -229,7 +229,7 @@ PalBool indirectDrawTest() if (!palCanQueuePresent(queue, surface)) { palDestroyQueue(queue); queue = nullptr; - } else { + } else { // found a queue foundQueue = PAL_TRUE; break; @@ -367,7 +367,7 @@ PalBool indirectDrawTest() }; // clang-format on - uint32_t indices[6] = { 0, 1, 2, 2, 3, 0 }; + uint32_t indices[6] = {0, 1, 2, 2, 3, 0}; // vertex buffer PalBufferCreateInfo bufferCreateInfo = {0}; @@ -567,8 +567,8 @@ PalBool indirectDrawTest() readFile(sources[i], bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.code = bytecode; + shaderCreateInfo.codeSize = bytecodeSize; shaderCreateInfo.entries = &entries[i]; shaderCreateInfo.entryCount = 1; @@ -580,7 +580,7 @@ PalBool indirectDrawTest() palFree(nullptr, bytecode); } - + // create pipeline layout PalPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {0}; result = palCreatePipelineLayout(device, &pipelineLayoutCreateInfo, &pipelineLayout); @@ -798,7 +798,7 @@ PalBool indirectDrawTest() barrierInfo.newState = PAL_USAGE_STATE_PRESENT; barrierInfo.dstStages = PAL_PIPELINE_STAGE_NONE; palCmdImageBarrier(cmdBuffers[currentFrame], image, &imageRange, &barrierInfo); - + result = palCmdEnd(cmdBuffers[currentFrame]); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to end command buffer"); @@ -846,7 +846,7 @@ PalBool indirectDrawTest() for (int i = 0; i < imageCount; i++) { palDestroySemaphore(renderFinishedSemaphores[i]); - palDestroyImageView(imageViews[i]); + palDestroyImageView(imageViews[i]); } palDestroyBuffer(indirectBuffer); diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 6a09e5b9..8901fca7 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -1,7 +1,7 @@ #include "pal/pal_graphics.h" -#include "pal/pal_video.h" #include "pal/pal_system.h" +#include "pal/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 @@ -35,7 +35,7 @@ PalBool meshTest() PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; PalSemaphore** renderFinishedSemaphores; // count of swapchain images - PalFence** inFlightImages; // count of swapchain images + PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -80,7 +80,7 @@ PalBool meshTest() PalWindowHandleInfo winHandle = {0}; palGetWindowHandleInfo(window, &winHandle); - // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; palGetPlatformInfo(&platformInfo); @@ -152,7 +152,7 @@ PalBool meshTest() // We want an adapter that supports spirv 1.5 or dxil 6.5 palGetAdapterInfo(adapter, &adapterInfo); - + // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { @@ -194,12 +194,12 @@ PalBool meshTest() // create surface result = palCreateSurface( - device, - winHandle.nativeWindow, - winHandle.nativeInstance, - windowInstanceType, + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, &surface); - + if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create surface"); return PAL_FALSE; @@ -217,7 +217,7 @@ PalBool meshTest() if (!palCanQueuePresent(queue, surface)) { palDestroyQueue(queue); queue = nullptr; - } else { + } else { // found a queue foundQueue = PAL_TRUE; break; @@ -393,8 +393,8 @@ PalBool meshTest() readFile(sources[i], bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.code = bytecode; + shaderCreateInfo.codeSize = bytecodeSize; shaderCreateInfo.entries = &entries[i]; shaderCreateInfo.entryCount = 1; @@ -643,7 +643,7 @@ PalBool meshTest() for (int i = 0; i < imageCount; i++) { palDestroySemaphore(renderFinishedSemaphores[i]); - palDestroyImageView(imageViews[i]); + palDestroyImageView(imageViews[i]); } palDestroyCommandPool(cmdPool); diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index f1819f94..2339a680 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -152,11 +152,7 @@ PalBool multiDescriptorSetTest() return PAL_FALSE; } - result = palAllocateCommandBuffer( - device, - cmdPool, - PAL_COMMAND_BUFFER_TYPE_PRIMARY, - &cmdBuffer); + result = palAllocateCommandBuffer(device, cmdPool, PAL_COMMAND_BUFFER_TYPE_PRIMARY, &cmdBuffer); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to allocate command buffer"); @@ -194,8 +190,8 @@ PalBool multiDescriptorSetTest() computeEntry.entryName = "main"; computeEntry.stage = PAL_SHADER_STAGE_COMPUTE; - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.code = bytecode; + shaderCreateInfo.codeSize = bytecodeSize; shaderCreateInfo.entries = &computeEntry; shaderCreateInfo.entryCount = 1; @@ -239,10 +235,8 @@ PalBool multiDescriptorSetTest() descriptorSetLayoutcreateInfo.bindingCount = 1; descriptorSetLayoutcreateInfo.bindings = &descriptorBinding; - result = palCreateDescriptorSetLayout( - device, - &descriptorSetLayoutcreateInfo, - &descriptorSetLayout); + result = + palCreateDescriptorSetLayout(device, &descriptorSetLayoutcreateInfo, &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create descriptor set layout"); @@ -268,9 +262,9 @@ PalBool multiDescriptorSetTest() // allocate the sets from the descriptor pool for (int i = 0; i < 3; i++) { result = palAllocateDescriptorSet( - device, - descriptorPool, - descriptorSetLayout, + device, + descriptorPool, + descriptorSetLayout, &descriptorSets[i]); if (result != PAL_RESULT_SUCCESS) { @@ -288,7 +282,7 @@ PalBool multiDescriptorSetTest() descriptorBufferInfos[i].stride = 16; // sizeof(vec4) or float4. } - PalDescriptorSetWriteInfo writeInfos[3]; + PalDescriptorSetWriteInfo writeInfos[3]; for (int i = 0; i < 3; i++) { writeInfos[i].layoutBindingIndex = 0; // single descriptor binding writeInfos[i].bufferInfos = &descriptorBufferInfos[i]; @@ -394,7 +388,7 @@ PalBool multiDescriptorSetTest() buildData.workGroupSize[0] = 16; // must match shader (local_size on glsl) buildData.workGroupSize[1] = 16; // must match shader (local_size on glsl) - buildData.workGroupSize[2] = 1; // must match shader (local_size on glsl) + buildData.workGroupSize[2] = 1; // must match shader (local_size on glsl) // device limits buildData.workGroupCount[0] = caps.computeCaps.maxWorkGroupCount[0]; @@ -450,7 +444,7 @@ PalBool multiDescriptorSetTest() submitInfo.cmdBuffer = cmdBuffer; submitInfo.fence = fence; submitInfo.waitStages = PAL_PIPELINE_STAGE_TRANSFER; - + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); @@ -489,9 +483,9 @@ PalBool multiDescriptorSetTest() int index = row * BUFFER_SIZE + x; uint8_t rgb[3]; - rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; - rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; - rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255: 0; + rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255 : 0; + rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255 : 0; + rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255 : 0; fwrite(rgb, 1, 3, file); } } diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index db088fbc..9d39d2ea 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -107,7 +107,7 @@ PalBool rayTracingTest() adapter = nullptr; continue; } - + // We want an adapter that supports spirv 1.4 or dxil 6.3 palGetAdapterInfo(adapter, &adapterInfo); @@ -159,11 +159,7 @@ PalBool rayTracingTest() return PAL_FALSE; } - result = palAllocateCommandBuffer( - device, - cmdPool, - PAL_COMMAND_BUFFER_TYPE_PRIMARY, - &cmdBuffer); + result = palAllocateCommandBuffer(device, cmdPool, PAL_COMMAND_BUFFER_TYPE_PRIMARY, &cmdBuffer); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to allocate command buffer"); @@ -210,8 +206,8 @@ PalBool rayTracingTest() readFile(source, bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.code = bytecode; + shaderCreateInfo.codeSize = bytecodeSize; shaderCreateInfo.entries = entries; shaderCreateInfo.entryCount = 3; @@ -246,10 +242,7 @@ PalBool rayTracingTest() } // create a vertex buffer to store the vertices in - float vertices[] = { - 0.0f, 1.0f, - 1.0f, -1.0f, - -1.0f, -1.0f}; + float vertices[] = {0.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f}; bufferCreateInfo.size = sizeof(vertices); bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_READ_ONLY_INPUT; @@ -327,11 +320,7 @@ PalBool rayTracingTest() asInstance.mask = 0xFF; asInstance.hitGroupOffset = 0; // we only have 1 hitGroup - float transform[12] = { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f - }; + float transform[12] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; memcpy(asInstance.transform, transform, sizeof(float) * 12); uint64_t instanceBufferSize = 0; @@ -350,11 +339,7 @@ PalBool rayTracingTest() // copy instance struct to the buffer data = nullptr; - result = palMapBuffer( - instanceBuffer, - 0, - instanceBufferSize, - &data); + result = palMapBuffer(instanceBuffer, 0, instanceBufferSize, &data); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to map buffer"); @@ -377,7 +362,7 @@ PalBool rayTracingTest() // get the build sizes for tlas uint32_t blasScratchSize = buildSizes.scratchBufferSize; palGetAccelerationStructureBuildSize(device, &tlasBuildInfo, &buildSizes); - + // create the tlas buffer and tlas bufferCreateInfo.size = buildSizes.accelerationStructureSize; bufferCreateInfo.usages = PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE; @@ -424,10 +409,8 @@ PalBool rayTracingTest() descriptorSetLayoutcreateInfo.bindingCount = 2; descriptorSetLayoutcreateInfo.bindings = descriptorBindings; - result = palCreateDescriptorSetLayout( - device, - &descriptorSetLayoutcreateInfo, - &descriptorSetLayout); + result = + palCreateDescriptorSetLayout(device, &descriptorSetLayoutcreateInfo, &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create descriptor set layout"); @@ -444,7 +427,7 @@ PalBool rayTracingTest() PalDescriptorPoolCreateInfo descriptorPoolCreateInfo = {0}; descriptorPoolCreateInfo.maxDescriptorSets = 1; // only one set - descriptorPoolCreateInfo.bindingSizeCount = 2; // two binding type + descriptorPoolCreateInfo.bindingSizeCount = 2; // two binding type descriptorPoolCreateInfo.bindingSizes = bindingSizes; result = palCreateDescriptorPool(device, &descriptorPoolCreateInfo, &descriptorPool); @@ -547,7 +530,7 @@ PalBool rayTracingTest() pipelineCreateInfo.shaderCount = 1; pipelineCreateInfo.shaderGroupCount = 3; pipelineCreateInfo.shaderGroups = shaderGroupCreateInfos; - pipelineCreateInfo.shaders = &rayTracingShader; + pipelineCreateInfo.shaders = &rayTracingShader; result = palCreateRayTracingPipeline(device, &pipelineCreateInfo, &pipeline); if (result != PAL_RESULT_SUCCESS) { @@ -563,7 +546,7 @@ PalBool rayTracingTest() missLocalData.color[0] = 0.0f; missLocalData.color[1] = 0.0f; missLocalData.color[2] = 0.0f; - + LocalData closestLocalData; // green color for miss closestLocalData.color[0] = 0.0f; closestLocalData.color[1] = 1.0f; @@ -613,7 +596,7 @@ PalBool rayTracingTest() palCmdBindPipeline(cmdBuffer, pipeline); palCmdBindDescriptorSet(cmdBuffer, 0, descriptorSet); - + // build the blas and tlas infos PalDeviceAddress scratchBufferAddress = palGetBufferDeviceAddress(scratchBuffer); blasBuildInfo.dst = blas; @@ -646,7 +629,7 @@ PalBool rayTracingTest() barrierInfo.srcStages = PAL_PIPELINE_STAGE_RAY_TRACING_SHADER; barrierInfo.dstStages = PAL_PIPELINE_STAGE_TRANSFER; palCmdBufferBarrier(cmdBuffer, buffer, &barrierInfo); - + // now we copy from the GPU buffer into the staging buffer PalBufferCopyInfo copyInfo = {0}; copyInfo.size = bufferBytes; @@ -663,7 +646,7 @@ PalBool rayTracingTest() submitInfo.cmdBuffer = cmdBuffer; submitInfo.fence = fence; submitInfo.waitStages = PAL_PIPELINE_STAGE_RAY_TRACING_SHADER; - + result = palSubmitCommandBuffer(queue, &submitInfo); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to submit command buffer"); @@ -696,9 +679,9 @@ PalBool rayTracingTest() int index = row * BUFFER_SIZE + x; uint8_t rgb[3]; - rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; - rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; - rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255: 0; + rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255 : 0; + rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255 : 0; + rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255 : 0; fwrite(rgb, 1, 3, file); } } @@ -706,7 +689,7 @@ PalBool rayTracingTest() // update sbt and trace again // since we still have the record array we used to create the pipeline // we just change the underlying data and update the record - + // change miss from black to white missLocalData.color[0] = 1.0f; missLocalData.color[1] = 1.0f; @@ -798,9 +781,9 @@ PalBool rayTracingTest() int index = row * BUFFER_SIZE + x; uint8_t rgb[3]; - rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255: 0; - rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255: 0; - rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255: 0; + rgb[0] = pixels[index * 4 + 0] > 0.5f ? 255 : 0; + rgb[1] = pixels[index * 4 + 1] > 0.5f ? 255 : 0; + rgb[2] = pixels[index * 4 + 2] > 0.5f ? 255 : 0; fwrite(rgb, 1, 3, file); } } diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index e64d0b04..39e94295 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -1,7 +1,7 @@ #include "pal/pal_graphics.h" -#include "pal/pal_video.h" #include "pal/pal_system.h" +#include "pal/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 @@ -65,7 +65,7 @@ PalBool textureTest() PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; PalSemaphore** renderFinishedSemaphores; // count of swapchain images - PalFence** inFlightImages; // count of swapchain images + PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -117,7 +117,7 @@ PalBool textureTest() PalWindowHandleInfo winHandle = {0}; palGetWindowHandleInfo(window, &winHandle); - // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; palGetPlatformInfo(&platformInfo); @@ -182,7 +182,7 @@ PalBool textureTest() // We want an adapter that supports spirv 1.0 or dxil 6.0 palGetAdapterInfo(adapter, &adapterInfo); - + // we prefer spirv first if an adapter supports multiple shader formats uint32_t target = 0; if (adapterInfo.shaderFormats & PAL_SHADER_FORMAT_SPIRV) { @@ -224,12 +224,12 @@ PalBool textureTest() // create surface result = palCreateSurface( - device, - winHandle.nativeWindow, - winHandle.nativeInstance, - windowInstanceType, + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, &surface); - + if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create surface"); return PAL_FALSE; @@ -247,7 +247,7 @@ PalBool textureTest() if (!palCanQueuePresent(queue, surface)) { palDestroyQueue(queue); queue = nullptr; - } else { + } else { // found a queue foundQueue = PAL_TRUE; break; @@ -425,7 +425,7 @@ PalBool textureTest() return PAL_FALSE; } - // we dont want to load the texture from disk so we will create a + // we dont want to load the texture from disk so we will create a // checkerboard texture and use that rather uint32_t texture[TEXTURE_WIDTH * TEXTURE_HEIGHT]; memset(texture, 0, TEXTURE_WIDTH * TEXTURE_HEIGHT); @@ -437,7 +437,7 @@ PalBool textureTest() imageCreateInfo.arrayLayerCount = 1; imageCreateInfo.depth = 1; imageCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; - imageCreateInfo.mipLevelCount = 1; // simple + imageCreateInfo.mipLevelCount = 1; // simple imageCreateInfo.sampleCount = PAL_SAMPLE_COUNT_1; // simple imageCreateInfo.type = PAL_IMAGE_TYPE_2D; imageCreateInfo.usages = PAL_IMAGE_USAGE_TRANSFER_DST | PAL_IMAGE_USAGE_SAMPLED; @@ -460,7 +460,7 @@ PalBool textureTest() PalImageStagingRequirements stagingReq = {0}; palComputeImageStagingRequirements( - device, + device, imageCreateInfo.format, &bufferImageCopyInfo, &stagingReq); @@ -484,23 +484,14 @@ PalBool textureTest() // copy data void* data = nullptr; - result = palMapBuffer( - imageStagingBuffer, - 0, - imageStagingBufferCreateInfo.size, - &data); + result = palMapBuffer(imageStagingBuffer, 0, imageStagingBufferCreateInfo.size, &data); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to map buffer"); return PAL_FALSE; } - palWriteImageStaging( - device, - imageCreateInfo.format, - &bufferImageCopyInfo, - texture, - data); + palWriteImageStaging(device, imageCreateInfo.format, &bufferImageCopyInfo, texture, data); palUnmapBuffer(imageStagingBuffer); @@ -540,11 +531,7 @@ PalBool textureTest() checkerboardRange.layerArrayCount = 1; palCmdImageBarrier(cmdBuffers[0], checkerboard, &checkerboardRange, &barrierInfo); - palCmdCopyBufferToImage( - cmdBuffers[0], - checkerboard, - imageStagingBuffer, - &bufferImageCopyInfo); + palCmdCopyBufferToImage(cmdBuffers[0], checkerboard, imageStagingBuffer, &bufferImageCopyInfo); // transition the image to shader read state barrierInfo.oldState = PAL_USAGE_STATE_TRANSFER_WRITE; @@ -579,9 +566,9 @@ PalBool textureTest() checkerboardImageViewCreateInfo.format = PAL_FORMAT_R8G8B8A8_UNORM; result = palCreateImageView( - device, - checkerboard, - &checkerboardImageViewCreateInfo, + device, + checkerboard, + &checkerboardImageViewCreateInfo, &checkerboardImageView); if (result != PAL_RESULT_SUCCESS) { @@ -603,10 +590,7 @@ PalBool textureTest() samplerCreateInfo.minFilterMode = PAL_FILTER_MODE_LINEAR; samplerCreateInfo.maxAnisotropy = 1.0f; - result = palCreateSampler( - device, - &samplerCreateInfo, - &sampler); + result = palCreateSampler(device, &samplerCreateInfo, &sampler); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create sampler"); @@ -661,8 +645,8 @@ PalBool textureTest() readFile(sources[i], bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.code = bytecode; + shaderCreateInfo.codeSize = bytecodeSize; shaderCreateInfo.entries = &entries[i]; shaderCreateInfo.entryCount = 1; @@ -679,7 +663,7 @@ PalBool textureTest() PalDescriptorSetLayoutBinding descriptorBindings[2]; descriptorBindings[0].descriptorCount = 1; // not an array descriptorBindings[0].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE; - + descriptorBindings[1].descriptorCount = 1; // not an array descriptorBindings[1].descriptorType = PAL_DESCRIPTOR_TYPE_SAMPLER; @@ -687,10 +671,8 @@ PalBool textureTest() descriptorSetLayoutcreateInfo.bindingCount = 2; descriptorSetLayoutcreateInfo.bindings = descriptorBindings; - result = palCreateDescriptorSetLayout( - device, - &descriptorSetLayoutcreateInfo, - &descriptorSetLayout); + result = + palCreateDescriptorSetLayout(device, &descriptorSetLayoutcreateInfo, &descriptorSetLayout); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to create descriptor set layout"); @@ -741,7 +723,7 @@ PalBool textureTest() writeInfos[0].arrayElement = 0; writeInfos[0].bufferInfos = nullptr; writeInfos[0].samplerInfos = nullptr; - writeInfos[0].tlasInfos = nullptr; + writeInfos[0].tlasInfos = nullptr; writeInfos[1].layoutBindingIndex = 1; writeInfos[1].samplerInfos = &descriptorSamplerInfo; @@ -751,7 +733,7 @@ PalBool textureTest() writeInfos[1].arrayElement = 0; writeInfos[1].imageViewInfos = nullptr; - writeInfos[1].tlasInfos = nullptr; + writeInfos[1].tlasInfos = nullptr; writeInfos[1].bufferInfos = nullptr; result = palUpdateDescriptorSet(device, 2, writeInfos); @@ -974,7 +956,7 @@ PalBool textureTest() palCmdBindVertexBuffers(cmdBuffers[currentFrame], 0, 1, &vertexBuffer, offset); palCmdDraw(cmdBuffers[currentFrame], 6, 1, 0, 0); palCmdEndRendering(cmdBuffers[currentFrame]); - + // change the state of the image view to make it presentable barrierInfo.oldState = PAL_USAGE_STATE_COLOR_ATTACHMENT_WRITE; barrierInfo.srcStages = PAL_PIPELINE_STAGE_COLOR_ATTACHMENT; @@ -1029,7 +1011,7 @@ PalBool textureTest() for (int i = 0; i < imageCount; i++) { palDestroySemaphore(renderFinishedSemaphores[i]); - palDestroyImageView(imageViews[i]); + palDestroyImageView(imageViews[i]); } palDestroyDescriptorPool(descriptorPool); diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index c62338f6..81a07f11 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -1,7 +1,7 @@ #include "pal/pal_graphics.h" -#include "pal/pal_video.h" #include "pal/pal_system.h" +#include "pal/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 @@ -35,7 +35,7 @@ PalBool triangleTest() PalSemaphore* imageAvailableSemaphores[MAX_FRAMES_IN_FLIGHT]; PalFence* inFlightFences[MAX_FRAMES_IN_FLIGHT]; PalSemaphore** renderFinishedSemaphores; // count of swapchain images - PalFence** inFlightImages; // count of swapchain images + PalFence** inFlightImages; // count of swapchain images PalPipelineLayout* pipelineLayout = nullptr; PalPipeline* pipeline = nullptr; @@ -83,7 +83,7 @@ PalBool triangleTest() PalWindowHandleInfo winHandle = {0}; palGetWindowHandleInfo(window, &winHandle); - // using pal_system.h will be easy to know the underlying windowing API or use typedefs. + // using pal_system.h will be easy to know the underlying windowing API or use typedefs. // We will use the pal_system module. PalPlatformInfo platformInfo = {0}; palGetPlatformInfo(&platformInfo); @@ -190,10 +190,10 @@ PalBool triangleTest() // create surface result = palCreateSurface( - device, - winHandle.nativeWindow, - winHandle.nativeInstance, - windowInstanceType, + device, + winHandle.nativeWindow, + winHandle.nativeInstance, + windowInstanceType, &surface); if (result != PAL_RESULT_SUCCESS) { @@ -213,7 +213,7 @@ PalBool triangleTest() if (!palCanQueuePresent(queue, surface)) { palDestroyQueue(queue); queue = nullptr; - } else { + } else { // found a queue foundQueue = PAL_TRUE; break; @@ -474,8 +474,8 @@ PalBool triangleTest() readFile(sources[i], bytecode, &bytecodeSize); - shaderCreateInfo.bytecode = bytecode; - shaderCreateInfo.bytecodeSize = bytecodeSize; + shaderCreateInfo.code = bytecode; + shaderCreateInfo.codeSize = bytecodeSize; shaderCreateInfo.entries = &entries[i]; shaderCreateInfo.entryCount = 1; @@ -752,7 +752,7 @@ PalBool triangleTest() for (int i = 0; i < imageCount; i++) { palDestroySemaphore(renderFinishedSemaphores[i]); - palDestroyImageView(imageViews[i]); + palDestroyImageView(imageViews[i]); } palDestroyBuffer(vertexBuffer); @@ -762,7 +762,7 @@ PalBool triangleTest() palDestroyQueue(queue); palDestroyDevice(device); palShutdownGraphics(); - + palFree(nullptr, imageViews); palFree(nullptr, renderFinishedSemaphores); palFree(nullptr, inFlightImages); diff --git a/tests/opengl/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c index ed072fd2..d363611c 100644 --- a/tests/opengl/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -67,24 +67,24 @@ static void* PAL_CALL eventDriverWorker(void* arg) // set dispatch modes. opengl needs only window resize palSetEventDispatchMode( - shared->openglEventDriver, - PAL_EVENT_TYPE_WINDOW_SIZE, + shared->openglEventDriver, + PAL_EVENT_TYPE_WINDOW_SIZE, PAL_DISPATCH_MODE_POLL); // video needs window close and resize palSetEventDispatchMode( - shared->videoEventDriver, - PAL_EVENT_TYPE_WINDOW_CLOSE, + shared->videoEventDriver, + PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); palSetEventDispatchMode( - shared->videoEventDriver, - PAL_EVENT_TYPE_WINDOW_SIZE, + shared->videoEventDriver, + PAL_EVENT_TYPE_WINDOW_SIZE, PAL_DISPATCH_MODE_POLL); palSetEventDispatchMode( - shared->videoEventDriver, - PAL_EVENT_TYPE_KEYDOWN, + shared->videoEventDriver, + PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // we are done @@ -141,7 +141,11 @@ static void* PAL_CALL rendererWorkder(void* arg) case PAL_EVENT_TYPE_WINDOW_SIZE: { uint32_t width, height; palUnpackUint32(event.data, &width, &height); - palLog(nullptr, "Video event driver sent a resize event (%d, %d)", width, height); + palLog( + nullptr, + "Video event driver sent a resize event (%d, %d)", + width, + height); glViewport(0, 0, width, height); // we can optionally send back a user event @@ -295,7 +299,6 @@ PalBool multiThreadOpenGlTest() const PalGLFBConfig* closest = nullptr; closest = palGetClosestGLFBConfig(fbConfigs, fbCount, &desired); - // all windows also needs to be created on the main thread PalWindowCreateInfo windowCreateInfo = {0}; windowCreateInfo.width = 640; diff --git a/tests/opengl/opengl_context_test.c b/tests/opengl/opengl_context_test.c index 7dd9832e..6413caf8 100644 --- a/tests/opengl/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -17,7 +17,7 @@ typedef void(PAL_GL_APIENTRY* PFNGLCLEARPROC)(uint32_t mask); // use GL typedefs PalBool openglContextTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - + // fill the event driver create info PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator @@ -65,7 +65,7 @@ PalBool openglContextTest() logResult(result, "Failed to initialize opengl"); return PAL_FALSE; } - + // enumerate supported opengl framebuffer configs int32_t fbCount = 0; result = palEnumerateGLFBConfigs(&fbCount, nullptr); @@ -167,7 +167,7 @@ PalBool openglContextTest() // If pal video system will not be used, there is no need to initialize it PalWindowHandleInfo winHandle = {0}; palGetWindowHandleInfo(window, &winHandle); - + // PalGLWindow is just a struct to hold native handles PalGLWindow glWindow = {0}; glWindow.instance = winHandle.nativeInstance; @@ -186,11 +186,11 @@ PalBool openglContextTest() // fill the context create info with the closest FBConfig PalGLContextCreateInfo contextCreateInfo = {0}; - contextCreateInfo.debug = PAL_TRUE; // debug context + contextCreateInfo.debug = PAL_TRUE; // debug context contextCreateInfo.fbConfig = closest; // we use the closest to what we want contextCreateInfo.major = info->major; // context major contextCreateInfo.minor = info->minor; // context minor - contextCreateInfo.noError = PAL_FALSE; // check PAL_GL_EXTENSION_NO_ERROR + contextCreateInfo.noError = PAL_FALSE; // check PAL_GL_EXTENSION_NO_ERROR // check PAL_GL_EXTENSION_FLUSH_CONTROL contextCreateInfo.release = PAL_GL_RELEASE_BEHAVIOR_NONE; diff --git a/tests/opengl/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c index 59048148..f69b6b9d 100644 --- a/tests/opengl/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -65,7 +65,7 @@ PalBool openglMultiContextTest() logResult(result, "Failed to initialize opengl"); return PAL_FALSE; } - + // enumerate supported opengl framebuffer configs int32_t fbCount = 0; result = palEnumerateGLFBConfigs(&fbCount, nullptr); @@ -149,7 +149,7 @@ PalBool openglMultiContextTest() // because we are using both pal_video and pal_opengl createInfo.fbConfigBackend = PAL_FBCONFIG_BACKEND_PAL_OPENGL; createInfo.fbConfigIndex = closest->index; - + // create the window with the create info struct PalWindow* window = nullptr; result = palCreateWindow(&createInfo, &window); @@ -186,11 +186,11 @@ PalBool openglMultiContextTest() // fill the context create info with the closest FBConfig PalGLContextCreateInfo contextCreateInfo = {0}; - contextCreateInfo.debug = PAL_TRUE; // debug context + contextCreateInfo.debug = PAL_TRUE; // debug context contextCreateInfo.fbConfig = closest; // we use the closest to what we want contextCreateInfo.major = info->major; // context major contextCreateInfo.minor = info->minor; // context minor - contextCreateInfo.noError = PAL_FALSE; // check PAL_GL_EXTENSION_NO_ERROR + contextCreateInfo.noError = PAL_FALSE; // check PAL_GL_EXTENSION_NO_ERROR // check PAL_GL_EXTENSION_FLUSH_CONTROL contextCreateInfo.release = PAL_GL_RELEASE_BEHAVIOR_NONE; diff --git a/tests/system/cpu_test.c b/tests/system/cpu_test.c index 64313a7e..96c1915b 100644 --- a/tests/system/cpu_test.c +++ b/tests/system/cpu_test.c @@ -1,6 +1,6 @@ -#include "tests.h" #include "pal/pal_system.h" +#include "tests.h" #include // for strcat static inline const char* cpuArchToString(PalCpuArch arch) diff --git a/tests/system/platform_test.c b/tests/system/platform_test.c index a0813e13..917d20b2 100644 --- a/tests/system/platform_test.c +++ b/tests/system/platform_test.c @@ -1,6 +1,6 @@ -#include "tests.h" #include "pal/pal_system.h" +#include "tests.h" static inline const char* platformToString(PalPlatformType type) { @@ -45,7 +45,7 @@ PalBool platformTest() // get the platform info. Users must cache this palGetPlatformInfo(&platformInfo); - + palLog(nullptr, "Platform: %s", platformToString(platformInfo.type)); palLog(nullptr, " Name: %s", platformInfo.name); palLog(nullptr, " API: %s", platformApiToString(platformInfo.apiType)); diff --git a/tests/tests.c b/tests/tests.c index ac78f63d..ccf263f5 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -13,9 +13,11 @@ static TestEntry s_Test[MAX_TESTS]; static const char* s_FailedString = "FAILED"; static const char* s_PassedString = "PASSED"; -void registerTest(TestFn func, const char* name) +void registerTest( + TestFn func, + const char* name) { - TestEntry entry = { func, name }; + TestEntry entry = {func, name}; s_Test[s_Count++] = entry; } diff --git a/tests/tests_main.c b/tests/tests_main.c index ca3fadf6..3b22546d 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -56,11 +56,11 @@ int main(int argc, char** argv) #endif #if PAL_HAS_GRAPHICS_MODULE == 1 - // registerTest(graphicsTest, "Graphics Test"); + registerTest(graphicsTest, "Graphics Test"); // registerTest(computeTest, "Compute Test"); // registerTest(rayTracingTest, "Ray Tracing Test"); // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); - registerTest(customBackendTest, "Custom Backend Test"); + // registerTest(customBackendTest, "Custom Backend Test"); #endif // PAL_HAS_GRAPHICS_MODULE #if PAL_HAS_GRAPHICS_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 && PAL_HAS_SYSTEM_MODULE == 1 diff --git a/tests/thread/condvar_test.c b/tests/thread/condvar_test.c index 319e29ae..167878fe 100644 --- a/tests/thread/condvar_test.c +++ b/tests/thread/condvar_test.c @@ -1,6 +1,6 @@ -#include "tests.h" #include "pal/pal_thread.h" +#include "tests.h" #define THREAD_COUNT 4 diff --git a/tests/thread/mutex_test.c b/tests/thread/mutex_test.c index e1b06b50..48c282f0 100644 --- a/tests/thread/mutex_test.c +++ b/tests/thread/mutex_test.c @@ -1,6 +1,6 @@ -#include "tests.h" #include "pal/pal_thread.h" +#include "tests.h" #define MAX_COUNTER 10000 #define THREAD_COUNT 2 diff --git a/tests/thread/thread_test.c b/tests/thread/thread_test.c index 1e14a35c..5ef63d2a 100644 --- a/tests/thread/thread_test.c +++ b/tests/thread/thread_test.c @@ -1,6 +1,6 @@ -#include "tests.h" #include "pal/pal_thread.h" +#include "tests.h" #define THREAD_TIME 1000 #define THREAD_COUNT 4 diff --git a/tests/thread/tls_test.c b/tests/thread/tls_test.c index 70921c22..206b0c53 100644 --- a/tests/thread/tls_test.c +++ b/tests/thread/tls_test.c @@ -1,6 +1,6 @@ -#include "tests.h" #include "pal/pal_thread.h" +#include "tests.h" // data every thread will have its own copy of typedef struct { diff --git a/tests/video/attach_window_test.c b/tests/video/attach_window_test.c index 3a141838..ad0ed578 100644 --- a/tests/video/attach_window_test.c +++ b/tests/video/attach_window_test.c @@ -209,7 +209,7 @@ PalBool attachWindowTest() { palLog(nullptr, "Press A to attach and D to detach window"); palLog(nullptr, "Press Escape or click close button to close Test"); - + // fill the event driver create info PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator diff --git a/tests/video/cursor_test.c b/tests/video/cursor_test.c index 6b887a54..2cde06da 100644 --- a/tests/video/cursor_test.c +++ b/tests/video/cursor_test.c @@ -75,7 +75,7 @@ PalBool cursorTest() logResult(result, "Failed to create window cursor"); return PAL_FALSE; } - + // fill the create info struct PalWindowCreateInfo createInfo = {0}; createInfo.monitor = nullptr; // use default monitor diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index c9080d1d..31415d8c 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -866,14 +866,23 @@ PalBool customDecorationTest() } palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_CLOSE, PAL_DISPATCH_MODE_POLL); - palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_DECORATION_MODE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_TYPE_WINDOW_DECORATION_MODE, + PAL_DISPATCH_MODE_POLL); palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_KEYDOWN, PAL_DISPATCH_MODE_POLL); // we use PAL_DISPATCH_MODE_CALLBACK for the mouse button to get // real time events which we then use for moving and resizing - palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_MOUSE_BUTTONDOWN, PAL_DISPATCH_MODE_CALLBACK); + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_TYPE_MOUSE_BUTTONDOWN, + PAL_DISPATCH_MODE_CALLBACK); palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_MOUSE_MOVE, PAL_DISPATCH_MODE_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_MONITOR_DPI_CHANGED, PAL_DISPATCH_MODE_CALLBACK); + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_TYPE_MONITOR_DPI_CHANGED, + PAL_DISPATCH_MODE_CALLBACK); // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must @@ -955,7 +964,7 @@ PalBool customDecorationTest() return PAL_TRUE; -#else +#else palLog(nullptr, "Custom decoration not supported"); return PAL_FALSE; #endif // __linux__ diff --git a/tests/video/native_instance_test.c b/tests/video/native_instance_test.c index b6b55e9b..18c0daf3 100644 --- a/tests/video/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -309,7 +309,7 @@ void closeInstance(void* instance) PalBool nativeInstanceTest() { palLog(nullptr, "Press Escape or click close button to close Test"); - + // fill the event driver create info PalEventDriverCreateInfo eventDriverCreateInfo = {0}; eventDriverCreateInfo.allocator = nullptr; // default allocator diff --git a/tests/video/native_integration_test.c b/tests/video/native_integration_test.c index dc3e4327..ea8b7cfb 100644 --- a/tests/video/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -387,7 +387,7 @@ PalBool nativeIntegrationTest() if (features & PAL_VIDEO_FEATURE_WINDOW_SET_TITLE) { palSetWindowTitle(window, "Hello from PAL API"); } - + palLog(nullptr, "Getting window title with native API"); getWindowTitle(&windowInfo); palLog(nullptr, "Window title: %s", s_TitleBuffer); diff --git a/tests/video/window_test.c b/tests/video/window_test.c index d7cdaa30..e8f99408 100644 --- a/tests/video/window_test.c +++ b/tests/video/window_test.c @@ -179,9 +179,18 @@ PalBool windowTest() // we set callback mode for modal begin and end. Since we want to capture // that instantly - palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_MODAL_BEGIN, PAL_DISPATCH_MODE_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_MODAL_END, PAL_DISPATCH_MODE_CALLBACK); - palSetEventDispatchMode(eventDriver, PAL_EVENT_TYPE_WINDOW_DECORATION_MODE, PAL_DISPATCH_MODE_POLL); + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_TYPE_WINDOW_MODAL_BEGIN, + PAL_DISPATCH_MODE_CALLBACK); + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_TYPE_WINDOW_MODAL_END, + PAL_DISPATCH_MODE_CALLBACK); + palSetEventDispatchMode( + eventDriver, + PAL_EVENT_TYPE_WINDOW_DECORATION_MODE, + PAL_DISPATCH_MODE_POLL); // initialize the video system. We pass the event driver to recieve video // related events the video system does not copy the event driver, it must diff --git a/tools/abi_dump/core_abi_dump.c b/tools/abi_dump/core_abi_dump.c index 03e2c27c..5ccf101c 100644 --- a/tools/abi_dump/core_abi_dump.c +++ b/tools/abi_dump/core_abi_dump.c @@ -18,21 +18,18 @@ PalBool coreABIDump(uint32_t flags) } FieldInfo versionFields[] = { - { "major", {0, 4}, FIELD(PalVersion, major) }, - { "minor", {4, 4}, FIELD(PalVersion, minor) }, - { "build", {8, 4}, FIELD(PalVersion, build) } - }; + {"major", {0, 4}, FIELD(PalVersion, major)}, + {"minor", {4, 4}, FIELD(PalVersion, minor)}, + {"build", {8, 4}, FIELD(PalVersion, build)}}; FieldInfo allocatorFields[] = { - { "allocate", {0, 8}, FIELD(PalAllocator, allocate) }, - { "free", {8, 8}, FIELD(PalAllocator, free) }, - { "userData", {16, 8}, FIELD(PalAllocator, userData) } - }; + {"allocate", {0, 8}, FIELD(PalAllocator, allocate)}, + {"free", {8, 8}, FIELD(PalAllocator, free)}, + {"userData", {16, 8}, FIELD(PalAllocator, userData)}}; FieldInfo loggerFields[] = { - { "callback", {0, 8}, FIELD(PalLogger, callback) }, - { "userData", {8, 8}, FIELD(PalLogger, userData) } - }; + {"callback", {0, 8}, FIELD(PalLogger, callback)}, + {"userData", {8, 8}, FIELD(PalLogger, userData)}}; StructInfo versionInfo = {0}; versionInfo.name = "PalVersion"; diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index c6cb6107..5e0151cb 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -19,23 +19,21 @@ PalBool eventABIDump(uint32_t flags) } FieldInfo eventFields[] = { - { "data", {0, 8}, FIELD(PalEvent, data) }, - { "data2", {8, 8}, FIELD(PalEvent, data2) }, - { "userId", {16, 4}, FIELD(PalEvent, userId) }, - { "type", {20, 4}, FIELD(PalEvent, type) } - }; + {"data", {0, 8}, FIELD(PalEvent, data)}, + {"data2", {8, 8}, FIELD(PalEvent, data2)}, + {"userId", {16, 4}, FIELD(PalEvent, userId)}, + {"type", {20, 4}, FIELD(PalEvent, type)}}; FieldInfo eventQueueFields[] = { - { "push", {0, 8}, FIELD(PalEventQueue, push) }, - { "poll", {8, 8}, FIELD(PalEventQueue, poll) }, - { "userData", {16, 8}, FIELD(PalEventQueue, userData) } - }; + {"push", {0, 8}, FIELD(PalEventQueue, push)}, + {"poll", {8, 8}, FIELD(PalEventQueue, poll)}, + {"userData", {16, 8}, FIELD(PalEventQueue, userData)}}; FieldInfo eventDriverCreateInfoFields[] = { - { "allocator", {0, 8}, FIELD(PalEventDriverCreateInfo, allocator) }, - { "queue", {8, 8}, FIELD(PalEventDriverCreateInfo, queue) }, - { "callback", {16, 8}, FIELD(PalEventDriverCreateInfo, callback) }, - { "userData", {24, 8}, FIELD(PalEventDriverCreateInfo, userData) }, + {"allocator", {0, 8}, FIELD(PalEventDriverCreateInfo, allocator)}, + {"queue", {8, 8}, FIELD(PalEventDriverCreateInfo, queue)}, + {"callback", {16, 8}, FIELD(PalEventDriverCreateInfo, callback)}, + {"userData", {24, 8}, FIELD(PalEventDriverCreateInfo, userData)}, }; StructInfo eventInfo = {0}; diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index ce10e0bb..59f26f62 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -263,9 +263,9 @@ static PalBool deviceDump(uint32_t flags) }; FieldInfo shaderCreateInfoFields[] = { - { "bytecode", {0, 8}, FIELD(PalShaderCreateInfo, bytecode) }, + { "bcode", {0, 8}, FIELD(PalShaderCreateInfo, code) }, { "entries", {8, 8}, FIELD(PalShaderCreateInfo, entries) }, - { "bytecodeSize", {16, 4}, FIELD(PalShaderCreateInfo, bytecodeSize) }, + { "codeSize", {16, 4}, FIELD(PalShaderCreateInfo, codeSize) }, { "entryCount", {20, 4}, FIELD(PalShaderCreateInfo, entryCount) } }; // clang-format on diff --git a/tools/abi_dump/opengl_abi_dump.c b/tools/abi_dump/opengl_abi_dump.c index e6c3ad41..e6c177fc 100644 --- a/tools/abi_dump/opengl_abi_dump.c +++ b/tools/abi_dump/opengl_abi_dump.c @@ -19,48 +19,44 @@ PalBool openglABIDump(uint32_t flags) } FieldInfo glInfoFields[] = { - { "extensions", {0, 8}, FIELD(PalGLInfo, extensions) }, - { "major", {8, 4}, FIELD(PalGLInfo, major) }, - { "minor", {12, 4}, FIELD(PalGLInfo, minor) }, - { "backend", {16, 4}, FIELD(PalGLInfo, backend) }, - { "api", {20, 4}, FIELD(PalGLInfo, api) }, - { "vendor", {24, 32}, FIELD(PalGLInfo, vendor) }, - { "graphicsCard", {56, 64}, FIELD(PalGLInfo, graphicsCard) }, - { "version", {120, 64}, FIELD(PalGLInfo, version) } - }; + {"extensions", {0, 8}, FIELD(PalGLInfo, extensions)}, + {"major", {8, 4}, FIELD(PalGLInfo, major)}, + {"minor", {12, 4}, FIELD(PalGLInfo, minor)}, + {"backend", {16, 4}, FIELD(PalGLInfo, backend)}, + {"api", {20, 4}, FIELD(PalGLInfo, api)}, + {"vendor", {24, 32}, FIELD(PalGLInfo, vendor)}, + {"graphicsCard", {56, 64}, FIELD(PalGLInfo, graphicsCard)}, + {"version", {120, 64}, FIELD(PalGLInfo, version)}}; FieldInfo fbConfigFields[] = { - { "doubleBuffer", {0, 4}, FIELD(PalGLFBConfig, doubleBuffer) }, - { "stereo", {4, 4}, FIELD(PalGLFBConfig, stereo) }, - { "sRGB", {8, 4}, FIELD(PalGLFBConfig, sRGB) }, - { "index", {12, 2}, FIELD(PalGLFBConfig, index) }, - { "redBits", {14, 2}, FIELD(PalGLFBConfig, redBits) }, - { "greenBits", {16, 2}, FIELD(PalGLFBConfig, greenBits) }, - { "blueBits", {18, 2}, FIELD(PalGLFBConfig, blueBits) }, - { "alphaBits", {20, 2}, FIELD(PalGLFBConfig, alphaBits) }, - { "depthBits", {22, 2}, FIELD(PalGLFBConfig, depthBits) }, - { "stencilBits", {24, 2}, FIELD(PalGLFBConfig, stencilBits) }, - { "samples", {26, 2}, FIELD(PalGLFBConfig, samples) } - }; + {"doubleBuffer", {0, 4}, FIELD(PalGLFBConfig, doubleBuffer)}, + {"stereo", {4, 4}, FIELD(PalGLFBConfig, stereo)}, + {"sRGB", {8, 4}, FIELD(PalGLFBConfig, sRGB)}, + {"index", {12, 2}, FIELD(PalGLFBConfig, index)}, + {"redBits", {14, 2}, FIELD(PalGLFBConfig, redBits)}, + {"greenBits", {16, 2}, FIELD(PalGLFBConfig, greenBits)}, + {"blueBits", {18, 2}, FIELD(PalGLFBConfig, blueBits)}, + {"alphaBits", {20, 2}, FIELD(PalGLFBConfig, alphaBits)}, + {"depthBits", {22, 2}, FIELD(PalGLFBConfig, depthBits)}, + {"stencilBits", {24, 2}, FIELD(PalGLFBConfig, stencilBits)}, + {"samples", {26, 2}, FIELD(PalGLFBConfig, samples)}}; FieldInfo windowFields[] = { - { "instance", {0, 8}, FIELD(PalGLWindow, instance) }, - { "window", {8, 8}, FIELD(PalGLWindow, window) } - }; + {"instance", {0, 8}, FIELD(PalGLWindow, instance)}, + {"window", {8, 8}, FIELD(PalGLWindow, window)}}; FieldInfo contextCreateInfoFields[] = { - { "window", {0, 8}, FIELD(PalGLContextCreateInfo, window) }, - { "fbConfig", {8, 8}, FIELD(PalGLContextCreateInfo, fbConfig) }, - { "shareContext", {16, 8}, FIELD(PalGLContextCreateInfo, shareContext) }, - { "profile", {24, 4}, FIELD(PalGLContextCreateInfo, profile) }, - { "reset", {28, 4}, FIELD(PalGLContextCreateInfo, reset) }, - { "release", {32, 4}, FIELD(PalGLContextCreateInfo, release) }, - { "forward", {36, 4}, FIELD(PalGLContextCreateInfo, forward) }, - { "noError", {40, 4}, FIELD(PalGLContextCreateInfo, noError) }, - { "debug", {44, 4}, FIELD(PalGLContextCreateInfo, debug) }, - { "major", {48, 4}, FIELD(PalGLContextCreateInfo, major) }, - { "minor", {52, 4}, FIELD(PalGLContextCreateInfo, minor) } - }; + {"window", {0, 8}, FIELD(PalGLContextCreateInfo, window)}, + {"fbConfig", {8, 8}, FIELD(PalGLContextCreateInfo, fbConfig)}, + {"shareContext", {16, 8}, FIELD(PalGLContextCreateInfo, shareContext)}, + {"profile", {24, 4}, FIELD(PalGLContextCreateInfo, profile)}, + {"reset", {28, 4}, FIELD(PalGLContextCreateInfo, reset)}, + {"release", {32, 4}, FIELD(PalGLContextCreateInfo, release)}, + {"forward", {36, 4}, FIELD(PalGLContextCreateInfo, forward)}, + {"noError", {40, 4}, FIELD(PalGLContextCreateInfo, noError)}, + {"debug", {44, 4}, FIELD(PalGLContextCreateInfo, debug)}, + {"major", {48, 4}, FIELD(PalGLContextCreateInfo, major)}, + {"minor", {52, 4}, FIELD(PalGLContextCreateInfo, minor)}}; StructInfo glInfo = {0}; glInfo.name = "PalGLInfo"; diff --git a/tools/abi_dump/system_abi_dump.c b/tools/abi_dump/system_abi_dump.c index 539bd6ca..1f9f25c9 100644 --- a/tools/abi_dump/system_abi_dump.c +++ b/tools/abi_dump/system_abi_dump.c @@ -19,26 +19,24 @@ PalBool systemABIDump(uint32_t flags) } FieldInfo platformInfoFields[] = { - { "type", {0, 4}, FIELD(PalPlatformInfo, type) }, - { "apiType", {4, 4}, FIELD(PalPlatformInfo, apiType) }, - { "totalMemory", {8, 4}, FIELD(PalPlatformInfo, totalMemory) }, - { "totalRAM", {12, 4}, FIELD(PalPlatformInfo, totalRAM) }, - { "version", {16, 12}, FIELD(PalPlatformInfo, version) }, - { "name", {28, 32}, FIELD(PalPlatformInfo, name) } - }; + {"type", {0, 4}, FIELD(PalPlatformInfo, type)}, + {"apiType", {4, 4}, FIELD(PalPlatformInfo, apiType)}, + {"totalMemory", {8, 4}, FIELD(PalPlatformInfo, totalMemory)}, + {"totalRAM", {12, 4}, FIELD(PalPlatformInfo, totalRAM)}, + {"version", {16, 12}, FIELD(PalPlatformInfo, version)}, + {"name", {28, 32}, FIELD(PalPlatformInfo, name)}}; FieldInfo cpuInfoFields[] = { - { "features", {0, 8}, FIELD(PalCPUInfo, features) }, - { "architecture", {8, 4}, FIELD(PalCPUInfo, architecture) }, - { "numCores", {12, 4}, FIELD(PalCPUInfo, numCores) }, - { "cacheL1", {16, 4}, FIELD(PalCPUInfo, cacheL1) }, - { "cacheL2", {20, 4}, FIELD(PalCPUInfo, cacheL2) }, - { "cacheL3", {24, 4}, FIELD(PalCPUInfo, cacheL3) }, - { "numLogicalProcessors", {28, 4}, FIELD(PalCPUInfo, numLogicalProcessors) }, - { "vendor", {32, 16}, FIELD(PalCPUInfo, vendor) }, - { "model", {48, 64}, FIELD(PalCPUInfo, model) } - }; - + {"features", {0, 8}, FIELD(PalCPUInfo, features)}, + {"architecture", {8, 4}, FIELD(PalCPUInfo, architecture)}, + {"numCores", {12, 4}, FIELD(PalCPUInfo, numCores)}, + {"cacheL1", {16, 4}, FIELD(PalCPUInfo, cacheL1)}, + {"cacheL2", {20, 4}, FIELD(PalCPUInfo, cacheL2)}, + {"cacheL3", {24, 4}, FIELD(PalCPUInfo, cacheL3)}, + {"numLogicalProcessors", {28, 4}, FIELD(PalCPUInfo, numLogicalProcessors)}, + {"vendor", {32, 16}, FIELD(PalCPUInfo, vendor)}, + {"model", {48, 64}, FIELD(PalCPUInfo, model)}}; + StructInfo platformInfo = {0}; platformInfo.name = "PalPlatformInfo"; platformInfo.fields = platformInfoFields; diff --git a/tools/abi_dump/thread_abi_dump.c b/tools/abi_dump/thread_abi_dump.c index 8ed53078..ca576b09 100644 --- a/tools/abi_dump/thread_abi_dump.c +++ b/tools/abi_dump/thread_abi_dump.c @@ -19,11 +19,10 @@ PalBool threadABIDump(uint32_t flags) } FieldInfo threadCreateInfoFields[] = { - { "stackSize", {0, 8}, FIELD(PalThreadCreateInfo, stackSize) }, - { "allocator", {8, 8}, FIELD(PalThreadCreateInfo, allocator) }, - { "entry", {16, 8}, FIELD(PalThreadCreateInfo, entry) }, - { "arg", {24, 8}, FIELD(PalThreadCreateInfo, arg) } - }; + {"stackSize", {0, 8}, FIELD(PalThreadCreateInfo, stackSize)}, + {"allocator", {8, 8}, FIELD(PalThreadCreateInfo, allocator)}, + {"entry", {16, 8}, FIELD(PalThreadCreateInfo, entry)}, + {"arg", {24, 8}, FIELD(PalThreadCreateInfo, arg)}}; StructInfo threadCreateInfo = {0}; threadCreateInfo.name = "PalThreadCreateInfo"; diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index 5bab5793..ffbbe473 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -19,66 +19,59 @@ PalBool videoABIDump(uint32_t flags) } FieldInfo monitorInfoFields[] = { - { "x", {0, 4}, FIELD(PalMonitorInfo, x) }, - { "y", {4, 4}, FIELD(PalMonitorInfo, y) }, - { "width", {8, 4}, FIELD(PalMonitorInfo, width) }, - { "height", {12, 4}, FIELD(PalMonitorInfo, height) }, - { "dpi", {16, 4}, FIELD(PalMonitorInfo, dpi) }, - { "refreshRate", {20, 4}, FIELD(PalMonitorInfo, refreshRate) }, - { "orientation", {24, 4}, FIELD(PalMonitorInfo, orientation) }, - { "primary", {28, 4}, FIELD(PalMonitorInfo, primary) }, - { "name", {32, 32}, FIELD(PalMonitorInfo, name) } - }; + {"x", {0, 4}, FIELD(PalMonitorInfo, x)}, + {"y", {4, 4}, FIELD(PalMonitorInfo, y)}, + {"width", {8, 4}, FIELD(PalMonitorInfo, width)}, + {"height", {12, 4}, FIELD(PalMonitorInfo, height)}, + {"dpi", {16, 4}, FIELD(PalMonitorInfo, dpi)}, + {"refreshRate", {20, 4}, FIELD(PalMonitorInfo, refreshRate)}, + {"orientation", {24, 4}, FIELD(PalMonitorInfo, orientation)}, + {"primary", {28, 4}, FIELD(PalMonitorInfo, primary)}, + {"name", {32, 32}, FIELD(PalMonitorInfo, name)}}; FieldInfo monitorModeFields[] = { - { "bpp", {0, 4}, FIELD(PalMonitorMode, bpp) }, - { "refreshRate", {4, 4}, FIELD(PalMonitorMode, refreshRate) }, - { "width", {8, 4}, FIELD(PalMonitorMode, width) }, - { "height", {12, 4}, FIELD(PalMonitorMode, height) } - }; + {"bpp", {0, 4}, FIELD(PalMonitorMode, bpp)}, + {"refreshRate", {4, 4}, FIELD(PalMonitorMode, refreshRate)}, + {"width", {8, 4}, FIELD(PalMonitorMode, width)}, + {"height", {12, 4}, FIELD(PalMonitorMode, height)}}; FieldInfo flashInfoFields[] = { - { "flags", {0, 4}, FIELD(PalFlashInfo, flags) }, - { "interval", {4, 4}, FIELD(PalFlashInfo, interval) }, - { "count", {8, 4}, FIELD(PalFlashInfo, count) } - }; + {"flags", {0, 4}, FIELD(PalFlashInfo, flags)}, + {"interval", {4, 4}, FIELD(PalFlashInfo, interval)}, + {"count", {8, 4}, FIELD(PalFlashInfo, count)}}; FieldInfo iconCreateInfoFields[] = { - { "pixels", {0, 8}, FIELD(PalIconCreateInfo, pixels) }, - { "width", {8, 4}, FIELD(PalIconCreateInfo, width) }, - { "height", {12, 4}, FIELD(PalIconCreateInfo, height) } - }; + {"pixels", {0, 8}, FIELD(PalIconCreateInfo, pixels)}, + {"width", {8, 4}, FIELD(PalIconCreateInfo, width)}, + {"height", {12, 4}, FIELD(PalIconCreateInfo, height)}}; FieldInfo cursorCreateInfoFields[] = { - { "pixels", {0, 8}, FIELD(PalCursorCreateInfo, pixels) }, - { "width", {8, 4}, FIELD(PalCursorCreateInfo, width) }, - { "height", {12, 4}, FIELD(PalCursorCreateInfo, height) }, - { "xHotspot", {16, 4}, FIELD(PalCursorCreateInfo, xHotspot) }, - { "yHotspot", {20, 4}, FIELD(PalCursorCreateInfo, yHotspot) } - }; + {"pixels", {0, 8}, FIELD(PalCursorCreateInfo, pixels)}, + {"width", {8, 4}, FIELD(PalCursorCreateInfo, width)}, + {"height", {12, 4}, FIELD(PalCursorCreateInfo, height)}, + {"xHotspot", {16, 4}, FIELD(PalCursorCreateInfo, xHotspot)}, + {"yHotspot", {20, 4}, FIELD(PalCursorCreateInfo, yHotspot)}}; FieldInfo windowHandleInfoFields[] = { - { "nativeInstance", {0, 8}, FIELD(PalWindowHandleInfo, nativeInstance) }, - { "nativeWindow", {8, 8}, FIELD(PalWindowHandleInfo, nativeWindow) }, - { "nativeHandle1", {16, 8}, FIELD(PalWindowHandleInfo, nativeHandle1) }, - { "nativeHandle2", {24, 8}, FIELD(PalWindowHandleInfo, nativeHandle2) }, - { "nativeHandle3", {32, 8}, FIELD(PalWindowHandleInfo, nativeHandle3) } - }; + {"nativeInstance", {0, 8}, FIELD(PalWindowHandleInfo, nativeInstance)}, + {"nativeWindow", {8, 8}, FIELD(PalWindowHandleInfo, nativeWindow)}, + {"nativeHandle1", {16, 8}, FIELD(PalWindowHandleInfo, nativeHandle1)}, + {"nativeHandle2", {24, 8}, FIELD(PalWindowHandleInfo, nativeHandle2)}, + {"nativeHandle3", {32, 8}, FIELD(PalWindowHandleInfo, nativeHandle3)}}; FieldInfo windowCreateInfoFields[] = { - { "title", {0, 8}, FIELD(PalWindowCreateInfo, title) }, - { "monitor", {8, 8}, FIELD(PalWindowCreateInfo, monitor) }, - { "appName", {16, 8}, FIELD(PalWindowCreateInfo, appName) }, - { "instanceName", {24, 8}, FIELD(PalWindowCreateInfo, instanceName) }, - { "fbConfigBackend", {32, 4}, FIELD(PalWindowCreateInfo, fbConfigBackend) }, - { "fbConfigIndex", {36, 4}, FIELD(PalWindowCreateInfo, fbConfigIndex) }, - { "width", {40, 4}, FIELD(PalWindowCreateInfo, width) }, - { "height", {44, 4}, FIELD(PalWindowCreateInfo, height) }, - { "show", {48, 4}, FIELD(PalWindowCreateInfo, show) }, - { "style", {52, 4}, FIELD(PalWindowCreateInfo, style) }, - { "state", {56, 4}, FIELD(PalWindowCreateInfo, state) }, - { "center", {60, 4}, FIELD(PalWindowCreateInfo, center) } - }; + {"title", {0, 8}, FIELD(PalWindowCreateInfo, title)}, + {"monitor", {8, 8}, FIELD(PalWindowCreateInfo, monitor)}, + {"appName", {16, 8}, FIELD(PalWindowCreateInfo, appName)}, + {"instanceName", {24, 8}, FIELD(PalWindowCreateInfo, instanceName)}, + {"fbConfigBackend", {32, 4}, FIELD(PalWindowCreateInfo, fbConfigBackend)}, + {"fbConfigIndex", {36, 4}, FIELD(PalWindowCreateInfo, fbConfigIndex)}, + {"width", {40, 4}, FIELD(PalWindowCreateInfo, width)}, + {"height", {44, 4}, FIELD(PalWindowCreateInfo, height)}, + {"show", {48, 4}, FIELD(PalWindowCreateInfo, show)}, + {"style", {52, 4}, FIELD(PalWindowCreateInfo, style)}, + {"state", {56, 4}, FIELD(PalWindowCreateInfo, state)}, + {"center", {60, 4}, FIELD(PalWindowCreateInfo, center)}}; StructInfo monitorInfo = {0}; monitorInfo.name = "PalMonitorInfo"; From 2f4ad33614f5d49c4b057acd79f54860a084bf9a Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 23 Jul 2026 14:10:04 +0000 Subject: [PATCH 361/372] add a new field to the graphics debugger --- include/pal/pal_graphics.h | 367 +++++++------- include/pal/pal_video.h | 100 ++-- src/graphics/d3d12/pal_adapter_d3d12.c | 42 +- src/graphics/d3d12/pal_as_d3d12.c | 20 +- src/graphics/d3d12/pal_buffer_d3d12.c | 70 +-- src/graphics/d3d12/pal_command_pool_d3d12.c | 82 ++-- src/graphics/d3d12/pal_commands_d3d12.c | 462 +++++++++--------- src/graphics/d3d12/pal_d3d12.c | 62 +-- src/graphics/d3d12/pal_d3d12.h | 4 +- src/graphics/d3d12/pal_descriptors_d3d12.c | 134 ++--- src/graphics/d3d12/pal_device_d3d12.c | 134 ++--- src/graphics/d3d12/pal_image_d3d12.c | 91 ++-- src/graphics/d3d12/pal_pipeline_d3d12.c | 106 ++-- src/graphics/d3d12/pal_sbt_d3d12.c | 60 +-- src/graphics/d3d12/pal_swapchain_d3d12.c | 96 ++-- src/graphics/d3d12/pal_sync_d3d12.c | 72 +-- src/graphics/pal_graphics.c | 8 +- src/graphics/pal_graphics_backends.h | 6 + src/graphics/vulkan/pal_adapter_vulkan.c | 42 +- src/graphics/vulkan/pal_as_vulkan.c | 30 +- src/graphics/vulkan/pal_buffer_vulkan.c | 73 +-- src/graphics/vulkan/pal_command_pool_vulkan.c | 80 +-- src/graphics/vulkan/pal_commands_vulkan.c | 392 ++++++++------- src/graphics/vulkan/pal_descriptors_vulkan.c | 74 +-- src/graphics/vulkan/pal_device_vulkan.c | 131 ++--- src/graphics/vulkan/pal_image_vulkan.c | 95 ++-- src/graphics/vulkan/pal_pipeline_vulkan.c | 76 +-- src/graphics/vulkan/pal_sbt_vulkan.c | 104 ++-- src/graphics/vulkan/pal_swapchain_vulkan.c | 129 ++--- src/graphics/vulkan/pal_sync_vulkan.c | 69 +-- src/graphics/vulkan/pal_vulkan.c | 14 +- src/graphics/vulkan/pal_vulkan.h | 2 +- tests/graphics/custom_backend_test.c | 140 ++++-- tests/graphics/ray_tracing_test.c | 4 +- tools/abi_dump/graphics_abi_dump.c | 16 +- 35 files changed, 1740 insertions(+), 1647 deletions(-) diff --git a/include/pal/pal_graphics.h b/include/pal/pal_graphics.h index 31248abd..c659ad12 100644 --- a/include/pal/pal_graphics.h +++ b/include/pal/pal_graphics.h @@ -577,6 +577,7 @@ * - getHighestSupportedShaderTarget * - createDevice * - destroyDevice + * - getDeviceLostReason * - allocateMemory * - freeMemory * - createQueue @@ -672,7 +673,7 @@ typedef struct PalDevice PalDevice; /** * @struct PalMemory - * @brief Opaque handle to a device memory. This is not `CPU` memory. + * @brief Opaque handle to a device memory. This is not CPU memory. * * @since 2.0 */ @@ -2105,12 +2106,14 @@ typedef struct { typedef struct { void* userData; /**< Optional user provided data. Can be `nullptr`.*/ PalDebugCallback callback; /**< Debug callback function.*/ + PalBool enableGPUValidation; /**< Enable GPU-Based validation.*/ PalBool denyGeneral; /**< Do not recieve general messages.*/ PalBool denyValidation; /**< Do not recieve validation messages.*/ PalBool denyPerformance; /**< Do not recieve performance messages.*/ PalBool denyInfoSeverity; /**< Do not recieve info severity messages.*/ PalBool denyWarningSeverity; /**< Do not recieve warning severity messages.*/ PalBool denyErrorSeverity; /**< Do not recieve error severity messages.*/ + uint32_t reserved; /**< 0 for now.*/ } PalGraphicsDebugger; /** @@ -2902,6 +2905,13 @@ typedef struct { */ void(PAL_CALL* destroyDevice)(PalDevice* device); + /** + * Backend implementation of ::palGetDeviceLostReason. + * + * Must obey the rules and semantics documented in palGetDeviceLostReason(). + */ + uint32_t(PAL_CALL* getDeviceLostReason)(PalDevice* device); + /** * Backend implementation of ::palAllocateMemory. * @@ -3825,9 +3835,9 @@ typedef struct { PalAccelerationStructure** outAs); /** - * Backend implementation of ::palDestroyAccelerationstructure. + * Backend implementation of ::palDestroyAccelerationStructure. * - * Must obey the rules and semantics documented in palDestroyAccelerationstructure(). + * Must obey the rules and semantics documented in palDestroyAccelerationStructure(). */ void(PAL_CALL* destroyAccelerationstructure)(PalAccelerationStructure* as); @@ -4172,8 +4182,6 @@ PAL_API PalResult PAL_CALL palEnumerateAdapters( /** * @brief Get information about an adapter (GPU). * - * The graphics system must be initialized before this call. - * * @param[in] adapter Adapter to query information on. * @param[out] info Pointer to a PalAdapterInfo to fill. * @@ -4189,8 +4197,6 @@ PAL_API void PAL_CALL palGetAdapterInfo( /** * @brief Get capabilites or limits about an adapter (GPU). * - * The graphics system must be initialized before this call. - * * @param[in] adapter Adapter to query capabilities on. * @param[out] caps Pointer to a PalAdapterCapabilities to fill. * @@ -4206,8 +4212,6 @@ PAL_API void PAL_CALL palGetAdapterCapabilities( /** * @brief Get the supported features of an adapter (GPU). * - * The graphics system must be initialized before this call. - * * @param[in] adapter Adapter to query features on. * * @return adapter features on success or `0` on failure. @@ -4222,8 +4226,6 @@ PAL_API PalAdapterFeatures PAL_CALL palGetAdapterFeatures(PalAdapter* adapter); /** * @brief Get the highest supported shader target of an adapter (GPU). * - * The graphics system must be initialized before this call. - * * @param[in] adapter Adapter to query. * @param[in] shaderFormat The shader format. Must have only a single bit set. * @@ -4242,8 +4244,8 @@ PAL_API uint32_t PAL_CALL palGetHighestSupportedShaderTarget( /** * @brief Create a device from an adapter (GPU). * - * The graphics system must be initialized before this call. PAL does not enable any features - * by default. + * PAL does not enable any features by default. The created device must be destroyed using + * `palDestroyDevice()`. * * Every requested feature must be supported by the adapter. Use `palGetAdapterFeatures` to check * the supported features of the adapter that can be enabled. Using a feature which is not @@ -4269,7 +4271,7 @@ PAL_API PalResult PAL_CALL palCreateDevice( /** * @brief Destroy a device. * - * The graphics system must be initialized before this call. + * All resources created with the device must be destroyed before this call. * * @param[in] device Pointer to the device to destroy. * @@ -4281,10 +4283,25 @@ PAL_API PalResult PAL_CALL palCreateDevice( */ PAL_API void PAL_CALL palDestroyDevice(PalDevice* device); +/** + * @brief Get the native device lost reason code. + * + * This function returns the backend-specific native code for the reason the device + * was lost. Backends that do not provide explicit device lost reason codes return + * their standard device lost code. + * + * @param[in] device The device. + * + * Thread safety: Thread safe. + * + * @since 2.0 + */ +PAL_API uint32_t PAL_CALL palGetDeviceLostReason(PalDevice* device); + /** * @brief Allocates GPU memory for the specified device. * - * The graphics system must be initialized before this call. On CPU adapters, there is usually no + * On CPU adapters, there is usually no * `PAL_MEMORY_TYPE_GPU_ONLY` memory type available. So it uses shared memory as the vram and set * the shared memory to the `PAL_MEMORY_TYPE_GPU_ONLY` for correctness. * @@ -4314,7 +4331,6 @@ PAL_API PalResult PAL_CALL palAllocateMemory( /** * @brief Free GPU memory allocated by palAllocateMemory. * - * The graphics system must be initialized before this call. * If `memory` is `nullptr`, this function will return silently. * * @param[in] memory Pointer to memory to free. @@ -4330,8 +4346,6 @@ PAL_API void PAL_CALL palFreeMemory(PalMemory* memory); /** * @brief Get sampler anisotropy feature capabilites or limits about a device. * - * The graphics system must be initialized before this call. - * * `PAL_ADAPTER_FEATURE_SAMPLER_ANISOTROPY` must be supported and enabled when creating the * device. Otherwise behavior is undefined. * @@ -4349,8 +4363,6 @@ PAL_API void PAL_CALL palQuerySamplerAnisotropyCapabilities( /** * @brief Get multi view feature capabilites or limits about a device. * - * The graphics system must be initialized before this call. - * * `PAL_ADAPTER_FEATURE_MULTI_VIEW` must be supported and enabled when creating the * device. Otherwise behavior is undefined. * @@ -4368,8 +4380,6 @@ PAL_API void PAL_CALL palQueryMultiViewCapabilities( /** * @brief Get multi viewport feature capabilites or limits about a device. * - * The graphics system must be initialized before this call. - * * `PAL_ADAPTER_FEATURE_MULTI_VIEWPORT` must be supported and enabled when creating the * device. Otherwise behavior is undefined. * @@ -4387,8 +4397,6 @@ PAL_API void PAL_CALL palQueryMultiViewportCapabilities( /** * @brief Get depth stencil feature capabilites or limits about a device. * - * The graphics system must be initialized before this call. - * * `PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE` must be supported and enabled when creating the * device. Otherwise behavior is undefined. * @@ -4406,8 +4414,6 @@ PAL_API void PAL_CALL palQueryDepthStencilCapabilities( /** * @brief Get fragment shading rate feature capabilites or limits about a device. * - * The graphics system must be initialized before this call. - * * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled when creating the * device. Otherwise behavior is undefined. * @@ -4425,8 +4431,6 @@ PAL_API void PAL_CALL palQueryFragmentShadingRateCapabilities( /** * @brief Get mesh shader feature capabilites or limits about a device. * - * The graphics system must be initialized before this call. - * * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled when creating the * device. Otherwise behavior is undefined. * @@ -4444,8 +4448,6 @@ PAL_API void PAL_CALL palQueryMeshShaderCapabilities( /** * @brief Get ray tracing feature capabilites or limits about a device. * - * The graphics system must be initialized before this call. - * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled when creating the * device. Otherwise behavior is undefined. * @@ -4463,8 +4465,6 @@ PAL_API void PAL_CALL palQueryRayTracingCapabilities( /** * @brief Get descriptor indexing feature capabilites or limits about a device. * - * The graphics system must be initialized before this call. - * * `PAL_ADAPTER_FEATURE_DESCRIPTOR_INDEXING` must be supported and enabled when creating the * device. Otherwise behavior is undefined. * @@ -4482,7 +4482,7 @@ PAL_API void PAL_CALL palQueryDescriptorIndexingCapabilities( /** * @brief Create a queue from a device. * - * The graphics system must be initialized before this call. + * The created queue must be destroyed using `palDestroyQueue()`. * * The number of queues of each type which can be created is limited per adapter. check with * PalAdapterCapabilities::maxComputeQueues, PalAdapterCapabilities::maxGraphicsQueues and @@ -4513,8 +4513,6 @@ PAL_API PalResult PAL_CALL palCreateQueue( /** * @brief Destroy a queue. * - * The graphics system must be initialized before this call. - * * @param[in] queue Queue to destroy. * * Thread safety: Thread safe if the device used to create the queue is @@ -4528,8 +4526,6 @@ PAL_API void PAL_CALL palDestroyQueue(PalQueue* queue); /** * @brief Check if a queue is presentable to the provided window. * - * The graphics system must be initialized before this call. - * * @param[in] queue Queue to query. * @param[in] surface Surface to check presentation support for. * @@ -4547,8 +4543,6 @@ PAL_API PalBool PAL_CALL palCanQueuePresent( /** * @brief Blocks indefinitely until the queue becomes idle. * - * The graphics system must be initialized before this call. - * * This function blocks indefinitely until all submitted work on the queue has been completetd. * Returns `PAL_RESULT_SUCCESS` to indicate all pending operations has been completetd. * @@ -4566,8 +4560,6 @@ PAL_API PalResult PAL_CALL palWaitQueue(PalQueue* queue); /** * @brief Returns a list of all supported formats of an adapter (GPU). * - * The graphics system must be initialized before this call. - * * This function returns the supported format with the supported image usages * associated with the format. This is a handy way of selecting a format based on the image * usages. Use palIsFormatSupported() to check for a specific format. @@ -4593,8 +4585,6 @@ PAL_API void PAL_CALL palEnumerateFormats( /** * @brief Check support for a format on an adapter (GPU). * - * The graphics system must be initialized before this call. - * * This is much faster than enumerating all the formats to pick one. You directly check support * for the format you want to use. Call palQueryFormatImageUsages() to check for supported image * usages if format is supported. @@ -4617,8 +4607,6 @@ PAL_API PalBool PAL_CALL palIsFormatSupported( /** * @brief Checks supported image usages associated with a format. * - * The graphics system must be initialized before this call. - * * @param[in] adapter Adapter to query format on. * @param[in] format Format to query image usages for. * @@ -4635,12 +4623,10 @@ PAL_API PalImageUsages PAL_CALL palQueryFormatImageUsages( /** * @brief Checks supported sample count associated with a format. * - * The graphics system must be initialized before this call. - * * @param[in] adapter Adapter to query format on. * @param[in] format Format to query sample count for. * - * @return Supported sample count on success otherwise `0` on failure. + * @return Supported sample count on success otherwise 0 on failure. * * Thread safety: Thread safe. * @@ -4653,7 +4639,7 @@ PAL_API PalSampleCount PAL_CALL palQueryFormatSampleCount( /** * @brief Create an image. * - * The graphics system must be initialized before this call. + * The created image must be destroyed using `palDestroyImage()`. * * PalImageCreateInfo::width, PalImageCreateInfo::height and PalImageCreateInfo::sampleCount * must not be greater than the limits of the adapter used to create the device. Check @@ -4679,8 +4665,6 @@ PAL_API PalResult PAL_CALL palCreateImage( /** * @brief Destroy an image. * - * The graphics system must be initialized before this call. - * * @param[in] image Image to destroy. * * Thread safety: Thread safe if the device used to create the image is @@ -4694,7 +4678,6 @@ PAL_API void PAL_CALL palDestroyImage(PalImage* image); /** * @brief Get information about an image. * - * The graphics system must be initialized before this call. * This function also supports swapchain images. * * @param[in] image Image to query information on. @@ -4712,8 +4695,6 @@ PAL_API void PAL_CALL palGetImageInfo( /** * @brief Get memory requirements for the provided image. * - * The graphics system must be initialized before this call. - * * @param[in] image Image to query memory requirements on. * @param[out] requirements Pointer to a PalMemoryRequirements to fill. * @@ -4728,7 +4709,6 @@ PAL_API void PAL_CALL palGetImageMemoryRequirements( /** * @brief Bind an allocated memory to an image. * - * The graphics system must be initialized before this call. * The memory size and alignment should match the requirements of the image. * Get the requirements with palGetImageMemoryRequirements(). * @@ -4752,7 +4732,7 @@ PAL_API PalResult PAL_CALL palBindImageMemory( /** * @brief Create an image view. * - * The graphics system must be initialized before this call. + * The created image view must be destroyed using `palDestroyImageView()`. * * PalImageViewCreateInfo::type must be compatible by the type of the base image. Eg. A 2D base * image must be have an image view of either `PAL_IMAGE_VIEW_TYPE_2D` or @@ -4784,8 +4764,6 @@ PAL_API PalResult PAL_CALL palCreateImageView( /** * @brief Destroy an image view. * - * The graphics system must be initialized before this call. - * * @param[in] imageView Image view to destroy. * * Thread safety: Thread safe if the device used to create the image view is @@ -4799,9 +4777,7 @@ PAL_API void PAL_CALL palDestroyImageView(PalImageView* imageView); /** * @brief Create a sampler. * - * The graphics system must be initialized before this call. - * Samplers are immutable so any parameter used to create it cannot will be fixed after - * creation. + * The created sampler must be destroyed using `palDestroySampler()`. * * @param[in] device Device that creates the sampler. * @param[in] info Pointer to a PalSamplerCreateInfo struct that specifies parameters. @@ -4823,8 +4799,6 @@ PAL_API PalResult PAL_CALL palCreateSampler( /** * @brief Destroy a sampler. * - * The graphics system must be initialized before this call. - * * @param[in] sampler Sampler to destroy. * * Thread safety: Thread safe if the device used to create the sampler is @@ -4838,7 +4812,7 @@ PAL_API void PAL_CALL palDestroySampler(PalSampler* sampler); /** * @brief Create a surface for a window. * - * The graphics system must be initialized before this call. + * The created surface must be destroyed using `palDestroySurface()`. * * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the device. * Otherwise behavior is undefined. @@ -4867,7 +4841,7 @@ PAL_API PalResult PAL_CALL palCreateSurface( /** * @brief Destroy a surface. * - * The graphics system must be initialized before this call. + * * * @param[in] surface Surface to destroy. * @@ -4882,7 +4856,7 @@ PAL_API void PAL_CALL palDestroySurface(PalSurface* surface); /** * @brief Get surface capabilites about a device. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the * device. Otherwise behavior is undefined. @@ -4903,7 +4877,8 @@ PAL_API void PAL_CALL palGetSurfaceCapabilities( /** * @brief Create a swaphain. * - * The graphics system must be initialized before this call. + * + * The created swapchain must be destroyed using `palDestroySwapchain()`. * * `PAL_ADAPTER_FEATURE_SWAPCHAIN` must be supported and enabled when creating the device. * Otherwise behavior is undefined. @@ -4932,7 +4907,7 @@ PAL_API PalResult PAL_CALL palCreateSwapchain( /** * @brief Destroy a swapchain. * - * The graphics system must be initialized before this call. + * * * @param[in] swapchain Swapchain to destroy. * @@ -4947,7 +4922,7 @@ PAL_API void PAL_CALL palDestroySwapchain(PalSwapchain* swapchain); /** * @brief Get a swapchain image from the list of images with an index. * - * The graphics system must be initialized before this call. + * * * @param[in] swapchain Swapchain to get image from. * @param[in] index Index of image in the list. Must not be greater than the image count. @@ -4966,7 +4941,7 @@ PAL_API PalImage* PAL_CALL palGetSwapchainImage( /** * @brief Get the next available image from the swapchain image list. * - * The graphics system must be initialized before this call. + * * * @param[in] swapchain Swapchain to get image index from. * @param[in] info Pointer to a PalSwapchainNextImageInfo struct that specifies parameters. @@ -4988,7 +4963,7 @@ PAL_API PalResult PAL_CALL palGetNextSwapchainImage( /** * @brief Present the swapchain. * - * The graphics system must be initialized before this call. + * * * @param[in] swapchain Swapchain to present. * @param[in] imageIndex Swapchain image index to present. @@ -5009,7 +4984,7 @@ PAL_API PalResult PAL_CALL palPresentSwapchain( /** * @brief Resize the provided swapchain. * - * The graphics system must be initialized before this call. + * * * The swapchain images must not be in use before this call. All resources (image views) that * reference the swapchain images must be destroyed and recreated. @@ -5033,7 +5008,8 @@ PAL_API PalResult PAL_CALL palResizeSwapchain( /** * @brief Create a shader. * - * The graphics system must be initialized before this call. + * + * The created shader must be destroyed using `palDestroyShader()`. * * `PAL_ADAPTER_FEATURE_GEOMETRY_SHADER` must be supported and enabled by the device if * `PAL_SHADER_STAGE_GEOMETRY` will be used. @@ -5072,7 +5048,7 @@ PAL_API PalResult PAL_CALL palCreateShader( /** * @brief Destroy a shader. * - * The graphics system must be initialized before this call. + * * * @param[in] shader Shader to destroy. * @@ -5087,7 +5063,8 @@ PAL_API void PAL_CALL palDestroyShader(PalShader* shader); /** * @brief Create a fence. * - * The graphics system must be initialized before this call. + * + * The created fence must be destroyed using `palDestroyFence()`. * * @param[in] device Device that creates the fence. * @param[in] signaled True if fence should be created signaled. If true, the fence must be reset @@ -5110,7 +5087,7 @@ PAL_API PalResult PAL_CALL palCreateFence( /** * @brief Destroy a fence. * - * The graphics system must be initialized before this call. + * * * @param[in] fence Fence to destroy. * @@ -5125,7 +5102,7 @@ PAL_API void PAL_CALL palDestroyFence(PalFence* fence); /** * @brief Wait for a fence. * - * The graphics system must be initialized before this call. + * * * This function blocks for `timeout` until the fence is signaled or there is a timeout. * Returns `PAL_RESULT_SUCCESS` or `PAL_RESULT_TIMEOUT` respectively. @@ -5148,7 +5125,7 @@ PAL_API PalResult PAL_CALL palWaitFence( /** * @brief Reset a fence to an unsignaled state. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_FENCE_RESET` must be supported and enabled when creating the * device. Otherwise behavior is undefined. @@ -5168,7 +5145,7 @@ PAL_API PalResult PAL_CALL palResetFence(PalFence* fence); /** * @brief Checks if the provided fence is in a signaled state. * - * The graphics system must be initialized before this call. + * * * @param[in] fence Fence to check. * @@ -5185,7 +5162,8 @@ PAL_API PalBool PAL_CALL palIsFenceSignaled(PalFence* fence); /** * @brief Create a semaphore. * - * The graphics system must be initialized before this call. + * + * The created semaphore must be destroyed using `palDestroySemaphore()`. * * @param[in] device Device that creates the semaphore. * @param[in] enableTimeline If true, `PAL_ADAPTER_FEATURE_TIMELINE_SEMAPHORE` must be supported @@ -5208,7 +5186,7 @@ PAL_API PalResult PAL_CALL palCreateSemaphore( /** * @brief Destroy a semaphore. * - * The graphics system must be initialized before this call. + * * * @param[in] semaphore Semaphore to destroy. * @@ -5223,7 +5201,7 @@ PAL_API void PAL_CALL palDestroySemaphore(PalSemaphore* semaphore); /** * @brief Waits for a semaphore to reach the provided value. * - * The graphics system must be initialized before this call. + * * The provided semaphore must be a timeline semaphore. Otherwise undefined behavior. * * @param[in] semaphore Semaphore to wait on. @@ -5247,7 +5225,7 @@ PAL_API PalResult PAL_CALL palWaitSemaphore( /** * @brief Signals a semaphore from the provided value. * - * The graphics system must be initialized before this call. + * * The provided semaphore must be a timeline semaphore. Otherwise undefined behavior. * * @param[in] semaphore Semaphore to signal. @@ -5271,7 +5249,7 @@ PAL_API PalResult PAL_CALL palSignalSemaphore( /** * @brief Get the value of a semaphore. * - * The graphics system must be initialized before this call. + * * The provided semaphore must be a timeline semaphore. Otherwise undefined behavior. * * @param[in] semaphore Semaphore to get its value. @@ -5293,7 +5271,8 @@ PAL_API PalResult PAL_CALL palGetSemaphoreValue( /** * @brief Create a command pool from a device. * - * The graphics system must be initialized before this call. + * + * The created command pool must be destroyed using `palDestroyCommandPool()`. * * @param[in] device Device that creates the command pool. * @param[in] queue Queue the command pool buffers will be submitted to. @@ -5315,7 +5294,7 @@ PAL_API PalResult PAL_CALL palCreateCommandPool( /** * @brief Destroy a command pool. * - * The graphics system must be initialized before this call. + * * All command buffers allocated from the pool must be freed before this call, * otherwise undefined behavior. * @@ -5332,7 +5311,7 @@ PAL_API void PAL_CALL palDestroyCommandPool(PalCommandPool* pool); /** * @brief Reset all command buffers allocated from the provided command pool. * - * The graphics system must be initialized before this call. + * * * @param[in] pool Command pool to reset its command buffers. * @@ -5348,7 +5327,7 @@ PAL_API PalResult PAL_CALL palResetCommandPool(PalCommandPool* pool); /** * @brief Allocate a command buffer from the provided command pool. * - * The graphics system must be initialized before this call. + * * * @param[in] device Device to allocate command buffer on. * @param[in] pool Command pool to allocate command buffer from. @@ -5372,7 +5351,7 @@ PAL_API PalResult PAL_CALL palAllocateCommandBuffer( /** * @brief Free an allocated command buffer. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer to free. * @@ -5387,7 +5366,7 @@ PAL_API void PAL_CALL palFreeCommandBuffer(PalCommandBuffer* cmdBuffer); /** * @brief Reset the provided command buffer. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer to reset. * @@ -5403,7 +5382,7 @@ PAL_API PalResult PAL_CALL palResetCommandBuffer(PalCommandBuffer* cmdBuffer); /** * @brief Submit a command buffer to the provided queue for execution. * - * The graphics system must be initialized before this call. The command buffer must not + * The command buffer must not * be in a recording state. * * @param[in] queue Queue to execute the command buffer. @@ -5423,7 +5402,7 @@ PAL_API PalResult PAL_CALL palSubmitCommandBuffer( /** * @brief Begin recording commands to the provided command buffer. * - * The graphics system must be initialized before this call. This function must be called + * This function must be called * before any other `palCmd**` function is used. * * @param[in] cmdBuffer Command buffer to begin recording. @@ -5443,7 +5422,7 @@ PAL_API PalResult PAL_CALL palCmdBegin( /** * @brief End recording commands to the provided command buffer. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer to begin recording. * @@ -5460,7 +5439,7 @@ PAL_API PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer); /** * @brief Execute a secondary command buffer within a primary command buffer. * - * The graphics system must be initialized before this call. The `secondaryCmdBuffer` must + * The `secondaryCmdBuffer` must * be created with the type `PAL_COMMAND_BUFFER_TYPE_SECONDARY`. * * @param[in] primaryCmdBuffer Primary command buffer. Must be in recording state. @@ -5477,7 +5456,7 @@ PAL_API void PAL_CALL palCmdExecuteCommandBuffer( /** * @brief Set the fragment shading rate used for draw calls. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_FRAGMENT_SHADING_RATE` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -5496,7 +5475,7 @@ PAL_API void PAL_CALL palCmdSetFragmentShadingRate( /** * @brief Dispatch mesh shader workgroups. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_MESH_SHADER` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -5522,7 +5501,7 @@ PAL_API void PAL_CALL palCmdDrawMeshTasks( /** * @brief Dispatch mesh shader workgroups using parameters from a buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH` must be supported * and enabled by the device. Otherwise behavior is undefined. @@ -5547,7 +5526,7 @@ PAL_API void PAL_CALL palCmdDrawMeshTasksIndirect( /** * @brief Dispatch mesh shader workgroups using parameters from buffers. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_MESH_SHADER` and `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_MESH_COUNT` must be * supported and enabled by the device. Otherwise behavior is undefined. @@ -5574,7 +5553,7 @@ PAL_API void PAL_CALL palCmdDrawMeshTasksIndirectCount( /** * @brief Build or update an acceleration structure. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -5593,7 +5572,7 @@ PAL_API void PAL_CALL palCmdBuildAccelerationStructure( /** * @brief Begin a rendering pass. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] info Pointer to a PalRenderingInfo struct that specifies parameters. @@ -5609,7 +5588,7 @@ PAL_API void PAL_CALL palCmdBeginRendering( /** * @brief End a rendering pass. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @@ -5622,7 +5601,7 @@ PAL_API void PAL_CALL palCmdEndRendering(PalCommandBuffer* cmdBuffer); /** * @brief Copy data from one buffer to the other. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] dst Destination buffer. @@ -5642,7 +5621,7 @@ PAL_API void PAL_CALL palCmdCopyBuffer( /** * @brief Copy data from a buffer to an image. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] dstImage Destination image. @@ -5662,7 +5641,7 @@ PAL_API void PAL_CALL palCmdCopyBufferToImage( /** * @brief Copy data from one image to the other. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] dst Destination image. @@ -5682,7 +5661,7 @@ PAL_API void PAL_CALL palCmdCopyImage( /** * @brief Copy data from an image to a buffer. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] dstBuffer Destination buffer. @@ -5702,7 +5681,7 @@ PAL_API void PAL_CALL palCmdCopyImageToBuffer( /** * @brief Bind a pipeline. * - * The graphics system must be initialized before this call. Every pipeline knows it types which is + * Every pipeline knows it types which is * set at the respective creation functions. (`palCreate**Graphics/Compute/RayTracing**Pipeline`). * * @param[in] cmdBuffer Command buffer being recorded. @@ -5719,7 +5698,7 @@ PAL_API void PAL_CALL palCmdBindPipeline( /** * @brief Set the viewport(s) used in draw commands. * - * The graphics system must be initialized before this call. This always overwrites any previous + * This always overwrites any previous * viewports that were set since the first viewport index is always 0. * * @param[in] cmdBuffer Command buffer being recorded. @@ -5738,7 +5717,7 @@ PAL_API void PAL_CALL palCmdSetViewport( /** * @brief Set the scissor(s) used in draw commands. * - * The graphics system must be initialized before this call. This always overwrites any previous + * This always overwrites any previous * scissors that were set since the first scissor index is always 0. * * @param[in] cmdBuffer Command buffer being recorded. @@ -5757,7 +5736,7 @@ PAL_API void PAL_CALL palCmdSetScissors( /** * @brief Bind vertex buffer(s) used in draw commands. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] firstSlot Index of the first vertex buffer binding slot. @@ -5781,7 +5760,7 @@ PAL_API void PAL_CALL palCmdBindVertexBuffers( /** * @brief Bind index buffer used in draw commands. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Index buffer to bind. @@ -5803,7 +5782,7 @@ PAL_API void PAL_CALL palCmdBindIndexBuffer( /** * @brief Issue a non-indexed draw command. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] vertexCount Number of vertices to draw. @@ -5828,7 +5807,7 @@ PAL_API void PAL_CALL palCmdDraw( /** * @brief Issue a non-indexed draw command using buffers. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -5854,7 +5833,7 @@ PAL_API void PAL_CALL palCmdDrawIndirect( /** * @brief Issue a non-indexed draw command using buffers. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -5881,7 +5860,7 @@ PAL_API void PAL_CALL palCmdDrawIndirectCount( /** * @brief Issue an indexed draw command. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] indexCount Number of indices to draw. @@ -5908,7 +5887,7 @@ PAL_API void PAL_CALL palCmdDrawIndexed( /** * @brief Issue an indexed draw command using buffers. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -5933,7 +5912,7 @@ PAL_API void PAL_CALL palCmdDrawIndexedIndirect( /** * @brief Issue an indexed draw command using buffers. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_INDIRECT_DRAW_COUNT` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -5963,10 +5942,10 @@ PAL_API void PAL_CALL palCmdDrawIndexedIndirectCount( * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. * - * The graphics system must be initialized before this call. This function defines a - * dependency between `oldUsageState` and `newUsageState`. It ensures that all - * operations performed under `oldUsageState` are completed and visible before the acceleration - * structure is accessed under `newUsageState`. + * This function defines a + * dependency between `PalBarrierInfo::oldState` and `PalBarrierInfo::newState`. It ensures that + * all operations performed under the old `PalBarrierInfo::oldState` are completed and visible + * before the acceleration structure is accessed under `PalBarrierInfo::newState`. * * This function does not modify the acceleration structure, it only exforces execution ordering * and acceleration structure memory visibility. @@ -5977,13 +5956,13 @@ PAL_API void PAL_CALL palCmdDrawIndexedIndirectCount( * Example: * * To make sure BLAS builds before TLAS access it and TLAS does not use scratch buffer - * whilst BLAS is buidling, - * we put a barrier to transition the BLAS to ensure it has finished building and the scratch - * buffer is not being used. This is expressed with `oldUsageState` being - * `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE`. + * whilst BLAS is buidling, we put a barrier to transition the BLAS to ensure it has finished + * building and the scratch buffer is not being used. This is expressed with + * `PalBarrierInfo::oldState` being set to `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_WRITE` and + * `PalBarrierInfo::srcStages` being set to `PAL_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD`. * - * `newUsageState` should be the new usage state we want after the BLAS - * has finished building which is `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ`. + * `PalBarrierInfo::newState` being `PAL_USAGE_STATE_ACCELERATION_STRUCTURE_READ` and + * `PalBarrierInfo::dstStages` being `PAL_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] as Acceleration structure to set barrier on. @@ -5991,8 +5970,6 @@ PAL_API void PAL_CALL palCmdDrawIndexedIndirectCount( * * Thread safety: Thread safe if `cmdBuffer` is externally synchronized. * - * @note A pipeline must be bound before this call. - * * @since 2.0 * @sa palCmdImageBarrier * @sa palCmdBufferBarrier @@ -6005,10 +5982,10 @@ PAL_API void PAL_CALL palCmdAccelerationStructureBarrier( /** * @brief Transition an image from one usage state to another. * - * The graphics system must be initialized before this call. This function defines a - * dependency between `oldUsageState` and `newUsageState`. It ensures that all - * operations performed under `oldUsageState` are completed and visible before the image - * is accessed under `newUsageState`. + * This function defines a + * dependency between `PalBarrierInfo::oldState` and `PalBarrierInfo::newState`. It ensures that all + * operations performed under `PalBarrierInfo::oldState` are completed and visible before the image + * is accessed under `PalBarrierInfo::newState`. * * This function does not modify the image, it only exforces execution ordering and image memory * visibility. @@ -6017,11 +5994,12 @@ PAL_API void PAL_CALL palCmdAccelerationStructureBarrier( * * To make sure the an image is ready for presenting after a render pass, * we put a barrier to transition the image to ensure the render pass has finished writing - * to the image. This is expressed with `oldUsageState` being - * `PAL_USAGE_STATE_COLOR_ATTACHMENT`. + * to the image. This is expressed with `PalBarrierInfo::oldState` being + * `PAL_USAGE_STATE_COLOR_ATTACHMENT` and `PalBarrierInfo::srcStages` being + * `PAL_PIPELINE_STAGE_COLOR_ATTACHMENT`. * - * `newUsageState` should be the new usage state we want after the render pass - * has finished which is `PAL_USAGE_STATE_PRESENT`. + * `PalBarrierInfo::newState` being `PAL_USAGE_STATE_PRESENT` and + * `PalBarrierInfo::dstStages` being `PAL_PIPELINE_STAGE_NONE`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] image Image to set barrier on. @@ -6043,10 +6021,10 @@ PAL_API void PAL_CALL palCmdImageBarrier( /** * @brief Transition a buffer from one usage state to another. * - * The graphics system must be initialized before this call. This function defines a - * dependency between `oldUsageState` and `newUsageState`. It ensures that all - * operations performed under `oldUsageState` are completed and visible before the buffer - * is accessed under `newUsageState`. + * This function defines a + * dependency between `PalBarrierInfo::oldState` and `PalBarrierInfo::newState`. It ensures that all + * operations performed under `PalBarrierInfo::oldState` are completed and visible before the buffer + * is accessed under `PalBarrierInfo::newState`. * * This function does not modify the buffer, it only exforces execution ordering and buffer memory * visibility. @@ -6054,11 +6032,13 @@ PAL_API void PAL_CALL palCmdImageBarrier( * Example: * * To read back data from a buffer that will be written to by a shader, - * we put a barrier to transition the buffer to ensurethe shader has finished writing to the - * buffer. This is expressed with `oldUsageState` being `PAL_USAGE_STATE_SHADER_WRITE`. + * we put a barrier to transition the buffer to ensure the shader has finished writing to the + * buffer. This is expressed with `PalBarrierInfo::oldState` being `PAL_USAGE_STATE_SHADER_WRITE` + * and `PalBarrierInfo::srcStages` being the shader stage that wrote to the buffer + * (eg. `PAL_PIPELINE_STAGE_COMPUTE_SHADER`). * - * `newUsageState` should be the new usage state we want after the write - * has finished which is`PAL_USAGE_STATE_TRANSFER_READ`. + * `PalBarrierInfo::newState` being `PAL_USAGE_STATE_TRANSFER_READ` and + * `PalBarrierInfo::dstStages` being `PAL_PIPELINE_STAGE_TRANSFER`. * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] buffer Buffer to set barrier on. @@ -6078,7 +6058,7 @@ PAL_API void PAL_CALL palCmdBufferBarrier( /** * @brief Dispatch compute shader workgroups. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] groupCountX Number of compute shader groups to dispatch on the x axis. @@ -6101,7 +6081,7 @@ PAL_API void PAL_CALL palCmdDispatch( /** * @brief Dispatch compute shader workgroups with base offset. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_DISPATCH_BASE` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6133,7 +6113,7 @@ PAL_API void PAL_CALL palCmdDispatchBase( /** * @brief Dispatch compute shader workgroups using parameters from a buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_INDIRECT_DISPATCH` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6156,7 +6136,7 @@ PAL_API void PAL_CALL palCmdDispatchIndirect( /** * @brief Dispatch rays. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6185,7 +6165,7 @@ PAL_API void PAL_CALL palCmdTraceRays( /** * @brief Dispatch rays using parameters from a buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_INDIRECT_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6214,7 +6194,7 @@ PAL_API void PAL_CALL palCmdTraceRaysIndirect( /** * @brief Bind a descriptor set to the provided command buffer. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] setIndex Index of the descriptor set to bind. @@ -6234,7 +6214,7 @@ PAL_API void PAL_CALL palCmdBindDescriptorSet( /** * @brief Update push constant data for the provided command buffer. * - * The graphics system must be initialized before this call. + * * * @param[in] cmdBuffer Command buffer being recorded. * @param[in] offset Offset in bytes into the push constant range. @@ -6256,7 +6236,7 @@ PAL_API void PAL_CALL palCmdPushConstants( /** * @brief Set the cull mode for the provided command buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6275,7 +6255,7 @@ PAL_API void PAL_CALL palCmdSetCullMode( /** * @brief Set the front face for the provided command buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6294,7 +6274,7 @@ PAL_API void PAL_CALL palCmdSetFrontFace( /** * @brief Set the primitive topology for the provided command buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6313,7 +6293,7 @@ PAL_API void PAL_CALL palCmdSetPrimitiveTopology( /** * @brief Set depth test enable for the provided command buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6332,7 +6312,7 @@ PAL_API void PAL_CALL palCmdSetDepthTestEnable( /** * @brief Set depth write enable for the provided command buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6351,7 +6331,7 @@ PAL_API void PAL_CALL palCmdSetDepthWriteEnable( /** * @brief Set depth stencil operation for the provided command buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP` must be supported and enabled by the device. * @@ -6377,7 +6357,8 @@ PAL_API void PAL_CALL palCmdSetStencilOp( /** * @brief Create an acceleration structure. * - * The graphics system must be initialized before this call. + * + * The created acceleration structure must be destroyed using `palDestroyAccelerationStructure()`. * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6393,7 +6374,7 @@ PAL_API void PAL_CALL palCmdSetStencilOp( * Thread safety: Thread safe if `device` is externally synchronized. * * @since 2.0 - * @sa palDestroyAccelerationstructure + * @sa palDestroyAccelerationStructure */ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( PalDevice* device, @@ -6403,7 +6384,7 @@ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( /** * @brief Destroy an acceleration structure. * - * The graphics system must be initialized before this call. + * * * @param[in] as Acceleration structure to destroy. * @@ -6413,12 +6394,12 @@ PAL_API PalResult PAL_CALL palCreateAccelerationstructure( * @since 2.0 * @sa palCreateAccelerationstructure */ -PAL_API void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* as); +PAL_API void PAL_CALL palDestroyAccelerationStructure(PalAccelerationStructure* as); /** * @brief Get the build size of an acceleration structure. * - * The graphics system must be initialized before this call. + * * PalAccelerationStructureBuildInfo::dst, PalAccelerationStructureBuildInfo::scratchBufferAddress * and PalAccelerationStructureBuildInfo::src must be set to `nullptr`. * @@ -6441,7 +6422,8 @@ PAL_API void PAL_CALL palGetAccelerationStructureBuildSize( /** * @brief Create a buffer. * - * The graphics system must be initialized before this call. + * + * The created buffer must be destroyed using `palDestroyBuffer()`. * * `PAL_ADAPTER_FEATURE_BUFFER_DEVICE_ADDRESS` must be supported and enabled by the devic. * Otherwise behavior is undefined. @@ -6473,7 +6455,7 @@ PAL_API PalResult PAL_CALL palCreateBuffer( /** * @brief Destroy a buffer. * - * The graphics system must be initialized before this call. + * * * @param[in] buffer buffer to destroy. * @@ -6488,7 +6470,7 @@ PAL_API void PAL_CALL palDestroyBuffer(PalBuffer* buffer); /** * @brief Get memory requirements for the provided buffer. * - * The graphics system must be initialized before this call. + * * * @param[in] buffer Buffer to query memory requirements on. * @param[out] requirements Pointer to a PalMemoryRequirements to fill. @@ -6504,7 +6486,7 @@ PAL_API void PAL_CALL palGetBufferMemoryRequirements( /** * @brief Compute size for an acceleration structure instance buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6529,7 +6511,7 @@ PAL_API void PAL_CALL palComputeInstanceStagingSize( /** * @brief Compute requirements for an image staging buffer. * - * The graphics system must be initialized before this call. This does not allocate memory + * This does not allocate memory * for the buffer. This function is required for all image copy staging buffers. * * `PalBufferImageCopyInfo::bufferRowLength` and `PalBufferImageCopyInfo::bufferImageHeight` @@ -6556,7 +6538,7 @@ PAL_API void PAL_CALL palComputeImageStagingRequirements( /** * @brief Write data to an instance staging buffer. * - * The graphics system must be initialized before this call. + * * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6580,7 +6562,7 @@ PAL_API void PAL_CALL palWriteInstanceStaging( /** * @brief Write data to an image staging buffer. * - * The graphics system must be initialized before this call. + * * * @param[in] device The device to use. * @param[in] imageFormat Destination image format. @@ -6603,7 +6585,7 @@ PAL_API void PAL_CALL palWriteImageStaging( /** * @brief Bind an allocated memory to a buffer. * - * The graphics system must be initialized before this call. + * * The memory size and alignment should match the requirements of the buffer. * Get the requirements with palGetBufferMemoryRequirements(). * @@ -6627,7 +6609,7 @@ PAL_API PalResult PAL_CALL palBindBufferMemory( /** * @brief Maps buffer to CPU visible address space. * - * The graphics system must be initialized before this call. The buffer must have a valid + * The buffer must have a valid * memory bound to it before this call. * * Only `PAL_MEMORY_TYPE_CPU_UPLOAD` and `PAL_MEMORY_TYPE_CPU_READBACK` can be mapped to @@ -6659,7 +6641,7 @@ PAL_API PalResult PAL_CALL palMapBuffer( /** * @brief Unmap buffer from CPU visible address space. * - * The graphics system must be initialized before this call. The buffer must be mapped + * The buffer must be mapped * before this call. After this call, the CPU pointer must not be used anymore. * * @param[in] buffer Pointer to buffer to unmap. @@ -6674,7 +6656,7 @@ PAL_API void PAL_CALL palUnmapBuffer(PalBuffer* buffer); /** * @brief Get the device address of the provided buffer. * - * The graphics system must be initialized before this call. Buffer must have + * Buffer must have * `PAL_BUFFER_USAGE_DEVICE_ADDRESS` usage flag. * * @param[in] buffer Buffer to get its device address. @@ -6690,7 +6672,8 @@ PAL_API PalDeviceAddress PAL_CALL palGetBufferDeviceAddress(PalBuffer* buffer); /** * @brief Create a descriptor set layout that defines the bindings used by descriptor sets. * - * The graphics system must be initialized before this call. + * + * The created descriptor set layout must be destroyed using `palDestroyDescriptorSetLayout()`. * * This defines the layout, ordering and the number of descriptors a descriptor set uses. * @@ -6718,7 +6701,7 @@ PAL_API PalResult PAL_CALL palCreateDescriptorSetLayout( /** * @brief Destroy a descriptor set layout. * - * The graphics system must be initialized before this call. + * * * @param[in] layout Descriptor set layout to destroy. * @@ -6733,7 +6716,8 @@ PAL_API void PAL_CALL palDestroyDescriptorSetLayout(PalDescriptorSetLayout* layo /** * @brief Create a descriptor pool to allocate descriptor sets. * - * The graphics system must be initialized before this call. + * + * The created descriptor pool must be destroyed using `palDestroyDescriptorPool()`. * * @param[in] device Device that creates the descriptor pool. * @param[in] info Pointer to a PalDescriptorPoolCreateInfo struct that specifies parameters. @@ -6755,7 +6739,7 @@ PAL_API PalResult PAL_CALL palCreateDescriptorPool( /** * @brief Destroy a descriptor pool. * - * The graphics system must be initialized before this call. + * * * @param[in] pool Descriptor pool to destroy. * @@ -6770,7 +6754,7 @@ PAL_API void PAL_CALL palDestroyDescriptorPool(PalDescriptorPool* pool); /** * @brief Reset the provided descriptor pool. This resets all allocated descriptor sets. * - * The graphics system must be initialized before this call. + * * * @param[in] pool Descriptor pool to reset. * @@ -6786,7 +6770,7 @@ PAL_API PalResult PAL_CALL palResetDescriptorPool(PalDescriptorPool* pool); /** * @brief Allocate a descriptor set from the provided descriptor pool. * - * The graphics system must be initialized before this call. The descriptor set will be + * The descriptor set will be * allocated uninitialized therefore update it before use except the case where descriptor * indexing is enabled. * @@ -6814,7 +6798,7 @@ PAL_API PalResult PAL_CALL palAllocateDescriptorSet( /** * @brief Update a descriptor set with descriptors (resources). * - * The graphics system must be initialized before this call. + * * * If the write info has no valid resource handle, then `PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS` * must be supported and enabled when creating the device. Otherwise behavior is undefined. @@ -6839,7 +6823,8 @@ PAL_API PalResult PAL_CALL palUpdateDescriptorSet( * @brief Create a pipeline layout. This defines the descriptor set interfaces and push * constant ranges. * - * The graphics system must be initialized before this call. + * + * The created pipeline layout must be destroyed using `palDestroyPipelineLayout()`. * * @param[in] device Device that creates the pipeline layout. * @param[in] info Pointer to a PalPipelineLayoutCreateInfo struct that specifies parameters. @@ -6861,7 +6846,7 @@ PAL_API PalResult PAL_CALL palCreatePipelineLayout( /** * @brief Destroy a pipeline layout. * - * The graphics system must be initialized before this call. + * * * @param[in] layout Pipeline layout to destroy. * @@ -6876,7 +6861,8 @@ PAL_API void PAL_CALL palDestroyPipelineLayout(PalPipelineLayout* layout); /** * @brief Create a graphics pipeline. * - * The graphics system must be initialized before this call. + * + * The created pipeline must be destroyed using `palDestroyPipeline()`. * * @param[in] device Device that creates the graphics pipeline. * @param[in] info Pointer to a PalGraphicsPipelineCreateInfo struct that specifies parameters. @@ -6898,7 +6884,8 @@ PAL_API PalResult PAL_CALL palCreateGraphicsPipeline( /** * @brief Create a compute pipeline. * - * The graphics system must be initialized before this call. + * + * The created pipeline must be destroyed using `palDestroyPipeline()`. * * @param[in] device Device that creates the compute pipeline. * @param[in] info Pointer to a PalComputePipelineCreateInfo struct that specifies parameters. @@ -6922,7 +6909,8 @@ PAL_API PalResult PAL_CALL palCreateComputePipeline( /** * @brief Create a ray tracing pipeline. * - * The graphics system must be initialized before this call. + * + * The created pipeline must be destroyed using `palDestroyPipeline()`. * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6949,7 +6937,7 @@ PAL_API PalResult PAL_CALL palCreateRayTracingPipeline( /** * @brief Destroy a pipeline. * - * The graphics system must be initialized before this call. + * * * @param[in] pipeline Pipeline to destroy. * @@ -6966,7 +6954,8 @@ PAL_API void PAL_CALL palDestroyPipeline(PalPipeline* pipeline); /** * @brief Create a shader binding table. * - * The graphics system must be initialized before this call. + * + * The created shader binding table must be destroyed using `palDestroyShaderBindingTable()`. * * `PAL_ADAPTER_FEATURE_RAY_TRACING` must be supported and enabled by the device. * Otherwise behavior is undefined. @@ -6997,7 +6986,7 @@ PAL_API PalResult PAL_CALL palCreateShaderBindingTable( /** * @brief Destroy a shader binding table. * - * The graphics system must be initialized before this call. + * * * @param[in] sbt Shader binding table to destroy. * @@ -7012,7 +7001,7 @@ PAL_API void PAL_CALL palDestroyShaderBindingTable(PalShaderBindingTable* sbt); /** * @brief Update a shader binding table record payloads. * - * The graphics system must be initialized before this call. + * * * This call does not update shader handles. It only updates the payload associated * with the record. PalShaderBindingTableRecordInfo::groupIndex is the index into diff --git a/include/pal/pal_video.h b/include/pal/pal_video.h index a7c26da5..2893604a 100644 --- a/include/pal/pal_video.h +++ b/include/pal/pal_video.h @@ -642,8 +642,6 @@ PAL_API void PAL_CALL palUpdateVideo(); /** * @brief Get the supported features of the video system. * - * The video system must be initialized before this call. - * * @return video features on success or `0` on failure. * * Thread safety: Thread safe. @@ -686,7 +684,7 @@ PAL_API PalResult PAL_CALL palEnumerateMonitors( /** * @brief Get the primary connected monitor. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_MONITOR_GET_PRIMARY` must be supported otherwise undefined behavior. * * The monitor handle must not be freed by the user, they are managed by the @@ -705,7 +703,7 @@ PAL_API void PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor); /** * @brief Get information about a monitor. * - * The video system must be initialized before this call. + * * * This function takes in a PalMonitorInfo and fills it. * Some of the fields are set to defaults if the operation is not supported on @@ -726,7 +724,7 @@ PAL_API void PAL_CALL palGetMonitorInfo( * @brief Return a list of all supported monitor display modes for the provided * monitor. * - * The video system must be initialized before this call. + * * * Call this function first with PalMonitorMode array set to `nullptr` to get the * number of supported monitor display modes. Allocate memory for the @@ -750,7 +748,7 @@ PAL_API void PAL_CALL palEnumerateMonitorModes( /** * @brief Get the current monitor display mode of the provided monitor. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_MONITOR_GET_MODE` must be supported otherwise undefined behavior. * * @param[in] monitor Monitor to query its current display mode. @@ -769,7 +767,7 @@ PAL_API void PAL_CALL palGetCurrentMonitorMode( /** * @brief Set the active display monitor mode of the provided monitor. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_MONITOR_SET_MODE` Must be supported otherwise undefined behavior. * * PAL only validates the monitor display mode pointer not the values. To be @@ -798,7 +796,7 @@ PAL_API PalResult PAL_CALL palSetMonitorMode( /** * @brief Check if a monitor display mode is valid on the provided monitor. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_MONITOR_VALIDATE_MODE` must be supported otherwise undefined behavior. * * @param[in] monitor The monitor. @@ -818,7 +816,7 @@ PAL_API PalResult PAL_CALL palValidateMonitorMode( /** * @brief Set the orientation for a monitor. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_MONITOR_SET_ORIENTATION` must be supported otherwise undefined behavior. * * This change is temporary and is reset when the platform (OS) reboots. @@ -840,7 +838,7 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( /** * @brief Create a window. * - * The video system must be initialized before this call. + * * * `PalWindowCreateInfo::fbConfigIndex` is the loop index from the drivers supported FBConfigs. * `PalWindowCreateInfo::fbConfigBackend` is used to tell the video system the source of @@ -880,7 +878,7 @@ PAL_API PalResult PAL_CALL palCreateWindow( /** * @brief Destroy the provided window. * - * The video system must be initialized before this call. + * * This only destroys windows created by PAL. * * @param[in] window Pointer to the window to destroy. @@ -895,7 +893,7 @@ PAL_API void PAL_CALL palDestroyWindow(PalWindow* window); /** * @brief Minimize a maximized or restored window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_STATE` must be supported otherwise undefined behavior. * If the window is already minimized, this functions does nothing. * @@ -912,7 +910,7 @@ PAL_API void PAL_CALL palMinimizeWindow(PalWindow* window); /** * @brief Maximize a minimized or restored window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_STATE` must be supported otherwise undefined behavior. * If the window is already maximized, this functions does nothing. * @@ -929,7 +927,7 @@ PAL_API void PAL_CALL palMaximizeWindow(PalWindow* window); /** * @brief Restores a window to it previous state. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_STATE` must be supported otherwise undefined behavior. * If the window is already restored, this functions does nothing. * @@ -948,7 +946,7 @@ PAL_API void PAL_CALL palRestoreWindow(PalWindow* window); /** * @brief Show the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY` must be supported otherwise undefined behavior. * All windows are created hidden if not explicitly shown. * This does nothing if the window is already shown. @@ -965,7 +963,7 @@ PAL_API void PAL_CALL palShowWindow(PalWindow* window); /** * @brief Hide the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_VISIBILITY` must be supported otherwise undefined behavior. * This does nothing if the window is already hidden. * @@ -981,7 +979,7 @@ PAL_API void PAL_CALL palHideWindow(PalWindow* window); /** * @brief Request the platform (OS) to visually flash the provided window. * - * The video system must be initialized before this call. + * * * If `PAL_FLASH_FLAG_CAPTION` is used, `PAL_VIDEO_FEATURE_WINDOW_FLASH_CAPTION` must * be supported. @@ -1003,7 +1001,7 @@ PAL_API void PAL_CALL palFlashWindow( /** * @brief Get the style of the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_GET_STYLE` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1021,7 +1019,7 @@ PAL_API void PAL_CALL palGetWindowStyle( /** * @brief Get the monitor the provided window is currently on. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_GET_MONITOR` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1038,7 +1036,7 @@ PAL_API void PAL_CALL palGetWindowMonitor( /** * @brief Get the title of the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_GET_TITLE` must be supported otherwise undefined behavior. * * Set the buffer to `nullptr` to get the size of the window name in bytes. @@ -1065,7 +1063,7 @@ PAL_API void PAL_CALL palGetWindowTitle( /** * @brief Get the position of the provided window in pixels. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_GET_POS` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1085,7 +1083,7 @@ PAL_API void PAL_CALL palGetWindowPos( /** * @brief Get the size of the provided window in pixels. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_GET_SIZE` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1105,7 +1103,7 @@ PAL_API void PAL_CALL palGetWindowSize( /** * @brief Get the state of the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_GET_STATE` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1123,7 +1121,7 @@ PAL_API void PAL_CALL palGetWindowState( * @brief Get the state of the keycodes (layout aware keys) of the * keyboard. * - * The video system must be initialized before this call. + * * * The returned pointer must not be freed. The state is updated when * palUpdateVideo() is called. The array must be index with PalKeycodes and @@ -1141,7 +1139,7 @@ PAL_API const PalBool* PAL_CALL palGetKeycodeState(); * @brief Get the state of the scancodes (layout independent keys) of * the keyboard. * - * The video system must be initialized before this call. + * * * The returned pointer must not be freed. The state is updated when * palUpdateVideo() is called. The array must be index with PalScancodes and @@ -1158,7 +1156,7 @@ PAL_API const PalBool* PAL_CALL palGetScancodeState(); /** * @brief Get the state of the buttons of the mouse. * - * The video system must be initialized before this call. + * * * The returned pointer must not be freed. The state is updated when * palUpdateVideo() is called. The array must be index with PalMouseButton and @@ -1175,7 +1173,7 @@ PAL_API const PalBool* PAL_CALL palGetMouseState(); /** * @brief Get the relative movement of the mouse in desktop pixels. * - * The video system must be initialized before this call. + * * The relative movement will be updated when palUpdateVideo() is called. * * @param[in] dx Pointer to recieve the mouse relative movement x. Can be @@ -1195,7 +1193,7 @@ PAL_API void PAL_CALL palGetMouseDelta( /** * @brief Get the wheel delta of the mouse. * - * The video system must be initialized before this call. + * * The wheel delta will be updated when palUpdateVideo() is called. * * @param[in] dx Pointer to recieve the mouse wheel delta x. Can be `nullptr`. @@ -1213,7 +1211,7 @@ PAL_API void PAL_CALL palGetMouseWheelDelta( /** * @brief Check if the provided window is visible. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_GET_VISIBILITY` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1229,7 +1227,7 @@ PAL_API PalBool PAL_CALL palIsWindowVisible(PalWindow* window); /** * @brief Get the current input-focused window per application. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_GET_INPUT_FOCUS` must be supported otherwise undefined behavior. * * @return The current input-focused window on success or `nullptr` on @@ -1244,7 +1242,7 @@ PAL_API PalWindow* PAL_CALL palGetFocusWindow(); /** * @brief Get the native handle of the provided window. * - * The video system must be initialized before this call. + * * * On Wayland: `::nativeHandle1`, `::nativeHandle2` and `::nativeHandle3` * are `xdg_surface`, `xdg_toplevel` and `wl_egl_window` respectively if available. @@ -1263,7 +1261,7 @@ PAL_API void PAL_CALL palGetWindowHandleInfo( /** * @brief Set the opacity of the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_TRANSPARENT_WINDOW` must be supported otherwise undefined behavior. * The window must have `PAL_WINDOW_STYLE_TRANSPARENT` style. * @@ -1281,7 +1279,7 @@ PAL_API void PAL_CALL palSetWindowOpacity( /** * @brief Set the style of the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_STYLE` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1299,7 +1297,7 @@ PAL_API void PAL_CALL palSetWindowStyle( /** * @brief Set the title of the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_TITLE` must be supported otherwise undefined behavior. * The title must be a UTF-8 encoding null terminated string. * @@ -1318,7 +1316,7 @@ PAL_API void PAL_CALL palSetWindowTitle( /** * @brief Set the position of the provided window in pixels. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_POS` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1338,7 +1336,7 @@ PAL_API void PAL_CALL palSetWindowPos( /** * @brief Set the size of the provided window in pixels. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_SIZE` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1360,7 +1358,7 @@ PAL_API void PAL_CALL palSetWindowSize( /** * @brief Request input focus for the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_INPUT_FOCUS` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1375,7 +1373,7 @@ PAL_API void PAL_CALL palSetFocusWindow(PalWindow* window); /** * @brief Create an icon. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported otherwise undefined behavior. * * @param[in] info Pointer to a PalIconCreateInfo struct that specifies parameters. @@ -1396,7 +1394,7 @@ PAL_API PalResult PAL_CALL palCreateIcon( /** * @brief Destroy the provided icon. * - * The video system must be initialized before this call. + * * * @param[in] icon Pointer to the icon to destroy. * @@ -1410,7 +1408,7 @@ PAL_API void PAL_CALL palDestroyIcon(PalIcon* icon); /** * @brief Set the icon for the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_WINDOW_SET_ICON` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1427,7 +1425,7 @@ PAL_API void PAL_CALL palSetWindowIcon( /** * @brief Create a cursor. * - * The video system must be initialized before this call. + * * * @param[in] info Pointer to a PalCursorCreateInfo struct that specifies parameters. * @param[out] outCursor Pointer to a PalCursor to recieve the created cursor. @@ -1447,7 +1445,7 @@ PAL_API PalResult PAL_CALL palCreateCursor( /** * @brief Create a system cursor. * - * The video system must be initialized before this call. + * * * @param[in] type The system cursor type to create. * @param[out] outCursor Pointer to a PalCursor to recieve the created cursor. @@ -1467,7 +1465,7 @@ PAL_API PalResult PAL_CALL palCreateCursorFrom( /** * @brief Destroy the provided cursor. * - * The video system must be initialized before this call. + * * * @param[in] cursor Pointer to the cursor to destroy. * @@ -1481,7 +1479,7 @@ PAL_API void PAL_CALL palDestroyCursor(PalCursor* cursor); /** * @brief Show or hide the cursor. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_CURSOR_SET_VISIBILITY` must be supported otherwise undefined behavior. * * This affects all created cursors since the platform (OS) merges all cursors @@ -1498,7 +1496,7 @@ PAL_API void PAL_CALL palShowCursor(PalBool show); /** * @brief Clip the cursor to the provided window. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_CLIP_CURSOR` must be supported otherwise undefined behavior. * * If the window is destroyed without unclipping the cursor, this cursor might @@ -1520,7 +1518,7 @@ PAL_API void PAL_CALL palClipCursor( * @brief Get the position of the cursor relative to the provided window in * pixels. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_CURSOR_GET_POS` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1542,7 +1540,7 @@ PAL_API void PAL_CALL palGetCursorPos( * @brief Set the position of the cursor relative to the provided window in * pixels. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_CURSOR_SET_POS` must be supported otherwise undefined behavior. * * @param[in] window Pointer to the window. @@ -1561,7 +1559,7 @@ PAL_API void PAL_CALL palSetCursorPos( /** * @brief Set the cursor for the provided window. * - * The video system must be initialized before this call. + * * * @param[in] window Pointer to the window. * @param[in] cursor Pointer to the cursor. Set to `nullptr` to revert. @@ -1577,7 +1575,7 @@ PAL_API void PAL_CALL palSetWindowCursor( /** * @brief Get the native application instance or display. * - * The video system must be initialized before this call. + * * * This returns the native instance or display of the application * PAL video was initialized in. @@ -1599,7 +1597,7 @@ PAL_API void* PAL_CALL palGetInstance(); /** * @brief Attach a foreign or native window to PAL video system. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_FOREIGN_WINDOWS` must be supported otherwise undefined behavior. * * This function registers the provided window with PAL video system so it @@ -1638,7 +1636,7 @@ PAL_API PalResult PAL_CALL palAttachWindow( /** * @brief Detach a foreign or native window from PAL video system. * - * The video system must be initialized before this call. + * * `PAL_VIDEO_FEATURE_FOREIGN_WINDOWS` must be supported otherwise undefined behavior. * * This function unregisters the provided window from PAL video system. diff --git a/src/graphics/d3d12/pal_adapter_d3d12.c b/src/graphics/d3d12/pal_adapter_d3d12.c index aae4bb1a..a7046e9a 100644 --- a/src/graphics/d3d12/pal_adapter_d3d12.c +++ b/src/graphics/d3d12/pal_adapter_d3d12.c @@ -120,14 +120,14 @@ void PAL_CALL getAdapterInfoD3D12( PalAdapterInfo* info) { HRESULT result = 0; - AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + AdapterD3D12* adapterImpl = (AdapterD3D12*)adapter; DXGI_ADAPTER_DESC3 desc; D3D12_FEATURE_DATA_ARCHITECTURE1 arch = {0}; - ID3D12Device* device = d3d12Adapter->tmpDevice; + ID3D12Device* device = adapterImpl->tmpDevice; D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; - d3d12Adapter->handle->lpVtbl->GetDesc3(d3d12Adapter->handle, &desc); + adapterImpl->handle->lpVtbl->GetDesc3(adapterImpl->handle, &desc); result = device->lpVtbl->CheckFeatureSupport( device, @@ -142,8 +142,8 @@ void PAL_CALL getAdapterInfoD3D12( LARGE_INTEGER driverVersion = {0}; info->driverVersion = 0; - result = d3d12Adapter->handle->lpVtbl->CheckInterfaceSupport( - d3d12Adapter->handle, + result = adapterImpl->handle->lpVtbl->CheckInterfaceSupport( + adapterImpl->handle, &IID_Adapter, &driverVersion); @@ -192,7 +192,7 @@ void PAL_CALL getAdapterCapabilitiesD3D12( PalAdapter* adapter, PalAdapterCapabilities* caps) { - AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + AdapterD3D12* adapterImpl = (AdapterD3D12*)adapter; PalViewportCapabilities* viewportCaps = &caps->viewportCaps; PalImageCapabilities* imageCaps = &caps->imageCaps; PalResourceCapabilities* resourceCaps = &caps->resourceCaps; @@ -240,7 +240,7 @@ void PAL_CALL getAdapterCapabilitiesD3D12( // resource limits // always supported - getDescriptorTierLimitsD3D12(d3d12Adapter->tmpDevice, resourceCaps, nullptr); + getDescriptorTierLimitsD3D12(adapterImpl->tmpDevice, resourceCaps, nullptr); resourceCaps->maxBoundSets = 32; // compute limits @@ -256,9 +256,9 @@ void PAL_CALL getAdapterCapabilitiesD3D12( PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) { HRESULT result; - AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + AdapterD3D12* adapterImpl = (AdapterD3D12*)adapter; PalAdapterFeatures features = 0; - ID3D12Device* device = d3d12Adapter->tmpDevice; + ID3D12Device* device = adapterImpl->tmpDevice; D3D12_FEATURE_DATA_D3D12_OPTIONS options = {0}; D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {0}; @@ -376,7 +376,7 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesD3D12(PalAdapter* adapter) features |= PAL_ADAPTER_FEATURE_IMAGE_VIEW_CUBE_ARRAY; features |= PAL_ADAPTER_FEATURE_NULL_DESCRIPTORS; - if (d3d12Adapter->level >= D3D_FEATURE_LEVEL_12_0) { + if (adapterImpl->level >= D3D_FEATURE_LEVEL_12_0) { features |= PAL_ADAPTER_FEATURE_DEPTH_STENCIL_RESOLVE; } return features; @@ -394,7 +394,7 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( return PAL_MAKE_SHADER_TARGET(5, 1); } - AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + AdapterD3D12* adapterImpl = (AdapterD3D12*)adapter; D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {0}; D3D_SHADER_MODEL models[11]; @@ -415,8 +415,8 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetD3D12( D3D_SHADER_MODEL highestModel = D3D_SHADER_MODEL_5_1; for (int i = 0; i < 11; i++) { shaderModel.HighestShaderModel = models[i]; - result = d3d12Adapter->tmpDevice->lpVtbl->CheckFeatureSupport( - d3d12Adapter->tmpDevice, + result = adapterImpl->tmpDevice->lpVtbl->CheckFeatureSupport( + adapterImpl->tmpDevice, D3D12_FEATURE_SHADER_MODEL, &shaderModel, sizeof(shaderModel)); @@ -471,8 +471,8 @@ void PAL_CALL enumerateFormatsD3D12( PalFormatInfo* outFormats) { int32_t fmtCount = 0; - AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; - ID3D12Device* device = d3d12Adapter->tmpDevice; + AdapterD3D12* adapterImpl = (AdapterD3D12*)adapter; + ID3D12Device* device = adapterImpl->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; for (int i = 0; i < PAL_FORMAT_COUNT; i++) { @@ -510,8 +510,8 @@ PalBool PAL_CALL isFormatSupportedD3D12( PalAdapter* adapter, PalFormat format) { - AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; - ID3D12Device* device = d3d12Adapter->tmpDevice; + AdapterD3D12* adapterImpl = (AdapterD3D12*)adapter; + ID3D12Device* device = adapterImpl->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; DXGI_FORMAT fmt = formatToD3D12(format); @@ -535,8 +535,8 @@ PalImageUsages PAL_CALL queryFormatImageUsagesD3D12( PalFormat format) { HRESULT result; - AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; - ID3D12Device* device = d3d12Adapter->tmpDevice; + AdapterD3D12* adapterImpl = (AdapterD3D12*)adapter; + ID3D12Device* device = adapterImpl->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; DXGI_FORMAT fmt = formatToD3D12(format); @@ -574,8 +574,8 @@ PalSampleCount PAL_CALL queryFormatSampleCountD3D12( PalFormat format) { HRESULT result; - AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; - ID3D12Device* device = d3d12Adapter->tmpDevice; + AdapterD3D12* adapterImpl = (AdapterD3D12*)adapter; + ID3D12Device* device = adapterImpl->tmpDevice; D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {0}; DXGI_FORMAT fmt = formatToD3D12(format); diff --git a/src/graphics/d3d12/pal_as_d3d12.c b/src/graphics/d3d12/pal_as_d3d12.c index f4633890..8a9eb20d 100644 --- a/src/graphics/d3d12/pal_as_d3d12.c +++ b/src/graphics/d3d12/pal_as_d3d12.c @@ -15,8 +15,8 @@ PalResult PAL_CALL createAccelerationstructureD3D12( { HRESULT result; AccelerationStructureD3D12* as = nullptr; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - BufferD3D12* d3d12Buffer = (BufferD3D12*)info->buffer; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; + BufferD3D12* bufferImpl = (BufferD3D12*)info->buffer; as = palAllocate(s_D3D12.allocator, sizeof(AccelerationStructureD3D12), 0); if (!as) { @@ -24,7 +24,7 @@ PalResult PAL_CALL createAccelerationstructureD3D12( } as->type = info->type; - as->handle = d3d12Buffer->handle; + as->handle = bufferImpl->handle; as->address = as->handle->lpVtbl->GetGPUVirtualAddress(as->handle); as->address += info->offset; *outAs = (PalAccelerationStructure*)as; @@ -33,8 +33,8 @@ PalResult PAL_CALL createAccelerationstructureD3D12( void PAL_CALL destroyAccelerationstructureD3D12(PalAccelerationStructure* as) { - AccelerationStructureD3D12* d3dAs = (AccelerationStructureD3D12*)as; - palFree(s_D3D12.allocator, d3dAs); + AccelerationStructureD3D12* asImpl = (AccelerationStructureD3D12*)as; + palFree(s_D3D12.allocator, asImpl); } void PAL_CALL getAccelerationStructureBuildSizeD3D12( @@ -42,7 +42,7 @@ void PAL_CALL getAccelerationStructureBuildSizeD3D12( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO sizeInfo = {0}; @@ -58,8 +58,8 @@ void PAL_CALL getAccelerationStructureBuildSizeD3D12( memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count); fillBuildInfoD3D12(PAL_TRUE, info, geometries, &buildInfo); - d3d12Device->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( - d3d12Device->handle, + deviceImpl->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( + deviceImpl->handle, &buildInfo.Inputs, &sizeInfo); @@ -68,8 +68,8 @@ void PAL_CALL getAccelerationStructureBuildSizeD3D12( } else { fillBuildInfoD3D12(PAL_TRUE, info, nullptr, &buildInfo); - d3d12Device->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( - d3d12Device->handle, + deviceImpl->handle->lpVtbl->GetRaytracingAccelerationStructurePrebuildInfo( + deviceImpl->handle, &buildInfo.Inputs, &sizeInfo); } diff --git a/src/graphics/d3d12/pal_buffer_d3d12.c b/src/graphics/d3d12/pal_buffer_d3d12.c index d975263e..dc079b3b 100644 --- a/src/graphics/d3d12/pal_buffer_d3d12.c +++ b/src/graphics/d3d12/pal_buffer_d3d12.c @@ -56,7 +56,7 @@ PalResult PAL_CALL createBufferD3D12( { HRESULT result; BufferD3D12* buffer = nullptr; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; buffer = palAllocate(s_D3D12.allocator, sizeof(BufferD3D12), 0); if (!buffer) { @@ -118,8 +118,8 @@ PalResult PAL_CALL createBufferD3D12( } } - result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateCommittedResource( + deviceImpl->handle, &heapProps, 0, &buffer->desc, @@ -129,14 +129,14 @@ PalResult PAL_CALL createBufferD3D12( (void**)&buffer->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } buffer->isMemoryManaged = PAL_TRUE; } - buffer->device = d3d12Device; + buffer->device = deviceImpl; buffer->usages = info->usages; buffer->size = info->size; *outBuffer = (PalBuffer*)buffer; @@ -145,26 +145,26 @@ PalResult PAL_CALL createBufferD3D12( void PAL_CALL destroyBufferD3D12(PalBuffer* buffer) { - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - if (d3d12Buffer->isMemoryManaged) { - d3d12Buffer->handle->lpVtbl->Release(d3d12Buffer->handle); + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; + if (bufferImpl->isMemoryManaged) { + bufferImpl->handle->lpVtbl->Release(bufferImpl->handle); } - palFree(s_D3D12.allocator, d3d12Buffer); + palFree(s_D3D12.allocator, bufferImpl); } void PAL_CALL getBufferMemoryRequirementsD3D12( PalBuffer* buffer, PalMemoryRequirements* requirements) { - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - ID3D12Device5* device = d3d12Buffer->device->handle; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; + ID3D12Device5* device = bufferImpl->device->handle; D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; allocationInfo = - *device->lpVtbl->GetResourceAllocationInfo(device, &__ret, 0, 1, &d3d12Buffer->desc); + *device->lpVtbl->GetResourceAllocationInfo(device, &__ret, 0, 1, &bufferImpl->desc); - requirements->supportedMemoryTypes = getSupportedMemoryTypes(d3d12Buffer->usages); + requirements->supportedMemoryTypes = getSupportedMemoryTypes(bufferImpl->usages); requirements->alignment = allocationInfo.Alignment; requirements->size = allocationInfo.SizeInBytes; } @@ -251,42 +251,42 @@ PalResult PAL_CALL bindBufferMemoryD3D12( uint64_t offset) { HRESULT result; - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - DeviceD3D12* device = d3d12Buffer->device; - MemoryD3D12* d3d12Memory = (MemoryD3D12*)memory; - if (d3d12Buffer->isMemoryManaged) { + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; + DeviceD3D12* device = bufferImpl->device; + MemoryD3D12* memoryImpl = (MemoryD3D12*)memory; + if (bufferImpl->isMemoryManaged) { return PAL_RESULT_CODE_INVALID_OPERATION; } D3D12_RESOURCE_STATES state = 0; - d3d12Buffer->canStateChange = PAL_TRUE; - if (d3d12Memory->type == PAL_MEMORY_TYPE_CPU_UPLOAD) { + bufferImpl->canStateChange = PAL_TRUE; + if (memoryImpl->type == PAL_MEMORY_TYPE_CPU_UPLOAD) { state = D3D12_RESOURCE_STATE_GENERIC_READ; - d3d12Buffer->canStateChange = PAL_FALSE; + bufferImpl->canStateChange = PAL_FALSE; - } else if (d3d12Memory->type == PAL_MEMORY_TYPE_CPU_UPLOAD) { + } else if (memoryImpl->type == PAL_MEMORY_TYPE_CPU_UPLOAD) { state = D3D12_RESOURCE_STATE_COPY_DEST; - d3d12Buffer->canStateChange = PAL_FALSE; + bufferImpl->canStateChange = PAL_FALSE; } - if (d3d12Buffer->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { + if (bufferImpl->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE) { state = D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE; - d3d12Buffer->canStateChange = PAL_FALSE; + bufferImpl->canStateChange = PAL_FALSE; } - if (d3d12Buffer->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { + if (bufferImpl->usages & PAL_BUFFER_USAGE_ACCELERATION_STRUCTURE_SCRATCH) { state = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; } result = device->handle->lpVtbl->CreatePlacedResource( device->handle, - d3d12Memory->handle, + memoryImpl->handle, offset, - &d3d12Buffer->desc, + &bufferImpl->desc, state, nullptr, &IID_Resource, - (void**)&d3d12Buffer->handle); + (void**)&bufferImpl->handle); if (FAILED(result)) { pollMessagesD3D12(device); @@ -302,9 +302,9 @@ PalResult PAL_CALL mapBufferD3D12( uint64_t size, void** outPtr) { - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; void* ptr = nullptr; - HRESULT result = d3d12Buffer->handle->lpVtbl->Map(d3d12Buffer->handle, 0, nullptr, &ptr); + HRESULT result = bufferImpl->handle->lpVtbl->Map(bufferImpl->handle, 0, nullptr, &ptr); if (FAILED(result)) { return makeResultD3D12(result); } @@ -315,15 +315,15 @@ PalResult PAL_CALL mapBufferD3D12( void PAL_CALL unmapBufferD3D12(PalBuffer* buffer) { - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - d3d12Buffer->handle->lpVtbl->Unmap(d3d12Buffer->handle, 0, nullptr); + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; + bufferImpl->handle->lpVtbl->Unmap(bufferImpl->handle, 0, nullptr); } PalDeviceAddress PAL_CALL getBufferDeviceAddressD3D12(PalBuffer* buffer) { - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - if (d3d12Buffer->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { - return d3d12Buffer->handle->lpVtbl->GetGPUVirtualAddress(d3d12Buffer->handle); + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; + if (bufferImpl->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS) { + return bufferImpl->handle->lpVtbl->GetGPUVirtualAddress(bufferImpl->handle); } return 0; } diff --git a/src/graphics/d3d12/pal_command_pool_d3d12.c b/src/graphics/d3d12/pal_command_pool_d3d12.c index 6e89b319..8356b164 100644 --- a/src/graphics/d3d12/pal_command_pool_d3d12.c +++ b/src/graphics/d3d12/pal_command_pool_d3d12.c @@ -15,14 +15,14 @@ PalResult PAL_CALL createCommandPoolD3D12( { HRESULT result; CommandPoolD3D12* pool = nullptr; - QueueD3D12* d3d12Queue = (QueueD3D12*)queue; + QueueD3D12* queueImpl = (QueueD3D12*)queue; pool = palAllocate(s_D3D12.allocator, sizeof(CommandPoolD3D12), 0); if (!pool) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } - switch (d3d12Queue->type) { + switch (queueImpl->type) { case PAL_QUEUE_TYPE_COMPUTE: { pool->type = D3D12_COMMAND_LIST_TYPE_COMPUTE; break; @@ -56,7 +56,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( PalCommandBuffer** outCmdBuffer) { HRESULT result; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; CommandBufferD3D12* cmdBuffer = nullptr; CommandPoolD3D12* cmdPool = (CommandPoolD3D12*)pool; @@ -83,21 +83,21 @@ PalResult PAL_CALL allocateCommandBufferD3D12( } // create an allocator - result = d3d12Device->handle->lpVtbl->CreateCommandAllocator( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateCommandAllocator( + deviceImpl->handle, cmdBufferType, &IID_CommandAllocator, (void**)&cmdBuffer->allocator); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } // create the command list ID3D12GraphicsCommandList* cmdList = nullptr; - result = d3d12Device->handle->lpVtbl->CreateCommandList( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateCommandList( + deviceImpl->handle, 0, cmdBufferType, cmdBuffer->allocator, @@ -106,7 +106,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdList); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -125,8 +125,8 @@ PalResult PAL_CALL allocateCommandBufferD3D12( bufferDesc.SampleDesc.Count = 1; bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateCommittedResource( + deviceImpl->handle, &heapProps, 0, &bufferDesc, @@ -136,14 +136,14 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdBuffer->buffer); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } // create staging buffer heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateCommittedResource( + deviceImpl->handle, &heapProps, 0, &bufferDesc, @@ -153,7 +153,7 @@ PalResult PAL_CALL allocateCommandBufferD3D12( (void**)&cmdBuffer->stagingBuffer); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -161,55 +161,55 @@ PalResult PAL_CALL allocateCommandBufferD3D12( cmdList->lpVtbl->QueryInterface(cmdList, &IID_CommandList6, (void**)&cmdBuffer->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } cmdList->lpVtbl->Release(cmdList); cmdBuffer->handle->lpVtbl->Close(cmdBuffer->handle); - cmdBuffer->device = d3d12Device; + cmdBuffer->device = deviceImpl; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; } void PAL_CALL freeCommandBufferD3D12(PalCommandBuffer* cmdBuffer) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - d3d12CmdBuffer->handle->lpVtbl->Release(d3d12CmdBuffer->handle); - d3d12CmdBuffer->allocator->lpVtbl->Release(d3d12CmdBuffer->allocator); - d3d12CmdBuffer->buffer->lpVtbl->Release(d3d12CmdBuffer->buffer); - d3d12CmdBuffer->stagingBuffer->lpVtbl->Release(d3d12CmdBuffer->stagingBuffer); - - palFree(s_D3D12.allocator, (void*)d3d12CmdBuffer->linearAllocator.memory); - palFree(s_D3D12.allocator, d3d12CmdBuffer); + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + cmdBufferImpl->handle->lpVtbl->Release(cmdBufferImpl->handle); + cmdBufferImpl->allocator->lpVtbl->Release(cmdBufferImpl->allocator); + cmdBufferImpl->buffer->lpVtbl->Release(cmdBufferImpl->buffer); + cmdBufferImpl->stagingBuffer->lpVtbl->Release(cmdBufferImpl->stagingBuffer); + + palFree(s_D3D12.allocator, (void*)cmdBufferImpl->linearAllocator.memory); + palFree(s_D3D12.allocator, cmdBufferImpl); } PalResult PAL_CALL resetCommandBufferD3D12(PalCommandBuffer* cmdBuffer) { HRESULT result; - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - result = d3d12CmdBuffer->allocator->lpVtbl->Reset(d3d12CmdBuffer->allocator); + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + result = cmdBufferImpl->allocator->lpVtbl->Reset(cmdBufferImpl->allocator); if (FAILED(result)) { return makeResultD3D12(result); } - result = d3d12CmdBuffer->handle->lpVtbl->Reset( - d3d12CmdBuffer->handle, - d3d12CmdBuffer->allocator, + result = cmdBufferImpl->handle->lpVtbl->Reset( + cmdBufferImpl->handle, + cmdBufferImpl->allocator, nullptr); if (FAILED(result)) { return makeResultD3D12(result); } - result = d3d12CmdBuffer->handle->lpVtbl->Close(d3d12CmdBuffer->handle); + result = cmdBufferImpl->handle->lpVtbl->Close(cmdBufferImpl->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12CmdBuffer->device); + pollMessagesD3D12(cmdBufferImpl->device); return makeResultD3D12(result); } - d3d12CmdBuffer->pipeline = nullptr; + cmdBufferImpl->pipeline = nullptr; return PAL_RESULT_SUCCESS; } @@ -218,12 +218,12 @@ PalResult PAL_CALL submitCommandBufferD3D12( PalCommandBufferSubmitInfo* info) { HRESULT ret; - QueueD3D12* d3d12Queue = (QueueD3D12*)queue; - ID3D12CommandQueue* queueHandle = d3d12Queue->handle; - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)info->cmdBuffer; + QueueD3D12* queueImpl = (QueueD3D12*)queue; + ID3D12CommandQueue* queueHandle = queueImpl->handle; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)info->cmdBuffer; // poll pending messages - pollMessagesD3D12(d3d12CmdBuffer->device); + pollMessagesD3D12(cmdBufferImpl->device); // wait semaphore if (info->waitSemaphore) { @@ -249,12 +249,12 @@ PalResult PAL_CALL submitCommandBufferD3D12( } } - ID3D12CommandList* cmdLists[1] = {(ID3D12CommandList*)d3d12CmdBuffer->handle}; + ID3D12CommandList* cmdLists[1] = {(ID3D12CommandList*)cmdBufferImpl->handle}; queueHandle->lpVtbl->ExecuteCommandLists(queueHandle, 1, cmdLists); - pollMessagesD3D12(d3d12CmdBuffer->device); + pollMessagesD3D12(cmdBufferImpl->device); - d3d12Queue->fenceValue++; - ret = queueHandle->lpVtbl->Signal(queueHandle, d3d12Queue->fence, d3d12Queue->fenceValue); + queueImpl->fenceValue++; + ret = queueHandle->lpVtbl->Signal(queueHandle, queueImpl->fence, queueImpl->fenceValue); if (FAILED(ret)) { return makeResultD3D12(ret); } diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index fe40f2b5..8fce796f 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -155,33 +155,33 @@ PalResult PAL_CALL cmdBeginD3D12( PalRenderingLayoutInfo* info) { HRESULT result; - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - result = d3d12CmdBuffer->allocator->lpVtbl->Reset(d3d12CmdBuffer->allocator); + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + result = cmdBufferImpl->allocator->lpVtbl->Reset(cmdBufferImpl->allocator); if (FAILED(result)) { - pollMessagesD3D12(d3d12CmdBuffer->device); + pollMessagesD3D12(cmdBufferImpl->device); return makeResultD3D12(result); } - result = d3d12CmdBuffer->handle->lpVtbl->Reset( - d3d12CmdBuffer->handle, - d3d12CmdBuffer->allocator, + result = cmdBufferImpl->handle->lpVtbl->Reset( + cmdBufferImpl->handle, + cmdBufferImpl->allocator, nullptr); if (FAILED(result)) { - pollMessagesD3D12(d3d12CmdBuffer->device); + pollMessagesD3D12(cmdBufferImpl->device); return makeResultD3D12(result); } - d3d12CmdBuffer->linearAllocator.offset = 0; + cmdBufferImpl->linearAllocator.offset = 0; return PAL_RESULT_SUCCESS; } PalResult PAL_CALL cmdEndD3D12(PalCommandBuffer* cmdBuffer) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - HRESULT result = d3d12CmdBuffer->handle->lpVtbl->Close(d3d12CmdBuffer->handle); + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + HRESULT result = cmdBufferImpl->handle->lpVtbl->Close(cmdBufferImpl->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12CmdBuffer->device); + pollMessagesD3D12(cmdBufferImpl->device); return makeResultD3D12(result); } @@ -192,27 +192,27 @@ void PAL_CALL cmdExecuteCommandBufferD3D12( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { - CommandBufferD3D12* d3dPrimaryCmdBuffer = (CommandBufferD3D12*)primaryCmdBuffer; - CommandBufferD3D12* d3dSecondaryCmdBuffer = (CommandBufferD3D12*)secondaryCmdBuffer; + CommandBufferD3D12* primaryCmdBufferImpl = (CommandBufferD3D12*)primaryCmdBuffer; + CommandBufferD3D12* secondaryCmdBufferImpl = (CommandBufferD3D12*)secondaryCmdBuffer; - d3dPrimaryCmdBuffer->handle->lpVtbl->ExecuteBundle( - d3dPrimaryCmdBuffer->handle, - (ID3D12GraphicsCommandList*)d3dSecondaryCmdBuffer->handle); + primaryCmdBufferImpl->handle->lpVtbl->ExecuteBundle( + primaryCmdBufferImpl->handle, + (ID3D12GraphicsCommandList*)secondaryCmdBufferImpl->handle); } void PAL_CALL cmdSetFragmentShadingRateD3D12( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; D3D12_SHADING_RATE shadingRate = shadingRateToD3D12(state->rate); D3D12_SHADING_RATE_COMBINER combinerOps[2]; for (int i = 0; i < 2; i++) { combinerOps[i] = combinerOpsToD3D12(state->combinerOps[i]); } - d3d12CmdBuffer->handle->lpVtbl->RSSetShadingRate( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->RSSetShadingRate( + cmdBufferImpl->handle, shadingRate, combinerOps); } @@ -223,9 +223,9 @@ void PAL_CALL cmdDrawMeshTasksD3D12( uint32_t groupCountY, uint32_t groupCountZ) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - d3d12CmdBuffer->handle->lpVtbl - ->DispatchMesh(d3d12CmdBuffer->handle, groupCountX, groupCountY, groupCountZ); + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + cmdBufferImpl->handle->lpVtbl + ->DispatchMesh(cmdBufferImpl->handle, groupCountX, groupCountY, groupCountZ); } void PAL_CALL cmdDrawMeshTasksIndirectD3D12( @@ -233,15 +233,15 @@ void PAL_CALL cmdDrawMeshTasksIndirectD3D12( PalBuffer* buffer, uint32_t drawCount) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = cmdBufferImpl->device; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; - d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->ExecuteIndirect( + cmdBufferImpl->handle, device->meshSignature, drawCount, - d3d12Buffer->handle, + bufferImpl->handle, 0, nullptr, 0); @@ -253,18 +253,18 @@ void PAL_CALL cmdDrawMeshTasksIndirectCountD3D12( PalBuffer* countBuffer, uint32_t maxDrawCount) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - BufferD3D12* d3d12CountBuffer = (BufferD3D12*)countBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = cmdBufferImpl->device; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; + BufferD3D12* countBufferImpl = (BufferD3D12*)countBuffer; - d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->ExecuteIndirect( + cmdBufferImpl->handle, device->meshSignature, maxDrawCount, - d3d12Buffer->handle, + bufferImpl->handle, 0, - d3d12CountBuffer->handle, + countBufferImpl->handle, 0); } @@ -272,24 +272,24 @@ void PAL_CALL cmdBuildAccelerationStructureD3D12( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC buildInfo = {0}; if (info->type == PAL_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL) { D3D12_RAYTRACING_GEOMETRY_DESC* geometries = nullptr; geometries = palLinearAlloc( - &d3d12CmdBuffer->linearAllocator, + &cmdBufferImpl->linearAllocator, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count, 0); memset(geometries, 0, sizeof(D3D12_RAYTRACING_GEOMETRY_DESC) * info->count); fillBuildInfoD3D12(PAL_FALSE, info, geometries, &buildInfo); - d3d12CmdBuffer->handle->lpVtbl - ->BuildRaytracingAccelerationStructure(d3d12CmdBuffer->handle, &buildInfo, 0, nullptr); + cmdBufferImpl->handle->lpVtbl + ->BuildRaytracingAccelerationStructure(cmdBufferImpl->handle, &buildInfo, 0, nullptr); } else { fillBuildInfoD3D12(PAL_FALSE, info, nullptr, &buildInfo); - d3d12CmdBuffer->handle->lpVtbl - ->BuildRaytracingAccelerationStructure(d3d12CmdBuffer->handle, &buildInfo, 0, nullptr); + cmdBufferImpl->handle->lpVtbl + ->BuildRaytracingAccelerationStructure(cmdBufferImpl->handle, &buildInfo, 0, nullptr); } } @@ -297,7 +297,7 @@ void PAL_CALL cmdBeginRenderingD3D12( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; D3D12_RENDER_PASS_RENDER_TARGET_DESC colorAttachments[MAX_ATTACHMENTS]; D3D12_RENDER_PASS_DEPTH_STENCIL_DESC depthStencilAttachment = {0}; D3D12_CPU_DESCRIPTOR_HANDLE colorCpuHandles[MAX_ATTACHMENTS]; @@ -437,16 +437,16 @@ void PAL_CALL cmdBeginRenderingD3D12( tmpDesc = &depthStencilAttachment; } - d3d12CmdBuffer->handle->lpVtbl->OMSetRenderTargets( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->OMSetRenderTargets( + cmdBufferImpl->handle, info->colorAttachentCount, colorCpuHandles, PAL_FALSE, tmpCpuHandle); D3D12_RENDER_PASS_FLAGS flags = renderingFlagToD3D12(info->flags); - d3d12CmdBuffer->handle->lpVtbl->BeginRenderPass( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->BeginRenderPass( + cmdBufferImpl->handle, info->colorAttachentCount, colorAttachments, tmpDesc, @@ -455,8 +455,8 @@ void PAL_CALL cmdBeginRenderingD3D12( void PAL_CALL cmdEndRenderingD3D12(PalCommandBuffer* cmdBuffer) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - d3d12CmdBuffer->handle->lpVtbl->EndRenderPass(d3d12CmdBuffer->handle); + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + cmdBufferImpl->handle->lpVtbl->EndRenderPass(cmdBufferImpl->handle); } void PAL_CALL cmdCopyBufferD3D12( @@ -465,11 +465,11 @@ void PAL_CALL cmdCopyBufferD3D12( PalBuffer* src, PalBufferCopyInfo* copyInfo) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; BufferD3D12* dstbuffer = (BufferD3D12*)dst; BufferD3D12* srcBuffer = (BufferD3D12*)src; - d3d12CmdBuffer->handle->lpVtbl->CopyBufferRegion( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->CopyBufferRegion( + cmdBufferImpl->handle, dstbuffer->handle, copyInfo->dstOffset, srcBuffer->handle, @@ -483,7 +483,7 @@ void PAL_CALL cmdCopyBufferToImageD3D12( PalBuffer* srcBuffer, PalBufferImageCopyInfo* copyInfo) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; ImageD3D12* dst = (ImageD3D12*)dstImage; BufferD3D12* src = (BufferD3D12*)srcBuffer; @@ -527,8 +527,8 @@ void PAL_CALL cmdCopyBufferToImageD3D12( uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); dstLocation.SubresourceIndex = index; - d3d12CmdBuffer->handle->lpVtbl->CopyTextureRegion( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->CopyTextureRegion( + cmdBufferImpl->handle, &dstLocation, copyInfo->imageOffsetX, copyInfo->imageOffsetY, @@ -545,7 +545,7 @@ void PAL_CALL cmdCopyImageD3D12( PalImage* src, PalImageCopyInfo* copyInfo) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; ImageD3D12* dstImage = (ImageD3D12*)dst; ImageD3D12* srcImage = (ImageD3D12*)src; @@ -591,8 +591,8 @@ void PAL_CALL cmdCopyImageD3D12( dstLocation.SubresourceIndex = dstIndex; srcLocation.SubresourceIndex = srcIndex; - d3d12CmdBuffer->handle->lpVtbl->CopyTextureRegion( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->CopyTextureRegion( + cmdBufferImpl->handle, &dstLocation, copyInfo->dstOffsetX, copyInfo->dstOffsetY, @@ -609,7 +609,7 @@ void PAL_CALL cmdCopyImageToBufferD3D12( PalImage* srcImage, PalBufferImageCopyInfo* copyInfo) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; BufferD3D12* dst = (BufferD3D12*)dstBuffer; ImageD3D12* src = (ImageD3D12*)srcImage; @@ -655,8 +655,8 @@ void PAL_CALL cmdCopyImageToBufferD3D12( uint32_t index = level + (layer * maxLevels) + (plane * maxLevels * maxLayers); srcLocation.SubresourceIndex = index; - d3d12CmdBuffer->handle->lpVtbl->CopyTextureRegion( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->CopyTextureRegion( + cmdBufferImpl->handle, &dstLocation, 0, 0, @@ -671,45 +671,45 @@ void PAL_CALL cmdBindPipelineD3D12( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - PipelineD3D12* d3dPipeline = (PipelineD3D12*)pipeline; - if (d3dPipeline->type == RAY_TRACING_PIPELINE) { - d3d12CmdBuffer->handle->lpVtbl->SetPipelineState1( - d3d12CmdBuffer->handle, - d3dPipeline->handle); + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + PipelineD3D12* pipelineImpl = (PipelineD3D12*)pipeline; + if (pipelineImpl->type == RAY_TRACING_PIPELINE) { + cmdBufferImpl->handle->lpVtbl->SetPipelineState1( + cmdBufferImpl->handle, + pipelineImpl->handle); - d3d12CmdBuffer->handle->lpVtbl->SetComputeRootSignature( - d3d12CmdBuffer->handle, - d3dPipeline->layout->handle); + cmdBufferImpl->handle->lpVtbl->SetComputeRootSignature( + cmdBufferImpl->handle, + pipelineImpl->layout->handle); } else { - d3d12CmdBuffer->handle->lpVtbl->SetPipelineState( - d3d12CmdBuffer->handle, - d3dPipeline->handle); - - d3d12CmdBuffer->handle->lpVtbl->SetComputeRootSignature( - d3d12CmdBuffer->handle, - d3dPipeline->layout->handle); - - if (d3dPipeline->type == GRAPHICS_PIPELINE) { - d3d12CmdBuffer->handle->lpVtbl->IASetPrimitiveTopology( - d3d12CmdBuffer->handle, - d3dPipeline->topology); - - d3d12CmdBuffer->handle->lpVtbl->SetGraphicsRootSignature( - d3d12CmdBuffer->handle, - d3dPipeline->layout->handle); - - if (d3dPipeline->hasFsr) { - d3d12CmdBuffer->handle->lpVtbl->RSSetShadingRate( - d3d12CmdBuffer->handle, - d3dPipeline->shadingRate, - d3dPipeline->combinerOps); + cmdBufferImpl->handle->lpVtbl->SetPipelineState( + cmdBufferImpl->handle, + pipelineImpl->handle); + + cmdBufferImpl->handle->lpVtbl->SetComputeRootSignature( + cmdBufferImpl->handle, + pipelineImpl->layout->handle); + + if (pipelineImpl->type == GRAPHICS_PIPELINE) { + cmdBufferImpl->handle->lpVtbl->IASetPrimitiveTopology( + cmdBufferImpl->handle, + pipelineImpl->topology); + + cmdBufferImpl->handle->lpVtbl->SetGraphicsRootSignature( + cmdBufferImpl->handle, + pipelineImpl->layout->handle); + + if (pipelineImpl->hasFsr) { + cmdBufferImpl->handle->lpVtbl->RSSetShadingRate( + cmdBufferImpl->handle, + pipelineImpl->shadingRate, + pipelineImpl->combinerOps); } } } - d3d12CmdBuffer->pipeline = d3dPipeline; + cmdBufferImpl->pipeline = pipelineImpl; } void PAL_CALL cmdSetViewportD3D12( @@ -717,10 +717,10 @@ void PAL_CALL cmdSetViewportD3D12( uint32_t count, PalViewport* viewports) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - D3D12_VIEWPORT d3dViewports[D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + D3D12_VIEWPORT viewportsImpl[D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; for (int i = 0; i < count; i++) { - D3D12_VIEWPORT* tmp = &d3dViewports[i]; + D3D12_VIEWPORT* tmp = &viewportsImpl[i]; tmp->TopLeftX = viewports[i].x; tmp->TopLeftY = viewports[i].y; tmp->Width = viewports[i].width; @@ -729,7 +729,7 @@ void PAL_CALL cmdSetViewportD3D12( tmp->MaxDepth = viewports[i].maxDepth; } - d3d12CmdBuffer->handle->lpVtbl->RSSetViewports(d3d12CmdBuffer->handle, count, d3dViewports); + cmdBufferImpl->handle->lpVtbl->RSSetViewports(cmdBufferImpl->handle, count, viewportsImpl); } void PAL_CALL cmdSetScissorsD3D12( @@ -737,17 +737,17 @@ void PAL_CALL cmdSetScissorsD3D12( uint32_t count, PalRect2D* scissors) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - D3D12_RECT d3dScissors[D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + D3D12_RECT scissorsImpl[D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; for (int i = 0; i < count; i++) { - D3D12_RECT* tmp = &d3dScissors[i]; + D3D12_RECT* tmp = &scissorsImpl[i]; tmp->left = scissors[i].x; tmp->top = scissors[i].y; tmp->right = scissors[i].width; tmp->bottom = scissors[i].height; } - d3d12CmdBuffer->handle->lpVtbl->RSSetScissorRects(d3d12CmdBuffer->handle, count, d3dScissors); + cmdBufferImpl->handle->lpVtbl->RSSetScissorRects(cmdBufferImpl->handle, count, scissorsImpl); } void PAL_CALL cmdBindVertexBuffersD3D12( @@ -757,11 +757,11 @@ void PAL_CALL cmdBindVertexBuffersD3D12( PalBuffer** buffers, uint64_t* offsets) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - PipelineD3D12* pipeline = d3d12CmdBuffer->pipeline; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + PipelineD3D12* pipeline = cmdBufferImpl->pipeline; D3D12_VERTEX_BUFFER_VIEW* views = nullptr; views = palLinearAlloc( - &d3d12CmdBuffer->linearAllocator, + &cmdBufferImpl->linearAllocator, sizeof(D3D12_VERTEX_BUFFER_VIEW) * count, 0); @@ -773,8 +773,8 @@ void PAL_CALL cmdBindVertexBuffersD3D12( views[i].StrideInBytes = pipeline->strides[i]; } - d3d12CmdBuffer->handle->lpVtbl - ->IASetVertexBuffers(d3d12CmdBuffer->handle, firstSlot, count, views); + cmdBufferImpl->handle->lpVtbl + ->IASetVertexBuffers(cmdBufferImpl->handle, firstSlot, count, views); } void PAL_CALL cmdBindIndexBufferD3D12( @@ -783,7 +783,7 @@ void PAL_CALL cmdBindIndexBufferD3D12( uint64_t offset, PalIndexType type) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; D3D12_INDEX_BUFFER_VIEW view = {0}; BufferD3D12* indexBuffer = (BufferD3D12*)buffer; @@ -796,7 +796,7 @@ void PAL_CALL cmdBindIndexBufferD3D12( view.Format = DXGI_FORMAT_R32_UINT; } - d3d12CmdBuffer->handle->lpVtbl->IASetIndexBuffer(d3d12CmdBuffer->handle, &view); + cmdBufferImpl->handle->lpVtbl->IASetIndexBuffer(cmdBufferImpl->handle, &view); } void PAL_CALL cmdDrawD3D12( @@ -806,9 +806,9 @@ void PAL_CALL cmdDrawD3D12( uint32_t firstVertex, uint32_t firstInstance) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - d3d12CmdBuffer->handle->lpVtbl->DrawInstanced( - d3d12CmdBuffer->handle, + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + cmdBufferImpl->handle->lpVtbl->DrawInstanced( + cmdBufferImpl->handle, vertexCount, instanceCount, firstVertex, @@ -820,15 +820,15 @@ void PAL_CALL cmdDrawIndirectD3D12( PalBuffer* buffer, uint32_t count) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = cmdBufferImpl->device; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; - d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->ExecuteIndirect( + cmdBufferImpl->handle, device->drawSignature, count, - d3d12Buffer->handle, + bufferImpl->handle, 0, nullptr, 0); @@ -840,18 +840,18 @@ void PAL_CALL cmdDrawIndirectCountD3D12( PalBuffer* countBuffer, uint32_t maxDrawCount) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - BufferD3D12* d3d12CountBuffer = (BufferD3D12*)countBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = cmdBufferImpl->device; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; + BufferD3D12* countBufferImpl = (BufferD3D12*)countBuffer; - d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->ExecuteIndirect( + cmdBufferImpl->handle, device->drawSignature, maxDrawCount, - d3d12Buffer->handle, + bufferImpl->handle, 0, - d3d12CountBuffer->handle, + countBufferImpl->handle, 0); } @@ -863,9 +863,9 @@ void PAL_CALL cmdDrawIndexedD3D12( int32_t vertexOffset, uint32_t firstInstance) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - d3d12CmdBuffer->handle->lpVtbl->DrawIndexedInstanced( - d3d12CmdBuffer->handle, + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + cmdBufferImpl->handle->lpVtbl->DrawIndexedInstanced( + cmdBufferImpl->handle, indexCount, instanceCount, firstIndex, @@ -878,15 +878,15 @@ void PAL_CALL cmdDrawIndexedIndirectD3D12( PalBuffer* buffer, uint32_t count) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = cmdBufferImpl->device; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; - d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->ExecuteIndirect( + cmdBufferImpl->handle, device->drawIndexedSignature, count, - d3d12Buffer->handle, + bufferImpl->handle, 0, nullptr, 0); @@ -898,18 +898,18 @@ void PAL_CALL cmdDrawIndexedIndirectCountD3D12( PalBuffer* countBuffer, uint32_t maxDrawCount) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - BufferD3D12* d3d12CountBuffer = (BufferD3D12*)countBuffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = cmdBufferImpl->device; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; + BufferD3D12* countBufferImpl = (BufferD3D12*)countBuffer; - d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->ExecuteIndirect( + cmdBufferImpl->handle, device->drawIndexedSignature, maxDrawCount, - d3d12Buffer->handle, + bufferImpl->handle, 0, - d3d12CountBuffer->handle, + countBufferImpl->handle, 0); } @@ -918,12 +918,12 @@ void PAL_CALL cmdAccelerationStructureBarrierD3D12( PalAccelerationStructure* as, PalBarrierInfo* info) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - AccelerationStructureD3D12* d3dAs = (AccelerationStructureD3D12*)as; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + AccelerationStructureD3D12* asImpl = (AccelerationStructureD3D12*)as; D3D12_RESOURCE_BARRIER barrier = {0}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrier.UAV.pResource = d3dAs->handle; - d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + barrier.UAV.pResource = asImpl->handle; + cmdBufferImpl->handle->lpVtbl->ResourceBarrier(cmdBufferImpl->handle, 1, &barrier); } void PAL_CALL cmdImageBarrierD3D12( @@ -932,8 +932,8 @@ void PAL_CALL cmdImageBarrierD3D12( PalImageSubresourceRange* subresourceRange, PalBarrierInfo* info) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - ImageD3D12* d3d12Image = (ImageD3D12*)image; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + ImageD3D12* imageImpl = (ImageD3D12*)image; D3D12_RESOURCE_STATES old, new; D3D12_RESOURCE_BARRIER barrier = {0}; @@ -943,8 +943,8 @@ void PAL_CALL cmdImageBarrierD3D12( // read/write barrier without transition if (old == new && old == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrier.UAV.pResource = d3d12Image->handle; - d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + barrier.UAV.pResource = imageImpl->handle; + cmdBufferImpl->handle->lpVtbl->ResourceBarrier(cmdBufferImpl->handle, 1, &barrier); return; } @@ -959,34 +959,34 @@ void PAL_CALL cmdImageBarrierD3D12( uint32_t startLevel = subresourceRange->startMipLevel; uint32_t startLayer = subresourceRange->startArrayLayer; - uint32_t maxLevels = d3d12Image->info.mipLevelCount; - uint32_t maxLayers = d3d12Image->info.arrayLayerCount; + uint32_t maxLevels = imageImpl->info.mipLevelCount; + uint32_t maxLayers = imageImpl->info.arrayLayerCount; uint32_t barrierCount = layerCount * levelCount * planeCount; if (startLevel == 0 && levelCount == maxLevels && startLayer == 0 && layerCount == maxLayers) { // full resource barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = d3d12Image->handle; + barrier.Transition.pResource = imageImpl->handle; barrier.Transition.StateBefore = old; barrier.Transition.StateAfter = new; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + cmdBufferImpl->handle->lpVtbl->ResourceBarrier(cmdBufferImpl->handle, 1, &barrier); return; } if (layerCount == 1 && layerCount == 1 && planeCount == 1) { // single plane barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = d3d12Image->handle; + barrier.Transition.pResource = imageImpl->handle; barrier.Transition.StateBefore = old; barrier.Transition.StateAfter = new; barrier.Transition.Subresource = startLevel + startLayer * maxLevels; - d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + cmdBufferImpl->handle->lpVtbl->ResourceBarrier(cmdBufferImpl->handle, 1, &barrier); return; } barriers = palLinearAlloc( - &d3d12CmdBuffer->linearAllocator, + &cmdBufferImpl->linearAllocator, sizeof(D3D12_RESOURCE_BARRIER) * barrierCount, 0); @@ -998,7 +998,7 @@ void PAL_CALL cmdImageBarrierD3D12( D3D12_RESOURCE_BARRIER* tmp = &barriers[count++]; tmp->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - tmp->Transition.pResource = d3d12Image->handle; + tmp->Transition.pResource = imageImpl->handle; tmp->Transition.StateBefore = old; tmp->Transition.StateAfter = new; tmp->Transition.Subresource = index; @@ -1006,7 +1006,7 @@ void PAL_CALL cmdImageBarrierD3D12( } } - d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, barrierCount, barriers); + cmdBufferImpl->handle->lpVtbl->ResourceBarrier(cmdBufferImpl->handle, barrierCount, barriers); } void PAL_CALL cmdBufferBarrierD3D12( @@ -1014,10 +1014,10 @@ void PAL_CALL cmdBufferBarrierD3D12( PalBuffer* buffer, PalBarrierInfo* info) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; D3D12_RESOURCE_STATES old, new; - if (!d3d12Buffer->canStateChange) { + if (!bufferImpl->canStateChange) { return; } @@ -1027,15 +1027,15 @@ void PAL_CALL cmdBufferBarrierD3D12( D3D12_RESOURCE_BARRIER barrier = {0}; if (old == new && D3D12_RESOURCE_STATE_UNORDERED_ACCESS) { barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrier.UAV.pResource = d3d12Buffer->handle; + barrier.UAV.pResource = bufferImpl->handle; } else { barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = d3d12Buffer->handle; + barrier.Transition.pResource = bufferImpl->handle; barrier.Transition.StateBefore = old; barrier.Transition.StateAfter = new; } - d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + cmdBufferImpl->handle->lpVtbl->ResourceBarrier(cmdBufferImpl->handle, 1, &barrier); } void PAL_CALL cmdDispatchD3D12( @@ -1044,24 +1044,24 @@ void PAL_CALL cmdDispatchD3D12( uint32_t groupCountY, uint32_t groupCountZ) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - d3d12CmdBuffer->handle->lpVtbl - ->Dispatch(d3d12CmdBuffer->handle, groupCountX, groupCountY, groupCountZ); + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + cmdBufferImpl->handle->lpVtbl + ->Dispatch(cmdBufferImpl->handle, groupCountX, groupCountY, groupCountZ); } void PAL_CALL cmdDispatchIndirectD3D12( PalCommandBuffer* cmdBuffer, PalBuffer* buffer) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; - DeviceD3D12* device = d3d12CmdBuffer->device; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; + DeviceD3D12* device = cmdBufferImpl->device; - d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->ExecuteIndirect( + cmdBufferImpl->handle, device->dispatchSignature, 1, // one dispatch - d3d12Buffer->handle, + bufferImpl->handle, 0, nullptr, 0); @@ -1075,25 +1075,25 @@ void PAL_CALL cmdTraceRaysD3D12( uint32_t height, uint32_t depth) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; - uint64_t stride = d3d12Sbt->raygen.region.StrideInBytes; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + ShaderBindingTableD3D12* sbtImpl = (ShaderBindingTableD3D12*)sbt; + uint64_t stride = sbtImpl->raygen.region.StrideInBytes; D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; - raygenAddress.SizeInBytes = d3d12Sbt->raygen.region.SizeInBytes; - raygenAddress.StartAddress = d3d12Sbt->baseAddress + raygenIndex * stride; + raygenAddress.SizeInBytes = sbtImpl->raygen.region.SizeInBytes; + raygenAddress.StartAddress = sbtImpl->baseAddress + raygenIndex * stride; // we need to make sure the SBT is up to date - commitShaderbindingTableUpdateD3D12(d3d12CmdBuffer, d3d12Sbt); + commitShaderbindingTableUpdateD3D12(cmdBufferImpl, sbtImpl); D3D12_DISPATCH_RAYS_DESC desc = {0}; desc.Width = width; desc.Height = height; desc.Depth = depth; desc.RayGenerationShaderRecord = raygenAddress; - desc.HitGroupTable = d3d12Sbt->hit.region; - desc.MissShaderTable = d3d12Sbt->miss.region; - desc.CallableShaderTable = d3d12Sbt->callable.region; - d3d12CmdBuffer->handle->lpVtbl->DispatchRays(d3d12CmdBuffer->handle, &desc); + desc.HitGroupTable = sbtImpl->hit.region; + desc.MissShaderTable = sbtImpl->miss.region; + desc.CallableShaderTable = sbtImpl->callable.region; + cmdBufferImpl->handle->lpVtbl->DispatchRays(cmdBufferImpl->handle, &desc); } void PAL_CALL cmdTraceRaysIndirectD3D12( @@ -1103,18 +1103,18 @@ void PAL_CALL cmdTraceRaysIndirectD3D12( PalBuffer* buffer) { HRESULT result; - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - DeviceD3D12* device = d3d12CmdBuffer->device; - ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; - BufferD3D12* d3d12Buffer = (BufferD3D12*)buffer; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + DeviceD3D12* device = cmdBufferImpl->device; + ShaderBindingTableD3D12* sbtImpl = (ShaderBindingTableD3D12*)sbt; + BufferD3D12* bufferImpl = (BufferD3D12*)buffer; D3D12_DISPATCH_RAYS_DESC desc = {0}; // we need to make sure the SBT is up to date - commitShaderbindingTableUpdateD3D12(d3d12CmdBuffer, d3d12Sbt); + commitShaderbindingTableUpdateD3D12(cmdBufferImpl, sbtImpl); // BufferD3D12 is mappable void* ptr = nullptr; - result = d3d12Buffer->handle->lpVtbl->Map(d3d12Buffer->handle, 0, nullptr, &ptr); + result = bufferImpl->handle->lpVtbl->Map(bufferImpl->handle, 0, nullptr, &ptr); if (FAILED(result)) { return; } @@ -1122,34 +1122,34 @@ void PAL_CALL cmdTraceRaysIndirectD3D12( // copy indirect parameters from the buffer PalDispatchIndirectData data = {0}; memcpy(&data, ptr, sizeof(PalDispatchIndirectData)); - d3d12Buffer->handle->lpVtbl->Unmap(d3d12Buffer->handle, 0, nullptr); + bufferImpl->handle->lpVtbl->Unmap(bufferImpl->handle, 0, nullptr); desc.Width = data.groupCountXOrWidth; desc.Height = data.groupCountXOrHeight; desc.Depth = data.groupCountXOrDepth; - uint64_t stride = d3d12Sbt->raygen.region.StrideInBytes; + uint64_t stride = sbtImpl->raygen.region.StrideInBytes; D3D12_GPU_VIRTUAL_ADDRESS_RANGE raygenAddress = {0}; - raygenAddress.SizeInBytes = d3d12Sbt->raygen.region.SizeInBytes; - raygenAddress.StartAddress = d3d12Sbt->baseAddress + raygenIndex * stride; + raygenAddress.SizeInBytes = sbtImpl->raygen.region.SizeInBytes; + raygenAddress.StartAddress = sbtImpl->baseAddress + raygenIndex * stride; desc.RayGenerationShaderRecord = raygenAddress; - desc.HitGroupTable = d3d12Sbt->hit.region; - desc.MissShaderTable = d3d12Sbt->miss.region; - desc.CallableShaderTable = d3d12Sbt->callable.region; + desc.HitGroupTable = sbtImpl->hit.region; + desc.MissShaderTable = sbtImpl->miss.region; + desc.CallableShaderTable = sbtImpl->callable.region; // fill the data into the tmp upload buffer of the command buffer ptr = nullptr; - d3d12CmdBuffer->stagingBuffer->lpVtbl->Map(d3d12CmdBuffer->stagingBuffer, 0, nullptr, &ptr); + cmdBufferImpl->stagingBuffer->lpVtbl->Map(cmdBufferImpl->stagingBuffer, 0, nullptr, &ptr); memcpy(ptr, &desc, sizeof(D3D12_DISPATCH_RAYS_DESC)); - d3d12CmdBuffer->stagingBuffer->lpVtbl->Unmap(d3d12CmdBuffer->stagingBuffer, 0, nullptr); + cmdBufferImpl->stagingBuffer->lpVtbl->Unmap(cmdBufferImpl->stagingBuffer, 0, nullptr); // copy to the gpu tmp buffer of the command buffer and execute with that - d3d12CmdBuffer->handle->lpVtbl->CopyBufferRegion( - d3d12CmdBuffer->handle, - d3d12CmdBuffer->buffer, + cmdBufferImpl->handle->lpVtbl->CopyBufferRegion( + cmdBufferImpl->handle, + cmdBufferImpl->buffer, 0, - d3d12CmdBuffer->stagingBuffer, + cmdBufferImpl->stagingBuffer, 0, sizeof(D3D12_DISPATCH_RAYS_DESC)); @@ -1159,14 +1159,14 @@ void PAL_CALL cmdTraceRaysIndirectD3D12( barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - barrier.Transition.pResource = d3d12CmdBuffer->buffer; - d3d12CmdBuffer->handle->lpVtbl->ResourceBarrier(d3d12CmdBuffer->handle, 1, &barrier); + barrier.Transition.pResource = cmdBufferImpl->buffer; + cmdBufferImpl->handle->lpVtbl->ResourceBarrier(cmdBufferImpl->handle, 1, &barrier); - d3d12CmdBuffer->handle->lpVtbl->ExecuteIndirect( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->ExecuteIndirect( + cmdBufferImpl->handle, device->raySignature, 1, - d3d12CmdBuffer->buffer, + cmdBufferImpl->buffer, 0, nullptr, 0); @@ -1177,10 +1177,10 @@ void PAL_CALL cmdBindDescriptorSetD3D12( uint32_t setIndex, PalDescriptorSet* set) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - PipelineD3D12* pipeline = d3d12CmdBuffer->pipeline; - DescriptorSetD3D12* d3dSet = (DescriptorSetD3D12*)set; - DescriptorPoolD3D12* pool = d3dSet->pool; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + PipelineD3D12* pipeline = cmdBufferImpl->pipeline; + DescriptorSetD3D12* setImpl = (DescriptorSetD3D12*)set; + DescriptorPoolD3D12* pool = setImpl->pool; // bind heaps uint32_t heapCount = 0; @@ -1192,10 +1192,10 @@ void PAL_CALL cmdBindDescriptorSetD3D12( if (pool->hasSamplerHeap) { heaps[heapCount++] = pool->samplerHeap.handle; } - d3d12CmdBuffer->handle->lpVtbl->SetDescriptorHeaps(d3d12CmdBuffer->handle, heapCount, heaps); + cmdBufferImpl->handle->lpVtbl->SetDescriptorHeaps(cmdBufferImpl->handle, heapCount, heaps); // bind resource descriptor table - uint32_t resourceCount = d3dSet->layout->bindingCount - d3dSet->layout->samplerCount; + uint32_t resourceCount = setImpl->layout->bindingCount - setImpl->layout->samplerCount; uint32_t baseIndex = setIndex; if (pipeline->layout->constantIndex != UINT32_MAX) { // If push constant was used to create the pipeline layout @@ -1206,20 +1206,20 @@ void PAL_CALL cmdBindDescriptorSetD3D12( if (resourceCount) { D3D12_GPU_DESCRIPTOR_HANDLE base; base.ptr = getDescriptorHandleD3D12( - d3dSet->resourceOffset, + setImpl->resourceOffset, pool->resourceHeap.incrementSize, pool->resourceHeap.gpuBase); if (pipeline->type == GRAPHICS_PIPELINE) { - d3d12CmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->SetGraphicsRootDescriptorTable( + cmdBufferImpl->handle, baseIndex, // base set index is resource first before sampler base); } else { // ray tracing uses the compute path - d3d12CmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->SetComputeRootDescriptorTable( + cmdBufferImpl->handle, baseIndex, // base set index is resource first before sampler base); } @@ -1228,23 +1228,23 @@ void PAL_CALL cmdBindDescriptorSetD3D12( } // bind sampler descriptor table - if (d3dSet->layout->samplerCount) { + if (setImpl->layout->samplerCount) { D3D12_GPU_DESCRIPTOR_HANDLE base; base.ptr = getDescriptorHandleD3D12( - d3dSet->samplerOffset, + setImpl->samplerOffset, pool->samplerHeap.incrementSize, pool->samplerHeap.gpuBase); if (pipeline->type == GRAPHICS_PIPELINE) { - d3d12CmdBuffer->handle->lpVtbl->SetGraphicsRootDescriptorTable( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->SetGraphicsRootDescriptorTable( + cmdBufferImpl->handle, baseIndex, base); } else { // ray tracing uses the compute path - d3d12CmdBuffer->handle->lpVtbl->SetComputeRootDescriptorTable( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->SetComputeRootDescriptorTable( + cmdBufferImpl->handle, baseIndex, base); } @@ -1257,12 +1257,12 @@ void PAL_CALL cmdPushConstantsD3D12( uint32_t size, const void* value) { - CommandBufferD3D12* d3d12CmdBuffer = (CommandBufferD3D12*)cmdBuffer; - PipelineD3D12* pipeline = d3d12CmdBuffer->pipeline; + CommandBufferD3D12* cmdBufferImpl = (CommandBufferD3D12*)cmdBuffer; + PipelineD3D12* pipeline = cmdBufferImpl->pipeline; if (pipeline->layout->constantIndex != UINT32_MAX) { if (pipeline->type == GRAPHICS_PIPELINE) { - d3d12CmdBuffer->handle->lpVtbl->SetGraphicsRoot32BitConstants( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->SetGraphicsRoot32BitConstants( + cmdBufferImpl->handle, pipeline->layout->constantIndex, size / 4, value, @@ -1270,8 +1270,8 @@ void PAL_CALL cmdPushConstantsD3D12( } else { // ray tracing uses the compute path - d3d12CmdBuffer->handle->lpVtbl->SetComputeRoot32BitConstants( - d3d12CmdBuffer->handle, + cmdBufferImpl->handle->lpVtbl->SetComputeRoot32BitConstants( + cmdBufferImpl->handle, pipeline->layout->constantIndex, size / 4, value, diff --git a/src/graphics/d3d12/pal_d3d12.c b/src/graphics/d3d12/pal_d3d12.c index 8fb22379..7eb4e6a8 100644 --- a/src/graphics/d3d12/pal_d3d12.c +++ b/src/graphics/d3d12/pal_d3d12.c @@ -8,36 +8,30 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" +// clang-format off // IIDS IID IID_Device = {0xc4fec28f, 0x7966, 0x4e95, 0x9f, 0x94, 0xf4, 0x31, 0xcb, 0x56, 0xc3, 0xb8}; IID IID_Adapter = {0x3c8d99d1, 0x4fbf, 0x4181, 0xa8, 0x2c, 0xaf, 0x66, 0xbf, 0x7b, 0xd2, 0x4e}; IID IID_Factory = {0xc1b6694f, 0xff09, 0x44a9, 0xb0, 0x3c, 0x77, 0x90, 0x0a, 0x0a, 0x1d, 0x17}; -IID IID_DebugController = - {0x344488b7, 0x6846, 0x474b, 0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0}; -IID IID_DebugController1 = - {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8, 0xad, 0x15, 0x90, 0x00, 0xaf, 0x43, 0x04}; +IID IID_Debug = {0x344488b7, 0x6846, 0x474b, 0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0}; +IID IID_Debug1 = {0xaffaa4ca, 0x63fe, 0x4d8e, 0xb8, 0xad, 0x15, 0x90, 0x00, 0xaf, 0x43, 0x04}; IID IID_InfoQueue = {0x0742a90b, 0xc387, 0x483f, 0xb9, 0x46, 0x30, 0xa7, 0xe4, 0xe6, 0x14, 0x58}; IID IID_Heap = {0x6b3b2502, 0x6e51, 0x45b3, 0x90, 0xee, 0x98, 0x84, 0x26, 0x5e, 0x8d, 0xf3}; IID IID_Queue = {0x0ec870a6, 0x5d7e, 0x4c22, 0x8c, 0xfc, 0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed}; IID IID_Swapchain = {0x94d99bdb, 0xf1f8, 0x4ab0, 0xb2, 0x36, 0x7d, 0xa0, 0x17, 0x0e, 0xda, 0xb1}; -IID IID_CommandAllocator = - {0x6102dee4, 0xaf59, 0x4b09, 0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24}; +IID IID_CommandAllocator = {0x6102dee4, 0xaf59, 0x4b09, 0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24}; IID IID_CommandList = {0x7116d91c, 0xe7e4, 0x47ce, 0xb8, 0xc6, 0xec, 0x81, 0x68, 0xf4, 0x37, 0xe5}; IID IID_CommandList6 = {0xc3827890, 0xe548, 0x4cfa, 0x96, 0xcf, 0x56, 0x89, 0xa9, 0x37, 0x0f, 0x80}; -IID IID_CommandSignature = - {0xc36a797c, 0xec80, 0x4f0a, 0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1}; -IID IID_DescriptorHeap = - {0x8efb471d, 0x616c, 0x4f49, 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51}; -IID IID_RootSignature = - {0xc54a6b66, 0x72df, 0x4ee8, 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14}; +IID IID_CommandSignature = {0xc36a797c, 0xec80, 0x4f0a, 0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1}; +IID IID_DescriptorHeap = {0x8efb471d, 0x616c, 0x4f49, 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51}; +IID IID_RootSignature = {0xc54a6b66, 0x72df, 0x4ee8, 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14}; IID IID_Device5 = {0x8b4f173b, 0x2fea, 0x4b80, 0x8f, 0x58, 0x43, 0x07, 0x19, 0x1a, 0xb9, 0x5d}; -IID IID_PipelineState = - {0x765a30f3, 0xf624, 0x4c6f, 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45}; +IID IID_PipelineState = {0x765a30f3, 0xf624, 0x4c6f, 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45}; IID IID_StateObject = {0x47016943, 0xfca8, 0x4594, 0x93, 0xea, 0xaf, 0x25, 0x8b, 0x55, 0x34, 0x6d}; IID IID_Resource = {0x696442be, 0xa72e, 0x4059, 0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad}; -IID IID_StateObjectProps = - {0xde5fa827, 0x9bf9, 0x4f26, 0x89, 0xff, 0xd7, 0xf5, 0x6f, 0xde, 0x38, 0x60}; +IID IID_StateObjectProps = {0xde5fa827, 0x9bf9, 0x4f26, 0x89, 0xff, 0xd7, 0xf5, 0x6f, 0xde, 0x38, 0x60}; IID IID_Fence = {0x0a753dcf, 0xc4d8, 0x4b91, 0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76}; +// clang-format on D3D12 s_D3D12 = {0}; @@ -1084,38 +1078,28 @@ PalResult PAL_CALL initGraphicsD3D12( s_D3D12.handle, "D3D12SerializeVersionedRootSignature"); - if (debugger) { + if (debugger && debugger->callback) { s_D3D12.getDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress( s_D3D12.handle, "D3D12GetDebugInterface"); if (s_D3D12.getDebugInterface) { - ID3D12Debug* debugController = nullptr; - ID3D12Debug1* debugController1 = nullptr; - HRESULT hr = s_D3D12.getDebugInterface(&IID_DebugController, (void**)&debugController); + ID3D12Debug* debug = nullptr; + HRESULT hr = s_D3D12.getDebugInterface(&IID_Debug, (void**)&debug); if (SUCCEEDED(hr)) { - debugController->lpVtbl->EnableDebugLayer(debugController); - hr = debugController->lpVtbl->QueryInterface( - debugController, - &IID_DebugController1, - (void**)&debugController1); - - if (SUCCEEDED(hr)) { - debugController1->lpVtbl->SetEnableSynchronizedCommandQueueValidation( - debugController1, - TRUE); - - debugController1->lpVtbl->SetEnableGPUBasedValidation( - debugController1, - TRUE); - - debugController1->lpVtbl->Release(debugController1); + debug->lpVtbl->EnableDebugLayer(debug); + if (debugger->enableGPUValidation) { + ID3D12Debug1* debug1 = nullptr; + hr = debug->lpVtbl->QueryInterface(debug, &IID_Debug1, (void**)&debug1); + if (SUCCEEDED(hr)) { + debug1->lpVtbl->SetEnableSynchronizedCommandQueueValidation(debug1, TRUE); + debug1->lpVtbl->SetEnableGPUBasedValidation(debug1, TRUE); + debug1->lpVtbl->Release(debug1); + } } - - debugController->lpVtbl->Release(debugController); } - if (debugController) { + if (debug) { // message types if (!debugger->denyGeneral) s_D3D12.categories[s_D3D12.categoryCount++] = D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED; diff --git a/src/graphics/d3d12/pal_d3d12.h b/src/graphics/d3d12/pal_d3d12.h index 281a2502..750d7150 100644 --- a/src/graphics/d3d12/pal_d3d12.h +++ b/src/graphics/d3d12/pal_d3d12.h @@ -410,8 +410,8 @@ void pollMessagesD3D12(DeviceD3D12* device); extern IID IID_Device; extern IID IID_Adapter; extern IID IID_Factory; -extern IID IID_DebugController; -extern IID IID_DebugController1; +extern IID IID_Debug; +extern IID IID_Debug1; extern IID IID_InfoQueue; extern IID IID_Heap; extern IID IID_Queue; diff --git a/src/graphics/d3d12/pal_descriptors_d3d12.c b/src/graphics/d3d12/pal_descriptors_d3d12.c index 1bbeb5f8..b2e3bf0e 100644 --- a/src/graphics/d3d12/pal_descriptors_d3d12.c +++ b/src/graphics/d3d12/pal_descriptors_d3d12.c @@ -14,7 +14,7 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( PalDescriptorSetLayout** outLayout) { HRESULT result; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; DescriptorSetLayoutD3D12* layout = nullptr; DescriptorSetBinding* bindings = nullptr; uint32_t count = info->bindingCount; @@ -126,27 +126,27 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( } // check limits - if (sampledImageCount > d3d12Device->limits.maxDescriptorSampledImages) { + if (sampledImageCount > deviceImpl->limits.maxDescriptorSampledImages) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (storageImageCount > d3d12Device->limits.maxDescriptorStorageImages) { + if (storageImageCount > deviceImpl->limits.maxDescriptorStorageImages) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (storageBufferCount > d3d12Device->limits.maxDescriptorStorageBuffers) { + if (storageBufferCount > deviceImpl->limits.maxDescriptorStorageBuffers) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (uniformBufferCount > d3d12Device->limits.maxDescriptorUniformBuffers) { + if (uniformBufferCount > deviceImpl->limits.maxDescriptorUniformBuffers) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (tlasCount > d3d12Device->limits.maxDescriptorAccelerationStructures) { + if (tlasCount > deviceImpl->limits.maxDescriptorAccelerationStructures) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (samplerCount > d3d12Device->limits.maxDescriptorSamplers) { + if (samplerCount > deviceImpl->limits.maxDescriptorSamplers) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -160,9 +160,9 @@ PalResult PAL_CALL createDescriptorSetLayoutD3D12( void PAL_CALL destroyDescriptorSetLayoutD3D12(PalDescriptorSetLayout* layout) { - DescriptorSetLayoutD3D12* d3d12Layout = (DescriptorSetLayoutD3D12*)layout; - palFree(s_D3D12.allocator, d3d12Layout->bindings); - palFree(s_D3D12.allocator, d3d12Layout); + DescriptorSetLayoutD3D12* layoutImpl = (DescriptorSetLayoutD3D12*)layout; + palFree(s_D3D12.allocator, layoutImpl->bindings); + palFree(s_D3D12.allocator, layoutImpl); } PalResult PAL_CALL createDescriptorPoolD3D12( @@ -171,7 +171,7 @@ PalResult PAL_CALL createDescriptorPoolD3D12( PalDescriptorPool** outPool) { HRESULT result; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; DescriptorPoolD3D12* pool = nullptr; // partially bound is not supported @@ -232,20 +232,20 @@ PalResult PAL_CALL createDescriptorPoolD3D12( desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; desc.NumDescriptors = resourceCount; - result = d3d12Device->handle->lpVtbl->CreateDescriptorHeap( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateDescriptorHeap( + deviceImpl->handle, &desc, &IID_DescriptorHeap, (void**)&heap->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } // get increment size - heap->incrementSize = d3d12Device->handle->lpVtbl->GetDescriptorHandleIncrementSize( - d3d12Device->handle, + heap->incrementSize = deviceImpl->handle->lpVtbl->GetDescriptorHandleIncrementSize( + deviceImpl->handle, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); // get base CPU and GPU base pointer @@ -270,20 +270,20 @@ PalResult PAL_CALL createDescriptorPoolD3D12( desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; desc.NumDescriptors = limits->maxSamplers; - result = d3d12Device->handle->lpVtbl->CreateDescriptorHeap( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateDescriptorHeap( + deviceImpl->handle, &desc, &IID_DescriptorHeap, (void**)&heap->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } // get increment size - heap->incrementSize = d3d12Device->handle->lpVtbl->GetDescriptorHandleIncrementSize( - d3d12Device->handle, + heap->incrementSize = deviceImpl->handle->lpVtbl->GetDescriptorHandleIncrementSize( + deviceImpl->handle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); // get base CPU and GPU base pointer @@ -305,32 +305,32 @@ PalResult PAL_CALL createDescriptorPoolD3D12( void PAL_CALL destroyDescriptorPoolD3D12(PalDescriptorPool* pool) { - DescriptorPoolD3D12* d3d12Pool = (DescriptorPoolD3D12*)pool; - if (d3d12Pool->hasResourceHeap) { - d3d12Pool->resourceHeap.handle->lpVtbl->Release(d3d12Pool->resourceHeap.handle); + DescriptorPoolD3D12* poolImpl = (DescriptorPoolD3D12*)pool; + if (poolImpl->hasResourceHeap) { + poolImpl->resourceHeap.handle->lpVtbl->Release(poolImpl->resourceHeap.handle); } - if (d3d12Pool->hasSamplerHeap) { - d3d12Pool->samplerHeap.handle->lpVtbl->Release(d3d12Pool->samplerHeap.handle); + if (poolImpl->hasSamplerHeap) { + poolImpl->samplerHeap.handle->lpVtbl->Release(poolImpl->samplerHeap.handle); } - palFree(s_D3D12.allocator, d3d12Pool->sets); - palFree(s_D3D12.allocator, d3d12Pool); + palFree(s_D3D12.allocator, poolImpl->sets); + palFree(s_D3D12.allocator, poolImpl); } PalResult PAL_CALL resetDescriptorPoolD3D12(PalDescriptorPool* pool) { - DescriptorPoolD3D12* d3d12Pool = (DescriptorPoolD3D12*)pool; - d3d12Pool->resourceHeap.nextOffset = 0; - d3d12Pool->samplerHeap.nextOffset = 0; - d3d12Pool->usedSets = 0; - - d3d12Pool->limits.usedAs = 0; - d3d12Pool->limits.usedSampledImages = 0; - d3d12Pool->limits.usedSamplers = 0; - d3d12Pool->limits.usedStorageBuffers = 0; - d3d12Pool->limits.usedStorageImages = 0; - d3d12Pool->limits.usedUniformBuffers = 0; + DescriptorPoolD3D12* poolImpl = (DescriptorPoolD3D12*)pool; + poolImpl->resourceHeap.nextOffset = 0; + poolImpl->samplerHeap.nextOffset = 0; + poolImpl->usedSets = 0; + + poolImpl->limits.usedAs = 0; + poolImpl->limits.usedSampledImages = 0; + poolImpl->limits.usedSamplers = 0; + poolImpl->limits.usedStorageBuffers = 0; + poolImpl->limits.usedStorageImages = 0; + poolImpl->limits.usedUniformBuffers = 0; return PAL_RESULT_SUCCESS; } @@ -340,9 +340,9 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( PalDescriptorSetLayout* layout, PalDescriptorSet** outSet) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - DescriptorPoolD3D12* d3d12Pool = (DescriptorPoolD3D12*)pool; - DescriptorSetLayoutD3D12* d3d12Layout = (DescriptorSetLayoutD3D12*)layout; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; + DescriptorPoolD3D12* poolImpl = (DescriptorPoolD3D12*)pool; + DescriptorSetLayoutD3D12* layoutImpl = (DescriptorSetLayoutD3D12*)layout; DescriptorSetD3D12* set = nullptr; uint32_t storageImageCount = 0; @@ -353,8 +353,8 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( uint32_t tlasCount = 0; // get requirements for the sets using the provided layout - for (int i = 0; i < d3d12Layout->bindingCount; i++) { - DescriptorSetBinding* binding = &d3d12Layout->bindings[i]; + for (int i = 0; i < layoutImpl->bindingCount; i++) { + DescriptorSetBinding* binding = &layoutImpl->bindings[i]; if (binding->type == PAL_DESCRIPTOR_TYPE_SAMPLER) { samplerCount += binding->range.NumDescriptors; @@ -377,13 +377,13 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( } // validate descriptor sets limits - if (d3d12Pool->usedSets + 1 > d3d12Pool->maxSets) { + if (poolImpl->usedSets + 1 > poolImpl->maxSets) { // all sets are used return PAL_RESULT_CODE_OUT_OF_MEMORY; } // check descriptor limits - DescriptorHeapLimits* limits = &d3d12Pool->limits; + DescriptorHeapLimits* limits = &poolImpl->limits; if (limits->usedAs + tlasCount > limits->maxAs) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } @@ -409,16 +409,16 @@ PalResult PAL_CALL allocateDescriptorSetD3D12( } // assign offset base to the set so we know where to start and end for each set. - set = &d3d12Pool->sets[d3d12Pool->usedSets++]; - set->resourceOffset = d3d12Pool->resourceHeap.nextOffset; - set->samplerOffset = d3d12Pool->samplerHeap.nextOffset; - set->layout = d3d12Layout; - set->pool = d3d12Pool; + set = &poolImpl->sets[poolImpl->usedSets++]; + set->resourceOffset = poolImpl->resourceHeap.nextOffset; + set->samplerOffset = poolImpl->samplerHeap.nextOffset; + set->layout = layoutImpl; + set->pool = poolImpl; uint32_t totalDescriptors = tlasCount + storageBufferCount + uniformBufferCount; totalDescriptors += sampledImageCount + storageImageCount; - d3d12Pool->resourceHeap.nextOffset += totalDescriptors; - d3d12Pool->samplerHeap.nextOffset += samplerCount; + poolImpl->resourceHeap.nextOffset += totalDescriptors; + poolImpl->samplerHeap.nextOffset += samplerCount; limits->usedAs += tlasCount; limits->usedSampledImages += sampledImageCount; @@ -435,7 +435,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( uint32_t count, PalDescriptorSetWriteInfo* infos) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; for (int i = 0; i < count; i++) { PalDescriptorSetWriteInfo* info = &infos[i]; DescriptorSetD3D12* set = (DescriptorSetD3D12*)info->descriptorSet; @@ -467,8 +467,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { if (info->samplerInfos) { SamplerD3D12* sampler = (SamplerD3D12*)info->samplerInfos[j].sampler; - d3d12Device->handle->lpVtbl->CreateSampler( - d3d12Device->handle, + deviceImpl->handle->lpVtbl->CreateSampler( + deviceImpl->handle, &sampler->desc, dst); @@ -482,7 +482,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; - d3d12Device->handle->lpVtbl->CreateSampler(d3d12Device->handle, &desc, dst); + deviceImpl->handle->lpVtbl->CreateSampler(deviceImpl->handle, &desc, dst); } } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE) { @@ -496,8 +496,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.RaytracingAccelerationStructure.Location = tlas->address; } - d3d12Device->handle->lpVtbl - ->CreateShaderResourceView(d3d12Device->handle, nullptr, &desc, dst); + deviceImpl->handle->lpVtbl + ->CreateShaderResourceView(deviceImpl->handle, nullptr, &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { D3D12_SHADER_RESOURCE_VIEW_DESC desc = {0}; @@ -523,8 +523,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } fillSubresourceD3D12(DESC_TYPE_SRV, type, &range, &desc); - d3d12Device->handle->lpVtbl - ->CreateShaderResourceView(d3d12Device->handle, handle, &desc, dst); + deviceImpl->handle->lpVtbl + ->CreateShaderResourceView(deviceImpl->handle, handle, &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {0}; @@ -548,8 +548,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( } fillSubresourceD3D12(DESC_TYPE_UAV, type, &range, &desc); - d3d12Device->handle->lpVtbl - ->CreateUnorderedAccessView(d3d12Device->handle, handle, nullptr, &desc, dst); + deviceImpl->handle->lpVtbl + ->CreateUnorderedAccessView(deviceImpl->handle, handle, nullptr, &desc, dst); } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_UNIFORM_BUFFER) { D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {0}; @@ -563,8 +563,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.BufferLocation = address + bufferInfo->offset; } - d3d12Device->handle->lpVtbl->CreateConstantBufferView( - d3d12Device->handle, + deviceImpl->handle->lpVtbl->CreateConstantBufferView( + deviceImpl->handle, &desc, dst); @@ -592,8 +592,8 @@ PalResult PAL_CALL updateDescriptorSetD3D12( desc.Buffer.NumElements = bufferInfo->size / stride; } - d3d12Device->handle->lpVtbl - ->CreateUnorderedAccessView(d3d12Device->handle, handle, nullptr, &desc, dst); + deviceImpl->handle->lpVtbl + ->CreateUnorderedAccessView(deviceImpl->handle, handle, nullptr, &desc, dst); } } } diff --git a/src/graphics/d3d12/pal_device_d3d12.c b/src/graphics/d3d12/pal_device_d3d12.c index 061bc2fb..16d916e0 100644 --- a/src/graphics/d3d12/pal_device_d3d12.c +++ b/src/graphics/d3d12/pal_device_d3d12.c @@ -31,7 +31,7 @@ PalResult PAL_CALL createDeviceD3D12( { HRESULT result; DeviceD3D12* device = nullptr; - AdapterD3D12* d3d12Adapter = (AdapterD3D12*)adapter; + AdapterD3D12* adapterImpl = (AdapterD3D12*)adapter; // check if any of the features are not supported PalAdapterFeatures adapterFeatures = getAdapterFeaturesD3D12(adapter); @@ -52,8 +52,8 @@ PalResult PAL_CALL createDeviceD3D12( // get and cache highest shader model device->shaderModel = getHighestSupportedShaderTargetD3D12(adapter, PAL_SHADER_FORMAT_DXIL); result = s_D3D12.createDevice( - (IUnknown*)d3d12Adapter->handle, - d3d12Adapter->level, + (IUnknown*)adapterImpl->handle, + adapterImpl->level, &IID_Device, (void**)&tmpDevice); @@ -297,46 +297,52 @@ PalResult PAL_CALL createDeviceD3D12( device->canFenceReset = PAL_TRUE; } - device->adapter = d3d12Adapter->handle; + device->adapter = adapterImpl->handle; *outDevice = (PalDevice*)device; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyDeviceD3D12(PalDevice* device) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (d3d12Device->meshSignature) { - d3d12Device->meshSignature->lpVtbl->Release(d3d12Device->meshSignature); + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; + if (deviceImpl->meshSignature) { + deviceImpl->meshSignature->lpVtbl->Release(deviceImpl->meshSignature); } - if (d3d12Device->raySignature) { - d3d12Device->raySignature->lpVtbl->Release(d3d12Device->raySignature); + if (deviceImpl->raySignature) { + deviceImpl->raySignature->lpVtbl->Release(deviceImpl->raySignature); } - if (d3d12Device->dispatchSignature) { - d3d12Device->dispatchSignature->lpVtbl->Release(d3d12Device->dispatchSignature); + if (deviceImpl->dispatchSignature) { + deviceImpl->dispatchSignature->lpVtbl->Release(deviceImpl->dispatchSignature); } - if (d3d12Device->drawIndexedSignature) { - d3d12Device->drawIndexedSignature->lpVtbl->Release(d3d12Device->drawIndexedSignature); + if (deviceImpl->drawIndexedSignature) { + deviceImpl->drawIndexedSignature->lpVtbl->Release(deviceImpl->drawIndexedSignature); } - if (d3d12Device->drawSignature) { - d3d12Device->drawSignature->lpVtbl->Release(d3d12Device->drawSignature); + if (deviceImpl->drawSignature) { + deviceImpl->drawSignature->lpVtbl->Release(deviceImpl->drawSignature); } - d3d12Device->rtvAllocator.heap->lpVtbl->Release(d3d12Device->rtvAllocator.heap); - d3d12Device->dsvAllocator.heap->lpVtbl->Release(d3d12Device->dsvAllocator.heap); + deviceImpl->rtvAllocator.heap->lpVtbl->Release(deviceImpl->rtvAllocator.heap); + deviceImpl->dsvAllocator.heap->lpVtbl->Release(deviceImpl->dsvAllocator.heap); - d3d12Device->queue->lpVtbl->Release(d3d12Device->queue); - d3d12Device->handle->lpVtbl->Release(d3d12Device->handle); + deviceImpl->queue->lpVtbl->Release(deviceImpl->queue); + deviceImpl->handle->lpVtbl->Release(deviceImpl->handle); - if (d3d12Device->infoQueue) { - d3d12Device->infoQueue->lpVtbl->Release(d3d12Device->infoQueue); - palFree(s_D3D12.allocator, d3d12Device->scratchBuffer); + if (deviceImpl->infoQueue) { + deviceImpl->infoQueue->lpVtbl->Release(deviceImpl->infoQueue); + palFree(s_D3D12.allocator, deviceImpl->scratchBuffer); } - palFree(s_D3D12.allocator, d3d12Device); + palFree(s_D3D12.allocator, deviceImpl); +} + +uint32_t PAL_CALL getDeviceLostReasonD3D12(PalDevice* device) +{ + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; + return deviceImpl->handle->lpVtbl->GetDeviceRemovedReason(deviceImpl->handle); } PalResult PAL_CALL allocateMemoryD3D12( @@ -347,7 +353,7 @@ PalResult PAL_CALL allocateMemoryD3D12( PalMemory** outMemory) { HRESULT result; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; MemoryD3D12* memory = nullptr; memory = palAllocate(s_D3D12.allocator, sizeof(MemoryD3D12), 0); @@ -365,11 +371,11 @@ PalResult PAL_CALL allocateMemoryD3D12( desc.Properties.Type = D3D12_HEAP_TYPE_UPLOAD; } - result = d3d12Device->handle->lpVtbl - ->CreateHeap(d3d12Device->handle, &desc, &IID_Heap, (void**)&memory->handle); + result = deviceImpl->handle->lpVtbl + ->CreateHeap(deviceImpl->handle, &desc, &IID_Heap, (void**)&memory->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -380,9 +386,9 @@ PalResult PAL_CALL allocateMemoryD3D12( void PAL_CALL freeMemoryD3D12(PalMemory* memory) { - MemoryD3D12* d3d12Memory = (MemoryD3D12*)memory; - d3d12Memory->handle->lpVtbl->Release(d3d12Memory->handle); - palFree(s_D3D12.allocator, d3d12Memory); + MemoryD3D12* memoryImpl = (MemoryD3D12*)memory; + memoryImpl->handle->lpVtbl->Release(memoryImpl->handle); + palFree(s_D3D12.allocator, memoryImpl); } void PAL_CALL querySamplerAnisotropyCapabilitiesD3D12( @@ -427,15 +433,15 @@ void PAL_CALL queryFragmentShadingRateCapabilitiesD3D12( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; caps->supportedShadingRates = (1u << PAL_FRAGMENT_SHADING_RATE_1X1); caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_1X2); caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_2X1); caps->supportedShadingRates |= (1u << PAL_FRAGMENT_SHADING_RATE_2X2); D3D12_FEATURE_DATA_D3D12_OPTIONS6 options = {0}; - d3d12Device->handle->lpVtbl->CheckFeatureSupport( - d3d12Device->handle, + deviceImpl->handle->lpVtbl->CheckFeatureSupport( + deviceImpl->handle, D3D12_FEATURE_D3D12_OPTIONS6, &options, sizeof(options)); @@ -497,10 +503,10 @@ void PAL_CALL queryDescriptorIndexingCapabilitiesD3D12( PalDevice* device, PalDescriptorIndexingCapabilities* caps) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; caps->flags = PAL_DESCRIPTOR_INDEXING_FLAG_NON_UNIFORM_INDEXING; caps->flags |= PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND; - getDescriptorTierLimitsD3D12(d3d12Device->handle, nullptr, caps); + getDescriptorTierLimitsD3D12(deviceImpl->handle, nullptr, caps); } PalResult PAL_CALL createQueueD3D12( @@ -509,35 +515,35 @@ PalResult PAL_CALL createQueueD3D12( PalQueue** outQueue) { HRESULT result; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; QueueD3D12* queue = nullptr; D3D12_COMMAND_QUEUE_DESC desc = {0}; switch (type) { case PAL_QUEUE_TYPE_COMPUTE: { desc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; - if (!d3d12Device->limits.freeComputeQueues) { + if (!deviceImpl->limits.freeComputeQueues) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } - d3d12Device->limits.freeComputeQueues--; + deviceImpl->limits.freeComputeQueues--; break; } case PAL_QUEUE_TYPE_GRAPHICS: { desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - if (!d3d12Device->limits.freeGraphicsQueues) { + if (!deviceImpl->limits.freeGraphicsQueues) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } - d3d12Device->limits.freeGraphicsQueues--; + deviceImpl->limits.freeGraphicsQueues--; break; } case PAL_QUEUE_TYPE_COPY: { desc.Type = D3D12_COMMAND_LIST_TYPE_COPY; - if (!d3d12Device->limits.freeCopyQueues) { + if (!deviceImpl->limits.freeCopyQueues) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } - d3d12Device->limits.freeCopyQueues--; + deviceImpl->limits.freeCopyQueues--; break; } } @@ -547,21 +553,21 @@ PalResult PAL_CALL createQueueD3D12( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - result = d3d12Device->handle->lpVtbl->CreateCommandQueue( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateCommandQueue( + deviceImpl->handle, &desc, &IID_Queue, (void**)&queue->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); palFree(s_D3D12.allocator, queue); return makeResultD3D12(result); } // create fence used for queue wait - result = d3d12Device->handle->lpVtbl - ->CreateFence(d3d12Device->handle, 0, 0, &IID_Fence, (void**)&queue->fence); + result = deviceImpl->handle->lpVtbl + ->CreateFence(deviceImpl->handle, 0, 0, &IID_Fence, (void**)&queue->fence); if (FAILED(result)) { palFree(s_D3D12.allocator, queue); @@ -585,22 +591,22 @@ PalResult PAL_CALL createQueueD3D12( void PAL_CALL destroyQueueD3D12(PalQueue* queue) { - QueueD3D12* d3d12Queue = (QueueD3D12*)queue; - d3d12Queue->fence->lpVtbl->Release(d3d12Queue->fence); - d3d12Queue->handle->lpVtbl->Release(d3d12Queue->handle); - CloseHandle(d3d12Queue->fenceEvent); - palFree(s_D3D12.allocator, d3d12Queue); + QueueD3D12* queueImpl = (QueueD3D12*)queue; + queueImpl->fence->lpVtbl->Release(queueImpl->fence); + queueImpl->handle->lpVtbl->Release(queueImpl->handle); + CloseHandle(queueImpl->fenceEvent); + palFree(s_D3D12.allocator, queueImpl); } PalResult PAL_CALL waitQueueD3D12(PalQueue* queue) { - QueueD3D12* d3d12Queue = (QueueD3D12*)queue; - ID3D12Fence* fence = d3d12Queue->fence; - HANDLE event = d3d12Queue->fenceEvent; + QueueD3D12* queueImpl = (QueueD3D12*)queue; + ID3D12Fence* fence = queueImpl->fence; + HANDLE event = queueImpl->fenceEvent; // wait on the fence if the submited work is not done - if (fence->lpVtbl->GetCompletedValue(fence) < d3d12Queue->fenceValue) { - fence->lpVtbl->SetEventOnCompletion(fence, d3d12Queue->fenceValue, event); + if (fence->lpVtbl->GetCompletedValue(fence) < queueImpl->fenceValue) { + fence->lpVtbl->SetEventOnCompletion(fence, queueImpl->fenceValue, event); WaitForSingleObject(event, INFINITE); CloseHandle(event); } @@ -611,8 +617,8 @@ PalBool PAL_CALL canQueuePresentD3D12( PalQueue* queue, PalSurface* surface) { - QueueD3D12* d3d12Queue = (QueueD3D12*)queue; - if (d3d12Queue->type == PAL_QUEUE_TYPE_GRAPHICS) { + QueueD3D12* queueImpl = (QueueD3D12*)queue; + if (queueImpl->type == PAL_QUEUE_TYPE_GRAPHICS) { return PAL_TRUE; // all graphics queues support presentation } return PAL_FALSE; @@ -624,7 +630,7 @@ PalResult PAL_CALL createShaderD3D12( PalShader** outShader) { ShaderD3D12* shader = nullptr; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; void* bytecode = nullptr; shader = palAllocate(s_D3D12.allocator, sizeof(ShaderD3D12), 0); @@ -657,10 +663,10 @@ PalResult PAL_CALL createShaderD3D12( void PAL_CALL destroyShaderD3D12(PalShader* shader) { - ShaderD3D12* d3dShader = (ShaderD3D12*)shader; - palFree(s_D3D12.allocator, (void*)d3dShader->byteCode.pShaderBytecode); - palFree(s_D3D12.allocator, d3dShader->entries); - palFree(s_D3D12.allocator, d3dShader); + ShaderD3D12* shaderImpl = (ShaderD3D12*)shader; + palFree(s_D3D12.allocator, (void*)shaderImpl->byteCode.pShaderBytecode); + palFree(s_D3D12.allocator, shaderImpl->entries); + palFree(s_D3D12.allocator, shaderImpl); } #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_image_d3d12.c b/src/graphics/d3d12/pal_image_d3d12.c index 8a244ebe..bfc9b1e5 100644 --- a/src/graphics/d3d12/pal_image_d3d12.c +++ b/src/graphics/d3d12/pal_image_d3d12.c @@ -129,7 +129,7 @@ PalResult PAL_CALL createImageD3D12( { HRESULT result; ImageD3D12* image = nullptr; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; image = palAllocate(s_D3D12.allocator, sizeof(ImageD3D12), 0); if (!image) { @@ -171,8 +171,8 @@ PalResult PAL_CALL createImageD3D12( D3D12_HEAP_PROPERTIES heapProps = {0}; heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateCommittedResource( + deviceImpl->handle, &heapProps, 0, &image->desc, @@ -182,7 +182,7 @@ PalResult PAL_CALL createImageD3D12( (void**)&image->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -200,39 +200,39 @@ PalResult PAL_CALL createImageD3D12( image->info.sampleCount = info->sampleCount; image->info.width = info->width; - image->device = d3d12Device; + image->device = deviceImpl; *outImage = (PalImage*)image; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyImageD3D12(PalImage* image) { - ImageD3D12* d3d12Image = (ImageD3D12*)image; - if (d3d12Image->isMemoryManaged) { - d3d12Image->handle->lpVtbl->Release(d3d12Image->handle); + ImageD3D12* imageImpl = (ImageD3D12*)image; + if (imageImpl->isMemoryManaged) { + imageImpl->handle->lpVtbl->Release(imageImpl->handle); } - palFree(s_D3D12.allocator, d3d12Image); + palFree(s_D3D12.allocator, imageImpl); } void PAL_CALL getImageInfoD3D12( PalImage* image, PalImageInfo* info) { - ImageD3D12* d3d12Image = (ImageD3D12*)image; - *info = d3d12Image->info; + ImageD3D12* imageImpl = (ImageD3D12*)image; + *info = imageImpl->info; } void PAL_CALL getImageMemoryRequirementsD3D12( PalImage* image, PalMemoryRequirements* requirements) { - ImageD3D12* d3d12Image = (ImageD3D12*)image; - ID3D12Device5* device = d3d12Image->device->handle; + ImageD3D12* imageImpl = (ImageD3D12*)image; + ID3D12Device5* device = imageImpl->device->handle; D3D12_RESOURCE_ALLOCATION_INFO allocationInfo = {0}; D3D12_RESOURCE_ALLOCATION_INFO __ret = {0}; allocationInfo = - *device->lpVtbl->GetResourceAllocationInfo(device, &__ret, 0, 1, &d3d12Image->desc); + *device->lpVtbl->GetResourceAllocationInfo(device, &__ret, 0, 1, &imageImpl->desc); requirements->supportedMemoryTypes = (1u << PAL_MEMORY_TYPE_GPU_ONLY); requirements->alignment = allocationInfo.Alignment; @@ -245,13 +245,13 @@ PalResult PAL_CALL bindImageMemoryD3D12( uint64_t offset) { HRESULT result; - ImageD3D12* d3d12Image = (ImageD3D12*)image; - ID3D12Device5* device = d3d12Image->device->handle; - if (d3d12Image->info.belongsToSwapchain) { + ImageD3D12* imageImpl = (ImageD3D12*)image; + ID3D12Device5* device = imageImpl->device->handle; + if (imageImpl->info.belongsToSwapchain) { return PAL_RESULT_CODE_INVALID_OPERATION; } - if (d3d12Image->isMemoryManaged) { + if (imageImpl->isMemoryManaged) { return PAL_RESULT_CODE_INVALID_OPERATION; } @@ -260,14 +260,14 @@ PalResult PAL_CALL bindImageMemoryD3D12( device, mem, offset, - &d3d12Image->desc, + &imageImpl->desc, 0, nullptr, &IID_Resource, - (void**)&d3d12Image->handle); + (void**)&imageImpl->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Image->device); + pollMessagesD3D12(imageImpl->device); return makeResultD3D12(result); } @@ -282,8 +282,8 @@ PalResult PAL_CALL createImageViewD3D12( { HRESULT result; ImageViewD3D12* imageView = nullptr; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - ImageD3D12* d3d12Image = (ImageD3D12*)image; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; + ImageD3D12* imageImpl = (ImageD3D12*)image; imageView = palAllocate(s_D3D12.allocator, sizeof(ImageViewD3D12), 0); if (!imageView) { @@ -291,12 +291,12 @@ PalResult PAL_CALL createImageViewD3D12( } imageView->heapIndex = UINT32_MAX; - PalBool hasRTV = (d3d12Image->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); - PalBool hasDSV = (d3d12Image->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); + PalBool hasRTV = (imageImpl->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); + PalBool hasDSV = (imageImpl->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); imageView->format = formatToD3D12(info->format); if (info->subresourceRange.aspect == PAL_IMAGE_ASPECT_COLOR && hasRTV) { - RTVHeapAllocator* allocator = &d3d12Device->rtvAllocator; + RTVHeapAllocator* allocator = &deviceImpl->rtvAllocator; uint32_t index = allocator->freeTop; allocator->freeTop = allocator->freeList[index]; @@ -307,11 +307,11 @@ PalResult PAL_CALL createImageViewD3D12( desc.Format = imageView->format; fillSubresourceD3D12(DESC_TYPE_RTV, info->type, &info->subresourceRange, &desc); imageView->heapIndex = index; - d3d12Device->handle->lpVtbl - ->CreateRenderTargetView(d3d12Device->handle, d3d12Image->handle, &desc, dst); + deviceImpl->handle->lpVtbl + ->CreateRenderTargetView(deviceImpl->handle, imageImpl->handle, &desc, dst); } else if (info->subresourceRange.aspect != PAL_IMAGE_ASPECT_COLOR && hasDSV) { - DSVHeapAllocator* allocator = &d3d12Device->dsvAllocator; + DSVHeapAllocator* allocator = &deviceImpl->dsvAllocator; uint32_t index = allocator->freeTop; allocator->freeTop = allocator->freeList[index]; @@ -322,38 +322,38 @@ PalResult PAL_CALL createImageViewD3D12( desc.Format = imageView->format; fillSubresourceD3D12(DESC_TYPE_DSV, info->type, &info->subresourceRange, &desc); imageView->heapIndex = index; - d3d12Device->handle->lpVtbl - ->CreateDepthStencilView(d3d12Device->handle, d3d12Image->handle, &desc, dst); + deviceImpl->handle->lpVtbl + ->CreateDepthStencilView(deviceImpl->handle, imageImpl->handle, &desc, dst); } imageView->range = info->subresourceRange; imageView->type = info->type; - imageView->image = d3d12Image; + imageView->image = imageImpl; - imageView->device = d3d12Device; + imageView->device = deviceImpl; *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyImageViewD3D12(PalImageView* imageView) { - ImageViewD3D12* d3dImageView = (ImageViewD3D12*)imageView; - DeviceD3D12* device = d3dImageView->device; + ImageViewD3D12* imageViewImpl = (ImageViewD3D12*)imageView; + DeviceD3D12* device = imageViewImpl->device; RTVHeapAllocator* allocator = nullptr; - if (d3dImageView->heapIndex != UINT32_MAX) { - if (d3dImageView->range.aspect == PAL_IMAGE_ASPECT_COLOR) { + if (imageViewImpl->heapIndex != UINT32_MAX) { + if (imageViewImpl->range.aspect == PAL_IMAGE_ASPECT_COLOR) { RTVHeapAllocator* allocator = &device->rtvAllocator; - allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; - allocator->freeTop = d3dImageView->heapIndex; + allocator->freeList[imageViewImpl->heapIndex] = allocator->freeTop; + allocator->freeTop = imageViewImpl->heapIndex; } else { DSVHeapAllocator* allocator = &device->dsvAllocator; - allocator->freeList[d3dImageView->heapIndex] = allocator->freeTop; - allocator->freeTop = d3dImageView->heapIndex; + allocator->freeList[imageViewImpl->heapIndex] = allocator->freeTop; + allocator->freeTop = imageViewImpl->heapIndex; } } - palFree(s_D3D12.allocator, d3dImageView); + palFree(s_D3D12.allocator, imageViewImpl); } PalResult PAL_CALL createSamplerD3D12( @@ -361,8 +361,8 @@ PalResult PAL_CALL createSamplerD3D12( const PalSamplerCreateInfo* info, PalSampler** outSampler) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - if (info->maxAnisotropy > d3d12Device->limits.maxAnisotropy) { + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; + if (info->maxAnisotropy > deviceImpl->limits.maxAnisotropy) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -401,8 +401,7 @@ PalResult PAL_CALL createSamplerD3D12( void PAL_CALL destroySamplerD3D12(PalSampler* sampler) { - SamplerD3D12* d3dSampler = (SamplerD3D12*)sampler; - palFree(s_D3D12.allocator, d3dSampler); + palFree(s_D3D12.allocator, sampler); } #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_pipeline_d3d12.c b/src/graphics/d3d12/pal_pipeline_d3d12.c index b7cf2556..5f2d172a 100644 --- a/src/graphics/d3d12/pal_pipeline_d3d12.c +++ b/src/graphics/d3d12/pal_pipeline_d3d12.c @@ -387,7 +387,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( const PalPipelineLayoutCreateInfo* info, PalPipelineLayout** outLayout) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; PipelineLayoutD3D12* layout = nullptr; uint32_t resourceCount = 0; uint32_t samplerCount = 0; @@ -404,11 +404,11 @@ PalResult PAL_CALL createPipelineLayoutD3D12( D3D12_ROOT_SIGNATURE_FLAGS rootFlags = 0; rootFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; - if (info->descriptorSetLayoutCount > d3d12Device->limits.maxBoundDescriptorSets) { + if (info->descriptorSetLayoutCount > deviceImpl->limits.maxBoundDescriptorSets) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (d3d12Device->shaderModel >= PAL_MAKE_SHADER_TARGET(6, 6)) { + if (deviceImpl->shaderModel >= PAL_MAKE_SHADER_TARGET(6, 6)) { rootFlags |= D3D12_ROOT_SIGNATURE_FLAG_CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED; rootFlags |= D3D12_ROOT_SIGNATURE_FLAG_SAMPLER_HEAP_DIRECTLY_INDEXED; } @@ -430,7 +430,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( if (info->usePushConstant) { pushConstantSize = info->pushConstantInfo.offset + info->pushConstantInfo.size; - if (pushConstantSize > d3d12Device->limits.maxPushConstantSize) { + if (pushConstantSize > deviceImpl->limits.maxPushConstantSize) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -545,12 +545,12 @@ PalResult PAL_CALL createPipelineLayoutD3D12( ID3DBlob* blob = nullptr; HRESULT result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } - result = d3d12Device->handle->lpVtbl->CreateRootSignature( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateRootSignature( + deviceImpl->handle, 0, blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), @@ -558,7 +558,7 @@ PalResult PAL_CALL createPipelineLayoutD3D12( (void**)&layout->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -581,9 +581,9 @@ PalResult PAL_CALL createPipelineLayoutD3D12( void PAL_CALL destroyPipelineLayoutD3D12(PalPipelineLayout* layout) { - PipelineLayoutD3D12* d3d12Layout = (PipelineLayoutD3D12*)layout; - d3d12Layout->handle->lpVtbl->Release(d3d12Layout->handle); - palFree(s_D3D12.allocator, d3d12Layout); + PipelineLayoutD3D12* layoutImpl = (PipelineLayoutD3D12*)layout; + layoutImpl->handle->lpVtbl->Release(layoutImpl->handle); + palFree(s_D3D12.allocator, layoutImpl); } PalResult PAL_CALL createGraphicsPipelineD3D12( @@ -596,7 +596,7 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( uint32_t totalSize = 0; PalBool alphaToCoverageEnable = PAL_FALSE; PipelineD3D12* pipeline = nullptr; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; PipelineLayoutD3D12* layout = (PipelineLayoutD3D12*)info->pipelineLayout; D3D12_INPUT_ELEMENT_DESC* elementDescs = nullptr; @@ -680,11 +680,11 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( vertexCount += layout->attributeCount; } - if (info->vertexLayoutCount > d3d12Device->limits.maxVertexLayouts) { + if (info->vertexLayoutCount > deviceImpl->limits.maxVertexLayouts) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (vertexCount > d3d12Device->limits.maxVertexAttributes) { + if (vertexCount > deviceImpl->limits.maxVertexAttributes) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -904,18 +904,18 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( PalStencilOpState* back = &state->backStencilOpState; PalStencilOpState* front = &state->frontStencilOpState; - D3D12_DEPTH_STENCILOP_DESC* d3dBack = &depthStencilStream->desc.BackFace; - D3D12_DEPTH_STENCILOP_DESC* d3dFront = &depthStencilStream->desc.FrontFace; + D3D12_DEPTH_STENCILOP_DESC* backDesc = &depthStencilStream->desc.BackFace; + D3D12_DEPTH_STENCILOP_DESC* frontDesc = &depthStencilStream->desc.FrontFace; - d3dBack->StencilFunc = compareOpToD3D12(back->compareOp); - d3dBack->StencilDepthFailOp = stencilOpToD3D12(back->depthFailOp); - d3dBack->StencilFailOp = stencilOpToD3D12(back->failOp); - d3dBack->StencilPassOp = stencilOpToD3D12(back->passOp); + backDesc->StencilFunc = compareOpToD3D12(back->compareOp); + backDesc->StencilDepthFailOp = stencilOpToD3D12(back->depthFailOp); + backDesc->StencilFailOp = stencilOpToD3D12(back->failOp); + backDesc->StencilPassOp = stencilOpToD3D12(back->passOp); - d3dFront->StencilFunc = compareOpToD3D12(front->compareOp); - d3dFront->StencilDepthFailOp = stencilOpToD3D12(front->depthFailOp); - d3dFront->StencilFailOp = stencilOpToD3D12(front->failOp); - d3dFront->StencilPassOp = stencilOpToD3D12(front->passOp); + frontDesc->StencilFunc = compareOpToD3D12(front->compareOp); + frontDesc->StencilDepthFailOp = stencilOpToD3D12(front->depthFailOp); + frontDesc->StencilFailOp = stencilOpToD3D12(front->failOp); + frontDesc->StencilPassOp = stencilOpToD3D12(front->passOp); depthStencilStream->desc.DepthFunc = compareOpToD3D12(state->compareOp); depthStencilStream->desc.DepthEnable = state->enableDepthTest; @@ -1018,14 +1018,14 @@ PalResult PAL_CALL createGraphicsPipelineD3D12( streamDesc.pPipelineStateSubobjectStream = &graphicsStreamDesc; streamDesc.SizeInBytes = totalSize; - result = d3d12Device->handle->lpVtbl->CreatePipelineState( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreatePipelineState( + deviceImpl->handle, &streamDesc, &IID_PipelineState, &pipeline->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -1052,7 +1052,7 @@ PalResult PAL_CALL createComputePipelineD3D12( const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline) { - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; PipelineLayoutD3D12* layout = (PipelineLayoutD3D12*)info->pipelineLayout; ShaderD3D12* shader = (ShaderD3D12*)info->computeShader; PipelineD3D12* pipeline = nullptr; @@ -1066,14 +1066,14 @@ PalResult PAL_CALL createComputePipelineD3D12( desc.CS = shader->byteCode; desc.pRootSignature = layout->handle; - HRESULT result = d3d12Device->handle->lpVtbl->CreateComputePipelineState( - d3d12Device->handle, + HRESULT result = deviceImpl->handle->lpVtbl->CreateComputePipelineState( + deviceImpl->handle, &desc, &IID_PipelineState, &pipeline->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -1094,19 +1094,19 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( PalPipeline** outPipeline) { HRESULT result; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; PipelineLayoutD3D12* layout = (PipelineLayoutD3D12*)info->pipelineLayout; PipelineD3D12* pipeline = nullptr; - if (info->maxAttributeSize > d3d12Device->limits.maxHitAttributeSize) { + if (info->maxAttributeSize > deviceImpl->limits.maxHitAttributeSize) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (info->maxPayloadSize > d3d12Device->limits.maxPayloadSize) { + if (info->maxPayloadSize > deviceImpl->limits.maxPayloadSize) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } - if (info->maxRecursionDepth > d3d12Device->limits.maxRecursionDepth) { + if (info->maxRecursionDepth > deviceImpl->limits.maxRecursionDepth) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -1356,12 +1356,12 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( ID3DBlob* blob = nullptr; result = s_D3D12.serializeVersionedRootSignature(&rootDesc, &blob, nullptr); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } - result = d3d12Device->handle->lpVtbl->CreateRootSignature( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateRootSignature( + deviceImpl->handle, 0, blob->lpVtbl->GetBufferPointer(blob), blob->lpVtbl->GetBufferSize(blob), @@ -1369,7 +1369,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( (void**)&pipeline->localRootSignature); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -1393,14 +1393,14 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( desc.NumSubobjects = subObjectCount; desc.pSubobjects = subObjects; - result = d3d12Device->handle->lpVtbl->CreateStateObject( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateStateObject( + deviceImpl->handle, &desc, &IID_StateObject, &pipeline->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -1422,29 +1422,29 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) { - PipelineD3D12* d3dPipeline = (PipelineD3D12*)pipeline; - if (d3dPipeline->type == RAY_TRACING_PIPELINE) { - ID3D12StateObject* handle = d3dPipeline->handle; + PipelineD3D12* pipelineImpl = (PipelineD3D12*)pipeline; + if (pipelineImpl->type == RAY_TRACING_PIPELINE) { + ID3D12StateObject* handle = pipelineImpl->handle; handle->lpVtbl->Release(handle); } else { - ID3D12PipelineState* handle = d3dPipeline->handle; + ID3D12PipelineState* handle = pipelineImpl->handle; handle->lpVtbl->Release(handle); } - if (d3dPipeline->localRootSignature) { - d3dPipeline->localRootSignature->lpVtbl->Release(d3dPipeline->localRootSignature); + if (pipelineImpl->localRootSignature) { + pipelineImpl->localRootSignature->lpVtbl->Release(pipelineImpl->localRootSignature); } - if (d3dPipeline->strides) { - palFree(s_D3D12.allocator, d3dPipeline->strides); + if (pipelineImpl->strides) { + palFree(s_D3D12.allocator, pipelineImpl->strides); } - if (d3dPipeline->shaderExports) { - palFree(s_D3D12.allocator, d3dPipeline->shaderExports); + if (pipelineImpl->shaderExports) { + palFree(s_D3D12.allocator, pipelineImpl->shaderExports); } - palFree(s_D3D12.allocator, d3dPipeline); + palFree(s_D3D12.allocator, pipelineImpl); } #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_sbt_d3d12.c b/src/graphics/d3d12/pal_sbt_d3d12.c index adcbc24b..84e64f88 100644 --- a/src/graphics/d3d12/pal_sbt_d3d12.c +++ b/src/graphics/d3d12/pal_sbt_d3d12.c @@ -16,7 +16,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( PalShaderBindingTable** outSbt) { HRESULT result; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; ShaderBindingTableD3D12* sbt = nullptr; PipelineD3D12* pipeline = (PipelineD3D12*)info->rayTracingPipeline; ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; @@ -71,7 +71,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( ID3D12StateObjectProperties* props = NULL; result = handle->lpVtbl->QueryInterface(handle, &IID_StateObjectProps, (void**)&props); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -160,8 +160,8 @@ PalResult PAL_CALL createShaderBindingTableD3D12( bufferDesc.SampleDesc.Count = 1; bufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; - result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateCommittedResource( + deviceImpl->handle, &heapProps, 0, &bufferDesc, @@ -171,14 +171,14 @@ PalResult PAL_CALL createShaderBindingTableD3D12( (void**)&sbt->buffer); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } // create staging buffer heapProps.Type = D3D12_HEAP_TYPE_UPLOAD; - result = d3d12Device->handle->lpVtbl->CreateCommittedResource( - d3d12Device->handle, + result = deviceImpl->handle->lpVtbl->CreateCommittedResource( + deviceImpl->handle, &heapProps, 0, &bufferDesc, @@ -188,7 +188,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( (void**)&sbt->stagingBuffer); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -234,7 +234,7 @@ PalResult PAL_CALL createShaderBindingTableD3D12( void* ptr = nullptr; result = sbt->stagingBuffer->lpVtbl->Map(sbt->stagingBuffer, 0, nullptr, &ptr); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -348,11 +348,11 @@ PalResult PAL_CALL createShaderBindingTableD3D12( void PAL_CALL destroyShaderBindingTableD3D12(PalShaderBindingTable* sbt) { - ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; - d3d12Sbt->buffer->lpVtbl->Release(d3d12Sbt->buffer); - d3d12Sbt->stagingBuffer->lpVtbl->Unmap(d3d12Sbt->stagingBuffer, 0, nullptr); - d3d12Sbt->stagingBuffer->lpVtbl->Release(d3d12Sbt->stagingBuffer); - palFree(s_D3D12.allocator, d3d12Sbt); + ShaderBindingTableD3D12* sbtImpl = (ShaderBindingTableD3D12*)sbt; + sbtImpl->buffer->lpVtbl->Release(sbtImpl->buffer); + sbtImpl->stagingBuffer->lpVtbl->Unmap(sbtImpl->stagingBuffer, 0, nullptr); + sbtImpl->stagingBuffer->lpVtbl->Release(sbtImpl->stagingBuffer); + palFree(s_D3D12.allocator, sbtImpl); } void PAL_CALL updateShaderBindingTableD3D12( @@ -360,8 +360,8 @@ void PAL_CALL updateShaderBindingTableD3D12( uint32_t count, PalShaderBindingTableRecordInfo* infos) { - ShaderBindingTableD3D12* d3d12Sbt = (ShaderBindingTableD3D12*)sbt; - PipelineD3D12* pipeline = d3d12Sbt->pipeline; + ShaderBindingTableD3D12* sbtImpl = (ShaderBindingTableD3D12*)sbt; + PipelineD3D12* pipeline = sbtImpl->pipeline; ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; uint64_t stride = 0; @@ -376,35 +376,35 @@ void PAL_CALL updateShaderBindingTableD3D12( if (index < sbtInfo->raygenCount) { // raygen group offset = 0; - stride = d3d12Sbt->raygen.region.StrideInBytes; - startIndex = d3d12Sbt->raygen.startIndex; + stride = sbtImpl->raygen.region.StrideInBytes; + startIndex = sbtImpl->raygen.startIndex; } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { // miss group - offset = d3d12Sbt->miss.offset; - stride = d3d12Sbt->miss.region.StrideInBytes; - startIndex = d3d12Sbt->miss.startIndex; + offset = sbtImpl->miss.offset; + stride = sbtImpl->miss.region.StrideInBytes; + startIndex = sbtImpl->miss.startIndex; } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { // hit group - offset = d3d12Sbt->hit.offset; - stride = d3d12Sbt->hit.region.StrideInBytes; - startIndex = d3d12Sbt->hit.startIndex; + offset = sbtImpl->hit.offset; + stride = sbtImpl->hit.region.StrideInBytes; + startIndex = sbtImpl->hit.startIndex; } else { // callable group - offset = d3d12Sbt->callable.offset; - stride = d3d12Sbt->callable.region.StrideInBytes; - startIndex = d3d12Sbt->callable.startIndex; + offset = sbtImpl->callable.offset; + stride = sbtImpl->callable.region.StrideInBytes; + startIndex = sbtImpl->callable.startIndex; } // write payload uint32_t localIndex = index - startIndex; - uint8_t* dst = (uint8_t*)d3d12Sbt->stagingPtr + offset + (localIndex * stride); - memcpy(dst + d3d12Sbt->handleSize, info->localData, info->localDataSize); + uint8_t* dst = (uint8_t*)sbtImpl->stagingPtr + offset + (localIndex * stride); + memcpy(dst + sbtImpl->handleSize, info->localData, info->localDataSize); } - d3d12Sbt->isDirty = PAL_TRUE; + sbtImpl->isDirty = PAL_TRUE; } #endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file diff --git a/src/graphics/d3d12/pal_swapchain_d3d12.c b/src/graphics/d3d12/pal_swapchain_d3d12.c index fbe1eb87..b62f92d6 100644 --- a/src/graphics/d3d12/pal_swapchain_d3d12.c +++ b/src/graphics/d3d12/pal_swapchain_d3d12.c @@ -43,7 +43,7 @@ void PAL_CALL getSurfaceCapabilitiesD3D12( PalSurfaceCapabilities* caps) { SurfaceD3D12* d3dSurface = (SurfaceD3D12*)surface; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; PalBool supportHDR10 = PAL_FALSE; IDXGISwapChain1* swapchain1 = nullptr; IDXGISwapChain3* swapchain3 = nullptr; @@ -60,7 +60,7 @@ void PAL_CALL getSurfaceCapabilitiesD3D12( s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( s_D3D12.factory, - (IUnknown*)d3d12Device->queue, + (IUnknown*)deviceImpl->queue, d3dSurface->handle, &desc, nullptr, @@ -116,8 +116,8 @@ void PAL_CALL getSurfaceCapabilitiesD3D12( for (int i = 0; i < PAL_SURFACE_FORMAT_COUNT; i++) { formatSupport.Format = baseFormats[i]; - d3d12Device->handle->lpVtbl->CheckFeatureSupport( - d3d12Device->handle, + deviceImpl->handle->lpVtbl->CheckFeatureSupport( + deviceImpl->handle, D3D12_FEATURE_FORMAT_SUPPORT, &formatSupport, sizeof(formatSupport)); @@ -156,12 +156,12 @@ PalResult PAL_CALL createSwapchainD3D12( { HRESULT result; SurfaceD3D12* d3dSurface = (SurfaceD3D12*)surface; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; - QueueD3D12* d3d12Queue = (QueueD3D12*)queue; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; + QueueD3D12* queueImpl = (QueueD3D12*)queue; SwapchainD3D12* swapchain = nullptr; PalBool isHDRColorspace = PAL_FALSE; - if (d3d12Queue->type != PAL_QUEUE_TYPE_GRAPHICS) { + if (queueImpl->type != PAL_QUEUE_TYPE_GRAPHICS) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -228,7 +228,7 @@ PalResult PAL_CALL createSwapchainD3D12( swapchain->flags = desc.Flags; result = s_D3D12.factory->lpVtbl->CreateSwapChainForHwnd( s_D3D12.factory, - (IUnknown*)d3d12Queue->handle, + (IUnknown*)queueImpl->handle, d3dSurface->handle, &desc, nullptr, @@ -236,7 +236,7 @@ PalResult PAL_CALL createSwapchainD3D12( &swapchain1); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); return makeResultD3D12(result); } @@ -266,7 +266,7 @@ PalResult PAL_CALL createSwapchainD3D12( swapchain->handle->lpVtbl->GetBuffer(swapchain->handle, i, &IID_Resource, (void**)&tmp); ImageD3D12* image = &swapchain->images[i]; - image->device = d3d12Device; + image->device = deviceImpl; image->handle = tmp; image->info.belongsToSwapchain = PAL_TRUE; @@ -287,8 +287,8 @@ PalResult PAL_CALL createSwapchainD3D12( swapchain->windowWidth = windowRect.right - windowRect.left; swapchain->windowWidth = windowRect.bottom - windowRect.top; - swapchain->device = d3d12Device; - swapchain->queue = d3d12Queue->handle; + swapchain->device = deviceImpl; + swapchain->queue = queueImpl->handle; swapchain->imageCount = info->imageCount; *outSwapchain = (PalSwapchain*)swapchain; return PAL_RESULT_SUCCESS; @@ -296,21 +296,21 @@ PalResult PAL_CALL createSwapchainD3D12( void PAL_CALL destroySwapchainD3D12(PalSwapchain* swapchain) { - SwapchainD3D12* d3d12Swapchain = (SwapchainD3D12*)swapchain; - d3d12Swapchain->handle->lpVtbl->Release(d3d12Swapchain->handle); - palFree(s_D3D12.allocator, d3d12Swapchain->images); - palFree(s_D3D12.allocator, d3d12Swapchain); + SwapchainD3D12* swapchainImpl = (SwapchainD3D12*)swapchain; + swapchainImpl->handle->lpVtbl->Release(swapchainImpl->handle); + palFree(s_D3D12.allocator, swapchainImpl->images); + palFree(s_D3D12.allocator, swapchainImpl); } PalImage* PAL_CALL getSwapchainImageD3D12( PalSwapchain* swapchain, uint32_t index) { - SwapchainD3D12* d3d12Swapchain = (SwapchainD3D12*)swapchain; - if (index > d3d12Swapchain->imageCount) { + SwapchainD3D12* swapchainImpl = (SwapchainD3D12*)swapchain; + if (index > swapchainImpl->imageCount) { return nullptr; } - return (PalImage*)&d3d12Swapchain->images[index]; + return (PalImage*)&swapchainImpl->images[index]; } PalResult PAL_CALL getNextSwapchainImageD3D12( @@ -320,16 +320,16 @@ PalResult PAL_CALL getNextSwapchainImageD3D12( { HRESULT result; uint32_t index = 0; - SwapchainD3D12* d3d12Swapchain = (SwapchainD3D12*)swapchain; - ID3D12CommandQueue* queue = d3d12Swapchain->queue; + SwapchainD3D12* swapchainImpl = (SwapchainD3D12*)swapchain; + ID3D12CommandQueue* queue = swapchainImpl->queue; - index = d3d12Swapchain->handle->lpVtbl->GetCurrentBackBufferIndex(d3d12Swapchain->handle); + index = swapchainImpl->handle->lpVtbl->GetCurrentBackBufferIndex(swapchainImpl->handle); if (info->fence) { FenceD3D12* fence = (FenceD3D12*)info->fence; fence->value++; result = queue->lpVtbl->Signal(queue, fence->handle, fence->value); if (FAILED(result)) { - pollMessagesD3D12(d3d12Swapchain->device); + pollMessagesD3D12(swapchainImpl->device); return makeResultD3D12(result); } } @@ -353,8 +353,8 @@ PalResult PAL_CALL presentSwapchainD3D12( PalSemaphore* waitSemaphore) { HRESULT result; - SwapchainD3D12* d3d12Swapchain = (SwapchainD3D12*)swapchain; - ID3D12CommandQueue* queue = d3d12Swapchain->queue; + SwapchainD3D12* swapchainImpl = (SwapchainD3D12*)swapchain; + ID3D12CommandQueue* queue = swapchainImpl->queue; if (waitSemaphore) { SemaphoreD3D12* semaphore = (SemaphoreD3D12*)waitSemaphore; @@ -371,23 +371,23 @@ PalResult PAL_CALL presentSwapchainD3D12( } // poll pending messages - pollMessagesD3D12(d3d12Swapchain->device); + pollMessagesD3D12(swapchainImpl->device); - result = d3d12Swapchain->handle->lpVtbl->Present( - d3d12Swapchain->handle, - d3d12Swapchain->syncInterval, - d3d12Swapchain->presentFlags); + result = swapchainImpl->handle->lpVtbl->Present( + swapchainImpl->handle, + swapchainImpl->syncInterval, + swapchainImpl->presentFlags); - pollMessagesD3D12(d3d12Swapchain->device); + pollMessagesD3D12(swapchainImpl->device); if (FAILED(result)) { if (result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET) { - pollMessagesD3D12(d3d12Swapchain->device); + pollMessagesD3D12(swapchainImpl->device); return makeResultD3D12(result); } // check if swapchain needs to be resize RECT windowRect; - PalBool ret = GetClientRect((HWND)d3d12Swapchain->surface->handle, &windowRect); + PalBool ret = GetClientRect((HWND)swapchainImpl->surface->handle, &windowRect); uint32_t w = windowRect.right - windowRect.left; uint32_t h = windowRect.bottom - windowRect.top; if (!ret) { @@ -397,7 +397,7 @@ PalResult PAL_CALL presentSwapchainD3D12( GetLastError()); } - if (w != d3d12Swapchain->windowWidth || h != d3d12Swapchain->windowHeight) { + if (w != swapchainImpl->windowWidth || h != swapchainImpl->windowHeight) { return PAL_RESULT_CODE_OUT_OF_DATE; } @@ -413,27 +413,27 @@ PalResult PAL_CALL resizeSwapchainD3D12( uint32_t newHeight) { HRESULT result; - SwapchainD3D12* d3d12Swapchain = (SwapchainD3D12*)swapchain; - result = d3d12Swapchain->handle->lpVtbl->ResizeBuffers( - d3d12Swapchain->handle, - d3d12Swapchain->imageCount, + SwapchainD3D12* swapchainImpl = (SwapchainD3D12*)swapchain; + result = swapchainImpl->handle->lpVtbl->ResizeBuffers( + swapchainImpl->handle, + swapchainImpl->imageCount, newWidth, newHeight, - d3d12Swapchain->format, - d3d12Swapchain->flags); + swapchainImpl->format, + swapchainImpl->flags); if (FAILED(result)) { - pollMessagesD3D12(d3d12Swapchain->device); + pollMessagesD3D12(swapchainImpl->device); return makeResultD3D12(result); } // fill all images with the creation info - for (int i = 0; i < d3d12Swapchain->imageCount; i++) { + for (int i = 0; i < swapchainImpl->imageCount; i++) { ID3D12Resource* tmp = nullptr; - d3d12Swapchain->handle->lpVtbl - ->GetBuffer(d3d12Swapchain->handle, i, &IID_Resource, (void**)&tmp); + swapchainImpl->handle->lpVtbl + ->GetBuffer(swapchainImpl->handle, i, &IID_Resource, (void**)&tmp); - ImageD3D12* image = &d3d12Swapchain->images[i]; + ImageD3D12* image = &swapchainImpl->images[i]; image->handle = tmp; image->info.height = newHeight; image->info.width = newWidth; @@ -441,7 +441,7 @@ PalResult PAL_CALL resizeSwapchainD3D12( // get and cache window size for swapchain out of date error RECT windowRect; - SurfaceD3D12* surface = d3d12Swapchain->surface; + SurfaceD3D12* surface = swapchainImpl->surface; if (!GetClientRect((HWND)surface->handle, &windowRect)) { return palMakeResult( PAL_RESULT_CODE_PLATFORM_FAILURE, @@ -449,8 +449,8 @@ PalResult PAL_CALL resizeSwapchainD3D12( GetLastError()); } - d3d12Swapchain->windowWidth = windowRect.right - windowRect.left; - d3d12Swapchain->windowWidth = windowRect.bottom - windowRect.top; + swapchainImpl->windowWidth = windowRect.right - windowRect.left; + swapchainImpl->windowWidth = windowRect.bottom - windowRect.top; return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/d3d12/pal_sync_d3d12.c b/src/graphics/d3d12/pal_sync_d3d12.c index c553f55f..1822bb9e 100644 --- a/src/graphics/d3d12/pal_sync_d3d12.c +++ b/src/graphics/d3d12/pal_sync_d3d12.c @@ -14,7 +14,7 @@ PalResult PAL_CALL createFenceD3D12( PalFence** outFence) { HRESULT result; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; FenceD3D12* fence = nullptr; fence = palAllocate(s_D3D12.allocator, sizeof(FenceD3D12), 0); @@ -22,11 +22,11 @@ PalResult PAL_CALL createFenceD3D12( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - result = d3d12Device->handle->lpVtbl - ->CreateFence(d3d12Device->handle, 0, 0, &IID_Fence, (void**)&fence->handle); + result = deviceImpl->handle->lpVtbl + ->CreateFence(deviceImpl->handle, 0, 0, &IID_Fence, (void**)&fence->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); palFree(s_D3D12.allocator, fence); return makeResultD3D12(result); } @@ -41,7 +41,7 @@ PalResult PAL_CALL createFenceD3D12( } fence->canReset = PAL_FALSE; - if (d3d12Device->canFenceReset) { + if (deviceImpl->canFenceReset) { fence->canReset = PAL_TRUE; } @@ -53,10 +53,10 @@ PalResult PAL_CALL createFenceD3D12( void PAL_CALL destroyFenceD3D12(PalFence* fence) { - FenceD3D12* d3d12Fence = (FenceD3D12*)fence; - d3d12Fence->handle->lpVtbl->Release(d3d12Fence->handle); - CloseHandle(d3d12Fence->event); - palFree(s_D3D12.allocator, d3d12Fence); + FenceD3D12* fenceImpl = (FenceD3D12*)fence; + fenceImpl->handle->lpVtbl->Release(fenceImpl->handle); + CloseHandle(fenceImpl->event); + palFree(s_D3D12.allocator, fenceImpl); } PalResult PAL_CALL waitFenceD3D12( @@ -64,13 +64,13 @@ PalResult PAL_CALL waitFenceD3D12( uint64_t timeout) { HRESULT result; - FenceD3D12* d3d12Fence = (FenceD3D12*)fence; + FenceD3D12* fenceImpl = (FenceD3D12*)fence; DWORD ret = 0; - uint64_t value = d3d12Fence->value; - HANDLE event = d3d12Fence->event; + uint64_t value = fenceImpl->value; + HANDLE event = fenceImpl->event; - if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) < value) { - result = d3d12Fence->handle->lpVtbl->SetEventOnCompletion(d3d12Fence->handle, value, event); + if (fenceImpl->handle->lpVtbl->GetCompletedValue(fenceImpl->handle) < value) { + result = fenceImpl->handle->lpVtbl->SetEventOnCompletion(fenceImpl->handle, value, event); if (FAILED(result)) { return makeResultD3D12(result); @@ -92,16 +92,16 @@ PalResult PAL_CALL waitFenceD3D12( PalResult PAL_CALL resetFenceD3D12(PalFence* fence) { - FenceD3D12* d3d12Fence = (FenceD3D12*)fence; - d3d12Fence->handle->lpVtbl->Signal(d3d12Fence->handle, 0); - d3d12Fence->value = 0; + FenceD3D12* fenceImpl = (FenceD3D12*)fence; + fenceImpl->handle->lpVtbl->Signal(fenceImpl->handle, 0); + fenceImpl->value = 0; return PAL_RESULT_SUCCESS; } PalBool PAL_CALL isFenceSignaledD3D12(PalFence* fence) { - FenceD3D12* d3d12Fence = (FenceD3D12*)fence; - if (d3d12Fence->handle->lpVtbl->GetCompletedValue(d3d12Fence->handle) == 0) { + FenceD3D12* fenceImpl = (FenceD3D12*)fence; + if (fenceImpl->handle->lpVtbl->GetCompletedValue(fenceImpl->handle) == 0) { return PAL_FALSE; } return PAL_TRUE; @@ -113,7 +113,7 @@ PalResult PAL_CALL createSemaphoreD3D12( PalSemaphore** outSemaphore) { HRESULT result; - DeviceD3D12* d3d12Device = (DeviceD3D12*)device; + DeviceD3D12* deviceImpl = (DeviceD3D12*)device; SemaphoreD3D12* semaphore = nullptr; semaphore = palAllocate(s_D3D12.allocator, sizeof(SemaphoreD3D12), 0); @@ -125,11 +125,11 @@ PalResult PAL_CALL createSemaphoreD3D12( semaphore->isTimeline = PAL_TRUE; } - result = d3d12Device->handle->lpVtbl - ->CreateFence(d3d12Device->handle, 0, 0, &IID_Fence, (void**)&semaphore->handle); + result = deviceImpl->handle->lpVtbl + ->CreateFence(deviceImpl->handle, 0, 0, &IID_Fence, (void**)&semaphore->handle); if (FAILED(result)) { - pollMessagesD3D12(d3d12Device); + pollMessagesD3D12(deviceImpl); palFree(s_D3D12.allocator, semaphore); return makeResultD3D12(result); } @@ -151,10 +151,10 @@ PalResult PAL_CALL createSemaphoreD3D12( void PAL_CALL destroySemaphoreD3D12(PalSemaphore* semaphore) { - SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; - d3d12Semaphore->handle->lpVtbl->Release(d3d12Semaphore->handle); - CloseHandle(d3d12Semaphore->event); - palFree(s_D3D12.allocator, d3d12Semaphore); + SemaphoreD3D12* semaphoreImpl = (SemaphoreD3D12*)semaphore; + semaphoreImpl->handle->lpVtbl->Release(semaphoreImpl->handle); + CloseHandle(semaphoreImpl->event); + palFree(s_D3D12.allocator, semaphoreImpl); } PalResult PAL_CALL waitSemaphoreD3D12( @@ -164,12 +164,12 @@ PalResult PAL_CALL waitSemaphoreD3D12( { HRESULT result; DWORD ret = 0; - SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; + SemaphoreD3D12* semaphoreImpl = (SemaphoreD3D12*)semaphore; - HANDLE event = d3d12Semaphore->event; - if (d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle) < value) { - result = d3d12Semaphore->handle->lpVtbl->SetEventOnCompletion( - d3d12Semaphore->handle, + HANDLE event = semaphoreImpl->event; + if (semaphoreImpl->handle->lpVtbl->GetCompletedValue(semaphoreImpl->handle) < value) { + result = semaphoreImpl->handle->lpVtbl->SetEventOnCompletion( + semaphoreImpl->handle, value, event); @@ -196,8 +196,8 @@ PalResult PAL_CALL signalSemaphoreD3D12( PalQueue* queue, uint64_t value) { - SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; - HRESULT result = d3d12Semaphore->handle->lpVtbl->Signal(d3d12Semaphore->handle, value); + SemaphoreD3D12* semaphoreImpl = (SemaphoreD3D12*)semaphore; + HRESULT result = semaphoreImpl->handle->lpVtbl->Signal(semaphoreImpl->handle, value); if (FAILED(result)) { return makeResultD3D12(result); } @@ -209,8 +209,8 @@ PalResult PAL_CALL getSemaphoreValueD3D12( PalSemaphore* semaphore, uint64_t* value) { - SemaphoreD3D12* d3d12Semaphore = (SemaphoreD3D12*)semaphore; - *value = d3d12Semaphore->handle->lpVtbl->GetCompletedValue(d3d12Semaphore->handle); + SemaphoreD3D12* semaphoreImpl = (SemaphoreD3D12*)semaphore; + *value = semaphoreImpl->handle->lpVtbl->GetCompletedValue(semaphoreImpl->handle); return PAL_RESULT_SUCCESS; } diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index 608a3aaf..f068fb45 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -67,6 +67,7 @@ static PalBool validateVtableVersion1(const PalGraphicsBackendVtable1* vtable1) // device !vtable1->createDevice || !vtable1->destroyDevice || + !vtable1->getDeviceLostReason || // memory !vtable1->allocateMemory || @@ -393,6 +394,11 @@ void PAL_CALL palDestroyDevice(PalDevice* device) device->backend.vtbl1->destroyDevice(device); } +uint32_t PAL_CALL palGetDeviceLostReason(PalDevice* device) +{ + device->backend.vtbl1->getDeviceLostReason(device); +} + PalResult PAL_CALL palAllocateMemory( PalDevice* device, PalMemoryType type, @@ -1364,7 +1370,7 @@ PalResult PAL_CALL palCreateAccelerationstructure( return PAL_RESULT_SUCCESS; } -void PAL_CALL palDestroyAccelerationstructure(PalAccelerationStructure* as) +void PAL_CALL palDestroyAccelerationStructure(PalAccelerationStructure* as) { as->backend.vtbl1->destroyAccelerationstructure(as); } diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index d1d83188..1d4204e1 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -51,6 +51,8 @@ PalResult PAL_CALL createDeviceVk( void PAL_CALL destroyDeviceVk(PalDevice* device); +uint32_t PAL_CALL getDeviceLostReasonVk(PalDevice* device); + PalResult PAL_CALL allocateMemoryVk( PalDevice* device, PalMemoryType type, @@ -613,6 +615,7 @@ static PalGraphicsBackendVtable1 s_VkBackend1 = { .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetVk, .createDevice = createDeviceVk, .destroyDevice = destroyDeviceVk, + .getDeviceLostReason = getDeviceLostReasonVk, .allocateMemory = allocateMemoryVk, .freeMemory = freeMemoryVk, .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesVk, @@ -777,6 +780,8 @@ PalResult PAL_CALL createDeviceD3D12( void PAL_CALL destroyDeviceD3D12(PalDevice* device); +uint32_t PAL_CALL getDeviceLostReasonD3D12(PalDevice* device); + PalResult PAL_CALL allocateMemoryD3D12( PalDevice* device, PalMemoryType type, @@ -1302,6 +1307,7 @@ static PalGraphicsBackendVtable1 s_D3D12Backend1 = { .getHighestSupportedShaderTarget = getHighestSupportedShaderTargetD3D12, .createDevice = createDeviceD3D12, .destroyDevice = destroyDeviceD3D12, + .getDeviceLostReason = getDeviceLostReasonD3D12, .allocateMemory = allocateMemoryD3D12, .freeMemory = freeMemoryD3D12, .querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilitiesD3D12, diff --git a/src/graphics/vulkan/pal_adapter_vulkan.c b/src/graphics/vulkan/pal_adapter_vulkan.c index 2f9652d2..ff63ee4d 100644 --- a/src/graphics/vulkan/pal_adapter_vulkan.c +++ b/src/graphics/vulkan/pal_adapter_vulkan.c @@ -151,8 +151,8 @@ void PAL_CALL getAdapterInfoVk( PalAdapter* adapter, PalAdapterInfo* info) { - AdapterVk* vkAdapter = (AdapterVk*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + AdapterVk* adapterImpl = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapterImpl->handle; VkPhysicalDeviceProperties props = {0}; VkPhysicalDeviceMemoryProperties memProps = {0}; @@ -210,8 +210,8 @@ void PAL_CALL getAdapterCapabilitiesVk( PalAdapter* adapter, PalAdapterCapabilities* caps) { - AdapterVk* vkAdapter = (AdapterVk*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + AdapterVk* adapterImpl = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapterImpl->handle; VkPhysicalDeviceProperties props = {0}; s_Vk.getPhysicalDeviceProperties(phyDevice, &props); @@ -330,8 +330,8 @@ PalAdapterFeatures PAL_CALL getAdapterFeaturesVk(PalAdapter* adapter) uint32_t extensionCount = 0; VkPhysicalDeviceProperties props = {0}; - AdapterVk* vkAdapter = (AdapterVk*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + AdapterVk* adapterImpl = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapterImpl->handle; // get supported extensions s_Vk.getPhysicalDeviceProperties(phyDevice, &props); @@ -690,9 +690,9 @@ uint32_t PAL_CALL getHighestSupportedShaderTargetVk( return 0; } - AdapterVk* vkAdapter = (AdapterVk*)adapter; + AdapterVk* adapterImpl = (AdapterVk*)adapter; VkPhysicalDeviceProperties props = {0}; - s_Vk.getPhysicalDeviceProperties(vkAdapter->handle, &props); + s_Vk.getPhysicalDeviceProperties(adapterImpl->handle, &props); if (props.apiVersion >= VK_API_VERSION_1_3) { return PAL_MAKE_SHADER_TARGET(1, 6); @@ -716,8 +716,8 @@ void PAL_CALL enumerateFormatsVk( PalFormatInfo* outFormats) { int32_t fmtCount = 0; - AdapterVk* vkAdapter = (AdapterVk*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + AdapterVk* adapterImpl = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapterImpl->handle; VkFormatProperties props = {0}; for (int i = 0; i < PAL_FORMAT_COUNT; i++) { @@ -746,8 +746,8 @@ PalBool PAL_CALL isFormatSupportedVk( PalAdapter* adapter, PalFormat format) { - AdapterVk* vkAdapter = (AdapterVk*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + AdapterVk* adapterImpl = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapterImpl->handle; VkFormatProperties props = {0}; VkFormat fmt = formatToVk(format); @@ -762,8 +762,8 @@ PalImageUsages PAL_CALL queryFormatImageUsagesVk( PalAdapter* adapter, PalFormat format) { - AdapterVk* vkAdapter = (AdapterVk*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + AdapterVk* adapterImpl = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapterImpl->handle; VkFormatProperties props = {0}; VkFormat fmt = formatToVk(format); @@ -780,31 +780,31 @@ PalSampleCount PAL_CALL queryFormatSampleCountVk( PalFormat format) { VkResult result; - AdapterVk* vkAdapter = (AdapterVk*)adapter; + AdapterVk* adapterImpl = (AdapterVk*)adapter; VkFormatProperties props = {0}; VkImageFormatProperties formatProps = {0}; VkFormat fmt = formatToVk(format); - s_Vk.getPhysicalDeviceFormatProperties(vkAdapter->handle, fmt, &props); + s_Vk.getPhysicalDeviceFormatProperties(adapterImpl->handle, fmt, &props); if (props.optimalTilingFeatures == 0) { return PAL_SAMPLE_COUNT_1; } - VkImageUsageFlags vkImageUsage = 0; + VkImageUsageFlags imageUsageImpl = 0; PalImageUsages imageUsages = imageUsageFromVk(props.optimalTilingFeatures); PalBool isDepth = (imageUsages & PAL_IMAGE_USAGE_DEPTH_ATTACHEMENT) != 0; if (isDepth) { - vkImageUsage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + imageUsageImpl = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } else { - vkImageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + imageUsageImpl = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } result = s_Vk.getPhysicalDeviceImageFormatProperties( - vkAdapter->handle, + adapterImpl->handle, fmt, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - vkImageUsage, + imageUsageImpl, 0, &formatProps); diff --git a/src/graphics/vulkan/pal_as_vulkan.c b/src/graphics/vulkan/pal_as_vulkan.c index 497f2299..177c9584 100644 --- a/src/graphics/vulkan/pal_as_vulkan.c +++ b/src/graphics/vulkan/pal_as_vulkan.c @@ -15,7 +15,7 @@ PalResult PAL_CALL createAccelerationstructureVk( { VkResult result; AccelerationStructureVk* as = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; BufferVk* buffer = (BufferVk*)info->buffer; as = palAllocate(s_Vk.allocator, sizeof(AccelerationStructureVk), 0); @@ -34,10 +34,10 @@ PalResult PAL_CALL createAccelerationstructureVk( createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; } - result = vkDevice->createAccelerationStructure( - vkDevice->handle, + result = deviceImpl->createAccelerationStructure( + deviceImpl->handle, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &as->handle); if (result != VK_SUCCESS) { @@ -48,22 +48,22 @@ PalResult PAL_CALL createAccelerationstructureVk( VkAccelerationStructureDeviceAddressInfoKHR addressInfo = {0}; addressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR; addressInfo.accelerationStructure = as->handle; - as->address = vkDevice->getAccelerationDeviceAddress(vkDevice->handle, &addressInfo); + as->address = deviceImpl->getAccelerationDeviceAddress(deviceImpl->handle, &addressInfo); - as->device = vkDevice; + as->device = deviceImpl; *outAs = (PalAccelerationStructure*)as; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyAccelerationstructureVk(PalAccelerationStructure* as) { - AccelerationStructureVk* vkAs = (AccelerationStructureVk*)as; - vkAs->device->destroyAccelerationStructure( - vkAs->device->handle, - vkAs->handle, - &s_Vk.vkAllocator); + AccelerationStructureVk* asImpl = (AccelerationStructureVk*)as; + asImpl->device->destroyAccelerationStructure( + asImpl->device->handle, + asImpl->handle, + &s_Vk.allocatorImpl); - palFree(s_Vk.allocator, vkAs); + palFree(s_Vk.allocator, asImpl); } void PAL_CALL getAccelerationStructureBuildSizeVk( @@ -71,7 +71,7 @@ void PAL_CALL getAccelerationStructureBuildSizeVk( PalAccelerationStructureBuildInfo* info, PalAccelerationStructureBuildSize* size) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkAccelerationStructureGeometryKHR* geometries = nullptr; uint32_t* maxPrimities = nullptr; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; @@ -89,8 +89,8 @@ void PAL_CALL getAccelerationStructureBuildSizeVk( VkAccelerationStructureBuildSizesInfoKHR sizeInfo = {0}; sizeInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR; - vkDevice->getAccelerationBuildsize( - vkDevice->handle, + deviceImpl->getAccelerationBuildsize( + deviceImpl->handle, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, maxPrimities, diff --git a/src/graphics/vulkan/pal_buffer_vulkan.c b/src/graphics/vulkan/pal_buffer_vulkan.c index 25b7e5ec..50f3a09c 100644 --- a/src/graphics/vulkan/pal_buffer_vulkan.c +++ b/src/graphics/vulkan/pal_buffer_vulkan.c @@ -196,7 +196,7 @@ PalResult PAL_CALL createBufferVk( { VkResult result; BufferVk* buffer = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; MemoryVk* memory = nullptr; buffer = palAllocate(s_Vk.allocator, sizeof(BufferVk), 0); @@ -217,7 +217,8 @@ PalResult PAL_CALL createBufferVk( createInfo.size = info->size; createInfo.usage = bufferUsageToVk(info->usages); - result = s_Vk.createBuffer(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &buffer->handle); + result = + s_Vk.createBuffer(deviceImpl->handle, &createInfo, &s_Vk.allocatorImpl, &buffer->handle); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -234,15 +235,15 @@ PalResult PAL_CALL createBufferVk( // allocate and manage memory VkMemoryRequirements memReq = {0}; - s_Vk.getBufferMemoryRequirements(vkDevice->handle, buffer->handle, &memReq); + s_Vk.getBufferMemoryRequirements(deviceImpl->handle, buffer->handle, &memReq); VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = (VkDeviceSize)memReq.size; VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; - uint32_t memoryMask = vkDevice->memoryClassMask[memoryType] & memReq.memoryTypeBits; - uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, memoryMask); + uint32_t memoryMask = deviceImpl->memoryClassMask[memoryType] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(deviceImpl->phyDevice, memoryMask); if (!(memoryMask & (1u << memoryIndex))) { return PAL_RESULT_CODE_PLATFORM_FAILURE; } @@ -255,16 +256,16 @@ PalResult PAL_CALL createBufferVk( } result = s_Vk.allocateMemory( - vkDevice->handle, + deviceImpl->handle, &allocateInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &memory->handle); if (result != VK_SUCCESS) { return makeResultVk(result); } - result = s_Vk.bindBufferMemory(vkDevice->handle, buffer->handle, memory->handle, 0); + result = s_Vk.bindBufferMemory(deviceImpl->handle, buffer->handle, memory->handle, 0); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -275,18 +276,21 @@ PalResult PAL_CALL createBufferVk( buffer->memory = memory; buffer->usages = info->usages; - buffer->device = vkDevice; + buffer->device = deviceImpl; *outBuffer = (PalBuffer*)buffer; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyBufferVk(PalBuffer* buffer) { - BufferVk* vkBuffer = (BufferVk*)buffer; - s_Vk.destroyBuffer(vkBuffer->device->handle, vkBuffer->handle, &s_Vk.vkAllocator); - if (vkBuffer->isMemoryManaged) { - s_Vk.freeMemory(vkBuffer->device->handle, vkBuffer->memory->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkBuffer->memory); + BufferVk* bufferImpl = (BufferVk*)buffer; + s_Vk.destroyBuffer(bufferImpl->device->handle, bufferImpl->handle, &s_Vk.allocatorImpl); + if (bufferImpl->isMemoryManaged) { + s_Vk.freeMemory( + bufferImpl->device->handle, + bufferImpl->memory->handle, + &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, bufferImpl->memory); } palFree(s_Vk.allocator, buffer); } @@ -295,14 +299,14 @@ void PAL_CALL getBufferMemoryRequirementsVk( PalBuffer* buffer, PalMemoryRequirements* requirements) { - BufferVk* vkBuffer = (BufferVk*)buffer; - DeviceVk* device = vkBuffer->device; + BufferVk* bufferImpl = (BufferVk*)buffer; + DeviceVk* device = bufferImpl->device; VkMemoryRequirements memReq = {0}; - s_Vk.getBufferMemoryRequirements(device->handle, vkBuffer->handle, &memReq); + s_Vk.getBufferMemoryRequirements(device->handle, bufferImpl->handle, &memReq); requirements->alignment = (uint64_t)memReq.alignment; requirements->size = (uint64_t)memReq.size; - requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, vkBuffer->usages); + requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, bufferImpl->usages); requirements->supportedMemoryTypes = 0; if ((memReq.memoryTypeBits & device->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY]) != 0) { @@ -399,21 +403,24 @@ PalResult PAL_CALL bindBufferMemoryVk( uint64_t offset) { VkResult result; - MemoryVk* vkMemory = (MemoryVk*)memory; - BufferVk* vkBuffer = (BufferVk*)buffer; + MemoryVk* memoryImpl = (MemoryVk*)memory; + BufferVk* bufferImpl = (BufferVk*)buffer; - if (vkBuffer->memory) { + if (bufferImpl->memory) { return PAL_RESULT_CODE_INVALID_OPERATION; } - result = - s_Vk.bindBufferMemory(vkBuffer->device->handle, vkBuffer->handle, vkMemory->handle, offset); + result = s_Vk.bindBufferMemory( + bufferImpl->device->handle, + bufferImpl->handle, + memoryImpl->handle, + offset); if (result != VK_SUCCESS) { return makeResultVk(result); } - vkBuffer->memory = vkMemory; + bufferImpl->memory = memoryImpl; return PAL_RESULT_SUCCESS; } @@ -424,10 +431,10 @@ PalResult PAL_CALL mapBufferVk( void** outPtr) { VkResult result; - BufferVk* vkBuffer = (BufferVk*)buffer; - DeviceVk* device = vkBuffer->device; + BufferVk* bufferImpl = (BufferVk*)buffer; + DeviceVk* device = bufferImpl->device; - result = s_Vk.mapMemory(device->handle, vkBuffer->memory->handle, offset, size, 0, outPtr); + result = s_Vk.mapMemory(device->handle, bufferImpl->memory->handle, offset, size, 0, outPtr); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -436,21 +443,21 @@ PalResult PAL_CALL mapBufferVk( void PAL_CALL unmapBufferVk(PalBuffer* buffer) { - BufferVk* vkBuffer = (BufferVk*)buffer; - s_Vk.unmapMemory(vkBuffer->device->handle, vkBuffer->memory->handle); + BufferVk* bufferImpl = (BufferVk*)buffer; + s_Vk.unmapMemory(bufferImpl->device->handle, bufferImpl->memory->handle); } PalDeviceAddress PAL_CALL getBufferDeviceAddressVk(PalBuffer* buffer) { - BufferVk* vkBuffer = (BufferVk*)buffer; - if (!(vkBuffer->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS)) { + BufferVk* bufferImpl = (BufferVk*)buffer; + if (!(bufferImpl->usages & PAL_BUFFER_USAGE_DEVICE_ADDRESS)) { return 0; } VkBufferDeviceAddressInfoKHR bufferInfo = {0}; - bufferInfo.buffer = vkBuffer->handle; + bufferInfo.buffer = bufferImpl->handle; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; - return vkBuffer->device->getBufferrAddress(vkBuffer->device->handle, &bufferInfo); + return bufferImpl->device->getBufferrAddress(bufferImpl->device->handle, &bufferInfo); } #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_command_pool_vulkan.c b/src/graphics/vulkan/pal_command_pool_vulkan.c index 198846f5..227ed37a 100644 --- a/src/graphics/vulkan/pal_command_pool_vulkan.c +++ b/src/graphics/vulkan/pal_command_pool_vulkan.c @@ -15,9 +15,9 @@ PalResult PAL_CALL createCommandPoolVk( { VkResult result; CommandPoolVk* pool = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; - QueueVk* vkQueue = (QueueVk*)queue; - PhysicalQueue* phyQueue = vkQueue->phyQueue; + DeviceVk* deviceImpl = (DeviceVk*)device; + QueueVk* queueImpl = (QueueVk*)queue; + PhysicalQueue* phyQueue = queueImpl->phyQueue; pool = palAllocate(s_Vk.allocator, sizeof(CommandPoolVk), 0); if (!pool) { @@ -28,21 +28,21 @@ PalResult PAL_CALL createCommandPoolVk( cInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; cInfo.queueFamilyIndex = phyQueue->familyIndex; cInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - result = s_Vk.createCommandPool(vkDevice->handle, &cInfo, &s_Vk.vkAllocator, &pool->handle); + result = s_Vk.createCommandPool(deviceImpl->handle, &cInfo, &s_Vk.allocatorImpl, &pool->handle); if (result != VK_SUCCESS) { return makeResultVk(result); } - pool->device = vkDevice; + pool->device = deviceImpl; *outPool = (PalCommandPool*)pool; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyCommandPoolVk(PalCommandPool* pool) { - CommandPoolVk* vkPool = (CommandPoolVk*)pool; - s_Vk.destroyCommandPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkPool); + CommandPoolVk* cmdPoolImpl = (CommandPoolVk*)pool; + s_Vk.destroyCommandPool(cmdPoolImpl->device->handle, cmdPoolImpl->handle, &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, cmdPoolImpl); } PalResult PAL_CALL allocateCommandBufferVk( @@ -53,8 +53,8 @@ PalResult PAL_CALL allocateCommandBufferVk( { VkResult result; CommandBufferVk* cmdBuffer = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; - CommandPoolVk* vkPool = (CommandPoolVk*)pool; + DeviceVk* deviceImpl = (DeviceVk*)device; + CommandPoolVk* cmdPoolImpl = (CommandPoolVk*)pool; cmdBuffer = palAllocate(s_Vk.allocator, sizeof(CommandBufferVk), 0); if (!cmdBuffer) { @@ -73,7 +73,7 @@ PalResult PAL_CALL allocateCommandBufferVk( VkCommandBufferAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocateInfo.commandBufferCount = 1; - allocateInfo.commandPool = vkPool->handle; + allocateInfo.commandPool = cmdPoolImpl->handle; allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; cmdBuffer->primary = PAL_TRUE; @@ -82,7 +82,7 @@ PalResult PAL_CALL allocateCommandBufferVk( cmdBuffer->primary = PAL_FALSE; } - result = s_Vk.allocateCommandBuffer(vkDevice->handle, &allocateInfo, &cmdBuffer->handle); + result = s_Vk.allocateCommandBuffer(deviceImpl->handle, &allocateInfo, &cmdBuffer->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, (void*)cmdBuffer->allocator.memory); palFree(s_Vk.allocator, cmdBuffer); @@ -96,8 +96,11 @@ PalResult PAL_CALL allocateCommandBufferVk( bufCreateInfo.usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT; bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - result = - s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &cmdBuffer->buffer); + result = s_Vk.createBuffer( + deviceImpl->handle, + &bufCreateInfo, + &s_Vk.allocatorImpl, + &cmdBuffer->buffer); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -105,54 +108,57 @@ PalResult PAL_CALL allocateCommandBufferVk( // allocate CPU upload memory and bind VkMemoryRequirements memReq = {0}; - s_Vk.getBufferMemoryRequirements(vkDevice->handle, cmdBuffer->buffer, &memReq); + s_Vk.getBufferMemoryRequirements(deviceImpl->handle, cmdBuffer->buffer, &memReq); VkMemoryAllocateInfo bufferAllocateInfo = {0}; bufferAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; bufferAllocateInfo.allocationSize = memReq.size; - uint32_t mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; - uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + uint32_t mask = deviceImpl->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(deviceImpl->phyDevice, mask); bufferAllocateInfo.memoryTypeIndex = memoryIndex; result = s_Vk.allocateMemory( - vkDevice->handle, + deviceImpl->handle, &bufferAllocateInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &cmdBuffer->bufferMemory); if (result != VK_SUCCESS) { return makeResultVk(result); } - s_Vk.bindBufferMemory(vkDevice->handle, cmdBuffer->buffer, cmdBuffer->bufferMemory, 0); + s_Vk.bindBufferMemory(deviceImpl->handle, cmdBuffer->buffer, cmdBuffer->bufferMemory, 0); - cmdBuffer->device = vkDevice; - cmdBuffer->pool = vkPool; + cmdBuffer->device = deviceImpl; + cmdBuffer->pool = cmdPoolImpl; *outCmdBuffer = (PalCommandBuffer*)cmdBuffer; return PAL_RESULT_SUCCESS; } void PAL_CALL freeCommandBufferVk(PalCommandBuffer* cmdBuffer) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; s_Vk.freeCommandBuffer( - vkCmdBuffer->device->handle, - vkCmdBuffer->pool->handle, + cmdBufferImpl->device->handle, + cmdBufferImpl->pool->handle, 1, - &vkCmdBuffer->handle); + &cmdBufferImpl->handle); - s_Vk.destroyBuffer(vkCmdBuffer->device->handle, vkCmdBuffer->buffer, &s_Vk.vkAllocator); - s_Vk.freeMemory(vkCmdBuffer->device->handle, vkCmdBuffer->bufferMemory, &s_Vk.vkAllocator); + s_Vk.destroyBuffer(cmdBufferImpl->device->handle, cmdBufferImpl->buffer, &s_Vk.allocatorImpl); + s_Vk.freeMemory( + cmdBufferImpl->device->handle, + cmdBufferImpl->bufferMemory, + &s_Vk.allocatorImpl); - palFree(s_Vk.allocator, (void*)vkCmdBuffer->allocator.memory); - palFree(s_Vk.allocator, vkCmdBuffer); + palFree(s_Vk.allocator, (void*)cmdBufferImpl->allocator.memory); + palFree(s_Vk.allocator, cmdBufferImpl); } PalResult PAL_CALL resetCommandBufferVk(PalCommandBuffer* cmdBuffer) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - VkResult result = s_Vk.resetCommandBuffer(vkCmdBuffer->handle, 0); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + VkResult result = s_Vk.resetCommandBuffer(cmdBufferImpl->handle, 0); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -170,9 +176,9 @@ PalResult PAL_CALL submitCommandBufferVk( VkFence fenceHandle = nullptr; VkSemaphore waitSemaphoreHandle = nullptr; VkSemaphore signalSemaphoreHandle = nullptr; - QueueVk* vkQueue = (QueueVk*)queue; - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)info->cmdBuffer; - PhysicalQueue* phyQueue = vkQueue->phyQueue; + QueueVk* queueImpl = (QueueVk*)queue; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)info->cmdBuffer; + PhysicalQueue* phyQueue = queueImpl->phyQueue; if (info->waitSemaphore) { SemaphoreVk* tmp = (SemaphoreVk*)info->waitSemaphore; @@ -192,7 +198,7 @@ PalResult PAL_CALL submitCommandBufferVk( } VkCommandBufferSubmitInfoKHR cmdBufferSubmitInfo = {0}; - cmdBufferSubmitInfo.commandBuffer = vkCmdBuffer->handle; + cmdBufferSubmitInfo.commandBuffer = cmdBufferImpl->handle; cmdBufferSubmitInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR; VkSemaphoreSubmitInfoKHR waitSubmitInfo = {0}; @@ -216,7 +222,7 @@ PalResult PAL_CALL submitCommandBufferVk( submitInfo.waitSemaphoreInfoCount = waitSemaphoreCount; submitInfo.signalSemaphoreInfoCount = signalSemaphoreCount; - result = vkCmdBuffer->device->queueSubmit(phyQueue->handle, 1, &submitInfo, fenceHandle); + result = cmdBufferImpl->device->queueSubmit(phyQueue->handle, 1, &submitInfo, fenceHandle); if (result != VK_SUCCESS) { return makeResultVk(result); } diff --git a/src/graphics/vulkan/pal_commands_vulkan.c b/src/graphics/vulkan/pal_commands_vulkan.c index cf1eca4b..9c74eada 100644 --- a/src/graphics/vulkan/pal_commands_vulkan.c +++ b/src/graphics/vulkan/pal_commands_vulkan.c @@ -226,7 +226,7 @@ PalResult PAL_CALL cmdBeginVk( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; VkCommandBufferBeginInfo beginInfo = {0}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -235,14 +235,14 @@ PalResult PAL_CALL cmdBeginVk( VkCommandBufferInheritanceRenderingInfoKHR layout = {0}; layout.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR; - vkCmdBuffer->allocator.offset = 0; // reset + cmdBufferImpl->allocator.offset = 0; // reset VkFormat format = VK_FORMAT_UNDEFINED; VkFormat* colorAttachments = nullptr; - if (!vkCmdBuffer->primary) { + if (!cmdBufferImpl->primary) { // secondary command buffer colorAttachments = palLinearAlloc( - &vkCmdBuffer->allocator, + &cmdBufferImpl->allocator, sizeof(VkFormat) * info->colorAttachentCount, 0); @@ -274,7 +274,7 @@ PalResult PAL_CALL cmdBeginVk( beginInfo.pNext = &inheritanceInfo; } - VkResult result = s_Vk.cmdBegin(vkCmdBuffer->handle, &beginInfo); + VkResult result = s_Vk.cmdBegin(cmdBufferImpl->handle, &beginInfo); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -283,8 +283,8 @@ PalResult PAL_CALL cmdBeginVk( PalResult PAL_CALL cmdEndVk(PalCommandBuffer* cmdBuffer) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - VkResult result = s_Vk.cmdEnd(vkCmdBuffer->handle); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + VkResult result = s_Vk.cmdEnd(cmdBufferImpl->handle); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -296,9 +296,9 @@ PalResult PAL_CALL cmdExecuteCommandBufferVk( PalCommandBuffer* primaryCmdBuffer, PalCommandBuffer* secondaryCmdBuffer) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)primaryCmdBuffer; - CommandBufferVk* vkCmdBuffer2 = (CommandBufferVk*)secondaryCmdBuffer; - s_Vk.cmdExecuteCommandBuffer(vkCmdBuffer->handle, 1, &vkCmdBuffer2->handle); + CommandBufferVk* primaryCmdBufferImpl = (CommandBufferVk*)primaryCmdBuffer; + CommandBufferVk* secondaryCmdBufferImpl = (CommandBufferVk*)secondaryCmdBuffer; + s_Vk.cmdExecuteCommandBuffer(primaryCmdBufferImpl->handle, 1, &secondaryCmdBufferImpl->handle); return PAL_RESULT_SUCCESS; } @@ -306,15 +306,15 @@ void PAL_CALL cmdSetFragmentShadingRateVk( PalCommandBuffer* cmdBuffer, PalFragmentShadingRateState* state) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; VkExtent2D size = getShadingRateSizeVk(state->rate); VkFragmentShadingRateCombinerOpKHR combinerOps[2]; for (int i = 0; i < 2; i++) { combinerOps[i] = combinerOpsToVk(state->combinerOps[i]); } - device->cmdSetFragmentShadingRate(vkCmdBuffer->handle, &size, combinerOps); + device->cmdSetFragmentShadingRate(cmdBufferImpl->handle, &size, combinerOps); } void PAL_CALL cmdDrawMeshTasksVk( @@ -323,9 +323,9 @@ void PAL_CALL cmdDrawMeshTasksVk( uint32_t groupCountY, uint32_t groupCountZ) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; - device->cmdDrawMeshTask(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; + device->cmdDrawMeshTask(cmdBufferImpl->handle, groupCountX, groupCountY, groupCountZ); } void PAL_CALL cmdDrawMeshTasksIndirectVk( @@ -333,12 +333,13 @@ void PAL_CALL cmdDrawMeshTasksIndirectVk( PalBuffer* buffer, uint32_t drawCount) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; - BufferVk* vkBuffer = (BufferVk*)buffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; + BufferVk* bufferImpl = (BufferVk*)buffer; uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); - device->cmdDrawMeshTaskIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, drawCount, stride); + device + ->cmdDrawMeshTaskIndirect(cmdBufferImpl->handle, bufferImpl->handle, 0, drawCount, stride); } void PAL_CALL cmdDrawMeshTasksIndirectCountVk( @@ -347,17 +348,17 @@ void PAL_CALL cmdDrawMeshTasksIndirectCountVk( PalBuffer* countBuffer, uint32_t maxDrawCount) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; - BufferVk* vkBuffer = (BufferVk*)buffer; - BufferVk* vkCountBuffer = (BufferVk*)countBuffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; + BufferVk* bufferImpl = (BufferVk*)buffer; + BufferVk* countBufferImpl = (BufferVk*)countBuffer; uint32_t stride = sizeof(VkDrawMeshTasksIndirectCommandEXT); device->cmdDrawMeshTaskIndirectCount( - vkCmdBuffer->handle, - vkBuffer->handle, + cmdBufferImpl->handle, + bufferImpl->handle, 0, - vkCountBuffer->handle, + countBufferImpl->handle, 0, maxDrawCount, stride); @@ -367,23 +368,23 @@ void PAL_CALL cmdBuildAccelerationStructureVk( PalCommandBuffer* cmdBuffer, PalAccelerationStructureBuildInfo* info) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; VkAccelerationStructureGeometryKHR* geometries = nullptr; VkAccelerationStructureBuildRangeInfoKHR* rangeInfos = nullptr; const VkAccelerationStructureBuildRangeInfoKHR** tmpRangeInfos = nullptr; VkAccelerationStructureBuildGeometryInfoKHR buildInfo = {0}; - tmpRangeInfos = palLinearAlloc(&vkCmdBuffer->allocator, sizeof(void*) * info->count, 0); + tmpRangeInfos = palLinearAlloc(&cmdBufferImpl->allocator, sizeof(void*) * info->count, 0); geometries = palLinearAlloc( - &vkCmdBuffer->allocator, + &cmdBufferImpl->allocator, sizeof(VkAccelerationStructureGeometryKHR) * info->count, 0); rangeInfos = palLinearAlloc( - &vkCmdBuffer->allocator, + &cmdBufferImpl->allocator, sizeof(VkAccelerationStructureBuildRangeInfoKHR) * info->count, 0); @@ -395,15 +396,15 @@ void PAL_CALL cmdBuildAccelerationStructureVk( tmpRangeInfos[i] = &rangeInfos[i]; } - vkCmdBuffer->device - ->cmdBuildAccelerationStructures(vkCmdBuffer->handle, 1, &buildInfo, tmpRangeInfos); + cmdBufferImpl->device + ->cmdBuildAccelerationStructures(cmdBufferImpl->handle, 1, &buildInfo, tmpRangeInfos); } void PAL_CALL cmdBeginRenderingVk( PalCommandBuffer* cmdBuffer, PalRenderingInfo* info) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; VkRenderingInfoKHR rendering = {0}; rendering.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR; @@ -412,7 +413,7 @@ void PAL_CALL cmdBeginRenderingVk( VkRenderingAttachmentInfoKHR* colorAttachments = nullptr; colorAttachments = palLinearAlloc( - &vkCmdBuffer->allocator, + &cmdBufferImpl->allocator, sizeof(VkRenderingAttachmentInfoKHR) * info->colorAttachentCount, 0); @@ -574,13 +575,13 @@ void PAL_CALL cmdBeginRenderingVk( } rendering.flags = renderingFlagToVk(info->flags); - vkCmdBuffer->device->cmdBeginRendering(vkCmdBuffer->handle, &rendering); + cmdBufferImpl->device->cmdBeginRendering(cmdBufferImpl->handle, &rendering); } void PAL_CALL cmdEndRenderingVk(PalCommandBuffer* cmdBuffer) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - vkCmdBuffer->device->cmdEndRendering(vkCmdBuffer->handle); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + cmdBufferImpl->device->cmdEndRendering(cmdBufferImpl->handle); } void PAL_CALL cmdCopyBufferVk( @@ -589,7 +590,7 @@ void PAL_CALL cmdCopyBufferVk( PalBuffer* src, PalBufferCopyInfo* copyInfo) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; BufferVk* dstBuffer = (BufferVk*)dst; BufferVk* srcBuffer = (BufferVk*)src; @@ -597,7 +598,7 @@ void PAL_CALL cmdCopyBufferVk( copyRegion.size = copyInfo->size; copyRegion.dstOffset = copyInfo->dstOffset; copyRegion.srcOffset = copyInfo->srcOffset; - s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, srcBuffer->handle, dstBuffer->handle, 1, ©Region); + s_Vk.cmdCopyBuffer(cmdBufferImpl->handle, srcBuffer->handle, dstBuffer->handle, 1, ©Region); } void PAL_CALL cmdCopyBufferToImageVk( @@ -606,7 +607,7 @@ void PAL_CALL cmdCopyBufferToImageVk( PalBuffer* srcBuffer, PalBufferImageCopyInfo* copyInfo) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; ImageVk* dst = (ImageVk*)dstImage; BufferVk* src = (BufferVk*)srcBuffer; @@ -629,7 +630,7 @@ void PAL_CALL cmdCopyBufferToImageVk( copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; s_Vk.cmdCopyBufferToImage( - vkCmdBuffer->handle, + cmdBufferImpl->handle, src->handle, dst->handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -643,7 +644,7 @@ void PAL_CALL cmdCopyImageVk( PalImage* src, PalImageCopyInfo* copyInfo) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; ImageVk* dstImage = (ImageVk*)dst; ImageVk* srcImage = (ImageVk*)src; @@ -671,7 +672,7 @@ void PAL_CALL cmdCopyImageVk( copyRegion.srcSubresource.mipLevel = copyInfo->srcMipLevel; s_Vk.cmdCopyImage( - vkCmdBuffer->handle, + cmdBufferImpl->handle, srcImage->handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstImage->handle, @@ -686,7 +687,7 @@ void PAL_CALL cmdCopyImageToBufferVk( PalImage* srcImage, PalBufferImageCopyInfo* copyInfo) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; BufferVk* dst = (BufferVk*)dstBuffer; ImageVk* src = (ImageVk*)srcImage; @@ -709,7 +710,7 @@ void PAL_CALL cmdCopyImageToBufferVk( copyRegion.imageSubresource.mipLevel = copyInfo->ImageMipLevel; s_Vk.cmdCopyImageToBuffer( - vkCmdBuffer->handle, + cmdBufferImpl->handle, src->handle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->handle, @@ -721,10 +722,10 @@ void PAL_CALL cmdBindPipelineVk( PalCommandBuffer* cmdBuffer, PalPipeline* pipeline) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - PipelineVk* vkPipeline = (PipelineVk*)pipeline; - s_Vk.cmdBindPipeline(vkCmdBuffer->handle, vkPipeline->bindPoint, vkPipeline->handle); - vkCmdBuffer->pipeline = vkPipeline; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipelineImpl = (PipelineVk*)pipeline; + s_Vk.cmdBindPipeline(cmdBufferImpl->handle, pipelineImpl->bindPoint, pipelineImpl->handle); + cmdBufferImpl->pipeline = pipelineImpl; } void PAL_CALL cmdSetViewportVk( @@ -732,11 +733,11 @@ void PAL_CALL cmdSetViewportVk( uint32_t count, PalViewport* viewports) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - VkViewport* vkViewports = nullptr; - vkViewports = palLinearAlloc(&vkCmdBuffer->allocator, sizeof(VkViewport) * count, 0); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + VkViewport* viewportsImpl = nullptr; + viewportsImpl = palLinearAlloc(&cmdBufferImpl->allocator, sizeof(VkViewport) * count, 0); for (int i = 0; i < count; i++) { - VkViewport* tmp = &vkViewports[i]; + VkViewport* tmp = &viewportsImpl[i]; tmp->x = viewports[i].x; tmp->y = viewports[i].y; tmp->width = viewports[i].width; @@ -745,7 +746,7 @@ void PAL_CALL cmdSetViewportVk( tmp->maxDepth = viewports[i].maxDepth; } - s_Vk.cmdSetViewports(vkCmdBuffer->handle, 0, count, vkViewports); + s_Vk.cmdSetViewports(cmdBufferImpl->handle, 0, count, viewportsImpl); } void PAL_CALL cmdSetScissorsVk( @@ -753,18 +754,18 @@ void PAL_CALL cmdSetScissorsVk( uint32_t count, PalRect2D* scissors) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - VkRect2D* vkScissors = nullptr; - vkScissors = palLinearAlloc(&vkCmdBuffer->allocator, sizeof(VkRect2D) * count, 0); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + VkRect2D* scissorsImpl = nullptr; + scissorsImpl = palLinearAlloc(&cmdBufferImpl->allocator, sizeof(VkRect2D) * count, 0); for (int i = 0; i < count; i++) { - VkRect2D* tmp = &vkScissors[i]; + VkRect2D* tmp = &scissorsImpl[i]; tmp->offset.x = scissors[i].x; tmp->offset.y = scissors[i].y; tmp->extent.width = scissors[i].width; tmp->extent.height = scissors[i].height; } - s_Vk.cmdSetScissors(vkCmdBuffer->handle, 0, count, vkScissors); + s_Vk.cmdSetScissors(cmdBufferImpl->handle, 0, count, scissorsImpl); } void PAL_CALL cmdBindVertexBuffersVk( @@ -774,15 +775,15 @@ void PAL_CALL cmdBindVertexBuffersVk( PalBuffer** buffers, uint64_t* offsets) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - VkBuffer* vkBuffers = nullptr; - vkBuffers = palLinearAlloc(&vkCmdBuffer->allocator, sizeof(VkBuffer) * count, 0); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + VkBuffer* buffersImpl = nullptr; + buffersImpl = palLinearAlloc(&cmdBufferImpl->allocator, sizeof(VkBuffer) * count, 0); for (int i = 0; i < count; i++) { BufferVk* tmp = (BufferVk*)buffers[i]; - vkBuffers[i] = tmp->handle; + buffersImpl[i] = tmp->handle; } - s_Vk.cmdBindVertexBuffers(vkCmdBuffer->handle, firstSlot, count, vkBuffers, offsets); + s_Vk.cmdBindVertexBuffers(cmdBufferImpl->handle, firstSlot, count, buffersImpl, offsets); } void PAL_CALL cmdBindIndexBufferVk( @@ -791,14 +792,14 @@ void PAL_CALL cmdBindIndexBufferVk( uint64_t offset, PalIndexType type) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - BufferVk* vkBuffer = (BufferVk*)buffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + BufferVk* bufferImpl = (BufferVk*)buffer; VkIndexType bufferType = VK_INDEX_TYPE_UINT32; if (type == PAL_INDEX_TYPE_UINT16) { bufferType = VK_INDEX_TYPE_UINT16; } - s_Vk.cmdBindIndexBuffer(vkCmdBuffer->handle, vkBuffer->handle, offset, bufferType); + s_Vk.cmdBindIndexBuffer(cmdBufferImpl->handle, bufferImpl->handle, offset, bufferType); } void PAL_CALL cmdDrawVk( @@ -808,8 +809,8 @@ void PAL_CALL cmdDrawVk( uint32_t firstVertex, uint32_t firstInstance) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - s_Vk.cmdDraw(vkCmdBuffer->handle, vertexCount, instanceCount, firstVertex, firstInstance); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + s_Vk.cmdDraw(cmdBufferImpl->handle, vertexCount, instanceCount, firstVertex, firstInstance); } void PAL_CALL cmdDrawIndirectVk( @@ -817,10 +818,10 @@ void PAL_CALL cmdDrawIndirectVk( PalBuffer* buffer, uint32_t count) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - BufferVk* vkBuffer = (BufferVk*)buffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + BufferVk* bufferImpl = (BufferVk*)buffer; uint32_t stride = sizeof(VkDrawIndirectCommand); - s_Vk.cmdDrawIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); + s_Vk.cmdDrawIndirect(cmdBufferImpl->handle, bufferImpl->handle, 0, count, stride); } void PAL_CALL cmdDrawIndirectCountVk( @@ -829,17 +830,17 @@ void PAL_CALL cmdDrawIndirectCountVk( PalBuffer* countBuffer, uint32_t maxDrawCount) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - BufferVk* vkBuffer = (BufferVk*)buffer; - BufferVk* vkCountBuffer = (BufferVk*)countBuffer; - DeviceVk* device = vkCmdBuffer->device; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + BufferVk* bufferImpl = (BufferVk*)buffer; + BufferVk* countBufferImpl = (BufferVk*)countBuffer; + DeviceVk* device = cmdBufferImpl->device; uint32_t stride = sizeof(VkDrawIndirectCommand); device->cmdDrawIndirectCount( - vkCmdBuffer->handle, - vkBuffer->handle, + cmdBufferImpl->handle, + bufferImpl->handle, 0, - vkCountBuffer->handle, + countBufferImpl->handle, 0, maxDrawCount, stride); @@ -853,9 +854,9 @@ void PAL_CALL cmdDrawIndexedVk( int32_t vertexOffset, uint32_t firstInstance) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; s_Vk.cmdDrawIndexed( - vkCmdBuffer->handle, + cmdBufferImpl->handle, indexCount, instanceCount, firstIndex, @@ -868,10 +869,10 @@ void PAL_CALL cmdDrawIndexedIndirectVk( PalBuffer* buffer, uint32_t count) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - BufferVk* vkBuffer = (BufferVk*)buffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + BufferVk* bufferImpl = (BufferVk*)buffer; uint32_t stride = sizeof(VkDrawIndexedIndirectCommand); - s_Vk.cmdDrawIndexedIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0, count, stride); + s_Vk.cmdDrawIndexedIndirect(cmdBufferImpl->handle, bufferImpl->handle, 0, count, stride); } void PAL_CALL cmdDrawIndexedIndirectCountVk( @@ -880,17 +881,17 @@ void PAL_CALL cmdDrawIndexedIndirectCountVk( PalBuffer* countBuffer, uint32_t maxDrawCount) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - BufferVk* vkBuffer = (BufferVk*)buffer; - BufferVk* vkCountBuffer = (BufferVk*)countBuffer; - DeviceVk* device = vkCmdBuffer->device; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + BufferVk* bufferImpl = (BufferVk*)buffer; + BufferVk* countBufferImpl = (BufferVk*)countBuffer; + DeviceVk* device = cmdBufferImpl->device; uint32_t stride = sizeof(VkDrawIndexedIndirectCommand); device->cmdDrawIndexedIndirectCount( - vkCmdBuffer->handle, - vkBuffer->handle, + cmdBufferImpl->handle, + bufferImpl->handle, 0, - vkCountBuffer->handle, + countBufferImpl->handle, 0, maxDrawCount, stride); @@ -901,8 +902,8 @@ void PAL_CALL cmdAccelerationStructureBarrierVk( PalAccelerationStructure* as, PalBarrierInfo* info) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - PipelineVk* pipeline = vkCmdBuffer->pipeline; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipeline = cmdBufferImpl->pipeline; VkMemoryBarrier2KHR barrier = {0}; barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR; @@ -918,7 +919,7 @@ void PAL_CALL cmdAccelerationStructureBarrierVk( dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; dependencyInfo.memoryBarrierCount = 1; dependencyInfo.pMemoryBarriers = &barrier; - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); + cmdBufferImpl->device->cmdPipelineBarrier(cmdBufferImpl->handle, &dependencyInfo); } void PAL_CALL cmdImageBarrierVk( @@ -927,9 +928,9 @@ void PAL_CALL cmdImageBarrierVk( PalImageSubresourceRange* subresourceRange, PalBarrierInfo* info) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - PipelineVk* pipeline = vkCmdBuffer->pipeline; - ImageVk* vkImage = (ImageVk*)image; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipeline = cmdBufferImpl->pipeline; + ImageVk* imageImpl = (ImageVk*)image; VkImageMemoryBarrier2KHR barrier = {0}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR; @@ -943,7 +944,7 @@ void PAL_CALL cmdImageBarrierVk( barrier.dstAccessMask = new.access; barrier.newLayout = new.layout; - barrier.image = vkImage->handle; + barrier.image = imageImpl->handle; barrier.subresourceRange.aspectMask = imageAspectToVk(subresourceRange->aspect); barrier.subresourceRange.baseArrayLayer = subresourceRange->startArrayLayer; barrier.subresourceRange.baseMipLevel = subresourceRange->startMipLevel; @@ -954,7 +955,7 @@ void PAL_CALL cmdImageBarrierVk( dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; dependencyInfo.imageMemoryBarrierCount = 1; dependencyInfo.pImageMemoryBarriers = &barrier; - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); + cmdBufferImpl->device->cmdPipelineBarrier(cmdBufferImpl->handle, &dependencyInfo); } void PAL_CALL cmdBufferBarrierVk( @@ -962,9 +963,9 @@ void PAL_CALL cmdBufferBarrierVk( PalBuffer* buffer, PalBarrierInfo* info) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - PipelineVk* pipeline = vkCmdBuffer->pipeline; - BufferVk* vkBuffer = (BufferVk*)buffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipeline = cmdBufferImpl->pipeline; + BufferVk* bufferImpl = (BufferVk*)buffer; VkBufferMemoryBarrier2KHR barrier = {0}; barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR; @@ -976,7 +977,7 @@ void PAL_CALL cmdBufferBarrierVk( barrier.dstStageMask = pipelineStagesToVk(info->dstStages); barrier.dstAccessMask = new.access; - barrier.buffer = vkBuffer->handle; + barrier.buffer = bufferImpl->handle; barrier.offset = 0; barrier.size = VK_WHOLE_SIZE; @@ -984,7 +985,7 @@ void PAL_CALL cmdBufferBarrierVk( dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; dependencyInfo.bufferMemoryBarrierCount = 1; dependencyInfo.pBufferMemoryBarriers = &barrier; - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); + cmdBufferImpl->device->cmdPipelineBarrier(cmdBufferImpl->handle, &dependencyInfo); } void PAL_CALL cmdDispatchVk( @@ -993,8 +994,8 @@ void PAL_CALL cmdDispatchVk( uint32_t groupCountY, uint32_t groupCountZ) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - s_Vk.cmdDispatch(vkCmdBuffer->handle, groupCountX, groupCountY, groupCountZ); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + s_Vk.cmdDispatch(cmdBufferImpl->handle, groupCountX, groupCountY, groupCountZ); } void PAL_CALL cmdDispatchBaseVk( @@ -1006,11 +1007,11 @@ void PAL_CALL cmdDispatchBaseVk( uint32_t groupCountY, uint32_t groupCountZ) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; device->cmdDispatchBase( - vkCmdBuffer->handle, + cmdBufferImpl->handle, baseGroupX, baseGroupY, baseGroupZ, @@ -1023,9 +1024,9 @@ void PAL_CALL cmdDispatchIndirectVk( PalCommandBuffer* cmdBuffer, PalBuffer* buffer) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - BufferVk* vkBuffer = (BufferVk*)buffer; - s_Vk.cmdDispatchIndirect(vkCmdBuffer->handle, vkBuffer->handle, 0); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + BufferVk* bufferImpl = (BufferVk*)buffer; + s_Vk.cmdDispatchIndirect(cmdBufferImpl->handle, bufferImpl->handle, 0); } void PAL_CALL cmdTraceRaysVk( @@ -1036,24 +1037,25 @@ void PAL_CALL cmdTraceRaysVk( uint32_t height, uint32_t depth) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; - ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; + ShaderBindingTableVk* sbtImpl = (ShaderBindingTableVk*)sbt; VkStridedDeviceAddressRegionKHR raygenAddress = {0}; - raygenAddress.size = vkSbt->raygen.region.size; - raygenAddress.stride = vkSbt->raygen.region.stride; - raygenAddress.deviceAddress = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; + raygenAddress.size = sbtImpl->raygen.region.size; + raygenAddress.stride = sbtImpl->raygen.region.stride; + raygenAddress.deviceAddress = + sbtImpl->baseAddress + raygenIndex * sbtImpl->raygen.region.stride; // we need to make sure the SBT is up to date - commitShaderbindingTableUpdate(vkCmdBuffer, vkSbt); + commitShaderbindingTableUpdate(cmdBufferImpl, sbtImpl); - vkCmdBuffer->device->cmdTraceRays( - vkCmdBuffer->handle, + cmdBufferImpl->device->cmdTraceRays( + cmdBufferImpl->handle, &raygenAddress, - &vkSbt->miss.region, - &vkSbt->hit.region, - &vkSbt->callable.region, + &sbtImpl->miss.region, + &sbtImpl->hit.region, + &sbtImpl->callable.region, width, height, depth); @@ -1065,20 +1067,25 @@ void PAL_CALL cmdTraceRaysIndirectVk( PalShaderBindingTable* sbt, PalBuffer* buffer) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; - BufferVk* vkBuffer = (BufferVk*)buffer; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + ShaderBindingTableVk* sbtImpl = (ShaderBindingTableVk*)sbt; + BufferVk* bufferImpl = (BufferVk*)buffer; - PalDeviceAddress address = vkSbt->baseAddress + raygenIndex * vkSbt->raygen.region.stride; - vkSbt->raygen.region.deviceAddress = address; + PalDeviceAddress address = sbtImpl->baseAddress + raygenIndex * sbtImpl->raygen.region.stride; + sbtImpl->raygen.region.deviceAddress = address; // we need to make sure the SBT is up to date - commitShaderbindingTableUpdate(vkCmdBuffer, vkSbt); + commitShaderbindingTableUpdate(cmdBufferImpl, sbtImpl); // copy user buffer data into a tmp gpu buffer abd execute with it VkBufferCopy copyRegion = {0}; copyRegion.size = sizeof(VkTraceRaysIndirectCommandKHR); - s_Vk.cmdCopyBuffer(vkCmdBuffer->handle, vkBuffer->handle, vkCmdBuffer->buffer, 1, ©Region); + s_Vk.cmdCopyBuffer( + cmdBufferImpl->handle, + bufferImpl->handle, + cmdBufferImpl->buffer, + 1, + ©Region); // put a memory barrier VkBufferMemoryBarrier2KHR barrier = {0}; @@ -1088,7 +1095,7 @@ void PAL_CALL cmdTraceRaysIndirectVk( barrier.dstStageMask = VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR; barrier.dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT_KHR; - barrier.buffer = vkCmdBuffer->buffer; + barrier.buffer = cmdBufferImpl->buffer; barrier.offset = 0; barrier.size = VK_WHOLE_SIZE; @@ -1096,20 +1103,21 @@ void PAL_CALL cmdTraceRaysIndirectVk( dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; dependencyInfo.bufferMemoryBarrierCount = 1; dependencyInfo.pBufferMemoryBarriers = &barrier; - vkCmdBuffer->device->cmdPipelineBarrier(vkCmdBuffer->handle, &dependencyInfo); + cmdBufferImpl->device->cmdPipelineBarrier(cmdBufferImpl->handle, &dependencyInfo); VkDeviceAddress bufAddress = 0; VkBufferDeviceAddressInfoKHR bufferInfo = {0}; - bufferInfo.buffer = vkCmdBuffer->buffer; + bufferInfo.buffer = cmdBufferImpl->buffer; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO_KHR; - bufAddress = vkCmdBuffer->device->getBufferrAddress(vkCmdBuffer->device->handle, &bufferInfo); - - vkCmdBuffer->device->cmdTraceRaysIndirect( - vkCmdBuffer->handle, - &vkSbt->raygen.region, - &vkSbt->miss.region, - &vkSbt->hit.region, - &vkSbt->callable.region, + bufAddress = + cmdBufferImpl->device->getBufferrAddress(cmdBufferImpl->device->handle, &bufferInfo); + + cmdBufferImpl->device->cmdTraceRaysIndirect( + cmdBufferImpl->handle, + &sbtImpl->raygen.region, + &sbtImpl->miss.region, + &sbtImpl->hit.region, + &sbtImpl->callable.region, bufAddress); } @@ -1118,17 +1126,17 @@ void PAL_CALL cmdBindDescriptorSetVk( uint32_t setIndex, PalDescriptorSet* set) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - PipelineVk* pipeline = vkCmdBuffer->pipeline; - DescriptorSetVk* vkSet = (DescriptorSetVk*)set; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipeline = cmdBufferImpl->pipeline; + DescriptorSetVk* setImpl = (DescriptorSetVk*)set; s_Vk.cmdBindDescriptorSets( - vkCmdBuffer->handle, + cmdBufferImpl->handle, pipeline->bindPoint, pipeline->layout, setIndex, 1, - &vkSet->handle, + &setImpl->handle, 0, nullptr); } @@ -1139,13 +1147,13 @@ void PAL_CALL cmdPushConstantsVk( uint64_t size, const void* value) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - PipelineVk* pipeline = vkCmdBuffer->pipeline; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + PipelineVk* pipeline = cmdBufferImpl->pipeline; s_Vk.cmdPushConstants( - vkCmdBuffer->handle, + cmdBufferImpl->handle, pipeline->layout, - vkCmdBuffer->device->shaderStages, + cmdBufferImpl->device->shaderStages, offset, size, value); @@ -1155,97 +1163,97 @@ void PAL_CALL cmdSetCullModeVk( PalCommandBuffer* cmdBuffer, PalCullMode cullMode) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; - VkCullModeFlags vkCullMode = 0; + VkCullModeFlags cullModeImpl = 0; switch (cullMode) { case PAL_CULL_MODE_BACK: - vkCullMode = VK_CULL_MODE_BACK_BIT; + cullModeImpl = VK_CULL_MODE_BACK_BIT; case PAL_CULL_MODE_FRONT: - vkCullMode = VK_CULL_MODE_FRONT_BIT; + cullModeImpl = VK_CULL_MODE_FRONT_BIT; case PAL_CULL_MODE_NONE: - vkCullMode = VK_CULL_MODE_NONE; + cullModeImpl = VK_CULL_MODE_NONE; } - device->cmdSetCullMode(vkCmdBuffer->handle, vkCullMode); + device->cmdSetCullMode(cmdBufferImpl->handle, cullModeImpl); } void PAL_CALL cmdSetFrontFaceVk( PalCommandBuffer* cmdBuffer, PalFrontFace frontFace) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; - VkFrontFace vkFrontFace = 0; + VkFrontFace frontFaceImpl = 0; switch (frontFace) { case PAL_FRONT_FACE_CLOCKWISE: - vkFrontFace = VK_FRONT_FACE_CLOCKWISE; + frontFaceImpl = VK_FRONT_FACE_CLOCKWISE; case PAL_FRONT_FACE_COUNTER_CLOCKWISE: - vkFrontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + frontFaceImpl = VK_FRONT_FACE_COUNTER_CLOCKWISE; } - device->cmdSetFrontFace(vkCmdBuffer->handle, vkFrontFace); + device->cmdSetFrontFace(cmdBufferImpl->handle, frontFaceImpl); } void PAL_CALL cmdSetPrimitiveTopologyVk( PalCommandBuffer* cmdBuffer, PalPrimitiveTopology topology) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; - VkPrimitiveTopology vkTopology = 0; + VkPrimitiveTopology topologyImpl = 0; switch (topology) { case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: { - vkTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + topologyImpl = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; break; } case PAL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: { - vkTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + topologyImpl = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; break; } case PAL_PRIMITIVE_TOPOLOGY_LINE_LIST: { - vkTopology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + topologyImpl = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; break; } case PAL_PRIMITIVE_TOPOLOGY_LINE_STRIP: { - vkTopology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; + topologyImpl = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; break; } case PAL_PRIMITIVE_TOPOLOGY_POINT_LIST: { - vkTopology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + topologyImpl = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; break; } } - device->cmdSetPrimitiveTopology(vkCmdBuffer->handle, vkTopology); + device->cmdSetPrimitiveTopology(cmdBufferImpl->handle, topologyImpl); } void PAL_CALL cmdSetDepthTestEnableVk( PalCommandBuffer* cmdBuffer, PalBool enable) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; - device->cmdSetDepthTestEnable(vkCmdBuffer->handle, enable); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; + device->cmdSetDepthTestEnable(cmdBufferImpl->handle, enable); } void PAL_CALL cmdSetDepthWriteEnableVk( PalCommandBuffer* cmdBuffer, PalBool enable) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; - device->cmdSetDepthWriteEnable(vkCmdBuffer->handle, enable); + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; + device->cmdSetDepthWriteEnable(cmdBufferImpl->handle, enable); } void PAL_CALL cmdSetStencilOpVk( @@ -1256,8 +1264,8 @@ void PAL_CALL cmdSetStencilOpVk( PalStencilOp depthFailOp, PalCompareOp compareOp) { - CommandBufferVk* vkCmdBuffer = (CommandBufferVk*)cmdBuffer; - DeviceVk* device = vkCmdBuffer->device; + CommandBufferVk* cmdBufferImpl = (CommandBufferVk*)cmdBuffer; + DeviceVk* device = cmdBufferImpl->device; VkStencilFaceFlags faceFlags = 0; if (faceMask & PAL_STENCIL_FACE_FLAG_BACK) { faceFlags |= VK_STENCIL_FACE_BACK_BIT; @@ -1267,12 +1275,18 @@ void PAL_CALL cmdSetStencilOpVk( faceFlags |= VK_STENCIL_FACE_FRONT_BIT; } - VkStencilOp vkFailOp = stencilOpToVk(failOp); - VkStencilOp vkPassOp = stencilOpToVk(passOp); - VkStencilOp vkDepthFailOp = stencilOpToVk(depthFailOp); - VkCompareOp vkCompareOp = compareOpToVk(compareOp); - - device->cmdSetStencilOp(vkCmdBuffer->handle, faceFlags, failOp, passOp, depthFailOp, compareOp); + VkStencilOp failOpImpl = stencilOpToVk(failOp); + VkStencilOp passOpImpl = stencilOpToVk(passOp); + VkStencilOp depthFailOpImpl = stencilOpToVk(depthFailOp); + VkCompareOp compareOpImpl = compareOpToVk(compareOp); + + device->cmdSetStencilOp( + cmdBufferImpl->handle, + faceFlags, + failOpImpl, + passOpImpl, + depthFailOpImpl, + compareOpImpl); } #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_descriptors_vulkan.c b/src/graphics/vulkan/pal_descriptors_vulkan.c index b3b9a8f5..d5502105 100644 --- a/src/graphics/vulkan/pal_descriptors_vulkan.c +++ b/src/graphics/vulkan/pal_descriptors_vulkan.c @@ -39,7 +39,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( PalDescriptorSetLayout** outLayout) { VkResult result; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkDescriptorSetLayoutBinding* bindings = nullptr; VkDescriptorBindingFlags* bindingFlags = nullptr; DescriptorSetLayoutVk* layout = nullptr; @@ -73,7 +73,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( binding->descriptorType = descriptortypeToVk(info->bindings[i].descriptorType); binding->pImmutableSamplers = nullptr; - binding->stageFlags = vkDevice->shaderStages; + binding->stageFlags = deviceImpl->shaderStages; // set descriptor indexing flags if (info->flags & PAL_DESCRIPTOR_INDEXING_FLAG_UPDATE_AFTER_BIND) { @@ -97,9 +97,9 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( } result = s_Vk.createDescriptorSetLayout( - vkDevice->handle, + deviceImpl->handle, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &layout->handle); palFree(s_Vk.allocator, bindings); @@ -108,7 +108,7 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( return makeResultVk(result); } - layout->device = vkDevice; + layout->device = deviceImpl; layout->flags = info->flags; *outLayout = (PalDescriptorSetLayout*)layout; return PAL_RESULT_SUCCESS; @@ -116,10 +116,13 @@ PalResult PAL_CALL createDescriptorSetLayoutVk( void PAL_CALL destroyDescriptorSetLayoutVk(PalDescriptorSetLayout* layout) { - DescriptorSetLayoutVk* vkLayout = (DescriptorSetLayoutVk*)layout; - s_Vk.destroyDescriptorSetLayout(vkLayout->device->handle, vkLayout->handle, &s_Vk.vkAllocator); + DescriptorSetLayoutVk* layoutImpl = (DescriptorSetLayoutVk*)layout; + s_Vk.destroyDescriptorSetLayout( + layoutImpl->device->handle, + layoutImpl->handle, + &s_Vk.allocatorImpl); - palFree(s_Vk.allocator, layout); + palFree(s_Vk.allocator, layoutImpl); } PalResult PAL_CALL createDescriptorPoolVk( @@ -128,7 +131,7 @@ PalResult PAL_CALL createDescriptorPoolVk( PalDescriptorPool** outPool) { VkResult result; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; DescriptorPoolVk* pool = nullptr; VkDescriptorPoolSize* poolSizes = nullptr; uint32_t bindingSizeCount = info->bindingSizeCount; @@ -155,8 +158,11 @@ PalResult PAL_CALL createDescriptorPoolVk( createInfo.poolSizeCount = bindingSizeCount; createInfo.pPoolSizes = poolSizes; - result = - s_Vk.createDescriptorPool(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &pool->handle); + result = s_Vk.createDescriptorPool( + deviceImpl->handle, + &createInfo, + &s_Vk.allocatorImpl, + &pool->handle); palFree(s_Vk.allocator, poolSizes); if (result != VK_SUCCESS) { @@ -164,7 +170,7 @@ PalResult PAL_CALL createDescriptorPoolVk( return makeResultVk(result); } - pool->device = vkDevice; + pool->device = deviceImpl; pool->flags = info->flags; *outPool = (PalDescriptorPool*)pool; return PAL_RESULT_SUCCESS; @@ -172,15 +178,15 @@ PalResult PAL_CALL createDescriptorPoolVk( void PAL_CALL destroyDescriptorPoolVk(PalDescriptorPool* pool) { - DescriptorPoolVk* vkPool = (DescriptorPoolVk*)pool; - s_Vk.destroyDescriptorPool(vkPool->device->handle, vkPool->handle, &s_Vk.vkAllocator); + DescriptorPoolVk* poolImpl = (DescriptorPoolVk*)pool; + s_Vk.destroyDescriptorPool(poolImpl->device->handle, poolImpl->handle, &s_Vk.allocatorImpl); palFree(s_Vk.allocator, pool); } PalResult PAL_CALL resetDescriptorPoolVk(PalDescriptorPool* pool) { - DescriptorPoolVk* vkPool = (DescriptorPoolVk*)pool; - s_Vk.resetDescriptorPool(vkPool->device->handle, vkPool->handle, 0); + DescriptorPoolVk* poolImpl = (DescriptorPoolVk*)pool; + s_Vk.resetDescriptorPool(poolImpl->device->handle, poolImpl->handle, 0); return PAL_RESULT_SUCCESS; } @@ -191,9 +197,9 @@ PalResult PAL_CALL allocateDescriptorSetVk( PalDescriptorSet** outSet) { VkResult result; - DeviceVk* vkDevice = (DeviceVk*)device; - DescriptorPoolVk* vkPool = (DescriptorPoolVk*)pool; - DescriptorSetLayoutVk* vkLayout = (DescriptorSetLayoutVk*)layout; + DeviceVk* deviceImpl = (DeviceVk*)device; + DescriptorPoolVk* poolImpl = (DescriptorPoolVk*)pool; + DescriptorSetLayoutVk* layoutImpl = (DescriptorSetLayoutVk*)layout; DescriptorSetVk* set = nullptr; set = palAllocate(s_Vk.allocator, sizeof(DescriptorSetVk), 0); @@ -203,18 +209,18 @@ PalResult PAL_CALL allocateDescriptorSetVk( VkDescriptorSetAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocateInfo.descriptorPool = vkPool->handle; + allocateInfo.descriptorPool = poolImpl->handle; allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &vkLayout->handle; + allocateInfo.pSetLayouts = &layoutImpl->handle; - result = s_Vk.allocateDescriptorSet(vkDevice->handle, &allocateInfo, &set->handle); + result = s_Vk.allocateDescriptorSet(deviceImpl->handle, &allocateInfo, &set->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, set); return makeResultVk(result); } - set->pool = vkPool; - set->device = vkDevice; + set->pool = poolImpl; + set->device = deviceImpl; *outSet = (PalDescriptorSet*)set; return PAL_RESULT_SUCCESS; } @@ -225,7 +231,7 @@ PalResult PAL_CALL updateDescriptorSetVk( PalDescriptorSetWriteInfo* infos) { VkResult result; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkWriteDescriptorSet* writes = nullptr; VkDescriptorBufferInfo* bufferInfos = nullptr; VkDescriptorImageInfo* imageInfos = nullptr; @@ -314,9 +320,9 @@ PalResult PAL_CALL updateDescriptorSetVk( if (info->bufferInfos) { PalDescriptorBufferInfo* tmp = &info->bufferInfos[j]; - BufferVk* vkBuffer = (BufferVk*)tmp->buffer; + BufferVk* bufferImpl = (BufferVk*)tmp->buffer; - bufferInfo->buffer = vkBuffer->handle; + bufferInfo->buffer = bufferImpl->handle; bufferInfo->offset = tmp->offset; bufferInfo->range = tmp->size; } @@ -334,29 +340,29 @@ PalResult PAL_CALL updateDescriptorSetVk( if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLER) { if (info->samplerInfos) { PalDescriptorSamplerInfo* tmp = &info->samplerInfos[j]; - SamplerVk* vkSampler = (SamplerVk*)tmp->sampler; - imageInfo->sampler = vkSampler->handle; + SamplerVk* samplerImpl = (SamplerVk*)tmp->sampler; + imageInfo->sampler = samplerImpl->handle; imageInfo->imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; } } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_STORAGE_IMAGE) { if (info->imageViewInfos) { PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; - ImageViewVk* vkImageView = (ImageViewVk*)tmp->imageView; + ImageViewVk* imageViewImpl = (ImageViewVk*)tmp->imageView; imageInfo->sampler = nullptr; imageInfo->imageLayout = VK_IMAGE_LAYOUT_GENERAL; - imageInfo->imageView = vkImageView->handle; + imageInfo->imageView = imageViewImpl->handle; } } else if (info->descriptorType == PAL_DESCRIPTOR_TYPE_SAMPLED_IMAGE) { if (info->imageViewInfos) { PalDescriptorImageViewInfo* tmp = &info->imageViewInfos[j]; - ImageViewVk* vkImageView = (ImageViewVk*)tmp->imageView; + ImageViewVk* imageViewImpl = (ImageViewVk*)tmp->imageView; imageInfo->sampler = nullptr; imageInfo->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageInfo->imageView = vkImageView->handle; + imageInfo->imageView = imageViewImpl->handle; } } } @@ -382,7 +388,7 @@ PalResult PAL_CALL updateDescriptorSetVk( } } - s_Vk.updateDescriptorSet(vkDevice->handle, count, writes, 0, nullptr); + s_Vk.updateDescriptorSet(deviceImpl->handle, count, writes, 0, nullptr); palFree(s_Vk.allocator, writes); palFree(s_Vk.allocator, bufferInfos); palFree(s_Vk.allocator, imageInfos); diff --git a/src/graphics/vulkan/pal_device_vulkan.c b/src/graphics/vulkan/pal_device_vulkan.c index d5266bdc..88a96fc6 100644 --- a/src/graphics/vulkan/pal_device_vulkan.c +++ b/src/graphics/vulkan/pal_device_vulkan.c @@ -417,8 +417,8 @@ PalResult PAL_CALL createDeviceVk( DeviceVk* device = nullptr; VkPhysicalDeviceProperties props = {0}; - AdapterVk* vkAdapter = (AdapterVk*)adapter; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkAdapter->handle; + AdapterVk* adapterImpl = (AdapterVk*)adapter; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)adapterImpl->handle; s_Vk.getPhysicalDeviceProperties(phyDevice, &props); VkQueueFamilyProperties* queueFamilyProps = nullptr; @@ -709,7 +709,7 @@ PalResult PAL_CALL createDeviceVk( createInfo.queueCreateInfoCount = queueFamilyCount; createInfo.pNext = next; - result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.vkAllocator, &device->handle); + result = s_Vk.createDevice(phyDevice, &createInfo, &s_Vk.allocatorImpl, &device->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, queueFamilyProps); palFree(s_Vk.allocator, queueCreateInfos); @@ -805,10 +805,15 @@ PalResult PAL_CALL createDeviceVk( void PAL_CALL destroyDeviceVk(PalDevice* device) { - DeviceVk* vkDevice = (DeviceVk*)device; - s_Vk.destroyDevice(vkDevice->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkDevice->phyQueues); - palFree(s_Vk.allocator, vkDevice); + DeviceVk* deviceImpl = (DeviceVk*)device; + s_Vk.destroyDevice(deviceImpl->handle, &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, deviceImpl->phyQueues); + palFree(s_Vk.allocator, deviceImpl); +} + +uint32_t PAL_CALL getDeviceLostReasonVk(PalDevice* device) +{ + return (uint32_t)VK_ERROR_DEVICE_LOST; } PalResult PAL_CALL allocateMemoryVk( @@ -820,7 +825,7 @@ PalResult PAL_CALL allocateMemoryVk( { VkResult result; MemoryVk* memory = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = size; @@ -834,10 +839,10 @@ PalResult PAL_CALL allocateMemoryVk( uint32_t memoryTypeMask = 0; uint32_t usages = 0; palUnpackUint32(memoryMask, &memoryTypeMask, &usages); - uint32_t memoryClassMask = vkDevice->memoryClassMask[type] & memoryTypeMask; + uint32_t memoryClassMask = deviceImpl->memoryClassMask[type] & memoryTypeMask; // pick an index using the scoring system and check if the memory index is valid - uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, memoryClassMask); + uint32_t memoryIndex = findBestMemoryIndexVk(deviceImpl->phyDevice, memoryClassMask); if (!(memoryClassMask & (1u << memoryIndex))) { return PAL_RESULT_CODE_PLATFORM_FAILURE; } @@ -849,14 +854,17 @@ PalResult PAL_CALL allocateMemoryVk( allocateInfo.pNext = &allocateFlagsInfo; } - result = - s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &memory->handle); + result = s_Vk.allocateMemory( + deviceImpl->handle, + &allocateInfo, + &s_Vk.allocatorImpl, + &memory->handle); if (result != VK_SUCCESS) { return makeResultVk(result); } - memory->device = vkDevice; + memory->device = deviceImpl; memory->type = type; *outMemory = (PalMemory*)memory; return PAL_RESULT_SUCCESS; @@ -864,18 +872,18 @@ PalResult PAL_CALL allocateMemoryVk( void PAL_CALL freeMemoryVk(PalMemory* memory) { - MemoryVk* vkMemory = (MemoryVk*)memory; - s_Vk.freeMemory(vkMemory->device->handle, vkMemory->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkMemory); + MemoryVk* memoryImpl = (MemoryVk*)memory; + s_Vk.freeMemory(memoryImpl->device->handle, memoryImpl->handle, &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, memoryImpl); } void PAL_CALL querySamplerAnisotropyCapabilitiesVk( PalDevice* device, PalSamplerAnisotropyCapabilities* caps) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkPhysicalDeviceProperties props = {0}; - s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); + s_Vk.getPhysicalDeviceProperties(deviceImpl->phyDevice, &props); caps->maxAnisotropy = props.limits.maxSamplerAnisotropy; } @@ -883,13 +891,13 @@ void PAL_CALL queryMultiViewCapabilitiesVk( PalDevice* device, PalMultiViewCapabilities* caps) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkPhysicalDeviceMultiviewPropertiesKHR props = {0}; VkPhysicalDeviceProperties2 properties2 = {0}; props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + s_Vk.getPhysicalDeviceProperties2(deviceImpl->phyDevice, &properties2); caps->maxViewCount = props.maxMultiviewViewCount; if (caps->maxViewCount == 0) { @@ -901,9 +909,9 @@ void PAL_CALL queryMultiViewportCapabilitiesVk( PalDevice* device, PalMultiViewportCapabilities* caps) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkPhysicalDeviceProperties props = {0}; - s_Vk.getPhysicalDeviceProperties(vkDevice->phyDevice, &props); + s_Vk.getPhysicalDeviceProperties(deviceImpl->phyDevice, &props); caps->maxCount = props.limits.maxViewports; } @@ -911,13 +919,13 @@ void PAL_CALL queryDepthStencilCapabilitiesVk( PalDevice* device, PalDepthStencilCapabilities* caps) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceDepthStencilResolvePropertiesKHR props = {0}; props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES_KHR; properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + s_Vk.getPhysicalDeviceProperties2(deviceImpl->phyDevice, &properties2); caps->supportsIndependentResolve = props.independentResolve; caps->supportsIndependentResolveNone = props.independentResolveNone; @@ -961,13 +969,13 @@ void PAL_CALL queryFragmentShadingRateCapabilitiesVk( PalDevice* device, PalFragmentShadingRateCapabilities* caps) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceFragmentShadingRatePropertiesKHR props = {0}; props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR; properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + s_Vk.getPhysicalDeviceProperties2(deviceImpl->phyDevice, &properties2); memset(caps, 0, sizeof(PalFragmentShadingRateCapabilities)); for (int i = 0; i < PAL_FRAGMENT_SHADING_RATE_COUNT; i++) { @@ -1000,13 +1008,13 @@ void PAL_CALL queryMeshShaderCapabilitiesVk( PalDevice* device, PalMeshShaderCapabilities* caps) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceMeshShaderPropertiesEXT props = {0}; props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT; properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + s_Vk.getPhysicalDeviceProperties2(deviceImpl->phyDevice, &properties2); caps->maxOutputPrimitives = props.maxMeshOutputPrimitives; caps->maxOutputVertices = props.maxMeshOutputVertices; @@ -1026,7 +1034,7 @@ void PAL_CALL queryRayTracingCapabilitiesVk( PalDevice* device, PalRayTracingCapabilities* caps) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkPhysicalDeviceProperties2 properties2 = {0}; properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; VkPhysicalDeviceRayTracingPipelinePropertiesKHR props = {0}; @@ -1035,7 +1043,7 @@ void PAL_CALL queryRayTracingCapabilitiesVk( accProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR; props.pNext = &accProps; properties2.pNext = &props; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + s_Vk.getPhysicalDeviceProperties2(deviceImpl->phyDevice, &properties2); caps->maxRecursionDepth = props.maxRayRecursionDepth; caps->maxHitAttributeSize = props.maxRayHitAttributeSize; @@ -1051,7 +1059,7 @@ void PAL_CALL queryDescriptorIndexingCapabilitiesVk( PalDevice* device, PalDescriptorIndexingCapabilities* caps) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkPhysicalDeviceDescriptorIndexingFeaturesEXT desc = {0}; desc.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT; @@ -1070,8 +1078,8 @@ void PAL_CALL queryDescriptorIndexingCapabilitiesVk( features.pNext = &desc; props.pNext = &accProps; properties2.pNext = &props; - s_Vk.getPhysicalDeviceFeatures2(vkDevice->phyDevice, &features); - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &properties2); + s_Vk.getPhysicalDeviceFeatures2(deviceImpl->phyDevice, &features); + s_Vk.getPhysicalDeviceProperties2(deviceImpl->phyDevice, &properties2); caps->flags = 0; if (desc.descriptorBindingPartiallyBound) { @@ -1119,11 +1127,11 @@ PalResult PAL_CALL createQueueVk( PalQueueType type, PalQueue** outQueue) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkQueueFlags queueFlag = 0; QueueVk* queue = nullptr; - if (vkDevice->phyQueueCount == 0) { + if (deviceImpl->phyQueueCount == 0) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } @@ -1147,8 +1155,8 @@ PalResult PAL_CALL createQueueVk( // we index the for loop so we dont always start at the beginning, this way // we cycle through all queue families each time we create a queue PhysicalQueue* phyQueue = nullptr; - for (int i = vkDevice->phyQueueIndex; i < vkDevice->phyQueueCount; i++) { - PhysicalQueue* pq = &vkDevice->phyQueues[i]; + for (int i = deviceImpl->phyQueueIndex; i < deviceImpl->phyQueueCount; i++) { + PhysicalQueue* pq = &deviceImpl->phyQueues[i]; // check if the physical queue supports the requested operation // and if its not already used if (pq->usages & queueFlag && pq->usedUsages != queueFlag) { @@ -1160,15 +1168,15 @@ PalResult PAL_CALL createQueueVk( if (!phyQueue) { // we didnt get any queue, we check if we started the loop at the beginning or mid way - if (vkDevice->phyQueueIndex == 0) { + if (deviceImpl->phyQueueIndex == 0) { // we searched all queue families return PAL_RESULT_CODE_OUT_OF_MEMORY; } else { // we start at the beginning and go through the queue families again - vkDevice->phyQueueIndex = 0; - for (int i = vkDevice->phyQueueIndex; i < vkDevice->phyQueueCount; i++) { - PhysicalQueue* pq = &vkDevice->phyQueues[i]; + deviceImpl->phyQueueIndex = 0; + for (int i = deviceImpl->phyQueueIndex; i < deviceImpl->phyQueueCount; i++) { + PhysicalQueue* pq = &deviceImpl->phyQueues[i]; if (pq->usages & queueFlag && pq->usedUsages != queueFlag) { pq->usedUsages |= queueFlag; phyQueue = pq; @@ -1187,26 +1195,26 @@ PalResult PAL_CALL createQueueVk( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - vkDevice->phyQueueIndex = (vkDevice->phyQueueIndex + 1) % vkDevice->phyQueueCount; + deviceImpl->phyQueueIndex = (deviceImpl->phyQueueIndex + 1) % deviceImpl->phyQueueCount; queue->phyQueue = phyQueue; queue->usage = queueFlag; - queue->device = vkDevice; + queue->device = deviceImpl; *outQueue = (PalQueue*)queue; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyQueueVk(PalQueue* queue) { - QueueVk* vkQueue = (QueueVk*)queue; - PhysicalQueue* phyQueue = vkQueue->phyQueue; - phyQueue->usedUsages &= ~vkQueue->usage; - palFree(s_Vk.allocator, vkQueue); + QueueVk* queueImpl = (QueueVk*)queue; + PhysicalQueue* phyQueue = queueImpl->phyQueue; + phyQueue->usedUsages &= ~queueImpl->usage; + palFree(s_Vk.allocator, queueImpl); } PalResult PAL_CALL waitQueueVk(PalQueue* queue) { - QueueVk* vkQueue = (QueueVk*)queue; - VkResult result = s_Vk.waitQueue(vkQueue->phyQueue->handle); + QueueVk* queueImpl = (QueueVk*)queue; + VkResult result = s_Vk.waitQueue(queueImpl->phyQueue->handle); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -1219,13 +1227,13 @@ PalBool PAL_CALL canQueuePresentVk( PalSurface* surface) { VkResult result; - QueueVk* vkQueue = (QueueVk*)queue; - PhysicalQueue* phyQueue = vkQueue->phyQueue; - SurfaceVk* vkSurface = (SurfaceVk*)surface; + QueueVk* queueImpl = (QueueVk*)queue; + PhysicalQueue* phyQueue = queueImpl->phyQueue; + SurfaceVk* surfaceImpl = (SurfaceVk*)surface; // check if the queue is a graphics queue before we check its family // index for presentation support. - if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { + if (queueImpl->usage != VK_QUEUE_GRAPHICS_BIT) { return PAL_FALSE; } @@ -1233,7 +1241,7 @@ PalBool PAL_CALL canQueuePresentVk( result = s_Vk.checkSurfaceSupport( phyQueue->phyDevice, phyQueue->familyIndex, - vkSurface->handle, + surfaceImpl->handle, &supported); if (result == VK_SUCCESS && supported) { @@ -1250,7 +1258,7 @@ PalResult PAL_CALL createShaderVk( { VkResult result; ShaderVk* shader = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; shader = palAllocate(s_Vk.allocator, sizeof(ShaderVk), 0); if (!shader) { @@ -1276,13 +1284,14 @@ PalResult PAL_CALL createShaderVk( createInfo.codeSize = info->codeSize; createInfo.pCode = (const uint32_t*)info->code; - result = s_Vk.createShader(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &shader->handle); + result = + s_Vk.createShader(deviceImpl->handle, &createInfo, &s_Vk.allocatorImpl, &shader->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, shader); return makeResultVk(result); } - shader->device = vkDevice; + shader->device = deviceImpl; shader->entryCount = info->entryCount; *outShader = (PalShader*)shader; return PAL_RESULT_SUCCESS; @@ -1290,10 +1299,10 @@ PalResult PAL_CALL createShaderVk( void PAL_CALL destroyShaderVk(PalShader* shader) { - ShaderVk* vkShader = (ShaderVk*)shader; - s_Vk.destroyShader(vkShader->device->handle, vkShader->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkShader->entries); - palFree(s_Vk.allocator, vkShader); + ShaderVk* shaderImpl = (ShaderVk*)shader; + s_Vk.destroyShader(shaderImpl->device->handle, shaderImpl->handle, &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, shaderImpl->entries); + palFree(s_Vk.allocator, shaderImpl); } #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_image_vulkan.c b/src/graphics/vulkan/pal_image_vulkan.c index 7803a2d0..2a281682 100644 --- a/src/graphics/vulkan/pal_image_vulkan.c +++ b/src/graphics/vulkan/pal_image_vulkan.c @@ -151,7 +151,7 @@ PalResult PAL_CALL createImageVk( { VkResult result; ImageVk* image = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; MemoryVk* memory = nullptr; image = palAllocate(s_Vk.allocator, sizeof(ImageVk), 0); @@ -189,7 +189,7 @@ PalResult PAL_CALL createImageVk( createInfo.imageType = VK_IMAGE_TYPE_1D; } - result = s_Vk.createImage(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &image->handle); + result = s_Vk.createImage(deviceImpl->handle, &createInfo, &s_Vk.allocatorImpl, &image->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, image); return makeResultVk(result); @@ -201,30 +201,30 @@ PalResult PAL_CALL createImageVk( // allocate and manage memory VkMemoryRequirements memReq = {0}; - s_Vk.getImageMemoryRequirements(vkDevice->handle, image->handle, &memReq); + s_Vk.getImageMemoryRequirements(deviceImpl->handle, image->handle, &memReq); VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = (VkDeviceSize)memReq.size; - uint32_t memoryMask = vkDevice->memoryClassMask[memoryType] & memReq.memoryTypeBits; - uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, memoryMask); + uint32_t memoryMask = deviceImpl->memoryClassMask[memoryType] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(deviceImpl->phyDevice, memoryMask); if (!(memoryMask & (1u << memoryIndex))) { return PAL_RESULT_CODE_PLATFORM_FAILURE; } allocateInfo.memoryTypeIndex = memoryIndex; result = s_Vk.allocateMemory( - vkDevice->handle, + deviceImpl->handle, &allocateInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &memory->handle); if (result != VK_SUCCESS) { return makeResultVk(result); } - result = s_Vk.bindImageMemory(vkDevice->handle, image->handle, memory->handle, 0); + result = s_Vk.bindImageMemory(deviceImpl->handle, image->handle, memory->handle, 0); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -233,7 +233,7 @@ PalResult PAL_CALL createImageVk( image->isMemoryManaged = PAL_TRUE; } - image->device = vkDevice; + image->device = deviceImpl; image->info.type = info->type; image->info.format = info->format; image->info.usages = info->usages; @@ -252,40 +252,40 @@ PalResult PAL_CALL createImageVk( void PAL_CALL destroyImageVk(PalImage* image) { - ImageVk* vkImage = (ImageVk*)image; - if (vkImage->info.belongsToSwapchain) { + ImageVk* imageImpl = (ImageVk*)image; + if (imageImpl->info.belongsToSwapchain) { return; } - s_Vk.destroyImage(vkImage->device->handle, vkImage->handle, &s_Vk.vkAllocator); - if (vkImage->isMemoryManaged) { - s_Vk.freeMemory(vkImage->device->handle, vkImage->memory->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkImage->memory); + s_Vk.destroyImage(imageImpl->device->handle, imageImpl->handle, &s_Vk.allocatorImpl); + if (imageImpl->isMemoryManaged) { + s_Vk.freeMemory(imageImpl->device->handle, imageImpl->memory->handle, &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, imageImpl->memory); } - palFree(s_Vk.allocator, vkImage); + palFree(s_Vk.allocator, imageImpl); } void PAL_CALL getImageInfoVk( PalImage* image, PalImageInfo* info) { - ImageVk* vkImage = (ImageVk*)image; - *info = vkImage->info; + ImageVk* imageImpl = (ImageVk*)image; + *info = imageImpl->info; } void PAL_CALL getImageMemoryRequirementsVk( PalImage* image, PalMemoryRequirements* requirements) { - ImageVk* vkImage = (ImageVk*)image; - if (vkImage->info.belongsToSwapchain) { + ImageVk* imageImpl = (ImageVk*)image; + if (imageImpl->info.belongsToSwapchain) { return; } - DeviceVk* device = vkImage->device; + DeviceVk* device = imageImpl->device; VkMemoryRequirements memReq = {0}; - s_Vk.getImageMemoryRequirements(device->handle, vkImage->handle, &memReq); + s_Vk.getImageMemoryRequirements(device->handle, imageImpl->handle, &memReq); requirements->alignment = (uint64_t)memReq.alignment; requirements->size = (uint64_t)memReq.size; requirements->memoryMask = palPackUint32(memReq.memoryTypeBits, 0); @@ -301,18 +301,18 @@ PalResult PAL_CALL bindImageMemoryVk( PalMemory* memory, uint64_t offset) { - ImageVk* vkImage = (ImageVk*)image; - if (vkImage->info.belongsToSwapchain) { + ImageVk* imageImpl = (ImageVk*)image; + if (imageImpl->info.belongsToSwapchain) { return PAL_RESULT_CODE_INVALID_OPERATION; } - if (vkImage->memory) { + if (imageImpl->memory) { return PAL_RESULT_CODE_INVALID_OPERATION; } - MemoryVk* vkMemory = (MemoryVk*)memory; - s_Vk.bindImageMemory(vkImage->device->handle, vkImage->handle, vkMemory->handle, offset); - vkImage->memory = vkMemory; + MemoryVk* memoryImpl = (MemoryVk*)memory; + s_Vk.bindImageMemory(imageImpl->device->handle, imageImpl->handle, memoryImpl->handle, offset); + imageImpl->memory = memoryImpl; return PAL_RESULT_SUCCESS; } @@ -324,8 +324,8 @@ PalResult PAL_CALL createImageViewVk( { VkResult result = VK_SUCCESS; ImageViewVk* imageView = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; - ImageVk* vkImage = (ImageVk*)image; + DeviceVk* deviceImpl = (DeviceVk*)device; + ImageVk* imageImpl = (ImageVk*)image; imageView = palAllocate(s_Vk.allocator, sizeof(ImageViewVk), 0); if (!imageView) { @@ -335,7 +335,7 @@ PalResult PAL_CALL createImageViewVk( VkImageViewCreateInfo createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.format = formatToVk(info->format); - createInfo.image = vkImage->handle; + createInfo.image = imageImpl->handle; createInfo.viewType = imageViewTypeToVk(info->type); createInfo.subresourceRange.aspectMask = imageAspectToVk(info->subresourceRange.aspect); @@ -344,16 +344,19 @@ PalResult PAL_CALL createImageViewVk( createInfo.subresourceRange.levelCount = info->subresourceRange.mipLevelCount; createInfo.subresourceRange.layerCount = info->subresourceRange.layerArrayCount; - result = - s_Vk.createImageView(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &imageView->handle); + result = s_Vk.createImageView( + deviceImpl->handle, + &createInfo, + &s_Vk.allocatorImpl, + &imageView->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, imageView); return makeResultVk(result); } - imageView->device = vkDevice; - imageView->image = vkImage; + imageView->device = deviceImpl; + imageView->image = imageImpl; imageView->layerCount = createInfo.subresourceRange.layerCount; *outImageView = (PalImageView*)imageView; return PAL_RESULT_SUCCESS; @@ -361,9 +364,12 @@ PalResult PAL_CALL createImageViewVk( void PAL_CALL destroyImageViewVk(PalImageView* imageView) { - ImageViewVk* vkImageView = (ImageViewVk*)imageView; - s_Vk.destroyImageView(vkImageView->device->handle, vkImageView->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkImageView); + ImageViewVk* imageViewImpl = (ImageViewVk*)imageView; + s_Vk.destroyImageView( + imageViewImpl->device->handle, + imageViewImpl->handle, + &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, imageViewImpl); } PalResult PAL_CALL createSamplerVk( @@ -373,7 +379,7 @@ PalResult PAL_CALL createSamplerVk( { VkResult result = VK_SUCCESS; SamplerVk* sampler = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; sampler = palAllocate(s_Vk.allocator, sizeof(SamplerVk), 0); if (!sampler) { @@ -400,23 +406,24 @@ PalResult PAL_CALL createSamplerVk( createInfo.addressModeW = addressModeToVk(info->addressModeW); createInfo.borderColor = borderColorToVk(info->borderColor); - result = s_Vk.createSampler(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &sampler->handle); + result = + s_Vk.createSampler(deviceImpl->handle, &createInfo, &s_Vk.allocatorImpl, &sampler->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, sampler); return makeResultVk(result); } - sampler->device = vkDevice; + sampler->device = deviceImpl; *outSampler = (PalSampler*)sampler; return PAL_RESULT_SUCCESS; } void PAL_CALL destroySamplerVk(PalSampler* sampler) { - SamplerVk* vkSampler = (SamplerVk*)sampler; - s_Vk.destroySampler(vkSampler->device->handle, vkSampler->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkSampler); + SamplerVk* samplerImpl = (SamplerVk*)sampler; + s_Vk.destroySampler(samplerImpl->device->handle, samplerImpl->handle, &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, samplerImpl); } #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_pipeline_vulkan.c b/src/graphics/vulkan/pal_pipeline_vulkan.c index 19cb8dfe..e237216b 100644 --- a/src/graphics/vulkan/pal_pipeline_vulkan.c +++ b/src/graphics/vulkan/pal_pipeline_vulkan.c @@ -140,7 +140,7 @@ PalResult PAL_CALL createPipelineLayoutVk( PalPipelineLayout** outLayout) { VkResult result; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; PipelineLayoutVk* layout = nullptr; VkPushConstantRange pushConstantRange = {0}; VkDescriptorSetLayout* descriptorLayouts = nullptr; @@ -173,16 +173,16 @@ PalResult PAL_CALL createPipelineLayoutVk( if (info->usePushConstant) { pushConstantRange.size = info->pushConstantInfo.size; - pushConstantRange.stageFlags = vkDevice->shaderStages; + pushConstantRange.stageFlags = deviceImpl->shaderStages; pushConstantRange.offset = info->pushConstantInfo.offset; createInfo.pushConstantRangeCount = 1; createInfo.pPushConstantRanges = &pushConstantRange; } result = s_Vk.createPipelineLayout( - vkDevice->handle, + deviceImpl->handle, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &layout->handle); if (info->descriptorSetLayoutCount) { @@ -194,7 +194,7 @@ PalResult PAL_CALL createPipelineLayoutVk( return makeResultVk(result); } - layout->device = vkDevice; + layout->device = deviceImpl; *outLayout = (PalPipelineLayout*)layout; return PAL_RESULT_SUCCESS; } @@ -205,7 +205,7 @@ void PAL_CALL destroyPipelineLayoutVk(PalPipelineLayout* layout) s_Vk.destroyPipelineLayout( pipelineLayout->device->handle, pipelineLayout->handle, - &s_Vk.vkAllocator); + &s_Vk.allocatorImpl); palFree(s_Vk.allocator, layout); } @@ -217,7 +217,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( { VkResult result; PipelineVk* pipeline = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; PipelineLayoutVk* layout = (PipelineLayoutVk*)info->pipelineLayout; VkPipelineShaderStageCreateInfo* shaderStages = nullptr; @@ -406,27 +406,27 @@ PalResult PAL_CALL createGraphicsPipelineVk( dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_BIAS; dynamicStates[dynCount++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE; - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { + if (deviceImpl->features & PAL_ADAPTER_FEATURE_DYNAMIC_CULL_MODE) { dynamicStates[dynCount++] = VK_DYNAMIC_STATE_CULL_MODE_EXT; } - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { + if (deviceImpl->features & PAL_ADAPTER_FEATURE_DYNAMIC_FRONT_FACE) { dynamicStates[dynCount++] = VK_DYNAMIC_STATE_FRONT_FACE_EXT; } - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { + if (deviceImpl->features & PAL_ADAPTER_FEATURE_DYNAMIC_PRIMITIVE_TOPOLOGY) { dynamicStates[dynCount++] = VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT; } - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { + if (deviceImpl->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_TEST_ENABLE) { dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT; } - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { + if (deviceImpl->features & PAL_ADAPTER_FEATURE_DYNAMIC_DEPTH_WRITE_ENABLE) { dynamicStates[dynCount++] = VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT; } - if (vkDevice->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { + if (deviceImpl->features & PAL_ADAPTER_FEATURE_DYNAMIC_STENCIL_OP) { dynamicStates[dynCount++] = VK_DYNAMIC_STATE_STENCIL_OP_EXT; } @@ -516,18 +516,18 @@ PalResult PAL_CALL createGraphicsPipelineVk( PalStencilOpState* back = &state->backStencilOpState; PalStencilOpState* front = &state->frontStencilOpState; - VkStencilOpState* vkBack = &depthStencilState.back; - VkStencilOpState* vkFront = &depthStencilState.front; + VkStencilOpState* backImpl = &depthStencilState.back; + VkStencilOpState* frontImpl = &depthStencilState.front; - vkBack->compareOp = compareOpToVk(back->compareOp); - vkBack->depthFailOp = stencilOpToVk(back->depthFailOp); - vkBack->failOp = stencilOpToVk(back->failOp); - vkBack->passOp = stencilOpToVk(back->passOp); + backImpl->compareOp = compareOpToVk(back->compareOp); + backImpl->depthFailOp = stencilOpToVk(back->depthFailOp); + backImpl->failOp = stencilOpToVk(back->failOp); + backImpl->passOp = stencilOpToVk(back->passOp); - vkFront->compareOp = compareOpToVk(front->compareOp); - vkFront->depthFailOp = stencilOpToVk(front->depthFailOp); - vkFront->failOp = stencilOpToVk(front->failOp); - vkFront->passOp = stencilOpToVk(front->passOp); + frontImpl->compareOp = compareOpToVk(front->compareOp); + frontImpl->depthFailOp = stencilOpToVk(front->depthFailOp); + frontImpl->failOp = stencilOpToVk(front->failOp); + frontImpl->passOp = stencilOpToVk(front->passOp); depthStencilState.depthCompareOp = compareOpToVk(state->compareOp); depthStencilState.depthTestEnable = state->enableDepthTest; @@ -635,11 +635,11 @@ PalResult PAL_CALL createGraphicsPipelineVk( createInfo.pNext = &dynRendering; result = s_Vk.createGraphicsPipeline( - vkDevice->handle, + deviceImpl->handle, 0, 1, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &pipeline->handle); if (result != VK_SUCCESS) { @@ -659,7 +659,7 @@ PalResult PAL_CALL createGraphicsPipelineVk( } pipeline->bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - pipeline->device = vkDevice; + pipeline->device = deviceImpl; pipeline->layout = layout->handle; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -670,7 +670,7 @@ PalResult PAL_CALL createComputePipelineVk( const PalComputePipelineCreateInfo* info, PalPipeline** outPipeline) { - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; PipelineLayoutVk* layout = (PipelineLayoutVk*)info->pipelineLayout; ShaderVk* shader = (ShaderVk*)info->computeShader; PipelineVk* pipeline = nullptr; @@ -690,11 +690,11 @@ PalResult PAL_CALL createComputePipelineVk( createInfo.stage.pName = shader->entries[0].entryName; VkResult result = s_Vk.createComputePipeline( - vkDevice->handle, + deviceImpl->handle, nullptr, 1, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &pipeline->handle); if (result != VK_SUCCESS) { @@ -703,7 +703,7 @@ PalResult PAL_CALL createComputePipelineVk( } pipeline->bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; - pipeline->device = vkDevice; + pipeline->device = deviceImpl; pipeline->layout = layout->handle; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -715,13 +715,13 @@ PalResult PAL_CALL createRayTracingPipelineVk( PalPipeline** outPipeline) { VkResult result; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; PipelineLayoutVk* layout = (PipelineLayoutVk*)info->pipelineLayout; PipelineVk* pipeline = nullptr; VkPipelineShaderStageCreateInfo* shaderStages = nullptr; VkRayTracingShaderGroupCreateInfoKHR* groups = nullptr; - if (info->maxPayloadSize > vkDevice->limits.maxPayloadSize) { + if (info->maxPayloadSize > deviceImpl->limits.maxPayloadSize) { return PAL_RESULT_CODE_INVALID_ARGUMENT; } @@ -850,13 +850,13 @@ PalResult PAL_CALL createRayTracingPipelineVk( createInfo.maxPipelineRayRecursionDepth = info->maxRecursionDepth; createInfo.layout = layout->handle; - result = vkDevice->createRayTracingPipeline( - vkDevice->handle, + result = deviceImpl->createRayTracingPipeline( + deviceImpl->handle, nullptr, nullptr, 1, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &pipeline->handle); palFree(s_Vk.allocator, groups); @@ -867,7 +867,7 @@ PalResult PAL_CALL createRayTracingPipelineVk( } pipeline->bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR; - pipeline->device = vkDevice; + pipeline->device = deviceImpl; pipeline->layout = layout->handle; *outPipeline = (PalPipeline*)pipeline; return PAL_RESULT_SUCCESS; @@ -875,8 +875,8 @@ PalResult PAL_CALL createRayTracingPipelineVk( void PAL_CALL destroyPipelineVk(PalPipeline* pipeline) { - PipelineVk* vkPipeline = (PipelineVk*)pipeline; - s_Vk.destroyPipeline(vkPipeline->device->handle, vkPipeline->handle, &s_Vk.vkAllocator); + PipelineVk* pipelineImpl = (PipelineVk*)pipeline; + s_Vk.destroyPipeline(pipelineImpl->device->handle, pipelineImpl->handle, &s_Vk.allocatorImpl); palFree(s_Vk.allocator, pipeline); } diff --git a/src/graphics/vulkan/pal_sbt_vulkan.c b/src/graphics/vulkan/pal_sbt_vulkan.c index 7d492a0b..382557b7 100644 --- a/src/graphics/vulkan/pal_sbt_vulkan.c +++ b/src/graphics/vulkan/pal_sbt_vulkan.c @@ -16,7 +16,7 @@ PalResult PAL_CALL createShaderBindingTableVk( PalShaderBindingTable** outSbt) { VkResult result; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; ShaderBindingTableVk* sbt = nullptr; PipelineVk* pipeline = (PipelineVk*)info->rayTracingPipeline; ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; @@ -39,7 +39,7 @@ PalResult PAL_CALL createShaderBindingTableVk( VkPhysicalDeviceProperties2KHR props = {0}; props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; props.pNext = &rayProps; - s_Vk.getPhysicalDeviceProperties2(vkDevice->phyDevice, &props); + s_Vk.getPhysicalDeviceProperties2(deviceImpl->phyDevice, &props); uint32_t groupHandleSize = rayProps.shaderGroupHandleSize; uint32_t groupHandleAlignment = rayProps.shaderGroupHandleAlignment; @@ -119,7 +119,8 @@ PalResult PAL_CALL createShaderBindingTableVk( bufCreateInfo.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; bufCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - result = s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->buffer); + result = + s_Vk.createBuffer(deviceImpl->handle, &bufCreateInfo, &s_Vk.allocatorImpl, &sbt->buffer); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -127,8 +128,11 @@ PalResult PAL_CALL createShaderBindingTableVk( // create staging buffer bufCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; sbt->stagingBufferSize = bufferSize; - result = - s_Vk.createBuffer(vkDevice->handle, &bufCreateInfo, &s_Vk.vkAllocator, &sbt->stagingBuffer); + result = s_Vk.createBuffer( + deviceImpl->handle, + &bufCreateInfo, + &s_Vk.allocatorImpl, + &sbt->stagingBuffer); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -136,14 +140,14 @@ PalResult PAL_CALL createShaderBindingTableVk( // allocate CPU upload memory and bind VkMemoryRequirements memReq = {0}; - s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->buffer, &memReq); + s_Vk.getBufferMemoryRequirements(deviceImpl->handle, sbt->buffer, &memReq); VkMemoryAllocateInfo allocateInfo = {0}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memReq.size; - uint32_t mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; - uint32_t memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + uint32_t mask = deviceImpl->memoryClassMask[PAL_MEMORY_TYPE_GPU_ONLY] & memReq.memoryTypeBits; + uint32_t memoryIndex = findBestMemoryIndexVk(deviceImpl->phyDevice, mask); allocateInfo.memoryTypeIndex = memoryIndex; VkMemoryAllocateFlagsInfo allocateFlagsInfo = {0}; @@ -151,34 +155,37 @@ PalResult PAL_CALL createShaderBindingTableVk( allocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; allocateInfo.pNext = &allocateFlagsInfo; - result = - s_Vk.allocateMemory(vkDevice->handle, &allocateInfo, &s_Vk.vkAllocator, &sbt->bufferMemory); + result = s_Vk.allocateMemory( + deviceImpl->handle, + &allocateInfo, + &s_Vk.allocatorImpl, + &sbt->bufferMemory); if (result != VK_SUCCESS) { return makeResultVk(result); } // allocate memory for staging buffer - s_Vk.getBufferMemoryRequirements(vkDevice->handle, sbt->stagingBuffer, &memReq); + s_Vk.getBufferMemoryRequirements(deviceImpl->handle, sbt->stagingBuffer, &memReq); allocateInfo.allocationSize = memReq.size; - mask = vkDevice->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] & memReq.memoryTypeBits; - memoryIndex = findBestMemoryIndexVk(vkDevice->phyDevice, mask); + mask = deviceImpl->memoryClassMask[PAL_MEMORY_TYPE_CPU_UPLOAD] & memReq.memoryTypeBits; + memoryIndex = findBestMemoryIndexVk(deviceImpl->phyDevice, mask); allocateInfo.memoryTypeIndex = memoryIndex; allocateInfo.pNext = nullptr; // we dont need the address result = s_Vk.allocateMemory( - vkDevice->handle, + deviceImpl->handle, &allocateInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &sbt->stagingBufferMemory); if (result != VK_SUCCESS) { return makeResultVk(result); } - s_Vk.bindBufferMemory(vkDevice->handle, sbt->buffer, sbt->bufferMemory, 0); - s_Vk.bindBufferMemory(vkDevice->handle, sbt->stagingBuffer, sbt->stagingBufferMemory, 0); + s_Vk.bindBufferMemory(deviceImpl->handle, sbt->buffer, sbt->bufferMemory, 0); + s_Vk.bindBufferMemory(deviceImpl->handle, sbt->stagingBuffer, sbt->stagingBufferMemory, 0); // get shader group handles uint32_t handlesSize = totalGroups * groupHandleSize; @@ -187,8 +194,8 @@ PalResult PAL_CALL createShaderBindingTableVk( return PAL_RESULT_CODE_OUT_OF_MEMORY; } - result = vkDevice->getRayTracingShaderGroupHandles( - vkDevice->handle, + result = deviceImpl->getRayTracingShaderGroupHandles( + deviceImpl->handle, pipeline->handle, 0, totalGroups, @@ -201,7 +208,8 @@ PalResult PAL_CALL createShaderBindingTableVk( // copy handles into the buffer void* ptr = nullptr; - result = s_Vk.mapMemory(vkDevice->handle, sbt->stagingBufferMemory, 0, VK_WHOLE_SIZE, 0, &ptr); + result = + s_Vk.mapMemory(deviceImpl->handle, sbt->stagingBufferMemory, 0, VK_WHOLE_SIZE, 0, &ptr); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -272,7 +280,7 @@ PalResult PAL_CALL createShaderBindingTableVk( VkBufferDeviceAddressInfo bufferAddressInfo = {0}; bufferAddressInfo.buffer = sbt->buffer; bufferAddressInfo.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO; - sbt->baseAddress = s_Vk.getBufferDeviceAddress(vkDevice->handle, &bufferAddressInfo); + sbt->baseAddress = s_Vk.getBufferDeviceAddress(deviceImpl->handle, &bufferAddressInfo); // raygen sbt->raygen.region.deviceAddress = sbt->baseAddress; @@ -303,7 +311,7 @@ PalResult PAL_CALL createShaderBindingTableVk( sbt->callable.region.stride = callableStride; palFree(s_Vk.allocator, handles); - sbt->device = vkDevice; + sbt->device = deviceImpl; sbt->handleSize = groupHandleSize; sbt->pipeline = pipeline; @@ -314,15 +322,15 @@ PalResult PAL_CALL createShaderBindingTableVk( void PAL_CALL destroyShaderBindingTableVk(PalShaderBindingTable* sbt) { - ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; - DeviceVk* device = vkSbt->device; - s_Vk.unmapMemory(device->handle, vkSbt->stagingBufferMemory); - - s_Vk.destroyBuffer(device->handle, vkSbt->buffer, &s_Vk.vkAllocator); - s_Vk.destroyBuffer(device->handle, vkSbt->stagingBuffer, &s_Vk.vkAllocator); - s_Vk.freeMemory(device->handle, vkSbt->bufferMemory, &s_Vk.vkAllocator); - s_Vk.freeMemory(device->handle, vkSbt->stagingBufferMemory, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkSbt); + ShaderBindingTableVk* sbtImpl = (ShaderBindingTableVk*)sbt; + DeviceVk* device = sbtImpl->device; + s_Vk.unmapMemory(device->handle, sbtImpl->stagingBufferMemory); + + s_Vk.destroyBuffer(device->handle, sbtImpl->buffer, &s_Vk.allocatorImpl); + s_Vk.destroyBuffer(device->handle, sbtImpl->stagingBuffer, &s_Vk.allocatorImpl); + s_Vk.freeMemory(device->handle, sbtImpl->bufferMemory, &s_Vk.allocatorImpl); + s_Vk.freeMemory(device->handle, sbtImpl->stagingBufferMemory, &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, sbtImpl); } void PAL_CALL updateShaderBindingTableVk( @@ -330,9 +338,9 @@ void PAL_CALL updateShaderBindingTableVk( uint32_t count, PalShaderBindingTableRecordInfo* infos) { - ShaderBindingTableVk* vkSbt = (ShaderBindingTableVk*)sbt; - DeviceVk* vkDevice = vkSbt->device; - PipelineVk* pipeline = vkSbt->pipeline; + ShaderBindingTableVk* sbtImpl = (ShaderBindingTableVk*)sbt; + DeviceVk* deviceImpl = sbtImpl->device; + PipelineVk* pipeline = sbtImpl->pipeline; ShaderBindingTableInfo* sbtInfo = &pipeline->sbtInfo; uint32_t stride = 0; @@ -347,35 +355,35 @@ void PAL_CALL updateShaderBindingTableVk( if (index < sbtInfo->raygenCount) { // raygen group offset = 0; - stride = vkSbt->raygen.region.stride; - startIndex = vkSbt->raygen.startIndex; + stride = sbtImpl->raygen.region.stride; + startIndex = sbtImpl->raygen.startIndex; } else if (index < sbtInfo->raygenCount + sbtInfo->missCount) { // miss group - offset = vkSbt->miss.offset; - stride = vkSbt->miss.region.stride; - startIndex = vkSbt->miss.startIndex; + offset = sbtImpl->miss.offset; + stride = sbtImpl->miss.region.stride; + startIndex = sbtImpl->miss.startIndex; } else if (index < sbtInfo->raygenCount + sbtInfo->missCount + sbtInfo->hitCount) { // hit group - offset = vkSbt->hit.offset; - stride = vkSbt->hit.region.stride; - startIndex = vkSbt->hit.startIndex; + offset = sbtImpl->hit.offset; + stride = sbtImpl->hit.region.stride; + startIndex = sbtImpl->hit.startIndex; } else { // callable group - offset = vkSbt->callable.offset; - stride = vkSbt->callable.region.stride; - startIndex = vkSbt->callable.startIndex; + offset = sbtImpl->callable.offset; + stride = sbtImpl->callable.region.stride; + startIndex = sbtImpl->callable.startIndex; } // write payload uint32_t localIndex = index - startIndex; - uint8_t* dst = (uint8_t*)vkSbt->stagingPtr + offset + (localIndex * stride); - memcpy(dst + vkSbt->handleSize, info->localData, info->localDataSize); + uint8_t* dst = (uint8_t*)sbtImpl->stagingPtr + offset + (localIndex * stride); + memcpy(dst + sbtImpl->handleSize, info->localData, info->localDataSize); } - vkSbt->isDirty = PAL_TRUE; + sbtImpl->isDirty = PAL_TRUE; } #endif // PAL_HAS_VULKAN_BACKEND \ No newline at end of file diff --git a/src/graphics/vulkan/pal_swapchain_vulkan.c b/src/graphics/vulkan/pal_swapchain_vulkan.c index 655e056f..1926e045 100644 --- a/src/graphics/vulkan/pal_swapchain_vulkan.c +++ b/src/graphics/vulkan/pal_swapchain_vulkan.c @@ -17,7 +17,7 @@ PalResult PAL_CALL createSurfaceVk( { VkResult result; SurfaceVk* surface = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; VkSurfaceKHR tmp = nullptr; surface = palAllocate(s_Vk.allocator, sizeof(SurfaceVk), 0); @@ -38,7 +38,7 @@ PalResult PAL_CALL createSurfaceVk( cInfo.hinstance = windowInstance; cInfo.hwnd = window; cInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + result = s_Vk.createWin32Surface(s_Vk.instance, &cInfo, &s_Vk.allocatorImpl, &tmp); #else if (instanceType == PAL_WINDOW_INSTANCE_TYPE_WIN32) { @@ -56,7 +56,7 @@ PalResult PAL_CALL createSurfaceVk( cInfo.flags = 0; cInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR; cInfo.surface = window; - result = s_Vk.createWaylandSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + result = s_Vk.createWaylandSurface(s_Vk.instance, &cInfo, &s_Vk.allocatorImpl, &tmp); } else if (instanceType == PAL_WINDOW_INSTANCE_TYPE_X11) { if (!s_Vk.createXlibSurface) { @@ -67,7 +67,7 @@ PalResult PAL_CALL createSurfaceVk( cInfo.dpy = windowInstance; cInfo.window = (Window)(uintptr_t)(window); cInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; - result = s_Vk.createXlibSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + result = s_Vk.createXlibSurface(s_Vk.instance, &cInfo, &s_Vk.allocatorImpl, &tmp); } else if (instanceType == PAL_WINDOW_INSTANCE_TYPE_XCB) { if (!s_Vk.createXcbSurface) { @@ -78,7 +78,7 @@ PalResult PAL_CALL createSurfaceVk( cInfo.connection = windowInstance; cInfo.window = (xcb_window_t)(uintptr_t)(window); cInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; - result = s_Vk.createXcbSurface(s_Vk.instance, &cInfo, &s_Vk.vkAllocator, &tmp); + result = s_Vk.createXcbSurface(s_Vk.instance, &cInfo, &s_Vk.allocatorImpl, &tmp); } #endif // _WIN32 @@ -87,7 +87,7 @@ PalResult PAL_CALL createSurfaceVk( return makeResultVk(result); } - surface->device = vkDevice; + surface->device = deviceImpl; surface->handle = tmp; *outSurface = (PalSurface*)surface; return PAL_RESULT_SUCCESS; @@ -95,9 +95,9 @@ PalResult PAL_CALL createSurfaceVk( void PAL_CALL destroySurfaceVk(PalSurface* surface) { - SurfaceVk* vkSurface = (SurfaceVk*)surface; - s_Vk.destroySurface(s_Vk.instance, vkSurface->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkSurface); + SurfaceVk* surfaceImpl = (SurfaceVk*)surface; + s_Vk.destroySurface(s_Vk.instance, surfaceImpl->handle, &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, surfaceImpl); } void PAL_CALL getSurfaceCapabilitiesVk( @@ -107,16 +107,16 @@ void PAL_CALL getSurfaceCapabilitiesVk( { int32_t formatCount = 0; uint32_t modeCount = 0; - SurfaceVk* vkSurface = (SurfaceVk*)surface; + SurfaceVk* surfaceImpl = (SurfaceVk*)surface; VkSurfaceFormatKHR* formats = nullptr; VkPresentModeKHR* modes = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; - VkPhysicalDevice phyDevice = (VkPhysicalDevice)vkDevice->phyDevice; + DeviceVk* deviceImpl = (DeviceVk*)device; + VkPhysicalDevice phyDevice = (VkPhysicalDevice)deviceImpl->phyDevice; memset(caps, 0, sizeof(PalSurfaceCapabilities)); - s_Vk.getSurfacePresentModes(phyDevice, vkSurface->handle, &modeCount, nullptr); - s_Vk.getSurfaceFormats(phyDevice, vkSurface->handle, &formatCount, nullptr); + s_Vk.getSurfacePresentModes(phyDevice, surfaceImpl->handle, &modeCount, nullptr); + s_Vk.getSurfaceFormats(phyDevice, surfaceImpl->handle, &formatCount, nullptr); modes = palAllocate(s_Vk.allocator, sizeof(VkPresentModeKHR) * modeCount, 0); formats = palAllocate(s_Vk.allocator, sizeof(VkSurfaceFormatKHR) * formatCount, 0); @@ -124,11 +124,11 @@ void PAL_CALL getSurfaceCapabilitiesVk( return; } - s_Vk.getSurfacePresentModes(phyDevice, vkSurface->handle, &modeCount, modes); - s_Vk.getSurfaceFormats(phyDevice, vkSurface->handle, &formatCount, formats); + s_Vk.getSurfacePresentModes(phyDevice, surfaceImpl->handle, &modeCount, modes); + s_Vk.getSurfaceFormats(phyDevice, surfaceImpl->handle, &formatCount, formats); VkSurfaceCapabilitiesKHR surfaceCaps; - s_Vk.getSurfaceCapabilities(phyDevice, vkSurface->handle, &surfaceCaps); + s_Vk.getSurfaceCapabilities(phyDevice, surfaceImpl->handle, &surfaceCaps); caps->minImageWidth = surfaceCaps.minImageExtent.width; caps->minImageHeight = surfaceCaps.minImageExtent.height; caps->maxImageWidth = surfaceCaps.maxImageExtent.width; @@ -209,14 +209,14 @@ PalResult PAL_CALL createSwapchainVk( SwapchainVk* swapchain = nullptr; VkImage* images = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; - QueueVk* vkQueue = (QueueVk*)queue; - PhysicalQueue* phyQueue = vkQueue->phyQueue; - SurfaceVk* vkSurface = (SurfaceVk*)surface; + DeviceVk* deviceImpl = (DeviceVk*)device; + QueueVk* queueImpl = (QueueVk*)queue; + PhysicalQueue* phyQueue = queueImpl->phyQueue; + SurfaceVk* surfaceImpl = (SurfaceVk*)surface; // check if the queue is a graphics queue before we check its family // index for presentation support. - if (vkQueue->usage != VK_QUEUE_GRAPHICS_BIT) { + if (queueImpl->usage != VK_QUEUE_GRAPHICS_BIT) { return PAL_RESULT_CODE_INVALID_HANDLE; } @@ -228,7 +228,7 @@ PalResult PAL_CALL createSwapchainVk( VkSwapchainCreateInfoKHR createInfo = {0}; createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.surface = vkSurface->handle; + createInfo.surface = surfaceImpl->handle; createInfo.imageArrayLayers = info->imageArrayLayerCount; createInfo.imageExtent.width = info->width; createInfo.imageExtent.height = info->height; @@ -278,10 +278,10 @@ PalResult PAL_CALL createSwapchainVk( } // create swapchain - VkResult result = vkDevice->createSwapchain( - vkDevice->handle, + VkResult result = deviceImpl->createSwapchain( + deviceImpl->handle, &createInfo, - &s_Vk.vkAllocator, + &s_Vk.allocatorImpl, &swapchain->handle); if (result != VK_SUCCESS) { @@ -291,21 +291,21 @@ PalResult PAL_CALL createSwapchainVk( // get and cache all images uint32_t count = 0; - result = vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, nullptr); + result = deviceImpl->getSwapchainImages(deviceImpl->handle, swapchain->handle, &count, nullptr); swapchain->images = palAllocate(s_Vk.allocator, sizeof(ImageVk) * count, 0); images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); if (!swapchain->images || !images) { - vkDevice->destroySwapchain(vkDevice->handle, swapchain->handle, &s_Vk.vkAllocator); + deviceImpl->destroySwapchain(deviceImpl->handle, swapchain->handle, &s_Vk.allocatorImpl); palFree(s_Vk.allocator, swapchain); return PAL_RESULT_CODE_OUT_OF_MEMORY; } - vkDevice->getSwapchainImages(vkDevice->handle, swapchain->handle, &count, images); + deviceImpl->getSwapchainImages(deviceImpl->handle, swapchain->handle, &count, images); // fill all images with the creation info for (int i = 0; i < count; i++) { ImageVk* image = &swapchain->images[i]; - image->device = vkDevice; + image->device = deviceImpl; image->handle = images[i]; image->info.belongsToSwapchain = PAL_TRUE; @@ -321,8 +321,8 @@ PalResult PAL_CALL createSwapchainVk( } palFree(s_Vk.allocator, images); - swapchain->device = vkDevice; - swapchain->queue = vkQueue; + swapchain->device = deviceImpl; + swapchain->queue = queueImpl; swapchain->imageCount = count; *outSwapchain = (PalSwapchain*)swapchain; return PAL_RESULT_SUCCESS; @@ -330,22 +330,22 @@ PalResult PAL_CALL createSwapchainVk( void PAL_CALL destroySwapchainVk(PalSwapchain* swapchain) { - SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; - vkSwapchain->device->destroySwapchain( - vkSwapchain->device->handle, - vkSwapchain->handle, - &s_Vk.vkAllocator); - - palFree(s_Vk.allocator, vkSwapchain->images); - palFree(s_Vk.allocator, vkSwapchain); + SwapchainVk* swapchainImpl = (SwapchainVk*)swapchain; + swapchainImpl->device->destroySwapchain( + swapchainImpl->device->handle, + swapchainImpl->handle, + &s_Vk.allocatorImpl); + + palFree(s_Vk.allocator, swapchainImpl->images); + palFree(s_Vk.allocator, swapchainImpl); } PalImage* PAL_CALL getSwapchainImageVk( PalSwapchain* swapchain, uint32_t index) { - SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; - return (PalImage*)&vkSwapchain->images[index]; + SwapchainVk* swapchainImpl = (SwapchainVk*)swapchain; + return (PalImage*)&swapchainImpl->images[index]; } PalResult PAL_CALL getNextSwapchainImageVk( @@ -358,16 +358,16 @@ PalResult PAL_CALL getNextSwapchainImageVk( uint64_t timeInNanoseconds = 0; VkFence fenceHandle = nullptr; VkSemaphore semaphoreHandle = nullptr; - SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; + SwapchainVk* swapchainImpl = (SwapchainVk*)swapchain; if (info->fence) { - FenceVk* vkFence = (FenceVk*)info->fence; - fenceHandle = vkFence->handle; + FenceVk* fenceImpl = (FenceVk*)info->fence; + fenceHandle = fenceImpl->handle; } if (info->signalSemaphore) { - SemaphoreVk* vkSemaphore = (SemaphoreVk*)info->signalSemaphore; - semaphoreHandle = vkSemaphore->handle; + SemaphoreVk* semaphoreImpl = (SemaphoreVk*)info->signalSemaphore; + semaphoreHandle = semaphoreImpl->handle; } if (info->timeout) { @@ -378,9 +378,9 @@ PalResult PAL_CALL getNextSwapchainImageVk( } } - result = vkSwapchain->device->acquireNextImage( - vkSwapchain->device->handle, - vkSwapchain->handle, + result = swapchainImpl->device->acquireNextImage( + swapchainImpl->device->handle, + swapchainImpl->handle, timeInNanoseconds, semaphoreHandle, fenceHandle, @@ -399,12 +399,12 @@ PalResult PAL_CALL presentSwapchainVk( uint32_t imageIndex, PalSemaphore* waitSemaphore) { - SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; + SwapchainVk* swapchainImpl = (SwapchainVk*)swapchain; int32_t semaphoreCount = 0; VkSemaphore semaphoreHandle = nullptr; if (waitSemaphore) { - SemaphoreVk* vkSemaphore = (SemaphoreVk*)waitSemaphore; - semaphoreHandle = vkSemaphore->handle; + SemaphoreVk* semaphoreImpl = (SemaphoreVk*)waitSemaphore; + semaphoreHandle = semaphoreImpl->handle; semaphoreCount = 1; } @@ -412,12 +412,13 @@ PalResult PAL_CALL presentSwapchainVk( VkPresentInfoKHR presentInfo = {0}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &vkSwapchain->handle; + presentInfo.pSwapchains = &swapchainImpl->handle; presentInfo.pImageIndices = &imageIndex; presentInfo.pWaitSemaphores = &semaphoreHandle; presentInfo.waitSemaphoreCount = semaphoreCount; - result = vkSwapchain->device->queuePresent(vkSwapchain->queue->phyQueue->handle, &presentInfo); + result = + swapchainImpl->device->queuePresent(swapchainImpl->queue->phyQueue->handle, &presentInfo); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -431,9 +432,9 @@ PalResult PAL_CALL resizeSwapchainVk( uint32_t newHeight) { VkResult result; - SwapchainVk* vkSwapchain = (SwapchainVk*)swapchain; - VkSwapchainKHR oldSwapchain = vkSwapchain->handle; - DeviceVk* device = vkSwapchain->device; + SwapchainVk* swapchainImpl = (SwapchainVk*)swapchain; + VkSwapchainKHR oldSwapchain = swapchainImpl->handle; + DeviceVk* device = swapchainImpl->device; VkImage* images = nullptr; VkSwapchainCreateInfoKHR createInfo = {0}; @@ -445,24 +446,24 @@ PalResult PAL_CALL resizeSwapchainVk( result = device->createSwapchain( device->handle, &createInfo, - &s_Vk.vkAllocator, - &vkSwapchain->handle); + &s_Vk.allocatorImpl, + &swapchainImpl->handle); if (result != VK_SUCCESS) { return makeResultVk(result); } - uint32_t count = vkSwapchain->imageCount; + uint32_t count = swapchainImpl->imageCount; images = palAllocate(s_Vk.allocator, sizeof(VkImage) * count, 0); if (!images) { return PAL_RESULT_CODE_OUT_OF_MEMORY; } - device->destroySwapchain(device->handle, oldSwapchain, &s_Vk.vkAllocator); - device->getSwapchainImages(device->handle, vkSwapchain->handle, &count, images); + device->destroySwapchain(device->handle, oldSwapchain, &s_Vk.allocatorImpl); + device->getSwapchainImages(device->handle, swapchainImpl->handle, &count, images); // fill all images with the new create info for (int i = 0; i < count; i++) { - ImageVk* image = &vkSwapchain->images[i]; + ImageVk* image = &swapchainImpl->images[i]; image->handle = images[i]; image->info.height = createInfo.imageExtent.height; image->info.width = createInfo.imageExtent.width; diff --git a/src/graphics/vulkan/pal_sync_vulkan.c b/src/graphics/vulkan/pal_sync_vulkan.c index 65203bc2..f78c6bda 100644 --- a/src/graphics/vulkan/pal_sync_vulkan.c +++ b/src/graphics/vulkan/pal_sync_vulkan.c @@ -15,7 +15,7 @@ PalResult PAL_CALL createFenceVk( { VkResult result; FenceVk* fence = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; fence = palAllocate(s_Vk.allocator, sizeof(FenceVk), 0); if (!fence) { @@ -28,29 +28,29 @@ PalResult PAL_CALL createFenceVk( createInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; } - result = s_Vk.createFence(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &fence->handle); + result = s_Vk.createFence(deviceImpl->handle, &createInfo, &s_Vk.allocatorImpl, &fence->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, fence); return makeResultVk(result); } - fence->device = vkDevice; + fence->device = deviceImpl; *outFence = (PalFence*)fence; return PAL_RESULT_SUCCESS; } void PAL_CALL destroyFenceVk(PalFence* fence) { - FenceVk* vkFence = (FenceVk*)fence; - s_Vk.destroyFence(vkFence->device->handle, vkFence->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkFence); + FenceVk* fenceImpl = (FenceVk*)fence; + s_Vk.destroyFence(fenceImpl->device->handle, fenceImpl->handle, &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, fenceImpl); } PalResult PAL_CALL waitFenceVk( PalFence* fence, uint64_t timeout) { - FenceVk* vkFence = (FenceVk*)fence; + FenceVk* fenceImpl = (FenceVk*)fence; VkResult result; uint64_t timeInNano = 0; if (timeout) { @@ -61,7 +61,7 @@ PalResult PAL_CALL waitFenceVk( } } - result = s_Vk.waitFence(vkFence->device->handle, 1, &vkFence->handle, PAL_TRUE, timeInNano); + result = s_Vk.waitFence(fenceImpl->device->handle, 1, &fenceImpl->handle, PAL_TRUE, timeInNano); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -71,8 +71,8 @@ PalResult PAL_CALL waitFenceVk( PalResult PAL_CALL resetFenceVk(PalFence* fence) { - FenceVk* vkFence = (FenceVk*)fence; - VkResult result = s_Vk.resetFence(vkFence->device->handle, 1, &vkFence->handle); + FenceVk* fenceImpl = (FenceVk*)fence; + VkResult result = s_Vk.resetFence(fenceImpl->device->handle, 1, &fenceImpl->handle); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -82,8 +82,8 @@ PalResult PAL_CALL resetFenceVk(PalFence* fence) PalBool PAL_CALL isFenceSignaledVk(PalFence* fence) { - FenceVk* vkFence = (FenceVk*)fence; - VkResult result = s_Vk.isFenceSignaled(vkFence->device->handle, vkFence->handle); + FenceVk* fenceImpl = (FenceVk*)fence; + VkResult result = s_Vk.isFenceSignaled(fenceImpl->device->handle, fenceImpl->handle); if (result == VK_SUCCESS) { return PAL_TRUE; @@ -99,7 +99,7 @@ PalResult PAL_CALL createSemaphoreVk( { VkResult result; SemaphoreVk* semaphore = nullptr; - DeviceVk* vkDevice = (DeviceVk*)device; + DeviceVk* deviceImpl = (DeviceVk*)device; semaphore = palAllocate(s_Vk.allocator, sizeof(SemaphoreVk), 0); if (!semaphore) { @@ -121,24 +121,30 @@ PalResult PAL_CALL createSemaphoreVk( } createInfo.pNext = next; - result = - s_Vk.createSemaphore(vkDevice->handle, &createInfo, &s_Vk.vkAllocator, &semaphore->handle); + result = s_Vk.createSemaphore( + deviceImpl->handle, + &createInfo, + &s_Vk.allocatorImpl, + &semaphore->handle); if (result != VK_SUCCESS) { palFree(s_Vk.allocator, semaphore); return makeResultVk(result); } - semaphore->device = vkDevice; + semaphore->device = deviceImpl; *outSemaphore = (PalSemaphore*)semaphore; return PAL_RESULT_SUCCESS; } void PAL_CALL destroySemaphoreVk(PalSemaphore* semaphore) { - SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; - s_Vk.destroySemaphore(vkSemaphore->device->handle, vkSemaphore->handle, &s_Vk.vkAllocator); - palFree(s_Vk.allocator, vkSemaphore); + SemaphoreVk* semaphoreImpl = (SemaphoreVk*)semaphore; + s_Vk.destroySemaphore( + semaphoreImpl->device->handle, + semaphoreImpl->handle, + &s_Vk.allocatorImpl); + palFree(s_Vk.allocator, semaphoreImpl); } PalResult PAL_CALL waitSemaphoreVk( @@ -148,8 +154,8 @@ PalResult PAL_CALL waitSemaphoreVk( { VkResult result; uint64_t timeInNano = 0; - SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; - if (!vkSemaphore->isTimeline) { + SemaphoreVk* semaphoreImpl = (SemaphoreVk*)semaphore; + if (!semaphoreImpl->isTimeline) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } @@ -164,10 +170,11 @@ PalResult PAL_CALL waitSemaphoreVk( VkSemaphoreWaitInfo waitInfo = {0}; waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO; waitInfo.semaphoreCount = 1; - waitInfo.pSemaphores = &vkSemaphore->handle; + waitInfo.pSemaphores = &semaphoreImpl->handle; waitInfo.pValues = &value; - result = vkSemaphore->device->waitSemaphore(vkSemaphore->device->handle, &waitInfo, timeInNano); + result = + semaphoreImpl->device->waitSemaphore(semaphoreImpl->device->handle, &waitInfo, timeInNano); if (result != VK_SUCCESS) { return makeResultVk(result); @@ -182,17 +189,17 @@ PalResult PAL_CALL signalSemaphoreVk( uint64_t value) { VkResult result; - SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; - if (!vkSemaphore->isTimeline) { + SemaphoreVk* semaphoreImpl = (SemaphoreVk*)semaphore; + if (!semaphoreImpl->isTimeline) { return PAL_RESULT_CODE_FEATURE_NOT_SUPPORTED; } VkSemaphoreSignalInfo signalInfo = {0}; signalInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SIGNAL_INFO; - signalInfo.semaphore = vkSemaphore->handle; + signalInfo.semaphore = semaphoreImpl->handle; signalInfo.value = value; - result = vkSemaphore->device->signalSemaphore(vkSemaphore->device->handle, &signalInfo); + result = semaphoreImpl->device->signalSemaphore(semaphoreImpl->device->handle, &signalInfo); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -204,10 +211,10 @@ PalResult PAL_CALL getSemaphoreValueVk( PalSemaphore* semaphore, uint64_t* value) { - SemaphoreVk* vkSemaphore = (SemaphoreVk*)semaphore; - VkResult result = vkSemaphore->device->getSemaphoreValue( - vkSemaphore->device->handle, - vkSemaphore->handle, + SemaphoreVk* semaphoreImpl = (SemaphoreVk*)semaphore; + VkResult result = semaphoreImpl->device->getSemaphoreValue( + semaphoreImpl->device->handle, + semaphoreImpl->handle, value); if (result != VK_SUCCESS) { diff --git a/src/graphics/vulkan/pal_vulkan.c b/src/graphics/vulkan/pal_vulkan.c index f79599f7..5269db87 100644 --- a/src/graphics/vulkan/pal_vulkan.c +++ b/src/graphics/vulkan/pal_vulkan.c @@ -1529,12 +1529,12 @@ PalResult PAL_CALL initGraphicsVk( } // vk allocator - s_Vk.vkAllocator.pfnAllocation = allocateVk; - s_Vk.vkAllocator.pfnFree = freeVk; - s_Vk.vkAllocator.pfnReallocation = reallocVk; + s_Vk.allocatorImpl.pfnAllocation = allocateVk; + s_Vk.allocatorImpl.pfnFree = freeVk; + s_Vk.allocatorImpl.pfnReallocation = reallocVk; VkInstance instance = nullptr; - result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.vkAllocator, &instance); + result = s_Vk.createInstance(&instanceCreateInfo, &s_Vk.allocatorImpl, &instance); if (result != VK_SUCCESS) { return makeResultVk(result); } @@ -1612,7 +1612,7 @@ PalResult PAL_CALL initGraphicsVk( instance, "vkDestroyDebugUtilsMessengerEXT"); - s_Vk.createMessenger(instance, &debugCreateInfo, &s_Vk.vkAllocator, &s_Vk.messenger); + s_Vk.createMessenger(instance, &debugCreateInfo, &s_Vk.allocatorImpl, &s_Vk.messenger); } // clang-format on @@ -1624,10 +1624,10 @@ PalResult PAL_CALL initGraphicsVk( void PAL_CALL shutdownGraphicsVk() { if (s_Vk.messenger) { - s_Vk.destroyMessenger(s_Vk.instance, s_Vk.messenger, &s_Vk.vkAllocator); + s_Vk.destroyMessenger(s_Vk.instance, s_Vk.messenger, &s_Vk.allocatorImpl); } - s_Vk.destroyInstance(s_Vk.instance, &s_Vk.vkAllocator); + s_Vk.destroyInstance(s_Vk.instance, &s_Vk.allocatorImpl); freeLibrary(s_Vk.handle); if (s_Vk.adapters) { palFree(s_Vk.allocator, s_Vk.adapters); diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h index 75f60c4d..3dfda991 100644 --- a/src/graphics/vulkan/pal_vulkan.h +++ b/src/graphics/vulkan/pal_vulkan.h @@ -456,7 +456,7 @@ typedef struct { PalDebugCallback callback; const PalAllocator* allocator; AdapterVk* adapters; - VkAllocationCallbacks vkAllocator; + VkAllocationCallbacks allocatorImpl; } Vulkan; extern Vulkan s_Vk; diff --git a/tests/graphics/custom_backend_test.c b/tests/graphics/custom_backend_test.c index 0cd1132f..86847353 100644 --- a/tests/graphics/custom_backend_test.c +++ b/tests/graphics/custom_backend_test.c @@ -123,6 +123,11 @@ static void PAL_CALL destroyDevice(PalDevice* device) { } +static uint32_t PAL_CALL getDeviceLostReason(PalDevice* device) +{ + return 1; +} + static PalResult PAL_CALL allocateMemory( PalDevice* device, PalMemoryType type, @@ -669,57 +674,90 @@ PalBool customBackendTest() { // build the vtable PalGraphicsBackendVtable1 vtable = {0}; - vtable.enumerateAdapters = enumerateAdapters, vtable.getAdapterInfo = getAdapterInfo, - vtable.getAdapterCapabilities = getAdapterCapabilities, - vtable.getAdapterFeatures = getAdapterFeatures, - vtable.getHighestSupportedShaderTarget = getHighestSupportedShaderTarget, - vtable.createDevice = createDevice, vtable.destroyDevice = destroyDevice, - vtable.allocateMemory = allocateMemory, vtable.freeMemory = freeMemory, - vtable.querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilities, - vtable.createQueue = createQueue, vtable.destroyQueue = destroyQueue, - vtable.waitQueue = waitQueue, vtable.canQueuePresent = canQueuePresent, - vtable.enumerateFormats = enumerateFormats, vtable.isFormatSupported = isFormatSupported, - vtable.queryFormatImageUsages = queryFormatImageUsages, - vtable.queryFormatSampleCount = queryFormatSampleCount, vtable.createImage = createImage, - vtable.destroyImage = destroyImage, vtable.getImageInfo = getImageInfo, - vtable.getImageMemoryRequirements = getImageMemoryRequirements, - vtable.bindImageMemory = bindImageMemory, vtable.createImageView = createImageView, - vtable.destroyImageView = destroyImageView, vtable.createSampler = createSampler, - vtable.destroySampler = destroySampler, vtable.createShader = createShader, - vtable.destroyShader = destroyShader, vtable.createFence = createFence, - vtable.destroyFence = destroyFence, vtable.waitFence = waitFence, - vtable.resetFence = resetFence, vtable.isFenceSignaled = isFenceSignaled, - vtable.createSemaphore = createSemaphore, vtable.destroySemaphore = destroySemaphore, - vtable.createCommandPool = createCommandPool, vtable.destroyCommandPool = destroyCommandPool, - vtable.allocateCommandBuffer = allocateCommandBuffer, - vtable.freeCommandBuffer = freeCommandBuffer, vtable.resetCommandBuffer = resetCommandBuffer, - vtable.submitCommandBuffer = submitCommandBuffer, vtable.cmdBegin = cmdBegin, - vtable.cmdEnd = cmdEnd, vtable.cmdExecuteCommandBuffer = cmdExecuteCommandBuffer, - vtable.cmdBeginRendering = cmdBeginRendering, vtable.cmdEndRendering = cmdEndRendering, - vtable.cmdCopyBuffer = cmdCopyBuffer, vtable.cmdCopyBufferToImage = cmdCopyBufferToImage, - vtable.cmdCopyImage = cmdCopyImage, vtable.cmdCopyImageToBuffer = cmdCopyImageToBuffer, - vtable.cmdBindPipeline = cmdBindPipeline, vtable.cmdSetViewport = cmdSetViewport, - vtable.cmdSetScissors = cmdSetScissors, vtable.cmdBindVertexBuffers = cmdBindVertexBuffers, - vtable.cmdBindIndexBuffer = cmdBindIndexBuffer, vtable.cmdDraw = cmdDraw, - vtable.cmdDrawIndexed = cmdDrawIndexed, vtable.cmdImageBarrier = cmdImageBarrier, - vtable.cmdBufferBarrier = cmdBufferBarrier, vtable.cmdDispatch = cmdDispatch, - vtable.cmdBindDescriptorSet = cmdBindDescriptorSet, vtable.cmdPushConstants = cmdPushConstants, - vtable.createBuffer = createBuffer, vtable.destroyBuffer = destroyBuffer, - vtable.getBufferMemoryRequirements = getBufferMemoryRequirements, - vtable.computeImageStagingRequirements = computeImageStagingRequirements, - vtable.writeImageStaging = writeImageStaging, vtable.bindBufferMemory = bindBufferMemory, - vtable.mapBuffer = mapBuffer, vtable.unmapBuffer = unmapBuffer, - vtable.createDescriptorSetLayout = createDescriptorSetLayout, - vtable.destroyDescriptorSetLayout = destroyDescriptorSetLayout, - vtable.createDescriptorPool = createDescriptorPool, - vtable.destroyDescriptorPool = destroyDescriptorPool, - vtable.resetDescriptorPool = resetDescriptorPool, - vtable.allocateDescriptorSet = allocateDescriptorSet, - vtable.updateDescriptorSet = updateDescriptorSet, - vtable.createPipelineLayout = createPipelineLayout, - vtable.destroyPipelineLayout = destroyPipelineLayout, - vtable.createGraphicsPipeline = createGraphicsPipeline, - vtable.createComputePipeline = createComputePipeline, vtable.destroyPipeline = destroyPipeline; + vtable.enumerateAdapters = enumerateAdapters; + vtable.getAdapterInfo = getAdapterInfo; + vtable.getAdapterCapabilities = getAdapterCapabilities; + vtable.getAdapterFeatures = getAdapterFeatures; + vtable.getHighestSupportedShaderTarget = getHighestSupportedShaderTarget; + vtable.createDevice = createDevice; + vtable.destroyDevice = destroyDevice; + vtable.getDeviceLostReason = getDeviceLostReason; + vtable.allocateMemory = allocateMemory; + vtable.freeMemory = freeMemory; + vtable.querySamplerAnisotropyCapabilities = querySamplerAnisotropyCapabilities; + vtable.createQueue = createQueue; + vtable.destroyQueue = destroyQueue; + vtable.waitQueue = waitQueue; + vtable.canQueuePresent = canQueuePresent; + vtable.enumerateFormats = enumerateFormats; + vtable.isFormatSupported = isFormatSupported; + vtable.queryFormatImageUsages = queryFormatImageUsages; + vtable.queryFormatSampleCount = queryFormatSampleCount; + vtable.createImage = createImage; + vtable.destroyImage = destroyImage; + vtable.getImageInfo = getImageInfo; + vtable.getImageMemoryRequirements = getImageMemoryRequirements; + vtable.bindImageMemory = bindImageMemory; + vtable.createImageView = createImageView; + vtable.destroyImageView = destroyImageView; + vtable.createSampler = createSampler; + vtable.destroySampler = destroySampler; + vtable.createShader = createShader; + vtable.destroyShader = destroyShader; + vtable.createFence = createFence; + vtable.destroyFence = destroyFence; + vtable.waitFence = waitFence; + vtable.resetFence = resetFence; + vtable.isFenceSignaled = isFenceSignaled; + vtable.createSemaphore = createSemaphore; + vtable.destroySemaphore = destroySemaphore; + vtable.createCommandPool = createCommandPool; + vtable.destroyCommandPool = destroyCommandPool; + vtable.allocateCommandBuffer = allocateCommandBuffer; + vtable.freeCommandBuffer = freeCommandBuffer; + vtable.resetCommandBuffer = resetCommandBuffer; + vtable.submitCommandBuffer = submitCommandBuffer; + vtable.cmdBegin = cmdBegin; + vtable.cmdEnd = cmdEnd; + vtable.cmdExecuteCommandBuffer = cmdExecuteCommandBuffer; + vtable.cmdBeginRendering = cmdBeginRendering; + vtable.cmdEndRendering = cmdEndRendering; + vtable.cmdCopyBuffer = cmdCopyBuffer; + vtable.cmdCopyBufferToImage = cmdCopyBufferToImage; + vtable.cmdCopyImage = cmdCopyImage; + vtable.cmdCopyImageToBuffer = cmdCopyImageToBuffer; + vtable.cmdBindPipeline = cmdBindPipeline; + vtable.cmdSetViewport = cmdSetViewport; + vtable.cmdSetScissors = cmdSetScissors; + vtable.cmdBindVertexBuffers = cmdBindVertexBuffers; + vtable.cmdBindIndexBuffer = cmdBindIndexBuffer; + vtable.cmdDraw = cmdDraw; + vtable.cmdDrawIndexed = cmdDrawIndexed; + vtable.cmdImageBarrier = cmdImageBarrier; + vtable.cmdBufferBarrier = cmdBufferBarrier; + vtable.cmdDispatch = cmdDispatch; + vtable.cmdBindDescriptorSet = cmdBindDescriptorSet; + vtable.cmdPushConstants = cmdPushConstants; + vtable.createBuffer = createBuffer; + vtable.destroyBuffer = destroyBuffer; + vtable.getBufferMemoryRequirements = getBufferMemoryRequirements; + vtable.computeImageStagingRequirements = computeImageStagingRequirements; + vtable.writeImageStaging = writeImageStaging; + vtable.bindBufferMemory = bindBufferMemory; + vtable.mapBuffer = mapBuffer; + vtable.unmapBuffer = unmapBuffer; + vtable.createDescriptorSetLayout = createDescriptorSetLayout; + vtable.destroyDescriptorSetLayout = destroyDescriptorSetLayout; + vtable.createDescriptorPool = createDescriptorPool; + vtable.destroyDescriptorPool = destroyDescriptorPool; + vtable.resetDescriptorPool = resetDescriptorPool; + vtable.allocateDescriptorSet = allocateDescriptorSet; + vtable.updateDescriptorSet = updateDescriptorSet; + vtable.createPipelineLayout = createPipelineLayout; + vtable.destroyPipelineLayout = destroyPipelineLayout; + vtable.createGraphicsPipeline = createGraphicsPipeline; + vtable.createComputePipeline = createComputePipeline; + vtable.destroyPipeline = destroyPipeline; PalGraphicsBackendInfo backendInfo = {0}; backendInfo.version = PAL_GRAPHICS_BACKEND_VTABLE_VERSION_1; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 9d39d2ea..aa95e589 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -791,8 +791,8 @@ PalBool rayTracingTest() fclose(file); palUnmapBuffer(stagingBuffer); - palDestroyAccelerationstructure(blas); - palDestroyAccelerationstructure(tlas); + palDestroyAccelerationStructure(blas); + palDestroyAccelerationStructure(tlas); palDestroyFence(fence); palDestroyPipeline(pipeline); diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index 59f26f62..1b2a58e1 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -1761,12 +1761,14 @@ PalBool graphicsABIDump(uint32_t flags) FieldInfo graphicsDebuggerFields[] = { { "userData", {0, 8}, FIELD(PalGraphicsDebugger, userData) }, { "callback", {8, 8}, FIELD(PalGraphicsDebugger, callback) }, - { "denyGeneral", {16, 4}, FIELD(PalGraphicsDebugger, denyGeneral) }, - { "denyValidation", {20, 4}, FIELD(PalGraphicsDebugger, denyValidation) }, - { "denyPerformance", {24, 4}, FIELD(PalGraphicsDebugger, denyPerformance) }, - { "denyInfoSeverity", {28, 4}, FIELD(PalGraphicsDebugger, denyInfoSeverity) }, - { "denyWarningSeverity", {32, 4}, FIELD(PalGraphicsDebugger, denyWarningSeverity) }, - { "denyErrorSeverity", {36, 4}, FIELD(PalGraphicsDebugger, denyErrorSeverity) } + { "enableGPUValidation", {16, 4}, FIELD(PalGraphicsDebugger, enableGPUValidation) }, + { "denyGeneral", {20, 4}, FIELD(PalGraphicsDebugger, denyGeneral) }, + { "denyValidation", {24, 4}, FIELD(PalGraphicsDebugger, denyValidation) }, + { "denyPerformance", {28, 4}, FIELD(PalGraphicsDebugger, denyPerformance) }, + { "denyInfoSeverity", {32, 4}, FIELD(PalGraphicsDebugger, denyInfoSeverity) }, + { "denyWarningSeverity", {36, 4}, FIELD(PalGraphicsDebugger, denyWarningSeverity) }, + { "denyErrorSeverity", {40, 4}, FIELD(PalGraphicsDebugger, denyErrorSeverity) }, + { "reserved", {44, 4}, FIELD(PalGraphicsDebugger, reserved) } }; FieldInfo graphicsBackendInfoFields[] = { @@ -1781,7 +1783,7 @@ PalBool graphicsABIDump(uint32_t flags) graphicsDebugger.fields = graphicsDebuggerFields; graphicsDebugger.fieldCount = ARRAY_SIZE(graphicsDebuggerFields); graphicsDebugger.expected.alignof = 8; - graphicsDebugger.expected.size = 40; + graphicsDebugger.expected.size = 48; graphicsDebugger.expected.padding = 0; graphicsDebugger.actual = STRUCT(PalGraphicsDebugger); From a8b4b12d2c08b1172c5c87a066e5247f6e44ee69 Mon Sep 17 00:00:00 2001 From: nichcode Date: Thu, 23 Jul 2026 16:47:44 +0000 Subject: [PATCH 362/372] update readme --- README.md | 166 +++++---------------------------------------- tests/tests_main.c | 82 +++++++++++----------- 2 files changed, 59 insertions(+), 189 deletions(-) diff --git a/README.md b/README.md index 0ff63484..9c5471b4 100644 --- a/README.md +++ b/README.md @@ -4,158 +4,37 @@ ![Language: C99](https://img.shields.io/badge/language-C99-green.svg) ## Overview +PAL is a lightweight, low-level, explicit cross-platform abstraction layer in C over +platform and graphics APIs with support for modular builds and custom backends. PAL is stateless and transparent. Queries return current state, reflecting changes made through native API calls. -PAL is a lightweight, low-level, cross-platform abstraction layer in **C**, designed to be explicit and as close to the OS as possible similar in philosophy to Vulkan. PAL makes it possible to safely mix native API with its API in a very straight forward way. This is one of the main reasons why PAL exists. +PAL supports Windows and Linux. Both Wayland and X11 are supported on Linux. -PAL is transparent. All queries like window size, position, monitor info reflect the current platform state. Using PAL is like working directly with the OS. PAL applies no hidden logic, makes no assumptions, and leaves behavior fully in your control. - -The goal of PAL is very simple. Write low-level cross-platform code without having per platform files -all over the place. (eg. `renderer_vulkan`, `renderer_d3d12`, `window_win32`, etc). - -This approach gives you total control. You handle events, manage resources, and cache state explicitly. PAL provides the building blocks, how you use them, whether for simple applications or advanced frameworks is entirely up to you. - -Get Window Size -```c -// Direct query from the platform, not cached by PAL -palGetWindowSize(window, &w, &h); -``` -> Note: palGetWindowSize queries the OS directly. If your application needs continuous updates (e.g., window moves or resizes frequently), it is more efficient to listen to PAL events rather than repeatedly querying the OS. This ensures your app stays performant. - ---- - -## Why PAL? - -While libraries like SDL or GLFW focus on simplifying development -through high-level abstractions. **PAL is different:** - -- **Explicit**: You decide how memory, events, and handles are managed. -- **Low Overhead**: PAL is close to raw OS calls, ensuring performance. -- **Modular**: Pick only the subsystems you need (video, event, threading, OpenGL, etc.). -- **Extendable**: Plug in your own backends (event queue, allocator, GPUbackend, etc.). -- **Transparent**: Exposes raw OS handles when you need them. - ---- - -## Quick Start - -Here’s the smallest program that opens a PAL window: - -```c -#include "pal/pal_video.h" - -int main() { - PalEventDriver* driver = nullptr; - PalEventDriverCreateInfo info = {0}; - palCreateEventDriver(&info, &driver); - - palInitVideo(nullptr, driver); - - PalWindow* window = nullptr; - PalWindowCreateInfo w = {0}; - w.width = 640; - w.height = 480; - w.title = "Hello PAL"; - w.show = PAL_TRUE; - palCreateWindow(&w, &window); - - while (1) { - palUpdateVideo(); - PalEvent e; - while (palPollEvent(driver, &e)) { - if (e.type == PAL_EVENT_TYPE_WINDOW_CLOSE) return 0; - } - } -} -``` - -Build and run this, and you’ll get a cross-platform window managed entirely by PAL. - -For more detailed examples, see the [tests folder](./tests) tests folder, which contains full usage scenarios and validation cases. - ---- - -## Philosophy -- PAL is a thin layer over the OS, not a framework or library. -- Queries return the current platform state, reflecting any changes made through direct OS calls. -- Developers are responsible for state tracking, caching, and event handling. -- PAL enables cross-platform consistency while preserving full OS behavior and control. -- Advanced users can build libraries or frameworks on top of PAL. -- Minimal overhead (close to raw OS calls) -- Explicit API (no hidden behavior or defaults) -- Event system supporting both polling and callbacks -- Written in C for easy integration -- Stateless: Opaque handles, no internal caching -- No lowest common denominator: exposes platform capabilities directly -- Modular builds: include only the subsystems you need - ---- - -## Supported Platforms -- Windows (Vista+) -- Linux (X11) -- Linux (Wayland) - -## Planned Platforms -- macOS (Cocoa) -- Android -- iOS - -## Dependencies -- Standard C library -- Platform SDKs (Win32, X11, Cocoa, etc.) -- [Make for Windows](https://www.gnu.org/software/make/) (if not using Visual Studio) -- XRandR (1.2+) for X11 -- libXcursor for X11 - -## Compilers -- GCC -- Clang -- MSVC - ---- +PAL is released under the [Zlib License](https://opensource.org/licenses/Zlib). -## Build +## Building PAL +PAL is written in C99 and uses Premake as its build system. PAL supports Windows Vista and later. PAL can be built with GCC, Clang and MSVC. Configure build options with [pal_config.lua](./pal_config.lua). **true/false** to turn on and off a build option. [pal_config.h](./include/pal/pal_config.h) is the reflection of the systems that will be built. -PAL is written in **C99** and uses Premake as its build system. Configure modules via [pal_config.lua](./pal_config.lua). -See [pal_config.h](./include/pal/pal_config.h) to see the reflection of modules that will be built. +X11 needs XRandR (1.2+) and libXcursor. -**Windows** +### Windows ```bash -premake\premake5.exe gmake # generate Makefiles (default: GCC) -premake\premake5.exe gmake --compiler=clang +premake\premake5.exe gmake # generate Makefiles for GCC +premake\premake5.exe gmake --compiler=clang # generate Makefiles for Clang + +premake\premake5.exe vs2022 # generate Visual Studio 2022 project For MSVC +premake\premake5.exe vs2022 --compiler=clang # generate Visual Studio 2022 project For Clang -premake\premake5.exe vs2022 # generate Visual Studio project (default: MSVC) -premake\premake5.exe vs2022 --compiler=clang +premake\premake5.exe vs2026 # generate Visual Studio 2026 project for MSVC +premake\premake5.exe vs2026 --compiler=clang # generate Visual Studio 2026 project For Clang ``` -**Linux** +### Linux ```bash -./premake/premake5 gmake # generate Makefiles (default: GCC) +./premake/premake5 gmake # generate Makefiles for GCC +./premake/premake5 gmake --compiler=clang # generate Makefiles for Clang ``` -Enable tests in `pal_config.lua` by setting `PAL_BUILD_TEST_APPLICATION = true`. - ---- - -## Modules - -- `pal_core` - memory, log, time, version -- `pal_video` - windows, monitors, mouse, keyboard -- `pal_event` - event queue, event callback -- `pal_thread` - threads, synchronization -- `pal_opengl` - framebuffer configs, context -- `pal_graphics` - Vulkan, D3D12, Metal, Custom - -### Planned Modules -- `pal_network` -- `pal_audio` -- `pal_hid` -- `pal_filesystem` - ---- - ## Documentation - PAL uses [Doxygen](https://www.doxygen.nl/) for generating API documentation. ```bash @@ -165,16 +44,7 @@ doxygen doxyfile The generated HTML docs will be available in `docs/html/`. ---- - ## Contributing - Contributions are welcome! Please open an issue or pull request. See [CONTRIBUTING.md](./.github/CONTRIBUTING.md) for how and what to contribute. Thanks for contributing to PAL. - ---- - -## License - -PAL is released under the [Zlib License](https://opensource.org/licenses/Zlib). diff --git a/tests/tests_main.c b/tests/tests_main.c index 3b22546d..945b964f 100644 --- a/tests/tests_main.c +++ b/tests/tests_main.c @@ -8,70 +8,70 @@ int main(int argc, char** argv) palLog(nullptr, "%s: %s", "PAL Version", palGetVersionString()); // core - // registerTest(loggerTest, "Logger Test"); - // registerTest(timeTest, "Time Test"); + registerTest(loggerTest, "Logger Test"); + registerTest(timeTest, "Time Test"); // event - // registerTest(eventTest, "Event test"); - // registerTest(userEventTest, "User Event Test"); + registerTest(eventTest, "Event test"); + registerTest(userEventTest, "User Event Test"); #if PAL_HAS_SYSTEM_MODULE == 1 - // registerTest(platformTest, "Platform Test"); - // registerTest(cpuTest, "CPU Test"); + registerTest(platformTest, "Platform Test"); + registerTest(cpuTest, "CPU Test"); #endif // PAL_HAS_SYSTEM_MODULE #if PAL_HAS_THREAD_MODULE == 1 - // registerTest(threadTest, "Thread Test"); - // registerTest(tlsTest, "TLS Test"); - // registerTest(mutexTest, "Mutex Test"); - // registerTest(condvarTest, "Condvar Test"); + registerTest(threadTest, "Thread Test"); + registerTest(tlsTest, "TLS Test"); + registerTest(mutexTest, "Mutex Test"); + registerTest(condvarTest, "Condvar Test"); #endif // PAL_HAS_THREAD_MODULE #if PAL_HAS_VIDEO_MODULE == 1 - // registerTest(videoTest, "Video Test"); - // registerTest(monitorTest, "Monitor Test"); - // registerTest(monitorModeTest, "Monitor Mode Test"); - // registerTest(windowTest, "Window Test"); - // registerTest(iconTest, "Icon Test"); - // registerTest(cursorTest, "Cursor Test"); - // registerTest(inputWindowTest, "Input Window Test"); - // registerTest(systemCursorTest, "System Cursor Test"); - // registerTest(attachWindowTest, "Attach Window Test"); - // registerTest(charEventTest, "Char Event Test"); - // registerTest(nativeIntegrationTest, "Native Integration Test"); - // registerTest(nativeInstanceTest, "Native Instance Test"); - // registerTest(customDecorationTest, "Custom Decoration Test"); + registerTest(videoTest, "Video Test"); + registerTest(monitorTest, "Monitor Test"); + registerTest(monitorModeTest, "Monitor Mode Test"); + registerTest(windowTest, "Window Test"); + registerTest(iconTest, "Icon Test"); + registerTest(cursorTest, "Cursor Test"); + registerTest(inputWindowTest, "Input Window Test"); + registerTest(systemCursorTest, "System Cursor Test"); + registerTest(attachWindowTest, "Attach Window Test"); + registerTest(charEventTest, "Char Event Test"); + registerTest(nativeIntegrationTest, "Native Integration Test"); + registerTest(nativeInstanceTest, "Native Instance Test"); + registerTest(customDecorationTest, "Custom Decoration Test"); #endif // PAL_HAS_VIDEO_MODULE // This test can run without video system so long as your have a valid window #if PAL_HAS_OPENGL_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 - // registerTest(openglTest, "Opengl Test"); - // registerTest(openglFBConfigTest, "Opengl FBConfig Test"); - // registerTest(openglContextTest, "Context Test"); - // registerTest(openglMultiContextTest, "Opengl Multi Context Test"); + registerTest(openglTest, "Opengl Test"); + registerTest(openglFBConfigTest, "Opengl FBConfig Test"); + registerTest(openglContextTest, "Context Test"); + registerTest(openglMultiContextTest, "Opengl Multi Context Test"); #endif // PAL_HAS_OPENGL_MODULE #if PAL_HAS_OPENGL_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 && PAL_HAS_THREAD_MODULE == 1 - // registerTest(multiThreadOpenGlTest, "Multi Thread Opengl Test"); -#endif + registerTest(multiThreadOpenGlTest, "Multi Thread Opengl Test"); +#endif // PAL_HAS_OPENGL_MODULE #if PAL_HAS_GRAPHICS_MODULE == 1 registerTest(graphicsTest, "Graphics Test"); - // registerTest(computeTest, "Compute Test"); - // registerTest(rayTracingTest, "Ray Tracing Test"); - // registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); - // registerTest(customBackendTest, "Custom Backend Test"); + registerTest(computeTest, "Compute Test"); + registerTest(rayTracingTest, "Ray Tracing Test"); + registerTest(multiDescriptorSetTest, "Multi Descriptor Set Test"); + registerTest(customBackendTest, "Custom Backend Test"); #endif // PAL_HAS_GRAPHICS_MODULE #if PAL_HAS_GRAPHICS_MODULE == 1 && PAL_HAS_VIDEO_MODULE == 1 && PAL_HAS_SYSTEM_MODULE == 1 - // registerTest(clearColorTest, "Clear Color Test"); - // registerTest(triangleTest, "Triangle Test"); - // registerTest(meshTest, "Mesh Test"); - // registerTest(textureTest, "Texture Test"); - // registerTest(geometryTest, "Geometry Test"); - // registerTest(indirectDrawTest, "Indirect Draw Test"); - // registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); -#endif // + registerTest(clearColorTest, "Clear Color Test"); + registerTest(triangleTest, "Triangle Test"); + registerTest(meshTest, "Mesh Test"); + registerTest(textureTest, "Texture Test"); + registerTest(geometryTest, "Geometry Test"); + registerTest(indirectDrawTest, "Indirect Draw Test"); + registerTest(descriptorIndexingTest, "Descriptor Indexing Test"); +#endif // PAL_HAS_GRAPHICS_MODULE runTests(); return 0; From d1d1aae8ce78e465efc0fbc6aa3f170bc5aeef81 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 24 Jul 2026 08:01:14 +0000 Subject: [PATCH 363/372] change event payload to uint64 --- CHANGELOG.md | 11 +++++-- include/pal/pal_core.h | 64 ++++++++++++++++++++--------------------- include/pal/pal_event.h | 6 ++-- 3 files changed, 43 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f5b7e8f..d9f51773 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,8 +83,15 @@ - `palGetClosestGLFBConfig()` now takes `count` paramter as `uint32_t`. - `palGetMouseWheelDelta()` now takes `dx` and `dy` paramters as `float`. - `palJoinThread()` now takes `retval` paramters as `void**`. -- These function now returns `void` instead of `PalResult` and does not do runtime -validation anymore: invalid arguments, feature not supported results in undefined behavior: +- `palUnpackUint32()` now takes `data` paramters as `uint64_t`. +- `palUnpackInt32()` now takes `data` paramters as `uint64_t`. +- `palUnpackPointer()` now takes `data` paramters as `uint64_t`. +- `palUnpackFloat()` now takes `data` paramters as `uint64_t`. +- `palPackUint32()` now returns `uint64_t` instead of `int64_t`. +- `palPackInt32()` now returns `uint64_t` instead of `int64_t`. +- `palPackPointer()` now returns `uint64_t` instead of `int64_t`. +- `palPackFloat()` now returns `uint64_t` instead of `int64_t`. +- These function now returns `void` instead of `PalResult` and does not do runtime validation anymore: - `palGetPlatformInfo()` - `palGetCPUInfo()` - `palGetThreadName()` diff --git a/include/pal/pal_core.h b/include/pal/pal_core.h index 80c7c4cd..0c3961da 100644 --- a/include/pal/pal_core.h +++ b/include/pal/pal_core.h @@ -411,71 +411,69 @@ static inline PalResult PAL_CALL palMakeResult( } /** - * @brief Combine two 32-bit unsigned integers into a single 64-bit signed - * integer. + * @brief Combine two 32-bit unsigned integers into a single 64-bit unsigned integer. * - * @return The combined 64-bit signed integer. + * @return The combined 64-bit unsigned integer. * * Thread safety: Thread safe. * * @since 1.0 * @sa palUnpackUint32 */ -static inline int64_t PAL_CALL palPackUint32( +static inline uint64_t PAL_CALL palPackUint32( uint32_t low, uint32_t high) { - return (int64_t)(((uint64_t)high << 32) | (uint64_t)low); + return (uint64_t)(((uint64_t)high << 32) | (uint64_t)low); } /** - * @brief Combine two 32-bit signed integers into a single 64-bit signed - * integer. + * @brief Combine two 32-bit signed integers into a single 64-bit unsigned integer. * - * @return The combined 64-bit signed integer. + * @return The combined 64-bit unsigned integer. * * Thread safety: Thread safe. * * @since 1.0 * @sa palUnpackInt32 */ -static inline int64_t PAL_CALL palPackInt32( +static inline uint64_t PAL_CALL palPackInt32( int32_t low, int32_t high) { - return ((int64_t)(uint32_t)high << 32) | (uint32_t)low; + return ((uint64_t)(uint32_t)high << 32) | (uint32_t)low; } /** - * @brief Pack a pointer into a 64-bit signed integer. + * @brief Pack a pointer into a 64-bit unsigned integer. * - * @return The packed 64-bit signed integer. + * @return The packed 64-bit unsigned integer. * * Thread safety: Thread safe. * * @since 1.0 * @sa palUnpackPointer */ -static inline int64_t PAL_CALL palPackPointer(void* ptr) +static inline uint64_t PAL_CALL palPackPointer(void* ptr) { - return (int64_t)(uintptr_t)ptr; + return (uint64_t)(uintptr_t)ptr; } /** - * @brief Combine two floats into a single 64-bit signed integer. + * @brief Combine two floats into a single 64-bit unsigned integer. * - * @return The combined 64-bit signed integer. + * @return The combined 64-bit unsigned integer. * * Thread safety: Thread safe. * * @since 1.3 * @sa palUnpackFloat */ -static inline int64_t PAL_CALL palPackFloat( +static inline uint64_t PAL_CALL palPackFloat( float low, float high) { - int64_t combined = 0; + uint64_t combined = 0; #if PAL_BIG_ENDIAN memcpy(&((uint32_t*)&combined)[0], &high, sizeof(float)); memcpy(&((uint32_t*)&combined)[1], &low, sizeof(float)); @@ -488,10 +486,10 @@ static inline int64_t PAL_CALL palPackFloat( } /** - * @brief Retrieve two 32-bit unsigned integers from a 64-bit signed integer. + * @brief Retrieve two 32-bit unsigned integers from a 64-bit unsigned integer. * - * @param[out] outLow Low value of the 64-bit signed integer. - * @param[out] outHigh High value of the 64-bit signed integer. + * @param[out] outLow Low value of the 64-bit unsigned integer. + * @param[out] outHigh High value of the 64-bit unsigned integer. * * Thread safety: Thread safe. * @@ -499,7 +497,7 @@ static inline int64_t PAL_CALL palPackFloat( * @sa palPackUint32 */ static inline void PAL_CALL palUnpackUint32( - int64_t data, + uint64_t data, uint32_t* outLow, uint32_t* outHigh) { @@ -513,10 +511,10 @@ static inline void PAL_CALL palUnpackUint32( } /** - * @brief Retrieve two 32-bit signed integers from a 64-bit signed integer. + * @brief Retrieve two 32-bit signed integers from a 64-bit unsigned integer. * - * @param[out] outLow Low value of the 64-bit signed integer. - * @param[out] outHigh High value of the 64-bit signed integer. + * @param[out] outLow Low value of the 64-bit unsigned integer. + * @param[out] outHigh High value of the 64-bit unsigned integer. * * Thread safety: Thread-safe if `outLow` and `outHigh` are * thread local. @@ -525,7 +523,7 @@ static inline void PAL_CALL palUnpackUint32( * @sa palPackInt32 */ static inline void PAL_CALL palUnpackInt32( - int64_t data, + uint64_t data, int32_t* outLow, int32_t* outHigh) { @@ -539,25 +537,25 @@ static inline void PAL_CALL palUnpackInt32( } /** - * @brief Unpack a pointer from a 64-bit signed integer. + * @brief Unpack a pointer from a 64-bit unsigned integer. * - * @return The pointer from the 64-bit signed integer. + * @return The pointer from the 64-bit unsigned integer. * * Thread safety: Thread safe. * * @since 1.0 * @sa palPackPointer */ -static inline void* PAL_CALL palUnpackPointer(int64_t data) +static inline void* PAL_CALL palUnpackPointer(uint64_t data) { return (void*)(uintptr_t)data; } /** - * @brief Retrieve two floats from a 64-bit signed integer. + * @brief Retrieve two floats from a 64-bit unsigned integer. * - * @param[out] outLow Low value of the 64-bit signed integer. - * @param[out] outHigh High value of the 64-bit signed integer. + * @param[out] outLow Low value of the 64-bit unsigned integer. + * @param[out] outHigh High value of the 64-bit unsigned integer. * * Thread safety: Thread-safe if `outLow` and `outHigh` are * thread local. @@ -566,7 +564,7 @@ static inline void* PAL_CALL palUnpackPointer(int64_t data) * @sa palPackFloat */ static inline void PAL_CALL palUnpackFloat( - int64_t data, + uint64_t data, float* low, float* high) { diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index fac2e276..8c32775f 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -322,9 +322,9 @@ typedef PalBool(PAL_CALL* PalPollFn)( PalEvent* outEvent); struct PalEvent { - int64_t data; /**< First data payload.*/ - int64_t data2; /**< Second data payload.*/ - int32_t userId; /**< You can have user events upto int32_t max.*/ + uint64_t data; /**< First data payload.*/ + uint64_t data2; /**< Second data payload.*/ + uint32_t userId; /**< User event id.*/ PalEventType type; /**< (eg. `PAL_EVENT_TYPE_WINDOW_MOVE`).*/ }; From 807382cead11e06f2d471b97bb56a0f812784f73 Mon Sep 17 00:00:00 2001 From: nichcode Date: Fri, 24 Jul 2026 13:37:16 +0000 Subject: [PATCH 364/372] improve event payloads documentation --- include/pal/pal_event.h | 341 ++++++++++++++++++++++++++-------------- pal_config.lua | 8 +- 2 files changed, 230 insertions(+), 119 deletions(-) diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 8c32775f..3dbe68fa 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -21,201 +21,312 @@ #define PAL_DECORATION_MODE_COUNT 2 /** - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() + * PAL_EVENT_TYPE_WINDOW_CLOSE + * + * data2: + * window + * + * Helpers: + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_WINDOW_CLOSE 0 /** - * event.data : lower 32 bits = width, upper 32 bits = height - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackUint32() - * - palUnpackPointer() + * PAL_EVENT_TYPE_WINDOW_SIZE + * + * data: + * bits 0-31: width + * bits 32-63: height + * + * data2: + * window + * + * Helpers: + * palUnpackUint32(event.data, &width, &height) + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_WINDOW_SIZE 1 /** - * event.data : lower 32 bits = x, upper 32 bits = y - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackInt32() - * - palUnpackPointer() + * PAL_EVENT_TYPE_WINDOW_MOVE + * + * data: + * bits 0-31: x + * bits 32-63: y + * + * data2: + * window + * + * Helpers: + * palUnpackInt32(event.data, &x, &y) + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_WINDOW_MOVE 2 /** - * event.data : state(minimized, maximized, restored). - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() + * PAL_EVENT_TYPE_WINDOW_STATE + * + * data: + * bits 0-31: state (minimized, maximized, restored). + * bits 32-63: unused + * + * data2: + * window + * + * Helpers: + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_WINDOW_STATE 3 /** - * event.data : `PAL_TRUE` for focus gained or `PAL_FALSE` for focus lost. - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() + * PAL_EVENT_TYPE_WINDOW_FOCUS + * + * data: + * bits 0-31: focus gained (`PAL_TRUE`/`PAL_FALSE`). + * bits 32-63: unused + * + * data2: + * window + * + * Helpers: + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_WINDOW_FOCUS 4 /** - * event.data : `PAL_TRUE` for visible or `PAL_FALSE` for hidden. - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() + * PAL_EVENT_TYPE_WINDOW_VISIBILITY + * + * data: + * bits 0-31: visibility (`PAL_TRUE`/`PAL_FALSE`). + * bits 32-63: unused + * + * data2: + * window + * + * Helpers: + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_WINDOW_VISIBILITY 5 /** - * event.data2 : window + * PAL_EVENT_TYPE_WINDOW_MODAL_BEGIN + * + * data2: + * window + * + * Helpers: + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_WINDOW_MODAL_BEGIN 6 /** - * event.data2 : window + * PAL_EVENT_TYPE_WINDOW_MODAL_END + * + * data2: + * window + * + * Helpers: + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_WINDOW_MODAL_END 7 /** - * event.data2 : window + * PAL_EVENT_TYPE_MONITOR_DPI_CHANGED + * + * data: + * bits 0-31: dpi + * bits 32-63: unused + * + * data2: + * window + * + * Helpers: + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_MONITOR_DPI_CHANGED 8 /** - * event.data2 : window + * PAL_EVENT_TYPE_MONITOR_LIST_CHANGED + * + * data2: + * window + * + * Helpers: + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_MONITOR_LIST_CHANGED 9 /** - * event.data : lower 32 bits = keycode, upper 32 bits = scancode - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackUint32() - * - palUnpackPointer() + * PAL_EVENT_TYPE_KEYDOWN + * + * data: + * bits 0-31: keycode + * bits 32-63: scancode + * + * data2: + * window + * + * Helpers: + * palUnpackUint32(event.data, &keycode, &scancode) + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_KEYDOWN 10 /** - * event.data : lower 32 bits = keycode, upper 32 bits = scancode - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackUint32() - * - palUnpackPointer() + * PAL_EVENT_TYPE_KEYREPEAT + * + * data: + * bits 0-31: keycode + * bits 32-63: scancode + * + * data2: + * window + * + * Helpers: + * palUnpackUint32(event.data, &keycode, &scancode) + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_KEYREPEAT 11 /** - * event.data : lower 32 bits = keycode, upper 32 bits = scancode - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackUint32() - * - palUnpackPointer() + * PAL_EVENT_TYPE_KEYUP + * + * data: + * bits 0-31: keycode + * bits 32-63: scancode + * + * data2: + * window + * + * Helpers: + * palUnpackUint32(event.data, &keycode, &scancode) + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_KEYUP 12 /** - * event.data : lower 32 bits = button, upper 32 bits = serial - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() + * PAL_EVENT_TYPE_MOUSE_BUTTONDOWN + * + * data: + * bits 0-31: button + * bits 32-63: serial + * + * data2: + * window + * + * Helpers: + * palUnpackUint32(event.data, &button, &serial) + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_MOUSE_BUTTONDOWN 13 /** - * event.data : lower 32 bits = button, upper 32 bits = serial - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() + * PAL_EVENT_TYPE_MOUSE_BUTTONUP + * + * data: + * bits 0-31: button + * bits 32-63: serial + * + * data2: + * window + * + * Helpers: + * palUnpackUint32(event.data, &button, &serial) + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_MOUSE_BUTTONUP 14 /** - * event.data : lower 32 bits = x, upper 32 bits = y - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackInt32() - * - palUnpackPointer() + * PAL_EVENT_TYPE_MOUSE_MOVE + * + * data: + * bits 0-31: x + * bits 32-63: y + * + * data2: + * window + * + * Helpers: + * palUnpackInt32(event.data, &x, &y) + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_MOUSE_MOVE 15 /** - * event.data : lower 32 bits = dx, upper 32 bits = dy - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackFloat() - * - palUnpackPointer() + * PAL_EVENT_TYPE_MOUSE_DELTA + * + * data: + * bits 0-31: dx + * bits 32-63: dy + * + * data2: + * window + * + * Helpers: + * palUnpackFloat(event.data, &dx, &dy) + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_MOUSE_DELTA 16 /** - * event.data : lower 32 bits = dx, upper 32 bits = dy - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackFloat() - * - palUnpackPointer() + * PAL_EVENT_TYPE_MOUSE_WHEEL + * + * data: + * bits 0-31: dx + * bits 32-63: dy + * + * data2: + * window + * + * Helpers: + * palUnpackFloat(event.data, &dx, &dy) + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_MOUSE_WHEEL 17 /** - * event.userId : User event ID or type. - * - * Use inline helpers: - * - palPackInt32() - * - palPackUint32() - * - palPackPointer() - * - palUnpackInt32() - * - palUnpackUint32() - * - palUnpackPointer() + * PAL_EVENT_TYPE_USER + * + * userId: + * User event ID or type. + * + * Helpers: + * palPackInt32() + * palPackUint32() + * palPackPointer() + * palUnpackInt32() + * palUnpackUint32() + * palUnpackPointer() */ #define PAL_EVENT_TYPE_USER 18 /** - * event.data : codepoint - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() + * PAL_EVENT_TYPE_KEYCHAR + * + * data: + * bits 0-31: codepoint + * bits 32-63: unused + * + * data2: + * window + * + * Helpers: + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_KEYCHAR 19 /** - * event.data : negotiated decorations mode - * - * event.data2 : window - * - * Use inline helpers: - * - palUnpackPointer() + * PAL_EVENT_TYPE_WINDOW_DECORATION_MODE + * + * data: + * bits 0-31: decorations mode + * bits 32-63: unused + * + * data2: + * window + * + * Helpers: + * window = palUnpackPointer(event.data2) */ #define PAL_EVENT_TYPE_WINDOW_DECORATION_MODE 20 diff --git a/pal_config.lua b/pal_config.lua index 821efe2d..ed26914e 100644 --- a/pal_config.lua +++ b/pal_config.lua @@ -9,16 +9,16 @@ PAL_BUILD_TEST_APPLICATION = true PAL_BUILD_ABI_DUMP = true -- build system module -PAL_BUILD_SYSTEM_MODULE = false +PAL_BUILD_SYSTEM_MODULE = true -- build thread module -PAL_BUILD_THREAD_MODULE = false +PAL_BUILD_THREAD_MODULE = true -- build video module -PAL_BUILD_VIDEO_MODULE = false +PAL_BUILD_VIDEO_MODULE = true -- build opengl module -PAL_BUILD_OPENGL_MODULE = false +PAL_BUILD_OPENGL_MODULE = true -- build graphics module PAL_BUILD_GRAPHICS_MODULE = true From 7a4468e1956177860c19145a40c118b0de94a6a6 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 25 Jul 2026 10:58:03 +0000 Subject: [PATCH 365/372] add homepage.md file --- README.md | 67 +++++++++++++++++++---- docs/Doxyfile | 4 +- docs/homepage.md | 11 ++++ include/pal/pal_event.h | 116 ++++++++++++++++++++-------------------- 4 files changed, 127 insertions(+), 71 deletions(-) create mode 100644 docs/homepage.md diff --git a/README.md b/README.md index 9c5471b4..704b51a7 100644 --- a/README.md +++ b/README.md @@ -5,33 +5,78 @@ ## Overview PAL is a lightweight, low-level, explicit cross-platform abstraction layer in C over -platform and graphics APIs with support for modular builds and custom backends. PAL is stateless and transparent. Queries return current state, reflecting changes made through native API calls. +platform and graphics APIs with support for modular builds and custom backends. +PAL is stateless and transparent. Queries return current state, +reflecting changes made through native API calls. -PAL supports Windows and Linux. Both Wayland and X11 are supported on Linux. +PAL supports Windows, Linux, Vulkan and D3D12. Both Wayland and X11 are supported on Linux. PAL is released under the [Zlib License](https://opensource.org/licenses/Zlib). ## Building PAL -PAL is written in C99 and uses Premake as its build system. PAL supports Windows Vista and later. PAL can be built with GCC, Clang and MSVC. Configure build options with [pal_config.lua](./pal_config.lua). **true/false** to turn on and off a build option. [pal_config.h](./include/pal/pal_config.h) is the reflection of the systems that will be built. +PAL is written in C99 and uses Premake as its build system. PAL supports Windows Vista and later. PAL can be built with GCC, Clang and MSVC. Build options are configure with [pal_config.lua](./pal_config.lua). `true` to enable or `false` to disable a build option. It is recommended to not disable `PAL_BUILD_ABI_DUMP` build option. [pal_config.h](./include/pal/pal_config.h) is the reflection of the systems that will be built. X11 needs XRandR (1.2+) and libXcursor. +See below on how to generate project files for each compiler and toolset. PAL generates **.vscode** folder when generating GNU Make projects. + ### Windows +GNU Make (GCC): +```bash +premake\premake5.exe gmake +``` + +GNU Make (Clang): +```bash +premake\premake5.exe gmake --compiler=clang +``` + +Visual Studio 2022 (MSVC) +```bash +premake\premake5.exe vs2022 +``` + +Visual Studio 2022 (Clang) +```bash +premake\premake5.exe vs2022 --compiler=clang +``` + +Visual Studio 2026 (MSVC) ```bash -premake\premake5.exe gmake # generate Makefiles for GCC -premake\premake5.exe gmake --compiler=clang # generate Makefiles for Clang +premake\premake5.exe vs2026 +``` + +Visual Studio 2026 (Clang) +```bash +premake\premake5.exe vs2026 --compiler=clang +``` -premake\premake5.exe vs2022 # generate Visual Studio 2022 project For MSVC -premake\premake5.exe vs2022 --compiler=clang # generate Visual Studio 2022 project For Clang +### Linux +GNU Make (GCC): +```bash +./premake/premake5 gmake +``` -premake\premake5.exe vs2026 # generate Visual Studio 2026 project for MSVC -premake\premake5.exe vs2026 --compiler=clang # generate Visual Studio 2026 project For Clang +GNU Make (Clang): +```bash +./premake/premake5 gmake --compiler=clang +``` + +## Verify PAL ABI +If the ABI dump tool was enabled when geenrating the projects, build the project and run the command below to verify that your C99 compiler conforms to the PAL ABI. The command below use the release build. Replace **Release** with **Debug** if using debug build. + +### Windows +```bash +cd bin +cd Release +abi-dump.exe --quick ``` ### Linux ```bash -./premake/premake5 gmake # generate Makefiles for GCC -./premake/premake5 gmake --compiler=clang # generate Makefiles for Clang +cd bin +cd Release +./abi-dump --quick ``` ## Documentation diff --git a/docs/Doxyfile b/docs/Doxyfile index 812f0ffc..0c60d3c4 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -991,7 +991,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ../include/pal +INPUT = ../include/pal homepage.md # This tag can be used to specify the character encoding of the source files # that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses @@ -1157,7 +1157,7 @@ FILTER_SOURCE_PATTERNS = # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the Doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = homepage.md # If the IMPLICIT_DIR_DOCS tag is set to YES, any README.md file found in sub- # directories of the project's root, is used as the documentation for that sub- diff --git a/docs/homepage.md b/docs/homepage.md new file mode 100644 index 00000000..bb0787cd --- /dev/null +++ b/docs/homepage.md @@ -0,0 +1,11 @@ + +# Prime Abstraction Layer + +PAL is a lightweight, low-level, explicit cross-platform abstraction layer in C over +platform and graphics APIs with support for modular builds and custom backends. +PAL is stateless and transparent. Queries return current state, +reflecting changes made through native API calls. + +PAL supports Windows, Linux, Vulkan and D3D12. Both Wayland and X11 are supported on Linux. + +PAL is released under the [Zlib License](https://opensource.org/licenses/Zlib). \ No newline at end of file diff --git a/include/pal/pal_event.h b/include/pal/pal_event.h index 3dbe68fa..1eab8ced 100644 --- a/include/pal/pal_event.h +++ b/include/pal/pal_event.h @@ -22,10 +22,10 @@ /** * PAL_EVENT_TYPE_WINDOW_CLOSE - * + * * data2: * window - * + * * Helpers: * window = palUnpackPointer(event.data2) */ @@ -33,14 +33,14 @@ /** * PAL_EVENT_TYPE_WINDOW_SIZE - * + * * data: * bits 0-31: width * bits 32-63: height - * + * * data2: * window - * + * * Helpers: * palUnpackUint32(event.data, &width, &height) * window = palUnpackPointer(event.data2) @@ -49,14 +49,14 @@ /** * PAL_EVENT_TYPE_WINDOW_MOVE - * + * * data: * bits 0-31: x * bits 32-63: y - * + * * data2: * window - * + * * Helpers: * palUnpackInt32(event.data, &x, &y) * window = palUnpackPointer(event.data2) @@ -65,14 +65,14 @@ /** * PAL_EVENT_TYPE_WINDOW_STATE - * + * * data: * bits 0-31: state (minimized, maximized, restored). * bits 32-63: unused - * + * * data2: * window - * + * * Helpers: * window = palUnpackPointer(event.data2) */ @@ -80,14 +80,14 @@ /** * PAL_EVENT_TYPE_WINDOW_FOCUS - * + * * data: * bits 0-31: focus gained (`PAL_TRUE`/`PAL_FALSE`). * bits 32-63: unused - * + * * data2: * window - * + * * Helpers: * window = palUnpackPointer(event.data2) */ @@ -95,14 +95,14 @@ /** * PAL_EVENT_TYPE_WINDOW_VISIBILITY - * + * * data: * bits 0-31: visibility (`PAL_TRUE`/`PAL_FALSE`). * bits 32-63: unused - * + * * data2: * window - * + * * Helpers: * window = palUnpackPointer(event.data2) */ @@ -110,10 +110,10 @@ /** * PAL_EVENT_TYPE_WINDOW_MODAL_BEGIN - * + * * data2: * window - * + * * Helpers: * window = palUnpackPointer(event.data2) */ @@ -121,10 +121,10 @@ /** * PAL_EVENT_TYPE_WINDOW_MODAL_END - * + * * data2: * window - * + * * Helpers: * window = palUnpackPointer(event.data2) */ @@ -132,14 +132,14 @@ /** * PAL_EVENT_TYPE_MONITOR_DPI_CHANGED - * + * * data: * bits 0-31: dpi * bits 32-63: unused - * + * * data2: * window - * + * * Helpers: * window = palUnpackPointer(event.data2) */ @@ -147,10 +147,10 @@ /** * PAL_EVENT_TYPE_MONITOR_LIST_CHANGED - * + * * data2: * window - * + * * Helpers: * window = palUnpackPointer(event.data2) */ @@ -158,14 +158,14 @@ /** * PAL_EVENT_TYPE_KEYDOWN - * + * * data: * bits 0-31: keycode * bits 32-63: scancode - * + * * data2: * window - * + * * Helpers: * palUnpackUint32(event.data, &keycode, &scancode) * window = palUnpackPointer(event.data2) @@ -174,14 +174,14 @@ /** * PAL_EVENT_TYPE_KEYREPEAT - * + * * data: * bits 0-31: keycode * bits 32-63: scancode - * + * * data2: * window - * + * * Helpers: * palUnpackUint32(event.data, &keycode, &scancode) * window = palUnpackPointer(event.data2) @@ -190,14 +190,14 @@ /** * PAL_EVENT_TYPE_KEYUP - * + * * data: * bits 0-31: keycode * bits 32-63: scancode - * + * * data2: * window - * + * * Helpers: * palUnpackUint32(event.data, &keycode, &scancode) * window = palUnpackPointer(event.data2) @@ -206,14 +206,14 @@ /** * PAL_EVENT_TYPE_MOUSE_BUTTONDOWN - * + * * data: * bits 0-31: button * bits 32-63: serial - * + * * data2: * window - * + * * Helpers: * palUnpackUint32(event.data, &button, &serial) * window = palUnpackPointer(event.data2) @@ -222,14 +222,14 @@ /** * PAL_EVENT_TYPE_MOUSE_BUTTONUP - * + * * data: * bits 0-31: button * bits 32-63: serial - * + * * data2: * window - * + * * Helpers: * palUnpackUint32(event.data, &button, &serial) * window = palUnpackPointer(event.data2) @@ -238,14 +238,14 @@ /** * PAL_EVENT_TYPE_MOUSE_MOVE - * + * * data: * bits 0-31: x * bits 32-63: y - * + * * data2: * window - * + * * Helpers: * palUnpackInt32(event.data, &x, &y) * window = palUnpackPointer(event.data2) @@ -254,14 +254,14 @@ /** * PAL_EVENT_TYPE_MOUSE_DELTA - * + * * data: * bits 0-31: dx * bits 32-63: dy - * + * * data2: * window - * + * * Helpers: * palUnpackFloat(event.data, &dx, &dy) * window = palUnpackPointer(event.data2) @@ -270,14 +270,14 @@ /** * PAL_EVENT_TYPE_MOUSE_WHEEL - * + * * data: * bits 0-31: dx * bits 32-63: dy - * + * * data2: * window - * + * * Helpers: * palUnpackFloat(event.data, &dx, &dy) * window = palUnpackPointer(event.data2) @@ -286,10 +286,10 @@ /** * PAL_EVENT_TYPE_USER - * + * * userId: * User event ID or type. - * + * * Helpers: * palPackInt32() * palPackUint32() @@ -302,14 +302,14 @@ /** * PAL_EVENT_TYPE_KEYCHAR - * + * * data: * bits 0-31: codepoint * bits 32-63: unused - * + * * data2: * window - * + * * Helpers: * window = palUnpackPointer(event.data2) */ @@ -317,14 +317,14 @@ /** * PAL_EVENT_TYPE_WINDOW_DECORATION_MODE - * + * * data: * bits 0-31: decorations mode * bits 32-63: unused - * + * * data2: * window - * + * * Helpers: * window = palUnpackPointer(event.data2) */ From 3a8055025e79f462a0107ca8e344a78d311def46 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 25 Jul 2026 19:36:06 +0000 Subject: [PATCH 366/372] add pull request reference --- CHANGELOG.md | 122 +++--- src/core/pal_result.h | 16 +- src/event/pal_default_queue.h | 2 +- src/graphics/d3d12/pal_d3d12.h | 14 +- src/graphics/pal_linear_allocator.h | 4 +- src/graphics/vulkan/pal_vulkan.h | 78 ++-- src/opengl/egl/pal_egl.h | 6 +- src/opengl/pal_opengl_backends.h | 2 +- src/video/wayland/pal_wayland.h | 10 +- src/video/wayland/pal_wayland_protocols.h | 494 ++++++++++------------ src/video/x11/pal_x11.h | 2 +- 11 files changed, 359 insertions(+), 391 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d9f51773..24903cf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,12 @@ ### Features -- Added a graphics system API (`pal_graphics.h`). -- Added `palGetResultCode()` to get the result code from a result value. -- Added `palGetResultSource()` to get the result source from a result value. -- Added `palGetResultNativeCode()` to get the result native code from a result value. -- Added `palGetSupportedGLAPIs()` to check supported opengl api types. -- Added type `PalResultCode` with values: +- Added a graphics system API (`pal_graphics.h`). (#4) +- Added `palGetResultCode()` to get the result code from a result value. (#4) +- Added `palGetResultSource()` to get the result source from a result value. (#4) +- Added `palGetResultNativeCode()` to get the result native code from a result value. (#4) +- Added `palGetSupportedGLAPIs()` to check supported opengl api types. (#4) +- Added type `PalResultCode` with values: (#4) - `PAL_RESULT_CODE_INVALID_ARGUMENT` - `PAL_RESULT_CODE_OUT_OF_MEMORY` - `PAL_RESULT_CODE_PLATFORM_FAILURE` @@ -22,7 +22,7 @@ - `PAL_RESULT_CODE_INVALID_OPERATION` - `PAL_RESULT_CODE_DEVICE_LOST` - `PAL_RESULT_CODE_OUT_OF_DATE` -- Added type `PalResultSource` with values: +- Added type `PalResultSource` with values: (#4) - `PAL_RESULT_SOURCE_NONE` - `PAL_RESULT_SOURCE_WIN32` - `PAL_RESULT_SOURCE_POSIX` @@ -30,68 +30,68 @@ - `PAL_RESULT_SOURCE_VULKAN` - `PAL_RESULT_SOURCE_D3D12` - `PAL_RESULT_SOURCE_METAL` -- Added type `PalGLBackend` with values: +- Added type `PalGLBackend` with values: (#4) - `PAL_GL_BACKEND_EGL` - `PAL_GL_BACKEND_GLX` - `PAL_GL_BACKEND_WGL` -- Added type `PalGLAPI` with values: +- Added type `PalGLAPI` with values: (#4) - `PAL_GL_API_OPENGL` - `PAL_GL_API_OPENGL_ES` -- Added `_COUNT` constants to all type groups (eg. `PAL_EVENT_TYPE_COUNT`). -- Added `PAL_GL_GRAPHICS_CARD_NAME_SIZE`,`PAL_GL_VENDOR_NAME_SIZE` and `PAL_GL_VERSION_NAME_SIZE` constants. +- Added `_COUNT` constants to all type groups (eg. `PAL_EVENT_TYPE_COUNT`). (#4) +- Added `PAL_GL_GRAPHICS_CARD_NAME_SIZE`,`PAL_GL_VENDOR_NAME_SIZE` and `PAL_GL_VERSION_NAME_SIZE` constants. (#4) ### Changes -- `palGetVersion()` now returns `void` and takes a pointer to the struct. -- `palFormatResult()` now takes two additional parameters -- Converted all enum types to fixed-width integer types and their values to standalone constants (eg. `PalResult` to `uint64_t`). -- Removed all previous `PalResult` values except: `PAL_RESULT_SUCCESS` -- Removed `palGLSetInstance()` function. -- Removed `palGLGetBackend()` function. -- Removed `palGetVideoFeaturesEx()` function and `PalVideoFeatures64` enum. -- Removed `palGetWindowHandleInfoEx()` function and `PalWindowHandleInfoEX` struct. -- Removed `palGetRawMouseWheelDelta()` function. -- Removed `palSetPreferredInstance()` function. -- Removed `palSetFBConfig()` function. -- Removed `PAL_FBCONFIG_BACKEND_GLES`. -- `palInitGL()` now takes two additional parameters. -- `palEnumerateGLFBConfigs()` no longer takes the `glWindow` and `count` now as `uint32_t` -- `palInitVideo()` now takes an additional parameter. -- `palGetWindowHandleInfo()` now returns `PalResult` and takes a pointer to the struct. -- `PalGLInfo` now has `backend` and `api` fields. -- Renamed `nativeDisplay` to `nativeInstance` in `PalWindowHandleInfo`. -- Renamed `display` to `instance` in `PalGLWindow`. -- `PalWindowHandleInfo` now has `nativeHandle1`, `nativeHandle2` and `nativeHandle3` fields. -- `PalWindowCreateInfo` now has `state`, `appName`, `instanceName`, `fbConfigBackend` and `fbConfigIndex` fields. -- Removed `maximized` and `minimized` in `PalWindowCreateInfo`. -- Removed `UintXX` and `IntXX` types in favor of standard `uintXX_t` and `intXX_t`. -- Removed `_MAX` constants from all type groups (eg. `PAL_EVENT_MAX`). -- Replaced standard `bool` type and `true`/`false` constants with `PalBool` type and `PAL_TRUE`/`PAL_FALSE`. -- Renamed `PalGLRelease` to `PalGLReleaseBehavior`. -- Renamed `palGLGetProcAddress()` to `palGetGLProcAddress()`. -- Renamed event type constants from `PAL_EVENT_**` to `PAL_EVENT_TYPE_**`. -- Renamed dispatch mode constants from `PAL_DISPATCH_**` to `PAL_DISPATCH_MODE_**`. -- Renamed platform type constants from `PAL_PLATFORM_**` to `PAL_PLATFORM_TYPE_**`. -- Renamed platform api type constants from `PAL_PLATFORM_API_**` to `PAL_PLATFORM_API_TYPE_**`. -- Renamed cursor type constants from `PAL_CURSOR_**` to `PAL_CURSOR_TYPE_**`. -- Renamed flash flag constants from `PAL_FLASH_**` to `PAL_FLASH_FLAG_**`. -- Renamed fbConfig backend type constants from `PAL_FBCONFIG_BACKEND_**` to `PAL_FBCONFIG_BACKEND_**`. -- Renamed `PalFlashFlag` to `PalFlashFlags`. -- `palGetMouseDelta()` now takes `dx` and `dy` paramters as `float`. -- `palEnumerateMonitors()` now takes `count` paramter as `uint32_t`. -- `palEnumerateMonitorModes()` now takes `count` paramter as `uint32_t`. -- `palGetClosestGLFBConfig()` now takes `count` paramter as `uint32_t`. -- `palGetMouseWheelDelta()` now takes `dx` and `dy` paramters as `float`. -- `palJoinThread()` now takes `retval` paramters as `void**`. -- `palUnpackUint32()` now takes `data` paramters as `uint64_t`. -- `palUnpackInt32()` now takes `data` paramters as `uint64_t`. -- `palUnpackPointer()` now takes `data` paramters as `uint64_t`. -- `palUnpackFloat()` now takes `data` paramters as `uint64_t`. -- `palPackUint32()` now returns `uint64_t` instead of `int64_t`. -- `palPackInt32()` now returns `uint64_t` instead of `int64_t`. -- `palPackPointer()` now returns `uint64_t` instead of `int64_t`. -- `palPackFloat()` now returns `uint64_t` instead of `int64_t`. -- These function now returns `void` instead of `PalResult` and does not do runtime validation anymore: +- `palGetVersion()` now returns `void` and takes a pointer to the struct. (#4) +- `palFormatResult()` now takes two additional parameters (#4) +- Converted all enum types to fixed-width integer types and their values to standalone constants (eg. `PalResult` to `uint64_t`). (#4) +- Removed all previous `PalResult` values except: `PAL_RESULT_SUCCESS` (#4) +- Removed `palGLSetInstance()` function. (#4) +- Removed `palGLGetBackend()` function. (#4) +- Removed `palGetVideoFeaturesEx()` function and `PalVideoFeatures64` enum. (#4) +- Removed `palGetWindowHandleInfoEx()` function and `PalWindowHandleInfoEX` struct. (#4) +- Removed `palGetRawMouseWheelDelta()` function. (#4) +- Removed `palSetPreferredInstance()` function. (#4) +- Removed `palSetFBConfig()` function. (#4) +- Removed `PAL_FBCONFIG_BACKEND_GLES`. (#4) +- `palInitGL()` now takes two additional parameters. (#4) +- `palEnumerateGLFBConfigs()` no longer takes the `glWindow` and `count` now as `uint32_t` (#4) +- `palInitVideo()` now takes an additional parameter. (#4) +- `palGetWindowHandleInfo()` now returns `PalResult` and takes a pointer to the struct. (#4) +- `PalGLInfo` now has `backend` and `api` fields. (#4) +- Renamed `nativeDisplay` to `nativeInstance` in `PalWindowHandleInfo`. (#4) +- Renamed `display` to `instance` in `PalGLWindow`. (#4) +- `PalWindowHandleInfo` now has `nativeHandle1`, `nativeHandle2` and `nativeHandle3` fields. (#4) +- `PalWindowCreateInfo` now has `state`, `appName`, `instanceName`, `fbConfigBackend` and `fbConfigIndex` fields. (#4) +- Removed `maximized` and `minimized` in `PalWindowCreateInfo`. (#4) +- Removed `UintXX` and `IntXX` types in favor of standard `uintXX_t` and `intXX_t`. (#4) +- Removed `_MAX` constants from all type groups (eg. `PAL_EVENT_MAX`). (#4) +- Replaced standard `bool` type and `true`/`false` constants with `PalBool` type and `PAL_TRUE`/`PAL_FALSE`. (#4) +- Renamed `PalGLRelease` to `PalGLReleaseBehavior`. (#4) +- Renamed `palGLGetProcAddress()` to `palGetGLProcAddress()`. (#4) +- Renamed event type constants from `PAL_EVENT_**` to `PAL_EVENT_TYPE_**`. (#4) +- Renamed dispatch mode constants from `PAL_DISPATCH_**` to `PAL_DISPATCH_MODE_**`. (#4) +- Renamed platform type constants from `PAL_PLATFORM_**` to `PAL_PLATFORM_TYPE_**`. (#4) +- Renamed platform api type constants from `PAL_PLATFORM_API_**` to `PAL_PLATFORM_API_TYPE_**`. (#4) +- Renamed cursor type constants from `PAL_CURSOR_**` to `PAL_CURSOR_TYPE_**`. (#4) +- Renamed flash flag constants from `PAL_FLASH_**` to `PAL_FLASH_FLAG_**`. (#4) +- Renamed fbConfig backend type constants from `PAL_FBCONFIG_BACKEND_**` to `PAL_FBCONFIG_BACKEND_**`. (#4) +- Renamed `PalFlashFlag` to `PalFlashFlags`. (#4) +- `palGetMouseDelta()` now takes `dx` and `dy` paramters as `float`. (#4) +- `palEnumerateMonitors()` now takes `count` paramter as `uint32_t`. (#4) +- `palEnumerateMonitorModes()` now takes `count` paramter as `uint32_t`. (#4) +- `palGetClosestGLFBConfig()` now takes `count` paramter as `uint32_t`. (#4) +- `palGetMouseWheelDelta()` now takes `dx` and `dy` paramters as `float`. (#4) +- `palJoinThread()` now takes `retval` paramters as `void**`. (#4) +- `palUnpackUint32()` now takes `data` paramters as `uint64_t`. (#4) +- `palUnpackInt32()` now takes `data` paramters as `uint64_t`. (#4) +- `palUnpackPointer()` now takes `data` paramters as `uint64_t`. (#4) +- `palUnpackFloat()` now takes `data` paramters as `uint64_t`. (#4) +- `palPackUint32()` now returns `uint64_t` instead of `int64_t`. (#4) +- `palPackInt32()` now returns `uint64_t` instead of `int64_t`. (#4) +- `palPackPointer()` now returns `uint64_t` instead of `int64_t`. (#4) +- `palPackFloat()` now returns `uint64_t` instead of `int64_t`. (#4) +- These function now returns `void` instead of `PalResult` and does not do runtime validation anymore: (#4) - `palGetPlatformInfo()` - `palGetCPUInfo()` - `palGetThreadName()` diff --git a/src/core/pal_result.h b/src/core/pal_result.h index 95d0e3c8..3ed5b28b 100644 --- a/src/core/pal_result.h +++ b/src/core/pal_result.h @@ -106,24 +106,28 @@ static const char* resultSourceToString(PalResult result) return "NONE"; } -static void formatResultMsg(PalResult result, char* buffer, char* msg) +static void formatResultMsg( + PalResult result, + char* buffer, + char* msg) { const char* baseString = resultCodeToString(result); const char* sourceString = resultSourceToString(result); const char* baseDescription = resultCodeToDescription(result); uint32_t nativeCode = palGetResultNativeCode(result); - + const char* description = ""; if (msg) { description = msg; } format( - buffer, - "Source: %s\n PAL Code: %s\n Native Code: 0x%08x\n PAL Description: %s\n Native Description: %s", - sourceString, + buffer, + "Source: %s\n PAL Code: %s\n Native Code: 0x%08x\n PAL Description: %s\n Native " + "Description: %s", + sourceString, baseString, - nativeCode, + nativeCode, baseDescription, description); } diff --git a/src/event/pal_default_queue.h b/src/event/pal_default_queue.h index a755d908..5eabc067 100644 --- a/src/event/pal_default_queue.h +++ b/src/event/pal_default_queue.h @@ -15,7 +15,7 @@ PalEventQueue* createDefaultEventQueue(const PalAllocator* allocator); void destroyDefaultEventQueue( - const PalAllocator* allocator, + const PalAllocator* allocator, PalEventQueue* queue); #endif // _PAL_DEFAULT_QUEUE_H \ No newline at end of file diff --git a/src/graphics/d3d12/pal_d3d12.h b/src/graphics/d3d12/pal_d3d12.h index 750d7150..4dab4a46 100644 --- a/src/graphics/d3d12/pal_d3d12.h +++ b/src/graphics/d3d12/pal_d3d12.h @@ -9,12 +9,12 @@ #define _PAL_D3D12_H #if PAL_HAS_D3D12_BACKEND +#include "graphics/pal_linear_allocator.h" #include "pal/pal_graphics.h" -#include #include -#include #include -#include "graphics/pal_linear_allocator.h" +#include +#include #define MAX_RTV 1024 #define MAX_DSV 512 @@ -29,12 +29,12 @@ #define DESC_TYPE_SRV 2 #define DESC_TYPE_UAV 3 -typedef HRESULT (WINAPI* PFN_CreateDXGIFactory2)( +typedef HRESULT(WINAPI* PFN_CreateDXGIFactory2)( UINT, REFIID, void**); -typedef HRESULT (__stdcall *PFN_D3D12SerializeVersionedRootSignature)( +typedef HRESULT(__stdcall* PFN_D3D12SerializeVersionedRootSignature)( const D3D12_VERSIONED_ROOT_SIGNATURE_DESC*, ID3DBlob**, ID3DBlob**); @@ -389,8 +389,8 @@ void fillBuildInfoD3D12( D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC* buildInfo); void getDescriptorTierLimitsD3D12( - void* device, - PalResourceCapabilities* caps, + void* device, + PalResourceCapabilities* caps, PalDescriptorIndexingCapabilities* descCaps); void fillSubresourceD3D12( diff --git a/src/graphics/pal_linear_allocator.h b/src/graphics/pal_linear_allocator.h index f26a311c..3bd4dd3e 100644 --- a/src/graphics/pal_linear_allocator.h +++ b/src/graphics/pal_linear_allocator.h @@ -19,8 +19,8 @@ typedef struct { } PalLinearAllocator; static void* palLinearAlloc( - PalLinearAllocator* allocator, - uint64_t size, + PalLinearAllocator* allocator, + uint64_t size, uint64_t alignment) { uint64_t defAlign = alignment; diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h index 3dfda991..1baac8eb 100644 --- a/src/graphics/vulkan/pal_vulkan.h +++ b/src/graphics/vulkan/pal_vulkan.h @@ -9,16 +9,16 @@ #define _PAL_VULKAN_H #if PAL_HAS_VULKAN_BACKEND +#include "graphics/pal_linear_allocator.h" #include "pal/pal_graphics.h" #include -#include "graphics/pal_linear_allocator.h" typedef struct _XDisplay Display; typedef unsigned long Window; typedef struct xcb_connection_t xcb_connection_t; typedef uint32_t xcb_window_t; -typedef struct HINSTANCE__ *HINSTANCE; -typedef struct HWND__ *HWND; +typedef struct HINSTANCE__* HINSTANCE; +typedef struct HWND__* HWND; typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; typedef VkFlags VkXlibSurfaceCreateFlagsKHR; @@ -26,59 +26,59 @@ typedef VkFlags VkXcbSurfaceCreateFlagsKHR; typedef VkFlags VkWin32SurfaceCreateFlagsKHR; typedef struct VkWaylandSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkWaylandSurfaceCreateFlagsKHR flags; - struct wl_display* display; - struct wl_surface* surface; + VkStructureType sType; + const void* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display* display; + struct wl_surface* surface; } VkWaylandSurfaceCreateInfoKHR; typedef struct VkXlibSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkXlibSurfaceCreateFlagsKHR flags; - Display* dpy; - Window window; + VkStructureType sType; + const void* pNext; + VkXlibSurfaceCreateFlagsKHR flags; + Display* dpy; + Window window; } VkXlibSurfaceCreateInfoKHR; typedef struct VkXcbSurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkXcbSurfaceCreateFlagsKHR flags; - xcb_connection_t* connection; - xcb_window_t window; + VkStructureType sType; + const void* pNext; + VkXcbSurfaceCreateFlagsKHR flags; + xcb_connection_t* connection; + xcb_window_t window; } VkXcbSurfaceCreateInfoKHR; typedef struct VkWin32SurfaceCreateInfoKHR { - VkStructureType sType; - const void* pNext; - VkWin32SurfaceCreateFlagsKHR flags; - HINSTANCE hinstance; - HWND hwnd; + VkStructureType sType; + const void* pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; } VkWin32SurfaceCreateInfoKHR; -typedef VkResult (VKAPI_PTR *PFN_vkCreateWaylandSurfaceKHR)( - VkInstance, - const VkWaylandSurfaceCreateInfoKHR*, - const VkAllocationCallbacks*, +typedef VkResult(VKAPI_PTR* PFN_vkCreateWaylandSurfaceKHR)( + VkInstance, + const VkWaylandSurfaceCreateInfoKHR*, + const VkAllocationCallbacks*, VkSurfaceKHR*); -typedef VkResult (VKAPI_PTR *PFN_vkCreateXlibSurfaceKHR)( - VkInstance, - const VkXlibSurfaceCreateInfoKHR*, - const VkAllocationCallbacks*, +typedef VkResult(VKAPI_PTR* PFN_vkCreateXlibSurfaceKHR)( + VkInstance, + const VkXlibSurfaceCreateInfoKHR*, + const VkAllocationCallbacks*, VkSurfaceKHR*); -typedef VkResult (VKAPI_PTR *PFN_vkCreateXcbSurfaceKHR)( - VkInstance, - const VkXcbSurfaceCreateInfoKHR*, - const VkAllocationCallbacks*, +typedef VkResult(VKAPI_PTR* PFN_vkCreateXcbSurfaceKHR)( + VkInstance, + const VkXcbSurfaceCreateInfoKHR*, + const VkAllocationCallbacks*, VkSurfaceKHR*); -typedef VkResult (VKAPI_PTR *PFN_vkCreateWin32SurfaceKHR)( - VkInstance, - const VkWin32SurfaceCreateInfoKHR*, - const VkAllocationCallbacks*, +typedef VkResult(VKAPI_PTR* PFN_vkCreateWin32SurfaceKHR)( + VkInstance, + const VkWin32SurfaceCreateInfoKHR*, + const VkAllocationCallbacks*, VkSurfaceKHR*); typedef struct { diff --git a/src/opengl/egl/pal_egl.h b/src/opengl/egl/pal_egl.h index 101791e0..1742204c 100644 --- a/src/opengl/egl/pal_egl.h +++ b/src/opengl/egl/pal_egl.h @@ -38,7 +38,7 @@ typedef void* EGLNativeDisplayType; #define EGL_OPENGL_BIT 0x0008 #define EGL_OPENGL_ES_BIT 0x0001 #define EGL_OPENGL_ES_API 0x30A0 -#define EGL_CLIENT_APIS 0x308D +#define EGL_CLIENT_APIS 0x308D #define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0) #define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0) #define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0) @@ -178,9 +178,9 @@ typedef EGLSurface (*eglCreateWindowSurfaceFn)( const EGLint*); typedef const GLubyte* (*glGetStringFn)(GLenum); -typedef void(*glClearFn)(uint32_t); +typedef void (*glClearFn)(uint32_t); -typedef void(*glClearColorFn)( +typedef void (*glClearColorFn)( float, float, float, diff --git a/src/opengl/pal_opengl_backends.h b/src/opengl/pal_opengl_backends.h index fdb6abd0..3b82f2e8 100644 --- a/src/opengl/pal_opengl_backends.h +++ b/src/opengl/pal_opengl_backends.h @@ -8,8 +8,8 @@ #ifndef _PAL_OPENGL_BACKENDS_H #define _PAL_OPENGL_BACKENDS_H -#include "pal_platform.h" #include "pal/pal_opengl.h" +#include "pal_platform.h" // clang-format off typedef struct { diff --git a/src/video/wayland/pal_wayland.h b/src/video/wayland/pal_wayland.h index fd75ba90..9fed614b 100644 --- a/src/video/wayland/pal_wayland.h +++ b/src/video/wayland/pal_wayland.h @@ -14,14 +14,14 @@ #include "pal/pal_video.h" #include "video/pal_video_egl.h" -#include -#include -#include #include +#include #include #include #include -#include +#include +#include +#include #include #include @@ -171,7 +171,7 @@ typedef struct { int monitorCount; PalWindowState state; PalWindow* window; - + struct xdg_surface* xdgSurface; struct xdg_toplevel* xdgToplevel; struct wl_buffer* buffer; diff --git a/src/video/wayland/pal_wayland_protocols.h b/src/video/wayland/pal_wayland_protocols.h index b14c5b63..2ffb13be 100644 --- a/src/video/wayland/pal_wayland_protocols.h +++ b/src/video/wayland/pal_wayland_protocols.h @@ -16,355 +16,323 @@ // ================================================== static inline void* wlRegistryBind( - struct wl_registry *wl_registry, - uint32_t name, - const struct wl_interface *interface, + struct wl_registry* wl_registry, + uint32_t name, + const struct wl_interface* interface, uint32_t version) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *)wl_registry, - WL_REGISTRY_BIND, - interface, - version, - 0, - name, - interface->name, - version, + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_registry, + WL_REGISTRY_BIND, + interface, + version, + 0, + name, + interface->name, + version, NULL); - return (void *)id; + return (void*)id; } static inline int wlRegistryAddListener( - struct wl_registry *wl_registry, - const struct wl_registry_listener *listener, - void *data) + struct wl_registry* wl_registry, + const struct wl_registry_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_registry, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_registry, (void (**)(void))listener, data); } -static inline struct wl_registry* wlDisplayGetRegistry( - struct wl_display *wl_display) +static inline struct wl_registry* wlDisplayGetRegistry(struct wl_display* wl_display) { - struct wl_proxy *registry; - registry = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_display, + struct wl_proxy* registry; + registry = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_display, 1, // WL_DISPLAY_GET_REGISTRY - s_Wl.registryInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_display), - 0, - NULL); + s_Wl.registryInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_display), + 0, + NULL); - return (struct wl_registry *)registry; + return (struct wl_registry*)registry; } static inline int wlOutputAddListener( - struct wl_output *wl_output, - const struct wl_output_listener *listener, - void *data) + struct wl_output* wl_output, + const struct wl_output_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_output, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_output, (void (**)(void))listener, data); } -static inline struct wl_surface* wlCompositorCreateSurface( - struct wl_compositor *wl_compositor) +static inline struct wl_surface* wlCompositorCreateSurface(struct wl_compositor* wl_compositor) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_compositor, + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_compositor, 0, // WL_COMPOSITOR_CREATE_SURFACE, - s_Wl.surfaceInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_compositor), - 0, - NULL); + s_Wl.surfaceInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_compositor), + 0, + NULL); - return (struct wl_surface*) id; + return (struct wl_surface*)id; } -static inline void wlSurfaceCommit(struct wl_surface *wl_surface) +static inline void wlSurfaceCommit(struct wl_surface* wl_surface) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_surface, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, 6, // WL_SURFACE_COMMIT - NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0); + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0); } -static inline void wlSurfaceDestroy(struct wl_surface *wl_surface) +static inline void wlSurfaceDestroy(struct wl_surface* wl_surface) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_surface, + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, 0, // WL_SURFACE_DESTROY - NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - WL_MARSHAL_FLAG_DESTROY); + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + WL_MARSHAL_FLAG_DESTROY); } static inline struct wl_shm_pool* wlShmCreatePool( - struct wl_shm *wl_shm, - int32_t fd, + struct wl_shm* wl_shm, + int32_t fd, int32_t size) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_shm, + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_shm, 0, // WL_SHM_CREATE_POOL - s_Wl.shmPoolInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_shm), - 0, - NULL, - fd, - size); + s_Wl.shmPoolInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm), + 0, + NULL, + fd, + size); - return (struct wl_shm_pool *) id; + return (struct wl_shm_pool*)id; } -static inline void wlShmPoolDestroy(struct wl_shm_pool *wl_shm_pool) +static inline void wlShmPoolDestroy(struct wl_shm_pool* wl_shm_pool) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_DESTROY, - NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_shm_pool), - WL_MARSHAL_FLAG_DESTROY); + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_shm_pool, + WL_SHM_POOL_DESTROY, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm_pool), + WL_MARSHAL_FLAG_DESTROY); } static inline struct wl_buffer* wlShmPoolCreateBuffer( - struct wl_shm_pool *wl_shm_pool, - int32_t offset, - int32_t width, - int32_t height, - int32_t stride, + struct wl_shm_pool* wl_shm_pool, + int32_t offset, + int32_t width, + int32_t height, + int32_t stride, uint32_t format) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_shm_pool, - WL_SHM_POOL_CREATE_BUFFER, - s_Wl.bufferInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_shm_pool), - 0, - NULL, - offset, - width, - height, - stride, - format); + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_shm_pool, + WL_SHM_POOL_CREATE_BUFFER, + s_Wl.bufferInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_shm_pool), + 0, + NULL, + offset, + width, + height, + stride, + format); - return (struct wl_buffer *) id; + return (struct wl_buffer*)id; } -static inline void wlBufferDestroy(struct wl_buffer *wl_buffer) +static inline void wlBufferDestroy(struct wl_buffer* wl_buffer) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_buffer, - WL_BUFFER_DESTROY, - NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_buffer), - WL_MARSHAL_FLAG_DESTROY); + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_buffer, + WL_BUFFER_DESTROY, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_buffer), + WL_MARSHAL_FLAG_DESTROY); } static inline void wlSurfaceAttach( - struct wl_surface *wl_surface, - struct wl_buffer *buffer, - int32_t x, + struct wl_surface* wl_surface, + struct wl_buffer* buffer, + int32_t x, int32_t y) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_surface, - WL_SURFACE_ATTACH, - NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0, - buffer, - x, - y); + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, + WL_SURFACE_ATTACH, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0, + buffer, + x, + y); } static inline void wlSurfaceDamageBuffer( - struct wl_surface *wl_surface, - int32_t x, - int32_t y, - int32_t width, + struct wl_surface* wl_surface, + int32_t x, + int32_t y, + int32_t width, int32_t height) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_surface, - WL_SURFACE_DAMAGE_BUFFER, - NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0, - x, - y, - width, - height); + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, + WL_SURFACE_DAMAGE_BUFFER, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0, + x, + y, + width, + height); } static inline int wlSurfaceAddListener( - struct wl_surface *wl_surface, - const struct wl_surface_listener *listener, - void *data) + struct wl_surface* wl_surface, + const struct wl_surface_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_surface, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_surface, (void (**)(void))listener, data); } static inline int wlSeatAddListener( - struct wl_seat *wl_seat, - const struct wl_seat_listener *listener, - void *data) + struct wl_seat* wl_seat, + const struct wl_seat_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_seat, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_seat, (void (**)(void))listener, data); } -static inline struct wl_pointer* wlSeatGetPointer(struct wl_seat *wl_seat) +static inline struct wl_pointer* wlSeatGetPointer(struct wl_seat* wl_seat) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_seat, - WL_SEAT_GET_POINTER, - s_Wl.pointerInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_seat), - 0, - NULL); + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_seat, + WL_SEAT_GET_POINTER, + s_Wl.pointerInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_seat), + 0, + NULL); - return (struct wl_pointer *) id; + return (struct wl_pointer*)id; } -static inline struct wl_keyboard* wlSeatGetKeyboard(struct wl_seat *wl_seat) +static inline struct wl_keyboard* wlSeatGetKeyboard(struct wl_seat* wl_seat) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_seat, - WL_SEAT_GET_KEYBOARD, - s_Wl.keyboardInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_seat), - 0, - NULL); + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_seat, + WL_SEAT_GET_KEYBOARD, + s_Wl.keyboardInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_seat), + 0, + NULL); - return (struct wl_keyboard *) id; + return (struct wl_keyboard*)id; } static inline int wlPointerAddListener( - struct wl_pointer *wl_pointer, - const struct wl_pointer_listener *listener, - void *data) + struct wl_pointer* wl_pointer, + const struct wl_pointer_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_pointer, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_pointer, (void (**)(void))listener, data); } static inline void wlPointerSetCursor( - struct wl_pointer *wl_pointer, - uint32_t serial, - struct wl_surface *surface, - int32_t hotspot_x, + struct wl_pointer* wl_pointer, + uint32_t serial, + struct wl_surface* surface, + int32_t hotspot_x, int32_t hotspot_y) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_pointer, - WL_POINTER_SET_CURSOR, - NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_pointer), - 0, - serial, - surface, - hotspot_x, - hotspot_y); + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_pointer, + WL_POINTER_SET_CURSOR, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_pointer), + 0, + serial, + surface, + hotspot_x, + hotspot_y); } static inline int wlKeyboardAddListener( - struct wl_keyboard *wl_keyboard, - const struct wl_keyboard_listener *listener, - void *data) + struct wl_keyboard* wl_keyboard, + const struct wl_keyboard_listener* listener, + void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy *) wl_keyboard, - (void (**)(void)) listener, data); + return s_Wl.proxyAddListener((struct wl_proxy*)wl_keyboard, (void (**)(void))listener, data); } -static inline struct wl_region* wlCompositorCreateRegion( - struct wl_compositor *wl_compositor) +static inline struct wl_region* wlCompositorCreateRegion(struct wl_compositor* wl_compositor) { - struct wl_proxy *id; - id = s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_compositor, - WL_COMPOSITOR_CREATE_REGION, - s_Wl.regionInterface, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_compositor), - 0, - NULL); + struct wl_proxy* id; + id = s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_compositor, + WL_COMPOSITOR_CREATE_REGION, + s_Wl.regionInterface, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_compositor), + 0, + NULL); - return (struct wl_region *) id; + return (struct wl_region*)id; } static inline void wlRegionAdd( - struct wl_region *wl_region, - int32_t x, - int32_t y, - int32_t width, + struct wl_region* wl_region, + int32_t x, + int32_t y, + int32_t width, int32_t height) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_region, - WL_REGION_ADD, - NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_region), - 0, - x, - y, - width, - height); + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_region, + WL_REGION_ADD, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_region), + 0, + x, + y, + width, + height); } static inline void wlSurfaceSetOpaqueRegion( - struct wl_surface *wl_surface, - struct wl_region *region) + struct wl_surface* wl_surface, + struct wl_region* region) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_surface, - WL_SURFACE_SET_OPAQUE_REGION, - NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_surface), - 0, - region); + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_surface, + WL_SURFACE_SET_OPAQUE_REGION, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_surface), + 0, + region); } -static inline void wlRegionDestroy(struct wl_region *wl_region) +static inline void wlRegionDestroy(struct wl_region* wl_region) { - s_Wl.proxyMarshalFlags( - (struct wl_proxy *) wl_region, - WL_REGION_DESTROY, - NULL, - s_Wl.proxyGetVersion( - (struct wl_proxy *) wl_region), - WL_MARSHAL_FLAG_DESTROY); + s_Wl.proxyMarshalFlags( + (struct wl_proxy*)wl_region, + WL_REGION_DESTROY, + NULL, + s_Wl.proxyGetVersion((struct wl_proxy*)wl_region), + WL_MARSHAL_FLAG_DESTROY); } // ================================================== @@ -381,11 +349,17 @@ extern const struct wl_interface xdg_surface_interface; extern const struct wl_interface xdg_toplevel_interface; struct xdg_wm_base_listener { - void (*ping)(void*, struct xdg_wm_base*, uint32_t); + void (*ping)( + void*, + struct xdg_wm_base*, + uint32_t); }; struct xdg_surface_listener { - void (*configure)(void*, struct xdg_surface*, uint32_t); + void (*configure)( + void*, + struct xdg_surface*, + uint32_t); }; struct xdg_toplevel_listener { @@ -415,10 +389,7 @@ static inline int xdgWmBaseAddListener( const struct xdg_wm_base_listener* listener, void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy*)xdg_wm_base, - (void (**)(void))listener, - data); + return s_Wl.proxyAddListener((struct wl_proxy*)xdg_wm_base, (void (**)(void))listener, data); } static inline struct xdg_surface* xdgWmBaseGetXdgSurface( @@ -438,8 +409,7 @@ static inline struct xdg_surface* xdgWmBaseGetXdgSurface( return (struct xdg_surface*)id; } -static inline struct xdg_toplevel* -xdgSurfaceGetToplevel(struct xdg_surface* xdg_surface) +static inline struct xdg_toplevel* xdgSurfaceGetToplevel(struct xdg_surface* xdg_surface) { struct wl_proxy* id; id = s_Wl.proxyMarshalFlags( @@ -471,10 +441,7 @@ static inline int xdgSurfaceAddListener( const struct xdg_surface_listener* listener, void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy*)xdg_surface, - (void (**)(void))listener, - data); + return s_Wl.proxyAddListener((struct wl_proxy*)xdg_surface, (void (**)(void))listener, data); } static inline void xdgSurfaceDestroy(struct xdg_surface* xdg_surface) @@ -535,10 +502,7 @@ static inline int xdgToplevelAddListener( const struct xdg_toplevel_listener* listener, void* data) { - return s_Wl.proxyAddListener( - (struct wl_proxy*)xdg_toplevel, - (void (**)(void))listener, - data); + return s_Wl.proxyAddListener((struct wl_proxy*)xdg_toplevel, (void (**)(void))listener, data); } static inline void xdgToplevelSetMinSize( @@ -611,8 +575,8 @@ struct zxdg_toplevel_decoration_v1_listener { extern const struct wl_interface zxdg_decoration_manager_v1_interface; extern const struct wl_interface zxdg_toplevel_decoration_v1_interface; -static inline void zxdgDecorationManagerV1Destroy( - struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1) +static inline void +zxdgDecorationManagerV1Destroy(struct zxdg_decoration_manager_v1* zxdg_decoration_manager_v1) { s_Wl.proxyMarshalFlags( (struct wl_proxy*)zxdg_decoration_manager_v1, @@ -650,8 +614,8 @@ static inline int zxdgToplevelDecorationV1AddListener( data); } -static inline void zxdgToplevelDecorationV1Destroy( - struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1) +static inline void +zxdgToplevelDecorationV1Destroy(struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1) { s_Wl.proxyMarshalFlags( (struct wl_proxy*)zxdg_toplevel_decoration_v1, diff --git a/src/video/x11/pal_x11.h b/src/video/x11/pal_x11.h index 7849a36a..0a730492 100644 --- a/src/video/x11/pal_x11.h +++ b/src/video/x11/pal_x11.h @@ -505,7 +505,7 @@ typedef struct { PalEventDriver* eventDriver; WindowData* windowData; MonitorData* monitorData; - + XOpenDisplayFn openDisplay; XCloseDisplayFn closeDisplay; XGetWindowAttributesFn getWindowAttributes; From 539c97d6f053f19cb2cd105d1390a596cc340cf4 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sat, 25 Jul 2026 19:41:55 +0000 Subject: [PATCH 367/372] fix formatting issues --- tests/tests.h | 8 ++++++-- tools/abi_dump/dumps.h | 25 +++++++++++++------------ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/tests/tests.h b/tests/tests.h index 7ea250a1..91feb1b7 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -7,7 +7,9 @@ typedef PalBool (*TestFn)(); -void registerTest(TestFn func, const char* name); +void registerTest( + TestFn func, + const char* name); void runTests(); static PalBool readFile( @@ -37,7 +39,9 @@ static PalBool readFile( return PAL_TRUE; } -static inline void logResult(PalResult result, const char* msg) +static inline void logResult( + PalResult result, + const char* msg) { char buffer[256]; palFormatResult(result, 256, buffer); diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 39e0b969..29c8d838 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -53,7 +53,7 @@ typedef struct { typedef struct { const char* name; - FieldInfo* fields; + FieldInfo* fields; uint32_t fieldCount; StructBase expected; StructBase actual; @@ -91,7 +91,7 @@ static PalBool checkABI( } } - fieldSize += 2; // add 6 spaces + fieldSize += 2; // add 6 spaces uint32_t seperatorSize = fieldSize + expectedSize + actualSize + 4; // add 4 spaces for (int i = 0; i < seperatorSize; i++) { seperator[i] = '='; @@ -112,15 +112,15 @@ static PalBool checkABI( palLog(nullptr, "Alignment: (%u, %u)", info->expected.alignof, info->actual.alignof); palLog(nullptr, "Padding: (%02u, %02u)", info->expected.padding, info->actual.padding); palLog(nullptr, seperator); - + palLog( - nullptr, - "%-*s %-*s %-*s", - fieldSize, - "Field", - expectedSize, - "Expected", - actualSize, + nullptr, + "%-*s %-*s %-*s", + fieldSize, + "Field", + expectedSize, + "Expected", + actualSize, "Actual"); palLog(nullptr, seperator); @@ -138,8 +138,9 @@ static PalBool checkABI( // clang-format on if (flags & DUMP_FLAG_VERBOSE) { - palLog(nullptr, - "%-*s (%03u, %03u) (%03u, %03u)", + palLog( + nullptr, + "%-*s (%03u, %03u) (%03u, %03u)", fieldSize, field->name, field->expected.offset, From ef8f31db729cbfa12e7b1de1b0736475e4de9725 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 26 Jul 2026 09:29:08 +0000 Subject: [PATCH 368/372] change since to 2.0.0 --- CHANGELOG.md | 3 +- README.md | 2 + include/{pal => pal2}/pal_core.h | 46 +++---- include/{pal => pal2}/pal_event.h | 34 ++--- include/{pal => pal2}/pal_graphics.h | 0 include/{pal => pal2}/pal_opengl.h | 40 +++--- include/{pal => pal2}/pal_system.h | 16 +-- include/{pal => pal2}/pal_thread.h | 72 +++++----- include/{pal => pal2}/pal_video.h | 150 ++++++++++----------- pal.lua | 2 +- src/core/pal_format.h | 2 +- src/core/pal_version.c | 2 +- src/core/posix/pal_memory_posix.c | 2 +- src/core/posix/pal_time_posix.c | 2 +- src/core/win32/pal_memory_win32.c | 2 +- src/core/win32/pal_time_win32.c | 2 +- src/event/pal_default_queue.h | 2 +- src/graphics/d3d12/pal_d3d12.h | 2 +- src/graphics/pal_graphics_backends.h | 2 +- src/graphics/pal_linear_allocator.h | 2 +- src/graphics/vulkan/pal_vulkan.h | 2 +- src/opengl/egl/pal_egl.h | 2 +- src/opengl/pal_opengl.c | 2 +- src/opengl/pal_opengl_backends.h | 2 +- src/opengl/pal_opengl_shared.h | 2 +- src/opengl/wgl/pal_wgl.h | 2 +- src/system/linux/pal_cpu_linux.c | 2 +- src/system/linux/pal_platform_linux.c | 2 +- src/system/win32/pal_cpu_win32.c | 2 +- src/system/win32/pal_platform_win32.c | 2 +- src/thread/posix/pal_thread_posix.h | 2 +- src/thread/posix/pal_tls_posix.c | 2 +- src/thread/win32/pal_thread_win32.h | 2 +- src/thread/win32/pal_tls_win32.c | 2 +- src/video/pal_video_backends.h | 2 +- src/video/wayland/pal_wayland.h | 2 +- src/video/win32/pal_video_win32.h | 2 +- src/video/x11/pal_x11.h | 2 +- tests/event/event_test.c | 2 +- tests/event/user_event_test.c | 2 +- tests/graphics/clear_color_test.c | 6 +- tests/graphics/compute_test.c | 2 +- tests/graphics/custom_backend_test.c | 2 +- tests/graphics/descriptor_indexing_test.c | 6 +- tests/graphics/geometry_test.c | 6 +- tests/graphics/graphics_test.c | 2 +- tests/graphics/indirect_draw_test.c | 6 +- tests/graphics/mesh_test.c | 6 +- tests/graphics/multi_descriptor_set_test.c | 2 +- tests/graphics/ray_tracing_test.c | 2 +- tests/graphics/texture_test.c | 6 +- tests/graphics/triangle_test.c | 6 +- tests/opengl/multi_thread_opengl_test.c | 6 +- tests/opengl/opengl_context_test.c | 4 +- tests/opengl/opengl_fbconfig_test.c | 4 +- tests/opengl/opengl_multi_context_test.c | 4 +- tests/opengl/opengl_test.c | 4 +- tests/system/cpu_test.c | 2 +- tests/system/platform_test.c | 2 +- tests/tests.h | 2 +- tests/tests.lua | 2 +- tests/thread/condvar_test.c | 2 +- tests/thread/mutex_test.c | 2 +- tests/thread/thread_test.c | 2 +- tests/thread/tls_test.c | 2 +- tests/video/attach_window_test.c | 2 +- tests/video/char_event_test.c | 2 +- tests/video/cursor_test.c | 2 +- tests/video/custom_decoration_test.c | 4 +- tests/video/icon_test.c | 2 +- tests/video/input_window_test.c | 2 +- tests/video/monitor_mode_test.c | 2 +- tests/video/monitor_test.c | 2 +- tests/video/native_instance_test.c | 2 +- tests/video/native_integration_test.c | 2 +- tests/video/system_cursor_test.c | 2 +- tests/video/video_test.c | 2 +- tests/video/window_test.c | 2 +- tools/abi_dump/abi_dump.lua | 2 +- tools/abi_dump/abi_dump_main.c | 79 +++++++++++ tools/abi_dump/dumps.h | 2 +- tools/abi_dump/event_abi_dump.c | 2 +- tools/abi_dump/graphics_abi_dump.c | 2 +- tools/abi_dump/opengl_abi_dump.c | 2 +- tools/abi_dump/system_abi_dump.c | 2 +- tools/abi_dump/thread_abi_dump.c | 2 +- tools/abi_dump/video_abi_dump.c | 2 +- 87 files changed, 360 insertions(+), 278 deletions(-) rename include/{pal => pal2}/pal_core.h (97%) rename include/{pal => pal2}/pal_event.h (98%) rename include/{pal => pal2}/pal_graphics.h (100%) rename include/{pal => pal2}/pal_opengl.h (97%) rename include/{pal => pal2}/pal_system.h (97%) rename include/{pal => pal2}/pal_thread.h (96%) rename include/{pal => pal2}/pal_video.h (97%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24903cf0..a90051c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ ### Features -- Added a graphics system API (`pal_graphics.h`). (#4) +- Added a graphics system API (`pal2/pal_graphics.h`). (#4) - Added `palGetResultCode()` to get the result code from a result value. (#4) - Added `palGetResultSource()` to get the result source from a result value. (#4) - Added `palGetResultNativeCode()` to get the result native code from a result value. (#4) @@ -42,6 +42,7 @@ ### Changes +- Moved all public header files to `pal2` directory (eg. `pal2/pal_video.h`). (#4) - `palGetVersion()` now returns `void` and takes a pointer to the struct. (#4) - `palFormatResult()` now takes two additional parameters (#4) - Converted all enum types to fixed-width integer types and their values to standalone constants (eg. `PalResult` to `uint64_t`). (#4) diff --git a/README.md b/README.md index 704b51a7..86369363 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ cd Release ./abi-dump --quick ``` +To view additional commands, run the abi dump tool with `--help`. + ## Documentation PAL uses [Doxygen](https://www.doxygen.nl/) for generating API documentation. diff --git a/include/pal/pal_core.h b/include/pal2/pal_core.h similarity index 97% rename from include/pal/pal_core.h rename to include/pal2/pal_core.h index 0c3961da..6543167a 100644 --- a/include/pal/pal_core.h +++ b/include/pal2/pal_core.h @@ -103,7 +103,7 @@ typedef uint32_t PalBool; * Example: `PAL_RESULT_SOURCE_WIN32` means the native code was retrieved from win32 * (`GetLastError()`). * - * @since 1.0 + * @since 2.0 */ typedef uint64_t PalResult; @@ -141,7 +141,7 @@ typedef uint16_t PalResultSource; * * @return Pointer to the allocated memory on success or `nullptr` on failure. * - * @since 1.0 + * @since 2.0 * @sa PalFreeFn */ typedef void*(PAL_CALL* PalAllocateFn)( @@ -156,7 +156,7 @@ typedef void*(PAL_CALL* PalAllocateFn)( * @param[in] userData Optional pointer to user data. Can be `nullptr`. * @param[in] ptr Pointer to memory previously allocated by PalAllocateFn. * - * @since 1.0 + * @since 2.0 * @sa PalAllocateFn */ typedef void(PAL_CALL* PalFreeFn)( @@ -170,7 +170,7 @@ typedef void(PAL_CALL* PalFreeFn)( * @param userData Optional pointer to user data passed from ::PalLogger. Can be `nullptr`. * @param msg Null-terminated UTF-8 log message. * - * @since 1.0 + * @since 2.0 * @sa palLog */ typedef void(PAL_CALL* PalLogCallback)( @@ -181,7 +181,7 @@ typedef void(PAL_CALL* PalLogCallback)( * @struct PalVersion * @brief Describes the version of PAL. * - * @since 1.0 + * @since 2.0 */ typedef struct { uint32_t major; /**< Major version (breaking changes).*/ @@ -197,7 +197,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 + * @since 2.0 */ typedef struct { PalAllocateFn allocate; /**< Allocate function pointer.*/ @@ -213,7 +213,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 + * @since 2.0 */ typedef struct { PalLogCallback callback; /**< Callback function pointer.*/ @@ -231,7 +231,7 @@ typedef struct { * * Thread safety: Thread safe if buffer is per thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palFormatResult( PalResult result, @@ -245,7 +245,7 @@ PAL_API void PAL_CALL palFormatResult( * * Thread safety: Thread safe if version is per thread. * - * @since 1.0 + * @since 2.0 * @sa palGetVersionString */ PAL_API void PAL_CALL palGetVersion(PalVersion* version); @@ -257,7 +257,7 @@ PAL_API void PAL_CALL palGetVersion(PalVersion* version); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palGetVersion */ PAL_API const char* PAL_CALL palGetVersionString(); @@ -274,7 +274,7 @@ PAL_API const char* PAL_CALL palGetVersionString(); * Thread safety: Thread safe if the provided allocator is thread safe. The default allocator * is thread safe. * - * @since 1.0 + * @since 2.0 * @sa palFree */ PAL_API void* PAL_CALL palAllocate( @@ -291,7 +291,7 @@ PAL_API void* PAL_CALL palAllocate( * Thread safety: Thread safe if the provided allocator is thread * safe. The default allocator is thread safe. * - * @since 1.0 + * @since 2.0 * @sa palAllocate */ PAL_API void PAL_CALL palFree( @@ -309,7 +309,7 @@ PAL_API void PAL_CALL palFree( * callbacks may be invoked concurrently. The user must ensure the callback * implementation is thread safe. * - * @since 1.0 + * @since 2.0 * @sa palFormatResult */ PAL_API void PAL_CALL palLog( @@ -324,7 +324,7 @@ PAL_API void PAL_CALL palLog( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palGetPerformanceFrequency */ PAL_API uint64_t PAL_CALL palGetPerformanceCounter(); @@ -336,7 +336,7 @@ PAL_API uint64_t PAL_CALL palGetPerformanceCounter(); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palGetPerformanceCounter */ PAL_API uint64_t PAL_CALL palGetPerformanceFrequency(); @@ -417,7 +417,7 @@ static inline PalResult PAL_CALL palMakeResult( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palUnpackUint32 */ static inline uint64_t PAL_CALL palPackUint32( @@ -434,7 +434,7 @@ static inline uint64_t PAL_CALL palPackUint32( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palUnpackInt32 */ static inline uint64_t PAL_CALL palPackInt32( @@ -451,7 +451,7 @@ static inline uint64_t PAL_CALL palPackInt32( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palUnpackPointer */ static inline uint64_t PAL_CALL palPackPointer(void* ptr) @@ -466,7 +466,7 @@ static inline uint64_t PAL_CALL palPackPointer(void* ptr) * * Thread safety: Thread safe. * - * @since 1.3 + * @since 2.0 * @sa palUnpackFloat */ static inline uint64_t PAL_CALL palPackFloat( @@ -493,7 +493,7 @@ static inline uint64_t PAL_CALL palPackFloat( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palPackUint32 */ static inline void PAL_CALL palUnpackUint32( @@ -519,7 +519,7 @@ static inline void PAL_CALL palUnpackUint32( * Thread safety: Thread-safe if `outLow` and `outHigh` are * thread local. * - * @since 1.0 + * @since 2.0 * @sa palPackInt32 */ static inline void PAL_CALL palUnpackInt32( @@ -543,7 +543,7 @@ static inline void PAL_CALL palUnpackInt32( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palPackPointer */ static inline void* PAL_CALL palUnpackPointer(uint64_t data) @@ -560,7 +560,7 @@ static inline void* PAL_CALL palUnpackPointer(uint64_t data) * Thread safety: Thread-safe if `outLow` and `outHigh` are * thread local. * - * @since 1.3 + * @since 2.0 * @sa palPackFloat */ static inline void PAL_CALL palUnpackFloat( diff --git a/include/pal/pal_event.h b/include/pal2/pal_event.h similarity index 98% rename from include/pal/pal_event.h rename to include/pal2/pal_event.h index 1eab8ced..24f6115c 100644 --- a/include/pal/pal_event.h +++ b/include/pal2/pal_event.h @@ -14,7 +14,7 @@ #ifndef _PAL_EVENT_H #define _PAL_EVENT_H -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #define PAL_DECORATION_MODE_CLIENT_SIDE 0 #define PAL_DECORATION_MODE_SERVER_SIDE 1 @@ -341,7 +341,7 @@ * @struct PalEventDriver * @brief Opaque handle to an event driver. * - * @since 1.0 + * @since 2.0 */ typedef struct PalEventDriver PalEventDriver; @@ -349,7 +349,7 @@ typedef struct PalEventDriver PalEventDriver; * @struct PalEvent * @brief A single event. * - * @since 1.0 + * @since 2.0 */ typedef struct PalEvent PalEvent; @@ -360,7 +360,7 @@ typedef struct PalEvent PalEvent; * All decoration types follow the format `PAL_DECORATION_MODE_**` for * consistency and API use. * - * @since 1.3 + * @since 2.0 */ typedef uint32_t PalDecorationMode; @@ -371,7 +371,7 @@ typedef uint32_t PalDecorationMode; * All event types follow the format `PAL_EVENT_TYPE_**` for consistency and * API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalEventType; @@ -382,7 +382,7 @@ typedef uint32_t PalEventType; * All dispatch modes follow the format `PAL_DISPATCH_MODE_**` for consistency * and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalDispatchMode; @@ -393,7 +393,7 @@ typedef uint32_t PalDispatchMode; * @param[in] userData Optional pointer to user data. Can be `nullptr`. * @param[in] event Pointer to the event. * - * @since 1.0 + * @since 2.0 * @sa PalPushFn */ typedef void(PAL_CALL* PalEventCallback)( @@ -407,7 +407,7 @@ typedef void(PAL_CALL* PalEventCallback)( * @param[in] userData Optional pointer to user data. Can be `nullptr`. * @param[in] event Pointer to the event to push. * - * @since 1.0 + * @since 2.0 * @sa PalEventCallback */ typedef void(PAL_CALL* PalPushFn)( @@ -425,7 +425,7 @@ typedef void(PAL_CALL* PalPushFn)( * @param[in] userData Optional pointer to user data. Can be `nullptr`. * @param[out] outEvent Pointer to the PalEvent to recieve the event. * - * @since 1.0 + * @since 2.0 * @sa PalPushFn */ typedef PalBool(PAL_CALL* PalPollFn)( @@ -445,7 +445,7 @@ struct PalEvent { * * Provides user-defined event queue push and poll functions. * - * @since 1.0 + * @since 2.0 */ typedef struct { PalPushFn push; /**< Push function pointer.*/ @@ -459,7 +459,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 + * @since 2.0 */ typedef struct { const PalAllocator* allocator; /**< Set to `nullptr` to use default.*/ @@ -488,7 +488,7 @@ typedef struct { * thread safe and `outEventDriver` is per thread. The default allocator is * thread safe. * - * @since 1.0 + * @since 2.0 * @sa palDestroyEventDriver */ PAL_API PalResult PAL_CALL palCreateEventDriver( @@ -503,7 +503,7 @@ PAL_API PalResult PAL_CALL palCreateEventDriver( * Thread safety: Thread safe if the allocator used to create * the event driver is thread safe and `eventDriver` is per thread. * - * @since 1.0 + * @since 2.0 * @sa palCreateEventDriver */ PAL_API void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver); @@ -524,7 +524,7 @@ PAL_API void PAL_CALL palDestroyEventDriver(PalEventDriver* eventDriver); * Thread safety: Thread safe if multiple threads are not * simultaneously setting dispatch mode on the same `eventDriver`. * - * @since 1.0 + * @since 2.0 * @sa palGetEventDispatchMode */ PAL_API void PAL_CALL palSetEventDispatchMode( @@ -544,7 +544,7 @@ PAL_API void PAL_CALL palSetEventDispatchMode( * Thread safety: Thread safe if multiple threads are not * simultaneously setting dispatch mode on the same `eventDriver`. * - * @since 1.0 + * @since 2.0 * @sa palSetEventDispatchMode */ PAL_API PalDispatchMode PAL_CALL palGetEventDispatchMode( @@ -568,7 +568,7 @@ PAL_API PalDispatchMode PAL_CALL palGetEventDispatchMode( * safe or every thread has its own `eventDriver`. The default event queue is * not thread safe. * - * @since 1.0 + * @since 2.0 * @sa palPollEvent */ PAL_API void PAL_CALL palPushEvent( @@ -591,7 +591,7 @@ PAL_API void PAL_CALL palPushEvent( * safe or every thread has its own `eventDriver`. The default event queue is * not thread safe. * - * @since 1.0 + * @since 2.0 * @sa palPushEvent */ PAL_API PalBool PAL_CALL palPollEvent( diff --git a/include/pal/pal_graphics.h b/include/pal2/pal_graphics.h similarity index 100% rename from include/pal/pal_graphics.h rename to include/pal2/pal_graphics.h diff --git a/include/pal/pal_opengl.h b/include/pal2/pal_opengl.h similarity index 97% rename from include/pal/pal_opengl.h rename to include/pal2/pal_opengl.h index ddb30664..20b26acb 100644 --- a/include/pal/pal_opengl.h +++ b/include/pal2/pal_opengl.h @@ -66,7 +66,7 @@ * @struct PalGLContext * @brief Opaque handle to an opengl context. * - * @since 1.0 + * @since 2.0 */ typedef struct PalGLContext PalGLContext; @@ -77,7 +77,7 @@ typedef struct PalGLContext PalGLContext; * All opengl extensions follow the format `PAL_GL_EXTENSION_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint64_t PalGLExtensions; @@ -88,7 +88,7 @@ typedef uint64_t PalGLExtensions; * All opengl profiles follow the format `PAL_GL_PROFILE_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalGLProfile; @@ -99,7 +99,7 @@ typedef uint32_t PalGLProfile; * All context reset behavior follow the format `PAL_GL_CONTEXT_RESET_**` * for consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalGLContextReset; @@ -110,7 +110,7 @@ typedef uint32_t PalGLContextReset; * All opengl context release behavior follow the format * `PAL_GL_RELEASE_BEHAVIOR_**` for consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalGLReleaseBehavior; @@ -138,7 +138,7 @@ typedef uint32_t PalGLAPI; * @struct PalGLInfo * @brief Information about the opengl driver. * - * @since 1.0 + * @since 2.0 */ typedef struct { PalGLExtensions extensions; /**< Supported extensions.*/ @@ -155,7 +155,7 @@ typedef struct { * @struct PalGLFBConfig * @brief Information about an opengl framebuffer. * - * @since 1.0 + * @since 2.0 */ typedef struct { PalBool doubleBuffer; /**< If `PAL_TRUE` double buffering is supported.*/ @@ -178,7 +178,7 @@ typedef struct { * This can be allocated statically or dynamically since its used for * holding native handles. The handles will not be copied. * - * @since 1.0 + * @since 2.0 */ typedef struct { void* instance; /**< (HINSTANCE on Win32 or wl_display on Wayland)*/ @@ -191,7 +191,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 + * @since 2.0 */ typedef struct { const PalGLWindow* window; /**< Window to create context for.*/ @@ -229,7 +229,7 @@ typedef struct { * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palShutdownGL */ PAL_API PalResult PAL_CALL palInitGL( @@ -245,7 +245,7 @@ PAL_API PalResult PAL_CALL palInitGL( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palInitGL */ PAL_API void PAL_CALL palShutdownGL(); @@ -260,7 +260,7 @@ PAL_API void PAL_CALL palShutdownGL(); * * Thread safety: Thread-safe. * - * @since 1.0 + * @since 2.0 */ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); @@ -283,7 +283,7 @@ PAL_API const PalGLInfo* PAL_CALL palGetGLInfo(); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palInitGL */ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( @@ -305,7 +305,7 @@ PAL_API PalResult PAL_CALL palEnumerateGLFBConfigs( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( PalGLFBConfig* configs, @@ -333,7 +333,7 @@ PAL_API const PalGLFBConfig* PAL_CALL palGetClosestGLFBConfig( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palDestroyGLContext */ PAL_API PalResult PAL_CALL palCreateGLContext( @@ -350,7 +350,7 @@ PAL_API PalResult PAL_CALL palCreateGLContext( * * Thread safety: Thread safe if the `context` is per thread. * - * @since 1.0 + * @since 2.0 * @sa palCreateGLContext */ PAL_API void PAL_CALL palDestroyGLContext(PalGLContext* context); @@ -374,7 +374,7 @@ PAL_API void PAL_CALL palDestroyGLContext(PalGLContext* context); * Thread safety: Thread safe, but only one thread may have the * current context at a time. * - * @since 1.0 + * @since 2.0 */ PAL_API PalResult PAL_CALL palMakeContextCurrent( PalGLWindow* glWindow, @@ -391,7 +391,7 @@ PAL_API PalResult PAL_CALL palMakeContextCurrent( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palInitGL */ PAL_API void* PAL_CALL palGetGLProcAddress(const char* name); @@ -411,7 +411,7 @@ PAL_API void* PAL_CALL palGetGLProcAddress(const char* name); * Thread safety: Must only be called from a thread that has a * bound context. * - * @since 1.0 + * @since 2.0 * @sa palMakeContextCurrent */ PAL_API PalResult PAL_CALL palSwapBuffers( @@ -430,7 +430,7 @@ PAL_API PalResult PAL_CALL palSwapBuffers( * Thread safety: Must only be called from a thread with a bound * context. * - * @since 1.0 + * @since 2.0 * @sa palMakeContextCurrent */ PAL_API void PAL_CALL palSetSwapInterval(int32_t interval); diff --git a/include/pal/pal_system.h b/include/pal2/pal_system.h similarity index 97% rename from include/pal/pal_system.h rename to include/pal2/pal_system.h index 596fedfa..c60227dc 100644 --- a/include/pal/pal_system.h +++ b/include/pal2/pal_system.h @@ -62,7 +62,7 @@ * All CPU achitectures follow the format `PAL_CPU_ARCH_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalCpuArch; @@ -73,7 +73,7 @@ typedef uint32_t PalCpuArch; * All CPU features sets follow the format `PAL_CPU_FEATURE_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint64_t PalCpuFeatures; @@ -87,7 +87,7 @@ typedef uint64_t PalCpuFeatures; * All platform types follow the format `PAL_PLATFORM_TYPE_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalPlatformType; @@ -101,7 +101,7 @@ typedef uint32_t PalPlatformType; * All platform API types follow the format `PAL_PLATFORM_API_TYPE_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalPlatformApiType; @@ -109,7 +109,7 @@ typedef uint32_t PalPlatformApiType; * @struct PalPlatformInfo * @brief Information about a platform (OS). * - * @since 1.0 + * @since 2.0 */ typedef struct { PalPlatformType type; /**< (eg. `PAL_PLATFORM_TYPE_WINDOWS`).*/ @@ -124,7 +124,7 @@ typedef struct { * @struct PalCPUInfo * @brief Information about a CPU. * - * @since 1.0 + * @since 2.0 */ typedef struct { PalCpuFeatures features; /**< Supported CPU features (instructions).*/ @@ -148,7 +148,7 @@ typedef struct { * * Thread safety: Thread-safe if `info` is per thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palGetPlatformInfo(PalPlatformInfo* info); @@ -165,7 +165,7 @@ PAL_API void PAL_CALL palGetPlatformInfo(PalPlatformInfo* info); * Thread safety: Thread-safe if the proivded allocator is * thread safe and `info` is per thread. The default allocator is thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palGetCPUInfo( const PalAllocator* allocator, diff --git a/include/pal/pal_thread.h b/include/pal2/pal_thread.h similarity index 96% rename from include/pal/pal_thread.h rename to include/pal2/pal_thread.h index e4d26c36..d67dbee3 100644 --- a/include/pal/pal_thread.h +++ b/include/pal2/pal_thread.h @@ -30,7 +30,7 @@ * @struct PalThread * @brief Opaque handle to a thread. * - * @since 1.0 + * @since 2.0 */ typedef struct PalThread PalThread; @@ -38,7 +38,7 @@ typedef struct PalThread PalThread; * @typedef PalTLSId * @brief Opaque handle to a Thread Local Storage. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalTLSId; @@ -46,7 +46,7 @@ typedef uint32_t PalTLSId; * @struct PalMutex * @brief Opaque handle to a mutex. * - * @since 1.0 + * @since 2.0 */ typedef struct PalMutex PalMutex; @@ -54,7 +54,7 @@ typedef struct PalMutex PalMutex; * @struct PalCondVar * @brief Opaque handle to a condition variable. * - * @since 1.0 + * @since 2.0 */ typedef struct PalCondVar PalCondVar; @@ -65,7 +65,7 @@ typedef struct PalCondVar PalCondVar; * All thread features follow the format `PAL_THREAD_FEATURE_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalThreadFeatures; @@ -76,7 +76,7 @@ typedef uint32_t PalThreadFeatures; * All thread priority types follow the format `PAL_THREAD_PRIORITY_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalThreadPriority; @@ -88,7 +88,7 @@ typedef uint32_t PalThreadPriority; * * @return The return value of the thread as a pointer. * - * @since 1.0 + * @since 2.0 */ typedef void* (*PalThreadFn)(void* arg); @@ -100,7 +100,7 @@ typedef void* (*PalThreadFn)(void* arg); * * @param[in] userData Optional pointer to user data. Can be `nullptr`. * - * @since 1.0 + * @since 2.0 */ typedef void (*PaTlsDestructorFn)(void* userData); @@ -110,7 +110,7 @@ typedef void (*PaTlsDestructorFn)(void* userData); * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 + * @since 2.0 */ typedef struct { uint64_t stackSize; /**< Set to 0 to use default*/ @@ -140,7 +140,7 @@ typedef struct { * thread safe and `outThread` is per thread. The default allocator is * thread safe. * - * @since 1.0 + * @since 2.0 * @sa palDetachThread */ PAL_API PalResult PAL_CALL palCreateThread( @@ -161,7 +161,7 @@ PAL_API PalResult PAL_CALL palCreateThread( * * Thread safety: Thread safe if `retval` is per thread. * - * @since 1.0 + * @since 2.0 */ PAL_API PalResult PAL_CALL palJoinThread( PalThread* thread, @@ -180,7 +180,7 @@ PAL_API PalResult PAL_CALL palJoinThread( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palDetachThread(PalThread* thread); @@ -191,7 +191,7 @@ PAL_API void PAL_CALL palDetachThread(PalThread* thread); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palSleep(uint64_t milliseconds); @@ -201,7 +201,7 @@ PAL_API void PAL_CALL palSleep(uint64_t milliseconds); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palYield(); @@ -212,7 +212,7 @@ PAL_API void PAL_CALL palYield(); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API PalThread* PAL_CALL palGetCurrentThread(); @@ -225,7 +225,7 @@ PAL_API PalThread* PAL_CALL palGetCurrentThread(); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API PalThreadFeatures PAL_CALL palGetThreadFeatures(); @@ -240,7 +240,7 @@ PAL_API PalThreadFeatures PAL_CALL palGetThreadFeatures(); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread); @@ -255,7 +255,7 @@ PAL_API PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread); @@ -282,7 +282,7 @@ PAL_API uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread); * @note On MacOS: Thread names are limited to 64 characters including the null * terminator. * - * @since 1.0 + * @since 2.0 * @sa palSetThreadName */ PAL_API void PAL_CALL palGetThreadName( @@ -306,7 +306,7 @@ PAL_API void PAL_CALL palGetThreadName( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API PalResult PAL_CALL palSetThreadPriority( PalThread* thread, @@ -332,7 +332,7 @@ PAL_API PalResult PAL_CALL palSetThreadPriority( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 */ PAL_API PalResult PAL_CALL palSetThreadAffinity( PalThread* thread, @@ -358,7 +358,7 @@ PAL_API PalResult PAL_CALL palSetThreadAffinity( * @note On MacOS: Thread names are limited to 64 characters including the null * terminator. * - * @since 1.0 + * @since 2.0 * @sa palGetThreadName */ PAL_API PalResult PAL_CALL palSetThreadName( @@ -379,7 +379,7 @@ PAL_API PalResult PAL_CALL palSetThreadName( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palDestroyTLS */ PAL_API PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor); @@ -391,7 +391,7 @@ PAL_API PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palCreateTL */ PAL_API void PAL_CALL palDestroyTLS(PalTLSId id); @@ -405,7 +405,7 @@ PAL_API void PAL_CALL palDestroyTLS(PalTLSId id); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palSetTLS */ PAL_API void* PAL_CALL palGetTLS(PalTLSId id); @@ -418,7 +418,7 @@ PAL_API void* PAL_CALL palGetTLS(PalTLSId id); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palGetTLS */ PAL_API void PAL_CALL palSetTLS( @@ -437,7 +437,7 @@ PAL_API void PAL_CALL palSetTLS( * Thread safety: Thread safe if the provided allocator is * thread safe and `outMutex` is per thread. * - * @since 1.0 + * @since 2.0 * @sa palDestroyMutex */ PAL_API PalResult PAL_CALL palCreateMutex( @@ -455,7 +455,7 @@ PAL_API PalResult PAL_CALL palCreateMutex( * Thread safety: Thread safe if the allocator used to create * the mutex is thread safe and `mutex` is per thread. * - * @since 1.0 + * @since 2.0 * @sa palCreateMutex */ PAL_API void PAL_CALL palDestroyMutex(PalMutex* mutex); @@ -467,7 +467,7 @@ PAL_API void PAL_CALL palDestroyMutex(PalMutex* mutex); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palUnlockMutex */ PAL_API void PAL_CALL palLockMutex(PalMutex* mutex); @@ -481,7 +481,7 @@ PAL_API void PAL_CALL palLockMutex(PalMutex* mutex); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palLockMutex */ PAL_API void PAL_CALL palUnlockMutex(PalMutex* mutex); @@ -500,7 +500,7 @@ PAL_API void PAL_CALL palUnlockMutex(PalMutex* mutex); * Thread safety: Thread safe if the provided allocator is * thread safe and `outCondVar` is per thread. * - * @since 1.0 + * @since 2.0 * @sa palDestroyCondVar */ PAL_API PalResult PAL_CALL palCreateCondVar( @@ -519,7 +519,7 @@ PAL_API PalResult PAL_CALL palCreateCondVar( * Thread safety: Thread safe if the allocator used to create * the condition varibale is thread safe and `condVar` is per thread. * - * @since 1.0 + * @since 2.0 * @sa palCreateCondVar */ PAL_API void PAL_CALL palDestroyCondVar(PalCondVar* condVar); @@ -541,7 +541,7 @@ PAL_API void PAL_CALL palDestroyCondVar(PalCondVar* condVar); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palWaitCondVarTimeout */ PAL_API PalResult PAL_CALL palWaitCondVar( @@ -561,7 +561,7 @@ PAL_API PalResult PAL_CALL palWaitCondVar( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palWaitCondVar */ PAL_API PalResult PAL_CALL palWaitCondVarTimeout( @@ -576,7 +576,7 @@ PAL_API PalResult PAL_CALL palWaitCondVarTimeout( * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palBroadcastCondVar */ PAL_API void PAL_CALL palSignalCondVar(PalCondVar* condVar); @@ -588,7 +588,7 @@ PAL_API void PAL_CALL palSignalCondVar(PalCondVar* condVar); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palSignalCondVar */ PAL_API void PAL_CALL palBroadcastCondVar(PalCondVar* condVar); diff --git a/include/pal/pal_video.h b/include/pal2/pal_video.h similarity index 97% rename from include/pal/pal_video.h rename to include/pal2/pal_video.h index 2893604a..b6269b50 100644 --- a/include/pal/pal_video.h +++ b/include/pal2/pal_video.h @@ -324,7 +324,7 @@ * @struct PalMonitor * @brief Opaque handle to a monitor. * - * @since 1.0 + * @since 2.0 */ typedef struct PalMonitor PalMonitor; @@ -332,7 +332,7 @@ typedef struct PalMonitor PalMonitor; * @struct PalWindow * @brief Opaque handle to a window. * - * @since 1.0 + * @since 2.0 */ typedef struct PalWindow PalWindow; @@ -340,7 +340,7 @@ typedef struct PalWindow PalWindow; * @struct PalIcon * @brief Opaque handle to an icon. * - * @since 1.0 + * @since 2.0 */ typedef struct PalIcon PalIcon; @@ -348,7 +348,7 @@ typedef struct PalIcon PalIcon; * @struct PalCursor * @brief Opaque handle to a cursor. * - * @since 1.0 + * @since 2.0 */ typedef struct PalCursor PalCursor; @@ -359,7 +359,7 @@ typedef struct PalCursor PalCursor; * All video features follow the format `PAL_VIDEO_FEATURE_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint64_t PalVideoFeatures; @@ -370,7 +370,7 @@ typedef uint64_t PalVideoFeatures; * All orientation types follow the format `PAL_ORIENTATION_**` for consistency * and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalOrientation; @@ -382,7 +382,7 @@ typedef uint32_t PalOrientation; * All window flags follow the format `PAL_WINDOW_STYLE_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalWindowStyle; @@ -393,7 +393,7 @@ typedef uint32_t PalWindowStyle; * All window states follow the format `PAL_WINDOW_STATE_**` for consistency and * API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalWindowState; @@ -407,7 +407,7 @@ typedef uint32_t PalWindowState; * All flash flags follow the format `PAL_FLASH_FLAG_**` for consistency and * API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalFlashFlags; @@ -418,7 +418,7 @@ typedef uint32_t PalFlashFlags; * All FBConfig backends follow the format `PAL_FBCONFIG_BACKEND_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalFBConfigBackend; @@ -429,7 +429,7 @@ typedef uint32_t PalFBConfigBackend; * All scancodes follow the format `PAL_SCANCODE_**` for consistency and * API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalScancode; @@ -440,7 +440,7 @@ typedef uint32_t PalScancode; * All keycodes follow the format `PAL_KEYCODE_**` for consistency and API * use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalKeycode; @@ -451,7 +451,7 @@ typedef uint32_t PalKeycode; * All mouse buttons follow the format `PAL_MOUSE_BUTTON_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalMouseButton; @@ -462,7 +462,7 @@ typedef uint32_t PalMouseButton; * All cursor types follow the format `PAL_CURSOR_TYPE_**` for * consistency and API use. * - * @since 1.0 + * @since 2.0 */ typedef uint32_t PalCursorType; @@ -470,7 +470,7 @@ typedef uint32_t PalCursorType; * @struct PalMonitorInfo * @brief Information about a monitor. * - * @since 1.0 + * @since 2.0 */ typedef struct { int32_t x; /**< X position in pixels.*/ @@ -488,7 +488,7 @@ typedef struct { * @struct PalMonitorMode * @brief information about a monitor display mode. * - * @since 1.0 + * @since 2.0 */ typedef struct { uint32_t bpp; /**< Bits per pixel.*/ @@ -503,7 +503,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 + * @since 2.0 */ typedef struct { PalFlashFlags flags; /**< (eg. `PAL_FLASH_FLAG_CAPTION`).*/ @@ -517,7 +517,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 + * @since 2.0 */ typedef struct { const uint8_t* pixels; /**< Pixels in `RGBA` format.*/ @@ -531,7 +531,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 + * @since 2.0 */ typedef struct { const uint8_t* pixels; /**< Pixels in `RGBA` format.*/ @@ -545,7 +545,7 @@ typedef struct { * @struct PalWindowHandleInfo * @brief Information about a window handle. * - * @since 1.0 + * @since 2.0 */ typedef struct { void* nativeInstance; /**< The platform (OS) display or instance.*/ @@ -561,7 +561,7 @@ typedef struct { * * Uninitialized fields may result in undefined behavior. * - * @since 1.0 + * @since 2.0 */ typedef struct { const char* title; /**< Title in UTF-8 encoding.*/ @@ -604,7 +604,7 @@ typedef struct { * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palShutdownVideo */ PAL_API PalResult PAL_CALL palInitVideo( @@ -620,7 +620,7 @@ PAL_API PalResult PAL_CALL palInitVideo( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palInitVideo */ PAL_API void PAL_CALL palShutdownVideo(); @@ -634,7 +634,7 @@ PAL_API void PAL_CALL palShutdownVideo(); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palInitVideo */ PAL_API void PAL_CALL palUpdateVideo(); @@ -646,7 +646,7 @@ PAL_API void PAL_CALL palUpdateVideo(); * * Thread safety: Thread safe. * - * @since 1.0 + * @since 2.0 * @sa palInitVideo */ PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures(); @@ -674,7 +674,7 @@ PAL_API PalVideoFeatures PAL_CALL palGetVideoFeatures(); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palGetPrimaryMonitor */ PAL_API PalResult PAL_CALL palEnumerateMonitors( @@ -695,7 +695,7 @@ PAL_API PalResult PAL_CALL palEnumerateMonitors( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palEnumerateMonitors */ PAL_API void PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor); @@ -714,7 +714,7 @@ PAL_API void PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor); * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palGetMonitorInfo( PalMonitor* monitor, @@ -738,7 +738,7 @@ PAL_API void PAL_CALL palGetMonitorInfo( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palEnumerateMonitorModes( PalMonitor* monitor, @@ -757,7 +757,7 @@ PAL_API void PAL_CALL palEnumerateMonitorModes( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palSetMonitorMode */ PAL_API void PAL_CALL palGetCurrentMonitorMode( @@ -786,7 +786,7 @@ PAL_API void PAL_CALL palGetCurrentMonitorMode( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palGetCurrentMonitorMode */ PAL_API PalResult PAL_CALL palSetMonitorMode( @@ -807,7 +807,7 @@ PAL_API PalResult PAL_CALL palSetMonitorMode( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API PalResult PAL_CALL palValidateMonitorMode( PalMonitor* monitor, @@ -829,7 +829,7 @@ PAL_API PalResult PAL_CALL palValidateMonitorMode( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API PalResult PAL_CALL palSetMonitorOrientation( PalMonitor* monitor, @@ -869,7 +869,7 @@ PAL_API PalResult PAL_CALL palSetMonitorOrientation( * * - Creating hidden window is not supported. It will be ignored. * - * @since 1.0 + * @since 2.0 */ PAL_API PalResult PAL_CALL palCreateWindow( const PalWindowCreateInfo* info, @@ -885,7 +885,7 @@ PAL_API PalResult PAL_CALL palCreateWindow( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palCreateWindow */ PAL_API void PAL_CALL palDestroyWindow(PalWindow* window); @@ -901,7 +901,7 @@ PAL_API void PAL_CALL palDestroyWindow(PalWindow* window); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palMaximizeWindow * @sa palRestoreWindow */ @@ -918,7 +918,7 @@ PAL_API void PAL_CALL palMinimizeWindow(PalWindow* window); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palMinimizeWindow * @sa palRestoreWindow */ @@ -937,7 +937,7 @@ PAL_API void PAL_CALL palMaximizeWindow(PalWindow* window); * * @note Wayland does not support restoring a minimized windows. * - * @since 1.0 + * @since 2.0 * @sa palMinimizeWindow * @sa palMaximizeWindow */ @@ -955,7 +955,7 @@ PAL_API void PAL_CALL palRestoreWindow(PalWindow* window); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palHideWindow */ PAL_API void PAL_CALL palShowWindow(PalWindow* window); @@ -971,7 +971,7 @@ PAL_API void PAL_CALL palShowWindow(PalWindow* window); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palShowWindow */ PAL_API void PAL_CALL palHideWindow(PalWindow* window); @@ -992,7 +992,7 @@ PAL_API void PAL_CALL palHideWindow(PalWindow* window); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palFlashWindow( PalWindow* window, @@ -1009,7 +1009,7 @@ PAL_API void PAL_CALL palFlashWindow( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palSetWindowStyle */ PAL_API void PAL_CALL palGetWindowStyle( @@ -1027,7 +1027,7 @@ PAL_API void PAL_CALL palGetWindowStyle( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palGetWindowMonitor( PalWindow* window, @@ -1051,7 +1051,7 @@ PAL_API void PAL_CALL palGetWindowMonitor( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palSetWindowTitle */ PAL_API void PAL_CALL palGetWindowTitle( @@ -1072,7 +1072,7 @@ PAL_API void PAL_CALL palGetWindowTitle( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palSetWindowPos */ PAL_API void PAL_CALL palGetWindowPos( @@ -1092,7 +1092,7 @@ PAL_API void PAL_CALL palGetWindowPos( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palSetWindowSize */ PAL_API void PAL_CALL palGetWindowSize( @@ -1111,7 +1111,7 @@ PAL_API void PAL_CALL palGetWindowSize( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palGetWindowState( PalWindow* window, @@ -1131,7 +1131,7 @@ PAL_API void PAL_CALL palGetWindowState( * * Thread safety: Thread-safe. * - * @since 1.0 + * @since 2.0 */ PAL_API const PalBool* PAL_CALL palGetKeycodeState(); @@ -1149,7 +1149,7 @@ PAL_API const PalBool* PAL_CALL palGetKeycodeState(); * * Thread safety: Thread-safe. * - * @since 1.0 + * @since 2.0 */ PAL_API const PalBool* PAL_CALL palGetScancodeState(); @@ -1166,7 +1166,7 @@ PAL_API const PalBool* PAL_CALL palGetScancodeState(); * * @Thread safety: Thread-safe. * - * @since 1.0 + * @since 2.0 */ PAL_API const PalBool* PAL_CALL palGetMouseState(); @@ -1184,7 +1184,7 @@ PAL_API const PalBool* PAL_CALL palGetMouseState(); * Thread safety: Thread-safe if `dx` and `dy` are thread * local. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palGetMouseDelta( float* dx, @@ -1202,7 +1202,7 @@ PAL_API void PAL_CALL palGetMouseDelta( * Thread safety: Thread-safe if `dx` and `dy` are thread * local. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palGetMouseWheelDelta( float* dx, @@ -1220,7 +1220,7 @@ PAL_API void PAL_CALL palGetMouseWheelDelta( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API PalBool PAL_CALL palIsWindowVisible(PalWindow* window); @@ -1235,7 +1235,7 @@ PAL_API PalBool PAL_CALL palIsWindowVisible(PalWindow* window); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API PalWindow* PAL_CALL palGetFocusWindow(); @@ -1252,7 +1252,7 @@ PAL_API PalWindow* PAL_CALL palGetFocusWindow(); * * Thread safety: Thread-safe. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palGetWindowHandleInfo( PalWindow* window, @@ -1270,7 +1270,7 @@ PAL_API void PAL_CALL palGetWindowHandleInfo( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palSetWindowOpacity( PalWindow* window, @@ -1287,7 +1287,7 @@ PAL_API void PAL_CALL palSetWindowOpacity( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palGetWindowStyle */ PAL_API void PAL_CALL palSetWindowStyle( @@ -1306,7 +1306,7 @@ PAL_API void PAL_CALL palSetWindowStyle( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palGetWindowTitle */ PAL_API void PAL_CALL palSetWindowTitle( @@ -1325,7 +1325,7 @@ PAL_API void PAL_CALL palSetWindowTitle( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palGetWindowPos */ PAL_API void PAL_CALL palSetWindowPos( @@ -1347,7 +1347,7 @@ PAL_API void PAL_CALL palSetWindowPos( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palGetWindowSize */ PAL_API void PAL_CALL palSetWindowSize( @@ -1365,7 +1365,7 @@ PAL_API void PAL_CALL palSetWindowSize( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palGetFocusWindow */ PAL_API void PAL_CALL palSetFocusWindow(PalWindow* window); @@ -1384,7 +1384,7 @@ PAL_API void PAL_CALL palSetFocusWindow(PalWindow* window); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palDestroyIcon */ PAL_API PalResult PAL_CALL palCreateIcon( @@ -1400,7 +1400,7 @@ PAL_API PalResult PAL_CALL palCreateIcon( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palCreateIcon */ PAL_API void PAL_CALL palDestroyIcon(PalIcon* icon); @@ -1416,7 +1416,7 @@ PAL_API void PAL_CALL palDestroyIcon(PalIcon* icon); * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palSetWindowIcon( PalWindow* window, @@ -1435,7 +1435,7 @@ PAL_API void PAL_CALL palSetWindowIcon( * * Thread safety: Must only be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palDestroyCursor */ PAL_API PalResult PAL_CALL palCreateCursor( @@ -1455,7 +1455,7 @@ PAL_API PalResult PAL_CALL palCreateCursor( * * Thread safety: Must only be called from the main thread. * - * @since 1.1 + * @since 2.0 * @sa palDestroyCursor */ PAL_API PalResult PAL_CALL palCreateCursorFrom( @@ -1471,7 +1471,7 @@ PAL_API PalResult PAL_CALL palCreateCursorFrom( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 * @sa palCreateCursor */ PAL_API void PAL_CALL palDestroyCursor(PalCursor* cursor); @@ -1489,7 +1489,7 @@ PAL_API void PAL_CALL palDestroyCursor(PalCursor* cursor); * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palShowCursor(PalBool show); @@ -1508,7 +1508,7 @@ PAL_API void PAL_CALL palShowCursor(PalBool show); * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palClipCursor( PalWindow* window, @@ -1529,7 +1529,7 @@ PAL_API void PAL_CALL palClipCursor( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palGetCursorPos( PalWindow* window, @@ -1549,7 +1549,7 @@ PAL_API void PAL_CALL palGetCursorPos( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palSetCursorPos( PalWindow* window, @@ -1566,7 +1566,7 @@ PAL_API void PAL_CALL palSetCursorPos( * * Thread safety: Must be called from the main thread. * - * @since 1.0 + * @since 2.0 */ PAL_API void PAL_CALL palSetWindowCursor( PalWindow* window, @@ -1590,7 +1590,7 @@ PAL_API void PAL_CALL palSetWindowCursor( * * @note The returned instance or display must not be freed. * - * @since 1.2 + * @since 2.0 */ PAL_API void* PAL_CALL palGetInstance(); @@ -1624,7 +1624,7 @@ PAL_API void* PAL_CALL palGetInstance(); * * Thread safety: Must be called from the main thread. * - * @since 1.2 + * @since 2.0 * @sa palGetInstance * @sa palDestroyWindow * @sa palDetachWindow @@ -1659,7 +1659,7 @@ PAL_API PalResult PAL_CALL palAttachWindow( * * Thread safety: Must be called from the main thread. * - * @since 1.2 + * @since 2.0 * @sa palAttachWindow */ PAL_API PalResult PAL_CALL palDetachWindow( diff --git a/pal.lua b/pal.lua index 86d8ce83..d55405ae 100644 --- a/pal.lua +++ b/pal.lua @@ -1,7 +1,7 @@ dofile("pal_config.lua") -project "PAL" +project "PAL2" if PAL_BUILD_STATIC_LIBRARY then kind "StaticLib" else diff --git a/src/core/pal_format.h b/src/core/pal_format.h index de11eb59..4256c062 100644 --- a/src/core/pal_format.h +++ b/src/core/pal_format.h @@ -8,7 +8,7 @@ #ifndef _PAL_FORMAT_H #define _PAL_FORMAT_H -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #include #include diff --git a/src/core/pal_version.c b/src/core/pal_version.c index 0534d934..361cd8bb 100644 --- a/src/core/pal_version.c +++ b/src/core/pal_version.c @@ -5,7 +5,7 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #define PAL_VERSION_MAJOR 2 #define PAL_VERSION_MINOR 0 diff --git a/src/core/posix/pal_memory_posix.c b/src/core/posix/pal_memory_posix.c index 66017faf..e4f31ac6 100644 --- a/src/core/posix/pal_memory_posix.c +++ b/src/core/posix/pal_memory_posix.c @@ -9,7 +9,7 @@ #if _PAL_HAS_POSIX #define _POSIX_C_SOURCE 200112L -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #include void* PAL_CALL palAllocate( diff --git a/src/core/posix/pal_time_posix.c b/src/core/posix/pal_time_posix.c index 4e8f7923..fcf979ae 100644 --- a/src/core/posix/pal_time_posix.c +++ b/src/core/posix/pal_time_posix.c @@ -9,7 +9,7 @@ #if _PAL_HAS_POSIX #define _POSIX_C_SOURCE 200112L -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #include uint64_t PAL_CALL palGetPerformanceCounter() diff --git a/src/core/win32/pal_memory_win32.c b/src/core/win32/pal_memory_win32.c index 4f8c9bc8..0a65ce42 100644 --- a/src/core/win32/pal_memory_win32.c +++ b/src/core/win32/pal_memory_win32.c @@ -6,7 +6,7 @@ */ #ifdef _WIN32 -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #if defined(_MSC_VER) || defined(__MINGW32__) #include diff --git a/src/core/win32/pal_time_win32.c b/src/core/win32/pal_time_win32.c index c6a5a1ce..a8981241 100644 --- a/src/core/win32/pal_time_win32.c +++ b/src/core/win32/pal_time_win32.c @@ -19,7 +19,7 @@ #define UNICODE #endif // UNICODE -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #include uint64_t PAL_CALL palGetPerformanceCounter() diff --git a/src/event/pal_default_queue.h b/src/event/pal_default_queue.h index 5eabc067..bc271c6d 100644 --- a/src/event/pal_default_queue.h +++ b/src/event/pal_default_queue.h @@ -8,7 +8,7 @@ #ifndef _PAL_DEFAULT_QUEUE_H #define _PAL_DEFAULT_QUEUE_H -#include "pal/pal_event.h" +#include "pal2/pal_event.h" #define MAX_EVENTS 512 diff --git a/src/graphics/d3d12/pal_d3d12.h b/src/graphics/d3d12/pal_d3d12.h index 4dab4a46..cc37f351 100644 --- a/src/graphics/d3d12/pal_d3d12.h +++ b/src/graphics/d3d12/pal_d3d12.h @@ -10,7 +10,7 @@ #if PAL_HAS_D3D12_BACKEND #include "graphics/pal_linear_allocator.h" -#include "pal/pal_graphics.h" +#include "pal2/pal_graphics.h" #include #include #include diff --git a/src/graphics/pal_graphics_backends.h b/src/graphics/pal_graphics_backends.h index 1d4204e1..59fb0542 100644 --- a/src/graphics/pal_graphics_backends.h +++ b/src/graphics/pal_graphics_backends.h @@ -8,7 +8,7 @@ #ifndef _PAL_GRAPHICS_BACKENDS_H #define _PAL_GRAPHICS_BACKENDS_H -#include "pal/pal_graphics.h" +#include "pal2/pal_graphics.h" // clang-format off typedef struct { diff --git a/src/graphics/pal_linear_allocator.h b/src/graphics/pal_linear_allocator.h index 3bd4dd3e..bbbbe636 100644 --- a/src/graphics/pal_linear_allocator.h +++ b/src/graphics/pal_linear_allocator.h @@ -8,7 +8,7 @@ #ifndef _PAL_LINEAR_ALLOCATOR_H #define _PAL_LINEAR_ALLOCATOR_H -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #define align(v, a) (v + a - 1) & ~(a - 1) diff --git a/src/graphics/vulkan/pal_vulkan.h b/src/graphics/vulkan/pal_vulkan.h index 1baac8eb..79331c63 100644 --- a/src/graphics/vulkan/pal_vulkan.h +++ b/src/graphics/vulkan/pal_vulkan.h @@ -10,7 +10,7 @@ #if PAL_HAS_VULKAN_BACKEND #include "graphics/pal_linear_allocator.h" -#include "pal/pal_graphics.h" +#include "pal2/pal_graphics.h" #include typedef struct _XDisplay Display; diff --git a/src/opengl/egl/pal_egl.h b/src/opengl/egl/pal_egl.h index 1742204c..6cbe0d2c 100644 --- a/src/opengl/egl/pal_egl.h +++ b/src/opengl/egl/pal_egl.h @@ -5,7 +5,7 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal/pal_opengl.h" +#include "pal2/pal_opengl.h" #ifndef _PAL_EGL_H #define _PAL_EGL_H diff --git a/src/opengl/pal_opengl.c b/src/opengl/pal_opengl.c index bdb1fc58..78f7692d 100644 --- a/src/opengl/pal_opengl.c +++ b/src/opengl/pal_opengl.c @@ -5,7 +5,7 @@ Licensed under the Zlib license. See LICENSE file in root. */ -#include "pal/pal_opengl.h" +#include "pal2/pal_opengl.h" #include "pal_opengl_backends.h" #include diff --git a/src/opengl/pal_opengl_backends.h b/src/opengl/pal_opengl_backends.h index 3b82f2e8..e2d49cd8 100644 --- a/src/opengl/pal_opengl_backends.h +++ b/src/opengl/pal_opengl_backends.h @@ -8,7 +8,7 @@ #ifndef _PAL_OPENGL_BACKENDS_H #define _PAL_OPENGL_BACKENDS_H -#include "pal/pal_opengl.h" +#include "pal2/pal_opengl.h" #include "pal_platform.h" // clang-format off diff --git a/src/opengl/pal_opengl_shared.h b/src/opengl/pal_opengl_shared.h index 745a12a3..82e4fd7a 100644 --- a/src/opengl/pal_opengl_shared.h +++ b/src/opengl/pal_opengl_shared.h @@ -8,7 +8,7 @@ #ifndef _PAL_OPENGL_SHARED_H #define _PAL_OPENGL_SHARED_H -#include "pal/pal_core.h" +#include "pal2/pal_core.h" PalBool checkString( const char* string, diff --git a/src/opengl/wgl/pal_wgl.h b/src/opengl/wgl/pal_wgl.h index 5e7a297e..f6df70e0 100644 --- a/src/opengl/wgl/pal_wgl.h +++ b/src/opengl/wgl/pal_wgl.h @@ -22,7 +22,7 @@ #define UNICODE #endif // UNICODE -#include "pal/pal_opengl.h" +#include "pal2/pal_opengl.h" #include #define PAL_GL_CLASS L"PALGLClass" diff --git a/src/system/linux/pal_cpu_linux.c b/src/system/linux/pal_cpu_linux.c index 4d98efee..93b7c27f 100644 --- a/src/system/linux/pal_cpu_linux.c +++ b/src/system/linux/pal_cpu_linux.c @@ -6,7 +6,7 @@ #ifdef __linux__ #define _POSIX_C_SOURCE 200112L -#include "pal/pal_system.h" +#include "pal2/pal_system.h" #include #include #include diff --git a/src/system/linux/pal_platform_linux.c b/src/system/linux/pal_platform_linux.c index 09f23985..ef3ab057 100644 --- a/src/system/linux/pal_platform_linux.c +++ b/src/system/linux/pal_platform_linux.c @@ -6,7 +6,7 @@ #ifdef __linux__ #define _POSIX_C_SOURCE 200112L -#include "pal/pal_system.h" +#include "pal2/pal_system.h" #include #include #include diff --git a/src/system/win32/pal_cpu_win32.c b/src/system/win32/pal_cpu_win32.c index 9b1c3630..83c62a7a 100644 --- a/src/system/win32/pal_cpu_win32.c +++ b/src/system/win32/pal_cpu_win32.c @@ -19,7 +19,7 @@ #define UNICODE #endif // UNICODE -#include "pal/pal_system.h" +#include "pal2/pal_system.h" #include #include diff --git a/src/system/win32/pal_platform_win32.c b/src/system/win32/pal_platform_win32.c index 7c078d18..5b52e2e9 100644 --- a/src/system/win32/pal_platform_win32.c +++ b/src/system/win32/pal_platform_win32.c @@ -19,7 +19,7 @@ #define UNICODE #endif // UNICODE -#include "pal/pal_system.h" +#include "pal2/pal_system.h" #include #include diff --git a/src/thread/posix/pal_thread_posix.h b/src/thread/posix/pal_thread_posix.h index a8a993e7..ae14211b 100644 --- a/src/thread/posix/pal_thread_posix.h +++ b/src/thread/posix/pal_thread_posix.h @@ -12,7 +12,7 @@ #if _PAL_HAS_POSIX #define _POSIX_C_SOURCE 200112L -#include "pal/pal_thread.h" +#include "pal2/pal_thread.h" #include #include #include diff --git a/src/thread/posix/pal_tls_posix.c b/src/thread/posix/pal_tls_posix.c index d2a3b4d3..98d516b4 100644 --- a/src/thread/posix/pal_tls_posix.c +++ b/src/thread/posix/pal_tls_posix.c @@ -8,7 +8,7 @@ #include "pal_platform.h" #if _PAL_HAS_POSIX -#include "pal/pal_thread.h" +#include "pal2/pal_thread.h" #include PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor) diff --git a/src/thread/win32/pal_thread_win32.h b/src/thread/win32/pal_thread_win32.h index 623257a5..b45499ff 100644 --- a/src/thread/win32/pal_thread_win32.h +++ b/src/thread/win32/pal_thread_win32.h @@ -22,7 +22,7 @@ #define UNICODE #endif // UNICODE -#include "pal/pal_thread.h" +#include "pal2/pal_thread.h" #include struct PalMutex { diff --git a/src/thread/win32/pal_tls_win32.c b/src/thread/win32/pal_tls_win32.c index 04fc6492..d56c68a8 100644 --- a/src/thread/win32/pal_tls_win32.c +++ b/src/thread/win32/pal_tls_win32.c @@ -19,7 +19,7 @@ #define UNICODE #endif // UNICODE -#include "pal/pal_thread.h" +#include "pal2/pal_thread.h" #include PalTLSId PAL_CALL palCreateTLS(PaTlsDestructorFn destructor) diff --git a/src/video/pal_video_backends.h b/src/video/pal_video_backends.h index 868bc5e7..e72076bb 100644 --- a/src/video/pal_video_backends.h +++ b/src/video/pal_video_backends.h @@ -7,7 +7,7 @@ #ifndef _PAL_VIDEO_BACKENDS_H #define _PAL_VIDEO_BACKENDS_H -#include "pal/pal_video.h" +#include "pal2/pal_video.h" // clang-format off typedef struct { diff --git a/src/video/wayland/pal_wayland.h b/src/video/wayland/pal_wayland.h index 9fed614b..ec99cac8 100644 --- a/src/video/wayland/pal_wayland.h +++ b/src/video/wayland/pal_wayland.h @@ -12,7 +12,7 @@ #define MAX_SPAN_MONITORS 4 -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "video/pal_video_egl.h" #include #include diff --git a/src/video/win32/pal_video_win32.h b/src/video/win32/pal_video_win32.h index 3f3aa980..de085d8c 100644 --- a/src/video/win32/pal_video_win32.h +++ b/src/video/win32/pal_video_win32.h @@ -22,7 +22,7 @@ #define UNICODE #endif // UNICODE -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include #define PAL_VIDEO_CLASS L"PALVideoClass" diff --git a/src/video/x11/pal_x11.h b/src/video/x11/pal_x11.h index 0a730492..5ebe50cf 100644 --- a/src/video/x11/pal_x11.h +++ b/src/video/x11/pal_x11.h @@ -13,7 +13,7 @@ #define TO_PAL_HANDLE(type, val) ((type*)(uintptr_t)(val)) #define FROM_PAL_HANDLE(type, handle) ((type)(uintptr_t)(handle)) -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "video/pal_video_egl.h" #include #include diff --git a/tests/event/event_test.c b/tests/event/event_test.c index 05b85727..374963dd 100644 --- a/tests/event/event_test.c +++ b/tests/event/event_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_event.h" +#include "pal2/pal_event.h" #include "tests.h" #define MAX_ITERATIONS 10 diff --git a/tests/event/user_event_test.c b/tests/event/user_event_test.c index fcd61c1e..856e4d31 100644 --- a/tests/event/user_event_test.c +++ b/tests/event/user_event_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_event.h" +#include "pal2/pal_event.h" #include "tests.h" #define USER_CLOSE_EVENT_ID 44568 diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index fc46b9be..a354765f 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -1,7 +1,7 @@ -#include "pal/pal_graphics.h" -#include "pal/pal_system.h" -#include "pal/pal_video.h" +#include "pal2/pal_graphics.h" +#include "pal2/pal_system.h" +#include "pal2/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index 73888c21..d9a2c2de 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_graphics.h" +#include "pal2/pal_graphics.h" #include "tests.h" #define BUFFER_SIZE 400 diff --git a/tests/graphics/custom_backend_test.c b/tests/graphics/custom_backend_test.c index 86847353..7715f253 100644 --- a/tests/graphics/custom_backend_test.c +++ b/tests/graphics/custom_backend_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_graphics.h" +#include "pal2/pal_graphics.h" #include "tests.h" // we use the same fields for each of our handles so we just typedef a base handle struct diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index 5512f4ab..a7b561d9 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -1,7 +1,7 @@ -#include "pal/pal_graphics.h" -#include "pal/pal_system.h" -#include "pal/pal_video.h" +#include "pal2/pal_graphics.h" +#include "pal2/pal_system.h" +#include "pal2/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index fc0ecba3..4d3cb169 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -1,7 +1,7 @@ -#include "pal/pal_graphics.h" -#include "pal/pal_system.h" -#include "pal/pal_video.h" +#include "pal2/pal_graphics.h" +#include "pal2/pal_system.h" +#include "pal2/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 diff --git a/tests/graphics/graphics_test.c b/tests/graphics/graphics_test.c index 7e5e871f..86ad96dc 100644 --- a/tests/graphics/graphics_test.c +++ b/tests/graphics/graphics_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_graphics.h" +#include "pal2/pal_graphics.h" #include "tests.h" PalBool graphicsTest() diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index 18e0443a..a9cfc498 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -1,7 +1,7 @@ -#include "pal/pal_graphics.h" -#include "pal/pal_system.h" -#include "pal/pal_video.h" +#include "pal2/pal_graphics.h" +#include "pal2/pal_system.h" +#include "pal2/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 8901fca7..5ae0cee4 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -1,7 +1,7 @@ -#include "pal/pal_graphics.h" -#include "pal/pal_system.h" -#include "pal/pal_video.h" +#include "pal2/pal_graphics.h" +#include "pal2/pal_system.h" +#include "pal2/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 2339a680..7a76e52f 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_graphics.h" +#include "pal2/pal_graphics.h" #include "tests.h" #define BUFFER_SIZE 400 diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index aa95e589..38f7697c 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_graphics.h" +#include "pal2/pal_graphics.h" #include "tests.h" #define BUFFER_SIZE 400 diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 39e94295..7b4ccd7e 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -1,7 +1,7 @@ -#include "pal/pal_graphics.h" -#include "pal/pal_system.h" -#include "pal/pal_video.h" +#include "pal2/pal_graphics.h" +#include "pal2/pal_system.h" +#include "pal2/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index 81a07f11..caabb3b8 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -1,7 +1,7 @@ -#include "pal/pal_graphics.h" -#include "pal/pal_system.h" -#include "pal/pal_video.h" +#include "pal2/pal_graphics.h" +#include "pal2/pal_system.h" +#include "pal2/pal_video.h" #include "tests.h" #define WINDOW_WIDTH 640 diff --git a/tests/opengl/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c index d363611c..ad621b01 100644 --- a/tests/opengl/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -1,7 +1,7 @@ -#include "pal/pal_opengl.h" -#include "pal/pal_thread.h" -#include "pal/pal_video.h" +#include "pal2/pal_opengl.h" +#include "pal2/pal_thread.h" +#include "pal2/pal_video.h" #include "tests.h" // opengl typedefs diff --git a/tests/opengl/opengl_context_test.c b/tests/opengl/opengl_context_test.c index 6413caf8..d307505b 100644 --- a/tests/opengl/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -1,6 +1,6 @@ -#include "pal/pal_opengl.h" -#include "pal/pal_video.h" // for window +#include "pal2/pal_opengl.h" +#include "pal2/pal_video.h" // for window #include "tests.h" static const char* g_BoolsToSting[2] = {"False", "True"}; diff --git a/tests/opengl/opengl_fbconfig_test.c b/tests/opengl/opengl_fbconfig_test.c index 68e96048..ec7f33f9 100644 --- a/tests/opengl/opengl_fbconfig_test.c +++ b/tests/opengl/opengl_fbconfig_test.c @@ -1,6 +1,6 @@ -#include "pal/pal_opengl.h" -#include "pal/pal_video.h" // for window +#include "pal2/pal_opengl.h" +#include "pal2/pal_video.h" // for window #include "tests.h" static const char* g_BoolsToSting[2] = {"False", "True"}; diff --git a/tests/opengl/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c index f69b6b9d..0f8c3029 100644 --- a/tests/opengl/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -1,6 +1,6 @@ -#include "pal/pal_opengl.h" -#include "pal/pal_video.h" // for window +#include "pal2/pal_opengl.h" +#include "pal2/pal_video.h" // for window #include "tests.h" static const char* g_BoolsToSting[2] = {"False", "True"}; diff --git a/tests/opengl/opengl_test.c b/tests/opengl/opengl_test.c index cf0c0411..d7c062fd 100644 --- a/tests/opengl/opengl_test.c +++ b/tests/opengl/opengl_test.c @@ -1,6 +1,6 @@ -#include "pal/pal_opengl.h" -#include "pal/pal_video.h" +#include "pal2/pal_opengl.h" +#include "pal2/pal_video.h" #include "tests.h" PalBool openglTest() diff --git a/tests/system/cpu_test.c b/tests/system/cpu_test.c index 96c1915b..4ee60358 100644 --- a/tests/system/cpu_test.c +++ b/tests/system/cpu_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_system.h" +#include "pal2/pal_system.h" #include "tests.h" #include // for strcat diff --git a/tests/system/platform_test.c b/tests/system/platform_test.c index 917d20b2..7986eb91 100644 --- a/tests/system/platform_test.c +++ b/tests/system/platform_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_system.h" +#include "pal2/pal_system.h" #include "tests.h" static inline const char* platformToString(PalPlatformType type) diff --git a/tests/tests.h b/tests/tests.h index 91feb1b7..a9fe2a54 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -2,7 +2,7 @@ #ifndef _TESTS_H #define _TESTS_H -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #include typedef PalBool (*TestFn)(); diff --git a/tests/tests.lua b/tests/tests.lua index 53917dc0..4564368f 100644 --- a/tests/tests.lua +++ b/tests/tests.lua @@ -94,4 +94,4 @@ project "tests" "%{wks.location}/tests" } - links { "PAL" } + links { "PAL2" } diff --git a/tests/thread/condvar_test.c b/tests/thread/condvar_test.c index 167878fe..83a200c1 100644 --- a/tests/thread/condvar_test.c +++ b/tests/thread/condvar_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_thread.h" +#include "pal2/pal_thread.h" #include "tests.h" #define THREAD_COUNT 4 diff --git a/tests/thread/mutex_test.c b/tests/thread/mutex_test.c index 48c282f0..4bbafdab 100644 --- a/tests/thread/mutex_test.c +++ b/tests/thread/mutex_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_thread.h" +#include "pal2/pal_thread.h" #include "tests.h" #define MAX_COUNTER 10000 diff --git a/tests/thread/thread_test.c b/tests/thread/thread_test.c index 5ef63d2a..73054d4e 100644 --- a/tests/thread/thread_test.c +++ b/tests/thread/thread_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_thread.h" +#include "pal2/pal_thread.h" #include "tests.h" #define THREAD_TIME 1000 diff --git a/tests/thread/tls_test.c b/tests/thread/tls_test.c index 206b0c53..87e9e73e 100644 --- a/tests/thread/tls_test.c +++ b/tests/thread/tls_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_thread.h" +#include "pal2/pal_thread.h" #include "tests.h" // data every thread will have its own copy of diff --git a/tests/video/attach_window_test.c b/tests/video/attach_window_test.c index ad0ed578..ed873c0d 100644 --- a/tests/video/attach_window_test.c +++ b/tests/video/attach_window_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" #ifdef _WIN32 diff --git a/tests/video/char_event_test.c b/tests/video/char_event_test.c index 30ef2a82..641e8db3 100644 --- a/tests/video/char_event_test.c +++ b/tests/video/char_event_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" PalBool charEventTest() diff --git a/tests/video/cursor_test.c b/tests/video/cursor_test.c index 2cde06da..3e355dab 100644 --- a/tests/video/cursor_test.c +++ b/tests/video/cursor_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" PalBool cursorTest() diff --git a/tests/video/custom_decoration_test.c b/tests/video/custom_decoration_test.c index 31415d8c..8740c531 100644 --- a/tests/video/custom_decoration_test.c +++ b/tests/video/custom_decoration_test.c @@ -2,7 +2,7 @@ #ifdef __linux__ #define _GNU_SOURCE #define _POSIX_C_SOURCE 200112L // for linux -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" #include @@ -834,7 +834,7 @@ static void PAL_CALL onEvent( } #else -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #endif // __linux__ PalBool customDecorationTest() diff --git a/tests/video/icon_test.c b/tests/video/icon_test.c index 74d1af70..e06fd194 100644 --- a/tests/video/icon_test.c +++ b/tests/video/icon_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" PalBool iconTest() diff --git a/tests/video/input_window_test.c b/tests/video/input_window_test.c index 93656f8f..bc84ad3b 100644 --- a/tests/video/input_window_test.c +++ b/tests/video/input_window_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" #define DISPATCH_MODE_POLL 0 diff --git a/tests/video/monitor_mode_test.c b/tests/video/monitor_mode_test.c index 92881c95..5ab02744 100644 --- a/tests/video/monitor_mode_test.c +++ b/tests/video/monitor_mode_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" PalBool monitorModeTest() diff --git a/tests/video/monitor_test.c b/tests/video/monitor_test.c index fed27c0c..b2cf099f 100644 --- a/tests/video/monitor_test.c +++ b/tests/video/monitor_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" PalBool monitorTest() diff --git a/tests/video/native_instance_test.c b/tests/video/native_instance_test.c index 18c0daf3..08381cbc 100644 --- a/tests/video/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" #ifdef _WIN32 diff --git a/tests/video/native_integration_test.c b/tests/video/native_integration_test.c index ea8b7cfb..d8156b12 100644 --- a/tests/video/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" #ifdef _WIN32 diff --git a/tests/video/system_cursor_test.c b/tests/video/system_cursor_test.c index afa883f1..ed63cd72 100644 --- a/tests/video/system_cursor_test.c +++ b/tests/video/system_cursor_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" PalBool systemCursorTest() diff --git a/tests/video/video_test.c b/tests/video/video_test.c index fef72a7b..6bc23f84 100644 --- a/tests/video/video_test.c +++ b/tests/video/video_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" PalBool videoTest() diff --git a/tests/video/window_test.c b/tests/video/window_test.c index e8f99408..1707fa72 100644 --- a/tests/video/window_test.c +++ b/tests/video/window_test.c @@ -1,5 +1,5 @@ -#include "pal/pal_video.h" +#include "pal2/pal_video.h" #include "tests.h" // make the window borderless if supported diff --git a/tools/abi_dump/abi_dump.lua b/tools/abi_dump/abi_dump.lua index a633bdfc..0dd558f2 100644 --- a/tools/abi_dump/abi_dump.lua +++ b/tools/abi_dump/abi_dump.lua @@ -21,4 +21,4 @@ project "abi-dump" "%{wks.location}/tools/abi_dump" } - links { "PAL" } + links { "PAL2" } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index cfe0c715..f08cfe2a 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -12,10 +12,31 @@ #ifdef _WIN32 #define EXE_NAME "abi-dump.exe" +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX +#include + +#define DLL_HANDLE HMODULE +#define LOAD_DLL(path) LoadLibraryA("PAL2.dll") +#define FREE_DLL(handle) FreeLibrary(handle) +#define GET_FUNC(handle, name) GetProcAddress(handle, name) + #else #define EXE_NAME "abi-dump" +#include + +#define DLL_HANDLE void* +#define LOAD_DLL dlopen("libPAL2.so", RTLD_LAZY) +#define FREE_DLL(handle) dlclose(handle) +#define GET_FUNC(handle, name) dlsym(handle, name) #endif // _WIN32 +typedef void (PAL_CALL* GetVersionFn)(PalVersion* version); + static int logDumpStatus(PalBool status) { int ret = -1; @@ -29,6 +50,55 @@ static int logDumpStatus(PalBool status) return ret; } +static PalBool checkPALVersion(uint32_t flags) +{ + GetVersionFn getVersion = nullptr; + DLL_HANDLE handle = LOAD_DLL; + if (!handle) { + palLog(nullptr, "Failed to load PAL library"); + return PAL_FALSE; + } + + getVersion = GET_FUNC(handle, "palGetVersion"); + if (!getVersion) { + palLog(nullptr, "Failed to load palGetVersion in PAL library"); + FREE_DLL(handle); + return PAL_FALSE; + } + + PalVersion version; + getVersion(&version); + FREE_DLL(handle); + + if (!(flags & DUMP_FLAG_QUICK)) { + palLog(nullptr, ""); + palLog(nullptr, "==========================================="); + palLog(nullptr, "PAL ABI Dump"); + palLog(nullptr, "==========================================="); + palLog(nullptr, ""); + } + + if (strcmp(VERSION, "1.0") == 0) { + // ABI Dump v1.0 == PAL v2.0.0 + if (version.major == 2 && version.minor == 0 && version.build == 0) { + if (flags & DUMP_FLAG_VERBOSE) { + palLog(nullptr, "Expected PAL Version: 2.0.0"); + palLog( + nullptr, + "Actual PAL Version: %d.%d.%d", + version.major, + version.minor, + version.build); + + palLog(nullptr, "Target Library: PAL2"); + } + return PAL_TRUE; + } + } + + return PAL_FALSE; +} + // clang-format off int main(int argc, char** argv) { @@ -82,6 +152,15 @@ int main(int argc, char** argv) dumps |= DUMP_FLAG_ALL; } + status = checkPALVersion(flags); + if (!status) { + if (flags & DUMP_FLAG_QUICK) { + return logDumpStatus(status); + } else { + return -1; + } + } + if (dumps & DUMP_FLAG_CORE) { status = coreABIDump(flags); if (status) { diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 29c8d838..788659ee 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -8,7 +8,7 @@ #ifndef _DUMPS_H #define _DUMPS_H -#include "pal/pal_core.h" +#include "pal2/pal_core.h" #include static const char* s_FailedString = "FAILED"; diff --git a/tools/abi_dump/event_abi_dump.c b/tools/abi_dump/event_abi_dump.c index 5e0151cb..d38fa93d 100644 --- a/tools/abi_dump/event_abi_dump.c +++ b/tools/abi_dump/event_abi_dump.c @@ -6,7 +6,7 @@ */ #include "dumps.h" -#include "pal/pal_event.h" +#include "pal2/pal_event.h" PalBool eventABIDump(uint32_t flags) { diff --git a/tools/abi_dump/graphics_abi_dump.c b/tools/abi_dump/graphics_abi_dump.c index 1b2a58e1..a7d891ad 100644 --- a/tools/abi_dump/graphics_abi_dump.c +++ b/tools/abi_dump/graphics_abi_dump.c @@ -6,7 +6,7 @@ */ #include "dumps.h" -#include "pal/pal_graphics.h" +#include "pal2/pal_graphics.h" static PalBool adapterDump(uint32_t flags) { diff --git a/tools/abi_dump/opengl_abi_dump.c b/tools/abi_dump/opengl_abi_dump.c index e6c177fc..e3a6c5eb 100644 --- a/tools/abi_dump/opengl_abi_dump.c +++ b/tools/abi_dump/opengl_abi_dump.c @@ -6,7 +6,7 @@ */ #include "dumps.h" -#include "pal/pal_opengl.h" +#include "pal2/pal_opengl.h" PalBool openglABIDump(uint32_t flags) { diff --git a/tools/abi_dump/system_abi_dump.c b/tools/abi_dump/system_abi_dump.c index 1f9f25c9..1eee93ab 100644 --- a/tools/abi_dump/system_abi_dump.c +++ b/tools/abi_dump/system_abi_dump.c @@ -6,7 +6,7 @@ */ #include "dumps.h" -#include "pal/pal_system.h" +#include "pal2/pal_system.h" PalBool systemABIDump(uint32_t flags) { diff --git a/tools/abi_dump/thread_abi_dump.c b/tools/abi_dump/thread_abi_dump.c index ca576b09..ca3c335d 100644 --- a/tools/abi_dump/thread_abi_dump.c +++ b/tools/abi_dump/thread_abi_dump.c @@ -6,7 +6,7 @@ */ #include "dumps.h" -#include "pal/pal_thread.h" +#include "pal2/pal_thread.h" PalBool threadABIDump(uint32_t flags) { diff --git a/tools/abi_dump/video_abi_dump.c b/tools/abi_dump/video_abi_dump.c index ffbbe473..9456f8ac 100644 --- a/tools/abi_dump/video_abi_dump.c +++ b/tools/abi_dump/video_abi_dump.c @@ -6,7 +6,7 @@ */ #include "dumps.h" -#include "pal/pal_video.h" +#include "pal2/pal_video.h" PalBool videoABIDump(uint32_t flags) { From 1d9bdc1f0d9efa55e28ff04919ae663cf887a187 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 26 Jul 2026 10:31:31 -0700 Subject: [PATCH 369/372] fix clang and msvc warnings and errors --- src/graphics/d3d12/pal_buffer_d3d12.c | 4 ++-- src/graphics/d3d12/pal_commands_d3d12.c | 6 +++--- src/graphics/d3d12/pal_d3d12.c | 4 ++-- src/graphics/d3d12/pal_descriptors_d3d12.c | 12 ++++++------ src/graphics/d3d12/pal_pipeline_d3d12.c | 6 +++--- src/graphics/d3d12/pal_sbt_d3d12.c | 20 ++++++++++---------- src/graphics/pal_graphics.c | 18 +++++++++--------- src/graphics/pal_linear_allocator.h | 10 +++++----- src/graphics/vulkan/pal_sbt_vulkan.c | 20 ++++++++++---------- src/video/pal_video.c | 8 ++++---- src/video/win32/pal_video_win32.c | 6 +++--- tests/graphics/clear_color_test.c | 2 +- tests/graphics/compute_test.c | 4 ++-- tests/graphics/descriptor_indexing_test.c | 4 ++-- tests/graphics/geometry_test.c | 4 ++-- tests/graphics/indirect_draw_test.c | 4 ++-- tests/graphics/mesh_test.c | 4 ++-- tests/graphics/multi_descriptor_set_test.c | 4 ++-- tests/graphics/ray_tracing_test.c | 6 +++--- tests/graphics/texture_test.c | 4 ++-- tests/graphics/triangle_test.c | 4 ++-- tests/opengl/multi_thread_opengl_test.c | 2 +- tests/opengl/opengl_context_test.c | 2 +- tests/opengl/opengl_fbconfig_test.c | 2 +- tests/opengl/opengl_multi_context_test.c | 2 +- tests/tests.h | 6 +++--- tools/abi_dump/abi_dump_main.c | 4 ++-- tools/abi_dump/dumps.h | 4 ++-- 28 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/graphics/d3d12/pal_buffer_d3d12.c b/src/graphics/d3d12/pal_buffer_d3d12.c index dc079b3b..75ba9c87 100644 --- a/src/graphics/d3d12/pal_buffer_d3d12.c +++ b/src/graphics/d3d12/pal_buffer_d3d12.c @@ -8,7 +8,7 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" -#define align(v, a) (v + a - 1) & ~(a - 1) +#define _ALIGN(v, a) (v + a - 1) & ~(a - 1) static uint32_t getSupportedMemoryTypes(PalBufferUsages usages) { @@ -184,7 +184,7 @@ void PAL_CALL computeImageStagingRequirementsD3D12( PalImageStagingRequirements* requirements) { uint32_t imageFormatSize = getFormatSizeD3D12(imageFormat); - uint32_t rowPitch = align((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + uint32_t rowPitch = _ALIGN((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); uint32_t bufferImageHeight = 0; if (copyInfo->bufferImageHeight) { bufferImageHeight = copyInfo->bufferImageHeight; diff --git a/src/graphics/d3d12/pal_commands_d3d12.c b/src/graphics/d3d12/pal_commands_d3d12.c index 8fce796f..cc864568 100644 --- a/src/graphics/d3d12/pal_commands_d3d12.c +++ b/src/graphics/d3d12/pal_commands_d3d12.c @@ -8,7 +8,7 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" -#define align(v, a) (v + a - 1) & ~(a - 1) +#define _ALIGN(v, a) (v + a - 1) & ~(a - 1) static D3D12_RENDER_PASS_FLAGS renderingFlagToD3D12(PalRenderingFlags flags) { @@ -503,7 +503,7 @@ void PAL_CALL cmdCopyBufferToImageD3D12( footPrint->Footprint.Format = formatToD3D12(dst->info.format); uint32_t imageFormatSize = getFormatSizeD3D12(dst->info.format); - uint64_t rowPitch = align((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + uint64_t rowPitch = _ALIGN((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); footPrint->Footprint.RowPitch = (UINT)rowPitch; uint32_t planeCount = 1; @@ -628,7 +628,7 @@ void PAL_CALL cmdCopyImageToBufferD3D12( srcLocation.pResource = src->handle; uint32_t imageFormatSize = getFormatSizeD3D12(src->info.format); - uint64_t rowPitch = align((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); + uint64_t rowPitch = _ALIGN((uint64_t)copyInfo->imageWidth * imageFormatSize, TEXTURE_PITCH); footPrint->Footprint.RowPitch = (UINT)rowPitch; D3D12_BOX box = {0}; diff --git a/src/graphics/d3d12/pal_d3d12.c b/src/graphics/d3d12/pal_d3d12.c index 7eb4e6a8..d1d4803c 100644 --- a/src/graphics/d3d12/pal_d3d12.c +++ b/src/graphics/d3d12/pal_d3d12.c @@ -694,7 +694,7 @@ void fillBuildInfoD3D12( tmp->Triangles.Transform3x4 = tmpData->transformBufferAddress; tmp->Triangles.IndexBuffer = tmpData->indexBufferAddress; - tmp->Triangles.IndexCount = info->geometries[i].primitiveCount * 3; + tmp->Triangles.IndexCount = (UINT)info->geometries[i].primitiveCount * 3; if (tmpData->indexType == PAL_INDEX_TYPE_UINT16) { if (tmp->Triangles.IndexBuffer) { tmp->Triangles.IndexFormat = DXGI_FORMAT_R16_FLOAT; @@ -1160,4 +1160,4 @@ void PAL_CALL shutdownGraphicsD3D12() memset(&s_D3D12, 0, sizeof(s_D3D12)); } -#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file +#endif // PAL_HAS_D3D12_BACKEND diff --git a/src/graphics/d3d12/pal_descriptors_d3d12.c b/src/graphics/d3d12/pal_descriptors_d3d12.c index b2e3bf0e..e96cdf18 100644 --- a/src/graphics/d3d12/pal_descriptors_d3d12.c +++ b/src/graphics/d3d12/pal_descriptors_d3d12.c @@ -558,7 +558,7 @@ PalResult PAL_CALL updateDescriptorSetD3D12( if (info->bufferInfos) { PalDescriptorBufferInfo* bufferInfo = &info->bufferInfos[j]; BufferD3D12* buffer = (BufferD3D12*)bufferInfo->buffer; - desc.SizeInBytes = bufferInfo->size; + desc.SizeInBytes = (UINT)bufferInfo->size; address = buffer->handle->lpVtbl->GetGPUVirtualAddress(buffer->handle); desc.BufferLocation = address + bufferInfo->offset; } @@ -580,16 +580,16 @@ PalResult PAL_CALL updateDescriptorSetD3D12( uint32_t stride = 4; if (bufferInfo->stride) { - stride = bufferInfo->stride; - desc.Buffer.StructureByteStride = bufferInfo->stride; + stride = (UINT)bufferInfo->stride; + desc.Buffer.StructureByteStride = stride; } else { desc.Format = DXGI_FORMAT_R32_TYPELESS; desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; } handle = buffer->handle; - desc.Buffer.FirstElement = bufferInfo->offset / stride; - desc.Buffer.NumElements = bufferInfo->size / stride; + desc.Buffer.FirstElement = (UINT)bufferInfo->offset / stride; + desc.Buffer.NumElements = (UINT)bufferInfo->size / stride; } deviceImpl->handle->lpVtbl @@ -600,4 +600,4 @@ PalResult PAL_CALL updateDescriptorSetD3D12( return PAL_RESULT_SUCCESS; } -#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file +#endif // PAL_HAS_D3D12_BACKEND diff --git a/src/graphics/d3d12/pal_pipeline_d3d12.c b/src/graphics/d3d12/pal_pipeline_d3d12.c index 5f2d172a..a8aa98c7 100644 --- a/src/graphics/d3d12/pal_pipeline_d3d12.c +++ b/src/graphics/d3d12/pal_pipeline_d3d12.c @@ -8,7 +8,7 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" -#define align(v, a) (v + a - 1) & ~(a - 1) +#define _ALIGN(v, a) (v + a - 1) & ~(a - 1) #if INTPTR_MAX == INT64_MAX #define PTR_SIZE 8 @@ -1344,7 +1344,7 @@ PalResult PAL_CALL createRayTracingPipelineD3D12( if (localRootSize) { D3D12_ROOT_PARAMETER1 parameter = {0}; parameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; - parameter.Constants.Num32BitValues = align(localRootSize, 4) / 4; + parameter.Constants.Num32BitValues = _ALIGN(localRootSize, 4) / 4; parameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootDesc = {0}; @@ -1447,4 +1447,4 @@ void PAL_CALL destroyPipelineD3D12(PalPipeline* pipeline) palFree(s_D3D12.allocator, pipelineImpl); } -#endif // PAL_HAS_D3D12_BACKEND \ No newline at end of file +#endif // PAL_HAS_D3D12_BACKEND diff --git a/src/graphics/d3d12/pal_sbt_d3d12.c b/src/graphics/d3d12/pal_sbt_d3d12.c index 84e64f88..8a757656 100644 --- a/src/graphics/d3d12/pal_sbt_d3d12.c +++ b/src/graphics/d3d12/pal_sbt_d3d12.c @@ -8,7 +8,7 @@ #if PAL_HAS_D3D12_BACKEND #include "pal_d3d12.h" -#define align(v, a) (v + a - 1) & ~(a - 1) +#define _ALIGN(v, a) (v + a - 1) & ~(a - 1) PalResult PAL_CALL createShaderBindingTableD3D12( PalDevice* device, @@ -116,10 +116,10 @@ PalResult PAL_CALL createShaderBindingTableD3D12( uint32_t hitStride = 0; uint32_t callableStride = 0; - raygenStride = align(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); - missStride = align(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); - hitStride = align(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); - callableStride = align(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); + raygenStride = _ALIGN(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); + missStride = _ALIGN(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); + hitStride = _ALIGN(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); + callableStride = _ALIGN(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); // get region size uint32_t raygenRegionSize = raygenStride * sbtInfo->raygenCount; @@ -134,18 +134,18 @@ PalResult PAL_CALL createShaderBindingTableD3D12( uint32_t hitOffset = 0; uint32_t callableOffset = 0; - raygenOffset = align(offset, groupBaseAlignment); + raygenOffset = _ALIGN(offset, groupBaseAlignment); offset = raygenOffset + raygenRegionSize; - missOffset = align(offset, groupBaseAlignment); + missOffset = _ALIGN(offset, groupBaseAlignment); offset = missOffset + missRegionSize; - hitOffset = align(offset, groupBaseAlignment); + hitOffset = _ALIGN(offset, groupBaseAlignment); offset = hitOffset + hitRegionSize; - callableOffset = align(offset, groupBaseAlignment); + callableOffset = _ALIGN(offset, groupBaseAlignment); offset = callableOffset + callableRegionSize; - uint32_t bufferSize = align(offset, groupBaseAlignment); + uint32_t bufferSize = _ALIGN(offset, groupBaseAlignment); // create gpu buffer D3D12_HEAP_PROPERTIES heapProps = {0}; diff --git a/src/graphics/pal_graphics.c b/src/graphics/pal_graphics.c index f068fb45..6331d117 100644 --- a/src/graphics/pal_graphics.c +++ b/src/graphics/pal_graphics.c @@ -299,7 +299,7 @@ PalResult PAL_CALL palEnumerateAdapters( PalResult result = 0; int totalCount = 0; int index = 0; - int _count = 0; + uint32_t _count = 0; for (int i = 0; i < s_Graphics.backendCount; i++) { BackendData* backend = &s_Graphics.backends[i]; @@ -396,7 +396,7 @@ void PAL_CALL palDestroyDevice(PalDevice* device) uint32_t PAL_CALL palGetDeviceLostReason(PalDevice* device) { - device->backend.vtbl1->getDeviceLostReason(device); + return (uint32_t)device->backend.vtbl1->getDeviceLostReason(device); } PalResult PAL_CALL palAllocateMemory( @@ -521,7 +521,7 @@ PalBool PAL_CALL palCanQueuePresent( PalQueue* queue, PalSurface* surface) { - queue->backend.vtbl1->canQueuePresent(queue, surface); + return queue->backend.vtbl1->canQueuePresent(queue, surface); } PalResult PAL_CALL palWaitQueue(PalQueue* queue) @@ -545,21 +545,21 @@ PalBool PAL_CALL palIsFormatSupported( PalAdapter* adapter, PalFormat format) { - adapter->backend.vtbl1->isFormatSupported(adapter, format); + return adapter->backend.vtbl1->isFormatSupported(adapter, format); } PalImageUsages PAL_CALL palQueryFormatImageUsages( PalAdapter* adapter, PalFormat format) { - adapter->backend.vtbl1->queryFormatImageUsages(adapter, format); + return adapter->backend.vtbl1->queryFormatImageUsages(adapter, format); } PalSampleCount PAL_CALL palQueryFormatSampleCount( PalAdapter* adapter, PalFormat format) { - adapter->backend.vtbl1->queryFormatSampleCount(adapter, format); + return adapter->backend.vtbl1->queryFormatSampleCount(adapter, format); } // ================================================== @@ -611,7 +611,7 @@ PalResult PAL_CALL palBindImageMemory( PalMemory* memory, uint64_t offset) { - image->backend.vtbl1->bindImageMemory(image, memory, offset); + return image->backend.vtbl1->bindImageMemory(image, memory, offset); } // ================================================== @@ -992,12 +992,12 @@ PalResult PAL_CALL palCmdBegin( PalCommandBuffer* cmdBuffer, PalRenderingLayoutInfo* info) { - cmdBuffer->backend.vtbl1->cmdBegin(cmdBuffer, info); + return cmdBuffer->backend.vtbl1->cmdBegin(cmdBuffer, info); } PalResult PAL_CALL palCmdEnd(PalCommandBuffer* cmdBuffer) { - cmdBuffer->backend.vtbl1->cmdEnd(cmdBuffer); + return cmdBuffer->backend.vtbl1->cmdEnd(cmdBuffer); } void PAL_CALL palCmdExecuteCommandBuffer( diff --git a/src/graphics/pal_linear_allocator.h b/src/graphics/pal_linear_allocator.h index bbbbe636..61d2a9ed 100644 --- a/src/graphics/pal_linear_allocator.h +++ b/src/graphics/pal_linear_allocator.h @@ -10,7 +10,7 @@ #include "pal2/pal_core.h" -#define align(v, a) (v + a - 1) & ~(a - 1) +#define _ALIGN(v, a) (v + a - 1) & ~(a - 1) typedef struct { uint8_t* memory; @@ -23,12 +23,12 @@ static void* palLinearAlloc( uint64_t size, uint64_t alignment) { - uint64_t defAlign = alignment; + uint64_t defaultAlign = alignment; if (alignment == 0) { - defAlign = 16; + defaultAlign = 16; } - uint64_t offset = align(allocator->offset, defAlign); + uint64_t offset = _ALIGN(allocator->offset, defaultAlign); if (offset + size > allocator->size) { // allocate a bigger block void* block = palAllocate(nullptr, allocator->size * 2, 0); @@ -47,4 +47,4 @@ static void* palLinearAlloc( return ptr; } -#endif // _PAL_LINEAR_ALLOCATOR_H \ No newline at end of file +#endif // _PAL_LINEAR_ALLOCATOR_H diff --git a/src/graphics/vulkan/pal_sbt_vulkan.c b/src/graphics/vulkan/pal_sbt_vulkan.c index 382557b7..68e530cd 100644 --- a/src/graphics/vulkan/pal_sbt_vulkan.c +++ b/src/graphics/vulkan/pal_sbt_vulkan.c @@ -8,7 +8,7 @@ #if PAL_HAS_VULKAN_BACKEND #include "pal_vulkan.h" -#define align(v, a) (v + a - 1) & ~(a - 1) +#define _ALIGN(v, a) (v + a - 1) & ~(a - 1) PalResult PAL_CALL createShaderBindingTableVk( PalDevice* device, @@ -78,10 +78,10 @@ PalResult PAL_CALL createShaderBindingTableVk( // get strides uint32_t callableStride = 0; - uint32_t raygenStride = align(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); - uint32_t missStride = align(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); - uint32_t hitStride = align(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); - callableStride = align(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); + uint32_t raygenStride = _ALIGN(groupHandleSize + sbtInfo->raygenDataSize, groupHandleAlignment); + uint32_t missStride = _ALIGN(groupHandleSize + sbtInfo->missDataSize, groupHandleAlignment); + uint32_t hitStride = _ALIGN(groupHandleSize + sbtInfo->hitDataSize, groupHandleAlignment); + callableStride = _ALIGN(groupHandleSize + sbtInfo->callableDataSize, groupHandleAlignment); // get region size uint32_t raygenRegionSize = raygenStride * sbtInfo->raygenCount; @@ -96,19 +96,19 @@ PalResult PAL_CALL createShaderBindingTableVk( uint32_t hitOffset = 0; uint32_t callableOffset = 0; - raygenOffset = align(offset, groupBaseAlignment); + raygenOffset = _ALIGN(offset, groupBaseAlignment); offset = raygenOffset + raygenRegionSize; - missOffset = align(offset, groupBaseAlignment); + missOffset = _ALIGN(offset, groupBaseAlignment); offset = missOffset + missRegionSize; - hitOffset = align(offset, groupBaseAlignment); + hitOffset = _ALIGN(offset, groupBaseAlignment); offset = hitOffset + hitRegionSize; - callableOffset = align(offset, groupBaseAlignment); + callableOffset = _ALIGN(offset, groupBaseAlignment); offset = callableOffset + callableRegionSize; - uint32_t bufferSize = align(offset, groupBaseAlignment); + uint32_t bufferSize = _ALIGN(offset, groupBaseAlignment); // create gpu buffer VkBufferCreateInfo bufCreateInfo = {0}; diff --git a/src/video/pal_video.c b/src/video/pal_video.c index 25d0e3d1..486c9cf6 100644 --- a/src/video/pal_video.c +++ b/src/video/pal_video.c @@ -138,7 +138,7 @@ PalResult PAL_CALL palEnumerateMonitors( void PAL_CALL palGetPrimaryMonitor(PalMonitor** outMonitor) { - return s_Backend->getPrimaryMonitor(outMonitor); + s_Backend->getPrimaryMonitor(outMonitor); } void PAL_CALL palGetMonitorInfo( @@ -164,7 +164,7 @@ void PAL_CALL palGetCurrentMonitorMode( PalMonitor* monitor, PalMonitorMode* mode) { - return s_Backend->getCurrentMonitorMode(monitor, mode); + s_Backend->getCurrentMonitorMode(monitor, mode); } PalResult PAL_CALL palSetMonitorMode( @@ -201,7 +201,7 @@ PalResult PAL_CALL palCreateWindow( void PAL_CALL palDestroyWindow(PalWindow* window) { - return s_Backend->destroyWindow(window); + s_Backend->destroyWindow(window); } void PAL_CALL palMinimizeWindow(PalWindow* window) @@ -480,4 +480,4 @@ PalResult PAL_CALL palDetachWindow( void* PAL_CALL palGetInstance() { return s_Backend->getInstance(); -} \ No newline at end of file +} diff --git a/src/video/win32/pal_video_win32.c b/src/video/win32/pal_video_win32.c index db071673..3c61d19c 100644 --- a/src/video/win32/pal_video_win32.c +++ b/src/video/win32/pal_video_win32.c @@ -287,7 +287,7 @@ LRESULT CALLBACK videoProc( if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = PAL_EVENT_TYPE_MOUSE_WHEEL; - event.data = palPackFloat(s_Mouse.WheelX, 0); + event.data = palPackFloat((float)s_Mouse.WheelX, 0); event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); } @@ -305,7 +305,7 @@ LRESULT CALLBACK videoProc( if (mode != PAL_DISPATCH_MODE_NONE) { PalEvent event = {0}; event.type = PAL_EVENT_TYPE_MOUSE_WHEEL; - event.data = palPackFloat(0, s_Mouse.WheelY); + event.data = palPackFloat(0, (float)s_Mouse.WheelY); event.data2 = palPackPointer((PalWindow*)hwnd); palPushEvent(driver, &event); } @@ -1036,4 +1036,4 @@ void* win32GetInstance() return (void*)s_Win32.instance; } -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 diff --git a/tests/graphics/clear_color_test.c b/tests/graphics/clear_color_test.c index a354765f..a16dedca 100644 --- a/tests/graphics/clear_color_test.c +++ b/tests/graphics/clear_color_test.c @@ -104,7 +104,7 @@ PalBool clearColorTest() } // enumerate all available adapters - int32_t adapterCount = 0; + uint32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get adapters"); diff --git a/tests/graphics/compute_test.c b/tests/graphics/compute_test.c index d9a2c2de..733769ed 100644 --- a/tests/graphics/compute_test.c +++ b/tests/graphics/compute_test.c @@ -50,7 +50,7 @@ PalBool computeTest() } // enumerate all available adapters - int32_t adapterCount = 0; + uint32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get adapters"); @@ -144,7 +144,7 @@ PalBool computeTest() } // create a compute shader - uint64_t bytecodeSize = 0; + uint32_t bytecodeSize = 0; void* bytecode = nullptr; const char* source = nullptr; diff --git a/tests/graphics/descriptor_indexing_test.c b/tests/graphics/descriptor_indexing_test.c index a7b561d9..62b2b6e3 100644 --- a/tests/graphics/descriptor_indexing_test.c +++ b/tests/graphics/descriptor_indexing_test.c @@ -150,7 +150,7 @@ PalBool descriptorIndexingTest() } // enumerate all available adapters - int32_t adapterCount = 0; + uint32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get adapters"); @@ -630,7 +630,7 @@ PalBool descriptorIndexingTest() } // create shaders - uint64_t bytecodeSize = 0; + uint32_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; PalShaderEntryInfo entries[2]; diff --git a/tests/graphics/geometry_test.c b/tests/graphics/geometry_test.c index 4d3cb169..95bc4610 100644 --- a/tests/graphics/geometry_test.c +++ b/tests/graphics/geometry_test.c @@ -107,7 +107,7 @@ PalBool geometryTest() } // enumerate all available adapters - int32_t adapterCount = 0; + uint32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get adapters"); @@ -346,7 +346,7 @@ PalBool geometryTest() } // create shaders - uint64_t bytecodeSize = 0; + uint32_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[3]; PalShaderEntryInfo entries[3]; diff --git a/tests/graphics/indirect_draw_test.c b/tests/graphics/indirect_draw_test.c index a9cfc498..6c36042d 100644 --- a/tests/graphics/indirect_draw_test.c +++ b/tests/graphics/indirect_draw_test.c @@ -119,7 +119,7 @@ PalBool indirectDrawTest() } // enumerate all available adapters - int32_t adapterCount = 0; + uint32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get adapters"); @@ -520,7 +520,7 @@ PalBool indirectDrawTest() } // create shaders - uint64_t bytecodeSize = 0; + uint32_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; PalShaderEntryInfo entries[2]; diff --git a/tests/graphics/mesh_test.c b/tests/graphics/mesh_test.c index 5ae0cee4..ed453f87 100644 --- a/tests/graphics/mesh_test.c +++ b/tests/graphics/mesh_test.c @@ -107,7 +107,7 @@ PalBool meshTest() } // enumerate all available adapters - int32_t adapterCount = 0; + uint32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get adapters"); @@ -346,7 +346,7 @@ PalBool meshTest() } // create shaders - uint64_t bytecodeSize = 0; + uint32_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; PalShaderEntryInfo entries[2]; diff --git a/tests/graphics/multi_descriptor_set_test.c b/tests/graphics/multi_descriptor_set_test.c index 7a76e52f..4764068b 100644 --- a/tests/graphics/multi_descriptor_set_test.c +++ b/tests/graphics/multi_descriptor_set_test.c @@ -54,7 +54,7 @@ PalBool multiDescriptorSetTest() } // enumerate all available adapters - int32_t adapterCount = 0; + uint32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get adapters"); @@ -160,7 +160,7 @@ PalBool multiDescriptorSetTest() } // create a compute shader - uint64_t bytecodeSize = 0; + uint32_t bytecodeSize = 0; void* bytecode = nullptr; const char* source = nullptr; diff --git a/tests/graphics/ray_tracing_test.c b/tests/graphics/ray_tracing_test.c index 38f7697c..3fbffc3a 100644 --- a/tests/graphics/ray_tracing_test.c +++ b/tests/graphics/ray_tracing_test.c @@ -58,7 +58,7 @@ PalBool rayTracingTest() } // enumerate all available adapters - int32_t adapterCount = 0; + uint32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get adapters"); @@ -167,7 +167,7 @@ PalBool rayTracingTest() } // create ray tracing shaders - uint64_t bytecodeSize = 0; + uint32_t bytecodeSize = 0; void* bytecode = nullptr; const char* source = nullptr; PalShaderEntryInfo entries[3]; @@ -360,7 +360,7 @@ PalBool rayTracingTest() tlasBuildInfo.buildMode = PAL_ACCELERATION_STRUCTURE_BUILD_MODE_BUILD; // get the build sizes for tlas - uint32_t blasScratchSize = buildSizes.scratchBufferSize; + uint32_t blasScratchSize = (uint32_t)buildSizes.scratchBufferSize; palGetAccelerationStructureBuildSize(device, &tlasBuildInfo, &buildSizes); // create the tlas buffer and tlas diff --git a/tests/graphics/texture_test.c b/tests/graphics/texture_test.c index 7b4ccd7e..7d3ac75d 100644 --- a/tests/graphics/texture_test.c +++ b/tests/graphics/texture_test.c @@ -144,7 +144,7 @@ PalBool textureTest() } // enumerate all available adapters - int32_t adapterCount = 0; + uint32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get adapters"); @@ -598,7 +598,7 @@ PalBool textureTest() } // create shaders - uint64_t bytecodeSize = 0; + uint32_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; PalShaderEntryInfo entries[2]; diff --git a/tests/graphics/triangle_test.c b/tests/graphics/triangle_test.c index caabb3b8..77f9f52d 100644 --- a/tests/graphics/triangle_test.c +++ b/tests/graphics/triangle_test.c @@ -110,7 +110,7 @@ PalBool triangleTest() } // enumerate all available adapters - int32_t adapterCount = 0; + uint32_t adapterCount = 0; result = palEnumerateAdapters(&adapterCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to get adapters"); @@ -427,7 +427,7 @@ PalBool triangleTest() } // create shaders - uint64_t bytecodeSize = 0; + uint32_t bytecodeSize = 0; void* bytecode = nullptr; const char* sources[2]; PalShaderEntryInfo entries[2]; diff --git a/tests/opengl/multi_thread_opengl_test.c b/tests/opengl/multi_thread_opengl_test.c index ad621b01..f7f5e52e 100644 --- a/tests/opengl/multi_thread_opengl_test.c +++ b/tests/opengl/multi_thread_opengl_test.c @@ -257,7 +257,7 @@ PalBool multiThreadOpenGlTest() } // get all FBConfigs and select one - int32_t fbCount = 0; + uint32_t fbCount = 0; result = palEnumerateGLFBConfigs(&fbCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to query GL FBConfigs"); diff --git a/tests/opengl/opengl_context_test.c b/tests/opengl/opengl_context_test.c index d307505b..dba0dab9 100644 --- a/tests/opengl/opengl_context_test.c +++ b/tests/opengl/opengl_context_test.c @@ -67,7 +67,7 @@ PalBool openglContextTest() } // enumerate supported opengl framebuffer configs - int32_t fbCount = 0; + uint32_t fbCount = 0; result = palEnumerateGLFBConfigs(&fbCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to query GL FBConfigs"); diff --git a/tests/opengl/opengl_fbconfig_test.c b/tests/opengl/opengl_fbconfig_test.c index ec7f33f9..7e217696 100644 --- a/tests/opengl/opengl_fbconfig_test.c +++ b/tests/opengl/opengl_fbconfig_test.c @@ -39,7 +39,7 @@ PalBool openglFBConfigTest() } // enumerate supported opengl framebuffer configs - int32_t fbCount = 0; + uint32_t fbCount = 0; result = palEnumerateGLFBConfigs(&fbCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to query GL FBConfigs"); diff --git a/tests/opengl/opengl_multi_context_test.c b/tests/opengl/opengl_multi_context_test.c index 0f8c3029..1ff6be3f 100644 --- a/tests/opengl/opengl_multi_context_test.c +++ b/tests/opengl/opengl_multi_context_test.c @@ -67,7 +67,7 @@ PalBool openglMultiContextTest() } // enumerate supported opengl framebuffer configs - int32_t fbCount = 0; + uint32_t fbCount = 0; result = palEnumerateGLFBConfigs(&fbCount, nullptr); if (result != PAL_RESULT_SUCCESS) { logResult(result, "Failed to query GL FBConfigs"); diff --git a/tests/tests.h b/tests/tests.h index a9fe2a54..e6203f84 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -15,7 +15,7 @@ void runTests(); static PalBool readFile( const char* filename, void* buffer, - uint64_t* size) + uint32_t* size) { FILE* file = fopen(filename, "rb"); if (!file) { @@ -23,13 +23,13 @@ static PalBool readFile( } fseek(file, 0, SEEK_END); - uint64_t tmpSize = ftell(file); + uint32_t tmpSize = (uint32_t)ftell(file); fseek(file, 0, SEEK_SET); if (buffer) { tmpSize = *size; size_t read = fread(buffer, 1, tmpSize, file); - if (read != tmpSize) { + if ((uint32_t)read != tmpSize) { return PAL_FALSE; } } diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index f08cfe2a..e6090b66 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -21,7 +21,7 @@ #include #define DLL_HANDLE HMODULE -#define LOAD_DLL(path) LoadLibraryA("PAL2.dll") +#define LOAD_DLL LoadLibraryA("PAL2.dll") #define FREE_DLL(handle) FreeLibrary(handle) #define GET_FUNC(handle, name) GetProcAddress(handle, name) @@ -59,7 +59,7 @@ static PalBool checkPALVersion(uint32_t flags) return PAL_FALSE; } - getVersion = GET_FUNC(handle, "palGetVersion"); + getVersion = (GetVersionFn)GET_FUNC(handle, "palGetVersion"); if (!getVersion) { palLog(nullptr, "Failed to load palGetVersion in PAL library"); FREE_DLL(handle); diff --git a/tools/abi_dump/dumps.h b/tools/abi_dump/dumps.h index 788659ee..81f9245f 100644 --- a/tools/abi_dump/dumps.h +++ b/tools/abi_dump/dumps.h @@ -85,7 +85,7 @@ static PalBool checkABI( for (uint32_t i = 0; i < info->fieldCount; i++) { FieldInfo* field = &info->fields[i]; - uint32_t size = strlen(field->name); + uint32_t size = (uint32_t)strlen(field->name); if (size > fieldSize) { fieldSize = size; } @@ -169,4 +169,4 @@ PalBool videoABIDump(uint32_t flags); PalBool openglABIDump(uint32_t flags); PalBool graphicsABIDump(uint32_t flags); -#endif // _DUMPS_H \ No newline at end of file +#endif // _DUMPS_H From c0ede2dea054ea4e95ee7e5d59408e7d7c87d90a Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 26 Jul 2026 13:27:47 +0000 Subject: [PATCH 370/372] fix clang warnings and errors linux --- premake5.lua | 6 ++++++ src/graphics/vulkan/pal_adapter_vulkan.c | 5 ++--- src/graphics/vulkan/pal_swapchain_vulkan.c | 2 +- src/opengl/egl/pal_context_egl.c | 1 + src/system/linux/pal_platform_linux.c | 4 ++-- src/thread/posix/pal_thread_posix.c | 5 ++--- src/video/wayland/pal_video_wayland.c | 10 +++++----- src/video/wayland/pal_wayland.h | 5 ----- src/video/x11/pal_video_x11.c | 18 ++++++++++++------ src/video/x11/pal_window_x11.c | 8 ++++---- src/video/x11/pal_x11.h | 15 ++++----------- tests/video/native_instance_test.c | 1 + tests/video/native_integration_test.c | 2 +- 13 files changed, 41 insertions(+), 41 deletions(-) diff --git a/premake5.lua b/premake5.lua index d2e10a66..e077f905 100644 --- a/premake5.lua +++ b/premake5.lua @@ -377,6 +377,12 @@ workspace(workspaceName) if (_OPTIONS["compiler"] == "clang") then toolset("clang") + buildoptions { + -- warnings + "-Wno-switch", -- for switch statements + "-Wno-switch-enum" -- for switch statements + } + intellisenseMode = "linux-clang-x64" compilerPath = "/usr/bin/clang" else diff --git a/src/graphics/vulkan/pal_adapter_vulkan.c b/src/graphics/vulkan/pal_adapter_vulkan.c index ff63ee4d..787118c6 100644 --- a/src/graphics/vulkan/pal_adapter_vulkan.c +++ b/src/graphics/vulkan/pal_adapter_vulkan.c @@ -65,9 +65,9 @@ PalResult PAL_CALL enumerateAdaptersVk( uint32_t* count, PalAdapter** outAdapters) { - int deviceCount = 0; + uint32_t deviceCount = 0; int adapterCount = 0; - int extCount = 0; + uint32_t extCount = 0; VkResult ret; VkExtensionProperties* exts = nullptr; VkPhysicalDeviceProperties props = {0}; @@ -102,7 +102,6 @@ PalResult PAL_CALL enumerateAdaptersVk( PalBool found = PAL_FALSE; s_Vk.enumerateDeviceExtensionProperties(phyDevice, nullptr, &extCount, exts); - for (int i = 0; i < extCount; i++) { const char* ext = exts[i].extensionName; if (strcmp(ext, "VK_KHR_dynamic_rendering") == 0) { diff --git a/src/graphics/vulkan/pal_swapchain_vulkan.c b/src/graphics/vulkan/pal_swapchain_vulkan.c index 1926e045..79248621 100644 --- a/src/graphics/vulkan/pal_swapchain_vulkan.c +++ b/src/graphics/vulkan/pal_swapchain_vulkan.c @@ -105,7 +105,7 @@ void PAL_CALL getSurfaceCapabilitiesVk( PalSurface* surface, PalSurfaceCapabilities* caps) { - int32_t formatCount = 0; + uint32_t formatCount = 0; uint32_t modeCount = 0; SurfaceVk* surfaceImpl = (SurfaceVk*)surface; VkSurfaceFormatKHR* formats = nullptr; diff --git a/src/opengl/egl/pal_context_egl.c b/src/opengl/egl/pal_context_egl.c index be3c8b6e..5738d5c4 100644 --- a/src/opengl/egl/pal_context_egl.c +++ b/src/opengl/egl/pal_context_egl.c @@ -45,6 +45,7 @@ static ContextData* findContextData(PalGLContext* context) return &s_Egl.contextData[i]; } } + return nullptr; } static void freeContextData(PalGLContext* context) diff --git a/src/system/linux/pal_platform_linux.c b/src/system/linux/pal_platform_linux.c index ef3ab057..dff70a2a 100644 --- a/src/system/linux/pal_platform_linux.c +++ b/src/system/linux/pal_platform_linux.c @@ -33,8 +33,8 @@ void PAL_CALL palGetPlatformInfo(PalPlatformInfo* info) } char line[256]; - char name[15]; - char version[15]; + char name[16]; + char version[16]; // parse version and name from the release file while (fgets(line, sizeof(line), file)) { if (strncmp(line, "NAME=", 5) == 0) { diff --git a/src/thread/posix/pal_thread_posix.c b/src/thread/posix/pal_thread_posix.c index 16027df1..9c37709a 100644 --- a/src/thread/posix/pal_thread_posix.c +++ b/src/thread/posix/pal_thread_posix.c @@ -125,10 +125,9 @@ PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread) } else if (param.sched_priority == 0) { return PAL_THREAD_PRIORITY_NORMAL; } - - } else { - return PAL_THREAD_PRIORITY_HIGH; } + + return PAL_THREAD_PRIORITY_HIGH; } uint64_t PAL_CALL palGetThreadAffinity(PalThread* thread) diff --git a/src/video/wayland/pal_video_wayland.c b/src/video/wayland/pal_video_wayland.c index 05893183..7203d6c2 100644 --- a/src/video/wayland/pal_video_wayland.c +++ b/src/video/wayland/pal_video_wayland.c @@ -488,9 +488,9 @@ static void outputGeometry( struct wl_output* output, int32_t x, int32_t y, - int32_t, // we dont need physical size - int32_t, // we dont need physical size - int32_t, // we dont need subpixel + int32_t tmp, // we dont need physical size + int32_t tmp2, // we dont need physical size + int32_t tmp3, // we dont need subpixel const char* make, const char* model, int32_t transform) @@ -714,7 +714,7 @@ static void pointerHandleLeave( struct wl_surface* surface) { if (s_Wl.pointerSurface == surface) { - s_Wl.pointerSurface == nullptr; + s_Wl.pointerSurface = nullptr; } } @@ -939,7 +939,7 @@ static void keyboardHandleLeave( struct wl_surface* surface) { if (s_Wl.keyboardSurface == surface) { - s_Wl.keyboardSurface == nullptr; + s_Wl.keyboardSurface = nullptr; } } diff --git a/src/video/wayland/pal_wayland.h b/src/video/wayland/pal_wayland.h index ec99cac8..dec6f6a8 100644 --- a/src/video/wayland/pal_wayland.h +++ b/src/video/wayland/pal_wayland.h @@ -53,11 +53,6 @@ typedef struct wl_proxy* (*wl_proxy_marshal_flags_fn)( typedef uint32_t (*wl_proxy_get_version_fn)(struct wl_proxy*); -typedef int (*wl_proxy_add_listener_fn)( - struct wl_proxy*, - void (**)(void), - void*); - typedef int (*wl_display_get_error_fn)(struct wl_display*); typedef int (*wl_display_dispatch_pending_fn)(struct wl_display*); typedef int (*wl_display_flush_fn)(struct wl_display*); diff --git a/src/video/x11/pal_video_x11.c b/src/video/x11/pal_video_x11.c index fca897ee..16956e96 100644 --- a/src/video/x11/pal_video_x11.c +++ b/src/video/x11/pal_video_x11.c @@ -278,6 +278,8 @@ static int getWindowMonitorDPI(WindowData* data) return info->dpi; } } + + return 96; } void sendWMEvent( @@ -929,12 +931,16 @@ PalResult xInitVideo( // we load GLX s_X11.glxHandle = dlopen("libGL.so.1", RTLD_LAZY); if (s_X11.glxHandle) { - GLXGetProcAddressFn load = nullptr; - load = (GLXGetProcAddressFn)dlsym(s_X11.glxHandle, "glXGetProcAddress"); - s_X11.glxGetFBConfigs = (GLXGetFBConfigsFn)load("glXGetFBConfigs"); - s_X11.glxGetFBConfigAttrib = (GLXGetFBConfigAttribFn)load("glXGetFBConfigAttrib"); - s_X11.glxGetVisualFromFBConfig = - (GLXGetVisualFromFBConfigFn)load("glXGetVisualFromFBConfig"); + GLXGetProcAddressFn loadFunc = nullptr; + loadFunc = (GLXGetProcAddressFn)dlsym(s_X11.glxHandle, "glXGetProcAddress"); + s_X11.glxGetFBConfigs = (GLXGetFBConfigsFn)loadFunc( + (const unsigned char*)"glXGetFBConfigs"); + + s_X11.glxGetFBConfigAttrib = (GLXGetFBConfigAttribFn)loadFunc( + (const unsigned char*)"glXGetFBConfigAttrib"); + + s_X11.glxGetVisualFromFBConfig = (GLXGetVisualFromFBConfigFn)loadFunc( + (const unsigned char*)"glXGetVisualFromFBConfig"); } // load EGL diff --git a/src/video/x11/pal_window_x11.c b/src/video/x11/pal_window_x11.c index de381527..5f5ad698 100644 --- a/src/video/x11/pal_window_x11.c +++ b/src/video/x11/pal_window_x11.c @@ -13,7 +13,7 @@ #include static int xErrorHandler( - Display*, + Display* display, XErrorEvent* e) { // this is use for simple success and failure @@ -305,7 +305,7 @@ PalResult xCreateWindow( s_X11Atoms.UTF8_STRING, 8, // unsigned char PropModeReplace, - info->title, + (const unsigned char*)info->title, strlen(info->title)); } else { @@ -756,7 +756,7 @@ void xSetWindowOpacity( PalWindow* window, float opacity) { - unsigned long value = (unsigned long)(opacity * 0xFFFFFFFFUL + 0.5f); + uint32_t value = (uint32_t)(opacity * (float)0xFFFFFFFFUL + 0.5f); s_X11.changeProperty( s_X11.display, FROM_PAL_HANDLE(Window, window), @@ -783,7 +783,7 @@ void xSetWindowTitle( s_X11Atoms.UTF8_STRING, 8, // unsigned char PropModeReplace, - title, + (const unsigned char*)title, strlen(title)); } else { diff --git a/src/video/x11/pal_x11.h b/src/video/x11/pal_x11.h index 5ebe50cf..b1ba5c19 100644 --- a/src/video/x11/pal_x11.h +++ b/src/video/x11/pal_x11.h @@ -46,7 +46,9 @@ typedef XVisualInfo* (*GLXGetVisualFromFBConfigFn)( Display*, GLXFBConfig); -typedef XVisualInfo* (*GLXGetProcAddressFn)(const unsigned char*); +typedef void (*GLXProc)(); + +typedef GLXProc (*GLXGetProcAddressFn)(const unsigned char*); typedef Display* (*XOpenDisplayFn)(const char*); typedef int (*XCloseDisplayFn)(Display*); @@ -348,15 +350,6 @@ typedef XWMHints* (*XGetWMHintsFn)( Display*, Window); -typedef Cursor (*XCreatePixmapCursorFn)( - Display*, - Pixmap, - Pixmap, - XColor*, - XColor*, - unsigned int, - unsigned int); - typedef int (*XSetInputFocusFn)( Display*, Window, @@ -417,7 +410,7 @@ typedef int (*XCloseIMFn)(XIM); typedef XIC (*XCreateICFn)( XIM, - ...) _X_SENTINEL(0); + ...); typedef void (*XDestroyICFn)(XIC); diff --git a/tests/video/native_instance_test.c b/tests/video/native_instance_test.c index 08381cbc..f5f1f684 100644 --- a/tests/video/native_instance_test.c +++ b/tests/video/native_instance_test.c @@ -263,6 +263,7 @@ void* openDisplayWin32() #ifdef _WIN32 return GetModuleHandleW(nullptr); #endif // _WIN32 + return nullptr; } void closeDisplayWin32(void* instance) diff --git a/tests/video/native_integration_test.c b/tests/video/native_integration_test.c index d8156b12..c28d0a1c 100644 --- a/tests/video/native_integration_test.c +++ b/tests/video/native_integration_test.c @@ -175,7 +175,7 @@ void setWindowTitleX11(PalWindowHandleInfo* windowInfo) s_UTF8_STRING, 8, // unsigned char PropModeReplace, - title, + (const unsigned char*)title, strlen(title)); } else { From 7989cbaf1a0dcf51b244c901d7b71c9e66b6a1df Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 26 Jul 2026 13:35:26 +0000 Subject: [PATCH 371/372] reformat code with improved abi dump tool --- src/thread/posix/pal_thread_posix.c | 2 +- src/video/wayland/pal_video_wayland.c | 2 +- src/video/x11/pal_video_x11.c | 12 ++++++------ tools/abi_dump/abi_dump_main.c | 10 +++++----- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/thread/posix/pal_thread_posix.c b/src/thread/posix/pal_thread_posix.c index 9c37709a..82a00f57 100644 --- a/src/thread/posix/pal_thread_posix.c +++ b/src/thread/posix/pal_thread_posix.c @@ -126,7 +126,7 @@ PalThreadPriority PAL_CALL palGetThreadPriority(PalThread* thread) return PAL_THREAD_PRIORITY_NORMAL; } } - + return PAL_THREAD_PRIORITY_HIGH; } diff --git a/src/video/wayland/pal_video_wayland.c b/src/video/wayland/pal_video_wayland.c index 7203d6c2..fa5fc2a7 100644 --- a/src/video/wayland/pal_video_wayland.c +++ b/src/video/wayland/pal_video_wayland.c @@ -488,7 +488,7 @@ static void outputGeometry( struct wl_output* output, int32_t x, int32_t y, - int32_t tmp, // we dont need physical size + int32_t tmp, // we dont need physical size int32_t tmp2, // we dont need physical size int32_t tmp3, // we dont need subpixel const char* make, diff --git a/src/video/x11/pal_video_x11.c b/src/video/x11/pal_video_x11.c index 16956e96..4223386f 100644 --- a/src/video/x11/pal_video_x11.c +++ b/src/video/x11/pal_video_x11.c @@ -933,14 +933,14 @@ PalResult xInitVideo( if (s_X11.glxHandle) { GLXGetProcAddressFn loadFunc = nullptr; loadFunc = (GLXGetProcAddressFn)dlsym(s_X11.glxHandle, "glXGetProcAddress"); - s_X11.glxGetFBConfigs = (GLXGetFBConfigsFn)loadFunc( - (const unsigned char*)"glXGetFBConfigs"); + s_X11.glxGetFBConfigs = + (GLXGetFBConfigsFn)loadFunc((const unsigned char*)"glXGetFBConfigs"); - s_X11.glxGetFBConfigAttrib = (GLXGetFBConfigAttribFn)loadFunc( - (const unsigned char*)"glXGetFBConfigAttrib"); + s_X11.glxGetFBConfigAttrib = + (GLXGetFBConfigAttribFn)loadFunc((const unsigned char*)"glXGetFBConfigAttrib"); - s_X11.glxGetVisualFromFBConfig = (GLXGetVisualFromFBConfigFn)loadFunc( - (const unsigned char*)"glXGetVisualFromFBConfig"); + s_X11.glxGetVisualFromFBConfig = + (GLXGetVisualFromFBConfigFn)loadFunc((const unsigned char*)"glXGetVisualFromFBConfig"); } // load EGL diff --git a/tools/abi_dump/abi_dump_main.c b/tools/abi_dump/abi_dump_main.c index e6090b66..8eaae783 100644 --- a/tools/abi_dump/abi_dump_main.c +++ b/tools/abi_dump/abi_dump_main.c @@ -35,7 +35,7 @@ #define GET_FUNC(handle, name) dlsym(handle, name) #endif // _WIN32 -typedef void (PAL_CALL* GetVersionFn)(PalVersion* version); +typedef void(PAL_CALL* GetVersionFn)(PalVersion* version); static int logDumpStatus(PalBool status) { @@ -84,10 +84,10 @@ static PalBool checkPALVersion(uint32_t flags) if (flags & DUMP_FLAG_VERBOSE) { palLog(nullptr, "Expected PAL Version: 2.0.0"); palLog( - nullptr, - "Actual PAL Version: %d.%d.%d", - version.major, - version.minor, + nullptr, + "Actual PAL Version: %d.%d.%d", + version.major, + version.minor, version.build); palLog(nullptr, "Target Library: PAL2"); From 8cbe699d20734bce179260a48c620d8522acf183 Mon Sep 17 00:00:00 2001 From: nichcode Date: Sun, 26 Jul 2026 13:45:44 +0000 Subject: [PATCH 372/372] v2.0.0 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 86369363..74af4d32 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ PAL supports Windows, Linux, Vulkan and D3D12. Both Wayland and X11 are supporte PAL is released under the [Zlib License](https://opensource.org/licenses/Zlib). ## Building PAL -PAL is written in C99 and uses Premake as its build system. PAL supports Windows Vista and later. PAL can be built with GCC, Clang and MSVC. Build options are configure with [pal_config.lua](./pal_config.lua). `true` to enable or `false` to disable a build option. It is recommended to not disable `PAL_BUILD_ABI_DUMP` build option. [pal_config.h](./include/pal/pal_config.h) is the reflection of the systems that will be built. +PAL is written in C99 and uses Premake as its build system. PAL supports Windows Vista and later. PAL can be built with GCC, Clang and MSVC. Build options are configure with [pal_config.lua](./pal_config.lua). `true` to enable or `false` to disable a build option. It is recommended to not disable `PAL_BUILD_ABI_DUMP` build option. X11 needs XRandR (1.2+) and libXcursor.

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%0AX!AS3v>Zsb(fUbrn(Sl&w}ai;f`r`*@mn6NE$ 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 diff --git a/premake/premake5.exe b/premake/premake5.exe index 1a637aa93c942a9268937d8732abf463ebe8bddc..32f354f95b3d7c57248eb8b003141e189bcf81e5 100644 GIT binary patch literal 1567744 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 S5&M@Q?gv``fBTJQ;C}&!BFwY^ literal 1568256 zcmdqKd3;pW`9D6{NZ7oCFc4H^)Tr?j!Dw89ahZV`xFZt?f`A*uqKGRIW+Yn0;3UfQ zI+nKDR%_KRpK4pXek=lR30ne@1W;MD)o87rFfLIm1Q+J_en02Vl7y&zeLtUne!N~` zX6`-roaa2}*`Mc}TY1?kM~=hc$i-hG;c%?MC;xfm|F8eAAj{!6V(hvj98VA2cHEk* z;I`vtExK;0yJpGaYnNPglY7BcH{ZNC5NGWpEEs~w;JV;)+*9iR7JJm9XcV z^*#BHU4I$AAbG9JalB)2_7P(opA5o8hsxzwzL)QCIOVGc)7Rg#9gYEVDgEiFF4RcH z^&Cg_isVD~v-X4O4?eEDd8DIU0JU#A2Rj3)3t3p=+ zXH$lt-C&2q#OHpr&G_d58I9M?99<{jM)fF%<4Am7fX|G79*3iGe2s1>bHrR7^=MGl zr=4g1#Xj#Wufy>rpLYYtz`f&@zU{^@S-OM^DYyd;Wr21buH7{^E=EJ*(gBm z^@(YXy(l)sVOF%>I&Y1`k>xPPa=}0bv12Ybcf`$#J*F{v5AHAfU>(WNv|5$(>3n>4 znbwp7v!O9`jA_kr2CYWZYEz#*z+2Ous-=Tp&>*@D5R8rInijsqhLi@aO#y3{dWj9Q z76XzSi^@&wjv~{vt|%%stx%E2jBIp!=cT41GxE&TuF0wnUs3rwxoz!LEk+h#+|D`NXj+rprd0qmURDHr zM4Fst#Z;$hOl-2ug2-D&cTG zjEgn^t-jdAY!x}*;lK=Kz2-FH) z6nhFkIUzZP>Aj|K1f~!kVp@e}WJ7U0hhG|YhOi2)YU@{tgm;bLCg!UA?O>p$Rs9VY zWnuJ8=Wno~YZus?&lA|WK*{y-y3N>_Q5@d__SXZ8GYGBJ+O(!R)sNmF(X^V))MO5`c~XJ>DH2tMa65_djPb0!94nUhi{m-#)R61b z3wI9KaEm7MASFSxY{AK&Wg>`S|tgITi*;9~@f#(WGOqy#p zdkV=X!Dx*We{SE(nnB=33{cwaDVRd!T2lbj6sI#dp{9^9wX0JA6XtT+6NB;Gt;M{w z8pPSqXw=8~M9ei4w|Lo*X@a(TOq0Dyx8Q&271(Z9FE{8dhDh%qIP*V^-HVF7DV`i5bomJ!xL>fCx z>tzmb=E5~oFHV1n5H|2&-GA&Qne$T)h3aaUa-nzHG@UJun zLJZahqMp)V)LTpV45zot7?w?(bgTojg6!MXfD;M86n8Lo;w1MFN5Fc8GD3udaMlj% zA_#{IBb~WM{m(JGNM}~)(8~5(<`93w zmeBM{P@p#!NSHZW{1ZZ33&Q97tgVa zqmxU`rnhp{nXiN8qLa%j8xqF-its^aR6S4XHpY4!3sd?)gv-40AW#*^dBa@rDlieS zHWC?uiY*kBLGV^=V#13_nH5b-hXpWYFk6?|^meY9vp#;F7i%(D80Y1VM2q=T^Mv(g zQ%7DP$5Xf}Qd>AYJiwe#0Fx2#YJ z{?85_?TvI}*}c}L&hHU8%iAUEerNheVSH&2my;`R_E`BFvGQm8txdA>#sA5YA1h0~ z$Q^RoOaAv)u;gHC5H;4^T%b&An>RWompD}y?#*`uqEia|(bLR^4~+YlK;F_!sCq%9 z8f=BR!RXaR)gb%em?4k`p(1ys^%)5wNe=<*u7W_$A#=elUvx3}cp{|cRA(i|%UFM? zX8Ba+@=Y1lDtaw^IXP z%^NKyHLV@g0av_9$uOxfIAM{9&sMc>J+I*DNGCu8 zjW)vS$`1ly2&*mv9I&doBDW98x)ri`B3Z*3pO67{q9xLit>-+kQ1}7x);hEMG6diy zLjWP)8s4Yg=ne0=hl6(t?3g|PXA|IyxR&ntxfuWpnsbt9PGdNyUktAU_d&3>3glFY z>eqQ$j_4E^ReeUyNsU_CcT}NcGv^{rH?pp||G}u^Wz<438lh;+=uGhT6tM=*4_MoR zv7t4O4;BHKq<6@!+yXPvPVjCN_f=x*%@cBp@^L z0YuJ@FB4!6uu#wfPf^g!rI}kLrc5#9&6QVPzQMNFLq$$80>QX2q|R>}-P@4*yzF%V z+QXExzMx%mp&4lwyXHc3!7|w8`Rura35xcAr@e)AI(cN zzX1{;E2mLAzo-38_zGvw(Jq7+)aj_C2k<$Bqfy_E=?5VnX^;@^p(6=56p1Hbbp|0$ zOrLd#rdNpq)q8*zr`hyXZlIzGdZQ(SwaF8LxQ3nKyl71UO@UVR_`5b|^)xqVQPH#_ z&(Vkh5?a;OFY2}dYa}dNbaIQ`$>rbB3EYQNCu60Pna+iY$VQ6p$olPGTUE5GiC1J{ zvXh)^7-m_RB`pH6sxC1FjF|T;>fyPOgSnwoBL^WhOjtCh5VTWX*DNUGKs2|iXCQBd z^6|K79f@%Y&63?BuZ-0OC~j0q3xrmpxuG%qVZ#=$@j!FK2esvxwVMh!0rg4M>I_z_ zUkXD3>N-PTPjUi*+U}e%)4Als_|TX?%UrOX&jfO|ljglvb5OfpSSk`g6<6LnZ~nXu z0m}(c(*5;?N7|R|Z`k579@uPcPCY5^n)YXU`=3dp7MySk#Q2FHjU3|eTa&w?R|B!x zK*7O4#Vbbr_d!muV?gBRf0+@6+bQzsdd8`>XR{?7@ws4Mnx#`Ga}#pr%`FxDQ{)?W47x7i<T%pc}nPN3rGYTSa z8>4*mr(rm@}L<--!WGS zCPjYV{nj_lDCsw~s-H>6dP1q0VBvbqWHMZ~)HJAX8oSb7?{Ip(Fk1FgJ(ObEMLm?7 z)^j#&cmNYzg$ep5oDJ`&ArTton{aDxc$larkC4EX^XE}LandjeVgGwP-U*9_+&T!> z3ioomD%l?FAiTt73d+0c?ZjrwQN4`%HQ4aG=d81El;&XQ)W z>g0}Zzg}^0ifQTff(9IMWKwhYroJC;X2V^e2Ycnz_RnDy!5ZokFosl29Ve;^C|q~svUy|M}$TOA%!UeTGh1fM1t)fX9MUeUs4rN z+lV~DRVZrLO~VK#)I^gzP|*S=*+F9!U4VgAxA4?d2#(MhViOD0)X!=RK?dVMrVI+k zykg$Qe~(5TVmRMCB0d~H;0s_0Fg(D6me}M?Yz#y;xf?!!0fi`@VZ+L+V0&=}ux`v9Z9MPskfTrdM>@l=?I9#5u+dxWUp z*hO7%V4QJpFZZ^Gd$TITzd?UJ-H(5QUfwZ=fRnS5p+W8CY757SsLxlQ7{dw>x?x~U z>vSw6t~oQWsROW9uvikLD#3S{D5NaLK!v02SSTl)jGw&*$rdpFv?mawd%Hnx?Bv2i zNhAZOf*m_PnGPjig5bRt-m#~OR>8nESG-@7>p*zUYkfQ+@0asNfmuNd*@!VmC&Jj- zyK-W2tTxMx-c8rsjKcqkPK2DC=njuk7yc|4Ch5@bM{*tN`&Z>VqUT?Q4%CxB&xLu^ zjaZyfKN6w9PYh??mk&TX#DYaN#_GIoeot%x8hk}HD}6<^b+>`FVu7siel~pzx1r#z zybgS^cB5IAMB`dj`$6&zdi@lkC`9|#9eJ{Y>OxI^G}qy?n%A8PH1qe__U{t=_eu8e zarW<#_+1&BT)gfmyMsJjV3@XM-SPI7PcaFRp0S~hBj8Jm{H)ECpJxl8lPU1h1 zo;x5a4I%*S{$>{E?Q+^bYhI^>>0fcu*;%i3r@_ZdpJscx8o6Eh&DiZ7M*W>wrm{v# zgG#GKL8Xg_0yyF;irDC z7KHI#r@!GHqkeE6O+7@_TGeGA!OH1|!FPakv>#Wa@M9o}#7`V@OqN67rxY z!#IajRyT#5CKEsMcNDI%yx~8B1Gjp}C|Jqo2Av6`VVAJZ=LO+T;s)5eWe8>8Og9Bp zpaRtJG+H1gY}=i`VSDSKS#mCX2s82#l%4QntJ##uwRWr9k0wN+DcU|u!IMz89I&Y? z0$4?^OHAf|622PoST1NW5WPp(0Mjm$Zo)5CT5@UK$)KCgb_QfDLxP~+X|$b$h;lN# zWz^pQscF0aolEc?D>3eeq=a_W@Z2B(6`rCIJ@o#;m?EA-JT6pbPi;W>ltA>@b$ix! zfzh#y)I%PGKDAs?3(m%hL?;(?&J-Bh(0RuXh{{|8?(ez2L5c7=@O}%zAH-%H;JO{z zB|?WQuU90Y7Voz)umVfD&czvhj>H1G`Z>BHod0-M;5>prft`*^5lAK&ZS$9tdIa2&*3*1fA7RF36`AV9xk3cfh24_vjPN;A<5H__=-w39CTI)$AyGrriSAL8;+81hGVXVW3Dp39*%MiN4a`$w#LYv zSQKCcc{L5k3>%JTehN5RIq{h5_utp}_|;mWoSXZZW3`5%T3OO}XmUU8JQ@a%T42LK z+fiWfXc#;;3}t{Jeh~mT*9PEt4Zt}z=??!uNVhnH{A)h7$?k6Sxo!l=4myT-eeWj_ zfi(1Nk$280nSaA+@Qym$F<`^~&^R%&RB#`q;ehb5)-G@>dF1v^bf&qsRXu-(=2GkV zMyw%X_w_X6wedGh9)%zkG6svwWf%%*VKey)BZX|Irs+Qe{J(r+gTKLU4|@=41TDX2 zJ={xvEtRf%$}i6KiyuQZTASAm!}R$(j^7Zv^#>A(btTjEwcWTDh+N+J^v_Je=b4_>|>56-n8d=%HbnUu)b>stbc0f#e2n- z8ZM!m(*g8z+KG_QCL zvjr)_>{{_8KAKlF+83Hv(8e8%KfqL+8S&HcKH9`A64*;eX)BvqUZ-VtQ>P#)&iGC# zOAE>w?mCU(uH3Rjd>rV7AeX~Cg^EeX2wK&q-`mCmm6C-(V>3K~aet}+_zfR~#;=7S zaHy6hPO1ew_pXIpq_s)ikJZrkp3?W!)0^@g`pUzp){WA-SyiW6FSlFYgVwet2C$5F zluFz~hpkv@kj}sB5a#(ab7>vyWm3y(h8ct)o7WjICN?G=?A*`@b1R@O#V`TyX>-PnB1!IExYm$uO8?@oA~cxBrXiN6=0}GO5ty zK6Kxz{xF3@&Fm4BG~t<;744zHRzO!U zKy|UaX_H*&wso47+o)cHGWCjMDzzS<=2nG@6WmAOSYV>lkPI8!@$6*%iOn5ex7XUk zNHGF_*2l@1YNuIJioqDKLQvWnh-P_{+2V*7LEffAxh0>VW~BQqj23fcu_hrpZsNtG zYzipc&bk1f)kZV5n8gyiZG&~2svm?Rik;S;*hSf@t3BW0l}S>@Zc|UPzlh)21%Ibk z6pS32$qvbQro`u0yzdq(!doc3AtrsKmU*32OvEoXy{uiYsE8e}$PA9aA?y_#!7N|S zqHUdbb#ySa0!U;5z5wMx!{4YrqFqDV4P2Ba#}bm`X*M}Nx3LfJ1)l7~d*Klc`!UFH z_8mLl$q&QdEsLxsQc{tT+to)cU^WU6HBK(JsI%6y{ze^(pQHvjWbSn=;Zo0Sz*8{g zuGZ`ZSI8Y`ZloU?NHk8YL%~RRKZ`Dgp|~Pm;wIH~d<@r?;865)DIofhTw7WQv7cPEUi6o)fAWy2V`qgN zL*QhXv2kNDfH9WnMBmKVXYy$pxgH8PurVSmZ7>J4fSa?yMsg|~_^;o{mBVy}&g*U~ z$PEuLR(l7t911zcNE1BZU{NXZO^x@;@{(@LIemy#=nWv?pQXTR+rTV`)s4uj(XbE` zPiD&k7Tj&SJSjI+TG4Ja_;K5YZmlHvAdyngO#yTn&q4~-)oPGT0g3tAgL%f?R2F7z z1WGj8lKC%VwQtaHaR5$%FZCvnFDWopwo|8KTh(ib0??-xt0Crk>>inr`sYi;$k#ce z>AcGm|IN0@#Kb0cP41R20LQ~W zqc#O)mD(ec-V=?U^7FF72S9s1w#*hxJH0D2C+We{$MUK@Cp z+m{}T{;)QPUk#E9n)ObsQb7R1DNwPU%hR%SwA>yjwHr-X4Jq0{avOt3<07SzXYIC;kBLd`~VPwR6Trm_Me@(-a;Ipn(g0N=RMFnJcKgQOBLC5-P& zAcUCbtU>DGC;|!QtwuE2u&udP^*$o9R<}0LABQOmlf5BZvtb>s$1T4-jM21}-vt6xCIr36hs3;K(4#zMv?$((3_*|tkdpP@#iT{>+A?b2qo|I?&hIzr!5 z$2^;~OS4n0i>38u)skxc?rP~teYlRFt?G}E2%3}{HiN2|l&!Ia4#|V1NfM-oD4FV9 zI#TPabX1>Lmwdovlh)GrO7~!np`$UhDuorSZ`^E;dn?98xF$O8tWr#p;czB-(%!{O zFJ-tkNYsH5$^*bf?8c&6(?ZPnpt4@36?S7$anNc*;Mi=2riWz3bdZ4nacs#_HGj>= zLan9pH_RpsQ!cqA8K$%B#r#Zv#xsWzWk!(^H1j?O&H&3Hc>jto`c%+bbNJ||T4^;A8Q8lipFJGc%!k}RIQr!N7+-_HwNb&`x5Iu8>Jt`Mb z(1V0oyBhr%sRV7;a9$2a*Ne}K?ucd~kp(h;<&x&cr{ z3#@BND#r7~$BcZQC!HWGA)%PHbVPmDCd1$4x3>8W|0c*`H%3Qs-!^rxA}xRfF<<&{ zu}dnMv3nB3`C@)lRJ5oE?xmaEY`fWQsvf^#E&d#~wC!fMsTy1hSZ%5{%6s*KP9z%K zyy&w!RMqzwnSHtlu`J+rf5>M>A1PXeK^CUt1EzI^Y0WE0xZ>l;7Hz@k_=M|C`TnWd z@Ot=7)6&lbu_o+@12&J!la2{6V*saZ z0*E$a_Z3wWB4R|{Nc|jpK&~Lo9&>%MoD1HrB4X(FUeR=Qt1i!KS5tq^)eII@sc|67 zg~rVq56EFVKQ-QMj4mobWDmRmQqV=vmZq&B(r=_FbHzp>%`3fE%-;aI)G-7?&}6_f z_gpd?1k9S<74J)PSOuo_vA-kN__F ztS(i#lJ}ppNgxsOk_5UsN){;6j?nF5vd4jJSDx{#$!6Ni>@TYRu0+$5aX~nc>(d)`e;2RO&>4HcTFFebn&O*nl1!T2%H=G zENcuy>17@K-Ts$#&cU9`x=c*tKFgX(K^OKU!3X~-B>2bMH3^=5_zwEe#i5@j>7wHg z8Ny_Z=m(oJ5W?Wk!x0CSt(G5NMk3l2WLc&%gof*-8ZA$|cG00a3ZIV`wX2qnP4Gp&m|l=BhJ<_0A5jrw;e zabsa;GX7~smpavpFEbdOYcw#(Oi#HXv3wX6y)Hj9D|RitHeR_R!RRz~r+s5rd_owN zqcg!(>phGLI@Yp9NjuV5BSU8eEqHUQy@M)R?m8vrO|UdAvYyo=C{NoFsMsAE9;o;z zbVShFgh<0vQ)%>tk0D)aEBZC4I9wSm=6h!`j12j<1`}{}p3G^`He_}((%3;mHimkY ziXBVcQvdL^{z?=5iGKV?83a=6u3C~ztI9zQ-#7TT=_;koKW5{@I=HZ$Gwb)h!QJg2 zzLbCa@HCFqBOo~i!wY`mgUpz}i_R94c0CKgBD(e~8A!2>Lee87^NmG?GzQ&tdYMGF zZUc&4%a#!rd(9FAbU%U*lgL$%93e9;gj&CfcR>Nf)>+`U*y1d`&&a|a0^|>&*-3fl z*h>b zRs-wy&DiW5mWU1{oj{-HTGKP1V=w)OD{zM+g2-D{_XBp@zAo|6UrS%#=numpOr|8% z8Et?SY}+9#N3WoiOD0ilj}EyuBx;%Qg>cxNE($eK^||z@vV_i0+mmERm;viSSpce6 zKeH=y!6t@0JoLKEET)Gs6qD_Var_~H*5(b1Tzhn zn?ePCYr8+EF}~GbvHi|@B2Op9a-9#Atl!a%z>T%N_H@`s?uN$Yqs-XkYDzY`LfC&5 za3;1k>_l%n!^ogdMsF>lyx2uq@$52;;>Gq&RBo;J8@?u=wcT6Mc*hg|SWV)2x{#=P zdvOpZ<}GQCbi0h{A5}KI9y+oTu4l}(`4&whXa6Ia*88%VYt%}?vW!YH=K8OtaD^`c z6ZJ*7R*F4DnjZa1b zVy-{ltg%wu$MQjpT!>C`!8=xenZFQJTR(Ep^I-QVD1O_3iW3IKhfaG!7U!RDA9pqM;CQ8N5 z2?6f=jbjH~7$HTZ81Tps@d#o!RAlWS%$Hb^Sq>K=JYGB#Ue8C+lDQg*y|CCSp&rLdIfsrqj#`Nc8`1=F7YO=GI^o#V9T%MeizK#`W&{x z`SSQ)btiVO;sF?);h`8kR`rECiX)$b!mHD_&>GFA+|6^LeSCyA2uI_(4v~K!-{3u9 z>^$6;ve;I2)Lvd})NStsjr3TMv_6yYme<;@0@6#P-enpD%Vj=*eEo{|AJ@y)u(K9B zu)QK5ytaHmWHfY1C8ejxyKn%uc{MM3f~a3*F*Bh1E^sJ(tZvH70*->@)Gf=$WbpA7 zXrkutLGu+GIUGu{W3Ip6ppiT!^Li$9q_3X!3AEaZbuKw}2h$pR)dWn5j<|_PCKqSz zZWNe+P-Xpsl45LC_5ao@)=S@r5g4$Pjs;F?WEc}Mm<6Sf$)lQ4j%a7-;CAqP=L-B+ z_ImWv0#F1)ENY|V2|oyp((805cn^j?!zoJuM%+t6gk?6x8J$~z5-P51yZXsrN%8%~ zddvxP?VZf?E!|F=f6>zc#cS zL-uP8&b0q<&-XYnHa=bEmYSG&b+&mRCnu04lUvC!AE^Er;Cv)E*L&2Tfnl)qP+EVf z-Cjga7b;I+=VQL@2=)|W$9cIF%^2`;jMYFi*QWSM13tsD(vN zw>?<{Y0ZJRN-`m$MoAN(NNe;=8(7!thzo?o-wbha)g08AG85vB+}7;~i@BStx5NgN z)g+tt@Dn%j%2iaD`vjjAFyV0V4u)H zZfQT&EBo0`WG8jCmt-v)%2XJl!6R>gN;?8OerMIa)m@Y`sA=WIfqancy$>QeW0;=e zqPIPn;_uHXDLz7NnxsM+L*LQzGX?_!P=O+5f~+b-3SYjXf(tU$8PB$07nuek*+?kLUK!*$VK4Q=qnRMv@+e8<0c#KUB7Ur7 ze>WhrsUS_?2y_wjHgz|GMk)Q9S)T$Oj#E+gSo_cqQ65&!>p9Eiqe1cXRom2$QH+?3 zxIIkjwetPo88lw(x3<#GO~y+xT(G1ut&fe>PN?J|j*=bR(ANm7;{zPLaok0gue|_j z+Kat>=;f4nvpOR+M(Eu5qk;-AJ?)+niz%0wYxZ?i1a0a9=tk-`0rD3pu}hY?$pyE} zI1_vJ{Owil<{G!caf8f7yrz{YuQBn#HXqUPqlSpN92iagik;!dVE*`Vs^?zofifSx z9`#KQN5zJ4pXJb1IshH{Qz}+@Uf|IxC5Y#6E7SuD)Uz!@DL+b&+SRj2qGn8~_w(;V zc@v|V&+Cwzetd`?Hr0a-|KaEX;DJh}Q(Ef>!IM|f=cz2G%1zugV5FUL74Sofi;|ABR< zhn|ydRzRE@6Ic&TY+m$XXo4HczMWA#MF z-iAx;tpzO*d*f4EY2OWzqem{L(@H-rSFb)eyF{SZE9I|8dp1jx-zv=zE>G-qdMVXcI!CJRI zHZ4@RScR$`v>ddyiP?af0S_)Z6ED+*%R^ab*e#1_MsLP-?lX-J;DA*mC#Fi~Z@`?r z*c1V2&_J6s=GuStV0cw+>g>;w9MNljFt7@>HEUs$vsJEw0D;xEurFC*s6l|d=ft8p zz-jU@A(?NcCf5vS_uqs6dGwBH?PEDEPv4;}l&^CB220&oJqfC>%Ujox<6G(Jefo|V zLa=e>x>wE}#G`ne6cA$e^f`VfZSnlB4q7qhIssERqw|W1%;>yQRmNhG#?YDad~E2y zvF;%6E%Vt5GjE3-HB!140|%pOLq}aMw#am+cfzIJq1=FVDT>ZBtPnS?5XA7O&b3-``71&O7>5}Svs&irr5TJR5rJ$hrg4uJ>I76 zv3{jjY!7NG$m<(IG(TWt!d$Rpn=mqk_87 zr8igRGzMbl;hY)!O2C-Z9jG|CWFaedrOlGd;YqtCmTXSQfdzt0IVdcl#$XUEVEiZ~ zE0lvcWylgPqct3t)p(PMYTDUlB%xC5R|2kcgbM>XEM*Wu=vw|ANSPme0)S~SAZaRx zu4Nb{5^;mRI;cu8te^r`Y>V191&&45d<@xx{n8o3UR_C$^<%Sn1EH6AT4F=pc}GFt zaD6a~m(^C81#k_jZ&5eO0Q34Cfc+O&@L8`my_ncO4x>d3dp`Ge*5+Dauo1t0fSXZANZNv2cB;o@L7rYg?0hnRS(g8 z%`CwC2&T2vRZ68Ah-hH4)bp0XEcN7J2e%;=5_ShCgdL$^AZB(T9i_{wwo3in*XDb^ zcK)oJmHouXx64T*o8=&Y7ImGUG!{nYJZzUe!!W=$+~(MvL+UAPcGKPfDA1$ja!;Xb zBQA-**hKKrMeyLV&E|;|XgHs3Vu8c$&}R;!T1@T-t*seN0@jvfD|jfKCj-7@f22Qc z?=kN4uU8?rk=YnJYQLwz2#;W*Y7Hqrwa)W5#O^(Lvf&_Wm!HpX%LbYy zgIGS7bCBjbn4ne7*+#hwHr9KlhC>}$r^k;-IBF_S=qk;=I zs}blT)!%N&)Odk%!#0i8WZ||RrV*C~GJ29pO`2w9nK6Uwcl2WF*xdv?ut1y2dKO3O z%oh8S^(64=D=#tXzsIW# zt;W~$ER2}zc66;`8wK1Y_|C$pX}?K=!0coQl&(H{3d0nrM}Re~veXGcU+z)Ep9dYp z^3KDP#F-mCI{6(XIWaR!or#XU!Yld_wE?l^HTeLdlR;?4i_2vy>Ucem&rb-SF7<@C zp^m^cdR=*u?m^-ArLp?_cYtjHiZ8A0n|(tV)+s8De15difKAj69vfGWP$5WDN0pzx zT+is0C(|ca6_-zeDQ*8H{QbvXOZ6~v5m>4> zFCFaYtO9fPpt39f2=@!pPcu*uwR6HbwD(vTSVz)Zv60NIi=*bJ6tzf4@V|vq0^l%Y zZJ_i)Au^Q<{w2jIEESUrSHr+|DG<{NCSj3ka<_yJMS@Q-9v<0fGM>x!($p@pr+=Oe zdr1_Orqz|yD9O52!MeI8*@MVOJ3g|9_S?_kU;w_%cmnI*GUJo5^V-#?QZm+md=ht( z@m!p*Nu!tn?bxNjQ=o%(+>*QPGhJYAPDj;!pc~q-!wWMVI|gu0rWd6wB1W|l%9CqQ z*&>zNJC>f1q~EWtKlu85IM%G^7)kkDAo$Q)i*k5xzbXqx^|K(6Uii}5@~EIg=zX0+X!}nXXJKNB_S|!WJX{lxS$a&vh`Ez z>ip78t<^xIr~eocc9R0`XV>y4M4Z?Vg|_6`S5SB zWr5n{!8~Gc4ur{=yIL^}WM8Q#y`h-2DX59Yl+{=;|-C(A6$(Yp5n+ z?-NNh2YJ5kU~Jrd4<-^)680F1+=PT-W9d?7=)(FsT!rau)L)D*D8}!61fLb3F*aon zIK>%1pRp;#?70M|gXgVnC2fpOp}3pOZK2+EwFe<8=y5Im-qu!7&*`ZlDK-Fj%$0m|GD93p@v~;VI0yib9jruoo@$f+a{AYZr zm7az z;JiyPek&=-XkgkG1CB^xEgA0H6Zh%S-Y}c~iJ0AdXS|G~%?CC&c;Y9U)}WFP(Z@&@ zT?~{eJ9XEvm>*Skd(Z+nu=#Ju?EklL=7a|z);OHUDa_(_h*tI6kx~+vXUy3d=RI6r z7%-M^2Z;C2)N?tBzzzIA1`dG<8p1gCFP!I_P=@ngC0!KHLESdYe&j-O2u{qE%MZi9 zUFz2pU{s=egOsiH))&GSP}JPBV%$GPq807x-kVVhajyK>!Dn|%I*{f>@(kx|&?3o= zK`V<}!Qw?&8ThW5jJ_lUAq(ZVpsCWT-}GeI#fRKzcU`JomK|8$)A?f%VQ%W0~2Yws!1?F)uV5IR-q`PR@N#;+HVW}^!sezGU z-Pdq6J_9-15^n{q!SNyZ54IIfK&!M^lh80jV?S>#O;^Y}6#8)2O|?<~8f(RAk@YPd zJ#k@bf8qa|e(el%!;jbtzk5R#SVuXf2ZKj!Od$~_&?)c&tGVe($;!EotO_e>(Of|)K@@ntJ%M# zQDxL$4Q(HYT<9?Bzd+Y?>OBlGnY4nda8TstjdaICMRUC`fSD7%lFu4GSbmK4nQ47> z;0>uiql9l&vvFt-N>H=H*vmGj09BN{c*`@y@Ju(X@-rbY z2u@`RyL1X1tWr+T-J{JhiW+T_$mT`(qwwyhJGFfRT|dRmvMvT?KBjJBBpq)Ku&WBz zVnIqCtRO$&JNw+-!=ut?p@}j|rMuA7br#hz4qo4rS5!38p zYEQjROGbUpdlt()X%#_2V%y;qCurj+GesM~&dl|2WGfIA0(s2TskM($_N&PQ=cmRm zAYHIpV7(`P2F@8RY4b{IZER)AaIuwp50XG`&2^wDRqgUL@-wtaSYw;UtB!|c#4B}u zr&xnn8bpJ!k^?Wop%J87KQl3?=K*WbFlDmVK0k5u-`M+9C+augpUt2r(S@}0u!>zq z!(VYJQVv@Dt*{(8AzF+e(n$Uis$xVOdsy>W8x1Q$B5E!v+GAim3$|JE1qXI>pd4m# z(z|I@d#)wQGmp{j@Ik_W84l&zat*NBN9d9!F=DC?gFRt0HHwt+xn13du!n7FclFwS zJeKkBua(DN8$abVrQm!LjwIV3x-JPpa#FGdcS23(iEVlZ?#u7SX7_hu+hLD%a5Qq+ zn~8wu5%TX)-$ARBn;vWNmHRNc*9u<) zJZ1UUMOD1o+zinoCuW-X$*>t3dGIx89mv?PGpX*5(kz@^cWYMo-`sQOq1BJd#a9>! zb8|7^7?(Qmk6(%%=s>lMPVT8R>Z81acv&585dQ(|fLZcs2v6ehwIF=)3b-;-S_3WD zqW&=+;h-!@9=s{?8ZooF^GfXe1)h3YKb0p>A&G&)g%t~;+n#!C>&-FmzS|3xUVBm(6*GTt4GFK`Nb z08GI0Lr!Qk3z;CA!G%b<4mc_nrR_t&zAH9Xv;)$&xbxtH89Qi`=Q%Qo zvp0Q0PsX`Cucu1yAFm@{_9%BA2f)aFdWv)+3iata=iQElLtZTAT4IuVH>m7ql6#)r z`kpFYZo`&wz9f_g&L=`0K^dq~9r_s5LL=F<%tG`v4HwPm4;me~tPdVyd)$a2x@2O) z2-L4<1&S9krEWW#1y*#g#7B4}GJoM?VeJ>0CCb^E&@jPuu-H+m?6geRI z(iy<4?K6v~5kgNPXm3Q*E>Rr9qDwCu7J3Ql78}OSYlBAF4_+RXP_au!MLwAq)f(|U4 z{f;;eGSUuTdCj0DINiO`P0ym4XR2`Lv5@~^fzgHvGC{rOx^UIEne9p&94B+dbV>RL zCCyip$yYoD&S%rs8MpVLtrxG9OX#pbVpN!0RkR zMp^bA5Bn-MEpM|=gp1vYY)-Q+m>AlHDOUpf`5^H)wdVnGgmr>hurwD=7E-pe#PCzY zFdaRy{GZ6ei*EW~B=b_Q#^aj5@JI{Hq*eVKK_+2dt3Q5y`CV*V@6X)sk6-Wc=#i#j zBw|z!45RP>CiJeIrKR*xS(1WdXG%748xP*(Wbfd~*zxF@xu(<&X|(YKTN>>ZvseTX z4CSD;9@Y*`=e3;>yIu*eC0v`o&%;XbVj9?!r3u%c@DuhPJCc1Ir`h1W`QHSoRgKz^ z+#Zur56dvDwHKRjvec-@*shyPie9e(gQ=@U|Hwh?|Had-W3Epw#GJKEXoYF3jz>(y zKG7nTM(Mjl!+s*wLNfO#c*{|5zeM?r^DSVal?yN*3oze%l)%6jZ38eyJ$9)|YByGu ztrqhZFQSkL*=Q#67`=g6J&XI(TGTzi%1061Gf)=Wz>sROyftzf51PLgTN=O>bD?p#=CHy=Hdb1GFx3BP4q!8gqJ>E6>gfb`XW*b51FZEW1%a0bfx%( z)%CteU0Al0$3_$j=?M`gT)~(elRE_1nQ#FzwtOe1^yXpO9F28X(i(1B*-m*l;Tn;C z?l?ZTow5z~G`^d$`ve&EKm$;ZmmcC8Pp9E!^s4UUWlL3J*T!hlCv3bHb>6+w_N(*J zS3UYdRVPbAhp7|vja&|bT??E85xWLyXI6eXQHek-Ex?`>{(cwkJdGQWgwRi|7}0@$!ujevF@1ZRonjKwywENzWmL{=gl<4g zj?T+5sWgu~+mhxH{btkO@=Efb_D@lk438Gxwzg8$_%QGq>CVD-4b(5_*SCQ|;YVWW z&BvLVXOCOecNZ_{7Yy|OO)8qpLfA4 zUGz`h=J_c}$29M6xQ&teDL z)Udlr=M)~{^2`SY;sJYr$@T!7G6xv=IMnat>`s_WXg3Lm%Xd!>UymK%U5vh>u0)&I zQe-63+gb$QJ?{*L87X*GEdm^oJBrRj6xZ*>`xoYhv1cBPVT*Z$Q1mhT+ySNM+$@0`8HGYOb<9MfAwzaWMV2#Jc-sJ|ykNY52j;Q^tgpGgxQC}z}$ai7A} za{~Aln4k>qN1krHS0q6F(aA@0`gx=|C4zroKcX-#5+P2#^57|oCk~i!{q!Ed58Dx- zh(IdaA6=p|0SQ-#_qbY+r&gl?mmC?NYc-^N5xA`gtI?^*|b zWtuk$*BA^Fgb?(I$a5V#fuz`~Rzr`0q!=(G;#m4Km!By8!N z+8FP1!1fDapBhYCUUG`F_zLzmQ`Iml*+35u&mW8XAL!|0@hB?@VM3%Ayc9Iku@98JGtm z=6n&1F2^ey5ma$gz48kSzA+OSLu6Diwk!)h9bjaSk%VB{0AgeRE<8e%yA!V8$#W?F1C74DAm7pXOLl<}zYsFrRr7R{|r;i5sFmO6UwDn>~XZ3+zc69^u08l!xZuVi2N zZXHH)dn)O9)7TKASa|>;zZEB32UiSAnim^AmusA{`Rdr}MuflQya9_${bbMQ|nk((|haeExyQul(*B--b|A*qpIcJT>4M3(Q0YO?4 zOg^i~Bf>1j0?jV?8bIxhVN@jsz>$ijzJw}d?9VI;unTEZO>f~~8xU8wRN0$A7yhENb z>P?6kG2_u>Ew(WMn5T%uakRoa>PZf(J;W``5AgfL;!Ec(v>Z{*?%yh5qIL*7%q2fzOf=I!_jODb&jOAyK z%we+5C1qf?t6xq{6AAGP16Q;Fgp!cz#V?Rlr9O^F^sacn3i27napc%i9O*3%U~`iQ z?U?JlGK2y}+ThUdlko$~<+DCaxL#i_4$?KkCRFAt*$wR)B5f6aFfG=sZ$Mh5#1$q! z5*;O6kE08DJmLB|zD98J9-3wGoE&IIwdpqn5NBP!*v(m_x~Fs%Y;0)s3_g4Ugq^jA zl=40%3FiLYe2UZ-Gd6S)8eo4cEhW&$AT(sNO=w2YeoD~zj#^#BI#qi6hZbh_j}yZd zY&SkUAMd94b&-kok^{si_V`Hp-FW7zkw9i1Hu4$IbOWhT zP);WB`REX~wfHFL3646nCJ*r3#B)1&ydHD;0XvV69Q+=CAU1cqe(@@V@nF21wL={< zhmUXn+BeC!;H-%>}!j^{bV17^vIm7*SHyPYDJP0Yxtkc`Xo4O z-!$u;pZ;IWy8bjh>vwMc_OpI+N}pM8WGa^w{GZIa^pbC$_1{1FznJx-gtYzUZtlkM{ze^P&B1`w$AVFQO!=NH0;7`hC7CtMHR zMllY->zX6KSKv3d1WK~uG?<>{3D-5rHnZ?+7mSQi6J&eiR40v&=ma}_7>8Aex~y_L zm?LJHT{y+aYDR$%;ekI|4UMj9h5~?+jtt{)e3W8b#{*xb%7?J8X0=BR+S?@_NypPi z%M_+TW)yE4z@^SWevKh6A0A@;!v(tjAv~N=_HeP|)2Xwn6Rrnpp~$cU2)oj!I-68( zq$4Yug#&GDi$Oht9Xz}Rx56-<@fDrjq>j*S1~kLsf!CM}q{1S#r~ZgtuVRC*3m)br zwYoMy?^q43jwLwe6fSqGdg*>*pjG7}6-LWY(?bS|1|u4S1~j3$yGB)DY}&>&1!Y|0 z!KUb-OfOUWdufkyAcsu;OUC!#87yl7ic8{G?23Nk`|mCzo&f-jpoD7Eg zI1Qw1XTs&z0A6JSxcXL-`cx`WE*4=ux=9U^1+=3qbR?3X>J>fA4cj2oOV{+YUb?GJ z*0UOB&nkdmX=+xaclfIe;-yL}koyBPui+p8qv0M|zT2U%TNw$qO9X!m&%#(eeHL=M zFW-n58Pa?_fhbigI2|Q|;OZ&(s3~694C4g$h*&4VXf1}Tag)+BPaER&=rA$$CbiWs z!d$;ljb67Tu|)n_hbTS2t1m3q9u}6AzbxzjM?5X- z4_G>XAzdL@0-$i7zsQf_pv=yQJqCAq8!t@EGF}+e^j5*(7JSc^FDAa_;G4N%i#fQ( z3kAUE0?~p_I)VX9_lc}Wg6&ww?pz=Ddv`$Zd8;Bv(wqaG0o_#r&6CTEAQL@Gb75vjYB3n10i zv$1Z|x>Oq+d*L+OZaxcd*Y4=YaG2VU;Q*3B8aAdlBhsb2Y{^R$H5ba!mKVDmdPhLy@ zJ&NBc;fF7tOR%f?#-hK#UtI&ViaggrgNZ=5L=64`N~gp2IPROV%EigIo|{qsVs%WM z8*<)}hT^GOmn^P3S7LVS(KuiGxD0r>rSBHRdloaC7S3;ItTg=p4o1WIFfon#i!coR z(MO8@%z?OND5EI52rk*zIf21wwK#$J#CFnZh^V{?*J2^y1^QNgXK*n39d|!oU~odU zz3;lQ0-K2-Tj$~s>Sa>m&wv|j7?YsK{EHbXd6K~4ng_7P{D}3zyS6W(OtlTyP~>_w zj4Hb9_=ON3jiBf?qwqHt{xxO~6R6=Nkh@j6ctT~um{JKGE=x2;D;KNts*p&oM8>Y0 zali5S1$!$Pz0>eofA>we=D@9&NO~}pA4C_ySmj+DvK;%kqm_4AFU$CVg`dUz&z*2R za|_a3!i175k|s*zLnUh?H`+H(NeLjcbfz~k%*Pxwq6RPdQ`|2~BO%Nm*gkU|wK7*I&6;@cuLu9n?m z^HzKhSYn`Cv&0Iirt58S9fl>$v!VYbqdguSrH*>N?7Fqp&~(&u9yjv`7eT_&O=EyQRy73i^XuRYMRNoo zoDK#Gz$_53jv{KJAA*~NE<`XUogzEkEGiQj=S@#&->2bNu0^|Y)v=RyRoP4Z+y1L? ze{9Tw7+a$v02^E?W^fDIYqFKmz_G^MNScoV%GYW19F0PJ>{;X&267H2LIV=6frJ~} zd`%#u>>mE2$BAhceI@wgK(MIqmw_N{Qe$C9{Q9yjUL24n$B|}-hI6<)pVbr}QfXm_ zTBGcd1Y)EB0Qy&wC@8{-G?ph3pDr|l)tX4Sj70(wSQY1*BQv8uyzE;_>A#gFWhhd_ zfM3eus>UD%+KK{V&N2r^6(~g}Bu7+%6!TW!N9nbm?-vB})>~BtQp!%`eNN;x5_xFB z$>59S86qAz&2la?{9SKUQ=+_}k>^Du<3q_qbG>eCn4iXRczA9Ke_X4w{k>PqdZX8B zMJf`ZYbPu%2<1hW7Q}~f^K5F5FrRRqB=pRGzaqjr=09-pS zg!ci1gJQ5d`?p5q_2p+VP=Hc04#``0kpS&E;;2Rgx;Z)c@yZ?g|w?u z=T}A)PXnnPX{;VGy6*GSLPP65zamtSXu$@*tlReCcp!PXl;nrNO;zTCZbT0u4b|tL z4{+4oao+TEH~Y@3a)k32HskX&;kha$1yC>|_#9;8!1VZ7;#rS^kP)^q9%#bZ7D>o@ zhzGqsVjqZkt8=LNw~|I!lfh!h7L_l;Dzg~!#G^?l;`B=~r0Y&dAmQn>&i?e9>D3KB?|M;;_9WRZem{daK%XT80TVPzhwI?a8o5a9d!7^^i6^ z^szYzg2zvV56o$Pgp?rKWjuLj#*>;m;l;G7v)^Y@RR{p#6mJK8N!I$|-NDPVSRv35 z5-l5_PhZo{YqCvjXe;ztPu)f&BCEtcfWi)WJDgBbkNp?bK_H2d?A~hv5VEd(G)+2)MuZ;QDWM=o9#nl5${hP5_@#tz5JU( z19&=Hh;L6|M!H?qE+NRYu|kzXle^Tb*xUhrKZi3(z&d6=xG59(J;wbrz_l=$g(1@z z6LVT*Rs5ag!M$qsZiJ6l1fO^{(d;!+b?M%pwjp$_@*A*sbTJI}_XAf*gG1Ta z=D>C}{nxM!0OqZH51CjDybF)h#3ytHo`4kL!D^RYC1uDL^FzvzzeL4|5AVi{xn3K| za#(~fe3Z9s>UXsqQ}t}&_bdla{& zE7jhs7H78}iDNu+pFEOq-6B^*5Kz663<7EADQwL8W`IIRzZ#zj*K_lcbol_Z59%&O z#hGZX`l7kGi7R-i`({Bb0~dI|B(AP?4Ciw<>cMUbTDq|$?b!)VYpq188oib6lxbw+ z8P?`YKMB|67!XTdWH|HYy1+Kisp^+T-cDoP9=x+#^Fp7Rv!#5F+Y6QC--N!DO~9CFX=<{aG$S zj5H@-Ss)VUk)lPs4I2p`DHBxdqlrJqB7^?kHe>|#!!SE+Ra<|U8G)j{;`&eI`hVJI z{cq+o&|A9xu^UT7vBcHE1G@fEnrPYdUXnxr%{P$9#(A1VHYXp+?&pzo3HlH0M}Ch- zk~=9;0*MEO#xN%852a1NG)8w$Xlx=IS6_K}+QQAl&=#)RwB^);XxhT%Z%tc?D^j%e z<&i>LuHiykhw$rgv?XAA0jAJa7g||)*?5Gs^$C0UTH5jq?nzsvA+Ba7Z4vm4*I*=R zikC@m`~+>`BeR;e^I;0xY@tt*TDIEFDf-Nn($w!LU8}}(YSl;S z`D#T!?FP3Xy|zL6I{^m1bdw`*{IKH9`Q@RK5*RU?I3XD5ybIAU*aThf#=&WS{@R_ldw2Y*#@(D&~g|@;sVl%h$t{4%JBM(93Zclt)PE&|7El z(d`rF7G#!Az^j5w+#x6LwyW6oKBW^uYk(hbr9$Zh-q_KnbmFZq{K(M3tE~-0J*B}Y zN+jYBTPFMfU`myG^`vz$m z__e5|cJ+5FC2B=b6n}d`Qc}nCljpA}rg7pdJA1*&bH{MjMTUw`Ys8L)eynl-8s{lbqxl|BCTe*e~N#x4-GdCiQ4imDM)QWwqQc6g-aQJQQQ%cn|wlcn_# z;#;y*aT!IsVQxS)xYRC`5_^uJxdPVz&+?)amggqlShN>$9|$9dt*iE`>?3^@O6KCCh{I_h!%1VV(N$_)JWhefRRxVpvxexoT2l|k^M0dxn@~1oWC3}qXuI;b- zt#02+f85*j5z57O_*UNeK7{8-{ONt+sMXmHT=@W3-s2T~|B#)dc%L1B{#IVuWvu=bKUZFf)?dh%PwY-{h^oVX!|TUY#sWlu zFK4g55#E=M=XenfT6yKCm@FjUmX($N#y4a2j+K?42^RLptB{a;5Bn*>;@BRw53T%h zV|C?zWA!DU;Ya1a@!yr7;_nk<^_>7A+=UC_kMQ4}AL74jKEQuBy&v^2!-MY$qE>H- z-dD5|ON(5jv3h6pfucJ60Lyg^M79Kj#zGD3v2L+k3}A1 zbpmObYJBbo<;}(Y{XTrD!j}X$hMM^Djt|L955CB$*X7{zQuK!2JMp!cIc7}mfGXsf z57w2}nz2g`P?~i6z9oOZIED=$DJlj@YW7^Qku)o317FF*=TgZ+ZEMY2)tA4L?;|Dy zxxH}xA$rw`?~14wKC72Km=ud2dtacxFLIodEf&$GW7j8KtY!Evjmuz;mM#)V_&sw5 z_Wr@uxKHo%xgrk+g18ZjcwmSvwyCRXdTvDhcqy(|ycu4Gpi^iP=qXTfh~gX);7#lw z#pcpCgh6?rPQy&L-4LEiu20t44cRx4vilq}=To!fi*O?c>6&WSP%^AQD7ZO+)5g{W zoZWW=Hn=P;=GJwD6wtg0%@GOTiN9SEuXF=RZXn6=FF_Lbd71c~k`!yIIk7HEZ%PHf zEif=;%3ARPACx93#R+=>Pi$8&>|vM(?*X+Qun%B@dTCR05NyNc<8004z`s61xpNb) zQmKBEy?=X^UMLg?k?5NTV4)BT@VNOCm{tEDZ|4FZRdpx+NhS#)1ZD)H@qtDOij4{t zwZR0Po6LkeFp(fASRdG?OQ~9mFoReSf|F>bx1+R6yY{u!cH6q!ZXatG5nl;W5{N*+ zs#vXp)_UV;joKm)%lyB;bMCy7ptigF=fh;~+(2CzbvbUw&OSxvk|kHX#@;asb)KPgwSg zV|l4(i`QqKPTQmG6gCzd-(G-c!{t&T_)4T)(wWwd@Tsit+9~0JTJfIA!+XZSd#00O zZ>nNj-8^L_$7d%qwURjY^eHraj&4}8=Vm|V$=Fnv%8I#?RB|%(;%_pE@mo1LJJce5 z!6hb4J{KvQ&x?H7K!bc<Zm*$nd7+I}k5Bo2zNtm}t9-mp zlWO0~BFS}08bp5##*b=M74CQNqo@Zj{K_pttG$3e3-iKaQQ=C+F*4^kqGi_Bnv0Q? zS4g^@QNfz6j>z{+5e_LjBHxZeUZim3HTiO#4uC?OK4`s1RdfKtmw2Lr>w`5rJ*~gu z!ZJh!SzG976RSJZ8f*vmU6`JavxCcZNBOnHXUTC#VUuUvQL>dB%BB&%V-_Tw{jZMl?jro$xD$V9+ehiU+DF;@%vLh(5R zWWca`C0B`wt&>7s87sU6eUJjfneQLl3XgP+7(x;A>k!ym)Fd*X#I@-u&$HKm)*0A( z2A(~z&qyrV)R^9^9d1l%YCmmM`d?*IPOlObpG7b1azz;Ao@zP5s9A*Xf7;0;B~(J8 zU9Ii_Z0gf=!CDgsK@MLt6j=hUvSzvGb~M1c5K#idfwPWvwIq<$*wwPL-}!Ai#XOAjFJ z^R_%DWh*5gc>1m1U>^4|S^&@8-&R{~ryU-T*=kIFNCRR%SWREemW}Vpbs{H$jw2bcUbmi)eQU{DEJ3TkP+8$=-6)G0!SH124p@H` zySxf6>pYLQUMRH%tPeR7=EIKt^=?E@*jjK>1l@@5+m=#`=ka3uB_2TUe9E-cEhG74 z5JXo!#qS9`CM}T*PB+<5ebWUMk$+1RS*izOg(hu@WtlWj-j}=2qC0ZRoE|-#A1SWA z*we~#LJwV8F(p#Lv2#lFa9-pDGu|eB^H<+g%^9~gFY?#^B8o}Q0Kj&->F!~h;Njd6 zu5{pKv>cpb5Ji{!oMs%8h9~fp-?Awad2K60a^c#trphXOth2m|e(~Xe3L*oJfKeYU@&JWsbSzXQ2Q2kfi3{AUWD)d3qKX%C^8XX|eq(27~ z&eHR@|6;~z^iJwK?<4CAO<$rcId|Fzh!rJ9f3oHz>4z*h*~_wD)c%DA@^O9L)eb?g zsG#+&IaJU(`I+|Lci``Nd{o?cr8e)@LL6}u?kQ39kK|-j}VB0aQHx6}CQseKHccifON7+{xlBIVbBt&t4I>>;; z7cg3C%kh^^sf^10>4;3pPJ3>h0`qw}@(VM%HJ@oSbQ$NJXd>U9s7i-lF{4NFR(M-h zp9p0t>#089bH|UllnUE~$!S@W#}#r-mlFkVhh6ui z%%bQ?Btq)nFmA%F3%d4%EV}kuxdDj_iF!FBY(6Yd*kzB}qE<%al6X_4{GRxf{(YWV z^EaX-Btstm2LcqM9mDxVet1;NB~v1jM2WFWH`_kTOeMx~86IP_tVvD@k6<`cz}!k$ zMSz5z_Rsza`qlkD_h}N71&Jr0(de_DO`eKgtkA19?|Z&3=E0bj{)BX|Vq<{W!`QTSgG!dM{HjFAv3nSuenRq*f7I|H zSkvuL!IL2lwBf_rxq9ud3|JU!%Q-9-InUakQ34Vh+wYe>cV8>b#>(O<|@ zA~~4F(QUriEO3k@>J{}x^tN)B&QZ3Z6buWSFVwr*NIGoYjqv%)f$wX|pP?&dAR!Zb z{#w~Z)Asa#hfSE~2^1IHe`osEAb+}~{YaA@!}*&>08-h+d0jG%vWZ!5dJ`YRrH+xM zH}QjORI85sy#f-^UjI8iqdI$~1GPhTP`Bu5-6Ok4$Q23;jaDHKBwh&HnS4!MqKB@Q zXIKLv_^t3#XDx9pR8P0Io+3AR(RngUFLY1aFXb*NnlP*%-SQ@}FCN@=`h~^^`$=wO zSnpPC*=@VGblQbCc3fDc_I2lr-0DjHesygCa#doNc1Fer+KY{?zPyWr zWd4B`LpRo$?+6<>u{w>dE^tr>)SGj&By%$`?Zrl`Cn%gJ+#2)%q6<&!J^;OVJ*Cg6 zy(WBW?Rk-jB&p8}*6dl%-omo_8kD%`rwhJED_;(vfAaWkx$%#;>0k$u8;T9b#H7jeaWUyrTzZ zlH8`rbfA+GkW`Rzg^Ab5po2LS+YCv7P8USZJyR=m@DBh ze7qZc+;xe|b-GJx!S0Av)7f%pQsfLIFsmY`WYbq0i<4VKoO9^*$omwN+)+Ic@slED zn!ZUtpA=fxiDH*BrYA1(1wX4FTGU01pFl&y4$0Gu(Jp=LF zS&@;t1uAWnEON?fZyC}E#H7@nH6e6mB<+GN5`QwSBTP%%D$Wk!ykuI^qhXP?GC7bo zGLm3?E@`^bvx?OvOp7GkBN5}v>g+SH0}?`MhcaNp(hX)o){1BY)B?&;=Fr{Cj9t^KAs}8OQ<+K-I<`@Jm zMcyONBqp5*`f~G3&hsum$-!T#PHUyJB&c~?a(N`iWM`XX2!pIXvuMN|(ayCihM7+s zyg^c^ekxcD_NSiCq8rcMpmL((`9Lz^Dr9*5*vcL%Pzm97=F8A@jA&!JIW)0{qLn_v z-)d;IVNO@(bm?1qPMg%Bs^;`>GR@AMPIqo=_&ed6QxD(z;W4M;^qImiXk(!drSHu2 zJ_UW|RcIrnwj6!sNA0^DDea4xeGDt5 z{gGE5AesK(kd7$lRN3cd3HC2^(NOs>>QxU zhA&BN_#A+pn5FL-1h16v_iZJL9*m;W!rv4=@3nuMlrHEsoZ@qY#Zfp)qH(8A2(8!5 zK?>$FkV1}3_#$DUOklOmMMukxZ&}=A4H!J&%{Vjd<{-=%I^moj_Co z&&IENHoVL}+;C4jU#9!{ z}t8bR-}SIv?|FcX{Z(bZ&Yg5wjp2Vv`Yn#U_!Q`x6hH^(yrjCosv19;+qXAir z$IeH2?+<5$`PH*D691$|nE4;FHq+@BjOtS+qo1_E+`H_V4YD|9rrc!)8CUiYmu;y; zBX#U5V=wKk-4;yKrZhO|{E_*@J~Dr@tPxo@lHrNS zObQyr!(yng*W&RRQ{R2|!-^h|4zUP_>BCvs_~ak&kMio5Es(?FDSBA>)2W!;hwKDw zfI1o!Q_y%f8$i9O2sEU2xvwjG685JUIV-nz;@rI^d*}uGM@~iYvIiV`$fYV%`p&Xb z`ZXR|oi4Q}q3`@2V+iNGEz5UGU70Sm+NtZeS*2X6#a?@Ay3}(HmbyEu)Z@0Uza(9% z;%$9rNmi-#d-c6PqQVp~#LND}X|XP=)C#Ar$J3<>oKmM`mAb|$b#J=VdCnLQd_6P9 zOPo^6(xs}MQhiyaDx6ZGbSaEEfHUzT)1@FLFslLiKoyN%-hMpnICgoBL33V6xC9GF zrB&rYCq*^O&}W}oJd_6U!NmT3nqoy(P=` ztSQfM!o<(r782dg3s01S9)=UfXdwKfO#821)j;^3Pc5%UoipVe zB*sIwqe5Z=AtkZFR7&A9!tV6iZ@nilgy*-mM89fd8@6m;_%o;pgiJ(?BBt`nRixKm z_I)V{ii~y+z?8$FhYKF?gzKXR$3@_FrV}I18Uvv)U@w7%6mul(2T0CP>9^W293 zjDutNM3TvLK$r#SJry`I{M;YkmC?c7D*A_6?k-o+uajkmCkdblvx&_UaVF0!aXk)e zA@-q#o`=LH7bqT33bW_gIDV$Z{@{HgtM3##EjTq(G^}OAJv4BL4 zR&h3QMU`kQdO~;DBEK^bpwZFisS`%za!Q-gfOh~jkfJaZd8dia3>D_|7y2nA_SDi} zp96IIdkOZm)_Y?6DLw5?^;ATBLCb4nzDT!^5pd;4gkQ{+=sBXUL9vDE)RrD@+YCN0 zhK(;YEvV#}zu2d@&szvzV7qj9nO8sro(AJ4Ew@=mU?Gb2(-=Vb5*Lexy4eS@VBz|hr>w! zgRo66%~W9h@+%swg|*7+Tp37^|BLOx!Gf!eppSkp0W{r_a-2l--t(N(F=(GCTk<7# z6jK7;Il;4lSlL4h@v^^i$#73(;{F8Hsj78E#u}0M-~|TlH%Fensc9-K`F$H5Ni6z$ ziGm@DMsav2?u_!gH>{({GV2WDpW7m?+W;gbL{+t@3z}4-FcHVd8!4AazqLbb??Ix< zh95s{vTXU3y zqK=o%5-J!&Q4x^X*RIz)4ymfFVj1V>101u0wUKI+NMr|3>l?Dh<7Ms7>cv?8kzG=Y zGTo(@5>hdp)L_!FLll_yjQwO_`Ytu3!>{eYGDdb=28ydx10r&L$7{{h(TobhpN<|R ztE&KfAaRMaEPgXWql-*fl1sDRHLXkKkW#Pcc_m87&(%4^dGvkep8QO|(*QVO*siDM zM24GDyuA44u>i0eqd5hdTwRy5PBOjxj;dj&y`RGXQ=_ma4UH#$gir)TCHStRPZ%!; z%vr1P#$j7Y^)=JVG}Vf#X#h=a2JNZ@xrIUNXo94cYDq4^W>O|0^YVdyH7(K&c{v43 z)gi$61z2v`BK@~=k&(U0mEezZB|0$Vy%z{Dp66-3PcOK8`o_EL8=yu7J$zm6=_PvB zZZ#cCc|7!Bv~N>_b(UNXTvH=fh#|v&)~cQ#Loc@I&fFtZNLG;*DUvm075?xW!ebMQ zQK79yNSFz}1Ks&y>`cp^*+u8rzg54|=g#@;Fdi0!tJq_|e1Sdx)OfY$!zYQAP`vC% z&I^Zssb4@nA}e@V>nIlc5q>NEFfV>dz1U-a<2`W|A_#S|8*8n2 z!CFG!ZRM57i)pMqRni@@VA6xYp}+}=Cx*;na<-Rk-mMq;`JRtjo@rGq@ee@{y!Yx( zJ>bKN7#s}#H2TYsh@HHblG@vULGLANDy!c6c|NV9-_O~cSu=yq8?|yoORG&~tQXWV zoSW#^(A@Bl+_wsT+5FM4^vyhSbHc4}=+jVHeSzv{1p{vDky|%y50CzY zaO?aNRYhl9br001r}YlK`Y)TwuyYKx_V2uaO6l6Ii8#haKeLZfH?l*t!sx|_;B zcE&#^`7Gmw-*ryAubr>DHO}eQ$)BKGLaW=a{!zV`aH@Gt5vzl@MP@>Cl!iZ*ca>`g zx^?)CjOMy(2QeI0mtu8B6HmZGCMFY1QcMs9bX|J!oFx+V*a$|iEDGnKOI4vh#8)J> z#T4i+NwpJSu#XBE^>24D`)6HD^SlBshf&Wm-OT0H)A(Dn>S^y|72fnJM0)$o=EHbh zW(9KJftL;P#o6;iRv!)q2Eoex=?LYs7Ya6y)h`UimN>zMmkbYm1~?{>cLvnC;8=)cOwyZQgV#`^M3E*eBokS%Ch58RRCq4vs7`x0fTxYu_H}<4*gg&&Vt=;rgt; zUW6V?n?@Kx3XQEyV#V5Q6LJ)g} z=YmyzS^nS{7;xScc&mCMBbZd+^;R4H>6w7EjaESy)kL1!G(xT19HB;6Iwou_&bP_% zi*)wv?Rr<=ujtofW00I9;S2i&4%|v-lX1jOR}WjuFvr0e)Q~=&uONbR26rg@makfv zS*#do;mM}b*BLj+Jd5TFaSbkT@YWe7+FLJ`(eU)idsaXFkB>g@tE8Jfbd%I4BMgs) zTtT#1*uec@tffQ78!uc)whP90`ik-R16U^*O2Ms6$&oKc0I)*M@wN1DX0Z@>zn8;c z*&mS=9psmXNIjy5C4R=+a*JgE>e9($|Mn$41yd#Nhr|zLdpPv09)Z*Uls+$Q2l3>I z5Mu|R!|!>3PFhFPE92)pklX*sZ3z)1=@%d4nkDXO{jChByHms~#QPI@67~hY>I+6h zK1kVzVY*v=K{2Xh>>ciCRh6)6@jZ1DSh)jxGcWO!OI=mFQHQggwn;o?gK#z=PtCOZ zJR7ze1WeOMoI0=4Vr4D+!H_M_e(iJ_xuR&M^nf9D-MT8|w{B|+SeyYx0`fbBaSgRw3^`g7eZ@q%N$>{9O_ge#0-{iTY zj+xGD@L5;-{Z@nNw=QEmS2oGMsE8L_thRit!CxOQD33LmM!W!v1(?-XLx@`!#~LV! zxLVGYEcvs>XPAyHgqby?1MaN_#VtpTg>t9X7a47TkCX8Hj;-|zU5SF)Y66#R?9j!^ zT}SIFRxicI$nL!*U9z@1viI2Kg6VR{E;H#9l*vn%v1ZSAs_N{Y&|X?TsAGGPis&I^ z7c3iE@K?hY96hw)ox>I^99r<&bU`5^JNCPse(I7fs}}kqim<(qasp#H`EwGADS3mU zSFaGSqJJk!j>KhR-G0T{;_up$9uiuvbzy8|B#?BCNBYdq2(kX*FkOT>D57r(JX_iV(t|6O;x zfAr6Y=8`F0N-=eprw zXMcJ2AOcZcrZuQ4=WzkeZC5P@+N5O~xHGrmz+L)wyJ6vwq=%i;ZcIP_ntHC=&1uup z&%aLfy}`~mkz;S+D-95WjZxsF_Q2hP+Pz1=w;p^uY`fpk&%ddjr^cJe9q&KuG8=+c zmzsd>!Onz+bl_Xk?8)tcZx3qrU-T>Y9%HoM(T~3?k5jYzW^SY3(?z~dxC#Y`H=P!L zzP|YZD2Cg)$k^J| zRbL>nKtvdeJ>m$F)QCZ}>YPwRD#9ndRXjWcJtj@G3-ZIEiKg~rS)WZ4Jt)r<3M8b33J1p@Pm2BIZK1h?*Uml}o{CFq)K7;G!6o&H5;WF$iq0xBu ztE^|~^);W=@AE|VV#aZY`4eF+Hl2j>ZQ}Qo@=bC@5i}_FlYP+XFi!+-fbEp-UvKZ7 zA^g0jji}e$Da+fa`OIw^oJiccABxA-n_BX}Gm#IWto^-imbaoEP2zd*Yg&{u@&UdL z>qFuDOmW@1PwrdjpdPKfmrJ^FP`V)k5n0!FpG+NAn=}xNH%^VU4R95({^HrF?ito! z+SP?*Ir51m@WS<`l?VGBw00QS;s1)~5+^`y#7}gax z#f?0yu`df+jZ5QSEkVTD`KsGqk+0QvRjDdQIPXhtrKetJ)jp;MPWv}Xg^w3H6~=DA zDHsbZ4O)ESSD>pVUPo<@kqj&`kqnuQu_=wQImLXuf!Lh#U~ExEsAlT2F~Xx>W_IU~ zrHhFG32TCw1~<9`*9WmeW(W~-$Ew}?TwuCcP7+VbpGx@?q-Av*a@1>}&Q;gkd-bd()?+fL;mPHL~{_7@;-Nr=vpk3N}Wgy{m6^t zR=G<@E(ls{E23*pafQEN5+q*7P-C)WQj_&9+4h}pde^=B zWdPIvs5JSpu>R%8!MX<5GzZoyymT%M0|~l8ri#|_H0cM;#;;iK7xm}p<_9^+$6%nP zPE&C()rW^ZRKzt%4jBpkBPR*o<#Ngy1c{W8GQ>J|*`F>FS@xU?5fK*J?j!kR@*2VU zCooaR`D7byLX>m^V&p#xn?+Q@m=o9~o zkzKF@3nORk>f3d4djhxnOMrz__U+$rvsiBam9t*3@zs0sMGKnXr^0BX-;^S+KkWc2 z7Z6Uol)>_+H#o{-*F zGNi4wL+C%b!#_>$_^o`X5G%GxtubGn$7R%PTTA3U6(X(Btg5e;6ejMzc)>`c29M-k z!!xI|W{an>kG7OgOBeE&WIscq&cW-Pt-KYvynkBaL(F1tqpti{XL{X!oM!BAER zXeG}i6smSl2wAv+ijvrvYFf8dG*)#6X*Sfn2M?B`)j|F|4&( z`m##J?>MW$eVorg!Ju5Fz)im$n z424)CwuV^Hd6$b}p6E{u^luO?QA2E_<|_Z-x!x`b$%RS`;F$m;Q>B{EkVS)5XUMv$ zBG|mQF+OVm|N4{6X0!r@KbCBGo%;)dZUPlSnhTV+ z_!8%vmRmuxYCBfQ$A?b~S>WY0~j?OyPZ*j;PiASqJ1pbZ!iAy#1K;1}pxRR&kEi13cyOr?!Jy-X? z`ZEa);+t=@>^oTLHcC2-c4K6Y>`>q-7z8&-R$v97oFoe>UN%Lt{;73E2#`*Jrqds_ zs=HFl55OzP2Hm@z=fSAY>+On^1+69pFD95Trd3I(|o~i)dgVDJ73NnGYRneIr zku@);9_e=aAN^-F5J+Op@#)QwCu?BYW$NHfca~+~>=mCkaekx(&O&dNGo@e0sebLq z^lQuD&BDP~PEW*&@Tb}}QY}pdu+c}a5nG{x&Mtwc)1Q+yEMGe%1xwW}wKV6aAedU4 zL3fi{n<=;@&Tq8xsNm3bc~(|GRbH*;K2_G) zL4B!LxEU{dngn*K8|lg90(aa>!En1qkft|LD-&xn zv23}inTb6$GqHMSXDztx0>RO>(jPH9E>UpfIGd~tji=fteTmapeyVO}`c|dk>CW^m zg?b2|HLF-OMg49G%<%0DTydDrg6rT?k&`m;9sDc{&Qr4BJW=DR95@etRl)n3lUN~x zdL;wOjK^88(mY;X7eP?1N$n%k4UTWj!tqAXatDaJU$sZJ67hJf=P|bzv7Kp^3$FLq^sOCl#Ot!L zJ)E$l*TmY3a)Rsen+A)P}8|)bYn9Td!dO8uN=aPU{Qx~&>9s0+26*| z0@jw8OSIM_tqHal7aFj=yx5s=OYJq!hmQ*pg{>6*j8Iek>z6}=vD>npR2BU>HD31@ z$Ucl`Z-s6!#4lNS;tI{dghF2#`#4Mn#8Rii{?hMc0gLq$-m-%a0H4m@j41-7--Q>I zGx-pbhH@8A1N}J}x#=E}UJw9%&qn~=gio=4@2~oO3h2)b2KrtBL;Wy7$CNq;=v%Xz zRzRN!BH7O3hoqN{-V>5Uft&e@Zk1@=aFmw=r>elql$=fW3+hyy(( z07q3}K#7LEh6KqxRlt8;f7w?Q65y&=tR2+7cW+5ePnN<|^9RW9nI9+(rl-ele}Pxv zOA0l^!ONLh(B<(}X5Fytw*hkp>HPfVW-Tps3uXm1D_>VQ= zWfK!u^I})HNFUgo-0Gll{wV%ni2Z_cO>ahecy22-vCb+QCBMO;$At(bR^$m1&r|JL z_|#|9+cs45GP@QzqGDS>m5OO_$YHGE^R1muicDzXkD@uij?W7I-bZHV0#EDrV7SCV zVO%3QNk;^`g{KuJ|0jHjglWX{@-5joi3sS#f7~p$=15>m)meI}`U}vB93b?2FsHK% zyoqYT>kFs^+Wj05YSsG+x3bI?Zmk)BYH!FzDZ2%aKP$aDp3$|eEG~!?i4AR{z_egj zV%R0X$aKIosuLk?Km<-OWtHTZLZ}%L-cQq;Y*UA?fKx1#e0WaI>n(}7S+q%p=mgkl zq7x2{B&2Gaek_M}zogBROwgA`(Fe9#0_->Q!V{uz=Cgbbk5;EAS_#-c_)PU(4&8_1 z!7LSYW;S9!Ovsj`>E32US8qoweW8dMpcI#GkeiXcj4w?Xvs-Gv$fS{)Tu5}i`XDsvva{cZ^zX-# z6z=~TewWY)i_uK=D%G1|=)-aUKl<}a62vKZT^j8;8a-HfYZa#4@4j#}Y2M3$-sn+uM2i-l%{n?NNu#4AE;mKKirtu+4j|**gPNbgPUld5;Tga*IRAyYrsSG4^ z0U@`L9g5qW(zOW5m0d=j>)Z^Iqf7J4PSxs5@VOIO1Q{z-=pnJ44I|C??+qUl%2ma2 zy`_BGHmfsZFGqku9nW=kdH5ocFnwe^*PCCYPfk47Li>98g7DR#V8u#JB~jL?xk7~WV@apENVG1UYP7V(wX-sL!1h~d6i z@u$v&Ub{uA*O<6l*Pbo^1yuIUyQKtY0KLYN+O=ks951GNk6k24T=gmg@xh^%q^pxf z(%B^SojPoN2OpGHx~OXMq70?x%)iW^^5<8CbFi6X_f5tPn?S(T^yDiCY$XDuQ`KUE z=aZgY*OfB+wQehqH{`Rgk^5k_SY$`v5OK|%`Jh&u2(%9Y-tTji4}rClfIAD71)s3G zzV@XhW^75hc{a*<G^} zlBqgUWzg!gqY%xg-~t49m#o|Mgli7Qc>cU+V}nE*7WH|BA(B=RUeLQ`@ z9j5A2jn-J1e&NSY<{IEDT@3x*?dXq!?mfb#V0 zQXAm!n=dV1|LFPJTf%uM|)=UJo7*epN< zC^C+F(z&*`*A@`5evIGR=_g_yNOR+VDWu5?PBXy&{ByaL%XSW;U1U6J*EDZo4VDY+ zL0sP~0C8daQ=EN{q6>ks$i$SAi)+>q%7i}H$ik7LcH~+V6R5i8XM{=epgl+*y{oR?+RYT4+?Q`Zu z_PYEVLLdFum4Z_G-05Ec&5}BL2Gd71JjDN&HORHT8E8 zeKetfV$K2CD1yZ_eT1;SFY7qRCM5`N3b~<=*vKL1qo5Mx9aBjcYVM;1DiV2%Ba-Un z91VmeWYXfsA!LrmebFr(mK?%E$ecb!=13vPoVnU-o^!HJkvVl)@o4)bZ^SdS<2EE4MlapiH?1*p}RP3u9SqT-cRC?D=!_FXvJ<}4BiME}t07)Z$K z7)Y%Sz&z*(%)(|Vdp^B)UH~+rd_x#_uH;Ws$V{D0AhT@cTc{atp#7kw*^1XDM3px3 zQ5FZo^4eL}Jt5&wXkt4F%!ILnE<5OoKuvTc3NYmyfO9KWjz!Ufh2e9B@?ta8mt#*5 zinaC#;pNa&8abd#3`$G}tXf9si^*ajT8~W&?83+codw}@425zgNj1tqXf(8pC?=nX zLdA^{BcYc4*a($$w%0)^9Vh098@{FS*?`knN@J$&GeifHR#j>+A)q~Y2%tfhDm`t6 zh6`byMVUr73UYQ*qgeEbg8UeqT&P*)1LBPkW^F*K@ILB=qk>gI*i*;M8aUL|9c(v* z&+;Cq1CP`-T9Ru?kC&hlmk%hLC_+0JddN_(J@&3UKu|C}1MHT`U0LHcWZ>xs*$X6t zKjL+8PUv)luxAIwHcUwEs_iD0kvMA zT{cb}z0`AQJj&tEP$kL=qQU8=3hZZ6Ra!L4(Y|+sSS$6~1E;$%ITdA{{2DuzUupZ+ zI^JQhV;3jaNxgREpoRqBh-_5g1OG#OQ;~=IrX4UWn*;?)BDyV72n&>0E&53mQEN^P zHg~e{cYmPwmZ>>uwYRi|iN9u>sP=JcbT*e#?K_+6)AYuu+NN0PL8|RxcGpcbA_3wI zTqER=Y(mfhT)av`fQ2JQ%`275jq)KvkL6lC{XrS2=PofECs<9z=A*z}w8u-qB~#59 zme`_7R>r-tnNayraG8r|xK~D>=CTy3-jaK`Zh9V?S+{uNmc^rb7RTn)J*-5ZLl;2j zvhg}N*u#1ebb6vcQmvzcSFB^N{m6xx)i4FQW@@%&Ep2*7R>tWw>mW`TaAwJ#q1wK%Lb**?PnO3CRFV^I@KcwtI zo@ehAC&%Hji2FU>cRQub*{nkAb|kow7ftKhU8Y;QE#;*)B^sSmoIC*o0|VfB0$bHP zXuO*P3H6?J?JH6$eu0mJuGsASlh~eQzhIuNN*|$iqWRF0Q<{?EMI}?>w4hc%$P+ja zI-9J1MqZmN+W`KRZ9nD$*DGv*I7V7lmgITvSg&tUT_#%tp+KS?-o%U?aZ+?2lHh&h zW2h@fNTHH7tRz_jBQQ@viA=Hv$>h+Pc$N9_{6!G5S%E;t;Te!MoVBLJzG zkVZ(74>m-=B)$P9_;(VriFhB{e6ndRWT~+^{YXixAvwTSAgy0@gArHr10x_Wj?qmK ztZr3QRKeL?RT%1cOHu`I*UGM`5Q~vsyAq(X+iMlC#vU-WJ*B$JtoEm$Mx0xk?ko=+ zd`PH?wCHIXn{Qk6@JP>HJM&n)%~;rup7hw!q_tt)CO^(w?%l~(eeJ6jNC*?9k4c9x zQAk|%kkPc5ZsMM}JGa&^$ite*^jy|$R`npGLa|1Gj3F;i6S28{({~xikY^G&-*gi` ztMi?bp-*|pvvqGI(QpoZN~g-rOsBveo{h^FFbdPXMfxV1u(NQ3yYB#eq*xEnA@49r zC1nG#$>(|PdvT`nwJ%?g2*|-PHP~#Mov)Xe?tZhzHa(3`nN@vySo1_W>BPpA!7SoM zQisXAf}5s#?p`N=S#`yT$SM^YYiMt+M^Fwj3V$pr7lR>eJ+g_r%B$L6(_wfTJ7Q6} zGqfVl#^Gk@31r|PAf`>;NKf42^>5VWx&FrI;`%(-m3+c{zRAbOj4$HzLq0K?ebkZm zh?CMtRNI5)(xafgA4m?h3_Yq0WImDd!IiQiM*5t#=*f{jYoT8)4QOpxFPk-p^}oHF zrNcVw?i^r@#wIUd0V(&Gc~BP4=?}f&Eb~L;DPKLp{@Z0xl+(}wPmzrOR)h~Ui_F)nl*x7o#xELTZEQ|3X4F?UJ*i~5&-o8oenwZVpkPnrT<@eYlpDA0_B zutR}{-1QE@zhLdXm&FXC>I7!Qu9^0O247a1}ncd%~l@!Ns8%@=CWY?@q=$0j7vMq7aVht7T4Y2uei?OL_XlGJ6zmQ6++`MVg z^uY~sUsTrd22g7{`jGtuWK1^l<2oa+a_ooSmn0-=Lelc894%!=PoiwK9X*Mf3GEy( zh_(~DE#n-3s5xG?o+cdYkb_0xnbCu1dfL9vSPU$cJYWB&8dZrlw~Lcd z*OFt|xuXkGu$!edV!#ej!flzEp%fnBYF-5GK$p_)|SE8|BRcB1?T zcAQ_p4NmO1Wzs?MdD@)_>GH1w-jH=72YI<4pn2~3oq~V;LJhn|>zZBxUI?h+lO)D2 zBdO?HcaC=@N?-%aJ*_{L3BmzvKwQI=jwc^-FuWjWU9Kn!Qn6A3A=*_)TDuCux233w zrD=~BSk@l<-7xjw#-wnQFn31FYs&MbOFUoFPZ}{}y@;+TV&&Xm9G(DT1@9TaX^mC% z$_a{jJkI`Mc8z2fP1ljx1P;Bs8hTg!lH#M^Csj|d`JnNLm|`OJ6mg5hEg9;dgeCJc zYhcA4D?)^pushmb0>v@xj@v-wsV&#VIq9SHHb~=kXSM`VgEPaU#rOhEpHTGPuJ}xB zr&yXoX-cSpwMXzWdQQCeFz+Yq3qO*aAh^emvC8?uTFtM?O}nE)I*G2e{W9u(FVr!bVy z0$G~EIZ}k*^?{mRVP|)z1>c{}5_}_#855{_VK`ts6HFp85wSN&ikZURsW}9}8oi-7 z4-TRyQjTjP+WSpg&@EU@+>S=9)}7>BOsYa{v`Rd>+ zXa22qQXqZHQm>_dK5ea&7c;+=oNDEHh;1s?j3Zan^(MKBPZKFlay!|F-;JbiYR8{o z%v_mmG3xB^n}nau#E&~rSC`*tz1t|L@%My|(;)&G<86)L5aR>xF>fX?LK0KO&N^6t zl-nr5nihwX)g#4*uYVUE4I)W&YXc4U_FxQ4h0$MICwz8izv5}Fd}2caZI0p3R$yu? zWCQ1hK)boA5@+9hBiX}hH%)5^9L-^{OgvEPpYHo`?S=jt*X>2xl|f>5VXh>6+4HOS zCvYt#9$^RD`zZ*lj`GO)oU7JJSOamOUFHqdTvrjs6;#43jx?)!CBrPfr>jpBOhNXa z!Vg-;y9}`z#)v_k2G0az#}kQw8bule>A;&|QM0Wkpj?)BL`uHYa$9L$Kr9bmh!8D& zE(MM1pu4VGv^uf;5UhSUneY>yMwr;TjT%|KhVopN)m7MFR+jStIIA@ z5))eQzz9asd^}aQE=nomZCO>CM;;_=9zDm^o1U8%7J2!m zltrxa!IIco`*f+XkqP<+zTUmm4Dt1FjsfERFIc0?0L z-uN59yPL7F#W=KV6c4ife;@CNcKkMa@NCarH|JA8+3yzoV!pE9ZC%fI(EW6BznJJ> zYP75=J~PZBXb|MGMDRutMpOjApxz&@kp>xQeDr->lAdyMTSu(^94^iYdi=eKlR_~z zTYU5~o_5!tBN#}bA!OaLddOf_b9{ESU4`96|LgR%k(hKR7zbv8h&af0*=LXwBvwDU ze;d!#i}K@9Rq#M$tiOHv1?O+uT7OYq`|Jz*f5L5$Rzpd9{RO($uLbF~sLk7FLtLoK z5-GXLX-R^$&8(}eXs`cF{};JOWIV2})lWUG7pe+HW@xl+36BoN;EiCF`w6S!dZ5D7 zCR7>WKfHd=Lv?ld{pNdG^SPza3`n64pGh%@n^i55M!^dH_(INmYyP?qDO?}{{0omV zOK=6^EdTS{$GiF^ij^4nNB3WfN7~`&!HJ%`?&qE}MWt8d;X%;ax|b%X05E<0Wc4!m(9TrMr87p8h6-u9R4oG|+MMkZX4 z1@d*$rsL&n+@?bLD%~_*z6v*$@dee25DN^lp=Y1`j2Aw%nz?5o0Fq*bW>g{uB4#Cu z&F*?(Or=!#iwv;4zF7UF1SQ`F=p314E2M&CH|sXU6&?N@W%ZI}jhozK-M2NV{U&SO zV(}}h2}yV|%83;*{^0mmD2^IV_3JkRwipC|c5`OM(Ht4RIJ(_h(t^^^P} zx4KzSxOn}8^YUB|@p+ujlYDyl?BVkQpM8AZ;PYob7M~yU87K9-@=Ehcb1c{01*L^W zr6Y<*mX?;3l$Mrak|Y>dm`W8Cash#~gu86g7>IM}kj6cb&fqO$5XPPMcFV<=L^#oJ z^;$d3=+*&I_{MHkswH!!X?@yi!0G3-+M-Bd$ht)Q=l-U|agCzm6Iuv(_#NT(UG|Ej80tUR7c^Mr=*&h|^4RVK$TO#Ab(2 z_Uh2=#&2Y!G?e?=Zw8z<)4`cuLEJI{d{@i2W}wBuNsUJOFn!4>Yi^XRLr6U)yq(Ht z5o|u*Y9K@rhh?jvt4Q$WX6Ygo5j`EJM$G&51(d zBgAdc65bMXdJ|@xt3Z@m$m?kh%e5ouMb14Fh-euN?IgY}C&(arNGJKqj+EbM?M6Sw zaT1u83^oTU{qZ?@#v_7_tv4I3ZjNh|a#ujB^gzUxuAjc-!?h>XOuoHD2o+DO3JfS- z3>{D*ovZgZ#x4#u{}o&luwDu9_S>Gj4UkUIilE|{@ygGRCXGj>Zh~bAZ6FwJjDctD zYnQ56mPIT=&&IxJe?fR;pUyrW5T7<~G z$^F3H=(LMCX*xRJIicpDCt4u93lRE7asCYzV zt;|+{EZPF+jy30?9f7FY%h8C-N9pvY57(Yp<8=ti@zV1YP1U>l)u8oCVvHEr2vK%*Vq}v^wdh!O284g!q39tY$qHMlo5OB1c8U0NPT|P^Ig!Pk_}c{6E~p76yX!9Y zPe;KOj3x^s2_|qoMfydY!S&bW`a>3rG#R8xCPy_}OS8$y$*Su>>gi?>LA>xw6sNKN z?Y!YUD!fAONqQyjWA%dQ318tNU^yl+a;D|qP@pCPctais-B(P7HmP(s21Trbq=WYXP?!d1uQW6T+8ne_vMqim->E- zXDR%UicKUkt`0?0hgbmCA>%-O9b4)H1$nGQ%GsOqN+i>Kr4aP-*%gb|Gp5k=Vx2rq zEi$%ZXK}D*&+6A(pdX>z0)oy0Hkw6&>Q zv&$8c4^Kv}!!2f&p*YrfQ_?<*LrcKL!7p3@)N{P-$6;m|4BUI4R3~~FC5eXKFBi#{ zhy#5{3rl;DRYl4mDgO0yNYGI~f&L3G;^o9c*mpv67M{%y^&s&RT~WMn+jUHbu8;E? zQZL0{%2^E(A5eZU{r1scO5-Rbci{14->0||tkL`^I#CFc$3}H>hkYjdT%ZqrMxUSr zL7u4XMxYn;H1t9C6jIP$4~EgDGJn(f+@TkQFF=%tcmso1x&g(|9~q&^xzS?KQ!R&b z(V3zeQ0eG*n4SQJV9(g+tJUSv*^@8^^Ok@%-@%-cQul6ZF{ORn0<8q1f6`z8LWP6@fch3QJbsZ$mh zMi^6B1?||cu||+)b1Icp%kO98clx|@_Ijy~%)DY~iW$QL%j4Amr&BT-h07>XYVz^+a zIe^!zPDOj*CQe^S40}Dtp%&FX80aUWTlU$1MWd7sy_OKMKPsOHgs&XWZP zA~C?%G5T?r^N9??)I_{ewoHADE+qr-o1?I> zh+k1)$Bv`Q)?|2zX%&U6%Ya6)00f0&$Xdv9Z!&{Q1_Dzx7c{XaT!Q$-FLJJgn<@~B zge#b#$)TE_6<7f536Bm|VJ4}BVK?3Jp}*#-@aXhhoI+#5wnGTg&`qol*i27b$mvr_ zcT|CbQJT?)$sa1Gvc=KM>KF%#Ib_w6$uL%Af1y;*>7f09n24EtPmt}y&?KZ8=@8mj z+cR`T&Nrt=`>5N~`WYU^o9M<)JE*35c5&7lV*P+1U@V2qbr_AwHzqIC)_s?#Mi_e%ZU(k{bPMO!r1mbY3&zUSPPww%kJ%;nz9 zrJcDvn7LHvyso!gj(mMNIddsAymMEOi*va!bGamQxiWLvp1Hg?bNN8#a#QBACv&+s zb7^NT4`wbU$Gy{s^30|9zBqTQGnZ!Oa$)9jiF0Yj=UgvqAG9M{!dS~n^I7P!xrQKIx{|KE)6zt0QZ(Fz~W) z_KnQol@xwS;jg)@0dWQnhY>(uFX#}q&Zq#ztTelgmDE5L-I5o8`}iI|E=F$f*QT{r z+vN1I;E`*a_6;2Ji}RL)=cIUqvt}N3^Gc{$sp=7di+Q17n@cGw`(2&Y+H=?0AF1WXCRnGxpsEHL0ZUFvv-$>4wt-fN# zL#qu{nJ;JdhUE(LFY2$mAfL&DFOhQQ{fG(HE+1Xo_mLkwnx}Qj8=rP z#-53uqz5vUfe7n6EZ~(u_o)8BxhffIcjR<^vdL-3@}d(t{d#zv z=2q({mj0&nVh&wGoF`e4@8*L+h9%)%Q@0) zV4m-3eP6B>1KX2$QFvR@w$Dta?Us9tp5 zG-1Z>(kKcaP^-A*`jG?>pS94mzILCK72W(D>MDNM0Gn$w27azI|7u$IsCQ%LL83Z) zGe0@t-y}Td6Z@o&_=SHQBP@@PHaC2xLWV}$P2cB{NbO?5)vMwLxRa>OYZIdhMsa zmwI^x&8OeYyoXdE+3f(L-7JYFk6-qSzj&hA*7oK{-{SUj|%6q56cq6gaj)`CG?lBXGjB58oIRe#uW75@`^tm7?FC-Ar0P> zWe91Y7HfPVF<=_zZ>=vbu5`E8gCH9gnlU)^>lSi=0p@b7O$5C$ZgsN6qL0e^F?1&g z?H9-DOSIXQAW_FU+Keq{Az$4Ti>i}97JYy>eC zAvs6iF8g)xo?3^#D+J`G=GO#9GI3DH3cAklUPwt>4)=zxFgjtYaJ+eJ9_&TcWM=H4U~snZJC0 ztiB19@-M7zda?XUB@b9W8R8)nTTWk=W3aiL%nA>7sLnj7c6Hd)om;6&`Y#U?= zq~xt~BDT*f4Ow>yNQn@&&?Rwd1-}{u*pd@W*i?y62oC?D6f&c$CdY2?;BuW8^MWqExS3wwaX%J`2xN7$8#~?~aK=Cj4v(eVdsGWe0mpUoz6z9XbSB+Kw7bObKH{%A==aPyIDMVKZB4yt-CS;VHb}8oNKYs{T_vhUT_acQO`x1salfxJ5x7L$!7kqF7HluHc z&s0Q+eleVWF-D8A2>a--X7u)QS7e9amx^^qYKZ7Aa03cz_>5&O%7!PTqqmPWL~1B@ zv?TOf)W1S#SA9JQpecS0;Scj{p(sa`DzhIw=v`Z5DP(DApwx7%MZG+`8X3O?k{5I7 zIUVu2&?vo5Wc$9glk8E7OvXf5Op8QM3$`M^DCn5p_S(My=RK{%-0#}PhUvNIE(+NdG5|qG@pV!cMcHbQa5T78IRv>DN9WWPB#CJ{yL!_R7~G(Hmwu8b zi61(s1lF1X%*OgBJ$WCGugd^)5$CD{%nfpu#LF5( z8kl8oIilV{_-BE``BrGVDLHdIPb~96z66^gmEYAFrXMH@S3Z!B=?hyW5TALJ#bh^w ze}nGpsud=&%*nx+NXj7YtY<@(Cx~rv^e9@Zjr34v>fiY`YCa(85*HkfHGf@uF8A;L z20yV92v)tI@fQ+Iw=g;)!VFgJio62~?3XD3!=bNgdwb2Py13tZR-HTE0z|H<^3O-! zX>8sTs@Z*et=L$`=b~Z~BfP#~)plLKAETW3atG2#z7Nrn;>^Q0q)~sq8Fgn_k7T zE;m`~>F^@G_61)QT30RYnq8iIDhp&5=6PAzW)<=iR(5ntkx|pl9`1IQ_4A&4PF2OQ zZ6IWE^yttyi3VXSs?>_pHVC8FKPPie{JxiE<|3}2D*@>!frJLl)>2ih*S=TsoG@E7Rxyp?FXc2j5IM&mzf4l2h;R#kCdJJUND(te z0ribUhtp+ovL4He;W9zgGvk%J0FNCJ{SC(bfz-n;$OR6b{(C%2|bD4VaEfz|yX zm91K+(cyso(7(w1&F1LseU^aufdA+iKQHau45R%lr`AfR;m(B4ak4L1mAzhv6g}>I`MY zriE8OIS52Wp&*h6m9czy#c%qYE+C2E)1i3bzbzEe541$DJ@>WLX(PWT{*@ZzWiJKv zf%9*#>jOvA6KQh$1?BFnXm6#|SxjP&((u%jyX$gPTfO#P))G`;v0R5Ll=U4W&<@X< ze4wF;sw2I2jWm?*=C$wZX4CwNZa?K}?-dBM*Wm_#~)lS9T6 z;!`U~tXT~DE$IGU&qMWf4|u~TEH)-~Bdb8URL>NMNc=82pBG10`I3_2n8R?op**ht zA93#jA60cN{?BBRFoeJf0umMLsIiTWk65%4gLNjEkTWm?Q3UY?w6T=7x0S*Spdth( zkxY-%($=>2UHi1Z-u8OiUc^T=2@(Pb3DPP^Rn*p=ajFg4LcnVN-?jIdM;>~;zw7Vw z&xc{ooU_k*ix)3FFDal*i)|kn%+rY3Sx9__y0|ooTJve^=lW@Bz3x4iRiST z6V{4!YFdCt+@MScJO0QoVh3 zxpd{4GWE9Vr%*)cYaN?OVNZI(#+O|k8(bUTcKKbdmEa~;2D~UUci-vqE;GlhwSATi zML6;%F&Z?r*pd~-Syq?;&6%ppQjJwY2lAb4I)0I}?I#m+$$-LDtConQi4PRl_NeXgP>OHyx4L(UT@ z75FQ|KT+kHi80YJ_CcPcK~{adn+CpCD>NDG6Vfie^|=3J@K#ZRpR@M$w(@($0%t`G zPdvdnw4z*WjOC15iIAa`LmF1A|0!#)wIdc%>Y$o{FB)c1FS}Z(%e7@t9r{aHd0lz`RWesigP zLaEUuxB%FNk`2*glb{jCCG^B0U7M6_VLQEez#(D|6kueS&Naf8iv&8l*sQ5u35$^t zaL@CHYu0*m@@+X?`s|Zo!$+5I&l}+e^6e|sqLtcXKf+`}_1q3huSwqtC{dNwRk$+% zYTqQsGy7_sMukpl^MT})yMdeYAxL3_yLIo_an`qGL7uD7`7>VZK<^boN(IsY0ji@O&LMO=~ zk*N10eaosTAY$6(XWp0fG?GCJE{Ekj@u+y<3&SyD8uwo=)2OPC-HQ?eUXAVc_OwjX zZX~6?VEe-|bIjw96{3HYDH2MqgbV8+Xo+9yF=fv>io#(sc0-;_LGPyvWjn17ixbQ< zVk~2MalIJ~CFsFrG8xDW8og;mTGwEc6{K!<(?PZj5Ew(J?Qu%8b{S!yJedMO0C5uTSSx9ja zOV_*t_J%Qc!dG=3^cH!%eDUP(w;+7wSfzfPlq>d2U2KI@tS7%%I+a}uvLclKw-|JC zhK&zQicKY9h$5%2o5qLTL`pAE{n@6iAGfQv&|loZRw?{VCMCn7agvf@5$G;w6D+2% zhqhfxYt<)MF;%d_Z&p2}%+0aldQi0B>5ElC8A`<$WE86GDJorw6sCD*PfE)m)5TJU z>|27;$$F0c(hZzHFNz=6Jx>N+lYa9OuZrS^aM7wZpB_{8rXnspROkD$1q(BB760^C z8;Gq!BB`)-LVJbLNM%kQDd*XNNk;3R=#YkqW{TVyNUT+mSep-t74}gzIzgf+)~Q6K zc~}_%RB7}Cnw41NrfbdQ-4*Q$#Cz>YD+D0w6$Vq*svbP7CcA2{22AEXk0>LPI7-y^ z#DFMfVevOflzS!g*f0CXYi8!xQsVAvO z)uEg*vMr2Ck2CWCI|G!kvbgC#N?gjx$=0NZJsm31CSoXS{z%~lrtw3C8^A^jH{?PI zH)eDC$_O_OQ;ot5CEU0t)NCT#5JylIM@8gS*dr+UhF`@Q92!ampP?P1eKuO%EbVmE zw7?p_gzqw1_foS2mn;b!?Zh}-BgrhuPiUfR+B~dbvw3!=;gH8K=KVA(=KT`GdGto3 zpAu~P42eaE>HLDxa=bWt2}Y*z6B1ytBaNVkCH+VHkx#&WiH6)5+_7=6Zw#{K&!iq? zyVjz!;&ioGiU?&2b2fK`>9P=6lRt!wOP2*&cDfr-@dtLy@=^?>9De?+*1|IA(`9pn zFk#2J*M8{_dIO%WZtb<}iH^XO3+aF&O1!B&uLHK4yDM6#Je)j#<*#JMkIT-yG-4fA z)^Io@9M$qbtc{Ja{XxHb3k~|=xB%dV!DO3DcX|wH+(fTqMDK>7GwQwZglnp2rsp~gVu*gK@vr_}JLhA>==oLHIb?0E{nA}+sty|x3@u)Kv;7)u2?A@`^{dSUmSb?lO9g+H zi-LZI&}U^xgw6WmZMv=t*}mbooPd&NW-4R=kx}DGW_pwUvEVTy0C(6d3F`#&tx$1~ zeE@t($3f5Un1Y@#PJ8U&lNvoAQMdNkKM`~tf}cvF&~l5Hn9bLgOWL7Z6lK4qtmRg@ zhsuWyuv#9hR1a2`vEGCy`}9-AqH%1}{DhM_UQ(=kNU?5`r0hJzoKdzl+$|269tfMf zW>yWDRsHsP>g8xpdLkzW(u0?9q^{jze7#f7jI<}vn<3DHzYvQCho5!qn|Un$pw?{G z{s|`tAv*!*R(t{dPDJRL-1#nd*ffo{1Q5gJIau2nJ5`#RWPDdO<>;l%>>fJK+$zv@ zxqNWCUFL)Oho5jQoomjXz7w`VcHS;_gC66Xqf{Z=#ADB5^b}u2+tYW-?;ZSJ{S~!Q zu#Kl%*+B3k8t}x<;L4-QbiPAn7wo)kvUp(&Jp2L~r>CILyL9w}!#eu4PUI3JE0MlU zqHiltQF4vZ+R+0jmO|q)12DcndUfR3id}%8t9F_pQU#b|*k47_Hhm|1#XX}y3p?gA zs4;{TwDyT}rCqmC6xq>>MR;hLUdeMWv7SW;Gd4a03iT?#6gX6;6-*eK;(=6E9R2s& z>-sdF>)kg?j~#n|@aJ{GpR2&1p0TuS7=mi)Th)T7D5duJ2N4bq>?MJ9>4a zVcG<{5=p+ow9)29hq#3%_6nwn|E_%i16ME&IjM;Hz_jR@f@MWuS#+v8d*gn?x*OU{ z0+^`Pn17cVeB$ZCe$OJ^|N9oI&mc4{E*rbNPTIGZ=@#pyMOIsr7jY1&(cH1Z8gJCe zgI*xQzeeA(iVpxuTQ?}}%8@|fnr@PnBSVtHc4AK+%4g{%;2I zi64zkJ)`U<^N$U3$5ri&)%P+q5F;!jkA?n$d z`Zn#Za`rfxjqi`r4MCB-$(&9`pdYW^~(RJqyNN@Mj!n; z>6#inOfaLzX(~7R*tP$okrPP$oq+$+y}J2v8Q=?3#qtc$09({vR#BzOf8>Z-K8vtH z9ywdorR;JL52LM`i<)wyt&(rS$TU&S(vuZio*q9PXXWBhO@VRuHf^*CwaCh?giBm3 zzWZl@@ONRgSIPGmobM;T>UMpQ-+TEj-|zLajPl=b-jVw9_d_IB8UK4RL=zwUjLv^4 z@<2xYLg+E!&iLD)tf_MHfq*s34#+xmK`pckpRs8SzXR6X0f!?il!P46kA6YWl=Qg2dAAimxX#t7my z>#%x(Xcc9%#OiR?;na)LiuL*amfLmq%+D!q^>by)A6N!4BHfGWR}v;1hy*o{Yr9R27nr69@~*VK4eOS%w2Cj;oARqShuOr%3qBC#)q+XuAvT zmqAKO5KZFh3QwTDacrQw(L0%~ViB^5aAE^q#BT=@OG>%Tp{6@{VL2w2H)h^0;$zUgMsE&FNO%@NGn~FMlAMd4=Va+=yjvy_=-QVe&{T)? zsm>#dz)?@wKIe9HrJQX5DQ6o5x_!#vO$rRgAgUT+BCMA(wVDD|+dX}OByn}o=qt6) zk%Uu*1B>jc#+Mhe2*s0eDV~gg@Uwor8QHf~>{jhTtfHkoC5?P$yFMv()uMah_pLkf zwo`qc7hO?xM1%&<$T5RMNY>*$MaI*&6oyK80HIOrn1<1chMgrbdV-p{)?H458Yr$% zcZrNH7eeR|E2BMdwv`qaRp%Y;*;(WOo!wbf{x-F@kSAi)y`}JbnCOrz!f0JZRVfL| zB4nOMQxUEs79n;P(e9z>O173cBF-s`eah*=oN>ZLK&!S6?}ypknCr)U$yT8RI=8+< zFV=ro_d*WH{@86Cz{?ui=ae`ZV2xH0cSR5+49x<&9*zTOx>tWBM}PhY`C!q|5p6{Y zA{8?Soh48-q`f_dZo4E+9wHl`Ff5YKT=RXZXf~ZJ0y!87it z(@iEygkM{{jbnLBjbIjX-M#j&y7G}r&g0hO3+5x9&5+>aeKVlCSQoZ4J5EXnAEl4pRglbLd!0R{R``@)G|iL?fR1Xe-VaX>hZDx2xjXr<^PUV2>g$f|*` zrQQl#s;-EYec9?(I`soqcM##s;VVL<1f7?xxFDSPWOaPt{53y<+1Y)QWJ!g+TMB`O zy%Xk6YsftqY?cx63$k8Vky<5SP){ZhwSgyvB>j~K*YQAli78#GSp3{|XQjk0T|yve zbqAPb;mTYRKq66CajaYPM7#J+KQ2f`myG(PMavTZRh-$CEuyryPi$lN%S zn))CwhpnUZG$bQtS|Xl*TFS%595(!9nrPDo-W}~ z;nYk!@1b&%XNvT0XL@o715LJx{;;5YkJ>3NQSRUD2VpTQ=V;$+--`lhQ~-%0x;iDC z*wK2#br*)Lsd*wcc5)@NL&P?E$`(X1s)nIx4b(A$RrsFzD^>)8Ulk6jhODq)f?KTm zETz*lTDK`{VYFeycxcCd;CW>ZbA}E*^*0XG3Y6@flPmtmu*|0p`C$B^*Z||@HT}t; zb(9`}CIQfK7Bl7!GgQF?k!y*Kt@7Ej1i9D;l* zc*H60iv$!4bwLdZ3~Lk^UN>$)WHV$j$(ANS z5SUzCk(x*I0t(a{E|s14{T}%T1PQ7H35@?J&SHSTAhjPWu3=cPRF7z>488Sm-q4p0 z8~SoxaJdZqdR5$>a?V% zDp}rw78%nsx~o^?65PUwD8+n}JfuBSs$B;3J6-Am^p5S$aLlt=u=(gYbZz_wBRm<) zcp1z5_jRumd80Fy&6!?qma$C8jb(HGSnkP`x<|%hKc{9<#&S<)EaTpFEH7hiEMp;1 zjVrb3{iL=^cIu4fhnZgfP{vZHdnxns!~C(_mnn6hjAdGGEca!`GW}i0a;h^HL&oy( z`$;bI$8vxAG>v2T%UD)FD-d^-%vS9F%y>9oMz&^3Zk6$bosz$&cj!d7VrX^C^=ABd z$A)vA;o(X=4C^k=+ni=1bao0J#kegWJK9(mRz1ApmxosT z03`)o$^^uV*stDC;*>@GjtnAn2#6>BNg?$N(4|9x7b`>oZ;yHGpfZTi)6pY9{_7!C z7SmV#_}d&0q`woTzxT1Jyl?$=n28%?AA#JD!(Pmd>z;ef=}auCrO^E0lup~~&@6mg z>eeF?XRtU#l(TP{$BxT^odbAhXnM!(9^(3Ec{|06L?|q~P^s`DAA`lXy)Qk5AO(E_ z64x_om=PF^+xvitCpL~tX!69^0afaN0OOg1s?>*g6gyy4?lmfR*juKKbzwmCx^eB^ zWkKV@PUFsxv)`l^Ihzh~Wn8Hie!Smsx>4ZtY4Wzh+L3HqgX#my;HHi7GL?C-Dy>M( zRaUH>=C?w}2Ex-jZ}$qcJSIvALQM~0+A1iS1(YytxOxhp4hx{3KA=D_M?i2`0qRsP z;n)`UQ?kJpLmZHNRQ!-%Vmc=b|7yq;7Gc#M->Q5jl%3UAjr6;GgYbE zgqZENZ`N&2poH_ZL^ZKr7M}zm&M~vULk69aNgLV$wX&TJ+M8MbUa5PM27qj8-podD ztZyix8j2DV=`a!qXF{k-dJ&j13RyhjlV<51$o~qhUNc7|^ zw@A}Np6zmUvg`kvrM@U=aBmc8N67O>N5nBFS$cuaav}#c?Pz!r3P5F`%8AUVL(WGv zk6bX~RF)^el7re%kf~$aU-4Ew*4=@jdGyv07T!n_Fi+V=Cg0~EW6@=1%_;fT(2YDC zVhyd0+5>=9jN08Jtf5C5wQpzZP_5wEjx}`tv4}}=ByUKaCYZ^>wnEpyV8}ft<)@qZ zOAQf}ihmy>J#mQy3{t^9{|KyuR=1M4Z4i@z5D`9A*M0rV5tmn?t~ z2O?ZW9w^{wH;cRi5c>LO2Ox~MLkq0lWxPlttfw*(F((Vqlj$)I&;%MQ*fxhj;|^(I z2sBm<%DQ`&Q{yYxp{A%&I_X# z-b7&@TGhE_6b>?VYG0>0^18w&TJBz zR-+bo0CzsX!3N2(tC6JWMas5@fXy%|AAt@!lKWIUwNQ9kwlLYLdh?zy=Q($@MXv~9 z-T9Ex1n7SUt)JcS-l6qj4(G$6m6_HNq*+lSNb^r$R%Txk{|I!%%Qz%NN)xh?t3vAmmx&i?8*$j4yqeUdWggl!b9$ z&kb$=DJ%8U>hZ9ZYP6lkZ51*E!zR52e(ZWUiwn3diajLOlVVpPOPAdBlPe-Dx-v=A zNV=k;5ayDeFxE)l?+_>~!>Lx|S^kD6M}ZI)4AsJgsIY^n%PA;F0eG5a0pr3BxyHmn zc=>>_sI+2rF&1h2(uMrL%lMkAyJXb5DL%2ZLjFfpuj*IA$7lZxbx=Jw+V%i0xvs=c zu#@WuY6u)+2tmwIOSDQ@?VvWer-L}rc66`IXKcB=Q0|FMkd854;SRg*yL!g}IeILjE?0{%1x5@nFw{5}lbb(Ifq)+^5C0WbeU%2x!g_ zMSxOmgm_k_@>|GI%7xtvRSDb^93sSio8-`9#f6SUoz!HU#WkLU#LNPo2>;t^&4c2SOK5zN{Od{L zH_5wE|0o|en8*h@vx`x2p^kW8=)2aUW>u(4fmw_O<#4F;&nVsgqF@ZT^92(|>z#dd?@ThA?spt z9Nf0|vt1tvdIo~E>q}REh!8(MmC}7@db|Xx45S=@>ubY8`zId;DVpDCJGB1# zkQ{+Tk@+WVlqi8l&M7o+I&(hQt5ii8$uHDK@*IvbM)EMW7|AbmjO1rwB>#oAA+d5v zvo?-y_)T`oly*8FCRrl)Sy)gwhQpwjv`S(C+%}>=q57e4 zS%gGVdn1WyTBbCMW>ap6cfeXKnw^lfdJ#(7StypmmQ6$-vM@Nx2`P&I#Fu0_1s?P9 ze>k~%Y!IW9mi2?21-E=aG6TZKB-i)_o~Gw}qHq^4m&p?K(cm1BTtOo`=G5QvobF^p z@GPY44!_8|0mKB+f9>#>%hAhB6cfSFtl7{MV{arGoAt%})a`jqX5t~aOe5)0)SYo3 z@XbjSUWjo{nK|eu=)?{_f5U!lA+#lIeG(%9QdfvVHE?v+*uofYsh?jOwv=r^Y5?jd zrUN13SyWAwAT4Y^;sjK+Z~9K6Za}I-J@MDvX7fQK(XKj*2m295UF~EUBb&&E1(pi+ z8+cH{$pmUUjV~9oh|Ma308=COOhrLYXOa|3wfl(vvM*5EcY7)E_Zy_-V+At$Uc2G9 z*%g>)hCr|^*#@0OD3%8ykJ?wA^(J8mo4d)HEs=gsdR`D~TLj-S*?_G-gsXZYRZp0; zyKnc&YM+S9nsN{9A}mMGy1zQOntJBBY}4E~lDqgV@+rs&CJBcnx(^W)GW>lo@evi@ zCvLlAZ=}Aj-ks-5U8!DjzlW3H!)nBwH`#XEzBG_+dpco-j;^`@jV`n?QuVmw&n-Ro z%ITSCS&MAl?tB*WI~Ami=Ywmk+~y02zOZ*jg`vCgdHM) z@d!QsErMB@dto@96Ru$Wa)%3wE(zD1`(Dn!^WQs@wH?IHGFhzcqU5Z>G-5#M?BkNI z&N)P=;O_gC4^OXs|9^?vy3R{XV*GU-4oBFBW9n$)=wM&rhh+E`1Dk+Rxyt6h+YU4s zmGwRRH)m_Unb_j%@f1u>`TG>{tLe3u+^bE+9&>)rbADfVvVMMr^Lx;FexdWb*ZF;h z{8qumq_&OsgE+}4m$@ZENv~a?9`cgSnOXEmRD_&mnv&wN~XxcnbJ zDftj}>5A{WUDZEuyFT(m@;39i`(C%}OFweEp1RNNItRny#E;#sw|_xy=byM;Rros` z3_LhZ}55K0oq3H^I1NhWGguWpPz4Us#780^aR~~rsWf3{}s2HzvJ3BoM4;yS($#gt?8iv$fSayo=h0vf#x;oWCikdWAT#XF zhv}HhE`OW-aj=7&#HB0QAqnhU`?L|?z@u=ot~_9sNj5frfBXeM49iqbde?<4|A68V zngTmqB5O@Ia{C-i00&xL#JG3M?6EB;3S(Cv?es)pXfSo%sp4C!Y7SFPbSfG6>|y=b zjKY*{9A?wR7r1w2TY!|IuGsk@E3`J0m{T1|T)Q?Mi68dIU+_d9R<66$w1>{vsx#ZH zf2JSfEQLMNM%lfH)4)65lFRhT#6RR%x^Z*vzFdl@#td!J4Ju*ppiwD<{o;R~iKZ5| zW>-qc4y+A9(i38X&HhXr4KXK8u5l|P_oo18#>C$nyT-J>GC(V0pCWz++Pz??f9JLN z{+*bB4)gCM6BDuNiQ9ggHzp?TUhyv=9TJR!^483*sJ-@;|AHQg2k4b_0!g=a|JKf? z;~x5~j8;4+KG9diu*W^L+POi<0ei08BYY%&3y|B1yx;Pvv2Sw6XcPNF99cnwZez>5 zaSc}Q{=;EhB=C)hc>01h8%hJXz(s1iR^2Ly#|)PuYcR0KdII@b3E&B0j}1qM_O*KF`b$!5;z_P^X}uF)rTVcA@rvW z1Qe-RG2ZZEvO|;nhNL@eQ@+WFo1l*UHv^gx4JS@HWQq zlM9CICcEtgLtZUgcOXDC*amAqvIx!>yL0x(ypI%QvU}M3Q{;VK36L3?d{DvKee3=h zu$n43hRhuPe$y!L{}IMc$_ECw@qSsb_8EDf`YiusPglU>FH4pN_%RK*#ydX1jq=XJ z61sxer8#25m7@Pnu&`^{XpYN{1)cZCQ$k+%c1 zDG+5sSZ$^^h|7a=>9y+V7*6zJC%3|W1*#ox?ig8!2pnvgRwHY&p6exRTbjqdN$3=W z938PK0kxA2dn-(C>s4os*2gH?TKa=4Sbf>b=UO%_@WvWUouETA?e#OlwH>QuJHpArUBkL6+=Lz=`{hv9rU#X&z>~fJebRi)_YoDzt>kUu*2e0^jXaw< zyHrLKEharmd78}dGCi3L^lEx;ajMfx1KjLc_aL)FpSJtx>&Sjp=grPc5L=ibNje6r zF>Wr;oR7$-LUX(AAoBwqIK`~_?20Hy z{N46Pzzg{mdtH0-s25|sSabeT_e8ed5qmD6)Inb7)U2NnDxu!{CLP$Fa7u!i?94>r$0JZ_L-I!4DcDAM(lfLwT#q$3B$i zh$`Dk^z;A`aKONFMV_3!%bVG|gp$gRb58`v6oeMUXM>Lww+IE<>$f5JG+ITYDu6B5 z3t9Z|L)L&8zTiZ_IQ+SM9KtJQl4v5c3O64J5%wWMaD_n4%F@+A;oVRoggmp$kWxY3 z&joWT^l;c3%hYJ5$Y`#@E-1|wrAFaNe8H<&y1LSpk3_7x@<{ErRg2(L9ry&P2|74z zk45>s+b)rMDl)(jKm-yiyh5u-2gbIQzl>N{Rfpjj+b&SRaMCDX)Xa_gk_~K5(X~?} z1A{$;iBC2#m>^iqH&}LCg|9S|^9Rz`vL%!=w#sx^^O^pcDv&R%FfK|x!Y-J}$vvi3 z*n{*bN{-WoC8MCdOd8l-2==-2th}RH#O%dXa zZF%8Xpxxw%+_2!hf|;H*u+I(TW*VsQlynA2D@7r{q-2m32Gt}jN5P<6DT~nD>CnqV zqZ4t=AT$h;H60hGIWI0zKOIqMH)>p>yqH8BXoiIcB06^UG9)JO01WKkB;JZjRZ3_l zyt|S`lXwUZtV0IHo)vo0gp}ncoKcM}H(n!FaBK>Tj4h8oK__%(5y{{~8e?X8ZkdTL z!p9Q{%PXNM9(2jdL|0Qy2=Fpu)Rr+9vwX|Onz-o`6P-8~RdZ*A;whiqA_5(2uJ572 zw~14C=9P8+cGZZG_eJeDa+;$razF|~=5R|eT5Gw84-~|vhiM7YIv{7RSV@G_GB`+L zdA!F?cqWTqyr+;aIQ2v40lFgkr(+oX>$^i8%AEZeM@WYWyro>6kB^u&Kakmvo>}{Y z`}tmViPFVNg}c~i$u$svOrE=9&+kw{W92&UTo$Pu;AUN5j>DwwaZIfD}brY*|hX+OH&DPb+o6u;Gm{O5i2POqEEX$p=M%qo-Ml= z&h%zBAa_W)8cOCZk?Tu9tDf{r5dKM|4^|}Sq?TQUf%YclhNq+Oh`>YRwy~*~2IS|} zftDA+@IXmdpnVp0xRIry+Py}b3{#;F;n-MFxSU81S`Y_e=uP5&^+NVM(O8a%MkvHV zW6O%Gt=Hl&d*c7}nDH7{)GzUycbJ2{a>Tg^7Y+&hgM-r%Pum_jI2MSWo5+qIg2_sc zs~A8$<}c}PuN!N|YhAI&X`63Io@oSkg=(LOepO<)f_`*EK)+P*f04qfP=bzIkwu~8 zf<+8K!h5#TDd`qiyid#lYrA8wi>^08s}0LTiQ-5Cb!5xjv8X*Bcj6RnBeYPc(%d@b z*NrdSI{DX);pUCMqms}=posi!2pxNYK=xtcyjJZB?Mrcb#r6$TR7;%qTTBlo9M&!Z>qykw+Mb9J=?hgo8A;4X+&sTL?+D}IZ&rSllb+nd za!-YlOBN|`dFX_XOIy71W83BvAiP zSk81Q1Wti{Z~JTwcDnv=6((e&#v?#(0{90)i6sErA^h31tPtE`{S_4PW!C_BBGmVI zDEW0+T*R9UC2w2~{^#ZgavZ|r8SWZ__PSWevW*VQcaoqZ1kWTap|avqWhCFp8U&w@ zs#P1EmYHt}AJ}Uj6|UWR7W-SEyWwh&xdT6EHqP#bg&@U0IaiglLRVbPkv*V*cPtCM zZt?Y|lf!_w!vUT`*(isK4DbRa`M_<YMu}`Op7N^;6!p`tSV^XpS=RYQ5o-PwKJ} zz0XX&>irft_e}5oLwc`-bIiYj{} znZiOA(zcz^>uF?6tTbHn1%I?SoD4Ok11yWCPy+8o63it+O@eRdH`J^skCLhaQII|$ zW`$?F?L}1IfGU%12eoWR3=xY|9s6mxW|eao`zeN+@=H+kHXqUWS4bk8GNEs~?e@Hf zyJg(=%Zg|FS_`9*4VN+%Vry@GZFBCz7ho201mG z?*e)jmUuWl&U#U&;d2Dg5`ku)NZeT`kT}RU5gxJTq_7lf9D>yQ=Kp)WL(_avWmqm!NJw> z+=BvtouF_2;TX$;^83#GrUgAgj=@59oj)d1O=4IjC#qUo^( z+>wwBOVxrFPx9r8Xh1OVDP1JgLy_G^Ihej9>CI3NMS4HV;4|xQDD|L1(LOI%^j9Ls zE|u{pA}su)WdBJlUTV5YGJsle;@0_c=93jFG4_bM9c=&n0!iw=Y-#@8%;>Z9I>#SL zg4H9i{tMt?jZNwZnH>K?Y!5juntyVRi<~9MllZkBflcRO#!VuN4*nO>6dIkl!h=Ly z&3_`^Lb2TXK7rDFv~~X?_lK-|N4_(B@joO=_uS&wNGzyJ3JAZ*ApR}$>~v!#y++xP}@VZKdk zz&4TpaY6%-J50|Uq*`-ePlh&1;Ns;0WvioPOT0GZdFqoQ1WYPo5YUM}ML;;B*vBZQ zPG#~CnHWocXg#Nk&`3`dM_b7(D=b&VKuHhVd&_Nz>S{RA&LlF2B!(lY7E7ns(?v4u zn)(^H;|R?Cz2Bv=vOI^=fE;j@y@*Z8%C}*lV|oVu{fC8{hmP+xq%qdK0BWvY=0Qo+)^M)uMjhCdWCOTeofDN|QkUSQR+(d{DQ2B(n0p7_8NW7E}a zEF6b!IMdOoyJsABBh6{u=;J%==?n}W&I*5!`ZSjyG`S}m99VSfqFWF%MYpnPv~Rtm z7^A&wi=OBMxLiglu#JUtxwJf5CN)q&~zD7NZ_K;kNb zBGr|+)1=F~3Wo_t9H!5nyGDUXz;ct!nsOrt)X%YJNJo*EKJpy)5YMx=`Ht`%thU9RoS35Co_XwS}c8Fl>fVMV!%HD~o3H1dOeiDzjBsM{Xz4e;7Rn!y{ z{zWO3F{6dZD zKS_r2r0Istdc*>_i@?nvN8}u=-MR8F6t3#jP&KwhP$wRy=eM5|CNgeL|E9#*MOI&3 zeBD@HZXE2O(7IHXE@#;u#RUmtuz1^!MjevJ^CV4~60Ey{#9M`ZY6%+?8_Uwn+lxhY zNO?*~^d`^Cd0vovE`e))^!g-N^S$byer4YyS$yYSN&M^20cy| zJ@b`GA|Jlk9rV0TIE)V%Ulz%MjLVOuoJc>+hk4bt|0O!B!VXLPjyEMK1y&;wtJg}~ z%gz_uM>7F~M!)^*eUP(^{F-~okPk$55AdPZP$Fl z7b|M8{w0R5v&ZRlf`R=Q_kE^3Q2X5KMwvJaT*a(T)FxujXYH}?MCfK+!wfc-)$U() z21Erz!xsvxy5!W*$n;5q)0^A_I>9M{)+B3$jG6zEQ%r~FF3qBKa- zVCyByi*<0w`iGpSt|^PJJK5`so*uMz2gw2;{oqXzwUFlUPuN~d8Ijm^mr=vYJ@ggd zy-ZgRRmtRGL_qF&vzhE2Yp=xonIn0bTDr+gUT;Er>N((?H{!Pqz`AIKpM5iOMUfLt zAiR)6Fz$lCHp=RC0=qOb^P2mX-3@Jn>!(DTcfg8?q5yMH8QRCCWu||rOzd*uZdQPX z*$CK6wy9_;7)$K2yWt3&{11EVn)bW}Wm*_)E`q~Z4j;LqJU5>@-==kIDe4&tyBXX{X~B|CQd=?5LfpEtQ24O@!86!hy5a0`~2#nAnEubTm`MC z8;n`|8*01ORE4ZHWqJ8o14)xqZy2|_gEis3UL)9rT1<>lyH@|%ef7WlSTyF~_6E-( zLjIkx{%7nj^Kf!LzwJwt5R(S1)F^+Sn269?->lX z`iMa35z6X0Ft`J2=-9U!JkJg85c6}qE@p)+?8|B3a%o@&4P2bp0OU4%-hL1D3wz)T zc-|(qYy&}Zx9ziowFg#Dvr0I)PY8N;qHtba97LT0@r`#CdJe@71*!%J>J-E)gshn0 zcJjLwKLkKdw7wZc>+|QEVWv(7Uo;u?b9`0d_+&ebkiX7?BTI=;{SOc+@xQ%LXewP= zD#ZFN#N+bt*VK;jbH&nd64i*fO8CU*KpY{2f?$$CFfE83@*evaFsU4CR2Zsp%2eKH z`v{er)?%L=I?qrCQHF?+)rF_yVNRqz_DvUljjmGKmrgH%wD-Qza1 zO8;o&2YUqKX0d0Q<%KWDpd8Ut&QE}+>hOAUCYb(EKLMIf{TV6`0iBngm4lYaC;_Jy<1@Nf=099RKA0ak zy4N4eUS)bZ(=X-tt#uV;*0pdsbx30mn#s$*XO^Jecrq(yxFWMZ$tcjYufnDlU5_GB z&iw65*Rxv=Id2i(v?CkcbiT&NTXlbkZ%V3|;jy!=r*&*ok-q_)2*)05UpmqWrQO7p z#L$al+bXP;Rn}bq*O8X!wL==t9rQvRMl}rHAw3ObNp=R5j$-Q9QI`ImY65&_;R2Rz z(AW?pH9p`r?iA}fSyj3HbY8Nw0L58|bYpp7QTYosTJK9=F}!zxr85sK1Y1>8H2WPu zqJq75w(SfV4IL4q0p&vv`Xw?>6YIupY`Rr2Rl18JPxn~wtoncC!jNJ@omhU?!Kc5Sv8>q249?$EEJs~x$CMrWk*q$DE>0n3=a7;L0(Q$HqBx{JN-!- zlX6mqXeBDFi#I~Z65`9zL+4@U#mVZ$!$2=|>_E0!=T&(N?nnnZ5zU!u|Lkn@k#V`p z>A6b+37s91Ktf})odM8zi}f8nXzqU{+Xn&y-To{~Ni+icU(DXNb`pK%mZ=hoX#Jy^ z$Jw`37@VF_!8+Vd)W71VndsFv)<6YAU_J_2mHi8UUR$N;^Y0h+clZb zc>rBL5w6?$e2vfd`TT;9&F5sEoyjLNhs@s$Ns8q&D&L5oC^a^907MbAB&S?yAk@C= zj_45)Y7=*rh&_>F6a-&j2KhKiSyt0I*=;6+F@v{35)Ug8g5 zGsS%isVnl^(=XehJ|0*08Q1JYy!4cK=B}P7(ExKD6P7>Q%VnD%mhtj=md{K^GsyRA zd?s=I$x%L)+{?lTZjaN&Ncl=rvhH63I2g}^h*^}BB|b3L*z|?~5W9j2B1j9O6`1*k z2+;Ng2493*hneR5Q=LBD*}>Rtd+kkM)m-Ou@+!o=T7_*vZZa;v+-`e`Q*I08!uUaB zsz~}u;ag)OGPUliXptHcZj$Q>tD5>h{3nfiVq=6qtkx0dRGX8&qIS*CBaqV#dSb;~ zpO!7M+wR}2ib$9r*aD;SDeI5+6R@bJ)mqU)&G_58cKB6*L1;7lwFs6b2FMv4!(MSL ziiOlth=(xQ?YjAU!cHHP4aJ-pWfS7uCb*w%zxX65V1x%nLA z^A>Y7{FAw#nLGJb_Dz|1$x4YO?0eW^p&qnP`#;65>F{gk&*Jz6K5?$Ij&aHeTSz{i zZ!jLM4ke~lAOfsA8mx4CqZ5~HM)Tt~2e;`Pu_GeiScE##t-M2Ko*yd;T5qMt&a4Vr zgQn52zvVK3O@l_;hoNe)o$m7%-S@oFHjQ6^bxK3nVKAA>+}WK<(bx z_y$s}-War=W$Q@4TrYhni$+KgE}0(&s$+$N-RX<4AP>Y(d|<;lbm?4oL9{5|*_SSk z@ASn}*DNzW-}#2|atG^V7b~QP6W(Aal}7pADV2VuE?Ic8oOkYGI>kMHRh%(YNV>grSADu}&k?TFz1dh7s>9>EPpLZV*%08*ytU73V zwu$s!4(Bon9M0h|KU*mW^To&(^@PcMm0hDcb$QrQlfNPftKUdv8yu6DrSPM1+tuu25a0f?03=) z+(t~}QB|KTjt*HIJ-)bojVRn;$;98l(+R#4ok$uji}j_i#9ySwT_D?iw84DTLA6rh z%peLo1Mw8*$K5N(t@(5ySvLlG#fGJ@T!fTrp+@mjNfy$T61s^O92LcO8e8;;WPEju zuge*qtniB9j8jD(-y^)kv4gDdkP+-L6KM2N+X?w7C$E`YYpFHAoF4I|@ZT}rwRqX&N zMtLdkeZ45t}SIbCXkEKg2rxN*6m~^MSNU3uG^!@)vF{3mNPC z>^1TvIpr`no$K34^9^v9tw9fM zJlg0+z3nM+-yzQvgD;S_#0xl{eFj-J7TRI}($)dq z_rdQ$S?gM67Pw+ZQzj&d3T9#E)9r06(7pbTNc*7S1PW+q_DI_w!(H7ve7}}Gt}-{^U~2LsiELW zp>CBW`$AQn?TFrWed+NT;7myz6af)x30sDbqffh5|g3tGeJ{Ho)hPGGNmx8rw zPU`QGN*c=~tqI~vmDWTFN-<%lcOB*V0@G~|W&FthL_9K)nyovafMS356Z}>#=(bzB zm7MZW*H{6UeTO{R{KYrjuKP}K_TYOS-*@wQgwJbyD){^qq;_RY*Wcyao%gID@7nA2 z6ncxYH!z1EYX2@GxH6Gukg7tqA&#ShAAWn1&@(wcfBg<8)dU68WTgP3G2=z zdIEcC+3bs;ouO*ufx4PyiNFl#erP%8=(NQ`&i; zXv)*j%Y@t5QZ$~c_CNuIdQuOqA%YE0IzVHS!dl1JZ%%2>Bu;eFy;lpHX@z`)5^ewvQ?hzjivi*^ zl(+1(ctwuWx!&cs=rhDfVyhsVzEt>#2KL`7d|9JV^b?|3AOi!KCKjU2uOoGwS=+z9 z0ZY*8aI#cp#5EfaE3UoB&KX>K>`7- z|73)e8|WjfIn}eR!c*oZE;TptHG)MFn^8spvyZ7L zqi`&zVH)3MzxI)PtXzpWUnvS${UMsQY_xhP^a9gYH$|)-@tiwvs64IC*b*+0&`5`| z@z~|*kqCO&c}zb-9G_J$2CRiM&E~g7K#se$HLKb@n|)zgPdHhD0qLRW1#p_J>v8Sb~K+VD#>pr* zhxR#gnvm*4){WUbU3*lLuD}FAh}UTbMsJN{vgpL)+}9OI;a(j>0EJKM+4}{cZ1=mmFi(F~jJpg1#T$XJg!F z7k#$lk}6SipcWA$?VY*xG}rnrp1XqoU4)A&k5qLTTgpJHQdiZ!*cf_S6`5fhW4N6(1K z^0{zH)itxH8Ev9ICV)g)P$Z-hM*HfD>cRP5(YYxSr1Cg32{RE2b=*bW+x_np?|b9_tI! zth#9+6;VE7C+ji$8IBsW-x+iBUg(w*Y*45iDFn?<)Xgq1v+YvjZBk>bB3GRn+_37x z%}3jguK&Dg9TWSDNRzULD80yDAydb1D>%UmN8$&TGzarAq7o^^Tv*`=rEo2>yVCO^ zrOeE1b;Fv!=8k#{|&0@IO2ttOSaS!s;l0}JOqKr-18EV zcPjvaDrp~5g~q&G6_gnF-wY?uH?p6z$~nSF!bV(y8P90}>uEu%Nor24 zg%BY@W;G_WdHv+X?J}q-BS+1c!`5Hh28}O?!Zu{7%{QMPu~uW3R6h+86TH-0aRvQW zHe7n{hr*b%9o5xYS6}Llzjy`4{?TjVuM|W-Dpw`(SB&T+Ng@2H*;eVLGH;!jkEX9> z^S_kr9jexFU@NCrm&{#y`s>)Y6<#VrA@!^}@7Yv(Q+TP<6>>Dn9Lr03@R?OiYDyg{ zZU*}RKqzAv0tbRIXgD~_R85_N!!hiHmIH&l@niUf?`5#YOKW;Po#MQlH}6u23fS6f z#T==Zk9e<0n8f?(l6F5re8@J`B=_UAKWt5SsX%7=jYLZVf0iU z!(+rgGGy>sqONOJ1O!$W(l@1S_oTd<3*WtF@4G+#-@W}Vm5c9e_1cBl0_F%HTG9ON zN=_y#7EczTD`nrgoZi-+cp}o=CpHo9oJzCRNu`O4Tp0hQG}fDPK}ySx=sb2oNu_Cy zn{D0QcNnbBS%%zWHqXYiSfcOZSL#RE+`@Cxlxq8hCgol_()ajx=a#tgk1&e9s(nmb zZeWucA83eGipL&_HHCFNUkOdd-}>oEk~7z|3Oj{Vs||7Sw)j9}?0H>S_{`{jeN;%E z{>$HtMUe8QVrc@$UJ6*-@Jh&WGZL~3ZU*n(Cly1S}$RuLG4aJoor5`IQ(E?@Ykm_H!6R3$`X{*WRJ z!u{`mG1MF?9o!X0LyYECj9*ZkbN-NRg;b!C8WRALtu*VO8%FQ`VmMi}s*((}=$3SJ zsTbH{#d28#q@!G>JtJCHY^vh#lx)~x^2Cw!Ad&vVvfa^@MIq}Av+4^o2$_n2w+soI zj@BwU8tZ&)Y;2F6)n;N&S=(R?**0tucDR(pEP_Q@?>p+RD~QfF9*B1Xfd@rKzihB$ zSwj6>M!=)8=!OShkh{ot;v2aL!hlO4j@|ZS%S53DRJophSI#+KYD%BEY%u=#km4=G z`rxccRc`eJWyxeSUSHM^`_HKAXJBhj;8#{W+_h$X6?@3?-@Z*w)w}Iyn?!u0g*&_L z!NrOu4dv&f6z6)Kzc@Oq*%oZG#2ufF}!^f}?=_$Rw3>A{PyksT#y zKhDv>LjAmC=+B?2pULs-hrHvLyR3=t7zHCfPdoSITRyMy5jcv#i_s*h$nKvzVtPlO zpM|57NH-k55OlYJmq*ZGBktzpj0K3zamzb6RanyVg}zjpHJkdFRs;i0p#NSwO;lwm z;}|_#PpiVnQb2_!v+7yXy`)?a(w{pLa>QJ+%`xBIYu|c9elK%Nl^!9DBN8W7Hxk`C z;11!4aA`J>^%W9t30Li@tWge-p!}TVG$6j)E{DI6_lWt#vXHePHv3}&?H8kIX=Js@ zp-`<1rF5TS3b0;cP{42F2{%}KyKuBKg6Ln8Q)clr^;2^H{<*gk9cz+_h@WE~7_w9le^^h#xiH%I;7fHj^wdWF+0kjgaMyPXwF zC$CSPtJ}tg;0HI!DsJt}Yr7J$PkO@iC+%%4tguyYqGg91fRj_co~_}p}Y?Dw*()V7$zcPFOk7D_+bQPz4q__F1;3^M1M%)s^EG>ND*U8lQ+JLxIaxy z*3CS;zKM>&QTE%VPt$C2{O8WnhHFMR+0d`nRIh#J9~|;@&JOWa5K{#CLg>x5z+q)Q zmG#yW({<}2<%^GLT7qr*7QZkH zkljXa`XULcClcps7KLvR9f(MRzM}e}Wr0Sk=s1)t5L`?UB}J*=5{>AyIuoAwKnZHe zf$_0V)pkdlfiUesc#uGeZsj&atWSzrt(4BZm%eP2Mr8#$!bg<05{_+XVApBjwcVW4W_=bU;EiRC53O9k3j)nP{{reTD^unDiO>5V}@D zh#u8vyIt?qJAky9F!XXn9+-jM9G@dY1&+=zKFG#9LWVk8CDf?LW+VfMl^v&5J*~RG zDsbR&Yhu87)K%LTm2bbB3ol!kDyK$Z-we;rG!B`8C29u#e;i5<_Hw20b3w+SMbYwV zs|L%2-cDJnCm`o|ef$iOBOzk^5ki(@Imi;j7@axUDX5e`CxS|P4pxAAnK@vz;ffU^ z$JVICG~~;%GpIBnK3E+)1Ilv^ZOh*9WoQzb%H;Uj+z1&#!rdIfx+e7*emx@C$KMr> zfxG0VW);CT6uZ-@1U5&7<|I4FWW*SGNre?^So9`vSc$y|-TN7O<#ZX|t=miK;ZMyDD0wC(PAp zTHhe6CPORgy^PA@eZ4*=q&BF!0FJZ0en3-WC@Aa*VEHqwLiniNeST3(X)_RI~@|lPe4l`{EjsGG`((` zGSk7yM@at>1e)U?AITrU^w9?p z{fM}|NatbwM(H>~<8obZoyUSsmke%yOjb7Ik^N+mwI@(Jcx<21kP?-3#(qom3^!l~ zq-SRPBf?efwQmI2LkQd`^vxHvK2Dgm*R6>S;?8>9?okKLc~G~BAvQ`vm!K_&x;-g- za=qG<_1rAY%#BRN0!1;xs68Y~Z=?K@ZE_fGlRbG%c27pW*=wihqs6^JqqUs3te)S? zXvIwAA-Ul13SKZ;CxMS_jDC;4y$mNshK{-Cpjh58 zqMwtsvNS#Gz1DM3VT}gI+8j8g%fYH6svOGWEoZ)bdscO&yAa&y^T28HAo7%K(BSlOQ;4F9qEJ zr<|V~&2VD5m&_%dwR?=#jWm<`e3nddcFh|pzV>?3IXvf0IN04Gv!A$7X6S>QAIw1V znu28ENoMntX#XM>X$?FR!&RL!&~unNLSPAgFBgs>pBgE2NL(mmz&-Zw-y17)&dK4^ z(82~wj43|FRT%4fd+zgqaI1=^D4w9b_Kg70Ay&V6Q0P~$JzH*N|I~U=JQrLcCaX`p zE)bueN1cR86n+#E@P09gCjJA-DIaN`G>ofORj|^jCV)^8a-wnka6#1d|XlGfpDlqu?(N0V*le7BLUaMOhU3UJZ&|`1pTv3K) ztL$j0(->;}?c0qup_-%jQ&aVGN9)}g+1}wbouTI0IiR~N>o9xJayjHI6>9`vsQK|= z;tKQJfLCu%A{(k?J>Rh8`fVEWXw1RCf(Irc=2XaN^#&6&?EeJ3&RQ+rqSxy8SVFpH_0RbTdM9;Raarx_QGsrihHoLU@mA(*OH7Rxz%YFU&= z=oO|e8iA?Vmx|P~8r+`v7;a#1d5pWNLA}665wN;8T#kmv3`nvnQRG0?n#|@s=DD-M zAi*9@@`)Lh>YieU@~E6_0gCt=sk3=MU_AjpBth?Uo&7%h&#=z6BPtu(S-6-R-kA;$<66Pv z%t@S826%sD$Tx_K!9htc{CMSh1I9gS2!Lw!_K!s(rlVngFfcRea*gXxDK9WP(MdsN~N zrhoP5IQjaSa4%tXZtS)C?K-YV3hC(=Zq1DQy>F*mrNm_%#^9l8&UJYU|E(I^-deFq zDrj)bd-czZe?y*quQu+*Bo^b|mycrC+p5qJ3*V~kCHpY$#Q=6qIQct`q*eb^_HAoS z5~P6mLylDE4-qRH@dFAwhU}(YL^;gzqHLi=iL@q!2D^jK5sSt)+&cvGeFxrRCzn;x z_9nb?*!o??X2zwrhDoWBRNMjm%MR#MrK%Ub_8PEV0XlWFdZc${&@_V=ntexGD5w6> z@%0kk)c9JZ>R=8AO{m$B$=6)VHGYEkL0&mI;_NZon+94-{EkqQYy-Jw&k|IumS(ZZ z$uR?&WnvM_HDEms_na7WwDnxELiZZ2DHt3%QGK4nQS{TpdO$-$;IS>AlkLGAZ(>Y( zc4oVWu4ac_A??qQ_D>zX{e+R8NDp{l9o;TqC0b+XPqsI07%>l~7Sg4otrtiK*~wmG zk_0mk3uc0@^8i(d1GsQr3-x}MoQ*c3$DvQZr2McY|8-LSN#P;%sX&%|O7c|%6CX;w z$oD&tU%;9Z;|yhFd=3Rti%9s85237P8nI)r3((5i7HBH2Qp}+y&UAt8%FH-SUGJQ@ z=l@ExENKk$U|If=VOegY=fmgZomiGZB<}F&IhJMauXUy0P?csF8J}~vMc-A&o#d1f z=k90Z?&iZEDsY`yS>U?kg9WbJ`TT~@gM2#p?BKJP&)a6~=dwP=XaC&e z$MbLGUxD0G|BZb1?swEnoAJEn7sBkh;SwRtaUWl%XZPR>f_--YmsGK$ z07KTOvqDDhX#2CYp@GTQYlKrJJUfSbZgGJvpE&#=e?sd$J?ptYwYLFF8(z{u;)Bl3tAseFwQO$~EPR#g zHAEn+#6Zr;Q0E+$4U9nK)dH~ASg_XEEb$>!c!G~2DS^2os4~Hnaz8wm- zc#SVp+tP~|1{lmqd{b3*0Tlq0?ce|uX3z1WND*KQbZ%)oWI?Fi5{IX@1R4#tLwW)D z{3JolGb3n~fk<87ZU&L#xv}}FgMd$_OcOy`ft>x9%4xV;Po5dB z$s(rOdUKh5?Wx25f6?c^zU}w<;C=M@jC7xWYhQcn@c(Che&)pNWk1|?=Yaob-N|0| zJ4xXT49=&6PakS~wAzZ;{x9!~)3YaN4;X_!$r*ZI`=UDjf+KdvASBz@CU;K@-`I=f z_^KV9I&=Pw9St76ooEHt)0&N~oph${e(YG^`?}qnU<*Rt-77j26w|)TMI$ zOuoDCW6iOo$LyoWh|^tR!@M^kJ5MQD#>7CD~X6 zru3~nFhQi$yFgGT_bvrNR2Elc#P99i!?yAozRg`_!;aWFh#&9$xhAGf39NI>m^E5$ zjQ-^QSE-~r2+cW(F?1PKgjI`g?b2rY5ku^0m>b@1Gc`M0wE(f_ zA6rYVuTkmJhavlA8nok8^Tl>o=kMqib>_#$QD>iYo%es;I=_=u=cBgH*d;qQGYJ|avMzI z?^dH7$0eqORJ#mRvA^5RfND5b0+#wy-EL-lK^TC}Hrs6Qvjula7Hd~^Qu4Y;oR9&d zI^*N|Ds){xMK@Devv8m#IigFLvhcLFa3(JG$aHY7NjCabHv{d63(n;=jAP30{${%&+Rb6Q ze_C5uPq!V$9g4vko~8@$-7f`tLLa_-UZ}%w_hSoz4_nKmF+gC!WuL393z$O8Yr246 z-DH6uDXA>@jY)%F1{5mHA&gYum$ZGliuol&)i%F31hhn*XXdGWUjF<(*@tk%l9dqvLe+#^WmYYZeth?Si^U;L|9YKBSqWjT>Or`+s>wlDf;Ms zCKza@_iN4R1Kpau+Msz`Yi`*;d%`PW=b7zFc-<0GiWltGOPDI+)&YPmF9`?1F5bx1 zsckhZy{)F2bzwJ`Z(AAdJa(^8mo$6Y7di$pBoBgM!3{3*Q#f9hj_AbOt%hi^b~%1) zs}KU93Z;yik*=b$YZcLWN!KdI`BluN3gvt9tI&aOcV~^hXUD+97RIkFtpB^0EO?H2 z>a;Utos2Celu*B-aeK&0W~~7$c>yOFa~$?GAshWCYH(J{Va;qkSaTBKU zS;$RkS&`2R!^PXc#oUf6GAFYt)rtI*{W-gvqgYvz>OZs&NOSM$=s|ZZQX7+n)W!jG z%Rp*tl4o>7YJ?_j2_NZ4Y#pbpW;X2RwHB*&&uSKL2V8SV%*`s}BY^Q=Vv zG5#Fr~>>N6oGQ95niu>LI*h4qVKNTsWKtlP zN=rvr&#@f-bWxV0MuK17c-iH5a18lV*k*E)`gBxLJWP6Xuf8K-<5?PgMIf3IbB7KS zjDJcLw!)U2aIl8cVog+A&AMrLmgkBF=>)5NIqxCX{y5uUl0tCjtJV}r1@IuHuIL?BQ?>0L!Qa8B|svzwV9XyN_fU~ zx(YLAiffrDzWT>90>=NP%{>{nP4X&QEnsW6F3%1L2~CFPq)&>7E# z0EiH*l>o62_S@KhUjYArg?VhN1`LnkFJvqg_P}=lfu10ppJO2$zWCUb{e^(27Vz0l zgsRvK{JUps%^}6AZ=;&WQu^kPHHXl4j)=h7K3u^J&N?X)ToXHfJL34+$7J^Rbf2l1 zYQ|K$&Ao_fEs2_pLLEbOzbLK%LXl(AT*`^~&&k87=F2l(MbT76mOO;wn?F!guS3F6 zy`jnA;c)y#kt%a!xjO==T;SDj2M1IorfU8|@xPeE);ex+vrq$zGy@xx;Om}E*J(Km zc!&sxPbR*CAgDV2S8M&ckMp<6MziS3U5x3*U1%}anm;flb}Bnp5ZelvdVStQmZ3;q z{}sGM1YW|PADDr-Xw_Xg38xS6&yTNQCte&j2aV^qnT#|y0b$!Q%kEjx>~?fMWx>j( z*``_o{Szr|G_gU#mc=0eGNc4REx%36>Fi9749Pc@^b;Xcgid=gGOaUwq#QeONS%|4 z$GpIuZ`auK&Bk5#)1B^2z8#5wi3eLwte=hC&X%KZglBI$ZskbJsd1)j;_X>ZDhkJ} zx#|24fT1lk1MR9#WQfadz>p{|`;kNzYfV`%VJ>(0tu?y|2P~fG+j9lmYfW!GP5){C zq6|s<3t`-MekzCO=)|1P_-@%FC62mktG?b8`jhpC%)m>hL-+Vtg7m85J4~N#U*5hkAl`P;Hqq(bTZ1E4M^~e{uc=GJ|iB21TfI=_uqKt;sojHmaye7v}wl1Du5J@O5g0F zGkz!9F^n`fBK8}dks*ZQ_!m$lv5o~$lyvpW9DpjK=w1LC7H^XPHlpHf9Duf)143CV z1{`DnwB4>40u1x%pVI)^ZvM`Vq*f^aU1WjL0%*HA@I<>}Pueo64Z$}53_!;UK#zb- zN)6OJ2^kd4jM6;9eX>A;lr5q7>!I?^^`E1*oDW8*|NJ{M4v#71LJjQp%wz^5 z!Bw$u+1*}lcl#Cx{x5kA3bD?y?lr{ierz|Z&(vgg%+syg@T)YR4%jpE`4Db6sY3G~ z+sD^QaweYt=D#-+u_H2j zx!qi7xgTVMqDK z;HRVGpOM!L_kef@;Xpb=-l&g8d!x2hd82mmoBHZ%#D2j~L-7`G)TiYyE;BuYEwc|Z zADmCv>Q(WL=7s@1z(ZA~Cs)O{R0Y0MIL4wR)SGG%;eoP%}NlT zD6JEmgAzHwFD{)Sil`DnW>_R0)~({LsN9>d=aVuX8`Us)q1F~X-z`@3NLT!@qwe+eBK zwM=L2e55Y>;)OF(yGnBqyu8>|X)v5b66ym4FZcEMEU;h8HiFRc+nGCmZg?Tb5rl2R zdGv~`z@cq47`tWGp`^Zw4JJRbH+x`;Pcy??rC#V!J2#xDhIIdUR*4I^k+RPaO(HjE ztG5|89{q*#lM-#hQ7|Fm9h*54u(3o+D$e@UNS%QTz2y$~pP}KmnHM_0v~q?on$n`q zHZ$Q%3R7LN5`;B-D9Qe_^p=h^Mxs=po1}ci7tA{Oqi1|#A@zeE8xLYv;ixy5f5kfn zD~00;uX?w<&!l;c@9=-w(2#Fz+)&ynFn2%CdJ=RI9*gH-cTtoRJMr>6z)gi>lbEsrh#=A;l%DXLTg)56o%IWf z5C|+Ns>SpJ_RukQO!*}%6rEUM#D8~9FBhp;)r`}WQg}Uux<6g_aENbRZSQ$f_k&)@ zTincRzDodU%MvoU5HLLA=Wq9dO~00%wJBO&LE&Jc5|RIJ4{mOim4rm;n>)LAB#wVP zOmT9ArTXoDSpQb%>iW0xlzlJ~s8ReBo7{uJTwj#8cfymm6f_X%uB3a(Idl&o57TFH zZ8hd>=EHKORlyzJtvBdQ0XSt!o)w=ijXGHbClnl2LSUpp;c4v_DFk5jSEBzBlb@_v z*tzkkZJqP`hNqF$iEM_%a2Z~UC8pM`xiZO6bDq*0Eewn5}mD3Q;u{Md>0yHJ-a zAi3lZT0b<8-5_bhVq0Xt1gR)Ep5o$N+ec9YSf<4H2V?E)HT;HJgciPG$#v8EvjShu zkm$GNX0js2mlG_(PDzzuzJINvo8*u|jJd9px%>VIu3JnMzt$4u+ zc{2I(EJhG?o|5~f0C^LEN5OUR8yJ2y_^#cne-IFf1lM{EKjA{em3Q;)TuC5N72i|K zX3uDvYRvB;D}`rkeNjS(fFlBQLSiV^d8hlN06~Ypr0uI zMkD@9pxX!u=HlDUW#f9FFBo2?SZ8I#pzn>OQ6kQqWd88-S_0XkUhZ5;)Oa&E(1Qq8 zv1t-)c}qMqxWL{Qde8N&Hx)^|r9AU&ZjYRLb6W7l8woJFh7U=byf!**TQop2anJk} zX9+^C$nEZ@4O+8y^A=`);lR%7_?}^ODpnZTu{jwC$M=j+zURGUwBb z?DI*7Q^#$36x<+o_!ajt3m6-!)E-x8`akzbWXtT3*oHZ%xPpZo|!47VVjwg zD|v*Lj;?ZC1bT5bA*$u-z4Qe6Lq#62JH?wR7AlnmIrH??j+8$o&-DF